commit 2ae2a551a6290f46734307bbfdafea4b1a2cf2ba Author: cutealien Date: Fri Jan 3 19:05:16 2020 +0000 Merging r5975 through r6036 from trunk to ogl-es branch. GLES drivers adapted, but only did make compile-tests. git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/branches/ogl-es@6038 dfc29bdd-3216-0410-991c-e03cc46cb475 diff --git a/bin/Linux/readme.txt b/bin/Linux/readme.txt new file mode 100644 index 00000000..c93be396 --- /dev/null +++ b/bin/Linux/readme.txt @@ -0,0 +1,4 @@ +If you wish to compile the engine in linux yourself, +goto the \source directory. Run a 'make' in the subfolder 'Irrlicht'. +After this, you should be able to make all example applications in \examples. +Then just start an X Server and run them, from the directory where they are. diff --git a/bin/OSX/readme.txt b/bin/OSX/readme.txt new file mode 100644 index 00000000..21cf3de3 --- /dev/null +++ b/bin/OSX/readme.txt @@ -0,0 +1 @@ +If you want to compile only the Irrlicht Engine you should use XCode project available at source/Irrlicht/ directory. You can also use examples/BuildAllExamples.xcworkspace file to build the Irrlicht Engine + all examples. diff --git a/bin/Win32-VisualStudio/irrlicht.ico b/bin/Win32-VisualStudio/irrlicht.ico new file mode 100644 index 00000000..49f8eabb Binary files /dev/null and b/bin/Win32-VisualStudio/irrlicht.ico differ diff --git a/bin/Win32-VisualStudio/readme.txt b/bin/Win32-VisualStudio/readme.txt new file mode 100644 index 00000000..d5c7b7b5 --- /dev/null +++ b/bin/Win32-VisualStudio/readme.txt @@ -0,0 +1,25 @@ +The Win32-VisualStudio version is currently (Irrlicht 1.8) compiled with VS 2010 using the Windows 7.1 SDK as platform toolset. +You might get the necessary Windows Platform SDK here: http://msdn.microsoft.com/en-us/windows/bb980924.aspx + +To link to that Irrlicht.dll you need to set platform toolset in your VS version to the same target or re-compile the Irrlicht.dll using another platform toolset. + +To re-compile Irrlicht for Win32-VisualStudio: +There are several project files for different VS versions in source/Irrlicht. +Irrlicht10.0.sln is for VS 2010 +Irrlicht11.0.sln is for VS 2012 +Irrlicht12.0.sln is for VS 2013 + +To compile Irrlicht + all examples and all tools check the BuildAllExamples_*.sln files in the examples folder. + +For newer VS versions you have update one of those projects (VS usually can do that automatically when you open an older solution file). + +Currently each of those solutions does set the platform toolset "Windows 7.1 SDK" (to be compatible to each other). +You might want to change that in the project settings and set it to your current version. +Make sure you use the same platform toolset in your application and in the engine. +Also when compiling examples each example has to use the same platform toolset as was used for the engine. + +Platform should be Win32 +Configuration is by default "Release" +But you can also chose "Debug" if you want Irrlicht with Debug information. +Static builds are possible but you have to additionally set the _IRR_STATIC_LIB_ define in the application when linking to a static Irrlicht.lib + diff --git a/bin/Win32-gcc/irrlicht.ico b/bin/Win32-gcc/irrlicht.ico new file mode 100644 index 00000000..49f8eabb Binary files /dev/null and b/bin/Win32-gcc/irrlicht.ico differ diff --git a/bin/Win32-gcc/readme.txt b/bin/Win32-gcc/readme.txt new file mode 100644 index 00000000..f7294d9d --- /dev/null +++ b/bin/Win32-gcc/readme.txt @@ -0,0 +1,16 @@ +If you wish to compile Irrlicht for Win32-gcc you have several choices. + +1. You can work from within a MinGW shell. +Go to the folder source/Irrlicht and run the Makefile with: +make win32 +Examples can be build by going into the folder of the example (for example examples/01.HelloWorld) and running the Makefile with: +make all_win32 + +2. Use the Code::Blocks IDE +There is a project file called Irrlicht-gcc.cbp in source/Irrlicht to compile just the engine. +Be sure to select a Windows target like "Win32 - release - accurate math - dll" + +There is also Code::Blocks workspace file in the examples folder called BuildAllExamples.workspace +Again be sure to select a Windows target like "Win32 - release - accurate math - dll" +This workspace allows you to compile the engine together with all examples and tools. + diff --git a/bin/Win64-VisualStudio/irrlicht.ico b/bin/Win64-VisualStudio/irrlicht.ico new file mode 100644 index 00000000..49f8eabb Binary files /dev/null and b/bin/Win64-VisualStudio/irrlicht.ico differ diff --git a/bin/Win64-VisualStudio/readme.txt b/bin/Win64-VisualStudio/readme.txt new file mode 100644 index 00000000..063b5e71 --- /dev/null +++ b/bin/Win64-VisualStudio/readme.txt @@ -0,0 +1,24 @@ +The Win64-VisualStudio version is currently (Irrlicht 1.8) compiled with VS 2010 using the Windows 7.1 SDK as platform toolset. +You might get the necessary Windows Platform SDK here: http://msdn.microsoft.com/en-us/windows/bb980924.aspx + +To link to that Irrlicht.dll you need to set platform toolset in your VS version to the same target or re-compile the Irrlicht.dll using another platform toolset. + +To re-compile Irrlicht for Win32-VisualStudio: +There are several project files for different VS versions in source/Irrlicht. +Irrlicht10.0.sln is for VS 2010 +Irrlicht11.0.sln is for VS 2012 +Irrlicht12.0.sln is for VS 2013 + +To compile Irrlicht + all examples and all tools check the BuildAllExamples_*.sln files in the examples folder. + +For newer VS versions you have update one of those projects (VS usually can do that automatically when you open an older solution file). + +Currently each of those solutions does set the platform toolset "Windows 7.1 SDK" (to be compatible to each other). +You might want to change that in the project settings and set it to your current version. +Make sure you use the same platform toolset in your application and in the engine. +Also when compiling examples each example has to use the same platform toolset as was used for the engine. + +Platform should be Win64 +Configuration is by default "Release" +But you can also chose "Debug" if you want Irrlicht with Debug information. +Static builds are possible but you have to additionally set the _IRR_STATIC_LIB_ define in the application when linking to a static Irrlicht.lib diff --git a/bin/emscripten/readme.txt b/bin/emscripten/readme.txt new file mode 100644 index 00000000..36c09160 --- /dev/null +++ b/bin/emscripten/readme.txt @@ -0,0 +1 @@ +If you wish to compile Irrlicht for emscripten please check the documenation in examples/01.HelloWorld_emscripten. diff --git a/changes.txt b/changes.txt new file mode 100644 index 00000000..e86cc1a5 --- /dev/null +++ b/changes.txt @@ -0,0 +1,5467 @@ +-------------------------- +Changes in ogl-es (not yet released - will be merged with trunk at some point) + +- Add support for (experimental) WebGL1 driver for emscripten (still work in process) +- Add support for emscripten. Thanks @labsin for the patch. +- Add IVideoDriver::getAmbientLight function so shaders can access global ambient light easier +- Merge material changes for COGLES1MaterialRenderer_LIGHTMAP and COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL which had been done in OGL in trunk (r2740) to ensure materials look the same on all platforms. +- Added support for PVR textures. Loader offer support for compressed DXT1-5, PVRTC/PVRTC-II, ETC1/ETC2 texture formats. + +-------------------------- +Changes in 1.9 (not yet released) +- Fix bug that AnimatedMeshSceneNode ignored ReadOnlyMaterials flag when checking materials for transparent render passes. +- Unify checks if materials should use transparent render pass with new IVideoDriver::needsTransparentRenderPass function. +- Material.ZWriteEnable is now of type E_ZWRITE instead of bool. This allows now setting materials to always "on" independent of material type and transparency. + This breaks compiling. To have old values replace false with EZW_OFF and true with EWZ_AUTO. +- Materials EMT_REFLECTION_2_LAYER and EMT_TRANSPARENT_REFLECTION_2_LAYER on OpenGL are now same as in D3D9. Before GL used a sphere-map for those instead of reflection. +- Bugfix: CGUIToolBar automatic placement no longer outside of screen when there are modals screens when creating it. + Or when there are other window elements going over full window-size. + Thanks to Stephen Lynx for the bugreport and to Srgio Augusto Vianna for writing a test case with a bug example. + Changes: a) Never move the toolbar below it's parents lower border. b) No longer check all element-types, but only try to be below other toolbars or menues. +- Add a normalType parameter to IGeometryCreator::createCylinderMesh +- Add a normalsUpdate parameter to IMeshManipulator::transform to allow updating the normals with the inverse-transpose of the transformation matrix. +- Bugfix: quaternion::slerp now uses lerpN instead of lerp to keep result normalized. +- Add function quaternion::lerpN which is like lerp but normalizes the result. +- Add function ISceneManager::createShadowVolumeSceneNode to allow custom ISceneNode's to use shadows. +- CGUITabControl serialization changed to allow using custom tabs (before only CGUITab could be serialized). + There was a lot of rewriting involved, including some minor interface changes (IGUITab* can now be added directly for example). + See http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=52344 for a thread about this. + Thanks @chronologicaldot for bringing this up, writing a patch proposal and even writing test. +- CGUITabControl no longer eats EMIE_LMOUSE_PRESSED_DOWN (doesn't seem to need it, was just done for a planned feature which is not implemented yet). +- Removing a tab in CGUITabControl will now also remove the tab-element. Fixes problems like tabs still being around & visible when you removed the active tab. +- Add example 28.CubeMapping. + Based originally on EnvCubeMap example from irrSpintz engine. + Including a cubemap texture from Emil Persson, aka Humus from http://www.humus.name +- IGeometryCreator::createCubeMesh has a new parameter to allow creating different types of cube meshes. + Added a new cube-mesh with meshbuffers per side. + Also single buffer cube-mesh now normalizes it's normals. +- Bugfix: CBillboardTextSceneNode no longer disregards IsVisible flag +- FPS-camera rotation now smoother. + First bug was that it would sometimes skip back because it worked with wrong values for the screen-center position. + Second (and bigger) bug was that it ignored all cursor-movement which happened between device->run() and the point where + the animator did run. Tiny side-effect your camera will now rotate generally faster. +- Fix ms3d loader to work on big endian systems which need floats to be aligned in memory. Thanks @ kas1e, Corto and Salas for the patch (http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=52538). +- Bugfix: COBJMeshFileLoder no longer overwrites transparency value with 1.0 when it's set before the diffuse color value in the mtl file. Thanks @Boshen for bugreport (#445). +- Bugfix: OpenGL no longer antialiasing stencil buffer when driver has antialiasing disabled. +- Add IShadowVolumeSceneNode::setOptimization to allow disabling optimizations for meshes were contour shadows fail. +- Stencil shadows work now also with directional light +- Add example 27.PostProcessing written by Boshen Guan +- Drivers can now try to create textures from images in more exotic color formats (like floating point formats). It depends on the driver how much that works (so far mainly OpenGL can handle it somewhat). +- Fix OpenGL to no longer switch colors red and blue in 24-bit RGB format. But warnings added to documentation to avoid 24-bit textures as they are generally just trouble. +- No longer try to convert ECF_R5G6B5 to ECF_A1R5G5B5 on OpenGL (just made texture-loading seem to fail). +- Add flag SIrrlichtCreationParameters.WindowResizable. Mainly to work around troubles with SDL+OpenGL on some platforms where resizing later can be tricky/impossible. +- Add operator[] to vector2d and vector3d +- Bugfix: IrrlichtDevice::isWindowMinimized no longer returns true when it's maximized on Windows. +- Ignore degenerated faces in obj file loader when they would generate triangles where 2 vertices use identical indices. +- Add CMatrix4::transformVec4 to transform vectors with 4 elements (thx @ devsh) +- Add ITexture::getOriginalColorFormat to access color format of images used to create a texture +- Add IMemoryReadFile interface which allows direct access to memory block used as file. +- Add IReadFile::getType() interface to all users to find out what kind of class implements that interface. +- .dae/Collada reader/writer now handle whitespace in texture-filenames with escape characters (handle them as xs:anyURI). +- Add function string::insert. +- EditBox now still allows overwriting characters when the text-length is at max. +- Bugfix: CMatrix4::transformPlane was calculating the wrong plane-normal before. +- SViewFrustum::recalculateBoundingBox no longer includes camera position in the bounding-box. Only using frustum corners now. Thx @DevSH for bugreport & patch. +- Camera uses now OGL projection matrices with OpenGL driver. Fixes wrong near-plane values with OpenGL (showed too much before). +- Add a flag to most CMatrix4::buildProjectionMatrix functions to allow creating OpenGL projection matrices (target range of -w to w instead of 0 to w). +- Bugfix: CCameraSceneNode resets the IsOrthogonal flag to false now when it recalculates a projection matrix. +- SViewFrustum::setFrom and SViewFrustum constructor now use a parameter to allow to set the correct near clipping plane when the projection matrix doesn't use a target depth range of 0 to z, but for example -z to z. So OGL projections matrices can now also use it. +- Remove code to read boundingbox element in Collada reader as it's not in Collada specification. +- .dae/Collada reader now converts from Collada's right-handed to Irrlicht's left handed coordinate system (switching z to -z) +- Add irr::string::eraseTrailingFloatZeros to kick out trailing 0's for strings generated from floats. +- .dae/Collada writer now converts from Irrlicht's left-handed to Collada's right-handed coordinate system (switching z to -z) +- Switch Collada writer to utf8 xml's. +- Add IXMLWriterUTF8 +- IColladaMeshWriter::writeScene got an additional flag to decide if root should be written. +- _IRR_MATERIAL_MAX_TEXTURES_ now set to 8 by default. So we can use now 8 textures per material without recompiling the engine. + Additionally there's a new global variable irr::video::MATERIAL_MAX_TEXTURES_USED which can be set to lower numbers to avoid most of the costs coming with this for people not needing more textures. + But using more textures via _IRR_MATERIAL_MAX_TEXTURES_ also has become less calculation intensive than it was in the past, so in release builds the difference is hardly noticeable. +- Serialization fixes for materials in irr format (in IVideoDriver::createAttributesFromMaterial/fillMaterialStructureFromAttributes). +- Add serialization for ToolTip to IGUIElement. Thanks @chronologicaldot for patch (http://irrlicht.sourceforge.net/forum/viewtopic.php?f=2&t=52374) +- Try recovering lost device in D3D9 for 3 seconds when device reset fails after resizing Window. +- Add typedefs like value_type and size_type to array, list and map like std containers have. Thanks @SLC for idea (http://irrlicht.sourceforge.net/forum/viewtopic.php?f=1&t=52363) +- Remove unused enum E_LOST_RESOURCE +- CGUIComboBox uses now EGDS_SCROLLBAR_SIZE instead of EGDS_WINDOW_BUTTON_WIDTH for the width of the listbox button to allow changing that without changing window topbar height. + Thanks @LunaRebirth for reporting. (Forum: http://irrlicht.sourceforge.net/forum/viewtopic.php?f=1&t=52297&p=303682#p303682) +- CGUIListbox, CGUITreeView and CGUITable now resize scrollbars when EGDS_SCROLLBAR_SIZE in the skin changes without having to re-create the elements. + This also fixes the problem that drawing looked wrong when this value got changed after the elements were created. + Thanks @LunaRebirth for reporting. (Forum: http://irrlicht.sourceforge.net/forum/viewtopic.php?f=1&t=52297&p=303682#p303682) +- Scrollbar buttons can no longer get larger than half the ScrollBar element to avoid them overlapping. +- Add IVideoDriver::swapMaterialRenderers to allow swapping the renderer used to render a certain material. +- IMeshManipulator functions createMeshWith1TCoords, createMeshWith2TCoords and createMeshWithTangents no longer weld vertices while converting meshes. Use IMeshManipulator::createMeshWelded if you need that welding. +- Add ITerrainSceneNode::setFixedBorderLOD to handle connecting terrain nodes without gaps. Thanks @diho for the bugreport, testcase and a patch proposal (http://irrlicht.sourceforge.net/forum/viewtopic.php?f=9&t=51220). +- PLY loader now works with files which use "st" instead of "uv" for texture coordinates (like generated from Blender or Assimp). Thanks @JLouisB for patch (http://irrlicht.sourceforge.net/forum/viewtopic.php?f=9&t=52261). +- STL writer does now also write binary files when EMWF_WRITE_BINARY flag is used. Based on patch from JLouisB (http://irrlicht.sourceforge.net/forum/viewtopic.php?f=9&t=52261). + (EMWF_WRITE_COMPRESSED also still works for downward compatibility) +- Improved PLY exporter. Thanks for Patch from JLouisB. (Forum: http://irrlicht.sourceforge.net/forum/viewtopic.php?f=9&t=52261): + - Support for UV and vertex colors. + - Support for binary PLY files export with the EMWF_WRITE_BINARY flag + - Fix for the meshes with 32 bits index +- Fix wrong colors on big endian platforms with burnings renders. Thx @kas1e for reporting and @curaga for the patch (#318). Forum bug discussion at http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=52177. +- Fix bug #440 where OpenGL driver enabled second texture for single-texture materials when setMaterial was called twice. Thx@ "number Zero" for bugreport and test-case. +- Irrlicht icon now loaded with LR_DEFAULTSIZE to better support larger icon requests. Thx@ luthyr for report and bugfix. +- Cursor on X11 behaves now like on Win32 and doesn't try to clip positions to the window +- IImage::copyToWithAlpha has a new parameter to allow combining alpha value instead of replacing them. This uses new blitters called BLITTER_TEXTURE_COMBINE_ALPHA. Thx @chronologicaldot for providing this patch and @burningreggae for his feedback. +- Add _IRR_COMPILE_WITH_PARTICLES_ to control compilation of particle system +- Add IGUIImage::setDrawBackground to allow disabling background drawing even when no texture is set. +- Fix: IGUIContextMenu now raises sub-menu when they would otherwise be displayed below bottom-border of root gui element. +- Prevent initializing/quitting SDL several times when using more than one Irrlicht device. +- Reduce log-messages for "loaded texture" and "loaded mesh" from ELL_INFORMATION to ELL_DEBUG. +- Add IGUIButton::setOverrideColor to allow overriding text-color (same function as statictexts and editboxes have). +- Add functions IGUIButton::getClickShiftState and IGUIButton::getClickControlState to get shift/ctrl key-state when a button was clicked. Thanks @StarSonata for patch. +- Add function ISceneManager::clearAllRegisteredNodesForRendering. +- Add function IVideoDriver::queryTextureFormat to allow checking if a driver supports textures with a specific color format. +- ISceneManager::getMesh can now creates meshes with alternative cache-names. +- Lets the BSP loader find textures inserted with relative paths. Thx@ curaga for patch +- Slightly simplified ALLOC_STRATEGY_DOUBLE in arrays +- Add alternative BoundingBox calculation for BillboardSceneNode which can take in a camera node. Thx @Seven and @JacKDuRdEn for bugreports. +- FPS camera now supports keyboard rotation. +- Base FPS-camera movement on last position of mouse instead of always center (works better on platforms where cursor-placement is not allowed) +- Octrees with other vertex types than EVT_2TCOORDS can now also use VBO's. +- Add IOctreeSceneNode interface to control polygon clipping checks for octree scene nodes. +- Add support for different geometric primitives to meshbuffers. Thanks @gerdb for patch proposal (http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=45999) +- change SEvent::SUserEvent.UserData1 and SEvent::SUserEvent.UserData1 from s32 to size_t to avoid cutting numbers on some 64-bit platforms (SDL and Windows) +- Improve speed of draw3DBox (OpenGL and D3D9). Thanks @zerochen for patch (https://sourceforge.net/p/irrlicht/patches/256) +- Support more keys on OSX "[]\". Thanks @neoascetic for patch (#313). +- Fix IBillboardTextSceneNode::setTextColor which did nothing in the past. It now maps to setColor instead. +- Add access functions to IBillboardTextSceneNode (getText, getFont). +- Add access functions to ITextSceneNode (getText, getTextColor, setFont, getFont). +- Try harder to move Window to custom WindowPosition set in SIrrlichtCreationParameters on X11. Thx@ Hernan Ezequiel Di Giorgi for the patch (#304). +- Fix bug in virtual filessystem which prevented createFileList from working. Thx @Cube for reporting a problem. +- ITriangleSelector now can also return meshbuffer collision information. +- core::string::split now adds delimiter to token before delimiter when keepSeparators is true. That way we never end up with 2 tokens for an original string with a single character. +- Bugfix: SMesh::recalculateBoundingBox() does now ignore empty boundingboxes of meshbuffers instead of adding them. +- IIrrXMLReader::getAttributeValueAsInt and IIrrXMLReader::getAttributeValueAsFloat can now return a custom default-value when the attribute is not found. +- core::string::split now handles ignoreEmptyTokens=false correct. Thanks @manni63 for bugreport: http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=51551&p=299375#p299375 +- Bugfix: Previously when some material had a texture matrix and another didn't those materials were still considered identical. Which had prevented correct switching between materials with and without texture matrices. +- IWriteFile::write now returning size_t (like fwrite in c-lib). Also sizeToWrite parameter changed from u32 to size_t. +- IReadFile::read now returning size_t (like fread in c-lib). Also sizeToRead parameter changed from u32 to size_t. +- add clear function to strings. +- Collision manager now using const camera pointers. +- Several fixes for SceneNodeAnimatorCollisionResponse, based on http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=33098&p=290746 + Thanks to all people who reported and to JLouisB and kinkreet for the patches: + - Gravity is now fps independent + - Values of gravity now like documented (wasn't 1 unit = 1m before, had been 1m = current frames per second, so maybe 100 units = 1m). + Note that jump-values for fps-camera must also change when adapting gravity! + Several examples got adapted for new ranges. + - Pausing timer now pauses animator. Also doesn't reset values anymore with pauses. + - Clones no longer have 1000 times the gravity of original animator. + - Should now be fps independent +- Speedup CTriangleSelector (mainly for animated meshes) +- CTriangleSelector now supports 32-bit meshbuffers. Thanks @Wol101 for reporting and patch-proposal. +- Fix: CTriangleSelector no longer resets it's boundingbox to 0,0,0 (was wrong when a meshbuffer was not around 0) +- Fix: Collada writer now uses wrap_p for third texture wrap value instead of invalid wrap_w (thx @Yoran for bugreport) +- Several getter functions in IAttributes made const (thx @Erik Schultheis for the patch) +- Fix: CTriangleSelector no longer ignores meshbuffer transformations from skinned meshes (thx @AlexAzazel for report and test-model). +- Randomizer now returns range 0..randMax as documented and no longer 1..randMax as it did before. randMax got reduced by 1. + Note: You will generally get different numbers than before! If you need the exact old calculations, please check the corresponding sources in Irrlicht 1.8 in os.cpp/.h +- Resetting Randomizer with 0 or no longer breaks it (will be set to 1). Same for other numbers for which it wasn't defined. +- Add SMaterialLayer::TextureWrapW for cubemap texture wrap mode at W axis. +- Add cubemap texture support for D3D9 and OpenGL drivers. +- Do no longer re-calculate md2 frames when they don't change (thx @npc for reporting) +- Add multibyteToWString wrapper functions around mbstowcs which work with Irrlicht string class. +- Fix: addFileArchive now grab()'s the archive when you pass one in by pointer. +- Fix: Prevent division by 0 in CGUIScrollBar::setPos +- Fix: Add missing serialization to CSceneNodeAnimatorCameraFPS and CSceneNodeAnimatorCameraMaya +- Fix: File-open dialog now restores the original locale after modifying it internally +- Fix first calculation of the camerascenenode boundingsphere. +- Fix bug with ignored opening brace in .X files with DeclData section. Thx @Alin for bugreport and patch. +- Fix problem with OpenGL textures cache. +- Add clear buffer flags and marked some methods used for clear buffers as deprecated. +- Fix skinned meshes not playing their last frame. Also clarified animation documentation to describe current behavior more exactly. +- Add IWriteFile::flush interface (thx @ JLouisB for the patch). +- CLightSceneNode::updateAbsolutePosition does now light recalculations. This is to fix using animators with lights. +- Fix Collada export for objects with rotations around more than 1 axis. +- Add ISceneNodeAnimatorCameraMaya::setTargetMinDistance and getTargetMinDistance. +- Add override font to IGUITreeView +- CGUIComboBox now updates selection-list when font changes while it's open (thx @ rubixcuber for bugreport) +- CAnimatedMeshSceneNode::setMesh does now set the animation speed again to that of the mesh (had been changed in 1.7, but not for obvious reasons) +- .x meshloader regards now AnimTicksPerSecond (thx @qian for a test-model and bugreport) +- Interface getMeshType moved from IAnimatedMesh up to IMesh. +- Add b3d mesh-writer. Static writer written by Hendu, support for animated meshes added by JLouisB, testing and bugfixes by CuteAlien. +- Node-collision functions of SceneCollisionManager like getSceneNodeFromScreenCoordinatesBB will now ignore collisions against empty boundingboxes. +- Cameras return again an empty boundingbox (at 0,0,0) instead of returning the frustum boundingbox (was changed in very old Irrlicht version). + You can access the frustum boundingbox through the frustum itself. + This means cameras no longer show up in the node-collision of the SceneCollisionManager (showing up there because of their frustum bounding-box was too confusing). +- Fix problem in IrrlichtDevice::setResizable on X11 that caused window titlebars to hide occasionally under the taskbar in some systems (Ubuntu, Mint). +- Added new IRenderTarget interface. +- Replace the swprintf and snprintf defines by swprintf_irr and snprintf_irr to avoid conflicts with the standard libraries (and other libraries). +- XBox support removed as it would need DX8 (this was about the original XBox). +- Support for Direct3D 8 removed after svn revision 5052 due to lack of maintenance. +- _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX removed. This was a bugfix for VS2003 (in combination with .NET) which we haven't supported in a while. +- VS 2005 support removed after svn revision 5048. +- WinCE 6 supported removed after svn revision 5046. +- NVidia CG support removed after svn revision 5045 due to lack of maintenance. NVidia has also stopped supporting this. +- TA burningvideo: + enabled triangle fan again so that skybox works.[need more testmeshes if other trianglefan than skybox doesn't work] + correct vc2013 project files for x64,static lib + correct alphablend vs add [was broken] +- Add a new core::rect constructor which takes a dimension parameter and set's left-top to 0. +- mtl (obj) format reader and write now regards texture scaling and translation. (thx @thanhle for noticing and patch proposal). +- Added Visual Studio 2013 project files. +- Added new color formats: ECF_R8, ECF_R8G8, ECF_D16, ECF_D32, ECF_D24S8. +- Can now enable/disable background drawing for IGUITable. +- Bugfix: Cloning CBillboardSceneNode now copies colors and sizes. +- EditBox works now with numpad on X11 +- Added helper functions for converting between wchar and utf-8. Patch provided by Hendu. +- Added sphere frustum culling support. Patch provided by Hendu. +- Fixed issues with setViewPort method under OpenGL. (reported by anontypist) +- Fixed several selection, highlighting and clipping bugs in CGUITreeview (thx @ AReichl for the patch + test) +- Removed DllMain from the static windows build (thx @ AReichl for reporting) +- Fixed maximize/minimize under Linux by supporting NETWM hints. Patch provided by hendu. +- ISceneNode::deserializeAttributes uses now old values for parameters which are not in the attributes (thx @entity for noticing). +- Add interface for easier access to scrollbars for IGUIListBox, IGUITreeView and IGUITable +- Fix serializing colors as strings. Was previously mixing up strings with number-arrays and hex color values. Now using hex color values always, but also fixed the the handling when it get's number-array strings. +- Fix IAttributes::setAttribute implementation for textures (did do nothing before). +- Added support for separate blending in OpenGL and D3D9 drivers. +- Added pack_textureBlendFuncSeparate and unpack_textureBlendFuncSeparate functions, which allow to use separate blending functions in OpenGL. +- Added BlendFactor field to SMaterial which allow user to set blending factor per SMaterial set call without use EMT_ONETEXTURE_BLEND type. +- Fixed issue with blending operation set to EBO_NONE and some transparent material types. +- Add a code profiler (stop-watch style) +- Add IGUITable::getItemHeight to access item (row) height +- Add override font to IGUITable +- IGUITable can now disable the active column. +- IGUIElement::getElementFromPoint now virtual +- Fixed issue with wrongly enabled Z-writing for transparent shader materials. Thanks Hendu for this fix. +- Allow more control over particle behavior. This also changed the default behavior. +- ISceneNodeAnimators can now be disabled and paused. +- Maya camera no longer get's stuck in "rotating" state when a mouse-up event is lost (thx @ JLouisB for reporting). +- Focus behavior of IGUIEnvironment now controllable (right-click focus, mouse-over focus). Disabled elements no longer get the focus unless users enforce it. +- Buttons can now now have 7 more image-states, 1 more sprite-state and the sprites are now scaleable. +- Spritebanks can now draw scaled sprites and are a little easier to use. +- Improved i18n key input for X11 (languages like cyrillic work now). +- Fix bug that ListBox would not allow to 'tab' to the next element (thx @ FlavourBoat for reporting) +- IGUIEnvironment::getNextElement now public (was only in CGUIEnvironment before). +- Add an overwrite mode to editbox. Patch provided by Adam(aka kingadami). +- Add IGUIImages::setDrawBounds/getDrawBounds to allow coding stuff like progress bars. +- Add IGUIImages::setSourceRect/getSourceRect to allow using only parts of an image (can also be used to mirror and scroll them). +- Dev-Cpp project file removed (wasn't really supported for some time already) +- Collada dae-loader now set's the vertex colors (thx @sf17k for report and test-models) +- IAttributes interface changed. Parameters are now passed by const-ref instead of per value. +- Fix c::b project obj folder names. Some static builds had used the shared folders (thx @ gerdb for reporting) +- Add ITexture::getSource which can be used to check where the last IVideoDriver::getTexture call found the texture. +- Add IMeshTextureLoader interface and replace texture-loading algorithms in most meshloaders. +- CGUICheckBox no longer gives up focus on EMIE_LMOUSE_LEFT_UP (thx @Demre and @REDDemon for reporting) +- Bugfix: IGUIElement::addChild now prevents setting an element as it's own child. +- GUI editor improvements (prevent crash, improve UI) +- Add IrrlichtDevice::setWindowSize. +- Bugfix: getFont for xml-fonts now also works for fonts inside archives (thx @Neirdan for bugreport) +- Added function irr::core::mergeFilename +- Add ISceneNodeAnimator::setStartTime/getStartTime to allow resetting movement animators. +- Improve speed for finalizing skinned meshes (removal of unnecessary frames after loading) (thx @ichtyander for the testmodel) +- Collada loader now instantiates camera nodes which had been ignore so far (thx @NemoStein for the test .dae) +- line2d::intersectWith has a new parameter to allow ignoring intersections with coincident lines +- vector2d::equals now has an tolerance parameter for passing the epsilon (like vector3d had). Note that this changes the default + behavior of vector2d::equals as well as functions using it like the operators for ==, !=, <, >, <=, >= when using vector2d with f64 + as the tolerance is increased in that case (for f32 and integer values it shouldn't make any difference). +- Material renderers which offers blending feature (eg. EMT_TRANSPARENT_ALPHA_CHANNEL, EMT_ONETEXTURE_BLEND etc.) require SMaterial::BlendOperation set to other value than EBO_NONE. +- Removed support for built-in T&L variables in ASM/GLSL shaders (variables related to vertices eg. gl_MultiTexCoord0 are still supported). This change allow us to reduce CPU overhead in shader material renderers. +- IGUIEnvironment::hasFocus has now a parameter checkSubElements as subelements are usually seen as part of an element. Default unfortunately must be false due to backward compatibility. +- Add IGUIElement::isTrulyVisible which works like ISceneNode::isTrulyVisible and checks for parent visibility as well. +- Improved DDS loader and added support for DXTn (DXT1-5) compressed textures in OpenGL and Direct3D9 drivers. +- Add function ISceneNode::getTransformedBoundingBoxEdges. +- Improve automatic compiling under Solaris (proposed by curaga) +- Add in IGUICheckBox: setDrawBackground, isDrawBackgroundEnabled, setDrawBorder, isDrawBorderEnabled +- IGUISpinBox now passes on the EGET_BUTTON_CLICKED, EGET_EDITBOX_CHANGED and EGET_EDITBOX_ENTER events from it's sub-elements. +- IGUISpinBox no longer validates values after each character type but only on KEY_ENTER and when losing focus. New behavior can be set with IGUISpinBox::setValidateOn +- IAttributes::getAttributeAs functions now can have a customizable default-parameter to return when attributeName is not found +- Added ECFN_DISABLED value (it works like ECFN_NEVER worked before) and changed ECFN_NEVER behaviour + (it works like its equivalent value in OpenGL/Direct3D). +- Removed boolean interface from IShaderConstantSetCallBack, please use integer interface instead of them. +- Add a LeakHunter class which can be enabled with compile-flag _IRR_COMPILE_WITH_LEAK_HUNTER_ to find leaking IReferenceCounted objects. +- Add _IRR_COMPILE_WITH_XML_ define to allow compiling Irrlicht without xml (patch written by curaga) +- Add functions to set/get cursor character and blinktime to IGUIEditBox +- Collada exporter calculates values for orthographic camera now on export +- Collada exporter now exports the camera up-vector correctly. +- Add IColladaMeshWriter::findGeometryNameForNode +- Add getters IGUIButton::isDrawBorderEnabled and IGUIButton::isDrawBackgroundEnabled + +- changed CSkyBoxSceneNode to drawIndexedTriangleList instead of drawIndexedTriangleFan (because software renderers don't have fans.. and i needed the demo functionable) +- added x64 to vs2008 project ( buildAllExamples_v9 ) [paths: obj64, win64-visualstudio] +- burningvideo: getMaxTextureSize adjusted [ changed meaning of SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE +- burningvideo: mipmaplevel adjusted ( not that bad bokeh...(sometimes) ) + +-------------------------- +Changes in 1.8.5 + - Fix CIrrDeviceSDL::getVideoModeList which didn't return video modes before. Thx @kas1e for report and patch. + - CIrrDeviceMacOSX now sets the SEvent.MouseInput Shift and Control values on mouse events like the other devices. Thanks @ Zero King for patch (#321) + - isWindowFocused in IrrDeviceSDL device now returns the input focus like the other devices. Before it was returning a mouse-over-window state. + - Prevent SDL device from dropping OpenGL resources on Win32 when setResizable was called with OpenGL driver. Thanks @ kas1e for reporting (http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=52083&start=0) + And thanks to http://www.bytehazard.com/articles/sdlres.html for the workaround. + - Fix isWindowActive when using SDL device. Before it was only active when the mouse was over the window. Thanks @ kas1e for reporting (http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=52083&start=0) + - Fix SViewFrustum::clipLine. Was before clipping at wrong points (inverse places along lines). + - Fix compilation on OSX and prevent capturing mouse cursor when Window is not on top (Patch #319) + Thanks at Artem Shoobovych for bugreport and patch (https://sourceforge.net/p/irrlicht/patches/319/) + - Fix serialization of OverrideTextColorEnabled flag in CGUITab. Thanks @ chronologicaldot for reporting (http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=52344&p=303891#p303891) + - CFileSystem::getAbsolutePath no longer wrongly converts an empty filename to "/" on unix platforms. + This fixes the bug that CFileSystem::createAndOpenFile("") returned a (strange behaving) non-null file pointer. + Additional check also added in createAndOpenFile to early out on empty names. + - Fix bug in cursor positions when compiled with newer Windows SDK's (v110 in VS2012) and running on Systems >= Windows Vista in windowed mode. + Thanks @Mustapha Tachouct for the bugreport and patch proposal. Also thanks @BakeMyCake for an earlier report. + - IOSOperator::getSysteMemory() no longer returns incorrect values with >2GB. Thanks @Eduline - human development for report and patch. + - Increase KEY_KEY_CODES_COUNT to fix problem with laptop keyboards which return the keycode 0xff for the function key. Thx @Klokancz for bugreport and patch. + - Fix bug when calling activateJoysticks on windows several times. It had appened joystick information instead of replacing it, thereby increasing joystick number on each call. + Only happened compiling with _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ (which is the default). Linux and SDL implementation not affected. + Thx @Andrea Demetrio for the bugreport. + - Fix bug in fast_atof when reading floating point numbers with more than 16 digits past the dot. Those produced completely wrong results (sometimes even causing INF numbers). + This bug also did cause many meshloaders to have problems with certain meshes (basically all text-based formats are affected). + - Accuracy of fast_atof is back to older Irrlicht versions (fixes test warnings, usually not a noticable problem). + - Fix crash in eventhandling when calling remove() on a contextmenu while it has focus. + - CImageLoaderJPG::isALoadableFileFormat uses a test which allows to load more jpg formats (for example uncompressed jpg's). Thx @Yaron Cohen-Tal for report, test-image and his help with the patch. + +-------------------------- +Changes in 1.8.4 (9th July 2016, svn r5321) + - Tests on Unix now have a short pause between switching drivers to avoid certain X11 errors. + - Fix CEnumAttribute::getInt() which could crash (thx @ luthyr for reporting) + - No longer try to run tests for drivers not supported on a platform + - Update lights and renderTargetTexture tests to work with Windows 10 (can't have so tiny Windows anymore). + - Deprecate CMatrix4::transformBox as the result is no longer a boundingbox. Use CMatrix4::transformBoxEx instead (which has been available for a long time). + - Fix CSceneCollisionManager::getPickedNodeBB which could sometimes miss collisions. + - Add -U__STRICT_ANSI__ option to c::b project files to allow compiling with -std=c++11 and add an error when trying to compile with Irrlicht with __STRICT_ANSI__ + - Update libpng to 1.6.23 + - Update zlib to 1.2.8 + - Fix some compile warnings in aes which got handled as errors by some c++11 compilers. + - Get rid of some misleading-indentation warnings in gcc6 + - Fix serialization of the InputReceiverEnabled flag in CCameraSceneNode + - Fix pasting text from X11 applications to Irrlicht. Thanks @est31 for the patch. + - Tests give now a warning when stabilizing screenshots failed. Aslo trying more often now (a hack as taking screenshots otherwise fails often in windowed mode on some systems). + +-------------------------- +Changes in 1.8.3 (13.9.2015) + - Fix the fix for compiling on GCC5 (thanks to est31 for report and patch) + +-------------------------- +Changes in 1.8.2 (30.8.2015) + + - Add VS2013 project files + - Fix compiling with IRR_LINUX_XCURSOR_ + - Fix compiling with NO_IRR_COMPILE_WITH_LIBJPEG_ (thx to anontypist for report and patch). + - Fix compiling on GCC5 on MinGW (thanks to Slipxy for finding the bug and to osense for reporting it). + - Fix loading of .X and .B3D models with non-normalized quaternion rotations (thanks to JLouisB for a test-model). + - Fix compiling on Free BSD (thanks to leper for reporting and patch) + - Fix bug with multiple SetPixelFormat calls. (reported and fixed by anontypist) + - Fix bug related to memory release in PNG image loader. Thanks elephoenix for it. + - Fix crash in CGUIListBox when users pressed end key folled by any other key in an empty, focused list box (thanks at porcus for report and patch). + - Fix use of enabling defines for wal2 (halflife) image loader. Thanks to hendu for noticing. + - Fix userClipPlane test by inserting the stabilizeScreenBackground call + - Demo enables antialiasing now correct (thanks to Mel for noticing). + - Update glext.h (bug #429) + - Example 22 no longer select a random texture after loading a new texture (thanks at mongoose7 for reporting). + - Fix bug in IGUISkin serialization which messed up serialization of the button-pressed offsets (thanks at Midnight for reporting). + - IGUIStaticText::getTextHeight returns now the correct height for texts with newlines even WordWrap is not set. + - Crashfix for CGUIEditBox. CGUIEditBox::setMultiLine must break text when changed or other functions like getTextDimension can crash afterward for strings with newline characters. + - CGUIEditBox and the GUI-Editor now convert pasted text correctly using mbstowcs. + - C::B project files work again on newer Linux-distributions which have cleaned up their dev-lib dependencies. + - Makefile for the new IrrFontTool links now correctly to libfontconfig + +-------------------------- +Changes in 1.8.1 (17.11.2013) + + - Improved OpenGL performance under OSX (Thanks devonsoft for reporting). + - Fixed OSX compilation issues. + - [KNOWN BUG] Software driver doesn't work properly under OSX 10.9. + - For speed improvement the following attributes accessible by ISceneManager::getParameters() are no longer updated in release: + "culled", "calls", "drawn_solid", "drawn_transparent", "drawn_transparent_effect". + They can be enabled by compiling Irrlicht with the define _IRR_SCENEMANAGER_DEBUG. + Thanks @hendu for reporting, see http://irrlicht.sourceforge.net/forum/viewtopic.php?f=2&t=48211 for the discussion. + - Fix compile problem with CIrrDeviceSDL on VS2008 (and maybe other systems). Thanks @HellFlip for reporting. + - Fix quaternion::rotationFromTo() (Thanks @takamoto for reporting) + - Fix iszero for s64 (Thanks @chronologicaldot for reporting) + - Fix crash in SoftwareDriver2 when Material was EMT_DETAIL_MAP but texture[1] was not set (Thanks for fix by chronologicaldot) + - Fix buffer overrun in x-loader (Thanks for fix by Otaka) + - Fix cursor visibility update problem under Windows 8 (Thanks @luthyr for reporting) + - Fix irredit links in loadScene/saveScene docs. + - Fix issue in CAnimatedMeshSceneNode::clone which caused a crash. (reported and fixed by luthyr) + - Fix compiling errors for c++ builder (thx @Greatwolf for many patches and @cfanderek for reminding) + - Initialized IColladaMeshWriter::GeometryWriting which was uninitialized. + - Fix linker trouble with irr::core::equalsByUl when compiling Irrlicht as managed code (thx @ Memorial76 for a report + testcase) + - Fix crashes in CCubeSceneNode::clone and CSphereSceneNode::clone (reported by marsupial) + - Fix the clipping in the listbox drawing which was only showing the right line of the sunken pane (reported by Mloren and Abraxas). + - Initialize slider in example 05 correct (reported by Zerochen) + - Fix crash in CMeshSceneNode::clone when the mesh had no shadow (reported by christianclavet, bug-fix found by Nadro) + +-------------------------- +Changes in 1.8 (7.11.2012) + + - Let sphere mesh use full opaque color, just as all the other ones do + + - Gcc on Win32 (MinGW) now also works with the _w file access functions when compiled with _IRR_WCHAR_FILESYSTEM. (thx @ alexzk for reporting compile troubles) + + - Fix a bunch of off-by one errors in irr::core::string in functions equals_substring_ignore_case, findFirst, findFirstChar, findNext, findLast, findLastChar, replace, remove and removeChars. + This prevents some potential memory access errors, find functions no longer try to find the \0, replace no longer replaces the \0 and remove no longer tries to remove it (which did remove the last character instead). + + - matrix4::setRotationAxisRadians added + + - user clipplanes fixed + + - Skip rendering of lines, points, and polygons, as these lead to crahses due to wrong access to the vertex lists. A fix would need major rewrite of the vertex cache, or at least some other render methods. + + - Add mipmap generation for makeColorKeyTexture + + - Add another saveScene overload which allows to pass in a user-created XMLWriter. Patch suggested by eversilver. + + - quaternion conversions to and from matrix4 no longer invert rotations. + To test if your code was affected by this you can set IRR_TEST_BROKEN_QUATERNION_USE in quaternion.h and try to compile your application. + Then on all compile-errors when you pass the matrix to the quaternion you can replace the matrix with the transposed matrix. + For all errors you get on getMatrix() you can use quaternion::getMatrix_transposed instead. + + - CGUIEnvironment::loadGui - loading a gui into a target-element no longer messes up when the gui-file contained guienvironment serialization. + + - Colladawriter now exports materials per node when those are used in Irrlicht + + - Colladawriter now writing matrices for node transformations as old solution did not work with CDummyTransformationSceneNode's. + + - Colladawriter no longer create an extra node for the scenemanger as has that job in Collada. + + - Colladwriter no longer makes all Scenenodes children of ambient-light as that can be parallel on the same layer instead. + + - Colladareader now creates the ambient-light correct instead of creating a point-light for it. + + - Add new parameter to array reallocate function. This prevents a reallocation in case the array would become smaller. As the reallocation operation is quite time consuming, this can be avoided on request now, on the expense of more memory consumption. + + - Add IAnimatedMeshSceneNode::getLoopMode (asked for by JLouisB) + + - CSceneNodeAnimatorCameraFPS now resets the key-input when it was disabled (thx @ gerdb for reporting and patch-proposal) + + - Properly destroy OpenGL resources on linux (thx @curaga for the patch) + + - Fix diplay bux in the attribute-panel of the GUIEditor. Fixes bug 3517314 (thx @Darkcoder for reporting). + + - Allow caching cursor position on X11 to work around slow XQueryPointer calls (thx @Hendu for reporting+patch proposal) + + - Make sure after EGET_EDITBOX_ENTER and EGET_COMBO_BOX_CHANGED event processing no more code is executed for the corresponding editbox or combobox objects to allow clearing the environment on those actions (see comments on bug-id 2995838). + + - Fix string::replace which failed replacing substrings at the end when the replacement was longer + + - Struct packing works now with gcc 4.7 changes on MinGW (thx @Sudi for reporting). + + - Struct packing uses now same solution throughout (by including headers in corresponding places) + + - User can now set characters used for decimal point in fast_atof for localisation. + + - Add parameter useAlphaChannel to second IGUIEnvironment::addImage function. + + - Get rid of unnecessary warning "Could not load sprite bank because the file does not exist" for "#defaultfont". + + - Fix MRT disabling. Bug found and fixed by hendu. + + - core:::array::reallocate returning now immediately when it has nothing to do. Should reduce a lot of memory thrashing on irrArrays. + + - Start mesh animations at first OnAnimate , before start-frame was rather random. Thx @Auria for reporting and patch proposal. + + - renderTargetTexture now working with ECF_R5G6B5 + + - add -fPic in c::b linux fast math shared build. + + - Fix by Auria for starting the animated meshes only at first OnAnimate instead of at random times and animation frames. + + - Add support for MAX_COMBINED_TEXTURES, which allows more texture support than with the original fixed pipeline texture check under OpenGL. Now, more than 4 textures should also work with newer gfx cards and drivers, which often only support 4 fixed pipeline textures. + + - triangle3d::isPointInsideFast now using some epsilon to catch all points on the borders. + + - triangle3d::getIntersectionOfPlaneWithLine calculates now with higher precision for more exact results. + + - triangle3d::isOnSameSide (used by isPointInside) calculates now with higher precision and uses some epsilon to make it work with larger integers and less floating point troubles. Slightly slower now. + + - new function equalsByUlp to test for spacing between floating point numbers. + + - speedup for collada writing. + + - speedup for xml-writing. + + - Fix 8bit grey image TGAs, which were not working due to missing palette. Also switched to RGB8 format, as otherwise a loss in precision would occur. Thanks to Klunk for the error report and a test image. + + - fixed issues with a D3D driver and Aero effects. + + - Fix font-drawing in CGUIButton to use EGDF_BUTTON again (thx @DJLinux for reporting). + + - Add texture cache with proper reference handling. This avoids deletion of textures while still being active on the GPU. Test case and fix by m(att)giuca + + - CFileSystem::removeFileArchive now checking for normalized path + + - Fix zip's with passwords on 64-bit systems (thx @ Dr. Gladman for writing the bugfix) + + - replace asserts in tests with macro assert_log to allow running all tests through on problems. + + - added IGUIElement::setName and IGUIElement::getName (similar to ISceneNode) + + - irr::s64 support + + - line2d::getClosestPoint can now also get the closest point on the line additional to only checking for closest point on the line-segment. + + - avoid division by zero in line2d::getClosestPoint when start- and endpoint are identical + + - Support for sw drivers under OSX + + - Fix font-loading which got broken by fixed xml-loading. Thanks @ pc0de for finding and providing a test and patch. + + - Don't crash draw2DSpriteBatch when it get's no textures. + + - Add support for int passing in setShaderConstant + + - Support for better collada texture wrapping support on loading. + + - Fix for render context change where only the window id is given. We now try to change only the window ID, keeping context and display unchanged. Suggestion by vovo4ka from the forum. + + - XML-reader now ignores all whitespace-only EXN_TEXT elements as old way didn't work in cross-platform way (and arguably also not well on Windows). + + - CXMLReader initializes IsEmptyElement now. + + - line2d::intersectWith and and line2d::getClosestPoint work now also with integers. + + + - line2d::intersectWith and and line2d::getClosestPoint work now also with integers. + + - line2d::getMiddle and line3d::getMiddle work now also with integers. But can be slower for compilers which are not optimizing division by 2 to multiplication by 0.5 for floats. + + - Add Nadro's initial Cg support. Example 10 is enhanced to allow also Cg shaders. + + - Add mipmap support from FBO extension, patch by Nadro. + + - Add vertex optimization algorithm submitted by curaga + + - rename texureBlend functions to textureBlend + + - Add threshold for slerp calculation, switching between linear and slerp at this point. + + - Fix for bug 3401933 - vertex color interpolation with shadow volumes in the scene + + - Fixed bug in button sprites reported by RdR + + - Fixed button state sprite animations for pressed, focused and hovered. + + - Added serialization for terrain smooth factor, patch by RdR + + - Implemented more button states for sprite banks, patch submitted by RdR + + - Add IGUIEnvironment::getHovered to get the element most recently known to be under the mouse cursor + + - Add FPS settings for animated meshes, which allows to push animation speed from files to Irrlicht animation system + + - Maya camera updates + + - Add support for bsp brush entities. Written by Hendu. + + - weighted normals recalculation fixed + + - Billboard improvements + + - API docs updates + + - triangle selector improvements + + - OSX improvements by Auria + + - Add new methods for adding and removing file archives based on ifilearchive pointers. + + - Add getBackgroundColor, isDrawBackgroundEnabled and isDrawBorderEnabled to IGUIStaticText (thx 4 patch from Nalin). + + - Reduction of multiple skinning the same mesh and frame in one render cycle + + - Added ISceneNodeAnimatorCameraFPS::getKeyMap and a new ISceneNodeAnimatorCameraFPS::setKeyMap. + + - CSceneNodeAnimatorCameraFPS uses now SKeyMap instead of SCamKeyMap (structs were identical which was confusing and there wasn't any explanation in comments, so I decided to simplify it). + + - Add some workaround to MeshViewer to show how we can currently fix the FPS-cam when users to alt-tab while moving. We can improve that some day when we have focus-events, but this works for now. + + - Fix LZMA decompression + + - Ply normal fixes + + - HW buffers only support rendering with both vertex and index buffers + + - Enables VBOs for water node + + - Octree support for non-standard vertex meshes + + - Fix rotationFromTo + + - Added ConstIterator + + - Fix for getScreenCoordinatesFrom3DPosition to use proper RTT sizes + + - Add IGUIComboBox::setMaxSelectionRows and IGUIComboBox::getMaxSelectionRows + + - Scenemanager switches from type ESNT_UNKNOWN to type ESNT_SCENE_MANAGER. + + - Add getActiveFont to all elements which have setOverrideFont for cleaner code + + - Add getOverrideFont to all elements which have setOverrideFont to have a consistent interface + + - IGUIEditBox: added missing serialization for Border + + - IGUIEditBox: remove bug that added spaces to the end of each line + + - IGUIEditBox: fix crash that happened when wordwrapping was enabled, spaces were entered beyond the border and then cursor-key was pressed. + + - IGUIEditBox::setDrawBackground added. + + - CGUISkin::draw3DSunkenPane no longer ignores fillBackGround in non-flat mode. Also borderlines are no longer drawn overlapping to avoid ugly corners. + + - CDummyTransformationSceneNode::clone() added. + + - IParticleSystemSceneNode::doParticleSystem now public to allow rendering outside scenegraph. + + - getRelativeFilenames updates and fixes + + - Renamed IOSOperator::getOperationSystemVersion to getOperatingSystemVersion. Changed return type from wchar_t to core::stringc, as that's the internal representation the name is built on. + + - Added IGUITabControl::insertTab, IGUITabControl::removeTab, IGUITabControl::clear and IGUITabControl::getTabAt + + - Add 32bit support to some mesh manipulator methods + + - Fix mipmap locking under OpenGL + + - Improvement of screenshot function to support more color formats and targets + + - getAngle fix to avoid NaNs + + - Available gfx memory output in log messages + + - Improved 2d render settings and caching + + - Initial suppport for sRGB render functions + + - Improved terrain scene node rendering + + - Paletted png image support fixed + + - Gamma settings in image loaders improved + + - Support for relative filenames in serialization + + - Access to selectors inside meta selectors implemented + + - DirectInput joystick support + + - Support for scaling with draw2dimage with burnings video + + - More gl extensions have correctly initialised return values + + - Some fixes for quaternion to euler function + + - Properly return nullptr if RTT creation fails on low levels + + - Added IGUIListBox::getItemAt + + - Add more image formats tried to load by q3 level loader + + - Add fast_atof improvements from assimp, also strtoul10 method + + - Add blend equation function for MRTs + + - Add new material fields for blend operation and polygon offset (depth bias). + + - Reorder texture stage assignments + + - Improved VSync handling + + - Fix Ogre loader for materials with more than one texture + + - Fix createMeshCopy material handling + + - Framework target for OSX project added + + - Terrain scene node fixes + + - Fix HSL color class + + - Fix color selection GUI element + + - Transparency issues in particle system fixed + + - Particle sphere emitter rand values fixed + + - Support Unicode SHY dynamic hypen in word wrap + + - Fix OBJ reader sometimes running over EOF + + - Added IGUITable::getColumnWidth + + - Billboard text animates in OnAnimate now + + - Fix mountpoint reader to properly sync file names and firectories + + - Added the ability to open an archive from an IReadFile*, added a FileToHeader tool with instructions of how to make a portable app that consists of a single executable file. + + - Added suppport for right-to-left (RTL) text, supplied by Auria from STK + + - Added ISceneManager::createSceneNodeAnimator to create animators by name + + - The Makefile now creates a symlink from the soname to the binary name during install. Binary compatibility is only confirmed between same minor releases. + + - Added SMF mesh loader, loads meshes from 3D World Studio. Originally written by Joseph Ellis + + - The loader selection process now consistently checks loader lists in reverse order, so new loaders added to Irrlicht override the internal ones. This applies when adding external mesh, image, scene and archive loaders, image writers, plus node, animator and GUI element factories. + + - Added getters to retrieve mesh, scene and archive loaders. + + - Added ISceneLoader interface and .irr loader. Users can now add their own scene loaders to the scene manager and use them by calling loadScene. + + - Renamed IGUIElement::bringToBack to sendToBack, like in Windows + + - Send EGET_ELEMENT_CLOSED event when context menus should be closed (thx @ Mloren for reporting). + + - Added treeview to GUI editor, provided by Armen + + - Added root type for GUI environment + + - zip archive fixes: Fix directory tags in file list. Fix loading of stream zip files which have file sizes only in the central directory. + + - Fixed panel scrollbars in GUI editor, reported by Armen + + - Fix b3d loading of files with mixed mesh/bone sections. + + - Fix particle emitters which used integer random numbers so far. The distributions of the particles should be much better (and the code also somewhat faster) now. + + - Add new random method frand: Returns a random number in the interval [0..1] and gives better distributions than using fmodf on the integer number. + + - Add node parameter to saveScene and loadScene. saveScene saves the given node and all descendants to the file (if 0, the full scene is saved as before). loadScene loads all elements of the scene as childs of the given node. As before, 0 would load the file on the top level (scenemanager). + + - Add method to make a filename relative to a given directory. + + - Fix setMesh to correctly update the joints cache. + + - Fix setting transition time of skinned meshes back to 0. + + - Add some getters to IGUIImage: getImage, getColor + + - Fix OpenGL FBODepthTexture to create less overhead + + - Fix MRT disabling under OpenGL + + - API change: Added write only lock mode for textures. The lock method has changed the signature and uses an enum parameter now instead of a bool. The default is still to lock for read/write (previously 'false'). The old 'true' value should be replaced by ETLM_READ_ONLY. + + - Speedup deleting of particles + + - Add function IParticleSystemSceneNode::clearParticles + + - Fix RTT render states under OpenGL + + - Fix AntiAliasing setup under Windows/OpenGL in case no AA is available + + - Fix transformation matrices when RTT used + + - API change: getScreenCoordinatesFrom3DPosition has a new parameter, which needs to be set to true to get the original behavior. Now, the method returns coordinates which would fit as render coordinates of a currently enabled viewport. With the parameter set to true the result would fit only after the viewport is reset to full window rendering. + + - More checks for Stencilbuffer + + - Improve render state resets + + - Fix MRT handling + + - Fix file search + + - Add flag and method to disable clipping of the text to the gui element rectangle in GUI static text. + + - addShadowVolumeSceneNode now replaces an existing shadow. One should avoid to call this method multiple times without changing any parameter, as it is quite time consuming and cannot recognize the duplicate calls. + + - Add function IGUIEnvironment::removeFont (TODO: Does not remove the texture from cache so far) + + - Fixed mem leak in mountfilesystem + + - Update to libjpeg 8b, zlib 1.2.5, bzip2 1.0.6, libpng 1.4.4 and lzma from 9.20 SDK + + - Functions in IMeshCache expecting IAnimatedMesh* parameters removed as similar functions with IMesh* can be used since a while. Fixes also problems when IAnimatedMesh* got upcasted to IMesh*. (thx @ Greenya for reporting) + + - Fix blend states for MRTs + + - 64bit targets for MSVC added + + - The following functions will now use a "ISceneNode *" instead of a "const ISceneNode *": + ITriangleSelector::getSceneNodeForTriangle, ISceneNodeAnimatorCollisionResponse::getCollisionNode, ISceneCollisionManager::getCollisionPoint and ISceneCollisionManager::getCollisionResultPosition. + As collision functions often are followed by changing node positions users where so far forced to using const_casts (found by Greenya). + + - Add vector3d::getAs3Values (patch provided by slavik262) + + - Add function to SViewFrustum to get corners of the near plane (patch provided by Matt Kline, aka slavik262) + + - ParticleFadeOutAffector::setFadeOutTime can no longer be set to invalid values + + - ParticleFadeOutAffector uses now throughout u32 for fadeOutTime (found by greenya) + + - Add missing access function CParticleSystemSceneNode::getAffectors() (seen by B@z) + + - Add missing setters/getters for particle emitters (seen by B@z) + + - Compile-defines can now be disabled from Makefiles/Projectfiles instead of having to change IrrCompileConfig.h each time. + + - IGUITabControl::setActiveTab should only take IGUITab* and not IGUIElement* (thx to greenya for finding) + + - Add new skin-colors: EGDC_GRAY_WINDOW_SYMBOL, EGDC_EDITABLE, EGDC_GRAY_EDITABLE, EGDC_FOCUSED_EDITABLE + + - Disabled state is now extended to sub-elements + + - Make disabled state for several elements more visible + + - Bugfix: Icons in tabcontrol get now affected immediately by skin-changes + + - Proper cleanup if visual not created + + - XML reader bugfix + + - Disable mipmaps in 2d mode everywhere + + - Add xml example written by Yoran Bosman. + + - Fix cursor cleanup under Linux when using multiple devices + + - Fix collada parser + + - Fix MRT reset under D3D + + - Add a generic attribute interface for querying video driver attributes which are not necessarily of type bool. This interface allows to check certain supported features, such as the number of user clip planes, supported lights and textures, MRTs, and other things. The interface might change in the future, but it's fully functional already. The supported attributes are listed in the API docs of the function: +The following names can be queried for the given types: + * MaxTextures (int) The maximum number of simultaneous textures supported by the driver. This can be less than the supported number of textures of the driver. Use _IRR_MATERIAL_MAX_TEXTURES_ to adapt the number. + * MaxSupportedTextures (int) The maximum number of simultaneous textures supported by the fixed function pipeline of the (hw) driver. The actual supported number of textures supported by the engine can be lower. + * MaxLights (int) Number of hardware lights supported in the fixed function pipeline of the driver, typically 6-8. Use light manager or deferred shading for more. + * MaxAnisotropy (int) Number of anisotropy levels supported for filtering. At least 1, max is typically at 16 or 32. + * MaxUserClipPlanes (int) Number of additional clip planes, which can be set by the user via dedicated driver methods. + * MaxAuxBuffers (int) Special render buffers, which are currently not really usable inside Irrlicht. Only supported by OpenGL + * MaxMultipleRenderTargets (int) Number of render targets which can be bound simultaneously. Rendering to MRTs is done via shaders. + * MaxIndices (int) Number of indices which can be used in one render call (i.e. one mesh buffer). + * MaxTextureSize (int) Dimension that a texture may have, both in width and height. + * MaxGeometryVerticesOut (int) Number of vertices the geometry shader can output in one pass. Only OpenGL so far. + * MaxTextureLODBias (float) Maximum value for LOD bias. Is usually at around 16, but can be lower on some systems. + * Version (int) Version of the driver. Should be Major*100+Minor + * ShaderLanguageVersion (int) Version of the high level shader language. Should be Major*100+Minor. + + - Fix getRotationDegrees + + - Add creation parameter which allows to disable highres timers on Windows upon device creation. + + - Several transparency setup bugs fixed. Now, alpha_vertex_blend uses proper alpha blending instead of a mixed add/alpha blending. + + - Added a method to get real time and date in a human readable struct + + - Fix add folder archives method to support files without trailing slashes. + + - fix transparent_reflection_2_layers + + - Add support for MSVC 2010 + + - Fix "unsupported format" warning on RTT usage + + - Add IGUIElement::bringToBack (patch written by DtD, although I'm to blame for the function-name) + + - BurningVideo + - add Normalmap Rendering (one light only), pushed Burningvideo to 0.46 + - add Stencil Shadow Rendering (one color only and 32 bit only), + pushed Burningvideo to 0.47 + - internal vertexformat changed + - changed fixpoint from 9 to 10 bit fract resolution + - renamed createBurningVideoDriver to createBurningVideoDriver and uses SIrrlichtCreationParameters like opengl + - internal interfaces for the trianglerenders unified. + + - Example 11, changed the light billboards to use the light color. + allow to disable the bump/parallax on the earth like in the room ( with transparency ) + + - added DDS Image files, DXT2, DXT3, DXT4, DXT5, based on code from nvidia and Randy Reddig + + - added Halflife 1 Model Loader (based on code by Fabio Concas) + Halflife 1.1.0.8, Counter-Strike 1.6 working + -> Load all Textures ( can even optimize it to texture atlas ), all bone animation, all submodels. + -> But to make use of the values (named animation, mouth animation) + the Interface for IAnimatedMeshSceneNode has to be redone. + + TODO: + ->can handle float frames numbers, the interface for getMesh should be reworked + This is my idea of a new getMesh interface for IAnimatedMesh + + //! Returns the IMesh interface for a frame. + /** \param frameA: Frame number as zero based index. + The Blend Factor is in the fractional part of frameA + The Mesh will be calculated as + frame = integer(frameA) * (1-fractional(frameA )) + frameB * fractional(frameA) + FrameNr KeyFrameA KeyFrameB + 40.0 1 0 + 40.1 0.9 0.1 + 40.5 0.5 0.5 + 40.9 0.1 0.9 + 41.0 0 1 + \param frameB: Frame number as zero based index. The other KeyFrame which is blended with FrameA. + \param userParam: for Example Level of detail, or something else + */ + virtual IMesh* getMesh(f32 frameA, s32 frameB = 0,s32 param = 0) = 0; + + For now i used the (unused, always 255) detail level parameter and set a blend percentage as + s32 frameNr = (s32) getFrameNr(); + s32 frameBlend = (s32) (core::fract ( getFrameNr() ) * 1000.f); + return Mesh->getMesh(frameNr, frameBlend, StartFrame, EndFrame); + + So no interface is affected. + + -> TODO: Quaternion Rotation is done private hand made and should be done with irrlicht quaternions + + - Included 357kb Yodan.mdl mesh and copyright info file from Doug Hillyer + to the media directory, used in example 7. collision as 4th model. + + - added Halflife 1 Texture Loader + Valve uses WAL archive types like quake2. textures are inside model files + I reworked the existing ImageloaderWAL and added named Halflife textures to wal2 ( they have no extension ) + and an LMP (palette/texture) loader into the same file (all using 32bit now) + + - added WAD Archive Loader (Quake2 (WAL2) and Halflife (WAL3) are supported) + + - CFileList + added Offset Parameter to SFileListEntry and removed the private array from the archive loaders. + CFileList::addItem now uses automatic incremental id if id = 0 + + - added void splitFilename, splits a path into components + + - added parameter make_lower to substring ( copy just lower case ) + string subString(u32 begin, s32 length, bool make_lower = false ) const + + - ColorConverter added + //! converts a 8 bit palettized or non palettized image (A8) into R8G8B8 + static void convert8BitTo24Bit(const u8* in, s16* out, s32 width, s32 height, const s32* palette, s32 linepad = 0, bool flip=false); + //! converts a 8 bit palettized or non palettized image (A8) into A8R8G8B8 + static void convert8BitTo32Bit(const u8* in, u8* out, s32 width, s32 height, const u8* palette, s32 linepad = 0, bool flip=false); + + - In IGUITreeView "clearChilds" and "hasChilds" deprecated for "clearChildren" and "hasChildren" (thx @Greenya for noticing) + + - add CGUIEditBox::getOverrideColor and CGUIEditBox::isOverrideColorEnabled + + - add dimension2d::operator- + + - Add logging level ELL_DEBUG + + - Add parameter DisplayAdapter to creation params to allow selecting the card when more than one card is in the system. + + - Added support for custom cursors + + - WM_SYSCOMMAND - SC_KEYMENU message is now ignored (F10 and ALT in Win32 windowed mode) + + - Avoid argument lookup ambiguity in swap when used in combination with stl. Using same trick as boost now and use 2 different template parameters in it. + + - Add UseMipMap flag in material + + - Add occlusion query support. Based on code by Nadro + + - Add support for vertex_array_bgra extension in OpenGL driver. This will speed up OpenGL rendering quite a lot as it skips the silly color conversion thing we have to do otherwise. + + - Replace raw xml char implementation with template struct in order to decouple the type from POD types. May also help for 64bit problems or changes needed there. + + - Fixed bug causing memory access violation in string::replace found and patched by Nalin. + + - Fix windows32 class unregister + + - Add parameter to line2d::intersectWith to allow getting intersections outside the segments (thx Yoran). + + - External windows are not destroyed anymore + + - clamp values in getRotationDegrees to avoid nan values + + - texture size in terrain mesh fixed + + - ms3d fixes + + - Add new matrix methods for infinite projection matrix + + - Support new OpenGL 2.x shader creation + +----------------------------- +Changes in 1.7.4 (not yet released) + + - fixed getDepthFunction in IQ3Shader which always returned ECFN_EQUAL due to missing break (found by the cppcheck tool) + + - STL loader improved to handle arbitrary file starts + + - Compiler problem with gcc4.6 and big endian systems fixed + + - Change include order to get example 21 compiling on MinGW. + + - Irrlicht.dll has correct name now again (was named libIrrlicht.dll in c::b). This fixes bugreport 3518765 reported by tetho. + + - Fix linker path in example 16 for C::B project file (linker path was in include path section). + + - Link with opengl32 and gdi32 in Example 14 in C::B. + + - Remove --no-export-all-symbols which got recently added to the windows build as that flag is not known by gcc on Windows. + + - Fix bug in example 23 where Width and Height got mixed up. Thanks @Lazier for reporting. + + - Fix for R5G6B5 converter submitted by XMight + + - Fix conversion warning under mingw, found by Randajad + + - Set EMF_NORMALIZE_NORMALS correct for syndey model in Demo (thanks @ Midnight for reporting). + + - SceneNodeAnimatorFlyCircle fixes serialization of RadiusEllipsoid (was writing Radius). Thx @ wing64 for reporting. + + - Yield on Linux now uses nanosleep with 1ns as 0 isn't guaranteed to yield (thx @ hendu for finding + fix) + +----------------------------- +Changes in 1.7.3 (20.02.2012) + + - SceneNodeAnimatorFlyCircle fixes serialization of RadiusEllipsoid (was writing Radius). Thx @ wing64 for reporting. + + - Yield on Linux now uses nanosleep with 1ns as 0 isn't guaranteed to yield (thx @ hendu for finding + fix) + + - GUIEditor attributes have now scrollbar to be editable + + - Remove warning when compiling line2d::intersectWith with other types than f32. + + - Document that triangle3d::isPointInside should not be used with int's. + + - triangle3d::isPointInsideFast handles 'on-border' cases now consistently. + + - Some more editbox fixes + + - Harden Linux joystick usage, in case the driver returns illegal values + + - Some more editbox fixes + + - Harden Linux joystick usage, in case the driver returns illegal values + + - Bugfix: vector2d.normalize() and vector3d.normalize() had returned wrong results with very short vectors since Irrlicht 1.5. Thanks to Willem Swart for Bugreport + testcase. + + - Unknown keymappings now use the X11 keycode instead of 0 to make such keys at least usable in games. + + - KeyMapping for KeyInput.Key on X11 ignores states like shift&ctrl now like on Windows. + + - Additional keymappings for X11 (tested with german and us keyboards which seem to work now in all cases). + + - Fix crash in multiline editbox when pasting several lines into it on Windows (found by Reiko) + + - example 09.Meshviewer no longer catches keys while a modal dialog is open + + - Fix SSharedMeshBuffer + + - Fix right handed ortho matrix + + - editbox no longer displays cursor when disabled + + - editbox autoscrolling now at least works good enough to actually show the text which the user is typing in. + + - editbox no longer moves text into next line when it fails wrapping creating senseless empty lines which mess up scrolling. + + - Fix crash in editbox when scrolling up with empty first lines caused by textwrapping. + + - Fix endianess conversions + + - Changes to isPointInside + + - Fix focus problem when removing an unfocused modal dialog reported by Reiko here: http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=44358 + + - Fix md2 normals problem again + + - Add integer template specialization for vector3d::getSphericalCoordinateAngles which rounds angles to nearest integer now. + + - Recalculate FrameRect and ScrollPos in CGUIEditBox when AbsoluteRect gets changed (thx @ serengeor for report + testcase) + + - Fix crash in editbox + + - Fix crash in editbox + + - Fix 'k' in bigfont.png (thx @ Scrappi for reporting) + + - fix serialization for CBillboardSceneNode, it had missed 2 color (thx for finding + patch from pc0de) + + - EMIE_MOUSE_WHEEL messages now handled correctly in several gui-element when wheel isn't just 1.0 or -1.0 (thx @ Reiko for reporting) + + - Fix problems in Textwrapping in CGUIStaticText. Did use wrong size and did ignore last word of the text (thx @ Reiko for bugreport) + + - Fix crash in collada (.dae) loading + + - Fix bug handling in case RTT is not properly created + + - Fix SColorf interpolation + + - Fix bug handling in case RTT is not properly created + + - Fix SColorf interpolation + + - Fix memory-leaks in example 22 MaterialViewer + + - Fix array::erase which did destroy objects more than once when used with a range (thx @ RedDragCZ for reporting + testcase). + + - Copy now all membervariables for CCameraSceneNode when cloning. + + - ICameraSceneNode::IsOrthogonal is correctly serialized and cloned now. + + - CGUIScrollBar passes unused mousemove-events now to parent element. Fixes focus-bug in ComboBox reported by REDDemon here: http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=43474&highlight= + + - Fix getAngle and getAngleWith + + - Fix clipping in CGUITabControl + + - Fix clipping in CGUITable, reported by ceyron + + - Skip bone weights and additional information in ms3d file if no joint was defined before. + + - Fix mem leak in CImage, found by mloren. + + - Fix tga writing, reported by xirtamatrix + + - Tab-positions care now about the borders correctly + + - TabControl now respositions it's tabs when setTabVerticalAlignment is changed (thx @ ceyron for reporting+testcase) + + - CGUIModalScreen now no longer takes focus itself, but tries to give it first child when possible to fix modal windows losing focus all the time + + - Modal screens no longer blinks when gui-elements call removeFocus on themself (thx @ yaten for reporting+testcase) + + - Fix crash in multiline-editbox when selecting with mouse (thx @ ceyron for reporting and testcase) + + - Fix render context creation for OpenGL under Windows. + + - Fix the reset problem of d3d9 driver in combination with hardware buffers. + + - Fix .x loader in case of unused vertices. + + - Avoid empty line in texts with very large words. Text wrapping would introduce an empty line in earlier versions. + + - Add a new attribute which assigns hw mapping hint to the whole Mesh. + + - Allow creation of water scene node without mesh. + + - Fix regeneration of skydome. + + - Fix scene node type and factory support for volume light + + - Q3 maps no longer crash when faces try accessing lightmaps which are not mentioned to be loaded in the file. + + - Fix crash on null-readfile in texture loading + + - Get particles saved before 1.7.2 (for example in irrEdit) working again (thx to smashly for problem reporting) + + - Fix IGUIScrollBar setMax and setMin which had been restricted wrongly (reported by REDDemon) + + - Fix CNullDriver::createImage - Creating the image from a texture-rectangle which doesn't start at 0,0 works now again (thx @ ceyron for bugreport+testcase) + + - Menu no longer sets highlight state when clicking disabled menu-item (reported by Mloren) + + - Treeview can now be disabled + +----------------------------- +Changes in 1.7.2 (15.11.2010) + + - Fix in d3d9 driver, which caused a crash when device creation failed. Bug found and fixed by Kostya + + - Fix a wrong access to Value instead of ValueW. Found and fixed by vroad. + + - Fix line loop rendering in d3d drivers. Fix submitted by tonic. + + - Fix tar recognition in tar reader. + + - Fix blend mode setup in OpenGL driver, when using the material2d override, as pointed out by Auria + + - Avoid crash due to tcoords2 handling. Might need some more fixing to work correctly. + + - Fix 2d line intersections. Has had problems with consecutive, but non-overlapping line segments and with overlapping line segments. + + - Fix image creation from texture, found by dataslayer + + - Fix crashes when taking Screenhots for DirectX in Windowed mode (thx to agamemnus for reporting) + + - StaticText does now serialize the background color + + - Fix gui-elements which didn't care when skin-colors changed. That made it impossible to make the gui slowly transparent (thx to PI for reporting). + Note that it couldn't be completely fixed for the SpinBox without breaking the interface, so for that element you have to enforce this by calling for example element->setValue(element->getValue()) once. + + - Fix CXMLReaderImpl::getAttributeValueAsInt which returned wrong values with large integers (thx to squisher for finding) + + - Fix compile problem in swap when using irrlicht in combination with stl (backport from trunk r3281) + + - Add EGET_TREEVIEW_NODE_COLLAPSE and deprecate EGET_TREEVIEW_NODE_COLLAPS (found by greenya) + + - Fix serialization in CParticleSystemSceneNode (found by B@z) + + - Prevent crash in BillboardTextSceneNode when a custom font is used. Found and fixed by Nalin (bugtracker id: 3020487) + + - Fix problem in animation system that currentFrame got messed up after long pauses (especially when not starting at frame 0). + See forum thread (http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?p=210537#210537) and bug id 2898876. + Also remove BeginFrameTime in CAnimatedMeshSceneNode as it hasn't been used anymore since some time. + + - Add framerate and current frame information for animations in example 09 and do some minor cleanup. + + - Added another test for xml-reader. + + - Fix serialization in several particle emitters and affectors (thx to Ion Dune for reporting). + + - Fix compile-error on VS for vector2d::getAngleTrig when used with integers. (thx to greenya for reporting) + + - Fix bug in dimension2d::getInterpolated that caused wrong results when used with integers as template parameter. (thx to Greenya for noticing a warning which made me look over this code). + + - Remove 2 minor memory leaks in meshloaders (found by tool cppcheck-1.43) + + - reduce file dependencies for IGUIEventReceiver.h (thx ngc92) + + - Initialize GUIEvent.Element in several places (found by greenya) + + - Add EGDS_MESSAGE_BOX_MAX_TEXT_WIDTH and deprecated EGDS_MESSAGE_BOX_MAX_TEST_WIDTH (thx to greenya for reporting). + + - Fix colors in irr files. + + - Fix several places where "used" in core::string was used wrongly preventing some memory corruption + + - Remove additional slash in pathnames in X-Loader + + - Fix crash in CGUIListBox when environment was cleared on events + + - Bugfix: Clear up depth-textures which could not be attached in OpenGL to prevent crashes. + + - Fix arrowMesh boundingbox. + + - Fix rounding problem in getInterpolated in the color classes + + - Scrollbar in GUIListbox now uses default id -1 instead of 0 + + - Fix octree clipping issues. + + - Fix obj loader. + + - clone function fixes. + + - Fix tooltips. + + - Fix Ogre parser. + +----------------------------- +Changes in 1.7.1 (17.02.2010) + + - Fix octree with frustum+parent checks enabled (didn't clip at all before). Now using plane-checks instead of edge-checks for frustum-box intersection. + + - Prevent that X11 selects larger resolutions in fullscreen even when perfect fits are available. + + - Ignore setResizable also on X11 when we're fullscreen to avoid messing up the window mode. + + - Work around a crash when pressing ESC after closing a Messagebox (found by Acki) + + - Prevent borland compile warnings in SColorHSL::FromRGB and in SVertexColorThresholdManipulator (found by mdeininger) + + - Improve Windows version detection rules (Patch from brferreira) + + - Make it compile on Borland compilers (thx to mdeininger) + + - Make sure that CAnimatedMeshSceneNode::clone calls the virtual updateAbsolutePosition for the new object + + - Fix that clones got dropped too often when SceneNodes without parent got cloned (found by Ulf) + + - Make sure TAB is still recognized on X11 when shift+tab is pressed. This does also fix going to the previous tabstop on X11. + + - Send EGET_ELEMENT_LEFT also when there won't be a new hovered element + + - Update docs for EGET_ELEMENT_LEFT and EGET_ELEMENT_HOVERED + + - Fix tooltips: Remove them when the element is hidden or removed (thx to seven for finding) + + - Fix tooltips: Make (more) sure they don't get confused by gui-subelements + + - Fix tooltips: Get faster relaunch times working + + - Fix tooltips: Make sure hovered element is never the tooltip itself + + - Fix string::remove which got in an endless loop when remove was called with an empty string (found and fixed by Ulf) + + - Correctly release the GLSL shaders + + - Make sure we only release an X11 atom when it was actually created + + - Fix aabbox collision test, which not only broke the collision test routines, but also frustum culling, octree tests, etc. + + - Fix compilation problem under OSX due to wrong glProgramParameteri usage + + - mem leak in OBJ loader fixed + + - Removed some default parameters to reduce ambigious situations + +--------------------------- +Changes in 1.7 (03.02.2010) + + - Implement minimize and deminimize under OSX. + + - Define sorting order for vector2d and vector3d in operators <, <=, > and >= to fix bugs 2783509 and 2783510. Operators order now by X,Y,Z and use float tolerances. + + - Ogre mesh 32bit indices fixed. + + - Fix tooltips for gui-elements with sub-element like IGUISpinBox (id: 2927079, found by ArakisTheKitsune) + + - ITimer no longer stops when started twice + + - wchar_t filesystem updates under Windows. + + - Joystick POV fixed under Windows, ids fixed under OSX. + + - Some updates to skinned mesh for better bones support and scaling animations. + + - OSX supports external window id in creation parameters now. + + - Fix bbox collision tests. + + - Updates for win32 key handling + + - new convenience method for flat plane creation. + + - Sky dome and other meshes use VBOs by default now. + + - Speed up b3d loading for files with many frames, material color flags and vertex color support enhanced. + + - Add hasType to IGUIElement as a dynamic_cast substitute. + + - Add another parameter to IGUISkin::draw3DWindowBackground to allow getting the client area without actually drawing + + - Add function getClientRect to IGUIWindow for getting the draw-able area + + - Fix bug that menus on IGUIWindows with titlebar got drawn too high (id: 2714400) + + - Renamed OctTree to Octree + + - Allow getting a ConstIterator from a non-const core:list + + - Add swap functions to irrMath and to the core classes. + + - Deprecate map::isEmpty() and replace it with map::empty() to make it similar to other base classes. + + - Allow to set the logging level already in SIrrlichtCreationParameters. + + - Add clearSystemMessages to devices (implemented only for Linux and Win32 so far). + + - Support changing the render window from beginScene also with OpenGL driver. + + - Add getMaterial2D which allows to alter the 2d render state settings, such as filtering, anti-aliasing, thickness, etc. + + - Fix incorrect cursorpos for resizable windows on Windows Vista (found and patched by buffer) + + - Change the beginScene window parameter from void* to SExposedVideoData&. This will allow to manage contexts for OpenGL at some point. + + - Add bzip2 and LZMA decompression modes for zip loader. + + - Add OBJ_TEXTURE_PATH and B3D_TEXTURE_PATH to SceneParameters to allow setting texture-paths for obj and b3d. + + - Irrlicht keeps now filenames additionally to the internally used names, thereby fixing some problems with uppercase-filenames on Linux. + + - Bugfix: Mousewheel no longer sends EMIE_MOUSE_WHEEL messages twice on Linux. + + - Use latest jpeglib + + - refactoring: E_ATTRIBUTE_TYPE and IAttribute have now own headers + + - CStringWArrayAttribute speedup + + - SceneNodeAnimatorFollowSpline can now loop and pingpong + + - Meshviewer.example got some fast-scale buttons. + + - Support AES-encrypted zip files. Should work with 128, 196, and 256 bit AES. This addition also adds a new PRNG, SHA, and other algorithms to the engine, though no interface is yet added for them. The implementation of the encryption algorithms is provided by Dr Brian Gladman. + + - flattenFilename and getAbsolutePath fixed and properly added at several places. + + - Added geometry shaders for OpenGL. A first version of the code was submitted by Matthew Kielan (devsh). + + - Bugfix: irrArray should no longer crash when using other allocators. + + - Add MaterialViewer example. + + - Texture activation now back in setMaterial, which simplifies writing external material renderers (OpenGL only). + + - Checkbox uses now disabled text color when disabled. + + - Changed colors for window-title caption to keep them readable when not active. + + - Draw sub-menus to left side if they would be outside main-window otherwise. + + - Give ListBox better defaults for the ScrollBar stepsizes. + + - Double and triple click events now for each mouse-button. Old events for that got removed. + + - Fix adding archives twice, which caused multiple archives of the same name and type covering each other. This one required a texture name change from using backslashes to slashes under Windows. + + - Give access to texture mipmaps. You can provide custom mipmap textures upon generation, regeneration, and locking. + Make sure the provided data is large enough and covers all miplevels. Also the returned pointer (from lock) will only cover the smaller data of the mipmap level dimension chosen (level 0 is the original texture). + + - Separate TextureWrap mode into U and V fields + + - Add mirror texture wrap modes + + - windows show now active/inactive state + + - remove unneeded drop/grab calls found by manik_sheeri + + - fix rounding problem in IGUIElements which have EGUIA_SCALE alignments. + + - MessageBox supports now automatic resizing and images. + Deprecated EGDS_MESSAGE_BOX_WIDTH and EGDS_MESSAGE_BOX_HEIGHT + + - Let maya-cam animator react on a setTarget call to the camera which happened outside it's own control + + - New contextmenue features: + automatic checking for checked flag. + close handling now customizable + serialization can handle incomplete xml's + setEventParent now in public interface + New function findItemWithCommandId + New function insertItem + + - new vector3d::getSphericalCoordinateAngles method. + + - new triangle3d::isTotalOutsideBox method. + + - Newly introduced VertexManipulator interface. This allows for very easy creation of vertex manipulation algorithms. Several manipulators, e.g. vertex color changer and transformation algorithms are already available. + + - createMeshWith1TCoords avoids vertex duplication + + - getRotation now handles matrices with scaling as well + + - Ogre format animations now supported. + + - irrArray: Fixed issues with push_front and reallocation + Changed behavior for set_pointer and clear, when free_when_destroyed is false + + - NPK (Nebula device archive) reader added, it's an uncompressed PAK-like format + + - SSkinMeshBuffer::MoveTo* methods renamed to convertTo* + + - Multiple Render Target (MRT) support added, including some enhanced blend features where supported + + - Directory changing fixed for virtual file systems (Archives etc) + + - Fix texture matrix init in scene manager and driver + + - More draw2dimage support in software drivers + + - Sphere node now properly chooses a good tesselation based on the parameters + + - Active camera not registered twice anymore + + - Parallax/normal map shader rotation bug under OpenGL fixed + + - bump map handling for obj files fixed + + - Fog serialization added + + - New context menu features added + + - Bounding Box updates for skinned meshes fixed + + - The current FPS for an animated scene node can be queried now, added some variables to serialization + + - Scrollbars fixed + + - Fixed 2d vertex primitive method to correctly handle transparency + + - Fullscreen handling has been enhanced for Windows, now proper resolution is restored on Alt-Tab etc. + + - Cameras can now be added to the scene node without automatically activating them + Clone method added + + - New video driver method getMaxTextureSize + + - PAK archive reader fixed + + - TRANSPARENT_ALPHA_CHANNEL_REF uses modulate to enable lighting + + - LIGHTMAP_ADD now always uses add operator + + - Some Unicode file system fixes + + - destructor of irrString not virtual anymore, please don't derive from irrString + Some new methods added, for searching and splitting + Assignment operator optimized + + - new lightness method for SColor + + - draw3DTriangle now renders filled polygons, old behavior can be achieved by setting EMT_WIREFRAME + +----------------------------- +Changes in 1.6.1 (13.01.2010) + + - Fix pingpong for CSceneNodeAnimatorFlyStraight (found by gbox) + + - Fix bug with IGUIEditBox where the cursor position is reset on text change. + + - Make sure the window top-left corner on Windows is not negative on start so that Windows sytem-menu is always visible. + + - Fix problem that the window did sometimes not get the keyboard focus in X11 in fullscreen. Add more debug output in case focus grabbing goes wrong. + + - Fix screensize in videodriver when we didn't get the requested window size. This also prevents that gui-clicks are no longer synchronized with gui-drawing and elements can't be hit anymore. + + - Bugfix: Prevent a crash when getTypeName was called for the guienvironment. EGUIET_ELEMENT got changed for this. + + - Bugfix: Horizontal centered font with linebreaks draw now all lines. For example multiline TextSceneNodes work again. + + - Bugfix: spinbox can no longer get in an endless loop due to floating point rounding error (found by slavik262) + + - !!API change!! Disabled AntiAliasing of Lines in material default + Please enable this manually per material when sure that it won't lead to SW rendering. + + - IGUIComboBox: clicking on the statictext displaying the active selection does now close and open listbox correctly. (Bug found by Reiko) + + - Scrollbuttons in IGUITabControl adapt now to tab-height. + + - Fix texturing of cylinder mesh + + - Fix modal dialog position (found by LoneBoco: http://sourceforge.net/tracker/?func=detail&aid=2900266&group_id=74339&atid=540676) + + - Fix DMF loading + + - Fixing left+right special keys (ctrl, shift, alt) on Win32 (thanks to pc0de for good patch-ideas). + + - Make stringarrays for enums in IGUISkin a little safer + + - Add support for keys KEY_PRINT, KEY_HOME (on numpad) and KEY_NUMLOCK on Linux. + + - Fix material handling in createMeshWith1TCoords + + - Fix another (OldValue == NewValue) before drop()/grap(), this time in CTextureAttribute::setTexture. + + - Fix LIGHTMAP_LIGHTING for D3D drivers. + + - AntiAliasing disabled for debug render elements. + + - Bugfix: CGUIToolBar::addButton does no longer mess up when no image is set and does now actually work with the text. + + - Fix ninja animation range which got messed up a little when b3d animations got fixed (thx gbox for finding) + +--------------------------- +Changes in 1.6 (23.09.2009) + + - Added IFileSystem::createEmptyFileList, exposed IFileList::sort, addItem and added getID + + - Fix MAKE_IRR_ID so it can be used from outside the irr namespace (Micha's patch) + + - Renamed some methods in ISkinnedMesh to match the official Irrlicht naming scheme according to createXXX() + + - Change debug data to draw using lines instead of arrows, which is much faster. Patch by pc0de + + - Fix a bug with FPS camera animator causing stutters. Patch by FuzzYspo0N + + - Fix scrolling controls in CGUITabControl + + - Fix a bug when getting optimal texture size in D3D drivers, by Jetro Lauha (tonic) + + - Added EGDS_TITLEBARTEXT_DISTANCE_X and EGDS_TITLEBARTEXT_DISTANCE_Y to GUI, submitted by FuzzYspo0N + + - Fix for UFT8 filenames displayed in file dialog, patch by MadHyde. + + - Added const method for array::binary_search, potentially slow as it doesn't sort the list! + + - Add support for scaling button images. + + - Irrlicht can now come with multiple device types compiled in, the device to use is selected by SIrrlichtCreationParameters.DeviceType. This defaults to EIDT_BEST which automatically select the best device available starting with native, then X11, SDL and finally the console. + + - Added support for EXP2 fog distribution. This required a change in the setFog parameters where now an enum value instead of the bool linear is given. + + - IFileSystem changes: + + - Renamed the following functions- + IFileArchive::getArchiveType to getType + IFileSystem::registerFileArchive to addFileArchive + IFileSystem::unregisterFileArchive to removeFileArchive + IFileArchive::openFile to createAndOpenFile + + - New enum, E_FILE_ARCHIVE_TYPE. getType on IArchiveLoader and IFileArchive now both return this. + + - IFileSystem::addFileArchive takes a parameter to specify the archive type rather always using the file extension. IFileSystem::addZipFileArchive, addFolderFileArchive and addPakFileArchive now use this but these functions are now marked as deprecated. Users should now use addFileArchive instead. + + - Added TAR archive loader. + + - The ZIP archive loader can now load gzip files, combined with the TAR loader this means Irrlicht now has native support for .tar.gz + Currently this must be done in two calls, for example: + fileSystem->addFileArchive("path/to/myArchive.tar.gz"); + fileSystem->addFileArchive("myArchive.tar"); + + - Fix highlighting in IGUIEditBox where kerning pairs are used in the font. For example in future italic, OS or other custom fonts. + + - IOSOperator::getTextFromClipboard returns now const c8* instead of c8* + + - Support for copy&paste on linux (X11) added (fixing bug 2804014 found by Pan) + + - bugfix for 2795321 found by egrath: Don't rely anymore on broken XkbSetDetectableAutoRepeat. + + - bugfix: CMountPointReader::openFile no longer returns true for empty files. Corresponding test added. + + - Direct3D now also uses screen coordinates in 2d mode, just like OpenGL. This means that screen coords are going from 0..ScreenWidth and 0..ScreenHeight instead of -1..1. + + - ALT+F4 keypress now closes Windows SDL device + + - Allow Direct3D drivers in SDL, patch by Halifax + + - Added compiler error when attempting to compile with VC6. + + - Use setWindowTextA in Windows device for WIN64 platform, posted by veegun + + - ELL_ERROR log events are now created when shaders fail to compile or link, reported by Halan + + - irrList now uses irrAllocator, fixed by Nox + + - Added IGUIWindow::setDraggable and IGUIWindow::isDraggable, by Nox + + - Added SGI RGB file reader by Gary Conway, for loading Silicon Graphics .rgb, .rgba, .sgi, .int and .inta textures + + - Renamed setResizeAble to setResizable + + - Added new device method minimizeWindow which minimizes the window (just as if the minimize button has been clicked). + + - SkyDome is now serialized correctly + + - Added PLY mesh reader and writer + + - Ensure ListBox on combo box doesn't hang off the bottom of the GUI root, by Matthias Specht + + - Made IGUIElements recalculate clipping rectangle after setNotClipped, reported by Aelis440 + + - Bug fix for the combo box where it showed white text instead of skin color before being focused, fix posted by drewbacca + + - EGDS_MESSAGE_BOX_HEIGHT is now honoured, bug reported by Spkka + + - Fixed a bug in the edit box where events are sometimes sent to a null parent, reported by Sudi. + + - Coordinate system fix for OpenGL in SDL device + + - Added generic console device. You can now use Irrlicht to create and manipuate graphics on a shell where no graphics hardware + or windowing system is available. To enable it uncomment #define _IRR_USE_CONSOLE_DEVICE_ in IrrCompileConfig.h + - The console device can now present images from the software drivers and display them as ASCII art in the console + - By default it replaces the default font in the skin, to prevent fonts from being huge. + + - Fixed problems with changing cursor visibility while mouse is pressed on windows + + - Allow control of background drawing in listbox + + - Allow control of drawing background and titlebar in windows + + - Improved window serialization + + - Add mouse events EMIE_MOUSE_DOUBLE_CLICK and EMIE_MOUSE_TRIPLE_CLICK (thx to Ulf for patch proposal) + + - Set "ButtonStates" for mouse events also on Linux (was only for Windows formerly) + + - Add Shift+Control states to mouse event + + - bugfix (2003238): serialize modal screens + + - allow stacking modal screens + + - allowing hiding modals + + - replace many IsVisible checks with virtual isVisible() checks in IGUIElement + + - bugfix: reset selected row when clearing CGUITable + + - adding events EGET_EDITBOX_CHANGED and EGET_EDITBOX_MARKING_CHANGED + + - prevent editbox from recalculating its textbreaking each frame + + - let spinbox react on each textchange without waiting for enter to prevent getting value changes without corresponding EGET_SPINBOX_CHANGED events. + + - new test for zipreader + + - prevent dropping objects accidentally in many set functions + + - Reversed change in vector3d::normalize. + Works now again as documented and a corresponding test has been added. + Does fix bug 2770709 (https://sourceforge.net/tracker/?func=detail&aid=2770709&group_id=74339&atid=540676) + + - Animations can now be paused by setting the fps to 0. + + - Avoid fp-precision problem in getPickedNodeBB (see also http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=33838&highlight=). + This change might also fix the problem with picking nodes found by aanderse (http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=32890&highlight=) + + - implemented isALoadableFileFormat ( File *file ) for the Archive Loader + + - PixelBlend16 and PixelBlend16_simd are working for the new rules. + + - bugfix. CLightSceneNode didn't correctly update it's attributes + + - vector template and equals tests + also set the equal test for s32 to behave like the f32 routine. + The function equals always implements a weak test. + that means a tolerance MUST always be used if you use the equal function. default is 1. + + - VideoDriver drawPixel + The HW renderes are using the alpha components for blending. + The Software Renderes and image loaders are using CImage::setPixel copy. + so setPixel is engaged to either blends or copy the pixel + default: false + - Burningvideo + added RenderMaterial EMT_SPHERE_MAP + pushed burningsvideo to 0.43 + added RenderMaterial EMT_REFLECTION_2_LAYER + pushed burningsvideo to 0.44 + set EMT_TRANSPARENT_ALPHA_CHANNEL_REF + to use AlphaRef 0.5 like Direct3D + + One Note: in OpenGL there is know difference between sphere_map and reflection layer + both using GL_TEXTURE_GEN_MODE GL_SPHERE_MAP, whereas in d3d one time using camera_normal + on sphere and reflection on refletcion_layer. + + The visual difference is that on sphere map the "image is not moving" when you rotate the + viewer. For Burning i took the opengl visual. always moving + + - rename quake3 SEntity to IEntity to be confom with IShader + + - fixed createMeshWith2TCoords, normals were missing during copy. + + - added + //! Creates a copy of the mesh, which will only consist of S3DVertex vertices. + IMesh* CMeshManipulator::createMeshWith1TCoords(IMesh* mesh) const + + - added io::IFileSystem* CSceneManager::getFileSystem() + + - added virtual const c8* ISceneManager::getAnimatorTypeName(ESCENE_NODE_ANIMATOR_TYPE type); + + - added CSceneNodeAnimatorFlyCircle::radiusEllipsoid. + if radiusEllipsoid == 0 the default circle animation is done + else radiusEllipsoid forms the b-axe of the ellipsoid. + -> gummiball bouncing + + - added ISceneManager::createFlyStraightAnimator variable bool ping-pong + used in loop mode to device if start from beginning ( default ) or make ping-pong + -> straight bouncing + + - changed IFileSystem::registerFileArchive + remove the index of the hierarchy and added a new interface method + //! move the hirarchy of the filesystem. moves sourceIndex relative up or down + virtual bool moveFileArchive( u32 sourceIndex, s32 relative ) = 0; + + - bugfix and changes in SViewFrustum::SViewFrustum + wrong size of Matrices copy. + renamed E_TRANSFORMATION_STATE_2 to E_TRANSFORMATION_STATE_FRUSTUM + therefore also changed SViewFrustum::setTransformState to not tap + + in the pitfall again of wrong memory... + + - moved + //! EMT_ONETEXTURE_BLEND: has BlendFactor Alphablending + inline bool textureBlendFunc_hasAlpha ( E_BLEND_FACTOR factor ) const + from the material renderes ( 3x declared ) to SMaterial.h + + - updated managed light example to use standard driver selection + + - BurningsVideo + - LightModel reworked. + Point Light & Direction Light works for Diffuse Color as expected + Specular and Fog still have problems ( needs new pixel shader ) + pushed burningsvideo to 0.42 for this major step + + - removed obsolete matrix transformations + renamed E_TRANSFORMATION_STATE_2 to E_TRANSFORMATION_STATE_BURNING + + - cleaned line3d.h vector3d.h template behavior. + many mixed f32/f64 implementations are here. i'm not sure if this should be + the default behavior to use f64 for example for 1.0/x value, because they + benefit from more precisions, but in my point of view the user is responsible + of choosing a vector3d or vector3d. + + - added core::squareroot to irrmath.h + -> for having candidates for faster math in the same file + + - added AllowZWriteOnTransparent from SceneManager to burningsvideo + + -added hasAlpha() to ITexture + This info can be used for e.q to downgrade a transparent alpha channel blit + to add if the texture has no alpha channel. + +- FileSystem 2.0 SUPER MASTER MAJOR API CHANGE !!! + + The FileSystem is now build internally like for e.g. the image- and meshloaders. + There exists a known list of ArchiveLoaders, which know how to produce a Archive. + The Loaders and the Archives can be attached/detached on runtime. + + The FileNames are now stored as io::path. where c16 is toggled between char/wchar + with the #define flag _IRR_WCHAR_FILESYSTEM, to supported unicode backends (default:off) + Replaced most (const c8* filename) to string references. + + Basically the FileSystem is divided into two regions. Native and Virtual. + Native means using the backend OS. + Virtual means only use currently attached IArchives. + + Browsing + each FileSystem has it's own workdirectory and it's own methods to + - create a FileTree + - add/remove files & directory ( to be done ) + Hint: store a savegame in a zip archive... + + basic browsing for all archives is implemented. + Example 21. Quake3Explorer shows this + + TODO: + - a file filter should be implemented. + - The IArchive should have a function to create a filetree + for now CFileList is used. + + Class Hierarchy: + + IArchiveLoader: is able to produce a IFileArchive + - ZipLoader + - PakLoader + - MountPointReader ( formaly known as CUnzipReader ) + + IFileArchive: + -ZipArchive + -PakArchive + -MountPoint (known as FolderFile) + + IFileSystem + - addArchiveLoader + + - changed implementation of isALoadableFileExtension in all loaders + to have consistent behavior + - added a parameter to IFileList * createFileList + setFileListSystem + allows to query files in any of the game archives + standard behavior listtype = SYSTEM ( default) + + - CLimitReadFile + added multiple file random-access support. + solved problems with mixed compressed & uncompressed files in a zip + +- IrrlichtDevice + added: + virtual bool setGammaRamp( f32 red, f32 green, f32 blue, f32 brightness, f32 contrast ) = 0; + virtual bool getGammaRamp( f32 &red, f32 &green, f32 &blue ) = 0; + and calculating methods to DeviceStub. + + - irrlicht.h + changed exported irrlicht.dll routines createDevice, createDeviceEx, IdentityMatrix + to extern "C" name mangling. + + - ParticleSystem + removed the private (old?,wrong?) interface from the ParticleEffectors + to match the parent class irr::io::IAttributeExchangingObject::deserializeAttributes + +- Generic + - vector3d& normalize() optimized + added reciprocal_squareroot for f64 + + - dimension2d + added operator dimension2d& operator=(const dimension2d& other) + to cast between different types + + - vector2d bugfix operator+= + + - C3DSMeshLoader renamed chunks const u16 to a enum + removing "variable declared but never used warning" + + - added a global const identity Material + changed all references *((video::SMaterial*)0) to point to IdentityMaterial + removed warning: "a NULL reference is not allowed" + + - modified IRRLICHT_MATH to not support reciprocal stuff + but to use faster float-to-int conversion. + + - core::matrix4 + USE_MATRIX_TEST + + i tried to optimize the identity-check ( w.r.t. performance) + i didn't succeed so well, so i made a define for the matrix isIdentity -check + for now it's sometimes faster to always calculate versus identity-check + but if there are a lot of scenenodes/ particles one can profit from the + fast_inverse matrix, when no scaling is used. further approvement could + be done on inverse for just translation! ( many static scenenodes are not rotated, + they are just placed somewhere in the world) + one thing to take in account is that sizeof(matrix) is 64 byte and + with the additional bool/u32 makes it 66 byte which is not really cache-friendly.. + + - added buildRotateFromTo + Builds a matrix that rotates from one vector to another + + - irr::array. changed allocating routine in push_back + + added a new method setAllocStrategy, + safe ( used + 1 ), double ( used * 2 + 1) + better default strategies will be implemented + + - removed binary_search_const + i added it quite a long time ago, but it doesnt make real sense + a call to a sort method should happen always. i just wanted to safe + a few cycles.. + - added binary_search_multi + searches for a multi-set ( more than 1 entry in the sorted array) + returns start and end-index + + - changed some identity matrix settings to use core::IdentityMatrix + + - added deletePathFromFilename to generic string functions in coreutil.h and + removed from CZipReader and CPakReader + + - s32 deserializeAttributes used instead of virtual void deserializeAttributes in + ParticleSystem ( wrong virtual was used) + +- strings & Locale + - started to add locale support + - added verify to string + - added some helper functions + +- XBOX + i have access to a XBOX development machine now. I started to compile + for the XBOX. Question: Who did the previous implementation?. There + is no XBOX-Device inhere. maybe it's forbidden because of using the offical + Microsoft XDK. I will implement a native or sdl device based on opendk. + irrlicht compiles without errors on the xbox but can't be used. + +- Windows Mobile + reworked a little. added the mobile example to the windows solution for + cross development. + added maximal 128x128 texture size for windows mobile ( memory issues ) + +- Collision Speed Up + + The Collision Speed Up greatly improves with many small static child-nodes + + - added COctTreeTriangleSelector::getTriangles for 3dline from user Piraaate + + - modified createOctTreeTriangleSelector and createTriangleSelector + to allow node == 0, to be added to a meta selector + + - CSceneNodeAnimatorCollisionResponse has the same problem as CSceneNodeAnimatorFPS + on first update: + Problem. you start setting the map. (setWorld). First update cames 4000 ms later. + The Animator applies the missing force... big problem... + changed to react on first update like camera. + + - add Variable FirstUpdate. if set to true ( on all changes ) + then position, lasttime, and falling are initialized + + -added #define OCTTREE_USE_HARDWARE in Octree.h + + if defined octtree uses internally a derived scene::MeshBuffer which has + the possibility to use the Hardware Vertex Buffer for static vertices and + dirty indices;-) + + if defined OCTTREE_USE_HARDWARE octree uses internally a derived scene::CMeshBuffer + so it's not just a replacement inside the octree. It also in the OctTreeSceneNode. + #define OCTTREE_PARENTTEST is also used. It's skip testing on fully outside and takes everything on fully inside + + - virtual void ISceneNode::updateAbsolutePosition() + - changed inline CMatrix4 CMatrix4::operator*(const CMatrix4& m2) const + + - changed inline bool CMatrix4::isIdentity() const + to look first on Translation, because this is the most challenging element + + - virtual core::matrix4 getRelativeTransformation() const + Hierarchy on Identity-Check + 1) ->getRelativeTransform -> 9 floating point checks to be passed as Identity + 2) ->isIdentity () -> 16 floating point checks to be passed as Identity + + - inline void CMatrix4::transformBoxEx(core::aabbox3d& box) const + added isIdentity() check + +- changed CSceneNodeAnimatorCollisionResponse + - added CSceneNodeAnimatorCollisionResponse::setGravity + needed to set the differents Forces for the Animator. for eq. water.. + - added CSceneNodeAnimatorCollisionResponse::setAnimateTarget + - added CSceneNodeAnimatorCollisionResponse::getAnimateTarget + - changed CSceneNodeAnimatorCollisionResponse::animateNode to react on FirstUpdate + - TODO: set Gravity to Physically frame independent values.. + current response uses an frame depdended acceleration vector. + ~9.81 m/s^2 was achieved at around 50 fps with a setting of -0.03 + may effect existing application.. + +- SceneNodes + - CSkyDomeSceneNode + moved radius ( default 1000 ) to constructor + added Normals + added DebugInfo + added Material.ZBuffer, added SceneManager + + - CVolumeLightSceneNode: + changed default blending OneTextureBlendgl_src_color gl_src_alpha to + EMT_TRANSPARENT_ADD_COLOR ( gl_src_color gl_one ) + which gives the same effect on non-transparent-materials. + Following the unspoken guide-line, lowest effect as default + + - changed SceneNode Skydome from f64 to f32 + + - AnimatedMesh Debug Data: + mesh normals didn't rotate with the scenenode fixed ( matrix-multiplication order) + + - Camera SceneNode setPosition + Camera now finally allow to change position and target and updates all + effected animators.. + +- Device: + added the current mousebutton state to the Mouse Event + so i need to get the current mouse state from the OS + +- GUI + + - CGUIFont: + - added virtual void setInvisibleCharacters( const wchar_t *s ) = 0; + define which characters should not be drawn ( send to driver) by the font. + default: setInvisibleCharacters ( L" " ); + + - added MultiLine rendering + should avoid to us CStaticText breaking text in future + + - CGUIListBox + - changed Scrollbar LargeStepSize to ItemHeight + which easy enables to scroll line by line + + - CGUIScrollBar + - bug: event lost when moving outside the window + - bug: Scrollbar notifyListBox notify when the scrollbar is clicked. + - changed timed event in draw to OnPostRender + + - added GUI Image List from Reinhard Ostermeier, modified to work + + - FileOpenDialog + changed the static text for the filename to an edit box. + + - changed the interface for addEditBox to match with addStaticText + + - changed the interface for addSpinBox to match with addEditBox + + - added MouseWheel to Spinbox + + - changed CGUITable CLICK_AREA from 3 to 12 to enable clicking on the visible marker + + - CGUISpritebank + removed some crashes with empty Sprite banks + + - IGUIScrollBar + added SetMin before min was always 0 + changed ScrollWheel Direction on horizontal to move right on wheel up, left on wheel down + + - IComboBox: added ItemData + + - optimized IsVisible check in IGUIElement::draw + +- Image Loaders + - added TGA file type 2 ( grayscale uncompressed ) + - added TGA file type (1) 8 Bit indexed color uncompressed + + ColorConverter: + - added convert_B8G8R8toA8R8G8B8 + - added convert_B8G8R8A8toA8R8G8B8 + +- Media Files + - added missing shaders and textures to map-20kdm2. + Taken from free implementation + - ball.wav. adjusted DC-Offset, amplified to -4dB, trim cross-zero + - impact.wav clip-restoration, trim cross-zero + - added gun.md2, gun.pcx to media-files + - added new irrlicht logo irrlicht3.png + +- OctTree + -added + #define OCTTREE_PARENTTEST ( default: disabled ) + used to leave-out children test if the parent passed a complete frustum. + plus: leaves out children test + minus: all edges have to be checked + - added MeshBuffer Hardware Hint Vertex to octtree + +- CQuake3ShaderSceneNode: + - removed function releaseMesh + Shader doesn't copy the original mesh anymore ( saving memory ) + so therefore this (for others often misleading ) function was removed + - changed constructor to take a (shared) destination meshbuffer for rendering + reducing vertex-memory to a half + - don't copy the original vertices anymore + - added deformvertexes autosprite + - added deformvertexes move + - added support for RTCW and Raven BSPs ( qmap2 ) + - added polygonoffset (TODO: not perfect) + - added added nomipmaps + - added rgbgen const + - added alphagen + - added MesBuffer Hardware Hint Vertex/Index to Quake3: static geometry, dynamic indices + - added Quake3Explorer examples + - added wave noise + - added tcmod transform + - added whiteimage + - added collision to Quake3Explorer + - renamed SMD3QuaterionTag* to SMD3QuaternionTag* ( typo ) + - updated quake3:blendfunc + - added crouch to Quake3Explorer + (modifying the ellipsiodRadius of the camera animator ) + added crouch to CSceneNodeAnimatorCameraFPS + still problems with stand up and collision + - Quake3MapLoader + modified memory allocation for faster loading + - Quake3LoadParam + added Parameter to the Mesh-Loader + - added + The still existing missing caulking of curved surfaces. + using round in the coordinates doesn't solve the problem. + but for the demo bsp mesh it solves the problem... (luck) + so for now it's switchable. + TJUNCTION_SOLVER_ROUND + default:off + +- BurningVideo + - pushed BurningsVideo to 0.40 + - added blendfunc gl_one_minus_dst_alpha gl_one + - added blendfunc gl_dst_color gl_zero + - added blendfunc gl_dst_color src_alpha + - modified AlphaChannel_Ref renderer to support alpha test lessequal + - addded 32 Bit Index Buffer + - added sourceRect/destRect check to 2D-Blitter ( slower, but resolves crash ) + - added setTextureCreationFlag video::ETCF_ALLOW_NON_POWER_2 + Burning checks this flag and when set, it bypasses the power2 size check, + which is necessary on 3D but can be avoided on 2D. + used on fonts automatically. + - added Support for Destination Alpha + +- Direct3D8 + - added 32 Bit Index Buffer + - compile for XBOX + +- Direct3D9 + - fixed crash on RTT Textures DepthBuffer freed twice. + added deleteAllTextures to destructor + +- NullDriver + - removeallTextures. added setMaterial ( SMaterial() ) to clean pointers for freed textures + + - ISceneCollisionManager::getSceneNodeAndCollisionPointFromRay() allows selection by BB and triangle on a heirarchy of scene nodes. + + - Triangle selectors created from animated mesh scene nodes will update themselves as required to stay in sync with the node. + + - IVideoDriver has methods to enumerate the available image loaders and writers. + + - Octtree scene nodes are now IMeshSceneNodes rather than ISceneNodes, and so you can call getMesh() on them. + + - 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 occurred. 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 behavior 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) behavior 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.2 (16.12.2009) + + - Properly check boundaries in getFont and setFont. + + - Reinit values in the driver when scene manager is cleared. + + - Normals handling fixed in createMeshWithTangents, existing normals are not always destroyed now. + + - Fix terrain smoothing, bug found by loverlinfish + + - SOLARIS recognition removed. Please specify the platform define manually. This allows for compilation under sparc/Linux and sparc/Solaris + + - Some uninitialized variables fixed + + - FreeBSD joystick support added (for Debian package) + + - Fix cursor problems found by buffer and by rvl2 as described in http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=34823&highlight= + + - OSX/XCode updates + + - MS3D loader bug fixed + + - Float parse bug fixed + +------------------------------------- +Changes in version 1.5.1 (05.08.2009) + + - Make sure a missing font does not corrupt the skin. + + - Fix getAngle in vector2d as suggested by xray. This has only a minor impact on s32 vectors. + + - bugfix: CGUIFont::getCharacterFromPos regards now kerning (found by Arras) + + - Add support for range fog in some OpenGL versions. + + - Fix for shadow volume removal, submitted by vitek. + + - Avoid using X11 autorepeat to deal with broken X11 versions. + + - Speculars are properly exported into mtl files now, instead of corrupting them. + + - Binary type loading in attributes fixed. + + - bugfix: Use make_lower throughout for spritebank filenames (found and patched by Ion Dune) + + - STL loader fixed: Right-handedness corrected, normals and bboxes are correctly added now. + + - bugfix: CUnZipReader::openFile no longer returns true for empty files. Corresponding test added. + + - Big endian issues in .x loader fixed. + + - HSLColor methods repaired. + + - copyToScaling fixed. + + - Fixed problem with highlighting menus when mouse was outside sub-menu area. + + - bugfix (2796207): menu acted (wrongly) on left-click down instead of left-click up. + + - bswap16 fallback macro fixed + + - getBaseName fixed to work correct with dots in filenames. + + - static method isDriverSupported allows for simple check of available drivers. + + - Some defines added to check for the Irrlicht version of the library. + + - Make sure all renderstates are properly initialized + + - Wrong size for main depth buffer fixed. + + - Fix 3ds shininess to the allowed range. + + - Fix loading of Collada files from irrEdit 1.2 + + - Remove texture pointers after texture clear. + + - WindowsCE pathnames fixed. + + - Some virtuals are now overridden as expected. + + - Incomplete FBOs are properly signalled now + + - Update to libpng 1.2.35, fixed issues on 64bit machines with system's libpng. + + - Fixed wrong grab/drop in setOverrideFont + + - Added draw2dRectOutline + + - rectf and recti added. + + - Fix ALPHA_CHANNEL_REF to a fixed check for alpha==127 as expected. + + - Fixed OSX device bug where screen size was not set in fullscreen mode. + + - cursor setVisible changed to be called less often. + + - OpenGL version calculation fixed. + + - OSX device now supports shift and ctrl keys. + + - Fixed ambient light issues in burningsvideo. + + - device reset for d3d fixed when using VBOs. + + - Fix dimension2d += + + - MD2 mesh loader: Now uses much less memory, reduced number of allocations when loading meshes. + + - OpenGL render state (texture wrongly cached) fixed. + + - Fixed animator removal. + + - Checnged collision checks for children of invisible elements to also be ignored (as they're actually invisible due to inheritance). + + - Fix terrain to use 32bit only when necessary, make terrain use hw buffers. Heightmap loading and height calculation fixed. Visibility and LOD calculations updated. + + - Some mem leaks fixed + + - FPS camera resets the cursor better + +----------------------------------- +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. + + - 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. + + - Changed the initial attenuation back to (0,1/radius,0). To override this value simply change the attenuation in the SLight (lightnode->getLightData().Attenuation.set(x,y,z)) + + - Dirty fix for OSX device setResizable and a bug fix to do with resizing the device. + + - 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 behavior 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. + + - BBoxes of animated meshes (skinned meshes) are updated again. + + - Lost devices (as found with D3D) are properly handled now. So the screen can be resized or minimized without crashing the app. + + - Renamed IGUIElement::setRelativePosition(const core::rect& r) to IGUIElement::setRelativePositionProportional(), as it has radically different functionality from setRelativePosition(const core::rect& r) + + - Added IGUIElement::setRelativePosition(const core::position2di & position) to set a new position while retaining the existing height and width. + + - Many Collada fixes. z_up coords are supported now, texture coords are properly loaded. Transparency is supported. + + - Camera scene node rotation and target can now be bound together so that changing one automatically changes the other (as the FPS camera has always done). See ICameraSceneNode::bindTargetAndRotation() + + - Removed the extra libpng files for OSX. OSX now also uses the default libpng. + + - Enhanced PCX support with some more color formats and write support. + + - Fixed LMTS problems with extra data in files. + + - Removed VS6 .dsw / .dsp project files - VS6 is no longer supported. + + - Particles can be scaled during animations. Particle scaling needs to happen in the emitter now, instead of in the Particle system scene node. Deprecation methods will guide the user. + + - 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 ) + + - Fixed scaled octree nodes being incorrectly frustum culled. + + - FSAA under OpenGL and Win32 added. Now all hw drivers and platforms should support it. + + - Unlimited RTT fix for D3D systems. Depth buffers are now shared if possible, otherwise a new depth buffer is generated. In order to save VidMem one should create RTTs starting with the largest one. + + - Avoid RTTs with nonFBO-support under OpenGL which are larger than the screen. Since we rely on rendering into textures in this case we need to clamp the size by the screensize. + + - Fixes for getAbsoluteFilename under Linux in order to return a filename instead of en empty string in case the file doesn't exist. + + - Use absolute path names when creating / finding textures. + + - Font tool implementation for Linux with xft, by Neil Burlock. + + - Support for normals and UV coords from DeclData in .x files. + + - Modified line2d::intersectWith() to cover more cases. + + - Added IVideoDriver::drawPixel(). + + - Moved the window pointer from endScene to beginScene, as this is required for OpenGL support of external window pointers. + + - Fix for terrain culling. + + - Added minimize button to win32 window (if resizable) + + - Major API change: RTTs are now created via addRenderTargetTexture instead of createRenderTargetTexture, which allows to retrieve them from the texture cache, but also changes the way of removing the RTTs, and especially one must not drop the pointer anymore. + + - WindowsCE-Bugfix + + - disableFeature can be used to override feature support of the video driver. + + - draw2DImage can now also handle RTTs under OpenGL (which were flipped before). + + - Ogre mesh format fixes for proper texture support. + + - Added .obj mesh writer. + + - Some core::string constructors made explicit to avoid unintended conversions. Just add core::stringc() or core::stringw() around the old code to avoid warnings. + + - IdentityMatrix is now a properly defined global, with external visibility on all platforms. + + - Bugfix for context releases with glx 1.3 on error. + + - Removed constraints for sizes of the terrain scene node. + + - Support for 32bit indices in a special MeshBuffer class. + + - isBetweenPoints return true now even for the begin and end points, i.e. line segments are now including their start and end. + + - Fix XML reader creation for non-existing files and invalid callbacks. + + - Changed interpretation of MaterialTypeParam==0 in transparent materials. Now it's consistent with all other values, but one has to set the value to 0.5 to get the old behavior (slightly faster rendering, but no smooth borders) + + - Replaced transformBox by transformBoxEx in some internal methods to avoid major malfunction of the transformations. + + - Fix use of zip file inside zip files. + + - Avoid loading textures which are not used by the mesh in b3d loader. + + - Added scaleTCoords methods to MeshManipulator + + - Enable use of other meshes for shadow mesh generation, can be used to speed up shadow generation and rendering for complex meshes. Patch based on a version by tonic. + + - Fixed usage of SIrrCreationParameters struct, which dind't have copy constructor and assignment operator anymore, since the Irrlicht version string was made const. + + - New glext.h (version 41) and glxext.h (version 20) supporting OpenGL 3.0 + + - Added support for read-only locking of textures. Can speed up those calls. + + - Added support for locking RTTs under OpenGL. + + - Implementation of UserData events from system events. + + - ICameraSceneNode::setIsOrthogonal replaced by a parameter to setProjectionMatrix. + + - All meshbuffers are now dynamically allocated to avoid problems with grabbed buffers, which may be deleted before the last drop happens (due to static memory allocation). + + - Enhanced scene graph traversal with example from rogerborg. + + - FPS camera disabling of event receiver works better now. + + - scene deserialization allows for a user defined callback after a new scene node is created. + + - Fixed tangent mesh loading from .irrmesh files. + + - OpenGL clamp modes are now properly set. + + - IMeshManipulator::transformMesh renamed to transform, also supports meshbuffers now. + scaleMesh renamed to scale, supports meshbuffers as well. + + - vector3d::rotationToDirection added. + + - New mesh generators for cone and cylinder. + + - Hardware accelerated Vertex and Index Buffer support finally integrated into Irrlicht. Thanks to a resource handling idea by Klasker and the almost immediate implementation by Luke, Irrlicht now supports VBOs under OpenGL and D3D. + Hardware buffers make rendering the same vertices much faster. To use this feature with a mesh, simply set a usage type via MeshBuffer->setHardwareMappingHint(scene::EHM_STATIC). The driver will upload the vertices and indices on the next draw and reuse this information without the need to upload it each frame. + Vertex and Index buffers can also be updated separately, which is e.g. useful for the terrain node's LOD. + + - Changed FBO creation according to Nadro's patch. Seems to have zbuffer problems currently. + + - Update to libpng 1.2.29 + + - Compiler flag for PerfHUD support added. + + - recalculateNormals and tangent space creation enhancements by ryanclark. + + - Added getColorFormat methods for device and driver, returning the color format of the device's window and the driver's framebuffer. + + - Added isFullscreen method. + + - Added isWindowFocused and isWindowMinimized methods. + + - Screenshots are now always made from the frontbuffer, so always the last completely rendered image is captured. However, overlapping windows may corrupt those parts of the screenshot (as was previously happening with d3d already). + + - New device creation parameter to disable Irrlicht's system event handling. + + - New device creation parameter to specify depth bits. + + - New device creation parameter to request alpha channel in framebuffer. + + - Draw2DImage methods under OpenGL now also handle RTTs correctly. + + - Fixed RTT bug which lead to strangely clamped textures. + + - Speed improvement for screenshots on some Intel cards under OpenGL. + + - My3D file loader fixed. + + - Terrain mesh performance increased. + + - Fixed mem leak in cube node. + + - Compiler errors in shaders won't corrupt the material renderer list anymore. + + - Quake3 shader files now have properly working texture matrices again. + + - FPS and Maya style cameras are now standard cameras with a special animator. + - ISceneNodeAnimator now inherits IEventReceiver + - New method ISceneNodeAnimator::isEventReceiverEnabled, returns false by default + - CCameraSceneNode::OnEvent passes events to animators with enabled event receivers + - ISceneNodeAnimatorCameraFPS and ISceneNodeAnimatorCameraMaya interfaces for changing camera settings at run-time. + + - Changed SExposedVideoData to use void* instead of s32. Fixed 64bit portability. + + - Added support for front face culling. + + - Fix for HLSL shaders in one file. + + - Billboard::setColor bug fix by rogerborg. + + - Scene node sorting uses squared distances now. + + - Enhanced API for hte math functions. Many of them will now return a reference to *this for chained method invocations. + + - prevent .x loader to load .xml files. + + - AntiAlias support for OSX device. + + - Period character handling bug fixed. + + - New filesystem methods for filename handling. + + - added getVideoModeList and getDesktopResolution support for OSX + + - Octree supports tangent meshes now. Some performance improvements for the generation. + + - Fix mouse pointer and fullscreen mode problems in OSX. + + - Make cube and sphere scene node a mesh scene node (for access to the cube/sphere mesh). + + - Support for normal maps in 3ds files. Mem leak fixed. Loading for files with keyframe data fixed. + + - BillboardTextSceneNode is now an IBillboardSceneNode and an ITextSceneNode. + + - Support for external windows under Linux. + + - .X loader bug fixes. + + - Better debug visualization for MeshSceneNodes. + + - Fixed bug in material serialization when using the NullDriver. + + - Fix for Win32 CursorControl::setVisible + + - Support for LWO files. + + - Support for Collada 1.4 files. + + - Better and faster terrain smoothing by Frosty Topaz. + + - Fixed a performance bug in ISceneNode constructor reported by izhbq412 + + - Win32 device now makes the cursor invisible immediately when setVisible(false) is called. + + - Command line tool for mesh conversion added. + + - Added volume light scene node + + - .obj files now won't duplicate vertices unnecessarily. This allows recalculation of smooth normals and other things, and is also faster when rendering. The loading is a little slower now. + They also support normal maps and texture clamping now. Group support added, can be ignored via scene manager attribute scene::OBJ_LOADER_IGNORE_GROUPS. + Normals will be calculated if the file doesn't provide them. + + - Better fix for hires timers on dual core machines by RogerBorg + + - added Initial Windows Mobile 6 Version. + - Windows Mobile 6 SDK + - Visual Studio 2005 + + - Added checks to avoid buffer overrun in b3d loader. Enabled normals calculation in all cases, previously it was not done for lightmapped meshes. + Fixed transparency support. Added mipmap creation flag support which might disable mipmap creation too often. Should be checked. + + - Burningvideo: MipMap Selection repaired + + - renamed private Driver function getTextureSizeFromImageSize to getTextureSizeFromSurfaceSize + + - Added collision manager speedup patch by RogerBorg. + + - D3D drivers now releases the IImage member from initialization, thus freeing lots of memory. The image is accessible via the driver anyway. + + - SDL device character handling enhanced. + + - MeshBuffers can now access the elements of the S3DVertex base class in all vertex types directly, instead of using the getVertices() pointer access. This simplifies simple mesh manipulations as it does not require a switch statement over all vertex types. + + - More OpenGL renderstate bugs fixed + + - GLSL changes for setting arrays. Also allow for only pixel or vertex shader to be set. + + - Bugfix for removeChild in AnimatedMeshSceneNode. + + - Some bugfixes for Joint handling and skinned meshes. Added getJointCount in IAnimatedMeshSceneNode and isStatic in ISkinnedMesh. + + - Added WAL image format support based on the original loader by Murphy McCauley, written for Irrlicht around version 0.7. + + - OpenGL RTTs now also support alpha values. + + - New method driver->getVendorInfo() to query information about the actual hardware driver. + + - Fixed somed CQuake3ShaderSceneNode problems. + + - Changed BurningsVideo internal Vertex Format. version changed to 0.39 + + - SceneManager: + Removed the seperate rendering states for quake3 Shader Scene Nodes. + Nodes are now solid or transparent. ( but still more states are needed ) + + - GUI: + + - Editbox didn't draw children + - Checking IsEnabled is now consistent across all GUI elements + - Move window to front bug fixed. + - Disabling the BMP loader now compiles without the built-in font + - Added setTextAlignment to IGUIComboBox + - Avoid dropping skin pointer which is in use. + - Better warning for fonts without regions (sometimes wrong file is loaded by the user). + - Fixed a bug in CGUISpriteBank which caused a crash when a non-looping animated sprite reached the end of its animation. + - Modal screens no longer flash invisible children when rejecting a focus change. + - Finally added StarSonata patch with table element and TabControl additions. Table is based on MultiColor listbox by Acki, and has loads of changes by CuteAlien. + +------------------------------------------- +Changes in version 1.4.2 (22.9.2008) + + - Unified the handling of zwrite enable with transparent materials on all hw accelerated drivers. This means that all transparent materials will now disable ZWrite, ignoring the material flag. + There is a scene manager attribute, though, which will revert this behavior to the usual SMaterial driven way. Simply call + SceneManager->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true) and set the SMaterial flag as desired. + + - Some changes for texture matrices in q3 shaders. + + - Added BlindSide's irrAllocator patch for proper TextureMatrix release under Win32 with any CRT library. + + - Added VC9 project files. + + - Added getEmitter for particle system scene nodes. + + - Fixed rounding problem in getScreenCoordinatesFrom3DPosition + + - Fixed Software renderer color flicker, was a shift bug I believe. + + - irrMap fix to make root node always black, by rogerborg. + + - Possible core dump fixed in particle system node, by CuteAlien. + + - Mem leak fixed in b3d loader. + + - Avoid double rendering of child nodes of joints. + + - Support for d3d draw2dimage clipping by CuteAlien. + + - Fixed an animation transition bug, pointed out by wuallen. + + - Fixed the major problem with OpenGL drivers, that claim to be 2.x compatible, but don't offer NPOT support (well, they do, but only in sw rendering...). Now we check for the extension string only. + + - Fixed .obj loader bug which inserted vertices in wrong buffers. + + - Fixed minor mem leak in Linux device. + +------------------------------------------- +Changes in version 1.4.1 (04 Jun 2008) + + - MD3 meshes are movable again. + + - New JPG image writer version by Vitek. + + - Texture matrix fixes, all methods should now work as expected. + + - Some container methods now return the this pointer after member functions have been called on them, in order to allow call chains. + + - Some new methods for SColorf access, for uniform API of all colors. + + - bug fix for SMaterialLayer equality check. Did only check the TextureMatrix pointers, instead of the matrices. + + - New getMesh method for the SceneManager, which takes an IReadFile instead of a filename. + + - Support for flags _WIN32 and _WIN64 in addition to WIN32 and WIN64 added, this simplifies usage of Irrlicht headers under MSVC. + + - Fixed a crash in GUIMeshViewer + + - new string method findLastChar by Halifax + + - GUIEditBox got the 1 pixel shift after click fixed. + + - Some debug visualization has been fixed for skinned meshes + + - Undef PI symbol before declaring core::PI to avoid compilation problems + + - SAnimatedMesh now properly returns properties of Meshes[0] if those exist, such that it should be usable in place of an SMesh again. + + - Fixed 2d initialisation in opengl and d3d9 driver. This should fix problems with render states mixing up and distrubing, e.g. skin effects. + + - Avoid a crash when passing setSkin the current skin + + + - Fixed current frame calculation for non-looped animations. Bug reported by greenya. + + - Fixed bug in CBillboardSceneNode::setColor, reported by rogerborg + + - Fixed clipping of menu, toolbar and combo box GUI elements, reported by greenya + - setNotClipped now applies all the way up to the root of the GUI environment, rather than just to the next parent + + - Made new scene managers use the original manager's GUIEnvironment, reported by MasterGod + + - Fixed IGUICheckBox::setEnabled, reported by Dorth + + - Fixed the FollowSpline animator to avoid crashes when only one waypoint is given. + + - OpenGL VolumeShadow now uses glPolygonOffset to avoid zbuffer artifacts. + + - Fixed meshbuffer corruption in append methods. + + - Fixed mem leaks in irrArray. + + - Fixed minor bugs in ISceneNode and ISceneManager. + + - Fixed the MeshCache handling of GeometryCreator meshes. + + - Terrain LOD bugfix. + + - Some Collada 1.3 loader enhancements and bug fixes. + + - Fixed a bug in CGUISpriteBank which caused a crash when a non-looping animated sprite reached the end of its animation. + + - Enhanced the .obj loader with the patch from ryanclark. This allows for recalculation of smoothed normals of the mesh, also should decrease the tri count on some meshes. + + - Avoid the global Logger to be destroyed too early. + + - Function setbit was renamed to setbit_cond to avoid name clashes. + + - Fixed .x animations with multiple references to the same joint from different meshes. Fixed texture path problems. + + - Support for Milkshape 1.8 files, also with multiple weights per joint. + + - The config file now also supports _IRR_OSX_PLATFORM_ and _IRR_USE_OSX_DEVICE_. This allows to use the Linux device (X11 support) on OSX. + + - Avoid terrain scene node crash when heightmap cannot be loaded. + + - Speed improvements for WaterSceneNode. + + - FlyCircle animator now also works for upvectors (Direction parameter) which are not (0,1,0). Is also faster now, since most calculations are done on init. Thanks to Dorth for working on this. + + - The 3ds loader correctly creates a texture matrix when texture tiling properties are found in the file. + + - Fix for S3DVertex comparison operators. Used some wrong logic. + + - Bugfix getCurrentRenderTargetSize in D3D drivers. Due to signature differences a wrong virtual method was chosen. Thanks to Jiang for finding it. + +------------------------------------------- +Changes in version 1.4 (30 Nov 2007) + + - Major API change: All material properties which are available per texture layer (curently texture, texture matrix, texture filters, and texture wrap mode) are separated into a new struct SMaterialLayer. You can access them via the array TextureLayer[] in SMaterial. The texture matrix methods in SMaterial are still alive, and also textures can be accessed via methods in SMaterial now. But still, many places in user code need some update (usually changing material.Textures[i] to material.TextureLayer[i].Texture etc.) + + - Major API rewriting for proper const usage. Now, most getter methods are const and so are the larger parameters and return values. Moreover, many methods taking only unsigned numbers now use u32 instead of s32 in order to recognize this limitation from the method's signature. + + - the base class for nearly all Irrlicht classes has been renamed from IUnknown to IReferenceCounted + + - Fixed Skybox texture orientations. They are now displayed non-flipped. Existing skyboxes have to be changed, though: Exchange left and right texture. Textures from Terragen and other tools can be used directly, now. Quake maps will also need the right/left exchange. + + - Added ITexture::isRenderTarget() + + - Added STL mesh file format reader and writer. + + - Added IMeshManipulator::createMeshWelded which creates a copy of the mesh with similar vertices welded together. + + - Irrlicht now has its own file format for static meshes. It is based on xml and has the + extension .irrmesh. Irrlicht is able to write every IMesh to this file format, and of course to + read it back again. + + - Irrlicht is now able to write Meshes out into files. Use ISceneManager::createMeshWriter() + to obtain an interface with which you can write out meshes. Currently, an own .irrmesh + file format is supported as well as the COLLADA file format. + + - fixed the keyboard autorepeat difference between Linux and Windows. Thanks to denton we now have only KeyPressed events on both systems in case of autorepeat. + + - Added several new particle emitters and affectors from IrrSpintz. Also some new getter and setter methods were added. + + - D3D transparent materials do not disable zbuffer writing automatically anymore. This has to be done by the user to keep those settings configurable. + + - OpenGL texture now also require a regenerateMipmapLevels() after unlocking. This is the same as for d3d devices now. + + - Point sprite support in the driver. Point sprites use just one 3d vertex and a size to create a textured billboard on the GPU. This can provide fast particle systems, especially in combination with shaders. The proper particle extension will follow later on as it needs some more refactoring. + + - OpenGL 2D drawing accuracy fix by tuXXX + + - Added OnResize and getCurrentRenderTargetSize to the software video drivers. + + - Added Spot light type for dynamic lights. Note that both position and direction for all dynamic lights are now determined by the LightSceneNode, the SLight attributes are only used for internal purposes. + API change! One can easily work around this change by setting the LightSceneNode's Position and Rotation instead of the SLight's. This change won't provoke a compile error, though, and can hence go unrecognized besides the visual problems. + The lights use a default direction (0,0,-1) which is rotated by the usual scene node transformations and can hence be modified by scene node animators. + A change in the Radius usage can lead to strange artifacts. Just increase the Radius in this case. further handling of Radius is to be discussed. + + - Added per pixel fog support for OpenGL. + + - Added driver support for user defined clip planes, based on mandrav's patch. + The OpenGL version is more picky about ModelView matrices, so it's best to set the projection plane at the time it is used. + + - .obj files now load relative indices correctly. Collada files load textures. + + - A new MeshBuffer implementation is publicly available. It supports a shared vertex list for all MeshBuffers, used for MS3D meshes. + + - MeshBuffers can recalculate their BoundingBoxes on their own now, no need for MeshManipulators. New append methods help to merge MeshBuffers. take care that the types match! + + - The new texture generation mode is working. With ETCF_NO_ALPHA_CHANNEL textures are generated without ALPHA bits reserved. + + - D3D9 hardware mipmap updates are re-enabled, problems should be reported. + + - In some cases fullscreeen modes under win32 should have a better frame rate now. + + - Fixed the hillplane mesh to work with non-quadratic dimensions as well. Changed the interface also, so use a u32 dimension to specify the tilecount now. + + - Hires timers are disabled on windows systems with more than one CPU, due to bugs + in the BIOS of many multi-core motherboards. To enable hires timers in your project, + use SetProcessAffinityMask to set to use only one CPU before creating the device. + + - OpenGL render targets now the same way up as the other drivers. If you have + written opengl shaders that use render targets then you'll need to change your + texture coordinates accordingly. + + - Fixed some OpenGL renderstate stuff. setBasicRenderstate returns with + active texture layer 0. The material renderer must return from OnUnset + with the same active texture layer. The alpha test is disabled and the + texture mode should be GL_MODULATE. + + - Fixed CSoftwareTexture2::getOriginalSize, reported by CaptainPants. Added a + new method CSoftwareTexture2::getMaxMipMapSize to return the size of the largest + mipmap, which is used by texelarea instead of getOriginalSize. + + - Changed parameter order of addArrowMesh and added default parameters such + that it's enough to set the color (or even just the name). + + - Fixed bugs in MY3D and OBJ loader. + + - Added IMeshCache::clearUnusedMeshes(). This allows the user to remove + meshes that are sitting in the mesh cache but aren't used by any scene nodes. + This is useful for example when changing levels. + + - Added IUnknown::getReferenceCount() + + - createDevice now reports errors if the driverType is unknown, previously it + created a window but populated it with a null driver without any warning. + + - Fixed a bug in CBillboardTextSceneNode::setText where the old text was not + cleared. + + - Changed irrArray::linear_search to use the == operator rather than < + This may be slower in some cases, but it no longer returns false positives + when searching arrays of classes that override the < operator but + !(x for relative positioning within their parents + + - getFileSystem added to the GUI environment + + - New IGUISpriteBank, used to hold 2d image data like fonts and GUI icons. + Icons provided by the built-in font are now accessed through the skin's sprite bank. + Users can override the icons by setting a different sprite bank and setting new sprites. + + - Skins are now serializable and are loaded/saved with the GUI. + + - IGUIStaticText getter/setter functions patch by rogerborg. + +- added 3d TextSceneNode2. to view a Text in real 3D Space + in fact it is a combination of Billboard & TextSceneNode + +- Burning Video (the second but only complete software renderer) + - New Compile Config BURNINGVIDEO_RENDERER_ULTRA_FAST + - New Compile Config BURNINGVIDEO_RENDERER_FAST + touching the 20fps border in the demo ( P4 mobile 2Ghz ). 15fps average. + ( Compile config Release Fast-FPU ) + + - VertexCache for Tansformed & Light Vertices + boost small drawPrimitive Calls ( 2DRectangle, Billboard ) and Real Index Triangles + + - Bilinear Dither + - clipping test ( compare instead of generic plane normal ) + - support for NOT using vertexcolor + #define SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + +- added vertex to color to billboard. + shade top & shade down. + to support some static lighting effect on billboards + +- Implemented line rendering for SoftwareDriver + +- XMLWriter fix for 32bit wchar_t (esp. for big endian) + +- updated to latest PNG library + +- implemented CImagerWriterJpeg::writeImage + +- The ISceneManager::addCameraSceneNodeFPS() has a new parameter named 'jumpSpeed' + and a Key Map Entry. + +- added param to IIImageWriteFile::writeImage + control Parameter for the backend ( e.g. jpeg compression level ) + +- addContextMenu: CGUIEnvironment::addContextMenu set the focus on the submenu. + +- Added IFileSystem::createMemoryReadFile for accessing memory like a file. + +- Added core::map class submitted by Nastase Catalin (Kat'Oun) + +- Fix vertex colors for .x and .ms3d, alpha bug in .obj + +- Fixed 16bit depth screens under Windows. + +- Implemented getMeshBuffer(SMaterial) for all AnimatedMeshes. + It was returning 0 for all implementations previously. User defined IMesh derivates + will also have to implement it now due to the removed empty implementation. + +- Added yield() method to IrrlichtDevice which allows to pause the Irrlicht process for + a very short time. This allows other processes to execute without a major + penalty for the Irrlicht application. + +- Added sleep() methd to IrrlichtDevice, for pausing the Irrlicht process for a longer + amount of time. + +- Auto-split mesh to 16bit buffers in 3ds loader + +- 8bit RGB332 image format support + +- isActive() under Linux now behaves like the Windows variant: True iff window has focus + +- Fixed(?) the glXGetProcAddress problems with different drivers + +- B3D changes by Luke: + Texture scaling bugfix, support for alpha blending, new option to normalise weights, + animation code optimization, fixed memory leak + +- ROUNDING_ERROR is now ROUNDING_ERROR_f32 or ROUNDING_ERROR_f64 + +- Material ZBuffer flag changed to a u32 value + Reason: change ( off or on ) to , off, lequal, equal + Necessary for multi-pass if previous stage has had transparency + +- DebugDataVisible is now an enum of flags + show normals is supported ( uses the new build in arrowmesh ) + +- New Function: GeometryCreator + addArrowMesh. build a closed cylinder and a cone + used to show normals as debug feature + +- New Function: + CMeshManipulator::transformMesh(scene::IMesh* mesh, const core::matrix4& m) const + transforms VertexPosition and VertexNormal + +- BUGFIX: CGUIButton notified Pressed when Mouse was clicked Inside ( correct ) + but also left up outside rectangle ( incorrect) + +- BUGFIX: Octree:getPolys(const scene::SViewFrustum& frustum, SIndexData* idxdata) + was recursive calling invisible children + +- CFileList: Changed FileListEntry sorting to + a) Directory comes first + b) sorting ignores case + so it feel's more like common browers + +- added a Texture transform to IVideoDriver::setTransform + +- quaternion::getmatrix + in fact the getmatrix version is returning the transposed. + i'm quite sure that this is the wrong implementation. + so this should be verified to remove the getmatrix_transposed version... + +- Quake3 Map Loader: + new loading method + - Bezier Patches with LOD more than 3 + - Multiple Meshes, stay compatible with the previous version + - Indexed Triangle List + - initial support for quake3 Shaders and Entities + - Shaders are parsed. When it's possible to resolve a 2 Texture Scheme it's taken + Shaders exist in namespace scene::quake3 + - The Example Quake3Map shows how to continue applying the Q3Shaders with SceneNodes + ( for example animmap converts to TextureAnimator.) + TODO: use the Irrlicht Variable Syntax to remove redundant code.. + +- added getVertexPitch() to IMeshBuffer interface + +- added generic isupper, isspace.. functions to coreutil.h to remove dependencies for ctype.h + ( future: it's possibly to use binary comparison test..) + removed 1000's include of string.h and moved one to irrstring.h + in preparing of complete removing the MSVC. + +- moved fast_atof.h to the public include + added strtol10 to remove dependencies for stdlib.h + anyway math.h is needed for powf + +- core::vector3d + added getInterpolated_quadratic. + vector3d getInterpolated_quadratic(const vector3d& v2, const vector3d& v3, const T d) const + // this*(1-d)*(1-d) + 2 * v2 * (1-d) + v3 * d * d; + +- irrstring: added param start to findLast(T c, s32 start = -1 ) + reason: to continue searching reverse on a specific position + (parameter is checked against boundaries ) + +- added operation reciprocal_squareroot to irrmath. + core::reciprocal_squareroot = 1.f / sqrtf ( x ) + changed the core::vector3df normalize vector. + specialized templates are not allowed in irrlicht currently, so it's only for f32 for now. + a C function and a NVidia Version are in irrmath.h + +- add Primitives to CFPSCounter + and changed interpolation to 1500ms instead of 2000ms + and rounding to ceiling.. + +- added Interface setAmbientLight to ISceneManager + it was a Bug, because SceneManager always calls Driver therefore AmbientLight has to be set in SceneManager. + +- changed GUIFont & FontTool to support kerning ( on a global basis ) + very basic mode.. apply an offset for position + useful for example if you want to apply an outline stroke in your favorite + and therefore let the texture grow. + and to correct the border back on drawing, specify the parameter in IGUIFont. + this is quite useful if you want to use more artistic fonts. + default = 0 + better kerning would need a seperate coordinate set for each symbol. + +- changed MD2_FRAME_SHIFT to lower framerate + -> lower IPol + problems can occur if somebody uses hardcoded frame-numbers instead + of Animation name... + +- changed spelling "frustrum" to "frustum" + + -> changed also SViewFrustrum.h to SViewFrustum.h + +- changed Parameter AutomaticCulling from bool to enum E_CULLING_TYPE + to support more than two culling modes. + + added Frustum culling ( it's a copy & paste from the octree ) + added initial bounding sphere + used for culling point lights.. + +- Added getSystemMemory and getProcessorSpeedMHz for Windows and Linux to the OSOperator, submitted by Vitek. + +------------------------------------------- +Changes in version 1.2 (29 Nov 2006) + +- Added Solaris/Sparc port (basically some compiler define statements). Irrlicht and the examples should compile out-of-the-box on Suns with the usual Makefiles and gnumake. + +- Added texture matrix support for hardware accelerated drivers. This allows for efficient texture coord manipulations for complete meshes at once. + +- Multisampling with OpenGL under Linux added + +- Non-power-of-two textures are left unscaled if the driver supports such textures. + +- new draw2DImage method that speeds up drawing many quads from the same texture. Font drawing is improved by this under OpenGL. + +- TGA files are now always correctly flipped and loaded if compressed. All PNG color formats are now supported, including correct alpha handling. + +- 3ds mesh loader fix in texture loading, now loads some textures that were not loaded before, but might introduce problems with very recent files. OGRE mesh loader bugfixes and lightmap support. Several B3d mesh loader updates. Obj and mtl loader enhancements. + +- A new compile flag (IRR_OPENGL_USE_EXTPOINTER) allows Irrlicht to either use OpenGL extension function pointers or direct OpenGL calls. + +- OpenGL now uses frame buffer objects for render targets larger than the screen, supplied by Mandrav + +- Split ESNRP_LIGHT_AND_CAMERA passes into ESNRP_LIGHT and ESNRP_CAMERA to fix a problem with lights being rendered before cameras in OpenGL (thanks again to Vitek for finding this). ESNRP_LIGHT_AND_CAMERA is now deprecated. + +- Fixed many OpenGL render state problems which were related to wrong texture states. The textures are now enabled and disabled by the material renderers in OnSetMaterial. Also enabled the texture state cache which helps preventing texture changes just as the one for D3Dx. Thanks to hey_i_am_real for some good hints on where the problem was located. + +- Added compile flag _IRR_COMPILE_WITH_X11_ which is by default enabled. Disabling the flag removes all X11 dependencies from Irrlicht and allows for a headless Linux Irrlicht server - added by request :-) + +- Win32 OpenGL driver tries to use the requested bpp size. + +- Default texture format is now A8R8G8B8 if not explicitly specified. This fixes some color artifacts with lightmaps. Bugfix submitted by hey_i_am_real. + +- In OnPostRender all transformations were taken as relative and multiplied with the root transformation matrix every time due to a wrong check for the real root node. This shoudl increase render performance for scenes with lots of (invisible) nodes. + +- Added correct list copy constructor. + +- Color selection dialog added. + +- New GUI skin "Burning Skin". + it's a black & white skin. look elegant on true-color. + and looks ok on 1-Bit ( e.g. no vertex color in burnings video ) + +- GUIStatic text is correctly grayed out if disabled. + +- Added getHeight method for terrain node submitted by Spintz. It calculates the height from the base mesh instead of requiring ray casts and collision detection and is much faster. + +- New methods core::lerp to linearly interpolate two floats and SColor.getLuminance to calculate luminance of RGB color. + +- MAJOR API CHANGE: + Fixed matrix access methods mat(x,y). These were previously said to be (row,column) but actually were (column, row). This lead to some confusion and made their use quite tricky. Irrlicht code is updated for the new method, but applications will silently fail now (i.e. compile without errors, but not working as expected). + +- Update to zlib-1.2.3 + +- Fixed vertex alpha handling in DirectX drivers. + +- Image writers fixed and working (at least for little endian systems). + +- VSync under Linux fixed and correctly working. + +- New os::Byteswap::byteswap methods which can be used for byteswapping (endianess correction) in mesh loaders and image loaders. + +- New video driver feature to check for multitexture feature. + +- Direct3D drivers update the devicelost variable if reseeting failed with this return code. + +- VideoModeList under Linux is correctly filled now. No glX calls are made if GLX extension is not found - only software drivers are available then. RandR extension can be enabled with a new compile flag in IrrCompileConfig.h, either instead of XF86VidMode or in addition. + +- Big Endian support for MS3D loader. + +- Apfelbaum software renderer: basic mipmap support (per triangle), switch for using w-buffer instad z-buffer ( default on ) + +- Better FPU support: Changed various fpu-call's in whole project (main reason to use faster float to int conversion on x86. ( fistp )) + +- changed Visual Studio 7.1 vcproj project config "Release Fast FPU" to __fastcall in /QIfist + +- CGUIFont added True Alpha Font Support. (currently it's a little hack, but it'a good starting point. Fonts are back compatible. To use the new feature make first pixel half transparent in the font file.) + +- Scolor: replaced s16 color with u16 color, replaced s32 color with u32 color to get rid of unnecessary arithmetic shift + +- Colorconverter: X8R8G8B8toA1R5G5B5, set Alpha High, minor: A1R5G5B5toA8R8G8B8 changed if (a) to conditional set + +- CImage: added boxfilter (weigthed average), (generic, slow) + +- The scene manager now sets an ambient light color when calling ISceneManager::drawAll(). + You can influence this by calling ISceneManager::setAmbientLight(). That light color + is also stored when saving .irr files via ISceneManager::saveScene(). + +- Loaded COLLADA files which contained only one single mesh now behave like all the + other loaded meshes, and the #meshname workaround has been removed. + +- File lists are now sorted. + +- Dynamically checking the OpenGL version now instead of at compile time to call the supported methods of the executing machine, not that one of the compile host. This should fix the extension check and the automatic mipmap update. + +- Fixed vertex alpha handling of 2D images with OpenGL. + +- Default depth buffer under Windows now 24bit to avoid zbuffer fighting. + +- Fixed light count in OpenGL. + +- Particle emitters can now be enabled/disabled via a new method. + +- Sky dome is rotatable just like the sky box. + +- Rotation animator can be applied to several nodes now, before it only rotated the first one it was applied to. + +- Support for drawing other vertex primitive lists such as triangle strips. + +- Default specular color is white again, thus simply enabling shininess is enough to get speculars. + +- Some .x loader and animator improvements. Vertex color support. + +- isActive now also work under Linux. + +------------------------------------------- + +Changes in version 1.1 (06 Aug 2006) + +- New example to show some features of the .irr format + +- Added support for making screenshots in all video drivers and a general + possibility to save any IImage to several file formats. + Some image writers are not yet implemented. As a testcase screenshots + are now available in the demo by pressing F9. + This code was contributed by Travis Vitek. + +- Changed EAMTS_OCT to EAMT_OCT. + +- Improved .3ds and .obj file importers. + +- Added support for .b3d (Blitz Basic) submitted by Luke Hoschke and + .pak (Quake archive) files submitted by skreamz. + +- Added sky dome implementation contributed by Anders la Cour-Harbo (alc). + +- In addition to the Cube scene node (formerly test scene node) there is now also a sphere scene node available, + with an adjustable amount of polygons. Use ISceneManager::addSphereSceneNode to create it. + Thx to Alfaz93 for making available his code on which this node is based on. + Note that both nodes now use default material settings, e.g. lighting is enabled by default. + +- Fixed Linux keyhandling for many keys. + +- The aspect ratio has been inverted in the matrix, which means when setting a new aspect ratio + for cameras, set it to screen.width/screen.height now instead of screen.height/screen.width + as previously. + +- added support for reading/importing binary .x files. + +- .ms3d and .x normals are now correctly transformed in animations, bounding + boxes are slightly better transformed, but not yet correct. + +- Added possibility to load and save Irrlicht scenes to and from xml files via + ISceneManager::saveScene and ISceneManager::loadScene. Note that not all + scene nodes are supported yet, but most features should already work. + +- Bounding box of the Skybox corrected (set to null) + +- The SMaterial structure now supports 4 textures. (Currently ignored by the renderers and their materials.) + +- Test scene node renamed to CubeSceneNode. + +- Added scene node animator factories. This is the same as scene node + factories, but for scene node animators. + +- Added scene node factories. This is an interface making it possible to dynamicly + create scene nodes. To be able to add custom scene nodes to Irrlicht and + to make it possible for the scene manager to save and load those external scene nodes, simply + implement this interface and register it in you scene manager via ISceneManager:: + registerSceneNodeFactory + +- Introduced IMeshSceneNode interface with the possibility to set readonly materials to make + it possible to use the mesh materials directly instead of overriding them. In this way + it is possible to change the materials of a mesh causing all mesh scene nodes + referencing this mesh to change, too. + +- Added possibility to load OGRE .mesh files directly, thanks to Christian Stehno who contributed + a loader for this. + +- Merged with Irrlicht 1.0 for MacOS + +- Added a method getType() to ISceneNodeAnimator. + +- There is now a system to serialize and deserialize attributes of scene nodes. In this way + it should be quite simple to to expose the attributes of your scene node for scripting + languages, editors, debuggers or xml serialization purposes. + +- Irrlicht containers and strings now have allocators, making it possible to + use them across .dll boundaries. + +- Changed the name of scene nodes from wide character to to char* for speed and memory reasons. + +- Renamed IStringParameter class to IAttributes and enhanced it to be able to + serialize its content into and from xml. + +- Textures now have a method getName(). + +- Added the methods getTextureCount() and getTextureByIndex() to IVideoDriver. + +- Most classes now derive virtually from IUnknown. + +------------------------------------------- +Changes in version 1.0 (19 Apr 2006) + +- Irrlicht now will load d3d 9 dlls (like d3dx9_27.dll) manually if needed. If you compile irrlicht + with an SDK which needs one of these dlls, irrlicht will now also start up on a pc without + these Dlls installed. Note that now these dlls will also only be loaded if your application + uses shaders. If the dlls are missing, shader support will be disabled. + +- The Apfelbaum Software Software Renderer now works in 32 bit and is capable of rendering dynamic + lighting as well as doing alpha channel blending. + +- Added support for the Code::Blocks IDE (http://www.codeblocks.org) + +- It is now possible to draw temporarily to foreign windows, by specifying a window handle when + calling IVideoDriver::endScene(). Note: This does not work in fullscreen mode and is not + implemented for all devices (only for D3D8, D3D9, Software1 and Software2, and only for Windows). + In addition, you can also specify the source rectangle to present. + +- Picking is now more accurate and also works with view ports and better with orthogonal cameras. + +- Scene Nodes now have an additional flag, IsDebugObject. This denotes if a + scene node is a debug object. Debug objects have some special properties, + for example they can be easily excluded + from collision detection, picking or from serialization, etc. + +- Scene Nodes now have the possibility to return their type using + virtual ESCENE_NODE_TYPE getType(). + +- Improved support for orthogonal rendering: Skyboxes and billboards can be + used with orthogonal cameras now, too. + +- Fixed a bug in collision + +- Fixed some marshalling bugs in Irrlicht.NET + +- Some fixes to make gcc 4 happy. + +- Fixed a bug which caused the engine to crash when trying to use the + apfelbaum software rasterizer with linux + +- Several improvements to Irrlicht.NET, for example string output for vectors, viewfrustrum access + for cameras, drawing of bounding boxes, support for orthogonal cameras. + +- Updated DMF importer to support new DeleD functionalities, solid materials will now be + shown correctly again in Irrlicht. Thanks to Salvatore "Il Buzzo". + +- Added a method to change the return value of ICameraSceneNode::isOrthogonal + +- Improved md2 animation playback + +- Fixed the REFLECTION_2_LAYER materials. Now also works for OpenGL. Had to change the parameters + of this material (for all drivers), the reflection is now at texture 2 and the diffuse map at + texture 1. This was the other way round before. + +- Added examples for csharp, visualbasic, delphi.net and boo. + +- Several other small bug fixes. + +------------------------------------------------------------------------------------- +Changes in version 0.14.0 (30 November 2005) + +- Irrlicht now includes another video driver type. Together with D3D8, D3D9, OpenGL, the NULL + driver and the Software Renderer, an Irrlicht user now has the decision between 6 renderers: + The new included renderer is The Apfelbaum 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. In short: It looks a lot like the already available hardware + accelerated drivers, but without hardware. :) This renderer has been written entirely by + Thomas Alten, thanks a lot for this huge contribution. + +- Irrlicht now supports anisotropic filtering. Use the SMaterial::AnisotropicFilter member or + EMF_ANISOTROPIC_FILTER flag to enable it. I implemented this for all 3 hardware accelerated + drivers: D3D8, D3D9 and OpenGL. + +- Irrlicht now supports the recently released new microsoft compiler. Irrlicht versions compiled + with older verions of this compiler can now also be used with the new one, which wasn't possible + previously because of a name mangeling issue. + +- All 2D drawing functions can now be used to draw into textures (render targets). This also + means for example that the whole GUI environment can be rendered into textures. + +- Irrlicht.NET now supports shaders. + +- Irrlicht now loads all textures in 32 bit mode by default. (Previously this + was 16bit). To change this behavior back again, use + device->getVideoDriver()->setTextureCreationFlag(ETCF_ALWAYS_16_BIT, true); + +- Irrlicht.NET now supports Particlesystems and Shaders. Thanks to a code + contribution by Delight. + +- Fixed a bug in the mipmap generation. Now mipmaps are not that blurry + anymore and the rendering quality has been improved a lot. + +- It is now possible to assign a userData int to callback functions of shaders. In this way it + it easily possible to use the same callback method for multiple materials and distinguish + between them during the call. + +- Directional lights are now supported in the OpenGL and D3D drivers. To switch on directional + lighting, set the light type to ELT_DIRECTIONAL in the SLight structure. + +- Fixed several bugs in the GLSL implementation. Thanks to Michael Zoech for + sending in his improvements. + +- For the windows version of Irrlicht, the engine now displays an icon in the + program window, if there is one available in the start path with the name "irr.ico". + +- It is now possible to use images with alpha channels on buttons. Use the new + IGUIButton::setUseAlphaChannel() method to enable this feature. + +- The scene manager has a new method getSceneNodeFromName() which finds a scene node by its name. + +- It is now also possible to attach scene nodes to joints/bones of sceletal animated .x files. + (Using IAnimatedMesh->getXJointNode() ). This was previously only possible with milkshape models. + +- Billboards now draw their bounding box when debugdata is set to visible for them. + +- Lights now draw their bounding box and radius when debugdata is set to visible for them. + +- Upgraded to irrXML 1.2. Thanks to some hints by Patrik Mller, irrXML, the XML parser used + by the Irrlicht Engine now has CDATA support and some other useful new features. + +- Support for VisualC++ (Express) 2005. Added a project file and a IrrlichtPropsVC2005.vsprops + file which sets the no deprecate define and adds needed libraries. + +- Fixed size of the bounding box of billboards. + +- Billboards are now also culled by default, increasing rendering speed a bit. + +- Fixed a bug which caused the .ms3d loader to crash when loading .ms3d files + without materials. Thanks to sdi2000 for posting this. + +- Fixed a bug causing the possibility to crash when destructing the scene + graph or a scene node with children. + +- Fixed some bugs which caused invalid RTT operations, when for example the + render target texture was smaller than the screen. + +- Fixed a heavy bug in Irrlicht.NET causing lots of memory leaks when drawing text. + +- Fixed a bug in the attachement of scene nodes to animated X files. + +- Fixed a bug in the .NET Vector3D addition operator. + +- Updated to Salvatore Russo's DMF loader version 1.3. Notes by him: + This version just adds some new functionalities. First of all Alpha Blended Textures are now + supported by DeleD as well as loader. Because of some trouble with Irrlicht 0.12.0 TGA loading, + TGA textures are always flipped so I've added a parameter so that you can choose to + flip or not all TGA textures coords, this way: + SceneManager->getParameters()->setParameter(scene::DMF_FLIP_ALPHA_TEXTURES, true); + you can also set material transparent reference value by setting: + SceneManager->getParameters()->setParameter(scene::DMF_ALPHA_CHANNEL_REF, 0.01); + you can use every value beetween 0 and 1, but to respect DeleD rapresentation + 0.01 is OK, just a note, if you set 0, it's just like you set 0.5, this means + that each pixel found corresponding to a position in alpha map that has a value<127 + won't be drawn. + +- Fixed a small bug in the line breaking algorithm. + +- Fixed a bug which caused the engine to display strange artifact pixels when drawing 2D images + like text in screens which odd resolutions. + +- Slightly changed the interface of createDevice and createDeviceEx(): the version parameter + now is a char* instead of wchar_t*. Also, IrrlichtDevice::getVersion() now returns char* + instead of wchar_t*. + +- Fixed some parts in the source to make Irrlicht compile in Linux 64. + +- Renamed the EDT_DIRECTX8, EDT_DIRECTX9, _IRR_COMPILE_WITH_DIRECTX_8_ and + _IRR_COMPILE_WITH_DIRECTX_8_ enumeration literals to EDT_DIRECT3D8, EDT_DIRECT3D9, + _IRR_COMPILE_WITH_DIRECT3D_8_ and _IRR_COMPILE_WITH_DIRECT3D_9_. You might need to + update your code and compilation settings with these new names. + +- Added the remaining '..' directory in the linux version of the file list + +- Updated to a faster version of the TerrainSceneNode by Spintz. Much thanks again! + +- Fixed a bug causing billboards to be displayed upside down. + +- The D3D drivers now won't crash anymore when they get feeded with nullpointers as shader constants. + +- Irrlicht now identifies the Linux platform it runs on and returns a more detailed string + when calling getOperationSystemVersion(). + +- Fixed some bugs in several collision test methods thanks to Spintz. + +- Updated font tool + +- Made the list::iterator constructor which took a sklistnode as parameter private, + to make Irrlicht compatible with the Errlicht interface. + +------------------------------------------------------------------------------------- +Changes in version 0.12.0 (24 August 2005) + +- It is now possible to have multiple scene managers. Use ISceneManager::createNewSceneManager() + to create a new one. This can be used to easily draw and/or store two independent scenes at + the same time. + +- Irrlicht now supports GLSL, the OpenGL Shading Language, which means Irrlicht now + supports 14 shading modes/languages: ARB Vertex Programs, ARB Pixel Programs, HLSL, + GLSL 100, GLSL 110VS1.1, VS2.0, VS3.0, PS1.1, PS1.2, PS1.3, PS1.4, PS2.0, PS3.0. + Lots of thanks go to William Finlayson for implementing this and making available his code + to be used in Irrlicht. + +- Added support for pixel shader 3.0 and vertex shader 3.0. + +- Irrlicht now supports detail maps, use EMT_DETAIL_MAP for this. The new terrain scene node + tutorial shows how to use detail maps. + +- Again some changes have been made in Irrlicht.NET. For example it is now a little bit more memory + friendly, I removed several bugs and made the terrain scene node, realtime shadows and key codes + available. + In addition, I extended the .net example application a lot, just try it out. + +- I've worked around a heavy bug in the microsoft compiler which caused lots of bugs in Irrlicht.NET. + They are all fixed now. See http://support.microsoft.com/default.aspx?kbid=823071 for details. + +- The timer of the engine has been enhanced a lot, which maybe needs a little change in your + project if you are upgrading from an older version of Irrlicht. It is now possible + to set the speed of the timer, a new time value, and to start and stop it. Also, all + calls to getTime() will now return the same value within the same drawing frame. + The timer will only advance when ITimer::tick() is called. IrrlichtDevice::run() will + call this method automatically, but if you aren't using this method, and you are wondering + why your scene is not animating anymore, just call Device->getTimer()->tick() before + drawing your scene. If you need the system time, not the new virtual time, + use ITimer::getRealTime(). + +- The material EMT_TRANSPARENT_ALPHA_CHANNEL now is using a configurable alpha ref value. + The default value is 127, which means people who are using this material for drawing + things like grass, trees etc will get nice results automatically when changing to 0.12.0. + To change to a different alpha ref value, just change SMaterial::MaterialTypeParam value. + See EMT_TRANSPARENT_ALPHA_CHANNEL for details. + Also, this fixes two bugs: + - A bug causing the D3D versions not looking like the OpenGL version. + - A second bug which caused the texture to look like disappearing when looking at from far away. + +- Upgraded to a new dmf loader version by Salvatore Russo which is able to use a texture path + and material directories. Set DMF_USE_MATERIALS_DIRS and DMF_TEXTURE_PATH using the + ISceneManager::getParameters() method. + +- It is now possible to set a separate scale for the second texture coordinate set in the + terrain scene node when calling ITerrainSceneNode::scaleTexture(). This is useful when using + detail maps on the terrain. + +- Added a new material flag named EMF_NORMALIZE_NORMALS. You can enable this if you need + to scale a dynamic lighted model. Usually, its normals will get scaled too then and it + will get darker. If you enable the EMF_NORMALIZE_NORMALS flag, the normals will be + normalized again. + +- When loading Milkshape .ms3d files, Irrlicht also loads materials and tries to apply the textures. + Thanks to atomice for this patch. + +- The ISceneManager::addCameraSceneNodeFPS() has a new parameter named 'noVerticalMovement' with which + it is possible to disable vertical movement of the FPS camera and make the camera behave just like + in most ego shooters today. + +- Made Irrlicht 64 bit compatible, removing some 32 bit only constructs. However, I wasn't able to + test it out extensively. If you are compiling Irrlicht for a 64 bit windows environment and get + a linker problem, try playerdark's solution: + "The linker settings are so that no machine is specified in the drop down field, instead, + the command line option /MACHINE:x86 is set manually which interferes with the 64 bit linker + of course. Removing that from the 64 bit version (and replacing it with the drop down selection + in the 32 bit version for that matter) fixed the linker problem." + +- There is now a IrrlichtDevice::postEventFromUser() method available, to make it possible to + post key or mouse input events to the engine if you are using an own input library for + example for doing joystick input. + +- The GUI Environment now has an own basic RTTI system, and all IGUIElement derived classes + have a method named getType(). This is needed for the .NET wrapper but will be used + later for serializing and deserializing. + If you wrote your own GUIElements, you need to set the type for your element as first parameter + in the constructor of IGUIElement. For own (=unknown) elements, simply use EGUIET_ELEMENT. + +- Thanks to William Finlayson, Irrlicht now also supports RTT (render to texture) when + rendering using OpenGL. + +- Thanks to William Finlayson, the EMT_REFLECTION_2_LAYER is now implemented in the + OpenGL version of Irrlicht, too. + +- There is now a mesh cache interface available. With this, is is possible to get access to + all loaded meshes, and to remove them to free memory. You can get access to the cache + using ISceneManager::getMeshCache(). Please note that the addMesh() method of ISceneManager + now is now longer available, you can find it now in the IMeshCache interface. + +- The VideoDriver now has a method for clearing the zbuffer at any time: IVideoDriver::clearZBuffer(). + With this, it is for example easily possible to overlay two scenes. + +- Fixed a bug which caused Irrlicht to crash when loading grayscale jpeg files. + +- Somebody sent me an .x file (tank_human1_crashes_irrlicht.zip) which caused Irrlicht to crash. + It seems I've lost that mail, but maybe you are reading this: It's fixed now. :) + +- Fixed a bug which caused the diffuse maps of lightmaps to disappear under certain circumstances + in OpenGL. + +- Its now possible to make IGUIStaticText draw its background. + +- Removed the first two default parameters from + IGPUProgrammingServices::addShaderMaterialFromFiles() to prevent SWIG + to create non compilable wrapper code. + +- Fixed a small bug which caused the terrain scene node to be culled incorrectly. + +- Changed the names the driver return (now "OpenGL 1.5", "Direct3D 9.0" and "Direct3D 8.1") + +- Added a new macro _IRR_DEBUG_BREAK_IF which is now used instead of the _asm int 3 break points in + debug mode. + +- Fixed a bug were the software renderer didn't clip 2d rectangles. This effect was visible for + example when using list boxes, selecting an entry at the end an scrolling up so that it wasn't + visible anymore. + +- There is now a new gui event available (named EGET_COMBO_BOX_CHANGED) which will be + sent when the selected item in a combo box has been changed. Finally. + +- Fixed a Problem which caused an empty window to be created when a rendering device + could not be initialized under special circumstances. Thanks to Sascha Plumhoff for + the bug report. + +- Fixed a bug with the FileList in Linux, reported by DrAnonymous and fixed by William Finlayson. + +- Fixed some bad documentation bugs. + +- The XWindow handle is now exposed too, via IVideoDriver::getExposedVideoData(). + +------------------------------------------------------------------------------------- +Changes in version 0.11.0 (08 July 2005) + +- Antialiasing is now supported by Irrlicht in the D3D8 and D3D9 renderer. To switch + it on, use createDeviceEx() and set SIrrlichtCreationParameters::AntiAlias to true. + +- Irrlicht.NET can now run inside a pre created Windows.Form window. + +- I'm no longer providing a Visual Studio 7.0 project/solution file for the Irrlicht + Engine sourcecode, only 7.1 and 6.0 are supported. If you are using Visual Studio 7.0, + just open the .dsp file for Visual Studio 6.0, it will be converted automatically. + +- Irrlicht.NET includes now all basic GUI Elements and can capture GUI events. There are + still some features missing, but it is already enough to do simple things like showing + message boxes, displaying images, getting input strings, etc. + +- Improved the .NET documentation a bit. + +- There is a full implemented ISceneCollisionManager now available in Irrlicht.NET. + +- The Linux OpenGL renderer now supports mip mapping. + +- It is now possible to compile Irrlicht as shared lib in Linux. To do this, go into the source + folder and run 'make sharedlib'. This should create a libIrrlicht.so.0.11.0 file in + lib/Linux. To install it in /usr/local/lib, you can run 'make install'. + +- The drawing of the GUI system has been refactored and a lot of redundant code has + been removed. + +- The new method IVideoDriver::draw2DRectangle() is able to draw rectangles not only + filled with a single color, but with a gradient from four colors. This is implemented + in all drivers except the Software driver which still uses one color for this method. + +- It is now possible to customize the GUI system's skin a lot more: Simply implement your + own IGUISkin interface and implement the draw..() methods. + +- There are now two build-in skins available: Windows Classic and Windows Metallic. The + default skin is now Windows Metallic, if you want to change back to the old skin, use the + following code: + gui::IGUISkin* newskin = environment->createSkin(gui::EGST_WINDOWS_CLASSIC); + environment->setSkin(newskin); + newskin->drop(); + +- Added improved keyboard input handling for the Linux version of Irrlicht, thanks to + Fabien Coutant for the fix. + +- Fixed a bug in the Linux OpenGLDriver which caused to load a wrong OpenGL extension + and made multitexturing look quite strange. Thanks to hybrid for spotting out that + bug. + +- COLLADA file loading now works the same like the loading of other meshes: Just + call ISceneManager::getMesh("yourfile") and display it using for example + ISceneManager::addAnimatedMesh(yourLoadedMesh); + To make it possible to create instances from meshes, lights and cameras in COLLADA + files again as in irrlicht 0.10, just enable the collada instance creating mode: + SceneManager->getParameters()->setParameter(COLLADA_CREATE_SCENE_INSTANCES, true); + +- Added lots of useful methods to the IStringParameters class. It is now possible to + set not only strings but also boolean, integer and float values as parameters. +- Fixed a bug with the TRANSPARENT_ALPHA_CHANNEL materials in all renderers to make them + work more as expected: They didn't write to the zbuffer. If you are using this + material and you don't want the new setting, just set the ZWriteEnable flag in the + SMaterial structure of your transparent material to false. Thanks to Fabien to + point this out. + +- There are now some new defines making it possible to use system installed libs instead of + the ones which come with Irrlicht: _IRR_USE_NON_SYSTEM_JPEG_LIB_, + _IRR_USE_NON_SYSTEM_LIB_PNG_ and _IRR_USE_NON_SYSTEM_ZLIB_, which are defined by default + in the file IrrCompileConfig.h + +- Renamed ISceneManager::getStringParameters() to ISceneManager::getParameters() +- Changed the define _IRR_D3D_SHADER_DEBUGGING to _IRR_D3D_NO_SHADER_DEBUGGING to be + able to make it defined by default and to let it be included in the doxygen documentation. + +- The SceneManager now does not do any culling tests for cameras, lights and skyboxes. + +- Added a transformBoxEx() method to matrix4 which transforms a bounding box more accurate. + +- Small edit box copy & paste bug fixed thanks to Fish HF + +- Fixed a bug which caused the engine to read windows messages when embedded in + a custom win32 control when called IrrlichtDevice::setResizeAble(). Thanks for + Duncan Mac Leod to find that bug. + +- Fixed a bug in the HLSL renderer which caused Irrlicht to crash, if no vertex shader + was specified. Thanks to mightypanda for reporting this. + +- Fixed a bug in the normal map generation thanks to jox. Parallax mapping and + normalmapping now even look a lot better because of this. ;) + +- Updated to irrXML 1.1: + - The XML parser is now also able to parse embedded text correctly when it is shorter than + 2 characters. + - The XML parser now treats whitespace quite smart and doesn't report it when it is + obviously used for formatting the xml file. (Text won't be reported when it only contains + whitespace and is shorter than 3 characters) + - The XML parser won't crash anymore when the xml file is malformed and an attribute has + an opening but no closing attribute. + - Removed a documentation which claimed that the xml parser doesn't work as the xml standard + when replacing special characters, which wasn't true. + +------------------------------------------------------------------------------------- +Changes in version 0.10.0 (26 May 2005) + +- The engine is now able to use parallax mapping. It's implemented for D3D9, D3D8 and OpenGL. + The perPixelLighing tutorial shows how to use it. Thanks go to Terry Welsh who wrote + the 'Parallax Mapping with Offset Limiting'-paper on which the Irrlicht implementation + is based and who allowed me to use his texture for use in the example. + +- Added render to texture support. Currently, only the D3D9, D3D8 and the software renderer + are able to use this feature. There is a new example, showing how to render scenes into + a texture. + +- Irrlicht now can load .png textures. There is also a new compile configuration + define to exclude the png loading option: _IRR_COMPILE_WITH_LIBPNG_. Thanks to + rt who originally wrote the png loader and who allowed me to use and modify his code + and place it under the Irrlicht Engine license. + +- Added support for COLLADA files. COLLADA is an open Digital Asset Exchange Schema for the + interactive 3D industry. There are exporters and importers for this format available + for most of the big 3d packages at http://collada.org. Irrlicht can import COLLADA files + by using the ISceneManager::getMesh() method. As COLLADA need not contain only one single mesh + but multiple meshes and a whole scene setup with lights, cameras and mesh instances, + this loader sets up a scene as described by the COLLADA file instead of loading + and returning one mesh. The returned mesh is just a dummy object. However, if the + COLLADA file does not include any tags, only meshes will be loaded by the + engine and no scene nodes should be created. Meshes included in + the scene will be added into the scene manager with the following naming scheme: + path/to/file/file.dea#meshname. The loading of such meshes is logged. + Currently, this loader is able to create meshes (made of only polygons), lights, + and cameras. Materials and animations are currently not supported but this will + change with future releases. + +- Added Delgine DeleD .dmf mesh loading support. I simply added Salvatore Russo's .dmf loader to + Irrlicht, and changed some parts of it. Thanks to Salvatore for his work and for allowing + me to use his code in Irrlicht and put it under Irrlicht's license. + +- Specular highlights are now finally usable the engine. To activate, simply set the shininess + of a scene node to a value other than 0: sceneNode->getMaterial(0).Shininess = 20.0f; + You can also change the color of the highlights using + sceneNode->getMaterial(0).SpecularColor.set(255,255,255,255);. The specular color of the + dynamic lights will influence the highlight color, too, but they are set to a useful + value by default when creating the light. This feature is currently only available in + the D3D drivers. + +- Added a new material type: EMT_TRANSPARENT_ALPHA_CHANNEL_REF. This draws a pixel of the + material only when the alpha channel has a value greater than 128. It is ideal for drawing + for example leaves of plants and does not use alpha blending, so it is a lot faster than + EMT_TRANSPARENT_ALPHA_CHANNEL. + +- There is now a createDeviceEx() method with which it is possible to create an Irrlicht Engine + device into an already existing window. This currently only works in Windows. + This method will be extended in the future with other options. + +- Irrlicht.NET has been extended with ports of the SceneNodeAnimators, TriangleSelectors + the FileSystem and Font drawing. Also the documentation of it has been improved a lot. + +- There are two new tutorials/examples available. One demonstrates how to use render to texture + feature, the other one shows how to run Irrlicht inside a precreated Win32 window/widget. + This means there are now 17 examples available in the SDK. + +- The software renderer now renders 3d geometry transparent when its material is + somewhat transparent. + +- The XML Parser has been enhanced. Several small bugs have been fixed and there are some + new features: The parser can now read ASCII, UTF-8, UTF-16 and UTF-32 (both little and + big endian) files, and return the parsed string data in one selectable format from the + same list. In addition, it is now completely independent from Irrlicht. If you wish to + use the parser without the engine, take a look at the newly created project at + http://irrxml.sourceforge.net. + +- Upgraded to DirectX Exporter Mod 1.3.1 + +- Upgraded dev-cpp project file to Dev-C++ 4.9.9.2. Removed dependency to zlib and + jpeglib for devcpp, the necessary .c files are now simply included in the project. + +- Renamed the VisualStudio and DevCpp sub directories in the SDK to Win32-gcc, + Win32-VisualStudio. + +- Fixed a bug in irrXML causing it to replace xml characters wrongly sometimes. + +- The C++ decorations at createDevice() have been added again, because lots of people + started to mix the gcc and the microsoft .DLL and got confused why the thing crashed + at random positions. + +- Moved heapsink and heapsort into the core namespace. + +- Updated to My3D version 3.15 + +- Fixed the wrongly drawn alpha channel material in OpenGL driver and a problem with the + VertexAlpha material in the same driver. + +- Implemented multipass rendering in the OCTTree scene node now too. This means that octtrees can + now contain transparent materials as well. + +- Improved string comparison speed, especially when comparing with pointer to char or w_char, + no more temporary strings are being constructed now. In addition, there are some new + string comparison methods in this class. + +- Added string::replace() method. + +- Added string::trim() method. + +- Addes string::erase() method. + +- Fixed a bug in array which caused data corruption if an element which already inside the + the array was pushed_back. Thanks to vox for reporting this and to provide a solutin + +- Added ISceneManager::addMesh() method. + +- Added IMeshManipulator::recalculateNormals(IMeshBuffer*) method. + +- The file array.h has been renamed to irrArray.h + +- Due to a bug, Irrlicht 0.9 didn't cull the scene nodes anymore which resulted in a huge + performance loss. This is fixed now. + +- After lots releases ignoring the 'make the fps camera smoother request', it is now + finally integrated. + +- Removed audiere dependency and the mp3 file, reeducing SDK download size. + +- A bug was fixed causing the binding of the wrong fragment program sometimes in OpenGL. + +- Lots of internal filenames have been renamed. All CVideo* files have been renamed to + fit the other name conventions, CD3D9Driver.h into CD3D9Driver.h for example. + +- The IMaterialRenderer interface now has the new method getRenderCapability() which + returns if the material is able to be rendererd with all settings on current hardware. + +- Added IMeshManipulator::setVertexColors(); + +- Added float color reading support in the 3DS loader. + +- video::EVDF_BILINEAR_FILER renamed to EVDF_BILINEAR_FILTER + +- core::equals function added. + +- fixed a small bug in fast_atof thanks to jox + +- Added a method ICamera::isOrthogonal() which is being used by + ISceneCollisionManager::getRayFromScreenCoordinates(), thanks to a bug report and fix by + jox in this thread: http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=6243 + +- Added some fixes to the GUI environment to make the parent and child pointers be more + consistent as suggested by jox in this thread: http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=6220 + +- Fixed a bug which caused the ambient light not to be reset after a window resize in D3D8 and 9. + Thanks to jox for this bug report and fix. + +- vector3df equals method added. + +- added SColorf::getInterpolated() method + +- Moved ITextSceneNode interface to include folder. + +- Fixed a small bug in the My3DLoader which failed sometimes finding the right textures. + +- Fixed bounding box problem with meshes without joints in .X file loader, thanks to + jox. (http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=6669) + +- Fixed IFileSystem::getWorkingDirectory in Linux version. + (http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=6678) + +------------------------------------------------------------------------------------- +Changes in version 0.9 (28 Mar 2005) + +- There is now a 100% working terrain renderer available. The old buggy and unfinished terrain + scene node has been replaced by a new TerrainSceneNode which is based on Spintz's + GeoMipMapSceneNode and Soconnes terrain renderer. Lots of thanks for their work on + this and that they allowed it to be modified and integrated into Irrlicht. + +- It is now possible for a scene node to draw itself in multiple passes. This means it can + register itself for multiple render passes (E_SCENE_NODE_RENDER_PASS) and during rendering + it can query the current render pass using ISceneManager::getSceneNodeRenderPass(). With + this, SceneNodes can contain solid and transparent materials at the same time and will be + rendered in the correct order from now on. + The IAnimatedMeshSceneNode and the IMeshSceneNode implement this feature, so it is now + possible to create for example cars with transparent windows without the need of a separate + scene node. Because of this change, all render time enumeration values have been renamed. + +- Irrlicht is now able to load OCT files directly. OCT files + can be created with Paul Nette's Radiosity Processor from http://www.fluidstudios.com + or exported from Blender with Murphy McCauley's exporter. This exporter can be found + in the directory \exporters\OCTTools of the Irrlicht SDK or from his homepage + http://www.constantthought.com/project/OCTTools. A lot of thanks go to Murphy McCauley + for this work on this and his permission to include his OCTTools into Irrlicht. + +- Irrlicht is now able to load Cartography shop 4 (.csm) files directly. A lot of + thanks go to Saurav Mohapatra for this work on this and his permission to adapt and + include his IrrCSM library into Irrlicht. If you are using .csm files, please note that + you'll have to set the path of the textures before loading meshes. You can do this using + SceneManager->getStringParameters()->setParameter(scene::CSM_TEXTURE_PATH, + "path/to/your/textures");. The original loader can be obtained from + http://www.geocities.com/standard_template/index.html + +- Irrlicht is now able to load Pulsar LMTools (.lmts) files directly because it now + integrates a modified version of Jonas Petersen's lmts loader in version 1.5 (from + http://development.mindfloaters.de/). Lots of thanks go to him for creating this + loader and giving his permission to add it to Irrlicht. If you are using this loader, + please note that you can set the path of the textures before loading .lmts files. + You can do this using SceneManager->getStringParameters()->setParameter( + scene::LMTS_TEXTURE_PATH, "path/to/your/textures"); + +- Irrlicht is now able to load my3D files directly. The My3DTools 3.12 loader by + Zhuck Dimitry was (a bit modified and) integrated into the engine. Lots of thanks + go to him for his work and for giving his permission to do that. Newer versions + of this loader can be found at http://my3dproject.nm.ru. The exporters for this + file format have also been added into the \exporters directory of the SDK. + +- To be able to replace built-in meshloaders with newer external versions without the + need of recompiling the engine, now mesh loaders which are added to the engine using + ISceneManager::addExternalMeshLoader() are prefered over built-in mesh loaders. + Thanks to for his suggestion of this. + +- D3D8 and D3D9 support for dev-cpp has been improved. If you are using Dev-Cpp and + a DirectX-Devpack for recompiling the engine, just add + -DIRR_COMPILE_WITH_DX9_DEV_PACK to your compiler + settings and something like -ld3dx9 -ld3dx8 to the linker settings and + press 'compile'. + +- The SceneManager now contains an interface for storing and exchanging parameters. + ISceneManager::getStringParameters() returns IStringParameters, which can be used for + example by extensions like external mesh loaders to set and read independent parameters. + This is also currently used by the newly built in CMS, LMTS and MY3D loader: It is possible to + set a value 'CSM_TexturePath', 'LMTS_TexturePath' or 'MY3D_TexturePath' to let them know + the path of the textures. + +- IAnimatedMeshSceneNode now has two new methods for being able to have more influcence + on the animation playback: It is now possible to set the playback mode to looped or + non looped with IAnimatedMeshSceneNode::setLoopMode() and it is possible to set + a callback interface which will be called when animation playback has finished + using IAnimatedMeshSceneNode::setAnimationEndCallback(). Thanks to Electron for his + suggestion for this addition. + +- The software renderer has a new triangle renderer specialized on disabled zread and write. + This means that skyboxes are now rendered in the correct order when using the software + renderer. + +- Multitexturing and other extensions in Linux are now turned on by default. There is a new + #define in the file IrrCompileConfig.h for disabling this again: LINUX_OPENGL_USE_EXTENSIONS + +- There is now a EET_USER_EVENT user event type for making it possible to send custom + events through the system. + +- The setTarget()-method of the FPSCameraSceneNode now is finally correctly implemented. + +- Changing parents of scene nodes is now much safer. The parent member of a scene node now is + set to 0 in all cases and should never point to invalid data when rearranging the scene node + tree. In addition, there is now a getParent() method in the ISceneNode class. + +- Debug breakpoints using "_asm int 3" are now only being used when in debug mode and + using Micosoft's compiler. Now more exotic compilers like BorlandC++ will like + Irrlicht better because of this. + +- Updated zlib version to 1.2.2 + +- An implementation of 3D triangle clipping in the software renderer has been started. It + is not 100% ready, but it is a beginning. This means now for version 0.9, that there are + not that much artifact triangles drawn anymore. But this means also that drawing is + a lot faster and that triangles clipped at the border of the screen will disappear + too fast. If anyone wants to finish the drawClippedIndexedTriangleListT() method + in the CSoftwareDriver class, he is welcome :) + +- There is a new parameter in the IVideoDriver::createImageFromData() which causes the + image to be able to own foreign memory. + +- A renderstate setting has been fixed which caused to disable mip maps on wrong geometry + when there was other geometry which had no mip maps. At least this bug doesn't appear + on my hardware any more, I hope this means the problem it is now fixed. + +- A bug in the D3D version of the stencil shadows has been fixed thanks to Murphy. Sometimes + you could see a small shadow similar to the the real shadow in the scene. This should now + be fixed. + +- Irrlicht can now draw non filled concyclic reqular 2d polyons like triangles, tetragons, + pentagons, hexagons, heptagons, octagons, enneagons, decagons, hendecagons, dodecagon and + triskaidecagons. And circles. Yes, I was a little bit bored. Christian Lins made a + suggestion to add 2D circle drawing support to Irrlicht, and I did this, but also added + support for drawing these figures using the same method. Check out + IVideoDriver::draw2DPolygon(). + +- Removed a memory leak when creating hlsl pixel shaders. + +- I've made varoius updates to the documentation and moved to doxygen 1.4 + +- Fixed a bug in the xml reader which caused it to crash when reading empty xml files. + +- Removed the buggy bsp tree scene node from the engine. + +- Tweaked some settings with some GUI elements. + +- ISceneNode::getAbsolutePosition now should be way faster. + +- Applied a fix by William Finlayson to the opengl stencil shadow drawing code which + fixes several bugs. + +- There is now a min_ and max_ template function available in the core namespace. + +- Added some bugfixes to MayaCameraSceneNode by jox. An even more improved version can + be found at http://development.mindfloaters.de/Downloads.12.0.html. + +- core::array now has a push_front method. + +- core::array now has an insert method. (Thanks to jox) + +- IrrlichtDevice now has a getEventReceiver() method. + +- Fixed a mouse wheel - mouse coordinates bug thanks to a bug report and fix by jox. + +- Changed the first parameter in IGUIContextMenu::addItem(wchar_t* text, ...) to const. + Thanks to jox.. again. :) + +- Fixed ignore path bug in zip file reader thanks to Pr3t3nd3r. It is now possible + to use zip files with the complete path to the files from the archive. + +- Fixed matrix4::rotateVect method after a suggestion by several users. (I think Electron, + Pr3t3nd3r, Jox) Thanks all :) + +- Fixed a bug in CGUIEditbox that enables you to write more characters than the max set + limit, thanks to Rush for the bug report and fix. + +- Added getAngleTrig() method to vector2d as suggested by Pr3t3nd3r, thanks! + +- After a suggestion by schick, plane3d now stores the normal vector first, and then + the distance to the origin. + +- A bug was fixed which caused 2D elements to be drawn with a second texture set in OpenGL + mode when 3D geometry with >1 textures has been rendered before. This effect has often + been reported as darkened 2D gui in the forum. + +- A bug in IrrCompileConfig prevented users to be able to recompile irrlicht with D3D9 + with gcc. This is now fixed, thanks to Jedive. + +- The project setup for Dev-C++ is now nicer. Added lots of folders and cleaned up the + whole setup a little bit with this. + +- Fixed a small bug in CGUIScrollbar reported by Klaus Niederkrueger. + +- The Checkbox rect is now clipped correctly, thanks to jox for that bug report. + +- The debug names of all scene nodes and GUI elements are now set correctly. + +- Applied a patch making it possible to compile Irrlicht without OpenGL in Linux. + +- core::rect::clipAgainst was fixed thanks to a bug report and correction by Jox. + +------------------------------------------------------------------------------------- +Changes in version 0.8 (19 Feb 2005) + +- Irrlicht now supports HLSL. This is possible using the new + IGPUProgrammingServices::addHighLevelShaderMaterial() methods. Also, methods for setting high + level shader constants have been added. + +- Irrlicht.NET now supports events and cursor control. This means now you can read mouse + and keyboard input from .NET projects like C# and VB.net too. + +- There are three new built in materials for doing normal/bump mapping available: + EMT_NORMAL_MAP_SOLID, EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR and + EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA. If the hardware does not + support these, the materials will fall back to their base materials. To be able to + use these materials, there is the new vertex type 'S3DVertexTangents', the material + does not work with any other vertex types. There are some new methods to create meshes + with this vertex type (IMeshManipulator::createMeshWithTangents()). + +- A new example/tutorial (11.PerPixelLighting) shows how to use per pixel lighting + in your applications. + +- The software renderer now works in Linux, too. + +- Irrlicht now has a built-in normal map generator. It creates on the fly 32 and 16 bit + normal maps from height maps (IVideoDriver::makeNormalMapTexture). As most other things + in Irrlicht, the generator does not depend on D3D, D3DX or OpenGL. + +- Added shader debugging capabilities to Irrlicht. If _IRR_D3D_SHADER_DEBUGGING is + defined in IrrCompileConfig.h (commented out by default), it is now possible to + debug all D3D9 shaders in VisualStudio. All shaders (which have been generated in memory + or read from archives for example) will be emitted into a temporary file for this purpose. + To debug your shaders, choose Debug->Direct3D->StartWithDirect3DDebugging in Visual Studio, + and for every shader a file named 'irr_dbg_shader_%%.vsh' or 'irr_dbg_shader_%%.psh' + will be created. Drag'n'drop the file you want to debug into visual studio. That's it. + You can now set breakpoints and watch registers etc. This works both with ASM, HLSL, + pixel and vertex shaders. + Note that the engine will run in D3D REF for this, which is a lot slower than HAL. + +- Support for compressed .tga texture loading added. (Support from 0.4.1 was buggy) + Thanks to neojzs for posting his improvement. + +- Support for 32 bit .bmp texture loading added. + +- Global particles are now possible. Use IParticleSystem::setParticlesAreGlobal() + to switch between global and local particles. A demonstration of this can be seen in the + new tutorial (11.SpecialFX2). + +- It is now possible to let IGUIImages draw themselves using the alpha channel of the texture + they show. Use IGUIImage::setUseAlphaChannel() for this. + +- ITexture now has a method for rebuilding the mip map levels: regenerateMipMapLevels(). + This is useful for example after locking and modifying the texture. + +- Gravity acceleration speed in CollisionResponseAnimator was changed thanks to a suggestion + by Morrog. The accelerationPerSecond value has been removed beacause of this, you + can now control everything just with the gravity vector. Note that the gravity value + must now be a little bit smaller to achieve the same effect as before. + +- Fixed a problem with several material renderers which weren't able to update their states + at the right time sometimes. A new method OnRender() will be called every time the + material is actually used. + +- Adjusted all tutorials to fit some interface changes. + +- Changed the opengl shader of tutorial 10 to fit the d3d shaders. The now look the same. + +- The MeshManipulator has a new method createMeshWithTangents() which creates a mesh + with normals, tangents and binormals from any mesh. + +- Wrong 2D alpha channel renderstates have been set when using D3D9 and 8. This has been fixed now. + +- When loading 32 bit images with an alpha channel and storing them internally as 16 bit, the + alpha channel got lost. This is now fixed, the remaining one bit alpha channel is now + stored correctly. + +- There is a new overloaded IGUIEnvironment::addImage method, which creates an image directly with + a texture as parameter, adjusting its size to the original size of the texture. + +- A small bug in rect::isValid() has been fixed, thanks to jox. + +- Fixed a bug in D3D8, D3D9 and OpenGL, which caused Materials be set and unset with an unequal + amount when mixing 3d with 2d grafics or stencil buffer shadows. + +- If you are recompiling the whole engine with Visual Studio 6 (which means + Irrlicht.dll, NOT the application which is using Irrlicht), DirectX9 support is disabled + now by default, because Microsoft stopped support for DX9 on VS6 in December + 2004. You can reenable this by uncommenting the new define at the bottom of + IrrCompileConfig.h, if you have an old SDK for example. + +- The mixed fvf and vertex shader system in D3D8 caused a slight issue in Irrlicht ending up + in really messed up render states sometimes. This is now fixed. + +- A major bug with the OpenGL renderer which occurred on some OpenGL implementations + has been removed thanks to a bugfix by Murphy and a great report and some investigations + by ElectroDruid. + +- Sorting transparent scene nodes was broken in all previous versions of Irrlicht. This + didn't attract a lot attention because most users used the ADD_COLOR transparencies for which + the sorting is not relevant. Thanks to Morrog and mmm76, sorting now is right. +- After the application window is resized, getViewport() no longer returns viewport as the + first time the window has been created. + +- The draw primitive functions are no longer wrongly checking the maximum primitive count with + the vertex amount value. Thanks to Spintz for the bug report. + +- Template materials in X files just like exported in the panda exporter are now + supported, thanks to JoeWright. + +- Changed the stringc typedef slightly to make it work with people not using + namespace irr. Thanks to schick. + +- Refactored the MeshManipulator code, which in some cases now uses template methods for performing + calculations on different vertex types. + +- Fixed an interface problem with newer versions of libJPEG. + Thanks to Fabien Coutant and Simon Barner for some help and clues into the right direction. + Was not able to add system specific zlib/jpeglib support due to issues on + some strange systems/users and a lack of time, sorry. + +- Typo in plane3d and triangle3d: method isFrontFacting renamed to isFrontFacing. + +------------------------------------------------------------------------------------- +Changes in version 0.7.1: (26 Sep 2004) + +- Fixed some bugs which prevented the engine to compile with gcc 3.4.1. + +- Fixed a problem with the OpenGL driver, which caused the renderstates not to be reset correctly + when drawing scene nodes with reflective materials. + +- Fixed error in Irrlicht's software mip map generation, which caused that some mipmap levels + looked strange. This fix was found by jox, the hardcore bug fixer, + so many thanks go to him. Again. :) + +- Disabled hardware mip map generation in D3D9 again, because it seems to cause problems on + some hardware. I don't have any hardware where this problem occurs, but I hope this helps. + +- Fixed a small bug in fast_atof submitted in the forum by da_dude. + +- Fixed string operator + after a bug report by osre and a fix suggestion by jox. + +- IEventReceiver now has a virtual destructor for the people who needed it. + +- 3DS-Loader patched due to some suggestions of Daniel Azkona Coya. + +------------------------------------------------------------------------------------- +Changes in version 0.7: (11 Sep 2004) + +- The first version of Irrlicht.NET is included in this release. It is a managed C++ + wrapper .DLL which makes the most important features of the engine available for all + .NET languages. The wrapper is incomplete, but it can already be used. + You can find the documentation for this .DLL in the compiled help file doc\IrrlichtNET.chm. + There are also two very basic examples available, which show how to use Irrlicht.NET + from C# and VisualBasic. + +- Low level vertex and pixel shader programming is now possible. There are + now some methods with which you can write GPU programs in vertex/pixel shader assembler + using Direct3D 8 and 9 and in ARB vertex and fragment program assembler for OpenGL. + You can use the IGPUProgrammingServices interface which can be reached by + IVideoDriver->getGPUProgrammingServices() for this. The new material types you can create + with this can be combined with all other already existing material types. + For example, it is possible to create a new material which uses a vertex shader to + calculate texture coordinates and diffuse colors, and let this be rendered by the built in + material video::EMT_TRANSPARENT_ADD_COLOR. + Support for high level programming languages like GLSL or HLSL is planned for the + following releases. Also note that you won't be able to use all techniques shaders offer with + Irrlicht, due to its current high level abstraction of the 3D APIs. For example, the engine + does not expose vertex streams or vertex buffers currently. + +- There is a new tutorial showing how to use shaders with the engine. In addition, all + old tutorials have been rewritten and adapted. For example, the hello world + tutorial now also shows how to set up visual studio .NET to use it with + the engine. + +- Hardware mip map level generation of textures is now supported when using D3D9. + +- Internal pointers and data of the video drivers can now be exposed for experienced users with + VideoDriver::getExposedVideoData(). For example, you can get a pointer to the IDirect3DDevice9 + interface and the HWND window handle, if the engine is running with D3D9. + +- The createDevice() function has a new additional parameter: bool vsync. With this, it is now + possible to enable or disable the waiting for the vertical retrace period. This is implemented + in D3D9, D3D8, and the Windows OpenGL driver only, the software driver will ignore this flag. + +- The engine now behaves like in the documentation: irr::createDevice() returns 0, if + the desired driver could not be initialized. + +- There is a new SceneNode available: The ITextSceneNode is able to display 2D text at a + position in 3D space. Use ISceneManager::addTextSceneNode() to create one. + +- Finally now all VideoDrivers have a draw2DLine() implementation, thanks to some additions sent in + by Vash TheStampede. + +- Applied some changes to the compilation configuration, so that it should now + be easier to use the engine with XBOX projects. Thanks to MattyBoy for sending + in some clues for this. + +- Some improvements for the linux version of the engine: The NULL device is finally fully operational with Linux + too, and also all examples and even the techdemo compile and run with this OS. + +- The default field of view in the cameras of the irrlicht engine was a little bit + extreme, so I changed it now from core::PI / 3.5f to core::PI / 2.5f. + +- Added a new draw2DImage method for partially draw a 2d Texture, as sent in by zola with + implementations for OpenGL, D3D8 and D3D9. Software implementation is missing. + +- The string class is now able to convert integer values into a string or append it as string + to itself. + +- Added a getDriverType() method to the IVideoDriver interface. + +- Added a getTransform() method to the IVideoDriver interface. + +- The EMT_TRANSPARENT_ALPHA_CHANNEL material in OpenGL is now implemented. + +- The integrated XML Parser now works better with different text file formats. (ASCII, UFT-16,..) + +- IGUIEdit Box now feels more like a windows editbox, thanks to some changes by Jox + +- Added a new method to IVideoDriver: createImageFromData as suggested by Oliver Klems. + +- Fixed a the EMT_TRANSPARENT_ALPHA_CHANNEL problem in D3D8 and D3D9 due to a suggestion by Jox. + +- Added 3 methods created by zola to the quaternion class: fromAngleAxis(), toEuler() and + operator*(vector3df&). + +- A bug in a matrix multiplication operator was fixed. + +- Changed visual studio project files to version 7.1, but provided 7.0 project files + for people with that version. + +- Added SceneNodeAnimatorRotation rotation fix as posted by warui + +- Added normalization fix to vector2d and 3d. Warui suggested a fix like that in the forum. + The one I made has the same result, but is a little bit faster. + +- Fixed some problems with the drawStencilShadow() method in the OpenGL implementation of the + IVideoDriver interface after some suggestions by Nicholas Bray. + +- Added IGUIButton::setPressed() and isPressed(). + +- Fixed checkPrimitiveCount() bug in NullDevice. + +- Applied jox's matrix4::getRotationDegrees() fix, many thanks for posting this! + +- Changed aabbox3d::getExtend() to getExtent(). + +- Changed IXMLReader::isEmtpyElement() to isEmptyElement() + +- Fixed a bug in CSceneManager::getSceneNodeFromId() which caused the engine to crash sometimes. + +- Fixed a bug in CGUISkin::setSize reported by REAPER. This method never worked before. + +- Improved texture mapping and normals of the TestSceneNode, thanks go again to Jox. + +- ScrollBar is now posting mousewheel events, thanks go to REAPER to post this bug and a fix for it. + +- Added - operator to vector2d and vector3d, thanks to calimero + +- Fixed a bug in vector2d::getAngle() and vector2d::rotateBy() thanks to Jox. + +- Fixed a bug in quaternion::set(f32 x, f32 y, f32 z) thanks again to Jox. + +- Fixed a bug in list::insert_before and list::insert_after, reported by Haddock. + +- Fixed a bug in XML Parser which caused a seqfault on linux. Thanks for G.o.D reporting this problem. + +- EDriverType enumeration renamed to E_DRIVER_TYPE + +- SceneNodeRenderTime enumeration renamed to E_SCENE_NODE_RENDER_PASS + +------------------------------------------------------------------------------------- +Changes in version 0.6: (09 Mar 2004) + +- Irrlicht now includes its own XML parser. It provides forward-only, read-only + access to a stream of non validated XML data. It can read everywhere Irrlicht can, + also in compressed .zip-Files for example. Use IFileSystem::createXMLReader() to + use it. + +- Like the new XMLReader, there is also a IXMLWriter available for making it easier + to write xml files. + +- There is a new tutorial available in the SDK. It is for more advanced users, and + shows how to create a 3d model viewer with the engine easily. It shows how to + use menus, tabcontrols, edit-, message- and sky boxes. + The resulting program can also be used as tool, to check if the engine + loads exported 3d models correctly. + +- Again, there are some new GUI widgets available: A ComboBox, a ToolBar, a PushButton + and an ImageButton. The last two are simply the old IGUIButton, but it is now able + to display additional images and behave like a PushButton. + +- It is now possible to make the drawing window resizeable, if it is in windowed mode. + Use IVideoDriver::setResizeAble(true) to do this. + +- The .x file reader and animation player now should work with 99% of all text .x files. + This is achieved by most of the following bug fixes. + +- Fixed a huge bug in the .x file reader, which caused that negative coordinates were + interpreted as positive ones sometimes. This caused that sometimes .x animations + were played wrong. + +- Slerp interpolation of the quaternion class fixed. This means that also some bugs + in the animation of .x files are removed now. + +- Added virtual joints to not weighted vertices to improve .x file animations. + +- The FileSystem is now 100% implemented. Finally it is now possible to write files + too. There is a new Class IWriteFile and the corresponding + IFileSystem::createAndWriteFile() + +- Added lots of text and sample code to the documentation. In most parts + documentation should be clearer now. + +- The ISceneManager has a clear() method, which clears the whole scene, all scene nodes + are removed. + +- All ISceneNodes now own a new method called removeAll(), which deletes all children + of the node. + +- Fixed a bug which prevented the possibility to compile directx8 without + having installed directx9. + +- Fixed a bug in 3d line dawing in D3D 8 and 9. + +- All video drivers now print out the gfx adapter type, vendor and driver version + into the log strings. + +- The D3D9 device is now as fast as the D3D8 device. + +- The string class has an additional new constructor for creating a string from + character data with a specific length. + +- Bug fixed in string class assignment operator which might cause a crash in very + special circumstances. + +- Added a findNext() method to the string class. + +- The ISceneNode class now has a isDebugDataVisible() method. + +- Some lines were changed to make the source of the engine compatible to VS.NET 2003. + +- Some functionality of the IFileList and IFileSystem was missing in the Linux version + of the engine. This caused the FileOpen-Dialog not to work. I fixed this problem. + +- The Middle and Right mouse button were swapped in the Linux version. This is now + fixed. + +- Multitexturing should now work with most linux systems too, thanks to a bug + report by Martin Piskernig. + +- The logger now has an additional log() method which accepts another combination + of strings. + +- Fixed a bug which caused fonts to be displayed very transparent in OpenGL. + +- Removed one of the redundant overloaded IGUIEnvironment::updateAbsolutePosition() + methods. + +- Fixed lots of clipping problems in all GUI Widgets. + +- core::rect has the new methods getCenter() and isValid(). + +- Scrollbar buttons are now disabled if it is not possible to scroll. + +------------------------------------------------------------------------------------- +Changes in version 0.5: (17 Feb 2004) + +------------------------------------- +/ Highlights in short: +/ * DirectX 9 support +/ * .x file support in all render devices including opengl and software +/ * new materials like lightmaps with dynamic lighting +/ * fog +/ * stencil buffer shadows now also work in OpenGL device +/ * more gui widgets: tab controls, edit boxes, menus +/ * spline animation support +/ * mouse wheel support +/ * triangle fan drawing +/ * quaternions +/ * improved keyboard input control +/ * lots of bugfixes including improved quake 3 map support +------------------------------------- + +- DirectX 9 is now supported by Irrlicht. This does not mean that it replaces + DirectX 8. The engine now supports both. You can now select between OpenGL, + DirectX8, DirectX9, Software and the Null device. + +- The engine now is able to read and display .x files. Using + Microsoft's excellent .x file exporter for Maya or MAX which comes + with the DX8 and DX9 SDK, it is now possible to create content for + the engine easily. Using .X files with Irrlicht is independent of D3D, + they can be used with OpenGL and with Linux for example too. + Currently only text file .x files are supported, and some animated .x + files may be displayed not 100% correctly, because the animation player + may still have some small bugs. It works perfectly with most .x files which + come with the DX9-SDK. Some skinned mesh .x files which use + quaternions for animating joints have some problems, there might be a + bug somewhere. I commented the lines with a possible bug in CXAnimationPlayer.cpp. + +- The GUI Environment now supports edit boxes. They should support unicode input + from every keyboard around the world, scrolling, copying and pasting (exchanging + data with the clipboard directly), maximum character amount, marking and all + shortcuts like ctrl+X, ctrl+V, ctrg+C, shift+Left, shift+Right, Home, End, + and so on. Wow, I never programmed an edit box, its much more work than it + seems to be. + +- Tabcontrols are now available in the GUI environment. It is also + possible to create tabs without tabcontrols, to be able to create + invisible gui elements for grouping other elements together. + +- Another new supported GUI Element are context menus. They support + ordinary text menu items, separators and sub menus. In Addition, + a standard menu as seen at the top of most windows can be + created easily with them. + +- Rewrote all tutorials to fit the new API. + +- Spline animations are now supported thanks to a spline scene node animator + written by Matthias Gall. + +- Taskswitching now works with Direct3D 8 and 9 devices in fullscreen mode. + +- Added Material types EMT_LIGHTMAP_LIGHTING, EMT_LIGHTMAP_LIGHTING_M2, + EMT_LIGHTMAP_LIGHTING_M4 and EMT_LIGHTMAP_ADD. + +- The engine now supports drawing of trianglefans. To do this, use + IVideoDriver::drawIndexedTriangleFan(). Mario Gruber sent in code for this, + so lots of thanks go to him! + +- It is now possible to draw 3d objects with fog. Simply switch on the fog flag + in the objects material. To change to way fog is drawn (per pixel/vertex, color, + linear/expontential) use IVideoDriver::setFog(); + +- With IrrlichtDevice::getOSOperator() a pointer to an interface is returned, with + which it is possible to do some operation system specific operations. Currently + there are only 3 methods supported, but more will be added in the future. + +- Mouse wheel input is now supported. + +- The Key Event structure of SEvent now contains a Char entry, describing the + corresponding character of the pressed key. Also two bools were added, + specifying if shift or ctrl was pressed too. + +- The version of the Operating System is now printed out into the log at + startup. + +- There is now a non-const getBoundingBox() method in IMeshBuffer and + IMesh available. + +- IGUIElement now has a method getElementFromId(), which searches children + (and its children if wanted) for an element with a specific id. If you + want to search all items, just do + IGUIEnvironment::getRootGUIElement::getElementFromId(). + +- ISceneNode::updateAbsolutePosition() is now public + +- Small bug fixed in CMeshManipulator::scaleMesh(). + +- The engine now supports Quaternions. + +- A bug was fixed causing the windows caption not to be displayed in + Windows 95/98/ME. + +- IGUIEnvironment::getBuildInFont() was renamed to getBuiltInFont(). + +- IGUIElement::bringToFront() is able to brint a child to the front. + Windows for example are now using this new feature. + +- Changed the texture mapping of the test scene node a little bit based on + code sent in by Dr Andros C Bragianos. + +- Added code to fix some bug in some ATI drivers. Thanks to ariaci for posting + this code. + +- Stencil buffer shadows now also work with the OpenGL device, they worked only + in D3D in earlier versions. Lots of thanks go to Philipp Dortmann, who + sent in a modification to the opengl driver! + +- IGUIStaticText::setWordWarp() renamed to setWordWrap(), + IGUIStaticText::enableOverrrideColor() renamed to enableOverrideColor() + [thanks to saigumi] + +- A bug was fixed, causing that the window was not able to be closed with Alt+F4 + in Win95/98. + +- Optimized the Octree-Scene node a little bit for getting more rendering speed. + Culling is now done with the real frustum, not the bounding box around it. + Speed increase is about 5%, it's not much but ok. + +- Bug fixed in the Quake 3 .bsp file loader, which caused holes to appear in + some maps. + +- Combination of 3D displaying and drawing GUI elements was improved, and the + priority of input receiving of 3d cameras and gui elements swapped. + +- A bug in the static text was fixed, which caused it to draw itself outside + of its clipping rectangle. + +- KeyFocus and MouseFocus methods in GUIEnvironment are now merged into one method. + +- The Clamptexturecoordinates flag in the material was removed. + +- IVideoDriver::draw3DLine in all devices was improved. + +- The devcpp-version of the binary DLL which comes with the SDK is now faster. + I'll compile this version from now on always with optimization switched on. + +- Other, Minor New/Changed methods in public interfaces: + * buildShadowMatrix in matrix4 + * getRotationDegrees in matrix4 (sent in by Chev) + * rotateVect in matrix4 + * linear_search in array + * recalculateBoundingBox in MeshManipulator + * ISceneManager::addStaticText() now has a parameter for word wrapping + * getCharacterFromPos() in IGUIFont + * drawMeshBuffer() in IVideoDriver; + * interpolate() in matrix4 + * getLast in array + +------------------------------------------------------------------------------------- +Changes in version 0.4.2: (13 Dec 2003) + +- The engine does no more use only 16 bit textures internaly. Now all + other texture formats are supported too. This means higher precision + and better quality images. In this context, the ISurface interface has + been replaced by IImage, and the ISurfaceLoader by IImageLoader. + +- By changing the texture creation mode of the IVideoDriver, it is now + possible to influence how textures are created: You can choose between + 'optimized for speed', 'optimized for quality' or simply set constant + bit depth like 'always 32 bit'. Also, you can now enable and disable + Mip map generation with these flags. Take a look at + IVideoDriver::setTextureCreationFlag() for details. + +- There is now some support for outdoor or terrain rendering available. + You can create a static mesh from a heightmap and a texture using + ISceneManager::addTerrainMesh(). You can specify a huge texture if you + like, even bigger as your hardware allows to render, because the texture + will be splitted up if necessary. + Another possibility for doing terrain rendering is the new Terrain Scene + node. But it is only in a very early alpha stage, I disabled for example + the use of different level of details. + +- It is now possible to load software images into memory from files on + disk, without creating a hardware texture. You can do this by calling + IVideoDriver::createImageFromFile(). This is very useful for example + for loading heighmaps for terrain renderers. + +- The Quake 3 Map Loader now supports curved surfaces, thanks to by Dean P. Macri + who sent in his code. (He also sent in lots of other cool stuff, which I will merge + with the code of next releases, lots of thanks to him!) + +- It is now possible to control what text is printed out to the console and + the debug window of Visual Studio. By getting a pointer to the ILogger + interface, is is possible to adjust if Warning, Error or Informational + texts should be printed out. In addition, now every text can be caught + by the event receiver. + +- The engine is now capable of loading .PCX files. Only a few PCX formats + are supported currently, but at least the common used formats + of most textures of the quake 2 models. Thanks go to Dean P. Macri who + sent in the code for the new PCXLoader! + +- A new Scene node is available, which simply does nothing. It is useful for doing + advanced transformations or for structuring the scene graph. + +- The ISceneManager::addOctTreeSceneNode() now takes AnimatedMeshes as parameter. + If this new method is called, the first frame in the animated mesh is taken as + mesh to construct the octree. This means that you won't have to write + addOctTreeSceneNode(yourMesh->getMesh(0)) anymore, but can use + addOctTreeSceneNode(yourMesh), which is a little bit more intuitive. + +- The Driver type enumeration have been adapted to the Irrlicht + naming conventions. For example instead of writing DT_OPENGL, now write + EDT_OPENGL. + +- The ITexture interface has two new methods for getting the size of the + texture: ITexture::getSize() and ITexture::getOriginalSize(). This replaces + the old getDimension()-method and allows to disable bugs which are generated + by the automatic scaling to optimal sizes of textures. + +- There are some new keycodes available: KEY_COMMA, KEY_PLUS, KEY_MINUS, KEY_PERIOD. + +- There are now 3 lightmap Material types: EMT_LIGHTMAP, EMT_LIGHTMAP_M2 and + EMT_LIGHTMAP_M4, which are making the lightmaps 2 or 4 times brighter. If you used + the Material EMT_LIGHTMAP in your code, you should replace it now with + EMT_LIGHTMAP_M4. + +- The transformation enumeration names have been adapted to the irrlicht + naming conventions. For example instead of writing TS_VIEW, now write + ETS_VIEW. + +- Video driver feature enumeration names have been changed from + EK3DVDF_... to EVDF_... + +- The GUIEnvironment now has a new method: getRootGUIElement(). With this it + is possible now to add external created custom GUI Elements to the gui environment, + without an existing internal GUI element as parent. + +- The setViewPort()-Method of the OpenGL-device now works, too. Nothing stands now + in the way of creating splitscreen applications using the OpenGL device. + Oliver Klems sent code for this, I slightly modified it. Thank you! + +- Corrected a bug, which made the EMT_REFLECTION_2_LAYER Material disappear on some + hardware. + +- Sirshane sent in a bug fix: It is now possible to make the mouse cursor + invisible in the Linux version of the engine. Thanx sirshane! + +- getFrameNr() of IAnimatedMeshSceneNode is now public. + +- Again a small bug in the 3ds file loader was fixed. + +- A small bug causing light positions being transformed in the OpenGL + driver differently compared to D3D. Thanx to Matthias Gall for reporting + this! + +- Typing error fixed: ISceneCollisionMananger::getRayFromScreenCoordiantes renamed to + getRayFromScreenCoordinates. + +- Linux support with multitexturing and mipmap generation has been improved. + +- A bug was fixed which caused the Engine not to run when compiled + as dynamic library under linux. Thanks to Shane Parker who pointed out + the problem. + +- A bug was fixed in position2d.h in the operator +=, and the list iterator now + has per and postfix operators. Thanks to Isometric God for spotting this out. + +- A bug was fixed in the Metatriangleselector, causing it to detect only collisions + with the last TriangleSelector in it. + +------------------------------------------------------------------------------------- +Changes in version 0.4.1: (18 Sep 2003) + + +- Input events are now processed faster than repaint and window events. This + means that input commands now effect things directly, in earlier versions + there could be a delay when there were low frames per second. Some people + noticed this when moving with the fps camera in large levels: The camera + sometimes stopped seconds after the button was released. This is now fixed. + +- A Message Box is now available in the GUI Environment. It looks like the + windows message boxes and supports OK, Cancel, Yes and No buttons, which + can be combined freely. Also, it shows multiline text and adjusts its size + based on the amount of text it shows, so it should be very useful for displaying + (debug) messages during runtime. + +- It is now possible to make all windows (message boxes, file open dialogs, + simple windows) modal. + +- IGUIStaticText now supports multiline text via automatic word warp and manual + line breaking with '\n'. You only need to switch it on with + yourText->setWordWrap(true); + +- Non default MD2 animations are now supported. Which means simply that you can + enumerate the names of all md2 animations and the AnimatedMeshSceneNode now supports + a setMD2Animation() with a character string as parameter instead of a constant. + +- You do not need an event receiver anymore for sending user events to the active + camera, this is now done autmaticly. In addition, it is now possible to + set a new event receiver during runtime of the engine using IrrlichtDevice:: + setEventReceiver(). + +- It is now possible to disable and enable the input receiver of a camera. This + is useful for example for removing the users control of the camera. To do this, + call camera->setInputReceiverEnabled(false); + +- The first person shooter camera now supports a keymap: You can define your own + key mapping to control the camera when you create it with ISceneManager:: + addCameraSceneNodeFPS(). + +- Thanks to Jon Pry, the engine now also loads compressed TGA texture files. Now only + 8 bit palette using TGAs are missing. :) + +- There are methods for converting 3d coordinates in 2d coordinates and the other + way round. You can find them as two new methods of the ISceneCollisionManager: + getRayFromScreenCoordiantes() and getScreenCoordinatesFrom3DPosition(). + +- There are now access methods in IGUIWindow for getting pointers to the + maximize, minimize and close buttons, to be able to remove them for + example. + +- Before starting up the engine, a version check now is performed and a warning is + written, if Irrlicht.DLL version and header version of your application do + not match. + +- A bug with the skybox has been fixed: In OpenGL, it was possible to see the + borders of the skybox. In addition, when a skybox was visible, there were + errors in the texture coordinates of other meshes. This is all fixed now. + +- A bug has been fixed causing the engine to crash when removing gui childs + which where created inside the .dll but are removed from outside. + +- A bug was fixed causing the engine to crash when drawing debug data of + octtree scene nodes with geometry data with vertices with one texture + coordiante. + +- Multitexturing now works with linux, too. Thanx to Jon Pry again, for showing + me where the problem was. + +- The bug (reported by saigumi) preventing scene nodes attached to a camera + from moving correctly is now fixed. + +- The "Climb-Walls" bug (reported first by Matthias Gall) is fixed. Gravity + acceleration is now quadratic instead of linear. + +- A warning is now printed out, if more vertices are rendererd with one call + than the hardware supports. + +- Other, Minor New/Changed methods in public interfaces: + * get and setText() in IGUISkin + * += operators are now available in the string class. + * setRelativePosition() in IGUIElement + * enumeration EKEY_CODES renamed to EKEY_CODE + * getMaximalPrimitiveCount() in IVideoDriver + * getAnimationCount() in IAnimatedMeshMD2 + * getAnimationName() in IAnimatedMeshMD2 + +------------------------------------------------------------------------------------- +Changes in version 0.4: (04 Sep 2003) + +- Collision detection and reponse based on ellipsoids in now implemented. + There is a new method available in the ISceneCollisionMananger, which returns + a collision response point. In addition, a new SceneNodeAnimator is available, + which causes a scene node, to which it is attached to, not to move through + walls, to climb stairs and to be affected by gravity. This scene node animator + can be attached to any scene node. For example adding it to the FPSCamera, it makes + the user possible to walk through the 3d world as in first person shooters. + +- There is now a full featured Particle System included in the engine for + creating fire, explosions, snow, smoke and so on. + It is customizeable and extensible. There is a ParticleSystemScene node + available in the SceneManager and some standard particle emitters and + affectors are already implemented. + +- Realistic water: The engine now features an IWaterSurfaceScene node, which + animates a static mesh with water waves. In combination with the new + EMT_REFLECTION or EMT_TRANSPARENT_REFLECTION material type, you can easily + create realistic animated water surfaces. + +- Triangle base picking is now possible using the ISceneCollisionMananager. + If a collision happened, the intersection point and the triangle causing + the intersection is returned. + +- Stencil shadows are now drawn using the ZFail method by default, but it is + possible to choose ZPass, if wished. This means that the camera may now move + inside the shadow volumes and no errors will occur. In addition a stencil + shadow bug is now fixed: In 0.3 there where no shadows visible in the TechDemo. + +- The interface of ISceneNode has changed: There is no more a RelativeTransformation + and AnimatedRelativeTransformation matrix. They have been replaced by 3 vectors: + RelativeTranslation, RelativeRotation and RelativeScale, which can be accessed by + the corresponing get() and set() methods. This simplifies the interface + a lot. Also, the set/getRelativePosition was renamed to set/getPosition. + +- The new IAnimatedMeshMD2 interface now returns start, begin time and + fps of every MD2 animation type. In this context, IAnimatedMeshSceneNode + got a new method called setMD2Animation(), which accepts a single constant + like EMAT_ATTACK, which starts and plays the fitting animation (attack + animation in this case), simplifying the interface a lot. + +- Some scene nodes can now draw debug data like their bounding boxes. + This feature is switched on for a single node by calling + ISceneNode::setDebugDataVisible(true). Looks really interesting for + animated scene nodes like particle systems or animated meshes. + +- There is now a IGUIInOutFader avaiable, which is able to fade in or + out the whole screen or parts of it. + +- The new IVideoModeList is a list with all available video modes. It can + be retrieved with IrrlichtDevice::getVideoModeList(). If you are confused + now, because you think you have to create an Irrlicht Device with a video + mode before being able to get the video mode list, let me tell you that + there is no need to start up an Irrlicht Device with DT_DIRECTX8, DT_OPENGL or + DT_SOFTWARE: For this (and for lots of other reasons) the null device, + DT_NULL exists. + +- With the new IMeshManipulator interface accessible with + ISceneManager::getMeshManipulator() it is possible to perform some basic + operations on meshes: Flipping all surfaces, recalculating all normals, + scaling the mesh, creating a new texture mapping and so on. + +- A new material for creating water surfaces or glass with reflections on it + is available: EMT_REFLECTION_2_LAYER and EMT_TRANSPARENT_REFLECTION_2_LAYER. + It has uses a reflection map, and an additional optional texture. + The transparency of this material is set by the alpha color value in the vertices. + +- Another new material is EMT_SOLID_2_LAYER. It is a material with 2 textures, + blended together with the alpha value of the vertex color. This material is + currently only available in DirectX. + +- Trilinear Filtering is now supported by the engine. + There is a new option in SMaterial: TrilinearFilter and EMF_TRILINEAR_FILTER. + +- The addChild() method of the IAnimatedMeshSceneNode for adding SceneNodes to + joints of skeletal animated meshes was removed. + Instead there is now a new method: getMS3DJointNode(). This returns a pointer + to a child node, which has the same transformation as the corresponding joint. + In this way it is possible to do more advanced operations with joints and + attaching scene nodes to joints. Also, the IAnimatedMeshMS3D interface now gives + access to all joints. In this way, you can easily enumerate all names of all + joints in the mesh. + +- Font and color of every IGUIStaticText can now be set separately, without + modifying the IGUISkin. + +- There is now a ELEMENT_LEFT gui event, which all hovered elements receive when they + are left. + +- All features of the FileOpenDialog are now working. + +- Debug informations are now printed out to the console window + also on the win32 platform. + +- FPSCamera now supports setTarget(). Its not precise but working. + +- Textures of 3ds files are now loaded from the same directory in which the + 3ds file is. If the texture is not found there, the texture is tried to be + loaded from the current working directory. + +- A small bug in the 3ds file loader has been fixed. There were 3ds files exported + by anim8or, where the reading of the 3ds file never stopped. + +- It is now possible to configure the minimal amount of polygons contained + in every node in an OctTree via addOctTreeSceneNode(). + +- There is a new template class in the core namespace: triangle3d. With this, + it is easy to find intersections between lines and triangles, find out if + a point is within a triangle and so on. + +- A small bug in ISceneManager::addHillPlaneMesh() was fixed: Now the right tile + amount is created. + +- There is a new SceneNode available: IDummyTransformationSceneNode. It exists + for making it possible to insert matrix transformations anywhere into the + scene graph. + +- Added a new SceneNode animator for deleting Scene nodes automatically after some + time. Create it with ISceneManager::createDeleteAnimator(). + +- The techdemo now is interactive. After a short non-interactive flight over + the quake 3 level, you are placed as player inside the level, may move around, + shoot fire balls and take a look at some animated characters which are placed + on the map. + +- I fixed a bug which caused the screen get black when choosing shadows and fullscreen + on some special 3d adapters. + +- I fixed some bugs in the linux port: The timer returned an incorrect time, causing + wrong animations everywhere and the releasing of keys and mouse buttons was not + sent as event. In addition, I placed a copy of the zlib.a and jpeglib.a into the + /lib/Linux directory and changed the Makefiles of the examples and the source + of the engine for doing this automatically in the future, so I hope there will be no + problems with other versions of zlib and jpeglib anymore. + +- There are 2 new tutorials: One showing how to do collision detection and + for special effects. + +- Other, Minor New/Changed methods in public interfaces: + * getVersion() in IrrlichtDevice + * getLengthSQ() in vector3d + * getInterpolated() in vector3d + * getInterpolated() in SColor + * getAngle() in vector2d + * getAngleWith() in vector2d + * getPrimitiveCountDrawed() in IVideoDriver renamed to getPrimitiveCountDrawn() + * getSceneNodeFromSceenCoordinates() renamed to getSceneNodeFromScreenCoordinates() + * getMeshType() in IAnimatedMesh + * getInterpolated() in aabbox + * setMD2Animation() in IAnimatedMeshSceneNode + * getFullFileName() in IFileList + * addShadowVolumeSceneNode() in IAnimatedMeshSceneNode extended with zfail parameter + * drawStencilShadowVolume() in IVideoDriver extended with zfail parameter + * getDistanceFromSQ() in vector3d + * subString() in string + * findFirst() in string + * findLast() in string + * getTriangleSelector() in ISceneNode + * setTriangleSelector() in ISceneNode + * draw3DTriangle() in IVideoDriver + * setShadowColor() in ISceneManager + * getShadowColor() in ISceneManager + * addToDeletionQueue() in ISceneManager + * getSceneNodeFromId() in ISceneManager + +------------------------------------------------------------------------------------- +Changes in version 0.3: (18 Jul 2003) + +- Linux port: The Irrlicht Engine now compiles and runs on Linux. Currently only + the OpenGL driver is available. The Software driver would be there too, if + somebody could tell me a fast way to blit a A1R5G5B5 surface to the screen + using X. + All examples do compile and run, but there are some things missing: + * It is not yet possible to make the mouse cursor invisibe. + * The timer seems not to return the currect time. + * Multitexturing does not work correctly on all gfx adapters. + +- Ms3D Animations: The engine is now able to play skeletal animations directy + from Milkshape 3D (.ms3d) files. It is also possible to attach objects to + parts of the animated mesh. For example a weapon to the left hand of + the animated model. + +- Because the swprintf function in Windows32 does not match the ISO C standard, + and it does in linux and all other platforms, there is now a define in Irrlicht.h, + to make the code be the same on all platforms: + #define swprintf _snwprintf + This simply means that you need to add a parameter to your swprintf calls if + you used this function in your win32 irrlicht engine projects. For example instead + of writing + wchar_t tmp[255]; + swprint(tmp, "FPS: %d", fps); + you now write + wchar_t tmp[255]; + swprint(tmp, 255, "FPS: %d", fps); + +- Automatic culling has changed a little bit: It is now done by the SceneManager. + Scene nodes now only need to return a valid, non transformed bounding box to be + culled automatically. It is explained in the CustomSceneNode Tutorial how this works. + +- It is now possible to use the engine easily for 2D graphics: There are now to new + methods in the IVideoDriver, which create an 1bit alpha channel for textures + using an color key. The methods are both named makeColorKeyTexture. There is a + tutorial '2d graphics' which explains how this works. + +- The rect template class was removed and replaced by the rectEx class. There + is now only one rectangle template available, called 'rect' for simplifying + the interface. + +- The texture coordinate bug in Milkshape 3d models with lots of shared vertices + was fixed. + +- Bugfix with GUI environment hovering invisible elements. + +- There are two new tutorials: One for 2d graphics, and one for user interface. + +- Tutorial changes: + * All backslashes replaced by slashes in file names in + all tutorials for linux compatibility. + * RectEx replaces with rect in 1.HelloWorld + * Added second parameter to swprintf in 2.Quake3Map + * Added bounding box creation to 3.CustomSceneNode + * Added second parameter to swprintf in 4.Movement + +- New/Changed methods in public interfaces: + * getClosestPoint in line3d + * getMatrixOfMeshPart in IAnimatedMesh + * removeChild in ISceneNode now returns true or false + * addChild in IAnimatedMeshSceneNode + * setParent in ISceneNode + +------------------------------------------------------------------------------------- +Changes in version 0.2.5: (22 Jun 2003) + +- A new material type is available: EMT_TRANSPARENT_VERTEX_ALPHA, which + realizes transparency based on the vertex alpha color. It currently is + only implemented in the DirectX device. + +- There is now an ISceneCollisionManager available. Get it with + getSceneCollisionManager() from the ISceneManager. It currently only implements + picking, but more is coming soon. + +- Automatic Culling based on Bounding Boxes is implemented now. It can be switched on + or off for every SceneNode seperately using ISceneNode::setAutomaticCulling(). + It is on by default. + +- It is now possible to remove loaded textures for freeing memory or reloading them. + Use IVideoDriver::removeTexture() or removeAllTextures(). + +- New drawing methods in the IVideoDriver interface: + * Draw3dLine(), drawing a 3d line. + * Draw3dBox(), which draws an axis aligned bounding box. + * Draw2dLine(), currently only supported by the Software device. + +- MD2 bugfixes: + * There was a small bug with texture coordinates. + * Frames are now correctly interpolated when playing animations. + +- Bugfix in the 3ds file format loader: Single objects in the 3ds file with multiple + materials attached are now loaded correctly. + +- list.h renamed to irrlist.h due to compatibility issues. + +- Now works with Dev-C++ 5 Beta 8. (4.9.8.0) + +- New/Changed methods in public interfaces: + * 'getInverse' in matrix4. + * 'transformBox' in matrix4. + * 'repair' in aabbox. + * 'intersectsWithLine' in aabbox. + * 'getVector' in line3d. + * 'getMiddle' in line3d. + * 'normalize' method in vector3d and vector2d now returns reference to vector. + * 'getTransformedBoundingBox' in ISceneNode. + * 'getChildren' in ISceneNode + * 'setRotation' in ISceneNode + * 'addHillPlaneMesh' in ISceneManager now accepts a texture repeat count parameter. + + +------------------------------------------------------------------------------------- +Changes in version 0.2: (19 May 2003) + +- The engine is now able to load .3ds files, with their materials and textures. + +- There are some new SceneNodeAnimators: A fly straight animator and a texture animator. + +- Texture coordinates can now be set to clamp or wrap mode with + a flag in the SMaterial struct. + +- Skyboxes are implemented. + +- Billboards now work 100% correctly. + +- The IAnimatedMeshSceneNode is now able to draw shadows of itself. To enable this, just call + addShadowVolumeSceneNode(). Please note that shadows are currently just experimental, + there are some bugs, and they only only in Direct3D mode. + +- A small bug in the view frustum and the octree fixed. + +- The default aspect ratio in all camera scene nodes was changed. + +- Some changes and extenstions to the core::matrix4, SViewFrustum, plane3d and + aabbox were made. The plane3dex was removed, there is now only one plane implementation + available. Implemented some ideas and suggestions by Mark Jeacocke. Thanx a lot! + +- The interface for adding dynamic lights has been enhanced. There are some new methods + for handling dynamic light in the IVideoDriver interface. For example, it is now possible + to change the ambient light. + +- There is a new parameter in the createDevice() function, which specifies if the + stencil buffer should be activated. Also, now all parameters have default parameters. + +- There is now a timer object to get the current timer. It can be received using + the getTimer() method from the IrrlichtDevice. + +- The first person shooter camera is now able to be moved by external using + setRelativePosition() and the sceneNodeAnimators. In addition, it now supports + multiple FPS cameras. + +- Mesh format loading extenstions are now possible. To extend the engine with a + mesh format it currently does not support (e.g. .cob), just implement a + IMeshLoader interface and add it to the engine calling + ISceneManager::addExternalMeshLoader(). + +- It is now possible to extend the Irrlicht Engine easily with new texture file format + loaders. If there is an image file format the engine does not support (for example + .gif files) the IImageLoader interface can be implemented to load .gif files + and added to the engine via IVideoDriver::addExternalSurfaceLoader(). + +------------------------------------------------------------------------------------- +Changes in version 0.1.5: (03 Apr 2003) + +- The zlib and libjpeg are now included in the SDK. + +- It is now possible to let the scene manager generate a hilly plane on the fly. + +- The Interface for handling dynamic lights was simplified. + +- The OpenGL 2D and 3D device is now full implemented. + +- There is now a way to access to root scene node from the scene manager, and so it + is possible to add external created custom scene nodes to the scene. + +- There is a new Camera control scene node available in the engine: First Person Shooter + Camera Control. Look with mouse movement, move and strafe with the cursor keys. + +- The engine now compiles with g++ and the Microsoft compilers, which enables it to + develop applications for the engine with VisualC++6.0, VisualC++.NET and Dev-C++. + +- There is now a ICursorControl available in the engine, which is able to modify the + mouse cursor: Get/Set the position of the cursor, make it invisible or visible. + +- video::Color was renamed to video::SColor to fit the Irrlicht Engine naming conventions + and for g++ compatibility issues in the Vertices. + +------------------------------------------------------------------------------------- +Release notes of version 0.1: (14 Mar 2003) + + This is an alpha version of the SDK. So please note that there are + features missing in the engine and maybe also some bugs. The following + list is a complete list of parts of this alpha SDK which do not work + 100% correct. All other parts which can be found in the documentation + and accessed with the Irrlicht header files work and can already be + used. + +- OpenGL Device + The OpenGL Device is currently only able to load textures and draw basic + 3D primitives. No 2D functions, complex materials and dynamic light are + implemented. Please use the DirectX8 or the Software Device instead. + In the next release (0.2) the OpenGL device will be complete. + +- Software Device + Dynamic lighting, multitexturing, 3d clipping and bilinear filtering are + not implemented because the Software Device was intented to to only 2d + functions, the primitive 3d functions are only an addition. Until the + first non beta release (1.0) of the Engine, some more 3d functionality + will be added. + +- BspTree + The binary space partition scene node does not work correctly and has + some bugs in it, which might lead to crashes. Please use the OctTree + scene node instead. There is nearly no difference between the interface + of them. + +- MeshViewerGUIElement + The camera control of this element is currently disabled. + +- FileOpenDialog + Not all functions are implemented. + +- Render to Texture support + Is not implemented yet. + +- MS3D Skeletal Animation + A loaded mesh is currently not animated and only drawn static. + +- Quake 3 maps + No support for curved surfaces yet. + +- Linux Support + The engine currently only runs with Windows platforms. A linux version + will be available somewhere between the versions 0.2 and 0.5, it depends + on the need of the users. + +------------------------------------------------------------------------------------- diff --git a/doc/aesGladman.txt b/doc/aesGladman.txt new file mode 100644 index 00000000..e7ebb1c4 --- /dev/null +++ b/doc/aesGladman.txt @@ -0,0 +1,34 @@ +The Irrlicht Engine may be compiled to provide support for AES encrypted files. The implementation used by Irrlicht is provided by Dr Brian Gladman. The license for these files (including AES, a PRNG, SHA, and other algorithms) is as follows + +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- +*/ + diff --git a/doc/bzip2-license.txt b/doc/bzip2-license.txt new file mode 100644 index 00000000..f420cffb --- /dev/null +++ b/doc/bzip2-license.txt @@ -0,0 +1,42 @@ + +-------------------------------------------------------------------------- + +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2007 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Julian Seward, jseward@bzip.org +bzip2/libbzip2 version 1.0.5 of 10 December 2007 + +-------------------------------------------------------------------------- diff --git a/doc/irrlicht-license.txt b/doc/irrlicht-license.txt new file mode 100644 index 00000000..19e40eca --- /dev/null +++ b/doc/irrlicht-license.txt @@ -0,0 +1,26 @@ +Copyright (C) 2002-2012 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 + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Please note that the Irrlicht Engine is based in part on the work of the + Independent JPEG Group, the zlib, libPng and aesGladman. This means that if you use + the Irrlicht Engine in your product, you must acknowledge somewhere in your + documentation that you've used the IJPG code. It would also be nice to mention + that you use the Irrlicht Engine, the zlib, libPng and aesGladman. See the + corresponding license files for further informations. It is also possible to disable + usage of those additional libraries by defines in the IrrCompileConfig.h header and + recompiling the engine. diff --git a/doc/jpglib-license.txt b/doc/jpglib-license.txt new file mode 100644 index 00000000..07bb50b2 --- /dev/null +++ b/doc/jpglib-license.txt @@ -0,0 +1,351 @@ +The Independent JPEG Group's JPEG software +========================================== + +README for release 8d of 15-Jan-2012 +==================================== + +This distribution contains the eighth public release of the Independent JPEG +Group's free JPEG software. You are welcome to redistribute this software and +to use it for any purpose, subject to the conditions under LEGAL ISSUES, below. + +This software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone, +Bill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson, +Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, Ge' Weijers, +and other members of the Independent JPEG Group. + +IJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee +(also known as JPEG, together with ITU-T SG16). + + +DOCUMENTATION ROADMAP +===================== + +This file contains the following sections: + +OVERVIEW General description of JPEG and the IJG software. +LEGAL ISSUES Copyright, lack of warranty, terms of distribution. +REFERENCES Where to learn more about JPEG. +ARCHIVE LOCATIONS Where to find newer versions of this software. +ACKNOWLEDGMENTS Special thanks. +FILE FORMAT WARS Software *not* to get. +TO DO Plans for future IJG releases. + +Other documentation files in the distribution are: + +User documentation: + install.txt How to configure and install the IJG software. + usage.txt Usage instructions for cjpeg, djpeg, jpegtran, + rdjpgcom, and wrjpgcom. + *.1 Unix-style man pages for programs (same info as usage.txt). + wizard.txt Advanced usage instructions for JPEG wizards only. + change.log Version-to-version change highlights. +Programmer and internal documentation: + libjpeg.txt How to use the JPEG library in your own programs. + example.c Sample code for calling the JPEG library. + structure.txt Overview of the JPEG library's internal structure. + filelist.txt Road map of IJG files. + coderules.txt Coding style rules --- please read if you contribute code. + +Please read at least the files install.txt and usage.txt. Some information +can also be found in the JPEG FAQ (Frequently Asked Questions) article. See +ARCHIVE LOCATIONS below to find out where to obtain the FAQ article. + +If you want to understand how the JPEG code works, we suggest reading one or +more of the REFERENCES, then looking at the documentation files (in roughly +the order listed) before diving into the code. + + +OVERVIEW +======== + +This package contains C software to implement JPEG image encoding, decoding, +and transcoding. JPEG (pronounced "jay-peg") is a standardized compression +method for full-color and gray-scale images. + +This software implements JPEG baseline, extended-sequential, and progressive +compression processes. Provision is made for supporting all variants of these +processes, although some uncommon parameter settings aren't implemented yet. +We have made no provision for supporting the hierarchical or lossless +processes defined in the standard. + +We provide a set of library routines for reading and writing JPEG image files, +plus two sample applications "cjpeg" and "djpeg", which use the library to +perform conversion between JPEG and some other popular image file formats. +The library is intended to be reused in other applications. + +In order to support file conversion and viewing software, we have included +considerable functionality beyond the bare JPEG coding/decoding capability; +for example, the color quantization modules are not strictly part of JPEG +decoding, but they are essential for output to colormapped file formats or +colormapped displays. These extra functions can be compiled out of the +library if not required for a particular application. + +We have also included "jpegtran", a utility for lossless transcoding between +different JPEG processes, and "rdjpgcom" and "wrjpgcom", two simple +applications for inserting and extracting textual comments in JFIF files. + +The emphasis in designing this software has been on achieving portability and +flexibility, while also making it fast enough to be useful. In particular, +the software is not intended to be read as a tutorial on JPEG. (See the +REFERENCES section for introductory material.) Rather, it is intended to +be reliable, portable, industrial-strength code. We do not claim to have +achieved that goal in every aspect of the software, but we strive for it. + +We welcome the use of this software as a component of commercial products. +No royalty is required, but we do ask for an acknowledgement in product +documentation, as described under LEGAL ISSUES. + + +LEGAL ISSUES +============ + +In plain English: + +1. We don't promise that this software works. (But if you find any bugs, + please let us know!) +2. You can use this software for whatever you want. You don't have to pay us. +3. You may not pretend that you wrote this software. If you use it in a + program, you must acknowledge somewhere in your documentation that + you've used the IJG code. + +In legalese: + +The authors make NO WARRANTY or representation, either express or implied, +with respect to this software, its quality, accuracy, merchantability, or +fitness for a particular purpose. This software is provided "AS IS", and you, +its user, assume the entire risk as to its quality and accuracy. + +This software is copyright (C) 1991-2012, Thomas G. Lane, Guido Vollbeding. +All Rights Reserved except as specified below. + +Permission is hereby granted to use, copy, modify, and distribute this +software (or portions thereof) for any purpose, without fee, subject to these +conditions: +(1) If any part of the source code for this software is distributed, then this +README file must be included, with this copyright and no-warranty notice +unaltered; and any additions, deletions, or changes to the original files +must be clearly indicated in accompanying documentation. +(2) If only executable code is distributed, then the accompanying +documentation must state that "this software is based in part on the work of +the Independent JPEG Group". +(3) Permission for use of this software is granted only if the user accepts +full responsibility for any undesirable consequences; the authors accept +NO LIABILITY for damages of any kind. + +These conditions apply to any software derived from or based on the IJG code, +not just to the unmodified library. If you use our work, you ought to +acknowledge us. + +Permission is NOT granted for the use of any IJG author's name or company name +in advertising or publicity relating to this software or products derived from +it. This software may be referred to only as "the Independent JPEG Group's +software". + +We specifically permit and encourage the use of this software as the basis of +commercial products, provided that all warranty or liability claims are +assumed by the product vendor. + + +ansi2knr.c is included in this distribution by permission of L. Peter Deutsch, +sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA. +ansi2knr.c is NOT covered by the above copyright and conditions, but instead +by the usual distribution terms of the Free Software Foundation; principally, +that you must include source code if you redistribute it. (See the file +ansi2knr.c for full details.) However, since ansi2knr.c is not needed as part +of any program generated from the IJG code, this does not limit you more than +the foregoing paragraphs do. + +The Unix configuration script "configure" was produced with GNU Autoconf. +It is copyright by the Free Software Foundation but is freely distributable. +The same holds for its supporting scripts (config.guess, config.sub, +ltmain.sh). Another support script, install-sh, is copyright by X Consortium +but is also freely distributable. + +The IJG distribution formerly included code to read and write GIF files. +To avoid entanglement with the Unisys LZW patent, GIF reading support has +been removed altogether, and the GIF writer has been simplified to produce +"uncompressed GIFs". This technique does not use the LZW algorithm; the +resulting GIF files are larger than usual, but are readable by all standard +GIF decoders. + +We are required to state that + "The Graphics Interchange Format(c) is the Copyright property of + CompuServe Incorporated. GIF(sm) is a Service Mark property of + CompuServe Incorporated." + + +REFERENCES +========== + +We recommend reading one or more of these references before trying to +understand the innards of the JPEG software. + +The best short technical introduction to the JPEG compression algorithm is + Wallace, Gregory K. "The JPEG Still Picture Compression Standard", + Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44. +(Adjacent articles in that issue discuss MPEG motion picture compression, +applications of JPEG, and related topics.) If you don't have the CACM issue +handy, a PostScript file containing a revised version of Wallace's article is +available at http://www.ijg.org/files/wallace.ps.gz. The file (actually +a preprint for an article that appeared in IEEE Trans. Consumer Electronics) +omits the sample images that appeared in CACM, but it includes corrections +and some added material. Note: the Wallace article is copyright ACM and IEEE, +and it may not be used for commercial purposes. + +A somewhat less technical, more leisurely introduction to JPEG can be found in +"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by +M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides +good explanations and example C code for a multitude of compression methods +including JPEG. It is an excellent source if you are comfortable reading C +code but don't know much about data compression in general. The book's JPEG +sample code is far from industrial-strength, but when you are ready to look +at a full implementation, you've got one here... + +The best currently available description of JPEG is the textbook "JPEG Still +Image Data Compression Standard" by William B. Pennebaker and Joan L. +Mitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1. +Price US$59.95, 638 pp. The book includes the complete text of the ISO JPEG +standards (DIS 10918-1 and draft DIS 10918-2). +Although this is by far the most detailed and comprehensive exposition of +JPEG publicly available, we point out that it is still missing an explanation +of the most essential properties and algorithms of the underlying DCT +technology. +If you think that you know about DCT-based JPEG after reading this book, +then you are in delusion. The real fundamentals and corresponding potential +of DCT-based JPEG are not publicly known so far, and that is the reason for +all the mistaken developments taking place in the image coding domain. + +The original JPEG standard is divided into two parts, Part 1 being the actual +specification, while Part 2 covers compliance testing methods. Part 1 is +titled "Digital Compression and Coding of Continuous-tone Still Images, +Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS +10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of +Continuous-tone Still Images, Part 2: Compliance testing" and has document +numbers ISO/IEC IS 10918-2, ITU-T T.83. +IJG JPEG 8 introduces an implementation of the JPEG SmartScale extension +which is specified in two documents: A contributed document at ITU and ISO +with title "ITU-T JPEG-Plus Proposal for Extending ITU-T T.81 for Advanced +Image Coding", April 2006, Geneva, Switzerland. The latest version of this +document is Revision 3. And a contributed document ISO/IEC JTC1/SC29/WG1 N +5799 with title "Evolution of JPEG", June/July 2011, Berlin, Germany. + +The JPEG standard does not specify all details of an interchangeable file +format. For the omitted details we follow the "JFIF" conventions, revision +1.02. JFIF 1.02 has been adopted as an Ecma International Technical Report +and thus received a formal publication status. It is available as a free +download in PDF format from +http://www.ecma-international.org/publications/techreports/E-TR-098.htm. +A PostScript version of the JFIF document is available at +http://www.ijg.org/files/jfif.ps.gz. There is also a plain text version at +http://www.ijg.org/files/jfif.txt.gz, but it is missing the figures. + +The TIFF 6.0 file format specification can be obtained by FTP from +ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme +found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems. +IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6). +Instead, we recommend the JPEG design proposed by TIFF Technical Note #2 +(Compression tag 7). Copies of this Note can be obtained from +http://www.ijg.org/files/. It is expected that the next revision +of the TIFF spec will replace the 6.0 JPEG design with the Note's design. +Although IJG's own code does not support TIFF/JPEG, the free libtiff library +uses our library to implement TIFF/JPEG per the Note. + + +ARCHIVE LOCATIONS +================= + +The "official" archive site for this software is www.ijg.org. +The most recent released version can always be found there in +directory "files". This particular version will be archived as +http://www.ijg.org/files/jpegsrc.v8d.tar.gz, and in Windows-compatible +"zip" archive format as http://www.ijg.org/files/jpegsr8d.zip. + +The JPEG FAQ (Frequently Asked Questions) article is a source of some +general information about JPEG. +It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/ +and other news.answers archive sites, including the official news.answers +archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/. +If you don't have Web or FTP access, send e-mail to mail-server@rtfm.mit.edu +with body + send usenet/news.answers/jpeg-faq/part1 + send usenet/news.answers/jpeg-faq/part2 + + +ACKNOWLEDGMENTS +=============== + +Thank to Juergen Bruder for providing me with a copy of the common DCT +algorithm article, only to find out that I had come to the same result +in a more direct and comprehensible way with a more generative approach. + +Thank to Istvan Sebestyen and Joan L. Mitchell for inviting me to the +ITU JPEG (Study Group 16) meeting in Geneva, Switzerland. + +Thank to Thomas Wiegand and Gary Sullivan for inviting me to the +Joint Video Team (MPEG & ITU) meeting in Geneva, Switzerland. + +Thank to Thomas Richter and Daniel Lee for inviting me to the +ISO/IEC JTC1/SC29/WG1 (also known as JPEG, together with ITU-T SG16) +meeting in Berlin, Germany. + +Thank to John Korejwa and Massimo Ballerini for inviting me to +fruitful consultations in Boston, MA and Milan, Italy. + +Thank to Hendrik Elstner, Roland Fassauer, Simone Zuck, Guenther +Maier-Gerber, Walter Stoeber, Fred Schmitz, and Norbert Braunagel +for corresponding business development. + +Thank to Nico Zschach and Dirk Stelling of the technical support team +at the Digital Images company in Halle for providing me with extra +equipment for configuration tests. + +Thank to Richard F. Lyon (then of Foveon Inc.) for fruitful +communication about JPEG configuration in Sigma Photo Pro software. + +Thank to Andrew Finkenstadt for hosting the ijg.org site. + +Last but not least special thank to Thomas G. Lane for the original +design and development of this singular software package. + + +FILE FORMAT WARS +================ + +The ISO/IEC JTC1/SC29/WG1 standards committee (also known as JPEG, together +with ITU-T SG16) currently promotes different formats containing the name +"JPEG" which is misleading because these formats are incompatible with +original DCT-based JPEG and are based on faulty technologies. +IJG therefore does not and will not support such momentary mistakes +(see REFERENCES). +There exist also distributions under the name "OpenJPEG" promoting such +kind of formats which is misleading because they don't support original +JPEG images. +We have no sympathy for the promotion of inferior formats. Indeed, one of +the original reasons for developing this free software was to help force +convergence on common, interoperable format standards for JPEG files. +Don't use an incompatible file format! +(In any case, our decoder will remain capable of reading existing JPEG +image files indefinitely.) + +Furthermore, the ISO committee pretends to be "responsible for the popular +JPEG" in their public reports which is not true because they don't respond to +actual requirements for the maintenance of the original JPEG specification. + +There are currently distributions in circulation containing the name +"libjpeg" which claim to be a "derivative" or "fork" of the original +libjpeg, but don't have the features and are incompatible with formats +supported by actual IJG libjpeg distributions. Furthermore, they +violate the license conditions as described under LEGAL ISSUES above. +We have no sympathy for the release of misleading and illegal +distributions derived from obsolete code bases. +Don't use an obsolete code base! + + +TO DO +===== + +Version 8 is the first release of a new generation JPEG standard +to overcome the limitations of the original JPEG specification. +More features are being prepared for coming releases... + +Please send bug reports, offers of help, etc. to jpeg-info@jpegclub.org. diff --git a/doc/libpng-license.txt b/doc/libpng-license.txt new file mode 100644 index 00000000..0c927409 --- /dev/null +++ b/doc/libpng-license.txt @@ -0,0 +1,111 @@ + +This copy of the libpng notices is provided for your convenience. In case of +any discrepancy between this copy and the notices in the file png.h that is +included in the libpng distribution, the latter shall prevail. + +COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: + +If you modify libpng you may insert additional notices immediately following +this sentence. + +This code is released under the libpng license. + +libpng versions 1.2.6, August 15, 2004, through 1.5.9, February 18, 2012, are +Copyright (c) 2004, 2006-2011 Glenn Randers-Pehrson, and are +distributed according to the same disclaimer and license as libpng-1.2.5 +with the following individual added to the list of Contributing Authors + + Cosmin Truta + +libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are +Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are +distributed according to the same disclaimer and license as libpng-1.0.6 +with the following individuals added to the list of Contributing Authors + + Simon-Pierre Cadieux + Eric S. Raymond + Gilles Vollant + +and with the following additions to the disclaimer: + + There is no warranty against interference with your enjoyment of the + library or against infringement. There is no warranty that our + efforts or the library will fulfill any of your particular purposes + or needs. This library is provided with all faults, and the entire + risk of satisfactory quality, performance, accuracy, and effort is with + the user. + +libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are +Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are +distributed according to the same disclaimer and license as libpng-0.96, +with the following individuals added to the list of Contributing Authors: + + Tom Lane + Glenn Randers-Pehrson + Willem van Schaik + +libpng versions 0.89, June 1996, through 0.96, May 1997, are +Copyright (c) 1996, 1997 Andreas Dilger +Distributed according to the same disclaimer and license as libpng-0.88, +with the following individuals added to the list of Contributing Authors: + + John Bowler + Kevin Bracey + Sam Bushell + Magnus Holmgren + Greg Roelofs + Tom Tanner + +libpng versions 0.5, May 1995, through 0.88, January 1996, are +Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. + +For the purposes of this copyright and license, "Contributing Authors" +is defined as the following set of individuals: + + Andreas Dilger + Dave Martindale + Guy Eric Schalnat + Paul Schmidt + Tim Wegner + +The PNG Reference Library is supplied "AS IS". The Contributing Authors +and Group 42, Inc. disclaim all warranties, expressed or implied, +including, without limitation, the warranties of merchantability and of +fitness for any purpose. The Contributing Authors and Group 42, Inc. +assume no liability for direct, indirect, incidental, special, exemplary, +or consequential damages, which may result from the use of the PNG +Reference Library, even if advised of the possibility of such damage. + +Permission is hereby granted to use, copy, modify, and distribute this +source code, or portions hereof, for any purpose, without fee, subject +to the following restrictions: + +1. The origin of this source code must not be misrepresented. + +2. Altered versions must be plainly marked as such and must not + be misrepresented as being the original source. + +3. This Copyright notice may not be removed or altered from any + source or altered source distribution. + +The Contributing Authors and Group 42, Inc. specifically permit, without +fee, and encourage the use of this source code as a component to +supporting the PNG file format in commercial products. If you use this +source code in a product, acknowledgment is not required but would be +appreciated. + + +A "png_get_copyright" function is available, for convenient use in "about" +boxes and the like: + + printf("%s",png_get_copyright(NULL)); + +Also, the PNG logo (in PNG format, of course) is supplied in the +files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). + +Libpng is OSI Certified Open Source Software. OSI Certified Open Source is a +certification mark of the Open Source Initiative. + +Glenn Randers-Pehrson +glennrp at users.sourceforge.net +February 18, 2012 diff --git a/doc/readme.txt b/doc/readme.txt new file mode 100644 index 00000000..3485418e --- /dev/null +++ b/doc/readme.txt @@ -0,0 +1,2 @@ +Linux Users: There are some tools at the web for reading .chm files (try http://xchm.sourceforge.net/). +You can find a html version of this documentation at http://irrlicht.sourceforge.net/docu/index.html \ No newline at end of file diff --git a/doc/release_checklist.txt b/doc/release_checklist.txt new file mode 100644 index 00000000..840e7728 --- /dev/null +++ b/doc/release_checklist.txt @@ -0,0 +1,60 @@ +Checklist for Irrlicht developers for doing releases. + +- PRE-BUILD TESTS: +- - Run tests in the tests folder +- - Compile and run all examples for testing (preferably on all platforms, +compilers, settings ... until you are certain enough stuff works sufficiently). +Ask for help for platforms which you don't own. +- - Compile the tools on all platforms you have. Note that some tools are in the buildall-examples VS project files on Windows, but on Linux +command line you have to compile them individually. + +- VERSION UPDATES: +- - check IRRLICHT_SDK_VERSION (in IrrCompileConfig.h) +- - check version number in the Makefile +- - update readme.txt (version number, supported compilers) +- - Add new release information (date+version-number) in changes.txt +- - go through folders if other .txt files still make sense (things change and updating those files tends to be forgotten) + +- BUILDING THE RELEASE +- - run a clean build for buildAllExamples in the examples folder with the +target compiler for 32-bit and for release (preferably oldest supported VS +compiler, otherwise oldest you have still installed) +- - when possible compile the dll for MinGW on Windows (in release and with -s for smaller size) +- - when possible compile the dll for 64 bit (again with Visual Studio and release) +- - run makedocumentation in scripts\doc\irrlicht +- - create a target directory, like irrlicht-1.8.1 for example +- - svn export to the target directory +- - copy the subfolders of doctemp into the doc folder of the target directory + careful, this should only be one(!) subfolder (we ended up with copies before, maybe Windows/Linux builds use different names?) +- - copy all .exe files (except test.exe) from bin\Win32-VisualStudio (.pdb's are not necessary) +- - copy Irrlicht.dll from bin\Win32-visualstudio +- - copy the files in lib\Win32-visualstudio +- - copy Irrlicht.dll from bin\Win64-VisualStudio +- - copy the files in lib\Win64-visualstudio +- - copy Irrlicht.dll from bin\Win32-gcc +- - copy the files in lib\Win32-gcc +- - remove the tests folder +- - remove scripts folder (if the release comes with docs, if you do a release +without docs for smaller filesizes then the script folder has to stay in). +- - create a zip file +- - figure out how to fix unix access right for shell-scripts in the zip file (my +trick so far is: unzip in Linux, set +x for all .sh files, zip again) + +RELEASING: +- - upload the zip-file somewhere, then download it again on all platforms and do + another quick test with that file (do examples still run, can you compile) +- - give the link to the zip out on the mailinglist for others to look at +- - Upload new documentation (the content of doc/html) to: web.sourceforge.net + (sftp protocol, user and passwd are your sourceforge account, the folder + might not be shown - but you can still cd into it!): + /home/project-web/i/ir/irrlicht/htdocs + Best create first a folder with a new name, copy stuff in there, test (just + check the website), rename old folder and give new folder the "docu" name. + Then you can delete the old folder if you want. +- - upload the zip by logging in to sourceforge and using the "Files" menu (needs + admin privileges and it's the 'Files' menu between 'Summary' and 'Reviews'). + The target is in one of the Irrlicht SDK subfolders. Then click the "i" beside + the file and "select all" to make it the active download. +- - write a forum post, tell everyone in facebook, reddit, your friends... +- - login to wordpress at http://irrlicht.sourceforge.net/wp-login.php, update the + downloads section and write a release post. diff --git a/doc/upgrade-guide.txt b/doc/upgrade-guide.txt new file mode 100644 index 00000000..ee638b9a --- /dev/null +++ b/doc/upgrade-guide.txt @@ -0,0 +1,2891 @@ +This file contains API changes between consecutive versions. You can get the +relevant information about all changes to the public Irrlicht API needed for +upgrading your code (esp. custom scene nodes and GUI elements) to a new Irrlicht +version. Since all changes are incremental you should skip forward to the +version you use right now and check each note until you reach the desired +version. +Please note that the changes described here do not contain functional changes, +but only syntactical ones. Also, new methods are not documented here and +have to be looked up in the API documentation instead. + +Basically, all changes have to be reflected in user code where used. Removed +and renamed methods are obviously not existant anymore. A hint is usually given +for such changes on how to remedy the situation. +Changed signatures of methods might go unnoticed. That need not be a bad thing, +e.g. for changes from s32 to u32 the parameters are usually automatically +converted by the compiler. However, one should be careful when writing custom +scene nodes or GUI elements. It might happen that the methods are not properly +chosen as candidates for virtual overloading. So always check that methods in +the user code have the proper signatures just as the interface versions. The +change hint will help to identify necessary changes. + +Changes for Version 1.2 +----------------------- +Removed compile flag (always used where available) +_IRR_LINUX_OPENGL_USE_EXTENSIONS_ + +IAnimatedMeshB3d: +Removed (no replacement available) + virtual void AddMatrixToJoint(s32 jointNumber, core::matrix4* matrix) = 0; + +IGUIElement.h +Changed signatures (made const) + IGUIElement* getParent() const + core::rect getRelativePosition() const + +IGUITabControl.h +Changed signatures (const param) + virtual IGUITab* addTab(const wchar_t* caption, s32 id=-1) = 0; + +IImage.h +Changed signatures (made const) + virtual ECOLOR_FORMAT getColorFormat() const = 0; + +IParticleAffector.h +Changed inheritance (from irr:IUnknown) + class IParticleAffector : public virtual io::IAttributeExchangingObject + +IParticleEmitter.h +Changed inheritance (from irr:IUnknown) + class IParticleEmitter : public virtual io::IAttributeExchangingObject + +IParticleSystemSceneNode.h +Changed signatures (const param) + virtual IParticleEmitter* createPointEmitter( + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 5, + u32 maxParticlesPerSecond = 10, + video::SColor minStartColor = video::SColor(255,0,0,0), + virtual IParticleEmitter* createBoxEmitter( + const core::aabbox3df& box = core::aabbox3df(-10,28,-10,10,30,10), + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 5, + u32 maxParticlesPerSecond = 10, + video::SColor minStartColor = video::SColor(255,0,0,0), + + virtual IParticleAffector* createGravityAffector( + const core::vector3df& gravity = core::vector3df(0.0f,-0.03f,0.0f), + u32 timeForceLost = 1000) = 0; + +ISceneManager.h +Changed signatures (additional param) + virtual ISceneNodeAnimator* createFlyCircleAnimator(const core::vector3df& center, + f32 radius, f32 speed=0.001f, const core::vector3df& direction= core::vector3df ( 0.f, 1.f, 0.f ) ) = 0; + +ITexture.h +Changed signatures (made const) + virtual ECOLOR_FORMAT getColorFormat() const = 0; + +IVideoDriver.h +Changed signatures (changed default param, use ECF_A1R5G5B5 explicitly for old behavior) + virtual ITexture* addTexture(const core::dimension2d& size, + const c8* name, ECOLOR_FORMAT format = ECF_A8R8G8B8) = 0; +Changed signatures (made const) + virtual ITexture* createRenderTargetTexture(const core::dimension2d& size) = 0; + +matrix4.h +Changed signatures (swapped parameter, it was (col, row) before although the names did not represent this) + f32& operator()(s32 row, s32 col); + const f32& operator()(s32 row, s32 col) const; + +S3DVertex.h +Changed signatures (unconst param) + S3DVertex(f32 x, f32 y, f32 z, f32 nx, f32 ny, f32 nz, SColor c, f32 tu, f32 tv); + S3DVertex(const core::vector3df& pos, const core::vector3df& normal, + SColor color, const core::vector2d& tcoords); + S3DVertex2TCoords(f32 x, f32 y, f32 z, SColor c, f32 tu, f32 tv, f32 tu2, f32 tv2); + S3DVertex2TCoords(const core::vector3df& pos, SColor color, + const core::vector2d& tcoords, const core::vector2d& tcoords2); + S3DVertex2TCoords(f32 x, f32 y, f32 z, f32 nx, f32 ny, f32 nz, SColor c, f32 tu, f32 tv); + S3DVertex2TCoords(const core::vector3df& pos, const core::vector3df& normal, + SColor color, const core::vector2d& tcoords); + S3DVertexTangents(const core::vector3df& pos, + const core::vector2df& tcoords, SColor c); + +SColor.h +Changed signatures (changed param types from signed to unsigned) + inline u16 RGBA16(u32 r, u32 g, u32 b, u32 a); + inline u16 RGB16(u32 r, u32 g, u32 b); + inline u16 X8R8G8B8toA1R5G5B5(u32 color); + inline u32 A1R5G5B5toA8R8G8B8(u32 color); + inline u32 R5G6B5toA8R8G8B8(u16 color); + inline u16 R5G6B5toA1R5G5B5(u16 color); + inline u16 A1R5G5B5toR5G6B5(u16 color); + inline u32 getAlpha(u16 color); + inline u32 getRed(u16 color); + inline u32 getGreen(u16 color); + inline u32 getBlue(u16 color); + inline u32 getLuminance(u16 color); + inline SColor (u32 a, u32 r, u32 g, u32 b); + inline SColor(u32 clr); + inline u32 getAlpha() const + inline u32 getRed() const + inline u32 getGreen() const + inline u32 getBlue() const + inline void setAlpha(u32 a); + inline void setRed(u32 r); + inline void setGreen(u32 g); + inline void setBlue(u32 b); + inline u16 toA1R5G5B5() const + inline void toOpenGLColor(u8* dest) const + inline void set(u32 a, u32 r, u32 g, u32 b); + inline void set(u32 col); +Changed signatures (const param) + inline SColor getInterpolated(const SColor &other, f32 d) const +Changed public member (type changed) + u32 color; + + +Changes for Version 1.3 +----------------------- +Globally renamed Frustrum to Frustum in all signatures and code parts + +IAnimatedMeshB3d.h +Renamed methods (small first letter) + virtual void setInterpolationMode(s32 mode) = 0; + virtual void setAnimateMode(s32 mode) = 0; + +IAnimatedMeshSceneNode.h +changed signature (changed types) + virtual void setAnimationSpeed(f32 framesPerSecond) = 0; + +ICameraSceneNode.h +Renamed methods and changed signature (changed types, frustum renaming) + virtual const SViewFrustum* getViewFrustum() const = 0; + +IFileSystem.h +Renamed method (from addUnZipFileArchive) + virtual bool addFolderFileArchive(const c8* filename, bool ignoreCase = true, bool ignorePaths = true) = 0; + +IGUIContextMenu.h +Changed signature (added param) + virtual s32 addItem(const wchar_t* text, s32 commandId=-1, bool enabled=true, + bool hasSubMenu=false, bool checked=false) = 0; + +IGUIElement.h +Changed inheritance + class IGUIElement : public virtual io::IAttributeExchangingObject, public IEventReceiver +Changed signature (made const) + core::rect getAbsolutePosition() const + +IGUIEnvironment.h +Changed signature (added param) + virtual IGUIButton* addButton(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0, const wchar_t* tooltiptext = 0) = 0; + +IGUIListBox.h +Removed method (Using sprite bank now) + virtual void setIconFont(IGUIFont* font) = 0; +Change signature (changed types, due to sprite bank) + virtual s32 addItem(const wchar_t* text, s32 icon) = 0; + +IGUISkin.h +Changed inheritance + class IGUISkin : public virtual io::IAttributeExchangingObject + +IGUIToolbar.h +Changed signature (Added param for tooltips) + virtual IGUIButton* addButton(s32 id=-1, const wchar_t* text=0, const wchar_t* tooltiptext=0, + video::ITexture* img=0, video::ITexture* pressedimg=0, + bool isPushButton=false, bool useAlphaChannel=false) = 0; + +IImage.h +Changed signature (made const) + virtual u32 getPitch() const = 0; + +IImageWriter.h +Changed signature (additional param) + virtual bool writeImage(io::IWriteFile *file, IImage *image, u32 param = 0) = 0; + +IMeshBuffer.h +Changed signature (changed return type) + virtual u32 getVertexCount() const = 0; + virtual u32 getIndexCount() const = 0; +Removed method (use setBoundingBox instead) + virtual core::aabbox3df& getBoundingBox() = 0; + +IMesh.h +Changed signature (changed types, made const) + virtual u32 getMeshBufferCount() const = 0; + virtual IMeshBuffer* getMeshBuffer(u32 nr) const = 0; +Removed method (use setBoundingBox instead) + virtual core::aabbox3d& getBoundingBox() = 0; + +IReadFile.h +Changed signature (changed types) + virtual s32 read(void* buffer, u32 sizeToRead) = 0; + +irrArray.h +Changed signature (made const) + s32 binary_search(const T& element, s32 left, s32 right) const + +irrMath.h +Constant changed + const f32 PI = 3.14159265359f; +Constants removed (use RADTODEG64 or DEGTORAD64 instead) + const f64 GRAD_PI = 180.0 / PI64; + const f64 GRAD_PI2 = PI64 / 180.0; +Changed signature (added tolerance parameter) + inline bool equals(const f32 a, const f32 b, const f32 tolerance = ROUNDING_ERROR_32) + +irrString.h +Changed signature (const param) + template string(const B* const c, u32 length); + template string(const B* const c); + template string& operator=(const B* const c); + template string operator+(const B* const c) const + bool operator ==(const T* const str) const + bool operator !=(const T* const str) const + bool equalsn(const T* const str, int len) const + void append(const T* const other); + s32 findFirstChar(const T* const c, u32 count) const + template s32 findFirstCharNotInList(const B* const c, u32 count) const + template s32 findLastCharNotInList(const B* const c, u32 count) const + template s32 find(const B* const str) const + void operator += (const T* const c); +Changed signature (changed type from signed) + T& operator [](const u32 index) const + u32 size() const + void append(const string& other, u32 length); + void reserve(u32 count); + s32 findNext(T c, u32 startPos) const + string subString(u32 begin, s32 length) const + void erase(u32 index); + void reallocate(u32 new_size); +Changed signature (added param) + s32 findLast(T c, s32 start = -1) const + +ISceneManager.h +Changed signature (changed default param from 128 minimalPolysPerNode) + virtual ISceneNode* addOctTreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent=0, + s32 id=-1, s32 minimalPolysPerNode=256, bool alsoAddIfMeshPointerZero=false) = 0; + virtual ISceneNode* addOctTreeSceneNode(IMesh* mesh, ISceneNode* parent=0, + s32 id=-1, s32 minimalPolysPerNode=256, bool alsoAddIfMeshPointerZero=false) = 0; +Changed signature (added param) + virtual ICameraSceneNode* addCameraSceneNodeFPS(ISceneNode* parent = 0, + f32 rotateSpeed = 100.0f, f32 moveSpeed = 500.0f, s32 id=-1, + SKeyMap* keyMapArray=0, s32 keyMapSize=0, bool noVerticalMovement=false, + f32 jumpSpeed = 0.f) = 0; + + 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, + video::SColor shade_top = 0xFFFFFFFF, video::SColor shade_down = 0xFFFFFFFF) = 0; + + virtual ITerrainSceneNode* addTerrainSceneNode( + const c8* heightMapFileName, + ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& rotation = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& scale = core::vector3df(1.0f,1.0f,1.0f), + video::SColor vertexColor = video::SColor(255,255,255,255), + s32 maxLOD=5, E_TERRAIN_PATCH_SIZE patchSize=ETPS_17, s32 smoothFactor=0) = 0; + + virtual ITerrainSceneNode* addTerrainSceneNode( + io::IReadFile* heightMapFile, + ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& rotation = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& scale = core::vector3df(1.0f,1.0f,1.0f), + video::SColor vertexColor = video::SColor(255,255,255,255), + s32 maxLOD=5, E_TERRAIN_PATCH_SIZE patchSize=ETPS_17, s32 smoothFactor=0) = 0; +Changed signature (changed return type) + virtual u32 registerNodeForRendering(ISceneNode* node, + E_SCENE_NODE_RENDER_PASS pass = ESNRP_AUTOMATIC) = 0; + +ISceneNodeAnimatorCollisionResponse.h +Changed signature (made const) + virtual void setEllipsoidTranslation(const core::vector3df &translation) = 0; + +ISceneNode.h +Renamed method (from OnPreRender) + virtual void OnRegisterSceneNode(); +Renamed method (from OnPostRender) + virtual void OnAnimate(u32 timeMs); +Changed signature (made const) + virtual const core::aabbox3d getTransformedBoundingBox() const + const core::matrix4& getAbsoluteTransformation() const + virtual bool isVisible() const + virtual s32 getID() const + scene::ISceneNode* getParent() const + virtual ESCENE_NODE_TYPE getType() const +Changed signature (changed type) + virtual video::SMaterial& getMaterial(u32 num); + void setMaterialTexture(u32 textureLayer, video::ITexture* texture); + void setAutomaticCulling( E_CULLING_TYPE state); + virtual void setDebugDataVisible(E_DEBUG_SCENE_TYPE visible); +Changed signature (changed return type) + virtual u32 getMaterialCount(); + virtual const core::vector3df& getRotation() const + E_CULLING_TYPE getAutomaticCulling() const +Changed signature (changed return type, made const) + E_DEBUG_SCENE_TYPE isDebugDataVisible() const + +ITerrainSceneNode.h +Changed signature (changed return type) + virtual u32 getIndexCount() = 0; + +ITexture.h +Changed signature (changed return type, made const) + virtual u32 getPitch() const = 0; +Removed method (Available in SMaterial now) + core::matrix4& getTransformation(); + +IVideoDriver.h +Changed signature (changed types) + virtual ITexture* getTextureByIndex(u32 index) = 0; + virtual void drawVertexPrimitiveList(const void* vertices, u32 vertexCount, const u16* indexList, u32 triangleCount, E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType) = 0; + virtual void drawIndexedTriangleList(const S3DVertex* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) = 0; + virtual void drawIndexedTriangleList(const S3DVertex2TCoords* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) = 0; + virtual void drawIndexedTriangleList(const S3DVertexTangents* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) = 0; + virtual void drawIndexedTriangleFan(const S3DVertex* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) = 0; + virtual void drawIndexedTriangleFan(const S3DVertex2TCoords* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) = 0; + virtual const SLight& getDynamicLight(u32 idx) = 0; + virtual IMaterialRenderer* getMaterialRenderer(u32 idx) = 0; + virtual const c8* getMaterialRendererName(u32 idx) = 0; +Changed signature (const param) + virtual void drawMeshBuffer( const scene::IMeshBuffer* mb) = 0; + virtual io::IAttributes* createAttributesFromMaterial(const video::SMaterial& material) = 0; +Changed signature (added param) + virtual u32 getPrimitiveCountDrawn( u32 param = 0 ) = 0; + virtual bool writeImageToFile(IImage* image, const c8* filename, u32 param = 0) = 0; + virtual IImage* createImageFromData(ECOLOR_FORMAT format, + const core::dimension2d& size, void *data, + bool ownForeignMemory=false, + bool deleteMemory = true) = 0; +Changed signature (changed return types) + virtual u32 getMaximalDynamicLightAmount() = 0; + virtual u32 getDynamicLightCount() = 0; + virtual u32 getMaximalPrimitiveCount() = 0; + virtual u32 getMaterialRendererCount() = 0; + +matrix4.h +Changed signature (added param) + matrix4( eConstructor constructor = EM4CONST_IDENTITY ); +Changed signature (const param) + f32& operator()(const s32 row, const s32 col); + const f32& operator()(const s32 row, const s32 col) const +Changed signature (param order) + void transformVect( vector3df& out, const vector3df& in ) const; + +quaternion.h +Changed signature (changed return type) + void slerp( quaternion q1, const quaternion q2, f32 interpolate ); + +SColor.h +Renamed method (from getLuminance), changed types + inline s32 getAverage(s16 color); +Changed signature (changed return types) + inline f32 getLuminance() const +Changed signature (const param) + inline SColorf getInterpolated(const SColorf &other, f32 d) const + +SMaterial.h +Constant type changed + const u32 MATERIAL_MAX_TEXTURES = 4; +Type changed + class SMaterial +Public members removed (use Textures[] instead) + ITexture* Texture1; + ITexture* Texture2; + ITexture* Texture3; + ITexture* Texture4; +Public members removed (use setFlag()/getFlag() instead) + Flags[] +Public members changed (type changed) + u32 ZBuffer; +Changed signature (made const) + inline bool operator!=(const SMaterial& b) const + +SMeshBuffer.h +Changed signature (changed param) + virtual u32 getVertexCount() const + virtual u32 getIndexCount() const +Removed method (use setBoundingBox instead) + virtual core::aabbox3d& getBoundingBox(); + +SMeshBufferLightMap.h +Changed signature (changed param) + virtual u32 getVertexCount() const + virtual u32 getIndexCount() const +Removed method (use setBoundingBox instead) + virtual core::aabbox3d& getBoundingBox(); + +SMeshBufferTangents.h +Changed signature (changed param) + virtual u32 getVertexCount() const + virtual u32 getIndexCount() const +Removed method (use setBoundingBox instead) + virtual core::aabbox3d& getBoundingBox(); + +SMesh.h +Changed signature (changed param, made const) + virtual u32 getMeshBufferCount() const + virtual IMeshBuffer* getMeshBuffer(u32 nr) const +Removed method (use setBoundingBox instead); + virtual core::aabbox3d& getBoundingBox(); + +vector3d.h +Changed signature (changed return type) + T getLength() const +Changed signature (changed type) + vector3d getInterpolated(const vector3d& other, const T d) const + +Changes for Version 1.3.1 +------------------------- +Changed types: + SMeshBuffer* types are now template typedefs from CMeshBuffer + +dimension2d.h +Changed signature (const param) + dimension2d(const T& width, const T& height); + dimension2d operator/(const T& scale); + dimension2d operator*(const T& scale); + +IAnimatedMeshSceneNode.h +Changed signature (made const) + virtual s32 getFrameNr() const = 0; + virtual s32 getStartFrame() const = 0; + virtual s32 getEndFrame() const = 0; +Renamed method (from getAbsoluteTransformation) + virtual const SMD3QuaterionTag& getMD3TagTransformation( const core::stringc & tagname) = 0; + +IGUIButton.h +Renamed method (from getUseAlphaChannel) + virtual bool isAlphaChannelUsed() = 0; + +IGUIElementFactory.h +Changed signature (made const) + EGUI_ELEMENT_TYPE getType() const + virtual const c8* getTypeName() const + +IGUIEnvironment.h +Changed signature (added param) + virtual bool saveGUI(const c8* filename, IGUIElement* start=0) = 0; + virtual bool saveGUI(io::IWriteFile* file, IGUIElement* start=0) = 0; + virtual bool loadGUI(const c8* filename, IGUIElement* parent=0) = 0; + virtual bool loadGUI(io::IReadFile* file, IGUIElement* parent=0) = 0; + +IGUIFontBitmap.h +Changed signature (made const) + virtual EGUI_FONT_TYPE getType() const { return EGFT_BITMAP; } + +IGUIFont.h +Changed signature (made const) + virtual EGUI_FONT_TYPE getType() const { return EGFT_CUSTOM; } + +IGUISkin.h +Changed signature (added param) + virtual IGUIFont* getFont(EGUI_DEFAULT_FONT which=EGDF_DEFAULT) = 0; + virtual void setFont(IGUIFont* font, EGUI_DEFAULT_FONT which=EGDF_DEFAULT) = 0; +Changed signature (made const) + virtual EGUI_SKIN_TYPE getType() const { return EGST_UNKNOWN; }; + +IImage.h +Changed signature (made const) + virtual const core::dimension2d& getDimension() const = 0; + virtual u32 getRedMask() const = 0; + virtual u32 getGreenMask() const = 0; + virtual u32 getBlueMask() const = 0; + virtual u32 getAlphaMask() const = 0; +Changed signature (changed return type, made const) + virtual u32 getBitsPerPixel() const = 0; + virtual u32 getBytesPerPixel() const = 0; + virtual u32 getImageDataSizeInBytes() const = 0; + virtual u32 getImageDataSizeInPixels() const = 0; +Changed signature (changed param type, made const) + virtual SColor getPixel(u32 x, u32 y) const = 0; + +IMeshCache.h +Changed signature (const param) + virtual void removeMesh(const IAnimatedMesh* const mesh) = 0; +Changed signature (const param, made const) + virtual s32 getMeshIndex(const IAnimatedMesh* const mesh) const = 0; + virtual const c8* getMeshFilename(const IAnimatedMesh* const mesh) const = 0; + virtual const c8* getMeshFilename(const IMesh* const mesh) const = 0; +Changed signature (changed return type, made const) + virtual u32 getMeshCount() const = 0; +Changed signature (changed param type) + virtual IAnimatedMesh* getMeshByIndex(u32 index) = 0; +Changed signature (made const) + virtual const c8* getMeshFilename(u32 index) const = 0; + +IParticleAffector.h +Changed signature (made const) + virtual E_PARTICLE_AFFECTOR_TYPE getType() const = 0; + +IParticleEmitter.h +Changed signature (made const) + virtual E_PARTICLE_EMITTER_TYPE getType() const = 0; + +irrString.h +Changed signature (const param) + string(const double number); +Changed signature (changed return type) + string& operator += (T c); + string& operator += (const string& other); +Changed signature (changed return type, const param) + string& operator += (const T* const c); + string& operator += (const int i); + string& operator += (const double i); + +ISceneManager.h +Changed signature (added param) + virtual ITerrainSceneNode* addTerrainSceneNode( + const c8* heightMapFileName, + ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& rotation = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& scale = core::vector3df(1.0f,1.0f,1.0f), + video::SColor vertexColor = video::SColor(255,255,255,255), + s32 maxLOD=5, E_TERRAIN_PATCH_SIZE patchSize=ETPS_17, s32 smoothFactor=0, + bool addAlsoIfHeightmapEmpty = false) = 0; + virtual ITerrainSceneNode* addTerrainSceneNode( + io::IReadFile* heightMapFile, + ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& rotation = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& scale = core::vector3df(1.0f,1.0f,1.0f), + video::SColor vertexColor = video::SColor(255,255,255,255), + s32 maxLOD=5, E_TERRAIN_PATCH_SIZE patchSize=ETPS_17, s32 smoothFactor=0, + bool addAlsoIfHeightmapEmpty = false) = 0; + virtual ISceneManager* createNewSceneManager(bool cloneContent=false) = 0; + +ISceneNodeAnimator.h +Changed signature (made const) + virtual ESCENE_NODE_ANIMATOR_TYPE getType() const + +ITexture.h +Changed signature (made const) + virtual bool hasMipMaps() const + +IVideoDriver.h +Changed signature (reference param) + virtual void draw3DBox(const core::aabbox3d& box, + SColor color = SColor(255,255,255,255)) = 0; +Changed signature (added defaults for param) + virtual void draw2DImage(video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, + s32 kerningWidth=0, + const core::rect* clipRect=0, + SColor color=SColor(255,255,255,255), + bool useAlphaChannelOfTexture=false) = 0; +Changed signature (changed return type) + virtual const SExposedVideoData& getExposedVideoData() = 0; + +line3d.h +Changed signature (changed return type) + T getLength() const + +matrix4.h +Changed type to template class + template class CMatrix4 + typedef CMatrix4 matrix4; +Changed signature (changed return type) + T& operator()(const s32 row, const s32 col); + const T& operator()(const s32 row, const s32 col) const + T& operator[](u32 index); + const T& operator[](u32 index) const +Changed signature (changed param type) + inline CMatrix4& operator=(const T& scalar); + const T* pointer() const + T* pointer(); + CMatrix4 operator*(const T& scalar) const; + CMatrix4& operator*=(const T& scalar); + void transformVect(T *out,const core::vector3df &in) const; + void rotateVect(T *out,const core::vector3df &in) const; + void multiplyWith1x4Matrix(T* matrix) const; + CMatrix4 interpolate(const core::CMatrix4& b, f32 time) const; + +plane3d.h +Renamed method (from existsInterSection) + bool existsIntersection(const plane3d& other) const + +quaternion.h +Changed signature (unconst param) + void slerp( quaternion q1, quaternion q2, f32 interpolate ); + +SExposedVideoData.h +Removed public member (replaced by X11Display and X11Window) + OpenGLLinux.Window; + +SIrrCreationParameters.h +Changed public member (changed type for 64bit system support) + void* WindowId; + +triangle3d.h +Changed method to private + bool isOnSameSide(const vector3d& p1, const vector3d& p2, + const vector3d& a, const vector3d& b) const + +vector2d.h +Changed signature (changed return value) + T getLength() const + T getDistanceFrom(const vector2d& other) const + +vector3d.h +Changed signature (changed return value) + T getDistanceFrom(const vector3d& other) const + +Changes for Version 1.4 +----------------------- +This release had many changes in API method signatures. Many methods have been +made const, also several parameter types were changed. The two most noticeable +changes (which almost every user of the Irrlicht API will come across) are the +renaming of IUnknown to IReferenceCounted and const-ref change of the SEvent +structure of the OnEvent method. Another important change: DirectX8 support is +now by default disabled, enable the define in IrrCompileConfig.h to restore the +old behavior. + +IReferenceCounted.h +Renamed Type (from IUnknown). This changed most classes in Irrlicht + class IReferenceCounted + +IEventReceiver.h +Changed signature (made const) + virtual bool OnEvent(const SEvent& event) = 0; + +IrrCompileConfig.h +DirectX8 support is now by default disabled + +CMeshBuffer.h +Removed method + virtual u32 getVertexPitch() const + +fast_atof.h +Changed signature to allow optional second parameter + u32 strtol10(const char* in, const char** out=0) + +IAnimatedMesh.h +Changed inheritance (instead of IReferenceCounted) + class IAnimatedMesh : public IMesh +Changed signature (made const) + virtual u32 getFrameCount() const = 0; + +IAnimatedMeshSceneNode.h +Changed signature (changed param type) + virtual void setCurrentFrame(f32 frame) = 0; +Replaced methods (generalized method getJointNode available) + virtual ISceneNode* getMS3DJointNode(const c8* jointName) = 0; + virtual ISceneNode* getXJointNode(const c8* jointName) = 0; + virtual ISceneNode* getB3DJointNode(const c8* jointName) = 0; +Changed signature (changed return type) + virtual f32 getFrameNr() const = 0; +Changed signature (made const) + virtual bool isReadOnlyMaterials() const = 0; + +IAttributeExchangingObject.h +Changed signature (made const) + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const {} + +IAttributes.h +Changed signature (made const, changed param type) + virtual u32 getAttributeCount() const = 0; +Changed signature (added param) + virtual bool read(io::IXMLReader* reader, bool readCurrentElementOnly=false, const wchar_t* elementName=0) = 0; + virtual bool write(io::IXMLWriter* writer, bool writeXMLHeader=false, const wchar_t* elementName=0) = 0; +Changed signature (made const-ref param) + virtual void addMatrix(const c8* attributeName, const core::matrix4& v) = 0; + virtual void setAttribute(const c8* attributeName, const core::matrix4& v) = 0; + virtual void setAttribute(s32 index, const core::matrix4& v) = 0; + +IBillboardSceneNode.h +Changed signature (made const) + virtual const core::dimension2d& getSize() const = 0; + virtual void getColor(video::SColor & topColor, video::SColor & bottomColor) const = 0; + +ICameraSceneNode.h +Changed signature (made const) + virtual const core::matrix4& getProjectionMatrix() const = 0; + virtual const core::matrix4& getViewMatrix() const = 0; + virtual bool OnEvent(const SEvent& event) = 0; + virtual f32 getNearValue() const = 0; + virtual f32 getFarValue() const = 0; + virtual f32 getAspectRatio() const = 0; + virtual f32 getFOV() const = 0; + virtual bool isInputReceiverEnabled() const = 0; + virtual bool isOrthogonal() const + +ICursorControl.h +Changed signature (made const) + virtual bool isVisible() const = 0; + +IFileList.h +Changed signature (made const, changed param or return types) + virtual u32 getFileCount() const = 0; + virtual const c8* getFileName(u32 index) const = 0; + virtual const c8* getFullFileName(u32 index) = 0; + virtual bool isDirectory(u32 index) const = 0; + +IFileSystem.h 2007-09-17 09:53:10.000000000 +0200 +Changed signature (made const method and const-ref param) + virtual core::stringc getAbsolutePath(const core::stringc& filename) const = 0; + virtual core::stringc getFileDir(const core::stringc& filename) const = 0; +Changed signature (made const) + virtual IFileList* createFileList() const = 0; + virtual bool existFile(const c8* filename) const = 0; + +IGUIButton.h +Changed signature (made const) + virtual bool isPressed() const = 0; + virtual bool isAlphaChannelUsed() const = 0; + virtual bool isPushButton() const = 0; + virtual bool isDrawingBorder() const = 0; + +IGUICheckBox.h +Changed signature (made const) + virtual bool isChecked() const = 0; + +IGUIComboBox.h +Changed signature (made const, changed param or return types) + virtual u32 getItemCount() const = 0; + virtual const wchar_t* getItem(u32 idx) const = 0; + virtual s32 getSelected() const = 0; +Changed signature (changed param or return types) + virtual u32 addItem(const wchar_t* text) = 0; + virtual void removeItem(u32 id) = 0; + +IGUIContextMenu.h +Changed signature (changed param or return types) + virtual u32 getItemCount() const = 0; + virtual u32 addItem(const wchar_t* text, s32 commandId=-1, bool enabled=true, bool hasSubMenu=false, bool checked=false) = 0; + virtual void setItemText(u32 idx, const wchar_t* text) = 0; + virtual void setItemEnabled(u32 idx, bool enabled) = 0; + virtual void setItemChecked(u32 idx, bool enabled) = 0; + virtual void removeItem(u32 idx) = 0; + virtual void setItemCommandId(u32 idx, s32 id) = 0; +Changed signature (made const, changed param or return types) + virtual const wchar_t* getItemText(u32 idx) const = 0; + virtual bool isItemEnabled(u32 idx) const = 0; + virtual bool isItemChecked(u32 idx) const = 0; + virtual s32 getSelectedItem() const = 0; + virtual s32 getItemCommandId(u32 idx) const = 0; + virtual IGUIContextMenu* getSubMenu(u32 idx) const = 0; + +IGUIEditBox.h +Changed signature (changed param or return types) + virtual void setMax(u32 max) = 0; +Changed signature (made const, changed param or return types) + virtual u32 getMax() const = 0; + +IGUIElementFactory.h +Changed signature (made const) + virtual s32 getCreatableGUIElementTypeCount() const = 0; + virtual EGUI_ELEMENT_TYPE getCreateableGUIElementType(s32 idx) const = 0; + virtual const c8* getCreateableGUIElementTypeName(s32 idx) const = 0; + virtual const c8* getCreateableGUIElementTypeName(EGUI_ELEMENT_TYPE type) const = 0; + +IGUIElement.h +Changed signature (made const) + bool isNotClipped() const + virtual bool isVisible() const + virtual bool isSubElement() const + virtual bool isEnabled() const + virtual const wchar_t* getText() const + virtual s32 getID() const + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const +Changed signature (made const-ref param or return type) + virtual const core::stringw& getToolTipText() const + virtual bool OnEvent(const SEvent& event) + +IGUIEnvironment.h +Changed signature (changed return type) + virtual bool setFocus(IGUIElement* element) = 0; + virtual bool removeFocus(IGUIElement* element) = 0; +Changed signature (made const) + virtual IGUIElement* getFocus() const = 0; + virtual bool hasFocus(IGUIElement* element) const = 0; + virtual video::IVideoDriver* getVideoDriver() const = 0; + virtual io::IFileSystem* getFileSystem() const = 0; + virtual IOSOperator* getOSOperator() const = 0; + virtual IGUISkin* getSkin() const = 0; + virtual IGUIFont* getBuiltInFont() const = 0; + virtual IGUIElementFactory* getDefaultGUIElementFactory() const = 0; + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const =0; +Changed signature (made const-ref param or return type) + virtual bool postEventFromUser(const SEvent& event) = 0; +Changed signature (made const, changed param or return types) + virtual u32 getRegisteredGUIElementFactoryCount() const = 0; + virtual IGUIElementFactory* getGUIElementFactory(u32 index) const = 0; + +IGUIFileOpenDialog.h +Changed signature (made const) + virtual const wchar_t* getFileName() const = 0; + +IGUIFontBitmap.h +Changed signature (made const) + virtual IGUISpriteBank* getSpriteBank() const = 0; + virtual u32 getSpriteNoFromChar(const wchar_t *c) const = 0; + virtual s32 getKerningWidth(const wchar_t* thisLetter=0, const wchar_t* previousLetter=0) const = 0; + +IGUIFont.h +Changed signature (made const) + virtual core::dimension2d getDimension(const wchar_t* text) const = 0; + virtual s32 getCharacterFromPos(const wchar_t* text, s32 pixel_x) const = 0; + virtual s32 getKerningWidth(const wchar_t* thisLetter=0, const wchar_t* previousLetter=0) const = 0; + virtual s32 getKerningHeight() const = 0; + +IGUIListBox.h +Changed signature (made const, changed param or return types) + virtual u32 getItemCount() const = 0; + virtual const wchar_t* getListItem(u32 id) const = 0; + virtual s32 getIcon(u32 index) const = 0; +Changed signature (changed param or return types) + virtual u32 addItem(const wchar_t* text) = 0; + virtual u32 addItem(const wchar_t* text, s32 icon) = 0; + virtual void removeItem(u32 index) = 0; +Changed signature (made const) + virtual s32 getSelected() const = 0; + +IGUIMeshViewer.h +Changed signature (made const) + virtual const video::SMaterial& getMaterial() const = 0; + +IGUIScrollBar.h +Changed signature (made const) + virtual s32 getMax() const = 0; + virtual s32 getSmallStep() const = 0; + virtual s32 getPos() const = 0; + +IGUISkin.h +Changed signature (made const) + virtual video::SColor getColor(EGUI_DEFAULT_COLOR color) const = 0; + virtual s32 getSize(EGUI_DEFAULT_SIZE size) const = 0; + virtual const wchar_t* getDefaultText(EGUI_DEFAULT_TEXT text) const = 0; + virtual IGUIFont* getFont(EGUI_DEFAULT_FONT which=EGDF_DEFAULT) const = 0; + virtual IGUISpriteBank* getSpriteBank() const = 0; + virtual u32 getIcon(EGUI_DEFAULT_ICON icon) const = 0; + +IGUISpriteBank.h +Changed signature (made const) + virtual u32 getTextureCount() const = 0; + virtual video::ITexture* getTexture(u32 index) const = 0; + +IGUIStaticText.h +Changed signature (made const) + virtual IGUIFont* getOverrideFont(void) const = 0; + virtual video::SColor const& getOverrideColor(void) const = 0; + virtual bool isOverrideColorEnabled(void) const = 0; + virtual bool isWordWrapEnabled(void) const = 0; + virtual s32 getTextHeight() const = 0; + virtual s32 getTextWidth(void) const = 0; + +IGUITabControl.h +Changed signature (made const) + virtual s32 getNumber() const = 0; + virtual s32 getTabCount() const = 0; + virtual IGUITab* getTab(s32 idx) const = 0; + virtual s32 getActiveTab() const = 0; + +IGUIWindow.h +Changed signature (made const) + virtual IGUIButton* getCloseButton() const = 0; + virtual IGUIButton* getMinimizeButton() const = 0; + virtual IGUIButton* getMaximizeButton() const = 0; + +IImageLoader.h +Changed signature (made const) + virtual bool isALoadableFileExtension(const c8* fileName) const = 0; + virtual bool isALoadableFileFormat(io::IReadFile* file) const = 0; + virtual IImage* loadImage(io::IReadFile* file) const = 0; + +IImageWriter.h +Changed signature (made const) + virtual bool isAWriteableFileExtension(const c8* fileName) const = 0; + virtual bool writeImage(io::IWriteFile *file, IImage *image, u32 param = 0) const = 0; + +ILogger.h +Changed signature (made const) + virtual ELOG_LEVEL getLogLevel() const = 0; + +IMaterialRenderer.h +Changed signature (made const-ref param) + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, bool resetAllRenderstates, IMaterialRendererServices* services) {}; +Changed signature (made const) + virtual bool isTransparent() const { return false; } + virtual s32 getRenderCapability() const { return 0; } + +IMesh.h +Changed signature (made const) + virtual IMeshBuffer* getMeshBuffer( const video::SMaterial &material) const = 0; + +IMeshLoader.h +Changed signature (made const) + virtual bool isALoadableFileExtension(const c8* fileName) const = 0; + +IMeshManipulator.h +Removed method (now in IMeshBuffer) + virtual void recalculateBoundingBox(scene::IMeshBuffer* buffer) const + +IMeshSceneNode.h +Changed signature (made const) + virtual bool isReadOnlyMaterials() const = 0; + +IOSOperator.h +Changed signature (made const) + virtual const wchar_t* getOperationSystemVersion() const = 0; + virtual void copyToClipboard(const c8* text) const = 0; + virtual c8* getTextFromClipboard() const = 0; + virtual bool getProcessorSpeedMHz(u32* MHz) const = 0; + virtual bool getSystemMemory(u32* Total, u32* Avail) const = 0; + +IParticleAffector.h +Changed signature (made const) + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const {} + +IParticleEmitter.h +Changed signature (made const) + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const {} + +IParticleSystemSceneNode.h +Changed signature (changed return type, changed param types) + virtual IParticlePointEmitter* createPointEmitter( + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 5, + u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin=2000, u32 lifeTimeMax=4000, + s32 maxAngleDegrees=0) = 0; + virtual IParticleEmitter* createBoxEmitter( + const core::aabbox3df& box = core::aabbox3df(-10,28,-10,10,30,10), + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 5, + u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin=2000, u32 lifeTimeMax=4000, + s32 maxAngleDegrees=0) = 0; + virtual IParticleFadeOutAffector* createFadeOutParticleAffector( + const video::SColor& targetColor = video::SColor(0,0,0,0), + u32 timeNeededToFadeOut = 1000) = 0; + virtual IParticleGravityAffector* createGravityAffector( + const core::vector3df& gravity = core::vector3df(0.0f,-0.03f,0.0f), + u32 timeForceLost = 1000) = 0; + +IQ3Shader.h +Removed method + bool operator < ( const SVariable &other ) const + +IReadFile.h +Changed param types (adapt the correct C-API for file positions) + virtual bool seek(long finalPos, bool relativeMovement = false) = 0; + virtual long getSize() const = 0; + virtual long getPos() const = 0; + IReadFile* createLimitReadFile(const c8* fileName, IReadFile* alreadyOpenedFile, long areaSize); + IReadFile* createMemoryReadFile(void* memory, long size, const c8* fileName, bool deleteMemoryWhenDropped); +Changed signature (made const) + virtual const c8* getFileName() const = 0; + +IrrlichtDevice.h +Changed signature (made const) + virtual bool isWindowActive() const = 0; + virtual const c8* getVersion() const = 0; +Changed signature (made const-ref param) + virtual void postEventFromUser(const SEvent& event) = 0; + +irrList.h +Changed some structures in order to incorporate a ConstIterator class. + Iterator begin() + ConstIterator begin() const + Iterator end() + ConstIterator end() const + Iterator getLast() + ConstIterator getLast() const + void insert_after(const Iterator& it, const T& element) + void insert_before(const Iterator& it, const T& element) + +irrMath.h +Changed signature (Use const references for better class handling) + inline const T& min_(const T& a, const T& b) + inline const T& min_(const T& a, const T& b, const T& c) + inline const T& max_(const T& a, const T& b) + inline const T& max_(const T& a, const T& b, const T& c) + inline T abs_(const T& a) + inline T lerp(const T& a, const T& b, const f32 t) + inline const T clamp (const T& value, const T& low, const T& high) + +irrString.h +Changed signature (made proper const method) + T& operator [](const u32 index) + const T& operator [](const u32 index) const + +irrXML.h +Changed signature (adapt the correct C-API for file positions, made const) + virtual long getSize() const = 0; +Changed signature (changed param types) + virtual unsigned int getAttributeCount() const = 0; + +ISceneManager.h +Changed signature (changed param types) + 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; +Changed signature (changed param types and order) + virtual IAnimatedMesh* addArrowMesh(const c8* name, + video::SColor vtxColor0=0xFFFFFFFF, + video::SColor vtxColor1=0xFFFFFFFF, + u32 tesselationCylinder=4, u32 tesselationCone=8, + f32 height=1.f, f32 cylinderHeight=0.6f, + f32 width0=0.05f, f32 width1=0.3f) = 0; +Changed signature (changed param types) + virtual bool postEventFromUser(const SEvent& event) = 0; + virtual ISceneNodeFactory* getSceneNodeFactory(u32 index) = 0; + virtual ISceneNodeAnimatorFactory* getSceneNodeAnimatorFactory(u32 index) = 0; +Changed signature (made const) + virtual E_SCENE_NODE_RENDER_PASS getSceneNodeRenderPass() const = 0; +Changed signature (changed param types, made const) + virtual u32 getRegisteredSceneNodeFactoryCount() const = 0; + virtual u32 getRegisteredSceneNodeAnimatorFactoryCount() const = 0; + virtual const video::SColorf& getAmbientLight() const = 0; + +ISceneNodeAnimatorCollisionResponse.h +Changed signature (made const) + virtual bool isFalling() const = 0; + +ISceneNodeAnimatorFactory.h +Changed signature (changed param types, made const) + virtual u32 getCreatableSceneNodeAnimatorTypeCount() const = 0; + virtual ESCENE_NODE_ANIMATOR_TYPE getCreateableSceneNodeAnimatorType(u32 idx) const = 0; + virtual const c8* getCreateableSceneNodeAnimatorTypeName(u32 idx) const = 0; +Changed signature (made const) + virtual const c8* getCreateableSceneNodeAnimatorTypeName(ESCENE_NODE_ANIMATOR_TYPE type) const = 0; + +ISceneNodeFactory.h +Changed signature (changed param types, made const) + virtual u32 getCreatableSceneNodeTypeCount() const = 0; + virtual ESCENE_NODE_TYPE getCreateableSceneNodeType(u32 idx) const = 0; + virtual const c8* getCreateableSceneNodeTypeName(u32 idx) const = 0; +Changed signature (made const) + virtual const c8* getCreateableSceneNodeTypeName(ESCENE_NODE_TYPE type) const = 0; + +ISceneNode.h +Changed signature (made const) + virtual u32 getMaterialCount() const + bool isDebugObject() const + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const + +IShadowVolumeSceneNode.h +Changed signature (made const param) + virtual void setMeshToRenderFrom(const IMesh* mesh) = 0; + +ITerrainSceneNode.h +Changed signature (made const) + virtual u32 getIndexCount() const = 0; + virtual void getMeshBufferForLOD(SMeshBufferLightMap& mb, s32 LOD) const = 0; + virtual s32 getCurrentLODOfPatches(core::array& LODs) const = 0; + virtual f32 getHeight( f32 x, f32 y ) const = 0; +Changed signature (made const, made const-ref param) + virtual const core::vector3df& getTerrainCenter() const = 0; + +ITexture.h +Changed signature (made const) + virtual const core::dimension2d& getOriginalSize() const = 0; + virtual const core::dimension2d& getSize() const = 0; + virtual E_DRIVER_TYPE getDriverType() const = 0; + const core::stringc& getName() const { return Name; } + +ITimer.h +Changed signature (made const) + virtual u32 getRealTime() const = 0; + virtual u32 getTime() const = 0; + virtual f32 getSpeed() const = 0; + virtual bool isStopped() const = 0; + +ITriangleSelector.h +Changed signature (made const) + virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, + s32& outTriangleCount, const core::matrix4* transform=0) const = 0; + virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, + s32& outTriangleCount, const core::aabbox3d& box, + const core::matrix4* transform=0) const = 0; + virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, + s32& outTriangleCount, const core::line3d& line, + const core::matrix4* transform=0) const = 0; + +IVideoDriver.h +Changed signature (made const, changed param type) + virtual u32 getTextureCount() const = 0; +Changed signature (made const param) in all draw2DImage methods + virtual void draw2DImage(const video::ITexture* texture, +Changed signature (made const-ref param, made const) + virtual const core::dimension2d& getScreenSize() const = 0; + virtual const core::dimension2d& getCurrentRenderTargetSize() const = 0; +Changed signature (made const) + virtual bool queryFeature(E_VIDEO_DRIVER_FEATURE feature) const = 0; + virtual const core::matrix4& getTransform(E_TRANSFORMATION_STATE state) const = 0; + virtual ITexture* createRenderTargetTexture(const core::dimension2d& size, const c8* name = 0) = 0; + virtual void makeColorKeyTexture(video::ITexture* texture, video::SColor color) const = 0; + virtual void makeColorKeyTexture(video::ITexture* texture, + core::position2d colorKeyPixelPos) const = 0; + virtual void makeNormalMapTexture(video::ITexture* texture, f32 amplitude=1.0f) const = 0; + virtual s32 getFPS() const = 0; + virtual u32 getPrimitiveCountDrawn( u32 param = 0 ) const = 0; + virtual u32 getMaximalDynamicLightAmount() const = 0; + virtual u32 getDynamicLightCount() const = 0; + virtual const SLight& getDynamicLight(u32 idx) const = 0; + virtual const wchar_t* getName() const = 0; + virtual u32 getMaximalPrimitiveCount() const = 0; + virtual bool getTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag) const = 0; + virtual u32 getMaterialRendererCount() const = 0; + virtual const c8* getMaterialRendererName(u32 idx) const = 0; + virtual E_DRIVER_TYPE getDriverType() const = 0; + +IWriteFile.h +Changed signature (changed param type) + virtual s32 write(const void* buffer, u32 sizeToWrite) = 0; + virtual bool seek(long finalPos, bool relativeMovement = false) = 0; +Changed signature (changed param type, made const) + virtual long getPos() const = 0; +Changed signature (made const) + virtual const c8* getFileName() const = 0; + +line2d.h +Changed signature (made const) + vector2d getUnitVector() const + f64 getAngleWith(const line2d& l) const + T getPointOrientation(const vector2d& point) const + bool isPointOnLine(const vector2d& point) const + +matrix4.h +Changed signature (made template param) + void setTranslation( const vector3d& translation ); + vector3d getTranslation() const; + void setInverseTranslation( const vector3d& translation ); + inline void setRotationRadians( const vector3d& rotation ); + void setRotationDegrees( const vector3d& rotation ); + core::vector3d getRotationDegrees() const; + inline void setInverseRotationRadians( const vector3d& rotation ); + void setInverseRotationDegrees( const vector3d& rotation ); + void setScale( const vector3d& scale ); + core::vector3d getScale() const; + +rect.h +Changed signature (made non-const ref param, C++ conformance) + rect& operator+=(const position2d& pos) + rect& operator-=(const position2d& pos) + +S3DVertex.h +Changed inheritance (S3DVertex is now base class of other vertex types) +struct S3DVertex2TCoords : public S3DVertex +struct S3DVertexTangents : public S3DVertex + +SAnimatedMesh.h +Changed signature (changed param type, made const) + virtual u32 getFrameCount() const + +SColor.h +Changed signature (changed param type) + inline u32 A1R5G5B5toA8R8G8B8(u16 color) + +SLight.h +Removed attribute (use LightSceneNode position instead) + core::vector3df Position; + +SMaterial.h +Changed attribute structure (texture layer properties are now in thenew TextureLayer array). This changes access to Textures, TextureMatrix, TextureWrap, and the filter settings, which are also per-layer now. + SMaterialLayer TextureLayer[MATERIAL_MAX_TEXTURES]; + +vector3d.h +Changed signature (made template param) + bool equals(const vector3d& other, const T tolerance = (T)ROUNDING_ERROR_32 ) const + +Changes for Version 1.4.1 +------------------------- +Since this version is a backward compatible bugfix release, the API changes are only a few. None of them should result +in uncompilable code. Newly found warnings might point out wrongly used variables, additional casts or type changes in the +app should easily fix that. The only change which might go unnoticed by the compiler, but affect the application is the +changed initialization in SColorf. This was done to synchronize with other constructors from SColorf and SColor, though, +so the expectations are now much better met. +Also, OSX users have to adjust the defines in IrrCompileConfig, as we now also have OSX defines in Irrlicht style. It's now +even possible to build with X11 support under OSX without changes in the device code. + +SColor.h +Changed signature (SColorf is now default initialized to alpha=1.0f) + SColorf(f32 r=0.f, f32 g=0.f, f32 b=0.f, f32 a=1.f) : r(r), g(g), b(b), a(a) {} + +IrrCompileConfig.h +Split the OSX define into platform and device (from old MACOSX define) + _IRR_OSX_PLATFORM_ for Apple systems running OSX + _IRR_USE_OSX_DEVICE_ for Cocoa native windowing on OSX + +ISceneManager.h +Added new overload for getMesh with IReadFile instead of filename. + virtual IAnimatedMesh* getMesh(io::IReadFile* file) = 0; + +irrMath.h +Renamed method setbit + REALINLINE void setbit_cond ( u32 &state, s32 condition, u32 mask ) + +ISceneNode.h +Changed signature (because the debug data enum values can be OR'ed to enable multiple debug data types) + virtual void setDebugDataVisible(s32 state) + s32 isDebugDataVisible() const + s32 DebugDataVisible; + +matrix4.h +Changed signature (Added return values to some methods) + inline CMatrix4& setbyproduct(const CMatrix4& other_a,const CMatrix4& other_b ); + CMatrix4& setbyproduct_nocheck(const CMatrix4& other_a,const CMatrix4& other_b ); + inline CMatrix4& makeIdentity(); + CMatrix4& setTranslation( const vector3d& translation ); + CMatrix4& setInverseTranslation( const vector3d& translation ); + inline CMatrix4& setRotationRadians( const vector3d& rotation ); + CMatrix4& setRotationDegrees( const vector3d& rotation ); + inline CMatrix4& setInverseRotationRadians( const vector3d& rotation ); + CMatrix4& setInverseRotationDegrees( const vector3d& rotation ); + CMatrix4& setScale( const vector3d& scale ); + CMatrix4& buildProjectionMatrixPerspectiveFovRH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar); + CMatrix4& buildProjectionMatrixPerspectiveFovLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar); + CMatrix4& buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar); + CMatrix4& buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar); + CMatrix4& buildProjectionMatrixOrthoLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar); + CMatrix4& buildProjectionMatrixOrthoRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar); + CMatrix4& buildCameraLookAtMatrixLH(...) + CMatrix4& buildCameraLookAtMatrixRH(...) + CMatrix4& buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point=1.0f); + CMatrix4& buildNDCToDCMatrix( const core::rect& area, f32 zScale); + CMatrix4& setTextureScale( f32 sx, f32 sy ); + CMatrix4& setTextureRotationCenter( f32 radAngle ); + CMatrix4& setTextureScaleCenter( f32 sx, f32 sy ); + CMatrix4& setTextureTranslate( f32 x, f32 y ); + CMatrix4& setM(const T* data); +Added overload (for one scale value for all axes) + CMatrix4& setScale( const T scale ) { return setScale(core::vector3d(scale,scale,scale)); } + +S3DVertex.h +Added operator + bool operator<(const S3DVertex& other) const + bool operator<(const S3DVertex2TCoords& other) const + bool operator<(const S3DVertexTangents& other) const + +irrString.h +Changed signature (int->u32, negative length didn't make sense) + bool equalsn(const string& other, u32 n) const + bool equalsn(const T* const str, u32 n) const +New overload/missing method (completing the findLast... and find...Char methods) + s32 findLastChar(const T* const c, u32 count) const +Changed signature (Added return value) + string& trim() + +Changes for Version 1.4.2 +------------------------- +This is once more a bugfix release of the 1.4 branch, and hence pretty API-consistent and backward compatible. The major reason to publish this release is the OpenGL bug, which made several OpenGL 2.x drivers run in SW emulation. +However, we also introduced some driver consistency fixes, which might affect your application's behavior. So read through the next points thoroughly. + +SceneParameters.h (and general video driver behavior) +The way Irrlicht handles zbuffer writing with transparent materials has changed. This was an issue ever since, because the default behavior in Irrlicht is to disable writing to the z-buffer for all really transparent, i.e. blending materials. This avoids problems with intersecting faces, but can also break renderings. And this is now consistent for both OpenGL and Direct3D. +If transparent materials should use the SMaterial flag for ZWriteEnable just as other material types use the newly introduced attribute scene::ALLOW_ZWRITE_ON_TRANSPARENT like this: +SceneManager->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true); +All transparent materials will henceforth work as specified by the material flag, until the scenemanager attribute is set to false. + +SMaterialLayer.h +The texture matrix now uses irrAllocator for memory handling. This shouldn't be noticeable from the user application (besides fixed heap corruptions on Windows machines), but is still mentioned for completeness. + +ISceneNode.h +Documentation error. The docs said that children of a scene node are not visible if the node itself is set to visible. This is of course wrong, children inherit non-visibility of the parent and are hence invisible if the parent is. If the parent is visible, the visibility flag of the child determines its status. + +SColor.h +Removed methods (use the unsigned versions and cast in your app if necessary) + inline s32 getRedSigned(u16 color) + inline s32 getGreenSigned(u16 color) + inline s32 getBlueSigned(u16 color) + +IParticleSystemSceneNode.h +Changed default values (the old direction default was no real direction) + virtual IParticleAnimatedMeshSceneNodeEmitter* createAnimatedMeshSceneNodeEmitter(...) + virtual IParticleCylinderEmitter* createCylinderEmitter(...) + virtual IParticleMeshEmitter* createMeshEmitter(...) + +IBoneSceneNode.h +Changed signature (Made const) + virtual E_BONE_SKINNING_SPACE getSkinningSpace() const=0; + +IrrlichtDevice.h +Changed signature (Return value bool instead of void). Returns whether the event has been handled somewhere. + virtual bool postEventFromUser(const SEvent& event) = 0; + +Changes for Version 1.5 +----------------------- +Another major release, so expect API breaks at several places. The changes +herein are described as a difference to Irrlicht 1.4.2. + +The most noticeable changes are the speed factor of the FPS camera (now units/ms +instead of units/s, so divide the parameter by 1000.f) and the new interfaces +of the camera nodes, based on scene node animators. Custom camera nodes should +be adpated to this new scheme, although they might still work. Also, particle +sizes are now set and handled by the emitters, which requires a change of the +particle system constructor call or adaption of the setParticleSize method to +work on the emitters. A deprecation method is issued if the old scheme is used. +Light setting has also changed, the SLight struct is used in even less +situations than before, instead use methods in ILightSceneNode. + +Other changes did change major parts of the underlying structures, but might go +unnoticed on the user level. This includes 32bit indices and Vertex Buffer +Objects. However, VBOs require the user to call setDirty on Meshes or +MeshBuffers after changes to the vertex or index data. The all need only to be +done once before the next render call, but again after subsequent changes later +on. + + +All Mesh types and MeshBuffers: +New methods for VBO support. Once VBOs are enabled for a meshbuffer, changes +will only be effective after a call to setDirty(). VBOs are enabled by default +for some scene nodes. + virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX); + +All MeshBuffers: +Due to the 32bit support, it might happen that indices are stored as 32bit integers. The actual index type can be queried from a mesh buffer. + virtual video::E_INDEX_TYPE getIndexType() const + +IrrCompileConfig.h +Some new defines for configuring Irrlicht +_IRR_USE_WINDOWS_CE_DEVICE_ for Windows CE API based device +_IRR_COMPILE_WITH_JOYSTICK_EVENTS_ to enable joystick support (enabled by default) +_IRR_COMPILE_WITH_LWO_LOADER_ to enable the LWO mesh loader (enabled by default) +_IRR_COMPILE_WITH_OBJ_WRITER_ to enable the OBJ mesh writer (enabled by default) +_IRR_COMPILE_WITH_WAL_LOADER_ to enable the WAL image loader (enabled by default) +_IRR_USE_NVIDIA_PERFHUD_ for support of the PerfHUD tool (disabled by default) + +SceneParameters.h +New parameter scene::OBJ_LOADER_IGNORE_GROUPS, which allows to ignore the group structure of obj files. It's disabled by default, meaning obj groups will be represented by separate meshbuffers. + +SColor.h +Renamed method names of the SColorHSL class + void fromRGB(const SColor &color); + void toRGB(SColor &color) const; + +ITexture.h +Added new parameter + virtual void* lock(bool readOnly = false) = 0; + +IMeshManipulator.h +Renamed methods (the old ones still exist, but are deprecated). The new methods also work on meshbuffers, not just meshes. +(renamed from scaleMesh) + virtual void scale(IMesh* mesh, const core::vector3df& factor) const = 0; +(renamed from transformMesh) + virtual void transform(IMesh* mesh, const core::matrix4& m) const = 0; +Changed signature (Added new parameters to adjust the algorithm) + virtual IMesh* createMeshWithTangents(IMesh* mesh, bool recalculateNormals=false, bool smooth=false, bool angleWeighted=false) const = 0; + +IBillboardTextSceneNode.h +New interface replacing the multiple inheritance from bliiboard and text scene node previously used by the billboard text scene node. + +IParticleSystemSceneNode.h +All emitters have minStartSize and maxStartSize parameters now, since partice size is handled by the emitters now. +Default value added + virtual void setParticlesAreGlobal(bool global=true) = 0; + +fast_atof.h +Signature change (return value changed from u32) +inline s32 strtol10(const char* in, const char** out=0) +Signature change (parameter changed from float) +inline const char* fast_atof_move( const char * in, f32 & out) + +IAnimatedMeshSceneNode.h +Added new parameter (dummy node used for simplifying shadow calculation) + virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh=0, + s32 id=-1, bool zfailmethod=true, f32 infinity=10000.0f) = 0; + +ISceneManager.h +Removed extra render passes for quake shaders +Changed scene node from ISceneNode to IMeshSceneNode + virtual IMeshSceneNode* addCubeSceneNode(f32 size=10.0f, ISceneNode* parent=0, s32 id=-1, ...) + virtual IMeshSceneNode* addSphereSceneNode(f32 radius=5.0f, s32 polyCount=16, ...) +Changed default value (from 256 to 512, for efficiency on common gfx hardware) + virtual ISceneNode* addOctTreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent=0, + s32 id=-1, s32 minimalPolysPerNode=512, bool alsoAddIfMeshPointerZero=false) = 0; +Changed default value (from 500.f, to adapt the changed speed scale) + virtual ICameraSceneNode* addCameraSceneNodeFPS(ISceneNode* parent = 0, + f32 rotateSpeed = 100.0f, f32 moveSpeed = .5f, s32 id=-1, ...) +Added default values + virtual ISceneNode* addSkyDomeSceneNode(video::ITexture* texture, + u32 horiRes=16, u32 vertRes=8, + f64 texturePercentage=0.9, f64 spherePercentage=2.0, + ISceneNode* parent=0, s32 id=-1) = 0; +Changed return value (from ITextSceneNode, due to changed inheritance) + virtual IBillboardTextSceneNode* addBillboardTextSceneNode( gui::IGUIFont* font, const wchar_t* text, ...) +Changed default value (gravity, from -100.f) + virtual ISceneNodeAnimatorCollisionResponse* createCollisionResponseAnimator( + ITriangleSelector* world, ISceneNode* sceneNode, + const core::vector3df& ellipsoidRadius = core::vector3df(30,60,30), + const core::vector3df& gravityPerSecond = core::vector3df(0,-10.0f,0), + const core::vector3df& ellipsoidTranslation = core::vector3df(0,0,0), + f32 slidingValue = 0.0005f) = 0; + +ISceneNodeAnimator.h +Changed inheritance (for interactive animators) + class ISceneNodeAnimator : public io::IAttributeExchangingObject, public IEventReceiver +Changed to pure virtual (bug fix) + virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0) = 0; + +IVideoModeList.h +Changed return value (constification) + virtual const core::dimension2d& getDesktopResolution() const = 0; + +IBoneSceneNode.h +Deprecation: Use getName instead. + virtual const c8* getBoneName() const; + +vector3d.h +Changed return value (return *this) + vector3d& set(const T nx, const T ny, const T nz) {X=nx; Y=ny; Z=nz; return *this;} + vector3d& set(const vector3d& p) {X=p.X; Y=p.Y; Z=p.Z;return *this;} + vector3d& setLength(T newlength) + vector3d& invert() +Added default value + void rotateXZBy(f64 degrees, const vector3d& center=vector3d()) + void rotateXYBy(f64 degrees, const vector3d& center=vector3d()) + void rotateYZBy(f64 degrees, const vector3d& center=vector3d()) +Changed parameter type (interpolation factor must not be integral) + vector3d getInterpolated(const vector3d& other, f64 d) const + vector3d getInterpolated_quadratic(const vector3d& v2, const vector3d& v3, f64 d) const +Method made const + vector3d getHorizontalAngle() const + +SLight.h +Attenuation can be overridden by ILightSceneMethod setRadius() Attenuation will +change to (0,1.f/radius,0). Can be overridden after radius was set. +The following members are read-only now: + f32 Radius; + E_LIGHT_TYPE Type; + bool CastShadows; + +ITerrainSceneNode.h +Parameter type changed (diue to possible 32bit indices) + virtual void getMeshBufferForLOD(IDynamicMeshBuffer& mb, s32 LOD=0) const =0; +Added dafault value (highest detail) + virtual void setLODOfPatch(s32 patchX, s32 patchZ, s32 LOD=0) =0; + +SExposedVideoData.h +Changed member attributes (from s32, to fix 64bit architecture problems) + void* HWnd; + void* HDc; + void* HRc; + void* HWnd; + +IAnimatedMeshMD3.h +Changed return value (constification) + const SMD3QuaterionTag& operator[](u32 index) const + +IQ3Shader.h +Changed default q3 shader values (from LIGHTMAP_M2) + const video::E_MATERIAL_TYPE defaultMaterialType = video::EMT_LIGHTMAP_M4; + const video::E_MODULATE_FUNC defaultModulate = video::EMFN_MODULATE_4X; + +ISceneNode.h +Method made virtual + virtual const core::matrix4& getAbsoluteTransformation() const +Changed return value (constified) + virtual const core::vector3df& getScale() const + virtual const core::vector3df& getPosition() const + +IEventReceiver.h +Removed member from UserEvent + f32 UserData3; + +SMaterial.h +Changed member type (from u32) + char ZBuffer; + +IGUISkin.h +Added parameter (for alignment) + virtual void draw3DTabButton(IGUIElement* element, bool active, + const core::rect& rect, const core::rect* clip=0, gui::EGUI_ALIGNMENT alignment=EGUIA_UPPERLEFT) = 0; + 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; + +quaternion.h +Renamed method (from getDotProduct) + inline f32 dotProduct(const quaternion& other) const; +Changed return value (return *this) + quaternion& set(f32 x, f32 y, f32 z, f32 w); + quaternion& set(f32 x, f32 y, f32 z); + quaternion& set(const core::vector3df& vec); + quaternion& makeInverse(); + quaternion& slerp( quaternion q1, quaternion q2, f32 interpolate ); + quaternion& fromAngleAxis (f32 angle, const vector3df& axis); + quaternion& makeIdentity(); + quaternion& rotationFromTo(const vector3df& from, const vector3df& to); + +IVideoDriver.h +Added parameters (moved from endScene) and added default values + virtual bool beginScene(bool backBuffer=true, bool zBuffer=true, + SColor color=SColor(255,0,0,0), void* windowId=0, + core::rect* sourceRect=0) = 0; +Removed parameter (move to beginScene) + virtual bool endScene() = 0; +Renamed method (note, also affects ReferenceCount behavior!) +Use addRenderTargetTexture instead of createRenderTargetTexture + virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, + const c8* name=0) =0; +Changed parameters (for 32bit index support) + 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; +Changed parameter (colors are const pointers now) + 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; + +IQ3LevelMesh.h +Added default value + virtual const quake3::SShader* getShader( const c8* filename, bool fileNameIsValid=true ) = 0; + +ICameraSceneNode.h +Added method parameter (required to set orthogonal together with projection to avoid inconsistencies) + virtual void setProjectionMatrix(const core::matrix4& projection, bool isOrthogonal = false) = 0; +Removed method (use new parameter in setProjectionMatrix) + void setIsOrthogonal( bool orthogonal ) +Constified return value + virtual const core::vector3df& getTarget() const = 0; + virtual const core::vector3df& getUpVector() const = 0; + +matrix4.h +Removed method (use transformPlane) + void transformPlane_new( core::plane3d &plane) const; +Changed qulifications (to enable use under Win32 systems, too) + IRRLICHT_API extern const matrix4 IdentityMatrix; + +SIrrCreationParameters.h +Changed member attribute types + u8 Bits; + const c8* const SDK_version_do_not_use; + +IGUIElement.h +Renamed method from setRelativePosition (to distinguish rather different parameter interpretation) + void setRelativePositionProportional(const core::rect& r) + +irrString.h +Constructors made explicit (use core::stringc(var) in places where var was used before) + explicit string(const double number) + explicit string(int number) + explicit string(unsigned int number) +Added parameter (allows use of method for stringw, and other things) + string& trim(const string & whitespace = " \t\n\r") + +vector2d.h +Changed return value (return *this) + vector2d& set(T nx, T ny) {X=nx; Y=ny; return *this; } + vector2d& set(const vector2d& p) { X=p.X; Y=p.Y; return *this; } +Added default value + vector2d& rotateBy(f64 degrees, const vector2d& center=vector2d()) +Changed parameter type (interpolation factor must not be int) + vector2d getInterpolated(const vector2d& other, f64 d) const + vector2d getInterpolated_quadratic(const vector2d& v2, const vector2d& v3, f64 d) const + vector2d& interpolate(const vector2d& a, const vector2d& b, f64 d) + +Changes for Version 1.5.1 +------------------------- +This release is a pure bugfixes release, with almost no visible API changes. All changes should be backward compatible (as it's just a minor release), but you have to recompile the app due to changes in the virtual method tables. + +dimension2d.h +Fixed a bug in the operator+=, added operator-= and changed comparison to equal() method. + dimension2d& operator-=(const dimension2d& other) + +IrrCompileConfig.h +Added defines to check for the Irrlicht version in the code. + IRRLICHT_VERSION_MAJOR + IRRLICHT_VERSION_MINOR + IRRLICHT_VERSION_REVISION + IRRLICHT_VERSION_SVN // only defined if you're using a version from SVN, i.e. not officially released one + +IrrlichtDevice.h +Added static method isDriverSupported which checks the driver support of the library + static bool isDriverSupported(video::E_DRIVER_TYPE driver) + +irrMath.h +Added iszero specialization for f64 + bool iszero(const f64 a, const f64 tolerance = ROUNDING_ERROR_64) + +irrXML.h +Added deleteCallback flag for cleanup of the ReadCallback. + IrrXMLReader* createIrrXMLReader(IFileReadCallBack* callback, bool deleteCallback = false); + IrrXMLReaderUTF16* createIrrXMLReaderUTF16(IFileReadCallBack* callback, bool deleteCallback = false); + IrrXMLReaderUTF32* createIrrXMLReaderUTF32(IFileReadCallBack* callback, bool deleteCallback = false); + +ISceneNode.h +Added getSceneManager to get the currently used scene manager of the node. + ISceneManager* getSceneManager(void) const + +IVideoDriver.h +Added default values for vType, pType, and iType + virtual void drawVertexPrimitiveList(const void* vertices, u32 vertexCount, const void* indexList, u32 primCount, + E_VERTEX_TYPE vType=EVT_STANDARD, scene::E_PRIMITIVE_TYPE pType=scene::EPT_TRIANGLES, E_INDEX_TYPE iType=EIT_16BIT) +Added method to draw 2d rectangle outline + void draw2DRectangleOutline(const core::recti& pos, SColor color=SColor(255,255,255,255)) + +matrix4.h +Added method to get transposedInverse + CMatrix4 transposedInverse(*this, EM4CONST_INVERSE_TRANSPOSED) + +rect.h +Added typedefs + typedef rect rectf; + typedef rect recti; + +SSharedMeshBuffer.h +Split hardware mapping hint into vertex and index part + E_HARDWARE_MAPPING getHardwareMappingHint_Vertex() const + E_HARDWARE_MAPPING getHardwareMappingHint_Index() const + void setHardwareMappingHint( E_HARDWARE_MAPPING NewMappingHint, E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX ) + +vector2d.h +Fix angle calculation for integer vectors + +Changes for Version 1.5.2 +------------------------- +Even less visible changes have been made in this version. Only the automatic Solaris OS recognition has changed, so make sure you have all things defined properly if you compile for Solaris. And the float parser bugfix is a visible change, though non-interfering for existing code. + +Changes for Version 1.6.0 +------------------------- +This releases has many changes in method signatures. The most obvious ones are signedness changes from s32 to u32. Since many templates won't accept both types, you need to change the types manually in your code. The other major change is from many different types of strings to the new class io::path. These changes should be transparent to the app, unless you need proper overrides in derived classes. +Finally, some deprecated methods have been removed, and some were simply renamed. Just check the API if some methods is not found anymore. + +IMeshSceneNode.h +Added default parameters for identity transformation + IMeshSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1,1,1)) + +path.h +This is a new type, which handles stuff with UTF file systems. +typedef core::string io::path; + +ESceneNodeTypes.h +New scene node identifiers + ESNT_SKY_DOME = MAKE_IRR_ID('s','k','y','d'), + ESNT_Q3SHADER_SCENE_NODE = MAKE_IRR_ID('q','3','s','h'), + ESNT_VOLUME_LIGHT = MAKE_IRR_ID('v','o','l','l'), + +IGUIListBox.h +New methods + virtual void setSelected(const wchar_t *item) = 0; + virtual void setItemHeight( s32 height ) = 0; + virtual void setDrawBackground(bool draw) = 0; + +ITexture.h +New texture generation flag for burnings video driver + //! Allow the Driver to use Non-Power-2-Textures + ETCF_ALLOW_NON_POWER_2 = 0x00000040, +Parameter change (now using path type instead of C-strings) + ITexture(const io::path& name) +Signedness change + virtual const core::dimension2d& getOriginalSize() const = 0; + virtual const core::dimension2d& getSize() const = 0; +New method + virtual bool hasAlpha() const +Parameter change (now using path type instead of stringc) + const io::path& getName() const + +ILightManager.h +This is a new interface for the light manager + class ILightManager : public IReferenceCounted + +IGUIEditBox.h +Signedness change + virtual core::dimension2du getTextDimension() = 0; + +ITriangleSelector.h +New method + virtual const ISceneNode* getSceneNodeForTriangle(u32 triangleIndex) const = 0; + +IMeshManipulator.h +New methods + virtual void makePlanarTextureMapping(scene::IMeshBuffer* meshbuffer, f32 resolution=0.001f) const =0; + virtual void makePlanarTextureMapping(scene::IMeshBuffer* buffer, f32 resolutionS, f32 resolutionT, u8 axis, const core::vector3df& offset) const =0; + virtual IMesh* createMeshWith1TCoords(IMesh* mesh) const = 0; + +SceneParameters.h +Removed parameter + const c8* const DMF_USE_MATERIALS_DIRS = "DMF_MaterialsDir"; +New parameters + const c8* const DMF_IGNORE_MATERIALS_DIRS = "DMF_IgnoreMaterialsDir"; + const c8* const OBJ_LOADER_IGNORE_MATERIAL_FILES = "OBJ_IgnoreMaterialFiles"; + const c8* const B3D_LOADER_IGNORE_MIPMAP_FLAG = "B3D_IgnoreMipmapFlag"; + const c8* const DEBUG_NORMAL_LENGTH = "DEBUG_Normal_Length"; + const c8* const DEBUG_NORMAL_COLOR = "DEBUG_Normal_Color"; + +SViewFrustum.h +Removed method (use getTransform) + void setTransformState( video::E_TRANSFORMATION_STATE state); +New methods + core::matrix4& getTransform( video::E_TRANSFORMATION_STATE state); + const core::matrix4& getTransform( video::E_TRANSFORMATION_STATE state) const; + bool clipLine(core::line3d& line) const; + +IFileList.h +Changed parameters (to io::path) + virtual const io::path& getFileName(u32 index) const = 0; + virtual const io::path& getFullFileName(u32 index) const = 0; +New methods + virtual u32 getFileSize(u32 index) const = 0; + virtual s32 findFile(const io::path& filename, bool isFolder=false) const = 0; + virtual const io::path& getPath() const = 0; + +coreutil.h +New methods + s32 isFileExtension(const io::path& filename, + const io::path& ext0, const io::path& ext1, const io::path& ext2) + bool hasFileExtension(const io::path& filename, + const io::path& ext0, const io::path& ext1 = "", const io::path& ext2 = "") + stringw& cutFilenameExtension ( stringw &dest, const stringw &source ) + core::stringw& deletePathFromFilename(core::stringw& filename) + core::stringc& deletePathFromFilename(core::stringc& filename) + io::path& deletePathFromPath(io::path& filename, s32 pathCount) + s32 isInSameDirectory ( const io::path& path, const io::path& file ) + +IGUIComboBox.h +New methods + virtual u32 getItemData(u32 idx) const = 0; + virtual s32 getIndexForItemData(u32 data ) const = 0; +New parameter + virtual u32 addItem(const wchar_t* text, u32 data = 0) = 0; + +irrArray.h +New allocation scheme member + array() +Use overload instead of different name + s32 binary_search(const T& element) const +New method + void setAllocStrategy ( eAllocStrategy newStrategy = ALLOC_STRATEGY_DOUBLE ) + s32 binary_search_multi(const T& element, s32 &last) + +IrrCompileConfig.h +New compiler flags + #define _IRR_MATERIAL_MAX_TEXTURES_ 4 + //! Define _IRR_D3D_USE_LEGACY_HLSL_COMPILER to enable the old HLSL compiler in recent DX SDKs + #define BURNINGVIDEO_RENDERER_CE + #define IGNORE_DEPRECATED_WARNING + #define _IRR_COMPILE_WITH_PLY_LOADER_ + #define _IRR_COMPILE_WITH_PLY_WRITER_ + #define _IRR_COMPILE_WITH_RGB_LOADER_ + #define __IRR_COMPILE_WITH_ZIP_ARCHIVE_LOADER_ + #define __IRR_COMPILE_WITH_MOUNT_ARCHIVE_LOADER_ + #define __IRR_COMPILE_WITH_PAK_ARCHIVE_LOADER_ + #define __IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_ + //! _IRR_WINDOWS_CE_PLATFORM_ for Windows CE + //! _IRR_COMPILE_WITH_WINDOWS_DEVICE_ for Windows API based device + //! _IRR_COMPILE_WITH_WINDOWS_CE_DEVICE_ for Windows CE API based device + //! _IRR_COMPILE_WITH_OSX_DEVICE_ for Cocoa native windowing on OSX + //! _IRR_COMPILE_WITH_X11_DEVICE_ for Linux X11 based device + //! _IRR_COMPILE_WITH_SDL_DEVICE_ for platform independent SDL framework + //! _IRR_COMPILE_WITH_CONSOLE_DEVICE_ for no windowing system, used as a fallback +Removed compiler flags + //! _IRR_USE_SDL_DEVICE_ for platform independent SDL framework + //! _IRR_USE_WINDOWS_DEVICE_ for Windows API based device + //! _IRR_USE_WINDOWS_CE_DEVICE_ for Windows CE API based device + //! _IRR_USE_LINUX_DEVICE_ for X11 based device + //! _IRR_USE_OSX_DEVICE_ for Cocoa native windowing on OSX +Old compilers rejected + # error "Only Microsoft Visual Studio 7.0 and later are supported." +Force symbol export in shared libraries built with gcc. + #define IRRLICHT_API __attribute__ ((visibility("default"))) + +IGUIFileOpenDialog.h +New method + virtual const io::path& getDirectoryName() = 0; + +EDeviceTypes.h +New enum for multi-device support + enum E_DEVICE_TYPE + +IMeshLoader.h +Changed parameter to use io::path instead of C strings + virtual bool isALoadableFileExtension(const io::path& filename) const = 0; + +IAnimatedMeshSceneNode.h +Changed return value to pointer type + virtual const SMD3QuaternionTag* getMD3TagTransformation( const core::stringc & tagname) = 0; + +ISceneManager.h +New enum values and numbering + enum E_SCENE_NODE_RENDER_PASS + ESNRP_NONE =0, + ESNRP_TRANSPARENT =16, + ESNRP_TRANSPARENT_EFFECT =32, +Changed parameter to use io::path instead of C strings + virtual IAnimatedMesh* getMesh(const io::path& filename) = 0; +New methods + virtual io::IFileSystem* getFileSystem() = 0; + virtual ITriangleSelector* createTriangleSelector(IAnimatedMeshSceneNode* node) = 0; + virtual const c8* getAnimatorTypeName(ESCENE_NODE_ANIMATOR_TYPE type) = 0; + virtual ISkinnedMesh* createSkinnedMesh() = 0; + virtual void setLightManager(ILightManager* lightManager) = 0; + virtual const IGeometryCreator* getGeometryCreator(void) const = 0; + virtual bool isCulled(const ISceneNode* node) const =0; +Changed return type to IMeshSceneNode + virtual IMeshSceneNode* addOctTreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent=0, + s32 id=-1, s32 minimalPolysPerNode=512, bool alsoAddIfMeshPointerZero=false) = 0; + virtual IMeshSceneNode* addOctTreeSceneNode(IMesh* mesh, ISceneNode* parent=0, + s32 id=-1, s32 minimalPolysPerNode=256, bool alsoAddIfMeshPointerZero=false) = 0; + virtual IMeshSceneNode* addQuake3SceneNode(IMeshBuffer* meshBuffer, const quake3::IShader * shader, + ISceneNode* parent=0, s32 id=-1) = 0; +New parameter invertMouse + virtual ICameraSceneNode* addCameraSceneNodeFPS(ISceneNode* parent = 0, + f32 rotateSpeed = 100.0f, f32 moveSpeed = 0.5f, s32 id=-1, + SKeyMap* keyMapArray=0, s32 keyMapSize=0, bool noVerticalMovement=false, + f32 jumpSpeed = 0.f, bool invertMouse=false) = 0; +New parameter radius + virtual ISceneNode* addSkyDomeSceneNode(video::ITexture* texture, + u32 horiRes=16, u32 vertRes=8, + f32 texturePercentage=0.9, f32 spherePercentage=2.0,f32 radius = 1000.f, + ISceneNode* parent=0, s32 id=-1) = 0; +Changed to use io::path instead of C strings + virtual ITerrainSceneNode* addTerrainSceneNode( + const io::path& heightMapFileName, + ISceneNode* parent=0, s32 id=-1, + virtual IAnimatedMesh* addHillPlaneMesh(const io::path& 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; + virtual IAnimatedMesh* addArrowMesh(const io::path& name, + video::SColor vtxColor0=0xFFFFFFFF, + video::SColor vtxColor1=0xFFFFFFFF, + u32 tesselationCylinder=4, u32 tesselationCone=8, + virtual IAnimatedMesh* addSphereMesh(const io::path& name, + f32 radius=5.f, u32 polyCountX = 16, + u32 polyCountY = 16) = 0; + virtual bool saveScene(const io::path& filename, ISceneUserDataSerializer* userDataSerializer=0) = 0; + virtual bool loadScene(const io::path& filename, ISceneUserDataSerializer* userDataSerializer=0) = 0; +Changed to use io::path instead of C strings and signedness change + virtual IAnimatedMesh* addTerrainMesh(const io::path& 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; +New method + virtual IAnimatedMesh* addVolumeLightMesh(const io::path& name, + const u32 SubdivideU = 32, const u32 SubdivideV = 32, + const video::SColor FootColor = video::SColor(51, 0, 230, 180), + const video::SColor TailColor = video::SColor(0, 0, 0, 0)) = 0; +Constification of method + virtual ICameraSceneNode* getActiveCamera() const =0; +New parameters + 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), + f32 startPosition = 0.f, + f32 radiusEllipsoid = 0.f) = 0; + virtual ISceneNodeAnimator* createFlyStraightAnimator(const core::vector3df& startPoint, + const core::vector3df& endPoint, u32 timeForWay, bool loop=false, bool pingpong = false) = 0; + +ISceneNodeAnimatorCollisionResponse.h +New interface + class ICollisionCallback : public virtual IReferenceCounted +New methods for ISceneNodeAnimatorCollisionResponse + virtual void setAnimateTarget ( bool enable ) = 0; + virtual bool getAnimateTarget () const = 0; + virtual void setTargetNode(ISceneNode * node) = 0; + virtual ISceneNode* getTargetNode(void) const = 0; + virtual bool collisionOccurred() const = 0; + virtual const core::vector3df & getCollisionPoint() const = 0; + virtual const core::triangle3df & getCollisionTriangle() const = 0; + virtual const core::vector3df & getCollisionResultPosition(void) const = 0; + virtual const ISceneNode* getCollisionNode(void) const = 0; + virtual void setCollisionCallback(ICollisionCallback* callback) = 0; + +ILightSceneNode.h +New methods + virtual void setVisible(bool isVisible) = 0; + +EMeshWriterEnums.h +New enums + EMWT_PLY = MAKE_IRR_ID('p','l','y',0) + EMWF_WRITE_BINARY = 0x4 + +ISceneNodeAnimator.h +New method + virtual bool hasFinished(void) const + +SMaterialLayer.h +Changed types + u8 TextureWrap; + bool BilinearFilter:1; + bool TrilinearFilter:1; + u8 AnisotropicFilter; +New member + s8 LODBias; + +IVideoModeList.h +Signedness change + virtual core::dimension2d getVideoModeResolution(s32 modeNumber) const = 0; + virtual core::dimension2d getVideoModeResolution(const core::dimension2d& minSize, const core::dimension2d& maxSize) const = 0; + virtual const core::dimension2d& getDesktopResolution() const = 0; + +EMaterialFlags.h +Enum values changed (all renumbered) + +ISkinnedMesh.h +Renamed methods (was create... before, but these methods grab the things they create) + virtual SSkinMeshBuffer* addMeshBuffer() = 0; + virtual SJoint* addJoint(SJoint *parent=0) = 0; + virtual SWeight* addWeight(SJoint *joint) = 0; + virtual SPositionKey* addPositionKey(SJoint *joint) = 0; + virtual SScaleKey* addScaleKey(SJoint *joint) = 0; + virtual SRotationKey* addRotationKey(SJoint *joint) = 0; + +SLight.h +Type change + bool CastShadows:1; + +IGUITreeView.h +New element +// written by Reinhard Ostermeier, reinhard@nospam.r-ostermeier.de + class IGUITreeView : public IGUIElement + +IAnimatedMeshMD3.h +Renamed class (from SMD3QuaterionTag) + struct SMD3QuaternionTag + +IGUIEnvironment.h +New methods + virtual IGUIImageList* createImageList( video::ITexture* texture, + core::dimension2d imageSize, bool useAlphaChannel ) = 0; + virtual IGUITreeView* addTreeView(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1, bool drawBackground=false, + bool scrollBarVertical = true, bool scrollBarHorizontal = false) = 0; +Changed parameters to use io::path (instead of C strings) + virtual IGUIFont* getFont(const io::path& filename) = 0; + virtual IGUISpriteBank* getSpriteBank(const io::path& filename) = 0; + virtual IGUISpriteBank* addEmptySpriteBank(const io::path& name) = 0; + virtual bool saveGUI(const io::path& filename, IGUIElement* start=0) = 0; + virtual bool loadGUI(const io::path& filename, IGUIElement* parent=0) = 0; +New parameter "border" + virtual IGUISpinBox* addSpinBox(const wchar_t* text, const core::rect& rectangle, + bool border=true,IGUIElement* parent=0, s32 id=-1) = 0; + +IQ3Shader.h +Made non-const + static core::stringc irrEmptyStringc(""); +New enum values + enum eQ3MeshIndex + E_Q3_MESH_FOG, + E_Q3_MESH_UNRESOLVED, + +IGeometryCreator.h +New interface + class IGeometryCreator : public IReferenceCounted + +IFileArchive.h +New interfaces + class IFileArchive : public virtual IReferenceCounted + class IArchiveLoader : public virtual IReferenceCounted + +IFileSystem.h +Changed parameters to use io::path (instead of C strings/stringc) + virtual IReadFile* createAndOpenFile(const path& filename) =0; + virtual IReadFile* createMemoryReadFile(void* memory, s32 len, const path& fileName, bool deleteMemoryWhenDropped=false) =0; + virtual IWriteFile* createAndWriteFile(const path& filename, bool append=false) =0; + virtual const path& getWorkingDirectory() =0; + virtual bool changeWorkingDirectoryTo(const path& newDirectory) =0; + virtual path getAbsolutePath(const path& filename) const =0; + virtual path getFileDir(const path& filename) const =0; + virtual path getFileBasename(const path& filename, bool keepExtension=true) const =0; + virtual bool existFile(const path& filename) const =0; + virtual IXMLReader* createXMLReader(const path& filename) =0; + virtual IXMLReaderUTF8* createXMLReaderUTF8(const path& filename) =0; + virtual IXMLWriter* createXMLWriter(const path& filename) =0; +New methods + virtual IReadFile* createLimitReadFile(const path& fileName, + IReadFile* alreadyOpenedFile, long pos, long areaSize) =0; + virtual IWriteFile* createMemoryWriteFile(void* memory, s32 len, const path& fileName, bool deleteMemoryWhenDropped=false) =0; + virtual bool addFileArchive(const path& filename, bool ignoreCase=true, bool ignorePaths=true, + E_FILE_ARCHIVE_TYPE archiveType=EFAT_UNKNOWN) =0; + virtual void addArchiveLoader(IArchiveLoader* loader) =0; + virtual u32 getFileArchiveCount() const =0; + virtual bool removeFileArchive(u32 index) =0; + virtual bool removeFileArchive(const path& filename) =0; + virtual bool moveFileArchive(u32 sourceIndex, s32 relative) =0; + virtual IFileArchive* getFileArchive(u32 index) =0; + virtual path& flattenFilename(path& directory, const path& root="/") const =0; + virtual EFileSystemType setFileListSystem(EFileSystemType listType) =0; +Deprecate methods + virtual bool addZipFileArchive(const c8* filename, bool ignoreCase=true, bool ignorePaths=true) + virtual bool addFolderFileArchive(const c8* filename, bool ignoreCase=true, bool ignorePaths=true) + virtual bool addPakFileArchive(const c8* filename, bool ignoreCase=true, bool ignorePaths=true) +Constification of method + virtual IFileList* createFileList() =0; + +IrrlichtDevice.h +Renamed method (from setResizeAble) + virtual void setResizable(bool resize=false) = 0; +New methods + virtual void minimizeWindow() =0; + virtual void maximizeWindow() =0; + virtual void restoreWindow() =0; + virtual bool setGammaRamp(f32 red, f32 green, f32 blue, + f32 relativebrightness, f32 relativecontrast) =0; + virtual bool getGammaRamp(f32 &red, f32 &green, f32 &blue, + f32 &brightness, f32 &contrast) =0; + virtual E_DEVICE_TYPE getType() const = 0; + +irrMath.h +Renamed from ROUNDING_ERROR_32 + const f32 ROUNDING_ERROR_f32 = 0.000001f; +Renamed from ROUNDING_ERROR_64 + const f64 ROUNDING_ERROR_f64 = 0.00000001; +New constant + const s32 ROUNDING_ERROR_S32 = 1; +New methods + bool isnotzero(const f32 a, const f32 tolerance = ROUNDING_ERROR_f32) + u16 if_c_a_else_b ( const s16 condition, const u16 a, const u16 b ) + f32 squareroot(const f32 f) + f64 squareroot(const f64 f) + s32 squareroot(const s32 f) + f64 reciprocal_squareroot(const f64 x) + s32 reciprocal_squareroot(const s32 x) + f64 reciprocal ( const f64 f ) + +IGPUProgrammingServices.h +Changed parameters to use io::path + virtual s32 addHighLevelShaderMaterialFromFiles( + const io::path& vertexShaderProgramFileName, + const c8* vertexShaderEntryPointName = "main", + E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1, + const io::path& pixelShaderProgramFileName = "", + const c8* pixelShaderEntryPointName = "main", + E_PIXEL_SHADER_TYPE psCompileTarget = EPST_PS_1_1, + IShaderConstantSetCallBack* callback = 0, + virtual s32 addShaderMaterialFromFiles(const io::path& vertexShaderProgramFileName, + const io::path& pixelShaderProgramFileName, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData = 0) = 0; + +ISceneNode.h +New method + virtual bool isTrulyVisible() const + +IEventReceiver.h +New enum values + EMIE_MOUSE_DOUBLE_CLICK, + EMIE_MOUSE_TRIPLE_CLICK, + EGET_DIRECTORY_SELECTED, + EGET_EDITBOX_CHANGED, + EGET_EDITBOX_MARKING_CHANGED, + EGET_TREEVIEW_NODE_DESELECT, + EGET_TREEVIEW_NODE_SELECT, + EGET_TREEVIEW_NODE_EXPAND, + EGET_TREEVIEW_NODE_COLLAPS, + EGET_COUNT +New enum + enum E_MOUSE_BUTTON_STATE_MASK +New members + bool Shift:1; + bool Control:1; + u32 ButtonStates; +New methods + bool isLeftPressed() const { return 0 != ( ButtonStates & EMBSM_LEFT ); } + bool isRightPressed() const { return 0 != ( ButtonStates & EMBSM_RIGHT ); } + bool isMiddlePressed() const { return 0 != ( ButtonStates & EMBSM_MIDDLE ); } +Types changed + bool PressedDown:1; + bool Shift:1; + bool Control:1; + +IGUISpriteBank.h +New method + virtual void draw2DSpriteBatch(const core::array& indices, const core::array& pos, + const core::rect* clip=0, + const video::SColor& color= video::SColor(255,255,255,255), + u32 starttime=0, u32 currenttime=0, + bool loop=true, bool center=false) = 0; + +SMaterial.h +New enums + enum E_COMPARISON_FUNC + enum E_COLOR_PLANE + enum E_ALPHA_SOURCE + enum E_ANTI_ALIASING_MODE + enum E_COLOR_MATERIAL +New parameters + inline f32 pack_texureBlendFunc ( const E_BLEND_FACTOR srcFact, const E_BLEND_FACTOR dstFact, const E_MODULATE_FUNC modulate=EMFN_MODULATE_1X, const u32 alphaSource=EAS_TEXTURE ) + inline void unpack_texureBlendFunc ( E_BLEND_FACTOR &srcFact, E_BLEND_FACTOR &dstFact, + E_MODULATE_FUNC &modulo, u32& alphaSource, const f32 param ) +New methods + inline bool textureBlendFunc_hasAlpha ( const E_BLEND_FACTOR factor ) +Default value set elsewhere now (see IrrCompileConfig.h) + const u32 MATERIAL_MAX_TEXTURES = _IRR_MATERIAL_MAX_TEXTURES_; +Types changed + u8 ZBuffer; + bool Wireframe:1; + bool PointCloud:1; + bool GouraudShading:1; + bool Lighting:1; + bool ZWriteEnable:1; + bool BackfaceCulling:1; + bool FrontfaceCulling:1; + bool FogEnable:1; + bool NormalizeNormals:1; +New members + u8 AntiAliasing; + u8 ColorMask:4; + u8 ColorMaterial:3; +New constant + IRRLICHT_API extern SMaterial IdentityMaterial; + +IGUISkin.h +New enum values + EGDS_TITLEBARTEXT_DISTANCE_X, + EGDS_TITLEBARTEXT_DISTANCE_Y, + +quaternion.h +New parameters + void getMatrix( matrix4 &dest, const vector3df &translation ) const; +New method + void getMatrixCenter( matrix4 &dest, const vector3df ¢er, const vector3df &translation ) const; + +ISceneNodeAnimatorCameraFPS.h +New method + virtual void setInvertMouse(bool invert) = 0; + +IImage.h +New enum values + /** Floating Point formats. The following formats may only be used for render target textures. */ + ECF_R16F, + ECF_G16R16F, + ECF_A16B16G16R16F, + ECF_R32F, + ECF_G32R32F, + ECF_A32B32G32R32F, + ECF_UNKNOWN +Signedness change + virtual const core::dimension2d& getDimension() const = 0; + virtual void copyToScaling(void* target, u32 width, u32 height, ECOLOR_FORMAT format=ECF_A8R8G8B8, u32 pitch=0) =0; +New parameter + virtual void setPixel(u32 x, u32 y, const SColor &color, bool blend = false ) = 0; +New method + virtual void copyToScalingBoxFilter(IImage* target, s32 bias = 0, bool blend = false) = 0; + static u32 getBitsPerPixelFromFormat(const ECOLOR_FORMAT format) + static bool isRenderTargetOnlyFormat(const ECOLOR_FORMAT format) + +IVideoDriver.h +New enum values (only existing if _IRR_MATERIAL_MAX_TEXTURES_ large enough) + ETS_TEXTURE_4 + ETS_TEXTURE_5 + ETS_TEXTURE_6 + ETS_TEXTURE_7 +New enums + enum E_RENDER_TARGET + enum E_FOG_TYPE +New type + struct SOverrideMaterial +New methods + virtual u32 getImageLoaderCount() const = 0; + virtual IImageLoader* getImageLoader(u32 n) = 0; + virtual u32 getImageWriterCount() const = 0; + virtual IImageWriter* getImageWriter(u32 n) = 0; + virtual bool setRenderTarget(E_RENDER_TARGET target, bool clearTarget=true, + bool clearZBuffer=true, SColor color=video::SColor(0,0,0,0)) =0; + virtual void draw2DVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primCount, + E_VERTEX_TYPE vType=EVT_STANDARD, + scene::E_PRIMITIVE_TYPE pType=scene::EPT_TRIANGLES, + E_INDEX_TYPE iType=EIT_16BIT) =0; + virtual void draw2DImageBatch(const video::ITexture* texture, + const core::array >& positions, + const core::array >& sourceRects, + const core::rect* clipRect=0, + SColor color=SColor(255,255,255,255), + bool useAlphaChannelOfTexture=false) =0; + virtual void turnLightOn(s32 lightIndex, bool turnOn) =0; + virtual bool writeImageToFile(IImage* image, io::IWriteFile* file, u32 param =0) =0; + virtual IImage* createImage(ITexture* texture, + const core::position2d& pos, const core::dimension2d& size) =0; + virtual void setMinHardwareBufferVertexCount(u32 count) =0; + virtual SOverrideMaterial& getOverrideMaterial() =0; +Changed parameters to use io::path + virtual ITexture* getTexture(const io::path& filename) = 0; + virtual void renameTexture(ITexture* texture, const io::path& newName) = 0; + virtual ITexture* addTexture(const io::path& name, IImage* image) = 0; + virtual IImage* createImageFromFile(const io::path& filename) = 0; + virtual bool writeImageToFile(IImage* image, const io::path& filename, u32 param = 0) = 0; + virtual video::ITexture* findTexture(const io::path& filename) = 0; +Changed signedness + virtual ITexture* addTexture(const core::dimension2d& size, + const io::path& name, ECOLOR_FORMAT format = ECF_A8R8G8B8) = 0; + virtual const core::dimension2d& getScreenSize() const =0; + virtual const core::dimension2d& getCurrentRenderTargetSize() const =0; + virtual IImage* createImageFromData(ECOLOR_FORMAT format, + const core::dimension2d& size, void *data, + bool ownForeignMemory=false, + bool deleteMemory = true) =0; + virtual IImage* createImage(ECOLOR_FORMAT format, const core::dimension2d& size) =0; + virtual IImage* createImage(IImage* imageToCopy, + const core::position2d& pos, + const core::dimension2d& size) =0; + virtual void OnResize(const core::dimension2d& size) =0; +Changed signedness and usage of io::path + virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, + const io::path& name = "rt", const ECOLOR_FORMAT format = ECF_UNKNOWN) =0; +Removed deprecated method + virtual ITexture* createRenderTargetTexture(const core::dimension2d& size, + const c8* name=0) =0; +New parameter + virtual void makeColorKeyTexture(video::ITexture* texture, + video::SColor color, bool zeroTexels = false) const =0; + virtual void makeColorKeyTexture(video::ITexture* texture, + core::position2d colorKeyPixelPos, bool zeroTexels = false) const =0; +Changed parameters + virtual void setFog(SColor color=SColor(0,255,255,255), + E_FOG_TYPE fogType=EFT_FOG_LINEAR, + f32 start=50.0f, f32 end=100.0f, f32 density=0.01f, + bool pixelFog=false, bool rangeFog=false) =0; +Changed return types + virtual s32 addDynamicLight(const SLight& light) =0; + +EDriverFeatures.h +New enum values + EVDF_ALPHA_TO_COVERAGE, + EVDF_COLOR_MASK, + +IGUIScrollBar.h +New methods + virtual void setMin(s32 max) = 0; + virtual s32 getMin() const = 0; + +IQ3LevelMesh.h +Removed method + virtual void releaseMesh(s32 index) = 0; +Made return value non-const + virtual quake3::tQ3EntityList& getEntityList() = 0; + +ISceneCollisionManager.h +New parameter + virtual bool getCollisionPoint(const core::line3d& ray, + ITriangleSelector* selector, core::vector3df& outCollisionPoint, + core::triangle3df& outTriangle, const ISceneNode*& outNode) =0; + virtual core::vector3df getCollisionResultPosition( + ITriangleSelector* selector, + 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 = 0.0005f, + const core::vector3df& gravityDirectionAndSpeed = core::vector3df(0.0f, 0.0f, 0.0f)) = 0; +Made parameter const& + virtual core::line3d getRayFromScreenCoordinates( + const core::position2d & pos, ICameraSceneNode* camera = 0) = 0; + virtual core::position2d getScreenCoordinatesFrom3DPosition( + const core::vector3df & pos, ICameraSceneNode* camera=0) = 0; +Made parameter const& and added new parameter + virtual ISceneNode* getSceneNodeFromScreenCoordinatesBB(const core::position2d& pos, + s32 idBitMask=0, bool bNoDebugObjects=false, ISceneNode* root=0) =0; + virtual ISceneNode* getSceneNodeFromRayBB(const core::line3d& ray, + s32 idBitMask=0, bool bNoDebugObjects=false, ISceneNode* root=0) =0; +New method + virtual ISceneNode* getSceneNodeAndCollisionPointFromRay( + core::line3df ray, core::vector3df & outCollisionPoint, + core::triangle3df & outTriangle, s32 idBitMask = 0, + ISceneNode * collisionRootNode = 0, bool noDebugObjects = false) = 0; + +irrlicht.h +Changed interface of method (qualifiers and signedness) + extern "C" 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)), + u32 bits = 16, + bool fullscreen = false, + bool stencilbuffer = false, + bool vsync = false, + IEventReceiver* receiver = 0); + extern "C" IRRLICHT_API IrrlichtDevice* IRRCALLCONV createDeviceEx( + const SIrrlichtCreationParameters& parameters); + +IImageLoader.h +Changed parameters to use io::path + virtual bool isALoadableFileExtension(const io::path& filename) const = 0; + +IGUIWindow.h +New methods + virtual bool isDraggable() const = 0; + virtual void setDraggable(bool draggable) = 0; + virtual void setDrawBackground(bool draw) = 0; + virtual bool getDrawBackground() const = 0; + virtual void setDrawTitlebar(bool draw) = 0; + virtual bool getDrawTitlebar() const = 0; + +ICameraSceneNode.h +New methods + virtual void setViewMatrixAffector(const core::matrix4& affector) =0; + virtual const core::matrix4& getViewMatrixAffector() const =0; + +EGUIElementTypes.h +New enum value + EGUIET_TREE_VIEW, + +IImageWriter.h +Changed parameters to use io::path + virtual bool isAWriteableFileExtension(const io::path& filename) const = 0; + +SIrrCreationParameters.h +Added members + E_DEVICE_TYPE DeviceType; + bool Doublebuffer; + bool Stereobuffer; +Changed signedness + core::dimension2d WindowSize; +Changed type (from bool) + u8 AntiAlias; + +matrix4.h +New methods + bool isOrthogonal() const; + CMatrix4& buildRotateFromTo(const core::vector3df& from, const core::vector3df& to); + void setRotationCenter(const core::vector3df& center, const core::vector3df& translate); + void buildAxisAlignedBillboard( const core::vector3df& camPos, + const core::vector3df& center, const core::vector3df& translation, + const core::vector3df& axis, const core::vector3df& from); + +IWriteFile.h +Changed parameters to use io::path + virtual const path& getFileName() const = 0; + +IGUITable.h +New methods + virtual void setSelected( s32 index ) = 0; +Changed type (from wide c string) + virtual void setCellText(u32 rowIndex, u32 columnIndex, const core::stringw& text) = 0; + virtual void setCellText(u32 rowIndex, u32 columnIndex, const core::stringw& text, video::SColor color) = 0; + +SKeyMap.h +New enum value + EKA_CROUCH, + +IGUIFont.h +Changed type (from wide c string) + virtual void draw(const core::stringw& text, const core::rect& position, + video::SColor color, bool hcenter=false, bool vcenter=false, + const core::rect* clip=0) = 0; +Changed signedness + virtual core::dimension2d getDimension(const wchar_t* text) const = 0; +New method + virtual void setInvisibleCharacters( const wchar_t *s ) = 0; + +IMeshCache.h +Changed parameters to use io::path + virtual void addMesh(const io::path& filename, IAnimatedMesh* mesh) = 0; + virtual IAnimatedMesh* getMeshByFilename(const io::path& filename) = 0; + virtual const io::path& getMeshFilename(u32 index) const = 0; + virtual const io::path& getMeshFilename(const IAnimatedMesh* const mesh) const = 0; + virtual const io::path& getMeshFilename(const IMesh* const mesh) const = 0; + virtual bool setMeshFilename(u32 index, const io::path& filename) = 0; + virtual bool setMeshFilename(const IAnimatedMesh* const mesh, const io::path& filename) = 0; + virtual bool setMeshFilename(const IMesh* const mesh, const io::path& filename) = 0; + virtual bool isMeshLoaded(const io::path& filename) = 0; + +IGUIButton.h +Added default value + virtual void setImage(video::ITexture* image=0) = 0; + virtual void setPressedImage(video::ITexture* image=0) = 0; + virtual void setSpriteBank(IGUISpriteBank* bank=0) = 0; + virtual void setIsPushButton(bool isPushButton=true) = 0; + virtual void setPressed(bool pressed=true) = 0; + virtual void setUseAlphaChannel(bool useAlphaChannel=true) = 0; + virtual void setDrawBorder(bool border=true) = 0; +New methods + virtual void setScaleImage(bool scaleImage=true) = 0; + virtual bool isScalingImage() const = 0; + +position2d.h +Replaced by vector2d + +IGUIImageList.h +New interface + class IGUIImageList : public virtual IReferenceCounted + +rect.h +Added second template parameter to allow mismatched signedness + template + rect(const position2d& pos, const dimension2d& size) + +IParticleEmitter.h +Removed wrong overrides + virtual void serializeAttributes(io::IAttributes* out, + io::SAttributeReadWriteOptions* options=0) const {} + virtual s32 deserializeAttributes(s32 startIndex, io::IAttributes* in, + io::SAttributeReadWriteOptions* options=0) { return 0; } + +IOSOperator.h +Return const string + virtual const c8* getTextFromClipboard() const = 0; + +IGUIElement.h +Signedness change + void setMaxSize(core::dimension2du size) + void setMinSize(core::dimension2du size) + +IReadFile.h +Changed parameters to use io::path + virtual const io::path& getFileName() const = 0; + IReadFile* createReadFile(const io::path& fileName); + IReadFile* createLimitReadFile(const io::path& fileName, IReadFile* alreadyOpenedFile, long pos, long areaSize); + IReadFile* createMemoryReadFile(void* memory, long size, const io::path& fileName, bool deleteMemoryWhenDropped); + +IGUITabControl.h +New methods + virtual void setTabMaxWidth(s32 width ) = 0; + virtual s32 getTabMaxWidth() const = 0; + +IParticleAffector.h +Removed wrong overrides + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const {} + virtual s32 deserializeAttributes(s32 startIndex, io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) { return 0; } + +ILogger.h +New method + virtual void log(const c8* text, const wchar_t* hint, ELOG_LEVEL ll=ELL_INFORMATION) = 0; + +vector2d.h +New methods + vector2d(const dimension2d& other) : X(other.Width), Y(other.Height) {} + vector2d& operator=(const dimension2d& other) { X = other.Width; Y = other.Height; return *this; } + vector2d operator+(const dimension2d& other) const { return vector2d(X + other.Width, Y + other.Height); } + vector2d& operator+=(const dimension2d& other) { X += other.Width; Y += other.Height; return *this; } + vector2d operator-(const dimension2d& other) const { return vector2d(X - other.Width, Y - other.Height); } + vector2d& operator-=(const dimension2d& other) { X -= other.Width; Y -= other.Height; return *this; } + // 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; } + +Changes for Version 1.6.1 +------------------------- +This is again just a bugfix release. However, some minor API changes have happened. The most important one is the removal of lins anti-aliasing from SMaterial's default values. Please add that line smoothing flag to the materials you want to be smoothed. But note that this may lead to drastically reduced performance, if no multi-sampling is active. + +IFileList.h +new methods + virtual u32 getID(u32 index) const = 0; + virtual u32 addItem(const io::path& fullPath, u32 size, bool isDirectory, u32 id=0) = 0; + virtual void sort() = 0; + +IrrCompileConfig.h +Removed auto recognition of Solaris OS, please define the setting on your own if you need it + _IRR_SOLARIS_PLATFORM_ + +IGUITreeView.h +removed methods (use automatically generated versions) + IGUITreeViewNode() {} + virtual ~IGUITreeViewNode() {} + virtual ~IGUITreeView() {} + +IFileSystem.h +new method + virtual IFileList* createEmptyFileList(const io::path& path, bool ignoreCase, bool ignorePaths) =0; + +SMaterial.h +Removed default value (EAAM_LINE_SMOOTH from AntiAliasing) + ZBuffer(ECFN_LESSEQUAL), AntiAliasing(EAAM_SIMPLE), ColorMask(ECP_ALL), + +IGUISkin.h +new enum value + EGST_COUNT + + +Changes for Version 1.7 +------------------------- +This version has less API-breaking changes than the previous major changes. It has many new features, which simply add methods. All those changes, which affect old methods or structures are mostly put in parallel to the old (and now deprecated) methods. Only a few things are changed without backward compatibility: The texture wrap mode is split into separate U and V modes. The beginScene void* parameter has been replaced by an SExposedVideoData. Simply wrap the pointer with this struct and it should work again. +EMIE_LMOUSE_DOUBLE_CLICK replaces EMIE_MOUSE_DOUBLE_CLICK and EMIE_LMOUSE_TRIPLE_CLICK replaces EMIE_MOUSE_TRIPLE_CLICK +Elements used in the array container need now to have an operator= +Here comes the full list: + +path.h +New type +struct SNamedPath + +triangle3d.h +New method +bool isTotalOutsideBox(const aabbox3d& box) const + +ESceneNodeTypes.h +Changed enum value (from octt) +ESNT_OCTREE = MAKE_IRR_ID('o','c','t','r'), + +SColor.h +New method +f32 getLightness() const + +driverChoice.h +New method +static irr::video::E_DRIVER_TYPE driverChoiceConsole(bool allDrivers=true) + +ITexture.h +New parameter +virtual void regenerateMipMapLevels(void* mipmapData=0) = 0; +Changed return value (from io:path) +const io::SNamedPath& getName() const { return NamedPath; } + +SceneParameters.h +New scene parameters +const c8* const OBJ_TEXTURE_PATH = "OBJ_TexturePath"; +const c8* const B3D_TEXTURE_PATH = "B3D_TexturePath"; + +IMeshManipulator.h +Not virtual anymore +void setVertexColorAlpha(IMesh* mesh, s32 alpha) const +void setVertexColors(IMesh* mesh, video::SColor color) const +void scale(IMeshBuffer* buffer, const core::vector3df& factor) const +void scaleMesh(IMesh* mesh, const core::vector3df& factor) const +void scaleTCoords(scene::IMesh* mesh, const core::vector2df& factor, u32 level=1) const +void scaleTCoords(scene::IMeshBuffer* buffer, const core::vector2df& factor, u32 level=1) const +void transform(IMesh* mesh, const core::matrix4& m) const +void transform(IMeshBuffer* buffer, const core::matrix4& m) const +New method +template +bool apply(const Functor& func, IMeshBuffer* buffer, bool boundingBoxUpdate=false) const +template +bool apply(const Functor& func, IMesh* mesh, bool boundingBoxUpdate=false) const +virtual void recalculateTangents(IMesh* mesh, bool recalculateNormals=false, + bool smooth=false, bool angleWeighted=false) const=0; +void scale(IMesh* mesh, const core::vector3df& factor) const +New parameter +virtual IMesh* createMeshWithTangents(IMesh* mesh, bool recalculateNormals=false, bool smooth=false, bool angleWeighted=false, bool recalculateTangents=true) const = 0; + +coreutil.h +Changed return type and parameters (from stringc/w) +inline io::path& cutFilenameExtension ( io::path &dest, const io::path &source ) +inline io::path& getFileNameExtension ( io::path &dest, const io::path &source ) +inline io::path& deletePathFromFilename(io::path& filename) +Fixed behavior +inline io::path& deletePathFromPath(io::path& filename, s32 pathCount) + +ICursorControl.h +Return const-ref +virtual const core::position2d& getPosition() = 0; + +irrArray.h +Fixed allocator template usage +array(const array& other) : data(0) +const array& operator=(const array& other) +bool operator == (const array& other) const +bool operator != (const array& other) const +Changed behavior for free_when_destroyed +void set_pointer(T* newPointer, u32 size, bool _is_sorted=false, bool _free_when_destroyed=true) +void set_free_when_destroyed(bool f) + +irrMap.h +Renamed method (from isEmpty) +bool empty() const +New method +void swap(map& other) + +IAnimatedMesh.h +virtual f32 getAnimationSpeed() const =0; + +IAttributes.h +Made parameters const-ref +virtual void addArray(const c8* attributeName, const core::array& value) = 0; +virtual void setAttribute(const c8* attributeName, const core::array& value) = 0; +virtual void setAttribute(s32 index, const core::array& value) = 0; + +ISceneManager.h +Renamed method (from OctTree) +virtual IMeshSceneNode* addOctreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent=0, + s32 id=-1, s32 minimalPolysPerNode=512, bool alsoAddIfMeshPointerZero=false) = 0; +virtual IMeshSceneNode* addOctreeSceneNode(IMesh* mesh, ISceneNode* parent=0, + s32 id=-1, s32 minimalPolysPerNode=256, bool alsoAddIfMeshPointerZero=false) = 0; +virtual ITriangleSelector* createOctreeTriangleSelector(IMesh* mesh, + ISceneNode* node, s32 minimalPolysPerNode=32) = 0; +New parameter (makeActive) +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, bool makeActive=true) = 0; +virtual ICameraSceneNode* addCameraSceneNodeMaya(ISceneNode* parent = 0, + f32 rotateSpeed = -1500.0f, f32 zoomSpeed = 200.0f, + f32 translationSpeed = 1500.0f, s32 id=-1, + bool makeActive=true) = 0; +virtual ICameraSceneNode* addCameraSceneNodeFPS(ISceneNode* parent = 0, + f32 rotateSpeed = 100.0f, f32 moveSpeed = 0.5f, s32 id=-1, + SKeyMap* keyMapArray=0, s32 keyMapSize=0, bool noVerticalMovement=false, + f32 jumpSpeed = 0.f, bool invertMouse=false, + bool makeActive=true) = 0; +Make parameter const +virtual IMeshSceneNode* addQuake3SceneNode(const IMeshBuffer* meshBuffer, const quake3::IShader * shader, + ISceneNode* parent=0, s32 id=-1) = 0; +New parameter (loop, pingpong) +virtual ISceneNodeAnimator* createFollowSplineAnimator(s32 startTime, + const core::array< core::vector3df >& points, + f32 speed = 1.0f, f32 tightness = 0.5f, bool loop=true, bool pingpong=false) = 0; + +SMaterialLayer.h +New clamp modes +ETC_MIRROR_CLAMP, ETC_MIRROR_CLAMP_TO_EDGE, ETC_MIRROR_CLAMP_TO_BORDER +New material layer modes (replaces TextureWrap) +TextureWrapU(ETC_REPEAT), TextureWrapV(ETC_REPEAT) + +vector3d.h +Use tolerance to compare, changed order function to total order +bool operator<=(const vector3d&other) const +bool operator>=(const vector3d&other) const +bool operator<(const vector3d&other) const +bool operator>(const vector3d&other) const +New method +vector3d getSphericalCoordinateAngles() +New method specializations +template <> +inline vector3d vector3d::operator /(s32 val) const {return core::vector3d(X/val,Y/val,Z/val);} +template <> +inline vector3d& vector3d::operator /=(s32 val) {X/=val;Y/=val;Z/=val; return *this;} + +SExposedVideoData.h +New constructors +SExposedVideoData() {OpenGLWin32.HDc=0; OpenGLWin32.HRc=0; OpenGLWin32.HWnd=0;} +explicit SExposedVideoData(void* Window) {OpenGLWin32.HDc=0; OpenGLWin32.HRc=0; OpenGLWin32.HWnd=Window;} + +IGUIEnvironment.h +New method +virtual IGUIFont* addFont(const io::path& name, IGUIFont* font) = 0; +New parameter (image) +virtual IGUIWindow* addMessageBox(const wchar_t* caption, const wchar_t* text=0, + bool modal = true, s32 flags = EMBF_OK, IGUIElement* parent=0, s32 id=-1, video::ITexture* image=0) = 0; + +IGeometryCreator.h +New method +IMesh* createPlaneMesh(const core::dimension2d& tileSize, + const core::dimension2d& tileCount, + video::SMaterial* material, + const core::dimension2d& textureRepeatCount) const + +IFileArchive.h +New archive type +EFAT_NPK = MAKE_IRR_ID('N','P','K', 0), +New member for storing the password of AES-encrypted archives +core::stringc Password; + +IFileSystem.h +New parameter (password) +virtual bool addFileArchive(const path& filename, bool ignoreCase=true, + bool ignorePaths=true, + E_FILE_ARCHIVE_TYPE archiveType=EFAT_UNKNOWN, + const core::stringc& password="") =0; + +IrrlichtDevice.h +New method +virtual void clearSystemMessages() = 0; + +irrMath.h +Changed constant (from 1) +const s32 ROUNDING_ERROR_S32 = 0; +New method +template +inline void swap(T& a, T& b) + +IGPUProgrammingServices.h +New parameters (for geometry shaders) +virtual s32 addHighLevelShaderMaterial +virtual s32 addHighLevelShaderMaterialFromFiles +virtual s32 addHighLevelShaderMaterialFromFiles +New overload (for calling with geometry shaders) +s32 addHighLevelShaderMaterial +s32 addHighLevelShaderMaterialFromFiles +s32 addHighLevelShaderMaterialFromFiles + +ISceneNode.h +New types + typedef core::list ISceneNodeList; + typedef core::list ISceneNodeAnimatorList; + +IEventReceiver.h +Renamed events (split from EMIE_MOUSE_*) +EMIE_LMOUSE_DOUBLE_CLICK, +EMIE_RMOUSE_DOUBLE_CLICK, +EMIE_MMOUSE_DOUBLE_CLICK, +EMIE_LMOUSE_TRIPLE_CLICK, +EMIE_RMOUSE_TRIPLE_CLICK, +EMIE_MMOUSE_TRIPLE_CLICK, + +IGUISpriteBank.h +New method +virtual s32 addTextureAsSprite(video::ITexture* texture) = 0; +virtual void clear() = 0; + +SMaterial.h +Changed binary packing (non-visible from user calls) +inline f32 pack_texureBlendFunc ( const E_BLEND_FACTOR srcFact, const E_BLEND_FACTOR dstFact, const E_MODULATE_FUNC modulate=EMFN_MODULATE_1X, const u32 alphaSource=EAS_TEXTURE ) + +IGUISkin.h +New values +EGDS_MESSAGE_BOX_GAP_SPACE, +EGDS_MESSAGE_BOX_MIN_TEXT_WIDTH, +EGDS_MESSAGE_BOX_MAX_TEST_WIDTH, +EGDS_MESSAGE_BOX_MIN_TEXT_HEIGHT, +EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT, +New parameter (checkClientArea) +virtual core::rect draw3DWindowBackground(IGUIElement* element, + bool drawTitleBar, video::SColor titleBarColor, + const core::rect& rect, + const core::rect* clip=0, + core::rect* checkClientArea=0) = 0; + +quaternion.h +New operator +bool operator!=(const quaternion& other) const; +New method +inline quaternion& set(const core::quaternion& quat); +inline bool equals(const quaternion& other, + const f32 tolerance = ROUNDING_ERROR_f32 ) const; + +irrList.h +New method +u32 size() const +void swap(list& other) + +IVideoDriver.h +New render targets +ERT_MULTI_RENDER_TEXTURES +New class +struct IRenderTarget +Changed parameter (from void*) +virtual bool beginScene(bool backBuffer=true, bool zBuffer=true, + SColor color=SColor(255,0,0,0), + const SExposedVideoData& videoData=SExposedVideoData(), + core::rect* sourceRect=0) =0; +New parameter (mipmapData) +virtual ITexture* addTexture(const io::path& name, IImage* image, void* mipmapData=0) = 0; +New method +virtual bool setRenderTarget(const core::array& texture, + bool clearBackBuffer=true, bool clearZBuffer=true, + SColor color=video::SColor(0,0,0,0)) =0; +void drawIndexedTriangleFan(const S3DVertexTangents* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) +virtual void getFog(SColor& color, E_FOG_TYPE& fogType, + f32& start, f32& end, f32& density, + bool& pixelFog, bool& rangeFog) = 0; +virtual SMaterial& getMaterial2D() =0; +virtual void enableMaterial2D(bool enable=true) =0; +virtual core::dimension2du getMaxTextureSize() const =0; +Made non-virtual +void drawIndexedTriangleList(const S3DVertex* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) +void drawIndexedTriangleList(const S3DVertex2TCoords* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) +void drawIndexedTriangleList(const S3DVertexTangents* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) +void drawIndexedTriangleFan(const S3DVertex* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) +void drawIndexedTriangleFan(const S3DVertex2TCoords* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) + +EDriverFeatures.h +New driver feature enums +EVDF_MULTIPLE_RENDER_TARGETS, +EVDF_MRT_BLEND, +EVDF_MRT_COLOR_MASK, +EVDF_MRT_BLEND_FUNC, +EVDF_GEOMETRY_SHADER, + +IGUIWindow.h +New method +virtual core::rect getClientRect() const = 0; + +IGUIContextMenu.h +New enum +enum ECONTEXT_MENU_CLOSE +New method +virtual void setCloseHandling(ECONTEXT_MENU_CLOSE onClose) = 0; +virtual ECONTEXT_MENU_CLOSE getCloseHandling() const = 0; +virtual u32 insertItem(u32 idx, const wchar_t* text, s32 commandId=-1, bool enabled=true, + bool hasSubMenu=false, bool checked=false, bool autoChecking=false) = 0; +virtual s32 findItemWithCommandId(s32 commandId, u32 idxStartSearch=0) const = 0; +virtual void setItemAutoChecking(u32 idx, bool autoChecking) = 0; +virtual bool getItemAutoChecking(u32 idx) const = 0; +virtual void setEventParent(IGUIElement *parent) = 0; +New parameter +virtual u32 addItem(const wchar_t* text, s32 commandId=-1, bool enabled=true, + bool hasSubMenu=false, bool checked=false, bool autoChecking=false) = 0; + +SIrrCreationParameters.h +New parameter (LoggingLevel) +createDevice + +matrix4.h +New method +bool equals(const core::CMatrix4& other, const T tolerance=(T)ROUNDING_ERROR_f64) const; + +SSkinMeshBuffer.h +Renamed method (from MoveTo_2TCoords) +virtual void convertTo2TCoords() +Renamed method (from MoveTo_Tangents) +virtual void convertToTangents() + +SVertexManipulator.h +New classes (for vertex manipulation) +class SVertexColorSetManipulator : public IVertexManipulator +class SVertexColorSetAlphaManipulator : public IVertexManipulator +class SVertexColorInvertManipulator : public IVertexManipulator +class SVertexColorThresholdManipulator : public IVertexManipulator +class SVertexColorBrightnessManipulator : public IVertexManipulator +class SVertexColorContrastManipulator : public IVertexManipulator +class SVertexColorContrastBrightnessManipulator : public IVertexManipulator +class SVertexColorGammaManipulator : public IVertexManipulator +; +class SVertexColorScaleManipulator : public IVertexManipulator +class SVertexColorDesaturateToLightnessManipulator : public IVertexManipulator +class SVertexColorDesaturateToAverageManipulator : public IVertexManipulator +class SVertexColorDesaturateToLuminanceManipulator : public IVertexManipulator +class SVertexColorInterpolateLinearManipulator : public IVertexManipulator +class SVertexColorInterpolateQuadraticManipulator : public IVertexManipulator +class SVertexPositionScaleManipulator : public IVertexManipulator +; +class SVertexPositionScaleAlongNormalsManipulator : public IVertexManipulator +class SVertexPositionTransformManipulator : public IVertexManipulator +class SVertexTCoordsScaleManipulator : public IVertexManipulator + +IMeshCache.h +Renamed method (from getMeshByFilename) +virtual IAnimatedMesh* getMeshByName(const io::path& name) = 0; +Renamed method and changed return type (from getMeshFilename/io::path) +virtual const io::SNamedPath& getMeshName(u32 index) const = 0; +virtual const io::SNamedPath& getMeshName(const IAnimatedMesh* const mesh) const = 0; +virtual const io::SNamedPath& getMeshName(const IMesh* const mesh) const = 0; +Renamed method (from setMeshFilename) +virtual bool renameMesh(u32 index, const io::path& name) = 0; +virtual bool renameMesh(const IAnimatedMesh* const mesh, const io::path& name) = 0; +virtual bool renameMesh(const IMesh* const mesh, const io::path& name) = 0; + +IGUIElement.h +Changed parameter (to const-ref) + IGUIElement(EGUI_ELEMENT_TYPE type, IGUIEnvironment* environment, IGUIElement* parent, +s32 id, const core::rect& rectangle) +New method +virtual bool hasType(EGUI_ELEMENT_TYPE type) const + +irrString.h +Changed parameter (to template with allocator) in all methods with templates +Made destructor non-virtual +~string() +Added parameter +s32 find(const B* const str, const u32 start = 0) const +New method +void remove(T c) +void remove(const string toRemove) +void removeChars(const string & characters) +template +u32 split(container& ret, const T* const c, u32 count=1, bool ignoreEmptyTokens=true, bool keepSeparators=false) const + +vector2d.h +Use tolerance to compare, changed order function to total order +bool operator<=(const vector2d&other) const +bool operator>=(const vector2d&other) const +bool operator<(const vector2d&other) const +bool operator>(const vector2d&other) const + diff --git a/examples/01.HelloWorld/HelloWorld.cbp b/examples/01.HelloWorld/HelloWorld.cbp new file mode 100644 index 00000000..1811e4a8 --- /dev/null +++ b/examples/01.HelloWorld/HelloWorld.cbp @@ -0,0 +1,58 @@ + + + + + + diff --git a/examples/01.HelloWorld/HelloWorld.vcproj b/examples/01.HelloWorld/HelloWorld.vcproj new file mode 100644 index 00000000..3a2fdb0e --- /dev/null +++ b/examples/01.HelloWorld/HelloWorld.vcproj @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/01.HelloWorld/HelloWorld.xcodeproj/project.pbxproj b/examples/01.HelloWorld/HelloWorld.xcodeproj/project.pbxproj new file mode 100644 index 00000000..c3c5eb5f --- /dev/null +++ b/examples/01.HelloWorld/HelloWorld.xcodeproj/project.pbxproj @@ -0,0 +1,290 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 01.HelloWorld.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 01.HelloWorld.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 01.HelloWorld.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 01.HelloWorld */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "01.HelloWorld" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 01.HelloWorld; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 01.HelloWorld.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0710; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "HelloWorld" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 01.HelloWorld */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + GCC_C_LANGUAGE_STANDARD = c11; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "HelloWorld" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "01.HelloWorld" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/01.HelloWorld/HelloWorld.xcodeproj/xcshareddata/xcschemes/01.HelloWorld.xcscheme b/examples/01.HelloWorld/HelloWorld.xcodeproj/xcshareddata/xcschemes/01.HelloWorld.xcscheme new file mode 100644 index 00000000..ba196db3 --- /dev/null +++ b/examples/01.HelloWorld/HelloWorld.xcodeproj/xcshareddata/xcschemes/01.HelloWorld.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/01.HelloWorld/HelloWorld_vc10.vcxproj b/examples/01.HelloWorld/HelloWorld_vc10.vcxproj new file mode 100644 index 00000000..509ccbed --- /dev/null +++ b/examples/01.HelloWorld/HelloWorld_vc10.vcxproj @@ -0,0 +1,233 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 01.HelloWorld + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9} + HelloWorld + + + + Application + false + MultiByte + + + Application + false + MultiByte + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/HelloWorld.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\01.HelloWorld.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/HelloWorld.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\01.HelloWorld.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/HelloWorld.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\01.HelloWorld.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/HelloWorld.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\01.HelloWorld.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/01.HelloWorld/HelloWorld_vc11.vcxproj b/examples/01.HelloWorld/HelloWorld_vc11.vcxproj new file mode 100644 index 00000000..c131e023 --- /dev/null +++ b/examples/01.HelloWorld/HelloWorld_vc11.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 01.HelloWorld + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9} + HelloWorld + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/HelloWorld.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\01.HelloWorld.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/HelloWorld.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\01.HelloWorld.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/HelloWorld.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\01.HelloWorld.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/HelloWorld.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\01.HelloWorld.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/01.HelloWorld/HelloWorld_vc12.vcxproj b/examples/01.HelloWorld/HelloWorld_vc12.vcxproj new file mode 100644 index 00000000..109da6b3 --- /dev/null +++ b/examples/01.HelloWorld/HelloWorld_vc12.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 01.HelloWorld + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9} + HelloWorld + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/HelloWorld.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\01.HelloWorld.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/HelloWorld.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\01.HelloWorld.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/HelloWorld.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\01.HelloWorld.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/HelloWorld.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\01.HelloWorld.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/01.HelloWorld/HelloWorld_vc14.vcxproj b/examples/01.HelloWorld/HelloWorld_vc14.vcxproj new file mode 100644 index 00000000..23853d7b --- /dev/null +++ b/examples/01.HelloWorld/HelloWorld_vc14.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 01.HelloWorld + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9} + HelloWorld + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/HelloWorld.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\01.HelloWorld.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/HelloWorld.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\01.HelloWorld.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/HelloWorld.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\01.HelloWorld.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/HelloWorld.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\01.HelloWorld.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/01.HelloWorld/Makefile b/examples/01.HelloWorld/Makefile new file mode 100644 index 00000000..6b6d16fd --- /dev/null +++ b/examples/01.HelloWorld/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 01.HelloWorld +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/01.HelloWorld/main.cpp b/examples/01.HelloWorld/main.cpp new file mode 100644 index 00000000..aeb0c570 --- /dev/null +++ b/examples/01.HelloWorld/main.cpp @@ -0,0 +1,269 @@ +/** Example 001 HelloWorld + +This tutorial shows how to set up the IDE for using the Irrlicht Engine and how +to write a simple HelloWorld program with it. The program will show how to use +the basics of the VideoDriver, the GUIEnvironment, and the SceneManager. +Microsoft Visual Studio is used as an IDE, but you will also be able to +understand everything if you are using a different one or even another +operating system than Windows. + +You have to include the header file in order to use the engine. The +header file can be found in the Irrlicht Engine SDK directory \c include. To let +the compiler find this header file, the directory where it is located has to be +added in your project as include path. This is different for every IDE and +compiler you use. Let's explain shortly how to do this in Visual Studio 2010: + +- In Visual Studio 2010 select the Menu Project -> Properties. Select the + "C/C++" - "General" option, and select the "Additional Include Directories". + Add the \c include directory of the Irrlicht engine folder to the list of + directories. Now the compiler will find the irrlicht.h header file. We also + need the irrlicht.lib to be found, so select "Linker" - "General" and + add the \c lib/Win64-visualStudio or \c lib/Win32-visualStudio directory + to "Additional Library Directories". Which of the 2 Irrlicht versions you + chose depends on the target platform for your application (win32 or x64). + In your project properties you can see what your active solution platform + is, you can use the same one for Irrlicht. + +To be able to use the Irrlicht.DLL file, we need to link with the Irrlicht.lib. +In most IDE's you have to add irrlicht.lib (or irrlicht.a or irrlicht.so on +Linux) to your Linker input files. + +For VisualStudio we can be lazy and use the pragma comment lib. +We also want to get rid of the console window, which pops up when starting a +program with main() (instead of WinMain). This is done by the second pragma. +We could also use the WinMain method, though losing platform independence then. +*/ +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup") +#endif + +/* +That's it. With your IDE set up like this, you will now be able to develop +applications with the Irrlicht Engine. + +Lets start! + +After we have set up the IDE, the compiler will know where to find the Irrlicht +Engine header files so we can include it now in our code. +*/ +#include + +/* +That header just adds the getExampleMediaPath tool-functions to help locating +the media we need. More about that later below. +*/ +#include "exampleHelper.h" + +/* +In the Irrlicht Engine, everything can be found in the namespace 'irr'. So if +you want to use a class of the engine, you have to write irr:: before the name +of the class. For example to use the IrrlichtDevice write: irr::IrrlichtDevice. +To get rid of the irr:: in front of the name of every class, we tell the +compiler that we use that namespace from now on, and we will not have to write +irr:: anymore. +Note that you never should do that in headers - otherwise you will pollute the +namespace of every file including such a header. So in headers always write +out the full names including all namespaces. +*/ +using namespace irr; + +/* +There are 5 sub namespaces in the Irrlicht Engine. Take a look at them, you can +read a detailed description of them in the documentation by clicking on the top +menu item 'Namespace List' or by using this link: +http://irrlicht.sourceforge.net/docu/namespaces.html +Like the irr namespace, we do not want these 5 sub namespaces now, to keep this +example simple. Hence, we tell the compiler again that we do not want always to +write their names. +*/ +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +/* +This is the main method. We can now use main() on every platform. +*/ +int main() +{ + /* + The most important function of the engine is the createDevice() + function. The IrrlichtDevice is created by it, which is the root + object for doing anything with the engine. createDevice() has the + following parameters: + + - driverType: Type of the video driver. This can currently be the Null-device, + one of the two software renderers, D3D9, or OpenGL. In this + example we use EDT_BURNINGSVIDEO, but to try out, you might want to + change it to EDT_SOFTWARE, EDT_NULL, EDT_DIRECT3D9, or EDT_OPENGL. + Generally you will want to use OpenGL or Direct3D as they are + using your graphic card for calculations instead of the CPU and + are way faster (and usually better looking). We just use one of the + software renderers here as it even works when your graphic card driver + isn't set up for 3d support. + + - windowSize: Size of the Window or screen in FullScreenMode to be + created. In this example we use 640x480. + + - bits: Amount of color bits per pixel. This should be 16 or 32. The + parameter is often ignored when running in windowed mode. More + commonly you would chose 32 bit, again we're just playing it safe. + + - fullscreen: Specifies if we want the device to run in fullscreen mode + or windowed. + + - stencilbuffer: Specifies if we want to use the stencil buffer (you + need it for drawing shadows). + + - vsync: Specifies if we want to have vsync enabled, this is only useful + in fullscreen mode. + + - eventReceiver: An object to receive events. We do not want to use this + parameter here, and set it to 0. + + Always check the return value to cope with unsupported drivers, + dimensions, etc. + */ + IrrlichtDevice *device = + createDevice( video::EDT_OGLES1, dimension2d(640, 480), 16, + false, false, false, 0); + + if (!device) + return 1; + + /* + Set the caption of the window to some nice text. Note that there is an + 'L' in front of the string. The Irrlicht Engine uses wide character + strings when displaying text. + */ + device->setWindowCaption(L"Hello World! - Irrlicht Engine Demo"); + + /* + Get a pointer to the VideoDriver, the SceneManager and the graphical + user interface environment, so that we do not always have to write + device->getVideoDriver(), device->getSceneManager(), or + device->getGUIEnvironment(). + */ + IVideoDriver* driver = device->getVideoDriver(); + ISceneManager* smgr = device->getSceneManager(); + IGUIEnvironment* guienv = device->getGUIEnvironment(); + + /* + We add a hello world label to the window, using the GUI environment. + The text is placed at the position (10,10) as top left corner and + (260,22) as lower right corner. + */ + guienv->addStaticText(L"Hello World! This is Irrlicht with the burnings software renderer!", + rect(10,10,260,22), true); + + /* + Get a media path dedicated for your platform. Finding media files for your + applications can be tricky. First you have 2 options - working with relative + paths or working with absolute paths. + + On Windows a common solution is that your installer will write a key into + the registry with the absolute path of wherever the user installed the + media. And in your application you read out that key from the registry. + On Linux a common solution is to use config file which is placed in some + fixed location (for example in a . file/folder in the user home). + + But you can also work with relative paths - which is what we do here. There + is a slight complication with relative paths as they are relative to your + current working directory. And that depends on the way your application is + started and it might change inside your application. But mostly it will be + set to your executable on start so you can ignore that problem while + developing. + + When inside VisualStudio the current working directory is set to your + project files location unless you overwrite Project properties - Debugging + - Working Directory. In Irrlicht examples the media folder is on most + platforms ../../media which works for the examples as it's relative to our + project files as well as to the binary (.exe) files. + + Whatever you chose to find your base-folder for media - wrap it with some + function and then you can improve the code to locate the media later on. + */ + const io::path mediaPath = getExampleMediaPath(); + + /* + To show something interesting, we load a Quake 2 model and display it. + We get the Mesh from the Scene Manager with getMesh() and add a SceneNode + to display the mesh with addAnimatedMeshSceneNode(). Check the return value + of getMesh() to become aware of loading problems and other errors. + + Instead of writing the filename sydney.md2, it would also be possible + to load a Maya object file (.obj), a complete Quake3 map (.bsp) or any + other supported file format. By the way, that cool Quake 2 model + called sydney was modeled by Brian Collins. + */ + IAnimatedMesh* mesh = smgr->getMesh(mediaPath + "sydney.md2"); + if (!mesh) + { + device->drop(); + return 1; + } + IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh ); + + /* + To let the mesh look a little bit nicer, we change its material. We + disable lighting because we do not have a dynamic light in here, and + the mesh would be totally black otherwise. Then we set the frame loop, + such that the predefined STAND animation is used. And last, we apply a + texture to the mesh. Without it the mesh would be drawn using only a + color. + */ + if (node) + { + node->setMaterialFlag(EMF_LIGHTING, false); + node->setMD2Animation(scene::EMAT_STAND); + node->setMaterialTexture( 0, driver->getTexture(mediaPath + "sydney.bmp") ); + } + + /* + To look at the mesh, we place a camera into 3d space at the position + (0, 30, -40). The camera looks from there to (0,5,0), which is + approximately the place where our md2 model is. + */ + smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0)); + + /* + OK, now we have set up the scene, lets draw everything: We run the + device in a while() loop, until the device does not want to run any + more. This would be when the user closes the window or presses ALT+F4 + (or whatever keycode closes a window on your OS). + */ + while(device->run()) + { + /* + Anything can be drawn between a beginScene() and an endScene() + call. The beginScene() call clears the screen with a color and + the depth buffer, if desired. Then we let the Scene Manager and + the GUI Environment draw their content. With the endScene() + call everything is presented on the screen. + */ + driver->beginScene(ECBF_COLOR | ECBF_DEPTH, SColor(255,100,101,140)); + + smgr->drawAll(); + guienv->drawAll(); + + driver->endScene(); + } + + /* + After we are done with the render loop, we have to delete the Irrlicht + Device created before with createDevice(). In the Irrlicht Engine, you + have to delete all objects you created with a method or function which + starts with 'create'. The object is simply deleted by calling ->drop(). + See the documentation at irr::IReferenceCounted::drop() for more + information. + */ + device->drop(); + + return 0; +} + +/* +That's it. Compile and run. +**/ diff --git a/examples/01.HelloWorld/tutorial.html b/examples/01.HelloWorld/tutorial.html new file mode 100644 index 00000000..e46c9542 --- /dev/null +++ b/examples/01.HelloWorld/tutorial.html @@ -0,0 +1,394 @@ + + +Irrlicht Engine Tutorial + + + + +
+ + + + + + + + + +
Tutorial 1.HelloWorld
+

This Tutorial shows how to set up the IDE for using the + Irrlicht Engine and how to write a simple HelloWorld program + with it. The program will show how to use the basics of + the VideoDriver, the GUIEnvironment and the SceneManager.
+ The result of this example will look like this:

+


+

+
+
+ + + + + + +
Setting up the + IDE
+
+

To use the engine, we will have to include + the header file <irrlicht.h>, which can be found + in the Irrlicht Engine SDK directory \include. To let + the compiler find this header file, the directory where + it is located should be specified somewhere. This is different + for every IDE and compiler. I will explain how to do this + in Microsoft Visual Studio C++ 6.0 and .NET:

+ +
+
    +
  • +
    If you use Version 6.0, select the Menu + Extras -> Options. Select the directories tab, and + select the 'Include' Item in the combo box. Add the + \include directory of the Irrlicht Engine folder to + the list of directories. Now the compiler will find + the Irrlicht.h header file. We also need the location + of irrlicht.lib to be listed, so select the 'Libraries' + tab and add the \lib\VisualStudio directory.
    +
    +   
    +  
    + +
    +
  • +
  • If your IDE is Visual Studio .NET, select Tools -> + Options. Select the Projects entry and then select VC++ + directories. Select 'show directories for include files' + in the combo box, and add the \include directory of the + Irrlicht Engine folder to the list of directories so the + compiler will find the Irrlicht.h header file. We also + need the irrlicht.lib to be found, so select 'show directories + for Library files' and add the \lib\VisualStudio directory.
    +
    + +
    +
  • +
+ +

 

+
+
+ + + + + + + + +
Lets start!
+
+
+
+

After we have set up the IDE, the compiler will know + where to find the Irrlicht Engine header files so + we can include it now into our code.

+ + + + + +
#include <irrlicht.h>
+

In the Irrlicht Engine, everything can be found in + the namespace 'irr'. So if you want to use a class + of the engine, you'll have to type an irr:: before + the name of the class. For example, to use the IrrlichtDevice, + write: irr::IrrlichtDevice. To avoid having to put + irr:: before of the name of every class, we tell the + compiler that we use that namespace.

+ + + + + +
using namespace irr;
+

There are 5 sub-namespaces in the Irrlicht Engine. + Take a look at them: you can read a detailed description + of them in the documentation by clicking on the top + menu item 'Namespace + List'. To keep this example simple, we don't want + to have to specify the name spaces, Hence:

+ + + + + +
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
+

To be able to use the Irrlicht.DLL file, we need + to link with the Irrlicht.lib. We could set this option + in the project settings, but to make it easy we use + a pragma comment:

+ + + + + +
#pragma comment(lib, "Irrlicht.lib")
+

Now the main method: to keep this example simple + we use int main(), which can be used on any platform. + However, on Windows platforms, we could also use the + WinMain method if we would want to get rid of the + console window which pops up when starting a program + with main().

+ + + + + +
int main()
{
+

The most important function of the engine is the + 'createDevice' function. The Irrlicht Device, which + is the root object for doing everything with the engine, + can be created with it. createDevice() has 7 parameters:

+
+
    +
  • + +
    deviceType: Type of the device. This can currently + be the Null device, the Software device, Direct3D8, Direct3D9, + or OpenGL. In this example we use EDT_SOFTWARE, but, to try + them out, you might want to change it to EDT_NULL, EDT_DIRECT3D8, + EDT_DIRECT3D9 or EDT_OPENGL.
    +
  • +
  • +
    windowSize: Size of the window or + full screen mode to be created. In this example + we use 512x384.
    + +
  • +
  • +
    bits: Number of bits per pixel when + in full screen mode. This should be 16 or 32. This + parameter is ignored when running in windowed mode.
    +
  • +
  • +
    fullscreen: Specifies if we want + the device to run in full screen mode or not.
    +
  • +
  • stencilbuffer: Specifies if we want to use the stencil + buffer for drawing shadows.
  • + +
  • vsync: Specifies if we want to have vsync enabled. + This is only useful in full screen mode.
  • +
  • +
    eventReceiver: An object to receive + events. We do not want to use this parameter here, + and set it to 0.
    +
  • +
+ + + + + +
IrrlichtDevice *device =
createDevice(EDT_SOFTWARE, dimension2d<s32>(512, 384), 16,
false, false, false, 0);
+

Now we set the caption of the window to some nice text. + Note that there is a 'L' in front of the string: the + Irrlicht Engine uses wide character strings when displaying + text.

+ + + + + +
device->setWindowCaption(L"Hello World! - Irrlicht Engine Demo");
+

Now we store a pointer to the video driver, the SceneManager, + and the graphical user interface environment so that + we do not always have to write device->getVideoDriver(), + device->getSceneManager(), and device->getGUIEnvironment().

+ + + + + +
IVideoDriver* driver = device->getVideoDriver();
ISceneManager* smgr = device->getSceneManager();
IGUIEnvironment* guienv = device->getGUIEnvironment();
+

We add a hello world label to the window using the + GUI environment. The text is placed at the position + (10,10) as top left corner and (200,22) as lower right + corner.

+ + + + + +
guienv->addStaticText(L"Hello World! This is the Irrlicht Software engine!",
rect<s32>(10,10,200,22), true);
+

To display something interesting, we load a Quake 2 + model and display it. We only have to get the Mesh from + the Scene Manager with getMesh() and add a SceneNode + to display the mesh with addAnimatedMeshSceneNode(). + Instead of loading a Quake2 file (.md2), it is also + possible to load a Maya object file (.obj), a complete + Quake3 map (.bsp), or a Milshape file (.ms3d).
+ By the way, that cool Quake 2 model called sydney.md2 + was modelled by Brian Collins.

+ + + + + +
IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2");
IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh );
+

To make the mesh look a little bit nicer, we change + its material a little bit: we disable lighting because + we do not have a dynamic light in here and the mesh + would be totally black. Then we set the frame loop so + that the animation is looped between the frames 0 and + 310. Then, at last, we apply a texture to the mesh. + Without it the mesh would be drawn using only a solid + color.

+ + + + + +
if (node)
{
node->setMaterialFlag(EMF_LIGHTING, false);
node->setFrameLoop(0, 310);
node->setMaterialTexture( 0, driver->getTexture("../../media/sydney.bmp") );
}
+
+

To look at the mesh, we place a camera into 3d space + at the position (0, 10, -40). The camera looks from + there to (0,5,0).

+ + + + + +
smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0));
+

Ok. Now that we have set up the scene, let's draw everything: + we run the device in a while() loop until the device + does not want to run any more. This would be when the + user closes the window or presses ALT+F4 in Windows.

+ + + + + +
while(device->run())
{
+

Everything must be drawn between a beginScene() and + an endScene() call. The beginScene clears the screen + with a color and also the depth buffer, if desired. + Then we let the Scene Manager and the GUI environment + draw their content. With the endScene() call, everything + is presented on the screen.

+ + + + + + +
	driver->beginScene(true, true, SColor(255,100,101,140));
+ smgr->drawAll(); + guienv->drawAll();
+
	driver->endScene();
+}
+

After we are finished, we have to delete the Irrlicht + Device created earlier with createDevice(). With the + Irrlicht Engine, you should delete all objects you created + with a method or function that starts with 'create'. + The object is deleted simply by calling ->drop(). + See the documentation + for more information.

+ + + + + +
	device->drop();
return 0; +}
+

That's it. Compile and run.

+

 

+
+
+
+
+ + + + + + + +
Possible Errors + or Problems
+
+
+

Visual Studio
+ + While trying to compile the tutorial, if you get the + error:

+ + + + +
fatal + error C1083: Cannot open include file: 'irrlicht.h': + No such file or directory
+

Solution: You may have set the include directory improperly + in the Visual Studio options. See above + for information on setting it.

+ + + + + +
LINK + : LNK6004: HelloWorld.exe not found or not built + by the last incremental link; performing full link
+ LINK : fatal error LNK1104: cannot open file "Irrlicht.lib"
+ Error executing link.exe
+

Solution: You may have set the library directory improperly. + See above for information on + setting it.
+ +
+

+

Compiler independent problems
+
If the tutorial compiles successfully but gives + the error:

+ + + + + +
This + application has failed to start because Irrlicht.dll + was not found. Re-installing the application may + fix this problem
+

Solution: You may have forgotten to copy the Irrlicht.dll + file from Irrlicht\bin\VisualStudio to the directory + the tutorial's project file is in.

+ If the tutorial compiles and runs successfully but produces + errors in the console like:
+
+ + + + + +
Could + not load mesh, because file could not be opened.: + ../media/sydney.md2
+

Or:

+ + + + + +
Could + not open file of texture: stones.jpg
+
Could not load texture: stones.jpg
+

Solution: The file listed in the error message cannot + be found. Ensure that the directory specified in the + main.cpp exists and is where the file is located.
+

+
+
+
+

 

+ + diff --git a/examples/01.HelloWorld_Android/AndroidManifest.xml b/examples/01.HelloWorld_Android/AndroidManifest.xml new file mode 100755 index 00000000..b26b4d40 --- /dev/null +++ b/examples/01.HelloWorld_Android/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + diff --git a/examples/01.HelloWorld_Android/android_tools.cpp b/examples/01.HelloWorld_Android/android_tools.cpp new file mode 100644 index 00000000..758a0a8d --- /dev/null +++ b/examples/01.HelloWorld_Android/android_tools.cpp @@ -0,0 +1,184 @@ +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "android_tools.h" +#include // for the occasional debugging, style: __android_log_print(ANDROID_LOG_VERBOSE, "Irrlicht", "%s\n", "We do log"); + +namespace irr +{ +namespace android +{ + +// Not all DisplayMetrics are available through the NDK. +// So we access the Java classes with the JNI interface. +// You can access other Java classes available in Android in similar ways. +// Function based roughly on the code from here: http://stackoverflow.com/questions/13249164/android-using-jni-from-nativeactivity +bool getDisplayMetrics(android_app* app, SDisplayMetrics & metrics) +{ + if (!app || !app->activity || !app->activity->vm ) + return false; + + JNIEnv* jni = 0; + app->activity->vm->AttachCurrentThread(&jni, NULL); + if (!jni ) + return false; + + + // get all the classes we want to access from the JVM + jclass classNativeActivity = jni->FindClass("android/app/NativeActivity"); + jclass classWindowManager = jni->FindClass("android/view/WindowManager"); + jclass classDisplay = jni->FindClass("android/view/Display"); + jclass classDisplayMetrics = jni->FindClass("android/util/DisplayMetrics"); + + if (!classNativeActivity || !classWindowManager || !classDisplay || !classDisplayMetrics) + { + app->activity->vm->DetachCurrentThread(); + return false; + } + + + // Get all the methods we want to access from the JVM classes + // Note: You can get the signatures (third parameter of GetMethodID) for all + // functions of a class with the javap tool, like in the following example for class DisplayMetrics: + // javap -s -classpath myandroidpath/adt-bundle-linux-x86_64-20131030/sdk/platforms/android-10/android.jar android/util/DisplayMetrics + jmethodID idNativeActivity_getWindowManager = jni->GetMethodID( classNativeActivity + , "getWindowManager" + , "()Landroid/view/WindowManager;"); + jmethodID idWindowManager_getDefaultDisplay = jni->GetMethodID( classWindowManager + , "getDefaultDisplay" + , "()Landroid/view/Display;"); + jmethodID idDisplayMetrics_constructor = jni->GetMethodID( classDisplayMetrics + , "" + , "()V"); + jmethodID idDisplay_getMetrics = jni->GetMethodID( classDisplay + , "getMetrics" + , "(Landroid/util/DisplayMetrics;)V"); + + if (!idNativeActivity_getWindowManager || !idWindowManager_getDefaultDisplay || !idDisplayMetrics_constructor + || !idDisplay_getMetrics) + { + app->activity->vm->DetachCurrentThread(); + return false; + } + + + // In Java the following code would be: getWindowManager().getDefaultDisplay().getMetrics(metrics); + // Note: If you need to call java functions in time-critical places you can split getting the jmethodID's + // and calling the functions into separate functions as you only have to get the jmethodID's once. + jobject windowManager = jni->CallObjectMethod(app->activity->clazz, idNativeActivity_getWindowManager); + + if (!windowManager) + { + app->activity->vm->DetachCurrentThread(); + return false; + } + jobject display = jni->CallObjectMethod(windowManager, idWindowManager_getDefaultDisplay); + if (!display) + { + app->activity->vm->DetachCurrentThread(); + return false; + } + jobject displayMetrics = jni->NewObject( classDisplayMetrics, idDisplayMetrics_constructor); + if (!displayMetrics) + { + app->activity->vm->DetachCurrentThread(); + return false; + } + jni->CallVoidMethod(display, idDisplay_getMetrics, displayMetrics); + + // access the fields of DisplayMetrics (we ignore the DENSITY constants) + jfieldID idDisplayMetrics_widthPixels = jni->GetFieldID( classDisplayMetrics, "widthPixels", "I"); + jfieldID idDisplayMetrics_heightPixels = jni->GetFieldID( classDisplayMetrics, "heightPixels", "I"); + jfieldID idDisplayMetrics_density = jni->GetFieldID( classDisplayMetrics, "density", "F"); + jfieldID idDisplayMetrics_densityDpi = jni->GetFieldID( classDisplayMetrics, "densityDpi", "I"); + jfieldID idDisplayMetrics_scaledDensity = jni->GetFieldID( classDisplayMetrics, "scaledDensity", "F"); + jfieldID idDisplayMetrics_xdpi = jni->GetFieldID(classDisplayMetrics, "xdpi", "F"); + jfieldID idDisplayMetrics_ydpi = jni->GetFieldID(classDisplayMetrics, "ydpi", "F"); + + if ( idDisplayMetrics_widthPixels ) + metrics.widthPixels = jni->GetIntField(displayMetrics, idDisplayMetrics_widthPixels); + if ( idDisplayMetrics_heightPixels ) + metrics.heightPixels = jni->GetIntField(displayMetrics, idDisplayMetrics_heightPixels); + if (idDisplayMetrics_density ) + metrics.density = jni->GetFloatField(displayMetrics, idDisplayMetrics_density); + if (idDisplayMetrics_densityDpi) + metrics.densityDpi = jni->GetIntField(displayMetrics, idDisplayMetrics_densityDpi); + if (idDisplayMetrics_scaledDensity) + metrics.scaledDensity = jni->GetFloatField(displayMetrics, idDisplayMetrics_scaledDensity); + if ( idDisplayMetrics_xdpi ) + metrics.xdpi = jni->GetFloatField(displayMetrics, idDisplayMetrics_xdpi); + if ( idDisplayMetrics_ydpi ) + metrics.ydpi = jni->GetFloatField(displayMetrics, idDisplayMetrics_ydpi); + + app->activity->vm->DetachCurrentThread(); + return true; +} + +void setSoftInputVisibility(android_app* app, bool visible) +{ + // NOTE: Unfortunately ANativeActivity_showSoftInput from the NDK does not work and Google does not care. + // This is based on the solution from @Ratamovic from here: http://stackoverflow.com/questions/5864790/how-to-show-the-soft-keyboard-on-native-activity + + if (!app || !app->activity || !app->activity->vm ) + return; + + JNIEnv* jni = 0; + app->activity->vm->AttachCurrentThread(&jni, NULL); + if (!jni ) + return; + + // get all the classes we want to access from the JVM (could be cached) + jclass classNativeActivity = jni->FindClass("android/app/NativeActivity"); + jclass classInputMethodManager = jni->FindClass("android/view/inputmethod/InputMethodManager"); + jclass classWindow = jni->FindClass("android/view/Window"); + jclass classView = jni->FindClass("android/view/View"); + + if (classNativeActivity && classInputMethodManager && classWindow) + { + // Get all the methods we want to access from the JVM classes (could be cached) + jmethodID mid_getSystemService = jni->GetMethodID(classNativeActivity, "getSystemService","(Ljava/lang/String;)Ljava/lang/Object;"); + jmethodID mid_showSoftInput = jni->GetMethodID(classInputMethodManager, "showSoftInput", "(Landroid/view/View;I)Z"); + + jmethodID mid_hideSoftInput = jni->GetMethodID(classInputMethodManager, "hideSoftInputFromWindow", "(Landroid/os/IBinder;I)Z"); + jmethodID mid_getWindow = jni->GetMethodID(classNativeActivity, "getWindow", "()Landroid/view/Window;"); + jmethodID mid_getWindowToken = jni->GetMethodID(classView, "getWindowToken", "()Landroid/os/IBinder;"); + jmethodID mid_getDecorView = jni->GetMethodID(classWindow, "getDecorView", "()Landroid/view/View;"); + + if ( mid_getSystemService && mid_showSoftInput && mid_hideSoftInput && mid_getWindow && mid_getDecorView && mid_getWindowToken ) + { + jstring paramInput = jni->NewStringUTF("input_method"); + jobject objInputMethodManager = jni->CallObjectMethod(app->activity->clazz, mid_getSystemService, paramInput); + jni->DeleteLocalRef(paramInput); + + jobject objWindow = jni->CallObjectMethod(app->activity->clazz, mid_getWindow); + + if ( visible && objInputMethodManager && objWindow) + { + jobject objDecorView = jni->CallObjectMethod(objWindow, mid_getDecorView); + if ( objDecorView ) + { + int showFlags = 0; + jni->CallBooleanMethod(objInputMethodManager, mid_showSoftInput, objDecorView, showFlags); + } + } + else if ( !visible && objInputMethodManager && objWindow ) + { + jobject objDecorView = jni->CallObjectMethod(objWindow, mid_getDecorView); + if ( objDecorView ) + { + jobject objBinder = jni->CallObjectMethod(objDecorView, mid_getWindowToken); + if ( objBinder ) + { + int hideFlags = 0; + jni->CallBooleanMethod(objInputMethodManager, mid_hideSoftInput, objBinder, hideFlags); + } + } + } + } + } + + app->activity->vm->DetachCurrentThread(); +} + +} // namespace android +} // namespace irr diff --git a/examples/01.HelloWorld_Android/android_tools.h b/examples/01.HelloWorld_Android/android_tools.h new file mode 100644 index 00000000..2a3d66f7 --- /dev/null +++ b/examples/01.HelloWorld_Android/android_tools.h @@ -0,0 +1,33 @@ +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_ANDROID_TOOLS_H__ +#define __IRR_ANDROID_TOOLS_H__ + +#include +#include + +namespace irr +{ +namespace android +{ + +struct SDisplayMetrics +{ + irr::s32 widthPixels; + irr::s32 heightPixels; + irr::f32 density; + irr::s32 densityDpi; + irr::f32 scaledDensity; + irr::f32 xdpi; + irr::f32 ydpi; +}; + +//! Access SDisplayMetrics +extern bool getDisplayMetrics(android_app* app, SDisplayMetrics & metrics); + +extern void setSoftInputVisibility(android_app* app, bool visible); +} +} + +#endif // __IRR_ANDROID_TOOLS_H__ diff --git a/examples/01.HelloWorld_Android/build.xml b/examples/01.HelloWorld_Android/build.xml new file mode 100755 index 00000000..3ebae63b --- /dev/null +++ b/examples/01.HelloWorld_Android/build.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/examples/01.HelloWorld_Android/jni/Android.mk b/examples/01.HelloWorld_Android/jni/Android.mk new file mode 100755 index 00000000..3ac2aa4c --- /dev/null +++ b/examples/01.HelloWorld_Android/jni/Android.mk @@ -0,0 +1,50 @@ +LOCAL_PATH := $(call my-dir)/.. +IRRLICHT_PROJECT_PATH := $(LOCAL_PATH) + +include $(CLEAR_VARS) +LOCAL_MODULE := Irrlicht +LOCAL_SRC_FILES := $(IRRLICHT_PROJECT_PATH)/../../lib/Android/libIrrlicht.a +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) + +LOCAL_MODULE := HelloWorldMobile + +LOCAL_CFLAGS := -pipe -fno-exceptions -fno-rtti -fstrict-aliasing + +ifndef NDEBUG +LOCAL_CFLAGS += -g -D_DEBUG +else +LOCAL_CFLAGS += -fexpensive-optimizations -O3 +endif + +ifeq ($(TARGET_ARCH_ABI),x86) +LOCAL_CFLAGS += -fno-stack-protector +endif + +LOCAL_C_INCLUDES := ../../include + +LOCAL_SRC_FILES := main.cpp android_tools.cpp + +LOCAL_LDLIBS := -lEGL -llog -lGLESv1_CM -lGLESv2 -lz -landroid + +LOCAL_STATIC_LIBRARIES := Irrlicht android_native_app_glue + +include $(BUILD_SHARED_LIBRARY) + +$(call import-module,android/native_app_glue) + +# copy Irrlicht data to assets + +$(shell mkdir -p $(IRRLICHT_PROJECT_PATH)/assets) +$(shell mkdir -p $(IRRLICHT_PROJECT_PATH)/assets/media) +$(shell mkdir -p $(IRRLICHT_PROJECT_PATH)/assets/media/Shaders) +$(shell mkdir -p $(IRRLICHT_PROJECT_PATH)/src) +$(shell cp $(IRRLICHT_PROJECT_PATH)/../../media/Shaders/*.* $(IRRLICHT_PROJECT_PATH)/assets/media/Shaders/) +$(shell cp $(IRRLICHT_PROJECT_PATH)/../../media/irrlichtlogo3.png $(IRRLICHT_PROJECT_PATH)/assets/media/) +$(shell cp $(IRRLICHT_PROJECT_PATH)/../../media/dwarf.x $(IRRLICHT_PROJECT_PATH)/assets/media/) +$(shell cp $(IRRLICHT_PROJECT_PATH)/../../media/dwarf.jpg $(IRRLICHT_PROJECT_PATH)/assets/media/) +$(shell cp $(IRRLICHT_PROJECT_PATH)/../../media/axe.jpg $(IRRLICHT_PROJECT_PATH)/assets/media/) +$(shell cp $(IRRLICHT_PROJECT_PATH)/../../media/fonthaettenschweiler.bmp $(IRRLICHT_PROJECT_PATH)/assets/media/) +$(shell cp $(IRRLICHT_PROJECT_PATH)/../../media/bigfont.png $(IRRLICHT_PROJECT_PATH)/assets/media/) + diff --git a/examples/01.HelloWorld_Android/jni/Application.mk b/examples/01.HelloWorld_Android/jni/Application.mk new file mode 100755 index 00000000..6c4880ea --- /dev/null +++ b/examples/01.HelloWorld_Android/jni/Application.mk @@ -0,0 +1,2 @@ +APP_PLATFORM := android-10 +APP_MODULES := HelloWorldMobile diff --git a/examples/01.HelloWorld_Android/main.cpp b/examples/01.HelloWorld_Android/main.cpp new file mode 100644 index 00000000..087da556 --- /dev/null +++ b/examples/01.HelloWorld_Android/main.cpp @@ -0,0 +1,387 @@ +/** Example 027 Helloworld_Android + This example shows a simple application for Android. +*/ + +#include + +#ifdef _IRR_ANDROID_PLATFORM_ + +#include +#include "android_tools.h" +#include "android/window.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + + +enum GUI_IDS +{ + GUI_INFO_FPS, + GUI_IRR_LOGO, +}; + + +/* + Android is using multitouch events. + We allow users to move around the Irrlicht logo as example of how to use those. +*/ +class MyEventReceiver : public IEventReceiver +{ +public: + MyEventReceiver(android_app* app ) + : Device(0), AndroidApp(app), SpriteToMove(0), TouchID(-1) + { + } + + void Init(IrrlichtDevice *device) + { + Device = device; + } + + virtual bool OnEvent(const SEvent& event) + { + if (event.EventType == EET_TOUCH_INPUT_EVENT) + { + /* + For now we fake mouse-events. Touch-events will be handled inside Irrlicht in the future, but until + that is implemented you can use this workaround to get a GUI which works at least for simple elements like + buttons. That workaround does ignore multi-touch events - if you need several buttons pressed at the same + time you have to handle that yourself. + */ + SEvent fakeMouseEvent; + fakeMouseEvent.EventType = EET_MOUSE_INPUT_EVENT; + fakeMouseEvent.MouseInput.X = event.TouchInput.X; + fakeMouseEvent.MouseInput.Y = event.TouchInput.Y; + fakeMouseEvent.MouseInput.Shift = false; + fakeMouseEvent.MouseInput.Control = false; + fakeMouseEvent.MouseInput.ButtonStates = 0; + fakeMouseEvent.MouseInput.Event = EMIE_COUNT; + + switch (event.TouchInput.Event) + { + case ETIE_PRESSED_DOWN: + { + // We only work with the first for now.force opengl error + if ( TouchID == -1 ) + { + fakeMouseEvent.MouseInput.Event = EMIE_LMOUSE_PRESSED_DOWN; + + if (Device) + { + position2d touchPoint(event.TouchInput.X, event.TouchInput.Y); + IGUIElement * logo = Device->getGUIEnvironment()->getRootGUIElement()->getElementFromId ( GUI_IRR_LOGO ); + if ( logo && logo->isPointInside (touchPoint) ) + { + TouchID = event.TouchInput.ID; + SpriteToMove = logo; + SpriteStartRect = SpriteToMove->getRelativePosition(); + TouchStartPos = touchPoint; + } + } + } + break; + } + case ETIE_MOVED: + if ( TouchID == event.TouchInput.ID ) + { + fakeMouseEvent.MouseInput.Event = EMIE_MOUSE_MOVED; + fakeMouseEvent.MouseInput.ButtonStates = EMBSM_LEFT; + + if ( SpriteToMove && TouchID == event.TouchInput.ID ) + { + + position2d touchPoint(event.TouchInput.X, event.TouchInput.Y); + MoveSprite(touchPoint); + } + } + break; + case ETIE_LEFT_UP: + if ( TouchID == event.TouchInput.ID ) + { + fakeMouseEvent.MouseInput.Event = EMIE_LMOUSE_LEFT_UP; + + if ( SpriteToMove ) + { + TouchID = -1; + position2d touchPoint(event.TouchInput.X, event.TouchInput.Y); + MoveSprite(touchPoint); + SpriteToMove = 0; + } + } + break; + default: + break; + } + + if ( fakeMouseEvent.MouseInput.Event != EMIE_COUNT && Device ) + { + Device->postEventFromUser(fakeMouseEvent); + } + } + else if ( event.EventType == EET_GUI_EVENT ) + { + /* + Show and hide the soft input keyboard when an edit-box get's the focus. + */ + switch(event.GUIEvent.EventType) + { + case EGET_EDITBOX_ENTER: + if ( event.GUIEvent.Caller->getType() == EGUIET_EDIT_BOX ) + { + if( Device->getGUIEnvironment() ) + Device->getGUIEnvironment()->setFocus(NULL); + android::setSoftInputVisibility(AndroidApp, false); + } + break; + case EGET_ELEMENT_FOCUS_LOST: + if ( event.GUIEvent.Caller->getType() == EGUIET_EDIT_BOX ) + { + /* Unfortunatly this only works on some android devices. + On other devices Android passes through touch-input events when the virtual keyboard is clicked while blocking those events in areas where the keyboard isn't. + Very likely an Android bug as it only happens in certain cases (like Android Lollipop with landscape mode on MotoG, but also some reports from other devices). + Or maybe Irrlicht still does something wrong. + Can't figure it out so far - so be warned - with landscape mode you might be better off writing your own keyboard. + */ + android::setSoftInputVisibility(AndroidApp, false); + } + break; + case EGET_ELEMENT_FOCUSED: + if ( event.GUIEvent.Caller->getType() == EGUIET_EDIT_BOX ) + { + android::setSoftInputVisibility(AndroidApp, true); + } + break; + default: + break; + } + } + + return false; + } + + void MoveSprite(const irr::core::position2d &touchPos) + { + irr::core::position2d move(touchPos-TouchStartPos); + SpriteToMove->setRelativePosition(SpriteStartRect.UpperLeftCorner + move); + } + +private: + IrrlichtDevice * Device; + android_app* AndroidApp; + gui::IGUIElement * SpriteToMove; + core::rect SpriteStartRect; + core::position2d TouchStartPos; + s32 TouchID; +}; + +/* Mainloop. +*/ +void mainloop( IrrlichtDevice *device, IGUIStaticText * infoText ) +{ + u32 loop = 0; // loop is reset when the app is destroyed unlike runCounter + static u32 runCounter = 0; // static's seem to survive even an app-destroy message (not sure if that's guaranteed). + while(device->run()) + { + /* + The window seems to be always active in this setup. + That's because when it's not active Android will stop the code from running. + */ + if (device->isWindowActive()) + { + /* + Show FPS and some counters to show which parts of an app run + in different app-lifecycle states. + */ + if ( infoText ) + { + stringw str = L"FPS:"; + str += (s32)device->getVideoDriver()->getFPS(); + str += L" r:"; + str += runCounter; + str += L" l:"; + str += loop; + infoText->setText ( str.c_str() ); + } + + device->getVideoDriver()->beginScene(true, true, SColor(0,100,100,100)); + device->getSceneManager()->drawAll(); + device->getGUIEnvironment()->drawAll(); + device->getVideoDriver()->endScene (); + } + device->yield(); // probably nicer to the battery + ++runCounter; + ++loop; + } +} + +/* Main application code. */ +void android_main(android_app* app) +{ + // Make sure glue isn't stripped. + app_dummy(); + + /* + The receiver can already receive system events while createDeviceEx is called. + So we create it first. + */ + MyEventReceiver receiver(app); + + /* + Create the device. + You have currently the choice between 2 drivers: + EDT_OGLES1 is basically a opengl fixed function pipeline. + EDT_OGLES2 is a shader pipeline. Irrlicht comes with shaders to simulate + typical fixed function materials. For this to work the + corresponding shaders from the Irrlicht media/Shaders folder are + copied to the application assets folder (done in the Makefile). + */ + SIrrlichtCreationParameters param; +// param.DriverType = EDT_OGLES1; // android:glEsVersion in AndroidManifest.xml should be "0x00010000" (requesting 0x00020000 will also guarantee that ES1 works) + param.DriverType = EDT_OGLES2; // android:glEsVersion in AndroidManifest.xml should be "0x00020000" + param.WindowSize = dimension2d(300,300); // using 0,0 it will automatically set it to the maximal size + param.PrivateData = app; + param.Bits = 24; + param.ZBufferBits = 16; + param.AntiAlias = 0; + param. EventReceiver = &receiver; + + /* Logging is written to a file. So your application should disable all logging when you distribute your + application or it can fill up that file over time. + */ +#ifndef _DEBUG + param.LoggingLevel = ELL_NONE; +#endif + + IrrlichtDevice *device = createDeviceEx(param); + if (device == 0) + return; + + receiver.Init(device); + +// ANativeActivity_setWindowFlags(app->activity, AWINDOW_FLAG_FULLSCREEN, 0); + + IVideoDriver* driver = device->getVideoDriver(); + ISceneManager* smgr = device->getSceneManager(); + IGUIEnvironment* guienv = device->getGUIEnvironment(); + ILogger* logger = device->getLogger(); + IFileSystem * fs = device->getFileSystem(); + + /* Access to the Android native window. You often need this when accessing NDK functions like we are doing here. + Note that windowWidth/windowHeight have already subtracted things like the taskbar which your device might have, + so you get the real size of your render-window. + */ + ANativeWindow* nativeWindow = static_cast(driver->getExposedVideoData().OGLESAndroid.Window); + int32_t windowWidth = ANativeWindow_getWidth(app->window); + int32_t windowHeight = ANativeWindow_getHeight(app->window); + + /* Get display metrics. We are accessing the Java functions of the JVM directly in this case as there is no NDK function for that yet. + Checkout android_tools.cpp if you want to know how that is done. */ + irr::android::SDisplayMetrics displayMetrics; + memset(&displayMetrics, 0, sizeof displayMetrics); + irr::android::getDisplayMetrics(app, displayMetrics); + + /* For troubleshooting you can use the Irrlicht logger. + The Irrlicht logging messages are send to the Android logging system using the tag "Irrlicht". + They stay in a file there, so you can check them even after running your app. + You can watch them with the command: "adb logcat Irrlicht:V DEBUG:V *:S" + This means Irrlicht _V_erbose, debug messages verbose (p.E callstack on crashes) and all other messages _S_ilent. + Clean the logging file with: "adb logcat -c". + See http://developer.android.com/tools/debugging/debugging-log.html for more advanced log options. + */ + char strDisplay[1000]; + sprintf(strDisplay, "Window size:(%d/%d)\nDisplay size:(%d/%d)", windowWidth, windowHeight, displayMetrics.widthPixels, displayMetrics.heightPixels); + logger->log(strDisplay); + + core::dimension2d dim(driver->getScreenSize()); + sprintf(strDisplay, "getScreenSize:(%d/%d)", dim.Width, dim.Height); + logger->log(strDisplay); + + + /* Your media must be somewhere inside the assets folder. The assets folder is the root for the file system. + This example copies the media in the Android.mk makefile. */ + stringc mediaPath = "media/"; + + // The Android assets file-system does not know which sub-directories it has (blame google). + // So we have to add all sub-directories in assets manually. Otherwise we could still open the files, + // but existFile checks will fail (which are for example needed by getFont). + for ( u32 i=0; i < fs->getFileArchiveCount(); ++i ) + { + IFileArchive* archive = fs->getFileArchive(i); + if ( archive->getType() == EFAT_ANDROID_ASSET ) + { + archive->addDirectoryToFileList(mediaPath); + break; + } + } + + /* Set the font-size depending on your device. + dpi=dots per inch. 1 inch = 2.54 cm. */ + IGUISkin* skin = guienv->getSkin(); + IGUIFont* font = 0; + if ( displayMetrics.xdpi < 100 ) // just guessing some value where fontsize might start to get too small + font = guienv->getFont(mediaPath + "fonthaettenschweiler.bmp"); + else + font = guienv->getFont(mediaPath + "bigfont.png"); + if (font) + skin->setFont(font); + + // A field to show some text. Comment out stat->setText in run() if you want to see the dpi instead of the fps. + IGUIStaticText *text = guienv->addStaticText(stringw(displayMetrics.xdpi).c_str(), + rect(5,5,635,35), false, false, 0, GUI_INFO_FPS ); + guienv->addEditBox( L"", rect(5,40,475,80)); + + // add irrlicht logo + IGUIImage * logo = guienv->addImage(driver->getTexture(mediaPath + "irrlichtlogo3.png"), + core::position2d(5,85), true, 0, GUI_IRR_LOGO); + s32 minLogoWidth = windowWidth/3; + if ( logo && logo->getRelativePosition().getWidth() < minLogoWidth ) + { + /* Scale to make it better visible on high-res devices (we could also work with dpi here). + */ + logo->setScaleImage(true); + core::rect logoPos(logo->getRelativePosition()); + f32 scale = (f32)minLogoWidth/(f32)logoPos.getWidth(); + logoPos.LowerRightCorner.X = logoPos.UpperLeftCorner.X + minLogoWidth; + logoPos.LowerRightCorner.Y = logoPos.UpperLeftCorner.Y + (s32)((f32)logoPos.getHeight()*scale); + logo->setRelativePosition(logoPos); + } + + /* + Add a 3d model. Note that you might need to add light when using other models. + A copy of the model and it's textures must be inside the assets folder to be installed to Android. + In this example we do copy it to the assets folder in the Makefile jni/Android.mk + */ + IAnimatedMesh* mesh = smgr->getMesh(mediaPath + "dwarf.x"); + if (!mesh) + { + device->closeDevice(); + device->drop(); + return; + } + smgr->addAnimatedMeshSceneNode( mesh ); + + + /* + To look at the mesh, we place a camera. + */ + smgr->addCameraSceneNode(0, vector3df(15,40,-90), vector3df(0,30,0)); + + /* + Mainloop. Applications usually never quit themself in Android. The OS is responsible for that. + */ + mainloop(device, text); + + /* Cleanup */ + device->setEventReceiver(0); + device->closeDevice(); + device->drop(); +} + +#endif // defined(_IRR_ANDROID_PLATFORM_) + +/* +**/ diff --git a/examples/01.HelloWorld_Android/project.properties b/examples/01.HelloWorld_Android/project.properties new file mode 100755 index 00000000..5bf8b31b --- /dev/null +++ b/examples/01.HelloWorld_Android/project.properties @@ -0,0 +1 @@ +target = android-10 diff --git a/examples/01.HelloWorld_Android/readme.txt b/examples/01.HelloWorld_Android/readme.txt new file mode 100644 index 00000000..2a9d66f5 --- /dev/null +++ b/examples/01.HelloWorld_Android/readme.txt @@ -0,0 +1,95 @@ +------------ +REQUIREMENTS +------------ + +To use Android you need to have installed: +- Android SDK (from http://developer.android.com) +- Android NDK (from http://developer.android.com) +- ant (a build tool commonly used for Java) +- A Java jdk (for example openjdk-6-jdk) +- GNU Make 3.81 or later +- A recent version of awk +- On Windows you need to have Cygwin (at least version 1.7) installed + +---------------------------- +BUILDING Irrlicht & your App +---------------------------- + +1. Assign your Android SDK path to an ANDROID_HOME environment variable. +2. Add $ANDROID_HOME/tools and $ANDROID_HOME/platform-tools and the Android NDK main folder to your PATH environment variable. +3. Go to: source/Irrlicht/Android and call "ndk-build" or "ndk-build NDEBUG=1" +4. Go to: examples/01.HelloWorld_Android and call "ndk-build" or "ndk-build NDEBUG=1" +5. Call "ant debug" to create package +6. Connect device to PC (with USB debugging mode ON) or turn on emulator. +7. Call "adb -d install bin/HelloWorldMobile-debug.apk" (if you use emulator please add "-e" parameter instead of "-d") to install package on your device/emulator. + +Troubleshooting: + +Error: Unable to resolve project target 'android-10' +Solution: Run "android sdk" in sdk/tools and install API 10. + Alternatively you can probably (not yet tested) set another APP_PLATFORM + in the Application.mk's for the project and for Irrlicht. In this case you + should likely also change the android:minSdkVersion in the AndroidManifest.xml + +----- +FILES +----- + +AndroidManifest.xml: + Every Android application needs one of those to describe the needs of the application. + Must have exactly this name. + See http://developer.android.com/guide/topics/manifest/manifest-intro.html + +build.xml: + Ant build file to create the final package. + You might want to create a new one as described in the Android documentation: + http://developer.android.com/tools/projects/projects-cmdline.html + That will then also update project.properties. + +project.properties + Contains the build target (and maybe other project properties). Must exist. + +jni: + A folder by this name must exist below the folder where you have build.xml. + Usually it contains the native (c/c++) source files, but in our case we put + the source-files one level higher (with LOCAL_PATH in Android.mk). + +jni/Android.mk: + The Makefile for the project. + Source-files in the project are added to LOCAL_SRC_FILES + In the Irrlicht example it also copies the assets, but you can + also already create your project assets in the right place. + +jni/Application.mk: + Optional file which for example restricts which modules are installed and + where you can set specific target architectures. + More info about this can be found in the ndk docs. + +res: + A folder with resources which districuted with your application and can be accessed via ID's. + Unfortunately no direct NDK access to resources at the time of writing this. So you either have + to access them with java-code and copy to c++ somehow or you have to use hacks to read the format + directly (which is done by some apps, but not future-safe and google recommends not doing that). + Please check the official "App Resources" android developer documention, as this is rather complex. + We use it only for the application icons in this example. + +assets: + Files in here are distributed with your app. It's acting like a read-only file system. + +assets/media/Shaders: + Shader code needed by the OGLES2 driver to simulate a fixed function pipeline. + In the example this code is automatically copied within the Android.mk makefile. + The path where the shaders are searched is set in the IRR_OGLES2_SHADER_PATH define in IrrCompileConfig.h + The names are hardcoded so they have to be identical to those found in media/Shaders. + You can rewrite the shaders, but ensure to add some working shaders files by those names. + The OGLES1 driver doesn't need those files. + +obj: + All object and library files mentioned in the Android.mk are put in here before linking. + +libs: + Contains the binaries of your application after compilation. The application itself is a lib(probably because native code can't run directly but only as lib). + +src: + The src folder is needed when you have Java sources and should only contain .java and .aidl files. + Although the examples doesn't use Java the makefile creates this folder as the ant build.xml in the android sdk needs it. diff --git a/examples/01.HelloWorld_Android/res/drawable-hdpi/irr_icon.png b/examples/01.HelloWorld_Android/res/drawable-hdpi/irr_icon.png new file mode 100755 index 00000000..65813ad1 Binary files /dev/null and b/examples/01.HelloWorld_Android/res/drawable-hdpi/irr_icon.png differ diff --git a/examples/01.HelloWorld_Android/res/drawable-ldpi/irr_icon.png b/examples/01.HelloWorld_Android/res/drawable-ldpi/irr_icon.png new file mode 100755 index 00000000..11e3ae24 Binary files /dev/null and b/examples/01.HelloWorld_Android/res/drawable-ldpi/irr_icon.png differ diff --git a/examples/01.HelloWorld_Android/res/drawable-mdpi/irr_icon.png b/examples/01.HelloWorld_Android/res/drawable-mdpi/irr_icon.png new file mode 100755 index 00000000..b0fdc957 Binary files /dev/null and b/examples/01.HelloWorld_Android/res/drawable-mdpi/irr_icon.png differ diff --git a/examples/01.HelloWorld_Android/res/drawable-xhdpi/irr_icon.png b/examples/01.HelloWorld_Android/res/drawable-xhdpi/irr_icon.png new file mode 100755 index 00000000..89573a3c Binary files /dev/null and b/examples/01.HelloWorld_Android/res/drawable-xhdpi/irr_icon.png differ diff --git a/examples/01.HelloWorld_emscripten/Makefile b/examples/01.HelloWorld_emscripten/Makefile new file mode 100644 index 00000000..f60a678e --- /dev/null +++ b/examples/01.HelloWorld_emscripten/Makefile @@ -0,0 +1,98 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 01.HelloEmscripten +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +all_emscripten: EMSCRIPTEN=1 + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG + ifdef EMSCRIPTEN + LDFLAGS += -s DEMANGLE_SUPPORT=1 + endif + CXXFLAGS += -g -Wall +else + ifdef EMSCRIPTEN + LDFLAGS += -O3 + endif + CXXFLAGS += -O3 +endif +ifdef EMSCRIPTEN + CXXFLAGS += -std=gnu++11 -U__STRICT_ANSI__ +endif + +ifdef EMSCRIPTEN + all: all_emscripten +else + all: all_linux +endif + +# target specific settings +all_linux all_emscripten all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL +ifndef EMSCRIPTEN + LDFLAGS += -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +endif +all_linux clean_linux: SYSTEM=Linux +all_emscripten clean_emscripten: SYSTEM=emscripten +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +all_emscripten clean_emscripten: SUF=.html +all_emscripten: CXXFLAGS += -fno-exceptions -fno-rtti -fstrict-aliasing -std=gnu++11 -U__STRICT_ANSI__ +# Pass on a custom html file. +#all_emscripten: CXXFLAGS += --shell-file shell_minimal.html +all_emscripten: LDFLAGS += -lGL -lSDL --preload-file ../../media@/media -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=1 +#If you know the maximum memory (in bytes) which your application need then set it. It can speed things up a lot. +#all_emscripten: LDFLAGS += -s TOTAL_MEMORY=268435456 +# You need the FULL_ES2 when using EDT_OGLES2 driver +#all_emscripten: LDFLAGS += -s FULL_ES2=1 +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +# Enable compiling to WASM and not just asm.js (you have to set it in the engine Makefile as well) +ifdef EMSCRIPTEN + ifdef WASM + CXXFLAGS += -s WASM=1 + endif +endif + +emscripten: all_emscripten + +all_linux all_win32 all_emscripten static_win32: + $(warning Building...) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(Sources) -o $(DESTPATH) $(LDFLAGS) + +clean: clean_linux clean_win32 clean_emscripten + $(warning Cleaning...) + +clean_linux clean_win32: + @$(RM) $(DESTPATH) + +clean_emscripten: + @$(RM) $(BinPath)/$(Target).data + @$(RM) $(BinPath)/$(Target).html* + @$(RM) $(BinPath)/$(Target).js + + +.PHONY: all all_win32 all_emscripten static_win32 clean clean_linux clean_win32 clean_emscripten + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/01.HelloWorld_emscripten/main.cpp b/examples/01.HelloWorld_emscripten/main.cpp new file mode 100644 index 00000000..86b960da --- /dev/null +++ b/examples/01.HelloWorld_emscripten/main.cpp @@ -0,0 +1,240 @@ +/** Example 001 HelloWorld adapted to emscripten + +This Tutorial shows how to run code with emscripten. +Emscripten compiles c++ to asm.js to allow it running inside a webbrowser. +You have to setup the emscripten environment on your system first to use this. +*/ +#include +#include "exampleHelper.h" +#include +#include + +/* +The code in here is mostly similar to the usual HelloWorld. +You can find more information about it there. Here we mainly document the +differences needed for emscripten. +*/ + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +/* +This part not necessary for emscripten, only useful to keep it in +in case you want to run the same code on Windows with VS as well. +*/ +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup") +#endif + + +/* +Variables on the stack will stay intact between runs of one_iter() +*/ +IrrlichtDevice *device = 0; +IVideoDriver* driver = 0; +ISceneManager* smgr = 0; +IGUIEnvironment* guienv = 0; + +ICameraSceneNode* camera = 0; +dimension2d screenSize(640, 480); + +#ifdef __EMSCRIPTEN__ +/* + Handle changes in canvas size which are done with html/js. + Note that it's only OK for windowed so far, + the switch to fullscreen not yet working. + Also the emscripten_get_canvas_size might cause a slow-down + (but haven't found yet a way to avoid it with SDL1). + */ +void checkCanvasResize() +{ + int w, h, fs; + emscripten_get_canvas_size(&w, &h, &fs); + const core::dimension2d canvasDim(w,h); + if ( canvasDim != screenSize ) + { + screenSize = canvasDim; + driver->OnResize(canvasDim); + driver->setViewPort(irr::core::rect(0,0,w,h)); + + irr::f32 aspect = (irr::f32)w / (irr::f32)h; + camera->setAspectRatio(aspect); + } +} + + +/* + emscripten can't run things in an endless-loop or otherwise the browse will consider + the script to hang. +*/ +void one_iter() +{ + if(!device->run()) + { + // Could clean up here in theory, but not sure if it makes a difference + + /* + This tells emscripten to not run any further code. + */ + emscripten_cancel_main_loop(); + return; + } + + // In case you have a resizeable canvas (resized from html) + //checkCanvasResize(); + + driver->beginScene(ECBF_COLOR | ECBF_DEPTH, SColor(255,100,101,140)); + + smgr->drawAll(); + guienv->drawAll(); + + driver->endScene(); +} +#endif //__EMSCRIPTEN__ + + +/* + The main method is also run on emscripten. +*/ +int main() +{ + /* + Printing out the build date/time is very useful to find troubles with unexpected browser-caches. + */ + printf("Build-date: %s %s\n", __DATE__, __TIME__); + + SIrrlichtCreationParameters parameters; + /* + Create device flags for emscripten are still experimental + and might not all work. + + - deviceType: You can to use EDT_OGLES2 or EDT_WEBGL1 on emscripten. + EDT_WEBGL1 is better optimized but does not yet support all options. + EDT_OGLES2 needs -s FULL_ES2=1 as linker flag in the Makefile. + */ +#ifndef __EMSCRIPTEN__ + parameters.DriverType = EDT_OGLES2; +#else //__EMSCRIPTEN__ + parameters.DriverType = EDT_WEBGL1; +#endif //__EMSCRIPTEN__ + + parameters.LoggingLevel = ELL_DEBUG; + parameters.WindowSize = screenSize; + parameters.Stencilbuffer = false; + parameters.AntiAlias = 4; + + device = createDeviceEx(parameters); + + if (!device) + return 1; + + /* + Window caption will set the title-text in the browser. + */ + device->setWindowCaption(L"Hello World! - Irrlicht Engine Demo"); + + /* + Get a pointer to the VideoDriver, the SceneManager and the graphical + user interface environment, so that we do not always have to write + device->getVideoDriver(), device->getSceneManager(), or + device->getGUIEnvironment(). + */ + driver = device->getVideoDriver(); + smgr = device->getSceneManager(); + guienv = device->getGUIEnvironment(); + + /* + We add a hello world label to the window, using the GUI environment. + The text is placed at the position (10,10) as top left corner and + (260,22) as lower right corner. + */ + guienv->addStaticText(L"Hello World! This is Irrlicht on emscripten!", + rect(10,10,260,22), true); + + /* + Get a media path dedicated for your platform. + We tell emscripten to copy the media folder in the Makefile with: + "--preload-file ../../media@/media" + That copies our ../../media folder in a .data + file which is loaded by the browser. It can then be accessed there + by "/media" name (that's the parameter after the '@'). + Note that usually you would try to copy only as many files + as absolutely necessary to reduce start-up times. + */ + const io::path mediaPath = getExampleMediaPath(); + + /* + Make a model called Sydney show up. + */ + IAnimatedMesh* mesh = smgr->getMesh(mediaPath + "sydney.md2"); + if (!mesh) + { + device->drop(); + return 1; + } + IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh ); + + /* + Disable lighting because we do not have a dynamic light in here, and + the mesh would be totally black otherwise. + Set the frame loop such that the predefined STAND animation is used. + Add a texture to the model. + */ + if (node) + { + node->setMaterialFlag(EMF_LIGHTING, false); + node->setMD2Animation(scene::EMAT_STAND); + node->setMaterialTexture( 0, driver->getTexture(mediaPath + "sydney.bmp") ); + } + + /* + To look at the mesh, we place a camera into 3d space at the position + (0, 30, -40). The camera looks from there to (0,5,0), which is + approximately the place where our md2 model is. + */ + camera = smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0)); + +#ifndef __EMSCRIPTEN__ // this part only so you can run the same code on desktop + /* + On desktop we run and endless loop until the user closes the window or + presses ALT+F4 (or whatever keycode closes a window). + */ + while(device->run()) + { + driver->beginScene(ECBF_COLOR | ECBF_DEPTH, SColor(255,100,101,140)); + + smgr->drawAll(); + guienv->drawAll(); + + driver->endScene(); + } + device->drop(); + +#else // __EMSCRIPTEN__ + + /* + Setting fps to 0 or a negative value will use the browser’s + requestAnimationFrame mechanism to call the main loop function. + Emscripten documentation recommends to do that, but you can also set + another fps value and the browser will try to call the main-loop + fps times per second. + The simulate_infinite_loop tells emscripten that this is an application + which will simulate an infinite loop. There is also a flag in the + Makefile about that: -s NO_EXIT_RUNTIME=1 + */ + int fps = 0; + int simulate_infinite_loop = 1; + emscripten_set_main_loop(one_iter, fps, simulate_infinite_loop); +#endif //__EMSCRIPTEN__ + + return 0; +} + +/* +That's it. Compile and run. +**/ diff --git a/examples/01.HelloWorld_emscripten/readme.txt b/examples/01.HelloWorld_emscripten/readme.txt new file mode 100644 index 00000000..e1cfb5b2 --- /dev/null +++ b/examples/01.HelloWorld_emscripten/readme.txt @@ -0,0 +1,24 @@ +Emscripten is a project to compile c/c++ code int the asm.js format which can be run in some browsers. +See http://kripken.github.io/emscripten-site for more information. + +emscripten support for Irrlicht is a work in process. Use at your own risk. +Might take work and knowledge to get it running. + +------------ +REQUIREMENTS +------------ +You have to install the emscripten environment. + +---------------------------- +BUILDING Irrlicht & your App +---------------------------- + +Linux: +Go into source/Irrlicht folder and call: +emmake make emscripten + + +Go into examples/01.HelloWord_emscripten folder and call: +emmake make all_emscripten + +Note: The shell_minimal.html is currently not used (as resizing isn't working yet correctly), but can be enabled in the Makefile. diff --git a/examples/01.HelloWorld_emscripten/shell_minimal.html b/examples/01.HelloWorld_emscripten/shell_minimal.html new file mode 100644 index 00000000..15d8b3bf --- /dev/null +++ b/examples/01.HelloWorld_emscripten/shell_minimal.html @@ -0,0 +1,180 @@ + + + + + + Emscripten-Generated Code + + + + + + + + + + +
+
emscripten
+
Downloading...
+
+ +
+
+ +
+
+
+ Resize canvas + Lock/hide mouse pointer +     + +
+ +
+ +
+ + {{{ SCRIPT }}} + + diff --git a/examples/01.HelloWorld_iOS/Assets.xcassets/AppIcon.appiconset/Contents.json b/examples/01.HelloWorld_iOS/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..36d2c80d --- /dev/null +++ b/examples/01.HelloWorld_iOS/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/examples/01.HelloWorld_iOS/HelloWorld_iOS.xcodeproj/project.pbxproj b/examples/01.HelloWorld_iOS/HelloWorld_iOS.xcodeproj/project.pbxproj new file mode 100644 index 00000000..18933c8d --- /dev/null +++ b/examples/01.HelloWorld_iOS/HelloWorld_iOS.xcodeproj/project.pbxproj @@ -0,0 +1,302 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E172FF01C1DB99B0024464F /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E172FEF1C1DB99B0024464F /* UIKit.framework */; }; + 5E172FF21C1DB9C80024464F /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E172FF11C1DB9C80024464F /* CoreMotion.framework */; }; + 5E172FF41C1DBA610024464F /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E172FF31C1DBA610024464F /* OpenGLES.framework */; }; + 5E172FF81C1DBAC30024464F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E172FF71C1DBAC30024464F /* Foundation.framework */; }; + 5E172FFC1C1DBB280024464F /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E172FFB1C1DBB280024464F /* QuartzCore.framework */; }; + 5E6AC1831C1DA8A100DADD92 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E6AC1821C1DA8A100DADD92 /* main.cpp */; }; + 5E6AC1881C1DA9C000DADD92 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E6AC1871C1DA9C000DADD92 /* media */; }; + 5E6AC18B1C1DAA3100DADD92 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5E6AC18A1C1DAA3100DADD92 /* Assets.xcassets */; }; + 5E6AC18D1C1DAD9500DADD92 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E6AC18C1C1DAD9500DADD92 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E172FEF1C1DB99B0024464F /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 5E172FF11C1DB9C80024464F /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = System/Library/Frameworks/CoreMotion.framework; sourceTree = SDKROOT; }; + 5E172FF31C1DBA610024464F /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; + 5E172FF71C1DBAC30024464F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 5E172FFB1C1DBB280024464F /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + 5E6AC1821C1DA8A100DADD92 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E6AC1871C1DA9C000DADD92 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; + 5E6AC1891C1DA9CE00DADD92 /* 28.HelloWorld_iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 28.HelloWorld_iOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E6AC18A1C1DAA3100DADD92 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 5E6AC18C1C1DAD9500DADD92 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/iOS/libIrrlicht.a; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E6AC1651C1DA6CF00DADD92 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E172FF21C1DB9C80024464F /* CoreMotion.framework in Frameworks */, + 5E172FF81C1DBAC30024464F /* Foundation.framework in Frameworks */, + 5E172FF41C1DBA610024464F /* OpenGLES.framework in Frameworks */, + 5E172FF01C1DB99B0024464F /* UIKit.framework in Frameworks */, + 5E172FFC1C1DBB280024464F /* QuartzCore.framework in Frameworks */, + 5E6AC18D1C1DAD9500DADD92 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E6AC15F1C1DA6CF00DADD92 = { + isa = PBXGroup; + children = ( + 5E6AC1821C1DA8A100DADD92 /* main.cpp */, + 5E6AC1851C1DA91500DADD92 /* Libraries */, + 5E6AC1841C1DA90B00DADD92 /* Products */, + 5E6AC1861C1DA91E00DADD92 /* Resources */, + ); + sourceTree = ""; + }; + 5E6AC1841C1DA90B00DADD92 /* Products */ = { + isa = PBXGroup; + children = ( + 5E6AC1891C1DA9CE00DADD92 /* 28.HelloWorld_iOS.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E6AC1851C1DA91500DADD92 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E172FF11C1DB9C80024464F /* CoreMotion.framework */, + 5E172FF71C1DBAC30024464F /* Foundation.framework */, + 5E172FF31C1DBA610024464F /* OpenGLES.framework */, + 5E172FEF1C1DB99B0024464F /* UIKit.framework */, + 5E172FFB1C1DBB280024464F /* QuartzCore.framework */, + 5E6AC18C1C1DAD9500DADD92 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E6AC1861C1DA91E00DADD92 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E6AC18A1C1DAA3100DADD92 /* Assets.xcassets */, + 5E6AC1871C1DA9C000DADD92 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E6AC1671C1DA6CF00DADD92 /* 28.HelloWorld_iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E6AC17F1C1DA6D000DADD92 /* Build configuration list for PBXNativeTarget "28.HelloWorld_iOS" */; + buildPhases = ( + 5E6AC1641C1DA6CF00DADD92 /* Sources */, + 5E6AC1651C1DA6CF00DADD92 /* Frameworks */, + 5E6AC1661C1DA6CF00DADD92 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 28.HelloWorld_iOS; + productName = 28.HelloWorld_iOS; + productReference = 5E6AC1891C1DA9CE00DADD92 /* 28.HelloWorld_iOS.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E6AC1601C1DA6CF00DADD92 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E6AC1671C1DA6CF00DADD92 = { + CreatedOnToolsVersion = 7.1.1; + }; + }; + }; + buildConfigurationList = 5E6AC1631C1DA6CF00DADD92 /* Build configuration list for PBXProject "HelloWorld_iOS" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E6AC15F1C1DA6CF00DADD92; + productRefGroup = 5E6AC15F1C1DA6CF00DADD92; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E6AC1671C1DA6CF00DADD92 /* 28.HelloWorld_iOS */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E6AC1661C1DA6CF00DADD92 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E6AC18B1C1DAA3100DADD92 /* Assets.xcassets in Resources */, + 5E6AC1881C1DA9C000DADD92 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E6AC1641C1DA6CF00DADD92 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E6AC1831C1DA8A100DADD92 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E6AC17D1C1DA6D000DADD92 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5E6AC17E1C1DA6D000DADD92 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5E6AC1801C1DA6D000DADD92 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + HEADER_SEARCH_PATHS = "$(SRCROOT)/../../include"; + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_ios.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/iOS"; + PRODUCT_BUNDLE_IDENTIFIER = "org.irrlicht.-8-HelloWorld-iOS"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 5E6AC1811C1DA6D000DADD92 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + HEADER_SEARCH_PATHS = "$(SRCROOT)/../../include"; + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_ios.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/iOS"; + PRODUCT_BUNDLE_IDENTIFIER = "org.irrlicht.-8-HelloWorld-iOS"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E6AC1631C1DA6CF00DADD92 /* Build configuration list for PBXProject "HelloWorld_iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E6AC17D1C1DA6D000DADD92 /* Debug */, + 5E6AC17E1C1DA6D000DADD92 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E6AC17F1C1DA6D000DADD92 /* Build configuration list for PBXNativeTarget "28.HelloWorld_iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E6AC1801C1DA6D000DADD92 /* Debug */, + 5E6AC1811C1DA6D000DADD92 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E6AC1601C1DA6CF00DADD92 /* Project object */; +} diff --git a/examples/01.HelloWorld_iOS/HelloWorld_iOS.xcodeproj/xcshareddata/xcschemes/28.HelloWorld_iOS.xcscheme b/examples/01.HelloWorld_iOS/HelloWorld_iOS.xcodeproj/xcshareddata/xcschemes/28.HelloWorld_iOS.xcscheme new file mode 100644 index 00000000..61feff08 --- /dev/null +++ b/examples/01.HelloWorld_iOS/HelloWorld_iOS.xcodeproj/xcshareddata/xcschemes/28.HelloWorld_iOS.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/01.HelloWorld_iOS/main.cpp b/examples/01.HelloWorld_iOS/main.cpp new file mode 100644 index 00000000..93b9405f --- /dev/null +++ b/examples/01.HelloWorld_iOS/main.cpp @@ -0,0 +1,62 @@ +#include +#include "exampleHelper.h" + +using namespace irr; + +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +// It's important for iOS projects to use 'irrlicht_main' instead of standard 'main' function. + +void irrlicht_main() +{ + IrrlichtDevice *device = createDevice(EDT_OGLES2, dimension2d(0, 0), 16, false, false, false, 0); + + if (!device) + return; + + device->setWindowCaption(L"Hello World! - Irrlicht Engine Demo"); + + IVideoDriver* driver = device->getVideoDriver(); + ISceneManager* smgr = device->getSceneManager(); + IGUIEnvironment* guienv = device->getGUIEnvironment(); + + guienv->addStaticText(L"Hello World! This is the Irrlicht Software renderer!", rect(10,10,260,22), true); + + const io::path mediaPath = getExampleMediaPath(); + + IAnimatedMesh* mesh = smgr->getMesh(mediaPath + "sydney.md2"); + + if (!mesh) + { + device->drop(); + return; + } + + IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh ); + + if (node) + { + node->setMaterialFlag(EMF_LIGHTING, false); + node->setMD2Animation(scene::EMAT_STAND); + node->setMaterialTexture( 0, driver->getTexture(mediaPath + "sydney.bmp") ); + } + + smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0)); + + while (device->run()) + if (device->isWindowActive()) + { + driver->beginScene(ECBF_COLOR | ECBF_DEPTH, SColor(255,255,255,255)); + + smgr->drawAll(); + guienv->drawAll(); + + driver->endScene(); + } + + device->drop(); +} diff --git a/examples/02.Quake3Map/Makefile b/examples/02.Quake3Map/Makefile new file mode 100644 index 00000000..10f2fcd7 --- /dev/null +++ b/examples/02.Quake3Map/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 02.Quake3Map +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/02.Quake3Map/Quake3Map.cbp b/examples/02.Quake3Map/Quake3Map.cbp new file mode 100644 index 00000000..2d54a9c1 --- /dev/null +++ b/examples/02.Quake3Map/Quake3Map.cbp @@ -0,0 +1,58 @@ + + + + + + diff --git a/examples/02.Quake3Map/Quake3Map.vcproj b/examples/02.Quake3Map/Quake3Map.vcproj new file mode 100644 index 00000000..4416fbb4 --- /dev/null +++ b/examples/02.Quake3Map/Quake3Map.vcproj @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/02.Quake3Map/Quake3Map.xcodeproj/project.pbxproj b/examples/02.Quake3Map/Quake3Map.xcodeproj/project.pbxproj new file mode 100644 index 00000000..e9ef2605 --- /dev/null +++ b/examples/02.Quake3Map/Quake3Map.xcodeproj/project.pbxproj @@ -0,0 +1,326 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 02.Quake3Map.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 02.Quake3Map.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 02.Quake3Map.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 02.Quake3Map */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "02.Quake3Map" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 02.Quake3Map; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 02.Quake3Map.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Quake3Map" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 02.Quake3Map */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = "org.irrlicht.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = "org.irrlicht.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Quake3Map" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "02.Quake3Map" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/02.Quake3Map/Quake3Map.xcodeproj/xcshareddata/xcschemes/02.Quake3Map.xcscheme b/examples/02.Quake3Map/Quake3Map.xcodeproj/xcshareddata/xcschemes/02.Quake3Map.xcscheme new file mode 100644 index 00000000..68dd239a --- /dev/null +++ b/examples/02.Quake3Map/Quake3Map.xcodeproj/xcshareddata/xcschemes/02.Quake3Map.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/02.Quake3Map/Quake3Map_vc10.vcxproj b/examples/02.Quake3Map/Quake3Map_vc10.vcxproj new file mode 100644 index 00000000..f45673aa --- /dev/null +++ b/examples/02.Quake3Map/Quake3Map_vc10.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 02.Quake3Map + {D1A464A2-D479-458C-98A2-60965D823CD1} + Quake3Map + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Quake3Map.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\02.Quake3Map.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Quake3Map.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\02.Quake3Map.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Quake3Map.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\02.Quake3Map.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Quake3Map.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\02.Quake3Map.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/02.Quake3Map/Quake3Map_vc11.vcxproj b/examples/02.Quake3Map/Quake3Map_vc11.vcxproj new file mode 100644 index 00000000..f45673aa --- /dev/null +++ b/examples/02.Quake3Map/Quake3Map_vc11.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 02.Quake3Map + {D1A464A2-D479-458C-98A2-60965D823CD1} + Quake3Map + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Quake3Map.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\02.Quake3Map.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Quake3Map.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\02.Quake3Map.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Quake3Map.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\02.Quake3Map.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Quake3Map.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\02.Quake3Map.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/02.Quake3Map/Quake3Map_vc12.vcxproj b/examples/02.Quake3Map/Quake3Map_vc12.vcxproj new file mode 100644 index 00000000..042060f3 --- /dev/null +++ b/examples/02.Quake3Map/Quake3Map_vc12.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 02.Quake3Map + {D1A464A2-D479-458C-98A2-60965D823CD1} + Quake3Map + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Quake3Map.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\02.Quake3Map.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Quake3Map.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\02.Quake3Map.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Quake3Map.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\02.Quake3Map.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Quake3Map.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\02.Quake3Map.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/02.Quake3Map/Quake3Map_vc14.vcxproj b/examples/02.Quake3Map/Quake3Map_vc14.vcxproj new file mode 100644 index 00000000..df7001d1 --- /dev/null +++ b/examples/02.Quake3Map/Quake3Map_vc14.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 02.Quake3Map + {D1A464A2-D479-458C-98A2-60965D823CD1} + Quake3Map + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Quake3Map.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\02.Quake3Map.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Quake3Map.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\02.Quake3Map.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Quake3Map.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\02.Quake3Map.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Quake3Map.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\02.Quake3Map.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/02.Quake3Map/main.cpp b/examples/02.Quake3Map/main.cpp new file mode 100644 index 00000000..042b70fe --- /dev/null +++ b/examples/02.Quake3Map/main.cpp @@ -0,0 +1,185 @@ +/** Example 002 Quake3Map + +This tutorial shows how to load a Quake 3 map into the engine, create a +SceneNode for optimizing the speed of rendering, and how to create a user +controlled camera. + +Please note that you should know the basics of the engine before starting this +tutorial. Just take a short look at the first tutorial, if you haven't done +this yet: http://irrlicht.sourceforge.net/docu/example001.html + +Lets start like the HelloWorld example: We include the irrlicht header files +and an additional file to be able to ask the user for a driver type using the +console. +*/ +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +/* +As already written in the HelloWorld example, in the Irrlicht Engine everything +can be found in the namespace 'irr'. To get rid of the irr:: in front of the +name of every class, we tell the compiler that we use that namespace from now +on, and we will not have to write that 'irr::'. There are 5 other sub +namespaces 'core', 'scene', 'video', 'io' and 'gui'. Unlike in the HelloWorld +example, we do not call 'using namespace' for these 5 other namespaces, because +in this way you will see what can be found in which namespace. But if you like, +you can also include the namespaces like in the previous example. +*/ +using namespace irr; + +/* +Again, to be able to use the Irrlicht.DLL file, we need to link with the +Irrlicht.lib. We could set this option in the project settings, but to make it +easy, we use a pragma comment lib: +*/ +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +/* +OK, lets start. Again, we use the main() method as start, not the WinMain(). +*/ +int main() +{ + /* + Like in the HelloWorld example, we create an IrrlichtDevice with + createDevice(). The difference now is that we ask the user to select + which video driver to use. The Software device might be + too slow to draw a huge Quake 3 map, but just for the fun of it, we make + this decision possible, too. + */ + + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(true); + if (driverType==video::EDT_COUNT) + return 1; + + // create device and exit if creation failed + + IrrlichtDevice *device = + createDevice(driverType, core::dimension2d(640, 480)); + + if (device == 0) + return 1; // could not create selected driver. + + /* + Get a pointer to the video driver and the SceneManager so that + we do not always have to call irr::IrrlichtDevice::getVideoDriver() and + irr::IrrlichtDevice::getSceneManager(). + */ + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + + /* + To display the Quake 3 map, we first need to load it. Quake 3 maps + are packed into .pk3 files which are nothing else than .zip files. + So we add the .pk3 file to our irr::io::IFileSystem. After it was added, + we can read from the files in that archive as if they were stored on disk. + */ + device->getFileSystem()->addFileArchive(getExampleMediaPath() + "map-20kdm2.pk3"); + + /* + Now we can load the mesh by calling irr::scene::ISceneManager::getMesh(). + We get a pointer returned to an irr::scene::IAnimatedMesh. Quake 3 maps are + not really animated, they are only a chunk of static geometry with + some materials attached. Hence the IAnimatedMesh consists of only one + frame, so we get the "first frame" of the "animation", which is our + quake level and create an Octree scene node with it, using + irr::scene::ISceneManager::addOctreeSceneNode(). + The Octree optimizes the scene a little bit, trying to draw only geometry + which is currently visible. An alternative to the Octree would be a + irr::scene::IMeshSceneNode, which would always draw the complete + geometry of the mesh, without optimization. Try it: Use + irr::scene::ISceneManager::addMeshSceneNode() instead of + addOctreeSceneNode() and compare the primitives drawn by the video + driver. (There is a irr::video::IVideoDriver::getPrimitiveCountDrawn() + method in the irr::video::IVideoDriver class). Note that this + optimization with the Octree is only useful when drawing huge meshes + consisting of lots of geometry and if users can't see the whole scene at + once. + */ + scene::IAnimatedMesh* mesh = smgr->getMesh("20kdm2.bsp"); + scene::ISceneNode* node = 0; + + if (mesh) + node = smgr->addOctreeSceneNode(mesh->getMesh(0), 0, -1, 1024); +// node = smgr->addMeshSceneNode(mesh->getMesh(0)); + + /* + Because the level was not modeled around the origin (0,0,0), we + translate the whole level a little bit. This is done on + irr::scene::ISceneNode level using the methods + irr::scene::ISceneNode::setPosition() (in this case), + irr::scene::ISceneNode::setRotation(), and + irr::scene::ISceneNode::setScale(). + */ + if (node) + node->setPosition(core::vector3df(-1300,-144,-1249)); + + /* + Now we need a camera to look at the Quake 3 map. + We want to create a user controlled camera. There are some + cameras available in the Irrlicht engine. For example the + MayaCamera which can be controlled like the camera in Maya: + Rotate with left mouse button pressed, Zoom with both buttons pressed, + translate with right mouse button pressed. This could be created with + irr::scene::ISceneManager::addCameraSceneNodeMaya(). But for this + example, we want to create a camera which behaves like the ones in + first person shooter games (FPS) and hence use + irr::scene::ISceneManager::addCameraSceneNodeFPS(). + */ + smgr->addCameraSceneNodeFPS(); + + /* + The mouse cursor needs not be visible, so we hide it via the + irr::IrrlichtDevice::ICursorControl. + */ + device->getCursorControl()->setVisible(false); + + /* + Everything is set up, so lets draw it. We also write the current + frames per second and the primitives drawn into the caption of the + window. The test for irr::IrrlichtDevice::isWindowActive() is optional, + but prevents the engine to grab the mouse cursor after task switching + when other programs are active. The call to irr::IrrlichtDevice::yield() + will avoid the busy loop to eat up all CPU cycles when the window is not + active. + */ + int lastFPS = -1; + + while(device->run()) + { + if (device->isWindowActive()) + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,200,200,200)); + smgr->drawAll(); + driver->endScene(); + + int fps = driver->getFPS(); + + if (lastFPS != fps) + { + core::stringw str = L"Irrlicht Engine - Quake 3 Map example ["; + str += driver->getName(); + str += "] FPS:"; + str += fps; + + device->setWindowCaption(str.c_str()); + lastFPS = fps; + } + } + else + device->yield(); + } + + /* + In the end, delete the Irrlicht device. + */ + device->drop(); + return 0; +} + +/* +That's it. Compile and play around with the program. +**/ diff --git a/examples/02.Quake3Map/tutorial.html b/examples/02.Quake3Map/tutorial.html new file mode 100644 index 00000000..1858b866 --- /dev/null +++ b/examples/02.Quake3Map/tutorial.html @@ -0,0 +1,181 @@ + + +Irrlicht Engine Tutorial + + + + +
+ + + + + + + + +
+ Tutorial 2.Quake3Map
+

This Tutorial shows how to load a Quake 3 map into the engine, create + a SceneNode for optimizing the speed of rendering and how to create + a user controlled camera. Please note that you should know the basics + of the engine before starting this tutorial, just take a short look + at the first tutorial, 1.HelloWorld, if you haven't done this yet.
+ The result of this example will look like this:

+


+

+
+
+ + + + + + + +
+ Lets start!
+

Lets start like the HelloWorld example: We include the irrlicht header + files and an additional file to be able
+ to ask the user for a driver type using the console.

+ + + + +
#include <irrlicht.h>
#include <iostream>
+

As already written in the HelloWorld example, in the Irrlicht Engine, + everything can be found in the namespace 'irr'. To get rid of the irr:: + in front of the name of every class, we tell the compiler that we use + that namespace from now on, and we will not have to write that 'irr::'.
+ There are 5 other sub namespaces 'core', 'scene', 'video', 'io' and + 'gui'. Unlike in the HelloWorld example, we do not a 'using namespace' + for these 5 other namespaces because in this way you will see what can + be found in which namespace. But if you like, you can also include the + namespaces like in the previous example. Code just like you want to.

+ + + + +
using namespace irr;
+

Again, to be able to use the Irrlicht.DLL file, we need to link with + the Irrlicht.lib. We could set this option in the project settings, + but to make it easy, we use a pragma comment lib:

+ + + + +
#pragma comment(lib, "Irrlicht.lib")
+ +
+

Ok, lets start. Again, we use the main() method as start, not the WinMain(), + because its shorter to write.

+ + + + +
int main()
{
+

Like in the HelloWorld example, we create an IrrlichtDevice with createDevice(). + The difference now is that we ask the user to select which hardware accelerated + driver to use. The Software device would be too slow to draw a huge Quake + 3 map, but just for the fun of it, we make this decision possible too.

+ + + + +
// ask user for driver

video::E_DRIVER_TYPE driverType = video::EDT_DIRECT3D9;

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) Apfelbaum Software Renderer\n"\
" (f) NullDevice\n (otherKey) exit\n\n");
+char i;
std::cin >> i;

switch(i)
{
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;
default: return 1;
}

// create device and exit if creation failed

IrrlichtDevice *device =
createDevice(driverType, core::dimension2d<s32>(640, 480));

if (device == 0)
return 1;
+

Get a pointer to the video driver and the SceneManager so that we do + not always have to write device->getVideoDriver() and device->getSceneManager().

+ + + + +
video::IVideoDriver* driver = device->getVideoDriver();
+scene::ISceneManager* smgr = device->getSceneManager();
+

To display the Quake 3 map, we first need to load it. Quake 3 maps are + packed into .pk3 files wich are nothing other than .zip files. So we add + the .pk3 file to our FileSystem. After it was added, we are able to read + from the files in that archive as they would directly be stored on disk.

+ + + + +
device->getFileSystem()->addZipFileArchive("../../media/map-20kdm2.pk3");
+

Now we can load the mesh by calling getMesh(). We get a pointer returned + to a IAnimatedMesh. As you know, Quake 3 maps are not really animated, + they are only a huge chunk of static geometry with some materials attached. + Hence the IAnimated mesh consists of only one frame,
+ so we get the "first frame" of the "animation", which + is our quake level and create an OctTree scene node with it, using addOctTreeSceneNode(). + The OctTree optimizes the scene a little bit, trying to draw only geometry + which is currently visible. An alternative to the OctTree would be a AnimatedMeshSceneNode, + which would draw always the complete geometry of the mesh, without optimization. + Try it out: Write addAnimatedMeshSceneNode instead of addOctTreeSceneNode + and compare the primitives drawed by the video driver. (There is a getPrimitiveCountDrawed() + method in the IVideoDriver class). Note that this optimization with the + Octree is only useful when drawing huge meshes consiting of lots of geometry.

+ + + + +
scene::IAnimatedMesh* mesh = smgr->getMesh("20kdm2.bsp");
scene::ISceneNode* node = 0; + +if (mesh)
node = smgr->addOctTreeSceneNode(mesh->getMesh(0));
+

Because the level was modelled not around the origin (0,0,0), we translate + the whole level a little bit.

+ + + + +
if (node)
node->setPosition(core::vector3df(-1300,-144,-1249));
+

Now we only need a Camera to look at the Quake 3 map. And we want to + create a user controlled camera. There are some different cameras available + in the Irrlicht engine. For example the Maya Camera which can be controlled + compareable to the camera in Maya: Rotate with left mouse button pressed, + Zoom with both buttons pressed,
+ translate with right mouse button pressed. This could be created with + addCameraSceneNodeMaya(). But for this example, we want to create a camera + which behaves like the ones in first person shooter games (FPS):

+ + + + +
smgr->addCameraSceneNodeFPS();
+

The mouse cursor needs not to be visible, so we make it invisible.

+ + + + +
device->getCursorControl()->setVisible(false);
+

We have done everything, so lets draw it. We also write the current frames + per second and the drawn primitives to the caption of the window. The + 'if (device->isWindowActive())' line is optional, but prevents the + engine render to set the position of the mouse cursor after task switching + when other program are active.

+ + + + +
int lastFPS = -1;
+
while(device->run())
+{
+  driver->beginScene(true, true, video::SColor(0,200,200,200));
+  smgr->drawAll();
+  driver->endScene();
+
  int fps = driver->getFPS();
+
  if (lastFPS != fps)
+  {
+     core::stringw str = L"Irrlicht Engine - Quake 3 Map example [";
str += driver->getName();
str += "] FPS:";
str += fps;
device->setWindowCaption(str.c_str());
lastFPS = fps; + } +}
+

In the end, delete the Irrlicht device.

+ + + + +
  device->drop();
return 0;
}
+

That's it. Compile and play around with the program.

+

 

+

 

+ + diff --git a/examples/03.CustomSceneNode/CustomSceneNode.cbp b/examples/03.CustomSceneNode/CustomSceneNode.cbp new file mode 100644 index 00000000..4295fbc3 --- /dev/null +++ b/examples/03.CustomSceneNode/CustomSceneNode.cbp @@ -0,0 +1,58 @@ + + + + + + diff --git a/examples/03.CustomSceneNode/CustomSceneNode.vcproj b/examples/03.CustomSceneNode/CustomSceneNode.vcproj new file mode 100644 index 00000000..890d308b --- /dev/null +++ b/examples/03.CustomSceneNode/CustomSceneNode.vcproj @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/03.CustomSceneNode/CustomSceneNode.xcodeproj/project.pbxproj b/examples/03.CustomSceneNode/CustomSceneNode.xcodeproj/project.pbxproj new file mode 100644 index 00000000..9ac9c7c1 --- /dev/null +++ b/examples/03.CustomSceneNode/CustomSceneNode.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 03.CustomSceneNode.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 03.CustomSceneNode.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 03.CustomSceneNode.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 03.CustomSceneNode */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "03.CustomSceneNode" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 03.CustomSceneNode; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 03.CustomSceneNode.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "CustomSceneNode" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 03.CustomSceneNode */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "CustomSceneNode" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "03.CustomSceneNode" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/03.CustomSceneNode/CustomSceneNode.xcodeproj/xcshareddata/xcschemes/03.CustomSceneNode.xcscheme b/examples/03.CustomSceneNode/CustomSceneNode.xcodeproj/xcshareddata/xcschemes/03.CustomSceneNode.xcscheme new file mode 100644 index 00000000..e186f6d6 --- /dev/null +++ b/examples/03.CustomSceneNode/CustomSceneNode.xcodeproj/xcshareddata/xcschemes/03.CustomSceneNode.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/03.CustomSceneNode/CustomSceneNode_vc10.vcxproj b/examples/03.CustomSceneNode/CustomSceneNode_vc10.vcxproj new file mode 100644 index 00000000..77e9e6e1 --- /dev/null +++ b/examples/03.CustomSceneNode/CustomSceneNode_vc10.vcxproj @@ -0,0 +1,247 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 03.CustomSceneNode + {171CCDFA-C140-4956-8EB7-F0168F4521D3} + CustomSceneNode + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/CustomSceneNode.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\03.CustomSceneNode.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/CustomSceneNode.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\03.CustomSceneNode.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/CustomSceneNode.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + .\Release/CustomSceneNode.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\03.CustomSceneNode.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + .\Release/CustomSceneNode.pdb + Console + false + + + + + + + .\Release/CustomSceneNode.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + .\Release/CustomSceneNode.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\03.CustomSceneNode.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + .\Release/CustomSceneNode.pdb + Console + false + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/03.CustomSceneNode/CustomSceneNode_vc11.vcxproj b/examples/03.CustomSceneNode/CustomSceneNode_vc11.vcxproj new file mode 100644 index 00000000..77e9e6e1 --- /dev/null +++ b/examples/03.CustomSceneNode/CustomSceneNode_vc11.vcxproj @@ -0,0 +1,247 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 03.CustomSceneNode + {171CCDFA-C140-4956-8EB7-F0168F4521D3} + CustomSceneNode + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/CustomSceneNode.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\03.CustomSceneNode.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/CustomSceneNode.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\03.CustomSceneNode.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/CustomSceneNode.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + .\Release/CustomSceneNode.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\03.CustomSceneNode.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + .\Release/CustomSceneNode.pdb + Console + false + + + + + + + .\Release/CustomSceneNode.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + .\Release/CustomSceneNode.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\03.CustomSceneNode.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + .\Release/CustomSceneNode.pdb + Console + false + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/03.CustomSceneNode/CustomSceneNode_vc12.vcxproj b/examples/03.CustomSceneNode/CustomSceneNode_vc12.vcxproj new file mode 100644 index 00000000..aa125e42 --- /dev/null +++ b/examples/03.CustomSceneNode/CustomSceneNode_vc12.vcxproj @@ -0,0 +1,247 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 03.CustomSceneNode + {171CCDFA-C140-4956-8EB7-F0168F4521D3} + CustomSceneNode + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/CustomSceneNode.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\03.CustomSceneNode.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/CustomSceneNode.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\03.CustomSceneNode.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/CustomSceneNode.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + .\Release/CustomSceneNode.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\03.CustomSceneNode.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + .\Release/CustomSceneNode.pdb + Console + false + + + + + + + .\Release/CustomSceneNode.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + .\Release/CustomSceneNode.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\03.CustomSceneNode.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + .\Release/CustomSceneNode.pdb + Console + false + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/03.CustomSceneNode/CustomSceneNode_vc14.vcxproj b/examples/03.CustomSceneNode/CustomSceneNode_vc14.vcxproj new file mode 100644 index 00000000..42e75d1f --- /dev/null +++ b/examples/03.CustomSceneNode/CustomSceneNode_vc14.vcxproj @@ -0,0 +1,247 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 03.CustomSceneNode + {171CCDFA-C140-4956-8EB7-F0168F4521D3} + CustomSceneNode + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/CustomSceneNode.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\03.CustomSceneNode.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/CustomSceneNode.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\03.CustomSceneNode.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/CustomSceneNode.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + .\Release/CustomSceneNode.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\03.CustomSceneNode.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + .\Release/CustomSceneNode.pdb + Console + false + + + + + + + .\Release/CustomSceneNode.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + .\Release/CustomSceneNode.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\03.CustomSceneNode.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + .\Release/CustomSceneNode.pdb + Console + false + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/03.CustomSceneNode/Makefile b/examples/03.CustomSceneNode/Makefile new file mode 100644 index 00000000..7daed21a --- /dev/null +++ b/examples/03.CustomSceneNode/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 03.CustomSceneNode +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/03.CustomSceneNode/main.cpp b/examples/03.CustomSceneNode/main.cpp new file mode 100644 index 00000000..95529312 --- /dev/null +++ b/examples/03.CustomSceneNode/main.cpp @@ -0,0 +1,268 @@ +/** Example 003 Custom SceneNode + +This tutorial is more advanced than the previous ones. +If you are currently just playing around with the Irrlicht +engine, you may want to look at other examples first. +This tutorials shows how to create a custom scene node and +how to use it in the engine. A custom scene node is needed +if you want to implement a render technique the Irrlicht +Engine currently does not support. For example, you can write +an indoor portal based renderer or an advanced terrain scene +node with it. By creating custom scene nodes, you can +easily extend the Irrlicht Engine and adapt it to your needs. + +I will keep the tutorial simple: Keep everything very short +and everything in one .cpp file. This is the style which +will also be used in most of the following tutorials. + +To start, I include the header files, use the irr namespace, +and tell the linker to link with the .lib file. +*/ +#include +#include "driverChoice.h" + +using namespace irr; + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +/* +Here comes the more sophisticated part of this tutorial: +The class of our very own custom scene node. To keep it simple, +our scene node will not be an indoor portal renderer nor a terrain +scene node, but a simple tetrahedron, a 3D object consisting of 4 +connected vertices, which only draws itself and does nothing more. +Note that this scenario does not require a custom scene node in Irrlicht. +Instead one would create a mesh from the geometry and pass it to a +irr::scene::IMeshSceneNode. This example just illustrates creation of a custom +scene node in a simple setting. + +To allow our scene node to be inserted into the Irrlicht +Engine scene, the class we create needs to be derived from the +irr::scene::ISceneNode class and has to override some methods. +*/ + +class CSampleSceneNode : public scene::ISceneNode +{ + + /* + First, we declare some member variables: + The bounding box, 4 vertices, and the material of the tetrahedron. + */ + core::aabbox3d Box; + video::S3DVertex Vertices[4]; + video::SMaterial Material; + +public: + + /* + The parameters of the constructor specify the parent of the scene node, + a pointer to the scene manager, and an id of the scene node. + In the constructor we call the parent class' constructor, + set some properties of the material, and create the 4 vertices of + the tetrahedron. + */ + + CSampleSceneNode(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id) + : scene::ISceneNode(parent, mgr, id) + { + Material.Wireframe = false; + Material.Lighting = false; + Material.Thickness=0.f; + + Vertices[0] = video::S3DVertex(0,0,10, 5,1,0, + video::SColor(255,0,255,255), 0, 1); + Vertices[1] = video::S3DVertex(10,0,-10, 10,0,0, + video::SColor(255,255,0,255), 1, 1); + Vertices[2] = video::S3DVertex(0,20,0, 20,1,1, + video::SColor(255,255,255,0), 1, 0); + Vertices[3] = video::S3DVertex(-10,0,-10, 40,0,1, + video::SColor(255,0,255,0), 0, 0); + + /* + The Irrlicht Engine needs to know the bounding box of a scene node. + It will use it for automatic culling and other things. Hence, we + need to create a bounding box from the 4 vertices we use. + If you do not want the engine to use the box for automatic culling, + and/or don't want to create the box, you could also call + irr::scene::ISceneNode::setAutomaticCulling() with irr::scene::EAC_OFF. + */ + Box.reset(Vertices[0].Pos); + for (s32 i=1; i<4; ++i) + Box.addInternalPoint(Vertices[i].Pos); + } + + /* + Before it is drawn, the irr::scene::ISceneNode::OnRegisterSceneNode() + method of every scene node in the scene is called by the scene manager. + If the scene node wishes to draw itself, it may register itself in the + scene manager to be drawn. This is necessary to tell the scene manager + when it should call irr::scene::ISceneNode::render(). For + example, normal scene nodes render their content one after another, + while stencil buffer shadows would like to be drawn after all other + scene nodes. And camera or light scene nodes need to be rendered before + all other scene nodes (if at all). So here we simply register the + scene node to render normally. If we would like to let it be rendered + like cameras or light, we would have to call + SceneManager->registerNodeForRendering(this, SNRT_LIGHT_AND_CAMERA); + After this, we call the actual irr::scene::ISceneNode::OnRegisterSceneNode() + method of the base class, which lets all the child scene nodes of this node + register themselves. + */ + virtual void OnRegisterSceneNode() + { + if (IsVisible) + SceneManager->registerNodeForRendering(this); + + ISceneNode::OnRegisterSceneNode(); + } + + /* + In the render() method most of the interesting stuff happens: The + Scene node renders itself. We override this method and draw the + tetrahedron. + */ + virtual void render() + { + /* Indices into the 'Vertices' array. A triangle needs 3 vertices + so you have to pass the 3 corresponding indices for each triangle to + tell which of the vertices should be used for it. */ + u16 indices[] = { 0,2,3, 2,1,3, 1,0,3, 2,0,1 }; + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + + driver->setMaterial(Material); + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + driver->drawVertexPrimitiveList(&Vertices[0], 4, &indices[0], 4, video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT); + } + + /* + And finally we create three small additional methods. + irr::scene::ISceneNode::getBoundingBox() returns the bounding box of + this scene node, irr::scene::ISceneNode::getMaterialCount() returns the + amount of materials in this scene node (our tetrahedron only has one + material), and irr::scene::ISceneNode::getMaterial() returns the + material at an index. Because we have only one material, we can + return that and assume that no one ever calls getMaterial() with an index + greater than 0. + */ + virtual const core::aabbox3d& getBoundingBox() const + { + return Box; + } + + virtual u32 getMaterialCount() const + { + return 1; + } + + virtual video::SMaterial& getMaterial(u32 i) + { + return Material; + } +}; + +/* +That's it. The Scene node is done. Now we start the engine, +create the scene node and a camera, and look at the result. +*/ +int main() +{ + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + // create device + IrrlichtDevice *device = createDevice(driverType, + core::dimension2d(640, 480), 16, false); + + if (device == 0) + return 1; // could not create selected driver. + + // set window caption, get some pointers, create a camera + + device->setWindowCaption(L"Custom Scene Node - Irrlicht Engine Demo"); + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + + smgr->addCameraSceneNode(0, core::vector3df(0,-40,0), core::vector3df(0,0,0)); + + /* + Create our scene node. I don't check the result of calling new, as it + should throw an exception rather than returning 0 on failure. Because + the new node will create itself with a reference count of 1, and then + will have another reference added by its parent scene node when it is + added to the scene, I need to drop my reference to it. Best practice is + to drop it only *after* I have finished using it, regardless of what + the reference count of the object is after creation. + */ + CSampleSceneNode *myNode = + new CSampleSceneNode(smgr->getRootSceneNode(), smgr, 666); + + /* + To animate something in this boring scene consisting only of one + tetrahedron, and to show that you now can use your scene node like any + other scene node in the engine, we add an animator to the scene node, + which rotates the node a little bit. + irr::scene::ISceneManager::createRotationAnimator() could return 0, so + should be checked. + */ + scene::ISceneNodeAnimator* anim = + smgr->createRotationAnimator(core::vector3df(0.8f, 0, 0.8f)); + + if(anim) + { + myNode->addAnimator(anim); + + /* + I'm done referring to anim, so must + irr::IReferenceCounted::drop() this reference now because it + was produced by a createFoo() function. As I shouldn't refer to + it again, ensure that I can't by setting to 0. + */ + anim->drop(); + anim = 0; + } + + /* + I'm done with my CSampleSceneNode object, and so must drop my reference. + This won't delete the object, yet, because it is still attached to the + scene graph, which prevents the deletion until the graph is deleted or the + custom scene node is removed from it. + */ + myNode->drop(); + myNode = 0; // As I shouldn't refer to it again, ensure that I can't + + /* + Now draw everything and finish. + */ + u32 frames=0; + while(device->run()) + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0,100,100,100)); + + smgr->drawAll(); + + driver->endScene(); + if (++frames==100) // don't update more often, setWindowCaption can be expensive + { + core::stringw str = L"Irrlicht Engine ["; + str += driver->getName(); + str += L"] FPS: "; + str += (s32)driver->getFPS(); + + device->setWindowCaption(str.c_str()); + frames=0; + } + } + + device->drop(); + + return 0; +} + +/* +That's it. Compile and play around with the program. +**/ diff --git a/examples/03.CustomSceneNode/tutorial.html b/examples/03.CustomSceneNode/tutorial.html new file mode 100644 index 00000000..becc3d77 --- /dev/null +++ b/examples/03.CustomSceneNode/tutorial.html @@ -0,0 +1,222 @@ + + +Irrlicht Engine Tutorial + + + + +
+ + + + + + + + +
+
+
+
Tutorial 3.CustomSceneNode
+
+
+
+

This Tutorial is a tutorial for more advanced developers. If you are + currently just playing around with the Irrlicht engine, please look + at other examples first. This tutorial shows how to create a custom + scene node and how to use it in the engine. A custom scene node is needed, + if you want to implement a render technique, the Irrlicht Engine is + currently not supporting. For example you can write a indoor portal + based renderer or a advanced terrain scene node with it. With creating + custom scene nodes, you can easily extend the Irrlicht Engine and adapt + it to your needs.

+

I will keep the tutorial simple: Keep everything very short, everything + in one .cpp file, and I'll use the engine here as in all other tutorials. + At the end of the tutorial, the result will look like the image below. + This looks not very exciting, but it is a complete customized scene + node and a good point to start from creating you own scene nodes.

+


+

+
+
+
+ + + + + + + +
+ Lets start!
+

To start, I include the header files, use the irr namespace, and tell + the linker to link with the .lib file.

+ + + + +
#include <irrlicht.h>
using namespace irr;
#pragma comment(lib, "Irrlicht.lib")
+

Here comes the most sophisticated part of this tutorial: The class + of our very own custom scene node. To keep it simple,
+ our scene node will not be an indoor portal renderer nor a terrain scene + node, but a simple tetraeder, a 3d object consiting of 4 connected vertices, + which only draws itself and does nothing more.

+

To let our scene node be able to be inserted into the Irrlicht Engine + scene, the class we create needs only be derived from the ISceneNode + class and has to override some methods.

+ + + + +
class CSampleSceneNode : public scene::ISceneNode
{
+

First, we declare some member variables, to hold data for our tetraeder: + The bounding box, 4 vertices, and
+ the material of the tetraeder.

+ + + + +
core::aabbox3d<f32> Box;
video::S3DVertex Vertices[4];
video::SMaterial Material;
+

The parameters of the constructor specify the parent of the scene node, + a pointer to the scene manager, and an id of the scene node. In the + constructor itself, we call the parent classes constructor, set some + properties of the material we use to draw the scene node and create + the 4 vertices of the tetraeder we will draw later.

+ + + + +
public:
CSampleSceneNode(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id)
+ : scene::ISceneNode(parent, mgr, id)
+{ 
+  Material.Wireframe = false;
+  Material.Lighting = false;
+
  Vertices[0] = video::S3DVertex(0,0,10, 1,1,0,video::SColor(255,0,255,255),0,1);
+  Vertices[1] = video::S3DVertex(10,0,-10, 1,0,0,video::SColor(255,255,0,255),1,1); 
+  Vertices[2] = video::S3DVertex(0,20,0, 0,1,1,video::SColor(255,255,255,0),1,0);
+  Vertices[3] = video::S3DVertex(-10,0,-10, 0,0,1,video::SColor(255,0,255,0),0,0);
+
+
+ The Irrlicht Engine needs to know the bounding box of your scene node. + It will use it for doing automatic culling and other things. Hence we + need to create a bounding box from the 4 vertices we use. If you do not + want the engine to use the box for automatic culling, and/or don't want + to create the box, you could also write
+ AutomaticCullingEnabled = false;.
+
+ + + + +
  Box.reset(Vertices[0].Pos);
for (s32 i=1; i<4; ++i)
Box.addInternalPoint(Vertices[i].Pos); +}
+
+

Before it is drawn, the OnPreRender() method of every scene node in + the scene is called by the scene manager. If the scene node wishes to + draw itself, it may register itself in the scene manager to be drawn. + This is necessary to tell the scene manager when it should call the + ::render method. For example normal scene nodes render their content + one after another, while stencil buffer shadows would like to be drawn + after all other scene nodes. And camera or light scene nodes need to + be rendered before all other scene nodes (if at all).
+ So here we simply register the scene node to get rendered normally. + If we would like to let it be rendered like cameras or light, we would + have to call SceneManager->registerNodeForRendering(this, SNRT_LIGHT_AND_CAMERA); +
+ After this, we call the OnPreRender-method of the base class ISceneNode, + which simply lets also all the child scene nodes of this node register + themselves.

+
+ + + + +
virtual void OnPreRender()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this); + + ISceneNode::OnPreRender(); +}
+

In the render() method most of the interresting stuff happenes: The Scene + node renders itself. We override this method and draw the tetraeder.

+ + + + +
virtual void render()
{
u16 indices[] = { 0,2,3, 2,1,3, 1,0,3, 2,0,1 }; + video::IVideoDriver* driver = SceneManager->getVideoDriver();
+
  driver->setMaterial(Material);
+  driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
+  driver->drawIndexedTriangleList(&Vertices[0], 4, &indices[0], 4);
+}
+

At least, we create three small additional methods. GetBoundingBox() + returns the bounding box of this scene node,
+ GetMaterialCount() returns the amount of materials in this scene node + (our tetraeder only has one material), and getMaterial() returns the material + at an index. Because we have only one material here, we can return the + only one material, assuming that no one ever calls getMaterial() with + an index greater than 0.

+ + + + +
  virtual const core::aabbox3d<f32>& getBoundingBox() const
{
return Box;
}
  virtual u32 getMaterialCount()
+  {
+    return 1;
+  }
  virtual video::SMaterial& getMaterial(u32 i)
+  {
+    return Material;
+  } 
+};
+

That's it. The Scene node is done. Now we simply have to start the engine, + create the scene node and a camera, and look at the result.

+ + + + +
int main()
{ + IrrlichtDevice *device = + createDevice(video::EDT_OPENGL, core::dimension2d<s32>(640, 480), 16, false);
  device->setWindowCaption(L"Custom Scene Node - Irrlicht Engine Demo");
  video::IVideoDriver* driver = device->getVideoDriver();
+           scene::ISceneManager* smgr = device->getSceneManager();
+
  smgr->addCameraSceneNode(0, core::vector3df(0,-40,0), core::vector3df(0,0,0));
+                   
+

Create our scene node. Note that it is dropped (->drop()) instantly + after we create it. This is possible because the scene manager now takes + care of it. This is not nessecary, it would also be possible to drop it + at the end of the program.

+ + + + +
CSampleSceneNode *myNode = 
new CSampleSceneNode(smgr->getRootSceneNode(), smgr, 666); + +myNode->drop();
+

To animate something in this boring scene consisting only of one tetraeder, + and to show, that you now can use your scene node like any other scene + node in the engine, we add an animator to the scene node, which rotates + the node a little bit.

+ + + + +
scene::ISceneNodeAnimator* anim = 
smgr->createRotationAnimator(core::vector3df(0.8f, 0, 0.8f)); + +myNode->addAnimator(anim); +anim->drop();
+

Now draw everything and finish.

+ + + + +
  while(device->run())
{
driver->beginScene(true, true, video::SColor(0,100,100,100)); + + smgr->drawAll(); + + driver->endScene(); + } + +device->drop(); +return 0; +}
+

That's it. Compile and play around with the program.

+

 

+ + diff --git a/examples/04.Movement/Makefile b/examples/04.Movement/Makefile new file mode 100644 index 00000000..c5d50c9d --- /dev/null +++ b/examples/04.Movement/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 04.Movement +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/04.Movement/Movement.cbp b/examples/04.Movement/Movement.cbp new file mode 100644 index 00000000..76e2f439 --- /dev/null +++ b/examples/04.Movement/Movement.cbp @@ -0,0 +1,55 @@ + + + + + + diff --git a/examples/04.Movement/Movement.vcproj b/examples/04.Movement/Movement.vcproj new file mode 100644 index 00000000..105c6258 --- /dev/null +++ b/examples/04.Movement/Movement.vcproj @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/04.Movement/Movement.xcodeproj/project.pbxproj b/examples/04.Movement/Movement.xcodeproj/project.pbxproj new file mode 100644 index 00000000..06d14890 --- /dev/null +++ b/examples/04.Movement/Movement.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 04.Movement.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 04.Movement.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 04.Movement.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 04.Movement */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "04.Movement" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 04.Movement; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 04.Movement.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Movement" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 04.Movement */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Movement" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "04.Movement" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/04.Movement/Movement.xcodeproj/xcshareddata/xcschemes/04.Movement.xcscheme b/examples/04.Movement/Movement.xcodeproj/xcshareddata/xcschemes/04.Movement.xcscheme new file mode 100644 index 00000000..aec7f206 --- /dev/null +++ b/examples/04.Movement/Movement.xcodeproj/xcshareddata/xcschemes/04.Movement.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/04.Movement/Movement_vc10.vcxproj b/examples/04.Movement/Movement_vc10.vcxproj new file mode 100644 index 00000000..131479da --- /dev/null +++ b/examples/04.Movement/Movement_vc10.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 04.Movement + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF} + Movement + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Movement.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\04.Movement.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Movement.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\04.Movement.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Movement.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\04.Movement.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Movement.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\04.Movement.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/04.Movement/Movement_vc11.vcxproj b/examples/04.Movement/Movement_vc11.vcxproj new file mode 100644 index 00000000..131479da --- /dev/null +++ b/examples/04.Movement/Movement_vc11.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 04.Movement + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF} + Movement + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Movement.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\04.Movement.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Movement.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\04.Movement.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Movement.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\04.Movement.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Movement.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\04.Movement.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/04.Movement/Movement_vc12.vcxproj b/examples/04.Movement/Movement_vc12.vcxproj new file mode 100644 index 00000000..bbebe747 --- /dev/null +++ b/examples/04.Movement/Movement_vc12.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 04.Movement + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF} + Movement + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Movement.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\04.Movement.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Movement.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\04.Movement.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Movement.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\04.Movement.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Movement.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\04.Movement.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/04.Movement/Movement_vc14.vcxproj b/examples/04.Movement/Movement_vc14.vcxproj new file mode 100644 index 00000000..f56853e9 --- /dev/null +++ b/examples/04.Movement/Movement_vc14.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 04.Movement + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF} + Movement + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Movement.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\04.Movement.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Movement.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\04.Movement.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Movement.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\04.Movement.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Movement.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\04.Movement.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/04.Movement/main.cpp b/examples/04.Movement/main.cpp new file mode 100644 index 00000000..dcbcc30e --- /dev/null +++ b/examples/04.Movement/main.cpp @@ -0,0 +1,265 @@ +/** Example 004 Movement + +This tutorial shows how to move and animate SceneNodes. The +basic concept of SceneNodeAnimators is shown as well as manual +movement of nodes using the keyboard. We'll demonstrate framerate +independent movement, which means moving by an amount dependent +on the duration of the last run of the Irrlicht loop. + +Example 19.MouseAndJoystick shows how to handle other input than keyboard. + +As always, include the header files, use the irr namespace, +and tell the linker to link with the .lib file. +*/ +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +using namespace irr; + +/* +To receive events like mouse and keyboard input, or GUI events like +"button has been clicked", we need an object which is derived from the +irr::IEventReceiver object. There is only one method to override: +irr::IEventReceiver::OnEvent(). This method will be called by the engine once +when an event happens. What we really want to know is whether a key is being +held down, and so we will remember the current state of each key. +*/ +class MyEventReceiver : public IEventReceiver +{ +public: + // This is the one method that we have to implement + virtual bool OnEvent(const SEvent& event) + { + // Remember whether each key is down or up + if (event.EventType == irr::EET_KEY_INPUT_EVENT) + KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown; + + /* + Always return false by default. If you return true you tell the engine + that you handled this event completely and the Irrlicht should not + process it any further. So for example if you return true for all + EET_KEY_INPUT_EVENT events then Irrlicht would not pass on key-events + to it's GUI system. + */ + return false; + } + + // This is used to check whether a key is being held down + virtual bool IsKeyDown(EKEY_CODE keyCode) const + { + return KeyIsDown[keyCode]; + } + + MyEventReceiver() + { + for (u32 i=0; i(640, 480), 16, false, false, false, &receiver); + + if (device == 0) + return 1; // could not create selected driver. + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + + const io::path mediaPath = getExampleMediaPath(); + + /* + Create the node which will be moved with the WSAD keys. We create a + sphere node, which is a built-in geometry primitive. We place the node + at (0,0,30) and assign a texture to it to let it look a little bit more + interesting. Because we have no dynamic lights in this scene we disable + lighting for each model (otherwise the models would be black). + */ + scene::ISceneNode * sphereNode = smgr->addSphereSceneNode(); + if (sphereNode) + { + sphereNode->setPosition(core::vector3df(0,0,30)); + sphereNode->setMaterialTexture(0, driver->getTexture(mediaPath + "wall.bmp")); + sphereNode->setMaterialFlag(video::EMF_LIGHTING, false); + } + + /* + Now we create another node, movable using a scene node animator. Scene + node animators modify scene nodes and can be attached to any scene node + like mesh scene nodes, billboards, lights and even camera scene nodes. + Scene node animators are not only able to modify the position of a + scene node, they can also animate the textures of an object for + example. We create a cube scene node and attach a 'fly circle' scene + node animator to it, letting this node fly around our sphere scene node. + */ + scene::ISceneNode* cubeNode = smgr->addCubeSceneNode(); + if (cubeNode) + { + cubeNode->setMaterialTexture(0, driver->getTexture(mediaPath + "t351sml.jpg")); + cubeNode->setMaterialFlag(video::EMF_LIGHTING, false); + scene::ISceneNodeAnimator* anim = + smgr->createFlyCircleAnimator(core::vector3df(0,0,30), 20.0f); + if (anim) + { + cubeNode->addAnimator(anim); + anim->drop(); + } + } + + /* + The last scene node we add is a b3d model of a walking ninja. Is shows the + use of a 'fly straight' animator to move the node between two points. + */ + scene::IAnimatedMeshSceneNode* ninjaNode = + smgr->addAnimatedMeshSceneNode(smgr->getMesh(mediaPath + "ninja.b3d")); + + if (ninjaNode) + { + scene::ISceneNodeAnimator* anim = + smgr->createFlyStraightAnimator(core::vector3df(100,0,60), + core::vector3df(-100,0,60), 3500, true); + if (anim) + { + ninjaNode->addAnimator(anim); + anim->drop(); + } + + /* + To make the model look right we disable lighting, set the + frames between which the animation should loop, rotate the + model around 180 degrees, and adjust the animation speed and + the texture. To set the correct animation (frames and speed), we + would also be able to just call + "ninjaNode->setMD2Animation(scene::EMAT_RUN)" for the 'run' + animation instead of "setFrameLoop" and "setAnimationSpeed", + But that only works with MD2 animations, while this can be used to + start other animations. For MD2 it's usually good advice not to use + hardcoded frame-numbers... + */ + ninjaNode->setMaterialFlag(video::EMF_LIGHTING, false); + + ninjaNode->setFrameLoop(0, 13); + ninjaNode->setAnimationSpeed(15); +// ninjaNode->setMD2Animation(scene::EMAT_RUN); + + ninjaNode->setScale(core::vector3df(2.f,2.f,2.f)); + ninjaNode->setRotation(core::vector3df(0,-90,0)); +// ninjaNode->setMaterialTexture(0, driver->getTexture(mediaPath + "sydney.bmp")); + + } + + + /* + To be able to look at and move around in this scene, we create a first + person shooter style camera and make the mouse cursor invisible. + */ + smgr->addCameraSceneNodeFPS(); + device->getCursorControl()->setVisible(false); + + /* + Add a colorful irrlicht logo + */ + device->getGUIEnvironment()->addImage( + driver->getTexture(mediaPath + "irrlichtlogoalpha2.tga"), + core::position2d(10,20)); + + /* + Lets draw the scene and also write the current frames per second and the + name of the driver to the caption of the window. + */ + int lastFPS = -1; + + // In order to do framerate independent movement, we have to know + // how long it was since the last frame + u32 then = device->getTimer()->getTime(); + + // This is the movement speed in units per second. + const f32 MOVEMENT_SPEED = 5.f; + + while(device->run()) + { + // Work out a frame delta time. + const u32 now = device->getTimer()->getTime(); + const f32 frameDeltaTime = (f32)(now - then) / 1000.f; // Time in seconds + then = now; + + /* Check if keys W, S, A or D are being held down, and move the + sphere node around respectively. */ + core::vector3df nodePosition = sphereNode->getPosition(); + + if(receiver.IsKeyDown(irr::KEY_KEY_W)) + nodePosition.Y += MOVEMENT_SPEED * frameDeltaTime; + else if(receiver.IsKeyDown(irr::KEY_KEY_S)) + nodePosition.Y -= MOVEMENT_SPEED * frameDeltaTime; + + if(receiver.IsKeyDown(irr::KEY_KEY_A)) + nodePosition.X -= MOVEMENT_SPEED * frameDeltaTime; + else if(receiver.IsKeyDown(irr::KEY_KEY_D)) + nodePosition.X += MOVEMENT_SPEED * frameDeltaTime; + + sphereNode->setPosition(nodePosition); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,113,113,133)); + + smgr->drawAll(); // draw the 3d scene + device->getGUIEnvironment()->drawAll(); // draw the gui environment (the logo) + + driver->endScene(); + + int fps = driver->getFPS(); + + if (lastFPS != fps) + { + core::stringw tmp(L"Movement Example - Irrlicht Engine ["); + tmp += driver->getName(); + tmp += L"] fps: "; + tmp += fps; + + device->setWindowCaption(tmp.c_str()); + lastFPS = fps; + } + } + + /* + In the end, delete the Irrlicht device. + */ + device->drop(); + + return 0; +} + +/* +That's it. Compile and play around with the program. +**/ diff --git a/examples/04.Movement/tutorial.html b/examples/04.Movement/tutorial.html new file mode 100644 index 00000000..28b207dc --- /dev/null +++ b/examples/04.Movement/tutorial.html @@ -0,0 +1,188 @@ + + +Irrlicht Engine Tutorial + + + + +
+ + + + + + + + +
+
+
+
Tutorial 4.Movement
+
+
+
+

This Tutorial shows how to move and animate SceneNodes. The basic concept + of SceneNodeAnimators is shown as well as manual movement of nodes using + the keyboard.

+

The program which is described here will look like this:

+


+

+
+
+
+ + + + + + + +
+ Lets start!
+

As always, I include the header files, use the irr namespace, and tell + the linker to link with the .lib file.

+ + + + +
#include <stdio.h>
#include <wchar.h>
#include <irrlicht.h>
+
using namespace irr;
+
#pragma comment(lib, "Irrlicht.lib")
+

In this tutorial, one of our goals is to move a scene node using some + keys on the keyboard. We store a pointer to the scene node we want to + move with the keys here.
+ The other pointer is a pointer to the Irrlicht Device, which we need + int the EventReceiver to manipulate the scene node and to get the active + camera.

+ + + + +
scene::ISceneNode* node = 0;
IrrlichtDevice* device = 0;
+

To get events like mouse and keyboard input, or GUI events like "the + OK button has been clicked", we need an object wich is derived + from the IEventReceiver object. There is only one method to override: + OnEvent. This method will be called by the engine when an event happened. + We will use this input to move the scene node with the keys W and S.

+ + + + +
class MyEventReceiver : public IEventReceiver
{
public:
virtual bool OnEvent(const SEvent& event)
{
+

If the key 'W' or 'S' was left up, we get the position of the scene + node, and modify the Y coordinate a little bit. So if you press 'W', + the node moves up, and if you press 'S' it moves down.

+ + + + +
if (node != 0 && event.EventType == irr::EET_KEY_INPUT_EVENT&&
!event.KeyInput.PressedDown)
{
switch(event.KeyInput.Key)
{
case KEY_KEY_W:
case KEY_KEY_S:
{
core::vector3df v = node->getPosition();
v.Y += event.KeyInput.Key == KEY_KEY_W ? 2.0f : -2.0f;
node->setPosition(v);
}
return true;
}
} return false;
}
};
+ +
+

The event receiver for moving a scene node is ready. So lets just create + an Irrlicht Device and the scene node we want to move. We also create + some other additional scene nodes, to show that there are also some different + possibilities to move and animate scene nodes.

+ + + + +
int main()
{
MyEventReceiver receiver; + + device = createDevice(video::EDT_OPENGL, core::dimension2d<s32>(640, 480), + 16, false, false, false, &receiver);
+
   video::IVideoDriver* driver = device->getVideoDriver();
+   scene::ISceneManager* smgr = device->getSceneManager();
+
+

Create the node for moving it with the 'W' and 'S' key. We create a + sphere node, which is a built in geometric primitive scene node. + We place the node at (0,0,30) and assign a texture to it to let it look + a little bit more interesting.

+ + + + +
node = smgr->addSphereSceneNode();
+node->setPosition(core::vector3df(0,0,30));
+node->setMaterialFlag(video::EMF_LIGHTING, false);
+node->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp"));
+

Now we create another node, moving using a scene node animator. Scene + node animators modify scene nodes and can be attached to any scene node + like
+ mesh scene nodes, billboards, lights and even camera scene nodes. Scene + node animators are not only able to modify the position of a scene node, + they can
+ also animate the textures of an object for example. We create a test scene + node again an attach a 'fly circle' scene node to it, letting this node + fly around our first test scene node.

+ + + + +
scene::ISceneNode* n = smgr->addCubeSceneNode();
+n->setMaterialTexture(0, driver->getTexture("../../media/t351sml.jpg"));
+n->setMaterialFlag(video::EMF_LIGHTING, false);
+scene::ISceneNodeAnimator* anim = 
+	smgr->createFlyCircleAnimator(core::vector3df(0,0,30), 20.0f);
+n->addAnimator(anim);
+anim->drop();
+

The last scene node we add to show possibilities of scene node animators + is a md2 model, which uses a 'fly straight' animator to run between to + points.

+ + + + +
scene::IAnimatedMeshSceneNode* anms = smgr->addAnimatedMeshSceneNode(
smgr->getMesh("../../media/sydney.md2")); + +if (n)
{
anim = smgr->createFlyStraightAnimator(core::vector3df(100,0,60),
core::vector3df(-100,0,60), 10000, true);
anms->addAnimator(anim);
anim->drop();
+
+

To make to model look right we set the frames between which + the animation should loop, rotate the model around 180 degrees, and adjust + the animation speed and the texture.
+ To set the right animation (frames and speed), we would also be able to + just call "anms->setMD2Animation(scene::EMAT_RUN)" for the + 'run' animation instead of "setFrameLoop" and "setAnimationSpeed", + but this only works with MD2 animations, and so you know how to start + other animations.

+ + + + +
   anms->setMaterialFlag(video::EMF_LIGHTING, false);
anms->setFrameLoop(320, 360); + anms->setAnimationSpeed(30);
anms->setRotation(core::vector3df(0,180.0f,0));
anms->setMaterialTexture(0, driver->getTexture("../../media/sydney.bmp"));
}
+

To be able to look at and move around in this scene, we create a first + person shooter style camera and make the mouse cursor invisible.

+ + + + +
smgr->addCameraSceneNodeFPS(0, 100.0f, 100.0f);
device->getCursorControl()->setVisible(false);
+

We have done everything, so lets draw it. We also write the current frames + per second and the name of the driver to the caption of the window.

+ + + + +
int lastFPS = -1;
+
while(device->run())
+{
+     driver->beginScene(true, true, video::SColor(255,90,90,156));
+     smgr->drawAll();
+     driver->endScene();
+
     int fps = driver->getFPS();
+
     if (lastFPS != fps)
+     {
+        wchar_t tmp[1024];
+        swprintf(tmp, 1024, L"Movement Example - Irrlicht Engine (%ls)(fps:%d)",
driver->getName(), fps);
+
       device->setWindowCaption(tmp);
+       lastFPS = fps;
+     }
+}
+
+device->drop();
return 0;
}
+

That's it. Compile and play around with the program.

+

 

+

 

+ + diff --git a/examples/05.UserInterface/Makefile b/examples/05.UserInterface/Makefile new file mode 100644 index 00000000..fb919746 --- /dev/null +++ b/examples/05.UserInterface/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 05.UserInterface +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/05.UserInterface/UserInterface.cbp b/examples/05.UserInterface/UserInterface.cbp new file mode 100644 index 00000000..99887189 --- /dev/null +++ b/examples/05.UserInterface/UserInterface.cbp @@ -0,0 +1,55 @@ + + + + + + diff --git a/examples/05.UserInterface/UserInterface.vcproj b/examples/05.UserInterface/UserInterface.vcproj new file mode 100644 index 00000000..44281698 --- /dev/null +++ b/examples/05.UserInterface/UserInterface.vcproj @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/05.UserInterface/UserInterface.xcodeproj/project.pbxproj b/examples/05.UserInterface/UserInterface.xcodeproj/project.pbxproj new file mode 100644 index 00000000..1e03a8ee --- /dev/null +++ b/examples/05.UserInterface/UserInterface.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 05.UserInterface.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 05.UserInterface.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 05.UserInterface.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 05.UserInterface */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "05.UserInterface" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 05.UserInterface; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 05.UserInterface.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "UserInterface" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 05.UserInterface */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "UserInterface" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "05.UserInterface" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/05.UserInterface/UserInterface.xcodeproj/xcshareddata/xcschemes/05.UserInterface.xcscheme b/examples/05.UserInterface/UserInterface.xcodeproj/xcshareddata/xcschemes/05.UserInterface.xcscheme new file mode 100644 index 00000000..3edc9eb3 --- /dev/null +++ b/examples/05.UserInterface/UserInterface.xcodeproj/xcshareddata/xcschemes/05.UserInterface.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/05.UserInterface/UserInterface_vc10.vcxproj b/examples/05.UserInterface/UserInterface_vc10.vcxproj new file mode 100644 index 00000000..d4be57f1 --- /dev/null +++ b/examples/05.UserInterface/UserInterface_vc10.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 05.UserInterface + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53} + UserInterface + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/UserInterface.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\05.UserInterface.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/UserInterface.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\05.UserInterface.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/UserInterface.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\05.UserInterface.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/UserInterface.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\05.UserInterface.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/05.UserInterface/UserInterface_vc11.vcxproj b/examples/05.UserInterface/UserInterface_vc11.vcxproj new file mode 100644 index 00000000..d4be57f1 --- /dev/null +++ b/examples/05.UserInterface/UserInterface_vc11.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 05.UserInterface + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53} + UserInterface + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/UserInterface.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\05.UserInterface.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/UserInterface.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\05.UserInterface.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/UserInterface.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\05.UserInterface.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/UserInterface.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\05.UserInterface.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/05.UserInterface/UserInterface_vc12.vcxproj b/examples/05.UserInterface/UserInterface_vc12.vcxproj new file mode 100644 index 00000000..3945262f --- /dev/null +++ b/examples/05.UserInterface/UserInterface_vc12.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 05.UserInterface + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53} + UserInterface + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/UserInterface.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\05.UserInterface.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/UserInterface.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\05.UserInterface.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/UserInterface.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\05.UserInterface.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/UserInterface.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\05.UserInterface.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/05.UserInterface/UserInterface_vc14.vcxproj b/examples/05.UserInterface/UserInterface_vc14.vcxproj new file mode 100644 index 00000000..0b66809b --- /dev/null +++ b/examples/05.UserInterface/UserInterface_vc14.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 05.UserInterface + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53} + UserInterface + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/UserInterface.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\05.UserInterface.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/UserInterface.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\05.UserInterface.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/UserInterface.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\05.UserInterface.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/UserInterface.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\05.UserInterface.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/05.UserInterface/main.cpp b/examples/05.UserInterface/main.cpp new file mode 100644 index 00000000..501eed3d --- /dev/null +++ b/examples/05.UserInterface/main.cpp @@ -0,0 +1,293 @@ +/** Example 005 User Interface + +This tutorial shows how to use the built in User Interface of +the Irrlicht Engine. It will give a brief overview and show +how to create and use windows, buttons, scroll bars, static +texts, and list boxes. + +As always, we include the header files, and use the irrlicht +namespaces. We also store a pointer to the Irrlicht device, +a counter variable for changing the creation position of a window, +and a pointer to a listbox. +*/ +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +using namespace irr; + +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +// Declare a structure to hold some context for the event receiver so that it +// has it available inside its OnEvent() method. +struct SAppContext +{ + IrrlichtDevice *device; + s32 counter; + IGUIListBox* listbox; +}; + +// Define some values that we'll use to identify individual GUI controls. +enum +{ + GUI_ID_QUIT_BUTTON = 101, + GUI_ID_NEW_WINDOW_BUTTON, + GUI_ID_FILE_OPEN_BUTTON, + GUI_ID_TRANSPARENCY_SCROLL_BAR +}; + +/* + Set the skin transparency by changing the alpha values of all skin-colors +*/ +void setSkinTransparency(s32 alpha, irr::gui::IGUISkin * skin) +{ + for (s32 i=0; igetColor((EGUI_DEFAULT_COLOR)i); + col.setAlpha(alpha); + skin->setColor((EGUI_DEFAULT_COLOR)i, col); + } +} + +/* +The Event Receiver is not only capable of getting keyboard and +mouse input events, but also events of the graphical user interface +(gui). There are events for almost everything: button click, +listbox selection change, events that say that a element was hovered +and so on. To be able to react to some of these events, we create +an event receiver. +We only react to gui events, and if it's such an event, we get the +id of the caller (the gui element which caused the event) and get +the pointer to the gui environment. +*/ +class MyEventReceiver : public IEventReceiver +{ +public: + MyEventReceiver(SAppContext & context) : Context(context) { } + + virtual bool OnEvent(const SEvent& event) + { + if (event.EventType == EET_GUI_EVENT) + { + s32 id = event.GUIEvent.Caller->getID(); + IGUIEnvironment* env = Context.device->getGUIEnvironment(); + + switch(event.GUIEvent.EventType) + { + + /* + If a scrollbar changed its scroll position, and it is + 'our' scrollbar (the one with id GUI_ID_TRANSPARENCY_SCROLL_BAR), + then we change the transparency of all gui elements. This is an + easy task: There is a skin object, in which all color + settings are stored. We simply go through all colors + stored in the skin and change their alpha value. + */ + case EGET_SCROLL_BAR_CHANGED: + if (id == GUI_ID_TRANSPARENCY_SCROLL_BAR) + { + s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos(); + setSkinTransparency(pos, env->getSkin()); + } + break; + + /* + If a button was clicked, it could be one of 'our' + three buttons. If it is the first, we shut down the engine. + If it is the second, we create a little window with some + text on it. We also add a string to the list box to log + what happened. And if it is the third button, we create + a file open dialog, and add also this as string to the list box. + That's all for the event receiver. + */ + case EGET_BUTTON_CLICKED: + switch(id) + { + case GUI_ID_QUIT_BUTTON: + Context.device->closeDevice(); + return true; + + case GUI_ID_NEW_WINDOW_BUTTON: + { + Context.listbox->addItem(L"Window created"); + Context.counter += 30; + if (Context.counter > 200) + Context.counter = 0; + + IGUIWindow* window = env->addWindow( + rect(100 + Context.counter, 100 + Context.counter, 300 + Context.counter, 200 + Context.counter), + false, // modal? + L"Test window"); + + env->addStaticText(L"Please close me", + rect(35,35,140,50), + true, // border? + false, // wordwrap? + window); + } + return true; + + case GUI_ID_FILE_OPEN_BUTTON: + Context.listbox->addItem(L"File open"); + // There are some options for the file open dialog + // We set the title, make it a modal window, and make sure + // that the working directory is restored after the dialog + // is finished. + env->addFileOpenDialog(L"Please choose a file.", true, 0, -1, true); + return true; + + default: + return false; + } + break; + + case EGET_FILE_SELECTED: + { + // show the model filename, selected in the file dialog + IGUIFileOpenDialog* dialog = + (IGUIFileOpenDialog*)event.GUIEvent.Caller; + Context.listbox->addItem(dialog->getFileName()); + } + break; + + default: + break; + } + } + + return false; + } + +private: + SAppContext & Context; +}; + + +/* +OK, now for the more interesting part. First, create the Irrlicht device. As in +some examples before, we ask the user which driver he wants to use for this +example. +*/ +int main() +{ + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + // create device and exit if creation failed + IrrlichtDevice * device = createDevice(driverType, core::dimension2d(640, 480)); + + if (device == 0) + return 1; // could not create selected driver. + + /* The creation was successful, now we set the event receiver and + store pointers to the driver and to the gui environment. */ + + device->setWindowCaption(L"Irrlicht Engine - User Interface Demo"); + device->setResizable(true); + + video::IVideoDriver* driver = device->getVideoDriver(); + IGUIEnvironment* env = device->getGUIEnvironment(); + + const io::path mediaPath = getExampleMediaPath(); + + /* + To make the font a little bit nicer, we load an external font + and set it as the new default font in the skin. + To keep the standard font for tool tip text, we set it to + the built-in font. + */ + + IGUISkin* skin = env->getSkin(); + IGUIFont* font = env->getFont(mediaPath + "fonthaettenschweiler.bmp"); + if (font) + skin->setFont(font); + + skin->setFont(env->getBuiltInFont(), EGDF_TOOLTIP); + + /* + We add three buttons. The first one closes the engine. The second + creates a window and the third opens a file open dialog. The third + parameter is the id of the button, with which we can easily identify + the button in the event receiver. + */ + + env->addButton(rect(10,240,110,240 + 32), 0, GUI_ID_QUIT_BUTTON, + L"Quit", L"Exits Program"); + env->addButton(rect(10,280,110,280 + 32), 0, GUI_ID_NEW_WINDOW_BUTTON, + L"New Window", L"Launches a new Window"); + env->addButton(rect(10,320,110,320 + 32), 0, GUI_ID_FILE_OPEN_BUTTON, + L"File Open", L"Opens a file"); + + /* + Now, we add a static text and a scrollbar, which modifies the + transparency of all gui elements. We set the maximum value of + the scrollbar to 255, because that's the maximal value for + a color value. + Then we create an other static text and a list box. + */ + + env->addStaticText(L"Transparent Control:", rect(150,20,350,40), true); + IGUIScrollBar* scrollbar = env->addScrollBar(true, + rect(150, 45, 350, 60), 0, GUI_ID_TRANSPARENCY_SCROLL_BAR); + scrollbar->setMax(255); + scrollbar->setPos(255); + setSkinTransparency( scrollbar->getPos(), env->getSkin()); + + // set scrollbar position to alpha value of an arbitrary element + scrollbar->setPos(env->getSkin()->getColor(EGDC_WINDOW).getAlpha()); + + env->addStaticText(L"Logging ListBox:", rect(50,110,250,130), true); + IGUIListBox * listbox = env->addListBox(rect(50, 140, 250, 210)); + env->addEditBox(L"Editable Text", rect(350, 80, 550, 100)); + + // Store the appropriate data in a context structure. + SAppContext context; + context.device = device; + context.counter = 0; + context.listbox = listbox; + + // Then create the event receiver, giving it that context structure. + MyEventReceiver receiver(context); + + // And tell the device to use our custom event receiver. + device->setEventReceiver(&receiver); + + + /* + And at last, we create a nice Irrlicht Engine logo in the top left corner. + */ + env->addImage(driver->getTexture(mediaPath + "irrlichtlogo2.png"), + position2d(10,10)); + + + /* + That's all, we only have to draw everything. + */ + + while(device->run() && driver) + if (device->isWindowActive()) + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, SColor(0,200,200,200)); + + env->drawAll(); + + driver->endScene(); + } + + device->drop(); + + return 0; +} + +/* +**/ diff --git a/examples/05.UserInterface/tutorial.html b/examples/05.UserInterface/tutorial.html new file mode 100644 index 00000000..3f3614fa --- /dev/null +++ b/examples/05.UserInterface/tutorial.html @@ -0,0 +1,225 @@ + + +Irrlicht Engine Tutorial + + + + +
+ + + + + + + + +
+
+
+
Tutorial 5.User Interface
+
+
+
+

This tutorial shows how to use the built in User Interface of the Irrlicht + Engine. It will give a brief overview and show how to create and use + windows, buttons, scroll bars, static texts and list boxes.

+

The program which is described here will look like this:

+


+

+
+
+
+ + + + + + + +
+ Lets start!
+

As always, we include the header files (conio and curses for getting + user input from the console), and use the irrlicht namespaces. We also + store a pointer to the Irrlicht device, a counter variable for changing + the creation position of a window, and a pointer to a listbox.

+ + + + +
#include <irrlicht.h>
+#include <iostream>
+using namespace irr;
+
using namespace core;
+using namespace scene;
+using namespace video;
+using namespace io;
+using namespace gui;
+
#pragma comment(lib, "Irrlicht.lib")
+
IrrlichtDevice *device = 0;
+s32 cnt = 0;
+IGUIListBox* listbox = 0;
+
+

The Event Receiver is not only capable of getting keyboard and mouse + input events, but also events of the graphical user interface (gui). + There are events for almost everything: Button click, Listbox selection + change, events that say that a element was hovered and so on. To be + able to react to some of these events, we create
+ an event receiver. We only react to gui events, and if it's such an + event, we get the id of the caller (the gui element which caused the + event) and get the pointer to the gui environment.

+ + + + +
class MyEventReceiver : public IEventReceiver
{
public:
virtual bool OnEvent(const SEvent& event)
{
if (event.EventType == EET_GUI_EVENT)
{
s32 id = event.GUIEvent.Caller->getID();
IGUIEnvironment* env = device->getGUIEnvironment();
+
            switch(event.GUIEvent.EventType)
+            {
+
+

If a scrollbar changed its scroll position, and it is 'our' scrollbar + (the one with id 104), then we change the
+ transparency of all gui elements. This is a very easy task: There is + a skin object, in which all color settings are stored. We simply go + through all colors stored in the skin and change their alpha value. +

+ + + + +
case EGET_SCROLL_BAR_CHANGED:
if (id == 104)
{
s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();

for (s32 i=0; i<EGDC_COUNT ; ++i)
{
SColor col = env->getSkin()->getColor((EGUI_DEFAULT_COLOR)i);
col.setAlpha(pos);
env->getSkin()->setColor((EGUI_DEFAULT_COLOR)i, col);
}
}
break;
+

If a button was clicked, it could be one of 'our' three buttons. If + it is the first, we shut down the engine.
+ If it is the second, we create a little window with some text on it. + We also add a string to the list box to log
+ what happened. And if it is the third button, we create a file open + dialog, and add also this as string to the list box.
+ That's all for the event receiver.

+ + + + +
+
       case EGET_BUTTON_CLICKED:
+              if (id == 101)
+              {
+                 device->closeDevice();
+                 return true;
+              }
+
              if (id == 102)
+              {
+                 listbox->addItem(L"Window created");
+                 cnt += 30;
+                 if (cnt > 200) 
+                   cnt = 0;
+
                 IGUIWindow* window = env->addWindow(
+                       rect<s32>(100 + cnt, 100 + cnt, 300 + cnt, 200 + cnt), 
false, // modal? + L"Test window");
+
                 env->addStaticText(L"Please close me", 
+                       rect<s32>(35,35,140,50),
+                       true, // border?,
+                       false, // wordwrap?
+                       window);
+
+                 return true;
+              }
+
              if (id == 103)
+              {
+                 listbox->addItem(L"File open");
+                 env->addFileOpenDialog(L"Please choose a file.");
+                 return true;
+              }
+
              break;
+          }
+       }
+       return false;
+    }
+ };
+
+

Ok, now for the more interesting part. First, create the Irrlicht device. + As in some examples before, we ask the user which driver he wants to + use for this example:

+
+ + + + +
int main()
+{
+  // ask user for driver
+  video::E_DRIVER_TYPE driverType;
+
+
+  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) Apfelbaum Software Renderer\n"\
" (f) NullDevice\n (otherKey) exit\n\n");

char i;
std::cin >> i;
+ switch(i)
{
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;
default: return 1;
} + + // create device and exit if creation failed + device = createDevice(driverType, core::dimension2d<s32>(640, 480));
+ if (device == 0) + return 1; +
+
+

The creation was successful, now we set the event receiver and store + pointers to the driver and to the gui environment.

+ + + + +
MyEventReceiver receiver;
+device->setEventReceiver(&receiver);
+device->setWindowCaption(L"Irrlicht Engine - User Inferface Demo");
+
video::IVideoDriver* driver = device->getVideoDriver();
+IGUIEnvironment* env = device->getGUIEnvironment();
+
+
+

We add three buttons. The first one closes the engine. The second creates + a window and the third opens a file open dialog. The third parameter is + the id of the button, with which we can easily identify the button in + the event receiver.

+ + + + +
env->addButton(rect<s32>(10,240,100,270), 0, 101, L"Quit");
env->addButton(rect<s32>(10,280,100,320), 0, 102, L"New Window");
env->addButton(rect<s32>(10,330,100,370), 0, 103, L"File Open");
+

Now, we add a static text and a scrollbar, which modifies the transparency + of all gui elements. We set the maximum value of the scrollbar to 255, + because that's the maximal value for a color value.
+ Then we create an other static text and a list box.

+ + + + +
env->addStaticText(L"Transparent Control:", rect<s32>(150,20,350,40), true);
IGUIScrollBar* scrollbar = env->addScrollBar(true, + rect<s32>(150, 45, 350, 60), 0, 104);
scrollbar->setMax(255);
+
env->addStaticText(L"Logging ListBox:", rect<s32>(50,110,250,130), true);
+listbox = env->addListBox(rect<s32>(50, 140, 250, 210));
+
+ To make the font a little bit nicer, we load an external font and set it + as new font in the skin. An at last, we create a nice Irrlicht Engine logo + in the top left corner.
+
+ + + + +
IGUISkin* skin = env->getSkin();
IGUIFont* font = env->getFont("../../media/fonthaettenschweiler.bmp");
if (font)
skin->setFont(font);
+
IGUIImage* img = env->addImage(
driver->getTexture("../../media/irrlichtlogoalpha.tga"),
position2d<int>(10,10));
+

That's all, we only have to draw everything.

+ + + + +
+
  while(device->run() && driver)
if (device->isWindowActive())
{
driver->beginScene(true, true, SColor(0,122,65,171)); + env->drawAll(); + driver->endScene(); + } + + device->drop();
+
  return 0;
+}
+
+ +
+

 

+ + diff --git a/examples/06.2DGraphics/2DGraphics.cbp b/examples/06.2DGraphics/2DGraphics.cbp new file mode 100644 index 00000000..f7b73962 --- /dev/null +++ b/examples/06.2DGraphics/2DGraphics.cbp @@ -0,0 +1,55 @@ + + + + + + diff --git a/examples/06.2DGraphics/2DGraphics.vcproj b/examples/06.2DGraphics/2DGraphics.vcproj new file mode 100644 index 00000000..b21c3517 --- /dev/null +++ b/examples/06.2DGraphics/2DGraphics.vcproj @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/06.2DGraphics/2DGraphics.xcodeproj/project.pbxproj b/examples/06.2DGraphics/2DGraphics.xcodeproj/project.pbxproj new file mode 100644 index 00000000..5848bbf1 --- /dev/null +++ b/examples/06.2DGraphics/2DGraphics.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 06.2DGraphics.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 06.2DGraphics.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 06.2DGraphics.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 06.2DGraphics */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "06.2DGraphics" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 06.2DGraphics; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 06.2DGraphics.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "2DGraphics" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 06.2DGraphics */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "2DGraphics" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "06.2DGraphics" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/06.2DGraphics/2DGraphics.xcodeproj/xcshareddata/xcschemes/06.2DGraphics.xcscheme b/examples/06.2DGraphics/2DGraphics.xcodeproj/xcshareddata/xcschemes/06.2DGraphics.xcscheme new file mode 100644 index 00000000..6a138026 --- /dev/null +++ b/examples/06.2DGraphics/2DGraphics.xcodeproj/xcshareddata/xcschemes/06.2DGraphics.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/06.2DGraphics/2DGraphics_vc10.vcxproj b/examples/06.2DGraphics/2DGraphics_vc10.vcxproj new file mode 100644 index 00000000..07fd309f --- /dev/null +++ b/examples/06.2DGraphics/2DGraphics_vc10.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 06.2DGraphics + {E71B6F18-10DC-4101-A541-F6D33F71B2BD} + 2DGraphics + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/2DGraphics.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\06.2DGraphics.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/2DGraphics.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\06.2DGraphics.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Debug/2DGraphics.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\06.2DGraphics.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/2DGraphics.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\06.2DGraphics.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/06.2DGraphics/2DGraphics_vc11.vcxproj b/examples/06.2DGraphics/2DGraphics_vc11.vcxproj new file mode 100644 index 00000000..07fd309f --- /dev/null +++ b/examples/06.2DGraphics/2DGraphics_vc11.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 06.2DGraphics + {E71B6F18-10DC-4101-A541-F6D33F71B2BD} + 2DGraphics + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/2DGraphics.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\06.2DGraphics.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/2DGraphics.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\06.2DGraphics.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Debug/2DGraphics.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\06.2DGraphics.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/2DGraphics.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\06.2DGraphics.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/06.2DGraphics/2DGraphics_vc12.vcxproj b/examples/06.2DGraphics/2DGraphics_vc12.vcxproj new file mode 100644 index 00000000..a4750aad --- /dev/null +++ b/examples/06.2DGraphics/2DGraphics_vc12.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 06.2DGraphics + {E71B6F18-10DC-4101-A541-F6D33F71B2BD} + 2DGraphics + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/2DGraphics.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\06.2DGraphics.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/2DGraphics.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\06.2DGraphics.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Debug/2DGraphics.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\06.2DGraphics.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/2DGraphics.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\06.2DGraphics.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/06.2DGraphics/2DGraphics_vc14.vcxproj b/examples/06.2DGraphics/2DGraphics_vc14.vcxproj new file mode 100644 index 00000000..e4d22b1c --- /dev/null +++ b/examples/06.2DGraphics/2DGraphics_vc14.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 06.2DGraphics + {E71B6F18-10DC-4101-A541-F6D33F71B2BD} + 2DGraphics + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/2DGraphics.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\06.2DGraphics.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/2DGraphics.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\06.2DGraphics.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Debug/2DGraphics.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\06.2DGraphics.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/2DGraphics.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\06.2DGraphics.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/06.2DGraphics/Makefile b/examples/06.2DGraphics/Makefile new file mode 100644 index 00000000..84cb831d --- /dev/null +++ b/examples/06.2DGraphics/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 06.2DGraphics +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/06.2DGraphics/main.cpp b/examples/06.2DGraphics/main.cpp new file mode 100644 index 00000000..930fbea5 --- /dev/null +++ b/examples/06.2DGraphics/main.cpp @@ -0,0 +1,168 @@ +/** Example 006 2D Graphics + +This tutorial shows how to do 2d graphics with the Irrlicht Engine. +It shows how to draw images, keycolor based sprites, +transparent rectangles, and different fonts. You may consider +this useful if you want to make a 2d game with the engine, or if +you want to draw a cool interface or head up display for your 3d game. + +As always, I include the header files, use the irr namespace, +and tell the linker to link with the .lib file. +*/ +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +using namespace irr; + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +/* +At first, we let the user select the driver type, then start up the engine, set +a caption, and get a pointer to the video driver. +*/ +int main() +{ + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + // create device + IrrlichtDevice *device = createDevice(driverType, + core::dimension2d(512, 384)); + + if (device == 0) + return 1; // could not create selected driver. + + device->setWindowCaption(L"Irrlicht Engine - 2D Graphics Demo"); + + video::IVideoDriver* driver = device->getVideoDriver(); + + const io::path mediaPath = getExampleMediaPath(); + + /* + All 2d graphics in this example are put together into one texture, + 2ddemo.png. Because we want to draw colorkey based sprites, we need to + load this texture and tell the engine, which part of it should be + transparent based on a colorkey. + + In this example, we don't tell it the color directly, we just say "Hey + Irrlicht Engine, you'll find the color I want at position (0,0) on the + texture.". Instead, it would be also possible to call + driver->makeColorKeyTexture(images, video::SColor(0,0,0,0)), to make + e.g. all black pixels transparent. Please note that + makeColorKeyTexture just creates an alpha channel based on the color. + */ + video::ITexture* images = driver->getTexture(mediaPath + "2ddemo.png"); + driver->makeColorKeyTexture(images, core::position2d(0,0)); + + /* + To be able to draw some text with two different fonts, we first load + them. OK, we load just one. As the first font we just use the default + font which is built into the engine. Also, we define two rectangles + which specify the position of the images of the red imps (little flying + creatures) in the texture. + */ + gui::IGUIFont* font = device->getGUIEnvironment()->getBuiltInFont(); + gui::IGUIFont* font2 = + device->getGUIEnvironment()->getFont(mediaPath + "fonthaettenschweiler.bmp"); + + core::rect imp1(349,15,385,78); + core::rect imp2(387,15,423,78); + + /* + Prepare a nicely filtering 2d render mode for special cases. + */ + driver->getMaterial2D().TextureLayer[0].BilinearFilter=true; + driver->getMaterial2D().AntiAliasing=video::EAAM_FULL_BASIC; + + /* + Everything is prepared, now we can draw everything in the draw loop, + between the begin scene and end scene calls. In this example, we are + just doing 2d graphics, but it would be no problem to mix them with 3d + graphics. Just try it out, and draw some 3d vertices or set up a scene + with the scene manager and draw it. + */ + while(device->run() && driver) + { + if (device->isWindowActive()) + { + u32 time = device->getTimer()->getTime(); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,120,102,136)); + + /* + First, we draw 3 sprites, using the alpha channel we + created with makeColorKeyTexture. The last parameter + specifies that the drawing method should use this alpha + channel. The last-but-one parameter specifies a + color, with which the sprite should be colored. + (255,255,255,255) is full white, so the sprite will + look like the original. The third sprite is drawn + with the red channel modulated based on the time. + */ + + // draw fire & dragons background world + driver->draw2DImage(images, core::position2d(50,50), + core::rect(0,0,342,224), 0, + video::SColor(255,255,255,255), true); + + // draw flying imp + driver->draw2DImage(images, core::position2d(164,125), + (time/500 % 2) ? imp1 : imp2, 0, + video::SColor(255,255,255,255), true); + + // draw second flying imp with color cycle + driver->draw2DImage(images, core::position2d(270,105), + (time/500 % 2) ? imp1 : imp2, 0, + video::SColor(255,(time) % 255,255,255), true); + + /* + Drawing text is really simple. The code should be self + explanatory. + */ + + // draw some text + if (font) + font->draw(L"This demo shows that Irrlicht is also capable of drawing 2D graphics.", + core::rect(130,10,300,50), + video::SColor(255,255,255,255)); + + // draw some other text + if (font2) + font2->draw(L"Also mixing with 3d graphics is possible.", + core::rect(130,20,300,60), + video::SColor(255,time % 255,time % 255,255)); + + /* + Next, we draw the Irrlicht Engine logo (without + using a color or an alpha channel). Since we slightly scale + the image we use the prepared filter mode. + */ + driver->enableMaterial2D(); + driver->draw2DImage(images, core::rect(10,10,108,48), + core::rect(354,87,442,118)); + driver->enableMaterial2D(false); + + /* + Finally draw a half-transparent rect under the mouse cursor. + */ + core::position2d m = device->getCursorControl()->getPosition(); + driver->draw2DRectangle(video::SColor(100,255,255,255), + core::rect(m.X-20, m.Y-20, m.X+20, m.Y+20)); + + driver->endScene(); + } + } + + device->drop(); + + return 0; +} + +/* +That's all. I hope it was not too difficult. +**/ diff --git a/examples/06.2DGraphics/tutorial.html b/examples/06.2DGraphics/tutorial.html new file mode 100644 index 00000000..ea6291af --- /dev/null +++ b/examples/06.2DGraphics/tutorial.html @@ -0,0 +1,163 @@ + + +Irrlicht Engine Tutorial + + + + +
+ + + + + + + + +
+
+
+
Tutorial 6. 2D Graphics
+
+
+
+

This Tutorial shows how to do 2d graphics with the Irrlicht Engine. + It shows how to draw images, keycolor based sprites, transparent rectangles + and different fonts. You will may consider this useful if you want to + make a 2d game with the engine, or if you want to draw a cool interface + or head up display for your 3d game.

+

The program which is described here will look like this:

+


+

+
+
+
+ + + + + + + +
+ Lets start!
+

As always, I include the header files, use the irr namespace, and tell + the linker to link with the .lib file.

+ + + + +
#include <irrlicht.h>
#include <iostream>

using namespace irr;
+
#pragma comment(lib, "Irrlicht.lib")
+               
+

At first, we let the user select the driver type, then start up the + engine, set a caption, and get a pointer to the video driver.

+ + + + +
int main()
{
// let user select driver type
video::E_DRIVER_TYPE driverType;

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) Apfelbaum Software Renderer\n"\
" (f) NullDevice\n (otherKey) exit\n\n");

char i;
std::cin >> i;

switch(i)
{
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;
default: return 0;
}

// create device
+
  IrrlichtDevice *device = createDevice(driverType,
+         core::dimension2d<s32>(512, 384));
+
  if (device == 0)
+      return 1;
+ 
device->setWindowCaption(L"Irrlicht Engine - 2D Graphics Demo");
+
  video::IVideoDriver* driver = device->getVideoDriver();
+

All 2d graphics in this example are put together into one texture, + 2ddemo.bmp. Because we want to draw colorkey based sprites, we need + to load this texture and tell the engine, which part of it should be + transparent based on a colorkey. In this example, we don't tell it the + color directly, we just say "Hey Irrlicht Engine, you'll find the + color I want at position (0,0) on the texture.". Instead, it would + be also possible to call driver->makeColorKeyTexture(images, + video::SColor(0,0,0,0)), to make e.g. all black pixels transparent. + Please note, that makeColorKeyTexture just creates an alpha channel + based on the color.

+ + + + +
video::ITexture* images = driver->getTexture("../../media/2ddemo.bmp");
driver->makeColorKeyTexture(images, core::position2d<s32>(0,0));
+

To be able to draw some text with two different fonts, we load them. + Ok, we load just one, as first font we just use the default font which + is built into the engine.
+ Also, we define two rectangles, which specify the position of the images + of the red imps (little flying creatures) in the texture.

+ + + + +
gui::IGUIFont* font = device->getGUIEnvironment()->getBuiltInFont();
gui::IGUIFont* font2 = device->getGUIEnvironment()->getFont( + "../../media/fonthaettenschweiler.bmp");
+
core::rect<s32> imp1(349,15,385,78);
+core::rect<s32> imp2(387,15,423,78);
+

Everything is prepared, now we can draw everything in the draw loop, + between the begin scene and end scene calls. In this example, we are + just doing 2d graphics, but it would be no problem to mix them with + 3d graphics. Just try it out, and draw some 3d vertices or set up a + scene with the scene manager and draw it.

+
+ + + + +
while(device->run() && driver)
{
if (device->isWindowActive())
{
u32 time = device->getTimer()->getTime();
driver->beginScene(true, true, video::SColor(0,120,102,136)); +
+

First, we draw 3 sprites, using the alpha channel we created with makeColorKeyTexture. + The last parameter specifiys that the drawing method should use thiw alpha + channel. The parameter before the last one specifies a color, with wich + the sprite should be colored. (255,255,255,255) is full white, so the + sprite will look like the original. The third sprite is drawed colored + based on the time.

+ + + + +
// draw fire & dragons background world
driver->draw2DImage(images, core::position2d<s32>(50,50),
core::rect<s32>(0,0,342,224), 0,
video::SColor(255,255,255,255), true);
+
// draw flying imp 
+driver->draw2DImage(images, core::position2d<s32>(164,125),
+  (time/500 % 2) ? imp1 : imp2, 0, 
+   video::SColor(255,255,255,255), true);
+
// draw second flying imp with colorcylce
+driver->draw2DImage(images, core::position2d<s32>(270,105),
+  (time/500 % 2) ? imp1 : imp2, 0, 
+  video::SColor(255,(time) % 255,255,255), true);
+

Drawing text is really simple. The code should be self explanatory.

+ + + + +
// draw some text
if (font)
font->draw(L"This is some text.",
core::rect<s32>(130,10,300,50),
video::SColor(255,255,255,255));
+
// draw some other text
+if (font2)
+   font2->draw(L"This is some other text.", 
+       core::rect<s32>(130,20,300,60),
+       video::SColor(255,time % 255,time % 255,255));
+

At last, we draw the Irrlicht Engine logo (without using a color or an + alpha channel) and a transparent 2d Rectangle at the position of the mouse + cursor.

+ + + + +
    // draw logo
driver->draw2DImage(images, core::position2d<s32>(10,10),
core::rect<s32>(354,87,442,118));
+
    // draw transparent rect under cursor
+    core::position2d<s32> m = device->getCursorControl()->getPosition();
+    driver->draw2DRectangle(video::SColor(100,255,255,255),
+          core::rect<s32>(m.X-20, m.Y-20, m.X+20, m.Y+20));
+
    driver->endScene();
+  }
+}
+

That's all, it was not really difficult, I hope.

+ + + + +
   device->drop();
+   return 0;
+}
+
+

 

+

 

+ + diff --git a/examples/07.Collision/Collision.cbp b/examples/07.Collision/Collision.cbp new file mode 100644 index 00000000..1d735879 --- /dev/null +++ b/examples/07.Collision/Collision.cbp @@ -0,0 +1,55 @@ + + + + + + diff --git a/examples/07.Collision/Collision.vcproj b/examples/07.Collision/Collision.vcproj new file mode 100644 index 00000000..a4e4b076 --- /dev/null +++ b/examples/07.Collision/Collision.vcproj @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/07.Collision/Collision.xcodeproj/project.pbxproj b/examples/07.Collision/Collision.xcodeproj/project.pbxproj new file mode 100644 index 00000000..2dbe0680 --- /dev/null +++ b/examples/07.Collision/Collision.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 07.Collision.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 07.Collision.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 07.Collision.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 07.Collision */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "07.Collision" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 07.Collision; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 07.Collision.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Collision" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 07.Collision */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Collision" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "07.Collision" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/07.Collision/Collision.xcodeproj/xcshareddata/xcschemes/07.Collision.xcscheme b/examples/07.Collision/Collision.xcodeproj/xcshareddata/xcschemes/07.Collision.xcscheme new file mode 100644 index 00000000..c9728c83 --- /dev/null +++ b/examples/07.Collision/Collision.xcodeproj/xcshareddata/xcschemes/07.Collision.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/07.Collision/Collision_vc10.vcxproj b/examples/07.Collision/Collision_vc10.vcxproj new file mode 100644 index 00000000..72fcae0a --- /dev/null +++ b/examples/07.Collision/Collision_vc10.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 07.Collision + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E} + Collision + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Collision.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\07.Collision.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Collision.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\07.Collision.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Collision.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\07.Collision.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Collision.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\07.Collision.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/07.Collision/Collision_vc11.vcxproj b/examples/07.Collision/Collision_vc11.vcxproj new file mode 100644 index 00000000..72fcae0a --- /dev/null +++ b/examples/07.Collision/Collision_vc11.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 07.Collision + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E} + Collision + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Collision.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\07.Collision.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Collision.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\07.Collision.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Collision.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\07.Collision.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Collision.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\07.Collision.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/07.Collision/Collision_vc12.vcxproj b/examples/07.Collision/Collision_vc12.vcxproj new file mode 100644 index 00000000..6434626b --- /dev/null +++ b/examples/07.Collision/Collision_vc12.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 07.Collision + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E} + Collision + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Collision.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\07.Collision.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Collision.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\07.Collision.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Collision.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\07.Collision.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Collision.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\07.Collision.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/07.Collision/Collision_vc14.vcxproj b/examples/07.Collision/Collision_vc14.vcxproj new file mode 100644 index 00000000..06983f17 --- /dev/null +++ b/examples/07.Collision/Collision_vc14.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 07.Collision + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E} + Collision + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Collision.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\07.Collision.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Collision.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\07.Collision.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Collision.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\07.Collision.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Collision.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\07.Collision.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/07.Collision/Makefile b/examples/07.Collision/Makefile new file mode 100644 index 00000000..25efc238 --- /dev/null +++ b/examples/07.Collision/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 07.Collision +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/07.Collision/main.cpp b/examples/07.Collision/main.cpp new file mode 100644 index 00000000..a52f493e --- /dev/null +++ b/examples/07.Collision/main.cpp @@ -0,0 +1,375 @@ +/** Example 007 Collision + +We will describe 2 methods: Automatic collision detection for moving through +3d worlds with stair climbing and sliding, and manual scene node and triangle +picking using a ray. In this case, we will use a ray coming out from the +camera, but you can use any ray. + +To start, we take the program from tutorial 2, which loads and displays a +quake 3 level. We will use the level to walk in it and to pick triangles from. +In addition we'll place 3 animated models into it for triangle picking. The +following code starts up the engine and loads the level, as per tutorial 2. +*/ +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +using namespace irr; + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +enum +{ + // I use this ISceneNode ID to indicate a scene node that is + // not pickable by getSceneNodeAndCollisionPointFromRay() + ID_IsNotPickable = 0, + + // I use this flag in ISceneNode IDs to indicate that the + // scene node can be picked by ray selection. + IDFlag_IsPickable = 1 << 0, + + // I use this flag in ISceneNode IDs to indicate that the + // scene node can be highlighted. In this example, the + // homonids can be highlighted, but the level mesh can't. + IDFlag_IsHighlightable = 1 << 1 +}; + +int main() +{ + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + // create device + + IrrlichtDevice *device = + createDevice(driverType, core::dimension2d(640, 480), 16, false); + + if (device == 0) + return 1; // could not create selected driver. + + /* + If we want to receive information about the material of a hit triangle we have to get + collisions per meshbuffer. The only disadvantage of this is that getting them per + meshbuffer can be a little bit slower than per mesh, but usually that's not noticeable. + If you set this to false you will no longer get material names in the title bar. + */ + const bool separateMeshBuffers = true; + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + + const io::path mediaPath = getExampleMediaPath(); + + device->getFileSystem()->addFileArchive(mediaPath + "map-20kdm2.pk3"); + + scene::IAnimatedMesh* q3levelmesh = smgr->getMesh("20kdm2.bsp"); + scene::IMeshSceneNode* q3node = 0; + + // The Quake mesh is pickable, but doesn't get highlighted. + if (q3levelmesh) + q3node = smgr->addOctreeSceneNode(q3levelmesh->getMesh(0), 0, IDFlag_IsPickable); + + /* + 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 + triangle selector is a class which can fetch the triangles from scene + nodes for doing different things with them, for example collision + detection. There are different triangle selectors, and all can be + created with the ISceneManager. In this example, we create an + OctreeTriangleSelector, which optimizes the triangle output a little + bit by reducing it like an octree. This is very useful for huge meshes + like quake 3 levels. After we created the triangle selector, we attach + it to the q3node. This is not necessary, but in this way, we do not + need to care for the selector, for example dropping it after we do not + need it anymore. + */ + + scene::ITriangleSelector* selector = 0; + + if (q3node) + { + q3node->setPosition(core::vector3df(-1350,-130,-1400)); + + /* + There is currently no way to split an octree by material. + So if we need material infos we have to create one octree per + meshbuffer and put them together in a MetaTriangleSelector. + */ + if ( separateMeshBuffers && q3node->getMesh()->getMeshBufferCount() > 1) + { + scene::IMetaTriangleSelector * metaSelector = smgr->createMetaTriangleSelector(); + for ( irr::u32 m=0; m < q3node->getMesh()->getMeshBufferCount(); ++m ) + { + scene::ITriangleSelector* + bufferSelector = smgr->createOctreeTriangleSelector( + q3node->getMesh()->getMeshBuffer(m), m, q3node); + if ( bufferSelector ) + { + metaSelector->addTriangleSelector( bufferSelector ); + bufferSelector->drop(); + } + } + selector = metaSelector; + } + else + { + // If you don't need material infos just create one octree for the + // whole mesh. + selector = smgr->createOctreeTriangleSelector( + q3node->getMesh(), q3node, 128); + } + q3node->setTriangleSelector(selector); + // We're not done with this selector yet, so don't drop it. + } + + + /* + We add a first person shooter camera to the scene so that we can see and + move in the quake 3 level like in tutorial 2. But this, time, we add a + special animator to the camera: A collision response animator. This + animator modifies the scene node to which it is attached in order to + prevent it from moving through walls and to add gravity to the node. The + only things we have to tell the animator is how the world looks like, + how big the scene node is, how much gravity to apply and so on. After the + collision response animator is attached to the camera, we do not have to do + anything else for collision detection, it's all done automatically. + The rest of the collision detection code below is for picking. And please + note another cool feature: The collision response animator can be + attached also to all other scene nodes, not only to cameras. And it can + be mixed with other scene node animators. In this way, collision + detection and response in the Irrlicht engine is really easy. + + Now we'll take a closer look on the parameters of + createCollisionResponseAnimator(). The first parameter is the + TriangleSelector, which specifies how the world, against which collision + detection is done, looks like. The second parameter is the scene node, + which is the object which is affected by collision detection - in our + case it is the camera. The third defines how big the object is, it is + the radius of an ellipsoid. Try it out and change the radius to smaller + values, the camera will be able to move closer to walls after this. The + next parameter is the direction and speed of gravity. We'll set it to + (0, -1000, 0), which approximates realistic gravity (depends on the units + which are used in the scene model). You could set it to (0,0,0) to disable + gravity. And the last value is just an offset: Without it the ellipsoid with + which collision detection is done would be around the camera and the camera + would be in the middle of the ellipsoid. But as human beings, we are used to + have our eyes on top of the body, not in the middle of it. So we place the + scene node 50 units over the center of the ellipsoid with this parameter. + And that's it, collision detection works now. + */ + + // Set a jump speed of 300 units per second, which gives a fairly realistic jump + // when used with the gravity of (0, -1000, 0) in the collision response animator. + scene::ICameraSceneNode* camera = + smgr->addCameraSceneNodeFPS(0, 100.0f, .3f, ID_IsNotPickable, 0, 0, true, 300.f); + camera->setPosition(core::vector3df(50,50,-60)); + camera->setTarget(core::vector3df(-70,30,-60)); + + if (selector) + { + scene::ISceneNodeAnimatorCollisionResponse * anim = smgr->createCollisionResponseAnimator( + selector, camera, core::vector3df(30,50,30), + core::vector3df(0,-1000,0), core::vector3df(0,30,0)); + selector->drop(); // As soon as we're done with the selector, drop it. + camera->addAnimator(anim); + anim->drop(); // And likewise, drop the animator when we're done referring to it. + } + + // Now I create three animated characters which we can pick, a dynamic light for + // lighting them, and a billboard for drawing where we found an intersection. + + // First, let's get rid of the mouse cursor. We'll use a billboard to show + // what we're looking at. + device->getCursorControl()->setVisible(false); + + // Add the billboard. + scene::IBillboardSceneNode * bill = smgr->addBillboardSceneNode(); + bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR ); + bill->setMaterialTexture(0, driver->getTexture(mediaPath + "particle.bmp")); + bill->setMaterialFlag(video::EMF_LIGHTING, false); + bill->setMaterialFlag(video::EMF_ZBUFFER, false); + bill->setSize(core::dimension2d(20.0f, 20.0f)); + bill->setID(ID_IsNotPickable); // This ensures that we don't accidentally ray-pick it + + /* Add 3 animated hominids, which we can pick using a ray-triangle intersection. + They all animate quite slowly, to make it easier to see that accurate triangle + selection is being performed. */ + scene::IAnimatedMeshSceneNode* node = 0; + + video::SMaterial material; + + // Add an MD2 node, which uses vertex-based animation. + node = smgr->addAnimatedMeshSceneNode(smgr->getMesh(mediaPath + "faerie.md2"), + 0, IDFlag_IsPickable | IDFlag_IsHighlightable); + node->setPosition(core::vector3df(-90,-15,-140)); // Put its feet on the floor. + node->setScale(core::vector3df(1.6f)); // Make it appear realistically scaled + node->setMD2Animation(scene::EMAT_POINT); + node->setAnimationSpeed(20.f); + material.setTexture(0, driver->getTexture(mediaPath + "faerie2.bmp")); + material.Lighting = true; + material.NormalizeNormals = true; + node->getMaterial(0) = material; + + // Now create a triangle selector for it. The selector will know that it + // is associated with an animated node, and will update itself as necessary. + selector = smgr->createTriangleSelector(node, separateMeshBuffers); + node->setTriangleSelector(selector); + selector->drop(); // We're done with this selector, so drop it now. + + // And this B3D file uses skinned skeletal animation. + node = smgr->addAnimatedMeshSceneNode(smgr->getMesh(mediaPath + "ninja.b3d"), + 0, IDFlag_IsPickable | IDFlag_IsHighlightable); + node->setScale(core::vector3df(10)); + node->setPosition(core::vector3df(-75,-66,-80)); + node->setRotation(core::vector3df(0,90,0)); + node->setAnimationSpeed(8.f); + node->getMaterial(0).NormalizeNormals = true; + node->getMaterial(0).Lighting = true; + // Just do the same as we did above. + selector = smgr->createTriangleSelector(node, separateMeshBuffers); + node->setTriangleSelector(selector); + selector->drop(); + + // This X files uses skeletal animation, but without skinning. + node = smgr->addAnimatedMeshSceneNode(smgr->getMesh(mediaPath + "dwarf.x"), + 0, IDFlag_IsPickable | IDFlag_IsHighlightable); + node->setPosition(core::vector3df(-70,-66,-30)); // Put its feet on the floor. + node->setRotation(core::vector3df(0,-90,0)); // And turn it towards the camera. + node->setAnimationSpeed(20.f); + node->getMaterial(0).Lighting = true; + selector = smgr->createTriangleSelector(node, separateMeshBuffers); + node->setTriangleSelector(selector); + selector->drop(); + + // And this mdl file uses skinned skeletal animation. + node = smgr->addAnimatedMeshSceneNode(smgr->getMesh(mediaPath + "yodan.mdl"), + 0, IDFlag_IsPickable | IDFlag_IsHighlightable); + node->setPosition(core::vector3df(-90,-25,20)); + node->setScale(core::vector3df(0.8f)); + node->getMaterial(0).Lighting = true; + node->setAnimationSpeed(20.f); + + // Just do the same as we did above. + selector = smgr->createTriangleSelector(node, separateMeshBuffers); + node->setTriangleSelector(selector); + selector->drop(); + + material.setTexture(0, 0); + material.Lighting = false; + + // Add a light, so that the unselected nodes aren't completely dark. + 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(ID_IsNotPickable); // Make it an invalid target for selection. + + // Remember which scene node is highlighted + scene::ISceneNode* highlightedSceneNode = 0; + scene::ISceneCollisionManager* collMan = smgr->getSceneCollisionManager(); + + // draw the selection triangle only as wireframe + material.Wireframe=true; + + while(device->run()) + if (device->isWindowActive()) + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0)); + smgr->drawAll(); + + // Unlight any currently highlighted scene node + if (highlightedSceneNode) + { + highlightedSceneNode->setMaterialFlag(video::EMF_LIGHTING, true); + highlightedSceneNode = 0; + } + + // All intersections in this example are done with a ray cast out from the camera to + // a distance of 1000. You can easily modify this to check (e.g.) a bullet + // trajectory or a sword's position, or create a ray from a mouse click position using + // ISceneCollisionManager::getRayFromScreenCoordinates() + core::line3d ray; + ray.start = camera->getPosition(); + ray.end = ray.start + (camera->getTarget() - ray.start).normalize() * 1000.0f; + + + // This call is all you need to perform ray/triangle collision on every scene node + // that has a triangle selector, including the Quake level mesh. It finds the nearest + // collision point/triangle, and returns the scene node containing that point. + // Irrlicht provides other types of selection, including ray/triangle selector, + // ray/box and ellipse/triangle selector, plus associated helpers. + // You might also want to check the other methods of ISceneCollisionManager. + + irr::io::SNamedPath hitTextureName; + scene::SCollisionHit hitResult; + scene::ISceneNode * selectedSceneNode =collMan->getSceneNodeAndCollisionPointFromRay( + hitResult, // Returns all kind of info about the collision + ray, + IDFlag_IsPickable, // This ensures that only nodes that we have + // set up to be pickable are considered + 0); // Check the entire scene (this is actually the implicit default) + + + // If the ray hit anything, move the billboard to the collision position + // and draw the triangle that was hit. + if(selectedSceneNode) + { + bill->setPosition(hitResult.Intersection); // Show the current intersection point with the level or a mesh + + // We need to reset the transform before doing our own rendering. + driver->setTransform(video::ETS_WORLD, core::matrix4()); + driver->setMaterial(material); + driver->draw3DTriangle(hitResult.Triangle, video::SColor(0,255,0,0)); // Show which triangle has been hit + + // We can check the flags for the scene node that was hit to see if it should be + // highlighted. The animated nodes can be highlighted, but not the Quake level mesh + if((selectedSceneNode->getID() & IDFlag_IsHighlightable) == IDFlag_IsHighlightable) + { + highlightedSceneNode = selectedSceneNode; + + // Highlighting in this case means turning lighting OFF for this node, + // which means that it will be drawn with full brightness. + highlightedSceneNode->setMaterialFlag(video::EMF_LIGHTING, false); + } + + // When separateMeshBuffers is set to true we can now find out which material was hit + if ( hitResult.MeshBuffer && hitResult.Node && hitResult.Node->getMaterial(hitResult.MaterialIndex).TextureLayer[0].Texture ) + { + // Note we are interested in the node material and not in the meshbuffer material. + // Otherwise we wouldn't get the fairy2 texture which is only set on the node. + hitTextureName = hitResult.Node->getMaterial(hitResult.MaterialIndex).TextureLayer[0].Texture->getName(); + } + } + + // We're all done drawing, so end the scene. + driver->endScene(); + + // Show some info in title-bar + int fps = driver->getFPS(); + static core::stringw lastString; + core::stringw str = L"Collision detection example - Irrlicht Engine ["; + str += driver->getName(); + str += "] FPS:"; + str += fps; + if ( !hitTextureName.getInternalName().empty() ) + { + str += " "; + irr::io::path texName(hitTextureName.getInternalName()); + str += core::deletePathFromFilename(texName); + } + if ( str != lastString ) // changing caption is somewhat expensive, so don't when nothing changed + { + device->setWindowCaption(str.c_str()); + lastString = str; + } + } + + device->drop(); + + return 0; +} + +/* +**/ diff --git a/examples/07.Collision/tutorial.html b/examples/07.Collision/tutorial.html new file mode 100644 index 00000000..c04fce99 --- /dev/null +++ b/examples/07.Collision/tutorial.html @@ -0,0 +1,308 @@ + + +Irrlicht Engine Tutorial + + + + +
+ + + + + + + + +
+
+
+
Tutorial 7. Collision detection + and response
+
+
+
+

In this tutorial, I will show how to collision detection with the Irrlicht + Engine. I will describe 3 methods: Automatic collision detection for + moving through 3d worlds with stair climbing and sliding, manual triangle + picking and manual scene node picking.

+

The program which is described here will look like this:

+


+

+
+
+
+ + + + + + + +
+ Lets start!
+
+

To start, we take the program from tutorial 2, which loaded and displayed + a quake 3 level. We will use the level to walk in it and to pick triangles + from it. In addition we'll place 3 animated models into it for scene + node picking. The following code starts up the engine and loads a + quake 3 level. I will not explain it, because it should already be + known from tutorial 2.

+ + + + +
#include <irrlicht.h>
+#include <iostream>
+
using namespace irr; + +#pragma comment(lib, "Irrlicht.lib") + +int main() +{ + // let user select driver type +
video::E_DRIVER_TYPE driverType;

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) Apfelbaum Software Renderer\n"\
" (f) NullDevice\n (otherKey) exit\n\n");

char i;
std::cin >> i;

switch(i)
{
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;
default: return 0;
}
+ // create device
+
  IrrlichtDevice *device = createDevice(driverType,
+     core::dimension2d<s32>(640, 480), 16, false);
+ if (device == 0)
return 1; // could not create selected driver.

video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();

device->getFileSystem()->addZipFileArchive
("../../media/map-20kdm2.pk3"); + + + scene::IAnimatedMesh* q3levelmesh = smgr->getMesh("20kdm2.bsp"); + scene::ISceneNode* q3node = 0; + + if (q3levelmesh) + q3node = smgr->addOctTreeSceneNode(q3levelmesh->getMesh(0)); +
+
+

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 triangle selector is a class which can fetch the triangles from + scene nodes for doing different things with them, for example collision + detection. There are different triangle selectors, and all can be + created with the ISceneManager. In this example, we create an OctTreeTriangleSelector, + which optimizes the triangle output a little bit by reducing it like + an octree. This is very useful for huge meshes like quake 3 levels.
+ Afte we created the triangle selector, we attach it to the q3node. + This is not necessary, but in this way, we do not need to care for + the selector, for example dropping it after we do not need it anymore.

+ + + + +
scene::ITriangleSelector* selector = 0;
+	
+	if (q3node)
+	{		
+		q3node->setPosition(core::vector3df(-1370,-130,-1400));
+
+		selector = smgr->createOctTreeTriangleSelector(
+            q3levelmesh->getMesh(0), q3node, 128);
+		q3node->setTriangleSelector(selector);
+	}
+

We add a first person shooter camera to the scene for being able + to move in the quake 3 level like in tutorial 2. But this, time, we + add a special animator to the camera: A Collision Response animator. + This thing modifies the scene node to which it is attached to in that + way, that it may no more move through walls and is affected by gravity. + The only thing we have to tell the animator is how the world looks + like, how big the scene node is, how gravity and so on. After the + collision response animator is attached to the camera, we do not have + to do anything more for collision detection, anything is done automaticly, + all other collision detection code below is for picking. And please + note another cool feature: The collsion response animator can be attached + also to all other scene nodes, not only to cameras. And it can be + mixed with other scene node animators. In this way, collision detection + and response in the Irrlicht
+ engine is really, really easy.
+ Now we'll take a closer look on the parameters of createCollisionResponseAnimator(). + The first parameter is the TriangleSelector, which specifies how the + world, against collision detection is done looks like. The second + parameter is the scene node, which is the object, which is affected + by collision detection, in our case it is the camera. The third defines + how big the object is, it is the radius of an ellipsoid. Try it out + and change the radius to smaller values, the camera will be able to + move closer to walls after this. The next parameter is the direction + and speed of gravity. You could set it to (0,0,0) to disable gravity. + And the last value is just a translation: Without this, the ellipsoid + with which collision detection is done would be around the camera, + and the camera would be in the middle of the ellipsoid. But as human + beings, we are used to have our eyes on top of the body, with which + we collide with our world, not in the middle of it. So we place the + scene node 50 units over the center of the ellipsoid with this parameter. + And that's it, collision detection works now.
+

+ + + + +
	scene::ICameraSceneNode* camera = 	
camera = smgr->addCameraSceneNodeFPS(0,100.0f,300.0f); + camera->setPosition(core::vector3df(-100,50,-150)); + + scene::ISceneNodeAnimator* anim =
smgr->createCollisionResponseAnimator( + selector, camera, core::vector3df(30,50,30), + core::vector3df(0,-3,0), + core::vector3df(0,50,0));
+ selector->drop();
+ camera->addAnimator(anim); + anim->drop();
+

Because collision detection is no big deal in irrlicht, I'll describe + how to do two different types of picking in the next section. But + before this, I'll prepare the scene a little. I need three animated + characters which we
+ could pick later, a dynamic light for lighting them, a billboard for + drawing where we found an intersection, and, yes, I need to get rid + of this mouse cursor. :)

+ + + + +
	// disable mouse cursor
+
+	device->getCursorControl()->setVisible(false);
+
+	// add billboard
+
+	scene::IBillboardSceneNode * bill = smgr->addBillboardSceneNode();
+	bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR );
+	bill->setMaterialTexture(0, driver->getTexture(
"../../media/particle.bmp")); + bill->setMaterialFlag(video::EMF_LIGHTING, false); + bill->setSize(core::dimension2d<f32>(20.0f, 20.0f)); + + // add 3 animated faeries. + + video::SMaterial material; + material.Texture1 = driver->getTexture(
"../../media/faerie2.bmp"
); + material.Lighting = true; + + scene::IAnimatedMeshSceneNode* node = 0; + scene::IAnimatedMesh* faerie = smgr->getMesh(
"../../media/faerie.md2"); + + if (faerie) + { + node = smgr->addAnimatedMeshSceneNode(faerie); + node->setPosition(core::vector3df(-70,0,-90)); + node->setMD2Animation(scene::EMAT_RUN); + node->getMaterial(0) = material; + + node = smgr->addAnimatedMeshSceneNode(faerie); + node->setPosition(core::vector3df(-70,0,-30)); + node->setMD2Animation(scene::EMAT_SALUTE); + node->getMaterial(0) = material; + + node = smgr->addAnimatedMeshSceneNode(faerie); + node->setPosition(core::vector3df(-70,0,-60)); + node->setMD2Animation(scene::EMAT_JUMP); + node->getMaterial(0) = material; + } + + material.Texture1 = 0; + material.Lighting = false; + + // Add a light + + smgr->addLightSceneNode(0, core::vector3df(-60,100,400), + video::SColorf(1.0f,1.0f,1.0f,1.0f), + 600.0f);
+

For not making it to complicated, I'm doing picking inside the drawing + loop. We take two pointers for storing the current and the last selected + scene node and start the loop.

+
+ + + + +
	scene::ISceneNode* selectedSceneNode = 0;
+	scene::ISceneNode* lastSelectedSceneNode = 0;
+
+	
+	int lastFPS = -1;
+
+	while(device->run())
if (device->isWindowActive()) + { + driver->beginScene(true, true, 0); + + smgr->drawAll();
+

After we've drawn the whole scene whit smgr->drawAll(), we'll do + the first picking: We want to know which triangle of the world we are + looking at. In addition, we want the exact point of the quake 3 level + we are looking at. For this, we create a 3d line starting at the position + of the camera and going through the lookAt-target of it. Then we ask + the collision manager if this line collides with a triangle of the world + stored in the triangle selector. If yes, we draw the 3d triangle and + set the position of the billboard to the intersection point.

+ + + + +
		core::line3d<f32> line;
+		line.start = camera->getPosition();
+		line.end = line.start +
+         (camera->getTarget() - line.start).normalize() * 1000.0f;
+
+		core::vector3df intersection;
+		core::triangle3df tri;
+
+		if (smgr->getSceneCollisionManager()->getCollisionPoint(
+			line, selector, intersection, tri))
+		{
+			bill->setPosition(intersection);
+				
+			driver->setTransform(video::ETS_WORLD, core::matrix4());
+			driver->setMaterial(material);
+			driver->draw3DTriangle(tri, video::SColor(0,255,0,0));
+		}
+

Another type of picking supported by the Irrlicht Engine is scene + node picking based on bouding boxes. Every scene node has got a bounding + box, and because of that, it's very fast for example to get the scene + node which the camera looks
+ at. Again, 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.

+ + + + +
		selectedSceneNode = smgr->getSceneCollisionManager()->
+          getSceneNodeFromCameraBB(camera);
+
+		if (lastSelectedSceneNode)
+			lastSelectedSceneNode->setMaterialFlag(
+                video::EMF_LIGHTING, true);
+
+		if (selectedSceneNode == q3node ||
+           selectedSceneNode == bill)
+			selectedSceneNode = 0;
+
+		if (selectedSceneNode)
+			selectedSceneNode->setMaterialFlag(
+               video::EMF_LIGHTING, false);
+
+		lastSelectedSceneNode = selectedSceneNode;
+

That's it, we just have to finish drawing.

+ + + + +
		driver->endScene();
+
+		int fps = driver->getFPS();
+
+		if (lastFPS != fps)
+		{
+		  core::stringw str = L"Collision detection example - Irrlicht Engine [";
str += driver->getName();
str += "] FPS:";
str += fps;

device->setWindowCaption(str.c_str());
lastFPS = fps;
} + } + + device->drop(); + + return 0; +} + +
+

 

+

 

+
+
+

 

+ + diff --git a/examples/08.SpecialFX/Makefile b/examples/08.SpecialFX/Makefile new file mode 100644 index 00000000..2a382f35 --- /dev/null +++ b/examples/08.SpecialFX/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 08.SpecialFX +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/08.SpecialFX/SpecialFX.cbp b/examples/08.SpecialFX/SpecialFX.cbp new file mode 100644 index 00000000..c23c621f --- /dev/null +++ b/examples/08.SpecialFX/SpecialFX.cbp @@ -0,0 +1,54 @@ + + + + + + diff --git a/examples/08.SpecialFX/SpecialFX.vcproj b/examples/08.SpecialFX/SpecialFX.vcproj new file mode 100644 index 00000000..e22266e3 --- /dev/null +++ b/examples/08.SpecialFX/SpecialFX.vcproj @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/08.SpecialFX/SpecialFX.xcodeproj/project.pbxproj b/examples/08.SpecialFX/SpecialFX.xcodeproj/project.pbxproj new file mode 100644 index 00000000..cc37ca7f --- /dev/null +++ b/examples/08.SpecialFX/SpecialFX.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 08.SpecialFX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 08.SpecialFX.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 08.SpecialFX.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 08.SpecialFX */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "08.SpecialFX" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 08.SpecialFX; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 08.SpecialFX.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "SpecialFX" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 08.SpecialFX */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "SpecialFX" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "08.SpecialFX" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/08.SpecialFX/SpecialFX.xcodeproj/xcshareddata/xcschemes/08.SpecialFX.xcscheme b/examples/08.SpecialFX/SpecialFX.xcodeproj/xcshareddata/xcschemes/08.SpecialFX.xcscheme new file mode 100644 index 00000000..71ffc702 --- /dev/null +++ b/examples/08.SpecialFX/SpecialFX.xcodeproj/xcshareddata/xcschemes/08.SpecialFX.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/08.SpecialFX/SpecialFX_vc10.vcxproj b/examples/08.SpecialFX/SpecialFX_vc10.vcxproj new file mode 100644 index 00000000..fd669a1a --- /dev/null +++ b/examples/08.SpecialFX/SpecialFX_vc10.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 08.SpecialFX + {C869BF55-B9D6-4980-BC92-60FA0CF8411A} + SpecialFX + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/SpecialFX.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\08.SpecialFx.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/SpecialFX.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\08.SpecialFx.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Debug/SpecialFX.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\08.SpecialFx.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/SpecialFX.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\08.SpecialFx.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/08.SpecialFX/SpecialFX_vc11.vcxproj b/examples/08.SpecialFX/SpecialFX_vc11.vcxproj new file mode 100644 index 00000000..fd669a1a --- /dev/null +++ b/examples/08.SpecialFX/SpecialFX_vc11.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 08.SpecialFX + {C869BF55-B9D6-4980-BC92-60FA0CF8411A} + SpecialFX + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/SpecialFX.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\08.SpecialFx.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/SpecialFX.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\08.SpecialFx.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Debug/SpecialFX.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\08.SpecialFx.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/SpecialFX.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\08.SpecialFx.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/08.SpecialFX/SpecialFX_vc12.vcxproj b/examples/08.SpecialFX/SpecialFX_vc12.vcxproj new file mode 100644 index 00000000..45f60640 --- /dev/null +++ b/examples/08.SpecialFX/SpecialFX_vc12.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 08.SpecialFX + {C869BF55-B9D6-4980-BC92-60FA0CF8411A} + SpecialFX + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/SpecialFX.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\08.SpecialFx.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/SpecialFX.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\08.SpecialFx.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Debug/SpecialFX.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\08.SpecialFx.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/SpecialFX.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\08.SpecialFx.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/08.SpecialFX/SpecialFX_vc14.vcxproj b/examples/08.SpecialFX/SpecialFX_vc14.vcxproj new file mode 100644 index 00000000..d91a31f6 --- /dev/null +++ b/examples/08.SpecialFX/SpecialFX_vc14.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 08.SpecialFX + {C869BF55-B9D6-4980-BC92-60FA0CF8411A} + SpecialFX + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/SpecialFX.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\08.SpecialFx.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/SpecialFX.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\08.SpecialFx.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Debug/SpecialFX.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\08.SpecialFx.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/SpecialFX.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\08.SpecialFx.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/08.SpecialFX/main.cpp b/examples/08.SpecialFX/main.cpp new file mode 100644 index 00000000..c72674b7 --- /dev/null +++ b/examples/08.SpecialFX/main.cpp @@ -0,0 +1,326 @@ +/** Example 008 SpecialFX + +This tutorial describes how to do special effects. It shows how to use stencil +buffer shadows, the particle system, billboards, dynamic light, and the water +surface scene node. + +We start like in some tutorials before. Please note that this time, the +'shadows' flag in createDevice() is set to true, for we want to have a dynamic +shadow cast from an animated character. If this example runs too slow, +set it to false. The Irrlicht Engine also checks if your hardware doesn't +support the stencil buffer, and then disables shadows by itself. +*/ + +#include +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +using namespace irr; + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +int main() +{ + // ask if user would like shadows + char i = 'y'; + printf("Please press 'y' if you want to use realtime shadows.\n"); + + std::cin >> i; + + const bool shadows = (i == 'y'); + + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + + /* + Create device and exit if creation failed. We make the stencil flag + optional to avoid slow screen modes for runs without shadows. + */ + + IrrlichtDevice *device = + createDevice(driverType, core::dimension2d(640, 480), + 16, false, shadows); + + if (device == 0) + return 1; // could not create selected driver. + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + + const io::path mediaPath = getExampleMediaPath(); + + /* + For our environment, we load a .3ds file. It is a small room I modeled + with Anim8or and exported into the 3ds format because the Irrlicht + Engine does not support the .an8 format. I am a very bad 3d graphic + artist, and so the texture mapping is not very nice in this model. + Luckily I am a better programmer than artist, and so the Irrlicht + Engine is able to create a cool texture mapping for me: Just use the + mesh manipulator and create a planar texture mapping for the mesh. If + you want to see the mapping I made with Anim8or, uncomment this line. I + also did not figure out how to set the material right in Anim8or, it + has a specular light color which I don't really like. I'll switch it + off too with this code. + */ + + scene::IAnimatedMesh* mesh = smgr->getMesh(mediaPath + "room.3ds"); + + smgr->getMeshManipulator()->makePlanarTextureMapping(mesh->getMesh(0), 0.004f); + + scene::ISceneNode* node = 0; + + node = smgr->addAnimatedMeshSceneNode(mesh); + node->setMaterialTexture(0, driver->getTexture(mediaPath + "wall.jpg")); + node->getMaterial(0).SpecularColor.set(0,0,0,0); + + /* + Now, for the first special effect: Animated water. It works like this: + The WaterSurfaceSceneNode takes a mesh as input and makes it wave like + a water surface. And if we let this scene node use a nice material like + the EMT_REFLECTION_2_LAYER, it looks really cool. We are doing this + with the next few lines of code. As input mesh, we create a hill plane + mesh, without hills. But any other mesh could be used for this, you + could even use the room.3ds (which would look really strange) if you + want to. + */ + + mesh = smgr->addHillPlaneMesh( "myHill", + core::dimension2d(20,20), + core::dimension2d(40,40), 0, 0, + core::dimension2d(0,0), + core::dimension2d(10,10)); + + node = smgr->addWaterSurfaceSceneNode(mesh->getMesh(0), 3.0f, 300.0f, 30.0f); + node->setPosition(core::vector3df(0,7,0)); + + node->setMaterialTexture(0, driver->getTexture(mediaPath + "stones.jpg")); + node->setMaterialTexture(1, driver->getTexture(mediaPath + "water.jpg")); + + node->setMaterialType(video::EMT_REFLECTION_2_LAYER); + + /* + The second special effect is very basic, I bet you saw it already in + some Irrlicht Engine demos: A transparent billboard combined with a + dynamic light. We simply create a light scene node, let it fly around, + and to make it look more cool, we attach a billboard scene node to it. + */ + + // create light + scene::ILightSceneNode * lightNode = smgr->addLightSceneNode(0, core::vector3df(0,0,0), + video::SColorf(1.0f, 0.6f, 0.7f, 1.0f), 800.0f); + scene::ISceneNodeAnimator* anim = 0; + anim = smgr->createFlyCircleAnimator (core::vector3df(0,150,0),250.0f, 0.0005f); + lightNode ->addAnimator(anim); + anim->drop(); + + // attach billboard to light + + node = smgr->addBillboardSceneNode(lightNode, core::dimension2d(50, 50)); + node->setMaterialFlag(video::EMF_LIGHTING, false); + node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); + node->setMaterialTexture(0, driver->getTexture(mediaPath + "particlewhite.bmp")); + + /* + The next special effect is a lot more interesting: A particle system. + The particle system in the Irrlicht Engine is quite modular and + extensible, but yet easy to use. There is a particle system scene node + into which you can put a particle emitter, which makes particles come out + of nothing. These emitters are quite flexible and usually have lots of + parameters like direction, amount, and color of the particles they + create. + + There are different emitters, for example a point emitter which lets + particles pop out at a fixed point. If the particle emitters available + in the engine are not enough for you, you can easily create your own + ones, you'll simply have to create a class derived from the + IParticleEmitter interface and attach it to the particle system using + setEmitter(). In this example we create a box particle emitter, which + creates particles randomly inside a box. The parameters define the box, + direction of the particles, minimal and maximal new particles per + second, color, and minimal and maximal lifetime of the particles. + + Because only with emitters particle system would be a little bit + boring, there are particle affectors which modify particles while + they fly around. Affectors can be added to a particle system for + simulating additional effects like gravity or wind. + The particle affector we use in this example is an affector which + modifies the color of the particles: It lets them fade out. Like the + particle emitters, additional particle affectors can also be + implemented by you, simply derive a class from IParticleAffector and + add it with addAffector(). + + After we set a nice material to the particle system, we have a cool + looking camp fire. By adjusting material, texture, particle emitter, + and affector parameters, it is also easily possible to create smoke, + rain, explosions, snow, and so on. + */ + + // create a particle system + + scene::IParticleSystemSceneNode* ps = + smgr->addParticleSystemSceneNode(false); + + if (ps) + { + scene::IParticleEmitter* em = ps->createBoxEmitter( + core::aabbox3d(-7,0,-7,7,1,7), // emitter size + core::vector3df(0.0f,0.06f,0.0f), // initial direction + 80,100, // emit rate + video::SColor(0,255,255,255), // darkest color + video::SColor(0,255,255,255), // brightest color + 800,2000,0, // min and max age, angle + core::dimension2df(10.f,10.f), // min size + core::dimension2df(20.f,20.f)); // max size + + ps->setEmitter(em); // this grabs the emitter + em->drop(); // so we can drop it here without deleting it + + scene::IParticleAffector* paf = ps->createFadeOutParticleAffector(); + + ps->addAffector(paf); // same goes for the affector + paf->drop(); + + ps->setPosition(core::vector3df(-70,60,40)); + ps->setScale(core::vector3df(2,2,2)); + ps->setMaterialFlag(video::EMF_LIGHTING, false); + ps->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false); + ps->setMaterialTexture(0, driver->getTexture(mediaPath + "fire.bmp")); + ps->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); + } + + /* + Next we add a volumetric light node, which adds a glowing fake area light to + the scene. Like with the billboards and particle systems we also assign a + texture for the desired effect, though this time we'll use a texture animator + to create the illusion of a magical glowing area effect. + */ + scene::IVolumeLightSceneNode * n = smgr->addVolumeLightSceneNode(0, -1, + 32, // Subdivisions on U axis + 32, // Subdivisions on V axis + video::SColor(0, 255, 255, 255), // foot color + video::SColor(0, 0, 0, 0)); // tail color + + if (n) + { + n->setScale(core::vector3df(56.0f, 56.0f, 56.0f)); + n->setPosition(core::vector3df(-120,50,40)); + + // load textures for animation + core::array textures; + for (s32 g=7; g > 0; --g) + { + core::stringc tmp(mediaPath); + tmp += "portal"; + tmp += g; + tmp += ".bmp"; + video::ITexture* t = driver->getTexture( tmp.c_str() ); + textures.push_back(t); + } + + // create texture animator + scene::ISceneNodeAnimator* glow = smgr->createTextureAnimator(textures, 150); + + // add the animator + n->addAnimator(glow); + + // drop the animator because it was created with a create() function + glow->drop(); + } + + /* + As our last special effect, we want a dynamic shadow be cast from an + animated character. For this we load a DirectX .x model and place it + into our world. For creating the shadow, we simply need to call + addShadowVolumeSceneNode(). The color of shadows is only adjustable + globally for all shadows, by calling ISceneManager::setShadowColor(). + Voila, here is our dynamic shadow. + + Because the character is a little bit too small for this scene, we make + it bigger using setScale(). And because the character is lighted by a + dynamic light, we need to normalize the normals to make the lighting on + it correct. This is always necessary if the scale of a dynamic lighted + model is not (1,1,1). Otherwise it would get too dark or too bright + because the normals will be scaled too. + */ + + // add animated character + + mesh = smgr->getMesh(mediaPath + "dwarf.x"); + scene::IAnimatedMeshSceneNode* anode = 0; + + anode = smgr->addAnimatedMeshSceneNode(mesh); + anode->setPosition(core::vector3df(-50,20,-60)); + anode->setAnimationSpeed(15); + + /* + Shadows still have to be drawn even then the node causing them is not visible itself. + We have to disable culling if the node is animated or it's transformations change + as otherwise the shadow is not updated correctly. + If you have many objects and this becomes a speed problem you will have to figure + out some manual culling (for exampling hiding all objects beyond a certain distance). + */ + anode->setAutomaticCulling(scene::EAC_OFF); + + // add shadow + anode->addShadowVolumeSceneNode(); + smgr->setShadowColor(video::SColor(150,0,0,0)); + + // make the model a bit bigger + anode->setScale(core::vector3df(2,2,2)); + // because of the scaling we have to normalize its normals for correct lighting + anode->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true); + + // let the dwarf slowly rotate around it's y axis + scene::ISceneNodeAnimator* ra = smgr->createRotationAnimator(irr::core::vector3df(0, 0.1f, 0)); + anode->addAnimator(ra); + ra->drop(); + + /* + Finally we simply have to draw everything, that's all. + */ + + scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(); + camera->setPosition(core::vector3df(-50,50,-150)); + camera->setFarValue(10000.0f); // this increase a shadow visible range. + + // disable mouse cursor + device->getCursorControl()->setVisible(false); + + s32 lastFPS = -1; + + while(device->run()) + if (device->isWindowActive()) + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0)); + + smgr->drawAll(); + + driver->endScene(); + + const s32 fps = driver->getFPS(); + + if (lastFPS != fps) + { + core::stringw str = L"Irrlicht Engine - SpecialFX example ["; + str += driver->getName(); + str += "] FPS:"; + str += fps; + + device->setWindowCaption(str.c_str()); + lastFPS = fps; + } + } + + device->drop(); + + return 0; +} + +/* +**/ diff --git a/examples/08.SpecialFX/project.properties b/examples/08.SpecialFX/project.properties new file mode 100644 index 00000000..6f9611b1 --- /dev/null +++ b/examples/08.SpecialFX/project.properties @@ -0,0 +1,14 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}\tools\proguard\proguard-android.txt:proguard-project.txt + +# Project target. +target=android-10 diff --git a/examples/08.SpecialFX/tutorial.html b/examples/08.SpecialFX/tutorial.html new file mode 100644 index 00000000..8c1fc51a --- /dev/null +++ b/examples/08.SpecialFX/tutorial.html @@ -0,0 +1,278 @@ + + +Irrlicht Engine Tutorial + + + + +
+ + + + + + + + +
+
+
Tutorial 8. Special Effects
+
+
+
+

This tutorials describes how to do special effects. It shows how to + use stencil buffer shadows, the particle system, billboards, dynamic + light and the water surface scene node.

+

The program which is described here will look like this:

+


+

+
+
+
+ + + + + + + +
Lets start!
+
+

We start like in some tutorials before. Please note that this time, + the 'shadows' flag in createDevice() is set to true, for we want to + have a dynamic shadow casted from an animated character. If your this + example runs to slow, set it to false. The Irrlicht Engine checks + if your hardware doesn't support the stencil buffer, and disables + shadows by itself, but just in case the demo runs slow on your hardware.

+ + + + +
#include <irrlicht.h>
+#include <iostream>
+
using namespace irr; + +#pragma comment(lib, "Irrlicht.lib") + +int main() +{ + // ask user for driver
video::E_DRIVER_TYPE driverType;
+ 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) Apfelbaum Software Renderer\n"\
" (f) NullDevice\n (otherKey) exit\n\n");

char i;
std::cin >> i;

switch(i)
{
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;
default: return 1;
} + + // create device and exit if creation failed
IrrlichtDevice *device = createDevice(driverType, + core::dimension2d<s32>(640, 480), 16, false, true); + + if (device == 0) + return 1; + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); +
+
+

For our environment, we load a .3ds file. It is a small room I modelled + with Anim8or and exported it into the 3ds format because the Irrlicht + Engine did not support the .an8 format when I wrote this tutorial. + I am a very bad 3d graphic artist, and so the texture mapping is not + very nice in this model. Luckily I am a better programmer than artist, + and so the Irrlicht Engine is able to create a cool texture mapping + for me: Just use the mesh manipulator and create a planar texture + mapping for the mesh. If you want to see the mapping I made with Anim8or, + uncomment this line. I also did not figure out how to
+ set the material right in Anim8or, it has a specular light color + which I don't really
+ like. I'll switch it off too with this code.

+ + + + +
	scene::IAnimatedMesh* mesh = smgr->getMesh(
+		"../../media/room.3ds");
+
+	smgr->getMeshManipulator()->makePlanarTextureMapping(
+		mesh->getMesh(0), 0.008f);
+
+	scene::ISceneNode* node = 0;
+
+	node = smgr->addAnimatedMeshSceneNode(mesh);
+	node->setMaterialTexture(0,	driver->getTexture("../../media/wall.jpg"));
+	node->getMaterial(0).SpecularColor.set(0,0,0,0);
+

Now, for the first special effect: Animated water. It works like + this: The WaterSurfaceSceneNode takes a mesh as input and makes it + wave like a water surface. And if we let this scene node use a nice + material like the MT_REFLECTION_2_LAYER, it looks really cool. We + are doing this with the next few lines of code. As input mesh, we + create a hill plane mesh, without hills. But any other mesh could + be used for this, you could even use the room.3ds (which would look + really strange) if you wanted to.

+ + + + +
	mesh = smgr->addHillPlaneMesh("myHill",
+		core::dimension2d<f32>(20,20),
+		core::dimension2d<s32>(40,40), 0, 0,
+		core::dimension2d<f32>(0,0),
+		core::dimension2d<f32>(10,10));
+
+	node = smgr->addWaterSurfaceSceneNode(mesh->getMesh(0), 3.0f, 300.0f, 30.0f);
+	node->setPosition(core::vector3df(0,7,0));
+
+	node->setMaterialTexture(0,	driver->getTexture("../../media/stones.jpg"));
+	node->setMaterialTexture(1,	driver->getTexture("../../media/water.jpg"));
+
+	node->setMaterialType(video::EMT_REFLECTION_2_LAYER);
+
+

The second special effect is very basic, I bet you saw it already + in some Irrlicht Engine demos: A transparent billboard combined with + a dynamic light. We simply create a light scene node, let it fly around, + an to make it look more cool, we attach a billboard scene node to + it.

+ + + + +
	// create light
+
+	node = smgr->addLightSceneNode(0, core::vector3df(0,0,0), 
+		video::SColorf(1.0f, 0.6f, 0.7f, 1.0f), 600.0f);
+	scene::ISceneNodeAnimator* anim = 0;
+	anim = smgr->createFlyCircleAnimator (core::vector3df(0,150,0),250.0f);
+	node->addAnimator(anim);
+	anim->drop();
+
+	// attach billboard to light
+
+	node = smgr->addBillboardSceneNode(node, core::dimension2d<f32>(50, 50));
+	node->setMaterialFlag(video::EMF_LIGHTING, false);
+	node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
+	node->setMaterialTexture(0,	driver->getTexture("../../media/particlewhite.bmp"));
+
+
+

The next special effect is a lot more interesting: A particle system. + The particle system in the Irrlicht Engine is quit modular and extensible + and yet easy to use. There is a particle system scene node into which + you can put particle emitters, which make particles come out of nothing. + These emitters are quite flexible and usually have lots of parameters + like direction, amount and color of the particles they should create.
+ There are different emitters, for example a point emitter which lets + particles pop out at a fixed point. If the particle emitters available + in the engine are not enough for you, you can easily create your own + ones, you'll simply have to create a class derived from the IParticleEmitter + interface and attach it to the particle system using setEmitter().
+ In this example we create a box particle emitter, which creates particles + randomly inside a box. The parameters define the box, direction of + the particles, minimal and maximal new particles per second, color + and minimal and maximal livetime of the particles.

+

Because only with emitters particle system would be a little bit + boring, there are particle affectors, which modify particles during + they fly around. They can be added to the particle system, simulating + additional effects like gravity or wind. The particle affector we + use in this example is an affector, which modifies the color of the + particles: It lets them fade out. Like the particle emitters, additional + particle affectors can also be implemented by you, simply derive a + class from IParticleAffector and add it with addAffector(). After + we set a nice material to the particle system, we have a cool looking + camp fire. By adjusting material, texture, particle emitter and affector + parameters, it is also easily possible to create smoke, rain, explosions, + snow, and so on.
+

+
+ + + + +
	scene::IParticleSystemSceneNode* ps = 0;
+	ps = smgr->addParticleSystemSceneNode(false);
+	ps->setPosition(core::vector3df(-70,60,40));
+	ps->setScale(core::vector3df(2,2,2));
+
+	ps->setParticleSize(core::dimension2d<f32>(20.0f, 10.0f));
+
+	scene::IParticleEmitter* em = ps->createBoxEmitter(
+		core::aabbox3d<f32>(-7,0,-7,7,1,7), 
+		core::vector3df(0.0f,0.03f,0.0f),
+		80,100, 
+		video::SColor(0,255,255,255), video::SColor(0,255,255,255),
+		800,2000);
+
+	ps->setEmitter(em);
+	em->drop();
+
+	scene::IParticleAffector* paf = 
+		ps->createFadeOutParticleAffector();
+
+	ps->addAffector(paf);
+	paf->drop();
+
+	ps->setMaterialFlag(video::EMF_LIGHTING, false);
+	ps->setMaterialTexture(0, driver->getTexture("../../media/particle.bmp"));
+	ps->setMaterialType(video::EMT_TRANSPARENT_VERTEX_ALPHA);
+

As our last special effect, we want a dynamic shadow be casted from + an animated character. For this we load a DirectX .x model and place + it into our world. For creating the shadow, we simply need to call addShadowVolumeSceneNode(). + The color of shadows is only adjustable globally for all shadows, by + calling ISceneManager::setShadowColor(). Voila, here is our dynamic + shadow.
+ Because the character is a little bit too small for this scene, we make + it bigger using setScale(). And because the character is lighted by + a dynamic light, we need to normalize the normals to make the lighting + on it correct. This is always necessary if the scale of a dynamic lighted + model is not (1,1,1). Otherwise it would get too dark or too bright + because the normals will be scaled too.

+ + + + +
	mesh = smgr->getMesh("../../media/dwarf.x");
+	scene::IAnimatedMeshSceneNode* anode = 0;
+
+	anode = smgr->addAnimatedMeshSceneNode(mesh);
+	anode->setPosition(core::vector3df(-50,20,-60));
+	anode->setAnimationSpeed(15);
+
+	// add shadow
+	anode->addShadowVolumeSceneNode();	
+	smgr->setShadowColor(video::SColor(220,0,0,0));
+
+	// make the model a little bit bigger and normalize its normals 
// because of this for correct lighting

anode->setScale(core::vector3df(2,2,2));
anode->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);

+

Finally we simply have to draw everything, that's all.

+ + + + +
	scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS();
+	camera->setPosition(core::vector3df(-50,50,-150));
+
+
+	int lastFPS = -1;
+
+	while(device->run())
+	{
+		driver->beginScene(true, true, 0);
+
+		smgr->drawAll();
+
+		driver->endScene();
+
+		int fps = driver->getFPS();
+
+		if (lastFPS != fps)
+		{
+		  core::stringw str = L"Irrlicht Engine - SpecialFX example [";
str += driver->getName();
str += "] FPS:";
str += fps;

device->setWindowCaption(str.c_str());
lastFPS = fps;
} + } + + device->drop(); + + return 0; +} + +
+
+

 

+

 

+

 

+
+
+

 

+ + diff --git a/examples/09.Meshviewer/9.Meshviewer.rc b/examples/09.Meshviewer/9.Meshviewer.rc new file mode 100644 index 00000000..32085837 --- /dev/null +++ b/examples/09.Meshviewer/9.Meshviewer.rc @@ -0,0 +1,84 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// German (Austria) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEA) +#ifdef _WIN32 +LANGUAGE LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON "icon.ico" +#endif // German (Austria) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/examples/09.Meshviewer/Makefile b/examples/09.Meshviewer/Makefile new file mode 100644 index 00000000..e90ab524 --- /dev/null +++ b/examples/09.Meshviewer/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 09.Meshviewer +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/09.Meshviewer/Meshviewer.cbp b/examples/09.Meshviewer/Meshviewer.cbp new file mode 100644 index 00000000..be11327b --- /dev/null +++ b/examples/09.Meshviewer/Meshviewer.cbp @@ -0,0 +1,55 @@ + + + + + + diff --git a/examples/09.Meshviewer/Meshviewer.vcproj b/examples/09.Meshviewer/Meshviewer.vcproj new file mode 100644 index 00000000..4077b860 --- /dev/null +++ b/examples/09.Meshviewer/Meshviewer.vcproj @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/09.Meshviewer/Meshviewer.xcodeproj/project.pbxproj b/examples/09.Meshviewer/Meshviewer.xcodeproj/project.pbxproj new file mode 100644 index 00000000..e9137d14 --- /dev/null +++ b/examples/09.Meshviewer/Meshviewer.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 09.Meshviewer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 09.Meshviewer.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 09.Meshviewer.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 09.Meshviewer */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "09.Meshviewer" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 09.Meshviewer; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 09.Meshviewer.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Meshviewer" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 09.Meshviewer */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Meshviewer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "09.Meshviewer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/09.Meshviewer/Meshviewer.xcodeproj/xcshareddata/xcschemes/09.Meshviewer.xcscheme b/examples/09.Meshviewer/Meshviewer.xcodeproj/xcshareddata/xcschemes/09.Meshviewer.xcscheme new file mode 100644 index 00000000..0625d5ee --- /dev/null +++ b/examples/09.Meshviewer/Meshviewer.xcodeproj/xcshareddata/xcschemes/09.Meshviewer.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/09.Meshviewer/Meshviewer_vc10.vcxproj b/examples/09.Meshviewer/Meshviewer_vc10.vcxproj new file mode 100644 index 00000000..eb918ccd --- /dev/null +++ b/examples/09.Meshviewer/Meshviewer_vc10.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 09.Meshviewer + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06} + Meshviewer + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/Meshviewer.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\09.MeshViewer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Meshviewer.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\09.MeshViewer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Debug/Meshviewer.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\09.MeshViewer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Meshviewer.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\09.MeshViewer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/09.Meshviewer/Meshviewer_vc11.vcxproj b/examples/09.Meshviewer/Meshviewer_vc11.vcxproj new file mode 100644 index 00000000..eb918ccd --- /dev/null +++ b/examples/09.Meshviewer/Meshviewer_vc11.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 09.Meshviewer + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06} + Meshviewer + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/Meshviewer.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\09.MeshViewer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Meshviewer.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\09.MeshViewer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Debug/Meshviewer.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\09.MeshViewer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Meshviewer.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\09.MeshViewer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/09.Meshviewer/Meshviewer_vc12.vcxproj b/examples/09.Meshviewer/Meshviewer_vc12.vcxproj new file mode 100644 index 00000000..effddf22 --- /dev/null +++ b/examples/09.Meshviewer/Meshviewer_vc12.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 09.Meshviewer + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06} + Meshviewer + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/Meshviewer.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\09.MeshViewer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Meshviewer.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\09.MeshViewer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Debug/Meshviewer.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\09.MeshViewer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Meshviewer.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\09.MeshViewer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/09.Meshviewer/Meshviewer_vc14.vcxproj b/examples/09.Meshviewer/Meshviewer_vc14.vcxproj new file mode 100644 index 00000000..f96053dd --- /dev/null +++ b/examples/09.Meshviewer/Meshviewer_vc14.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 09.Meshviewer + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06} + Meshviewer + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/Meshviewer.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\09.MeshViewer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Meshviewer.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\09.MeshViewer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Debug/Meshviewer.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\09.MeshViewer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Meshviewer.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\09.MeshViewer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/09.Meshviewer/icon.ico b/examples/09.Meshviewer/icon.ico new file mode 100644 index 00000000..49f8eabb Binary files /dev/null and b/examples/09.Meshviewer/icon.ico differ diff --git a/examples/09.Meshviewer/main.cpp b/examples/09.Meshviewer/main.cpp new file mode 100644 index 00000000..010ad6eb --- /dev/null +++ b/examples/09.Meshviewer/main.cpp @@ -0,0 +1,1044 @@ +/** Example 009 Mesh Viewer + +This tutorial show how to create a more complex application with the engine. +We construct a simple mesh viewer using the user interface API and the +scene management of Irrlicht. The tutorial show how to create and use Buttons, +Windows, Toolbars, Menus, ComboBoxes, Tabcontrols, Editboxes, Images, +MessageBoxes, SkyBoxes, and how to parse XML files with the integrated XML +reader of the engine. + +We start like in most other tutorials: Include all necessary header files, add +a comment to let the engine be linked with the correct .lib file in Visual +Studio, and declare some global variables. We also add two 'using namespace' +statements, so we do not need to write the whole names of all classes. In this +tutorial, we use a lot of stuff from the gui namespace. +*/ +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +using namespace irr; +using namespace gui; + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + + +/* +Some global variables used later on +*/ +IrrlichtDevice *Device = 0; +io::path StartUpModelFile; +core::stringw MessageText; +core::stringw Caption; +scene::ISceneNode* Model = 0; +scene::ISceneNode* SkyBox = 0; +bool Octree=false; +bool UseLight=false; + +scene::ICameraSceneNode* Camera[2] = {0, 0}; + +// Values used to identify individual GUI elements +enum +{ + GUI_ID_DIALOG_ROOT_WINDOW = 0x10000, + + GUI_ID_X_SCALE, + GUI_ID_Y_SCALE, + GUI_ID_Z_SCALE, + + GUI_ID_OPEN_MODEL, + GUI_ID_SET_MODEL_ARCHIVE, + GUI_ID_LOAD_AS_OCTREE, + + GUI_ID_SKY_BOX_VISIBLE, + GUI_ID_TOGGLE_DEBUG_INFO, + + GUI_ID_DEBUG_OFF, + GUI_ID_DEBUG_BOUNDING_BOX, + GUI_ID_DEBUG_NORMALS, + GUI_ID_DEBUG_SKELETON, + GUI_ID_DEBUG_WIRE_OVERLAY, + GUI_ID_DEBUG_HALF_TRANSPARENT, + GUI_ID_DEBUG_BUFFERS_BOUNDING_BOXES, + GUI_ID_DEBUG_ALL, + + GUI_ID_MODEL_MATERIAL_SOLID, + GUI_ID_MODEL_MATERIAL_TRANSPARENT, + GUI_ID_MODEL_MATERIAL_REFLECTION, + + GUI_ID_CAMERA_MAYA, + GUI_ID_CAMERA_FIRST_PERSON, + + GUI_ID_POSITION_TEXT, + + GUI_ID_ABOUT, + GUI_ID_QUIT, + + GUI_ID_TEXTUREFILTER, + GUI_ID_SKIN_TRANSPARENCY, + GUI_ID_SKIN_ANIMATION_FPS, + + GUI_ID_BUTTON_SET_SCALE, + GUI_ID_BUTTON_SCALE_MUL10, + GUI_ID_BUTTON_SCALE_DIV10, + GUI_ID_BUTTON_OPEN_MODEL, + GUI_ID_BUTTON_SHOW_ABOUT, + GUI_ID_BUTTON_SHOW_TOOLBOX, + GUI_ID_BUTTON_SELECT_ARCHIVE, + + GUI_ID_ANIMATION_INFO, + + // And some magic numbers + MAX_FRAMERATE = 80, + DEFAULT_FRAMERATE = 30 +}; + + +/* +Toggle between various cameras +*/ +void setActiveCamera(scene::ICameraSceneNode* newActive) +{ + if (0 == Device) + return; + + scene::ICameraSceneNode * active = Device->getSceneManager()->getActiveCamera(); + active->setInputReceiverEnabled(false); + + newActive->setInputReceiverEnabled(true); + Device->getSceneManager()->setActiveCamera(newActive); +} + +/* + Set the skin transparency by changing the alpha values of all skin-colors +*/ +void setSkinTransparency(s32 alpha, irr::gui::IGUISkin * skin) +{ + for (s32 i=0; igetColor((EGUI_DEFAULT_COLOR)i); + col.setAlpha(alpha); + skin->setColor((EGUI_DEFAULT_COLOR)i, col); + } +} + +/* + Update the display of the model scaling +*/ +void updateScaleInfo(scene::ISceneNode* model) +{ + IGUIElement* toolboxWnd = Device->getGUIEnvironment()->getRootGUIElement()->getElementFromId(GUI_ID_DIALOG_ROOT_WINDOW, true); + if (!toolboxWnd) + return; + if (!model) + { + toolboxWnd->getElementFromId(GUI_ID_X_SCALE, true)->setText( L"-" ); + toolboxWnd->getElementFromId(GUI_ID_Y_SCALE, true)->setText( L"-" ); + toolboxWnd->getElementFromId(GUI_ID_Z_SCALE, true)->setText( L"-" ); + } + else + { + core::vector3df scale = model->getScale(); + toolboxWnd->getElementFromId(GUI_ID_X_SCALE, true)->setText( core::stringw(scale.X).c_str() ); + toolboxWnd->getElementFromId(GUI_ID_Y_SCALE, true)->setText( core::stringw(scale.Y).c_str() ); + toolboxWnd->getElementFromId(GUI_ID_Z_SCALE, true)->setText( core::stringw(scale.Z).c_str() ); + } +} + +/* +Function showAboutText() displays a messagebox with a caption and +a message text. The texts will be stored in the MessageText and Caption +variables at startup. +*/ +void showAboutText() +{ + // create modal message box with the text + // loaded from the xml file. + Device->getGUIEnvironment()->addMessageBox( + Caption.c_str(), MessageText.c_str()); +} + + +/* +Function loadModel() loads a model and displays it using an +addAnimatedMeshSceneNode and the scene manager. Nothing difficult. It also +displays a short message box, if the model could not be loaded. +*/ +void loadModel(const io::path& filename) +{ + io::path extension; + core::getFileNameExtension(extension, filename); + extension.make_lower(); + + // if a texture is loaded apply it to the current model.. + if (extension == ".jpg" || extension == ".pcx" || + extension == ".png" || extension == ".ppm" || + extension == ".pgm" || extension == ".pbm" || + extension == ".psd" || extension == ".tga" || + extension == ".bmp" || extension == ".wal" || + extension == ".rgb" || extension == ".rgba") + { + // Ensure reloading texture by clearing old one out of cache + video::ITexture * texture = Device->getVideoDriver()->findTexture( filename ); + if ( texture ) + Device->getVideoDriver()->removeTexture(texture); + + // Load the new one and put int on the model + texture = Device->getVideoDriver()->getTexture( filename ); + if ( texture && Model ) + { + Model->setMaterialTexture(0, texture); + } + return; + } + // if a archive is loaded add it to the FileArchive.. + else if (extension == ".pk3" || extension == ".zip" || extension == ".pak" || extension == ".npk") + { + Device->getFileSystem()->addFileArchive(filename.c_str()); + return; + } + + // Remove old model + + if (Model) + { + Model->remove(); + Model = 0; + } + + // .irr is a scene format, so load as scene and set Model pointer to first object in the scene + + if (extension==".irr") + { + core::array outNodes; + Device->getSceneManager()->loadScene(filename); + Device->getSceneManager()->getSceneNodesFromType(scene::ESNT_ANIMATED_MESH, outNodes); + if (outNodes.size()) + Model = outNodes[0]; + return; + } + + // load a model into the engine. Also log the time it takes to load it. + + u32 then = Device->getTimer()->getRealTime(); + scene::IAnimatedMesh* mesh = Device->getSceneManager()->getMesh( filename.c_str() ); + Device->getLogger()->log("Loading time (ms): ", core::stringc(Device->getTimer()->getRealTime() - then).c_str()); + + if (!mesh) + { + // model could not be loaded + + if (StartUpModelFile != filename) + Device->getGUIEnvironment()->addMessageBox( + Caption.c_str(), L"The model could not be loaded. " \ + L"Maybe it is not a supported file format."); + return; + } + + // set default material properties + + if (Octree) + Model = Device->getSceneManager()->addOctreeSceneNode(mesh->getMesh(0)); + else + { + scene::IAnimatedMeshSceneNode* animModel = Device->getSceneManager()->addAnimatedMeshSceneNode(mesh); + Model = animModel; + } + Model->setMaterialFlag(video::EMF_LIGHTING, UseLight); + Model->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, UseLight); +// Model->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false); + Model->setDebugDataVisible(scene::EDS_OFF); + + // we need to uncheck the menu entries. would be cool to fake a menu event, but + // that's not so simple. so we do it brute force + gui::IGUIContextMenu* menu = (gui::IGUIContextMenu*)Device->getGUIEnvironment()->getRootGUIElement()->getElementFromId(GUI_ID_TOGGLE_DEBUG_INFO, true); + if (menu) + for(int item = 1; item < 6; ++item) + menu->setItemChecked(item, false); + updateScaleInfo(Model); +} + + +/* +Function createToolBox() creates a toolbox window. In this simple mesh +viewer, this toolbox only contains a controls to change the scale +and animation speed of the model and a control to set the transparency +of the GUI-elements. +*/ +void createToolBox() +{ + // remove tool box if already there + IGUIEnvironment* env = Device->getGUIEnvironment(); + IGUIElement* root = env->getRootGUIElement(); + IGUIElement* e = root->getElementFromId(GUI_ID_DIALOG_ROOT_WINDOW, true); + if (e) + e->remove(); + + // create the toolbox window + IGUIWindow* wnd = env->addWindow(core::rect(600,45,800,480), + false, L"Toolset", 0, GUI_ID_DIALOG_ROOT_WINDOW); + + // create tab control and tabs + IGUITabControl* tab = env->addTabControl( + core::rect(2,20,800-602,480-7), wnd, true, true); + + IGUITab* t1 = tab->addTab(L"Config"); + + // add some edit boxes and a button to tab one + env->addStaticText(L"Scale:", + core::rect(10,20,60,45), false, false, t1); + env->addStaticText(L"X:", core::rect(22,48,40,66), false, false, t1); + env->addEditBox(L"1.0", core::rect(40,46,130,66), true, t1, GUI_ID_X_SCALE); + env->addStaticText(L"Y:", core::rect(22,82,40,96), false, false, t1); + env->addEditBox(L"1.0", core::rect(40,76,130,96), true, t1, GUI_ID_Y_SCALE); + env->addStaticText(L"Z:", core::rect(22,108,40,126), false, false, t1); + env->addEditBox(L"1.0", core::rect(40,106,130,126), true, t1, GUI_ID_Z_SCALE); + + env->addButton(core::rect(10,134,85,165), t1, GUI_ID_BUTTON_SET_SCALE, L"Set"); + + // quick scale buttons + env->addButton(core::rect(65,20,95,40), t1, GUI_ID_BUTTON_SCALE_MUL10, L"* 10"); + env->addButton(core::rect(100,20,130,40), t1, GUI_ID_BUTTON_SCALE_DIV10, L"* 0.1"); + + updateScaleInfo(Model); + + // add transparency control + env->addStaticText(L"GUI Transparency Control:", + core::rect(10,200,150,225), true, false, t1); + IGUIScrollBar* scrollbar = env->addScrollBar(true, + core::rect(10,225,150,240), t1, GUI_ID_SKIN_TRANSPARENCY); + scrollbar->setMax(255); + scrollbar->setPos(255); + + // add framerate control + env->addStaticText(L":", core::rect(10,240,150,265), true, false, t1); + env->addStaticText(L"Framerate:", + core::rect(12,240,75,265), false, false, t1); + // current frame info + env->addStaticText(L"", core::rect(75,240,200,265), false, false, t1, + GUI_ID_ANIMATION_INFO); + scrollbar = env->addScrollBar(true, + core::rect(10,265,150,280), t1, GUI_ID_SKIN_ANIMATION_FPS); + scrollbar->setMax(MAX_FRAMERATE); + scrollbar->setMin(-MAX_FRAMERATE); + scrollbar->setPos(DEFAULT_FRAMERATE); + scrollbar->setSmallStep(1); +} + +/* +Function updateToolBox() is called each frame to update dynamic information in +the toolbox. +*/ +void updateToolBox() +{ + IGUIEnvironment* env = Device->getGUIEnvironment(); + IGUIElement* root = env->getRootGUIElement(); + IGUIElement* dlg = root->getElementFromId(GUI_ID_DIALOG_ROOT_WINDOW, true); + if (!dlg ) + return; + + // update the info we have about the animation of the model + IGUIStaticText * aniInfo = (IGUIStaticText *)(dlg->getElementFromId(GUI_ID_ANIMATION_INFO, true)); + if (aniInfo) + { + if ( Model && scene::ESNT_ANIMATED_MESH == Model->getType() ) + { + scene::IAnimatedMeshSceneNode* animatedModel = (scene::IAnimatedMeshSceneNode*)Model; + + core::stringw str( (s32)core::round_(animatedModel->getAnimationSpeed()) ); + str += L" Frame: "; + str += core::stringw((s32)animatedModel->getFrameNr()); + aniInfo->setText(str.c_str()); + } + else + aniInfo->setText(L""); + } +} + +void onKillFocus() +{ + // Avoid that the FPS-camera continues moving when the user presses alt-tab while + // moving the camera. + const core::list& animators = Camera[1]->getAnimators(); + core::list::ConstIterator iter = animators.begin(); + while ( iter != animators.end() ) + { + if ( (*iter)->getType() == scene::ESNAT_CAMERA_FPS ) + { + // we send a key-down event for all keys used by this animator + scene::ISceneNodeAnimatorCameraFPS * fpsAnimator = static_cast(*iter); + const core::array& keyMap = fpsAnimator->getKeyMap(); + for ( irr::u32 i=0; i< keyMap.size(); ++i ) + { + irr::SEvent event; + event.EventType = EET_KEY_INPUT_EVENT; + event.KeyInput.Key = keyMap[i].KeyCode; + event.KeyInput.PressedDown = false; + fpsAnimator->OnEvent(event); + } + } + ++iter; + } +} + +/* +Function hasModalDialog() checks if we currently have a modal dialog open. +*/ +bool hasModalDialog() +{ + if ( !Device ) + return false; + IGUIEnvironment* env = Device->getGUIEnvironment(); + IGUIElement * focused = env->getFocus(); + while ( focused ) + { + if ( focused->isVisible() && focused->hasType(EGUIET_MODAL_SCREEN) ) + return true; + focused = focused->getParent(); + } + return false; +} + +/* +To get all the events sent by the GUI Elements, we need to create an event +receiver. This one is really simple. If an event occurs, it checks the id of +the caller and the event type, and starts an action based on these values. For +example, if a menu item with id GUI_ID_OPEN_MODEL was selected, it opens a file-open-dialog. +*/ +class MyEventReceiver : public IEventReceiver +{ +public: + virtual bool OnEvent(const SEvent& event) + { + // Key events + if (event.EventType == EET_KEY_INPUT_EVENT && + event.KeyInput.PressedDown == false) + { + if ( OnKeyUp(event.KeyInput.Key) ) + return true; + } + + // GUI events + if (event.EventType == EET_GUI_EVENT) + { + s32 id = event.GUIEvent.Caller->getID(); + IGUIEnvironment* env = Device->getGUIEnvironment(); + + switch(event.GUIEvent.EventType) + { + case EGET_MENU_ITEM_SELECTED: + // a menu item was clicked + OnMenuItemSelected( (IGUIContextMenu*)event.GUIEvent.Caller ); + break; + + case EGET_FILE_SELECTED: + { + // load the model file, selected in the file open dialog + IGUIFileOpenDialog* dialog = + (IGUIFileOpenDialog*)event.GUIEvent.Caller; + loadModel(dialog->getFileNameP()); + } + break; + + case EGET_SCROLL_BAR_CHANGED: + + // control skin transparency + if (id == GUI_ID_SKIN_TRANSPARENCY) + { + const s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos(); + setSkinTransparency(pos, env->getSkin()); + } + // control animation speed + else if (id == GUI_ID_SKIN_ANIMATION_FPS) + { + const s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos(); + if (scene::ESNT_ANIMATED_MESH == Model->getType()) + ((scene::IAnimatedMeshSceneNode*)Model)->setAnimationSpeed((f32)pos); + } + break; + + case EGET_COMBO_BOX_CHANGED: + + // control anti-aliasing/filtering + if (id == GUI_ID_TEXTUREFILTER) + { + OnTextureFilterSelected( (IGUIComboBox*)event.GUIEvent.Caller ); + } + break; + + case EGET_BUTTON_CLICKED: + + switch(id) + { + case GUI_ID_BUTTON_SET_SCALE: + { + // set model scale + gui::IGUIElement* root = env->getRootGUIElement(); + core::vector3df scale; + core::stringc s; + + s = root->getElementFromId(GUI_ID_X_SCALE, true)->getText(); + scale.X = (f32)atof(s.c_str()); + s = root->getElementFromId(GUI_ID_Y_SCALE, true)->getText(); + scale.Y = (f32)atof(s.c_str()); + s = root->getElementFromId(GUI_ID_Z_SCALE, true)->getText(); + scale.Z = (f32)atof(s.c_str()); + + if (Model) + Model->setScale(scale); + updateScaleInfo(Model); + } + break; + case GUI_ID_BUTTON_SCALE_MUL10: + if (Model) + Model->setScale(Model->getScale()*10.f); + updateScaleInfo(Model); + break; + case GUI_ID_BUTTON_SCALE_DIV10: + if (Model) + Model->setScale(Model->getScale()*0.1f); + updateScaleInfo(Model); + break; + case GUI_ID_BUTTON_OPEN_MODEL: + env->addFileOpenDialog(L"Please select a model file to open"); + break; + case GUI_ID_BUTTON_SHOW_ABOUT: + showAboutText(); + break; + case GUI_ID_BUTTON_SHOW_TOOLBOX: + createToolBox(); + break; + case GUI_ID_BUTTON_SELECT_ARCHIVE: + env->addFileOpenDialog(L"Please select your game archive/directory"); + break; + } + + break; + default: + break; + } + } + + return false; + } + + + /* + Handle key-up events + */ + bool OnKeyUp(irr::EKEY_CODE keyCode) + { + // Don't handle keys if we have a modal dialog open as it would lead + // to unexpected application behaviour for the user. + if ( hasModalDialog() ) + return false; + + // Escape swaps Camera Input + if (keyCode == irr::KEY_ESCAPE) + { + if (Device) + { + scene::ICameraSceneNode * camera = + Device->getSceneManager()->getActiveCamera(); + if (camera) + { + camera->setInputReceiverEnabled( !camera->isInputReceiverEnabled() ); + } + return true; + } + } + else if (keyCode == irr::KEY_F1) + { + // Swap display of position information about the camera + if (Device) + { + IGUIElement* elem = Device->getGUIEnvironment()->getRootGUIElement()->getElementFromId(GUI_ID_POSITION_TEXT); + if (elem) + elem->setVisible(!elem->isVisible()); + } + } + else if (keyCode == irr::KEY_KEY_M) + { + if (Device) + Device->minimizeWindow(); + } + else if (keyCode == irr::KEY_KEY_L) + { + UseLight=!UseLight; + if (Model) + { + Model->setMaterialFlag(video::EMF_LIGHTING, UseLight); + Model->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, UseLight); + } + } + return false; + } + + + /* + Handle "menu item clicked" events. + */ + void OnMenuItemSelected( IGUIContextMenu* menu ) + { + s32 id = menu->getItemCommandId(menu->getSelectedItem()); + IGUIEnvironment* env = Device->getGUIEnvironment(); + + switch(id) + { + case GUI_ID_OPEN_MODEL: // File -> Open Model File & Texture + env->addFileOpenDialog(L"Please select a model file to open"); + break; + case GUI_ID_SET_MODEL_ARCHIVE: // File -> Set Model Archive + env->addFileOpenDialog(L"Please select your game archive/directory"); + break; + case GUI_ID_LOAD_AS_OCTREE: // File -> LoadAsOctree + Octree = !Octree; + menu->setItemChecked(menu->getSelectedItem(), Octree); + break; + case GUI_ID_QUIT: // File -> Quit + Device->closeDevice(); + break; + case GUI_ID_SKY_BOX_VISIBLE: // View -> Skybox + menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem())); + SkyBox->setVisible(!SkyBox->isVisible()); + break; + case GUI_ID_DEBUG_OFF: // View -> Debug Information + menu->setItemChecked(menu->getSelectedItem()+1, false); + menu->setItemChecked(menu->getSelectedItem()+2, false); + menu->setItemChecked(menu->getSelectedItem()+3, false); + menu->setItemChecked(menu->getSelectedItem()+4, false); + menu->setItemChecked(menu->getSelectedItem()+5, false); + menu->setItemChecked(menu->getSelectedItem()+6, false); + if (Model) + Model->setDebugDataVisible(scene::EDS_OFF); + break; + case GUI_ID_DEBUG_BOUNDING_BOX: // View -> Debug Information + menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem())); + if (Model) + Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_BBOX)); + break; + case GUI_ID_DEBUG_NORMALS: // View -> Debug Information + menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem())); + if (Model) + Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_NORMALS)); + break; + case GUI_ID_DEBUG_SKELETON: // View -> Debug Information + menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem())); + if (Model) + Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_SKELETON)); + break; + case GUI_ID_DEBUG_WIRE_OVERLAY: // View -> Debug Information + menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem())); + if (Model) + Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_MESH_WIRE_OVERLAY)); + break; + case GUI_ID_DEBUG_HALF_TRANSPARENT: // View -> Debug Information + menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem())); + if (Model) + Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_HALF_TRANSPARENCY)); + break; + case GUI_ID_DEBUG_BUFFERS_BOUNDING_BOXES: // View -> Debug Information + menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem())); + if (Model) + Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_BBOX_BUFFERS)); + break; + case GUI_ID_DEBUG_ALL: // View -> Debug Information + menu->setItemChecked(menu->getSelectedItem()-1, true); + menu->setItemChecked(menu->getSelectedItem()-2, true); + menu->setItemChecked(menu->getSelectedItem()-3, true); + menu->setItemChecked(menu->getSelectedItem()-4, true); + menu->setItemChecked(menu->getSelectedItem()-5, true); + menu->setItemChecked(menu->getSelectedItem()-6, true); + if (Model) + Model->setDebugDataVisible(scene::EDS_FULL); + break; + case GUI_ID_ABOUT: // Help->About + showAboutText(); + break; + case GUI_ID_MODEL_MATERIAL_SOLID: // View -> Material -> Solid + if (Model) + Model->setMaterialType(video::EMT_SOLID); + break; + case GUI_ID_MODEL_MATERIAL_TRANSPARENT: // View -> Material -> Transparent + if (Model) + Model->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); + break; + case GUI_ID_MODEL_MATERIAL_REFLECTION: // View -> Material -> Reflection + if (Model) + Model->setMaterialType(video::EMT_SPHERE_MAP); + break; + + case GUI_ID_CAMERA_MAYA: + setActiveCamera(Camera[0]); + break; + case GUI_ID_CAMERA_FIRST_PERSON: + setActiveCamera(Camera[1]); + break; + } + } + + /* + Handle the event that one of the texture-filters was selected in the corresponding combobox. + */ + void OnTextureFilterSelected( IGUIComboBox* combo ) + { + s32 pos = combo->getSelected(); + switch (pos) + { + case 0: + if (Model) + { + Model->setMaterialFlag(video::EMF_BILINEAR_FILTER, false); + Model->setMaterialFlag(video::EMF_TRILINEAR_FILTER, false); + Model->setMaterialFlag(video::EMF_ANISOTROPIC_FILTER, false); + } + break; + case 1: + if (Model) + { + Model->setMaterialFlag(video::EMF_BILINEAR_FILTER, true); + Model->setMaterialFlag(video::EMF_TRILINEAR_FILTER, false); + } + break; + case 2: + if (Model) + { + Model->setMaterialFlag(video::EMF_BILINEAR_FILTER, false); + Model->setMaterialFlag(video::EMF_TRILINEAR_FILTER, true); + } + break; + case 3: + if (Model) + { + Model->setMaterialFlag(video::EMF_ANISOTROPIC_FILTER, true); + } + break; + case 4: + if (Model) + { + Model->setMaterialFlag(video::EMF_ANISOTROPIC_FILTER, false); + } + break; + } + } +}; + + +/* +Most of the hard work is done. We only need to create the Irrlicht Engine +device and all the buttons, menus and toolbars. We start up the engine as +usual, using createDevice(). To make our application catch events, we set our +eventreceiver as parameter. As you can see, there is also a call to +IrrlichtDevice::setResizeable(). This makes the render window resizeable, which +is quite useful for a mesh viewer. +*/ +int main(int argc, char* argv[]) +{ + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + // create device and exit if creation failed + MyEventReceiver receiver; + Device = createDevice(driverType, core::dimension2d(800, 600), + 16, false, false, false, &receiver); + + if (Device == 0) + return 1; // could not create selected driver. + + Device->setResizable(true); + + Device->setWindowCaption(L"Irrlicht Engine - Loading..."); + + video::IVideoDriver* driver = Device->getVideoDriver(); + IGUIEnvironment* env = Device->getGUIEnvironment(); + scene::ISceneManager* smgr = Device->getSceneManager(); + smgr->getParameters()->setAttribute(scene::COLLADA_CREATE_SCENE_INSTANCES, true); + + driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true); + + smgr->addLightSceneNode(0, core::vector3df(200,200,200), + video::SColorf(1.0f,1.0f,1.0f),2000); + smgr->setAmbientLight(video::SColorf(0.3f,0.3f,0.3f)); + // add our media directory as "search path" + Device->getFileSystem()->addFileArchive(getExampleMediaPath()); + + /* + The next step is to read the configuration file. It is stored in the xml + format and looks a little bit like this: + + @verbatim + + + + + Hello! + + + @endverbatim + + We need the data stored in there to be written into the global variables + StartUpModelFile, MessageText and Caption. This is now done using the + Irrlicht Engine integrated XML parser: + */ + + // read configuration from xml file + + io::IXMLReader* xml = Device->getFileSystem()->createXMLReader( L"config.xml"); + + while(xml && xml->read()) + { + switch(xml->getNodeType()) + { + case io::EXN_TEXT: + // in this xml file, the only text which occurs is the + // messageText + MessageText = xml->getNodeData(); + break; + case io::EXN_ELEMENT: + { + if (core::stringw("startUpModel") == xml->getNodeName()) + StartUpModelFile = xml->getAttributeValue(L"file"); + else + if (core::stringw("messageText") == xml->getNodeName()) + Caption = xml->getAttributeValue(L"caption"); + } + break; + default: + break; + } + } + + if (xml) + xml->drop(); // don't forget to delete the xml reader + + // We can pass a model to load per command line parameter + if (argc > 1) + StartUpModelFile = argv[1]; + + // set a nicer font + IGUISkin* skin = env->getSkin(); + IGUIFont* font = env->getFont("fonthaettenschweiler.bmp"); + if (font) + skin->setFont(font); + + /* + Now create the Menu. + It is possible to create submenus for every menu item. The call + menu->addItem(L"File", -1, true, true); for example adds a new menu + Item with the name "File" and the id -1. The following parameter says + that the menu item should be enabled, and the last one says, that there + should be a submenu. The submenu can now be accessed with + menu->getSubMenu(0), because the "File" entry is the menu item with + index 0. + */ + gui::IGUIContextMenu* menu = env->addMenu(); + menu->addItem(L"File", -1, true, true); + menu->addItem(L"View", -1, true, true); + menu->addItem(L"Camera", -1, true, true); + menu->addItem(L"Help", -1, true, true); + + gui::IGUIContextMenu* submenu; + submenu = menu->getSubMenu(0); + submenu->addItem(L"Open Model File & Texture...", GUI_ID_OPEN_MODEL); + submenu->addItem(L"Set Model Archive...", GUI_ID_SET_MODEL_ARCHIVE); + submenu->addItem(L"Load as Octree", GUI_ID_LOAD_AS_OCTREE); + submenu->addSeparator(); + submenu->addItem(L"Quit", GUI_ID_QUIT); + + submenu = menu->getSubMenu(1); + submenu->addItem(L"sky box visible", GUI_ID_SKY_BOX_VISIBLE, true, false, true); + submenu->addItem(L"toggle model debug information", GUI_ID_TOGGLE_DEBUG_INFO, true, true); + submenu->addItem(L"model material", -1, true, true ); + + submenu = submenu->getSubMenu(1); + submenu->addItem(L"Off", GUI_ID_DEBUG_OFF); + submenu->addItem(L"Bounding Box", GUI_ID_DEBUG_BOUNDING_BOX); + submenu->addItem(L"Normals", GUI_ID_DEBUG_NORMALS); + submenu->addItem(L"Skeleton", GUI_ID_DEBUG_SKELETON); + submenu->addItem(L"Wire overlay", GUI_ID_DEBUG_WIRE_OVERLAY); + submenu->addItem(L"Half-Transparent", GUI_ID_DEBUG_HALF_TRANSPARENT); + submenu->addItem(L"Buffers bounding boxes", GUI_ID_DEBUG_BUFFERS_BOUNDING_BOXES); + submenu->addItem(L"All", GUI_ID_DEBUG_ALL); + + submenu = menu->getSubMenu(1)->getSubMenu(2); + submenu->addItem(L"Solid", GUI_ID_MODEL_MATERIAL_SOLID); + submenu->addItem(L"Transparent", GUI_ID_MODEL_MATERIAL_TRANSPARENT); + submenu->addItem(L"Reflection", GUI_ID_MODEL_MATERIAL_REFLECTION); + + submenu = menu->getSubMenu(2); + submenu->addItem(L"Maya Style", GUI_ID_CAMERA_MAYA); + submenu->addItem(L"First Person", GUI_ID_CAMERA_FIRST_PERSON); + + submenu = menu->getSubMenu(3); + submenu->addItem(L"About", GUI_ID_ABOUT); + + /* + Below the menu we want a toolbar, onto which we can place colored + buttons and important looking stuff like a senseless combobox. + */ + + // create toolbar + + gui::IGUIToolBar* bar = env->addToolBar(); + + video::ITexture* image = driver->getTexture("open.png"); + bar->addButton(GUI_ID_BUTTON_OPEN_MODEL, 0, L"Open a model",image, 0, false, true); + + image = driver->getTexture("tools.png"); + bar->addButton(GUI_ID_BUTTON_SHOW_TOOLBOX, 0, L"Open Toolset",image, 0, false, true); + + image = driver->getTexture("zip.png"); + bar->addButton(GUI_ID_BUTTON_SELECT_ARCHIVE, 0, L"Set Model Archive",image, 0, false, true); + + image = driver->getTexture("help.png"); + bar->addButton(GUI_ID_BUTTON_SHOW_ABOUT, 0, L"Open Help", image, 0, false, true); + + // create a combobox for texture filters + + gui::IGUIComboBox* box = env->addComboBox(core::rect(250,4,350,23), bar, GUI_ID_TEXTUREFILTER); + box->addItem(L"No filtering"); + box->addItem(L"Bilinear"); + box->addItem(L"Trilinear"); + box->addItem(L"Anisotropic"); + box->addItem(L"Isotropic"); + + /* + To make the editor look a little bit better, we disable transparent gui + elements, and add an Irrlicht Engine logo. In addition, a text showing + the current frames per second value is created and the window caption is + changed. + */ + + // disable alpha + + for (s32 i=0; igetSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i); + col.setAlpha(255); + env->getSkin()->setColor((gui::EGUI_DEFAULT_COLOR)i, col); + } + + // add a tabcontrol + + createToolBox(); + + // create fps text + + IGUIStaticText* fpstext = env->addStaticText(L"", + 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); + postext->setVisible(false); + + // set window caption + Caption += " - ["; + Caption += driver->getName(); + Caption += "]"; + Device->setWindowCaption(Caption.c_str()); + + /* + Now we show the about message box at start up, and load the first model. + To make everything look better a skybox is created. We also add a user + controlled camera, to make the application more interactive. + Finally, everything is drawn in a standard drawing loop. + */ + + // show about message box and load default model + if (argc==1) + showAboutText(); + loadModel(StartUpModelFile.c_str()); + + // add skybox + SkyBox = smgr->addSkyBoxSceneNode( + driver->getTexture("irrlicht2_up.jpg"), + driver->getTexture("irrlicht2_dn.jpg"), + driver->getTexture("irrlicht2_lf.jpg"), + driver->getTexture("irrlicht2_rt.jpg"), + driver->getTexture("irrlicht2_ft.jpg"), + driver->getTexture("irrlicht2_bk.jpg")); + + // add a camera scene node + Camera[0] = smgr->addCameraSceneNodeMaya(); + Camera[0]->setFarValue(20000.f); + // Maya cameras reposition themselves relative to their target, so target the location + // where the mesh scene node is placed. + Camera[0]->setTarget(core::vector3df(0,30,0)); + + Camera[1] = smgr->addCameraSceneNodeFPS(); + Camera[1]->setFarValue(20000.f); + Camera[1]->setPosition(core::vector3df(0,0,-70)); + Camera[1]->setTarget(core::vector3df(0,30,0)); + + setActiveCamera(Camera[0]); + + // load the irrlicht engine logo + IGUIImage *img = + env->addImage(driver->getTexture("irrlichtlogo2.png"), + core::position2d(10, driver->getScreenSize().Height - 128)); + + // lock the logo's edges to the bottom left corner of the screen + img->setAlignment(EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, + EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT); + + // remember state so we notice when the window does lose the focus + bool hasFocus = Device->isWindowFocused(); + + // draw everything + while(Device->run() && driver) + { + // Catch focus changes (workaround until Irrlicht has events for this) + bool focused = Device->isWindowFocused(); + if ( hasFocus && !focused ) + onKillFocus(); + hasFocus = focused; + + if (Device->isWindowActive()) + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(150,50,50,50)); + + smgr->drawAll(); + env->drawAll(); + + driver->endScene(); + + // update information about current frame-rate + core::stringw str(L"FPS: "); + str.append(core::stringw(driver->getFPS())); + str += L" Tris: "; + str.append(core::stringw(driver->getPrimitiveCountDrawn())); + fpstext->setText(str.c_str()); + + // update information about the active camera + scene::ICameraSceneNode* cam = Device->getSceneManager()->getActiveCamera(); + str = L"Pos: "; + str.append(core::stringw(cam->getPosition().X)); + str += L" "; + str.append(core::stringw(cam->getPosition().Y)); + str += L" "; + str.append(core::stringw(cam->getPosition().Z)); + str += L" Tgt: "; + str.append(core::stringw(cam->getTarget().X)); + str += L" "; + str.append(core::stringw(cam->getTarget().Y)); + str += L" "; + str.append(core::stringw(cam->getTarget().Z)); + postext->setText(str.c_str()); + + // update the tool dialog + updateToolBox(); + } + else + Device->yield(); + } + + Device->drop(); + return 0; +} + +/* +**/ diff --git a/examples/09.Meshviewer/resource.h b/examples/09.Meshviewer/resource.h new file mode 100644 index 00000000..a8e8616a --- /dev/null +++ b/examples/09.Meshviewer/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by 9.Meshviewer.rc +// +#define IDI_ICON1 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/examples/09.Meshviewer/tutorial.html b/examples/09.Meshviewer/tutorial.html new file mode 100644 index 00000000..d296b6ca --- /dev/null +++ b/examples/09.Meshviewer/tutorial.html @@ -0,0 +1,182 @@ + + +Irrlicht Engine Tutorial + + + + +
+ + + + + + + + +
+
+
Tutorial 9. Mesh Viewer
+
+
+
+

This tutorial shows how to create a more complex application with + the engine. We construct a simple mesh viewer using the user interface + API and the scenemanagement of Irrlicht.
+ The tutorial shows how to create and use Buttons, Windows, Toolbars, + Menus, ComboBoxes, Tabcontrols, Editboxes, Images, MessageBoxes, SkyBoxes, + and how to parse XML files with the integrated XML reader of the engine.

+

The program which is described here will look like this:

+


+

+
+
+
+ + + + + + + +
Lets start!
+
+

We start like in most other tutorials: Include all nesessary header + files, add a comment to let the engine be linked with the right .lib + file in Visual Studio, and deklare some global variables. We also + add two 'using namespece' statements, so we do not need to write the + whole names of all classes. In this tutorial, we use a lot stuff from + the gui namespace.

+ + + + +
#include <irrlicht.h>
#include <iostream>

using namespace irr;
using namespace gui;

#pragma comment(lib, "Irrlicht.lib")

IrrlichtDevice *Device = 0;
core::stringc StartUpModelFile;
core::stringw MessageText;
core::stringw Caption;
scene::IAnimatedMeshSceneNode* Model = 0;
scene::ISceneNode* SkyBox = 0;
+

The three following functions do several stuff used by the mesh + viewer. The first function showAboutText() simply displays a messagebox + with a caption and a message text. The texts will be stored in the + MessageText and Caption variables at startup.

+ + + + +
void showAboutText()
{
// create modal message box with the text
// loaded from the xml file
.
Device->getGUIEnvironment()->addMessageBox(
Caption.c_str(), MessageText.c_str());
}
+

The second function loadModel() loads a model and displays it using + an addAnimatedMeshSceneNode and the scene manager. Nothing difficult. + It also displays a short message box, if the model could not be loaded. +

+ + + + +
void loadModel(const c8* filename)
{
// load a model into the engine
if (Model)
Model->remove();
Model = 0;

scene::IAnimatedMesh* m = Device->getSceneManager()->getMesh(filename);
if (!m)
{
// model could not be loaded
if (StartUpModelFile != filename)
Device->getGUIEnvironment()->addMessageBox(
Caption.c_str(), L"The model could not be loaded. " \
L"Maybe it is not a supported file format.");
return;
}

// set default material properties
Model = Device->getSceneManager()->addAnimatedMeshSceneNode(m);
Model->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
Model->setMaterialFlag(video::EMF_LIGHTING, false);
Model->setDebugDataVisible(true);
}
+

Finally, the third function creates a toolbox window. In this simple + mesh viewer, this toolbox only contains a tab control with three edit + boxes for changing the scale of the displayed model.

+ + + + +
void createToolBox()
{
// remove tool box if already there
IGUIEnvironment* env = Device->getGUIEnvironment();
IGUIElement* root = env->getRootGUIElement();
IGUIElement* e = root->getElementFromId(5000, true);
if (e) e->remove();

// create the toolbox window
IGUIWindow* wnd = env->addWindow(core::rect<s32>(450,25,640,480),
false, L"Toolset", 0, 5000);

// create tab control and tabs
IGUITabControl* tab = env->addTabControl(
core::rect<s32>(2,20,640-452,480-7), wnd, true, true);
IGUITab* t1 = tab->addTab(L"Scale");
IGUITab* t2 = tab->addTab(L"Empty Tab");

// add some edit boxes and a button to tab one
env->addEditBox(L"1.0", core::rect<s32>(40,50,130,70), true, t1, 901);
env->addEditBox(L"1.0", core::rect<s32>(40,80,130,100), true, t1, 902);
env->addEditBox(L"1.0", core::rect<s32>(40,110,130,130), true, t1, 903);
env->addButton(core::rect<s32>(10,150,100,190), t1, 1101, L"set");

// bring irrlicht engine logo to front, because it
// now may be below the newly created toolbox
root->bringToFront(root->getElementFromId(666, true));
}
+

To get all the events sent by the GUI Elements, we need to create + an event receiver. This one is really simple. If an event occurs, + it checks the id of the caller and the event type, and starts an action + based on these values. For example, if a menu item with id 100 was + selected, if opens a file-open-dialog.

+
+ + + + +
class MyEventReceiver : public IEventReceiver
{
public:
virtual bool OnEvent(const SEvent& event)
{
if (event.EventType == EET_GUI_EVENT)
{
s32 id = event.GUIEvent.Caller->getID();
IGUIEnvironment* env = Device->getGUIEnvironment();
switch(event.GUIEvent.EventType)
{
case EGET_MENU_ITEM_SELECTED:
{
// a menu item was clicked
IGUIContextMenu* menu = (IGUIContextMenu*)event.GUIEvent.Caller;
s32 id = menu->getItemCommandId(menu->getSelectedItem());

switch(id)
{
case 100: // File -> Open Model
env->addFileOpenDialog(L"Please select a model file to open");
break;
case 200: // File -> Quit
Device->closeDevice();
break;
case 300: // View -> Skybox
SkyBox->setVisible(!SkyBox->isVisible());
break;
case 400: // View -> Debug Information
if (Model)
Model->setDebugDataVisible(!Model->isDebugDataVisible());
break;
case 500: // Help->About
showAboutText();
break;
case 610: // View -> Material -> Solid
if (Model)
Model->setMaterialType(video::EMT_SOLID);
break;
case 620: // View -> Material -> Transparent
if (Model)
Model->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
break;
case 630: // View -> Material -> Reflection
if (Model)
Model->setMaterialType(video::EMT_SPHERE_MAP);
break;
}
break;
}
case EGET_FILE_SELECTED:
{
// load the model file, selected in the file open dialog
IGUIFileOpenDialog* dialog =
(IGUIFileOpenDialog*)event.GUIEvent.Caller;
loadModel(core::stringc(dialog->getFilename()).c_str());
}
case EGET_BUTTON_CLICKED:
switch(id)
{
case 1101:
{
// set scale
gui::IGUIElement* root = env->getRootGUIElement();
core::vector3df scale;
core::stringc s;
s = root->getElementFromId(901, true)->getText();
scale.X = (f32)atof(s.c_str());
s = root->getElementFromId(902, true)->getText();
scale.Y = (f32)atof(s.c_str());
s = root->getElementFromId(903, true)->getText();
scale.Z = (f32)atof(s.c_str());
if (Model)
Model->setScale(scale);
}
break;
case 1102:
env->addFileOpenDialog(L"Please select a model file to open");
break;
case 1103:
showAboutText();
break;
case 1104:
createToolBox();
break;
}
break;
}
}
return false;
}
};
+

Most of the hard work is done. We only need to create the Irrlicht + Engine device and all the buttons, menus and toolbars. We start up the + engine as usual, using createDevice(). To make our application catch + events, we set our eventreceiver as parameter. The #ifdef WIN32 preprocessor + commands are not necesarry, but I included them to make the tutorial + use DirectX on Windows and OpenGL on all other platforms like Linux. + As you can see, there is also a unusual call to IrrlichtDevice::setResizeAble(). + This makes the render window resizeable, which is quite useful for a + mesh viewer.

+ + + + +
int main()
{
// ask user for driver +
video::E_DRIVER_TYPE driverType; +
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) Apfelbaum Software Renderer\n"\
" (f) NullDevice\n (otherKey) exit\n\n");

char key;
std::cin >> key;

switch(key)
{
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;
default: return 1;
} +
// create device and exit if creation failed +
MyEventReceiver receiver;
Device = createDevice(driverType, core::dimension2d<s32>(640, 480),
16, false, false, false, &receiver); +
if (Device == 0)
return 1; // could not create selected driver.

Device->setResizable(true);
Device->setWindowCaption(L"Irrlicht Engine - Loading...");

video::IVideoDriver* driver = Device->getVideoDriver();
IGUIEnvironment* env = Device->getGUIEnvironment();
scene::ISceneManager* smgr = Device->getSceneManager();
+

The next step is to read the configuration file. It is stored in the + xml format and looks a little bit like this:
+
+ <?xml version="1.0"?>
+ <config>
+ <startUpModel file="some filename" />
+ <messageText caption="Irrlicht Engine Mesh Viewer">
+ Hello!
+ </messageText>
+ </config>

+
+ We need the data stored in there to be written into the global variables + StartUpModelFile, MessageText and Caption. This is now done using the + Irrlicht Engine integrated XML parser:

+ + + + +
	// read configuration from xml file
io::IXMLReader* xml =
Device->getFileSystem()->createXMLReader("../../media/config.xml");
while(xml && xml->read())
{
switch(xml->getNodeType())
{
case io::EXN_TEXT:
// in this xml file, the only text which occurs is the messageText
MessageText = xml->getNodeData();
break;
case io::EXN_ELEMENT:
{
if (core::stringw("startUpModel") == xml->getNodeName())
StartUpModelFile = xml->getAttributeValue(L"file");
else
if (core::stringw("messageText") == xml->getNodeName())
Caption = xml->getAttributeValue(L"caption");
}
break;
}
}
if (xml)
xml->drop(); // don't forget to delete the xml reader
+
+

That wasn't difficult. Now we'll set a nicer font and create the Menu. + It is possible to create submenus for every menu item. The call menu->addItem(L"File", + -1, true, true); for example adds a new menu Item with the name "File" + and the id -1. The following parameter says that the menu item should + be enabled, and the last one says, that there should be a submenu. The + submenu can now be accessed with menu->getSubMenu(0), because the + "File" entry is the menu item with index 0.

+ + + + +
	// set a nicer font
IGUISkin* skin = env->getSkin();
IGUIFont* font = env->getFont("../../media/fonthaettenschweiler.bmp");
if (font)
skin->setFont(font);

// create menu
gui::IGUIContextMenu* menu = env->addMenu();
menu->addItem(L"File", -1, true, true);
menu->addItem(L"View", -1, true, true);
menu->addItem(L"Help", -1, true, true);

gui::IGUIContextMenu* submenu;
submenu = menu->getSubMenu(0);
submenu->addItem(L"Open Model File...", 100);
submenu->addSeparator();
submenu->addItem(L"Quit", 200);

submenu = menu->getSubMenu(1);
submenu->addItem(L"toggle sky box visibility", 300);
submenu->addItem(L"toggle model debug information", 400);
submenu->addItem(L"model material", -1, true, true );

submenu = submenu->getSubMenu(2);
submenu->addItem(L"Solid", 610);
submenu->addItem(L"Transparent", 620);
submenu->addItem(L"Reflection", 630);

submenu = menu->getSubMenu(2);
submenu->addItem(L"About", 500); +
+
+ We want a toolbar, onto which we can place colored buttons and important + looking stuff like a senseless combobox.
+
+ + + + +
	// create toolbar
gui::IGUIToolBar* bar = env->addToolBar();
bar->addButton(1102, 0, driver->getTexture("../../media/open.bmp"));
bar->addButton(1103, 0, driver->getTexture("../../media/help.bmp"));
bar->addButton(1104, 0, driver->getTexture("../../media/tools.bmp"));

// create a combobox with some senseless texts
gui::IGUIComboBox* box = env->addComboBox(core::rect<s32>(100,5,200,25), bar);
box->addItem(L"Bilinear");
box->addItem(L"Trilinear");
box->addItem(L"Anisotropic");
box->addItem(L"Isotropic");
box->addItem(L"Psychedelic");
box->addItem(L"No filtering");
+
+ To make the editor look a little bit better, we disable transparent gui + elements, and add a Irrlicht Engine logo. In addition, a text, which will + show the current frame per second value is created, and the window caption + changed.
+
+ + + + +
	// disable alpha
for (s32 i=0; i<gui::EGDC_COUNT ; ++i)
{
video::SColor col = env->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
col.setAlpha(255);
env->getSkin()->setColor((gui::EGUI_DEFAULT_COLOR)i, col);
}

// add a tabcontrol
createToolBox();

// add the irrlicht engine logo
IGUIImage* img = env->addImage(core::rect<s32>(22,429,108,460), 0, 666);
img->setImage(driver->getTexture("../../media/irrlichtlogoaligned.jpg"));

// create fps text
IGUIStaticText* fpstext =
env->addStaticText(L"", core::rect<s32>(210,26,270,41), true);

// set window caption
Caption += " - [";
Caption += driver->getName();
Caption += "]";
Device->setWindowCaption(Caption.c_str());
+
+ That's nearly the whole application. We simply show the about message + box at start up, and load the first model. To make everything look better, + a skybox is created and a user controled camera, to make the application + a little bit more interactive. Finally, everything is drawed in a standard + drawing loop.
+
+ + + + +
	// show about message box and load default model
showAboutText();
loadModel(StartUpModelFile.c_str());

// add skybox

SkyBox = smgr->addSkyBoxSceneNode(
driver->getTexture("../../media/irrlicht2_up.bmp"),
driver->getTexture("../../media/irrlicht2_dn.bmp"),
driver->getTexture("../../media/irrlicht2_lf.bmp"),
driver->getTexture("../../media/irrlicht2_rt.bmp"),
driver->getTexture("../../media/irrlicht2_ft.bmp"),
driver->getTexture("../../media/irrlicht2_bk.bmp"));

// add a camera scene node
smgr->addCameraSceneNodeMaya();

// draw everything
while(Device->run() && driver)
if (Device->isWindowActive())
{
driver->beginScene(true, true, video::SColor(150,50,50,50));
smgr->drawAll();
env->drawAll();

driver->endScene();

core::stringw str = L"FPS: ";
str += driver->getFPS();
fpstext->setText(str.c_str());
}
Device->drop();
return 0;
}
+
+ Compile and run this, and you have a fully functional 3d Mesh viewer.
+
+
+

 

+ + diff --git a/examples/10.Shaders/Makefile b/examples/10.Shaders/Makefile new file mode 100644 index 00000000..fc57b656 --- /dev/null +++ b/examples/10.Shaders/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 10.Shaders +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/10.Shaders/Shaders.cbp b/examples/10.Shaders/Shaders.cbp new file mode 100644 index 00000000..b4f9dc53 --- /dev/null +++ b/examples/10.Shaders/Shaders.cbp @@ -0,0 +1,56 @@ + + + + + + diff --git a/examples/10.Shaders/Shaders.vcproj b/examples/10.Shaders/Shaders.vcproj new file mode 100644 index 00000000..e730a2f9 --- /dev/null +++ b/examples/10.Shaders/Shaders.vcproj @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/10.Shaders/Shaders.xcodeproj/project.pbxproj b/examples/10.Shaders/Shaders.xcodeproj/project.pbxproj new file mode 100644 index 00000000..6c36ed9a --- /dev/null +++ b/examples/10.Shaders/Shaders.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 10.Shaders.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 10.Shaders.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 10.Shaders.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 10.Shaders */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "10.Shaders" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 10.Shaders; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 10.Shaders.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Shaders" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 10.Shaders */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Shaders" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "10.Shaders" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/10.Shaders/Shaders.xcodeproj/xcshareddata/xcschemes/10.Shaders.xcscheme b/examples/10.Shaders/Shaders.xcodeproj/xcshareddata/xcschemes/10.Shaders.xcscheme new file mode 100644 index 00000000..b6111a44 --- /dev/null +++ b/examples/10.Shaders/Shaders.xcodeproj/xcshareddata/xcschemes/10.Shaders.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/10.Shaders/Shaders_vc10.vcxproj b/examples/10.Shaders/Shaders_vc10.vcxproj new file mode 100644 index 00000000..55e1e888 --- /dev/null +++ b/examples/10.Shaders/Shaders_vc10.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 10.Shaders + {27158C82-CD15-4A9B-9848-35E7065B209F} + Shaders + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Shaders.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\10.Shaders.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Shaders.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\10.Shaders.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Shaders.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\10.Shaders.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Shaders.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\10.Shaders.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/10.Shaders/Shaders_vc11.vcxproj b/examples/10.Shaders/Shaders_vc11.vcxproj new file mode 100644 index 00000000..55e1e888 --- /dev/null +++ b/examples/10.Shaders/Shaders_vc11.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 10.Shaders + {27158C82-CD15-4A9B-9848-35E7065B209F} + Shaders + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Shaders.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\10.Shaders.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Shaders.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\10.Shaders.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Shaders.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\10.Shaders.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Shaders.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\10.Shaders.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/10.Shaders/Shaders_vc12.vcxproj b/examples/10.Shaders/Shaders_vc12.vcxproj new file mode 100644 index 00000000..b7dedf0a --- /dev/null +++ b/examples/10.Shaders/Shaders_vc12.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 10.Shaders + {27158C82-CD15-4A9B-9848-35E7065B209F} + Shaders + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Shaders.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\10.Shaders.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Shaders.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\10.Shaders.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Shaders.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\10.Shaders.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Shaders.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\10.Shaders.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/10.Shaders/Shaders_vc14.vcxproj b/examples/10.Shaders/Shaders_vc14.vcxproj new file mode 100644 index 00000000..dfc7ff69 --- /dev/null +++ b/examples/10.Shaders/Shaders_vc14.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 10.Shaders + {27158C82-CD15-4A9B-9848-35E7065B209F} + Shaders + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Shaders.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\10.Shaders.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Shaders.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\10.Shaders.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Shaders.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\10.Shaders.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Shaders.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\10.Shaders.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/10.Shaders/main.cpp b/examples/10.Shaders/main.cpp new file mode 100644 index 00000000..1beb3deb --- /dev/null +++ b/examples/10.Shaders/main.cpp @@ -0,0 +1,464 @@ +/** Example 010 Shaders + +This tutorial shows how to use shaders for D3D9, and OpenGL with the +engine and how to create new material types with them. It also shows how to +disable the generation of mipmaps at texture loading, and how to use text scene +nodes. + +This tutorial does not explain how shaders work. I would recommend to read the +D3D or OpenGL, documentation, to search a tutorial, or to read a book about +this. + +At first, we need to include all headers and do the stuff we always do, like in +nearly all other tutorials: +*/ +#include +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +using namespace irr; + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +/* +Because we want to use some interesting shaders in this tutorials, we need to +set some data for them to make them able to compute nice colors. In this +example, we'll use a simple vertex shader which will calculate the color of the +vertex based on the position of the camera. +For this, the shader needs the following data: The inverted world matrix for +transforming the normal, the clip matrix for transforming the position, the +camera position and the world position of the object for the calculation of the +angle of light, and the color of the light. To be able to tell the shader all +this data every frame, we have to derive a class from the +IShaderConstantSetCallBack interface and override its only method, namely +OnSetConstants(). This method will be called every time the material is set. +The method setVertexShaderConstant() of the IMaterialRendererServices interface +is used to set the data the shader needs. If the user chose to use a High Level +shader language like HLSL instead of Assembler in this example, you have to set +the variable name as parameter instead of the register index. +*/ + +IrrlichtDevice* device = 0; +bool UseHighLevelShaders = false; + +class MyShaderCallBack : public video::IShaderConstantSetCallBack +{ +public: + MyShaderCallBack() : WorldViewProjID(-1), TransWorldID(-1), InvWorldID(-1), PositionID(-1), + ColorID(-1), TextureID(-1), FirstUpdate(true) + { + } + + virtual void OnSetConstants(video::IMaterialRendererServices* services, + s32 userData) + { + video::IVideoDriver* driver = services->getVideoDriver(); + + // get shader constants id. + + if (UseHighLevelShaders && FirstUpdate) + { + WorldViewProjID = services->getVertexShaderConstantID("mWorldViewProj"); + TransWorldID = services->getVertexShaderConstantID("mTransWorld"); + InvWorldID = services->getVertexShaderConstantID("mInvWorld"); + PositionID = services->getVertexShaderConstantID("mLightPos"); + ColorID = services->getVertexShaderConstantID("mLightColor"); + + // Textures ID are important only for OpenGL interface. + + if(driver->getDriverType() == video::EDT_OPENGL) + TextureID = services->getVertexShaderConstantID("myTexture"); + + FirstUpdate = false; + } + + // set inverted world matrix + // if we are using highlevel shaders (the user can select this when + // starting the program), we must set the constants by name. + + core::matrix4 invWorld = driver->getTransform(video::ETS_WORLD); + invWorld.makeInverse(); + + if (UseHighLevelShaders) + services->setVertexShaderConstant(InvWorldID, invWorld.pointer(), 16); + else + services->setVertexShaderConstant(invWorld.pointer(), 0, 4); + + // set clip matrix + + core::matrix4 worldViewProj; + worldViewProj = driver->getTransform(video::ETS_PROJECTION); + worldViewProj *= driver->getTransform(video::ETS_VIEW); + worldViewProj *= driver->getTransform(video::ETS_WORLD); + + if (UseHighLevelShaders) + services->setVertexShaderConstant(WorldViewProjID, worldViewProj.pointer(), 16); + else + services->setVertexShaderConstant(worldViewProj.pointer(), 4, 4); + + // set camera position + + core::vector3df pos = device->getSceneManager()-> + getActiveCamera()->getAbsolutePosition(); + + if (UseHighLevelShaders) + services->setVertexShaderConstant(PositionID, reinterpret_cast(&pos), 3); + else + services->setVertexShaderConstant(reinterpret_cast(&pos), 8, 1); + + // set light color + + video::SColorf col(0.0f,1.0f,1.0f,0.0f); + + if (UseHighLevelShaders) + services->setVertexShaderConstant(ColorID, + reinterpret_cast(&col), 4); + else + services->setVertexShaderConstant(reinterpret_cast(&col), 9, 1); + + // set transposed world matrix + + core::matrix4 world = driver->getTransform(video::ETS_WORLD); + world = world.getTransposed(); + + if (UseHighLevelShaders) + { + services->setVertexShaderConstant(TransWorldID, world.pointer(), 16); + + // set texture, for textures you can use both an int and a float setPixelShaderConstant interfaces (You need it only for an OpenGL driver). + s32 TextureLayerID = 0; + services->setPixelShaderConstant(TextureID, &TextureLayerID, 1); + } + else + services->setVertexShaderConstant(world.pointer(), 10, 4); + } + +private: + s32 WorldViewProjID; + s32 TransWorldID; + s32 InvWorldID; + s32 PositionID; + s32 ColorID; + s32 TextureID; + + bool FirstUpdate; +}; + +/* +The next few lines start up the engine just like in most other tutorials +before. But in addition, we ask the user if he wants to use high level shaders +in this example, if he selected a driver which is capable of doing so. +*/ +int main() +{ + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + // ask the user if we should use high level shaders for this example + if (driverType == video::EDT_DIRECT3D9 || + driverType == video::EDT_OPENGL) + { + char i = 'y'; + printf("Please press 'y' if you want to use high level shaders.\n"); + std::cin >> i; + if (i == 'y') + { + UseHighLevelShaders = true; + } + } + + // create device + + device = createDevice(driverType, core::dimension2d(640, 480)); + + if (device == 0) + return 1; // could not create selected driver. + + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + gui::IGUIEnvironment* gui = device->getGUIEnvironment(); + + const io::path mediaPath = getExampleMediaPath(); + + /* + Now for the more interesting parts. If we are using Direct3D, we want + to load vertex and pixel shader programs, if we have OpenGL, we want to + use ARB fragment and vertex programs. I wrote the corresponding + programs down into the files d3d9.ps, d3d9.vs, opengl.ps and opengl.vs. + We only need the right filenames now. This is done in the following switch. + Note, that it is not necessary to write the shaders into text files, + like in this example. You can even write the shaders directly as strings + into the cpp source file, and use later addShaderMaterial() instead of + addShaderMaterialFromFiles(). + */ + + io::path vsFileName; // filename for the vertex shader + io::path psFileName; // filename for the pixel shader + + switch(driverType) + { + case video::EDT_DIRECT3D9: + if (UseHighLevelShaders) + { + psFileName = mediaPath + "d3d9.hlsl"; + vsFileName = psFileName; // both shaders are in the same file + } + else + { + psFileName = mediaPath + "d3d9.psh"; + vsFileName = mediaPath + "d3d9.vsh"; + } + break; + + case video::EDT_OGLES1: + case video::EDT_OGLES2: + UseHighLevelShaders=true; + { + psFileName = "../../media/ogles2.frag"; + vsFileName = "../../media/ogles2.vert"; + } + break; + case video::EDT_OPENGL: + if (UseHighLevelShaders) + { + psFileName = mediaPath + "opengl.frag"; + vsFileName = mediaPath + "opengl.vert"; + } + else + { + psFileName = mediaPath + "opengl.psh"; + vsFileName = mediaPath + "opengl.vsh"; + } + break; + } + + /* + In addition, we check if the hardware and the selected renderer is + capable of executing the shaders we want. If not, we simply set the + filename string to 0. This is not necessary, but useful in this + example: For example, if the hardware is able to execute vertex shaders + but not pixel shaders, we create a new material which only uses the + vertex shader, and no pixel shader. Otherwise, if we would tell the + engine to create this material and the engine sees that the hardware + wouldn't be able to fulfill the request completely, it would not + create any new material at all. So in this example you would see at + least the vertex shader in action, without the pixel shader. + */ + + if (!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) && + !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)) + { + device->getLogger()->log("WARNING: Pixel shaders disabled "\ + "because of missing driver/hardware support."); + psFileName = ""; + } + + if (!driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) && + !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)) + { + device->getLogger()->log("WARNING: Vertex shaders disabled "\ + "because of missing driver/hardware support."); + vsFileName = ""; + } + + /* + Now lets create the new materials. As you maybe know from previous + examples, a material type in the Irrlicht engine is set by simply + changing the MaterialType value in the SMaterial struct. And this value + is just a simple 32 bit value, like video::EMT_SOLID. So we only need + the engine to create a new value for us which we can set there. To do + this, we get a pointer to the IGPUProgrammingServices and call + addShaderMaterialFromFiles(), which returns such a new 32 bit value. + That's all. + + The parameters to this method are the following: First, the names of + the files containing the code of the vertex and the pixel shader. If + you would use addShaderMaterial() instead, you would not need file + names, then you could write the code of the shader directly as string. + The following parameter is a pointer to the IShaderConstantSetCallBack + class we wrote at the beginning of this tutorial. If you don't want to + set constants, set this to 0. The last parameter tells the engine which + material it should use as base material. + + To demonstrate this, we create two materials with a different base + material, one with EMT_SOLID and one with EMT_TRANSPARENT_ADD_COLOR. + */ + + // create materials + + video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices(); + s32 newMaterialType1 = 0; + s32 newMaterialType2 = 0; + + if (gpu) + { + /* + Create one callback instance for each shader material you add. + Reason is that the getVertexShaderConstantID returns ID's which are + only valid per added material (The ID's tend to be identical + as long as the shader code is exactly identical, but it's not good + style to depend on that). + */ + MyShaderCallBack* mcSolid = new MyShaderCallBack(); + MyShaderCallBack* mcTransparentAdd = new MyShaderCallBack(); + + // create the shaders depending on if the user wanted high level + // or low level shaders: + + if (UseHighLevelShaders) + { + // create material from high level shaders (hlsl, glsl) + + newMaterialType1 = gpu->addHighLevelShaderMaterialFromFiles( + vsFileName, "vertexMain", video::EVST_VS_1_1, + psFileName, "pixelMain", video::EPST_PS_1_1, + mcSolid, video::EMT_SOLID, 0); + + newMaterialType2 = gpu->addHighLevelShaderMaterialFromFiles( + vsFileName, "vertexMain", video::EVST_VS_1_1, + psFileName, "pixelMain", video::EPST_PS_1_1, + mcTransparentAdd, video::EMT_TRANSPARENT_ADD_COLOR, 0); + } + else + { + // create material from low level shaders (asm or arb_asm) + + newMaterialType1 = gpu->addShaderMaterialFromFiles(vsFileName, + psFileName, mcSolid, video::EMT_SOLID); + + newMaterialType2 = gpu->addShaderMaterialFromFiles(vsFileName, + psFileName, mcTransparentAdd, video::EMT_TRANSPARENT_ADD_COLOR); + } + + mcSolid->drop(); + mcTransparentAdd->drop(); + } + + /* + Now it's time for testing the materials. We create a test cube and set + the material we created. In addition, we add a text scene node to the + cube and a rotation animator to make it look more interesting and + important. + */ + + // create test scene node 1, with the new created material type 1 + + scene::ISceneNode* node = smgr->addCubeSceneNode(50); + node->setPosition(core::vector3df(0,0,0)); + node->setMaterialTexture(0, driver->getTexture(mediaPath + "wall.bmp")); + node->setMaterialFlag(video::EMF_LIGHTING, false); + node->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType1); + + smgr->addTextSceneNode(gui->getBuiltInFont(), + L"PS & VS & EMT_SOLID", + video::SColor(255,255,255,255), node); + + scene::ISceneNodeAnimator* anim = smgr->createRotationAnimator( + core::vector3df(0,0.3f,0)); + node->addAnimator(anim); + anim->drop(); + + /* + Same for the second cube, but with the second material we created. + */ + + // create test scene node 2, with the new created material type 2 + + node = smgr->addCubeSceneNode(50); + node->setPosition(core::vector3df(0,-10,50)); + node->setMaterialTexture(0, driver->getTexture(mediaPath + "wall.bmp")); + node->setMaterialFlag(video::EMF_LIGHTING, false); + node->setMaterialFlag(video::EMF_BLEND_OPERATION, true); + node->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType2); + + smgr->addTextSceneNode(gui->getBuiltInFont(), + L"PS & VS & EMT_TRANSPARENT", + video::SColor(255,255,255,255), node); + + anim = smgr->createRotationAnimator(core::vector3df(0,0.3f,0)); + node->addAnimator(anim); + anim->drop(); + + /* + Then we add a third cube without a shader on it, to be able to compare + the cubes. + */ + + // add a scene node with no shader + + node = smgr->addCubeSceneNode(50); + node->setPosition(core::vector3df(0,50,25)); + node->setMaterialTexture(0, driver->getTexture(mediaPath + "wall.bmp")); + node->setMaterialFlag(video::EMF_LIGHTING, false); + smgr->addTextSceneNode(gui->getBuiltInFont(), L"NO SHADER", + video::SColor(255,255,255,255), node); + + /* + And last, we add a skybox and a user controlled camera to the scene. + For the skybox textures, we disable mipmap generation, because we don't + need mipmaps on it. + */ + + // add a nice skybox + + driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); + + smgr->addSkyBoxSceneNode( + driver->getTexture(mediaPath + "irrlicht2_up.jpg"), + driver->getTexture(mediaPath + "irrlicht2_dn.jpg"), + driver->getTexture(mediaPath + "irrlicht2_lf.jpg"), + driver->getTexture(mediaPath + "irrlicht2_rt.jpg"), + driver->getTexture(mediaPath + "irrlicht2_ft.jpg"), + driver->getTexture(mediaPath + "irrlicht2_bk.jpg")); + + driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true); + + // add a camera and disable the mouse cursor + + scene::ICameraSceneNode* cam = smgr->addCameraSceneNodeFPS(); + cam->setPosition(core::vector3df(-100,50,100)); + cam->setTarget(core::vector3df(0,0,0)); + device->getCursorControl()->setVisible(false); + + /* + Now draw everything. That's all. + */ + + int lastFPS = -1; + + while(device->run()) + if (device->isWindowActive()) + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,0,0,0)); + smgr->drawAll(); + driver->endScene(); + + int fps = driver->getFPS(); + + if (lastFPS != fps) + { + core::stringw str = L"Irrlicht Engine - Vertex and pixel shader example ["; + str += driver->getName(); + str += "] FPS:"; + str += fps; + + device->setWindowCaption(str.c_str()); + lastFPS = fps; + } + } + + device->drop(); + + return 0; +} + +/* +Compile and run this, and I hope you have fun with your new little shader +writing tool :). +**/ diff --git a/examples/10.Shaders/tutorial.html b/examples/10.Shaders/tutorial.html new file mode 100644 index 00000000..05c4f08a --- /dev/null +++ b/examples/10.Shaders/tutorial.html @@ -0,0 +1,566 @@ + + +Irrlicht Engine Tutorial + + + + +
+ + + + + + + + +
+
+
Tutorial 10. Shaders
+
+
+
+

This tutorial shows how to use shaders for D3D8, D3D9 and OpenGL with + the engine and how to create new material types with them. It also shows + how to disable the generation of mipmaps at texture loading, and how + to use text scene nodes.

+

This tutorial does not explain how shaders work. I would recommend + to read the D3D or OpenGL documentation, to search a tutorial, or to + read a book about this.

+

The program which is described here will look like this:

+


+

+
+
+
+ + + + + + + +
Lets start!
+
+

At first, we need to include all headers and do the stuff we always + do, like in nearly all other tutorials:

+ + + + +
#include <irrlicht.h>
#include <iostream>

using namespace irr;

#pragma comment(lib, "Irrlicht.lib")
+

Because we want to use some interesting shaders in this tutorials, + we need to set some data for them to make them able to compute nice + colors. In this example, we'll use a simple vertex shader which will + calculate the color of the vertex based on the position of the camera. + For this, the shader needs the following data: The inverted world + matrix for transforming the normal, the clip matrix for transforming + the position, the camera position and the world position of the object + for the calculation of the angle of light, and the color of the light. + To be able to tell the shader all this data every frame, we have to + derive a class from the IShaderConstantSetCallBack interface and override + its only method, namely OnSetConstants(). This method will be called + every time the material is set.
+ The method setVertexShaderConstant() of the IMaterialRendererServices + interface is used to set the data the shader needs. If the user chose + to use a High Level shader language like HLSL instead of Assembler + in this example, you have to set the variable name as parameter instead + of the register index.

+ + + + +
IrrlichtDevice* device = 0;
bool UseHighLevelShaders = false;

class MyShaderCallBack : public video::IShaderConstantSetCallBack
{
public: +
virtual void OnSetConstants(video::IMaterialRendererServices* services, s32 userData)
{
video::IVideoDriver* driver = services->getVideoDriver();

// set inverted world matrix
// if we are using highlevel shaders (the user can select this when
// starting the program), we must set the constants by name.

core::matrix4 invWorld = driver->getTransform(video::ETS_WORLD);
invWorld.makeInverse();

if (UseHighLevelShaders)
services->setVertexShaderConstant("mInvWorld", &invWorld.M[0], 16);
else
services->setVertexShaderConstant(&invWorld.M[0], 0, 4);

// set clip matrix
core::matrix4 worldViewProj;
worldViewProj = driver->getTransform(video::ETS_PROJECTION);
worldViewProj *= driver->getTransform(video::ETS_VIEW);
worldViewProj *= driver->getTransform(video::ETS_WORLD);

if (UseHighLevelShaders)
services->setVertexShaderConstant("mWorldViewProj", &worldViewProj.M[0], 16);
else
services->setVertexShaderConstant(&worldViewProj.M[0], 4, 4);

// set camera position
core::vector3df pos = device->getSceneManager()->
getActiveCamera()->getAbsolutePosition();

if (UseHighLevelShaders)
services->setVertexShaderConstant("mLightPos", reinterpret_cast<f32*>(&pos), 3);
else
services->setVertexShaderConstant(reinterpret_cast<f32*>(&pos), 8, 1);

// set light color
video::SColorf col(0.0f,1.0f,1.0f,0.0f);

if (UseHighLevelShaders)
services->setVertexShaderConstant("mLightColor", reinterpret_cast<f32*>(&col), 4);
else
services->setVertexShaderConstant(reinterpret_cast<f32*>(&col), 9, 1);

// set transposed world matrix
core::matrix4 world = driver->getTransform(video::ETS_WORLD);
world = world.getTransposed();

if (UseHighLevelShaders)
services->setVertexShaderConstant("mTransWorld", &world.M[0], 16);
else
services->setVertexShaderConstant(&world.M[0], 10, 4);
}
};
+

The next few lines start up the engine. Just like in most other + tutorials before. But in addition, we ask the user if he wants this + example to use high level shaders if he selected a driver which is + capable of doing so.

+ + + + +
int main()
{
// let user select driver type

video::E_DRIVER_TYPE driverType = video::EDT_DIRECTX9;

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) Apfelbaum Software Renderer\n"\
" (f) NullDevice\n (otherKey) exit\n\n");

char i;
std::cin >> i;

switch(i)
{
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;
default: return 1;
}

// ask the user if we should use high level shaders for this example
if (driverType == video::EDT_DIRECT3D9 ||
driverType == video::EDT_OPENGL) + {
printf("Please press 'y' if you want to use high level shaders.\n");
std::cin >> i;
if (i == 'y')
UseHighLevelShaders = true;
}

// create device

device = createDevice(driverType, core::dimension2d<s32>(640, 480));

if (device == 0)
{
printf("\nWas not able to create driver.\n"\
"Please restart and select another driver.\n"
);
getch();
return 1;
}

video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
gui::IGUIEnvironment* gui = device->getGUIEnvironment();
+

Now for the more interesting parts. If we are using Direct3D, we + want to load vertex and pixel shader programs, if we have
+ OpenGL, we want to use ARB fragment and vertex programs. I wrote the + corresponding programs down into the files d3d8.ps, d3d8.vs, d3d9.ps, + d3d9.vs, opengl.ps and opengl.vs. We only need the right filenames + now. This is done in the following switch. Note, that it is not necessary + to write the shaders into text files, like in this example. You can + even write the shaders directly as strings into the cpp source file, + and use later addShaderMaterial() instead of addShaderMaterialFromFiles().

+ + + + +
	c8* vsFileName = 0; // filename for the vertex shader
c8* psFileName = 0; // filename for the pixel shader

switch(driverType)
{
case video::EDT_DIRECT3D8:
psFileName = "../../media/d3d8.psh";
vsFileName = "../../media/d3d8.vsh";
break;
case video::EDT_DIRECT3D9:
if (UseHighLevelShaders)
{
psFileName = "../../media/d3d9.hlsl";
vsFileName = psFileName; // both shaders are in the same file
}
else
{
psFileName = "../../media/d3d9.psh";
vsFileName = "../../media/d3d9.vsh";
}
break;
case video::EDT_OPENGL:
if (UseHighLevelShaders)
{
psFileName = "../../media/opengl.frag";
vsFileName = "../../media/opengl.vert";
}
else
{
psFileName = "../../media/opengl.psh";
vsFileName = "../../media/opengl.vsh";
}
break;
}
+
+

In addition, we check if the hardware and the selected renderer + is capable of executing the shaders we want. If not, we simply set + the filename string to 0. This is not necessary, but useful in this + example: For example, if the hardware is able to execute vertex shaders + but not pixel shaders, we create a new material which only uses the + vertex shader, and no pixel shader. Otherwise, if we would tell the + engine to create this material and the engine sees that the hardware + wouldn't be able to fullfill the request completely,
+ it would not create any new material at all. So in this example you + would see at least the vertex shader in action, without the pixel + shader.

+
+ + + + +
	if (!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
!driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1))
{
device->getLogger()->log("WARNING: Pixel shaders disabled "\
"because of missing driver/hardware support.");
psFileName = 0;
}

if (!driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
!driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1))
{
device->getLogger()->log("WARNING: Vertex shaders disabled "\
"because of missing driver/hardware support.");
vsFileName = 0;
}
+

Now lets create the new materials.
+ As you maybe know from previous examples, a material type in the Irrlicht + engine is set by simply changing the MaterialType value in the SMaterial + struct. And this value is just a simple 32 bit value, like video::EMT_SOLID. + So we only need the engine to create a new value for us which we can + set there. To do this, we get a pointer to the IGPUProgrammingServices + and call addShaderMaterialFromFiles(), which returns such a new 32 bit + value. That's all.
+ The parameters to this method are the following: First, the names of + the files containing the code of the vertex and the pixel shader.
+ If you would use addShaderMaterial() instead, you would not need file + names, then you could write the code of the shader directly as string. + The following parameter is a pointer to the IShaderConstantSetCallBack + class we wrote at the beginning of this tutorial. If you don't want + to set constants, set this to 0. The last paramter tells the engine + which material it should use as base material.
+ To demonstrate this, we create two materials with a different base material, + one with EMT_SOLID and one with EMT_TRANSPARENT_ADD_COLOR.

+ + + + +
	// create materials

video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();

s32 newMaterialType1 = 0;
s32 newMaterialType2 = 0;

if (gpu)
{
MyShaderCallBack* mc = new MyShaderCallBack();
+ // create the shaders depending on if the user wanted high level
// or low level shaders:


if (UseHighLevelShaders)
{
// create material from high level shaders (hlsl or glsl)

newMaterialType1 = gpu->addHighLevelShaderMaterialFromFiles(
vsFileName, "vertexMain", video::EVST_VS_1_1,
psFileName, "pixelMain", video::EPST_PS_1_1,
mc, video::EMT_SOLID);

newMaterialType2 = gpu->addHighLevelShaderMaterialFromFiles(
vsFileName, "vertexMain", video::EVST_VS_1_1,
psFileName, "pixelMain", video::EPST_PS_1_1,
mc, video::EMT_TRANSPARENT_ADD_COLOR);
}
else
{
// create material from low level shaders (asm or arb_asm)

newMaterialType1 = gpu->addShaderMaterialFromFiles(vsFileName,
psFileName, mc, video::EMT_SOLID);

newMaterialType2 = gpu->addShaderMaterialFromFiles(vsFileName,
psFileName, mc, video::EMT_TRANSPARENT_ADD_COLOR);
}

mc->drop();
}
+

Now its time for testing out the materials. We create a test cube + and set the material we created. In addition, we add a text scene node + to the cube and a rotatation animator, to make it look more interesting + and important.

+ + + + +

+	// create test scene node 1, with the new created material type 1
+
+	scene::ISceneNode* node = smgr->addCubeSceneNode(50);
+	node->setPosition(core::vector3df(0,0,0));
+	node->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp"));
+	node->setMaterialFlag(video::EMF_LIGHTING, false);
+	node->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType1);
+
+	smgr->addTextSceneNode(gui->getBuiltInFont(),
+			L"PS & VS & EMT_SOLID",
+			video::SColor(255,255,255,255),	node);
+
+	scene::ISceneNodeAnimator* anim = smgr->createRotationAnimator(
+			core::vector3df(0,0.3f,0));
+	node->addAnimator(anim);
+	anim->drop();
+

Same for the second cube, but with the second material we created.

+ + + + +
	// create test scene node 2, with the new created material type 2
+
+	node = smgr->addCubeSceneNode(50);
+	node->setPosition(core::vector3df(0,-10,50));
+	node->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp"));
+	node->setMaterialFlag(video::EMF_LIGHTING, false);
+	node->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType2);
+
+	smgr->addTextSceneNode(gui->getBuiltInFont(),
+			L"PS & VS & EMT_TRANSPARENT",
+			video::SColor(255,255,255,255),	node);
+
+	anim = smgr->createRotationAnimator(core::vector3df(0,0.3f,0));
+	node->addAnimator(anim);
+	anim->drop();
+
+ Then we add a third cube without a shader on it, to be able to compare + the cubes.
+
+ + + + +
	// add a scene node with no shader 
+
+	node = smgr->addCubeSceneNode(50);
+	node->setPosition(core::vector3df(0,50,25));
+	node->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp"));
+	node->setMaterialFlag(video::EMF_LIGHTING, false);
+	smgr->addTextSceneNode(gui->getBuiltInFont(), L"NO SHADER",
+		video::SColor(255,255,255,255), node);
+            
+
+ And last, we add a skybox and a user controlled camera to the scene. For + the skybox textures, we disable mipmap generation, because we don't need + mipmaps on it.
+
+ + + + +
	// add a nice skybox

driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);

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"));

driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);

// add a camera and disable the mouse cursor

scene::ICameraSceneNode* cam = smgr->addCameraSceneNodeFPS(0, 100.0f, 100.0f);
cam->setPosition(core::vector3df(-100,50,100));
cam->setTarget(core::vector3df(0,0,0));
device->getCursorControl()->setVisible(false);
+
+ Now draw everything. That's all.
+
+ + + + +
	int lastFPS = -1;

while(device->run())
if (device->isWindowActive())
{
driver->beginScene(true, true, video::SColor(255,0,0,0));
smgr->drawAll();
driver->endScene();

int fps = driver->getFPS();

if (lastFPS != fps)
{
core::stringw str = L"Irrlicht Engine - Vertex and pixel shader example [";
str += driver->getName();
str += "] FPS:";
str += fps;
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
}

device->drop();

return 0;
+
+ Compile and run this, and I hope you have fun with your new little shader + writing tool :).
+
+
+
+ + + + + + + +
Shader files
+
+

The files containing the shaders can be found in the media directory + of the SDK. However, they look like this:

+ + + + + + + +
D3D9.HLSL
+
+// part of the Irrlicht Engine Shader example.
+// These simple Direct3D9 pixel and vertex shaders will be loaded by the shaders
+// example. Please note that these example shaders don't do anything really useful. 
+// They only demonstrate that shaders can be used in Irrlicht.
+
+//-----------------------------------------------------------------------------
+// Global variables
+//-----------------------------------------------------------------------------
+float4x4 mWorldViewProj;  // World * View * Projection transformation
+float4x4 mInvWorld;       // Inverted world matrix
+float4x4 mTransWorld;     // Transposed world matrix
+float3 mLightPos;         // Light position
+float4 mLightColor;       // Light color
+
+
+// Vertex shader output structure
+struct VS_OUTPUT
+{
+	float4 Position   : POSITION;   // vertex position 
+	float4 Diffuse    : COLOR0;     // vertex diffuse color
+	float2 TexCoord   : TEXCOORD0;  // tex coords
+};
+
+
+VS_OUTPUT vertexMain( in float4 vPosition : POSITION,
+                      in float3 vNormal   : NORMAL,
+                      float2 texCoord     : TEXCOORD0 )
+{
+	VS_OUTPUT Output;
+
+	// transform position to clip space 
+	Output.Position = mul(vPosition, mWorldViewProj);
+	
+	// transform normal 
+	float3 normal = mul(vNormal, mInvWorld);
+	
+	// renormalize normal 
+	normal = normalize(normal);
+	
+	// position in world coodinates
+	float3 worldpos = mul(mTransWorld, vPosition);
+	
+	// calculate light vector, vtxpos - lightpos
+	float3 lightVector = worldpos - mLightPos;
+	
+	// normalize light vector 
+	lightVector = normalize(lightVector);
+	
+	// calculate light color 
+	float3 tmp = dot(-lightVector, normal);
+	tmp = lit(tmp.x, tmp.y, 1.0);
+	
+	tmp = mLightColor * tmp.y;
+	Output.Diffuse = float4(tmp.x, tmp.y, tmp.z, 0);
+	Output.TexCoord = texCoord;
+	
+	return Output;
+}
+
+
+
+// Pixel shader output structure
+struct PS_OUTPUT
+{
+    float4 RGBColor : COLOR0;  // Pixel color    
+};
+
+
+sampler2D tex0;
+	
+PS_OUTPUT pixelMain( float2 TexCoord : TEXCOORD0,
+                     float4 Position : POSITION,
+                     float4 Diffuse  : COLOR0 ) 
+{ 
+	PS_OUTPUT Output;
+
+	float4 col = tex2D( tex0, TexCoord );  // sample color map
+	
+	// multiply with diffuse and do other senseless operations
+	Output.RGBColor = Diffuse * col;
+	Output.RGBColor *= 4.0;
+
+	return Output;
+}
+
+ + + + + + + +
D3D9.VSH
+; part of the Irrlicht Engine Shader example.
+; This Direct3D9 vertex shader will be loaded by the engine.
+; Please note that these example shaders don't do anything really useful. 
+; They only demonstrate that shaders can be used in Irrlicht.
+vs.1.1 + +dcl_position v0; ; declare position +dcl_normal v1; ; declare normal +dcl_color v2; ; declare color +dcl_texcoord0 v3; ; declare texture coordinate
+; transpose and transform position to clip space +mul r0, v0.x, c4 +mad r0, v0.y, c5, r0 +mad r0, v0.z, c6, r0 +add oPos, c7, r0 + +; transform normal +dp3 r1.x, v1, c0 +dp3 r1.y, v1, c1 +dp3 r1.z, v1, c2 + +; renormalize normal +dp3 r1.w, r1, r1 +rsq r1.w, r1.w +mul r1, r1, r1.w + +; calculate light vector +m4x4 r6, v0, c10 ; vertex into world position +add r2, c8, -r6 ; vtxpos - lightpos + +; normalize light vector +dp3 r2.w, r2, r2 +rsq r2.w, r2.w +mul r2, r2, r2.w + +; calculate light color +dp3 r3, r1, r2 ; dp3 with negative light vector +lit r5, r3 ; clamp to zero if r3 < 0, r5 has diffuce component in r5.y +mul oD0, r5.y, c9 ; ouput diffuse color +mov oT0, v3 ; store texture coordinates
+
+ + + + + + + +
D3D9.PSH
+; part of the Irrlicht Engine Shader example.
+; This simple Direct3D9 pixel shader will be loaded by the engine.
+; Please note that these example shaders don't do anything really useful. 
+; They only demonstrate that shaders can be used in Irrlicht.
+ps.1.1 + +tex t0 ; sample color map +add r0, v0, v0 ; mulitply with color +mul t0, t0, r0 ; mulitply with color +add r0, t0, t0 ; make it brighter and store result +
+
+ + + + + + + +
D3D8.VSH
+; part of the Irrlicht Engine Shader example.
+; This Direct3D9 vertex shader will be loaded by the engine.
+; Please note that these example shaders don't do anything really useful. 
+; They only demonstrate that shaders can be used in Irrlicht.
+vs.1.1 + +; transpose and transform position to clip space +mul r0, v0.x, c4 +mad r0, v0.y, c5, r0 +mad r0, v0.z, c6, r0 +add oPos, c7, r0 + +; transform normal +dp3 r1.x, v1, c0 +dp3 r1.y, v1, c1 +dp3 r1.z, v1, c2 + +; renormalize normal +dp3 r1.w, r1, r1 +rsq r1.w, r1.w +mul r1, r1, r1.w + +; calculate light vector +m4x4 r6, v0, c10 ; vertex into world position +add r2, c8, -r6 ; vtxpos - lightpos + +; normalize light vector +dp3 r2.w, r2, r2 +rsq r2.w, r2.w +mul r2, r2, r2.w + +; calculate light color +dp3 r3, r1, r2 ; dp3 with negative light vector +lit r5, r3 ; clamp to zero if r3 < 0, r5 has diffuce component in r5.y +mul oD0, r5.y, c9 ; ouput diffuse color +mov oT0, v3 ; store texture coordinates
+
+ + + + + + + +
D3D8.PSH
+; part of the Irrlicht Engine Shader example.
+; This simple Direct3D9 pixel shader will be loaded by the engine.
+; Please note that these example shaders don't do anything really useful. 
+; They only demonstrate that shaders can be used in Irrlicht.
+ps.1.1 + +tex t0 ; sample color map +mul_x2 t0, t0, v0 ; mulitply with color +add r0, t0, t0 ; make it brighter and store result
+
+ + + + + + + +
OPENGL.VSH
+!!ARBvp1.0
+# part of the Irrlicht Engine Shader example.
+# Please note that these example shaders don't do anything really useful. 
+# They only demonstrate that shaders can be used in Irrlicht.
+#input +ATTRIB InPos = vertex.position; +ATTRIB InColor = vertex.color; +ATTRIB InNormal = vertex.normal; +ATTRIB InTexCoord = vertex.texcoord; + +#output +OUTPUT OutPos = result.position; +OUTPUT OutColor = result.color; +OUTPUT OutTexCoord = result.texcoord; + +PARAM MVP[4] = { state.matrix.mvp }; # modelViewProjection matrix. +TEMP Temp; +TEMP TempColor; +TEMP TempNormal; +TEMP TempPos; + +#transform position to clip space +DP4 Temp.x, MVP[0], InPos; +DP4 Temp.y, MVP[1], InPos; +DP4 Temp.z, MVP[2], InPos; +DP4 Temp.w, MVP[3], InPos; + +#transform normal +DP3 TempNormal.x, InNormal.x, program.local[0]; +DP3 TempNormal.y, InNormal.y, program.local[1]; +DP3 TempNormal.z, InNormal.z, program.local[2]; + +#renormalize normal +DP3 TempNormal.w, TempNormal, TempNormal; +RSQ TempNormal.w, TempNormal.w; +MUL TempNormal, TempNormal, TempNormal.w; + +# calculate light vector +DP4 TempPos.x, InPos, program.local[10]; # vertex into world position +DP4 TempPos.y, InPos, program.local[11]; +DP4 TempPos.z, InPos, program.local[12]; +DP4 TempPos.w, InPos, program.local[13]; + +ADD TempPos, program.local[8], -TempPos; # vtxpos - lightpos + +# normalize light vector +DP3 TempPos.w, TempPos, TempPos; +RSQ TempPos.w, TempPos.w; +MUL TempPos, TempPos, TempPos.w; + +# calculate light color +DP3 TempColor, TempNormal, TempPos; # dp3 with negative light vector +LIT OutColor, TempColor; # clamp to zero if r3 < 0, r5 has diffuce component in r5.y +MUL OutColor, TempColor.y, program.local[9]; # ouput diffuse color +MOV OutColor.w, 1.0; # we want alpha to be always 1 +MOV OutTexCoord, InTexCoord; # store texture coordinate +MOV OutPos, Temp; + +END
+
+ + + + + + + +
OPENGL.PSH
+!!ARBfp1.0
+# part of the Irrlicht Engine Shader example.
+# Please note that these example shaders don't do anything really useful. 
+# They only demonstrate that shaders can be used in Irrlicht.
+#Input +ATTRIB inTexCoord = fragment.texcoord; # texture coordinates +ATTRIB inColor = fragment.color.primary; # interpolated diffuse color + +#Output +OUTPUT outColor = result.color; + +TEMP texelColor; +TEMP tmp; +TXP texelColor, inTexCoord, texture, 2D; + +ADD tmp, inColor, inColor; # mulitply with color +MUL texelColor, texelColor, tmp; # mulitply with color +ADD outColor, texelColor, texelColor; # make it brighter and store result + +END
+

 

+
+
+

 

+

 

+ + diff --git a/examples/11.PerPixelLighting/Makefile b/examples/11.PerPixelLighting/Makefile new file mode 100644 index 00000000..fddcd343 --- /dev/null +++ b/examples/11.PerPixelLighting/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 11.PerPixelLighting +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/11.PerPixelLighting/PerPixelLighting.cbp b/examples/11.PerPixelLighting/PerPixelLighting.cbp new file mode 100644 index 00000000..709dd850 --- /dev/null +++ b/examples/11.PerPixelLighting/PerPixelLighting.cbp @@ -0,0 +1,56 @@ + + + + + + diff --git a/examples/11.PerPixelLighting/PerPixelLighting.vcproj b/examples/11.PerPixelLighting/PerPixelLighting.vcproj new file mode 100644 index 00000000..94d7e6a7 --- /dev/null +++ b/examples/11.PerPixelLighting/PerPixelLighting.vcproj @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/11.PerPixelLighting/PerPixelLighting.xcodeproj/project.pbxproj b/examples/11.PerPixelLighting/PerPixelLighting.xcodeproj/project.pbxproj new file mode 100644 index 00000000..cac51bca --- /dev/null +++ b/examples/11.PerPixelLighting/PerPixelLighting.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 11.PerPixelLighting.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 11.PerPixelLighting.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 11.PerPixelLighting.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 11.PerPixelLighting */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "11.PerPixelLighting" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 11.PerPixelLighting; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 11.PerPixelLighting.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "PerPixelLighting" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 11.PerPixelLighting */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "PerPixelLighting" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "11.PerPixelLighting" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/11.PerPixelLighting/PerPixelLighting.xcodeproj/xcshareddata/xcschemes/11.PerPixelLighting.xcscheme b/examples/11.PerPixelLighting/PerPixelLighting.xcodeproj/xcshareddata/xcschemes/11.PerPixelLighting.xcscheme new file mode 100644 index 00000000..ddd1fcf4 --- /dev/null +++ b/examples/11.PerPixelLighting/PerPixelLighting.xcodeproj/xcshareddata/xcschemes/11.PerPixelLighting.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/11.PerPixelLighting/PerPixelLighting_vc10.vcxproj b/examples/11.PerPixelLighting/PerPixelLighting_vc10.vcxproj new file mode 100644 index 00000000..2179bc44 --- /dev/null +++ b/examples/11.PerPixelLighting/PerPixelLighting_vc10.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 11.PerPixelLighting + {C4B42409-542D-4EFC-9E6B-44713FD47A33} + PerPixelLighting + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/PerPixelLighting.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\11.PerPixelLighting.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/PerPixelLighting.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\11.PerPixelLighting.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/PerPixelLighting.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\11.PerPixelLighting.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/PerPixelLighting.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\11.PerPixelLighting.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/11.PerPixelLighting/PerPixelLighting_vc11.vcxproj b/examples/11.PerPixelLighting/PerPixelLighting_vc11.vcxproj new file mode 100644 index 00000000..2179bc44 --- /dev/null +++ b/examples/11.PerPixelLighting/PerPixelLighting_vc11.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 11.PerPixelLighting + {C4B42409-542D-4EFC-9E6B-44713FD47A33} + PerPixelLighting + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/PerPixelLighting.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\11.PerPixelLighting.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/PerPixelLighting.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\11.PerPixelLighting.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/PerPixelLighting.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\11.PerPixelLighting.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/PerPixelLighting.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\11.PerPixelLighting.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/11.PerPixelLighting/PerPixelLighting_vc12.vcxproj b/examples/11.PerPixelLighting/PerPixelLighting_vc12.vcxproj new file mode 100644 index 00000000..ca2c3f4c --- /dev/null +++ b/examples/11.PerPixelLighting/PerPixelLighting_vc12.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 11.PerPixelLighting + {C4B42409-542D-4EFC-9E6B-44713FD47A33} + PerPixelLighting + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/PerPixelLighting.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\11.PerPixelLighting.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/PerPixelLighting.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\11.PerPixelLighting.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/PerPixelLighting.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\11.PerPixelLighting.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/PerPixelLighting.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\11.PerPixelLighting.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/11.PerPixelLighting/PerPixelLighting_vc14.vcxproj b/examples/11.PerPixelLighting/PerPixelLighting_vc14.vcxproj new file mode 100644 index 00000000..3e6da846 --- /dev/null +++ b/examples/11.PerPixelLighting/PerPixelLighting_vc14.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 11.PerPixelLighting + {C4B42409-542D-4EFC-9E6B-44713FD47A33} + PerPixelLighting + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/PerPixelLighting.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\11.PerPixelLighting.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/PerPixelLighting.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\11.PerPixelLighting.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/PerPixelLighting.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\11.PerPixelLighting.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/PerPixelLighting.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\11.PerPixelLighting.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/11.PerPixelLighting/main.cpp b/examples/11.PerPixelLighting/main.cpp new file mode 100644 index 00000000..c2e03af2 --- /dev/null +++ b/examples/11.PerPixelLighting/main.cpp @@ -0,0 +1,483 @@ +/** Example 011 Per-Pixel Lighting + +This tutorial shows how to use one of the built in more complex materials in +irrlicht: Per pixel lighted surfaces using normal maps and parallax mapping. It +will also show how to use fog and moving particle systems. And don't panic: You +do not need any experience with shaders to use these materials in Irrlicht. + +At first, we need to include all headers and do the stuff we always do, like in +nearly all other tutorials. +*/ +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +using namespace irr; + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +/* +For this example, we need an event receiver, to make it possible for the user +to switch between the three available material types. In addition, the event +receiver will create some small GUI window which displays what material is +currently being used. There is nothing special done in this class, so maybe you +want to skip reading it. +*/ +class MyEventReceiver : public IEventReceiver +{ +public: + + MyEventReceiver(scene::ISceneNode* room,scene::ISceneNode* earth, + gui::IGUIEnvironment* env, video::IVideoDriver* driver) + { + // store pointer to room so we can change its drawing mode + Room = room; + Earth = earth; + Driver = driver; + + // set a nicer font + gui::IGUISkin* skin = env->getSkin(); + gui::IGUIFont* font = env->getFont(getExampleMediaPath() + "fonthaettenschweiler.bmp"); + if (font) + skin->setFont(font); + + // add window and listbox + gui::IGUIWindow* window = env->addWindow( + core::rect(460,375,630,470), false, L"Use 'E' + 'R' to change"); + + ListBox = env->addListBox( + core::rect(2,22,165,88), window); + + ListBox->addItem(L"Diffuse"); + ListBox->addItem(L"Bump mapping"); + ListBox->addItem(L"Parallax mapping"); + ListBox->setSelected(1); + + // create problem text + ProblemText = env->addStaticText( + L"Your hardware or this renderer is not able to use the "\ + L"needed shaders for this material. Using fall back materials.", + core::rect(150,20,470,80)); + + ProblemText->setOverrideColor(video::SColor(100,255,255,255)); + + // set start material (prefer parallax mapping if available) + video::IMaterialRenderer* renderer = + Driver->getMaterialRenderer(video::EMT_PARALLAX_MAP_SOLID); + if (renderer && renderer->getRenderCapability() == 0) + ListBox->setSelected(2); + + // set the material which is selected in the listbox + setMaterial(); + } + + bool OnEvent(const SEvent& event) + { + // check if user presses the key 'E' or 'R' + if (event.EventType == irr::EET_KEY_INPUT_EVENT && + !event.KeyInput.PressedDown && Room && ListBox) + { + // change selected item in listbox + + int sel = ListBox->getSelected(); + if (event.KeyInput.Key == irr::KEY_KEY_R) + ++sel; + else + if (event.KeyInput.Key == irr::KEY_KEY_E) + --sel; + else + return false; + + if (sel > 2) sel = 0; + if (sel < 0) sel = 2; + ListBox->setSelected(sel); + + // set the material which is selected in the listbox + setMaterial(); + } + + return false; + } + +private: + + // sets the material of the room mesh the the one set in the + // list box. + void setMaterial() + { + video::E_MATERIAL_TYPE type = video::EMT_SOLID; + + // change material setting + switch(ListBox->getSelected()) + { + case 0: type = video::EMT_SOLID; + break; + case 1: type = video::EMT_NORMAL_MAP_SOLID; + break; + case 2: type = video::EMT_PARALLAX_MAP_SOLID; + break; + } + + Room->setMaterialType(type); + + // change material setting + switch(ListBox->getSelected()) + { + case 0: type = video::EMT_TRANSPARENT_VERTEX_ALPHA; + break; + case 1: type = video::EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA; + break; + case 2: type = video::EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA; + break; + } + + Earth->setMaterialType(type); + + /* + We need to add a warning if the materials will not be able to + be displayed 100% correctly. This is no problem, they will be + rendered using fall back materials, but at least the user + should know that it would look better on better hardware. We + simply check if the material renderer is able to draw at full + quality on the current hardware. The + IMaterialRenderer::getRenderCapability() returns 0 if this is + the case. + */ + video::IMaterialRenderer* renderer = Driver->getMaterialRenderer(type); + + // display some problem text when problem + if (!renderer || renderer->getRenderCapability() != 0) + ProblemText->setVisible(true); + else + ProblemText->setVisible(false); + } + +private: + + gui::IGUIStaticText* ProblemText; + gui::IGUIListBox* ListBox; + + scene::ISceneNode* Room; + scene::ISceneNode* Earth; + video::IVideoDriver* Driver; +}; + + +/* +Now for the real fun. We create an Irrlicht Device and start to setup the scene. +*/ +int main() +{ + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + // create device + + IrrlichtDevice* device = createDevice(driverType, + core::dimension2d(640, 480)); + + if (device == 0) + return 1; // could not create selected driver. + + /* + Before we start with the interesting stuff, we do some simple things: + Store pointers to the most important parts of the engine (video driver, + scene manager, gui environment) to safe us from typing too much, add an + irrlicht engine logo to the window and a user controlled first person + shooter style camera. Also, we let the engine know that it should store + all textures in 32 bit. This necessary because for parallax mapping, we + need 32 bit textures. + */ + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + gui::IGUIEnvironment* env = device->getGUIEnvironment(); + + driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true); + + const io::path mediaPath = getExampleMediaPath(); + + // add irrlicht logo + env->addImage(driver->getTexture(mediaPath + "irrlichtlogo3.png"), + core::position2d(10,10)); + + // add camera + scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(); + camera->setPosition(core::vector3df(-200,200,-200)); + + // disable mouse cursor + device->getCursorControl()->setVisible(false); + + /* + Because we want the whole scene to look a little bit scarier, we add + some fog to it. This is done by a call to IVideoDriver::setFog(). There + you can set various fog settings. In this example, we use pixel fog, + because it will work well with the materials we'll use in this example. + Please note that you will have to set the material flag EMF_FOG_ENABLE + to 'true' in every scene node which should be affected by this fog. + */ + driver->setFog(video::SColor(0,138,125,81), video::EFT_FOG_LINEAR, 250, 1000, .003f, true, false); + + /* + To be able to display something interesting, we load a mesh from a .3ds + file which is a room I modeled with anim8or. It is the same room as + from the specialFX example. Maybe you remember from that tutorial, I am + no good modeler at all and so I totally messed up the texture mapping + in this model, but we can simply repair it with the + IMeshManipulator::makePlanarTextureMapping() method. + */ + + scene::IAnimatedMesh* roomMesh = smgr->getMesh(mediaPath + "room.3ds"); + scene::ISceneNode* room = 0; + scene::ISceneNode* earth = 0; + + if (roomMesh) + { + // The room mesh doesn't have proper texture mapping on the + // floor, so we can recreate the mapping on runtime. + smgr->getMeshManipulator()->makePlanarTextureMapping( + roomMesh->getMesh(0), 0.003f); + + /* + Now for the first exciting thing: If we successfully loaded the + mesh we need to apply textures to it. Because we want this room + to be displayed with a very cool material, we have to do a + little bit more than just set the textures. Instead of only + loading a color map as usual, we also load a height map which + is simply a grayscale texture. From this height map, we create + a normal map which we will set as second texture of the room. + If you already have a normal map, you could directly set it, + but I simply didn't find a nice normal map for this texture. + The normal map texture is being generated by the + makeNormalMapTexture method of the VideoDriver. The second + parameter specifies the height of the heightmap. If you set it + to a bigger value, the map will look more rocky. + */ + + video::ITexture* normalMap = + driver->getTexture(mediaPath + "rockwall_height.bmp"); + + if (normalMap) + driver->makeNormalMapTexture(normalMap, 9.0f); + + /* + But just setting color and normal map is not everything. The + material we want to use needs some additional information per + vertex like tangents and binormals. Because we are too lazy to + calculate that information now, we let Irrlicht do this for us. + That's why we call IMeshManipulator::createMeshWithTangents(). + It creates a mesh copy with tangents and binormals from another + mesh. After we've done that, we simply create a standard + mesh scene node with this mesh copy, set color and normal map + and adjust some other material settings. Note that we set + EMF_FOG_ENABLE to true to enable fog in the room. + */ + + scene::IMesh* tangentMesh = smgr->getMeshManipulator()-> + createMeshWithTangents(roomMesh->getMesh(0)); + + room = smgr->addMeshSceneNode(tangentMesh); + room->setMaterialTexture(0, + driver->getTexture(mediaPath + "rockwall.jpg")); + room->setMaterialTexture(1, normalMap); + + // Stones don't glitter.. + room->getMaterial(0).SpecularColor.set(0,0,0,0); + room->getMaterial(0).Shininess = 0.f; + + room->setMaterialFlag(video::EMF_FOG_ENABLE, true); + room->setMaterialType(video::EMT_PARALLAX_MAP_SOLID); + // adjust height for parallax effect + room->getMaterial(0).MaterialTypeParam = 1.f / 64.f; + + // drop mesh because we created it with a create.. call. + tangentMesh->drop(); + } + + /* + After we've created a room shaded by per pixel lighting, we add a + sphere into it with the same material, but we'll make it transparent. + In addition, because the sphere looks somehow like a familiar planet, + we make it rotate. The procedure is similar as before. The difference + is that we are loading the mesh from an .x file which already contains + a color map so we do not need to load it manually. But the sphere is a + little bit too small for our needs, so we scale it by the factor 50. + */ + + // add earth sphere + + scene::IAnimatedMesh* earthMesh = smgr->getMesh(mediaPath + "earth.x"); + if (earthMesh) + { + //perform various tasks with the mesh manipulator + scene::IMeshManipulator *manipulator = smgr->getMeshManipulator(); + + // create mesh copy with tangent information from original earth.x mesh + scene::IMesh* tangentSphereMesh = + manipulator->createMeshWithTangents(earthMesh->getMesh(0)); + + // set the alpha value of all vertices to 200 + manipulator->setVertexColorAlpha(tangentSphereMesh, 200); + + // scale the mesh by factor 50 + core::matrix4 m; + m.setScale ( core::vector3df(50,50,50) ); + manipulator->transform( tangentSphereMesh, m ); + + earth = smgr->addMeshSceneNode(tangentSphereMesh); + + earth->setPosition(core::vector3df(-70,130,45)); + + // load heightmap, create normal map from it and set it + video::ITexture* earthNormalMap = driver->getTexture(mediaPath + "earthbump.jpg"); + if (earthNormalMap) + { + driver->makeNormalMapTexture(earthNormalMap, 20.0f); + earth->setMaterialTexture(1, earthNormalMap); + earth->setMaterialType(video::EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA); + } + + // adjust material settings + earth->setMaterialFlag(video::EMF_FOG_ENABLE, true); + + // add rotation animator + scene::ISceneNodeAnimator* anim = + smgr->createRotationAnimator(core::vector3df(0,0.1f,0)); + earth->addAnimator(anim); + anim->drop(); + + // drop mesh because we created it with a create.. call. + tangentSphereMesh->drop(); + } + + /* + Per pixel lighted materials only look cool when there are moving + lights. So we add some. And because moving lights alone are so boring, + we add billboards to them, and a whole particle system to one of them. + We start with the first light which is red and has only the billboard + attached. + */ + + // add light 1 (more green) + scene::ILightSceneNode* light1 = + smgr->addLightSceneNode(0, core::vector3df(0,0,0), + video::SColorf(0.5f, 1.0f, 0.5f, 0.0f), 800.0f); + + // add fly circle animator to light 1 + scene::ISceneNodeAnimator* anim = + smgr->createFlyCircleAnimator (core::vector3df(50,300,0),190.0f, -0.003f); + light1->addAnimator(anim); + anim->drop(); + + // attach billboard to the light + scene::IBillboardSceneNode* bill = + smgr->addBillboardSceneNode(light1, core::dimension2d(60, 60)); + + bill->setMaterialFlag(video::EMF_LIGHTING, false); + bill->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false); + bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); + bill->setMaterialTexture(0, driver->getTexture(mediaPath + "particlegreen.jpg")); + + /* + Now the same again, with the second light. The difference is that we + add a particle system to it too. And because the light moves, the + particles of the particle system will follow. If you want to know more + about how particle systems are created in Irrlicht, take a look at the + SpecialFX example. Maybe you will have noticed that we only add 2 + lights, this has a simple reason: The low end version of this material + was written in ps1.1 and vs1.1, which doesn't allow more lights. You + could add a third light to the scene, but it won't be used to shade the + walls. But of course, this will change in future versions of Irrlicht + where higher versions of pixel/vertex shaders will be implemented too. + */ + + // add light 2 (red) + scene::ISceneNode* light2 = + smgr->addLightSceneNode(0, core::vector3df(0,0,0), + video::SColorf(1.0f, 0.2f, 0.2f, 0.0f), 800.0f); + + // add fly circle animator to light 2 + anim = smgr->createFlyCircleAnimator(core::vector3df(0,150,0), 200.0f, + 0.001f, core::vector3df(0.2f, 0.9f, 0.f)); + light2->addAnimator(anim); + anim->drop(); + + // attach billboard to light + bill = smgr->addBillboardSceneNode(light2, core::dimension2d(120, 120)); + bill->setMaterialFlag(video::EMF_LIGHTING, false); + bill->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false); + bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); + bill->setMaterialTexture(0, driver->getTexture(mediaPath + "particlered.bmp")); + + // add particle system + scene::IParticleSystemSceneNode* ps = + smgr->addParticleSystemSceneNode(false, light2); + + // create and set emitter + scene::IParticleEmitter* em = ps->createBoxEmitter( + core::aabbox3d(-3,0,-3,3,1,3), + core::vector3df(0.0f,0.03f,0.0f), + 80,100, + video::SColor(10,255,255,255), video::SColor(10,255,255,255), + 400,1100); + em->setMinStartSize(core::dimension2d(30.0f, 40.0f)); + em->setMaxStartSize(core::dimension2d(30.0f, 40.0f)); + + ps->setEmitter(em); + em->drop(); + + // create and set affector + scene::IParticleAffector* paf = ps->createFadeOutParticleAffector(); + ps->addAffector(paf); + paf->drop(); + + // adjust some material settings + ps->setMaterialFlag(video::EMF_LIGHTING, false); + ps->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false); + ps->setMaterialTexture(0, driver->getTexture(mediaPath + "fireball.bmp")); + ps->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); + + MyEventReceiver receiver(room, earth, env, driver); + device->setEventReceiver(&receiver); + + /* + Finally, draw everything. That's it. + */ + + int lastFPS = -1; + + while(device->run()) + if (device->isWindowActive()) + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0)); + + smgr->drawAll(); + env->drawAll(); + + driver->endScene(); + + int fps = driver->getFPS(); + + if (lastFPS != fps) + { + core::stringw str = L"Per pixel lighting example - Irrlicht Engine ["; + str += driver->getName(); + str += "] FPS:"; + str += fps; + + device->setWindowCaption(str.c_str()); + lastFPS = fps; + } + } + + device->drop(); + + return 0; +} + +/* +**/ diff --git a/examples/11.PerPixelLighting/tutorial.html b/examples/11.PerPixelLighting/tutorial.html new file mode 100644 index 00000000..89e87bd8 --- /dev/null +++ b/examples/11.PerPixelLighting/tutorial.html @@ -0,0 +1,502 @@ + + +Irrlicht Engine Tutorial + + + + +
+ + + + + + + + +
+
+
Tutorial 11. Per pixel lighting
+
+
+
+

This tutorial shows how to use one of the built in more complex materials + in irrlicht: Per pixel lighted surfaces using normal maps and parallax + mapping. It will also show how to use fog and moving particle systems. + And don't panic: You dont need any experience with shaders to use these + materials in Irrlicht.

+

The program which is described here will look like this:

+


+

+
+
+
+ + + + + + + +
Lets start!
+
+

At first, we need to include all headers and do the stuff we always + do, like in nearly all other tutorials.

+ + + + +
#include <irrlicht.h>
#include <iostream>

using namespace irr;

#pragma comment(lib, "Irrlicht.lib")
+

For this example, we need an event receiver, to make it possible + for the user to switch between the three available material types. + In addition, the event receiver will create some small GUI window + which displays what material is currently being used. There is nothing + special done in this class, so maybe you want to skip reading it.

+ + + + +
class MyEventReceiver : public IEventReceiver
+{
+public:
+
+	MyEventReceiver(scene::ISceneNode* room, 
+		gui::IGUIEnvironment* env, video::IVideoDriver* driver)
+	{
+		// store pointer to room so we can change its drawing mode
+		Room = room;
+		Driver = driver;
+
+		// set a nicer font
+		gui::IGUISkin* skin = env->getSkin();
+		gui::IGUIFont* font = env->getFont("../../media/fonthaettenschweiler.bmp");
+		if (font)
+			skin->setFont(font);
+
+		// add window and listbox
+		gui::IGUIWindow* window = env->addWindow(
+			core::rect(490,390,630,470), false, L"Use 'E' + 'R' to change");
+
+		ListBox = env->addListBox(
+			core::rect(2,22,135,78), window);
+
+		ListBox->addItem(L"Diffuse");
+		ListBox->addItem(L"Bump mapping");
+		ListBox->addItem(L"Parallax mapping");
+		ListBox->setSelected(1);
+
+		// create problem text
+		ProblemText = env->addStaticText(
+			L"Your hardware or this renderer is not able to use the "\
+			L"needed shaders for this material. Using fall back materials.",
+			core::rect(150,20,470,60));
+
+		ProblemText->setOverrideColor(video::SColor(100,255,255,255));
+
+		// set start material (prefer parallax mapping if available)
+		video::IMaterialRenderer* renderer = 
+			Driver->getMaterialRenderer(video::EMT_PARALLAX_MAP_SOLID);
+		if (renderer && renderer->getRenderCapability() == 0)
+			ListBox->setSelected(2);
+
+		// set the material which is selected in the listbox
+		setMaterial();
+	}
+
+	bool OnEvent(const SEvent& event)
+	{
+		// check if user presses the key 'E' or 'R'
+		if (event.EventType == irr::EET_KEY_INPUT_EVENT &&
+			!event.KeyInput.PressedDown && Room && ListBox)
+		{
+			// change selected item in listbox 
+
+			int sel = ListBox->getSelected();
+			if (event.KeyInput.Key == irr::KEY_KEY_R)
+				++sel;
+			else
+			if (event.KeyInput.Key == irr::KEY_KEY_E)
+				--sel;
+			else 
+				return false;
+
+			if (sel > 2) sel = 0;
+			if (sel < 0) sel = 2;
+			ListBox->setSelected(sel);
+			
+			// set the material which is selected in the listbox
+			setMaterial();
+		}
+
+		return false;
+	}
+
+private:
+
+	// sets the material of the room mesh the the one set in the 
+	// list box.
+	void setMaterial()
+	{
+		video::E_MATERIAL_TYPE type = video::EMT_SOLID;
+
+		// change material setting
+		switch(ListBox->getSelected())
+		{
+		case 0: type = video::EMT_SOLID;
+			break;
+		case 1: type = video::EMT_NORMAL_MAP_SOLID;
+			break;
+		case 2: type = video::EMT_PARALLAX_MAP_SOLID;
+			break;
+		}
+
+		Room->setMaterialType(type);
+
+

We need to add a warning if the materials will not be able to be + displayed 100% correctly. This is no problem, they will be renderered + using fall back materials, but at least the user should know that + it would look better on better hardware. We simply check if the material + renderer is able to draw at full quality on the current hardware. + The IMaterialRenderer::getRenderCapability() returns 0 if this is + the case.
+

+ + + + +
video::IMaterialRenderer* renderer = Driver->getMaterialRenderer(type);
+
+		// display some problem text when problem
+		if (!renderer || renderer->getRenderCapability() != 0)
+			ProblemText->setVisible(true);
+		else
+			ProblemText->setVisible(false);
+	}
+
+private:
+
+	gui::IGUIStaticText* ProblemText;
+	gui::IGUIListBox* ListBox;
+
+	scene::ISceneNode* Room;	
+	video::IVideoDriver* Driver;
+};
+


+ Now for the real fun. We create an Irrlicht Device and start to setup + the scene.
+

+ + + + +
int main()
+{
+	// let user select driver type
+
+	video::E_DRIVER_TYPE driverType = video::EDT_DIRECT3D9;
+
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) Apfelbaum Software Renderer\n"\
" (f) NullDevice\n (otherKey) exit\n\n");
+ char i; + std::cin >> i; + + switch(i)
{
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;
default: return 0;
} + + // create device + + IrrlichtDevice* device = createDevice(driverType, core::dimension2d(640, 480)); + + if (device == 0) + return 1; // could not create selected driver. +
+
+ Before we start with the interesting stuff, we do some simple things: + Store pointers to the most important parts of the engine (video driver,
+ scene manager, gui environment) to safe us from typing too much, add + an irrlicht engine logo to the window and a user controlled first person + shooter style camera. Also, we let the engine now that it should store + all textures in 32 bit. This necessary because for parallax mapping, + we need 32 bit textures.
+
+ + + + +
+	video::IVideoDriver* driver = device->getVideoDriver();
+	scene::ISceneManager* smgr = device->getSceneManager();
+	gui::IGUIEnvironment* env = device->getGUIEnvironment();
+
+	driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true);
+
+	// add irrlicht logo
+	env->addImage(driver->getTexture("../../media/irrlichtlogoalpha.tga"),
+		core::position2d(10,10));
+		
+	// add camera
+	scene::ICameraSceneNode* camera = 
+		smgr->addCameraSceneNodeFPS(0,100.0f,300.0f);
+	camera->setPosition(core::vector3df(-200,200,-200));
+
+	// disable mouse cursor
+	device->getCursorControl()->setVisible(false);
+
+ Because we want the whole scene to look a little bit scarier, we add + some fog to it. This is done by a call to IVideoDriver::setFog(). There + you can set
+ various fog settings. In this example, we use pixel fog, because it + will work well with the materials we'll use in this example. Please + note that you will have to set the material flag EMF_FOG_ENABLE to 'true' + in every scene node which should be affected by this fog.
+
+ + + + +
driver->setFog(video::SColor(0,138,125,81), true, 250, 1000, 0, true);
+
+ To be able to display something interesting, we load a mesh from a .3ds + file which is a room I modeled with anim8or. It is the same room as +
+ from the specialFX example. Maybe you remember from that tutorial, I + am no good modeler at all and so I totally messed up the texture mapping + in this model, but we can simply repair it with the IMeshManipulator::makePlanarTextureMapping() + method.
+
+ + + + +
	scene::IAnimatedMesh* roomMesh = smgr->getMesh(
+		"../../media/room.3ds");
+	scene::ISceneNode* room = 0;
+
+	if (roomMesh)
+	{
+		smgr->getMeshManipulator()->makePlanarTextureMapping(
+				roomMesh->getMesh(0), 0.003f);
+
+ Now for the first exciting thing: If we successfully loaded the mesh + we need to apply textures to it. Because we want this room to be displayed + with a very cool material, we have to do a little bit more than just + set the textures. Instead of only loading a color map as usual, we also + load a height map which is simply a grayscale texture. From this height + map, we create a normal map which we will set as second texture of the + room. If you already have a normal map, you could directly set it, but + I simply didn´t find a nice normal map for this texture. The normal + map texture is being generated by the makeNormalMapTexture method
+ of the VideoDriver. The second parameter specifies the height of the + heightmap. If you set it to a bigger value, the map will look more rocky.
+
+ + + + +
		video::ITexture* colorMap = driver->getTexture("../../media/rockwall.bmp");
+		video::ITexture* normalMap = driver->getTexture("../../media/rockwall_height.bmp");
+		
+		driver->makeNormalMapTexture(normalMap, 9.0f);
+
+ But just setting color and normal map is not everything. The material + we want to use needs some additional informations per vertex like tangents + and binormals.
+ Because we are too lazy to calculate that information now, we let Irrlicht + do this for us. That's why we call IMeshManipulator::createMeshWithTangents(). + It
+ creates a mesh copy with tangents and binormals from any other mesh. + After we've done that, we simply create a standard mesh scene node with + this
+ mesh copy, set color and normal map and adjust some other material settings. + Note that we set EMF_FOG_ENABLE to true to enable fog in the room.
+
+ + + + +
scene::IMesh* tangentMesh = smgr->getMeshManipulator()->createMeshWithTangents(
roomMesh->getMesh(0));

room = smgr->addMeshSceneNode(tangentMesh);
room->setMaterialTexture(0, colorMap);
room->setMaterialTexture(1, normalMap);
room->getMaterial(0).SpecularColor.set(0,0,0,0);
room->setMaterialFlag(video::EMF_FOG_ENABLE, true);
room->setMaterialType(video::EMT_PARALLAX_MAP_SOLID);
room->getMaterial(0).MaterialTypeParam = 0.02f; // adjust height for parallax effect
// drop mesh because we created it with a create.. call.
tangentMesh->drop();
}
+
+ After we've created a room shaded by per pixel lighting, we add a sphere + into it with the same material, but we'll make it transparent. In addition,
+ because the sphere looks somehow like a familiar planet, we make it + rotate. The procedure is similar as before. The difference is that we + are loading
+ the mesh from an .x file which already contains a color map so we do + not need to load it manually. But the sphere is a little bit too small + for our needs, so we scale it by the factor 50.
+
+ + + + +
// add earth sphere
+
+	scene::IAnimatedMesh* earthMesh = smgr->getMesh("../../media/earth.x");
+	if (earthMesh)
+	{
+		// create mesh copy with tangent informations from original earth.x mesh
+		scene::IMesh* tangentSphereMesh = 
+			smgr->getMeshManipulator()->createMeshWithTangents(earthMesh->getMesh(0));
+
+		// set the alpha value of all vertices to 200
+		smgr->getMeshManipulator()->setVertexColorAlpha(tangentSphereMesh, 200);
+		
+		// scale the mesh by factor 50
+		smgr->getMeshManipulator()->scaleMesh(
+			tangentSphereMesh, core::vector3df(50,50,50));
+
+		// create mesh scene node
+		scene::ISceneNode* sphere = smgr->addMeshSceneNode(tangentSphereMesh);
+		sphere->setPosition(core::vector3df(-70,130,45));
+
+		// load heightmap, create normal map from it and set it
+		video::ITexture* earthNormalMap = driver->getTexture("../../media/earthbump.bmp");
+		driver->makeNormalMapTexture(earthNormalMap, 20.0f);
+		sphere->setMaterialTexture(1, earthNormalMap);
+
+		// adjust material settings
+		sphere->setMaterialFlag(video::EMF_FOG_ENABLE, true);
+		sphere->setMaterialType(video::EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA); 
+
+		// add rotation animator
+		scene::ISceneNodeAnimator* anim =
+			smgr->createRotationAnimator(core::vector3df(0,0.1f,0));	
+		sphere->addAnimator(anim);
+		anim->drop();
+
+		// drop mesh because we created it with a create.. call.
+		tangentSphereMesh->drop();
+	}
+
+ Per pixel lighted materials only look cool when there are moving lights. + So we add some. And because moving lights alone are so boring, we add + billboards
+ to them, and a whole particle system to one of them. We start with the + first light which is red and has only the billboard attached.
+
+ + + + +
// add light 1 (nearly red)
+	scene::ILightSceneNode* light1 = 
+		smgr->addLightSceneNode(0, core::vector3df(0,0,0), 
+		video::SColorf(0.5f, 1.0f, 0.5f, 0.0f), 200.0f);
+
+	// add fly circle animator to light 1
+	scene::ISceneNodeAnimator* anim = 
+		smgr->createFlyCircleAnimator (core::vector3df(50,300,0),190.0f, -0.003f);
+	light1->addAnimator(anim);
+	anim->drop();
+
+	// attach billboard to the light
+	scene::ISceneNode* bill = 
+		smgr->addBillboardSceneNode(light1, core::dimension2d(60, 60));
+
+	bill->setMaterialFlag(video::EMF_LIGHTING, false);
+	bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
+	bill->setMaterialTexture(0, driver->getTexture("../../media/particlered.bmp"));
+
+ Now the same again, with the second light. The difference is that we + add a particle system to it too. And because the light moves, the particles + of the particlesystem will follow. If you want to know more about how + particle systems are created in Irrlicht, take a look at the specialFx + example.
+ Maybe you will have noticed that we only add 2 lights, this has a simple + reason: The low end version of this material was written in ps1.1 and + vs1.1, which doesn't allow more lights. You could add a third light + to the scene, but it won't be used to shade the walls. But of course, + this will change in future versions of Irrlicht were higher versions + of pixel/vertex shaders will be implemented too.
+
+ + + + +
// add light 2 (gray)
+	scene::ISceneNode* light2 = 
+		smgr->addLightSceneNode(0, core::vector3df(0,0,0), 
+		video::SColorf(1.0f, 0.2f, 0.2f, 0.0f), 200.0f);
+
+	// add fly circle animator to light 2
+	anim = smgr->createFlyCircleAnimator (core::vector3df(0,150,0),200.0f); 
+	light2->addAnimator(anim);
+	anim->drop();
+
+	// attach billboard to light
+	bill = smgr->addBillboardSceneNode(light2, core::dimension2d(120, 120));
+	bill->setMaterialFlag(video::EMF_LIGHTING, false);
+	bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
+	bill->setMaterialTexture(0, driver->getTexture("../../media/particlewhite.bmp"));
+
+	// add particle system
+	scene::IParticleSystemSceneNode* ps = 
+		smgr->addParticleSystemSceneNode(false, light2);
+
+	ps->setParticleSize(core::dimension2d(30.0f, 40.0f));
+
+	// create and set emitter
+	scene::IParticleEmitter* em = ps->createBoxEmitter(
+		core::aabbox3d(-3,0,-3,3,1,3), 
+		core::vector3df(0.0f,0.03f,0.0f),
+		80,100, 
+		video::SColor(0,255,255,255), video::SColor(0,255,255,255),
+		400,1100);
+	ps->setEmitter(em);
+	em->drop();
+
+	// create and set affector
+	scene::IParticleAffector* paf = ps->createFadeOutParticleAffector();
+	ps->addAffector(paf);
+	paf->drop();
+
+	// adjust some material settings
+	ps->setMaterialFlag(video::EMF_LIGHTING, false);
+	ps->setMaterialTexture(0, driver->getTexture("../../media/fireball.bmp"));
+	ps->setMaterialType(video::EMT_TRANSPARENT_VERTEX_ALPHA);
+
+
+	MyEventReceiver receiver(room, env, driver);
+	device->setEventReceiver(&receiver);
+
+ Finally, draw everything. That's it.
+
+ + + + +
int lastFPS = -1;
+
+	while(device->run())
+	if (device->isWindowActive())
+	{
+		driver->beginScene(true, true, 0);
+
+		smgr->drawAll();
+		env->drawAll();
+
+		driver->endScene();
+
+		int fps = driver->getFPS();
+
+		if (lastFPS != fps)
+		{
+		  core::stringw str = L"Per pixel lighting example - Irrlicht Engine [";
+		  str += driver->getName();
+		  str += "] FPS:";
+		  str += fps;
+
+		  device->setWindowCaption(str.c_str());
+		  lastFPS = fps;
+		}
+	}
+
+	device->drop();
+	
+	return 0;
+}
+
+
+
+
+
+

 

+ + diff --git a/examples/12.TerrainRendering/Makefile b/examples/12.TerrainRendering/Makefile new file mode 100644 index 00000000..362bf06e --- /dev/null +++ b/examples/12.TerrainRendering/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 12.TerrainRendering +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/12.TerrainRendering/TerrainRendering.cbp b/examples/12.TerrainRendering/TerrainRendering.cbp new file mode 100644 index 00000000..2bf6dead --- /dev/null +++ b/examples/12.TerrainRendering/TerrainRendering.cbp @@ -0,0 +1,56 @@ + + + + + + diff --git a/examples/12.TerrainRendering/TerrainRendering.vcproj b/examples/12.TerrainRendering/TerrainRendering.vcproj new file mode 100644 index 00000000..22005623 --- /dev/null +++ b/examples/12.TerrainRendering/TerrainRendering.vcproj @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/12.TerrainRendering/TerrainRendering.xcodeproj/project.pbxproj b/examples/12.TerrainRendering/TerrainRendering.xcodeproj/project.pbxproj new file mode 100644 index 00000000..63b8efe1 --- /dev/null +++ b/examples/12.TerrainRendering/TerrainRendering.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 12.TerrainRendering.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 12.TerrainRendering.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 12.TerrainRendering.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 12.TerrainRendering */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "12.TerrainRendering" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 12.TerrainRendering; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 12.TerrainRendering.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "TerrainRendering" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 12.TerrainRendering */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "TerrainRendering" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "12.TerrainRendering" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/12.TerrainRendering/TerrainRendering.xcodeproj/xcshareddata/xcschemes/12.TerrainRendering.xcscheme b/examples/12.TerrainRendering/TerrainRendering.xcodeproj/xcshareddata/xcschemes/12.TerrainRendering.xcscheme new file mode 100644 index 00000000..13efddb9 --- /dev/null +++ b/examples/12.TerrainRendering/TerrainRendering.xcodeproj/xcshareddata/xcschemes/12.TerrainRendering.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/12.TerrainRendering/TerrainRendering_vc10.vcxproj b/examples/12.TerrainRendering/TerrainRendering_vc10.vcxproj new file mode 100644 index 00000000..22bd8b6d --- /dev/null +++ b/examples/12.TerrainRendering/TerrainRendering_vc10.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 12.TerrainRendering + {3A5B74E5-6390-43B0-A459-2793B81FFD31} + TerrainRendering + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/TerrainRendering.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\12.TerrainRendering.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/TerrainRendering.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\12.TerrainRendering.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/TerrainRendering.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\12.TerrainRendering.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/TerrainRendering.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\12.TerrainRendering.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/12.TerrainRendering/TerrainRendering_vc11.vcxproj b/examples/12.TerrainRendering/TerrainRendering_vc11.vcxproj new file mode 100644 index 00000000..22bd8b6d --- /dev/null +++ b/examples/12.TerrainRendering/TerrainRendering_vc11.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 12.TerrainRendering + {3A5B74E5-6390-43B0-A459-2793B81FFD31} + TerrainRendering + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/TerrainRendering.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\12.TerrainRendering.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/TerrainRendering.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\12.TerrainRendering.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/TerrainRendering.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\12.TerrainRendering.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/TerrainRendering.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\12.TerrainRendering.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/12.TerrainRendering/TerrainRendering_vc12.vcxproj b/examples/12.TerrainRendering/TerrainRendering_vc12.vcxproj new file mode 100644 index 00000000..4fb6b9b8 --- /dev/null +++ b/examples/12.TerrainRendering/TerrainRendering_vc12.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 12.TerrainRendering + {3A5B74E5-6390-43B0-A459-2793B81FFD31} + TerrainRendering + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/TerrainRendering.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\12.TerrainRendering.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/TerrainRendering.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\12.TerrainRendering.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/TerrainRendering.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\12.TerrainRendering.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/TerrainRendering.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\12.TerrainRendering.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/12.TerrainRendering/TerrainRendering_vc14.vcxproj b/examples/12.TerrainRendering/TerrainRendering_vc14.vcxproj new file mode 100644 index 00000000..bf067fa2 --- /dev/null +++ b/examples/12.TerrainRendering/TerrainRendering_vc14.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 12.TerrainRendering + {3A5B74E5-6390-43B0-A459-2793B81FFD31} + TerrainRendering + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/TerrainRendering.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\12.TerrainRendering.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/TerrainRendering.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\12.TerrainRendering.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/TerrainRendering.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\12.TerrainRendering.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/TerrainRendering.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\12.TerrainRendering.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/12.TerrainRendering/main.cpp b/examples/12.TerrainRendering/main.cpp new file mode 100644 index 00000000..7c38598e --- /dev/null +++ b/examples/12.TerrainRendering/main.cpp @@ -0,0 +1,286 @@ +/** Example 012 Terrain Rendering + +This tutorial will briefly show how to use the terrain renderer of Irrlicht. It +will also show the terrain renderer triangle selector to be able to do +collision detection with terrain. + +Note that the Terrain Renderer in Irrlicht is based on Spintz' +GeoMipMapSceneNode, lots of thanks go to him. DeusXL provided a new elegant +simple solution for building larger area on small heightmaps -> terrain +smoothing. + +In the beginning there is nothing special. We include the needed header files +and create an event listener to listen if the user presses certain keys. +*/ +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +using namespace irr; + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + + +class MyEventReceiver : public IEventReceiver +{ +public: + + MyEventReceiver(scene::ISceneNode* terrain, scene::ISceneNode* skybox, scene::ISceneNode* skydome) : + Terrain(terrain), Skybox(skybox), Skydome(skydome), showBox(true), showDebug(false) + { + Skybox->setVisible(showBox); + Skydome->setVisible(!showBox); + } + + bool OnEvent(const SEvent& event) + { + // check if user presses the key 'W' or 'D' + if (event.EventType == irr::EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown) + { + switch (event.KeyInput.Key) + { + case irr::KEY_KEY_W: // switch wire frame mode + Terrain->setMaterialFlag(video::EMF_WIREFRAME, + !Terrain->getMaterial(0).Wireframe); + Terrain->setMaterialFlag(video::EMF_POINTCLOUD, false); + return true; + case irr::KEY_KEY_P: // switch point cloud mode + Terrain->setMaterialFlag(video::EMF_POINTCLOUD, + !Terrain->getMaterial(0).PointCloud); + Terrain->setMaterialFlag(video::EMF_WIREFRAME, false); + return true; + case irr::KEY_KEY_D: // toggle detail map + Terrain->setMaterialType( + 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; + case irr::KEY_KEY_X: // toggle debug information + showDebug=!showDebug; + Terrain->setDebugDataVisible(showDebug?scene::EDS_BBOX_ALL:scene::EDS_OFF); + return true; + default: + break; + } + } + + return false; + } + +private: + scene::ISceneNode* Terrain; + scene::ISceneNode* Skybox; + scene::ISceneNode* Skydome; + bool showBox; + bool showDebug; +}; + + +/* +The start of the main function starts like in most other example. We ask the +user for the desired renderer and start it up. This time with the advanced +parameter handling. +*/ +int main() +{ + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + // 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. + + + /* + First, we add standard stuff to the scene: A nice irrlicht engine + logo, a small help text, a user controlled camera, and we disable + the mouse cursor. + */ + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + gui::IGUIEnvironment* env = device->getGUIEnvironment(); + + driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true); + + const io::path mediaPath = getExampleMediaPath(); + + // add irrlicht logo + env->addImage(driver->getTexture(mediaPath + "irrlichtlogo2.png"), + core::position2d(10,10)); + + //set other font + env->getSkin()->setFont(env->getFont(mediaPath + "fontlucida.png")); + + // add some help text (let's ignore 'P' and 'X' which are more about debugging) + env->addStaticText( + 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 = + smgr->addCameraSceneNodeFPS(0,100.0f,1.2f); + + camera->setPosition(core::vector3df(2700*2,255*2,2600*2)); + camera->setTarget(core::vector3df(2397*2,343*2,2700*2)); + camera->setFarValue(42000.0f); + + // disable mouse cursor + device->getCursorControl()->setVisible(false); + + /* + Here comes the terrain renderer scene node: We add it just like any + other scene node to the scene using + ISceneManager::addTerrainSceneNode(). The first parameter is a + file name to the heightmap we use. A heightmap is simply a gray scale + texture. The terrain renderer loads it and creates the 3D terrain from + it. + + To make the terrain look bigger, we change it's scale factor to + (40, 4.4, 40). Because we don't have any dynamic lights in the + scene, we switch off the lighting, and we set the file + terrain-texture.jpg as texture for the terrain and detailmap3.jpg as + second texture, called detail map. At last, we set the scale values for + the texture: The first texture will be repeated only one time over the + whole terrain, and the second one (detail map) 20 times. + */ + + // add terrain scene node + scene::ITerrainSceneNode* terrain = smgr->addTerrainSceneNode( + mediaPath + "terrain-heightmap.bmp", + 0, // parent node + -1, // node id + core::vector3df(0.f, 0.f, 0.f), // position + core::vector3df(0.f, 0.f, 0.f), // rotation + core::vector3df(40.f, 4.4f, 40.f), // scale + video::SColor ( 255, 255, 255, 255 ), // vertexColor + 5, // maxLOD + scene::ETPS_17, // patchSize + 4 // smoothFactor + ); + + terrain->setMaterialFlag(video::EMF_LIGHTING, false); + + terrain->setMaterialTexture(0, + driver->getTexture(mediaPath + "terrain-texture.jpg")); + terrain->setMaterialTexture(1, + driver->getTexture(mediaPath + "detailmap3.jpg")); + + terrain->setMaterialType(video::EMT_DETAIL_MAP); + + terrain->scaleTexture(1.0f, 20.0f); + + /* + To be able to do collision with the terrain, we create a triangle selector. + If you want to know what triangle selectors do, just take a look into the + collision tutorial. The terrain triangle selector works together with the + terrain. To demonstrate this, we create a collision response animator + and attach it to the camera, so that the camera will not be able to fly + through the terrain. + */ + + // create triangle selector for the terrain + scene::ITriangleSelector* selector + = smgr->createTerrainTriangleSelector(terrain, 0); + terrain->setTriangleSelector(selector); + + // create collision response animator and attach it to the camera + scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator( + selector, camera, core::vector3df(60,100,60), + core::vector3df(0,0,0), + core::vector3df(0,50,0)); + selector->drop(); + camera->addAnimator(anim); + anim->drop(); + + /* If you need access to the terrain data you can also do this directly via the following code fragment. + */ + scene::CDynamicMeshBuffer* buffer = new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT); + terrain->getMeshBufferForLOD(*buffer, 0); + video::S3DVertex2TCoords* data = (video::S3DVertex2TCoords*)buffer->getVertexBuffer().getData(); + // Work on data or get the IndexBuffer with a similar call. + buffer->drop(); // When done drop the buffer again. + + /* + To make the user be able to switch between normal and wireframe mode, + we create an instance of the event receiver from above and let Irrlicht + know about it. In addition, we add the skybox which we already used in + lots of Irrlicht examples and a skydome, which is shown mutually + exclusive with the skybox by pressing 'S'. + */ + + // create skybox and skydome + driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); + + scene::ISceneNode* skybox=smgr->addSkyBoxSceneNode( + driver->getTexture(mediaPath + "irrlicht2_up.jpg"), + driver->getTexture(mediaPath + "irrlicht2_dn.jpg"), + driver->getTexture(mediaPath + "irrlicht2_lf.jpg"), + driver->getTexture(mediaPath + "irrlicht2_rt.jpg"), + driver->getTexture(mediaPath + "irrlicht2_ft.jpg"), + driver->getTexture(mediaPath + "irrlicht2_bk.jpg")); + scene::ISceneNode* skydome=smgr->addSkyDomeSceneNode(driver->getTexture(mediaPath + "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. + */ + + int lastFPS = -1; + + while(device->run()) + if (device->isWindowActive()) + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0)); + + smgr->drawAll(); + env->drawAll(); + + driver->endScene(); + + // display frames per second in window title + int fps = driver->getFPS(); + if (lastFPS != fps) + { + core::stringw str = L"Terrain Renderer - Irrlicht Engine ["; + str += driver->getName(); + str += "] FPS:"; + str += fps; + // Also print terrain height of current camera position + // We can use camera position because terrain is located at coordinate origin + str += " Height: "; + str += terrain->getHeight(camera->getAbsolutePosition().X, + camera->getAbsolutePosition().Z); + + device->setWindowCaption(str.c_str()); + lastFPS = fps; + } + } + + device->drop(); + + return 0; +} + +/* +Now you know how to use terrain in Irrlicht. +**/ diff --git a/examples/12.TerrainRendering/tutorial.html b/examples/12.TerrainRendering/tutorial.html new file mode 100644 index 00000000..f3d765f9 --- /dev/null +++ b/examples/12.TerrainRendering/tutorial.html @@ -0,0 +1,122 @@ + + +Irrlicht Engine Tutorial + + + + +
+ + + + + + + + +
+
+
Tutorial 12. Terrain Rendering
+
+
+
+

This tutorial will briefly show how to use the terrain renderer of + Irrlicht. It will also show the terrain renderer triangle selector to + be able to do collision detection with terrain.

+

The program which is described here will look like this:

+

+


+ Note that the terrain renderer in Irrlicht is based the terrain renderer + by Soconne and the GeoMipMapSceneNode developed by Spinz, lots of thanks + go to them.

+
+
+
+ + + + + + + +
Lets start!
+
+

In the beginning there is nothing special. We include the needed + header files and create an event listener to listen if the user presses + the 'W' key so we can switch to wireframe mode and if he presses 'D' + we toggle to material between solid and detail mapped.

+ + + + +
#include <irrlicht.h>
#include <iostream>
using namespace irr;

#pragma comment(lib, "Irrlicht.lib")

class MyEventReceiver : public IEventReceiver
{
public:
MyEventReceiver(scene::ISceneNode* terrain)
{
// store pointer to terrain so we can change its drawing mode
Terrain = terrain;
}

bool OnEvent(const SEvent& event)
{
// check if user presses the key 'W' or 'D'
if (event.EventType == irr::EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown)
{
switch (event.KeyInput.Key)
{
case irr::KEY_KEY_W: // switch wire frame mode
Terrain->setMaterialFlag(video::EMF_WIREFRAME, !Terrain->getMaterial(0).Wireframe);
return true;
case irr::KEY_KEY_D: // toggle detail map
Terrain->setMaterialType(
Terrain->getMaterial(0).MaterialType == video::EMT_SOLID ?
video::EMT_DETAIL_MAP : video::EMT_SOLID);
return true;
}
}
return false;
}

private:
scene::ISceneNode* Terrain;
};

+

The start of the main function starts like in most other example. + We ask the user for the desired renderer and start it up.

+ + + + +
int main()
{
// let user select driver type

video::E_DRIVER_TYPE driverType = video::EDT_DIRECT3D9;

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) Apfelbaum Software Renderer\n"\
" (f) NullDevice\n (otherKey) exit\n\n");

char i;
std::cin >> i;

switch(i)
{
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;
default: return 1;
}

// create device
IrrlichtDevice* device = createDevice(driverType, core::dimension2d<s32>(640, 480));

if (device == 0)
return 1; // could not create selected driver.
+

First, we add standard stuff to the scene: A nice irrlicht engine + logo, a small help text, a user controlled camera, and we disable + the mouse cursor.

+ + + + +
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
gui::IGUIEnvironment* env = device->getGUIEnvironment();

driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true);

// add irrlicht logo
env->addImage(driver->getTexture("../../media/irrlichtlogoalpha.tga"),
core::position2d<s32>(10,10));
+// add some help text
gui::IGUIStaticText* text = env->addStaticText(
L"Press 'W' to change wireframe mode\nPress 'D' to toggle detail map",
core::rect<s32>(10,453,200,475), true, true, 0, -1, true);
+// add camera
scene::ICameraSceneNode* camera =
smgr->addCameraSceneNodeFPS(0,100.0f,1200.0f);
camera->setPosition(core::vector3df(1900*2,255*2,3700*2));
camera->setTarget(core::vector3df(2397*2,343*2,2700*2));
camera->setFarValue(12000.0f);

// disable mouse cursor
device->getCursorControl()->setVisible(false);
+

Here comes the terrain renderer scene node: We add it just like + any other scene node to the scene using ISceneManager::addTerrainSceneNode(). + The only parameter we use is a file name to the heightmap we use. + A heightmap is simply a gray scale texture. The terrain renderer loads + it and creates the 3D terrain from it.
+ To make the terrain look more big, we change the scale factor of it + to (40, 4.4, 40). Because we don't have any dynamic lights in the + scene, we switch off the lighting, and we set the file terrain-texture.jpg + as texture for the terrain and detailmap3.jpg as second texture, called + detail map. At last, we set the scale values for the texture: The + first texture will be repeated only one time over the whole terrain, + and the second one (detail map) 20 times.

+ + + + +
// add terrain scene node
scene::ITerrainSceneNode* terrain = smgr->addTerrainSceneNode(
"../../media/terrain-heightmap.bmp");

terrain->setScale(core::vector3df(40, 4.4f, 40));
terrain->setMaterialFlag(video::EMF_LIGHTING, false);

terrain->setMaterialTexture(0, driver->getTexture("../../media/terrain-texture.jpg"));
terrain->setMaterialTexture(1, driver->getTexture("../../media/detailmap3.jpg"));

terrain->setMaterialType(video::EMT_DETAIL_MAP);
terrain->scaleTexture(1.0f, 20.0f);
+

To be able to do collision with the terrain, we create a triangle + selector. If you want to know what triangle selectors do, just take + a look into the collision tutorial. The terrain triangle selector + works together with the terrain. To demonstrate this, we create a + collision response animator and attach it to the camera, so that the + camera will not be able to fly through the terrain.

+
+ + + + +
// create triangle selector for the terrain	
scene::ITriangleSelector* selector =
smgr->createTerrainTriangleSelector(terrain, 0);
terrain->setTriangleSelector(selector);

// create collision response animator and attach it to the camera
scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator(
selector, camera, core::vector3df(60,100,60),
core::vector3df(0,0,0),
core::vector3df(0,50,0));
selector->drop();
camera->addAnimator(anim);
anim->drop();
+

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.

+ + + + +
// create event receiver
MyEventReceiver receiver(terrain);
device->setEventReceiver(&receiver);

// create skybox
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);

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"));
+driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);
+

That's it, draw everything. Now you know how to use terrain in Irrlicht.

+ + + + +
	int lastFPS = -1;

while(device->run())
if (device->isWindowActive())
{
driver->beginScene(true, true, 0 );

smgr->drawAll();
env->drawAll();

driver->endScene(); +
// display frames per second in window title + int fps = driver->getFPS();

if (lastFPS != fps)
{
core::stringw str = L"Terrain Renderer - Irrlicht Engine [";
str += driver->getName();
str += "] FPS:";
str += fps;
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
}

device->drop();

return 0;
}
+

 

+
+
+

 

+ + diff --git a/examples/13.RenderToTexture/Makefile b/examples/13.RenderToTexture/Makefile new file mode 100644 index 00000000..1022075a --- /dev/null +++ b/examples/13.RenderToTexture/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 13.RenderToTexture +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/13.RenderToTexture/RenderToTexture.cbp b/examples/13.RenderToTexture/RenderToTexture.cbp new file mode 100644 index 00000000..78c760b6 --- /dev/null +++ b/examples/13.RenderToTexture/RenderToTexture.cbp @@ -0,0 +1,55 @@ + + + + + + diff --git a/examples/13.RenderToTexture/RenderToTexture.vcproj b/examples/13.RenderToTexture/RenderToTexture.vcproj new file mode 100644 index 00000000..8fd8e6c2 --- /dev/null +++ b/examples/13.RenderToTexture/RenderToTexture.vcproj @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/13.RenderToTexture/RenderToTexture.xcodeproj/project.pbxproj b/examples/13.RenderToTexture/RenderToTexture.xcodeproj/project.pbxproj new file mode 100644 index 00000000..f2f6fb31 --- /dev/null +++ b/examples/13.RenderToTexture/RenderToTexture.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 13.RenderToTexture.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 13.RenderToTexture.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 13.RenderToTexture.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 13.RenderToTexture */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "13.RenderToTexture" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 13.RenderToTexture; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 13.RenderToTexture.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "RenderToTexture" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 13.RenderToTexture */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "RenderToTexture" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "13.RenderToTexture" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/13.RenderToTexture/RenderToTexture.xcodeproj/xcshareddata/xcschemes/13.RenderToTexture.xcscheme b/examples/13.RenderToTexture/RenderToTexture.xcodeproj/xcshareddata/xcschemes/13.RenderToTexture.xcscheme new file mode 100644 index 00000000..3c99c7ce --- /dev/null +++ b/examples/13.RenderToTexture/RenderToTexture.xcodeproj/xcshareddata/xcschemes/13.RenderToTexture.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/13.RenderToTexture/RenderToTexture_vc10.vcxproj b/examples/13.RenderToTexture/RenderToTexture_vc10.vcxproj new file mode 100644 index 00000000..b41b2772 --- /dev/null +++ b/examples/13.RenderToTexture/RenderToTexture_vc10.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 13.RenderToTexture + {0914E5C8-5352-467B-8421-C9EB35BD5596} + RenderToTexture + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/RenderToTexture.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\13.RenderToTexture.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/RenderToTexture.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\13.RenderToTexture.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Debug/RenderToTexture.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\13.RenderToTexture.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/RenderToTexture.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\13.RenderToTexture.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/13.RenderToTexture/RenderToTexture_vc11.vcxproj b/examples/13.RenderToTexture/RenderToTexture_vc11.vcxproj new file mode 100644 index 00000000..b41b2772 --- /dev/null +++ b/examples/13.RenderToTexture/RenderToTexture_vc11.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 13.RenderToTexture + {0914E5C8-5352-467B-8421-C9EB35BD5596} + RenderToTexture + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/RenderToTexture.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\13.RenderToTexture.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/RenderToTexture.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\13.RenderToTexture.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Debug/RenderToTexture.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\13.RenderToTexture.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/RenderToTexture.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\13.RenderToTexture.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/13.RenderToTexture/RenderToTexture_vc12.vcxproj b/examples/13.RenderToTexture/RenderToTexture_vc12.vcxproj new file mode 100644 index 00000000..5ede2aee --- /dev/null +++ b/examples/13.RenderToTexture/RenderToTexture_vc12.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 13.RenderToTexture + {0914E5C8-5352-467B-8421-C9EB35BD5596} + RenderToTexture + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/RenderToTexture.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\13.RenderToTexture.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/RenderToTexture.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\13.RenderToTexture.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Debug/RenderToTexture.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\13.RenderToTexture.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/RenderToTexture.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\13.RenderToTexture.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/13.RenderToTexture/RenderToTexture_vc14.vcxproj b/examples/13.RenderToTexture/RenderToTexture_vc14.vcxproj new file mode 100644 index 00000000..5316976e --- /dev/null +++ b/examples/13.RenderToTexture/RenderToTexture_vc14.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 13.RenderToTexture + {0914E5C8-5352-467B-8421-C9EB35BD5596} + RenderToTexture + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/RenderToTexture.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\13.RenderToTexture.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/RenderToTexture.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\13.RenderToTexture.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Debug/RenderToTexture.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\13.RenderToTexture.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/RenderToTexture.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\13.RenderToTexture.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/13.RenderToTexture/main.cpp b/examples/13.RenderToTexture/main.cpp new file mode 100644 index 00000000..99a18eac --- /dev/null +++ b/examples/13.RenderToTexture/main.cpp @@ -0,0 +1,229 @@ +/** Example 013 Render To Texture + +This tutorial shows how to render to a texture using Irrlicht. Render to +texture is a feature where everything which would usually be rendered to +the screen is instead written to a (special) texture. This can be used to +create nice special effects. +In addition, this tutorial shows how to enable specular highlights. + +In the beginning, everything as usual. Include the needed headers, ask the user +for the rendering driver, create the Irrlicht device: +*/ + +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +using namespace irr; + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +int main() +{ + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + // create device and exit if creation failed + + IrrlichtDevice *device = + createDevice(driverType, core::dimension2d(640, 480), + 16, false, false); + + if (device == 0) + return 1; // could not create selected driver. + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + gui::IGUIEnvironment* env = device->getGUIEnvironment(); + + const io::path mediaPath = getExampleMediaPath(); + + /* + Now, we load an animated mesh to be displayed. As in most examples, + we'll take the fairy md2 model. The difference here: We set the + shininess of the model to a value other than 0 which is the default + value. This enables specular highlights on the model if dynamic + lighting is on. The value influences the size of the highlights. + */ + + // load and display animated fairy mesh + + scene::IAnimatedMeshSceneNode* fairy = smgr->addAnimatedMeshSceneNode( + smgr->getMesh(mediaPath + "faerie.md2")); + + if (fairy) + { + fairy->setMaterialTexture(0, + driver->getTexture(mediaPath + "faerie2.bmp")); // set diffuse texture + fairy->setMaterialFlag(video::EMF_LIGHTING, true); // enable dynamic lighting + fairy->getMaterial(0).Shininess = 20.0f; // set size of specular highlights + fairy->setPosition(core::vector3df(-10,0,-100)); + fairy->setMD2Animation ( scene::EMAT_STAND ); + } + + /* + To make specular highlights appear on the model, we need a dynamic + light in the scene. We add one directly in vicinity of the model. In + addition, to make the model not that dark, we set the ambient light to + gray. + */ + + // add white light + smgr->addLightSceneNode(0, core::vector3df(-15,5,-105), + video::SColorf(1.0f, 1.0f, 1.0f)); + + // set ambient light + smgr->setAmbientLight(video::SColor(0,60,60,60)); + + /* + The next is just some standard stuff: Add a test cube and let it rotate + to make the scene more interesting. The user defined camera and cursor + setup is made later on, right before the render loop. + */ + + // create test cube + scene::ISceneNode* cube = smgr->addCubeSceneNode(60); + + // let the cube rotate and set some light settings + scene::ISceneNodeAnimator* anim = smgr->createRotationAnimator( + core::vector3df(0.3f, 0.3f,0)); + + cube->setPosition(core::vector3df(-100,0,-100)); + cube->setMaterialFlag(video::EMF_LIGHTING, false); // disable dynamic lighting + cube->addAnimator(anim); + anim->drop(); + + // set window caption + device->setWindowCaption(L"Irrlicht Engine - Render to Texture and Specular Highlights example"); + + /* + To test out the render to texture feature, we need to define our + new rendertarget. The rendertarget will need one texture to receive + the result you would otherwise see on screen and one texture + which is used as depth-buffer. + + (Note: If you worked with older Irrlicht versions (before 1.9) you might be + used to only create a rendertarget texture and no explicit rendertarget. While + that's still possible, it's no longer recommended.) + + The rendertarget textures are not like standard textures, but need to be created + first. To create them, we call IVideoDriver::addRenderTargetTexture() + and specify the size of the texture and the type. + For depth-maps you can use types ECF_D16, ECF_D32 or ECF_D24S8. When ECF_D24S8 + you can also use a stencil-buffer. + + Because we want to render the scene not from the user camera into the + texture, we add another fixed camera to the scene. But before we do all + this, we check if the current running driver is able to render to + textures. If it is not, we simply display a warning text. + */ + + // create render target + video::IRenderTarget* renderTarget = 0; + scene::ICameraSceneNode* fixedCam = 0; + + if (driver->queryFeature(video::EVDF_RENDER_TO_TARGET)) + { + const core::dimension2d rtDim(256, 256); // always use same size for render target texture and it's depth-buffer + video::ITexture* renderTargetTex = driver->addRenderTargetTexture(rtDim, "RTT1", video::ECF_A8R8G8B8); + video::ITexture* renderTargetDepth = driver->addRenderTargetTexture(rtDim, "DepthStencil", video::ECF_D16); + + renderTarget = driver->addRenderTarget(); + renderTarget->setTexture(renderTargetTex, renderTargetDepth); + + cube->setMaterialTexture(0, renderTargetTex); // set material of cube to render target + + // add fixed camera + fixedCam = smgr->addCameraSceneNode(0, core::vector3df(10,10,-80), + core::vector3df(-10,10,-100)); + } + else + { + // create problem text + gui::IGUISkin* skin = env->getSkin(); + gui::IGUIFont* font = env->getFont(mediaPath + "fonthaettenschweiler.bmp"); + if (font) + skin->setFont(font); + + gui::IGUIStaticText* text = env->addStaticText( + L"Your hardware or this renderer is not able to use the "\ + L"render to texture feature. RTT Disabled.", + core::rect(150,20,470,60)); + + text->setOverrideColor(video::SColor(100,255,255,255)); + } + + // add fps camera + scene::ICameraSceneNode* fpsCamera = smgr->addCameraSceneNodeFPS(); + fpsCamera->setPosition(core::vector3df(-50,50,-150)); + + // disable mouse cursor + device->getCursorControl()->setVisible(false); + + /* + Nearly finished. Now we need to draw everything. Every frame, we draw + the scene twice. Once from the fixed camera into the render target + texture and once as usual. When rendering into the render target, we + need to disable the visibility of the test cube, because it has the + render target texture applied to it. That's it, wasn't too complicated + I hope. :) + */ + + int lastFPS = -1; + + while(device->run()) + if (device->isWindowActive()) + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0)); + + if (renderTarget) + { + // draw scene into render target + + // set render target + driver->setRenderTargetEx(renderTarget, video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0,0,0,255)); + + // make cube invisible and set fixed camera as active camera + cube->setVisible(false); + smgr->setActiveCamera(fixedCam); + + // draw whole scene into render buffer + smgr->drawAll(); + + // set back old render target (the screen) + driver->setRenderTargetEx(0, 0); + + // make the cube visible and set the user controlled camera as active one + cube->setVisible(true); + smgr->setActiveCamera(fpsCamera); + } + + // draw scene normally + smgr->drawAll(); + env->drawAll(); + + driver->endScene(); + + // display frames per second in window title + int fps = driver->getFPS(); + if (lastFPS != fps) + { + core::stringw str = L"Irrlicht Engine - Render to Texture and Specular Highlights example"; + str += " FPS:"; + str += fps; + + device->setWindowCaption(str.c_str()); + lastFPS = fps; + } + } + + device->drop(); // drop device + return 0; +} + +/* +**/ diff --git a/examples/13.RenderToTexture/tutorial.html b/examples/13.RenderToTexture/tutorial.html new file mode 100644 index 00000000..26340a3e --- /dev/null +++ b/examples/13.RenderToTexture/tutorial.html @@ -0,0 +1,244 @@ + + +Irrlicht Engine Tutorial + + + + +
+ + + + + + + + +
+
+
Tutorial 13. Render to Texture
+
+
+
+

This tutorial shows how to render to a texture using Irrlicht. Render + to texture is a feature with which it is possible to create nice special + effects. In addition, this tutorial shows how to enable specular highlights.

+

The program which is described here will look like this:

+


+

+
+
+
+ + + + + + + +
Lets start!
+
+

In the beginning, everything as usual. Include the needed headers, + ask the user for the rendering driver, create the Irrlicht Device:

+ + + + +
#include <irrlicht.h>
+#include <iostream>
+
+using namespace irr;
+
+#pragma comment(lib, "Irrlicht.lib")
+
+int main()
+{
+	// let user select driver type
+
+	video::E_DRIVER_TYPE driverType = video::EDT_DIRECT3D9;
+
+	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) Apfelbaum Software Renderer\n"\
" (f) NullDevice\n (otherKey) exit\n\n"); + + char i; + std::cin >> i; + + switch(i)
{
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;
default: return 1;
} + + // create device and exit if creation failed + + IrrlichtDevice *device = + createDevice(driverType, core::dimension2d(640, 480), + 16, false, false); + + if (device == 0) + return 1; // could not create selected driver. + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + gui::IGUIEnvironment* env = device->getGUIEnvironment();
+

Now, we load an animated mesh to be displayed. As in most examples, + we'll take the fairy md2 model. The difference here: We set the shininess
+ of the model to a value other than 0 which is the default value. This + enables specular highlights on the model if dynamic lighting is on. + The value influences the size of the highlights.

+ + + + +
// load and display animated fairy mesh
+
+	scene::IAnimatedMeshSceneNode* fairy = smgr->addAnimatedMeshSceneNode(
+		smgr->getMesh("../../media/faerie.md2"));
+
+	if (fairy)
+	{
+		fairy->setMaterialTexture(0, driver->getTexture("../../media/faerie2.bmp")); // set diffuse texture
+		fairy->setMaterialFlag(video::EMF_LIGHTING, true); // enable dynamic lighting
+		fairy->getMaterial(0).Shininess = 20.0f; // set size of specular highlights
+		fairy->setPosition(core::vector3df(-10,0,-100));
+	}
+

To make specular highlights appear on the model, we need a dynamic + light in the scene. We add one directly in vicinity of the model. + In addition, to make the model not that dark, we set the ambient light + to gray.

+ + + + +
+	// add white light
+	scene::ILightSceneNode* light = smgr->addLightSceneNode(0,
+		core::vector3df(-15,5,-105), video::SColorf(1.0f, 1.0f, 1.0f));
+
+	// set ambient light
+	driver->setAmbientLight(video::SColor(0,60,60,60));
+

The next is just some standard stuff: Add a user controlled camera + to the scene, disable mouse cursor, and add a test cube and let it + rotate to make the scene more interesting.

+ + + + +
+	// add fps camera
+	scene::ICameraSceneNode* fpsCamera = smgr->addCameraSceneNodeFPS();
+	fpsCamera->setPosition(core::vector3df(-50,50,-150));
+
+	// disable mouse cursor
+	device->getCursorControl()->setVisible(false);
+
+	// create test cube
+	scene::ISceneNode* test = smgr->addCubeSceneNode(60);
+
+	// let the cube rotate and set some light settings
+	scene::ISceneNodeAnimator* anim = smgr->createRotationAnimator(
+		core::vector3df(0.3f, 0.3f,0));
+
+	test->setPosition(core::vector3df(-100,0,-100));
+	test->setMaterialFlag(video::EMF_LIGHTING, false); // disable dynamic lighting
+	test->addAnimator(anim);
+	anim->drop();
+
+	// set window caption
+	device->setWindowCaption(L"Irrlicht Engine - Render to Texture and Specular Highlights example");
+

To test out the render to texture feature, we need a render target + texture. These are not like standard textures, but need to be created + first. To create one, we call IVideoDriver::createRenderTargetTexture() + and specify the size of the texture. Please don't use sizes bigger + than the frame buffer for this, because the render target shares the + zbuffer with the frame buffer. And because we want to render the scene + not from the user camera into the texture, we add another, fixed camera + to the scene. But before we do all this, we check if the current running + driver is able to render to textures. If it is not, we simply display + a warning text.

+ + + + +
// create render target
+	video::ITexture* rt = 0;
+	scene::ICameraSceneNode* fixedCam = 0;
+	
+
+	if (driver->queryFeature(video::EVDF_RENDER_TO_TARGET))
+	{
+		rt = driver->createRenderTargetTexture(core::dimension2d(256,256));
+		test->setMaterialTexture(0, rt); // set material of cube to render target
+
+		// add fixed camera
+		fixedCam = smgr->addCameraSceneNode(0, core::vector3df(10,10,-80),
+			core::vector3df(-10,10,-100));
+	}
+	else
+	{
+		// create problem text
+		gui::IGUISkin* skin = env->getSkin();
+		gui::IGUIFont* font = env->getFont("../../media/fonthaettenschweiler.bmp");
+		if (font)
+			skin->setFont(font);
+
+		gui::IGUIStaticText* text = env->addStaticText(
+			L"Your hardware or this renderer is not able to use the "\
+			L"render to texture feature. RTT Disabled.",
+			core::rect(150,20,470,60));
+
+		text->setOverrideColor(video::SColor(100,255,255,255));
+	}
+

Nearly finished. Now we need to draw everything. Every frame, we + draw the scene twice. Once from the fixed camera into the render target + texture and once as usual. When rendering into the render target, + we need to disable the visibilty of the test cube, because it has + the render target texture applied to it.
+ That's, wasn't quite complicated I hope. :)

+ + + + +
while(device->run())
+	if (device->isWindowActive())
+	{
+		driver->beginScene(true, true, 0);
+
+		if (rt)
+		{
+			// draw scene into render target
+			
+			// set render target texture
+			driver->setRenderTarget(rt, true, true, video::SColor(0,0,0,255));     
+
+			// make cube invisible and set fixed camera as active camera
+			test->setVisible(false);
+			smgr->setActiveCamera(fixedCam);
+
+			// draw whole scene into render buffer
+			smgr->drawAll();                 
+
+			// set back old render target
+			driver->setRenderTarget(0);      
+
+			// make the cube visible and set the user controlled camera as active one
+			test->setVisible(true);
+			smgr->setActiveCamera(fpsCamera);
+		}
+		
+		// draw scene normally
+		smgr->drawAll(); 
+		env->drawAll();
+
+		driver->endScene();
+	}
+
+	if (rt)
+		rt->drop(); // drop render target because we created if with a create() method
+
+	device->drop(); // drop device
+	return 0;
+}
+
+ +

 

+
+
+

 

+ + diff --git a/examples/13.RenderToTexture_emscripten/Makefile b/examples/13.RenderToTexture_emscripten/Makefile new file mode 100644 index 00000000..81dcc442 --- /dev/null +++ b/examples/13.RenderToTexture_emscripten/Makefile @@ -0,0 +1,74 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 13.RenderToTexture +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +all_emscripten: EMSCRIPTEN=1 + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG + ifdef EMSCRIPTEN + LDFLAGS += -s DEMANGLE_SUPPORT=1 + endif + CXXFLAGS += -g -Wall +else + ifdef EMSCRIPTEN + LDFLAGS += -O3 + endif + CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_emscripten + +# target specific settings +all_linux all_emscripten all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_emscripten clean_emscripten: SYSTEM=emscripten +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +all_emscripten clean_emscripten: SUF=.html +all_emscripten: CXXFLAGS += -fno-exceptions -fno-rtti -fstrict-aliasing -std=gnu++11 -U__STRICT_ANSI__ +all_emscripten: LDFLAGS += -lGL -lSDL --preload-file ../../media@/media -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=1 +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 all_emscripten static_win32: + $(warning Building...) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(Sources) -o $(DESTPATH) $(LDFLAGS) + +clean: clean_linux clean_win32 clean_emscripten + $(warning Cleaning...) + +clean_linux clean_win32: + @$(RM) $(DESTPATH) + +clean_emscripten: + @$(RM) $(BinPath)/$(Target).data + @$(RM) $(BinPath)/$(Target).html* + @$(RM) $(BinPath)/$(Target).js + + +.PHONY: all all_win32 all_emscripten static_win32 clean clean_linux clean_win32 clean_emscripten + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/13.RenderToTexture_emscripten/main.cpp b/examples/13.RenderToTexture_emscripten/main.cpp new file mode 100644 index 00000000..f9916887 --- /dev/null +++ b/examples/13.RenderToTexture_emscripten/main.cpp @@ -0,0 +1,172 @@ +/** Example 013 Render To Texture on emscripten +*/ + +#include +#include +#include "exampleHelper.h" + +using namespace irr; + +IrrlichtDevice *device = 0; +video::IVideoDriver* driver = 0; +scene::ISceneManager* smgr = 0; +gui::IGUIEnvironment* guienv = 0; +scene::ICameraSceneNode* fpsCamera = 0; +scene::ICameraSceneNode* fixedCam = 0; +video::IRenderTarget* renderTarget = 0; +scene::ISceneNode* cube = 0; + +void one_iter() +{ + if(!device->run()) + { + // Could clean up here in theory, but not sure if it makes a difference + + /* + This tells emscripten to not run any further code. + */ + emscripten_cancel_main_loop(); + return; + } + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0)); + + if (renderTarget) + { + // draw scene into render target + + // set render target + driver->setRenderTargetEx(renderTarget, video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0,0,0,255)); + + // make cube invisible and set fixed camera as active camera + cube->setVisible(false); + smgr->setActiveCamera(fixedCam); + + // draw whole scene into render buffer + smgr->drawAll(); + + // set back old render target + // The buffer might have been distorted, so clear it + driver->setRenderTargetEx(0, 0, video::SColor(0)); + + // make the cube visible and set the user controlled camera as active one + cube->setVisible(true); + smgr->setActiveCamera(fpsCamera); + } + + // draw scene normally + smgr->drawAll(); + guienv->drawAll(); + + driver->endScene(); +} + +int main() +{ + // create device and exit if creation failed + + device = createDevice(video::EDT_WEBGL1, core::dimension2d(640, 480), 16, false, false); + + if (device == 0) + return 1; // could not create selected driver. + + driver = device->getVideoDriver(); + smgr = device->getSceneManager(); + guienv = device->getGUIEnvironment(); + + const io::path mediaPath = getExampleMediaPath(); + + + // load and display animated fairy mesh + scene::IAnimatedMeshSceneNode* fairy = smgr->addAnimatedMeshSceneNode( + smgr->getMesh(mediaPath + "faerie.md2")); + + if (!fairy) + return 1; + + fairy->setMaterialTexture(0, driver->getTexture(mediaPath + "faerie2.bmp")); // set diffuse texture + fairy->setMaterialFlag(video::EMF_LIGHTING, true); // enable dynamic lighting + fairy->getMaterial(0).Shininess = 20.0f; // set size of specular highlights + fairy->setPosition(core::vector3df(-10,0,-100)); + fairy->setMD2Animation ( scene::EMAT_STAND ); + + // add white light + smgr->addLightSceneNode(0, core::vector3df(-15,5,-105), video::SColorf(1.0f, 1.0f, 1.0f)); + + // set ambient light + smgr->setAmbientLight(video::SColor(0,60,60,60)); + + /* + The next is just some standard stuff: Add a test cube and let it rotate + to make the scene more interesting. The user defined camera and cursor + setup is made later on, right before the render loop. + */ + + // create test cube + cube = smgr->addCubeSceneNode(60); + + // let the cube rotate and set some light settings + scene::ISceneNodeAnimator* anim = smgr->createRotationAnimator( + core::vector3df(0.3f, 0.3f,0)); + + cube->setPosition(core::vector3df(-100,0,-100)); + cube->setMaterialFlag(video::EMF_LIGHTING, false); // disable dynamic lighting + cube->addAnimator(anim); + anim->drop(); + + // set window caption + device->setWindowCaption(L"Irrlicht Engine - Render to Texture and Specular Highlights example"); + + /* + To test out the render to texture feature, we need a render target + texture. These are not like standard textures, but need to be created + first. To create one, we call IVideoDriver::addRenderTargetTexture() + and specify the size of the texture. Please don't use sizes bigger than + the frame buffer for this, because the render target shares the zbuffer + with the frame buffer. + Because we want to render the scene not from the user camera into the + texture, we add another fixed camera to the scene. But before we do all + this, we check if the current running driver is able to render to + textures. If it is not, we simply display a warning text. + */ + + // create render target + if (driver->queryFeature(video::EVDF_RENDER_TO_TARGET)) + { + video::ITexture* renderTargetTex = driver->addRenderTargetTexture(core::dimension2d(256, 256), "RTT1", video::ECF_A8R8G8B8); + video::ITexture* renderTargetDepth = driver->addRenderTargetTexture(core::dimension2d(256, 256), "DepthStencil", video::ECF_D16); + + renderTarget = driver->addRenderTarget(); + renderTarget->setTexture(renderTargetTex, renderTargetDepth); + + cube->setMaterialTexture(0, renderTargetTex); // set material of cube to render target + + // add fixed camera + fixedCam = smgr->addCameraSceneNode(0, core::vector3df(10,10,-80), + core::vector3df(-10,10,-100)); + } + else + { + return 1; + } + + // add fps camera + fpsCamera = smgr->addCameraSceneNodeFPS(); + fpsCamera->setPosition(core::vector3df(-50,50,-150)); + +/* + Setting fps to 0 or a negative value will use the browser’s + requestAnimationFrame mechanism to call the main loop function. + Emscripten documentation recommends to do that, but you can also set + another fps value and the browser will try to call the main-loop + fps times per second. + The simulate_infinite_loop tells emscripten that this is an application + which will simulate an infinite loop. There is also a flag in the + Makefile about that: -s NO_EXIT_RUNTIME=1 + */ + int fps = 0; + int simulate_infinite_loop = 1; + emscripten_set_main_loop(one_iter, fps, simulate_infinite_loop); + + return 0; +} diff --git a/examples/14.Win32Window/Makefile b/examples/14.Win32Window/Makefile new file mode 100644 index 00000000..5813ca0a --- /dev/null +++ b/examples/14.Win32Window/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 14.Win32Window +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/14.Win32Window/Win32Window.cbp b/examples/14.Win32Window/Win32Window.cbp new file mode 100644 index 00000000..06f310b7 --- /dev/null +++ b/examples/14.Win32Window/Win32Window.cbp @@ -0,0 +1,43 @@ + + + + + + diff --git a/examples/14.Win32Window/Win32Window.vcproj b/examples/14.Win32Window/Win32Window.vcproj new file mode 100644 index 00000000..c8576c76 --- /dev/null +++ b/examples/14.Win32Window/Win32Window.vcproj @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/14.Win32Window/Win32Window_vc10.vcxproj b/examples/14.Win32Window/Win32Window_vc10.vcxproj new file mode 100644 index 00000000..0ea47dbd --- /dev/null +++ b/examples/14.Win32Window/Win32Window_vc10.vcxproj @@ -0,0 +1,239 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 14.Win32Window + {772FBE05-D05A-467B-9842-BEC409EEA8D0} + Win32Window + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Win32Window.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-VisualStudio\14.Win32Window.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Win32Window.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win64-VisualStudio\14.Win32Window.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Win32Window.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-VisualStudio\14.Win32Window.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Win32Window.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win64-VisualStudio\14.Win32Window.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/14.Win32Window/Win32Window_vc11.vcxproj b/examples/14.Win32Window/Win32Window_vc11.vcxproj new file mode 100644 index 00000000..0ea47dbd --- /dev/null +++ b/examples/14.Win32Window/Win32Window_vc11.vcxproj @@ -0,0 +1,239 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 14.Win32Window + {772FBE05-D05A-467B-9842-BEC409EEA8D0} + Win32Window + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Win32Window.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-VisualStudio\14.Win32Window.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Win32Window.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win64-VisualStudio\14.Win32Window.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Win32Window.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-VisualStudio\14.Win32Window.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Win32Window.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win64-VisualStudio\14.Win32Window.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/14.Win32Window/Win32Window_vc12.vcxproj b/examples/14.Win32Window/Win32Window_vc12.vcxproj new file mode 100644 index 00000000..814a398d --- /dev/null +++ b/examples/14.Win32Window/Win32Window_vc12.vcxproj @@ -0,0 +1,239 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 14.Win32Window + {772FBE05-D05A-467B-9842-BEC409EEA8D0} + Win32Window + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Win32Window.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-VisualStudio\14.Win32Window.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Win32Window.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win64-VisualStudio\14.Win32Window.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Win32Window.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-VisualStudio\14.Win32Window.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Win32Window.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win64-VisualStudio\14.Win32Window.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/14.Win32Window/Win32Window_vc14.vcxproj b/examples/14.Win32Window/Win32Window_vc14.vcxproj new file mode 100644 index 00000000..3142d412 --- /dev/null +++ b/examples/14.Win32Window/Win32Window_vc14.vcxproj @@ -0,0 +1,239 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 14.Win32Window + {772FBE05-D05A-467B-9842-BEC409EEA8D0} + Win32Window + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/Win32Window.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-VisualStudio\14.Win32Window.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/Win32Window.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win64-VisualStudio\14.Win32Window.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/Win32Window.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-VisualStudio\14.Win32Window.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/Win32Window.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win64-VisualStudio\14.Win32Window.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/14.Win32Window/main.cpp b/examples/14.Win32Window/main.cpp new file mode 100644 index 00000000..183381b9 --- /dev/null +++ b/examples/14.Win32Window/main.cpp @@ -0,0 +1,263 @@ +/** Example 014 Win32 Window + +This example only runs under MS Windows and demonstrates that Irrlicht can +render inside a win32 window. MFC and .NET Windows.Forms windows are possible, +too. + +In the beginning, we create a windows window using the windows API. I'm not +going to explain this code, because it is windows specific. See the MSDN or a +windows book for details. +*/ + +#include +#ifndef _IRR_WINDOWS_ +#error Windows only example +#else +#include // this example only runs with windows +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +using namespace irr; + +#ifdef _MSC_VER +#pragma comment(lib, "irrlicht.lib") +#endif + +HWND hOKButton; +HWND hWnd; + +static LRESULT CALLBACK CustomWndProc(HWND hWnd, UINT message, + WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_COMMAND: + { + HWND hwndCtl = (HWND)lParam; + int code = HIWORD(wParam); + + if (hwndCtl == hOKButton) + { + DestroyWindow(hWnd); + PostQuitMessage(0); + return 0; + } + } + break; + case WM_DESTROY: + PostQuitMessage(0); + return 0; + + } + + return DefWindowProc(hWnd, message, wParam, lParam); +} + + +/* + Now ask for the driver and create the Windows specific window. +*/ +int main() +{ + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + printf("Select the render window (some dead window may exist too):\n"\ + " (a) Window with button (via CreationParam)\n"\ + " (b) Window with button (via beginScene)\n"\ + " (c) Own Irrlicht window (default behavior)\n"\ + " (otherKey) exit\n\n"); + + char key; + std::cin >> key; + if (key != 'a' && key != 'b' && key != 'c') + return 1; + + HINSTANCE hInstance = 0; + // create dialog + + const fschar_t* Win32ClassName = __TEXT("CIrrlichtWindowsTestDialog"); + + WNDCLASSEX wcex; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = (WNDPROC)CustomWndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = DLGWINDOWEXTRA; + wcex.hInstance = hInstance; + wcex.hIcon = NULL; + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW); + wcex.lpszMenuName = 0; + wcex.lpszClassName = Win32ClassName; + wcex.hIconSm = 0; + + RegisterClassEx(&wcex); + + DWORD style = WS_SYSMENU | WS_BORDER | WS_CAPTION | + WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SIZEBOX; + + int windowWidth = 440; + int windowHeight = 380; + + hWnd = CreateWindow( Win32ClassName, __TEXT("Irrlicht Win32 window example"), + style, 100, 100, windowWidth, windowHeight, + NULL, NULL, hInstance, NULL); + + RECT clientRect; + GetClientRect(hWnd, &clientRect); + windowWidth = clientRect.right; + windowHeight = clientRect.bottom; + + // create ok button + + hOKButton = CreateWindow(__TEXT("BUTTON"), __TEXT("OK - Close"), WS_CHILD | WS_VISIBLE | BS_TEXT, + windowWidth - 160, windowHeight - 40, 150, 30, hWnd, NULL, hInstance, NULL); + + // create some text + + CreateWindow(__TEXT("STATIC"), __TEXT("This is Irrlicht running inside a standard Win32 window.\n")\ + __TEXT("Also mixing with MFC and .NET Windows.Forms is possible."), + WS_CHILD | WS_VISIBLE, 20, 20, 400, 40, hWnd, NULL, hInstance, NULL); + + // create window to put irrlicht in + + HWND hIrrlichtWindow = CreateWindow(__TEXT("BUTTON"), __TEXT(""), + WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, + 50, 80, 320, 220, hWnd, NULL, hInstance, NULL); + video::SExposedVideoData videodata((key=='b')?hIrrlichtWindow:0); + + /* + So now that we have some window, we can create an Irrlicht device + inside of it. We use Irrlicht createEx() function for this. We only + need the handle (HWND) to that window, set it as windowsID parameter + and start up the engine as usual. That's it. + */ + // create irrlicht device in the button window + + irr::SIrrlichtCreationParameters param; + param.DriverType = driverType; + if (key=='a') + param.WindowId = reinterpret_cast(hIrrlichtWindow); + + irr::IrrlichtDevice* device = irr::createDeviceEx(param); + + // setup a simple 3d scene + + irr::scene::ISceneManager* smgr = device->getSceneManager(); + video::IVideoDriver* driver = device->getVideoDriver(); + + if (driverType==video::EDT_OPENGL) + { + HDC HDc=GetDC(hIrrlichtWindow); + PIXELFORMATDESCRIPTOR pfd={0}; + pfd.nSize=sizeof(PIXELFORMATDESCRIPTOR); + int pf = GetPixelFormat(HDc); + DescribePixelFormat(HDc, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd); + pfd.dwFlags |= PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW; + pfd.cDepthBits=16; + pf = ChoosePixelFormat(HDc, &pfd); + SetPixelFormat(HDc, pf, &pfd); + videodata.OpenGLWin32.HDc = HDc; + videodata.OpenGLWin32.HRc=wglCreateContext(HDc); + wglShareLists((HGLRC)driver->getExposedVideoData().OpenGLWin32.HRc, (HGLRC)videodata.OpenGLWin32.HRc); + } + scene::ICameraSceneNode* cam = smgr->addCameraSceneNode(); + cam->setTarget(core::vector3df(0,0,0)); + + scene::ISceneNodeAnimator* anim = + smgr->createFlyCircleAnimator(core::vector3df(0,15,0), 30.0f); + cam->addAnimator(anim); + anim->drop(); + + scene::ISceneNode* cube = smgr->addCubeSceneNode(20); + + const io::path mediaPath = getExampleMediaPath(); + + cube->setMaterialTexture(0, driver->getTexture(mediaPath + "wall.bmp")); + cube->setMaterialTexture(1, driver->getTexture(mediaPath + "water.jpg")); + cube->setMaterialFlag( video::EMF_LIGHTING, false ); + cube->setMaterialType( video::EMT_REFLECTION_2_LAYER ); + + smgr->addSkyBoxSceneNode( + driver->getTexture(mediaPath + "irrlicht2_up.jpg"), + driver->getTexture(mediaPath + "irrlicht2_dn.jpg"), + driver->getTexture(mediaPath + "irrlicht2_lf.jpg"), + driver->getTexture(mediaPath + "irrlicht2_rt.jpg"), + driver->getTexture(mediaPath + "irrlicht2_ft.jpg"), + driver->getTexture(mediaPath + "irrlicht2_bk.jpg")); + + // This shows that we can render to multiple windows within one application + device->getGUIEnvironment()->addStaticText(core::stringw("Second screen render").c_str(),core::recti(0,0,200,200)); + + // show and execute dialog + + ShowWindow(hWnd , SW_SHOW); + UpdateWindow(hWnd); + + // do message queue + + /* + Now the only thing missing is the drawing loop using + IrrlichtDevice::run(). We do this as usual. But instead of this, there + is another possibility: You can also simply use your own message loop + using GetMessage, DispatchMessage and whatever. Calling + Device->run() will cause Irrlicht to dispatch messages internally too. + You need not call Device->run() if you want to do your own message + dispatching loop, but Irrlicht will not be able to fetch user input + then and you have to do it on your own using the window messages, + DirectInput, or whatever. + */ + + while (device->run()) + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0), 1.f, 0, videodata); + smgr->drawAll(); + driver->endScene(); + if (key=='b') + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0xbbbbbbbb)); + device->getGUIEnvironment()->drawAll(); + driver->endScene(); + } + } + + /* + The alternative, own message dispatching loop without Device->run() + would look like this: + */ + + /*MSG msg; + while (true) + { + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + + if (msg.message == WM_QUIT) + break; + } + + // advance virtual time + device->getTimer()->tick(); + + // draw engine picture + driver->beginScene(true, true, 0, (key=='c')?hIrrlichtWindow:0); + smgr->drawAll(); + driver->endScene(); + }*/ + + device->closeDevice(); + device->drop(); + + return 0; +} +#endif // if windows + +/* +That's it, Irrlicht now runs in your own windows window. +**/ diff --git a/examples/14.Win32Window/tutorial.html b/examples/14.Win32Window/tutorial.html new file mode 100644 index 00000000..6c5d5baa --- /dev/null +++ b/examples/14.Win32Window/tutorial.html @@ -0,0 +1,247 @@ + + +Irrlicht Engine Tutorial + + + + +
+ + + + + + + + +
+
+
Tutorial 14. Win32 Window
+
+
+
+

This example only runs in Windows and demonstrates that Irrlicht can + run inside a win32 window. MFC and .NET Windows.Forms windows are possible + too.

+

The program which is described here will look like this:

+


+

+
+
+
+ + + + + + + +
Lets start!
+
+

In the begining, we create a windows window using the windows API. + I'm not going to explain this code, because it is windows specific. + See the MSDN or a windows book for details.

+ + + + +
#include <irrlicht.h>
+#include <windows.h> // this example only runs with windows
+
+using namespace irr;
+
+#pragma comment(lib, "irrlicht.lib")
+
+HWND hOKButton;
+HWND hWnd;
+
+static LRESULT CALLBACK CustomWndProc(HWND hWnd, UINT message,
+    WPARAM wParam, LPARAM lParam)
+{
+	switch (message) 
+	{
+	case WM_COMMAND:
+		{
+			HWND hwndCtl = (HWND)lParam;
+			int code = HIWORD(wParam);
+
+			if (hwndCtl == hOKButton)
+			{
+				DestroyWindow(hWnd);
+				PostQuitMessage(0);
+				return 0;
+			}		
+		}
+		break;
+	case WM_DESTROY:
+		PostQuitMessage(0);
+		return 0;
+
+	}
+
+	return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+int main()
+//int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hpre, LPSTR cmd, int cc)
+{
+	HINSTANCE hInstance = 0;
+	// create dialog
+
+	const char* Win32ClassName = "CIrrlichtWindowsTestDialog";
+
+	WNDCLASSEX wcex;
+	wcex.cbSize			= sizeof(WNDCLASSEX); 
+	wcex.style			= CS_HREDRAW | CS_VREDRAW;
+	wcex.lpfnWndProc	= (WNDPROC)CustomWndProc;
+	wcex.cbClsExtra		= 0;
+	wcex.cbWndExtra		= DLGWINDOWEXTRA; 
+	wcex.hInstance		= hInstance;
+	wcex.hIcon			= NULL;
+	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
+	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW);
+	wcex.lpszMenuName	= 0;
+	wcex.lpszClassName	= Win32ClassName;
+	wcex.hIconSm		= 0;
+
+	RegisterClassEx(&wcex);
+
+	DWORD style = WS_SYSMENU | WS_BORDER | WS_CAPTION | 
+		WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MAXIMIZEBOX
+		| WS_MINIMIZEBOX | WS_SIZEBOX;
+
+	int windowWidth = 440;
+	int windowHeight = 380;
+
+	hWnd = CreateWindow( Win32ClassName, "Irrlicht Win32 window example",
+		style, 100, 100, windowWidth, windowHeight,
+		NULL, NULL, hInstance, NULL);
+
+	RECT clientRect;
+	GetClientRect(hWnd, &clientRect);
+	windowWidth = clientRect.right;
+	windowHeight = clientRect.bottom;
+
+	// create ok button
+
+	hOKButton = CreateWindow(
+	    "BUTTON", "OK - Close", WS_CHILD | WS_VISIBLE | BS_TEXT, 
+		windowWidth - 160, windowHeight - 40, 150, 30, hWnd, NULL, 
+		hInstance, NULL);
+
+	// create some text
+	
+	CreateWindow("STATIC", 
+        "This is Irrlicht running inside a standard Win32 window.\n"\
+		"Also mixing with MFC and .NET Windows.Forms is possible.",
+		WS_CHILD | WS_VISIBLE, 20, 20, 400, 40, hWnd, NULL, hInstance, NULL);
+
+	// create window to put irrlicht in
+
+	HWND hIrrlichtWindow =
CreateWindow("BUTTON", "", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, + 50, 80, 320, 220, hWnd, NULL, hInstance, NULL); + +
+

So now that we have some window, we can create an Irrlicht device + inside of it. We use Irrlicht createEx() function for this. We only + need the handle (HWND) to that window, set it as windowsID parameter + and start up the engine as usual. That's it.

+ + + + +
	// create irrlicht device in the button window
+
+	irr::SIrrlichtCreationParameters param;
+	param.WindowId = reinterpret_cast(hIrrlichtWindow); // hColorButton
+	param.DriverType = video::EDT_OPENGL;
+
+	irr::IrrlichtDevice* device = irr::createDeviceEx(param);
+	
+	// setup a simple 3d scene
+
+	irr::scene::ISceneManager* smgr = device->getSceneManager();
+	video::IVideoDriver* driver = device->getVideoDriver();
+
+	scene::ICameraSceneNode* cam = smgr->addCameraSceneNode();
+	cam->setTarget(core::vector3df(0,0,0));
+
+	scene::ISceneNodeAnimator* anim =
+	   smgr->createFlyCircleAnimator(core::vector3df(0,10,0), 30.0f);
+	cam->addAnimator(anim);
+	anim->drop();
+
+	scene::ISceneNode* cube = smgr->addCubeSceneNode(25);
+	cube->setMaterialFlag(video::EMF_LIGHTING, false);
+	
+	cube->setMaterialTexture(0, driver->getTexture("../../media/rockwall.bmp"));
+
+	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"));
+
+	// show and execute dialog
+
+	ShowWindow(hWnd , SW_SHOW);
+	UpdateWindow(hWnd);
+
+

Now the only thing missing is the drawing loop using IrrlichtDevice::run(). + We do this as usual. But instead of this, there is another possibility: + You can also simply use your own message loop using GetMessage, DispatchMessage + and whatever. Calling
+ Device->run() will cause Irrlicht to dispatch messages internally + too. You need not call Device->run() if you want to do your own + message dispatching loop, but Irrlicht will not be able to fetch user + input then and you have to do it on your own using the window messages, + DirectInput, or whatever.

+ + + + +
	while (device->run())
+	{
+		driver->beginScene(true, true, 0);
+		smgr->drawAll();
+		driver->endScene();
+	}
+
+	// the alternative, own message dispatching loop without Device->run() would
+	// look like this:
+
+	/*MSG msg;
+	while (true)
+	{
+		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+		{
+			TranslateMessage(&msg);
+			DispatchMessage(&msg);
+
+			if (msg.message == WM_QUIT)
+				break;
+		}
+		
+		// advance virtual time
+		device->getTimer()->tick();
+
+		// draw engine picture
+		driver->beginScene(true, true, 0);
+		smgr->drawAll();
+		driver->endScene();
+	}*/
+
+	device->closeDevice();
+	device->drop();
+
+	return 0;
+}
+

That's it, Irrlicht now runs in your own windows window.

+
+
+
+

 

+ + diff --git a/examples/15.LoadIrrFile/LoadIrrFile.cbp b/examples/15.LoadIrrFile/LoadIrrFile.cbp new file mode 100644 index 00000000..a0871586 --- /dev/null +++ b/examples/15.LoadIrrFile/LoadIrrFile.cbp @@ -0,0 +1,54 @@ + + + + + + diff --git a/examples/15.LoadIrrFile/LoadIrrFile.vcproj b/examples/15.LoadIrrFile/LoadIrrFile.vcproj new file mode 100644 index 00000000..fef46266 --- /dev/null +++ b/examples/15.LoadIrrFile/LoadIrrFile.vcproj @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/15.LoadIrrFile/LoadIrrFile.xcodeproj/project.pbxproj b/examples/15.LoadIrrFile/LoadIrrFile.xcodeproj/project.pbxproj new file mode 100644 index 00000000..69bd0417 --- /dev/null +++ b/examples/15.LoadIrrFile/LoadIrrFile.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 15.LoadIrrFile.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 15.LoadIrrFile.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 15.LoadIrrFile.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 15.LoadIrrFile */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "15.LoadIrrFile" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 15.LoadIrrFile; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 15.LoadIrrFile.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "LoadIrrFile" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 15.LoadIrrFile */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "LoadIrrFile" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "15.LoadIrrFile" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/15.LoadIrrFile/LoadIrrFile.xcodeproj/xcshareddata/xcschemes/15.LoadIrrFile.xcscheme b/examples/15.LoadIrrFile/LoadIrrFile.xcodeproj/xcshareddata/xcschemes/15.LoadIrrFile.xcscheme new file mode 100644 index 00000000..0de8a807 --- /dev/null +++ b/examples/15.LoadIrrFile/LoadIrrFile.xcodeproj/xcshareddata/xcschemes/15.LoadIrrFile.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/15.LoadIrrFile/LoadIrrFile_vc10.vcxproj b/examples/15.LoadIrrFile/LoadIrrFile_vc10.vcxproj new file mode 100644 index 00000000..db6dec20 --- /dev/null +++ b/examples/15.LoadIrrFile/LoadIrrFile_vc10.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 15.LoadIrrFile + {78C9F424-523C-49AC-94B7-823AA4A26BF9} + LoadIrrFile + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/LoadIrrFile.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\15.LoadIrrFile.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/LoadIrrFile.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\15.LoadIrrFile.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/LoadIrrFile.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\15.LoadIrrFile.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/LoadIrrFile.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\15.LoadIrrFile.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/15.LoadIrrFile/LoadIrrFile_vc11.vcxproj b/examples/15.LoadIrrFile/LoadIrrFile_vc11.vcxproj new file mode 100644 index 00000000..db6dec20 --- /dev/null +++ b/examples/15.LoadIrrFile/LoadIrrFile_vc11.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 15.LoadIrrFile + {78C9F424-523C-49AC-94B7-823AA4A26BF9} + LoadIrrFile + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/LoadIrrFile.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\15.LoadIrrFile.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/LoadIrrFile.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\15.LoadIrrFile.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/LoadIrrFile.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\15.LoadIrrFile.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/LoadIrrFile.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\15.LoadIrrFile.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/15.LoadIrrFile/LoadIrrFile_vc12.vcxproj b/examples/15.LoadIrrFile/LoadIrrFile_vc12.vcxproj new file mode 100644 index 00000000..97b4c717 --- /dev/null +++ b/examples/15.LoadIrrFile/LoadIrrFile_vc12.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 15.LoadIrrFile + {78C9F424-523C-49AC-94B7-823AA4A26BF9} + LoadIrrFile + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/LoadIrrFile.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\15.LoadIrrFile.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/LoadIrrFile.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\15.LoadIrrFile.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/LoadIrrFile.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\15.LoadIrrFile.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/LoadIrrFile.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\15.LoadIrrFile.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/15.LoadIrrFile/LoadIrrFile_vc14.vcxproj b/examples/15.LoadIrrFile/LoadIrrFile_vc14.vcxproj new file mode 100644 index 00000000..0811f131 --- /dev/null +++ b/examples/15.LoadIrrFile/LoadIrrFile_vc14.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 15.LoadIrrFile + {78C9F424-523C-49AC-94B7-823AA4A26BF9} + LoadIrrFile + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/LoadIrrFile.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\15.LoadIrrFile.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/LoadIrrFile.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\15.LoadIrrFile.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/LoadIrrFile.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\15.LoadIrrFile.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/LoadIrrFile.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\15.LoadIrrFile.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/15.LoadIrrFile/Makefile b/examples/15.LoadIrrFile/Makefile new file mode 100644 index 00000000..5fde1186 --- /dev/null +++ b/examples/15.LoadIrrFile/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 15.LoadIrrFile +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/15.LoadIrrFile/main.cpp b/examples/15.LoadIrrFile/main.cpp new file mode 100644 index 00000000..d28e6f67 --- /dev/null +++ b/examples/15.LoadIrrFile/main.cpp @@ -0,0 +1,181 @@ +/** Example 015 Loading Scenes from .irr Files + +Since version 1.1, Irrlicht is able to save and load +the full scene graph into an .irr file, an xml based +format. There is an editor available to edit +those files, named irrEdit (http://www.ambiera.com/irredit) +which can also be used as world and particle editor. +This tutorial shows how to use .irr files. + +Lets start: Create an Irrlicht device and setup the window. +*/ + +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +using namespace irr; + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +int main(int argc, char** argv) +{ + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + // create device and exit if creation failed + + IrrlichtDevice* device = + createDevice(driverType, core::dimension2d(640, 480)); + + if (device == 0) + return 1; // could not create selected driver. + + device->setWindowCaption(L"Load .irr file example"); + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + + /* + Now load our .irr file. + .irr files can store the whole scene graph including animators, + materials and particle systems. And there is also the possibility to + store arbitrary user data for every scene node in that file. To keep + this example simple, we are simply loading the scene here. See the + documentation at ISceneManager::loadScene and ISceneManager::saveScene + for more information. So to load and display a complicated huge scene, + we only need a single call to loadScene(). + */ + + // load the scene + /* You might have to work around some minor problems in current .irr loader: + - It can't load meshes relative to the .irr file, but only relative to the working directory. + So you might have to change your working directory to the path where the .irr file is in. + - When passing a custom parent node to loadScene then irr_scene attributes will be passed to that. + Usually not a problem, but for example AmbientLight will not change that way unless you create a custom + SceneNode type which can interpret those attributes. + */ + if (argc>1) + smgr->loadScene(argv[1]); + else + smgr->loadScene(getExampleMediaPath() + "example.irr"); + + /* + Now we'll create a camera, and give it a collision response animator + that's built from the mesh nodes in the scene we just loaded. + */ + scene::ICameraSceneNode * camera = smgr->addCameraSceneNodeFPS(0, 50.f, 0.1f); + + // Create a meta triangle selector to hold several triangle selectors. + scene::IMetaTriangleSelector * meta = smgr->createMetaTriangleSelector(); + + /* + Now we will find all the nodes in the scene and create triangle + selectors for all suitable nodes. Typically, you would want to make a + more informed decision about which nodes to performs collision checks + on; you could capture that information in the node name or Id. + */ + core::array nodes; + smgr->getSceneNodesFromType(scene::ESNT_ANY, nodes); // Find all nodes + + for (u32 i=0; i < nodes.size(); ++i) + { + scene::ISceneNode * node = nodes[i]; + scene::ITriangleSelector * selector = 0; + + switch(node->getType()) + { + case scene::ESNT_CUBE: + case scene::ESNT_ANIMATED_MESH: + // Because the selector won't animate with the mesh, + // and is only being used for camera collision, we'll just use an approximate + // bounding box instead of ((scene::IAnimatedMeshSceneNode*)node)->getMesh(0) + selector = smgr->createTriangleSelectorFromBoundingBox(node); + break; + + case scene::ESNT_MESH: + case scene::ESNT_SPHERE: // Derived from IMeshSceneNode + selector = smgr->createTriangleSelector(((scene::IMeshSceneNode*)node)->getMesh(), node); + break; + + case scene::ESNT_TERRAIN: + selector = smgr->createTerrainTriangleSelector((scene::ITerrainSceneNode*)node); + break; + + case scene::ESNT_OCTREE: + selector = smgr->createOctreeTriangleSelector(((scene::IMeshSceneNode*)node)->getMesh(), node); + break; + + default: + // Don't create a selector for this node type + break; + } + + if(selector) + { + // Add it to the meta selector, which will take a reference to it + meta->addTriangleSelector(selector); + // And drop my reference to it, so that the meta selector owns it. + selector->drop(); + } + } + + /* + Now that the mesh scene nodes have had triangle selectors created and added + to the meta selector, create a collision response animator from that meta selector. + */ + scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator( + meta, camera, core::vector3df(5,5,5), + core::vector3df(0,0,0)); + meta->drop(); // I'm done with the meta selector now + + camera->addAnimator(anim); + anim->drop(); // I'm done with the animator now + + // And set the camera position so that it doesn't start off stuck in the geometry + camera->setPosition(core::vector3df(0.f, 20.f, 0.f)); + + // Point the camera at the cube node, by finding the first node of type ESNT_CUBE + scene::ISceneNode * cube = smgr->getSceneNodeFromType(scene::ESNT_CUBE); + if(cube) + camera->setTarget(cube->getAbsolutePosition()); + + /* + That's it. Draw everything and finish as usual. + */ + + int lastFPS = -1; + + while(device->run()) + if (device->isWindowActive()) + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0,200,200,200)); + smgr->drawAll(); + driver->endScene(); + + int fps = driver->getFPS(); + + if (lastFPS != fps) + { + core::stringw str = L"Load Irrlicht File example - Irrlicht Engine ["; + str += driver->getName(); + str += "] FPS:"; + str += fps; + + device->setWindowCaption(str.c_str()); + lastFPS = fps; + } + + } + + device->drop(); + + return 0; +} + +/* +**/ diff --git a/examples/15.LoadIrrFile/tutorial.html b/examples/15.LoadIrrFile/tutorial.html new file mode 100644 index 00000000..e3e4a6b2 --- /dev/null +++ b/examples/15.LoadIrrFile/tutorial.html @@ -0,0 +1,129 @@ + + +Irrlicht Engine Tutorial + + + + +
+ + + + + + + + +
+ Tutorial 15. Load .irr File
+

Since version 1.1, Irrlicht is able to save and load the full scene + graph into an .irr file, an xml based format. There is also an editor + available to edit those files, named irrEdit on http://www.ambiera.com/irredit, + which can also be used as world and particle editor. This tutorial shows + how to use .irr files.

+


+

+
+
+ + + + + + + +
+ Lets start!
+

Lets start: Create an Irrlicht device and setup the window.

+ + + + +
#include 
+#include 
+using namespace irr;
+
+#pragma comment(lib, "Irrlicht.lib")
+
+int main()
+{
+	// ask user for driver
+
+	video::E_DRIVER_TYPE driverType;
+
+	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) Apfelbaum Software Renderer\n"\
+		" (f) NullDevice\n (otherKey) exit\n\n");
+
+	char i;
+	std::cin >> i;
+
+	switch(i)
+	{
+		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;
+		default: return 1;
+	}	
+
+	// create device and exit if creation failed
+
+	IrrlichtDevice* device =
+		createDevice(driverType, core::dimension2d(640, 480));
+
+	if (device == 0)
+		return 1; // could not create selected driver.
+
+	device->setWindowCaption(L"Load .irr file example");
+
+	video::IVideoDriver* driver = device->getVideoDriver();
+	scene::ISceneManager* smgr = device->getSceneManager();
+
+

Now load our .irr file. .irr files can store the whole scene graph + including animators, materials and particle systems. And there is also + the possibility to store arbitrary user data for every scene node in + that file. To keep this example simple, we are simply loading the scene + here. See the documentation at ISceneManager::loadScene and ISceneManager::saveScene + for more information. So to load and display a complicated huge scene, + we only need a single call to loadScene().

+ + + + +
// load the scene
smgr->loadScene("../../media/example.irr");
+

That was it already. Now add a camera and draw the scene.

+ + + + +
	// add a user controlled camera
+
+	smgr->addCameraSceneNodeFPS();
+
+	// and draw everything.
+	
+	while(device->run())
+	if (device->isWindowActive())
+	{
+		driver->beginScene(true, true, video::SColor(0,200,200,200));
+		smgr->drawAll();
+		driver->endScene();
+	}
+
+	device->drop();
+	
+	return 0;
+}
+
+ +
+

 

+
+

 

+

 

+ + diff --git a/examples/16.Quake3MapShader/Makefile b/examples/16.Quake3MapShader/Makefile new file mode 100644 index 00000000..e4d5fb19 --- /dev/null +++ b/examples/16.Quake3MapShader/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 16.Quake3MapShader +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/16.Quake3MapShader/Quake3MapShader.cbp b/examples/16.Quake3MapShader/Quake3MapShader.cbp new file mode 100644 index 00000000..544f80fe --- /dev/null +++ b/examples/16.Quake3MapShader/Quake3MapShader.cbp @@ -0,0 +1,56 @@ + + + + + + diff --git a/examples/16.Quake3MapShader/Quake3MapShader.vcproj b/examples/16.Quake3MapShader/Quake3MapShader.vcproj new file mode 100644 index 00000000..de658b34 --- /dev/null +++ b/examples/16.Quake3MapShader/Quake3MapShader.vcproj @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/16.Quake3MapShader/Quake3MapShader.xcodeproj/project.pbxproj b/examples/16.Quake3MapShader/Quake3MapShader.xcodeproj/project.pbxproj new file mode 100644 index 00000000..31edfb14 --- /dev/null +++ b/examples/16.Quake3MapShader/Quake3MapShader.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 16.Quake3MapShader.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 16.Quake3MapShader.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 16.Quake3MapShader.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 16.Quake3MapShader */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "16.Quake3MapShader" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 16.Quake3MapShader; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 16.Quake3MapShader.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Quake3MapShader" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 16.Quake3MapShader */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Quake3MapShader" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "16.Quake3MapShader" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/16.Quake3MapShader/Quake3MapShader.xcodeproj/xcshareddata/xcschemes/16.Quake3MapShader.xcscheme b/examples/16.Quake3MapShader/Quake3MapShader.xcodeproj/xcshareddata/xcschemes/16.Quake3MapShader.xcscheme new file mode 100644 index 00000000..02775ec0 --- /dev/null +++ b/examples/16.Quake3MapShader/Quake3MapShader.xcodeproj/xcshareddata/xcschemes/16.Quake3MapShader.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/16.Quake3MapShader/Quake3MapShader_vc10.vcxproj b/examples/16.Quake3MapShader/Quake3MapShader_vc10.vcxproj new file mode 100644 index 00000000..b5564f80 --- /dev/null +++ b/examples/16.Quake3MapShader/Quake3MapShader_vc10.vcxproj @@ -0,0 +1,194 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 16.Quake3MapShader + {EB3B38EA-5CE7-4983-845B-880661E69D09} + 16.Quake3MapShader + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + Cdecl + + + ..\..\bin\Win32-VisualStudio\16.Quake3MapShader.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + Cdecl + + + ..\..\bin\Win64-VisualStudio\16.Quake3MapShader.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\16.Quake3MapShader.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\16.Quake3MapShader.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/16.Quake3MapShader/Quake3MapShader_vc11.vcxproj b/examples/16.Quake3MapShader/Quake3MapShader_vc11.vcxproj new file mode 100644 index 00000000..b5564f80 --- /dev/null +++ b/examples/16.Quake3MapShader/Quake3MapShader_vc11.vcxproj @@ -0,0 +1,194 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 16.Quake3MapShader + {EB3B38EA-5CE7-4983-845B-880661E69D09} + 16.Quake3MapShader + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + Cdecl + + + ..\..\bin\Win32-VisualStudio\16.Quake3MapShader.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + Cdecl + + + ..\..\bin\Win64-VisualStudio\16.Quake3MapShader.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\16.Quake3MapShader.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\16.Quake3MapShader.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/16.Quake3MapShader/Quake3MapShader_vc12.vcxproj b/examples/16.Quake3MapShader/Quake3MapShader_vc12.vcxproj new file mode 100644 index 00000000..e41579e1 --- /dev/null +++ b/examples/16.Quake3MapShader/Quake3MapShader_vc12.vcxproj @@ -0,0 +1,194 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 16.Quake3MapShader + {EB3B38EA-5CE7-4983-845B-880661E69D09} + 16.Quake3MapShader + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + Cdecl + + + ..\..\bin\Win32-VisualStudio\16.Quake3MapShader.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + Cdecl + + + ..\..\bin\Win64-VisualStudio\16.Quake3MapShader.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\16.Quake3MapShader.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\16.Quake3MapShader.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/16.Quake3MapShader/Quake3MapShader_vc14.vcxproj b/examples/16.Quake3MapShader/Quake3MapShader_vc14.vcxproj new file mode 100644 index 00000000..9c850a13 --- /dev/null +++ b/examples/16.Quake3MapShader/Quake3MapShader_vc14.vcxproj @@ -0,0 +1,194 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 16.Quake3MapShader + {EB3B38EA-5CE7-4983-845B-880661E69D09} + 16.Quake3MapShader + Win32Proj + + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + Cdecl + + + ..\..\bin\Win32-VisualStudio\16.Quake3MapShader.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + Cdecl + + + ..\..\bin\Win64-VisualStudio\16.Quake3MapShader.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\16.Quake3MapShader.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\16.Quake3MapShader.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/16.Quake3MapShader/main.cpp b/examples/16.Quake3MapShader/main.cpp new file mode 100644 index 00000000..e8a318dc --- /dev/null +++ b/examples/16.Quake3MapShader/main.cpp @@ -0,0 +1,391 @@ +/** Example 016 Quake3 Map Shader Support + +This tutorial shows how to load a Quake 3 map into the +engine, create a SceneNode for optimizing the speed of +rendering and how to create a user controlled camera. + +Lets start like the HelloWorld example: We include +the irrlicht header files and an additional file to be able +to ask the user for a driver type using the console. +*/ +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +/* + define which Quake3 Level should be loaded +*/ +#define IRRLICHT_QUAKE3_ARENA +//#define ORIGINAL_QUAKE3_ARENA +//#define CUSTOM_QUAKE3_ARENA +//#define SHOW_SHADER_NAME + +#ifdef ORIGINAL_QUAKE3_ARENA + #define QUAKE3_STORAGE_FORMAT addFolderFileArchive + #define QUAKE3_STORAGE_1 "/baseq3/" + #ifdef CUSTOM_QUAKE3_ARENA + #define QUAKE3_STORAGE_2 "/cf/" + #define QUAKE3_MAP_NAME "maps/cf.bsp" + #else + #define QUAKE3_MAP_NAME "maps/q3dm8.bsp" + #endif +#endif + +#ifdef IRRLICHT_QUAKE3_ARENA + #define QUAKE3_STORAGE_FORMAT addFileArchive + #define QUAKE3_STORAGE_1 getExampleMediaPath() + "map-20kdm2.pk3" + #define QUAKE3_MAP_NAME "maps/20kdm2.bsp" +#endif + +using namespace irr; +using namespace scene; + +/* +Again, to be able to use the Irrlicht.DLL file, we need to link with the +Irrlicht.lib. We could set this option in the project settings, but +to make it easy, we use a pragma comment lib: +*/ +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + + +/* +A class to produce a series of screenshots +*/ +class CScreenShotFactory : public IEventReceiver +{ +public: + + CScreenShotFactory( IrrlichtDevice *device, const c8 * templateName, ISceneNode* node ) + : Device(device), Number(0), FilenameTemplate(templateName), Node(node) + { + FilenameTemplate.replace ( '/', '_' ); + FilenameTemplate.replace ( '\\', '_' ); + } + + bool OnEvent(const SEvent& event) + { + // check if user presses the key F9 + if ((event.EventType == EET_KEY_INPUT_EVENT) && + event.KeyInput.PressedDown) + { + if (event.KeyInput.Key == KEY_F9) + { + video::IImage* image = Device->getVideoDriver()->createScreenShot(); + if (image) + { + c8 buf[256]; + snprintf_irr(buf, 256, "%s_shot%04d.jpg", + FilenameTemplate.c_str(), + ++Number); + Device->getVideoDriver()->writeImageToFile(image, buf, 85 ); + image->drop(); + } + } + else + if (event.KeyInput.Key == KEY_F8) + { + if (Node->isDebugDataVisible()) + Node->setDebugDataVisible(scene::EDS_OFF); + else + Node->setDebugDataVisible(scene::EDS_BBOX_ALL); + } + } + return false; + } + +private: + IrrlichtDevice *Device; + u32 Number; + core::stringc FilenameTemplate; + ISceneNode* Node; +}; + + +/* +Ok, lets start. +*/ + +int IRRCALLCONV main(int argc, char* argv[]) +{ + /* + Like in the HelloWorld example, we create an IrrlichtDevice with + createDevice(). The difference now is that we ask the user to select + which hardware accelerated driver to use. The Software device would be + too slow to draw a huge Quake 3 map, but just for the fun of it, we make + this decision possible too. + */ + + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + // create device and exit if creation failed + const core::dimension2du videoDim(800,600); + + IrrlichtDevice *device = createDevice(driverType, videoDim, 32, false ); + + if (device == 0) + return 1; // could not create selected driver. + + const char* mapname=0; + if (argc>2) + mapname = argv[2]; + else + mapname = QUAKE3_MAP_NAME; + + /* + Get a pointer to the video driver and the SceneManager so that + we do not always have to write device->getVideoDriver() and + device->getSceneManager(). + */ + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + gui::IGUIEnvironment* gui = device->getGUIEnvironment(); + + const io::path mediaPath = getExampleMediaPath(); + + //! add our private media directory to the file system + device->getFileSystem()->addFileArchive(mediaPath); + + /* + To display the Quake 3 map, we first need to load it. Quake 3 maps + are packed into .pk3 files, which are nothing other than .zip files. + So we add the .pk3 file to our FileSystem. After it was added, + we are able to read from the files in that archive as they would + directly be stored on disk. + */ + if (argc>2) + device->getFileSystem()->QUAKE3_STORAGE_FORMAT(argv[1]); + else + device->getFileSystem()->QUAKE3_STORAGE_FORMAT(QUAKE3_STORAGE_1); +#ifdef QUAKE3_STORAGE_2 + device->getFileSystem()->QUAKE3_STORAGE_FORMAT(QUAKE3_STORAGE_2); +#endif + + // Quake3 Shader controls Z-Writing + smgr->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true); + + /* + Now we can load the mesh by calling getMesh(). We get a pointer returned + to a IAnimatedMesh. As you know, Quake 3 maps are not really animated, + they are only a huge chunk of static geometry with some materials + attached. Hence the IAnimated mesh consists of only one frame, + so we get the "first frame" of the "animation", which is our quake level + and create an Octree scene node with it, using addOctreeSceneNode(). + The Octree optimizes the scene a little bit, trying to draw only geometry + which is currently visible. An alternative to the Octree would be a + AnimatedMeshSceneNode, which would draw always the complete geometry of + the mesh, without optimization. Try it out: Write addAnimatedMeshSceneNode + instead of addOctreeSceneNode and compare the primitives drawn by the + video driver. (There is a getPrimitiveCountDrawed() method in the + IVideoDriver class). Note that this optimization with the Octree is only + useful when drawing huge meshes consisting of lots of geometry. + */ + scene::IQ3LevelMesh* const mesh = + (scene::IQ3LevelMesh*) smgr->getMesh(mapname); + + /* + add the geometry mesh to the Scene ( polygon & patches ) + The Geometry mesh is optimised for faster drawing + */ + scene::ISceneNode* node = 0; + if (mesh) + { + scene::IMesh * const geometry = mesh->getMesh(quake3::E_Q3_MESH_GEOMETRY); + node = smgr->addOctreeSceneNode(geometry, 0, -1, 4096); + } + + // create an event receiver for making screenshots + CScreenShotFactory screenshotFactory(device, mapname, node); + device->setEventReceiver(&screenshotFactory); + + /* + now construct SceneNodes for each Shader + The Objects are stored in the quake mesh scene::E_Q3_MESH_ITEMS + and the Shader ID is stored in the MaterialParameters + mostly dark looking skulls and moving lava.. or green flashing tubes? + */ + if ( mesh ) + { + // the additional mesh can be quite huge and is unoptimized + const scene::IMesh * const additional_mesh = mesh->getMesh(quake3::E_Q3_MESH_ITEMS); + +#ifdef SHOW_SHADER_NAME + gui::IGUIFont *font = device->getGUIEnvironment()->getFont(mediaPath + "fontlucida.png"); + u32 count = 0; +#endif + + for ( u32 i = 0; i!= additional_mesh->getMeshBufferCount(); ++i ) + { + const IMeshBuffer* meshBuffer = additional_mesh->getMeshBuffer(i); + const video::SMaterial& material = meshBuffer->getMaterial(); + + // The ShaderIndex is stored in the material parameter + const s32 shaderIndex = (s32) material.MaterialTypeParam2; + + // the meshbuffer can be rendered without additional support, or it has no shader + const quake3::IShader *shader = mesh->getShader(shaderIndex); + if (0 == shader) + { + continue; + } + + // we can dump the shader to the console in its + // original but already parsed layout in a pretty + // printers way.. commented out, because the console + // would be full... + // quake3::dumpShader ( Shader ); + + node = smgr->addQuake3SceneNode(meshBuffer, shader); + +#ifdef SHOW_SHADER_NAME + count += 1; + core::stringw name( node->getName() ); + node = smgr->addBillboardTextSceneNode( + font, name.c_str(), node, + core::dimension2d(80.0f, 8.0f), + core::vector3df(0, 10, 0)); +#endif + } + } + + /* + Now we only need a Camera to look at the Quake 3 map. And we want to + create a user controlled camera. There are some different cameras + available in the Irrlicht engine. For example the Maya Camera which can + be controlled comparable to the camera in Maya: Rotate with left mouse + button pressed, Zoom with both buttons pressed, translate with right + mouse button pressed. This could be created with + addCameraSceneNodeMaya(). But for this example, we want to create a + camera which behaves like the ones in first person shooter games (FPS). + */ + + scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(); + + /* + so we need a good starting Position in the level. + we can ask the Quake3 Loader for all entities with class_name + "info_player_deathmatch" + we choose a random launch + */ + if ( mesh ) + { + quake3::tQ3EntityList &entityList = mesh->getEntityList(); + + quake3::IEntity search; + search.name = "info_player_deathmatch"; + + s32 index = entityList.binary_search(search); + if (index >= 0) + { + s32 notEndList; + do + { + const quake3::SVarGroup *group = entityList[index].getGroup(1); + + u32 parsepos = 0; + const core::vector3df pos = + quake3::getAsVector3df(group->get("origin"), parsepos); + + parsepos = 0; + const f32 angle = quake3::getAsFloat(group->get("angle"), parsepos); + + core::vector3df target(0.f, 0.f, 1.f); + target.rotateXZBy(angle); + + camera->setPosition(pos); + camera->setTarget(pos + target); + + ++index; +/* + notEndList = ( index < (s32) entityList.size () && + entityList[index].name == search.name && + (device->getTimer()->getRealTime() >> 3 ) & 1 + ); +*/ + notEndList = index == 2; + } while ( notEndList ); + } + } + + /* + The mouse cursor needs not to be visible, so we make it invisible. + */ + + device->getCursorControl()->setVisible(false); + + // load the engine logo + gui->addImage(driver->getTexture("irrlichtlogo2.png"), + core::position2d(10, 10)); + + // show the driver logo + const core::position2di pos(videoDim.Width - 128, videoDim.Height - 64); + + switch ( driverType ) + { + case video::EDT_BURNINGSVIDEO: + gui->addImage(driver->getTexture("burninglogo.png"), pos); + break; + case video::EDT_OPENGL: + gui->addImage(driver->getTexture("opengllogo.png"), pos); + break; + case video::EDT_DIRECT3D9: + gui->addImage(driver->getTexture("directxlogo.png"), pos); + break; + } + + /* + We have done everything, so lets draw it. We also write the current + frames per second and the drawn primitives to the caption of the + window. The 'if (device->isWindowActive())' line is optional, but + prevents the engine render to set the position of the mouse cursor + after task switching when other program are active. + */ + int lastFPS = -1; + + while(device->run()) + if (device->isWindowActive()) + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,20,20,40)); + smgr->drawAll(); + gui->drawAll(); + driver->endScene(); + + int fps = driver->getFPS(); + //if (lastFPS != fps) + { + io::IAttributes * const attr = smgr->getParameters(); + core::stringw str = L"Q3 ["; + str += driver->getName(); + str += "] FPS:"; + str += fps; +#ifdef _IRR_SCENEMANAGER_DEBUG + str += " Cull:"; + str += attr->getAttributeAsInt("calls"); + str += "/"; + str += attr->getAttributeAsInt("culled"); + str += " Draw: "; + str += attr->getAttributeAsInt("drawn_solid"); + str += "/"; + str += attr->getAttributeAsInt("drawn_transparent"); + str += "/"; + str += attr->getAttributeAsInt("drawn_transparent_effect"); +#endif + device->setWindowCaption(str.c_str()); + lastFPS = fps; + } + } + + /* + In the end, delete the Irrlicht device. + */ + device->drop(); + + return 0; +} + +/* +**/ diff --git a/examples/17.HelloWorld_Mobile/17. HelloWorld for Windows Mobile on PC_v8.vcproj b/examples/17.HelloWorld_Mobile/17. HelloWorld for Windows Mobile on PC_v8.vcproj new file mode 100644 index 00000000..be07354f --- /dev/null +++ b/examples/17.HelloWorld_Mobile/17. HelloWorld for Windows Mobile on PC_v8.vcproj @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/17.HelloWorld_Mobile/17. HelloWorld for Windows Mobile on PC_v9.vcproj b/examples/17.HelloWorld_Mobile/17. HelloWorld for Windows Mobile on PC_v9.vcproj new file mode 100644 index 00000000..acdc249d --- /dev/null +++ b/examples/17.HelloWorld_Mobile/17. HelloWorld for Windows Mobile on PC_v9.vcproj @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/17.HelloWorld_Mobile/17. HelloWorld for Windows Mobile on PC_vc10.vcxproj b/examples/17.HelloWorld_Mobile/17. HelloWorld for Windows Mobile on PC_vc10.vcxproj new file mode 100644 index 00000000..0f047407 --- /dev/null +++ b/examples/17.HelloWorld_Mobile/17. HelloWorld for Windows Mobile on PC_vc10.vcxproj @@ -0,0 +1,180 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 17.HelloWorld_Mobile + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B} + My17HelloWorldforWindowsMobileonPC + Win32Proj + + + + Application + Unicode + true + Windows7.1SDK + + + Application + Unicode + true + Windows7.1SDK + + + Application + Unicode + Windows7.1SDK + + + Application + Unicode + Windows7.1SDK + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\17.HelloWorld_Mobile.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\17.HelloWorld_Mobile.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ..\..\bin\Win32-VisualStudio\17.HelloWorld_Mobile.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\17.HelloWorld_Mobile.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/17.HelloWorld_Mobile/17. HelloWorld for Windows Mobile on PC_vc11.vcxproj b/examples/17.HelloWorld_Mobile/17. HelloWorld for Windows Mobile on PC_vc11.vcxproj new file mode 100644 index 00000000..0f047407 --- /dev/null +++ b/examples/17.HelloWorld_Mobile/17. HelloWorld for Windows Mobile on PC_vc11.vcxproj @@ -0,0 +1,180 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 17.HelloWorld_Mobile + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B} + My17HelloWorldforWindowsMobileonPC + Win32Proj + + + + Application + Unicode + true + Windows7.1SDK + + + Application + Unicode + true + Windows7.1SDK + + + Application + Unicode + Windows7.1SDK + + + Application + Unicode + Windows7.1SDK + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\17.HelloWorld_Mobile.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\17.HelloWorld_Mobile.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ..\..\bin\Win32-VisualStudio\17.HelloWorld_Mobile.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\17.HelloWorld_Mobile.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/17.HelloWorld_Mobile/17. HelloWorld for Windows Mobile on PC_vc12.vcxproj b/examples/17.HelloWorld_Mobile/17. HelloWorld for Windows Mobile on PC_vc12.vcxproj new file mode 100644 index 00000000..30079f8b --- /dev/null +++ b/examples/17.HelloWorld_Mobile/17. HelloWorld for Windows Mobile on PC_vc12.vcxproj @@ -0,0 +1,180 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 17.HelloWorld_Mobile + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B} + My17HelloWorldforWindowsMobileonPC + Win32Proj + + + + Application + Unicode + true + Windows7.1SDK + + + Application + Unicode + true + Windows7.1SDK + + + Application + Unicode + Windows7.1SDK + + + Application + Unicode + Windows7.1SDK + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\17.HelloWorld_Mobile.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\17.HelloWorld_Mobile.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ..\..\bin\Win32-VisualStudio\17.HelloWorld_Mobile.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\17.HelloWorld_Mobile.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/17.HelloWorld_Mobile/HelloWorld_mobile.sln b/examples/17.HelloWorld_Mobile/HelloWorld_mobile.sln new file mode 100644 index 00000000..31932b79 --- /dev/null +++ b/examples/17.HelloWorld_Mobile/HelloWorld_mobile.sln @@ -0,0 +1,33 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "17.HelloWorld_mobile", "HelloWorld_mobile.vcproj", "{AD95D5D7-91D2-4030-B28D-23A6FE5C0359}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Irrlicht", "..\..\source\Irrlicht\Irrlicht_mobile6.vcproj", "{E08E042A-6C45-411B-92BE-3CC31331019F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Windows Mobile 6 Professional SDK (ARMV4I) = Debug|Windows Mobile 6 Professional SDK (ARMV4I) + Release|Windows Mobile 6 Professional SDK (ARMV4I) = Release|Windows Mobile 6 Professional SDK (ARMV4I) + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AD95D5D7-91D2-4030-B28D-23A6FE5C0359}.Debug|Windows Mobile 6 Professional SDK (ARMV4I).ActiveCfg = Debug|Windows Mobile 6 Professional SDK (ARMV4I) + {AD95D5D7-91D2-4030-B28D-23A6FE5C0359}.Debug|Windows Mobile 6 Professional SDK (ARMV4I).Build.0 = Debug|Windows Mobile 6 Professional SDK (ARMV4I) + {AD95D5D7-91D2-4030-B28D-23A6FE5C0359}.Debug|Windows Mobile 6 Professional SDK (ARMV4I).Deploy.0 = Debug|Windows Mobile 6 Professional SDK (ARMV4I) + {AD95D5D7-91D2-4030-B28D-23A6FE5C0359}.Release|Windows Mobile 6 Professional SDK (ARMV4I).ActiveCfg = Release|Windows Mobile 6 Professional SDK (ARMV4I) + {AD95D5D7-91D2-4030-B28D-23A6FE5C0359}.Release|Windows Mobile 6 Professional SDK (ARMV4I).Build.0 = Release|Windows Mobile 6 Professional SDK (ARMV4I) + {AD95D5D7-91D2-4030-B28D-23A6FE5C0359}.Release|Windows Mobile 6 Professional SDK (ARMV4I).Deploy.0 = Release|Windows Mobile 6 Professional SDK (ARMV4I) + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Windows Mobile 6 Professional SDK (ARMV4I).ActiveCfg = Debug|Windows Mobile 6 Professional SDK (ARMV4I) + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Windows Mobile 6 Professional SDK (ARMV4I).Build.0 = Debug|Windows Mobile 6 Professional SDK (ARMV4I) + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Windows Mobile 6 Professional SDK (ARMV4I).Deploy.0 = Debug|Windows Mobile 6 Professional SDK (ARMV4I) + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Windows Mobile 6 Professional SDK (ARMV4I).ActiveCfg = Release|Windows Mobile 6 Professional SDK (ARMV4I) + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Windows Mobile 6 Professional SDK (ARMV4I).Build.0 = Release|Windows Mobile 6 Professional SDK (ARMV4I) + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Windows Mobile 6 Professional SDK (ARMV4I).Deploy.0 = Release|Windows Mobile 6 Professional SDK (ARMV4I) + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/examples/17.HelloWorld_Mobile/HelloWorld_mobile.vcproj b/examples/17.HelloWorld_Mobile/HelloWorld_mobile.vcproj new file mode 100644 index 00000000..dcaca9ef --- /dev/null +++ b/examples/17.HelloWorld_Mobile/HelloWorld_mobile.vcproj @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/17.HelloWorld_Mobile/Makefile b/examples/17.HelloWorld_Mobile/Makefile new file mode 100644 index 00000000..a29ccaa2 --- /dev/null +++ b/examples/17.HelloWorld_Mobile/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 = 17.HelloWorld_Mobile +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 -lXcursor +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/17.HelloWorld_Mobile/main.cpp b/examples/17.HelloWorld_Mobile/main.cpp new file mode 100644 index 00000000..9db5806f --- /dev/null +++ b/examples/17.HelloWorld_Mobile/main.cpp @@ -0,0 +1,497 @@ +/** Deprecated. This was Example 017 Helloworld mobile for WinCE 6. + But WinCE6 support has been removed for Irrlicht 1.9. + If you still need that please use Irrlicht 1.8 or svn revision 5045 which was the last one to include it. + + Sources still kept for now as it compiles on other platform too. And we might use this example again + once we support Windows RT. +*/ + +#include + +#if defined ( _IRR_WINDOWS_ ) + #include +#endif + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +#pragma comment(lib, "Irrlicht.lib") + +class EventReceiver_basic : public IEventReceiver +{ +private: + IrrlichtDevice *Device; +public: + EventReceiver_basic ( IrrlichtDevice *device ): Device ( device ) {} + + virtual bool OnEvent(const SEvent& event) + { + if (event.EventType == EET_GUI_EVENT) + { + s32 id = event.GUIEvent.Caller->getID(); + + switch(event.GUIEvent.EventType) + { + case EGET_BUTTON_CLICKED: + if (id == 2) + { + Device->closeDevice(); + return true; + } break; + } + } + + return false; + } +}; + +class CSampleSceneNode : public ISceneNode +{ + aabbox3d Box; + S3DVertex Vertices[4]; + SMaterial Material; +public: + + CSampleSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id) + : ISceneNode(parent, mgr, id) + { + Material.Wireframe = false; + Material.Lighting = false; + + Vertices[0] = S3DVertex(0,0,10, 1,1,0, SColor(255,0,255,255), 0, 1); + Vertices[1] = S3DVertex(10,0,-10, 1,0,0, SColor(255,255,0,255), 1, 1); + Vertices[2] = S3DVertex(0,20,0, 0,1,1, SColor(255,255,255,0), 1, 0); + Vertices[3] = S3DVertex(-10,0,-10, 0,0,1, SColor(255,0,255,0), 0, 0); + Box.reset(Vertices[0].Pos); + for (s32 i=1; i<4; ++i) + Box.addInternalPoint(Vertices[i].Pos); + } + virtual void OnRegisterSceneNode() + { + if (IsVisible) + SceneManager->registerNodeForRendering(this); + + ISceneNode::OnRegisterSceneNode(); + } + + virtual void render() + { + u16 indices[] = { 0,2,3, 2,1,3, 1,0,3, 2,0,1 }; + IVideoDriver* driver = SceneManager->getVideoDriver(); + + driver->setMaterial(Material); + driver->setTransform(ETS_WORLD, AbsoluteTransformation); + driver->drawIndexedTriangleList(&Vertices[0], 4, &indices[0], 4); + } + + virtual const aabbox3d& getBoundingBox() const + { + return Box; + } + + virtual u32 getMaterialCount() + { + return 1; + } + + virtual SMaterial& getMaterial(u32 i) + { + return Material; + } +}; + +/*! + Startup a Windows Mobile Device +*/ +IrrlichtDevice *startup() +{ + // both software and burnings video can be used + E_DRIVER_TYPE driverType = EDT_SOFTWARE; // EDT_BURNINGSVIDEO; + + // create device + IrrlichtDevice *device = 0; + + // Use window mode on PC + device = createDevice(driverType, dimension2d(240, 320), 16, false ); + if ( 0 == device ) + return 0; + + IVideoDriver* driver = device->getVideoDriver(); + ISceneManager* smgr = device->getSceneManager(); + IGUIEnvironment* guienv = device->getGUIEnvironment(); + + // set the filesystem relative to the executable +#if defined (_IRR_WINDOWS_) + { + wchar_t buf[255]; + GetModuleFileNameW ( 0, buf, 255 ); + + io::path base = buf; + base = base.subString ( 0, base.findLast ( '\\' ) + 1 ); + device->getFileSystem()->addFileArchive ( base ); + } +#endif + + IGUIStaticText *text = guienv->addStaticText(L"FPS: 25", + rect(140,15,200,30), false, false, 0, 100 ); + + guienv->addButton(core::rect(200,10,238,30), 0, 2, L"Quit"); + + // add irrlicht logo + guienv->addImage(driver->getTexture("../../media/irrlichtlogo3.png"), + core::position2d(0,-2)); + return device; +} + +/*! +*/ +int run ( IrrlichtDevice *device ) +{ + while(device->run()) + if (device->isWindowActive()) + { + device->getVideoDriver()->beginScene(true, true, SColor(0,100,100,100)); + device->getSceneManager()->drawAll(); + device->getGUIEnvironment()->drawAll(); + device->getVideoDriver()->endScene (); + + IGUIElement *stat = device->getGUIEnvironment()-> + getRootGUIElement()->getElementFromId ( 100 ); + if ( stat ) + { + stringw str = L"FPS: "; + str += (s32)device->getVideoDriver()->getFPS(); + + stat->setText ( str.c_str() ); + } + } + + device->drop(); + return 0; +} + +/*! +*/ +int example_customscenenode() +{ + // create device + IrrlichtDevice *device = startup(); + if (device == 0) + return 1; // could not create selected driver. + + // create engine and camera + EventReceiver_basic receiver(device); + device->setEventReceiver(&receiver); + + IVideoDriver* driver = device->getVideoDriver(); + ISceneManager* smgr = device->getSceneManager(); + IGUIEnvironment* guienv = device->getGUIEnvironment(); + + + smgr->addCameraSceneNode(0, vector3df(0,-40,0), vector3df(0,0,0)); + + CSampleSceneNode *myNode = + new CSampleSceneNode(smgr->getRootSceneNode(), smgr, 666); + + ISceneNodeAnimator* anim = + smgr->createRotationAnimator(vector3df(0.8f, 0, 0.8f)); + + if(anim) + { + myNode->addAnimator(anim); + anim->drop(); + anim = 0; // As I shouldn't refer to it again, ensure that I can't + } + + myNode->drop(); + myNode = 0; // As I shouldn't refer to it again, ensure that I can't + + return run ( device ); +} + +class EventReceiver_terrain : public IEventReceiver +{ +public: + + EventReceiver_terrain(IrrlichtDevice *device, scene::ISceneNode* terrain, scene::ISceneNode* skybox, scene::ISceneNode* skydome) : + Device ( device ), Terrain(terrain), Skybox(skybox), Skydome(skydome), showBox(true) + { + Skybox->setVisible(true); + Skydome->setVisible(false); + } + + bool OnEvent(const SEvent& event) + { + if (event.EventType == EET_GUI_EVENT) + { + s32 id = event.GUIEvent.Caller->getID(); + + switch(event.GUIEvent.EventType) + { + case EGET_BUTTON_CLICKED: + if (id == 2) + { + Device->closeDevice(); + return true; + } break; + } + } + + // check if user presses the key 'W' or 'D' + if (event.EventType == irr::EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown) + { + switch (event.KeyInput.Key) + { + case irr::KEY_KEY_W: // switch wire frame mode + Terrain->setMaterialFlag(video::EMF_WIREFRAME, + !Terrain->getMaterial(0).Wireframe); + Terrain->setMaterialFlag(video::EMF_POINTCLOUD, false); + return true; + case irr::KEY_KEY_P: // switch wire frame mode + Terrain->setMaterialFlag(video::EMF_POINTCLOUD, + !Terrain->getMaterial(0).PointCloud); + Terrain->setMaterialFlag(video::EMF_WIREFRAME, false); + return true; + case irr::KEY_KEY_D: // toggle detail map + Terrain->setMaterialType( + 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; + } + } + + return false; + } + +private: + IrrlichtDevice *Device; + 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. This time with the advanced parameter handling. +*/ +int example_terrain() +{ + // create device + IrrlichtDevice *device = startup(); + if (device == 0) + return 1; // could not create selected driver. + + /* + First, we add standard stuff to the scene: A nice irrlicht engine + logo, a small help text, a user controlled camera, and we disable + the mouse cursor. + */ + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + gui::IGUIEnvironment* env = device->getGUIEnvironment(); + + + //set other font + //env->getSkin()->setFont(env->getFont("../../media/fontlucida.png")); + + // add some help text + env->addStaticText( + L"Press 'W' to change wireframe mode\nPress 'D' to toggle detail map\nPress 'S' to toggle skybox/skydome", + core::rect(5,250,235,320), true, true, 0, -1, true); + + // add camera + scene::ICameraSceneNode* camera = + smgr->addCameraSceneNodeFPS(0,100.0f,1.2f); + + camera->setPosition(core::vector3df(2700*2,255*2,2600*2)); + camera->setTarget(core::vector3df(2397*2,343*2,2700*2)); + camera->setFarValue(42000.0f); + + // disable mouse cursor + device->getCursorControl()->setVisible(false); + + /* + Here comes the terrain renderer scene node: We add it just like any + other scene node to the scene using + ISceneManager::addTerrainSceneNode(). The only parameter we use is a + file name to the heightmap we use. A heightmap is simply a gray scale + texture. The terrain renderer loads it and creates the 3D terrain from + it. + + To make the terrain look more big, we change the scale factor of + it to (40, 4.4, 40). Because we don't have any dynamic lights in the + scene, we switch off the lighting, and we set the file + terrain-texture.jpg as texture for the terrain and detailmap3.jpg as + second texture, called detail map. At last, we set the scale values for + the texture: The first texture will be repeated only one time over the + whole terrain, and the second one (detail map) 20 times. + */ + + // add terrain scene node + scene::ITerrainSceneNode* terrain = smgr->addTerrainSceneNode( + "../../media/terrain-heightmap.bmp", + 0, // parent node + -1, // node id + core::vector3df(0.f, 0.f, 0.f), // position + core::vector3df(0.f, 0.f, 0.f), // rotation + core::vector3df(40.f, 4.4f, 40.f), // scale + video::SColor ( 255, 255, 255, 255 ), // vertexColor + 5, // maxLOD + scene::ETPS_17, // patchSize + 4 // smoothFactor + ); + + if ( terrain ) + { + terrain->setMaterialFlag(video::EMF_LIGHTING, false); + + terrain->setMaterialTexture(0, + driver->getTexture("../../media/terrain-texture.jpg")); + terrain->setMaterialTexture(1, + driver->getTexture("../../media/detailmap3.jpg")); + + terrain->setMaterialType(video::EMT_DETAIL_MAP); + + terrain->scaleTexture(1.0f, 20.0f); + //terrain->setDebugDataVisible ( true ); + + /* + To be able to do collision with the terrain, we create a triangle selector. + If you want to know what triangle selectors do, just take a look into the + collision tutorial. The terrain triangle selector works together with the + terrain. To demonstrate this, we create a collision response animator + and attach it to the camera, so that the camera will not be able to fly + through the terrain. + */ + + // create triangle selector for the terrain + scene::ITriangleSelector* selector + = smgr->createTerrainTriangleSelector(terrain, 0); + terrain->setTriangleSelector(selector); + + // create collision response animator and attach it to the camera + scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator( + selector, camera, core::vector3df(60,100,60), + core::vector3df(0,0,0), + core::vector3df(0,50,0)); + selector->drop(); + camera->addAnimator(anim); + anim->drop(); + + /* If you need access to the terrain data you can also do this directly via the following code fragment. + */ + scene::CDynamicMeshBuffer* buffer = new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT); + terrain->getMeshBufferForLOD(*buffer, 0); + video::S3DVertex2TCoords* data = (video::S3DVertex2TCoords*)buffer->getVertexBuffer().getData(); + // Work on data or get the IndexBuffer with a similar call. + buffer->drop(); // When done drop the buffer again. + } + + /* + To make the user be able to switch between normal and wireframe mode, + we create an instance of the event receiver from above and let Irrlicht + know about it. In addition, we add the skybox which we already used in + lots of Irrlicht examples and a skydome, which is shown mutually + exclusive with the skybox by pressing 'S'. + */ + + // create skybox and skydome + driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); + + 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 + EventReceiver_terrain receiver( device, terrain, skybox, skydome); + device->setEventReceiver(&receiver); + + return run ( device ); +} + +/* +*/ +int example_helloworld() +{ + // create device + IrrlichtDevice *device = startup(); + if (device == 0) + return 1; // could not create selected driver. + + IVideoDriver* driver = device->getVideoDriver(); + ISceneManager* smgr = device->getSceneManager(); + IGUIEnvironment* guienv = device->getGUIEnvironment(); + + IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2"); + if (!mesh) + { + device->drop(); + return 1; + } + IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh ); + + /* + To let the mesh look a little bit nicer, we change its material. We + disable lighting because we do not have a dynamic light in here, and + the mesh would be totally black otherwise. Then we set the frame loop, + such that the predefined STAND animation is used. And last, we apply a + texture to the mesh. Without it the mesh would be drawn using only a + color. + */ + if (node) + { + node->setMaterialFlag(EMF_LIGHTING, false); + node->setMD2Animation(scene::EMAT_STAND); + node->setMaterialTexture( 0, driver->getTexture("../../media/sydney.bmp") ); + } + + /* + To look at the mesh, we place a camera into 3d space at the position + (0, 30, -40). The camera looks from there to (0,5,0), which is + approximately the place where our md2 model is. + */ + smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0)); + + EventReceiver_basic receiver(device); + device->setEventReceiver(&receiver); + + return run ( device ); + +} + +#if defined (_IRR_WINDOWS_) + #pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup") +#endif + +/* +*/ +int main() +{ + example_helloworld (); + example_customscenenode(); + //example_terrain(); +} + +/* +**/ diff --git a/examples/18.SplitScreen/Makefile b/examples/18.SplitScreen/Makefile new file mode 100644 index 00000000..fd414013 --- /dev/null +++ b/examples/18.SplitScreen/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 18.SplitScreen +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/18.SplitScreen/SplitScreen.cbp b/examples/18.SplitScreen/SplitScreen.cbp new file mode 100644 index 00000000..e1574a6d --- /dev/null +++ b/examples/18.SplitScreen/SplitScreen.cbp @@ -0,0 +1,55 @@ + + + + + + diff --git a/examples/18.SplitScreen/SplitScreen.vcproj b/examples/18.SplitScreen/SplitScreen.vcproj new file mode 100644 index 00000000..46cb6b78 --- /dev/null +++ b/examples/18.SplitScreen/SplitScreen.vcproj @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/18.SplitScreen/SplitScreen.xcodeproj/project.pbxproj b/examples/18.SplitScreen/SplitScreen.xcodeproj/project.pbxproj new file mode 100644 index 00000000..1201daf9 --- /dev/null +++ b/examples/18.SplitScreen/SplitScreen.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 18.SplitScreen.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 18.SplitScreen.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 18.SplitScreen.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 18.SplitScreen */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "18.SplitScreen" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 18.SplitScreen; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 18.SplitScreen.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "SplitScreen" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 18.SplitScreen */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "SplitScreen" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "18.SplitScreen" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/18.SplitScreen/SplitScreen.xcodeproj/xcshareddata/xcschemes/18.SplitScreen.xcscheme b/examples/18.SplitScreen/SplitScreen.xcodeproj/xcshareddata/xcschemes/18.SplitScreen.xcscheme new file mode 100644 index 00000000..0af4a284 --- /dev/null +++ b/examples/18.SplitScreen/SplitScreen.xcodeproj/xcshareddata/xcschemes/18.SplitScreen.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/18.SplitScreen/SplitScreen_vc10.vcxproj b/examples/18.SplitScreen/SplitScreen_vc10.vcxproj new file mode 100644 index 00000000..a0c211c7 --- /dev/null +++ b/examples/18.SplitScreen/SplitScreen_vc10.vcxproj @@ -0,0 +1,193 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 18.SplitScreen + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0} + 18.SplitScreen + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\18.SplitScreen.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\18.SplitScreen.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)SplitScreen.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\18.SplitScreen.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\18.SplitScreen.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/18.SplitScreen/SplitScreen_vc11.vcxproj b/examples/18.SplitScreen/SplitScreen_vc11.vcxproj new file mode 100644 index 00000000..e4707c58 --- /dev/null +++ b/examples/18.SplitScreen/SplitScreen_vc11.vcxproj @@ -0,0 +1,194 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 18.SplitScreen + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0} + 18.SplitScreen + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\18.SplitScreen.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)SplitScreen.pdb + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\18.SplitScreen.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)SplitScreen.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\18.SplitScreen.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\18.SplitScreen.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/18.SplitScreen/SplitScreen_vc12.vcxproj b/examples/18.SplitScreen/SplitScreen_vc12.vcxproj new file mode 100644 index 00000000..1c6c62d3 --- /dev/null +++ b/examples/18.SplitScreen/SplitScreen_vc12.vcxproj @@ -0,0 +1,194 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 18.SplitScreen + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0} + 18.SplitScreen + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\18.SplitScreen.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)SplitScreen.pdb + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\18.SplitScreen.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)SplitScreen.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\18.SplitScreen.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\18.SplitScreen.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/18.SplitScreen/SplitScreen_vc14.vcxproj b/examples/18.SplitScreen/SplitScreen_vc14.vcxproj new file mode 100644 index 00000000..7004b80c --- /dev/null +++ b/examples/18.SplitScreen/SplitScreen_vc14.vcxproj @@ -0,0 +1,194 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 18.SplitScreen + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0} + 18.SplitScreen + Win32Proj + + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\18.SplitScreen.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)SplitScreen.pdb + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\18.SplitScreen.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)SplitScreen.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\18.SplitScreen.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\18.SplitScreen.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/18.SplitScreen/main.cpp b/examples/18.SplitScreen/main.cpp new file mode 100644 index 00000000..600b7bf8 --- /dev/null +++ b/examples/18.SplitScreen/main.cpp @@ -0,0 +1,247 @@ +/** Example 018 Splitscreen + +A tutorial by Max Winkel. + +In this tutorial we'll learn how to use splitscreen (e.g. for racing-games) +with Irrlicht. We'll create a viewport divided +into 4 parts, with 3 fixed cameras and one user-controlled. + +Ok, let's start with the headers (I think there's +nothing to say about it) +*/ + +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +//Namespaces for the engine +using namespace irr; +using namespace core; +using namespace video; +using namespace scene; + +/* +Now we'll define the resolution in a constant for use in +initializing the device and setting up the viewport. In addition +we set up a global variable saying splitscreen is active or not. +*/ +//Resolution +const int ResX=800; +const int ResY=600; +const bool fullScreen=false; + +//Use SplitScreen? +bool SplitScreen=true; + +/* +Now we need four pointers to our cameras which are created later: +*/ +//cameras +ICameraSceneNode *camera[4]={0,0,0,0}; +/* +In our event-receiver we switch the SplitScreen-variable, +whenever the user press the S-key. All other events are sent +to the FPS camera. +*/ + +class MyEventReceiver : public IEventReceiver +{ + public: + virtual bool OnEvent(const SEvent& event) + { + //Key S enables/disables SplitScreen + if (event.EventType == irr::EET_KEY_INPUT_EVENT && + event.KeyInput.Key == KEY_KEY_S && event.KeyInput.PressedDown) + { + SplitScreen = !SplitScreen; + return true; + } + //Send all other events to camera4 + if (camera[3]) + return camera[3]->OnEvent(event); + return false; + } +}; + +/* +Ok, now the main-function: +First, we initialize the device, get the SourceManager and +VideoDriver, load an animated mesh from .md2 and a map from +.pk3. Because that's old stuff, I won't explain every step. +Just take care of the maps position. +*/ +int main() +{ + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + //Instance of the EventReceiver + MyEventReceiver receiver; + + //Initialise the engine + IrrlichtDevice *device = createDevice(driverType, + dimension2du(ResX,ResY), 32, fullScreen, + false, false, &receiver); + if (!device) + return 1; + + ISceneManager *smgr = device->getSceneManager(); + IVideoDriver *driver = device->getVideoDriver(); + + const io::path mediaPath = getExampleMediaPath(); + + //Load model + IAnimatedMesh *model = smgr->getMesh(mediaPath + "sydney.md2"); + if (!model) + return 1; + IAnimatedMeshSceneNode *model_node = smgr->addAnimatedMeshSceneNode(model); + //Load texture + if (model_node) + { + ITexture *texture = driver->getTexture(mediaPath + "sydney.bmp"); + model_node->setMaterialTexture(0,texture); + model_node->setMD2Animation(scene::EMAT_RUN); + //Disable lighting (we've got no light) + model_node->setMaterialFlag(EMF_LIGHTING,false); + } + + //Load map + device->getFileSystem()->addFileArchive(mediaPath + "map-20kdm2.pk3"); + IAnimatedMesh *map = smgr->getMesh("20kdm2.bsp"); + if (map) + { + ISceneNode *map_node = smgr->addOctreeSceneNode(map->getMesh(0)); + //Set position + map_node->setPosition(vector3df(-850,-220,-850)); + } + +/* +Now we create our four cameras. One is looking at the model +from the front, one from the top and one from the side. In +addition there's a FPS-camera which can be controlled by the +user. +*/ + // Create 3 fixed and one user-controlled cameras + //Front + camera[0] = smgr->addCameraSceneNode(0, vector3df(50,0,0), vector3df(0,0,0)); + //Top + camera[1] = smgr->addCameraSceneNode(0, vector3df(0,50,0), vector3df(0,0,0)); + //Left + camera[2] = smgr->addCameraSceneNode(0, vector3df(0,0,50), vector3df(0,0,0)); + //User-controlled + camera[3] = smgr->addCameraSceneNodeFPS(); + // don't start at sydney's position + if (camera[3]) + camera[3]->setPosition(core::vector3df(-50,0,-50)); + +/* +Create a variable for counting the fps and hide the mouse: +*/ + //Hide mouse + device->getCursorControl()->setVisible(false); + //We want to count the fps + int lastFPS = -1; + +/* +There wasn't much new stuff - till now! +Only by defining four cameras, the game won't be splitscreen. +To do this you need several steps: + - Set the viewport to the whole screen + - Begin a new scene (Clear screen) + + - The following 3 steps are repeated for every viewport in the splitscreen + - Set the viewport to the area you wish + - Activate the camera which should be "linked" with the viewport + - Render all objects + + - If you have a GUI: + - Set the viewport the whole screen + - Display the GUI + - End scene + +Sounds a little complicated, but you'll see it isn't: +*/ + + while(device->run()) + { + //Set the viewpoint to the whole screen and begin scene + driver->setViewPort(rect(0,0,ResX,ResY)); + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, SColor(255,100,100,100)); + //If SplitScreen is used + if (SplitScreen) + { + //Activate camera1 + smgr->setActiveCamera(camera[0]); + //Set viewpoint to the first quarter (left top) + driver->setViewPort(rect(0,0,ResX/2,ResY/2)); + //Draw scene + smgr->drawAll(); + //Activate camera2 + smgr->setActiveCamera(camera[1]); + //Set viewpoint to the second quarter (right top) + driver->setViewPort(rect(ResX/2,0,ResX,ResY/2)); + //Draw scene + smgr->drawAll(); + //Activate camera3 + smgr->setActiveCamera(camera[2]); + //Set viewpoint to the third quarter (left bottom) + driver->setViewPort(rect(0,ResY/2,ResX/2,ResY)); + //Draw scene + smgr->drawAll(); + //Set viewport the last quarter (right bottom) + driver->setViewPort(rect(ResX/2,ResY/2,ResX,ResY)); + } + //Activate camera4 + smgr->setActiveCamera(camera[3]); + //Draw scene + smgr->drawAll(); + driver->endScene(); + + /* + As you can probably see, the image is rendered for every + viewport separately. That means, that you'll loose much performance. + Ok, if you're asking "How do I have to set the viewport + to get this or that screen?", don't panic. It's really + easy: In the rect-function you define 4 coordinates: + - X-coordinate of the corner left top + - Y-coordinate of the corner left top + - X-coordinate of the corner right bottom + - Y-coordinate of the corner right bottom + + That means, if you want to split the screen into 2 viewports + you would give the following coordinates: + - 1st viewport: 0,0,ResX/2,ResY + - 2nd viewport: ResX/2,0,ResX,ResY + + If you didn't fully understand, just play around with the example + to check out what happens. + + Now we just view the current fps and shut down the engine, + when the user wants to: + */ + //Get and show fps + if (driver->getFPS() != lastFPS) + { + lastFPS = driver->getFPS(); + core::stringw tmp = L"Irrlicht SplitScreen-Example (FPS: "; + tmp += lastFPS; + tmp += ")"; + device->setWindowCaption(tmp.c_str()); + } + } + //Delete device + device->drop(); + return 0; +} +/* +That's it! Just compile and play around with the program. +Note: With the S-Key you can switch between using splitscreen +and not. +**/ + diff --git a/examples/19.MouseAndJoystick/Makefile b/examples/19.MouseAndJoystick/Makefile new file mode 100644 index 00000000..90d08fb3 --- /dev/null +++ b/examples/19.MouseAndJoystick/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 19.MouseAndJoystick +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/19.MouseAndJoystick/MouseAndJoystick.cbp b/examples/19.MouseAndJoystick/MouseAndJoystick.cbp new file mode 100644 index 00000000..7400072c --- /dev/null +++ b/examples/19.MouseAndJoystick/MouseAndJoystick.cbp @@ -0,0 +1,56 @@ + + + + + + diff --git a/examples/19.MouseAndJoystick/MouseAndJoystick.vcproj b/examples/19.MouseAndJoystick/MouseAndJoystick.vcproj new file mode 100644 index 00000000..84d8396f --- /dev/null +++ b/examples/19.MouseAndJoystick/MouseAndJoystick.vcproj @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/19.MouseAndJoystick/MouseAndJoystick.xcodeproj/project.pbxproj b/examples/19.MouseAndJoystick/MouseAndJoystick.xcodeproj/project.pbxproj new file mode 100644 index 00000000..5a3cddf3 --- /dev/null +++ b/examples/19.MouseAndJoystick/MouseAndJoystick.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 19.MouseAndJoystick.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 19.MouseAndJoystick.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 19.MouseAndJoystick.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 19.MouseAndJoystick */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "19.MouseAndJoystick" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 19.MouseAndJoystick; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 19.MouseAndJoystick.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "MouseAndJoystick" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 19.MouseAndJoystick */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "MouseAndJoystick" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "19.MouseAndJoystick" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/19.MouseAndJoystick/MouseAndJoystick.xcodeproj/xcshareddata/xcschemes/19.MouseAndJoystick.xcscheme b/examples/19.MouseAndJoystick/MouseAndJoystick.xcodeproj/xcshareddata/xcschemes/19.MouseAndJoystick.xcscheme new file mode 100644 index 00000000..a7e77e1d --- /dev/null +++ b/examples/19.MouseAndJoystick/MouseAndJoystick.xcodeproj/xcshareddata/xcschemes/19.MouseAndJoystick.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/19.MouseAndJoystick/MouseAndJoystick_vc10.vcxproj b/examples/19.MouseAndJoystick/MouseAndJoystick_vc10.vcxproj new file mode 100644 index 00000000..16c3a38f --- /dev/null +++ b/examples/19.MouseAndJoystick/MouseAndJoystick_vc10.vcxproj @@ -0,0 +1,231 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 19.MouseAndJoystick + {FE853A36-E0D1-4AC5-A792-B643E70D2953} + MouseAndJoystick + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/MouseAndJoystick.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\19.MouseAndJoystick.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/MouseAndJoystick.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\19.MouseAndJoystick.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/MouseAndJoystick.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\19.MouseAndJoystick.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/MouseAndJoystick.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\19.MouseAndJoystick.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/19.MouseAndJoystick/MouseAndJoystick_vc11.vcxproj b/examples/19.MouseAndJoystick/MouseAndJoystick_vc11.vcxproj new file mode 100644 index 00000000..16c3a38f --- /dev/null +++ b/examples/19.MouseAndJoystick/MouseAndJoystick_vc11.vcxproj @@ -0,0 +1,231 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 19.MouseAndJoystick + {FE853A36-E0D1-4AC5-A792-B643E70D2953} + MouseAndJoystick + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/MouseAndJoystick.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\19.MouseAndJoystick.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/MouseAndJoystick.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\19.MouseAndJoystick.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/MouseAndJoystick.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\19.MouseAndJoystick.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/MouseAndJoystick.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\19.MouseAndJoystick.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/19.MouseAndJoystick/MouseAndJoystick_vc12.vcxproj b/examples/19.MouseAndJoystick/MouseAndJoystick_vc12.vcxproj new file mode 100644 index 00000000..24dca694 --- /dev/null +++ b/examples/19.MouseAndJoystick/MouseAndJoystick_vc12.vcxproj @@ -0,0 +1,231 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 19.MouseAndJoystick + {FE853A36-E0D1-4AC5-A792-B643E70D2953} + MouseAndJoystick + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/MouseAndJoystick.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\19.MouseAndJoystick.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/MouseAndJoystick.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\19.MouseAndJoystick.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/MouseAndJoystick.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\19.MouseAndJoystick.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/MouseAndJoystick.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\19.MouseAndJoystick.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/19.MouseAndJoystick/MouseAndJoystick_vc14.vcxproj b/examples/19.MouseAndJoystick/MouseAndJoystick_vc14.vcxproj new file mode 100644 index 00000000..1c452c59 --- /dev/null +++ b/examples/19.MouseAndJoystick/MouseAndJoystick_vc14.vcxproj @@ -0,0 +1,231 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 19.MouseAndJoystick + {FE853A36-E0D1-4AC5-A792-B643E70D2953} + MouseAndJoystick + + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/MouseAndJoystick.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\19.MouseAndJoystick.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/MouseAndJoystick.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\19.MouseAndJoystick.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/MouseAndJoystick.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\19.MouseAndJoystick.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/MouseAndJoystick.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\19.MouseAndJoystick.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/19.MouseAndJoystick/main.cpp b/examples/19.MouseAndJoystick/main.cpp new file mode 100644 index 00000000..faa63057 --- /dev/null +++ b/examples/19.MouseAndJoystick/main.cpp @@ -0,0 +1,285 @@ +/** Example 019 Mouse and Joystick + +This tutorial builds on example 04.Movement which showed how to +handle keyboard events in Irrlicht. Here we'll handle mouse events +and joystick events, if you have a joystick connected and a device +that supports joysticks. These are currently Windows, Linux and SDL +devices. +*/ + +#ifdef _MSC_VER +// We'll define this to stop MSVC complaining about sprintf(). +#define _CRT_SECURE_NO_WARNINGS +#pragma comment(lib, "Irrlicht.lib") +#endif + +#include +#include "driverChoice.h" + +using namespace irr; + +/* +Just as we did in example 04.Movement, we'll store the latest state of the +mouse and the first joystick, updating them as we receive events. +*/ +class MyEventReceiver : public IEventReceiver +{ +public: + // We'll create a struct to record info on the mouse state + struct SMouseState + { + core::position2di Position; + bool LeftButtonDown; + SMouseState() : LeftButtonDown(false) { } + } MouseState; + + // This is the one method that we have to implement + virtual bool OnEvent(const SEvent& event) + { + // Remember the mouse state + if (event.EventType == irr::EET_MOUSE_INPUT_EVENT) + { + switch(event.MouseInput.Event) + { + case EMIE_LMOUSE_PRESSED_DOWN: + MouseState.LeftButtonDown = true; + break; + + case EMIE_LMOUSE_LEFT_UP: + MouseState.LeftButtonDown = false; + break; + + case EMIE_MOUSE_MOVED: + MouseState.Position.X = event.MouseInput.X; + MouseState.Position.Y = event.MouseInput.Y; + break; + + default: + // We won't use the wheel + break; + } + } + + // The state of each connected joystick is sent to us + // once every run() of the Irrlicht device. Store the + // state of the first joystick, ignoring other joysticks. + // This is currently only supported on Windows and Linux. + if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT + && event.JoystickEvent.Joystick == 0) + { + JoystickState = event.JoystickEvent; + } + + return false; + } + + const SEvent::SJoystickEvent & GetJoystickState(void) const + { + return JoystickState; + } + + const SMouseState & GetMouseState(void) const + { + return MouseState; + } + + + MyEventReceiver() + { + } + +private: + SEvent::SJoystickEvent JoystickState; +}; + + +/* +The event receiver for keeping the pressed keys is ready, the actual responses +will be made inside the render loop, right before drawing the scene. So lets +just create an irr::IrrlichtDevice and the scene node we want to move. We also +create some other additional scene nodes, to show that there are also some +different possibilities to move and animate scene nodes. +*/ +int main() +{ + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + // create device + MyEventReceiver receiver; + + IrrlichtDevice* device = createDevice(driverType, + core::dimension2d(640, 480), 16, false, false, false, &receiver); + + if (device == 0) + return 1; // could not create selected driver. + + + core::array joystickInfo; + if(device->activateJoysticks(joystickInfo)) + { + std::cout << "Joystick support is enabled and " << joystickInfo.size() << " joystick(s) are present." << std::endl; + + for(u32 joystick = 0; joystick < joystickInfo.size(); ++joystick) + { + std::cout << "Joystick " << joystick << ":" << std::endl; + std::cout << "\tName: '" << joystickInfo[joystick].Name.c_str() << "'" << std::endl; + std::cout << "\tAxes: " << joystickInfo[joystick].Axes << std::endl; + std::cout << "\tButtons: " << joystickInfo[joystick].Buttons << std::endl; + + std::cout << "\tHat is: "; + + switch(joystickInfo[joystick].PovHat) + { + case SJoystickInfo::POV_HAT_PRESENT: + std::cout << "present" << std::endl; + break; + + case SJoystickInfo::POV_HAT_ABSENT: + std::cout << "absent" << std::endl; + break; + + case SJoystickInfo::POV_HAT_UNKNOWN: + default: + std::cout << "unknown" << std::endl; + break; + } + } + } + else + { + std::cout << "Joystick support is not enabled." << std::endl; + } + + core::stringw tmp = L"Irrlicht Joystick Example ("; + tmp += joystickInfo.size(); + tmp += " joysticks)"; + device->setWindowCaption(tmp.c_str()); + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + + /* + We'll create an arrow mesh and move it around either with the joystick axis/hat, + or make it follow the mouse pointer. */ + scene::ISceneNode * node = smgr->addMeshSceneNode( + smgr->addArrowMesh( "Arrow", + video::SColor(255, 255, 0, 0), + video::SColor(255, 0, 255, 0), + 16,16, + 2.f, 1.3f, + 0.1f, 0.6f + ) + ); + node->setMaterialFlag(video::EMF_LIGHTING, false); + + scene::ICameraSceneNode * camera = smgr->addCameraSceneNode(); + camera->setPosition(core::vector3df(0, 0, -10)); + + // As in example 04, we'll use framerate independent movement. + u32 then = device->getTimer()->getTime(); + const f32 MOVEMENT_SPEED = 5.f; + + while(device->run()) + { + // Work out a frame delta time. + const u32 now = device->getTimer()->getTime(); + const f32 frameDeltaTime = (f32)(now - then) / 1000.f; // Time in seconds + then = now; + + bool movedWithJoystick = false; + core::vector3df nodePosition = node->getPosition(); + + if(joystickInfo.size() > 0) + { + f32 moveHorizontal = 0.f; // Range is -1.f for full left to +1.f for full right + f32 moveVertical = 0.f; // -1.f for full down to +1.f for full up. + + const SEvent::SJoystickEvent & joystickData = receiver.GetJoystickState(); + + // We receive the full analog range of the axes, and so have to implement our + // own dead zone. This is an empirical value, since some joysticks have more + // jitter or creep around the center point than others. We'll use 5% of the + // range as the dead zone, but generally you would want to give the user the + // option to change this. + const f32 DEAD_ZONE = 0.05f; + + moveHorizontal = + (f32)joystickData.Axis[SEvent::SJoystickEvent::AXIS_X] / 32767.f; + if(fabs(moveHorizontal) < DEAD_ZONE) + moveHorizontal = 0.f; + + moveVertical = + (f32)joystickData.Axis[SEvent::SJoystickEvent::AXIS_Y] / -32767.f; + if(fabs(moveVertical) < DEAD_ZONE) + moveVertical = 0.f; + + // POV hat info is only currently supported on Windows, but the value is + // guaranteed to be 65535 if it's not supported, so we can check its range. + const u16 povDegrees = joystickData.POV / 100; + if(povDegrees < 360) + { + if(povDegrees > 0 && povDegrees < 180) + moveHorizontal = 1.f; + else if(povDegrees > 180) + moveHorizontal = -1.f; + + if(povDegrees > 90 && povDegrees < 270) + moveVertical = -1.f; + else if(povDegrees > 270 || povDegrees < 90) + moveVertical = +1.f; + } + + if(!core::equals(moveHorizontal, 0.f) || !core::equals(moveVertical, 0.f)) + { + nodePosition.X += MOVEMENT_SPEED * frameDeltaTime * moveHorizontal; + nodePosition.Y += MOVEMENT_SPEED * frameDeltaTime * moveVertical; + movedWithJoystick = true; + } + } + + // If the arrow node isn't being moved with the joystick, then have it follow the mouse cursor. + if(!movedWithJoystick) + { + // Create a ray through the mouse cursor. + core::line3df ray = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates( + receiver.GetMouseState().Position, camera); + + // And intersect the ray with a plane around the node facing towards the camera. + core::plane3df plane(nodePosition, core::vector3df(0, 0, -1)); + core::vector3df mousePosition; + if(plane.getIntersectionWithLine(ray.start, ray.getVector(), mousePosition)) + { + // We now have a mouse position in 3d space; move towards it. + core::vector3df toMousePosition(mousePosition - nodePosition); + const f32 availableMovement = MOVEMENT_SPEED * frameDeltaTime; + + if(toMousePosition.getLength() <= availableMovement) + nodePosition = mousePosition; // Jump to the final position + else + nodePosition += toMousePosition.normalize() * availableMovement; // Move towards it + } + } + + node->setPosition(nodePosition); + + // Turn lighting on and off depending on whether the left mouse button is down. + node->setMaterialFlag(video::EMF_LIGHTING, receiver.GetMouseState().LeftButtonDown); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,113,113,133)); + smgr->drawAll(); // draw the 3d scene + driver->endScene(); + } + + /* + In the end, delete the Irrlicht device. + */ + device->drop(); + + return 0; +} + +/* +**/ diff --git a/examples/20.ManagedLights/Makefile b/examples/20.ManagedLights/Makefile new file mode 100644 index 00000000..6fe42450 --- /dev/null +++ b/examples/20.ManagedLights/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 20.ManagedLights +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/20.ManagedLights/ManagedLights.cbp b/examples/20.ManagedLights/ManagedLights.cbp new file mode 100644 index 00000000..5c94e995 --- /dev/null +++ b/examples/20.ManagedLights/ManagedLights.cbp @@ -0,0 +1,57 @@ + + + + + + diff --git a/examples/20.ManagedLights/ManagedLights.vcproj b/examples/20.ManagedLights/ManagedLights.vcproj new file mode 100644 index 00000000..850a8d27 --- /dev/null +++ b/examples/20.ManagedLights/ManagedLights.vcproj @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/20.ManagedLights/ManagedLights.xcodeproj/project.pbxproj b/examples/20.ManagedLights/ManagedLights.xcodeproj/project.pbxproj new file mode 100644 index 00000000..34988448 --- /dev/null +++ b/examples/20.ManagedLights/ManagedLights.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 20.ManagedLights.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 20.ManagedLights.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 20.ManagedLights.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 20.ManagedLights */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "20.ManagedLights" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 20.ManagedLights; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 20.ManagedLights.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "ManagedLights" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 20.ManagedLights */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "ManagedLights" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "20.ManagedLights" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/20.ManagedLights/ManagedLights.xcodeproj/xcshareddata/xcschemes/20.ManagedLights.xcscheme b/examples/20.ManagedLights/ManagedLights.xcodeproj/xcshareddata/xcschemes/20.ManagedLights.xcscheme new file mode 100644 index 00000000..5e640be9 --- /dev/null +++ b/examples/20.ManagedLights/ManagedLights.xcodeproj/xcshareddata/xcschemes/20.ManagedLights.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/20.ManagedLights/ManagedLights_vc10.vcxproj b/examples/20.ManagedLights/ManagedLights_vc10.vcxproj new file mode 100644 index 00000000..53568a92 --- /dev/null +++ b/examples/20.ManagedLights/ManagedLights_vc10.vcxproj @@ -0,0 +1,234 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 20.ManagedLights + {16007FE2-142B-47F8-93E1-519BA3F39E71} + ManagedLights + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/ManagedLights.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\Lib\Win32-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + ..\..\bin\Win32-VisualStudio\20.ManagedLights.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/ManagedLights.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + ..\..\bin\Win64-VisualStudio\20.ManagedLights.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/ManagedLights.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\20.ManagedLights.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/ManagedLights.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\20.ManagedLights.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/20.ManagedLights/ManagedLights_vc11.vcxproj b/examples/20.ManagedLights/ManagedLights_vc11.vcxproj new file mode 100644 index 00000000..53568a92 --- /dev/null +++ b/examples/20.ManagedLights/ManagedLights_vc11.vcxproj @@ -0,0 +1,234 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 20.ManagedLights + {16007FE2-142B-47F8-93E1-519BA3F39E71} + ManagedLights + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/ManagedLights.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\Lib\Win32-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + ..\..\bin\Win32-VisualStudio\20.ManagedLights.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/ManagedLights.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + ..\..\bin\Win64-VisualStudio\20.ManagedLights.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/ManagedLights.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\20.ManagedLights.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/ManagedLights.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\20.ManagedLights.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/20.ManagedLights/ManagedLights_vc12.vcxproj b/examples/20.ManagedLights/ManagedLights_vc12.vcxproj new file mode 100644 index 00000000..287f1b96 --- /dev/null +++ b/examples/20.ManagedLights/ManagedLights_vc12.vcxproj @@ -0,0 +1,234 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 20.ManagedLights + {16007FE2-142B-47F8-93E1-519BA3F39E71} + ManagedLights + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/ManagedLights.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\Lib\Win32-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + ..\..\bin\Win32-VisualStudio\20.ManagedLights.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/ManagedLights.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + ..\..\bin\Win64-VisualStudio\20.ManagedLights.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/ManagedLights.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\20.ManagedLights.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/ManagedLights.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\20.ManagedLights.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/20.ManagedLights/ManagedLights_vc14.vcxproj b/examples/20.ManagedLights/ManagedLights_vc14.vcxproj new file mode 100644 index 00000000..31e9e782 --- /dev/null +++ b/examples/20.ManagedLights/ManagedLights_vc14.vcxproj @@ -0,0 +1,234 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 20.ManagedLights + {16007FE2-142B-47F8-93E1-519BA3F39E71} + ManagedLights + + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/ManagedLights.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\Lib\Win32-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + ..\..\bin\Win32-VisualStudio\20.ManagedLights.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/ManagedLights.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + ..\..\bin\Win64-VisualStudio\20.ManagedLights.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/ManagedLights.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\20.ManagedLights.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/ManagedLights.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\20.ManagedLights.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/20.ManagedLights/main.cpp b/examples/20.ManagedLights/main.cpp new file mode 100644 index 00000000..f1fdb50d --- /dev/null +++ b/examples/20.ManagedLights/main.cpp @@ -0,0 +1,389 @@ +/** Example 020 Managed Lights + +Written by Colin MacDonald. This tutorial explains the use of the Light Manager +of Irrlicht. It enables the use of more dynamic light sources than the actual +hardware supports. Further applications of the Light Manager, such as per scene +node callbacks, are left out for simplicity of the example. +*/ + +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +using namespace irr; +using namespace core; + +#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 scene::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. + scene::ISceneManager * SceneManager; + core::array * SceneLightList; + scene::E_SCENE_NODE_RENDER_PASS CurrentRenderPass; + scene::ISceneNode * CurrentSceneNode; + +public: + CMyLightManager(scene::ISceneManager* sceneManager) + : Mode(NO_MANAGEMENT), RequestedMode(NO_MANAGEMENT), + SceneManager(sceneManager), SceneLightList(0), + CurrentRenderPass(scene::ESNRP_NONE), CurrentSceneNode(0) + { } + + // 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(scene::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(scene::E_SCENE_NODE_RENDER_PASS renderPass) + { + // I only want solid nodes to be lit, so after the solid pass, turn all lights off. + if (scene::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(scene::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 (scene::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() != scene::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) + { + scene::ISceneNode* lightNode = (*SceneLightList)[i]; + const 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) + { + if ((*SceneLightList)[i]->getType() != scene::ESNT_LIGHT) + continue; + scene::ILightSceneNode* lightNode = static_cast((*SceneLightList)[i]); + video::SLight & lightData = lightNode->getLightData(); + + if (video::ELT_DIRECTIONAL != lightData.Type) + lightNode->setVisible(false); + } + + scene::ISceneNode * parentZone = findZone(node); + if (parentZone) + turnOnZoneLights(parentZone); + } + } + + // Called after the specified scene node is rendered + virtual void OnNodePostRender(scene::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 + scene::ISceneNode * findZone(scene::ISceneNode * node) + { + if (!node) + return 0; + + if (node->getType() == scene::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(scene::ISceneNode * node) + { + core::list const & children = node->getChildren(); + for (core::list::ConstIterator child = children.begin(); + child != children.end(); ++child) + { + if ((*child)->getType() == scene::ESNT_LIGHT) + (*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(scene::ISceneNode* n, f64 d) + : node(n), distance(d) { } + + scene::ISceneNode* 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[]) +{ + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + IrrlichtDevice *device = createDevice(driverType, + dimension2d(640, 480), 32); + + if(!device) + return -1; + + f32 const lightRadius = 60.f; // Enough to reach the far side of each 'zone' + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + gui::IGUIEnvironment* guienv = device->getGUIEnvironment(); + + const io::path mediaPath = getExampleMediaPath(); + + gui::IGUISkin* skin = guienv->getSkin(); + if (skin) + { + skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255, 255, 255, 255)); + gui::IGUIFont* font = guienv->getFont(mediaPath + "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. + scene::ISceneNode * zoneRoot = smgr->addEmptySceneNode(); + zoneRoot->setPosition(vector3df(zoneX, zoneY, 0)); + + // Each zone contains a rotating cube + scene::IMeshSceneNode * node = smgr->addCubeSceneNode(15, zoneRoot); + scene::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. + scene::IBillboardSceneNode * billboard = smgr->addBillboardSceneNode(node); + billboard->setPosition(vector3df(0, -14, 30)); + billboard->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR ); + billboard->setMaterialTexture(0, driver->getTexture(mediaPath + "particle.bmp")); + billboard->setMaterialFlag(video::EMF_LIGHTING, false); + smgr->addLightSceneNode(billboard, vector3df(0, 0, 0), video::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(mediaPath + "particle.bmp")); + billboard->setMaterialFlag(video::EMF_LIGHTING, false); + smgr->addLightSceneNode(billboard, vector3df(0, 0, 0), video::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(mediaPath + "particle.bmp")); + billboard->setMaterialFlag(video::EMF_LIGHTING, false); + smgr->addLightSceneNode(billboard, vector3df(0, 0, 0), video::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(video::ECBF_COLOR | video::ECBF_DEPTH, video::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/21.Quake3Explorer/Makefile b/examples/21.Quake3Explorer/Makefile new file mode 100644 index 00000000..9b33360a --- /dev/null +++ b/examples/21.Quake3Explorer/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 21.Quake3Explorer +# List of source files, separated by spaces +Sources := main.cpp sound.cpp q3factory.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/21.Quake3Explorer/Quake3Explorer.cbp b/examples/21.Quake3Explorer/Quake3Explorer.cbp new file mode 100644 index 00000000..d32ac6f7 --- /dev/null +++ b/examples/21.Quake3Explorer/Quake3Explorer.cbp @@ -0,0 +1,78 @@ + + + + + + diff --git a/examples/21.Quake3Explorer/Quake3Explorer.vcproj b/examples/21.Quake3Explorer/Quake3Explorer.vcproj new file mode 100644 index 00000000..b869cc4c --- /dev/null +++ b/examples/21.Quake3Explorer/Quake3Explorer.vcproj @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/21.Quake3Explorer/Quake3Explorer.xcodeproj/project.pbxproj b/examples/21.Quake3Explorer/Quake3Explorer.xcodeproj/project.pbxproj new file mode 100644 index 00000000..ea3f8bdb --- /dev/null +++ b/examples/21.Quake3Explorer/Quake3Explorer.xcodeproj/project.pbxproj @@ -0,0 +1,336 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E3A0F831C1108A100545D10 /* q3factory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E3A0F7F1C1108A100545D10 /* q3factory.cpp */; }; + 5E3A0F841C1108A100545D10 /* sound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E3A0F811C1108A100545D10 /* sound.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 21.Quake3Explorer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 21.Quake3Explorer.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E3A0F7F1C1108A100545D10 /* q3factory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = q3factory.cpp; sourceTree = ""; }; + 5E3A0F801C1108A100545D10 /* q3factory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = q3factory.h; sourceTree = ""; }; + 5E3A0F811C1108A100545D10 /* sound.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sound.cpp; sourceTree = ""; }; + 5E3A0F821C1108A100545D10 /* sound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sound.h; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E3A0F7F1C1108A100545D10 /* q3factory.cpp */, + 5E3A0F801C1108A100545D10 /* q3factory.h */, + 5E3A0F811C1108A100545D10 /* sound.cpp */, + 5E3A0F821C1108A100545D10 /* sound.h */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 21.Quake3Explorer.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 21.Quake3Explorer */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "21.Quake3Explorer" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 21.Quake3Explorer; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 21.Quake3Explorer.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Quake3Explorer" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 21.Quake3Explorer */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E3A0F831C1108A100545D10 /* q3factory.cpp in Sources */, + 5E3A0F841C1108A100545D10 /* sound.cpp in Sources */, + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Quake3Explorer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "21.Quake3Explorer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/21.Quake3Explorer/Quake3Explorer.xcodeproj/xcshareddata/xcschemes/21.Quake3Explorer.xcscheme b/examples/21.Quake3Explorer/Quake3Explorer.xcodeproj/xcshareddata/xcschemes/21.Quake3Explorer.xcscheme new file mode 100644 index 00000000..4dfc785a --- /dev/null +++ b/examples/21.Quake3Explorer/Quake3Explorer.xcodeproj/xcshareddata/xcschemes/21.Quake3Explorer.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/21.Quake3Explorer/Quake3Explorer_vc10.vcxproj b/examples/21.Quake3Explorer/Quake3Explorer_vc10.vcxproj new file mode 100644 index 00000000..1a50c74b --- /dev/null +++ b/examples/21.Quake3Explorer/Quake3Explorer_vc10.vcxproj @@ -0,0 +1,199 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 21.Quake3Explorer + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD} + 21.Quake3Explorer + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\21.Quake3Explorer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\21.Quake3Explorer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)Quake3MapShader.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + FastCall + + + ..\..\bin\Win32-VisualStudio\21.Quake3Explorer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\21.Quake3Explorer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/21.Quake3Explorer/Quake3Explorer_vc11.vcxproj b/examples/21.Quake3Explorer/Quake3Explorer_vc11.vcxproj new file mode 100644 index 00000000..a2f2ff63 --- /dev/null +++ b/examples/21.Quake3Explorer/Quake3Explorer_vc11.vcxproj @@ -0,0 +1,200 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 21.Quake3Explorer + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD} + 21.Quake3Explorer + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\21.Quake3Explorer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)Quake3MapShader.pdb + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\21.Quake3Explorer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)Quake3MapShader.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\21.Quake3Explorer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + FastCall + + + ..\..\bin\Win64-VisualStudio\21.Quake3Explorer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/21.Quake3Explorer/Quake3Explorer_vc12.vcxproj b/examples/21.Quake3Explorer/Quake3Explorer_vc12.vcxproj new file mode 100644 index 00000000..f84bfc04 --- /dev/null +++ b/examples/21.Quake3Explorer/Quake3Explorer_vc12.vcxproj @@ -0,0 +1,200 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 21.Quake3Explorer + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD} + 21.Quake3Explorer + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\21.Quake3Explorer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)Quake3MapShader.pdb + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\21.Quake3Explorer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)Quake3MapShader.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + FastCall + + + ..\..\bin\Win32-VisualStudio\21.Quake3Explorer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\21.Quake3Explorer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/21.Quake3Explorer/Quake3Explorer_vc14.vcxproj b/examples/21.Quake3Explorer/Quake3Explorer_vc14.vcxproj new file mode 100644 index 00000000..eadcfea5 --- /dev/null +++ b/examples/21.Quake3Explorer/Quake3Explorer_vc14.vcxproj @@ -0,0 +1,200 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 21.Quake3Explorer + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD} + 21.Quake3Explorer + Win32Proj + + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\21.Quake3Explorer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)Quake3MapShader.pdb + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\21.Quake3Explorer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)Quake3MapShader.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + FastCall + + + ..\..\bin\Win32-VisualStudio\21.Quake3Explorer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + false + + + Level3 + + + FastCall + + + ..\..\bin\Win64-VisualStudio\21.Quake3Explorer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/21.Quake3Explorer/main.cpp b/examples/21.Quake3Explorer/main.cpp new file mode 100644 index 00000000..7b14c92f --- /dev/null +++ b/examples/21.Quake3Explorer/main.cpp @@ -0,0 +1,2189 @@ +/** Example 021 Quake3 Explorer + +This tutorial shows how to load different Quake 3 maps. + +Features: + - Load BSP Archives at Runtime from the menu + - Load a Map from the menu. Showing with Screenshot + - Set the VideoDriver at runtime from menu + - Adjust GammaLevel at runtime + - Create SceneNodes for the Shaders + - Load EntityList and create Entity SceneNodes + - Create Players with Weapons and with Collision Response + - Play music + +You can download the Quake III Arena demo ( copyright id software ) +at the following location: +ftp://ftp.idsoftware.com/idstuff/quake3/win32/q3ademo.exe + +Copyright 2006-2011 Burningwater, Thomas Alten +*/ + +#include +#include "driverChoice.h" +#include "exampleHelper.h" +#include "q3factory.h" +#include "sound.h" + +/* + Game Data is used to hold Data which is needed to drive the game +*/ +struct GameData +{ + GameData ( const path &startupDir) : + retVal(0), StartupDir(startupDir), createExDevice(0), Device(0) + { + setDefault (); + } + + void setDefault (); + s32 save ( const path &filename ); + s32 load ( const path &filename ); + + s32 debugState; + s32 gravityState; + s32 flyTroughState; + s32 wireFrame; + s32 guiActive; + s32 guiInputActive; + f32 GammaValue; + s32 retVal; + s32 sound; + + path StartupDir; + stringw CurrentMapName; + array CurrentArchiveList; + + vector3df PlayerPosition; + vector3df PlayerRotation; + + tQ3EntityList Variable; + + Q3LevelLoadParameter loadParam; + SIrrlichtCreationParameters deviceParam; + funcptr_createDeviceEx createExDevice; + IrrlichtDevice *Device; +}; + +/* + set default settings +*/ +void GameData::setDefault () +{ + debugState = EDS_OFF; + gravityState = 1; + flyTroughState = 0; + wireFrame = 0; + guiActive = 1; + guiInputActive = 0; + GammaValue = 1.f; + + // default deviceParam; +#if defined ( _IRR_WINDOWS_ ) + deviceParam.DriverType = EDT_DIRECT3D9; +#else + deviceParam.DriverType = EDT_OGLES2; // TODO: have to figure out what to use when we merge ogl-es with trunk. +#endif + deviceParam.WindowSize.Width = 800; + deviceParam.WindowSize.Height = 600; + deviceParam.Fullscreen = false; + deviceParam.Bits = 24; + deviceParam.ZBufferBits = 16; + deviceParam.Vsync = false; + deviceParam.AntiAlias = false; + + // default Quake3 loadParam + loadParam.defaultLightMapMaterial = EMT_LIGHTMAP; + loadParam.defaultModulate = EMFN_MODULATE_1X; + loadParam.defaultFilter = EMF_ANISOTROPIC_FILTER; + loadParam.verbose = 2; + loadParam.mergeShaderBuffer = 1; // merge meshbuffers with same material + loadParam.cleanUnResolvedMeshes = 1; // should unresolved meshes be cleaned. otherwise blue texture + loadParam.loadAllShaders = 1; // load all scripts in the script directory + loadParam.loadSkyShader = 0; // load sky Shader + loadParam.alpharef = 1; + + sound = 0; + + CurrentMapName = ""; + CurrentArchiveList.clear (); + + const io::path mediaPath = getExampleMediaPath(); + + // Explorer Media directory + CurrentArchiveList.push_back ( StartupDir + mediaPath ); + + // Add the original quake3 files before you load your custom map + // Most mods are using the original shaders, models&items&weapons + CurrentArchiveList.push_back("/q/baseq3/"); + + CurrentArchiveList.push_back(StartupDir + mediaPath + "map-20kdm2.pk3"); +} + +/* + Load the current game State from a typical quake3 cfg file +*/ +s32 GameData::load ( const path &filename ) +{ + if (!Device) + return 0; + + // the quake3 mesh loader can also handle *.shader and *.cfg file + IQ3LevelMesh* mesh = (IQ3LevelMesh*) Device->getSceneManager()->getMesh ( filename ); + if (!mesh) + return 0; + + tQ3EntityList &entityList = mesh->getEntityList (); + + stringc s; + u32 pos; + + for ( u32 e = 0; e != entityList.size (); ++e ) + { + //dumpShader ( s, &entityList[e], false ); + //printf ( s.c_str () ); + + for ( u32 g = 0; g != entityList[e].getGroupSize (); ++g ) + { + const SVarGroup *group = entityList[e].getGroup ( g ); + + for ( u32 index = 0; index < group->Variable.size (); ++index ) + { + const SVariable &v = group->Variable[index]; + pos = 0; + if ( v.name == "playerposition" ) + { + PlayerPosition = getAsVector3df ( v.content, pos ); + } + else + if ( v.name == "playerrotation" ) + { + PlayerRotation = getAsVector3df ( v.content, pos ); + } + } + } + } + + return 1; +} + +/* + Store the current game State in a quake3 configuration file +*/ +s32 GameData::save ( const path &filename ) +{ + return 0; + if (!Device) + return 0; + + c8 buf[128]; + u32 i; + + // Store current Archive for restart + CurrentArchiveList.clear(); + IFileSystem *fs = Device->getFileSystem(); + for ( i = 0; i != fs->getFileArchiveCount(); ++i ) + { + CurrentArchiveList.push_back ( fs->getFileArchive(i)->getFileList()->getPath() ); + } + + // Store Player Position and Rotation + ICameraSceneNode * camera = Device->getSceneManager()->getActiveCamera (); + if ( camera ) + { + PlayerPosition = camera->getPosition (); + PlayerRotation = camera->getRotation (); + } + + IWriteFile *file = fs->createAndWriteFile ( filename ); + if (!file) + return 0; + + snprintf_irr ( buf, 128, "playerposition %.f %.f %.f\nplayerrotation %.f %.f %.f\n", + PlayerPosition.X, PlayerPosition.Z, PlayerPosition.Y, + PlayerRotation.X, PlayerRotation.Z, PlayerRotation.Y); + file->write ( buf, (s32) strlen ( buf ) ); + for ( i = 0; i != fs->getFileArchiveCount(); ++i ) + { + snprintf_irr ( buf, 128, "archive %s\n",stringc ( fs->getFileArchive(i)->getFileList()->getPath() ).c_str () ); + file->write ( buf, (s32) strlen ( buf ) ); + } + + file->drop (); + return 1; +} + +/* + Representing a player +*/ +struct Q3Player : public IAnimationEndCallBack +{ + Q3Player () + : Device(0), MapParent(0), Mesh(0), WeaponNode(0), StartPositionCurrent(0) + { + animation[0] = 0; + memset(Anim, 0, sizeof(TimeFire)*4); + } + + virtual void OnAnimationEnd(IAnimatedMeshSceneNode* node); + + void create ( IrrlichtDevice *device, + IQ3LevelMesh* mesh, + ISceneNode *mapNode, + IMetaTriangleSelector *meta + ); + void shutdown (); + void setAnim ( const c8 *name ); + void respawn (); + void setpos ( const vector3df &pos, const vector3df& rotation ); + + ISceneNodeAnimatorCollisionResponse * cam() { return camCollisionResponse ( Device ); } + + IrrlichtDevice *Device; + ISceneNode* MapParent; + IQ3LevelMesh* Mesh; + IAnimatedMeshSceneNode* WeaponNode; + s32 StartPositionCurrent; + TimeFire Anim[4]; + c8 animation[64]; + c8 buf[64]; +}; + + +/* End player +*/ +void Q3Player::shutdown () +{ + setAnim ( 0 ); + + dropElement (WeaponNode); + + if ( Device ) + { + ICameraSceneNode* camera = Device->getSceneManager()->getActiveCamera(); + dropElement ( camera ); + Device = 0; + } + + MapParent = 0; + Mesh = 0; +} + + +/* create a new player +*/ +void Q3Player::create ( IrrlichtDevice *device, IQ3LevelMesh* mesh, ISceneNode *mapNode, IMetaTriangleSelector *meta ) +{ + setTimeFire ( Anim + 0, 200, FIRED ); + setTimeFire ( Anim + 1, 5000 ); + + if (!device) + return; + // load FPS weapon to Camera + Device = device; + Mesh = mesh; + MapParent = mapNode; + + ISceneManager *smgr = device->getSceneManager (); + IVideoDriver * driver = device->getVideoDriver(); + + ICameraSceneNode* camera = 0; + + core::array keyMap; + keyMap.set_used(12); + keyMap[0].Action = EKA_MOVE_FORWARD; + keyMap[0].KeyCode = KEY_UP; + keyMap[1].Action = EKA_MOVE_FORWARD; + keyMap[1].KeyCode = KEY_KEY_W; + + keyMap[2].Action = EKA_MOVE_BACKWARD; + keyMap[2].KeyCode = KEY_DOWN; + keyMap[3].Action = EKA_MOVE_BACKWARD; + keyMap[3].KeyCode = KEY_KEY_S; + + keyMap[4].Action = EKA_STRAFE_LEFT; + keyMap[4].KeyCode = KEY_LEFT; + keyMap[5].Action = EKA_STRAFE_LEFT; + keyMap[5].KeyCode = KEY_KEY_A; + + keyMap[6].Action = EKA_STRAFE_RIGHT; + keyMap[6].KeyCode = KEY_RIGHT; + keyMap[7].Action = EKA_STRAFE_RIGHT; + keyMap[7].KeyCode = KEY_KEY_D; + + keyMap[8].Action = EKA_JUMP_UP; + keyMap[8].KeyCode = KEY_KEY_J; + + keyMap[9].Action = EKA_CROUCH; + keyMap[9].KeyCode = KEY_KEY_C; + + keyMap[10].Action = EKA_ROTATE_LEFT; + keyMap[10].KeyCode = KEY_KEY_Q; + + keyMap[11].Action = EKA_ROTATE_RIGHT; + keyMap[11].KeyCode = KEY_KEY_E; + + camera = smgr->addCameraSceneNodeFPS(0, 100.0f, 0.6f, -1, keyMap.pointer(), keyMap.size(), false, 600.f); + camera->setName ( "First Person Camera" ); + //camera->setFOV ( 100.f * core::DEGTORAD ); + camera->setFarValue( 20000.f ); + + IAnimatedMeshMD2* weaponMesh = (IAnimatedMeshMD2*) smgr->getMesh("gun.md2"); + if ( 0 == weaponMesh ) + return; + + if ( weaponMesh->getMeshType() == EAMT_MD2 ) + { + s32 count = weaponMesh->getAnimationCount(); + for ( s32 i = 0; i != count; ++i ) + { + snprintf_irr ( buf, 64, "Animation: %s", weaponMesh->getAnimationName(i) ); + device->getLogger()->log(buf, ELL_INFORMATION); + } + } + + WeaponNode = smgr->addAnimatedMeshSceneNode( + weaponMesh, + smgr->getActiveCamera(), + 10, + vector3df( 0, 0, 0), + vector3df(-90,-90,90) + ); + WeaponNode->setMaterialFlag(EMF_LIGHTING, false); + WeaponNode->setMaterialTexture(0, driver->getTexture( "gun.jpg")); + WeaponNode->setLoopMode ( false ); + WeaponNode->setName ( "tommi the gun man" ); + + //create a collision auto response animator + ISceneNodeAnimator* anim = + smgr->createCollisionResponseAnimator( meta, camera, + vector3df(30,45,30), + getGravity ( "earth" ), + vector3df(0,40,0), + 0.0005f + ); + + camera->addAnimator( anim ); + anim->drop(); + + if ( meta ) + { + meta->drop (); + } + + respawn (); + setAnim ( "idle" ); +} + + +/* + so we need a good starting Position in the level. + we can ask the Quake3 Loader for all entities with class_name "info_player_deathmatch" +*/ +void Q3Player::respawn () +{ + if (!Device) + return; + ICameraSceneNode* camera = Device->getSceneManager()->getActiveCamera(); + + Device->getLogger()->log( "respawn" ); + + if (StartPositionCurrent >= Q3StartPosition(Mesh, camera, + StartPositionCurrent, cam()->getEllipsoidTranslation())) + StartPositionCurrent = 0; + else + ++StartPositionCurrent; +} + +/* + set Player position from saved coordinates +*/ +void Q3Player::setpos ( const vector3df &pos, const vector3df &rotation ) +{ + if (!Device) + return; + Device->getLogger()->log( "setpos" ); + + ICameraSceneNode* camera = Device->getSceneManager()->getActiveCamera(); + if ( camera ) + { + camera->setPosition ( pos ); + camera->setRotation ( rotation ); + //! New. FPSCamera and animators catches reset on animate 0 + camera->OnAnimate ( 0 ); + } +} + +/* set the Animation of the player and weapon +*/ +void Q3Player::setAnim ( const c8 *name ) +{ + if ( name ) + { + snprintf_irr ( animation, 64, "%s", name ); + if ( WeaponNode ) + { + WeaponNode->setAnimationEndCallback ( this ); + WeaponNode->setMD2Animation ( animation ); + } + } + else + { + animation[0] = 0; + if ( WeaponNode ) + { + WeaponNode->setAnimationEndCallback ( 0 ); + } + } +} + + +// Callback +void Q3Player::OnAnimationEnd(IAnimatedMeshSceneNode* node) +{ + setAnim ( 0 ); +} + + + +/* GUI Elements +*/ +struct GUI +{ + GUI () + { + memset ( this, 0, sizeof ( *this ) ); + } + + void drop() + { + dropElement ( Window ); + dropElement ( Logo ); + } + + IGUIComboBox* VideoDriver; + IGUIComboBox* VideoMode; + IGUICheckBox* FullScreen; + IGUICheckBox* Bit32; + IGUIScrollBar* MultiSample; + IGUIButton* SetVideoMode; + + IGUIScrollBar* Tesselation; + IGUIScrollBar* Gamma; + IGUICheckBox* Collision; + IGUICheckBox* Visible_Map; + IGUICheckBox* Visible_Shader; + IGUICheckBox* Visible_Fog; + IGUICheckBox* Visible_Unresolved; + IGUICheckBox* Visible_Skydome; + IGUIButton* Respawn; + + IGUITable* ArchiveList; + IGUIButton* ArchiveAdd; + IGUIButton* ArchiveRemove; + IGUIFileOpenDialog* ArchiveFileOpen; + IGUIButton* ArchiveUp; + IGUIButton* ArchiveDown; + + IGUIListBox* MapList; + IGUITreeView* SceneTree; + IGUIStaticText* StatusLine; + IGUIImage* Logo; + IGUIWindow* Window; +}; + + +/* + CQuake3EventHandler controls the game +*/ +class CQuake3EventHandler : public IEventReceiver +{ +public: + + CQuake3EventHandler( GameData *gameData ); + virtual ~CQuake3EventHandler (); + + void Animate(); + void Render(); + + void AddArchive ( const path& archiveName ); + void LoadMap ( const stringw& mapName, s32 collision ); + void CreatePlayers(); + void AddSky( u32 dome, const c8 *texture ); + Q3Player *GetPlayer ( u32 index ) { return &Player[index]; } + + void CreateGUI(); + void SetGUIActive( s32 command); + + bool OnEvent(const SEvent& eve); + + +private: + + GameData *Game; + + IQ3LevelMesh* Mesh; + ISceneNode* MapParent; + ISceneNode* ShaderParent; + ISceneNode* ItemParent; + ISceneNode* UnresolvedParent; + ISceneNode* BulletParent; + ISceneNode* FogParent; + ISceneNode * SkyNode; + IMetaTriangleSelector *Meta; + + c8 buf[256]; + + Q3Player Player[2]; + + struct SParticleImpact + { + u32 when; + vector3df pos; + vector3df outVector; + }; + array Impacts; + void useItem( Q3Player * player); + void createParticleImpacts( u32 now ); + + void createTextures (); + void addSceneTreeItem( ISceneNode * parent, IGUITreeViewNode* nodeParent); + + GUI gui; + void dropMap (); +}; + +/* Constructor +*/ +CQuake3EventHandler::CQuake3EventHandler( GameData *game ) +: Game(game), Mesh(0), MapParent(0), ShaderParent(0), ItemParent(0), UnresolvedParent(0), + BulletParent(0), FogParent(0), SkyNode(0), Meta(0) +{ + buf[0]=0; + // Also use 16 Bit Textures for 16 Bit RenderDevice + if ( Game->deviceParam.Bits == 16 ) + { + game->Device->getVideoDriver()->setTextureCreationFlag(ETCF_ALWAYS_16_BIT, true); + } + + // Quake3 Shader controls Z-Writing + game->Device->getSceneManager()->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true); + + // create internal textures + createTextures (); + + sound_init ( game->Device ); + + Game->Device->setEventReceiver ( this ); +} + + +// destructor +CQuake3EventHandler::~CQuake3EventHandler () +{ + Player[0].shutdown (); + sound_shutdown (); + + Game->save( "explorer.cfg" ); + + Game->Device->drop(); +} + + +// create runtime textures smog, fog +void CQuake3EventHandler::createTextures() +{ + IVideoDriver * driver = Game->Device->getVideoDriver(); + + dimension2du dim(64, 64); + + video::IImage* image; + u32 i; + u32 x; + u32 y; + u32 * data; + for ( i = 0; i != 8; ++i ) + { + image = driver->createImage ( video::ECF_A8R8G8B8, dim); + data = (u32*) image->getData (); + for ( y = 0; y != dim.Height; ++y ) + { + for ( x = 0; x != dim.Width; ++x ) + { + data [x] = 0xFFFFFFFF; + } + data = (u32*) ( (u8*) data + image->getPitch() ); + } + snprintf_irr ( buf, 64, "smoke_%02d", i ); + driver->addTexture( buf, image ); + image->drop (); + } + + // fog + for ( i = 0; i != 1; ++i ) + { + image = driver->createImage ( video::ECF_A8R8G8B8, dim); + data = (u32*) image->getData (); + for ( y = 0; y != dim.Height; ++y ) + { + for ( x = 0; x != dim.Width; ++x ) + { + data [x] = 0xFFFFFFFF; + } + data = (u32*) ( (u8*) data + image->getPitch() ); + } + snprintf_irr ( buf, 64, "fog_%02d", i ); + driver->addTexture( buf, image ); + image->drop (); + } +} + + +/* + create the GUI +*/ +void CQuake3EventHandler::CreateGUI() +{ + + IGUIEnvironment *env = Game->Device->getGUIEnvironment(); + IVideoDriver * driver = Game->Device->getVideoDriver(); + + gui.drop(); + + // set skin font + IGUIFont* font = env->getFont("fontlucida.png"); + if (font) + env->getSkin()->setFont(font); + env->getSkin()->setColor ( EGDC_BUTTON_TEXT, video::SColor(240,0xAA,0xAA,0xAA) ); + env->getSkin()->setColor ( EGDC_3D_HIGH_LIGHT, video::SColor(240,0x22,0x22,0x22) ); + env->getSkin()->setColor ( EGDC_3D_FACE, video::SColor(240,0x44,0x44,0x44) ); + env->getSkin()->setColor ( EGDC_EDITABLE, video::SColor(240,0x44,0x44,0x44) ); + env->getSkin()->setColor ( EGDC_FOCUSED_EDITABLE, video::SColor(240,0x54,0x54,0x54) ); + env->getSkin()->setColor ( EGDC_WINDOW, video::SColor(240,0x66,0x66,0x66) ); + + // minimal gui size 800x600 + dimension2d dim ( 800, 600 ); + dimension2d vdim ( Game->Device->getVideoDriver()->getScreenSize() ); + + if ( vdim.Height >= dim.Height && vdim.Width >= dim.Width ) + { + //dim = vdim; + } + else + { + } + + gui.Window = env->addWindow ( rect ( 0, 0, dim.Width, dim.Height ), false, L"Quake3 Explorer" ); + gui.Window->setToolTipText ( L"Quake3Explorer. Loads and show various BSP File Format and Shaders." ); + gui.Window->getCloseButton()->setToolTipText ( L"Quit Quake3 Explorer" ); + + // add a status line help text + gui.StatusLine = env->addStaticText( 0, rect( 5,dim.Height - 30,dim.Width - 5,dim.Height - 10), + false, false, gui.Window, -1, true + ); + + + env->addStaticText ( L"VideoDriver:", rect( dim.Width - 400, 24, dim.Width - 310, 40 ),false, false, gui.Window, -1, false ); + gui.VideoDriver = env->addComboBox(rect( dim.Width - 300, 24, dim.Width - 10, 40 ),gui.Window); + gui.VideoDriver->addItem(L"Direct3D 9.0c", EDT_DIRECT3D9 ); + gui.VideoDriver->addItem(L"OpenGL 1.5", EDT_OPENGL); + gui.VideoDriver->addItem(L"Software Renderer", EDT_OGLES1); + gui.VideoDriver->addItem(L"Burning's Video (TM) Thomas Alten", EDT_BURNINGSVIDEO); + gui.VideoDriver->setSelected ( gui.VideoDriver->getIndexForItemData ( Game->deviceParam.DriverType ) ); + gui.VideoDriver->setToolTipText ( L"Use a VideoDriver" ); + + env->addStaticText ( L"VideoMode:", rect( dim.Width - 400, 44, dim.Width - 310, 60 ),false, false, gui.Window, -1, false ); + gui.VideoMode = env->addComboBox(rect( dim.Width - 300, 44, dim.Width - 10, 60 ),gui.Window); + gui.VideoMode->setToolTipText ( L"Supported Screenmodes" ); + IVideoModeList *modeList = Game->Device->getVideoModeList(); + if ( modeList ) + { + s32 i; + for ( i = 0; i != modeList->getVideoModeCount (); ++i ) + { + u16 d = modeList->getVideoModeDepth ( i ); + if ( d < 16 ) + continue; + + u16 w = modeList->getVideoModeResolution ( i ).Width; + u16 h = modeList->getVideoModeResolution ( i ).Height; + u32 val = w << 16 | h; + + if ( gui.VideoMode->getIndexForItemData ( val ) >= 0 ) + continue; + + f32 aspect = (f32) w / (f32) h; + const c8 *a = ""; + if ( core::equals ( aspect, 1.3333333333f ) ) a = "4:3"; + else if ( core::equals ( aspect, 1.6666666f ) ) a = "15:9 widescreen"; + else if ( core::equals ( aspect, 1.7777777f ) ) a = "16:9 widescreen"; + else if ( core::equals ( aspect, 1.6f ) ) a = "16:10 widescreen"; + else if ( core::equals ( aspect, 2.133333f ) ) a = "20:9 widescreen"; + + snprintf_irr ( buf, sizeof ( buf ), "%d x %d, %s",w, h, a ); + gui.VideoMode->addItem ( stringw ( buf ).c_str(), val ); + } + } + gui.VideoMode->setSelected ( gui.VideoMode->getIndexForItemData ( + Game->deviceParam.WindowSize.Width << 16 | + Game->deviceParam.WindowSize.Height ) ); + + gui.FullScreen = env->addCheckBox ( Game->deviceParam.Fullscreen, rect( dim.Width - 400, 64, dim.Width - 300, 80 ), gui.Window,-1, L"Fullscreen" ); + gui.FullScreen->setToolTipText ( L"Set Fullscreen or Window Mode" ); + + gui.Bit32 = env->addCheckBox ( Game->deviceParam.Bits == 32, rect( dim.Width - 300, 64, dim.Width - 240, 80 ), gui.Window,-1, L"32Bit" ); + gui.Bit32->setToolTipText ( L"Use 16 or 32 Bit" ); + + env->addStaticText ( L"MultiSample:", rect( dim.Width - 235, 64, dim.Width - 150, 80 ),false, false, gui.Window, -1, false ); + gui.MultiSample = env->addScrollBar( true, rect( dim.Width - 150, 64, dim.Width - 70, 80 ), gui.Window,-1 ); + gui.MultiSample->setMin ( 0 ); + gui.MultiSample->setMax ( 8 ); + gui.MultiSample->setSmallStep ( 1 ); + gui.MultiSample->setLargeStep ( 1 ); + gui.MultiSample->setPos ( Game->deviceParam.AntiAlias ); + gui.MultiSample->setToolTipText ( L"Set the MultiSample (disable, 1x, 2x, 4x, 8x )" ); + + gui.SetVideoMode = env->addButton (rect( dim.Width - 60, 64, dim.Width - 10, 80 ), gui.Window, -1,L"set" ); + gui.SetVideoMode->setToolTipText ( L"Set Video Mode with current values" ); + + env->addStaticText ( L"Gamma:", rect( dim.Width - 400, 104, dim.Width - 310, 120 ),false, false, gui.Window, -1, false ); + gui.Gamma = env->addScrollBar( true, rect( dim.Width - 300, 104, dim.Width - 10, 120 ), gui.Window,-1 ); + gui.Gamma->setMin ( 50 ); + gui.Gamma->setMax ( 350 ); + gui.Gamma->setSmallStep ( 1 ); + gui.Gamma->setLargeStep ( 10 ); + gui.Gamma->setPos ( core::floor32 ( Game->GammaValue * 100.f ) ); + gui.Gamma->setToolTipText ( L"Adjust Gamma Ramp ( 0.5 - 3.5)" ); + Game->Device->setGammaRamp ( Game->GammaValue, Game->GammaValue, Game->GammaValue, 0.f, 0.f ); + + + env->addStaticText ( L"Tesselation:", rect( dim.Width - 400, 124, dim.Width - 310, 140 ),false, false, gui.Window, -1, false ); + gui.Tesselation = env->addScrollBar( true, rect( dim.Width - 300, 124, dim.Width - 10, 140 ), gui.Window,-1 ); + gui.Tesselation->setMin ( 2 ); + gui.Tesselation->setMax ( 12 ); + gui.Tesselation->setSmallStep ( 1 ); + gui.Tesselation->setLargeStep ( 1 ); + gui.Tesselation->setPos ( Game->loadParam.patchTesselation ); + gui.Tesselation->setToolTipText ( L"How smooth should curved surfaces be rendered" ); + + gui.Collision = env->addCheckBox ( true, rect( dim.Width - 400, 150, dim.Width - 300, 166 ), gui.Window,-1, L"Collision" ); + gui.Collision->setToolTipText ( L"Set collision on or off ( flythrough ). \nPress F7 on your Keyboard" ); + gui.Visible_Map = env->addCheckBox ( true, rect( dim.Width - 300, 150, dim.Width - 240, 166 ), gui.Window,-1, L"Map" ); + gui.Visible_Map->setToolTipText ( L"Show or not show the static part the Level. \nPress F3 on your Keyboard" ); + gui.Visible_Shader = env->addCheckBox ( true, rect( dim.Width - 240, 150, dim.Width - 170, 166 ), gui.Window,-1, L"Shader" ); + gui.Visible_Shader->setToolTipText ( L"Show or not show the Shader Nodes. \nPress F4 on your Keyboard" ); + gui.Visible_Fog = env->addCheckBox ( true, rect( dim.Width - 170, 150, dim.Width - 110, 166 ), gui.Window,-1, L"Fog" ); + gui.Visible_Fog->setToolTipText ( L"Show or not show the Fog Nodes. \nPress F5 on your Keyboard" ); + gui.Visible_Unresolved = env->addCheckBox ( true, rect( dim.Width - 110, 150, dim.Width - 10, 166 ), gui.Window,-1, L"Unresolved" ); + gui.Visible_Unresolved->setToolTipText ( L"Show the or not show the Nodes the Engine can't handle. \nPress F6 on your Keyboard" ); + gui.Visible_Skydome = env->addCheckBox ( true, rect( dim.Width - 110, 180, dim.Width - 10, 196 ), gui.Window,-1, L"Skydome" ); + gui.Visible_Skydome->setToolTipText ( L"Show the or not show the Skydome." ); + + //Respawn = env->addButton ( rect( dim.Width - 260, 90, dim.Width - 10, 106 ), 0,-1, L"Respawn" ); + + env->addStaticText ( L"Archives:", rect( 5, dim.Height - 530, dim.Width - 600,dim.Height - 514 ),false, false, gui.Window, -1, false ); + + gui.ArchiveAdd = env->addButton ( rect( dim.Width - 725, dim.Height - 530, dim.Width - 665, dim.Height - 514 ), gui.Window,-1, L"add" ); + gui.ArchiveAdd->setToolTipText ( L"Add an archive, usually packed zip-archives (*.pk3) to the Filesystem" ); + gui.ArchiveRemove = env->addButton ( rect( dim.Width - 660, dim.Height - 530, dim.Width - 600, dim.Height - 514 ), gui.Window,-1, L"del" ); + gui.ArchiveRemove->setToolTipText ( L"Remove the selected archive from the FileSystem." ); + gui.ArchiveUp = env->addButton ( rect( dim.Width - 575, dim.Height - 530, dim.Width - 515, dim.Height - 514 ), gui.Window,-1, L"up" ); + gui.ArchiveUp->setToolTipText ( L"Arrange Archive Look-up Hirachy. Move the selected Archive up" ); + gui.ArchiveDown = env->addButton ( rect( dim.Width - 510, dim.Height - 530, dim.Width - 440, dim.Height - 514 ), gui.Window,-1, L"down" ); + gui.ArchiveDown->setToolTipText ( L"Arrange Archive Look-up Hirachy. Move the selected Archive down" ); + + + gui.ArchiveList = env->addTable ( rect( 5,dim.Height - 510, dim.Width - 450,dim.Height - 410 ), gui.Window ); + gui.ArchiveList->addColumn ( L"Type", 0 ); + gui.ArchiveList->addColumn ( L"Real File Path", 1 ); + gui.ArchiveList->setColumnWidth ( 0, 60 ); + gui.ArchiveList->setColumnWidth ( 1, 284 ); + gui.ArchiveList->setToolTipText ( L"Show the attached Archives" ); + + + env->addStaticText ( L"Maps:", rect( 5, dim.Height - 400, dim.Width - 450,dim.Height - 380 ),false, false, gui.Window, -1, false ); + gui.MapList = env->addListBox ( rect( 5,dim.Height - 380, dim.Width - 450,dim.Height - 40 ), gui.Window, -1, true ); + gui.MapList->setToolTipText ( L"Show the current Maps in all Archives.\n Double-Click the Map to start the level" ); + + + // create a visible Scene Tree + env->addStaticText ( L"Scenegraph:", rect( dim.Width - 400, dim.Height - 400, dim.Width - 5,dim.Height - 380 ),false, false, gui.Window, -1, false ); + gui.SceneTree = env->addTreeView( rect( dim.Width - 400, dim.Height - 380, dim.Width - 5, dim.Height - 40 ), + gui.Window, -1, true, true, false ); + gui.SceneTree->setToolTipText ( L"Show the current Scenegraph" ); + gui.SceneTree->getRoot()->clearChildren(); + addSceneTreeItem ( Game->Device->getSceneManager()->getRootSceneNode(), gui.SceneTree->getRoot() ); + + + IGUIImageList* imageList = env->createImageList( driver->getTexture ( "iconlist.png" ), + dimension2di( 32, 32 ), true ); + + if ( imageList ) + { + gui.SceneTree->setImageList( imageList ); + imageList->drop (); + } + + + // load the engine logo + gui.Logo = env->addImage( driver->getTexture("irrlichtlogo3.png"), position2d(5, 16 ), true, 0 ); + gui.Logo->setToolTipText ( L"The great Irrlicht Engine" ); + + AddArchive ( "" ); +} + + +/* + Add an Archive to the FileSystems and updates the GUI +*/ +void CQuake3EventHandler::AddArchive ( const path& archiveName ) +{ + IFileSystem *fs = Game->Device->getFileSystem(); + u32 i; + + if ( archiveName.size () ) + { + bool exists = false; + for ( i = 0; i != fs->getFileArchiveCount(); ++i ) + { + if ( fs->getFileArchive(i)->getFileList()->getPath() == archiveName ) + { + exists = true; + break; + } + } + + if (!exists) + { + fs->addFileArchive(archiveName, true, false); + } + } + + // store the current archives in game data + // show the attached Archive in proper order + if ( gui.ArchiveList ) + { + gui.ArchiveList->clearRows(); + + for ( i = 0; i != fs->getFileArchiveCount(); ++i ) + { + IFileArchive * archive = fs->getFileArchive ( i ); + + u32 index = gui.ArchiveList->addRow(i); + + core::stringw typeName; + switch(archive->getType()) + { + case io::EFAT_ZIP: + typeName = "ZIP"; + break; + case io::EFAT_GZIP: + typeName = "gzip"; + break; + case io::EFAT_FOLDER: + typeName = "Mount"; + break; + case io::EFAT_PAK: + typeName = "PAK"; + break; + case io::EFAT_TAR: + typeName = "TAR"; + break; + default: + typeName = "archive"; + } + + gui.ArchiveList->setCellText ( index, 0, typeName ); + gui.ArchiveList->setCellText ( index, 1, archive->getFileList()->getPath() ); + } + } + + + // browse the archives for maps + if ( gui.MapList ) + { + gui.MapList->clear(); + + IGUISpriteBank *bank = Game->Device->getGUIEnvironment()->getSpriteBank("sprite_q3map"); + if ( 0 == bank ) + bank = Game->Device->getGUIEnvironment()->addEmptySpriteBank("sprite_q3map"); + + SGUISprite sprite; + SGUISpriteFrame frame; + core::rect r; + + bank->getSprites().clear(); + bank->getPositions().clear (); + gui.MapList->setSpriteBank ( bank ); + + u32 g = 0; + core::stringw s; + + // browse the attached file system + fs->setFileListSystem ( FILESYSTEM_VIRTUAL ); + fs->changeWorkingDirectoryTo ( "/maps/" ); + IFileList *fileList = fs->createFileList (); + fs->setFileListSystem ( FILESYSTEM_NATIVE ); + + for ( i=0; i< fileList->getFileCount(); ++i) + { + s = fileList->getFullFileName(i); + if ( s.find ( ".bsp" ) >= 0 ) + { + // get level screenshot. reformat texture to 128x128 + path c ( s ); + deletePathFromFilename ( c ); + cutFilenameExtension ( c, c ); + c = path ( "levelshots/" ) + c; + + dimension2du dim ( 128, 128 ); + IVideoDriver * driver = Game->Device->getVideoDriver(); + IImage* image = 0; + ITexture *tex = 0; + path filename; + + filename = c + ".jpg"; + if ( fs->existFile ( filename ) ) + image = driver->createImageFromFile( filename ); + if ( 0 == image ) + { + filename = c + ".tga"; + if ( fs->existFile ( filename ) ) + image = driver->createImageFromFile( filename ); + } + + if ( image ) + { + IImage* filter = driver->createImage ( video::ECF_R8G8B8, dim ); + image->copyToScalingBoxFilter ( filter, 0 ); + image->drop (); + image = filter; + } + + if ( image ) + { + tex = driver->addTexture ( filename, image ); + image->drop (); + } + + + bank->setTexture ( g, tex ); + + r.LowerRightCorner.X = dim.Width; + r.LowerRightCorner.Y = dim.Height; + gui.MapList->setItemHeight ( r.LowerRightCorner.Y + 4 ); + frame.rectNumber = bank->getPositions().size(); + frame.textureNumber = g; + + bank->getPositions().push_back(r); + + sprite.Frames.set_used ( 0 ); + sprite.Frames.push_back(frame); + sprite.frameTime = 0; + bank->getSprites().push_back(sprite); + + gui.MapList->addItem ( s.c_str (), g ); + g += 1; + } + } + fileList->drop (); + + gui.MapList->setSelected ( -1 ); + IGUIScrollBar * bar = (IGUIScrollBar*)gui.MapList->getElementFromId( 0 ); + if ( bar ) + bar->setPos ( 0 ); + + } + +} + +/* + clears the Map in Memory +*/ +void CQuake3EventHandler::dropMap () +{ + IVideoDriver * driver = Game->Device->getVideoDriver(); + + driver->removeAllHardwareBuffers (); + driver->removeAllTextures (); + + Player[0].shutdown (); + + + dropElement ( ItemParent ); + dropElement ( ShaderParent ); + dropElement ( UnresolvedParent ); + dropElement ( FogParent ); + dropElement ( BulletParent ); + + + Impacts.clear(); + + if ( Meta ) + { + Meta = 0; + } + + dropElement ( MapParent ); + dropElement ( SkyNode ); + + // clean out meshes, because textures are invalid + // TODO: better texture handling;-) + IMeshCache *cache = Game->Device->getSceneManager ()->getMeshCache(); + cache->clear (); + Mesh = 0; +} + +/* Load new map +*/ +void CQuake3EventHandler::LoadMap ( const stringw &mapName, s32 collision ) +{ + if ( 0 == mapName.size() ) + return; + + dropMap (); + + IFileSystem *fs = Game->Device->getFileSystem(); + ISceneManager *smgr = Game->Device->getSceneManager (); + + IReadFile* file = fs->createMemoryReadFile(&Game->loadParam, + sizeof(Game->loadParam), L"levelparameter.cfg", false); + + // load cfg file + smgr->getMesh( file ); + file->drop (); + + // load the actual map + Mesh = (IQ3LevelMesh*) smgr->getMesh(mapName); + if ( 0 == Mesh ) + return; + + /* + add the geometry mesh to the Scene ( polygon & patches ) + The Geometry mesh is optimised for faster drawing + */ + + IMesh *geometry = Mesh->getMesh(E_Q3_MESH_GEOMETRY); + if ( 0 == geometry || geometry->getMeshBufferCount() == 0) + return; + + Game->CurrentMapName = mapName; + + //create a collision list + Meta = 0; + + ITriangleSelector * selector = 0; + if (collision) + Meta = smgr->createMetaTriangleSelector(); + + //IMeshBuffer *b0 = geometry->getMeshBuffer(0); + //s32 minimalNodes = b0 ? core::s32_max ( 2048, b0->getVertexCount() / 32 ) : 2048; + s32 minimalNodes = 2048; + + MapParent = smgr->addOctreeSceneNode(geometry, 0, -1, minimalNodes); + MapParent->setName ( mapName ); + if ( Meta ) + { + selector = smgr->createOctreeTriangleSelector( geometry,MapParent, minimalNodes); + //selector = smgr->createTriangleSelector ( geometry, MapParent ); + Meta->addTriangleSelector( selector); + selector->drop (); + } + + // logical parent for the items + ItemParent = smgr->addEmptySceneNode(); + if ( ItemParent ) + ItemParent->setName ( "Item Container" ); + + ShaderParent = smgr->addEmptySceneNode(); + if ( ShaderParent ) + ShaderParent->setName ( "Shader Container" ); + + UnresolvedParent = smgr->addEmptySceneNode(); + if ( UnresolvedParent ) + UnresolvedParent->setName ( "Unresolved Container" ); + + FogParent = smgr->addEmptySceneNode(); + if ( FogParent ) + FogParent->setName ( "Fog Container" ); + + // logical parent for the bullets + BulletParent = smgr->addEmptySceneNode(); + if ( BulletParent ) + BulletParent->setName ( "Bullet Container" ); + + /* + now construct SceneNodes for each Shader + The Objects are stored in the quake mesh E_Q3_MESH_ITEMS + and the Shader ID is stored in the MaterialParameters + mostly dark looking skulls and moving lava.. or green flashing tubes? + */ + Q3ShaderFactory ( Game->loadParam, Game->Device, Mesh, E_Q3_MESH_ITEMS,ShaderParent, Meta, false ); + Q3ShaderFactory ( Game->loadParam, Game->Device, Mesh, E_Q3_MESH_FOG,FogParent, 0, false ); + Q3ShaderFactory ( Game->loadParam, Game->Device, Mesh, E_Q3_MESH_UNRESOLVED,UnresolvedParent, Meta, true ); + + /* + Now construct Models from Entity List + */ + Q3ModelFactory ( Game->loadParam, Game->Device, Mesh, ItemParent, false ); +} + +/* + Adds a SceneNode with an icon to the Scene Tree +*/ +void CQuake3EventHandler::addSceneTreeItem( ISceneNode * parent, IGUITreeViewNode* nodeParent) +{ + IGUITreeViewNode* node; + wchar_t msg[128]; + + s32 imageIndex; + list::ConstIterator it = parent->getChildren().begin(); + for (; it != parent->getChildren().end(); ++it) + { + switch ( (*it)->getType () ) + { + case ESNT_Q3SHADER_SCENE_NODE: imageIndex = 0; break; + case ESNT_CAMERA: imageIndex = 1; break; + case ESNT_EMPTY: imageIndex = 2; break; + case ESNT_MESH: imageIndex = 3; break; + case ESNT_OCTREE: imageIndex = 3; break; + case ESNT_ANIMATED_MESH: imageIndex = 4; break; + case ESNT_SKY_BOX: imageIndex = 5; break; + case ESNT_BILLBOARD: imageIndex = 6; break; + case ESNT_PARTICLE_SYSTEM: imageIndex = 7; break; + case ESNT_TEXT: imageIndex = 8; break; + default:imageIndex = -1; break; + } + + if ( imageIndex < 0 ) + { + swprintf_irr ( msg, 128, L"%hs,%hs", + Game->Device->getSceneManager ()->getSceneNodeTypeName ( (*it)->getType () ), + (*it)->getName() + ); + } + else + { + swprintf_irr ( msg, 128, L"%hs",(*it)->getName() ); + } + + node = nodeParent->addChildBack( msg, 0, imageIndex ); + + // Add all Animators + list::ConstIterator ait = (*it)->getAnimators().begin(); + for (; ait != (*it)->getAnimators().end(); ++ait) + { + imageIndex = -1; + swprintf_irr ( msg, 128, L"%hs", + Game->Device->getSceneManager ()->getAnimatorTypeName ( (*ait)->getType () ) + ); + + switch ( (*ait)->getType () ) + { + case ESNAT_FLY_CIRCLE: + case ESNAT_FLY_STRAIGHT: + case ESNAT_FOLLOW_SPLINE: + case ESNAT_ROTATION: + case ESNAT_TEXTURE: + case ESNAT_DELETION: + case ESNAT_COLLISION_RESPONSE: + case ESNAT_CAMERA_FPS: + case ESNAT_CAMERA_MAYA: + default: + break; + } + node->addChildBack( msg, 0, imageIndex ); + } + + addSceneTreeItem ( *it, node ); + } +} + + +// Adds life! +void CQuake3EventHandler::CreatePlayers() +{ + Player[0].create ( Game->Device, Mesh, MapParent, Meta ); +} + + +// Adds a skydome to the scene +void CQuake3EventHandler::AddSky( u32 dome, const c8 *texture) +{ + ISceneManager *smgr = Game->Device->getSceneManager (); + IVideoDriver * driver = Game->Device->getVideoDriver(); + + bool oldMipMapState = driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); + driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); + + if ( 0 == dome ) + { + // irrlicht order + //static const c8*p[] = { "ft", "lf", "bk", "rt", "up", "dn" }; + // quake3 order + static const c8*p[] = { "ft", "rt", "bk", "lf", "up", "dn" }; + + u32 i = 0; + snprintf_irr ( buf, 64, "%s_%s.jpg", texture, p[i] ); + SkyNode = smgr->addSkyBoxSceneNode( driver->getTexture ( buf ), 0, 0, 0, 0, 0 ); + + if (SkyNode) + { + for ( i = 0; i < 6; ++i ) + { + snprintf_irr ( buf, 64, "%s_%s.jpg", texture, p[i] ); + SkyNode->getMaterial(i).setTexture ( 0, driver->getTexture ( buf ) ); + } + } + } + else + if ( 1 == dome ) + { + snprintf_irr ( buf, 64, "%s.jpg", texture ); + SkyNode = smgr->addSkyDomeSceneNode( + driver->getTexture( buf ), 32,32, + 1.f, 1.f, 1000.f, 0, 11); + } + else + if ( 2 == dome ) + { + snprintf_irr ( buf, 64, "%s.jpg", texture ); + SkyNode = smgr->addSkyDomeSceneNode( + driver->getTexture( buf ), 16,8, + 0.95f, 2.f, 1000.f, 0, 11); + } + + if (SkyNode) + SkyNode->setName("Skydome"); + //SkyNode->getMaterial(0).ZBuffer = video::EMDF_DEPTH_LESS_EQUAL; + + driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, oldMipMapState); +} + + +// enable GUI elements +void CQuake3EventHandler::SetGUIActive( s32 command) +{ + bool inputState = false; + + ICameraSceneNode * camera = Game->Device->getSceneManager()->getActiveCamera (); + + switch ( command ) + { + case 0: Game->guiActive = 0; inputState = !Game->guiActive; break; + case 1: Game->guiActive = 1; inputState = !Game->guiActive;;break; + case 2: Game->guiActive ^= 1; inputState = !Game->guiActive;break; + case 3: + if ( camera ) + inputState = !camera->isInputReceiverEnabled(); + break; + } + + if ( camera ) + { + camera->setInputReceiverEnabled ( inputState ); + Game->Device->getCursorControl()->setVisible( !inputState ); + } + + if ( gui.Window ) + { + gui.Window->setVisible ( Game->guiActive != 0 ); + } + + if ( Game->guiActive && + gui.SceneTree && Game->Device->getGUIEnvironment()->getFocus() != gui.SceneTree + ) + { + gui.SceneTree->getRoot()->clearChildren(); + addSceneTreeItem ( Game->Device->getSceneManager()->getRootSceneNode(), gui.SceneTree->getRoot() ); + } + + Game->Device->getGUIEnvironment()->setFocus ( Game->guiActive ? gui.Window: 0 ); +} + + +/* + Handle game input +*/ +bool CQuake3EventHandler::OnEvent(const SEvent& eve) +{ + if ( eve.EventType == EET_LOG_TEXT_EVENT ) + { + return false; + } + + if ( Game->guiActive && eve.EventType == EET_GUI_EVENT ) + { + if ( eve.GUIEvent.Caller == gui.MapList && eve.GUIEvent.EventType == gui::EGET_LISTBOX_SELECTED_AGAIN ) + { + s32 selected = gui.MapList->getSelected(); + if ( selected >= 0 ) + { + stringw loadMap = gui.MapList->getListItem ( selected ); + if ( 0 == MapParent || loadMap != Game->CurrentMapName ) + { + printf ( "Loading map %ls\n", loadMap.c_str() ); + LoadMap ( loadMap , 1 ); + if ( 0 == Game->loadParam.loadSkyShader ) + { + AddSky ( 1, "skydome2" ); + } + CreatePlayers (); + CreateGUI (); + SetGUIActive ( 0 ); + return true; + } + } + } + else + if ( eve.GUIEvent.Caller == gui.ArchiveRemove && eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED ) + { + Game->Device->getFileSystem()->removeFileArchive( gui.ArchiveList->getSelected() ); + Game->CurrentMapName = ""; + AddArchive ( "" ); + } + else + if ( eve.GUIEvent.Caller == gui.ArchiveAdd && eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED ) + { + if ( 0 == gui.ArchiveFileOpen ) + { + Game->Device->getFileSystem()->setFileListSystem ( FILESYSTEM_NATIVE ); + gui.ArchiveFileOpen = Game->Device->getGUIEnvironment()->addFileOpenDialog ( L"Add Game Archive" , false,gui.Window ); + } + } + else + if ( eve.GUIEvent.Caller == gui.ArchiveFileOpen && eve.GUIEvent.EventType == gui::EGET_FILE_SELECTED ) + { + AddArchive ( gui.ArchiveFileOpen->getFileNameP() ); + gui.ArchiveFileOpen = 0; + } + else + if ( eve.GUIEvent.Caller == gui.ArchiveFileOpen && eve.GUIEvent.EventType == gui::EGET_DIRECTORY_SELECTED ) + { + AddArchive ( gui.ArchiveFileOpen->getDirectoryName() ); + } + else + if ( eve.GUIEvent.Caller == gui.ArchiveFileOpen && eve.GUIEvent.EventType == gui::EGET_FILE_CHOOSE_DIALOG_CANCELLED ) + { + gui.ArchiveFileOpen = 0; + } + else + if ( ( eve.GUIEvent.Caller == gui.ArchiveUp || eve.GUIEvent.Caller == gui.ArchiveDown ) && + eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED ) + { + s32 rel = eve.GUIEvent.Caller == gui.ArchiveUp ? -1 : 1; + if ( Game->Device->getFileSystem()->moveFileArchive ( gui.ArchiveList->getSelected (), rel ) ) + { + s32 newIndex = core::s32_clamp ( gui.ArchiveList->getSelected() + rel, 0, gui.ArchiveList->getRowCount() - 1 ); + AddArchive ( "" ); + gui.ArchiveList->setSelected ( newIndex ); + Game->CurrentMapName = ""; + } + } + else + if ( eve.GUIEvent.Caller == gui.VideoDriver && eve.GUIEvent.EventType == gui::EGET_COMBO_BOX_CHANGED ) + { + Game->deviceParam.DriverType = (E_DRIVER_TYPE) gui.VideoDriver->getItemData ( gui.VideoDriver->getSelected() ); + } + else + if ( eve.GUIEvent.Caller == gui.VideoMode && eve.GUIEvent.EventType == gui::EGET_COMBO_BOX_CHANGED ) + { + u32 val = gui.VideoMode->getItemData ( gui.VideoMode->getSelected() ); + Game->deviceParam.WindowSize.Width = val >> 16; + Game->deviceParam.WindowSize.Height = val & 0xFFFF; + } + else + if ( eve.GUIEvent.Caller == gui.FullScreen && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED ) + { + Game->deviceParam.Fullscreen = gui.FullScreen->isChecked(); + } + else + if ( eve.GUIEvent.Caller == gui.Bit32 && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED ) + { + Game->deviceParam.Bits = gui.Bit32->isChecked() ? 32 : 16; + } + else + if ( eve.GUIEvent.Caller == gui.MultiSample && eve.GUIEvent.EventType == gui::EGET_SCROLL_BAR_CHANGED ) + { + Game->deviceParam.AntiAlias = gui.MultiSample->getPos(); + } + else + if ( eve.GUIEvent.Caller == gui.Tesselation && eve.GUIEvent.EventType == gui::EGET_SCROLL_BAR_CHANGED ) + { + Game->loadParam.patchTesselation = gui.Tesselation->getPos (); + } + else + if ( eve.GUIEvent.Caller == gui.Gamma && eve.GUIEvent.EventType == gui::EGET_SCROLL_BAR_CHANGED ) + { + Game->GammaValue = gui.Gamma->getPos () * 0.01f; + Game->Device->setGammaRamp ( Game->GammaValue, Game->GammaValue, Game->GammaValue, 0.f, 0.f ); + } + else + if ( eve.GUIEvent.Caller == gui.SetVideoMode && eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED ) + { + Game->retVal = 2; + Game->Device->closeDevice(); + } + else + if ( eve.GUIEvent.Caller == gui.Window && eve.GUIEvent.EventType == gui::EGET_ELEMENT_CLOSED ) + { + Game->Device->closeDevice(); + } + else + if ( eve.GUIEvent.Caller == gui.Collision && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED ) + { + // set fly through active + Game->flyTroughState ^= 1; + Player[0].cam()->setAnimateTarget ( Game->flyTroughState == 0 ); + + printf ( "collision %d\n", Game->flyTroughState == 0 ); + } + else + if ( eve.GUIEvent.Caller == gui.Visible_Map && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED ) + { + bool v = gui.Visible_Map->isChecked(); + + if ( MapParent ) + { + printf ( "static node set visible %d\n",v ); + MapParent->setVisible ( v ); + } + } + else + if ( eve.GUIEvent.Caller == gui.Visible_Shader && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED ) + { + bool v = gui.Visible_Shader->isChecked(); + + if ( ShaderParent ) + { + printf ( "shader node set visible %d\n",v ); + ShaderParent->setVisible ( v ); + } + } + else + if ( eve.GUIEvent.Caller == gui.Visible_Skydome && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED ) + { + if ( SkyNode ) + { + bool v = !SkyNode->isVisible(); + printf ( "skynode set visible %d\n",v ); + SkyNode->setVisible ( v ); + } + } + else + if ( eve.GUIEvent.Caller == gui.Respawn && eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED ) + { + Player[0].respawn (); + } + + return false; + } + + // fire + if ((eve.EventType == EET_KEY_INPUT_EVENT && eve.KeyInput.Key == KEY_SPACE && + eve.KeyInput.PressedDown == false) || + (eve.EventType == EET_MOUSE_INPUT_EVENT && eve.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) + ) + { + ICameraSceneNode * camera = Game->Device->getSceneManager()->getActiveCamera (); + if ( camera && camera->isInputReceiverEnabled () ) + { + useItem( Player + 0 ); + } + } + + // gui active + if ((eve.EventType == EET_KEY_INPUT_EVENT && eve.KeyInput.Key == KEY_F1 && + eve.KeyInput.PressedDown == false) || + (eve.EventType == EET_MOUSE_INPUT_EVENT && eve.MouseInput.Event == EMIE_RMOUSE_LEFT_UP) + ) + { + SetGUIActive ( 2 ); + } + + // check if user presses the key + if ( eve.EventType == EET_KEY_INPUT_EVENT && eve.KeyInput.PressedDown == false) + { + // Escape toggles camera Input + if ( eve.KeyInput.Key == irr::KEY_ESCAPE ) + { + SetGUIActive ( 3 ); + } + else + if (eve.KeyInput.Key == KEY_F11) + { + // screenshot are taken without gamma! + IImage* image = Game->Device->getVideoDriver()->createScreenShot(); + if (image) + { + core::vector3df pos; + core::vector3df rot; + ICameraSceneNode * cam = Game->Device->getSceneManager()->getActiveCamera (); + if ( cam ) + { + pos = cam->getPosition (); + rot = cam->getRotation (); + } + + snprintf_irr(buf, 256, "%s_%ls_%.0f_%.0f_%.0f_%.0f_%.0f_%.0f.jpg", + DRIVER_TYPE_NAMES_SHORT[Game->Device->getVideoDriver()->getDriverType()], + Game->CurrentMapName.c_str(), + pos.X, pos.Y, pos.Z, + rot.X, rot.Y, rot.Z + ); + path filename ( buf ); + filename.replace ( '/', '_' ); + printf ( "screenshot : %s\n", filename.c_str() ); + Game->Device->getVideoDriver()->writeImageToFile(image, filename, 100 ); + image->drop(); + } + } + else + if (eve.KeyInput.Key == KEY_F9) + { + s32 value = EDS_OFF; + + Game->debugState = ( Game->debugState + 1 ) & 3; + + switch ( Game->debugState ) + { + case 1: value = EDS_NORMALS | EDS_MESH_WIRE_OVERLAY | EDS_BBOX_ALL; break; + case 2: value = EDS_NORMALS | EDS_MESH_WIRE_OVERLAY | EDS_SKELETON; break; + } +/* + // set debug map data on/off + debugState = debugState == EDS_OFF ? + EDS_NORMALS | EDS_MESH_WIRE_OVERLAY | EDS_BBOX_ALL: + EDS_OFF; +*/ + if ( ItemParent ) + { + list::ConstIterator it = ItemParent->getChildren().begin(); + for (; it != ItemParent->getChildren().end(); ++it) + { + (*it)->setDebugDataVisible ( value ); + } + } + + if ( ShaderParent ) + { + list::ConstIterator it = ShaderParent->getChildren().begin(); + for (; it != ShaderParent->getChildren().end(); ++it) + { + (*it)->setDebugDataVisible ( value ); + } + } + + if ( UnresolvedParent ) + { + list::ConstIterator it = UnresolvedParent->getChildren().begin(); + for (; it != UnresolvedParent->getChildren().end(); ++it) + { + (*it)->setDebugDataVisible ( value ); + } + } + + if ( FogParent ) + { + list::ConstIterator it = FogParent->getChildren().begin(); + for (; it != FogParent->getChildren().end(); ++it) + { + (*it)->setDebugDataVisible ( value ); + } + } + + if ( SkyNode ) + { + SkyNode->setDebugDataVisible ( value ); + } + + } + else + if (eve.KeyInput.Key == KEY_F8) + { + // set gravity on/off + Game->gravityState ^= 1; + Player[0].cam()->setGravity ( getGravity ( Game->gravityState ? "earth" : "none" ) ); + printf ( "gravity %s\n", Game->gravityState ? "earth" : "none" ); + } + else + if (eve.KeyInput.Key == KEY_F7) + { + // set fly through active + Game->flyTroughState ^= 1; + Player[0].cam()->setAnimateTarget ( Game->flyTroughState == 0 ); + if ( gui.Collision ) + gui.Collision->setChecked ( Game->flyTroughState == 0 ); + + printf ( "collision %d\n", Game->flyTroughState == 0 ); + } + else + if (eve.KeyInput.Key == KEY_F2) + { + Player[0].respawn (); + } + else + if (eve.KeyInput.Key == KEY_F3) + { + if ( MapParent ) + { + bool v = !MapParent->isVisible (); + printf ( "static node set visible %d\n",v ); + MapParent->setVisible ( v ); + if ( gui.Visible_Map ) + gui.Visible_Map->setChecked ( v ); + } + } + else + if (eve.KeyInput.Key == KEY_F4) + { + if ( ShaderParent ) + { + bool v = !ShaderParent->isVisible (); + printf ( "shader node set visible %d\n",v ); + ShaderParent->setVisible ( v ); + if ( gui.Visible_Shader ) + gui.Visible_Shader->setChecked ( v ); + } + } + else + if (eve.KeyInput.Key == KEY_F5) + { + if ( FogParent ) + { + bool v = !FogParent->isVisible (); + printf ( "fog node set visible %d\n",v ); + FogParent->setVisible ( v ); + if ( gui.Visible_Fog ) + gui.Visible_Fog->setChecked ( v ); + } + + } + else + if (eve.KeyInput.Key == KEY_F6) + { + if ( UnresolvedParent ) + { + bool v = !UnresolvedParent->isVisible (); + printf ( "unresolved node set visible %d\n",v ); + UnresolvedParent->setVisible ( v ); + if ( gui.Visible_Unresolved ) + gui.Visible_Unresolved->setChecked ( v ); + } + } + } + + // check if user presses the key C ( for crouch) + if ( eve.EventType == EET_KEY_INPUT_EVENT && eve.KeyInput.Key == KEY_KEY_C ) + { + // crouch + ISceneNodeAnimatorCollisionResponse *anim = Player[0].cam (); + if ( anim && 0 == Game->flyTroughState ) + { + if ( false == eve.KeyInput.PressedDown ) + { + // stand up + anim->setEllipsoidRadius ( vector3df(30,45,30) ); + anim->setEllipsoidTranslation ( vector3df(0,40,0)); + + } + else + { + // on your knees + anim->setEllipsoidRadius ( vector3df(30,20,30) ); + anim->setEllipsoidTranslation ( vector3df(0,20,0)); + } + return true; + } + } + return false; +} + + + +/* + useItem +*/ +void CQuake3EventHandler::useItem( Q3Player * player) +{ + ISceneManager* smgr = Game->Device->getSceneManager(); + ICameraSceneNode* camera = smgr->getActiveCamera(); + + if (!camera) + return; + + SParticleImpact imp; + imp.when = 0; + + // get line of camera + + vector3df start = camera->getPosition(); + + if ( player->WeaponNode ) + { + start.X += 0.f; + start.Y += 0.f; + start.Z += 0.f; + } + + vector3df end = (camera->getTarget() - start); + end.normalize(); + start += end*20.0f; + + end = start + (end * camera->getFarValue()); + + triangle3df triangle; + line3d line(start, end); + + // get intersection point with map + scene::ISceneNode* hitNode; + if (smgr->getSceneCollisionManager()->getCollisionPoint( + line, Meta, end, triangle,hitNode)) + { + // collides with wall + vector3df out = triangle.getNormal(); + out.setLength(0.03f); + + imp.when = 1; + imp.outVector = out; + imp.pos = end; + + player->setAnim ( "pow" ); + player->Anim[1].next += player->Anim[1].delta; + } + else + { + // doesnt collide with wall + vector3df start = camera->getPosition(); + if ( player->WeaponNode ) + { + //start.X += 10.f; + //start.Y += -5.f; + //start.Z += 1.f; + } + + vector3df end = (camera->getTarget() - start); + end.normalize(); + start += end*20.0f; + end = start + (end * camera->getFarValue()); + } + + // create fire ball + ISceneNode* node = 0; + node = smgr->addBillboardSceneNode( BulletParent,dimension2d(10,10), start); + + node->setMaterialFlag(EMF_LIGHTING, false); + node->setMaterialTexture(0, Game->Device->getVideoDriver()->getTexture("fireball.bmp")); + node->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false); + node->setMaterialType(EMT_TRANSPARENT_ADD_COLOR); + + f32 length = (f32)(end - start).getLength(); + const f32 speed = 5.8f; + u32 time = (u32)(length / speed); + + ISceneNodeAnimator* anim = 0; + + // set flight line + + anim = smgr->createFlyStraightAnimator(start, end, time); + node->addAnimator(anim); + anim->drop(); + + snprintf_irr ( buf, 64, "bullet: %s on %.1f,%1.f,%1.f", + imp.when ? "hit" : "nohit", end.X, end.Y, end.Z ); + node->setName ( buf ); + + + anim = smgr->createDeleteAnimator(time); + node->addAnimator(anim); + anim->drop(); + + if (imp.when) + { + // create impact note + imp.when = Game->Device->getTimer()->getTime() + + (time + (s32) ( ( 1.f + Noiser::get() ) * 250.f )); + Impacts.push_back(imp); + } + + // play sound +} + +// rendered when bullets hit something +void CQuake3EventHandler::createParticleImpacts( u32 now ) +{ + ISceneManager* sm = Game->Device->getSceneManager(); + + struct smokeLayer + { + const c8 * texture; + f32 scale; + f32 minparticleSize; + f32 maxparticleSize; + f32 boxSize; + u32 minParticle; + u32 maxParticle; + u32 fadeout; + u32 lifetime; + }; + + smokeLayer smoke[] = + { + { "smoke2.jpg", 0.4f, 1.5f, 18.f, 20.f, 20, 50, 2000, 10000 }, + { "smoke3.jpg", 0.2f, 1.2f, 15.f, 20.f, 10, 30, 1000, 12000 } + }; + + + u32 i; + u32 g; + s32 factor = 1; + for ( g = 0; g != 2; ++g ) + { + smoke[g].minParticle *= factor; + smoke[g].maxParticle *= factor; + smoke[g].lifetime *= factor; + smoke[g].boxSize *= Noiser::get() * 0.5f; + } + + for ( i=0; i < Impacts.size(); ++i) + { + if (now < Impacts[i].when) + continue; + + // create smoke particle system + IParticleSystemSceneNode* pas = 0; + + for ( g = 0; g != 2; ++g ) + { + pas = sm->addParticleSystemSceneNode(false, BulletParent, -1, Impacts[i].pos); + + snprintf_irr ( buf, 64, "bullet impact smoke at %.1f,%.1f,%1.f", + Impacts[i].pos.X,Impacts[i].pos.Y,Impacts[i].pos.Z); + pas->setName ( buf ); + + // create a flat smoke + vector3df direction = Impacts[i].outVector; + direction *= smoke[g].scale; + IParticleEmitter* em = pas->createBoxEmitter( + aabbox3d(-4.f,0.f,-4.f,20.f,smoke[g].minparticleSize,20.f), + direction,smoke[g].minParticle, smoke[g].maxParticle, + video::SColor(0,0,0,0),video::SColor(0,128,128,128), + 250,4000, 60); + + em->setMinStartSize (dimension2d( smoke[g].minparticleSize, smoke[g].minparticleSize)); + em->setMaxStartSize (dimension2d( smoke[g].maxparticleSize, smoke[g].maxparticleSize)); + + pas->setEmitter(em); + em->drop(); + + // particles get invisible + IParticleAffector* paf = pas->createFadeOutParticleAffector( + video::SColor ( 0, 0, 0, 0 ), smoke[g].fadeout); + pas->addAffector(paf); + paf->drop(); + + // particle system life time + ISceneNodeAnimator* anim = sm->createDeleteAnimator( smoke[g].lifetime); + pas->addAnimator(anim); + anim->drop(); + + pas->setMaterialFlag(video::EMF_LIGHTING, false); + pas->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false); + pas->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR ); + pas->setMaterialTexture(0, Game->Device->getVideoDriver()->getTexture( smoke[g].texture )); + } + + + // play impact sound + #ifdef USE_IRRKLANG +/* + if (irrKlang) + { + audio::ISound* sound = + irrKlang->play3D(impactSound, Impacts[i].pos, false, false, true); + + if (sound) + { + // adjust max value a bit to make to sound of an impact louder + sound->setMinDistance(400); + sound->drop(); + } + } +*/ + #endif + + + // delete entry + Impacts.erase(i); + i--; + } +} + +/* + render +*/ +void CQuake3EventHandler::Render() +{ + IVideoDriver * driver = Game->Device->getVideoDriver(); + if ( 0 == driver ) + return; + + // TODO: This does not work, yet. + const bool anaglyph=false; + if (anaglyph) + { + scene::ICameraSceneNode* cameraOld = Game->Device->getSceneManager()->getActiveCamera(); + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, SColor(0,0,0,0)); + driver->getOverrideMaterial().Material.ColorMask = ECP_NONE; + driver->getOverrideMaterial().EnableFlags = EMF_COLOR_MASK; + driver->getOverrideMaterial().EnablePasses = ESNRP_SKY_BOX + + ESNRP_SOLID + + ESNRP_TRANSPARENT + + ESNRP_TRANSPARENT_EFFECT + + ESNRP_SHADOW; + Game->Device->getSceneManager()->drawAll(); + driver->clearBuffers(video::ECBF_DEPTH, video::SColor(255,0,0,0)); + + const vector3df oldPosition = cameraOld->getPosition(); + const vector3df oldTarget = cameraOld->getTarget(); + const matrix4 startMatrix = cameraOld->getAbsoluteTransformation(); + const vector3df focusPoint = (oldTarget - + cameraOld->getAbsolutePosition()).setLength(10000) + + cameraOld->getAbsolutePosition() ; + + scene::ICameraSceneNode* camera = cameraOld;//Game->Device->getSceneManager()->addCameraSceneNode(); + + //Left eye... + vector3df pos; + matrix4 move; + + move.setTranslation( vector3df(-1.5f,0.0f,0.0f) ); + pos=(startMatrix*move).getTranslation(); + + driver->getOverrideMaterial().Material.ColorMask = ECP_RED; + driver->getOverrideMaterial().EnableFlags = EMF_COLOR_MASK; + driver->getOverrideMaterial().EnablePasses = + ESNRP_SKY_BOX|ESNRP_SOLID|ESNRP_TRANSPARENT| + ESNRP_TRANSPARENT_EFFECT|ESNRP_SHADOW; + + camera->setPosition(pos); + camera->setTarget(focusPoint); + + Game->Device->getSceneManager()->drawAll(); + driver->clearBuffers(video::ECBF_DEPTH, video::SColor(255, 0, 0, 0)); + + //Right eye... + move.setTranslation( vector3df(1.5f,0.0f,0.0f) ); + pos=(startMatrix*move).getTranslation(); + + driver->getOverrideMaterial().Material.ColorMask = ECP_GREEN + ECP_BLUE; + driver->getOverrideMaterial().EnableFlags = EMF_COLOR_MASK; + driver->getOverrideMaterial().EnablePasses = + ESNRP_SKY_BOX|ESNRP_SOLID|ESNRP_TRANSPARENT| + ESNRP_TRANSPARENT_EFFECT|ESNRP_SHADOW; + + camera->setPosition(pos); + camera->setTarget(focusPoint); + + Game->Device->getSceneManager()->drawAll(); + + driver->getOverrideMaterial().Material.ColorMask=ECP_ALL; + driver->getOverrideMaterial().EnableFlags=0; + driver->getOverrideMaterial().EnablePasses=0; + + if (camera != cameraOld) + { + Game->Device->getSceneManager()->setActiveCamera(cameraOld); + camera->remove(); + } + else + { + camera->setPosition(oldPosition); + camera->setTarget(oldTarget); + } + } + else + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, SColor(0,0,0,0)); + Game->Device->getSceneManager()->drawAll(); + } + Game->Device->getGUIEnvironment()->drawAll(); + driver->endScene(); +} + +/* + update the generic scene node +*/ +void CQuake3EventHandler::Animate() +{ + u32 now = Game->Device->getTimer()->getTime(); + + Q3Player * player = Player + 0; + + checkTimeFire ( player->Anim, 4, now ); + + // Query Scene Manager attributes + if ( player->Anim[0].flags & FIRED ) + { + wchar_t msg[128]; + IVideoDriver * driver = Game->Device->getVideoDriver(); + +#ifdef _IRR_SCENEMANAGER_DEBUG + IAttributes * attr = Game->Device->getSceneManager()->getParameters(); + swprintf_irr ( msg, 128, + L"Q3 %s [%ls], FPS:%03d Tri:%.03fm Cull %d/%d nodes (%d,%d,%d)", + Game->CurrentMapName.c_str(), + driver->getName(), + driver->getFPS (), + (f32) driver->getPrimitiveCountDrawn( 0 ) * ( 1.f / 1000000.f ), + attr->getAttributeAsInt ( "culled" ), + attr->getAttributeAsInt ( "calls" ), + attr->getAttributeAsInt ( "drawn_solid" ), + attr->getAttributeAsInt ( "drawn_transparent" ), + attr->getAttributeAsInt ( "drawn_transparent_effect" ) + ); +#else +swprintf_irr ( msg, 128, + L"Q3 %s [%ls], FPS:%03d Tri:%.03fm", + Game->CurrentMapName.c_str(), + driver->getName(), + driver->getFPS (), + (f32) driver->getPrimitiveCountDrawn( 0 ) * ( 1.f / 1000000.f ) + ); +#endif + Game->Device->setWindowCaption( msg ); + + swprintf_irr ( msg, 128, + L"%03d fps, F1 GUI on/off, F2 respawn, F3-F6 toggle Nodes, F7 Collision on/off" + L", F8 Gravity on/off, Right Mouse Toggle GUI", + Game->Device->getVideoDriver()->getFPS () + ); + if ( gui.StatusLine ) + gui.StatusLine->setText ( msg ); + player->Anim[0].flags &= ~FIRED; + } + + // idle.. + if ( player->Anim[1].flags & FIRED ) + { + if ( strcmp ( player->animation, "idle" ) ) + player->setAnim ( "idle" ); + + player->Anim[1].flags &= ~FIRED; + } + + createParticleImpacts ( now ); + +} + + +/* The main game states +*/ +void runGame ( GameData *game ) +{ + if ( game->retVal >= 3 ) + return; + + game->Device = (*game->createExDevice) ( game->deviceParam ); + if ( 0 == game->Device) + { + // could not create selected driver. + game->retVal = 0; + return; + } + + // create an event receiver based on current game data + CQuake3EventHandler *eventHandler = new CQuake3EventHandler( game ); + + // load stored config + game->load ( "explorer.cfg" ); + + // add our media directory and archive to the file system + for ( u32 i = 0; i < game->CurrentArchiveList.size(); ++i ) + { + eventHandler->AddArchive ( game->CurrentArchiveList[i] ); + } + + // Load a Map or startup to the GUI + if ( game->CurrentMapName.size () ) + { + eventHandler->LoadMap ( game->CurrentMapName, 1 ); + if ( 0 == game->loadParam.loadSkyShader ) + eventHandler->AddSky ( 1, "skydome2" ); + eventHandler->CreatePlayers (); + eventHandler->CreateGUI (); + eventHandler->SetGUIActive ( 0 ); + + // set player to last position on restart + if ( game->retVal == 2 ) + { + eventHandler->GetPlayer( 0 )->setpos ( game->PlayerPosition, game->PlayerRotation ); + } + } + else + { + // start up empty + eventHandler->AddSky ( 1, "skydome2" ); + eventHandler->CreatePlayers (); + eventHandler->CreateGUI (); + eventHandler->SetGUIActive ( 1 ); + background_music ( "IrrlichtTheme.ogg" ); + } + + + game->retVal = 3; + while( game->Device->run() ) + { + eventHandler->Animate (); + eventHandler->Render (); + //if ( !game->Device->isWindowActive() ) + game->Device->yield(); + } + + game->Device->setGammaRamp ( 1.f, 1.f, 1.f, 0.f, 0.f ); + delete eventHandler; +} + +#if defined (_IRR_WINDOWS_) && 0 + #pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup") +#endif + + +/* The main routine, doing all setup +*/ +int IRRCALLCONV main(int argc, char* argv[]) +{ + path prgname(argv[0]); + GameData game ( deletePathFromPath ( prgname, 1 ) ); + + // dynamically load irrlicht + const c8 * dllName = argc > 1 ? argv[1] : "irrlicht.dll"; + game.createExDevice = load_createDeviceEx ( dllName ); + if ( 0 == game.createExDevice ) + { + game.retVal = 3; + printf ( "Could not load %s.\n", dllName ); + return game.retVal; // could not load dll + } + + // start without asking for driver + game.retVal = 1; + do + { + // if driver could not created, ask for another driver + if ( game.retVal == 0 ) + { + game.setDefault (); + // ask user for driver + game.deviceParam.DriverType=driverChoiceConsole(); + if (game.deviceParam.DriverType==video::EDT_COUNT) + game.retVal = 3; + } + runGame ( &game ); + } while ( game.retVal < 3 ); + + return game.retVal; +} + +/* +**/ diff --git a/examples/21.Quake3Explorer/q3factory.cpp b/examples/21.Quake3Explorer/q3factory.cpp new file mode 100644 index 00000000..476a2ed4 --- /dev/null +++ b/examples/21.Quake3Explorer/q3factory.cpp @@ -0,0 +1,825 @@ +/*! + Model Factory. + create the additional scenenodes for ( bullets, health... ) + + Defines the Entities for Quake3 +*/ + +#include +#include "q3factory.h" +#include "sound.h" + +using namespace irr; +using namespace scene; +using namespace gui; +using namespace video; +using namespace core; +using namespace quake3; + +//! This list is based on the original quake3. +static const SItemElement Quake3ItemElement [] = { +{ "item_health", + {"models/powerups/health/medium_cross.md3", + "models/powerups/health/medium_sphere.md3"}, + "sound/items/n_health.wav", + "icons/iconh_yellow", + "25 Health", + 25, + HEALTH, + SUB_NONE, + SPECIAL_SFX_BOUNCE | SPECIAL_SFX_ROTATE_1 +}, +{ "item_health_large", + "models/powerups/health/large_cross.md3", + "models/powerups/health/large_sphere.md3", + "sound/items/l_health.wav", + "icons/iconh_red", + "50 Health", + 50, + HEALTH, + SUB_NONE, + SPECIAL_SFX_BOUNCE | SPECIAL_SFX_ROTATE_1 +}, +{ + "item_health_mega", + "models/powerups/health/mega_cross.md3", + "models/powerups/health/mega_sphere.md3", + "sound/items/m_health.wav", + "icons/iconh_mega", + "Mega Health", + 100, + HEALTH, + SUB_NONE, + SPECIAL_SFX_BOUNCE | SPECIAL_SFX_ROTATE_1 +}, +{ + "item_health_small", + "models/powerups/health/small_cross.md3", + "models/powerups/health/small_sphere.md3", + "sound/items/s_health.wav", + "icons/iconh_green", + "5 Health", + 5, + HEALTH, + SUB_NONE, + SPECIAL_SFX_BOUNCE | SPECIAL_SFX_ROTATE_1 +}, +{ "ammo_bullets", + "models/powerups/ammo/machinegunam.md3", + "", + "sound/misc/am_pkup.wav", + "icons/icona_machinegun", + "Bullets", + 50, + AMMO, + MACHINEGUN, + SPECIAL_SFX_BOUNCE, +}, +{ + "ammo_cells", + "models/powerups/ammo/plasmaam.md3", + "", + "sound/misc/am_pkup.wav", + "icons/icona_plasma", + "Cells", + 30, + AMMO, + PLASMAGUN, + SPECIAL_SFX_BOUNCE +}, +{ "ammo_rockets", + "models/powerups/ammo/rocketam.md3", + "", + "", + "icons/icona_rocket", + "Rockets", + 5, + AMMO, + ROCKET_LAUNCHER, + SPECIAL_SFX_ROTATE +}, +{ + "ammo_shells", + "models/powerups/ammo/shotgunam.md3", + "", + "sound/misc/am_pkup.wav", + "icons/icona_shotgun", + "Shells", + 10, + AMMO, + SHOTGUN, + SPECIAL_SFX_ROTATE +}, +{ + "ammo_slugs", + "models/powerups/ammo/railgunam.md3", + "", + "sound/misc/am_pkup.wav", + "icons/icona_railgun", + "Slugs", + 10, + AMMO, + RAILGUN, + SPECIAL_SFX_ROTATE +}, +{ + "item_armor_body", + "models/powerups/armor/armor_red.md3", + "", + "sound/misc/ar2_pkup.wav", + "icons/iconr_red", + "Heavy Armor", + 100, + ARMOR, + SUB_NONE, + SPECIAL_SFX_ROTATE +}, +{ + "item_armor_combat", + "models/powerups/armor/armor_yel.md3", + "", + "sound/misc/ar2_pkup.wav", + "icons/iconr_yellow", + "Armor", + 50, + ARMOR, + SUB_NONE, + SPECIAL_SFX_ROTATE +}, +{ + "item_armor_shard", + "models/powerups/armor/shard.md3", + "", + "sound/misc/ar1_pkup.wav", + "icons/iconr_shard", + "Armor Shared", + 5, + ARMOR, + SUB_NONE, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_gauntlet", + "models/weapons2/gauntlet/gauntlet.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_gauntlet", + "Gauntlet", + 0, + WEAPON, + GAUNTLET, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_shotgun", + "models/weapons2/shotgun/shotgun.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_shotgun", + "Shotgun", + 10, + WEAPON, + SHOTGUN, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_machinegun", + "models/weapons2/machinegun/machinegun.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_machinegun", + "Machinegun", + 40, + WEAPON, + MACHINEGUN, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_grenadelauncher", + "models/weapons2/grenadel/grenadel.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_grenade", + "Grenade Launcher", + 10, + WEAPON, + GRENADE_LAUNCHER, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_rocketlauncher", + "models/weapons2/rocketl/rocketl.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_rocket", + "Rocket Launcher", + 10, + WEAPON, + ROCKET_LAUNCHER, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_lightning", + "models/weapons2/lightning/lightning.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_lightning", + "Lightning Gun", + 100, + WEAPON, + LIGHTNING, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_railgun", + "models/weapons2/railgun/railgun.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_railgun", + "Railgun", + 10, + WEAPON, + RAILGUN, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_plasmagun", + "models/weapons2/plasma/plasma.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_plasma", + "Plasma Gun", + 50, + WEAPON, + PLASMAGUN, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_bfg", + "models/weapons2/bfg/bfg.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_bfg", + "BFG10K", + 20, + WEAPON, + BFG, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_grapplinghook", + "models/weapons2/grapple/grapple.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_grapple", + "Grappling Hook", + 0, + WEAPON, + GRAPPLING_HOOK, + SPECIAL_SFX_ROTATE +}, +{ + 0 +} + +}; + + +/*! +*/ +const SItemElement * getItemElement ( const stringc& key ) +{ + const SItemElement *item = Quake3ItemElement; + + while ( item->key ) + { + if ( 0 == strcmp ( key.c_str(), item->key ) ) + return item; + item += 1; + } + return 0; +} + +/*! + Quake3 Model Factory. + Takes the mesh buffers and creates scenenodes for their associated shaders +*/ +void Q3ShaderFactory ( Q3LevelLoadParameter &loadParam, + IrrlichtDevice *device, + IQ3LevelMesh* mesh, + eQ3MeshIndex meshIndex, + ISceneNode *parent, + IMetaTriangleSelector *meta, + bool showShaderName ) +{ + if ( 0 == mesh || 0 == device ) + return; + + IMeshSceneNode* node = 0; + ISceneManager* smgr = device->getSceneManager(); + ITriangleSelector * selector = 0; + + // the additional mesh can be quite huge and is unoptimized + // Save to cast to SMesh + SMesh * additional_mesh = (SMesh*) mesh->getMesh ( meshIndex ); + if ( 0 == additional_mesh || additional_mesh->getMeshBufferCount() == 0) + return; + + char buf[128]; + if ( loadParam.verbose > 0 ) + { + loadParam.startTime = device->getTimer()->getRealTime(); + if ( loadParam.verbose > 1 ) + { + snprintf_irr(buf, 128, "q3shaderfactory start" ); + device->getLogger()->log( buf, ELL_INFORMATION); + } + } + + IGUIFont *font = 0; + if ( showShaderName ) + font = device->getGUIEnvironment()->getFont("fontlucida.png"); + + IVideoDriver *driver = device->getVideoDriver(); + + // create helper textures + if ( 1 ) + { + tTexArray tex; + u32 pos = 0; + getTextures ( tex, "$redimage $blueimage $whiteimage $checkerimage", pos, + device->getFileSystem(), driver ); + } + + s32 sceneNodeID = 0; + for ( u32 i = 0; i!= additional_mesh->getMeshBufferCount (); ++i ) + { + IMeshBuffer *meshBuffer = additional_mesh->getMeshBuffer ( i ); + const SMaterial &material = meshBuffer->getMaterial(); + + //! The ShaderIndex is stored in the second material parameter + s32 shaderIndex = (s32) material.MaterialTypeParam2; + + // the meshbuffer can be rendered without additional support, or it has no shader + IShader *shader = (IShader *) mesh->getShader ( shaderIndex ); + + // no shader, or mapped to existing material + if ( 0 == shader ) + { + +#if 1 + // clone mesh + SMesh * m = new SMesh (); + m->addMeshBuffer ( meshBuffer ); + SMaterial &mat = m->getMeshBuffer( 0 )->getMaterial(); + if ( mat.getTexture( 0 ) == 0 ) + mat.setTexture ( 0, driver->getTexture ( "$blueimage" ) ); + if ( mat.getTexture( 1 ) == 0 ) + mat.setTexture ( 1, driver->getTexture ( "$redimage" ) ); + + IMesh * store = smgr->getMeshManipulator ()->createMeshWith2TCoords ( m ); + m->drop(); + + node = smgr->addMeshSceneNode ( store, parent, sceneNodeID ); + node->setAutomaticCulling ( scene::EAC_OFF ); + store->drop (); + sceneNodeID += 1; +#endif + } + else if ( 1 ) + { +/* + stringc s; + dumpShader ( s, shader ); + printf ( s.c_str () ); +*/ + // create sceneNode + node = smgr->addQuake3SceneNode ( meshBuffer, shader, parent, sceneNodeID ); + node->setAutomaticCulling ( scene::EAC_FRUSTUM_BOX ); + sceneNodeID += 1; + } + + // show Debug Shader Name + if ( showShaderName && node ) + { + swprintf_irr ( (wchar_t*) buf, 64, L"%hs:%d", node->getName(),node->getID() ); + smgr->addBillboardTextSceneNode( + font, + (wchar_t*) buf, + node, + dimension2d(80.0f, 8.0f), + vector3df(0, 10, 0), + sceneNodeID); + sceneNodeID += 1; + } + + // create Portal Rendertargets + if ( shader ) + { + const SVarGroup *group = shader->getGroup(1); + if ( group->isDefined( "surfaceparm", "portal" ) ) + { + } + + } + + + // add collision + // find out if shader is marked as nonsolid + u8 doCreate = meta !=0 ; + + if ( shader ) + { + const SVarGroup *group = shader->getGroup(1); + if ( group->isDefined( "surfaceparm", "trans" ) + // || group->isDefined( "surfaceparm", "sky" ) + // || group->isDefined( "surfaceparm", "nonsolid" ) + ) + { + if ( !group->isDefined( "surfaceparm", "metalsteps" ) ) + { + doCreate = 0; + } + } + } + + if ( doCreate ) + { + IMesh *m = 0; + + //! controls if triangles are modified by the scenenode during runtime + bool takeOriginal = true; + + if ( takeOriginal ) + { + m = new SMesh (); + ((SMesh*) m )->addMeshBuffer (meshBuffer); + } + else + { + m = node->getMesh(); + } + + //selector = smgr->createOctreeTriangleSelector ( m, 0, 128 ); + selector = smgr->createTriangleSelector ( m, 0 ); + meta->addTriangleSelector ( selector ); + selector->drop (); + + if ( takeOriginal ) + { + delete m; + } + } + + } + +#if 0 + if ( meta ) + { + selector = smgr->createOctreeTriangleSelector ( additional_mesh, 0 ); + meta->addTriangleSelector ( selector ); + selector->drop (); + } +#endif + + if ( loadParam.verbose > 0 ) + { + loadParam.endTime = device->getTimer()->getRealTime (); + snprintf_irr(buf, 128, "q3shaderfactory needed %04d ms to create %d shader nodes", + loadParam.endTime - loadParam.startTime, + sceneNodeID + ); + device->getLogger()->log(buf, ELL_INFORMATION); + } + +} + + +/*! + create Items from Entity +*/ +void Q3ModelFactory ( Q3LevelLoadParameter &loadParam, + IrrlichtDevice *device, + IQ3LevelMesh* masterMesh, + ISceneNode *parent, + bool showShaderName + ) +{ + if ( 0 == masterMesh ) + return; + + tQ3EntityList &entity = masterMesh->getEntityList (); + ISceneManager* smgr = device->getSceneManager(); + + + char buf[128]; + const SVarGroup *group; + IEntity search; + s32 index; + s32 lastIndex; + +/* + stringc s; + FILE *f = 0; + f = fopen ( "entity.txt", "wb" ); + for ( index = 0; (u32) index < entityList.size (); ++index ) + { + const IEntity *entity = &entityList[ index ]; + s = entity->name; + dumpShader ( s, entity ); + fwrite ( s.c_str(), 1, s.size(), f ); + } + fclose ( f ); +*/ + IAnimatedMeshMD3* model; + SMD3Mesh * mesh; + const SMD3MeshBuffer *meshBuffer; + IMeshSceneNode* node; + ISceneNodeAnimator* anim; + const IShader *shader; + u32 pos; + vector3df p; + u32 nodeCount = 0; + tTexArray textureArray; + + IGUIFont *font = 0; + if ( showShaderName ) + font = device->getGUIEnvironment()->getFont("fontlucida.png"); + + const SItemElement *itemElement; + + // walk list + for ( index = 0; (u32) index < entity.size(); ++index ) + { + itemElement = getItemElement ( entity[index].name ); + if ( 0 == itemElement ) + continue; + + pos = 0; + p = getAsVector3df ( entity[index].getGroup(1)->get ( "origin" ), pos ); + + nodeCount += 1; + for ( u32 g = 0; g < 2; ++g ) + { + if ( 0 == itemElement->model[g] || itemElement->model[g][0] == 0 ) + continue; + model = (IAnimatedMeshMD3*) smgr->getMesh( itemElement->model[g] ); + if ( 0 == model ) + continue; + + mesh = model->getOriginalMesh(); + for ( u32 j = 0; j != mesh->Buffer.size (); ++j ) + { + meshBuffer = mesh->Buffer[j]; + if ( 0 == meshBuffer ) + continue; + + shader = masterMesh->getShader ( meshBuffer->Shader.c_str(), false ); + IMeshBuffer *final = model->getMesh(0)->getMeshBuffer(j); + if ( shader ) + { + //!TODO: Hack don't modify the vertexbuffer. make it better;-) + final->getMaterial().ColorMask = 0; + node = smgr->addQuake3SceneNode ( final, shader, parent ); + final->getMaterial().ColorMask = 15; + } + else + { + // clone mesh + SMesh * m = new SMesh (); + m->addMeshBuffer ( final ); + node = smgr->addMeshSceneNode ( m, parent ); + m->drop(); + } + + if ( 0 == node ) + { + snprintf_irr ( buf, 128, "q3ModelFactory shader %s failed", meshBuffer->Shader.c_str() ); + device->getLogger()->log ( buf ); + continue; + } + + // node was maybe centered by shaderscenenode + node->setPosition ( p ); + node->setName ( meshBuffer->Shader ); + node->setAutomaticCulling ( scene::EAC_BOX ); + + // add special effects to node + if ( itemElement->special & SPECIAL_SFX_ROTATE || + (g == 0 && itemElement->special & SPECIAL_SFX_ROTATE_1) + ) + { + anim = smgr->createRotationAnimator ( vector3df ( 0.f, + 2.f, 0.f ) ); + node->addAnimator ( anim ); + anim->drop (); + } + + if ( itemElement->special & SPECIAL_SFX_BOUNCE ) + { + //anim = smgr->createFlyStraightAnimator ( + // p, p + vector3df ( 0.f, 60.f, 0.f ), 1000, true, true ); + anim = smgr->createFlyCircleAnimator ( + p + vector3df( 0.f, 20.f, 0.f ), + 20.f, + 0.005f, + vector3df ( 1.f, 0.f, 0.f ), + core::fract ( nodeCount * 0.05f ), + 1.f + ); + node->addAnimator ( anim ); + anim->drop (); + } + } + } + // show name + if ( showShaderName ) + { + swprintf_irr ( (wchar_t*) buf, sizeof(buf) / 2, L"%hs", itemElement->key ); + smgr->addBillboardTextSceneNode( + font, + (wchar_t*) buf, + parent, + dimension2d(80.0f, 8.0f), + p + vector3df(0, 30, 0), + 0); + } + } + + // music + search.name = "worldspawn"; + index = entity.binary_search_multi ( search, lastIndex ); + + if ( index >= 0 ) + { + group = entity[ index ].getGroup(1); + background_music ( group->get ( "music" ).c_str () ); + } + + // music + search.name = "worldspawn"; + index = entity.binary_search_multi ( search, lastIndex ); + + if ( index >= 0 ) + { + group = entity[ index ].getGroup(1); + background_music ( group->get ( "music" ).c_str () ); + } + + //IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2"); + //IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh ); + +} + +/*! + so we need a good starting Position in the level. + we can ask the Quake3 Loader for all entities with class_name "info_player_deathmatch" +*/ +s32 Q3StartPosition ( IQ3LevelMesh* mesh, + ICameraSceneNode* camera, + s32 startposIndex, + const vector3df &translation + ) +{ + if ( 0 == mesh ) + return 0; + + tQ3EntityList &entityList = mesh->getEntityList (); + + IEntity search; + search.name = "info_player_start"; // "info_player_deathmatch"; + + // find all entities in the multi-list + s32 lastIndex; + s32 index = entityList.binary_search_multi ( search, lastIndex ); + + if ( index < 0 ) + { + search.name = "info_player_deathmatch"; + index = entityList.binary_search_multi ( search, lastIndex ); + } + + if ( index < 0 ) + return 0; + + index += core::clamp ( startposIndex, 0, lastIndex - index ); + + u32 parsepos; + + const SVarGroup *group; + group = entityList[ index ].getGroup(1); + + parsepos = 0; + vector3df pos = getAsVector3df ( group->get ( "origin" ), parsepos ); + pos += translation; + + parsepos = 0; + f32 angle = getAsFloat ( group->get ( "angle"), parsepos ); + + vector3df target ( 0.f, 0.f, 1.f ); + target.rotateXZBy ( angle - 90.f, vector3df () ); + + if ( camera ) + { + camera->setPosition ( pos ); + camera->setTarget ( pos + target ); + //! New. FPSCamera and animators catches reset on animate 0 + camera->OnAnimate ( 0 ); + } + return lastIndex - index + 1; +} + + +/*! + gets a accumulated force on a given surface +*/ +vector3df getGravity ( const c8 * surface ) +{ + if ( 0 == strcmp ( surface, "earth" ) ) return vector3df ( 0.f, -900.f, 0.f ); + if ( 0 == strcmp ( surface, "moon" ) ) return vector3df ( 0.f, -6.f , 0.f ); + if ( 0 == strcmp ( surface, "water" ) ) return vector3df ( 0.1f, -2.f, 0.f ); + if ( 0 == strcmp ( surface, "ice" ) ) return vector3df ( 0.2f, -9.f, 0.3f ); + + return vector3df ( 0.f, 0.f, 0.f ); +} + + + +/* + Dynamically load the Irrlicht Library +*/ + +#if defined(_IRR_WINDOWS_API_) +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +#include + +funcptr_createDevice load_createDevice ( const c8 * filename) +{ + return (funcptr_createDevice) GetProcAddress ( LoadLibrary ( filename ), "createDevice" ); +} + +funcptr_createDeviceEx load_createDeviceEx ( const c8 * filename) +{ + return (funcptr_createDeviceEx) GetProcAddress ( LoadLibrary ( filename ), "createDeviceEx" ); +} + +#else + +// TODO: Dynamic Loading for other os + +funcptr_createDevice load_createDevice ( const c8 * filename) +{ + return createDevice; +} + +funcptr_createDeviceEx load_createDeviceEx ( const c8 * filename) +{ + return createDeviceEx; +} + +#endif + +/* + get the current collision response camera animator +*/ +ISceneNodeAnimatorCollisionResponse* camCollisionResponse( IrrlichtDevice * device ) +{ + ICameraSceneNode *camera = device->getSceneManager()->getActiveCamera(); + ISceneNodeAnimatorCollisionResponse *a = 0; + + list::ConstIterator it = camera->getAnimators().begin(); + for (; it != camera->getAnimators().end(); ++it) + { + a = (ISceneNodeAnimatorCollisionResponse*) (*it); + if ( a->getType() == ESNAT_COLLISION_RESPONSE ) + return a; + } + + return 0; +} + + +//! internal Animation +void setTimeFire ( TimeFire *t, u32 delta, u32 flags ) +{ + t->flags = flags; + t->next = 0; + t->delta = delta; +} + + +void checkTimeFire ( TimeFire *t, u32 listSize, u32 now ) +{ + u32 i; + for ( i = 0; i < listSize; ++i ) + { + if ( now < t[i].next ) + continue; + + t[i].next = core::max_ ( now + t[i].delta, t[i].next + t[i].delta ); + t[i].flags |= FIRED; + } +} diff --git a/examples/21.Quake3Explorer/q3factory.h b/examples/21.Quake3Explorer/q3factory.h new file mode 100644 index 00000000..d9606ed0 --- /dev/null +++ b/examples/21.Quake3Explorer/q3factory.h @@ -0,0 +1,149 @@ +/*! + Model Factory. + create the additional scenenodes for ( bullets, health... ) + + Defines the Entities for Quake3 +*/ +#ifndef __QUAKE3_FACTORY__H_INCLUDED__ +#define __QUAKE3_FACTORY__H_INCLUDED__ + +using namespace irr; +using namespace scene; +using namespace gui; +using namespace video; +using namespace core; +using namespace quake3; +using namespace io; + + + +//! Defines to which group the entities belong +enum eItemGroup +{ + WEAPON, + AMMO, + ARMOR, + HEALTH, + POWERUP +}; + +//! define a supgroup for the item. for e.q the Weapons +enum eItemSubGroup +{ + SUB_NONE = 0, + GAUNTLET, + MACHINEGUN, + SHOTGUN, + GRENADE_LAUNCHER, + ROCKET_LAUNCHER, + LIGHTNING, + RAILGUN, + PLASMAGUN, + BFG, + GRAPPLING_HOOK, + NAILGUN, + PROX_LAUNCHER, + CHAINGUN, +}; + +//! aplly a special effect to the shader +enum eItemSpecialEffect +{ + SPECIAL_SFX_NONE = 0, + SPECIAL_SFX_ROTATE = 1, + SPECIAL_SFX_BOUNCE = 2, + SPECIAL_SFX_ROTATE_1 = 4, +}; + +// a List for defining a model +struct SItemElement +{ + const c8 *key; + const c8 *model[2]; + const c8 *sound; + const c8 *icon; + const c8 *pickup; + s32 value; + eItemGroup group; + eItemSubGroup sub; + u32 special; +}; + + +//! Get's an entity based on it's key +const SItemElement * getItemElement ( const stringc& key ); + +/*! + Quake3 Model Factory. + Takes the mesh buffers and creates scenenodes for their associated shaders +*/ +void Q3ShaderFactory ( Q3LevelLoadParameter &loadParam, + IrrlichtDevice *device, + IQ3LevelMesh* mesh, + eQ3MeshIndex meshIndex, + ISceneNode *parent, + IMetaTriangleSelector *meta, + bool showShaderName + ); + + +/*! + Creates Model based on the entity list +*/ +void Q3ModelFactory ( Q3LevelLoadParameter &loadParam, + IrrlichtDevice *device, + IQ3LevelMesh* masterMesh, + ISceneNode *parent, + bool showShaderName + ); + +/*! + so we need a good starting Position in the level. + we can ask the Quake3 Loader for all entities with class_name "info_player_deathmatch" +*/ +s32 Q3StartPosition ( IQ3LevelMesh* mesh, + ICameraSceneNode* camera, + s32 startposIndex, + const vector3df &translation + ); +/*! + gets a accumulated force on a given surface +*/ +vector3df getGravity ( const c8 * surface ); + + +/* + Dynamically load the Irrlicht Library +*/ +funcptr_createDevice load_createDevice ( const c8 * filename); +funcptr_createDeviceEx load_createDeviceEx ( const c8 * filename); + + +//! Macro for save Dropping an Element +#define dropElement(x) if (x) { x->remove(); x = 0; } + + +/* + get the current collision respone camera animator +*/ +ISceneNodeAnimatorCollisionResponse* camCollisionResponse( IrrlichtDevice * device ); + +//! internal Animation +enum eTimeFireFlag +{ + FIRED = 1, +}; + +struct TimeFire +{ + u32 flags; + u32 next; + u32 delta; +}; + +void setTimeFire ( TimeFire *t, u32 delta, u32 flags = 0 ); +void checkTimeFire ( TimeFire *t, u32 listSize, u32 now ); + +#endif // __QUAKE3_FACTORY__H_INCLUDED__ + + diff --git a/examples/21.Quake3Explorer/sound.cpp b/examples/21.Quake3Explorer/sound.cpp new file mode 100644 index 00000000..f693e660 --- /dev/null +++ b/examples/21.Quake3Explorer/sound.cpp @@ -0,0 +1,98 @@ +/*! + Sound Factory. + provides a sound interface + +*/ + +#include "sound.h" + + +//#define USE_IRRKLANG + +#ifdef USE_IRRKLANG + +#include +#ifdef _MSC_VER + #pragma comment (lib, "irrKlang.lib") +#endif + +using namespace irrklang; + +struct soundfile: public IFileReader +{ + soundfile ( io::IReadFile* f ): file (f ) {} + virtual ~soundfile () { file->drop (); } + + virtual ik_s32 read(void* buffer, ik_u32 sizeToRead) { return file->read ( buffer, sizeToRead ); } + virtual bool seek(ik_s32 finalPos, bool relativeMovement = false) { return file->seek ( finalPos, relativeMovement ); } + virtual ik_s32 getSize(){ return file->getSize (); } + virtual ik_s32 getPos() {return file->getPos (); } + virtual const ik_c8* getFileName() { return file->getFileName().c_str(); } + io::IReadFile* file; +}; + +struct klangFactory : public irrklang::IFileFactory +{ + klangFactory ( IrrlichtDevice *device ) { Device = device; } + + virtual irrklang::IFileReader* createFileReader(const ik_c8* filename) + { + io::IReadFile* file = Device->getFileSystem()->createAndOpenFile(filename); + if ( 0 == file ) + return 0; + + return new soundfile ( file ); + } + + IrrlichtDevice *Device; +}; + +ISoundEngine *engine = 0; +ISound *backMusic = 0; + +void sound_init ( IrrlichtDevice *device ) +{ + engine = createIrrKlangDevice (); + if ( 0 == engine ) + return; + + klangFactory *f = new klangFactory ( device ); + engine->addFileFactory ( f ); +} + +void sound_shutdown () +{ + if ( backMusic ) + backMusic->drop (); + + if ( engine ) + engine->drop (); +} + +void background_music ( const c8 * file ) +{ + if ( 0 == engine ) + return; + + if ( backMusic ) + { + backMusic->stop (); + backMusic->drop (); + } + + backMusic = engine->play2D ( file, true, false, true ); + + if ( backMusic ) + { + backMusic->setVolume ( 0.5f ); + } +} + +#else + +void sound_init ( IrrlichtDevice *device ) {} +void sound_shutdown () {} +void background_music ( const c8 * file ) {} + +#endif + diff --git a/examples/21.Quake3Explorer/sound.h b/examples/21.Quake3Explorer/sound.h new file mode 100644 index 00000000..033e9bb6 --- /dev/null +++ b/examples/21.Quake3Explorer/sound.h @@ -0,0 +1,18 @@ +/*! + Sound Factory. + provides a sound interface + +*/ +#ifndef __QUAKE3_SOUND__H_INCLUDED__ +#define __QUAKE3_SOUND__H_INCLUDED__ + +#include + +using namespace irr; + +void sound_init ( IrrlichtDevice *device ); +void sound_shutdown (); +void background_music ( const c8 * file ); + + +#endif // __QUAKE3_SOUND__H_INCLUDED__ diff --git a/examples/22.MaterialViewer/Makefile b/examples/22.MaterialViewer/Makefile new file mode 100644 index 00000000..fcbdc22e --- /dev/null +++ b/examples/22.MaterialViewer/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 22.MaterialViewer +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/22.MaterialViewer/MaterialViewer.cbp b/examples/22.MaterialViewer/MaterialViewer.cbp new file mode 100644 index 00000000..7d4a0624 --- /dev/null +++ b/examples/22.MaterialViewer/MaterialViewer.cbp @@ -0,0 +1,74 @@ + + + + + + diff --git a/examples/22.MaterialViewer/MaterialViewer.vcproj b/examples/22.MaterialViewer/MaterialViewer.vcproj new file mode 100644 index 00000000..7419359f --- /dev/null +++ b/examples/22.MaterialViewer/MaterialViewer.vcproj @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/22.MaterialViewer/MaterialViewer.xcodeproj/project.pbxproj b/examples/22.MaterialViewer/MaterialViewer.xcodeproj/project.pbxproj new file mode 100644 index 00000000..c278e231 --- /dev/null +++ b/examples/22.MaterialViewer/MaterialViewer.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 22.MaterialViewer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 22.MaterialViewer.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 22.MaterialViewer.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 22.MaterialViewer */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "22.MaterialViewer" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 22.MaterialViewer; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 22.MaterialViewer.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "MaterialViewer" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 22.MaterialViewer */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "MaterialViewer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "22.MaterialViewer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/22.MaterialViewer/MaterialViewer.xcodeproj/xcshareddata/xcschemes/22.MaterialViewer.xcscheme b/examples/22.MaterialViewer/MaterialViewer.xcodeproj/xcshareddata/xcschemes/22.MaterialViewer.xcscheme new file mode 100644 index 00000000..eed2899f --- /dev/null +++ b/examples/22.MaterialViewer/MaterialViewer.xcodeproj/xcshareddata/xcschemes/22.MaterialViewer.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/22.MaterialViewer/MaterialViewer_vc10.vcxproj b/examples/22.MaterialViewer/MaterialViewer_vc10.vcxproj new file mode 100644 index 00000000..5e5560bd --- /dev/null +++ b/examples/22.MaterialViewer/MaterialViewer_vc10.vcxproj @@ -0,0 +1,234 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 22.MaterialViewer + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA} + MaterialViewer + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/MaterialViewer.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\22.MaterialViewer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + .\Release/MaterialViewer.pdb + Console + + + + + + + .\Release/MaterialViewer.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\22.MaterialViewer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + .\Release/MaterialViewer.pdb + Console + + + + + + + .\Debug/MaterialViewer.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\22.MaterialViewer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/MaterialViewer.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\22.MaterialViewer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + .\Debug/MaterialViewer.pdb + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/22.MaterialViewer/MaterialViewer_vc11.vcxproj b/examples/22.MaterialViewer/MaterialViewer_vc11.vcxproj new file mode 100644 index 00000000..582faee9 --- /dev/null +++ b/examples/22.MaterialViewer/MaterialViewer_vc11.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 22.MaterialViewer + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA} + MaterialViewer + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/MaterialViewer.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\22.MaterialViewer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + .\Release/MaterialViewer.pdb + Console + + + + + + + .\Release/MaterialViewer.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\22.MaterialViewer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + .\Release/MaterialViewer.pdb + Console + + + + + + + .\Debug/MaterialViewer.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\22.MaterialViewer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + .\Debug/MaterialViewer.pdb + Console + + + + + + + .\Debug/MaterialViewer.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\22.MaterialViewer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + .\Debug/MaterialViewer.pdb + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/22.MaterialViewer/MaterialViewer_vc12.vcxproj b/examples/22.MaterialViewer/MaterialViewer_vc12.vcxproj new file mode 100644 index 00000000..ca494237 --- /dev/null +++ b/examples/22.MaterialViewer/MaterialViewer_vc12.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 22.MaterialViewer + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA} + MaterialViewer + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/MaterialViewer.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\22.MaterialViewer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + .\Release/MaterialViewer.pdb + Console + + + + + + + .\Release/MaterialViewer.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\22.MaterialViewer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + .\Release/MaterialViewer.pdb + Console + + + + + + + .\Debug/MaterialViewer.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\22.MaterialViewer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + .\Debug/MaterialViewer.pdb + Console + + + + + + + .\Debug/MaterialViewer.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\22.MaterialViewer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + .\Debug/MaterialViewer.pdb + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/22.MaterialViewer/MaterialViewer_vc14.vcxproj b/examples/22.MaterialViewer/MaterialViewer_vc14.vcxproj new file mode 100644 index 00000000..f568176e --- /dev/null +++ b/examples/22.MaterialViewer/MaterialViewer_vc14.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 22.MaterialViewer + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA} + MaterialViewer + + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Release/MaterialViewer.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\22.MaterialViewer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + .\Release/MaterialViewer.pdb + Console + + + + + + + .\Release/MaterialViewer.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\22.MaterialViewer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + .\Release/MaterialViewer.pdb + Console + + + + + + + .\Debug/MaterialViewer.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\22.MaterialViewer.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + .\Debug/MaterialViewer.pdb + Console + + + + + + + .\Debug/MaterialViewer.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\22.MaterialViewer.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + .\Debug/MaterialViewer.pdb + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/22.MaterialViewer/main.cpp b/examples/22.MaterialViewer/main.cpp new file mode 100755 index 00000000..83309260 --- /dev/null +++ b/examples/22.MaterialViewer/main.cpp @@ -0,0 +1,1047 @@ +/** Example 022 Material Viewer + +This example can be used to play around with material settings and watch the results. +Only the default non-shader materials are used in here. + +You have a node with a mesh, one dynamic light and global ambient light to play around with. +You can move the light with cursor-keys and +/-. +You can move the camera while left-mouse button is clicked. +*/ + +// TODO: Should be possible to set all material values by the GUI. +// For now just change the defaultMaterial in CApp::init for the rest. +// TODO: Allow users to switch between a sphere and a box mesh. + +#include +#include "driverChoice.h" +#include "exampleHelper.h" +#include "main.h" + +using namespace irr; + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +/* + Variables within the empty namespace are globals which are restricted to this file. +*/ +namespace +{ + // For the gui id's + enum EGUI_IDS + { + GUI_ID_OPEN_TEXTURE = 1, + GUI_ID_QUIT, + GUI_ID_MAX + }; + + // Name used in texture selection to clear the textures on the node + const core::stringw CLEAR_TEXTURE = L"CLEAR texture"; + + // some useful color constants + const video::SColor SCOL_BLACK = video::SColor(255, 0, 0, 0); + const video::SColor SCOL_BLUE = video::SColor(255, 0, 0, 255); + const video::SColor SCOL_CYAN = video::SColor(255, 0, 255, 255); + const video::SColor SCOL_GRAY = video::SColor(255, 128,128, 128); + const video::SColor SCOL_GREEN = video::SColor(255, 0, 255, 0); + const video::SColor SCOL_MAGENTA = video::SColor(255, 255, 0, 255); + const video::SColor SCOL_RED = video::SColor(255, 255, 0, 0); + const video::SColor SCOL_YELLOW = video::SColor(255, 255, 255, 0); + const video::SColor SCOL_WHITE = video::SColor(255, 255, 255, 255); +}; // namespace + +/* + Returns a new unique number on each call. +*/ +s32 makeUniqueId() +{ + static int unique = GUI_ID_MAX; + ++unique; + return unique; +} + +/* + Find out which vertex-type is needed for the given material type. +*/ +video::E_VERTEX_TYPE getVertexTypeForMaterialType(video::E_MATERIAL_TYPE materialType) +{ + using namespace video; + + switch ( materialType ) + { + case EMT_SOLID: + return EVT_STANDARD; + + case EMT_SOLID_2_LAYER: + return EVT_STANDARD; + + case EMT_LIGHTMAP: + case EMT_LIGHTMAP_ADD: + case EMT_LIGHTMAP_M2: + case EMT_LIGHTMAP_M4: + case EMT_LIGHTMAP_LIGHTING: + case EMT_LIGHTMAP_LIGHTING_M2: + case EMT_LIGHTMAP_LIGHTING_M4: + return EVT_2TCOORDS; + + case EMT_DETAIL_MAP: + return EVT_2TCOORDS; + + case EMT_SPHERE_MAP: + return EVT_STANDARD; + + case EMT_REFLECTION_2_LAYER: + return EVT_2TCOORDS; + + case EMT_TRANSPARENT_ADD_COLOR: + return EVT_STANDARD; + + case EMT_TRANSPARENT_ALPHA_CHANNEL: + return EVT_STANDARD; + + case EMT_TRANSPARENT_ALPHA_CHANNEL_REF: + return EVT_STANDARD; + + case EMT_TRANSPARENT_VERTEX_ALPHA: + return EVT_STANDARD; + + case EMT_TRANSPARENT_REFLECTION_2_LAYER: + return EVT_2TCOORDS; + + case EMT_NORMAL_MAP_SOLID: + case EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR: + case EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA: + case EMT_PARALLAX_MAP_SOLID: + case EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR: + case EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA: + return EVT_TANGENTS; + + case EMT_ONETEXTURE_BLEND: + return EVT_STANDARD; + + case EMT_FORCE_32BIT: + return EVT_STANDARD; + } + return EVT_STANDARD; +} + +/* + Custom GUI-control to edit colorvalues. +*/ +// Constructor +CColorControl::CColorControl(gui::IGUIEnvironment* guiEnv, const core::position2d & pos, const wchar_t *text, IGUIElement* parent, s32 id) + : gui::IGUIElement(gui::EGUIET_ELEMENT, guiEnv, parent,id, core::rect< s32 >(pos, pos+core::dimension2d(80, 75))) + , DirtyFlag(true) + , Color(0) + , ColorStatic(0) + , EditAlpha(0) + , EditRed(0) + , EditGreen(0) + , EditBlue(0) +{ + using namespace gui; + ButtonSetId = makeUniqueId(); + + const core::rect< s32 > rectControls(0,0,AbsoluteRect.getWidth(),AbsoluteRect.getHeight() ); + IGUIStaticText * groupElement = guiEnv->addStaticText (L"", rectControls, true, false, this, -1, false); + groupElement->setNotClipped(true); + + guiEnv->addStaticText (text, core::rect(0,0,80,15), false, false, groupElement, -1, false); + + EditAlpha = addEditForNumbers(guiEnv, core::position2d(0,15), L"a", -1, groupElement ); + EditRed = addEditForNumbers(guiEnv, core::position2d(0,30), L"r", -1, groupElement ); + EditGreen = addEditForNumbers(guiEnv, core::position2d(0,45), L"g", -1, groupElement ); + EditBlue = addEditForNumbers(guiEnv, core::position2d(0,60), L"b", -1, groupElement ); + + ColorStatic = guiEnv->addStaticText (L"", core::rect(60,15,80,75), true, false, groupElement, -1, true); + + guiEnv->addButton (core::rect(60,35,80,50), groupElement, ButtonSetId, L"set"); + setEditsFromColor(Color); +} + +// event receiver +bool CColorControl::OnEvent(const SEvent &event) +{ + if ( event.EventType != EET_GUI_EVENT ) + return false; + + if ( event.GUIEvent.Caller->getID() == ButtonSetId && event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED ) + { + Color = getColorFromEdits(); + setEditsFromColor(Color); + } + + return false; +} + +// set the color values +void CColorControl::setColor(const video::SColor& col) +{ + DirtyFlag = true; + Color = col; + setEditsFromColor(Color); +} + +// Add a staticbox for a description + an editbox so users can enter numbers +gui::IGUIEditBox* CColorControl::addEditForNumbers(gui::IGUIEnvironment* guiEnv, const core::position2d & pos, const wchar_t *text, s32 id, gui::IGUIElement * parent) +{ + using namespace gui; + + core::rect< s32 > rect(pos, pos+core::dimension2d(10, 15)); + guiEnv->addStaticText (text, rect, false, false, parent, -1, false); + rect += core::position2d( 20, 0 ); + rect.LowerRightCorner.X += 20; + gui::IGUIEditBox* edit = guiEnv->addEditBox(L"0", rect, true, parent, id); + return edit; +} + +// Get the color value from the editfields +video::SColor CColorControl::getColorFromEdits() const +{ + video::SColor col; + + if (EditAlpha) + { + u32 alpha = core::strtoul10(core::stringc(EditAlpha->getText()).c_str()); + if (alpha > 255) + alpha = 255; + col.setAlpha(alpha); + } + + if (EditRed) + { + u32 red = core::strtoul10(core::stringc(EditRed->getText()).c_str()); + if (red > 255) + red = 255; + col.setRed(red); + } + + if (EditGreen) + { + u32 green = core::strtoul10(core::stringc(EditGreen->getText()).c_str()); + if (green > 255) + green = 255; + col.setGreen(green); + } + + if (EditBlue) + { + u32 blue = core::strtoul10(core::stringc(EditBlue->getText()).c_str()); + if (blue > 255) + blue = 255; + col.setBlue(blue); + } + + return col; +} + +// Fill the editfields with the value for the given color +void CColorControl::setEditsFromColor(video::SColor col) +{ + DirtyFlag = true; + if ( EditAlpha ) + EditAlpha->setText( core::stringw(col.getAlpha()).c_str() ); + if ( EditRed ) + EditRed->setText( core::stringw(col.getRed()).c_str() ); + if ( EditGreen ) + EditGreen->setText( core::stringw(col.getGreen()).c_str() ); + if ( EditBlue ) + EditBlue->setText( core::stringw(col.getBlue()).c_str() ); + if ( ColorStatic ) + ColorStatic->setBackgroundColor(col); +} + +/* + Custom GUI-control for to edit all colors typically used in materials and lights +*/ +// Constructor +CTypicalColorsControl::CTypicalColorsControl(gui::IGUIEnvironment* guiEnv, const core::position2d & pos, bool hasEmissive, IGUIElement* parent, s32 id) + : gui::IGUIElement(gui::EGUIET_ELEMENT, guiEnv, parent,id, core::rect(pos,pos+core::dimension2d(60,250))) + , ControlAmbientColor(0), ControlDiffuseColor(0), ControlSpecularColor(0), ControlEmissiveColor(0) +{ + ControlAmbientColor = new CColorControl( guiEnv, core::position2d(0, 0), L"Ambient", this); + ControlDiffuseColor = new CColorControl( guiEnv, core::position2d(0, 75), L"Diffuse", this ); + ControlSpecularColor = new CColorControl( guiEnv, core::position2d(0, 150), L"Specular", this ); + if ( hasEmissive ) + { + ControlEmissiveColor = new CColorControl( guiEnv, core::position2d(0, 225), L"Emissive", this ); + } +} + +// Destructor +CTypicalColorsControl::~CTypicalColorsControl() +{ + ControlAmbientColor->drop(); + ControlDiffuseColor->drop(); + if ( ControlEmissiveColor ) + ControlEmissiveColor->drop(); + ControlSpecularColor->drop(); +} + +// Set the color values to those within the material +void CTypicalColorsControl::setColorsToMaterialColors(const video::SMaterial & material) +{ + ControlAmbientColor->setColor(material.AmbientColor); + ControlDiffuseColor->setColor(material.DiffuseColor); + ControlEmissiveColor->setColor(material.EmissiveColor); + ControlSpecularColor->setColor(material.SpecularColor); +} + +// Update all changed colors in the material +void CTypicalColorsControl::updateMaterialColors(video::SMaterial & material) const +{ + if ( ControlAmbientColor->isDirty() ) + material.AmbientColor = ControlAmbientColor->getColor(); + if ( ControlDiffuseColor->isDirty() ) + material.DiffuseColor = ControlDiffuseColor->getColor(); + if ( ControlEmissiveColor->isDirty() ) + material.EmissiveColor = ControlEmissiveColor->getColor(); + if ( ControlSpecularColor->isDirty() ) + material.SpecularColor = ControlSpecularColor->getColor(); +} + +// Set the color values to those from the light data +void CTypicalColorsControl::setColorsToLightDataColors(const video::SLight & lightData) +{ + ControlAmbientColor->setColor(lightData.AmbientColor.toSColor()); + ControlDiffuseColor->setColor(lightData.DiffuseColor.toSColor()); + ControlSpecularColor->setColor(lightData.SpecularColor.toSColor()); +} + +// Update all changed colors in the light data +void CTypicalColorsControl::updateLightColors(video::SLight & lightData) const +{ + if ( ControlAmbientColor->isDirty() ) + lightData.AmbientColor = video::SColorf( ControlAmbientColor->getColor() ); + if ( ControlDiffuseColor->isDirty() ) + lightData.DiffuseColor = video::SColorf( ControlDiffuseColor->getColor() ); + if ( ControlSpecularColor->isDirty() ) + lightData.SpecularColor = video::SColorf(ControlSpecularColor->getColor() ); +} + +// To reset the dirty flags +void CTypicalColorsControl::resetDirty() +{ + ControlAmbientColor->resetDirty(); + ControlDiffuseColor->resetDirty(); + ControlSpecularColor->resetDirty(); + if ( ControlEmissiveColor ) + ControlEmissiveColor->resetDirty(); +} + + +/* + GUI-Control to offer a selection of available textures. +*/ +CTextureControl::CTextureControl(gui::IGUIEnvironment* guiEnv, video::IVideoDriver * driver, const core::position2d & pos, IGUIElement* parent, s32 id) +: gui::IGUIElement(gui::EGUIET_ELEMENT, guiEnv, parent,id, core::rect(pos,pos+core::dimension2d(150,15))) +, DirtyFlag(true), ComboTexture(0) +{ + core::rect rectCombo(0, 0, AbsoluteRect.getWidth(),AbsoluteRect.getHeight()); + ComboTexture = guiEnv->addComboBox (rectCombo, this); + updateTextures(driver); +} + +bool CTextureControl::OnEvent(const SEvent &event) +{ + if ( event.EventType != EET_GUI_EVENT ) + return false; + + if ( event.GUIEvent.Caller == ComboTexture && event.GUIEvent.EventType == gui::EGET_COMBO_BOX_CHANGED ) + { + DirtyFlag = true; + } + + return false; +} + +// Workaround for a problem with comboboxes. +// We have to get in front when the combobox wants to get in front or combobox-list might be drawn below other elements. +bool CTextureControl::bringToFront(IGUIElement* element) +{ + bool result = gui::IGUIElement::bringToFront(element); + if ( Parent && element == ComboTexture ) + result &= Parent->bringToFront(this); + return result; +} + +// return selected texturename (if any, otherwise 0) +const wchar_t * CTextureControl::getSelectedTextureName() const +{ + s32 selected = ComboTexture->getSelected(); + if ( selected < 0 ) + return 0; + return ComboTexture->getItem(selected); +} + +void CTextureControl::selectTextureByName(const irr::core::stringw& name) +{ + for (u32 i=0; i< ComboTexture->getItemCount(); ++i) + { + if ( name == ComboTexture->getItem(i)) + { + ComboTexture->setSelected(i); + DirtyFlag = true; + return; + } + } +} + +// Put the names of all currently loaded textures in a combobox +void CTextureControl::updateTextures(video::IVideoDriver * driver) +{ + s32 oldSelected = ComboTexture->getSelected(); + s32 selectNew = -1; + core::stringw oldTextureName; + if ( oldSelected >= 0 ) + { + oldTextureName = ComboTexture->getItem(oldSelected); + } + ComboTexture->clear(); + for ( u32 i=0; i < driver->getTextureCount(); ++i ) + { + video::ITexture * texture = driver->getTextureByIndex(i); + core::stringw name( texture->getName() ); + ComboTexture->addItem( name.c_str() ); + if ( !oldTextureName.empty() && selectNew < 0 && name == oldTextureName ) + selectNew = i; + } + + // add another name which can be used to clear the texture + ComboTexture->addItem( CLEAR_TEXTURE.c_str() ); + if ( CLEAR_TEXTURE == oldTextureName ) + selectNew = ComboTexture->getItemCount()-1; + + if ( selectNew >= 0 ) + ComboTexture->setSelected(selectNew); + + DirtyFlag = true; +} + +/* + Control which allows setting some of the material values for a meshscenenode +*/ +void CMaterialControl::init(scene::IMeshSceneNode* node, IrrlichtDevice * device, const core::position2d & pos, const wchar_t * description) +{ + if ( Initialized || !node || !device) // initializing twice or with invalid data not allowed + return; + + Driver = device->getVideoDriver (); + gui::IGUIEnvironment* guiEnv = device->getGUIEnvironment(); + scene::ISceneManager* smgr = device->getSceneManager(); + const video::SMaterial & material = node->getMaterial(0); + + s32 top = pos.Y; + + // Description + guiEnv->addStaticText(description, core::rect(pos.X, top, pos.X+60, top+15), false, false, 0, -1, false); + top += 15; + + // Control for material type + core::rect rectCombo(pos.X, top, 150, top+15); + top += 15; + ComboMaterial = guiEnv->addComboBox (rectCombo); + for ( int i=0; i <= (int)video::EMT_ONETEXTURE_BLEND; ++i ) + { + ComboMaterial->addItem( core::stringw(video::sBuiltInMaterialTypeNames[i]).c_str() ); + } + ComboMaterial->setSelected( (s32)material.MaterialType ); + + // Control to enable/disabling material lighting + core::rect rectBtn(core::position2d(pos.X, top), core::dimension2d(100, 15)); + top += 15; + ButtonLighting = guiEnv->addButton (rectBtn, 0, -1, L"Lighting"); + ButtonLighting->setIsPushButton(true); + ButtonLighting->setPressed(material.Lighting); + core::rect rectInfo( rectBtn.LowerRightCorner.X, rectBtn.UpperLeftCorner.Y, rectBtn.LowerRightCorner.X+40, rectBtn.UpperLeftCorner.Y+15 ); + InfoLighting = guiEnv->addStaticText(L"", rectInfo, true, false ); + InfoLighting->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER ); + + // Controls for colors + TypicalColorsControl = new CTypicalColorsControl(guiEnv, core::position2d(pos.X, top), true, guiEnv->getRootGUIElement()); + top += 300; + TypicalColorsControl->setColorsToMaterialColors(material); + + // Controls for selecting the material textures + guiEnv->addStaticText(L"Textures", core::rect(pos.X, top, pos.X+60, top+15), false, false, 0, -1, false); + top += 15; + + for (irr::u32 i=0; igetRootGUIElement()); + top += 15; + } + + Initialized = true; +} + +void CMaterialControl::update(scene::IMeshSceneNode* sceneNode, scene::IMeshSceneNode* sceneNode2T, scene::IMeshSceneNode* sceneNodeTangents) +{ + if ( !Initialized ) + return; + + video::SMaterial & material = sceneNode->getMaterial(0); + video::SMaterial & material2T = sceneNode2T->getMaterial(0); + video::SMaterial & materialTangents = sceneNodeTangents->getMaterial(0); + + s32 selectedMaterial = ComboMaterial->getSelected(); + if ( selectedMaterial >= (s32)video::EMT_SOLID && selectedMaterial <= (s32)video::EMT_ONETEXTURE_BLEND) + { + // Show the node which has a mesh to work with the currently selected material + video::E_VERTEX_TYPE vertexType = getVertexTypeForMaterialType((video::E_MATERIAL_TYPE)selectedMaterial); + switch ( vertexType ) + { + case video::EVT_STANDARD: + material.MaterialType = (video::E_MATERIAL_TYPE)selectedMaterial; + sceneNode->setVisible(true); + sceneNode2T->setVisible(false); + sceneNodeTangents->setVisible(false); + break; + case video::EVT_2TCOORDS: + material2T.MaterialType = (video::E_MATERIAL_TYPE)selectedMaterial; + sceneNode->setVisible(false); + sceneNode2T->setVisible(true); + sceneNodeTangents->setVisible(false); + break; + case video::EVT_TANGENTS: + materialTangents.MaterialType = (video::E_MATERIAL_TYPE)selectedMaterial; + sceneNode->setVisible(false); + sceneNode2T->setVisible(false); + sceneNodeTangents->setVisible(true); + break; + } + } + + // Always update materials of all nodes, otherwise the tool is confusing to use. + updateMaterial(material); + updateMaterial(material2T); + updateMaterial(materialTangents); + + if ( ButtonLighting->isPressed() ) + InfoLighting->setText(L"is on"); + else + InfoLighting->setText(L"is off"); + + TypicalColorsControl->resetDirty(); + + for (irr::u32 i=0; iresetDirty(); +} + +void CMaterialControl::updateTextures() +{ + for (irr::u32 i=0; iupdateTextures(Driver); +} + +void CMaterialControl::selectTextures(const irr::core::stringw& name) +{ + for (irr::u32 i=0; iselectTextureByName(name); +} + +bool CMaterialControl::isLightingEnabled() const +{ + return ButtonLighting && ButtonLighting->isPressed(); +} + +void CMaterialControl::updateMaterial(video::SMaterial & material) +{ + TypicalColorsControl->updateMaterialColors(material); + material.Lighting = ButtonLighting->isPressed(); + for (irr::u32 i=0; iisDirty() ) + { + material.TextureLayer[i].Texture = Driver->getTexture( io::path(TextureControls[i]->getSelectedTextureName()) ); + } + } +} + +/* + Control to allow setting the color values of a lightscenenode. +*/ + +void CLightNodeControl::init(scene::ILightSceneNode* node, gui::IGUIEnvironment* guiEnv, const core::position2d & pos, const wchar_t * description) +{ + if ( Initialized || !node || !guiEnv) // initializing twice or with invalid data not allowed + return; + + guiEnv->addStaticText(description, core::rect(pos.X, pos.Y, pos.X+70, pos.Y+15), false, false, 0, -1, false); + TypicalColorsControl = new CTypicalColorsControl(guiEnv, core::position2d(pos.X, pos.Y+15), false, guiEnv->getRootGUIElement()); + const video::SLight & lightData = node->getLightData(); + TypicalColorsControl->setColorsToLightDataColors(lightData); + Initialized = true; +} + +void CLightNodeControl::update(scene::ILightSceneNode* node) +{ + if ( !Initialized ) + return; + + video::SLight & lightData = node->getLightData(); + TypicalColorsControl->updateLightColors(lightData); +} + +/* + Main application class +*/ + +/* + Event handler +*/ +bool CApp::OnEvent(const SEvent &event) +{ + if (event.EventType == EET_GUI_EVENT) + { + gui::IGUIEnvironment* env = Device->getGUIEnvironment(); + + switch(event.GUIEvent.EventType) + { + case gui::EGET_MENU_ITEM_SELECTED: + { + gui::IGUIContextMenu* menu = (gui::IGUIContextMenu*)event.GUIEvent.Caller; + s32 id = menu->getItemCommandId(menu->getSelectedItem()); + + switch(id) + { + case GUI_ID_OPEN_TEXTURE: // File -> Open Texture + env->addFileOpenDialog(L"Please select a texture file to open"); + break; + case GUI_ID_QUIT: // File -> Quit + setRunning(false); + break; + } + } + break; + + case gui::EGET_FILE_SELECTED: + { + // load the model file, selected in the file open dialog + gui::IGUIFileOpenDialog* dialog = + (gui::IGUIFileOpenDialog*)event.GUIEvent.Caller; + loadTexture(io::path(dialog->getFileName()).c_str()); + } + break; + + default: + break; + } + } + else if (event.EventType == EET_KEY_INPUT_EVENT) + { + KeysPressed[event.KeyInput.Key] = event.KeyInput.PressedDown; + } + else if (event.EventType == EET_MOUSE_INPUT_EVENT) + { + if (!MousePressed && event.MouseInput.isLeftPressed()) + { + gui::IGUIEnvironment* guiEnv = Device->getGUIEnvironment(); + if ( guiEnv->getHovered() == guiEnv->getRootGUIElement() ) // Click on background + { + MousePressed = true; + MouseStart.X = event.MouseInput.X; + MouseStart.Y = event.MouseInput.Y; + } + } + else if (MousePressed && !event.MouseInput.isLeftPressed()) + { + MousePressed = false; + } + } + + return false; +} + +// Application initialization +// returns true when it was successful initialized, otherwise false. +bool CApp::init(int argc, char *argv[]) +{ + // ask user for driver + Config.DriverType=driverChoiceConsole(); + if (Config.DriverType==video::EDT_COUNT) + return false; + + // create the device with the settings from our config + Device = createDevice(Config.DriverType, Config.ScreenSize); + if (!Device) + return false; + + Device->setWindowCaption( core::stringw(video::DRIVER_TYPE_NAMES[Config.DriverType]).c_str() ); + Device->setEventReceiver(this); + + scene::ISceneManager* smgr = Device->getSceneManager(); + video::IVideoDriver * driver = Device->getVideoDriver (); + gui::IGUIEnvironment* guiEnv = Device->getGUIEnvironment(); + MeshManipulator = smgr->getMeshManipulator(); + + // set a nicer font + gui::IGUISkin* skin = guiEnv->getSkin(); + gui::IGUIFont* font = guiEnv->getFont(getExampleMediaPath() + "fonthaettenschweiler.bmp"); + if (font) + skin->setFont(font); + + // remove some alpha value because it makes those menus harder to read otherwise + video::SColor col3dHighLight( skin->getColor(gui::EGDC_APP_WORKSPACE) ); + col3dHighLight.setAlpha(255); + video::SColor colHighLight( col3dHighLight ); + skin->setColor(gui::EGDC_HIGH_LIGHT, colHighLight ); + skin->setColor(gui::EGDC_3D_HIGH_LIGHT, col3dHighLight ); + + // Add some textures which are useful to test material settings + createDefaultTextures(driver); + + // create a menu + gui::IGUIContextMenu * menuBar = guiEnv->addMenu(); + menuBar->addItem(L"File", -1, true, true); + + gui::IGUIContextMenu* subMenuFile = menuBar->getSubMenu(0); + subMenuFile->addItem(L"Open texture ...", GUI_ID_OPEN_TEXTURE); + subMenuFile->addSeparator(); + subMenuFile->addItem(L"Quit", GUI_ID_QUIT); + + // a static camera + Camera = smgr->addCameraSceneNode (0, core::vector3df(0, 40, -40), + core::vector3df(0, 10, 0), + -1); + + // default material + video::SMaterial defaultMaterial; + defaultMaterial.Shininess = 20.f; + + // add the nodes which are used to show the materials + SceneNode = smgr->addCubeSceneNode (30.0f, 0, -1, + core::vector3df(0, 0, 0), + core::vector3df(0.f, 45.f, 0.f), + core::vector3df(1.0f, 1.0f, 1.0f)); + SceneNode->getMaterial(0) = defaultMaterial; + + const s32 controlsTop = 20; + MeshMaterialControl = new CMaterialControl(); + MeshMaterialControl->init( SceneNode, Device, core::position2d(10,controlsTop), L"Material" ); + MeshMaterialControl->selectTextures(core::stringw("CARO_A8R8G8B8")); // set a useful default texture + + // create nodes with other vertex types + scene::IMesh * mesh2T = MeshManipulator->createMeshWith2TCoords(SceneNode->getMesh()); + SceneNode2T = smgr->addMeshSceneNode(mesh2T, 0, -1, SceneNode->getPosition(), SceneNode->getRotation(), SceneNode->getScale() ); + mesh2T->drop(); + + scene::IMesh * meshTangents = MeshManipulator->createMeshWithTangents(SceneNode->getMesh(), false, false, false); + SceneNodeTangents = smgr->addMeshSceneNode(meshTangents, 0, -1 + , SceneNode->getPosition(), SceneNode->getRotation(), SceneNode->getScale() ); + meshTangents->drop(); + + + // add one light + NodeLight = smgr->addLightSceneNode(0, core::vector3df(0, 0, -40), + video::SColorf(1.0f, 1.0f, 1.0f), + 35.0f); + LightControl = new CLightNodeControl(); + LightControl->init(NodeLight, guiEnv, core::position2d(550,controlsTop), L"Dynamic light" ); + + // one large cube around everything. That's mainly to make the light more obvious. + scene::IMeshSceneNode* backgroundCube = smgr->addCubeSceneNode (200.0f, 0, -1, core::vector3df(0, 0, 0), + core::vector3df(45, 0, 0), + core::vector3df(1.0f, 1.0f, 1.0f)); + backgroundCube->getMaterial(0).BackfaceCulling = false; // we are within the cube, so we have to disable backface culling to see it + backgroundCube->getMaterial(0).EmissiveColor.set(255,50,50,50); // we keep some self lighting to keep texts visible + + + // Add a the mesh vertex color control + guiEnv->addStaticText(L"Mesh", core::rect(200, controlsTop, 270, controlsTop+15), false, false, 0, -1, false); + ControlVertexColors = new CColorControl( guiEnv, core::position2d(200, controlsTop+15), L"Vertex colors", guiEnv->getRootGUIElement()); + video::S3DVertex * vertices = (video::S3DVertex *)SceneNode->getMesh()->getMeshBuffer(0)->getVertices(); + if ( vertices ) + { + ControlVertexColors->setColor(vertices[0].Color); + } + + // Add a control for ambient light + GlobalAmbient = new CColorControl( guiEnv, core::position2d(550, 300), L"Global ambient", guiEnv->getRootGUIElement()); + GlobalAmbient->setColor( smgr->getAmbientLight().toSColor() ); + + return true; +} + +/* + Update one frame +*/ +bool CApp::update() +{ + using namespace irr; + + video::IVideoDriver* videoDriver = Device->getVideoDriver(); + if ( !Device->run() ) + return false; + + // Figure out delta time since last frame + ITimer * timer = Device->getTimer(); + u32 newTick = timer->getRealTime(); + f32 deltaTime = RealTimeTick > 0 ? f32(newTick-RealTimeTick)/1000.f : 0.f; // in seconds + RealTimeTick = newTick; + + if ( Device->isWindowActive() || Config.RenderInBackground ) + { + gui::IGUIEnvironment* guiEnv = Device->getGUIEnvironment(); + scene::ISceneManager* smgr = Device->getSceneManager(); + gui::IGUISkin * skin = guiEnv->getSkin(); + + // update our controls + MeshMaterialControl->update(SceneNode, SceneNode2T, SceneNodeTangents); + LightControl->update(NodeLight); + + // Update vertices + if ( ControlVertexColors->isDirty() ) + { + MeshManipulator->setVertexColors (SceneNode->getMesh(), ControlVertexColors->getColor()); + MeshManipulator->setVertexColors (SceneNode2T->getMesh(), ControlVertexColors->getColor()); + MeshManipulator->setVertexColors (SceneNodeTangents->getMesh(), ControlVertexColors->getColor()); + ControlVertexColors->resetDirty(); + } + + // update ambient light settings + if ( GlobalAmbient->isDirty() ) + { + smgr->setAmbientLight( GlobalAmbient->getColor() ); + GlobalAmbient->resetDirty(); + } + + // Let the user move the light around + const float zoomSpeed = 10.f * deltaTime; + const float rotationSpeed = 100.f * deltaTime; + if ( KeysPressed[KEY_PLUS] || KeysPressed[KEY_ADD]) + ZoomOut(NodeLight, zoomSpeed); + if ( KeysPressed[KEY_MINUS] || KeysPressed[KEY_SUBTRACT]) + ZoomOut(NodeLight, -zoomSpeed); + if ( KeysPressed[KEY_RIGHT]) + RotateHorizontal(NodeLight, rotationSpeed); + if ( KeysPressed[KEY_LEFT]) + RotateHorizontal(NodeLight, -rotationSpeed); + UpdateRotationAxis(NodeLight, LightRotationAxis); + if ( KeysPressed[KEY_UP]) + RotateAroundAxis(NodeLight, rotationSpeed, LightRotationAxis); + if ( KeysPressed[KEY_DOWN]) + RotateAroundAxis(NodeLight, -rotationSpeed, LightRotationAxis); + + // Let the user move the camera around + if (MousePressed) + { + gui::ICursorControl* cursorControl = Device->getCursorControl(); + const core::position2d& mousePos = cursorControl->getPosition (); + RotateHorizontal(Camera, rotationSpeed * (MouseStart.X - mousePos.X)); + RotateAroundAxis(Camera, rotationSpeed * (mousePos.Y - MouseStart.Y), CameraRotationAxis); + MouseStart = mousePos; + } + + // draw everything + video::SColor bkColor( skin->getColor(gui::EGDC_APP_WORKSPACE) ); + videoDriver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, bkColor); + + smgr->drawAll(); + guiEnv->drawAll(); + + if ( MeshMaterialControl->isLightingEnabled() ) + { + // draw a line from the light to the target + video::SMaterial lineMaterial; + lineMaterial.Lighting = false; + videoDriver->setMaterial(lineMaterial); + videoDriver->setTransform(video::ETS_WORLD, core::IdentityMatrix); + videoDriver->draw3DLine(NodeLight->getAbsolutePosition(), SceneNode->getAbsolutePosition()); + } + + videoDriver->endScene(); + } + + // be nice + Device->sleep( 5 ); + + return true; +} + +// Close down the application +void CApp::quit() +{ + IsRunning = false; + + delete LightControl; + LightControl = NULL; + + delete MeshMaterialControl; + MeshMaterialControl = NULL; + + if ( ControlVertexColors ) + { + ControlVertexColors->drop(); + ControlVertexColors = NULL; + } + if ( GlobalAmbient ) + { + GlobalAmbient->drop(); + GlobalAmbient = NULL; + } + if ( Device ) + { + Device->closeDevice(); + Device->drop(); + Device = NULL; + } +} + +// Create some useful textures. +void CApp::createDefaultTextures(video::IVideoDriver * driver) +{ + const u32 width = 256; + const u32 height = 256; + video::IImage * imageA8R8G8B8 = driver->createImage (video::ECF_A8R8G8B8, core::dimension2d(width, height)); + if ( !imageA8R8G8B8 ) + return; + const u32 pitch = imageA8R8G8B8->getPitch(); + + // Some nice square-pattern with 9 typical colors + // Note that the function put readability over speed, you shouldn't use setPixel at runtime but for initialization it's nice. + for ( u32 y = 0; y < height; ++ y ) + { + for ( u32 x = 0; x < pitch; ++x ) + { + if ( y < height/3 ) + { + if ( x < width/3 ) + imageA8R8G8B8->setPixel (x, y, SCOL_BLACK); + else if ( x < 2*width/3 ) + imageA8R8G8B8->setPixel (x, y, SCOL_BLUE); + else + imageA8R8G8B8->setPixel (x, y, SCOL_CYAN); + } + else if ( y < 2*height/3 ) + { + if ( x < width/3 ) + imageA8R8G8B8->setPixel (x, y, SCOL_GRAY); + else if ( x < 2*width/3 ) + imageA8R8G8B8->setPixel (x, y, SCOL_GREEN); + else + imageA8R8G8B8->setPixel (x, y, SCOL_MAGENTA); + } + else + { + if ( x < width/3 ) + imageA8R8G8B8->setPixel (x, y, SCOL_RED); + else if ( x < 2*width/3 ) + imageA8R8G8B8->setPixel (x, y, SCOL_YELLOW); + else + imageA8R8G8B8->setPixel (x, y, SCOL_WHITE); + } + } + } + driver->addTexture (io::path("CARO_A8R8G8B8"), imageA8R8G8B8); + + // all white + imageA8R8G8B8->fill(SCOL_WHITE); + driver->addTexture (io::path("WHITE_A8R8G8B8"), imageA8R8G8B8); + + // all black + imageA8R8G8B8->fill(SCOL_BLACK); + driver->addTexture (io::path("BLACK_A8R8G8B8"), imageA8R8G8B8); + + // gray-scale + for ( u32 y = 0; y < height; ++ y ) + { + for ( u32 x = 0; x < pitch; ++x ) + { + imageA8R8G8B8->setPixel (x, y, video::SColor(y, x,x,x) ); + } + } + driver->addTexture (io::path("GRAYSCALE_A8R8G8B8"), imageA8R8G8B8); + + imageA8R8G8B8->drop(); +} + +// Load a texture and make sure nodes know it when more textures are available. +void CApp::loadTexture(const io::path &name) +{ + Device->getVideoDriver()->getTexture(name); + MeshMaterialControl->updateTextures(); +} + +void CApp::RotateHorizontal(irr::scene::ISceneNode* node, irr::f32 angle) +{ + if ( node ) + { + core::vector3df pos(node->getPosition()); + core::vector2df dir(pos.X, pos.Z); + dir.rotateBy(angle); + pos.X = dir.X; + pos.Z = dir.Y; + node->setPosition(pos); + } +} + +void CApp::RotateAroundAxis(irr::scene::ISceneNode* node, irr::f32 angle, const irr::core::vector3df& axis) +{ + if ( node ) + { + // TOOD: yeah, doesn't rotate around top/bottom yet. Fixes welcome. + core::vector3df pos(node->getPosition()); + core::matrix4 mat; + mat.setRotationAxisRadians (core::degToRad(angle), axis); + mat.rotateVect(pos); + node->setPosition(pos); + } +} + +void CApp::ZoomOut(irr::scene::ISceneNode* node, irr::f32 units) +{ + if ( node ) + { + core::vector3df pos(node->getPosition()); + irr::f32 len = pos.getLength() + units; + pos.setLength(len); + node->setPosition(pos); + } +} + +void CApp::UpdateRotationAxis(irr::scene::ISceneNode* node, irr::core::vector3df& axis) +{ + // Find a perpendicular axis to the x,z vector. If none found (vector straight up/down) continue to use the existing one. + core::vector3df pos(node->getPosition()); + if ( !core::equals(pos.X, 0.f) || !core::equals(pos.Z, 0.f) ) + { + axis.X = -pos.Z; + axis.Z = pos.X; + axis.normalize(); + } +} + +/* + Short main as most is done in classes. +*/ +int main(int argc, char *argv[]) +{ + CApp APP; + + if ( !APP.init(argc, argv) ) + { + printf("init failed\n"); + APP.quit(); + return 1; + } + + APP.setRunning(true); + + /* + main application loop + */ + while(APP.isRunning()) + { + if ( !APP.update() ) + break; + } + + APP.quit(); + + return 0; +} + +/* +**/ diff --git a/examples/22.MaterialViewer/main.h b/examples/22.MaterialViewer/main.h new file mode 100644 index 00000000..8fabc01d --- /dev/null +++ b/examples/22.MaterialViewer/main.h @@ -0,0 +1,319 @@ +#ifndef EXAMPLE22_MATERIAL_VIEWER_MAIN_H +#define EXAMPLE22_MATERIAL_VIEWER_MAIN_H + +#include + +// Helper control to allow setting colors +class CColorControl : public irr::gui::IGUIElement +{ +public: + CColorControl(irr::gui::IGUIEnvironment* guiEnv, const irr::core::position2d & pos, const wchar_t *text, irr::gui::IGUIElement* parent, irr::s32 id=-1); + + // Event receiver + virtual bool OnEvent(const irr::SEvent &event); + + // Set the color values + void setColor(const irr::video::SColor& col); + + // Get the color values + const irr::video::SColor& getColor() const + { + return Color; + } + + // To reset the dirty flag + void resetDirty() + { + DirtyFlag = false; + } + + // when the color was changed the dirty flag is set + bool isDirty() const + { + return DirtyFlag; + }; + +protected: + + // Add a staticbox for a description + an editbox so users can enter numbers + irr::gui::IGUIEditBox* addEditForNumbers(irr::gui::IGUIEnvironment* guiEnv, const irr::core::position2d & pos, const wchar_t *text, irr::s32 id, irr::gui::IGUIElement * parent); + + // Get the color value from the editfields + irr::video::SColor getColorFromEdits() const; + + // Fill the editfields with the value for the given color + void setEditsFromColor(irr::video::SColor col); + +private: + + bool DirtyFlag; + irr::video::SColor Color; + irr::s32 ButtonSetId; + irr::gui::IGUIStaticText * ColorStatic; + irr::gui::IGUIEditBox * EditAlpha; + irr::gui::IGUIEditBox * EditRed; + irr::gui::IGUIEditBox * EditGreen; + irr::gui::IGUIEditBox * EditBlue; +}; + +/* + Custom GUI-control for to edit all colors typically used in materials and lights +*/ +class CTypicalColorsControl : public irr::gui::IGUIElement +{ +public: + // Constructor + CTypicalColorsControl(irr::gui::IGUIEnvironment* guiEnv, const irr::core::position2d & pos, bool hasEmissive, irr::gui::IGUIElement* parent, irr::s32 id=-1); + + // Destructor + virtual ~CTypicalColorsControl(); + + // Set the color values to those within the material + void setColorsToMaterialColors(const irr::video::SMaterial & material); + + // Update all changed colors in the material + void updateMaterialColors(irr::video::SMaterial & material) const; + + // Set the color values to those from the light data + void setColorsToLightDataColors(const irr::video::SLight & lightData); + + // Update all changed colors in the light data + void updateLightColors(irr::video::SLight & lightData) const; + + // To reset the dirty flags + void resetDirty(); + +private: + CColorControl* ControlAmbientColor; + CColorControl* ControlDiffuseColor; + CColorControl* ControlSpecularColor; + CColorControl* ControlEmissiveColor; +}; + +/* + GUI-Control to offer a selection of available textures. +*/ +class CTextureControl : public irr::gui::IGUIElement +{ +public: + CTextureControl(irr::gui::IGUIEnvironment* guiEnv, irr::video::IVideoDriver * driver, const irr::core::position2d & pos, irr::gui::IGUIElement* parent, irr::s32 id=-1); + + virtual bool OnEvent(const irr::SEvent &event); + + // Workaround for a problem with comboboxes. + // We have to get in front when the combobox wants to get in front or combobox-list might be drawn below other elements. + virtual bool bringToFront(irr::gui::IGUIElement* element); + + // Return selected texturename (if any, otherwise 0) + const wchar_t * getSelectedTextureName() const; + + // Change active selectionbased on the texture name + void selectTextureByName(const irr::core::stringw& name); + + // Reset the dirty flag + void resetDirty() + { + DirtyFlag = false; + } + + // When the texture was changed the dirty flag is set + bool isDirty() const + { + return DirtyFlag; + }; + + // Put the names of all currently loaded textures in a combobox + void updateTextures(irr::video::IVideoDriver * driver); + +private: + bool DirtyFlag; + irr::gui::IGUIComboBox * ComboTexture; +}; + +/* + Control which allows setting some of the material values for a meshscenenode +*/ +class CMaterialControl +{ +public: + // constructor + CMaterialControl() + : Initialized(false), Driver(0) + , TypicalColorsControl(0), ButtonLighting(0), InfoLighting(0), ComboMaterial(0) + { + for (irr::u32 i=0; idrop(); + } + if ( TypicalColorsControl ) + TypicalColorsControl->drop(); + } + + void init(irr::scene::IMeshSceneNode* node, irr::IrrlichtDevice * device, const irr::core::position2d & pos, const wchar_t * description); + + void update(irr::scene::IMeshSceneNode* sceneNode, irr::scene::IMeshSceneNode* sceneNode2T, irr::scene::IMeshSceneNode* sceneNodeTangents); + + void updateTextures(); + + void selectTextures(const irr::core::stringw& name); + + bool isLightingEnabled() const; + +protected: + + void updateMaterial(irr::video::SMaterial & material); + + bool Initialized; + irr::video::IVideoDriver * Driver; + CTypicalColorsControl* TypicalColorsControl; + irr::gui::IGUIButton * ButtonLighting; + irr::gui::IGUIStaticText* InfoLighting; + irr::gui::IGUIComboBox * ComboMaterial; + CTextureControl* TextureControls[irr::video::MATERIAL_MAX_TEXTURES]; +}; + +/* + Control to allow setting the color values of a lightscenenode. +*/ +class CLightNodeControl +{ +public: + // constructor + CLightNodeControl() : Initialized(false), TypicalColorsControl(0) + {} + + ~CLightNodeControl() + { + if ( TypicalColorsControl ) + TypicalColorsControl->drop(); + } + + void init(irr::scene::ILightSceneNode* node, irr::gui::IGUIEnvironment* guiEnv, const irr::core::position2d & pos, const wchar_t * description); + + void update(irr::scene::ILightSceneNode* node); + +protected: + bool Initialized; + CTypicalColorsControl* TypicalColorsControl; +}; + +/* + Application configuration +*/ +struct SConfig +{ + SConfig() + : RenderInBackground(true) + , DriverType(irr::video::EDT_NULL) + , ScreenSize(640, 480) + { + } + + bool RenderInBackground; + irr::video::E_DRIVER_TYPE DriverType; + irr::core::dimension2d ScreenSize; +}; + +/* + Main application class +*/ +class CApp : public irr::IEventReceiver +{ + friend int main(int argc, char *argv[]); + +public: + // constructor + CApp() + : IsRunning(false) + , RealTimeTick(0) + , Device(0) + , MeshManipulator(0) + , Camera(0) + , SceneNode(0), SceneNode2T(0), SceneNodeTangents(0), NodeLight(0) + , CameraRotationAxis(irr::core::vector3df(1,0,0)) + , LightRotationAxis(irr::core::vector3df(1,0,0)) + , MeshMaterialControl(0) + , LightControl(0) + , ControlVertexColors(0) + , GlobalAmbient(0) + , MousePressed(false) + { + memset(KeysPressed, 0, sizeof KeysPressed); + } + + // destructor + ~CApp() + { + } + + // Tell it to stop running + void setRunning(bool appRuns) + { + IsRunning = appRuns; + } + + // Check if it should continue running + bool isRunning() const + { + return IsRunning; + } + + // Event handler + virtual bool OnEvent(const irr::SEvent &event); + +protected: + + // Application initialization + // returns true when it was successful initialized, otherwise false. + bool init(int argc, char *argv[]); + + // Update one frame + bool update(); + + // Close down the application + void quit(); + + // Create some useful textures. + void createDefaultTextures(irr::video::IVideoDriver * driver); + + // Load a texture and make sure nodes know it when more textures are available. + void loadTexture(const irr::io::path &name); + + // Rotate a node around the origin (0,0,0) + void RotateHorizontal(irr::scene::ISceneNode* node, irr::f32 angle); + void RotateAroundAxis(irr::scene::ISceneNode* node, irr::f32 angle, const irr::core::vector3df& axis); + void ZoomOut(irr::scene::ISceneNode* node, irr::f32 units); + void UpdateRotationAxis(irr::scene::ISceneNode* node, irr::core::vector3df& axis); + + +private: + SConfig Config; + bool IsRunning; + irr::u32 RealTimeTick; + irr::IrrlichtDevice * Device; + irr::scene::IMeshManipulator* MeshManipulator; + irr::scene::ICameraSceneNode * Camera; + irr::scene::IMeshSceneNode* SceneNode; + irr::scene::IMeshSceneNode* SceneNode2T; + irr::scene::IMeshSceneNode* SceneNodeTangents; + irr::scene::ILightSceneNode* NodeLight; + irr::core::vector3df CameraRotationAxis; + irr::core::vector3df LightRotationAxis; + CMaterialControl* MeshMaterialControl; + CLightNodeControl* LightControl; + CColorControl* ControlVertexColors; + CColorControl* GlobalAmbient; + bool KeysPressed[irr::KEY_KEY_CODES_COUNT]; + bool MousePressed; + irr::core::position2d MouseStart; +}; + +#endif diff --git a/examples/23.SMeshHandling/Makefile b/examples/23.SMeshHandling/Makefile new file mode 100644 index 00000000..3c7710b7 --- /dev/null +++ b/examples/23.SMeshHandling/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 23.SMeshHandling +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/23.SMeshHandling/SMeshHandling.cbp b/examples/23.SMeshHandling/SMeshHandling.cbp new file mode 100644 index 00000000..920efacc --- /dev/null +++ b/examples/23.SMeshHandling/SMeshHandling.cbp @@ -0,0 +1,44 @@ + + + + + + diff --git a/examples/23.SMeshHandling/SMeshHandling.vcproj b/examples/23.SMeshHandling/SMeshHandling.vcproj new file mode 100644 index 00000000..a63d583b --- /dev/null +++ b/examples/23.SMeshHandling/SMeshHandling.vcproj @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/23.SMeshHandling/SMeshHandling.xcodeproj/project.pbxproj b/examples/23.SMeshHandling/SMeshHandling.xcodeproj/project.pbxproj new file mode 100644 index 00000000..4382e543 --- /dev/null +++ b/examples/23.SMeshHandling/SMeshHandling.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 23.SMeshHandling.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 23.SMeshHandling.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 23.SMeshHandling.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 23.SMeshHandling */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "23.SMeshHandling" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 23.SMeshHandling; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 23.SMeshHandling.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "SMeshHandling" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 23.SMeshHandling */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "SMeshHandling" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "23.SMeshHandling" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/23.SMeshHandling/SMeshHandling.xcodeproj/xcshareddata/xcschemes/23.SMeshHandling.xcscheme b/examples/23.SMeshHandling/SMeshHandling.xcodeproj/xcshareddata/xcschemes/23.SMeshHandling.xcscheme new file mode 100644 index 00000000..9a7fc357 --- /dev/null +++ b/examples/23.SMeshHandling/SMeshHandling.xcodeproj/xcshareddata/xcschemes/23.SMeshHandling.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/23.SMeshHandling/SMeshHandling_vc10.vcxproj b/examples/23.SMeshHandling/SMeshHandling_vc10.vcxproj new file mode 100644 index 00000000..949f1ce6 --- /dev/null +++ b/examples/23.SMeshHandling/SMeshHandling_vc10.vcxproj @@ -0,0 +1,191 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 23.SMeshHandling + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7} + 23.SMeshHandling + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\23.SMeshHandling.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\23.SMeshHandling.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)SMeshHandling.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\23.SMeshHandling.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\23.SMeshHandling.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/23.SMeshHandling/SMeshHandling_vc11.vcxproj b/examples/23.SMeshHandling/SMeshHandling_vc11.vcxproj new file mode 100644 index 00000000..83332f4d --- /dev/null +++ b/examples/23.SMeshHandling/SMeshHandling_vc11.vcxproj @@ -0,0 +1,192 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 23.SMeshHandling + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7} + 23.SMeshHandling + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\23.SMeshHandling.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)SMeshHandling.pdb + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\23.SMeshHandling.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)SMeshHandling.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\23.SMeshHandling.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\23.SMeshHandling.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/23.SMeshHandling/SMeshHandling_vc12.vcxproj b/examples/23.SMeshHandling/SMeshHandling_vc12.vcxproj new file mode 100644 index 00000000..46b2382c --- /dev/null +++ b/examples/23.SMeshHandling/SMeshHandling_vc12.vcxproj @@ -0,0 +1,192 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 23.SMeshHandling + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7} + 23.SMeshHandling + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\23.SMeshHandling.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)SMeshHandling.pdb + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\23.SMeshHandling.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)SMeshHandling.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\23.SMeshHandling.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\23.SMeshHandling.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/23.SMeshHandling/SMeshHandling_vc14.vcxproj b/examples/23.SMeshHandling/SMeshHandling_vc14.vcxproj new file mode 100644 index 00000000..6c9b712b --- /dev/null +++ b/examples/23.SMeshHandling/SMeshHandling_vc14.vcxproj @@ -0,0 +1,192 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 23.SMeshHandling + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7} + 23.SMeshHandling + Win32Proj + + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\23.SMeshHandling.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)SMeshHandling.pdb + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\23.SMeshHandling.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)SMeshHandling.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\23.SMeshHandling.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\23.SMeshHandling.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/23.SMeshHandling/main.cpp b/examples/23.SMeshHandling/main.cpp new file mode 100644 index 00000000..2d413094 --- /dev/null +++ b/examples/23.SMeshHandling/main.cpp @@ -0,0 +1,426 @@ +/** Example 023 SMeshBufferHandling + +A tutorial by geoff. + +In this tutorial we'll learn how to create custom meshes and deal with them +with Irrlicht. We'll create an interesting heightmap with some lighting effects. +With keys 1,2,3 you can choose a different mesh layout, which is put into the +mesh buffers as desired. All positions, normals, etc. are updated accordingly. + +Ok, let's start with the headers (I think there's nothing to say about it) +*/ + +#include +#include "driverChoice.h" + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +//Namespaces for the engine +using namespace irr; +using namespace video; +using namespace core; +using namespace scene; +using namespace io; +using namespace gui; + +/* This is the type of the functions which work out the colour. */ +typedef SColor colour_func(f32 x, f32 y, f32 z); + +/* Here comes a set of functions which can be used for coloring the nodes while +creating the mesh. */ + +// Greyscale, based on the height. +SColor grey(f32, f32, f32 z) +{ + u32 n = (u32)(255.f * z); + return SColor(255, n, n, n); +} + +// Interpolation between blue and white, with red added in one +// direction and green in the other. +SColor yellow(f32 x, f32 y, f32) +{ + return SColor(255, 128 + (u32)(127.f * x), 128 + (u32)(127.f * y), 255); +} + +// Pure white. +SColor white(f32, f32, f32) { return SColor(255, 255, 255, 255); } + +/* The type of the functions which generate the heightmap. x and y +range between -0.5 and 0.5, and s is the scale of the heightmap. */ + +typedef f32 generate_func(s16 x, s16 y, f32 s); + +// An interesting sample function :-) +f32 eggbox(s16 x, s16 y, f32 s) +{ + const f32 r = 4.f*sqrtf((f32)(x*x + y*y))/s; + const f32 z = expf(-r * 2) * (cosf(0.2f * x) + cosf(0.2f * y)); + return 0.25f+0.25f*z; +} + +// A rather dumb sine function :-/ +f32 moresine(s16 x, s16 y, f32 s) +{ + const f32 xx=0.3f*(f32)x/s; + const f32 yy=12*y/s; + const f32 z = sinf(xx*xx+yy)*sinf(xx+yy*yy); + return 0.25f + 0.25f * z; +} + +// A simple function +f32 justexp(s16 x, s16 y, f32 s) +{ + const f32 xx=6*x/s; + const f32 yy=6*y/s; + const f32 z = (xx*xx+yy*yy); + return 0.3f*z*cosf(xx*yy); +} + +/* A simple class for representing heightmaps. Most of this should be obvious. */ + +class HeightMap +{ +private: + const u16 Width; + const u16 Height; + f32 s; + core::array data; +public: + HeightMap(u16 _w, u16 _h) : Width(_w), Height(_h), s(0.f), data(0) + { + s = sqrtf((f32)(Width * Width + Height * Height)); + data.set_used(Width * Height); + } + + // Fill the heightmap with values generated from f. + void generate(generate_func f) + { + u32 i=0; + for(u16 y = 0; y < Height; ++y) + for(u16 x = 0; x < Width; ++x) + set(i++, calc(f, x, y)); + } + + u16 height() const { return Height; } + u16 width() const { return Width; } + + f32 calc(generate_func f, u16 x, u16 y) const + { + const f32 xx = (f32)x - Width*0.5f; + const f32 yy = (f32)y - Height*0.5f; + return f((u16)xx, (u16)yy, s); + } + + // The height at (x, y) is at position y * Width + x. + + void set(u16 x, u16 y, f32 z) { data[y * Width + x] = z; } + void set(u32 i, f32 z) { data[i] = z; } + f32 get(u16 x, u16 y) const { return data[y * Width + x]; } + + /* The only difficult part. This considers the normal at (x, y) to + be the cross product of the vectors between the adjacent points + in the horizontal and vertical directions. + + s is a scaling factor, which is necessary if the height units are + different from the coordinate units; for example, if your map has + heights in meters and the coordinates are in units of a + kilometer. */ + + vector3df getnormal(u16 x, u16 y, f32 s) const + { + const f32 zc = get(x, y); + f32 zl, zr, zu, zd; + + if (x == 0) + { + zr = get(x + 1, y); + zl = zc + zc - zr; + } + else if (x == Width - 1) + { + zl = get(x - 1, y); + zr = zc + zc - zl; + } + else + { + zr = get(x + 1, y); + zl = get(x - 1, y); + } + + if (y == 0) + { + zd = get(x, y + 1); + zu = zc + zc - zd; + } + else if (y == Height - 1) + { + zu = get(x, y - 1); + zd = zc + zc - zu; + } + else + { + zd = get(x, y + 1); + zu = get(x, y - 1); + } + + return vector3df(s * 2 * (zl - zr), 4, s * 2 * (zd - zu)).normalize(); + } +}; + +/* A class which generates a mesh from a heightmap. */ +class TMesh +{ +private: + u16 Width; + u16 Height; + f32 Scale; +public: + SMesh* Mesh; + + TMesh() : Mesh(0), Width(0), Height(0), Scale(1.f) + { + Mesh = new SMesh(); + } + + ~TMesh() + { + Mesh->drop(); + } + + // Unless the heightmap is small, it won't all fit into a single + // SMeshBuffer. This function chops it into pieces and generates a + // buffer from each one. + + void init(const HeightMap &hm, f32 scale, colour_func cf, IVideoDriver *driver) + { + Scale = scale; + + const u32 mp = driver -> getMaximalPrimitiveCount(); + Width = hm.width(); + Height = hm.height(); + + const u32 sw = mp / (6 * Height); // the width of each piece + + u32 i=0; + for(u32 y0 = 0; y0 < Height; y0 += sw) + { + u16 y1 = y0 + sw; + if (y1 >= Height) + y1 = Height - 1; // the last one might be narrower + addstrip(hm, cf, y0, y1, i); + ++i; + } + if (igetMeshBufferCount()) + { + // clear the rest + for (u32 j=i; jgetMeshBufferCount(); ++j) + { + Mesh->getMeshBuffer(j)->drop(); + } + Mesh->MeshBuffers.erase(i,Mesh->getMeshBufferCount()-i); + } + // set dirty flag to make sure that hardware copies of this + // buffer are also updated, see IMesh::setHardwareMappingHint + Mesh->setDirty(); + Mesh->recalculateBoundingBox(); + } + + // Generate a SMeshBuffer which represents all the vertices and + // indices for values of y between y0 and y1, and add it to the + // mesh. + + void addstrip(const HeightMap &hm, colour_func cf, u16 y0, u16 y1, u32 bufNum) + { + SMeshBuffer *buf = 0; + if (bufNumgetMeshBufferCount()) + { + buf = (SMeshBuffer*)Mesh->getMeshBuffer(bufNum); + } + else + { + // create new buffer + buf = new SMeshBuffer(); + Mesh->addMeshBuffer(buf); + // to simplify things we drop here but continue using buf + buf->drop(); + } + buf->Vertices.set_used((1 + y1 - y0) * Width); + + u32 i=0; + for (u16 y = y0; y <= y1; ++y) + { + for (u16 x = 0; x < Width; ++x) + { + const f32 z = hm.get(x, y); + const f32 xx = (f32)x/(f32)Width; + const f32 yy = (f32)y/(f32)Height; + + S3DVertex& v = buf->Vertices[i++]; + v.Pos.set(x, Scale * z, y); + v.Normal.set(hm.getnormal(x, y, Scale)); + v.Color=cf(xx, yy, z); + v.TCoords.set(xx, yy); + } + } + + buf->Indices.set_used(6 * (Width - 1) * (y1 - y0)); + i=0; + for(u16 y = y0; y < y1; ++y) + { + for(u16 x = 0; x < Width - 1; ++x) + { + const u16 n = (y-y0) * Width + x; + buf->Indices[i]=n; + buf->Indices[++i]=n + Width; + buf->Indices[++i]=n + Width + 1; + buf->Indices[++i]=n + Width + 1; + buf->Indices[++i]=n + 1; + buf->Indices[++i]=n; + ++i; + } + } + + buf->recalculateBoundingBox(); + } +}; + +/* +Our event receiver implementation, taken from tutorial 4. +*/ +class MyEventReceiver : public IEventReceiver +{ +public: + // This is the one method that we have to implement + virtual bool OnEvent(const SEvent& event) + { + // Remember whether each key is down or up + if (event.EventType == irr::EET_KEY_INPUT_EVENT) + KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown; + + return false; + } + + // This is used to check whether a key is being held down + virtual bool IsKeyDown(EKEY_CODE keyCode) const + { + return KeyIsDown[keyCode]; + } + + MyEventReceiver() + { + for (u32 i=0; igetVideoDriver(); + ISceneManager *smgr = device->getSceneManager(); + device->setWindowCaption(L"Irrlicht Example for SMesh usage."); + + /* + Create the custom mesh and initialize with a heightmap + */ + TMesh mesh; + HeightMap hm = HeightMap(255, 255); + hm.generate(eggbox); + mesh.init(hm, 50.f, grey, driver); + + // Add the mesh to the scene graph + IMeshSceneNode* meshnode = smgr -> addMeshSceneNode(mesh.Mesh); + meshnode->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false); + + // light is just for nice effects + ILightSceneNode *node = smgr->addLightSceneNode(0, vector3df(0,100,0), + SColorf(1.0f, 0.6f, 0.7f, 1.0f), 500.0f); + if (node) + { + node->getLightData().Attenuation.set(0.f, 1.f/500.f, 0.f); + ISceneNodeAnimator* anim = smgr->createFlyCircleAnimator(vector3df(0,150,0),250.0f); + if (anim) + { + node->addAnimator(anim); + anim->drop(); + } + } + + ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(); + if (camera) + { + camera->setPosition(vector3df(-20.f, 150.f, -20.f)); + camera->setTarget(vector3df(200.f, -80.f, 150.f)); + camera->setFarValue(20000.0f); + } + + /* + Just a usual render loop with event handling. The custom mesh is + a usual part of the scene graph which gets rendered by drawAll. + */ + while(device->run()) + { + if(!device->isWindowActive()) + { + device->sleep(100); + continue; + } + + if(receiver.IsKeyDown(irr::KEY_KEY_W)) + { + meshnode->setMaterialFlag(video::EMF_WIREFRAME, !meshnode->getMaterial(0).Wireframe); + } + else if(receiver.IsKeyDown(irr::KEY_KEY_1)) + { + hm.generate(eggbox); + mesh.init(hm, 50.f, grey, driver); + } + else if(receiver.IsKeyDown(irr::KEY_KEY_2)) + { + hm.generate(moresine); + mesh.init(hm, 50.f, yellow, driver); + } + else if(receiver.IsKeyDown(irr::KEY_KEY_3)) + { + hm.generate(justexp); + mesh.init(hm, 50.f, yellow, driver); + } + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, SColor(0xff000000)); + smgr->drawAll(); + driver->endScene(); + } + + device->drop(); + + return 0; +} + +/* +That's it! Just compile and play around with the program. +**/ diff --git a/examples/24.CursorControl/CursorControl.cbp b/examples/24.CursorControl/CursorControl.cbp new file mode 100644 index 00000000..b8aa231f --- /dev/null +++ b/examples/24.CursorControl/CursorControl.cbp @@ -0,0 +1,57 @@ + + + + + + diff --git a/examples/24.CursorControl/CursorControl.vcproj b/examples/24.CursorControl/CursorControl.vcproj new file mode 100644 index 00000000..1bc2f531 --- /dev/null +++ b/examples/24.CursorControl/CursorControl.vcproj @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/24.CursorControl/CursorControl.xcodeproj/project.pbxproj b/examples/24.CursorControl/CursorControl.xcodeproj/project.pbxproj new file mode 100644 index 00000000..2000a263 --- /dev/null +++ b/examples/24.CursorControl/CursorControl.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 24.CursorControl.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 24.CursorControl.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 24.CursorControl.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 24.CursorControl */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "24.CursorControl" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 24.CursorControl; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 24.CursorControl.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "CursorControl" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 24.CursorControl */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "CursorControl" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "24.CursorControl" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/24.CursorControl/CursorControl.xcodeproj/xcshareddata/xcschemes/24.CursorControl.xcscheme b/examples/24.CursorControl/CursorControl.xcodeproj/xcshareddata/xcschemes/24.CursorControl.xcscheme new file mode 100644 index 00000000..2bf741e7 --- /dev/null +++ b/examples/24.CursorControl/CursorControl.xcodeproj/xcshareddata/xcschemes/24.CursorControl.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/24.CursorControl/CursorControl_vc10.vcxproj b/examples/24.CursorControl/CursorControl_vc10.vcxproj new file mode 100644 index 00000000..913c520a --- /dev/null +++ b/examples/24.CursorControl/CursorControl_vc10.vcxproj @@ -0,0 +1,187 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 24.CursorControl + {02B67A37-50E1-49DB-BECF-905BC029C2FE} + 24.CursorControl + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\24.CursorControl.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\24.CursorControl.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)CursorControl.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\24.CursorControl.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\24.CursorControl.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/24.CursorControl/CursorControl_vc11.vcxproj b/examples/24.CursorControl/CursorControl_vc11.vcxproj new file mode 100644 index 00000000..7eadc6f1 --- /dev/null +++ b/examples/24.CursorControl/CursorControl_vc11.vcxproj @@ -0,0 +1,188 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 24.CursorControl + {02B67A37-50E1-49DB-BECF-905BC029C2FE} + 24.CursorControl + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\24.CursorControl.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)CursorControl.pdb + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\24.CursorControl.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)CursorControl.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\24.CursorControl.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\24.CursorControl.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/24.CursorControl/CursorControl_vc12.vcxproj b/examples/24.CursorControl/CursorControl_vc12.vcxproj new file mode 100644 index 00000000..26fdf871 --- /dev/null +++ b/examples/24.CursorControl/CursorControl_vc12.vcxproj @@ -0,0 +1,188 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 24.CursorControl + {02B67A37-50E1-49DB-BECF-905BC029C2FE} + 24.CursorControl + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\24.CursorControl.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)CursorControl.pdb + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\24.CursorControl.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)CursorControl.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\24.CursorControl.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\24.CursorControl.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/24.CursorControl/CursorControl_vc14.vcxproj b/examples/24.CursorControl/CursorControl_vc14.vcxproj new file mode 100644 index 00000000..40a0a88e --- /dev/null +++ b/examples/24.CursorControl/CursorControl_vc14.vcxproj @@ -0,0 +1,188 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 24.CursorControl + {02B67A37-50E1-49DB-BECF-905BC029C2FE} + 24.CursorControl + Win32Proj + + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\24.CursorControl.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)CursorControl.pdb + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\24.CursorControl.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)CursorControl.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\24.CursorControl.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\24.CursorControl.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/24.CursorControl/Makefile b/examples/24.CursorControl/Makefile new file mode 100644 index 00000000..f30f3701 --- /dev/null +++ b/examples/24.CursorControl/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 24.CursorControl +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/24.CursorControl/main.cpp b/examples/24.CursorControl/main.cpp new file mode 100644 index 00000000..22c22cb7 --- /dev/null +++ b/examples/24.CursorControl/main.cpp @@ -0,0 +1,566 @@ +/** Example 024 CursorControl + +Show how to modify cursors and offer some useful tool-functions for creating cursors. +It can also be used for experiments with the mouse in general. +*/ + +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +const int DELAY_TIME = 3000; + +enum ETimerAction +{ + ETA_MOUSE_VISIBLE, + ETA_MOUSE_INVISIBLE, +}; + +/* + Structure to allow delayed execution of some actions. +*/ +struct TimerAction +{ + u32 TargetTime; + ETimerAction Action; +}; + +/* +*/ +struct SAppContext +{ + SAppContext() + : Device(0), InfoStatic(0), EventBox(0), CursorBox(0), SpriteBox(0) + , ButtonSetVisible(0), ButtonSetInvisible(0), ButtonSimulateBadFps(0) + , ButtonChangeIcon(0) + , SimulateBadFps(false) + { + } + + void update() + { + if (!Device) + return; + u32 timeNow = Device->getTimer()->getTime(); + for ( u32 i=0; i < TimerActions.size(); ++i ) + { + if ( timeNow >= TimerActions[i].TargetTime ) + { + runTimerAction(TimerActions[i]); + TimerActions.erase(i); + } + else + { + ++i; + } + } + } + + void runTimerAction(const TimerAction& action) + { + if (ETA_MOUSE_VISIBLE == action.Action) + { + Device->getCursorControl()->setVisible(true); + ButtonSetVisible->setEnabled(true); + } + else if ( ETA_MOUSE_INVISIBLE == action.Action) + { + Device->getCursorControl()->setVisible(false); + ButtonSetInvisible->setEnabled(true); + } + } + + /* + Add another icon which the user can click and select as cursor later on. + */ + void addIcon(const stringw& name, const SCursorSprite &sprite, bool addCursor=true) + { + // Sprites are just icons - not yet cursors. They can be displayed by Irrlicht sprite functions and be used to create cursors. + SpriteBox->addItem(name.c_str(), sprite.SpriteId); + Sprites.push_back(sprite); + + // create the cursor together with the icon? + if ( addCursor ) + { + /* Here we create a hardware cursor from a sprite */ + Device->getCursorControl()->addIcon(sprite); + + // ... and add it to the cursors selection listbox to the other system cursors. + CursorBox->addItem(name.c_str()); + } + } + + IrrlichtDevice * Device; + gui::IGUIStaticText * InfoStatic; + gui::IGUIListBox * EventBox; + gui::IGUIListBox * CursorBox; + gui::IGUIListBox * SpriteBox; + gui::IGUIButton * ButtonSetVisible; + gui::IGUIButton * ButtonSetInvisible; + gui::IGUIButton * ButtonSimulateBadFps; + gui::IGUIButton * ButtonChangeIcon; + array TimerActions; + bool SimulateBadFps; + array Sprites; +}; + +/* + Helper function to print mouse event names into a stringw +*/ +void PrintMouseEventName(const SEvent& event, stringw &result) +{ + switch ( event.MouseInput.Event ) + { + case EMIE_LMOUSE_PRESSED_DOWN: result += stringw(L"EMIE_LMOUSE_PRESSED_DOWN"); break; + case EMIE_RMOUSE_PRESSED_DOWN: result += stringw(L"EMIE_RMOUSE_PRESSED_DOWN"); break; + case EMIE_MMOUSE_PRESSED_DOWN: result += stringw(L"EMIE_MMOUSE_PRESSED_DOWN"); break; + case EMIE_LMOUSE_LEFT_UP: result += stringw(L"EMIE_LMOUSE_LEFT_UP"); break; + case EMIE_RMOUSE_LEFT_UP: result += stringw(L"EMIE_RMOUSE_LEFT_UP"); break; + case EMIE_MMOUSE_LEFT_UP: result += stringw(L"EMIE_MMOUSE_LEFT_UP"); break; + case EMIE_MOUSE_MOVED: result += stringw(L"EMIE_MOUSE_MOVED"); break; + case EMIE_MOUSE_WHEEL: result += stringw(L"EMIE_MOUSE_WHEEL"); break; + case EMIE_LMOUSE_DOUBLE_CLICK: result += stringw(L"EMIE_LMOUSE_DOUBLE_CLICK"); break; + case EMIE_RMOUSE_DOUBLE_CLICK: result += stringw(L"EMIE_RMOUSE_DOUBLE_CLICK"); break; + case EMIE_MMOUSE_DOUBLE_CLICK: result += stringw(L"EMIE_MMOUSE_DOUBLE_CLICK"); break; + case EMIE_LMOUSE_TRIPLE_CLICK: result += stringw(L"EMIE_LMOUSE_TRIPLE_CLICK"); break; + case EMIE_RMOUSE_TRIPLE_CLICK: result += stringw(L"EMIE_RMOUSE_TRIPLE_CLICK"); break; + case EMIE_MMOUSE_TRIPLE_CLICK: result += stringw(L"EMIE_MMOUSE_TRIPLE_CLICK"); break; + default: + break; + } +} + +/* + Helper function to print all the state information which get from a mouse-event into a stringw +*/ +void PrintMouseState(const SEvent& event, stringw &result) +{ + result += stringw(L"X: "); + result += stringw(event.MouseInput.X); + result += stringw(L"\n"); + + result += stringw(L"Y: "); + result += stringw(event.MouseInput.Y); + result += stringw(L"\n"); + + + result += stringw(L"Wheel: "); + result += stringw(event.MouseInput.Wheel); + result += stringw(L"\n"); + + result += stringw(L"Shift: "); + if ( event.MouseInput.Shift ) + result += stringw(L"true\n"); + else + result += stringw(L"false\n"); + + result += stringw(L"Control: "); + if ( event.MouseInput.Control ) + result += stringw(L"true\n"); + else + result += stringw(L"false\n"); + + result += stringw(L"ButtonStates: "); + result += stringw(event.MouseInput.ButtonStates); + result += stringw(L"\n"); + + result += stringw(L"isLeftPressed: "); + if ( event.MouseInput.isLeftPressed() ) + result += stringw(L"true\n"); + else + result += stringw(L"false\n"); + + result += stringw(L"isRightPressed: "); + if ( event.MouseInput.isRightPressed() ) + result += stringw(L"true\n"); + else + result += stringw(L"false\n"); + + result += stringw(L"isMiddlePressed: "); + if ( event.MouseInput.isMiddlePressed() ) + result += stringw(L"true\n"); + else + result += stringw(L"false\n"); + + result += stringw(L"Event: "); + + PrintMouseEventName(event, result); + + result += stringw(L"\n"); +} + +/* + A typical event receiver. +*/ +class MyEventReceiver : public IEventReceiver +{ +public: + MyEventReceiver(SAppContext & context) : Context(context) { } + + virtual bool OnEvent(const SEvent& event) + { + if (event.EventType == EET_GUI_EVENT ) + { + switch ( event.GUIEvent.EventType ) + { + case EGET_BUTTON_CLICKED: + { + u32 timeNow = Context.Device->getTimer()->getTime(); + TimerAction action; + action.TargetTime = timeNow + DELAY_TIME; + if ( event.GUIEvent.Caller == Context.ButtonSetVisible ) + { + action.Action = ETA_MOUSE_VISIBLE; + Context.TimerActions.push_back(action); + Context.ButtonSetVisible->setEnabled(false); + } + else if ( event.GUIEvent.Caller == Context.ButtonSetInvisible ) + { + action.Action = ETA_MOUSE_INVISIBLE; + Context.TimerActions.push_back(action); + Context.ButtonSetInvisible->setEnabled(false); + } + else if ( event.GUIEvent.Caller == Context.ButtonSimulateBadFps ) + { + Context.SimulateBadFps = Context.ButtonSimulateBadFps->isPressed(); + } + else if ( event.GUIEvent.Caller == Context.ButtonChangeIcon ) + { + /* + Replace an existing cursor icon by another icon. + The user has to select both - the icon which should be replaced and the icon which will replace it. + */ + s32 selectedCursor = Context.CursorBox->getSelected(); + s32 selectedSprite = Context.SpriteBox->getSelected(); + if ( selectedCursor >= 0 && selectedSprite >= 0 ) + { + /* + This does replace the icon. + */ + Context.Device->getCursorControl()->changeIcon((ECURSOR_ICON)selectedCursor, Context.Sprites[selectedSprite] ); + + /* + Do also show the new icon. + */ + Context.Device->getCursorControl()->setActiveIcon( ECURSOR_ICON(selectedCursor) ); + } + } + } + break; + case EGET_LISTBOX_CHANGED: + case EGET_LISTBOX_SELECTED_AGAIN: + { + if ( event.GUIEvent.Caller == Context.CursorBox ) + { + /* + Find out which cursor the user selected + */ + s32 selected = Context.CursorBox->getSelected(); + if ( selected >= 0 ) + { + /* + Here we set the new cursor icon which will now be used within our window. + */ + Context.Device->getCursorControl()->setActiveIcon( ECURSOR_ICON(selected) ); + } + } + } + break; + default: + break; + } + } + + if (event.EventType == EET_MOUSE_INPUT_EVENT) + { + stringw infoText; + PrintMouseState(event, infoText); + Context.InfoStatic->setText(infoText.c_str()); + if ( event.MouseInput.Event != EMIE_MOUSE_MOVED && event.MouseInput.Event != EMIE_MOUSE_WHEEL ) // no spam + { + infoText = L""; + PrintMouseEventName(event, infoText); + Context.EventBox->insertItem(0, infoText.c_str(), -1); + } + } + + return false; + } + +private: + SAppContext & Context; +}; + +/* + Use several imagefiles as animation frames for a sprite which can be used as cursor icon. + The images in those files all need to have the same size. + Return sprite index on success or -1 on failure +*/ +s32 AddAnimatedIconToSpriteBank( gui::IGUISpriteBank * spriteBank, video::IVideoDriver* driver, const array< io::path >& files, u32 frameTime ) +{ + if ( !spriteBank || !driver || !files.size() ) + return -1; + + video::ITexture * tex = driver->getTexture( files[0] ); + if ( tex ) + { + array< rect >& spritePositions = spriteBank->getPositions(); + u32 idxRect = spritePositions.size(); + spritePositions.push_back( rect(0,0, tex->getSize().Width, tex->getSize().Height) ); + + SGUISprite sprite; + sprite.frameTime = frameTime; + + array< SGUISprite >& sprites = spriteBank->getSprites(); + u32 startIdx = spriteBank->getTextureCount(); + for ( u32 f=0; f < files.size(); ++f ) + { + tex = driver->getTexture( files[f] ); + if ( tex ) + { + spriteBank->addTexture( driver->getTexture(files[f]) ); + gui::SGUISpriteFrame frame; + frame.rectNumber = idxRect; + frame.textureNumber = startIdx+f; + sprite.Frames.push_back( frame ); + } + } + + sprites.push_back( sprite ); + return sprites.size()-1; + } + + return -1; +} + +/* + Use several images within one imagefile as animation frames for a sprite which can be used as cursor icon + The sizes of the icons within that file all need to have the same size + Return sprite index on success or -1 on failure +*/ +s32 AddAnimatedIconToSpriteBank( gui::IGUISpriteBank * spriteBank, video::IVideoDriver* driver, const io::path& file, const array< rect >& rects, u32 frameTime ) +{ + if ( !spriteBank || !driver || !rects.size() ) + return -1; + + video::ITexture * tex = driver->getTexture( file ); + if ( tex ) + { + array< rect >& spritePositions = spriteBank->getPositions(); + u32 idxRect = spritePositions.size(); + u32 idxTex = spriteBank->getTextureCount(); + spriteBank->addTexture( tex ); + + SGUISprite sprite; + sprite.frameTime = frameTime; + + array< SGUISprite >& sprites = spriteBank->getSprites(); + for ( u32 i=0; i < rects.size(); ++i ) + { + spritePositions.push_back( rects[i] ); + + gui::SGUISpriteFrame frame; + frame.rectNumber = idxRect+i; + frame.textureNumber = idxTex; + sprite.Frames.push_back( frame ); + } + + sprites.push_back( sprite ); + return sprites.size()-1; + } + + return -1; +} + +/* + Create a non-animated icon from the given file and position and put it into the spritebank. + We can use this icon later on in a cursor. +*/ +s32 AddIconToSpriteBank( gui::IGUISpriteBank * spriteBank, video::IVideoDriver* driver, const io::path& file, const core::rect& rect ) +{ + if ( !spriteBank || !driver ) + return -1; + + video::ITexture * tex = driver->getTexture( file ); + if ( tex ) + { + core::array< core::rect >& spritePositions = spriteBank->getPositions(); + spritePositions.push_back( rect ); + array< SGUISprite >& sprites = spriteBank->getSprites(); + spriteBank->addTexture( tex ); + + gui::SGUISpriteFrame frame; + frame.rectNumber = spritePositions.size()-1; + frame.textureNumber = spriteBank->getTextureCount()-1; + + SGUISprite sprite; + sprite.frameTime = 0; + sprite.Frames.push_back( frame ); + + sprites.push_back( sprite ); + + return sprites.size()-1; + } + + return -1; +} + +int main() +{ + video::E_DRIVER_TYPE driverType = driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + IrrlichtDevice * device = createDevice(driverType, dimension2d(640, 480)); + if (device == 0) + return 1; // could not create selected driver. + + // It's sometimes of interest to know how the mouse behaves after a resize + device->setResizable(true); + + device->setWindowCaption(L"Cursor control - Irrlicht engine tutorial"); + video::IVideoDriver* driver = device->getVideoDriver(); + IGUIEnvironment* env = device->getGUIEnvironment(); + + gui::IGUISpriteBank * SpriteBankIcons; + + SAppContext context; + context.Device = device; + + rect< s32 > rectInfoStatic(10,10, 200, 200); + env->addStaticText (L"Cursor state information", rectInfoStatic, true, true); + rectInfoStatic.UpperLeftCorner += dimension2di(0, 15); + context.InfoStatic = env->addStaticText (L"", rectInfoStatic, true, true); + rect< s32 > rectEventBox(10,210, 200, 400); + env->addStaticText (L"click events (new on top)", rectEventBox, true, true); + rectEventBox.UpperLeftCorner += dimension2di(0, 15); + context.EventBox = env->addListBox(rectEventBox); + rect< s32 > rectCursorBox(210,10, 400, 250); + env->addStaticText (L"cursors, click to set the active one", rectCursorBox, true, true); + rectCursorBox.UpperLeftCorner += dimension2di(0, 15); + context.CursorBox = env->addListBox(rectCursorBox); + rect< s32 > rectSpriteBox(210,260, 400, 400); + env->addStaticText (L"sprites", rectSpriteBox, true, true); + rectSpriteBox.UpperLeftCorner += dimension2di(0, 15); + context.SpriteBox = env->addListBox(rectSpriteBox); + + context.ButtonSetVisible = env->addButton( rect( 410, 20, 560, 40 ), 0, -1, L"set visible (delayed)" ); + context.ButtonSetInvisible = env->addButton( rect( 410, 50, 560, 70 ), 0, -1, L"set invisible (delayed)" ); + context.ButtonSimulateBadFps = env->addButton( rect( 410, 80, 560, 100 ), 0, -1, L"simulate bad FPS" ); + context.ButtonSimulateBadFps->setIsPushButton(true); + context.ButtonChangeIcon = env->addButton( rect( 410, 140, 560, 160 ), 0, -1, L"replace cursor icon\n(cursor+sprite must be selected)" ); + + // set the names for all the system cursors + for ( int i=0; i < (int)gui::ECI_COUNT; ++i ) + { + context.CursorBox->addItem(stringw( GUICursorIconNames[i] ).c_str()); + } + + /* + Create sprites which then can be used as cursor icons. + */ + SpriteBankIcons = env->addEmptySpriteBank(io::path("cursor_icons")); + context.SpriteBox->setSpriteBank(SpriteBankIcons); + + const io::path mediaPath = getExampleMediaPath(); + + // create one animated icon from several files + array< io::path > files; + files.push_back( io::path(mediaPath + "icon_crosshairs16x16bw1.png") ); + files.push_back( io::path(mediaPath + "icon_crosshairs16x16bw2.png") ); + files.push_back( io::path(mediaPath + "icon_crosshairs16x16bw3.png") ); + files.push_back( io::path(mediaPath + "icon_crosshairs16x16bw3.png") ); + files.push_back( io::path(mediaPath + "icon_crosshairs16x16bw2.png") ); + SCursorSprite spriteBw; // the sprite + some additional information needed for cursors + spriteBw.SpriteId = AddAnimatedIconToSpriteBank( SpriteBankIcons, driver, files, 200 ); + spriteBw.SpriteBank = SpriteBankIcons; + spriteBw.HotSpot = position2d(7,7); + context.addIcon(L"crosshair_bw", spriteBw); + + // create one animated icon from one file + array< rect > iconRects; + iconRects.push_back( rect(0,0, 16, 16) ); + iconRects.push_back( rect(16,0, 32, 16) ); + iconRects.push_back( rect(0,16, 16, 32) ); + iconRects.push_back( rect(0,16, 16, 32) ); + iconRects.push_back( rect(16,0, 32, 16) ); + SCursorSprite spriteCol; // the sprite + some additional information needed for cursors + spriteCol.SpriteId = AddAnimatedIconToSpriteBank( SpriteBankIcons, driver, io::path(mediaPath + "icon_crosshairs16x16col.png"), iconRects, 200 ); + spriteCol.HotSpot = position2d(7,7); + spriteCol.SpriteBank = SpriteBankIcons; + context.addIcon(L"crosshair_colored", spriteCol); + + // Create some non-animated icons + rect rectIcon; + SCursorSprite spriteNonAnimated(SpriteBankIcons, 0, position2d(7,7)); + + rectIcon = rect(0,0, 16, 16); + spriteNonAnimated.SpriteId = AddIconToSpriteBank( SpriteBankIcons, driver, io::path(mediaPath + "icon_crosshairs16x16col.png"), rectIcon ); + context.addIcon(L"crosshair_col1", spriteNonAnimated, false); + + rectIcon = rect(16,0, 32, 16); + spriteNonAnimated.SpriteId = AddIconToSpriteBank( SpriteBankIcons, driver, io::path(mediaPath + "icon_crosshairs16x16col.png"), rectIcon ); + context.addIcon(L"crosshair_col2", spriteNonAnimated, false); + + rectIcon = rect(0,16, 16, 32); + spriteNonAnimated.SpriteId = AddIconToSpriteBank( SpriteBankIcons, driver, io::path(mediaPath + "icon_crosshairs16x16col.png"), rectIcon ); + context.addIcon(L"crosshair_col3", spriteNonAnimated, false); + + + MyEventReceiver receiver(context); + device->setEventReceiver(&receiver); + + while(device->run() && driver) + { + // if (device->isWindowActive()) + { + u32 realTimeNow = device->getTimer()->getRealTime(); + + context.update(); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, SColor(0,200,200,200)); + + env->drawAll(); + + // draw custom sprite with Irrlicht functions for comparison. It should usually look the same as the cursors. + if ( context.SpriteBox ) + { + s32 selectedSprite = context.SpriteBox->getSelected(); + if ( selectedSprite >= 0 && context.Sprites[selectedSprite].SpriteId >= 0 ) + { + SpriteBankIcons->draw2DSprite(u32(context.Sprites[selectedSprite].SpriteId), position2di(580, 140), 0, video::SColor(255, 255, 255, 255), 0, realTimeNow); + } + } + + driver->endScene(); + } + + // By simulating bad fps we can find out if hardware-support for cursors works or not. If it works the cursor will move as usual,while it otherwise will just update with 2 fps now. + if ( context.SimulateBadFps ) + { + device->sleep(500); // 2 fps + } + else + { + device->sleep(10); + } + } + + device->drop(); + + return 0; +} + +/* +**/ diff --git a/examples/25.XmlHandling/Makefile b/examples/25.XmlHandling/Makefile new file mode 100644 index 00000000..359b8f04 --- /dev/null +++ b/examples/25.XmlHandling/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 25.XmlHandling +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/25.XmlHandling/XmlHandling.cbp b/examples/25.XmlHandling/XmlHandling.cbp new file mode 100644 index 00000000..b9bc5c9f --- /dev/null +++ b/examples/25.XmlHandling/XmlHandling.cbp @@ -0,0 +1,55 @@ + + + + + + diff --git a/examples/25.XmlHandling/XmlHandling.vcproj b/examples/25.XmlHandling/XmlHandling.vcproj new file mode 100644 index 00000000..152a4158 --- /dev/null +++ b/examples/25.XmlHandling/XmlHandling.vcproj @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/25.XmlHandling/XmlHandling.xcodeproj/project.pbxproj b/examples/25.XmlHandling/XmlHandling.xcodeproj/project.pbxproj new file mode 100644 index 00000000..6a162330 --- /dev/null +++ b/examples/25.XmlHandling/XmlHandling.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 25.XmlHandling.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 25.XmlHandling.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 25.XmlHandling.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 25.XmlHandling */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "25.XmlHandling" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 25.XmlHandling; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 25.XmlHandling.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "XmlHandling" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 25.XmlHandling */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "XmlHandling" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "25.XmlHandling" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/25.XmlHandling/XmlHandling.xcodeproj/xcshareddata/xcschemes/25.XmlHandling.xcscheme b/examples/25.XmlHandling/XmlHandling.xcodeproj/xcshareddata/xcschemes/25.XmlHandling.xcscheme new file mode 100644 index 00000000..2d21c8eb --- /dev/null +++ b/examples/25.XmlHandling/XmlHandling.xcodeproj/xcshareddata/xcschemes/25.XmlHandling.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/25.XmlHandling/XmlHandling_vc10.vcxproj b/examples/25.XmlHandling/XmlHandling_vc10.vcxproj new file mode 100644 index 00000000..43f9e73f --- /dev/null +++ b/examples/25.XmlHandling/XmlHandling_vc10.vcxproj @@ -0,0 +1,182 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 25.XmlHandling + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E} + 25.XmlHandling + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + false + + + Level3 + + + Cdecl + + + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + false + + + Level3 + + + Cdecl + + + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/25.XmlHandling/XmlHandling_vc11.vcxproj b/examples/25.XmlHandling/XmlHandling_vc11.vcxproj new file mode 100644 index 00000000..43f9e73f --- /dev/null +++ b/examples/25.XmlHandling/XmlHandling_vc11.vcxproj @@ -0,0 +1,182 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 25.XmlHandling + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E} + 25.XmlHandling + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + false + + + Level3 + + + Cdecl + + + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + false + + + Level3 + + + Cdecl + + + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/25.XmlHandling/XmlHandling_vc12.vcxproj b/examples/25.XmlHandling/XmlHandling_vc12.vcxproj new file mode 100644 index 00000000..53546373 --- /dev/null +++ b/examples/25.XmlHandling/XmlHandling_vc12.vcxproj @@ -0,0 +1,182 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 25.XmlHandling + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E} + 25.XmlHandling + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + false + + + Level3 + + + Cdecl + + + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + false + + + Level3 + + + Cdecl + + + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/25.XmlHandling/XmlHandling_vc14.vcxproj b/examples/25.XmlHandling/XmlHandling_vc14.vcxproj new file mode 100644 index 00000000..4fdb56a3 --- /dev/null +++ b/examples/25.XmlHandling/XmlHandling_vc14.vcxproj @@ -0,0 +1,182 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 25.XmlHandling + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E} + 25.XmlHandling + Win32Proj + + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + false + + + Level3 + + + Cdecl + + + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + false + + + Level3 + + + Cdecl + + + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/25.XmlHandling/main.cpp b/examples/25.XmlHandling/main.cpp new file mode 100644 index 00000000..657ad8dc --- /dev/null +++ b/examples/25.XmlHandling/main.cpp @@ -0,0 +1,506 @@ +/** Example 025 Xml Handling + +Demonstrates loading and saving of configurations via XML + +@author Y.M. Bosman \ + +This demo features a fully usable system for configuration handling. The code +can easily be integrated into own apps. + +*/ + +#include +#include "exampleHelper.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + + +/* SettingManager class. + +This class loads and writes the settings and manages the options. + +The class makes use of irrMap which is a an associative arrays using a +red-black tree it allows easy mapping of a key to a value, along the way there +is some information on how to use it. +*/ + +class SettingManager +{ +public: + + // Construct setting managers and set default settings + SettingManager(const stringw& settings_file): SettingsFile(settings_file), NullDevice(0) + { + // Irrlicht null device, we want to load settings before we actually created our device, therefore, nulldevice + NullDevice = irr::createDevice(irr::video::EDT_NULL); + + //DriverOptions is an irrlicht map, + //we can insert values in the map in two ways by calling insert(key,value) or by using the [key] operator + //the [] operator overrides values if they already exist + DriverOptions.insert(L"Software", EDT_SOFTWARE); + DriverOptions.insert(L"OpenGL", EDT_OPENGL); + DriverOptions.insert(L"Direct3D9", EDT_DIRECT3D9); + + //some resolution options + ResolutionOptions.insert(L"640x480", dimension2du(640,480)); + ResolutionOptions.insert(L"800x600", dimension2du(800,600)); + ResolutionOptions.insert(L"1024x768", dimension2du(1024,768)); + + //our preferred defaults + SettingMap.insert(L"driver", L"Direct3D9"); + SettingMap.insert(L"resolution", L"640x480"); + SettingMap.insert(L"fullscreen", L"0"); //0 is false + } + + // Destructor, you could store settings automatically on exit of your + // application if you wanted to in our case we simply drop the + // nulldevice + ~SettingManager() + { + if (NullDevice) + { + NullDevice->closeDevice(); + NullDevice->drop(); + } + }; + + /* + Load xml from disk, overwrite default settings + The xml we are trying to load has the following structure + settings nested in sections nested in the root node, like so +
+		
+		
+			
+		
+	
+ */ + bool load() + { + //if not able to create device don't attempt to load + if (!NullDevice) + return false; + + irr::io::IXMLReader* xml = NullDevice->getFileSystem()->createXMLReader(SettingsFile); //create xml reader + if (!xml) + return false; + + const stringw settingTag(L"setting"); //we'll be looking for this tag in the xml + stringw currentSection; //keep track of our current section + const stringw videoTag(L"video"); //constant for videotag + + //while there is more to read + while (xml->read()) + { + //check the node type + switch (xml->getNodeType()) + { + //we found a new element + case irr::io::EXN_ELEMENT: + { + //we currently are in the empty or mygame section and find the video tag so we set our current section to video + if (currentSection.empty() && videoTag.equals_ignore_case(xml->getNodeName())) + { + currentSection = videoTag; + } + //we are in the video section and we find a setting to parse + else if (currentSection.equals_ignore_case(videoTag) && settingTag.equals_ignore_case(xml->getNodeName() )) + { + //read in the key + stringw key = xml->getAttributeValueSafe(L"name"); + //if there actually is a key to set + if (!key.empty()) + { + //set the setting in the map to the value, + //the [] operator overrides values if they already exist or inserts a new key value + //pair into the settings map if it was not defined yet + SettingMap[key] = xml->getAttributeValueSafe(L"value"); + } + } + + //.. + // You can add your own sections and tags to read in here + //.. + } + break; + + //we found the end of an element + case irr::io::EXN_ELEMENT_END: + //we were at the end of the video section so we reset our tag + currentSection=L""; + break; + } + } + + // don't forget to delete the xml reader + xml->drop(); + + return true; + } + + // Save the xml to disk. We use the nulldevice. + bool save() + { + + //if not able to create device don't attempt to save + if (!NullDevice) + return false; + + //create xml writer + irr::io::IXMLWriter* xwriter = NullDevice->getFileSystem()->createXMLWriter( SettingsFile ); + if (!xwriter) + return false; + + //write out the obligatory xml header. Each xml-file needs to have exactly one of those. + xwriter->writeXMLHeader(); + + //start element mygame, you replace the label "mygame" with anything you want + xwriter->writeElement(L"mygame"); + xwriter->writeLineBreak(); //new line + + //start section with video settings + xwriter->writeElement(L"video"); + xwriter->writeLineBreak(); //new line + + // getIterator gets us a pointer to the first node of the settings map + // every iteration we increase the iterator which gives us the next map node + // until we reach the end we write settings one by one by using the nodes key and value functions + map::Iterator i = SettingMap.getIterator(); + for(; !i.atEnd(); i++) + { + //write element as + //the second parameter indicates this is an empty element with no children, just attributes + xwriter->writeElement(L"setting",true, L"name", i->getKey().c_str(), L"value",i->getValue().c_str() ); + xwriter->writeLineBreak(); + } + xwriter->writeLineBreak(); + + //close video section + xwriter->writeClosingTag(L"video"); + xwriter->writeLineBreak(); + + //.. + // You can add writing sound settings, savegame information etc + //.. + + //close mygame section + xwriter->writeClosingTag(L"mygame"); + + //delete xml writer + xwriter->drop(); + + return true; + } + + // Set setting in our manager + void setSetting(const stringw& name, const stringw& value) + { + SettingMap[name]=value; + } + + // set setting overload to quickly assign integers to our setting map + void setSetting(const stringw& name, s32 value) + { + SettingMap[name]=stringw(value); + } + + // Get setting as string + stringw getSetting(const stringw& key) const + { + //the find function or irrmap returns a pointer to a map Node + //if the key can be found, otherwise it returns null + //the map node has the function getValue and getKey, as we already know the key, we return node->getValue() + map::Node* n = SettingMap.find(key); + if (n) + return n->getValue(); + else + return L""; + } + + // + bool getSettingAsBoolean(const stringw& key ) const + { + stringw s = getSetting(key); + if (s.empty()) + return false; + return s.equals_ignore_case(L"1"); + } + + // + s32 getSettingAsInteger(const stringw& key) const + { + //we implicitly cast to string instead of stringw because strtol10 does not accept wide strings + const stringc s = getSetting(key); + if (s.empty()) + return 0; + + return strtol10(s.c_str()); + } + +public: + map DriverOptions; //available options for driver config + map ResolutionOptions; //available options for resolution config +private: + SettingManager(const SettingManager& other); // defined but not implemented + SettingManager& operator=(const SettingManager& other); // defined but not implemented + + map SettingMap; //current config + + stringw SettingsFile; // location of the xml, usually the + irr::IrrlichtDevice* NullDevice; +}; + +/* +Application context for global variables +*/ +struct SAppContext +{ + SAppContext() + : Device(0),Gui(0), Driver(0), Settings(0), ShouldQuit(false), + ButtonSave(0), ButtonExit(0), ListboxDriver(0), + ListboxResolution(0), CheckboxFullscreen(0) + { + } + + ~SAppContext() + { + if (Settings) + delete Settings; + + if (Device) + { + Device->closeDevice(); + Device->drop(); + } + } + + IrrlichtDevice* Device; + IGUIEnvironment* Gui; + IVideoDriver* Driver; + SettingManager* Settings; + bool ShouldQuit; + + //settings dialog + IGUIButton* ButtonSave; + IGUIButton* ButtonExit; + IGUIListBox* ListboxDriver; + IGUIListBox* ListboxResolution; + IGUICheckBox* CheckboxFullscreen; +}; + +/* + A typical event receiver. +*/ +class MyEventReceiver : public IEventReceiver +{ +public: + MyEventReceiver(SAppContext & a) : App(a) { } + + virtual bool OnEvent(const SEvent& event) + { + if (event.EventType == EET_GUI_EVENT ) + { + switch ( event.GUIEvent.EventType ) + { + //handle button click events + case EGET_BUTTON_CLICKED: + { + //Our save button was called so we obtain the settings from our dialog and save them + if ( event.GUIEvent.Caller == App.ButtonSave ) + { + //if there is a selection write it + if ( App.ListboxDriver->getSelected() != -1) + App.Settings->setSetting(L"driver", App.ListboxDriver->getListItem(App.ListboxDriver->getSelected())); + + //if there is a selection write it + if ( App.ListboxResolution->getSelected() != -1) + App.Settings->setSetting(L"resolution", App.ListboxResolution->getListItem(App.ListboxResolution->getSelected())); + + App.Settings->setSetting(L"fullscreen", App.CheckboxFullscreen->isChecked()); + + + if (App.Settings->save()) + { + App.Gui->addMessageBox(L"settings save",L"settings saved, please restart for settings to change effect","",true); + } + } + // cancel/exit button clicked, tell the application to exit + else if ( event.GUIEvent.Caller == App.ButtonExit) + { + App.ShouldQuit = true; + } + } + break; + } + } + + return false; + } + +private: + SAppContext & App; +}; + + +/* +Function to create a video settings dialog +This dialog shows the current settings from the configuration xml and allows them to be changed +*/ +void createSettingsDialog(SAppContext& app) +{ + // first get rid of alpha in gui + for (irr::s32 i=0; igetSkin()->getColor((irr::gui::EGUI_DEFAULT_COLOR)i); + col.setAlpha(255); + app.Gui->getSkin()->setColor((irr::gui::EGUI_DEFAULT_COLOR)i, col); + } + + //create video settings windows + gui::IGUIWindow* windowSettings = app.Gui->addWindow(rect(10,10,400,400),true,L"Videosettings"); + app.Gui->addStaticText (L"Select your desired video settings", rect< s32 >(10,20, 200, 40), false, true, windowSettings); + + // add listbox for driver choice + app.Gui->addStaticText (L"Driver", rect< s32 >(10,50, 200, 60), false, true, windowSettings); + app.ListboxDriver = app.Gui->addListBox(rect(10,60,220,120), windowSettings, 1,true); + + //add all available options to the driver choice listbox + map::Iterator i = app.Settings->DriverOptions.getIterator(); + for(; !i.atEnd(); i++) + app.ListboxDriver->addItem(i->getKey().c_str()); + + //set currently selected driver + app.ListboxDriver->setSelected(app.Settings->getSetting("driver").c_str()); + + // add listbox for resolution choice + app.Gui->addStaticText (L"Resolution", rect< s32 >(10,130, 200, 140), false, true, windowSettings); + app.ListboxResolution = app.Gui->addListBox(rect(10,140,220,200), windowSettings, 1,true); + + //add all available options to the resolution listbox + map::Iterator ri = app.Settings->ResolutionOptions.getIterator(); + for(; !ri.atEnd(); ri++) + app.ListboxResolution->addItem(ri->getKey().c_str()); + + //set currently selected resolution + app.ListboxResolution->setSelected(app.Settings->getSetting("resolution").c_str()); + + //add checkbox to toggle fullscreen, initially set to loaded setting + app.CheckboxFullscreen = app.Gui->addCheckBox( + app.Settings->getSettingAsBoolean("fullscreen"), + rect(10,220,220,240), windowSettings, -1, + L"Fullscreen"); + + //last but not least add save button + app.ButtonSave = app.Gui->addButton( + rect(80,250,150,270), windowSettings, 2, + L"Save video settings"); + + //exit/cancel button + app.ButtonExit = app.Gui->addButton( + rect(160,250,240,270), windowSettings, 2, + L"Cancel and exit"); +} + +/* +The main function. Creates all objects and does the XML handling. +*/ +int main() +{ + //create new application context + SAppContext app; + + //create device creation parameters that can get overwritten by our settings file + SIrrlichtCreationParameters param; + param.DriverType = EDT_SOFTWARE; + param.WindowSize.set(640,480); + + // Try to load config. + // I leave it as an exercise of the reader to store the configuration in the local application data folder, + // the only logical place to store config data for games. For all other operating systems I redirect to your manuals + app.Settings = new SettingManager(getExampleMediaPath() + "settings.xml"); + if ( !app.Settings->load() ) + { + // ... + // Here add your own exception handling, for now we continue because there are defaults set in SettingManager constructor + // ... + } + else + { + //settings xml loaded from disk, + + //map driversetting to driver type and test if the setting is valid + //the DriverOptions map contains string representations mapped to to irrlicht E_DRIVER_TYPE enum + //e.g "direct3d9" will become 4 + //see DriverOptions in the settingmanager class for details + map::Node* driver = app.Settings->DriverOptions.find( app.Settings->getSetting("driver") ); + + if (driver) + { + if ( irr::IrrlichtDevice::isDriverSupported( static_cast( driver->getValue() ))) + { + // selected driver is supported, so we use it. + param.DriverType = static_cast( driver->getValue()); + } + } + + //map resolution setting to dimension in a similar way as demonstrated above + map::Node* res = app.Settings->ResolutionOptions.find( app.Settings->getSetting("resolution") ); + if (res) + { + param.WindowSize = res->getValue(); + } + + //get fullscreen setting from config + param.Fullscreen = app.Settings->getSettingAsBoolean("fullscreen"); + } + + //create the irrlicht device using the settings + app.Device = createDeviceEx(param); + if (app.Device == 0) + { + // You can add your own exception handling on driver failure + exit(0); + } + + app.Device->setWindowCaption(L"Xmlhandling - Irrlicht engine tutorial"); + app.Driver = app.Device->getVideoDriver(); + app.Gui = app.Device->getGUIEnvironment(); + + createSettingsDialog(app); + + //set event receiver so we can respond to gui events + MyEventReceiver receiver(app); + app.Device->setEventReceiver(&receiver); + + //enter main loop + while (!app.ShouldQuit && app.Device->run()) + { + if (app.Device->isWindowActive()) + { + app.Driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, SColor(0,200,200,200)); + app.Gui->drawAll(); + app.Driver->endScene(); + } + app.Device->sleep(10); + } + + //app destroys device in destructor + + return 0; +} + +/* +**/ diff --git a/examples/26.OcclusionQuery/Makefile b/examples/26.OcclusionQuery/Makefile new file mode 100644 index 00000000..b01efd30 --- /dev/null +++ b/examples/26.OcclusionQuery/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 26.OcclusionQuery +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/26.OcclusionQuery/OcclusionQuery.cbp b/examples/26.OcclusionQuery/OcclusionQuery.cbp new file mode 100644 index 00000000..09587e5d --- /dev/null +++ b/examples/26.OcclusionQuery/OcclusionQuery.cbp @@ -0,0 +1,55 @@ + + + + + + diff --git a/examples/26.OcclusionQuery/OcclusionQuery.vcproj b/examples/26.OcclusionQuery/OcclusionQuery.vcproj new file mode 100644 index 00000000..602f2d3d --- /dev/null +++ b/examples/26.OcclusionQuery/OcclusionQuery.vcproj @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/26.OcclusionQuery/OcclusionQuery.xcodeproj/project.pbxproj b/examples/26.OcclusionQuery/OcclusionQuery.xcodeproj/project.pbxproj new file mode 100644 index 00000000..26ea259a --- /dev/null +++ b/examples/26.OcclusionQuery/OcclusionQuery.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 26.OcclusionQuery.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 26.OcclusionQuery.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 26.OcclusionQuery.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 26.OcclusionQuery */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "26.OcclusionQuery" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 26.OcclusionQuery; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 26.OcclusionQuery.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "OcclusionQuery" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 26.OcclusionQuery */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "OcclusionQuery" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "26.OcclusionQuery" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/26.OcclusionQuery/OcclusionQuery.xcodeproj/xcshareddata/xcschemes/26.OcclusionQuery.xcscheme b/examples/26.OcclusionQuery/OcclusionQuery.xcodeproj/xcshareddata/xcschemes/26.OcclusionQuery.xcscheme new file mode 100644 index 00000000..3004daa8 --- /dev/null +++ b/examples/26.OcclusionQuery/OcclusionQuery.xcodeproj/xcshareddata/xcschemes/26.OcclusionQuery.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/26.OcclusionQuery/OcclusionQuery_vc10.vcxproj b/examples/26.OcclusionQuery/OcclusionQuery_vc10.vcxproj new file mode 100644 index 00000000..370d3683 --- /dev/null +++ b/examples/26.OcclusionQuery/OcclusionQuery_vc10.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 26.OcclusionQuery + {5CE0E2E7-879D-4152-B61D-24E7D0707B45} + OcclusionQuery + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug\OcclusionQuery.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\26.OcclusionQuery.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug\OcclusionQuery.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\26.OcclusionQuery.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release\OcclusionQuery.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\26.OcclusionQuery.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release\OcclusionQuery.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\26.OcclusionQuery.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/26.OcclusionQuery/OcclusionQuery_vc11.vcxproj b/examples/26.OcclusionQuery/OcclusionQuery_vc11.vcxproj new file mode 100644 index 00000000..370d3683 --- /dev/null +++ b/examples/26.OcclusionQuery/OcclusionQuery_vc11.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 26.OcclusionQuery + {5CE0E2E7-879D-4152-B61D-24E7D0707B45} + OcclusionQuery + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug\OcclusionQuery.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\26.OcclusionQuery.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug\OcclusionQuery.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\26.OcclusionQuery.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release\OcclusionQuery.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\26.OcclusionQuery.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release\OcclusionQuery.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\26.OcclusionQuery.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/26.OcclusionQuery/OcclusionQuery_vc12.vcxproj b/examples/26.OcclusionQuery/OcclusionQuery_vc12.vcxproj new file mode 100644 index 00000000..e181a45f --- /dev/null +++ b/examples/26.OcclusionQuery/OcclusionQuery_vc12.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 26.OcclusionQuery + {5CE0E2E7-879D-4152-B61D-24E7D0707B45} + OcclusionQuery + + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + Application + false + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug\OcclusionQuery.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\26.OcclusionQuery.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug\OcclusionQuery.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\26.OcclusionQuery.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release\OcclusionQuery.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\26.OcclusionQuery.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release\OcclusionQuery.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\26.OcclusionQuery.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/26.OcclusionQuery/OcclusionQuery_vc14.vcxproj b/examples/26.OcclusionQuery/OcclusionQuery_vc14.vcxproj new file mode 100644 index 00000000..d52b6d59 --- /dev/null +++ b/examples/26.OcclusionQuery/OcclusionQuery_vc14.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 26.OcclusionQuery + {5CE0E2E7-879D-4152-B61D-24E7D0707B45} + OcclusionQuery + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug\OcclusionQuery.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\26.OcclusionQuery.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug\OcclusionQuery.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\26.OcclusionQuery.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release\OcclusionQuery.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\26.OcclusionQuery.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release\OcclusionQuery.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\26.OcclusionQuery.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/26.OcclusionQuery/main.cpp b/examples/26.OcclusionQuery/main.cpp new file mode 100644 index 00000000..6aea63cb --- /dev/null +++ b/examples/26.OcclusionQuery/main.cpp @@ -0,0 +1,216 @@ +/** Example 026 OcclusionQuery + +This tutorial shows how to speed up rendering by use of the +OcclusionQuery feature. The usual rendering tries to avoid rendering of +scene nodes by culling those nodes which are outside the visible area, the +view frustum. However, this technique does not cope with occluded objects +which are still in the line of sight, but occluded by some larger object +between the object and the eye (camera). Occlusion queries check exactly that. +The queries basically measure the number of pixels that a previous render +left on the screen. +Since those pixels cannot be recognized at the end of a rendering anymore, +the pixel count is measured directly when rendering. Thus, one needs to render +the occluder (the object in front) first. This object needs to write to the +z-buffer in order to become a real occluder. Then the node is rendered and in +case a z-pass happens, i.e. the pixel is written to the framebuffer, the pixel +is counted in the query. +The result of a query is the number of pixels which got through. One can, based +on this number, judge if the scene node is visible enough to be rendered, or if +the node should be removed in the next round. Also note that the number of +pixels is a safe over approximation in general. The pixels might be overdrawn +later on, and the GPU tries to avoid inaccuracies which could lead to false +negatives in the queries. + +As you might have recognized already, we had to render the node to get the +numbers. So where's the benefit, you might say. There are several ways where +occlusion queries can help. It is often a good idea to just render the bbox +of the node instead of the actual mesh. This is really fast and is a safe over +approximation. If you need a more exact render with the actual geometry, it's +a good idea to render with just basic solid material. Avoid complex shaders +and state changes through textures. There's no need while just doing the +occlusion query. At least if the render is not used for the actual scene. This +is the third way to optimize occlusion queries. Just check the queries every +5th or 10th frame, or even less frequent. This depends on the movement speed +of the objects and camera. +*/ + +#ifdef _MSC_VER +// We'll also define this to stop MSVC complaining about sprintf(). +#define _CRT_SECURE_NO_WARNINGS +#pragma comment(lib, "Irrlicht.lib") +#endif + +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +using namespace irr; + +/* +We need keyboard input events to switch some parameters +*/ +class MyEventReceiver : public IEventReceiver +{ +public: + // This is the one method that we have to implement + virtual bool OnEvent(const SEvent& event) + { + // Remember whether each key is down or up + if (event.EventType == irr::EET_KEY_INPUT_EVENT) + KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown; + + return false; + } + + // This is used to check whether a key is being held down + virtual bool IsKeyDown(EKEY_CODE keyCode) const + { + return KeyIsDown[keyCode]; + } + + MyEventReceiver() + { + for (u32 i=0; i(640, 480), 16, false, false, false, &receiver); + + if (device == 0) + return 1; // could not create selected driver. + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + + const io::path mediaPath = getExampleMediaPath(); + + smgr->getGUIEnvironment()->addStaticText(L"Press Space to hide occluder.", core::recti(10,10, 200,50)); + + /* + Create the node to be occluded. We create a sphere node with high poly count. + */ + scene::ISceneNode * node = smgr->addSphereSceneNode(10, 64); + if (node) + { + node->setPosition(core::vector3df(0,0,60)); + node->setMaterialTexture(0, driver->getTexture(mediaPath + "wall.bmp")); + node->setMaterialFlag(video::EMF_LIGHTING, false); + } + + /* + Now we create another node, the occluder. It's a simple plane. + */ + scene::ISceneNode* plane = smgr->addMeshSceneNode(smgr->addHillPlaneMesh( + "plane", core::dimension2df(10,10), core::dimension2du(2,2)), 0, -1, + core::vector3df(0,0,20), core::vector3df(270,0,0)); + + if (plane) + { + plane->setMaterialTexture(0, driver->getTexture(mediaPath + "t351sml.jpg")); + plane->setMaterialFlag(video::EMF_LIGHTING, false); + plane->setMaterialFlag(video::EMF_BACK_FACE_CULLING, true); + } + + /* + Here we create the occlusion query. Because we don't have a plain mesh scene node + (ESNT_MESH or ESNT_ANIMATED_MESH), we pass the base geometry as well. Instead, + we could also pass a simpler mesh or the bounding box. But we will use a time + based method, where the occlusion query renders to the frame buffer and in case + of success (occlusion), the mesh is not drawn for several frames. + */ + driver->addOcclusionQuery(node, ((scene::IMeshSceneNode*)node)->getMesh()); + + /* + We have done everything, just a camera and draw it. We also write the + current frames per second and the name of the driver to the caption of the + window to examine the render speedup. + We also store the time for measuring the time since the last occlusion query ran + and store whether the node should be visible in the next frames. + */ + smgr->addCameraSceneNode(); + int lastFPS = -1; + u32 timeNow = device->getTimer()->getTime(); + bool nodeVisible=true; + + while(device->run()) + { + plane->setVisible(!receiver.IsKeyDown(irr::KEY_SPACE)); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,113,113,133)); + /* + First, we draw the scene, possibly without the occluded element. This is necessary + because we need the occluder to be drawn first. You can also use several scene + managers to collect a number of possible occluders in a separately rendered + scene. + */ + node->setVisible(nodeVisible); + smgr->drawAll(); + smgr->getGUIEnvironment()->drawAll(); + + /* + Once in a while, here every 100 ms, we check the visibility. We run the queries, + update the pixel value, and query the result. Since we already rendered the node + we render the query invisible. The update is made blocking, as we need the result + immediately. If you don't need the result immediately, e.g. because you have other + things to render, you can call the update non-blocking. This gives the GPU more + time to pass back the results without flushing the render pipeline. + If the update was called non-blocking, the result from getOcclusionQueryResult is + either the previous value, or 0xffffffff if no value has been generated at all, yet. + The result is taken immediately as visibility flag for the node. + */ + if (device->getTimer()->getTime()-timeNow>100) + { + driver->runAllOcclusionQueries(false); + driver->updateAllOcclusionQueries(); + nodeVisible=driver->getOcclusionQueryResult(node)>0; + timeNow=device->getTimer()->getTime(); + } + + driver->endScene(); + + int fps = driver->getFPS(); + + if (lastFPS != fps) + { + core::stringw tmp(L"OcclusionQuery Example ["); + tmp += driver->getName(); + tmp += L"] fps: "; + tmp += fps; + + device->setWindowCaption(tmp.c_str()); + lastFPS = fps; + } + } + + /* + In the end, delete the Irrlicht device. + */ + device->drop(); + + return 0; +} + +/* +That's it. Compile and play around with the program. +**/ diff --git a/examples/27.PostProcessing/Makefile b/examples/27.PostProcessing/Makefile new file mode 100644 index 00000000..c5905005 --- /dev/null +++ b/examples/27.PostProcessing/Makefile @@ -0,0 +1,38 @@ +# 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 = 27.PostProcessing +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 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32: LDFLAGS = -L../../lib/Win32-gcc -lIrrlicht -lopengl32 -lm +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/27.PostProcessing/PostProcessing.cbp b/examples/27.PostProcessing/PostProcessing.cbp new file mode 100644 index 00000000..8c7f68e6 --- /dev/null +++ b/examples/27.PostProcessing/PostProcessing.cbp @@ -0,0 +1,56 @@ + + + + + + diff --git a/examples/27.PostProcessing/PostProcessing_vc10.vcxproj b/examples/27.PostProcessing/PostProcessing_vc10.vcxproj new file mode 100644 index 00000000..65e47f37 --- /dev/null +++ b/examples/27.PostProcessing/PostProcessing_vc10.vcxproj @@ -0,0 +1,231 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 27.PostProcessing + {2B885150-210F-4CA7-957E-2C3D75974308} + PostProcessing + + + + Application + false + MultiByte + + + Application + false + MultiByte + + + Application + false + MultiByte + + + Application + false + MultiByte + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/PostProcessing.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/PostProcessing.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/PostProcessing.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/PostProcessing.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/27.PostProcessing/PostProcessing_vc11.vcxproj b/examples/27.PostProcessing/PostProcessing_vc11.vcxproj new file mode 100644 index 00000000..8a732900 --- /dev/null +++ b/examples/27.PostProcessing/PostProcessing_vc11.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 27.PostProcessing + {F864F96D-F6AE-43E2-9A12-218B1A081255} + PostProcessing + + + + Application + false + MultiByte + v110 + + + Application + false + MultiByte + v110 + + + Application + false + MultiByte + v110 + + + Application + false + MultiByte + v110 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/PostProcessing.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/PostProcessing.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/PostProcessing.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/PostProcessing.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/27.PostProcessing/PostProcessing_vc12.vcxproj b/examples/27.PostProcessing/PostProcessing_vc12.vcxproj new file mode 100644 index 00000000..8aef23bd --- /dev/null +++ b/examples/27.PostProcessing/PostProcessing_vc12.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 27.PostProcessing + {17E74625-568E-4008-897E-CAD12A332B0C} + PostProcessing + + + + Application + false + MultiByte + v110 + + + Application + false + MultiByte + v110 + + + Application + false + MultiByte + v110 + + + Application + false + MultiByte + v110 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/PostProcessing.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/PostProcessing.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/PostProcessing.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/PostProcessing.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/27.PostProcessing/PostProcessing_vc14.vcxproj b/examples/27.PostProcessing/PostProcessing_vc14.vcxproj new file mode 100644 index 00000000..a39c5551 --- /dev/null +++ b/examples/27.PostProcessing/PostProcessing_vc14.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 27.PostProcessing + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2} + PostProcessing + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/PostProcessing.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/PostProcessing.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/PostProcessing.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/PostProcessing.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/27.PostProcessing/main.cpp b/examples/27.PostProcessing/main.cpp new file mode 100644 index 00000000..2f49ccfc --- /dev/null +++ b/examples/27.PostProcessing/main.cpp @@ -0,0 +1,417 @@ +/** Example 027 Post Processing + +This tutorial shows how to implement post processing for D3D9 and OpenGL with +the engine. In order to do post processing, scene objects are firstly rendered +to render target. With the help of screen quad, the render target texture +is then drawn on the quad with shader-defined effects applied. + +This tutorial shows how to create a screen quad. It also shows how to create a +render target texture and associate it with the quad. Effects are defined as +shaders which are applied during rendering the quad with the render target +texture attached to it. + +A simple color inverse example is presented in this tutorial. The effect is +written in HLSL and GLSL. + +@author Boshen Guan + +We include all headers and define necessary variables as we have done before. +*/ +#include "driverChoice.h" +#include "exampleHelper.h" + +#include + +using namespace irr; + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +/* +We write a class derived from IShaderConstantSetCallBack class and implement +OnSetConstants callback interface. In this callback, we will set constants +used by the shader. +In this example, our HLSL shader needs texture size as input in its vertex +shader. Therefore, we set texture size in OnSetConstants callback using +setVertexShaderConstant function. +*/ + +IrrlichtDevice* device = 0; +video::ITexture* rt = 0; + +class QuadShaderCallBack : public video::IShaderConstantSetCallBack +{ +public: + QuadShaderCallBack() : FirstUpdate(true), TextureSizeID(-1), TextureSamplerID(-1) + { } + + virtual void OnSetConstants(video::IMaterialRendererServices* services, + s32 userData) + { + core::dimension2d size = rt->getSize(); + + // get texture size array + f32 textureSize[] = + { + (f32)size.Width, (f32)size.Height + }; + + if ( FirstUpdate ) + { + TextureSizeID = services->getVertexShaderConstantID("TextureSize"); + TextureSamplerID = services->getPixelShaderConstantID("TextureSampler"); + } + + // set texture size to vertex shader + services->setVertexShaderConstant(TextureSizeID, reinterpret_cast(textureSize), 2); + + // set texture for an OpenGL driver + s32 textureLayer = 0; + services->setPixelShaderConstant(TextureSamplerID, &textureLayer, 1); + } + +private: + bool FirstUpdate; + s32 TextureSizeID; + s32 TextureSamplerID; +}; + +class ScreenQuad : public IReferenceCounted +{ +public: + + ScreenQuad(video::IVideoDriver* driver) + : Driver(driver) + { + // --------------------------------> u + // |[1](-1, 1)----------[2](1, 1) + // | | ( 0, 0) / | (1, 0) + // | | / | + // | | / | + // | | / | + // | | / | + // | | / | + // | | / | + // | | / | + // | | / | + // |[0](-1, -1)---------[3](1, -1) + // | ( 0, 1) (1, 1) + // V + // v + + /* + A screen quad is composed of two adjacent triangles with 4 vertices. + Vertex [0], [1] and [2] create the first triangle and Vertex [0], + [2] and [3] create the second one. To map texture on the quad, UV + coordinates are assigned to the vertices. The origin of UV coordinate + locates on the top-left corner. And the value of UVs range from 0 to 1. + */ + + // define vertices array + + Vertices[0] = irr::video::S3DVertex(-1.0f, -1.0f, 0.0f, 1, 1, 0, irr::video::SColor(0,255,255,255), 0.0f, 1.0f); + Vertices[1] = irr::video::S3DVertex(-1.0f, 1.0f, 0.0f, 1, 1, 0, irr::video::SColor(0,255,255,255), 0.0f, 0.0f); + Vertices[2] = irr::video::S3DVertex( 1.0f, 1.0f, 0.0f, 1, 1, 0, irr::video::SColor(0,255,255,255), 1.0f, 0.0f); + Vertices[3] = irr::video::S3DVertex( 1.0f, -1.0f, 0.0f, 1, 1, 0, irr::video::SColor(0,255,255,255), 1.0f, 1.0f); + + // define indices for triangles + + Indices[0] = 0; + Indices[1] = 1; + Indices[2] = 2; + Indices[3] = 0; + Indices[4] = 2; + Indices[5] = 3; + + // turn off lighting as default + Material.setFlag(video::EMF_LIGHTING, false); + + // set texture warp settings to clamp to edge pixel + for (u32 i = 0; i < video::MATERIAL_MAX_TEXTURES; i++) + { + Material.TextureLayer[i].TextureWrapU = video::ETC_CLAMP_TO_EDGE; + Material.TextureLayer[i].TextureWrapV = video::ETC_CLAMP_TO_EDGE; + } + } + + virtual ~ScreenQuad() {} + + + //! render the screen quad + virtual void render() + { + // set the material of screen quad + Driver->setMaterial(Material); + + // set matrices to fit the quad to full viewport + Driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); + Driver->setTransform(video::ETS_VIEW, core::IdentityMatrix); + Driver->setTransform(video::ETS_PROJECTION, core::IdentityMatrix); + + // draw screen quad + Driver->drawVertexPrimitiveList(Vertices, 4, Indices, 2); + } + + //! sets a flag of material to a new value + virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) + { + Material.setFlag(flag, newvalue); + } + + //! sets the texture of the specified layer in material to the new texture. + void setMaterialTexture(u32 textureLayer, video::ITexture* texture) + { + Material.setTexture(textureLayer, texture); + } + + //! sets the material type to a new material type. + virtual void setMaterialType(video::E_MATERIAL_TYPE newType) + { + Material.MaterialType = newType; + } + +private: + + video::IVideoDriver *Driver; + video::S3DVertex Vertices[4]; + u16 Indices[6]; + video::SMaterial Material; +}; + +/* +We start up the engine just like before. Then shader programs are selected +according to the driver type. +*/ +int main() +{ + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + // create device + device = createDevice(driverType, core::dimension2d(640, 480)); + + if (device == 0) + return 1; // could not create selected driver. + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + + /* + In this example, high level post processing shaders are loaded for both + Direct3D and OpenGL drivers. + File pp_d3d9.hlsl is for Direct3D 9, and pp_opengl.frag/pp_opengl.vert + are for OpenGL. + */ + + const io::path mediaPath = getExampleMediaPath(); + io::path vsFileName; // filename for the vertex shader + io::path psFileName; // filename for the pixel shader + + switch(driverType) + { + case video::EDT_DIRECT3D9: + psFileName = mediaPath + "pp_d3d9.hlsl"; + vsFileName = psFileName; // both shaders are in the same file + break; + + case video::EDT_OPENGL: + psFileName = mediaPath + "pp_opengl.frag"; + vsFileName = mediaPath + "pp_opengl.vert"; + break; + } + + /* + Check for hardware capability of executing the corresponding shaders + on selected renderer. This is not necessary though. + */ + + if (!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) && + !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)) + { + device->getLogger()->log("WARNING: Pixel shaders disabled "\ + "because of missing driver/hardware support."); + psFileName = ""; + } + + if (!driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) && + !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)) + { + device->getLogger()->log("WARNING: Vertex shaders disabled "\ + "because of missing driver/hardware support."); + vsFileName = ""; + } + + /* + An animated mesh is loaded to be displayed. As in most examples, + we'll take the fairy md2 model. + */ + + // load and display animated fairy mesh + + scene::IAnimatedMeshSceneNode* fairy = smgr->addAnimatedMeshSceneNode( + smgr->getMesh(mediaPath + "faerie.md2")); + + if (fairy) + { + fairy->setMaterialTexture(0, + driver->getTexture(mediaPath + "faerie2.bmp")); // set diffuse texture + fairy->setMaterialFlag(video::EMF_LIGHTING, false); // disable dynamic lighting + fairy->setPosition(core::vector3df(-10,0,-100)); + fairy->setMD2Animation ( scene::EMAT_STAND ); + } + + // add scene camera + smgr->addCameraSceneNode(0, core::vector3df(10,10,-80), + core::vector3df(-10,10,-100)); + + /* + We create a render target texture (RTT) with the same size as frame buffer. + Instead of rendering the scene directly to the frame buffer, we firstly + render it to this RTT. Post processing is then applied based on this RTT. + RTT size needs not to be the same with frame buffer though. However in this + example, we expect the result of rendering to RTT to be consistent with the + result of rendering directly to the frame buffer. Therefore, the size of + RTT keeps the same with frame buffer. + */ + + // create render target + + if (driver->queryFeature(video::EVDF_RENDER_TO_TARGET)) + { + rt = driver->addRenderTargetTexture(core::dimension2d(640, 480), "RTT1"); + } + else + { + device->getLogger()->log("Your hardware or this renderer is not able to use the "\ + "render to texture feature. RTT Disabled."); + } + + /* + Post processing is achieved by rendering a screen quad with this RTT (with + previously rendered result) as a texture on the quad. A screen quad is + geometry of flat plane composed of two adjacent triangles covering the + entire area of viewport. In this pass of rendering, RTT works just like + a normal texture and is drawn on the quad during rendering. We can then + take control of this rendering process by applying various shader-defined + materials to the quad. In other words, we can achieve different effect by + writing different shaders. + This process is called post processing because it normally does not rely + on scene geometry. The inputs of this process are just textures, or in + other words, just images. With the help of screen quad, we can draw these + images on the screen with different effects. For example, we can adjust + contrast, make grayscale, add noise, do more fancy effect such as blur, + bloom, ghost, or just like in this example, we invert the color to produce + negative image. + Note that post processing is not limited to use only one texture. It can + take multiple textures as shader inputs to provide desired result. In + addition, post processing can also be chained to produce compound result. + */ + + // we create a screen quad + ScreenQuad *screenQuad = new ScreenQuad(driver); + + // turn off mip maps and bilinear filter since we do not want interpolated result + screenQuad->setMaterialFlag(video::EMF_USE_MIP_MAPS, false); + screenQuad->setMaterialFlag(video::EMF_BILINEAR_FILTER, false); + + // set quad texture to RTT we just create + screenQuad->setMaterialTexture(0, rt); + + /* + Let's create material for the quad. Like in other example, we create material + using IGPUProgrammingServices and call addShaderMaterialFromFiles, which + returns a material type identifier. + */ + + // create materials + + video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices(); + s32 ppMaterialType = 0; + + if (gpu) + { + // We write a QuadShaderCallBack class that implements OnSetConstants + // callback of IShaderConstantSetCallBack class at the beginning of + // this tutorial. We set shader constants in this callback. + + // create an instance of callback class + + QuadShaderCallBack* mc = new QuadShaderCallBack(); + + // create material from post processing shaders + + ppMaterialType = gpu->addHighLevelShaderMaterialFromFiles( + vsFileName, "vertexMain", video::EVST_VS_1_1, + psFileName, "pixelMain", video::EPST_PS_1_1, mc); + + mc->drop(); + } + + // set post processing material type to the quad + screenQuad->setMaterialType((video::E_MATERIAL_TYPE)ppMaterialType); + + /* + Now draw everything. That's all. + */ + + int lastFPS = -1; + + while(device->run()) + { + if (device->isWindowActive()) + { + driver->beginScene(true, true, video::SColor(255,0,0,0)); + + if (rt) + { + // draw scene into render target + + // set render target to RTT + driver->setRenderTarget(rt, true, true, video::SColor(255,0,0,0)); + + // draw scene to RTT just like normal rendering + smgr->drawAll(); + + // after rendering to RTT, we change render target back + driver->setRenderTarget(0, true, true, video::SColor(255,0,0,0)); + + // render screen quad to apply post processing + screenQuad->render(); + } + else + { + // draw scene normally + smgr->drawAll(); + } + + driver->endScene(); + + int fps = driver->getFPS(); + + if (lastFPS != fps) + { + core::stringw str = L"Irrlicht Engine - Post processing example ["; + str += driver->getName(); + str += "] FPS:"; + str += fps; + + device->setWindowCaption(str.c_str()); + lastFPS = fps; + } + } + } + + // do not forget to manually drop the screen quad + + screenQuad->drop(); + + device->drop(); + + return 0; +} + +/* +**/ diff --git a/examples/28.CubeMapping/CubeMapping.cbp b/examples/28.CubeMapping/CubeMapping.cbp new file mode 100644 index 00000000..f8025e49 --- /dev/null +++ b/examples/28.CubeMapping/CubeMapping.cbp @@ -0,0 +1,56 @@ + + + + + + diff --git a/examples/28.CubeMapping/CubeMapping_vc10.vcxproj b/examples/28.CubeMapping/CubeMapping_vc10.vcxproj new file mode 100644 index 00000000..403cd970 --- /dev/null +++ b/examples/28.CubeMapping/CubeMapping_vc10.vcxproj @@ -0,0 +1,231 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 28.CubeMapping + {9A2CE404-75E2-4195-837D-BED5B0FF3FA7} + CubeMapping + + + + Application + false + MultiByte + + + Application + false + MultiByte + + + Application + false + MultiByte + + + Application + false + MultiByte + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/CubeMapping.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\28.CubeMapping.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/CubeMapping.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\28.CubeMapping.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/CubeMapping.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\28.CubeMapping.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/CubeMapping.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\28.CubeMapping.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/28.CubeMapping/CubeMapping_vc11.vcxproj b/examples/28.CubeMapping/CubeMapping_vc11.vcxproj new file mode 100644 index 00000000..bd8bbb92 --- /dev/null +++ b/examples/28.CubeMapping/CubeMapping_vc11.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 28.CubeMapping + {3DAD16DC-3D80-46EA-ADD8-C4418CEDE553} + CubeMapping + + + + Application + false + MultiByte + v110 + + + Application + false + MultiByte + v110 + + + Application + false + MultiByte + v110 + + + Application + false + MultiByte + v110 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/CubeMapping.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\28.CubeMapping.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/CubeMapping.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\28.CubeMapping.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/CubeMapping.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\28.CubeMapping.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/CubeMapping.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\28.CubeMapping.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/28.CubeMapping/CubeMapping_vc12.vcxproj b/examples/28.CubeMapping/CubeMapping_vc12.vcxproj new file mode 100644 index 00000000..1c7f9201 --- /dev/null +++ b/examples/28.CubeMapping/CubeMapping_vc12.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 28.CubeMapping + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5} + CubeMapping + + + + Application + false + MultiByte + v110 + + + Application + false + MultiByte + v110 + + + Application + false + MultiByte + v110 + + + Application + false + MultiByte + v110 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/CubeMapping.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\28.CubeMapping.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/CubeMapping.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\28.CubeMapping.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/CubeMapping.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\28.CubeMapping.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/CubeMapping.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\28.CubeMapping.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/28.CubeMapping/CubeMapping_vc14.vcxproj b/examples/28.CubeMapping/CubeMapping_vc14.vcxproj new file mode 100644 index 00000000..55e11efc --- /dev/null +++ b/examples/28.CubeMapping/CubeMapping_vc14.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 28.CubeMapping + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A} + CubeMapping + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/CubeMapping.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\28.CubeMapping.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/CubeMapping.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\28.CubeMapping.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/CubeMapping.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\28.CubeMapping.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/CubeMapping.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\28.CubeMapping.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/28.CubeMapping/Makefile b/examples/28.CubeMapping/Makefile new file mode 100644 index 00000000..22514c2c --- /dev/null +++ b/examples/28.CubeMapping/Makefile @@ -0,0 +1,38 @@ +# 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 = 28.CubeMapping +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 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32: LDFLAGS = -L../../lib/Win32-gcc -lIrrlicht -lopengl32 -lm +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/28.CubeMapping/main.cpp b/examples/28.CubeMapping/main.cpp new file mode 100644 index 00000000..b831d318 --- /dev/null +++ b/examples/28.CubeMapping/main.cpp @@ -0,0 +1,770 @@ +/** Example 028 CubeMapping + +Shows usage of cubemap textures and how to do some simple environment mapping. +Cubemap textures have images for all 6 directions of a cube in a single texture. +Environment is used to reflect the environment around an object onto the object. +Cubemaps only work with shader materials which are written to support cube mapping. + +@author Michael Zeilfelder, based on EnvCubeMap example from irrSpintz engine. + +Start with the usual includes. +*/ + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +using namespace irr; + + +/* + A callback class for our cubemap shader. + We need a shader material which maps the cubemap texture to + the polygon vertices of objects. +*/ +class CubeMapReflectionCallback : public video::IShaderConstantSetCallBack +{ +public: + CubeMapReflectionCallback(scene::ISceneManager* smgr, int styleUVW) + : SceneMgr(smgr) + , StyleUVW(styleUVW), Roughness(0.f) + , styleUvwID(-1) , worldViewProjID(-1), worldID(-1), cameraPosID(-1) + {} + + /* + Setting the style to map vertex UV-coordinates to the cubemap textures. + - Specular style is typically used for mirrors and highlight reflections. + - Diffuse style is commonly used in image based lighting calculations and + often in combination with a higher roughness. Think of it as the sum of all + light which reaches a point on your object. + - Using model vertices directly for UV's is just nice for testing sometimes. + Maybe has more uses? Experiment around :-) + */ + void SetStyleUVW(int style) + { + StyleUVW = style; + } + + int GetStyleUVW() const + { + return StyleUVW; + } + + /* + We could also call this sharpness as the rougher a material the less + sharp the reflections of a cubemap are (light for rough materials + spreads out more while smooth materials reflect it more like a mirror). + Roughness is calculated using the mipmaps of the cubemap texture. + Note that rendertarget cubemap textures won't have mipmaps, so unfortunately + it won't work for those. + Also currently only OpenGL is able to interpolate seamless over cubemap borders. + On Direct3D9 you will only smooth per side, but not over side-borders. + */ + void SetRoughness(float roughness) + { + Roughness = roughness; + } + + float getRoughness() const + { + return Roughness; + } + + /* + Typical code which passes a few values from c++ to shader. + */ + virtual void OnSetMaterial(const video::SMaterial& material) + {} + + virtual void OnSetConstants(video::IMaterialRendererServices* services, s32 userData) + { + video::IVideoDriver* driver = services->getVideoDriver(); + + if ( worldViewProjID < 0 ) // first update + { + styleUvwID = services->getVertexShaderConstantID("StyleUVW"); + if( driver->getDriverType() == video::EDT_DIRECT3D9 ) + { + worldViewProjID = services->getVertexShaderConstantID("WorldViewProj"); + } + worldID = services->getVertexShaderConstantID("World"); + cameraPosID = services->getVertexShaderConstantID("CameraPos"); + roughnessID = services->getPixelShaderConstantID("Roughness"); + } + + services->setVertexShaderConstant(styleUvwID, &StyleUVW, 1 ); + + irr::core::matrix4 world = driver->getTransform(irr::video::ETS_WORLD); + services->setVertexShaderConstant(worldID, world.pointer(), 16); + + if( driver->getDriverType() == video::EDT_DIRECT3D9 ) + { + irr::core::matrix4 worldViewProj; + worldViewProj = driver->getTransform(irr::video::ETS_PROJECTION); + worldViewProj *= driver->getTransform(irr::video::ETS_VIEW); + worldViewProj *= world; + services->setVertexShaderConstant(worldViewProjID, worldViewProj.pointer(), 16); + } + + core::vector3df cameraPos = SceneMgr->getActiveCamera()->getAbsolutePosition(); + services->setVertexShaderConstant(cameraPosID, &cameraPos.X, 3 ); + services->setPixelShaderConstant(roughnessID, &Roughness, 1 ); + } + +private: + scene::ISceneManager* SceneMgr; + + int StyleUVW; // 0 = specular, 1=diffuse, 2 = use model vertex coordinates for uvw. + float Roughness; // cubemap 0 = specular ... highest value depends on number of mipmaps in the texture + + irr::s32 styleUvwID; + irr::s32 worldViewProjID; + irr::s32 worldID; + irr::s32 cameraPosID; + irr::s32 roughnessID; +}; + +/* + To keep the example compact our event-receiver acts also like a main + application class. So it handles user input, updates the dynamic parts of + the UI and it keeps some 3d nodes around. +*/ +class MyEventReceiver : public IEventReceiver +{ +public: + MyEventReceiver() : Driver(0), Shader(0) + ,BackgroundSkybox(0), BackgroundCube(0) + , CubemapUpdates(2) + , CurrentStyleUVW(0), CurrentRoughness(0) + , NeedCubemapUpdate(true) + { + StyleNamesUVW.push_back( L"specular" ); + StyleNamesUVW.push_back( L"diffuse" ); + StyleNamesUVW.push_back( L"model coordinates" ); + } + + // Handle the key input + virtual bool OnEvent(const SEvent& event) + { + if (event.EventType == EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown == false) + { + switch(event.KeyInput.Key ) + { + case KEY_SPACE: + // Switch between different texture mapping styles + if ( Shader ) + { + Shader->SetStyleUVW((Shader->GetStyleUVW()+1)%StyleNamesUVW.size()); + updateStyleUVW(); + } + break; + case KEY_KEY_B: + // Switch between our 2 different backgrounds + if ( BackgroundSkybox && BackgroundCube ) + { + if ( BackgroundSkybox->isVisible() ) + { + BackgroundSkybox->setVisible(false); + BackgroundCube->setVisible(true); + } + else + { + BackgroundSkybox->setVisible(true); + BackgroundCube->setVisible(false); + } + NeedCubemapUpdate = true; + } + break; + case KEY_KEY_I: + // Show/hide the info text nodes + for (u32 i=0; isetVisible(!InfoTextNodes[i]->isVisible()); + break; + case KEY_KEY_S: + // Enable/disable seamless smoothing of mipmaps over cube borders + if ( Driver ) + { + Driver->disableFeature(video::EVDF_TEXTURE_CUBEMAP_SEAMLESS, Driver->queryFeature(video::EVDF_TEXTURE_CUBEMAP_SEAMLESS) ); + updateSeamless(); + } + break; + case KEY_KEY_U: + // Switch dynamic cubemap updates on/off. + CubemapUpdates = (CubemapUpdates+1) % 3; + updateCubemapUpdates(); + break; + case KEY_PLUS: + case KEY_ADD: + // Make material rougher + if ( Shader ) + { + Shader->SetRoughness( Shader->getRoughness() + 0.5f ); + updateRoughness(); + } + break; + case KEY_MINUS: + case KEY_SUBTRACT: + { + // Make material smoother + if ( Shader ) + { + float roughness = Shader->getRoughness() - 0.5f; + if ( roughness >= 0.f ) + { + Shader->SetRoughness(roughness); + updateRoughness(); + } + } + break; + } + default: + break; + } + } + + return false; + } + + // Some helper functions to update the UI + void updateStyleUVW() + { + if ( CurrentStyleUVW && Shader) + CurrentStyleUVW->setText(StyleNamesUVW[Shader->GetStyleUVW()].c_str()); + } + + void updateRoughness() + { + if ( CurrentRoughness && Shader ) + { + CurrentRoughness->setText( irr::core::stringw(Shader->getRoughness()).c_str() ); + } + } + + void updateSeamless() + { + if ( CurrentSeamlessCubemap && Driver ) + { + CurrentSeamlessCubemap->setText( Driver->queryFeature(video::EVDF_TEXTURE_CUBEMAP_SEAMLESS) ? L"ON" : L"OFF" ); + } + } + + void updateCubemapUpdates() + { + if ( CurrentCubemapUpdates ) + { + switch ( CubemapUpdates ) + { + case 0: CurrentCubemapUpdates->setText( L"static"); break; + case 1: CurrentCubemapUpdates->setText( L"dynamic" ); break; + case 2: CurrentCubemapUpdates->setText( L"dynamic+mips" ); break; + } + } + } + + // Check if the cubemap textures should be updated with new screenshots + // return 0 for no update, 1 for update, 2 for update and fix mip-maps + int checkCubemapUpdate() + { + if ( NeedCubemapUpdate || CubemapUpdates == 2) + { + NeedCubemapUpdate = false; + return 2; + } + + return CubemapUpdates; + } + + // Add some text-node floating above it's parent node. + void addInfoTextNode(irr::gui::IGUIFont* font, const wchar_t* text, irr::scene::ISceneNode* parent) + { + if ( parent ) + { + const video::SColor infoTextCol(250, 70, 90, 90); + core::dimension2du dim(font->getDimension(text)); + core::dimension2df dimf((f32)dim.Width, (f32)dim.Height); + scene::IBillboardTextSceneNode* infoNode = parent->getSceneManager()->addBillboardTextSceneNode( font, text, parent, dimf, core::vector3df(0, 120, 0), -1, infoTextCol, infoTextCol); + InfoTextNodes.push_back(infoNode); + } + } + + irr::video::IVideoDriver* Driver; + CubeMapReflectionCallback* Shader; + + scene::ISceneNode* BackgroundSkybox; + scene::ISceneNode* BackgroundCube; + irr::core::array InfoTextNodes; + + int CubemapUpdates; // 0 = static, 1 = dynamic, 2 = dynamic with rtt + + irr::core::array StyleNamesUVW; + + irr::gui::IGUIStaticText* CurrentStyleUVW; + irr::gui::IGUIStaticText* CurrentRoughness; + irr::gui::IGUIStaticText* CurrentSeamlessCubemap; + irr::gui::IGUIStaticText* CurrentCubemapUpdates; + +private: + bool NeedCubemapUpdate; +}; + +/* Workaround for OpenGL's upside-down images. + Texture origins (0,0) in OpenGL are usually at the left-bottom instead of the more common left-top image formats. + Irrlicht internally uses textures with left-top origin and then corrects the texture-matrices in the fixed-function pipeline. + For shader materials it's left to the users to handle those UV-flips for the texture-matrix. + Render target textures (RTT's) in OpenGL are rendered with left-bottom origin and Irrlicht can't change that, so all RTT textures + in memory are upside-down (unlike all other Irrlicht textures). + In the fixed function pipeline Irrlicht handles this by flipping the RTT's texture matrix once more and for shaders it's again + left to the users to handle it. + Cubemap textures are different from other textures in OpenGL. Each cube side has left-top as the origin. So not flipping Irrlicht textures for those would be fine. + Except - OpenGL RTT's still render left-bottom - even when the target is a cubemap RTT. + I found no good way around this so far - it just seems messed up as we get a left-handed/right handed coordinate system change that way. + + So... the following 2 defines are two different workarounds I found. Both are ugly, which one is better in reality depends probably on the scene. + Only use one of those: + CUBEMAP_UPSIDE_DOWN_GL_PROJECTION is relatively fast as it just changes the project matrix. The problem is that changing the projection matrix + means changing front/backside culling. So every node rendered has to flip the material flags for those. + + CUBEMAP_USPIDE_DOWN_RTT will change the texture memory itself and flip the image upside-down. + While easier to do, this involves texture-locking and is very slow. +*/ +#define CUBEMAP_UPSIDE_DOWN_GL_PROJECTION +//#define CUBEMAP_USPIDE_DOWN_RTT + + +// Flip frontface/backface culling for all nodes +#ifdef CUBEMAP_UPSIDE_DOWN_GL_PROJECTION +void flipCullingFlags(const core::array& nodes) +{ + for ( irr::u32 n=0; n < nodes.size(); ++n ) + { + scene::ISceneNode* node = nodes[n]; + const irr::u32 matCount = node->getMaterialCount(); + for ( irr::u32 m=0; m < matCount; ++m) + { + video::SMaterial& mat = node->getMaterial(m); + mat.BackfaceCulling = !mat.BackfaceCulling; + mat.FrontfaceCulling = !mat.FrontfaceCulling; + } + } +} +#endif + + +/* + Render the environment around a node into a cubemap texture. +*/ +void renderEnvironmentCubeMap(irr::video::IVideoDriver* driver, irr::scene::ICameraSceneNode* cubeMapCamera, irr::scene::ISceneNode* cubeCenterNode, video::IRenderTarget* cubeMapRT, video::ITexture* dynamicCubeMapRTT, video::ITexture* depthStencilRTT) +{ + // Change to the cubemap camera which has a few specific render-settings + scene::ISceneManager* smgr = cubeMapCamera->getSceneManager(); + scene::ICameraSceneNode * oldCam = smgr->getActiveCamera(); + smgr->setActiveCamera( cubeMapCamera ); + + /* + We want to see everything around the center node, so hide the node + itself, otherwise it would be in the way. + Then set the camera to that node's position. + */ + cubeCenterNode->setVisible( false ); + const core::vector3df center( cubeCenterNode->getAbsolutePosition() ); + cubeMapCamera->setPosition( center ); + + /* + Render all 6 directions. Which means simple setting the camera target/up + vector to all 6 directions and then render the full scene each time. + So yeah - updating an environment cube-map means 6 full renders for each + object which needs an environment map. In other words - you generally only + want to do that in pre-processing, not in realtime. + */ + const core::vector3df targetVecs[6] = { + core::vector3df(1.f, 0.f, 0.f), + core::vector3df(-1.f, 0.f, 0.f), + core::vector3df(0.f, 1.f, 0.f), + core::vector3df(0.f, -1.f, 0.f), + core::vector3df(0.f, 0.f, 1.f), + core::vector3df(0.f, 0.f, -1.f) + }; + + const core::vector3df upVecs[6] = { + core::vector3df( 0,1,0 ), + core::vector3df( 0,1,0 ), + core::vector3df( 0,0,-1 ), + core::vector3df( 0,0,1 ), + core::vector3df( 0,1,0 ), + core::vector3df( 0,1,0 ) + }; + for ( int s=0; s<6; ++s ) + { + cubeMapCamera->setUpVector( upVecs[s] ); + cubeMapCamera->setTarget( center + targetVecs[s] ); + // Here we tell into which side of the cubemap texture we want to write + cubeMapRT->setTexture(dynamicCubeMapRTT, depthStencilRTT, (video::E_CUBE_SURFACE)(video::ECS_POSX + s)); + driver->setRenderTargetEx(cubeMapRT, video::ECBF_ALL); + smgr->drawAll(); + +#ifdef CUBEMAP_USPIDE_DOWN_RTT + // This works because the lock for rtt's always flips in Irrlicht. + // So in this case lock() unlock will result in a flipped texture + // But be warned - it's very, very slow! + driver->setRenderTarget(0); // to avoid accessing active rt + dynamicCubeMapRTT->lock(video::ETLM_READ_WRITE, 0, s, video::ETLF_FLIP_Y_UP_RTT); + dynamicCubeMapRTT->unlock(); +#endif + } + + //dynamicCubeMapRTT->regenerateMipMapLevels(); // Unfortunately we can't seem to have mipmaps for rtt's + + driver->setRenderTarget(0); + cubeCenterNode->setVisible( true ); + smgr->setActiveCamera( oldCam ); +} + +/* + Typical setup at the main start. +*/ +int main() +{ + // Ask user for driver + video::E_DRIVER_TYPE driverType = driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + // Create device + MyEventReceiver eventReceiver; + const core::dimension2d dimDevice(1024, 768); + IrrlichtDevice* device = createDevice( driverType, dimDevice, 32, false, false, false, &eventReceiver ); + if (!device) + return 1; + + const io::path mediaPath = getExampleMediaPath(); + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + gui::IGUIEnvironment* env = device->getGUIEnvironment(); + eventReceiver.Driver = driver; + + // Set window title + core::stringw strCaption(L"Cubemap example - Irrlicht Engine ["); + strCaption += driver->getName(); + strCaption += L"]"; + device->setWindowCaption(strCaption.c_str()); + + // set a nicer font + gui::IGUISkin* skin = env->getSkin(); + gui::IGUIFont* font = env->getFont(mediaPath + "fonthaettenschweiler.bmp"); + if (font) + skin->setFont(font); + + /* + Create a shader material for cube mapping + */ + video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices(); + s32 cubeMapReflectionMaterial = 0; + if( gpu ) + { + // Decide on shader to use based on active driver + irr::io::path vsFileName; + irr::io::path psFileName; + switch( driverType ) + { + case video::EDT_DIRECT3D9: + vsFileName = mediaPath + "cubeMapReflectionVS.hlsl"; + psFileName = mediaPath + "cubeMapReflectionPS.hlsl"; + break; + + case video::EDT_OPENGL: + vsFileName = mediaPath + "cubeMapReflection.vert"; + psFileName = mediaPath + "cubeMapReflection.frag"; + break; + } + + CubeMapReflectionCallback* cubeMapCB = new CubeMapReflectionCallback(smgr, 2); + cubeMapReflectionMaterial = gpu->addHighLevelShaderMaterialFromFiles( + vsFileName, "VS", video::EVST_VS_1_1, + psFileName, "PS", video::EPST_PS_3_0, + cubeMapCB, video::EMT_SOLID ); + if ( cubeMapReflectionMaterial >= 0 ) + eventReceiver.Shader = cubeMapCB; + cubeMapCB->drop(); + } + + // add fps camera + scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(0, 100.f, 1.f); + camera->setPosition( core::vector3df( 0,10,-200 ) ); + device->getCursorControl()->setVisible(false); + + /* + Get 6 images forming a cubemap. The coordinate system used in those images + seemed to be different than the one in Irrlicht. I decided to leave it like + that because it's pretty common that way. If you get cubemap textures which + seem to have x/y/z axis named different you'll just have to experiment until + you figured out the correct order. + */ + core::array cubeMapImages; + cubeMapImages.push_back(driver->createImageFromFile( mediaPath + "cubemap_posx.jpg" )); + cubeMapImages.push_back(driver->createImageFromFile( mediaPath + "cubemap_negx.jpg" )); + cubeMapImages.push_back(driver->createImageFromFile( mediaPath + "cubemap_posy.jpg" )); + cubeMapImages.push_back(driver->createImageFromFile( mediaPath + "cubemap_negy.jpg" )); + cubeMapImages.push_back(driver->createImageFromFile( mediaPath + "cubemap_posz.jpg" )); + cubeMapImages.push_back(driver->createImageFromFile( mediaPath + "cubemap_negz.jpg" )); + + /* Create a cubemap texture from those images. Note that 6 images become a single texture now. */ + video::ITexture* cubeMapStaticTex = 0; + cubeMapStaticTex = driver->addTextureCubemap("cm", cubeMapImages[0], cubeMapImages[1], cubeMapImages[2], cubeMapImages[3], cubeMapImages[4], cubeMapImages[5]); + for ( u32 i=0; idrop(); + cubeMapImages.clear(); + + /* Create a render target, cubemap render-target-textures and a camera with settings for cube mapping */ + video::IRenderTarget* cubeMapRT = driver->addRenderTarget(); + video::ITexture* dynamicCubeMapRTT = 0; + video::ITexture* depthStencilRTT = 0; + video::ITexture* dynamicCubeMapRTT_intermediate = 0; // just for rendering, but not used in material + video::ITexture* dynamicCubeMapTex = 0; // dynamic and with mipmaps + scene::ICameraSceneNode* cubeMapCamera = 0; + if( driver->queryFeature( video::EVDF_RENDER_TO_TARGET ) ) + { + // Create cube map textures and render target cubemap textures. + const u32 dynamicCubeMapSize = 512; + dynamicCubeMapRTT = driver->addRenderTargetTextureCubemap(dynamicCubeMapSize, "cube_rtr"); + depthStencilRTT = driver->addRenderTargetTexture(irr::core::dimension2du(dynamicCubeMapSize, dynamicCubeMapSize), "cubemap_ds", irr::video::ECF_D24S8); + + dynamicCubeMapRTT_intermediate = driver->addRenderTargetTextureCubemap(dynamicCubeMapSize, "cube_rtr"); + dynamicCubeMapTex = driver->addTextureCubemap(dynamicCubeMapSize, "cube_tex"); + + // Camera for creating an environment cubemap + cubeMapCamera = smgr->addCameraSceneNode(); + cubeMapCamera->setFOV(core::PI* 0.5f); // 90 view angle + cubeMapCamera->setAspectRatio(1.f); // it's a cube... all sides have the same length + smgr->setActiveCamera( camera ); + } + + /* + Add sphere-nodes which will be using the cubemaps as materials. + You may also want to experiment with other node-types here! + */ + + scene::ISceneNode* sphereNode = 0; + scene::ISceneNode* sphereNode2 = 0; + scene::ISceneNode* sphereNode3 = 0; + scene::IMesh* sphereMesh = smgr->getGeometryCreator()->createSphereMesh(100.f); + if( sphereMesh ) + { + // Nothing really special here except they need the shader material to display cubemaps. + sphereNode = smgr->addMeshSceneNode( sphereMesh ); + sphereNode->setPosition( core::vector3df(-250,0,0) ); + sphereNode->updateAbsolutePosition(); + sphereNode->setMaterialFlag( video::EMF_LIGHTING, false ); + sphereNode->setMaterialTexture( 0, dynamicCubeMapRTT ); + sphereNode->setMaterialType( (video::E_MATERIAL_TYPE)cubeMapReflectionMaterial ); + eventReceiver.addInfoTextNode(font, L"Cubemap dynamic rtt, no mip-maps", sphereNode); + + if ( dynamicCubeMapTex ) + { + sphereNode3 = smgr->addMeshSceneNode( sphereMesh ); + sphereNode3->setPosition( core::vector3df(0,0,250) ); + sphereNode3->updateAbsolutePosition(); + sphereNode3->setMaterialFlag( video::EMF_LIGHTING, false ); + sphereNode3->setMaterialTexture( 0, dynamicCubeMapTex ); + sphereNode3->getMaterial(0).TextureLayer[0].TrilinearFilter = false; // this is default anyway. It would be faster - but you can only access integer mip-levels - no filtering between mip-levels. + sphereNode3->setMaterialType( (video::E_MATERIAL_TYPE)cubeMapReflectionMaterial ); + eventReceiver.addInfoTextNode(font, L"Cubemap dynamic with mip-maps", sphereNode3); + } + + if ( cubeMapStaticTex ) + { + sphereNode2 = smgr->addMeshSceneNode( sphereMesh ); + sphereNode2->setPosition( core::vector3df(250,0,0) ); + sphereNode2->updateAbsolutePosition(); + sphereNode2->setMaterialFlag( video::EMF_LIGHTING, false ); + sphereNode2->setMaterialTexture( 0, cubeMapStaticTex ); + sphereNode2->getMaterial(0).TextureLayer[0].TrilinearFilter = true; // this way smoothing happens between different mip-levels. + sphereNode2->setMaterialType( (video::E_MATERIAL_TYPE)cubeMapReflectionMaterial ); + eventReceiver.addInfoTextNode(font, L"Cubemap fixed images", sphereNode2); + } + + sphereMesh->drop(); + } + + /* Add some background which will show up in the environment maps. + For first one we use the same textures as used in the spheres. + Note the difference between a skybox and a cubemap is that the skybox really uses 6 different + textures. While the cubemap uses a single texture created from 6 images. */ + eventReceiver.BackgroundSkybox = smgr->addSkyBoxSceneNode( + driver->getTexture(mediaPath + "cubemap_posy.jpg"), // top + driver->getTexture(mediaPath + "cubemap_negy.jpg"), // bottom + driver->getTexture(mediaPath + "cubemap_posz.jpg"), // left + driver->getTexture(mediaPath + "cubemap_negz.jpg"), // right + driver->getTexture(mediaPath + "cubemap_posx.jpg"), // front + driver->getTexture(mediaPath + "cubemap_negx.jpg")); // back + + + + /* Another background for comparison and to make it more obvious + when the spheres reflect the environment and when they use static cubemaps. */ + scene::IMesh * cubeMesh = smgr->getGeometryCreator()->createCubeMesh( core::vector3df(10.f, 10.f, 10.f), scene::ECMT_6BUF_4VTX_NP); + smgr->getMeshManipulator()->scale(cubeMesh, core::vector3df(-1, 1, 1)); + if( cubeMesh ) + { + smgr->getMeshManipulator()->setVertexColors( cubeMesh->getMeshBuffer(0), video::SColor(255, 240, 10, 10) ); + smgr->getMeshManipulator()->setVertexColors( cubeMesh->getMeshBuffer(1), video::SColor(255, 240, 130, 10) ); + smgr->getMeshManipulator()->setVertexColors( cubeMesh->getMeshBuffer(2), video::SColor(255, 50, 250, 10) ); + smgr->getMeshManipulator()->setVertexColors( cubeMesh->getMeshBuffer(3), video::SColor(255, 70, 10, 250) ); + smgr->getMeshManipulator()->setVertexColors( cubeMesh->getMeshBuffer(4), video::SColor(255, 240, 250, 10) ); + smgr->getMeshManipulator()->setVertexColors( cubeMesh->getMeshBuffer(5), video::SColor(255, 85, 250, 250) ); + + eventReceiver.BackgroundCube = smgr->addMeshSceneNode( cubeMesh ); + cubeMesh->drop(); + + eventReceiver.BackgroundCube->setScale( core::vector3df( 200, 200, 200 ) ); + eventReceiver.BackgroundCube->setMaterialFlag( video::EMF_LIGHTING, false ); + eventReceiver.BackgroundCube->setVisible(false); + } + +#ifdef CUBEMAP_UPSIDE_DOWN_GL_PROJECTION + if ( driverType == video::EDT_OPENGL ) + { + // Flip projection matrix (note this also flips front/backface culling) + core::matrix4 matProj = cubeMapCamera->getProjectionMatrix(); + matProj[4] = -matProj[4]; + matProj[5] = -matProj[5]; + matProj[6] = -matProj[6]; + matProj[7] = -matProj[7]; + cubeMapCamera->setProjectionMatrix(matProj); + } +#endif + + /* + Add some moving node to show the difference between static/dynamic environment maps + */ + scene::IMeshSceneNode * movingNode = smgr->addCubeSceneNode(30.f); + movingNode->getMaterial(0).Lighting = false; + smgr->getMeshManipulator()->setVertexColors( movingNode->getMesh()->getMeshBuffer(0), video::SColor(255, 230, 200, 150)); + scene::ISceneNodeAnimator* circleAnimator = smgr->createFlyCircleAnimator(core::vector3df(-125, -50.f, 125), 300.f, 0.0005f); + movingNode->addAnimator(circleAnimator); + circleAnimator->drop(); + + /* Add some UI */ + if ( eventReceiver.Shader ) + { + skin->setColor(gui::EGDC_3D_FACE, video::SColor(50, 160, 120, 120)); + + u32 top = dimDevice.Height - 200; + const u32 left = dimDevice.Width - 350; + const u32 right = dimDevice.Width - 10; + irr::gui::IGUIStaticText * stextUVW = env->addStaticText(L" Style of generating texture coordinates:\n Change with (space)", core::recti(left, top, right, top+35), false, true, 0, -1, true); + top += 40; + stextUVW->setTextAlignment(gui::EGUIA_UPPERLEFT, gui::EGUIA_UPPERLEFT); + eventReceiver.CurrentStyleUVW = env->addStaticText(L"", core::recti(240,0, 400, 20), false, false, stextUVW); + eventReceiver.updateStyleUVW(); + + irr::gui::IGUIStaticText * stextRoughness = env->addStaticText(L" Roughness:\n Change with (+) and (-)", core::recti(left, top, right, top+35), false, true, 0, -1, true); + top += 40; + eventReceiver.CurrentRoughness = env->addStaticText( L"", core::recti(240,0, 400, 20), false, false, stextRoughness); + eventReceiver.updateRoughness(); + + irr::gui::IGUIStaticText * stextSeamlessCupemap = env->addStaticText(L" Seamless cubemap (with roughness):\n Change with (s)", core::recti(left, top, right, top+35), false, true, 0, -1, true); + top += 40; + eventReceiver.CurrentSeamlessCubemap = env->addStaticText( L"", core::recti(240,0, 400, 20), false, false, stextSeamlessCupemap); + eventReceiver.updateSeamless(); + + irr::gui::IGUIStaticText * stextUpdates = env->addStaticText(L" Cubemap updates:\n Change with (u)", core::recti(left, top, right, top+35), false, true, 0, -1, true); + top += 40; + eventReceiver.CurrentCubemapUpdates = env->addStaticText( L"", core::recti(240,0, 400, 20), false, false, stextUpdates); + eventReceiver.updateCubemapUpdates(); + + env->addStaticText(L" Change background with (b)", core::recti(left, top, right, top+15), false, true, 0, -1, true); + top += 20; + + env->addStaticText(L" Show/hide info nodes with (i)", core::recti(left, top, right, top+15), false, true, 0, -1, true); + } + + + /* Main loop */ + while(device->run()) + { + if (device->isWindowActive()) + { + driver->beginScene(true, true, video::SColor(255, 127, 127, 255)); + + /* Check if we want to update the environment maps. + Usually not something you'll do every frame, but either once at the star + or maybe updating an environment map once in a while. + */ + int updateCubemaps = eventReceiver.checkCubemapUpdate(); + if( dynamicCubeMapRTT && sphereNode && updateCubemaps > 0 ) + { +#ifdef CUBEMAP_UPSIDE_DOWN_GL_PROJECTION + core::array allNodes; + if ( driverType == video::EDT_OPENGL ) + { + /* + Flipping projection matrix flips front/backface culling. + We only have a skybox so in this case this still would be fast, with more objects it's getting more ugly. + */ + smgr->getSceneNodesFromType(scene::ESNT_ANY, allNodes); + flipCullingFlags(allNodes); + } +#endif + /* + If rendered just once then this node has still a white (or even undefined) texture at this point + Just hiding it and render the background when rendering the cubemap for the other node is less noticable + than having a big white dot in the environment texture. + Render order can matter if you want several environment maps in your scene. + */ + if (sphereNode3) + sphereNode3->setVisible(false); + + renderEnvironmentCubeMap(driver, cubeMapCamera, sphereNode, cubeMapRT, dynamicCubeMapRTT, depthStencilRTT); + + if ( sphereNode3) + { + if ( updateCubemaps == 2 ) + { + /* + Our rtt's unfortunately don't have mipmaps (sorry, not sure if we can get that somehow...) + So if we want mipmaps in the dynamic cubemap we have to copy it to a non-rtt texture. + Warning: Very, very slow. Far slower than just creating an environment map as this + will copy the texture from GPU to main memory - copy it to a new texture, create mip-maps and + upload the result back to the GPU. + */ + renderEnvironmentCubeMap(driver, cubeMapCamera, sphereNode3, cubeMapRT, dynamicCubeMapRTT_intermediate, depthStencilRTT); + for ( int i=0; i<6; ++i) + { + void * rtData = dynamicCubeMapRTT_intermediate->lock(video::ETLM_READ_ONLY, 0, i, video::ETLF_NONE); + void * tData = dynamicCubeMapTex->lock(video::ETLM_READ_WRITE, 0, i); + memcpy(tData, rtData, dynamicCubeMapTex->getPitch()*dynamicCubeMapTex->getSize().Width); + dynamicCubeMapRTT_intermediate->unlock(); + dynamicCubeMapTex->unlock(); + dynamicCubeMapTex->regenerateMipMapLevels(); + } + } + sphereNode3->setVisible(true); + } + +#ifdef CUBEMAP_UPSIDE_DOWN_GL_PROJECTION + if ( driverType == video::EDT_OPENGL ) + { + flipCullingFlags(allNodes); + } +#endif + } + + smgr->drawAll(); + env->drawAll(); + + driver->endScene(); + } + } + + device->drop(); + + return 0; +} + +/* +**/ diff --git a/examples/29.HardwareSkinning/where_is_it.txt b/examples/29.HardwareSkinning/where_is_it.txt new file mode 100644 index 00000000..afe0b22e --- /dev/null +++ b/examples/29.HardwareSkinning/where_is_it.txt @@ -0,0 +1,2 @@ +This example is currently only available in Irrlicht svn branch for the shader-pipeline: https://sourceforge.net/p/irrlicht/code/HEAD/tree/branches/shader-pipeline +It will be merged with the svn trunk at some point in the future. diff --git a/examples/30.Profiling/Makefile b/examples/30.Profiling/Makefile new file mode 100644 index 00000000..fa113d48 --- /dev/null +++ b/examples/30.Profiling/Makefile @@ -0,0 +1,56 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := 30.Profiling +# List of source files, separated by spaces +Sources := main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/30.Profiling/Profiling.cbp b/examples/30.Profiling/Profiling.cbp new file mode 100644 index 00000000..0f71fbde --- /dev/null +++ b/examples/30.Profiling/Profiling.cbp @@ -0,0 +1,55 @@ + + + + + + diff --git a/examples/30.Profiling/Profiling.vcproj b/examples/30.Profiling/Profiling.vcproj new file mode 100644 index 00000000..494f9bb4 --- /dev/null +++ b/examples/30.Profiling/Profiling.vcproj @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/30.Profiling/Profiling.xcodeproj/project.pbxproj b/examples/30.Profiling/Profiling.xcodeproj/project.pbxproj new file mode 100644 index 00000000..6468c707 --- /dev/null +++ b/examples/30.Profiling/Profiling.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* 30.Profiling.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 30.Profiling.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* 30.Profiling.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* 30.Profiling */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "30.Profiling" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 30.Profiling; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* 30.Profiling.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Profiling" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* 30.Profiling */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Profiling" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "30.Profiling" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/30.Profiling/Profiling.xcodeproj/xcshareddata/xcschemes/30.Profiling.xcscheme b/examples/30.Profiling/Profiling.xcodeproj/xcshareddata/xcschemes/30.Profiling.xcscheme new file mode 100644 index 00000000..111087e8 --- /dev/null +++ b/examples/30.Profiling/Profiling.xcodeproj/xcshareddata/xcschemes/30.Profiling.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/30.Profiling/Profiling_vc10.vcxproj b/examples/30.Profiling/Profiling_vc10.vcxproj new file mode 100644 index 00000000..7fba2fa9 --- /dev/null +++ b/examples/30.Profiling/Profiling_vc10.vcxproj @@ -0,0 +1,184 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 30.Profiling + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97} + 30.Profiling + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\30.Profiling.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)Profiling.pdb + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\30.Profiling.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)Profiling.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\30.Profiling.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\30.Profiling.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/30.Profiling/Profiling_vc11.vcxproj b/examples/30.Profiling/Profiling_vc11.vcxproj new file mode 100644 index 00000000..265698a9 --- /dev/null +++ b/examples/30.Profiling/Profiling_vc11.vcxproj @@ -0,0 +1,188 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 30.Profiling + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97} + 30.Profiling + Win32Proj + + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\30.Profiling.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)Profiling.pdb + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\30.Profiling.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)Profiling.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\30.Profiling.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\30.Profiling.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/30.Profiling/Profiling_vc12.vcxproj b/examples/30.Profiling/Profiling_vc12.vcxproj new file mode 100644 index 00000000..1b5e4972 --- /dev/null +++ b/examples/30.Profiling/Profiling_vc12.vcxproj @@ -0,0 +1,188 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 30.Profiling + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97} + 30.Profiling + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\30.Profiling.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)Profiling.pdb + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\30.Profiling.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)Profiling.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\30.Profiling.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\30.Profiling.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/30.Profiling/Profiling_vc14.vcxproj b/examples/30.Profiling/Profiling_vc14.vcxproj new file mode 100644 index 00000000..caf33cd9 --- /dev/null +++ b/examples/30.Profiling/Profiling_vc14.vcxproj @@ -0,0 +1,188 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 30.Profiling + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97} + 30.Profiling + Win32Proj + + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ..\..\bin\Win32-VisualStudio\30.Profiling.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)Profiling.pdb + Console + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ..\..\bin\Win64-VisualStudio\30.Profiling.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)Profiling.pdb + Console + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win32-VisualStudio\30.Profiling.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + true + Speed + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Sync + + + Level3 + + + Cdecl + + + ..\..\bin\Win64-VisualStudio\30.Profiling.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + \ No newline at end of file diff --git a/examples/30.Profiling/main.cpp b/examples/30.Profiling/main.cpp new file mode 100644 index 00000000..0ad479af --- /dev/null +++ b/examples/30.Profiling/main.cpp @@ -0,0 +1,507 @@ +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +// Copyright by Michael Zeilfelder + +/** Example 030 Profiling + +Profiling is used to get runtime information about code code. + +There exist several independent profiling tools. +Examples for free profilers are "gprof" for the GNU toolchain and "very sleepy" +from codersnotes for Windows. Proprietary tools are for example "VTune" from +Intel or "AMD APP Profiler". Those tools work by sampling the running +application regularly to get statistic information about the called functions. +The way to use them is to compile your application with special flags +to include profiling information (some also work with debug information). They +also might allow to profile only certain parts of the code, although +most can't do that. The sampling is usually rather time-consuming which means +the application will be very slow when collecting the profiling data. It's often +useful to start with one of those tools to get an overview over the bottlenecks +in your application. Those tools have the advantage that they don't need any +modifications inside the code. + +Once you need to dig deeper the Irrlicht profiler can help you. It works nearly +like a stopwatch. You add start/stop blocks into the parts of your code which +you need to check and the Irrlicht profiler will give you then the exact times +of execution for those parts. And unlike general profiler tools you don't just +get average information about the run-time but also worst-cases. Which tends +to be information you really for a stable framerate. Also the Irrlicht profiler +has a low overhead and affects only the areas which you want to time. So you +can profile applications with nearly original speed. + +Irrlicht itself has such profiling information, which is useful to figure out +where the runtime inside the engine is spend. To get that profiling data you +need to recompile Irrlicht with _IRR_COMPILE_WITH_PROFILING_ enabled as +collecting profiling information is disabled by default for speed reasons. +*/ + +/* + It's usually a good idea to wrap all your profile code with a define. + That way you don't have to worry too much about the runtime profiling + itself takes. You can remove the profiling code completely when you release + the software by removing a single define.Or sometimes you might want to + have several such defines for different areas of your application code. +*/ +#define ENABLE_MY_PROFILE // comment out to remove the profiling code +#ifdef ENABLE_MY_PROFILE + // calls code X + #define MY_PROFILE(X) X +#else + // removes the code for X in the pre-processor + #define MY_PROFILE(X) +#endif // IRR_PROFILE + +#include +#include "driverChoice.h" +#include "exampleHelper.h" + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +/* + We have the choice between working with fixed and with automatic profiling id's. + Here are some fixed ID's we will be using. +*/ +enum EProfiles +{ + EP_APP_TIME_ONCE, + EP_APP_TIME_UPDATED, + EP_SCOPE1, + EP_SCOPE2, + EP_DRAW_SCENE +}; + +// For our example scenes +enum EScenes +{ + ES_NONE, // no scene set + ES_CUBE, + ES_QUAKE_MAP, + ES_DWARVES, + + ES_COUNT // counting how many scenes we have +}; + +/* + Controlling the profiling display is application specific behavior. + We use function keys in our case and play around with all the parameters. + In real applications you will likely only need something to make the + profiling-display visible/invisible and switch pages while the parameters + can be set to fixed values. +*/ +class MyEventReceiver : public IEventReceiver +{ +public: + // constructor + MyEventReceiver(ISceneManager * smgr) : GuiProfiler(0), IncludeOverview(true), IgnoreUncalled(false), ActiveScene(ES_NONE), SceneManager(smgr) {} + + virtual bool OnEvent(const SEvent& event) + { + if (event.EventType == EET_KEY_INPUT_EVENT) + { + if ( event.KeyInput.PressedDown ) + { + /* + Catching keys to control the profiling display and the profiler itself + */ + switch ( event.KeyInput.Key ) + { + case KEY_F1: + GuiProfiler->setVisible( !GuiProfiler->isVisible() ); + break; + case KEY_F2: + GuiProfiler->nextPage(IncludeOverview); + break; + case KEY_F3: + GuiProfiler->previousPage(IncludeOverview); + break; + case KEY_F4: + GuiProfiler->firstPage(IncludeOverview); + break; + case KEY_F5: + IncludeOverview = !IncludeOverview; + GuiProfiler->firstPage(IncludeOverview); // not strictly needed, but otherwise the update won't update + break; + case KEY_F6: + /* + You can set more filters. This one filters out profile data which was never called. + */ + IgnoreUncalled = !IgnoreUncalled; + GuiProfiler->setFilters(IgnoreUncalled ? 1 : 0, 0, 0.f, 0); + break; + case KEY_F7: + GuiProfiler->setShowGroupsTogether( !GuiProfiler->getShowGroupsTogether() ); + break; + case KEY_F8: + NextScene(); + break; + case KEY_F9: + { + u32 index = 0; + if ( getProfiler().findGroupIndex(index, L"grp runtime") ) + { + getProfiler().resetGroup(index); + } + } + break; + case KEY_F10: + { + u32 index = 0; + if ( getProfiler().findDataIndex(index, L"scope 3") ) + { + getProfiler().resetDataByIndex(index); + } + } + break; + case KEY_F11: + getProfiler().resetAll(); + break; + case KEY_KEY_F: + GuiProfiler->setFrozen(!GuiProfiler->getFrozen()); + break; + default: + break; + } + } + } + + return false; + } + + /* + Some example scenes so we have something to profile + */ + void NextScene() + { + SceneManager->clear(); + ActiveScene = (ActiveScene+1) % ES_COUNT; + if ( ActiveScene == 0 ) + ActiveScene = ActiveScene+1; + + switch ( ActiveScene ) + { + case ES_CUBE: + { + /* + Simple scene with cube and light. + */ + MY_PROFILE(CProfileScope p(L"cube", L"grp switch scene");) + + SceneManager->addCameraSceneNode (0, core::vector3df(0, 0, 0), + core::vector3df(0, 0, 100), + -1); + + SceneManager->addCubeSceneNode (30.0f, 0, -1, + core::vector3df(0, 20, 100), + core::vector3df(45, 45, 45), + core::vector3df(1.0f, 1.0f, 1.0f)); + + SceneManager->addLightSceneNode(0, core::vector3df(0, 0, 0), + video::SColorf(1.0f, 1.0f, 1.0f), + 100.0f); + } + break; + case ES_QUAKE_MAP: + { + /* + Our typical Irrlicht example quake map. + */ + MY_PROFILE(CProfileScope p(L"quake map", L"grp switch scene");) + + scene::IAnimatedMesh* mesh = SceneManager->getMesh("20kdm2.bsp"); + scene::ISceneNode* node = 0; + + if (mesh) + node = SceneManager->addOctreeSceneNode(mesh->getMesh(0), 0, -1, 1024); + if (node) + node->setPosition(core::vector3df(-1300,-144,-1249)); + SceneManager->addCameraSceneNodeFPS(); + } + break; + case ES_DWARVES: + { + /* + Stress-test Irrlicht a little bit by creating many objects. + */ + MY_PROFILE(CProfileScope p(L"dwarfes", L"grp switch scene");) + + scene::IAnimatedMesh* aniMesh = SceneManager->getMesh( getExampleMediaPath() + "dwarf.x" ); + if (aniMesh) + { + scene::IMesh * mesh = aniMesh->getMesh (0); + if ( !mesh ) + break; + + /* + You can never have too many dwarves. So let's make some. + */ + const int nodesX = 30; + const int nodesY = 5; + const int nodesZ = 30; + + aabbox3df bbox = mesh->getBoundingBox(); + vector3df extent = bbox.getExtent(); + const f32 GAP = 10.f; + f32 halfSizeX = 0.5f * (nodesX*extent.X + GAP*(nodesX-1)); + f32 halfSizeY = 0.5f * (nodesY*extent.Y + GAP*(nodesY-1)); + f32 halfSizeZ = 0.5f * (nodesZ*extent.Z + GAP*(nodesZ-1)); + + for ( int x = 0; x < nodesX; ++x ) + { + irr::f32 gapX = x > 0 ? (x-1)*GAP : 0.f; + irr::f32 posX = -halfSizeX + x*extent.X + gapX; + for ( int y = 0; y < nodesY; ++y ) + { + irr::f32 gapY = y > 0 ? (y-1)*GAP : 0.f; + irr::f32 posY = -halfSizeY + y*extent.Y + gapY; + for ( int z=0; z < nodesZ; ++z ) + { + irr::f32 gapZ = z > 0 ? (z-1)*GAP : 0.f; + irr::f32 posZ = -halfSizeZ + z*extent.Z + gapZ; + scene::IAnimatedMeshSceneNode * node = SceneManager->addAnimatedMeshSceneNode(aniMesh, NULL, -1, vector3df(posX, posY, posZ) ); + node->setMaterialFlag(video::EMF_LIGHTING, false); + } + } + } + + irr::scene::ICameraSceneNode * camera = SceneManager->addCameraSceneNodeFPS(0, 20.f, 0.1f ); + camera->updateAbsolutePosition(); + camera->setTarget( vector3df(0,0,0) ); + camera->updateAbsolutePosition(); + camera->setPosition(irr::core::vector3df(halfSizeX+extent.X, halfSizeY+extent.Y, halfSizeZ+extent.Z)); + camera->updateAbsolutePosition(); + } + } + break; + } + } + + IGUIProfiler * GuiProfiler; + bool IncludeOverview; + bool IgnoreUncalled; + u32 ActiveScene; + scene::ISceneManager* SceneManager; +}; + +void recursive(int recursion) +{ + /* + As the profiler uses internally counters for start stop and only + takes profile data when that counter is zero we count all recursions + as a single call. + If you want to profile each call on it's own you have to use explicit start/stop calls and + stop the profile id right before the recursive call. + */ + MY_PROFILE(CProfileScope p3(L"recursive", L"grp runtime");) + if (recursion > 0 ) + recursive(recursion-1); +} + +int main() +{ + /* + Setup, nothing special here. + */ + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + /* + Profiler is independent of the device - so we can time the device setup + */ + MY_PROFILE(s32 pDev = getProfiler().add(L"createDevice", L"grp runtime");) + MY_PROFILE(getProfiler().start(pDev);) + + IrrlichtDevice * device = createDevice(driverType, core::dimension2d(640, 480)); + if (device == 0) + { + /* + When working with start/stop you should add a stop to all exit paths. + Although in this case it wouldn't matter as we don't do anything with it when we quit here. + */ + MY_PROFILE(getProfiler().stop(pDev);) + return 1; // could not create selected driver. + } + MY_PROFILE(getProfiler().stop(pDev);) + + video::IVideoDriver* driver = device->getVideoDriver(); + IGUIEnvironment* env = device->getGUIEnvironment(); + scene::ISceneManager* smgr = device->getSceneManager(); + + const io::path mediaPath = getExampleMediaPath(); + + /* + A map we use for one of our test-scenes. + */ + device->getFileSystem()->addFileArchive(mediaPath + "map-20kdm2.pk3"); + + MyEventReceiver receiver(smgr); + device->setEventReceiver(&receiver); + receiver.NextScene(); + + /* + Show some info about the controls used in this example + */ + IGUIStaticText * staticText = env->addStaticText( + L" to show/hide the profiling display\n" + L" to show the next page\n" + L" to show the previous page\n" + L" to show the first page\n" + L" to flip between including the group overview\n" + L" to flip between ignoring and showing uncalled data\n" + L" to flip between showing 1 group per page or all together\n" + L" to change our scene\n" + L" to reset the \"grp runtime\" data\n" + L" to reset the scope 3 data\n" + L" to reset all data\n" + L" to freeze/unfreeze the display\n" + , recti(10,10, 250, 140), true, true, 0, -1, true); + staticText->setWordWrap(false); + + /* + IGUIProfiler is can be used to show active profiling data at runtime. + */ + receiver.GuiProfiler = env->addProfilerDisplay(core::recti(40, 140, 600, 470)); + receiver.GuiProfiler->setDrawBackground(true); + + /* + Get a monospaced font - it's nicer when working with rows of numbers. + */ + IGUIFont* font = env->getFont(mediaPath + "fontcourier.bmp"); + if (font) + receiver.GuiProfiler->setOverrideFont(font); + + + /* + Adding ID's has to be done before the start/stop calls. + This allows start/stop to be really fast and we still have nice information like + names and groups. + Groups are created automatically each time an ID with a new group-name is added. + Groups exist to sort the display data in a nicer way. + */ + MY_PROFILE( + getProfiler().add(EP_APP_TIME_ONCE, L"full time", L"grp runtime"); + getProfiler().add(EP_APP_TIME_UPDATED, L"full time updated", L"grp runtime"); + getProfiler().add(EP_SCOPE1, L"scope 1", L"grp runtime"); + getProfiler().add(EP_DRAW_SCENE, L"draw scene", L"grp runtime"); + ) + + /* + Two timers which run the whole time. One will be continuously updated the other won't. + */ + MY_PROFILE(getProfiler().start(EP_APP_TIME_ONCE);) + MY_PROFILE(getProfiler().start(EP_APP_TIME_UPDATED);) + + s32 lastFPS = -1; + while(device->run() && driver) + { + if (device->isWindowActive()) + { + /* + For comparison show the FPS in the title bar + */ + s32 fps = driver->getFPS(); + if (lastFPS != fps) + { + core::stringw str = L"FPS: "; + str += fps; + device->setWindowCaption(str.c_str()); + lastFPS = fps; + } + + /* + Times are only updated on stop() calls. So if we want a long-running timer + to update we have to stop() and start() it in between. + Note that this will also update the call-counter and is rarely needed. + */ + MY_PROFILE(getProfiler().stop(EP_APP_TIME_UPDATED);) + MY_PROFILE(getProfiler().start(EP_APP_TIME_UPDATED);) + + /* + The following CProfileScope's will all do the same thing: + they measure the time this loop takes. They call start() + when the object is created and call stop() when it + is destroyed. + + The first one creates an ID on it's first call and will + do constant string-comparisons for the name. It's + the slowest, but most comfortable solution. Use it when you + just need to run a quick check without the hassle of setting + up id's. + */ + MY_PROFILE(CProfileScope p3(L"scope 3", L"grp runtime");) + + /* + Second CProfileScope solution will create a data block on first + call. So it's a little bit slower on the first run. But usually + that's hardly noticeable. + */ + MY_PROFILE(CProfileScope p2(EP_SCOPE2, L"scope 2", L"grp runtime");) + + /* + Last CProfileScope solution is the fastest one. But you must add + the id before you can use it like that. + */ + MY_PROFILE(CProfileScope p1(EP_SCOPE1)); + + /* + Call a recursive function to show how profiler only counts it once. + */ + recursive(5); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, SColor(0,200,200,200)); + + /* + If you want to profile only some lines and not a complete scope + then you have to work with start() and stop() calls. + */ + MY_PROFILE(getProfiler().start(EP_DRAW_SCENE);) + smgr->drawAll(); + MY_PROFILE(getProfiler().stop(EP_DRAW_SCENE);) + + /* + If it doesn't matter if the profiler takes some time you can also + be lazy and create id's automatically on the spot: + */ + MY_PROFILE(s32 pEnv = getProfiler().add(L"draw env", L"grp runtime");) + MY_PROFILE(getProfiler().start(pEnv);) + env->drawAll(); + MY_PROFILE(getProfiler().stop(pEnv);) + + driver->endScene(); + } + } + + /* + Shutdown. + */ + device->drop(); + + /* + The profiler is independent of an device - so we can still work with it. + */ + + MY_PROFILE(getProfiler().stop(EP_APP_TIME_UPDATED)); + MY_PROFILE(getProfiler().stop(EP_APP_TIME_ONCE)); + + /* + Print a complete overview of the profiling data to the console. + */ + MY_PROFILE(core::stringw output); + MY_PROFILE(getProfiler().printAll(output)); + MY_PROFILE(printf("%s", core::stringc(output).c_str() )); + + return 0; +} + +/* +**/ diff --git a/examples/BuildAllExamples.workspace b/examples/BuildAllExamples.workspace new file mode 100644 index 00000000..d5cb5827 --- /dev/null +++ b/examples/BuildAllExamples.workspace @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/BuildAllExamples.xcworkspace/contents.xcworkspacedata b/examples/BuildAllExamples.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..ae4d7b20 --- /dev/null +++ b/examples/BuildAllExamples.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/BuildAllExamples_vc10.sln b/examples/BuildAllExamples_vc10.sln new file mode 100644 index 00000000..27618b7c --- /dev/null +++ b/examples/BuildAllExamples_vc10.sln @@ -0,0 +1,437 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Irrlicht", "..\source\Irrlicht\Irrlicht10.0.vcxproj", "{E08E042A-6C45-411B-92BE-3CC31331019F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "01.HelloWorld", "01.HelloWorld\HelloWorld_vc10.vcxproj", "{5AD4C95C-BA38-4692-BA4B-8C25A86208F9}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "02.Quake3Map", "02.Quake3Map\Quake3Map_vc10.vcxproj", "{D1A464A2-D479-458C-98A2-60965D823CD1}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "03.CustomSceneNode", "03.CustomSceneNode\CustomSceneNode_vc10.vcxproj", "{171CCDFA-C140-4956-8EB7-F0168F4521D3}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "04.Movement", "04.Movement\Movement_vc10.vcxproj", "{7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "05.UserInterface", "05.UserInterface\UserInterface_vc10.vcxproj", "{622C9DD7-0391-49FF-AF53-24F9D5A8EC53}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "06.2DGraphics", "06.2DGraphics\2DGraphics_vc10.vcxproj", "{E71B6F18-10DC-4101-A541-F6D33F71B2BD}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "07.Collision", "07.Collision\Collision_vc10.vcxproj", "{3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "08.SpecialFX", "08.SpecialFX\SpecialFX_vc10.vcxproj", "{C869BF55-B9D6-4980-BC92-60FA0CF8411A}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "09.Meshviewer", "09.Meshviewer\Meshviewer_vc10.vcxproj", "{2AE24484-22FC-481B-9A40-7CD0DA5C8E06}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "10.Shaders", "10.Shaders\Shaders_vc10.vcxproj", "{27158C82-CD15-4A9B-9848-35E7065B209F}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "11.PerPixelLighting", "11.PerPixelLighting\PerPixelLighting_vc10.vcxproj", "{C4B42409-542D-4EFC-9E6B-44713FD47A33}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "12.TerrainRendering", "12.TerrainRendering\TerrainRendering_vc10.vcxproj", "{3A5B74E5-6390-43B0-A459-2793B81FFD31}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "13.RenderToTexture", "13.RenderToTexture\RenderToTexture_vc10.vcxproj", "{0914E5C8-5352-467B-8421-C9EB35BD5596}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "14.Win32Window", "14.Win32Window\Win32Window_vc10.vcxproj", "{772FBE05-D05A-467B-9842-BEC409EEA8D0}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "15.LoadIrrFile", "15.LoadIrrFile\LoadIrrFile_vc10.vcxproj", "{78C9F424-523C-49AC-94B7-823AA4A26BF9}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "16.Quake3MapShader", "16.Quake3MapShader\Quake3MapShader_vc10.vcxproj", "{EB3B38EA-5CE7-4983-845B-880661E69D09}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "17.HelloWorld_Mobile", "17.HelloWorld_Mobile\17. HelloWorld for Windows Mobile on PC_vc10.vcxproj", "{2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "18.SplitScreen", "18.SplitScreen\SplitScreen_vc10.vcxproj", "{1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "19.MouseAndJoystick", "19.MouseAndJoystick\MouseAndJoystick_vc10.vcxproj", "{FE853A36-E0D1-4AC5-A792-B643E70D2953}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "20.ManagedLights", "20.ManagedLights\ManagedLights_vc10.vcxproj", "{16007FE2-142B-47F8-93E1-519BA3F39E71}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "21.Quake3Explorer", "21.Quake3Explorer\Quake3Explorer_vc10.vcxproj", "{CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "22.MaterialViewer", "22.MaterialViewer\MaterialViewer_vc10.vcxproj", "{4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "23.SMeshHandling", "23.SMeshHandling\SMeshHandling_vc10.vcxproj", "{6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "24.CursorControl", "24.CursorControl\CursorControl_vc10.vcxproj", "{02B67A37-50E1-49DB-BECF-905BC029C2FE}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo", "Demo\Demo_vc10.vcxproj", "{6F076455-D955-45D4-9C68-4AD4E45F2D47}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GUIEditor", "..\tools\GUIEditor\GUI Editor_vc10.vcxproj", "{853A396E-C031-4C26-A716-5B4E176BE11D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FontTool", "..\tools\IrrFontTool\newFontTool\irrFontTool_vc10.vcxproj", "{4D53E40F-37E3-42B1-8848-F4C6F8313A17}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MeshConverter", "..\tools\MeshConverter\MeshConverter_vc10.vcxproj", "{E72B637E-4AA6-46F3-885F-AC67B4B470ED}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "26.OcclusionQuery", "26.OcclusionQuery\OcclusionQuery_vc10.vcxproj", "{5CE0E2E7-879D-4152-B61D-24E7D0707B45}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "25.XmlHandling", "25.XmlHandling\XmlHandling_vc10.vcxproj", "{8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "30.Profiling", "30.Profiling\Profiling_vc10.vcxproj", "{65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "27.PostProcessing", "27.PostProcessing\PostProcessing_vc10.vcxproj", "{2B885150-210F-4CA7-957E-2C3D75974308}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "28.CubeMapping", "28.CubeMapping\CubeMapping_vc10.vcxproj", "{9A2CE404-75E2-4195-837D-BED5B0FF3FA7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.ActiveCfg = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.Build.0 = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.ActiveCfg = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.Build.0 = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.ActiveCfg = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.Build.0 = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.ActiveCfg = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.Build.0 = Release|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Debug|Win32.ActiveCfg = Debug|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Debug|Win32.Build.0 = Debug|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Debug|x64.ActiveCfg = Debug|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Debug|x64.Build.0 = Debug|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release|Win32.ActiveCfg = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release|Win32.Build.0 = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release|x64.ActiveCfg = Release|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release|x64.Build.0 = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Debug|Win32.ActiveCfg = Debug|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Debug|Win32.Build.0 = Debug|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Debug|x64.ActiveCfg = Debug|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Debug|x64.Build.0 = Debug|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release|Win32.ActiveCfg = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release|Win32.Build.0 = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release|x64.ActiveCfg = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release|x64.Build.0 = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Debug|Win32.ActiveCfg = Debug|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Debug|Win32.Build.0 = Debug|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Debug|x64.ActiveCfg = Debug|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Debug|x64.Build.0 = Debug|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release|Win32.ActiveCfg = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release|Win32.Build.0 = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release|x64.ActiveCfg = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release|x64.Build.0 = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Debug|Win32.ActiveCfg = Debug|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Debug|Win32.Build.0 = Debug|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Debug|x64.ActiveCfg = Debug|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Debug|x64.Build.0 = Debug|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release|Win32.ActiveCfg = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release|Win32.Build.0 = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release|x64.ActiveCfg = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release|x64.Build.0 = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Debug|Win32.ActiveCfg = Debug|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Debug|Win32.Build.0 = Debug|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Debug|x64.ActiveCfg = Debug|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Debug|x64.Build.0 = Debug|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release|Win32.ActiveCfg = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release|Win32.Build.0 = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release|x64.ActiveCfg = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release|x64.Build.0 = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Debug|Win32.ActiveCfg = Debug|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Debug|Win32.Build.0 = Debug|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Debug|x64.ActiveCfg = Debug|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Debug|x64.Build.0 = Debug|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release|Win32.ActiveCfg = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release|Win32.Build.0 = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release|x64.ActiveCfg = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release|x64.Build.0 = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Debug|Win32.ActiveCfg = Debug|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Debug|Win32.Build.0 = Debug|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Debug|x64.ActiveCfg = Debug|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Debug|x64.Build.0 = Debug|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release|Win32.ActiveCfg = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release|Win32.Build.0 = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release|x64.ActiveCfg = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release|x64.Build.0 = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Debug|Win32.Build.0 = Debug|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Debug|x64.ActiveCfg = Debug|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Debug|x64.Build.0 = Debug|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release|Win32.ActiveCfg = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release|Win32.Build.0 = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release|x64.ActiveCfg = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release|x64.Build.0 = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Debug|Win32.ActiveCfg = Debug|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Debug|Win32.Build.0 = Debug|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Debug|x64.ActiveCfg = Debug|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Debug|x64.Build.0 = Debug|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release|Win32.ActiveCfg = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release|Win32.Build.0 = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release|x64.ActiveCfg = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release|x64.Build.0 = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Debug|Win32.ActiveCfg = Debug|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Debug|Win32.Build.0 = Debug|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Debug|x64.ActiveCfg = Debug|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Debug|x64.Build.0 = Debug|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release|Win32.ActiveCfg = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release|Win32.Build.0 = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release|x64.ActiveCfg = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release|x64.Build.0 = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Debug|Win32.ActiveCfg = Debug|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Debug|Win32.Build.0 = Debug|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Debug|x64.ActiveCfg = Debug|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Debug|x64.Build.0 = Debug|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release|Win32.ActiveCfg = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release|Win32.Build.0 = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release|x64.ActiveCfg = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release|x64.Build.0 = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Debug|Win32.ActiveCfg = Debug|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Debug|Win32.Build.0 = Debug|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Debug|x64.ActiveCfg = Debug|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Debug|x64.Build.0 = Debug|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release|Win32.ActiveCfg = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release|Win32.Build.0 = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release|x64.ActiveCfg = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release|x64.Build.0 = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Debug|Win32.ActiveCfg = Debug|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Debug|Win32.Build.0 = Debug|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Debug|x64.ActiveCfg = Debug|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Debug|x64.Build.0 = Debug|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release|Win32.ActiveCfg = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release|Win32.Build.0 = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release|x64.ActiveCfg = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release|x64.Build.0 = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Debug|Win32.ActiveCfg = Debug|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Debug|Win32.Build.0 = Debug|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Debug|x64.ActiveCfg = Debug|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Debug|x64.Build.0 = Debug|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release|Win32.ActiveCfg = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release|Win32.Build.0 = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release|x64.ActiveCfg = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release|x64.Build.0 = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Debug|Win32.ActiveCfg = Debug|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Debug|Win32.Build.0 = Debug|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Debug|x64.ActiveCfg = Debug|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Debug|x64.Build.0 = Debug|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release|Win32.ActiveCfg = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release|Win32.Build.0 = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release|x64.ActiveCfg = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release|x64.Build.0 = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Debug|Win32.ActiveCfg = Debug|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Debug|Win32.Build.0 = Debug|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Debug|x64.ActiveCfg = Debug|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Debug|x64.Build.0 = Debug|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release|Win32.ActiveCfg = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release|Win32.Build.0 = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release|x64.ActiveCfg = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release|x64.Build.0 = Release|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Debug|Win32.ActiveCfg = Debug|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Debug|Win32.Build.0 = Debug|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Debug|x64.ActiveCfg = Debug|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Debug|x64.Build.0 = Debug|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Release|Win32.ActiveCfg = Release|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Release|Win32.Build.0 = Release|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Release|x64.ActiveCfg = Release|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Release|x64.Build.0 = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Debug|Win32.ActiveCfg = Debug|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Debug|Win32.Build.0 = Debug|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Debug|x64.ActiveCfg = Debug|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Debug|x64.Build.0 = Debug|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release|Win32.ActiveCfg = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release|Win32.Build.0 = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release|x64.ActiveCfg = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release|x64.Build.0 = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Debug|Win32.Build.0 = Debug|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Debug|x64.ActiveCfg = Debug|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Debug|x64.Build.0 = Debug|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release|Win32.ActiveCfg = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release|Win32.Build.0 = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release|x64.ActiveCfg = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release|x64.Build.0 = Release|x64 + {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}.Debug|x64.ActiveCfg = Debug|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Debug|x64.Build.0 = Debug|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release|Win32.ActiveCfg = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release|Win32.Build.0 = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release|x64.ActiveCfg = Release|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release|x64.Build.0 = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Debug|Win32.ActiveCfg = Debug|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Debug|Win32.Build.0 = Debug|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Debug|x64.ActiveCfg = Debug|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Debug|x64.Build.0 = Debug|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release|Win32.ActiveCfg = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release|Win32.Build.0 = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release|x64.ActiveCfg = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release|x64.Build.0 = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Debug|Win32.ActiveCfg = Debug|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Debug|Win32.Build.0 = Debug|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Debug|x64.ActiveCfg = Debug|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Debug|x64.Build.0 = Debug|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release|Win32.ActiveCfg = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release|Win32.Build.0 = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release|x64.ActiveCfg = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release|x64.Build.0 = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Debug|Win32.ActiveCfg = Debug|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Debug|Win32.Build.0 = Debug|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Debug|x64.ActiveCfg = Debug|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Debug|x64.Build.0 = Debug|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release|Win32.ActiveCfg = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release|Win32.Build.0 = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release|x64.ActiveCfg = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release|x64.Build.0 = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Debug|Win32.ActiveCfg = Debug|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Debug|Win32.Build.0 = Debug|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Debug|x64.ActiveCfg = Debug|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Debug|x64.Build.0 = Debug|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release|Win32.ActiveCfg = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release|Win32.Build.0 = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release|x64.ActiveCfg = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release|x64.Build.0 = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Debug|Win32.ActiveCfg = Debug|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Debug|Win32.Build.0 = Debug|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Debug|x64.ActiveCfg = Debug|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Debug|x64.Build.0 = Debug|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release|Win32.ActiveCfg = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release|Win32.Build.0 = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release|x64.ActiveCfg = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release|x64.Build.0 = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Debug|Win32.ActiveCfg = Debug|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Debug|Win32.Build.0 = Debug|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Debug|x64.ActiveCfg = Debug|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Debug|x64.Build.0 = Debug|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release|Win32.ActiveCfg = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release|Win32.Build.0 = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release|x64.ActiveCfg = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release|x64.Build.0 = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Debug|Win32.ActiveCfg = Debug|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Debug|Win32.Build.0 = Debug|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Debug|x64.ActiveCfg = Debug|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Debug|x64.Build.0 = Debug|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release|Win32.ActiveCfg = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release|Win32.Build.0 = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release|x64.ActiveCfg = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release|x64.Build.0 = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Debug|Win32.ActiveCfg = Debug|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Debug|Win32.Build.0 = Debug|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Debug|x64.ActiveCfg = Debug|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Debug|x64.Build.0 = Debug|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release|Win32.ActiveCfg = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release|Win32.Build.0 = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release|x64.ActiveCfg = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release|x64.Build.0 = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Debug|Win32.ActiveCfg = Debug|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Debug|Win32.Build.0 = Debug|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Debug|x64.ActiveCfg = Debug|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Debug|x64.Build.0 = Debug|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release|Win32.ActiveCfg = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release|Win32.Build.0 = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release|x64.ActiveCfg = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release|x64.Build.0 = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Debug|Win32.ActiveCfg = Debug|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Debug|Win32.Build.0 = Debug|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Debug|x64.ActiveCfg = Debug|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Debug|x64.Build.0 = Debug|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release|Win32.ActiveCfg = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release|Win32.Build.0 = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release|x64.ActiveCfg = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release|x64.Build.0 = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Debug|Win32.ActiveCfg = Debug|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Debug|Win32.Build.0 = Debug|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Debug|x64.ActiveCfg = Debug|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Debug|x64.Build.0 = Debug|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|Win32.ActiveCfg = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|Win32.Build.0 = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|x64.ActiveCfg = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|x64.Build.0 = Release|x64 + {2B885150-210F-4CA7-957E-2C3D75974308}.Debug|Win32.ActiveCfg = Debug|Win32 + {2B885150-210F-4CA7-957E-2C3D75974308}.Debug|Win32.Build.0 = Debug|Win32 + {2B885150-210F-4CA7-957E-2C3D75974308}.Debug|x64.ActiveCfg = Debug|x64 + {2B885150-210F-4CA7-957E-2C3D75974308}.Debug|x64.Build.0 = Debug|x64 + {2B885150-210F-4CA7-957E-2C3D75974308}.Release|Win32.ActiveCfg = Release|Win32 + {2B885150-210F-4CA7-957E-2C3D75974308}.Release|Win32.Build.0 = Release|Win32 + {2B885150-210F-4CA7-957E-2C3D75974308}.Release|x64.ActiveCfg = Release|x64 + {2B885150-210F-4CA7-957E-2C3D75974308}.Release|x64.Build.0 = Release|x64 + {9A2CE404-75E2-4195-837D-BED5B0FF3FA7}.Debug|Win32.ActiveCfg = Debug|Win32 + {9A2CE404-75E2-4195-837D-BED5B0FF3FA7}.Debug|Win32.Build.0 = Debug|Win32 + {9A2CE404-75E2-4195-837D-BED5B0FF3FA7}.Debug|x64.ActiveCfg = Debug|x64 + {9A2CE404-75E2-4195-837D-BED5B0FF3FA7}.Debug|x64.Build.0 = Debug|x64 + {9A2CE404-75E2-4195-837D-BED5B0FF3FA7}.Release|Win32.ActiveCfg = Release|Win32 + {9A2CE404-75E2-4195-837D-BED5B0FF3FA7}.Release|Win32.Build.0 = Release|Win32 + {9A2CE404-75E2-4195-837D-BED5B0FF3FA7}.Release|x64.ActiveCfg = Release|x64 + {9A2CE404-75E2-4195-837D-BED5B0FF3FA7}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/examples/BuildAllExamples_vc11.sln b/examples/BuildAllExamples_vc11.sln new file mode 100644 index 00000000..6b5b06e2 --- /dev/null +++ b/examples/BuildAllExamples_vc11.sln @@ -0,0 +1,440 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Irrlicht", "..\source\Irrlicht\Irrlicht11.0.vcxproj", "{E08E042A-6C45-411B-92BE-3CC31331019F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "01.HelloWorld", "01.HelloWorld\HelloWorld_vc11.vcxproj", "{5AD4C95C-BA38-4692-BA4B-8C25A86208F9}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "02.Quake3Map", "02.Quake3Map\Quake3Map_vc11.vcxproj", "{D1A464A2-D479-458C-98A2-60965D823CD1}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "03.CustomSceneNode", "03.CustomSceneNode\CustomSceneNode_vc11.vcxproj", "{171CCDFA-C140-4956-8EB7-F0168F4521D3}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "04.Movement", "04.Movement\Movement_vc11.vcxproj", "{7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "05.UserInterface", "05.UserInterface\UserInterface_vc11.vcxproj", "{622C9DD7-0391-49FF-AF53-24F9D5A8EC53}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "06.2DGraphics", "06.2DGraphics\2DGraphics_vc11.vcxproj", "{E71B6F18-10DC-4101-A541-F6D33F71B2BD}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "07.Collision", "07.Collision\Collision_vc11.vcxproj", "{3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "08.SpecialFX", "08.SpecialFX\SpecialFX_vc11.vcxproj", "{C869BF55-B9D6-4980-BC92-60FA0CF8411A}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "09.Meshviewer", "09.Meshviewer\Meshviewer_vc11.vcxproj", "{2AE24484-22FC-481B-9A40-7CD0DA5C8E06}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "10.Shaders", "10.Shaders\Shaders_vc11.vcxproj", "{27158C82-CD15-4A9B-9848-35E7065B209F}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "11.PerPixelLighting", "11.PerPixelLighting\PerPixelLighting_vc11.vcxproj", "{C4B42409-542D-4EFC-9E6B-44713FD47A33}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "12.TerrainRendering", "12.TerrainRendering\TerrainRendering_vc11.vcxproj", "{3A5B74E5-6390-43B0-A459-2793B81FFD31}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "13.RenderToTexture", "13.RenderToTexture\RenderToTexture_vc11.vcxproj", "{0914E5C8-5352-467B-8421-C9EB35BD5596}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "14.Win32Window", "14.Win32Window\Win32Window_vc11.vcxproj", "{772FBE05-D05A-467B-9842-BEC409EEA8D0}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "15.LoadIrrFile", "15.LoadIrrFile\LoadIrrFile_vc11.vcxproj", "{78C9F424-523C-49AC-94B7-823AA4A26BF9}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "16.Quake3MapShader", "16.Quake3MapShader\Quake3MapShader_vc11.vcxproj", "{EB3B38EA-5CE7-4983-845B-880661E69D09}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "17.HelloWorld_Mobile", "17.HelloWorld_Mobile\17. HelloWorld for Windows Mobile on PC_vc11.vcxproj", "{2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "18.SplitScreen", "18.SplitScreen\SplitScreen_vc11.vcxproj", "{1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "19.MouseAndJoystick", "19.MouseAndJoystick\MouseAndJoystick_vc11.vcxproj", "{FE853A36-E0D1-4AC5-A792-B643E70D2953}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "20.ManagedLights", "20.ManagedLights\ManagedLights_vc11.vcxproj", "{16007FE2-142B-47F8-93E1-519BA3F39E71}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "21.Quake3Explorer", "21.Quake3Explorer\Quake3Explorer_vc11.vcxproj", "{CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "22.MaterialViewer", "22.MaterialViewer\MaterialViewer_vc11.vcxproj", "{4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "23.SMeshHandling", "23.SMeshHandling\SMeshHandling_vc11.vcxproj", "{6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "24.CursorControl", "24.CursorControl\CursorControl_vc11.vcxproj", "{02B67A37-50E1-49DB-BECF-905BC029C2FE}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo", "Demo\Demo_vc11.vcxproj", "{6F076455-D955-45D4-9C68-4AD4E45F2D47}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GUIEditor", "..\tools\GUIEditor\GUI Editor_vc11.vcxproj", "{853A396E-C031-4C26-A716-5B4E176BE11D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FontTool", "..\tools\IrrFontTool\newFontTool\irrFontTool_vc11.vcxproj", "{4D53E40F-37E3-42B1-8848-F4C6F8313A17}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MeshConverter", "..\tools\MeshConverter\MeshConverter_vc11.vcxproj", "{E72B637E-4AA6-46F3-885F-AC67B4B470ED}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "26.OcclusionQuery", "26.OcclusionQuery\OcclusionQuery_vc11.vcxproj", "{5CE0E2E7-879D-4152-B61D-24E7D0707B45}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "25.XmlHandling", "25.XmlHandling\XmlHandling_vc11.vcxproj", "{8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "30.Profiling", "30.Profiling\Profiling_vc11.vcxproj", "{65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "27.PostProcessing", "27.PostProcessing\PostProcessing_vc11.vcxproj", "{F864F96D-F6AE-43E2-9A12-218B1A081255}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "28.CubeMapping", "28.CubeMapping\CubeMapping_vc11.vcxproj", "{3DAD16DC-3D80-46EA-ADD8-C4418CEDE553}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.ActiveCfg = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.Build.0 = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.ActiveCfg = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.Build.0 = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.ActiveCfg = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.Build.0 = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.ActiveCfg = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.Build.0 = Release|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Debug|Win32.ActiveCfg = Debug|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Debug|Win32.Build.0 = Debug|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Debug|x64.ActiveCfg = Debug|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Debug|x64.Build.0 = Debug|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release|Win32.ActiveCfg = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release|Win32.Build.0 = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release|x64.ActiveCfg = Release|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release|x64.Build.0 = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Debug|Win32.ActiveCfg = Debug|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Debug|Win32.Build.0 = Debug|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Debug|x64.ActiveCfg = Debug|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Debug|x64.Build.0 = Debug|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release|Win32.ActiveCfg = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release|Win32.Build.0 = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release|x64.ActiveCfg = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release|x64.Build.0 = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Debug|Win32.ActiveCfg = Debug|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Debug|Win32.Build.0 = Debug|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Debug|x64.ActiveCfg = Debug|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Debug|x64.Build.0 = Debug|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release|Win32.ActiveCfg = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release|Win32.Build.0 = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release|x64.ActiveCfg = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release|x64.Build.0 = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Debug|Win32.ActiveCfg = Debug|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Debug|Win32.Build.0 = Debug|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Debug|x64.ActiveCfg = Debug|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Debug|x64.Build.0 = Debug|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release|Win32.ActiveCfg = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release|Win32.Build.0 = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release|x64.ActiveCfg = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release|x64.Build.0 = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Debug|Win32.ActiveCfg = Debug|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Debug|Win32.Build.0 = Debug|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Debug|x64.ActiveCfg = Debug|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Debug|x64.Build.0 = Debug|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release|Win32.ActiveCfg = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release|Win32.Build.0 = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release|x64.ActiveCfg = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release|x64.Build.0 = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Debug|Win32.ActiveCfg = Debug|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Debug|Win32.Build.0 = Debug|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Debug|x64.ActiveCfg = Debug|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Debug|x64.Build.0 = Debug|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release|Win32.ActiveCfg = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release|Win32.Build.0 = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release|x64.ActiveCfg = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release|x64.Build.0 = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Debug|Win32.ActiveCfg = Debug|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Debug|Win32.Build.0 = Debug|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Debug|x64.ActiveCfg = Debug|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Debug|x64.Build.0 = Debug|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release|Win32.ActiveCfg = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release|Win32.Build.0 = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release|x64.ActiveCfg = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release|x64.Build.0 = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Debug|Win32.Build.0 = Debug|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Debug|x64.ActiveCfg = Debug|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Debug|x64.Build.0 = Debug|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release|Win32.ActiveCfg = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release|Win32.Build.0 = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release|x64.ActiveCfg = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release|x64.Build.0 = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Debug|Win32.ActiveCfg = Debug|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Debug|Win32.Build.0 = Debug|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Debug|x64.ActiveCfg = Debug|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Debug|x64.Build.0 = Debug|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release|Win32.ActiveCfg = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release|Win32.Build.0 = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release|x64.ActiveCfg = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release|x64.Build.0 = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Debug|Win32.ActiveCfg = Debug|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Debug|Win32.Build.0 = Debug|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Debug|x64.ActiveCfg = Debug|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Debug|x64.Build.0 = Debug|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release|Win32.ActiveCfg = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release|Win32.Build.0 = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release|x64.ActiveCfg = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release|x64.Build.0 = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Debug|Win32.ActiveCfg = Debug|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Debug|Win32.Build.0 = Debug|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Debug|x64.ActiveCfg = Debug|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Debug|x64.Build.0 = Debug|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release|Win32.ActiveCfg = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release|Win32.Build.0 = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release|x64.ActiveCfg = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release|x64.Build.0 = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Debug|Win32.ActiveCfg = Debug|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Debug|Win32.Build.0 = Debug|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Debug|x64.ActiveCfg = Debug|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Debug|x64.Build.0 = Debug|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release|Win32.ActiveCfg = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release|Win32.Build.0 = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release|x64.ActiveCfg = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release|x64.Build.0 = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Debug|Win32.ActiveCfg = Debug|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Debug|Win32.Build.0 = Debug|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Debug|x64.ActiveCfg = Debug|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Debug|x64.Build.0 = Debug|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release|Win32.ActiveCfg = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release|Win32.Build.0 = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release|x64.ActiveCfg = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release|x64.Build.0 = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Debug|Win32.ActiveCfg = Debug|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Debug|Win32.Build.0 = Debug|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Debug|x64.ActiveCfg = Debug|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Debug|x64.Build.0 = Debug|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release|Win32.ActiveCfg = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release|Win32.Build.0 = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release|x64.ActiveCfg = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release|x64.Build.0 = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Debug|Win32.ActiveCfg = Debug|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Debug|Win32.Build.0 = Debug|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Debug|x64.ActiveCfg = Debug|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Debug|x64.Build.0 = Debug|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release|Win32.ActiveCfg = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release|Win32.Build.0 = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release|x64.ActiveCfg = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release|x64.Build.0 = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Debug|Win32.ActiveCfg = Debug|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Debug|Win32.Build.0 = Debug|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Debug|x64.ActiveCfg = Debug|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Debug|x64.Build.0 = Debug|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release|Win32.ActiveCfg = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release|Win32.Build.0 = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release|x64.ActiveCfg = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release|x64.Build.0 = Release|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Debug|Win32.ActiveCfg = Debug|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Debug|Win32.Build.0 = Debug|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Debug|x64.ActiveCfg = Debug|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Debug|x64.Build.0 = Debug|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Release|Win32.ActiveCfg = Release|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Release|Win32.Build.0 = Release|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Release|x64.ActiveCfg = Release|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Release|x64.Build.0 = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Debug|Win32.ActiveCfg = Debug|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Debug|Win32.Build.0 = Debug|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Debug|x64.ActiveCfg = Debug|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Debug|x64.Build.0 = Debug|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release|Win32.ActiveCfg = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release|Win32.Build.0 = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release|x64.ActiveCfg = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release|x64.Build.0 = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Debug|Win32.Build.0 = Debug|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Debug|x64.ActiveCfg = Debug|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Debug|x64.Build.0 = Debug|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release|Win32.ActiveCfg = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release|Win32.Build.0 = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release|x64.ActiveCfg = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release|x64.Build.0 = Release|x64 + {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}.Debug|x64.ActiveCfg = Debug|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Debug|x64.Build.0 = Debug|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release|Win32.ActiveCfg = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release|Win32.Build.0 = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release|x64.ActiveCfg = Release|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release|x64.Build.0 = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Debug|Win32.ActiveCfg = Debug|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Debug|Win32.Build.0 = Debug|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Debug|x64.ActiveCfg = Debug|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Debug|x64.Build.0 = Debug|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release|Win32.ActiveCfg = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release|Win32.Build.0 = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release|x64.ActiveCfg = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release|x64.Build.0 = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Debug|Win32.ActiveCfg = Debug|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Debug|Win32.Build.0 = Debug|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Debug|x64.ActiveCfg = Debug|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Debug|x64.Build.0 = Debug|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release|Win32.ActiveCfg = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release|Win32.Build.0 = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release|x64.ActiveCfg = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release|x64.Build.0 = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Debug|Win32.ActiveCfg = Debug|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Debug|Win32.Build.0 = Debug|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Debug|x64.ActiveCfg = Debug|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Debug|x64.Build.0 = Debug|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release|Win32.ActiveCfg = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release|Win32.Build.0 = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release|x64.ActiveCfg = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release|x64.Build.0 = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Debug|Win32.ActiveCfg = Debug|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Debug|Win32.Build.0 = Debug|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Debug|x64.ActiveCfg = Debug|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Debug|x64.Build.0 = Debug|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release|Win32.ActiveCfg = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release|Win32.Build.0 = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release|x64.ActiveCfg = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release|x64.Build.0 = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Debug|Win32.ActiveCfg = Debug|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Debug|Win32.Build.0 = Debug|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Debug|x64.ActiveCfg = Debug|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Debug|x64.Build.0 = Debug|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release|Win32.ActiveCfg = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release|Win32.Build.0 = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release|x64.ActiveCfg = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release|x64.Build.0 = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Debug|Win32.ActiveCfg = Debug|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Debug|Win32.Build.0 = Debug|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Debug|x64.ActiveCfg = Debug|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Debug|x64.Build.0 = Debug|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release|Win32.ActiveCfg = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release|Win32.Build.0 = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release|x64.ActiveCfg = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release|x64.Build.0 = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Debug|Win32.ActiveCfg = Debug|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Debug|Win32.Build.0 = Debug|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Debug|x64.ActiveCfg = Debug|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Debug|x64.Build.0 = Debug|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release|Win32.ActiveCfg = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release|Win32.Build.0 = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release|x64.ActiveCfg = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release|x64.Build.0 = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Debug|Win32.ActiveCfg = Debug|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Debug|Win32.Build.0 = Debug|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Debug|x64.ActiveCfg = Debug|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Debug|x64.Build.0 = Debug|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release|Win32.ActiveCfg = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release|Win32.Build.0 = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release|x64.ActiveCfg = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release|x64.Build.0 = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Debug|Win32.ActiveCfg = Debug|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Debug|Win32.Build.0 = Debug|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Debug|x64.ActiveCfg = Debug|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Debug|x64.Build.0 = Debug|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release|Win32.ActiveCfg = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release|Win32.Build.0 = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release|x64.ActiveCfg = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release|x64.Build.0 = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Debug|Win32.ActiveCfg = Debug|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Debug|Win32.Build.0 = Debug|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Debug|x64.ActiveCfg = Debug|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Debug|x64.Build.0 = Debug|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release|Win32.ActiveCfg = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release|Win32.Build.0 = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release|x64.ActiveCfg = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release|x64.Build.0 = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Debug|Win32.ActiveCfg = Debug|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Debug|Win32.Build.0 = Debug|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Debug|x64.ActiveCfg = Debug|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Debug|x64.Build.0 = Debug|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|Win32.ActiveCfg = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|Win32.Build.0 = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|x64.ActiveCfg = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|x64.Build.0 = Release|x64 + {F864F96D-F6AE-43E2-9A12-218B1A081255}.Debug|Win32.ActiveCfg = Debug|Win32 + {F864F96D-F6AE-43E2-9A12-218B1A081255}.Debug|Win32.Build.0 = Debug|Win32 + {F864F96D-F6AE-43E2-9A12-218B1A081255}.Debug|x64.ActiveCfg = Debug|x64 + {F864F96D-F6AE-43E2-9A12-218B1A081255}.Debug|x64.Build.0 = Debug|x64 + {F864F96D-F6AE-43E2-9A12-218B1A081255}.Release|Win32.ActiveCfg = Release|Win32 + {F864F96D-F6AE-43E2-9A12-218B1A081255}.Release|Win32.Build.0 = Release|Win32 + {F864F96D-F6AE-43E2-9A12-218B1A081255}.Release|x64.ActiveCfg = Release|x64 + {F864F96D-F6AE-43E2-9A12-218B1A081255}.Release|x64.Build.0 = Release|x64 + {3DAD16DC-3D80-46EA-ADD8-C4418CEDE553}.Debug|Win32.ActiveCfg = Debug|Win32 + {3DAD16DC-3D80-46EA-ADD8-C4418CEDE553}.Debug|Win32.Build.0 = Debug|Win32 + {3DAD16DC-3D80-46EA-ADD8-C4418CEDE553}.Debug|x64.ActiveCfg = Debug|x64 + {3DAD16DC-3D80-46EA-ADD8-C4418CEDE553}.Debug|x64.Build.0 = Debug|x64 + {3DAD16DC-3D80-46EA-ADD8-C4418CEDE553}.Release|Win32.ActiveCfg = Release|Win32 + {3DAD16DC-3D80-46EA-ADD8-C4418CEDE553}.Release|Win32.Build.0 = Release|Win32 + {3DAD16DC-3D80-46EA-ADD8-C4418CEDE553}.Release|x64.ActiveCfg = Release|x64 + {3DAD16DC-3D80-46EA-ADD8-C4418CEDE553}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/examples/BuildAllExamples_vc12.sln b/examples/BuildAllExamples_vc12.sln new file mode 100644 index 00000000..a6786e25 --- /dev/null +++ b/examples/BuildAllExamples_vc12.sln @@ -0,0 +1,1132 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.40629.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "01.HelloWorld", "01.HelloWorld\HelloWorld_vc12.vcxproj", "{5AD4C95C-BA38-4692-BA4B-8C25A86208F9}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "02.Quake3Map", "02.Quake3Map\Quake3Map_vc12.vcxproj", "{D1A464A2-D479-458C-98A2-60965D823CD1}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "03.CustomSceneNode", "03.CustomSceneNode\CustomSceneNode_vc12.vcxproj", "{171CCDFA-C140-4956-8EB7-F0168F4521D3}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "04.Movement", "04.Movement\Movement_vc12.vcxproj", "{7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "05.UserInterface", "05.UserInterface\UserInterface_vc12.vcxproj", "{622C9DD7-0391-49FF-AF53-24F9D5A8EC53}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "06.2DGraphics", "06.2DGraphics\2DGraphics_vc12.vcxproj", "{E71B6F18-10DC-4101-A541-F6D33F71B2BD}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "07.Collision", "07.Collision\Collision_vc12.vcxproj", "{3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "08.SpecialFX", "08.SpecialFX\SpecialFX_vc12.vcxproj", "{C869BF55-B9D6-4980-BC92-60FA0CF8411A}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "09.Meshviewer", "09.Meshviewer\Meshviewer_vc12.vcxproj", "{2AE24484-22FC-481B-9A40-7CD0DA5C8E06}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "10.Shaders", "10.Shaders\Shaders_vc12.vcxproj", "{27158C82-CD15-4A9B-9848-35E7065B209F}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "11.PerPixelLighting", "11.PerPixelLighting\PerPixelLighting_vc12.vcxproj", "{C4B42409-542D-4EFC-9E6B-44713FD47A33}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "12.TerrainRendering", "12.TerrainRendering\TerrainRendering_vc12.vcxproj", "{3A5B74E5-6390-43B0-A459-2793B81FFD31}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "13.RenderToTexture", "13.RenderToTexture\RenderToTexture_vc12.vcxproj", "{0914E5C8-5352-467B-8421-C9EB35BD5596}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "14.Win32Window", "14.Win32Window\Win32Window_vc12.vcxproj", "{772FBE05-D05A-467B-9842-BEC409EEA8D0}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "15.LoadIrrFile", "15.LoadIrrFile\LoadIrrFile_vc12.vcxproj", "{78C9F424-523C-49AC-94B7-823AA4A26BF9}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "16.Quake3MapShader", "16.Quake3MapShader\Quake3MapShader_vc12.vcxproj", "{EB3B38EA-5CE7-4983-845B-880661E69D09}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "17.HelloWorld_Mobile", "17.HelloWorld_Mobile\17. HelloWorld for Windows Mobile on PC_vc12.vcxproj", "{2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "18.SplitScreen", "18.SplitScreen\SplitScreen_vc12.vcxproj", "{1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "19.MouseAndJoystick", "19.MouseAndJoystick\MouseAndJoystick_vc12.vcxproj", "{FE853A36-E0D1-4AC5-A792-B643E70D2953}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "20.ManagedLights", "20.ManagedLights\ManagedLights_vc12.vcxproj", "{16007FE2-142B-47F8-93E1-519BA3F39E71}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "21.Quake3Explorer", "21.Quake3Explorer\Quake3Explorer_vc12.vcxproj", "{CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "22.MaterialViewer", "22.MaterialViewer\MaterialViewer_vc12.vcxproj", "{4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "23.SMeshHandling", "23.SMeshHandling\SMeshHandling_vc12.vcxproj", "{6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "24.CursorControl", "24.CursorControl\CursorControl_vc12.vcxproj", "{02B67A37-50E1-49DB-BECF-905BC029C2FE}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "25.XmlHandling", "25.XmlHandling\XmlHandling_vc12.vcxproj", "{8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "26.OcclusionQuery", "26.OcclusionQuery\OcclusionQuery_vc12.vcxproj", "{5CE0E2E7-879D-4152-B61D-24E7D0707B45}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "30.Profiling", "30.Profiling\Profiling_vc12.vcxproj", "{65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GUIEditor", "..\tools\GUIEditor\GUI Editor_vc12.vcxproj", "{853A396E-C031-4C26-A716-5B4E176BE11D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FontTool", "..\tools\IrrFontTool\newFontTool\irrFontTool_vc12.vcxproj", "{4D53E40F-37E3-42B1-8848-F4C6F8313A17}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MeshConverter", "..\tools\MeshConverter\MeshConverter_vc12.vcxproj", "{E72B637E-4AA6-46F3-885F-AC67B4B470ED}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo", "Demo\Demo_vc12.vcxproj", "{6F076455-D955-45D4-9C68-4AD4E45F2D47}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Irrlicht", "..\source\Irrlicht\Irrlicht12.0.vcxproj", "{E08E042A-6C45-411B-92BE-3CC31331019F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "27.PostProcessing", "27.PostProcessing\PostProcessing_vc12.vcxproj", "{17E74625-568E-4008-897E-CAD12A332B0C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "28.CubeMapping", "28.CubeMapping\CubeMapping_vc12.vcxproj", "{1FDD5E75-9EB3-4467-B672-0BFC105B84A5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release - Fast FPU|Win32 = Release - Fast FPU|Win32 + Release - Fast FPU|x64 = Release - Fast FPU|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + SDL-Debug|Win32 = SDL-Debug|Win32 + SDL-Debug|x64 = SDL-Debug|x64 + Static lib - Debug|Win32 = Static lib - Debug|Win32 + Static lib - Debug|x64 = Static lib - Debug|x64 + Static lib - Release - Fast FPU|Win32 = Static lib - Release - Fast FPU|Win32 + Static lib - Release - Fast FPU|x64 = Static lib - Release - Fast FPU|x64 + Static lib - Release|Win32 = Static lib - Release|Win32 + Static lib - Release|x64 = Static lib - Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Debug|Win32.ActiveCfg = Debug|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Debug|Win32.Build.0 = Debug|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Debug|x64.ActiveCfg = Debug|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Debug|x64.Build.0 = Debug|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release - Fast FPU|x64.Build.0 = Release|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release|Win32.ActiveCfg = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release|Win32.Build.0 = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release|x64.ActiveCfg = Release|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release|x64.Build.0 = Release|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.SDL-Debug|x64.Build.0 = Debug|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Debug|x64.Build.0 = Debug|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Release|Win32.Build.0 = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Release|x64.ActiveCfg = Release|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Release|x64.Build.0 = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Debug|Win32.ActiveCfg = Debug|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Debug|Win32.Build.0 = Debug|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Debug|x64.ActiveCfg = Debug|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Debug|x64.Build.0 = Debug|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release - Fast FPU|x64.Build.0 = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release|Win32.ActiveCfg = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release|Win32.Build.0 = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release|x64.ActiveCfg = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release|x64.Build.0 = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.SDL-Debug|x64.Build.0 = Debug|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Debug|x64.Build.0 = Debug|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Release|Win32.Build.0 = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Release|x64.ActiveCfg = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Release|x64.Build.0 = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Debug|Win32.ActiveCfg = Debug|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Debug|Win32.Build.0 = Debug|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Debug|x64.ActiveCfg = Debug|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Debug|x64.Build.0 = Debug|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release - Fast FPU|x64.Build.0 = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release|Win32.ActiveCfg = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release|Win32.Build.0 = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release|x64.ActiveCfg = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release|x64.Build.0 = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.SDL-Debug|x64.Build.0 = Debug|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Debug|x64.Build.0 = Debug|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Release|Win32.Build.0 = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Release|x64.ActiveCfg = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Release|x64.Build.0 = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Debug|Win32.ActiveCfg = Debug|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Debug|Win32.Build.0 = Debug|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Debug|x64.ActiveCfg = Debug|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Debug|x64.Build.0 = Debug|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release - Fast FPU|x64.Build.0 = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release|Win32.ActiveCfg = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release|Win32.Build.0 = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release|x64.ActiveCfg = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release|x64.Build.0 = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.SDL-Debug|x64.Build.0 = Debug|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Debug|x64.Build.0 = Debug|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Release|Win32.Build.0 = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Release|x64.ActiveCfg = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Release|x64.Build.0 = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Debug|Win32.ActiveCfg = Debug|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Debug|Win32.Build.0 = Debug|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Debug|x64.ActiveCfg = Debug|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Debug|x64.Build.0 = Debug|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release - Fast FPU|x64.Build.0 = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release|Win32.ActiveCfg = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release|Win32.Build.0 = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release|x64.ActiveCfg = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release|x64.Build.0 = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.SDL-Debug|x64.Build.0 = Debug|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Debug|x64.Build.0 = Debug|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Release|Win32.Build.0 = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Release|x64.ActiveCfg = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Release|x64.Build.0 = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Debug|Win32.ActiveCfg = Debug|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Debug|Win32.Build.0 = Debug|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Debug|x64.ActiveCfg = Debug|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Debug|x64.Build.0 = Debug|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release - Fast FPU|x64.Build.0 = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release|Win32.ActiveCfg = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release|Win32.Build.0 = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release|x64.ActiveCfg = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release|x64.Build.0 = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.SDL-Debug|x64.Build.0 = Debug|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Debug|x64.Build.0 = Debug|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Release|Win32.Build.0 = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Release|x64.ActiveCfg = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Release|x64.Build.0 = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Debug|Win32.ActiveCfg = Debug|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Debug|Win32.Build.0 = Debug|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Debug|x64.ActiveCfg = Debug|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Debug|x64.Build.0 = Debug|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release - Fast FPU|x64.Build.0 = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release|Win32.ActiveCfg = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release|Win32.Build.0 = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release|x64.ActiveCfg = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release|x64.Build.0 = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.SDL-Debug|x64.Build.0 = Debug|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Debug|x64.Build.0 = Debug|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Release|Win32.Build.0 = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Release|x64.ActiveCfg = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Release|x64.Build.0 = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Debug|Win32.Build.0 = Debug|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Debug|x64.ActiveCfg = Debug|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Debug|x64.Build.0 = Debug|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release - Fast FPU|x64.Build.0 = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release|Win32.ActiveCfg = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release|Win32.Build.0 = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release|x64.ActiveCfg = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release|x64.Build.0 = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.SDL-Debug|x64.Build.0 = Debug|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Debug|x64.Build.0 = Debug|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Release|Win32.Build.0 = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Release|x64.ActiveCfg = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Release|x64.Build.0 = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Debug|Win32.ActiveCfg = Debug|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Debug|Win32.Build.0 = Debug|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Debug|x64.ActiveCfg = Debug|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Debug|x64.Build.0 = Debug|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release - Fast FPU|x64.Build.0 = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release|Win32.ActiveCfg = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release|Win32.Build.0 = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release|x64.ActiveCfg = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release|x64.Build.0 = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.SDL-Debug|x64.Build.0 = Debug|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Debug|x64.Build.0 = Debug|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Release|Win32.Build.0 = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Release|x64.ActiveCfg = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Release|x64.Build.0 = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Debug|Win32.ActiveCfg = Debug|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Debug|Win32.Build.0 = Debug|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Debug|x64.ActiveCfg = Debug|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Debug|x64.Build.0 = Debug|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release - Fast FPU|x64.Build.0 = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release|Win32.ActiveCfg = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release|Win32.Build.0 = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release|x64.ActiveCfg = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release|x64.Build.0 = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.SDL-Debug|x64.Build.0 = Debug|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Debug|x64.Build.0 = Debug|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Release|Win32.Build.0 = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Release|x64.ActiveCfg = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Release|x64.Build.0 = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Debug|Win32.ActiveCfg = Debug|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Debug|Win32.Build.0 = Debug|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Debug|x64.ActiveCfg = Debug|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Debug|x64.Build.0 = Debug|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release - Fast FPU|x64.Build.0 = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release|Win32.ActiveCfg = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release|Win32.Build.0 = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release|x64.ActiveCfg = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release|x64.Build.0 = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.SDL-Debug|x64.Build.0 = Debug|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Debug|x64.Build.0 = Debug|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Release|Win32.Build.0 = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Release|x64.ActiveCfg = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Release|x64.Build.0 = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Debug|Win32.ActiveCfg = Debug|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Debug|Win32.Build.0 = Debug|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Debug|x64.ActiveCfg = Debug|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Debug|x64.Build.0 = Debug|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release - Fast FPU|x64.Build.0 = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release|Win32.ActiveCfg = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release|Win32.Build.0 = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release|x64.ActiveCfg = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release|x64.Build.0 = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.SDL-Debug|x64.Build.0 = Debug|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Debug|x64.Build.0 = Debug|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Release|Win32.Build.0 = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Release|x64.ActiveCfg = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Release|x64.Build.0 = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Debug|Win32.ActiveCfg = Debug|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Debug|Win32.Build.0 = Debug|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Debug|x64.ActiveCfg = Debug|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Debug|x64.Build.0 = Debug|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release - Fast FPU|x64.Build.0 = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release|Win32.ActiveCfg = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release|Win32.Build.0 = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release|x64.ActiveCfg = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release|x64.Build.0 = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.SDL-Debug|x64.Build.0 = Debug|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Debug|x64.Build.0 = Debug|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Release|Win32.Build.0 = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Release|x64.ActiveCfg = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Release|x64.Build.0 = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Debug|Win32.ActiveCfg = Debug|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Debug|Win32.Build.0 = Debug|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Debug|x64.ActiveCfg = Debug|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Debug|x64.Build.0 = Debug|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release - Fast FPU|x64.Build.0 = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release|Win32.ActiveCfg = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release|Win32.Build.0 = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release|x64.ActiveCfg = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release|x64.Build.0 = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.SDL-Debug|x64.Build.0 = Debug|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Debug|x64.Build.0 = Debug|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Release|Win32.Build.0 = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Release|x64.ActiveCfg = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Release|x64.Build.0 = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Debug|Win32.ActiveCfg = Debug|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Debug|Win32.Build.0 = Debug|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Debug|x64.ActiveCfg = Debug|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Debug|x64.Build.0 = Debug|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release - Fast FPU|x64.Build.0 = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release|Win32.ActiveCfg = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release|Win32.Build.0 = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release|x64.ActiveCfg = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release|x64.Build.0 = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.SDL-Debug|x64.Build.0 = Debug|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Debug|x64.Build.0 = Debug|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Release|Win32.Build.0 = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Release|x64.ActiveCfg = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Release|x64.Build.0 = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Debug|Win32.ActiveCfg = Debug|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Debug|Win32.Build.0 = Debug|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Debug|x64.ActiveCfg = Debug|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Debug|x64.Build.0 = Debug|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release - Fast FPU|x64.Build.0 = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release|Win32.ActiveCfg = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release|Win32.Build.0 = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release|x64.ActiveCfg = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release|x64.Build.0 = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.SDL-Debug|x64.Build.0 = Debug|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Debug|x64.Build.0 = Debug|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Release|Win32.Build.0 = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Release|x64.ActiveCfg = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Release|x64.Build.0 = Release|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Debug|Win32.ActiveCfg = Debug|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Debug|Win32.Build.0 = Debug|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Debug|x64.ActiveCfg = Debug|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Debug|x64.Build.0 = Debug|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Release - Fast FPU|x64.Build.0 = Release|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Release|Win32.ActiveCfg = Release|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Release|Win32.Build.0 = Release|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Release|x64.ActiveCfg = Release|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Release|x64.Build.0 = Release|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.SDL-Debug|x64.Build.0 = Debug|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Static lib - Debug|x64.Build.0 = Debug|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Static lib - Release|Win32.Build.0 = Release|Win32 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Static lib - Release|x64.ActiveCfg = Release|x64 + {2A29B6B1-AFC4-46C7-9944-7052AAE66F7B}.Static lib - Release|x64.Build.0 = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Debug|Win32.ActiveCfg = Debug|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Debug|Win32.Build.0 = Debug|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Debug|x64.ActiveCfg = Debug|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Debug|x64.Build.0 = Debug|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release - Fast FPU|x64.Build.0 = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release|Win32.ActiveCfg = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release|Win32.Build.0 = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release|x64.ActiveCfg = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release|x64.Build.0 = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.SDL-Debug|x64.Build.0 = Debug|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Debug|x64.Build.0 = Debug|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Release|Win32.Build.0 = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Release|x64.ActiveCfg = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Release|x64.Build.0 = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Debug|Win32.Build.0 = Debug|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Debug|x64.ActiveCfg = Debug|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Debug|x64.Build.0 = Debug|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release - Fast FPU|x64.Build.0 = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release|Win32.ActiveCfg = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release|Win32.Build.0 = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release|x64.ActiveCfg = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release|x64.Build.0 = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.SDL-Debug|x64.Build.0 = Debug|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Debug|x64.Build.0 = Debug|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Release|Win32.Build.0 = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Release|x64.ActiveCfg = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Release|x64.Build.0 = Release|x64 + {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}.Debug|x64.ActiveCfg = Debug|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Debug|x64.Build.0 = Debug|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release - Fast FPU|x64.Build.0 = Release|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release|Win32.ActiveCfg = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release|Win32.Build.0 = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release|x64.ActiveCfg = Release|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release|x64.Build.0 = Release|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.SDL-Debug|x64.Build.0 = Debug|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Debug|x64.Build.0 = Debug|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Release|Win32.Build.0 = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Release|x64.ActiveCfg = Release|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Release|x64.Build.0 = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Debug|Win32.ActiveCfg = Debug|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Debug|Win32.Build.0 = Debug|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Debug|x64.ActiveCfg = Debug|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Debug|x64.Build.0 = Debug|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release - Fast FPU|x64.Build.0 = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release|Win32.ActiveCfg = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release|Win32.Build.0 = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release|x64.ActiveCfg = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release|x64.Build.0 = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.SDL-Debug|x64.Build.0 = Debug|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Debug|x64.Build.0 = Debug|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Release|Win32.Build.0 = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Release|x64.ActiveCfg = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Release|x64.Build.0 = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Debug|Win32.ActiveCfg = Debug|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Debug|Win32.Build.0 = Debug|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Debug|x64.ActiveCfg = Debug|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Debug|x64.Build.0 = Debug|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release - Fast FPU|x64.Build.0 = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release|Win32.ActiveCfg = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release|Win32.Build.0 = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release|x64.ActiveCfg = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release|x64.Build.0 = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.SDL-Debug|x64.Build.0 = Debug|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Debug|x64.Build.0 = Debug|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Release|Win32.Build.0 = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Release|x64.ActiveCfg = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Release|x64.Build.0 = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Debug|Win32.ActiveCfg = Debug|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Debug|Win32.Build.0 = Debug|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Debug|x64.ActiveCfg = Debug|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Debug|x64.Build.0 = Debug|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release - Fast FPU|x64.Build.0 = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release|Win32.ActiveCfg = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release|Win32.Build.0 = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release|x64.ActiveCfg = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release|x64.Build.0 = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.SDL-Debug|x64.Build.0 = Debug|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Debug|x64.Build.0 = Debug|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Release|Win32.Build.0 = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Release|x64.ActiveCfg = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Release|x64.Build.0 = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Debug|Win32.ActiveCfg = Debug|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Debug|Win32.Build.0 = Debug|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Debug|x64.ActiveCfg = Debug|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Debug|x64.Build.0 = Debug|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release - Fast FPU|x64.Build.0 = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release|Win32.ActiveCfg = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release|Win32.Build.0 = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release|x64.ActiveCfg = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release|x64.Build.0 = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.SDL-Debug|x64.Build.0 = Debug|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Debug|x64.Build.0 = Debug|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Release|Win32.Build.0 = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Release|x64.ActiveCfg = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Release|x64.Build.0 = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Debug|Win32.ActiveCfg = Debug|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Debug|Win32.Build.0 = Debug|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Debug|x64.ActiveCfg = Debug|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Debug|x64.Build.0 = Debug|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release - Fast FPU|x64.Build.0 = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release|Win32.ActiveCfg = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release|Win32.Build.0 = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release|x64.ActiveCfg = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release|x64.Build.0 = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.SDL-Debug|x64.Build.0 = Debug|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Debug|x64.Build.0 = Debug|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Release|Win32.Build.0 = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Release|x64.ActiveCfg = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Release|x64.Build.0 = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Debug|Win32.ActiveCfg = Debug|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Debug|Win32.Build.0 = Debug|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Debug|x64.ActiveCfg = Debug|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Debug|x64.Build.0 = Debug|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release - Fast FPU|x64.Build.0 = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release|Win32.ActiveCfg = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release|Win32.Build.0 = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release|x64.ActiveCfg = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release|x64.Build.0 = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.SDL-Debug|x64.Build.0 = Debug|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Debug|x64.Build.0 = Debug|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Release|Win32.Build.0 = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Release|x64.ActiveCfg = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Release|x64.Build.0 = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Debug|Win32.ActiveCfg = Debug|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Debug|Win32.Build.0 = Debug|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Debug|x64.ActiveCfg = Debug|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Debug|x64.Build.0 = Debug|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release - Fast FPU|x64.Build.0 = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|Win32.ActiveCfg = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|Win32.Build.0 = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|x64.ActiveCfg = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|x64.Build.0 = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.SDL-Debug|x64.Build.0 = Debug|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Debug|x64.Build.0 = Debug|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Release|Win32.Build.0 = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Release|x64.ActiveCfg = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Release|x64.Build.0 = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Debug|Win32.ActiveCfg = Debug|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Debug|Win32.Build.0 = Debug|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Debug|x64.ActiveCfg = Debug|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Debug|x64.Build.0 = Debug|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release - Fast FPU|x64.Build.0 = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release|Win32.ActiveCfg = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release|Win32.Build.0 = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release|x64.ActiveCfg = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release|x64.Build.0 = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.SDL-Debug|x64.Build.0 = Debug|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Debug|x64.Build.0 = Debug|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Release|Win32.Build.0 = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Release|x64.ActiveCfg = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Release|x64.Build.0 = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Debug|Win32.ActiveCfg = Debug|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Debug|Win32.Build.0 = Debug|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Debug|x64.ActiveCfg = Debug|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Debug|x64.Build.0 = Debug|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release - Fast FPU|x64.Build.0 = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release|Win32.ActiveCfg = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release|Win32.Build.0 = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release|x64.ActiveCfg = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release|x64.Build.0 = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.SDL-Debug|x64.Build.0 = Debug|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Debug|x64.Build.0 = Debug|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Release|Win32.Build.0 = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Release|x64.ActiveCfg = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Release|x64.Build.0 = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Debug|Win32.ActiveCfg = Debug|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Debug|Win32.Build.0 = Debug|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Debug|x64.ActiveCfg = Debug|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Debug|x64.Build.0 = Debug|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release - Fast FPU|x64.Build.0 = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release|Win32.ActiveCfg = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release|Win32.Build.0 = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release|x64.ActiveCfg = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release|x64.Build.0 = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.SDL-Debug|x64.Build.0 = Debug|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Debug|x64.Build.0 = Debug|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Release|Win32.Build.0 = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Release|x64.ActiveCfg = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Release|x64.Build.0 = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Debug|Win32.ActiveCfg = Debug|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Debug|Win32.Build.0 = Debug|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Debug|x64.ActiveCfg = Debug|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Debug|x64.Build.0 = Debug|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release - Fast FPU|x64.Build.0 = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release|Win32.ActiveCfg = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release|Win32.Build.0 = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release|x64.ActiveCfg = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release|x64.Build.0 = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.SDL-Debug|x64.Build.0 = Debug|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Debug|x64.Build.0 = Debug|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Release|Win32.Build.0 = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Release|x64.ActiveCfg = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Release|x64.Build.0 = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.ActiveCfg = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.Build.0 = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.ActiveCfg = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.Build.0 = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.ActiveCfg = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.Build.0 = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.ActiveCfg = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.Build.0 = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.ActiveCfg = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.Build.0 = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.ActiveCfg = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.Build.0 = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|Win32.ActiveCfg = SDL-Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|Win32.Build.0 = SDL-Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|x64.ActiveCfg = SDL-Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|x64.Build.0 = SDL-Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.ActiveCfg = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.Build.0 = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.ActiveCfg = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.Build.0 = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.Build.0 = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.ActiveCfg = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.Build.0 = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.ActiveCfg = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.Build.0 = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.ActiveCfg = Static lib - Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.Build.0 = Static lib - Release|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Debug|Win32.ActiveCfg = Debug|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Debug|Win32.Build.0 = Debug|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Debug|x64.ActiveCfg = Debug|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Debug|x64.Build.0 = Debug|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Release - Fast FPU|x64.Build.0 = Release|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Release|Win32.ActiveCfg = Release|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Release|Win32.Build.0 = Release|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Release|x64.ActiveCfg = Release|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Release|x64.Build.0 = Release|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.SDL-Debug|x64.Build.0 = Debug|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Debug|x64.Build.0 = Debug|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Release|Win32.Build.0 = Release|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Release|x64.ActiveCfg = Release|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Release|x64.Build.0 = Release|x64 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Debug|Win32.ActiveCfg = Debug|Win32 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Debug|Win32.Build.0 = Debug|Win32 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Debug|x64.ActiveCfg = Debug|x64 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Debug|x64.Build.0 = Debug|x64 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Release - Fast FPU|x64.Build.0 = Release|x64 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Release|Win32.ActiveCfg = Release|Win32 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Release|Win32.Build.0 = Release|Win32 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Release|x64.ActiveCfg = Release|x64 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Release|x64.Build.0 = Release|x64 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.SDL-Debug|x64.Build.0 = Debug|x64 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Static lib - Debug|x64.Build.0 = Debug|x64 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Static lib - Release|Win32.Build.0 = Release|Win32 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Static lib - Release|x64.ActiveCfg = Release|x64 + {1FDD5E75-9EB3-4467-B672-0BFC105B84A5}.Static lib - Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/examples/BuildAllExamples_vc14.sln b/examples/BuildAllExamples_vc14.sln new file mode 100644 index 00000000..4766c3b5 --- /dev/null +++ b/examples/BuildAllExamples_vc14.sln @@ -0,0 +1,1099 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "01.HelloWorld", "01.HelloWorld\HelloWorld_vc14.vcxproj", "{5AD4C95C-BA38-4692-BA4B-8C25A86208F9}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "02.Quake3Map", "02.Quake3Map\Quake3Map_vc14.vcxproj", "{D1A464A2-D479-458C-98A2-60965D823CD1}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "03.CustomSceneNode", "03.CustomSceneNode\CustomSceneNode_vc14.vcxproj", "{171CCDFA-C140-4956-8EB7-F0168F4521D3}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "04.Movement", "04.Movement\Movement_vc14.vcxproj", "{7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "05.UserInterface", "05.UserInterface\UserInterface_vc14.vcxproj", "{622C9DD7-0391-49FF-AF53-24F9D5A8EC53}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "06.2DGraphics", "06.2DGraphics\2DGraphics_vc14.vcxproj", "{E71B6F18-10DC-4101-A541-F6D33F71B2BD}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "07.Collision", "07.Collision\Collision_vc14.vcxproj", "{3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "08.SpecialFX", "08.SpecialFX\SpecialFX_vc14.vcxproj", "{C869BF55-B9D6-4980-BC92-60FA0CF8411A}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "09.Meshviewer", "09.Meshviewer\Meshviewer_vc14.vcxproj", "{2AE24484-22FC-481B-9A40-7CD0DA5C8E06}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "10.Shaders", "10.Shaders\Shaders_vc14.vcxproj", "{27158C82-CD15-4A9B-9848-35E7065B209F}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "11.PerPixelLighting", "11.PerPixelLighting\PerPixelLighting_vc14.vcxproj", "{C4B42409-542D-4EFC-9E6B-44713FD47A33}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "12.TerrainRendering", "12.TerrainRendering\TerrainRendering_vc14.vcxproj", "{3A5B74E5-6390-43B0-A459-2793B81FFD31}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "13.RenderToTexture", "13.RenderToTexture\RenderToTexture_vc14.vcxproj", "{0914E5C8-5352-467B-8421-C9EB35BD5596}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "14.Win32Window", "14.Win32Window\Win32Window_vc14.vcxproj", "{772FBE05-D05A-467B-9842-BEC409EEA8D0}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "15.LoadIrrFile", "15.LoadIrrFile\LoadIrrFile_vc14.vcxproj", "{78C9F424-523C-49AC-94B7-823AA4A26BF9}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "16.Quake3MapShader", "16.Quake3MapShader\Quake3MapShader_vc14.vcxproj", "{EB3B38EA-5CE7-4983-845B-880661E69D09}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "18.SplitScreen", "18.SplitScreen\SplitScreen_vc14.vcxproj", "{1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "19.MouseAndJoystick", "19.MouseAndJoystick\MouseAndJoystick_vc14.vcxproj", "{FE853A36-E0D1-4AC5-A792-B643E70D2953}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "20.ManagedLights", "20.ManagedLights\ManagedLights_vc14.vcxproj", "{16007FE2-142B-47F8-93E1-519BA3F39E71}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "21.Quake3Explorer", "21.Quake3Explorer\Quake3Explorer_vc14.vcxproj", "{CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "22.MaterialViewer", "22.MaterialViewer\MaterialViewer_vc14.vcxproj", "{4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "23.SMeshHandling", "23.SMeshHandling\SMeshHandling_vc14.vcxproj", "{6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "24.CursorControl", "24.CursorControl\CursorControl_vc14.vcxproj", "{02B67A37-50E1-49DB-BECF-905BC029C2FE}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "25.XmlHandling", "25.XmlHandling\XmlHandling_vc14.vcxproj", "{8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "26.OcclusionQuery", "26.OcclusionQuery\OcclusionQuery_vc14.vcxproj", "{5CE0E2E7-879D-4152-B61D-24E7D0707B45}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "30.Profiling", "30.Profiling\Profiling_vc14.vcxproj", "{65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GUIEditor", "..\tools\GUIEditor\GUI Editor_vc14.vcxproj", "{853A396E-C031-4C26-A716-5B4E176BE11D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FontTool", "..\tools\IrrFontTool\newFontTool\irrFontTool_vc14.vcxproj", "{4D53E40F-37E3-42B1-8848-F4C6F8313A17}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MeshConverter", "..\tools\MeshConverter\MeshConverter_vc14.vcxproj", "{E72B637E-4AA6-46F3-885F-AC67B4B470ED}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo", "Demo\Demo_vc14.vcxproj", "{6F076455-D955-45D4-9C68-4AD4E45F2D47}" + ProjectSection(ProjectDependencies) = postProject + {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Irrlicht", "..\source\Irrlicht\Irrlicht14.0.vcxproj", "{E08E042A-6C45-411B-92BE-3CC31331019F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "27.PostProcessing", "27.PostProcessing\PostProcessing_vc14.vcxproj", "{F25F2AC4-AEDA-4A95-9769-01A2652B54A2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "28.CubeMapping", "28.CubeMapping\CubeMapping_vc14.vcxproj", "{DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release - Fast FPU|Win32 = Release - Fast FPU|Win32 + Release - Fast FPU|x64 = Release - Fast FPU|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + SDL-Debug|Win32 = SDL-Debug|Win32 + SDL-Debug|x64 = SDL-Debug|x64 + Static lib - Debug|Win32 = Static lib - Debug|Win32 + Static lib - Debug|x64 = Static lib - Debug|x64 + Static lib - Release - Fast FPU|Win32 = Static lib - Release - Fast FPU|Win32 + Static lib - Release - Fast FPU|x64 = Static lib - Release - Fast FPU|x64 + Static lib - Release|Win32 = Static lib - Release|Win32 + Static lib - Release|x64 = Static lib - Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Debug|Win32.ActiveCfg = Debug|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Debug|Win32.Build.0 = Debug|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Debug|x64.ActiveCfg = Debug|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Debug|x64.Build.0 = Debug|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release - Fast FPU|x64.Build.0 = Release|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release|Win32.ActiveCfg = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release|Win32.Build.0 = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release|x64.ActiveCfg = Release|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Release|x64.Build.0 = Release|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.SDL-Debug|x64.Build.0 = Debug|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Debug|x64.Build.0 = Debug|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Release|Win32.Build.0 = Release|Win32 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Release|x64.ActiveCfg = Release|x64 + {5AD4C95C-BA38-4692-BA4B-8C25A86208F9}.Static lib - Release|x64.Build.0 = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Debug|Win32.ActiveCfg = Debug|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Debug|Win32.Build.0 = Debug|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Debug|x64.ActiveCfg = Debug|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Debug|x64.Build.0 = Debug|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release - Fast FPU|x64.Build.0 = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release|Win32.ActiveCfg = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release|Win32.Build.0 = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release|x64.ActiveCfg = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Release|x64.Build.0 = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.SDL-Debug|x64.Build.0 = Debug|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Debug|x64.Build.0 = Debug|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Release|Win32.Build.0 = Release|Win32 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Release|x64.ActiveCfg = Release|x64 + {D1A464A2-D479-458C-98A2-60965D823CD1}.Static lib - Release|x64.Build.0 = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Debug|Win32.ActiveCfg = Debug|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Debug|Win32.Build.0 = Debug|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Debug|x64.ActiveCfg = Debug|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Debug|x64.Build.0 = Debug|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release - Fast FPU|x64.Build.0 = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release|Win32.ActiveCfg = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release|Win32.Build.0 = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release|x64.ActiveCfg = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Release|x64.Build.0 = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.SDL-Debug|x64.Build.0 = Debug|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Debug|x64.Build.0 = Debug|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Release|Win32.Build.0 = Release|Win32 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Release|x64.ActiveCfg = Release|x64 + {171CCDFA-C140-4956-8EB7-F0168F4521D3}.Static lib - Release|x64.Build.0 = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Debug|Win32.ActiveCfg = Debug|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Debug|Win32.Build.0 = Debug|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Debug|x64.ActiveCfg = Debug|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Debug|x64.Build.0 = Debug|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release - Fast FPU|x64.Build.0 = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release|Win32.ActiveCfg = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release|Win32.Build.0 = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release|x64.ActiveCfg = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Release|x64.Build.0 = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.SDL-Debug|x64.Build.0 = Debug|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Debug|x64.Build.0 = Debug|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Release|Win32.Build.0 = Release|Win32 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Release|x64.ActiveCfg = Release|x64 + {7BDBB7E8-E0C9-4A0D-83C1-D389D6140FEF}.Static lib - Release|x64.Build.0 = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Debug|Win32.ActiveCfg = Debug|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Debug|Win32.Build.0 = Debug|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Debug|x64.ActiveCfg = Debug|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Debug|x64.Build.0 = Debug|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release - Fast FPU|x64.Build.0 = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release|Win32.ActiveCfg = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release|Win32.Build.0 = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release|x64.ActiveCfg = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Release|x64.Build.0 = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.SDL-Debug|x64.Build.0 = Debug|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Debug|x64.Build.0 = Debug|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Release|Win32.Build.0 = Release|Win32 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Release|x64.ActiveCfg = Release|x64 + {622C9DD7-0391-49FF-AF53-24F9D5A8EC53}.Static lib - Release|x64.Build.0 = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Debug|Win32.ActiveCfg = Debug|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Debug|Win32.Build.0 = Debug|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Debug|x64.ActiveCfg = Debug|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Debug|x64.Build.0 = Debug|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release - Fast FPU|x64.Build.0 = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release|Win32.ActiveCfg = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release|Win32.Build.0 = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release|x64.ActiveCfg = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Release|x64.Build.0 = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.SDL-Debug|x64.Build.0 = Debug|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Debug|x64.Build.0 = Debug|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Release|Win32.Build.0 = Release|Win32 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Release|x64.ActiveCfg = Release|x64 + {E71B6F18-10DC-4101-A541-F6D33F71B2BD}.Static lib - Release|x64.Build.0 = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Debug|Win32.ActiveCfg = Debug|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Debug|Win32.Build.0 = Debug|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Debug|x64.ActiveCfg = Debug|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Debug|x64.Build.0 = Debug|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release - Fast FPU|x64.Build.0 = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release|Win32.ActiveCfg = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release|Win32.Build.0 = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release|x64.ActiveCfg = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Release|x64.Build.0 = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.SDL-Debug|x64.Build.0 = Debug|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Debug|x64.Build.0 = Debug|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Release|Win32.Build.0 = Release|Win32 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Release|x64.ActiveCfg = Release|x64 + {3E30297B-5BE3-4A5C-B31E-08A28ADDB29E}.Static lib - Release|x64.Build.0 = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Debug|Win32.Build.0 = Debug|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Debug|x64.ActiveCfg = Debug|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Debug|x64.Build.0 = Debug|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release - Fast FPU|x64.Build.0 = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release|Win32.ActiveCfg = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release|Win32.Build.0 = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release|x64.ActiveCfg = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Release|x64.Build.0 = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.SDL-Debug|x64.Build.0 = Debug|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Debug|x64.Build.0 = Debug|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Release|Win32.Build.0 = Release|Win32 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Release|x64.ActiveCfg = Release|x64 + {C869BF55-B9D6-4980-BC92-60FA0CF8411A}.Static lib - Release|x64.Build.0 = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Debug|Win32.ActiveCfg = Debug|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Debug|Win32.Build.0 = Debug|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Debug|x64.ActiveCfg = Debug|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Debug|x64.Build.0 = Debug|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release - Fast FPU|x64.Build.0 = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release|Win32.ActiveCfg = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release|Win32.Build.0 = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release|x64.ActiveCfg = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Release|x64.Build.0 = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.SDL-Debug|x64.Build.0 = Debug|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Debug|x64.Build.0 = Debug|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Release|Win32.Build.0 = Release|Win32 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Release|x64.ActiveCfg = Release|x64 + {2AE24484-22FC-481B-9A40-7CD0DA5C8E06}.Static lib - Release|x64.Build.0 = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Debug|Win32.ActiveCfg = Debug|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Debug|Win32.Build.0 = Debug|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Debug|x64.ActiveCfg = Debug|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Debug|x64.Build.0 = Debug|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release - Fast FPU|x64.Build.0 = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release|Win32.ActiveCfg = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release|Win32.Build.0 = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release|x64.ActiveCfg = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Release|x64.Build.0 = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.SDL-Debug|x64.Build.0 = Debug|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Debug|x64.Build.0 = Debug|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Release|Win32.Build.0 = Release|Win32 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Release|x64.ActiveCfg = Release|x64 + {27158C82-CD15-4A9B-9848-35E7065B209F}.Static lib - Release|x64.Build.0 = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Debug|Win32.ActiveCfg = Debug|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Debug|Win32.Build.0 = Debug|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Debug|x64.ActiveCfg = Debug|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Debug|x64.Build.0 = Debug|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release - Fast FPU|x64.Build.0 = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release|Win32.ActiveCfg = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release|Win32.Build.0 = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release|x64.ActiveCfg = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Release|x64.Build.0 = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.SDL-Debug|x64.Build.0 = Debug|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Debug|x64.Build.0 = Debug|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Release|Win32.Build.0 = Release|Win32 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Release|x64.ActiveCfg = Release|x64 + {C4B42409-542D-4EFC-9E6B-44713FD47A33}.Static lib - Release|x64.Build.0 = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Debug|Win32.ActiveCfg = Debug|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Debug|Win32.Build.0 = Debug|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Debug|x64.ActiveCfg = Debug|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Debug|x64.Build.0 = Debug|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release - Fast FPU|x64.Build.0 = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release|Win32.ActiveCfg = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release|Win32.Build.0 = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release|x64.ActiveCfg = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Release|x64.Build.0 = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.SDL-Debug|x64.Build.0 = Debug|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Debug|x64.Build.0 = Debug|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Release|Win32.Build.0 = Release|Win32 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Release|x64.ActiveCfg = Release|x64 + {3A5B74E5-6390-43B0-A459-2793B81FFD31}.Static lib - Release|x64.Build.0 = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Debug|Win32.ActiveCfg = Debug|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Debug|Win32.Build.0 = Debug|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Debug|x64.ActiveCfg = Debug|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Debug|x64.Build.0 = Debug|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release - Fast FPU|x64.Build.0 = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release|Win32.ActiveCfg = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release|Win32.Build.0 = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release|x64.ActiveCfg = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Release|x64.Build.0 = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.SDL-Debug|x64.Build.0 = Debug|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Debug|x64.Build.0 = Debug|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Release|Win32.Build.0 = Release|Win32 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Release|x64.ActiveCfg = Release|x64 + {0914E5C8-5352-467B-8421-C9EB35BD5596}.Static lib - Release|x64.Build.0 = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Debug|Win32.ActiveCfg = Debug|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Debug|Win32.Build.0 = Debug|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Debug|x64.ActiveCfg = Debug|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Debug|x64.Build.0 = Debug|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release - Fast FPU|x64.Build.0 = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release|Win32.ActiveCfg = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release|Win32.Build.0 = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release|x64.ActiveCfg = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Release|x64.Build.0 = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.SDL-Debug|x64.Build.0 = Debug|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Debug|x64.Build.0 = Debug|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Release|Win32.Build.0 = Release|Win32 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Release|x64.ActiveCfg = Release|x64 + {772FBE05-D05A-467B-9842-BEC409EEA8D0}.Static lib - Release|x64.Build.0 = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Debug|Win32.ActiveCfg = Debug|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Debug|Win32.Build.0 = Debug|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Debug|x64.ActiveCfg = Debug|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Debug|x64.Build.0 = Debug|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release - Fast FPU|x64.Build.0 = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release|Win32.ActiveCfg = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release|Win32.Build.0 = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release|x64.ActiveCfg = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Release|x64.Build.0 = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.SDL-Debug|x64.Build.0 = Debug|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Debug|x64.Build.0 = Debug|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Release|Win32.Build.0 = Release|Win32 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Release|x64.ActiveCfg = Release|x64 + {78C9F424-523C-49AC-94B7-823AA4A26BF9}.Static lib - Release|x64.Build.0 = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Debug|Win32.ActiveCfg = Debug|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Debug|Win32.Build.0 = Debug|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Debug|x64.ActiveCfg = Debug|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Debug|x64.Build.0 = Debug|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release - Fast FPU|x64.Build.0 = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release|Win32.ActiveCfg = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release|Win32.Build.0 = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release|x64.ActiveCfg = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Release|x64.Build.0 = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.SDL-Debug|x64.Build.0 = Debug|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Debug|x64.Build.0 = Debug|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Release|Win32.Build.0 = Release|Win32 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Release|x64.ActiveCfg = Release|x64 + {EB3B38EA-5CE7-4983-845B-880661E69D09}.Static lib - Release|x64.Build.0 = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Debug|Win32.ActiveCfg = Debug|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Debug|Win32.Build.0 = Debug|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Debug|x64.ActiveCfg = Debug|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Debug|x64.Build.0 = Debug|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release - Fast FPU|x64.Build.0 = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release|Win32.ActiveCfg = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release|Win32.Build.0 = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release|x64.ActiveCfg = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release|x64.Build.0 = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.SDL-Debug|x64.Build.0 = Debug|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Debug|x64.Build.0 = Debug|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Release|Win32.Build.0 = Release|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Release|x64.ActiveCfg = Release|x64 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Static lib - Release|x64.Build.0 = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Debug|Win32.Build.0 = Debug|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Debug|x64.ActiveCfg = Debug|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Debug|x64.Build.0 = Debug|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release - Fast FPU|x64.Build.0 = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release|Win32.ActiveCfg = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release|Win32.Build.0 = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release|x64.ActiveCfg = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Release|x64.Build.0 = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.SDL-Debug|x64.Build.0 = Debug|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Debug|x64.Build.0 = Debug|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Release|Win32.Build.0 = Release|Win32 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Release|x64.ActiveCfg = Release|x64 + {FE853A36-E0D1-4AC5-A792-B643E70D2953}.Static lib - Release|x64.Build.0 = Release|x64 + {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}.Debug|x64.ActiveCfg = Debug|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Debug|x64.Build.0 = Debug|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release - Fast FPU|x64.Build.0 = Release|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release|Win32.ActiveCfg = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release|Win32.Build.0 = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release|x64.ActiveCfg = Release|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release|x64.Build.0 = Release|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.SDL-Debug|x64.Build.0 = Debug|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Debug|x64.Build.0 = Debug|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Release|Win32.Build.0 = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Release|x64.ActiveCfg = Release|x64 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Static lib - Release|x64.Build.0 = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Debug|Win32.ActiveCfg = Debug|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Debug|Win32.Build.0 = Debug|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Debug|x64.ActiveCfg = Debug|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Debug|x64.Build.0 = Debug|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release - Fast FPU|x64.Build.0 = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release|Win32.ActiveCfg = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release|Win32.Build.0 = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release|x64.ActiveCfg = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Release|x64.Build.0 = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.SDL-Debug|x64.Build.0 = Debug|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Debug|x64.Build.0 = Debug|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Release|Win32.Build.0 = Release|Win32 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Release|x64.ActiveCfg = Release|x64 + {CDC4AAA9-72E1-4FFA-A04D-7EF59D8B97CD}.Static lib - Release|x64.Build.0 = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Debug|Win32.ActiveCfg = Debug|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Debug|Win32.Build.0 = Debug|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Debug|x64.ActiveCfg = Debug|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Debug|x64.Build.0 = Debug|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release - Fast FPU|x64.Build.0 = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release|Win32.ActiveCfg = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release|Win32.Build.0 = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release|x64.ActiveCfg = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Release|x64.Build.0 = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.SDL-Debug|x64.Build.0 = Debug|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Debug|x64.Build.0 = Debug|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Release|Win32.Build.0 = Release|Win32 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Release|x64.ActiveCfg = Release|x64 + {4E6C2F8D-BA92-4C5B-96FD-72D4FE8BD7FA}.Static lib - Release|x64.Build.0 = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Debug|Win32.ActiveCfg = Debug|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Debug|Win32.Build.0 = Debug|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Debug|x64.ActiveCfg = Debug|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Debug|x64.Build.0 = Debug|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release - Fast FPU|x64.Build.0 = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release|Win32.ActiveCfg = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release|Win32.Build.0 = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release|x64.ActiveCfg = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Release|x64.Build.0 = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.SDL-Debug|x64.Build.0 = Debug|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Debug|x64.Build.0 = Debug|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Release|Win32.Build.0 = Release|Win32 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Release|x64.ActiveCfg = Release|x64 + {6AEC2AA2-C9FF-4B7D-B07A-94A9D34B41D7}.Static lib - Release|x64.Build.0 = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Debug|Win32.ActiveCfg = Debug|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Debug|Win32.Build.0 = Debug|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Debug|x64.ActiveCfg = Debug|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Debug|x64.Build.0 = Debug|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release - Fast FPU|x64.Build.0 = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release|Win32.ActiveCfg = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release|Win32.Build.0 = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release|x64.ActiveCfg = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Release|x64.Build.0 = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.SDL-Debug|x64.Build.0 = Debug|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Debug|x64.Build.0 = Debug|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Release|Win32.Build.0 = Release|Win32 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Release|x64.ActiveCfg = Release|x64 + {02B67A37-50E1-49DB-BECF-905BC029C2FE}.Static lib - Release|x64.Build.0 = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Debug|Win32.ActiveCfg = Debug|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Debug|Win32.Build.0 = Debug|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Debug|x64.ActiveCfg = Debug|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Debug|x64.Build.0 = Debug|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release - Fast FPU|x64.Build.0 = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release|Win32.ActiveCfg = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release|Win32.Build.0 = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release|x64.ActiveCfg = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Release|x64.Build.0 = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.SDL-Debug|x64.Build.0 = Debug|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Debug|x64.Build.0 = Debug|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Release|Win32.Build.0 = Release|Win32 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Release|x64.ActiveCfg = Release|x64 + {8FDA260E-EF27-4F8C-8720-7AF707DD0D9E}.Static lib - Release|x64.Build.0 = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Debug|Win32.ActiveCfg = Debug|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Debug|Win32.Build.0 = Debug|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Debug|x64.ActiveCfg = Debug|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Debug|x64.Build.0 = Debug|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release - Fast FPU|x64.Build.0 = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release|Win32.ActiveCfg = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release|Win32.Build.0 = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release|x64.ActiveCfg = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Release|x64.Build.0 = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.SDL-Debug|x64.Build.0 = Debug|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Debug|x64.Build.0 = Debug|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Release|Win32.Build.0 = Release|Win32 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Release|x64.ActiveCfg = Release|x64 + {5CE0E2E7-879D-4152-B61D-24E7D0707B45}.Static lib - Release|x64.Build.0 = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Debug|Win32.ActiveCfg = Debug|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Debug|Win32.Build.0 = Debug|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Debug|x64.ActiveCfg = Debug|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Debug|x64.Build.0 = Debug|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release - Fast FPU|x64.Build.0 = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|Win32.ActiveCfg = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|Win32.Build.0 = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|x64.ActiveCfg = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|x64.Build.0 = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.SDL-Debug|x64.Build.0 = Debug|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Debug|x64.Build.0 = Debug|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Release|Win32.Build.0 = Release|Win32 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Release|x64.ActiveCfg = Release|x64 + {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Static lib - Release|x64.Build.0 = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Debug|Win32.ActiveCfg = Debug|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Debug|Win32.Build.0 = Debug|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Debug|x64.ActiveCfg = Debug|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Debug|x64.Build.0 = Debug|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release - Fast FPU|x64.Build.0 = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release|Win32.ActiveCfg = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release|Win32.Build.0 = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release|x64.ActiveCfg = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Release|x64.Build.0 = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.SDL-Debug|x64.Build.0 = Debug|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Debug|x64.Build.0 = Debug|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Release|Win32.Build.0 = Release|Win32 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Release|x64.ActiveCfg = Release|x64 + {853A396E-C031-4C26-A716-5B4E176BE11D}.Static lib - Release|x64.Build.0 = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Debug|Win32.ActiveCfg = Debug|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Debug|Win32.Build.0 = Debug|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Debug|x64.ActiveCfg = Debug|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Debug|x64.Build.0 = Debug|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release - Fast FPU|x64.Build.0 = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release|Win32.ActiveCfg = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release|Win32.Build.0 = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release|x64.ActiveCfg = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Release|x64.Build.0 = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.SDL-Debug|x64.Build.0 = Debug|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Debug|x64.Build.0 = Debug|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Release|Win32.Build.0 = Release|Win32 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Release|x64.ActiveCfg = Release|x64 + {4D53E40F-37E3-42B1-8848-F4C6F8313A17}.Static lib - Release|x64.Build.0 = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Debug|Win32.ActiveCfg = Debug|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Debug|Win32.Build.0 = Debug|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Debug|x64.ActiveCfg = Debug|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Debug|x64.Build.0 = Debug|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release - Fast FPU|x64.Build.0 = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release|Win32.ActiveCfg = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release|Win32.Build.0 = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release|x64.ActiveCfg = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Release|x64.Build.0 = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.SDL-Debug|x64.Build.0 = Debug|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Debug|x64.Build.0 = Debug|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Release|Win32.Build.0 = Release|Win32 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Release|x64.ActiveCfg = Release|x64 + {E72B637E-4AA6-46F3-885F-AC67B4B470ED}.Static lib - Release|x64.Build.0 = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Debug|Win32.ActiveCfg = Debug|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Debug|Win32.Build.0 = Debug|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Debug|x64.ActiveCfg = Debug|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Debug|x64.Build.0 = Debug|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release - Fast FPU|x64.Build.0 = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release|Win32.ActiveCfg = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release|Win32.Build.0 = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release|x64.ActiveCfg = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Release|x64.Build.0 = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.SDL-Debug|x64.Build.0 = Debug|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Debug|x64.Build.0 = Debug|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Release|Win32.Build.0 = Release|Win32 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Release|x64.ActiveCfg = Release|x64 + {6F076455-D955-45D4-9C68-4AD4E45F2D47}.Static lib - Release|x64.Build.0 = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.ActiveCfg = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.Build.0 = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.ActiveCfg = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.Build.0 = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.ActiveCfg = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.Build.0 = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.ActiveCfg = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.Build.0 = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.ActiveCfg = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.Build.0 = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.ActiveCfg = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.Build.0 = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|Win32.ActiveCfg = SDL-Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|Win32.Build.0 = SDL-Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|x64.ActiveCfg = SDL-Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|x64.Build.0 = SDL-Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.ActiveCfg = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.Build.0 = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.ActiveCfg = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.Build.0 = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.Build.0 = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.ActiveCfg = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.Build.0 = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.ActiveCfg = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.Build.0 = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.ActiveCfg = Static lib - Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.Build.0 = Static lib - Release|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Debug|Win32.ActiveCfg = Debug|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Debug|Win32.Build.0 = Debug|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Debug|x64.ActiveCfg = Debug|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Debug|x64.Build.0 = Debug|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Release - Fast FPU|x64.Build.0 = Release|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Release|Win32.ActiveCfg = Release|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Release|Win32.Build.0 = Release|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Release|x64.ActiveCfg = Release|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Release|x64.Build.0 = Release|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.SDL-Debug|x64.Build.0 = Debug|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Debug|x64.Build.0 = Debug|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Release|Win32.Build.0 = Release|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Release|x64.ActiveCfg = Release|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Release|x64.Build.0 = Release|x64 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Debug|Win32.ActiveCfg = Debug|Win32 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Debug|Win32.Build.0 = Debug|Win32 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Debug|x64.ActiveCfg = Debug|x64 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Debug|x64.Build.0 = Debug|x64 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Release - Fast FPU|x64.Build.0 = Release|x64 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Release|Win32.ActiveCfg = Release|Win32 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Release|Win32.Build.0 = Release|Win32 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Release|x64.ActiveCfg = Release|x64 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Release|x64.Build.0 = Release|x64 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.SDL-Debug|x64.Build.0 = Debug|x64 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Static lib - Debug|x64.Build.0 = Debug|x64 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Static lib - Release|Win32.Build.0 = Release|Win32 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Static lib - Release|x64.ActiveCfg = Release|x64 + {DEE0160F-8FBD-43EC-BB96-1B9C0ED1B51A}.Static lib - Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/examples/Demo/CDemo.cpp b/examples/Demo/CDemo.cpp new file mode 100644 index 00000000..49dd7b6e --- /dev/null +++ b/examples/Demo/CDemo.cpp @@ -0,0 +1,831 @@ +// This is a Demo of the Irrlicht Engine (c) 2005-2009 by N.Gebhardt. +// This file is not documented. + +#include "CDemo.h" +#include "exampleHelper.h" + +CDemo::CDemo(bool f, bool m, bool s, bool a, bool v, bool fsaa, video::E_DRIVER_TYPE d) +: fullscreen(f), music(m), shadows(s), additive(a), vsync(v), aa(fsaa), + driverType(d), device(0), +#ifdef USE_IRRKLANG + irrKlang(0), ballSound(0), impactSound(0), +#endif +#ifdef USE_SDL_MIXER + stream(0), ballSound(0), impactSound(0), +#endif + currentScene(-2), backColor(0), statusText(0), inOutFader(0), + quakeLevelMesh(0), quakeLevelNode(0), skyboxNode(0), model1(0), model2(0), + campFire(0), metaSelector(0), mapSelector(0), sceneStartTime(0), + timeForThisScene(0) +{ +} + + +CDemo::~CDemo() +{ + if (mapSelector) + mapSelector->drop(); + + if (metaSelector) + metaSelector->drop(); + +#ifdef USE_IRRKLANG + if (irrKlang) + irrKlang->drop(); +#endif +} + + +void CDemo::run() +{ + core::dimension2d resolution (800, 600); + + if ( driverType == video::EDT_BURNINGSVIDEO || driverType == video::EDT_SOFTWARE ) + { + resolution.Width = 640; + resolution.Height = 480; + } + + irr::SIrrlichtCreationParameters params; + params.DriverType=driverType; + params.WindowSize=resolution; + params.Bits=32; + params.Fullscreen=fullscreen; + params.Stencilbuffer=shadows; + params.Vsync=vsync; + params.AntiAlias=aa?8:0; + params.EventReceiver=this; + + device = createDeviceEx(params); + if (!device) + return; + + const io::path mediaPath = getExampleMediaPath(); + + if (device->getFileSystem()->existFile("irrlicht.dat")) + device->getFileSystem()->addFileArchive("irrlicht.dat"); + else + device->getFileSystem()->addFileArchive(mediaPath + "irrlicht.dat"); + if (device->getFileSystem()->existFile("map-20kdm2.pk3")) + device->getFileSystem()->addFileArchive("map-20kdm2.pk3"); + else + device->getFileSystem()->addFileArchive(mediaPath + "map-20kdm2.pk3"); + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + gui::IGUIEnvironment* guienv = device->getGUIEnvironment(); + + device->setWindowCaption(L"Irrlicht Engine Demo"); + + // set ambient light + smgr->setAmbientLight ( video::SColorf ( 0x00c0c0c0 ) ); + + wchar_t tmp[255]; + + // draw everything + + s32 now = 0; + s32 lastfps = 0; + sceneStartTime = device->getTimer()->getTime(); + while(device->run() && driver) + { + if (device->isWindowActive()) + { + #ifdef USE_IRRKLANG + // update 3D position for sound engine + scene::ICameraSceneNode* cam = smgr->getActiveCamera(); + if (cam && irrKlang) + irrKlang->setListenerPosition(cam->getAbsolutePosition(), cam->getTarget()); + #endif + + // load next scene if necessary + now = device->getTimer()->getTime(); + if (now - sceneStartTime > timeForThisScene && timeForThisScene!=-1) + switchToNextScene(); + + createParticleImpacts(); + + u16 clearFlag = video::ECBF_DEPTH; + + if (timeForThisScene != -1) + clearFlag |= video::ECBF_COLOR; + + driver->beginScene(clearFlag, backColor); + + smgr->drawAll(); + guienv->drawAll(); + driver->endScene(); + + // write statistics + const s32 nowfps = driver->getFPS(); + + swprintf_irr(tmp, 255, L"%ls fps:%3d triangles:%0.3f mio/s", + driver->getName(), driver->getFPS(), + driver->getPrimitiveCountDrawn(1) * (1.f / 1000000.f)); + + statusText->setText(tmp); + if ( nowfps != lastfps ) + { + device->setWindowCaption(tmp); + lastfps = nowfps; + } + } + } + + device->drop(); +} + + +bool CDemo::OnEvent(const SEvent& event) +{ + if (!device) + return false; + + if (event.EventType == EET_KEY_INPUT_EVENT && + event.KeyInput.Key == KEY_ESCAPE && + event.KeyInput.PressedDown == false) + { + // user wants to quit. + if (currentScene < 3) + timeForThisScene = 0; + else + device->closeDevice(); + } + else + if (((event.EventType == EET_KEY_INPUT_EVENT && + event.KeyInput.Key == KEY_SPACE && + event.KeyInput.PressedDown == false) || + (event.EventType == EET_MOUSE_INPUT_EVENT && + event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)) && + currentScene == 3) + { + // shoot + shoot(); + } + else + if (event.EventType == EET_KEY_INPUT_EVENT && + event.KeyInput.Key == KEY_F9 && + event.KeyInput.PressedDown == false) + { + video::IImage* image = device->getVideoDriver()->createScreenShot(); + if (image) + { + device->getVideoDriver()->writeImageToFile(image, "screenshot.bmp"); + device->getVideoDriver()->writeImageToFile(image, "screenshot.png"); + device->getVideoDriver()->writeImageToFile(image, "screenshot.tga"); + device->getVideoDriver()->writeImageToFile(image, "screenshot.ppm"); + device->getVideoDriver()->writeImageToFile(image, "screenshot.jpg"); + device->getVideoDriver()->writeImageToFile(image, "screenshot.pcx"); + image->drop(); + } + } + else + if (device->getSceneManager()->getActiveCamera()) + { + device->getSceneManager()->getActiveCamera()->OnEvent(event); + return true; + } + + return false; +} + + +void CDemo::switchToNextScene() +{ + currentScene++; + if (currentScene > 3) + currentScene = 1; + + scene::ISceneManager* sm = device->getSceneManager(); + scene::ISceneNodeAnimator* sa = 0; + scene::ICameraSceneNode* camera = 0; + + camera = sm->getActiveCamera(); + if (camera) + { + sm->setActiveCamera(0); + camera->remove(); + camera = 0; + } + + switch(currentScene) + { + case -1: // loading screen + timeForThisScene = 0; + createLoadingScreen(); + break; + + case 0: // load scene + timeForThisScene = 0; + loadSceneData(); + break; + + case 1: // panorama camera + { + currentScene += 1; + //camera = sm->addCameraSceneNode(0, core::vector3df(0,0,0), core::vector3df(-586,708,52)); + //camera->setTarget(core::vector3df(0,400,0)); + + core::array points; + + points.push_back(core::vector3df(-931.473755f, 138.300003f, 987.279114f)); // -49873 + points.push_back(core::vector3df(-847.902222f, 136.757553f, 915.792725f)); // -50559 + points.push_back(core::vector3df(-748.680420f, 152.254501f, 826.418945f)); // -51964 + points.push_back(core::vector3df(-708.428406f, 213.569580f, 784.466675f)); // -53251 + points.push_back(core::vector3df(-686.217651f, 288.141174f, 762.965576f)); // -54015 + points.push_back(core::vector3df(-679.685059f, 365.095612f, 756.551453f)); // -54733 + points.push_back(core::vector3df(-671.317871f, 447.360107f, 749.394592f)); // -55588 + points.push_back(core::vector3df(-669.468445f, 583.335632f, 747.711853f)); // -56178 + points.push_back(core::vector3df(-667.611267f, 727.313232f, 746.018250f)); // -56757 + points.push_back(core::vector3df(-665.853210f, 862.791931f, 744.436096f)); // -57859 + points.push_back(core::vector3df(-642.649597f, 1026.047607f, 724.259827f)); // -59705 + points.push_back(core::vector3df(-517.793884f, 838.396790f, 490.326050f)); // -60983 + points.push_back(core::vector3df(-474.387299f, 715.691467f, 344.639984f)); // -61629 + points.push_back(core::vector3df(-444.600250f, 601.155701f, 180.938095f)); // -62319 + points.push_back(core::vector3df(-414.808899f, 479.691406f, 4.866660f)); // -63048 + points.push_back(core::vector3df(-410.418945f, 429.642242f, -134.332687f)); // -63757 + points.push_back(core::vector3df(-399.837585f, 411.498383f, -349.350983f)); // -64418 + points.push_back(core::vector3df(-390.756653f, 403.970093f, -524.454407f)); // -65005 + points.push_back(core::vector3df(-334.864227f, 350.065491f, -732.397400f)); // -65701 + points.push_back(core::vector3df(-195.253387f, 349.577209f, -812.475891f)); // -66335 + points.push_back(core::vector3df(16.255573f, 363.743134f, -833.800415f)); // -67170 + points.push_back(core::vector3df(234.940964f, 352.957825f, -820.150696f)); // -67939 + points.push_back(core::vector3df(436.797668f, 349.236450f, -816.914185f)); // -68596 + points.push_back(core::vector3df(575.236206f, 356.244812f, -719.788513f)); // -69166 + points.push_back(core::vector3df(594.131042f, 387.173828f, -609.675598f)); // -69744 + points.push_back(core::vector3df(617.615234f, 412.002899f, -326.174072f)); // -70640 + points.push_back(core::vector3df(606.456848f, 403.221954f, -104.179291f)); // -71390 + points.push_back(core::vector3df(610.958252f, 407.037750f, 117.209778f)); // -72085 + points.push_back(core::vector3df(597.956909f, 395.167877f, 345.942200f)); // -72817 + points.push_back(core::vector3df(587.383118f, 391.444519f, 566.098633f)); // -73477 + points.push_back(core::vector3df(559.572449f, 371.991333f, 777.689453f)); // -74124 + points.push_back(core::vector3df(423.753204f, 329.990051f, 925.859741f)); // -74941 + points.push_back(core::vector3df(247.520050f, 252.818954f, 935.311829f)); // -75651 + points.push_back(core::vector3df(114.756012f, 199.799759f, 805.014160f)); + points.push_back(core::vector3df(96.783348f, 181.639481f, 648.188110f)); + points.push_back(core::vector3df(97.865623f, 138.905975f, 484.812561f)); + points.push_back(core::vector3df(99.612457f, 102.463669f, 347.603210f)); + points.push_back(core::vector3df(99.612457f, 102.463669f, 347.603210f)); + points.push_back(core::vector3df(99.612457f, 102.463669f, 347.603210f)); + + timeForThisScene = (points.size()-3)* 1000; + + camera = sm->addCameraSceneNode(0, points[0], core::vector3df(0 ,400,0)); + //camera->setTarget(core::vector3df(0,400,0)); + + sa = sm->createFollowSplineAnimator(device->getTimer()->getTime(), + points); + camera->addAnimator(sa); + sa->drop(); + + model1->setVisible(false); + model2->setVisible(false); + campFire->setVisible(false); + inOutFader->fadeIn(7000); + } + break; + + case 2: // down fly anim camera + camera = sm->addCameraSceneNode(0, core::vector3df(100,40,-80), core::vector3df(844,670,-885)); + sa = sm->createFlyStraightAnimator(core::vector3df(94, 1002, 127), + core::vector3df(108, 15, -60), 10000, true); + camera->addAnimator(sa); + timeForThisScene = 9900; + model1->setVisible(true); + model2->setVisible(false); + campFire->setVisible(false); + sa->drop(); + break; + + case 3: // interactive, go around + { + model1->setVisible(true); + model2->setVisible(true); + campFire->setVisible(true); + timeForThisScene = -1; + + core::array keyMap(11); + + keyMap.push_back( SKeyMap(EKA_MOVE_FORWARD, KEY_UP) ); + keyMap.push_back( SKeyMap(EKA_MOVE_FORWARD, KEY_KEY_W) ); + + keyMap.push_back( SKeyMap(EKA_MOVE_BACKWARD, KEY_DOWN) ); + keyMap.push_back( SKeyMap(EKA_MOVE_BACKWARD, KEY_KEY_S) ); + + keyMap.push_back( SKeyMap(EKA_STRAFE_LEFT, KEY_LEFT) ); + keyMap.push_back( SKeyMap(EKA_STRAFE_LEFT, KEY_KEY_A) ); + + keyMap.push_back( SKeyMap(EKA_STRAFE_RIGHT, KEY_RIGHT) ); + keyMap.push_back( SKeyMap(EKA_STRAFE_RIGHT, KEY_KEY_D) ); + + keyMap.push_back( SKeyMap(EKA_JUMP_UP, KEY_KEY_J) ); + + keyMap.push_back( SKeyMap(EKA_ROTATE_LEFT, KEY_KEY_Q) ); + + keyMap.push_back( SKeyMap(EKA_ROTATE_RIGHT, KEY_KEY_E) ); + + camera = sm->addCameraSceneNodeFPS(0, 100.0f, .4f, -1, keyMap.pointer(), keyMap.size(), false, 300.f); + camera->setPosition(core::vector3df(108,140,-140)); + camera->setFarValue(5000.0f); + + scene::ISceneNodeAnimatorCollisionResponse* collider = + sm->createCollisionResponseAnimator( + metaSelector, camera, core::vector3df(25,50,25), + core::vector3df(0, quakeLevelMesh ? -1000.f : 0.0f,0), + core::vector3df(0,45,0), 0.005f); + + camera->addAnimator(collider); + collider->drop(); + } + break; + } + + sceneStartTime = device->getTimer()->getTime(); +} + + +void CDemo::loadSceneData() +{ + // load quake level + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* sm = device->getSceneManager(); + + // Quake3 Shader controls Z-Writing + sm->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true); + + quakeLevelMesh = (scene::IQ3LevelMesh*) sm->getMesh("maps/20kdm2.bsp"); + + if (quakeLevelMesh) + { + u32 i; + + //move all quake level meshes (non-realtime) + core::matrix4 m; + m.setTranslation(core::vector3df(-1300,-70,-1249)); + + for ( i = 0; i != scene::quake3::E_Q3_MESH_SIZE; ++i ) + sm->getMeshManipulator()->transform(quakeLevelMesh->getMesh(i), m); + + quakeLevelNode = sm->addOctreeSceneNode( + quakeLevelMesh->getMesh( scene::quake3::E_Q3_MESH_GEOMETRY)); + if (quakeLevelNode) + { + //quakeLevelNode->setPosition(core::vector3df(-1300,-70,-1249)); + quakeLevelNode->setVisible(true); + + // create map triangle selector + mapSelector = sm->createOctreeTriangleSelector(quakeLevelMesh->getMesh(0), + quakeLevelNode, 128); + + // if not using shader and no gamma it's better to use more lighting, because + // quake3 level are usually dark + quakeLevelNode->setMaterialType ( video::EMT_LIGHTMAP_M4 ); + + // set additive blending if wanted + if (additive) + quakeLevelNode->setMaterialType(video::EMT_LIGHTMAP_ADD); + } + + // the additional mesh can be quite huge and is unoptimized + scene::IMesh * additional_mesh = quakeLevelMesh->getMesh ( scene::quake3::E_Q3_MESH_ITEMS ); + + for ( i = 0; i!= additional_mesh->getMeshBufferCount (); ++i ) + { + scene::IMeshBuffer *meshBuffer = additional_mesh->getMeshBuffer ( i ); + const video::SMaterial &material = meshBuffer->getMaterial(); + + //! The ShaderIndex is stored in the material parameter + s32 shaderIndex = (s32) material.MaterialTypeParam2; + + // the meshbuffer can be rendered without additional support, or it has no shader + const scene::quake3::IShader *shader = quakeLevelMesh->getShader ( shaderIndex ); + if ( 0 == shader ) + { + continue; + } + // Now add the MeshBuffer(s) with the current Shader to the Manager + sm->addQuake3SceneNode ( meshBuffer, shader ); + } + } + + const io::path mediaPath = getExampleMediaPath(); + + // load sydney model and create 2 instances + + scene::IAnimatedMesh* mesh = 0; + mesh = sm->getMesh(mediaPath + "sydney.md2"); + if (mesh) + { + model1 = sm->addAnimatedMeshSceneNode(mesh); + if (model1) + { + model1->setMaterialTexture(0, driver->getTexture(mediaPath + "spheremap.jpg")); + model1->setPosition(core::vector3df(100,40,-80)); + model1->setScale(core::vector3df(2,2,2)); + model1->setMD2Animation(scene::EMAT_STAND); + model1->setMaterialFlag(video::EMF_LIGHTING, false); + model1->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true); + model1->setMaterialType(video::EMT_SPHERE_MAP); + model1->setAutomaticCulling(scene::EAC_OFF); // avoid shadows not updating + scene::IShadowVolumeSceneNode * shadVol = model1->addShadowVolumeSceneNode(); + shadVol->setOptimization(scene::ESV_NONE); // Sydney has broken shadows otherwise + } + + model2 = sm->addAnimatedMeshSceneNode(mesh); + if (model2) + { + model2->setPosition(core::vector3df(180,15,-60)); + model2->setScale(core::vector3df(2,2,2)); + model2->setMD2Animation(scene::EMAT_RUN); + model2->setMaterialTexture(0, device->getVideoDriver()->getTexture(mediaPath + "sydney.bmp")); + model2->setMaterialFlag(video::EMF_LIGHTING, true); + model2->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true); + model2->setAutomaticCulling(scene::EAC_OFF); // avoid shadows not updating + scene::IShadowVolumeSceneNode * shadVol = model2->addShadowVolumeSceneNode(); + shadVol->setOptimization(scene::ESV_NONE); // Sydney has broken shadows otherwise + } + } + + scene::ISceneNodeAnimator* anim = 0; + + // create sky box + driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); + skyboxNode = sm->addSkyBoxSceneNode( + driver->getTexture(mediaPath + "irrlicht2_up.jpg"), + driver->getTexture(mediaPath + "irrlicht2_dn.jpg"), + driver->getTexture(mediaPath + "irrlicht2_lf.jpg"), + driver->getTexture(mediaPath + "irrlicht2_rt.jpg"), + driver->getTexture(mediaPath + "irrlicht2_ft.jpg"), + driver->getTexture(mediaPath + "irrlicht2_bk.jpg")); + driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true); + + // create walk-between-portals animation + + core::vector3df waypoint[2]; + waypoint[0].set(-150,40,100); + waypoint[1].set(350,40,100); + + if (model2) + { + anim = device->getSceneManager()->createFlyStraightAnimator( + waypoint[0], waypoint[1], 2000, true); + model2->addAnimator(anim); + anim->drop(); + } + + // create animation for portals; + + core::array textures; + for (s32 g=1; g<8; ++g) + { + core::stringc tmp(mediaPath + "portal"); + tmp += g; + tmp += ".bmp"; + video::ITexture* t = driver->getTexture( tmp ); + textures.push_back(t); + } + + anim = sm->createTextureAnimator(textures, 100); + + // create portals + + scene::IBillboardSceneNode* bill = 0; + + for (int r=0; r<2; ++r) + { + bill = sm->addBillboardSceneNode(0, core::dimension2d(100,100), + waypoint[r]+ core::vector3df(0,20,0)); + bill->setMaterialFlag(video::EMF_LIGHTING, false); + bill->setMaterialTexture(0, driver->getTexture(mediaPath + "portal1.bmp")); + bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); + bill->addAnimator(anim); + } + + anim->drop(); + + // create cirlce flying dynamic light with transparent billboard attached + + scene::ILightSceneNode* light = 0; + + light = sm->addLightSceneNode(0, + core::vector3df(0,0,0), video::SColorf(1.0f, 1.0f, 1.f, 1.0f), 500.f); + + anim = sm->createFlyCircleAnimator( + core::vector3df(100,150,80), 80.0f, 0.0005f); + + light->addAnimator(anim); + anim->drop(); + + bill = device->getSceneManager()->addBillboardSceneNode( + light, core::dimension2d(40,40)); + bill->setMaterialFlag(video::EMF_LIGHTING, false); + bill->setMaterialTexture(0, driver->getTexture(mediaPath + "particlewhite.bmp")); + bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); + + // create meta triangle selector with all triangles selectors in it. + metaSelector = sm->createMetaTriangleSelector(); + metaSelector->addTriangleSelector(mapSelector); + + // create camp fire + + campFire = sm->addParticleSystemSceneNode(false); + campFire->setPosition(core::vector3df(100,120,600)); + campFire->setScale(core::vector3df(2,2,2)); + + scene::IParticleEmitter* em = campFire->createBoxEmitter( + core::aabbox3d(-7,0,-7,7,1,7), + core::vector3df(0.0f,0.06f,0.0f), + 80,100, video::SColor(1,255,255,255),video::SColor(1,255,255,255), 800,2000); + + em->setMinStartSize(core::dimension2d(20.0f, 10.0f)); + em->setMaxStartSize(core::dimension2d(20.0f, 10.0f)); + campFire->setEmitter(em); + em->drop(); + + scene::IParticleAffector* paf = campFire->createFadeOutParticleAffector(); + campFire->addAffector(paf); + paf->drop(); + + campFire->setMaterialFlag(video::EMF_LIGHTING, false); + campFire->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false); + campFire->setMaterialTexture(0, driver->getTexture(mediaPath + "fireball.bmp")); + campFire->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); + + // load music + + #ifdef USE_IRRKLANG + if (music) + startIrrKlang(); + #endif + #ifdef USE_SDL_MIXER + if (music) + startSound(); + #endif +} + + +void CDemo::createLoadingScreen() +{ + core::dimension2d size = device->getVideoDriver()->getScreenSize(); + + device->getCursorControl()->setVisible(false); + + // setup loading screen + + backColor.set(255,90,90,156); + + // create in fader + + inOutFader = device->getGUIEnvironment()->addInOutFader(); + inOutFader->setColor(backColor, video::SColor ( 0, 230, 230, 230 )); + + const io::path mediaPath = getExampleMediaPath(); + + // irrlicht logo + device->getGUIEnvironment()->addImage(device->getVideoDriver()->getTexture(mediaPath + "irrlichtlogo2.png"), + core::position2d(5,5)); + + // loading text + + const int lwidth = size.Width - 20; + const int lheight = 16; + + core::rect pos(10, size.Height-lheight-10, 10+lwidth, size.Height-10); + + device->getGUIEnvironment()->addImage(pos); + statusText = device->getGUIEnvironment()->addStaticText(L"Loading...", pos, true); + statusText->setOverrideColor(video::SColor(255,205,200,200)); + + // load bigger font + + device->getGUIEnvironment()->getSkin()->setFont( + device->getGUIEnvironment()->getFont(mediaPath + "fonthaettenschweiler.bmp")); + + // set new font color + + device->getGUIEnvironment()->getSkin()->setColor(gui::EGDC_BUTTON_TEXT, + video::SColor(255,100,100,100)); +} + + +void CDemo::shoot() +{ + scene::ISceneManager* sm = device->getSceneManager(); + scene::ICameraSceneNode* camera = sm->getActiveCamera(); + + if (!camera || !mapSelector) + return; + + SParticleImpact imp; + imp.when = 0; + + // get line of camera + + core::vector3df start = camera->getPosition(); + core::vector3df end = (camera->getTarget() - start); + end.normalize(); + start += end*8.0f; + end = start + (end * camera->getFarValue()); + + core::triangle3df triangle; + + core::line3d line(start, end); + + // get intersection point with map + scene::ISceneNode* hitNode; + if (sm->getSceneCollisionManager()->getCollisionPoint( + line, mapSelector, end, triangle, hitNode)) + { + // collides with wall + core::vector3df out = triangle.getNormal(); + out.setLength(0.03f); + + imp.when = 1; + imp.outVector = out; + imp.pos = end; + } + else + { + // doesnt collide with wall + core::vector3df start = camera->getPosition(); + core::vector3df end = (camera->getTarget() - start); + end.normalize(); + start += end*8.0f; + end = start + (end * camera->getFarValue()); + } + + // create fire ball + scene::ISceneNode* node = 0; + node = sm->addBillboardSceneNode(0, + core::dimension2d(25,25), start); + + node->setMaterialFlag(video::EMF_LIGHTING, false); + node->setMaterialTexture(0, device->getVideoDriver()->getTexture(getExampleMediaPath() + "fireball.bmp")); + node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); + + f32 length = (f32)(end - start).getLength(); + const f32 speed = 0.6f; + u32 time = (u32)(length / speed); + + scene::ISceneNodeAnimator* anim = 0; + + // set flight line + + anim = sm->createFlyStraightAnimator(start, end, time); + node->addAnimator(anim); + anim->drop(); + + anim = sm->createDeleteAnimator(time); + node->addAnimator(anim); + anim->drop(); + + if (imp.when) + { + // create impact note + imp.when = device->getTimer()->getTime() + (time - 100); + Impacts.push_back(imp); + } + + // play sound + #ifdef USE_IRRKLANG + if (ballSound) + irrKlang->play2D(ballSound); + #endif + #ifdef USE_SDL_MIXER + if (ballSound) + playSound(ballSound); + #endif +} + + +void CDemo::createParticleImpacts() +{ + u32 now = device->getTimer()->getTime(); + scene::ISceneManager* sm = device->getSceneManager(); + + for (s32 i=0; i<(s32)Impacts.size(); ++i) + if (now > Impacts[i].when) + { + // create smoke particle system + scene::IParticleSystemSceneNode* pas = 0; + + pas = sm->addParticleSystemSceneNode(false, 0, -1, Impacts[i].pos); + + pas->setParticleSize(core::dimension2d(10.0f, 10.0f)); + + scene::IParticleEmitter* em = pas->createBoxEmitter( + core::aabbox3d(-5,-5,-5,5,5,5), + Impacts[i].outVector, 20,40, video::SColor(50,255,255,255),video::SColor(50,255,255,255), + 1200,1600, 20); + + pas->setEmitter(em); + em->drop(); + + scene::IParticleAffector* paf = campFire->createFadeOutParticleAffector(); + pas->addAffector(paf); + paf->drop(); + + pas->setMaterialFlag(video::EMF_LIGHTING, false); + pas->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false); + pas->setMaterialTexture(0, device->getVideoDriver()->getTexture(getExampleMediaPath() + "smoke.bmp")); + pas->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); + + scene::ISceneNodeAnimator* anim = sm->createDeleteAnimator(2000); + pas->addAnimator(anim); + anim->drop(); + + // play impact sound + #ifdef USE_IRRKLANG + if (irrKlang) + { + irrklang::ISound* sound = + irrKlang->play3D(impactSound, Impacts[i].pos, false, false, true); + + if (sound) + { + // adjust max value a bit to make to sound of an impact louder + sound->setMinDistance(400); + sound->drop(); + } + } + #endif + + #ifdef USE_SDL_MIXER + if (impactSound) + playSound(impactSound); + #endif + + // delete entry + Impacts.erase(i); + i--; + } +} + + +#ifdef USE_IRRKLANG +void CDemo::startIrrKlang() +{ + irrKlang = irrklang::createIrrKlangDevice(); + + if (!irrKlang) + return; + + const io::path mediaPath = getExampleMediaPath(); + + // play music + + irrklang::ISound* snd = irrKlang->play2D((mediaPath + "IrrlichtTheme.ogg").c_str(), true, false, true); + if ( !snd ) + snd = irrKlang->play2D("IrrlichtTheme.ogg", true, false, true); + + if (snd) + { + snd->setVolume(0.5f); // 50% volume + snd->drop(); + } + + // preload both sound effects + + ballSound = irrKlang->getSoundSource(mediaPath + "ball.wav"); + impactSound = irrKlang->getSoundSource(mediaPath + "impact.wav"); +} +#endif + + +#ifdef USE_SDL_MIXER +void CDemo::startSound() +{ + stream = NULL; + ballSound = NULL; + impactSound = NULL; + + SDL_Init(SDL_INIT_AUDIO); + + if (Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 4096)) + return; + + const io::path mediaPath = getExampleMediaPath(); + + stream = Mix_LoadMUS((mediaPath + "IrrlichtTheme.ogg").c_str()); + if (stream) + Mix_PlayMusic(stream, -1); + + ballSound = Mix_LoadWAV((mediaPath + "ball.wav").c_str()); + impactSound = Mix_LoadWAV((mediaPath + "impact.wav").c_str()); +} + +void CDemo::playSound(Mix_Chunk *sample) +{ + if (sample) + Mix_PlayChannel(-1, sample, 0); +} + +void CDemo::pollSound(void) +{ + SDL_Event event; + + while (SDL_PollEvent(&event)) + ; +} +#endif diff --git a/examples/Demo/CDemo.h b/examples/Demo/CDemo.h new file mode 100644 index 00000000..0b2ca39c --- /dev/null +++ b/examples/Demo/CDemo.h @@ -0,0 +1,110 @@ +// This is a Demo of the Irrlicht Engine (c) 2006 by N.Gebhardt. +// This file is not documented. + +#ifndef __C_DEMO_H_INCLUDED__ +#define __C_DEMO_H_INCLUDED__ + +//#define USE_IRRKLANG +//#define USE_SDL_MIXER + +#include + +#ifdef _IRR_WINDOWS_ +#include +#endif + +using namespace irr; + +// audio support + +#ifdef USE_IRRKLANG + #include // problem here? go to http://www.ambiera.com/irrklang and download + // the irrKlang library or undefine USE_IRRKLANG at the beginning + // of this file. + #ifdef _MSC_VER + #pragma comment (lib, "irrKlang.lib") + #endif +#endif +#ifdef USE_SDL_MIXER + # include + # include +#endif + +const int CAMERA_COUNT = 7; + +class CDemo : public IEventReceiver +{ +public: + + CDemo(bool fullscreen, bool music, bool shadows, bool additive, bool vsync, bool aa, video::E_DRIVER_TYPE driver); + + ~CDemo(); + + void run(); + + virtual bool OnEvent(const SEvent& event); + +private: + + void createLoadingScreen(); + void loadSceneData(); + void switchToNextScene(); + void shoot(); + void createParticleImpacts(); + + bool fullscreen; + bool music; + bool shadows; + bool additive; + bool vsync; + bool aa; + video::E_DRIVER_TYPE driverType; + IrrlichtDevice *device; + +#ifdef USE_IRRKLANG + void startIrrKlang(); + irrklang::ISoundEngine* irrKlang; + irrklang::ISoundSource* ballSound; + irrklang::ISoundSource* impactSound; +#endif + +#ifdef USE_SDL_MIXER + void startSound(); + void playSound(Mix_Chunk *); + void pollSound(); + Mix_Music *stream; + Mix_Chunk *ballSound; + Mix_Chunk *impactSound; +#endif + + struct SParticleImpact + { + u32 when; + core::vector3df pos; + core::vector3df outVector; + }; + + int currentScene; + video::SColor backColor; + + gui::IGUIStaticText* statusText; + gui::IGUIInOutFader* inOutFader; + + scene::IQ3LevelMesh* quakeLevelMesh; + scene::ISceneNode* quakeLevelNode; + scene::ISceneNode* skyboxNode; + scene::IAnimatedMeshSceneNode* model1; + scene::IAnimatedMeshSceneNode* model2; + scene::IParticleSystemSceneNode* campFire; + + scene::IMetaTriangleSelector* metaSelector; + scene::ITriangleSelector* mapSelector; + + s32 sceneStartTime; + s32 timeForThisScene; + + core::array Impacts; +}; + +#endif + diff --git a/examples/Demo/CMainMenu.cpp b/examples/Demo/CMainMenu.cpp new file mode 100644 index 00000000..ebc9469e --- /dev/null +++ b/examples/Demo/CMainMenu.cpp @@ -0,0 +1,401 @@ +// This is a Demo of the Irrlicht Engine (c) 2005-2009 by N.Gebhardt. +// This file is not documented. + +#include "CMainMenu.h" +#include "CDemo.h" +#include "exampleHelper.h" + + + +CMainMenu::CMainMenu() +: startButton(0), MenuDevice(0), selected(0), start(false), fullscreen(false), +#if defined(USE_IRRKLANG) || defined(USE_SDL_MIXER) + music(true), +#else + music(false), +#endif + shadows(true), additive(false), transparent(true), vsync(true), aa(true), +#ifndef _IRR_WINDOWS_ + driverType(video::EDT_OPENGL) +#else + driverType(video::EDT_DIRECT3D9) +#endif + //driverType(video::EDT_BURNINGSVIDEO) +{ +} + + +bool CMainMenu::run() +{ + video::E_DRIVER_TYPE driverType = EDT_OPENGL; + if (!IrrlichtDevice::isDriverSupported(video::EDT_OPENGL)) + driverType = video::video::EDT_BURNINGSVIDEO; + + MenuDevice = createDevice(driverType, + core::dimension2d(512, 384), 16, false, false, false, this); + + const io::path mediaPath = getExampleMediaPath(); + + if (MenuDevice->getFileSystem()->existFile("irrlicht.dat")) + MenuDevice->getFileSystem()->addFileArchive("irrlicht.dat"); + else + MenuDevice->getFileSystem()->addFileArchive(mediaPath + "irrlicht.dat"); + + video::IVideoDriver* driver = MenuDevice->getVideoDriver(); + scene::ISceneManager* smgr = MenuDevice->getSceneManager(); + gui::IGUIEnvironment* guienv = MenuDevice->getGUIEnvironment(); + + core::stringw str = "Irrlicht Engine Demo v"; + str += MenuDevice->getVersion(); + MenuDevice->setWindowCaption(str.c_str()); + + // set new Skin + gui::IGUISkin* newskin = guienv->createSkin(gui::EGST_BURNING_SKIN); + guienv->setSkin(newskin); + newskin->drop(); + + // load font + gui::IGUIFont* font = guienv->getFont(mediaPath + "fonthaettenschweiler.bmp"); + if (font) + guienv->getSkin()->setFont(font); + + // add images + + const s32 leftX = 260; + + // add tab control + gui::IGUITabControl* tabctrl = guienv->addTabControl(core::rect(leftX,10,512-10,384-10), + 0, true, true); + gui::IGUITab* optTab = tabctrl->addTab(L"Demo"); + gui::IGUITab* aboutTab = tabctrl->addTab(L"About"); + + // add list box + + gui::IGUIListBox* box = guienv->addListBox(core::rect(10,10,220,120), optTab, 1); + + const wchar_t* const names[] = + {L"Software Renderer", L"Burning's Video", + L"Direct3D 8", L"Direct3D 9", L"OpenGL 1.x-4.x", + L"OpenGL-ES 1.x", L"OpenGL-ES 2.x"}; + for (u32 i=1; iaddItem(names[i-1]); + } + + switch (driverType ) + { + case video::EDT_OPENGL: selected = 0; break; + case video::EDT_DIRECT3D9: selected = 1; break; + case video::EDT_BURNINGSVIDEO: selected = 2; break; + case video::EDT_SOFTWARE: selected = 3; break; + default: break; + } + box->setSelected(selected); + + // add button + + startButton = guienv->addButton(core::rect(30,295,200,324), optTab, 2, L"Start Demo"); + + // add checkbox + + const s32 d = 50; + + guienv->addCheckBox(fullscreen, core::rect(20,85+d,130,110+d), + optTab, 3, L"Fullscreen"); + guienv->addCheckBox(music, core::rect(135,85+d,245,110+d), + optTab, 4, L"Music & Sfx"); + guienv->addCheckBox(shadows, core::rect(20,110+d,135,135+d), + optTab, 5, L"Realtime shadows"); + guienv->addCheckBox(additive, core::rect(20,135+d,230,160+d), + optTab, 6, L"Old HW compatible blending"); + guienv->addCheckBox(vsync, core::rect(20,160+d,230,185+d), + optTab, 7, L"Vertical synchronisation"); + guienv->addCheckBox(aa, core::rect(20,185+d,230,210+d), + optTab, 8, L"Antialiasing"); + + // add about text + + const wchar_t* text2 = L"This is the tech demo of the Irrlicht engine. To start, "\ + L"select a video driver which works best with your hardware and press 'Start Demo'.\n"\ + L"What you currently see is displayed using the Burning Software Renderer (Thomas Alten).\n"\ + L"The Irrlicht Engine was written by me, Nikolaus Gebhardt. The models, "\ + L"maps and textures were placed at my disposal by B.Collins, M.Cook and J.Marton. The music was created by "\ + L"M.Rohde and is played back by irrKlang.\n"\ + L"For more information, please visit the homepage of the Irrlicht engine:\nhttp://irrlicht.sourceforge.net"; + + guienv->addStaticText(text2, core::rect(10, 10, 230, 320), + true, true, aboutTab); + + // add md2 model + + scene::IAnimatedMesh* mesh = smgr->getMesh(mediaPath + "faerie.md2"); + scene::IAnimatedMeshSceneNode* modelNode = smgr->addAnimatedMeshSceneNode(mesh); + if (modelNode) + { + modelNode->setPosition( core::vector3df(0.f, 0.f, -5.f) ); + modelNode->setMaterialTexture(0, driver->getTexture(mediaPath + "faerie2.bmp")); + modelNode->setMaterialFlag(video::EMF_LIGHTING, true); + modelNode->getMaterial(0).Shininess = 50.f; + modelNode->getMaterial(0).NormalizeNormals = true; + modelNode->setMD2Animation(scene::EMAT_STAND); + } + + // set ambient light (no sun light in the catacombs) + smgr->setAmbientLight( video::SColorf(0.2f, 0.2f, 0.2f) ); + + scene::ILightSceneNode *light; + scene::ISceneNodeAnimator* anim; + scene::ISceneNode* bill; + + enum eLightParticle + { + LIGHT_NONE, + LIGHT_GLOBAL, + LIGHT_RED, + LIGHT_BLUE + }; + core::vector3df lightDir[2] = { + core::vector3df(0.f, 0.1f, 0.4f), + core::vector3df(0.f, 0.1f, -0.4f), + }; + + struct SLightParticle + { + eLightParticle type; + u32 dir; + }; + const SLightParticle lightParticle[] = + { + //LIGHT_GLOBAL,0, + {LIGHT_RED,0}, + {LIGHT_BLUE,0}, + {LIGHT_RED,1}, + {LIGHT_BLUE,1}, + {LIGHT_NONE,0} + }; + + const SLightParticle *l = lightParticle; + while ( l->type != LIGHT_NONE ) + { + switch ( l->type ) + { + case LIGHT_GLOBAL: + // add illumination from the background + light = smgr->addLightSceneNode(0, core::vector3df(10.f,40.f,-5.f), + video::SColorf(0.2f, 0.2f, 0.2f), 90.f); + break; + case LIGHT_RED: + // add light nearly red + light = smgr->addLightSceneNode(0, core::vector3df(0,1,0), + video::SColorf(0.8f, 0.f, 0.f, 0.0f), 30.0f); + // attach red billboard to the light + bill = smgr->addBillboardSceneNode(light, core::dimension2d(10, 10)); + if ( bill ) + { + bill->setMaterialFlag(video::EMF_LIGHTING, false); + bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); + bill->setMaterialTexture(0, driver->getTexture(mediaPath + "particlered.bmp")); + } + // add fly circle animator to the light + anim = smgr->createFlyCircleAnimator(core::vector3df(0.f,0.f,-5.f),20.f, + 0.002f, lightDir [l->dir] ); + light->addAnimator(anim); + anim->drop(); + break; + case LIGHT_BLUE: + // add light nearly blue + light = smgr->addLightSceneNode(0, core::vector3df(0,1,0), + video::SColorf(0.f, 0.0f, 0.8f, 0.0f), 30.0f); + // attach blue billboard to the light + bill = smgr->addBillboardSceneNode(light, core::dimension2d(10, 10)); + if (bill) + { + bill->setMaterialFlag(video::EMF_LIGHTING, false); + bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); + bill->setMaterialTexture(0, driver->getTexture(mediaPath + "portal1.bmp")); + } + // add fly circle animator to the light + anim = smgr->createFlyCircleAnimator(core::vector3df(0.f,0.f,-5.f),20.f, + -0.002f, lightDir [l->dir], 0.5f); + light->addAnimator(anim); + anim->drop(); + break; + case LIGHT_NONE: + break; + } + l += 1; + } + + // create a fixed camera + smgr->addCameraSceneNode(0, core::vector3df(45,0,0), core::vector3df(0,0,10)); + + + // irrlicht logo and background + // add irrlicht logo + bool oldMipMapState = driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); + driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); + + guienv->addImage(driver->getTexture(mediaPath + "irrlichtlogo3.png"), + core::position2d(5,5)); + + video::ITexture* irrlichtBack = driver->getTexture(mediaPath + "demoback.jpg"); + + driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, oldMipMapState); + + // query original skin color + getOriginalSkinColor(); + + // set transparency + setTransparency(); + + // draw all + + while(MenuDevice->run()) + { + if (MenuDevice->isWindowActive()) + { + driver->beginScene(video::ECBF_DEPTH, video::SColor(0,0,0,0)); + + if (irrlichtBack) + driver->draw2DImage(irrlichtBack, + core::position2d(0,0)); + + smgr->drawAll(); + guienv->drawAll(); + driver->endScene(); + } + } + + MenuDevice->drop(); + + for (u32 i=1; igetVideoDriver()->createScreenShot(); + if (image) + { + MenuDevice->getVideoDriver()->writeImageToFile(image, "screenshot_main.jpg"); + image->drop(); + } + } + else + if (event.EventType == irr::EET_MOUSE_INPUT_EVENT && + event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP ) + { + core::rect r(event.MouseInput.X, event.MouseInput.Y, 0, 0); + gui::IGUIContextMenu* menu = MenuDevice->getGUIEnvironment()->addContextMenu(r, 0, 45); + menu->addItem(L"transparent menus", 666, transparent == false); + menu->addItem(L"solid menus", 666, transparent == true); + menu->addSeparator(); + menu->addItem(L"Cancel"); + } + else + if (event.EventType == EET_GUI_EVENT) + { + s32 id = event.GUIEvent.Caller->getID(); + switch(id) + { + case 45: // context menu + if (event.GUIEvent.EventType == gui::EGET_MENU_ITEM_SELECTED) + { + s32 s = ((gui::IGUIContextMenu*)event.GUIEvent.Caller)->getSelectedItem(); + if (s == 0 || s == 1) + { + transparent = !transparent; + setTransparency(); + } + } + break; + case 1: + if (event.GUIEvent.EventType == gui::EGET_LISTBOX_CHANGED || + event.GUIEvent.EventType == gui::EGET_LISTBOX_SELECTED_AGAIN) + { + selected = ((gui::IGUIListBox*)event.GUIEvent.Caller)->getSelected(); + //startButton->setEnabled(selected != 4); + startButton->setEnabled(true); + } + break; + case 2: + if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED ) + { + MenuDevice->closeDevice(); + start = true; + } + case 3: + if (event.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED ) + fullscreen = ((gui::IGUICheckBox*)event.GUIEvent.Caller)->isChecked(); + break; + case 4: + if (event.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED ) + music = ((gui::IGUICheckBox*)event.GUIEvent.Caller)->isChecked(); + break; + case 5: + if (event.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED ) + shadows = ((gui::IGUICheckBox*)event.GUIEvent.Caller)->isChecked(); + break; + case 6: + if (event.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED ) + additive = ((gui::IGUICheckBox*)event.GUIEvent.Caller)->isChecked(); + break; + case 7: + if (event.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED ) + vsync = ((gui::IGUICheckBox*)event.GUIEvent.Caller)->isChecked(); + break; + case 8: + if (event.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED ) + aa = ((gui::IGUICheckBox*)event.GUIEvent.Caller)->isChecked(); + break; + } + } + + return false; +} + + +void CMainMenu::getOriginalSkinColor() +{ + irr::gui::IGUISkin * skin = MenuDevice->getGUIEnvironment()->getSkin(); + for (s32 i=0; igetColor( (gui::EGUI_DEFAULT_COLOR)i ); + } + +} + + +void CMainMenu::setTransparency() +{ + irr::gui::IGUISkin * skin = MenuDevice->getGUIEnvironment()->getSkin(); + + for (u32 i=0; isetColor((gui::EGUI_DEFAULT_COLOR)i, col); + } +} + diff --git a/examples/Demo/CMainMenu.h b/examples/Demo/CMainMenu.h new file mode 100644 index 00000000..6a3dd358 --- /dev/null +++ b/examples/Demo/CMainMenu.h @@ -0,0 +1,56 @@ +// This is a Demo of the Irrlicht Engine (c) 2005 by N.Gebhardt. +// This file is not documentated. + +#ifndef __C_MAIN_MENU_H_INCLUDED__ +#define __C_MAIN_MENU_H_INCLUDED__ + +#include + +using namespace irr; + +class CMainMenu : public IEventReceiver +{ +public: + + CMainMenu(); + + bool run(); + + bool getFullscreen() const { return fullscreen; } + bool getMusic() const { return music; } + bool getShadows() const { return shadows; } + bool getAdditive() const { return additive; } + bool getVSync() const { return vsync; } + bool getAntiAliasing() const { return aa; } + video::E_DRIVER_TYPE getDriverType() const { return driverType; } + + + virtual bool OnEvent(const SEvent& event); + +private: + + void setTransparency(); + + gui::IGUIButton* startButton; + IrrlichtDevice *MenuDevice; + s32 selected; + bool start; + bool fullscreen; + bool music; + bool shadows; + bool additive; + bool transparent; + bool vsync; + bool aa; + video::E_DRIVER_TYPE driverType; + + scene::IAnimatedMesh* quakeLevel; + scene::ISceneNode* lightMapNode; + scene::ISceneNode* dynamicNode; + + video::SColor SkinColor [ gui::EGDC_COUNT ]; + void getOriginalSkinColor(); +}; + +#endif + diff --git a/examples/Demo/Demo.vcproj b/examples/Demo/Demo.vcproj new file mode 100644 index 00000000..fe55b37f --- /dev/null +++ b/examples/Demo/Demo.vcproj @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/Demo/Demo.xcodeproj/project.pbxproj b/examples/Demo/Demo.xcodeproj/project.pbxproj new file mode 100644 index 00000000..b27eb4c6 --- /dev/null +++ b/examples/Demo/Demo.xcodeproj/project.pbxproj @@ -0,0 +1,336 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34CC741B7F8EEF00F212E8 /* main.cpp */; }; + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B01B7F99F500B267D2 /* Cocoa.framework */; }; + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B41B7F9A0700B267D2 /* IOKit.framework */; }; + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */; }; + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */ = {isa = PBXBuildFile; fileRef = 5E8570BE1B7F9D3A00B267D2 /* media */; }; + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */; }; + 5EBFAE801BB493CC0095BC45 /* CDemo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5EBFAE7C1BB493CC0095BC45 /* CDemo.cpp */; }; + 5EBFAE811BB493CC0095BC45 /* CMainMenu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5EBFAE7E1BB493CC0095BC45 /* CMainMenu.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34CC511B7F8E6E00F212E8 /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E34CC741B7F8EEF00F212E8 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libIrrlicht.a; path = ../../lib/OSX/libIrrlicht.a; sourceTree = ""; }; + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 5E8570BE1B7F9D3A00B267D2 /* media */ = {isa = PBXFileReference; lastKnownFileType = folder; name = media; path = ../../media; sourceTree = ""; }; + 5EBFAE7C1BB493CC0095BC45 /* CDemo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CDemo.cpp; sourceTree = ""; }; + 5EBFAE7D1BB493CC0095BC45 /* CDemo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDemo.h; sourceTree = ""; }; + 5EBFAE7E1BB493CC0095BC45 /* CMainMenu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CMainMenu.cpp; sourceTree = ""; }; + 5EBFAE7F1BB493CC0095BC45 /* CMainMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CMainMenu.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570B61B7F9A3200B267D2 /* Cocoa.framework in Frameworks */, + 5E8570B71B7F9A3200B267D2 /* IOKit.framework in Frameworks */, + 5E8570B81B7F9A3200B267D2 /* OpenGL.framework in Frameworks */, + 5E8571181B7FBE8D00B267D2 /* libIrrlicht.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5EBFAE7C1BB493CC0095BC45 /* CDemo.cpp */, + 5EBFAE7D1BB493CC0095BC45 /* CDemo.h */, + 5EBFAE7E1BB493CC0095BC45 /* CMainMenu.cpp */, + 5EBFAE7F1BB493CC0095BC45 /* CMainMenu.h */, + 5E34CC741B7F8EEF00F212E8 /* main.cpp */, + 5E34CC761B7F905600F212E8 /* Libraries */, + 5E34CC521B7F8E6E00F212E8 /* Products */, + 5E34CC771B7F906D00F212E8 /* Resources */, + ); + sourceTree = ""; + }; + 5E34CC521B7F8E6E00F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34CC511B7F8E6E00F212E8 /* Demo.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E34CC761B7F905600F212E8 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E8570B01B7F99F500B267D2 /* Cocoa.framework */, + 5E8570B41B7F9A0700B267D2 /* IOKit.framework */, + 5E8570B21B7F99FE00B267D2 /* OpenGL.framework */, + 5E34CC781B7F90A000F212E8 /* libIrrlicht.a */, + ); + name = Libraries; + sourceTree = ""; + }; + 5E34CC771B7F906D00F212E8 /* Resources */ = { + isa = PBXGroup; + children = ( + 5E8570BE1B7F9D3A00B267D2 /* media */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E34CC501B7F8E6E00F212E8 /* Demo */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "Demo" */; + buildPhases = ( + 5E34CC4D1B7F8E6E00F212E8 /* Sources */, + 5E34CC4E1B7F8E6E00F212E8 /* Frameworks */, + 5E34CC4F1B7F8E6E00F212E8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Demo; + productName = 01.HelloWorld; + productReference = 5E34CC511B7F8E6E00F212E8 /* Demo.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34CC501B7F8E6E00F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Demo" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34CC521B7F8E6E00F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34CC501B7F8E6E00F212E8 /* Demo */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E34CC4F1B7F8E6E00F212E8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E8570BF1B7F9D3A00B267D2 /* media in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34CC4D1B7F8E6E00F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5EBFAE811BB493CC0095BC45 /* CMainMenu.cpp in Sources */, + 5EBFAE801BB493CC0095BC45 /* CDemo.cpp in Sources */, + 5E34CC751B7F8EEF00F212E8 /* main.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + }; + name = Release; + }; + 5E34CC6C1B7F8E6E00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34CC6D1B7F8E6E00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = YES; + DSTROOT = "$(SRCROOT)/../../bin/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../include", + ); + INFOPLIST_FILE = "$(SRCROOT)/../../media/info_osx.plist"; + INSTALL_PATH = /; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../lib/OSX"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Demo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34CC701B7F8E6E00F212E8 /* Build configuration list for PBXNativeTarget "Demo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34CC6C1B7F8E6E00F212E8 /* Debug */, + 5E34CC6D1B7F8E6E00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/examples/Demo/Demo.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme b/examples/Demo/Demo.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme new file mode 100644 index 00000000..e0fffcbd --- /dev/null +++ b/examples/Demo/Demo.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/Demo/Demo_vc10.vcxproj b/examples/Demo/Demo_vc10.vcxproj new file mode 100644 index 00000000..c6d213fe --- /dev/null +++ b/examples/Demo/Demo_vc10.vcxproj @@ -0,0 +1,283 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {6F076455-D955-45D4-9C68-4AD4E45F2D47} + Demo + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Release/Demo.tlb + + + + + MaxSpeed + Default + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\Demo.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Windows + + + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\Release/Demo.tlb + + + + + MaxSpeed + Default + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + $(OutDir)$(TargetName)$(TargetExt) + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Windows + + + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Debug/Demo.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Windows + + + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\Debug/Demo.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Windows + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/Demo/Demo_vc11.vcxproj b/examples/Demo/Demo_vc11.vcxproj new file mode 100644 index 00000000..f1db13d6 --- /dev/null +++ b/examples/Demo/Demo_vc11.vcxproj @@ -0,0 +1,283 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {6F076455-D955-45D4-9C68-4AD4E45F2D47} + Demo + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Release/Demo.tlb + + + + + MaxSpeed + Default + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\Demo.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Windows + + + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\Release/Demo.tlb + + + + + MaxSpeed + Default + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\Demo.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Windows + + + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Debug/Demo.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Windows + + + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\Debug/Demo.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Windows + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/Demo/Demo_vc12.vcxproj b/examples/Demo/Demo_vc12.vcxproj new file mode 100644 index 00000000..320adde3 --- /dev/null +++ b/examples/Demo/Demo_vc12.vcxproj @@ -0,0 +1,283 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {6F076455-D955-45D4-9C68-4AD4E45F2D47} + Demo + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Release/Demo.tlb + + + + + MaxSpeed + Default + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\Demo.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Windows + + + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\Release/Demo.tlb + + + + + MaxSpeed + Default + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + $(OutDir)$(TargetName)$(TargetExt) + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Windows + + + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Debug/Demo.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Windows + + + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\Debug/Demo.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Windows + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/Demo/Demo_vc14.vcxproj b/examples/Demo/Demo_vc14.vcxproj new file mode 100644 index 00000000..cb85feb3 --- /dev/null +++ b/examples/Demo/Demo_vc14.vcxproj @@ -0,0 +1,283 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {6F076455-D955-45D4-9C68-4AD4E45F2D47} + Demo + + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Release/Demo.tlb + + + + + MaxSpeed + Default + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\Demo.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Windows + + + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\Release/Demo.tlb + + + + + MaxSpeed + Default + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + $(OutDir)$(TargetName)$(TargetExt) + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Windows + + + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Debug/Demo.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Windows + + + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\Debug/Demo.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Windows + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/Demo/Makefile b/examples/Demo/Makefile new file mode 100644 index 00000000..706ce7c1 --- /dev/null +++ b/examples/Demo/Makefile @@ -0,0 +1,61 @@ +# 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 + +# Name of the executable created (.exe will be added automatically if necessary) +Target := Demo +# List of source files, separated by spaces +Sources := CDemo.cpp CMainMenu.cpp main.cpp +# Path to Irrlicht directory, should contain include/ and lib/ +IrrlichtHome := ../.. +# Path for the executable. Note that Irrlicht.dll should usually also be there for win32 systems +BinPath = ../../bin/$(SYSTEM) + +# general compiler settings (might need to be set when compiling the lib, too) +CPPFLAGS += -I$(IrrlichtHome)/include -I/usr/X11R6/include +ifndef NDEBUG +CXXFLAGS += -g -Wall +else +CXXFLAGS += -O3 +endif + +# if you enable sound add the proper library for linking +#LDFLAGS += -lIrrKlang +#LDFLAGS += -laudiere +#LDFLAGS += -lSDL_mixer -lSDL + +#default target is Linux +all: all_linux + +# target specific settings +all_linux all_win32 static_win32: LDFLAGS += -L$(IrrlichtHome)/lib/$(SYSTEM) -lIrrlicht +all_linux: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lEGL -lGLESv1_CM -lGLESv2 -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32 clean_win32 static_win32: SYSTEM=Win32-gcc +all_win32 clean_win32 static_win32: SUF=.exe +static_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ +all_win32: LDFLAGS += -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 -lm +static_win32: LDFLAGS += -lgdi32 -lwinspool -lcomdlg32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lopengl32 -lEGL -lGLESv1_CM -lGLESv2 +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = $(BinPath)/$(Target)$(SUF) + +all_linux all_win32 static_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 static_win32 clean clean_linux clean_win32 + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif +#solaris real-time features +ifeq ($(HOSTTYPE), sun4) +LDFLAGS += -lrt +endif diff --git a/examples/Demo/demo.cbp b/examples/Demo/demo.cbp new file mode 100644 index 00000000..4c620406 --- /dev/null +++ b/examples/Demo/demo.cbp @@ -0,0 +1,68 @@ + + + + + + diff --git a/examples/Demo/icon.ico b/examples/Demo/icon.ico new file mode 100644 index 00000000..49f8eabb Binary files /dev/null and b/examples/Demo/icon.ico differ diff --git a/examples/Demo/main.cpp b/examples/Demo/main.cpp new file mode 100644 index 00000000..4cef6e30 --- /dev/null +++ b/examples/Demo/main.cpp @@ -0,0 +1,40 @@ +// This is a Demo of the Irrlicht Engine (c) 2005-2009 by N.Gebhardt. +// This file is not documented. + +#include +#ifdef _IRR_WINDOWS_ +#include +#endif + +#include + +#include "CMainMenu.h" +#include "CDemo.h" + +using namespace irr; + +#ifdef _MSC_VER + +#pragma comment(lib, "Irrlicht.lib") +INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT ) +#else +int main(int argc, char* argv[]) +#endif +{ + CMainMenu menu; + + if (menu.run()) + { + CDemo demo(menu.getFullscreen(), + menu.getMusic(), + menu.getShadows(), + menu.getAdditive(), + menu.getVSync(), + menu.getAntiAliasing(), + menu.getDriverType()); + demo.run(); + } + + return 0; +} + diff --git a/examples/Demo/resource.h b/examples/Demo/resource.h new file mode 100644 index 00000000..eb3b976e --- /dev/null +++ b/examples/Demo/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by resscript.rc +// +#define IDI_ICON1 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/examples/Demo/resscript.rc b/examples/Demo/resscript.rc new file mode 100644 index 00000000..be12eb7f --- /dev/null +++ b/examples/Demo/resscript.rc @@ -0,0 +1,72 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Deutsch (sterreich) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEA) +#ifdef _WIN32 +LANGUAGE LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON DISCARDABLE "icon.ico" +#endif // Deutsch (sterreich) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/examples/Makefile b/examples/Makefile new file mode 100644 index 00000000..e187a005 --- /dev/null +++ b/examples/Makefile @@ -0,0 +1,8 @@ +DIRS = $(wildcard [0123]* Demo) + +all: $(DIRS) + +$(DIRS): + -@cd $@ && make clean && make + +.PHONY: $(DIRS) diff --git a/examples/buildAllExamples.sh b/examples/buildAllExamples.sh new file mode 100755 index 00000000..e9de098a --- /dev/null +++ b/examples/buildAllExamples.sh @@ -0,0 +1,8 @@ +#! /bin/bash +[ -z $1 ] || TARGET=$1 +[ -z $TARGET ] && TARGET=all +for i in [0123]* Demo; do + echo "Building $i"; + pushd $i && make clean $TARGET; + popd; +done diff --git a/examples/whereAreTheBinaries.txt b/examples/whereAreTheBinaries.txt new file mode 100644 index 00000000..d9f7d6ad --- /dev/null +++ b/examples/whereAreTheBinaries.txt @@ -0,0 +1,7 @@ +If you are searching for executeables of the examples and the demo, +you'll find some for Windows in the directory +/bin/win32-VisualStudio. + +For Linux, just go into the directory of the example you want and +execute a simple 'make' after you made the engine from source/Irrlicht. + diff --git a/include/CDynamicMeshBuffer.h b/include/CDynamicMeshBuffer.h new file mode 100644 index 00000000..4424fc86 --- /dev/null +++ b/include/CDynamicMeshBuffer.h @@ -0,0 +1,133 @@ +// Copyright (C) 2008-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_DYNAMIC_MESHBUFFER_H_INCLUDED__ +#define __C_DYNAMIC_MESHBUFFER_H_INCLUDED__ + +#include "IDynamicMeshBuffer.h" + +#include "CVertexBuffer.h" +#include "CIndexBuffer.h" + +namespace irr +{ +namespace scene +{ + + class CDynamicMeshBuffer: public IDynamicMeshBuffer + { + public: + //! constructor + CDynamicMeshBuffer(video::E_VERTEX_TYPE vertexType, video::E_INDEX_TYPE indexType) + : PrimitiveType(EPT_TRIANGLES) + { + VertexBuffer=new CVertexBuffer(vertexType); + IndexBuffer=new CIndexBuffer(indexType); + } + + //! destructor + virtual ~CDynamicMeshBuffer() + { + if (VertexBuffer) + VertexBuffer->drop(); + if (IndexBuffer) + IndexBuffer->drop(); + } + + virtual IVertexBuffer& getVertexBuffer() const _IRR_OVERRIDE_ + { + return *VertexBuffer; + } + + virtual IIndexBuffer& getIndexBuffer() const _IRR_OVERRIDE_ + { + return *IndexBuffer; + } + + virtual void setVertexBuffer(IVertexBuffer *newVertexBuffer) _IRR_OVERRIDE_ + { + if (newVertexBuffer) + newVertexBuffer->grab(); + if (VertexBuffer) + VertexBuffer->drop(); + + VertexBuffer=newVertexBuffer; + } + + virtual void setIndexBuffer(IIndexBuffer *newIndexBuffer) _IRR_OVERRIDE_ + { + if (newIndexBuffer) + newIndexBuffer->grab(); + if (IndexBuffer) + IndexBuffer->drop(); + + IndexBuffer=newIndexBuffer; + } + + //! Get Material of this buffer. + virtual const video::SMaterial& getMaterial() const _IRR_OVERRIDE_ + { + return Material; + } + + //! Get Material of this buffer. + virtual video::SMaterial& getMaterial() _IRR_OVERRIDE_ + { + return Material; + } + + //! Get bounding box + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_ + { + return BoundingBox; + } + + //! Set bounding box + virtual void setBoundingBox( const core::aabbox3df& box) _IRR_OVERRIDE_ + { + BoundingBox = box; + } + + //! Recalculate bounding box + virtual void recalculateBoundingBox() _IRR_OVERRIDE_ + { + if (!getVertexBuffer().size()) + BoundingBox.reset(0,0,0); + else + { + BoundingBox.reset(getVertexBuffer()[0].Pos); + for (u32 i=1; i BoundingBox; + //! Primitive type used for rendering (triangles, lines, ...) + E_PRIMITIVE_TYPE PrimitiveType; + private: + CDynamicMeshBuffer(const CDynamicMeshBuffer&); // = delete in c++11, prevent copying + + IVertexBuffer *VertexBuffer; + IIndexBuffer *IndexBuffer; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/CIndexBuffer.h b/include/CIndexBuffer.h new file mode 100644 index 00000000..69253c34 --- /dev/null +++ b/include/CIndexBuffer.h @@ -0,0 +1,226 @@ +// Copyright (C) 2008-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_INDEX_BUFFER_H_INCLUDED__ +#define __C_INDEX_BUFFER_H_INCLUDED__ + +#include "IIndexBuffer.h" + +namespace irr +{ +namespace scene +{ + + class CIndexBuffer : public IIndexBuffer + { + + class IIndexList + { + public: + virtual ~IIndexList(){}; + + virtual u32 stride() const =0; + virtual u32 size() const =0; + virtual void push_back(const u32 &element) =0; + virtual u32 operator [](u32 index) const =0; + virtual u32 getLast() =0; + virtual void setValue(u32 index, u32 value) =0; + virtual void set_used(u32 usedNow) =0; + virtual void reallocate(u32 new_size) =0; + virtual u32 allocated_size() const =0; + virtual void* pointer() =0; + virtual video::E_INDEX_TYPE getType() const =0; + }; + + template + class CSpecificIndexList : public IIndexList + { + public: + core::array Indices; + + virtual u32 stride() const _IRR_OVERRIDE_ {return sizeof(T);} + + virtual u32 size() const _IRR_OVERRIDE_ {return Indices.size();} + + virtual void push_back(const u32 &element) _IRR_OVERRIDE_ + { + // push const ref due to compiler problem with gcc 4.6, big endian + Indices.push_back((const T&)element); + } + + virtual u32 operator [](u32 index) const _IRR_OVERRIDE_ + { + return (u32)(Indices[index]); + } + + virtual u32 getLast() _IRR_OVERRIDE_ {return (u32)Indices.getLast();} + + virtual void setValue(u32 index, u32 value) _IRR_OVERRIDE_ + { + Indices[index]=(T)value; + } + + virtual void set_used(u32 usedNow) _IRR_OVERRIDE_ + { + Indices.set_used(usedNow); + } + + virtual void reallocate(u32 new_size) _IRR_OVERRIDE_ + { + Indices.reallocate(new_size); + } + + virtual u32 allocated_size() const _IRR_OVERRIDE_ + { + return Indices.allocated_size(); + } + + virtual void* pointer() _IRR_OVERRIDE_ {return Indices.pointer();} + + virtual video::E_INDEX_TYPE getType() const _IRR_OVERRIDE_ + { + if (sizeof(T)==sizeof(u16)) + return video::EIT_16BIT; + else + return video::EIT_32BIT; + } + }; + + public: + IIndexList *Indices; + + CIndexBuffer(video::E_INDEX_TYPE IndexType) :Indices(0), MappingHint(EHM_NEVER), ChangedID(1) + { + setType(IndexType); + } + + CIndexBuffer(const IIndexBuffer &IndexBufferCopy) :Indices(0), MappingHint(EHM_NEVER), ChangedID(1) + { + setType(IndexBufferCopy.getType()); + reallocate(IndexBufferCopy.size()); + + for (u32 n=0;n; + break; + } + case video::EIT_32BIT: + { + NewIndices=new CSpecificIndexList; + break; + } + } + + if (Indices) + { + NewIndices->reallocate( Indices->size() ); + + for(u32 n=0;nsize();++n) + NewIndices->push_back((*Indices)[n]); + + delete Indices; + } + + Indices=NewIndices; + } + + virtual void* getData() _IRR_OVERRIDE_ {return Indices->pointer();} + + virtual video::E_INDEX_TYPE getType() const _IRR_OVERRIDE_ {return Indices->getType();} + + virtual u32 stride() const _IRR_OVERRIDE_ {return Indices->stride();} + + virtual u32 size() const _IRR_OVERRIDE_ + { + return Indices->size(); + } + + virtual void push_back(const u32 &element) _IRR_OVERRIDE_ + { + Indices->push_back(element); + } + + virtual u32 operator [](u32 index) const _IRR_OVERRIDE_ + { + return (*Indices)[index]; + } + + virtual u32 getLast() _IRR_OVERRIDE_ + { + return Indices->getLast(); + } + + virtual void setValue(u32 index, u32 value) _IRR_OVERRIDE_ + { + Indices->setValue(index, value); + } + + virtual void set_used(u32 usedNow) _IRR_OVERRIDE_ + { + Indices->set_used(usedNow); + } + + virtual void reallocate(u32 new_size) _IRR_OVERRIDE_ + { + Indices->reallocate(new_size); + } + + virtual u32 allocated_size() const _IRR_OVERRIDE_ + { + return Indices->allocated_size(); + } + + virtual void* pointer() _IRR_OVERRIDE_ + { + return Indices->pointer(); + } + + //! get the current hardware mapping hint + virtual E_HARDWARE_MAPPING getHardwareMappingHint() const _IRR_OVERRIDE_ + { + return MappingHint; + } + + //! set the hardware mapping hint, for driver + virtual void setHardwareMappingHint( E_HARDWARE_MAPPING NewMappingHint ) _IRR_OVERRIDE_ + { + MappingHint=NewMappingHint; + } + + //! flags the mesh as changed, reloads hardware buffers + virtual void setDirty() _IRR_OVERRIDE_ + { + ++ChangedID; + } + + //! Get the currently used ID for identification of changes. + /** This shouldn't be used for anything outside the VideoDriver. */ + virtual u32 getChangedID() const _IRR_OVERRIDE_ {return ChangedID;} + + E_HARDWARE_MAPPING MappingHint; + u32 ChangedID; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/CMeshBuffer.h b/include/CMeshBuffer.h new file mode 100644 index 00000000..05b8acdf --- /dev/null +++ b/include/CMeshBuffer.h @@ -0,0 +1,319 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __T_MESH_BUFFER_H_INCLUDED__ +#define __T_MESH_BUFFER_H_INCLUDED__ + +#include "irrArray.h" +#include "IMeshBuffer.h" + +namespace irr +{ +namespace scene +{ + //! Template implementation of the IMeshBuffer interface + template + class CMeshBuffer : public IMeshBuffer + { + public: + //! Default constructor for empty meshbuffer + CMeshBuffer() + : ChangedID_Vertex(1), ChangedID_Index(1) + , MappingHint_Vertex(EHM_NEVER), MappingHint_Index(EHM_NEVER) + , PrimitiveType(EPT_TRIANGLES) + { + #ifdef _DEBUG + setDebugName("CMeshBuffer"); + #endif + } + + + //! Get material of this meshbuffer + /** \return Material of this buffer */ + virtual const video::SMaterial& getMaterial() const _IRR_OVERRIDE_ + { + return Material; + } + + + //! Get material of this meshbuffer + /** \return Material of this buffer */ + virtual video::SMaterial& getMaterial() _IRR_OVERRIDE_ + { + return Material; + } + + + //! Get pointer to vertices + /** \return Pointer to vertices. */ + virtual const void* getVertices() const _IRR_OVERRIDE_ + { + return Vertices.const_pointer(); + } + + + //! Get pointer to vertices + /** \return Pointer to vertices. */ + virtual void* getVertices() _IRR_OVERRIDE_ + { + return Vertices.pointer(); + } + + + //! Get number of vertices + /** \return Number of vertices. */ + virtual u32 getVertexCount() const _IRR_OVERRIDE_ + { + return Vertices.size(); + } + + //! Get type of index data which is stored in this meshbuffer. + /** \return Index type of this buffer. */ + virtual video::E_INDEX_TYPE getIndexType() const _IRR_OVERRIDE_ + { + return video::EIT_16BIT; + } + + //! Get pointer to indices + /** \return Pointer to indices. */ + virtual const u16* getIndices() const _IRR_OVERRIDE_ + { + return Indices.const_pointer(); + } + + + //! Get pointer to indices + /** \return Pointer to indices. */ + virtual u16* getIndices() _IRR_OVERRIDE_ + { + return Indices.pointer(); + } + + + //! Get number of indices + /** \return Number of indices. */ + virtual u32 getIndexCount() const _IRR_OVERRIDE_ + { + return Indices.size(); + } + + + //! Get the axis aligned bounding box + /** \return Axis aligned bounding box of this buffer. */ + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_ + { + return BoundingBox; + } + + + //! Set the axis aligned bounding box + /** \param box New axis aligned bounding box for this buffer. */ + //! set user axis aligned bounding box + virtual void setBoundingBox(const core::aabbox3df& box) _IRR_OVERRIDE_ + { + BoundingBox = box; + } + + + //! Recalculate the bounding box. + /** should be called if the mesh changed. */ + virtual void recalculateBoundingBox() _IRR_OVERRIDE_ + { + if (!Vertices.empty()) + { + BoundingBox.reset(Vertices[0].Pos); + const irr::u32 vsize = Vertices.size(); + for (u32 i=1; i(vertices)[i]); + BoundingBox.addInternalPoint(reinterpret_cast(vertices)[i].Pos); + } + + Indices.reallocate(getIndexCount()+numIndices); + for (i=0; igetVertexCount()); + for (i=0; igetVertexCount(); ++i) + { + Vertices.push_back(reinterpret_cast(other->getVertices())[i]); + } + + Indices.reallocate(getIndexCount()+other->getIndexCount()); + for (i=0; igetIndexCount(); ++i) + { + Indices.push_back(other->getIndices()[i]+vertexCount); + } + BoundingBox.addInternalBox(other->getBoundingBox()); + */ + } + + + //! get the current hardware mapping hint + virtual E_HARDWARE_MAPPING getHardwareMappingHint_Vertex() const _IRR_OVERRIDE_ + { + return MappingHint_Vertex; + } + + //! get the current hardware mapping hint + virtual E_HARDWARE_MAPPING getHardwareMappingHint_Index() const _IRR_OVERRIDE_ + { + return MappingHint_Index; + } + + //! set the hardware mapping hint, for driver + virtual void setHardwareMappingHint( E_HARDWARE_MAPPING NewMappingHint, E_BUFFER_TYPE Buffer=EBT_VERTEX_AND_INDEX ) _IRR_OVERRIDE_ + { + if (Buffer==EBT_VERTEX_AND_INDEX || Buffer==EBT_VERTEX) + MappingHint_Vertex=NewMappingHint; + if (Buffer==EBT_VERTEX_AND_INDEX || Buffer==EBT_INDEX) + MappingHint_Index=NewMappingHint; + } + + //! Describe what kind of primitive geometry is used by the meshbuffer + virtual void setPrimitiveType(E_PRIMITIVE_TYPE type) _IRR_OVERRIDE_ + { + PrimitiveType = type; + } + + //! Get the kind of primitive geometry which is used by the meshbuffer + virtual E_PRIMITIVE_TYPE getPrimitiveType() const _IRR_OVERRIDE_ + { + return PrimitiveType; + } + + //! flags the mesh as changed, reloads hardware buffers + virtual void setDirty(E_BUFFER_TYPE Buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_ + { + if (Buffer==EBT_VERTEX_AND_INDEX ||Buffer==EBT_VERTEX) + ++ChangedID_Vertex; + if (Buffer==EBT_VERTEX_AND_INDEX || Buffer==EBT_INDEX) + ++ChangedID_Index; + } + + //! Get the currently used ID for identification of changes. + /** This shouldn't be used for anything outside the VideoDriver. */ + virtual u32 getChangedID_Vertex() const _IRR_OVERRIDE_ {return ChangedID_Vertex;} + + //! Get the currently used ID for identification of changes. + /** This shouldn't be used for anything outside the VideoDriver. */ + virtual u32 getChangedID_Index() const _IRR_OVERRIDE_ {return ChangedID_Index;} + + u32 ChangedID_Vertex; + u32 ChangedID_Index; + + //! hardware mapping hint + E_HARDWARE_MAPPING MappingHint_Vertex; + E_HARDWARE_MAPPING MappingHint_Index; + + //! Material for this meshbuffer. + video::SMaterial Material; + //! Vertices of this buffer + core::array Vertices; + //! Indices into the vertices of this buffer. + core::array Indices; + //! Bounding box of this meshbuffer. + core::aabbox3d BoundingBox; + //! Primitive type used for rendering (triangles, lines, ...) + E_PRIMITIVE_TYPE PrimitiveType; + }; + + //! Standard meshbuffer + typedef CMeshBuffer SMeshBuffer; + //! Meshbuffer with two texture coords per vertex, e.g. for lightmaps + typedef CMeshBuffer SMeshBufferLightMap; + //! Meshbuffer with vertices having tangents stored, e.g. for normal mapping + typedef CMeshBuffer SMeshBufferTangents; +} // end namespace scene +} // end namespace irr + +#endif + + diff --git a/include/CVertexBuffer.h b/include/CVertexBuffer.h new file mode 100644 index 00000000..4d52779b --- /dev/null +++ b/include/CVertexBuffer.h @@ -0,0 +1,210 @@ +// Copyright (C) 2008-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_VERTEX_BUFFER_H_INCLUDED__ +#define __C_VERTEX_BUFFER_H_INCLUDED__ + +#include "IVertexBuffer.h" + + +namespace irr +{ +namespace scene +{ + + class CVertexBuffer : public IVertexBuffer + { + class IVertexList + { + public: + virtual ~IVertexList(){}; + + virtual u32 stride() const =0; + + virtual u32 size() const =0; + + virtual void push_back (const video::S3DVertex &element) =0; + virtual video::S3DVertex& operator [](const u32 index) const =0; + virtual video::S3DVertex& getLast() =0; + virtual void set_used(u32 usedNow) =0; + virtual void reallocate(u32 new_size) =0; + virtual u32 allocated_size() const =0; + virtual video::S3DVertex* pointer() =0; + virtual video::E_VERTEX_TYPE getType() const =0; + }; + + template + class CSpecificVertexList : public IVertexList + { + public: + core::array Vertices; + + virtual u32 stride() const _IRR_OVERRIDE_ {return sizeof(T);} + + virtual u32 size() const _IRR_OVERRIDE_ {return Vertices.size();} + + virtual void push_back (const video::S3DVertex &element) _IRR_OVERRIDE_ + {Vertices.push_back((T&)element);} + + virtual video::S3DVertex& operator [](const u32 index) const _IRR_OVERRIDE_ + {return (video::S3DVertex&)Vertices[index];} + + virtual video::S3DVertex& getLast() _IRR_OVERRIDE_ + {return (video::S3DVertex&)Vertices.getLast();} + + virtual void set_used(u32 usedNow) _IRR_OVERRIDE_ + {Vertices.set_used(usedNow);} + + virtual void reallocate(u32 new_size) _IRR_OVERRIDE_ + {Vertices.reallocate(new_size);} + + virtual u32 allocated_size() const _IRR_OVERRIDE_ + { + return Vertices.allocated_size(); + } + + virtual video::S3DVertex* pointer() _IRR_OVERRIDE_ {return Vertices.pointer();} + + virtual video::E_VERTEX_TYPE getType() const _IRR_OVERRIDE_ {return T::getType();} + }; + + public: + IVertexList *Vertices; + + CVertexBuffer(video::E_VERTEX_TYPE vertexType) : Vertices(0), + MappingHint(EHM_NEVER), ChangedID(1) + { + setType(vertexType); + } + + CVertexBuffer(const IVertexBuffer &VertexBufferCopy) : + Vertices(0), MappingHint(EHM_NEVER), + ChangedID(1) + { + setType(VertexBufferCopy.getType()); + reallocate(VertexBufferCopy.size()); + + for (u32 n=0;n; + break; + } + case video::EVT_2TCOORDS: + { + NewVertices=new CSpecificVertexList; + break; + } + case video::EVT_TANGENTS: + { + NewVertices=new CSpecificVertexList; + break; + } + } + if (Vertices) + { + NewVertices->reallocate( Vertices->size() ); + + for(u32 n=0;nsize();++n) + NewVertices->push_back((*Vertices)[n]); + + delete Vertices; + } + + Vertices=NewVertices; + } + + virtual void* getData() _IRR_OVERRIDE_ {return Vertices->pointer();} + + virtual video::E_VERTEX_TYPE getType() const _IRR_OVERRIDE_ {return Vertices->getType();} + + virtual u32 stride() const _IRR_OVERRIDE_ {return Vertices->stride();} + + virtual u32 size() const _IRR_OVERRIDE_ + { + return Vertices->size(); + } + + virtual void push_back (const video::S3DVertex &element) _IRR_OVERRIDE_ + { + Vertices->push_back(element); + } + + virtual video::S3DVertex& operator [](const u32 index) const _IRR_OVERRIDE_ + { + return (*Vertices)[index]; + } + + virtual video::S3DVertex& getLast() _IRR_OVERRIDE_ + { + return Vertices->getLast(); + } + + virtual void set_used(u32 usedNow) _IRR_OVERRIDE_ + { + Vertices->set_used(usedNow); + } + + virtual void reallocate(u32 new_size) _IRR_OVERRIDE_ + { + Vertices->reallocate(new_size); + } + + virtual u32 allocated_size() const _IRR_OVERRIDE_ + { + return Vertices->allocated_size(); + } + + virtual video::S3DVertex* pointer() _IRR_OVERRIDE_ + { + return Vertices->pointer(); + } + + //! get the current hardware mapping hint + virtual E_HARDWARE_MAPPING getHardwareMappingHint() const _IRR_OVERRIDE_ + { + return MappingHint; + } + + //! set the hardware mapping hint, for driver + virtual void setHardwareMappingHint( E_HARDWARE_MAPPING NewMappingHint ) _IRR_OVERRIDE_ + { + MappingHint=NewMappingHint; + } + + //! flags the mesh as changed, reloads hardware buffers + virtual void setDirty() _IRR_OVERRIDE_ + { + ++ChangedID; + } + + //! Get the currently used ID for identification of changes. + /** This shouldn't be used for anything outside the VideoDriver. */ + virtual u32 getChangedID() const _IRR_OVERRIDE_ {return ChangedID;} + + E_HARDWARE_MAPPING MappingHint; + u32 ChangedID; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/EAttributes.h b/include/EAttributes.h new file mode 100644 index 00000000..51f102b2 --- /dev/null +++ b/include/EAttributes.h @@ -0,0 +1,101 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_ATTRIBUTES_H_INCLUDED__ +#define __E_ATTRIBUTES_H_INCLUDED__ + +namespace irr +{ +namespace io +{ + +//! Types of attributes available for IAttributes +enum E_ATTRIBUTE_TYPE +{ + // integer attribute + EAT_INT = 0, + + // float attribute + EAT_FLOAT, + + // string attribute + EAT_STRING, + + // boolean attribute + EAT_BOOL, + + // enumeration attribute + EAT_ENUM, + + // color attribute + EAT_COLOR, + + // floating point color attribute + EAT_COLORF, + + // 3d vector attribute + EAT_VECTOR3D, + + // 2d position attribute + EAT_POSITION2D, + + // vector 2d attribute + EAT_VECTOR2D, + + // rectangle attribute + EAT_RECT, + + // matrix attribute + EAT_MATRIX, + + // quaternion attribute + EAT_QUATERNION, + + // 3d bounding box + EAT_BBOX, + + // plane + EAT_PLANE, + + // 3d triangle + EAT_TRIANGLE3D, + + // line 2d + EAT_LINE2D, + + // line 3d + EAT_LINE3D, + + // array of stringws attribute + EAT_STRINGWARRAY, + + // array of float + EAT_FLOATARRAY, + + // array of int + EAT_INTARRAY, + + // binary data attribute + EAT_BINARY, + + // texture reference attribute + EAT_TEXTURE, + + // user pointer void* + EAT_USER_POINTER, + + // dimension attribute + EAT_DIMENSION2D, + + // known attribute type count + EAT_COUNT, + + // unknown attribute + EAT_UNKNOWN +}; + +} // end namespace io +} // end namespace irr + +#endif diff --git a/include/ECullingTypes.h b/include/ECullingTypes.h new file mode 100644 index 00000000..eeb3d912 --- /dev/null +++ b/include/ECullingTypes.h @@ -0,0 +1,41 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_CULLING_TYPES_H_INCLUDED__ +#define __E_CULLING_TYPES_H_INCLUDED__ + +#include "irrTypes.h" + +namespace irr +{ +namespace scene +{ + + //! An enumeration for all types of automatic culling for built-in scene nodes + enum E_CULLING_TYPE + { + EAC_OFF = 0, + EAC_BOX = 1, + EAC_FRUSTUM_BOX = 2, + EAC_FRUSTUM_SPHERE = 4, + EAC_OCC_QUERY = 8 + }; + + //! Names for culling type + const c8* const AutomaticCullingNames[] = + { + "false", + "box", // camera box against node box + "frustum_box", // camera frustum against node box + "frustum_sphere", // camera frustum against node sphere + "occ_query", // occlusion query + 0 + }; + +} // end namespace scene +} // end namespace irr + + +#endif // __E_CULLING_TYPES_H_INCLUDED__ + diff --git a/include/EDebugSceneTypes.h b/include/EDebugSceneTypes.h new file mode 100644 index 00000000..987b7902 --- /dev/null +++ b/include/EDebugSceneTypes.h @@ -0,0 +1,50 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_DEBUG_SCENE_TYPES_H_INCLUDED__ +#define __E_DEBUG_SCENE_TYPES_H_INCLUDED__ + +namespace irr +{ +namespace scene +{ + + //! An enumeration for all types of debug data for built-in scene nodes (flags) + enum E_DEBUG_SCENE_TYPE + { + //! No Debug Data ( Default ) + EDS_OFF = 0, + + //! Show Bounding Boxes of SceneNode + EDS_BBOX = 1, + + //! Show Vertex Normals + EDS_NORMALS = 2, + + //! Shows Skeleton/Tags + EDS_SKELETON = 4, + + //! Overlays Mesh Wireframe + EDS_MESH_WIRE_OVERLAY = 8, + + //! Temporary use transparency Material Type + EDS_HALF_TRANSPARENCY = 16, + + //! Show Bounding Boxes of all MeshBuffers + EDS_BBOX_BUFFERS = 32, + + //! EDS_BBOX | EDS_BBOX_BUFFERS + EDS_BBOX_ALL = EDS_BBOX | EDS_BBOX_BUFFERS, + + //! Show all debug infos + EDS_FULL = 0xffffffff + }; + + +} // end namespace scene +} // end namespace irr + + +#endif // __E_DEBUG_SCENE_TYPES_H_INCLUDED__ + diff --git a/include/EDeviceTypes.h b/include/EDeviceTypes.h new file mode 100644 index 00000000..6b67c1af --- /dev/null +++ b/include/EDeviceTypes.h @@ -0,0 +1,70 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_DEVICE_TYPES_H_INCLUDED__ +#define __E_DEVICE_TYPES_H_INCLUDED__ + +namespace irr +{ + + //! An enum for the different device types supported by the Irrlicht Engine. + enum E_DEVICE_TYPE + { + + //! A device native to Microsoft Windows + /** This device uses the Win32 API and works in all versions of Windows. */ + EIDT_WIN32, + + //! A device native to Windows CE devices + /** This device works on Windows Mobile, Pocket PC and Microsoft SmartPhone devices */ + EIDT_WINCE, + + //! A device native to Unix style operating systems. + /** This device uses the X11 windowing system and works in Linux, Solaris, FreeBSD, OSX and + other operating systems which support X11. */ + EIDT_X11, + + //! A device native to Mac OSX + /** This device uses Apple's Cocoa API and works in Mac OSX 10.2 and above. */ + EIDT_OSX, + + //! A device native to the iOS + /** This device should be used with the OpenGL-ES driver. */ + EIDT_IOS, + + //! A device which uses Simple DirectMedia Layer + /** The SDL device works under all platforms supported by SDL but first must be compiled + in by defining the _IRR_COMPILE_WITH_SDL_DEVICE_ macro in IrrCompileConfig.h */ + EIDT_SDL, + + //! A device for raw framebuffer access + /** Best used with embedded devices and mobile systems. + Does not need X11 or other graphical subsystems. + May support hw-acceleration via OpenGL-ES for FBDirect */ + EIDT_FRAMEBUFFER, + + //! A simple text only device supported by all platforms. + /** This device allows applications to run from the command line without opening a window. + It can render the output of the software drivers to the console as ASCII. It only supports + mouse and keyboard in Windows operating systems. */ + EIDT_CONSOLE, + + //! This selection allows Irrlicht to choose the best device from the ones available. + /** If this selection is chosen then Irrlicht will try to use the IrrlichtDevice native + to your operating system. If this is unavailable then the X11, SDL and then console device + will be tried. This ensures that Irrlicht will run even if your platform is unsupported, + although it may not be able to render anything. */ + EIDT_BEST, + + //! A device for Android platforms + /** Best used with embedded devices and mobile systems. + Does not need X11 or other graphical subsystems. + May support hw-acceleration via OpenGL-ES */ + EIDT_ANDROID, + }; + +} // end namespace irr + +#endif // __E_DEVICE_TYPES_H_INCLUDED__ + diff --git a/include/EDriverFeatures.h b/include/EDriverFeatures.h new file mode 100644 index 00000000..6d7fee40 --- /dev/null +++ b/include/EDriverFeatures.h @@ -0,0 +1,157 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_DRIVER_FEATURES_H_INCLUDED__ +#define __E_DRIVER_FEATURES_H_INCLUDED__ + +namespace irr +{ +namespace video +{ + + //! enumeration for querying features of the video driver. + enum E_VIDEO_DRIVER_FEATURE + { + //! Is driver able to render to a surface? + EVDF_RENDER_TO_TARGET = 0, + + //! Is hardware transform and lighting supported? + EVDF_HARDWARE_TL, + + //! Are multiple textures per material possible? + EVDF_MULTITEXTURE, + + //! Is driver able to render with a bilinear filter applied? + EVDF_BILINEAR_FILTER, + + //! Can the driver handle mip maps? + EVDF_MIP_MAP, + + //! Can the driver update mip maps automatically? + EVDF_MIP_MAP_AUTO_UPDATE, + + //! Are stencilbuffers switched on and does the device support stencil buffers? + EVDF_STENCIL_BUFFER, + + //! Is Vertex Shader 1.1 supported? + EVDF_VERTEX_SHADER_1_1, + + //! Is Vertex Shader 2.0 supported? + EVDF_VERTEX_SHADER_2_0, + + //! Is Vertex Shader 3.0 supported? + EVDF_VERTEX_SHADER_3_0, + + //! Is Pixel Shader 1.1 supported? + EVDF_PIXEL_SHADER_1_1, + + //! Is Pixel Shader 1.2 supported? + EVDF_PIXEL_SHADER_1_2, + + //! Is Pixel Shader 1.3 supported? + EVDF_PIXEL_SHADER_1_3, + + //! Is Pixel Shader 1.4 supported? + EVDF_PIXEL_SHADER_1_4, + + //! Is Pixel Shader 2.0 supported? + EVDF_PIXEL_SHADER_2_0, + + //! Is Pixel Shader 3.0 supported? + EVDF_PIXEL_SHADER_3_0, + + //! Are ARB vertex programs v1.0 supported? + EVDF_ARB_VERTEX_PROGRAM_1, + + //! Are ARB fragment programs v1.0 supported? + EVDF_ARB_FRAGMENT_PROGRAM_1, + + //! Is GLSL supported? + EVDF_ARB_GLSL, + + //! Is HLSL supported? + EVDF_HLSL, + + //! Are non-square textures supported? + EVDF_TEXTURE_NSQUARE, + + //! Are non-power-of-two textures supported? + EVDF_TEXTURE_NPOT, + + //! Are framebuffer objects supported? + EVDF_FRAMEBUFFER_OBJECT, + + //! 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, + + //! Supports multiple render targets at once + EVDF_MULTIPLE_RENDER_TARGETS, + + //! Supports separate blend settings for multiple render targets + EVDF_MRT_BLEND, + + //! Supports separate color masks for multiple render targets + EVDF_MRT_COLOR_MASK, + + //! Supports separate blend functions for multiple render targets + EVDF_MRT_BLEND_FUNC, + + //! Supports geometry shaders + EVDF_GEOMETRY_SHADER, + + //! Supports occlusion queries + EVDF_OCCLUSION_QUERY, + + //! Supports polygon offset/depth bias for avoiding z-fighting + EVDF_POLYGON_OFFSET, + + //! Support for different blend functions. Without, only ADD is available + EVDF_BLEND_OPERATIONS, + + //! Support for separate blending for RGB and Alpha. + EVDF_BLEND_SEPARATE, + + //! Support for texture coord transformation via texture matrix + EVDF_TEXTURE_MATRIX, + + //! Support for DXTn compressed textures. + EVDF_TEXTURE_COMPRESSED_DXT, + + //! Support for PVRTC compressed textures. + EVDF_TEXTURE_COMPRESSED_PVRTC, + + //! Support for PVRTC2 compressed textures. + EVDF_TEXTURE_COMPRESSED_PVRTC2, + + //! Support for ETC1 compressed textures. + EVDF_TEXTURE_COMPRESSED_ETC1, + + //! Support for ETC2 compressed textures. + EVDF_TEXTURE_COMPRESSED_ETC2, + + //! Support for cube map textures. + EVDF_TEXTURE_CUBEMAP, + + //! Support for filtering across different faces of the cubemap + EVDF_TEXTURE_CUBEMAP_SEAMLESS, + + //! Support for clamping vertices beyond far-plane to depth instead of capping them. + EVDF_DEPTH_CLAMP, + + //! Only used for counting the elements of this enum + EVDF_COUNT + }; + +} // end namespace video +} // end namespace irr + + +#endif + diff --git a/include/EDriverTypes.h b/include/EDriverTypes.h new file mode 100644 index 00000000..f5a2e929 --- /dev/null +++ b/include/EDriverTypes.h @@ -0,0 +1,101 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_DRIVER_TYPES_H_INCLUDED__ +#define __E_DRIVER_TYPES_H_INCLUDED__ + +#include "irrTypes.h" + +namespace irr +{ +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 visualization. + /** 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. */ + EDT_SOFTWARE, + + //! 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 is longer supported in Irrlicht. You have to go back to Irrlicht 1.8 if you still need that. + DEPRECATED_EDT_DIRECT3D8_NO_LONGER_EXISTS, // keep enum to avoid breaking enumeration order (might be used in ini-files, serialization, etc) + + //! Direct3D 9 device, only available on Win32 platforms. + /** 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. */ + EDT_OPENGL, + + //! OpenGL-ES 1.x driver, for embedded and mobile systems + EDT_OGLES1, + + //! OpenGL-ES 2.x driver, for embedded and mobile systems + /** Supports shaders etc. */ + EDT_OGLES2, + + //! WebGL1 friendly subset of OpenGL-ES 2.x driver for Emscripten + EDT_WEBGL1, + + //! No driver, just for counting the elements + EDT_COUNT + }; + + const c8* const DRIVER_TYPE_NAMES[] = + { + "NullDriver", + "Software Renderer", + "Burning's Video", + "Direct3D 8.1", + "Direct3D 9.0c", + "OpenGL 1.x/2.x/3.x", + "OpenGL ES1", + "OpenGL ES2", + "WebGL 1", + 0 + }; + + const c8* const DRIVER_TYPE_NAMES_SHORT[] = + { + "null", + "software", + "burning", + "d3d8", + "d3d9", + "opengl", + "ogles1", + "ogles2", + "webgl1", + 0 + }; + +} // end namespace video +} // end namespace irr + + +#endif diff --git a/include/EFocusFlags.h b/include/EFocusFlags.h new file mode 100644 index 00000000..c5180024 --- /dev/null +++ b/include/EFocusFlags.h @@ -0,0 +1,38 @@ +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef E_FOCUS_FLAGS_H_INCLUDED__ +#define E_FOCUS_FLAGS_H_INCLUDED__ + +namespace irr +{ +namespace gui +{ + +//! Bitflags for defining the the focus behavior of the gui +// (all names start with SET as we might add REMOVE flags later to control that behavior as well) +enum EFOCUS_FLAG +{ + //! When set the focus changes when the left mouse-button got clicked while over an element + EFF_SET_ON_LMOUSE_DOWN = 0x1, + + //! When set the focus changes when the right mouse-button got clicked while over an element + //! Note that elements usually don't care about right-click and that won't change with this flag + //! This is mostly to allow taking away focus from elements with right-mouse additionally. + EFF_SET_ON_RMOUSE_DOWN = 0x2, + + //! When set the focus changes when the mouse-cursor is over an element + EFF_SET_ON_MOUSE_OVER = 0x4, + + //! When set the focus can be changed with TAB-key combinations. + EFF_SET_ON_TAB = 0x8, + + //! When set it's possible to set the focus to disabled elements. + EFF_CAN_FOCUS_DISABLED = 0x16 +}; + +} // namespace gui +} // namespace irr + +#endif + diff --git a/include/EGUIAlignment.h b/include/EGUIAlignment.h new file mode 100644 index 00000000..85f81b46 --- /dev/null +++ b/include/EGUIAlignment.h @@ -0,0 +1,38 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_GUI_ALIGNMENT_H_INCLUDED__ +#define __E_GUI_ALIGNMENT_H_INCLUDED__ + +namespace irr +{ +namespace gui +{ +enum EGUI_ALIGNMENT +{ + //! Aligned to parent's top or left side (default) + EGUIA_UPPERLEFT=0, + //! Aligned to parent's bottom or right side + EGUIA_LOWERRIGHT, + //! Aligned to the center of parent + EGUIA_CENTER, + //! Stretched to fit parent + EGUIA_SCALE +}; + +//! Names for alignments +const c8* const GUIAlignmentNames[] = +{ + "upperLeft", + "lowerRight", + "center", + "scale", + 0 +}; + +} // namespace gui +} // namespace irr + +#endif // __E_GUI_ALIGNMENT_H_INCLUDED__ + diff --git a/include/EGUIElementTypes.h b/include/EGUIElementTypes.h new file mode 100644 index 00000000..a26a02cf --- /dev/null +++ b/include/EGUIElementTypes.h @@ -0,0 +1,144 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_GUI_ELEMENT_TYPES_H_INCLUDED__ +#define __E_GUI_ELEMENT_TYPES_H_INCLUDED__ + +#include "irrTypes.h" + +namespace irr +{ +namespace gui +{ + +//! List of all basic Irrlicht GUI elements. +/** An IGUIElement returns this when calling IGUIElement::getType(); */ +enum EGUI_ELEMENT_TYPE +{ + //! A button (IGUIButton) + EGUIET_BUTTON = 0, + + //! A check box (IGUICheckBox) + EGUIET_CHECK_BOX, + + //! A combo box (IGUIComboBox) + EGUIET_COMBO_BOX, + + //! A context menu (IGUIContextMenu) + EGUIET_CONTEXT_MENU, + + //! A menu (IGUIMenu) + EGUIET_MENU, + + //! An edit box (IGUIEditBox) + EGUIET_EDIT_BOX, + + //! A file open dialog (IGUIFileOpenDialog) + EGUIET_FILE_OPEN_DIALOG, + + //! A color select open dialog (IGUIColorSelectDialog) + EGUIET_COLOR_SELECT_DIALOG, + + //! A in/out fader (IGUIInOutFader) + EGUIET_IN_OUT_FADER, + + //! An image (IGUIImage) + EGUIET_IMAGE, + + //! A list box (IGUIListBox) + EGUIET_LIST_BOX, + + //! A mesh viewer (IGUIMeshViewer) + EGUIET_MESH_VIEWER, + + //! A message box (IGUIWindow) + EGUIET_MESSAGE_BOX, + + //! A modal screen + EGUIET_MODAL_SCREEN, + + //! A scroll bar (IGUIScrollBar) + EGUIET_SCROLL_BAR, + + //! A spin box (IGUISpinBox) + EGUIET_SPIN_BOX, + + //! A static text (IGUIStaticText) + EGUIET_STATIC_TEXT, + + //! A tab (IGUITab) + EGUIET_TAB, + + //! A tab control + EGUIET_TAB_CONTROL, + + //! A Table + EGUIET_TABLE, + + //! A tool bar (IGUIToolBar) + EGUIET_TOOL_BAR, + + //! A Tree View + EGUIET_TREE_VIEW, + + //! A window + EGUIET_WINDOW, + + //! Unknown type. + EGUIET_ELEMENT, + + //! The root of the GUI + EGUIET_ROOT, + + //! IGUIProfiler + EGUIET_PROFILER, + + //! Not an element, amount of elements in there + EGUIET_COUNT, + + //! This enum is never used, it only forces the compiler to compile this enumeration to 32 bit. + EGUIET_FORCE_32_BIT = 0x7fffffff + +}; + +//! Names for built-in element types +const c8* const GUIElementTypeNames[] = +{ + "button", + "checkBox", + "comboBox", + "contextMenu", + "menu", + "editBox", + "fileOpenDialog", + "colorSelectDialog", + "inOutFader", + "image", + "listBox", + "meshViewer", + "messageBox", + "modalScreen", + "scrollBar", + "spinBox", + "staticText", + "tab", + "tabControl", + "table", + "toolBar", + "treeview", + "window", + "element", + "root", + "profiler", + 0 +}; + +} // end namespace gui +} // end namespace irr + +#endif + + + + diff --git a/include/EHardwareBufferFlags.h b/include/EHardwareBufferFlags.h new file mode 100644 index 00000000..d7594555 --- /dev/null +++ b/include/EHardwareBufferFlags.h @@ -0,0 +1,44 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_HARDWARE_BUFFER_FLAGS_INCLUDED__ +#define __E_HARDWARE_BUFFER_FLAGS_INCLUDED__ + +namespace irr +{ +namespace scene +{ + + enum E_HARDWARE_MAPPING + { + //! Don't store on the hardware + EHM_NEVER=0, + + //! Rarely changed, usually stored completely on the hardware + EHM_STATIC, + + //! Sometimes changed, driver optimized placement + EHM_DYNAMIC, + + //! Always changed, cache optimizing on the GPU + EHM_STREAM + }; + + enum E_BUFFER_TYPE + { + //! Does not change anything + EBT_NONE=0, + //! Change the vertex mapping + EBT_VERTEX, + //! Change the index mapping + EBT_INDEX, + //! Change both vertex and index mapping to the same value + EBT_VERTEX_AND_INDEX + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/EMaterialFlags.h b/include/EMaterialFlags.h new file mode 100644 index 00000000..04ef13ea --- /dev/null +++ b/include/EMaterialFlags.h @@ -0,0 +1,101 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_MATERIAL_FLAGS_H_INCLUDED__ +#define __E_MATERIAL_FLAGS_H_INCLUDED__ + +namespace irr +{ +namespace video +{ + + //! Material flags + enum E_MATERIAL_FLAG + { + //! Draw as wireframe or filled triangles? Default: false + EMF_WIREFRAME = 0x1, + + //! Draw as point cloud or filled triangles? Default: false + EMF_POINTCLOUD = 0x2, + + //! Flat or Gouraud shading? Default: true + EMF_GOURAUD_SHADING = 0x4, + + //! Will this material be lighted? Default: true + EMF_LIGHTING = 0x8, + + //! Is the ZBuffer enabled? Default: true + EMF_ZBUFFER = 0x10, + + //! May be written to the zbuffer or is it readonly. Default: true + /** This flag is ignored, if the material type is a transparent type. */ + EMF_ZWRITE_ENABLE = 0x20, + + //! Is backface culling enabled? Default: true + EMF_BACK_FACE_CULLING = 0x40, + + //! Is frontface culling enabled? Default: false + /** Overrides EMF_BACK_FACE_CULLING if both are enabled. */ + EMF_FRONT_FACE_CULLING = 0x80, + + //! Is bilinear filtering enabled? Default: true + EMF_BILINEAR_FILTER = 0x100, + + //! Is trilinear filtering enabled? Default: false + /** If the trilinear filter flag is enabled, + the bilinear filtering flag is ignored. */ + EMF_TRILINEAR_FILTER = 0x200, + + //! Is anisotropic filtering? Default: false + /** In Irrlicht you can use anisotropic texture filtering in + conjunction with bilinear or trilinear texture filtering + to improve rendering results. Primitives will look less + blurry with this flag switched on. */ + EMF_ANISOTROPIC_FILTER = 0x400, + + //! Is fog enabled? Default: false + EMF_FOG_ENABLE = 0x800, + + //! Normalizes normals. Default: false + /** You can enable this if you need to scale a dynamic lighted + model. Usually, its normals will get scaled too then and it + will get darker. If you enable the EMF_NORMALIZE_NORMALS flag, + the normals will be normalized again, and the model will look + as bright as it should. */ + EMF_NORMALIZE_NORMALS = 0x1000, + + //! Access to all layers texture wrap settings. Overwrites separate layer settings. + /** Note that if you want to change TextureWrapU, TextureWrapV, TextureWrapW + independently, then you can't work with this flag, but will have to set the variables + directly. */ + EMF_TEXTURE_WRAP = 0x2000, + + //! AntiAliasing mode + EMF_ANTI_ALIASING = 0x4000, + + //! ColorMask bits, for enabling the color planes + EMF_COLOR_MASK = 0x8000, + + //! ColorMaterial enum for vertex color interpretation + EMF_COLOR_MATERIAL = 0x10000, + + //! Flag for enabling/disabling mipmap usage + EMF_USE_MIP_MAPS = 0x20000, + + //! Flag for blend operation + EMF_BLEND_OPERATION = 0x40000, + + //! Flag for polygon offset + EMF_POLYGON_OFFSET = 0x80000, + + //! Flag for blend factor + EMF_BLEND_FACTOR = 0x160000 + }; + +} // end namespace video +} // end namespace irr + + +#endif // __E_MATERIAL_FLAGS_H_INCLUDED__ + diff --git a/include/EMaterialTypes.h b/include/EMaterialTypes.h new file mode 100644 index 00000000..cdbd4997 --- /dev/null +++ b/include/EMaterialTypes.h @@ -0,0 +1,234 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_MATERIAL_TYPES_H_INCLUDED__ +#define __E_MATERIAL_TYPES_H_INCLUDED__ + +namespace irr +{ +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. */ + 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. + */ + 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. */ + EMT_LIGHTMAP, + + //! 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. */ + 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 multiplied by 4 + for brightening. Like known in DirectX as D3DTOP_MODULATE4X. */ + EMT_LIGHTMAP_M4, + + //! Like EMT_LIGHTMAP, but also supports dynamic lighting. + EMT_LIGHTMAP_LIGHTING, + + //! Like EMT_LIGHTMAP_M2, but also supports dynamic lighting. + EMT_LIGHTMAP_LIGHTING_M2, + + //! Like EMT_LIGHTMAP_M4, 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 subtract + 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, + + //! 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 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. */ + 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. 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 leaves 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. + 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.*/ + 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. */ + 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. */ + 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. */ + EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA, + + //! 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 like EMT_PARALLAX_MAP_SOLID, but transparent. + /** Using EMT_TRANSPARENT_ADD_COLOR as base material. */ + EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR, + + //! 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. + The blend function is set to SMaterial::MaterialTypeParam with + pack_textureBlendFunc (for 2D) or pack_textureBlendFuncSeparate (for 3D). */ + EMT_ONETEXTURE_BLEND, + + //! This value is not used. It only forces this enumeration to compile to 32 bit. + EMT_FORCE_32BIT = 0x7fffffff + }; + + //! Array holding the built in material type names + const char* const sBuiltInMaterialTypeNames[] = + { + "solid", + "solid_2layer", + "lightmap", + "lightmap_add", + "lightmap_m2", + "lightmap_m4", + "lightmap_light", + "lightmap_light_m2", + "lightmap_light_m4", + "detail_map", + "sphere_map", + "reflection_2layer", + "trans_add", + "trans_alphach", + "trans_alphach_ref", + "trans_vertex_alpha", + "trans_reflection_2layer", + "normalmap_solid", + "normalmap_trans_add", + "normalmap_trans_vertexalpha", + "parallaxmap_solid", + "parallaxmap_trans_add", + "parallaxmap_trans_vertexalpha", + "onetexture_blend", + 0 + }; + +} // end namespace video +} // end namespace irr + + +#endif // __E_MATERIAL_TYPES_H_INCLUDED__ + diff --git a/include/EMeshWriterEnums.h b/include/EMeshWriterEnums.h new file mode 100644 index 00000000..16e1e376 --- /dev/null +++ b/include/EMeshWriterEnums.h @@ -0,0 +1,65 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_MESH_WRITER_ENUMS_H_INCLUDED__ +#define __E_MESH_WRITER_ENUMS_H_INCLUDED__ + +#include "irrTypes.h" + +namespace irr +{ +namespace scene +{ + + //! An enumeration for all supported types of built-in mesh writers + /** A scene mesh writers is represented by a four character code + such as 'irrm' or 'coll' instead of simple numbers, to avoid + name clashes with external mesh writers.*/ + enum EMESH_WRITER_TYPE + { + //! Irrlicht native mesh writer, for static .irrmesh files. + EMWT_IRR_MESH = MAKE_IRR_ID('i','r','r','m'), + + //! COLLADA mesh writer for .dae and .xml files + EMWT_COLLADA = MAKE_IRR_ID('c','o','l','l'), + + //! STL mesh writer for .stl files + EMWT_STL = MAKE_IRR_ID('s','t','l',0), + + //! OBJ mesh writer for .obj files + EMWT_OBJ = MAKE_IRR_ID('o','b','j',0), + + //! PLY mesh writer for .ply files + EMWT_PLY = MAKE_IRR_ID('p','l','y',0), + + //! B3D mesh writer, for static .b3d files + EMWT_B3D = MAKE_IRR_ID('b', '3', 'd', 0) + }; + + + //! flags configuring mesh writing + enum E_MESH_WRITER_FLAGS + { + //! no writer flags + EMWF_NONE = 0, + + //! write lightmap textures out if possible + //! Currently not used by any Irrlicht mesh-writer + // (Note: User meshwriters can still use it) + EMWF_WRITE_LIGHTMAPS = 0x1, + + //! write in a way that consumes less disk space + // (Note: Mainly there for user meshwriters) + EMWF_WRITE_COMPRESSED = 0x2, + + //! write in binary format rather than text + EMWF_WRITE_BINARY = 0x4 + }; + +} // end namespace scene +} // end namespace irr + + +#endif // __E_MESH_WRITER_ENUMS_H_INCLUDED__ + diff --git a/include/EMessageBoxFlags.h b/include/EMessageBoxFlags.h new file mode 100644 index 00000000..06468043 --- /dev/null +++ b/include/EMessageBoxFlags.h @@ -0,0 +1,36 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_MESSAGE_BOX_FLAGS_H_INCLUDED__ +#define __E_MESSAGE_BOX_FLAGS_H_INCLUDED__ + +namespace irr +{ +namespace gui +{ + +//! enumeration for message box layout flags +enum EMESSAGE_BOX_FLAG +{ + //! Flag for the OK button + EMBF_OK = 0x1, + + //! Flag for the cancel button + EMBF_CANCEL = 0x2, + + //! Flag for the yes button + EMBF_YES = 0x4, + + //! Flag for the no button + EMBF_NO = 0x8, + + //! This value is not used. It only forces this enumeration to compile in 32 bit. + EMBF_FORCE_32BIT = 0x7fffffff +}; + +} // namespace gui +} // namespace irr + +#endif + diff --git a/include/EPrimitiveTypes.h b/include/EPrimitiveTypes.h new file mode 100644 index 00000000..ae8f5f50 --- /dev/null +++ b/include/EPrimitiveTypes.h @@ -0,0 +1,61 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_PRIMITIVE_TYPES_H_INCLUDED__ +#define __E_PRIMITIVE_TYPES_H_INCLUDED__ + +namespace irr +{ +namespace scene +{ + + //! Enumeration for all primitive types there are. + enum E_PRIMITIVE_TYPE + { + //! All vertices are non-connected points. + EPT_POINTS=0, + + //! All vertices form a single connected line. + EPT_LINE_STRIP, + + //! Just as LINE_STRIP, but the last and the first vertex is also connected. + EPT_LINE_LOOP, + + //! Every two vertices are connected creating n/2 lines. + EPT_LINES, + + //! After the first two vertices each vertex defines a new triangle. + //! Always the two last and the new one form a new triangle. + EPT_TRIANGLE_STRIP, + + //! After the first two vertices each vertex defines a new triangle. + //! All around the common first vertex. + EPT_TRIANGLE_FAN, + + //! Explicitly set all vertices for each triangle. + EPT_TRIANGLES, + + //! After the first two vertices each further two vertices create a quad with the preceding two. + //! Not supported by Direct3D + EPT_QUAD_STRIP, + + //! Every four vertices create a quad. + //! Not supported by Direct3D + //! Deprecated with newer OpenGL drivers + EPT_QUADS, + + //! Just as LINE_LOOP, but filled. + //! Not supported by Direct3D + //! Deprecated with newer OpenGL drivers + EPT_POLYGON, + + //! The single vertices are expanded to quad billboards on the GPU. + EPT_POINT_SPRITES + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/EReadFileType.h b/include/EReadFileType.h new file mode 100644 index 00000000..b4124ccf --- /dev/null +++ b/include/EReadFileType.h @@ -0,0 +1,34 @@ +// Copyright (C) Michael Zeilfelder +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_READ_FILE_TYPES_H_INCLUDED__ +#define __E_READ_FILE_TYPES_H_INCLUDED__ + +#include "irrTypes.h" + +namespace irr +{ +namespace io +{ + + //! An enumeration for different class types implementing IReadFile + enum EREAD_FILE_TYPE + { + //! CReadFile + ERFT_READ_FILE = MAKE_IRR_ID('r','e','a','d'), + + //! CMemoryReadFile + ERFT_MEMORY_READ_FILE = MAKE_IRR_ID('r','m','e','m'), + + //! CLimitReadFile + ERFT_LIMIT_READ_FILE = MAKE_IRR_ID('r','l','i','m'), + + //! Unknown type + EFIT_UNKNOWN = MAKE_IRR_ID('u','n','k','n') + }; +} // end namespace io +} // end namespace irr + + +#endif diff --git a/include/ESceneNodeAnimatorTypes.h b/include/ESceneNodeAnimatorTypes.h new file mode 100644 index 00000000..f771d128 --- /dev/null +++ b/include/ESceneNodeAnimatorTypes.h @@ -0,0 +1,58 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_SCENE_NODE_ANIMATOR_TYPES_H_INCLUDED__ +#define __E_SCENE_NODE_ANIMATOR_TYPES_H_INCLUDED__ + +namespace irr +{ +namespace scene +{ + + //! An enumeration for all types of built-in scene node animators + enum ESCENE_NODE_ANIMATOR_TYPE + { + //! Fly circle scene node animator + ESNAT_FLY_CIRCLE = 0, + + //! Fly straight scene node animator + ESNAT_FLY_STRAIGHT, + + //! Follow spline scene node animator + ESNAT_FOLLOW_SPLINE, + + //! Rotation scene node animator + ESNAT_ROTATION, + + //! Texture scene node animator + ESNAT_TEXTURE, + + //! Deletion scene node animator + ESNAT_DELETION, + + //! Collision response scene node animator + ESNAT_COLLISION_RESPONSE, + + //! FPS camera animator + ESNAT_CAMERA_FPS, + + //! Maya camera animator + ESNAT_CAMERA_MAYA, + + //! Amount of built-in scene node animators + ESNAT_COUNT, + + //! Unknown scene node animator + ESNAT_UNKNOWN, + + //! This enum is never used, it only forces the compiler to compile this enumeration to 32 bit. + ESNAT_FORCE_32_BIT = 0x7fffffff + }; + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/include/ESceneNodeTypes.h b/include/ESceneNodeTypes.h new file mode 100644 index 00000000..0eeab92a --- /dev/null +++ b/include/ESceneNodeTypes.h @@ -0,0 +1,109 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_SCENE_NODE_TYPES_H_INCLUDED__ +#define __E_SCENE_NODE_TYPES_H_INCLUDED__ + +#include "irrTypes.h" + +namespace irr +{ +namespace scene +{ + + //! An enumeration for all types of built-in scene nodes + /** A scene node type is represented by a four character code + such as 'cube' or 'mesh' instead of simple numbers, to avoid + name clashes with external scene nodes.*/ + enum ESCENE_NODE_TYPE + { + //! of type CSceneManager (note that ISceneManager is not(!) an ISceneNode) + ESNT_SCENE_MANAGER = MAKE_IRR_ID('s','m','n','g'), + + //! simple cube scene node + ESNT_CUBE = MAKE_IRR_ID('c','u','b','e'), + + //! Sphere scene node + ESNT_SPHERE = MAKE_IRR_ID('s','p','h','r'), + + //! Text Scene Node + ESNT_TEXT = MAKE_IRR_ID('t','e','x','t'), + + //! Billboard text scene node + ESNT_BILLBOARD_TEXT = MAKE_IRR_ID('b','t','x','t'), + + //! Water Surface Scene Node + ESNT_WATER_SURFACE = MAKE_IRR_ID('w','a','t','r'), + + //! Terrain Scene Node + ESNT_TERRAIN = MAKE_IRR_ID('t','e','r','r'), + + //! Sky Box Scene Node + ESNT_SKY_BOX = MAKE_IRR_ID('s','k','y','_'), + + //! Sky Dome Scene Node + ESNT_SKY_DOME = MAKE_IRR_ID('s','k','y','d'), + + //! Shadow Volume Scene Node + ESNT_SHADOW_VOLUME = MAKE_IRR_ID('s','h','d','w'), + + //! Octree Scene Node + ESNT_OCTREE = MAKE_IRR_ID('o','c','t','r'), + + //! Mesh Scene Node + ESNT_MESH = MAKE_IRR_ID('m','e','s','h'), + + //! Light Scene Node + ESNT_LIGHT = MAKE_IRR_ID('l','g','h','t'), + + //! Empty Scene Node + ESNT_EMPTY = MAKE_IRR_ID('e','m','t','y'), + + //! Dummy Transformation Scene Node + ESNT_DUMMY_TRANSFORMATION = MAKE_IRR_ID('d','m','m','y'), + + //! Camera Scene Node + ESNT_CAMERA = MAKE_IRR_ID('c','a','m','_'), + + //! Billboard Scene Node + ESNT_BILLBOARD = MAKE_IRR_ID('b','i','l','l'), + + //! Animated Mesh Scene Node + ESNT_ANIMATED_MESH = MAKE_IRR_ID('a','m','s','h'), + + //! Particle System Scene Node + ESNT_PARTICLE_SYSTEM = MAKE_IRR_ID('p','t','c','l'), + + //! Quake3 Shader Scene Node + ESNT_Q3SHADER_SCENE_NODE = MAKE_IRR_ID('q','3','s','h'), + + //! Quake3 Model Scene Node ( has tag to link to ) + ESNT_MD3_SCENE_NODE = MAKE_IRR_ID('m','d','3','_'), + + //! Volume Light Scene Node + ESNT_VOLUME_LIGHT = MAKE_IRR_ID('v','o','l','l'), + + //! Maya Camera Scene Node + /** 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 */ + ESNT_CAMERA_FPS = MAKE_IRR_ID('c','a','m','F'), + + //! Unknown scene node + ESNT_UNKNOWN = MAKE_IRR_ID('u','n','k','n'), + + //! Will match with any scene node when checking types + ESNT_ANY = MAKE_IRR_ID('a','n','y','_') + }; + + + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/include/EShaderTypes.h b/include/EShaderTypes.h new file mode 100644 index 00000000..29eef56a --- /dev/null +++ b/include/EShaderTypes.h @@ -0,0 +1,90 @@ +#ifndef __E_SHADER_TYPES_H_INCLUDED__ +#define __E_SHADER_TYPES_H_INCLUDED__ + +#include "irrTypes.h" + +namespace irr +{ +namespace video +{ + +//! Compile target enumeration for the addHighLevelShaderMaterial() method. +enum E_VERTEX_SHADER_TYPE +{ + EVST_VS_1_1 = 0, + EVST_VS_2_0, + EVST_VS_2_a, + EVST_VS_3_0, + EVST_VS_4_0, + EVST_VS_4_1, + EVST_VS_5_0, + + //! This is not a type, but a value indicating how much types there are. + EVST_COUNT +}; + +//! Names for all vertex shader types, each entry corresponds to a E_VERTEX_SHADER_TYPE entry. +const c8* const VERTEX_SHADER_TYPE_NAMES[] = { + "vs_1_1", + "vs_2_0", + "vs_2_a", + "vs_3_0", + "vs_4_0", + "vs_4_1", + "vs_5_0", + 0 }; + +//! Compile target enumeration for the addHighLevelShaderMaterial() method. +enum E_PIXEL_SHADER_TYPE +{ + EPST_PS_1_1 = 0, + EPST_PS_1_2, + EPST_PS_1_3, + EPST_PS_1_4, + EPST_PS_2_0, + EPST_PS_2_a, + EPST_PS_2_b, + EPST_PS_3_0, + EPST_PS_4_0, + EPST_PS_4_1, + EPST_PS_5_0, + + //! This is not a type, but a value indicating how much types there are. + EPST_COUNT +}; + +//! Names for all pixel shader types, each entry corresponds to a E_PIXEL_SHADER_TYPE entry. +const c8* const PIXEL_SHADER_TYPE_NAMES[] = { + "ps_1_1", + "ps_1_2", + "ps_1_3", + "ps_1_4", + "ps_2_0", + "ps_2_a", + "ps_2_b", + "ps_3_0", + "ps_4_0", + "ps_4_1", + "ps_5_0", + 0 }; + +//! Enum for supported geometry shader types +enum E_GEOMETRY_SHADER_TYPE +{ + EGST_GS_4_0 = 0, + + //! This is not a type, but a value indicating how much types there are. + EGST_COUNT +}; + +//! String names for supported geometry shader types +const c8* const GEOMETRY_SHADER_TYPE_NAMES[] = { + "gs_4_0", + 0 }; + + +} // end namespace video +} // end namespace irr + +#endif // __E_SHADER_TYPES_H_INCLUDED__ + diff --git a/include/ETerrainElements.h b/include/ETerrainElements.h new file mode 100644 index 00000000..5bb48c0a --- /dev/null +++ b/include/ETerrainElements.h @@ -0,0 +1,36 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_TERRAIN_ELEMENTS_H__ +#define __E_TERRAIN_ELEMENTS_H__ + +namespace irr +{ +namespace scene +{ + + //! enumeration for patch sizes specifying the size of patches in the TerrainSceneNode + enum E_TERRAIN_PATCH_SIZE + { + //! patch size of 9, at most, use 4 levels of detail with this patch size. + ETPS_9 = 9, + + //! patch size of 17, at most, use 5 levels of detail with this patch size. + ETPS_17 = 17, + + //! patch size of 33, at most, use 6 levels of detail with this patch size. + ETPS_33 = 33, + + //! patch size of 65, at most, use 7 levels of detail with this patch size. + ETPS_65 = 65, + + //! patch size of 129, at most, use 8 levels of detail with this patch size. + ETPS_129 = 129 + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/EVertexAttributes.h b/include/EVertexAttributes.h new file mode 100644 index 00000000..f1180a80 --- /dev/null +++ b/include/EVertexAttributes.h @@ -0,0 +1,38 @@ +#ifndef __E_VERTEX_ATTRIBUTES_H_INCLUDED__ +#define __E_VERTEX_ATTRIBUTES_H_INCLUDED__ + +namespace irr +{ +namespace video +{ + +//! Enumeration for all vertex attributes there are. +enum E_VERTEX_ATTRIBUTES +{ + EVA_POSITION = 0, + EVA_NORMAL, + EVA_COLOR, + EVA_TCOORD0, + EVA_TCOORD1, + EVA_TANGENT, + EVA_BINORMAL, + EVA_COUNT +}; + +//! Array holding the built in vertex attribute names +const char* const sBuiltInVertexAttributeNames[] = +{ + "inVertexPosition", + "inVertexNormal", + "inVertexColor", + "inTexCoord0", + "inTexCoord1", + "inVertexTangent", + "inVertexBinormal", + 0 +}; + +} // end namespace video +} // end namespace irr + +#endif //__E_VERTEX_ATTRIBUTES_H_INCLUDED__ \ No newline at end of file diff --git a/include/IAnimatedMesh.h b/include/IAnimatedMesh.h new file mode 100644 index 00000000..0d252e8d --- /dev/null +++ b/include/IAnimatedMesh.h @@ -0,0 +1,74 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_ANIMATED_MESH_H_INCLUDED__ +#define __I_ANIMATED_MESH_H_INCLUDED__ + +#include "aabbox3d.h" +#include "IMesh.h" + +namespace irr +{ +namespace scene +{ + //! Interface for an animated mesh. + /** There are already simple implementations of this interface available so + you don't have to implement this interface on your own if you need to: + You might want to use irr::scene::SAnimatedMesh, irr::scene::SMesh, + irr::scene::SMeshBuffer etc. */ + class IAnimatedMesh : public IMesh + { + public: + + //! Gets the frame count of the animated mesh. + /** Note that the play-time is usually getFrameCount()-1 as it stops as soon as the last frame-key is reached. + \return The amount of frames. If the amount is 1, + it is a static, non animated mesh. */ + virtual u32 getFrameCount() const = 0; + + //! Gets the animation speed of the animated mesh. + /** \return The number of frames per second to play the + animation with by default. If the amount is 0, + it is a static, non animated mesh. */ + virtual f32 getAnimationSpeed() const = 0; + + //! Sets the animation speed of the animated mesh. + /** \param fps Number of frames per second to play the + animation with by default. If the amount is 0, + it is not animated. The actual speed is set in the + scene node the mesh is instantiated in.*/ + virtual void setAnimationSpeed(f32 fps) =0; + + //! Returns the IMesh interface for a frame. + /** \param frame: Frame number as zero based index. The maximum + frame number is getFrameCount() - 1; + \param detailLevel: Level of detail. 0 is the lowest, 255 the + highest level of detail. Most meshes will ignore the detail level. + \param startFrameLoop: Because some animated meshes (.MD2) are + blended between 2 static frames, and maybe animated in a loop, + the startFrameLoop and the endFrameLoop have to be defined, to + prevent the animation to be blended between frames which are + outside of this loop. + If startFrameLoop and endFrameLoop are both -1, they are ignored. + \param endFrameLoop: see startFrameLoop. + \return Returns the animated mesh based on a detail level. */ + virtual IMesh* getMesh(s32 frame, s32 detailLevel=255, s32 startFrameLoop=-1, s32 endFrameLoop=-1) = 0; + + //! Returns the type of the animated mesh. + /** In most cases it is not necessary to use this method. + This is useful for making a safe downcast. For example, + if getMeshType() returns EAMT_MD2 it's safe to cast the + IAnimatedMesh to IAnimatedMeshMD2. + \returns Type of the mesh. */ + virtual E_ANIMATED_MESH_TYPE getMeshType() const _IRR_OVERRIDE_ + { + return EAMT_UNKNOWN; + } + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/IAnimatedMeshMD2.h b/include/IAnimatedMeshMD2.h new file mode 100644 index 00000000..6830f37e --- /dev/null +++ b/include/IAnimatedMeshMD2.h @@ -0,0 +1,79 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_ANIMATED_MESH_MD2_H_INCLUDED__ +#define __I_ANIMATED_MESH_MD2_H_INCLUDED__ + +#include "IAnimatedMesh.h" + +namespace irr +{ +namespace scene +{ + + //! Types of standard md2 animations + enum EMD2_ANIMATION_TYPE + { + EMAT_STAND = 0, + EMAT_RUN, + EMAT_ATTACK, + EMAT_PAIN_A, + EMAT_PAIN_B, + EMAT_PAIN_C, + EMAT_JUMP, + EMAT_FLIP, + EMAT_SALUTE, + EMAT_FALLBACK, + EMAT_WAVE, + EMAT_POINT, + EMAT_CROUCH_STAND, + EMAT_CROUCH_WALK, + EMAT_CROUCH_ATTACK, + EMAT_CROUCH_PAIN, + EMAT_CROUCH_DEATH, + EMAT_DEATH_FALLBACK, + EMAT_DEATH_FALLFORWARD, + EMAT_DEATH_FALLBACKSLOW, + EMAT_BOOM, + + //! Not an animation, but amount of animation types. + EMAT_COUNT + }; + + //! Interface for using some special functions of MD2 meshes + class IAnimatedMeshMD2 : public IAnimatedMesh + { + public: + + //! Get frame loop data for a default MD2 animation type. + /** \param l The EMD2_ANIMATION_TYPE to get the frames for. + \param outBegin The returned beginning frame for animation type specified. + \param outEnd The returned ending frame for the animation type specified. + \param outFPS The number of frames per second, this animation should be played at. + \return beginframe, endframe and frames per second for a default MD2 animation type. */ + virtual void getFrameLoop(EMD2_ANIMATION_TYPE l, s32& outBegin, + s32& outEnd, s32& outFPS) const = 0; + + //! Get frame loop data for a special MD2 animation type, identified by name. + /** \param name Name of the animation. + \param outBegin The returned beginning frame for animation type specified. + \param outEnd The returned ending frame for the animation type specified. + \param outFPS The number of frames per second, this animation should be played at. + \return beginframe, endframe and frames per second for a special MD2 animation type. */ + virtual bool getFrameLoop(const c8* name, + s32& outBegin, s32& outEnd, s32& outFPS) const = 0; + + //! Get amount of md2 animations in this file. + virtual s32 getAnimationCount() const = 0; + + //! Get name of md2 animation. + /** \param nr: Zero based index of animation. */ + virtual const c8* getAnimationName(s32 nr) const = 0; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/IAnimatedMeshMD3.h b/include/IAnimatedMeshMD3.h new file mode 100644 index 00000000..08c897d0 --- /dev/null +++ b/include/IAnimatedMeshMD3.h @@ -0,0 +1,304 @@ +// Copyright (C) 2007-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_ANIMATED_MESH_MD3_H_INCLUDED__ +#define __I_ANIMATED_MESH_MD3_H_INCLUDED__ + +#include "IAnimatedMesh.h" +#include "IQ3Shader.h" +#include "quaternion.h" + +namespace irr +{ +namespace scene +{ + + enum eMD3Models + { + EMD3_HEAD = 0, + EMD3_UPPER, + EMD3_LOWER, + EMD3_WEAPON, + EMD3_NUMMODELS + }; + + //! Animation list + enum EMD3_ANIMATION_TYPE + { + // Animations for both lower and upper parts of the player + EMD3_BOTH_DEATH_1 = 0, + EMD3_BOTH_DEAD_1, + EMD3_BOTH_DEATH_2, + EMD3_BOTH_DEAD_2, + EMD3_BOTH_DEATH_3, + EMD3_BOTH_DEAD_3, + + // Animations for the upper part + EMD3_TORSO_GESTURE, + EMD3_TORSO_ATTACK_1, + EMD3_TORSO_ATTACK_2, + EMD3_TORSO_DROP, + EMD3_TORSO_RAISE, + EMD3_TORSO_STAND_1, + EMD3_TORSO_STAND_2, + + // Animations for the lower part + EMD3_LEGS_WALK_CROUCH, + EMD3_LEGS_WALK, + EMD3_LEGS_RUN, + EMD3_LEGS_BACK, + EMD3_LEGS_SWIM, + EMD3_LEGS_JUMP_1, + EMD3_LEGS_LAND_1, + EMD3_LEGS_JUMP_2, + EMD3_LEGS_LAND_2, + EMD3_LEGS_IDLE, + EMD3_LEGS_IDLE_CROUCH, + EMD3_LEGS_TURN, + + //! Not an animation, but amount of animation types. + EMD3_ANIMATION_COUNT + }; + + struct SMD3AnimationInfo + { + //! First frame + s32 first; + //! Last frame + s32 num; + //! Looping frames + s32 looping; + //! Frames per second + s32 fps; + }; + + +// byte-align structures +#include "irrpack.h" + + //! this holds the header info of the MD3 file + struct SMD3Header + { + c8 headerID[4]; //id of file, always "IDP3" + s32 Version; //this is a version number, always 15 + s8 fileName[68];//sometimes left Blank... 65 chars, 32bit aligned == 68 chars + s32 numFrames; //number of KeyFrames + s32 numTags; //number of 'tags' per frame + s32 numMeshes; //number of meshes/skins + s32 numMaxSkins;//maximum number of unique skins used in md3 file. artefact md2 + s32 frameStart; //starting position of frame-structur + s32 tagStart; //starting position of tag-structures + s32 tagEnd; //ending position of tag-structures/starting position of mesh-structures + s32 fileSize; + } PACK_STRUCT; + + //! this holds the header info of an MD3 mesh section + struct SMD3MeshHeader + { + c8 meshID[4]; //id, must be IDP3 + c8 meshName[68]; //name of mesh 65 chars, 32 bit aligned == 68 chars + + s32 numFrames; //number of meshframes in mesh + s32 numShader; //number of skins in mesh + s32 numVertices; //number of vertices + s32 numTriangles; //number of Triangles + + s32 offset_triangles; //starting position of Triangle data, relative to start of Mesh_Header + s32 offset_shaders; //size of header + s32 offset_st; //starting position of texvector data, relative to start of Mesh_Header + s32 vertexStart; //starting position of vertex data,relative to start of Mesh_Header + s32 offset_end; + } PACK_STRUCT; + + + //! Compressed Vertex Data + struct SMD3Vertex + { + s16 position[3]; + u8 normal[2]; + } PACK_STRUCT; + + //! Texture Coordinate + struct SMD3TexCoord + { + f32 u; + f32 v; + } PACK_STRUCT; + + //! Triangle Index + struct SMD3Face + { + s32 Index[3]; + } PACK_STRUCT; + + +// Default alignment +#include "irrunpack.h" + + //! Holding Frame Data for a Mesh + struct SMD3MeshBuffer : public IReferenceCounted + { + SMD3MeshHeader MeshHeader; + + core::stringc Shader; + core::array < s32 > Indices; + core::array < SMD3Vertex > Vertices; + core::array < SMD3TexCoord > Tex; + }; + + //! hold a tag info for connecting meshes + /** Basically its an alternate way to describe a transformation. */ + struct SMD3QuaternionTag + { + virtual ~SMD3QuaternionTag() + { + position.X = 0.f; + } + + // construct copy constructor + SMD3QuaternionTag( const SMD3QuaternionTag & copyMe ) + { + *this = copyMe; + } + + // construct for searching + SMD3QuaternionTag( const core::stringc& name ) + : Name ( name ) {} + + // construct from a position and euler angles in degrees + SMD3QuaternionTag ( const core::vector3df &pos, const core::vector3df &angle ) + : position(pos), rotation(angle * core::DEGTORAD) {} + + // set to matrix + void setto ( core::matrix4 &m ) + { + rotation.getMatrix ( m, position ); + } + + bool operator == ( const SMD3QuaternionTag &other ) const + { + return Name == other.Name; + } + + SMD3QuaternionTag & operator=( const SMD3QuaternionTag & copyMe ) + { + Name = copyMe.Name; + position = copyMe.position; + rotation = copyMe.rotation; + return *this; + } + + core::stringc Name; + core::vector3df position; + core::quaternion rotation; + }; + + //! holds a associative list of named quaternions + struct SMD3QuaternionTagList + { + SMD3QuaternionTagList() + { + Container.setAllocStrategy(core::ALLOC_STRATEGY_SAFE); + } + + // construct copy constructor + SMD3QuaternionTagList(const SMD3QuaternionTagList& copyMe) + { + *this = copyMe; + } + + virtual ~SMD3QuaternionTagList() {} + + SMD3QuaternionTag* get(const core::stringc& name) + { + SMD3QuaternionTag search ( name ); + s32 index = Container.linear_search ( search ); + if ( index >= 0 ) + return &Container[index]; + return 0; + } + + u32 size () const + { + return Container.size(); + } + + void set_used(u32 new_size) + { + s32 diff = (s32) new_size - (s32) Container.allocated_size(); + if ( diff > 0 ) + { + SMD3QuaternionTag e(""); + for ( s32 i = 0; i < diff; ++i ) + Container.push_back(e); + } + } + + const SMD3QuaternionTag& operator[](u32 index) const + { + return Container[index]; + } + + SMD3QuaternionTag& operator[](u32 index) + { + return Container[index]; + } + + void push_back(const SMD3QuaternionTag& other) + { + Container.push_back(other); + } + + SMD3QuaternionTagList& operator = (const SMD3QuaternionTagList & copyMe) + { + Container = copyMe.Container; + return *this; + } + + private: + core::array < SMD3QuaternionTag > Container; + }; + + + //! Holding Frames Buffers and Tag Infos + struct SMD3Mesh: public IReferenceCounted + { + SMD3Mesh () + { + MD3Header.numFrames = 0; + } + + virtual ~SMD3Mesh() + { + for (u32 i=0; idrop(); + } + + core::stringc Name; + core::array Buffer; + SMD3QuaternionTagList TagList; + SMD3Header MD3Header; + }; + + + //! Interface for using some special functions of MD3 meshes + class IAnimatedMeshMD3 : public IAnimatedMesh + { + public: + + //! tune how many frames you want to render in between. + virtual void setInterpolationShift(u32 shift, u32 loopMode) =0; + + //! get the tag list of the mesh. + virtual SMD3QuaternionTagList* getTagList(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) =0; + + //! get the original md3 mesh. + virtual SMD3Mesh* getOriginalMesh() =0; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/IAnimatedMeshSceneNode.h b/include/IAnimatedMeshSceneNode.h new file mode 100644 index 00000000..5a399039 --- /dev/null +++ b/include/IAnimatedMeshSceneNode.h @@ -0,0 +1,233 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_ANIMATED_MESH_SCENE_NODE_H_INCLUDED__ +#define __I_ANIMATED_MESH_SCENE_NODE_H_INCLUDED__ + +#include "ISceneNode.h" +#include "IBoneSceneNode.h" +#include "IAnimatedMeshMD2.h" +#include "IAnimatedMeshMD3.h" + +namespace irr +{ +namespace scene +{ + class IShadowVolumeSceneNode; + + enum E_JOINT_UPDATE_ON_RENDER + { + //! do nothing + EJUOR_NONE = 0, + + //! get joints positions from the mesh (for attached nodes, etc) + EJUOR_READ, + + //! control joint positions in the mesh (eg. ragdolls, or set the animation from animateJoints() ) + EJUOR_CONTROL + }; + + + class IAnimatedMeshSceneNode; + + //! Callback interface for catching events of ended animations. + /** Implement this interface and use + IAnimatedMeshSceneNode::setAnimationEndCallback to be able to + be notified if an animation playback has ended. + **/ + class IAnimationEndCallBack : public virtual IReferenceCounted + { + public: + + //! Will be called when the animation playback has ended. + /** See IAnimatedMeshSceneNode::setAnimationEndCallback for + more information. + \param node: Node of which the animation has ended. */ + virtual void OnAnimationEnd(IAnimatedMeshSceneNode* node) = 0; + }; + + //! Scene node capable of displaying an animated mesh. + class IAnimatedMeshSceneNode : public ISceneNode + { + public: + + //! Constructor + IAnimatedMeshSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) + : ISceneNode(parent, mgr, id, position, rotation, scale) {} + + //! Destructor + virtual ~IAnimatedMeshSceneNode() {} + + //! Sets the current frame number. + /** From now on the animation is played from this frame. + \param frame: Number of the frame to let the animation be started from. + The frame number must be a valid frame number of the IMesh used by this + scene node. Set IAnimatedMesh::getMesh() for details. */ + virtual void setCurrentFrame(f32 frame) = 0; + + //! Sets the frame numbers between the animation is looped. + /** The default is 0 to getFrameCount()-1 of the mesh. + Number of played frames is end-start. + It interpolates toward the last frame but stops when it is reached. + It does not interpolate back to start even when looping. + Looping animations should ensure last and first frame-key are identical. + \param begin: Start frame number of the loop. + \param end: End frame number of the loop. + \return True if successful, false if not. */ + virtual bool setFrameLoop(s32 begin, s32 end) = 0; + + //! Sets the speed with which the animation is played. + /** \param framesPerSecond: Frames per second played. */ + virtual void setAnimationSpeed(f32 framesPerSecond) = 0; + + //! Gets the speed with which the animation is played. + /** \return Frames per second played. */ + virtual f32 getAnimationSpeed() const =0; + + /** The shadow can be rendered using the ZPass or the zfail + method. ZPass is a little bit faster because the shadow volume + creation is easier, but with this method there occur ugly + looking artifacts when the camera is inside the shadow volume. + These error do not occur with the ZFail method, but it can + have trouble with clipping to the far-plane (it usually works + well in OpenGL and fails with other drivers). + \param shadowMesh: Optional custom mesh for shadow volume. + \param id: Id of the shadow scene node. This id can be used to + identify the node later. + \param zfailmethod: If set to true, the shadow will use the + zfail method, if not, zpass is used. + \param infinity: Value used by the shadow volume algorithm to + scale the shadow volume. For zfail shadow volumes on some drivers + only suppport finite shadows, so camera zfar must be larger than + shadow back cap,which is depending on the infinity parameter). + Infinity value also scales by the scaling factors of the model. + If shadows don't show up with zfail then try reducing infinity. + If shadows are cut-off then try increasing infinity. + \return Pointer to the created shadow scene node. This pointer + should not be dropped. See IReferenceCounted::drop() for more + information. */ + virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh=0, + s32 id=-1, bool zfailmethod=true, f32 infinity=1000.0f) = 0; + + //! Get a pointer to a joint in the mesh (if the mesh is a bone based mesh). + /** With this method it is possible to attach scene nodes to + joints for example possible to attach a weapon to the left hand + of an animated model. This example shows how: + \code + ISceneNode* hand = + yourAnimatedMeshSceneNode->getJointNode("LeftHand"); + hand->addChild(weaponSceneNode); + \endcode + Please note that the joint returned by this method may not exist + before this call and the joints in the node were created by it. + \param jointName: Name of the joint. + \return Pointer to the scene node which represents the joint + with the specified name. Returns 0 if the contained mesh is not + an skinned mesh or the name of the joint could not be found. */ + virtual IBoneSceneNode* getJointNode(const c8* jointName)=0; + + //! same as getJointNode(const c8* jointName), but based on id + virtual IBoneSceneNode* getJointNode(u32 jointID) = 0; + + //! Gets joint count. + /** \return Amount of joints in the mesh. */ + virtual u32 getJointCount() const = 0; + + //! Starts a default MD2 animation. + /** With this method it is easily possible to start a Run, + Attack, Die or whatever animation, if the mesh contained in + this scene node is an md2 mesh. Otherwise, nothing happens. + \param anim: An MD2 animation type, which should be played, for + example EMAT_STAND for the standing animation. + \return True if successful, and false if not, for example if + the mesh in the scene node is not a md2 mesh. */ + virtual bool setMD2Animation(EMD2_ANIMATION_TYPE anim) = 0; + + //! Starts a special MD2 animation. + /** With this method it is easily possible to start a Run, + Attack, Die or whatever animation, if the mesh contained in + this scene node is an md2 mesh. Otherwise, nothing happens. + This method uses a character string to identify the animation. + If the animation is a standard md2 animation, you might want to + start this animation with the EMD2_ANIMATION_TYPE enumeration + instead. + \param animationName: Name of the animation which should be + played. + \return Returns true if successful, and false if not, for + example if the mesh in the scene node is not an md2 mesh, or no + animation with this name could be found. */ + virtual bool setMD2Animation(const c8* animationName) = 0; + + //! Returns the currently displayed frame number. + virtual f32 getFrameNr() const = 0; + //! Returns the current start frame number. + virtual s32 getStartFrame() const = 0; + //! Returns the current end frame number. + virtual s32 getEndFrame() const = 0; + + //! Sets looping mode which is on by default. + /** If set to false, animations will not be played looped. */ + virtual void setLoopMode(bool playAnimationLooped) = 0; + + //! returns the current loop mode + /** When true the animations are played looped */ + virtual bool getLoopMode() const = 0; + + //! Sets a callback interface which will be called if an animation playback has ended. + /** Set this to 0 to disable the callback again. + Please note that this will only be called when in non looped + mode, see IAnimatedMeshSceneNode::setLoopMode(). */ + virtual void setAnimationEndCallback(IAnimationEndCallBack* callback=0) = 0; + + //! Sets if the scene node should not copy the materials of the mesh but use them in a read only style. + /** In this way it is possible to change the materials a mesh + causing all mesh scene nodes referencing this mesh to change + too. */ + virtual void setReadOnlyMaterials(bool readonly) = 0; + + //! Returns if the scene node should not copy the materials of the mesh but use them in a read only style + virtual bool isReadOnlyMaterials() const = 0; + + //! Sets a new mesh + virtual void setMesh(IAnimatedMesh* mesh) = 0; + + //! Returns the current mesh + virtual IAnimatedMesh* getMesh(void) = 0; + + //! Get the absolute transformation for a special MD3 Tag if the mesh is a md3 mesh, or the absolutetransformation if it's a normal scenenode + virtual const SMD3QuaternionTag* getMD3TagTransformation( const core::stringc & tagname) = 0; + + //! Set how the joints should be updated on render + virtual void setJointMode(E_JOINT_UPDATE_ON_RENDER mode)=0; + + //! Sets the transition time in seconds + /** Note: This needs to enable joints, and setJointmode set to + EJUOR_CONTROL. You must call animateJoints(), or the mesh will + not animate. */ + virtual void setTransitionTime(f32 Time) =0; + + //! animates the joints in the mesh based on the current frame. + /** Also takes in to account transitions. */ + virtual void animateJoints(bool CalculateAbsolutePositions=true) = 0; + + //! render mesh ignoring its transformation. + /** Culling is unaffected. */ + virtual void setRenderFromIdentity( bool On )=0; + + //! Creates a clone of this scene node and its children. + /** \param newParent An optional new parent. + \param newManager An optional new scene manager. + \return The newly created clone of this node. */ + virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) = 0; + + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/IAttributeExchangingObject.h b/include/IAttributeExchangingObject.h new file mode 100644 index 00000000..5b13cdba --- /dev/null +++ b/include/IAttributeExchangingObject.h @@ -0,0 +1,71 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_ATTRIBUTE_EXCHANGING_OBJECT_H_INCLUDED__ +#define __I_ATTRIBUTE_EXCHANGING_OBJECT_H_INCLUDED__ + +#include "IReferenceCounted.h" + + +namespace irr +{ + +namespace io +{ + +class IAttributes; + +//! Enumeration flags passed through SAttributeReadWriteOptions to the IAttributeExchangingObject object +enum E_ATTRIBUTE_READ_WRITE_FLAGS +{ + //! Serialization/Deserializion is done for an xml file + EARWF_FOR_FILE = 0x00000001, + + //! Serialization/Deserializion is done for an editor property box + EARWF_FOR_EDITOR = 0x00000002, + + //! When writing filenames, relative paths should be used + EARWF_USE_RELATIVE_PATHS = 0x00000004 +}; + + +//! struct holding data describing options +struct SAttributeReadWriteOptions +{ + //! Constructor + SAttributeReadWriteOptions() + : Flags(0), Filename(0) + { + } + + //! Combination of E_ATTRIBUTE_READ_WRITE_FLAGS or other, custom ones + s32 Flags; + + //! Optional filename + const fschar_t* Filename; +}; + + +//! An object which is able to serialize and deserialize its attributes into an attributes object +class IAttributeExchangingObject : virtual public IReferenceCounted +{ +public: + + //! Writes attributes of the object. + /** 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 + scripting languages, editors, debuggers or xml deserialization purposes. */ + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) {} + +}; + +} // end namespace io +} // end namespace irr + +#endif + diff --git a/include/IAttributes.h b/include/IAttributes.h new file mode 100644 index 00000000..507561d8 --- /dev/null +++ b/include/IAttributes.h @@ -0,0 +1,764 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_ATTRIBUTES_H_INCLUDED__ +#define __I_ATTRIBUTES_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "SColor.h" +#include "vector3d.h" +#include "vector2d.h" +#include "line2d.h" +#include "line3d.h" +#include "triangle3d.h" +#include "position2d.h" +#include "rect.h" +#include "dimension2d.h" +#include "matrix4.h" +#include "quaternion.h" +#include "plane3d.h" +#include "triangle3d.h" +#include "line2d.h" +#include "line3d.h" +#include "irrString.h" +#include "irrArray.h" +#include "IXMLReader.h" +#include "IXMLWriter.h" +#include "EAttributes.h" +#include "path.h" + +namespace irr +{ +namespace video +{ + class ITexture; +} // end namespace video +namespace io +{ + +//! Provides a generic interface for attributes and their values and the possibility to serialize them +class IAttributes : public virtual IReferenceCounted +{ +public: + + //! Returns amount of attributes in this collection of attributes. + virtual u32 getAttributeCount() const = 0; + + //! Returns attribute name by index. + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual const c8* getAttributeName(s32 index) const = 0; + + //! Returns the type of an attribute + //! \param attributeName: Name for the attribute + virtual E_ATTRIBUTE_TYPE getAttributeType(const c8* attributeName) const = 0; + + //! Returns attribute type by index. + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual E_ATTRIBUTE_TYPE getAttributeType(s32 index) const = 0; + + //! Returns the type string of the attribute + //! \param attributeName: String for the attribute type + //! \param defaultNotFound Value returned when attributeName was not found + virtual const wchar_t* getAttributeTypeString(const c8* attributeName, const wchar_t* defaultNotFound = L"unknown") const = 0; + + //! Returns the type string of the attribute by index. + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + //! \param defaultNotFound Value returned for an invalid index + virtual const wchar_t* getAttributeTypeString(s32 index, const wchar_t* defaultNotFound = L"unknown") const = 0; + + //! Returns if an attribute with a name exists + virtual bool existsAttribute(const c8* attributeName) const = 0; + + //! Returns attribute index from name, -1 if not found + virtual s32 findAttribute(const c8* attributeName) const = 0; + + //! Removes all attributes + virtual void clear() = 0; + + //! Reads attributes from a xml file. + //! \param reader The XML reader to read from + //! \param readCurrentElementOnly If set to true, reading only works if current element has the name 'attributes' or + //! the name specified using elementName. + //! \param elementName The surrounding element name. If it is null, the default one, "attributes" will be taken. + //! If set to false, the first appearing list of attributes are read. + virtual bool read(io::IXMLReader* reader, bool readCurrentElementOnly=false, const wchar_t* elementName=0) = 0; + + //! Write these attributes into a xml file + //! \param writer: The XML writer to write to + //! \param writeXMLHeader: Writes a header to the XML file, required if at the beginning of the file + //! \param elementName: The surrounding element name. If it is null, the default one, "attributes" will be taken. + virtual bool write(io::IXMLWriter* writer, bool writeXMLHeader=false, const wchar_t* elementName=0) = 0; + + + /* + + Integer Attribute + + */ + + //! Adds an attribute as integer + virtual void addInt(const c8* attributeName, s32 value) = 0; + + //! Sets an attribute as integer value + virtual void setAttribute(const c8* attributeName, s32 value) = 0; + + //! Gets an attribute as integer value + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual s32 getAttributeAsInt(const c8* attributeName, irr::s32 defaultNotFound=0) const = 0; + + //! Gets an attribute as integer value + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual s32 getAttributeAsInt(s32 index) const = 0; + + //! Sets an attribute as integer value + virtual void setAttribute(s32 index, s32 value) = 0; + + /* + + Float Attribute + + */ + + //! Adds an attribute as float + virtual void addFloat(const c8* attributeName, f32 value) = 0; + + //! Sets a attribute as float value + virtual void setAttribute(const c8* attributeName, f32 value) = 0; + + //! Gets an attribute as float value + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual f32 getAttributeAsFloat(const c8* attributeName, irr::f32 defaultNotFound=0.f) const = 0; + + //! Gets an attribute as float value + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual f32 getAttributeAsFloat(s32 index) const = 0; + + //! Sets an attribute as float value + virtual void setAttribute(s32 index, f32 value) = 0; + + /* + + String Attribute + + */ + + //! Adds an attribute as string + virtual void addString(const c8* attributeName, const c8* value) = 0; + + //! 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) = 0; + + //! Gets an attribute as string. + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + //! or defaultNotFound if attribute is not set. + virtual core::stringc getAttributeAsString(const c8* attributeName, const core::stringc& defaultNotFound=core::stringc()) const = 0; + + //! Gets an attribute as string. + //! \param attributeName Name of the attribute to get. + //! \param target Buffer where the string is copied to. + virtual void getAttributeAsString(const c8* attributeName, c8* target) const = 0; + + //! Returns attribute value as string by index. + //! \param index Index value, must be between 0 and getAttributeCount()-1. + virtual core::stringc getAttributeAsString(s32 index) const = 0; + + //! Sets an attribute value as string. + //! \param index Index value, must be between 0 and getAttributeCount()-1. + //! \param value String to which the attribute is set. + virtual void setAttribute(s32 index, const c8* value) = 0; + + // wide strings + + //! Adds an attribute as string + virtual void addString(const c8* attributeName, const wchar_t* value) = 0; + + //! 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) = 0; + + //! Gets an attribute as string. + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + //! or defaultNotFound if attribute is not set. + virtual core::stringw getAttributeAsStringW(const c8* attributeName, const core::stringw& defaultNotFound = core::stringw()) const = 0; + + //! Gets an attribute as string. + //! \param attributeName: Name of the attribute to get. + //! \param target: Buffer where the string is copied to. + virtual void getAttributeAsStringW(const c8* attributeName, wchar_t* target) const = 0; + + //! Returns attribute value as string by index. + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::stringw getAttributeAsStringW(s32 index) const = 0; + + //! Sets an attribute value as string. + //! \param index Index value, must be between 0 and getAttributeCount()-1. + //! \param value String to which the attribute is set. + virtual void setAttribute(s32 index, const wchar_t* value) = 0; + + /* + + Binary Data Attribute + + */ + + //! Adds an attribute as binary data + virtual void addBinary(const c8* attributeName, void* data, s32 dataSizeInBytes) = 0; + + //! Sets an attribute as binary data + virtual void setAttribute(const c8* attributeName, void* data, s32 dataSizeInBytes ) = 0; + + //! Gets an attribute as binary data + /** \param attributeName: Name of the attribute to get. + \param outData Pointer to buffer where data shall be stored. + \param maxSizeInBytes Maximum number of bytes to write into outData. + */ + virtual void getAttributeAsBinaryData(const c8* attributeName, void* outData, s32 maxSizeInBytes) const = 0; + + //! Gets an attribute as binary data + /** \param index: Index value, must be between 0 and getAttributeCount()-1. + \param outData Pointer to buffer where data shall be stored. + \param maxSizeInBytes Maximum number of bytes to write into outData. + */ + virtual void getAttributeAsBinaryData(s32 index, void* outData, s32 maxSizeInBytes) const = 0; + + //! Sets an attribute as binary data + virtual void setAttribute(s32 index, void* data, s32 dataSizeInBytes ) = 0; + + + /* + Array Attribute + */ + + //! Adds an attribute as wide string array + virtual void addArray(const c8* attributeName, const core::array& value) = 0; + + //! 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) = 0; + + //! Gets an attribute as an array of wide strings. + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + //! or defaultNotFound if attribute is not set. + virtual core::array getAttributeAsArray(const c8* attributeName, const core::array& defaultNotFound = core::array()) const = 0; + + //! 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) const = 0; + + //! Sets an attribute as an array of wide strings + virtual void setAttribute(s32 index, const core::array& value) = 0; + + + /* + + Bool Attribute + + */ + + //! Adds an attribute as bool + virtual void addBool(const c8* attributeName, bool value) = 0; + + //! Sets an attribute as boolean value + virtual void setAttribute(const c8* attributeName, bool value) = 0; + + //! Gets an attribute as boolean value + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual bool getAttributeAsBool(const c8* attributeName, bool defaultNotFound=false) const = 0; + + //! Gets an attribute as boolean value + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual bool getAttributeAsBool(s32 index) const = 0; + + //! Sets an attribute as boolean value + virtual void setAttribute(s32 index, bool value) = 0; + + /* + + Enumeration Attribute + + */ + + //! Adds an attribute as enum + virtual void addEnum(const c8* attributeName, const c8* enumValue, const c8* const* enumerationLiterals) = 0; + + //! Adds an attribute as enum + virtual void addEnum(const c8* attributeName, s32 enumValue, const c8* const* enumerationLiterals) = 0; + + //! Sets an attribute as enumeration + virtual void setAttribute(const c8* attributeName, const c8* enumValue, const c8* const* enumerationLiterals) = 0; + + //! Gets an attribute as enumeration + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual const c8* getAttributeAsEnumeration(const c8* attributeName, const c8* defaultNotFound = 0) const = 0; + + //! Gets an attribute as enumeration + /** \param attributeName: Name of the attribute to get. + \param enumerationLiteralsToUse: Use these enumeration literals to get + the index value instead of the set ones. This is useful when the + attribute list maybe was read from an xml file, and only contains the + enumeration string, but no information about its index. + \return Returns value of the attribute previously set by setAttribute() + */ + virtual s32 getAttributeAsEnumeration(const c8* attributeName, const c8* const* enumerationLiteralsToUse, s32 defaultNotFound = -1) const = 0; + + //! Gets an attribute as enumeration + /** \param index: Index value, must be between 0 and getAttributeCount()-1. + \param enumerationLiteralsToUse: Use these enumeration literals to get + the index value instead of the set ones. This is useful when the + attribute list maybe was read from an xml file, and only contains the + enumeration string, but no information about its index. + \param defaultNotFound Value returned when the attribute referenced by the index was not found. + \return Returns value of the attribute previously set by setAttribute() + */ + virtual s32 getAttributeAsEnumeration(s32 index, const c8* const* enumerationLiteralsToUse, s32 defaultNotFound = -1) const = 0; + + //! Gets an attribute as enumeration + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual const c8* getAttributeAsEnumeration(s32 index) const = 0; + + //! Gets the list of enumeration literals of an enumeration attribute + //! \param attributeName Name of the attribute to get. + //! \param outLiterals Set of strings to choose the enum name from. + virtual void getAttributeEnumerationLiteralsOfEnumeration(const c8* attributeName, core::array& outLiterals) const = 0; + + //! Gets the list of enumeration literals of an enumeration attribute + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + //! \param outLiterals Set of strings to choose the enum name from. + virtual void getAttributeEnumerationLiteralsOfEnumeration(s32 index, core::array& outLiterals) const = 0; + + //! Sets an attribute as enumeration + virtual void setAttribute(s32 index, const c8* enumValue, const c8* const* enumerationLiterals) = 0; + + + /* + + SColor Attribute + + */ + + //! Adds an attribute as color + virtual void addColor(const c8* attributeName, video::SColor value) = 0; + + + //! Sets a attribute as color + virtual void setAttribute(const c8* attributeName, video::SColor color) = 0; + + //! Gets an attribute as color + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual video::SColor getAttributeAsColor(const c8* attributeName, const video::SColor& defaultNotFound = video::SColor(0)) const = 0; + + //! Gets an attribute as color + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual video::SColor getAttributeAsColor(s32 index) const = 0; + + //! Sets an attribute as color + virtual void setAttribute(s32 index, video::SColor color) = 0; + + /* + + SColorf Attribute + + */ + + //! Adds an attribute as floating point color + virtual void addColorf(const c8* attributeName, video::SColorf value) = 0; + + //! Sets a attribute as floating point color + virtual void setAttribute(const c8* attributeName, video::SColorf color) = 0; + + //! Gets an attribute as floating point color + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual video::SColorf getAttributeAsColorf(const c8* attributeName, const video::SColorf& defaultNotFound = video::SColorf(0)) const = 0; + + //! Gets an attribute as floating point color + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual video::SColorf getAttributeAsColorf(s32 index) const = 0; + + //! Sets an attribute as floating point color + virtual void setAttribute(s32 index, video::SColorf color) = 0; + + + /* + + Vector3d Attribute + + */ + + //! Adds an attribute as 3d vector + virtual void addVector3d(const c8* attributeName, const core::vector3df& value) = 0; + + //! Sets a attribute as 3d vector + virtual void setAttribute(const c8* attributeName, const core::vector3df& v) = 0; + + //! Gets an attribute as 3d vector + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::vector3df getAttributeAsVector3d(const c8* attributeName, const core::vector3df& defaultNotFound=core::vector3df(0,0,0)) const = 0; + + //! Gets an attribute as 3d vector + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::vector3df getAttributeAsVector3d(s32 index) const = 0; + + //! Sets an attribute as vector + virtual void setAttribute(s32 index, const core::vector3df& v) = 0; + + /* + + Vector2d Attribute + + */ + + //! Adds an attribute as 2d vector + virtual void addVector2d(const c8* attributeName, const core::vector2df& value) = 0; + + //! Sets a attribute as 2d vector + virtual void setAttribute(const c8* attributeName, const core::vector2df& v) = 0; + + //! Gets an attribute as vector + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::vector2df getAttributeAsVector2d(const c8* attributeName, const core::vector2df& defaultNotFound=core::vector2df(0,0)) const = 0; + + //! Gets an attribute as position + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::vector2df getAttributeAsVector2d(s32 index) const = 0; + + //! Sets an attribute as 2d vector + virtual void setAttribute(s32 index, const core::vector2df& v) = 0; + + /* + + Position2d Attribute + + */ + + //! Adds an attribute as 2d position + virtual void addPosition2d(const c8* attributeName, const core::position2di& value) = 0; + + //! Sets a attribute as 2d position + virtual void setAttribute(const c8* attributeName, const core::position2di& v) = 0; + + //! Gets an attribute as position + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::position2di getAttributeAsPosition2d(const c8* attributeName, const core::position2di& defaultNotFound=core::position2di(0,0)) const = 0; + + //! Gets an attribute as position + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::position2di getAttributeAsPosition2d(s32 index) const = 0; + + //! Sets an attribute as 2d position + virtual void setAttribute(s32 index, const core::position2di& v) = 0; + + /* + + Rectangle Attribute + + */ + + //! Adds an attribute as rectangle + virtual void addRect(const c8* attributeName, const core::rect& value) = 0; + + //! Sets an attribute as rectangle + virtual void setAttribute(const c8* attributeName, const core::rect& v) = 0; + + //! Gets an attribute as rectangle + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::rect getAttributeAsRect(const c8* attributeName, const core::rect& defaultNotFound = core::rect()) const = 0; + + //! Gets an attribute as rectangle + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::rect getAttributeAsRect(s32 index) const = 0; + + //! Sets an attribute as rectangle + virtual void setAttribute(s32 index, const core::rect& v) = 0; + + + /* + + Dimension2d Attribute + + */ + + //! Adds an attribute as dimension2d + virtual void addDimension2d(const c8* attributeName, const core::dimension2d& value) = 0; + + //! Sets an attribute as dimension2d + virtual void setAttribute(const c8* attributeName, const core::dimension2d& v) = 0; + + //! Gets an attribute as dimension2d + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::dimension2d getAttributeAsDimension2d(const c8* attributeName, const core::dimension2d& defaultNotFound = core::dimension2d()) const = 0; + + //! Gets an attribute as dimension2d + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::dimension2d getAttributeAsDimension2d(s32 index) const = 0; + + //! Sets an attribute as dimension2d + virtual void setAttribute(s32 index, const core::dimension2d& v) = 0; + + + /* + matrix attribute + */ + + //! Adds an attribute as matrix + virtual void addMatrix(const c8* attributeName, const core::matrix4& v) = 0; + + //! Sets an attribute as matrix + virtual void setAttribute(const c8* attributeName, const core::matrix4& v) = 0; + + //! Gets an attribute as a matrix4 + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::matrix4 getAttributeAsMatrix(const c8* attributeName, const core::matrix4& defaultNotFound=core::matrix4()) const = 0; + + //! Gets an attribute as matrix + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::matrix4 getAttributeAsMatrix(s32 index) const = 0; + + //! Sets an attribute as matrix + virtual void setAttribute(s32 index, const core::matrix4& v) = 0; + + /* + quaternion attribute + + */ + + //! Adds an attribute as quaternion + virtual void addQuaternion(const c8* attributeName, const core::quaternion& v) = 0; + + //! Sets an attribute as quaternion + virtual void setAttribute(const c8* attributeName, const core::quaternion& v) = 0; + + //! Gets an attribute as a quaternion + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::quaternion getAttributeAsQuaternion(const c8* attributeName, const core::quaternion& defaultNotFound=core::quaternion(0,1,0, 0)) const = 0; + + //! Gets an attribute as quaternion + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::quaternion getAttributeAsQuaternion(s32 index) const = 0; + + //! Sets an attribute as quaternion + virtual void setAttribute(s32 index, const core::quaternion& v) = 0; + + /* + + 3d bounding box + + */ + + //! Adds an attribute as axis aligned bounding box + virtual void addBox3d(const c8* attributeName, const core::aabbox3df& v) = 0; + + //! Sets an attribute as axis aligned bounding box + virtual void setAttribute(const c8* attributeName, const core::aabbox3df& v) = 0; + + //! Gets an attribute as a axis aligned bounding box + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::aabbox3df getAttributeAsBox3d(const c8* attributeName, const core::aabbox3df& defaultNotFound=core::aabbox3df(0,0,0, 0,0,0)) const = 0; + + //! Gets an attribute as axis aligned bounding box + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::aabbox3df getAttributeAsBox3d(s32 index) const = 0; + + //! Sets an attribute as axis aligned bounding box + virtual void setAttribute(s32 index, const core::aabbox3df& v) = 0; + + /* + + plane + + */ + + //! Adds an attribute as 3d plane + virtual void addPlane3d(const c8* attributeName, const core::plane3df& v) = 0; + + //! Sets an attribute as 3d plane + virtual void setAttribute(const c8* attributeName, const core::plane3df& v) = 0; + + //! Gets an attribute as a 3d plane + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::plane3df getAttributeAsPlane3d(const c8* attributeName, const core::plane3df& defaultNotFound=core::plane3df(0,0,0, 0,1,0)) const = 0; + + //! Gets an attribute as 3d plane + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::plane3df getAttributeAsPlane3d(s32 index) const = 0; + + //! Sets an attribute as 3d plane + virtual void setAttribute(s32 index, const core::plane3df& v) = 0; + + + /* + + 3d triangle + + */ + + //! Adds an attribute as 3d triangle + virtual void addTriangle3d(const c8* attributeName, const core::triangle3df& v) = 0; + + //! Sets an attribute as 3d trianle + virtual void setAttribute(const c8* attributeName, const core::triangle3df& v) = 0; + + //! Gets an attribute as a 3d triangle + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::triangle3df getAttributeAsTriangle3d(const c8* attributeName, const core::triangle3df& defaultNotFound = core::triangle3df(core::vector3df(0,0,0), core::vector3df(0,0,0), core::vector3df(0,0,0))) const = 0; + + //! Gets an attribute as 3d triangle + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::triangle3df getAttributeAsTriangle3d(s32 index) const = 0; + + //! Sets an attribute as 3d triangle + virtual void setAttribute(s32 index, const core::triangle3df& v) = 0; + + + /* + + line 2d + + */ + + //! Adds an attribute as a 2d line + virtual void addLine2d(const c8* attributeName, const core::line2df& v) = 0; + + //! Sets an attribute as a 2d line + virtual void setAttribute(const c8* attributeName, const core::line2df& v) = 0; + + //! Gets an attribute as a 2d line + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::line2df getAttributeAsLine2d(const c8* attributeName, const core::line2df& defaultNotFound = core::line2df(0,0, 0,0)) const = 0; + + //! Gets an attribute as a 2d line + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::line2df getAttributeAsLine2d(s32 index) const = 0; + + //! Sets an attribute as a 2d line + virtual void setAttribute(s32 index, const core::line2df& v) = 0; + + + /* + + line 3d + + */ + + //! Adds an attribute as a 3d line + virtual void addLine3d(const c8* attributeName, const core::line3df& v) = 0; + + //! Sets an attribute as a 3d line + virtual void setAttribute(const c8* attributeName, const core::line3df& v) = 0; + + //! Gets an attribute as a 3d line + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::line3df getAttributeAsLine3d(const c8* attributeName, const core::line3df& defaultNotFound=core::line3df(0,0,0, 0,0,0)) const = 0; + + //! Gets an attribute as a 3d line + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::line3df getAttributeAsLine3d(s32 index) const = 0; + + //! Sets an attribute as a 3d line + virtual void setAttribute(s32 index, const core::line3df& v) = 0; + + + /* + + Texture Attribute + + */ + + //! Adds an attribute as texture reference + virtual void addTexture(const c8* attributeName, video::ITexture* texture, const io::path& filename = "") = 0; + + //! Sets an attribute as texture reference + virtual void setAttribute(const c8* attributeName, video::ITexture* texture, const io::path& filename = "") = 0; + + //! Gets an attribute as texture reference + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + virtual video::ITexture* getAttributeAsTexture(const c8* attributeName, video::ITexture* defaultNotFound=0) const = 0; + + //! Gets an attribute as texture reference + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual video::ITexture* getAttributeAsTexture(s32 index) const = 0; + + //! Sets an attribute as texture reference + virtual void setAttribute(s32 index, video::ITexture* texture, const io::path& filename = "") = 0; + + + /* + + User Pointer Attribute + + */ + + //! Adds an attribute as user pointer + virtual void addUserPointer(const c8* attributeName, void* userPointer) = 0; + + //! Sets an attribute as user pointer + virtual void setAttribute(const c8* attributeName, void* userPointer) = 0; + + //! Gets an attribute as user pointer + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + virtual void* getAttributeAsUserPointer(const c8* attributeName, void* defaultNotFound = 0) const = 0; + + //! Gets an attribute as user pointer + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual void* getAttributeAsUserPointer(s32 index) const = 0; + + //! Sets an attribute as user pointer + virtual void setAttribute(s32 index, void* userPointer) = 0; + +}; + +} // end namespace io +} // end namespace irr + +#endif + + + diff --git a/include/IBillboardSceneNode.h b/include/IBillboardSceneNode.h new file mode 100644 index 00000000..63846561 --- /dev/null +++ b/include/IBillboardSceneNode.h @@ -0,0 +1,84 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_BILLBOARD_SCENE_NODE_H_INCLUDED__ +#define __I_BILLBOARD_SCENE_NODE_H_INCLUDED__ + +#include "ISceneNode.h" + +namespace irr +{ +namespace scene +{ + class ICameraSceneNode; + +//! A billboard scene node. +/** A billboard is like a 3d sprite: A 2d element, +which always looks to the camera. It is usually used for explosions, fire, +lensflares, particles and things like that. +*/ +class IBillboardSceneNode : public ISceneNode +{ +public: + + //! Constructor + IBillboardSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position = core::vector3df(0,0,0)) + : ISceneNode(parent, mgr, id, position) {} + + //! Sets the size of the billboard, making it rectangular. + virtual void setSize(const core::dimension2d& size) = 0; + + //! Sets the size of the billboard with independent widths of the bottom and top edges. + /** \param[in] height The height of the billboard. + \param[in] bottomEdgeWidth The width of the bottom edge of the billboard. + \param[in] topEdgeWidth The width of the top edge of the billboard. + */ + virtual void setSize(f32 height, f32 bottomEdgeWidth, f32 topEdgeWidth) = 0; + + //! Returns the size of the billboard. + /** This will return the width of the bottom edge of the billboard. + Use getWidths() to retrieve the bottom and top edges independently. + \return Size of the billboard. + */ + virtual const core::dimension2d& getSize() const = 0; + + //! Gets the size of the the billboard and handles independent top and bottom edge widths correctly. + /** \param[out] height The height of the billboard. + \param[out] bottomEdgeWidth The width of the bottom edge of the billboard. + \param[out] topEdgeWidth The width of the top edge of the billboard. + */ + virtual void getSize(f32& height, f32& bottomEdgeWidth, f32& topEdgeWidth) const =0; + + //! Set the color of all vertices of the billboard + /** \param[in] overallColor Color to set */ + virtual void setColor(const video::SColor& overallColor) = 0; + + //! Set the color of the top and bottom vertices of the billboard + /** \param[in] topColor Color to set the top vertices + \param[in] bottomColor Color to set the bottom vertices */ + virtual void setColor(const video::SColor& topColor, + const video::SColor& bottomColor) = 0; + + //! Gets the color of the top and bottom vertices of the billboard + /** \param[out] topColor Stores the color of the top vertices + \param[out] bottomColor Stores the color of the bottom vertices */ + virtual void getColor(video::SColor& topColor, + video::SColor& bottomColor) const = 0; + + //! Get the real boundingbox used by the billboard, which can depend on the active camera. + /** The boundingbox returned will use absolute coordinates. + The billboard orients itself toward the camera and some only update in render(). + So we don't know the real boundingboxes before that. Which would be too late for culling. + That is why the usual getBoundingBox will return a "safe" boundingbox which is guaranteed + to contain the billboard. While this function can return the real one. */ + virtual const core::aabbox3d& getTransformedBillboardBoundingBox(const irr::scene::ICameraSceneNode* camera) = 0; +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/include/IBillboardTextSceneNode.h b/include/IBillboardTextSceneNode.h new file mode 100644 index 00000000..0526b63f --- /dev/null +++ b/include/IBillboardTextSceneNode.h @@ -0,0 +1,78 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_BILLBOARD_TEXT_SCENE_NODE_H_INCLUDED__ +#define __I_BILLBOARD_TEXT_SCENE_NODE_H_INCLUDED__ + +#include "IBillboardSceneNode.h" + +namespace irr +{ + +namespace gui +{ + class IGUIFont; +} + +namespace scene +{ + +//! A billboard text scene node. +/** Acts like a billboard which displays the currently set text. + Due to the exclusion of RTTI in Irrlicht we have to avoid multiple + inheritance. Hence, changes to the ITextSceneNode interface have + to be copied here manually. +*/ +class IBillboardTextSceneNode : public IBillboardSceneNode +{ +public: + + //! Constructor + IBillboardTextSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position = core::vector3df(0,0,0)) + : IBillboardSceneNode(parent, mgr, id, position) {} + + //! Sets the size of the billboard. + virtual void setSize(const core::dimension2d& size) = 0; + + //! Returns the size of the billboard. + virtual const core::dimension2d& getSize() const = 0; + + //! Set the color of all vertices of the billboard + /** \param overallColor: the color to set */ + virtual void setColor(const video::SColor & overallColor) = 0; + + //! Set the color of the top and bottom vertices of the billboard + /** \param topColor: the color to set the top vertices + \param bottomColor: the color to set the bottom vertices */ + virtual void setColor(const video::SColor & topColor, const video::SColor & bottomColor) = 0; + + //! Gets the color of the top and bottom vertices of the billboard + /** \param topColor: stores the color of the top vertices + \param bottomColor: stores the color of the bottom vertices */ + virtual void getColor(video::SColor & topColor, video::SColor & bottomColor) const = 0; + + //! sets the text string + virtual void setText(const wchar_t* text) = 0; + + //! get the text string + virtual const wchar_t* getText() const = 0; + + //! sets the color of the text + //! You can use setColor instead which does the same + virtual void setTextColor(video::SColor color) + { + setColor(color); + } + + //! Get the font used to draw the text + virtual gui::IGUIFont* getFont() const = 0; +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/include/IBoneSceneNode.h b/include/IBoneSceneNode.h new file mode 100644 index 00000000..4032bb0a --- /dev/null +++ b/include/IBoneSceneNode.h @@ -0,0 +1,108 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_BONE_SCENE_NODE_H_INCLUDED__ +#define __I_BONE_SCENE_NODE_H_INCLUDED__ + +#include "ISceneNode.h" + +namespace irr +{ +namespace scene +{ + + //! Enumeration for different bone animation modes + enum E_BONE_ANIMATION_MODE + { + //! The bone is usually animated, unless it's parent is not animated + EBAM_AUTOMATIC=0, + + //! The bone is animated by the skin, if it's parent is not animated then animation will resume from this bone onward + EBAM_ANIMATED, + + //! The bone is not animated by the skin + EBAM_UNANIMATED, + + //! Not an animation mode, just here to count the available modes + EBAM_COUNT + + }; + + enum E_BONE_SKINNING_SPACE + { + //! local skinning, standard + EBSS_LOCAL=0, + + //! global skinning + EBSS_GLOBAL, + + EBSS_COUNT + }; + + //! Names for bone animation modes + const c8* const BoneAnimationModeNames[] = + { + "automatic", + "animated", + "unanimated", + 0, + }; + + + //! Interface for bones used for skeletal animation. + /** Used with ISkinnedMesh and IAnimatedMeshSceneNode. */ + class IBoneSceneNode : public ISceneNode + { + public: + + IBoneSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id=-1) : + ISceneNode(parent, mgr, id),positionHint(-1),scaleHint(-1),rotationHint(-1) { } + + //! Get the name of the bone + /** \deprecated Use getName instead. This method may be removed by Irrlicht 1.9 */ + _IRR_DEPRECATED_ virtual const c8* getBoneName() const { return getName(); } + + //! Get the index of the bone + virtual u32 getBoneIndex() const = 0; + + //! Sets the animation mode of the bone. + /** \return True if successful. (Unused) */ + virtual bool setAnimationMode(E_BONE_ANIMATION_MODE mode) = 0; + + //! Gets the current animation mode of the bone + virtual E_BONE_ANIMATION_MODE getAnimationMode() const = 0; + + //! Get the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const = 0; + + //! Returns the relative transformation of the scene node. + //virtual core::matrix4 getRelativeTransformation() const = 0; + + //! The animation method. + virtual void OnAnimate(u32 timeMs) =0; + + //! The render method. + /** Does nothing as bones are not visible. */ + virtual void render() _IRR_OVERRIDE_ { } + + //! How the relative transformation of the bone is used + virtual void setSkinningSpace( E_BONE_SKINNING_SPACE space ) =0; + + //! How the relative transformation of the bone is used + virtual E_BONE_SKINNING_SPACE getSkinningSpace() const =0; + + //! Updates the absolute position based on the relative and the parents position + virtual void updateAbsolutePositionOfAllChildren()=0; + + s32 positionHint; + s32 scaleHint; + s32 rotationHint; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/ICameraSceneNode.h b/include/ICameraSceneNode.h new file mode 100644 index 00000000..2743dae8 --- /dev/null +++ b/include/ICameraSceneNode.h @@ -0,0 +1,210 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_CAMERA_SCENE_NODE_H_INCLUDED__ +#define __I_CAMERA_SCENE_NODE_H_INCLUDED__ + +#include "ISceneNode.h" +#include "IEventReceiver.h" + +namespace irr +{ +namespace scene +{ + struct SViewFrustum; + + //! Scene Node which is a (controllable) camera. + /** The whole scene will be rendered from the cameras point of view. + Because the ICameraSceneNode is a SceneNode, it can be attached to any + other scene node, and will follow its parents movement, rotation and so + on. + */ + class ICameraSceneNode : public ISceneNode, public IEventReceiver + { + public: + + //! Constructor + ICameraSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f,1.0f,1.0f)) + : ISceneNode(parent, mgr, id, position, rotation, scale), IsOrthogonal(false) {} + + //! Sets the projection matrix of the camera. + /** The core::matrix4 class has some methods to build a + projection matrix. e.g: + core::matrix4::buildProjectionMatrixPerspectiveFovLH. + Note that the matrix will only stay as set by this method until + one of the following Methods are called: setNearValue, + setFarValue, setAspectRatio, setFOV. + NOTE: The frustum is not updated before render() is called + unless you explicitly call updateMatrices() + \param projection The new projection matrix of the camera. + \param isOrthogonal Set this to true if the matrix is an + orthogonal one (e.g. from matrix4::buildProjectionMatrixOrtho). + */ + virtual void setProjectionMatrix(const core::matrix4& projection, bool isOrthogonal=false) =0; + + //! Gets the current projection matrix of the camera. + /** \return The current projection matrix of the camera. */ + virtual const core::matrix4& getProjectionMatrix() const =0; + + //! Gets the current view matrix of the camera. + /** \return The current view matrix of the camera. */ + virtual const core::matrix4& getViewMatrix() const =0; + + //! Sets a custom view matrix affector. + /** The matrix passed here, will be multiplied with the view + matrix when it gets updated. This allows for custom camera + setups like, for example, a reflection camera. + \param affector The affector matrix. */ + virtual void setViewMatrixAffector(const core::matrix4& affector) =0; + + //! Get the custom view matrix affector. + /** \return The affector matrix. */ + virtual const core::matrix4& getViewMatrixAffector() const =0; + + //! It is possible to send mouse and key events to the camera. + /** Most cameras may ignore this input, but camera scene nodes + which are created for example with + ISceneManager::addCameraSceneNodeMaya or + ISceneManager::addCameraSceneNodeFPS, may want to get + this input for changing their position, look at target or + whatever. */ + virtual bool OnEvent(const SEvent& event) =0; + + //! Sets the look at target of the camera + /** If the camera's target and rotation are bound ( @see + bindTargetAndRotation() ) then calling this will also change + the camera's scene node rotation to match the target. + Note that setTarget uses the current absolute position + internally, so if you changed setPosition since last rendering you must + call updateAbsolutePosition before using this function. + \param pos Look at target of the camera, in world co-ordinates. */ + virtual void setTarget(const core::vector3df& pos) =0; + + //! Sets the rotation of the node. + /** This only modifies the relative rotation of the node. + If the camera's target and rotation are bound ( @see + bindTargetAndRotation() ) then calling this will also change + the camera's target to match the rotation. + \param rotation New rotation of the node in degrees. */ + virtual void setRotation(const core::vector3df& rotation) =0; + + //! Gets the current look at target of the camera + /** \return The current look at target of the camera, in world co-ordinates */ + virtual const core::vector3df& getTarget() const =0; + + //! Sets the up vector of the camera. + /** \param pos: New upvector of the camera. */ + virtual void setUpVector(const core::vector3df& pos) =0; + + //! Gets the up vector of the camera. + /** \return The up vector of the camera, in world space. */ + virtual const core::vector3df& getUpVector() const =0; + + //! Gets the value of the near plane of the camera. + /** \return The value of the near plane of the camera. */ + virtual f32 getNearValue() const =0; + + //! Gets the value of the far plane of the camera. + /** \return The value of the far plane of the camera. */ + virtual f32 getFarValue() const =0; + + //! Gets the aspect ratio of the camera. + /** \return The aspect ratio of the camera. */ + virtual f32 getAspectRatio() const =0; + + //! Gets the field of view of the camera. + /** \return The field of view of the camera in radians. */ + virtual f32 getFOV() const =0; + + //! Sets the value of the near clipping plane. (default: 1.0f) + /** \param zn: New z near value. */ + virtual void setNearValue(f32 zn) =0; + + //! Sets the value of the far clipping plane (default: 2000.0f) + /** \param zf: New z far value. */ + virtual void setFarValue(f32 zf) =0; + + //! Sets the aspect ratio (default: 4.0f / 3.0f) + /** \param aspect: New aspect ratio. */ + virtual void setAspectRatio(f32 aspect) =0; + + //! Sets the field of view (Default: PI / 2.5f) + /** \param fovy: New field of view in radians. */ + virtual void setFOV(f32 fovy) =0; + + //! Get the view frustum. + /** \return The current view frustum. */ + virtual const SViewFrustum* getViewFrustum() const =0; + + //! Disables or enables the camera to get key or mouse inputs. + /** If this is set to true, the camera will respond to key + inputs otherwise not. */ + virtual void setInputReceiverEnabled(bool enabled) =0; + + //! Checks if the input receiver of the camera is currently enabled. + virtual bool isInputReceiverEnabled() const =0; + + //! Checks if a camera is orthogonal. + virtual bool isOrthogonal() const + { + return IsOrthogonal; + } + + //! Binds the camera scene node's rotation to its target position and vice versa, or unbinds them. + /** When bound, calling setRotation() will update the camera's + target position to be along its +Z axis, and likewise calling + 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 bound True to bind the camera's scene node rotation + and targeting, false to unbind them. + @see getTargetAndRotationBinding() */ + virtual void bindTargetAndRotation(bool bound) =0; + + //! Updates the matrices without uploading them to the driver + virtual void updateMatrices() = 0; + + //! Queries if the camera scene node's rotation and its target position are bound together. + /** @see bindTargetAndRotation() */ + virtual bool getTargetAndRotationBinding(void) const =0; + + //! Writes attributes of the camera node + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_ + { + ISceneNode::serializeAttributes(out, options); + + if (!out) + return; + out->addBool("IsOrthogonal", IsOrthogonal); + } + + //! Reads attributes of the camera node + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_ + { + ISceneNode::deserializeAttributes(in, options); + if (!in) + return; + + if ( in->findAttribute("IsOrthogonal") ) + IsOrthogonal = in->getAttributeAsBool("IsOrthogonal"); + } + + protected: + + void cloneMembers(const ICameraSceneNode* toCopyFrom) + { + IsOrthogonal = toCopyFrom->IsOrthogonal; + } + + bool IsOrthogonal; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/IColladaMeshWriter.h b/include/IColladaMeshWriter.h new file mode 100644 index 00000000..a8c6dd24 --- /dev/null +++ b/include/IColladaMeshWriter.h @@ -0,0 +1,456 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_I_COLLADA_MESH_WRITER_H_INCLUDED__ +#define __IRR_I_COLLADA_MESH_WRITER_H_INCLUDED__ + +#include "IMeshWriter.h" +#include "ISceneNode.h" +#include "IAnimatedMesh.h" +#include "SMaterial.h" + +namespace irr +{ +namespace io +{ + class IWriteFile; +} // end namespace io + +namespace scene +{ + //! Lighting models - more or less the way Collada categorizes materials + enum E_COLLADA_TECHNIQUE_FX + { + //! Blinn-phong which is default for opengl and dx fixed function pipelines. + //! But several well-known renderers don't support it and prefer phong. + ECTF_BLINN, + //! Phong shading, default in many external renderers. + ECTF_PHONG, + //! diffuse shaded surface that is independent of lighting. + ECTF_LAMBERT, + // constantly shaded surface that is independent of lighting. + ECTF_CONSTANT + }; + + //! How to interpret the opacity in collada + enum E_COLLADA_TRANSPARENT_FX + { + //! default - only alpha channel of color or texture is used. + ECOF_A_ONE = 0, + + //! Alpha values for each RGB channel of color or texture are used. + ECOF_RGB_ZERO = 1 + }; + + //! Color names collada uses in it's color samplers + enum E_COLLADA_COLOR_SAMPLER + { + ECCS_DIFFUSE, + ECCS_AMBIENT, + ECCS_EMISSIVE, + ECCS_SPECULAR, + ECCS_TRANSPARENT, + ECCS_REFLECTIVE + }; + + //! Irrlicht colors which can be mapped to E_COLLADA_COLOR_SAMPLER values + enum E_COLLADA_IRR_COLOR + { + //! Don't write this element at all + ECIC_NONE, + + //! Check IColladaMeshWriterProperties for custom color + ECIC_CUSTOM, + + //! Use SMaterial::DiffuseColor + ECIC_DIFFUSE, + + //! Use SMaterial::AmbientColor + ECIC_AMBIENT, + + //! Use SMaterial::EmissiveColor + ECIC_EMISSIVE, + + //! Use SMaterial::SpecularColor + ECIC_SPECULAR + }; + + //! Control when geometry elements are created + enum E_COLLADA_GEOMETRY_WRITING + { + //! Default - write each mesh exactly once to collada. Optimal but will not work with many tools. + ECGI_PER_MESH, + + //! Write each mesh as often as it's used with different materials-names in the scene. + //! Material names which are used here are created on export, so using the IColladaMeshWriterNames + //! interface you have some control over how many geometries are written. + ECGI_PER_MESH_AND_MATERIAL + }; + + //! Callback interface for properties which can be used to influence collada writing + class IColladaMeshWriterProperties : public virtual IReferenceCounted + { + public: + virtual ~IColladaMeshWriterProperties () {} + + //! Which lighting model should be used in the technique (FX) section when exporting effects (materials) + virtual E_COLLADA_TECHNIQUE_FX getTechniqueFx(const video::SMaterial& material) const = 0; + + //! Which texture index should be used when writing the texture of the given sampler color. + /** \return the index to the texture-layer or -1 if that texture should never be exported + Note: for ECCS_TRANSPARENT by default the alpha channel is used, if you want to use RGB you have to set + also the ECOF_RGB_ZERO flag in getTransparentFx. */ + virtual s32 getTextureIdx(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs) const = 0; + + //! Return which color from Irrlicht should be used for the color requested by collada + /** Note that collada allows exporting either texture or color, not both. + So color mapping is only checked if we have no valid texture already. + By default we try to return best fits when possible. For example ECCS_DIFFUSE is mapped to ECIC_DIFFUSE. + When ECIC_CUSTOM is returned then the result of getCustomColor will be used. */ + virtual E_COLLADA_IRR_COLOR getColorMapping(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs) const = 0; + + //! Return custom colors for certain color types requested by collada. + /** Only used when getColorMapping returns ECIC_CUSTOM for the same parameters. */ + virtual video::SColor getCustomColor(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs) const = 0; + + //! Return the transparence color interpretation. + /** Not this is only about ECCS_TRANSPARENT and does not affect getTransparency. */ + virtual E_COLLADA_TRANSPARENT_FX getTransparentFx(const video::SMaterial& material) const = 0; + + //! Transparency value for that material. + /** This value is additional to transparent settings, if both are set they will be multiplicated. + \return 1.0 for fully transparent, 0.0 for not transparent and not written at all when < 0.f */ + virtual f32 getTransparency(const video::SMaterial& material) const = 0; + + //! Reflectivity value for that material + /** The amount of perfect mirror reflection to be added to the reflected light + \return 0.0 - 1.0 for reflectivity and element is not written at all when < 0.f */ + virtual f32 getReflectivity(const video::SMaterial& material) const = 0; + + //! Return index of refraction for that material + /** By default we don't write that. + \return a value greater equal 0.f to write \ when it is lesser than 0 nothing will be written */ + virtual f32 getIndexOfRefraction(const video::SMaterial& material) const = 0; + + //! Should node be used in scene export? (only needed for scene-writing, ignored in mesh-writing) + //! By default all visible nodes are exported. + virtual bool isExportable(const irr::scene::ISceneNode * node) const = 0; + + //! Return the mesh for the given node. If it has no mesh or shouldn't export it's mesh + //! you can return 0 in which case only the transformation matrix of the node will be used. + // TODO: Function is not const because there is no const getMesh() function for several Irrlicht nodes. + virtual IMesh* getMesh(irr::scene::ISceneNode * node) = 0; + + //! Return if the node has it's own material overwriting the mesh-materials + /** Usually true except for mesh-nodes which have isReadOnlyMaterials set. + This is mostly important for naming (as ISceneNode::getMaterial() already returns the correct material). + You have to override it when exporting custom scenenodes with own materials. + \return true => The node's own material is used, false => ignore node material and use the one from the mesh */ + virtual bool useNodeMaterial(const scene::ISceneNode* node) const = 0; + + }; + + //! Callback interface to use custom names on collada writing. + /** You can either modify names and id's written to collada or you can use + this interface to just find out which names are used on writing. + Names are often used later as xs:anyURI, so avoid whitespace, '#' and '%' in the names. + */ + class IColladaMeshWriterNames : public virtual IReferenceCounted + { + public: + + virtual ~IColladaMeshWriterNames () {} + + //! Return a unique name for the given mesh + /** Note that names really must be unique here per mesh-pointer, so + mostly it's a good idea to return the nameForMesh from + IColladaMeshWriter::getDefaultNameGenerator(). Also names must follow + the xs:NCName standard to be valid, you can run them through + IColladaMeshWriter::toNCName to ensure that. + \param mesh Pointer to the mesh which needs a name + \param instance When E_COLLADA_GEOMETRY_WRITING is not ECGI_PER_MESH then + several instances of the same mesh can be written and this counts them. + */ + virtual irr::core::stringc nameForMesh(const scene::IMesh* mesh, int instance) = 0; + + //! Return a unique name for the given node + /** Note that names really must be unique here per node-pointer, so + mostly it's a good idea to return the nameForNode from + IColladaMeshWriter::getDefaultNameGenerator(). Also names must follow + the xs:NCName standard to be valid, you can run them through + IColladaMeshWriter::toNCName to ensure that. + */ + virtual irr::core::stringc nameForNode(const scene::ISceneNode* node) = 0; + + //! Return a name for the material + /** There is one material created in the writer for each unique name. + So you can use this to control the number of materials which get written. + For example Irrlicht does by default write one material for each material + instanced by a node. So if you know that in your application material + instances per node are identical between different nodes you can reduce + the number of exported materials using that knowledge by using identical + names for such shared materials. + Names must follow the xs:NCName standard to be valid, you can run them + through IColladaMeshWriter::toNCName to ensure that. + */ + virtual irr::core::stringc nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node) = 0; + }; + + + //! Interface for writing meshes + class IColladaMeshWriter : public IMeshWriter + { + public: + + IColladaMeshWriter() + : Properties(0), DefaultProperties(0), NameGenerator(0), DefaultNameGenerator(0) + , WriteTextures(true), WriteDefaultScene(true), ExportSMaterialOnce(true) + , AmbientLight(0.f, 0.f, 0.f, 1.f) + , UnitMeter(1.f), UnitName("meter") + , GeometryWriting(ECGI_PER_MESH) + { + ParamNamesUV[0] = "U"; + ParamNamesUV[1] = "V"; + } + + //! Destructor + virtual ~IColladaMeshWriter() + { + if ( Properties ) + Properties->drop(); + if ( DefaultProperties ) + DefaultProperties->drop(); + if ( NameGenerator ) + NameGenerator->drop(); + if ( DefaultNameGenerator ) + DefaultNameGenerator->drop(); + } + + //! writes a scene starting with the given node + //\param writeRoot: 0 = no, 1=yes unless root is scenemanager, 2=yes + virtual bool writeScene(io::IWriteFile* file, scene::ISceneNode* root, int writeRoot=1) = 0; + + + //! Set if texture information should be written + virtual void setWriteTextures(bool write) + { + WriteTextures = write; + } + + //! Get if texture information should be written + virtual bool getWriteTextures() const + { + return WriteTextures; + } + + //! Set if a default scene should be written when writing meshes. + /** Many collada readers fail to read a mesh if the collada files doesn't contain a scene as well. + The scene is doing an instantiation of the mesh. + When using writeScene this flag is ignored (as we have scene there already) + */ + virtual void setWriteDefaultScene(bool write) + { + WriteDefaultScene = write; + } + + //! Get if a default scene should be written + virtual bool getWriteDefaultScene() const + { + return WriteDefaultScene; + } + + //! Sets ambient color of the scene to write + virtual void setAmbientLight(const video::SColorf &ambientColor) + { + AmbientLight = ambientColor; + } + + //! Return ambient light of the scene which is written + virtual video::SColorf getAmbientLight() const + { + return AmbientLight; + } + + //! Set the unit distances for all elements and objects + /** + \param meter: Real-world meters to use per unit. Default 1 unit = 1 meter. For 1 unit = 1cm you would set to 0.01 + \param name: Name to use for distance unit. Default is "meter". */ + virtual void setUnit(irr::f32 meter, const irr::core::stringc& name) + { + UnitMeter = meter; + UnitName = name; + } + + //! Return real world meters to use per unit for all elements and objects + virtual irr::f32 getUnitMeter() const + { + return UnitMeter; + } + + //! Return name to use for distance units. Like p.E. "meter". + virtual irr::core::stringc getUnitName() const + { + return UnitName; + } + + //! Control when and how often a mesh is written + /** Optimally ECGI_PER_MESH would be always sufficient - writing geometry once per mesh. + Unfortunately many tools (at the time of writing this nearly all of them) have trouble + on import when different materials are used per node. So when you override materials + per node and importing the resulting collada has materials problems in other tools try + using other values here. + \param writeStyle One of the E_COLLADA_GEOMETRY_WRITING settings. + */ + virtual void setGeometryWriting(E_COLLADA_GEOMETRY_WRITING writeStyle) + { + GeometryWriting = writeStyle; + } + + //! Get the current style of geometry writing. + virtual E_COLLADA_GEOMETRY_WRITING getGeometryWriting() const + { + return GeometryWriting; + } + + //! Make certain there is only one collada material generated per Irrlicht material + /** Checks before creating a collada material-name if an identical + irr:::video::SMaterial has been exported already. If so don't export it with + another name. This is set by default and leads to way smaller .dae files. + Note that if you need to disable this flag for some reason you can still + get a similar effect using the IColladaMeshWriterNames::nameForMaterial + by returning identical names for identical materials there. + */ + virtual void setExportSMaterialsOnlyOnce(bool exportOnce) + { + ExportSMaterialOnce = exportOnce; + } + + virtual bool getExportSMaterialsOnlyOnce() const + { + return ExportSMaterialOnce; + } + + //! Set properties to use by the meshwriter instead of it's default properties. + /** Overloading properties with an own class allows modifying the writing process in certain ways. + By default properties are set to the DefaultProperties. */ + virtual void setProperties(IColladaMeshWriterProperties * p) + { + if ( p == Properties ) + return; + if ( p ) + p->grab(); + if ( Properties ) + Properties->drop(); + Properties = p; + } + + //! Get properties which are currently used. + virtual IColladaMeshWriterProperties * getProperties() const + { + return Properties; + } + + //! Return the original default properties of the writer. + /** You can use this pointer in your own properties to access and return default values. */ + IColladaMeshWriterProperties * getDefaultProperties() const + { + return DefaultProperties; + } + + //! Install a generator to create custom names on export. + virtual void setNameGenerator(IColladaMeshWriterNames * nameGenerator) + { + if ( nameGenerator == NameGenerator ) + return; + if ( nameGenerator ) + nameGenerator->grab(); + if ( NameGenerator ) + NameGenerator->drop(); + NameGenerator = nameGenerator; + } + + //! Get currently used name generator + virtual IColladaMeshWriterNames * getNameGenerator() const + { + return NameGenerator; + } + + //! Return the original default name generator of the writer. + /** You can use this pointer in your own generator to access and return default values. */ + IColladaMeshWriterNames * getDefaultNameGenerator() const + { + return DefaultNameGenerator; + } + + //! Restrict the characters of oldString a set of allowed characters in xs:NCName and add the prefix. + /** A tool function to help when using a custom name generator to generative valid names for collada names and id's. */ + virtual irr::core::stringc toNCName(const irr::core::stringc& oldString, const irr::core::stringc& prefix=irr::core::stringc("_NC_")) const = 0; + + //! After export you can find out which name had been used for writing the geometry for this node. + /** The name comes from IColladaMeshWriterNames::nameForMesh, but you can't access the node there. + \return Either a pointer to the name or NULL */ + // TODO: Function is not const because there is no const getMesh() function for several Irrlicht nodes. + virtual const irr::core::stringc* findGeometryNameForNode(ISceneNode* node) = 0; + + //! Change param name used for UV's. + /** Param names for UV's have a name. By default it's "U" and "V". + Usually it doesn't matter as names are optional in Collada anyway. + But unfortunately some tools insist on specific names. + So if "U", "V" does not work then try to export by setting this to "S", "T". + One tool which insists on "S", "T" is for example SketchUp. + */ + void SetParamNamesUV(const core::stringc& u, const core::stringc& v) + { + ParamNamesUV[0] = u; + ParamNamesUV[1] = v; + } + + + protected: + // NOTE: You usually should also call setProperties with the same parameter when using setDefaultProperties + virtual void setDefaultProperties(IColladaMeshWriterProperties * p) + { + if ( p == DefaultProperties ) + return; + if ( p ) + p->grab(); + if ( DefaultProperties ) + DefaultProperties->drop(); + DefaultProperties = p; + } + + // NOTE: You usually should also call setNameGenerator with the same parameter when using setDefaultProperties + virtual void setDefaultNameGenerator(IColladaMeshWriterNames * p) + { + if ( p == DefaultNameGenerator ) + return; + if ( p ) + p->grab(); + if ( DefaultNameGenerator ) + DefaultNameGenerator->drop(); + DefaultNameGenerator = p; + } + + protected: + irr::core::stringc ParamNamesUV[2]; + + private: + IColladaMeshWriterProperties * Properties; + IColladaMeshWriterProperties * DefaultProperties; + IColladaMeshWriterNames * NameGenerator; + IColladaMeshWriterNames * DefaultNameGenerator; + bool WriteTextures; + bool WriteDefaultScene; + bool ExportSMaterialOnce; + video::SColorf AmbientLight; + irr::f32 UnitMeter; + irr::core::stringc UnitName; + E_COLLADA_GEOMETRY_WRITING GeometryWriting; + }; + + +} // end namespace +} // end namespace + +#endif diff --git a/include/IContextManager.h b/include/IContextManager.h new file mode 100644 index 00000000..1937190e --- /dev/null +++ b/include/IContextManager.h @@ -0,0 +1,59 @@ +// Copyright (C) 2013-2015 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_I_CONTEXT_MANAGER_H_INCLUDED__ +#define __IRR_I_CONTEXT_MANAGER_H_INCLUDED__ + +#include "SExposedVideoData.h" +#include "SIrrCreationParameters.h" + +namespace irr +{ +namespace video +{ + // For system specific window contexts (used for OpenGL) + class IContextManager : public virtual IReferenceCounted + { + public: + //! Initialize manager with device creation parameters and device window (passed as exposed video data) + virtual bool initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& data) =0; + + //! Terminate manager, any cleanup that is left over. Manager needs a new initialize to be usable again + virtual void terminate() =0; + + //! Create surface based on current window set + virtual bool generateSurface() =0; + + //! Destroy current surface + virtual void destroySurface() =0; + + //! Create context based on current surface + virtual bool generateContext() =0; + + //! Destroy current context + virtual void destroyContext() =0; + + //! Get current context + virtual const SExposedVideoData& getContext() const =0; + + //! Change render context, disable old and activate new defined by videoData + //\param restorePrimaryOnZero When true: restore original driver context when videoData is set to 0 values. + // When false: resets the context when videoData is set to 0 values. + /** This is mostly used internally by IVideoDriver::beginScene(). + But if you want to switch threads which access your OpenGL driver you will have to + call this function as follows: + Old thread gives up context with: activateContext(irr::video::SExposedVideoData()); + New thread takes over context with: activateContext(videoDriver->getExposedVideoData()); + Note that only 1 thread at a time may access an OpenGL context. */ + virtual bool activateContext(const SExposedVideoData& videoData, bool restorePrimaryOnZero=false) =0; + + //! Swap buffers. + virtual bool swapBuffers() =0; + }; + +} // end namespace video +} // end namespace irr + + +#endif diff --git a/include/ICursorControl.h b/include/ICursorControl.h new file mode 100644 index 00000000..4597bf37 --- /dev/null +++ b/include/ICursorControl.h @@ -0,0 +1,199 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_CURSOR_CONTROL_H_INCLUDED__ +#define __I_CURSOR_CONTROL_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "position2d.h" +#include "rect.h" + +namespace irr +{ +namespace gui +{ + + class IGUISpriteBank; + + //! Default icons for cursors + enum ECURSOR_ICON + { + // Following cursors might be system specific, or might use an Irrlicht icon-set. No guarantees so far. + ECI_NORMAL, // arrow + ECI_CROSS, // Crosshair + ECI_HAND, // Hand + ECI_HELP, // Arrow and question mark + ECI_IBEAM, // typical text-selection cursor + ECI_NO, // should not click icon + ECI_WAIT, // hourclass + ECI_SIZEALL, // arrow in all directions + ECI_SIZENESW, // resizes in direction north-east or south-west + ECI_SIZENWSE, // resizes in direction north-west or south-east + ECI_SIZENS, // resizes in direction north or south + ECI_SIZEWE, // resizes in direction west or east + ECI_UP, // up-arrow + + // Implementer note: Should we add system specific cursors, which use guaranteed the system icons, + // then I would recommend using a naming scheme like ECI_W32_CROSS, ECI_X11_CROSSHAIR and adding those + // additionally. + + ECI_COUNT // maximal of defined cursors. Note that higher values can be created at runtime + }; + + //! Names for ECURSOR_ICON + const c8* const GUICursorIconNames[ECI_COUNT+1] = + { + "normal", + "cross", + "hand", + "help", + "ibeam", + "no", + "wait", + "sizeall", + "sizenesw", + "sizenwse", + "sizens", + "sizewe", + "sizeup", + 0 + }; + + //! structure used to set sprites as cursors. + struct SCursorSprite + { + SCursorSprite() + : SpriteBank(0), SpriteId(-1) + { + } + + SCursorSprite( gui::IGUISpriteBank * spriteBank, s32 spriteId, const core::position2d &hotspot=(core::position2d(0,0)) ) + : SpriteBank(spriteBank), SpriteId(spriteId), HotSpot(hotspot) + { + } + + IGUISpriteBank * SpriteBank; + s32 SpriteId; + core::position2d HotSpot; + }; + + //! platform specific behavior flags for the cursor + enum ECURSOR_PLATFORM_BEHAVIOR + { + //! default - no platform specific behavior + ECPB_NONE = 0, + + //! On X11 try caching cursor updates as XQueryPointer calls can be expensive. + /** Update cursor positions only when the irrlicht timer has been updated or the timer is stopped. + This means you usually get one cursor update per device->run() which will be fine in most cases. + See this forum-thread for a more detailed explanation: + http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=45525 + */ + ECPB_X11_CACHE_UPDATES = 1 + }; + + //! Interface to manipulate the mouse cursor. + class ICursorControl : public virtual IReferenceCounted + { + public: + + //! Changes the visible state of the mouse cursor. + /** \param visible: The new visible state. If true, the cursor will be visible, + if false, it will be invisible. */ + virtual void setVisible(bool visible) = 0; + + //! Returns if the cursor is currently visible. + /** \return True if the cursor is visible, false if not. */ + virtual bool isVisible() const = 0; + + //! Sets the new position of the cursor. + /** The position must be + between (0.0f, 0.0f) and (1.0f, 1.0f), where (0.0f, 0.0f) is + the top left corner and (1.0f, 1.0f) is the bottom right corner of the + render window. + \param pos New position of the cursor. */ + virtual void setPosition(const core::position2d &pos) = 0; + + //! Sets the new position of the cursor. + /** The position must be + between (0.0f, 0.0f) and (1.0f, 1.0f), where (0.0f, 0.0f) is + the top left corner and (1.0f, 1.0f) is the bottom right corner of the + render window. + \param x New x-coord of the cursor. + \param y New x-coord of the cursor. */ + virtual void setPosition(f32 x, f32 y) = 0; + + //! Sets the new position of the cursor. + /** \param pos: New position of the cursor. The coordinates are pixel units. */ + virtual void setPosition(const core::position2d &pos) = 0; + + //! Sets the new position of the cursor. + /** \param x New x-coord of the cursor. The coordinates are pixel units. + \param y New y-coord of the cursor. The coordinates are pixel units. */ + virtual void setPosition(s32 x, s32 y) = 0; + + //! Returns the current position of the mouse cursor. + /** \param updateCursor When true ask system/OS for current cursor position. + When false return the last known (buffered) position ( this is useful to + check what has become of a setPosition call with float numbers). + \return Returns the current position of the cursor. The returned position + is the position of the mouse cursor in pixel units. */ + virtual const core::position2d& getPosition(bool updateCursor=true) = 0; + + //! Returns the current position of the mouse cursor. + /** \param updateCursor When true ask system/OS for current cursor position. + When false return the last known (buffered) position (this is + useful to check what has become of a setPosition call with float numbers + and is often different from the values you passed in setPosition). + \return Returns the current position of the cursor. The returned position + is a value between (0.0f, 0.0f) and (1.0f, 1.0f), where (0.0f, 0.0f) is + the top left corner and (1.0f, 1.0f) is the bottom right corner of the + render window. */ + virtual core::position2d getRelativePosition(bool updateCursor=true) = 0; + + //! Sets an absolute reference rect for setting and retrieving the cursor position. + /** If this rect is set, the cursor position is not being calculated relative to + the rendering window but to this rect. You can set the rect pointer to 0 to disable + this feature again. This feature is useful when rendering into parts of foreign windows + for example in an editor. + \param rect: A pointer to an reference rectangle or 0 to disable the reference rectangle.*/ + virtual void setReferenceRect(core::rect* rect=0) = 0; + + + //! Sets the active cursor icon + /** Setting cursor icons is so far only supported on Win32 and Linux */ + virtual void setActiveIcon(ECURSOR_ICON iconId) {} + + //! Gets the currently active icon + virtual ECURSOR_ICON getActiveIcon() const { return gui::ECI_NORMAL; } + + //! Add a custom sprite as cursor icon. + /** \return Identification for the icon */ + virtual ECURSOR_ICON addIcon(const gui::SCursorSprite& icon) { return gui::ECI_NORMAL; } + + //! replace a cursor icon. + /** Changing cursor icons is so far only supported on Win32 and Linux + Note that this only changes the icons within your application, system cursors outside your + application will not be affected. + */ + virtual void changeIcon(ECURSOR_ICON iconId, const gui::SCursorSprite& sprite) {} + + //! Return a system-specific size which is supported for cursors. Larger icons will fail, smaller icons might work. + virtual core::dimension2di getSupportedIconSize() const { return core::dimension2di(0,0); } + + //! Set platform specific behavior flags. + virtual void setPlatformBehavior(ECURSOR_PLATFORM_BEHAVIOR behavior) {} + + //! Return platform specific behavior. + /** \return Behavior set by setPlatformBehavior or ECPB_NONE for platforms not implementing specific behaviors. + */ + virtual ECURSOR_PLATFORM_BEHAVIOR getPlatformBehavior() const { return ECPB_NONE; } + }; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IDummyTransformationSceneNode.h b/include/IDummyTransformationSceneNode.h new file mode 100644 index 00000000..60dfe208 --- /dev/null +++ b/include/IDummyTransformationSceneNode.h @@ -0,0 +1,42 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_DUMMY_TRANSFORMATION_SCENE_NODE_H_INCLUDED__ +#define __I_DUMMY_TRANSFORMATION_SCENE_NODE_H_INCLUDED__ + +#include "ISceneNode.h" + +namespace irr +{ +namespace scene +{ + +//! Dummy scene node for adding additional transformations 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. +This scene node is for example used by the IAnimatedMeshSceneNode for emulating +joint scene nodes when playing skeletal animations. +*/ +class IDummyTransformationSceneNode : public ISceneNode +{ +public: + + //! Constructor + IDummyTransformationSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id) + : ISceneNode(parent, mgr, id) {} + + //! Returns a reference to the current relative transformation matrix. + /** This is the matrix, this scene node uses instead of scale, translation + and rotation. */ + virtual core::matrix4& getRelativeTransformationMatrix() = 0; +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/include/IDynamicMeshBuffer.h b/include/IDynamicMeshBuffer.h new file mode 100644 index 00000000..e7c4ffe5 --- /dev/null +++ b/include/IDynamicMeshBuffer.h @@ -0,0 +1,211 @@ +// Copyright (C) 2008-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_DYNAMIC_MESH_BUFFER_H_INCLUDED__ +#define __I_DYNAMIC_MESH_BUFFER_H_INCLUDED__ + +#include "IMeshBuffer.h" +#include "IVertexBuffer.h" +#include "IIndexBuffer.h" + +namespace irr +{ +namespace scene +{ + + /** a dynamic meshBuffer */ + class IDynamicMeshBuffer : public IMeshBuffer + { + public: + virtual IVertexBuffer &getVertexBuffer() const =0; + virtual IIndexBuffer &getIndexBuffer() const =0; + + virtual void setVertexBuffer(IVertexBuffer *vertexBuffer) =0; + virtual void setIndexBuffer(IIndexBuffer *indexBuffer) =0; + + //! Get the material of this meshbuffer + /** \return Material of this buffer. */ + virtual video::SMaterial& getMaterial() =0; + + //! Get the material of this meshbuffer + /** \return Material of this buffer. */ + virtual const video::SMaterial& getMaterial() const =0; + + //! Get the axis aligned bounding box of this meshbuffer. + /** \return Axis aligned bounding box of this buffer. */ + virtual const core::aabbox3df& getBoundingBox() const =0; + + //! Set axis aligned bounding box + /** \param box User defined axis aligned bounding box to use + for this buffer. */ + virtual void setBoundingBox(const core::aabbox3df& box) =0; + + //! Recalculates the bounding box. Should be called if the mesh changed. + virtual void recalculateBoundingBox() =0; + + //! Append the vertices and indices to the current buffer + /** Only works for compatible vertex types. + \param vertices Pointer to a vertex array. + \param numVertices Number of vertices in the array. + \param indices Pointer to index array. + \param numIndices Number of indices in array. */ + virtual void append(const void* const vertices, u32 numVertices, const u16* const indices, u32 numIndices) _IRR_OVERRIDE_ + { + + } + + //! Append the meshbuffer to the current buffer + /** Only works for compatible vertex types + \param other Buffer to append to this one. */ + virtual void append(const IMeshBuffer* const other) _IRR_OVERRIDE_ + { + + } + + // ------------------- To be removed? ------------------- // + + //! get the current hardware mapping hint + virtual E_HARDWARE_MAPPING getHardwareMappingHint_Vertex() const _IRR_OVERRIDE_ + { + return getVertexBuffer().getHardwareMappingHint(); + } + + //! get the current hardware mapping hint + virtual E_HARDWARE_MAPPING getHardwareMappingHint_Index() const _IRR_OVERRIDE_ + { + return getIndexBuffer().getHardwareMappingHint(); + } + + //! set the hardware mapping hint, for driver + virtual void setHardwareMappingHint( E_HARDWARE_MAPPING NewMappingHint, E_BUFFER_TYPE Buffer=EBT_VERTEX_AND_INDEX ) _IRR_OVERRIDE_ + { + if (Buffer==EBT_VERTEX_AND_INDEX || Buffer==EBT_VERTEX) + getVertexBuffer().setHardwareMappingHint(NewMappingHint); + if (Buffer==EBT_VERTEX_AND_INDEX || Buffer==EBT_INDEX) + getIndexBuffer().setHardwareMappingHint(NewMappingHint); + } + + //! flags the mesh as changed, reloads hardware buffers + virtual void setDirty(E_BUFFER_TYPE Buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_ + { + if (Buffer==EBT_VERTEX_AND_INDEX || Buffer==EBT_VERTEX) + getVertexBuffer().setDirty(); + if (Buffer==EBT_VERTEX_AND_INDEX || Buffer==EBT_INDEX) + getIndexBuffer().setDirty(); + } + + virtual u32 getChangedID_Vertex() const _IRR_OVERRIDE_ + { + return getVertexBuffer().getChangedID(); + } + + virtual u32 getChangedID_Index() const _IRR_OVERRIDE_ + { + return getIndexBuffer().getChangedID(); + } + + // ------------------- Old interface ------------------- // + + //! Get type of vertex data which is stored in this meshbuffer. + /** \return Vertex type of this buffer. */ + virtual video::E_VERTEX_TYPE getVertexType() const _IRR_OVERRIDE_ + { + return getVertexBuffer().getType(); + } + + //! Get access to vertex data. The data is an array of vertices. + /** Which vertex type is used can be determined by getVertexType(). + \return Pointer to array of vertices. */ + virtual const void* getVertices() const _IRR_OVERRIDE_ + { + return getVertexBuffer().getData(); + } + + //! Get access to vertex data. The data is an array of vertices. + /** Which vertex type is used can be determined by getVertexType(). + \return Pointer to array of vertices. */ + virtual void* getVertices() _IRR_OVERRIDE_ + { + return getVertexBuffer().getData(); + } + + //! Get amount of vertices in meshbuffer. + /** \return Number of vertices in this buffer. */ + virtual u32 getVertexCount() const _IRR_OVERRIDE_ + { + return getVertexBuffer().size(); + } + + //! Get type of index data which is stored in this meshbuffer. + /** \return Index type of this buffer. */ + virtual video::E_INDEX_TYPE getIndexType() const _IRR_OVERRIDE_ + { + return getIndexBuffer().getType(); + } + + //! Get access to indices. + /** \return Pointer to indices array. */ + virtual const u16* getIndices() const _IRR_OVERRIDE_ + { + return (u16*)getIndexBuffer().getData(); + } + + //! Get access to indices. + /** \return Pointer to indices array. */ + virtual u16* getIndices() _IRR_OVERRIDE_ + { + return (u16*)getIndexBuffer().getData(); + } + + //! Get amount of indices in this meshbuffer. + /** \return Number of indices in this buffer. */ + virtual u32 getIndexCount() const _IRR_OVERRIDE_ + { + return getIndexBuffer().size(); + } + + //! returns position of vertex i + virtual const core::vector3df& getPosition(u32 i) const _IRR_OVERRIDE_ + { + return getVertexBuffer()[i].Pos; + } + + //! returns position of vertex i + virtual core::vector3df& getPosition(u32 i) _IRR_OVERRIDE_ + { + return getVertexBuffer()[i].Pos; + } + + //! returns texture coords of vertex i + virtual const core::vector2df& getTCoords(u32 i) const _IRR_OVERRIDE_ + { + return getVertexBuffer()[i].TCoords; + } + + //! returns texture coords of vertex i + virtual core::vector2df& getTCoords(u32 i) _IRR_OVERRIDE_ + { + return getVertexBuffer()[i].TCoords; + } + + //! returns normal of vertex i + virtual const core::vector3df& getNormal(u32 i) const _IRR_OVERRIDE_ + { + return getVertexBuffer()[i].Normal; + } + + //! returns normal of vertex i + virtual core::vector3df& getNormal(u32 i) _IRR_OVERRIDE_ + { + return getVertexBuffer()[i].Normal; + } + }; + + +} // end namespace scene +} // end namespace irr + +#endif + + diff --git a/include/IEventReceiver.h b/include/IEventReceiver.h new file mode 100644 index 00000000..44c86e6c --- /dev/null +++ b/include/IEventReceiver.h @@ -0,0 +1,660 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_EVENT_RECEIVER_H_INCLUDED__ +#define __I_EVENT_RECEIVER_H_INCLUDED__ + +#include "ILogger.h" +#include "Keycodes.h" +#include "irrString.h" + +namespace irr +{ + //! Enumeration for all event types there are. + enum EEVENT_TYPE + { + //! An event of the graphical user interface. + /** GUI events are created by the GUI environment or the GUI elements in response + to mouse or keyboard events. When a GUI element receives an event it will either + process it and return true, or pass the event to its parent. If an event is not absorbed + before it reaches the root element then it will then be passed to the user receiver. */ + EET_GUI_EVENT = 0, + + //! A mouse input event. + /** Mouse events are created by the device and passed to IrrlichtDevice::postEventFromUser + in response to mouse input received from the operating system. + Mouse events are first passed to the user receiver, then to the GUI environment and its elements, + then finally the input receiving scene manager where it is passed to the active camera. + */ + EET_MOUSE_INPUT_EVENT, + + //! A key input event. + /** Like mouse events, keyboard events are created by the device and passed to + IrrlichtDevice::postEventFromUser. They take the same path as mouse events. */ + EET_KEY_INPUT_EVENT, + + //! A touch input event. + EET_TOUCH_INPUT_EVENT, + + //! A accelerometer event. + EET_ACCELEROMETER_EVENT, + + //! A gyroscope event. + EET_GYROSCOPE_EVENT, + + //! A device motion event. + EET_DEVICE_MOTION_EVENT, + + //! A joystick (joypad, gamepad) input event. + /** Joystick events are created by polling all connected joysticks once per + device run() and then passing the events to IrrlichtDevice::postEventFromUser. + They take the same path as mouse events. + Windows, SDL: Implemented. + Linux: Implemented, with POV hat issues. + MacOS / Other: Not yet implemented. + */ + EET_JOYSTICK_INPUT_EVENT, + + //! A log event + /** Log events are only passed to the user receiver if there is one. If they are absorbed by the + user receiver then no text will be sent to the console. */ + EET_LOG_TEXT_EVENT, + + //! A user event with user data. + /** This is not used by Irrlicht and can be used to send user + specific data though the system. The Irrlicht 'window handle' + can be obtained from IrrlichtDevice::getExposedVideoData() + The usage and behavior depends on the operating system: + Windows: send a WM_USER message to the Irrlicht Window; the + wParam and lParam will be used to populate the + UserData1 and UserData2 members of the SUserEvent. + Linux: send a ClientMessage via XSendEvent to the Irrlicht + Window; the data.l[0] and data.l[1] members will be + cast to s32 and used as UserData1 and UserData2. + MacOS: Not yet implemented + */ + EET_USER_EVENT, + + //! Pass on raw events from the OS + EET_SYSTEM_EVENT, + + //! Application state events like a resume, pause etc. + EET_APPLICATION_EVENT, + + //! This enum is never used, it only forces the compiler to + //! compile these enumeration values to 32 bit. + EGUIET_FORCE_32_BIT = 0x7fffffff + + }; + + //! Enumeration for all mouse input events + enum EMOUSE_INPUT_EVENT + { + //! Left mouse button was pressed down. + EMIE_LMOUSE_PRESSED_DOWN = 0, + + //! Right mouse button was pressed down. + EMIE_RMOUSE_PRESSED_DOWN, + + //! Middle mouse button was pressed down. + EMIE_MMOUSE_PRESSED_DOWN, + + //! Left mouse button was left up. + EMIE_LMOUSE_LEFT_UP, + + //! Right mouse button was left up. + EMIE_RMOUSE_LEFT_UP, + + //! Middle mouse button was left up. + EMIE_MMOUSE_LEFT_UP, + + //! The mouse cursor changed its position. + EMIE_MOUSE_MOVED, + + //! The mouse wheel was moved. Use Wheel value in event data to find out + //! in what direction and how fast. + EMIE_MOUSE_WHEEL, + + //! Left mouse button double click. + //! This event is generated after the second EMIE_LMOUSE_PRESSED_DOWN event. + EMIE_LMOUSE_DOUBLE_CLICK, + + //! Right mouse button double click. + //! This event is generated after the second EMIE_RMOUSE_PRESSED_DOWN event. + EMIE_RMOUSE_DOUBLE_CLICK, + + //! Middle mouse button double click. + //! This event is generated after the second EMIE_MMOUSE_PRESSED_DOWN event. + EMIE_MMOUSE_DOUBLE_CLICK, + + //! Left mouse button triple click. + //! This event is generated after the third EMIE_LMOUSE_PRESSED_DOWN event. + EMIE_LMOUSE_TRIPLE_CLICK, + + //! Right mouse button triple click. + //! This event is generated after the third EMIE_RMOUSE_PRESSED_DOWN event. + EMIE_RMOUSE_TRIPLE_CLICK, + + //! Middle mouse button triple click. + //! This event is generated after the third EMIE_MMOUSE_PRESSED_DOWN event. + EMIE_MMOUSE_TRIPLE_CLICK, + + //! Mouse enters canvas used for rendering. + //! Only generated on emscripten + EMIE_MOUSE_ENTER_CANVAS, + + //! Mouse leaves canvas used for rendering. + //! Only generated on emscripten + EMIE_MOUSE_LEAVE_CANVAS, + + //! No real event. Just for convenience to get number of events + EMIE_COUNT + }; + + //! Masks for mouse button states + enum E_MOUSE_BUTTON_STATE_MASK + { + EMBSM_LEFT = 0x01, + EMBSM_RIGHT = 0x02, + EMBSM_MIDDLE = 0x04, + + //! currently only on windows + EMBSM_EXTRA1 = 0x08, + + //! currently only on windows + EMBSM_EXTRA2 = 0x10, + + EMBSM_FORCE_32_BIT = 0x7fffffff + }; + + //! Enumeration for all touch input events + enum ETOUCH_INPUT_EVENT + { + //! Touch was pressed down. + ETIE_PRESSED_DOWN = 0, + + //! Touch was left up. + ETIE_LEFT_UP, + + //! The touch changed its position. + ETIE_MOVED, + + //! No real event. Just for convenience to get number of events + ETIE_COUNT + }; + + enum ESYSTEM_EVENT_TYPE + { + //! From Android command handler for native activity messages + ESET_ANDROID_CMD = 0, + + // TODO: for example ESET_WINDOWS_MESSAGE for win32 message loop events + + //! No real event, but to get number of event types + ESET_COUNT + }; + + //! Enumeration for a commonly used application state events (it's useful mainly for mobile devices) + enum EAPPLICATION_EVENT_TYPE + { + //! The application will be resumed. + EAET_WILL_RESUME = 0, + + //! The application has been resumed. + EAET_DID_RESUME, + + //! The application will be paused. + EAET_WILL_PAUSE, + + //! The application has been paused. + EAET_DID_PAUSE, + + //! The application will be terminated. + EAET_WILL_TERMINATE, + + //! The application received a memory warning. + EAET_MEMORY_WARNING, + + //! No real event, but to get number of event types. + EAET_COUNT + }; + + namespace gui + { + + class IGUIElement; + + //! Enumeration for all events which are sendable by the gui system + enum EGUI_EVENT_TYPE + { + //! A gui element has lost its focus. + /** GUIEvent.Caller is losing the focus to GUIEvent.Element. + If the event is absorbed then the focus will not be changed. */ + EGET_ELEMENT_FOCUS_LOST = 0, + + //! A gui element has got the focus. + /** If the event is absorbed then the focus will not be changed. */ + EGET_ELEMENT_FOCUSED, + + //! The mouse cursor hovered over a gui element. + /** If an element has sub-elements you also get this message for the subelements */ + EGET_ELEMENT_HOVERED, + + //! The mouse cursor left the hovered element. + /** If an element has sub-elements you also get this message for the subelements */ + EGET_ELEMENT_LEFT, + + //! An element would like to close. + /** Windows and context menus use this event when they would like to close, + this can be canceled by absorbing the event. */ + EGET_ELEMENT_CLOSED, + + //! A button was clicked. + EGET_BUTTON_CLICKED, + + //! A scrollbar has changed its position. + EGET_SCROLL_BAR_CHANGED, + + //! A checkbox has changed its check state. + EGET_CHECKBOX_CHANGED, + + //! A new item in a listbox was selected. + /** NOTE: You also get this event currently when the same item was clicked again after more than 500 ms. */ + EGET_LISTBOX_CHANGED, + + //! An item in the listbox was selected, which was already selected. + /** NOTE: You get the event currently only if the item was clicked again within 500 ms or selected by "enter" or "space". */ + EGET_LISTBOX_SELECTED_AGAIN, + + //! A file has been selected in the file dialog + EGET_FILE_SELECTED, + + //! A directory has been selected in the file dialog + EGET_DIRECTORY_SELECTED, + + //! A file open dialog has been closed without choosing a file + EGET_FILE_CHOOSE_DIALOG_CANCELLED, + + //! 'Yes' was clicked on a messagebox + EGET_MESSAGEBOX_YES, + + //! 'No' was clicked on a messagebox + EGET_MESSAGEBOX_NO, + + //! 'OK' was clicked on a messagebox + EGET_MESSAGEBOX_OK, + + //! 'Cancel' was clicked on a messagebox + EGET_MESSAGEBOX_CANCEL, + + //! In an editbox 'ENTER' was pressed + EGET_EDITBOX_ENTER, + + //! The text in an editbox was changed. This does not include automatic changes in text-breaking. + EGET_EDITBOX_CHANGED, + + //! The marked area in an editbox was changed. + EGET_EDITBOX_MARKING_CHANGED, + + //! The tab was changed in an tab control + EGET_TAB_CHANGED, + + //! A menu item was selected in a (context) menu + EGET_MENU_ITEM_SELECTED, + + //! The selection in a combo box has been changed + EGET_COMBO_BOX_CHANGED, + + //! The value of a spin box has changed + EGET_SPINBOX_CHANGED, + + //! A table has changed + EGET_TABLE_CHANGED, + EGET_TABLE_HEADER_CHANGED, + EGET_TABLE_SELECTED_AGAIN, + + //! A tree view node lost selection. See IGUITreeView::getLastEventNode(). + EGET_TREEVIEW_NODE_DESELECT, + + //! A tree view node was selected. See IGUITreeView::getLastEventNode(). + EGET_TREEVIEW_NODE_SELECT, + + //! A tree view node was expanded. See IGUITreeView::getLastEventNode(). + EGET_TREEVIEW_NODE_EXPAND, + + //! A tree view node was collapsed. See IGUITreeView::getLastEventNode(). + EGET_TREEVIEW_NODE_COLLAPSE, + + //! deprecated - use EGET_TREEVIEW_NODE_COLLAPSE instead. This + //! may be removed by Irrlicht 1.9 + EGET_TREEVIEW_NODE_COLLAPS = EGET_TREEVIEW_NODE_COLLAPSE, + + //! No real event. Just for convenience to get number of events + EGET_COUNT + }; + } // end namespace gui + + +//! SEvents hold information about an event. See irr::IEventReceiver for details on event handling. +struct SEvent +{ + //! Any kind of GUI event. + struct SGUIEvent + { + //! IGUIElement who called the event + gui::IGUIElement* Caller; + + //! If the event has something to do with another element, it will be held here. + gui::IGUIElement* Element; + + //! Type of GUI Event + gui::EGUI_EVENT_TYPE EventType; + + }; + + //! Any kind of mouse event. + struct SMouseInput + { + //! X position of mouse cursor + s32 X; + + //! Y position of mouse cursor + s32 Y; + + //! mouse wheel delta, often 1.0 or -1.0, but can have other values < 0.f or > 0.f; + /** Only valid if event was EMIE_MOUSE_WHEEL */ + f32 Wheel; + + //! True if shift was also pressed + bool Shift:1; + + //! True if ctrl was also pressed + bool Control:1; + + //! A bitmap of button states. You can use isButtonPressed() to determine + //! if a button is pressed or not. + //! Currently only valid if the event was EMIE_MOUSE_MOVED + u32 ButtonStates; + + //! Is the left button pressed down? + bool isLeftPressed() const { return 0 != ( ButtonStates & EMBSM_LEFT ); } + + //! Is the right button pressed down? + bool isRightPressed() const { return 0 != ( ButtonStates & EMBSM_RIGHT ); } + + //! Is the middle button pressed down? + bool isMiddlePressed() const { return 0 != ( ButtonStates & EMBSM_MIDDLE ); } + + //! Type of mouse event + EMOUSE_INPUT_EVENT Event; + }; + + //! Any kind of keyboard event. + struct SKeyInput + { + //! Character corresponding to the key (0, if not a character, value undefined in key releases) + wchar_t Char; + + //! Key which has been pressed or released + EKEY_CODE Key; + + //! System dependent code. Only set for systems which are described below, otherwise undefined. + //! Android: int32_t with physical key as returned by AKeyEvent_getKeyCode + u32 SystemKeyCode; + + //! If not true, then the key was left up + bool PressedDown:1; + + //! True if shift was also pressed + bool Shift:1; + + //! True if ctrl was also pressed + bool Control:1; + }; + + //! Any kind of touch event. + struct STouchInput + { + // Touch ID. + size_t ID; + + // X position of simple touch. + s32 X; + + // Y position of simple touch. + s32 Y; + + //! Type of touch event. + ETOUCH_INPUT_EVENT Event; + }; + + //! Any kind of accelerometer event. + struct SAccelerometerEvent + { + + // X acceleration. + f64 X; + + // Y acceleration. + f64 Y; + + // Z acceleration. + f64 Z; + }; + + //! Any kind of gyroscope event. + struct SGyroscopeEvent + { + + // X rotation. + f64 X; + + // Y rotation. + f64 Y; + + // Z rotation. + f64 Z; + }; + + //! Any kind of device motion event. + struct SDeviceMotionEvent + { + + // X angle - roll. + f64 X; + + // Y angle - pitch. + f64 Y; + + // Z angle - yaw. + f64 Z; + }; + + //! A joystick event. + /** Unlike other events, joystick events represent the result of polling + * each connected joystick once per run() of the device. Joystick events will + * not be generated by default. If joystick support is available for the + * active device, _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ is defined, and + * @ref irr::IrrlichtDevice::activateJoysticks() has been called, an event of + * this type will be generated once per joystick per @ref IrrlichtDevice::run() + * regardless of whether the state of the joystick has actually changed. */ + struct SJoystickEvent + { + enum + { + NUMBER_OF_BUTTONS = 32, + + AXIS_X = 0, // e.g. analog stick 1 left to right + AXIS_Y, // e.g. analog stick 1 top to bottom + AXIS_Z, // e.g. throttle, or analog 2 stick 2 left to right + AXIS_R, // e.g. rudder, or analog 2 stick 2 top to bottom + AXIS_U, + AXIS_V, + NUMBER_OF_AXES=18 // (please tell Irrlicht maintainers if you absolutely need more axes) + }; + + /** A bitmap of button states. You can use IsButtonPressed() to + ( check the state of each button from 0 to (NUMBER_OF_BUTTONS - 1) */ + u32 ButtonStates; + + /** For AXIS_X, AXIS_Y, AXIS_Z, AXIS_R, AXIS_U and AXIS_V + * Values are in the range -32768 to 32767, with 0 representing + * the center position. You will receive the raw value from the + * joystick, and so will usually want to implement a dead zone around + * the center of the range. Axes not supported by this joystick will + * always have a value of 0. On Linux, POV hats are represented as axes, + * usually the last two active axis. + */ + s16 Axis[NUMBER_OF_AXES]; + + /** The POV represents the angle of the POV hat in degrees * 100, + * from 0 to 35,900. A value of 65535 indicates that the POV hat + * is centered (or not present). + * This value is only supported on Windows. On Linux, the POV hat + * will be sent as 2 axes instead. */ + u16 POV; + + //! The ID of the joystick which generated this event. + /** This is an internal Irrlicht index; it does not map directly + * to any particular hardware joystick. */ + u8 Joystick; + + //! A helper function to check if a button is pressed. + bool IsButtonPressed(u32 button) const + { + if(button >= (u32)NUMBER_OF_BUTTONS) + return false; + + return (ButtonStates & (1 << button)) ? true : false; + } + }; + + //! Any kind of log event. + struct SLogEvent + { + //! Pointer to text which has been logged + const c8* Text; + + //! Log level in which the text has been logged + ELOG_LEVEL Level; + }; + + //! Any kind of user event. + struct SUserEvent + { + //! Some user specified data as int + size_t UserData1; + + //! Another user specified data as int + size_t UserData2; + }; + + // Raw events from the OS + struct SSystemEvent + { + //! Android command handler native activity messages. + struct SAndroidCmd + { + //! APP_CMD_ enums defined in android_native_app_glue.h from the Android NDK + s32 Cmd; + }; + + // TOOD: more structs for iphone, Windows, X11, etc. + + ESYSTEM_EVENT_TYPE EventType; + union + { + struct SAndroidCmd AndroidCmd; + }; + }; + + // Application state event + struct SApplicationEvent + { + EAPPLICATION_EVENT_TYPE EventType; + }; + + EEVENT_TYPE EventType; + union + { + struct SGUIEvent GUIEvent; + struct SMouseInput MouseInput; + struct SKeyInput KeyInput; + struct STouchInput TouchInput; + struct SAccelerometerEvent AccelerometerEvent; + struct SGyroscopeEvent GyroscopeEvent; + struct SDeviceMotionEvent DeviceMotionEvent; + struct SJoystickEvent JoystickEvent; + struct SLogEvent LogEvent; + struct SUserEvent UserEvent; + struct SSystemEvent SystemEvent; + struct SApplicationEvent ApplicationEvent; + }; + +}; + +//! Interface of an object which can receive events. +/** Many of the engine's classes inherit IEventReceiver so they are able to +process events. Events usually start at a postEventFromUser function and are +passed down through a chain of event receivers until OnEvent returns true. See +irr::EEVENT_TYPE for a description of where each type of event starts, and the +path it takes through the system. */ +class IEventReceiver +{ +public: + + //! Destructor + virtual ~IEventReceiver() {} + + //! Called if an event happened. + /** Please take care that you should only return 'true' when you want to _prevent_ Irrlicht + * from processing the event any further. So 'true' does mean that an event is completely done. + * Therefore your return value for all unprocessed events should be 'false'. + \return True if the event was processed. + */ + virtual bool OnEvent(const SEvent& event) = 0; +}; + + +//! Information on a joystick, returned from @ref irr::IrrlichtDevice::activateJoysticks() +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 + * irr::SJoystickEvent Joystick ID. */ + u8 Joystick; + + //! The name that the joystick uses to identify itself. + core::stringc Name; + + //! The number of buttons that the joystick has. + u32 Buttons; + + //! The number of axes that the joystick has, i.e. X, Y, Z, R, U, V. + /** Note: with a Linux device, the POV hat (if any) will use two axes. These + * will be included in this count. */ + u32 Axes; + + //! An indication of whether the joystick has a POV hat. + /** A Windows device will identify the presence or absence of the POV hat. + * A Linux device cannot, and will always return POV_HAT_UNKNOWN. */ + enum + { + //! A hat is definitely present. + POV_HAT_PRESENT, + + //! A hat is definitely not present. + POV_HAT_ABSENT, + + //! The presence or absence of a hat cannot be determined. + POV_HAT_UNKNOWN + } PovHat; +}; // struct SJoystickInfo + + +} // end namespace irr + +#endif + diff --git a/include/IFileArchive.h b/include/IFileArchive.h new file mode 100644 index 00000000..7c2ed866 --- /dev/null +++ b/include/IFileArchive.h @@ -0,0 +1,148 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt/ Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_FILE_ARCHIVE_H_INCLUDED__ +#define __I_FILE_ARCHIVE_H_INCLUDED__ + +#include "IReadFile.h" +#include "IFileList.h" + +namespace irr +{ + +namespace io +{ + +//! FileSystemType: which filesystem should be used for e.g. browsing +enum EFileSystemType +{ + FILESYSTEM_NATIVE = 0, // Native OS FileSystem + FILESYSTEM_VIRTUAL // Virtual FileSystem +}; + +//! Contains the different types of archives +enum E_FILE_ARCHIVE_TYPE +{ + //! A PKZIP archive + EFAT_ZIP = MAKE_IRR_ID('Z','I','P', 0), + + //! A gzip archive + EFAT_GZIP = MAKE_IRR_ID('g','z','i','p'), + + //! A virtual directory + EFAT_FOLDER = MAKE_IRR_ID('f','l','d','r'), + + //! An ID Software PAK archive + EFAT_PAK = MAKE_IRR_ID('P','A','K', 0), + + //! A Nebula Device archive + EFAT_NPK = MAKE_IRR_ID('N','P','K', 0), + + //! A Tape ARchive + EFAT_TAR = MAKE_IRR_ID('T','A','R', 0), + + //! A wad Archive, Quake2, Halflife + EFAT_WAD = MAKE_IRR_ID('W','A','D', 0), + + //! An Android asset file archive + EFAT_ANDROID_ASSET = MAKE_IRR_ID('A','S','S','E'), + + //! The type of this archive is unknown + EFAT_UNKNOWN = MAKE_IRR_ID('u','n','k','n') +}; + +//! The FileArchive manages archives and provides access to files inside them. +class IFileArchive : public virtual IReferenceCounted +{ +public: + + //! Opens a file based on its name + /** Creates and returns a new IReadFile for a file in the archive. + \param filename The file to open + \return Returns A pointer to the created file on success, + or 0 on failure. */ + virtual IReadFile* createAndOpenFile(const path& filename) =0; + + //! Opens a file based on its position in the file list. + /** Creates and returns + \param index The zero based index of the file. + \return Returns a pointer to the created file on success, or 0 on failure. */ + virtual IReadFile* createAndOpenFile(u32 index) =0; + + //! Returns the complete file tree + /** \return Returns the complete directory tree for the archive, + including all files and folders */ + virtual const IFileList* getFileList() const =0; + + //! get the archive type + virtual E_FILE_ARCHIVE_TYPE getType() const { return EFAT_UNKNOWN; } + + //! return the name (id) of the file Archive + virtual const io::path& getArchiveName() const =0; + + //! Add a directory in the archive and all it's files to the FileList + /** Only needed for file-archives which have no information about their own + directory structure. In that case the user must add directories manually. + Currently this is necessary for archives of type EFAT_ANDROID_ASSET. + The root-path itself is already set by the engine. + If directories are not added manually opening files might still work, + but checks if file exists will fail. + */ + virtual void addDirectoryToFileList(const io::path &filename) {} + + //! An optionally used password string + /** This variable is publicly accessible from the interface in order to + avoid single access patterns to this place, and hence allow some more + obscurity. + */ + core::stringc Password; +}; + +//! Class which is able to create an archive from a file. +/** If you want the Irrlicht Engine be able to load archives of +currently unsupported file formats (e.g .wad), then implement +this and add your new Archive loader with +IFileSystem::addArchiveLoader() to the engine. */ +class IArchiveLoader : public virtual IReferenceCounted +{ +public: + //! Check if the file might be loaded by this class + /** Check based on the file extension (e.g. ".zip") + \param filename Name of file to check. + \return True if file seems to be loadable. */ + virtual bool isALoadableFileFormat(const path& filename) const =0; + + //! Check if the file might be loaded by this class + /** This check may look into the file. + \param file File handle to check. + \return True if file seems to be loadable. */ + virtual bool isALoadableFileFormat(io::IReadFile* file) const =0; + + //! Check to see if the loader can create archives of this type. + /** Check based on the archive type. + \param fileType The archive type to check. + \return True if the archive loader supports this type, false if not */ + virtual bool isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const =0; + + //! Creates an archive from the filename + /** \param filename File to use. + \param ignoreCase Searching is performed without regarding the case + \param ignorePaths Files are searched for without checking for the directories + \return Pointer to newly created archive, or 0 upon error. */ + virtual IFileArchive* createArchive(const path& filename, bool ignoreCase, bool ignorePaths) const =0; + + //! Creates an archive from the file + /** \param file File handle to use. + \param ignoreCase Searching is performed without regarding the case + \param ignorePaths Files are searched for without checking for the directories + \return Pointer to newly created archive, or 0 upon error. */ + virtual IFileArchive* createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const =0; +}; + + +} // end namespace io +} // end namespace irr + +#endif + diff --git a/include/IFileList.h b/include/IFileList.h new file mode 100644 index 00000000..2d0af466 --- /dev/null +++ b/include/IFileList.h @@ -0,0 +1,94 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_FILE_LIST_H_INCLUDED__ +#define __I_FILE_LIST_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "path.h" + +namespace irr +{ +namespace io +{ + +//! Provides a list of files and folders. +/** File lists usually contain a list of all files in a given folder, +but can also contain a complete directory structure. */ +class IFileList : public virtual IReferenceCounted +{ +public: + //! Get the number of files in the filelist. + /** \return Amount of files and directories in the file list. */ + virtual u32 getFileCount() const = 0; + + //! Gets the name of a file in the list, based on an index. + /** The path is not included in this name. Use getFullFileName for this. + \param index is the zero based index of the file which name should + be returned. The index must be less than the amount getFileCount() returns. + \return File name of the file. Returns 0, if an error occurred. */ + virtual const io::path& getFileName(u32 index) const = 0; + + //! Gets the full name of a file in the list including the path, based on an index. + /** \param index is the zero based index of the file which name should + be returned. The index must be less than the amount getFileCount() returns. + \return File name of the file. Returns 0 if an error occurred. */ + virtual const io::path& getFullFileName(u32 index) const = 0; + + //! Returns the size of a file in the file list, based on an index. + /** \param index is the zero based index of the file which should be returned. + The index must be less than the amount getFileCount() returns. + \return The size of the file in bytes. */ + virtual u32 getFileSize(u32 index) const = 0; + + //! Returns the file offset of a file in the file list, based on an index. + /** \param index is the zero based index of the file which should be returned. + The index must be less than the amount getFileCount() returns. + \return The offset of the file in bytes. */ + virtual u32 getFileOffset(u32 index) const = 0; + + //! Returns the ID of a file in the file list, based on an index. + /** This optional ID can be used to link the file list entry to information held + elsewhere. For example this could be an index in an IFileArchive, linking the entry + to its data offset, uncompressed size and CRC. + \param index is the zero based index of the file which should be returned. + The index must be less than the amount getFileCount() returns. + \return The ID of the file. */ + virtual u32 getID(u32 index) const = 0; + + //! Check if the file is a directory + /** \param index The zero based index which will be checked. The index + must be less than the amount getFileCount() returns. + \return True if the file is a directory, else false. */ + virtual bool isDirectory(u32 index) const = 0; + + //! Searches for a file or folder in the list + /** Searches for a file by name + \param filename The name of the file to search for. + \param isFolder True if you are searching for a directory path, false if you are searching for a file + \return Returns the index of the file in the file list, or -1 if + no matching name name was found. */ + virtual s32 findFile(const io::path& filename, bool isFolder=false) const = 0; + + //! Returns the base path of the file list + virtual const io::path& getPath() const = 0; + + //! Add as a file or folder to the list + /** \param fullPath The file name including path, from the root of the file list. + \param isDirectory True if this is a directory rather than a file. + \param offset The file offset inside an archive + \param size The size of the file in bytes. + \param id The ID of the file in the archive which owns it */ + virtual u32 addItem(const io::path& fullPath, u32 offset, u32 size, bool isDirectory, u32 id=0) = 0; + + //! Sorts the file list. You should call this after adding any items to the file list + virtual void sort() = 0; +}; + +} // end namespace irr +} // end namespace io + + +#endif + diff --git a/include/IFileSystem.h b/include/IFileSystem.h new file mode 100644 index 00000000..f9a6ee61 --- /dev/null +++ b/include/IFileSystem.h @@ -0,0 +1,399 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_FILE_SYSTEM_H_INCLUDED__ +#define __I_FILE_SYSTEM_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "IXMLReader.h" +#include "IXMLWriter.h" +#include "IFileArchive.h" + +namespace irr +{ +namespace video +{ + class IVideoDriver; +} // end namespace video +namespace io +{ + +class IReadFile; +class IWriteFile; +class IFileList; +class IAttributes; + + +//! The FileSystem manages files and archives and provides access to them. +/** It manages where files are, so that modules which use the the IO do not +need to know where every file is located. A file could be in a .zip-Archive or +as file on disk, using the IFileSystem makes no difference to this. */ +class IFileSystem : public virtual IReferenceCounted +{ +public: + + //! Opens a file for read access. + /** \param filename: Name of file to open. + \return Pointer to the created file interface. + The returned pointer should be dropped when no longer needed. + See IReferenceCounted::drop() for more information. */ + virtual IReadFile* createAndOpenFile(const path& filename) =0; + + //! Creates an IReadFile interface for accessing memory like a file. + /** This allows you to use a pointer to memory where an IReadFile is requested. + \param memory: A pointer to the start of the file in memory + \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 IReadFile when it is dropped. + \return Pointer to the created file interface. + The returned pointer should be dropped when no longer needed. + See IReferenceCounted::drop() for more information. + */ + virtual IReadFile* createMemoryReadFile(const void* memory, s32 len, const path& fileName, bool deleteMemoryWhenDropped=false) =0; + + //! Creates an IReadFile interface for accessing files inside files. + /** This is useful e.g. for archives. + \param fileName: The name given to this file + \param alreadyOpenedFile: Pointer to the enclosing file + \param pos: Start of the file inside alreadyOpenedFile + \param areaSize: The length of the file + \return A pointer to the created file interface. + The returned pointer should be dropped when no longer needed. + See IReferenceCounted::drop() for more information. + */ + virtual IReadFile* createLimitReadFile(const path& fileName, + IReadFile* alreadyOpenedFile, long pos, long areaSize) =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 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 path& 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 + appended to the file. + \return Pointer to the created file interface. 0 is returned, if the + file could not created or opened for writing. + The returned pointer should be dropped when no longer needed. + See IReferenceCounted::drop() for more information. */ + virtual IWriteFile* createAndWriteFile(const path& filename, bool append=false) =0; + + //! Adds an archive to the file system. + /** After calling this, the Irrlicht Engine will also search and open + files directly from this archive. This is useful for hiding data from + the end user, speeding up file access and making it possible to access + for example Quake3 .pk3 files, which are just renamed .zip files. By + default Irrlicht supports ZIP, PAK, TAR, PNK, and directories as + archives. You can provide your own archive types by implementing + IArchiveLoader and passing an instance to addArchiveLoader. + Irrlicht supports AES-encrypted zip files, and the advanced compression + techniques lzma and bzip2. + \param filename: Filename of the archive to add to the file system. + \param ignoreCase: If set to true, files in the archive can be accessed without + writing all letters in the right case. + \param ignorePaths: If set to true, files in the added archive can be accessed + without its complete path. + \param archiveType: If no specific E_FILE_ARCHIVE_TYPE is selected then + the type of archive will depend on the extension of the file name. If + you use a different extension then you can use this parameter to force + a specific type of archive. + \param password An optional password, which is used in case of encrypted archives. + \param retArchive A pointer that will be set to the archive that is added. + \return True if the archive was added successfully, false if not. */ + virtual bool addFileArchive(const path& filename, bool ignoreCase=true, + bool ignorePaths=true, + E_FILE_ARCHIVE_TYPE archiveType=EFAT_UNKNOWN, + const core::stringc& password="", + IFileArchive** retArchive=0) =0; + + //! Adds an archive to the file system. + /** After calling this, the Irrlicht Engine will also search and open + files directly from this archive. This is useful for hiding data from + the end user, speeding up file access and making it possible to access + for example Quake3 .pk3 files, which are just renamed .zip files. By + default Irrlicht supports ZIP, PAK, TAR, PNK, and directories as + archives. You can provide your own archive types by implementing + IArchiveLoader and passing an instance to addArchiveLoader. + Irrlicht supports AES-encrypted zip files, and the advanced compression + techniques lzma and bzip2. + If you want to add a directory as an archive, prefix its name with a + slash in order to let Irrlicht recognize it as a folder mount (mypath/). + Using this technique one can build up a search order, because archives + are read first, and can be used more easily with relative filenames. + \param file: Archive to add to the file system. + \param ignoreCase: If set to true, files in the archive can be accessed without + writing all letters in the right case. + \param ignorePaths: If set to true, files in the added archive can be accessed + without its complete path. + \param archiveType: If no specific E_FILE_ARCHIVE_TYPE is selected then + the type of archive will depend on the extension of the file name. If + you use a different extension then you can use this parameter to force + a specific type of archive. + \param password An optional password, which is used in case of encrypted archives. + \param retArchive A pointer that will be set to the archive that is added. + \return True if the archive was added successfully, false if not. */ + virtual bool addFileArchive(IReadFile* file, bool ignoreCase=true, + bool ignorePaths=true, + E_FILE_ARCHIVE_TYPE archiveType=EFAT_UNKNOWN, + const core::stringc& password="", + IFileArchive** retArchive=0) =0; + + //! Adds an archive to the file system. + /** \param archive: The archive to add to the file system. + \return True if the archive was added successfully, false if not. */ + virtual bool addFileArchive(IFileArchive* archive) =0; + + //! Get the number of archives currently attached to the file system + virtual u32 getFileArchiveCount() const =0; + + //! Removes an archive from the file system. + /** This will close the archive and free any file handles, but will not + close resources which have already been loaded and are now cached, for + example textures and meshes. + \param index: The index of the archive to remove + \return True on success, false on failure */ + virtual bool removeFileArchive(u32 index) =0; + + //! Removes an archive from the file system. + /** This will close the archive and free any file handles, but will not + close resources which have already been loaded and are now cached, for + example textures and meshes. Note that a relative filename might be + interpreted differently on each call, depending on the current working + directory. In case you want to remove an archive that was added using + a relative path name, you have to change to the same working directory + again. This means, that the filename given on creation is not an + identifier for the archive, but just a usual filename that is used for + locating the archive to work with. + \param filename The archive pointed to by the name will be removed + \return True on success, false on failure */ + virtual bool removeFileArchive(const path& filename) =0; + + //! Removes an archive from the file system. + /** This will close the archive and free any file handles, but will not + close resources which have already been loaded and are now cached, for + example textures and meshes. + \param archive The archive to remove. + \return True on success, false on failure */ + virtual bool removeFileArchive(const IFileArchive* archive) =0; + + //! Changes the search order of attached archives. + /** + \param sourceIndex: The index of the archive to change + \param relative: The relative change in position, archives with a lower index are searched first */ + virtual bool moveFileArchive(u32 sourceIndex, s32 relative) =0; + + //! Get the archive at a given index. + virtual IFileArchive* getFileArchive(u32 index) =0; + + //! Adds an external archive loader to the engine. + /** Use this function to add support for new archive types to the + engine, for example proprietary or encrypted file storage. */ + virtual void addArchiveLoader(IArchiveLoader* loader) =0; + + //! Gets the number of archive loaders currently added + virtual u32 getArchiveLoaderCount() const = 0; + + //! Retrieve the given archive loader + /** \param index The index of the loader to retrieve. This parameter is an 0-based + array index. + \return A pointer to the specified loader, 0 if the index is incorrect. */ + virtual IArchiveLoader* getArchiveLoader(u32 index) const = 0; + + //! Adds a zip archive to the file system. + /** \deprecated This function is provided for compatibility + with older versions of Irrlicht and may be removed in Irrlicht 1.9, + you should use addFileArchive instead. + After calling this, the Irrlicht Engine will search and open files directly from this archive too. + This is useful for hiding data from the end user, speeding up file access and making it possible to + access for example Quake3 .pk3 files, which are no different than .zip files. + \param filename: Filename of the zip archive to add to the file system. + \param ignoreCase: If set to true, files in the archive can be accessed without + writing all letters in the right case. + \param ignorePaths: If set to true, files in the added archive can be accessed + without its complete path. + \return True if the archive was added successfully, false if not. */ + _IRR_DEPRECATED_ virtual bool addZipFileArchive(const c8* filename, bool ignoreCase=true, bool ignorePaths=true) + { + return addFileArchive(filename, ignoreCase, ignorePaths, EFAT_ZIP); + } + + //! Adds an unzipped archive (or basedirectory with subdirectories..) to the file system. + /** \deprecated This function is provided for compatibility + with older versions of Irrlicht and may be removed in Irrlicht 1.9, + you should use addFileArchive instead. + Useful for handling data which will be in a zip file + \param filename: Filename of the unzipped zip archive base directory to add to the file system. + \param ignoreCase: If set to true, files in the archive can be accessed without + writing all letters in the right case. + \param ignorePaths: If set to true, files in the added archive can be accessed + without its complete path. + \return True if the archive was added successful, false if not. */ + _IRR_DEPRECATED_ virtual bool addFolderFileArchive(const c8* filename, bool ignoreCase=true, bool ignorePaths=true) + { + return addFileArchive(filename, ignoreCase, ignorePaths, EFAT_FOLDER); + } + + //! Adds a pak archive to the file system. + /** \deprecated This function is provided for compatibility + with older versions of Irrlicht and may be removed in Irrlicht 1.9, + you should use addFileArchive instead. + After calling this, the Irrlicht Engine will search and open files directly from this archive too. + This is useful for hiding data from the end user, speeding up file access and making it possible to + access for example Quake2/KingPin/Hexen2 .pak files + \param filename: Filename of the pak archive to add to the file system. + \param ignoreCase: If set to true, files in the archive can be accessed without + writing all letters in the right case. + \param ignorePaths: If set to true, files in the added archive can be accessed + without its complete path.(should not use with Quake2 paks + \return True if the archive was added successful, false if not. */ + _IRR_DEPRECATED_ virtual bool addPakFileArchive(const c8* filename, bool ignoreCase=true, bool ignorePaths=true) + { + return addFileArchive(filename, ignoreCase, ignorePaths, EFAT_PAK); + } + + //! Get the current working directory. + /** \return Current working directory as a string. */ + virtual const path& getWorkingDirectory() =0; + + //! Changes the current working directory. + /** \param newDirectory: A string specifying the new working directory. + The string is operating system dependent. Under Windows it has + the form ":\\\<..>". An example would be: "C:\Windows\" + \return True if successful, otherwise false. */ + virtual bool changeWorkingDirectoryTo(const path& newDirectory) =0; + + //! Converts a relative path to an absolute (unique) path, resolving symbolic links if required + /** \param filename Possibly relative file or directory name to query. + \result Absolute filename which points to the same file. */ + virtual path getAbsolutePath(const path& filename) const =0; + + //! Get the directory a file is located in. + /** \param filename: The file to get the directory from. + \return String containing the directory of the file. */ + virtual path getFileDir(const path& filename) const =0; + + //! Get 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 keepExtension True if filename with extension is returned otherwise everything + after the final '.' is removed as well. */ + virtual path getFileBasename(const path& filename, bool keepExtension=true) const =0; + + //! flatten a path and file name for example: "/you/me/../." becomes "/you" + virtual path& flattenFilename(path& directory, const path& root="/") const =0; + + //! Get the relative filename, relative to the given directory + virtual path getRelativeFilename(const path& filename, const path& directory) const =0; + + //! Creates a list of files and directories in the current working directory and returns it. + /** \return a Pointer to the created IFileList is returned. After the list has been used + it has to be deleted using its IFileList::drop() method. + See IReferenceCounted::drop() for more information. */ + virtual IFileList* createFileList() =0; + + //! Creates an empty filelist + /** \return a Pointer to the created IFileList is returned. After the list has been used + it has to be deleted using its IFileList::drop() method. + See IReferenceCounted::drop() for more information. */ + virtual IFileList* createEmptyFileList(const io::path& path, bool ignoreCase, bool ignorePaths) =0; + + //! Set the active type of file system. + virtual EFileSystemType setFileListSystem(EFileSystemType listType) =0; + + //! Determines if a file exists and could be opened. + /** \param filename is the string identifying the file which should be tested for existence. + \return True if file exists, and false if it does not exist or an error occurred. */ + virtual bool existFile(const path& filename) const =0; + + //! Creates a XML Reader from a file which returns all parsed strings as wide characters (wchar_t*). + /** Use createXMLReaderUTF8() if you prefer char* instead of wchar_t*. See IIrrXMLReader for + more information on how to use the parser. + \return 0, if file could not be opened, otherwise a pointer to the created + IXMLReader is returned. After use, the reader + has to be deleted using its IXMLReader::drop() method. + See IReferenceCounted::drop() for more information. */ + virtual IXMLReader* createXMLReader(const path& filename) =0; + + //! Creates a XML Reader from a file which returns all parsed strings as wide characters (wchar_t*). + /** Use createXMLReaderUTF8() if you prefer char* instead of wchar_t*. See IIrrXMLReader for + more information on how to use the parser. + \return 0, if file could not be opened, otherwise a pointer to the created + IXMLReader is returned. After use, the reader + has to be deleted using its IXMLReader::drop() method. + See IReferenceCounted::drop() for more information. */ + virtual IXMLReader* createXMLReader(IReadFile* file) =0; + + //! Creates a XML Reader from a file which returns all parsed strings as ASCII/UTF-8 characters (char*). + /** Use createXMLReader() if you prefer wchar_t* instead of char*. See IIrrXMLReader for + more information on how to use the parser. + \return 0, if file could not be opened, otherwise a pointer to the created + IXMLReader is returned. After use, the reader + has to be deleted using its IXMLReaderUTF8::drop() method. + See IReferenceCounted::drop() for more information. */ + virtual IXMLReaderUTF8* createXMLReaderUTF8(const path& filename) =0; + + //! Creates a XML Reader from a file which returns all parsed strings as ASCII/UTF-8 characters (char*). + /** Use createXMLReader() if you prefer wchar_t* instead of char*. See IIrrXMLReader for + more information on how to use the parser. + \return 0, if file could not be opened, otherwise a pointer to the created + IXMLReader is returned. After use, the reader + has to be deleted using its IXMLReaderUTF8::drop() method. + See IReferenceCounted::drop() for more information. */ + virtual IXMLReaderUTF8* createXMLReaderUTF8(IReadFile* file) =0; + + //! Creates a XML Writer from a file which will write ASCII/UTF-8 characters (char*). + /** \return 0, if file could not be opened, otherwise a pointer to the created + IXMLWriter is returned. After use, the reader + has to be deleted using its IXMLWriter::drop() method. + See IReferenceCounted::drop() for more information. */ + virtual IXMLWriterUTF8* createXMLWriterUTF8(const path& filename) =0; + + //! Creates a XML Writer from a file which will write ASCII/UTF-8 characters (char*). + /** \return 0, if file could not be opened, otherwise a pointer to the created + IXMLWriter is returned. After use, the reader + has to be deleted using its IXMLWriter::drop() method. + See IReferenceCounted::drop() for more information. */ + virtual IXMLWriterUTF8* createXMLWriterUTF8(IWriteFile* file) =0; + + //! Creates a XML Writer from a file. + /** \return 0, if file could not be opened, otherwise a pointer to the created + IXMLWriter is returned. After use, the reader + has to be deleted using its IXMLWriter::drop() method. + See IReferenceCounted::drop() for more information. */ + virtual IXMLWriter* createXMLWriter(const path& filename) =0; + + //! Creates a XML Writer from a file. + /** \return 0, if file could not be opened, otherwise a pointer to the created + IXMLWriter is returned. After use, the reader + has to be deleted using its IXMLWriter::drop() method. + See IReferenceCounted::drop() for more information. */ + virtual IXMLWriter* createXMLWriter(IWriteFile* file) =0; + + //! Creates a new empty collection of attributes, usable for serialization and more. + /** \param driver: Video driver to be used to load textures when specified as attribute values. + Can be null to prevent automatic texture loading by attributes. + \return Pointer to the created object. + If you no longer need the object, you should call IAttributes::drop(). + See IReferenceCounted::drop() for more information. */ + virtual IAttributes* createEmptyAttributes(video::IVideoDriver* driver=0) =0; +}; + + +} // end namespace io +} // end namespace irr + +#endif + diff --git a/include/IGPUProgrammingServices.h b/include/IGPUProgrammingServices.h new file mode 100644 index 00000000..abe910fc --- /dev/null +++ b/include/IGPUProgrammingServices.h @@ -0,0 +1,455 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GPU_PROGRAMMING_SERVICES_H_INCLUDED__ +#define __I_GPU_PROGRAMMING_SERVICES_H_INCLUDED__ + +#include "EShaderTypes.h" +#include "EMaterialTypes.h" +#include "EPrimitiveTypes.h" +#include "path.h" + +namespace irr +{ + +namespace io +{ + class IReadFile; +} // end namespace io + +namespace video +{ + +class IVideoDriver; +class IShaderConstantSetCallBack; + +//! Interface making it possible to create and use programs running on the GPU. +class IGPUProgrammingServices +{ +public: + + //! Destructor + virtual ~IGPUProgrammingServices() {} + + //! Adds a new high-level shading material renderer to the VideoDriver. + /** Currently only HLSL/D3D9 and GLSL/OpenGL are supported. + \param vertexShaderProgram String containing the source of the vertex + shader program. This can be 0 if no vertex program shall be used. + \param vertexShaderEntryPointName Name of the entry function of the + vertexShaderProgram (p.e. "main") + \param vsCompileTarget Vertex shader version the high level shader + shall be compiled to. + \param pixelShaderProgram String containing the source of the pixel + shader program. This can be 0 if no pixel shader shall be used. + \param pixelShaderEntryPointName Entry name of the function of the + pixelShaderProgram (p.e. "main") + \param psCompileTarget Pixel shader version the high level shader + shall be compiled to. + \param geometryShaderProgram String containing the source of the + geometry shader program. This can be 0 if no geometry shader shall be + used. + \param geometryShaderEntryPointName Entry name of the function of the + geometryShaderProgram (p.e. "main") + \param gsCompileTarget Geometry shader version the high level shader + shall be compiled to. + \param inType Type of vertices passed to geometry shader + \param outType Type of vertices created by geometry shader + \param verticesOut Maximal number of vertices created by geometry + shader. If 0, maximal number supported is assumed. + \param callback Pointer to an implementation of + IShaderConstantSetCallBack in which you can set the needed vertex, + pixel, and geometry shader program constants. Set this to 0 if you + don't need this. + \param baseMaterial Base material which renderstates will be used to + shade the material. + \param userData a user data int. This int can be set to any value and + will be set as parameter in the callback method when calling + OnSetConstants(). In this way it is easily possible to use the same + callback method for multiple materials and distinguish between them + during the call. + \return Number of the material type which can be set in + SMaterial::MaterialType to use the renderer. -1 is returned if an error + occurred, e.g. if a shader program could not be compiled or a compile + target is not reachable. The error strings are then printed to the + error log and can be caught with a custom event receiver. */ + virtual s32 addHighLevelShaderMaterial( + const c8* vertexShaderProgram, + const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, + const c8* pixelShaderProgram, + const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, + const c8* geometryShaderProgram, + const c8* geometryShaderEntryPointName = "main", + E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0, + scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES, + scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP, + u32 verticesOut = 0, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData = 0) = 0; + + //! convenience function for use without geometry shaders + s32 addHighLevelShaderMaterial( + const c8* vertexShaderProgram, + const c8* vertexShaderEntryPointName="main", + E_VERTEX_SHADER_TYPE vsCompileTarget=EVST_VS_1_1, + const c8* pixelShaderProgram=0, + const c8* pixelShaderEntryPointName="main", + E_PIXEL_SHADER_TYPE psCompileTarget=EPST_PS_1_1, + IShaderConstantSetCallBack* callback=0, + E_MATERIAL_TYPE baseMaterial=video::EMT_SOLID, + s32 userData=0) + { + return addHighLevelShaderMaterial( + vertexShaderProgram, vertexShaderEntryPointName, + vsCompileTarget, pixelShaderProgram, + pixelShaderEntryPointName, psCompileTarget, + 0, "main", EGST_GS_4_0, + scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, + callback, baseMaterial, userData); + } + + //! convenience function for use with many defaults, without geometry shader + /** All shader names are set to "main" and compile targets are shader + type 1.1. + */ + s32 addHighLevelShaderMaterial( + const c8* vertexShaderProgram, + const c8* pixelShaderProgram=0, + IShaderConstantSetCallBack* callback=0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData=0) + { + return addHighLevelShaderMaterial( + vertexShaderProgram, "main", + EVST_VS_1_1, pixelShaderProgram, + "main", EPST_PS_1_1, + 0, "main", EGST_GS_4_0, + scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, + callback, baseMaterial, userData); + } + + //! convenience function for use with many defaults, with geometry shader + /** All shader names are set to "main" and compile targets are shader + type 1.1 and geometry shader 4.0. + */ + s32 addHighLevelShaderMaterial( + const c8* vertexShaderProgram, + const c8* pixelShaderProgram = 0, + const c8* geometryShaderProgram = 0, + scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES, + scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP, + u32 verticesOut = 0, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData = 0 ) + { + return addHighLevelShaderMaterial( + vertexShaderProgram, "main", + EVST_VS_1_1, pixelShaderProgram, + "main", EPST_PS_1_1, + geometryShaderProgram, "main", EGST_GS_4_0, + inType, outType, verticesOut, + callback, baseMaterial, userData); + } + + //! Like IGPUProgrammingServices::addShaderMaterial(), but loads from files. + /** \param vertexShaderProgramFileName Text file containing the source + of the vertex shader program. Set to empty string if no vertex shader + shall be created. + \param vertexShaderEntryPointName Name of the entry function of the + vertexShaderProgram (p.e. "main") + \param vsCompileTarget Vertex shader version the high level shader + shall be compiled to. + \param pixelShaderProgramFileName Text file containing the source of + the pixel shader program. Set to empty string if no pixel shader shall + be created. + \param pixelShaderEntryPointName Entry name of the function of the + pixelShaderProgram (p.e. "main") + \param psCompileTarget Pixel shader version the high level shader + shall be compiled to. + \param geometryShaderProgramFileName Name of the source of + the geometry shader program. Set to empty string if no geometry shader + shall be created. + \param geometryShaderEntryPointName Entry name of the function of the + geometryShaderProgram (p.e. "main") + \param gsCompileTarget Geometry shader version the high level shader + shall be compiled to. + \param inType Type of vertices passed to geometry shader + \param outType Type of vertices created by geometry shader + \param verticesOut Maximal number of vertices created by geometry + shader. If 0, maximal number supported is assumed. + \param callback Pointer to an implementation of + IShaderConstantSetCallBack in which you can set the needed vertex, + pixel, and geometry shader program constants. Set this to 0 if you + don't need this. + \param baseMaterial Base material which renderstates will be used to + shade the material. + \param userData a user data int. This int can be set to any value and + will be set as parameter in the callback method when calling + OnSetConstants(). In this way it is easily possible to use the same + callback method for multiple materials and distinguish between them + during the call. + \return Number of the material type which can be set in + SMaterial::MaterialType to use the renderer. -1 is returned if an error + occurred, e.g. if a shader program could not be compiled or a compile + target is not reachable. The error strings are then printed to the + error log and can be caught with a custom event receiver. */ + virtual s32 addHighLevelShaderMaterialFromFiles( + const io::path& vertexShaderProgramFileName, + const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, + const io::path& pixelShaderProgramFileName, + const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, + const io::path& geometryShaderProgramFileName, + const c8* geometryShaderEntryPointName = "main", + E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0, + scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES, + scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP, + u32 verticesOut = 0, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData = 0) = 0; + + //! convenience function for use without geometry shaders + s32 addHighLevelShaderMaterialFromFiles( + const io::path& vertexShaderProgramFileName, + const c8* vertexShaderEntryPointName = "main", + E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1, + const io::path& pixelShaderProgramFileName = "", + const c8* pixelShaderEntryPointName = "main", + E_PIXEL_SHADER_TYPE psCompileTarget = EPST_PS_1_1, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData = 0) + { + return addHighLevelShaderMaterialFromFiles( + vertexShaderProgramFileName, vertexShaderEntryPointName, + vsCompileTarget, pixelShaderProgramFileName, + pixelShaderEntryPointName, psCompileTarget, + "", "main", EGST_GS_4_0, + scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, + callback, baseMaterial, userData); + } + + //! convenience function for use with many defaults, without geometry shader + /** All shader names are set to "main" and compile targets are shader + type 1.1. + */ + s32 addHighLevelShaderMaterialFromFiles( + const io::path& vertexShaderProgramFileName, + const io::path& pixelShaderProgramFileName = "", + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData = 0 ) + { + return addHighLevelShaderMaterialFromFiles( + vertexShaderProgramFileName, "main", + EVST_VS_1_1, pixelShaderProgramFileName, + "main", EPST_PS_1_1, + "", "main", EGST_GS_4_0, + scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, + callback, baseMaterial, userData); + } + + //! convenience function for use with many defaults, with geometry shader + /** All shader names are set to "main" and compile targets are shader + type 1.1 and geometry shader 4.0. + */ + s32 addHighLevelShaderMaterialFromFiles( + const io::path& vertexShaderProgramFileName, + const io::path& pixelShaderProgramFileName = "", + const io::path& geometryShaderProgramFileName = "", + scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES, + scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP, + u32 verticesOut = 0, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData = 0 ) + { + return addHighLevelShaderMaterialFromFiles( + vertexShaderProgramFileName, "main", + EVST_VS_1_1, pixelShaderProgramFileName, + "main", EPST_PS_1_1, + geometryShaderProgramFileName, "main", EGST_GS_4_0, + inType, outType, verticesOut, + callback, baseMaterial, userData); + } + + //! Like IGPUProgrammingServices::addShaderMaterial(), but loads from files. + /** \param vertexShaderProgram Text file handle containing the source + of the vertex shader program. Set to 0 if no vertex shader shall be + created. + \param vertexShaderEntryPointName Name of the entry function of the + vertexShaderProgram + \param vsCompileTarget Vertex shader version the high level shader + shall be compiled to. + \param pixelShaderProgram Text file handle containing the source of + the pixel shader program. Set to 0 if no pixel shader shall be created. + \param pixelShaderEntryPointName Entry name of the function of the + pixelShaderProgram (p.e. "main") + \param psCompileTarget Pixel shader version the high level shader + shall be compiled to. + \param geometryShaderProgram Text file handle containing the source of + the geometry shader program. Set to 0 if no geometry shader shall be + created. + \param geometryShaderEntryPointName Entry name of the function of the + geometryShaderProgram (p.e. "main") + \param gsCompileTarget Geometry shader version the high level shader + shall be compiled to. + \param inType Type of vertices passed to geometry shader + \param outType Type of vertices created by geometry shader + \param verticesOut Maximal number of vertices created by geometry + shader. If 0, maximal number supported is assumed. + \param callback Pointer to an implementation of + IShaderConstantSetCallBack in which you can set the needed vertex and + pixel shader program constants. Set this to 0 if you don't need this. + \param baseMaterial Base material which renderstates will be used to + shade the material. + \param userData a user data int. This int can be set to any value and + will be set as parameter in the callback method when calling + OnSetConstants(). In this way it is easily possible to use the same + callback method for multiple materials and distinguish between them + during the call. + \return Number of the material type which can be set in + SMaterial::MaterialType to use the renderer. -1 is returned if an + error occurred, e.g. if a shader program could not be compiled or a + compile target is not reachable. The error strings are then printed to + the error log and can be caught with a custom event receiver. */ + virtual s32 addHighLevelShaderMaterialFromFiles( + io::IReadFile* vertexShaderProgram, + const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, + io::IReadFile* pixelShaderProgram, + const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, + io::IReadFile* geometryShaderProgram, + const c8* geometryShaderEntryPointName = "main", + E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0, + scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES, + scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP, + u32 verticesOut = 0, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData = 0) = 0; + + //! convenience function for use without geometry shaders + s32 addHighLevelShaderMaterialFromFiles( + io::IReadFile* vertexShaderProgram, + const c8* vertexShaderEntryPointName = "main", + E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1, + io::IReadFile* pixelShaderProgram = 0, + const c8* pixelShaderEntryPointName = "main", + E_PIXEL_SHADER_TYPE psCompileTarget = EPST_PS_1_1, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData = 0) + { + return addHighLevelShaderMaterialFromFiles( + vertexShaderProgram, vertexShaderEntryPointName, + vsCompileTarget, pixelShaderProgram, + pixelShaderEntryPointName, psCompileTarget, + 0, "main", EGST_GS_4_0, + scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, + callback, baseMaterial, userData); + } + + //! Adds a new ASM shader material renderer to the VideoDriver + /** Note that it is a good idea to call IVideoDriver::queryFeature() in + advance to check if the IVideoDriver supports the vertex and/or pixel + shader version your are using. + + The material is added to the VideoDriver like with + IVideoDriver::addMaterialRenderer() and can be used like it had been + added with that method. + \param vertexShaderProgram String containing the source of the vertex + shader program. This can be 0 if no vertex program shall be used. + + For DX8 programs, the will always input registers look like this: v0: + position, v1: normal, v2: color, v3: texture coordinates, v4: texture + coordinates 2 if available. + + For DX9 programs, you can manually set the registers using the dcl_ + statements. + \param pixelShaderProgram String containing the source of the pixel + shader program. This can be 0 if you don't want to use a pixel shader. + \param callback Pointer to an implementation of + IShaderConstantSetCallBack in which you can set the needed vertex and + pixel shader program constants. Set this to 0 if you don't need this. + \param baseMaterial Base material which renderstates will be used to + shade the material. + \param userData a user data int. This int can be set to any value and + will be set as parameter in the callback method when calling + OnSetConstants(). In this way it is easily possible to use the same + callback method for multiple materials and distinguish between them + during the call. + \return Returns the number of the material type which can be set in + SMaterial::MaterialType to use the renderer. -1 is returned if an + error occurred. -1 is returned for example if a vertex or pixel shader + program could not be compiled, the error strings are then printed out + into the error log, and can be caught with a custom event receiver. */ + virtual s32 addShaderMaterial(const c8* vertexShaderProgram = 0, + const c8* pixelShaderProgram = 0, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData = 0) = 0; + + //! Like IGPUProgrammingServices::addShaderMaterial(), but loads from files. + /** \param vertexShaderProgram Text file containing the source of the + vertex shader program. Set to 0 if no shader shall be created. + \param pixelShaderProgram Text file containing the source of the pixel + shader program. Set to 0 if no shader shall be created. + \param callback Pointer to an IShaderConstantSetCallback object to + which the OnSetConstants function is called. + \param baseMaterial baseMaterial + \param userData a user data int. This int can be set to any value and + will be set as parameter in the callback method when calling + OnSetConstants(). In this way it is easily possible to use the same + callback method for multiple materials and distinguish between them + during the call. + \return Returns the number of the material type which can be set in + SMaterial::MaterialType to use the renderer. -1 is returned if an + error occurred. -1 is returned for example if a vertex or pixel shader + program could not be compiled, the error strings are then printed out + into the error log, and can be caught with a custom event receiver. */ + virtual s32 addShaderMaterialFromFiles(io::IReadFile* vertexShaderProgram, + io::IReadFile* pixelShaderProgram, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData = 0) = 0; + + //! Like IGPUProgrammingServices::addShaderMaterial(), but loads from files. + /** \param vertexShaderProgramFileName Text file name containing the + source of the vertex shader program. Set to 0 if no shader shall be + created. + \param pixelShaderProgramFileName Text file name containing the source + of the pixel shader program. Set to 0 if no shader shall be created. + \param callback Pointer to an IShaderConstantSetCallback object on + which the OnSetConstants function is called. + \param baseMaterial baseMaterial + \param userData a user data int. This int can be set to any value and + will be set as parameter in the callback method when calling + OnSetConstants(). In this way it is easily possible to use the same + callback method for multiple materials and distinguish between them + during the call. + \return Returns the number of the material type which can be set in + SMaterial::MaterialType to use the renderer. -1 is returned if an + error occurred. -1 is returned for example if a vertex or pixel shader + program could not be compiled, the error strings are then printed out + into the error log, and can be caught with a custom event receiver. */ + virtual s32 addShaderMaterialFromFiles(const io::path& vertexShaderProgramFileName, + const io::path& pixelShaderProgramFileName, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData = 0) = 0; +}; + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/include/IGUIButton.h b/include/IGUIButton.h new file mode 100644 index 00000000..1976adaf --- /dev/null +++ b/include/IGUIButton.h @@ -0,0 +1,264 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_BUTTON_H_INCLUDED__ +#define __I_GUI_BUTTON_H_INCLUDED__ + +#include "IGUIElement.h" + +namespace irr +{ + +namespace video +{ + class ITexture; +} // end namespace video + +namespace gui +{ + class IGUIFont; + class IGUISpriteBank; + + //! Current state of buttons used for drawing sprites. + //! Note that up to 3 states can be active at the same time: + //! EGBS_BUTTON_UP or EGBS_BUTTON_DOWN + //! EGBS_BUTTON_MOUSE_OVER or EGBS_BUTTON_MOUSE_OFF + //! EGBS_BUTTON_FOCUSED or EGBS_BUTTON_NOT_FOCUSED + enum EGUI_BUTTON_STATE + { + //! The button is not pressed. + EGBS_BUTTON_UP=0, + //! The button is currently pressed down. + EGBS_BUTTON_DOWN, + //! The mouse cursor is over the button + EGBS_BUTTON_MOUSE_OVER, + //! The mouse cursor is not over the button + EGBS_BUTTON_MOUSE_OFF, + //! The button has the focus + EGBS_BUTTON_FOCUSED, + //! The button doesn't have the focus + EGBS_BUTTON_NOT_FOCUSED, + //! The button is disabled All other states are ignored in that case. + EGBS_BUTTON_DISABLED, + //! not used, counts the number of enumerated items + EGBS_COUNT + }; + + //! Names for gui button state icons + const c8* const GUIButtonStateNames[EGBS_COUNT+1] = + { + "buttonUp", + "buttonDown", + "buttonMouseOver", + "buttonMouseOff", + "buttonFocused", + "buttonNotFocused", + "buttonDisabled", + 0 // count + }; + + //! State of buttons used for drawing texture images. + //! Note that only a single state is active at a time + //! Also when no image is defined for a state it will use images from another state + //! and if that state is not set from the replacement for that,etc. + //! So in many cases setting EGBIS_IMAGE_UP and EGBIS_IMAGE_DOWN is sufficient. + enum EGUI_BUTTON_IMAGE_STATE + { + //! When no other states have images they will all use this one. + EGBIS_IMAGE_UP, + //! When not set EGBIS_IMAGE_UP is used. + EGBIS_IMAGE_UP_MOUSEOVER, + //! When not set EGBIS_IMAGE_UP_MOUSEOVER is used. + EGBIS_IMAGE_UP_FOCUSED, + //! When not set EGBIS_IMAGE_UP_FOCUSED is used. + EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER, + //! When not set EGBIS_IMAGE_UP is used. + EGBIS_IMAGE_DOWN, + //! When not set EGBIS_IMAGE_DOWN is used. + EGBIS_IMAGE_DOWN_MOUSEOVER, + //! When not set EGBIS_IMAGE_DOWN_MOUSEOVER is used. + EGBIS_IMAGE_DOWN_FOCUSED, + //! When not set EGBIS_IMAGE_DOWN_FOCUSED is used. + EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER, + //! When not set EGBIS_IMAGE_UP or EGBIS_IMAGE_DOWN are used (depending on button state). + EGBIS_IMAGE_DISABLED, + //! not used, counts the number of enumerated items + EGBIS_COUNT + }; + + //! Names for gui button image states + const c8* const GUIButtonImageStateNames[EGBIS_COUNT+1] = + { + "Image", // not "ImageUp" as it otherwise breaks serialization of old files + "ImageUpOver", + "ImageUpFocused", + "ImageUpFocusedOver", + "PressedImage", // not "ImageDown" as it otherwise breaks serialization of old files + "ImageDownOver", + "ImageDownFocused", + "ImageDownFocusedOver", + "ImageDisabled", + 0 // count + }; + + //! GUI Button interface. + /** \par This element can create the following events of type EGUI_EVENT_TYPE: + \li EGET_BUTTON_CLICKED + */ + class IGUIButton : public IGUIElement + { + public: + + //! constructor + IGUIButton(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_BUTTON, environment, parent, id, rectangle) {} + + //! Sets another skin independent font. + /** If this is set to zero, the button uses the font of the skin. + \param font: New font to set. */ + virtual void setOverrideFont(IGUIFont* font=0) = 0; + + //! Gets the override font (if any) + /** \return The override font (may be 0) */ + virtual IGUIFont* getOverrideFont(void) const = 0; + + //! Get the font which is used right now for drawing + /** Currently this is the override font when one is set and the + font of the active skin otherwise */ + virtual IGUIFont* getActiveFont() const = 0; + + //! Sets another color for the button text. + /** When set, this color is used instead of EGDC_BUTTON_TEXT/EGDC_GRAY_TEXT. + You don't need to call enableOverrideColor(true), that's done by this function. + If you want the the color of the skin back, call enableOverrideColor(false); + \param color: New color of the text. */ + virtual void setOverrideColor(video::SColor color) = 0; + + //! Gets the override color + /** \return: The override color */ + virtual video::SColor getOverrideColor(void) const = 0; + + //! Sets if the button text should use the override color or the color in the gui skin. + /** \param enable: If set to true, the override color, which can be set + with IGUIStaticText::setOverrideColor is used, otherwise the + EGDC_BUTTON_TEXT or EGDC_GRAY_TEXT color of the skin. */ + virtual void enableOverrideColor(bool enable) = 0; + + //! Checks if an override color is enabled + /** \return true if the override color is enabled, false otherwise */ + virtual bool isOverrideColorEnabled(void) const = 0; + + //! Sets an image which should be displayed on the button when it is in the given state. + /** Only one image-state can be active at a time. Images are drawn below sprites. + If a state is without image it will try to use images from other states as described + in ::EGUI_BUTTON_IMAGE_STATE. + Images are a little less flexible than sprites, but easier to use. + \param state: One of ::EGUI_BUTTON_IMAGE_STATE + \param image: Image to be displayed or NULL to remove the image + \param sourceRect: Source rectangle on the image texture. When width or height are 0 then the full texture-size is used (default). */ + virtual void setImage(EGUI_BUTTON_IMAGE_STATE state, video::ITexture* image=0, const core::rect& sourceRect=core::rect(0,0,0,0)) = 0; + + //! Sets an image which should be displayed on the button when it is in normal state. + /** This is identical to calling setImage(EGBIS_IMAGE_UP, image); and might be deprecated in future revisions. + \param image: Image to be displayed */ + virtual void setImage(video::ITexture* image=0) = 0; + + //! Sets a background image for the button when it is in normal state. + /** This is identical to calling setImage(EGBIS_IMAGE_UP, image, sourceRect); and might be deprecated in future revisions. + \param image: Texture containing the image to be displayed + \param sourceRect: Position in the texture, where the image is located. + When width or height are 0 then the full texture-size is used */ + virtual void setImage(video::ITexture* image, const core::rect& sourceRect) = 0; + + //! Sets a background image for the button when it is in pressed state. + /** This is identical to calling setImage(EGBIS_IMAGE_DOWN, image); and might be deprecated in future revisions. + If no images is specified for the pressed state via + setPressedImage(), this image is also drawn in pressed state. + \param image: Image to be displayed */ + virtual void setPressedImage(video::ITexture* image=0) = 0; + + //! Sets an image which should be displayed on the button when it is in pressed state. + /** This is identical to calling setImage(EGBIS_IMAGE_DOWN, image, sourceRect); and might be deprecated in future revisions. + \param image: Texture containing the image to be displayed + \param sourceRect: Position in the texture, where the image is located */ + virtual void setPressedImage(video::ITexture* image, const core::rect& sourceRect) = 0; + + + //! Sets the sprite bank used by the button + /** NOTE: The spritebank itself is _not_ serialized so far. The sprites are serialized. + Which means after loading the gui you still have to set the spritebank manually. */ + virtual void setSpriteBank(IGUISpriteBank* bank=0) = 0; + + //! Sets the animated sprite for a specific button state + /** Several sprites can be drawn at the same time. + Sprites can be animated. + Sprites are drawn above the images. + \param index: Number of the sprite within the sprite bank, use -1 for no sprite + \param state: State of the button to set the sprite for + \param index: The sprite number from the current sprite bank + \param color: The color of the sprite + \param loop: True if the animation should loop, false if not + \param scale: True if the sprite should scale to button size, false if not */ + virtual void setSprite(EGUI_BUTTON_STATE state, s32 index, + video::SColor color=video::SColor(255,255,255,255), bool loop=false, bool scale=false) = 0; + + //! Get the sprite-index for the given state or -1 when no sprite is set + virtual s32 getSpriteIndex(EGUI_BUTTON_STATE state) const = 0; + + //! Get the sprite color for the given state. Color is only used when a sprite is set. + virtual video::SColor getSpriteColor(EGUI_BUTTON_STATE state) const = 0; + + //! Returns if the sprite in the given state does loop + virtual bool getSpriteLoop(EGUI_BUTTON_STATE state) const = 0; + + //! Returns if the sprite in the given state is scaled + virtual bool getSpriteScale(EGUI_BUTTON_STATE state) const = 0; + + //! Sets if the button should behave like a push button. + /** Which means it can be in two states: Normal or Pressed. With a click on the button, + the user can change the state of the button. */ + virtual void setIsPushButton(bool isPushButton=true) = 0; + + //! Sets the pressed state of the button if this is a pushbutton + virtual void setPressed(bool pressed=true) = 0; + + //! Returns if the button is currently pressed + virtual bool isPressed() const = 0; + + //! Sets if the alpha channel should be used for drawing background images on the button (default is false) + virtual void setUseAlphaChannel(bool useAlphaChannel=true) = 0; + + //! Returns if the alpha channel should be used for drawing background images on the button + virtual bool isAlphaChannelUsed() const = 0; + + //! Returns whether the button is a push button + virtual bool isPushButton() const = 0; + + //! Sets if the button should use the skin to draw its border and button face (default is true) + virtual void setDrawBorder(bool border=true) = 0; + + //! Returns if the border and button face are being drawn using the skin + virtual bool isDrawingBorder() const = 0; + + //! Sets if the button should scale the button images to fit + virtual void setScaleImage(bool scaleImage=true) = 0; + + //! Checks whether the button scales the used images + virtual bool isScalingImage() const = 0; + + //! Get if the shift key was pressed in last EGET_BUTTON_CLICKED event + /** Generated together with event, so info is available in the event-receiver. */ + virtual bool getClickShiftState() const = 0; + + //! Get if the control key was pressed in last EGET_BUTTON_CLICKED event + /** Generated together with event, so info is available in the event-receiver. */ + virtual bool getClickControlState() const = 0; + }; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUICheckBox.h b/include/IGUICheckBox.h new file mode 100644 index 00000000..3c0c8e3d --- /dev/null +++ b/include/IGUICheckBox.h @@ -0,0 +1,53 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_CHECKBOX_H_INCLUDED__ +#define __I_GUI_CHECKBOX_H_INCLUDED__ + +#include "IGUIElement.h" + +namespace irr +{ +namespace gui +{ + + //! GUI Check box interface. + /** \par This element can create the following events of type EGUI_EVENT_TYPE: + \li EGET_CHECKBOX_CHANGED + */ + class IGUICheckBox : public IGUIElement + { + public: + + //! constructor + IGUICheckBox(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_CHECK_BOX, environment, parent, id, rectangle) {} + + //! Set if box is checked. + virtual void setChecked(bool checked) = 0; + + //! Returns true if box is checked. + virtual bool isChecked() const = 0; + + //! Sets whether to draw the background + virtual void setDrawBackground(bool draw) = 0; + + //! Checks if background drawing is enabled + /** \return true if background drawing is enabled, false otherwise */ + virtual bool isDrawBackgroundEnabled() const = 0; + + //! Sets whether to draw the border + virtual void setDrawBorder(bool draw) = 0; + + //! Checks if border drawing is enabled + /** \return true if border drawing is enabled, false otherwise */ + virtual bool isDrawBorderEnabled() const = 0; + + }; + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUIColorSelectDialog.h b/include/IGUIColorSelectDialog.h new file mode 100644 index 00000000..a27991c9 --- /dev/null +++ b/include/IGUIColorSelectDialog.h @@ -0,0 +1,37 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_COLOR_SELECT_DIALOG_H_INCLUDED__ +#define __I_GUI_COLOR_SELECT_DIALOG_H_INCLUDED__ + +#include "IGUIElement.h" + +namespace irr +{ +namespace gui +{ + + //! Standard color chooser dialog. + class IGUIColorSelectDialog : public IGUIElement + { + public: + + //! constructor + IGUIColorSelectDialog(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_COLOR_SELECT_DIALOG, environment, parent, id, rectangle) {} + + //! get chosen color as usual SColor struct + virtual video::SColor getColor() =0; + + //! get chosen color as HSL values + virtual video::SColorHSL getColorHSL() =0; + + }; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUIComboBox.h b/include/IGUIComboBox.h new file mode 100644 index 00000000..8d238341 --- /dev/null +++ b/include/IGUIComboBox.h @@ -0,0 +1,74 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_COMBO_BOX_H_INCLUDED__ +#define __I_GUI_COMBO_BOX_H_INCLUDED__ + +#include "IGUIElement.h" + +namespace irr +{ +namespace gui +{ + + //! Combobox widget + /** \par This element can create the following events of type EGUI_EVENT_TYPE: + \li EGET_COMBO_BOX_CHANGED + */ + class IGUIComboBox : public IGUIElement + { + public: + + //! constructor + IGUIComboBox(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_COMBO_BOX, environment, parent, id, rectangle) {} + + //! Returns amount of items in box + virtual u32 getItemCount() const = 0; + + //! Returns string of an item. the idx may be a value from 0 to itemCount-1 + virtual const wchar_t* getItem(u32 idx) const = 0; + + //! Returns item data of an item. the idx may be a value from 0 to itemCount-1 + virtual u32 getItemData(u32 idx) const = 0; + + //! Returns index based on item data + virtual s32 getIndexForItemData(u32 data ) const = 0; + + //! Adds an item and returns the index of it + virtual u32 addItem(const wchar_t* text, u32 data = 0) = 0; + + //! Removes an item from the combo box. + /** Warning. This will change the index of all following items */ + virtual void removeItem(u32 idx) = 0; + + //! Deletes all items in the combo box + virtual void clear() = 0; + + //! Returns id of selected item. returns -1 if no item is selected. + virtual s32 getSelected() const = 0; + + //! Sets the selected item. Set this to -1 if no item should be selected + 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). */ + virtual void setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical) = 0; + + //! Set the maximal number of rows for the selection listbox + virtual void setMaxSelectionRows(u32 max) = 0; + + //! Get the maximal number of rows for the selection listbox + virtual u32 getMaxSelectionRows() const = 0; + }; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUIContextMenu.h b/include/IGUIContextMenu.h new file mode 100644 index 00000000..66237632 --- /dev/null +++ b/include/IGUIContextMenu.h @@ -0,0 +1,162 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_CONTEXT_MENU_H_INCLUDED__ +#define __I_GUI_CONTEXT_MENU_H_INCLUDED__ + +#include "IGUIElement.h" + +namespace irr +{ +namespace gui +{ + //! Close behavior. + //! Default is ECMC_REMOVE + enum ECONTEXT_MENU_CLOSE + { + //! do nothing - menu stays open + ECMC_IGNORE = 0, + + //! remove the gui element + ECMC_REMOVE = 1, + + //! call setVisible(false) + ECMC_HIDE = 2 + + // note to implementers - this is planned as bitset, so continue with 4 if you need to add further flags. + }; + + //! GUI Context menu interface. + /** \par This element can create the following events of type EGUI_EVENT_TYPE: + \li EGET_ELEMENT_CLOSED + \li EGET_MENU_ITEM_SELECTED + */ + class IGUIContextMenu : public IGUIElement + { + public: + + //! constructor + IGUIContextMenu(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_CONTEXT_MENU, environment, parent, id, rectangle) {} + + //! set behavior when menus are closed + virtual void setCloseHandling(ECONTEXT_MENU_CLOSE onClose) = 0; + + //! get current behavior when the menu will be closed + virtual ECONTEXT_MENU_CLOSE getCloseHandling() const = 0; + + //! Get amount of menu items + virtual u32 getItemCount() const = 0; + + //! Adds a menu item. + /** \param text: Text of menu item. Set this to 0 to create + an separator instead of a real item, which is the same like + calling addSeparator(); + \param commandId: Command id of menu item, a simple id you may + set to whatever you want. + \param enabled: Specifies if the menu item should be enabled. + \param hasSubMenu: Set this to true if there should be a submenu + at this item. You can access this submenu via getSubMenu(). + \param checked: Specifies if the menu item should be initially checked. + \param autoChecking: Specifies if the item should be checked by clicking + \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, bool autoChecking=false) = 0; + + //! Insert a menu item at specified position. + /** \param idx: Position to insert the new element, + should be smaller than itemcount otherwise the item is added to the end. + \param text: Text of menu item. Set this to 0 to create + an separator instead of a real item, which is the same like + calling addSeparator(); + \param commandId: Command id of menu item, a simple id you may + set to whatever you want. + \param enabled: Specifies if the menu item should be enabled. + \param hasSubMenu: Set this to true if there should be a submenu + at this item. You can access this submenu via getSubMenu(). + \param checked: Specifies if the menu item should be initially checked. + \param autoChecking: Specifies if the item should be checked by clicking + \return Returns the index of the new item */ + virtual u32 insertItem(u32 idx, const wchar_t* text, s32 commandId=-1, bool enabled=true, + bool hasSubMenu=false, bool checked=false, bool autoChecking=false) = 0; + + //! Find an item by its CommandID + /** + \param commandId: We are looking for the first item which has this commandID + \param idxStartSearch: Start searching from this index. + \return Returns the index of the item when found or otherwise -1. */ + virtual s32 findItemWithCommandId(s32 commandId, u32 idxStartSearch=0) const = 0; + + //! Adds a separator item to the menu + virtual void addSeparator() = 0; + + //! Get text of the menu item. + /** \param idx: Zero based index of the menu item */ + virtual const wchar_t* getItemText(u32 idx) const = 0; + + //! Sets text of the menu item. + /** \param idx: Zero based index of the menu item + \param text: New text of the item. */ + virtual void setItemText(u32 idx, const wchar_t* text) = 0; + + //! Check if a menu item is enabled + /** \param idx: Zero based index of the menu item */ + virtual bool isItemEnabled(u32 idx) const = 0; + + //! Sets if the menu item should be enabled. + /** \param idx: Zero based index of the menu item + \param enabled: True if it is enabled, otherwise false. */ + virtual void setItemEnabled(u32 idx, bool enabled) = 0; + + //! Sets if the menu item should be checked. + /** \param idx: Zero based index of the menu item + \param enabled: True if it is enabled, otherwise false. */ + virtual void setItemChecked(u32 idx, bool enabled) = 0; + + //! Check if a menu item is checked + /** \param idx: Zero based index of the menu item */ + virtual bool isItemChecked(u32 idx) const = 0; + + //! Removes a menu item + /** \param idx: Zero based index of the menu item */ + virtual void removeItem(u32 idx) = 0; + + //! Removes all menu items + virtual void removeAllItems() = 0; + + //! Get the selected item in the menu + /** \return Index of the selected item, -1 if none selected. */ + virtual s32 getSelectedItem() const = 0; + + //! Get the command id of a menu item + /** \param idx: Zero based index of the menu item */ + virtual s32 getItemCommandId(u32 idx) const = 0; + + //! Sets the command id of a menu item + /** \param idx: Zero based index of the menu item + \param id: Command id of menu item, a simple id you may + set to whatever you want. */ + virtual void setItemCommandId(u32 idx, s32 id) = 0; + + //! Get a pointer to the submenu of an item. + /** 0 is returned if there is no submenu + \param idx: Zero based index of the menu item + \return Returns a pointer to the submenu of an item. */ + virtual IGUIContextMenu* getSubMenu(u32 idx) const = 0; + + //! should the element change the checked status on clicking + virtual void setItemAutoChecking(u32 idx, bool autoChecking) = 0; + + //! does the element change the checked status on clicking + virtual bool getItemAutoChecking(u32 idx) const = 0; + + //! When an eventparent is set it receives events instead of the usual parent element + virtual void setEventParent(IGUIElement *parent) = 0; + }; + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUIEditBox.h b/include/IGUIEditBox.h new file mode 100644 index 00000000..0c126a3f --- /dev/null +++ b/include/IGUIEditBox.h @@ -0,0 +1,157 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_EDIT_BOX_H_INCLUDED__ +#define __I_GUI_EDIT_BOX_H_INCLUDED__ + +#include "IGUIElement.h" +#include "SColor.h" + +namespace irr +{ +namespace gui +{ + class IGUIFont; + + //! Single line edit box for editing simple text. + /** \par This element can create the following events of type EGUI_EVENT_TYPE: + \li EGET_EDITBOX_ENTER + \li EGET_EDITBOX_CHANGED + \li EGET_EDITBOX_MARKING_CHANGED + */ + class IGUIEditBox : public IGUIElement + { + public: + + //! constructor + IGUIEditBox(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_EDIT_BOX, environment, parent, id, rectangle) {} + + //! Sets another skin independent font. + /** If this is set to zero, the button uses the font of the skin. + \param font: New font to set. */ + virtual void setOverrideFont(IGUIFont* font=0) = 0; + + //! Gets the override font (if any) + /** \return The override font (may be 0) */ + virtual IGUIFont* getOverrideFont() const = 0; + + //! Get the font which is used right now for drawing + /** Currently this is the override font when one is set and the + font of the active skin otherwise */ + virtual IGUIFont* getActiveFont() const = 0; + + //! Sets another color for the text. + /** If set, the edit box does not use the EGDC_BUTTON_TEXT color defined + in the skin, but the set color instead. You don't need to call + IGUIEditBox::enableOverrrideColor(true) after this, this is done + by this function. + If you set a color, and you want the text displayed with the color + of the skin again, call IGUIEditBox::enableOverrideColor(false); + \param color: New color of the text. */ + virtual void setOverrideColor(video::SColor color) = 0; + + //! Gets the override color + virtual video::SColor getOverrideColor() const = 0; + + //! Sets if the text should use the override color or the color in the gui skin. + /** \param enable: If set to true, the override color, which can be set + with IGUIEditBox::setOverrideColor is used, otherwise the + EGDC_BUTTON_TEXT color of the skin. */ + virtual void enableOverrideColor(bool enable) = 0; + + //! Checks if an override color is enabled + /** \return true if the override color is enabled, false otherwise */ + virtual bool isOverrideColorEnabled(void) const = 0; + + //! Sets whether to draw the background + virtual void setDrawBackground(bool draw) = 0; + + //! Checks if background drawing is enabled + /** \return true if background drawing is enabled, false otherwise */ + virtual bool isDrawBackgroundEnabled() const = 0; + + //! Turns the border on or off + /** \param border: true if you want the border to be drawn, false if not */ + virtual void setDrawBorder(bool border) = 0; + + //! Checks if border drawing is enabled + /** \return true if border drawing is enabled, false otherwise */ + virtual bool isDrawBorderEnabled() const = 0; + + //! Sets text justification mode + /** \param horizontal: EGUIA_UPPERLEFT for left justified (default), + EGUIA_LOWERRIGHT for right justified, or EGUIA_CENTER for centered text. + \param vertical: EGUIA_UPPERLEFT to align with top edge, + EGUIA_LOWERRIGHT for bottom edge, or EGUIA_CENTER for centered text (default). */ + virtual void setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical) = 0; + + //! Enables or disables word wrap. + /** \param enable: If set to true, words going over one line are + broken to the next line. */ + virtual void setWordWrap(bool enable) = 0; + + //! Checks if word wrap is enabled + /** \return true if word wrap is enabled, false otherwise */ + virtual bool isWordWrapEnabled() const = 0; + + //! Enables or disables newlines. + /** \param enable: If set to true, the EGET_EDITBOX_ENTER event will not be fired, + instead a newline character will be inserted. */ + virtual void setMultiLine(bool enable) = 0; + + //! Checks if multi line editing is enabled + /** \return true if multi-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 */ + virtual void setAutoScroll(bool enable) = 0; + + //! Checks to see if automatic scrolling is enabled + /** \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 + /** 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 */ + virtual void setPasswordBox(bool passwordBox, wchar_t passwordChar = L'*') = 0; + + //! Returns true if the edit box is currently a password box. + virtual bool isPasswordBox() const = 0; + + //! Gets the size area of the text in the edit box + /** \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 + infinity. */ + virtual void setMax(u32 max) = 0; + + //! Returns maximum amount of characters, previously set by setMax(); + virtual u32 getMax() const = 0; + + //! Set the character used for the cursor. + /** By default it's "_" */ + virtual void setCursorChar(const wchar_t cursorChar) = 0; + + //! Get the character used for the cursor. + virtual wchar_t getCursorChar() const = 0; + + //! Set the blinktime for the cursor. 2x blinktime is one full cycle. + //** \param timeMs Blinktime in milliseconds. When set to 0 the cursor is constantly on without blinking */ + virtual void setCursorBlinkTime(irr::u32 timeMs) = 0; + + //! Get the cursor blinktime + virtual irr::u32 getCursorBlinkTime() const = 0; + }; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUIElement.h b/include/IGUIElement.h new file mode 100644 index 00000000..d5d0bace --- /dev/null +++ b/include/IGUIElement.h @@ -0,0 +1,1046 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_ELEMENT_H_INCLUDED__ +#define __I_GUI_ELEMENT_H_INCLUDED__ + +#include "IAttributeExchangingObject.h" +#include "irrList.h" +#include "rect.h" +#include "irrString.h" +#include "IEventReceiver.h" +#include "EGUIElementTypes.h" +#include "EGUIAlignment.h" +#include "IAttributes.h" +#include "IGUIEnvironment.h" + +namespace irr +{ +namespace gui +{ +//! Base class of all GUI elements. +class IGUIElement : public virtual io::IAttributeExchangingObject, public IEventReceiver +{ +public: + + //! Constructor + IGUIElement(EGUI_ELEMENT_TYPE type, IGUIEnvironment* environment, IGUIElement* parent, + s32 id, const core::rect& rectangle) + : Parent(0), RelativeRect(rectangle), AbsoluteRect(rectangle), + AbsoluteClippingRect(rectangle), DesiredRect(rectangle), + MaxSize(0,0), MinSize(1,1), IsVisible(true), IsEnabled(true), + IsSubElement(false), NoClip(false), ID(id), IsTabStop(false), TabOrder(-1), IsTabGroup(false), + AlignLeft(EGUIA_UPPERLEFT), AlignRight(EGUIA_UPPERLEFT), AlignTop(EGUIA_UPPERLEFT), AlignBottom(EGUIA_UPPERLEFT), + Environment(environment), Type(type) + { + #ifdef _DEBUG + setDebugName("IGUIElement"); + #endif + + // if we were given a parent to attach to + if (parent) + { + parent->addChildToEnd(this); + recalculateAbsolutePosition(true); + } + } + + + //! Destructor + virtual ~IGUIElement() + { + // delete all children + core::list::Iterator it = Children.begin(); + for (; it != Children.end(); ++it) + { + (*it)->Parent = 0; + (*it)->drop(); + } + } + + + //! Returns parent of this element. + IGUIElement* getParent() const + { + return Parent; + } + + //! Returns the relative rectangle of this element. + core::rect getRelativePosition() const + { + return RelativeRect; + } + + + //! Sets the relative rectangle of this element. + /** \param r The absolute position to set */ + void setRelativePosition(const core::rect& r) + { + if (Parent) + { + const core::rect& r2 = Parent->getAbsolutePosition(); + + core::dimension2df d((f32)(r2.getSize().Width), (f32)(r2.getSize().Height)); + + if (AlignLeft == EGUIA_SCALE) + ScaleRect.UpperLeftCorner.X = (f32)r.UpperLeftCorner.X / d.Width; + if (AlignRight == EGUIA_SCALE) + ScaleRect.LowerRightCorner.X = (f32)r.LowerRightCorner.X / d.Width; + if (AlignTop == EGUIA_SCALE) + ScaleRect.UpperLeftCorner.Y = (f32)r.UpperLeftCorner.Y / d.Height; + if (AlignBottom == EGUIA_SCALE) + ScaleRect.LowerRightCorner.Y = (f32)r.LowerRightCorner.Y / d.Height; + } + + DesiredRect = r; + updateAbsolutePosition(); + } + + //! 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. */ + 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); + 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. + Meaningful values are in the range [0...1], unless you intend this element to spill + outside its parent. */ + void setRelativePositionProportional(const core::rect& r) + { + if (!Parent) + return; + + const core::dimension2di& d = Parent->getAbsolutePosition().getSize(); + + DesiredRect = core::rect( + core::floor32((f32)d.Width * r.UpperLeftCorner.X), + core::floor32((f32)d.Height * r.UpperLeftCorner.Y), + core::floor32((f32)d.Width * r.LowerRightCorner.X), + core::floor32((f32)d.Height * r.LowerRightCorner.Y)); + + ScaleRect = r; + + updateAbsolutePosition(); + } + + + //! Gets the absolute rectangle of this element + core::rect getAbsolutePosition() const + { + return AbsoluteRect; + } + + + //! Returns the visible area of the element. + core::rect getAbsoluteClippingRect() const + { + return AbsoluteClippingRect; + } + + + //! 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. */ + void setNotClipped(bool noClip) + { + NoClip = noClip; + updateAbsolutePosition(); + } + + + //! Gets whether the element will ignore its parent's clipping rectangle + /** \return true if the element is not clipped by its parent's clipping rectangle. */ + bool isNotClipped() const + { + return NoClip; + } + + + //! Sets the maximum size allowed for this element + /** If set to 0,0, there is no maximum size */ + void setMaxSize(core::dimension2du size) + { + MaxSize = size; + updateAbsolutePosition(); + } + + + //! Sets the minimum size allowed for this element + void setMinSize(core::dimension2du size) + { + MinSize = size; + if (MinSize.Width < 1) + MinSize.Width = 1; + if (MinSize.Height < 1) + MinSize.Height = 1; + updateAbsolutePosition(); + } + + + //! The alignment defines how the borders of this element will be positioned when the parent element is resized. + void setAlignment(EGUI_ALIGNMENT left, EGUI_ALIGNMENT right, EGUI_ALIGNMENT top, EGUI_ALIGNMENT bottom) + { + AlignLeft = left; + AlignRight = right; + AlignTop = top; + AlignBottom = bottom; + + if (Parent) + { + core::rect r(Parent->getAbsolutePosition()); + + core::dimension2df d((f32)r.getSize().Width, (f32)r.getSize().Height); + + if (AlignLeft == EGUIA_SCALE) + ScaleRect.UpperLeftCorner.X = (f32)DesiredRect.UpperLeftCorner.X / d.Width; + if (AlignRight == EGUIA_SCALE) + ScaleRect.LowerRightCorner.X = (f32)DesiredRect.LowerRightCorner.X / d.Width; + if (AlignTop == EGUIA_SCALE) + ScaleRect.UpperLeftCorner.Y = (f32)DesiredRect.UpperLeftCorner.Y / d.Height; + if (AlignBottom == EGUIA_SCALE) + ScaleRect.LowerRightCorner.Y = (f32)DesiredRect.LowerRightCorner.Y / d.Height; + } + } + + + //! Updates the absolute position. + virtual void updateAbsolutePosition() + { + recalculateAbsolutePosition(false); + + // update all children + core::list::Iterator it = Children.begin(); + for (; it != Children.end(); ++it) + { + (*it)->updateAbsolutePosition(); + } + } + + + //! 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. + */ + virtual IGUIElement* getElementFromPoint(const core::position2d& point) + { + IGUIElement* target = 0; + + // we have to search from back to front, because later children + // might be drawn over the top of earlier ones. + + core::list::ConstIterator it = Children.getLast(); + + if (isVisible()) + { + while(it != Children.end()) + { + target = (*it)->getElementFromPoint(point); + if (target) + return target; + + --it; + } + } + + if (isVisible() && isPointInside(point)) + target = this; + + return target; + } + + + //! Returns true if a point is within this element. + /** 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) + { + if ( child && child != this ) + { + addChildToEnd(child); + child->updateAbsolutePosition(); + } + } + + //! Removes a child. + virtual void removeChild(IGUIElement* child) + { + core::list::Iterator it = Children.begin(); + for (; it != Children.end(); ++it) + if ((*it) == child) + { + (*it)->Parent = 0; + (*it)->drop(); + Children.erase(it); + return; + } + } + + + //! Removes this element from its parent. + virtual void remove() + { + if (Parent) + Parent->removeChild(this); + } + + + //! Draws the element and its children. + virtual void draw() + { + if ( isVisible() ) + { + core::list::Iterator it = Children.begin(); + for (; it != Children.end(); ++it) + (*it)->draw(); + } + } + + + //! animate the element and its children. + virtual void OnPostRender(u32 timeMs) + { + if ( isVisible() ) + { + core::list::Iterator it = Children.begin(); + for (; it != Children.end(); ++it) + (*it)->OnPostRender( timeMs ); + } + } + + + //! Moves this element. + virtual void move(core::position2d absoluteMovement) + { + setRelativePosition(DesiredRect + absoluteMovement); + } + + + //! Returns true if element is visible. + virtual bool isVisible() const + { + return IsVisible; + } + + //! Check whether the element is truly visible, taking into accounts its parents' visibility + /** \return true if the element and all its parents are visible, + false if this or any parent element is invisible. */ + virtual bool isTrulyVisible() const + { + if(!IsVisible) + return false; + + if(!Parent) + return true; + + return Parent->isTrulyVisible(); + } + + //! Sets the visible state of this element. + virtual void setVisible(bool visible) + { + IsVisible = visible; + } + + + //! Returns true if this element was created as part of its parent control + virtual bool isSubElement() const + { + return IsSubElement; + } + + + //! 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. */ + void setTabStop(bool enable) + { + IsTabStop = enable; + } + + + //! Returns true if this element can be focused by navigating with the tab key + bool isTabStop() const + { + return IsTabStop; + } + + + //! 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 + if (index < 0) + { + TabOrder = 0; + IGUIElement *el = getTabGroup(); + while (IsTabGroup && el && el->Parent) + el = el->Parent; + + IGUIElement *first=0, *closest=0; + if (el) + { + // find the highest element number + el->getNextElement(-1, true, IsTabGroup, first, closest, true); + if (first) + { + TabOrder = first->getTabOrder() + 1; + } + } + + } + else + TabOrder = index; + } + + + //! Returns the number in the tab order sequence + s32 getTabOrder() const + { + return TabOrder; + } + + + //! 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; + } + + + //! Returns true if this element is a tab group. + bool isTabGroup() const + { + return IsTabGroup; + } + + + //! Returns the container element which holds all elements in this element's tab group. + IGUIElement* getTabGroup() + { + IGUIElement *ret=this; + + while (ret && !ret->isTabGroup()) + ret = ret->getParent(); + + return ret; + } + + + //! Returns true if element is enabled + /** Currently elements do _not_ care about parent-states. + So if you want to affect children you have to enable/disable them all. + The only exception to this are sub-elements which also check their parent. + */ + virtual bool isEnabled() const + { + if ( isSubElement() && IsEnabled && getParent() ) + return getParent()->isEnabled(); + + return IsEnabled; + } + + + //! Sets the enabled state of this element. + virtual void setEnabled(bool enabled) + { + IsEnabled = enabled; + } + + + //! Sets the new caption of this element. + virtual void setText(const wchar_t* text) + { + Text = text; + } + + + //! Returns caption of this element. + virtual const wchar_t* getText() const + { + return Text.c_str(); + } + + + //! Sets the new caption of this element. + virtual void setToolTipText(const wchar_t* text) + { + ToolTipText = text; + } + + + //! Returns caption of this element. + virtual const core::stringw& getToolTipText() const + { + return ToolTipText; + } + + + //! Returns id. Can be used to identify the element. + virtual s32 getID() const + { + return ID; + } + + + //! Sets the id of this element + virtual void setID(s32 id) + { + ID = id; + } + + + //! Called if an event happened. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_ + { + return Parent ? Parent->OnEvent(event) : false; + } + + + //! Brings a child to front + /** \return True if successful, false if not. */ + virtual bool bringToFront(IGUIElement* element) + { + core::list::Iterator it = Children.begin(); + for (; it != Children.end(); ++it) + { + if (element == (*it)) + { + Children.erase(it); + Children.push_back(element); + return true; + } + } + + return false; + } + + + //! Moves a child to the back, so it's siblings are drawn on top of it + /** \return True if successful, false if not. */ + virtual bool sendToBack(IGUIElement* child) + { + core::list::Iterator it = Children.begin(); + if (child == (*it)) // already there + return true; + for (; it != Children.end(); ++it) + { + if (child == (*it)) + { + Children.erase(it); + Children.push_front(child); + return true; + } + } + + return false; + } + + //! Returns list with children of this element + virtual const core::list& getChildren() const + { + return Children; + } + + + //! Finds the first element with the given id. + /** \param id: Id to search for. + \param searchchildren: Set this to true, if also children of this + element may contain the element with the searched id and they + should be searched too. + \return Returns the first element with the given id. If no element + with this id was found, 0 is returned. */ + virtual IGUIElement* getElementFromId(s32 id, bool searchchildren=false) const + { + IGUIElement* e = 0; + + core::list::ConstIterator it = Children.begin(); + for (; it != Children.end(); ++it) + { + if ((*it)->getID() == id) + return (*it); + + if (searchchildren) + e = (*it)->getElementFromId(id, true); + + if (e) + return e; + } + + return e; + } + + + //! returns true if the given element is a child of this one. + //! \param child: The child element to check + bool isMyChild(IGUIElement* child) const + { + if (!child) + return false; + do + { + if (child->Parent) + child = child->Parent; + + } while (child->Parent && child != this); + + + return child == this; + } + + + //! 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) + \param includeDisabled: includes disabled 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, + bool includeDisabled=false) const + { + // we'll stop searching if we find this number + s32 wanted = startOrder + ( reverse ? -1 : 1 ); + if (wanted==-2) + wanted = 1073741824; // maximum s32 + + core::list::ConstIterator it = Children.begin(); + + s32 closestOrder, currentOrder; + + while(it != Children.end()) + { + // ignore invisible elements and their children + if ( ( (*it)->isVisible() || includeInvisible ) && + (group == true || (*it)->isTabGroup() == false) ) + { + // ignore disabled, but children are checked (disabled is currently per element ignoring parent states) + if ( (*it)->isEnabled() || includeDisabled ) + { + // only check tab stops and those with the same group status + if ((*it)->isTabStop() && ((*it)->isTabGroup() == group)) + { + currentOrder = (*it)->getTabOrder(); + + // is this what we're looking for? + if (currentOrder == wanted) + { + closest = *it; + return true; + } + + // is it closer than the current closest? + if (closest) + { + closestOrder = closest->getTabOrder(); + if ( ( reverse && currentOrder > closestOrder && currentOrder < startOrder) + ||(!reverse && currentOrder < closestOrder && currentOrder > startOrder)) + { + closest = *it; + } + } + else + if ( (reverse && currentOrder < startOrder) || (!reverse && currentOrder > startOrder) ) + { + closest = *it; + } + + // is it before the current first? + if (first) + { + closestOrder = first->getTabOrder(); + + if ( (reverse && closestOrder < currentOrder) || (!reverse && closestOrder > currentOrder) ) + { + first = *it; + } + } + else + { + first = *it; + } + } + } + // search within children + if ((*it)->getNextElement(startOrder, reverse, group, first, closest)) + { + return true; + } + } + ++it; + } + return false; + } + + + //! Returns the type of the gui element. + /** This is needed for the .NET wrapper but will be used + later for serializing and deserializing. + If you wrote your own GUIElements, you need to set the type for your element as first parameter + in the constructor of IGUIElement. For own (=unknown) elements, simply use EGUIET_ELEMENT as type */ + EGUI_ELEMENT_TYPE getType() const + { + return Type; + } + + //! Returns true if the gui element supports the given type. + /** This is mostly used to check if you can cast a gui element to the class that goes with the type. + Most gui elements will only support their own type, but if you derive your own classes from interfaces + you can overload this function and add a check for the type of the base-class additionally. + This allows for checks comparable to the dynamic_cast of c++ with enabled rtti. + Note that you can't do that by calling BaseClass::hasType(type), but you have to do an explicit + comparison check, because otherwise the base class usually just checks for the member variable + Type which contains the type of your derived class. + */ + virtual bool hasType(EGUI_ELEMENT_TYPE type) const + { + return type == Type; + } + + + //! Returns the type name of the gui element. + /** This is needed serializing elements. For serializing your own elements, override this function + and return your own type name which is created by your IGUIElementFactory */ + virtual const c8* getTypeName() const + { + return GUIElementTypeNames[Type]; + } + + //! Returns the name of the element. + /** \return Name as character string. */ + virtual const c8* getName() const + { + return Name.c_str(); + } + + + //! Sets the name of the element. + /** \param name New name of the gui element. */ + virtual void setName(const c8* name) + { + Name = name; + } + + + //! Sets the name of the element. + /** \param name New name of the gui element. */ + virtual void setName(const core::stringc& name) + { + Name = name; + } + + + //! 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. */ + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_ + { + out->addString("Name", Name.c_str()); + out->addInt("Id", ID ); + out->addString("Caption", getText()); + out->addString("ToolTip", getToolTipText().c_str()); + out->addRect("Rect", DesiredRect); + out->addPosition2d("MinSize", core::position2di(MinSize.Width, MinSize.Height)); + out->addPosition2d("MaxSize", core::position2di(MaxSize.Width, MaxSize.Height)); + out->addEnum("LeftAlign", AlignLeft, GUIAlignmentNames); + out->addEnum("RightAlign", AlignRight, GUIAlignmentNames); + out->addEnum("TopAlign", AlignTop, GUIAlignmentNames); + out->addEnum("BottomAlign", AlignBottom, GUIAlignmentNames); + out->addBool("Visible", IsVisible); + out->addBool("Enabled", IsEnabled); + out->addBool("TabStop", IsTabStop); + out->addBool("TabGroup", IsTabGroup); + out->addInt("TabOrder", TabOrder); + out->addBool("NoClip", NoClip); + } + + + //! 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. */ + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_ + { + setName(in->getAttributeAsString("Name", Name)); + setID(in->getAttributeAsInt("Id", ID)); + setText(in->getAttributeAsStringW("Caption", Text).c_str()); + setToolTipText(in->getAttributeAsStringW("ToolTip").c_str()); + setVisible(in->getAttributeAsBool("Visible", IsVisible)); + setEnabled(in->getAttributeAsBool("Enabled", IsEnabled)); + IsTabStop = in->getAttributeAsBool("TabStop", IsTabStop); + IsTabGroup = in->getAttributeAsBool("TabGroup", IsTabGroup); + TabOrder = in->getAttributeAsInt("TabOrder", TabOrder); + + core::position2di p = in->getAttributeAsPosition2d("MaxSize", core::position2di(MaxSize.Width, MaxSize.Height)); + setMaxSize(core::dimension2du(p.X,p.Y)); + + p = in->getAttributeAsPosition2d("MinSize", core::position2di(MinSize.Width, MinSize.Height)); + setMinSize(core::dimension2du(p.X,p.Y)); + + setAlignment((EGUI_ALIGNMENT) in->getAttributeAsEnumeration("LeftAlign", GUIAlignmentNames, AlignLeft), + (EGUI_ALIGNMENT)in->getAttributeAsEnumeration("RightAlign", GUIAlignmentNames, AlignRight), + (EGUI_ALIGNMENT)in->getAttributeAsEnumeration("TopAlign", GUIAlignmentNames, AlignTop), + (EGUI_ALIGNMENT)in->getAttributeAsEnumeration("BottomAlign", GUIAlignmentNames, AlignBottom)); + + setRelativePosition(in->getAttributeAsRect("Rect", DesiredRect)); + + setNotClipped(in->getAttributeAsBool("NoClip", NoClip)); + } + +protected: + // not virtual because needed in constructor + void addChildToEnd(IGUIElement* child) + { + if (child) + { + child->grab(); // prevent destruction when removed + child->remove(); // remove from old parent + child->LastParentRect = getAbsolutePosition(); + child->Parent = this; + Children.push_back(child); + } + } + + // not virtual because needed in constructor + void recalculateAbsolutePosition(bool recursive) + { + core::rect parentAbsolute(0,0,0,0); + core::rect parentAbsoluteClip; + f32 fw=0.f, fh=0.f; + + if (Parent) + { + parentAbsolute = Parent->AbsoluteRect; + + if (NoClip) + { + IGUIElement* p=this; + while (p->Parent) + p = p->Parent; + parentAbsoluteClip = p->AbsoluteClippingRect; + } + else + parentAbsoluteClip = Parent->AbsoluteClippingRect; + } + + 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(); + + if (AlignTop == EGUIA_SCALE || AlignBottom == EGUIA_SCALE) + fh = (f32)parentAbsolute.getHeight(); + + switch (AlignLeft) + { + case EGUIA_UPPERLEFT: + break; + case EGUIA_LOWERRIGHT: + DesiredRect.UpperLeftCorner.X += diffx; + break; + case EGUIA_CENTER: + DesiredRect.UpperLeftCorner.X += diffx/2; + break; + case EGUIA_SCALE: + DesiredRect.UpperLeftCorner.X = core::round32(ScaleRect.UpperLeftCorner.X * fw); + break; + } + + switch (AlignRight) + { + case EGUIA_UPPERLEFT: + break; + case EGUIA_LOWERRIGHT: + DesiredRect.LowerRightCorner.X += diffx; + break; + case EGUIA_CENTER: + DesiredRect.LowerRightCorner.X += diffx/2; + break; + case EGUIA_SCALE: + DesiredRect.LowerRightCorner.X = core::round32(ScaleRect.LowerRightCorner.X * fw); + break; + } + + switch (AlignTop) + { + case EGUIA_UPPERLEFT: + break; + case EGUIA_LOWERRIGHT: + DesiredRect.UpperLeftCorner.Y += diffy; + break; + case EGUIA_CENTER: + DesiredRect.UpperLeftCorner.Y += diffy/2; + break; + case EGUIA_SCALE: + DesiredRect.UpperLeftCorner.Y = core::round32(ScaleRect.UpperLeftCorner.Y * fh); + break; + } + + switch (AlignBottom) + { + case EGUIA_UPPERLEFT: + break; + case EGUIA_LOWERRIGHT: + DesiredRect.LowerRightCorner.Y += diffy; + break; + case EGUIA_CENTER: + DesiredRect.LowerRightCorner.Y += diffy/2; + break; + case EGUIA_SCALE: + DesiredRect.LowerRightCorner.Y = core::round32(ScaleRect.LowerRightCorner.Y * fh); + break; + } + + RelativeRect = DesiredRect; + + const s32 w = RelativeRect.getWidth(); + const s32 h = RelativeRect.getHeight(); + + // make sure the desired rectangle is allowed + if (w < (s32)MinSize.Width) + RelativeRect.LowerRightCorner.X = RelativeRect.UpperLeftCorner.X + MinSize.Width; + if (h < (s32)MinSize.Height) + RelativeRect.LowerRightCorner.Y = RelativeRect.UpperLeftCorner.Y + MinSize.Height; + if (MaxSize.Width && w > (s32)MaxSize.Width) + RelativeRect.LowerRightCorner.X = RelativeRect.UpperLeftCorner.X + MaxSize.Width; + if (MaxSize.Height && h > (s32)MaxSize.Height) + RelativeRect.LowerRightCorner.Y = RelativeRect.UpperLeftCorner.Y + MaxSize.Height; + + RelativeRect.repair(); + + AbsoluteRect = RelativeRect + parentAbsolute.UpperLeftCorner; + + if (!Parent) + parentAbsoluteClip = AbsoluteRect; + + AbsoluteClippingRect = AbsoluteRect; + AbsoluteClippingRect.clipAgainst(parentAbsoluteClip); + + LastParentRect = parentAbsolute; + + if ( recursive ) + { + // update all children + core::list::Iterator it = Children.begin(); + for (; it != Children.end(); ++it) + { + (*it)->recalculateAbsolutePosition(recursive); + } + } + } + +protected: + + //! List of all children of this element + core::list Children; + + //! Pointer to the parent + IGUIElement* Parent; + + //! relative rect of element + core::rect RelativeRect; + + //! absolute rect of element + core::rect AbsoluteRect; + + //! absolute clipping rect of element + core::rect AbsoluteClippingRect; + + //! the rectangle the element would prefer to be, + //! if it was not constrained by parent or max/min size + core::rect DesiredRect; + + //! for calculating the difference when resizing parent + core::rect LastParentRect; + + //! relative scale of the element inside its parent + core::rect ScaleRect; + + //! maximum and minimum size of the element + core::dimension2du MaxSize, MinSize; + + //! is visible? + bool IsVisible; + + //! is enabled? + bool IsEnabled; + + //! is a part of a larger whole and should not be serialized? + bool IsSubElement; + + //! does this element ignore its parent's clipping rectangle? + bool NoClip; + + //! caption + core::stringw Text; + + //! tooltip + core::stringw ToolTipText; + + //! users can set this for identifying the element by string + core::stringc Name; + + //! users can set this for identifying the element by integer + s32 ID; + + //! tab stop like in windows + bool IsTabStop; + + //! tab order + s32 TabOrder; + + //! tab groups are containers like windows, use ctrl+tab to navigate + bool IsTabGroup; + + //! tells the element how to act when its parent is resized + EGUI_ALIGNMENT AlignLeft, AlignRight, AlignTop, AlignBottom; + + //! GUI Environment + IGUIEnvironment* Environment; + + //! type of element + EGUI_ELEMENT_TYPE Type; +}; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUIElementFactory.h b/include/IGUIElementFactory.h new file mode 100644 index 00000000..a447c048 --- /dev/null +++ b/include/IGUIElementFactory.h @@ -0,0 +1,66 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_ELEMENT_FACTORY_H_INCLUDED__ +#define __I_GUI_ELEMENT_FACTORY_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "EGUIElementTypes.h" + +namespace irr +{ + +namespace gui +{ + class IGUIElement; + + //! Interface making it possible to dynamically create GUI elements + /** To be able to add custom elements to Irrlicht and to make it possible for the + scene manager to save and load them, simply implement this interface and register it + in your gui environment via IGUIEnvironment::registerGUIElementFactory. + Note: When implementing your own element factory, don't call IGUIEnvironment::grab() to + increase the reference counter of the environment. This is not necessary because the + it will grab() the factory anyway, and otherwise cyclic references will be created. + */ + class IGUIElementFactory : public virtual IReferenceCounted + { + public: + + //! adds an element to the gui environment based on its type id + /** \param type: Type of the element to add. + \param parent: Parent scene node of the new element, can be null to add to the root. + \return Pointer to the new element or null if not successful. */ + virtual IGUIElement* addGUIElement(EGUI_ELEMENT_TYPE type, IGUIElement* parent=0) = 0; + + //! adds a GUI element to the GUI Environment based on its type name + /** \param typeName: Type name of the element to add. + \param parent: Parent scene node of the new element, can be null to add it to the root. + \return Pointer to the new element or null if not successful. */ + virtual IGUIElement* addGUIElement(const c8* typeName, IGUIElement* parent=0) = 0; + + //! Get amount of GUI element types this factory is able to create + virtual s32 getCreatableGUIElementTypeCount() const = 0; + + //! Get type of a creatable element type + /** \param idx: Index of the element type in this factory. Must be a value between 0 and + getCreatableGUIElementTypeCount() */ + virtual EGUI_ELEMENT_TYPE getCreateableGUIElementType(s32 idx) const = 0; + + //! Get type name of a creatable GUI element type by index + /** \param idx: Index of the type in this factory. Must be a value between 0 and + getCreatableGUIElementTypeCount() */ + virtual const c8* getCreateableGUIElementTypeName(s32 idx) const = 0; + + //! returns type name of a creatable GUI element + /** \param type: Type of GUI element. + \return Name of the type if this factory can create the type, otherwise 0. */ + virtual const c8* getCreateableGUIElementTypeName(EGUI_ELEMENT_TYPE type) const = 0; + }; + + +} // end namespace gui +} // end namespace irr + +#endif // __I_GUI_ELEMENT_FACTORY_H_INCLUDED__ + diff --git a/include/IGUIEnvironment.h b/include/IGUIEnvironment.h new file mode 100644 index 00000000..695b41b8 --- /dev/null +++ b/include/IGUIEnvironment.h @@ -0,0 +1,654 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_ENVIRONMENT_H_INCLUDED__ +#define __I_GUI_ENVIRONMENT_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "IGUISkin.h" +#include "rect.h" +#include "EMessageBoxFlags.h" +#include "EFocusFlags.h" +#include "IEventReceiver.h" +#include "IXMLReader.h" +#include "IXMLWriter.h" +#include "path.h" + +namespace irr +{ + class IOSOperator; + class IEventReceiver; + + namespace io + { + class IReadFile; + class IWriteFile; + class IFileSystem; + } // end namespace io + namespace video + { + class IVideoDriver; + class ITexture; + } // end namespace video + +namespace gui +{ + +class IGUIElement; +class IGUIFont; +class IGUISpriteBank; +class IGUIScrollBar; +class IGUIImage; +class IGUIMeshViewer; +class IGUICheckBox; +class IGUIListBox; +class IGUITreeView; +class IGUIImageList; +class IGUIFileOpenDialog; +class IGUIColorSelectDialog; +class IGUIInOutFader; +class IGUIStaticText; +class IGUIEditBox; +class IGUISpinBox; +class IGUITabControl; +class IGUITab; +class IGUITable; +class IGUIContextMenu; +class IGUIComboBox; +class IGUIToolBar; +class IGUIButton; +class IGUIWindow; +class IGUIProfiler; +class IGUIElementFactory; + +//! GUI Environment. Used as factory and manager of all other GUI elements. +/** \par This element can create the following events of type EGUI_EVENT_TYPE (which are passed on to focused sub-elements): +\li EGET_ELEMENT_FOCUS_LOST +\li EGET_ELEMENT_FOCUSED +\li EGET_ELEMENT_LEFT +\li EGET_ELEMENT_HOVERED +*/ +class IGUIEnvironment : public virtual IReferenceCounted +{ +public: + + //! Draws all gui elements by traversing the GUI environment starting at the root node. + virtual void drawAll() = 0; + + //! Sets the focus to an element. + /** Causes a EGET_ELEMENT_FOCUS_LOST event followed by a + EGET_ELEMENT_FOCUSED event. If someone absorbed either of the events, + then the focus will not be changed. + \param element Pointer to the element which shall get the focus. + \return True on success, false on failure */ + virtual bool setFocus(IGUIElement* element) = 0; + + //! Returns the element which holds the focus. + /** \return Pointer to the element with focus. */ + virtual IGUIElement* getFocus() const = 0; + + //! Returns the element which was last under the mouse cursor + /** NOTE: This information is updated _after_ the user-eventreceiver + received it's mouse-events. To find the hovered element while catching + mouse events you have to use instead: + IGUIEnvironment::getRootGUIElement()->getElementFromPoint(mousePos); + \return Pointer to the element under the mouse. */ + virtual IGUIElement* getHovered() const = 0; + + //! Removes the focus from an element. + /** Causes a EGET_ELEMENT_FOCUS_LOST event. If the event is absorbed + then the focus will not be changed. + \param element Pointer to the element which shall lose the focus. + \return True on success, false on failure */ + virtual bool removeFocus(IGUIElement* element) = 0; + + //! Returns whether the element has focus + /** \param element Pointer to the element which is tested. + \param checkSubElements When true and focus is on a sub-element of element then it will still count as focused and return true + \return True if the element has focus, else false. */ + virtual bool hasFocus(const IGUIElement* element, bool checkSubElements=false) const = 0; + + //! Returns the current video driver. + /** \return Pointer to the video driver. */ + virtual video::IVideoDriver* getVideoDriver() const = 0; + + //! Returns 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. */ + virtual IOSOperator* getOSOperator() const = 0; + + //! Removes all elements from the environment. + virtual void clear() = 0; + + //! Posts an input event to the environment. + /** Usually you do not have to + use this method, it is used by the engine internally. + \param event The event to post. + \return True if succeeded, else false. */ + virtual bool postEventFromUser(const SEvent& event) = 0; + + //! This sets a new event receiver for gui events. + /** Usually you do not have to + use this method, it is used by the engine internally. + \param evr Pointer to the new receiver. */ + virtual void setUserEventReceiver(IEventReceiver* evr) = 0; + + //! Returns pointer to the current gui skin. + /** \return Pointer to the GUI skin. */ + virtual IGUISkin* getSkin() const = 0; + + //! Sets a new GUI Skin + /** You can use this to change the appearance of the whole GUI + Environment. You can set one of the built-in skins or implement your + own class derived from IGUISkin and enable it using this method. + To set for example the built-in Windows classic skin, use the following + code: + \code + gui::IGUISkin* newskin = environment->createSkin(gui::EGST_WINDOWS_CLASSIC); + environment->setSkin(newskin); + newskin->drop(); + \endcode + \param skin New skin to use. + */ + virtual void setSkin(IGUISkin* skin) = 0; + + //! Creates a new GUI Skin based on a template. + /** Use setSkin() to set the created skin. + \param type The type of the new skin. + \return Pointer to the created skin. + If you no longer need it, you should call IGUISkin::drop(). + See IReferenceCounted::drop() for more information. */ + virtual IGUISkin* createSkin(EGUI_SKIN_TYPE type) = 0; + + + //! Creates the image list from the given texture. + /** \param texture Texture to split into images + \param imageSize Dimension of each image + \param useAlphaChannel Flag whether alpha channel of the texture should be honored. + \return Pointer to the font. Returns 0 if the font could not be loaded. + This pointer should not be dropped. See IReferenceCounted::drop() for + more information. */ + virtual IGUIImageList* createImageList( video::ITexture* texture, + core::dimension2d imageSize, + bool useAlphaChannel ) = 0; + + //! Returns pointer to the font with the specified filename. + /** Loads the font if it was not loaded before. + \param filename Filename of the Font. + \return Pointer to the font. Returns 0 if the font could not be loaded. + This pointer should not be dropped. See IReferenceCounted::drop() for + more information. */ + virtual IGUIFont* getFont(const io::path& filename) = 0; + + //! Adds an externally loaded font to the font list. + /** This method allows to attach an already loaded font to the list of + existing fonts. The font is grabbed if non-null and adding was successful. + \param name Name the font should be stored as. + \param font Pointer to font to add. + \return Pointer to the font stored. This can differ from given parameter if the name previously existed. */ + virtual IGUIFont* addFont(const io::path& name, IGUIFont* font) = 0; + + //! remove loaded font + virtual void removeFont(IGUIFont* font) = 0; + + //! Returns the default built-in font. + /** \return Pointer to the default built-in font. + This pointer should not be dropped. See IReferenceCounted::drop() for + more information. */ + virtual IGUIFont* getBuiltInFont() const = 0; + + //! Returns pointer to the sprite bank which was added with addEmptySpriteBank + /** TODO: This should load files in the future, but not implemented so far. + \param filename Name of a spritebank added with addEmptySpriteBank + \return Pointer to the sprite bank. Returns 0 if it could not be loaded. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual IGUISpriteBank* getSpriteBank(const io::path& filename) = 0; + + //! Adds an empty sprite bank to the manager + /** \param name Name of the new sprite bank. + \return Pointer to the sprite bank. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual IGUISpriteBank* addEmptySpriteBank(const io::path& name) = 0; + + //! Returns the root gui element. + /** 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. + \return Pointer to the root element of the GUI. The returned pointer + should not be dropped. See IReferenceCounted::drop() for more + information. */ + virtual IGUIElement* getRootGUIElement() = 0; + + //! Adds a button element. + /** \param rectangle Rectangle specifying the borders of the button. + \param parent Parent gui element of the button. + \param id Id with which the gui element can be identified. + \param text Text displayed on the button. + \param tooltiptext Text displayed in the tooltip. + \return Pointer to the created button. Returns 0 if an error occurred. + This pointer should not be dropped. See IReferenceCounted::drop() for + more information. */ + virtual IGUIButton* addButton(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0, const wchar_t* tooltiptext = 0) = 0; + + //! Adds an empty window element. + /** \param rectangle Rectangle specifying the borders of the window. + \param modal Defines if the dialog is modal. This means, that all other + gui elements which were created before the window cannot be used until + it is removed. + \param text Text displayed as the window title. + \param parent Parent gui element of the window. + \param id Id with which the gui element can be identified. + \return Pointer to the created window. Returns 0 if an error occurred. + This pointer should not be dropped. See IReferenceCounted::drop() for + more information. */ + 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. + /** Input focus stays with children of the modal screen. + If you have some window x which should keep the input focus you + do something like: addModalScreen()->addChild(x). And x will then get the focus + and not lose it anymore. + The modal screen removes itself when it no longer has any children. + Note that it usually works badly to pass the modal screen already as parent when creating + a new element. It's better to add that new element later to the modal screen with addChild. + \param parent Parent gui element of the modal. + \return Pointer to the created modal. Returns 0 if an error occurred. + This pointer should not be dropped. See IReferenceCounted::drop() for + more information. */ + virtual IGUIElement* addModalScreen(IGUIElement* parent) = 0; + + //! Adds a message box. + /** \param caption Text to be displayed the title of the message box. + \param text Text to be displayed in the body of the message box. + \param modal Defines if the dialog is modal. This means, that all other + gui elements which were created before the message box cannot be used + until this messagebox is removed. + \param flags Flags specifying the layout of the message box using ::EMESSAGE_BOX_FLAG. + Create a message box with an OK and CANCEL button for example with (EMBF_OK | EMBF_CANCEL). + \param parent Parent gui element of the message box. + \param id Id with which the gui element can be identified. + \param image Optional texture which will be displayed beside the text as an image + \return Pointer to the created message box. Returns 0 if an error + occurred. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual IGUIWindow* addMessageBox(const wchar_t* caption, const wchar_t* text=0, + bool modal = true, s32 flags = EMBF_OK, IGUIElement* parent=0, s32 id=-1, video::ITexture* image=0) = 0; + + //! Adds a scrollbar. + /** \param horizontal Specifies if the scroll bar is drawn horizontal + or vertical. + \param rectangle Rectangle specifying the borders of the scrollbar. + \param parent Parent gui element of the scroll bar. + \param id Id to identify the gui element. + \return Pointer to the created scrollbar. Returns 0 if an error + occurred. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual IGUIScrollBar* addScrollBar(bool horizontal, const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1) = 0; + + //! Adds an image element. + /** \param image Image to be displayed. + \param pos Position of the image. The width and height of the image is + taken from the image. + \param useAlphaChannel Sets if the image should use the alpha channel + of the texture to draw itself. + \param parent Parent gui element of the image. + \param id Id to identify the gui element. + \param text Title text of the image (not displayed). + \return Pointer to the created image element. Returns 0 if an error + occurred. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual IGUIImage* addImage(video::ITexture* image, core::position2d pos, + bool useAlphaChannel=true, IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0) = 0; + + //! Adds an image element. + /** Use IGUIImage::setImage later to set the image to be displayed. + \param rectangle Rectangle specifying the borders of the image. + \param parent Parent gui element of the image. + \param id Id to identify the gui element. + \param text Title text of the image (not displayed). + \param useAlphaChannel Sets if the image should use the alpha channel + of the texture to draw itself. + \return Pointer to the created image element. Returns 0 if an error + occurred. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual IGUIImage* addImage(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0, bool useAlphaChannel=true) = 0; + + //! Adds a checkbox element. + /** \param checked Define the initial state of the check box. + \param rectangle Rectangle specifying the borders of the check box. + \param parent Parent gui element of the check box. + \param id Id to identify the gui element. + \param text Title text of the check box. + \return Pointer to the created check box. Returns 0 if an error + occurred. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual IGUICheckBox* addCheckBox(bool checked, const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0) = 0; + + //! Adds a list box element. + /** \param rectangle Rectangle specifying the borders of the list box. + \param parent Parent gui element of the list box. + \param id Id to identify the gui element. + \param drawBackground Flag whether the background should be drawn. + \return Pointer to the created list box. Returns 0 if an error occurred. + This pointer should not be dropped. See IReferenceCounted::drop() for + more information. */ + virtual IGUIListBox* addListBox(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1, bool drawBackground=false) = 0; + + //! Adds a tree view element. + /** \param rectangle Position and dimension of list box. + \param parent Parent gui element of the list box. + \param id Id to identify the gui element. + \param drawBackground Flag whether the background should be drawn. + \param scrollBarVertical Flag whether a vertical scrollbar should be used + \param scrollBarHorizontal Flag whether a horizontal scrollbar should be used + \return Pointer to the created list box. Returns 0 if an error occurred. + This pointer should not be dropped. See IReferenceCounted::drop() for + more information. */ + virtual IGUITreeView* addTreeView(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1, bool drawBackground=false, + bool scrollBarVertical = true, bool scrollBarHorizontal = false) = 0; + + //! Adds a mesh viewer. Not 100% implemented yet. + /** \param rectangle Rectangle specifying the borders of the mesh viewer. + \param parent Parent gui element of the mesh viewer. + \param id Id to identify the gui element. + \param text Title text of the mesh viewer. + \return Pointer to the created mesh viewer. Returns 0 if an error + occurred. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual IGUIMeshViewer* addMeshViewer(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0) = 0; + + //! Adds a file open dialog. + /** \param title Text to be displayed as the title of the dialog. + \param modal Defines if the dialog is modal. This means, that all other + gui elements which were created before the message box cannot be used + until this messagebox is removed. + \param parent Parent gui element of the dialog. + \param id Id to identify the gui element. + \param restoreCWD If set to true, the current working directory will be + restored after the dialog is closed in some way. Otherwise the working + directory will be the one that the file dialog was last showing. + \param startDir Optional path for which the file dialog will be opened. + \return Pointer to the created file open dialog. Returns 0 if an error + occurred. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual IGUIFileOpenDialog* addFileOpenDialog(const wchar_t* title=0, + bool modal=true, IGUIElement* parent=0, s32 id=-1, + bool restoreCWD=false, io::path::char_type* startDir=0) = 0; + + //! Adds a color select dialog. + /** \param title The title of the dialog. + \param modal Defines if the dialog is modal. This means, that all other + gui elements which were created before the dialog cannot be used + until it is removed. + \param parent The parent of the dialog. + \param id The ID of the dialog. + \return Pointer to the created file open dialog. Returns 0 if an error + occurred. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual IGUIColorSelectDialog* addColorSelectDialog(const wchar_t* title = 0, + bool modal=true, IGUIElement* parent=0, s32 id=-1) = 0; + + //! Adds a static text. + /** \param text Text to be displayed. Can be altered after creation by SetText(). + \param rectangle Rectangle specifying the borders of the static text + \param border Set to true if the static text should have a 3d border. + \param wordWrap Enable if the text should wrap into multiple lines. + \param parent Parent item of the element, e.g. a window. + \param id The ID of the element. + \param fillBackground Enable if the background shall be filled. + Defaults to false. + \return Pointer to the created static text. Returns 0 if an error + occurred. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual IGUIStaticText* addStaticText(const wchar_t* text, const core::rect& rectangle, + bool border=false, bool wordWrap=true, IGUIElement* parent=0, s32 id=-1, + bool fillBackground = false) = 0; + + //! Adds an edit box. + /** Supports Unicode input from every keyboard around the world, + scrolling, copying and pasting (exchanging data with the clipboard + directly), maximum character amount, marking, and all shortcuts like + ctrl+X, ctrl+V, ctrl+C, shift+Left, shift+Right, Home, End, and so on. + \param text Text to be displayed. Can be altered after creation + by setText(). + \param rectangle Rectangle specifying the borders of the edit box. + \param border Set to true if the edit box should have a 3d border. + \param parent Parent item of the element, e.g. a window. + Set it to 0 to place the edit box directly in the environment. + \param id The ID of the element. + \return Pointer to the created edit box. Returns 0 if an error occurred. + This pointer should not be dropped. See IReferenceCounted::drop() for + more information. */ + virtual IGUIEditBox* addEditBox(const wchar_t* text, const core::rect& rectangle, + bool border=true, IGUIElement* parent=0, s32 id=-1) = 0; + + //! Adds a spin box. + /** An edit box with up and down buttons + \param text Text to be displayed. Can be altered after creation by setText(). + \param rectangle Rectangle specifying the borders of the spin box. + \param border Set to true if the spin box should have a 3d border. + \param parent Parent item of the element, e.g. a window. + Set it to 0 to place the spin box directly in the environment. + \param id The ID of the element. + \return Pointer to the created spin box. Returns 0 if an error occurred. + This pointer should not be dropped. See IReferenceCounted::drop() for + more information. */ + virtual IGUISpinBox* addSpinBox(const wchar_t* text, const core::rect& rectangle, + bool border=true,IGUIElement* parent=0, s32 id=-1) = 0; + + //! Adds an element for fading in or out. + /** \param rectangle Rectangle specifying the borders of the fader. + If the pointer is NULL, the whole screen is used. + \param parent Parent item of the element, e.g. a window. + \param id An identifier for the fader. + \return Pointer to the created in-out-fader. Returns 0 if an error + occurred. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual IGUIInOutFader* addInOutFader(const core::rect* rectangle=0, IGUIElement* parent=0, s32 id=-1) = 0; + + //! Adds a tab control to the environment. + /** \param rectangle Rectangle specifying the borders of the tab control. + \param parent Parent item of the element, e.g. a window. + Set it to 0 to place the tab control directly in the environment. + \param fillbackground Specifies if the background of the tab control + should be drawn. + \param border Specifies if a flat 3d border should be drawn. This is + usually not necessary unless you place the control directly into + the environment without a window as parent. + \param id An identifier for the tab control. + \return Pointer to the created tab control element. Returns 0 if an + error occurred. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual IGUITabControl* addTabControl(const core::rect& rectangle, + IGUIElement* parent=0, bool fillbackground=false, + bool border=true, s32 id=-1) = 0; + + //! Adds tab to the environment. + /** You can use this element to group other elements. This is not used + for creating tabs on tab controls, please use IGUITabControl::addTab() + for this instead. + \param rectangle Rectangle specifying the borders of the tab. + \param parent Parent item of the element, e.g. a window. + Set it to 0 to place the tab directly in the environment. + \param id An identifier for the tab. + \return Pointer to the created tab. Returns 0 if an + error occurred. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual IGUITab* addTab(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1) = 0; + + //! Adds a context menu to the environment. + /** \param rectangle Rectangle specifying the borders of the menu. + Note that the menu is resizing itself based on what items you add. + \param parent Parent item of the element, e.g. a window. + Set it to 0 to place the menu directly in the environment. + \param id An identifier for the menu. + \return Pointer to the created context menu. Returns 0 if an + error occurred. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual IGUIContextMenu* addContextMenu(const core::rect& rectangle, + 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 + 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. + \param id An identifier for the menu. + \return Pointer to the created menu. Returns 0 if an + error occurred. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual IGUIContextMenu* addMenu(IGUIElement* parent=0, s32 id=-1) = 0; + + //! Adds a toolbar to the environment. + /** It is like a menu that is always placed on top of its parent, and + contains buttons. + \param parent Parent item of the element, e.g. a window. + Set it to 0 to place the tool bar directly in the environment. + \param id An identifier for the tool bar. + \return Pointer to the created tool bar. Returns 0 if an + error occurred. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual IGUIToolBar* addToolBar(IGUIElement* parent=0, s32 id=-1) = 0; + + //! Adds a combo box to the environment. + /** \param rectangle Rectangle specifying the borders of the combo box. + \param parent Parent item of the element, e.g. a window. + Set it to 0 to place the combo box directly in the environment. + \param id An identifier for the combo box. + \return Pointer to the created combo box. Returns 0 if an + error occurred. This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual IGUIComboBox* addComboBox(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1) = 0; + + //! Adds a table to the environment + /** \param rectangle Rectangle specifying the borders 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 occurred. + 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; + + //! Adds an element to display the information from the Irrlicht profiler + /** \param rectangle Rectangle specifying the borders of the element. + \param parent Parent of the element. When 0 the environment itself will + be the parent. + \param id An identifier for the element. */ + virtual IGUIProfiler* addProfilerDisplay(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1) = 0; + + //! Get the default element factory which can create all built-in elements + /** \return Pointer to the factory. + This pointer should not be dropped. See IReferenceCounted::drop() for + more information. */ + virtual IGUIElementFactory* getDefaultGUIElementFactory() const = 0; + + //! Adds an element factory to the gui environment. + /** Use this to extend the gui environment with new element types which + it should be able to create automatically, for example when loading + data from xml files. + \param factoryToAdd Pointer to new factory. */ + virtual void registerGUIElementFactory(IGUIElementFactory* factoryToAdd) = 0; + + //! Get amount of registered gui element factories. + /** \return Amount of registered gui element factories. */ + virtual u32 getRegisteredGUIElementFactoryCount() const = 0; + + //! Get a gui element factory by index + /** \param index Index of the factory. + \return Factory at given index, or 0 if no such factory exists. */ + virtual IGUIElementFactory* getGUIElementFactory(u32 index) const = 0; + + //! Adds a GUI element by its name + /** Each factory is checked if it can create an element of the given + name. The first match will be created. + \param elementName Name of the element to be created. + \param parent Parent of the new element, if not 0. + \return New GUI element, or 0 if no such element exists. */ + 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. + \return True if saving succeeded, else false. */ + virtual bool saveGUI(const io::path& 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. + \return True if saving succeeded, else false. */ + virtual bool saveGUI(io::IWriteFile* file, IGUIElement* start=0) = 0; + + //! Loads the gui. Note that the current gui is not cleared before. + /** When a parent is set the elements will be added below the parent, the parent itself does not deserialize. + When the file contains skin-settings from the gui-environment those are always serialized into the + guienvironment independent of the parent setting. + \param filename Name of the file. + \param parent Parent for the loaded GUI, root if 0. + \return True if loading succeeded, else false. */ + virtual bool loadGUI(const io::path& filename, IGUIElement* parent=0) = 0; + + //! Loads the gui. Note that the current gui is not cleared before. + /** When a parent is set the elements will be added below the parent, the parent itself does not deserialize. + When the file contains skin-settings from the gui-environment those are always serialized into the + guienvironment independent of the parent setting. + \param file The file to load from. + \param parent Parent for the loaded GUI, root if 0. + \return True if loading succeeded, else false. */ + virtual bool loadGUI(io::IReadFile* file, IGUIElement* parent=0) = 0; + + //! Writes attributes of the gui environment + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const =0; + + //! Reads attributes of the gui environment + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)=0; + + //! writes an element + virtual void writeGUIElement(io::IXMLWriter* writer, IGUIElement* node) =0; + + //! reads an element + virtual void readGUIElement(io::IXMLReader* reader, IGUIElement* node) =0; + + //! Find the next element which would be selected when pressing the tab-key + /** If you set the focus for the result you can manually force focus-changes like they + would happen otherwise by the tab-keys. + \param reverse When true it will search backward (toward lower TabOrder numbers, like shift+tab) + \param group When true it will search for the next tab-group (like ctrl+tab) + */ + virtual IGUIElement* getNextElement(bool reverse=false, bool group=false) = 0; + + //! Set the way the gui will handle automatic focus changes + /** The default is (EFF_SET_ON_LMOUSE_DOWN | EFF_SET_ON_TAB). + with the left mouse button. + This does not affect the setFocus function itself - users can still call that whenever they want on any element. + \param flags A bitmask which is a combination of ::EFOCUS_FLAG flags.*/ + virtual void setFocusBehavior(u32 flags) = 0; + + //! Get the way the gui does handle focus changes + /** \returns A bitmask which is a combination of ::EFOCUS_FLAG flags.*/ + virtual u32 getFocusBehavior() const = 0; +}; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUIFileOpenDialog.h b/include/IGUIFileOpenDialog.h new file mode 100644 index 00000000..96744cc8 --- /dev/null +++ b/include/IGUIFileOpenDialog.h @@ -0,0 +1,50 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_FILE_OPEN_DIALOG_H_INCLUDED__ +#define __I_GUI_FILE_OPEN_DIALOG_H_INCLUDED__ + +#include "IGUIElement.h" +#include "path.h" + +namespace irr +{ +namespace gui +{ + + //! Standard file chooser dialog. + /** \warning When the user selects a folder this does change the current working directory + + \par This element can create the following events of type EGUI_EVENT_TYPE: + \li EGET_DIRECTORY_SELECTED + \li EGET_FILE_SELECTED + \li EGET_FILE_CHOOSE_DIALOG_CANCELLED + */ + class IGUIFileOpenDialog : public IGUIElement + { + public: + + //! constructor + IGUIFileOpenDialog(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_FILE_OPEN_DIALOG, environment, parent, id, rectangle) {} + + //! Returns the filename of the selected file converted to wide characters. Returns NULL if no file was selected. + virtual const wchar_t* getFileName() const = 0; + + //! Returns the filename of the selected file. Is empty if no file was selected. + virtual const io::path& getFileNameP() const = 0; + + //! Returns the directory of the selected file. Empty if no directory was selected. + virtual const io::path& getDirectoryName() const = 0; + + //! Returns the directory of the selected file converted to wide characters. Returns NULL if no directory was selected. + virtual const wchar_t* getDirectoryNameW() const = 0; + }; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUIFont.h b/include/IGUIFont.h new file mode 100644 index 00000000..4746c81a --- /dev/null +++ b/include/IGUIFont.h @@ -0,0 +1,104 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_FONT_H_INCLUDED__ +#define __I_GUI_FONT_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "SColor.h" +#include "rect.h" +#include "irrString.h" + +namespace irr +{ +namespace gui +{ + +//! An enum for the different types of GUI font. +enum EGUI_FONT_TYPE +{ + //! Bitmap fonts loaded from an XML file or a texture. + 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. */ + EGFT_VECTOR, + + //! A font which uses a the native API provided by the operating system. + /** Currently not used. */ + EGFT_OS, + + //! An external font type provided by the user. + EGFT_CUSTOM +}; + +//! Font interface. +class IGUIFont : public virtual IReferenceCounted +{ +public: + + //! Draws some text and clips it to the specified rectangle if wanted. + /** \param text: Text to draw + \param position: Rectangle specifying position where to draw the text. + \param color: Color of the text + \param hcenter: Specifies if the text should be centered horizontally into the rectangle. + \param vcenter: Specifies if the text should be centered vertically into the rectangle. + \param clip: Optional pointer to a rectangle against which the text will be clipped. + If the pointer is null, no clipping will be done. */ + virtual void draw(const core::stringw& text, const core::rect& position, + video::SColor color, bool hcenter=false, bool vcenter=false, + const core::rect* clip=0) = 0; + + //! Calculates the width and height of a given string of 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; + + //! Calculates the index of the character in the text which is on a specific position. + /** \param text: Text string. + \param pixel_x: X pixel position of which the index of the character will be returned. + \return Returns zero based index of the character in the text, and -1 if no no character + is on this position. (=the text is too short). */ + virtual s32 getCharacterFromPos(const wchar_t* text, s32 pixel_x) const = 0; + + //! Returns the type of this font + virtual EGUI_FONT_TYPE getType() const { return EGFT_CUSTOM; } + + //! 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, + /** the global kerning distance is returned. + \param thisLetter: If this parameter is provided, the left side kerning + for this letter is added to the global kerning value. For example, a + space might only be one pixel wide, but it may be displayed as several + pixels. + \param previousLetter: If provided, kerning is calculated for both + letters and added to the global kerning value. For example, in a font + which supports kerning pairs a string such as 'Wo' may have the 'o' + tucked neatly under the 'W'. + */ + virtual s32 getKerningWidth(const wchar_t* thisLetter=0, const wchar_t* previousLetter=0) const = 0; + + //! Returns the distance between letters + virtual s32 getKerningHeight() const = 0; + + //! Define which characters should not be drawn by the font. + /** For example " " would not draw any space which is usually blank in + most fonts. + \param s String of symbols which are not send down to the videodriver + */ + virtual void setInvisibleCharacters( const wchar_t *s ) = 0; +}; + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUIFontBitmap.h b/include/IGUIFontBitmap.h new file mode 100644 index 00000000..42b94d94 --- /dev/null +++ b/include/IGUIFontBitmap.h @@ -0,0 +1,46 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_FONT_BITMAP_H_INCLUDED__ +#define __I_GUI_FONT_BITMAP_H_INCLUDED__ + +#include "IGUIFont.h" + +namespace irr +{ +namespace gui +{ + class IGUISpriteBank; + +//! Font interface. +class IGUIFontBitmap : public IGUIFont +{ +public: + + //! Returns the type of this font + virtual EGUI_FONT_TYPE getType() const _IRR_OVERRIDE_ { return EGFT_BITMAP; } + + //! returns the parsed Symbol Information + virtual IGUISpriteBank* getSpriteBank() const = 0; + + //! returns the sprite number from a given character + virtual u32 getSpriteNoFromChar(const wchar_t *c) const = 0; + + //! Gets kerning values (distance between letters) for the font. If no parameters are provided, + /** the global kerning distance is returned. + \param thisLetter: If this parameter is provided, the left side kerning for this letter is added + to the global kerning value. For example, a space might only be one pixel wide, but it may + be displayed as several pixels. + \param previousLetter: If provided, kerning is calculated for both letters and added to the global + kerning value. For example, EGFT_BITMAP will add the right kerning value of previousLetter to the + left side kerning value of thisLetter, then add the global value. + */ + virtual s32 getKerningWidth(const wchar_t* thisLetter=0, const wchar_t* previousLetter=0) const = 0; +}; + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUIImage.h b/include/IGUIImage.h new file mode 100644 index 00000000..c99de0dd --- /dev/null +++ b/include/IGUIImage.h @@ -0,0 +1,87 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_IMAGE_H_INCLUDED__ +#define __I_GUI_IMAGE_H_INCLUDED__ + +#include "IGUIElement.h" + +namespace irr +{ +namespace video +{ + class ITexture; +} +namespace gui +{ + //! GUI element displaying an image. + class IGUIImage : public IGUIElement + { + public: + + //! constructor + IGUIImage(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_IMAGE, environment, parent, id, rectangle) {} + + //! Sets an image texture + virtual void setImage(video::ITexture* image) = 0; + + //! Gets the image texture + virtual video::ITexture* getImage() const = 0; + + //! Sets the color of the image + /** \param color Color with which the image is drawn. If the color + equals Color(255,255,255,255) it is ignored. */ + virtual void setColor(video::SColor color) = 0; + + //! Sets if the image should scale to fit the element + virtual void setScaleImage(bool scale) = 0; + + //! Sets if the image should use its alpha channel to draw itself + virtual void setUseAlphaChannel(bool use) = 0; + + //! Gets the color of the image + virtual video::SColor getColor() const = 0; + + //! Returns true if the image is scaled to fit, false if not + virtual bool isImageScaled() const = 0; + + //! Returns true if the image is using the alpha channel, false if not + virtual bool isAlphaChannelUsed() const = 0; + + //! Sets the source rectangle of the image. By default the full image is used. + /** \param sourceRect coordinates inside the image or an area with size 0 for using the full image (default). */ + virtual void setSourceRect(const core::rect& sourceRect) = 0; + + //! Returns the customized source rectangle of the image to be used. + /** By default an empty rectangle of width and height 0 is returned which means the full image is used. */ + virtual core::rect getSourceRect() const = 0; + + //! Restrict drawing-area. + /** This allows for example to use the image as a progress bar. + Base for area is the image, which means: + - The original clipping area when the texture is scaled or there is no texture. + - The source-rect for an unscaled texture (but still restricted afterward by the clipping area) + Unlike normal clipping this does not affect the gui-children. + \param drawBoundUVs: Coordinates between 0 and 1 where 0 are for left+top and 1 for right+bottom + */ + virtual void setDrawBounds(const core::rect& drawBoundUVs = core::rect(0.f, 0.f, 1.f, 1.f)) = 0; + + //! Get drawing-area restrictions. + virtual core::rect getDrawBounds() const = 0; + + //! Sets whether to draw a background color (EGDC_3D_DARK_SHADOW) when no texture is set + /** By default it's enabled */ + virtual void setDrawBackground(bool draw) = 0; + + //! Checks if a background is drawn when no texture is set + /** \return true if background drawing is enabled, false otherwise */ + virtual bool isDrawBackgroundEnabled() const = 0; + }; + + +} // end namespace gui +} // end namespace irr + +#endif diff --git a/include/IGUIImageList.h b/include/IGUIImageList.h new file mode 100644 index 00000000..7f27a99e --- /dev/null +++ b/include/IGUIImageList.h @@ -0,0 +1,45 @@ +// This file is part of the "Irrlicht Engine". +// written by Reinhard Ostermeier, reinhard@nospam.r-ostermeier.de + +#ifndef __I_GUI_IMAGE_LIST_H_INCLUDED__ +#define __I_GUI_IMAGE_LIST_H_INCLUDED__ + +#include "IGUIElement.h" +#include "rect.h" +#include "irrTypes.h" + +namespace irr +{ +namespace gui +{ + +//! Font interface. +class IGUIImageList : public virtual IReferenceCounted +{ +public: + + //! Destructor + virtual ~IGUIImageList() {}; + + //! Draws an image and clips it to the specified rectangle if wanted + //! \param index: Index of the image + //! \param destPos: Position of the image to draw + //! \param clip: Optional pointer to a rectangle against which the text will be clipped. + //! If the pointer is null, no clipping will be done. + virtual void draw(s32 index, const core::position2d& destPos, + const core::rect* clip = 0) = 0; + + //! Returns the count of Images in the list. + //! \return Returns the count of Images in the list. + virtual s32 getImageCount() const = 0; + + //! Returns the size of the images in the list. + //! \return Returns the size of the images in the list. + virtual core::dimension2d getImageSize() const = 0; +}; + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUIInOutFader.h b/include/IGUIInOutFader.h new file mode 100644 index 00000000..a89f615f --- /dev/null +++ b/include/IGUIInOutFader.h @@ -0,0 +1,67 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_IN_OUT_FADER_H_INCLUDED__ +#define __I_GUI_IN_OUT_FADER_H_INCLUDED__ + +#include "IGUIElement.h" +#include "SColor.h" + +namespace irr +{ +namespace gui +{ + + //! Element for fading out or in + /** Here is a small example on how the class is used. In this example we fade + in from a total red screen in the beginning. As you can see, the fader is not + only useful for dramatic in and out fading, but also to show that the player + is hit in a first person shooter game for example. + \code + gui::IGUIInOutFader* fader = device->getGUIEnvironment()->addInOutFader(); + fader->setColor(video::SColor(0,255,0,0)); + fader->fadeIn(4000); + \endcode + */ + class IGUIInOutFader : public IGUIElement + { + public: + + //! constructor + IGUIInOutFader(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_IN_OUT_FADER, environment, parent, id, rectangle) {} + + //! Gets the color to fade out to or to fade in from. + 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. */ + 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 specifying 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 specifying 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. + virtual bool isReady() const = 0; + }; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUIListBox.h b/include/IGUIListBox.h new file mode 100644 index 00000000..b76888c8 --- /dev/null +++ b/include/IGUIListBox.h @@ -0,0 +1,142 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_LIST_BOX_H_INCLUDED__ +#define __I_GUI_LIST_BOX_H_INCLUDED__ + +#include "IGUIElement.h" +#include "SColor.h" + +namespace irr +{ +namespace gui +{ + class IGUISpriteBank; + class IGUIScrollBar; + + //! Enumeration for listbox colors + enum EGUI_LISTBOX_COLOR + { + //! Color of text + EGUI_LBC_TEXT=0, + //! Color of selected text + EGUI_LBC_TEXT_HIGHLIGHT, + //! Color of icon + EGUI_LBC_ICON, + //! Color of selected icon + EGUI_LBC_ICON_HIGHLIGHT, + //! Not used, just counts the number of available colors + EGUI_LBC_COUNT + }; + + + //! Default list box GUI element. + /** \par This element can create the following events of type EGUI_EVENT_TYPE: + \li EGET_LISTBOX_CHANGED + \li EGET_LISTBOX_SELECTED_AGAIN + */ + class IGUIListBox : public IGUIElement + { + public: + //! constructor + IGUIListBox(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_LIST_BOX, environment, parent, id, rectangle) {} + + //! returns amount of list items + virtual u32 getItemCount() const = 0; + + //! returns string of a list item. the may id be a value from 0 to itemCount-1 + virtual const wchar_t* getListItem(u32 id) const = 0; + + //! adds an list item, returns id of item + 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 The id of the new created item */ + virtual u32 addItem(const wchar_t* text, s32 icon) = 0; + + //! Removes an item from the list + virtual void removeItem(u32 index) = 0; + + //! get the the id of the item at the given absolute coordinates + /** \return The id of the list item or -1 when no item is at those coordinates*/ + virtual s32 getItemAt(s32 xpos, s32 ypos) const = 0; + + //! 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. */ + virtual void setSpriteBank(IGUISpriteBank* bank) = 0; + + //! clears the list, deletes all items in the listbox + virtual void clear() = 0; + + //! returns id of selected item. returns -1 if no item is selected. + virtual s32 getSelected() const = 0; + + //! sets the selected item. Set this to -1 if no item should be selected + virtual void setSelected(s32 index) = 0; + + //! sets the selected item. Set this to 0 if no item should be selected + virtual void setSelected(const wchar_t *item) = 0; + + //! set whether the listbox should scroll to newly selected items + virtual void setAutoScrollEnabled(bool scroll) = 0; + + //! returns true if automatic scrolling is enabled, false if not. + virtual bool isAutoScrollEnabled() const = 0; + + //! set all item colors at given index to color + virtual void setItemOverrideColor(u32 index, video::SColor color) = 0; + + //! set all item colors of specified type at given index to color + virtual void setItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType, video::SColor color) = 0; + + //! clear all item colors at index + virtual void clearItemOverrideColor(u32 index) = 0; + + //! clear item color at index for given colortype + virtual void clearItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) = 0; + + //! has the item at index its color overwritten? + virtual bool hasItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const = 0; + + //! return the overwrite color at given item index. + virtual video::SColor getItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const = 0; + + //! return the default color which is used for the given colorType + virtual video::SColor getItemDefaultColor(EGUI_LISTBOX_COLOR colorType) const = 0; + + //! set the item at the given index + 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. */ + virtual s32 insertItem(u32 index, const wchar_t* text, s32 icon) = 0; + + //! Swap the items at the given indices + virtual void swapItems(u32 index1, u32 index2) = 0; + + //! set global itemHeight + virtual void setItemHeight( s32 height ) = 0; + + //! Sets whether to draw the background + virtual void setDrawBackground(bool draw) = 0; + + //! Access the vertical scrollbar + virtual IGUIScrollBar* getVerticalScrollBar() const = 0; +}; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUIMeshViewer.h b/include/IGUIMeshViewer.h new file mode 100644 index 00000000..3255f4ed --- /dev/null +++ b/include/IGUIMeshViewer.h @@ -0,0 +1,53 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_MESH_VIEWER_H_INCLUDED__ +#define __I_GUI_MESH_VIEWER_H_INCLUDED__ + +#include "IGUIElement.h" + +namespace irr +{ + +namespace video +{ + class SMaterial; +} // end namespace video + +namespace scene +{ + class IAnimatedMesh; +} // end namespace scene + +namespace gui +{ + + //! 3d mesh viewing GUI element. + class IGUIMeshViewer : public IGUIElement + { + public: + + //! constructor + IGUIMeshViewer(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_MESH_VIEWER, environment, parent, id, rectangle) {} + + //! Sets the mesh to be shown + virtual void setMesh(scene::IAnimatedMesh* mesh) = 0; + + //! Gets the displayed mesh + virtual scene::IAnimatedMesh* getMesh() const = 0; + + //! Sets the material + virtual void setMaterial(const video::SMaterial& material) = 0; + + //! Gets the material + virtual const video::SMaterial& getMaterial() const = 0; + }; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUIProfiler.h b/include/IGUIProfiler.h new file mode 100644 index 00000000..995899c1 --- /dev/null +++ b/include/IGUIProfiler.h @@ -0,0 +1,82 @@ +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +// Written by Michael Zeilfelder + +#ifndef I_GUI_PROFILER_H_INCLUDED__ +#define I_GUI_PROFILER_H_INCLUDED__ + +#include "IGUIElement.h" + +namespace irr +{ +class IProfiler; + +namespace gui +{ + class IGUIFont; + + //! Element to display profiler information + class IGUIProfiler : public IGUIElement + { + public: + //! constructor + /** \param profiler You can pass a custom profiler, but typically you can pass 0 in which cases it takes the global profiler from Irrlicht */ + IGUIProfiler(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle, IProfiler* profiler = NULL) + : IGUIElement(EGUIET_PROFILER, environment, parent, id, rectangle) + {} + + //! Show first page of profile data + /** \param includeOverview When true show the group-overview page, when false show the profile data of the first group */ + virtual void firstPage(bool includeOverview=true) = 0; + + //! Show next page of profile data + /** \param includeOverview Include the group-overview page */ + virtual void nextPage(bool includeOverview=true) = 0; + + //! Show previous page of profile data + /** \param includeOverview Include the group-overview page */ + virtual void previousPage(bool includeOverview=true) = 0; + + //! Try to show as many group-pages together as possible instead of showing at most one group per page. + /** \param groupsTogether When true show several groups on one page, when false show max. one group per page. Default is false. */ + virtual void setShowGroupsTogether(bool groupsTogether) = 0; + + //! Can several groups be displayed per page? + virtual bool getShowGroupsTogether() const = 0; + + //! Sets another skin independent font. + /** If this is set to zero, the button uses the font of the skin. + \param font: New font to set. */ + virtual void setOverrideFont(IGUIFont* font=0) = 0; + + //! Gets the override font (if any) + /** \return The override font (may be 0) */ + virtual IGUIFont* getOverrideFont(void) const = 0; + + //! Get the font which is used right now for drawing + /** Currently this is the override font when one is set and the + font of the active skin otherwise */ + virtual IGUIFont* getActiveFont() const = 0; + + //! Sets whether to draw the background. By default disabled, + virtual void setDrawBackground(bool draw) = 0; + + //! Checks if background drawing is enabled + /** \return true if background drawing is enabled, false otherwise */ + virtual bool isDrawBackgroundEnabled() const = 0; + + //! Allows to freeze updates which makes it easier to read the numbers + /** Numbers are updated once when you switch pages. */ + virtual void setFrozen(bool freeze) = 0; + + //! Are updates currently frozen + virtual bool getFrozen() const = 0; + + //! Filters prevents data that doesn't achieve the conditions from being displayed + virtual void setFilters(irr::u32 minCalls = 0, irr::u32 minTimeSum = 0, irr::f32 minTimeAverage = 0.f, irr::u32 minTimeMax = 0) = 0; + }; + +} // end namespace gui +} // end namespace irr + +#endif diff --git a/include/IGUIScrollBar.h b/include/IGUIScrollBar.h new file mode 100644 index 00000000..c75900e9 --- /dev/null +++ b/include/IGUIScrollBar.h @@ -0,0 +1,65 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_SCROLL_BAR_H_INCLUDED__ +#define __I_GUI_SCROLL_BAR_H_INCLUDED__ + +#include "IGUIElement.h" + +namespace irr +{ +namespace gui +{ + + //! Default scroll bar GUI element. + /** \par This element can create the following events of type EGUI_EVENT_TYPE: + \li EGET_SCROLL_BAR_CHANGED + */ + class IGUIScrollBar : public IGUIElement + { + public: + + //! constructor + IGUIScrollBar(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_SCROLL_BAR, environment, parent, id, rectangle) {} + + //! sets the maximum value of the scrollbar. + virtual void setMax(s32 max) = 0; + //! gets the maximum value of the scrollbar. + virtual s32 getMax() const = 0; + + //! sets the minimum value of the scrollbar. + virtual void setMin(s32 min) = 0; + //! gets the minimum value of the scrollbar. + virtual s32 getMin() const = 0; + + //! gets the small step value + virtual s32 getSmallStep() const = 0; + + //! 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 + /** 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 + virtual s32 getPos() const = 0; + + //! sets the current position of the scrollbar + virtual void setPos(s32 pos) = 0; + }; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUISkin.h b/include/IGUISkin.h new file mode 100644 index 00000000..e685a1ed --- /dev/null +++ b/include/IGUISkin.h @@ -0,0 +1,580 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_SKIN_H_INCLUDED__ +#define __I_GUI_SKIN_H_INCLUDED__ + +#include "IAttributeExchangingObject.h" +#include "EGUIAlignment.h" +#include "SColor.h" +#include "rect.h" + +namespace irr +{ +namespace gui +{ + class IGUIFont; + class IGUISpriteBank; + class IGUIElement; + + //! Enumeration of available default skins. + /** To set one of the skins, use the following code, for example to set + the Windows classic skin: + \code + gui::IGUISkin* newskin = environment->createSkin(gui::EGST_WINDOWS_CLASSIC); + environment->setSkin(newskin); + newskin->drop(); + \endcode + */ + enum EGUI_SKIN_TYPE + { + //! Default windows look and feel + EGST_WINDOWS_CLASSIC=0, + + //! Like EGST_WINDOWS_CLASSIC, but with metallic shaded windows and buttons + EGST_WINDOWS_METALLIC, + + //! Burning's skin + EGST_BURNING_SKIN, + + //! An unknown skin, not serializable at present + EGST_UNKNOWN, + + //! this value is not used, it only specifies the number of skin types + EGST_COUNT + }; + + //! Names for gui element types + const c8* const GUISkinTypeNames[EGST_COUNT+1] = + { + "windowsClassic", + "windowsMetallic", + "burning", + "unknown", + 0, + }; + + + //! Enumeration for skin colors + enum EGUI_DEFAULT_COLOR + { + //! Dark shadow for three-dimensional display elements. + EGDC_3D_DARK_SHADOW = 0, + //! Shadow color for three-dimensional display elements (for edges facing away from the light source). + EGDC_3D_SHADOW, + //! Face color for three-dimensional display elements and for dialog box backgrounds. + EGDC_3D_FACE, + //! Highlight color for three-dimensional display elements (for edges facing the light source.) + EGDC_3D_HIGH_LIGHT, + //! Light color for three-dimensional display elements (for edges facing the light source.) + EGDC_3D_LIGHT, + //! Active window border. + EGDC_ACTIVE_BORDER, + //! Active window title bar text. + EGDC_ACTIVE_CAPTION, + //! Background color of multiple document interface (MDI) applications. + EGDC_APP_WORKSPACE, + //! Text on a button + EGDC_BUTTON_TEXT, + //! Grayed (disabled) text. + EGDC_GRAY_TEXT, + //! Item(s) selected in a control. + EGDC_HIGH_LIGHT, + //! Text of item(s) selected in a control. + EGDC_HIGH_LIGHT_TEXT, + //! Inactive window border. + EGDC_INACTIVE_BORDER, + //! Inactive window caption. + EGDC_INACTIVE_CAPTION, + //! Tool tip text color + EGDC_TOOLTIP, + //! Tool tip background color + EGDC_TOOLTIP_BACKGROUND, + //! Scrollbar gray area + EGDC_SCROLLBAR, + //! Window background + EGDC_WINDOW, + //! Window symbols like on close buttons, scroll bars and check boxes + EGDC_WINDOW_SYMBOL, + //! Icons in a list or tree + EGDC_ICON, + //! Selected icons in a list or tree + EGDC_ICON_HIGH_LIGHT, + //! Grayed (disabled) window symbols like on close buttons, scroll bars and check boxes + EGDC_GRAY_WINDOW_SYMBOL, + //! Window background for editable field (editbox, checkbox-field) + EGDC_EDITABLE, + //! Grayed (disabled) window background for editable field (editbox, checkbox-field) + EGDC_GRAY_EDITABLE, + //! Show focus of window background for editable field (editbox or when checkbox-field is pressed) + EGDC_FOCUSED_EDITABLE, + + //! this value is not used, it only specifies the amount of default colors + //! available. + EGDC_COUNT + }; + + //! Names for default skin colors + const c8* const GUISkinColorNames[EGDC_COUNT+1] = + { + "3DDarkShadow", + "3DShadow", + "3DFace", + "3DHighlight", + "3DLight", + "ActiveBorder", + "ActiveCaption", + "AppWorkspace", + "ButtonText", + "GrayText", + "Highlight", + "HighlightText", + "InactiveBorder", + "InactiveCaption", + "ToolTip", + "ToolTipBackground", + "ScrollBar", + "Window", + "WindowSymbol", + "Icon", + "IconHighlight", + "GrayWindowSymbol", + "Editable", + "GrayEditable", + "FocusedEditable", + 0, + }; + + //! Enumeration for default sizes. + enum EGUI_DEFAULT_SIZE + { + //! default with / height of scrollbar. Also width of drop-down button in comboboxes. + EGDS_SCROLLBAR_SIZE = 0, + //! height of menu + EGDS_MENU_HEIGHT, + //! width and height of a window titlebar button (like minimize/maximize/close buttons). The titlebar height is also calculated from that. + EGDS_WINDOW_BUTTON_WIDTH, + //! width of a checkbox check + EGDS_CHECK_BOX_WIDTH, + //! \deprecated This may be removed by Irrlicht 1.9 + EGDS_MESSAGE_BOX_WIDTH, + //! \deprecated This may be removed by Irrlicht 1.9 + EGDS_MESSAGE_BOX_HEIGHT, + //! width of a default button + EGDS_BUTTON_WIDTH, + //! height of a default button (OK and cancel buttons) + EGDS_BUTTON_HEIGHT, + //! distance for text from background + EGDS_TEXT_DISTANCE_X, + //! distance for text from background + EGDS_TEXT_DISTANCE_Y, + //! distance for text in the title bar, from the left of the window rect + EGDS_TITLEBARTEXT_DISTANCE_X, + //! distance for text in the title bar, from the top of the window rect + EGDS_TITLEBARTEXT_DISTANCE_Y, + //! free space in a messagebox between borders and contents on all sides + EGDS_MESSAGE_BOX_GAP_SPACE, + //! minimal space to reserve for messagebox text-width + EGDS_MESSAGE_BOX_MIN_TEXT_WIDTH, + //! maximal space to reserve for messagebox text-width + EGDS_MESSAGE_BOX_MAX_TEXT_WIDTH, + //! minimal space to reserve for messagebox text-height + EGDS_MESSAGE_BOX_MIN_TEXT_HEIGHT, + //! maximal space to reserve for messagebox text-height + EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT, + //! pixels to move an unscaled button image to the right when a button is pressed and the unpressed image looks identical + EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X, + //! pixels to move an unscaled button image down when a button is pressed and the unpressed image looks identical + EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y, + //! pixels to move the button text to the right when a button is pressed + EGDS_BUTTON_PRESSED_TEXT_OFFSET_X, + //! pixels to move the button text down when a button is pressed + EGDS_BUTTON_PRESSED_TEXT_OFFSET_Y, + //! pixels to move an unscaled button sprite to the right when a button is pressed + EGDS_BUTTON_PRESSED_SPRITE_OFFSET_X, + //! pixels to move an unscaled button sprite down when a button is pressed + EGDS_BUTTON_PRESSED_SPRITE_OFFSET_Y, + + //! this value is not used, it only specifies the amount of default sizes + //! available. + EGDS_COUNT + }; + + + //! Names for default skin sizes + const c8* const GUISkinSizeNames[EGDS_COUNT+1] = + { + "ScrollBarSize", + "MenuHeight", + "WindowButtonWidth", + "CheckBoxWidth", + "MessageBoxWidth", + "MessageBoxHeight", + "ButtonWidth", + "ButtonHeight", + "TextDistanceX", + "TextDistanceY", + "TitleBarTextX", + "TitleBarTextY", + "MessageBoxGapSpace", + "MessageBoxMinTextWidth", + "MessageBoxMaxTextWidth", + "MessageBoxMinTextHeight", + "MessageBoxMaxTextHeight", + "ButtonPressedImageOffsetX", + "ButtonPressedImageOffsetY", + "ButtonPressedTextOffsetX", + "ButtonPressedTextOffsetY", + "ButtonPressedSpriteOffsetX", + "ButtonPressedSpriteOffsetY", + 0 + }; + + + enum EGUI_DEFAULT_TEXT + { + //! Text for the OK button on a message box + EGDT_MSG_BOX_OK = 0, + //! Text for the Cancel button on a message box + EGDT_MSG_BOX_CANCEL, + //! Text for the Yes button on a message box + EGDT_MSG_BOX_YES, + //! Text for the No button on a message box + EGDT_MSG_BOX_NO, + //! Tooltip text for window close button + EGDT_WINDOW_CLOSE, + //! Tooltip text for window maximize button + EGDT_WINDOW_MAXIMIZE, + //! Tooltip text for window minimize button + EGDT_WINDOW_MINIMIZE, + //! Tooltip text for window restore button + EGDT_WINDOW_RESTORE, + + //! this value is not used, it only specifies the number of default texts + EGDT_COUNT + }; + + //! Names for default skin sizes + const c8* const GUISkinTextNames[EGDT_COUNT+1] = + { + "MessageBoxOkay", + "MessageBoxCancel", + "MessageBoxYes", + "MessageBoxNo", + "WindowButtonClose", + "WindowButtonMaximize", + "WindowButtonMinimize", + "WindowButtonRestore", + 0 + }; + + //! Customizable symbols for GUI + enum EGUI_DEFAULT_ICON + { + //! maximize window button + EGDI_WINDOW_MAXIMIZE = 0, + //! restore window button + EGDI_WINDOW_RESTORE, + //! close window button + EGDI_WINDOW_CLOSE, + //! minimize window button + EGDI_WINDOW_MINIMIZE, + //! resize icon for bottom right corner of a window + EGDI_WINDOW_RESIZE, + //! scroll bar up button + EGDI_CURSOR_UP, + //! scroll bar down button + EGDI_CURSOR_DOWN, + //! scroll bar left button + EGDI_CURSOR_LEFT, + //! scroll bar right button + EGDI_CURSOR_RIGHT, + //! icon for menu children + EGDI_MENU_MORE, + //! tick for checkbox + EGDI_CHECK_BOX_CHECKED, + //! down arrow for dropdown menus + EGDI_DROP_DOWN, + //! smaller up arrow + EGDI_SMALL_CURSOR_UP, + //! smaller down arrow + EGDI_SMALL_CURSOR_DOWN, + //! selection dot in a radio button + EGDI_RADIO_BUTTON_CHECKED, + //! << icon indicating there is more content to the left + EGDI_MORE_LEFT, + //! >> icon indicating that there is more content to the right + EGDI_MORE_RIGHT, + //! icon indicating that there is more content above + EGDI_MORE_UP, + //! icon indicating that there is more content below + EGDI_MORE_DOWN, + //! plus icon for trees + EGDI_EXPAND, + + //! minus icon for trees + EGDI_COLLAPSE, + //! file icon for file selection + EGDI_FILE, + //! folder icon for file selection + EGDI_DIRECTORY, + + //! value not used, it only specifies the number of icons + EGDI_COUNT + }; + + const c8* const GUISkinIconNames[EGDI_COUNT+1] = + { + "windowMaximize", + "windowRestore", + "windowClose", + "windowMinimize", + "windowResize", + "cursorUp", + "cursorDown", + "cursorLeft", + "cursorRight", + "menuMore", + "checkBoxChecked", + "dropDown", + "smallCursorUp", + "smallCursorDown", + "radioButtonChecked", + "moreLeft", + "moreRight", + "moreUp", + "moreDown", + "expand", + "collapse", + "file", + "directory", + 0 + }; + + // Customizable fonts + enum EGUI_DEFAULT_FONT + { + //! For static text, edit boxes, lists and most other places + EGDF_DEFAULT=0, + //! Font for buttons + EGDF_BUTTON, + //! Font for window title bars + EGDF_WINDOW, + //! Font for menu items + EGDF_MENU, + //! Font for tooltips + EGDF_TOOLTIP, + //! this value is not used, it only specifies the amount of default fonts + //! available. + EGDF_COUNT + }; + + const c8* const GUISkinFontNames[EGDF_COUNT+1] = + { + "defaultFont", + "buttonFont", + "windowFont", + "menuFont", + "tooltipFont", + 0 + }; + + //! A skin modifies the look of the GUI elements. + class IGUISkin : public virtual io::IAttributeExchangingObject + { + public: + + //! returns default color + virtual video::SColor getColor(EGUI_DEFAULT_COLOR color) const = 0; + + //! sets a default color + virtual void setColor(EGUI_DEFAULT_COLOR which, video::SColor newColor) = 0; + + //! returns size for the given size type + virtual s32 getSize(EGUI_DEFAULT_SIZE size) const = 0; + + //! Returns a default text. + /** For example for Message box button captions: + "OK", "Cancel", "Yes", "No" and so on. */ + virtual const wchar_t* getDefaultText(EGUI_DEFAULT_TEXT text) const = 0; + + //! Sets a default text. + /** For example for Message box button captions: + "OK", "Cancel", "Yes", "No" and so on. */ + virtual void setDefaultText(EGUI_DEFAULT_TEXT which, const wchar_t* newText) = 0; + + //! sets a default size + virtual void setSize(EGUI_DEFAULT_SIZE which, s32 size) = 0; + + //! returns the default font + virtual IGUIFont* getFont(EGUI_DEFAULT_FONT which=EGDF_DEFAULT) const = 0; + + //! sets a default font + virtual void setFont(IGUIFont* font, EGUI_DEFAULT_FONT which=EGDF_DEFAULT) = 0; + + //! returns the sprite bank + virtual IGUISpriteBank* getSpriteBank() const = 0; + + //! sets the sprite bank + virtual void setSpriteBank(IGUISpriteBank* bank) = 0; + + //! Returns a default icon + /** Returns the sprite index within the sprite bank */ + virtual u32 getIcon(EGUI_DEFAULT_ICON icon) const = 0; + + //! Sets a default icon + /** 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) = 0; + + //! draws a standard 3d button pane + /** 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. + \param element: Pointer to the element which wishes to draw this. 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 rect: Defining area where to draw. + \param clip: Clip area. */ + virtual void draw3DButtonPaneStandard(IGUIElement* element, + const core::rect& rect, + const core::rect* clip=0) = 0; + + //! draws a pressed 3d button pane + /** 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. + \param element: Pointer to the element which wishes to draw this. 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 rect: Defining area where to draw. + \param clip: Clip area. */ + virtual void draw3DButtonPanePressed(IGUIElement* element, + const core::rect& rect, + const core::rect* clip=0) = 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 IGUISkin, 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 fillBackGround: Specifies if the background should be filled with the background + color or not be drawn at all. + \param rect: Defining area where to draw. + \param clip: Clip area. */ + virtual void draw3DSunkenPane(IGUIElement* element, + video::SColor bgcolor, bool flat, bool fillBackGround, + const core::rect& rect, + const core::rect* clip=0) = 0; + + //! 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 IGUISkin, 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. + \param clip: Clip area. + \param checkClientArea: When set to non-null the function will not draw anything, + but will instead return the clientArea which can be used for drawing by the calling window. + That is the area without borders and without titlebar. + \return Returns rect where it would be good to draw title bar text. This will + work even when checkClientArea is set to a non-null value.*/ + virtual core::rect draw3DWindowBackground(IGUIElement* element, + bool drawTitleBar, video::SColor titleBarColor, + const core::rect& rect, + const core::rect* clip=0, + core::rect* checkClientArea=0) = 0; + + //! draws a standard 3d menu pane + /** 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. + \param element: Pointer to the element which wishes to draw this. 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 rect: Defining area where to draw. + \param clip: Clip area. */ + virtual void draw3DMenuPane(IGUIElement* element, + const core::rect& rect, + const core::rect* clip=0) = 0; + + //! draws a standard 3d tool bar + /** 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 IGUISkin, 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, + const core::rect& rect, + const core::rect* clip=0) = 0; + + //! draws a tab button + /** 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 IGUISkin, 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. + \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; + + //! draws a tab control body + /** \param element: Pointer to the element which wishes to draw this. 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 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 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; + + //! 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 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 + \param currenttime: The present time, used to calculate the frame number + \param loop: Whether the animation should loop or not + \param clip: Clip area. */ + virtual void drawIcon(IGUIElement* element, EGUI_DEFAULT_ICON icon, + const core::position2di position, u32 starttime=0, u32 currenttime=0, + bool loop=false, const core::rect* clip=0) = 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 + 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, + const core::rect& pos, const core::rect* clip = 0) = 0; + + //! get the type of this skin + virtual EGUI_SKIN_TYPE getType() const { return EGST_UNKNOWN; } + }; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUISpinBox.h b/include/IGUISpinBox.h new file mode 100644 index 00000000..1c647627 --- /dev/null +++ b/include/IGUISpinBox.h @@ -0,0 +1,92 @@ +// Copyright (C) 2006-2012 Michael Zeilfelder +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_SPIN_BOX_H_INCLUDED__ +#define __I_GUI_SPIN_BOX_H_INCLUDED__ + +#include "IGUIElement.h" + +namespace irr +{ +namespace gui +{ + class IGUIEditBox; + + //! Enumeration bitflag for when to validate the text typed into the spinbox + //! Default used by Irrlicht is: (EGUI_SBV_ENTER|EGUI_SBV_LOSE_FOCUS) + enum EGUI_SPINBOX_VALIDATION + { + //! Does not validate typed text, probably a bad idea setting this usually. + EGUI_SBV_NEVER = 0, + //! Validate on each change. Was default up to Irrlicht 1.8 + EGUI_SBV_CHANGE = 1, + //! Validate when enter was pressed + EGUI_SBV_ENTER = 2, + //! Validate when the editbox loses the focus + EGUI_SBV_LOSE_FOCUS = 4 + }; + + + //! Single line edit box + spin buttons + /** \par This element can create the following events of type EGUI_EVENT_TYPE: + \li EGET_SPINBOX_CHANGED + */ + class IGUISpinBox : public IGUIElement + { + public: + + //! constructor + IGUISpinBox(IGUIEnvironment* environment, IGUIElement* parent, + s32 id, core::rect rectangle) + : IGUIElement(EGUIET_SPIN_BOX, environment, parent, id, rectangle) {} + + //! Access the edit box used in the spin control + virtual IGUIEditBox* getEditBox() const = 0; + + //! set the current value of the spinbox + /** \param val: value to be set in the spinbox */ + virtual void setValue(f32 val) = 0; + + //! Get the current value of the spinbox + virtual f32 getValue() const = 0; + + //! set the range of values which can be used in the spinbox + /** \param min: minimum value + \param max: maximum value */ + virtual void setRange(f32 min, f32 max) = 0; + + //! get the minimum value which can be used in the spinbox + virtual f32 getMin() const = 0; + + //! get the maximum value which can be used in the spinbox + virtual f32 getMax() const = 0; + + //! Step size by which values are changed when pressing the spinbuttons + /** The step size also determines the number of decimal places to display + \param step: stepsize used for value changes when pressing spinbuttons */ + virtual void setStepSize(f32 step=1.f) = 0; + + //! Sets the number of decimal places to display. + //! Note that this also rounds the range to the same number of decimal places. + /** \param places: The number of decimal places to display, use -1 to reset */ + virtual void setDecimalPlaces(s32 places) = 0; + + //! get the current step size + virtual f32 getStepSize() const = 0; + + //! Sets when the spinbox has to validate entered text. + /** \param validateOn Can be any combination of EGUI_SPINBOX_VALIDATION bit flags */ + virtual void setValidateOn(u32 validateOn) = 0; + + //! Gets when the spinbox has to validate entered text. + /** \return A combination of EGUI_SPINBOX_VALIDATION bit flags */ + virtual u32 getValidateOn() const = 0; + }; + + +} // end namespace gui +} // end namespace irr + +#endif // __I_GUI_SPIN_BOX_H_INCLUDED__ + diff --git a/include/IGUISpriteBank.h b/include/IGUISpriteBank.h new file mode 100644 index 00000000..84816164 --- /dev/null +++ b/include/IGUISpriteBank.h @@ -0,0 +1,142 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_SPRITE_BANK_H_INCLUDED__ +#define __I_GUI_SPRITE_BANK_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "irrArray.h" +#include "SColor.h" +#include "rect.h" + +namespace irr +{ + +namespace video +{ + class ITexture; +} // end namespace video + +namespace gui +{ + +//! A single sprite frame. +// Note for implementer: Can't fix variable names to uppercase as this is a public interface used since a while +struct SGUISpriteFrame +{ + SGUISpriteFrame() : textureNumber(0), rectNumber(0) + { + } + + SGUISpriteFrame(u32 textureIndex, u32 positionIndex) + : textureNumber(textureIndex), rectNumber(positionIndex) + { + } + + //! Texture index in IGUISpriteBank + u32 textureNumber; + + //! Index in IGUISpriteBank::getPositions() + u32 rectNumber; +}; + +//! A sprite composed of several frames. +// Note for implementer: Can't fix variable names to uppercase as this is a public interface used since a while +struct SGUISprite +{ + SGUISprite() : frameTime(0) {} + SGUISprite(const SGUISpriteFrame& firstFrame) : frameTime(0) + { + Frames.push_back(firstFrame); + } + + core::array Frames; + u32 frameTime; +}; + + +//! Sprite bank interface. +/** See http://http://irrlicht.sourceforge.net/forum//viewtopic.php?f=9&t=25742 +* for more information how to use the spritebank. +*/ +class IGUISpriteBank : public virtual IReferenceCounted +{ +public: + + //! Returns the list of rectangles held by the sprite bank + virtual core::array< core::rect >& getPositions() = 0; + + //! Returns the array of animated sprites within the sprite bank + virtual core::array< SGUISprite >& getSprites() = 0; + + //! Returns the number of textures held by the sprite bank + virtual u32 getTextureCount() const = 0; + + //! Gets the texture with the specified index + virtual video::ITexture* getTexture(u32 index) const = 0; + + //! Adds a texture to the sprite bank + virtual void addTexture(video::ITexture* texture) = 0; + + //! Changes one of the textures in the sprite bank + virtual void setTexture(u32 index, video::ITexture* texture) = 0; + + //! Add the texture and use it for a single non-animated sprite. + /** The texture and the corresponding rectangle and sprite will all be added to the end of each array. + \returns The index of the sprite or -1 on failure */ + virtual s32 addTextureAsSprite(video::ITexture* texture) = 0; + + //! Clears sprites, rectangles and textures + virtual void clear() = 0; + + //! Draws a sprite in 2d with position and color + /** + \param index Index of SGUISprite to draw + \param pos Target position - depending on center value either the left-top or the sprite center is used as pivot + \param clip Clipping rectangle, can be 0 when clipping is not wanted. + \param color Color with which the image is drawn. + Note that the alpha component is used. If alpha is other than + 255, the image will be transparent. + \param starttime Tick when the first frame was drawn (only difference currenttime-starttime matters). + \param currenttime To calculate the frame of animated sprites + \param loop When true animations are looped + \param center When true pivot is set to the sprite-center. So it affects pos. + */ + virtual void draw2DSprite(u32 index, const core::position2di& pos, + const core::rect* clip=0, + const video::SColor& color= video::SColor(255,255,255,255), + u32 starttime=0, u32 currenttime=0, + bool loop=true, bool center=false) = 0; + + //! Draws a sprite in 2d with destination rectangle and colors + /** + \param index Index of SGUISprite to draw + \param destRect The sprite will be scaled to fit this target rectangle + \param clip Clipping rectangle, can be 0 when clipping is not wanted. + \param colors Array of 4 colors denoting the color values of + the corners of the destRect + \param timeTicks Current frame for animated sprites + (same as currenttime-starttime in other draw2DSprite function) + \param loop When true animations are looped + */ + virtual void draw2DSprite(u32 index, const core::rect& destRect, + const core::rect* clip=0, + const video::SColor * const colors=0, + u32 timeTicks = 0, + bool loop=true) = 0; + + //! Draws a sprite batch in 2d using an array of positions and a color + virtual void draw2DSpriteBatch(const core::array& indices, const core::array& pos, + const core::rect* clip=0, + const video::SColor& color= video::SColor(255,255,255,255), + u32 starttime=0, u32 currenttime=0, + bool loop=true, bool center=false) = 0; +}; + + +} // end namespace gui +} // end namespace irr + +#endif // __I_GUI_SPRITE_BANK_H_INCLUDED__ + diff --git a/include/IGUIStaticText.h b/include/IGUIStaticText.h new file mode 100644 index 00000000..b55bd95d --- /dev/null +++ b/include/IGUIStaticText.h @@ -0,0 +1,135 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_STATIC_TEXT_H_INCLUDED__ +#define __I_GUI_STATIC_TEXT_H_INCLUDED__ + +#include "IGUIElement.h" +#include "SColor.h" + +namespace irr +{ +namespace gui +{ + class IGUIFont; + + //! Multi or single line text label. + class IGUIStaticText : public IGUIElement + { + public: + + //! constructor + IGUIStaticText(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_STATIC_TEXT, environment, parent, id, rectangle) {} + + //! Sets another skin independent font. + /** If this is set to zero, the button uses the font of the skin. + \param font: New font to set. */ + virtual void setOverrideFont(IGUIFont* font=0) = 0; + + //! Gets the override font (if any) + /** \return The override font (may be 0) */ + virtual IGUIFont* getOverrideFont(void) const = 0; + + //! Get the font which is used right now for drawing + /** Currently this is the override font when one is set and the + font of the active skin otherwise */ + virtual IGUIFont* getActiveFont() const = 0; + + //! Sets another color for the text. + /** If set, the static text does not use the EGDC_BUTTON_TEXT color defined + in the skin, but the set color instead. You don't need to call + IGUIStaticText::enableOverrrideColor(true) after this, this is done + by this function. + If you set a color, and you want the text displayed with the color + of the skin again, call IGUIStaticText::enableOverrideColor(false); + \param color: New color of the text. */ + virtual void setOverrideColor(video::SColor color) = 0; + + //! Gets the override color + /** \return: The override color */ + virtual video::SColor getOverrideColor(void) const = 0; + + //! Sets if the static text should use the override color or the color in the gui skin. + /** \param enable: If set to true, the override color, which can be set + with IGUIStaticText::setOverrideColor is used, otherwise the + EGDC_BUTTON_TEXT color of the skin. */ + virtual void enableOverrideColor(bool enable) = 0; + + //! Checks if an override color is enabled + /** \return true if the override color is enabled, false otherwise */ + virtual bool isOverrideColorEnabled(void) const = 0; + + //! Sets another color for the background. + virtual void setBackgroundColor(video::SColor color) = 0; + + //! Sets whether to draw the background + virtual void setDrawBackground(bool draw) = 0; + + //! Checks if background drawing is enabled + /** \return true if background drawing is enabled, false otherwise */ + virtual bool isDrawBackgroundEnabled() const = 0; + + //! Gets the background color + /** \return: The background color */ + virtual video::SColor getBackgroundColor() const = 0; + + //! Sets whether to draw the border + virtual void setDrawBorder(bool draw) = 0; + + //! Checks if border drawing is enabled + /** \return true if border drawing is enabled, false otherwise */ + virtual bool isDrawBorderEnabled() const = 0; + + //! Sets text justification mode + /** \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; + + //! Enables or disables word wrap for using the static text as multiline text control. + /** \param enable: If set to true, words going over one line are + broken on to the next line. */ + virtual void setWordWrap(bool enable) = 0; + + //! Checks if word wrap is enabled + /** \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. + /** This is useful for adjusting the layout of gui elements based on the height + of the multiline text in this element. + \return Height of text in pixels. */ + virtual s32 getTextHeight() const = 0; + + //! Returns the width of the current text, in the current font + /** If the text is broken, this returns the width of the widest line + \return The width of the text, or the widest broken line. */ + virtual s32 getTextWidth(void) const = 0; + + //! Set whether the text in this label should be clipped if it goes outside bounds + virtual void setTextRestrainedInside(bool restrainedInside) = 0; + + //! Checks if the text in this label should be clipped if it goes outside bounds + virtual bool isTextRestrainedInside() const = 0; + + //! Set whether the string should be interpreted as right-to-left (RTL) text + /** \note This component does not implement the Unicode bidi standard, the + text of the component should be already RTL if you call this. The + main difference when RTL is enabled is that the linebreaks for multiline + elements are performed starting from the end. + */ + virtual void setRightToLeft(bool rtl) = 0; + + //! Checks whether the text in this element should be interpreted as right-to-left + virtual bool isRightToLeft() const = 0; + }; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUITabControl.h b/include/IGUITabControl.h new file mode 100644 index 00000000..8301238d --- /dev/null +++ b/include/IGUITabControl.h @@ -0,0 +1,164 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_TAB_CONTROL_H_INCLUDED__ +#define __I_GUI_TAB_CONTROL_H_INCLUDED__ + +#include "IGUIElement.h" +#include "SColor.h" +#include "IGUISkin.h" + +namespace irr +{ +namespace gui +{ + class IGUITab; + + //! A standard tab control + /** \par This element can create the following events of type EGUI_EVENT_TYPE: + \li EGET_TAB_CHANGED + */ + class IGUITabControl : public IGUIElement + { + public: + + //! constructor + IGUITabControl(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_TAB_CONTROL, environment, parent, id, rectangle) {} + + //! Adds a tab + virtual IGUITab* addTab(const wchar_t* caption, s32 id=-1) = 0; + + //! Adds an existing tab + /** Note that it will also add the tab as a child of this TabControl. + \return Index of added tab or -1 for failure*/ + virtual s32 addTab(IGUITab* tab) = 0; + + //! Insert the tab at the given index + /** \return The tab on success or NULL on failure. */ + virtual IGUITab* insertTab(s32 idx, const wchar_t* caption, s32 id=-1) = 0; + + //! Insert an existing tab + /** Note that it will also add the tab as a child of this TabControl. + \param idx Index at which tab will be inserted. Later tabs will be moved. + Previous active tab will stay active unless this is the first + element to be inserted in which case it becomes active. + \param tab New tab to insert. + \param serializationMode Internally used for serialization. You should not need this. + When true it reserves space for the index, doesn't move but replaces tabs + and it doesn't change the active tab. + \return Index of added tab (should be same as the one passed) or -1 for failure*/ + virtual s32 insertTab(s32 idx, IGUITab* tab, bool serializationMode=false) = 0; + + //! Removes a tab from the tabcontrol + virtual void removeTab(s32 idx) = 0; + + //! Clears the tabcontrol removing all tabs + virtual void clear() = 0; + + //! Returns amount of tabs in the tabcontrol + virtual s32 getTabCount() const = 0; + + //! Returns a tab based on zero based index + /** \param idx: zero based index of tab. Is a value between 0 and getTabcount()-1; + \return Returns pointer to the Tab. Returns 0 if no tab + is corresponding to this tab. */ + virtual IGUITab* getTab(s32 idx) const = 0; + + //! For given element find if it's a tab and return it's zero-based index (or -1 for not found) + /** \param tab Tab for which we are looking (usually you will look for an IGUITab* type as only + those can be tabs, but we allow looking for any kind of IGUIElement* as there are some + use-cases for that even if it just returns 0. For example this way you can check for + all children of this gui-element if they are tabs or some non-tab children.*/ + virtual s32 getTabIndex(const IGUIElement *tab) const = 0; + + //! Brings a tab to front. + /** \param idx: number of the tab. + \return Returns true if successful. */ + virtual bool setActiveTab(s32 idx) = 0; + + //! Brings a tab to front. + /** \param tab: pointer to the tab. + \return Returns true if successful. */ + virtual bool setActiveTab(IGUITab *tab) = 0; + + //! Returns which tab is currently active + virtual s32 getActiveTab() const = 0; + + //! get the the id of the tab at the given absolute coordinates + /** \return The id of the tab or -1 when no tab is at those coordinates*/ + virtual s32 getTabAt(s32 xpos, s32 ypos) const = 0; + + //! Set the height of the tabs + virtual void setTabHeight( s32 height ) = 0; + + //! Get the height of the tabs + /** return Returns the height of the tabs */ + virtual s32 getTabHeight() const = 0; + + //! set the maximal width of a tab. Per default width is 0 which means "no width restriction". + virtual void setTabMaxWidth(s32 width ) = 0; + + //! get the maximal width of a tab + virtual s32 getTabMaxWidth() const = 0; + + //! Set the alignment of the tabs + /** Use EGUIA_UPPERLEFT or EGUIA_LOWERRIGHT */ + virtual void setTabVerticalAlignment( gui::EGUI_ALIGNMENT alignment ) = 0; + + //! Get the alignment of the tabs + /** return Returns the alignment of the tabs */ + virtual gui::EGUI_ALIGNMENT getTabVerticalAlignment() const = 0; + + //! Set the extra width added to tabs on each side of the text + virtual void setTabExtraWidth( s32 extraWidth ) = 0; + + //! Get the extra width added to tabs on each side of the text + /** return Returns the extra width of the tabs */ + virtual s32 getTabExtraWidth() const = 0; + }; + + //! A tab-page, onto which other gui elements could be added. + /** IGUITab refers mostly to the page itself, but also carries some data about the tab in the tabbar of an IGUITabControl. */ + class IGUITab : public IGUIElement + { + public: + + //! constructor + IGUITab(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_TAB, environment, parent, id, rectangle) {} + + //! Returns zero based index of tab if in tabcontrol. + /** \deprecated Deprecated in 1.9, use IGUITabControl::getTabIndex instead*/ + _IRR_DEPRECATED_ virtual s32 getNumber() const + { + if (Parent && Parent->getType() == EGUIET_TAB_CONTROL) + return static_cast(Parent)->getTabIndex(this); + return -1; + } + + //! sets if the tab should draw its background + virtual void setDrawBackground(bool draw=true) = 0; + + //! sets the color of the background, if it should be drawn. + virtual void setBackgroundColor(video::SColor c) = 0; + + //! returns true if the tab is drawing its background, false if not + virtual bool isDrawingBackground() const = 0; + + //! returns the color of the background + virtual video::SColor getBackgroundColor() const = 0; + + //! sets the color of it's text in the tab-bar + virtual void setTextColor(video::SColor c) = 0; + + //! gets the color of the text + virtual video::SColor getTextColor() const = 0; + }; + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUITable.h b/include/IGUITable.h new file mode 100644 index 00000000..ea3afccc --- /dev/null +++ b/include/IGUITable.h @@ -0,0 +1,235 @@ +// Copyright (C) 2003-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_TABLE_H_INCLUDED__ +#define __I_GUI_TABLE_H_INCLUDED__ + +#include "IGUIElement.h" +#include "SColor.h" + +namespace irr +{ +namespace gui +{ + class IGUIFont; + class IGUIScrollBar; + + //! modes for ordering used when a column header is clicked + enum EGUI_COLUMN_ORDERING + { + //! Do not use ordering + EGCO_NONE, + + //! 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,... + EGCO_ASCENDING, + + //! Sort it descending by it's ascii value like: z,x,y,... + EGCO_DESCENDING, + + //! Sort it ascending on first click, descending on next, etc + EGCO_FLIP_ASCENDING_DESCENDING, + + //! Not used as mode, only to get maximum value for this enum + EGCO_COUNT + }; + + //! Names for EGUI_COLUMN_ORDERING types + const c8* const GUIColumnOrderingNames[] = + { + "none", + "custom", + "ascend", + "descend", + "ascend_descend", + 0, + }; + + enum EGUI_ORDERING_MODE + { + //! No element ordering + EGOM_NONE, + + //! Elements are ordered from the smallest to the largest. + EGOM_ASCENDING, + + //! Elements are ordered from the largest to the smallest. + EGOM_DESCENDING, + + //! this value is not used, it only specifies the amount of default ordering types + //! available. + EGOM_COUNT + }; + + const c8* const GUIOrderingModeNames[] = + { + "none", + "ascending", + "descending", + 0 + }; + + enum EGUI_TABLE_DRAW_FLAGS + { + EGTDF_ROWS = 1, + EGTDF_COLUMNS = 2, + EGTDF_ACTIVE_ROW = 4, + EGTDF_COUNT + }; + + //! Default list box GUI element. + /** \par This element can create the following events of type EGUI_EVENT_TYPE: + \li EGET_TABLE_CHANGED + \li EGET_TABLE_SELECTED_AGAIN + \li EGET_TABLE_HEADER_CHANGED + */ + class IGUITable : public IGUIElement + { + public: + //! constructor + IGUITable(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_TABLE, environment, parent, id, rectangle) {} + + //! Adds a column + /** If columnIndex is outside the current range, do push new column at the end */ + virtual void addColumn(const wchar_t* caption, s32 columnIndex=-1) = 0; + + //! remove a column from the table + virtual void removeColumn(u32 columnIndex) = 0; + + //! Returns the number of columns in the table control + virtual s32 getColumnCount() const = 0; + + //! Makes a column active. This will trigger an ordering process. + /** \param idx: The id of the column to make active or a negative number to make non active. + \param doOrder: Do also the ordering which depending on mode for active column + \return True when the column could be set active (aka - it did exist). */ + virtual bool setActiveColumn(s32 idx, bool doOrder=false) = 0; + + //! Returns which header is currently active + virtual s32 getActiveColumn() const = 0; + + //! Returns the ordering used by the currently active column + virtual EGUI_ORDERING_MODE getActiveColumnOrdering() const = 0; + + //! Set the width of a column + virtual void setColumnWidth(u32 columnIndex, u32 width) = 0; + + //! Get the width of a column + virtual u32 getColumnWidth(u32 columnIndex) const = 0; + + //! columns can be resized by drag 'n drop + virtual void setResizableColumns(bool resizable) = 0; + + //! can columns be resized by drag '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 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 + virtual s32 getSelected() const = 0; + + //! set which row is currently selected + virtual void setSelected( s32 index ) = 0; + + //! Get amount of rows in the tabcontrol + 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. + \return index of inserted row. */ + virtual u32 addRow(u32 rowIndex) = 0; + + //! Remove a row from the table + virtual void removeRow(u32 rowIndex) = 0; + + //! clears the table rows, but keeps the columns intact + virtual void clearRows() = 0; + + //! Swap two row positions. + 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. + \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 + virtual void setCellText(u32 rowIndex, u32 columnIndex, const core::stringw& text) = 0; + + //! Set the text of a cell, and set a color of this cell. + virtual void setCellText(u32 rowIndex, u32 columnIndex, const core::stringw& text, video::SColor color) = 0; + + //! Set the data of a cell + virtual void setCellData(u32 rowIndex, u32 columnIndex, void *data) = 0; + + //! Set the color of a cell text + virtual void setCellColor(u32 rowIndex, u32 columnIndex, video::SColor color) = 0; + + //! Get the text of a cell + virtual const wchar_t* getCellText(u32 rowIndex, u32 columnIndex ) const = 0; + + //! Get the data of a cell + virtual void* getCellData(u32 rowIndex, u32 columnIndex ) const = 0; + + //! clears the table, deletes all items in the table + virtual void clear() = 0; + + //! Set flags, as defined in ::EGUI_TABLE_DRAW_FLAGS, which influence the layout + virtual void setDrawFlags(s32 flags) = 0; + + //! Get the flags, as defined in ::EGUI_TABLE_DRAW_FLAGS, which influence the layout + virtual s32 getDrawFlags() const = 0; + + //! Sets another skin independent font. + /** If this is set to zero, the button uses the font of the skin. + \param font: New font to set. */ + virtual void setOverrideFont(IGUIFont* font=0) = 0; + + //! Gets the override font (if any) + /** \return The override font (may be 0) */ + virtual IGUIFont* getOverrideFont(void) const = 0; + + //! Get the font which is used right now for drawing + /** Currently this is the override font when one is set and the + font of the active skin otherwise */ + virtual IGUIFont* getActiveFont() const = 0; + + //! Get the height of items/rows + virtual s32 getItemHeight() const = 0; + + //! Access the vertical scrollbar + virtual IGUIScrollBar* getVerticalScrollBar() const = 0; + + //! Access the horizontal scrollbar + virtual IGUIScrollBar* getHorizontalScrollBar() const = 0; + + //! Sets whether to draw the background. + virtual void setDrawBackground(bool draw) = 0; + + //! Checks if background drawing is enabled + /** \return true if background drawing is enabled, false otherwise */ + virtual bool isDrawBackgroundEnabled() const = 0; + }; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUIToolbar.h b/include/IGUIToolbar.h new file mode 100644 index 00000000..58796bf4 --- /dev/null +++ b/include/IGUIToolbar.h @@ -0,0 +1,40 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_TOOL_BAR_H_INCLUDED__ +#define __I_GUI_TOOL_BAR_H_INCLUDED__ + +#include "IGUIElement.h" + +namespace irr +{ +namespace video +{ + class ITexture; +} // end namespace video +namespace gui +{ + class IGUIButton; + + //! Stays at the top of its parent like the menu bar and contains tool buttons + class IGUIToolBar : public IGUIElement + { + public: + + //! constructor + IGUIToolBar(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_TOOL_BAR, environment, parent, id, rectangle) {} + + //! Adds a button to the tool bar + virtual IGUIButton* addButton(s32 id=-1, const wchar_t* text=0,const wchar_t* tooltiptext=0, + video::ITexture* img=0, video::ITexture* pressedimg=0, + bool isPushButton=false, bool useAlphaChannel=false) = 0; + }; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUITreeView.h b/include/IGUITreeView.h new file mode 100644 index 00000000..8bcd824d --- /dev/null +++ b/include/IGUITreeView.h @@ -0,0 +1,298 @@ +// written by Reinhard Ostermeier, reinhard@nospam.r-ostermeier.de +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_TREE_VIEW_H_INCLUDED__ +#define __I_GUI_TREE_VIEW_H_INCLUDED__ + +#include "IGUIElement.h" +#include "IGUIImageList.h" +#include "irrTypes.h" + +namespace irr +{ +namespace gui +{ + class IGUIFont; + class IGUITreeView; + class IGUIScrollBar; + + + //! Node for gui tree view + /** \par This element can create the following events of type EGUI_EVENT_TYPE: + \li EGET_TREEVIEW_NODE_EXPAND + \li EGET_TREEVIEW_NODE_COLLAPS + \li EGET_TREEVIEW_NODE_DESELECT + \li EGET_TREEVIEW_NODE_SELECT + */ + class IGUITreeViewNode : public IReferenceCounted + { + public: + //! returns the owner (tree view) of this node + virtual IGUITreeView* getOwner() const = 0; + + //! Returns the parent node of this node. + /** For the root node this will return 0. */ + virtual IGUITreeViewNode* getParent() const = 0; + + //! returns the text of the node + virtual const wchar_t* getText() const = 0; + + //! sets the text of the node + virtual void setText( const wchar_t* text ) = 0; + + //! returns the icon text of the node + virtual const wchar_t* getIcon() const = 0; + + //! sets the icon text of the node + virtual void setIcon( const wchar_t* icon ) = 0; + + //! returns the image index of the node + virtual u32 getImageIndex() const = 0; + + //! sets the image index of the node + virtual void setImageIndex( u32 imageIndex ) = 0; + + //! returns the image index of the node + virtual u32 getSelectedImageIndex() const = 0; + + //! sets the image index of the node + virtual void setSelectedImageIndex( u32 imageIndex ) = 0; + + //! returns the user data (void*) of this node + virtual void* getData() const = 0; + + //! sets the user data (void*) of this node + virtual void setData( void* data ) = 0; + + //! returns the user data2 (IReferenceCounted) of this node + virtual IReferenceCounted* getData2() const = 0; + + //! sets the user data2 (IReferenceCounted) of this node + virtual void setData2( IReferenceCounted* data ) = 0; + + //! returns the child item count + virtual u32 getChildCount() const = 0; + + //! removes all children (recursive) from this node + virtual void clearChildren() = 0; + + //! removes all children (recursive) from this node + /** \deprecated Deprecated in 1.8, use clearChildren() instead. + This method may be removed by Irrlicht 1.9 */ + _IRR_DEPRECATED_ void clearChilds() + { + return clearChildren(); + } + + //! returns true if this node has child nodes + virtual bool hasChildren() const = 0; + + //! returns true if this node has child nodes + /** \deprecated Deprecated in 1.8, use hasChildren() instead. + This method may be removed by Irrlicht 1.9 */ + _IRR_DEPRECATED_ bool hasChilds() const + { + return hasChildren(); + } + + //! Adds a new node behind the last child node. + /** \param text text of the new node + \param icon icon text of the new node + \param imageIndex index of the image for the new node (-1 = none) + \param selectedImageIndex index of the selected image for the new node (-1 = same as imageIndex) + \param data user data (void*) of the new node + \param data2 user data2 (IReferenceCounted*) of the new node + \return The new node + */ + virtual IGUITreeViewNode* addChildBack( + const wchar_t* text, const wchar_t* icon = 0, + s32 imageIndex=-1, s32 selectedImageIndex=-1, + void* data=0, IReferenceCounted* data2=0) =0; + + //! Adds a new node before the first child node. + /** \param text text of the new node + \param icon icon text of the new node + \param imageIndex index of the image for the new node (-1 = none) + \param selectedImageIndex index of the selected image for the new node (-1 = same as imageIndex) + \param data user data (void*) of the new node + \param data2 user data2 (IReferenceCounted*) of the new node + \return The new node + */ + virtual IGUITreeViewNode* addChildFront( + const wchar_t* text, const wchar_t* icon = 0, + s32 imageIndex=-1, s32 selectedImageIndex=-1, + void* data=0, IReferenceCounted* data2=0 ) =0; + + //! Adds a new node behind the other node. + /** The other node has also to be a child node from this node. + \param other Node to insert after + \param text text of the new node + \param icon icon text of the new node + \param imageIndex index of the image for the new node (-1 = none) + \param selectedImageIndex index of the selected image for the new node (-1 = same as imageIndex) + \param data user data (void*) of the new node + \param data2 user data2 (IReferenceCounted*) of the new node + \return The new node or 0 if other is no child node from this + */ + virtual IGUITreeViewNode* insertChildAfter( + IGUITreeViewNode* other, + const wchar_t* text, const wchar_t* icon = 0, + s32 imageIndex=-1, s32 selectedImageIndex=-1, + void* data=0, IReferenceCounted* data2=0) =0; + + //! Adds a new node before the other node. + /** The other node has also to be a child node from this node. + \param other Node to insert before + \param text text of the new node + \param icon icon text of the new node + \param imageIndex index of the image for the new node (-1 = none) + \param selectedImageIndex index of the selected image for the new node (-1 = same as imageIndex) + \param data user data (void*) of the new node + \param data2 user data2 (IReferenceCounted*) of the new node + \return The new node or 0 if other is no child node from this + */ + virtual IGUITreeViewNode* insertChildBefore( + IGUITreeViewNode* other, + const wchar_t* text, const wchar_t* icon = 0, + s32 imageIndex=-1, s32 selectedImageIndex=-1, + void* data=0, IReferenceCounted* data2=0) = 0; + + //! Return the first child node from this node. + /** \return The first child node or 0 if this node has no children. */ + virtual IGUITreeViewNode* getFirstChild() const = 0; + + //! Return the last child node from this node. + /** \return The last child node or 0 if this node has no children. */ + virtual IGUITreeViewNode* getLastChild() const = 0; + + //! Returns the previous sibling node from this node. + /** \return The previous sibling node from this node or 0 if this is + the first node from the parent node. + */ + virtual IGUITreeViewNode* getPrevSibling() const = 0; + + //! Returns the next sibling node from this node. + /** \return The next sibling node from this node or 0 if this is + the last node from the parent node. + */ + virtual IGUITreeViewNode* getNextSibling() const = 0; + + //! Returns the next visible (expanded, may be out of scrolling) node from this node. + /** \return The next visible node from this node or 0 if this is + the last visible node. */ + virtual IGUITreeViewNode* getNextVisible() const = 0; + + //! Deletes a child node. + /** \return Returns true if the node was found as a child and is deleted. */ + virtual bool deleteChild( IGUITreeViewNode* child ) = 0; + + //! Moves a child node one position up. + /** \return True if the node was found as a child node and was not already the first child. */ + virtual bool moveChildUp( IGUITreeViewNode* child ) = 0; + + //! Moves a child node one position down. + /** \return True if the node was found as a child node and was not already the last child. */ + virtual bool moveChildDown( IGUITreeViewNode* child ) = 0; + + //! Returns true if the node is expanded (children are visible). + virtual bool getExpanded() const = 0; + + //! Sets if the node is expanded. + virtual void setExpanded( bool expanded ) = 0; + + //! Returns true if the node is currently selected. + virtual bool getSelected() const = 0; + + //! Sets this node as selected. + virtual void setSelected( bool selected ) = 0; + + //! Returns true if this node is the root node. + virtual bool isRoot() const = 0; + + //! Returns the level of this node. + /** The root node has level 0. Direct children of the root has level 1 ... */ + virtual s32 getLevel() const = 0; + + //! Returns true if this node is visible (all parents are expanded). + virtual bool isVisible() const = 0; + }; + + + //! Default tree view GUI element. + /** Displays a windows like tree buttons to expand/collapse the child + nodes of an node and optional tree lines. Each node consists of an + text, an icon text and a void pointer for user data. */ + class IGUITreeView : public IGUIElement + { + public: + //! constructor + IGUITreeView(IGUIEnvironment* environment, IGUIElement* parent, + s32 id, core::rect rectangle) + : IGUIElement( EGUIET_TREE_VIEW, environment, parent, id, rectangle ) {} + + //! returns the root node (not visible) from the tree. + virtual IGUITreeViewNode* getRoot() const = 0; + + //! returns the selected node of the tree or 0 if none is selected + virtual IGUITreeViewNode* getSelected() const = 0; + + //! returns true if the tree lines are visible + virtual bool getLinesVisible() const = 0; + + //! sets if the tree lines are visible + /** \param visible true for visible, false for invisible */ + virtual void setLinesVisible( bool visible ) = 0; + + //! Sets the font which should be used as icon font. + /** This font is set to the Irrlicht engine built-in-font by + default. Icons can be displayed in front of every list item. + An icon is a string, displayed with the icon font. When using + the build-in-font of the Irrlicht engine as icon font, the icon + strings defined in GUIIcons.h can be used. + */ + virtual void setIconFont( IGUIFont* font ) = 0; + + //! Sets a skin independent font. + /** \param font: New font to set or 0 to use the skin-font. */ + virtual void setOverrideFont(IGUIFont* font=0) = 0; + + //! Gets the override font (if any) + /** \return The override font (may be 0) */ + virtual IGUIFont* getOverrideFont(void) const = 0; + + //! Get the font which is used for drawing + /** This is the override font when one is set and the + font of the skin otherwise. */ + virtual IGUIFont* getActiveFont() const = 0; + + //! Sets the image list which should be used for the image and selected image of every node. + /** The default is 0 (no images). */ + virtual void setImageList( IGUIImageList* imageList ) = 0; + + //! Returns the image list which is used for the nodes. + virtual IGUIImageList* getImageList() const = 0; + + //! Sets if the image is left of the icon. Default is true. + virtual void setImageLeftOfIcon( bool bLeftOf ) = 0; + + //! Returns if the Image is left of the icon. Default is true. + virtual bool getImageLeftOfIcon() const = 0; + + //! Returns the node which is associated to the last event. + /** This pointer is only valid inside the OnEvent call! */ + virtual IGUITreeViewNode* getLastEventNode() const = 0; + + //! Access the vertical scrollbar + virtual IGUIScrollBar* getVerticalScrollBar() const = 0; + + //! Access the horizontal scrollbar + virtual IGUIScrollBar* getHorizontalScrollBar() const = 0; + }; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGUIWindow.h b/include/IGUIWindow.h new file mode 100644 index 00000000..60349d67 --- /dev/null +++ b/include/IGUIWindow.h @@ -0,0 +1,74 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GUI_WINDOW_H_INCLUDED__ +#define __I_GUI_WINDOW_H_INCLUDED__ + +#include "IGUIElement.h" +#include "EMessageBoxFlags.h" + +namespace irr +{ +namespace gui +{ + class IGUIButton; + + //! Default moveable window GUI element with border, caption and close icons. + /** \par This element can create the following events of type EGUI_EVENT_TYPE: + \li EGET_ELEMENT_CLOSED + */ + class IGUIWindow : public IGUIElement + { + public: + + //! constructor + IGUIWindow(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) + : IGUIElement(EGUIET_WINDOW, environment, parent, id, rectangle) {} + + //! Returns pointer to the close button + /** You can hide the button by calling setVisible(false) on the result. */ + virtual IGUIButton* getCloseButton() const = 0; + + //! Returns pointer to the minimize button + /** You can hide the button by calling setVisible(false) on the result. */ + virtual IGUIButton* getMinimizeButton() const = 0; + + //! Returns pointer to the maximize button + /** You can hide the button by calling setVisible(false) on the result. */ + virtual IGUIButton* getMaximizeButton() const = 0; + + //! Returns true if the window can be dragged with the mouse, false if not + virtual bool isDraggable() const = 0; + + //! Sets whether the window can be dragged by the mouse + virtual void setDraggable(bool draggable) = 0; + + //! Set if the window background will be drawn + virtual void setDrawBackground(bool draw) = 0; + + //! Get if the window background will be drawn + virtual bool getDrawBackground() const = 0; + + //! Set if the window titlebar will be drawn + //! Note: If the background is not drawn, then the titlebar is automatically also not drawn + virtual void setDrawTitlebar(bool draw) = 0; + + //! Get if the window titlebar will be drawn + virtual bool getDrawTitlebar() const = 0; + + //! Returns the rectangle of the drawable area (without border and without titlebar) + /** The coordinates are given relative to the top-left position of the gui element.
+ So to get absolute positions you have to add the resulting rectangle to getAbsolutePosition().UpperLeftCorner.
+ To get it relative to the parent element you have to add the resulting rectangle to getRelativePosition().UpperLeftCorner. + Beware that adding a menu will not change the clientRect as menus are own gui elements, so in that case you might want to subtract + the menu area additionally. */ + virtual core::rect getClientRect() const = 0; + }; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/include/IGeometryCreator.h b/include/IGeometryCreator.h new file mode 100644 index 00000000..6083f5b4 --- /dev/null +++ b/include/IGeometryCreator.h @@ -0,0 +1,209 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_GEOMETRY_CREATOR_H_INCLUDED__ +#define __I_GEOMETRY_CREATOR_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "IMesh.h" +#include "IImage.h" + +namespace irr +{ +namespace video +{ + class IVideoDriver; + class SMaterial; +} + +namespace scene +{ + + enum ECUBE_MESH_TYPE + { + //! Single buffer with 12 different vertices, normals are average of adjacent planes + //! Order for outgoing (front-face) normals of planes would be: NEG_Z, POS_X, POS_Z, NEG_X, POS_Y, NEG_Y + ECMT_1BUF_12VTX_NA, + + //! One buffer per side, each with 4 vertices, normals are perpendicular to sides + //! Note: You probably will have to scale down your texture uv's to avoid white lines at borders + // as this mesh sets them to 0,1 values. We can't do that when creating the mesh as it + // depends on texture resolution which we don't know at that point. + ECMT_6BUF_4VTX_NP + }; + +//! Helper class for creating geometry on the fly. +/** You can get an instance of this class through ISceneManager::getGeometryCreator() */ +class IGeometryCreator : public IReferenceCounted +{ +public: + + //! Creates a simple cube mesh. + /** + \param size Dimensions of the cube. + \param type One of ECUBE_MESH_TYPE. So you can chose between cubes with single material or independent materials per side. + \return Generated mesh. + */ + virtual IMesh* createCubeMesh(const core::vector3df& size=core::vector3df(5.f,5.f,5.f), ECUBE_MESH_TYPE type = ECMT_1BUF_12VTX_NA) const =0; + + //! Create a pseudo-random mesh representing a hilly terrain. + /** + \param tileSize The size of each tile. + \param tileCount The number of tiles in each dimension. + \param material The material to apply to the mesh. + \param hillHeight The maximum height of the hills. + \param countHills The number of hills along each dimension. + \param textureRepeatCount The number of times to repeat the material texture along each dimension. + \return Generated mesh. + */ + virtual IMesh* createHillPlaneMesh( + const core::dimension2d& tileSize, + const core::dimension2d& tileCount, + video::SMaterial* material, f32 hillHeight, + const core::dimension2d& countHills, + const core::dimension2d& textureRepeatCount) const =0; + + //! Create a simple rectangular textured plane mesh. + /** + \param tileSize The size of each tile. + \param tileCount The number of tiles in each dimension. + \param material The material to apply to the mesh. + \param textureRepeatCount The number of times to repeat the material texture along each dimension. + \return Generated mesh. + */ + IMesh* createPlaneMesh( + const core::dimension2d& tileSize, + const core::dimension2d& tileCount=core::dimension2du(1,1), + video::SMaterial* material=0, + const core::dimension2df& textureRepeatCount=core::dimension2df(1.f,1.f)) const + { + return createHillPlaneMesh(tileSize, tileCount, material, 0.f, core::dimension2df(), textureRepeatCount); + } + + //! Create a geoplane. + /** + \param radius Radius of the plane + \param rows How many rows to place + \param columns How many columns to place + \return Generated mesh. + */ + virtual IMesh* createGeoplaneMesh(f32 radius = 5.f, + u32 rows = 16, u32 columns = 16) const =0; + + //! Create a terrain mesh from an image representing a heightfield. + /** + \param texture The texture to apply to the terrain. + \param heightmap An image that will be interpreted as a heightmap. The + brightness (average color) of each pixel is interpreted as a height, + with a 255 brightness pixel producing the maximum height. + \param stretchSize The size that each pixel will produce, i.e. a + 512x512 heightmap + and a stretchSize of (10.f, 20.f) will produce a mesh of size + 5120.f x 10240.f + \param maxHeight The maximum height of the terrain. + \param driver The current video driver. + \param defaultVertexBlockSize (to be documented) + \param debugBorders (to be documented) + \return Generated mesh. + */ + virtual IMesh* createTerrainMesh(video::IImage* texture, + video::IImage* heightmap, + const core::dimension2d& stretchSize, + f32 maxHeight, video::IVideoDriver* driver, + const core::dimension2d& defaultVertexBlockSize, + bool debugBorders=false) const =0; + + //! Create an arrow mesh, composed of a cylinder and a cone. + /** + \param tesselationCylinder Number of quads composing the cylinder. + \param tesselationCone Number of triangles composing the cone's roof. + \param height Total height of the arrow + \param cylinderHeight Total height of the cylinder, should be lesser + than total height + \param widthCylinder Diameter of the cylinder + \param widthCone Diameter of the cone's base, should be not smaller + than the cylinder's diameter + \param colorCylinder color of the cylinder + \param colorCone color of the cone + \return Generated mesh. + */ + virtual IMesh* createArrowMesh(const u32 tesselationCylinder = 4, + const u32 tesselationCone = 8, const f32 height = 1.f, + const f32 cylinderHeight = 0.6f, const f32 widthCylinder = 0.05f, + const f32 widthCone = 0.3f, const video::SColor colorCylinder = 0xFFFFFFFF, + const video::SColor colorCone = 0xFFFFFFFF) const =0; + + + //! Create a sphere 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 + \return Generated mesh. + */ + virtual IMesh* createSphereMesh(f32 radius = 5.f, + u32 polyCountX = 16, u32 polyCountY = 16) const =0; + + //! Create a cylinder mesh. + /** + \param radius Radius of the cylinder. + \param length Length of the cylinder. + \param tesselation Number of quads around the circumference of the cylinder. + \param color The color of the cylinder. + \param closeTop If true, close the ends of the cylinder, otherwise leave them open. + \param oblique X-offset (shear) of top compared to bottom. + \param normalType When 0 side normals are radial from origin. Note that origin is at the bottom. + When 1 side normals are flat along top/bottom polygons. + NOTE: To get normals which are perpendicular to the side of an oblique + cylinder, don't use the oblique parameter. Instead set normalType to 1 + and create a cylinder with oblique set to 0. Then use + IMeshManipulator::transform with a shear matrix on the returned mesh. + You get a shear matrix for an identical effect of this oblique parameter when you + set the 4th element of an identity matrix to (oblique/length). + \return Generated mesh. + */ + virtual IMesh* createCylinderMesh(f32 radius, f32 length, + u32 tesselation, + const video::SColor& color=video::SColor(0xffffffff), + bool closeTop=true, f32 oblique=0.f, u32 normalType=0) const =0; + + //! Create a cone mesh. + /** + \param radius Radius of the cone. + \param length Length of the cone. + \param tesselation Number of quads around the circumference of the cone. + \param colorTop The color of the top of the cone. + \param colorBottom The color of the bottom of the cone. + \param oblique (to be documented) + \return Generated mesh. + */ + virtual IMesh* createConeMesh(f32 radius, f32 length, u32 tesselation, + const video::SColor& colorTop=video::SColor(0xffffffff), + const video::SColor& colorBottom=video::SColor(0xffffffff), + f32 oblique=0.f) const =0; + + //! Create a volume light mesh. + /** + \param subdivideU Horizontal patch count. + \param subdivideV Vertical patch count. + \param footColor Color at the bottom of the light. + \param tailColor Color at the mid of the light. + \param lpDistance Virtual distance of the light point for normals. + \param lightDim Dimensions of the light. + \return Generated mesh. + */ + virtual IMesh* createVolumeLightMesh( + const u32 subdivideU=32, const u32 subdivideV=32, + const video::SColor footColor = 0xffffffff, + const video::SColor tailColor = 0xffffffff, + const f32 lpDistance = 8.f, + const core::vector3df& lightDim = core::vector3df(1.f,1.2f,1.f)) const =0; +}; + + +} // end namespace scene +} // end namespace irr + +#endif // __I_GEOMETRY_CREATOR_H_INCLUDED__ + diff --git a/include/IImage.h b/include/IImage.h new file mode 100644 index 00000000..0092d00c --- /dev/null +++ b/include/IImage.h @@ -0,0 +1,553 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_IMAGE_H_INCLUDED__ +#define __I_IMAGE_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "position2d.h" +#include "rect.h" +#include "SColor.h" +#include "irrAllocator.h" +#include + +namespace irr +{ +namespace video +{ + +//! Interface for software image data. +/** Image loaders create these images from files. IVideoDrivers convert +these images into their (hardware) textures. +NOTE: Floating point formats are not well supported yet. Basically only getData() works for them. +*/ +class IImage : public virtual IReferenceCounted +{ +public: + + //! constructor + IImage(ECOLOR_FORMAT format, const core::dimension2d& size, bool deleteMemory) : + Format(format), Size(size), Data(0), MipMapsData(0), BytesPerPixel(0), Pitch(0), DeleteMemory(deleteMemory), DeleteMipMapsMemory(false) + { + BytesPerPixel = getBitsPerPixelFromFormat(Format) / 8; + Pitch = BytesPerPixel * Size.Width; + } + + //! destructor + virtual ~IImage() + { + if (DeleteMemory) + delete[] Data; + + if (DeleteMipMapsMemory) + Allocator.deallocate(MipMapsData); + } + + //! Returns the color format + ECOLOR_FORMAT getColorFormat() const + { + return Format; + } + + //! Returns width and height of image data. + const core::dimension2d& getDimension() const + { + return Size; + } + + //! Returns bits per pixel. + u32 getBitsPerPixel() const + { + + return getBitsPerPixelFromFormat(Format); + } + + //! Returns bytes per pixel + u32 getBytesPerPixel() const + { + return BytesPerPixel; + } + + //! Returns image data size in bytes + u32 getImageDataSizeInBytes() const + { + return getDataSizeFromFormat(Format, Size.Width, Size.Height); + } + + //! Returns image data size in pixels + u32 getImageDataSizeInPixels() const + { + return Size.Width * Size.Height; + } + + //! Returns pitch of image + u32 getPitch() const + { + return Pitch; + } + + //! Returns mask for red value of a pixel + u32 getRedMask() const + { + switch (Format) + { + case ECF_A1R5G5B5: + return 0x1F << 10; + case ECF_R5G6B5: + return 0x1F << 11; + case ECF_R8G8B8: + return 0x00FF0000; + case ECF_A8R8G8B8: + return 0x00FF0000; + default: + return 0x0; + } + } + + //! Returns mask for green value of a pixel + u32 getGreenMask() const + { + switch (Format) + { + case ECF_A1R5G5B5: + return 0x1F << 5; + case ECF_R5G6B5: + return 0x3F << 5; + case ECF_R8G8B8: + return 0x0000FF00; + case ECF_A8R8G8B8: + return 0x0000FF00; + default: + return 0x0; + } + } + + //! Returns mask for blue value of a pixel + u32 getBlueMask() const + { + switch (Format) + { + case ECF_A1R5G5B5: + return 0x1F; + case ECF_R5G6B5: + return 0x1F; + case ECF_R8G8B8: + return 0x000000FF; + case ECF_A8R8G8B8: + return 0x000000FF; + default: + return 0x0; + } + } + + //! Returns mask for alpha value of a pixel + u32 getAlphaMask() const + { + switch (Format) + { + case ECF_A1R5G5B5: + return 0x1 << 15; + case ECF_R5G6B5: + return 0x0; + case ECF_R8G8B8: + return 0x0; + case ECF_A8R8G8B8: + return 0xFF000000; + default: + return 0x0; + } + } + + //! Use this to get a pointer to the image data. + /** + \return Pointer to the image data. What type of data is pointed to + depends on the color format of the image. For example if the color + format is ECF_A8R8G8B8, it is of u32. */ + void* getData() const + { + return Data; + } + + //! Lock function. Use this to get a pointer to the image data. + /** Use getData instead. + \return Pointer to the image data. What type of data is pointed to + depends on the color format of the image. For example if the color + format is ECF_A8R8G8B8, it is of u32. Be sure to call unlock() after + you don't need the pointer any more. */ + _IRR_DEPRECATED_ void* lock() + { + return getData(); + } + + //! Unlock function. + /** Should be called after the pointer received by lock() is not + needed anymore. */ + _IRR_DEPRECATED_ void unlock() + { + } + + //! Get the mipmap size for this image for a certain mipmap level + /** level 0 will be full image size. Every further level is half the size. + Doesn't care if the image actually has mipmaps, just which size would be needed. */ + core::dimension2du getMipMapsSize(u32 mipmapLevel) const + { + return getMipMapsSize(Size, mipmapLevel); + } + + + //! Calculate mipmap size for a certain level + /** level 0 will be full image size. Every further level is half the size. */ + static core::dimension2du getMipMapsSize(const core::dimension2du& sizeLevel0, u32 mipmapLevel) + { + core::dimension2du result(sizeLevel0); + u32 i=0; + while (i != mipmapLevel) + { + if (result.Width>1) + result.Width >>= 1; + if (result.Height>1) + result.Height>>=1; + ++i; + + if ( result.Width == 1 && result.Height == 1 && i < mipmapLevel ) + return core::dimension2du(0,0); + } + return result; + } + + + //! Get mipmaps data. + /** Note that different mip levels are just behind each other in memory block. + So if you just get level 1 you also have the data for all other levels. + There is no level 0 - use getData to get the original image data. + */ + void* getMipMapsData(irr::u32 mipLevel=1) const + { + if ( MipMapsData && mipLevel > 0) + { + size_t dataSize = 0; + core::dimension2du mipSize(Size); + u32 i = 1; // We want the start of data for this level, not end. + + while (i != mipLevel) + { + if (mipSize.Width > 1) + mipSize.Width >>= 1; + + if (mipSize.Height > 1) + mipSize.Height >>= 1; + + dataSize += getDataSizeFromFormat(Format, mipSize.Width, mipSize.Height); + + ++i; + if ( mipSize.Width == 1 && mipSize.Height == 1 && i < mipLevel) + return 0; + } + + return MipMapsData + dataSize; + } + + return 0; + } + + //! Set mipmaps data. + /** This method allows you to put custom mipmaps data for + image. + \param data A byte array with pixel color information + \param ownForeignMemory If true, the image will use the data + pointer directly and own it afterward. If false, the memory + will by copied internally. + \param deleteMemory Whether the memory is deallocated upon + destruction. */ + void setMipMapsData(void* data, bool ownForeignMemory, bool deleteMemory) + { + if (data != MipMapsData) + { + if (DeleteMipMapsMemory) + { + Allocator.deallocate(MipMapsData); + + DeleteMipMapsMemory = false; + } + + if (data) + { + if (ownForeignMemory) + { + MipMapsData = static_cast(data); + + DeleteMipMapsMemory = deleteMemory; + } + else + { + u32 dataSize = 0; + u32 width = Size.Width; + u32 height = Size.Height; + + do + { + if (width > 1) + width >>= 1; + + if (height > 1) + height >>= 1; + + dataSize += getDataSizeFromFormat(Format, width, height); + } while (width != 1 || height != 1); + + MipMapsData = Allocator.allocate(dataSize); + memcpy(MipMapsData, data, dataSize); + + DeleteMipMapsMemory = true; + } + } + else + { + MipMapsData = 0; + } + } + } + + //! Returns a pixel + virtual SColor getPixel(u32 x, u32 y) const = 0; + + //! Sets a pixel + virtual void setPixel(u32 x, u32 y, const SColor &color, bool blend = false ) = 0; + + //! Copies the image into the target, scaling the image to fit + /** NOTE: mipmaps are ignored */ + 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 + /** NOTE: mipmaps are ignored */ + virtual void copyToScaling(IImage* target) =0; + + //! copies this surface into another + /** NOTE: mipmaps are ignored */ + virtual void copyTo(IImage* target, const core::position2d& pos=core::position2d(0,0)) =0; + + //! copies this surface into another + /** NOTE: mipmaps are ignored */ + virtual void copyTo(IImage* target, const core::position2d& pos, const core::rect& sourceRect, const core::rect* clipRect=0) =0; + + //! copies this surface into another, using the alpha mask and cliprect and a color to add with + /** NOTE: mipmaps are ignored + \param combineAlpha - When true then combine alpha channels. When false replace target image alpha with source image alpha. + */ + virtual void copyToWithAlpha(IImage* target, const core::position2d& pos, + const core::rect& sourceRect, const SColor &color, + const core::rect* clipRect = 0, + bool combineAlpha=false) =0; + + //! copies this surface into another, scaling it to fit, applying a box filter + /** NOTE: mipmaps are ignored */ + virtual void copyToScalingBoxFilter(IImage* target, s32 bias = 0, bool blend = false) = 0; + + //! fills the surface with given color + virtual void fill(const SColor &color) =0; + + //! Inform whether the image is compressed + _IRR_DEPRECATED_ bool isCompressed() const + { + return IImage::isCompressedFormat(Format); + } + + //! Check whether the image has MipMaps + /** \return True if image has MipMaps, else false. */ + _IRR_DEPRECATED_ bool hasMipMaps() const + { + return (getMipMapsData() != 0); + } + + //! get the amount of Bits per Pixel of the given color format + static u32 getBitsPerPixelFromFormat(const ECOLOR_FORMAT format) + { + switch(format) + { + case ECF_A1R5G5B5: + return 16; + case ECF_R5G6B5: + return 16; + case ECF_R8G8B8: + return 24; + case ECF_A8R8G8B8: + return 32; + case ECF_DXT1: + return 16; + case ECF_DXT2: + case ECF_DXT3: + case ECF_DXT4: + case ECF_DXT5: + return 32; + case ECF_PVRTC_RGB2: + return 12; + case ECF_PVRTC_ARGB2: + case ECF_PVRTC2_ARGB2: + return 16; + case ECF_PVRTC_RGB4: + return 24; + case ECF_PVRTC_ARGB4: + case ECF_PVRTC2_ARGB4: + return 32; + case ECF_ETC1: + case ECF_ETC2_RGB: + return 24; + case ECF_ETC2_ARGB: + return 32; + case ECF_D16: + return 16; + case ECF_D32: + return 32; + case ECF_D24S8: + return 32; + case ECF_R8: + return 8; + case ECF_R8G8: + return 16; + case ECF_R16: + return 16; + case ECF_R16G16: + return 32; + case ECF_R16F: + return 16; + case ECF_G16R16F: + return 32; + case ECF_A16B16G16R16F: + return 64; + case ECF_R32F: + return 32; + case ECF_G32R32F: + return 64; + case ECF_A32B32G32R32F: + return 128; + default: + return 0; + } + } + + //! calculate image data size in bytes for selected format, width and height. + static u32 getDataSizeFromFormat(ECOLOR_FORMAT format, u32 width, u32 height) + { + u32 imageSize = 0; + + switch (format) + { + case ECF_DXT1: + imageSize = ((width + 3) / 4) * ((height + 3) / 4) * 8; + break; + case ECF_DXT2: + case ECF_DXT3: + case ECF_DXT4: + case ECF_DXT5: + imageSize = ((width + 3) / 4) * ((height + 3) / 4) * 16; + break; + case ECF_PVRTC_RGB2: + case ECF_PVRTC_ARGB2: + imageSize = (core::max_(width, 16) * core::max_(height, 8) * 2 + 7) / 8; + break; + case ECF_PVRTC_RGB4: + case ECF_PVRTC_ARGB4: + imageSize = (core::max_(width, 8) * core::max_(height, 8) * 4 + 7) / 8; + break; + case ECF_PVRTC2_ARGB2: + imageSize = core::ceil32(width / 8.0f) * core::ceil32(height / 4.0f) * 8; + break; + case ECF_PVRTC2_ARGB4: + case ECF_ETC1: + case ECF_ETC2_RGB: + imageSize = core::ceil32(width / 4.0f) * core::ceil32(height / 4.0f) * 8; + break; + case ECF_ETC2_ARGB: + imageSize = core::ceil32(width / 4.0f) * core::ceil32(height / 4.0f) * 16; + break; + default: // uncompressed formats + imageSize = getBitsPerPixelFromFormat(format) / 8 * width; + imageSize *= height; + break; + } + + return imageSize; + } + + //! check if this is compressed color format + static bool isCompressedFormat(const ECOLOR_FORMAT format) + { + switch(format) + { + case ECF_DXT1: + case ECF_DXT2: + case ECF_DXT3: + case ECF_DXT4: + case ECF_DXT5: + case ECF_PVRTC_RGB2: + case ECF_PVRTC_ARGB2: + case ECF_PVRTC2_ARGB2: + case ECF_PVRTC_RGB4: + case ECF_PVRTC_ARGB4: + case ECF_PVRTC2_ARGB4: + case ECF_ETC1: + case ECF_ETC2_RGB: + case ECF_ETC2_ARGB: + return true; + default: + return false; + } + } + + //! check if the color format is only viable for depth/stencil textures + static bool isDepthFormat(const ECOLOR_FORMAT format) + { + switch(format) + { + case ECF_D16: + case ECF_D32: + case ECF_D24S8: + return true; + default: + return false; + } + } + + //! Check if the color format uses floating point values for pixels + static bool isFloatingPointFormat(const ECOLOR_FORMAT format) + { + if (isCompressedFormat(format)) + return false; + + switch(format) + { + case ECF_R16F: + case ECF_G16R16F: + case ECF_A16B16G16R16F: + case ECF_R32F: + case ECF_G32R32F: + case ECF_A32B32G32R32F: + return true; + default: + break; + } + return false; + } + +protected: + ECOLOR_FORMAT Format; + core::dimension2d Size; + + u8* Data; + u8* MipMapsData; + + u32 BytesPerPixel; + u32 Pitch; + + bool DeleteMemory; + bool DeleteMipMapsMemory; + + core::irrAllocator Allocator; +}; + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/include/IImageLoader.h b/include/IImageLoader.h new file mode 100644 index 00000000..13eef977 --- /dev/null +++ b/include/IImageLoader.h @@ -0,0 +1,66 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_SURFACE_LOADER_H_INCLUDED__ +#define __I_SURFACE_LOADER_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "IImage.h" +#include "ITexture.h" +#include "path.h" +#include "irrArray.h" + +namespace irr +{ +namespace io +{ + class IReadFile; +} // end namespace io +namespace video +{ + +//! Class which is able to create a image from a file. +/** If you want the Irrlicht Engine be able to load textures of +currently unsupported file formats (e.g .gif), then implement +this and add your new Surface loader with +IVideoDriver::addExternalImageLoader() to the engine. */ +class IImageLoader : public virtual IReferenceCounted +{ +public: + + //! Check if the file might be loaded by this class + /** Check is based on the file extension (e.g. ".tga") + \param filename Name of file to check. + \return True if file seems to be loadable. */ + virtual bool isALoadableFileExtension(const io::path& filename) const = 0; + + //! Check if the file might be loaded by this class + /** Check might look into the file. + \param file File handle to check. + \return True if file seems to be loadable. */ + virtual bool isALoadableFileFormat(io::IReadFile* file) const = 0; + + //! Creates a surface from the file + /** \param file File handle to check. + \return Pointer to newly created image, or 0 upon error. */ + virtual IImage* loadImage(io::IReadFile* file) const = 0; + + //! Creates a multiple surfaces from the file eg. whole cube map. + /** \param file File handle to check. + \param type Pointer to E_TEXTURE_TYPE where a recommended type of the texture will be stored. + \return Array of pointers to newly created images. */ + virtual core::array loadImages(io::IReadFile* file, E_TEXTURE_TYPE* type) const + { + core::array image; + + return image; + } +}; + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/include/IImageWriter.h b/include/IImageWriter.h new file mode 100644 index 00000000..884a488e --- /dev/null +++ b/include/IImageWriter.h @@ -0,0 +1,45 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef _I_IMAGE_WRITER_H_INCLUDED__ +#define _I_IMAGE_WRITER_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "irrString.h" +#include "coreutil.h" + +namespace irr +{ +namespace io +{ + class IWriteFile; +} // end namespace io + +namespace video +{ + class IImage; + + +//! Interface for writing software image data. +class IImageWriter : public IReferenceCounted +{ +public: + //! Check if this writer can write a file with the given extension + /** \param filename Name of the file to check. + \return True if file extension specifies a writable type. */ + virtual bool isAWriteableFileExtension(const io::path& filename) const = 0; + + //! Write image to file + /** \param file File handle to write to. + \param image Image to write into file. + \param param Writer specific parameter, influencing e.g. quality. + \return True if image was successfully written. */ + virtual bool writeImage(io::IWriteFile *file, IImage *image, u32 param = 0) const = 0; +}; + +} // namespace video +} // namespace irr + +#endif // _I_IMAGE_WRITER_H_INCLUDED__ + diff --git a/include/IIndexBuffer.h b/include/IIndexBuffer.h new file mode 100644 index 00000000..5599b0fb --- /dev/null +++ b/include/IIndexBuffer.h @@ -0,0 +1,65 @@ +// Copyright (C) 2008-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_INDEX_BUFFER_H_INCLUDED__ +#define __I_INDEX_BUFFER_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "irrArray.h" + +#include "SVertexIndex.h" + +namespace irr +{ + +namespace video +{ + +} + +namespace scene +{ + + class IIndexBuffer : public virtual IReferenceCounted + { + public: + + virtual void* getData() =0; + + virtual video::E_INDEX_TYPE getType() const =0; + virtual void setType(video::E_INDEX_TYPE IndexType) =0; + + virtual u32 stride() const =0; + + virtual u32 size() const =0; + virtual void push_back (const u32 &element) =0; + virtual u32 operator [](u32 index) const =0; + virtual u32 getLast() =0; + virtual void setValue(u32 index, u32 value) =0; + virtual void set_used(u32 usedNow) =0; + virtual void reallocate(u32 new_size) =0; + virtual u32 allocated_size() const=0; + + virtual void* pointer() =0; + + //! get the current hardware mapping hint + virtual E_HARDWARE_MAPPING getHardwareMappingHint() const =0; + + //! set the hardware mapping hint, for driver + virtual void setHardwareMappingHint( E_HARDWARE_MAPPING NewMappingHint ) =0; + + //! flags the meshbuffer as changed, reloads hardware buffers + virtual void setDirty() = 0; + + //! Get the currently used ID for identification of changes. + /** This shouldn't be used for anything outside the VideoDriver. */ + virtual u32 getChangedID() const = 0; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/ILightManager.h b/include/ILightManager.h new file mode 100644 index 00000000..ff667983 --- /dev/null +++ b/include/ILightManager.h @@ -0,0 +1,62 @@ +// Written by Colin MacDonald - all rights assigned to Nikolaus Gebhardt +// Copyright (C) 2008-2012 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 lightList: 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 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 new file mode 100644 index 00000000..62533a0d --- /dev/null +++ b/include/ILightSceneNode.h @@ -0,0 +1,87 @@ +// Copyright (C) 2002-2012 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_SCENE_NODE_H_INCLUDED__ +#define __I_LIGHT_SCENE_NODE_H_INCLUDED__ + +#include "ISceneNode.h" +#include "SLight.h" + +namespace irr +{ +namespace scene +{ + +//! Scene node which is a dynamic light. +/** You can switch the light on and off by making it visible or not. It can be +animated by ordinary scene node animators. If the light type is directional or +spot, the direction of the light source is defined by the rotation of the scene +node (assuming (0,0,1) as the local direction of the light). +*/ +class ILightSceneNode : public ISceneNode +{ +public: + + //! constructor + ILightSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position = core::vector3df(0,0,0)) + : ISceneNode(parent, mgr, id, position) {} + + //! Sets the light data associated with this ILightSceneNode + /** \param light The new light data. */ + virtual void setLightData(const video::SLight& light) = 0; + + //! Gets the light data associated with this ILightSceneNode + /** \return The light data. */ + virtual const video::SLight& getLightData() const = 0; + + //! Gets the light data associated with this ILightSceneNode + /** \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 + it to (0,1/radius,0). If you want to override this behavior, set the + attenuation after the radius. + NOTE: On OpenGL only the attenuation is set, there's no hard range. + \param radius The new radius. */ + virtual void setRadius(f32 radius) = 0; + + //! Gets the light's radius of influence. + /** \return The current radius. */ + virtual f32 getRadius() const = 0; + + //! Sets the light type. + /** \param type The new type. */ + virtual void setLightType(video::E_LIGHT_TYPE type) = 0; + + //! Gets the light type. + /** \return The current light type. */ + virtual video::E_LIGHT_TYPE getLightType() const = 0; + + //! Sets whether this light casts shadows. + /** Enabling this flag won't automatically cast shadows, the meshes + will still need shadow scene nodes attached. But one can enable or + disable distinct lights for shadow casting for performance reasons. + \param shadow True if this light shall cast shadows. */ + virtual void enableCastShadow(bool shadow=true) = 0; + + //! Check whether this light casts shadows. + /** \return True if light would cast shadows, else false. */ + virtual bool getCastShadow() const = 0; +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/include/ILogger.h b/include/ILogger.h new file mode 100644 index 00000000..b6c9f6f0 --- /dev/null +++ b/include/ILogger.h @@ -0,0 +1,102 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_LOGGER_H_INCLUDED__ +#define __I_LOGGER_H_INCLUDED__ + +#include "IReferenceCounted.h" + +namespace irr +{ + +//! Possible log levels. +//! When used has filter ELL_DEBUG means => log everything and ELL_NONE means => log (nearly) nothing. +//! When used to print logging information ELL_DEBUG will have lowest priority while ELL_NONE +//! messages are never filtered and always printed. +enum ELOG_LEVEL +{ + //! Used for printing information helpful in debugging + ELL_DEBUG, + + //! Useful information to print. For example hardware infos or something started/stopped. + ELL_INFORMATION, + + //! Warnings that something isn't as expected and can cause oddities + ELL_WARNING, + + //! Something did go wrong. + ELL_ERROR, + + //! Logs with ELL_NONE will never be filtered. + //! And used as filter it will remove all logging except ELL_NONE messages. + ELL_NONE +}; + + +//! Interface for logging messages, warnings and errors +class ILogger : public virtual IReferenceCounted +{ +public: + + //! Destructor + virtual ~ILogger() {} + + //! Returns the current set log level. + virtual ELOG_LEVEL getLogLevel() const = 0; + + //! Sets a new log level. + /** With this value, texts which are sent to the logger are filtered + out. For example setting this value to ELL_WARNING, only warnings and + errors are printed out. Setting it to ELL_INFORMATION, which is the + default setting, warnings, errors and informational texts are printed + out. + \param ll: new log level filter value. */ + virtual void setLogLevel(ELOG_LEVEL ll) = 0; + + //! Prints out a text into the log + /** \param text: Text to print out. + \param ll: Log level of the text. If the text is an error, set + it to ELL_ERROR, if it is warning set it to ELL_WARNING, and if it + is just an informational text, set it to ELL_INFORMATION. Texts are + filtered with these levels. If you want to be a text displayed, + independent on what level filter is set, use ELL_NONE. */ + virtual void log(const c8* text, ELOG_LEVEL ll=ELL_INFORMATION) = 0; + + //! Prints out a text into the log + /** \param text: Text to print out. + \param hint: Additional info. This string is added after a " :" to the + string. + \param ll: Log level of the text. If the text is an error, set + it to ELL_ERROR, if it is warning set it to ELL_WARNING, and if it + is just an informational text, set it to ELL_INFORMATION. Texts are + filtered with these levels. If you want to be a text displayed, + independent on what level filter is set, use ELL_NONE. */ + virtual void log(const c8* text, const c8* hint, ELOG_LEVEL ll=ELL_INFORMATION) = 0; + virtual void log(const c8* text, const wchar_t* hint, ELOG_LEVEL ll=ELL_INFORMATION) = 0; + + //! Prints out a text into the log + /** \param text: Text to print out. + \param hint: Additional info. This string is added after a " :" to the + string. + \param ll: Log level of the text. If the text is an error, set + it to ELL_ERROR, if it is warning set it to ELL_WARNING, and if it + is just an informational text, set it to ELL_INFORMATION. Texts are + filtered with these levels. If you want to be a text displayed, + independent on what level filter is set, use ELL_NONE. */ + virtual void log(const wchar_t* text, const wchar_t* hint, ELOG_LEVEL ll=ELL_INFORMATION) = 0; + + //! Prints out a text into the log + /** \param text: Text to print out. + \param ll: Log level of the text. If the text is an error, set + it to ELL_ERROR, if it is warning set it to ELL_WARNING, and if it + is just an informational text, set it to ELL_INFORMATION. Texts are + filtered with these levels. If you want to be a text displayed, + independent on what level filter is set, use ELL_NONE. */ + virtual void log(const wchar_t* text, ELOG_LEVEL ll=ELL_INFORMATION) = 0; +}; + +} // end namespace + +#endif + diff --git a/include/IMaterialRenderer.h b/include/IMaterialRenderer.h new file mode 100644 index 00000000..f23d0284 --- /dev/null +++ b/include/IMaterialRenderer.h @@ -0,0 +1,107 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_MATERIAL_RENDERER_H_INCLUDED__ +#define __I_MATERIAL_RENDERER_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "SMaterial.h" +#include "S3DVertex.h" + +namespace irr +{ +namespace video +{ + +class IVideoDriver; +class IMaterialRendererServices; +class IShaderConstantSetCallBack; + +//! Interface for material rendering. +/** Can be used to extend the engine with new materials. Refer to +IVideoDriver::addMaterialRenderer() for more information on how to extend the +engine with new materials. */ +class IMaterialRenderer : public virtual IReferenceCounted +{ +public: + + //! Called by the IVideoDriver implementation the let the renderer set its needed render states. + /** This is called during the IVideoDriver::setMaterial() call. + When overriding this, you can set some renderstates or for example a + vertex or pixel shader if you like. + \param material: The new material parameters to be set. The renderer + may change the material flags in this material. For example if this + material does not accept the zbuffer = true, it can set it to false. + This is useful, because in the next lastMaterial will be just the + material in this call. + \param lastMaterial: The material parameters which have been set before + this material. + \param resetAllRenderstates: True if all renderstates should really be + reset. This is usually true if the last rendering mode was not a usual + 3d rendering mode, but for example a 2d rendering mode. + You should reset really all renderstates if this is true, no matter if + the lastMaterial had some similar settings. This is used because in + most cases, some common renderstates are not changed if they are + already there, for example bilinear filtering, wireframe, + gouraudshading, lighting, zbuffer, zwriteenable, backfaceculling and + fogenable. + \param services: Interface providing some methods for changing + advanced, internal states of a IVideoDriver. */ + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) {} + + //! Called every time before a new bunch of geometry is being drawn using this material with for example drawIndexedTriangleList() call. + /** OnSetMaterial should normally only be called if the renderer decides + that the renderstates should be changed, it won't be called if for + example two drawIndexedTriangleList() will be called with the same + material set. This method will be called every time. This is useful for + example for materials with shaders, which don't only set new + renderstates but also shader constants. + \param service: Pointer to interface providing methods for setting + constants and other things. + \param vtxtype: Vertex type with which the next rendering will be done. + This can be used by the material renderer to set some specific + optimized shaders or if this is an incompatible vertex type for this + renderer, to refuse rendering for example. + \return Returns true if everything is OK, and false if nothing should + be rendered. The material renderer can choose to return false for + example if he doesn't support the specified vertex type. This is + actually done in D3D9 when using a normal mapped material with + a vertex type other than EVT_TANGENTS. */ + virtual bool OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) { return true; } + + //! Called by the IVideoDriver to unset this material. + /** Called during the IVideoDriver::setMaterial() call before the new + material will get the OnSetMaterial() call. */ + virtual void OnUnsetMaterial() {} + + //! Returns if the material is transparent. + /** The scene management needs to know this + for being able to sort the materials by opaque and transparent. */ + virtual bool isTransparent() const { return false; } + + //! Returns the render capability of the material. + /** Because some more complex materials + are implemented in multiple ways and need special hardware capabilities, it is possible + to query how the current material renderer is performing on the current hardware with this + function. + \return Returns 0 if everything is running fine. Any other value is material renderer + specific and means for example that the renderer switched back to a fall back material because + it cannot use the latest shaders. More specific examples: + Fixed function pipeline materials should return 0 in most cases, parallax mapped + material will only return 0 when at least pixel shader 1.4 is available on that machine. */ + virtual s32 getRenderCapability() const { return 0; } + + //! Access the callback provided by the users when creating shader materials + /** \returns Returns either the users provided callback or 0 when no such + callback exists. Non-shader materials will always return 0. */ + virtual IShaderConstantSetCallBack* getShaderConstantSetCallBack() const { return 0; } +}; + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/include/IMaterialRendererServices.h b/include/IMaterialRendererServices.h new file mode 100644 index 00000000..0c18535f --- /dev/null +++ b/include/IMaterialRendererServices.h @@ -0,0 +1,139 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_MATERIAL_RENDERER_SERVICES_H_INCLUDED__ +#define __I_MATERIAL_RENDERER_SERVICES_H_INCLUDED__ + +#include "SMaterial.h" +#include "S3DVertex.h" + +namespace irr +{ +namespace video +{ + +class IVideoDriver; + + +//! Interface providing some methods for changing advanced, internal states of a IVideoDriver. +class IMaterialRendererServices +{ +public: + + //! Destructor + virtual ~IMaterialRendererServices() {} + + //! Can be called by an IMaterialRenderer to make its work easier. + /** Sets all basic renderstates if needed. + Basic render states are diffuse, ambient, specular, and emissive color, + specular power, bilinear and trilinear filtering, wireframe mode, + grouraudshading, lighting, zbuffer, zwriteenable, backfaceculling and + fog enabling. + \param material The new material to be used. + \param lastMaterial The material used until now. + \param resetAllRenderstates Set to true if all renderstates should be + set, regardless of their current state. */ + virtual void setBasicRenderStates(const SMaterial& material, + const SMaterial& lastMaterial, + bool resetAllRenderstates) = 0; + + //! Return an index constant for the vertex shader based on a name. + virtual s32 getVertexShaderConstantID(const c8* name) = 0; + + //! Sets a constant for the vertex shader based on a name. + /** This can be used if you used a high level shader language like GLSL + or HLSL to create a shader. Example: If you created a shader which has + variables named 'mWorldViewProj' (containing the WorldViewProjection + matrix) and another one named 'fTime' containing one float, you can set + them in your IShaderConstantSetCallBack derived class like this: + \code + virtual void OnSetConstants(video::IMaterialRendererServices* services, s32 userData) + { + video::IVideoDriver* driver = services->getVideoDriver(); + + f32 time = (f32)os::Timer::getTime()/100000.0f; + services->setVertexShaderConstant("fTime", &time, 1); + + core::matrix4 worldViewProj(driver->getTransform(video::ETS_PROJECTION)); + worldViewProj *= driver->getTransform(video::ETS_VIEW); + worldViewProj *= driver->getTransform(video::ETS_WORLD); + services->setVertexShaderConstant("mWorldViewProj", worldViewProj.M, 16); + } + \endcode + \param index Index of the variable + \param floats Pointer to array of floats + \param count Amount of floats in array. + \return True if successful. + */ + virtual bool setVertexShaderConstant(s32 index, const f32* floats, int count) = 0; + + //! Int interface for the above. + virtual bool setVertexShaderConstant(s32 index, const s32* ints, int count) = 0; + + //! Sets a vertex shader constant. + /** Can be used if you created a shader using pixel/vertex shader + assembler or ARB_fragment_program or ARB_vertex_program. + \param data: Data to be set in the constants + \param startRegister: First register to be set + \param constantAmount: Amount of registers to be set. One register consists of 4 floats. */ + virtual void setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1) = 0; + + //! Return an index constant for the pixel shader based on a name. + virtual s32 getPixelShaderConstantID(const c8* name) = 0; + + //! Sets a constant for the pixel shader based on a name. + /** This can be used if you used a high level shader language like GLSL + or HLSL to create a shader. See setVertexShaderConstant() for an + example on how to use this. + \param index Index of the variable + \param floats Pointer to array of floats + \param count Amount of floats in array. + \return True if successful. */ + virtual bool setPixelShaderConstant(s32 index, const f32* floats, int count) = 0; + + //! Int interface for the above. + virtual bool setPixelShaderConstant(s32 index, const s32* ints, int count) = 0; + + //! Sets a pixel shader constant. + /** Can be used if you created a shader using pixel/vertex shader + assembler or ARB_fragment_program or ARB_vertex_program. + \param data Data to be set in the constants + \param startRegister First register to be set. + \param constantAmount Amount of registers to be set. One register consists of 4 floats. */ + virtual void setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1) = 0; + + //! \deprecated. This method may be removed by Irrlicht 2.0 + _IRR_DEPRECATED_ bool setVertexShaderConstant(const c8* name, const f32* floats, int count) + { + return setVertexShaderConstant(getVertexShaderConstantID(name), floats, count); + } + + //! \deprecated. This method may be removed by Irrlicht 2.0 + _IRR_DEPRECATED_ bool setVertexShaderConstant(const c8* name, const s32* ints, int count) + { + return setVertexShaderConstant(getVertexShaderConstantID(name), ints, count); + } + + //! \deprecated. This method may be removed by Irrlicht 2.0 + _IRR_DEPRECATED_ bool setPixelShaderConstant(const c8* name, const f32* floats, int count) + { + return setPixelShaderConstant(getPixelShaderConstantID(name), floats, count); + } + + //! \deprecated. This method may be removed by Irrlicht 2.0 + _IRR_DEPRECATED_ bool setPixelShaderConstant(const c8* name, const s32* ints, int count) + { + return setPixelShaderConstant(getPixelShaderConstantID(name), ints, count); + } + + //! Get pointer to the IVideoDriver interface + /** \return Pointer to the IVideoDriver interface */ + virtual IVideoDriver* getVideoDriver() = 0; +}; + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/include/IMemoryReadFile.h b/include/IMemoryReadFile.h new file mode 100644 index 00000000..435cfa53 --- /dev/null +++ b/include/IMemoryReadFile.h @@ -0,0 +1,31 @@ +// Copyright Michael Zeilfelder +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_MEMORY_READ_FILE_H_INCLUDED__ +#define __I_MEMORY_READ_FILE_H_INCLUDED__ + +#include "IReadFile.h" + +namespace irr +{ +namespace io +{ + + //! Interface providing read access to a memory read file. + class IMemoryReadFile : public IReadFile + { + public: + //! Get direct access to internal buffer of memory block used as file. + /** It's usually better to use the IReadFile functions to access + the file content. But as that buffer exist over the full life-time + of a CMemoryReadFile, it's sometimes nice to avoid the additional + data-copy which read() needs. + */ + virtual const void *getBuffer() const = 0; + }; +} // end namespace io +} // end namespace irr + +#endif + diff --git a/include/IMesh.h b/include/IMesh.h new file mode 100644 index 00000000..227ef509 --- /dev/null +++ b/include/IMesh.h @@ -0,0 +1,134 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_MESH_H_INCLUDED__ +#define __I_MESH_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "SMaterial.h" +#include "EHardwareBufferFlags.h" + +namespace irr +{ +namespace scene +{ + //! Possible types of meshes. + // Note: Was previously only used in IAnimatedMesh so it still has the "animated" in the name. + // But can now be used for all mesh-types as we need those casts as well. + enum E_ANIMATED_MESH_TYPE + { + //! Unknown animated mesh type. + EAMT_UNKNOWN = 0, + + //! Quake 2 MD2 model file + EAMT_MD2, + + //! Quake 3 MD3 model file + EAMT_MD3, + + //! Maya .obj static model + EAMT_OBJ, + + //! Quake 3 .bsp static Map + EAMT_BSP, + + //! 3D Studio .3ds file + EAMT_3DS, + + //! My3D Mesh, the file format by Zhuck Dimitry + EAMT_MY3D, + + //! Pulsar LMTools .lmts file. This Irrlicht loader was written by Jonas Petersen + EAMT_LMTS, + + //! Cartography Shop .csm file. This loader was created by Saurav Mohapatra. + EAMT_CSM, + + //! .oct file for Paul Nette's FSRad or from Murphy McCauley's Blender .oct exporter. + /** The oct file format contains 3D geometry and lightmaps and + can be loaded directly by Irrlicht */ + EAMT_OCT, + + //! Halflife MDL model file + EAMT_MDL_HALFLIFE, + + //! generic skinned mesh + EAMT_SKINNED, + + //! generic non-animated mesh + EAMT_STATIC + }; + + + class IMeshBuffer; + + //! Class which holds the geometry of an object. + /** An IMesh is nothing more than a collection of some mesh buffers + (IMeshBuffer). SMesh is a simple implementation of an IMesh. + A mesh is usually added to an IMeshSceneNode in order to be rendered. + */ + class IMesh : public virtual IReferenceCounted + { + public: + + //! Get the amount of mesh buffers. + /** \return Amount of mesh buffers (IMeshBuffer) in this mesh. */ + virtual u32 getMeshBufferCount() const = 0; + + //! Get pointer to a mesh buffer. + /** \param nr: Zero based index of the mesh buffer. The maximum value is + getMeshBufferCount() - 1; + \return Pointer to the mesh buffer or 0 if there is no such + mesh buffer. */ + virtual IMeshBuffer* getMeshBuffer(u32 nr) const = 0; + + //! Get pointer to a mesh buffer which fits a material + /** \param material: material to search for + \return Pointer to the mesh buffer or 0 if there is no such + mesh buffer. */ + virtual IMeshBuffer* getMeshBuffer( const video::SMaterial &material) const = 0; + + //! Get an axis aligned bounding box of the mesh. + /** \return Bounding box of this mesh. */ + virtual const core::aabbox3d& getBoundingBox() const = 0; + + //! Set user-defined axis aligned bounding box + /** \param box New bounding box to use for the mesh. */ + virtual void setBoundingBox( const core::aabbox3df& box) = 0; + + //! Sets a flag of all contained materials to a new value. + /** \param flag: Flag to set in all materials. + \param newvalue: New value to set in all materials. */ + virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) = 0; + + //! Set the hardware mapping hint + /** This methods allows to define optimization hints for the + hardware. This enables, e.g., the use of hardware buffers on + platforms that support this feature. This can lead to noticeable + performance gains. */ + virtual void setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) = 0; + + //! Flag the meshbuffer as changed, reloads hardware buffers + /** This method has to be called every time the vertices or + indices have changed. Otherwise, changes won't be updated + on the GPU in the next render cycle. */ + virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) = 0; + + //! Returns the type of the meshes. + /** This is useful for making a safe downcast. For example, + if getMeshType() returns EAMT_MD2 it's safe to cast the + IMesh to IAnimatedMeshMD2. + Note: It's no longer just about animated meshes, that name has just historical reasons. + \returns Type of the mesh */ + virtual E_ANIMATED_MESH_TYPE getMeshType() const + { + return EAMT_STATIC; + } + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/IMeshBuffer.h b/include/IMeshBuffer.h new file mode 100644 index 00000000..488eb029 --- /dev/null +++ b/include/IMeshBuffer.h @@ -0,0 +1,184 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_MESH_BUFFER_H_INCLUDED__ +#define __I_MESH_BUFFER_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "SMaterial.h" +#include "aabbox3d.h" +#include "S3DVertex.h" +#include "SVertexIndex.h" +#include "EHardwareBufferFlags.h" +#include "EPrimitiveTypes.h" + +namespace irr +{ +namespace scene +{ + //! Struct for holding a mesh with a single material. + /** A part of an IMesh which has the same material on each face of that + group. Logical groups of an IMesh need not be put into separate mesh + buffers, but can be. Separately animated parts of the mesh must be put + into separate mesh buffers. + Some mesh buffer implementations have limitations on the number of + vertices the buffer can hold. In that case, logical grouping can help. + Moreover, the number of vertices should be optimized for the GPU upload, + which often depends on the type of gfx card. Typical figures are + 1000-10000 vertices per buffer. + SMeshBuffer is a simple implementation of a MeshBuffer, which supports + up to 65535 vertices. + + Since meshbuffers are used for drawing, and hence will be exposed + to the driver, chances are high that they are grab()'ed from somewhere. + It's therefore required to dynamically allocate meshbuffers which are + passed to a video driver and only drop the buffer once it's not used in + the current code block anymore. + */ + class IMeshBuffer : public virtual IReferenceCounted + { + public: + + //! Get the material of this meshbuffer + /** \return Material of this buffer. */ + virtual video::SMaterial& getMaterial() = 0; + + //! Get the material of this meshbuffer + /** \return Material of this buffer. */ + virtual const video::SMaterial& getMaterial() const = 0; + + //! Get type of vertex data which is stored in this meshbuffer. + /** \return Vertex type of this buffer. */ + virtual video::E_VERTEX_TYPE getVertexType() const = 0; + + //! Get access to vertex data. The data is an array of vertices. + /** Which vertex type is used can be determined by getVertexType(). + \return Pointer to array of vertices. */ + virtual const void* getVertices() const = 0; + + //! Get access to vertex data. The data is an array of vertices. + /** Which vertex type is used can be determined by getVertexType(). + \return Pointer to array of vertices. */ + virtual void* getVertices() = 0; + + //! Get amount of vertices in meshbuffer. + /** \return Number of vertices in this buffer. */ + virtual u32 getVertexCount() const = 0; + + //! Get type of index data which is stored in this meshbuffer. + /** \return Index type of this buffer. */ + virtual video::E_INDEX_TYPE getIndexType() const =0; + + //! Get access to indices. + /** \return Pointer to indices array. */ + virtual const u16* getIndices() const = 0; + + //! Get access to indices. + /** \return Pointer to indices array. */ + virtual u16* getIndices() = 0; + + //! Get amount of indices in this meshbuffer. + /** \return Number of indices in this buffer. */ + virtual u32 getIndexCount() const = 0; + + //! Get the axis aligned bounding box of this meshbuffer. + /** \return Axis aligned bounding box of this buffer. */ + virtual const core::aabbox3df& getBoundingBox() const = 0; + + //! Set axis aligned bounding box + /** \param box User defined axis aligned bounding box to use + for this buffer. */ + virtual void setBoundingBox(const core::aabbox3df& box) = 0; + + //! Recalculates the bounding box. Should be called if the mesh changed. + virtual void recalculateBoundingBox() = 0; + + //! returns position of vertex i + virtual const core::vector3df& getPosition(u32 i) const = 0; + + //! returns position of vertex i + virtual core::vector3df& getPosition(u32 i) = 0; + + //! returns normal of vertex i + virtual const core::vector3df& getNormal(u32 i) const = 0; + + //! returns normal of vertex i + virtual core::vector3df& getNormal(u32 i) = 0; + + //! returns texture coord of vertex i + virtual const core::vector2df& getTCoords(u32 i) const = 0; + + //! returns texture coord of vertex i + virtual core::vector2df& getTCoords(u32 i) = 0; + + //! Append the vertices and indices to the current buffer + /** Only works for compatible vertex types. + \param vertices Pointer to a vertex array. + \param numVertices Number of vertices in the array. + \param indices Pointer to index array. + \param numIndices Number of indices in array. */ + virtual void append(const void* const vertices, u32 numVertices, const u16* const indices, u32 numIndices) = 0; + + //! Append the meshbuffer to the current buffer + /** Only works for compatible vertex types + \param other Buffer to append to this one. */ + virtual void append(const IMeshBuffer* const other) = 0; + + //! get the current hardware mapping hint + virtual E_HARDWARE_MAPPING getHardwareMappingHint_Vertex() const = 0; + + //! get the current hardware mapping hint + virtual E_HARDWARE_MAPPING getHardwareMappingHint_Index() const = 0; + + //! set the hardware mapping hint, for driver + virtual void setHardwareMappingHint( E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX ) = 0; + + //! flags the meshbuffer as changed, reloads hardware buffers + virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) = 0; + + //! Get the currently used ID for identification of changes. + /** This shouldn't be used for anything outside the VideoDriver. */ + virtual u32 getChangedID_Vertex() const = 0; + + //! Get the currently used ID for identification of changes. + /** This shouldn't be used for anything outside the VideoDriver. */ + virtual u32 getChangedID_Index() const = 0; + + //! Describe what kind of primitive geometry is used by the meshbuffer + /** Note: Default is EPT_TRIANGLES. Using other types is fine for rendering. + But meshbuffer manipulation functions might expect type EPT_TRIANGLES + to work correctly. Also mesh writers will generally fail (badly!) with other + types than EPT_TRIANGLES. */ + virtual void setPrimitiveType(E_PRIMITIVE_TYPE type) = 0; + + //! Get the kind of primitive geometry which is used by the meshbuffer + virtual E_PRIMITIVE_TYPE getPrimitiveType() const = 0; + + //! Calculate how many geometric primitives are used by this meshbuffer + virtual u32 getPrimitiveCount() const + { + const u32 indexCount = getIndexCount(); + switch (getPrimitiveType()) + { + case scene::EPT_POINTS: return indexCount; + case scene::EPT_LINE_STRIP: return indexCount-1; + case scene::EPT_LINE_LOOP: return indexCount; + case scene::EPT_LINES: return indexCount/2; + case scene::EPT_TRIANGLE_STRIP: return (indexCount-2); + case scene::EPT_TRIANGLE_FAN: return (indexCount-2); + case scene::EPT_TRIANGLES: return indexCount/3; + case scene::EPT_QUAD_STRIP: return (indexCount-2)/2; + case scene::EPT_QUADS: return indexCount/4; + case scene::EPT_POLYGON: return indexCount; // (not really primitives, that would be 1, works like line_strip) + case scene::EPT_POINT_SPRITES: return indexCount; + } + return 0; + } + + }; + +} // end namespace scene +} // end namespace irr + +#endif diff --git a/include/IMeshCache.h b/include/IMeshCache.h new file mode 100644 index 00000000..8916d77d --- /dev/null +++ b/include/IMeshCache.h @@ -0,0 +1,177 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_MESH_CACHE_H_INCLUDED__ +#define __I_MESH_CACHE_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "path.h" + +namespace irr +{ + +namespace scene +{ + class IMesh; + class IAnimatedMesh; + class IAnimatedMeshSceneNode; + class IMeshLoader; + + //! The mesh cache stores already loaded meshes and provides an interface to them. + /** You can access it using ISceneManager::getMeshCache(). All existing + scene managers will return a pointer to the same mesh cache, because it + is shared between them. 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. */ + class IMeshCache : public virtual IReferenceCounted + { + public: + + //! Destructor + virtual ~IMeshCache() {} + + //! Adds a mesh to the internal list of loaded meshes. + /** Usually, ISceneManager::getMesh() is called to load a mesh + from a file. That method searches the list of loaded meshes if + a mesh has already been loaded and returns a pointer to if it + is in that list and already in memory. Otherwise it loads the + mesh. With IMeshCache::addMesh(), it is possible to pretend + that a mesh already has been loaded. This method can be used + for example by mesh loaders who need to load more than one mesh + with one call. They can add additional meshes with this method + to the scene manager. The COLLADA loader for example uses this + method. + \param name Name of the mesh. When calling + ISceneManager::getMesh() with this name it will return the mesh + set by this method. + \param mesh Pointer to a mesh which will now be referenced by + this name. */ + virtual void addMesh(const io::path& name, IAnimatedMesh* mesh) = 0; + + //! Removes the mesh from the cache. + /** After loading a mesh with getMesh(), the mesh can be + removed from the cache using this method, freeing a lot of + memory. + \param mesh Pointer to the mesh which shall be removed. */ + virtual void removeMesh(const IMesh* const mesh) = 0; + + //! Returns amount of loaded meshes in the cache. + /** You can load new meshes into the cache using getMesh() and + addMesh(). If you ever need to access the internal mesh cache, + you can do this using removeMesh(), getMeshNumber(), + getMeshByIndex() and getMeshName(). + \return Number of meshes in cache. */ + virtual u32 getMeshCount() const = 0; + + //! Returns current index number of the mesh or -1 when not found. + /** \param mesh Pointer to the mesh to search for. + \return Index of the mesh in the cache, or -1 if not found. */ + virtual s32 getMeshIndex(const IMesh* const mesh) const = 0; + + //! Returns a mesh based on its index number. + /** \param index: Index of the mesh, number between 0 and + getMeshCount()-1. + Note that this number is only valid until a new mesh is loaded + or removed. + \return Pointer to the mesh or 0 if there is none with this + number. */ + virtual IAnimatedMesh* getMeshByIndex(u32 index) = 0; + + //! Returns a mesh based on its name (often a filename). + /** \deprecated Use getMeshByName() instead. This method may be removed by + Irrlicht 1.9 */ + _IRR_DEPRECATED_ IAnimatedMesh* getMeshByFilename(const io::path& filename) + { + return getMeshByName(filename); + } + + //! Get the name of a loaded mesh, based on its index. (Name is often identical to the filename). + /** \deprecated Use getMeshName() instead. This method may be removed by + Irrlicht 1.9 */ + _IRR_DEPRECATED_ const io::path& getMeshFilename(u32 index) const + { + return getMeshName(index).getInternalName(); + } + + //! Get the name of a loaded mesh, if there is any. (Name is often identical to the filename). + /** \deprecated Use getMeshName() instead. This method may be removed by + Irrlicht 1.9 */ + _IRR_DEPRECATED_ const io::path& getMeshFilename(const IMesh* const mesh) const + { + return getMeshName(mesh).getInternalName(); + } + + //! Renames a loaded mesh. + /** \deprecated Use renameMesh() instead. This method may be removed by + Irrlicht 1.9 */ + _IRR_DEPRECATED_ bool setMeshFilename(u32 index, const io::path& filename) + { + return renameMesh(index, filename); + } + + //! Renames a loaded mesh. + /** \deprecated Use renameMesh() instead. This method may be removed by + Irrlicht 1.9 */ + _IRR_DEPRECATED_ bool setMeshFilename(const IMesh* const mesh, const io::path& filename) + { + return renameMesh(mesh, filename); + } + + //! Returns a mesh based on its name. + /** \param name Name of the mesh. Usually a filename. + \return Pointer to the mesh or 0 if there is none with this number. */ + virtual IAnimatedMesh* getMeshByName(const io::path& name) = 0; + + //! Get the name of a loaded mesh, based on its index. + /** \param index: Index of the mesh, number between 0 and getMeshCount()-1. + \return The name if mesh was found and has a name, else the path is empty. */ + virtual const io::SNamedPath& getMeshName(u32 index) const = 0; + + //! Get the name of the loaded mesh if there is any. + /** \param mesh Pointer to mesh to query. + \return The name if mesh was found and has a name, else the path is empty. */ + virtual const io::SNamedPath& getMeshName(const IMesh* const mesh) const = 0; + + //! Renames a loaded mesh. + /** Note that renaming meshes might change the ordering of the + meshes, and so the index of the meshes as returned by + getMeshIndex() or taken by some methods will change. + \param index The index of the mesh in the cache. + \param name New name for the mesh. + \return True if mesh was renamed. */ + virtual bool renameMesh(u32 index, const io::path& name) = 0; + + //! Renames the loaded mesh + /** Note that renaming meshes might change the ordering of the + meshes, and so the index of the meshes as returned by + getMeshIndex() or taken by some methods will change. + \param mesh Mesh to be renamed. + \param name New name for the mesh. + \return True if mesh was renamed. */ + virtual bool renameMesh(const IMesh* const mesh, const io::path& name) = 0; + + //! Check if a mesh was already loaded. + /** \param name Name of the mesh. Usually a filename. + \return True if the mesh has been loaded, else false. */ + virtual bool isMeshLoaded(const io::path& name) = 0; + + //! Clears the whole mesh cache, removing all meshes. + /** All meshes will be reloaded completely when using ISceneManager::getMesh() + after calling this method. + Warning: If you have pointers to meshes that were loaded with ISceneManager::getMesh() + and you did not grab them, then they may become invalid. */ + virtual void clear() = 0; + + //! Clears all meshes that are held in the mesh cache but not used anywhere else. + /** Warning: If you have pointers to meshes that were loaded with ISceneManager::getMesh() + and you did not grab them, then they may become invalid. */ + virtual void clearUnusedMeshes() = 0; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/IMeshLoader.h b/include/IMeshLoader.h new file mode 100644 index 00000000..f81f3307 --- /dev/null +++ b/include/IMeshLoader.h @@ -0,0 +1,89 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_MESH_LOADER_H_INCLUDED__ +#define __I_MESH_LOADER_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "path.h" +#include "IMeshTextureLoader.h" + +namespace irr +{ +namespace io +{ + class IReadFile; +} // end namespace io +namespace scene +{ + class IAnimatedMesh; + +//! Class which is able to load an animated mesh from a file. +/** If you want Irrlicht be able to load meshes of +currently unsupported file formats (e.g. .cob), then implement +this and add your new Meshloader with +ISceneManager::addExternalMeshLoader() to the engine. */ +class IMeshLoader : public virtual IReferenceCounted +{ +public: + + //! Constructor + IMeshLoader() : TextureLoader(0) {} + + //! Destructor + virtual ~IMeshLoader() + { + if ( TextureLoader ) + TextureLoader->drop(); + } + + //! Returns true if the file might be loaded by this class. + /** This decision should be based on the file extension (e.g. ".cob") + only. + \param filename Name of the file to test. + \return True if the file might be loaded by this class. */ + virtual bool isALoadableFileExtension(const io::path& filename) const = 0; + + //! Creates/loads an animated mesh from the file. + /** \param file File handler to load the file from. + \return Pointer to the created mesh. Returns 0 if loading failed. + If you no longer need the mesh, you should call IAnimatedMesh::drop(). + See IReferenceCounted::drop() for more information. */ + virtual IAnimatedMesh* createMesh(io::IReadFile* file) = 0; + + //! Set a new texture loader which this meshloader can use when searching for textures. + /** NOTE: Not all meshloaders do support this interface. Meshloaders which + support it will return a non-null value in getMeshTextureLoader from the start. Setting a + texture-loader to a meshloader which doesn't support it won't help. + \param textureLoader The textureloader to use. When set to NULL the mesh will not load any textures. + */ + virtual void setMeshTextureLoader(IMeshTextureLoader* textureLoader) + { + if ( textureLoader != TextureLoader ) + { + if ( textureLoader ) + textureLoader->grab(); + if ( TextureLoader ) + TextureLoader->drop(); + TextureLoader = textureLoader; + } + } + + //! Get the texture loader used when this meshloader searches for textures. + /** NOTE: not all meshloaders support this interface so this can return NULL. + */ + virtual IMeshTextureLoader* getMeshTextureLoader() const + { + return TextureLoader; + } + +protected: + IMeshTextureLoader* TextureLoader; +}; + + +} // end namespace scene +} // end namespace irr + +#endif diff --git a/include/IMeshManipulator.h b/include/IMeshManipulator.h new file mode 100644 index 00000000..8ff59564 --- /dev/null +++ b/include/IMeshManipulator.h @@ -0,0 +1,445 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_MESH_MANIPULATOR_H_INCLUDED__ +#define __I_MESH_MANIPULATOR_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "vector3d.h" +#include "aabbox3d.h" +#include "matrix4.h" +#include "IAnimatedMesh.h" +#include "IMeshBuffer.h" +#include "SVertexManipulator.h" + +namespace irr +{ +namespace scene +{ + + struct SMesh; + + //! An interface for easy manipulation of meshes. + /** Scale, set alpha value, flip surfaces, and so on. This exists for + fixing problems with wrong imported or exported meshes quickly after + loading. It is not intended for doing mesh modifications and/or + animations during runtime. + */ + class IMeshManipulator : public virtual IReferenceCounted + { + public: + + //! Flips the direction of surfaces. + /** Changes backfacing triangles to frontfacing + triangles and vice versa. + \param mesh Mesh on which the operation is performed. */ + virtual void flipSurfaces(IMesh* mesh) const = 0; + + //! Sets the alpha vertex color value of the whole mesh to a new value. + /** \param mesh Mesh on which the operation is performed. + \param alpha New alpha value. Must be a value between 0 and 255. */ + void setVertexColorAlpha(IMesh* mesh, s32 alpha) const + { + apply(scene::SVertexColorSetAlphaManipulator(alpha), mesh); + } + + //! Sets the alpha vertex color value of the whole mesh to a new value. + /** \param buffer Meshbuffer on which the operation is performed. + \param alpha New alpha value. Must be a value between 0 and 255. */ + void setVertexColorAlpha(IMeshBuffer* buffer, s32 alpha) const + { + apply(scene::SVertexColorSetAlphaManipulator(alpha), buffer); + } + + //! Sets the colors of all vertices to one color + /** \param mesh Mesh on which the operation is performed. + \param color New color. */ + void setVertexColors(IMesh* mesh, video::SColor color) const + { + apply(scene::SVertexColorSetManipulator(color), mesh); + } + + //! Sets the colors of all vertices to one color + /** \param buffer Meshbuffer on which the operation is performed. + \param color New color. */ + void setVertexColors(IMeshBuffer* buffer, video::SColor color) const + { + apply(scene::SVertexColorSetManipulator(color), buffer); + } + + //! Recalculates all normals of the mesh. + /** \param mesh: Mesh on which the operation is performed. + \param smooth: If the normals shall be smoothed. + \param angleWeighted: If the normals shall be smoothed in relation to their angles. More expensive, but also higher precision. */ + virtual void recalculateNormals(IMesh* mesh, bool smooth = false, + bool angleWeighted = false) const=0; + + //! Recalculates all normals of the mesh buffer. + /** \param buffer: Mesh buffer on which the operation is performed. + \param smooth: If the normals shall be smoothed. + \param angleWeighted: If the normals shall be smoothed in relation to their angles. More expensive, but also higher precision. */ + virtual void recalculateNormals(IMeshBuffer* buffer, + bool smooth = false, bool angleWeighted = false) const=0; + + //! Recalculates tangents, requires a tangent mesh + /** \param mesh Mesh on which the operation is performed. + \param recalculateNormals If the normals shall be recalculated, otherwise original normals of the mesh are used unchanged. + \param smooth If the normals shall be smoothed. + \param angleWeighted If the normals shall be smoothed in relation to their angles. More expensive, but also higher precision. + */ + virtual void recalculateTangents(IMesh* mesh, + bool recalculateNormals=false, bool smooth=false, + bool angleWeighted=false) const=0; + + //! Recalculates tangents, requires a tangent mesh buffer + /** \param buffer Meshbuffer on which the operation is performed. + \param recalculateNormals If the normals shall be recalculated, otherwise original normals of the buffer are used unchanged. + \param smooth If the normals shall be smoothed. + \param angleWeighted If the normals shall be smoothed in relation to their angles. More expensive, but also higher precision. + */ + virtual void recalculateTangents(IMeshBuffer* buffer, + bool recalculateNormals=false, bool smooth=false, + bool angleWeighted=false) const=0; + + //! Scales the actual mesh, not a scene node. + /** \param mesh Mesh on which the operation is performed. + \param factor Scale factor for each axis. */ + void scale(IMesh* mesh, const core::vector3df& factor) const + { + apply(SVertexPositionScaleManipulator(factor), mesh, true); + } + + //! Scales the actual meshbuffer, not a scene node. + /** \param buffer Meshbuffer on which the operation is performed. + \param factor Scale factor for each axis. */ + void scale(IMeshBuffer* buffer, const core::vector3df& factor) const + { + apply(SVertexPositionScaleManipulator(factor), buffer, true); + } + + //! Scales the actual mesh, not a scene node. + /** \deprecated Use scale() instead. This method may be removed by Irrlicht 1.9 + \param mesh Mesh on which the operation is performed. + \param factor Scale factor for each axis. */ + _IRR_DEPRECATED_ void scaleMesh(IMesh* mesh, const core::vector3df& factor) const {return scale(mesh,factor);} + + //! Scale the texture coords of a mesh. + /** \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. */ + void scaleTCoords(scene::IMesh* mesh, const core::vector2df& factor, u32 level=1) const + { + apply(SVertexTCoordsScaleManipulator(factor, level), mesh); + } + + //! Scale the texture coords of a meshbuffer. + /** \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. */ + void scaleTCoords(scene::IMeshBuffer* buffer, const core::vector2df& factor, u32 level=1) const + { + apply(SVertexTCoordsScaleManipulator(factor, level), buffer); + } + + //! Applies a transformation to a mesh + /** \param mesh Mesh on which the operation is performed. + \param m transformation matrix. + \param normalsUpdate When 0 - don't update normals. + When 1 - update normals with inverse transposed of the transformation matrix + */ + void transform(IMesh* mesh, const core::matrix4& m, u32 normalsUpdate = 0) const + { + apply(SVertexPositionTransformManipulator(m), mesh, true); + + if ( normalsUpdate == 1 ) + { + core::matrix4 invT; + if ( m.getInverse(invT) ) + { + invT = invT.getTransposed(); + apply(SVertexNormalTransformManipulator(invT), mesh, false); + } + } + } + + //! Applies a transformation to a meshbuffer + /** \param buffer Meshbuffer on which the operation is performed. + \param m transformation matrix. + \param normalsUpdate When 0 - don't update normals. + When 1 - update normals with inverse transposed of the transformation matrix + */ + void transform(IMeshBuffer* buffer, const core::matrix4& m, u32 normalsUpdate = 0) const + { + apply(SVertexPositionTransformManipulator(m), buffer, true); + + if ( normalsUpdate == 1 ) + { + core::matrix4 invT; + if ( m.getInverse(invT) ) + { + invT = invT.getTransposed(); + apply(SVertexNormalTransformManipulator(invT), buffer, false); + } + } + } + + //! Applies a transformation to a mesh + /** \deprecated Use transform() instead. This method may be removed by Irrlicht 1.9 + \param mesh Mesh on which the operation is performed. + \param m transformation matrix. */ + _IRR_DEPRECATED_ virtual void transformMesh(IMesh* mesh, const core::matrix4& m) const {return transform(mesh,m);} + + //! Creates a planar texture mapping on the mesh + /** \param mesh: Mesh on which the operation is performed. + \param resolution: resolution of the planar mapping. This is + the value specifying which is the relation between world space + and texture coordinate space. */ + virtual void makePlanarTextureMapping(IMesh* mesh, f32 resolution=0.001f) const=0; + + //! Creates a planar texture mapping on the meshbuffer + /** \param meshbuffer: Buffer on which the operation is performed. + \param resolution: resolution of the planar mapping. This is + the value specifying which is the relation between world space + and texture coordinate space. */ + virtual void makePlanarTextureMapping(scene::IMeshBuffer* meshbuffer, f32 resolution=0.001f) const=0; + + //! Creates a planar texture mapping on the buffer + /** This method is currently implemented towards the LWO planar mapping. A more general biasing might be required. + \param mesh Mesh on which the operation is performed. + \param resolutionS Resolution of the planar mapping in horizontal direction. This is the ratio between object space and texture space. + \param resolutionT Resolution of the planar mapping in vertical direction. This is the ratio between object space and texture space. + \param axis The axis along which the texture is projected. The allowed values are 0 (X), 1(Y), and 2(Z). + \param offset Vector added to the vertex positions (in object coordinates). + */ + virtual void makePlanarTextureMapping(scene::IMesh* mesh, + f32 resolutionS, f32 resolutionT, + u8 axis, const core::vector3df& offset) const=0; + + //! Creates a planar texture mapping on the meshbuffer + /** This method is currently implemented towards the LWO planar mapping. A more general biasing might be required. + \param buffer Buffer on which the operation is performed. + \param resolutionS Resolution of the planar mapping in horizontal direction. This is the ratio between object space and texture space. + \param resolutionT Resolution of the planar mapping in vertical direction. This is the ratio between object space and texture space. + \param axis The axis along which the texture is projected. The allowed values are 0 (X), 1(Y), and 2(Z). + \param offset Vector added to the vertex positions (in object coordinates). + */ + virtual void makePlanarTextureMapping(scene::IMeshBuffer* buffer, + f32 resolutionS, f32 resolutionT, + u8 axis, const core::vector3df& offset) const=0; + + //! 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 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; + + //! Creates a copy of the mesh, which will only consist of S3DVertexTangents vertices. + /** This is useful if you want to draw tangent space normal + mapped geometry because it calculates the tangent and binormal + data which is needed there. + \param mesh Input mesh + \param recalculateNormals The normals are recalculated if set, + otherwise the original ones are kept. Note that keeping the + normals may introduce inaccurate tangents if the normals are + very different to those calculated from the faces. + \param smooth The normals/tangents are smoothed across the + meshbuffer's faces if this flag is set. + \param angleWeighted Improved smoothing calculation used + \param recalculateTangents Whether are actually calculated, or just the mesh with proper type is created. + \return Mesh consisting only of S3DVertexTangents vertices. If + you no longer need the cloned mesh, you should call + IMesh::drop(). See IReferenceCounted::drop() for more + information. */ + virtual IMesh* createMeshWithTangents(IMesh* mesh, + bool recalculateNormals=false, bool smooth=false, + bool angleWeighted=false, bool recalculateTangents=true) const=0; + + //! Creates a copy of the mesh, which will only consist of S3DVertex2TCoord vertices. + /** \param mesh Input mesh + \return Mesh consisting only of S3DVertex2TCoord vertices. If + you no longer need the cloned mesh, you should call + IMesh::drop(). See IReferenceCounted::drop() for more + information. */ + virtual IMesh* createMeshWith2TCoords(IMesh* mesh) const = 0; + + //! Creates a copy of the mesh, which will only consist of S3DVertex vertices. + /** \param mesh Input mesh + \return Mesh consisting only of S3DVertex vertices. If + you no longer need the cloned mesh, you should call + IMesh::drop(). See IReferenceCounted::drop() for more + information. */ + virtual IMesh* createMeshWith1TCoords(IMesh* mesh) const = 0; + + //! Creates a copy of a mesh with all vertices unwelded + /** \param mesh Input mesh + \return Mesh consisting only of unique faces. All vertices + which were previously shared are now duplicated. If you no + longer need the cloned mesh, you should call IMesh::drop(). See + IReferenceCounted::drop() for more information. */ + virtual IMesh* createMeshUniquePrimitives(IMesh* mesh) const = 0; + + //! Creates a copy of a mesh with vertices welded + /** \param mesh Input mesh + \param tolerance The threshold for vertex comparisons. + \return Mesh without redundant vertices. If you no longer need + the cloned mesh, you should call IMesh::drop(). See + IReferenceCounted::drop() for more information. */ + virtual IMesh* createMeshWelded(IMesh* mesh, f32 tolerance=core::ROUNDING_ERROR_f32) const = 0; + + //! Get amount of polygons in mesh. + /** \param mesh Input mesh + \return Number of polygons in mesh. */ + virtual s32 getPolyCount(IMesh* mesh) const = 0; + + //! Get amount of polygons in mesh. + /** \param mesh Input mesh + \return Number of polygons in mesh. */ + virtual s32 getPolyCount(IAnimatedMesh* mesh) const = 0; + + //! Create a new AnimatedMesh and adds the mesh to it + /** \param mesh Input mesh + \param type The type of the animated mesh to create. + \return Newly created animated mesh with mesh as its only + content. When you don't need the animated mesh anymore, you + should call IAnimatedMesh::drop(). See + IReferenceCounted::drop() for more information. */ + virtual IAnimatedMesh * createAnimatedMesh(IMesh* mesh, + scene::E_ANIMATED_MESH_TYPE type = scene::EAMT_UNKNOWN) const = 0; + + //! Vertex cache optimization according to the Forsyth paper + /** More information can be found at + http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html + + The function is thread-safe (read: you can optimize several + meshes in different threads). + + \param mesh Source mesh for the operation. + \return A new mesh optimized for the vertex cache. */ + virtual IMesh* createForsythOptimizedMesh(const IMesh *mesh) const = 0; + + //! Optimize the mesh with an algorithm tuned for heightmaps. + /** + This differs from usual simplification methods in two ways: + - it's intended to be lossless + - it has special care for the borders, which are useful with heightmap tiles + + This function is thread-safe. Remember to weld afterwards - this + function only moves vertices, it does not weld. + + \param mesh Mesh to operate on. + */ + virtual void heightmapOptimizeMesh(IMesh * const mesh, const f32 tolerance = core::ROUNDING_ERROR_f32) const = 0; + + //! Optimize the meshbuffer with an algorithm tuned for heightmaps. + /** + This differs from usual simplification methods in two ways: + - it's intended to be lossless + - it has special care for the borders, which are useful with heightmap tiles + + This function is thread-safe. Remember to weld afterward - this + function only moves vertices, it does not weld. + + \param mb Meshbuffer to operate on. + */ + virtual void heightmapOptimizeMesh(IMeshBuffer * const mb, const f32 tolerance = core::ROUNDING_ERROR_f32) const = 0; + + //! Apply a manipulator on the Meshbuffer + /** \param func A functor defining the mesh manipulation. + \param buffer The Meshbuffer to apply the manipulator to. + \param boundingBoxUpdate Specifies if the bounding box should be updated during manipulation. + \return True if the functor was successfully applied, else false. */ + template + bool apply(const Functor& func, IMeshBuffer* buffer, bool boundingBoxUpdate=false) const + { + return apply_(func, buffer, boundingBoxUpdate, func); + } + + + //! Apply a manipulator on the Mesh + /** \param func A functor defining the mesh manipulation. + \param mesh The Mesh to apply the manipulator to. + \param boundingBoxUpdate Specifies if the bounding box should be updated during manipulation. + \return True if the functor was successfully applied, else false. */ + template + bool apply(const Functor& func, IMesh* mesh, bool boundingBoxUpdate=false) const + { + if (!mesh) + return true; + bool result = true; + core::aabbox3df bufferbox; + for (u32 i=0; igetMeshBufferCount(); ++i) + { + result &= apply(func, mesh->getMeshBuffer(i), boundingBoxUpdate); + if (boundingBoxUpdate) + { + if (0==i) + bufferbox.reset(mesh->getMeshBuffer(i)->getBoundingBox()); + else + bufferbox.addInternalBox(mesh->getMeshBuffer(i)->getBoundingBox()); + } + } + if (boundingBoxUpdate) + mesh->setBoundingBox(bufferbox); + return result; + } + +protected: + //! Apply a manipulator based on the type of the functor + /** \param func A functor defining the mesh manipulation. + \param buffer The Meshbuffer to apply the manipulator to. + \param boundingBoxUpdate Specifies if the bounding box should be updated during manipulation. + \param typeTest Unused parameter, which handles the proper call selection based on the type of the Functor which is passed in two times. + \return True if the functor was successfully applied, else false. */ + template + bool apply_(const Functor& func, IMeshBuffer* buffer, bool boundingBoxUpdate, const IVertexManipulator& typeTest) const + { + if (!buffer) + return true; + + core::aabbox3df bufferbox; + for (u32 i=0; igetVertexCount(); ++i) + { + switch (buffer->getVertexType()) + { + case video::EVT_STANDARD: + { + video::S3DVertex* verts = (video::S3DVertex*)buffer->getVertices(); + func(verts[i]); + } + break; + case video::EVT_2TCOORDS: + { + video::S3DVertex2TCoords* verts = (video::S3DVertex2TCoords*)buffer->getVertices(); + func(verts[i]); + } + break; + case video::EVT_TANGENTS: + { + video::S3DVertexTangents* verts = (video::S3DVertexTangents*)buffer->getVertices(); + func(verts[i]); + } + break; + } + if (boundingBoxUpdate) + { + if (0==i) + bufferbox.reset(buffer->getPosition(0)); + else + bufferbox.addInternalPoint(buffer->getPosition(i)); + } + } + if (boundingBoxUpdate) + buffer->setBoundingBox(bufferbox); + return true; + } +}; + +} // end namespace scene +} // end namespace irr + + +#endif diff --git a/include/IMeshSceneNode.h b/include/IMeshSceneNode.h new file mode 100644 index 00000000..03c5c522 --- /dev/null +++ b/include/IMeshSceneNode.h @@ -0,0 +1,83 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_MESH_SCENE_NODE_H_INCLUDED__ +#define __I_MESH_SCENE_NODE_H_INCLUDED__ + +#include "ISceneNode.h" + +namespace irr +{ +namespace scene +{ + +class IShadowVolumeSceneNode; +class IMesh; + + +//! A scene node displaying a static mesh +class IMeshSceneNode : public ISceneNode +{ +public: + + //! Constructor + /** Use setMesh() to set the mesh to display. + */ + IMeshSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1,1,1)) + : ISceneNode(parent, mgr, id, position, rotation, scale) {} + + //! Sets a new mesh to display + /** \param mesh Mesh to display. */ + virtual void setMesh(IMesh* mesh) = 0; + + //! Get the currently defined mesh for display. + /** \return Pointer to mesh which is displayed by this node. */ + virtual IMesh* getMesh(void) = 0; + + /** The shadow can be rendered using the ZPass or the zfail + method. ZPass is a little bit faster because the shadow volume + creation is easier, but with this method there occur ugly + looking artifacts when the camera is inside the shadow volume. + These error do not occur with the ZFail method, but it can + have trouble with clipping to the far-plane (it usually works + well in OpenGL and fails with other drivers). + \param shadowMesh: Optional custom mesh for shadow volume. + \param id: Id of the shadow scene node. This id can be used to + identify the node later. + \param zfailmethod: If set to true, the shadow will use the + zfail method, if not, zpass is used. + \param infinity: Value used by the shadow volume algorithm to + scale the shadow volume. For zfail shadow volumes on some drivers + only suppport finite shadows, so camera zfar must be larger than + shadow back cap,which is depending on the infinity parameter). + Infinity value also scales by the scaling factors of the model. + If shadows don't show up with zfail then try reducing infinity. + If shadows are cut-off then try increasing infinity. + \return Pointer to the created shadow scene node. This pointer + should not be dropped. See IReferenceCounted::drop() for more + information. */ + virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh=0, + s32 id=-1, bool zfailmethod=true, f32 infinity=1000.0f) = 0; + + //! Sets if the scene node should not copy the materials of the mesh but use them in a read only style. + /** In this way it is possible to change the materials of a mesh + causing all mesh scene nodes referencing this mesh to change, too. + \param readonly Flag if the materials shall be read-only. */ + virtual void setReadOnlyMaterials(bool readonly) = 0; + + //! Check if the scene node should not copy the materials of the mesh but use them in a read only style + /** This flag can be set by setReadOnlyMaterials(). + \return Whether the materials are read-only. */ + virtual bool isReadOnlyMaterials() const = 0; +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/include/IMeshTextureLoader.h b/include/IMeshTextureLoader.h new file mode 100644 index 00000000..92df7b0d --- /dev/null +++ b/include/IMeshTextureLoader.h @@ -0,0 +1,65 @@ +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef IRR_I_MESH_TEXTURE_LOADER_H_INCLUDED__ +#define IRR_I_MESH_TEXTURE_LOADER_H_INCLUDED__ + +#include "path.h" +#include "IReferenceCounted.h" + +namespace irr +{ + +namespace video +{ + class ITexture; +} +namespace io +{ + class IReadFile; +} + +namespace scene +{ + +//! Finding and loading textures inside meshloaders. +/** A texture loader can search for a texture in several paths. +For example relative to a given texture-path, relative to the current +working directory or relative to a mesh- and/or material-file. +*/ +class IMeshTextureLoader : public virtual IReferenceCounted +{ +public: + + //! Destructor + virtual ~IMeshTextureLoader() {} + + //! Set a custom texture path. + /** This is the first path the texture-loader should search. */ + virtual void setTexturePath(const irr::io::path& path) = 0; + + //! Get the current custom texture path. + virtual const irr::io::path& getTexturePath() const = 0; + + //! Get the texture by searching for it in all paths that makes sense for the given textureName. + /** Usually you do not have to use this method, it is used internally by IMeshLoader's. + \param textureName Texturename as used in the mesh-format + \return Pointer to the texture. Returns 0 if loading failed.*/ + virtual irr::video::ITexture* getTexture(const irr::io::path& textureName) = 0; + + //! Meshloaders will search paths relative to the meshFile. + /** Usually you do not have to use this method, it is used internally by IMeshLoader's. + Any values you set here will likely be overwritten internally. */ + virtual void setMeshFile(const irr::io::IReadFile* meshFile) = 0; + + //! Meshloaders will try to look relative to the path of the materialFile + /** Usually you do not have to use this method, it is used internally by IMeshLoader's. + Any values you set here will likely be overwritten internally. */ + virtual void setMaterialFile(const irr::io::IReadFile* materialFile) = 0; +}; + + +} // end namespace scene +} // end namespace irr + +#endif diff --git a/include/IMeshWriter.h b/include/IMeshWriter.h new file mode 100644 index 00000000..8394c922 --- /dev/null +++ b/include/IMeshWriter.h @@ -0,0 +1,58 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_I_MESH_WRITER_H_INCLUDED__ +#define __IRR_I_MESH_WRITER_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "EMeshWriterEnums.h" + +namespace irr +{ +namespace io +{ + class IWriteFile; +} // end namespace io + +namespace scene +{ + class IMesh; + + //! Interface for writing meshes + class IMeshWriter : public virtual IReferenceCounted + { + public: + + //! Destructor + virtual ~IMeshWriter() {} + + //! Get the type of the mesh writer + /** For own implementations, use MAKE_IRR_ID as shown in the + EMESH_WRITER_TYPE enumeration to return your own unique mesh + type id. + \return Type of the mesh writer. */ + virtual EMESH_WRITER_TYPE getType() const = 0; + + //! Write a static mesh. + /** \param file File handle to write the mesh to. + \param mesh Pointer to mesh to be written. + \param flags Optional flags to set properties of the writer. + \return True if successful */ + virtual bool writeMesh(io::IWriteFile* file, scene::IMesh* mesh, + s32 flags=EMWF_NONE) = 0; + + // Writes an animated mesh + // for future use, only b3d writer is able to write animated meshes currently and that was implemented using the writeMesh above. + /* \return Returns true if successful */ + //virtual bool writeAnimatedMesh(io::IWriteFile* file, + // scene::IAnimatedMesh* mesh, + // s32 flags=EMWF_NONE) = 0; + }; + + +} // end namespace +} // end namespace + +#endif + diff --git a/include/IMetaTriangleSelector.h b/include/IMetaTriangleSelector.h new file mode 100644 index 00000000..2cbb385c --- /dev/null +++ b/include/IMetaTriangleSelector.h @@ -0,0 +1,43 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_META_TRIANGLE_SELECTOR_H_INCLUDED__ +#define __I_META_TRIANGLE_SELECTOR_H_INCLUDED__ + +#include "ITriangleSelector.h" + +namespace irr +{ +namespace scene +{ + +//! Interface for making multiple triangle selectors work as one big selector. +/** This 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. +*/ +class IMetaTriangleSelector : public ITriangleSelector +{ +public: + + //! Adds a triangle selector to the collection of triangle selectors. + /** \param toAdd: Pointer to an triangle selector to add to the list. */ + virtual void addTriangleSelector(ITriangleSelector* toAdd) = 0; + + //! Removes a specific triangle selector from the collection. + /** \param toRemove: Pointer to an triangle selector which is in the + list but will be removed. + \return True if successful, false if not. */ + virtual bool removeTriangleSelector(ITriangleSelector* toRemove) = 0; + + //! Removes all triangle selectors from the collection. + virtual void removeAllTriangleSelectors() = 0; +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/include/IOSOperator.h b/include/IOSOperator.h new file mode 100644 index 00000000..eeb1856d --- /dev/null +++ b/include/IOSOperator.h @@ -0,0 +1,50 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_OS_OPERATOR_H_INCLUDED__ +#define __I_OS_OPERATOR_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "irrString.h" + +namespace irr +{ + +//! The Operating system operator provides operation system specific methods and information. +class IOSOperator : public virtual IReferenceCounted +{ +public: + //! Get the current operation system version as string. + virtual const core::stringc& getOperatingSystemVersion() const = 0; + + //! Get the current operation system version as string. + /** \deprecated Use getOperatingSystemVersion instead. This method will be removed in Irrlicht 1.9. */ + _IRR_DEPRECATED_ const wchar_t* getOperationSystemVersion() const + { + return core::stringw(getOperatingSystemVersion()).c_str(); + } + + //! Copies text to the clipboard + virtual void copyToClipboard(const c8* text) const = 0; + + //! Get text from the clipboard + /** \return Returns 0 if no string is in there. */ + virtual const c8* getTextFromClipboard() const = 0; + + //! Get the processor speed in megahertz + /** \param MHz The integer variable to store the speed in. + \return True if successful, false if not */ + virtual bool getProcessorSpeedMHz(u32* MHz) const = 0; + + //! Get the total and available system RAM + /** \param totalBytes: will contain the total system memory in bytes + \param availableBytes: will contain the available memory in bytes + \return True if successful, false if not */ + virtual bool getSystemMemory(u32* totalBytes, u32* availableBytes) const = 0; + +}; + +} // end namespace + +#endif diff --git a/include/IOctreeSceneNode.h b/include/IOctreeSceneNode.h new file mode 100644 index 00000000..352a274a --- /dev/null +++ b/include/IOctreeSceneNode.h @@ -0,0 +1,83 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_OCTREE_SCENE_NODE_H_INCLUDED__ +#define __I_OCTREE_SCENE_NODE_H_INCLUDED__ + +#include "IMeshSceneNode.h" + +namespace irr +{ +namespace scene +{ + +//! Settings if/how octree scene nodes are using hardware mesh-buffers +/** VBO = Vertex buffer object = meshbuffers bound on the graphic-card instead of uploaded each frame. + It can not be generally said which mode is optimal for drawing as this depends + on the scene. So you have to try and experiment for your meshes which one works best. +*/ +enum EOCTREENODE_VBO +{ + //! No VBO's used. Vertices+indices send to graphic-card on each render. + EOV_NO_VBO, + + //! VBO's used. Draw the complete meshbuffers if any polygon in it is visible. + //! This allows VBO's for the meshbuffers to be completely static, but basically means + //! the octree is not used as an octree (not it still does do all the octree calculations) + //! Might work in very specific cases, but if this is gives you the best fastest results + //! you should probably compare as well to simply using a static mesh with no octree at all. + //! In most cases the other 2 options should work better with an octree. + EOV_USE_VBO, + + //! VBO's used. The index-buffer information is updated each frame + //! with only the visible parts of a tree-node. + //! So the vertex-buffer is static and the index-buffer is dynamic. + //! This is the default + EOV_USE_VBO_WITH_VISIBITLY +}; + +//! Kind of checks polygons of the octree scene nodes use against camera +enum EOCTREE_POLYGON_CHECKS +{ + //! Check against box of the camera frustum + //! This is the default + EOPC_BOX, + + //! against the camera frustum + EOPC_FRUSTUM + +}; + +//! A scene node displaying a static mesh +class IOctreeSceneNode : public irr::scene::IMeshSceneNode +{ +public: + + //! Constructor + /** Use setMesh() to set the mesh to display. + */ + IOctreeSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1,1,1)) + : IMeshSceneNode(parent, mgr, id, position, rotation, scale) {} + + //! Get if/how vertex buffer object are used for the meshbuffers + // NOTE: Will currently _always_ return EOV_NO_VBO. + // Octree's with VBO's don't work yet correctly. + virtual EOCTREENODE_VBO getUseVBO() const = 0; + + //! Set the kind of tests polygons do for visibility against the camera + virtual void setPolygonChecks(EOCTREE_POLYGON_CHECKS checks) = 0; + + //! Get the kind of tests polygons do for visibility against the camera + virtual EOCTREE_POLYGON_CHECKS getPolygonChecks() const = 0; +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/include/IParticleAffector.h b/include/IParticleAffector.h new file mode 100644 index 00000000..e2b83e8f --- /dev/null +++ b/include/IParticleAffector.h @@ -0,0 +1,72 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_AFFECTOR_H_INCLUDED__ +#define __I_PARTICLE_AFFECTOR_H_INCLUDED__ + +#include "IAttributeExchangingObject.h" +#include "SParticle.h" + +namespace irr +{ +namespace scene +{ + +//! Types of built in particle affectors +enum E_PARTICLE_AFFECTOR_TYPE +{ + EPAT_NONE = 0, + EPAT_ATTRACT, + EPAT_FADE_OUT, + EPAT_GRAVITY, + EPAT_ROTATE, + EPAT_SCALE, + EPAT_COUNT +}; + +//! Names for built in particle affectors +const c8* const ParticleAffectorTypeNames[] = +{ + "None", + "Attract", + "FadeOut", + "Gravity", + "Rotate", + "Scale", + 0 +}; + +//! A particle affector modifies particles. +class IParticleAffector : public virtual io::IAttributeExchangingObject +{ +public: + + //! constructor + IParticleAffector() : Enabled(true) {} + + //! Affects an array of particles. + /** \param now Current time. (Same as ITimer::getTime() would return) + \param particlearray Array of particles. + \param count Amount of particles in array. */ + virtual void affect(u32 now, SParticle* particlearray, u32 count) = 0; + + //! Sets whether or not the affector is currently enabled. + virtual void setEnabled(bool enabled) { Enabled = enabled; } + + //! Gets whether or not the affector is currently enabled. + virtual bool getEnabled() const { return Enabled; } + + //! Get emitter type + virtual E_PARTICLE_AFFECTOR_TYPE getType() const = 0; + +protected: + bool Enabled; +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/include/IParticleAnimatedMeshSceneNodeEmitter.h b/include/IParticleAnimatedMeshSceneNodeEmitter.h new file mode 100644 index 00000000..0e0646f2 --- /dev/null +++ b/include/IParticleAnimatedMeshSceneNodeEmitter.h @@ -0,0 +1,54 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_ANIMATED_MESH_SCENE_NODE_EMITTER_H_INCLUDED__ +#define __I_PARTICLE_ANIMATED_MESH_SCENE_NODE_EMITTER_H_INCLUDED__ + +#include "IParticleEmitter.h" +#include "IAnimatedMeshSceneNode.h" + +namespace irr +{ +namespace scene +{ + +//! A particle emitter which emits particles from mesh vertices. +class IParticleAnimatedMeshSceneNodeEmitter : public IParticleEmitter +{ +public: + + //! Set Mesh to emit particles from + virtual void setAnimatedMeshSceneNode( IAnimatedMeshSceneNode* node ) = 0; + + //! Set whether to use vertex normal for direction, or direction specified + virtual void setUseNormalDirection( bool useNormalDirection = true ) = 0; + + //! Set the amount that the normal is divided by for getting a particles direction + virtual void setNormalDirectionModifier( f32 normalDirectionModifier ) = 0; + + //! Sets whether to emit min<->max particles for every vertex or to pick min<->max vertices + virtual void setEveryMeshVertex( bool everyMeshVertex = true ) = 0; + + //! Get mesh we're emitting particles from + virtual const IAnimatedMeshSceneNode* getAnimatedMeshSceneNode() const = 0; + + //! Get whether to use vertex normal for direction, or direction specified + virtual bool isUsingNormalDirection() const = 0; + + //! Get the amount that the normal is divided by for getting a particles direction + virtual f32 getNormalDirectionModifier() const = 0; + + //! Gets whether to emit min<->max particles for every vertex or to pick min<->max vertices + virtual bool getEveryMeshVertex() const = 0; + + //! Get emitter type + virtual E_PARTICLE_EMITTER_TYPE getType() const _IRR_OVERRIDE_ { return EPET_ANIMATED_MESH; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif // __I_PARTICLE_ANIMATED_MESH_SCENE_NODE_EMITTER_H_INCLUDED__ + diff --git a/include/IParticleAttractionAffector.h b/include/IParticleAttractionAffector.h new file mode 100644 index 00000000..e858f8ac --- /dev/null +++ b/include/IParticleAttractionAffector.h @@ -0,0 +1,65 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_ATTRACTION_AFFECTOR_H_INCLUDED__ +#define __I_PARTICLE_ATTRACTION_AFFECTOR_H_INCLUDED__ + +#include "IParticleAffector.h" + +namespace irr +{ +namespace scene +{ + +//! A particle affector which attracts or detracts particles. +class IParticleAttractionAffector : public IParticleAffector +{ +public: + + //! Set the point that particles will attract to + virtual void setPoint( const core::vector3df& point ) = 0; + + //! Set the speed, in game units per second that the particles will attract to the specified point + virtual void setSpeed( f32 speed ) =0; + + //! Set whether or not the particles are attracting or detracting + virtual void setAttract( bool attract ) = 0; + + //! Set whether or not this will affect particles in the X direction + virtual void setAffectX( bool affect ) = 0; + + //! Set whether or not this will affect particles in the Y direction + virtual void setAffectY( bool affect ) = 0; + + //! Set whether or not this will affect particles in the Z direction + virtual void setAffectZ( bool affect ) = 0; + + //! Get the point that particles are attracted to + virtual const core::vector3df& getPoint() const = 0; + + //! Get the speed that points attract to the specified point + virtual f32 getSpeed() const =0; + + //! Get whether or not the particles are attracting or detracting + virtual bool getAttract() const = 0; + + //! Get whether or not the particles X position are affected + virtual bool getAffectX() const = 0; + + //! Get whether or not the particles Y position are affected + virtual bool getAffectY() const = 0; + + //! Get whether or not the particles Z position are affected + virtual bool getAffectZ() const = 0; + + //! Get emitter type + virtual E_PARTICLE_AFFECTOR_TYPE getType() const _IRR_OVERRIDE_ { return EPAT_ATTRACT; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif // __I_PARTICLE_ATTRACTION_AFFECTOR_H_INCLUDED__ + diff --git a/include/IParticleBoxEmitter.h b/include/IParticleBoxEmitter.h new file mode 100644 index 00000000..10790bf8 --- /dev/null +++ b/include/IParticleBoxEmitter.h @@ -0,0 +1,36 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_BOX_EMITTER_H_INCLUDED__ +#define __I_PARTICLE_BOX_EMITTER_H_INCLUDED__ + +#include "IParticleEmitter.h" +#include "aabbox3d.h" + +namespace irr +{ +namespace scene +{ + +//! A particle emitter which emits particles from a box shaped space +class IParticleBoxEmitter : public IParticleEmitter +{ +public: + + //! Set the box shape + virtual void setBox( const core::aabbox3df& box ) = 0; + + //! Get the box shape set + virtual const core::aabbox3df& getBox() const = 0; + + //! Get emitter type + virtual E_PARTICLE_EMITTER_TYPE getType() const _IRR_OVERRIDE_ { return EPET_BOX; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/include/IParticleCylinderEmitter.h b/include/IParticleCylinderEmitter.h new file mode 100644 index 00000000..ca42defe --- /dev/null +++ b/include/IParticleCylinderEmitter.h @@ -0,0 +1,59 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_CYLINDER_EMITTER_H_INCLUDED__ +#define __I_PARTICLE_CYLINDER_EMITTER_H_INCLUDED__ + +#include "IParticleEmitter.h" + +namespace irr +{ +namespace scene +{ + +//! A particle emitter which emits from a cylindrically shaped space. +class IParticleCylinderEmitter : public IParticleEmitter +{ +public: + + //! Set the center of the radius for the cylinder, at one end of the cylinder + virtual void setCenter( const core::vector3df& center ) = 0; + + //! Set the normal of the cylinder + virtual void setNormal( const core::vector3df& normal ) = 0; + + //! Set the radius of the cylinder + virtual void setRadius( f32 radius ) = 0; + + //! Set the length of the cylinder + virtual void setLength( f32 length ) = 0; + + //! Set whether or not to draw points inside the cylinder + virtual void setOutlineOnly( bool outlineOnly = true ) = 0; + + //! Get the center of the cylinder + virtual const core::vector3df& getCenter() const = 0; + + //! Get the normal of the cylinder + virtual const core::vector3df& getNormal() const = 0; + + //! Get the radius of the cylinder + virtual f32 getRadius() const = 0; + + //! Get the center of the cylinder + virtual f32 getLength() const = 0; + + //! Get whether or not to draw points inside the cylinder + virtual bool getOutlineOnly() const = 0; + + //! Get emitter type + virtual E_PARTICLE_EMITTER_TYPE getType() const _IRR_OVERRIDE_ { return EPET_CYLINDER; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/include/IParticleEmitter.h b/include/IParticleEmitter.h new file mode 100644 index 00000000..4e54e85d --- /dev/null +++ b/include/IParticleEmitter.h @@ -0,0 +1,128 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_EMITTER_H_INCLUDED__ +#define __I_PARTICLE_EMITTER_H_INCLUDED__ + +#include "IAttributeExchangingObject.h" +#include "SParticle.h" + +namespace irr +{ +namespace scene +{ + +//! Types of built in particle emitters +enum E_PARTICLE_EMITTER_TYPE +{ + EPET_POINT = 0, + EPET_ANIMATED_MESH, + EPET_BOX, + EPET_CYLINDER, + EPET_MESH, + EPET_RING, + EPET_SPHERE, + EPET_COUNT +}; + +//! Names for built in particle emitters +const c8* const ParticleEmitterTypeNames[] = +{ + "Point", + "AnimatedMesh", + "Box", + "Cylinder", + "Mesh", + "Ring", + "Sphere", + 0 +}; + +//! A particle emitter for using with particle systems. +/** A Particle emitter emits new particles into a particle system. +*/ +class IParticleEmitter : public virtual io::IAttributeExchangingObject +{ +public: + + //! Prepares an array with new particles to emit into the system + /** \param now Current time. + \param timeSinceLastCall Time elapsed since last call, in milliseconds. + \param outArray Pointer which will point to the array with the new + particles to add into the system. + \return Amount of new particles in the array. Can be 0. */ + virtual s32 emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray) = 0; + + //! Set direction the emitter emits particles + virtual void setDirection( const core::vector3df& newDirection ) = 0; + + //! Set minimum number of particles the emitter emits per second + virtual void setMinParticlesPerSecond( u32 minPPS ) = 0; + + //! Set maximum number of particles the emitter emits per second + virtual void setMaxParticlesPerSecond( u32 maxPPS ) = 0; + + //! Set minimum starting color for particles + virtual void setMinStartColor( const video::SColor& color ) = 0; + + //! Set maximum starting color for particles + virtual void setMaxStartColor( const video::SColor& color ) = 0; + + //! Set the maximum starting size for particles + virtual void setMaxStartSize( const core::dimension2df& size ) = 0; + + //! Set the minimum starting size for particles + virtual void setMinStartSize( const core::dimension2df& size ) = 0; + + //! Set the minimum particle life-time in milliseconds + virtual void setMinLifeTime( u32 lifeTimeMin ) = 0; + + //! Set the maximum particle life-time in milliseconds + virtual void setMaxLifeTime( u32 lifeTimeMax ) = 0; + + //! Set maximal random derivation from the direction + virtual void setMaxAngleDegrees( s32 maxAngleDegrees ) = 0; + + //! Get direction the emitter emits particles + virtual const core::vector3df& getDirection() const = 0; + + //! Get the minimum number of particles the emitter emits per second + virtual u32 getMinParticlesPerSecond() const = 0; + + //! Get the maximum number of particles the emitter emits per second + virtual u32 getMaxParticlesPerSecond() const = 0; + + //! Get the minimum starting color for particles + virtual const video::SColor& getMinStartColor() const = 0; + + //! Get the maximum starting color for particles + virtual const video::SColor& getMaxStartColor() const = 0; + + //! Get the maximum starting size for particles + virtual const core::dimension2df& getMaxStartSize() const = 0; + + //! Get the minimum starting size for particles + virtual const core::dimension2df& getMinStartSize() const = 0; + + //! Get the minimum particle life-time in milliseconds + virtual u32 getMinLifeTime() const = 0; + + //! Get the maximum particle life-time in milliseconds + virtual u32 getMaxLifeTime() const = 0; + + //! Get maximal random derivation from the direction + virtual s32 getMaxAngleDegrees() const = 0; + + //! Get emitter type + virtual E_PARTICLE_EMITTER_TYPE getType() const { return EPET_POINT; } +}; + +typedef IParticleEmitter IParticlePointEmitter; + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/include/IParticleFadeOutAffector.h b/include/IParticleFadeOutAffector.h new file mode 100644 index 00000000..67000c0b --- /dev/null +++ b/include/IParticleFadeOutAffector.h @@ -0,0 +1,41 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_FADE_OUT_AFFECTOR_H_INCLUDED__ +#define __I_PARTICLE_FADE_OUT_AFFECTOR_H_INCLUDED__ + +#include "IParticleAffector.h" + +namespace irr +{ +namespace scene +{ + +//! A particle affector which fades out the particles. +class IParticleFadeOutAffector : public IParticleAffector +{ +public: + + //! Sets the targetColor, i.e. the color the particles will interpolate to over time. + virtual void setTargetColor( const video::SColor& targetColor ) = 0; + + //! Sets the time in milliseconds it takes for each particle to fade out (minimal 1 ms) + virtual void setFadeOutTime( u32 fadeOutTime ) = 0; + + //! Gets the targetColor, i.e. the color the particles will interpolate to over time. + virtual const video::SColor& getTargetColor() const = 0; + + //! Gets the time in milliseconds it takes for each particle to fade out. + virtual u32 getFadeOutTime() const = 0; + + //! Get emitter type + virtual E_PARTICLE_AFFECTOR_TYPE getType() const _IRR_OVERRIDE_ { return EPAT_FADE_OUT; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif // __I_PARTICLE_FADE_OUT_AFFECTOR_H_INCLUDED__ + diff --git a/include/IParticleGravityAffector.h b/include/IParticleGravityAffector.h new file mode 100644 index 00000000..be2c244b --- /dev/null +++ b/include/IParticleGravityAffector.h @@ -0,0 +1,42 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_GRAVITY_AFFECTOR_H_INCLUDED__ +#define __I_PARTICLE_GRAVITY_AFFECTOR_H_INCLUDED__ + +#include "IParticleAffector.h" + +namespace irr +{ +namespace scene +{ + +//! A particle affector which applies gravity to particles. +class IParticleGravityAffector : public IParticleAffector +{ +public: + + //! Set the time in milliseconds when the gravity force is totally lost + /** At that point the particle does not move any more. */ + virtual void setTimeForceLost( f32 timeForceLost ) = 0; + + //! Set the direction and force of gravity in all 3 dimensions. + virtual void setGravity( const core::vector3df& gravity ) = 0; + + //! Get the time in milliseconds when the gravity force is totally lost + virtual f32 getTimeForceLost() const = 0; + + //! Get the direction and force of gravity. + virtual const core::vector3df& getGravity() const = 0; + + //! Get emitter type + virtual E_PARTICLE_AFFECTOR_TYPE getType() const _IRR_OVERRIDE_ { return EPAT_GRAVITY; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif // __I_PARTICLE_GRAVITY_AFFECTOR_H_INCLUDED__ + diff --git a/include/IParticleMeshEmitter.h b/include/IParticleMeshEmitter.h new file mode 100644 index 00000000..7f078064 --- /dev/null +++ b/include/IParticleMeshEmitter.h @@ -0,0 +1,54 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_MESH_EMITTER_H_INCLUDED__ +#define __I_PARTICLE_MESH_EMITTER_H_INCLUDED__ + +#include "IParticleEmitter.h" +#include "IMesh.h" + +namespace irr +{ +namespace scene +{ + +//! A particle emitter which emits from vertices of a mesh +class IParticleMeshEmitter : public IParticleEmitter +{ +public: + + //! Set Mesh to emit particles from + virtual void setMesh( IMesh* mesh ) = 0; + + //! Set whether to use vertex normal for direction, or direction specified + virtual void setUseNormalDirection( bool useNormalDirection = true ) = 0; + + //! Set the amount that the normal is divided by for getting a particles direction + virtual void setNormalDirectionModifier( f32 normalDirectionModifier ) = 0; + + //! Sets whether to emit min<->max particles for every vertex or to pick min<->max vertices + virtual void setEveryMeshVertex( bool everyMeshVertex = true ) = 0; + + //! Get Mesh we're emitting particles from + virtual const IMesh* getMesh() const = 0; + + //! Get whether to use vertex normal for direction, or direction specified + virtual bool isUsingNormalDirection() const = 0; + + //! Get the amount that the normal is divided by for getting a particles direction + virtual f32 getNormalDirectionModifier() const = 0; + + //! Gets whether to emit min<->max particles for every vertex or to pick min<->max vertices + virtual bool getEveryMeshVertex() const = 0; + + //! Get emitter type + virtual E_PARTICLE_EMITTER_TYPE getType() const _IRR_OVERRIDE_ { return EPET_MESH; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/include/IParticleRingEmitter.h b/include/IParticleRingEmitter.h new file mode 100644 index 00000000..7828b898 --- /dev/null +++ b/include/IParticleRingEmitter.h @@ -0,0 +1,47 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_RING_EMITTER_H_INCLUDED__ +#define __I_PARTICLE_RING_EMITTER_H_INCLUDED__ + +#include "IParticleEmitter.h" + +namespace irr +{ +namespace scene +{ + +//! A particle emitter which emits particles along a ring shaped area. +class IParticleRingEmitter : public IParticleEmitter +{ +public: + + //! Set the center of the ring + virtual void setCenter( const core::vector3df& center ) = 0; + + //! Set the radius of the ring + virtual void setRadius( f32 radius ) = 0; + + //! Set the thickness of the ring + virtual void setRingThickness( f32 ringThickness ) = 0; + + //! Get the center of the ring + virtual const core::vector3df& getCenter() const = 0; + + //! Get the radius of the ring + virtual f32 getRadius() const = 0; + + //! Get the thickness of the ring + virtual f32 getRingThickness() const = 0; + + //! Get emitter type + virtual E_PARTICLE_EMITTER_TYPE getType() const _IRR_OVERRIDE_ { return EPET_RING; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/include/IParticleRotationAffector.h b/include/IParticleRotationAffector.h new file mode 100644 index 00000000..374a2682 --- /dev/null +++ b/include/IParticleRotationAffector.h @@ -0,0 +1,41 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_ROTATION_AFFECTOR_H_INCLUDED__ +#define __I_PARTICLE_ROTATION_AFFECTOR_H_INCLUDED__ + +#include "IParticleAffector.h" + +namespace irr +{ +namespace scene +{ + +//! A particle affector which rotates the particle system. +class IParticleRotationAffector : public IParticleAffector +{ +public: + + //! Set the point that particles will rotate around + virtual void setPivotPoint( const core::vector3df& point ) = 0; + + //! Set the speed in degrees per second in all 3 dimensions + virtual void setSpeed( const core::vector3df& speed ) = 0; + + //! Get the point that particles are attracted to + virtual const core::vector3df& getPivotPoint() const = 0; + + //! Get the speed in degrees per second in all 3 dimensions + virtual const core::vector3df& getSpeed() const = 0; + + //! Get emitter type + virtual E_PARTICLE_AFFECTOR_TYPE getType() const _IRR_OVERRIDE_ { return EPAT_ROTATE; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif // __I_PARTICLE_ROTATION_AFFECTOR_H_INCLUDED__ + diff --git a/include/IParticleSphereEmitter.h b/include/IParticleSphereEmitter.h new file mode 100644 index 00000000..1bfe98c3 --- /dev/null +++ b/include/IParticleSphereEmitter.h @@ -0,0 +1,41 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_SPHERE_EMITTER_H_INCLUDED__ +#define __I_PARTICLE_SPHERE_EMITTER_H_INCLUDED__ + +#include "IParticleEmitter.h" + +namespace irr +{ +namespace scene +{ + +//! A particle emitter which emits from a spherical space. +class IParticleSphereEmitter : public IParticleEmitter +{ +public: + + //! Set the center of the sphere for particle emissions + virtual void setCenter( const core::vector3df& center ) = 0; + + //! Set the radius of the sphere for particle emissions + virtual void setRadius( f32 radius ) = 0; + + //! Get the center of the sphere for particle emissions + virtual const core::vector3df& getCenter() const = 0; + + //! Get the radius of the sphere for particle emissions + virtual f32 getRadius() const = 0; + + //! Get emitter type + virtual E_PARTICLE_EMITTER_TYPE getType() const _IRR_OVERRIDE_ { return EPET_SPHERE; } +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/include/IParticleSystemSceneNode.h b/include/IParticleSystemSceneNode.h new file mode 100644 index 00000000..b124cbc5 --- /dev/null +++ b/include/IParticleSystemSceneNode.h @@ -0,0 +1,572 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_PARTICLE_SYSTEM_SCENE_NODE_H_INCLUDED__ +#define __I_PARTICLE_SYSTEM_SCENE_NODE_H_INCLUDED__ + +#include "ISceneNode.h" +#include "IParticleAnimatedMeshSceneNodeEmitter.h" +#include "IParticleBoxEmitter.h" +#include "IParticleCylinderEmitter.h" +#include "IParticleMeshEmitter.h" +#include "IParticleRingEmitter.h" +#include "IParticleSphereEmitter.h" +#include "IParticleAttractionAffector.h" +#include "IParticleFadeOutAffector.h" +#include "IParticleGravityAffector.h" +#include "IParticleRotationAffector.h" +#include "dimension2d.h" + +namespace irr +{ +namespace scene +{ + +//! A particle system scene node for creating snow, fire, explosions, smoke... +/** A scene node controlling a particle System. The behavior of the particles +can be controlled by setting the right particle emitters and affectors. +You can for example easily create a campfire by doing this: + +\code + scene::IParticleSystemSceneNode* p = scenemgr->addParticleSystemSceneNode(); + p->setParticleSize(core::dimension2d(20.0f, 10.0f)); + scene::IParticleEmitter* em = p->createBoxEmitter( + core::aabbox3d(-5,0,-5,5,1,5), + core::vector3df(0.0f,0.03f,0.0f), + 40,80, video::SColor(0,255,255,255),video::SColor(0,255,255,255), 1100,2000); + p->setEmitter(em); + em->drop(); + scene::IParticleAffector* paf = p->createFadeOutParticleAffector(); + p->addAffector(paf); + paf->drop(); +\endcode +*/ + +//! Bitflags to control particle behavior +enum EParticleBehavior +{ + //! Continue emitting new particles even when the node is invisible + EPB_INVISIBLE_EMITTING = 1, + + //! Continue affecting particles even when the node is invisible + EPB_INVISIBLE_AFFECTING = 2, + + //! Continue updating particle positions or deleting them even when the node is invisible + EPB_INVISIBLE_ANIMATING = 4, + + //! Clear all particles when node gets invisible + EPB_CLEAR_ON_INVISIBLE = 8, + + //! Particle movement direction on emitting ignores the node rotation + //! This is mainly to allow backward compatible behavior to Irrlicht 1.8 + EPB_EMITTER_VECTOR_IGNORE_ROTATION = 16, + + //! On emitting global particles interpolate the positions randomly between the last and current node transformations. + //! This can be set to avoid gaps caused by fast node movement or low framerates, but will be somewhat + //! slower to calculate. + EPB_EMITTER_FRAME_INTERPOLATION = 32 +}; + +class IParticleSystemSceneNode : public ISceneNode +{ +public: + + //! Constructor + IParticleSystemSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) + : ISceneNode(parent, mgr, id, position, rotation, scale) + , ParticleBehavior(0) + { + } + + //! Sets the size of all particles. + virtual void setParticleSize( + const core::dimension2d &size = core::dimension2d(5.0f, 5.0f)) = 0; + + //! Sets if the particles should be global. + /** If they are, the particles are affected by the movement of the + particle system scene node too, otherwise they completely ignore it. + Default is true. */ + virtual void setParticlesAreGlobal(bool global=true) = 0; + + + //! Bitflags to change the particle behavior + /** + \param flags A combination of ::EParticleBehavior bit-flags. Default is 0. */ + virtual void setParticleBehavior(irr::u32 flags) + { + ParticleBehavior = flags; + } + + + //! Gets how particles behave in different situations + /** + \return A combination of ::EParticleBehavior flags */ + virtual irr::u32 getParticleBehavior() const + { + return ParticleBehavior; + } + + //! Remove all currently visible particles + virtual void clearParticles() = 0; + + //! Do manually update the particles. + /** This should only be called when you want to render the node outside + the scenegraph, as the node will care about this otherwise + automatically. */ + virtual void doParticleSystem(u32 time) = 0; + + //! Gets the particle emitter, which creates the particles. + /** \return The particle emitter. Can be 0 if none is set. */ + virtual IParticleEmitter* getEmitter() =0; + + //! Sets the particle emitter, which creates the particles. + /** A particle emitter can be created using one of the createEmitter + methods. For example to create and use a simple PointEmitter, call + IParticleEmitter* p = createPointEmitter(); setEmitter(p); p->drop(); + \param emitter: Sets the particle emitter. You can set this to 0 for + removing the current emitter and stopping the particle system emitting + new particles. */ + virtual void setEmitter(IParticleEmitter* emitter) = 0; + + //! Adds new particle effector to the particle system. + /** A particle affector modifies the particles. For example, the FadeOut + affector lets all particles fade out after some time. It is created and + used in this way: + \code + IParticleAffector* p = createFadeOutParticleAffector(); + addAffector(p); + p->drop(); + \endcode + Please note that an affector is not necessary for the particle system to + work. + \param affector: New affector. */ + virtual void addAffector(IParticleAffector* affector) = 0; + + //! Get a list of all particle affectors. + /** \return The list of particle affectors attached to this node. */ + virtual const core::list& getAffectors() const = 0; + + //! Removes all particle affectors in the particle system. + virtual void removeAllAffectors() = 0; + + //! Creates a particle emitter for an animated mesh scene node + /** \param node: Pointer to the animated mesh scene node to emit + particles from + \param useNormalDirection: If true, the direction of each particle + created will be the normal of the vertex that it's emitting from. The + normal is divided by the normalDirectionModifier parameter, which + defaults to 100.0f. + \param direction: Direction and speed of particle emission. + \param normalDirectionModifier: If the emitter is using the normal + direction then the normal of the vertex that is being emitted from is + divided by this number. + \param mbNumber: This allows you to specify a specific meshBuffer for + the IMesh* to emit particles from. The default value is -1, which + means a random meshBuffer picked from all of the meshes meshBuffers + will be selected to pick a random vertex from. If the value is 0 or + greater, it will only pick random vertices from the meshBuffer + specified by this value. + \param everyMeshVertex: If true, the emitter will emit between min/max + particles every second, for every vertex in the mesh, if false, it will + emit between min/max particles from random vertices in the mesh. + \param minParticlesPerSecond: Minimal amount of particles emitted per + second. + \param maxParticlesPerSecond: Maximal amount of particles emitted per + second. + \param minStartColor: Minimal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param maxStartColor: Maximal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param lifeTimeMin: Minimal lifetime of a particle, in milliseconds. + \param lifeTimeMax: Maximal lifetime of a particle, in milliseconds. + \param maxAngleDegrees: Maximal angle in degrees, the emitting + direction of the particle will differ from the original direction. + \param minStartSize: Minimal initial start size of a particle. The + real size of every particle is calculated as random interpolation + between minStartSize and maxStartSize. + \param maxStartSize: Maximal initial start size of a particle. The + real size of every particle is calculated as random interpolation + between minStartSize and maxStartSize. + \return Pointer to the created particle emitter. To set this emitter + as new emitter of this particle system, just call setEmitter(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more information. */ + virtual IParticleAnimatedMeshSceneNodeEmitter* createAnimatedMeshSceneNodeEmitter( + scene::IAnimatedMeshSceneNode* node, bool useNormalDirection = true, + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + f32 normalDirectionModifier = 100.0f, s32 mbNumber = -1, + bool everyMeshVertex = false, + u32 minParticlesPerSecond = 5, u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin = 2000, u32 lifeTimeMax = 4000, + s32 maxAngleDegrees = 0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) ) = 0; + + //! Creates a box particle emitter. + /** \param box: The box for the emitter. + \param direction: Direction and speed of particle emission. + \param minParticlesPerSecond: Minimal amount of particles emitted per + second. + \param maxParticlesPerSecond: Maximal amount of particles emitted per + second. + \param minStartColor: Minimal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param maxStartColor: Maximal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param lifeTimeMin: Minimal lifetime of a particle, in milliseconds. + \param lifeTimeMax: Maximal lifetime of a particle, in milliseconds. + \param maxAngleDegrees: Maximal angle in degrees, the emitting + direction of the particle will differ from the original direction. + \param minStartSize: Minimal initial start size of a particle. The + real size of every particle is calculated as random interpolation + between minStartSize and maxStartSize. + \param maxStartSize: Maximal initial start size of a particle. The + real size of every particle is calculated as random interpolation + between minStartSize and maxStartSize. + \return Pointer to the created particle emitter. To set this emitter + as new emitter of this particle system, just call setEmitter(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more information. */ + virtual IParticleBoxEmitter* createBoxEmitter( + const core::aabbox3df& box = core::aabbox3df(-10,28,-10,10,30,10), + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 5, + u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin=2000, u32 lifeTimeMax=4000, + s32 maxAngleDegrees=0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) ) = 0; + + //! Creates a particle emitter for emitting from a cylinder + /** \param center: The center of the circle at the base of the cylinder + \param radius: The thickness of the cylinder + \param normal: Direction of the length of the cylinder + \param length: The length of the the cylinder + \param outlineOnly: Whether or not to put points inside the cylinder or + on the outline only + \param direction: Direction and speed of particle emission. + \param minParticlesPerSecond: Minimal amount of particles emitted per + second. + \param maxParticlesPerSecond: Maximal amount of particles emitted per + second. + \param minStartColor: Minimal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param maxStartColor: Maximal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param lifeTimeMin: Minimal lifetime of a particle, in milliseconds. + \param lifeTimeMax: Maximal lifetime of a particle, in milliseconds. + \param maxAngleDegrees: Maximal angle in degrees, the emitting + direction of the particle will differ from the original direction. + \param minStartSize: Minimal initial start size of a particle. The + real size of every particle is calculated as random interpolation + between minStartSize and maxStartSize. + \param maxStartSize: Maximal initial start size of a particle. The + real size of every particle is calculated as random interpolation + between minStartSize and maxStartSize. + \return Pointer to the created particle emitter. To set this emitter + as new emitter of this particle system, just call setEmitter(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more information. */ + virtual IParticleCylinderEmitter* createCylinderEmitter( + const core::vector3df& center, f32 radius, + const core::vector3df& normal, f32 length, + bool outlineOnly = false, + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 5, u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin = 2000, u32 lifeTimeMax = 4000, + s32 maxAngleDegrees = 0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) ) = 0; + + //! Creates a mesh particle emitter. + /** \param mesh: Pointer to mesh to emit particles from + \param useNormalDirection: If true, the direction of each particle + created will be the normal of the vertex that it's emitting from. The + normal is divided by the normalDirectionModifier parameter, which + defaults to 100.0f. + \param direction: Direction and speed of particle emission. + \param normalDirectionModifier: If the emitter is using the normal + direction then the normal of the vertex that is being emitted from is + divided by this number. + \param mbNumber: This allows you to specify a specific meshBuffer for + the IMesh* to emit particles from. The default value is -1, which + means a random meshBuffer picked from all of the meshes meshBuffers + will be selected to pick a random vertex from. If the value is 0 or + greater, it will only pick random vertices from the meshBuffer + specified by this value. + \param everyMeshVertex: If true, the emitter will emit between min/max + particles every second, for every vertex in the mesh, if false, it will + emit between min/max particles from random vertices in the mesh. + \param minParticlesPerSecond: Minimal amount of particles emitted per + second. + \param maxParticlesPerSecond: Maximal amount of particles emitted per + second. + \param minStartColor: Minimal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param maxStartColor: Maximal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param lifeTimeMin: Minimal lifetime of a particle, in milliseconds. + \param lifeTimeMax: Maximal lifetime of a particle, in milliseconds. + \param maxAngleDegrees: Maximal angle in degrees, the emitting + direction of the particle will differ from the original direction. + \param minStartSize: Minimal initial start size of a particle. The + real size of every particle is calculated as random interpolation + between minStartSize and maxStartSize. + \param maxStartSize: Maximal initial start size of a particle. The + real size of every particle is calculated as random interpolation + between minStartSize and maxStartSize. + \return Pointer to the created particle emitter. To set this emitter + as new emitter of this particle system, just call setEmitter(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more information. */ + virtual IParticleMeshEmitter* createMeshEmitter( + scene::IMesh* mesh, bool useNormalDirection = true, + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + f32 normalDirectionModifier = 100.0f, s32 mbNumber = -1, + bool everyMeshVertex = false, + u32 minParticlesPerSecond = 5, u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin = 2000, u32 lifeTimeMax = 4000, + s32 maxAngleDegrees = 0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) ) = 0; + + //! Creates a point particle emitter. + /** \param direction: Direction and speed of particle emission. + \param minParticlesPerSecond: Minimal amount of particles emitted per + second. + \param maxParticlesPerSecond: Maximal amount of particles emitted per + second. + \param minStartColor: Minimal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param maxStartColor: Maximal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param lifeTimeMin: Minimal lifetime of a particle, in milliseconds. + \param lifeTimeMax: Maximal lifetime of a particle, in milliseconds. + \param maxAngleDegrees: Maximal angle in degrees, the emitting + direction of the particle will differ from the original direction. + \param minStartSize: Minimal initial start size of a particle. The + real size of every particle is calculated as random interpolation + between minStartSize and maxStartSize. + \param maxStartSize: Maximal initial start size of a particle. The + real size of every particle is calculated as random interpolation + between minStartSize and maxStartSize. + \return Pointer to the created particle emitter. To set this emitter + as new emitter of this particle system, just call setEmitter(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more information. */ + virtual IParticlePointEmitter* createPointEmitter( + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 5, + u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin=2000, u32 lifeTimeMax=4000, + s32 maxAngleDegrees=0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) ) = 0; + + //! Creates a ring particle emitter. + /** \param center: Center of ring + \param radius: Distance of points from center, points will be rotated + around the Y axis at a random 360 degrees and will then be shifted by + the provided ringThickness values in each axis. + \param ringThickness : thickness of the ring or how wide the ring is + \param direction: Direction and speed of particle emission. + \param minParticlesPerSecond: Minimal amount of particles emitted per + second. + \param maxParticlesPerSecond: Maximal amount of particles emitted per + second. + \param minStartColor: Minimal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param maxStartColor: Maximal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param lifeTimeMin: Minimal lifetime of a particle, in milliseconds. + \param lifeTimeMax: Maximal lifetime of a particle, in milliseconds. + \param maxAngleDegrees: Maximal angle in degrees, the emitting + direction of the particle will differ from the original direction. + \param minStartSize: Minimal initial start size of a particle. The + real size of every particle is calculated as random interpolation + between minStartSize and maxStartSize. + \param maxStartSize: Maximal initial start size of a particle. The + real size of every particle is calculated as random interpolation + between minStartSize and maxStartSize. + \return Pointer to the created particle emitter. To set this emitter + as new emitter of this particle system, just call setEmitter(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more information. */ + virtual IParticleRingEmitter* createRingEmitter( + const core::vector3df& center, f32 radius, f32 ringThickness, + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 5, + u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin=2000, u32 lifeTimeMax=4000, + s32 maxAngleDegrees=0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) ) = 0; + + //! Creates a sphere particle emitter. + /** \param center: Center of sphere + \param radius: Radius of sphere + \param direction: Direction and speed of particle emission. + \param minParticlesPerSecond: Minimal amount of particles emitted per + second. + \param maxParticlesPerSecond: Maximal amount of particles emitted per + second. + \param minStartColor: Minimal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param maxStartColor: Maximal initial start color of a particle. The + real color of every particle is calculated as random interpolation + between minStartColor and maxStartColor. + \param lifeTimeMin: Minimal lifetime of a particle, in milliseconds. + \param lifeTimeMax: Maximal lifetime of a particle, in milliseconds. + \param maxAngleDegrees: Maximal angle in degrees, the emitting + direction of the particle will differ from the original direction. + \param minStartSize: Minimal initial start size of a particle. The + real size of every particle is calculated as random interpolation + between minStartSize and maxStartSize. + \param maxStartSize: Maximal initial start size of a particle. The + real size of every particle is calculated as random interpolation + between minStartSize and maxStartSize. + \return Pointer to the created particle emitter. To set this emitter + as new emitter of this particle system, just call setEmitter(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more information. */ + virtual IParticleSphereEmitter* createSphereEmitter( + const core::vector3df& center, f32 radius, + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 5, + u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin=2000, u32 lifeTimeMax=4000, + s32 maxAngleDegrees=0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) ) = 0; + + //! Creates a point attraction affector. + /** This affector modifies the positions of the particles and attracts + them to a specified point at a specified speed per second. + \param point: Point to attract particles to. + \param speed: Speed in units per second, to attract to the specified + point. + \param attract: Whether the particles attract or detract from this + point. + \param affectX: Whether or not this will affect the X position of the + particle. + \param affectY: Whether or not this will affect the Y position of the + particle. + \param affectZ: Whether or not this will affect the Z position of the + particle. + \return Pointer to the created particle affector. To add this affector + as new affector of this particle system, just call addAffector(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more information. */ + virtual IParticleAttractionAffector* createAttractionAffector( + const core::vector3df& point, f32 speed = 1.0f, bool attract = true, + bool affectX = true, bool affectY = true, bool affectZ = true) = 0; + + //! Creates a scale particle affector. + /** This affector scales the particle to the a multiple of its size defined + by the scaleTo variable. + \param scaleTo: multiple of the size which the particle will be scaled to until deletion + \return Pointer to the created particle affector. + To add this affector as new affector of this particle system, + just call addAffector(). Note that you'll have to drop() the + returned pointer, after you don't need it any more, see + IReferenceCounted::drop() for more information. */ + virtual IParticleAffector* createScaleParticleAffector(const core::dimension2df& scaleTo = core::dimension2df(1.0f, 1.0f)) = 0; + + //! Creates a fade out particle affector. + /** This affector modifies the color of every particle and and reaches + the final color when the particle dies. This affector looks really + good, if the EMT_TRANSPARENT_ADD_COLOR material is used and the + targetColor is video::SColor(0,0,0,0): Particles are fading out into + void with this setting. + \param targetColor: Color whereto the color of the particle is changed. + \param timeNeededToFadeOut: How much time in milliseconds should the + affector need to change the color to the targetColor. + \return Pointer to the created particle affector. To add this affector + as new affector of this particle system, just call addAffector(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more information. */ + virtual IParticleFadeOutAffector* createFadeOutParticleAffector( + const video::SColor& targetColor = video::SColor(0,0,0,0), + u32 timeNeededToFadeOut = 1000) = 0; + + //! Creates a gravity affector. + /** This affector modifies the direction of the particle. It assumes + that the particle is fired out of the emitter with huge force, but is + loosing this after some time and is caught by the gravity then. This + affector is ideal for creating things like fountains. + \param gravity: Direction and force of gravity. + \param timeForceLost: Time in milliseconds when the force of the + emitter is totally lost and the particle does not move any more. This + is the time where gravity fully affects the particle. + \return Pointer to the created particle affector. To add this affector + as new affector of this particle system, just call addAffector(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more information. */ + virtual IParticleGravityAffector* createGravityAffector( + const core::vector3df& gravity = core::vector3df(0.0f,-0.03f,0.0f), + u32 timeForceLost = 1000) = 0; + + //! Creates a rotation affector. + /** This affector modifies the positions of the particles and attracts + them to a specified point at a specified speed per second. + \param speed: Rotation in degrees per second + \param pivotPoint: Point to rotate the particles around + \return Pointer to the created particle affector. To add this affector + as new affector of this particle system, just call addAffector(). Note + that you'll have to drop() the returned pointer, after you don't need + it any more, see IReferenceCounted::drop() for more information. */ + virtual IParticleRotationAffector* createRotationAffector( + const core::vector3df& speed = core::vector3df(5.0f,5.0f,5.0f), + const core::vector3df& pivotPoint = core::vector3df(0.0f,0.0f,0.0f) ) = 0; + + //! Writes attributes of the scene node. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_ + { + out->addInt("ParticleBehavior", ParticleBehavior); + } + + //! Reads attributes of the scene node. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_ + { + ParticleBehavior = in->getAttributeAsInt("ParticleBehavior", ParticleBehavior); + } + +protected: + s32 ParticleBehavior; +}; + +} // end namespace scene +} // end namespace irr + +#endif diff --git a/include/IProfiler.h b/include/IProfiler.h new file mode 100644 index 00000000..c2e837db --- /dev/null +++ b/include/IProfiler.h @@ -0,0 +1,480 @@ +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +// Written by Michael Zeilfelder + +#ifndef __I_PROFILER_H_INCLUDED__ +#define __I_PROFILER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#include "irrString.h" +#include "irrArray.h" +#include "ITimer.h" +#include // for INT_MAX (we should have a S32_MAX...) + +namespace irr +{ + +class ITimer; + +//! Used to store the profile data (and also used for profile group data). +struct SProfileData +{ + friend class IProfiler; + + SProfileData() + { + GroupIndex = 0; + reset(); + } + + bool operator<(const SProfileData& pd) const + { + return Id < pd.Id; + } + + bool operator==(const SProfileData& pd) const + { + return Id == pd.Id; + } + + u32 getGroupIndex() const + { + return GroupIndex; + } + + const core::stringw& getName() const + { + return Name; + } + + //! Each time profiling for this data is stopped it increases the counter by 1. + u32 getCallsCounter() const + { + return CountCalls; + } + + //! Longest time a profile call for this id took from start until it was stopped again. + u32 getLongestTime() const + { + return LongestTime; + } + + //! Time spend between start/stop + u32 getTimeSum() const + { + return TimeSum; + } + +private: + + // just to be used for searching as it does no initialization besides id + SProfileData(u32 id) : Id(id) {} + + void reset() + { + CountCalls = 0; + LongestTime = 0; + TimeSum = 0; + LastTimeStarted = 0; + StartStopCounter = 0; + } + + s32 Id; + u32 GroupIndex; + core::stringw Name; + + s32 StartStopCounter; // 0 means stopped > 0 means it runs. + u32 CountCalls; + u32 LongestTime; + u32 TimeSum; + + u32 LastTimeStarted; +}; + +//! Code-profiler. Please check the example in the Irrlicht examples folder about how to use it. +// Implementer notes: +// The design is all about allowing to use the central start/stop mechanism with minimal time overhead. +// This is why the class works without a virtual functions interface contrary to the usual Irrlicht design. +// And also why it works with id's instead of strings in the start/stop functions even if it makes using +// the class slightly harder. +// The class comes without reference-counting because the profiler instance is never released (TBD). +class IProfiler +{ +public: + //! Constructor. You could use this to create a new profiler, but usually getProfiler() is used to access the global instance. + IProfiler() : Timer(0), NextAutoId(INT_MAX) + {} + + virtual ~IProfiler() + {} + + //! Add an id with given name and group which can be used for profiling with start/stop + /** After calling this once you can start/stop profiling for the given id. + \param id: Should be >= 0 as negative id's are reserved for Irrlicht. Also very large numbers (near INT_MAX) might + have been added automatically by the other add function. + \param name: Name for displaying profile data. + \param groupName: Each id belongs into a group - this helps on displaying profile data. */ + inline void add(s32 id, const core::stringw &name, const core::stringw &groupName); + + //! Add an automatically generated for the given name and group which can be used for profiling with start/stop. + /** After calling this once you can start/stop profiling with the returned id. + \param name: Name for displaying profile data. + \param groupName: Each id belongs into a group - this helps on displaying profile data. + \return Automatic id's start at INT_MAX and count down for each new id. If the name already has an id then that id will be returned. */ + inline s32 add(const core::stringw &name, const core::stringw &groupName); + + //! Return the number of profile data blocks. There is one for each id. + u32 getProfileDataCount() const + { + return ProfileDatas.size(); + } + + //! Search for the index of the profile data by name + /** \param result Receives the resulting data index when one was found. + \param name String with name to search for + \return true when found, false when not found */ + inline bool findDataIndex(u32 & result, const core::stringw &name) const; + + //! Get the profile data + /** \param index A value between 0 and getProfileDataCount()-1. Indices can change when new id's are added.*/ + const SProfileData& getProfileDataByIndex(u32 index) const + { + return ProfileDatas[index]; + } + + //! Get the profile data + /** \param id Same value as used in ::add + \return Profile data for the given id or 0 when it does not exist. */ + inline const SProfileData* getProfileDataById(u32 id); + + //! Get the number of profile groups. Will be at least 1. + /** NOTE: The first groups is always L"overview" which is an overview for all existing groups */ + inline u32 getGroupCount() const + { + return ProfileGroups.size(); + } + + //! Get profile data for a group. + /** NOTE: The first groups is always L"overview" which is an overview for all existing groups */ + inline const SProfileData& getGroupData(u32 index) const + { + return ProfileGroups[index]; + } + + //! Find the group index by the group-name + /** \param result Receives the resulting group index when one was found. + \param name String with name to search for + \return true when found, false when not found */ + inline bool findGroupIndex(u32 & result, const core::stringw &name) const; + + + //! Start profile-timing for the given id + /** This increases an internal run-counter for the given id. It will profile as long as that counter is > 0. + NOTE: you have to add the id first with one of the ::add functions + */ + inline void start(s32 id); + + //! Stop profile-timing for the given id + /** This increases an internal run-counter for the given id. If it reaches 0 the time since start is recorded. + You should have the same amount of start and stop calls. If stop is called more often than start + then the additional stop calls will be ignored (counter never goes below 0) + */ + inline void stop(s32 id); + + //! Reset profile data for the given id + inline void resetDataById(s32 id); + + //! Reset profile data for the given index + inline void resetDataByIndex(u32 index); + + //! Reset profile data for a whole group + inline void resetGroup(u32 index); + + //! Reset all profile data + /** NOTE: This is not deleting id's or groups, just resetting all timers to 0. */ + inline void resetAll(); + + //! Write all profile-data into a string + /** \param result Receives the result string. + \param includeOverview When true a group-overview is attached first + \param suppressUncalled When true elements which got never called are not printed */ + virtual void printAll(core::stringw &result, bool includeOverview=false,bool suppressUncalled=true) const = 0; + + //! Write the profile data of one group into a string + /** \param result Receives the result string. + \param groupIndex_ */ + virtual void printGroup(core::stringw &result, u32 groupIndex, bool suppressUncalled) const = 0; + +protected: + + inline u32 addGroup(const core::stringw &name); + + // I would prefer using os::Timer, but os.h is not in the public interface so far. + // Timer must be initialized by the implementation. + ITimer * Timer; + core::array ProfileDatas; + core::array ProfileGroups; + +private: + s32 NextAutoId; // for giving out id's automatically +}; + +//! Access the Irrlicht profiler object. +/** Profiler is always accessible, except in destruction of global objects. +If you want to get internal profiling information about the engine itself +you will have to re-compile the engine with _IRR_COMPILE_WITH_PROFILING_ enabled. +But you can use the profiler for profiling your own projects without that. */ +IRRLICHT_API IProfiler& IRRCALLCONV getProfiler(); + +//! Class where the objects profile their own life-time. +/** This is a comfort wrapper around the IProfiler start/stop mechanism which is easier to use +when you want to profile a scope. You only have to create an object and it will profile it's own lifetime +for the given id. */ +class CProfileScope +{ +public: + //! Construct with an known id. + /** This is the fastest scope constructor, but the id must have been added before. + \param id Any id which you did add to the profiler before. */ + CProfileScope(s32 id) + : Id(id), Profiler(getProfiler()) + { + Profiler.start(Id); + } + + //! Object will create the given name, groupName combination for the id if it doesn't exist already + /** \param id: Should be >= 0 as negative id's are reserved for Irrlicht. Also very large numbers (near INT_MAX) might + have been created already by the automatic add function of ::IProfiler. + \param name: Name for displaying profile data. + \param groupName: Each id belongs into a group - this helps on displaying profile data. */ + CProfileScope(s32 id, const core::stringw &name, const core::stringw &groupName) + : Id(id), Profiler(getProfiler()) + { + Profiler.add(Id, name, groupName); + Profiler.start(Id); + } + + //! Object will create an id for the given name, groupName combination if they don't exist already + /** Slowest scope constructor, but usually still fine unless speed is very critical. + \param name: Name for displaying profile data. + \param groupName: Each id belongs into a group - this helps on displaying profile data. */ + CProfileScope(const core::stringw &name, const core::stringw &groupName) + : Profiler(getProfiler()) + { + Id = Profiler.add(name, groupName); + Profiler.start(Id); + } + + ~CProfileScope() + { + Profiler.stop(Id); + } + +protected: + s32 Id; + IProfiler& Profiler; +}; + + +// IMPLEMENTATION for in-line stuff + +void IProfiler::start(s32 id) +{ + s32 idx = ProfileDatas.binary_search(SProfileData(id)); + if ( idx >= 0 && Timer ) + { + ++ProfileDatas[idx].StartStopCounter; + if (ProfileDatas[idx].StartStopCounter == 1 ) + ProfileDatas[idx].LastTimeStarted = Timer->getRealTime(); + } +} + +void IProfiler::stop(s32 id) +{ + if ( Timer ) + { + u32 timeNow = Timer->getRealTime(); + s32 idx = ProfileDatas.binary_search(SProfileData(id)); + if ( idx >= 0 ) + { + SProfileData &data = ProfileDatas[idx]; + --ProfileDatas[idx].StartStopCounter; + if ( data.LastTimeStarted != 0 && ProfileDatas[idx].StartStopCounter == 0) + { + // update data for this id + ++data.CountCalls; + u32 diffTime = timeNow - data.LastTimeStarted; + data.TimeSum += diffTime; + if ( diffTime > data.LongestTime ) + data.LongestTime = diffTime; + data.LastTimeStarted = 0; + + // update data of it's group + SProfileData & group = ProfileGroups[data.GroupIndex]; + ++group.CountCalls; + group.TimeSum += diffTime; + if ( diffTime > group.LongestTime ) + group.LongestTime = diffTime; + group.LastTimeStarted = 0; + } + else if ( ProfileDatas[idx].StartStopCounter < 0 ) + { + // ignore additional stop calls + ProfileDatas[idx].StartStopCounter = 0; + } + } + } +} + +s32 IProfiler::add(const core::stringw &name, const core::stringw &groupName) +{ + u32 index; + if ( findDataIndex(index, name) ) + { + add( ProfileDatas[index].Id, name, groupName ); + return ProfileDatas[index].Id; + } + else + { + s32 id = NextAutoId; + --NextAutoId; + add( id, name, groupName ); + return id; + } +} + +void IProfiler::add(s32 id, const core::stringw &name, const core::stringw &groupName) +{ + u32 groupIdx; + if ( !findGroupIndex(groupIdx, groupName) ) + { + groupIdx = addGroup(groupName); + } + + SProfileData data(id); + s32 idx = ProfileDatas.binary_search(data); + if ( idx < 0 ) + { + data.reset(); + data.GroupIndex = groupIdx; + data.Name = name; + + ProfileDatas.push_back(data); + ProfileDatas.sort(); + } + else + { + // only reset on group changes, otherwise we want to keep the data or coding CProfileScope would become tricky. + if ( groupIdx != ProfileDatas[idx].GroupIndex ) + { + resetDataByIndex((u32)idx); + ProfileDatas[idx].GroupIndex = groupIdx; + } + ProfileDatas[idx].Name = name; + } +} + +u32 IProfiler::addGroup(const core::stringw &name) +{ + SProfileData group; + group.Id = -1; // Id for groups doesn't matter so far + group.Name = name; + ProfileGroups.push_back(group); + return ProfileGroups.size()-1; +} + +bool IProfiler::findDataIndex(u32 & result, const core::stringw &name) const +{ + for ( u32 i=0; i < ProfileDatas.size(); ++i ) + { + if ( ProfileDatas[i].Name == name ) + { + result = i; + return true; + } + } + + return false; +} + +const SProfileData* IProfiler::getProfileDataById(u32 id) +{ + SProfileData data(id); + s32 idx = ProfileDatas.binary_search(data); + if ( idx >= 0 ) + return &ProfileDatas[idx]; + return NULL; +} + +bool IProfiler::findGroupIndex(u32 & result, const core::stringw &name) const +{ + for ( u32 i=0; i < ProfileGroups.size(); ++i ) + { + if ( ProfileGroups[i].Name == name ) + { + result = i; + return true; + } + } + + return false; +} + +void IProfiler::resetDataById(s32 id) +{ + s32 idx = ProfileDatas.binary_search(SProfileData(id)); + if ( idx >= 0 ) + { + resetDataByIndex((u32)idx); + } +} + +void IProfiler::resetDataByIndex(u32 index) +{ + SProfileData &data = ProfileDatas[index]; + + SProfileData & group = ProfileGroups[data.GroupIndex]; + group.CountCalls -= data.CountCalls; + group.TimeSum -= data.TimeSum; + + data.reset(); +} + +//! Reset profile data for a whole group +void IProfiler::resetGroup(u32 index) +{ + for ( u32 i=0; i tStringList; + typedef core::array< video::ITexture* > tTexArray; + + // string helper.. TODO: move to generic files + inline s16 isEqual ( const core::stringc &string, u32 &pos, const c8 * const list[], u16 listSize ) + { + const char * in = string.c_str () + pos; + + for ( u16 i = 0; i != listSize; ++i ) + { + if (string.size() < pos) + return -2; + u32 len = (u32) strlen ( list[i] ); + if (string.size() < pos+len) + continue; + if ( in [len] != 0 && in [len] != ' ' ) + continue; + if ( strncmp ( in, list[i], len ) ) + continue; + + pos += len + 1; + return (s16) i; + } + return -2; + } + + inline f32 getAsFloat ( const core::stringc &string, u32 &pos ) + { + const char * in = string.c_str () + pos; + + f32 value = 0.f; + pos += (u32) ( core::fast_atof_move ( in, value ) - in ) + 1; + return value; + } + + //! get a quake3 vector translated to irrlicht position (x,-z,y ) + inline core::vector3df getAsVector3df ( const core::stringc &string, u32 &pos ) + { + core::vector3df v; + + v.X = getAsFloat ( string, pos ); + v.Z = getAsFloat ( string, pos ); + v.Y = getAsFloat ( string, pos ); + + return v; + } + + + /* + extract substrings + */ + inline void getAsStringList ( tStringList &list, s32 max, const core::stringc &string, u32 &startPos ) + { + list.clear (); + + s32 finish = 0; + s32 endPos; + do + { + endPos = string.findNext ( ' ', startPos ); + if ( endPos == -1 ) + { + finish = 1; + endPos = string.size(); + } + + list.push_back ( string.subString ( startPos, endPos - startPos ) ); + startPos = endPos + 1; + + if ( list.size() >= (u32) max ) + finish = 1; + + } while ( !finish ); + + } + + //! A blend function for a q3 shader. + struct SBlendFunc + { + SBlendFunc ( video::E_MODULATE_FUNC mod ) + : type ( video::EMT_SOLID ), modulate ( mod ), + param0( 0.f ), + isTransparent ( 0 ) {} + + video::E_MATERIAL_TYPE type; + video::E_MODULATE_FUNC modulate; + + f32 param0; + u32 isTransparent; + }; + + // parses the content of Variable cull + inline bool getCullingFunction ( const core::stringc &cull ) + { + if ( cull.size() == 0 ) + return true; + + bool ret = true; + static const c8 * funclist[] = { "none", "disable", "twosided" }; + + u32 pos = 0; + switch ( isEqual ( cull, pos, funclist, 3 ) ) + { + case 0: + case 1: + case 2: + ret = false; + break; + } + return ret; + } + + // parses the content of Variable depthfunc + // return a z-test + inline u8 getDepthFunction ( const core::stringc &string ) + { + u8 ret = video::ECFN_LESSEQUAL; + + if ( string.size() == 0 ) + return ret; + + static const c8 * funclist[] = { "lequal","equal" }; + + u32 pos = 0; + switch ( isEqual ( string, pos, funclist, 2 ) ) + { + case 0: + ret = video::ECFN_LESSEQUAL; + break; + case 1: + ret = video::ECFN_EQUAL; + break; + } + return ret; + } + + + /*! + parses the content of Variable blendfunc,alphafunc + it also make a hint for rendering as transparent or solid node. + + we assume a typical quake scene would look like this.. + 1) Big Static Mesh ( solid ) + 2) static scene item ( may use transparency ) but rendered in the solid pass + 3) additional transparency item in the transparent pass + + it's not 100% accurate! it just empirical.. + */ + inline static void getBlendFunc ( const core::stringc &string, SBlendFunc &blendfunc ) + { + if ( string.size() == 0 ) + return; + + // maps to E_BLEND_FACTOR + static const c8 * funclist[] = + { + "gl_zero", + "gl_one", + "gl_dst_color", + "gl_one_minus_dst_color", + "gl_src_color", + "gl_one_minus_src_color", + "gl_src_alpha", + "gl_one_minus_src_alpha", + "gl_dst_alpha", + "gl_one_minus_dst_alpha", + "gl_src_alpha_sat", + + "add", + "filter", + "blend", + + "ge128", + "gt0", + }; + + + u32 pos = 0; + s32 srcFact = isEqual ( string, pos, funclist, 16 ); + + if ( srcFact < 0 ) + return; + + u32 resolved = 0; + s32 dstFact = isEqual ( string, pos, funclist, 16 ); + + switch ( srcFact ) + { + case video::EBF_ZERO: + switch ( dstFact ) + { + // gl_zero gl_src_color == gl_dst_color gl_zero + case video::EBF_SRC_COLOR: + blendfunc.type = video::EMT_ONETEXTURE_BLEND; + blendfunc.param0 = video::pack_textureBlendFunc ( video::EBF_DST_COLOR, video::EBF_ZERO, blendfunc.modulate ); + blendfunc.isTransparent = 1; + resolved = 1; + break; + } break; + + case video::EBF_ONE: + switch ( dstFact ) + { + // gl_one gl_zero + case video::EBF_ZERO: + blendfunc.type = video::EMT_SOLID; + blendfunc.isTransparent = 0; + resolved = 1; + break; + + // gl_one gl_one + case video::EBF_ONE: + blendfunc.type = video::EMT_TRANSPARENT_ADD_COLOR; + blendfunc.isTransparent = 1; + resolved = 1; + break; + } break; + + case video::EBF_SRC_ALPHA: + switch ( dstFact ) + { + // gl_src_alpha gl_one_minus_src_alpha + case video::EBF_ONE_MINUS_SRC_ALPHA: + blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + blendfunc.param0 = 1.f/255.f; + blendfunc.isTransparent = 1; + resolved = 1; + break; + } break; + + case 11: + // add + blendfunc.type = video::EMT_TRANSPARENT_ADD_COLOR; + blendfunc.isTransparent = 1; + resolved = 1; + break; + case 12: + // filter = gl_dst_color gl_zero or gl_zero gl_src_color + blendfunc.type = video::EMT_ONETEXTURE_BLEND; + blendfunc.param0 = video::pack_textureBlendFunc ( video::EBF_DST_COLOR, video::EBF_ZERO, blendfunc.modulate ); + blendfunc.isTransparent = 1; + resolved = 1; + break; + case 13: + // blend = gl_src_alpha gl_one_minus_src_alpha + blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + blendfunc.param0 = 1.f/255.f; + blendfunc.isTransparent = 1; + resolved = 1; + break; + case 14: + // alphafunc ge128 + blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + blendfunc.param0 = 0.5f; + blendfunc.isTransparent = 1; + resolved = 1; + break; + case 15: + // alphafunc gt0 + blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + blendfunc.param0 = 1.f / 255.f; + blendfunc.isTransparent = 1; + resolved = 1; + break; + + } + + // use the generic blender + if ( 0 == resolved ) + { + blendfunc.type = video::EMT_ONETEXTURE_BLEND; + blendfunc.param0 = video::pack_textureBlendFunc ( + (video::E_BLEND_FACTOR) srcFact, + (video::E_BLEND_FACTOR) dstFact, + blendfunc.modulate); + + blendfunc.isTransparent = 1; + } + } + + // random noise [-1;1] + struct Noiser + { + static f32 get () + { + static u32 RandomSeed = 0x69666966; + RandomSeed = (RandomSeed * 3631 + 1); + + f32 value = ( (f32) (RandomSeed & 0x7FFF ) * (1.0f / (f32)(0x7FFF >> 1) ) ) - 1.f; + return value; + } + }; + + enum eQ3ModifierFunction + { + TCMOD = 0, + DEFORMVERTEXES = 1, + RGBGEN = 2, + TCGEN = 3, + MAP = 4, + ALPHAGEN = 5, + + FUNCTION2 = 0x10, + SCROLL = FUNCTION2 + 1, + SCALE = FUNCTION2 + 2, + ROTATE = FUNCTION2 + 3, + STRETCH = FUNCTION2 + 4, + TURBULENCE = FUNCTION2 + 5, + WAVE = FUNCTION2 + 6, + + IDENTITY = FUNCTION2 + 7, + VERTEX = FUNCTION2 + 8, + TEXTURE = FUNCTION2 + 9, + LIGHTMAP = FUNCTION2 + 10, + ENVIRONMENT = FUNCTION2 + 11, + DOLLAR_LIGHTMAP = FUNCTION2 + 12, + BULGE = FUNCTION2 + 13, + AUTOSPRITE = FUNCTION2 + 14, + AUTOSPRITE2 = FUNCTION2 + 15, + TRANSFORM = FUNCTION2 + 16, + EXACTVERTEX = FUNCTION2 + 17, + CONSTANT = FUNCTION2 + 18, + LIGHTINGSPECULAR = FUNCTION2 + 19, + MOVE = FUNCTION2 + 20, + NORMAL = FUNCTION2 + 21, + IDENTITYLIGHTING = FUNCTION2 + 22, + + WAVE_MODIFIER_FUNCTION = 0x30, + SINUS = WAVE_MODIFIER_FUNCTION + 1, + COSINUS = WAVE_MODIFIER_FUNCTION + 2, + SQUARE = WAVE_MODIFIER_FUNCTION + 3, + TRIANGLE = WAVE_MODIFIER_FUNCTION + 4, + SAWTOOTH = WAVE_MODIFIER_FUNCTION + 5, + SAWTOOTH_INVERSE = WAVE_MODIFIER_FUNCTION + 6, + NOISE = WAVE_MODIFIER_FUNCTION + 7, + + UNKNOWN = -2 + }; + + struct SModifierFunction + { + SModifierFunction () + : masterfunc0 ( UNKNOWN ), masterfunc1( UNKNOWN ), func ( SINUS ), + tcgen( TEXTURE ), rgbgen ( IDENTITY ), alphagen ( UNKNOWN ), + base ( 0 ), amp ( 1 ), phase ( 0 ), frequency ( 1 ), + wave ( 1 ), + x ( 0 ), y ( 0 ), z( 0 ), count( 0 ) {} + + // "tcmod","deformvertexes","rgbgen", "tcgen" + eQ3ModifierFunction masterfunc0; + // depends + eQ3ModifierFunction masterfunc1; + // depends + eQ3ModifierFunction func; + + eQ3ModifierFunction tcgen; + eQ3ModifierFunction rgbgen; + eQ3ModifierFunction alphagen; + + union + { + f32 base; + f32 bulgewidth; + }; + + union + { + f32 amp; + f32 bulgeheight; + }; + + f32 phase; + + union + { + f32 frequency; + f32 bulgespeed; + }; + + union + { + f32 wave; + f32 div; + }; + + f32 x; + f32 y; + f32 z; + u32 count; + + f32 evaluate ( f32 dt ) const + { + // phase in 0 and 1.. + f32 x = core::fract( (dt + phase ) * frequency ); + f32 y = 0.f; + + switch ( func ) + { + case SINUS: + y = sinf ( x * core::PI * 2.f ); + break; + case COSINUS: + y = cosf ( x * core::PI * 2.f ); + break; + case SQUARE: + y = x < 0.5f ? 1.f : -1.f; + break; + case TRIANGLE: + y = x < 0.5f ? ( 4.f * x ) - 1.f : ( -4.f * x ) + 3.f; + break; + case SAWTOOTH: + y = x; + break; + case SAWTOOTH_INVERSE: + y = 1.f - x; + break; + case NOISE: + y = Noiser::get(); + break; + default: + break; + } + + return base + ( y * amp ); + } + + + }; + + inline core::vector3df getMD3Normal ( u32 i, u32 j ) + { + const f32 lng = i * 2.0f * core::PI / 255.0f; + const f32 lat = j * 2.0f * core::PI / 255.0f; + return core::vector3df(cosf ( lat ) * sinf ( lng ), + sinf ( lat ) * sinf ( lng ), + cosf ( lng )); + } + + // + inline void getModifierFunc ( SModifierFunction& fill, const core::stringc &string, u32 &pos ) + { + if ( string.size() == 0 ) + return; + + static const c8 * funclist[] = + { + "sin","cos","square", + "triangle", "sawtooth","inversesawtooth", "noise" + }; + + fill.func = (eQ3ModifierFunction) isEqual ( string,pos, funclist,7 ); + fill.func = fill.func == UNKNOWN ? SINUS : (eQ3ModifierFunction) ((u32) fill.func + WAVE_MODIFIER_FUNCTION + 1); + + fill.base = getAsFloat ( string, pos ); + fill.amp = getAsFloat ( string, pos ); + fill.phase = getAsFloat ( string, pos ); + fill.frequency = getAsFloat ( string, pos ); + } + + + // name = "a b c .." + struct SVariable + { + core::stringc name; + core::stringc content; + + SVariable ( const c8 * n, const c8 *c = 0 ) : name ( n ), content (c) {} + virtual ~SVariable () {} + + void clear () + { + name = ""; + content = ""; + } + + s32 isValid () const + { + return name.size(); + } + + bool operator == ( const SVariable &other ) const + { + return 0 == strcmp ( name.c_str(), other.name.c_str () ); + } + + bool operator < ( const SVariable &other ) const + { + return 0 > strcmp ( name.c_str(), other.name.c_str () ); + } + + }; + + + // string database. "a" = "Hello", "b" = "1234.6" + struct SVarGroup + { + SVarGroup () { Variable.setAllocStrategy ( core::ALLOC_STRATEGY_SAFE ); } + virtual ~SVarGroup () {} + + u32 isDefined ( const c8 * name, const c8 * content = 0 ) const + { + for ( u32 i = 0; i != Variable.size (); ++i ) + { + if ( 0 == strcmp ( Variable[i].name.c_str(), name ) && + ( 0 == content || strstr ( Variable[i].content.c_str(), content ) ) + ) + { + return i + 1; + } + } + return 0; + } + + // searches for Variable name and returns is content + // if Variable is not found a reference to an Empty String is returned + const core::stringc &get( const c8 * name ) const + { + SVariable search ( name ); + s32 index = Variable.linear_search ( search ); + if ( index < 0 ) + return irrEmptyStringc; + + return Variable [ index ].content; + } + + // set the Variable name + void set ( const c8 * name, const c8 * content = 0 ) + { + u32 index = isDefined ( name, 0 ); + if ( 0 == index ) + { + Variable.push_back ( SVariable ( name, content ) ); + } + else + { + Variable [ index ].content = content; + } + } + + + core::array < SVariable > Variable; + }; + + //! holding a group a variable + struct SVarGroupList: public IReferenceCounted + { + SVarGroupList () + { + VariableGroup.setAllocStrategy ( core::ALLOC_STRATEGY_SAFE ); + } + virtual ~SVarGroupList () {} + + core::array < SVarGroup > VariableGroup; + }; + + + //! A Parsed Shader Holding Variables ordered in Groups + struct IShader + { + IShader () + : ID ( 0 ), VarGroup ( 0 ) {} + virtual ~IShader () {} + + void operator = (const IShader &other ) + { + ID = other.ID; + VarGroup = other.VarGroup; + name = other.name; + } + + bool operator == (const IShader &other ) const + { + return 0 == strcmp ( name.c_str(), other.name.c_str () ); + //return name == other.name; + } + + bool operator < (const IShader &other ) const + { + return strcmp ( name.c_str(), other.name.c_str () ) < 0; + //return name < other.name; + } + + u32 getGroupSize () const + { + if ( 0 == VarGroup ) + return 0; + return VarGroup->VariableGroup.size (); + } + + const SVarGroup * getGroup ( u32 stage ) const + { + if ( 0 == VarGroup || stage >= VarGroup->VariableGroup.size () ) + return 0; + + return &VarGroup->VariableGroup [ stage ]; + } + + // id + s32 ID; + SVarGroupList *VarGroup; // reference + + // Shader: shader name ( also first variable in first Vargroup ) + // Entity: classname ( variable in Group(1) ) + core::stringc name; + }; + + typedef IShader IEntity; + + typedef core::array < IEntity > tQ3EntityList; + + /* + dump shader like original layout, regardless of internal data holding + no recursive folding.. + */ + inline void dumpVarGroup ( core::stringc &dest, const SVarGroup * group, s32 stack ) + { + core::stringc buf; + + if ( stack > 0 ) + { + buf = ""; + for (s32 i = 0; i < stack - 1; ++i ) + buf += '\t'; + + buf += "{\n"; + dest.append ( buf ); + } + + for ( u32 g = 0; g != group->Variable.size(); ++g ) + { + buf = ""; + for (s32 i = 0; i < stack; ++i ) + buf += '\t'; + + buf += group->Variable[g].name; + buf += " "; + buf += group->Variable[g].content; + buf += "\n"; + dest.append ( buf ); + } + + if ( stack > 1 ) + { + buf = ""; + for (s32 i = 0; i < stack - 1; ++i ) + buf += '\t'; + + buf += "}\n"; + dest.append ( buf ); + } + } + + /*! + dump a Shader or an Entity + */ + inline core::stringc & dumpShader ( core::stringc &dest, const IShader * shader, bool entity = false ) + { + if ( 0 == shader ) + return dest; + + const u32 size = shader->VarGroup->VariableGroup.size (); + for ( u32 i = 0; i != size; ++i ) + { + const SVarGroup * group = &shader->VarGroup->VariableGroup[ i ]; + dumpVarGroup ( dest, group, core::clamp( (int)i, 0, 2 ) ); + } + + if ( !entity ) + { + if ( size <= 1 ) + { + dest.append ( "{\n" ); + } + dest.append ( "}\n" ); + } + return dest; + } + + + /* + quake3 doesn't care much about tga & jpg + load one or multiple files stored in name started at startPos to the texture array textures + if texture is not loaded 0 will be added ( to find missing textures easier) + */ + inline void getTextures(tTexArray &textures, + const core::stringc &name, u32 &startPos, + const io::IFileSystem *fileSystem, + video::IVideoDriver* driver) + { + static const char * const extension[] = + { + ".jpg", + ".jpeg", + ".png", + ".dds", + ".tga", + ".bmp", + ".pcx" + }; + + tStringList stringList; + getAsStringList(stringList, -1, name, startPos); + + textures.clear(); + + io::path loadFile; + for ( u32 i = 0; i!= stringList.size (); ++i ) + { + video::ITexture* texture = 0; + for (u32 g = 0; g != 7; ++g) + { + core::cutFilenameExtension ( loadFile, stringList[i] ); + + if ( loadFile == "$whiteimage" ) + { + texture = driver->getTexture( "$whiteimage" ); + if ( 0 == texture ) + { + core::dimension2du s ( 2, 2 ); + u32 image[4] = { 0xFFFFFFFF, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF }; + video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image ); + texture = driver->addTexture( "$whiteimage", w ); + w->drop (); + } + + } + else + if ( loadFile == "$redimage" ) + { + texture = driver->getTexture( "$redimage" ); + if ( 0 == texture ) + { + core::dimension2du s ( 2, 2 ); + u32 image[4] = { 0xFFFF0000, 0xFFFF0000,0xFFFF0000,0xFFFF0000 }; + video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image ); + texture = driver->addTexture( "$redimage", w ); + w->drop (); + } + } + else + if ( loadFile == "$blueimage" ) + { + texture = driver->getTexture( "$blueimage" ); + if ( 0 == texture ) + { + core::dimension2du s ( 2, 2 ); + u32 image[4] = { 0xFF0000FF, 0xFF0000FF,0xFF0000FF,0xFF0000FF }; + video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image ); + texture = driver->addTexture( "$blueimage", w ); + w->drop (); + } + } + else + if ( loadFile == "$checkerimage" ) + { + texture = driver->getTexture( "$checkerimage" ); + if ( 0 == texture ) + { + core::dimension2du s ( 2, 2 ); + u32 image[4] = { 0xFFFFFFFF, 0xFF000000,0xFF000000,0xFFFFFFFF }; + video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image ); + texture = driver->addTexture( "$checkerimage", w ); + w->drop (); + } + } + else + if ( loadFile == "$lightmap" ) + { + texture = 0; + } + else + { + loadFile.append ( extension[g] ); + } + + texture = driver->findTexture( loadFile ); + if ( texture ) + break; + + if ( fileSystem->existFile ( loadFile ) ) + { + texture = driver->getTexture( loadFile ); + if ( texture ) + break; + texture = 0; + } + } + // take 0 Texture + textures.push_back(texture); + } + } + + + //! Manages various Quake3 Shader Styles + class IShaderManager : public IReferenceCounted + { + }; + +} // end namespace quake3 +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/IRandomizer.h b/include/IRandomizer.h new file mode 100644 index 00000000..a0c07301 --- /dev/null +++ b/include/IRandomizer.h @@ -0,0 +1,33 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_RANDOMIZER_H_INCLUDED__ +#define __I_RANDOMIZER_H_INCLUDED__ + +#include "IReferenceCounted.h" + +namespace irr +{ + +//! Interface for generating random numbers +class IRandomizer : public virtual IReferenceCounted +{ +public: + //! resets the randomizer + /** \param value Initialization value (seed) */ + virtual void reset(s32 value=0x0f0f0f0f) =0; + + //! generates a pseudo random number in the range 0..randMax() + virtual s32 rand() const =0; + + //! generates a pseudo random number in the range 0..1 + virtual f32 frand() const =0; + + //! get maxmimum number generated by rand() + virtual s32 randMax() const =0; +}; + +} // end namespace irr + +#endif diff --git a/include/IReadFile.h b/include/IReadFile.h new file mode 100644 index 00000000..f3de9ebb --- /dev/null +++ b/include/IReadFile.h @@ -0,0 +1,61 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_READ_FILE_H_INCLUDED__ +#define __I_READ_FILE_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "coreutil.h" +#include "EReadFileType.h" + +namespace irr +{ +namespace io +{ + + //! Interface providing read access to a file. + class IReadFile : public virtual IReferenceCounted + { + public: + //! Reads an amount of bytes from the file. + /** \param buffer Pointer to buffer where read bytes are written to. + \param sizeToRead Amount of bytes to read from the file. + \return How many bytes were read. */ + virtual size_t read(void* buffer, size_t sizeToRead) = 0; + + //! Changes position in file + /** \param finalPos Destination position in the file. + \param relativeMovement If set to true, the position in the file is + changed relative to current position. Otherwise the position is changed + from beginning of file. + \return True if successful, otherwise false. */ + virtual bool seek(long finalPos, bool relativeMovement = false) = 0; + + //! Get size of file. + /** \return Size of the file in bytes. */ + virtual long getSize() const = 0; + + //! Get the current position in the file. + /** \return Current position in the file in bytes on success or -1L on failure. */ + virtual long getPos() const = 0; + + //! Get name of file. + /** \return File name as zero terminated character string. */ + virtual const io::path& getFileName() const = 0; + + //! Get the type of the class implementing this interface + virtual EREAD_FILE_TYPE getType() const + { + return EFIT_UNKNOWN; + } + }; + + //! Internal function, please do not use. + IReadFile* createLimitReadFile(const io::path& fileName, IReadFile* alreadyOpenedFile, long pos, long areaSize); + +} // end namespace io +} // end namespace irr + +#endif + diff --git a/include/IReferenceCounted.h b/include/IReferenceCounted.h new file mode 100644 index 00000000..42dfc92a --- /dev/null +++ b/include/IReferenceCounted.h @@ -0,0 +1,180 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_IREFERENCE_COUNTED_H_INCLUDED__ +#define __I_IREFERENCE_COUNTED_H_INCLUDED__ + +#include "irrTypes.h" + +#ifdef _IRR_COMPILE_WITH_LEAK_HUNTER_ + #include "leakHunter.h" +#endif + +namespace irr +{ + + //! Base class of most objects of the Irrlicht Engine. + /** This class provides reference counting through the methods grab() and drop(). + It also is able to store a debug string for every instance of an object. + Most objects of the Irrlicht + Engine are derived from IReferenceCounted, and so they are reference counted. + + When you create an object in the Irrlicht engine, calling a method + which starts with 'create', an object is created, and you get a pointer + to the new object. If you no longer need the object, you have + to call drop(). This will destroy the object, if grab() was not called + in another part of you program, because this part still needs the object. + Note, that you only need to call drop() to the object, if you created it, + and the method had a 'create' in it. + + A simple example: + + 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)); + 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 + ITexture* texture = driver->loadTexture("example.jpg"); + You will not have to drop the pointer to the loaded texture, because + the name of the method does not start with 'create'. The texture + is stored somewhere by the driver. + */ + class IReferenceCounted + { + public: + + //! Constructor. + IReferenceCounted() + : DebugName(0), ReferenceCounter(1) + { +#ifdef _IRR_COMPILE_WITH_LEAK_HUNTER_ + LeakHunter::addObject(this); +#endif + } + + //! Destructor. + virtual ~IReferenceCounted() + { + #ifdef _IRR_COMPILE_WITH_LEAK_HUNTER_ + LeakHunter::removeObject(this); + #endif + } + + //! Grabs the object. Increments the reference counter by one. + /** Someone who calls grab() to an object, should later also + call drop() to it. If an object never gets as much drop() as + grab() calls, it will never be destroyed. The + IReferenceCounted class provides a basic reference counting + mechanism with its methods grab() and drop(). Most objects of + the Irrlicht Engine are derived from IReferenceCounted, and so + they are reference counted. + + When you create an object in the Irrlicht engine, calling a + method which starts with 'create', an object is created, and + you get a pointer to the new object. If you no longer need the + object, you have to call drop(). This will destroy the object, + if grab() was not called in another part of you program, + because this part still needs the object. Note, that you only + need to call drop() to the object, if you created it, and the + method had a 'create' in it. + + A simple example: + + 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)); + 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 + ITexture* texture = driver->loadTexture("example.jpg"); + You will not have to drop the pointer to the loaded texture, + because the name of the method does not start with 'create'. + The texture is stored somewhere by the driver. */ + void grab() const { ++ReferenceCounter; } + + //! Drops the object. Decrements the reference counter by one. + /** The IReferenceCounted class provides a basic reference + counting mechanism with its methods grab() and drop(). Most + objects of the Irrlicht Engine are derived from + IReferenceCounted, and so they are reference counted. + + When you create an object in the Irrlicht engine, calling a + method which starts with 'create', an object is created, and + you get a pointer to the new object. If you no longer need the + object, you have to call drop(). This will destroy the object, + if grab() was not called in another part of you program, + because this part still needs the object. Note, that you only + need to call drop() to the object, if you created it, and the + method had a 'create' in it. + + A simple example: + + 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)); + 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 + ITexture* texture = driver->loadTexture("example.jpg"); + You will not have to drop the pointer to the loaded texture, + because the name of the method does not start with 'create'. + The texture is stored somewhere by the driver. + \return True, if the object was deleted. */ + bool drop() const + { + // someone is doing bad reference counting. + _IRR_DEBUG_BREAK_IF(ReferenceCounter <= 0) + + --ReferenceCounter; + if (!ReferenceCounter) + { + delete this; + return true; + } + + return false; + } + + //! Get the reference count. + /** \return Current value of the reference counter. */ + s32 getReferenceCount() const + { + return ReferenceCounter; + } + + //! Returns the debug name of the object. + /** The Debugname may only be set and changed by the object + itself. This method should only be used in Debug mode. + \return Returns a string, previously set by setDebugName(); */ + const c8* getDebugName() const + { + return DebugName; + } + + protected: + + //! Sets the debug name of the object. + /** The Debugname may only be set and changed by the object + itself. This method should only be used in Debug mode. + \param newName: New debug name to set. */ + void setDebugName(const c8* newName) + { + DebugName = newName; + } + + private: + + //! The debug name. + const c8* DebugName; + + //! The reference counter. Mutable to do reference counting on const objects. + mutable s32 ReferenceCounter; + }; + +} // end namespace irr + +#endif + diff --git a/include/IRenderTarget.h b/include/IRenderTarget.h new file mode 100644 index 00000000..ffe00a47 --- /dev/null +++ b/include/IRenderTarget.h @@ -0,0 +1,110 @@ +// Copyright (C) 2015 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_RENDER_TARGET_H_INCLUDED__ +#define __I_RENDER_TARGET_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "EDriverTypes.h" +#include "irrArray.h" + +namespace irr +{ +namespace video +{ + class ITexture; + + //! Enumeration of cube texture surfaces + enum E_CUBE_SURFACE + { + ECS_POSX = 0, + ECS_NEGX, + ECS_POSY, + ECS_NEGY, + ECS_POSZ, + ECS_NEGZ + }; + + //! Interface of a Render Target. + class IRenderTarget : public virtual IReferenceCounted + { + public: + + //! constructor + IRenderTarget() : DepthStencil(0), DriverType(EDT_NULL) + { + } + + //! Returns an array of previously set textures. + const core::array& getTexture() const + { + return Texture; + } + + //! Returns a of previously set depth / depth-stencil texture. + ITexture* getDepthStencil() const + { + return DepthStencil; + } + + //! Set multiple textures. + /** Set multiple textures for the render target. + \param texture Array of texture objects. These textures are used for a color outputs. + \param depthStencil Depth or packed depth-stencil texture. This texture is used as depth + or depth-stencil buffer. + \param cubeSurfaces When rendering to cube textures, set the surface to be used for each texture. Can be empty otherwise. + */ + virtual void setTexture(const core::array& texture, ITexture* depthStencil, const core::array& cubeSurfaces = core::array()) = 0; + + //! Set one texture. + void setTexture(ITexture* texture, ITexture* depthStencil) + { + core::array textureArray(1); + textureArray.push_back(texture); + + setTexture(textureArray, depthStencil); + } + + //! Set one cube surface texture. + void setTexture(ITexture* texture, ITexture* depthStencil, E_CUBE_SURFACE cubeSurface) + { + core::array textureArray(1); + textureArray.push_back(texture); + + core::array cubeSurfaces(1); + cubeSurfaces.push_back(cubeSurface); + + setTexture(textureArray, depthStencil, cubeSurfaces); + } + + //! Get driver type of render target. + E_DRIVER_TYPE getDriverType() const + { + return DriverType; + } + + protected: + + //! Textures assigned to render target. + core::array Texture; + + //! Depth or packed depth-stencil texture assigned to render target. + ITexture* DepthStencil; + + //! Active surface of cube textures + core::array CubeSurfaces; + + //! Driver type of render target. + E_DRIVER_TYPE DriverType; + + private: + // no copying (IReferenceCounted still allows that for reasons which take some time to work around) + IRenderTarget(const IRenderTarget&); + IRenderTarget& operator=(const IRenderTarget&); + }; + +} +} + +#endif diff --git a/include/ISceneCollisionManager.h b/include/ISceneCollisionManager.h new file mode 100644 index 00000000..ccfe8639 --- /dev/null +++ b/include/ISceneCollisionManager.h @@ -0,0 +1,284 @@ +// Copyright (C) 2002-2012 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_COLLISION_MANAGER_H_INCLUDED__ +#define __I_SCENE_COLLISION_MANAGER_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "vector3d.h" +#include "triangle3d.h" +#include "position2d.h" +#include "line3d.h" + +namespace irr +{ + +namespace scene +{ + class ISceneNode; + class ICameraSceneNode; + class ITriangleSelector; + class IMeshBuffer; + + struct SCollisionHit + { + //! Point of collision + core::vector3df Intersection; + + //! Triangle with which we collided + core::triangle3df Triangle; + + //! Triangle selector which contained the colliding triangle (useful when having MetaTriangleSelector) + ITriangleSelector* TriangleSelector; + + //! Node which contained the triangle (is 0 when selector doesn't have that information) + ISceneNode* Node; + + //! Meshbuffer which contained the triangle (is 0 when the selector doesn't have that information, only works when selectors are created per meshbuffer) + const IMeshBuffer* MeshBuffer; + + //! Index of selected material of the triangle in the SceneNode. Usually only valid when MeshBuffer is also set, otherwise always 0 + irr::u32 MaterialIndex; + + SCollisionHit() : TriangleSelector(0), Node(0), MeshBuffer(0), MaterialIndex(0) + {} + }; + + //! The Scene Collision Manager provides methods for performing collision tests and picking on scene nodes. + class ISceneCollisionManager : public virtual IReferenceCounted + { + public: + + //! Finds the nearest collision point of a line and lots of triangles, if there is one. + /** \param hitResult: Contains collision result when there was a collision detected. + \param ray: Line with which collisions are tested. + \param selector: TriangleSelector to be used for the collision check. + \return true if a collision was detected and false if not. */ + virtual bool getCollisionPoint(SCollisionHit& hitResult, const core::line3d& ray, + ITriangleSelector* selector) = 0; + + //! Finds the nearest collision point of a line and lots of triangles, if there is one. + /** \param ray: Line with which collisions are tested. + \param selector: TriangleSelector containing the triangles. It + can be created for example using + ISceneManager::createTriangleSelector() or + ISceneManager::createTriangleOctreeSelector(). + \param outCollisionPoint: If a collision is detected, this will + contain the position of the nearest collision to the line-start. + \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, ISceneNode*& outNode) + { + SCollisionHit hitResult; + if ( getCollisionPoint(hitResult, ray, selector) ) + { + outCollisionPoint = hitResult.Intersection; + outTriangle = hitResult.Triangle; + outNode = hitResult.Node; + return true; + } + return false; + } + + //! Collides a moving ellipsoid with a 3d world with gravity and returns the resulting new position of the ellipsoid. + /** This can be used for moving a character in a 3d world: The + character will slide at walls and is able to walk up stairs. + The method used how to calculate the collision result position + is based on the paper "Improved Collision detection and + Response" by Kasper Fauerby. + \param selector: TriangleSelector containing the triangles of + the world. It can be created for example using + ISceneManager::createTriangleSelector() or + ISceneManager::createTriangleOctreeSelector(). + \param ellipsoidPosition: Position of the ellipsoid. + \param ellipsoidRadius: Radius of the ellipsoid. + \param ellipsoidDirectionAndSpeed: Direction and speed of the + movement of the ellipsoid. + \param triout: Optional parameter where the last triangle + causing a collision is stored, if there is a collision. + \param hitPosition: Return value for the position of the collision + \param outFalling: Is set to true if the ellipsoid is falling + down, caused by gravity. + \param outNode: the node with which the ellipsoid collided (if any) + \param slidingSpeed: DOCUMENTATION NEEDED. + \param gravityDirectionAndSpeed: Direction and force of gravity. + \return New position of the ellipsoid. */ + virtual core::vector3df getCollisionResultPosition( + ITriangleSelector* selector, + const core::vector3df &ellipsoidPosition, + const core::vector3df& ellipsoidRadius, + const core::vector3df& ellipsoidDirectionAndSpeed, + core::triangle3df& triout, + core::vector3df& hitPosition, + bool& outFalling, + ISceneNode*& outNode, + f32 slidingSpeed = 0.0005f, + const core::vector3df& gravityDirectionAndSpeed + = core::vector3df(0.0f, 0.0f, 0.0f)) = 0; + + //! Returns a 3d ray which would go through the 2d screen coordinates. + /** \param pos: Screen coordinates in pixels. + \param camera: Camera from which the ray starts. If null, the + active camera is used. + \return Ray starting from the position of the camera and ending + at a length of the far value of the camera at a position which + would be behind the 2d screen coordinates. */ + virtual core::line3d getRayFromScreenCoordinates( + const core::position2d& pos, const ICameraSceneNode* camera = 0) = 0; + + //! Calculates 2d screen position from a 3d position. + /** \param pos: 3D position in world space to be transformed + into 2d. + \param camera: Camera to be used. If null, the currently active + camera is used. + \param useViewPort: Calculate screen coordinates relative to + the current view port. Please note that unless the driver does + not take care of the view port, it is usually best to get the + result in absolute screen coordinates (flag=false). + \return 2d screen coordinates which a object in the 3d world + would have if it would be rendered to the screen. If the 3d + position is behind the camera, it is set to (-1000,-1000). In + most cases you can ignore this fact, because if you use this + method for drawing a decorator over a 3d object, it will be + clipped by the screen borders. */ + virtual core::position2d getScreenCoordinatesFrom3DPosition( + const core::vector3df& pos, const ICameraSceneNode* camera=0, bool useViewPort=false) = 0; + + //! Gets the scene node, which is currently visible under the given screen coordinates, viewed from the currently active camera. + /** The collision tests are done using a bounding box for each + scene node. You can limit the recursive search so just all children of the specified root are tested. + \param pos: Position in pixel screen coordinates, under which + the returned scene node will be. + \param idBitMask: Only scene nodes with an id with bits set + like in this mask will be tested. If the BitMask is 0, this + feature is disabled. + Please note that the default node id of -1 will match with + every bitmask != 0 + \param bNoDebugObjects: Doesn't take debug objects into account + when true. These are scene nodes with IsDebugObject() = true. + \param root If different from 0, the search is limited to the children of this node. + \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(const core::position2d& pos, + s32 idBitMask=0, bool bNoDebugObjects=false, ISceneNode* root=0) =0; + + //! Returns the nearest scene node which collides with a 3d ray and whose id matches a bitmask. + /** The collision tests are done using a bounding box for each + scene node. The recursive search can be limited be specifying a scene node. + \param ray Line with which collisions are tested. + \param idBitMask Only scene nodes with an id which matches at + least one of the bits contained in this mask will be tested. + However, if this parameter is 0, then all nodes are checked. + \param bNoDebugObjects: Doesn't take debug objects into account when true. These + are scene nodes with IsDebugObject() = true. + \param root If different from 0, the search is limited to the children of this node. + \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(const core::line3d& ray, + s32 idBitMask=0, bool bNoDebugObjects=false, ISceneNode* root=0) =0; + + //! Get the scene node, which the given camera is looking at and whose id matches the bitmask. + /** A ray is simply cast from the position of the camera to + the view target position, and all scene nodes are tested + against this ray. The collision tests are done using a bounding + box for each scene node. + \param camera: Camera from which the ray is cast. + \param idBitMask: Only scene nodes with an id which matches at least one of the + bits contained in this mask will be tested. However, if this parameter is 0, then + all nodes are checked. + feature is disabled. + Please note that the default node id of -1 will match with + every bitmask != 0 + \param bNoDebugObjects: Doesn't take debug objects into account + when true. These are scene nodes with IsDebugObject() = true. + \return Scene node nearest to the camera, 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* getSceneNodeFromCameraBB(const ICameraSceneNode* camera, + s32 idBitMask=0, bool bNoDebugObjects = false) = 0; + + + //! Perform a ray/box and ray/triangle collision check on a hierarchy of scene nodes. + /** This checks all scene nodes under the specified one, first by ray/bounding + box, and then by accurate ray/triangle collision, finding the nearest collision, + and the scene node containing it. It returns the node hit, and (via output + parameters) the position of the collision, and the triangle that was hit. + + All scene nodes in the hierarchy tree under the specified node are checked. Only + nodes that are visible, with an ID that matches at least one bit in the supplied + bitmask, and which have a triangle selector are considered as candidates for being hit. + You do not have to build a meta triangle selector; the individual triangle selectors + of each candidate scene node are used automatically. + + \param ray: Line with which collisions are tested. + \param outCollisionPoint: If a collision is detected, this will contain the + position of the nearest collision. + \param outTriangle: If a collision is detected, this will contain the triangle + with which the ray collided. + \param idBitMask: Only scene nodes with an id which matches at least one of the + bits contained in this mask will be tested. However, if this parameter is 0, then + all nodes are checked. + \param collisionRootNode: the scene node at which to begin checking. Only this + node and its children will be checked. If you want to check the entire scene, + pass 0, and the root scene node will be used (this is the default). + \param noDebugObjects: when true, debug objects are not considered viable targets. + Debug objects are scene nodes with IsDebugObject() = true. + \return Returns the scene node containing the hit triangle nearest to ray.start. + If no collision is detected, then 0 is returned. */ + virtual ISceneNode* getSceneNodeAndCollisionPointFromRay( + SCollisionHit& hitResult, + const core::line3df& ray, + s32 idBitMask = 0, + ISceneNode * collisionRootNode = 0, + bool noDebugObjects = false) = 0; + + //! Perform a ray/box and ray/triangle collision check on a hierarchy of scene nodes. + /** Works same as other getSceneNodeAndCollisionPointFromRay but returns less information. + (was written before the other getSceneNodeAndCollisionPointFromRay implementation). + \param ray: Line with which collisions are tested. + \param outCollisionPoint: If a collision is detected, this will contain the + position of the nearest collision. + \param outTriangle: If a collision is detected, this will contain the triangle + with which the ray collided. + \param idBitMask: Only scene nodes with an id which matches at least one of the + bits contained in this mask will be tested. However, if this parameter is 0, then + all nodes are checked. + \param collisionRootNode: the scene node at which to begin checking. Only this + node and its children will be checked. If you want to check the entire scene, + pass 0, and the root scene node will be used (this is the default). + \param noDebugObjects: when true, debug objects are not considered viable targets. + Debug objects are scene nodes with IsDebugObject() = true. + \return Returns the scene node containing the hit triangle nearest to ray.start. + If no collision is detected, then 0 is returned. */ + virtual ISceneNode* getSceneNodeAndCollisionPointFromRay( + const core::line3df& ray, + core::vector3df& outCollisionPoint, + core::triangle3df& outTriangle, + s32 idBitMask = 0, + ISceneNode * collisionRootNode = 0, + bool noDebugObjects = false) + { + SCollisionHit hitResult; + ISceneNode* node = getSceneNodeAndCollisionPointFromRay(hitResult, ray, idBitMask, collisionRootNode, noDebugObjects); + if ( node ) + { + outCollisionPoint = hitResult.Intersection; + outTriangle = hitResult.Triangle; + } + return node; + } + + }; + +} // end namespace scene +} // end namespace irr + +#endif diff --git a/include/ISceneLoader.h b/include/ISceneLoader.h new file mode 100644 index 00000000..c71c15dd --- /dev/null +++ b/include/ISceneLoader.h @@ -0,0 +1,62 @@ +// Copyright (C) 2010-2012 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_LOADER_H_INCLUDED__ +#define __I_SCENE_LOADER_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "path.h" + +namespace irr +{ +namespace io +{ + class IReadFile; +} // end namespace io +namespace scene +{ + class ISceneNode; + class ISceneUserDataSerializer; + +//! Class which can load a scene into the scene manager. +/** If you want Irrlicht to be able to load currently unsupported +scene file formats (e.g. .vrml), then implement this and add your +new Sceneloader to the engine with ISceneManager::addExternalSceneLoader(). */ +class ISceneLoader : public virtual IReferenceCounted +{ +public: + + //! Returns true if the class might be able to load this file. + /** This decision should be based on the file extension (e.g. ".vrml") + only. + \param filename Name of the file to test. + \return True if the extension is a recognised type. */ + virtual bool isALoadableFileExtension(const io::path& filename) const = 0; + + //! Returns true if the class might be able to load this file. + /** This decision will be based on a quick look at the contents of the file. + \param file The file to test. + \return True if the extension is a recognised type. */ + virtual bool isALoadableFileFormat(io::IReadFile* file) const = 0; + + //! Loads the scene into the scene manager. + /** \param file File which contains the scene. + \param userDataSerializer: If you want to load user data which may be attached + to some some scene nodes in the file, implement the ISceneUserDataSerializer + interface and provide it as parameter here. Otherwise, simply specify 0 as this + parameter. + \param rootNode The node to load the scene into, if none is provided then the + scene will be loaded into the root node. + \return Returns true on success, false on failure. Returns 0 if loading failed. */ + virtual bool loadScene(io::IReadFile* file, ISceneUserDataSerializer* userDataSerializer=0, + ISceneNode* rootNode=0) = 0; + +}; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/ISceneManager.h b/include/ISceneManager.h new file mode 100644 index 00000000..29b4b878 --- /dev/null +++ b/include/ISceneManager.h @@ -0,0 +1,1688 @@ +// Copyright (C) 2002-2012 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_MANAGER_H_INCLUDED__ +#define __I_SCENE_MANAGER_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "irrArray.h" +#include "irrString.h" +#include "path.h" +#include "vector3d.h" +#include "dimension2d.h" +#include "SColor.h" +#include "ETerrainElements.h" +#include "ESceneNodeTypes.h" +#include "ESceneNodeAnimatorTypes.h" +#include "EMeshWriterEnums.h" +#include "SceneParameters.h" +#include "IGeometryCreator.h" +#include "ISkinnedMesh.h" +#include "IXMLWriter.h" + +namespace irr +{ + struct SKeyMap; + struct SEvent; + +namespace io +{ + class IReadFile; + class IAttributes; + class IWriteFile; + class IFileSystem; +} // end namespace io + +namespace gui +{ + class IGUIFont; + class IGUIEnvironment; +} // end namespace gui + +namespace video +{ + class IVideoDriver; + class SMaterial; + class IImage; + class ITexture; +} // end namespace video + +namespace scene +{ + //! Enumeration for render passes. + /** A parameter passed to the registerNodeForRendering() method of the ISceneManager, + specifying when the node wants to be drawn in relation to the other nodes. */ + enum E_SCENE_NODE_RENDER_PASS + { + //! No pass currently active + ESNRP_NONE =0, + + //! Camera pass. The active view is set up here. The very first pass. + ESNRP_CAMERA =1, + + //! In this pass, lights are transformed into camera space and added to the driver + ESNRP_LIGHT =2, + + //! This is used for sky boxes. + ESNRP_SKY_BOX =4, + + //! All normal objects can use this for registering themselves. + /** This value will never be returned by + ISceneManager::getSceneNodeRenderPass(). The scene manager + will determine by itself if an object is transparent or solid + and register the object as ESNRT_TRANSPARENT or ESNRP_SOLID + automatically if you call registerNodeForRendering with this + value (which is default). Note that it will register the node + only as ONE type. If your scene node has both solid and + transparent material types register it twice (one time as + ESNRP_SOLID, the other time as ESNRT_TRANSPARENT) and in the + render() method call getSceneNodeRenderPass() to find out the + current render pass and render only the corresponding parts of + the node. */ + ESNRP_AUTOMATIC =24, + + //! Solid scene nodes or special scene nodes without materials. + ESNRP_SOLID =8, + + //! Transparent scene nodes, drawn after solid nodes. They are sorted from back to front and drawn in that order. + ESNRP_TRANSPARENT =16, + + //! Transparent effect scene nodes, drawn after Transparent nodes. They are sorted from back to front and drawn in that order. + ESNRP_TRANSPARENT_EFFECT =32, + + //! Drawn after the solid nodes, before the transparent nodes, the time for drawing shadow volumes + ESNRP_SHADOW =64 + }; + + class IAnimatedMesh; + class IAnimatedMeshSceneNode; + class IBillboardSceneNode; + class IBillboardTextSceneNode; + class ICameraSceneNode; + class IDummyTransformationSceneNode; + class ILightManager; + class ILightSceneNode; + class IMesh; + class IMeshBuffer; + class IMeshCache; + class IMeshLoader; + class IMeshManipulator; + class IMeshSceneNode; + class IMeshWriter; + class IMetaTriangleSelector; + class IOctreeSceneNode; + class IParticleSystemSceneNode; + class ISceneCollisionManager; + class ISceneLoader; + class ISceneNode; + class ISceneNodeAnimator; + class ISceneNodeAnimatorCollisionResponse; + class ISceneNodeAnimatorFactory; + class ISceneNodeFactory; + class ISceneUserDataSerializer; + class IShadowVolumeSceneNode; + class ITerrainSceneNode; + class ITextSceneNode; + class ITriangleSelector; + class IVolumeLightSceneNode; + + namespace quake3 + { + struct IShader; + } // end namespace quake3 + + //! The Scene Manager manages scene nodes, mesh resources, cameras and all the other stuff. + /** All Scene nodes can be created only here. There is a always growing + list of scene nodes for lots of purposes: Indoor rendering scene nodes + like the Octree (addOctreeSceneNode()) or the terrain renderer + (addTerrainSceneNode()), different Camera scene nodes + (addCameraSceneNode(), addCameraSceneNodeMaya()), scene nodes for Light + (addLightSceneNode()), Billboards (addBillboardSceneNode()) and so on. + A scene node is a node in the hierarchical scene graph. Every scene node + may have children, which are other scene nodes. Children move relative + the their parents position. If the parent of a node is not visible, its + children won't be visible, too. In this way, it is for example easily + possible to attach a light to a moving car or to place a walking + character on a moving platform on a moving ship. + The SceneManager is also able to load 3d mesh files of different + formats. Take a look at getMesh() to find out what formats are + supported. If these formats are not enough, use + addExternalMeshLoader() to add new formats to the engine. + */ + class ISceneManager : public virtual IReferenceCounted + { + public: + + //! 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: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
FormatDescription
3D Studio (.3ds)Loader for 3D-Studio files which lots of 3D packages + * are able to export. Only static meshes are currently + * supported by this importer.
3D World Studio (.smf)Loader for Leadwerks SMF mesh files, a simple mesh format + * containing static geometry for games. The proprietary .STF texture format + * is not supported yet. This loader was originally written by Joseph Ellis.
Bliz Basic B3D (.b3d)Loader for blitz basic files, developed by Mark + * Sibly. This is the ideal animated mesh format for game + * characters as it is both rigidly defined and widely + * supported by modeling and animation software. + * As this format supports skeletal animations, an + * ISkinnedMesh will be returned by this importer.
Cartography shop 4 (.csm)Cartography Shop is a modeling program for creating + * architecture and calculating lighting. Irrlicht can + * directly import .csm files thanks to the IrrCSM library + * created by Saurav Mohapatra which is now integrated + * directly in Irrlicht. + *
COLLADA (.dae, .xml)COLLADA is an open Digital Asset Exchange Schema for + * the interactive 3D industry. There are exporters and + * importers for this format available for most of the + * big 3d packagesat http://collada.org. Irrlicht can + * import COLLADA files by using the + * ISceneManager::getMesh() method. COLLADA files need + * not contain only one single mesh but multiple meshes + * and a whole scene setup with lights, cameras and mesh + * instances, this loader can set up a scene as + * described by the COLLADA file instead of loading and + * returning one single mesh. By default, this loader + * behaves like the other loaders and does not create + * instances, but it can be switched into this mode by + * using + * SceneManager->getParameters()->setAttribute(COLLADA_CREATE_SCENE_INSTANCES, true); + * Created scene nodes will be named as the names of the + * nodes in the COLLADA file. The returned mesh is just + * a dummy object in this mode. Meshes included in the + * scene will be added into the scene manager with the + * following naming scheme: + * "path/to/file/file.dea#meshname". The loading of such + * meshes is logged. Currently, this loader is able to + + + * create meshes (made of only polygons), lights, and + * cameras. Materials and animations are currently not + * supported but this will change with future releases. + *
Delgine DeleD (.dmf)DeleD (delgine.com) is a 3D editor and level-editor + * combined into one and is specifically designed for 3D + * game-development. With this loader, it is possible to + * directly load all geometry is as well as textures and + * lightmaps from .dmf files. To set texture and + * material paths, see scene::DMF_USE_MATERIALS_DIRS. + * It is also possible to flip the alpha texture by setting + * scene::DMF_FLIP_ALPHA_TEXTURES to true and to set the + * material transparent reference value by setting + * scene::DMF_ALPHA_CHANNEL_REF to a float between 0 and + * 1. The loader is based on Salvatore Russo's .dmf + * loader, I just changed some parts of it. Thanks to + * Salvatore for his work and for allowing me to use his + * code in Irrlicht and put it under Irrlicht's license. + * For newer and more enhanced versions of the loader, + * take a look at delgine.com. + *
DirectX (.x)Platform independent importer (so not D3D-only) for + * .x files. Most 3D packages can export these natively + * and there are several tools for them available, e.g. + * the Maya exporter included in the DX SDK. + * .x files can include skeletal animations and Irrlicht + * is able to play and display them, users can manipulate + * the joints via the ISkinnedMesh interface. Currently, + * Irrlicht only supports uncompressed .x files.
Half-Life model (.mdl)This loader opens Half-life 1 models, it was contributed + * by Fabio Concas and adapted by Thomas Alten.
Irrlicht Mesh (.irrMesh)This is a static mesh format written in XML, native + * to Irrlicht and written by the irr mesh writer. + * This format is exported by the CopperCube engine's + * lightmapper.
LightWave (.lwo)Native to NewTek's LightWave 3D, the LWO format is well + * known and supported by many exporters. This loader will + * import LWO2 models including lightmaps, bumpmaps and + * reflection textures.
Maya (.obj)Most 3D software can create .obj files which contain + * static geometry without material data. The material + * files .mtl are also supported. This importer for + * Irrlicht can load them directly.
Milkshape (.ms3d).MS3D files contain models and sometimes skeletal + * animations from the Milkshape 3D modeling and animation + * software. Like the other skeletal mesh loaders, joints + * are exposed via the ISkinnedMesh animated mesh type.
My3D (.my3d).my3D is a flexible 3D file format. The My3DTools + * contains plug-ins to export .my3D files from several + * 3D packages. With this built-in importer, Irrlicht + * can read and display those files directly. This + * loader was written by Zhuck Dimitry who also created + * the whole My3DTools package. + *
OCT (.oct)The oct file format contains 3D geometry and + * lightmaps and can be loaded directly by Irrlicht. OCT + * files
can be created by FSRad, Paul Nette's + * radiosity processor or exported from Blender using + * OCTTools which can be found in the exporters/OCTTools + * directory of the SDK. Thanks to Murphy McCauley for + * creating all this.
OGRE Meshes (.mesh)Ogre .mesh files contain 3D data for the OGRE 3D + * engine. Irrlicht can read and display them directly + * with this importer. To define materials for the mesh, + * copy a .material file named like the corresponding + * .mesh file where the .mesh file is. (For example + * ogrehead.material for ogrehead.mesh). Thanks to + * Christian Stehno who wrote and contributed this + * loader.
Pulsar LMTools (.lmts)LMTools is a set of tools (Windows & Linux) for + * creating lightmaps. Irrlicht can directly read .lmts + * files thanks to
the importer created by Jonas + * Petersen. + * Notes for
this version of the loader:
+ * - It does not recognize/support user data in the + * *.lmts files.
+ * - The TGAs generated by LMTools don't work in + * Irrlicht for some reason (the textures are upside + * down). Opening and resaving them in a graphics app + * will solve the problem.
Quake 3 levels (.bsp)Quake 3 is a popular game by IDSoftware, and .pk3 + * files contain .bsp files and textures/lightmaps + * describing huge prelighted levels. Irrlicht can read + * .pk3 and .bsp files directly and thus render Quake 3 + * levels directly. Written by Nikolaus Gebhardt + * enhanced by Dean P. Macri with the curved surfaces + * feature.
Quake 2 models (.md2)Quake 2 models are characters with morph target + * animation. Irrlicht can read, display and animate + * them directly with this importer.
Quake 3 models (.md3)Quake 3 models are characters with morph target + * animation, they contain mount points for weapons and body + * parts and are typically made of several sections which are + * manually joined together.
Stanford Triangle (.ply)Invented by Stanford University and known as the native + * format of the infamous "Stanford Bunny" model, this is a + * popular static mesh format used by 3D scanning hardware + * and software. This loader supports extremely large models + * in both ASCII and binary format, but only has rudimentary + * material support in the form of vertex colors and texture + * coordinates.
Stereolithography (.stl)The STL format is used for rapid prototyping and + * computer-aided manufacturing, thus has no support for + * materials.
+ * + * To load and display a mesh quickly, just do this: + * \code + * SceneManager->addAnimatedMeshSceneNode( + * SceneManager->getMesh("yourmesh.3ds")); + * \endcode + * 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. + * \param alternativeCacheName: In case you want to have the mesh under another name in the cache (to create real copies) + * \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 io::path& filename, const io::path& alternativeCacheName=io::path("")) = 0; + + //! 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. + \return NULL if failed and pointer to the mesh if successful. + This pointer should not be dropped. See + IReferenceCounted::drop() for more information. */ + virtual IAnimatedMesh* getMesh(io::IReadFile* file) = 0; + + //! Get interface to the mesh cache which is shared between 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; + + //! 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; + + //! 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; + + //! Get the active FileSystem + /** \return Pointer to the FileSystem + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual io::IFileSystem* getFileSystem() = 0; + + //! adds Volume Lighting Scene Node. + /** Example Usage: + scene::IVolumeLightSceneNode * n = smgr->addVolumeLightSceneNode(0, -1, + 32, 32, //Subdivide U/V + video::SColor(0, 180, 180, 180), //foot color + video::SColor(0, 0, 0, 0) //tail color + ); + if (n) + { + 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), + const video::SColor tail = video::SColor(0, 0, 0, 0), + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) = 0; + + //! Adds a cube scene node + /** \param size: Size of the cube, uniformly in each dimension. + \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: Position of the space relative to its parent + where the scene node will be placed. + \param rotation: Initial rotation of the scene node. + \param scale: Initial scale of the scene node. + \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, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) = 0; + + //! Adds a sphere scene node of the given radius and detail + /** \param radius: Radius of the sphere. + \param polyCount: The number of vertices in horizontal and + vertical direction. The total polyCount of the sphere is + polyCount*polyCount. This parameter must be less than 256 to + stay within the 16-bit limit of the indices of a meshbuffer. + \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: Position of the space relative to its parent + where the scene node will be placed. + \param rotation: Initial rotation of the scene node. + \param scale: Initial scale of the scene node. + \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, + ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) = 0; + + //! Adds a scene node for rendering an animated mesh model. + /** \param mesh: Pointer to the loaded animated mesh to be displayed. + \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: Initial 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 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, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f), + bool alsoAddIfMeshPointerZero=false) = 0; + + //! Adds a scene node for rendering a static mesh. + /** \param mesh: Pointer to the loaded static mesh to be displayed. + \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: Initial 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 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), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f), + bool alsoAddIfMeshPointerZero=false) = 0; + + //! Adds a scene node for rendering a animated water surface mesh. + /** Looks really good when the Material type EMT_TRANSPARENT_REFLECTION + is used. + \param waveHeight: Height of the water waves. + \param waveSpeed: Speed of the water waves. + \param waveLength: Length of a water wave. + \param mesh: Pointer to the loaded static mesh to be displayed with water waves on it. + \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: Initial 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 ISceneNode* addWaterSurfaceSceneNode(IMesh* mesh, + f32 waveHeight=2.0f, f32 waveSpeed=300.0f, f32 waveLength=10.0f, + ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) = 0; + + + //! Adds a scene node for rendering using a octree 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 octree 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 octree 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 octree if successful, otherwise 0. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual IOctreeSceneNode* addOctreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent=0, + s32 id=-1, s32 minimalPolysPerNode=512, bool alsoAddIfMeshPointerZero=false) = 0; + + //! Adds a scene node for rendering using a octree 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, much + faster then a bsp tree. + \param mesh: The mesh containing all geometry from which the octree will be build. + \param parent: Parent node of the octree 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 octree if successful, otherwise 0. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual IOctreeSceneNode* addOctreeSceneNode(IMesh* mesh, ISceneNode* parent=0, + s32 id=-1, s32 minimalPolysPerNode=256, bool alsoAddIfMeshPointerZero=false) = 0; + + //! Adds a camera scene node to the scene graph and sets it as active camera. + /** 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. + 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. + \param makeActive Flag whether this camera should become the active one. + Make sure you always have one active 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, bool makeActive=true) = 0; + + //! Adds a maya style user controlled camera scene node to the scene graph. + /** This is a standard camera with an animator that provides mouse control similar + to camera in the 3D Software Maya by Alias Wavefront. + The camera does not react on setPosition anymore after applying this animator. Instead + use setTarget, to fix the target the camera the camera hovers around. And setDistance + to set the current distance from that target, i.e. the radius of the orbit the camera + hovers on. + \param parent: Parent scene node of the camera. Can be null. + \param rotateSpeed: Rotation speed of the camera. + \param zoomSpeed: Zoom speed of the camera. + \param translationSpeed: TranslationSpeed of the camera. + \param id: id of the camera. This id can be used to identify the camera. + \param distance Initial distance of the camera from the object + \param makeActive Flag whether this camera should become the active one. + Make sure you always have one active camera. + \return Returns a 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* addCameraSceneNodeMaya(ISceneNode* parent=0, + f32 rotateSpeed=-1500.f, f32 zoomSpeed=200.f, + f32 translationSpeed=1500.f, s32 id=-1, f32 distance=70.f, + bool makeActive=true) =0; + + //! Adds a camera scene node with an animator which provides mouse and keyboard control appropriate for first person shooters (FPS). + /** This FPS camera is intended to provide a demonstration of a + camera that behaves like a typical First Person Shooter. It is + useful for simple demos and prototyping but is not intended to + provide a full solution for a production quality game. It binds + the camera scene node rotation to the look-at target; @see + ICameraSceneNode::bindTargetAndRotation(). With this camera, + you look with the mouse, and move with cursor keys. If you want + to change the key layout, you can specify your own keymap. For + example to make the camera be controlled by the cursor keys AND + the keys W,A,S, and D, do something like this: + \code + SKeyMap keyMap[8]; + keyMap[0].Action = EKA_MOVE_FORWARD; + keyMap[0].KeyCode = KEY_UP; + keyMap[1].Action = EKA_MOVE_FORWARD; + keyMap[1].KeyCode = KEY_KEY_W; + + keyMap[2].Action = EKA_MOVE_BACKWARD; + keyMap[2].KeyCode = KEY_DOWN; + keyMap[3].Action = EKA_MOVE_BACKWARD; + keyMap[3].KeyCode = KEY_KEY_S; + + keyMap[4].Action = EKA_STRAFE_LEFT; + keyMap[4].KeyCode = KEY_LEFT; + keyMap[5].Action = EKA_STRAFE_LEFT; + keyMap[5].KeyCode = KEY_KEY_A; + + keyMap[6].Action = EKA_STRAFE_RIGHT; + keyMap[6].KeyCode = KEY_RIGHT; + keyMap[7].Action = EKA_STRAFE_RIGHT; + keyMap[7].KeyCode = KEY_KEY_D; + + camera = sceneManager->addCameraSceneNodeFPS(0, 100, 500, -1, keyMap, 8); + \endcode + \param parent: Parent scene node of the camera. Can be null. + \param rotateSpeed: Speed in degrees with which the camera is + rotated. This can be done only with the mouse. + \param moveSpeed: Speed in units per millisecond with which + the camera is moved. Movement is done with the cursor keys. + \param id: id of the camera. This id can be used to identify + the camera. + \param keyMapArray: Optional pointer to an array of a keymap, + specifying what keys should be used to move the camera. If this + is null, the default keymap is used. You can define actions + more then one time in the array, to bind multiple keys to the + same action. + \param keyMapSize: Amount of items in the keymap array. + \param noVerticalMovement: Setting this to true makes the + camera only move within a horizontal plane, and disables + vertical movement as known from most ego shooters. Default is + '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. + \param makeActive Flag whether this camera should become the active one. + Make sure you always have one active camera. + \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 = 0.5f, s32 id=-1, + SKeyMap* keyMapArray=0, s32 keyMapSize=0, bool noVerticalMovement=false, + f32 jumpSpeed = 0.f, bool invertMouse=false, + bool makeActive=true) = 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 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), + f32 radius=100.0f, s32 id=-1) = 0; + + //! 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 size Size of the billboard. This size is 2 dimensional + because a billboard only has width and height. + \param position Position of the space relative to its parent + where the billboard will be placed. + \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, + video::SColor colorTop = 0xFFFFFFFF, video::SColor colorBottom = 0xFFFFFFFF) = 0; + + //! 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 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 radius The Radius of the 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, + f32 texturePercentage=0.9, f32 spherePercentage=2.0,f32 radius = 1000.f, + ISceneNode* parent=0, s32 id=-1) = 0; + + //! Adds a particle system scene node to the scene graph. + /** \param withDefaultEmitter: Creates a default working point emitter + which emits 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: Initial 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), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) = 0; + + //! 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. + + 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 algorithm 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 behavior. + \param patchSize: patch size of the terrain. Only change if you + know what you are doing, this might lead to strange behavior. + \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 io::path& heightMapFileName, + ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& rotation = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& scale = core::vector3df(1.0f,1.0f,1.0f), + video::SColor vertexColor = video::SColor(255,255,255,255), + s32 maxLOD=5, E_TERRAIN_PATCH_SIZE patchSize=ETPS_17, s32 smoothFactor=0, + bool addAlsoIfHeightmapEmpty = false) = 0; + + //! 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 information 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 behavior. + \param patchSize: patch size of the terrain. Only change if you + know what you are doing, this might lead to strange behavior. + \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, + const core::vector3df& position = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& rotation = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& scale = core::vector3df(1.0f,1.0f,1.0f), + video::SColor vertexColor = video::SColor(255,255,255,255), + s32 maxLOD=5, E_TERRAIN_PATCH_SIZE patchSize=ETPS_17, s32 smoothFactor=0, + bool addAlsoIfHeightmapEmpty = false) = 0; + + //! Adds a quake3 scene node to the scene graph. + /** A Quake3 Scene renders multiple meshes for a specific HighLanguage Shader (Quake3 Style ) + \return Pointer to the quake3 scene node if successful, otherwise NULL. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual IMeshSceneNode* addQuake3SceneNode(const IMeshBuffer* meshBuffer, const quake3::IShader * shader, + ISceneNode* parent=0, s32 id=-1 + ) = 0; + + + //! Adds an empty scene node to the scene graph. + /** Can be used for doing advanced transformations + 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 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; + + //! Adds a text scene node, which is able to display 2d text at a position in three dimensional space + virtual ITextSceneNode* addTextSceneNode(gui::IGUIFont* font, const wchar_t* text, + video::SColor color=video::SColor(100,255,255,255), + ISceneNode* parent = 0, const core::vector3df& position = core::vector3df(0,0,0), + s32 id=-1) = 0; + + //! Adds a text scene node, which uses billboards. The node, and the text on it, will scale with distance. + /** + \param font The font to use on the billboard. Pass 0 to use the GUI environment's default font. + \param text The text to display on the billboard. + \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 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, + const core::dimension2d& size = core::dimension2d(10.0f, 10.0f), + const core::vector3df& position = core::vector3df(0,0,0), s32 id=-1, + video::SColor colorTop = 0xFFFFFFFF, video::SColor colorBottom = 0xFFFFFFFF) = 0; + + //! 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 specify + 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.0f x 100.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 io::path& 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 heightmap 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 io::path& 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; + + //! add a static arrow mesh to the meshpool + /** \param name Name of the mesh + \param vtxColorCylinder color of the cylinder + \param vtxColorCone color of the cone + \param tesselationCylinder Number of quads the cylinder side consists of + \param tesselationCone Number of triangles the cone's roof consists of + \param height Total height of the arrow + \param cylinderHeight Total height of the cylinder, should be lesser than total height + \param widthCylinder Diameter of the cylinder + \param widthCone 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 io::path& name, + video::SColor vtxColorCylinder=0xFFFFFFFF, + video::SColor vtxColorCone=0xFFFFFFFF, + u32 tesselationCylinder=4, u32 tesselationCone=8, + f32 height=1.f, f32 cylinderHeight=0.6f, + f32 widthCylinder=0.05f, f32 widthCone=0.3f) = 0; + + //! add a static sphere mesh to the meshpool + /** \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 + \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 io::path& name, + f32 radius=5.f, u32 polyCountX = 16, + u32 polyCountY = 16) = 0; + + //! Add a volume light mesh to the meshpool + /** \param name Name of the mesh + \param SubdivideU Horizontal subdivision count + \param SubdivideV Vertical subdivision count + \param FootColor Color of the bottom of the light + \param TailColor Color of the top of the light + \return Pointer to the volume light mesh if successful, otherwise 0. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. + */ + virtual IAnimatedMesh* addVolumeLightMesh(const io::path& name, + const u32 SubdivideU = 32, const u32 SubdivideV = 32, + const video::SColor FootColor = video::SColor(51, 0, 230, 180), + const video::SColor TailColor = video::SColor(0, 0, 0, 0)) = 0; + + //! 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 Pointer to the root scene node. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual ISceneNode* getRootSceneNode() = 0; + + //! 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 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; + + //! 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 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; + + //! 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 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. + /** \param type: Type of scene node to find (ESNT_ANY will return all child nodes). + \param outNodes: results will be added to this array (outNodes is not cleared). + \param start: Scene node to start from. This node and all children of this scene + node are checked (recursively, so also children of children, etc). If null is specified, + the root scene node is taken as start-node. */ + virtual void getSceneNodesFromType(ESCENE_NODE_TYPE type, + core::array& outNodes, + 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. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual ICameraSceneNode* getActiveCamera() const =0; + + //! Sets the currently active camera. + /** The previous active camera will be deactivated. + \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; + + //! Get the current color of shadows. + virtual video::SColor getShadowColor() const = 0; + + //! Create a shadow volume scene node to be used with custom nodes + /** Use this if you implement your own SceneNodes and need shadow volumes in them. + Otherwise you should generally use addShadowVolumeSceneNode functions from IMeshSceneNode or IAnimatedMeshSceneNode.*/ + virtual IShadowVolumeSceneNode* createShadowVolumeSceneNode(const IMesh* shadowMesh, ISceneNode* parent, s32 id, bool zfailmethod, f32 infinity) = 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 ) */ + virtual u32 registerNodeForRendering(ISceneNode* node, + E_SCENE_NODE_RENDER_PASS pass = ESNRP_AUTOMATIC) = 0; + + //! Clear all nodes which are currently registered for rendering + /** Usually you don't have to care about this as drawAll will clear nodes + after rendering them. But sometimes you might have to manully reset this. + For example when you deleted nodes between registering and rendering. */ + virtual void clearAllRegisteredNodesForRendering() = 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. */ + virtual void drawAll() = 0; + + //! Creates a rotation animator, which rotates the attached scene node around itself. + /** \param rotationSpeed Specifies the speed of the animation in degree per 10 milliseconds. + \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& rotationSpeed) = 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: 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. (phase) + \param radiusEllipsoid: if radiusEllipsoid != 0 then radius2 from a ellipsoid + begin. Value is in multiples of a circle, i.e. 0.5 is half way around. (phase) + \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), + f32 startPosition = 0.f, + f32 radiusEllipsoid = 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 milliseconds 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. + \param pingpong Flag to set whether the animator should fly + back from end to start again. + \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, bool pingpong = 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 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 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 meters, 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), + const core::vector3df& gravityPerSecond = core::vector3df(0,-10.0f,0), + const core::vector3df& ellipsoidTranslation = core::vector3df(0,0,0), + f32 slidingValue = 0.0005f) = 0; + + //! 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. + 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, bool loop=true, bool pingpong=false) = 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::createOctreeTriangleSelector(). + Please note that the created triangle selector is not automatically attached + to the scene node. You will have to call ISceneNode::setTriangleSelector() + for this. To create and attach a triangle selector is done like this: + \code + ITriangleSelector* s = sceneManager->createTriangleSelector(yourMesh, + yourSceneNode); + yourSceneNode->setTriangleSelector(s); + s->drop(); + \endcode + \param mesh: Mesh of which the triangles are taken. + \param node: Scene node of which transformation is used. + \param separateMeshbuffers: When true it's possible to get information which meshbuffer + got hit in collision tests. But has a slight speed cost. + \return The selector, or null if not successful. + If you no longer need the selector, you should call ITriangleSelector::drop(). + See IReferenceCounted::drop() for more information. */ + virtual ITriangleSelector* createTriangleSelector(IMesh* mesh, ISceneNode* node, bool separateMeshbuffers=false) = 0; + + //! Creates a simple ITriangleSelector, based on a meshbuffer. + /** + This is a static selector which won't update when the mesh changes. + \param meshBuffer Triangles of that meshbuffer are used + \param materialIndex If you pass a material index that index can be returned by the triangle selector. + \para node: Scene node of which transformation is used. + */ + virtual ITriangleSelector* createTriangleSelector(const IMeshBuffer* meshBuffer, irr::u32 materialIndex, ISceneNode* node) = 0; + + //! Creates a simple ITriangleSelector, based on an animated mesh scene node. + /** Details of the mesh associated with the node will be extracted internally. + \param node The animated mesh scene node from which to build the selector + \param separateMeshbuffers: When true it's possible to get information which meshbuffer + got hit in collision tests. But has a slight speed cost. + */ + virtual ITriangleSelector* createTriangleSelector(IAnimatedMeshSceneNode* node, bool separateMeshbuffers=false) = 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 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 octree. + /** Triangle selectors + can be used for doing collision detection. This triangle selector is + optimized for huge amounts of triangle, it organizes them in an octree. + Please note that the created triangle selector is not automatically attached + to the scene node. You will have to call ISceneNode::setTriangleSelector() + for this. To create and attach a triangle selector is done like this: + \code + ITriangleSelector* s = sceneManager->createOctreeTriangleSelector(yourMesh, + yourSceneNode); + yourSceneNode->setTriangleSelector(s); + s->drop(); + \endcode + For more information and examples on this, take a look at the collision + tutorial in the SDK. + \param 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 than this value, it will not be split into + smaller nodes. + \return The selector, or null if not successful. + If you no longer need the selector, you should call ITriangleSelector::drop(). + See IReferenceCounted::drop() for more information. */ + virtual ITriangleSelector* createOctreeTriangleSelector(IMesh* mesh, + ISceneNode* node, s32 minimalPolysPerNode=32) = 0; + + //! Creates a Triangle Selector for a single meshbuffer, optimized by an octree. + /** Triangle selectors + can be used for doing collision detection. This triangle selector is + optimized for huge amounts of triangle, it organizes them in an octree. + Please note that the created triangle selector is not automatically attached + to the scene node. You will have to call ISceneNode::setTriangleSelector() + for this. To create and attach a triangle selector is done like this: + \code + ITriangleSelector* s = sceneManager->createOctreeTriangleSelector(yourMesh, + yourSceneNode); + yourSceneNode->setTriangleSelector(s); + s->drop(); + \endcode + For more information and examples on this, take a look at the collision + tutorial in the SDK. + \param meshBuffer: Meshbuffer of which the triangles are taken. + \param materialIndex: Setting this value allows the triangle selector to return the material index + \param node: Scene node of which visibility and transformation is used. + \param minimalPolysPerNode: Specifies the minimal polygons contained a octree node. + If a node gets less polys than this value, it will not be split into + smaller nodes. + \return The selector, or null if not successful. + If you no longer need the selector, you should call ITriangleSelector::drop(). + See IReferenceCounted::drop() for more information. */ + virtual ITriangleSelector* createOctreeTriangleSelector(IMeshBuffer* meshBuffer, irr::u32 materialIndex, + ISceneNode* node, s32 minimalPolysPerNode=32) = 0; + + //! //! Creates a Triangle Selector, optimized by an octree. + /** \deprecated Use createOctreeTriangleSelector instead. This method may be removed by Irrlicht 1.9. */ + _IRR_DEPRECATED_ ITriangleSelector* createOctTreeTriangleSelector(IMesh* mesh, + ISceneNode* node, s32 minimalPolysPerNode=32) + { + return createOctreeTriangleSelector(mesh, node, minimalPolysPerNode); + } + + //! 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 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. + \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 to recompile the engine. + \param externalLoader: Implementation of a new mesh loader. */ + virtual void addExternalMeshLoader(IMeshLoader* externalLoader) = 0; + + //! Returns the number of mesh loaders supported by Irrlicht at this time + virtual u32 getMeshLoaderCount() const = 0; + + //! Retrieve the given mesh loader + /** \param index The index of the loader to retrieve. This parameter is an 0-based + array index. + \return A pointer to the specified loader, 0 if the index is incorrect. */ + virtual IMeshLoader* getMeshLoader(u32 index) const = 0; + + //! Adds an external scene 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. .vrml), just implement + the ISceneLoader interface in your loading class and add it with this method. + Using this method it is also possible to override the built-in scene loaders + with newer or updated versions without the need to recompile the engine. + \param externalLoader: Implementation of a new mesh loader. */ + virtual void addExternalSceneLoader(ISceneLoader* externalLoader) = 0; + + //! Returns the number of scene loaders supported by Irrlicht at this time + virtual u32 getSceneLoaderCount() const = 0; + + //! Retrieve the given scene loader + /** \param index The index of the loader to retrieve. This parameter is an 0-based + array index. + \return A pointer to the specified loader, 0 if the index is incorrect. */ + virtual ISceneLoader* getSceneLoader(u32 index) const = 0; + + //! 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; + + //! 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 immediately + 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 delete. */ + 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. */ + virtual bool postEventFromUser(const SEvent& event) = 0; + + //! Clears the whole scene. + /** All scene nodes are removed. */ + virtual void clear() = 0; + + //! Get interface to the parameters set in this scene. + /** String parameters can be used by plugins and mesh loaders. + See COLLADA_CREATE_SCENE_INSTANCES and DMF_USE_MATERIALS_DIRS */ + virtual io::IAttributes* getParameters() = 0; + + //! 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. */ + virtual E_SCENE_NODE_RENDER_PASS getSceneNodeRenderPass() const = 0; + + //! 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. + /** Use this to extend the scene manager with new scene node types which it should be + able to create automatically, for example when loading data from xml files. */ + virtual void registerSceneNodeFactory(ISceneNodeFactory* factoryToAdd) = 0; + + //! Get amount of registered scene node factories. + virtual u32 getRegisteredSceneNodeFactoryCount() const = 0; + + //! 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; + + //! 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. + /** Use this to extend the scene manager with new scene node animator types which it should be + able to create automatically, for example when loading data from xml files. */ + virtual void registerSceneNodeAnimatorFactory(ISceneNodeAnimatorFactory* factoryToAdd) = 0; + + //! Get amount of registered scene node animator factories. + virtual u32 getRegisteredSceneNodeAnimatorFactoryCount() const = 0; + + //! 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; + + //! Get typename from a scene node type or null if not found + virtual const c8* getSceneNodeTypeName(ESCENE_NODE_TYPE type) = 0; + + //! Returns a typename from a scene node animator type or null if not found + virtual const c8* getAnimatorTypeName(ESCENE_NODE_ANIMATOR_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 scene node animator based on its type name + /** \param typeName: Type of the scene node animator to add. + \param target: Target scene node of the new animator. + \return Returns pointer to the new scene node animator or null if not successful. You need to + drop this pointer after calling this, see IReferenceCounted::drop() for details. */ + virtual ISceneNodeAnimator* createSceneNodeAnimator(const char* typeName, ISceneNode* target=0) = 0; + + //! Creates a new scene manager. + /** This can be used to easily draw and/or store two + independent scenes at the same time. The mesh cache will be + shared between all existing scene managers, which means if you + load a mesh in the original scene manager using for example + getMesh(), the mesh will be available in all other scene + managers too, without loading. + The original/main scene manager will still be there and + accessible via IrrlichtDevice::getSceneManager(). If you need + input event in this new scene manager, for example for FPS + cameras, you'll need to forward input to this manually: Just + implement an IEventReceiver and call + yourNewSceneManager->postEventFromUser(), and return true so + that the original scene manager doesn't get the event. + Otherwise, all input will go to the main scene manager + automatically. + If you no longer need the new scene manager, you should call + ISceneManager::drop(). + See IReferenceCounted::drop() for more information. */ + virtual ISceneManager* createNewSceneManager(bool cloneContent=false) = 0; + + //! Saves the current scene into a file. + /** Scene nodes with the option isDebugObject set to true are + not being saved. The scene is usually written to an .irr file, + an xml based format. .irr files can Be edited with the Irrlicht + Engine Editor, irrEdit (http://www.ambiera.com/irredit/). To + load .irr files again, see ISceneManager::loadScene(). + \param filename Name of the file. + \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. + \param node Node which is taken as the top node of the scene. + This node and all of its descendants are saved into the scene + file. Pass 0 or the scene manager to save the full scene (which + is also the default). + \return True if successful. */ + virtual bool saveScene(const io::path& filename, ISceneUserDataSerializer* userDataSerializer=0, ISceneNode* node=0) = 0; + + //! Saves the current scene into a file. + /** Scene nodes with the option isDebugObject set to true are + not being saved. The scene is usually written to an .irr file, + an xml based format. .irr files can Be edited with the Irrlicht + Engine Editor, irrEdit (http://www.ambiera.com/irredit/). To + load .irr files again, see ISceneManager::loadScene(). + \param file File where the scene is saved into. + \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. + \param node Node which is taken as the top node of the scene. + This node and all of its descendants are saved into the scene + file. Pass 0 or the scene manager to save the full scene (which + is also the default). + \return True if successful. */ + virtual bool saveScene(io::IWriteFile* file, ISceneUserDataSerializer* userDataSerializer=0, ISceneNode* node=0) = 0; + + //! Saves the current scene into a file. + /** Scene nodes with the option isDebugObject set to true are + not being saved. The scene is usually written to an .irr file, + an xml based format. .irr files can Be edited with the Irrlicht + Engine Editor, irrEdit (http://www.ambiera.com/irredit/). To + load .irr files again, see ISceneManager::loadScene(). + \param writer XMLWriter with which the scene is saved. + \param currentPath Path which is used for relative file names. + Usually the directory of the file written into. + \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. + \param node Node which is taken as the top node of the scene. + This node and all of its descendants are saved into the scene + file. Pass 0 or the scene manager to save the full scene (which + is also the default). + \return True if successful. */ + virtual bool saveScene(io::IXMLWriter* writer, const io::path& currentPath, ISceneUserDataSerializer* userDataSerializer=0, ISceneNode* node=0) = 0; + + //! Loads a scene. Note that the current scene is not cleared before. + /** The scene is usually loaded from an .irr file, an xml based + format, but other scene formats can be added to the engine via + ISceneManager::addExternalSceneLoader. .irr files can Be edited + with the Irrlicht Engine Editor, irrEdit + (http://www.ambiera.com/irredit/) or saved directly by the engine + using ISceneManager::saveScene(). + \param filename Name of the file to load from. + \param userDataSerializer If you want to load user data + possibily saved in that file for some scene nodes in the file, + implement the ISceneUserDataSerializer interface and provide it + as parameter here. Otherwise, simply specify 0 as this + parameter. + \param rootNode Node which is taken as the root node of the + scene. Pass 0 to add the scene directly to the scene manager + (which is also the default). + \return True if successful. */ + virtual bool loadScene(const io::path& filename, ISceneUserDataSerializer* userDataSerializer=0, ISceneNode* rootNode=0) = 0; + + //! Loads a scene. Note that the current scene is not cleared before. + /** The scene is usually loaded from an .irr file, an xml based + format, but other scene formats can be added to the engine via + ISceneManager::addExternalSceneLoader. .irr files can Be edited + with the Irrlicht Engine Editor, irrEdit + (http://www.ambiera.com/irredit/) or saved directly by the engine + using ISceneManager::saveScene(). + \param file File where the scene is loaded from. + \param userDataSerializer If you want to load user data + saved in that file for some scene nodes in the file, + implement the ISceneUserDataSerializer interface and provide it + as parameter here. Otherwise, simply specify 0 as this + parameter. + \param rootNode Node which is taken as the root node of the + scene. Pass 0 to add the scene directly to the scene manager + (which is also the default). + \return True if successful. */ + virtual bool loadScene(io::IReadFile* file, ISceneUserDataSerializer* userDataSerializer=0, ISceneNode* rootNode=0) = 0; + + //! 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; + + //! Get a skinned mesh, which is not available as header-only code + /** Note: You need to drop() the pointer after use again, see IReferenceCounted::drop() + for details. */ + virtual ISkinnedMesh* createSkinnedMesh() = 0; + + //! Sets ambient color of the scene + virtual void setAmbientLight(const video::SColorf &ambientColor) = 0; + + //! 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 behavior. */ + virtual void setLightManager(ILightManager* lightManager) = 0; + + //! Get current render pass. + virtual E_SCENE_NODE_RENDER_PASS getCurrentRenderPass() const =0; + + //! Set current render pass. + virtual void setCurrentRenderPass(E_SCENE_NODE_RENDER_PASS nextPass) =0; + + //! Get an instance of a geometry creator. + /** The geometry creator provides some helper methods to create various types of + basic geometry. This can be useful for custom scene nodes. */ + virtual const IGeometryCreator* getGeometryCreator(void) const = 0; + + //! Check if node is culled in current view frustum + /** Please note that depending on the used culling method this + check can be rather coarse, or slow. A positive result is + correct, though, i.e. if this method returns true the node is + positively not visible. The node might still be invisible even + if this method returns false. + \param node The scene node which is checked for culling. + \return True if node is not visible in the current scene, else + false. */ + virtual bool isCulled(const ISceneNode* node) const =0; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/ISceneNode.h b/include/ISceneNode.h new file mode 100644 index 00000000..71910276 --- /dev/null +++ b/include/ISceneNode.h @@ -0,0 +1,874 @@ +// Copyright (C) 2002-2012 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_H_INCLUDED__ +#define __I_SCENE_NODE_H_INCLUDED__ + +#include "IAttributeExchangingObject.h" +#include "ESceneNodeTypes.h" +#include "ECullingTypes.h" +#include "EDebugSceneTypes.h" +#include "ISceneNodeAnimator.h" +#include "ITriangleSelector.h" +#include "SMaterial.h" +#include "irrString.h" +#include "aabbox3d.h" +#include "matrix4.h" +#include "irrList.h" +#include "IAttributes.h" + +namespace irr +{ +namespace scene +{ + class ISceneManager; + + //! Typedef for list of scene nodes + typedef core::list ISceneNodeList; + //! Typedef for list of scene node animators + typedef core::list ISceneNodeAnimatorList; + + //! Scene node interface. + /** A scene node is a node in the hierarchical scene graph. Every scene + node may have children, which are also scene nodes. Children move + relative to their parent's position. If the parent of a node is not + visible, its children won't be visible either. In this way, it is for + example easily possible to attach a light to a moving car, or to place + a walking character on a moving platform on a moving ship. + */ + class ISceneNode : virtual public io::IAttributeExchangingObject + { + public: + + //! Constructor + ISceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id=-1, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) + : RelativeTranslation(position), RelativeRotation(rotation), RelativeScale(scale), + Parent(0), SceneManager(mgr), TriangleSelector(0), ID(id), + AutomaticCullingState(EAC_BOX), DebugDataVisible(EDS_OFF), + IsVisible(true), IsDebugObject(false) + { + if (parent) + parent->addChild(this); + + updateAbsolutePosition(); + } + + + //! Destructor + virtual ~ISceneNode() + { + // delete all children + removeAll(); + + // delete all animators + ISceneNodeAnimatorList::Iterator ait = Animators.begin(); + for (; ait != Animators.end(); ++ait) + (*ait)->drop(); + + if (TriangleSelector) + TriangleSelector->drop(); + } + + + //! This method is called just before the rendering process of the whole scene. + /** Nodes may register themselves in the render pipeline during this call, + precalculate the geometry which should be renderered, and prevent their + children from being able to register themselves if they are clipped by simply + not calling their OnRegisterSceneNode method. + If you are implementing your own scene node, you should overwrite this method + with an implementation code looking like this: + \code + if (IsVisible) + SceneManager->registerNodeForRendering(this); + + ISceneNode::OnRegisterSceneNode(); + \endcode + */ + virtual void OnRegisterSceneNode() + { + if (IsVisible) + { + ISceneNodeList::Iterator it = Children.begin(); + for (; it != Children.end(); ++it) + (*it)->OnRegisterSceneNode(); + } + } + + + //! OnAnimate() is called just before rendering the whole scene. + /** Nodes may calculate or store animations here, and may do other useful things, + depending on what they are. Also, OnAnimate() should be called for all + child scene nodes here. This method will be called once per frame, independent + of whether the scene node is visible or not. + \param timeMs Current time in milliseconds. */ + virtual void OnAnimate(u32 timeMs) + { + if (IsVisible) + { + // animate this node with all animators + + ISceneNodeAnimatorList::Iterator ait = Animators.begin(); + while (ait != Animators.end()) + { + // continue to the next node before calling animateNode() + // so that the animator may remove itself from the scene + // node without the iterator becoming invalid + ISceneNodeAnimator* anim = *ait; + ++ait; + if ( anim->isEnabled() ) + { + anim->animateNode(this, timeMs); + } + } + + // update absolute position + updateAbsolutePosition(); + + // perform the post render process on all children + + ISceneNodeList::Iterator it = Children.begin(); + for (; it != Children.end(); ++it) + (*it)->OnAnimate(timeMs); + } + } + + + //! Renders the node. + virtual void render() = 0; + + + //! Returns the name of the node. + /** \return Name as character string. */ + virtual const c8* getName() const + { + return Name.c_str(); + } + + + //! Sets the name of the node. + /** \param name New name of the scene node. */ + virtual void setName(const c8* name) + { + Name = name; + } + + + //! Sets the name of the node. + /** \param name New name of the scene node. */ + virtual void setName(const core::stringc& name) + { + Name = name; + } + + + //! Get the axis aligned, not transformed bounding box of this node. + /** This means that if this node is an animated 3d character, + moving in a room, the bounding box will always be around the + origin. To get the box in real world coordinates, just + transform it with the matrix you receive with + getAbsoluteTransformation() or simply use + getTransformedBoundingBox(), which does the same. + \return The non-transformed bounding box. */ + virtual const core::aabbox3d& getBoundingBox() const = 0; + + + //! Get the axis aligned, transformed and animated absolute bounding box of this node. + /** Note: The result is still an axis-aligned bounding box, so it's size + changes with rotation. + \return The transformed bounding box. */ + virtual const core::aabbox3d getTransformedBoundingBox() const + { + core::aabbox3d box = getBoundingBox(); + AbsoluteTransformation.transformBoxEx(box); + return box; + } + + //! Get a the 8 corners of the original bounding box transformed and + //! animated by the absolute transformation. + /** Note: The result is _not_ identical to getTransformedBoundingBox().getEdges(), + but getting an aabbox3d of these edges would then be identical. + \param edges Receives an array with the transformed edges */ + virtual void getTransformedBoundingBoxEdges(core::array< core::vector3d >& edges) const + { + edges.set_used(8); + getBoundingBox().getEdges( edges.pointer() ); + for ( u32 i=0; i<8; ++i ) + AbsoluteTransformation.transformVect( edges[i] ); + } + + //! Get the absolute transformation of the node. Is recalculated every OnAnimate()-call. + /** NOTE: For speed reasons the absolute transformation is not + automatically recalculated on each change of the relative + transformation or by a transformation change of an parent. Instead the + update usually happens once per frame in OnAnimate. You can enforce + an update with updateAbsolutePosition(). + \return The absolute transformation matrix. */ + virtual const core::matrix4& getAbsoluteTransformation() const + { + return AbsoluteTransformation; + } + + + //! Returns the relative transformation of the scene node. + /** The relative transformation is stored internally as 3 + vectors: translation, rotation and scale. To get the relative + transformation matrix, it is calculated from these values. + \return The relative transformation matrix. */ + virtual core::matrix4 getRelativeTransformation() const + { + core::matrix4 mat; + mat.setRotationDegrees(RelativeRotation); + mat.setTranslation(RelativeTranslation); + + if (RelativeScale != core::vector3df(1.f,1.f,1.f)) + { + core::matrix4 smat; + smat.setScale(RelativeScale); + mat *= smat; + } + + return mat; + } + + + //! 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 requested visibility of the node, true means + visible (if all parents are also visible). */ + virtual bool isVisible() const + { + return IsVisible; + } + + //! Check 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 + { + 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. 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) + { + IsVisible = isVisible; + } + + + //! Get the id of the scene node. + /** This id can be used to identify the node. + \return The id. */ + virtual s32 getID() const + { + return ID; + } + + + //! Sets the id of the scene node. + /** This id can be used to identify the node. + \param id The new id. */ + virtual void setID(s32 id) + { + ID = id; + } + + + //! Adds a child to this scene node. + /** If the scene node already has a parent it is first removed + from the other parent. + \param child A pointer to the new child. */ + virtual void addChild(ISceneNode* child) + { + if (child && (child != this)) + { + // Change scene manager? + if (SceneManager != child->SceneManager) + child->setSceneManager(SceneManager); + + child->grab(); + child->remove(); // remove from old parent + Children.push_back(child); + child->Parent = this; + } + } + + + //! Removes a child from this scene node. + /** If found in the children list, the child pointer is also + dropped and might be deleted if no other grab exists. + \param child A pointer to the child which shall be removed. + \return True if the child was removed, and false if not, + e.g. because it couldn't be found in the children list. */ + virtual bool removeChild(ISceneNode* child) + { + ISceneNodeList::Iterator it = Children.begin(); + for (; it != Children.end(); ++it) + if ((*it) == child) + { + (*it)->Parent = 0; + (*it)->drop(); + Children.erase(it); + return true; + } + + return false; + } + + + //! Removes all children of this scene node + /** The scene nodes found in the children list are also dropped + and might be deleted if no other grab exists on them. + */ + virtual void removeAll() + { + ISceneNodeList::Iterator it = Children.begin(); + for (; it != Children.end(); ++it) + { + (*it)->Parent = 0; + (*it)->drop(); + } + + Children.clear(); + } + + + //! Removes this scene node from the scene + /** If no other grab exists for this node, it will be deleted. + */ + virtual void remove() + { + if (Parent) + Parent->removeChild(this); + } + + + //! Adds an animator which should animate this node. + /** \param animator A pointer to the new animator. */ + virtual void addAnimator(ISceneNodeAnimator* animator) + { + if (animator) + { + Animators.push_back(animator); + animator->grab(); + } + } + + + //! Get a list of all scene node animators. + /** \return The list of animators attached to this node. */ + const core::list& getAnimators() const + { + return Animators; + } + + + //! Removes an animator from this scene node. + /** If the animator is found, it is also dropped and might be + deleted if not other grab exists for it. + \param animator A pointer to the animator to be deleted. */ + virtual void removeAnimator(ISceneNodeAnimator* animator) + { + ISceneNodeAnimatorList::Iterator it = Animators.begin(); + for (; it != Animators.end(); ++it) + { + if ((*it) == animator) + { + (*it)->drop(); + Animators.erase(it); + return; + } + } + } + + + //! Removes all animators from this scene node. + /** The animators might also be deleted if no other grab exists + for them. */ + virtual void removeAnimators() + { + ISceneNodeAnimatorList::Iterator it = Animators.begin(); + for (; it != Animators.end(); ++it) + (*it)->drop(); + + Animators.clear(); + } + + + //! Returns the material based on the zero based index i. + /** To get the amount of materials used by this scene node, use + getMaterialCount(). This function is needed for inserting the + node into the scene hierarchy at an optimal position for + minimizing renderstate changes, but can also be used to + directly modify the material of a scene node. + \param num Zero based index. The maximal value is getMaterialCount() - 1. + \return The material at that index. */ + virtual video::SMaterial& getMaterial(u32 num) + { + return video::IdentityMaterial; + } + + + //! Get amount of materials used by this scene node. + /** \return Current amount of materials of this scene node. */ + virtual u32 getMaterialCount() const + { + return 0; + } + + + //! Sets all material flags at once to a new value. + /** Useful, for example, if you want the whole mesh to be + affected by light. + \param flag Which flag of all materials to be set. + \param newvalue New value of that flag. */ + void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) + { + for (u32 i=0; i= video::MATERIAL_MAX_TEXTURES) + return; + + for (u32 i=0; i& getChildren() const + { + return Children; + } + + + //! Changes the parent of the scene node. + /** \param newParent The new parent to be used. */ + virtual void setParent(ISceneNode* newParent) + { + grab(); + remove(); + + Parent = newParent; + + if (Parent) + Parent->addChild(this); + + drop(); + } + + + //! Returns the triangle selector attached to this scene node. + /** The Selector can be used by the engine for doing collision + detection. You can create a TriangleSelector with + ISceneManager::createTriangleSelector() or + ISceneManager::createOctreeTriangleSelector and set it with + ISceneNode::setTriangleSelector(). If a scene node got no triangle + selector, but collision tests should be done with it, a triangle + selector is created using the bounding box of the scene node. + \return A pointer to the TriangleSelector or 0, if there + is none. */ + virtual ITriangleSelector* getTriangleSelector() const + { + return TriangleSelector; + } + + + //! Sets the triangle selector of the scene node. + /** The Selector can be used by the engine for doing collision + detection. You can create a TriangleSelector with + ISceneManager::createTriangleSelector() or + ISceneManager::createOctreeTriangleSelector(). Some nodes may + create their own selector by default, so it would be good to + check if there is already a selector in this node by calling + ISceneNode::getTriangleSelector(). + \param selector New triangle selector for this scene node. */ + virtual void setTriangleSelector(ITriangleSelector* selector) + { + if (TriangleSelector != selector) + { + if (TriangleSelector) + TriangleSelector->drop(); + + TriangleSelector = selector; + if (TriangleSelector) + TriangleSelector->grab(); + } + } + + + //! Updates the absolute position based on the relative and the parents position + /** Note: This does not recursively update the parents absolute positions, so if you have a deeper + hierarchy you might want to update the parents first.*/ + virtual void updateAbsolutePosition() + { + if (Parent) + { + AbsoluteTransformation = + Parent->getAbsoluteTransformation() * getRelativeTransformation(); + } + else + AbsoluteTransformation = getRelativeTransformation(); + } + + + //! Returns the parent of this scene node + /** \return A pointer to the parent. */ + scene::ISceneNode* getParent() const + { + return Parent; + } + + + //! Returns type of the scene node + /** \return The type of this node. */ + virtual ESCENE_NODE_TYPE getType() const + { + return ESNT_UNKNOWN; + } + + + //! 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. + \param out The attribute container to write into. + \param options Additional options which might influence the + serialization. */ + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_ + { + if (!out) + return; + out->addString("Name", Name.c_str()); + out->addInt("Id", ID ); + + out->addVector3d("Position", getPosition() ); + out->addVector3d("Rotation", getRotation() ); + out->addVector3d("Scale", getScale() ); + + out->addBool("Visible", IsVisible ); + out->addInt("AutomaticCulling", AutomaticCullingState); + out->addInt("DebugDataVisible", DebugDataVisible ); + out->addBool("IsDebugObject", IsDebugObject ); + } + + + //! 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. + \param in The attribute container to read from. + \param options Additional options which might influence the + deserialization. */ + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_ + { + if (!in) + return; + Name = in->getAttributeAsString("Name", Name); + ID = in->getAttributeAsInt("Id", ID); + + setPosition(in->getAttributeAsVector3d("Position", RelativeTranslation)); + setRotation(in->getAttributeAsVector3d("Rotation", RelativeRotation)); + setScale(in->getAttributeAsVector3d("Scale", RelativeScale)); + + IsVisible = in->getAttributeAsBool("Visible", IsVisible); + if (in->existsAttribute("AutomaticCulling")) + { + s32 tmpState = in->getAttributeAsEnumeration("AutomaticCulling", + scene::AutomaticCullingNames); + if (tmpState != -1) + AutomaticCullingState = (u32)tmpState; + else + AutomaticCullingState = in->getAttributeAsInt("AutomaticCulling"); + } + + DebugDataVisible = in->getAttributeAsInt("DebugDataVisible", DebugDataVisible); + IsDebugObject = in->getAttributeAsBool("IsDebugObject", IsDebugObject); + + updateAbsolutePosition(); + } + + //! Creates a clone of this scene node and its children. + /** \param newParent An optional new parent. + \param newManager An optional new scene manager. + \return The newly created clone of this node. */ + virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) + { + return 0; // to be implemented by derived classes + } + + //! Retrieve the scene manager for this node. + /** \return The node's scene manager. */ + virtual ISceneManager* getSceneManager(void) const { return SceneManager; } + + protected: + + //! A clone function for the ISceneNode members. + /** This method can be used by clone() implementations of + derived classes + \param toCopyFrom The node from which the values are copied + \param newManager The new scene manager. */ + void cloneMembers(ISceneNode* toCopyFrom, ISceneManager* newManager) + { + Name = toCopyFrom->Name; + AbsoluteTransformation = toCopyFrom->AbsoluteTransformation; + RelativeTranslation = toCopyFrom->RelativeTranslation; + RelativeRotation = toCopyFrom->RelativeRotation; + RelativeScale = toCopyFrom->RelativeScale; + ID = toCopyFrom->ID; + setTriangleSelector(toCopyFrom->TriangleSelector); + AutomaticCullingState = toCopyFrom->AutomaticCullingState; + DebugDataVisible = toCopyFrom->DebugDataVisible; + IsVisible = toCopyFrom->IsVisible; + IsDebugObject = toCopyFrom->IsDebugObject; + + if (newManager) + SceneManager = newManager; + else + SceneManager = toCopyFrom->SceneManager; + + // clone children + + ISceneNodeList::Iterator it = toCopyFrom->Children.begin(); + for (; it != toCopyFrom->Children.end(); ++it) + (*it)->clone(this, newManager); + + // clone animators + + ISceneNodeAnimatorList::Iterator ait = toCopyFrom->Animators.begin(); + for (; ait != toCopyFrom->Animators.end(); ++ait) + { + ISceneNodeAnimator* anim = (*ait)->createClone(this, SceneManager); + if (anim) + { + addAnimator(anim); + anim->drop(); + } + } + } + + //! Sets the new scene manager for this node and all children. + //! Called by addChild when moving nodes between scene managers + void setSceneManager(ISceneManager* newManager) + { + SceneManager = newManager; + + ISceneNodeList::Iterator it = Children.begin(); + for (; it != Children.end(); ++it) + (*it)->setSceneManager(newManager); + } + + //! Name of the scene node. + core::stringc Name; + + //! Absolute transformation of the node. + core::matrix4 AbsoluteTransformation; + + //! Relative translation of the scene node. + core::vector3df RelativeTranslation; + + //! Relative rotation of the scene node. + core::vector3df RelativeRotation; + + //! Relative scale of the scene node. + core::vector3df RelativeScale; + + //! Pointer to the parent + ISceneNode* Parent; + + //! List of all children of this node + core::list Children; + + //! List of all animator nodes + core::list Animators; + + //! Pointer to the scene manager + ISceneManager* SceneManager; + + //! Pointer to the triangle selector + ITriangleSelector* TriangleSelector; + + //! ID of the node. + s32 ID; + + //! Automatic culling state + u32 AutomaticCullingState; + + //! Flag if debug data should be drawn, such as Bounding Boxes. + u32 DebugDataVisible; + + //! Is the node visible? + bool IsVisible; + + //! Is debug object? + bool IsDebugObject; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/ISceneNodeAnimator.h b/include/ISceneNodeAnimator.h new file mode 100644 index 00000000..cdff7009 --- /dev/null +++ b/include/ISceneNodeAnimator.h @@ -0,0 +1,170 @@ +// Copyright (C) 2002-2012 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_H_INCLUDED__ +#define __I_SCENE_NODE_ANIMATOR_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "vector3d.h" +#include "ESceneNodeAnimatorTypes.h" +#include "IAttributeExchangingObject.h" +#include "IAttributes.h" +#include "IEventReceiver.h" + +namespace irr +{ +namespace io +{ + class IAttributes; +} // end namespace io +namespace scene +{ + class ISceneNode; + class ISceneManager; + + //! Animates a scene node. Can animate position, rotation, material, and so on. + /** A scene node animator is able to animate a scene node in a very simple way. It may + change its position, rotation, scale and/or material. There are lots of animators + to choose from. You can create scene node animators with the ISceneManager interface. + */ + class ISceneNodeAnimator : public io::IAttributeExchangingObject, public IEventReceiver + { + public: + ISceneNodeAnimator() : IsEnabled(true), PauseTimeSum(0), PauseTimeStart(0), StartTime(0) + { + } + + //! Animates a scene node. + /** \param node Node to animate. + \param timeMs Current time in milliseconds. */ + virtual void animateNode(ISceneNode* node, u32 timeMs) =0; + + //! Creates a clone of this animator. + /** Please note that you will have to drop + (IReferenceCounted::drop()) the returned pointer after calling this. */ + virtual ISceneNodeAnimator* createClone(ISceneNode* node, + ISceneManager* newManager=0) =0; + + //! Returns true if this animator receives events. + /** When attached to an active camera, this animator will be + able to respond to events such as mouse and keyboard events. */ + virtual bool isEventReceiverEnabled() const + { + return false; + } + + //! Event receiver, override this function for camera controlling animators + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_ + { + return false; + } + + //! Returns type of the scene node animator + virtual ESCENE_NODE_ANIMATOR_TYPE getType() const + { + 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; + } + + //! Reset a time-based movement by changing the starttime. + /** By default most animators start on object creation. + This value is ignored by animators which don't work with a starttime. + Known problems: CSceneNodeAnimatorRotation currently overwrites this value constantly (might be changed in the future). + \param time Commonly you will use irr::ITimer::getTime(). + \param resetPauseTime Reset internal pause time for enabling/diabling animators as well + */ + virtual void setStartTime(u32 time, bool resetPauseTime=true) + { + StartTime = time; + if ( resetPauseTime ) + { + PauseTimeStart = 0; + PauseTimeSum = 0; + } + } + + //! Get the starttime. + /** This will return 0 for by animators which don't work with a starttime unless a starttime was manually set */ + virtual irr::u32 getStartTime() const + { + return StartTime; + } + + //! Sets the enabled state of this element. + /** + \param enabled When set to false ISceneNodes will not update the animator anymore. + Animators themselves usually don't care. So manual calls to animateNode still work. + \param timeNow When set to values > 0 on enabling and disabling an internal timer will be increased by the time disabled time. + Animator decide themselves how to handle that timer, but generally setting it will allow you to pause an animator, so it + will continue at the same position when you enable it again. To use that pass irr::ITimer::getTime() as value. + Animators with no timers will just ignore this. + */ + virtual void setEnabled(bool enabled, u32 timeNow=0) + { + if ( enabled == IsEnabled ) + return; + IsEnabled = enabled; + if ( enabled ) + { + if ( timeNow > 0 && PauseTimeStart > 0 ) + PauseTimeSum += timeNow-PauseTimeStart; + } + else + { + PauseTimeStart = timeNow; + } + } + + virtual bool isEnabled() const + { + return IsEnabled; + } + + //! Writes attributes of the scene node animator. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_ + { + out->addBool("IsEnabled", IsEnabled); + // timers not serialized as they usually depend on system-time which is different on each application start. + } + + //! Reads attributes of the scene node animator. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_ + { + IsEnabled = in->getAttributeAsBool("IsEnabled", IsEnabled); + PauseTimeSum = 0; + PauseTimeStart = 0; + } + + protected: + + /** This method can be used by clone() implementations of + derived classes + \param toCopyFrom The animator from which the values are copied */ + void cloneMembers(const ISceneNodeAnimator* toCopyFrom) + { + IsEnabled = toCopyFrom->IsEnabled; + PauseTimeSum = toCopyFrom->IsEnabled; + PauseTimeStart = toCopyFrom->PauseTimeStart; + StartTime = toCopyFrom->StartTime; + } + + bool IsEnabled; //! Only enabled animators are updated + u32 PauseTimeSum; //! Sum up time which the animator was disabled + u32 PauseTimeStart; //! Last time setEnabled(false) was called with a timer > 0 + u32 StartTime; //! Used by animators which are time-based, ignored otherwise. + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/ISceneNodeAnimatorCameraFPS.h b/include/ISceneNodeAnimatorCameraFPS.h new file mode 100644 index 00000000..91a00680 --- /dev/null +++ b/include/ISceneNodeAnimatorCameraFPS.h @@ -0,0 +1,75 @@ +// Copyright (C) 2002-2012 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_CAMERA_FPS_H_INCLUDED__ +#define __I_SCENE_NODE_ANIMATOR_CAMERA_FPS_H_INCLUDED__ + +#include "ISceneNodeAnimator.h" +#include "IEventReceiver.h" +#include "irrArray.h" + +namespace irr +{ + struct SKeyMap; + +namespace scene +{ + + //! Special scene node animator for FPS cameras + /** This scene node animator can be attached to a camera to make it act + like a first person shooter + */ + class ISceneNodeAnimatorCameraFPS : public ISceneNodeAnimator + { + public: + + //! Returns the speed of movement in units per millisecond + virtual f32 getMoveSpeed() const = 0; + + //! Sets the speed of movement in units per millisecond + virtual void setMoveSpeed(f32 moveSpeed) = 0; + + //! Returns the rotation speed when using keyboard + virtual f32 getRotateSpeedKeyboard() const = 0; + + //! Set the rotation speed when using keyboard + virtual void setRotateSpeedKeyboard(f32 rotateSpeed) = 0; + + //! Returns the rotation speed in degrees when using mouse + /** The degrees are equivalent to a half screen movement of the mouse, + i.e. if the mouse cursor had been moved to the border of the screen since + the last animation. */ + virtual f32 getRotateSpeed() const = 0; + + //! Set the rotation speed in degrees when using mouse + virtual void setRotateSpeed(f32 rotateSpeed) = 0; + + //! Sets the keyboard mapping for this animator (old style) + /** \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 the keyboard mapping for this animator + //! \param keymap The new keymap array + virtual void setKeyMap(const core::array& keymap) = 0; + + //! Gets the keyboard mapping for this animator + virtual const core::array& getKeyMap() const = 0; + + //! Sets whether vertical movement should be allowed. + /** If vertical movement is enabled then the camera may fight with + 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 + +#endif + diff --git a/include/ISceneNodeAnimatorCameraMaya.h b/include/ISceneNodeAnimatorCameraMaya.h new file mode 100644 index 00000000..a1dba263 --- /dev/null +++ b/include/ISceneNodeAnimatorCameraMaya.h @@ -0,0 +1,65 @@ +// Copyright (C) 2002-2012 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_CAMERA_MAYA_H_INCLUDED__ +#define __I_SCENE_NODE_ANIMATOR_CAMERA_MAYA_H_INCLUDED__ + +#include "ISceneNodeAnimator.h" + +namespace irr +{ + +namespace scene +{ + + //! Special scene node animator for Maya-style cameras + /** This scene node animator can be attached to a camera to make it act like a 3d + modeling tool. + The camera is moving relative to the target with the mouse, by pressing either + of the three buttons. + In order to move the camera, set a new target for the camera. The distance defines + the current orbit radius the camera moves on. Distance can be changed via the setter + or by mouse events. + */ + class ISceneNodeAnimatorCameraMaya : public ISceneNodeAnimator + { + public: + + //! Returns the speed of movement + virtual f32 getMoveSpeed() const = 0; + + //! Sets the speed of movement + virtual void setMoveSpeed(f32 moveSpeed) = 0; + + //! Returns the rotation speed + virtual f32 getRotateSpeed() const = 0; + + //! Set the rotation speed + virtual void setRotateSpeed(f32 rotateSpeed) = 0; + + //! Returns the zoom speed + virtual f32 getZoomSpeed() const = 0; + + //! Set the zoom speed + virtual void setZoomSpeed(f32 zoomSpeed) = 0; + + //! Returns the current distance, i.e. orbit radius + virtual f32 getDistance() const = 0; + + //! Set the distance + virtual void setDistance(f32 distance) = 0; + + //! Set the minimal distance to the camera target for zoom + virtual void setTargetMinDistance(f32 minDistance) = 0; + + //! Returns the minimal distance to the camera target for zoom + virtual f32 getTargetMinDistance() const = 0; + + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/ISceneNodeAnimatorCollisionResponse.h b/include/ISceneNodeAnimatorCollisionResponse.h new file mode 100644 index 00000000..66334127 --- /dev/null +++ b/include/ISceneNodeAnimatorCollisionResponse.h @@ -0,0 +1,171 @@ +// Copyright (C) 2002-2012 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_COLLISION_RESPONSE_H_INCLUDED__ +#define __I_SCENE_NODE_ANIMATOR_COLLISION_RESPONSE_H_INCLUDED__ + +#include "ISceneNode.h" + +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 occurs. + /** 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 + (e.g. walls and floors of the) world, as well as having it fall under gravity. + This animator provides a simple implementation of first person shooter cameras. + Attach it to a camera, and the camera will behave as the player control in a + first person shooter game: The camera stops and slides at walls, walks up stairs, + falls down if there is no floor under it, and so on. + + The animator will treat any change in the position of its target scene + node as movement, including a setPosition(), as movement. If you want to + teleport the target scene node manually to a location without it being effected + by collision geometry, then call setTargetNode(node) after calling node->setPosition(). + */ + class ISceneNodeAnimatorCollisionResponse : public ISceneNodeAnimator + { + public: + + //! Destructor + virtual ~ISceneNodeAnimatorCollisionResponse() {} + + //! Check if the attached scene node is falling. + /** Falling means that there is no blocking wall from the scene + node in the direction of the gravity. The implementation of + this method is very fast, no collision detection is done when + invoking it. + \return True if the scene node is falling, false if not. */ + virtual bool isFalling() const = 0; + + //! Sets the radius of the ellipsoid for collision detection and response. + /** If you have a scene node, and you are unsure about how big + the radius should be, you could use the following code to + determine it: + \code + core::aabbox box = yourSceneNode->getBoundingBox(); + core::vector3df radius = box.MaxEdge - box.getCenter(); + \endcode + \param radius: New radius of the ellipsoid. */ + virtual void setEllipsoidRadius(const core::vector3df& radius) = 0; + + //! Returns the radius of the ellipsoid for collision detection and response. + /** \return Radius of the ellipsoid. */ + virtual core::vector3df getEllipsoidRadius() const = 0; + + //! Sets the gravity of the environment. + /** A good example value would be core::vector3df(0,-100.0f,0) + for letting gravity affect all object to fall down. For bigger + gravity, make increase the length of the vector. You can + disable gravity by setting it to core::vector3df(0,0,0); + \param gravity: New gravity vector. */ + virtual void setGravity(const core::vector3df& gravity) = 0; + + //! Get current vector of gravity. + //! \return Gravity vector. */ + virtual core::vector3df getGravity() const = 0; + + //! 'Jump' the animator, by adding a jump speed opposite to its gravity + /** \param jumpSpeed The initial speed of the jump; the velocity will be opposite + to this animator's gravity vector. */ + virtual void jump(f32 jumpSpeed) = 0; + + //! Should the Target react on collision ( default = true ) + virtual void setAnimateTarget ( bool enable ) = 0; + virtual bool getAnimateTarget () const = 0; + + //! Set translation of the collision ellipsoid. + /** 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 translation: Translation of the ellipsoid relative + to the position of the scene node. */ + virtual void setEllipsoidTranslation(const core::vector3df &translation) = 0; + + //! Get the translation of the ellipsoid for collision detection. + /** See + ISceneNodeAnimatorCollisionResponse::setEllipsoidTranslation() + for more details. + \return Translation of the ellipsoid relative to the position + of the scene node. */ + virtual core::vector3df getEllipsoidTranslation() const = 0; + + //! Sets a triangle selector holding all triangles of the world with which the scene node may collide. + /** \param newWorld: New triangle selector containing triangles + to let the scene node collide with. */ + virtual void setWorld(ITriangleSelector* newWorld) = 0; + + //! Get the current triangle selector containing all triangles for collision detection. + virtual ITriangleSelector* getWorld() const = 0; + + //! Set the single node that this animator will act on. + /** \param node The new target node. Setting this will force the animator to update + its last target position for the node, allowing setPosition() to teleport + the node through collision geometry. */ + virtual void setTargetNode(ISceneNode * node) = 0; + + //! Gets the single node that this animator is acting on. + /** \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 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; + + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/ISceneNodeAnimatorFactory.h b/include/ISceneNodeAnimatorFactory.h new file mode 100644 index 00000000..a50703f2 --- /dev/null +++ b/include/ISceneNodeAnimatorFactory.h @@ -0,0 +1,69 @@ +// Copyright (C) 2002-2012 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_FACTORY_H_INCLUDED__ +#define __I_SCENE_NODE_ANIMATOR_FACTORY_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "ESceneNodeAnimatorTypes.h" + +namespace irr +{ +namespace scene +{ + class ISceneNode; + class ISceneNodeAnimator; + + //! Interface for dynamic creation of scene node animators + /** To be able to add custom scene node animators to Irrlicht and to make it possible for the + scene manager to save and load those external animators, simply implement this + interface and register it in you scene manager via ISceneManager::registerSceneNodeAnimatorFactory. + Note: When implementing your own scene node factory, don't call ISceneNodeManager::grab() to + increase the reference counter of the scene node manager. This is not necessary because the + scene node manager will grab() the factory anyway, and otherwise cyclic references will + be created and the scene manager and all its nodes won't get deallocated. + */ + class ISceneNodeAnimatorFactory : public virtual IReferenceCounted + { + public: + + //! creates a scene node animator based on its type id + /** \param type: Type of the scene node animator to add. + \param target: Target scene node of the new animator. + \return Returns pointer to the new scene node animator or null if not successful. You need to + drop this pointer after calling this, see IReferenceCounted::drop() for details. */ + virtual ISceneNodeAnimator* createSceneNodeAnimator(ESCENE_NODE_ANIMATOR_TYPE type, ISceneNode* target) = 0; + + //! creates a scene node animator based on its type name + /** \param typeName: Type of the scene node animator to add. + \param target: Target scene node of the new animator. + \return Returns pointer to the new scene node animator or null if not successful. You need to + drop this pointer after calling this, see IReferenceCounted::drop() for details. */ + virtual ISceneNodeAnimator* createSceneNodeAnimator(const c8* typeName, ISceneNode* target) = 0; + + //! returns amount of scene node animator types this factory is able to create + virtual u32 getCreatableSceneNodeAnimatorTypeCount() const = 0; + + //! returns type of a creatable scene node animator type + /** \param idx: Index of scene node animator type in this factory. Must be a value between 0 and + getCreatableSceneNodeTypeCount() */ + virtual ESCENE_NODE_ANIMATOR_TYPE getCreateableSceneNodeAnimatorType(u32 idx) const = 0; + + //! returns type name of a creatable scene node animator type + /** \param idx: Index of scene node animator type in this factory. Must be a value between 0 and + getCreatableSceneNodeAnimatorTypeCount() */ + virtual const c8* getCreateableSceneNodeAnimatorTypeName(u32 idx) const = 0; + + //! returns type name of a creatable scene node animator type + /** \param type: Type of scene node animator. + \return: Returns name of scene node animator type if this factory can create the type, otherwise 0. */ + virtual const c8* getCreateableSceneNodeAnimatorTypeName(ESCENE_NODE_ANIMATOR_TYPE type) const = 0; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/ISceneNodeFactory.h b/include/ISceneNodeFactory.h new file mode 100644 index 00000000..43043bd2 --- /dev/null +++ b/include/ISceneNodeFactory.h @@ -0,0 +1,68 @@ +// Copyright (C) 2002-2012 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_FACTORY_H_INCLUDED__ +#define __I_SCENE_NODE_FACTORY_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "ESceneNodeTypes.h" + +namespace irr +{ + +namespace scene +{ + class ISceneNode; + + //! Interface for dynamic creation of scene nodes + /** To be able to add custom scene nodes to Irrlicht and to make it possible for the + scene manager to save and load those external scene nodes, simply implement this + interface and register it in you scene manager via ISceneManager::registerSceneNodeFactory. + Note: When implementing your own scene node factory, don't call ISceneNodeManager::grab() to + increase the reference counter of the scene node manager. This is not necessary because the + scene node manager will grab() the factory anyway, and otherwise cyclic references will + be created and the scene manager and all its nodes won't get deallocated. + */ + class ISceneNodeFactory : public virtual IReferenceCounted + { + public: + //! 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. + 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. + 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 + virtual u32 getCreatableSceneNodeTypeCount() const = 0; + + //! returns type of a creatable scene node type + /** \param idx: Index of scene node type in this factory. Must be a value between 0 and + getCreatableSceneNodeTypeCount() */ + virtual ESCENE_NODE_TYPE getCreateableSceneNodeType(u32 idx) const = 0; + + //! returns type name of a creatable scene node type by index + /** \param idx: Index of scene node type in this factory. Must be a value between 0 and + getCreatableSceneNodeTypeCount() */ + virtual const c8* getCreateableSceneNodeTypeName(u32 idx) const = 0; + + //! returns type name of a creatable scene node type + /** \param type: Type of scene node. + \return: Returns name of scene node type if this factory can create the type, otherwise 0. */ + virtual const c8* getCreateableSceneNodeTypeName(ESCENE_NODE_TYPE type) const = 0; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/ISceneUserDataSerializer.h b/include/ISceneUserDataSerializer.h new file mode 100644 index 00000000..46b15b53 --- /dev/null +++ b/include/ISceneUserDataSerializer.h @@ -0,0 +1,51 @@ +// Copyright (C) 2002-2012 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_USER_DATA_SERIALIZER_H_INCLUDED__ +#define __I_SCENE_USER_DATA_SERIALIZER_H_INCLUDED__ + +#include "IReferenceCounted.h" + +namespace irr +{ +namespace io +{ + class IAttributes; +} // end namespace io +namespace scene +{ + class ISceneNode; + +//! Interface to read and write user data to and from .irr files. +/** This interface is to be implemented by the user, to make it possible to read +and write user data when reading or writing .irr files via ISceneManager. +To be used with ISceneManager::loadScene() and ISceneManager::saveScene() */ +class ISceneUserDataSerializer +{ +public: + + virtual ~ISceneUserDataSerializer() {} + + //! Called when the scene manager create a scene node while loading a file. + virtual void OnCreateNode(ISceneNode* node) = 0; + + //! Called when the scene manager read a scene node while loading a file. + /** The userData pointer contains a list of attributes with userData which + were attached to the scene node in the read scene file.*/ + virtual void OnReadUserData(ISceneNode* forSceneNode, io::IAttributes* userData) = 0; + + //! Called when the scene manager is writing a scene node to an xml file for example. + /** Implement this method and return a list of attributes containing the user data + you want to be saved together with the scene node. Return 0 if no user data should + be added. Please note that the scene manager will call drop() to the returned pointer + after it no longer needs it, so if you didn't create a new object for the return value + and returning a longer existing IAttributes object, simply call grab() before returning it. */ + virtual io::IAttributes* createUserData(ISceneNode* forSceneNode) = 0; +}; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/IShaderConstantSetCallBack.h b/include/IShaderConstantSetCallBack.h new file mode 100644 index 00000000..fdf9e9af --- /dev/null +++ b/include/IShaderConstantSetCallBack.h @@ -0,0 +1,85 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_SHADER_CONSTANT_SET_CALLBACT_H_INCLUDED__ +#define __I_SHADER_CONSTANT_SET_CALLBACT_H_INCLUDED__ + +#include "IReferenceCounted.h" + +namespace irr +{ +namespace video +{ + class IMaterialRendererServices; + class SMaterial; + +//! Interface making it possible to set constants for gpu programs every frame. +/** Implement this interface in an own class and pass a pointer to it to one of +the methods in IGPUProgrammingServices when creating a shader. The +OnSetConstants method will be called every frame now. */ +class IShaderConstantSetCallBack : public virtual IReferenceCounted +{ +public: + + //! Called to let the callBack know the used material (optional method) + /** + \code + class MyCallBack : public IShaderConstantSetCallBack + { + const video::SMaterial *UsedMaterial; + + OnSetMaterial(const video::SMaterial& material) + { + UsedMaterial=&material; + } + + OnSetConstants(IMaterialRendererServices* services, s32 userData) + { + services->setVertexShaderConstant("myColor", reinterpret_cast(&UsedMaterial->color), 4); + } + } + \endcode + */ + virtual void OnSetMaterial(const SMaterial& material) { } + + //! Called by the engine when the vertex and/or pixel shader constants for an material renderer should be set. + /** + Implement the IShaderConstantSetCallBack in an own class and implement your own + OnSetConstants method using the given IMaterialRendererServices interface. + Pass a pointer to this class to one of the methods in IGPUProgrammingServices + when creating a shader. The OnSetConstants method will now be called every time + before geometry is being drawn using your shader material. A sample implementation + would look like this: + \code + virtual void OnSetConstants(video::IMaterialRendererServices* services, s32 userData) + { + video::IVideoDriver* driver = services->getVideoDriver(); + + // set clip matrix at register 4 + core::matrix4 worldViewProj(driver->getTransform(video::ETS_PROJECTION)); + worldViewProj *= driver->getTransform(video::ETS_VIEW); + worldViewProj *= driver->getTransform(video::ETS_WORLD); + services->setVertexShaderConstant(&worldViewProj.M[0], 4, 4); + // for high level shading languages, this would be another solution: + //services->setVertexShaderConstant("mWorldViewProj", worldViewProj.M, 16); + + // set some light color at register 9 + video::SColorf col(0.0f,1.0f,1.0f,0.0f); + services->setVertexShaderConstant(reinterpret_cast(&col), 9, 1); + // for high level shading languages, this would be another solution: + //services->setVertexShaderConstant("myColor", reinterpret_cast(&col), 4); + } + \endcode + \param services: Pointer to an interface providing methods to set the constants for the shader. + \param userData: Userdata int which can be specified when creating the shader. + */ + virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData) = 0; +}; + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/include/IShadowVolumeSceneNode.h b/include/IShadowVolumeSceneNode.h new file mode 100644 index 00000000..f19e6aab --- /dev/null +++ b/include/IShadowVolumeSceneNode.h @@ -0,0 +1,65 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_SHADOW_VOLUME_SCENE_NODE_H_INCLUDED__ +#define __I_SHADOW_VOLUME_SCENE_NODE_H_INCLUDED__ + +#include "ISceneNode.h" + +namespace irr +{ +namespace scene +{ + class IMesh; + + enum ESHADOWVOLUME_OPTIMIZATION + { + //! Create volumes around every triangle + ESV_NONE, + + //! Create volumes only around the silhouette of the mesh + /** This can reduce the number of volumes drastically, + but will have an upfront-cost where it calculates adjacency of + triangles. Also it will not work with all models. Basically + if you see strange black shadow lines then you have a model + for which it won't work. + We get that information about adjacency by comparing the positions of + all edges in the mesh (even if they are in different meshbuffers). */ + ESV_SILHOUETTE_BY_POS + }; + + //! Scene node for rendering a shadow volume into a stencil buffer. + class IShadowVolumeSceneNode : public ISceneNode + { + public: + + //! constructor + IShadowVolumeSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id) + : ISceneNode(parent, mgr, id) {} + + //! Sets the mesh from which the shadow volume should be generated. + /** To optimize shadow rendering, use a simpler mesh for shadows. + */ + virtual void setShadowMesh(const IMesh* mesh) = 0; + + //! Updates the shadow volumes for current light positions. + virtual void updateShadowVolumes() = 0; + + //! Set optimization used to create shadow volumes + /** Default is ESV_SILHOUETTE_BY_POS. If the shadow + looks bad then give ESV_NONE a try (which will be slower). + Alternatively you can try to fix the model, it's often + because it's not closed (aka if you'd put water in it then + that would leak out). */ + virtual void setOptimization(ESHADOWVOLUME_OPTIMIZATION optimization) = 0; + + //! Get currently active optimization used to create shadow volumes + virtual ESHADOWVOLUME_OPTIMIZATION getOptimization() const = 0; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/ISkinnedMesh.h b/include/ISkinnedMesh.h new file mode 100644 index 00000000..783b26eb --- /dev/null +++ b/include/ISkinnedMesh.h @@ -0,0 +1,219 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_SKINNED_MESH_H_INCLUDED__ +#define __I_SKINNED_MESH_H_INCLUDED__ + +#include "irrArray.h" +#include "IBoneSceneNode.h" +#include "IAnimatedMesh.h" +#include "SSkinMeshBuffer.h" + +namespace irr +{ +namespace scene +{ + + enum E_INTERPOLATION_MODE + { + // constant does use the current key-values without interpolation + EIM_CONSTANT = 0, + + // linear interpolation + EIM_LINEAR, + + //! count of all available interpolation modes + EIM_COUNT + }; + + + //! Interface for using some special functions of Skinned meshes + class ISkinnedMesh : public IAnimatedMesh + { + public: + + //! Gets joint count. + /** \return Amount of joints in the skeletal animated mesh. */ + virtual u32 getJointCount() const = 0; + + //! Gets the name of a joint. + /** \param number: Zero based index of joint. The last joint + has the number getJointCount()-1; + \return Name of joint and null if an error happened. */ + virtual const c8* getJointName(u32 number) const = 0; + + //! Gets a joint number from its name + /** \param name: Name of the joint. + \return Number of the joint or -1 if not found. */ + virtual s32 getJointNumber(const c8* name) const = 0; + + //! Use animation from another mesh + /** The animation is linked (not copied) based on joint names + so make sure they are unique. + \return True if all joints in this mesh were + matched up (empty names will not be matched, and it's case + sensitive). Unmatched joints will not be animated. */ + virtual bool useAnimationFrom(const ISkinnedMesh *mesh) = 0; + + //! Update Normals when Animating + /** \param on If false don't animate, which is faster. + Else update normals, which allows for proper lighting of + animated meshes. */ + virtual void updateNormalsWhenAnimating(bool on) = 0; + + //! Sets Interpolation Mode + virtual void setInterpolationMode(E_INTERPOLATION_MODE mode) = 0; + + //! Animates this mesh's joints based on frame input + virtual void animateMesh(f32 frame, f32 blend)=0; + + //! Preforms a software skin on this mesh based of joint positions + virtual void skinMesh() = 0; + + //! converts the vertex type of all meshbuffers to tangents. + /** E.g. used for bump mapping. */ + virtual void convertMeshToTangents() = 0; + + //! Allows to enable hardware skinning. + /* This feature is not implemented in Irrlicht yet */ + virtual bool setHardwareSkinning(bool on) = 0; + + //! A vertex weight + struct SWeight + { + //! Index of the mesh buffer + u16 buffer_id; //I doubt 32bits is needed + + //! Index of the vertex + u32 vertex_id; //Store global ID here + + //! Weight Strength/Percentage (0-1) + f32 strength; + + private: + //! Internal members used by CSkinnedMesh + friend class CSkinnedMesh; + bool *Moved; + core::vector3df StaticPos; + core::vector3df StaticNormal; + }; + + + //! Animation keyframe which describes a new position + struct SPositionKey + { + f32 frame; + core::vector3df position; + }; + + //! Animation keyframe which describes a new scale + struct SScaleKey + { + f32 frame; + core::vector3df scale; + }; + + //! Animation keyframe which describes a new rotation + struct SRotationKey + { + f32 frame; + core::quaternion rotation; + }; + + //! Joints + struct SJoint + { + SJoint() : UseAnimationFrom(0), GlobalSkinningSpace(false), + positionHint(-1),scaleHint(-1),rotationHint(-1) + { + } + + //! The name of this joint + core::stringc Name; + + //! Local matrix of this joint + core::matrix4 LocalMatrix; + + //! List of child joints + core::array Children; + + //! List of attached meshes + core::array AttachedMeshes; + + //! Animation keys causing translation change + core::array PositionKeys; + + //! Animation keys causing scale change + core::array ScaleKeys; + + //! Animation keys causing rotation change + core::array RotationKeys; + + //! Skin weights + core::array Weights; + + //! Unnecessary for loaders, will be overwritten on finalize + core::matrix4 GlobalMatrix; + core::matrix4 GlobalAnimatedMatrix; + core::matrix4 LocalAnimatedMatrix; + core::vector3df Animatedposition; + core::vector3df Animatedscale; + core::quaternion Animatedrotation; + + core::matrix4 GlobalInversedMatrix; //the x format pre-calculates this + + private: + //! Internal members used by CSkinnedMesh + friend class CSkinnedMesh; + + SJoint *UseAnimationFrom; + bool GlobalSkinningSpace; + + s32 positionHint; + s32 scaleHint; + s32 rotationHint; + }; + + + //Interface for the mesh loaders (finalize should lock these functions, and they should have some prefix like loader_ + + //these functions will use the needed arrays, set values, etc to help the loaders + + //! exposed for loaders: to add mesh buffers + virtual core::array& getMeshBuffers() = 0; + + //! exposed for loaders: joints list + virtual core::array& getAllJoints() = 0; + + //! exposed for loaders: joints list + virtual const core::array& getAllJoints() const = 0; + + //! loaders should call this after populating the mesh + virtual void finalize() = 0; + + //! Adds a new meshbuffer to the mesh, access it as last one + virtual SSkinMeshBuffer* addMeshBuffer() = 0; + + //! Adds a new joint to the mesh, access it as last one + virtual SJoint* addJoint(SJoint *parent=0) = 0; + + //! Adds a new weight to the mesh, access it as last one + virtual SWeight* addWeight(SJoint *joint) = 0; + + //! Adds a new position key to the mesh, access it as last one + virtual SPositionKey* addPositionKey(SJoint *joint) = 0; + //! Adds a new scale key to the mesh, access it as last one + virtual SScaleKey* addScaleKey(SJoint *joint) = 0; + //! Adds a new rotation key to the mesh, access it as last one + virtual SRotationKey* addRotationKey(SJoint *joint) = 0; + + //! Check if the mesh is non-animated + virtual bool isStatic()=0; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/ITerrainSceneNode.h b/include/ITerrainSceneNode.h new file mode 100644 index 00000000..b0c822ce --- /dev/null +++ b/include/ITerrainSceneNode.h @@ -0,0 +1,190 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +// 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. + +#ifndef __I_TERRAIN_SCENE_NODE_H__ +#define __I_TERRAIN_SCENE_NODE_H__ + +#include "ETerrainElements.h" +#include "ISceneNode.h" +#include "IDynamicMeshBuffer.h" +#include "irrArray.h" + +namespace irr +{ +namespace io +{ + class IReadFile; +} // end namespace io +namespace scene +{ + class IMesh; + + //! A scene node for displaying terrain using the geo mip map algorithm. + /** 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 very quickly loading + * terrains and updating the indices at runtime to enable viewing very large terrains. 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 algorithm 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 ). + **/ + class ITerrainSceneNode : public ISceneNode + { + public: + //! Constructor + ITerrainSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position = core::vector3df(0.0f, 0.0f, 0.0f), + const core::vector3df& rotation = core::vector3df(0.0f, 0.0f, 0.0f), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f) ) + : ISceneNode (parent, mgr, id, position, rotation, scale) {} + + //! Get the bounding box of the terrain. + /** \return The bounding box of the entire terrain. */ + virtual const core::aabbox3d& getBoundingBox() const =0; + + //! Get the bounding box of a patch + /** \return The bounding box of the chosen patch. */ + virtual const core::aabbox3d& getBoundingBox(s32 patchX, s32 patchZ) const =0; + + //! Get the number of indices currently in the meshbuffer + /** \return The index count. */ + virtual u32 getIndexCount() const =0; + + //! Get pointer to the mesh + /** \return Pointer to the mesh. */ + virtual IMesh* getMesh() =0; + + //! Get pointer to the buffer used by the terrain (most users will not need this) + virtual IMeshBuffer* getRenderBuffer() =0; + + + //! Gets the meshbuffer data based on a specified level of detail. + /** \param mb A reference to an IDynamicMeshBuffer object + \param LOD The level of detail you want the indices from. */ + virtual void getMeshBufferForLOD(IDynamicMeshBuffer& mb, s32 LOD=0) const =0; + + //! Gets the indices for a specified patch at a specified Level of Detail. + /** \param indices A reference to an array of u32 indices. + \param patchX Patch x coordinate. + \param patchZ Patch z coordinate. + \param LOD The level of detail to get for that patch. If -1, + then get the CurrentLOD. If the CurrentLOD is set to -1, + meaning it's not shown, then it will retrieve the triangles at + the highest LOD (0). + \return Number of indices put into the buffer. */ + virtual s32 getIndicesForPatch(core::array& indices, + s32 patchX, s32 patchZ, s32 LOD=0) =0; + + //! Populates an array with the CurrentLOD of each patch. + /** \param LODs A reference to a core::array to hold the + values + \return Number of elements in the array */ + virtual s32 getCurrentLODOfPatches(core::array& LODs) const =0; + + //! Manually sets the LOD of a patch + /** NOTE: Any values set here are overwritten again in the automatic + recalculations when the camera changes. + \param patchX Patch x coordinate. + \param patchZ Patch z coordinate. + \param LOD The level of detail to set the patch to. */ + virtual void setLODOfPatch(s32 patchX, s32 patchZ, s32 LOD=0) =0; + + //! Get center of terrain. + virtual const core::vector3df& getTerrainCenter() const =0; + + //! Get height of a point of the terrain. + virtual f32 getHeight(f32 x, f32 y) const =0; + + //! Sets the movement camera threshold. + /** It is used to determine when to recalculate + indices for the scene node. The default value is 10.0f. */ + virtual void setCameraMovementDelta(f32 delta) =0; + + //! Sets the rotation camera threshold. + /** It is used to determine when to recalculate + indices for the scene node. The default value is 1.0f. */ + virtual void setCameraRotationDelta(f32 delta) =0; + + //! Sets whether or not the node should dynamically update its associated selector when the geomipmap data changes. + /** \param bVal: Boolean value representing whether or not to update selector dynamically. */ + virtual void setDynamicSelectorUpdate(bool bVal) =0; + + //! Override the default generation of distance thresholds. + /** For determining the LOD a patch is rendered at. If any LOD + is overridden, then the scene node will no longer apply scaling + factors to these values. If you override these distances, and + then apply a scale to the scene node, it is your responsibility + to update the new distances to work best with your new terrain + size. */ + virtual bool overrideLODDistance(s32 LOD, f64 newDistance) =0; + + //! Scales the base texture, similar to makePlanarTextureMapping. + /** \param scale The scaling amount. Values above 1.0 + increase the number of time the texture is drawn on the + terrain. Values below 0 will decrease the number of times the + texture is drawn on the terrain. Using negative values will + flip the texture, as well as still scaling it. + \param scale2 If set to 0 (default value), this will set the + second texture coordinate set to the same values as in the + first set. If this is another value than zero, it will scale + the second texture coordinate set by this value. */ + virtual void scaleTexture(f32 scale = 1.0f, f32 scale2=0.0f) =0; + + //! Initializes the terrain data. Loads the vertices from the heightMapFile. + /** The file must contain a loadable image of the heightmap. The heightmap + must be square. + \param file The file to read the image from. File is not rewinded. + \param vertexColor Color of all vertices. + \param smoothFactor Number of smoothing passes. */ + virtual bool loadHeightMap(io::IReadFile* file, + video::SColor vertexColor=video::SColor(255,255,255,255), + s32 smoothFactor=0) =0; + + //! Initializes the terrain data. Loads the vertices from the heightMapFile. + /** The data is interpreted as (signed) integers of the given bit size or + floats (with 32bits, signed). Allowed bitsizes for integers are + 8, 16, and 32. The heightmap must be square. + \param file The file to read the RAW data from. File is not rewinded. + \param bitsPerPixel Size of data if integers used, for floats always use 32. + \param signedData Whether we use signed or unsigned ints, ignored for floats. + \param floatVals Whether the data is float or int. + \param width Width (and also Height, as it must be square) of the heightmap. Use 0 for autocalculating from the filesize. + \param vertexColor Color of all vertices. + \param smoothFactor Number of smoothing passes. */ + virtual bool loadHeightMapRAW(io::IReadFile* file, s32 bitsPerPixel=16, + bool signedData=false, bool floatVals=false, s32 width=0, + video::SColor vertexColor=video::SColor(255,255,255,255), + s32 smoothFactor=0) =0; + + //! Force node to use a fixed LOD level at the borders of the terrain. + /** This can be useful when several TerrainSceneNodes are connected. + \param borderLOD When >= 0 all patches at the 4 borders will use the + given LOD. When < 0 borders are just regular patches (that's default). */ + virtual void setFixedBorderLOD(irr::s32 borderLOD=0) = 0; + + }; + +} // end namespace scene +} // end namespace irr + + +#endif // __I_TERRAIN_SCENE_NODE_H__ + diff --git a/include/ITextSceneNode.h b/include/ITextSceneNode.h new file mode 100644 index 00000000..2e12379f --- /dev/null +++ b/include/ITextSceneNode.h @@ -0,0 +1,55 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_TEXT_SCENE_NODE_H_INCLUDED__ +#define __I_TEXT_SCENE_NODE_H_INCLUDED__ + +#include "ISceneNode.h" + +namespace irr +{ + +namespace gui +{ + class IGUIFont; +} + +namespace scene +{ + +//! A scene node for displaying 2d text at a position in three dimensional space +class ITextSceneNode : public ISceneNode +{ +public: + + //! constructor + ITextSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position = core::vector3df(0,0,0)) + : ISceneNode(parent, mgr, id, position) {} + + //! sets the text string + virtual void setText(const wchar_t* text) = 0; + + //! get the text string + virtual const wchar_t* getText() const = 0; + + //! sets the color of the text + virtual void setTextColor(video::SColor color) = 0; + + //! get the color of the text + virtual video::SColor getTextColor() const = 0; + + //! set the font used to draw the text + virtual void setFont(gui::IGUIFont* font) = 0; + + //! Get the font used to draw the text + virtual gui::IGUIFont* getFont() const = 0; +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/include/ITexture.h b/include/ITexture.h new file mode 100644 index 00000000..f975abd8 --- /dev/null +++ b/include/ITexture.h @@ -0,0 +1,350 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_TEXTURE_H_INCLUDED__ +#define __I_TEXTURE_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "IImage.h" +#include "dimension2d.h" +#include "EDriverTypes.h" +#include "path.h" +#include "matrix4.h" + +namespace irr +{ +namespace video +{ + + +//! Enumeration flags used to tell the video driver with setTextureCreationFlag in which format textures should be created. +enum E_TEXTURE_CREATION_FLAG +{ + /** Forces the driver to create 16 bit textures always, independent of + which format the file on disk has. When choosing this you may lose + some color detail, but gain much speed and memory. 16 bit textures can + be transferred twice as fast as 32 bit textures and only use half of + the space in memory. + When using this flag, it does not make sense to use the flags + ETCF_ALWAYS_32_BIT, ETCF_OPTIMIZED_FOR_QUALITY, or + ETCF_OPTIMIZED_FOR_SPEED at the same time. + Not all texture formats are affected (usually those up to ECF_A8R8G8B8). */ + ETCF_ALWAYS_16_BIT = 0x00000001, + + /** Forces the driver to create 32 bit textures always, independent of + which format the file on disk has. Please note that some drivers (like + the software device) will ignore this, because they are only able to + create and use 16 bit textures. + Default is true. + When using this flag, it does not make sense to use the flags + ETCF_ALWAYS_16_BIT, ETCF_OPTIMIZED_FOR_QUALITY, or + ETCF_OPTIMIZED_FOR_SPEED at the same time. + Not all texture formats are affected (usually those up to ECF_A8R8G8B8). */ + ETCF_ALWAYS_32_BIT = 0x00000002, + + /** Lets the driver decide in which format the textures are created and + tries to make the textures look as good as possible. Usually it simply + chooses the format in which the texture was stored on disk. + When using this flag, it does not make sense to use the flags + ETCF_ALWAYS_16_BIT, ETCF_ALWAYS_32_BIT, or ETCF_OPTIMIZED_FOR_SPEED at + the same time. + Not all texture formats are affected (usually those up to ECF_A8R8G8B8). */ + ETCF_OPTIMIZED_FOR_QUALITY = 0x00000004, + + /** Lets the driver decide in which format the textures are created and + tries to create them maximizing render speed. + When using this flag, it does not make sense to use the flags + ETCF_ALWAYS_16_BIT, ETCF_ALWAYS_32_BIT, or ETCF_OPTIMIZED_FOR_QUALITY, + at the same time. + Not all texture formats are affected (usually those up to ECF_A8R8G8B8). */ + ETCF_OPTIMIZED_FOR_SPEED = 0x00000008, + + /** Creates textures with mipmap levels. + If disabled textures can not have mipmaps. + Default is true. */ + ETCF_CREATE_MIP_MAPS = 0x00000010, + + /** Discard any alpha layer and use non-alpha color format. + Warning: This may lead to getting 24-bit texture formats which + are often badly supported by drivers. So it's generally + not recommended to enable this flag. */ + ETCF_NO_ALPHA_CHANNEL = 0x00000020, + + //! Allow the Driver to use Non-Power-2-Textures + /** BurningVideo can handle Non-Power-2 Textures in 2D (GUI), but not in 3D. */ + ETCF_ALLOW_NON_POWER_2 = 0x00000040, + + //! Allow the driver to keep a copy of the texture in memory + /** Enabling this makes calls to ITexture::lock a lot faster, but costs main memory. + Currently only used in combination with OpenGL drivers. + NOTE: Disabling this does not yet work correctly with alpha-textures. + So the default is on for now (but might change with Irrlicht 1.9 if we get the alpha-troubles fixed). + */ + ETCF_ALLOW_MEMORY_COPY = 0x00000080, + + //! Enable automatic updating mip maps when the base texture changes. + /** Default is true. + This flag is only used when ETCF_CREATE_MIP_MAPS is also enabled and if the driver supports it. + Please note: + - On D3D (and maybe older OGL?) you can no longer manually set mipmap data when enabled + (for example mips from image loading will be ignored). + - On D3D (and maybe older OGL?) texture locking for mipmap levels usually won't work anymore. + - On new OGL this flag is ignored. + - When disabled you do _not_ get hardware mipmaps on D3D, so mipmap generation can be slower. + - When disabled you can still update your mipmaps when the texture changed by manually calling regenerateMipMapLevels. + - You can still call regenerateMipMapLevels when this flag is enabled (it will be a hint on d3d to update mips immediately) + */ + ETCF_AUTO_GENERATE_MIP_MAPS = 0x00000100, + + /** This flag is never used, it only forces the compiler to compile + these enumeration values to 32 bit. */ + ETCF_FORCE_32_BIT_DO_NOT_USE = 0x7fffffff +}; + +//! Enum for the mode for texture locking. Read-Only, write-only or read/write. +enum E_TEXTURE_LOCK_MODE +{ + //! The default mode. Texture can be read and written to. + ETLM_READ_WRITE = 0, + + //! Read only. The texture is downloaded, but not uploaded again. + /** Often used to read back shader generated textures. */ + ETLM_READ_ONLY, + + //! Write only. The texture is not downloaded and might be uninitialized. + /** The updated texture is uploaded to the GPU. + Used for initializing the shader from the CPU. */ + ETLM_WRITE_ONLY +}; + +//! Additional bitflags for ITexture::lock() call +enum E_TEXTURE_LOCK_FLAGS +{ + ETLF_NONE = 0, + + //! Flip left-bottom origin rendertarget textures upside-down + /** Irrlicht usually has all textures with left-top as origin. + And for drivers with a left-bottom origin coordinate system (OpenGL) + Irrlicht modifies the texture-matrix in the fixed function pipeline to make + the textures show up correctly (shader coders have to handle upside down + textures themselves). + But rendertarget textures (RTT's) are written by drivers the way the + coordinate system of that driver works. So on OpenGL images tend to look + upside down (aka Y coordinate going up) on lock() when this flag isn't set. + When the flag is set it will flip such textures on lock() to make them look + like non-rtt textures (origin left-top). Note that this also means the texture + will be uploaded flipped on unlock. So mostly you want to have this flag set + when you want to look at the texture or save it, but unset if you want to + upload it again to the card. + If you disable this flag you get the memory just as it is on the graphic card. + For backward compatibility reasons this flag is enabled by default. */ + ETLF_FLIP_Y_UP_RTT = 1 +}; + +//! Where did the last IVideoDriver::getTexture call find this texture +enum E_TEXTURE_SOURCE +{ + //! IVideoDriver::getTexture was never called (texture created otherwise) + ETS_UNKNOWN, + + //! Texture has been found in cache + ETS_FROM_CACHE, + + //! Texture had to be loaded + ETS_FROM_FILE +}; + +//! Enumeration describing the type of ITexture. +enum E_TEXTURE_TYPE +{ + //! 2D texture. + ETT_2D, + + //! Cubemap texture. + ETT_CUBEMAP +}; + +//! Interface of a Video Driver dependent Texture. +/** An ITexture is created by an IVideoDriver by using IVideoDriver::addTexture +or IVideoDriver::getTexture. After that, the texture may only be used by this +VideoDriver. As you can imagine, textures of the DirectX and the OpenGL device +will, e.g., not be compatible. An exception is the Software device and the +NULL device, their textures are compatible. If you try to use a texture +created by one device with an other device, the device will refuse to do that +and write a warning or an error message to the output buffer. +*/ +class ITexture : public virtual IReferenceCounted +{ +public: + + //! constructor + ITexture(const io::path& name, E_TEXTURE_TYPE type) : NamedPath(name), DriverType(EDT_NULL), OriginalColorFormat(ECF_UNKNOWN), + ColorFormat(ECF_UNKNOWN), Pitch(0), HasMipMaps(false), IsRenderTarget(false), Source(ETS_UNKNOWN), Type(type) + { + } + + //! Lock function. + /** Locks the Texture and returns a pointer to access the + pixels. After lock() has been called and all operations on the pixels + are done, you must call unlock(). + Locks are not accumulating, hence one unlock will do for an arbitrary + number of previous locks. You should avoid locking different levels without + unlocking in between, though, because only the last level locked will be + unlocked. + The size of the i-th mipmap level is defined as max(getSize().Width>>i,1) + and max(getSize().Height>>i,1) + \param mode Specifies what kind of changes to the locked texture are + allowed. Unspecified behavior will arise if texture is written in read + only mode or read from in write only mode. + Support for this feature depends on the driver, so don't rely on the + texture being write-protected when locking with read-only, etc. + \param mipmapLevel NOTE: Currently broken, sorry, we try if we can repair it for 1.9 release. + Number of the mipmapLevel to lock. 0 is main texture. + Non-existing levels will silently fail and return 0. + \param layer It determines which cubemap face or texture array layer should be locked. + \param lockFlags See E_TEXTURE_LOCK_FLAGS documentation. + \return Returns a pointer to the pixel data. The format of the pixel can + be determined by using getColorFormat(). 0 is returned, if + the texture cannot be locked. */ + virtual void* lock(E_TEXTURE_LOCK_MODE mode = ETLM_READ_WRITE, u32 mipmapLevel=0, u32 layer = 0, E_TEXTURE_LOCK_FLAGS lockFlags = ETLF_FLIP_Y_UP_RTT) = 0; + + //! Unlock function. Must be called after a lock() to the texture. + /** One should avoid to call unlock more than once before another lock. + The last locked mip level will be unlocked. + You may want to call regenerateMipMapLevels() after this when you changed any data. */ + virtual void unlock() = 0; + + //! Regenerates the mip map levels of the texture. + /** Required after modifying the texture, usually after calling unlock(). + \param data Optional parameter to pass in image data which will be + used instead of the previously stored or automatically generated mipmap + data. The data has to be a continuous pixel data for all mipmaps until + 1x1 pixel. Each mipmap has to be half the width and height of the previous + level. At least one pixel will be always kept. + \param layer It informs a texture about which cubemap or texture array layer + needs mipmap regeneration. */ + virtual void regenerateMipMapLevels(void* data = 0, u32 layer = 0) = 0; + + //! Get original size of the texture. + /** The texture is usually scaled, if it was created with an unoptimal + size. For example if the size was not a power of two. This method + returns the size of the texture it had before it was scaled. Can be + useful when drawing 2d images on the screen, which should have the + exact size of the original texture. Use ITexture::getSize() if you want + to know the real size it has now stored in the system. + \return The original size of the texture. */ + const core::dimension2d& getOriginalSize() const { return OriginalSize; }; + + //! Get dimension (=size) of the texture. + /** \return The size of the texture. */ + const core::dimension2d& getSize() const { return Size; }; + + //! Get driver type of texture. + /** This is the driver, which created the texture. This method is used + internally by the video devices, to check, if they may use a texture + because textures may be incompatible between different devices. + \return Driver type of texture. */ + E_DRIVER_TYPE getDriverType() const { return DriverType; }; + + //! Get the color format of texture. + /** \return The color format of texture. */ + ECOLOR_FORMAT getColorFormat() const { return ColorFormat; }; + + //! Get the original color format + /** When create textures from image data we will often use different color formats. + For example depending on driver TextureCreationFlag's. + This can give you the original format which the image used to create the texture had */ + ECOLOR_FORMAT getOriginalColorFormat() const { return OriginalColorFormat; }; + + //! Get pitch of the main texture (in bytes). + /** The pitch is the amount of bytes used for a row of pixels in a + texture. + \return Pitch of texture in bytes. */ + u32 getPitch() const { return Pitch; }; + + //! Check whether the texture has MipMaps + /** \return True if texture has MipMaps, else false. */ + bool hasMipMaps() const { return HasMipMaps; } + + //! Check whether the texture is a render target + /** Render targets can be set as such in the video driver, in order to + render a scene into the texture. Once unbound as render target, they can + be used just as usual textures again. + \return True if this is a render target, otherwise false. */ + bool isRenderTarget() const { return IsRenderTarget; } + + //! Get name of texture (in most cases this is the filename) + const io::SNamedPath& getName() const { return NamedPath; } + + //! Check where the last IVideoDriver::getTexture found this texture + E_TEXTURE_SOURCE getSource() const { return Source; } + + //! Used internally by the engine to update Source status on IVideoDriver::getTexture calls. + void updateSource(E_TEXTURE_SOURCE source) { Source = source; } + + //! Returns if the texture has an alpha channel + bool hasAlpha() const + { + bool status = false; + + switch (ColorFormat) + { + case ECF_A8R8G8B8: + case ECF_A1R5G5B5: + case ECF_DXT1: + case ECF_DXT2: + case ECF_DXT3: + case ECF_DXT4: + case ECF_DXT5: + case ECF_A16B16G16R16F: + case ECF_A32B32G32R32F: + status = true; + break; + default: + break; + } + + return status; + } + + //! Returns the type of texture + E_TEXTURE_TYPE getType() const { return Type; } + +protected: + + //! Helper function, helps to get the desired texture creation format from the flags. + /** \return Either ETCF_ALWAYS_32_BIT, ETCF_ALWAYS_16_BIT, + ETCF_OPTIMIZED_FOR_QUALITY, or ETCF_OPTIMIZED_FOR_SPEED. */ + inline E_TEXTURE_CREATION_FLAG getTextureFormatFromFlags(u32 flags) + { + if (flags & ETCF_OPTIMIZED_FOR_SPEED) + return ETCF_OPTIMIZED_FOR_SPEED; + if (flags & ETCF_ALWAYS_16_BIT) + return ETCF_ALWAYS_16_BIT; + if (flags & ETCF_ALWAYS_32_BIT) + return ETCF_ALWAYS_32_BIT; + if (flags & ETCF_OPTIMIZED_FOR_QUALITY) + return ETCF_OPTIMIZED_FOR_QUALITY; + return ETCF_OPTIMIZED_FOR_SPEED; + } + + io::SNamedPath NamedPath; + core::dimension2d OriginalSize; + core::dimension2d Size; + E_DRIVER_TYPE DriverType; + ECOLOR_FORMAT OriginalColorFormat; + ECOLOR_FORMAT ColorFormat; + u32 Pitch; + bool HasMipMaps; + bool IsRenderTarget; + E_TEXTURE_SOURCE Source; + E_TEXTURE_TYPE Type; +}; + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/include/ITimer.h b/include/ITimer.h new file mode 100644 index 00000000..709db975 --- /dev/null +++ b/include/ITimer.h @@ -0,0 +1,103 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_TIMER_H_INCLUDED__ +#define __I_TIMER_H_INCLUDED__ + +#include "IReferenceCounted.h" + +namespace irr +{ + +//! Interface for getting and manipulating the virtual time +class ITimer : public virtual IReferenceCounted +{ +public: + //! Returns current real time in milliseconds of the system. + /** This value does not start with 0 when the application starts. + For example in one implementation the value returned could be the + amount of milliseconds which have elapsed since the system was started. + */ + virtual u32 getRealTime() const = 0; + + enum EWeekday + { + EWD_SUNDAY=0, + EWD_MONDAY, + EWD_TUESDAY, + EWD_WEDNESDAY, + EWD_THURSDAY, + EWD_FRIDAY, + EWD_SATURDAY + }; + + struct RealTimeDate + { + // Hour of the day, from 0 to 23 + u32 Hour; + // Minute of the hour, from 0 to 59 + u32 Minute; + // Second of the minute, due to extra seconds from 0 to 61 + u32 Second; + // Year of the Gregorian calender + s32 Year; + // Month of the year, from 1 to 12 + u32 Month; + // Day of the month, from 1 to 31 + u32 Day; + // Weekday for the current day + EWeekday Weekday; + // Day of the year, from 1 to 366 + u32 Yearday; + // Whether daylight saving is on + bool IsDST; + }; + + virtual RealTimeDate getRealTimeAndDate() const = 0; + + //! Returns current virtual time in milliseconds. + /** This value starts with 0 and can be manipulated using setTime(), + stopTimer(), startTimer(), etc. This value depends on the set speed of + the timer if the timer is stopped, etc. If you need the system time, + use getRealTime() */ + virtual u32 getTime() const = 0; + + //! sets current virtual time + virtual void setTime(u32 time) = 0; + + //! Stops the virtual timer. + /** The timer is reference counted, which means everything which calls + stop() will also have to call start(), otherwise the timer may not + start/stop correctly again. */ + virtual void stop() = 0; + + //! Starts the virtual timer. + /** The timer is reference counted, which means everything which calls + stop() will also have to call start(), otherwise the timer may not + start/stop correctly again. */ + virtual void start() = 0; + + //! Sets the speed of the timer + /** The speed is the factor with which the time is running faster or + slower then the real system time. */ + virtual void setSpeed(f32 speed = 1.0f) = 0; + + //! Returns current speed of the timer + /** The speed is the factor with which the time is running faster or + slower then the real system time. */ + virtual f32 getSpeed() const = 0; + + //! Returns if the virtual timer is currently stopped + virtual bool isStopped() const = 0; + + //! Advances the virtual time + /** Makes the virtual timer update the time value based on the real + time. This is called automatically when calling IrrlichtDevice::run(), + but you can call it manually if you don't use this method. */ + virtual void tick() = 0; +}; + +} // end namespace irr + +#endif diff --git a/include/ITriangleSelector.h b/include/ITriangleSelector.h new file mode 100644 index 00000000..04aa0467 --- /dev/null +++ b/include/ITriangleSelector.h @@ -0,0 +1,195 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_TRIANGLE_SELECTOR_H_INCLUDED__ +#define __I_TRIANGLE_SELECTOR_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "triangle3d.h" +#include "aabbox3d.h" +#include "matrix4.h" +#include "line3d.h" +#include "irrArray.h" + +namespace irr +{ +namespace scene +{ + +class ISceneNode; +class ITriangleSelector; +class IMeshBuffer; + +//! Additional information about the triangle arrays returned by ITriangleSelector::getTriangles +/** ITriangleSelector are free to fill out this information fully, partly or ignore it. + Usually they will try to fill it when they can and set values to 0 otherwise. +*/ +struct SCollisionTriangleRange +{ + SCollisionTriangleRange() + : RangeStart(0), RangeSize(0) + , Selector(0), SceneNode(0) + , MeshBuffer(0), MaterialIndex(0) + {} + + //! Check if this triangle index inside the range + /** + \param triangleIndex Index to an element inside the array of triangles returned by ITriangleSelector::getTriangles + */ + bool isIndexInRange(irr::u32 triangleIndex) const + { + return triangleIndex >= RangeStart && triangleIndex < RangeStart+RangeSize; + } + + //! First index in the returned triangle array for which this struct is valid + irr::u32 RangeStart; + + //! Number of elements in the returned triangle array for which this struct is valid (starting with RangeStart) + irr::u32 RangeSize; + + //! Real selector which contained those triangles (useful when working with MetaTriangleSelector) + ITriangleSelector* Selector; + + //! SceneNode from which the triangles are from + ISceneNode* SceneNode; + + //! Meshbuffer from which the triangles are from + //! Is 0 when the ITriangleSelector doesn't support meshbuffer selection + const IMeshBuffer* MeshBuffer; + + //! Index of selected material in the SceneNode. Usually only valid when MeshBuffer is also set, otherwise always 0 + irr::u32 MaterialIndex; +}; + +//! Interface to return triangles with specific properties. +/** Every ISceneNode may have a triangle selector, available with +ISceneNode::getTriangleSelector() or ISceneManager::createTriangleSelector. +This is used for doing collision detection: For example if you know, that a +collision may have happened in the area between (1,1,1) and (10,10,10), you +can get all triangles of the scene node in this area with the +ITriangleSelector easily and check every triangle if it collided. */ +class ITriangleSelector : public virtual IReferenceCounted +{ +public: + + //! Get amount of all available triangles in this selector + virtual s32 getTriangleCount() const = 0; + + //! 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 + into the array. + \param transform Pointer to matrix for transforming the triangles + before they are returned. Useful for example to scale all triangles + down into an ellipsoid space. + \param useNodeTransform When the selector has a node then transform the + triangles by that node's transformation matrix. + \param outTriangleInfo When a pointer to an array is passed then that + array is filled with additional information about the returned triangles. + One element of SCollisionTriangleRange added for each range of triangles which + has distinguishable information. For example one range per meshbuffer. + */ + virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, + s32& outTriangleCount, const core::matrix4* transform=0, + bool useNodeTransform=true, + irr::core::array* outTriangleInfo=0) const = 0; + + //! Gets the triangles for one associated node which may lie within a specific bounding box. + /** + 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. + + This method will return at least the triangles that intersect the box, + but may return other triangles as well. + \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 + into the array. + \param box Only triangles which are in this axis aligned bounding box + will be written into the array. + \param transform Pointer to matrix for transforming the triangles + before they are returned. Useful for example to scale all triangles + down into an ellipsoid space. + \param useNodeTransform When the selector has a node then transform the + triangles by that node's transformation matrix. + \param outTriangleInfo When a pointer to an array is passed then that + array is filled with additional information about the returned triangles. + One element of SCollisionTriangleRange added for each range of triangles which + has distinguishable information. For example one range per meshbuffer. */ + virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, + s32& outTriangleCount, const core::aabbox3d& box, + const core::matrix4* transform=0, bool useNodeTransform=true, + irr::core::array* outTriangleInfo=0) const = 0; + + //! Gets the triangles for one associated node which have or may have contact with a 3d line. + /** + 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. + \param arraySize Size of the target array. + \param outTriangleCount Amount of triangles which have been written + into the array. + \param line Only triangles which may be in contact with this 3d line + will be written into the array. + \param transform Pointer to matrix for transforming the triangles + before they are returned. Useful for example to scale all triangles + down into an ellipsoid space. + \param useNodeTransform When the selector has a node then transform the + triangles by that node's transformation matrix. + \param outTriangleInfo When a pointer to an array is passed then that + array is filled with additional information about the returned triangles. + One element of SCollisionTriangleRange added for each range of triangles which + has distinguishable information. For example one range per meshbuffer. */ + virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, + s32& outTriangleCount, const core::line3d& line, + const core::matrix4* transform=0, bool useNodeTransform=true, + irr::core::array* outTriangleInfo=0) const = 0; + + //! Get number of TriangleSelectors that are part of this one + /** Only useful for MetaTriangleSelector, others return 1 + */ + virtual u32 getSelectorCount() const = 0; + + //! Get TriangleSelector based on index based on getSelectorCount + /** Only useful for MetaTriangleSelector, others return 'this' or 0 + */ + virtual ITriangleSelector* getSelector(u32 index) = 0; + + //! Get TriangleSelector based on index based on getSelectorCount + /** Only useful for MetaTriangleSelector, others return 'this' or 0 + */ + virtual const ITriangleSelector* getSelector(u32 index) const = 0; + + //! Get scene node associated with a given triangle. + /** With CMetaTriangleSelector-selectors it's possible to find out a node + belonging to a certain triangle index. + NOTE: triangleIndex has nothing to do with the order of triangles returned by getTriangles functions! + So you can _not_ use this function to find out anything about to which node returned triangles belong. + Use STriangleCollisionInfo struct for that. + \param triangleIndex: the index of the triangle for which you want to find. + \return The scene node associated with that triangle. + */ + virtual ISceneNode* getSceneNodeForTriangle(u32 triangleIndex) const = 0; +}; + +} // end namespace scene +} // end namespace irr + +#endif diff --git a/include/IVertexBuffer.h b/include/IVertexBuffer.h new file mode 100644 index 00000000..87603dea --- /dev/null +++ b/include/IVertexBuffer.h @@ -0,0 +1,52 @@ +// Copyright (C) 2008-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_VERTEX_BUFFER_H_INCLUDED__ +#define __I_VERTEX_BUFFER_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "irrArray.h" +#include "S3DVertex.h" + +namespace irr +{ +namespace scene +{ + + class IVertexBuffer : public virtual IReferenceCounted + { + public: + virtual void* getData() =0; + virtual video::E_VERTEX_TYPE getType() const =0; + virtual void setType(video::E_VERTEX_TYPE vertexType) =0; + virtual u32 stride() const =0; + virtual u32 size() const =0; + virtual void push_back(const video::S3DVertex &element) =0; + virtual video::S3DVertex& operator [](const u32 index) const =0; + virtual video::S3DVertex& getLast() =0; + virtual void set_used(u32 usedNow) =0; + virtual void reallocate(u32 new_size) =0; + virtual u32 allocated_size() const =0; + virtual video::S3DVertex* pointer() =0; + + //! get the current hardware mapping hint + virtual E_HARDWARE_MAPPING getHardwareMappingHint() const =0; + + //! set the hardware mapping hint, for driver + virtual void setHardwareMappingHint( E_HARDWARE_MAPPING NewMappingHint ) =0; + + //! flags the meshbuffer as changed, reloads hardware buffers + virtual void setDirty() =0; + + //! Get the currently used ID for identification of changes. + /** This shouldn't be used for anything outside the VideoDriver. */ + virtual u32 getChangedID() const = 0; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/IVideoDriver.h b/include/IVideoDriver.h new file mode 100644 index 00000000..a8031afc --- /dev/null +++ b/include/IVideoDriver.h @@ -0,0 +1,1538 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_I_VIDEO_DRIVER_H_INCLUDED__ +#define __IRR_I_VIDEO_DRIVER_H_INCLUDED__ + +#include "rect.h" +#include "SColor.h" +#include "ITexture.h" +#include "irrArray.h" +#include "matrix4.h" +#include "plane3d.h" +#include "dimension2d.h" +#include "position2d.h" +#include "IMeshBuffer.h" +#include "triangle3d.h" +#include "EDriverTypes.h" +#include "EDriverFeatures.h" +#include "SExposedVideoData.h" +#include "SOverrideMaterial.h" + +namespace irr +{ +namespace io +{ + class IAttributes; + struct SAttributeReadWriteOptions; + class IReadFile; + class IWriteFile; +} // end namespace io +namespace scene +{ + class IMeshBuffer; + class IMesh; + class IMeshManipulator; + class ISceneNode; +} // end namespace scene + +namespace video +{ + struct S3DVertex; + struct S3DVertex2TCoords; + struct S3DVertexTangents; + struct SLight; + class IImageLoader; + class IImageWriter; + class IMaterialRenderer; + class IGPUProgrammingServices; + class IRenderTarget; + + //! enumeration for geometry transformation states + enum E_TRANSFORMATION_STATE + { + //! View transformation + ETS_VIEW = 0, + //! World transformation + ETS_WORLD, + //! Projection transformation + ETS_PROJECTION, + //! Texture transformation + ETS_TEXTURE_0, + //! Texture transformation + ETS_TEXTURE_1, + //! Texture transformation + ETS_TEXTURE_2, + //! Texture transformation + ETS_TEXTURE_3, +#if _IRR_MATERIAL_MAX_TEXTURES_>4 + //! Texture transformation + ETS_TEXTURE_4, +#if _IRR_MATERIAL_MAX_TEXTURES_>5 + //! Texture transformation + ETS_TEXTURE_5, +#if _IRR_MATERIAL_MAX_TEXTURES_>6 + //! Texture transformation + ETS_TEXTURE_6, +#if _IRR_MATERIAL_MAX_TEXTURES_>7 + //! Texture transformation + ETS_TEXTURE_7, +#endif +#endif +#endif +#endif + //! Only used internally + ETS_COUNT = ETS_TEXTURE_0 + _IRR_MATERIAL_MAX_TEXTURES_ + }; + + //! Special render targets, which usually map to dedicated hardware + /** These render targets (besides 0 and 1) need not be supported by gfx cards */ + enum E_RENDER_TARGET + { + //! Render target is the main color frame buffer + ERT_FRAME_BUFFER=0, + //! Render target is a render texture + ERT_RENDER_TEXTURE, + //! Multi-Render target textures + ERT_MULTI_RENDER_TEXTURES, + //! Render target is the main color frame buffer + ERT_STEREO_LEFT_BUFFER, + //! 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 + }; + + //! Enum for the flags of clear buffer + enum E_CLEAR_BUFFER_FLAG + { + ECBF_NONE = 0, + ECBF_COLOR = 1, + ECBF_DEPTH = 2, + ECBF_STENCIL = 4, + ECBF_ALL = ECBF_COLOR|ECBF_DEPTH|ECBF_STENCIL + }; + + //! Enum for the types of fog distributions to choose from + enum E_FOG_TYPE + { + EFT_FOG_EXP=0, + EFT_FOG_LINEAR, + EFT_FOG_EXP2 + }; + + const c8* const FogTypeNames[] = + { + "FogExp", + "FogLinear", + "FogExp2", + 0 + }; + + //! 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 + this interface. You are able to use the Irrlicht Engine by only + invoking methods of this interface if you like to, although the + irr::scene::ISceneManager interface provides a lot of powerful classes + and methods to make the programmer's life easier. + */ + class IVideoDriver : public virtual IReferenceCounted + { + public: + + //! Applications must call this method before performing any rendering. + /** This method can clear the back- and the z-buffer. + \param clearFlag A combination of the E_CLEAR_BUFFER_FLAG bit-flags. + \param clearColor The clear color for the color buffer. + \param clearDepth The clear value for the depth buffer. + \param clearStencil The clear value for the stencil buffer. + \param videoData Handle of another window, if you want the + bitmap to be displayed on another window. If this is an empty + element, everything will be displayed in the default window. + Note: This feature is not fully implemented for all devices. + \param sourceRect Pointer to a rectangle defining the source + rectangle of the area to be presented. Set to null to present + everything. Note: not implemented in all devices. + \return False if failed. */ + virtual bool beginScene(u16 clearFlag=(u16)(ECBF_COLOR|ECBF_DEPTH), SColor clearColor = SColor(255,0,0,0), f32 clearDepth = 1.f, u8 clearStencil = 0, + const SExposedVideoData& videoData=SExposedVideoData(), core::rect* sourceRect = 0) = 0; + + //! Alternative beginScene implementation. Can't clear stencil buffer, but otherwise identical to other beginScene + bool beginScene(bool backBuffer, bool zBuffer, SColor color = SColor(255,0,0,0), + const SExposedVideoData& videoData = SExposedVideoData(), core::rect* sourceRect = 0) + { + u16 flag = 0; + + if (backBuffer) + flag |= ECBF_COLOR; + + if (zBuffer) + flag |= ECBF_DEPTH; + + return beginScene(flag, color, 1.f, 0, videoData, sourceRect); + } + + //! 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; + + //! 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; + + //! Disable a feature of the driver. + /** Can also be used to enable the features again. It is not + possible to enable unsupported features this way, though. + \param feature Feature to disable. + \param flag When true the feature is disabled, otherwise it is enabled. */ + virtual void disableFeature(E_VIDEO_DRIVER_FEATURE feature, bool flag=true) =0; + + //! Get attributes of the actual video driver + /** The following names can be queried for the given types: + MaxTextures (int) The maximum number of simultaneous textures supported by the driver. This can be less than the supported number of textures of the driver. Use _IRR_MATERIAL_MAX_TEXTURES_ to adapt the number. + MaxSupportedTextures (int) The maximum number of simultaneous textures supported by the fixed function pipeline of the (hw) driver. The actual supported number of textures supported by the engine can be lower. + MaxLights (int) Number of hardware lights supported in the fixed function pipeline of the driver, typically 6-8. Use light manager or deferred shading for more. + MaxAnisotropy (int) Number of anisotropy levels supported for filtering. At least 1, max is typically at 16 or 32. + MaxUserClipPlanes (int) Number of additional clip planes, which can be set by the user via dedicated driver methods. + MaxAuxBuffers (int) Special render buffers, which are currently not really usable inside Irrlicht. Only supported by OpenGL + MaxMultipleRenderTargets (int) Number of render targets which can be bound simultaneously. Rendering to MRTs is done via shaders. + MaxIndices (int) Number of indices which can be used in one render call (i.e. one mesh buffer). + MaxTextureSize (int) Dimension that a texture may have, both in width and height. + MaxGeometryVerticesOut (int) Number of vertices the geometry shader can output in one pass. Only OpenGL so far. + MaxTextureLODBias (float) Maximum value for LOD bias. Is usually at around 16, but can be lower on some systems. + Version (int) Version of the driver. Should be Major*100+Minor + ShaderLanguageVersion (int) Version of the high level shader language. Should be Major*100+Minor. + AntiAlias (int) Number of Samples the driver uses for each pixel. 0 and 1 means anti aliasing is off, typical values are 2,4,8,16,32 + */ + virtual const io::IAttributes& getDriverAttributes() const=0; + + //! Check if the driver was recently reset. + /** For d3d devices you will need to recreate the RTTs if the + driver was reset. Should be queried right after beginScene(). + */ + virtual bool checkDriverReset() =0; + + //! Sets transformation matrices. + /** \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; + + //! 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; + + //! Retrieve the number of image loaders + /** \return Number of image loaders */ + virtual u32 getImageLoaderCount() const = 0; + + //! Retrieve the given image loader + /** \param n The index of the loader to retrieve. This parameter is an 0-based + array index. + \return A pointer to the specified loader, 0 if the index is incorrect. */ + virtual IImageLoader* getImageLoader(u32 n) = 0; + + //! Retrieve the number of image writers + /** \return Number of image writers */ + virtual u32 getImageWriterCount() const = 0; + + //! Retrieve the given image writer + /** \param n The index of the writer to retrieve. This parameter is an 0-based + array index. + \return A pointer to the specified writer, 0 if the index is incorrect. */ + virtual IImageWriter* getImageWriter(u32 n) = 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; + + //! Get access to a named texture. + /** Loads the texture from disk if it is not + already loaded and generates mipmap levels if desired. + Texture loading can be influenced using the + setTextureCreationFlag() method. The texture can be in several + imageformats, such as BMP, JPG, TGA, PCX, PNG, and PSD. + \param filename Filename of the texture to be loaded. + \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 io::path& filename) = 0; + + //! Get access to a named texture. + /** Loads the texture from disk if it is not + already loaded and generates mipmap levels if desired. + Texture loading can be influenced using the + setTextureCreationFlag() method. The texture can be in several + imageformats, such as BMP, JPG, TGA, PCX, PNG, and PSD. + \param file Pointer to an already opened file. + \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; + + //! Returns a texture by index + /** \param index: Index of the texture, must be smaller than + getTextureCount() Please note that this index might change when + adding or removing textures + \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; + + //! Returns amount of textures currently loaded + /** \return Amount of textures currently loaded */ + virtual u32 getTextureCount() const = 0; + + //! 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 io::path& newName) = 0; + + //! Creates an empty texture of specified size. + /** \param size: Size of the texture. + \param name A name for the texture. Later calls to + getTexture() with this name will return this texture. + The name can _not_ be empty. + \param format Desired color format of the texture. Please note + that the driver may choose to create the texture in another + color format. + \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 io::path& name, ECOLOR_FORMAT format = ECF_A8R8G8B8) = 0; + + //! Creates a texture from an IImage. + /** \param name A name for the texture. Later calls of + getTexture() with this name will return this texture. + The name can _not_ be empty. + \param image Image the texture is created from. + \param mipmapData Optional pointer to a mipmaps data. + If this parameter is not given, the mipmaps are derived from image. + \return Pointer to the newly created texture. This pointer + should not be dropped. See IReferenceCounted::drop() for more + information. */ + _IRR_DEPRECATED_ ITexture* addTexture(const io::path& name, IImage* image, void* mipmapData) + { + if (image) + image->setMipMapsData(mipmapData, false, true); + + return addTexture(name, image); + } + + //! Creates a texture from an IImage. + /** \param name A name for the texture. Later calls of + getTexture() with this name will return this texture. + The name can _not_ be empty. + \param image Image the texture is created from. + \return Pointer to the newly created texture. This pointer + should not be dropped. See IReferenceCounted::drop() for more + information. */ + virtual ITexture* addTexture(const io::path& name, IImage* image) = 0; + + //! Creates a cubemap texture from loaded IImages. + /** \param name A name for the texture. Later calls of getTexture() with this name will return this texture. + The name can _not_ be empty. + \param imagePosX Image (positive X) the texture is created from. + \param imageNegX Image (negative X) the texture is created from. + \param imagePosY Image (positive Y) the texture is created from. + \param imageNegY Image (negative Y) the texture is created from. + \param imagePosZ Image (positive Z) the texture is created from. + \param imageNegZ Image (negative Z) the texture is created from. + \return Pointer to the newly created texture. This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual ITexture* addTextureCubemap(const io::path& name, IImage* imagePosX, IImage* imageNegX, IImage* imagePosY, + IImage* imageNegY, IImage* imagePosZ, IImage* imageNegZ) = 0; + + //! Creates an empty cubemap texture of specified size. + /** \param sideLen diameter of one side of the cube + \param name A name for the texture. Later calls of + getTexture() with this name will return this texture. + The name can _not_ be empty. + \param format Desired color format of the texture. Please note + that the driver may choose to create the texture in another + color format. + \return Pointer to the newly created texture. */ + virtual ITexture* addTextureCubemap(const irr::u32 sideLen, const io::path& name, ECOLOR_FORMAT format = ECF_A8R8G8B8) = 0; + + //! Adds a new render target texture to the texture cache. + /** \param size Size of the texture, in pixels. Width and + height should be a power of two (e.g. 64, 128, 256, 512, ...) + and it should not be bigger than the backbuffer, because it + shares the zbuffer with the screen buffer. + \param name A name for the texture. Later calls of getTexture() with this name will return this texture. + The name can _not_ be empty. + \param format The color format of the render target. Floating point formats are supported. + \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, + const io::path& name = "rt", const ECOLOR_FORMAT format = ECF_UNKNOWN) =0; + + //! Adds a new render target texture with 6 sides for a cubemap map to the texture cache. + /** NOTE: Only supported on D3D9 so far. + \param sideLen Length of one cubemap side. + \param name A name for the texture. Later calls of getTexture() with this name will return this texture. + The name can _not_ be empty. + \param format The color format of the render target. Floating point formats are supported. + \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* addRenderTargetTextureCubemap(const irr::u32 sideLen, + const io::path& name = "rt", const ECOLOR_FORMAT format = ECF_UNKNOWN) =0; + + //! Removes a texture from the texture cache and deletes it. + /** This method can free a lot of memory! + Please note that after calling this, the pointer to the + ITexture may no longer be valid, if it was not grabbed before + 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. + \param texture Texture to delete from the engine cache. */ + virtual void removeTexture(ITexture* texture) =0; + + //! Removes all textures from the texture cache and deletes them. + /** This method can free a lot of memory! + Please note that after calling this, the pointer to the + ITexture may no longer be valid, if it was not grabbed before + 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; + + //! Remove hardware buffer + virtual void removeHardwareBuffer(const scene::IMeshBuffer* mb) =0; + + //! Remove all hardware buffers + virtual void removeAllHardwareBuffers() =0; + + //! Create occlusion query. + /** Use node for identification and mesh for occlusion test. */ + virtual void addOcclusionQuery(scene::ISceneNode* node, + const scene::IMesh* mesh=0) =0; + + //! Remove occlusion query. + virtual void removeOcclusionQuery(scene::ISceneNode* node) =0; + + //! Remove all occlusion queries. + virtual void removeAllOcclusionQueries() =0; + + //! Run occlusion query. Draws mesh stored in query. + /** If the mesh shall not be rendered visible, use + overrideMaterial to disable the color and depth buffer. */ + virtual void runOcclusionQuery(scene::ISceneNode* node, bool visible=false) =0; + + //! Run all occlusion queries. Draws all meshes stored in queries. + /** If the meshes shall not be rendered visible, use + overrideMaterial to disable the color and depth buffer. */ + virtual void runAllOcclusionQueries(bool visible=false) =0; + + //! Update occlusion query. Retrieves results from GPU. + /** If the query shall not block, set the flag to false. + Update might not occur in this case, though */ + virtual void updateOcclusionQuery(scene::ISceneNode* node, bool block=true) =0; + + //! Update all occlusion queries. Retrieves results from GPU. + /** If the query shall not block, set the flag to false. + Update might not occur in this case, though */ + virtual void updateAllOcclusionQueries(bool block=true) =0; + + //! Return query result. + /** Return value is the number of visible pixels/fragments. + The value is a safe approximation, i.e. can be larger than the + actual value of pixels. */ + virtual u32 getOcclusionQueryResult(scene::ISceneNode* node) const =0; + + //! Create render target. + virtual IRenderTarget* addRenderTarget() = 0; + + //! Remove render target. + virtual void removeRenderTarget(IRenderTarget* renderTarget) = 0; + + //! Remove all render targets. + virtual void removeAllRenderTargets() = 0; + + //! 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. The alpha of other texels is not modified. + \param texture Texture whose alpha channel is modified. + \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. + \param zeroTexels \deprecated 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 behavior matches the legacy (buggy) behavior prior + to release 1.5 and is provided for backwards compatibility only. + This parameter may be removed by Irrlicht 1.9. */ + virtual void makeColorKeyTexture(video::ITexture* texture, + video::SColor color, + bool zeroTexels = false) const =0; + + //! 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 texel with this color will become fully transparent as + described above. + \param zeroTexels \deprecated 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 behavior matches the legacy (buggy) behavior prior + to release 1.5 and is provided for backwards compatibility only. + This parameter may be removed by Irrlicht 1.9. */ + virtual void makeColorKeyTexture(video::ITexture* texture, + core::position2d colorKeyPixelPos, + bool zeroTexels = false) const =0; + + //! Creates a normal map from a height map texture. + /** As input is considered to be a height map the texture is read like: + - For a 32-bit texture only the red channel is regarded + - For a 16-bit texture the rgb-values are averaged. + Output channels red/green for X/Y and blue for up (Z). + For a 32-bit texture we store additionally the height value in the + alpha channel. This value is used by the video::EMT_PARALLAX_MAP_SOLID + material and similar materials. + On the borders the texture is considered to repeat. + \param texture Height map texture which is converted to a normal map. + \param amplitude Constant value by which the height + information is multiplied.*/ + virtual void makeNormalMapTexture(video::ITexture* texture, f32 amplitude=1.0f) const =0; + + //! Set a render target. + /** This will only work if the driver supports the + EVDF_RENDER_TO_TARGET feature, which can be queried with + queryFeature(). Please note that you cannot render 3D or 2D + geometry with a render target as texture on it when you are rendering + the scene into this render target at the same time. It is usually only + possible to render into a texture between the + IVideoDriver::beginScene() and endScene() method calls. If you need the + best performance use this method instead of setRenderTarget. + \param target Render target object. + \param clearFlag A combination of the E_CLEAR_BUFFER_FLAG bit-flags. + \param clearColor The clear color for the color buffer. + \param clearDepth The clear value for the depth buffer. + \param clearStencil The clear value for the stencil buffer. + \return True if successful and false if not. */ + virtual bool setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor = SColor(255,0,0,0), + f32 clearDepth = 1.f, u8 clearStencil = 0) = 0; + + //! Sets a new render target. + /** This will only work if the driver supports the + EVDF_RENDER_TO_TARGET feature, which can be queried with + queryFeature(). Usually, rendering to textures is done in this + way: + \code + // create render target + ITexture* target = driver->addRenderTargetTexture(core::dimension2d(128,128), "rtt1"); + + // ... + + driver->setRenderTarget(target); // set render target + // .. draw stuff here + driver->setRenderTarget(0); // set previous render target + \endcode + Please note that you cannot render 3D or 2D geometry with a + render target as texture on it when you are rendering the scene + into this render target at the same time. It is usually only + possible to render into a texture between the + IVideoDriver::beginScene() and endScene() method calls. + \param texture New render target. Must be a texture created with + IVideoDriver::addRenderTargetTexture(). If set to 0, it sets + the previous render target which was set before the last + setRenderTarget() call. + \param clearFlag A combination of the E_CLEAR_BUFFER_FLAG bit-flags. + \param clearColor The clear color for the color buffer. + \param clearDepth The clear value for the depth buffer. + \param clearStencil The clear value for the stencil buffer. + \return True if successful and false if not. */ + virtual bool setRenderTarget(ITexture* texture, u16 clearFlag=ECBF_COLOR|ECBF_DEPTH, SColor clearColor = SColor(255,0,0,0), + f32 clearDepth = 1.f, u8 clearStencil = 0) = 0; + + //! Sets a new render target. + //! Prefer to use the setRenderTarget function taking flags as parameter as this one can't clear the stencil buffer. + //! It's still offered for backward compatibility. + bool setRenderTarget(ITexture* texture, bool clearBackBuffer, bool clearZBuffer, SColor color = SColor(255,0,0,0)) + { + u16 flag = 0; + + if (clearBackBuffer) + flag |= ECBF_COLOR; + + if (clearZBuffer) + flag |= ECBF_DEPTH; + + return setRenderTarget(texture, flag, color); + } + + //! 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; + + //! Gets the area of the current viewport. + /** \return Rectangle of the current viewport. */ + virtual const core::rect& getViewPort() const =0; + + //! Draws a vertex primitive list + /** 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. Please note that currently not all primitives are available for + all drivers, and some might be emulated via triangle renders. + \param vertices Pointer to array of vertices. + \param vertexCount Amount of vertices in the array. + \param indexList Pointer to array of indices. These define the vertices used + for each primitive. Depending on the pType, indices are interpreted as single + objects (for point like primitives), pairs (for lines), triplets (for + triangles), or quads. + \param primCount Amount of Primitives + \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 16bit indices. */ + virtual void drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primCount, + E_VERTEX_TYPE vType=EVT_STANDARD, + scene::E_PRIMITIVE_TYPE pType=scene::EPT_TRIANGLES, + E_INDEX_TYPE iType=EIT_16BIT) =0; + + //! Draws a vertex primitive list in 2d + /** Compared to the general (3d) version of this method, this + one sets up a 2d render mode, and uses only x and y of vectors. + 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. Please note that currently not all + primitives are available for all drivers, and some might be + emulated via triangle renders. This function is not available + for the sw drivers. + \param vertices Pointer to array of vertices. + \param vertexCount Amount of vertices in the array. + \param indexList Pointer to array of indices. These define the + vertices used for each primitive. Depending on the pType, + indices are interpreted as single objects (for point like + primitives), pairs (for lines), triplets (for triangles), or + quads. + \param primCount Amount of Primitives + \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 16bit indices. */ + virtual void draw2DVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primCount, + 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 + 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. + \param vertices Pointer to array of vertices. + \param vertexCount Amount of vertices in the array. + \param indexList Pointer to array of indices. + \param triangleCount Amount of Triangles. Usually amount of indices / 3. */ + void drawIndexedTriangleList(const S3DVertex* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) + { + drawVertexPrimitiveList(vertices, vertexCount, indexList, triangleCount, EVT_STANDARD, scene::EPT_TRIANGLES, EIT_16BIT); + } + + //! Draws an indexed triangle 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. + \param vertices Pointer to array of vertices. + \param vertexCount Amount of vertices in the array. + \param indexList Pointer to array of indices. + \param triangleCount Amount of Triangles. Usually amount of indices / 3. */ + void drawIndexedTriangleList(const S3DVertex2TCoords* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) + { + drawVertexPrimitiveList(vertices, vertexCount, indexList, triangleCount, EVT_2TCOORDS, scene::EPT_TRIANGLES, EIT_16BIT); + } + + //! Draws an indexed triangle 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. + \param vertices Pointer to array of vertices. + \param vertexCount Amount of vertices in the array. + \param indexList Pointer to array of indices. + \param triangleCount Amount of Triangles. Usually amount of indices / 3. */ + void drawIndexedTriangleList(const S3DVertexTangents* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) + { + drawVertexPrimitiveList(vertices, vertexCount, indexList, triangleCount, EVT_TANGENTS, scene::EPT_TRIANGLES, EIT_16BIT); + } + + //! Draws an indexed triangle fan. + /** 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. + \param vertices Pointer to array of vertices. + \param vertexCount Amount of vertices in the array. + \param indexList Pointer to array of indices. + \param triangleCount Amount of Triangles. Usually amount of indices - 2. */ + void drawIndexedTriangleFan(const S3DVertex* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) + { + drawVertexPrimitiveList(vertices, vertexCount, indexList, triangleCount, EVT_STANDARD, scene::EPT_TRIANGLE_FAN, EIT_16BIT); + } + + //! Draws an indexed triangle fan. + /** 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. + \param vertices Pointer to array of vertices. + \param vertexCount Amount of vertices in the array. + \param indexList Pointer to array of indices. + \param triangleCount Amount of Triangles. Usually amount of indices - 2. */ + void drawIndexedTriangleFan(const S3DVertex2TCoords* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) + { + drawVertexPrimitiveList(vertices, vertexCount, indexList, triangleCount, EVT_2TCOORDS, scene::EPT_TRIANGLE_FAN, EIT_16BIT); + } + + //! Draws an indexed triangle fan. + /** 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. + \param vertices Pointer to array of vertices. + \param vertexCount Amount of vertices in the array. + \param indexList Pointer to array of indices. + \param triangleCount Amount of Triangles. Usually amount of indices - 2. */ + void drawIndexedTriangleFan(const S3DVertexTangents* vertices, + u32 vertexCount, const u16* indexList, u32 triangleCount) + { + drawVertexPrimitiveList(vertices, vertexCount, indexList, triangleCount, EVT_TANGENTS, scene::EPT_TRIANGLE_FAN, EIT_16BIT); + } + + //! Draws a 3d line. + /** For some implementations, this method simply calls + drawVertexPrimitiveList for some triangles. + Note that the line is drawn using the current transformation + matrix and material. So if you need to draw the 3D line + independently of the current transformation, use + \code + driver->setMaterial(someMaterial); + driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); + \endcode + for some properly set up material before drawing the line. + Some drivers support line thickness set in the material. + \param start Start of the 3d line. + \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; + + //! Draws a 3d triangle. + /** This method calls drawVertexPrimitiveList for some triangles. + This method works with all drivers because it simply calls + drawVertexPrimitiveList, but it is hence not very fast. + Note that the triangle is drawn using the current + transformation matrix and material. So if you need to draw it + independently of the current transformation, use + \code + driver->setMaterial(someMaterial); + driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); + \endcode + for some properly set up material before drawing the triangle. + \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; + + //! Draws a 3d axis aligned box. + /** This method simply calls draw3DLine for the edges of the + box. Note that the box is drawn using the current transformation + matrix and material. So if you need to draw it independently of + the current transformation, use + \code + driver->setMaterial(someMaterial); + driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); + \endcode + for some properly set up material before drawing the box. + \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; + + //! 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. + \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, bool useAlphaChannelOfTexture=false) =0; + + //! Draws a 2d image using a color + /** (if color is other than + Color(255,255,255,255)) and the alpha channel of the texture. + \param texture Texture to be drawn. + \param destPos Upper left 2d destination position where the + image will be drawn. + \param sourceRect Source rectangle in the image. + \param clipRect Pointer to rectangle on the screen where the + image is clipped to. + If this pointer is NULL the image is not clipped. + \param color Color with which the image is drawn. If the color + equals Color(255,255,255,255) it is ignored. Note that the + alpha component is used: If alpha is other than 255, the image + will be transparent. + \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; + + //! 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 + one line. All drawings are clipped against clipRect (if != 0). + The subtextures are defined by the array of sourceRects and are + chosen by the indices given. + \param texture Texture to be drawn. + \param pos Upper left 2d destination position where the image + will be drawn. + \param sourceRects Source rectangles of the image. + \param indices List of indices which choose the actual + rectangle used each time. + \param kerningWidth Offset to Position on X + \param clipRect Pointer to rectangle on the screen where the + image is clipped to. + If this pointer is 0 then the image is not clipped. + \param color Color with which the image is drawn. + Note that the alpha component is used. If alpha is other than + 255, the image will be transparent. + \param useAlphaChannelOfTexture: If true, the alpha channel of + the texture is used to draw the image. */ + virtual void draw2DImageBatch(const video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, + s32 kerningWidth=0, + 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. + /** All drawings are clipped against clipRect (if != 0). + The subtextures are defined by the array of sourceRects and are + positioned using the array of positions. + \param texture Texture to be drawn. + \param positions Array of upper left 2d destinations where the + images will be drawn. + \param sourceRects Source rectangles of the image. + \param clipRect Pointer to rectangle on the screen where the + images are clipped to. + If this pointer is 0 then the image is not clipped. + \param color Color with which the image is drawn. + Note that the alpha component is used. If alpha is other than + 255, the image will be transparent. + \param useAlphaChannelOfTexture: If true, the alpha channel of + the texture is used to draw the image. */ + virtual void draw2DImageBatch(const video::ITexture* texture, + const core::array >& positions, + const core::array >& sourceRects, + const core::rect* clipRect=0, + SColor color=SColor(255,255,255,255), + 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. + \param texture The texture to draw from + \param destRect The rectangle to draw into + \param sourceRect The rectangle denoting a part of the texture + \param clipRect Clips the destination rectangle (may be 0) + \param colors Array of 4 colors denoting the color values of + the corners of the destRect + \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; + + //! Draws a 2d rectangle. + /** \param color Color of the rectangle to draw. The alpha + component will not be ignored and 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(SColor color, const core::rect& pos, + const core::rect* clip =0) =0; + + //! 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. + \param colorRightUp Color of the upper right corner to draw. + The alpha component will not be ignored and specifies how + transparent the rectangle will be. + \param colorLeftDown Color of the lower left corner to draw. + The alpha component will not be ignored and specifies how + transparent the rectangle will be. + \param colorRightDown Color of the lower right corner to draw. + The alpha component will not be ignored and 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(const core::rect& pos, + SColor colorLeftUp, SColor colorRightUp, + SColor colorLeftDown, SColor colorRightDown, + 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. + /** In theory both start and end will be included in coloring. + BUG: Currently hardware drivers (d3d/opengl) ignore the last pixel + (they use the so called "diamond exit rule" for drawing lines). + \param start Screen coordinates of the start of the line + in pixels. + \param end Screen coordinates of the start of the line in + pixels. + \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; + + //! Draws a pixel. + /** \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 polygon. + /** This method can be used to draw circles, but also + triangles, tetragons, pentagons, hexagons, heptagons, octagons, + enneagons, decagons, hendecagons, dodecagon, triskaidecagons, + etc. I think you'll got it now. And all this by simply + specifying the vertex count. Welcome to the wonders of + geometry. + \param center Position of center of circle (pixels). + \param radius Radius of circle in pixels. + \param color Color of the circle. + \param vertexCount Amount of vertices of the polygon. Specify 2 + to draw a line, 3 to draw a triangle, 4 for tetragons and a lot + (>10) for nearly a circle. */ + virtual void draw2DPolygon(core::position2d center, + f32 radius, + video::SColor color=SColor(100,255,255,255), + s32 vertexCount=10) =0; + + //! Draws a shadow volume into the stencil buffer. + /** To draw a stencil shadow, do this: First, draw all geometry. + Then use this method, to draw the shadow volume. Then, use + IVideoDriver::drawStencilShadow() to visualize the shadow. + Please note that the code for the opengl version of the method + is based on free code sent in by Philipp Dortmann, lots of + thanks go to him! + \param triangles Array of 3d vectors, specifying the shadow + volume. + \param zfail If set to true, zfail method is used, otherwise + zpass. + \param debugDataVisible The debug data that is enabled for this + shadow node + */ + virtual void drawStencilShadowVolume(const core::array& triangles, bool zfail=true, u32 debugDataVisible=0) =0; + + //! 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. + Please note that the code for the opengl version of the method + is based on free code sent in by Philipp Dortmann, lots of + thanks go to him! + \param clearStencilBuffer Set this to false, if you want to + draw every shadow with the same color, and only want to call + drawStencilShadow() once after all shadow volumes have been + drawn. Set this to true, if you want to paint every shadow with + its own color. + \param leftUpEdge Color of the shadow in the upper left corner + of screen. + \param rightUpEdge Color of the shadow in the upper right + corner of screen. + \param leftDownEdge Color of the shadow in the lower left + corner of screen. + \param rightDownEdge Color of the shadow in the lower right + corner of screen. */ + virtual void drawStencilShadow(bool clearStencilBuffer=false, + 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; + + //! Draws a mesh buffer + /** \param mb Buffer to draw */ + virtual void drawMeshBuffer(const scene::IMeshBuffer* mb) =0; + + //! Draws normals of a mesh buffer + /** \param mb Buffer to draw the normals of + \param length length scale factor of the normals + \param color Color the normals are rendered with + */ + virtual void drawMeshBufferNormals(const scene::IMeshBuffer* mb, f32 length=10.f, SColor color=0xffffffff) =0; + + //! Sets the fog mode. + /** These are global values attached to each 3d object rendered, + which has the fog flag enabled in its material. + \param color Color of the fog + \param fogType Type of fog used + \param start Only used in linear fog mode (linearFog=true). + Specifies where fog starts. + \param end Only used in linear fog mode (linearFog=true). + Specifies where fog ends. + \param density Only used in exponential fog mode + (linearFog=false). Must be a value between 0 and 1. + \param pixelFog Set this to false for vertex fog, and true if + you want per-pixel fog. + \param rangeFog Set this to true to enable range-based vertex + fog. The distance from the viewer is used to compute the fog, + not the z-coordinate. This is better, but slower. This might not + be available with all drivers and fog settings. */ + virtual void setFog(SColor color=SColor(0,255,255,255), + E_FOG_TYPE fogType=EFT_FOG_LINEAR, + f32 start=50.0f, f32 end=100.0f, f32 density=0.01f, + bool pixelFog=false, bool rangeFog=false) =0; + + //! Gets the fog mode. + virtual void getFog(SColor& color, E_FOG_TYPE& fogType, + f32& start, f32& end, f32& density, + bool& pixelFog, bool& rangeFog) = 0; + + //! Get the current color format of the color buffer + /** \return Color format of the color buffer. */ + 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; + + //! 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; + + //! Returns current frames per second value. + /** This value is updated approximately every 1.5 seconds and + is only intended to provide a rough guide to the average frame + 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; + + //! 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; + + //! Deletes all dynamic lights which were previously added with addDynamicLight(). + virtual void deleteAllDynamicLights() =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; + + //! Returns amount of dynamic lights currently set + /** \return Amount of dynamic lights currently set */ + 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; + + //! 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; + + //! Adds an external image loader to the engine. + /** This is useful if the Irrlicht Engine should be able to load + textures of currently unsupported file formats (e.g. gif). The + IImageLoader only needs to be implemented for loading this file + 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; + + //! Adds an external image writer to the engine. + /** This is useful if the Irrlicht Engine should be able to + write textures of currently unsupported file formats (e.g + .gif). The IImageWriter only needs to be implemented for + 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; + + //! Returns the maximum amount of primitives + /** (mostly vertices) which the device is able to render with + one drawVertexPrimitiveList call. + \return Maximum amount of primitives. */ + virtual u32 getMaximalPrimitiveCount() const =0; + + //! Enables or disables a texture creation flag. + /** These flags define how textures should be created. By + changing this value, you can influence for example the speed of + rendering a lot. But please note that the video drivers take + this value only as recommendation. It could happen that you + enable the ETCF_ALWAYS_16_BIT mode, but the driver still creates + 32 bit textures. + \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=true) =0; + + //! Returns if a texture creation flag is enabled or disabled. + /** You can change this value using setTextureCreationFlag(). + \param flag Texture creation flag. + \return The current texture creation flag enabled mode. */ + virtual bool getTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag) const =0; + + //! Creates a software images from a file. + /** No hardware texture will be created for those images. This + method is useful for example if you want to read a heightmap + for a terrain renderer. + \param filename Name of the file from which the images are created. + \param type Pointer to E_TEXTURE_TYPE where a recommended type of the texture will be stored. + \return The array of created images. + If you no longer need those images, you should call IImage::drop() on each of them. + See IReferenceCounted::drop() for more information. */ + virtual core::array createImagesFromFile(const io::path& filename, E_TEXTURE_TYPE* type = 0) = 0; + + //! Creates a software images from a file. + /** No hardware texture will be created for those images. This + method is useful for example if you want to read a heightmap + for a terrain renderer. + \param file File from which the image is created. + \param type Pointer to E_TEXTURE_TYPE where a recommended type of the texture will be stored. + \return The array of created images. + If you no longer need those images, you should call IImage::drop() on each of them. + See IReferenceCounted::drop() for more information. */ + virtual core::array createImagesFromFile(io::IReadFile* file, E_TEXTURE_TYPE* type = 0) = 0; + + //! Creates a software image from a file. + /** No hardware texture will be created for this image. This + method is useful for example if you want to read a heightmap + for a terrain renderer. + \param filename Name of the file from which the image is + created. + \return The created image. + If you no longer need the image, you should call IImage::drop(). + See IReferenceCounted::drop() for more information. */ + IImage* createImageFromFile(const io::path& filename) + { + core::array imageArray = createImagesFromFile(filename); + + for (u32 i = 1; i < imageArray.size(); ++i) + imageArray[i]->drop(); + + return (imageArray.size() > 0) ? imageArray[0] : 0; + } + + //! Creates a software image from a file. + /** No hardware texture will be created for this image. This + method is useful for example if you want to read a heightmap + for a terrain renderer. + \param file File from which the image is created. + \return The created image. + If you no longer need the image, you should call IImage::drop(). + See IReferenceCounted::drop() for more information. */ + IImage* createImageFromFile(io::IReadFile* file) + { + core::array imageArray = createImagesFromFile(file); + + for (u32 i = 1; i < imageArray.size(); ++i) + imageArray[i]->drop(); + + return (imageArray.size() > 0) ? imageArray[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 filename Name of the file to write. + \param param Control parameter for the backend (e.g. compression + level). + \return True on successful write. */ + virtual bool writeImageToFile(IImage* image, const io::path& 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 + method is useful for example if you want to read a heightmap + for a terrain renderer. + \param format Desired color format of the texture + \param size Desired size of the image + \param data A byte array with pixel color information + \param ownForeignMemory If true, the image will use the data + pointer directly and own it afterward. If false, the memory + will by copied internally. + WARNING: Setting this to 'true' will not work across dll boundaries. + So unless you link Irrlicht statically you should keep this to 'false'. + The parameter is mainly for internal usage. + \param deleteMemory Whether the memory is deallocated upon + destruction. + \return The created image. + 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, bool ownForeignMemory = false, + bool deleteMemory = true) = 0; + + //! Creates an empty software image. + /** + \param format Desired color format of the image. + \param size Size of the image to create. + \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; + + //! Creates a software image by converting it to given format from another image. + /** \deprecated Create an empty image and use copyTo(). This method may be removed by Irrlicht 1.9. + \param format Desired color format of the image. + \param imageToCopy Image to copy to the new image. + \return The created image. + If you no longer need the image, you should call IImage::drop(). + See IReferenceCounted::drop() for more information. */ + _IRR_DEPRECATED_ virtual IImage* createImage(ECOLOR_FORMAT format, IImage *imageToCopy) =0; + + //! Creates a software image from a part of another image. + /** \deprecated Create an empty image and use copyTo(). This method may be removed by Irrlicht 1.9. + \param imageToCopy Image to copy to the new image in part. + \param pos Position of rectangle to copy. + \param size Extents of rectangle to copy. + \return The created image. + If you no longer need the image, you should call IImage::drop(). + See IReferenceCounted::drop() for more information. */ + _IRR_DEPRECATED_ virtual IImage* createImage(IImage* imageToCopy, + const core::position2d& pos, + const core::dimension2d& size) =0; + + //! Creates a software image from a part of a texture. + /** + \param texture Texture to copy to the new image in part. + \param pos Position of rectangle to copy. + \param size Extents of rectangle to copy. + \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(ITexture* texture, + const core::position2d& pos, + 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; + + //! Adds a new material renderer to the video device. + /** Use this method to extend the VideoDriver with new material + types. To extend the engine using this method do the following: + Derive a class from IMaterialRenderer and override the methods + you need. For setting the right renderstates, you can try to + get a pointer to the real rendering device using + IVideoDriver::getExposedVideoData(). Add your class with + IVideoDriver::addMaterialRenderer(). To use an object being + displayed with your new material, set the MaterialType member of + the SMaterial struct to the value returned by this method. + If you simply want to create a new material using vertex and/or + pixel shaders it would be easier to use the + video::IGPUProgrammingServices interface which you can get + using the getGPUProgrammingServices() method. + \param renderer A pointer to the new renderer. + \param name Optional name for the material renderer entry. + \return The number of the material type which can be set in + SMaterial::MaterialType to use the renderer. -1 is returned if + an error occurred. 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; + + //! 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) const = 0; + + //! Get amount of currently available material renderers. + /** \return Amount of currently available material renderers. */ + virtual u32 getMaterialRendererCount() const =0; + + //! Get name of a material renderer + /** This string can, e.g., be used to test if a specific + renderer already has been registered/created, or use this + string to store data about materials: This returned name will + be also used when serializing materials. + \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 String with the name of the renderer, or 0 if not + exisiting */ + virtual const c8* getMaterialRendererName(u32 idx) const =0; + + //! Sets the name of a material renderer. + /** Will have no effect on built-in material renderers. + \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(). + \param name: New name of the material renderer. */ + virtual void setMaterialRendererName(s32 idx, const c8* name) =0; + + //! Swap the material renderers used for certain id's + /** Swap the IMaterialRenderers responsible for rendering specific + material-id's. This means every SMaterial using a MaterialType + with one of the indices involved here will now render differently. + \param idx1 First material index to swap. It must already exist or nothing happens. + \param idx2 Second material index to swap. It must already exist or nothing happens. + \param swapNames When true the renderer names also swap + When false the names will stay at the original index */ + virtual void swapMaterialRenderers(u32 idx1, u32 idx2, bool swapNames=true) = 0; + + //! Creates material attributes list from a material + /** This method is useful for serialization and more. + Please note that the video driver will use the material + renderer names from getMaterialRendererName() to write out the + material type name, so they should be set before. + \param material The material to serialize. + \param options Additional options which might influence the + serialization. + \return The io::IAttributes container holding the material + properties. */ + virtual io::IAttributes* createAttributesFromMaterial(const video::SMaterial& material, + io::SAttributeReadWriteOptions* options=0) =0; + + //! Fills an SMaterial structure from attributes. + /** Please note that for setting material types of the + material, the video driver will need to query the material + renderers for their names, so all non built-in materials must + 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; + + //! 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; + + //! Get type of video driver + /** \return Type of driver. */ + 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; + + //! Returns a pointer to the mesh manipulator. + virtual scene::IMeshManipulator* getMeshManipulator() =0; + + //! Clear the color, depth and/or stencil buffers. + virtual void clearBuffers(u16 flag, SColor color = SColor(255,0,0,0), f32 depth = 1.f, u8 stencil = 0) = 0; + + //! Clear the color, depth and/or stencil buffers. + _IRR_DEPRECATED_ void clearBuffers(bool backBuffer, bool depthBuffer, bool stencilBuffer, SColor color) + { + u16 flag = 0; + + if (backBuffer) + flag |= ECBF_COLOR; + + if (depthBuffer) + flag |= ECBF_DEPTH; + + if (stencilBuffer) + flag |= ECBF_STENCIL; + + clearBuffers(flag, color); + } + + //! Clears the ZBuffer. + /** Note that you usually need not to call this method, as it + is automatically done in IVideoDriver::beginScene() or + IVideoDriver::setRenderTarget() if you enable zBuffer. But if + you have to render some special things, you can clear the + zbuffer during the rendering process with this method any time. + */ + _IRR_DEPRECATED_ void clearZBuffer() + { + clearBuffers(ECBF_DEPTH, SColor(255,0,0,0), 1.f, 0); + } + + //! Make a screenshot of the last rendered frame. + /** \return An image created from the last rendered frame. */ + virtual IImage* createScreenShot(video::ECOLOR_FORMAT format=video::ECF_UNKNOWN, video::E_RENDER_TARGET target=video::ERT_FRAME_BUFFER) =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 io::path& filename) = 0; + + //! Set or unset 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 plane The plane itself. + \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; + + //! Enable or 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. */ + 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; + + //! Get the global Material, which might override local materials. + /** Depending on the enable flags, values from this Material + are used to override those of local materials of some + meshbuffer being rendered. + \return Reference to the Override Material. */ + virtual SOverrideMaterial& getOverrideMaterial() =0; + + //! Get the 2d override material for altering its values + /** The 2d override material allows to alter certain render + states of the 2d methods. Not all members of SMaterial are + honored, especially not MaterialType and Textures. Moreover, + the zbuffer is always ignored, and lighting is always off. All + other flags can be changed, though some might have to effect + in most cases. + Please note that you have to enable/disable this effect with + enableInitMaterial2D(). This effect is costly, as it increases + the number of state changes considerably. Always reset the + values when done. + \return Material reference which should be altered to reflect + the new settings. + */ + virtual SMaterial& getMaterial2D() =0; + + //! Enable the 2d override material + /** \param enable Flag which tells whether the material shall be + enabled or disabled. */ + virtual void enableMaterial2D(bool enable=true) =0; + + //! Get the graphics card vendor name. + 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; + + //! Get the global ambient light currently used by the driver + virtual const SColorf& getAmbientLight() const = 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; + + //! Get the maximum texture size supported. + virtual core::dimension2du getMaxTextureSize() const =0; + + //! Color conversion convenience function + /** Convert an image (as array of pixels) from source to destination + array, thereby converting the color format. The pixel size is + determined by the color formats. + \param sP Pointer to source + \param sF Color format of source + \param sN Number of pixels to convert, both array must be large enough + \param dP Pointer to destination + \param dF Color format of destination + */ + virtual void convertColor(const void* sP, ECOLOR_FORMAT sF, s32 sN, + void* dP, ECOLOR_FORMAT dF) const =0; + + //! Check if the driver supports creating textures with the given color format + /** \return True if the format is available, false if not. */ + virtual bool queryTextureFormat(ECOLOR_FORMAT format) const = 0; + + //! Used by some SceneNodes to check if a material should be rendered in the transparent render pass + virtual bool needsTransparentRenderPass(const irr::video::SMaterial& material) const = 0; + }; + +} // end namespace video +} // end namespace irr + + +#endif diff --git a/include/IVideoModeList.h b/include/IVideoModeList.h new file mode 100644 index 00000000..cc87b2e2 --- /dev/null +++ b/include/IVideoModeList.h @@ -0,0 +1,58 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_I_VIDEO_MODE_LIST_H_INCLUDED__ +#define __IRR_I_VIDEO_MODE_LIST_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "dimension2d.h" + +namespace irr +{ +namespace video +{ + + //! A list of all available video modes. + /** You can get a list via IrrlichtDevice::getVideoModeList(). + You only need the null device (EDT_NULL) to get the video-modes. */ + class IVideoModeList : public virtual IReferenceCounted + { + public: + + //! Gets amount of video modes in the list. + /** \return Returns amount of video modes. */ + virtual s32 getVideoModeCount() const = 0; + + //! 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; + + //! 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; + + //! Get the pixel depth of a video mode in bits. + /** \param modeNumber: zero based index of the video mode. + \return Size of each pixel of the specified video mode in bits. */ + virtual s32 getVideoModeDepth(s32 modeNumber) const = 0; + + //! Get current desktop screen resolution. + /** \return Size of screen in pixels of the current desktop video mode. */ + 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. */ + virtual s32 getDesktopDepth() const = 0; + }; + +} // end namespace video +} // end namespace irr + + +#endif + diff --git a/include/IVolumeLightSceneNode.h b/include/IVolumeLightSceneNode.h new file mode 100644 index 00000000..d67dff58 --- /dev/null +++ b/include/IVolumeLightSceneNode.h @@ -0,0 +1,60 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +// +// created by Dean Wadsworth aka Varmint Dec 31 2007 + +#ifndef __I_VOLUME_LIGHT_SCENE_NODE_H_INCLUDED__ +#define __I_VOLUME_LIGHT_SCENE_NODE_H_INCLUDED__ + +#include "ISceneNode.h" + +namespace irr +{ +namespace scene +{ + class IMeshBuffer; + + class IVolumeLightSceneNode : public ISceneNode + { + public: + + //! constructor + IVolumeLightSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position, + const core::vector3df& rotation, + const core::vector3df& scale) + : ISceneNode(parent, mgr, id, position, rotation, scale) {}; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_VOLUME_LIGHT; } + + //! Sets the number of segments across the U axis + virtual void setSubDivideU(const u32 inU) =0; + + //! Sets the number of segments across the V axis + virtual void setSubDivideV(const u32 inV) =0; + + //! Returns the number of segments across the U axis + virtual u32 getSubDivideU() const =0; + + //! Returns the number of segments across the V axis + virtual u32 getSubDivideV() const =0; + + //! Sets the color of the base of the light + virtual void setFootColor(const video::SColor inColor) =0; + + //! Sets the color of the tip of the light + virtual void setTailColor(const video::SColor inColor) =0; + + //! Returns the color of the base of the light + virtual video::SColor getFootColor() const =0; + + //! Returns the color of the tip of the light + virtual video::SColor getTailColor() const =0; + }; + +} // end namespace scene +} // end namespace irr + +#endif diff --git a/include/IWriteFile.h b/include/IWriteFile.h new file mode 100644 index 00000000..5cc48352 --- /dev/null +++ b/include/IWriteFile.h @@ -0,0 +1,51 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_WRITE_FILE_H_INCLUDED__ +#define __I_WRITE_FILE_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "path.h" + +namespace irr +{ +namespace io +{ + + //! Interface providing write access to a file. + class IWriteFile : public virtual IReferenceCounted + { + public: + //! Writes an amount of bytes to the file. + /** \param buffer Pointer to buffer of bytes to write. + \param sizeToWrite Amount of bytes to write to the file. + \return How much bytes were written. */ + virtual size_t write(const void* buffer, size_t sizeToWrite) = 0; + + //! Changes position in file + /** \param finalPos Destination position in the file. + \param relativeMovement If set to true, the position in the file is + changed relative to current position. Otherwise the position is changed + from begin of file. + \return True if successful, otherwise false. */ + virtual bool seek(long finalPos, bool relativeMovement = false) = 0; + + //! Get the current position in the file. + /** \return Current position in the file in bytes on success or -1L on failure */ + virtual long getPos() const = 0; + + //! Get name of file. + /** \return File name as zero terminated character string. */ + virtual const path& getFileName() const = 0; + + //! Flush the content of the buffer in the file + /** \return True if successful, otherwise false. */ + virtual bool flush() = 0; + }; + +} // end namespace io +} // end namespace irr + +#endif + diff --git a/include/IXMLReader.h b/include/IXMLReader.h new file mode 100644 index 00000000..7babb454 --- /dev/null +++ b/include/IXMLReader.h @@ -0,0 +1,31 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_XML_READER_H_INCLUDED__ +#define __I_XML_READER_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "irrXML.h" + +namespace irr +{ +namespace io +{ + //! An xml reader for wide characters, derived from IReferenceCounted. + /** This XML Parser can read any type of text files from any source + Irrlicht can read. Just call IFileSystem::createXMLReader(). For more + information on how to use the parser, see IIrrXMLReader */ + typedef IIrrXMLReader IXMLReader; + + //! An xml reader for ASCII or UTF-8 characters, derived from IReferenceCounted. + /** This XML Parser can read any type of text files from any source + Irrlicht can read. Just call IFileSystem::createXMLReaderUTF8(). For + more information on how to use the parser, see IIrrXMLReader */ + typedef IIrrXMLReader IXMLReaderUTF8; + +} // end namespace io +} // end namespace irr + +#endif + diff --git a/include/IXMLWriter.h b/include/IXMLWriter.h new file mode 100644 index 00000000..18c40e28 --- /dev/null +++ b/include/IXMLWriter.h @@ -0,0 +1,26 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_XML_WRITER_H_INCLUDED__ +#define __I_XML_WRITER_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "irrXML.h" + +namespace irr +{ +namespace io +{ + //! An xml writer for wide characters, derived from IReferenceCounted. + /** Call IFileSystem::createXMLReader(). to create an IXMLWriter */ + typedef IIrrXMLWriter IXMLWriter; + + //! An xml writer for ASCII or UTF-8 characters, derived from IReferenceCounted. + /** Call IFileSystem::createXMLReaderUtf8(). to create an IXMLWriter */ + typedef IIrrXMLWriter IXMLWriterUTF8; + +} // end namespace io +} // end namespace irr + +#endif diff --git a/include/IrrCompileConfig.h b/include/IrrCompileConfig.h new file mode 100644 index 00000000..e27156d2 --- /dev/null +++ b/include/IrrCompileConfig.h @@ -0,0 +1,961 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_COMPILE_CONFIG_H_INCLUDED__ +#define __IRR_COMPILE_CONFIG_H_INCLUDED__ + +//! Irrlicht SDK Version +#define IRRLICHT_VERSION_MAJOR 1 +#define IRRLICHT_VERSION_MINOR 9 +#define IRRLICHT_VERSION_REVISION 0 +// This flag will be defined only in SVN, the official release code will have +// it undefined +#define IRRLICHT_VERSION_SVN alpha +#define IRRLICHT_SDK_VERSION "1.9.0" + +#include // TODO: Although included elsewhere this is required at least for mingw + +//! The defines for different operating system are: +//! _IRR_WINDOWS_ for all irrlicht supported Windows versions +//! _IRR_WINDOWS_API_ for Windows or XBox +//! _IRR_LINUX_PLATFORM_ for Linux (it is defined here if no other os is defined) +//! _IRR_SOLARIS_PLATFORM_ for Solaris +//! _IRR_OSX_PLATFORM_ for Apple systems running OSX +//! _IRR_IOS_PLATFORM_ for Apple devices running iOS +//! _IRR_ANDROID_PLATFORM_ for devices running Android +//! _IRR_POSIX_API_ for Posix compatible systems +//! Note: PLATFORM defines the OS specific layer, API can group several platforms + +//! DEVICE is the windowing system used, several PLATFORMs support more than one DEVICE +//! Irrlicht can be compiled with more than one device +//! _IRR_COMPILE_WITH_WINDOWS_DEVICE_ for Windows API based device +//! _IRR_COMPILE_WITH_OSX_DEVICE_ for Cocoa native windowing on OSX +//! _IRR_COMPILE_WITH_X11_DEVICE_ for Linux X11 based device +//! _IRR_COMPILE_WITH_SDL_DEVICE_ for platform independent SDL framework +//! _IRR_COMPILE_WITH_CONSOLE_DEVICE_ for no windowing system, used as a fallback +//! _IRR_COMPILE_WITH_FB_DEVICE_ for framebuffer systems + +//! Passing defines to the compiler which have NO in front of the _IRR definename is an alternative +//! way which can be used to disable defines (instead of outcommenting them in this header). +//! So defines can be controlled from Makefiles or Projectfiles which allows building +//! different library versions without having to change the sources. +//! Example: NO_IRR_COMPILE_WITH_X11_ would disable X11 + +//! Uncomment this line to compile with the SDL device +//#define _IRR_COMPILE_WITH_SDL_DEVICE_ +#ifdef NO_IRR_COMPILE_WITH_SDL_DEVICE_ +#undef _IRR_COMPILE_WITH_SDL_DEVICE_ +#endif + +//! Comment this line to compile without the fallback console device. +#define _IRR_COMPILE_WITH_CONSOLE_DEVICE_ +#ifdef NO_IRR_COMPILE_WITH_CONSOLE_DEVICE_ +#undef _IRR_COMPILE_WITH_CONSOLE_DEVICE_ +#endif + +//! WIN32 for Windows32 +//! WIN64 for Windows64 +// The windows platform and API support SDL and WINDOW device +#if defined(_WIN32) || defined(_WIN64) || defined(WIN32) || defined(WIN64) +#define _IRR_WINDOWS_ +#define _IRR_WINDOWS_API_ +#define _IRR_COMPILE_WITH_WINDOWS_DEVICE_ +#endif + +#if defined(_MSC_VER) && (_MSC_VER < 1500) +# error "Only Microsoft Visual Studio 9.0 and later are supported." +#endif + +// XBox is deprecated (as DX8 is removed). Use Irrlicht 1.8 if you still want to work on this. +#if defined(_XBOX) + #undef _IRR_WINDOWS_ + #define _IRR_XBOX_PLATFORM_ // deprecated + #define _IRR_WINDOWS_API_ + //#define _IRR_COMPILE_WITH_WINDOWS_DEVICE_ + #undef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ + //#define _IRR_COMPILE_WITH_SDL_DEVICE_ + + #include +#endif + +#if defined(__APPLE__) || defined(MACOSX) +#if !defined(MACOSX) +#define MACOSX // legacy support +#endif +#if defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) || defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define _IRR_IOS_PLATFORM_ +#define _IRR_COMPILE_WITH_IOS_DEVICE_ +#define NO_IRR_COMPILE_WITH_OPENGL_ +// The application state events and following methods: IrrlichtDevice::isWindowActive, IrrlichtDevice::isWindowFocused, +// IrrlichtDevice::isWindowMinimized works out of box only if you'll use built-in CIrrDelegateiOS, +// so _IRR_COMPILE_WITH_IOS_BUILTIN_MAIN_ must be enabled in this case. If you need a custom UIApplicationDelegate +// you must disable _IRR_COMPILE_WITH_IOS_BUILTIN_MAIN_ definition and handle all application events yourself. +#define _IRR_COMPILE_WITH_IOS_BUILTIN_MAIN_ +#else +#define _IRR_OSX_PLATFORM_ +#define _IRR_COMPILE_WITH_OSX_DEVICE_ +#define NO_IRR_COMPILE_WITH_OGLES1_ +#define NO_IRR_COMPILE_WITH_OGLES2_ +#define NO_IRR_COMPILE_WITH_WEBGL1_ +#endif +#endif + +#if defined(__EMSCRIPTEN__) +#define _IRR_EMSCRIPTEN_PLATFORM_ +#define NO_IRR_COMPILE_WITH_JOYSTICK_EVENTS_ +#define NO_IRR_COMPILE_WITH_OPENGL_ +#define NO_IRR_COMPILE_WITH_OGLES1_ +#define _IRR_COMPILE_WITH_OGLES2_ +#define _IRR_COMPILE_WITH_WEBGL1_ +#define _IRR_COMPILE_WITH_EGL_MANAGER_ +#define _IRR_COMPILE_WITH_SDL_DEVICE_ +#define NO_IRR_COMPILE_WITH_X11_DEVICE_ +#define _IRR_LINUX_PLATFORM_ // emscripten basically working like a unix +#define NO_IRR_COMPILE_WITH_SOFTWARE_ +#define NO_IRR_COMPILE_WITH_BURNINGSVIDEO_ +#endif // __EMSCRIPTEN__ + +#if defined(__ANDROID__) +#define _IRR_ANDROID_PLATFORM_ +#define _IRR_COMPILE_WITH_ANDROID_DEVICE_ +#define _IRR_COMPILE_ANDROID_ASSET_READER_ +#define NO_IRR_COMPILE_WITH_OPENGL_ +#endif + +#if defined(__SVR4) && defined(__sun) +#define _IRR_SOLARIS_PLATFORM_ +#if defined(__sparc) + #define __BIG_ENDIAN__ +#endif +#endif + +#if !defined(_IRR_WINDOWS_API_) && !defined(_IRR_OSX_PLATFORM_) && !defined(_IRR_IOS_PLATFORM_) && !defined(_IRR_ANDROID_PLATFORM_) && !defined(_IRR_EMSCRIPTEN_PLATFORM_) +#ifndef _IRR_SOLARIS_PLATFORM_ +#define _IRR_LINUX_PLATFORM_ +#endif +#define _IRR_POSIX_API_ +#define _IRR_COMPILE_WITH_X11_DEVICE_ +#endif + + +//! Define _IRR_COMPILE_WITH_JOYSTICK_SUPPORT_ if you want joystick events. +#define _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ +#ifdef NO_IRR_COMPILE_WITH_JOYSTICK_EVENTS_ +#undef _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ +#endif + + +//! Maximum number of texture an SMaterial can have, up to 8 are supported by Irrlicht. +#define _IRR_MATERIAL_MAX_TEXTURES_ 8 + +//! Whether to support XML and XML-based formats (irrmesh, collada...) +#define _IRR_COMPILE_WITH_XML_ +#ifdef NO_IRR_COMPILE_WITH_XML_ +#undef _IRR_COMPILE_WITH_XML_ +#endif + +//! Add a leak-hunter to Irrlicht which helps finding unreleased reference counted objects. +//! NOTE: This is slow and should only be used for debugging +//#define _IRR_COMPILE_WITH_LEAK_HUNTER_ +#ifdef NO_IRR_COMPILE_WITH_LEAK_HUNTER_ +#undef _IRR_COMPILE_WITH_LEAK_HUNTER_ +#endif + +//! Enable profiling information in the engine +/** NOTE: The profiler itself always exists and can be used by applications. +This define is about the engine creating profile data +while it runs and enabling it will slow down the engine. */ +//#define _IRR_COMPILE_WITH_PROFILING_ +#ifdef NO_IRR_COMPILE_WITH_PROFILING_ +#undef _IRR_COMPILE_WITH_PROFILING_ +#endif + +//! Define _IRR_COMPILE_WITH_DIRECT3D_9_ to compile the Irrlicht engine with DIRECT3D9. +/** If you only want to use the software device or opengl you can disable those defines. +This switch is mostly disabled because people do not get the g++ compiler compile +directX header files, and directX is only available on Windows platforms. If you +are using Dev-Cpp, and want to compile this using a DX dev pack, you can define +_IRR_COMPILE_WITH_DX9_DEV_PACK_. So you simply need to add something like this +to the compiler settings: -DIRR_COMPILE_WITH_DX9_DEV_PACK +and this to the linker settings: -ld3dx9 +*/ +#if defined(_IRR_WINDOWS_API_) && (!defined(__GNUC__) || defined(IRR_COMPILE_WITH_DX9_DEV_PACK)) + +//! Define _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ if you want to use DirectInput for joystick handling. +/** This only applies to Windows devices, currently only supported under Win32 device. +If not defined, Windows Multimedia library is used, which offers also broad support for joystick devices. */ +#define _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ +#ifdef NO_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ +#undef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ +#endif +// can't get this to compile currently under borland, can be removed if someone has a better solution +#if defined(__BORLANDC__) +#undef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ +#endif + +//! enabled Direct3D 9 +#define _IRR_COMPILE_WITH_DIRECT3D_9_ +#ifdef NO_IRR_COMPILE_WITH_DIRECT3D_9_ +#undef _IRR_COMPILE_WITH_DIRECT3D_9_ +#endif + +#endif + +//! Define _IRR_COMPILE_WITH_OPENGL_ to compile the Irrlicht engine with OpenGL. +/** If you do not wish the engine to be compiled with OpenGL, comment this +define out. */ +#define _IRR_COMPILE_WITH_OPENGL_ +#ifdef NO_IRR_COMPILE_WITH_OPENGL_ +#undef _IRR_COMPILE_WITH_OPENGL_ +#endif + +//! Define required options for OpenGL drivers. +#if defined(_IRR_COMPILE_WITH_OPENGL_) + #if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) + #define _IRR_OPENGL_USE_EXTPOINTER_ + #define _IRR_COMPILE_WITH_WGL_MANAGER_ + #elif defined(_IRR_COMPILE_WITH_X11_DEVICE_) + #define _IRR_OPENGL_USE_EXTPOINTER_ + #define _IRR_COMPILE_WITH_GLX_MANAGER_ + #elif defined(_IRR_COMPILE_WITH_OSX_DEVICE_) + #define _IRR_COMPILE_WITH_NSOGL_MANAGER_ + #elif defined(_IRR_SOLARIS_PLATFORM_) + #define _IRR_COMPILE_WITH_GLX_MANAGER_ + #elif defined(_IRR_COMPILE_WITH_SDL_DEVICE_) + #define _IRR_OPENGL_USE_EXTPOINTER_ + #endif +#endif + + +// Debian 10 removed support for GLES1 in mesa. +// Can't tell about other Linux platforms or a way to test if it's still available, +// so removing OGLES1 support on Linux now to allow compiling to work by default. +#if defined(_IRR_LINUX_PLATFORM_) && !defined(_IRR_ANDROID_PLATFORM_) +#define NO_IRR_COMPILE_WITH_OGLES1_ +#endif + +//! Define _IRR_COMPILE_WITH_OGLES1_ to compile the Irrlicht engine with OpenGL ES 1.1. +/** If you do not wish the engine to be compiled with OpenGL ES 1.1, comment this +define out. */ +#define _IRR_COMPILE_WITH_OGLES1_ +#ifdef NO_IRR_COMPILE_WITH_OGLES1_ +#undef _IRR_COMPILE_WITH_OGLES1_ +#endif + +//! Define required options for OpenGL ES 1.1 drivers. +#if defined(_IRR_COMPILE_WITH_OGLES1_) +#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) || defined(_IRR_COMPILE_WITH_X11_DEVICE_) || defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_) +#define _IRR_OGLES1_USE_EXTPOINTER_ +#ifndef _IRR_COMPILE_WITH_EGL_MANAGER_ +#define _IRR_COMPILE_WITH_EGL_MANAGER_ +#endif +#elif defined(_IRR_COMPILE_WITH_IOS_DEVICE_) +#ifndef _IRR_COMPILE_WITH_EAGL_MANAGER_ +#define _IRR_COMPILE_WITH_EAGL_MANAGER_ +#endif +#endif +#endif + +//! Define _IRR_COMPILE_WITH_OGLES2_ to compile the Irrlicht engine with OpenGL ES 2.0. +/** If you do not wish the engine to be compiled with OpenGL ES 2.0, comment this +define out. */ +#define _IRR_COMPILE_WITH_OGLES2_ +#ifdef NO_IRR_COMPILE_WITH_OGLES2_ +#undef _IRR_COMPILE_WITH_OGLES2_ +#endif + +//! Define _IRR_COMPILE_WITH_WEBGL1_ to compile Irrlicht engine with a WebGL friendly +//! subset of the OpenGL ES 2.0 driver. +#define _IRR_COMPILE_WITH_WEBGL1_ +#ifdef NO_IRR_COMPILE_WITH_WEBGL1_ +#undef _IRR_COMPILE_WITH_WEBGL1_ +#endif +#ifdef _IRR_COMPILE_WITH_WEBGL1_ +#define _IRR_COMPILE_WITH_OGLES2_ // it's a subset of OGL ES2, so always needed when using WebGL +#endif + +//! Define required options for OpenGL ES 2.0 drivers. +#if defined(_IRR_COMPILE_WITH_OGLES2_) +#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) || defined(_IRR_COMPILE_WITH_X11_DEVICE_) || defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_) || defined(__EMSCRIPTEN__) +#define _IRR_OGLES2_USE_EXTPOINTER_ +#ifndef _IRR_COMPILE_WITH_EGL_MANAGER_ +#define _IRR_COMPILE_WITH_EGL_MANAGER_ +#endif +#elif defined(_IRR_COMPILE_WITH_IOS_DEVICE_) +#ifndef _IRR_COMPILE_WITH_EAGL_MANAGER_ +#define _IRR_COMPILE_WITH_EAGL_MANAGER_ +#endif +#endif +#endif + + + +//! Define _IRR_COMPILE_WITH_SOFTWARE_ to compile the Irrlicht engine with software driver +/** If you do not need the software driver, or want to use Burning's Video instead, +comment this define out */ +#define _IRR_COMPILE_WITH_SOFTWARE_ +#ifdef NO_IRR_COMPILE_WITH_SOFTWARE_ +#undef _IRR_COMPILE_WITH_SOFTWARE_ +#endif + +//! Define _IRR_COMPILE_WITH_BURNINGSVIDEO_ to compile the Irrlicht engine with Burning's video driver +/** If you do not need this software driver, you can comment this define out. */ +#define _IRR_COMPILE_WITH_BURNINGSVIDEO_ +#ifdef NO_IRR_COMPILE_WITH_BURNINGSVIDEO_ +#undef _IRR_COMPILE_WITH_BURNINGSVIDEO_ +#endif + +//! Define _IRR_COMPILE_WITH_X11_ to compile the Irrlicht engine with X11 support. +/** If you do not wish the engine to be compiled with X11, comment this +define out. */ +// Only used in LinuxDevice. +#define _IRR_COMPILE_WITH_X11_ +#ifdef NO_IRR_COMPILE_WITH_X11_ +#undef _IRR_COMPILE_WITH_X11_ +#endif + +//! On some Linux systems the XF86 vidmode extension or X11 RandR are missing. Use these flags +//! to remove the dependencies such that Irrlicht will compile on those systems, too. +//! If you don't need colored cursors you can also disable the Xcursor extension +#if defined(_IRR_LINUX_PLATFORM_) && defined(_IRR_COMPILE_WITH_X11_) +#define _IRR_LINUX_X11_VIDMODE_ +//#define _IRR_LINUX_X11_RANDR_ +#ifdef NO_IRR_LINUX_X11_VIDMODE_ +#undef _IRR_LINUX_X11_VIDMODE_ +#endif +#ifdef NO_IRR_LINUX_X11_RANDR_ +#undef _IRR_LINUX_X11_RANDR_ +#endif + +//! X11 has by default only monochrome cursors, but using the Xcursor library we can also get color cursor support. +//! If you have the need for custom color cursors on X11 then enable this and make sure you also link +//! to the Xcursor library in your Makefile/Projectfile. +//#define _IRR_LINUX_XCURSOR_ +#ifdef NO_IRR_LINUX_XCURSOR_ +#undef _IRR_LINUX_XCURSOR_ +#endif + +#endif + +//! Define _IRR_COMPILE_WITH_GUI_ to compile the engine with the built-in GUI +/** Disable this if you are using an external library to draw the GUI. If you disable this then +you will not be able to use anything provided by the GUI Environment, including loading fonts. */ +#define _IRR_COMPILE_WITH_GUI_ +#ifdef NO_IRR_COMPILE_WITH_GUI_ +#undef _IRR_COMPILE_WITH_GUI_ +#endif + +//! Define _IRR_COMPILE_WITH_PARTICLES to compile the engine the withe build-in particle system +/** You can disable this if you don't need particles or use an external particle system. */ +#define _IRR_COMPILE_WITH_PARTICLES_ +#ifdef NO_IRR_COMPILE_WITH_PARTICLES_ +#undef _IRR_COMPILE_WITH_PARTICLES_ +#endif + +//! Define _IRR_WCHAR_FILESYSTEM to enable unicode filesystem support for the engine. +/** This enables the engine to read/write from unicode filesystem. If you +disable this feature, the engine behave as before (ansi). This is currently only supported +for Windows based systems. You also have to set #define UNICODE for this to compile. +*/ +//#define _IRR_WCHAR_FILESYSTEM +#ifdef NO_IRR_WCHAR_FILESYSTEM +#undef _IRR_WCHAR_FILESYSTEM +#endif + +//! Define _IRR_COMPILE_WITH_JPEGLIB_ to enable compiling the engine using libjpeg. +/** This enables the engine to read jpeg images. If you comment this out, +the engine will no longer read .jpeg images. */ +#define _IRR_COMPILE_WITH_LIBJPEG_ +#ifdef NO_IRR_COMPILE_WITH_LIBJPEG_ +#undef _IRR_COMPILE_WITH_LIBJPEG_ +#endif + +//! Define _IRR_USE_NON_SYSTEM_JPEG_LIB_ to let irrlicht use the jpeglib which comes with irrlicht. +/** If this is commented out, Irrlicht will try to compile using the jpeg lib installed in the system. + This is only used when _IRR_COMPILE_WITH_LIBJPEG_ is defined. + NOTE: You will also have to modify the Makefile or project files when changing this default. + */ +#define _IRR_USE_NON_SYSTEM_JPEG_LIB_ +#ifdef NO_IRR_USE_NON_SYSTEM_JPEG_LIB_ +#undef _IRR_USE_NON_SYSTEM_JPEG_LIB_ +#endif + +//! Define _IRR_COMPILE_WITH_LIBPNG_ to enable compiling the engine using libpng. +/** This enables the engine to read png images. If you comment this out, +the engine will no longer read .png images. */ +#define _IRR_COMPILE_WITH_LIBPNG_ +#ifdef NO_IRR_COMPILE_WITH_LIBPNG_ +#undef _IRR_COMPILE_WITH_LIBPNG_ +#endif + +//! Define _IRR_USE_NON_SYSTEM_LIBPNG_ to let irrlicht use the libpng which comes with irrlicht. +/** If this is commented out, Irrlicht will try to compile using the libpng installed in the system. + This is only used when _IRR_COMPILE_WITH_LIBPNG_ is defined. + NOTE: You will also have to modify the Makefile or project files when changing this default. + */ +#define _IRR_USE_NON_SYSTEM_LIB_PNG_ +#ifdef NO_IRR_USE_NON_SYSTEM_LIB_PNG_ +#undef _IRR_USE_NON_SYSTEM_LIB_PNG_ +#endif + +//! Define _IRR_D3D_NO_SHADER_DEBUGGING to disable shader debugging in D3D9 +/** If _IRR_D3D_NO_SHADER_DEBUGGING is undefined in IrrCompileConfig.h, +it is possible to debug all D3D9 shaders in VisualStudio. All shaders +(which have been generated in memory or read from archives for example) will be emitted +into a temporary file at runtime for this purpose. To debug your shaders, choose +Debug->Direct3D->StartWithDirect3DDebugging in Visual Studio, and for every shader a +file named 'irr_dbg_shader_%%.vsh' or 'irr_dbg_shader_%%.psh' will be created. Drag'n'drop +the file you want to debug into visual studio. That's it. You can now set breakpoints and +watch registers, variables etc. This works with ASM, HLSL, and both with pixel and vertex shaders. +Note that the engine will run in D3D REF for this, which is a lot slower than HAL. */ +#define _IRR_D3D_NO_SHADER_DEBUGGING +#ifdef NO_IRR_D3D_NO_SHADER_DEBUGGING +#undef _IRR_D3D_NO_SHADER_DEBUGGING +#endif + +//! Define _IRR_D3D_USE_LEGACY_HLSL_COMPILER to enable the old HLSL compiler in recent DX SDKs +/** This enables support for ps_1_x shaders for recent DX SDKs. Otherwise, support +for this shader model is not available anymore in SDKs after Oct2006. You need to +distribute the OCT2006_d3dx9_31_x86.cab or OCT2006_d3dx9_31_x64.cab though, in order +to provide the user with the proper DLL. That's why it's disabled by default. */ +//#define _IRR_D3D_USE_LEGACY_HLSL_COMPILER +#ifdef NO_IRR_D3D_USE_LEGACY_HLSL_COMPILER +#undef _IRR_D3D_USE_LEGACY_HLSL_COMPILER +#endif + +//! Define _IRR_USE_NVIDIA_PERFHUD_ to opt-in to using the nVidia PerHUD tool +/** Enable, by opting-in, to use the nVidia PerfHUD performance analysis driver +tool . */ +#undef _IRR_USE_NVIDIA_PERFHUD_ + +//! Define one of the three setting for Burning's Video Software Rasterizer +/** So if we were marketing guys we could say Irrlicht has 4 Software-Rasterizers. + In a Nutshell: + All Burnings Rasterizers use 32 Bit Backbuffer, 32Bit Texture & 32 Bit Z or WBuffer, + 16 Bit/32 Bit can be adjusted on a global flag. + + BURNINGVIDEO_RENDERER_BEAUTIFUL + 32 Bit + Vertexcolor + Lighting + Per Pixel Perspective Correct + SubPixel/SubTexel Correct + + Bilinear Texturefiltering + WBuffer + + BURNINGVIDEO_RENDERER_FAST + 32 Bit + Per Pixel Perspective Correct + SubPixel/SubTexel Correct + WBuffer + + Bilinear Dithering TextureFiltering + WBuffer + + BURNINGVIDEO_RENDERER_ULTRA_FAST + 16Bit + SubPixel/SubTexel Correct + ZBuffer +*/ + +#define BURNINGVIDEO_RENDERER_BEAUTIFUL +//#define BURNINGVIDEO_RENDERER_FAST +//#define BURNINGVIDEO_RENDERER_ULTRA_FAST +//#define BURNINGVIDEO_RENDERER_CE + +//! Uncomment the following line if you want to ignore the deprecated warnings +//#define IGNORE_DEPRECATED_WARNING + +//! Define _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ to support ShadowVolumes +#define _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ +#ifdef NO_IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ +#undef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ +#endif + +//! Define _IRR_COMPILE_WITH_OCTREE_SCENENODE_ to support OctreeSceneNodes +#define _IRR_COMPILE_WITH_OCTREE_SCENENODE_ +#ifdef NO_IRR_COMPILE_WITH_OCTREE_SCENENODE_ +#undef _IRR_COMPILE_WITH_OCTREE_SCENENODE_ +#endif + +//! Define _IRR_COMPILE_WITH_TERRAIN_SCENENODE_ to support TerrainSceneNodes +#define _IRR_COMPILE_WITH_TERRAIN_SCENENODE_ +#ifdef NO_IRR_COMPILE_WITH_TERRAIN_SCENENODE_ +#undef _IRR_COMPILE_WITH_TERRAIN_SCENENODE_ +#endif + +//! Define _IRR_COMPILE_WITH_BILLBOARD_SCENENODE_ to support BillboardSceneNodes +#define _IRR_COMPILE_WITH_BILLBOARD_SCENENODE_ +#ifdef NO_IRR_COMPILE_WITH_BILLBOARD_SCENENODE_ +#undef _IRR_COMPILE_WITH_BILLBOARD_SCENENODE_ +#endif + +//! Define _IRR_COMPILE_WITH_WATER_SURFACE_SCENENODE_ to support WaterSurfaceSceneNodes +#define _IRR_COMPILE_WITH_WATER_SURFACE_SCENENODE_ +#ifdef NO_IRR_COMPILE_WITH_WATER_SURFACE_SCENENODE_ +#undef _IRR_COMPILE_WITH_WATER_SURFACE_SCENENODE_ +#endif + +//! Define _IRR_COMPILE_WITH_SKYDOME_SCENENODE_ to support SkydomeSceneNodes +#define _IRR_COMPILE_WITH_SKYDOME_SCENENODE_ +#ifdef NO_IRR_COMPILE_WITH_SKYDOME_SCENENODE_ +#undef _IRR_COMPILE_WITH_SKYDOME_SCENENODE_ +#endif + +//! Define _IRR_COMPILE_WITH_CUBE_SCENENODE_ to support CubeSceneNodes +#define _IRR_COMPILE_WITH_CUBE_SCENENODE_ +#ifdef NO_IRR_COMPILE_WITH_CUBE_SCENENODE_ +#undef _IRR_COMPILE_WITH_CUBE_SCENENODE_ +#endif + +//! Define _IRR_COMPILE_WITH_SPHERE_SCENENODE_ to support CubeSceneNodes +#define _IRR_COMPILE_WITH_SPHERE_SCENENODE_ +#ifdef NO_IRR_COMPILE_WITH_SPHERE_SCENENODE_ +#undef _IRR_COMPILE_WITH_SPHERE_SCENENODE_ +#endif + +//! Define _IRR_COMPILE_WITH_IRR_SCENE_LOADER_ if you want to be able to load +/** .irr scenes using ISceneManager::loadScene */ +#define _IRR_COMPILE_WITH_IRR_SCENE_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_IRR_SCENE_LOADER_ +#undef _IRR_COMPILE_WITH_IRR_SCENE_LOADER_ +#endif + +//! Define _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ if you want to use bone based +/** animated meshes. If you compile without this, you will be unable to load +B3D, MS3D or X meshes */ +#define _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ +#ifdef NO_IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ +#undef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ +#endif + +#ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ +//! Define _IRR_COMPILE_WITH_B3D_LOADER_ if you want to use Blitz3D files +#define _IRR_COMPILE_WITH_B3D_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_B3D_LOADER_ +#undef _IRR_COMPILE_WITH_B3D_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_MS3D_LOADER_ if you want to Milkshape files +#define _IRR_COMPILE_WITH_MS3D_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_MS3D_LOADER_ +#undef _IRR_COMPILE_WITH_MS3D_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_X_LOADER_ if you want to use Microsoft X files +#define _IRR_COMPILE_WITH_X_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_X_LOADER_ +#undef _IRR_COMPILE_WITH_X_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_OGRE_LOADER_ if you want to load Ogre 3D files +#define _IRR_COMPILE_WITH_OGRE_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_OGRE_LOADER_ +#undef _IRR_COMPILE_WITH_OGRE_LOADER_ +#endif +#endif // _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ + +//! Define _IRR_COMPILE_WITH_IRR_MESH_LOADER_ if you want to load Irrlicht Engine .irrmesh files +#define _IRR_COMPILE_WITH_IRR_MESH_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_IRR_MESH_LOADER_ +#undef _IRR_COMPILE_WITH_IRR_MESH_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_HALFLIFE_LOADER_ if you want to load Halflife animated files +#define _IRR_COMPILE_WITH_HALFLIFE_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_HALFLIFE_LOADER_ +#undef _IRR_COMPILE_WITH_HALFLIFE_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_MD2_LOADER_ if you want to load Quake 2 animated files +#define _IRR_COMPILE_WITH_MD2_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_MD2_LOADER_ +#undef _IRR_COMPILE_WITH_MD2_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_MD3_LOADER_ if you want to load Quake 3 animated files +#define _IRR_COMPILE_WITH_MD3_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_MD3_LOADER_ +#undef _IRR_COMPILE_WITH_MD3_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_3DS_LOADER_ if you want to load 3D Studio Max files +#define _IRR_COMPILE_WITH_3DS_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_3DS_LOADER_ +#undef _IRR_COMPILE_WITH_3DS_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_COLLADA_LOADER_ if you want to load Collada files +#define _IRR_COMPILE_WITH_COLLADA_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_COLLADA_LOADER_ +#undef _IRR_COMPILE_WITH_COLLADA_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_CSM_LOADER_ if you want to load Cartography Shop files +#define _IRR_COMPILE_WITH_CSM_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_CSM_LOADER_ +#undef _IRR_COMPILE_WITH_CSM_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_BSP_LOADER_ if you want to load Quake 3 BSP files +#define _IRR_COMPILE_WITH_BSP_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_BSP_LOADER_ +#undef _IRR_COMPILE_WITH_BSP_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_DMF_LOADER_ if you want to load DeleD files +#define _IRR_COMPILE_WITH_DMF_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_DMF_LOADER_ +#undef _IRR_COMPILE_WITH_DMF_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_LMTS_LOADER_ if you want to load LMTools files +#define _IRR_COMPILE_WITH_LMTS_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_LMTS_LOADER_ +#undef _IRR_COMPILE_WITH_LMTS_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_MY3D_LOADER_ if you want to load MY3D files +#define _IRR_COMPILE_WITH_MY3D_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_MY3D_LOADER_ +#undef _IRR_COMPILE_WITH_MY3D_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_OBJ_LOADER_ if you want to load Wavefront OBJ files +#define _IRR_COMPILE_WITH_OBJ_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_OBJ_LOADER_ +#undef _IRR_COMPILE_WITH_OBJ_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_OCT_LOADER_ if you want to load FSRad OCT files +#define _IRR_COMPILE_WITH_OCT_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_OCT_LOADER_ +#undef _IRR_COMPILE_WITH_OCT_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_LWO_LOADER_ if you want to load Lightwave3D files +#define _IRR_COMPILE_WITH_LWO_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_LWO_LOADER_ +#undef _IRR_COMPILE_WITH_LWO_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_STL_LOADER_ if you want to load stereolithography files +#define _IRR_COMPILE_WITH_STL_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_STL_LOADER_ +#undef _IRR_COMPILE_WITH_STL_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_PLY_LOADER_ if you want to load Polygon (Stanford Triangle) files +#define _IRR_COMPILE_WITH_PLY_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_PLY_LOADER_ +#undef _IRR_COMPILE_WITH_PLY_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_SMF_LOADER_ if you want to load 3D World Studio mesh files +#define _IRR_COMPILE_WITH_SMF_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_SMF_LOADER_ +#undef _IRR_COMPILE_WITH_SMF_LOADER_ +#endif + +//! Define _IRR_COMPILE_WITH_IRR_WRITER_ if you want to write static .irrMesh files +#define _IRR_COMPILE_WITH_IRR_WRITER_ +#ifdef NO_IRR_COMPILE_WITH_IRR_WRITER_ +#undef _IRR_COMPILE_WITH_IRR_WRITER_ +#endif +//! Define _IRR_COMPILE_WITH_COLLADA_WRITER_ if you want to write Collada files +#define _IRR_COMPILE_WITH_COLLADA_WRITER_ +#ifdef NO_IRR_COMPILE_WITH_COLLADA_WRITER_ +#undef _IRR_COMPILE_WITH_COLLADA_WRITER_ +#endif +//! Define _IRR_COMPILE_WITH_STL_WRITER_ if you want to write .stl files +#define _IRR_COMPILE_WITH_STL_WRITER_ +#ifdef NO_IRR_COMPILE_WITH_STL_WRITER_ +#undef _IRR_COMPILE_WITH_STL_WRITER_ +#endif +//! Define _IRR_COMPILE_WITH_OBJ_WRITER_ if you want to write .obj files +#define _IRR_COMPILE_WITH_OBJ_WRITER_ +#ifdef NO_IRR_COMPILE_WITH_OBJ_WRITER_ +#undef _IRR_COMPILE_WITH_OBJ_WRITER_ +#endif +//! Define _IRR_COMPILE_WITH_PLY_WRITER_ if you want to write .ply files +#define _IRR_COMPILE_WITH_PLY_WRITER_ +#ifdef NO_IRR_COMPILE_WITH_PLY_WRITER_ +#undef _IRR_COMPILE_WITH_PLY_WRITER_ +#endif +//! Define _IRR_COMPILE_WITH_B3D_WRITER_ if you want to write .b3d files +#define _IRR_COMPILE_WITH_B3D_WRITER_ +#ifdef NO_IRR_COMPILE_WITH_B3D_WRITER_ +#undef _IRR_COMPILE_WITH_B3D_WRITER_ +#endif + +//! Define _IRR_COMPILE_WITH_BMP_LOADER_ if you want to load .bmp files +//! Disabling this loader will also disable the built-in font +#define _IRR_COMPILE_WITH_BMP_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_BMP_LOADER_ +#undef _IRR_COMPILE_WITH_BMP_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_JPG_LOADER_ if you want to load .jpg files +#define _IRR_COMPILE_WITH_JPG_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_JPG_LOADER_ +#undef _IRR_COMPILE_WITH_JPG_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_PCX_LOADER_ if you want to load .pcx files +#define _IRR_COMPILE_WITH_PCX_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_PCX_LOADER_ +#undef _IRR_COMPILE_WITH_PCX_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_PNG_LOADER_ if you want to load .png files +#define _IRR_COMPILE_WITH_PNG_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_PNG_LOADER_ +#undef _IRR_COMPILE_WITH_PNG_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_PPM_LOADER_ if you want to load .ppm/.pgm/.pbm files +#define _IRR_COMPILE_WITH_PPM_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_PPM_LOADER_ +#undef _IRR_COMPILE_WITH_PPM_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_PSD_LOADER_ if you want to load .psd files +#define _IRR_COMPILE_WITH_PSD_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_PSD_LOADER_ +#undef _IRR_COMPILE_WITH_PSD_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_PVR_LOADER_ if you want to load .pvr files +#define _IRR_COMPILE_WITH_PVR_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_PVR_LOADER_ +#undef _IRR_COMPILE_WITH_PVR_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_DDS_LOADER_ if you want to load compressed .dds files +// Patent problem isn't related to this loader. +#define _IRR_COMPILE_WITH_DDS_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_DDS_LOADER_ +#undef _IRR_COMPILE_WITH_DDS_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_DDS_DECODER_LOADER_ if you want to load .dds files +//! loader will decompress these files and will send to the memory as uncompressed files. +// Outcommented because +// a) it doesn't compile on 64-bit currently +// b) anyone enabling it should be aware that S3TC compression algorithm which might be used in that loader +// is patented in the US by S3 and they do collect license fees when it's used in applications. +// So if you are unfortunate enough to develop applications for US market and their broken patent system be careful. +// #define _IRR_COMPILE_WITH_DDS_DECODER_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_DDS_DECODER_LOADER_ +#undef _IRR_COMPILE_WITH_DDS_DECODER_LOADER_ +#endif +#ifdef _IRR_COMPILE_WITH_DDS_DECODER_LOADER_ +#undef _IRR_COMPILE_WITH_DDS_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_TGA_LOADER_ if you want to load .tga files +#define _IRR_COMPILE_WITH_TGA_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_TGA_LOADER_ +#undef _IRR_COMPILE_WITH_TGA_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_WAL_LOADER_ if you want to load .wal files +#define _IRR_COMPILE_WITH_WAL_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_WAL_LOADER_ +#undef _IRR_COMPILE_WITH_WAL_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_LMP_LOADER_ if you want to load .lmp files +#define _IRR_COMPILE_WITH_LMP_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_LMP_LOADER_ +#undef _IRR_COMPILE_WITH_LMP_LOADER_ +#endif +//! Define _IRR_COMPILE_WITH_RGB_LOADER_ if you want to load Silicon Graphics .rgb/.rgba/.sgi/.int/.inta/.bw files +#define _IRR_COMPILE_WITH_RGB_LOADER_ +#ifdef NO_IRR_COMPILE_WITH_RGB_LOADER_ +#undef _IRR_COMPILE_WITH_RGB_LOADER_ +#endif + +//! Define _IRR_COMPILE_WITH_BMP_WRITER_ if you want to write .bmp files +#define _IRR_COMPILE_WITH_BMP_WRITER_ +#ifdef NO_IRR_COMPILE_WITH_BMP_WRITER_ +#undef _IRR_COMPILE_WITH_BMP_WRITER_ +#endif +//! Define _IRR_COMPILE_WITH_JPG_WRITER_ if you want to write .jpg files +#define _IRR_COMPILE_WITH_JPG_WRITER_ +#ifdef NO_IRR_COMPILE_WITH_JPG_WRITER_ +#undef _IRR_COMPILE_WITH_JPG_WRITER_ +#endif +//! Define _IRR_COMPILE_WITH_PCX_WRITER_ if you want to write .pcx files +#define _IRR_COMPILE_WITH_PCX_WRITER_ +#ifdef NO_IRR_COMPILE_WITH_PCX_WRITER_ +#undef _IRR_COMPILE_WITH_PCX_WRITER_ +#endif +//! Define _IRR_COMPILE_WITH_PNG_WRITER_ if you want to write .png files +#define _IRR_COMPILE_WITH_PNG_WRITER_ +#ifdef NO_IRR_COMPILE_WITH_PNG_WRITER_ +#undef _IRR_COMPILE_WITH_PNG_WRITER_ +#endif +//! Define _IRR_COMPILE_WITH_PPM_WRITER_ if you want to write .ppm files +#define _IRR_COMPILE_WITH_PPM_WRITER_ +#ifdef NO_IRR_COMPILE_WITH_PPM_WRITER_ +#undef _IRR_COMPILE_WITH_PPM_WRITER_ +#endif +//! Define _IRR_COMPILE_WITH_PSD_WRITER_ if you want to write .psd files +#define _IRR_COMPILE_WITH_PSD_WRITER_ +#ifdef NO_IRR_COMPILE_WITH_PSD_WRITER_ +#undef _IRR_COMPILE_WITH_PSD_WRITER_ +#endif +//! Define _IRR_COMPILE_WITH_TGA_WRITER_ if you want to write .tga files +#define _IRR_COMPILE_WITH_TGA_WRITER_ +#ifdef NO_IRR_COMPILE_WITH_TGA_WRITER_ +#undef _IRR_COMPILE_WITH_TGA_WRITER_ +#endif + +//! Define __IRR_COMPILE_WITH_ZIP_ARCHIVE_LOADER_ if you want to open ZIP and GZIP archives +/** ZIP reading has several more options below to configure. */ +#define __IRR_COMPILE_WITH_ZIP_ARCHIVE_LOADER_ +#ifdef NO__IRR_COMPILE_WITH_ZIP_ARCHIVE_LOADER_ +#undef __IRR_COMPILE_WITH_ZIP_ARCHIVE_LOADER_ +#endif +#ifdef __IRR_COMPILE_WITH_ZIP_ARCHIVE_LOADER_ +//! Define _IRR_COMPILE_WITH_ZLIB_ to enable compiling the engine using zlib. +/** This enables the engine to read from compressed .zip archives. If you +disable this feature, the engine can still read archives, but only uncompressed +ones. */ +#define _IRR_COMPILE_WITH_ZLIB_ +#ifdef NO_IRR_COMPILE_WITH_ZLIB_ +#undef _IRR_COMPILE_WITH_ZLIB_ +#endif +//! Define _IRR_USE_NON_SYSTEM_ZLIB_ to let irrlicht use the zlib which comes with irrlicht. +/** If this is commented out, Irrlicht will try to compile using the zlib + installed on the system. This is only used when _IRR_COMPILE_WITH_ZLIB_ is + defined. + NOTE: You will also have to modify the Makefile or project files when changing this default. + */ +#define _IRR_USE_NON_SYSTEM_ZLIB_ +#ifdef NO_IRR_USE_NON_SYSTEM_ZLIB_ +#undef _IRR_USE_NON_SYSTEM_ZLIB_ +#endif +//! Define _IRR_COMPILE_WITH_ZIP_ENCRYPTION_ if you want to read AES-encrypted ZIP archives +#define _IRR_COMPILE_WITH_ZIP_ENCRYPTION_ +#ifdef NO_IRR_COMPILE_WITH_ZIP_ENCRYPTION_ +#undef _IRR_COMPILE_WITH_ZIP_ENCRYPTION_ +#endif +//! Define _IRR_COMPILE_WITH_BZIP2_ if you want to support bzip2 compressed zip archives +/** bzip2 is superior to the original zip file compression modes, but requires +a certain amount of memory for decompression and adds several files to the +library. */ +#define _IRR_COMPILE_WITH_BZIP2_ +#ifdef NO_IRR_COMPILE_WITH_BZIP2_ +#undef _IRR_COMPILE_WITH_BZIP2_ +#endif +//! Define _IRR_USE_NON_SYSTEM_BZLIB_ to let irrlicht use the bzlib which comes with irrlicht. +/** If this is commented out, Irrlicht will try to compile using the bzlib +installed on the system. This is only used when _IRR_COMPILE_WITH_BZLIB_ is +defined. +NOTE: You will also have to modify the Makefile or project files when changing this default. +*/ +#define _IRR_USE_NON_SYSTEM_BZLIB_ +#ifdef NO_IRR_USE_NON_SYSTEM_BZLIB_ +#undef _IRR_USE_NON_SYSTEM_BZLIB_ +#endif +//! Define _IRR_COMPILE_WITH_LZMA_ if you want to use LZMA compressed zip files. +/** LZMA is a very efficient compression code, known from 7zip. Irrlicht +currently only supports zip archives, though. */ +#define _IRR_COMPILE_WITH_LZMA_ +#ifdef NO_IRR_COMPILE_WITH_LZMA_ +#undef _IRR_COMPILE_WITH_LZMA_ +#endif +#endif + +//! Define __IRR_COMPILE_WITH_MOUNT_ARCHIVE_LOADER_ if you want to mount folders as archives +#define __IRR_COMPILE_WITH_MOUNT_ARCHIVE_LOADER_ +#ifdef NO__IRR_COMPILE_WITH_MOUNT_ARCHIVE_LOADER_ +#undef __IRR_COMPILE_WITH_MOUNT_ARCHIVE_LOADER_ +#endif +//! Define __IRR_COMPILE_WITH_PAK_ARCHIVE_LOADER_ if you want to open ID software PAK archives +#define __IRR_COMPILE_WITH_PAK_ARCHIVE_LOADER_ +#ifdef NO__IRR_COMPILE_WITH_PAK_ARCHIVE_LOADER_ +#undef __IRR_COMPILE_WITH_PAK_ARCHIVE_LOADER_ +#endif +//! Define __IRR_COMPILE_WITH_NPK_ARCHIVE_LOADER_ if you want to open Nebula Device NPK archives +#define __IRR_COMPILE_WITH_NPK_ARCHIVE_LOADER_ +#ifdef NO__IRR_COMPILE_WITH_NPK_ARCHIVE_LOADER_ +#undef __IRR_COMPILE_WITH_NPK_ARCHIVE_LOADER_ +#endif +//! Define __IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_ if you want to open TAR archives +#define __IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_ +#ifdef NO__IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_ +#undef __IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_ +#endif +//! Define __IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_ if you want to open WAD archives +#define __IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_ +#ifdef NO__IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_ +#undef __IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_ +#endif + +//! Set FPU settings +/** Irrlicht should use approximate float and integer fpu techniques +precision will be lower but speed higher. currently X86 only +*/ +#if !defined(_IRR_OSX_PLATFORM_) && !defined(_IRR_SOLARIS_PLATFORM_) + //#define IRRLICHT_FAST_MATH + #ifdef NO_IRRLICHT_FAST_MATH + #undef IRRLICHT_FAST_MATH + #endif +#endif + +// Some cleanup and standard stuff + +#ifdef _IRR_WINDOWS_API_ + +// To build Irrlicht as a static library, you must define _IRR_STATIC_LIB_ in both the +// Irrlicht build, *and* in the user application, before #including +#ifndef _IRR_STATIC_LIB_ +#ifdef IRRLICHT_EXPORTS +#define IRRLICHT_API __declspec(dllexport) +#else +#define IRRLICHT_API __declspec(dllimport) +#endif // IRRLICHT_EXPORT +#else +#define IRRLICHT_API +#endif // _IRR_STATIC_LIB_ + +// Declare the calling convention. +#if defined(_STDCALL_SUPPORTED) +#define IRRCALLCONV __stdcall +#else +#define IRRCALLCONV __cdecl +#endif // STDCALL_SUPPORTED + +#else // _IRR_WINDOWS_API_ + +// Force symbol export in shared libraries built with gcc. +#if (__GNUC__ >= 4) && !defined(_IRR_STATIC_LIB_) && defined(IRRLICHT_EXPORTS) +#define IRRLICHT_API __attribute__ ((visibility("default"))) +#else +#define IRRLICHT_API +#endif + +#define IRRCALLCONV + +#endif // _IRR_WINDOWS_API_ + +#ifndef _IRR_WINDOWS_API_ + #undef _IRR_WCHAR_FILESYSTEM +#endif + +#if defined(_IRR_SOLARIS_PLATFORM_) + #undef _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ +#endif + +//! Define __IRR_HAS_S64 if the irr::s64 type should be enable (needs long long, available on most platforms, but not part of ISO C++ 98) +#define __IRR_HAS_S64 +#ifdef NO__IRR_HAS_S64 +#undef __IRR_HAS_S64 +#endif + +// These depend on XML +#ifndef _IRR_COMPILE_WITH_XML_ + #undef _IRR_COMPILE_WITH_IRR_MESH_LOADER_ + #undef _IRR_COMPILE_WITH_IRR_WRITER_ + #undef _IRR_COMPILE_WITH_COLLADA_WRITER_ + #undef _IRR_COMPILE_WITH_COLLADA_LOADER_ +#endif + +#if defined(__BORLANDC__) + #include + + // Borland 5.5.1 + #if __BORLANDC__ == 0x551 + #undef _tfinddata_t + #undef _tfindfirst + #undef _tfindnext + + #define _tfinddata_t __tfinddata_t + #define _tfindfirst __tfindfirst + #define _tfindnext __tfindnext + typedef long intptr_t; + #endif +#endif + +#ifndef __has_feature + #define __has_feature(x) 0 // Compatibility with non-clang compilers. +#endif + +#ifdef _DEBUG + //! A few attributes are written in CSceneManager when _IRR_SCENEMANAGER_DEBUG is enabled + // NOTE: Those attributes were used always until 1.8.0 and became a global define for 1.8.1 + // which is only enabled in debug because it had a large (sometimes >5%) impact on speed. + // A better solution in the long run is to break the interface and remove _all_ attribute + // access in functions like CSceneManager::drawAll and instead put that information in some + // own struct/class or in CSceneManager. + // See http://irrlicht.sourceforge.net/forum/viewtopic.php?f=2&t=48211 for the discussion. + #define _IRR_SCENEMANAGER_DEBUG + #ifdef NO_IRR_SCENEMANAGER_DEBUG + #undef _IRR_SCENEMANAGER_DEBUG + #endif +#endif + +#endif // __IRR_COMPILE_CONFIG_H_INCLUDED__ + diff --git a/include/IrrlichtDevice.h b/include/IrrlichtDevice.h new file mode 100644 index 00000000..ac02342b --- /dev/null +++ b/include/IrrlichtDevice.h @@ -0,0 +1,396 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_IRRLICHT_DEVICE_H_INCLUDED__ +#define __I_IRRLICHT_DEVICE_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "dimension2d.h" +#include "IVideoDriver.h" +#include "EDriverTypes.h" +#include "EDeviceTypes.h" +#include "IEventReceiver.h" +#include "ICursorControl.h" +#include "IVideoModeList.h" +#include "ITimer.h" +#include "IOSOperator.h" + +namespace irr +{ + class ILogger; + class IEventReceiver; + class IRandomizer; + + namespace io { + class IFileSystem; + } // end namespace io + + namespace gui { + class IGUIEnvironment; + } // end namespace gui + + namespace scene { + class ISceneManager; + } // end namespace scene + + namespace video { + class IContextManager; + } // end namespace video + + //! The Irrlicht device. You can create it with createDevice() or createDeviceEx(). + /** This is the most important class of the Irrlicht Engine. You can + access everything in the engine if you have a pointer to an instance of + this class. There should be only one instance of this class at any + time. + */ + class IrrlichtDevice : public virtual IReferenceCounted + { + public: + + //! Runs the device. + /** Also increments the virtual timer by calling + ITimer::tick();. You can prevent this + by calling ITimer::stop(); before and ITimer::start() after + calling IrrlichtDevice::run(). Returns false if device wants + to be deleted. Use it in this way: + \code + while(device->run()) + { + // draw everything here + } + \endcode + If you want the device to do nothing if the window is inactive + (recommended), use the slightly enhanced code shown at isWindowActive(). + + Note if you are running Irrlicht inside an external, custom + created window: Calling Device->run() will cause Irrlicht to + dispatch windows messages internally. + If you are running Irrlicht in your own custom window, you can + also simply use your own message loop using GetMessage, + DispatchMessage and whatever and simply don't use this method. + But note that Irrlicht will not be able to fetch user input + then. See irr::SIrrlichtCreationParameters::WindowId for more + information and example code. + */ + virtual bool run() = 0; + + //! Cause the device to temporarily pause execution and let other processes run. + /** This should bring down processor usage without major + performance loss for Irrlicht */ + virtual void yield() = 0; + + //! Pause execution and let other processes to run for a specified amount of time. + /** It may not wait the full given time, as sleep may be interrupted + \param timeMs: Time to sleep for in milliseconds. + \param pauseTimer: If true, pauses the device timer while sleeping + */ + virtual void sleep(u32 timeMs, bool pauseTimer=false) = 0; + + //! Provides access to the video driver for drawing 3d and 2d geometry. + /** \return Pointer the video driver. */ + virtual video::IVideoDriver* getVideoDriver() = 0; + + //! Provides access to the virtual file system. + /** \return Pointer to the file system. */ + virtual io::IFileSystem* getFileSystem() = 0; + + //! Provides access to the 2d user interface environment. + /** \return Pointer to the gui environment. */ + virtual gui::IGUIEnvironment* getGUIEnvironment() = 0; + + //! Provides access to the scene manager. + /** \return Pointer to the scene manager. */ + virtual scene::ISceneManager* getSceneManager() = 0; + + //! Provides access to the cursor control. + /** \return Pointer to the mouse cursor control interface. */ + virtual gui::ICursorControl* getCursorControl() = 0; + + //! Provides access to the message logger. + /** \return Pointer to the logger. */ + virtual ILogger* getLogger() = 0; + + //! Gets a list with all video modes available. + /** You only need a null driver (ED_NULL) to access + those video modes. So you can get the available modes + before starting any other video driver. + \return Pointer to a list with all video modes supported + by the gfx adapter. */ + virtual video::IVideoModeList* getVideoModeList() = 0; + + //! Get context manager + virtual video::IContextManager* getContextManager() = 0; + + //! Provides access to the operation system operator object. + /** The OS operator provides methods for + getting system specific information and doing system + specific operations, such as exchanging data with the clipboard + or reading the operation system version. + \return Pointer to the OS operator. */ + virtual IOSOperator* getOSOperator() = 0; + + //! Provides access to the engine's timer. + /** The system time can be retrieved by it as + well as the virtual time, which also can be manipulated. + \return Pointer to the ITimer object. */ + virtual ITimer* getTimer() = 0; + + //! Provides access to the engine's currently set randomizer. + /** \return Pointer to the IRandomizer object. */ + virtual IRandomizer* getRandomizer() const =0; + + //! Sets a new randomizer. + /** \param r Pointer to the new IRandomizer object. This object is + grab()'ed by the engine and will be released upon the next setRandomizer + call or upon device destruction. */ + virtual void setRandomizer(IRandomizer* r) =0; + + //! Creates a new default randomizer. + /** The default randomizer provides the random sequence known from previous + Irrlicht versions and is the initial randomizer set on device creation. + \return Pointer to the default IRandomizer object. */ + virtual IRandomizer* createDefaultRandomizer() const =0; + + //! Sets the caption of the window. + /** \param text: New text of the window caption. */ + virtual void setWindowCaption(const wchar_t* text) = 0; + + //! Returns if the window is active. + /** If the window is inactive, + nothing needs to be drawn. So if you don't want to draw anything + when the window is inactive, create your drawing loop this way: + \code + while(device->run()) + { + if (device->isWindowActive()) + { + // draw everything here + } + else + device->yield(); + } + \endcode + \return True if window is active. */ + virtual bool isWindowActive() const = 0; + + //! Checks if the Irrlicht window has the input focus + /** \return True if window has focus. */ + virtual bool isWindowFocused() const = 0; + + //! Checks if the Irrlicht window is minimized + /** \return True if window is minimized. */ + virtual bool isWindowMinimized() const = 0; + + //! Checks if the Irrlicht window is running in fullscreen mode + /** \return True if window is fullscreen. */ + virtual bool isFullscreen() const = 0; + + //! Get the current color format of the window + /** \return Color format of the window. */ + virtual video::ECOLOR_FORMAT getColorFormat() const = 0; + + //! Notifies the device that it should close itself. + /** IrrlichtDevice::run() will always return false after closeDevice() was called. */ + virtual void closeDevice() = 0; + + //! Get the version of the engine. + /** The returned string + will look like this: "1.2.3" or this: "1.2". + \return String which contains the version. */ + virtual const c8* getVersion() const = 0; + + //! Sets a new user event receiver which will receive events from the engine. + /** Return true in IEventReceiver::OnEvent to prevent the event from continuing along + the chain of event receivers. The path that an event takes through the system depends + on its type. See irr::EEVENT_TYPE for details. + \param receiver New receiver to be used. */ + virtual void setEventReceiver(IEventReceiver* receiver) = 0; + + //! Provides access to the current event receiver. + /** \return Pointer to the current event receiver. Returns 0 if there is none. */ + virtual IEventReceiver* getEventReceiver() = 0; + + //! Sends a user created event to the engine. + /** Is is usually not necessary to use this. However, if you + are using an own input library for example for doing joystick + input, you can use this to post key or mouse input events to + the engine. Internally, this method only delegates the events + further to the scene manager and the GUI environment. */ + virtual bool postEventFromUser(const SEvent& event) = 0; + + //! Sets the input receiving scene manager. + /** If set to null, the main scene manager (returned by + GetSceneManager()) will receive the input + \param sceneManager New scene manager to be used. */ + virtual void setInputReceivingSceneManager(scene::ISceneManager* sceneManager) = 0; + + //! Sets if the window should be resizable in windowed mode. + /** The default is false. This method only works in windowed + mode. + \param resize Flag whether the window should be resizable. */ + virtual void setResizable(bool resize=false) = 0; + + //! Resize the render window. + /** This will only work in windowed mode and is not yet supported on all systems. + It does set the drawing/clientDC size of the window, the window decorations are added to that. + You get the current window size with IVideoDriver::getScreenSize() (might be unified in future) + */ + virtual void setWindowSize(const irr::core::dimension2d& size) = 0; + + //! Minimizes the window if possible. + virtual void minimizeWindow() =0; + + //! Maximizes the window if possible. + virtual void maximizeWindow() =0; + + //! Restore the window to normal size if possible. + virtual void restoreWindow() =0; + + //! Get the position of the frame on-screen + virtual core::position2di getWindowPosition() = 0; + + //! 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 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. + */ + virtual bool activateJoysticks(core::array& joystickInfo) =0; + + //! Activate accelerometer. + virtual bool activateAccelerometer(float updateInterval = 0.016666f) = 0; + + //! Deactivate accelerometer. + virtual bool deactivateAccelerometer() = 0; + + //! Is accelerometer active. + virtual bool isAccelerometerActive() = 0; + + //! Is accelerometer available. + virtual bool isAccelerometerAvailable() = 0; + + //! Activate gyroscope. + virtual bool activateGyroscope(float updateInterval = 0.016666f) = 0; + + //! Deactivate gyroscope. + virtual bool deactivateGyroscope() = 0; + + //! Is gyroscope active. + virtual bool isGyroscopeActive() = 0; + + //! Is gyroscope available. + virtual bool isGyroscopeAvailable() = 0; + + //! Activate device motion. + virtual bool activateDeviceMotion(float updateInterval = 0.016666f) = 0; + + //! Deactivate device motion. + virtual bool deactivateDeviceMotion() = 0; + + //! Is device motion active. + virtual bool isDeviceMotionActive() = 0; + + //! Is device motion available. + virtual bool isDeviceMotionAvailable() = 0; + + //! Set the current Gamma Value for the Display + virtual bool setGammaRamp(f32 red, f32 green, f32 blue, + f32 relativebrightness, f32 relativecontrast) =0; + + //! Get the current Gamma Value for the Display + virtual bool getGammaRamp(f32 &red, f32 &green, f32 &blue, + f32 &brightness, f32 &contrast) =0; + + //! Set the maximal elapsed time between 2 clicks to generate doubleclicks for the mouse. It also affects tripleclick behavior. + /** When set to 0 no double- and tripleclicks will be generated. + \param timeMs maximal time in milliseconds for two consecutive clicks to be recognized as double click + */ + virtual void setDoubleClickTime(u32 timeMs) =0; + + //! Get the maximal elapsed time between 2 clicks to generate double- and tripleclicks for the mouse. + /** When return value is 0 no double- and tripleclicks will be generated. + \return maximal time in milliseconds for two consecutive clicks to be recognized as double click + */ + virtual u32 getDoubleClickTime() const =0; + + //! Remove messages pending in the system message loop + /** This function is usually used after messages have been buffered for a longer time, for example + when loading a large scene. Clearing the message loop prevents that mouse- or buttonclicks which users + have pressed in the meantime will now trigger unexpected actions in the gui.
+ So far the following messages are cleared:
+ Win32: All keyboard and mouse messages
+ Linux: All keyboard and mouse messages
+ All other devices are not yet supported here.
+ The function is still somewhat experimental, as the kind of messages we clear is based on just a few use-cases. + If you think further messages should be cleared, or some messages should not be cleared here, then please tell us. */ + virtual void clearSystemMessages() = 0; + + //! Get the type of the device. + /** This allows the user to check which windowing system is currently being + used. */ + virtual E_DEVICE_TYPE getType() const = 0; + + //! Check if a driver type is supported by the engine. + /** Even if true is returned the driver may not be available + for a configuration requested when creating the device. */ + static bool isDriverSupported(video::E_DRIVER_TYPE driver) + { + switch (driver) + { + case video::EDT_NULL: + return true; + case video::EDT_SOFTWARE: +#ifdef _IRR_COMPILE_WITH_SOFTWARE_ + return true; +#else + return false; +#endif + case video::EDT_BURNINGSVIDEO: +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return true; +#else + return false; +#endif + case video::EDT_DIRECT3D9: +#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ + return true; +#else + return false; +#endif + case video::EDT_OPENGL: +#ifdef _IRR_COMPILE_WITH_OPENGL_ + return true; +#else + return false; +#endif + case video::EDT_OGLES1: +#ifdef _IRR_COMPILE_WITH_OGLES1_ + return true; +#else + return false; +#endif + case video::EDT_OGLES2: +#ifdef _IRR_COMPILE_WITH_OGLES2_ + return true; +#else + return false; +#endif + case video::EDT_WEBGL1: +#ifdef _IRR_COMPILE_WITH_WEBGL1_ + return true; +#else + return false; +#endif + default: + return false; + } + } + }; + +} // end namespace irr + +#endif + diff --git a/include/Keycodes.h b/include/Keycodes.h new file mode 100644 index 00000000..8fb85942 --- /dev/null +++ b/include/Keycodes.h @@ -0,0 +1,189 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_KEY_CODES_H_INCLUDED__ +#define __IRR_KEY_CODES_H_INCLUDED__ + +namespace irr +{ + + enum EKEY_CODE + { + KEY_UNKNOWN = 0x0, + KEY_LBUTTON = 0x01, // Left mouse button + KEY_RBUTTON = 0x02, // Right mouse button + KEY_CANCEL = 0x03, // Control-break processing + KEY_MBUTTON = 0x04, // Middle mouse button (three-button mouse) + KEY_XBUTTON1 = 0x05, // Windows 2000/XP: X1 mouse button + KEY_XBUTTON2 = 0x06, // Windows 2000/XP: X2 mouse button + KEY_BACK = 0x08, // BACKSPACE key + KEY_TAB = 0x09, // TAB key + KEY_CLEAR = 0x0C, // CLEAR key + KEY_RETURN = 0x0D, // ENTER key + KEY_SHIFT = 0x10, // SHIFT key + KEY_CONTROL = 0x11, // CTRL key + KEY_MENU = 0x12, // ALT key + KEY_PAUSE = 0x13, // PAUSE key + KEY_CAPITAL = 0x14, // CAPS LOCK key + KEY_KANA = 0x15, // IME Kana mode + KEY_HANGUEL = 0x15, // IME Hanguel mode (maintained for compatibility use KEY_HANGUL) + KEY_HANGUL = 0x15, // IME Hangul mode + KEY_JUNJA = 0x17, // IME Junja mode + KEY_FINAL = 0x18, // IME final mode + KEY_HANJA = 0x19, // IME Hanja mode + KEY_KANJI = 0x19, // IME Kanji mode + KEY_ESCAPE = 0x1B, // ESC key + KEY_CONVERT = 0x1C, // IME convert + KEY_NONCONVERT = 0x1D, // IME nonconvert + KEY_ACCEPT = 0x1E, // IME accept + KEY_MODECHANGE = 0x1F, // IME mode change request + KEY_SPACE = 0x20, // SPACEBAR + KEY_PRIOR = 0x21, // PAGE UP key + KEY_NEXT = 0x22, // PAGE DOWN key + KEY_END = 0x23, // END key + KEY_HOME = 0x24, // HOME key + KEY_LEFT = 0x25, // LEFT ARROW key + KEY_UP = 0x26, // UP ARROW key + KEY_RIGHT = 0x27, // RIGHT ARROW key + KEY_DOWN = 0x28, // DOWN ARROW key + KEY_SELECT = 0x29, // SELECT key + KEY_PRINT = 0x2A, // PRINT key + KEY_EXECUT = 0x2B, // EXECUTE key + KEY_SNAPSHOT = 0x2C, // PRINT SCREEN key + KEY_INSERT = 0x2D, // INS key + KEY_DELETE = 0x2E, // DEL key + KEY_HELP = 0x2F, // HELP key + KEY_KEY_0 = 0x30, // 0 key + KEY_KEY_1 = 0x31, // 1 key + KEY_KEY_2 = 0x32, // 2 key + KEY_KEY_3 = 0x33, // 3 key + KEY_KEY_4 = 0x34, // 4 key + KEY_KEY_5 = 0x35, // 5 key + KEY_KEY_6 = 0x36, // 6 key + KEY_KEY_7 = 0x37, // 7 key + KEY_KEY_8 = 0x38, // 8 key + KEY_KEY_9 = 0x39, // 9 key + KEY_KEY_A = 0x41, // A key + KEY_KEY_B = 0x42, // B key + KEY_KEY_C = 0x43, // C key + KEY_KEY_D = 0x44, // D key + KEY_KEY_E = 0x45, // E key + KEY_KEY_F = 0x46, // F key + KEY_KEY_G = 0x47, // G key + KEY_KEY_H = 0x48, // H key + KEY_KEY_I = 0x49, // I key + KEY_KEY_J = 0x4A, // J key + KEY_KEY_K = 0x4B, // K key + KEY_KEY_L = 0x4C, // L key + KEY_KEY_M = 0x4D, // M key + KEY_KEY_N = 0x4E, // N key + KEY_KEY_O = 0x4F, // O key + KEY_KEY_P = 0x50, // P key + KEY_KEY_Q = 0x51, // Q key + KEY_KEY_R = 0x52, // R key + KEY_KEY_S = 0x53, // S key + KEY_KEY_T = 0x54, // T key + KEY_KEY_U = 0x55, // U key + KEY_KEY_V = 0x56, // V key + KEY_KEY_W = 0x57, // W key + KEY_KEY_X = 0x58, // X key + KEY_KEY_Y = 0x59, // Y key + KEY_KEY_Z = 0x5A, // Z key + KEY_LWIN = 0x5B, // Left Windows key (Microsoft Natural keyboard) + KEY_RWIN = 0x5C, // Right Windows key (Natural keyboard) + KEY_APPS = 0x5D, // Applications key (Natural keyboard) + KEY_SLEEP = 0x5F, // Computer Sleep key + KEY_NUMPAD0 = 0x60, // Numeric keypad 0 key + KEY_NUMPAD1 = 0x61, // Numeric keypad 1 key + KEY_NUMPAD2 = 0x62, // Numeric keypad 2 key + KEY_NUMPAD3 = 0x63, // Numeric keypad 3 key + KEY_NUMPAD4 = 0x64, // Numeric keypad 4 key + KEY_NUMPAD5 = 0x65, // Numeric keypad 5 key + KEY_NUMPAD6 = 0x66, // Numeric keypad 6 key + KEY_NUMPAD7 = 0x67, // Numeric keypad 7 key + KEY_NUMPAD8 = 0x68, // Numeric keypad 8 key + KEY_NUMPAD9 = 0x69, // Numeric keypad 9 key + KEY_MULTIPLY = 0x6A, // Multiply key + KEY_ADD = 0x6B, // Add key + KEY_SEPARATOR = 0x6C, // Separator key + KEY_SUBTRACT = 0x6D, // Subtract key + KEY_DECIMAL = 0x6E, // Decimal key + KEY_DIVIDE = 0x6F, // Divide key + KEY_F1 = 0x70, // F1 key + KEY_F2 = 0x71, // F2 key + KEY_F3 = 0x72, // F3 key + KEY_F4 = 0x73, // F4 key + KEY_F5 = 0x74, // F5 key + KEY_F6 = 0x75, // F6 key + KEY_F7 = 0x76, // F7 key + KEY_F8 = 0x77, // F8 key + KEY_F9 = 0x78, // F9 key + KEY_F10 = 0x79, // F10 key + KEY_F11 = 0x7A, // F11 key + KEY_F12 = 0x7B, // F12 key + KEY_F13 = 0x7C, // F13 key + KEY_F14 = 0x7D, // F14 key + KEY_F15 = 0x7E, // F15 key + KEY_F16 = 0x7F, // F16 key + KEY_F17 = 0x80, // F17 key + KEY_F18 = 0x81, // F18 key + KEY_F19 = 0x82, // F19 key + KEY_F20 = 0x83, // F20 key + KEY_F21 = 0x84, // F21 key + KEY_F22 = 0x85, // F22 key + KEY_F23 = 0x86, // F23 key + KEY_F24 = 0x87, // F24 key + KEY_NUMLOCK = 0x90, // NUM LOCK key + KEY_SCROLL = 0x91, // SCROLL LOCK key + KEY_LSHIFT = 0xA0, // Left SHIFT key + KEY_RSHIFT = 0xA1, // Right SHIFT key + KEY_LCONTROL = 0xA2, // Left CONTROL key + KEY_RCONTROL = 0xA3, // Right CONTROL key + KEY_LMENU = 0xA4, // Left MENU key + KEY_RMENU = 0xA5, // Right MENU key + KEY_BROWSER_BACK = 0xA6, // Browser Back key + KEY_BROWSER_FORWARD = 0xA7, // Browser Forward key + KEY_BROWSER_REFRESH = 0xA8, // Browser Refresh key + KEY_BROWSER_STOP = 0xA9, // Browser Stop key + KEY_BROWSER_SEARCH = 0xAA, // Browser Search key + KEY_BROWSER_FAVORITES =0xAB, // Browser Favorites key + KEY_BROWSER_HOME = 0xAC, // Browser Start and Home key + KEY_VOLUME_MUTE = 0xAD, // Volume Mute key + KEY_VOLUME_DOWN = 0xAE, // Volume Down key + KEY_VOLUME_UP = 0xAF, // Volume Up key + KEY_MEDIA_NEXT_TRACK = 0xB0, // Next Track key + KEY_MEDIA_PREV_TRACK = 0xB1, // Previous Track key + KEY_MEDIA_STOP = 0xB2, // Stop Media key + KEY_MEDIA_PLAY_PAUSE = 0xB3, // Play/Pause Media key + KEY_OEM_1 = 0xBA, // for US ";:" + KEY_PLUS = 0xBB, // Plus Key "+" + KEY_COMMA = 0xBC, // Comma Key "," + KEY_MINUS = 0xBD, // Minus Key "-" + KEY_PERIOD = 0xBE, // Period Key "." + KEY_OEM_2 = 0xBF, // for US "/?" + KEY_OEM_3 = 0xC0, // for US "`~" + KEY_OEM_4 = 0xDB, // for US "[{" + KEY_OEM_5 = 0xDC, // for US "\|" + KEY_OEM_6 = 0xDD, // for US "]}" + KEY_OEM_7 = 0xDE, // for US "'"" + KEY_OEM_8 = 0xDF, // None + KEY_OEM_AX = 0xE1, // for Japan "AX" + KEY_OEM_102 = 0xE2, // "<>" or "\|" + KEY_ATTN = 0xF6, // Attn key + KEY_CRSEL = 0xF7, // CrSel key + KEY_EXSEL = 0xF8, // ExSel key + KEY_EREOF = 0xF9, // Erase EOF key + KEY_PLAY = 0xFA, // Play key + KEY_ZOOM = 0xFB, // Zoom key + KEY_PA1 = 0xFD, // PA1 key + KEY_OEM_CLEAR = 0xFE, // Clear key + KEY_NONE = 0xFF, // usually no key mapping, but some laptops use it for fn key + + KEY_KEY_CODES_COUNT = 0x100 // this is not a key, but the amount of keycodes there are. + }; + +} // end namespace irr + +#endif + diff --git a/include/S3DVertex.h b/include/S3DVertex.h new file mode 100644 index 00000000..2040f9d1 --- /dev/null +++ b/include/S3DVertex.h @@ -0,0 +1,281 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __S_3D_VERTEX_H_INCLUDED__ +#define __S_3D_VERTEX_H_INCLUDED__ + +#include "vector3d.h" +#include "vector2d.h" +#include "SColor.h" + +namespace irr +{ +namespace video +{ + +//! Enumeration for all vertex types there are. +enum E_VERTEX_TYPE +{ + //! Standard vertex type used by the Irrlicht engine, video::S3DVertex. + EVT_STANDARD = 0, + + //! Vertex with two texture coordinates, video::S3DVertex2TCoords. + /** Usually used for geometry with lightmaps or other special materials. */ + EVT_2TCOORDS, + + //! Vertex with a tangent and binormal vector, video::S3DVertexTangents. + /** Usually used for tangent space normal mapping. + Usually tangent and binormal get send to shaders as texture coordinate sets 1 and 2. + */ + EVT_TANGENTS +}; + +//! Array holding the built in vertex type names +const char* const sBuiltInVertexTypeNames[] = +{ + "standard", + "2tcoords", + "tangents", + 0 +}; + +//! standard vertex used by the Irrlicht engine. +struct S3DVertex +{ + //! default constructor + S3DVertex() {} + + //! constructor + S3DVertex(f32 x, f32 y, f32 z, f32 nx, f32 ny, f32 nz, SColor c, f32 tu, f32 tv) + : Pos(x,y,z), Normal(nx,ny,nz), Color(c), TCoords(tu,tv) {} + + //! constructor + S3DVertex(const core::vector3df& pos, const core::vector3df& normal, + SColor color, const core::vector2d& tcoords) + : Pos(pos), Normal(normal), Color(color), TCoords(tcoords) {} + + //! Position + core::vector3df Pos; + + //! Normal vector + core::vector3df Normal; + + //! Color + SColor Color; + + //! Texture coordinates + core::vector2d TCoords; + + bool operator==(const S3DVertex& other) const + { + return ((Pos == other.Pos) && (Normal == other.Normal) && + (Color == other.Color) && (TCoords == other.TCoords)); + } + + bool operator!=(const S3DVertex& other) const + { + return ((Pos != other.Pos) || (Normal != other.Normal) || + (Color != other.Color) || (TCoords != other.TCoords)); + } + + bool operator<(const S3DVertex& other) const + { + return ((Pos < other.Pos) || + ((Pos == other.Pos) && (Normal < other.Normal)) || + ((Pos == other.Pos) && (Normal == other.Normal) && (Color < other.Color)) || + ((Pos == other.Pos) && (Normal == other.Normal) && (Color == other.Color) && (TCoords < other.TCoords))); + } + + //! Get type of the class + static E_VERTEX_TYPE getType() + { + return EVT_STANDARD; + } + + //\param d d=0 returns other, d=1 returns this, values between interpolate. + S3DVertex getInterpolated(const S3DVertex& other, f32 d) + { + d = core::clamp(d, 0.0f, 1.0f); + return S3DVertex(Pos.getInterpolated(other.Pos, d), + Normal.getInterpolated(other.Normal, d), + Color.getInterpolated(other.Color, d), + TCoords.getInterpolated(other.TCoords, d)); + } +}; + + +//! Vertex with two texture coordinates. +/** Usually used for geometry with lightmaps +or other special materials. +*/ +struct S3DVertex2TCoords : public S3DVertex +{ + //! default constructor + S3DVertex2TCoords() : S3DVertex() {} + + //! constructor with two different texture coords, but no normal + S3DVertex2TCoords(f32 x, f32 y, f32 z, SColor c, f32 tu, f32 tv, f32 tu2, f32 tv2) + : S3DVertex(x,y,z, 0.0f, 0.0f, 0.0f, c, tu,tv), TCoords2(tu2,tv2) {} + + //! constructor with two different texture coords, but no normal + S3DVertex2TCoords(const core::vector3df& pos, SColor color, + const core::vector2d& tcoords, const core::vector2d& tcoords2) + : S3DVertex(pos, core::vector3df(), color, tcoords), TCoords2(tcoords2) {} + + //! constructor with all values + S3DVertex2TCoords(const core::vector3df& pos, const core::vector3df& normal, const SColor& color, + const core::vector2d& tcoords, const core::vector2d& tcoords2) + : S3DVertex(pos, normal, color, tcoords), TCoords2(tcoords2) {} + + //! constructor with all values + S3DVertex2TCoords(f32 x, f32 y, f32 z, f32 nx, f32 ny, f32 nz, SColor c, f32 tu, f32 tv, f32 tu2, f32 tv2) + : S3DVertex(x,y,z, nx,ny,nz, c, tu,tv), TCoords2(tu2,tv2) {} + + //! constructor with the same texture coords and normal + S3DVertex2TCoords(f32 x, f32 y, f32 z, f32 nx, f32 ny, f32 nz, SColor c, f32 tu, f32 tv) + : S3DVertex(x,y,z, nx,ny,nz, c, tu,tv), TCoords2(tu,tv) {} + + //! constructor with the same texture coords and normal + S3DVertex2TCoords(const core::vector3df& pos, const core::vector3df& normal, + SColor color, const core::vector2d& tcoords) + : S3DVertex(pos, normal, color, tcoords), TCoords2(tcoords) {} + + //! constructor from S3DVertex + S3DVertex2TCoords(S3DVertex& o) : S3DVertex(o) {} + + //! Second set of texture coordinates + core::vector2d TCoords2; + + //! Equality operator + bool operator==(const S3DVertex2TCoords& other) const + { + return ((static_cast(*this)==other) && + (TCoords2 == other.TCoords2)); + } + + //! Inequality operator + bool operator!=(const S3DVertex2TCoords& other) const + { + return ((static_cast(*this)!=other) || + (TCoords2 != other.TCoords2)); + } + + bool operator<(const S3DVertex2TCoords& other) const + { + return ((static_cast(*this) < other) || + ((static_cast(*this) == other) && (TCoords2 < other.TCoords2))); + } + + static E_VERTEX_TYPE getType() + { + return EVT_2TCOORDS; + } + + //\param d d=0 returns other, d=1 returns this, values between interpolate. + S3DVertex2TCoords getInterpolated(const S3DVertex2TCoords& other, f32 d) + { + d = core::clamp(d, 0.0f, 1.0f); + return S3DVertex2TCoords(Pos.getInterpolated(other.Pos, d), + Normal.getInterpolated(other.Normal, d), + Color.getInterpolated(other.Color, d), + TCoords.getInterpolated(other.TCoords, d), + TCoords2.getInterpolated(other.TCoords2, d)); + } +}; + + +//! Vertex with a tangent and binormal vector. +/** Usually used for tangent space normal mapping. + Usually tangent and binormal get send to shaders as texture coordinate sets 1 and 2. +*/ +struct S3DVertexTangents : public S3DVertex +{ + //! default constructor + S3DVertexTangents() : S3DVertex() { } + + //! constructor + S3DVertexTangents(f32 x, f32 y, f32 z, f32 nx=0.0f, f32 ny=0.0f, f32 nz=0.0f, + SColor c = 0xFFFFFFFF, f32 tu=0.0f, f32 tv=0.0f, + f32 tanx=0.0f, f32 tany=0.0f, f32 tanz=0.0f, + f32 bx=0.0f, f32 by=0.0f, f32 bz=0.0f) + : S3DVertex(x,y,z, nx,ny,nz, c, tu,tv), Tangent(tanx,tany,tanz), Binormal(bx,by,bz) { } + + //! constructor + S3DVertexTangents(const core::vector3df& pos, SColor c, + const core::vector2df& tcoords) + : S3DVertex(pos, core::vector3df(), c, tcoords) { } + + //! constructor + S3DVertexTangents(const core::vector3df& pos, + const core::vector3df& normal, SColor c, + const core::vector2df& tcoords, + const core::vector3df& tangent=core::vector3df(), + const core::vector3df& binormal=core::vector3df()) + : S3DVertex(pos, normal, c, tcoords), Tangent(tangent), Binormal(binormal) { } + + //! Tangent vector along the x-axis of the texture + core::vector3df Tangent; + + //! Binormal vector (tangent x normal) + core::vector3df Binormal; + + bool operator==(const S3DVertexTangents& other) const + { + return ((static_cast(*this)==other) && + (Tangent == other.Tangent) && + (Binormal == other.Binormal)); + } + + bool operator!=(const S3DVertexTangents& other) const + { + return ((static_cast(*this)!=other) || + (Tangent != other.Tangent) || + (Binormal != other.Binormal)); + } + + bool operator<(const S3DVertexTangents& other) const + { + return ((static_cast(*this) < other) || + ((static_cast(*this) == other) && (Tangent < other.Tangent)) || + ((static_cast(*this) == other) && (Tangent == other.Tangent) && (Binormal < other.Binormal))); + } + + static E_VERTEX_TYPE getType() + { + return EVT_TANGENTS; + } + + S3DVertexTangents getInterpolated(const S3DVertexTangents& other, f32 d) + { + d = core::clamp(d, 0.0f, 1.0f); + return S3DVertexTangents(Pos.getInterpolated(other.Pos, d), + Normal.getInterpolated(other.Normal, d), + Color.getInterpolated(other.Color, d), + TCoords.getInterpolated(other.TCoords, d), + Tangent.getInterpolated(other.Tangent, d), + Binormal.getInterpolated(other.Binormal, d)); + } +}; + + + +inline u32 getVertexPitchFromType(E_VERTEX_TYPE vertexType) +{ + switch (vertexType) + { + case video::EVT_2TCOORDS: + return sizeof(video::S3DVertex2TCoords); + case video::EVT_TANGENTS: + return sizeof(video::S3DVertexTangents); + default: + return sizeof(video::S3DVertex); + } +} + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/include/SAnimatedMesh.h b/include/SAnimatedMesh.h new file mode 100644 index 00000000..45a4d486 --- /dev/null +++ b/include/SAnimatedMesh.h @@ -0,0 +1,189 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __S_ANIMATED_MESH_H_INCLUDED__ +#define __S_ANIMATED_MESH_H_INCLUDED__ + +#include "IAnimatedMesh.h" +#include "IMesh.h" +#include "aabbox3d.h" +#include "irrArray.h" + +namespace irr +{ +namespace scene +{ + + //! Simple implementation of the IAnimatedMesh interface. + struct SAnimatedMesh : public IAnimatedMesh + { + //! constructor + SAnimatedMesh(scene::IMesh* mesh=0, scene::E_ANIMATED_MESH_TYPE type=scene::EAMT_UNKNOWN) : IAnimatedMesh(), FramesPerSecond(25.f), Type(type) + { + #ifdef _DEBUG + setDebugName("SAnimatedMesh"); + #endif + addMesh(mesh); + recalculateBoundingBox(); + } + + //! destructor + virtual ~SAnimatedMesh() + { + // drop meshes + for (u32 i=0; idrop(); + } + + //! Gets the frame count of the animated mesh. + /** \return Amount of frames. If the amount is 1, it is a static, non animated mesh. */ + virtual u32 getFrameCount() const _IRR_OVERRIDE_ + { + return Meshes.size(); + } + + //! Gets the default animation speed of the animated mesh. + /** \return Amount of frames per second. If the amount is 0, it is a static, non animated mesh. */ + virtual f32 getAnimationSpeed() const _IRR_OVERRIDE_ + { + return FramesPerSecond; + } + + //! Gets the frame count of the animated mesh. + /** \param fps Frames per second to play the animation with. If the amount is 0, it is not animated. + The actual speed is set in the scene node the mesh is instantiated in.*/ + virtual void setAnimationSpeed(f32 fps) _IRR_OVERRIDE_ + { + FramesPerSecond=fps; + } + + //! Returns the IMesh interface for a frame. + /** \param frame: Frame number as zero based index. The maximum frame number is + getFrameCount() - 1; + \param detailLevel: Level of detail. 0 is the lowest, + 255 the highest level of detail. Most meshes will ignore the detail level. + \param startFrameLoop: start frame + \param endFrameLoop: end frame + \return The animated mesh based on a detail level. */ + virtual IMesh* getMesh(s32 frame, s32 detailLevel=255, s32 startFrameLoop=-1, s32 endFrameLoop=-1) _IRR_OVERRIDE_ + { + if (Meshes.empty()) + return 0; + + return Meshes[frame]; + } + + //! adds a Mesh + void addMesh(IMesh* mesh) + { + if (mesh) + { + mesh->grab(); + Meshes.push_back(mesh); + } + } + + //! Returns an axis aligned bounding box of the mesh. + /** \return A bounding box of this mesh is returned. */ + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_ + { + return Box; + } + + //! set user axis aligned bounding box + virtual void setBoundingBox(const core::aabbox3df& box) _IRR_OVERRIDE_ + { + Box = box; + } + + //! Recalculates the bounding box. + void recalculateBoundingBox() + { + Box.reset(0,0,0); + + if (Meshes.empty()) + return; + + Box = Meshes[0]->getBoundingBox(); + + for (u32 i=1; igetBoundingBox()); + } + + //! Returns the type of the animated mesh. + virtual E_ANIMATED_MESH_TYPE getMeshType() const _IRR_OVERRIDE_ + { + return Type; + } + + //! returns amount of mesh buffers. + virtual u32 getMeshBufferCount() const _IRR_OVERRIDE_ + { + if (Meshes.empty()) + return 0; + + return Meshes[0]->getMeshBufferCount(); + } + + //! returns pointer to a mesh buffer + virtual IMeshBuffer* getMeshBuffer(u32 nr) const _IRR_OVERRIDE_ + { + if (Meshes.empty()) + return 0; + + return Meshes[0]->getMeshBuffer(nr); + } + + //! Returns pointer to a mesh buffer which fits a material + /** \param material: material to search for + \return Returns the pointer to the mesh buffer or + NULL if there is no such mesh buffer. */ + virtual IMeshBuffer* getMeshBuffer( const video::SMaterial &material) const _IRR_OVERRIDE_ + { + if (Meshes.empty()) + return 0; + + return Meshes[0]->getMeshBuffer(material); + } + + //! Set a material flag for all meshbuffers of this mesh. + virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) _IRR_OVERRIDE_ + { + for (u32 i=0; isetMaterialFlag(flag, newvalue); + } + + //! set the hardware mapping hint, for driver + virtual void setHardwareMappingHint( E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX ) _IRR_OVERRIDE_ + { + for (u32 i=0; isetHardwareMappingHint(newMappingHint, buffer); + } + + //! flags the meshbuffer as changed, reloads hardware buffers + virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_ + { + for (u32 i=0; isetDirty(buffer); + } + + //! All meshes defining the animated mesh + core::array Meshes; + + //! The bounding box of this mesh + core::aabbox3d Box; + + //! Default animation speed of this mesh. + f32 FramesPerSecond; + + //! The type of the mesh. + E_ANIMATED_MESH_TYPE Type; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/SColor.h b/include/SColor.h new file mode 100644 index 00000000..7384da9b --- /dev/null +++ b/include/SColor.h @@ -0,0 +1,812 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __COLOR_H_INCLUDED__ +#define __COLOR_H_INCLUDED__ + +#include "irrTypes.h" +#include "irrMath.h" + +namespace irr +{ +namespace video +{ + //! An enum for the color format of textures used by the Irrlicht Engine. + /** A color format specifies how color information is stored. + NOTE: Byte order in memory is usually flipped (it's probably correct in bitmap files, but flipped on reading). + So for example ECF_A8R8G8B8 is BGRA in memory same as in DX9's D3DFMT_A8R8G8B8 format. + */ + enum ECOLOR_FORMAT + { + //! 16 bit color format used by the software driver. + /** It is thus preferred by all other irrlicht engine video drivers. + There are 5 bits for every color component, and a single bit is left + for alpha information. */ + ECF_A1R5G5B5 = 0, + + //! Standard 16 bit color format. + ECF_R5G6B5, + + //! 24 bit color, no alpha channel, but 8 bit for red, green and blue. + //! Warning: 24 bit formats tend to be badly supported. Depending on driver it's usually converted to another + // format or even not working at all. It's mostly better to use 16-bit or 32-bit formats. + ECF_R8G8B8, + + //! Default 32 bit color format. 8 bits are used for every component: red, green, blue and alpha. + //! Warning: This tends to be BGRA in memory (it's ARGB on file, but with usual big-endian memory it's flipped) + ECF_A8R8G8B8, + + /** Compressed image formats. **/ + + //! DXT1 color format. + ECF_DXT1, + + //! DXT2 color format. + ECF_DXT2, + + //! DXT3 color format. + ECF_DXT3, + + //! DXT4 color format. + ECF_DXT4, + + //! DXT5 color format. + ECF_DXT5, + + //! PVRTC RGB 2bpp. + ECF_PVRTC_RGB2, + + //! PVRTC ARGB 2bpp. + ECF_PVRTC_ARGB2, + + //! PVRTC RGB 4bpp. + ECF_PVRTC_RGB4, + + //! PVRTC ARGB 4bpp. + ECF_PVRTC_ARGB4, + + //! PVRTC2 ARGB 2bpp. + ECF_PVRTC2_ARGB2, + + //! PVRTC2 ARGB 4bpp. + ECF_PVRTC2_ARGB4, + + //! ETC1 RGB. + ECF_ETC1, + + //! ETC2 RGB. + ECF_ETC2_RGB, + + //! ETC2 ARGB. + ECF_ETC2_ARGB, + + /** The following formats may only be used for render target textures. */ + + /** Floating point formats. */ + + //! 16 bit format using 16 bits for the red channel. + ECF_R16F, + + //! 32 bit format using 16 bits for the red and green channels. + ECF_G16R16F, + + //! 64 bit format using 16 bits for the red, green, blue and alpha channels. + ECF_A16B16G16R16F, + + //! 32 bit format using 32 bits for the red channel. + ECF_R32F, + + //! 64 bit format using 32 bits for the red and green channels. + ECF_G32R32F, + + //! 128 bit format using 32 bits for the red, green, blue and alpha channels. + ECF_A32B32G32R32F, + + /** Unsigned normalized integer formats. */ + + //! 8 bit format using 8 bits for the red channel. + ECF_R8, + + //! 16 bit format using 8 bits for the red and green channels. + ECF_R8G8, + + //! 16 bit format using 16 bits for the red channel. + ECF_R16, + + //! 32 bit format using 16 bits for the red and green channels. + ECF_R16G16, + + /** Depth and stencil formats. */ + + //! 16 bit format using 16 bits for depth. + ECF_D16, + + //! 32 bit format using 32 bits for depth. + ECF_D32, + + //! 32 bit format using 24 bits for depth and 8 bits for stencil. + ECF_D24S8, + + //! Unknown color format: + ECF_UNKNOWN + }; + + //! Names for ECOLOR_FORMAT types + const c8* const ColorFormatNames[ECF_UNKNOWN+2] = + { + "A1R5G5B5", + "R5G6B5", + "R8G8B8", + "A8R8G8B8", + "DXT1", + "DXT2", + "DXT3", + "DXT4", + "DXT5", + "PVRTC_RGB2", + "PVRTC_ARGB2", + "PVRTC_RGB4", + "PVRTC_ARGB4", + "PVRTC2_ARGB2", + "PVRTC2_ARGB4", + "ETC1", + "ETC2_RGB", + "ETC2_ARGB", + "R16F", + "G16R16F", + "A16B16G16R16F", + "R32F", + "G32R32F", + "A32B32G32R32F", + "R8", + "R8G8", + "R16", + "R16G16", + "D16", + "D32", + "D24S8", + "UNKNOWN", + 0 + }; + + + //! Creates a 16 bit A1R5G5B5 color + inline u16 RGBA16(u32 r, u32 g, u32 b, u32 a=0xFF) + { + return (u16)((a & 0x80) << 8 | + (r & 0xF8) << 7 | + (g & 0xF8) << 2 | + (b & 0xF8) >> 3); + } + + + //! Creates a 16 bit A1R5G5B5 color + inline u16 RGB16(u32 r, u32 g, u32 b) + { + return RGBA16(r,g,b); + } + + + //! Creates a 16bit A1R5G5B5 color, based on 16bit input values + inline u16 RGB16from16(u16 r, u16 g, u16 b) + { + return (0x8000 | + (r & 0x1F) << 10 | + (g & 0x1F) << 5 | + (b & 0x1F)); + } + + + //! Converts a 32bit (X8R8G8B8) color to a 16bit A1R5G5B5 color + inline u16 X8R8G8B8toA1R5G5B5(u32 color) + { + return (u16)(0x8000 | + ( color & 0x00F80000) >> 9 | + ( color & 0x0000F800) >> 6 | + ( color & 0x000000F8) >> 3); + } + + + //! Converts a 32bit (A8R8G8B8) color to a 16bit A1R5G5B5 color + inline u16 A8R8G8B8toA1R5G5B5(u32 color) + { + return (u16)(( color & 0x80000000) >> 16| + ( color & 0x00F80000) >> 9 | + ( color & 0x0000F800) >> 6 | + ( color & 0x000000F8) >> 3); + } + + + //! Converts a 32bit (A8R8G8B8) color to a 16bit R5G6B5 color + inline u16 A8R8G8B8toR5G6B5(u32 color) + { + return (u16)(( color & 0x00F80000) >> 8 | + ( color & 0x0000FC00) >> 5 | + ( color & 0x000000F8) >> 3); + } + + + //! Convert A8R8G8B8 Color from A1R5G5B5 color + /** build a nicer 32bit Color by extending dest lower bits with source high bits. */ + inline u32 A1R5G5B5toA8R8G8B8(u16 color) + { + return ( (( -( (s32) color & 0x00008000 ) >> (s32) 31 ) & 0xFF000000 ) | + (( color & 0x00007C00 ) << 9) | (( color & 0x00007000 ) << 4) | + (( color & 0x000003E0 ) << 6) | (( color & 0x00000380 ) << 1) | + (( color & 0x0000001F ) << 3) | (( color & 0x0000001C ) >> 2) + ); + } + + + //! Returns A8R8G8B8 Color from R5G6B5 color + inline u32 R5G6B5toA8R8G8B8(u16 color) + { + return 0xFF000000 | + ((color & 0xF800) << 8)| + ((color & 0x07E0) << 5)| + ((color & 0x001F) << 3); + } + + + //! Returns A1R5G5B5 Color from R5G6B5 color + inline u16 R5G6B5toA1R5G5B5(u16 color) + { + return 0x8000 | (((color & 0xFFC0) >> 1) | (color & 0x1F)); + } + + + //! Returns R5G6B5 Color from A1R5G5B5 color + inline u16 A1R5G5B5toR5G6B5(u16 color) + { + return (((color & 0x7FE0) << 1) | (color & 0x1F)); + } + + + + //! Returns the alpha component from A1R5G5B5 color + /** In Irrlicht, alpha refers to opacity. + \return The alpha value of the color. 0 is transparent, 1 is opaque. */ + inline u32 getAlpha(u16 color) + { + return ((color >> 15)&0x1); + } + + + //! Returns the red component from A1R5G5B5 color. + /** Shift left by 3 to get 8 bit value. */ + inline u32 getRed(u16 color) + { + return ((color >> 10)&0x1F); + } + + + //! Returns the green component from A1R5G5B5 color + /** Shift left by 3 to get 8 bit value. */ + inline u32 getGreen(u16 color) + { + return ((color >> 5)&0x1F); + } + + + //! Returns the blue component from A1R5G5B5 color + /** Shift left by 3 to get 8 bit value. */ + inline u32 getBlue(u16 color) + { + return (color & 0x1F); + } + + + //! Returns the average from a 16 bit A1R5G5B5 color + inline s32 getAverage(s16 color) + { + return ((getRed(color)<<3) + (getGreen(color)<<3) + (getBlue(color)<<3)) / 3; + } + + + //! Class representing a 32 bit ARGB color. + /** The color values for alpha, red, green, and blue are + stored in a single u32. So all four values may be between 0 and 255. + Alpha in Irrlicht is opacity, so 0 is fully transparent, 255 is fully opaque (solid). + This class is used by most parts of the Irrlicht Engine + to specify a color. Another way is using the class SColorf, which + stores the color values in 4 floats. + This class must consist of only one u32 and must not use virtual functions. + */ + class SColor + { + public: + + //! Constructor of the Color. Does nothing. + /** The color value is not initialized to save time. */ + SColor() {} + + //! Constructs the color from 4 values representing the alpha, red, green and blue component. + /** Must be values between 0 and 255. */ + SColor (u32 a, u32 r, u32 g, u32 b) + : color(((a & 0xff)<<24) | ((r & 0xff)<<16) | ((g & 0xff)<<8) | (b & 0xff)) {} + + //! Constructs the color from a 32 bit value. Could be another color. + SColor(u32 clr) + : color(clr) {} + + //! Returns the alpha component of the color. + /** The alpha component defines how opaque a color is. + \return The alpha value of the color. 0 is fully transparent, 255 is fully opaque. */ + u32 getAlpha() const { return color>>24; } + + //! Returns the red component of the color. + /** \return Value between 0 and 255, specifying how red the color is. + 0 means no red, 255 means full red. */ + u32 getRed() const { return (color>>16) & 0xff; } + + //! Returns the green component of the color. + /** \return Value between 0 and 255, specifying how green the color is. + 0 means no green, 255 means full green. */ + u32 getGreen() const { return (color>>8) & 0xff; } + + //! Returns the blue component of the color. + /** \return Value between 0 and 255, specifying how blue the color is. + 0 means no blue, 255 means full blue. */ + u32 getBlue() const { return color & 0xff; } + + //! Get lightness of the color in the range [0,255] + f32 getLightness() const + { + return 0.5f*(core::max_(core::max_(getRed(),getGreen()),getBlue())+core::min_(core::min_(getRed(),getGreen()),getBlue())); + } + + //! Get luminance of the color in the range [0,255]. + f32 getLuminance() const + { + return 0.3f*getRed() + 0.59f*getGreen() + 0.11f*getBlue(); + } + + //! Get average intensity of the color in the range [0,255]. + u32 getAverage() const + { + return ( getRed() + getGreen() + getBlue() ) / 3; + } + + //! Sets the alpha component of the Color. + /** The alpha component defines how transparent a color should be. + \param a The alpha value of the color. 0 is fully transparent, 255 is fully opaque. */ + void setAlpha(u32 a) { color = ((a & 0xff)<<24) | (color & 0x00ffffff); } + + //! Sets the red component of the Color. + /** \param r: Has to be a value between 0 and 255. + 0 means no red, 255 means full red. */ + void setRed(u32 r) { color = ((r & 0xff)<<16) | (color & 0xff00ffff); } + + //! Sets the green component of the Color. + /** \param g: Has to be a value between 0 and 255. + 0 means no green, 255 means full green. */ + void setGreen(u32 g) { color = ((g & 0xff)<<8) | (color & 0xffff00ff); } + + //! Sets the blue component of the Color. + /** \param b: Has to be a value between 0 and 255. + 0 means no blue, 255 means full blue. */ + void setBlue(u32 b) { color = (b & 0xff) | (color & 0xffffff00); } + + //! Calculates a 16 bit A1R5G5B5 value of this color. + /** \return 16 bit A1R5G5B5 value of this color. */ + u16 toA1R5G5B5() const { return A8R8G8B8toA1R5G5B5(color); } + + //! Converts color to OpenGL color format + /** From ARGB to RGBA in 4 byte components for endian aware + passing to OpenGL + \param dest: address where the 4x8 bit OpenGL color is stored. */ + void toOpenGLColor(u8* dest) const + { + *dest = (u8)getRed(); + *++dest = (u8)getGreen(); + *++dest = (u8)getBlue(); + *++dest = (u8)getAlpha(); + } + + //! Sets all four components of the color at once. + /** Constructs the color from 4 values representing the alpha, + red, green and blue components of the color. Must be values + between 0 and 255. + \param a: Alpha component of the color. The alpha component + defines how transparent a color should be. Has to be a value + between 0 and 255. 255 means not transparent (opaque), 0 means + fully transparent. + \param r: Sets the red component of the Color. Has to be a + value between 0 and 255. 0 means no red, 255 means full red. + \param g: Sets the green component of the Color. Has to be a + value between 0 and 255. 0 means no green, 255 means full + green. + \param b: Sets the blue component of the Color. Has to be a + value between 0 and 255. 0 means no blue, 255 means full blue. */ + void set(u32 a, u32 r, u32 g, u32 b) + { + color = (((a & 0xff)<<24) | ((r & 0xff)<<16) | ((g & 0xff)<<8) | (b & 0xff)); + } + void set(u32 col) { color = col; } + + //! Compares the color to another color. + /** \return True if the colors are the same, and false if not. */ + bool operator==(const SColor& other) const { return other.color == color; } + + //! Compares the color to another color. + /** \return True if the colors are different, and false if they are the same. */ + bool operator!=(const SColor& other) const { return other.color != color; } + + //! comparison operator + /** \return True if this color is smaller than the other one */ + bool operator<(const SColor& other) const { return (color < other.color); } + + //! Adds two colors, result is clamped to 0..255 values + /** \param other Color to add to this color + \return Addition of the two colors, clamped to 0..255 values */ + SColor operator+(const SColor& other) const + { + return SColor(core::min_(getAlpha() + other.getAlpha(), 255u), + core::min_(getRed() + other.getRed(), 255u), + core::min_(getGreen() + other.getGreen(), 255u), + core::min_(getBlue() + other.getBlue(), 255u)); + } + + //! Interpolates the color with a f32 value to another color + /** \param other: Other color + \param d: value between 0.0f and 1.0f. d=0 returns other, d=1 returns this, values between interpolate. + \return Interpolated color. */ + SColor getInterpolated(const SColor &other, f32 d) const + { + d = core::clamp(d, 0.f, 1.f); + const f32 inv = 1.0f - d; + return SColor((u32)core::round32(other.getAlpha()*inv + getAlpha()*d), + (u32)core::round32(other.getRed()*inv + getRed()*d), + (u32)core::round32(other.getGreen()*inv + getGreen()*d), + (u32)core::round32(other.getBlue()*inv + getBlue()*d)); + } + + //! Returns interpolated color. ( quadratic ) + /** \param c1: first color to interpolate with + \param c2: second color to interpolate with + \param d: value between 0.0f and 1.0f. */ + SColor getInterpolated_quadratic(const SColor& c1, const SColor& c2, f32 d) const + { + // this*(1-d)*(1-d) + 2 * c1 * (1-d) + c2 * d * d; + d = core::clamp(d, 0.f, 1.f); + const f32 inv = 1.f - d; + const f32 mul0 = inv * inv; + const f32 mul1 = 2.f * d * inv; + const f32 mul2 = d * d; + + return SColor( + core::clamp( core::floor32( + getAlpha() * mul0 + c1.getAlpha() * mul1 + c2.getAlpha() * mul2 ), 0, 255 ), + core::clamp( core::floor32( + getRed() * mul0 + c1.getRed() * mul1 + c2.getRed() * mul2 ), 0, 255 ), + core::clamp ( core::floor32( + getGreen() * mul0 + c1.getGreen() * mul1 + c2.getGreen() * mul2 ), 0, 255 ), + core::clamp ( core::floor32( + getBlue() * mul0 + c1.getBlue() * mul1 + c2.getBlue() * mul2 ), 0, 255 )); + } + + //! set the color by expecting data in the given format + /** \param data: must point to valid memory containing color information in the given format + \param format: tells the format in which data is available + */ + void setData(const void *data, ECOLOR_FORMAT format) + { + switch (format) + { + case ECF_A1R5G5B5: + color = A1R5G5B5toA8R8G8B8(*(u16*)data); + break; + case ECF_R5G6B5: + color = R5G6B5toA8R8G8B8(*(u16*)data); + break; + case ECF_A8R8G8B8: + color = *(u32*)data; + break; + case ECF_R8G8B8: + { + const u8* p = (u8*)data; + set(255, p[0],p[1],p[2]); + } + break; + default: + color = 0xffffffff; + break; + } + } + + //! Write the color to data in the defined format + /** \param data: target to write the color. Must contain sufficiently large memory to receive the number of bytes neede for format + \param format: tells the format used to write the color into data + */ + void getData(void *data, ECOLOR_FORMAT format) const + { + switch(format) + { + case ECF_A1R5G5B5: + { + u16 * dest = (u16*)data; + *dest = video::A8R8G8B8toA1R5G5B5( color ); + } + break; + + case ECF_R5G6B5: + { + u16 * dest = (u16*)data; + *dest = video::A8R8G8B8toR5G6B5( color ); + } + break; + + case ECF_R8G8B8: + { + u8* dest = (u8*)data; + dest[0] = (u8)getRed(); + dest[1] = (u8)getGreen(); + dest[2] = (u8)getBlue(); + } + break; + + case ECF_A8R8G8B8: + { + u32 * dest = (u32*)data; + *dest = color; + } + break; + + default: + break; + } + } + + //! color in A8R8G8B8 Format + u32 color; + }; + + + //! Class representing a color with four floats. + /** The color values for red, green, blue + and alpha are each stored in a 32 bit floating point variable. + So all four values may be between 0.0f and 1.0f. + Another, faster way to define colors is using the class SColor, which + stores the color values in a single 32 bit integer. + */ + class SColorf + { + public: + //! Default constructor for SColorf. + /** Sets red, green and blue to 0.0f and alpha to 1.0f. */ + SColorf() : r(0.0f), g(0.0f), b(0.0f), a(1.0f) {} + + //! Constructs a color from up to four color values: red, green, blue, and alpha. + /** \param r: Red color component. Should be a value between + 0.0f meaning no red and 1.0f, meaning full red. + \param g: Green color component. Should be a value between 0.0f + meaning no green and 1.0f, meaning full green. + \param b: Blue color component. Should be a value between 0.0f + meaning no blue and 1.0f, meaning full blue. + \param a: Alpha color component of the color. The alpha + component defines how transparent a color should be. Has to be + a value between 0.0f and 1.0f, 1.0f means not transparent + (opaque), 0.0f means fully transparent. */ + SColorf(f32 r, f32 g, f32 b, f32 a = 1.0f) : r(r), g(g), b(b), a(a) {} + + //! Constructs a color from 32 bit Color. + /** \param c: 32 bit color from which this SColorf class is + constructed from. */ + SColorf(SColor c) + { + const f32 inv = 1.0f / 255.0f; + r = c.getRed() * inv; + g = c.getGreen() * inv; + b = c.getBlue() * inv; + a = c.getAlpha() * inv; + } + + //! Converts this color to a SColor without floats. + SColor toSColor() const + { + return SColor((u32)core::round32(a*255.0f), (u32)core::round32(r*255.0f), (u32)core::round32(g*255.0f), (u32)core::round32(b*255.0f)); + } + + //! Sets three color components to new values at once. + /** \param rr: Red color component. Should be a value between 0.0f meaning + no red (=black) and 1.0f, meaning full red. + \param gg: Green color component. Should be a value between 0.0f meaning + no green (=black) and 1.0f, meaning full green. + \param bb: Blue color component. Should be a value between 0.0f meaning + no blue (=black) and 1.0f, meaning full blue. */ + void set(f32 rr, f32 gg, f32 bb) {r = rr; g =gg; b = bb; } + + //! Sets all four color components to new values at once. + /** \param aa: Alpha component. Should be a value between 0.0f meaning + fully transparent and 1.0f, meaning opaque. + \param rr: Red color component. Should be a value between 0.0f meaning + no red and 1.0f, meaning full red. + \param gg: Green color component. Should be a value between 0.0f meaning + no green and 1.0f, meaning full green. + \param bb: Blue color component. Should be a value between 0.0f meaning + no blue and 1.0f, meaning full blue. */ + void set(f32 aa, f32 rr, f32 gg, f32 bb) {a = aa; r = rr; g =gg; b = bb; } + + //! Interpolates the color with a f32 value to another color + /** \param other: Other color + \param d: value between 0.0f and 1.0f + \return Interpolated color. */ + SColorf getInterpolated(const SColorf &other, f32 d) const + { + d = core::clamp(d, 0.f, 1.f); + const f32 inv = 1.0f - d; + return SColorf(other.r*inv + r*d, + other.g*inv + g*d, other.b*inv + b*d, other.a*inv + a*d); + } + + //! Returns interpolated color. ( quadratic ) + /** \param c1: first color to interpolate with + \param c2: second color to interpolate with + \param d: value between 0.0f and 1.0f. */ + inline SColorf getInterpolated_quadratic(const SColorf& c1, const SColorf& c2, + f32 d) const + { + d = core::clamp(d, 0.f, 1.f); + // this*(1-d)*(1-d) + 2 * c1 * (1-d) + c2 * d * d; + const f32 inv = 1.f - d; + const f32 mul0 = inv * inv; + const f32 mul1 = 2.f * d * inv; + const f32 mul2 = d * d; + + return SColorf (r * mul0 + c1.r * mul1 + c2.r * mul2, + g * mul0 + c1.g * mul1 + c2.g * mul2, + b * mul0 + c1.b * mul1 + c2.b * mul2, + a * mul0 + c1.a * mul1 + c2.a * mul2); + } + + + //! Sets a color component by index. R=0, G=1, B=2, A=3 + void setColorComponentValue(s32 index, f32 value) + { + switch(index) + { + case 0: r = value; break; + case 1: g = value; break; + case 2: b = value; break; + case 3: a = value; break; + } + } + + //! Returns the alpha component of the color in the range 0.0 (transparent) to 1.0 (opaque) + f32 getAlpha() const { return a; } + + //! Returns the red component of the color in the range 0.0 to 1.0 + f32 getRed() const { return r; } + + //! Returns the green component of the color in the range 0.0 to 1.0 + f32 getGreen() const { return g; } + + //! Returns the blue component of the color in the range 0.0 to 1.0 + f32 getBlue() const { return b; } + + //! red color component + f32 r; + + //! green color component + f32 g; + + //! blue component + f32 b; + + //! alpha color component + f32 a; + }; + + + //! Class representing a color in HSL format + /** The color values for hue, saturation, luminance + are stored in 32bit floating point variables. Hue is in range [0,360], + Luminance and Saturation are in percent [0,100] + */ + class SColorHSL + { + public: + SColorHSL ( f32 h = 0.f, f32 s = 0.f, f32 l = 0.f ) + : Hue ( h ), Saturation ( s ), Luminance ( l ) {} + + void fromRGB(const SColorf &color); + void toRGB(SColorf &color) const; + + f32 Hue; + f32 Saturation; + f32 Luminance; + + private: + inline f32 toRGB1(f32 rm1, f32 rm2, f32 rh) const; + + }; + + inline void SColorHSL::fromRGB(const SColorf &color) + { + const f32 maxVal = core::max_(color.getRed(), color.getGreen(), color.getBlue()); + const f32 minVal = (f32)core::min_(color.getRed(), color.getGreen(), color.getBlue()); + Luminance = (maxVal+minVal)*50; + if (core::equals(maxVal, minVal)) + { + Hue=0.f; + Saturation=0.f; + return; + } + + const f32 delta = maxVal-minVal; + if ( Luminance <= 50 ) + { + Saturation = (delta)/(maxVal+minVal); + } + else + { + Saturation = (delta)/(2-maxVal-minVal); + } + Saturation *= 100; + + if (core::equals(maxVal, color.getRed())) + Hue = (color.getGreen()-color.getBlue())/delta; + else if (core::equals(maxVal, color.getGreen())) + Hue = 2+((color.getBlue()-color.getRed())/delta); + else // blue is max + Hue = 4+((color.getRed()-color.getGreen())/delta); + + Hue *= 60.0f; + while ( Hue < 0.f ) + Hue += 360; + } + + + inline void SColorHSL::toRGB(SColorf &color) const + { + const f32 l = Luminance/100; + if (core::iszero(Saturation)) // grey + { + color.set(l, l, l); + return; + } + + f32 rm2; + + if ( Luminance <= 50 ) + { + rm2 = l + l * (Saturation/100); + } + else + { + rm2 = l + (1 - l) * (Saturation/100); + } + + const f32 rm1 = 2.0f * l - rm2; + + const f32 h = Hue / 360.0f; + color.set( toRGB1(rm1, rm2, h + 1.f/3.f), + toRGB1(rm1, rm2, h), + toRGB1(rm1, rm2, h - 1.f/3.f) + ); + } + + + // algorithm from Foley/Van-Dam + inline f32 SColorHSL::toRGB1(f32 rm1, f32 rm2, f32 rh) const + { + if (rh<0) + rh += 1; + if (rh>1) + rh -= 1; + + if (rh < 1.f/6.f) + rm1 = rm1 + (rm2 - rm1) * rh*6.f; + else if (rh < 0.5f) + rm1 = rm2; + else if (rh < 2.f/3.f) + rm1 = rm1 + (rm2 - rm1) * ((2.f/3.f)-rh)*6.f; + + return rm1; + } + +} // end namespace video +} // end namespace irr + +#endif diff --git a/include/SExposedVideoData.h b/include/SExposedVideoData.h new file mode 100644 index 00000000..35108f00 --- /dev/null +++ b/include/SExposedVideoData.h @@ -0,0 +1,119 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __S_EXPOSED_VIDEO_DATA_H_INCLUDED__ +#define __S_EXPOSED_VIDEO_DATA_H_INCLUDED__ + +// forward declarations for internal pointers +struct IDirect3D9; +struct IDirect3DDevice9; +struct IDirect3D8; +struct IDirect3DDevice8; + +namespace irr +{ +namespace video +{ + +//! structure for holding data describing a driver and operating system specific data. +/** This data can be retrieved by IVideoDriver::getExposedVideoData(). Use this with caution. +This only should be used to make it possible to extend the engine easily without +modification of its source. Note that this structure does not contain any valid data, if +you are using the software or the null device. +*/ +struct SExposedVideoData +{ + SExposedVideoData() {OpenGLWin32.HDc=0; OpenGLWin32.HRc=0; OpenGLWin32.HWnd=0;} + explicit SExposedVideoData(void* Window) {OpenGLWin32.HDc=0; OpenGLWin32.HRc=0; OpenGLWin32.HWnd=Window;} + + struct SD3D9 + { + //! Pointer to the IDirect3D9 interface + IDirect3D9* D3D9; + + //! Pointer to the IDirect3DDevice9 interface + IDirect3DDevice9* D3DDev9; + + //! Window handle. + /** Get with for example HWND h = reinterpret_cast(exposedData.D3D9.HWnd) */ + void* HWnd; + }; + + struct SOpenGLWin32 + { + //! Private GDI Device Context. + /** Get if for example with: HDC h = reinterpret_cast(exposedData.OpenGLWin32.HDc) */ + void* HDc; + + //! Permanent Rendering Context. + /** Get if for example with: HGLRC h = reinterpret_cast(exposedData.OpenGLWin32.HRc) */ + void* HRc; + + //! Window handle. + /** Get with for example with: HWND h = reinterpret_cast(exposedData.OpenGLWin32.HWnd) */ + void* HWnd; + }; + + struct SOpenGLLinux + { + // XWindow handles + void* X11Display; + void* X11Context; + unsigned long X11Window; + }; + + struct SOpenGLOSX + { + //! The NSOpenGLContext object. + void* Context; + + //! The NSWindow object. + void* Window; + }; + + struct SOpenGLFB + { + //! The EGLNativeWindowType object. + void* Window; + }; + + struct SOpenGLiOS + { + //! The EAGLContext object. + void* Context; + + //! The subview UIView object where the drawing happens. + void* View; + + //! The UIViewController object. + void* ViewController; + + //! The UIWindow object. + void* Window; + }; + + struct SOGLESAndroid + { + //! The ANativeWindow object. + void* Window; + }; + + union + { + SD3D9 D3D9; + SOpenGLWin32 OpenGLWin32; + SOpenGLLinux OpenGLLinux; + SOpenGLOSX OpenGLOSX; + SOpenGLFB OpenGLFB; + SOpenGLiOS OpenGLiOS; + SOGLESAndroid OGLESAndroid; + }; +}; + +} // end namespace video +} // end namespace irr + + +#endif + diff --git a/include/SIrrCreationParameters.h b/include/SIrrCreationParameters.h new file mode 100644 index 00000000..a169456c --- /dev/null +++ b/include/SIrrCreationParameters.h @@ -0,0 +1,330 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_IRRLICHT_CREATION_PARAMETERS_H_INCLUDED__ +#define __I_IRRLICHT_CREATION_PARAMETERS_H_INCLUDED__ + +#include "EDriverTypes.h" +#include "EDeviceTypes.h" +#include "dimension2d.h" +#include "ILogger.h" +#include "position2d.h" +#include "path.h" +#include "IrrCompileConfig.h" + +namespace irr +{ + class IEventReceiver; + + //! Structure for holding Irrlicht Device creation parameters. + /** This structure is used in the createDeviceEx() function. */ + struct SIrrlichtCreationParameters + { + //! Constructs a SIrrlichtCreationParameters structure with default values. + SIrrlichtCreationParameters() : + DeviceType(EIDT_BEST), + DriverType(video::EDT_BURNINGSVIDEO), + WindowSize(core::dimension2d(800, 600)), + WindowPosition(core::position2di(-1,-1)), + Bits(32), + ZBufferBits(24), + Fullscreen(false), + WindowResizable(false), + Stencilbuffer(true), + Vsync(false), + AntiAlias(0), + HandleSRGB(false), + WithAlphaChannel(false), + Doublebuffer(true), + IgnoreInput(false), + Stereobuffer(false), + HighPrecisionFPU(false), + EventReceiver(0), + WindowId(0), +#ifdef _DEBUG + LoggingLevel(ELL_DEBUG), +#else + LoggingLevel(ELL_INFORMATION), +#endif + DisplayAdapter(0), + DriverMultithreaded(false), + UsePerformanceTimer(true), + SDK_version_do_not_use(IRRLICHT_SDK_VERSION), + PrivateData(0), +#if defined(_IRR_COMPILE_WITH_IOS_DEVICE_) || defined(_IRR_ANDROID_PLATFORM_) || defined(_IRR_EMSCRIPTEN_PLATFORM_) + OGLES2ShaderPath("media/Shaders/") +#else + OGLES2ShaderPath("../../media/Shaders/") +#endif + { + } + + SIrrlichtCreationParameters(const SIrrlichtCreationParameters& other) : + SDK_version_do_not_use(IRRLICHT_SDK_VERSION) + {*this = other;} + + SIrrlichtCreationParameters& operator=(const SIrrlichtCreationParameters& other) + { + DeviceType = other.DeviceType; + DriverType = other.DriverType; + WindowSize = other.WindowSize; + WindowPosition = other.WindowPosition; + Bits = other.Bits; + ZBufferBits = other.ZBufferBits; + Fullscreen = other.Fullscreen; + WindowResizable = other.WindowResizable; + Stencilbuffer = other.Stencilbuffer; + Vsync = other.Vsync; + AntiAlias = other.AntiAlias; + HandleSRGB = other.HandleSRGB; + WithAlphaChannel = other.WithAlphaChannel; + Doublebuffer = other.Doublebuffer; + IgnoreInput = other.IgnoreInput; + Stereobuffer = other.Stereobuffer; + HighPrecisionFPU = other.HighPrecisionFPU; + EventReceiver = other.EventReceiver; + WindowId = other.WindowId; + LoggingLevel = other.LoggingLevel; + DisplayAdapter = other.DisplayAdapter; + DriverMultithreaded = other.DriverMultithreaded; + UsePerformanceTimer = other.UsePerformanceTimer; + PrivateData = other.PrivateData; + OGLES2ShaderPath = other.OGLES2ShaderPath; + return *this; + } + + //! Type of the device. + /** This setting decides the windowing system used by the device, most device types are native + to a specific operating system and so may not be available. + EIDT_WIN32 is only available on Windows desktops, + EIDT_WINCE is only available on Windows mobile devices, + EIDT_COCOA is only available on Mac OSX, + EIDT_X11 is available on Linux, Solaris, BSD and other operating systems which use X11, + EIDT_SDL is available on most systems if compiled in, + EIDT_CONSOLE is usually available but can only render to text, + EIDT_BEST will select the best available device for your operating system. + Default: EIDT_BEST. */ + E_DEVICE_TYPE DeviceType; + + //! Type of video driver used to render graphics. + /** This can currently be video::EDT_NULL, video::EDT_SOFTWARE, + video::EDT_BURNINGSVIDEO, video::EDT_DIRECT3D9, and video::EDT_OPENGL. + Default: EDT_BURNINGSVIDEO. */ + video::E_DRIVER_TYPE DriverType; + + //! Size of the window or the video mode in fullscreen mode. Default: 800x600 + core::dimension2d WindowSize; + + //! Position of the window on-screen. Default: (-1, -1) or centered. + core::position2di WindowPosition; + + //! Minimum Bits per pixel of the color buffer in fullscreen mode. Ignored if windowed mode. Default: 32. + u8 Bits; + + //! Minimum Bits per pixel of the depth buffer. Default: 24. + u8 ZBufferBits; + + //! Should be set to true if the device should run in fullscreen. + /** Otherwise the device runs in windowed mode. Default: false. */ + bool Fullscreen; + + //! Should a non-fullscreen window be resizable. + /** Might not be supported by all devices. Ignored when Fullscreen is true. + Default: false */ + bool WindowResizable; + + //! 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 drivers are able to + use the stencil buffer, hence it can be ignored during device + creation. Without the stencil buffer no shadows will be drawn. + Default: true. */ + bool Stencilbuffer; + + //! Specifies vertical synchronization. + /** If set to true, the driver will wait for the vertical + retrace period, otherwise not. May be silently ignored. + Default: false */ + bool Vsync; + + //! Specifies if the device should use fullscreen anti aliasing + /** Makes sharp/pixelated edges softer, but requires more + performance. Also, 2D elements might look blurred with this + switched on. The resulting rendering quality also depends on + the hardware and driver you are using, your program might look + different on different hardware with this. So if you are + 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. + The value is the maximal antialiasing factor requested for + the device. The creation method will automatically try smaller + values if no window can be created with the given 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; + + //! Flag to enable proper sRGB and linear color handling + /** In most situations, it is desirable to have the color handling in + non-linear sRGB color space, and only do the intermediate color + calculations in linear RGB space. If this flag is enabled, the device and + driver try to assure that all color input and output are color corrected + and only the internal color representation is linear. This means, that + the color output is properly gamma-adjusted to provide the brighter + colors for monitor display. And that blending and lighting give a more + natural look, due to proper conversion from non-linear colors into linear + color space for blend operations. If this flag is enabled, all texture colors + (which are usually in sRGB space) are correctly displayed. However vertex colors + and other explicitly set values have to be manually encoded in linear color space. + Default value: false. */ + bool HandleSRGB; + + //! Whether the main framebuffer uses an alpha channel. + /** In some situations it might be desirable 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 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, + this may lead to problems with the other computations of the + application. In this case setting this flag to true should help + - on the expense of performance loss, though. + Default value: false */ + bool HighPrecisionFPU; + + //! A user created event receiver. + IEventReceiver* EventReceiver; + + //! Window Id. + /** If this is set to a value other than 0, the Irrlicht Engine + will be created in an already existing window. + For Windows, set this to the HWND of the window you want. + For iOS, assign UIView to this variable. + The windowSize and FullScreen options will be ignored when using + the WindowId parameter. Default this is set to 0. + To make Irrlicht run inside the custom window, you still will + have to draw Irrlicht on your own. You can use this loop, as + usual: + \code + while (device->run()) + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, 0); + smgr->drawAll(); + driver->endScene(); + } + \endcode + Instead of this, you can also simply use your own message loop + using GetMessage, DispatchMessage and whatever. Calling + IrrlichtDevice::run() will cause Irrlicht to dispatch messages + internally too. You need not call Device->run() if you want to + do your own message dispatching loop, but Irrlicht will not be + able to fetch user input then and you have to do it on your own + using the window messages, DirectInput, or whatever. Also, + you'll have to increment the Irrlicht timer. + An alternative, own message dispatching loop without + device->run() would look like this: + \code + MSG msg; + while (true) + { + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + + if (msg.message == WM_QUIT) + break; + } + + // increase virtual timer time + device->getTimer()->tick(); + + // draw engine picture + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, 0); + smgr->drawAll(); + driver->endScene(); + } + \endcode + However, there is no need to draw the picture this often. Just + do it how you like. */ + void* WindowId; + + //! Specifies the logging level used in the logging interface. + /** The default value is ELL_INFORMATION. You can access the ILogger interface + later on from the IrrlichtDevice with getLogger() and set another level. + But if you need more or less logging information already from device creation, + then you have to change it here. + */ + ELOG_LEVEL LoggingLevel; + + //! Allows to select which graphic card is used for rendering when more than one card is in the system. + /** So far only supported on D3D */ + u32 DisplayAdapter; + + //! Create the driver multithreaded. + /** Default is false. Enabling this can slow down your application. + Note that this does _not_ make Irrlicht threadsafe, but only the underlying driver-API for the graphiccard. + So far only supported on D3D. */ + bool DriverMultithreaded; + + //! Enables use of high performance timers on Windows platform. + /** When performance timers are not used, standard GetTickCount() + is used instead which usually has worse resolution, but also less + problems with speed stepping and other techniques. + */ + bool UsePerformanceTimer; + + //! Don't use or change this parameter. + /** Always set it to IRRLICHT_SDK_VERSION, which is done by default. + This is needed for sdk version checks. */ + const c8* const SDK_version_do_not_use; + + //! Define some private data storage. + /** Used when platform devices need access to OS specific data structures etc. + This is only used for Android at th emoment in order to access the native + Java RE. */ + void *PrivateData; + + //! Set the path where default-shaders to simulate the fixed-function pipeline can be found. + /** This is about the shaders which can be found in media/Shaders by default. It's only necessary + to set when using OGL-ES 2.0 */ + irr::io::path OGLES2ShaderPath; + }; + + +} // end namespace irr + +#endif + diff --git a/include/SKeyMap.h b/include/SKeyMap.h new file mode 100644 index 00000000..3f1b68c5 --- /dev/null +++ b/include/SKeyMap.h @@ -0,0 +1,43 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __S_KEY_MAP_H_INCLUDED__ +#define __S_KEY_MAP_H_INCLUDED__ + +#include "Keycodes.h" + +namespace irr +{ + + //! enumeration for key actions. Used for example in the FPS Camera. + enum EKEY_ACTION + { + EKA_MOVE_FORWARD = 0, + EKA_MOVE_BACKWARD, + EKA_STRAFE_LEFT, + EKA_STRAFE_RIGHT, + EKA_JUMP_UP, + EKA_CROUCH, + EKA_ROTATE_LEFT, + EKA_ROTATE_RIGHT, + EKA_COUNT, + + //! This value is not used. It only forces this enumeration to compile in 32 bit. + EKA_FORCE_32BIT = 0x7fffffff + }; + + //! Struct storing which key belongs to which action. + struct SKeyMap + { + SKeyMap() {} + SKeyMap(EKEY_ACTION action, EKEY_CODE keyCode) : Action(action), KeyCode(keyCode) {} + + EKEY_ACTION Action; + EKEY_CODE KeyCode; + }; + +} // end namespace irr + +#endif + diff --git a/include/SLight.h b/include/SLight.h new file mode 100644 index 00000000..60df5f6b --- /dev/null +++ b/include/SLight.h @@ -0,0 +1,101 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __S_LIGHT_H_INCLUDED__ +#define __S_LIGHT_H_INCLUDED__ + +#include "SColor.h" + +namespace irr +{ +namespace video +{ + +//! Enumeration for different types of lights +enum E_LIGHT_TYPE +{ + //! point light, it has a position in space and radiates light in all directions + ELT_POINT, + //! spot light, it has a position in space, a direction, and a limited cone of influence + ELT_SPOT, + //! directional light, coming from a direction from an infinite distance + ELT_DIRECTIONAL, + + //! Only used for counting the elements of this enum + ELT_COUNT +}; + +//! Names for light types +const c8* const LightTypeNames[] = +{ + "Point", + "Spot", + "Directional", + 0 +}; + +//! structure for holding data describing a dynamic point light. +/** Irrlicht supports point lights, spot lights, and directional lights. +*/ +struct SLight +{ + SLight() : AmbientColor(0.f,0.f,0.f), DiffuseColor(1.f,1.f,1.f), + SpecularColor(1.f,1.f,1.f), Attenuation(1.f,0.f,0.f), + OuterCone(45.f), InnerCone(0.f), Falloff(2.f), + Position(0.f,0.f,0.f), Direction(0.f,0.f,1.f), + Radius(100.f), Type(ELT_POINT), CastShadows(true) + {} + + //! Ambient color emitted by the light + SColorf AmbientColor; + + //! Diffuse color emitted by the light. + /** This is the primary color you want to set. */ + SColorf DiffuseColor; + + //! Specular color emitted by the light. + /** For details how to use specular highlights, see SMaterial::Shininess */ + SColorf SpecularColor; + + //! Attenuation factors (constant, linear, quadratic) + /** Changes the light strength fading over distance. + Can also be altered by setting the radius, Attenuation will change to + (0,1.f/radius,0). Can be overridden after radius was set. */ + core::vector3df Attenuation; + + //! The angle of the spot's outer cone. Ignored for other lights. + f32 OuterCone; + + //! The angle of the spot's inner cone. Ignored for other lights. + f32 InnerCone; + + //! The light strength's decrease between Outer and Inner cone. Only for spot lights + f32 Falloff; + + //! Read-ONLY! Position of the light. + /** If Type is ELT_DIRECTIONAL, it is ignored. Changed via light scene node's position. */ + core::vector3df Position; + + //! Read-ONLY! Direction of the light. + /** If Type is ELT_POINT, it is ignored. Changed via light scene node's rotation. */ + core::vector3df Direction; + + //! Read-ONLY! Radius of light. Everything within this radius will be lighted. + /** On OpenGL light doesn't stop at radius. To get same light as in OpenGL in other drivers + do set the radius to a large value like sqrt(FLT_MAX) and then set the Attenuation afterwards. + */ + f32 Radius; + + //! Read-ONLY! Type of the light. Default: ELT_POINT + E_LIGHT_TYPE Type; + + //! Read-ONLY! Does the light cast shadows? + bool CastShadows:1; +}; + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/include/SMaterial.h b/include/SMaterial.h new file mode 100644 index 00000000..29bc3327 --- /dev/null +++ b/include/SMaterial.h @@ -0,0 +1,832 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __S_MATERIAL_H_INCLUDED__ +#define __S_MATERIAL_H_INCLUDED__ + +#include "SColor.h" +#include "matrix4.h" +#include "irrArray.h" +#include "irrMath.h" +#include "EMaterialTypes.h" +#include "EMaterialFlags.h" +#include "SMaterialLayer.h" + +namespace irr +{ +namespace video +{ + class ITexture; + + //! Flag for MaterialTypeParam (in combination with EMT_ONETEXTURE_BLEND) or for BlendFactor + //! BlendFunc = source * sourceFactor + dest * destFactor + enum E_BLEND_FACTOR + { + EBF_ZERO = 0, //!< src & dest (0, 0, 0, 0) + EBF_ONE, //!< src & dest (1, 1, 1, 1) + EBF_DST_COLOR, //!< src (destR, destG, destB, destA) + EBF_ONE_MINUS_DST_COLOR, //!< src (1-destR, 1-destG, 1-destB, 1-destA) + EBF_SRC_COLOR, //!< dest (srcR, srcG, srcB, srcA) + EBF_ONE_MINUS_SRC_COLOR, //!< dest (1-srcR, 1-srcG, 1-srcB, 1-srcA) + EBF_SRC_ALPHA, //!< src & dest (srcA, srcA, srcA, srcA) + EBF_ONE_MINUS_SRC_ALPHA, //!< src & dest (1-srcA, 1-srcA, 1-srcA, 1-srcA) + EBF_DST_ALPHA, //!< src & dest (destA, destA, destA, destA) + EBF_ONE_MINUS_DST_ALPHA, //!< src & dest (1-destA, 1-destA, 1-destA, 1-destA) + EBF_SRC_ALPHA_SATURATE //!< src (min(srcA, 1-destA), idem, ...) + }; + + //! Values defining the blend operation + enum E_BLEND_OPERATION + { + EBO_NONE = 0, //!< No blending happens + EBO_ADD, //!< Default blending adds the color values + EBO_SUBTRACT, //!< This mode subtracts the color values + EBO_REVSUBTRACT,//!< This modes subtracts destination from source + EBO_MIN, //!< Choose minimum value of each color channel + EBO_MAX, //!< Choose maximum value of each color channel + EBO_MIN_FACTOR, //!< Choose minimum value of each color channel after applying blend factors, not widely supported + EBO_MAX_FACTOR, //!< Choose maximum value of each color channel after applying blend factors, not widely supported + EBO_MIN_ALPHA, //!< Choose minimum value of each color channel based on alpha value, not widely supported + EBO_MAX_ALPHA //!< Choose maximum value of each color channel based on alpha value, not widely supported + }; + + //! MaterialTypeParam: e.g. DirectX: D3DTOP_MODULATE, D3DTOP_MODULATE2X, D3DTOP_MODULATE4X + enum E_MODULATE_FUNC + { + EMFN_MODULATE_1X = 1, + EMFN_MODULATE_2X = 2, + EMFN_MODULATE_4X = 4 + }; + + //! Comparison function, e.g. for depth buffer test + enum E_COMPARISON_FUNC + { + //! Depth test disabled (disable also write to depth buffer) + ECFN_DISABLED=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, + //! Test never succeeds + ECFN_NEVER + }; + + //! 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 + }; + + //! Source of the alpha value to take + /** This is currently only supported in EMT_ONETEXTURE_BLEND. You can use an + or'ed combination of values. Alpha values are modulated (multiplied). */ + enum E_ALPHA_SOURCE + { + //! Use no alpha, somewhat redundant with other settings + EAS_NONE=0, + //! Use vertex color alpha + EAS_VERTEX_COLOR, + //! Use texture alpha channel + EAS_TEXTURE + }; + + //! Pack srcFact, dstFact, Modulate and alpha source to MaterialTypeParam or BlendFactor + /** alpha source can be an OR'ed combination of E_ALPHA_SOURCE values. */ + inline f32 pack_textureBlendFunc(const E_BLEND_FACTOR srcFact, const E_BLEND_FACTOR dstFact, + const E_MODULATE_FUNC modulate=EMFN_MODULATE_1X, const u32 alphaSource=EAS_TEXTURE) + { + const u32 tmp = (alphaSource << 20) | (modulate << 16) | (srcFact << 12) | (dstFact << 8) | (srcFact << 4) | dstFact; + return FR(tmp); + } + + //! Pack srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, Modulate and alpha source to MaterialTypeParam or BlendFactor + /** alpha source can be an OR'ed combination of E_ALPHA_SOURCE values. */ + inline f32 pack_textureBlendFuncSeparate(const E_BLEND_FACTOR srcRGBFact, const E_BLEND_FACTOR dstRGBFact, + const E_BLEND_FACTOR srcAlphaFact, const E_BLEND_FACTOR dstAlphaFact, + const E_MODULATE_FUNC modulate=EMFN_MODULATE_1X, const u32 alphaSource=EAS_TEXTURE) + { + const u32 tmp = (alphaSource << 20) | (modulate << 16) | (srcAlphaFact << 12) | (dstAlphaFact << 8) | (srcRGBFact << 4) | dstRGBFact; + return FR(tmp); + } + + //! Unpack srcFact, dstFact, modulo and alphaSource factors + /** The fields don't use the full byte range, so we could pack even more... */ + inline void unpack_textureBlendFunc(E_BLEND_FACTOR &srcFact, E_BLEND_FACTOR &dstFact, + E_MODULATE_FUNC &modulo, u32& alphaSource, const f32 param) + { + const u32 state = IR(param); + alphaSource = (state & 0x00F00000) >> 20; + modulo = E_MODULATE_FUNC( ( state & 0x000F0000 ) >> 16 ); + srcFact = E_BLEND_FACTOR ( ( state & 0x000000F0 ) >> 4 ); + dstFact = E_BLEND_FACTOR ( ( state & 0x0000000F ) ); + } + + //! Unpack srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulo and alphaSource factors + /** The fields don't use the full byte range, so we could pack even more... */ + inline void unpack_textureBlendFuncSeparate(E_BLEND_FACTOR &srcRGBFact, E_BLEND_FACTOR &dstRGBFact, + E_BLEND_FACTOR &srcAlphaFact, E_BLEND_FACTOR &dstAlphaFact, + E_MODULATE_FUNC &modulo, u32& alphaSource, const f32 param) + { + const u32 state = IR(param); + alphaSource = (state & 0x00F00000) >> 20; + modulo = E_MODULATE_FUNC( ( state & 0x000F0000 ) >> 16 ); + srcAlphaFact = E_BLEND_FACTOR ( ( state & 0x0000F000 ) >> 12 ); + dstAlphaFact = E_BLEND_FACTOR ( ( state & 0x00000F00 ) >> 8 ); + srcRGBFact = E_BLEND_FACTOR ( ( state & 0x000000F0 ) >> 4 ); + dstRGBFact = E_BLEND_FACTOR ( ( state & 0x0000000F ) ); + } + + //! has blend factor alphablending + inline bool textureBlendFunc_hasAlpha ( const E_BLEND_FACTOR factor ) + { + switch ( factor ) + { + case EBF_SRC_ALPHA: + case EBF_ONE_MINUS_SRC_ALPHA: + case EBF_DST_ALPHA: + case EBF_ONE_MINUS_DST_ALPHA: + case EBF_SRC_ALPHA_SATURATE: + return true; + default: + return false; + } + } + + + //! 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 + //! Careful, enabling this can lead to software emulation under OpenGL + 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_CHANNEL_REF and multisampling. */ + EAAM_ALPHA_TO_COVERAGE=16 + }; + + //! These flags allow to define the interpretation of vertex color when lighting is enabled + /** Without lighting being enabled the vertex color is the only value defining the fragment color. + Once lighting is enabled, the four values for diffuse, ambient, emissive, and specular take over. + With these flags it is possible to define which lighting factor shall be defined by the vertex color + instead of the lighting factor which is the same for all faces of that material. + The default is to use vertex color for the diffuse value, another pretty common value is to use + vertex color for both diffuse and ambient factor. */ + enum E_COLOR_MATERIAL + { + //! Don't use vertex color for lighting + ECM_NONE=0, + //! Use vertex color for diffuse light, this is default + ECM_DIFFUSE, + //! Use vertex color for ambient light + ECM_AMBIENT, + //! Use vertex color for emissive light + ECM_EMISSIVE, + //! Use vertex color for specular light + ECM_SPECULAR, + //! Use vertex color for both diffuse and ambient light + ECM_DIFFUSE_AND_AMBIENT + }; + + //! DEPRECATED. Will be removed after Irrlicht 1.9. + /** Flags for the definition of the polygon offset feature. These flags define whether the offset should be into the screen, or towards the eye. */ + enum E_POLYGON_OFFSET + { + //! Push pixel towards the far plane, away from the eye + /** This is typically used for rendering inner areas. */ + EPO_BACK=0, + //! Pull pixels towards the camera. + /** This is typically used for polygons which should appear on top + of other elements, such as decals. */ + EPO_FRONT=1 + }; + + //! Names for polygon offset direction + const c8* const PolygonOffsetDirectionNames[] = + { + "Back", + "Front", + 0 + }; + + //! For SMaterial.ZWriteEnable + enum E_ZWRITE + { + //! zwrite always disabled for this material + EZW_OFF = 0, + + //! This is the default setting for SMaterial and tries to handle things automatically. + //! This is also the value which is set when SMaterial::setFlag(EMF_ZWRITE_ENABLE) is enabled. + //! Usually zwriting is enabled non-transparent materials - as far as Irrlicht can recognize those. + //! Basically Irrlicht tries to handle the zwriting for you and assumes transparent materials don't need it. + //! This is addionally affected by IVideoDriver::setAllowZWriteOnTransparent + EZW_AUTO, + + //! zwrite always enabled for this material + EZW_ON + }; + + //! Names for E_ZWRITE + const c8* const ZWriteNames[] = + { + "Off", + "Auto", + "On", + 0 + }; + + + + //! Maximum number of texture an SMaterial can have. + /** SMaterial might ignore some textures in most function, like assignment and comparison, + when SIrrlichtCreationParameters::MaxTextureUnits is set to a lower number. + */ + const u32 MATERIAL_MAX_TEXTURES = _IRR_MATERIAL_MAX_TEXTURES_; + + //! By default this is identical to MATERIAL_MAX_TEXTURES + /** Users can modify this value if they are certain they don't need all + available textures per material in their application. For example if you + never need more than 2 textures per material you can set this to 2. + + We (mostly) avoid dynamic memory in SMaterial, so the extra memory + will still be allocated. But by lowering MATERIAL_MAX_TEXTURES_USED the + material comparisons and assignments can be faster. Also several other + places in the engine can be faster when reducing this value to the limit + you need. + + NOTE: This should only be changed once and before any call to createDevice. + NOTE: Do not set it below 1 or above the value of _IRR_MATERIAL_MAX_TEXTURES_. + NOTE: Going below 4 is usually not worth it. + */ + IRRLICHT_API extern u32 MATERIAL_MAX_TEXTURES_USED; + + //! Struct for holding parameters for a material renderer + // Note for implementors: Serialization is in CNullDriver + class SMaterial + { + public: + //! Default constructor. Creates a solid, lit material with white colors + SMaterial() + : MaterialType(EMT_SOLID), AmbientColor(255,255,255,255), DiffuseColor(255,255,255,255), + EmissiveColor(0,0,0,0), SpecularColor(255,255,255,255), + Shininess(0.0f), MaterialTypeParam(0.0f), MaterialTypeParam2(0.0f), Thickness(1.0f), + ZBuffer(ECFN_LESSEQUAL), AntiAliasing(EAAM_SIMPLE), ColorMask(ECP_ALL), + ColorMaterial(ECM_DIFFUSE), BlendOperation(EBO_NONE), BlendFactor(0.0f), + PolygonOffsetFactor(0), PolygonOffsetDirection(EPO_FRONT), + PolygonOffsetDepthBias(0.f), PolygonOffsetSlopeScale(0.f), + Wireframe(false), PointCloud(false), GouraudShading(true), + Lighting(true), ZWriteEnable(EZW_AUTO), BackfaceCulling(true), FrontfaceCulling(false), + FogEnable(false), NormalizeNormals(false), UseMipMaps(true) + { } + + //! Copy constructor + /** \param other Material to copy from. */ + SMaterial(const SMaterial& other) + { + // These pointers are checked during assignment + for (u32 i=0; igetMaterial(0).Shininess = 20.0f; + \endcode + + You can change the color of the highlights using + \code + sceneNode->getMaterial(0).SpecularColor.set(255,255,255,255); + \endcode + + The specular color of the dynamic lights + (SLight::SpecularColor) will influence the the highlight color + too, but they are set to a useful value by default when + creating the light scene node. Here is a simple example on how + to use specular highlights: + \code + // load and display mesh + scene::IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( + smgr->getMesh("data/faerie.md2")); + node->setMaterialTexture(0, driver->getTexture("data/Faerie2.pcx")); // set diffuse texture + node->setMaterialFlag(video::EMF_LIGHTING, true); // enable dynamic lighting + node->getMaterial(0).Shininess = 20.0f; // set size of specular highlights + + // add white light + scene::ILightSceneNode* light = smgr->addLightSceneNode(0, + core::vector3df(5,5,5), video::SColorf(1.0f, 1.0f, 1.0f)); + \endcode */ + f32 Shininess; + + //! Free parameter, dependent on the material type. + /** Mostly ignored, used for example in EMT_PARALLAX_MAP_SOLID, + EMT_TRANSPARENT_ALPHA_CHANNEL and EMT_ONETEXTURE_BLEND. */ + f32 MaterialTypeParam; + + //! Second free parameter, dependent on the material type. + /** Mostly ignored. */ + f32 MaterialTypeParam2; + + //! Thickness of non-3dimensional elements such as lines and points. + f32 Thickness; + + //! Is the ZBuffer enabled? Default: ECFN_LESSEQUAL + /** If you want to disable depth test for this material + just set this parameter to ECFN_DISABLED. + Values are from E_COMPARISON_FUNC. */ + u8 ZBuffer; + + //! Sets the antialiasing mode + /** Values are chosen from E_ANTI_ALIASING_MODE. Default is + EAAM_SIMPLE, i.e. simple multi-sample anti-aliasing. */ + 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:4; + + //! Defines the interpretation of vertex color in the lighting equation + /** Values should be chosen from E_COLOR_MATERIAL. + When lighting is enabled, vertex color can be used instead of the + material values for light modulation. This allows to easily change e.g. the + diffuse light behavior of each face. The default, ECM_DIFFUSE, will result in + a very similar rendering as with lighting turned off, just with light shading. */ + u8 ColorMaterial:3; + + //! Store the blend operation of choice + /** Values to be chosen from E_BLEND_OPERATION. */ + E_BLEND_OPERATION BlendOperation:4; + + //! Store the blend factors + /** textureBlendFunc/textureBlendFuncSeparate functions should be used to write + properly blending factors to this parameter. + Due to historical reasons this parameter is not used for material type + EMT_ONETEXTURE_BLEND which uses MaterialTypeParam instead for the blend factor. + It's generally used only for materials without any blending otherwise (like EMT_SOLID). + It's main use is to allow having shader materials which can enable/disable + blending after they have been created. + When you set this you usually also have to set BlendOperation to a value != EBO_NONE + (setting it to EBO_ADD is probably the most common one value). */ + f32 BlendFactor; + + //! DEPRECATED. Will be removed after Irrlicht 1.9. Please use PolygonOffsetDepthBias instead. + /** Factor specifying how far the polygon offset should be made. + Specifying 0 disables the polygon offset. The direction is specified separately. + The factor can be from 0 to 7. + Note: This probably never worked on Direct3D9 (was coded for D3D8 which had different value ranges) */ + u8 PolygonOffsetFactor:3; + + //! DEPRECATED. Will be removed after Irrlicht 1.9. + /** Flag defining the direction the polygon offset is applied to. + Can be to front or to back, specified by values from E_POLYGON_OFFSET. */ + E_POLYGON_OFFSET PolygonOffsetDirection:1; + + //! A constant z-buffer offset for a polygon/line/point + /** The range of the value is driver specific. + On OpenGL you get units which are multiplied by the smallest value that is guaranteed to produce a resolvable offset. + On D3D9 you can pass a range between -1 and 1. But you should likely divide it by the range of the depthbuffer. + Like dividing by 65535.0 for a 16 bit depthbuffer. Thought it still might produce too large of a bias. + Some article (https://aras-p.info/blog/2008/06/12/depth-bias-and-the-power-of-deceiving-yourself/) + recommends multiplying by 2.0*4.8e-7 (and strangely on both 16 bit and 24 bit). */ + f32 PolygonOffsetDepthBias; + + //! Variable Z-Buffer offset based on the slope of the polygon. + /** For polygons looking flat at a camera you could use 0 (for example in a 2D game) + But in most cases you will have polygons rendered at a certain slope. + The driver will calculate the slope for you and this value allows to scale that slope. + The complete polygon offset is: PolygonOffsetSlopeScale*slope + PolygonOffsetDepthBias + A good default here is to use 1.f if you want to push the polygons away from the camera + and -1.f to pull them towards the camera. */ + f32 PolygonOffsetSlopeScale; + + //! Draw as wireframe or filled triangles? Default: false + /** The user can access a material flag using + \code material.Wireframe=true \endcode + or \code material.setFlag(EMF_WIREFRAME, true); \endcode */ + bool Wireframe:1; + + //! Draw as point cloud or filled triangles? Default: false + bool PointCloud:1; + + //! Flat or Gouraud shading? Default: true + bool GouraudShading:1; + + //! Will this material be lighted? Default: true + bool Lighting:1; + + //! Is the zbuffer writable or is it read-only. Default: EZW_AUTO. + /** If this parameter is not EZW_OFF, you probably also want to set ZBuffer + to values other than ECFN_DISABLED */ + E_ZWRITE ZWriteEnable:2; + + //! Is backface culling enabled? Default: true + bool BackfaceCulling:1; + + //! Is frontface culling enabled? Default: false + bool FrontfaceCulling:1; + + //! Is fog enabled? Default: false + bool FogEnable:1; + + //! Should normals be normalized? + /** Always use this if the mesh lit and scaled. Default: false */ + bool NormalizeNormals:1; + + //! Shall mipmaps be used if available + /** Sometimes, disabling mipmap usage can be useful. Default: true */ + bool UseMipMaps:1; + + //! Gets the texture transformation matrix for level i + /** \param i The desired level. Must not be larger than MATERIAL_MAX_TEXTURES + \return Texture matrix for texture level i. */ + core::matrix4& getTextureMatrix(u32 i) + { + return TextureLayer[i].getTextureMatrix(); + } + + //! Gets the immutable texture transformation matrix for level i + /** \param i The desired level. + \return Texture matrix for texture level i, or identity matrix for levels larger than MATERIAL_MAX_TEXTURES. */ + const core::matrix4& getTextureMatrix(u32 i) const + { + if (i=MATERIAL_MAX_TEXTURES) + return; + TextureLayer[i].setTextureMatrix(mat); + } + + //! Gets the i-th texture + /** \param i The desired level. + \return Texture for texture level i, if defined, else 0. */ + ITexture* getTexture(u32 i) const + { + return i < MATERIAL_MAX_TEXTURES ? TextureLayer[i].Texture : 0; + } + + //! Sets the i-th texture + /** If i>=MATERIAL_MAX_TEXTURES this setting will be ignored. + \param i The desired level. + \param tex Texture for texture level i. */ + void setTexture(u32 i, ITexture* tex) + { + if (i>=MATERIAL_MAX_TEXTURES) + return; + TextureLayer[i].Texture = tex; + } + + //! Sets the Material flag to the given value + /** \param flag The flag to be set. + \param value The new value for the flag. */ + void setFlag(E_MATERIAL_FLAG flag, bool value) + { + switch (flag) + { + case EMF_WIREFRAME: + Wireframe = value; break; + case EMF_POINTCLOUD: + PointCloud = value; break; + case EMF_GOURAUD_SHADING: + GouraudShading = value; break; + case EMF_LIGHTING: + Lighting = value; break; + case EMF_ZBUFFER: + ZBuffer = value; break; + case EMF_ZWRITE_ENABLE: + ZWriteEnable = value ? EZW_AUTO : EZW_OFF; break; + case EMF_BACK_FACE_CULLING: + BackfaceCulling = value; break; + case EMF_FRONT_FACE_CULLING: + FrontfaceCulling = value; break; + case EMF_BILINEAR_FILTER: + { + for (u32 i=0; i MatrixAllocator; + + //! Texture Matrix + /** Do not access this element directly as the internal + resource management has to cope with Null pointers etc. */ + core::matrix4* TextureMatrix; + }; + +} // end namespace video +} // end namespace irr + +#endif // __S_MATERIAL_LAYER_H_INCLUDED__ diff --git a/include/SMesh.h b/include/SMesh.h new file mode 100644 index 00000000..add6c9fb --- /dev/null +++ b/include/SMesh.h @@ -0,0 +1,153 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __S_MESH_H_INCLUDED__ +#define __S_MESH_H_INCLUDED__ + +#include "IMesh.h" +#include "IMeshBuffer.h" +#include "aabbox3d.h" +#include "irrArray.h" + +namespace irr +{ +namespace scene +{ + //! Simple implementation of the IMesh interface. + struct SMesh : public IMesh + { + //! constructor + SMesh() + { + #ifdef _DEBUG + setDebugName("SMesh"); + #endif + } + + //! destructor + virtual ~SMesh() + { + // drop buffers + for (u32 i=0; idrop(); + } + + //! clean mesh + virtual void clear() + { + for (u32 i=0; idrop(); + MeshBuffers.clear(); + BoundingBox.reset ( 0.f, 0.f, 0.f ); + } + + + //! returns amount of mesh buffers. + virtual u32 getMeshBufferCount() const _IRR_OVERRIDE_ + { + return MeshBuffers.size(); + } + + //! returns pointer to a mesh buffer + virtual IMeshBuffer* getMeshBuffer(u32 nr) const _IRR_OVERRIDE_ + { + return MeshBuffers[nr]; + } + + //! returns a meshbuffer which fits a material + /** reverse search */ + virtual IMeshBuffer* getMeshBuffer( const video::SMaterial & material) const _IRR_OVERRIDE_ + { + for (s32 i = (s32)MeshBuffers.size()-1; i >= 0; --i) + { + if ( material == MeshBuffers[i]->getMaterial()) + return MeshBuffers[i]; + } + + return 0; + } + + //! returns an axis aligned bounding box + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_ + { + return BoundingBox; + } + + //! set user axis aligned bounding box + virtual void setBoundingBox( const core::aabbox3df& box) _IRR_OVERRIDE_ + { + BoundingBox = box; + } + + //! recalculates the bounding box + void recalculateBoundingBox() + { + bool hasMeshBufferBBox = false; + for (u32 i=0; igetBoundingBox(); + if ( !bb.isEmpty() ) + { + if ( !hasMeshBufferBBox ) + { + hasMeshBufferBBox = true; + BoundingBox = bb; + } + else + { + BoundingBox.addInternalBox(bb); + } + + } + } + + if ( !hasMeshBufferBBox ) + BoundingBox.reset(0.0f, 0.0f, 0.0f); + } + + //! adds a MeshBuffer + /** The bounding box is not updated automatically. */ + void addMeshBuffer(IMeshBuffer* buf) + { + if (buf) + { + buf->grab(); + MeshBuffers.push_back(buf); + } + } + + //! sets a flag of all contained materials to a new value + virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) _IRR_OVERRIDE_ + { + for (u32 i=0; igetMaterial().setFlag(flag, newvalue); + } + + //! set the hardware mapping hint, for driver + virtual void setHardwareMappingHint( E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX ) _IRR_OVERRIDE_ + { + for (u32 i=0; isetHardwareMappingHint(newMappingHint, buffer); + } + + //! flags the meshbuffer as changed, reloads hardware buffers + virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_ + { + for (u32 i=0; isetDirty(buffer); + } + + //! The meshbuffers of this mesh + core::array MeshBuffers; + + //! The bounding box of this mesh + core::aabbox3d BoundingBox; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/SMeshBuffer.h b/include/SMeshBuffer.h new file mode 100644 index 00000000..03b441f3 --- /dev/null +++ b/include/SMeshBuffer.h @@ -0,0 +1,7 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +// replaced by template +#include "CMeshBuffer.h" + diff --git a/include/SMeshBufferLightMap.h b/include/SMeshBufferLightMap.h new file mode 100644 index 00000000..03b441f3 --- /dev/null +++ b/include/SMeshBufferLightMap.h @@ -0,0 +1,7 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +// replaced by template +#include "CMeshBuffer.h" + diff --git a/include/SMeshBufferTangents.h b/include/SMeshBufferTangents.h new file mode 100644 index 00000000..03b441f3 --- /dev/null +++ b/include/SMeshBufferTangents.h @@ -0,0 +1,7 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +// replaced by template +#include "CMeshBuffer.h" + diff --git a/include/SOverrideMaterial.h b/include/SOverrideMaterial.h new file mode 100644 index 00000000..8ecbae25 --- /dev/null +++ b/include/SOverrideMaterial.h @@ -0,0 +1,182 @@ +// Copyright (C) 2017 Michael Zeilfelder +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __S_OVERRIDE_MATERIAL_H_INCLUDED__ +#define __S_OVERRIDE_MATERIAL_H_INCLUDED__ + +#include "SMaterial.h" + +namespace irr +{ +namespace video +{ + + struct SOverrideMaterial + { + //! The Material values + SMaterial Material; + + //! Which values are overridden + /** OR'ed values from E_MATERIAL_FLAGS. */ + u32 EnableFlags; + + //! For those flags in EnableFlags which affect layers, set which of the layers are affected + bool EnableLayerFlags[MATERIAL_MAX_TEXTURES]; + + //! Which textures are overridden + bool EnableTextures[MATERIAL_MAX_TEXTURES]; + + //! Overwrite complete layers (settings of EnableLayerFlags and EnableTextures don't matter then for layer data) + bool EnableLayers[MATERIAL_MAX_TEXTURES]; + + //! Set in which render passes the material override is active. + /** OR'ed values from E_SCENE_NODE_RENDER_PASS. */ + u16 EnablePasses; + + //! Global enable flag, overwritten by the SceneManager in each pass + /** NOTE: This is generally _not_ set by users of the engine, but the + Scenemanager uses the EnablePass array and sets Enabled to true if the + Override material is enabled in the current pass. + As user you generally _only_ set EnablePasses. + The exception is when rendering without SceneManager but using draw calls in the VideoDriver. */ + bool Enabled; + + struct SMaterialTypeReplacement + { + SMaterialTypeReplacement(s32 original, u32 replacement) : Original(original), Replacement(replacement) {} + SMaterialTypeReplacement(u32 replacement) : Original(-1), Replacement(replacement) {} + + //! SMaterial.MaterialType to replace. + //! -1 for all types or a specific value to only replace that one (which is either one of E_MATERIAL_TYPE or a shader material id) + s32 Original; + + //! MaterialType to used to override Original (either one of E_MATERIAL_TYPE or a shader material id) + u32 Replacement; + }; + + //! To overwrite SMaterial::MaterialType + core::array MaterialTypes; + + //! Default constructor + SOverrideMaterial() : EnableFlags(0), EnablePasses(0), Enabled(false) + { + } + + //! disable overrides and reset all flags + void reset() + { + EnableFlags = 0; + EnablePasses = 0; + Enabled = false; + for (u32 i = 0; i < MATERIAL_MAX_TEXTURES; ++i) + { + EnableLayerFlags[i] = true; // doesn't do anything unless EnableFlags is set, just saying by default all texture layers are affected by flags + EnableTextures[i] = false; + EnableLayers[i] = false; + } + MaterialTypes.clear(); + } + + //! Apply the enabled overrides + void apply(SMaterial& material) + { + if (Enabled) + { + for (u32 i = 0; i < MaterialTypes.size(); ++i) + { + const SMaterialTypeReplacement& mtr = MaterialTypes[i]; + if (mtr.Original < 0 || (s32)mtr.Original == material.MaterialType) + material.MaterialType = (E_MATERIAL_TYPE)mtr.Replacement; + } + for (u32 f=0; f<32; ++f) + { + const u32 num=(1< *vertices) : IMeshBuffer(), Vertices(vertices), ChangedID_Vertex(1), ChangedID_Index(1), MappingHintVertex(EHM_NEVER), MappingHintIndex(EHM_NEVER) + { + #ifdef _DEBUG + setDebugName("SSharedMeshBuffer"); + #endif + } + + //! returns the material of this meshbuffer + virtual const video::SMaterial& getMaterial() const _IRR_OVERRIDE_ + { + return Material; + } + + //! returns the material of this meshbuffer + virtual video::SMaterial& getMaterial() _IRR_OVERRIDE_ + { + return Material; + } + + //! returns pointer to vertices + virtual const void* getVertices() const _IRR_OVERRIDE_ + { + if (Vertices) + return Vertices->const_pointer(); + else + return 0; + } + + //! returns pointer to vertices + virtual void* getVertices() _IRR_OVERRIDE_ + { + if (Vertices) + return Vertices->pointer(); + else + return 0; + } + + //! returns amount of vertices + virtual u32 getVertexCount() const _IRR_OVERRIDE_ + { + if (Vertices) + return Vertices->size(); + else + return 0; + } + + //! returns pointer to indices + virtual const u16* getIndices() const _IRR_OVERRIDE_ + { + return Indices.const_pointer(); + } + + //! returns pointer to indices + virtual u16* getIndices() _IRR_OVERRIDE_ + { + return Indices.pointer(); + } + + //! returns amount of indices + virtual u32 getIndexCount() const _IRR_OVERRIDE_ + { + return Indices.size(); + } + + //! Get type of index data which is stored in this meshbuffer. + virtual video::E_INDEX_TYPE getIndexType() const _IRR_OVERRIDE_ + { + return video::EIT_16BIT; + } + + //! returns an axis aligned bounding box + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_ + { + return BoundingBox; + } + + //! set user axis aligned bounding box + virtual void setBoundingBox( const core::aabbox3df& box) _IRR_OVERRIDE_ + { + BoundingBox = box; + } + + //! returns which type of vertex data is stored. + virtual video::E_VERTEX_TYPE getVertexType() const _IRR_OVERRIDE_ + { + return video::EVT_STANDARD; + } + + //! recalculates the bounding box. should be called if the mesh changed. + virtual void recalculateBoundingBox() _IRR_OVERRIDE_ + { + if (!Vertices || Vertices->empty() || Indices.empty()) + BoundingBox.reset(0,0,0); + else + { + BoundingBox.reset((*Vertices)[Indices[0]].Pos); + for (u32 i=1; i *Vertices; + + //! Array of indices + core::array Indices; + + //! ID used for hardware buffer management + u32 ChangedID_Vertex; + + //! ID used for hardware buffer management + u32 ChangedID_Index; + + //! Bounding box + core::aabbox3df BoundingBox; + + //! hardware mapping hint + E_HARDWARE_MAPPING MappingHintVertex; + E_HARDWARE_MAPPING MappingHintIndex; + + //! Primitive type used for rendering (triangles, lines, ...) + E_PRIMITIVE_TYPE PrimitiveType; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/SSkinMeshBuffer.h b/include/SSkinMeshBuffer.h new file mode 100644 index 00000000..a6c2b68d --- /dev/null +++ b/include/SSkinMeshBuffer.h @@ -0,0 +1,420 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_SKIN_MESH_BUFFER_H_INCLUDED__ +#define __I_SKIN_MESH_BUFFER_H_INCLUDED__ + +#include "IMeshBuffer.h" +#include "S3DVertex.h" + + +namespace irr +{ +namespace scene +{ + + +//! A mesh buffer able to choose between S3DVertex2TCoords, S3DVertex and S3DVertexTangents at runtime +struct SSkinMeshBuffer : public IMeshBuffer +{ + //! Default constructor + SSkinMeshBuffer(video::E_VERTEX_TYPE vt=video::EVT_STANDARD) : + ChangedID_Vertex(1), ChangedID_Index(1), VertexType(vt), + PrimitiveType(EPT_TRIANGLES), + MappingHint_Vertex(EHM_NEVER), MappingHint_Index(EHM_NEVER), + BoundingBoxNeedsRecalculated(true) + { + #ifdef _DEBUG + setDebugName("SSkinMeshBuffer"); + #endif + } + + //! Get Material of this buffer. + virtual const video::SMaterial& getMaterial() const _IRR_OVERRIDE_ + { + return Material; + } + + //! Get Material of this buffer. + virtual video::SMaterial& getMaterial() _IRR_OVERRIDE_ + { + return Material; + } + + //! Get standard vertex at given index + virtual video::S3DVertex *getVertex(u32 index) + { + switch (VertexType) + { + case video::EVT_2TCOORDS: + return (video::S3DVertex*)&Vertices_2TCoords[index]; + case video::EVT_TANGENTS: + return (video::S3DVertex*)&Vertices_Tangents[index]; + default: + return &Vertices_Standard[index]; + } + } + + //! Get pointer to vertex array + virtual const void* getVertices() const _IRR_OVERRIDE_ + { + switch (VertexType) + { + case video::EVT_2TCOORDS: + return Vertices_2TCoords.const_pointer(); + case video::EVT_TANGENTS: + return Vertices_Tangents.const_pointer(); + default: + return Vertices_Standard.const_pointer(); + } + } + + //! Get pointer to vertex array + virtual void* getVertices() _IRR_OVERRIDE_ + { + switch (VertexType) + { + case video::EVT_2TCOORDS: + return Vertices_2TCoords.pointer(); + case video::EVT_TANGENTS: + return Vertices_Tangents.pointer(); + default: + return Vertices_Standard.pointer(); + } + } + + //! Get vertex count + virtual u32 getVertexCount() const _IRR_OVERRIDE_ + { + switch (VertexType) + { + case video::EVT_2TCOORDS: + return Vertices_2TCoords.size(); + case video::EVT_TANGENTS: + return Vertices_Tangents.size(); + default: + return Vertices_Standard.size(); + } + } + + //! Get type of index data which is stored in this meshbuffer. + /** \return Index type of this buffer. */ + virtual video::E_INDEX_TYPE getIndexType() const _IRR_OVERRIDE_ + { + return video::EIT_16BIT; + } + + //! Get pointer to index array + virtual const u16* getIndices() const _IRR_OVERRIDE_ + { + return Indices.const_pointer(); + } + + //! Get pointer to index array + virtual u16* getIndices() _IRR_OVERRIDE_ + { + return Indices.pointer(); + } + + //! Get index count + virtual u32 getIndexCount() const _IRR_OVERRIDE_ + { + return Indices.size(); + } + + //! Get bounding box + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_ + { + return BoundingBox; + } + + //! Set bounding box + virtual void setBoundingBox( const core::aabbox3df& box) _IRR_OVERRIDE_ + { + BoundingBox = box; + } + + //! Recalculate bounding box + virtual void recalculateBoundingBox() _IRR_OVERRIDE_ + { + if(!BoundingBoxNeedsRecalculated) + return; + + BoundingBoxNeedsRecalculated = false; + + switch (VertexType) + { + case video::EVT_STANDARD: + { + if (Vertices_Standard.empty()) + BoundingBox.reset(0,0,0); + else + { + BoundingBox.reset(Vertices_Standard[0].Pos); + for (u32 i=1; i Vertices_Tangents; + core::array Vertices_2TCoords; + core::array Vertices_Standard; + core::array Indices; + + u32 ChangedID_Vertex; + u32 ChangedID_Index; + + //ISkinnedMesh::SJoint *AttachedJoint; + core::matrix4 Transformation; + + video::SMaterial Material; + video::E_VERTEX_TYPE VertexType; + + core::aabbox3d BoundingBox; + + //! Primitive type used for rendering (triangles, lines, ...) + E_PRIMITIVE_TYPE PrimitiveType; + + // hardware mapping hint + E_HARDWARE_MAPPING MappingHint_Vertex:3; + E_HARDWARE_MAPPING MappingHint_Index:3; + + bool BoundingBoxNeedsRecalculated:1; +}; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/SVertexIndex.h b/include/SVertexIndex.h new file mode 100644 index 00000000..d6837dc2 --- /dev/null +++ b/include/SVertexIndex.h @@ -0,0 +1,79 @@ +// Copyright (C) 2008-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __S_VERTEX_INDEX_H_INCLUDED__ +#define __S_VERTEX_INDEX_H_INCLUDED__ + +#include "irrTypes.h" + + +namespace irr +{ +namespace video +{ +enum E_INDEX_TYPE +{ + EIT_16BIT = 0, + EIT_32BIT +}; + + +/* +//! vertex index used by the Irrlicht engine. +template +struct SSpecificVertexIndex +{ + T Index; + + //! default constructor + SSpecificVertexIndex() {} + + //! constructor + SSpecificVertexIndex(u32 _index) :Index(_index) {} + + bool operator==(const SSpecificVertexIndex& other) const + { + return (Index == other.Index); + } + + bool operator!=(const SSpecificVertexIndex& other) const + { + return (Index != other.Index); + } + + bool operator<(const SSpecificVertexIndex& other) const + { + return (Index < other.Index); + } + + SSpecificVertexIndex operator+(const u32& other) const + { + return SSpecificVertexIndex(Index + other); + } + + operator const u32() const + { + return (const u32)Index; + } + + E_INDEX_TYPE getType() const + { + if (sizeof(T)==sizeof(u16)) + return video::EIT_16BIT; + return video::EIT_32BIT; + } + +}; + +//typedef SSpecificVertexIndex SVertexIndex; + +typedef u32 SVertexIndex; +*/ + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/include/SVertexManipulator.h b/include/SVertexManipulator.h new file mode 100644 index 00000000..3fda59de --- /dev/null +++ b/include/SVertexManipulator.h @@ -0,0 +1,306 @@ +// Copyright (C) 2009-2012 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __S_VERTEX_MANIPULATOR_H_INCLUDED__ +#define __S_VERTEX_MANIPULATOR_H_INCLUDED__ + +#include "S3DVertex.h" +#include "SColor.h" + +namespace irr +{ +namespace scene +{ + + class IMesh; + class IMeshBuffer; + struct SMesh; + + //! Interface for vertex manipulators. + /** You should derive your manipulator from this class if it shall be called for every vertex, getting as parameter just the vertex. + */ + struct IVertexManipulator + { + }; + //! Vertex manipulator to set color to a fixed color for all vertices + class SVertexColorSetManipulator : public IVertexManipulator + { + public: + SVertexColorSetManipulator(video::SColor color) : Color(color) {} + void operator()(video::S3DVertex& vertex) const + { + vertex.Color=Color; + } + private: + video::SColor Color; + }; + //! Vertex manipulator to set the alpha value of the vertex color to a fixed value + class SVertexColorSetAlphaManipulator : public IVertexManipulator + { + public: + SVertexColorSetAlphaManipulator(u32 alpha) : Alpha(alpha) {} + void operator()(video::S3DVertex& vertex) const + { + vertex.Color.setAlpha(Alpha); + } + private: + u32 Alpha; + }; + //! Vertex manipulator which inverts the RGB values + class SVertexColorInvertManipulator : public IVertexManipulator + { + public: + void operator()(video::S3DVertex& vertex) const + { + vertex.Color.setRed(255-vertex.Color.getRed()); + vertex.Color.setGreen(255-vertex.Color.getGreen()); + vertex.Color.setBlue(255-vertex.Color.getBlue()); + } + }; + //! Vertex manipulator to set vertex color to one of two values depending on a given threshold + /** If average of the color value is >Threshold the High color is chosen, else Low. */ + class SVertexColorThresholdManipulator : public IVertexManipulator + { + public: + SVertexColorThresholdManipulator(u8 threshold, video::SColor low, + video::SColor high) : Threshold(threshold), Low(low), High(high) {} + void operator()(video::S3DVertex& vertex) const + { + vertex.Color = ((u8)vertex.Color.getAverage()>Threshold)?High:Low; + } + private: + u8 Threshold; + video::SColor Low; + video::SColor High; + }; + //! Vertex manipulator which adjusts the brightness by the given amount + /** A positive value increases brightness, a negative value darkens the colors. */ + class SVertexColorBrightnessManipulator : public IVertexManipulator + { + public: + SVertexColorBrightnessManipulator(s32 amount) : Amount(amount) {} + void operator()(video::S3DVertex& vertex) const + { + vertex.Color.setRed(core::clamp(vertex.Color.getRed()+Amount, 0u, 255u)); + vertex.Color.setGreen(core::clamp(vertex.Color.getGreen()+Amount, 0u, 255u)); + vertex.Color.setBlue(core::clamp(vertex.Color.getBlue()+Amount, 0u, 255u)); + } + private: + s32 Amount; + }; + //! Vertex manipulator which adjusts the contrast by the given factor + /** Factors over 1 increase contrast, below 1 reduce it. */ + class SVertexColorContrastManipulator : public IVertexManipulator + { + public: + SVertexColorContrastManipulator(f32 factor) : Factor(factor) {} + void operator()(video::S3DVertex& vertex) const + { + vertex.Color.setRed(core::clamp(core::round32((vertex.Color.getRed()-128)*Factor)+128, 0, 255)); + vertex.Color.setGreen(core::clamp(core::round32((vertex.Color.getGreen()-128)*Factor)+128, 0, 255)); + vertex.Color.setBlue(core::clamp(core::round32((vertex.Color.getBlue()-128)*Factor)+128, 0, 255)); + } + private: + f32 Factor; + }; + //! Vertex manipulator which adjusts the contrast by the given factor and brightness by a signed amount. + /** Factors over 1 increase contrast, below 1 reduce it. + A positive amount increases brightness, a negative one darkens the colors. */ + class SVertexColorContrastBrightnessManipulator : public IVertexManipulator + { + public: + SVertexColorContrastBrightnessManipulator(f32 factor, s32 amount) : Factor(factor), Amount(amount+128) {} + void operator()(video::S3DVertex& vertex) const + { + vertex.Color.setRed(core::clamp(core::round32((vertex.Color.getRed()-128)*Factor)+Amount, 0, 255)); + vertex.Color.setGreen(core::clamp(core::round32((vertex.Color.getGreen()-128)*Factor)+Amount, 0, 255)); + vertex.Color.setBlue(core::clamp(core::round32((vertex.Color.getBlue()-128)*Factor)+Amount, 0, 255)); + } + private: + f32 Factor; + s32 Amount; + }; + //! Vertex manipulator which adjusts the brightness by a gamma operation + /** A value over one increases brightness, one below darkens the colors. */ + class SVertexColorGammaManipulator : public IVertexManipulator + { + public: + SVertexColorGammaManipulator(f32 gamma) : Gamma(1.f) + { + if (gamma != 0.f) + Gamma = 1.f/gamma; + } + void operator()(video::S3DVertex& vertex) const + { + vertex.Color.setRed(core::clamp(core::round32(powf((f32)(vertex.Color.getRed()),Gamma)), 0, 255)); + vertex.Color.setGreen(core::clamp(core::round32(powf((f32)(vertex.Color.getGreen()),Gamma)), 0, 255)); + vertex.Color.setBlue(core::clamp(core::round32(powf((f32)(vertex.Color.getBlue()),Gamma)), 0, 255)); + } + private: + f32 Gamma; + }; + //! Vertex manipulator which scales the color values + /** Can e.g be used for white balance, factor would be 255.f/brightest color. */ + class SVertexColorScaleManipulator : public IVertexManipulator + { + public: + SVertexColorScaleManipulator(f32 factor) : Factor(factor) {} + void operator()(video::S3DVertex& vertex) const + { + vertex.Color.setRed(core::clamp(core::round32(vertex.Color.getRed()*Factor), 0, 255)); + vertex.Color.setGreen(core::clamp(core::round32(vertex.Color.getGreen()*Factor), 0, 255)); + vertex.Color.setBlue(core::clamp(core::round32(vertex.Color.getBlue()*Factor), 0, 255)); + } + private: + f32 Factor; + }; + //! Vertex manipulator which desaturates the color values + /** Uses the lightness value of the color. */ + class SVertexColorDesaturateToLightnessManipulator : public IVertexManipulator + { + public: + void operator()(video::S3DVertex& vertex) const + { + vertex.Color=core::round32(vertex.Color.getLightness()); + } + }; + //! Vertex manipulator which desaturates the color values + /** Uses the average value of the color. */ + class SVertexColorDesaturateToAverageManipulator : public IVertexManipulator + { + public: + void operator()(video::S3DVertex& vertex) const + { + vertex.Color=vertex.Color.getAverage(); + } + }; + //! Vertex manipulator which desaturates the color values + /** Uses the luminance value of the color. */ + class SVertexColorDesaturateToLuminanceManipulator : public IVertexManipulator + { + public: + void operator()(video::S3DVertex& vertex) const + { + vertex.Color=core::round32(vertex.Color.getLuminance()); + } + }; + //! Vertex manipulator which interpolates the color values + /** Uses linear interpolation. */ + class SVertexColorInterpolateLinearManipulator : public IVertexManipulator + { + public: + SVertexColorInterpolateLinearManipulator(video::SColor color, f32 factor) : + Color(color), Factor(factor) {} + void operator()(video::S3DVertex& vertex) const + { + vertex.Color=vertex.Color.getInterpolated(Color, Factor); + } + private: + video::SColor Color; + f32 Factor; + }; + //! Vertex manipulator which interpolates the color values + /** Uses linear interpolation. */ + class SVertexColorInterpolateQuadraticManipulator : public IVertexManipulator + { + public: + SVertexColorInterpolateQuadraticManipulator(video::SColor color1, video::SColor color2, f32 factor) : + Color1(color1), Color2(color2), Factor(factor) {} + void operator()(video::S3DVertex& vertex) const + { + vertex.Color=vertex.Color.getInterpolated_quadratic(Color1, Color2, Factor); + } + private: + video::SColor Color1; + video::SColor Color2; + f32 Factor; + }; + + //! Vertex manipulator which scales the position of the vertex + class SVertexPositionScaleManipulator : public IVertexManipulator + { + public: + SVertexPositionScaleManipulator(const core::vector3df& factor) : Factor(factor) {} + template + void operator()(VType& vertex) const + { + vertex.Pos *= Factor; + } + private: + core::vector3df Factor; + }; + + //! Vertex manipulator which scales the position of the vertex along the normals + /** This can look more pleasing than the usual Scale operator, but + depends on the mesh geometry. + */ + class SVertexPositionScaleAlongNormalsManipulator : public IVertexManipulator + { + public: + SVertexPositionScaleAlongNormalsManipulator(const core::vector3df& factor) : Factor(factor) {} + template + void operator()(VType& vertex) const + { + vertex.Pos += vertex.Normal*Factor; + } + private: + core::vector3df Factor; + }; + + //! Vertex manipulator which transforms the position of the vertex + class SVertexPositionTransformManipulator : public IVertexManipulator + { + public: + SVertexPositionTransformManipulator(const core::matrix4& m) : Transformation(m) {} + template + void operator()(VType& vertex) const + { + Transformation.transformVect(vertex.Pos); + } + private: + core::matrix4 Transformation; + }; + + //! Vertex manipulator which transforms the normal of the vertex + class SVertexNormalTransformManipulator : public IVertexManipulator + { + public: + SVertexNormalTransformManipulator(const core::matrix4& m) : Transformation(m) {} + template + void operator()(VType& vertex) const + { + Transformation.transformVect(vertex.Normal); + } + private: + core::matrix4 Transformation; + }; + + //! Vertex manipulator which scales the TCoords of the vertex + class SVertexTCoordsScaleManipulator : public IVertexManipulator + { + public: + SVertexTCoordsScaleManipulator(const core::vector2df& factor, u32 uvSet=1) : Factor(factor), UVSet(uvSet) {} + void operator()(video::S3DVertex2TCoords& vertex) const + { + if (1==UVSet) + vertex.TCoords *= Factor; + else if (2==UVSet) + vertex.TCoords2 *= Factor; + } + template + void operator()(VType& vertex) const + { + if (1==UVSet) + vertex.TCoords *= Factor; + } + private: + core::vector2df Factor; + u32 UVSet; + }; + +} // end namespace scene +} // end namespace irr + + +#endif diff --git a/include/SViewFrustum.h b/include/SViewFrustum.h new file mode 100644 index 00000000..1b522976 --- /dev/null +++ b/include/SViewFrustum.h @@ -0,0 +1,462 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __S_VIEW_FRUSTUM_H_INCLUDED__ +#define __S_VIEW_FRUSTUM_H_INCLUDED__ + +#include "plane3d.h" +#include "vector3d.h" +#include "line3d.h" +#include "aabbox3d.h" +#include "matrix4.h" +#include "IVideoDriver.h" + +namespace irr +{ +namespace scene +{ + + //! Defines the view frustum. That's the space visible by the camera. + /** The view frustum is enclosed by 6 planes. These six planes share + eight points. A bounding box around these eight points is also stored in + this structure. + */ + struct SViewFrustum + { + enum VFPLANES + { + //! Far plane of the frustum. That is the plane furthest away from the eye. + VF_FAR_PLANE = 0, + //! Near plane of the frustum. That is the plane nearest to the eye. + VF_NEAR_PLANE, + //! Left plane of the frustum. + VF_LEFT_PLANE, + //! Right plane of the frustum. + VF_RIGHT_PLANE, + //! Bottom plane of the frustum. + VF_BOTTOM_PLANE, + //! Top plane of the frustum. + VF_TOP_PLANE, + + //! Amount of planes enclosing the view frustum. Should be 6. + VF_PLANE_COUNT + }; + + + //! Default Constructor + SViewFrustum() : BoundingRadius(0.f), FarNearDistance(0.f) {} + + //! Copy Constructor + SViewFrustum(const SViewFrustum& other); + + //! This constructor creates a view frustum based on a projection and/or view matrix. + //\param zClipFromZero: Clipping of z can be projected from 0 to w when true (D3D style) and from -w to w when false (OGL style). + SViewFrustum(const core::matrix4& mat, bool zClipFromZero); + + //! This constructor creates a view frustum based on a projection and/or view matrix. + //\param zClipFromZero: Clipping of z can be projected from 0 to w when true (D3D style) and from -w to w when false (OGL style). + inline void setFrom(const core::matrix4& mat, bool zClipFromZero); + + //! transforms the frustum by the matrix + /** \param mat: Matrix by which the view frustum is transformed.*/ + void transform(const core::matrix4& mat); + + //! returns the point which is on the far left upper corner inside the the view frustum. + core::vector3df getFarLeftUp() const; + + //! returns the point which is on the far left bottom corner inside the the view frustum. + core::vector3df getFarLeftDown() const; + + //! returns the point which is on the far right top corner inside the the view frustum. + core::vector3df getFarRightUp() const; + + //! returns the point which is on the far right bottom corner inside the the view frustum. + core::vector3df getFarRightDown() const; + + //! returns the point which is on the near left upper corner inside the the view frustum. + core::vector3df getNearLeftUp() const; + + //! returns the point which is on the near left bottom corner inside the the view frustum. + core::vector3df getNearLeftDown() const; + + //! returns the point which is on the near right top corner inside the the view frustum. + core::vector3df getNearRightUp() const; + + //! returns the point which is on the near right bottom corner inside the the view frustum. + core::vector3df getNearRightDown() const; + + //! returns a bounding box enclosing the whole view frustum + const core::aabbox3d &getBoundingBox() const; + + //! recalculates the bounding box and sphere based on the planes + inline void recalculateBoundingBox(); + + //! get the bounding sphere's radius (of an optimized sphere, not the AABB's) + float getBoundingRadius() const; + + //! get the bounding sphere's radius (of an optimized sphere, not the AABB's) + core::vector3df getBoundingCenter() const; + + //! the cam should tell the frustum the distance between far and near + void setFarNearDistance(float distance); + + //! get the given state's matrix based on frustum E_TRANSFORMATION_STATE + core::matrix4& getTransform( video::E_TRANSFORMATION_STATE state); + + //! get the given state's matrix based on frustum E_TRANSFORMATION_STATE + const core::matrix4& getTransform( video::E_TRANSFORMATION_STATE state) const; + + //! clips a line to the view frustum. + /** \return True if the line was clipped, false if not */ + bool clipLine(core::line3d& line) const; + + //! the position of the camera + core::vector3df cameraPosition; + + //! all planes enclosing the view frustum. + core::plane3d planes[VF_PLANE_COUNT]; + + //! bounding box around the view frustum + core::aabbox3d boundingBox; + + private: + //! Hold a copy of important transform matrices + enum E_TRANSFORMATION_STATE_FRUSTUM + { + ETS_VIEW = 0, + ETS_PROJECTION = 1, + ETS_COUNT_FRUSTUM + }; + + //! recalculates the bounding sphere based on the planes + inline void recalculateBoundingSphere(); + + //! Hold a copy of important transform matrices + core::matrix4 Matrices[ETS_COUNT_FRUSTUM]; + + float BoundingRadius; + float FarNearDistance; + core::vector3df BoundingCenter; + }; + + + /*! + Copy constructor ViewFrustum + */ + inline SViewFrustum::SViewFrustum(const SViewFrustum& other) + { + cameraPosition=other.cameraPosition; + boundingBox=other.boundingBox; + + u32 i; + for (i=0; i &SViewFrustum::getBoundingBox() const + { + return boundingBox; + } + + inline void SViewFrustum::recalculateBoundingBox() + { + boundingBox.reset(getNearLeftUp()); + boundingBox.addInternalPoint(getNearRightUp()); + boundingBox.addInternalPoint(getNearLeftDown()); + boundingBox.addInternalPoint(getNearRightDown()); + boundingBox.addInternalPoint(getFarRightUp()); + boundingBox.addInternalPoint(getFarLeftDown()); + boundingBox.addInternalPoint(getFarRightDown()); + boundingBox.addInternalPoint(getFarLeftUp()); + + // Also recalculate the bounding sphere when the bbox changes + recalculateBoundingSphere(); + } + + inline float SViewFrustum::getBoundingRadius() const + { + return BoundingRadius; + } + + inline core::vector3df SViewFrustum::getBoundingCenter() const + { + return BoundingCenter; + } + + inline void SViewFrustum::setFarNearDistance(float distance) + { + FarNearDistance = distance; + } + + //! This constructor creates a view frustum based on a projection + //! and/or view matrix. + inline void SViewFrustum::setFrom(const core::matrix4& mat, bool zClipFromZero) + { + // left clipping plane + planes[VF_LEFT_PLANE].Normal.X = mat[3 ] + mat[0]; + planes[VF_LEFT_PLANE].Normal.Y = mat[7 ] + mat[4]; + planes[VF_LEFT_PLANE].Normal.Z = mat[11] + mat[8]; + planes[VF_LEFT_PLANE].D = mat[15] + mat[12]; + + // right clipping plane + planes[VF_RIGHT_PLANE].Normal.X = mat[3 ] - mat[0]; + planes[VF_RIGHT_PLANE].Normal.Y = mat[7 ] - mat[4]; + planes[VF_RIGHT_PLANE].Normal.Z = mat[11] - mat[8]; + planes[VF_RIGHT_PLANE].D = mat[15] - mat[12]; + + // top clipping plane + planes[VF_TOP_PLANE].Normal.X = mat[3 ] - mat[1]; + planes[VF_TOP_PLANE].Normal.Y = mat[7 ] - mat[5]; + planes[VF_TOP_PLANE].Normal.Z = mat[11] - mat[9]; + planes[VF_TOP_PLANE].D = mat[15] - mat[13]; + + // bottom clipping plane + planes[VF_BOTTOM_PLANE].Normal.X = mat[3 ] + mat[1]; + planes[VF_BOTTOM_PLANE].Normal.Y = mat[7 ] + mat[5]; + planes[VF_BOTTOM_PLANE].Normal.Z = mat[11] + mat[9]; + planes[VF_BOTTOM_PLANE].D = mat[15] + mat[13]; + + // far clipping plane + planes[VF_FAR_PLANE].Normal.X = mat[3 ] - mat[2]; + planes[VF_FAR_PLANE].Normal.Y = mat[7 ] - mat[6]; + planes[VF_FAR_PLANE].Normal.Z = mat[11] - mat[10]; + planes[VF_FAR_PLANE].D = mat[15] - mat[14]; + + // near clipping plane + if ( zClipFromZero ) + { + planes[VF_NEAR_PLANE].Normal.X = mat[2]; + planes[VF_NEAR_PLANE].Normal.Y = mat[6]; + planes[VF_NEAR_PLANE].Normal.Z = mat[10]; + planes[VF_NEAR_PLANE].D = mat[14]; + } + else + { + // near clipping plane + planes[VF_NEAR_PLANE].Normal.X = mat[3 ] + mat[2]; + planes[VF_NEAR_PLANE].Normal.Y = mat[7 ] + mat[6]; + planes[VF_NEAR_PLANE].Normal.Z = mat[11] + mat[10]; + planes[VF_NEAR_PLANE].D = mat[15] + mat[14]; + } + + // normalize normals + u32 i; + for ( i=0; i != VF_PLANE_COUNT; ++i) + { + const f32 len = -core::reciprocal_squareroot( + planes[i].Normal.getLengthSQ()); + planes[i].Normal *= len; + planes[i].D *= len; + } + + // make bounding box + recalculateBoundingBox(); + } + + /*! + View Frustum depends on Projection & View Matrix + */ + inline core::matrix4& SViewFrustum::getTransform(video::E_TRANSFORMATION_STATE state) + { + u32 index = 0; + switch ( state ) + { + case video::ETS_PROJECTION: + index = SViewFrustum::ETS_PROJECTION; break; + case video::ETS_VIEW: + index = SViewFrustum::ETS_VIEW; break; + default: + break; + } + return Matrices [ index ]; + } + + /*! + View Frustum depends on Projection & View Matrix + */ + inline const core::matrix4& SViewFrustum::getTransform(video::E_TRANSFORMATION_STATE state) const + { + u32 index = 0; + switch ( state ) + { + case video::ETS_PROJECTION: + index = SViewFrustum::ETS_PROJECTION; break; + case video::ETS_VIEW: + index = SViewFrustum::ETS_VIEW; break; + default: + break; + } + return Matrices [ index ]; + } + + //! Clips a line to the frustum + inline bool SViewFrustum::clipLine(core::line3d& line) const + { + bool wasClipped = false; + for (u32 i=0; i < VF_PLANE_COUNT; ++i) + { + if (planes[i].classifyPointRelation(line.start) == core::ISREL3D_FRONT) + { + line.start = line.start.getInterpolated(line.end, + 1.f-planes[i].getKnownIntersectionWithLine(line.start, line.end)); + wasClipped = true; + } + if (planes[i].classifyPointRelation(line.end) == core::ISREL3D_FRONT) + { + line.end = line.start.getInterpolated(line.end, + 1.f-planes[i].getKnownIntersectionWithLine(line.start, line.end)); + wasClipped = true; + } + } + return wasClipped; + } + + inline void SViewFrustum::recalculateBoundingSphere() + { + // Find the center + const float shortlen = (getNearLeftUp() - getNearRightUp()).getLength(); + const float longlen = (getFarLeftUp() - getFarRightUp()).getLength(); + + const float farlen = FarNearDistance; + const float fartocenter = (farlen + (shortlen - longlen) * (shortlen + longlen)/(4*farlen)) / 2; + const float neartocenter = farlen - fartocenter; + + BoundingCenter = cameraPosition + -planes[VF_NEAR_PLANE].Normal * neartocenter; + + // Find the radius + core::vector3df dir[8]; + dir[0] = getFarLeftUp() - BoundingCenter; + dir[1] = getFarRightUp() - BoundingCenter; + dir[2] = getFarLeftDown() - BoundingCenter; + dir[3] = getFarRightDown() - BoundingCenter; + dir[4] = getNearRightDown() - BoundingCenter; + dir[5] = getNearLeftDown() - BoundingCenter; + dir[6] = getNearRightUp() - BoundingCenter; + dir[7] = getNearLeftUp() - BoundingCenter; + + u32 i = 0; + float diam[8] = { 0.f }; + + for (i = 0; i < 8; ++i) + diam[i] = dir[i].getLengthSQ(); + + float longest = 0; + + for (i = 0; i < 8; ++i) + { + if (diam[i] > longest) + longest = diam[i]; + } + + BoundingRadius = sqrtf(longest); + } + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/SceneParameters.h b/include/SceneParameters.h new file mode 100644 index 00000000..4e246902 --- /dev/null +++ b/include/SceneParameters.h @@ -0,0 +1,182 @@ +// Copyright (C) 2002-2012 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_PARAMETERS_H_INCLUDED__ +#define __I_SCENE_PARAMETERS_H_INCLUDED__ + +/*! \file SceneParameters.h + \brief Header file containing all scene parameters for modifying mesh loading etc. + + This file includes all parameter names which can be set using ISceneManager::getParameters() + to modify the behavior of plugins and mesh loaders. +*/ + +namespace irr +{ +namespace scene +{ + //! Name of the parameter for changing how Irrlicht handles the ZWrite flag for transparent (blending) materials + /** The default behavior in Irrlicht is to disable writing to the + z-buffer for all really transparent, i.e. blending materials. This + avoids problems with intersecting faces, but can also break renderings. + If transparent materials should use the SMaterial flag for ZWriteEnable + just as other material types use this attribute. + Use it like this: + \code + SceneManager->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true); + \endcode + **/ + const c8* const ALLOW_ZWRITE_ON_TRANSPARENT = "Allow_ZWrite_On_Transparent"; + + //! Deprecated, use IMeshLoader::getMeshTextureLoader()->setTexturePath instead. + /** Was used for changing the texture path of the built-in csm loader like this: + \code + SceneManager->getParameters()->setAttribute(scene::CSM_TEXTURE_PATH, "path/to/your/textures"); + \endcode + **/ + const c8* const CSM_TEXTURE_PATH = "CSM_TexturePath"; + + //! Deprecated, use IMeshLoader::getMeshTextureLoader()->setTexturePath instead. + /** Was used for changing the texture path of the built-in lmts loader like this: + \code + SceneManager->getParameters()->setAttribute(scene::LMTS_TEXTURE_PATH, "path/to/your/textures"); + \endcode + **/ + const c8* const LMTS_TEXTURE_PATH = "LMTS_TexturePath"; + + //! Deprecated, use IMeshLoader::getMeshTextureLoader()->setTexturePath instead. + /** Was used for changing the texture path of the built-in MY3D loader like this: + \code + SceneManager->getParameters()->setAttribute(scene::MY3D_TEXTURE_PATH, "path/to/your/textures"); + \endcode + **/ + const c8* const MY3D_TEXTURE_PATH = "MY3D_TexturePath"; + + //! Name of the parameter specifying the COLLADA mesh loading mode + /** + Specifies if the COLLADA loader should create instances of the models, lights and + cameras when loading COLLADA meshes. By default, this is set to false. If this is + set to true, the ISceneManager::getMesh() method will only return a pointer to a + dummy mesh and create instances of all meshes and lights and cameras in the collada + file by itself. Example: + \code + SceneManager->getParameters()->setAttribute(scene::COLLADA_CREATE_SCENE_INSTANCES, true); + \endcode + */ + const c8* const COLLADA_CREATE_SCENE_INSTANCES = "COLLADA_CreateSceneInstances"; + + //! Deprecated, use IMeshLoader::getMeshTextureLoader()->setTexturePath instead. + /** This path is prefixed to the file names defined in the Deled file when loading + textures. This allows to alter the paths for a specific project setting. + Use it like this: + \code + SceneManager->getStringParameters()->setAttribute(scene::DMF_TEXTURE_PATH, "path/to/your/textures"); + \endcode + **/ + const c8* const DMF_TEXTURE_PATH = "DMF_TexturePath"; + + //! Name of the parameter for preserving DMF textures dir structure with built-in DMF loader. + /** If this parameter is set to true, the texture directory defined in the Deled file + is ignored, and only the texture name is used to find the proper file. Otherwise, the + texture path is also used, which allows to use a nicer media layout. + Use it like this: + \code + //this way you won't use this setting (default) + SceneManager->getParameters()->setAttribute(scene::DMF_IGNORE_MATERIALS_DIRS, false); + \endcode + \code + //this way you'll use this setting + SceneManager->getParameters()->setAttribute(scene::DMF_IGNORE_MATERIALS_DIRS, true); + \endcode + **/ + const c8* const DMF_IGNORE_MATERIALS_DIRS = "DMF_IgnoreMaterialsDir"; + + //! Name of the parameter for setting reference value of alpha in transparent materials. + /** Use it like this: + \code + //this way you'll set alpha ref to 0.1 + SceneManager->getParameters()->setAttribute(scene::DMF_ALPHA_CHANNEL_REF, 0.1); + \endcode + **/ + const c8* const DMF_ALPHA_CHANNEL_REF = "DMF_AlphaRef"; + + //! Name of the parameter for choose to flip or not tga files. + /** Use it like this: + \code + //this way you'll choose to flip alpha textures + SceneManager->getParameters()->setAttribute(scene::DMF_FLIP_ALPHA_TEXTURES, true); + \endcode + **/ + const c8* const DMF_FLIP_ALPHA_TEXTURES = "DMF_FlipAlpha"; + + + //! Deprecated, use IMeshLoader::getMeshTextureLoader()->setTexturePath instead. + /** Was used for changing the texture path of the built-in obj loader like this: + \code + SceneManager->getParameters()->setAttribute(scene::OBJ_TEXTURE_PATH, "path/to/your/textures"); + \endcode + **/ + const c8* const OBJ_TEXTURE_PATH = "OBJ_TexturePath"; + + //! Flag to avoid loading group structures in .obj files + /** Use it like this: + \code + SceneManager->getParameters()->setAttribute(scene::OBJ_LOADER_IGNORE_GROUPS, true); + \endcode + **/ + const c8* const OBJ_LOADER_IGNORE_GROUPS = "OBJ_IgnoreGroups"; + + + //! Flag to avoid loading material .mtl file for .obj files + /** Use it like this: + \code + SceneManager->getParameters()->setAttribute(scene::OBJ_LOADER_IGNORE_MATERIAL_FILES, true); + \endcode + **/ + const c8* const OBJ_LOADER_IGNORE_MATERIAL_FILES = "OBJ_IgnoreMaterialFiles"; + + + //! 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"; + + //! Deprecated, use IMeshLoader::getMeshTextureLoader()->setTexturePath instead. + /** Was used for changing the texture path of the built-in b3d loader like this: + \code + SceneManager->getParameters()->setAttribute(scene::B3D_TEXTURE_PATH, "path/to/your/textures"); + \endcode + **/ + const c8* const B3D_TEXTURE_PATH = "B3D_TexturePath"; + + //! 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 */ + const c8* const IRR_SCENE_MANAGER_IS_EDITOR = "IRR_Editor"; + + //! Name of the parameter for setting the length of debug normals. + /** Use it like this: + \code + SceneManager->getParameters()->setAttribute(scene::DEBUG_NORMAL_LENGTH, 1.5f); + \endcode + **/ + const c8* const DEBUG_NORMAL_LENGTH = "DEBUG_Normal_Length"; + + //! Name of the parameter for setting the color of debug normals. + /** Use it like this: + \code + SceneManager->getParameters()->setAttributeAsColor(scene::DEBUG_NORMAL_COLOR, video::SColor(255, 255, 255, 255)); + \endcode + **/ + const c8* const DEBUG_NORMAL_COLOR = "DEBUG_Normal_Color"; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/aabbox3d.h b/include/aabbox3d.h new file mode 100644 index 00000000..27dfc384 --- /dev/null +++ b/include/aabbox3d.h @@ -0,0 +1,369 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_AABBOX_3D_H_INCLUDED__ +#define __IRR_AABBOX_3D_H_INCLUDED__ + +#include "irrMath.h" +#include "plane3d.h" +#include "line3d.h" + +namespace irr +{ +namespace core +{ + +//! Axis aligned bounding box in 3d dimensional space. +/** Has some useful methods used with occlusion culling or clipping. +*/ +template +class aabbox3d +{ + public: + + //! Default Constructor. + aabbox3d(): MinEdge(-1,-1,-1), MaxEdge(1,1,1) {} + //! Constructor with min edge and max edge. + aabbox3d(const vector3d& min, const vector3d& max): MinEdge(min), MaxEdge(max) {} + //! Constructor with only one point. + aabbox3d(const vector3d& init): MinEdge(init), MaxEdge(init) {} + //! Constructor with min edge and max edge as single values, not vectors. + aabbox3d(T minx, T miny, T minz, T maxx, T maxy, T maxz): MinEdge(minx, miny, minz), MaxEdge(maxx, maxy, maxz) {} + + // operators + //! Equality operator + /** \param other box to compare with. + \return True if both boxes are equal, else false. */ + inline bool operator==(const aabbox3d& other) const { return (MinEdge == other.MinEdge && other.MaxEdge == MaxEdge);} + //! Inequality operator + /** \param other box to compare with. + \return True if both boxes are different, else false. */ + inline bool operator!=(const aabbox3d& other) const { return !(MinEdge == other.MinEdge && other.MaxEdge == MaxEdge);} + + // functions + + //! Resets the bounding box to a one-point box. + /** \param x X coord of the point. + \param y Y coord of the point. + \param z Z coord of the point. */ + void reset(T x, T y, T z) + { + MaxEdge.set(x,y,z); + MinEdge = MaxEdge; + } + + //! Resets the bounding box. + /** \param initValue New box to set this one to. */ + void reset(const aabbox3d& initValue) + { + *this = initValue; + } + + //! Resets the bounding box to a one-point box. + /** \param initValue New point. */ + void reset(const vector3d& initValue) + { + MaxEdge = initValue; + MinEdge = initValue; + } + + //! Adds a point to the bounding box + /** The box grows bigger, if point was outside of the box. + \param p: Point to add into the box. */ + void addInternalPoint(const vector3d& p) + { + addInternalPoint(p.X, p.Y, p.Z); + } + + //! Adds another bounding box + /** The box grows bigger, if the new box was outside of the box. + \param b: Other bounding box to add into this box. */ + void addInternalBox(const aabbox3d& b) + { + addInternalPoint(b.MaxEdge); + addInternalPoint(b.MinEdge); + } + + //! Adds a point to the bounding box + /** The box grows bigger, if point is outside of the box. + \param x X coordinate of the point to add to this box. + \param y Y coordinate of the point to add to this box. + \param z Z coordinate of the point to add to this box. */ + void addInternalPoint(T x, T y, T z) + { + if (x>MaxEdge.X) MaxEdge.X = x; + if (y>MaxEdge.Y) MaxEdge.Y = y; + if (z>MaxEdge.Z) MaxEdge.Z = z; + + if (x getCenter() const + { + return (MinEdge + MaxEdge) / 2; + } + + //! Get extent of the box (maximal distance of two points in the box) + /** \return Extent of the bounding box. */ + vector3d getExtent() const + { + return MaxEdge - MinEdge; + } + + //! Get radius of the bounding sphere + /** \return Radius of the bounding sphere. */ + T getRadius() const + { + const T radius = getExtent().getLength() / 2; + return radius; + } + + //! Check if the box is empty. + /** This means that there is no space between the min and max edge. + \return True if box is empty, else false. */ + bool isEmpty() const + { + return MinEdge.equals ( MaxEdge ); + } + + //! Get the volume enclosed by the box in cubed units + T getVolume() const + { + const vector3d e = getExtent(); + return e.X * e.Y * e.Z; + } + + //! Get the surface area of the box in squared units + T getArea() const + { + const vector3d e = getExtent(); + return 2*(e.X*e.Y + e.X*e.Z + e.Y*e.Z); + } + + //! Stores all 8 edges of the box into an array + /** \param edges: Pointer to array of 8 edges. */ + void getEdges(vector3d *edges) const + { + const core::vector3d middle = getCenter(); + const core::vector3d diag = middle - MaxEdge; + + /* + Edges are stored in this way: + Hey, am I an ascii artist, or what? :) niko. + /3--------/7 + / | / | + / | / | + 1---------5 | + | /2- - -|- -6 + | / | / + |/ | / + 0---------4/ + */ + + edges[0].set(middle.X + diag.X, middle.Y + diag.Y, middle.Z + diag.Z); + edges[1].set(middle.X + diag.X, middle.Y - diag.Y, middle.Z + diag.Z); + edges[2].set(middle.X + diag.X, middle.Y + diag.Y, middle.Z - diag.Z); + edges[3].set(middle.X + diag.X, middle.Y - diag.Y, middle.Z - diag.Z); + edges[4].set(middle.X - diag.X, middle.Y + diag.Y, middle.Z + diag.Z); + edges[5].set(middle.X - diag.X, middle.Y - diag.Y, middle.Z + diag.Z); + edges[6].set(middle.X - diag.X, middle.Y + diag.Y, middle.Z - diag.Z); + edges[7].set(middle.X - diag.X, middle.Y - diag.Y, middle.Z - diag.Z); + } + + //! Repairs the box. + /** Necessary if for example MinEdge and MaxEdge are swapped. */ + void repair() + { + T t; + + if (MinEdge.X > MaxEdge.X) + { t=MinEdge.X; MinEdge.X = MaxEdge.X; MaxEdge.X=t; } + if (MinEdge.Y > MaxEdge.Y) + { t=MinEdge.Y; MinEdge.Y = MaxEdge.Y; MaxEdge.Y=t; } + if (MinEdge.Z > MaxEdge.Z) + { t=MinEdge.Z; MinEdge.Z = MaxEdge.Z; MaxEdge.Z=t; } + } + + // Check if MaxEdge > MinEdge + bool isValid() const + { + if (MinEdge.X > MaxEdge.X) return false; + if (MinEdge.Y > MaxEdge.Y) return false; + if (MinEdge.Z > MaxEdge.Z) return false; + + return true; + } + + //! Calculates a new interpolated bounding box. + /** d=0 returns other, d=1 returns this, all other values blend between + the two boxes. + \param other Other box to interpolate between + \param d Value between 0.0f and 1.0f. + \return Interpolated box. */ + aabbox3d getInterpolated(const aabbox3d& other, f32 d) const + { + f32 inv = 1.0f - d; + return aabbox3d((other.MinEdge*inv) + (MinEdge*d), + (other.MaxEdge*inv) + (MaxEdge*d)); + } + + //! Determines if a point is within this box. + /** Border is included (IS part of the box)! + \param p: Point to check. + \return True if the point is within the box and false if not */ + bool isPointInside(const vector3d& p) const + { + return (p.X >= MinEdge.X && p.X <= MaxEdge.X && + p.Y >= MinEdge.Y && p.Y <= MaxEdge.Y && + p.Z >= MinEdge.Z && p.Z <= MaxEdge.Z); + } + + //! Determines if a point is within this box and not its borders. + /** Border is excluded (NOT part of the box)! + \param p: Point to check. + \return True if the point is within the box and false if not. */ + bool isPointTotalInside(const vector3d& p) const + { + return (p.X > MinEdge.X && p.X < MaxEdge.X && + p.Y > MinEdge.Y && p.Y < MaxEdge.Y && + p.Z > MinEdge.Z && p.Z < MaxEdge.Z); + } + + //! Check if this box is completely inside the 'other' box. + /** \param other: Other box to check against. + \return True if this box is completely inside the other box, + otherwise false. */ + bool isFullInside(const aabbox3d& other) const + { + return (MinEdge.X >= other.MinEdge.X && MinEdge.Y >= other.MinEdge.Y && MinEdge.Z >= other.MinEdge.Z && + MaxEdge.X <= other.MaxEdge.X && MaxEdge.Y <= other.MaxEdge.Y && MaxEdge.Z <= other.MaxEdge.Z); + } + + //! Returns the intersection of this box with another, if possible. + aabbox3d intersect(const aabbox3d& other) const + { + aabbox3d out; + + if (!intersectsWithBox(other)) + return out; + + out.MaxEdge.X = min_(MaxEdge.X, other.MaxEdge.X); + out.MaxEdge.Y = min_(MaxEdge.Y, other.MaxEdge.Y); + out.MaxEdge.Z = min_(MaxEdge.Z, other.MaxEdge.Z); + + out.MinEdge.X = max_(MinEdge.X, other.MinEdge.X); + out.MinEdge.Y = max_(MinEdge.Y, other.MinEdge.Y); + out.MinEdge.Z = max_(MinEdge.Z, other.MinEdge.Z); + + return out; + } + + //! Determines if the axis-aligned box intersects with another axis-aligned box. + /** \param other: Other box to check a intersection with. + \return True if there is an intersection with the other box, + otherwise false. */ + bool intersectsWithBox(const aabbox3d& other) const + { + return (MinEdge.X <= other.MaxEdge.X && MinEdge.Y <= other.MaxEdge.Y && MinEdge.Z <= other.MaxEdge.Z && + MaxEdge.X >= other.MinEdge.X && MaxEdge.Y >= other.MinEdge.Y && MaxEdge.Z >= other.MinEdge.Z); + } + + //! Tests if the box intersects with a line + /** \param line: Line to test intersection with. + \return True if there is an intersection , else false. */ + bool intersectsWithLine(const line3d& line) const + { + return intersectsWithLine(line.getMiddle(), line.getVector().normalize(), + (T)(line.getLength() * 0.5)); + } + + //! Tests if the box intersects with a line + /** \param linemiddle Center of the line. + \param linevect Vector of the line. + \param halflength Half length of the line. + \return True if there is an intersection, else false. */ + bool intersectsWithLine(const vector3d& linemiddle, + const vector3d& linevect, T halflength) const + { + const vector3d e = getExtent() * (T)0.5; + const vector3d t = getCenter() - linemiddle; + + if ((fabs(t.X) > e.X + halflength * fabs(linevect.X)) || + (fabs(t.Y) > e.Y + halflength * fabs(linevect.Y)) || + (fabs(t.Z) > e.Z + halflength * fabs(linevect.Z)) ) + return false; + + T r = e.Y * (T)fabs(linevect.Z) + e.Z * (T)fabs(linevect.Y); + if (fabs(t.Y*linevect.Z - t.Z*linevect.Y) > r ) + return false; + + r = e.X * (T)fabs(linevect.Z) + e.Z * (T)fabs(linevect.X); + if (fabs(t.Z*linevect.X - t.X*linevect.Z) > r ) + return false; + + r = e.X * (T)fabs(linevect.Y) + e.Y * (T)fabs(linevect.X); + if (fabs(t.X*linevect.Y - t.Y*linevect.X) > r) + return false; + + return true; + } + + //! Classifies a relation with a plane. + /** \param plane Plane to classify relation to. + \return Returns ISREL3D_FRONT if the box is in front of the plane, + ISREL3D_BACK if the box is behind the plane, and + ISREL3D_CLIPPED if it is on both sides of the plane. */ + EIntersectionRelation3D classifyPlaneRelation(const plane3d& plane) const + { + vector3d nearPoint(MaxEdge); + vector3d farPoint(MinEdge); + + if (plane.Normal.X > (T)0) + { + nearPoint.X = MinEdge.X; + farPoint.X = MaxEdge.X; + } + + if (plane.Normal.Y > (T)0) + { + nearPoint.Y = MinEdge.Y; + farPoint.Y = MaxEdge.Y; + } + + if (plane.Normal.Z > (T)0) + { + nearPoint.Z = MinEdge.Z; + farPoint.Z = MaxEdge.Z; + } + + if (plane.Normal.dotProduct(nearPoint) + plane.D > (T)0) + return ISREL3D_FRONT; + + if (plane.Normal.dotProduct(farPoint) + plane.D > (T)0) + return ISREL3D_CLIPPED; + + return ISREL3D_BACK; + } + + //! The near edge + vector3d MinEdge; + + //! The far edge + vector3d MaxEdge; +}; + + //! Typedef for a f32 3d bounding box. + typedef aabbox3d aabbox3df; + //! Typedef for an integer 3d bounding box. + typedef aabbox3d aabbox3di; + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/include/coreutil.h b/include/coreutil.h new file mode 100644 index 00000000..b4d5e19f --- /dev/null +++ b/include/coreutil.h @@ -0,0 +1,205 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_CORE_UTIL_H_INCLUDED__ +#define __IRR_CORE_UTIL_H_INCLUDED__ + +#include "irrString.h" +#include "path.h" + +namespace irr +{ +namespace core +{ + +/*! \file coreutil.h + \brief File containing useful basic utility functions +*/ + +// ----------- some basic quite often used string functions ----------------- + +//! search if a filename has a proper extension +inline s32 isFileExtension (const io::path& filename, const io::path& ext0, + const io::path& ext1, const io::path& ext2) +{ + s32 extPos = filename.findLast ( '.' ); + if ( extPos < 0 ) + return 0; + + extPos += 1; + if ( filename.equals_substring_ignore_case ( ext0, extPos ) ) + return 1; + if ( filename.equals_substring_ignore_case ( ext1, extPos ) ) + return 2; + if ( filename.equals_substring_ignore_case ( ext2, extPos ) ) + return 3; + return 0; +} + +//! search if a filename has a proper extension +inline bool hasFileExtension(const io::path& filename, const io::path& ext0, + const io::path& ext1 = "", const io::path& ext2 = "") +{ + return isFileExtension ( filename, ext0, ext1, ext2 ) > 0; +} + +//! cut the filename extension from a source file path and store it in a dest file path +inline io::path& cutFilenameExtension ( io::path &dest, const io::path &source ) +{ + s32 endPos = source.findLast ( '.' ); + dest = source.subString ( 0, endPos < 0 ? source.size () : endPos ); + return dest; +} + +//! get the filename extension from a file path +inline io::path& getFileNameExtension ( io::path &dest, const io::path &source ) +{ + s32 endPos = source.findLast ( '.' ); + if ( endPos < 0 ) + dest = ""; + else + dest = source.subString ( endPos, source.size () ); + return dest; +} + +//! delete path from filename +inline io::path& deletePathFromFilename(io::path& filename) +{ + // delete path from filename + const fschar_t* s = filename.c_str(); + const fschar_t* p = s + filename.size(); + + // search for path separator or beginning + while ( *p != '/' && *p != '\\' && p != s ) + p--; + + if ( p != s ) + { + ++p; + filename = p; + } + return filename; +} + +//! trim paths +inline io::path& deletePathFromPath(io::path& filename, s32 pathCount) +{ + // delete path from filename + s32 i = filename.size(); + + // search for path separator or beginning + while ( i>=0 ) + { + if ( filename[i] == '/' || filename[i] == '\\' ) + { + if ( --pathCount <= 0 ) + break; + } + --i; + } + + if ( i>0 ) + { + filename [ i + 1 ] = 0; + filename.validate(); + } + else + filename=""; + return filename; +} + +//! looks if file is in the same directory of path. returns offset of directory. +//! 0 means in same directory. 1 means file is direct child of path +inline s32 isInSameDirectory ( const io::path& path, const io::path& file ) +{ + if ( path.size() && !path.equalsn ( file, path.size() ) ) + return -1; + + s32 subA = 0; + s32 subB = 0; + s32 pos = 0; + while ( (pos = path.findNext ( '/', pos )) >= 0 ) + { + subA += 1; + pos += 1; + } + + pos = 0; + while ( (pos = file.findNext ( '/', pos )) >= 0 ) + { + subB += 1; + pos += 1; + } + + return subB - subA; +} + +//! splits a path into components +static inline void splitFilename(const io::path &name, io::path* path=0, + io::path* filename=0, io::path* extension=0, bool make_lower=false) +{ + s32 i = name.size(); + s32 extpos = i; + + // search for path separator or beginning + while ( i >= 0 ) + { + if ( name[i] == '.' ) + { + extpos = i; + if ( extension ) + *extension = name.subString ( extpos + 1, name.size() - (extpos + 1), make_lower ); + } + else + if ( name[i] == '/' || name[i] == '\\' ) + { + if ( filename ) + *filename = name.subString ( i + 1, extpos - (i + 1), make_lower ); + if ( path ) + { + *path = name.subString ( 0, i + 1, make_lower ); + path->replace ( '\\', '/' ); + } + return; + } + i -= 1; + } + if ( filename ) + *filename = name.subString ( 0, extpos, make_lower ); +} + +//! create a filename from components +static inline io::path mergeFilename(const io::path& path, const io::path& filename, const io::path& extension = "") +{ + io::path result(path); + + if ( !result.empty() ) + { + fschar_t last = result.lastChar(); + if ( last != _IRR_TEXT('/') && last != _IRR_TEXT('\\') ) + result += _IRR_TEXT('/'); + } + if ( !filename.empty() ) + result += filename; + if ( !extension.empty() ) + { + if ( !result.empty() && extension[0] != _IRR_TEXT('.') ) + result += _IRR_TEXT('.'); + result += extension; + } + + return result; +} + + +//! some standard function ( to remove dependencies ) +inline s32 isdigit(s32 c) { return c >= '0' && c <= '9'; } +inline s32 isspace(s32 c) { return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v'; } +inline s32 isupper(s32 c) { return c >= 'A' && c <= 'Z'; } + + +} // end namespace core +} // end namespace irr + +#endif diff --git a/include/dimension2d.h b/include/dimension2d.h new file mode 100644 index 00000000..4f0a87a1 --- /dev/null +++ b/include/dimension2d.h @@ -0,0 +1,224 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_DIMENSION2D_H_INCLUDED__ +#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 + class dimension2d + { + public: + //! Default constructor for empty dimension + dimension2d() : Width(0), Height(0) {} + //! Constructor with width and height + 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) { } + + template + dimension2d& operator=(const dimension2d& other) + { + Width = (T) other.Width; + Height = (T) other.Height; + return *this; + } + + + //! Equality operator + bool operator==(const dimension2d& other) const + { + return core::equals(Width, other.Width) && + core::equals(Height, other.Height); + } + + //! Inequality operator + bool operator!=(const dimension2d& other) const + { + 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) + { + Width = width; + Height = height; + return *this; + } + + //! Divide width and height by scalar + dimension2d& operator/=(const T& scale) + { + Width /= scale; + Height /= scale; + return *this; + } + + //! Divide width and height by scalar + dimension2d operator/(const T& scale) const + { + return dimension2d(Width/scale, Height/scale); + } + + //! Multiply width and height by scalar + dimension2d& operator*=(const T& scale) + { + Width *= scale; + Height *= scale; + return *this; + } + + //! Multiply width and height by scalar + dimension2d operator*(const T& scale) const + { + return dimension2d(Width*scale, Height*scale); + } + + //! Add another dimension to this one. + dimension2d& operator+=(const dimension2d& other) + { + Width += other.Width; + Height += other.Height; + return *this; + } + + //! Add two dimensions + dimension2d operator+(const dimension2d& other) const + { + return dimension2d(Width+other.Width, Height+other.Height); + } + + //! Subtract a dimension from this one + dimension2d& operator-=(const dimension2d& other) + { + Width -= other.Width; + Height -= other.Height; + return *this; + } + + //! Subtract one dimension from another + dimension2d operator-(const dimension2d& other) const + { + return dimension2d(Width-other.Width, Height-other.Height); + } + + //! Get area + T getArea() const + { + return Width*Height; + } + + //! Get the optimal size according to some properties + /** This is a function often used for texture dimension + calculations. The function returns the next larger or + smaller dimension which is a power-of-two dimension + (2^n,2^m) and/or square (Width=Height). + \param requirePowerOfTwo Forces the result to use only + powers of two as values. + \param requireSquare Makes width==height in the result + \param larger Choose whether the result is larger or + smaller than the current dimension. If one dimension + need not be changed it is kept with any value of larger. + \param maxValue Maximum texturesize. if value > 0 size is + clamped to maxValue + \return The optimal dimension under the given + constraints. */ + dimension2d getOptimalSize( + bool requirePowerOfTwo=true, + bool requireSquare=false, + bool larger=true, + u32 maxValue = 0) const + { + u32 i=1; + u32 j=1; + if (requirePowerOfTwo) + { + while (i<(u32)Width) + i<<=1; + if (!larger && i!=1 && i!=(u32)Width) + i>>=1; + while (j<(u32)Height) + j<<=1; + if (!larger && j!=1 && j!=(u32)Height) + j>>=1; + } + else + { + i=(u32)Width; + j=(u32)Height; + } + + if (requireSquare) + { + if ((larger && (i>j)) || (!larger && (i 0 && i > maxValue) + i = maxValue; + + if ( maxValue > 0 && j > maxValue) + j = maxValue; + + return dimension2d((T)i,(T)j); + } + + //! Get the interpolated dimension + /** \param other Other dimension to interpolate with. + \param d Value between 0.0f and 1.0f. d=0 returns other, d=1 returns this, values between interpolate. + \return Interpolated dimension. */ + dimension2d getInterpolated(const dimension2d& other, f32 d) const + { + f32 inv = (1.0f - d); + return dimension2d( (T)(other.Width*inv + Width*d), (T)(other.Height*inv + Height*d)); + } + + + //! Width of the dimension. + T Width; + //! Height of the dimension. + T Height; + }; + + //! 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 + +#endif + diff --git a/include/driverChoice.h b/include/driverChoice.h new file mode 100644 index 00000000..accd4034 --- /dev/null +++ b/include/driverChoice.h @@ -0,0 +1,55 @@ +// Copyright (C) 2009-2012 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __E_DRIVER_CHOICE_H_INCLUDED__ +#define __E_DRIVER_CHOICE_H_INCLUDED__ + +#include +#include +#include "EDriverTypes.h" +#include "IrrlichtDevice.h" + +namespace irr +{ + + //! ask user for driver + static irr::video::E_DRIVER_TYPE driverChoiceConsole(bool allDrivers=false) + { +#if defined (_IRR_IPHONE_PLATFORM_) || defined (_IRR_ANDROID_PLATFORM_) + return irr::video::EDT_OGLES2; +#else + printf("Please select the driver you want:\n"); + irr::u32 i=0; + char c = 'a'; + + for (i=irr::video::EDT_COUNT; i>0; --i) + { + if ( allDrivers || irr::IrrlichtDevice::isDriverSupported(irr::video::E_DRIVER_TYPE(i-1)) ) + { + printf(" (%c) %s\n", c, irr::video::DRIVER_TYPE_NAMES[i-1]); + ++c; + } + } + + char userSelection; + std::cin >> userSelection; + c = 'a'; + + for (i=irr::video::EDT_COUNT; i>0; --i) + { + if ( allDrivers || irr::IrrlichtDevice::isDriverSupported(irr::video::E_DRIVER_TYPE(i-1)) ) + { + if (userSelection == c) + return irr::video::E_DRIVER_TYPE(i-1); + ++c; + } + } + + return irr::video::EDT_COUNT; +#endif + } + +} // end namespace irr + +#endif diff --git a/include/exampleHelper.h b/include/exampleHelper.h new file mode 100755 index 00000000..e1e7cb2e --- /dev/null +++ b/include/exampleHelper.h @@ -0,0 +1,25 @@ +// Copyright (C) 2015 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __EXAMPLE_HELPER_H_INCLUDED__ +#define __EXAMPLE_HELPER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#include "path.h" + +namespace irr +{ + +static io::path getExampleMediaPath() +{ +#if defined (_IRR_IOS_PLATFORM_) || defined (_IRR_ANDROID_PLATFORM_) || defined (_IRR_OSX_PLATFORM_) || defined (_IRR_EMSCRIPTEN_PLATFORM_) + return io::path("media/"); +#else + return io::path("../../media/"); +#endif +} + +} // end namespace irr + +#endif diff --git a/include/fast_atof.h b/include/fast_atof.h new file mode 100644 index 00000000..b829eaec --- /dev/null +++ b/include/fast_atof.h @@ -0,0 +1,374 @@ +// Copyright (C) 2002-2012 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 + +#ifndef __FAST_ATOF_H_INCLUDED__ +#define __FAST_ATOF_H_INCLUDED__ + +#include "irrMath.h" +#include "irrString.h" + +namespace irr +{ +namespace core +{ + //! Selection of characters which count as decimal point in fast_atof + // TODO: This should probably also be used in irr::core::string, but + // the float-to-string code used there has to be rewritten first. + IRRLICHT_API extern irr::core::stringc LOCALE_DECIMAL_POINTS; + +#define IRR_ATOF_TABLE_SIZE 17 +// we write [IRR_ATOF_TABLE_SIZE] here instead of [] to work around a swig bug +const float fast_atof_table[17] = { + 0.f, + 0.1f, + 0.01f, + 0.001f, + 0.0001f, + 0.00001f, + 0.000001f, + 0.0000001f, + 0.00000001f, + 0.000000001f, + 0.0000000001f, + 0.00000000001f, + 0.000000000001f, + 0.0000000000001f, + 0.00000000000001f, + 0.000000000000001f, + 0.0000000000000001f +}; + +//! Convert a simple string of base 10 digits into an unsigned 32 bit integer. +/** \param[in] in: The string of digits to convert. No leading chars are + allowed, only digits 0 to 9. Parsing stops at the first non-digit. + \param[out] out: (optional) If provided, it will be set to point at the + first character not used in the calculation. + \return The unsigned integer value of the digits. If the string specifies + too many digits to encode in an u32 then INT_MAX will be returned. +*/ +inline u32 strtoul10(const char* in, const char** out=0) +{ + if (!in) + { + if (out) + *out = in; + return 0; + } + + bool overflow=false; + u32 unsignedValue = 0; + while ( ( *in >= '0') && ( *in <= '9' )) + { + const u32 tmp = ( unsignedValue * 10 ) + ( *in - '0' ); + if (tmp (u32)INT_MAX) + { + if (negative) + return (s32)INT_MIN; + else + return (s32)INT_MAX; + } + else + { + if (negative) + return -((s32)unsignedValue); + else + return (s32)unsignedValue; + } +} + +//! Convert a hex-encoded character to an unsigned integer. +/** \param[in] in The digit to convert. Only digits 0 to 9 and chars A-F,a-f + will be considered. + \return The unsigned integer value of the digit. 0xffffffff if the input is + not hex +*/ +inline u32 ctoul16(char in) +{ + if (in >= '0' && in <= '9') + return in - '0'; + else if (in >= 'a' && in <= 'f') + return 10u + in - 'a'; + else if (in >= 'A' && in <= 'F') + return 10u + in - 'A'; + else + return 0xffffffff; +} + +//! Convert a simple string of base 16 digits into an unsigned 32 bit integer. +/** \param[in] in: The string of digits to convert. No leading chars are + allowed, only digits 0 to 9 and chars A-F,a-f are allowed. Parsing stops + at the first illegal char. + \param[out] out: (optional) If provided, it will be set to point at the + first character not used in the calculation. + \return The unsigned integer value of the digits. If the string specifies + too many digits to encode in an u32 then INT_MAX will be returned. +*/ +inline u32 strtoul16(const char* in, const char** out=0) +{ + if (!in) + { + if (out) + *out = in; + return 0; + } + + bool overflow=false; + u32 unsignedValue = 0; + while (true) + { + u32 tmp = 0; + if ((*in >= '0') && (*in <= '9')) + tmp = (unsignedValue << 4u) + (*in - '0'); + else if ((*in >= 'A') && (*in <= 'F')) + tmp = (unsignedValue << 4u) + (*in - 'A') + 10; + else if ((*in >= 'a') && (*in <= 'f')) + tmp = (unsignedValue << 4u) + (*in - 'a') + 10; + else + break; + if (tmp= '0') && (*in <= '7')) + tmp = (unsignedValue << 3u) + (*in - '0'); + else + break; + if (tmp= '0') && ( *in <= '9' ) ) + { + // If it looks like we're going to overflow, bail out + // now and start using floating point. + if (intValue >= MAX_SAFE_U32_VALUE) + break; + + intValue = (intValue * 10) + (*in - '0'); + ++in; + } + + f32 floatValue = (f32)intValue; + + // If there are any digits left to parse, then we need to use + // floating point arithmetic from here. + while ( ( *in >= '0') && ( *in <= '9' ) ) + { + floatValue = (floatValue * 10.f) + (f32)(*in - '0'); + ++in; + if (floatValue > FLT_MAX) // Just give up. + break; + } + + if (out) + *out = in; + + return floatValue; +} + +//! Provides a fast function for converting a string into a float. +/** This is not guaranteed to be as accurate as atof(), but is + approximately 6 to 8 times as fast. + \param[in] in The string to convert. + \param[out] result The resultant float will be written here. + \return Pointer to the first character in the string that wasn't used + to create the float value. +*/ +inline const char* fast_atof_move(const char* in, f32& result) +{ + // Please run the regression test when making any modifications to this function. + + result = 0.f; + if (!in) + return 0; + + const bool negative = ('-' == *in); + if (negative || ('+'==*in)) + ++in; + + f32 value = strtof10(in, &in); + + if ( LOCALE_DECIMAL_POINTS.findFirst(*in) >= 0 ) + { + const char* afterDecimal = ++in; + const f32 decimal = strtof10(in, &afterDecimal); + const size_t numDecimals = afterDecimal - in; + if (numDecimals < IRR_ATOF_TABLE_SIZE) + { + value += decimal * fast_atof_table[numDecimals]; + } + else + { + value += decimal * (f32)pow(10.f, -(float)numDecimals); + } + in = afterDecimal; + } + + if ('e' == *in || 'E' == *in) + { + ++in; + // Assume that the exponent is a whole number. + // strtol10() will deal with both + and - signs, + // but calculate as f32 to prevent overflow at FLT_MAX + // Using pow with float cast instead of powf as otherwise accuracy decreases. + value *= (f32)pow(10.f, (f32)strtol10(in, &in)); + } + + result = negative?-value:value; + return in; +} + +//! Convert a string to a floating point number +/** \param floatAsString The string to convert. + \param out Optional pointer to the first character in the string that + wasn't used to create the float value. + \result Float value parsed from the input string +*/ +inline float fast_atof(const char* floatAsString, const char** out=0) +{ + float ret; + if (out) + *out=fast_atof_move(floatAsString, ret); + else + fast_atof_move(floatAsString, ret); + return ret; +} + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/include/heapsort.h b/include/heapsort.h new file mode 100644 index 00000000..36211c4d --- /dev/null +++ b/include/heapsort.h @@ -0,0 +1,70 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_HEAPSORT_H_INCLUDED__ +#define __IRR_HEAPSORT_H_INCLUDED__ + +#include "irrTypes.h" + +namespace irr +{ +namespace core +{ + +//! Sinks an element into the heap. +template +inline void heapsink(T*array, s32 element, s32 max) +{ + while ((element<<1) < max) // there is a left child + { + s32 j = (element<<1); + + if (j+1 < max && array[j] < array[j+1]) + j = j+1; // take right child + + if (array[element] < array[j]) + { + T t = array[j]; // swap elements + array[j] = array[element]; + array[element] = t; + element = j; + } + else + return; + } +} + + +//! Sorts an array with size 'size' using heapsort. +template +inline void heapsort(T* array_, s32 size) +{ + // for heapsink we pretend this is not c++, where + // arrays start with index 0. So we decrease the array pointer, + // the maximum always +2 and the element always +1 + + T* virtualArray = array_ - 1; + s32 virtualSize = size + 2; + s32 i; + + // build heap + + for (i=((size-1)/2); i>=0; --i) + heapsink(virtualArray, i+1, virtualSize-1); + + // sort array, leave out the last element (0) + for (i=size-1; i>0; --i) + { + T t = array_[0]; + array_[0] = array_[i]; + array_[i] = t; + heapsink(virtualArray, 1, i + 1); + } +} + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/include/irrAllocator.h b/include/irrAllocator.h new file mode 100644 index 00000000..c7450ed7 --- /dev/null +++ b/include/irrAllocator.h @@ -0,0 +1,124 @@ +// Copyright (C) 2002-2012 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 + +#ifndef __IRR_ALLOCATOR_H_INCLUDED__ +#define __IRR_ALLOCATOR_H_INCLUDED__ + +#include "irrTypes.h" +#include +// necessary for older compilers +#include + +namespace irr +{ +namespace core +{ + +#ifdef DEBUG_CLIENTBLOCK +#undef DEBUG_CLIENTBLOCK +#define DEBUG_CLIENTBLOCK new +#endif + +//! Very simple allocator implementation, containers using it can be used across dll boundaries +template +class irrAllocator +{ +public: + + //! Destructor + virtual ~irrAllocator() {} + + //! Allocate memory for an array of objects + T* allocate(size_t cnt) + { + return (T*)internal_new(cnt* sizeof(T)); + } + + //! Deallocate memory for an array of objects + void deallocate(T* ptr) + { + internal_delete(ptr); + } + + //! Construct an element + void construct(T* ptr, const T&e) + { + new ((void*)ptr) T(e); + } + + //! Destruct an element + void destruct(T* ptr) + { + ptr->~T(); + } + +protected: + + virtual void* internal_new(size_t cnt) + { + return operator new(cnt); + } + + virtual void internal_delete(void* ptr) + { + operator delete(ptr); + } + +}; + + +//! Fast allocator, only to be used in containers inside the same memory heap. +/** Containers using it are NOT able to be used it across dll boundaries. Use this +when using in an internal class or function or when compiled into a static lib */ +template +class irrAllocatorFast +{ +public: + + //! Allocate memory for an array of objects + T* allocate(size_t cnt) + { + return (T*)operator new(cnt* sizeof(T)); + } + + //! Deallocate memory for an array of objects + void deallocate(T* ptr) + { + operator delete(ptr); + } + + //! Construct an element + void construct(T* ptr, const T&e) + { + new ((void*)ptr) T(e); + } + + //! Destruct an element + void destruct(T* ptr) + { + ptr->~T(); + } +}; + + + +#ifdef DEBUG_CLIENTBLOCK +#undef DEBUG_CLIENTBLOCK +#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__) +#endif + +//! defines an allocation strategy (used only by irr::array so far) +enum eAllocStrategy +{ + ALLOC_STRATEGY_SAFE = 0, // increase size by 1 + ALLOC_STRATEGY_DOUBLE = 1, // double size when under 500 elements, beyond that increase by 1/4th size. Plus a small constant. + ALLOC_STRATEGY_SQRT = 2 // not implemented +}; + + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/include/irrArray.h b/include/irrArray.h new file mode 100644 index 00000000..b8ffd705 --- /dev/null +++ b/include/irrArray.h @@ -0,0 +1,626 @@ +// Copyright (C) 2002-2012 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 + +#ifndef __IRR_ARRAY_H_INCLUDED__ +#define __IRR_ARRAY_H_INCLUDED__ + +#include "irrTypes.h" +#include "heapsort.h" +#include "irrAllocator.h" +#include "irrMath.h" + +namespace irr +{ +namespace core +{ + +//! Self reallocating template array (like stl vector) with additional features. +/** Some features are: Heap sorting, binary search methods, easier debugging. +*/ +template > +class array +{ + +public: + + //! Default constructor for empty array. + array() : data(0), allocated(0), used(0), + strategy(ALLOC_STRATEGY_DOUBLE), free_when_destroyed(true), is_sorted(true) + { + } + + + //! Constructs an array and allocates an initial chunk of memory. + /** \param start_count Amount of elements to pre-allocate. */ + explicit array(u32 start_count) : data(0), allocated(0), used(0), + strategy(ALLOC_STRATEGY_DOUBLE), + free_when_destroyed(true), is_sorted(true) + { + reallocate(start_count); + } + + + //! Copy constructor + array(const array& other) : data(0) + { + *this = other; + } + + + //! Destructor. + /** Frees allocated memory, if set_free_when_destroyed was not set to + false by the user before. */ + ~array() + { + clear(); + } + + + //! Reallocates the array, make it bigger or smaller. + /** \param new_size New size of array. + \param canShrink Specifies whether the array is reallocated even if + enough space is available. Setting this flag to false can speed up + array usage, but may use more memory than required by the data. + */ + void reallocate(u32 new_size, bool canShrink=true) + { + if (allocated==new_size) + return; + if (!canShrink && (new_size < allocated)) + return; + + T* old_data = data; + + data = allocator.allocate(new_size); //new T[new_size]; + allocated = new_size; + + // copy old data + const s32 end = used < new_size ? used : new_size; + + for (s32 i=0; iused) // access violation + + if (used + 1 > allocated) + { + // this doesn't work if the element is in the same + // array. So we'll copy the element first to be sure + // we'll get no data corruption + const T e(element); + + // increase data block + u32 newAlloc; + switch ( strategy ) + { + case ALLOC_STRATEGY_DOUBLE: + newAlloc = used + 5 + (allocated < 500 ? used : used >> 2); + break; + default: + case ALLOC_STRATEGY_SAFE: + newAlloc = used + 1; + break; + } + reallocate( newAlloc); + + // move array content and construct new element + // first move end one up + for (u32 i=used; i>index; --i) + { + if (i index) + allocator.destruct(&data[index]); + allocator.construct(&data[index], e); // data[index] = e; + } + else + { + // element inserted not at end + if ( used > index ) + { + // create one new element at the end + allocator.construct(&data[used], data[used-1]); + + // move the rest of the array content + for (u32 i=used-1; i>index; --i) + { + data[i] = data[i-1]; + } + // insert the new element + data[index] = element; + } + else + { + // insert the new element to the end + allocator.construct(&data[index], element); + } + } + // set to false as we don't know if we have the comparison operators + is_sorted = false; + ++used; + } + + + //! Clears the array and deletes all allocated memory. + void clear() + { + if (free_when_destroyed) + { + for (u32 i=0; i& operator=(const array& other) + { + if (this == &other) + return *this; + strategy = other.strategy; + + if (data) + clear(); + + //if (allocated < other.allocated) + if (other.allocated == 0) + data = 0; + else + data = allocator.allocate(other.allocated); // new T[other.allocated]; + + used = other.used; + free_when_destroyed = true; + is_sorted = other.is_sorted; + allocated = other.allocated; + + for (u32 i=0; i& other) const + { + if (used != other.used) + return false; + + for (u32 i=0; i& other) const + { + return !(*this==other); + } + + + //! Direct access operator + T& operator [](u32 index) + { + _IRR_DEBUG_BREAK_IF(index>=used) // access violation + + return data[index]; + } + + + //! Direct const access operator + const T& operator [](u32 index) const + { + _IRR_DEBUG_BREAK_IF(index>=used) // access violation + + return data[index]; + } + + + //! Gets last element. + T& getLast() + { + _IRR_DEBUG_BREAK_IF(!used) // access violation + + return data[used-1]; + } + + + //! Gets last element + const T& getLast() const + { + _IRR_DEBUG_BREAK_IF(!used) // access violation + + return data[used-1]; + } + + + //! Gets a pointer to the array. + /** \return Pointer to the array. */ + T* pointer() + { + return data; + } + + + //! Gets a const pointer to the array. + /** \return Pointer to the array. */ + const T* const_pointer() const + { + return data; + } + + + //! Get number of occupied elements of the array. + /** \return Size of elements in the array which are actually occupied. */ + u32 size() const + { + return used; + } + + + //! Get amount of memory allocated. + /** \return Amount of memory allocated. The amount of bytes + allocated would be allocated_size() * sizeof(ElementTypeUsed); */ + u32 allocated_size() const + { + return allocated; + } + + + //! Check if array is empty. + /** \return True if the array is empty false if not. */ + bool empty() const + { + return used == 0; + } + + + //! Sorts the array using heapsort. + /** There is no additional memory waste and the algorithm performs + O(n*log n) in worst case. */ + void sort() + { + if (!is_sorted && used>1) + heapsort(data, used); + is_sorted = true; + } + + + //! Performs a binary search for an element, returns -1 if not found. + /** The array will be sorted before the binary search if it is not + already sorted. Caution is advised! Be careful not to call this on + unsorted const arrays, or the slower method will be used. + \param element Element to search for. + \return Position of the searched element if it was found, + otherwise -1 is returned. */ + s32 binary_search(const T& element) + { + sort(); + return binary_search(element, 0, used-1); + } + + + //! Performs a binary search for an element if possible, returns -1 if not found. + /** This method is for const arrays and so cannot call sort(), if the array is + not sorted then linear_search will be used instead. Potentially very slow! + \param element Element to search for. + \return Position of the searched element if it was found, + otherwise -1 is returned. */ + s32 binary_search(const T& element) const + { + if (is_sorted) + return binary_search(element, 0, used-1); + else + return linear_search(element); + } + + + //! Performs a binary search for an element, returns -1 if not found. + /** \param element: Element to search for. + \param left First left index + \param right Last right index. + \return Position of the searched element if it was found, otherwise -1 + is returned. */ + s32 binary_search(const T& element, s32 left, s32 right) const + { + if (!used) + return -1; + + s32 m; + + do + { + m = (left+right)>>1; + + if (element < data[m]) + right = m - 1; + else + left = m + 1; + + } while((element < data[m] || data[m] < element) && left<=right); + // this last line equals to: + // " while((element != array[m]) && left<=right);" + // but we only want to use the '<' operator. + // the same in next line, it is "(element == array[m])" + + + if (!(element < data[m]) && !(data[m] < element)) + return m; + + return -1; + } + + + //! Performs a binary search for an element, returns -1 if not found. + //! it is used for searching a multiset + /** The array will be sorted before the binary search if it is not + already sorted. + \param element Element to search for. + \param &last return lastIndex of equal elements + \return Position of the first searched element if it was found, + otherwise -1 is returned. */ + s32 binary_search_multi(const T& element, s32 &last) + { + sort(); + s32 index = binary_search(element, 0, used-1); + if ( index < 0 ) + return index; + + // The search can be somewhere in the middle of the set + // look linear previous and past the index + last = index; + + while ( index > 0 && !(element < data[index - 1]) && !(data[index - 1] < element) ) + { + index -= 1; + } + // look linear up + while ( last < (s32) used - 1 && !(element < data[last + 1]) && !(data[last + 1] < element) ) + { + last += 1; + } + + return index; + } + + + //! Finds an element in linear time, which is very slow. + /** Use binary_search for faster finding. Only works if ==operator is + implemented. + \param element Element to search for. + \return Position of the searched element if it was found, otherwise -1 + is returned. */ + s32 linear_search(const T& element) const + { + for (u32 i=0; i=0; --i) + if (data[i] == element) + return i; + + return -1; + } + + + //! Erases an element from the array. + /** May be slow, because all elements following after the erased + element have to be copied. + \param index: Index of element to be erased. */ + void erase(u32 index) + { + _IRR_DEBUG_BREAK_IF(index>=used) // access violation + + for (u32 i=index+1; i=used || count<1) + return; + if (index+count>used) + count = used-index; + + u32 i; + for (i=index; i= index+count) // not already destructed before loop + allocator.destruct(&data[i-count]); + + allocator.construct(&data[i-count], data[i]); // data[i-count] = data[i]; + + if (i >= used-count) // those which are not overwritten + allocator.destruct(&data[i]); + } + + used-= count; + } + + + //! Sets if the array is sorted + void set_sorted(bool _is_sorted) + { + is_sorted = _is_sorted; + } + + + //! Swap the content of this array container with the content of another array + /** Afterward this object will contain the content of the other object and the other + object will contain the content of this object. + \param other Swap content with this object */ + void swap(array& other) + { + core::swap(data, other.data); + core::swap(allocated, other.allocated); + core::swap(used, other.used); + core::swap(allocator, other.allocator); // memory is still released by the same allocator used for allocation + eAllocStrategy helper_strategy(strategy); // can't use core::swap with bitfields + strategy = other.strategy; + other.strategy = helper_strategy; + bool helper_free_when_destroyed(free_when_destroyed); + free_when_destroyed = other.free_when_destroyed; + other.free_when_destroyed = helper_free_when_destroyed; + bool helper_is_sorted(is_sorted); + is_sorted = other.is_sorted; + other.is_sorted = helper_is_sorted; + } + + typedef TAlloc allocator_type; + typedef T value_type; + typedef u32 size_type; + +private: + T* data; + u32 allocated; + u32 used; + TAlloc allocator; + eAllocStrategy strategy:4; + bool free_when_destroyed:1; + bool is_sorted:1; +}; + + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/include/irrList.h b/include/irrList.h new file mode 100644 index 00000000..27044a45 --- /dev/null +++ b/include/irrList.h @@ -0,0 +1,414 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_LIST_H_INCLUDED__ +#define __IRR_LIST_H_INCLUDED__ + +#include "irrTypes.h" +#include "irrAllocator.h" +#include "irrMath.h" + +namespace irr +{ +namespace core +{ + + +//! Doubly linked list template. +template +class list +{ +private: + + //! List element node with pointer to previous and next element in the list. + struct SKListNode + { + SKListNode(const T& e) : Next(0), Prev(0), Element(e) {} + + SKListNode* Next; + SKListNode* Prev; + T Element; + }; + +public: + class ConstIterator; + + //! List iterator. + class Iterator + { + public: + Iterator() : Current(0) {} + + Iterator& operator ++() { Current = Current->Next; return *this; } + Iterator& operator --() { Current = Current->Prev; return *this; } + Iterator operator ++(s32) { Iterator tmp = *this; Current = Current->Next; return tmp; } + Iterator operator --(s32) { Iterator tmp = *this; Current = Current->Prev; return tmp; } + + Iterator& operator +=(s32 num) + { + if(num > 0) + { + while (num-- && this->Current != 0) ++(*this); + } + else + { + while(num++ && this->Current != 0) --(*this); + } + return *this; + } + + Iterator operator + (s32 num) const { Iterator tmp = *this; return tmp += num; } + Iterator& operator -=(s32 num) { return (*this)+=(-num); } + Iterator operator - (s32 num) const { return (*this)+ (-num); } + + bool operator ==(const Iterator& other) const { return Current == other.Current; } + bool operator !=(const Iterator& other) const { return Current != other.Current; } + bool operator ==(const ConstIterator& other) const { return Current == other.Current; } + bool operator !=(const ConstIterator& other) const { return Current != other.Current; } + + T & operator * () { return Current->Element; } + T * operator ->() { return &Current->Element; } + + private: + explicit Iterator(SKListNode* begin) : Current(begin) {} + + SKListNode* Current; + + friend class list; + friend class ConstIterator; + }; + + //! List iterator for const access. + class ConstIterator + { + public: + + ConstIterator() : Current(0) {} + ConstIterator(const Iterator& iter) : Current(iter.Current) {} + + ConstIterator& operator ++() { Current = Current->Next; return *this; } + ConstIterator& operator --() { Current = Current->Prev; return *this; } + ConstIterator operator ++(s32) { ConstIterator tmp = *this; Current = Current->Next; return tmp; } + ConstIterator operator --(s32) { ConstIterator tmp = *this; Current = Current->Prev; return tmp; } + + ConstIterator& operator +=(s32 num) + { + if(num > 0) + { + while(num-- && this->Current != 0) ++(*this); + } + else + { + while(num++ && this->Current != 0) --(*this); + } + return *this; + } + + ConstIterator operator + (s32 num) const { ConstIterator tmp = *this; return tmp += num; } + ConstIterator& operator -=(s32 num) { return (*this)+=(-num); } + ConstIterator operator - (s32 num) const { return (*this)+ (-num); } + + bool operator ==(const ConstIterator& other) const { return Current == other.Current; } + bool operator !=(const ConstIterator& other) const { return Current != other.Current; } + bool operator ==(const Iterator& other) const { return Current == other.Current; } + bool operator !=(const Iterator& other) const { return Current != other.Current; } + + const T & operator * () { return Current->Element; } + const T * operator ->() { return &Current->Element; } + + ConstIterator & operator =(const Iterator & iterator) { Current = iterator.Current; return *this; } + + private: + explicit ConstIterator(SKListNode* begin) : Current(begin) {} + + SKListNode* Current; + + friend class Iterator; + friend class list; + }; + + //! Default constructor for empty list. + list() + : First(0), Last(0), Size(0) {} + + + //! Copy constructor. + list(const list& other) : First(0), Last(0), Size(0) + { + *this = other; + } + + + //! Destructor + ~list() + { + clear(); + } + + + //! Assignment operator + void operator=(const list& other) + { + if(&other == this) + { + return; + } + + clear(); + + SKListNode* node = other.First; + while(node) + { + push_back(node->Element); + node = node->Next; + } + } + + + //! Returns amount of elements in list. + /** \return Amount of elements in the list. */ + u32 size() const + { + return Size; + } + u32 getSize() const + { + return Size; + } + + + //! Clears the list, deletes all elements in the list. + /** All existing iterators of this list will be invalid. */ + void clear() + { + while(First) + { + SKListNode * next = First->Next; + allocator.destruct(First); + allocator.deallocate(First); + First = next; + } + + //First = 0; handled by loop + Last = 0; + Size = 0; + } + + + //! Checks for empty list. + /** \return True if the list is empty and false if not. */ + bool empty() const + { + return (First == 0); + } + + + //! Adds an element at the end of the list. + /** \param element Element to add to the list. */ + void push_back(const T& element) + { + SKListNode* node = allocator.allocate(1); + allocator.construct(node, element); + + ++Size; + + if (First == 0) + First = node; + + node->Prev = Last; + + if (Last != 0) + Last->Next = node; + + Last = node; + } + + + //! Adds an element at the begin of the list. + /** \param element: Element to add to the list. */ + void push_front(const T& element) + { + SKListNode* node = allocator.allocate(1); + allocator.construct(node, element); + + ++Size; + + if (First == 0) + { + Last = node; + First = node; + } + else + { + node->Next = First; + First->Prev = node; + First = node; + } + } + + + //! Gets first node. + /** \return A list iterator pointing to the beginning of the list. */ + Iterator begin() + { + return Iterator(First); + } + + + //! Gets first node. + /** \return A const list iterator pointing to the beginning of the list. */ + ConstIterator begin() const + { + return ConstIterator(First); + } + + + //! Gets end node. + /** \return List iterator pointing to null. */ + Iterator end() + { + return Iterator(0); + } + + + //! Gets end node. + /** \return Const list iterator pointing to null. */ + ConstIterator end() const + { + return ConstIterator(0); + } + + + //! Gets last element. + /** \return List iterator pointing to the last element of the list. */ + Iterator getLast() + { + return Iterator(Last); + } + + + //! Gets last element. + /** \return Const list iterator pointing to the last element of the list. */ + ConstIterator getLast() const + { + return ConstIterator(Last); + } + + + //! Inserts an element after an element. + /** \param it Iterator pointing to element after which the new element + should be inserted. + \param element The new element to be inserted into the list. + */ + void insert_after(const Iterator& it, const T& element) + { + SKListNode* node = allocator.allocate(1); + allocator.construct(node, element); + + node->Next = it.Current->Next; + + if (it.Current->Next) + it.Current->Next->Prev = node; + + node->Prev = it.Current; + it.Current->Next = node; + ++Size; + + if (it.Current == Last) + Last = node; + } + + + //! Inserts an element before an element. + /** \param it Iterator pointing to element before which the new element + should be inserted. + \param element The new element to be inserted into the list. + */ + void insert_before(const Iterator& it, const T& element) + { + SKListNode* node = allocator.allocate(1); + allocator.construct(node, element); + + node->Prev = it.Current->Prev; + + if (it.Current->Prev) + it.Current->Prev->Next = node; + + node->Next = it.Current; + it.Current->Prev = node; + ++Size; + + if (it.Current == First) + First = node; + } + + + //! Erases an element. + /** \param it Iterator pointing to the element which shall be erased. + \return Iterator pointing to next element. */ + Iterator erase(Iterator& it) + { + // suggest changing this to a const Iterator& and + // working around line: it.Current = 0 (possibly with a mutable, or just let it be garbage?) + + Iterator returnIterator(it); + ++returnIterator; + + if(it.Current == First) + { + First = it.Current->Next; + } + else + { + it.Current->Prev->Next = it.Current->Next; + } + + if(it.Current == Last) + { + Last = it.Current->Prev; + } + else + { + it.Current->Next->Prev = it.Current->Prev; + } + + allocator.destruct(it.Current); + allocator.deallocate(it.Current); + it.Current = 0; + --Size; + + return returnIterator; + } + + //! Swap the content of this list container with the content of another list + /** Afterward this object will contain the content of the other object and the other + object will contain the content of this object. Iterators will afterward be valid for + the swapped object. + \param other Swap content with this object */ + void swap(list& other) + { + core::swap(First, other.First); + core::swap(Last, other.Last); + core::swap(Size, other.Size); + core::swap(allocator, other.allocator); // memory is still released by the same allocator used for allocation + } + + typedef T value_type; + typedef u32 size_type; + +private: + + SKListNode* First; + SKListNode* Last; + u32 Size; + irrAllocator allocator; + +}; + + +} // end namespace core +}// end namespace irr + +#endif + diff --git a/include/irrMap.h b/include/irrMap.h new file mode 100644 index 00000000..430f0adc --- /dev/null +++ b/include/irrMap.h @@ -0,0 +1,1114 @@ +// Copyright (C) 2006-2012 by Kat'Oun +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_MAP_H_INCLUDED__ +#define __IRR_MAP_H_INCLUDED__ + +#include "irrTypes.h" +#include "irrMath.h" + +namespace irr +{ +namespace core +{ + +//! map template for associative arrays using a red-black tree +template +class map +{ + //! red/black tree for map + template + class RBTree + { + public: + + RBTree(const KeyTypeRB& k, const ValueTypeRB& v) + : LeftChild(0), RightChild(0), Parent(0), Key(k), + Value(v), IsRed(true) {} + + void setLeftChild(RBTree* p) + { + LeftChild=p; + if (p) + p->setParent(this); + } + + void setRightChild(RBTree* p) + { + RightChild=p; + if (p) + p->setParent(this); + } + + void setParent(RBTree* p) { Parent=p; } + + void setValue(const ValueTypeRB& v) { Value = v; } + + void setRed() { IsRed = true; } + void setBlack() { IsRed = false; } + + RBTree* getLeftChild() const { return LeftChild; } + RBTree* getRightChild() const { return RightChild; } + RBTree* getParent() const { return Parent; } + + const ValueTypeRB& getValue() const + { + return Value; + } + + ValueTypeRB& getValue() + { + return Value; + } + + const KeyTypeRB& getKey() const + { + return Key; + } + + bool isRoot() const + { + return Parent==0; + } + + bool isLeftChild() const + { + return (Parent != 0) && (Parent->getLeftChild()==this); + } + + bool isRightChild() const + { + return (Parent!=0) && (Parent->getRightChild()==this); + } + + bool isLeaf() const + { + return (LeftChild==0) && (RightChild==0); + } + + unsigned int getLevel() const + { + if (isRoot()) + return 1; + else + return getParent()->getLevel() + 1; + } + + + bool isRed() const + { + return IsRed; + } + + bool isBlack() const + { + return !IsRed; + } + + private: + RBTree(); + + RBTree* LeftChild; + RBTree* RightChild; + + RBTree* Parent; + + KeyTypeRB Key; + ValueTypeRB Value; + + bool IsRed; + }; // RBTree + + public: + + typedef RBTree Node; + // We need the forward declaration for the friend declaration + class ConstIterator; + + //! Normal Iterator + class Iterator + { + friend class ConstIterator; + public: + + Iterator() : Root(0), Cur(0) {} + + // Constructor(Node*) + Iterator(Node* root) : Root(root) + { + reset(); + } + + // Copy constructor + Iterator(const Iterator& src) : Root(src.Root), Cur(src.Cur) {} + + void reset(bool atLowest=true) + { + if (atLowest) + Cur = getMin(Root); + else + Cur = getMax(Root); + } + + bool atEnd() const + { + return Cur==0; + } + + Node* getNode() const + { + return Cur; + } + + Iterator& operator=(const Iterator& src) + { + Root = src.Root; + Cur = src.Cur; + return (*this); + } + + void operator++(int) + { + inc(); + } + + void operator--(int) + { + dec(); + } + + Node* operator->() + { + return getNode(); + } + + Node& operator*() + { + _IRR_DEBUG_BREAK_IF(atEnd()) // access violation + + return *Cur; + } + + private: + + Node* getMin(Node* n) const + { + while(n && n->getLeftChild()) + n = n->getLeftChild(); + return n; + } + + Node* getMax(Node* n) const + { + while(n && n->getRightChild()) + n = n->getRightChild(); + return n; + } + + void inc() + { + // Already at end? + if (Cur==0) + return; + + if (Cur->getRightChild()) + { + // If current node has a right child, the next higher node is the + // node with lowest key beneath the right child. + Cur = getMin(Cur->getRightChild()); + } + else if (Cur->isLeftChild()) + { + // No right child? Well if current node is a left child then + // the next higher node is the parent + Cur = Cur->getParent(); + } + else + { + // Current node neither is left child nor has a right child. + // I.e. it is either right child or root + // The next higher node is the parent of the first non-right + // child (i.e. either a left child or the root) up in the + // hierarchy. Root's parent is 0. + while(Cur->isRightChild()) + Cur = Cur->getParent(); + Cur = Cur->getParent(); + } + } + + void dec() + { + // Already at end? + if (Cur==0) + return; + + if (Cur->getLeftChild()) + { + // If current node has a left child, the next lower node is the + // node with highest key beneath the left child. + Cur = getMax(Cur->getLeftChild()); + } + else if (Cur->isRightChild()) + { + // No left child? Well if current node is a right child then + // the next lower node is the parent + Cur = Cur->getParent(); + } + else + { + // Current node neither is right child nor has a left child. + // It is either left child or root + // The next higher node is the parent of the first non-left + // child (i.e. either a right child or the root) up in the + // hierarchy. Root's parent is 0. + + while(Cur->isLeftChild()) + Cur = Cur->getParent(); + Cur = Cur->getParent(); + } + } + + Node* Root; + Node* Cur; + }; // Iterator + + //! Const Iterator + class ConstIterator + { + friend class Iterator; + public: + + ConstIterator() : Root(0), Cur(0) {} + + // Constructor(Node*) + ConstIterator(const Node* root) : Root(root) + { + reset(); + } + + // Copy constructor + ConstIterator(const ConstIterator& src) : Root(src.Root), Cur(src.Cur) {} + ConstIterator(const Iterator& src) : Root(src.Root), Cur(src.Cur) {} + + void reset(bool atLowest=true) + { + if (atLowest) + Cur = getMin(Root); + else + Cur = getMax(Root); + } + + bool atEnd() const + { + return Cur==0; + } + + const Node* getNode() const + { + return Cur; + } + + ConstIterator& operator=(const ConstIterator& src) + { + Root = src.Root; + Cur = src.Cur; + return (*this); + } + + void operator++(int) + { + inc(); + } + + void operator--(int) + { + dec(); + } + + const Node* operator->() + { + return getNode(); + } + + const Node& operator*() + { + _IRR_DEBUG_BREAK_IF(atEnd()) // access violation + + return *Cur; + } + + private: + + const Node* getMin(const Node* n) const + { + while(n && n->getLeftChild()) + n = n->getLeftChild(); + return n; + } + + const Node* getMax(const Node* n) const + { + while(n && n->getRightChild()) + n = n->getRightChild(); + return n; + } + + void inc() + { + // Already at end? + if (Cur==0) + return; + + if (Cur->getRightChild()) + { + // If current node has a right child, the next higher node is the + // node with lowest key beneath the right child. + Cur = getMin(Cur->getRightChild()); + } + else if (Cur->isLeftChild()) + { + // No right child? Well if current node is a left child then + // the next higher node is the parent + Cur = Cur->getParent(); + } + else + { + // Current node neither is left child nor has a right child. + // It is either right child or root + // The next higher node is the parent of the first non-right + // child (i.e. either a left child or the root) up in the + // hierarchy. Root's parent is 0. + while(Cur->isRightChild()) + Cur = Cur->getParent(); + Cur = Cur->getParent(); + } + } + + void dec() + { + // Already at end? + if (Cur==0) + return; + + if (Cur->getLeftChild()) + { + // If current node has a left child, the next lower node is the + // node with highest key beneath the left child. + Cur = getMax(Cur->getLeftChild()); + } + else if (Cur->isRightChild()) + { + // No left child? Well if current node is a right child then + // the next lower node is the parent + Cur = Cur->getParent(); + } + else + { + // Current node neither is right child nor has a left child. + // It is either left child or root + // The next higher node is the parent of the first non-left + // child (i.e. either a right child or the root) up in the + // hierarchy. Root's parent is 0. + + while(Cur->isLeftChild()) + Cur = Cur->getParent(); + Cur = Cur->getParent(); + } + } + + const Node* Root; + const Node* Cur; + }; // ConstIterator + + + //! Parent First Iterator. + /** Traverses the tree from top to bottom. Typical usage is + when storing the tree structure, because when reading it + later (and inserting elements) the tree structure will + be the same. */ + class ParentFirstIterator + { + public: + + ParentFirstIterator() : Root(0), Cur(0) {} + + explicit ParentFirstIterator(Node* root) : Root(root), Cur(0) + { + reset(); + } + + void reset() + { + Cur = Root; + } + + bool atEnd() const + { + return Cur==0; + } + + Node* getNode() + { + return Cur; + } + + ParentFirstIterator& operator=(const ParentFirstIterator& src) + { + Root = src.Root; + Cur = src.Cur; + return (*this); + } + + void operator++(int) + { + inc(); + } + + Node* operator -> () + { + return getNode(); + } + + Node& operator* () + { + _IRR_DEBUG_BREAK_IF(atEnd()) // access violation + + return *getNode(); + } + + private: + + void inc() + { + // Already at end? + if (Cur==0) + return; + + // First we try down to the left + if (Cur->getLeftChild()) + { + Cur = Cur->getLeftChild(); + } + else if (Cur->getRightChild()) + { + // No left child? The we go down to the right. + Cur = Cur->getRightChild(); + } + else + { + // No children? Move up in the hierarchy until + // we either reach 0 (and are finished) or + // find a right uncle. + while (Cur!=0) + { + // But if parent is left child and has a right "uncle" the parent + // has already been processed but the uncle hasn't. Move to + // the uncle. + if (Cur->isLeftChild() && Cur->getParent()->getRightChild()) + { + Cur = Cur->getParent()->getRightChild(); + return; + } + Cur = Cur->getParent(); + } + } + } + + Node* Root; + Node* Cur; + + }; // ParentFirstIterator + + + //! Parent Last Iterator + /** Traverse the tree from bottom to top. + Typical usage is when deleting all elements in the tree + because you must delete the children before you delete + their parent. */ + class ParentLastIterator + { + public: + + ParentLastIterator() : Root(0), Cur(0) {} + + explicit ParentLastIterator(Node* root) : Root(root), Cur(0) + { + reset(); + } + + void reset() + { + Cur = getMin(Root); + } + + bool atEnd() const + { + return Cur==0; + } + + Node* getNode() + { + return Cur; + } + + ParentLastIterator& operator=(const ParentLastIterator& src) + { + Root = src.Root; + Cur = src.Cur; + return (*this); + } + + void operator++(int) + { + inc(); + } + + Node* operator -> () + { + return getNode(); + } + + Node& operator* () + { + _IRR_DEBUG_BREAK_IF(atEnd()) // access violation + + return *getNode(); + } + private: + + Node* getMin(Node* n) + { + while(n!=0 && (n->getLeftChild()!=0 || n->getRightChild()!=0)) + { + if (n->getLeftChild()) + n = n->getLeftChild(); + else + n = n->getRightChild(); + } + return n; + } + + void inc() + { + // Already at end? + if (Cur==0) + return; + + // Note: Starting point is the node as far down to the left as possible. + + // If current node has an uncle to the right, go to the + // node as far down to the left from the uncle as possible + // else just go up a level to the parent. + if (Cur->isLeftChild() && Cur->getParent()->getRightChild()) + { + Cur = getMin(Cur->getParent()->getRightChild()); + } + else + Cur = Cur->getParent(); + } + + Node* Root; + Node* Cur; + }; // ParentLastIterator + + + // AccessClass is a temporary class used with the [] operator. + // It makes it possible to have different behavior in situations like: + // myTree["Foo"] = 32; + // If "Foo" already exists update its value else insert a new element. + // int i = myTree["Foo"] + // If "Foo" exists return its value. + class AccessClass + { + // Let map be the only one who can instantiate this class. + friend class map; + + public: + + // Assignment operator. Handles the myTree["Foo"] = 32; situation + void operator=(const ValueType& value) + { + // Just use the Set method, it handles already exist/not exist situation + Tree.set(Key,value); + } + + // ValueType operator + operator ValueType() + { + Node* node = Tree.find(Key); + + // Not found + _IRR_DEBUG_BREAK_IF(node==0) // access violation + + return node->getValue(); + } + + private: + + AccessClass(map& tree, const KeyType& key) : Tree(tree), Key(key) {} + + AccessClass(); + + map& Tree; + const KeyType& Key; + }; // AccessClass + + + // Constructor. + map() : Root(0), Size(0) {} + + // Destructor + ~map() + { + clear(); + } + + // typedefs + typedef KeyType key_type; + typedef ValueType value_type; + typedef u32 size_type; + + //------------------------------ + // Public Commands + //------------------------------ + + //! Inserts a new node into the tree + /** \param keyNew: the index for this value + \param v: the value to insert + \return True if successful, false if it fails (already exists) */ + bool insert(const KeyType& keyNew, const ValueType& v) + { + // First insert node the "usual" way (no fancy balance logic yet) + Node* newNode = new Node(keyNew,v); + if (!insert(newNode)) + { + delete newNode; + return false; + } + + // Then attend a balancing party + while (!newNode->isRoot() && (newNode->getParent()->isRed())) + { + if (newNode->getParent()->isLeftChild()) + { + // If newNode is a left child, get its right 'uncle' + Node* newNodesUncle = newNode->getParent()->getParent()->getRightChild(); + if ( newNodesUncle!=0 && newNodesUncle->isRed()) + { + // case 1 - change the colors + newNode->getParent()->setBlack(); + newNodesUncle->setBlack(); + newNode->getParent()->getParent()->setRed(); + // Move newNode up the tree + newNode = newNode->getParent()->getParent(); + } + else + { + // newNodesUncle is a black node + if ( newNode->isRightChild()) + { + // and newNode is to the right + // case 2 - move newNode up and rotate + newNode = newNode->getParent(); + rotateLeft(newNode); + } + // case 3 + newNode->getParent()->setBlack(); + newNode->getParent()->getParent()->setRed(); + rotateRight(newNode->getParent()->getParent()); + } + } + else + { + // If newNode is a right child, get its left 'uncle' + Node* newNodesUncle = newNode->getParent()->getParent()->getLeftChild(); + if ( newNodesUncle!=0 && newNodesUncle->isRed()) + { + // case 1 - change the colors + newNode->getParent()->setBlack(); + newNodesUncle->setBlack(); + newNode->getParent()->getParent()->setRed(); + // Move newNode up the tree + newNode = newNode->getParent()->getParent(); + } + else + { + // newNodesUncle is a black node + if (newNode->isLeftChild()) + { + // and newNode is to the left + // case 2 - move newNode up and rotate + newNode = newNode->getParent(); + rotateRight(newNode); + } + // case 3 + newNode->getParent()->setBlack(); + newNode->getParent()->getParent()->setRed(); + rotateLeft(newNode->getParent()->getParent()); + } + + } + } + // Color the root black + Root->setBlack(); + return true; + } + + //! Replaces the value if the key already exists, otherwise inserts a new element. + /** \param k The index for this value + \param v The new value of */ + void set(const KeyType& k, const ValueType& v) + { + Node* p = find(k); + if (p) + p->setValue(v); + else + insert(k,v); + } + + //! Removes a node from the tree and returns it. + /** The returned node must be deleted by the user + \param k the key to remove + \return A pointer to the node, or 0 if not found */ + Node* delink(const KeyType& k) + { + Node* p = find(k); + if (p == 0) + return 0; + + // Rotate p down to the left until it has no right child, will get there + // sooner or later. + while(p->getRightChild()) + { + // "Pull up my right child and let it knock me down to the left" + rotateLeft(p); + } + // p now has no right child but might have a left child + Node* left = p->getLeftChild(); + + // Let p's parent point to p's child instead of point to p + if (p->isLeftChild()) + p->getParent()->setLeftChild(left); + + else if (p->isRightChild()) + p->getParent()->setRightChild(left); + + else + { + // p has no parent => p is the root. + // Let the left child be the new root. + setRoot(left); + } + + // p is now gone from the tree in the sense that + // no one is pointing at it, so return it. + + --Size; + return p; + } + + //! Removes a node from the tree and deletes it. + /** \return True if the node was found and deleted */ + bool remove(const KeyType& k) + { + Node* p = find(k); + return remove(p); + } + + //! Removes a node from the tree and deletes it. + /** \return True if the node was found and deleted */ + bool remove(Node* p) + { + if (p == 0) + { + return false; + } + + // Rotate p down to the left until it has no right child, will get there + // sooner or later. + while(p->getRightChild()) + { + // "Pull up my right child and let it knock me down to the left" + rotateLeft(p); + } + // p now has no right child but might have a left child + Node* left = p->getLeftChild(); + + // Let p's parent point to p's child instead of point to p + if (p->isLeftChild()) + p->getParent()->setLeftChild(left); + + else if (p->isRightChild()) + p->getParent()->setRightChild(left); + + else + { + // p has no parent => p is the root. + // Let the left child be the new root. + setRoot(left); + } + + // p is now gone from the tree in the sense that + // no one is pointing at it. Let's get rid of it. + delete p; + + --Size; + return true; + } + + //! Clear the entire tree + void clear() + { + ParentLastIterator i(getParentLastIterator()); + + while(!i.atEnd()) + { + Node* p = i.getNode(); + i++; // Increment it before it is deleted + // else iterator will get quite confused. + delete p; + } + Root = 0; + Size= 0; + } + + //! Is the tree empty? + //! \return Returns true if empty, false if not + bool empty() const + { + return Root == 0; + } + + //! \deprecated Use empty() instead. This method may be removed by Irrlicht 1.9 + _IRR_DEPRECATED_ bool isEmpty() const + { + return empty(); + } + + //! Search for a node with the specified key. + //! \param keyToFind: The key to find + //! \return Returns 0 if node couldn't be found. + Node* find(const KeyType& keyToFind) const + { + Node* pNode = Root; + + while(pNode!=0) + { + const KeyType& key=pNode->getKey(); + + if (keyToFind == key) + return pNode; + else if (keyToFind < key) + pNode = pNode->getLeftChild(); + else //keyToFind > key + pNode = pNode->getRightChild(); + } + + return 0; + } + + //! Gets the root element. + //! \return Returns a pointer to the root node, or + //! 0 if the tree is empty. + Node* getRoot() const + { + return Root; + } + + //! Returns the number of nodes in the tree. + u32 size() const + { + return Size; + } + + //! Swap the content of this map container with the content of another map + /** Afterwards this object will contain the content of the other object and the other + object will contain the content of this object. Iterators will afterwards be valid for + the swapped object. + \param other Swap content with this object */ + void swap(map& other) + { + core::swap(Root, other.Root); + core::swap(Size, other.Size); + } + + //------------------------------ + // Public Iterators + //------------------------------ + + //! Returns an iterator + Iterator getIterator() const + { + Iterator it(getRoot()); + return it; + } + + //! Returns a Constiterator + ConstIterator getConstIterator() const + { + Iterator it(getRoot()); + return it; + } + + //! Returns a ParentFirstIterator. + //! Traverses the tree from top to bottom. Typical usage is + //! when storing the tree structure, because when reading it + //! later (and inserting elements) the tree structure will + //! be the same. + ParentFirstIterator getParentFirstIterator() const + { + ParentFirstIterator it(getRoot()); + return it; + } + + //! Returns a ParentLastIterator to traverse the tree from + //! bottom to top. + //! Typical usage is when deleting all elements in the tree + //! because you must delete the children before you delete + //! their parent. + ParentLastIterator getParentLastIterator() const + { + ParentLastIterator it(getRoot()); + return it; + } + + //------------------------------ + // Public Operators + //------------------------------ + + //! operator [] for access to elements + /** for example myMap["key"] */ + AccessClass operator[](const KeyType& k) + { + return AccessClass(*this, k); + } + private: + + //------------------------------ + // Disabled methods + //------------------------------ + // Copy constructor and assignment operator deliberately + // defined but not implemented. The tree should never be + // copied, pass along references to it instead. + explicit map(const map& src); + map& operator = (const map& src); + + //! Set node as new root. + /** The node will be set to black, otherwise core dumps may arise + (patch provided by rogerborg). + \param newRoot Node which will be the new root + */ + void setRoot(Node* newRoot) + { + Root = newRoot; + if (Root != 0) + { + Root->setParent(0); + Root->setBlack(); + } + } + + //! Insert a node into the tree without using any fancy balancing logic. + /** \return false if that key already exist in the tree. */ + bool insert(Node* newNode) + { + bool result=true; // Assume success + + if (Root==0) + { + setRoot(newNode); + Size = 1; + } + else + { + Node* pNode = Root; + const KeyType& keyNew = newNode->getKey(); + while (pNode) + { + const KeyType& key=pNode->getKey(); + + if (keyNew == key) + { + result = false; + pNode = 0; + } + else if (keyNew < key) + { + if (pNode->getLeftChild() == 0) + { + pNode->setLeftChild(newNode); + pNode = 0; + } + else + pNode = pNode->getLeftChild(); + } + else // keyNew > key + { + if (pNode->getRightChild()==0) + { + pNode->setRightChild(newNode); + pNode = 0; + } + else + { + pNode = pNode->getRightChild(); + } + } + } + + if (result) + ++Size; + } + + return result; + } + + //! Rotate left. + //! Pull up node's right child and let it knock node down to the left + void rotateLeft(Node* p) + { + Node* right = p->getRightChild(); + + p->setRightChild(right->getLeftChild()); + + if (p->isLeftChild()) + p->getParent()->setLeftChild(right); + else if (p->isRightChild()) + p->getParent()->setRightChild(right); + else + setRoot(right); + + right->setLeftChild(p); + } + + //! Rotate right. + //! Pull up node's left child and let it knock node down to the right + void rotateRight(Node* p) + { + Node* left = p->getLeftChild(); + + p->setLeftChild(left->getRightChild()); + + if (p->isLeftChild()) + p->getParent()->setLeftChild(left); + else if (p->isRightChild()) + p->getParent()->setRightChild(left); + else + setRoot(left); + + left->setRightChild(p); + } + + //------------------------------ + // Private Members + //------------------------------ + Node* Root; // The top node. 0 if empty. + u32 Size; // Number of nodes in the tree +}; + +} // end namespace core +} // end namespace irr + +#endif // __IRR_MAP_H_INCLUDED__ + diff --git a/include/irrMath.h b/include/irrMath.h new file mode 100644 index 00000000..b97e270b --- /dev/null +++ b/include/irrMath.h @@ -0,0 +1,685 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_MATH_H_INCLUDED__ +#define __IRR_MATH_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#include "irrTypes.h" +#include +#include +#include // for abs() etc. +#include // For INT_MAX / UINT_MAX + +#if defined(_IRR_SOLARIS_PLATFORM_) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) || defined (_WIN32_WCE) + #define sqrtf(X) (irr::f32)sqrt((irr::f64)(X)) + #define sinf(X) (irr::f32)sin((irr::f64)(X)) + #define cosf(X) (irr::f32)cos((irr::f64)(X)) + #define asinf(X) (irr::f32)asin((irr::f64)(X)) + #define acosf(X) (irr::f32)acos((irr::f64)(X)) + #define atan2f(X,Y) (irr::f32)atan2((irr::f64)(X),(irr::f64)(Y)) + #define ceilf(X) (irr::f32)ceil((irr::f64)(X)) + #define floorf(X) (irr::f32)floor((irr::f64)(X)) + #define powf(X,Y) (irr::f32)pow((irr::f64)(X),(irr::f64)(Y)) + #define fmodf(X,Y) (irr::f32)fmod((irr::f64)(X),(irr::f64)(Y)) + #define fabsf(X) (irr::f32)fabs((irr::f64)(X)) + #define logf(X) (irr::f32)log((irr::f64)(X)) +#endif + +#ifndef FLT_MAX +#define FLT_MAX 3.402823466E+38F +#endif + +#ifndef FLT_MIN +#define FLT_MIN 1.17549435e-38F +#endif + +namespace irr +{ +namespace core +{ + + //! Rounding error constant often used when comparing f32 values. + + const s32 ROUNDING_ERROR_S32 = 0; + +#ifdef __IRR_HAS_S64 + const s64 ROUNDING_ERROR_S64 = 0; +#endif + const f32 ROUNDING_ERROR_f32 = 0.000001f; + const f64 ROUNDING_ERROR_f64 = 0.00000001; + +#ifdef PI // make sure we don't collide with a define +#undef PI +#endif + //! Constant for PI. + const f32 PI = 3.14159265359f; + + //! Constant for reciprocal of PI. + const f32 RECIPROCAL_PI = 1.0f/PI; + + //! Constant for half of PI. + const f32 HALF_PI = PI/2.0f; + +#ifdef PI64 // make sure we don't collide with a define +#undef PI64 +#endif + //! Constant for 64bit PI. + const f64 PI64 = 3.1415926535897932384626433832795028841971693993751; + + //! Constant for 64bit reciprocal of PI. + const f64 RECIPROCAL_PI64 = 1.0/PI64; + + //! 32bit Constant for converting from degrees to radians + const f32 DEGTORAD = PI / 180.0f; + + //! 32bit constant for converting from radians to degrees (formally known as GRAD_PI) + const f32 RADTODEG = 180.0f / PI; + + //! 64bit constant for converting from degrees to radians (formally known as GRAD_PI2) + const f64 DEGTORAD64 = PI64 / 180.0; + + //! 64bit constant for converting from radians to degrees + const f64 RADTODEG64 = 180.0 / PI64; + + //! Utility function to convert a radian value to degrees + /** Provided as it can be clearer to write radToDeg(X) than RADTODEG * X + \param radians The radians value to convert to degrees. + */ + inline f32 radToDeg(f32 radians) + { + return RADTODEG * radians; + } + + //! Utility function to convert a radian value to degrees + /** Provided as it can be clearer to write radToDeg(X) than RADTODEG * X + \param radians The radians value to convert to degrees. + */ + inline f64 radToDeg(f64 radians) + { + return RADTODEG64 * radians; + } + + //! Utility function to convert a degrees value to radians + /** Provided as it can be clearer to write degToRad(X) than DEGTORAD * X + \param degrees The degrees value to convert to radians. + */ + inline f32 degToRad(f32 degrees) + { + return DEGTORAD * degrees; + } + + //! Utility function to convert a degrees value to radians + /** Provided as it can be clearer to write degToRad(X) than DEGTORAD * X + \param degrees The degrees value to convert to radians. + */ + inline f64 degToRad(f64 degrees) + { + return DEGTORAD64 * degrees; + } + + //! returns minimum of two values. Own implementation to get rid of the STL (VS6 problems) + template + inline const T& min_(const T& a, const T& b) + { + return a < b ? a : b; + } + + //! returns minimum of three values. Own implementation to get rid of the STL (VS6 problems) + template + inline const T& min_(const T& a, const T& b, const T& c) + { + return a < b ? min_(a, c) : min_(b, c); + } + + //! returns maximum of two values. Own implementation to get rid of the STL (VS6 problems) + template + inline const T& max_(const T& a, const T& b) + { + return a < b ? b : a; + } + + //! returns maximum of three values. Own implementation to get rid of the STL (VS6 problems) + template + inline const T& max_(const T& a, const T& b, const T& c) + { + return a < b ? max_(b, c) : max_(a, c); + } + + //! returns abs of two values. Own implementation to get rid of STL (VS6 problems) + template + inline T abs_(const T& a) + { + return a < (T)0 ? -a : a; + } + + //! returns linear interpolation of a and b with ratio t + //! \return: a if t==0, b if t==1, and the linear interpolation else + template + inline T lerp(const T& a, const T& b, const f32 t) + { + return (T)(a*(1.f-t)) + (b*t); + } + + //! clamps a value between low and high + template + inline const T clamp (const T& value, const T& low, const T& high) + { + return min_ (max_(value,low), high); + } + + //! swaps the content of the passed parameters + // Note: We use the same trick as boost and use two template arguments to + // avoid ambiguity when swapping objects of an Irrlicht type that has not + // it's own swap overload. Otherwise we get conflicts with some compilers + // in combination with stl. + template + inline void swap(T1& a, T2& b) + { + T1 c(a); + a = b; + b = c; + } + + template + inline T roundingError(); + + template <> + inline f32 roundingError() + { + return ROUNDING_ERROR_f32; + } + + template <> + inline f64 roundingError() + { + return ROUNDING_ERROR_f64; + } + + template <> + inline s32 roundingError() + { + return ROUNDING_ERROR_S32; + } + + template <> + inline u32 roundingError() + { + return ROUNDING_ERROR_S32; + } + +#ifdef __IRR_HAS_S64 + template <> + inline s64 roundingError() + { + return ROUNDING_ERROR_S64; + } + + template <> + inline u64 roundingError() + { + return ROUNDING_ERROR_S64; + } +#endif + + template + inline T relativeErrorFactor() + { + return 1; + } + + template <> + inline f32 relativeErrorFactor() + { + return 4; + } + + template <> + inline f64 relativeErrorFactor() + { + return 8; + } + + //! returns if a equals b, taking possible rounding errors into account + template + inline bool equals(const T a, const T b, const T tolerance = roundingError()) + { + return (a + tolerance >= b) && (a - tolerance <= b); + } + + + //! returns if a equals b, taking relative error in form of factor + //! this particular function does not involve any division. + template + inline bool equalsRelative( const T a, const T b, const T factor = relativeErrorFactor()) + { + //https://eagergames.wordpress.com/2017/04/01/fast-parallel-lines-and-vectors-test/ + + const T maxi = max_( a, b); + const T mini = min_( a, b); + const T maxMagnitude = max_( maxi, -mini); + + return (maxMagnitude*factor + maxi) == (maxMagnitude*factor + mini); // MAD Wise + } + + union FloatIntUnion32 + { + FloatIntUnion32(float f1 = 0.0f) : f(f1) {} + // Portable sign-extraction + bool sign() const { return (i >> 31) != 0; } + + irr::s32 i; + irr::f32 f; + }; + + //! We compare the difference in ULP's (spacing between floating-point numbers, aka ULP=1 means there exists no float between). + //\result true when numbers have a ULP <= maxUlpDiff AND have the same sign. + inline bool equalsByUlp(f32 a, f32 b, int maxUlpDiff) + { + // Based on the ideas and code from Bruce Dawson on + // http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/ + // When floats are interpreted as integers the two nearest possible float numbers differ just + // by one integer number. Also works the other way round, an integer of 1 interpreted as float + // is for example the smallest possible float number. + + const FloatIntUnion32 fa(a); + const FloatIntUnion32 fb(b); + + // Different signs, we could maybe get difference to 0, but so close to 0 using epsilons is better. + if ( fa.sign() != fb.sign() ) + { + // Check for equality to make sure +0==-0 + if (fa.i == fb.i) + return true; + return false; + } + + // Find the difference in ULPs. + const int ulpsDiff = abs_(fa.i- fb.i); + if (ulpsDiff <= maxUlpDiff) + return true; + + return false; + } + + //! returns if a equals zero, taking rounding errors into account + inline bool iszero(const f64 a, const f64 tolerance = ROUNDING_ERROR_f64) + { + 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_f32) + { + return fabsf(a) <= tolerance; + } + + //! returns if a equals not zero, taking rounding errors into account + inline bool isnotzero(const f32 a, const f32 tolerance = ROUNDING_ERROR_f32) + { + return fabsf(a) > tolerance; + } + + //! returns if a equals zero, taking rounding errors into account + inline bool iszero(const s32 a, const s32 tolerance = 0) + { + return ( a & 0x7ffffff ) <= tolerance; + } + + //! returns if a equals zero, taking rounding errors into account + inline bool iszero(const u32 a, const u32 tolerance = 0) + { + return a <= tolerance; + } + +#ifdef __IRR_HAS_S64 + //! returns if a equals zero, taking rounding errors into account + inline bool iszero(const s64 a, const s64 tolerance = 0) + { + return abs_(a) <= tolerance; + } +#endif + + inline s32 s32_min(s32 a, s32 b) + { + const s32 mask = (a - b) >> 31; + return (a & mask) | (b & ~mask); + } + + inline s32 s32_max(s32 a, s32 b) + { + 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); + } + + /* + float IEEE-754 bit representation + + 0 0x00000000 + 1.0 0x3f800000 + 0.5 0x3f000000 + 3 0x40400000 + +inf 0x7f800000 + -inf 0xff800000 + +NaN 0x7fc00000 or 0x7ff00000 + in general: number = (sign ? -1:1) * 2^(exponent) * 1.(mantissa bits) + */ + + typedef union { u32 u; s32 s; f32 f; } inttofloat; + + #define F32_AS_S32(f) (*((s32 *) &(f))) + #define F32_AS_U32(f) (*((u32 *) &(f))) + #define F32_AS_U32_POINTER(f) ( ((u32 *) &(f))) + + #define F32_VALUE_0 0x00000000 + #define F32_VALUE_1 0x3f800000 + #define F32_SIGN_BIT 0x80000000U + #define F32_EXPON_MANTISSA 0x7FFFFFFFU + + //! code is taken from IceFPU + //! Integer representation of a floating-point value. +#ifdef IRRLICHT_FAST_MATH + #define IR(x) ((u32&)(x)) +#else + inline u32 IR(f32 x) {inttofloat tmp; tmp.f=x; return tmp.u;} +#endif + + //! Absolute integer representation of a floating-point value + #define AIR(x) (IR(x)&0x7fffffff) + + //! Floating-point representation of an integer value. +#ifdef IRRLICHT_FAST_MATH + #define FR(x) ((f32&)(x)) +#else + inline f32 FR(u32 x) {inttofloat tmp; tmp.u=x; return tmp.f;} + inline f32 FR(s32 x) {inttofloat tmp; tmp.s=x; return tmp.f;} +#endif + + //! integer representation of 1.0 + #define IEEE_1_0 0x3f800000 + //! integer representation of 255.0 + #define IEEE_255_0 0x437f0000 + +#ifdef IRRLICHT_FAST_MATH + #define F32_LOWER_0(f) (F32_AS_U32(f) > F32_SIGN_BIT) + #define F32_LOWER_EQUAL_0(f) (F32_AS_S32(f) <= F32_VALUE_0) + #define F32_GREATER_0(f) (F32_AS_S32(f) > F32_VALUE_0) + #define F32_GREATER_EQUAL_0(f) (F32_AS_U32(f) <= F32_SIGN_BIT) + #define F32_EQUAL_1(f) (F32_AS_U32(f) == F32_VALUE_1) + #define F32_EQUAL_0(f) ( (F32_AS_U32(f) & F32_EXPON_MANTISSA ) == F32_VALUE_0) + + // only same sign + #define F32_A_GREATER_B(a,b) (F32_AS_S32((a)) > F32_AS_S32((b))) + +#else + + #define F32_LOWER_0(n) ((n) < 0.0f) + #define F32_LOWER_EQUAL_0(n) ((n) <= 0.0f) + #define F32_GREATER_0(n) ((n) > 0.0f) + #define F32_GREATER_EQUAL_0(n) ((n) >= 0.0f) + #define F32_EQUAL_1(n) ((n) == 1.0f) + #define F32_EQUAL_0(n) ((n) == 0.0f) + #define F32_A_GREATER_B(a,b) ((a) > (b)) +#endif + + +#ifndef REALINLINE + #ifdef _MSC_VER + #define REALINLINE __forceinline + #else + #define REALINLINE inline + #endif +#endif + +#if defined(__BORLANDC__) || defined (__BCPLUSPLUS__) + + // 8-bit bools in Borland builder + + //! conditional set based on mask and arithmetic shift + REALINLINE u32 if_c_a_else_b ( const c8 condition, const u32 a, const u32 b ) + { + return ( ( -condition >> 7 ) & ( a ^ b ) ) ^ b; + } + + //! conditional set based on mask and arithmetic shift + REALINLINE u32 if_c_a_else_0 ( const c8 condition, const u32 a ) + { + return ( -condition >> 31 ) & a; + } +#else + + //! conditional set based on mask and arithmetic shift + REALINLINE u32 if_c_a_else_b ( const s32 condition, const u32 a, const u32 b ) + { + return ( ( -condition >> 31 ) & ( a ^ b ) ) ^ b; + } + + //! conditional set based on mask and arithmetic shift + REALINLINE u16 if_c_a_else_b ( const s16 condition, const u16 a, const u16 b ) + { + return ( ( -condition >> 15 ) & ( a ^ b ) ) ^ b; + } + + //! conditional set based on mask and arithmetic shift + REALINLINE u32 if_c_a_else_0 ( const s32 condition, const u32 a ) + { + return ( -condition >> 31 ) & a; + } +#endif + + /* + if (condition) state |= m; else state &= ~m; + */ + REALINLINE void setbit_cond ( u32 &state, s32 condition, u32 mask ) + { + // 0, or any positive to mask + //s32 conmask = -condition >> 31; + state ^= ( ( -condition >> 31 ) ^ state ) & mask; + } + + // NOTE: This is not as exact as the c99/c++11 round function, especially at high numbers starting with 8388609 + // (only low number which seems to go wrong is 0.49999997 which is rounded to 1) + // Also negative 0.5 is rounded up not down unlike with the standard function (p.E. input -0.5 will be 0 and not -1) + inline f32 round_( f32 x ) + { + return floorf( x + 0.5f ); + } + + // calculate: sqrt ( x ) + REALINLINE f32 squareroot(const f32 f) + { + return sqrtf(f); + } + + // calculate: sqrt ( x ) + REALINLINE f64 squareroot(const f64 f) + { + return sqrt(f); + } + + // calculate: sqrt ( x ) + REALINLINE s32 squareroot(const s32 f) + { + return static_cast(squareroot(static_cast(f))); + } + +#ifdef __IRR_HAS_S64 + // calculate: sqrt ( x ) + REALINLINE s64 squareroot(const s64 f) + { + return static_cast(squareroot(static_cast(f))); + } +#endif + + // calculate: 1 / sqrt ( x ) + REALINLINE f64 reciprocal_squareroot(const f64 x) + { + return 1.0 / sqrt(x); + } + + // calculate: 1 / sqrtf ( x ) + REALINLINE f32 reciprocal_squareroot(const f32 f) + { +#if defined ( IRRLICHT_FAST_MATH ) + // NOTE: Unlike comment below says I found inaccuracies already at 4'th significant bit. + // p.E: Input 1, expected 1, got 0.999755859 + + #if defined(_MSC_VER) && !defined(_WIN64) + // SSE reciprocal square root estimate, accurate to 12 significant + // bits of the mantissa + f32 recsqrt; + __asm rsqrtss xmm0, f // xmm0 = rsqrtss(f) + __asm movss recsqrt, xmm0 // return xmm0 + return recsqrt; + +/* + // comes from Nvidia + u32 tmp = (u32(IEEE_1_0 << 1) + IEEE_1_0 - *(u32*)&x) >> 1; + f32 y = *(f32*)&tmp; + return y * (1.47f - 0.47f * x * y * y); +*/ + #else + return 1.f / sqrtf(f); + #endif +#else // no fast math + return 1.f / sqrtf(f); +#endif + } + + // calculate: 1 / sqrtf( x ) + REALINLINE s32 reciprocal_squareroot(const s32 x) + { + return static_cast(reciprocal_squareroot(static_cast(x))); + } + + // calculate: 1 / x + REALINLINE f32 reciprocal( const f32 f ) + { +#if defined (IRRLICHT_FAST_MATH) + // NOTE: Unlike with 1.f / f the values very close to 0 return -nan instead of inf + + // SSE Newton-Raphson reciprocal estimate, accurate to 23 significant + // bi ts of the mantissa + // One Newton-Raphson Iteration: + // f(i+1) = 2 * rcpss(f) - f * rcpss(f) * rcpss(f) +#if defined(_MSC_VER) && !defined(_WIN64) + f32 rec; + __asm rcpss xmm0, f // xmm0 = rcpss(f) + __asm movss xmm1, f // xmm1 = f + __asm mulss xmm1, xmm0 // xmm1 = f * rcpss(f) + __asm mulss xmm1, xmm0 // xmm2 = f * rcpss(f) * rcpss(f) + __asm addss xmm0, xmm0 // xmm0 = 2 * rcpss(f) + __asm subss xmm0, xmm1 // xmm0 = 2 * rcpss(f) + // - f * rcpss(f) * rcpss(f) + __asm movss rec, xmm0 // return xmm0 + return rec; +#else // no support yet for other compilers + return 1.f / f; +#endif + //! i do not divide through 0.. (fpu expection) + // instead set f to a high value to get a return value near zero.. + // -1000000000000.f.. is use minus to stay negative.. + // must test's here (plane.normal dot anything ) checks on <= 0.f + //u32 x = (-(AIR(f) != 0 ) >> 31 ) & ( IR(f) ^ 0xd368d4a5 ) ^ 0xd368d4a5; + //return 1.f / FR ( x ); + +#else // no fast math + return 1.f / f; +#endif + } + + // calculate: 1 / x + REALINLINE f64 reciprocal ( const f64 f ) + { + return 1.0 / f; + } + + + // calculate: 1 / x, low precision allowed + REALINLINE f32 reciprocal_approxim ( const f32 f ) + { +#if defined( IRRLICHT_FAST_MATH) + + // SSE Newton-Raphson reciprocal estimate, accurate to 23 significant + // bi ts of the mantissa + // One Newton-Raphson Iteration: + // f(i+1) = 2 * rcpss(f) - f * rcpss(f) * rcpss(f) +#if defined(_MSC_VER) && !defined(_WIN64) + f32 rec; + __asm rcpss xmm0, f // xmm0 = rcpss(f) + __asm movss xmm1, f // xmm1 = f + __asm mulss xmm1, xmm0 // xmm1 = f * rcpss(f) + __asm mulss xmm1, xmm0 // xmm2 = f * rcpss(f) * rcpss(f) + __asm addss xmm0, xmm0 // xmm0 = 2 * rcpss(f) + __asm subss xmm0, xmm1 // xmm0 = 2 * rcpss(f) + // - f * rcpss(f) * rcpss(f) + __asm movss rec, xmm0 // return xmm0 + return rec; +#else // no support yet for other compilers + return 1.f / f; +#endif + +/* + // SSE reciprocal estimate, accurate to 12 significant bits of + f32 rec; + __asm rcpss xmm0, f // xmm0 = rcpss(f) + __asm movss rec , xmm0 // return xmm0 + return rec; +*/ +/* + register u32 x = 0x7F000000 - IR ( p ); + const f32 r = FR ( x ); + return r * (2.0f - p * r); +*/ +#else // no fast math + return 1.f / f; +#endif + } + + + REALINLINE s32 floor32(f32 x) + { + return (s32) floorf ( x ); + } + + REALINLINE s32 ceil32 ( f32 x ) + { + return (s32) ceilf ( x ); + } + + // NOTE: Please check round_ documentation about some inaccuracies in this compared to standard library round function. + REALINLINE s32 round32(f32 x) + { + return (s32) round_(x); + } + + inline f32 f32_max3(const f32 a, const f32 b, const f32 c) + { + return a > b ? (a > c ? a : c) : (b > c ? b : c); + } + + inline f32 f32_min3(const f32 a, const f32 b, const f32 c) + { + return a < b ? (a < c ? a : c) : (b < c ? b : c); + } + + inline f32 fract ( f32 x ) + { + return x - floorf ( x ); + } + +} // end namespace core +} // end namespace irr + +#ifndef IRRLICHT_FAST_MATH + using irr::core::IR; + using irr::core::FR; +#endif + +#endif diff --git a/include/irrString.h b/include/irrString.h new file mode 100644 index 00000000..0b57864a --- /dev/null +++ b/include/irrString.h @@ -0,0 +1,1525 @@ +// Copyright (C) 2002-2012 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 + +#ifndef __IRR_STRING_H_INCLUDED__ +#define __IRR_STRING_H_INCLUDED__ + +#include "irrTypes.h" +#include "irrAllocator.h" +#include "irrMath.h" +#include +#include +#include + +namespace irr +{ +namespace core +{ + +//! Very simple string class with some useful features. +/** string and string both accept Unicode AND ASCII/Latin-1, +so you can assign Unicode to string and ASCII/Latin-1 to string +(and the other way round) if you want to. + +However, note that the conversation between both is not done using any encoding. +This means that c8 strings are treated as ASCII/Latin-1, not UTF-8, and +are simply expanded to the equivalent wchar_t, while Unicode/wchar_t +characters are truncated to 8-bit ASCII/Latin-1 characters, discarding all +other information in the wchar_t. + +Helper functions for converting between UTF-8 and wchar_t are provided +outside the string class for explicit use. +*/ + +// forward declarations +template > +class string; +static size_t multibyteToWString(string& destination, const char* source, u32 sourceSize); +inline s32 isdigit(s32 c); + +enum eLocaleID +{ + IRR_LOCALE_ANSI = 0, + IRR_LOCALE_GERMAN = 1 +}; + +static eLocaleID locale_current = IRR_LOCALE_ANSI; +static inline void locale_set ( eLocaleID id ) +{ + locale_current = id; +} + +//! Returns a character converted to lower case +static inline u32 locale_lower ( u32 x ) +{ + switch ( locale_current ) + { + case IRR_LOCALE_GERMAN: + case IRR_LOCALE_ANSI: + break; + } + // ansi + return x >= 'A' && x <= 'Z' ? x + 0x20 : x; +} + +//! Returns a character converted to upper case +static inline u32 locale_upper ( u32 x ) +{ + switch ( locale_current ) + { + case IRR_LOCALE_GERMAN: + case IRR_LOCALE_ANSI: + break; + } + + // ansi + return x >= 'a' && x <= 'z' ? x + ( 'A' - 'a' ) : x; +} + +//! Convert this utf-8-encoded string to the platform's wchar. +/** The resulting string is always NULL-terminated and well-formed. +\param len The size of the output buffer in bytes. +*/ +IRRLICHT_API void utf8ToWchar(const char *in, wchar_t *out, const u64 len); + +//! Convert this wchar string to utf-8. +/** The resulting string is always NULL-terminated and well-formed. +\param len The size of the output buffer in bytes. +*/ +IRRLICHT_API void wcharToUtf8(const wchar_t *in, char *out, const u64 len); + + +template +class string +{ +public: + + typedef T char_type; + + //! Default constructor + string() + : array(0), allocated(1), used(1) + { + array = allocator.allocate(1); // new T[1]; + array[0] = 0; + } + + + //! Constructor + string(const string& other) + : array(0), allocated(0), used(0) + { + *this = other; + } + + //! Constructor from other string types + template + string(const string& other) + : array(0), allocated(0), used(0) + { + *this = other; + } + + + //! Constructs a string from a float + explicit string(const double number) + : array(0), allocated(0), used(0) + { + c8 tmpbuf[255]; + snprintf_irr(tmpbuf, 255, "%0.6f", number); + *this = tmpbuf; + } + + + //! Constructs a string from an int + explicit string(int number) + : array(0), allocated(0), used(0) + { + // store if negative and make positive + + bool negative = false; + if (number < 0) + { + number *= -1; + negative = true; + } + + // temporary buffer for 16 numbers + + c8 tmpbuf[16]={0}; + u32 idx = 15; + + // special case '0' + + if (!number) + { + tmpbuf[14] = '0'; + *this = &tmpbuf[14]; + return; + } + + // add numbers + + while(number && idx) + { + --idx; + tmpbuf[idx] = (c8)('0' + (number % 10)); + number /= 10; + } + + // add sign + + if (negative) + { + --idx; + tmpbuf[idx] = '-'; + } + + *this = &tmpbuf[idx]; + } + + + //! Constructs a string from an unsigned int + explicit string(unsigned int number) + : array(0), allocated(0), used(0) + { + // temporary buffer for 16 numbers + + c8 tmpbuf[16]={0}; + u32 idx = 15; + + // special case '0' + + if (!number) + { + tmpbuf[14] = '0'; + *this = &tmpbuf[14]; + return; + } + + // add numbers + + while(number && idx) + { + --idx; + tmpbuf[idx] = (c8)('0' + (number % 10)); + number /= 10; + } + + *this = &tmpbuf[idx]; + } + + + //! Constructs a string from a long + explicit string(long number) + : array(0), allocated(0), used(0) + { + // store if negative and make positive + + bool negative = false; + if (number < 0) + { + number *= -1; + negative = true; + } + + // temporary buffer for 16 numbers + + c8 tmpbuf[16]={0}; + u32 idx = 15; + + // special case '0' + + if (!number) + { + tmpbuf[14] = '0'; + *this = &tmpbuf[14]; + return; + } + + // add numbers + + while(number && idx) + { + --idx; + tmpbuf[idx] = (c8)('0' + (number % 10)); + number /= 10; + } + + // add sign + + if (negative) + { + --idx; + tmpbuf[idx] = '-'; + } + + *this = &tmpbuf[idx]; + } + + + //! Constructs a string from an unsigned long + explicit string(unsigned long number) + : array(0), allocated(0), used(0) + { + // temporary buffer for 16 numbers + + c8 tmpbuf[16]={0}; + u32 idx = 15; + + // special case '0' + + if (!number) + { + tmpbuf[14] = '0'; + *this = &tmpbuf[14]; + return; + } + + // add numbers + + while(number && idx) + { + --idx; + tmpbuf[idx] = (c8)('0' + (number % 10)); + number /= 10; + } + + *this = &tmpbuf[idx]; + } + + + //! Constructor for copying a string from a pointer with a given length + template + string(const B* const c, u32 length) + : array(0), allocated(0), used(0) + { + if (!c) + { + // correctly init the string to an empty one + *this=""; + return; + } + + allocated = used = length+1; + array = allocator.allocate(used); // new T[used]; + + for (u32 l = 0; l + string(const B* const c) + : array(0), allocated(0), used(0) + { + *this = c; + } + + + //! Destructor + ~string() + { + allocator.deallocate(array); // delete [] array; + } + + + //! Assignment operator + string& operator=(const string& other) + { + if (this == &other) + return *this; + + used = other.size()+1; + if (used>allocated) + { + allocator.deallocate(array); // delete [] array; + allocated = used; + array = allocator.allocate(used); //new T[used]; + } + + const T* p = other.c_str(); + for (u32 i=0; i + string& operator=(const string& other) + { + *this = other.c_str(); + return *this; + } + + + //! Assignment operator for strings, ASCII and Unicode + template + string& operator=(const B* const c) + { + if (!c) + { + if (!array) + { + array = allocator.allocate(1); //new T[1]; + allocated = 1; + } + used = 1; + array[0] = 0x0; + return *this; + } + + if ((void*)c == (void*)array) + return *this; + + u32 len = 0; + const B* p = c; + do + { + ++len; + } while(*p++); + + // we'll keep the old string for a while, because the new + // string could be a part of the current string. + T* oldArray = array; + + used = len; + if (used>allocated) + { + allocated = used; + array = allocator.allocate(used); //new T[used]; + } + + for (u32 l = 0; l operator+(const string& other) const + { + string str(*this); + str.append(other); + + return str; + } + + + //! Append operator for strings, ASCII and Unicode + template + string operator+(const B* const c) const + { + string str(*this); + str.append(c); + + return str; + } + + + //! Direct access operator + T& operator [](const u32 index) + { + _IRR_DEBUG_BREAK_IF(index>=used) // bad index + return array[index]; + } + + + //! Direct access operator + const T& operator [](const u32 index) const + { + _IRR_DEBUG_BREAK_IF(index>=used) // bad index + return array[index]; + } + + + //! Equality operator + bool operator==(const T* const str) const + { + if (!str) + return false; + + u32 i; + for (i=0; array[i] && str[i]; ++i) + if (array[i] != str[i]) + return false; + + return (!array[i] && !str[i]); + } + + + //! Equality operator + bool operator==(const string& other) const + { + for (u32 i=0; array[i] && other.array[i]; ++i) + if (array[i] != other.array[i]) + return false; + + return used == other.used; + } + + + //! Is smaller comparator + bool operator<(const string& other) const + { + for (u32 i=0; array[i] && other.array[i]; ++i) + { + const s32 diff = array[i] - other.array[i]; + if (diff) + return (diff < 0); + } + + return (used < other.used); + } + + + //! Inequality operator + bool operator!=(const T* const str) const + { + return !(*this == str); + } + + + //! Inequality operator + bool operator!=(const string& other) const + { + return !(*this == other); + } + + + //! Returns length of the string's content + /** \return Length of the string's content in characters, excluding + the trailing NUL. */ + u32 size() const + { + return used-1; + } + + //! Informs if the string is empty or not. + //! \return True if the string is empty, false if not. + bool empty() const + { + return (size() == 0); + } + + void clear(bool releaseMemory=true) + { + if ( releaseMemory ) + { + reallocate(1); + } + array[0] = 0; + used = 1; + } + + //! Returns character string + /** \return pointer to C-style NUL terminated string. */ + const T* c_str() const + { + return array; + } + + + //! Makes the string lower case. + string& make_lower() + { + for (u32 i=0; array[i]; ++i) + array[i] = locale_lower ( array[i] ); + return *this; + } + + + //! Makes the string upper case. + string& make_upper() + { + for (u32 i=0; array[i]; ++i) + array[i] = locale_upper ( array[i] ); + return *this; + } + + + //! Compares the strings ignoring case. + /** \param other: Other string to compare. + \return True if the strings are equal ignoring case. */ + bool equals_ignore_case(const string& other) const + { + for(u32 i=0; array[i] && other[i]; ++i) + if (locale_lower( array[i]) != locale_lower(other[i])) + return false; + + return used == other.used; + } + + //! Compares the strings ignoring case. + /** \param other: Other string to compare. + \param sourcePos: where to start to compare in the string + \return True if the strings are equal ignoring case. */ + bool equals_substring_ignore_case(const string&other, const s32 sourcePos = 0 ) const + { + if ( (u32) sourcePos >= used ) + return false; + + u32 i; + for( i=0; array[sourcePos + i] && other[i]; ++i) + if (locale_lower( array[sourcePos + i]) != locale_lower(other[i])) + return false; + + return array[sourcePos + i] == 0 && other[i] == 0; + } + + + //! Compares the strings ignoring case. + /** \param other: Other string to compare. + \return True if this string is smaller ignoring case. */ + bool lower_ignore_case(const string& other) const + { + for(u32 i=0; array[i] && other.array[i]; ++i) + { + s32 diff = (s32) locale_lower ( array[i] ) - (s32) locale_lower ( other.array[i] ); + if ( diff ) + return diff < 0; + } + + return used < other.used; + } + + + //! compares the first n characters of the strings + /** \param other Other string to compare. + \param n Number of characters to compare + \return True if the n first characters of both strings are equal. */ + bool equalsn(const string& other, u32 n) const + { + u32 i; + for(i=0; i < n && array[i] && other[i]; ++i) + if (array[i] != other[i]) + return false; + + // if one (or both) of the strings was smaller then they + // are only equal if they have the same length + return (i == n) || (used == other.used); + } + + + //! compares the first n characters of the strings + /** \param str Other string to compare. + \param n Number of characters to compare + \return True if the n first characters of both strings are equal. */ + bool equalsn(const T* const str, u32 n) const + { + if (!str) + return false; + u32 i; + for(i=0; i < n && array[i] && str[i]; ++i) + if (array[i] != str[i]) + return false; + + // if one (or both) of the strings was smaller then they + // are only equal if they have the same length + return (i == n) || (array[i] == 0 && str[i] == 0); + } + + + //! Appends a character to this string + /** \param character: Character to append. */ + string& append(T character) + { + if (used + 1 > allocated) + reallocate(used + 1); + + ++used; + + array[used-2] = character; + array[used-1] = 0; + + return *this; + } + + + //! Appends a char string to this string + /** \param other: Char string to append. */ + /** \param length: The length of the string to append. */ + string& append(const T* const other, u32 length=0xffffffff) + { + if (!other) + return *this; + + u32 len = 0; + const T* p = other; + while(*p) + { + ++len; + ++p; + } + if (len > length) + len = length; + + if (used + len > allocated) + reallocate(used + len); + + --used; + ++len; + + for (u32 l=0; l& append(const string& other) + { + if (other.size() == 0) + return *this; + + --used; + const u32 len = other.size()+1; + + if (used + len > allocated) + reallocate(used + len); + + for (u32 l=0; l& append(const string& other, u32 length) + { + if (other.size() == 0) + return *this; + + if (other.size() < length) + { + append(other); + return *this; + } + + if (used + length > allocated) + reallocate(used + length); + + --used; + + for (u32 l=0; l& insert(u32 pos, const char* s, u32 n) + { + if ( pos < used ) + { + reserve(used+n); + + // move stuff behind insert point + const u32 end = used+n-1; + for (u32 i=0; i + s32 findFirstCharNotInList(const B* const c, u32 count=1) const + { + if (!c || !count) + return -1; + + for (u32 i=0; i + s32 findLastCharNotInList(const B* const c, u32 count=1) const + { + if (!c || !count) + return -1; + + for (s32 i=(s32)(used-2); i>=0; --i) + { + u32 j; + for (j=0; j=0; --i) + if (array[i] == c) + return i; + + return -1; + } + + //! finds last occurrence of a character of a list in string + /** \param c: List of strings to find. For example if the method + should find the last occurrence of 'a' or 'b', this parameter should be "ab". + \param count: Amount of characters in the list. Usually, + this should be strlen(c) + \return Position where one of the characters has been found, + or -1 if not found. */ + s32 findLastChar(const T* const c, u32 count=1) const + { + if (!c || !count) + return -1; + + for (s32 i=(s32)used-2; i>=0; --i) + for (u32 j=0; j + s32 find(const B* const str, const u32 start = 0) const + { + if (str && *str) + { + u32 len = 0; + + while (str[len]) + ++len; + + if (len > used-1) + return -1; + + for (u32 i=start; i subString(u32 begin, s32 length, bool make_lower = false ) const + { + // if start after string + // or no proper substring length + if ((length <= 0) || (begin>=size())) + return string(""); + // clamp length to maximal value + if ((length+begin) > size()) + length = size()-begin; + + string o; + o.reserve(length+1); + + if ( !make_lower ) + { + for (s32 i=0; i& operator += (T c) + { + append(c); + return *this; + } + + + //! Appends a char string to this string + /** \param c Char string to append. */ + string& operator += (const T* const c) + { + append(c); + return *this; + } + + + //! Appends a string to this string + /** \param other String to append. */ + string& operator += (const string& other) + { + append(other); + return *this; + } + + + //! Appends a string representation of a number to this string + /** \param i Number to append. */ + string& operator += (const int i) + { + append(string(i)); + return *this; + } + + + //! Appends a string representation of a number to this string + /** \param i Number to append. */ + string& operator += (const unsigned int i) + { + append(string(i)); + return *this; + } + + + //! Appends a string representation of a number to this string + /** \param i Number to append. */ + string& operator += (const long i) + { + append(string(i)); + return *this; + } + + + //! Appends a string representation of a number to this string + /** \param i Number to append. */ + string& operator += (const unsigned long i) + { + append(string(i)); + return *this; + } + + + //! Appends a string representation of a number to this string + /** \param i Number to append. */ + string& operator += (const double i) + { + append(string(i)); + return *this; + } + + + //! Appends a string representation of a number to this string + /** \param i Number to append. */ + string& operator += (const float i) + { + append(string(i)); + return *this; + } + + + //! Replaces all characters of a special type with another one + /** \param toReplace Character to replace. + \param replaceWith Character replacing the old one. */ + string& replace(T toReplace, T replaceWith) + { + for (u32 i=0; i& replace(const string& toReplace, const string& replaceWith) + { + if (toReplace.size() == 0) + return *this; + + const T* other = toReplace.c_str(); + const T* replace = replaceWith.c_str(); + const u32 other_size = toReplace.size(); + const u32 replace_size = replaceWith.size(); + + // Determine the delta. The algorithm will change depending on the delta. + s32 delta = replace_size - other_size; + + // A character for character replace. The string will not shrink or grow. + if (delta == 0) + { + s32 pos = 0; + while ((pos = find(other, pos)) != -1) + { + for (u32 i = 0; i < replace_size; ++i) + array[pos + i] = replace[i]; + ++pos; + } + return *this; + } + + // We are going to be removing some characters. The string will shrink. + if (delta < 0) + { + u32 i = 0; + for (u32 pos = 0; pos < used; ++i, ++pos) + { + // Is this potentially a match? + if (array[pos] == *other) + { + // Check to see if we have a match. + u32 j; + for (j = 0; j < other_size; ++j) + { + if (array[pos + j] != other[j]) + break; + } + + // If we have a match, replace characters. + if (j == other_size) + { + for (j = 0; j < replace_size; ++j) + array[i + j] = replace[j]; + i += replace_size - 1; + pos += other_size - 1; + continue; + } + } + + // No match found, just copy characters. + array[i] = array[pos]; + } + array[i-1] = 0; + used = i; + + return *this; + } + + // We are going to be adding characters, so the string size will increase. + // Count the number of times toReplace exists in the string so we can allocate the new size. + u32 find_count = 0; + s32 pos = 0; + while ((pos = find(other, pos)) != -1) + { + ++find_count; + ++pos; + } + + // Re-allocate the string now, if needed. + u32 len = delta * find_count; + if (used + len > allocated) + reallocate(used + len); + + // Start replacing. + pos = 0; + while ((pos = find(other, pos)) != -1) + { + T* start = array + pos + other_size - 1; + T* ptr = array + used - 1; + T* end = array + delta + used -1; + + // Shift characters to make room for the string. + while (ptr != start) + { + *end = *ptr; + --ptr; + --end; + } + + // Add the new string now. + for (u32 i = 0; i < replace_size; ++i) + array[pos + i] = replace[i]; + + pos += replace_size; + used += delta; + } + + return *this; + } + + + //! Removes characters from a string. + /** \param c: Character to remove. */ + string& remove(T c) + { + u32 pos = 0; + u32 found = 0; + for (u32 i=0; i& remove(const string& toRemove) + { + u32 size = toRemove.size(); + if ( size == 0 ) + return *this; + u32 pos = 0; + u32 found = 0; + for (u32 i=0; i& removeChars(const string & characters) + { + if (characters.size() == 0) + return *this; + + u32 pos = 0; + u32 found = 0; + for (u32 i=0; i& trim(const string & whitespace = " \t\n\r") + { + // find start and end of the substring without the specified characters + const s32 begin = findFirstCharNotInList(whitespace.c_str(), whitespace.used); + if (begin == -1) + return (*this=""); + + const s32 end = findLastCharNotInList(whitespace.c_str(), whitespace.used); + + return (*this = subString(begin, (end +1) - begin)); + } + + //! Erase 0's at the end when a string ends with a floating point number + /** After generating strings from floats we often end up with strings + ending up with lots of zeros which don't add any value. Erase 'em all. + Examples: "0.100000" becomes "0.1" + "10.000000" becomes "10" + "foo 3.140000" becomes "foo 3.14" + "no_num.000" stays "no_num.000" + "1." stays "1." + */ + string& eraseTrailingFloatZeros(char decimalPoint='.') + { + s32 i=findLastCharNotInList("0", 1); + if ( i > 0 && (u32)i < used-2 ) // non 0 must be found and not last char (also used is at least 2 when i > 0) + { + u32 eraseStart=i+1; + u32 dot=0; + if( core::isdigit(array[i]) ) + { + while( --i>0 && core::isdigit(array[i]) ); + if ( array[i] == decimalPoint ) + dot = i; + } + else if ( array[i] == decimalPoint ) + { + dot = i; + eraseStart = i; + } + if ( dot > 0 && core::isdigit(array[dot-1]) ) + { + array[eraseStart] = 0; + used = eraseStart+1; + } + } + return *this; + } + + //! Erases a character from the string. + /** May be slow, because all elements + following after the erased element have to be copied. + \param index: Index of element to be erased. */ + string& erase(u32 index) + { + _IRR_DEBUG_BREAK_IF(index>=used) // access violation + + for (u32 i=index+1; i& validate() + { + // terminate on existing null + for (u32 i=0; i 0 ) + { + used = allocated; + array[used-1] = 0; + } + else + { + used = 0; + } + + return *this; + } + + //! gets the last char of a string or null + T lastChar() const + { + return used > 1 ? array[used-2] : 0; + } + + //! Split string into parts (tokens). + /** This method will split a string at certain delimiter characters + into the container passed in as reference. The type of the container + has to be given as template parameter. It must provide a push_back and + a size method. + \param ret The result container. Tokens are added, the container is not cleared. + \param delimiter C-style string of delimiter characters + \param countDelimiters Number of delimiter characters + \param ignoreEmptyTokens Flag to avoid empty substrings in the result + container. If two delimiters occur without a character in between or an + empty substring would be placed in the result. Or if a delimiter is the last + character an empty substring would be added at the end. If this flag is set, + only non-empty strings are stored. + \param keepSeparators Flag which allows to add the separator to the + result string. If this flag is true, the concatenation of the + substrings results in the original string. Otherwise, only the + characters between the delimiters are returned. + \return The number of resulting substrings + */ + template + u32 split(container& ret, const T* const delimiter, u32 countDelimiters=1, bool ignoreEmptyTokens=true, bool keepSeparators=false) const + { + if (!delimiter) + return 0; + + const u32 oldSize=ret.size(); + + u32 tokenStartIdx = 0; + for (u32 i=0; i 0) + ret.push_back(string(&array[tokenStartIdx], i - tokenStartIdx)); + else if ( !ignoreEmptyTokens ) + ret.push_back(string()); + if ( keepSeparators ) + { + ret.push_back(string(&array[i], 1)); + } + + tokenStartIdx = i+1; + break; + } + } + } + if ((used - 1) > tokenStartIdx) + ret.push_back(string(&array[tokenStartIdx], (used - 1) - tokenStartIdx)); + else if ( !ignoreEmptyTokens ) + ret.push_back(string()); + + return ret.size()-oldSize; + } + + friend size_t multibyteToWString(string& destination, const char* source, u32 sourceSize); + +private: + + //! Reallocate the array, make it bigger or smaller + void reallocate(u32 new_size) + { + T* old_array = array; + + array = allocator.allocate(new_size); //new T[new_size]; + allocated = new_size; + + const u32 amount = used < new_size ? used : new_size; + for (u32 i=0; i stringc; + +//! Typedef for wide character strings +typedef string stringw; + +//! Convert multibyte string to wide-character string +/** Wrapper around mbstowcs from standard library, but directly using Irrlicht string class. +What the function does exactly depends on the LC_CTYPE of the current c locale. +\param destination Wide-character string receiving the converted source +\param source multibyte string +\return The number of wide characters written to destination, not including the eventual terminating null character or -1 when conversion failed */ +static inline size_t multibyteToWString(string& destination, const core::string& source) +{ + return multibyteToWString(destination, source.c_str(), (u32)source.size()); +} + +//! Convert multibyte string to wide-character string +/** Wrapper around mbstowcs from standard library, but directly writing to Irrlicht string class. +What the function does exactly depends on the LC_CTYPE of the current c locale. +\param destination Wide-character string receiving the converted source +\param source multibyte string +\return The number of wide characters written to destination, not including the eventual terminating null character or -1 when conversion failed. */ +static inline size_t multibyteToWString(string& destination, const char* source) +{ + const u32 s = source ? (u32)strlen(source) : 0; + return multibyteToWString(destination, source, s); +} + +//! Internally used by the other multibyteToWString functions +static size_t multibyteToWString(string& destination, const char* source, u32 sourceSize) +{ + if ( sourceSize ) + { + destination.reserve(sourceSize+1); +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable: 4996) // 'mbstowcs': This function or variable may be unsafe. Consider using mbstowcs_s instead. +#endif + const size_t written = mbstowcs(destination.array, source, (size_t)sourceSize); +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + if ( written != (size_t)-1 ) + { + destination.used = (u32)written+1; + destination.array[destination.used-1] = 0; + } + else + { + // Likely character which got converted until the invalid character was encountered are in destination now. + // And it seems even 0-terminated, but I found no documentation anywhere that this (the 0-termination) is guaranteed :-( + destination.clear(); + } + return written; + } + else + { + destination.clear(); + return 0; + } +} + + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/include/irrTypes.h b/include/irrTypes.h new file mode 100644 index 00000000..aa99b50e --- /dev/null +++ b/include/irrTypes.h @@ -0,0 +1,247 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_TYPES_H_INCLUDED__ +#define __IRR_TYPES_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#if defined(__GNUC__) + #include // for __WORDSIZE +#endif + +namespace irr +{ + +//! 8 bit unsigned variable. +/** This is a typedef for unsigned char, it ensures portability of the engine. */ +#if defined(_MSC_VER) || ((__BORLANDC__ >= 0x530) && !defined(__STRICT_ANSI__)) +typedef unsigned __int8 u8; +#else +typedef unsigned char u8; +#endif + +//! 8 bit signed variable. +/** This is a typedef for signed char, it ensures portability of the engine. */ +#if defined(_MSC_VER) || ((__BORLANDC__ >= 0x530) && !defined(__STRICT_ANSI__)) +typedef __int8 s8; +#else +typedef signed char s8; +#endif + +//! 8 bit character variable. +/** This is a typedef for char, it ensures portability of the engine. */ +typedef char c8; + + + +//! 16 bit unsigned variable. +/** This is a typedef for unsigned short, it ensures portability of the engine. */ +#if defined(_MSC_VER) || ((__BORLANDC__ >= 0x530) && !defined(__STRICT_ANSI__)) +typedef unsigned __int16 u16; +#else +typedef unsigned short u16; +#endif + +//! 16 bit signed variable. +/** This is a typedef for signed short, it ensures portability of the engine. */ +#if defined(_MSC_VER) || ((__BORLANDC__ >= 0x530) && !defined(__STRICT_ANSI__)) +typedef __int16 s16; +#else +typedef signed short s16; +#endif + + + +//! 32 bit unsigned variable. +/** This is a typedef for unsigned int, it ensures portability of the engine. */ +#if defined(_MSC_VER) || ((__BORLANDC__ >= 0x530) && !defined(__STRICT_ANSI__)) +typedef unsigned __int32 u32; +#else +typedef unsigned int u32; +#endif + +//! 32 bit signed variable. +/** This is a typedef for signed int, it ensures portability of the engine. */ +#if defined(_MSC_VER) || ((__BORLANDC__ >= 0x530) && !defined(__STRICT_ANSI__)) +typedef __int32 s32; +#else +typedef signed int s32; +#endif + + +#ifdef __IRR_HAS_S64 +//! 64 bit unsigned variable. +/** This is a typedef for 64bit uint, it ensures portability of the engine. */ +#if defined(_MSC_VER) || ((__BORLANDC__ >= 0x530) && !defined(__STRICT_ANSI__)) +typedef unsigned __int64 u64; +#elif defined(__GNUC__) +#if defined(__WORDSIZE) && __WORDSIZE == 64 +typedef unsigned long int u64; +#else +__extension__ typedef unsigned long long u64; +#endif +#else +typedef unsigned long long u64; +#endif + +//! 64 bit signed variable. +/** This is a typedef for 64bit int, it ensures portability of the engine. */ +#if defined(_MSC_VER) || ((__BORLANDC__ >= 0x530) && !defined(__STRICT_ANSI__)) +typedef __int64 s64; +#elif defined(__GNUC__) +#if defined(__WORDSIZE) && __WORDSIZE == 64 +typedef long int s64; +#else +__extension__ typedef long long s64; +#endif +#else +typedef long long s64; +#endif +#endif // __IRR_HAS_S64 + + + +//! 32 bit floating point variable. +/** This is a typedef for float, it ensures portability of the engine. */ +typedef float f32; + +//! 64 bit floating point variable. +/** This is a typedef for double, it ensures portability of the engine. */ +typedef double f64; + + +} // end namespace irr + + +#include +#ifdef _IRR_WINDOWS_API_ +//! Defines for s{w,n}printf_irr because s{w,n}printf methods do not match the ISO C +//! standard on Windows platforms. +//! We want int snprintf_irr(char *str, size_t size, const char *format, ...); +//! and int swprintf_irr(wchar_t *wcs, size_t maxlen, const wchar_t *format, ...); +#if defined(_MSC_VER) && _MSC_VER > 1310 && !defined (_WIN32_WCE) +#define swprintf_irr swprintf_s +#define snprintf_irr sprintf_s +#elif !defined(__CYGWIN__) +#define swprintf_irr _snwprintf +#define snprintf_irr _snprintf +#endif + +// define the wchar_t type if not already built in. +#ifdef _MSC_VER +#ifndef _WCHAR_T_DEFINED +//! A 16 bit wide character type. +/** + Defines the wchar_t-type. + In VS6, its not possible to tell + the standard compiler to treat wchar_t as a built-in type, and + sometimes we just don't want to include the huge stdlib.h or wchar.h, + so we'll use this. +*/ +typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif // wchar is not defined +#endif // microsoft compiler +#else +#define swprintf_irr swprintf +#define snprintf_irr snprintf +#endif // _IRR_WINDOWS_API_ + +namespace irr +{ + +//! Type name for character type used by the file system. +/** Should the wide character version of the FileSystem be used it is a +16 bit character variable. Used for Unicode Filesystem and Unicode strings. +Else it is a 8 bit character variable. Used for ansi Filesystem and non-unicode +strings +*/ +#if defined(_IRR_WCHAR_FILESYSTEM) + typedef wchar_t fschar_t; + #define _IRR_TEXT(X) L##X +#else + typedef char fschar_t; + #define _IRR_TEXT(X) X +#endif + +} // end namespace irr + +//! define a break macro for debugging. +#if defined(_DEBUG) +#if defined(_IRR_WINDOWS_API_) && defined(_MSC_VER) && !defined (_WIN32_WCE) +#if defined(WIN64) || defined(_WIN64) // using portable common solution for x64 configuration + #include + #define _IRR_DEBUG_BREAK_IF( _CONDITION_ ) if (_CONDITION_) {_CrtDbgBreak();} +#else + #define _IRR_DEBUG_BREAK_IF( _CONDITION_ ) if (_CONDITION_) {_asm int 3} +#endif +#else + #include "assert.h" + #define _IRR_DEBUG_BREAK_IF( _CONDITION_ ) assert( !(_CONDITION_) ); +#endif +#else + #define _IRR_DEBUG_BREAK_IF( _CONDITION_ ) +#endif + +//! Defines a deprecated macro which generates a warning at compile time +/** The usage is simple +For typedef: typedef _IRR_DEPRECATED_ int test1; +For classes/structs: class _IRR_DEPRECATED_ test2 { ... }; +For methods: class test3 { _IRR_DEPRECATED_ virtual void foo() {} }; +For functions: template _IRR_DEPRECATED_ void test4(void) {} +**/ +#if defined(IGNORE_DEPRECATED_WARNING) +#define _IRR_DEPRECATED_ +#elif _MSC_VER >= 1310 //vs 2003 or higher +#define _IRR_DEPRECATED_ __declspec(deprecated) +#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) // all versions above 3.0 should support this feature +#define _IRR_DEPRECATED_ __attribute__ ((deprecated)) +#else +#define _IRR_DEPRECATED_ +#endif + +//! Defines an override macro, to protect virtual functions from typos and other mismatches +/** Usage in a derived class: +virtual void somefunc() _IRR_OVERRIDE_; +*/ +#if ( ((__GNUC__ > 4 ) || ((__GNUC__ == 4 ) && (__GNUC_MINOR__ >= 7))) && (defined(__GXX_EXPERIMENTAL_CXX0X) || __cplusplus >= 201103L) ) +#define _IRR_OVERRIDE_ override +#elif (_MSC_VER >= 1600 ) /* supported since MSVC 2010 */ +#define _IRR_OVERRIDE_ override +#elif (__clang_major__ >= 3 && __has_feature(cxx_override_control)) +#define _IRR_OVERRIDE_ override +#else +#define _IRR_OVERRIDE_ +#endif + +// memory debugging +#if defined(_DEBUG) && defined(IRRLICHT_EXPORTS) && defined(_MSC_VER) && \ + (_MSC_VER > 1299) && !defined(_IRR_DONT_DO_MEMORY_DEBUGGING_HERE) && !defined(_WIN32_WCE) + + #define CRTDBG_MAP_ALLOC + #define _CRTDBG_MAP_ALLOC + #define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__) + #include + #include + #define new DEBUG_CLIENTBLOCK +#endif + +//! ignore VC8 warning deprecated +/** The Microsoft compiler */ +#if defined(_IRR_WINDOWS_API_) && defined(_MSC_VER) && (_MSC_VER >= 1400) + //#pragma warning( disable: 4996) + //#define _CRT_SECURE_NO_DEPRECATE 1 + //#define _CRT_NONSTDC_NO_DEPRECATE 1 +#endif + + +//! creates four CC codes used in Irrlicht for simple ids +/** some compilers can create those by directly writing the +code like 'code', but some generate warnings so we use this macro here */ +#define MAKE_IRR_ID(c0, c1, c2, c3) \ + ((irr::u32)(irr::u8)(c0) | ((irr::u32)(irr::u8)(c1) << 8) | \ + ((irr::u32)(irr::u8)(c2) << 16) | ((irr::u32)(irr::u8)(c3) << 24 )) + +#endif // __IRR_TYPES_H_INCLUDED__ diff --git a/include/irrXML.h b/include/irrXML.h new file mode 100644 index 00000000..57c3b549 --- /dev/null +++ b/include/irrXML.h @@ -0,0 +1,645 @@ +// Copyright (C) 2002-2012 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 + +#ifndef __IRR_XML_H_INCLUDED__ +#define __IRR_XML_H_INCLUDED__ + +#include +#include "IrrCompileConfig.h" +#include "irrArray.h" +#include "irrString.h" + +/** \mainpage irrXML 1.2 API documentation +
+ + \section intro Introduction + + Welcome to the irrXML API documentation. + Here you'll find any information you'll need to develop applications with + irrXML. If you look for a tutorial on how to start, take a look at the \ref irrxmlexample, + at the homepage of irrXML at www.ambiera.com/irrxml/ + or into the SDK in the directory example. + + irrXML is intended to be a high speed and easy-to-use XML Parser for C++, and + this documentation is an important part of it. If you have any questions or + suggestions, just send a email to the author of the engine, Nikolaus Gebhardt + (niko (at) irrlicht3d.org). For more information about this parser, see \ref history. + + \section features Features + + irrXML provides forward-only, read-only + access to a stream of non validated XML data. It was fully implemented by + Nikolaus Gebhardt. Its current features are: + + - It it fast as lighting and has very low memory usage. It was + developed with the intention of being used in 3D games, as it already has been. + - irrXML is very small: It only consists of 60 KB of code and can be added easily + to your existing project. + - Of course, it is platform independent and works with lots of compilers. + - It is able to parse ASCII, UTF-8, UTF-16 and UTF-32 text files, both in + little and big endian format. + - Independent of the input file format, the parser can return all strings in ASCII, UTF-8, + UTF-16 and UTF-32 format. + - With its optional file access abstraction it has the advantage that it can read not + only from files but from any type of data (memory, network, ...). For example when + used with the Irrlicht Engine, it directly reads from compressed .zip files. + - Just like the Irrlicht Engine for which it was originally created, it is extremely easy + to use. + - It has no external dependencies, it does not even need the STL. + + Although irrXML has some strengths, it currently also has the following limitations: + + - The input xml file is not validated and assumed to be correct. + + \section irrxmlexample Example + + The following code demonstrates the basic usage of irrXML. A simple xml + file like this is parsed: + \code + + + + + + Welcome to the Mesh Viewer of the "Irrlicht Engine". + + + \endcode + + The code for parsing this file would look like this: + \code + #include + using namespace irr; // irrXML is located in the namespace irr::io + using namespace io; + + #include // we use STL strings to store data in this example + + void main() + { + // create the reader using one of the factory functions + + IrrXMLReader* xml = createIrrXMLReader("config.xml"); + + // strings for storing the data we want to get out of the file + std::string modelFile; + std::string messageText; + std::string caption; + + // parse the file until end reached + + while(xml && xml->read()) + { + switch(xml->getNodeType()) + { + case EXN_TEXT: + // in this xml file, the only text which occurs is the messageText + messageText = xml->getNodeData(); + break; + case EXN_ELEMENT: + { + if (!strcmp("model", xml->getNodeName())) + modelFile = xml->getAttributeValue("file"); + else + if (!strcmp("messageText", xml->getNodeName())) + caption = xml->getAttributeValue("caption"); + } + break; + } + } + + // delete the xml parser after usage + delete xml; + } + \endcode + + \section howto How to use + + Simply add the source files in the /src directory of irrXML to your project. Done. + + \section license License + + The irrXML license is based on the zlib license. Basically, this means you can do with + irrXML whatever you want: + + Copyright (C) 2002-2012 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 + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. + + \section history History + + As lots of references in this documentation and the source show, this xml + parser has originally been a part of the + Irrlicht Engine. But because + the parser has become very useful with the latest release, people asked for a + separate version of it, to be able to use it in non Irrlicht projects. With + irrXML 1.0, this has now been done. +*/ + +namespace irr +{ +namespace io +{ + //! Enumeration of all supported source text file formats + enum ETEXT_FORMAT + { + //! ASCII, file without byte order mark, or not a text file + ETF_ASCII, + + //! UTF-8 format + ETF_UTF8, + + //! UTF-16 format, big endian + ETF_UTF16_BE, + + //! UTF-16 format, little endian + ETF_UTF16_LE, + + //! UTF-32 format, big endian + ETF_UTF32_BE, + + //! UTF-32 format, little endian + ETF_UTF32_LE + }; + + + //! Enumeration for all xml nodes which are parsed by IrrXMLReader + enum EXML_NODE + { + //! No xml node. This is usually the node if you did not read anything yet. + EXN_NONE, + + //! An xml element such as <foo> + EXN_ELEMENT, + + //! End of an xml element such as </foo> + EXN_ELEMENT_END, + + //! Text within an xml element: <foo> this is the text. </foo> + //! Also text between 2 xml elements: </foo> this is the text. <foo> + EXN_TEXT, + + //! An xml comment like <!-- I am a comment --> or a DTD definition. + EXN_COMMENT, + + //! An xml cdata section like <![CDATA[ this is some CDATA ]]> + EXN_CDATA, + + //! Unknown element. + EXN_UNKNOWN + }; + + //! Callback class for file read abstraction. + /** With this, it is possible to make the xml parser read in other + things than just files. The Irrlicht engine is using this for example to + read xml from compressed .zip files. To make the parser read in + any other data, derive a class from this interface, implement the + two methods to read your data and give a pointer to an instance of + your implementation when calling createIrrXMLReader(), + createIrrXMLReaderUTF16() or createIrrXMLReaderUTF32() */ + class IFileReadCallBack + { + public: + + //! Destructor + virtual ~IFileReadCallBack() {} + + //! Reads an amount of bytes from the file. + /** \param buffer: Pointer to buffer where to read bytes will be written to. + \param sizeToRead: Amount of bytes to read from the file. + \return Returns how much bytes were read. */ + virtual int read(void* buffer, int sizeToRead) = 0; + + //! Returns size of file in bytes on success or -1L on failure. + virtual long getSize() const = 0; + }; + + //! Empty class to be used as parent class for IrrXMLReader. + /** If you need another class as base class for the xml reader, you can do this by creating + the reader using for example new CXMLReaderImpl(yourcallback); + The Irrlicht Engine for example needs IReferenceCounted as base class for every object to + let it automatically reference counted, hence it replaces IXMLBase with IReferenceCounted. + See irrXML.cpp on how this can be done in detail. */ + class IXMLBase + { + }; + + //! Interface providing easy read access to a XML file. + /** You can create an instance of this reader using one of the factory functions + createIrrXMLReader(), createIrrXMLReaderUTF16() and createIrrXMLReaderUTF32(). + If using the parser from the Irrlicht Engine, please use IFileSystem::createXMLReader() + instead. + For a detailed intro how to use the parser, see \ref irrxmlexample and \ref features. + + The typical usage of this parser looks like this: + \code + #include + using namespace irr; // irrXML is located in the namespace irr::io + using namespace io; + + void main() + { + // create the reader using one of the factory functions + IrrXMLReader* xml = createIrrXMLReader("config.xml"); + + if (xml == 0) + return; // file could not be opened + + // parse the file until end reached + while(xml->read()) + { + // based on xml->getNodeType(), do something. + } + + // delete the xml parser after usage + delete xml; + } + \endcode + See \ref irrxmlexample for a more detailed example. + */ + template + class IIrrXMLReader : public super_class + { + public: + + //! Destructor + virtual ~IIrrXMLReader() {} + + //! Reads forward to the next xml node. + /** \return Returns false, if there was no further node. */ + virtual bool read() = 0; + + //! Returns the type of the current XML node. + virtual EXML_NODE getNodeType() const = 0; + + //! Returns attribute count of the current XML node. + /** This is usually + non null if the current node is EXN_ELEMENT, and the element has attributes. + \return Returns amount of attributes of this xml node. */ + virtual unsigned int getAttributeCount() const = 0; + + //! Returns name of an attribute. + /** \param idx: Zero based index, should be something between 0 and getAttributeCount()-1. + \return Name of the attribute, 0 if an attribute with this index does not exist. */ + virtual const char_type* getAttributeName(int idx) const = 0; + + //! Returns the value of an attribute. + /** \param idx: Zero based index, should be something between 0 and getAttributeCount()-1. + \return Value of the attribute, 0 if an attribute with this index does not exist. */ + virtual const char_type* getAttributeValue(int idx) const = 0; + + //! Returns the value of an attribute. + /** \param name: Name of the attribute. + \return Value of the attribute, 0 if an attribute with this name does not exist. */ + virtual const char_type* getAttributeValue(const char_type* name) const = 0; + + //! Returns the value of an attribute in a safe way. + /** Like getAttributeValue(), but does not + return 0 if the attribute does not exist. An empty string ("") is returned then. + \param name: Name of the attribute. + \return Value of the attribute, and "" if an attribute with this name does not exist */ + virtual const char_type* getAttributeValueSafe(const char_type* name) const = 0; + + //! Returns the value of an attribute as integer. + /** \param name Name of the attribute. + \param defaultNotFound Value returned when name does not exist + \return Value of the attribute as integer or value of defaultNotFound + when name was not found or 0 when value could not be interpreted as integer */ + virtual int getAttributeValueAsInt(const char_type* name, int defaultNotFound=0) const = 0; + + //! Returns the value of an attribute as integer. + /** \param idx: Zero based index, should be something between 0 and getAttributeCount()-1. + \param defaultNotFound Value returned when index does not exist. + \return Value of the attribute as integer or value of defaultNotFound parameter for invalid index + or 0 when value could not be interpreted as integer */ + virtual int getAttributeValueAsInt(int idx, int defaultNotFound=0) const = 0; + + //! Returns the value of an attribute as float. + /** \param name: Name of the attribute. + \param defaultNotFound Value returned when name does not exist. + \return Value of the attribute as float or value of defaultNotFound parameter on failure + or 0 when value could not be interpreted as float. */ + virtual float getAttributeValueAsFloat(const char_type* name, float defaultNotFound=0.f) const = 0; + + //! Returns the value of an attribute as float. + /** \param idx: Zero based index, should be something between 0 and getAttributeCount()-1. + \param defaultNotFound Value returned when index does not exist. + \return Value of the attribute as float or value of defaultNotFound parameter on failure + or 0 when value could not be interpreted as float. */ + virtual float getAttributeValueAsFloat(int idx, float defaultNotFound=0.f) const = 0; + + //! Returns the name of the current node. + /** Only valid, if the node type is EXN_ELEMENT. + \return Name of the current node or 0 if the node has no name. */ + virtual const char_type* getNodeName() const = 0; + + //! Returns data of the current node. + /** Only valid if the node has some + data and it is of type EXN_TEXT, EXN_COMMENT, EXN_CDATA or EXN_UNKNOWN. */ + virtual const char_type* getNodeData() const = 0; + + //! Returns if an element is an empty element, like <foo /> + virtual bool isEmptyElement() const = 0; + + //! Returns format of the source xml file. + /** It is not necessary to use + this method because the parser will convert the input file format + to the format wanted by the user when creating the parser. This + method is useful to get/display additional information. */ + virtual ETEXT_FORMAT getSourceFormat() const = 0; + + //! Returns format of the strings returned by the parser. + /** This will be UTF8 for example when you created a parser with + IrrXMLReaderUTF8() and UTF32 when it has been created using + IrrXMLReaderUTF32. It should not be necessary to call this + method and only exists for informational purposes. */ + virtual ETEXT_FORMAT getParserFormat() const = 0; + }; + + //! Interface providing methods for making it easier to write XML files. + template + class IIrrXMLWriter : public super_class + { + public: + + //! Destructor + virtual ~IIrrXMLWriter() {} + + //! Writes an xml 1.0 header. + /** Looks like <?xml version="1.0"?>. This should always + be called before writing anything other, because also the text + file header for Unicode texts is written out with this method. */ + virtual void writeXMLHeader() = 0; + + //! Writes an xml element with maximal 5 attributes like "" or + //! <foo optAttr="value" />. + /** The element can be empty or not. + \param name: Name of the element + \param empty: Specifies if the element should be empty. Like + "". If You set this to false, something like this is + written instead: "". + \param attr1Name: 1st attributes name + \param attr1Value: 1st attributes value + \param attr2Name: 2nd attributes name + \param attr2Value: 2nd attributes value + \param attr3Name: 3rd attributes name + \param attr3Value: 3rd attributes value + \param attr4Name: 4th attributes name + \param attr4Value: 4th attributes value + \param attr5Name: 5th attributes name + \param attr5Value: 5th attributes value */ + virtual void writeElement(const char_type* name, bool empty=false, + const char_type* attr1Name = 0, const char_type* attr1Value = 0, + const char_type* attr2Name = 0, const char_type* attr2Value = 0, + const char_type* attr3Name = 0, const char_type* attr3Value = 0, + const char_type* attr4Name = 0, const char_type* attr4Value = 0, + const char_type* attr5Name = 0, const char_type* attr5Value = 0) = 0; + + //! Writes an xml element with any number of attributes + virtual void writeElement(const char_type* name, bool empty, + core::array > &names, core::array > &values) = 0; + + //! Writes a comment into the xml file + virtual void writeComment(const char_type* comment) = 0; + + //! Writes the closing tag for an element. Like "" + virtual void writeClosingTag(const char_type* name) = 0; + + //! Writes a text into the file. + /** All occurrences of special characters such as + & (&), < (<), > (>), and " (") are automatically + replaced. */ + virtual void writeText(const char_type* text) = 0; + + //! Writes a line break + virtual void writeLineBreak() = 0; + }; + + + template + struct xmlChar + { + T c; + xmlChar() {} + xmlChar(char in) : c(static_cast(in)) {} + xmlChar(wchar_t in) : c(static_cast(in)) {} +#if defined(__BORLANDC__) + // Note - removing explicit for Borland was to get it to even compile. + // There haven't been any kind of tests for that besides that. + xmlChar(unsigned char in) : c(static_cast(in)) {} + xmlChar(unsigned short in) : c(static_cast(in)) {} + xmlChar(unsigned int in) : c(static_cast(in)) {} + xmlChar(unsigned long in) : c(static_cast(in)) {} +#else + explicit xmlChar(unsigned char in) : c(static_cast(in)) {} + +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) // VS compiling without native wchar_t can't have it + explicit xmlChar(unsigned short in) : c(static_cast(in)) {} +#endif + explicit xmlChar(unsigned int in) : c(static_cast(in)) {} + explicit xmlChar(unsigned long in) : c(static_cast(in)) {} +#endif + operator T() const { return c; } + void operator=(int t) { c=static_cast(t); } + }; + + //! defines the utf-16 type. + /** Not using wchar_t for this because + wchar_t has 16 bit on windows and 32 bit on other operating systems. */ + typedef xmlChar char16; + + //! defines the utf-32 type. + /** Not using wchar_t for this because + wchar_t has 16 bit on windows and 32 bit on other operating systems. */ + typedef xmlChar char32; + + //! A UTF-8 or ASCII character xml parser. + /** This means that all character data will be returned in 8 bit ASCII or UTF-8 by this parser. + The file to read can be in any format, it will be converted to UTF-8 if it is not + in this format. + Create an instance of this with createIrrXMLReader(); + See IIrrXMLReader for description on how to use it. */ + typedef IIrrXMLReader IrrXMLReader; + + //! A UTF-16 xml parser. + /** This means that all character data will be returned in UTF-16 by this parser. + The file to read can be in any format, it will be converted to UTF-16 if it is not + in this format. + Create an instance of this with createIrrXMLReaderUTF16(); + See IIrrXMLReader for description on how to use it. */ + typedef IIrrXMLReader IrrXMLReaderUTF16; + + //! A UTF-32 xml parser. + /** This means that all character data will be returned in UTF-32 by this parser. + The file to read can be in any format, it will be converted to UTF-32 if it is not + in this format. + Create an instance of this with createIrrXMLReaderUTF32(); + See IIrrXMLReader for description on how to use it. */ + typedef IIrrXMLReader IrrXMLReaderUTF32; + +#ifdef _IRR_COMPILE_WITH_XML_ + + //! Creates an instance of an UFT-8 or ASCII character xml parser. + /** This means that all character data will be returned in 8 bit ASCII or UTF-8. + The file to read can be in any format, it will be converted to UTF-8 if it is not in this format. + If you are using the Irrlicht Engine, it is better not to use this function but + IFileSystem::createXMLReaderUTF8() instead. + \param filename: Name of file to be opened. + \return Returns a pointer to the created xml parser. This pointer should be + deleted using 'delete' after no longer needed. Returns 0 if an error occurred + and the file could not be opened. */ + IRRLICHT_API IrrXMLReader* IRRCALLCONV createIrrXMLReader(const char* filename); + + //! Creates an instance of an UFT-8 or ASCII character xml parser. + /** This means that all character data will be returned in 8 bit ASCII or UTF-8. The file to read can + be in any format, it will be converted to UTF-8 if it is not in this format. + If you are using the Irrlicht Engine, it is better not to use this function but + IFileSystem::createXMLReaderUTF8() instead. + \param file: Pointer to opened file, must have been opened in binary mode, e.g. + using fopen("foo.bar", "wb"); The file will not be closed after it has been read. + \return Returns a pointer to the created xml parser. This pointer should be + deleted using 'delete' after no longer needed. Returns 0 if an error occurred + and the file could not be opened. */ + IRRLICHT_API IrrXMLReader* IRRCALLCONV createIrrXMLReader(FILE* file); + + //! Creates an instance of an UFT-8 or ASCII character xml parser. + /** This means that all character data will be returned in 8 bit ASCII or UTF-8. The file to read can + be in any format, it will be converted to UTF-8 if it is not in this format. + If you are using the Irrlicht Engine, it is better not to use this function but + IFileSystem::createXMLReaderUTF8() instead. + \param callback: Callback for file read abstraction. Implement your own + callback to make the xml parser read in other things than just files. See + IFileReadCallBack for more information about this. + \param deleteCallback: if true, the callback will be deleted after the file + has been read. Otherwise the caller is responsible for cleaning it up. + \return Returns a pointer to the created xml parser. This pointer should be + deleted using 'delete' after no longer needed. Returns 0 if an error occurred + and the file could not be opened. */ + IRRLICHT_API IrrXMLReader* IRRCALLCONV createIrrXMLReader(IFileReadCallBack* callback, + bool deleteCallback = false); + + //! Creates an instance of an UFT-16 xml parser. + /** This means that + all character data will be returned in UTF-16. The file to read can + be in any format, it will be converted to UTF-16 if it is not in this format. + If you are using the Irrlicht Engine, it is better not to use this function but + IFileSystem::createXMLReader() instead. + \param filename: Name of file to be opened. + \return Returns a pointer to the created xml parser. This pointer should be + deleted using 'delete' after no longer needed. Returns 0 if an error occurred + and the file could not be opened. */ + IRRLICHT_API IrrXMLReaderUTF16* IRRCALLCONV createIrrXMLReaderUTF16(const char* filename); + + //! Creates an instance of an UFT-16 xml parser. + /** This means that all character data will be returned in UTF-16. The file to read can + be in any format, it will be converted to UTF-16 if it is not in this format. + If you are using the Irrlicht Engine, it is better not to use this function but + IFileSystem::createXMLReader() instead. + \param file: Pointer to opened file, must have been opened in binary mode, e.g. + using fopen("foo.bar", "wb"); The file will not be closed after it has been read. + \return Returns a pointer to the created xml parser. This pointer should be + deleted using 'delete' after no longer needed. Returns 0 if an error occurred + and the file could not be opened. */ + IRRLICHT_API IrrXMLReaderUTF16* IRRCALLCONV createIrrXMLReaderUTF16(FILE* file); + + //! Creates an instance of an UFT-16 xml parser. + /** This means that all character data will be returned in UTF-16. The file to read can + be in any format, it will be converted to UTF-16 if it is not in this format. + If you are using the Irrlicht Engine, it is better not to use this function but + IFileSystem::createXMLReader() instead. + \param callback: Callback for file read abstraction. Implement your own + callback to make the xml parser read in other things than just files. See + IFileReadCallBack for more information about this. + \param deleteCallback: if true, the callback will be deleted after the file + has been read. Otherwise the caller is responsible for cleaning it up. + \return Returns a pointer to the created xml parser. This pointer should be + deleted using 'delete' after no longer needed. Returns 0 if an error occurred + and the file could not be opened. */ + IRRLICHT_API IrrXMLReaderUTF16* IRRCALLCONV createIrrXMLReaderUTF16(IFileReadCallBack* callback, + bool deleteCallback = false); + + + //! Creates an instance of an UFT-32 xml parser. + /** This means that all character data will be returned in UTF-32. The file to read can + be in any format, it will be converted to UTF-32 if it is not in this format. + If you are using the Irrlicht Engine, it is better not to use this function but + IFileSystem::createXMLReader() instead. + \param filename: Name of file to be opened. + \return Returns a pointer to the created xml parser. This pointer should be + deleted using 'delete' after no longer needed. Returns 0 if an error occurred + and the file could not be opened. */ + IRRLICHT_API IrrXMLReaderUTF32* IRRCALLCONV createIrrXMLReaderUTF32(const char* filename); + + //! Creates an instance of an UFT-32 xml parser. + /** This means that all character data will be returned in UTF-32. The file to read can + be in any format, it will be converted to UTF-32 if it is not in this format. + if you are using the Irrlicht Engine, it is better not to use this function but + IFileSystem::createXMLReader() instead. + \param file: Pointer to opened file, must have been opened in binary mode, e.g. + using fopen("foo.bar", "wb"); The file will not be closed after it has been read. + \return Returns a pointer to the created xml parser. This pointer should be + deleted using 'delete' after no longer needed. Returns 0 if an error occurred + and the file could not be opened. */ + IRRLICHT_API IrrXMLReaderUTF32* IRRCALLCONV createIrrXMLReaderUTF32(FILE* file); + + //! Creates an instance of an UFT-32 xml parser. + /** This means that + all character data will be returned in UTF-32. The file to read can + be in any format, it will be converted to UTF-32 if it is not in this format. + If you are using the Irrlicht Engine, it is better not to use this function but + IFileSystem::createXMLReader() instead. + \param callback: Callback for file read abstraction. Implement your own + callback to make the xml parser read in other things than just files. See + IFileReadCallBack for more information about this. + \param deleteCallback: if true, the callback will be deleted after the file + has been read. Otherwise the caller is responsible for cleaning it up. + \return Returns a pointer to the created xml parser. This pointer should be + deleted using 'delete' after no longer needed. Returns 0 if an error occurred + and the file could not be opened. */ + IRRLICHT_API IrrXMLReaderUTF32* IRRCALLCONV createIrrXMLReaderUTF32(IFileReadCallBack* callback, + bool deleteCallback = false); + +#endif // _IRR_COMPILE_WITH_XML_ + + /*! \file irrXML.h + \brief Header file of the irrXML, the Irrlicht XML parser. + + This file includes everything needed for using irrXML, + the XML parser of the Irrlicht Engine. To use irrXML, + you only need to include this file in your project: + + \code + #include + \endcode + + It is also common to use the two namespaces in which irrXML is included, + directly after including irrXML.h: + + \code + #include + using namespace irr; + using namespace io; + \endcode + */ + +} // end namespace io +} // end namespace irr + +#endif // __IRR_XML_H_INCLUDED__ + diff --git a/include/irrlicht.h b/include/irrlicht.h new file mode 100644 index 00000000..ec623487 --- /dev/null +++ b/include/irrlicht.h @@ -0,0 +1,399 @@ +/* irrlicht.h -- interface of the 'Irrlicht Engine' + + Copyright (C) 2002-2012 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 + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Please note that the Irrlicht Engine is based in part on the work of the + Independent JPEG Group, the zlib and the libPng. This means that if you use + the Irrlicht Engine in your product, you must acknowledge somewhere in your + documentation that you've used the IJG code. It would also be nice to mention + that you use the Irrlicht Engine, the zlib and libPng. See the README files + in the jpeglib, the zlib and libPng for further information. +*/ + +#ifndef __IRRLICHT_H_INCLUDED__ +#define __IRRLICHT_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#include "aabbox3d.h" +#include "CDynamicMeshBuffer.h" +#include "CIndexBuffer.h" +#include "CMeshBuffer.h" +#include "coreutil.h" +#include "CVertexBuffer.h" +#include "IProfiler.h" +#include "dimension2d.h" +#include "ECullingTypes.h" +#include "EDebugSceneTypes.h" +#include "EDriverFeatures.h" +#include "EDriverTypes.h" +#include "EGUIAlignment.h" +#include "EGUIElementTypes.h" +#include "EHardwareBufferFlags.h" +#include "EMaterialFlags.h" +#include "EMaterialTypes.h" +#include "EMeshWriterEnums.h" +#include "EMessageBoxFlags.h" +#include "ESceneNodeAnimatorTypes.h" +#include "ESceneNodeTypes.h" +#include "ETerrainElements.h" +#include "fast_atof.h" +#include "heapsort.h" +#include "IAnimatedMesh.h" +#include "IAnimatedMeshMD2.h" +#include "IAnimatedMeshMD3.h" +#include "IAnimatedMeshSceneNode.h" +#include "IAttributeExchangingObject.h" +#include "IAttributes.h" +#include "IBillboardSceneNode.h" +#include "IBillboardTextSceneNode.h" +#include "IBoneSceneNode.h" +#include "ICameraSceneNode.h" +#include "IContextManager.h" +#include "ICursorControl.h" +#include "IDummyTransformationSceneNode.h" +#include "IDynamicMeshBuffer.h" +#include "IEventReceiver.h" +#include "IFileList.h" +#include "IFileSystem.h" +#include "IGeometryCreator.h" +#include "IGPUProgrammingServices.h" +#include "IGUIButton.h" +#include "IGUICheckBox.h" +#include "IGUIColorSelectDialog.h" +#include "IGUIComboBox.h" +#include "IGUIContextMenu.h" +#include "IGUIEditBox.h" +#include "IGUIElement.h" +#include "IGUIElementFactory.h" +#include "IGUIEnvironment.h" +#include "IGUIFileOpenDialog.h" +#include "IGUIFont.h" +#include "IGUIFontBitmap.h" +#include "IGUIImage.h" +#include "IGUIInOutFader.h" +#include "IGUIListBox.h" +#include "IGUIMeshViewer.h" +#include "IGUIScrollBar.h" +#include "IGUISkin.h" +#include "IGUISpinBox.h" +#include "IGUISpriteBank.h" +#include "IGUIStaticText.h" +#include "IGUITabControl.h" +#include "IGUITable.h" +#include "IGUIToolbar.h" +#include "IGUIWindow.h" +#include "IGUITreeView.h" +#include "IGUIProfiler.h" +#include "IImage.h" +#include "IImageLoader.h" +#include "IImageWriter.h" +#include "IIndexBuffer.h" +#include "ILightSceneNode.h" +#include "ILogger.h" +#include "IMaterialRenderer.h" +#include "IMaterialRendererServices.h" +#include "IMesh.h" +#include "IMeshBuffer.h" +#include "IMeshCache.h" +#include "IMeshLoader.h" +#include "IMeshManipulator.h" +#include "IMeshSceneNode.h" +#include "IMeshWriter.h" +#include "IOctreeSceneNode.h" +#include "IColladaMeshWriter.h" +#include "IMetaTriangleSelector.h" +#include "IOSOperator.h" +#include "IParticleSystemSceneNode.h" // also includes all emitters and attractors +#include "IQ3LevelMesh.h" +#include "IQ3Shader.h" +#include "IReadFile.h" +#include "IReferenceCounted.h" +#include "irrArray.h" +#include "IRandomizer.h" +#include "IRenderTarget.h" +#include "IrrlichtDevice.h" +#include "irrList.h" +#include "irrMap.h" +#include "irrMath.h" +#include "irrString.h" +#include "irrTypes.h" +#include "path.h" +#include "irrXML.h" +#include "ISceneCollisionManager.h" +#include "ISceneLoader.h" +#include "ISceneManager.h" +#include "ISceneNode.h" +#include "ISceneNodeAnimator.h" +#include "ISceneNodeAnimatorCameraFPS.h" +#include "ISceneNodeAnimatorCameraMaya.h" +#include "ISceneNodeAnimatorCollisionResponse.h" +#include "ISceneNodeAnimatorFactory.h" +#include "ISceneNodeFactory.h" +#include "ISceneUserDataSerializer.h" +#include "IShaderConstantSetCallBack.h" +#include "IShadowVolumeSceneNode.h" +#include "ISkinnedMesh.h" +#include "ITerrainSceneNode.h" +#include "ITextSceneNode.h" +#include "ITexture.h" +#include "ITimer.h" +#include "ITriangleSelector.h" +#include "IVertexBuffer.h" +#include "IVideoDriver.h" +#include "IVideoModeList.h" +#include "IVolumeLightSceneNode.h" +#include "IWriteFile.h" +#include "IXMLReader.h" +#include "IXMLWriter.h" +#include "ILightManager.h" +#include "Keycodes.h" +#include "line2d.h" +#include "line3d.h" +#include "matrix4.h" +#include "plane3d.h" +#include "position2d.h" +#include "quaternion.h" +#include "rect.h" +#include "S3DVertex.h" +#include "SAnimatedMesh.h" +#include "SceneParameters.h" +#include "SColor.h" +#include "SExposedVideoData.h" +#include "SIrrCreationParameters.h" +#include "SKeyMap.h" +#include "SLight.h" +#include "SMaterial.h" +#include "SMesh.h" +#include "SMeshBuffer.h" +#include "SMeshBufferLightMap.h" +#include "SMeshBufferTangents.h" +#include "SParticle.h" +#include "SSharedMeshBuffer.h" +#include "SSkinMeshBuffer.h" +#include "SVertexIndex.h" +#include "SViewFrustum.h" +#include "triangle3d.h" +#include "vector2d.h" +#include "vector3d.h" + +/*! \mainpage Irrlicht Engine 1.9 API documentation + * + *
+ * + * \section intro Introduction + * + * Welcome to the Irrlicht Engine API documentation. + * Here you'll find any information you'll need to develop applications with + * the Irrlicht Engine. If you are looking for a tutorial on how to start, you'll + * find some on the homepage of the Irrlicht Engine at + * irrlicht.sourceforge.net + * or inside the SDK in the examples directory. + * + * The Irrlicht Engine is intended to be an easy-to-use 3d engine, so + * this documentation is an important part of it. If you have any questions or + * suggestions, just send a email to the author of the engine, Nikolaus Gebhardt + * (niko (at) irrlicht3d.org). + * + * + * \section links Links + * + * Namespaces: A very good place to start reading + * the documentation.
+ * Class list: List of all classes with descriptions.
+ * Class members: Good place to find forgotten features.
+ * + * \section irrexample Short example + * + * A simple application, starting up the engine, loading a Quake 2 animated + * model file and the corresponding texture, animating and displaying it + * in front of a blue background and placing a user controlable 3d camera + * would look like the following code. I think this example shows the usage + * of the engine quite well: + * + * \code + * #include + * using namespace irr; + * + * int main() + * { + * // start up the engine + * IrrlichtDevice *device = createDevice(video::EDT_OPENGL, + * core::dimension2d(640,480)); + * + * video::IVideoDriver* driver = device->getVideoDriver(); + * scene::ISceneManager* scenemgr = device->getSceneManager(); + * + * device->setWindowCaption(L"Hello World!"); + * + * // load and show quake2 .md2 model + * scene::ISceneNode* node = scenemgr->addAnimatedMeshSceneNode( + * scenemgr->getMesh("quake2model.md2")); + * + * // if everything worked, add a texture and disable lighting + * if (node) + * { + * node->setMaterialTexture(0, driver->getTexture("texture.bmp")); + * node->setMaterialFlag(video::EMF_LIGHTING, false); + * } + * + * // add a first person shooter style user controlled camera + * scenemgr->addCameraSceneNodeFPS(); + * + * // draw everything + * while(device->run() && driver) + * { + * driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,0,0,255)); + * scenemgr->drawAll(); + * driver->endScene(); + * } + * + * // delete device + * device->drop(); + * return 0; + * } + * \endcode + * + * Irrlicht can load a lot of file formats automatically, see irr::scene::ISceneManager::getMesh() + * for a detailed list. So if you would like to replace the simple blue screen background by + * a cool Quake 3 Map, optimized by an octree, just insert this code + * somewhere before the while loop: + * + * \code + * // add .pk3 archive to the file system + * device->getFileSystem()->addZipFileArchive("quake3map.pk3"); + * + * // load .bsp file and show it using an octree + * scenemgr->addOctreeSceneNode( + * scenemgr->getMesh("quake3map.bsp")); + * \endcode + * + * As you can see, the engine uses namespaces. Everything in the engine is + * placed into the namespace 'irr', but there are also 5 sub namespaces. + * You can find a list of all namespaces with descriptions at the + * namespaces page. + * This is also a good place to start reading the documentation. If you + * don't want to write the namespace names all the time, just use all namespaces like + * this: + * \code + * using namespace core; + * using namespace scene; + * using namespace video; + * using namespace io; + * using namespace gui; + * \endcode + * + * There is a lot more the engine can do, but I hope this gave a short + * overview over the basic features of the engine. For more examples, please take + * a look into the examples directory of the SDK. + */ + +#include "SIrrCreationParameters.h" + +//! Everything in the Irrlicht Engine can be found in this namespace. +namespace irr +{ + //! Creates an Irrlicht device. The Irrlicht device is the root object for using the engine. + /** If you need more parameters to be passed to the creation of the Irrlicht Engine device, + use the createDeviceEx() function. + \param driverType: Type of the video driver to use. This can currently be video::EDT_NULL, + video::EDT_SOFTWARE, video::EDT_BURNINGSVIDEO, video::EDT_DIRECT3D9 and video::EDT_OPENGL. + \param windowSize: Size of the window or the video mode in fullscreen mode. + \param bits: Bits per pixel in fullscreen mode. Ignored if windowed mode. + \param fullscreen: Should be set to true if the device should run in fullscreen. Otherwise + the device runs in windowed mode. + \param stencilbuffer: 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. + \param vsync: Specifies vertical synchronization: If set to true, the driver will wait + for the vertical retrace period, otherwise not. + \param receiver: A user created event receiver. + \return Returns pointer to the created IrrlichtDevice or null if the + device could not be created. + */ + extern "C" IRRLICHT_API IrrlichtDevice* IRRCALLCONV createDevice( + video::E_DRIVER_TYPE driverType = video::EDT_SOFTWARE, + // parentheses are necessary for some compilers + const core::dimension2d& windowSize = (core::dimension2d(640,480)), + u32 bits = 32, + bool fullscreen = false, + bool stencilbuffer = true, + bool vsync = false, + IEventReceiver* receiver = 0); + + //! typedef for Function Pointer + typedef IrrlichtDevice* (IRRCALLCONV *funcptr_createDevice )( + video::E_DRIVER_TYPE driverType, + const core::dimension2d& windowSize, + u32 bits, + bool fullscreen, + bool stencilbuffer, + bool vsync, + IEventReceiver* receiver); + + + //! Creates an Irrlicht device with the option to specify advanced parameters. + /** Usually you should used createDevice() for creating an Irrlicht Engine device. + Use this function only if you wish to specify advanced parameters like a window + handle in which the device should be created. + \param parameters: Structure containing advanced parameters for the creation of the device. + See irr::SIrrlichtCreationParameters for details. + \return Returns pointer to the created IrrlichtDevice or null if the + device could not be created. */ + extern "C" IRRLICHT_API IrrlichtDevice* IRRCALLCONV createDeviceEx( + const SIrrlichtCreationParameters& parameters); + + //! typedef for Function Pointer + typedef IrrlichtDevice* (IRRCALLCONV *funcptr_createDeviceEx )( const SIrrlichtCreationParameters& parameters ); + + + // THE FOLLOWING IS AN EMPTY LIST OF ALL SUB NAMESPACES + // EXISTING ONLY FOR THE DOCUMENTATION SOFTWARE DOXYGEN. + + //! Basic classes such as vectors, planes, arrays, lists, and so on can be found in this namespace. + namespace core + { + } + + //! The gui namespace contains useful classes for easy creation of a graphical user interface. + namespace gui + { + } + + //! This namespace provides interfaces for input/output: Reading and writing files, accessing zip archives, xml files, ... + namespace io + { + } + + //! All scene management can be found in this namespace: Mesh loading, special scene nodes like octrees and billboards, ... + namespace scene + { + } + + //! The video namespace contains classes for accessing the video driver. All 2d and 3d rendering is done here. + namespace video + { + } +} + +/*! \file irrlicht.h + \brief Main header file of the irrlicht, the only file needed to include. +*/ + +#endif + diff --git a/include/irrpack.h b/include/irrpack.h new file mode 100644 index 00000000..ff922d06 --- /dev/null +++ b/include/irrpack.h @@ -0,0 +1,39 @@ +// Copyright (C) 2007-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +// include this file right before the data structures to be 1-aligned +// and add to each structure the PACK_STRUCT define just like this: +// struct mystruct +// { +// ... +// } PACK_STRUCT; +// Always include the irrunpack.h file right after the last type declared +// like this, and do not put any other types with different alignment +// in between! + +// byte-align structures +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) +# pragma warning(disable: 4103) +# pragma pack( push, packing ) +# pragma pack( 1 ) +# define PACK_STRUCT +#elif defined( __DMC__ ) +# pragma pack( push, 1 ) +# define PACK_STRUCT +#elif defined( __GNUC__ ) + // Using pragma pack might work with earlier gcc versions already, but + // it started to be necessary with gcc 4.7 on mingw unless compiled with -mno-ms-bitfields. + // And I found some hints on the web that older gcc versions on the other hand had sometimes + // trouble with pragma pack while they worked with __attribute__((packed)). +# if (__GNUC__ > 4 ) || ((__GNUC__ == 4 ) && (__GNUC_MINOR__ >= 7)) +# pragma pack( push, packing ) +# pragma pack( 1 ) +# define PACK_STRUCT +# else +# define PACK_STRUCT __attribute__((packed)) + #endif +#else +# error compiler not supported +#endif + diff --git a/include/irrunpack.h b/include/irrunpack.h new file mode 100644 index 00000000..ba478278 --- /dev/null +++ b/include/irrunpack.h @@ -0,0 +1,20 @@ +// Copyright (C) 2007-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +// include this file to switch back to default alignment +// file belongs to irrpack.h, see there for more info + +// Default alignment +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) +# pragma pack( pop, packing ) +#elif defined (__DMC__) +# pragma pack( pop ) +#elif defined( __GNUC__ ) +# if (__GNUC__ > 4 ) || ((__GNUC__ == 4 ) && (__GNUC_MINOR__ >= 7)) +# pragma pack( pop, packing ) +# endif +#endif + +#undef PACK_STRUCT + diff --git a/include/leakHunter.h b/include/leakHunter.h new file mode 100644 index 00000000..243f09ef --- /dev/null +++ b/include/leakHunter.h @@ -0,0 +1,69 @@ +// Copyright (C) 2013 Michael Zeilfelder +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __LEAK_HUNTER_INCLUDEED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_LEAK_HUNTER_ + +#include "irrArray.h" + +namespace irr +{ + class IReferenceCounted; + + //! A class helping to find unreleased objects of type IReferenceCounted. + /** To use this you have recompile Irrlicht with _IRR_COMPILE_WITH_LEAK_HUNTER_. + Note that this will slow down your application and should only be used for debugging. + The way to use is that you can check after you closed and dropped your last Irrlicht device + if there are still any IReferenceCounted left over which have not been deleted. + */ + class LeakHunter + { + public: + friend class IReferenceCounted; + + //! Clear all IReferenceCounted objects inside LeakHunter + /** This does not affect the IReferenceCounted themselves only the + counting of them. Usually you don't ever need to clear, but + sometimes it helps when for example you want to ignore + certain leaks. + */ + static void clearReferenceCountedObjects() + { + ReferenceCountedObjects.clear(); + } + + //! Access all objects which are currently reference counted. + static inline irr::core::array getReferenceCountedObjects() + { + return ReferenceCountedObjects; + } + + protected: + static inline void addObject(const IReferenceCounted* object) + { + ReferenceCountedObjects.push_back(object); + } + + static inline void removeObject(const IReferenceCounted* object) + { + irr::s32 idx = ReferenceCountedObjects.linear_search(object ); + if ( idx >= 0 ) + { + irr::core::swap( ReferenceCountedObjects[idx], ReferenceCountedObjects.getLast() ); + ReferenceCountedObjects.erase( ReferenceCountedObjects.size()-1 ); + } + } + + private: + // NOTE: We don't do additional grab()/drop()'s here as we want to supervise reference counted objects and not affect them otherwise. + IRRLICHT_API static irr::core::array ReferenceCountedObjects; + }; +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_LEAK_HUNTER_ + +#endif diff --git a/include/line2d.h b/include/line2d.h new file mode 100644 index 00000000..ce34c419 --- /dev/null +++ b/include/line2d.h @@ -0,0 +1,360 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_LINE_2D_H_INCLUDED__ +#define __IRR_LINE_2D_H_INCLUDED__ + +#include "irrTypes.h" +#include "vector2d.h" + +namespace irr +{ +namespace core +{ + +//! 2D line between two points with intersection methods. +template +class line2d +{ + public: + //! Default constructor for line going from (0,0) to (1,1). + line2d() : start(0,0), end(1,1) {} + //! Constructor for line between the two points. + line2d(T xa, T ya, T xb, T yb) : start(xa, ya), end(xb, yb) {} + //! Constructor for line between the two points given as vectors. + line2d(const vector2d& start, const vector2d& end) : start(start), end(end) {} + //! Copy constructor. + line2d(const line2d& other) : start(other.start), end(other.end) {} + + // operators + + line2d operator+(const vector2d& point) const { return line2d(start + point, end + point); } + line2d& operator+=(const vector2d& point) { start += point; end += point; return *this; } + + line2d operator-(const vector2d& point) const { return line2d(start - point, end - point); } + line2d& operator-=(const vector2d& point) { start -= point; end -= point; return *this; } + + bool operator==(const line2d& other) const + { return (start==other.start && end==other.end) || (end==other.start && start==other.end);} + bool operator!=(const line2d& other) const + { return !(start==other.start && end==other.end) || (end==other.start && start==other.end);} + + // functions + //! Set this line to new line going through the two points. + void setLine(const T& xa, const T& ya, const T& xb, const T& yb){start.set(xa, ya); end.set(xb, yb);} + //! Set this line to new line going through the two points. + void setLine(const vector2d& nstart, const vector2d& nend){start.set(nstart); end.set(nend);} + //! Set this line to new line given as parameter. + void setLine(const line2d& line){start.set(line.start); end.set(line.end);} + + //! Get length of line + /** \return Length of the line. */ + T getLength() const { return start.getDistanceFrom(end); } + + //! Get squared length of the line + /** \return Squared length of line. */ + T getLengthSQ() const { return start.getDistanceFromSQ(end); } + + //! Get middle of the line + /** \return center of the line. */ + vector2d getMiddle() const + { + return (start + end)/(T)2; + } + + //! Get the vector of the line. + /** \return The vector of the line. */ + vector2d getVector() const { return vector2d( end.X - start.X, end.Y - start.Y); } + + /*! Check if this segment intersects another segment, + or if segments are coincindent (colinear). */ + bool intersectAsSegments( const line2d& other) const + { + // Taken from: + // http://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/ + + // Find the four orientations needed for general and + // special cases + s32 o1 = start.checkOrientation( end, other.start); + s32 o2 = start.checkOrientation( end, other.end); + s32 o3 = other.start.checkOrientation( other.end, start); + s32 o4 = other.start.checkOrientation( other.end, end); + + // General case + if (o1 != o2 && o3 != o4) + return true; + + // Special Cases to check if segments are coolinear + if (o1 == 0 && other.start.isBetweenPoints( start, end)) return true; + if (o2 == 0 && other.end.isBetweenPoints( start, end)) return true; + if (o3 == 0 && start.isBetweenPoints( other.start, other.end)) return true; + if (o4 == 0 && end.isBetweenPoints( other.start, other.end)) return true; + + return false; // Doesn't fall in any of the above cases + } + + /*! Check if 2 segments are incident (intersects in exactly 1 point).*/ + bool incidentSegments( const line2d& other) const + { + return + start.checkOrientation( end, other.start) != start.checkOrientation( end, other.end) + && other.start.checkOrientation( other.end, start) != other.start.checkOrientation( other.end, end); + } + + /*! Check if 2 lines/segments are parallel or nearly parallel.*/ + bool nearlyParallel( const line2d& line, const T factor = relativeErrorFactor()) const + { + const vector2d a = getVector(); + const vector2d b = line.getVector(); + + return a.nearlyParallel( b, factor); + } + + /*! returns a intersection point of 2 lines (if lines are not parallel). Behaviour + undefined if lines are parallel or coincident. + It's on optimized intersectWith with checkOnlySegments=false and ignoreCoincidentLines=true + */ + vector2d fastLinesIntersection( const line2d& l) const + { + const f32 commonDenominator = (f32)((l.end.Y - l.start.Y)*(end.X - start.X) - + (l.end.X - l.start.X)*(end.Y - start.Y)); + + if ( commonDenominator != 0.f ) + { + const f32 numeratorA = (f32)((l.end.X - l.start.X)*(start.Y - l.start.Y) - + (l.end.Y - l.start.Y)*(start.X - l.start.X)); + + const f32 uA = numeratorA / commonDenominator; + + // Calculate the intersection point. + return vector2d ( + (T)(start.X + uA * (end.X - start.X)), + (T)(start.Y + uA * (end.Y - start.Y)) + ); + } + else + return l.start; + } + + /*! Check if this line intersect a segment. The eventual intersection point is returned in "out".*/ + bool lineIntersectSegment( const line2d& segment, vector2d & out) const + { + if (nearlyParallel( segment)) + return false; + + out = fastLinesIntersection( segment); + + return out.isBetweenPoints( segment.start, segment.end); + } + + //! Tests if this line intersects with another line. + /** \param l: Other line to test intersection with. + \param checkOnlySegments: Default is to check intersection between the begin and endpoints. + When set to false the function will check for the first intersection point when extending the lines. + \param out: If there is an intersection, the location of the + intersection will be stored in this vector. + \param ignoreCoincidentLines: When true coincident lines (lines above each other) are never considered as intersecting. + When false the center of the overlapping part is returned. + \return True if there is an intersection, false if not. */ + bool intersectWith(const line2d& l, vector2d& out, bool checkOnlySegments=true, bool ignoreCoincidentLines=false) const + { + // Uses the method given at: + // http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/ + const f32 commonDenominator = (f32)((l.end.Y - l.start.Y)*(end.X - start.X) - + (l.end.X - l.start.X)*(end.Y - start.Y)); + + const f32 numeratorA = (f32)((l.end.X - l.start.X)*(start.Y - l.start.Y) - + (l.end.Y - l.start.Y)*(start.X -l.start.X)); + + const f32 numeratorB = (f32)((end.X - start.X)*(start.Y - l.start.Y) - + (end.Y - start.Y)*(start.X -l.start.X)); + + if(equals(commonDenominator, 0.f)) + { + // The lines are either coincident or parallel + // if both numerators are 0, the lines are coincident + if(!ignoreCoincidentLines && equals(numeratorA, 0.f) && equals(numeratorB, 0.f)) + { + // Try and find a common endpoint + if(l.start == start || l.end == start) + out = start; + else if(l.end == end || l.start == end) + out = end; + // now check if the two segments are disjunct + else if (l.start.X>start.X && l.end.X>start.X && l.start.X>end.X && l.end.X>end.X) + return false; + else if (l.start.Y>start.Y && l.end.Y>start.Y && l.start.Y>end.Y && l.end.Y>end.Y) + return false; + else if (l.start.X maxp; + vector2d minp; + if ((start.X>l.start.X && start.X>l.end.X && start.X>end.X) || (start.Y>l.start.Y && start.Y>l.end.Y && start.Y>end.Y)) + maxp=start; + else if ((end.X>l.start.X && end.X>l.end.X && end.X>start.X) || (end.Y>l.start.Y && end.Y>l.end.Y && end.Y>start.Y)) + maxp=end; + else if ((l.start.X>start.X && l.start.X>l.end.X && l.start.X>end.X) || (l.start.Y>start.Y && l.start.Y>l.end.Y && l.start.Y>end.Y)) + maxp=l.start; + else + maxp=l.end; + if (maxp != start && ((start.X(); + if (start != maxp && start != minp) + out += start; + if (end != maxp && end != minp) + out += end; + if (l.start != maxp && l.start != minp) + out += l.start; + if (l.end != maxp && l.end != minp) + out += l.end; + out.X = (T)(out.X/2); + out.Y = (T)(out.Y/2); + } + + return true; // coincident + } + + return false; // parallel + } + + // Get the point of intersection on this line, checking that + // it is within the line segment. + const f32 uA = numeratorA / commonDenominator; + if (checkOnlySegments) + { + if(uA < 0.f || uA > 1.f) + return false; // Outside the line segment + + const f32 uB = numeratorB / commonDenominator; + if(uB < 0.f || uB > 1.f) + return false; // Outside the line segment + } + + // Calculate the intersection point. + out.X = (T)(start.X + uA * (end.X - start.X)); + out.Y = (T)(start.Y + uA * (end.Y - start.Y)); + return true; + } + + //! Get unit vector of the line. + /** \return Unit vector of this line. */ + vector2d getUnitVector() const + { + T len = (T)(1.0 / getLength()); + return vector2d((end.X - start.X) * len, (end.Y - start.Y) * len); + } + + //! Get angle between this line and given line. + /** \param l Other line for test. + \return Angle in degrees. */ + f64 getAngleWith(const line2d& l) const + { + vector2d vect = getVector(); + vector2d vect2 = l.getVector(); + return vect.getAngleWith(vect2); + } + + //! Tells us if the given point lies to the left, right, or on the line. + /** \return 0 if the point is on the line + <0 if to the left, or >0 if to the right. */ + T getPointOrientation(const vector2d& point) const + { + return ( (end.X - start.X) * (point.Y - start.Y) - + (point.X - start.X) * (end.Y - start.Y) ); + } + + //! Check if the given point is a member of the line + /** \return True if point is between start and end, else false. */ + bool isPointOnLine(const vector2d& point) const + { + T d = getPointOrientation(point); + return (d == 0 && point.isBetweenPoints(start, end)); + } + + //! Check if the given point is between start and end of the line. + /** Assumes that the point is already somewhere on the line. */ + bool isPointBetweenStartAndEnd(const vector2d& point) const + { + return point.isBetweenPoints(start, end); + } + + //! Get the closest point on this line to a point + /** \param checkOnlySegments: Default (true) is to return a point on the line-segment (between begin and end) of the line. + When set to false the function will check for the first the closest point on the the line even when outside the segment. */ + vector2d getClosestPoint(const vector2d& point, bool checkOnlySegments=true) const + { + vector2d c((f64)(point.X-start.X), (f64)(point.Y- start.Y)); + vector2d v((f64)(end.X-start.X), (f64)(end.Y-start.Y)); + f64 d = v.getLength(); + if ( d == 0 ) // can't tell much when the line is just a single point + return start; + v /= d; + f64 t = v.dotProduct(c); + + if ( checkOnlySegments ) + { + if (t < 0) return vector2d((T)start.X, (T)start.Y); + if (t > d) return vector2d((T)end.X, (T)end.Y); + } + + v *= t; + return vector2d((T)(start.X + v.X), (T)(start.Y + v.Y)); + } + + //! Start point of the line. + vector2d start; + //! End point of the line. + vector2d end; +}; + + // partial specialization to optimize lines (avoiding casts) + template <> + inline vector2df line2d::getClosestPoint(const vector2df& point, bool checkOnlySegments) const + { + const vector2df c = point - start; + vector2df v = end - start; + const f32 d = (f32)v.getLength(); + if ( d == 0 ) // can't tell much when the line is just a single point + return start; + v /= d; + const f32 t = v.dotProduct(c); + + if ( checkOnlySegments ) + { + if (t < 0) return start; + if (t > d) return end; + } + + v *= t; + return start + v; + } + + + //! Typedef for an f32 line. + typedef line2d line2df; + //! Typedef for an integer line. + typedef line2d line2di; + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/include/line3d.h b/include/line3d.h new file mode 100644 index 00000000..355c52f5 --- /dev/null +++ b/include/line3d.h @@ -0,0 +1,144 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_LINE_3D_H_INCLUDED__ +#define __IRR_LINE_3D_H_INCLUDED__ + +#include "irrTypes.h" +#include "vector3d.h" + +namespace irr +{ +namespace core +{ + +//! 3D line between two points with intersection methods. +template +class line3d +{ + public: + + //! Default constructor + /** line from (0,0,0) to (1,1,1) */ + line3d() : start(0,0,0), end(1,1,1) {} + //! Constructor with two points + line3d(T xa, T ya, T za, T xb, T yb, T zb) : start(xa, ya, za), end(xb, yb, zb) {} + //! Constructor with two points as vectors + line3d(const vector3d& start, const vector3d& end) : start(start), end(end) {} + + // operators + + line3d operator+(const vector3d& point) const { return line3d(start + point, end + point); } + line3d& operator+=(const vector3d& point) { start += point; end += point; return *this; } + + line3d operator-(const vector3d& point) const { return line3d(start - point, end - point); } + line3d& operator-=(const vector3d& point) { start -= point; end -= point; return *this; } + + bool operator==(const line3d& other) const + { return (start==other.start && end==other.end) || (end==other.start && start==other.end);} + bool operator!=(const line3d& other) const + { return !(start==other.start && end==other.end) || (end==other.start && start==other.end);} + + // functions + //! Set this line to a new line going through the two points. + void setLine(const T& xa, const T& ya, const T& za, const T& xb, const T& yb, const T& zb) + {start.set(xa, ya, za); end.set(xb, yb, zb);} + //! Set this line to a new line going through the two points. + void setLine(const vector3d& nstart, const vector3d& nend) + {start.set(nstart); end.set(nend);} + //! Set this line to new line given as parameter. + void setLine(const line3d& line) + {start.set(line.start); end.set(line.end);} + + //! Get length of line + /** \return Length of line. */ + T getLength() const { return start.getDistanceFrom(end); } + + //! Get squared length of line + /** \return Squared length of line. */ + T getLengthSQ() const { return start.getDistanceFromSQ(end); } + + //! Get middle of line + /** \return Center of line. */ + vector3d getMiddle() const + { + return (start + end)/(T)2; + } + + //! Get vector of line + /** \return vector of line. */ + vector3d getVector() const + { + return end - start; + } + + //! Check if the given point is between start and end of the line. + /** Assumes that the point is already somewhere on the line. + \param point The point to test. + \return True if point is on the line between start and end, else false. + */ + bool isPointBetweenStartAndEnd(const vector3d& point) const + { + return point.isBetweenPoints(start, end); + } + + //! Get the closest point on this line to a point + /** \param point The point to compare to. + \return The nearest point which is part of the line. */ + vector3d getClosestPoint(const vector3d& point) const + { + vector3d c = point - start; + vector3d v = end - start; + T d = (T)v.getLength(); + v /= d; + T t = v.dotProduct(c); + + if (t < (T)0.0) + return start; + if (t > d) + return end; + + v *= t; + return start + v; + } + + //! Check if the line intersects with a sphere + /** \param sorigin: Origin of the sphere. + \param sradius: Radius of the sphere. + \param outdistance: The distance to the first intersection point. + \return True if there is an intersection. + If there is one, the distance to the first intersection point + is stored in outdistance. */ + bool getIntersectionWithSphere(const vector3d& sorigin, T sradius, f64& outdistance) const + { + const vector3d q = sorigin - start; + T c = q.getLength(); + T v = q.dotProduct(getVector().normalize()); + T d = sradius * sradius - (c*c - v*v); + + if (d < 0.0) + return false; + + outdistance = v - core::squareroot ( d ); + return true; + } + + // member variables + + //! Start point of line + vector3d start; + //! End point of line + vector3d end; +}; + + //! Typedef for an f32 line. + typedef line3d line3df; + //! Typedef for an integer line. + typedef line3d line3di; + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/include/matrix4.h b/include/matrix4.h new file mode 100644 index 00000000..01289011 --- /dev/null +++ b/include/matrix4.h @@ -0,0 +1,2386 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_MATRIX_H_INCLUDED__ +#define __IRR_MATRIX_H_INCLUDED__ + +#include "irrMath.h" +#include "vector3d.h" +#include "vector2d.h" +#include "plane3d.h" +#include "aabbox3d.h" +#include "rect.h" +#include "irrString.h" + +// enable this to keep track of changes to the matrix +// and make simpler identity check for seldom changing matrices +// otherwise identity check will always compare the elements +//#define USE_MATRIX_TEST + +// this is only for debugging purposes +//#define USE_MATRIX_TEST_DEBUG + +#if defined( USE_MATRIX_TEST_DEBUG ) + +struct MatrixTest +{ + MatrixTest () : ID(0), Calls(0) {} + char buf[256]; + int Calls; + int ID; +}; +static MatrixTest MTest; + +#endif + +namespace irr +{ +namespace core +{ + + //! 4x4 matrix. Mostly used as transformation matrix for 3d calculations. + /** The matrix is a D3D style matrix, row major with translations in the 4th row. */ + template + class CMatrix4 + { + public: + + //! Constructor Flags + enum eConstructor + { + EM4CONST_NOTHING = 0, + EM4CONST_COPY, + EM4CONST_IDENTITY, + EM4CONST_TRANSPOSED, + EM4CONST_INVERSE, + EM4CONST_INVERSE_TRANSPOSED + }; + + //! Default constructor + /** \param constructor Choose the initialization style */ + CMatrix4( eConstructor constructor = EM4CONST_IDENTITY ); + + //! Constructor with value initialization + CMatrix4(const T& r0c0, const T& r0c1, const T& r0c2, const T& r0c3, + const T& r1c0, const T& r1c1, const T& r1c2, const T& r1c3, + const T& r2c0, const T& r2c1, const T& r2c2, const T& r2c3, + const T& r3c0, const T& r3c1, const T& r3c2, const T& r3c3) + { + M[0] = r0c0; M[1] = r0c1; M[2] = r0c2; M[3] = r0c3; + M[4] = r1c0; M[5] = r1c1; M[6] = r1c2; M[7] = r1c3; + M[8] = r2c0; M[9] = r2c1; M[10] = r2c2; M[11] = r2c3; + M[12] = r3c0; M[13] = r3c1; M[14] = r3c2; M[15] = r3c3; + } + + //! Copy constructor + /** \param other Other matrix to copy from + \param constructor Choose the initialization style */ + CMatrix4(const CMatrix4& other, eConstructor constructor = EM4CONST_COPY); + + //! Simple operator for directly accessing every element of the matrix. + T& operator()(const s32 row, const s32 col) + { +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return M[ row * 4 + col ]; + } + + //! Simple operator for directly accessing every element of the matrix. + const T& operator()(const s32 row, const s32 col) const { return M[row * 4 + col]; } + + //! Simple operator for linearly accessing every element of the matrix. + T& operator[](u32 index) + { +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return M[index]; + } + + //! Simple operator for linearly accessing every element of the matrix. + const T& operator[](u32 index) const { return M[index]; } + + //! Sets this matrix equal to the other matrix. + inline CMatrix4& operator=(const CMatrix4 &other); + + //! Sets all elements of this matrix to the value. + inline CMatrix4& operator=(const T& scalar); + + //! Returns pointer to internal array + const T* pointer() const { return M; } + T* pointer() + { +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return M; + } + + //! Returns true if other matrix is equal to this matrix. + bool operator==(const CMatrix4 &other) const; + + //! Returns true if other matrix is not equal to this matrix. + bool operator!=(const CMatrix4 &other) const; + + //! Add another matrix. + CMatrix4 operator+(const CMatrix4& other) const; + + //! Add another matrix. + CMatrix4& operator+=(const CMatrix4& other); + + //! Subtract another matrix. + CMatrix4 operator-(const CMatrix4& other) const; + + //! Subtract another matrix. + CMatrix4& operator-=(const CMatrix4& other); + + //! set this matrix to the product of two matrices + /** Calculate b*a */ + inline CMatrix4& setbyproduct(const CMatrix4& other_a,const CMatrix4& other_b ); + + //! Set this matrix to the product of two matrices + /** Calculate b*a, no optimization used, + use it if you know you never have a identity matrix */ + CMatrix4& setbyproduct_nocheck(const CMatrix4& other_a,const CMatrix4& other_b ); + + //! Multiply by another matrix. + /** Calculate other*this */ + CMatrix4 operator*(const CMatrix4& other) const; + + //! Multiply by another matrix. + /** Calculate and return other*this */ + CMatrix4& operator*=(const CMatrix4& other); + + //! Multiply by scalar. + CMatrix4 operator*(const T& scalar) const; + + //! Multiply by scalar. + CMatrix4& operator*=(const T& scalar); + + //! Set matrix to identity. + inline CMatrix4& makeIdentity(); + + //! 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; + + //! Set the translation of the current matrix. Will erase any previous values. + CMatrix4& setTranslation( const vector3d& translation ); + + //! Gets the current translation + vector3d getTranslation() const; + + //! Set the inverse translation of the current matrix. Will erase any previous values. + CMatrix4& setInverseTranslation( const vector3d& translation ); + + //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified. + inline CMatrix4& setRotationRadians( const vector3d& rotation ); + + //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified. + CMatrix4& setRotationDegrees( const vector3d& rotation ); + + //! Get the rotation, as set by setRotation() when you already know the scale. + /** If you already know the scale then this function is faster than the other getRotationDegrees overload. + NOTE: You will have the same end-rotation as used in setRotation, but it might not use the same axis values. + */ + core::vector3d getRotationDegrees(const vector3d& scale) const; + + //! Returns the rotation, as set by setRotation(). + /** NOTE: You will have the same end-rotation as used in setRotation, but it might not use the same axis values. + */ + core::vector3d getRotationDegrees() const; + + //! Make an inverted rotation matrix from Euler angles. + /** The 4th row and column are unmodified. */ + inline CMatrix4& setInverseRotationRadians( const vector3d& rotation ); + + //! Make an inverted rotation matrix from Euler angles. + /** The 4th row and column are unmodified. */ + inline CMatrix4& setInverseRotationDegrees( const vector3d& rotation ); + + //! Make a rotation matrix from angle and axis, assuming left handed rotation. + /** The 4th row and column are unmodified. */ + inline CMatrix4& setRotationAxisRadians(const T& angle, const vector3d& axis); + + //! Set Scale + CMatrix4& setScale( const vector3d& scale ); + + //! Set Scale + CMatrix4& setScale( const T scale ) { return setScale(core::vector3d(scale,scale,scale)); } + + //! Get Scale + core::vector3d getScale() const; + + //! Translate a vector by the inverse of the translation part of this matrix. + void inverseTranslateVect( vector3df& vect ) const; + + //! Rotate a vector by the inverse of the rotation part of this matrix. + void inverseRotateVect( vector3df& vect ) const; + + //! Rotate a vector by the rotation part of this matrix. + void rotateVect( vector3df& vect ) const; + + //! An alternate transform vector method, writing into a second vector + void rotateVect(core::vector3df& out, const core::vector3df& in) const; + + //! An alternate transform vector method, writing into an array of 3 floats + void rotateVect(T *out,const core::vector3df &in) const; + + //! Transforms the vector by this matrix + /** This operation is performed as if the vector was 4d with the 4th component =1 */ + void transformVect( vector3df& vect) const; + + //! Transforms input vector by this matrix and stores result in output vector + /** This operation is performed as if the vector was 4d with the 4th component =1 */ + void transformVect( vector3df& out, const vector3df& in ) const; + + //! An alternate transform vector method, writing into an array of 4 floats + /** This operation is performed as if the vector was 4d with the 4th component =1. + NOTE: out[3] will be written to (4th vector component)*/ + void transformVect(T *out,const core::vector3df &in) const; + + //! An alternate transform vector method, reading from and writing to an array of 3 floats + /** This operation is performed as if the vector was 4d with the 4th component =1 + NOTE: out[3] will be written to (4th vector component)*/ + void transformVec3(T *out, const T * in) const; + + //! An alternate transform vector method, reading from and writing to an array of 4 floats + void transformVec4(T *out, const T * in) const; + + //! Translate a vector by the translation part of this matrix. + /** This operation is performed as if the vector was 4d with the 4th component =1 */ + void translateVect( vector3df& vect ) const; + + //! Transforms a plane by this matrix + void transformPlane( core::plane3d &plane) const; + + //! Transforms a plane by this matrix + void transformPlane( const core::plane3d &in, core::plane3d &out) const; + + //! Transforms a axis aligned bounding box + /** The result box of this operation may not be accurate at all. For + correct results, use transformBoxEx() */ + void transformBox(core::aabbox3d& box) const; + + //! Transforms a axis aligned bounding box + /** The result box of this operation should be accurate, but this operation + is slower than transformBox(). */ + void transformBoxEx(core::aabbox3d& box) const; + + //! Multiplies this matrix by a 1x4 matrix + void multiplyWith1x4Matrix(T* matrix) const; + + //! Calculates inverse of matrix. Slow. + /** \return Returns false if there is no inverse matrix.*/ + bool makeInverse(); + + + //! Inverts a primitive matrix which only contains a translation and a rotation + /** \param out: where result matrix is written to. */ + bool getInversePrimitive ( CMatrix4& out ) const; + + //! Gets the inverse matrix of this one + /** \param out: where result matrix is written to. + \return Returns false if there is no inverse matrix. */ + bool getInverse(CMatrix4& out) const; + + //! Builds a right-handed perspective projection matrix based on a field of view + //\param zClipFromZero: Clipping of z can be projected from 0 to w when true (D3D style) and from -w to w when false (OGL style). + CMatrix4& buildProjectionMatrixPerspectiveFovRH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero=true); + + //! Builds a left-handed perspective projection matrix based on a field of view + CMatrix4& buildProjectionMatrixPerspectiveFovLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero=true); + + //! Builds a left-handed perspective projection matrix based on a field of view, with far plane at infinity + CMatrix4& buildProjectionMatrixPerspectiveFovInfinityLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon=0); + + //! Builds a right-handed perspective projection matrix. + CMatrix4& buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true); + + //! Builds a left-handed perspective projection matrix. + CMatrix4& buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true); + + //! Builds a left-handed orthogonal projection matrix. + //\param zClipFromZero: Clipping of z can be projected from 0 to 1 when true (D3D style) and from -1 to 1 when false (OGL style). + CMatrix4& buildProjectionMatrixOrthoLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true); + + //! Builds a right-handed orthogonal projection matrix. + CMatrix4& buildProjectionMatrixOrthoRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true); + + //! Builds a left-handed look-at matrix. + CMatrix4& buildCameraLookAtMatrixLH( + const vector3df& position, + const vector3df& target, + const vector3df& upVector); + + //! Builds a right-handed look-at matrix. + CMatrix4& buildCameraLookAtMatrixRH( + const vector3df& position, + const vector3df& target, + const vector3df& upVector); + + //! Builds a matrix that flattens geometry into a plane. + /** \param light: light source + \param plane: plane into which the geometry if flattened into + \param point: value between 0 and 1, describing the light source. + If this is 1, it is a point light, if it is 0, it is a directional light. */ + CMatrix4& buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point=1.0f); + + //! Builds a matrix which transforms a normalized Device Coordinate to Device Coordinates. + /** Used to scale <-1,-1><1,1> to viewport, for example from <-1,-1> <1,1> to the viewport <0,0><0,640> */ + CMatrix4& buildNDCToDCMatrix( const core::rect& area, f32 zScale); + + //! Creates a new matrix as interpolated matrix from two other ones. + /** \param b: other matrix to interpolate with + \param time: Must be a value between 0 and 1. */ + CMatrix4 interpolate(const core::CMatrix4& b, f32 time) const; + + //! Gets transposed matrix + CMatrix4 getTransposed() const; + + //! Gets transposed matrix + inline void getTransposed( CMatrix4& dest ) const; + + //! Builds a matrix that rotates from one vector to another + /** \param from: vector to rotate from + \param to: vector to rotate to + */ + CMatrix4& buildRotateFromTo(const core::vector3df& from, const core::vector3df& to); + + //! Builds a combined matrix which translates to a center before rotation and translates from origin afterwards + /** \param center Position to rotate around + \param translate Translation applied after the rotation + */ + void setRotationCenter(const core::vector3df& center, const core::vector3df& translate); + + //! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis + /** \param camPos: viewer position in world coo + \param center: object position in world-coo and rotation pivot + \param translation: object final translation from center + \param axis: axis to rotate about + \param from: source vector to rotate from + */ + void buildAxisAlignedBillboard(const core::vector3df& camPos, + const core::vector3df& center, + const core::vector3df& translation, + const core::vector3df& axis, + const core::vector3df& from); + + /* + construct 2D Texture transformations + rotate about center, scale, and transform. + */ + //! Set to a texture transformation matrix with the given parameters. + CMatrix4& buildTextureTransform( f32 rotateRad, + const core::vector2df &rotatecenter, + const core::vector2df &translate, + const core::vector2df &scale); + + //! Set texture transformation rotation + /** Rotate about z axis, recenter at (0.5,0.5). + Doesn't clear other elements than those affected + \param radAngle Angle in radians + \return Altered matrix */ + CMatrix4& setTextureRotationCenter( f32 radAngle ); + + //! Set texture transformation translation + /** Doesn't clear other elements than those affected. + \param x Offset on x axis + \param y Offset on y axis + \return Altered matrix */ + CMatrix4& setTextureTranslate( f32 x, f32 y ); + + //! Get texture transformation translation + /** \param x returns offset on x axis + \param y returns offset on y axis */ + void getTextureTranslate( f32& x, f32& y ) const; + + //! Set texture transformation translation, using a transposed representation + /** Doesn't clear other elements than those affected. + \param x Offset on x axis + \param y Offset on y axis + \return Altered matrix */ + CMatrix4& setTextureTranslateTransposed( f32 x, f32 y ); + + //! Set texture transformation scale + /** Doesn't clear other elements than those affected. + \param sx Scale factor on x axis + \param sy Scale factor on y axis + \return Altered matrix. */ + CMatrix4& setTextureScale( f32 sx, f32 sy ); + + //! Get texture transformation scale + /** \param sx Returns x axis scale factor + \param sy Returns y axis scale factor */ + void getTextureScale( f32& sx, f32& sy ) const; + + //! Set texture transformation scale, and recenter at (0.5,0.5) + /** Doesn't clear other elements than those affected. + \param sx Scale factor on x axis + \param sy Scale factor on y axis + \return Altered matrix. */ + CMatrix4& setTextureScaleCenter( f32 sx, f32 sy ); + + //! Sets all matrix data members at once + CMatrix4& setM(const T* data); + + //! Sets if the matrix is definitely identity matrix + void setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix); + + //! Gets if the matrix is definitely identity matrix + bool getDefinitelyIdentityMatrix() const; + + //! Compare two matrices using the equal method + bool equals(const core::CMatrix4& other, const T tolerance=(T)ROUNDING_ERROR_f64) const; + + private: + //! Matrix data, stored in row-major order + T M[16]; +#if defined ( USE_MATRIX_TEST ) + //! Flag is this matrix is identity matrix + mutable u32 definitelyIdentityMatrix; +#endif +#if defined ( USE_MATRIX_TEST_DEBUG ) + u32 id; + mutable u32 calls; +#endif + + }; + + // Default constructor + template + inline CMatrix4::CMatrix4( eConstructor constructor ) +#if defined ( USE_MATRIX_TEST ) + : definitelyIdentityMatrix(BIT_UNTESTED) +#endif +#if defined ( USE_MATRIX_TEST_DEBUG ) + ,id ( MTest.ID++), calls ( 0 ) +#endif + { + switch ( constructor ) + { + case EM4CONST_NOTHING: + case EM4CONST_COPY: + break; + case EM4CONST_IDENTITY: + case EM4CONST_INVERSE: + default: + makeIdentity(); + break; + } + } + + // Copy constructor + template + inline CMatrix4::CMatrix4( const CMatrix4& other, eConstructor constructor) +#if defined ( USE_MATRIX_TEST ) + : definitelyIdentityMatrix(BIT_UNTESTED) +#endif +#if defined ( USE_MATRIX_TEST_DEBUG ) + ,id ( MTest.ID++), calls ( 0 ) +#endif + { + switch ( constructor ) + { + case EM4CONST_IDENTITY: + makeIdentity(); + break; + case EM4CONST_NOTHING: + break; + case EM4CONST_COPY: + *this = other; + break; + case EM4CONST_TRANSPOSED: + other.getTransposed(*this); + break; + case EM4CONST_INVERSE: + if (!other.getInverse(*this)) + memset(M, 0, 16*sizeof(T)); + break; + case EM4CONST_INVERSE_TRANSPOSED: + if (!other.getInverse(*this)) + memset(M, 0, 16*sizeof(T)); + else + *this=getTransposed(); + break; + } + } + + //! Add another matrix. + template + inline CMatrix4 CMatrix4::operator+(const CMatrix4& other) const + { + CMatrix4 temp ( EM4CONST_NOTHING ); + + temp[0] = M[0]+other[0]; + temp[1] = M[1]+other[1]; + temp[2] = M[2]+other[2]; + temp[3] = M[3]+other[3]; + temp[4] = M[4]+other[4]; + temp[5] = M[5]+other[5]; + temp[6] = M[6]+other[6]; + temp[7] = M[7]+other[7]; + temp[8] = M[8]+other[8]; + temp[9] = M[9]+other[9]; + temp[10] = M[10]+other[10]; + temp[11] = M[11]+other[11]; + temp[12] = M[12]+other[12]; + temp[13] = M[13]+other[13]; + temp[14] = M[14]+other[14]; + temp[15] = M[15]+other[15]; + + return temp; + } + + //! Add another matrix. + template + inline CMatrix4& CMatrix4::operator+=(const CMatrix4& other) + { + M[0]+=other[0]; + M[1]+=other[1]; + M[2]+=other[2]; + M[3]+=other[3]; + M[4]+=other[4]; + M[5]+=other[5]; + M[6]+=other[6]; + M[7]+=other[7]; + M[8]+=other[8]; + M[9]+=other[9]; + M[10]+=other[10]; + M[11]+=other[11]; + M[12]+=other[12]; + M[13]+=other[13]; + M[14]+=other[14]; + M[15]+=other[15]; + + return *this; + } + + //! Subtract another matrix. + template + inline CMatrix4 CMatrix4::operator-(const CMatrix4& other) const + { + CMatrix4 temp ( EM4CONST_NOTHING ); + + temp[0] = M[0]-other[0]; + temp[1] = M[1]-other[1]; + temp[2] = M[2]-other[2]; + temp[3] = M[3]-other[3]; + temp[4] = M[4]-other[4]; + temp[5] = M[5]-other[5]; + temp[6] = M[6]-other[6]; + temp[7] = M[7]-other[7]; + temp[8] = M[8]-other[8]; + temp[9] = M[9]-other[9]; + temp[10] = M[10]-other[10]; + temp[11] = M[11]-other[11]; + temp[12] = M[12]-other[12]; + temp[13] = M[13]-other[13]; + temp[14] = M[14]-other[14]; + temp[15] = M[15]-other[15]; + + return temp; + } + + //! Subtract another matrix. + template + inline CMatrix4& CMatrix4::operator-=(const CMatrix4& other) + { + M[0]-=other[0]; + M[1]-=other[1]; + M[2]-=other[2]; + M[3]-=other[3]; + M[4]-=other[4]; + M[5]-=other[5]; + M[6]-=other[6]; + M[7]-=other[7]; + M[8]-=other[8]; + M[9]-=other[9]; + M[10]-=other[10]; + M[11]-=other[11]; + M[12]-=other[12]; + M[13]-=other[13]; + M[14]-=other[14]; + M[15]-=other[15]; + + return *this; + } + + //! Multiply by scalar. + template + inline CMatrix4 CMatrix4::operator*(const T& scalar) const + { + CMatrix4 temp ( EM4CONST_NOTHING ); + + temp[0] = M[0]*scalar; + temp[1] = M[1]*scalar; + temp[2] = M[2]*scalar; + temp[3] = M[3]*scalar; + temp[4] = M[4]*scalar; + temp[5] = M[5]*scalar; + temp[6] = M[6]*scalar; + temp[7] = M[7]*scalar; + temp[8] = M[8]*scalar; + temp[9] = M[9]*scalar; + temp[10] = M[10]*scalar; + temp[11] = M[11]*scalar; + temp[12] = M[12]*scalar; + temp[13] = M[13]*scalar; + temp[14] = M[14]*scalar; + temp[15] = M[15]*scalar; + + return temp; + } + + //! Multiply by scalar. + template + inline CMatrix4& CMatrix4::operator*=(const T& scalar) + { + M[0]*=scalar; + M[1]*=scalar; + M[2]*=scalar; + M[3]*=scalar; + M[4]*=scalar; + M[5]*=scalar; + M[6]*=scalar; + M[7]*=scalar; + M[8]*=scalar; + M[9]*=scalar; + M[10]*=scalar; + M[11]*=scalar; + M[12]*=scalar; + M[13]*=scalar; + M[14]*=scalar; + M[15]*=scalar; + + return *this; + } + + //! Multiply by another matrix. + template + inline CMatrix4& CMatrix4::operator*=(const CMatrix4& other) + { +#if defined ( USE_MATRIX_TEST ) + // do checks on your own in order to avoid copy creation + if ( !other.isIdentity() ) + { + if ( this->isIdentity() ) + { + return (*this = other); + } + else + { + CMatrix4 temp ( *this ); + return setbyproduct_nocheck( temp, other ); + } + } + return *this; +#else + CMatrix4 temp ( *this ); + return setbyproduct_nocheck( temp, other ); +#endif + } + + //! multiply by another matrix + // set this matrix to the product of two other matrices + // goal is to reduce stack use and copy + template + inline CMatrix4& CMatrix4::setbyproduct_nocheck(const CMatrix4& other_a,const CMatrix4& other_b ) + { + const T *m1 = other_a.M; + const T *m2 = other_b.M; + + M[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3]; + M[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3]; + M[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3]; + M[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3]; + + M[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7]; + M[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7]; + M[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7]; + M[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7]; + + M[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11]; + M[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11]; + M[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11]; + M[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11]; + + M[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15]; + M[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15]; + M[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15]; + M[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15]; +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + + //! multiply by another matrix + // set this matrix to the product of two other matrices + // goal is to reduce stack use and copy + template + inline CMatrix4& CMatrix4::setbyproduct(const CMatrix4& other_a, const CMatrix4& other_b ) + { +#if defined ( USE_MATRIX_TEST ) + if ( other_a.isIdentity () ) + return (*this = other_b); + else + if ( other_b.isIdentity () ) + return (*this = other_a); + else + return setbyproduct_nocheck(other_a,other_b); +#else + return setbyproduct_nocheck(other_a,other_b); +#endif + } + + //! multiply by another matrix + template + inline CMatrix4 CMatrix4::operator*(const CMatrix4& m2) const + { +#if defined ( USE_MATRIX_TEST ) + // Testing purpose.. + if ( this->isIdentity() ) + return m2; + if ( m2.isIdentity() ) + return *this; +#endif + + CMatrix4 m3 ( EM4CONST_NOTHING ); + + const T *m1 = M; + + m3[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3]; + m3[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3]; + m3[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3]; + m3[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3]; + + m3[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7]; + m3[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7]; + m3[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7]; + m3[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7]; + + m3[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11]; + m3[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11]; + m3[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11]; + m3[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11]; + + m3[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15]; + m3[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15]; + m3[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15]; + m3[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15]; + return m3; + } + + + + template + inline vector3d CMatrix4::getTranslation() const + { + return vector3d(M[12], M[13], M[14]); + } + + + template + inline CMatrix4& CMatrix4::setTranslation( const vector3d& translation ) + { + M[12] = translation.X; + M[13] = translation.Y; + M[14] = translation.Z; +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + template + inline CMatrix4& CMatrix4::setInverseTranslation( const vector3d& translation ) + { + M[12] = -translation.X; + M[13] = -translation.Y; + M[14] = -translation.Z; +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + template + inline CMatrix4& CMatrix4::setScale( const vector3d& scale ) + { + M[0] = scale.X; + M[5] = scale.Y; + M[10] = scale.Z; +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + //! Returns the absolute values of the scales of the matrix. + /** + Note that this returns the absolute (positive) values unless only scale is set. + 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 + { + // 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 + inline CMatrix4& CMatrix4::setRotationDegrees( const vector3d& rotation ) + { + return setRotationRadians( rotation * core::DEGTORAD ); + } + + template + inline CMatrix4& CMatrix4::setInverseRotationDegrees( const vector3d& rotation ) + { + return setInverseRotationRadians( rotation * core::DEGTORAD ); + } + + template + inline CMatrix4& CMatrix4::setRotationRadians( const vector3d& rotation ) + { + const f64 cr = cos( rotation.X ); + const f64 sr = sin( rotation.X ); + const f64 cp = cos( rotation.Y ); + const f64 sp = sin( rotation.Y ); + const f64 cy = cos( rotation.Z ); + const f64 sy = sin( rotation.Z ); + + M[0] = (T)( cp*cy ); + M[1] = (T)( cp*sy ); + M[2] = (T)( -sp ); + + const f64 srsp = sr*sp; + const f64 crsp = cr*sp; + + M[4] = (T)( srsp*cy-cr*sy ); + M[5] = (T)( srsp*sy+cr*cy ); + M[6] = (T)( sr*cp ); + + M[8] = (T)( crsp*cy+sr*sy ); + M[9] = (T)( crsp*sy-sr*cy ); + M[10] = (T)( cr*cp ); +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + + //! Returns a rotation that is equivalent to that set by setRotationDegrees(). + /** This code was sent in by Chev. Note that it does not necessarily return + the *same* Euler angles as those set by setRotationDegrees(), but the rotation will + be equivalent, i.e. will have the same result when used to rotate a vector or node. + This code was originally written by by Chev. + */ + template + inline core::vector3d CMatrix4::getRotationDegrees(const vector3d& scale_) const + { + const CMatrix4 &mat = *this; + core::vector3d scale(scale_); + // we need to check for negative scale on to axes, which would bring up wrong results + if (scale.Y<0 && scale.Z<0) + { + scale.Y =-scale.Y; + scale.Z =-scale.Z; + } + else if (scale.X<0 && scale.Z<0) + { + scale.X =-scale.X; + scale.Z =-scale.Z; + } + else if (scale.X<0 && scale.Y<0) + { + scale.X =-scale.X; + scale.Y =-scale.Y; + } + const core::vector3d invScale(core::reciprocal(scale.X),core::reciprocal(scale.Y),core::reciprocal(scale.Z)); + + f64 Y = -asin(core::clamp(mat[2]*invScale.X, -1.0, 1.0)); + const f64 C = cos(Y); + Y *= RADTODEG64; + + f64 rotx, roty, X, Z; + + if (!core::iszero(C)) + { + const f64 invC = core::reciprocal(C); + rotx = mat[10] * invC * invScale.Z; + roty = mat[6] * invC * invScale.Y; + X = atan2( roty, rotx ) * RADTODEG64; + rotx = mat[0] * invC * invScale.X; + roty = mat[1] * invC * invScale.X; + Z = atan2( roty, rotx ) * RADTODEG64; + } + else + { + X = 0.0; + rotx = mat[5] * invScale.Y; + roty = -mat[4] * invScale.Y; + Z = atan2( roty, rotx ) * RADTODEG64; + } + + // fix values that get below zero + if (X < 0.0) X += 360.0; + if (Y < 0.0) Y += 360.0; + if (Z < 0.0) Z += 360.0; + + return vector3d((T)X,(T)Y,(T)Z); + } + + //! Returns a rotation that is equivalent to that set by setRotationDegrees(). + /** This code was sent in by Chev. Note that it does not necessarily return + the *same* Euler angles as those set by setRotationDegrees(), but the rotation will + be equivalent, i.e. will have the same result when used to rotate a vector or node. + This code was originally written by by Chev. */ + template + inline core::vector3d CMatrix4::getRotationDegrees() const + { + return getRotationDegrees(getScale()); + } + + + //! Sets matrix to rotation matrix of inverse angles given as parameters + template + inline CMatrix4& CMatrix4::setInverseRotationRadians( const vector3d& rotation ) + { + f64 cr = cos( rotation.X ); + f64 sr = sin( rotation.X ); + f64 cp = cos( rotation.Y ); + f64 sp = sin( rotation.Y ); + f64 cy = cos( rotation.Z ); + f64 sy = sin( rotation.Z ); + + M[0] = (T)( cp*cy ); + M[4] = (T)( cp*sy ); + M[8] = (T)( -sp ); + + f64 srsp = sr*sp; + f64 crsp = cr*sp; + + M[1] = (T)( srsp*cy-cr*sy ); + M[5] = (T)( srsp*sy+cr*cy ); + M[9] = (T)( sr*cp ); + + M[2] = (T)( crsp*cy+sr*sy ); + M[6] = (T)( crsp*sy-sr*cy ); + M[10] = (T)( cr*cp ); +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + //! Sets matrix to rotation matrix defined by axis and angle, assuming LH rotation + template + inline CMatrix4& CMatrix4::setRotationAxisRadians( const T& angle, const vector3d& axis ) + { + const f64 c = cos(angle); + const f64 s = sin(angle); + const f64 t = 1.0 - c; + + const f64 tx = t * axis.X; + const f64 ty = t * axis.Y; + const f64 tz = t * axis.Z; + + const f64 sx = s * axis.X; + const f64 sy = s * axis.Y; + const f64 sz = s * axis.Z; + + M[0] = (T)(tx * axis.X + c); + M[1] = (T)(tx * axis.Y + sz); + M[2] = (T)(tx * axis.Z - sy); + + M[4] = (T)(ty * axis.X - sz); + M[5] = (T)(ty * axis.Y + c); + M[6] = (T)(ty * axis.Z + sx); + + M[8] = (T)(tz * axis.X + sy); + M[9] = (T)(tz * axis.Y - sx); + M[10] = (T)(tz * axis.Z + c); + +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + + /*! + */ + template + inline CMatrix4& CMatrix4::makeIdentity() + { + memset(M, 0, 16*sizeof(T)); + M[0] = M[5] = M[10] = M[15] = (T)1; +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=true; +#endif + return *this; + } + + + /* + check identity with epsilon + solve floating range problems.. + */ + template + inline bool CMatrix4::isIdentity() const + { +#if defined ( USE_MATRIX_TEST ) + if (definitelyIdentityMatrix) + return true; +#endif + if (!core::equals( M[12], (T)0 ) || !core::equals( M[13], (T)0 ) || !core::equals( M[14], (T)0 ) || !core::equals( M[15], (T)1 )) + return false; + + if (!core::equals( M[ 0], (T)1 ) || !core::equals( M[ 1], (T)0 ) || !core::equals( M[ 2], (T)0 ) || !core::equals( M[ 3], (T)0 )) + return false; + + if (!core::equals( M[ 4], (T)0 ) || !core::equals( M[ 5], (T)1 ) || !core::equals( M[ 6], (T)0 ) || !core::equals( M[ 7], (T)0 )) + return false; + + if (!core::equals( M[ 8], (T)0 ) || !core::equals( M[ 9], (T)0 ) || !core::equals( M[10], (T)1 ) || !core::equals( M[11], (T)0 )) + return false; +/* + if (!core::equals( M[ 0], (T)1 ) || + !core::equals( M[ 5], (T)1 ) || + !core::equals( M[10], (T)1 ) || + !core::equals( M[15], (T)1 )) + return false; + + for (s32 i=0; i<4; ++i) + for (s32 j=0; j<4; ++j) + if ((j != i) && (!iszero((*this)(i,j)))) + return false; +*/ +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=true; +#endif + 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.. + reducing floating point branches + but it needs the floats in memory.. + */ + template + inline bool CMatrix4::isIdentity_integer_base() const + { +#if defined ( USE_MATRIX_TEST ) + if (definitelyIdentityMatrix) + return true; +#endif + if(IR(M[0])!=F32_VALUE_1) return false; + if(IR(M[1])!=0) return false; + if(IR(M[2])!=0) return false; + if(IR(M[3])!=0) return false; + + if(IR(M[4])!=0) return false; + if(IR(M[5])!=F32_VALUE_1) return false; + if(IR(M[6])!=0) return false; + if(IR(M[7])!=0) return false; + + if(IR(M[8])!=0) return false; + if(IR(M[9])!=0) return false; + if(IR(M[10])!=F32_VALUE_1) return false; + if(IR(M[11])!=0) return false; + + if(IR(M[12])!=0) return false; + if(IR(M[13])!=0) return false; + if(IR(M[13])!=0) return false; + if(IR(M[15])!=F32_VALUE_1) return false; + +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=true; +#endif + return true; + } + + + template + inline void CMatrix4::rotateVect( vector3df& vect ) const + { + vector3df tmp = vect; + vect.X = tmp.X*M[0] + tmp.Y*M[4] + tmp.Z*M[8]; + vect.Y = tmp.X*M[1] + tmp.Y*M[5] + tmp.Z*M[9]; + vect.Z = tmp.X*M[2] + tmp.Y*M[6] + tmp.Z*M[10]; + } + + //! An alternate transform vector method, writing into a second vector + template + inline void CMatrix4::rotateVect(core::vector3df& out, const core::vector3df& in) const + { + out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8]; + out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9]; + out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10]; + } + + //! An alternate transform vector method, writing into an array of 3 floats + template + inline void CMatrix4::rotateVect(T *out, const core::vector3df& in) const + { + out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8]; + out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9]; + out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10]; + } + + template + inline void CMatrix4::inverseRotateVect( vector3df& vect ) const + { + vector3df tmp = vect; + vect.X = tmp.X*M[0] + tmp.Y*M[1] + tmp.Z*M[2]; + vect.Y = tmp.X*M[4] + tmp.Y*M[5] + tmp.Z*M[6]; + vect.Z = tmp.X*M[8] + tmp.Y*M[9] + tmp.Z*M[10]; + } + + template + inline void CMatrix4::transformVect( vector3df& vect) const + { + f32 vector[3]; + + vector[0] = vect.X*M[0] + vect.Y*M[4] + vect.Z*M[8] + M[12]; + vector[1] = vect.X*M[1] + vect.Y*M[5] + vect.Z*M[9] + M[13]; + vector[2] = vect.X*M[2] + vect.Y*M[6] + vect.Z*M[10] + M[14]; + + vect.X = vector[0]; + vect.Y = vector[1]; + vect.Z = vector[2]; + } + + template + inline void CMatrix4::transformVect( vector3df& out, const vector3df& in) const + { + out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12]; + out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13]; + out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14]; + } + + + template + inline void CMatrix4::transformVect(T *out, const core::vector3df &in) const + { + out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12]; + out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13]; + out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14]; + out[3] = in.X*M[3] + in.Y*M[7] + in.Z*M[11] + M[15]; + } + + template + inline void CMatrix4::transformVec3(T *out, const T * in) const + { + out[0] = in[0]*M[0] + in[1]*M[4] + in[2]*M[8] + M[12]; + out[1] = in[0]*M[1] + in[1]*M[5] + in[2]*M[9] + M[13]; + out[2] = in[0]*M[2] + in[1]*M[6] + in[2]*M[10] + M[14]; + } + + template + inline void CMatrix4::transformVec4(T *out, const T * in) const + { + out[0] = in[0]*M[0] + in[1]*M[4] + in[2]*M[8] + in[3]*M[12]; + out[1] = in[0]*M[1] + in[1]*M[5] + in[2]*M[9] + in[3]*M[13]; + out[2] = in[0]*M[2] + in[1]*M[6] + in[2]*M[10] + in[3]*M[14]; + out[3] = in[0]*M[3] + in[1]*M[7] + in[2]*M[11] + in[3]*M[15]; + } + + + //! Transforms a plane by this matrix + template + inline void CMatrix4::transformPlane( core::plane3d &plane) const + { + vector3df member; + // Transform the plane member point, i.e. rotate, translate and scale it. + transformVect(member, plane.getMemberPoint()); + + // Transform the normal by the transposed inverse of the matrix + CMatrix4 transposedInverse(*this, EM4CONST_INVERSE_TRANSPOSED); + vector3df normal = plane.Normal; + transposedInverse.rotateVect(normal); + plane.setPlane(member, normal.normalize()); + } + + //! Transforms a plane by this matrix + template + inline void CMatrix4::transformPlane( const core::plane3d &in, core::plane3d &out) const + { + out = in; + transformPlane( out ); + } + + //! Transforms the edge-points of a bounding box + //! Deprecated as it's usually not what people need (regards only 2 corners, but other corners might be outside the box after transformation) + //! Use transformBoxEx instead. + template + _IRR_DEPRECATED_ inline void CMatrix4::transformBox(core::aabbox3d& box) const + { +#if defined ( USE_MATRIX_TEST ) + if (isIdentity()) + return; +#endif + + transformVect(box.MinEdge); + transformVect(box.MaxEdge); + box.repair(); + } + + //! Transforms a axis aligned bounding box more accurately than transformBox() + template + inline void CMatrix4::transformBoxEx(core::aabbox3d& box) const + { +#if defined ( USE_MATRIX_TEST ) + if (isIdentity()) + return; +#endif + + const f32 Amin[3] = {box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z}; + const f32 Amax[3] = {box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z}; + + f32 Bmin[3]; + f32 Bmax[3]; + + Bmin[0] = Bmax[0] = M[12]; + Bmin[1] = Bmax[1] = M[13]; + Bmin[2] = Bmax[2] = M[14]; + + const CMatrix4 &m = *this; + + for (u32 i = 0; i < 3; ++i) + { + for (u32 j = 0; j < 3; ++j) + { + const f32 a = m(j,i) * Amin[j]; + const f32 b = m(j,i) * Amax[j]; + + if (a < b) + { + Bmin[i] += a; + Bmax[i] += b; + } + else + { + Bmin[i] += b; + Bmax[i] += a; + } + } + } + + box.MinEdge.X = Bmin[0]; + box.MinEdge.Y = Bmin[1]; + box.MinEdge.Z = Bmin[2]; + + box.MaxEdge.X = Bmax[0]; + box.MaxEdge.Y = Bmax[1]; + box.MaxEdge.Z = Bmax[2]; + } + + + //! Multiplies this matrix by a 1x4 matrix + template + inline void CMatrix4::multiplyWith1x4Matrix(T* matrix) const + { + /* + 0 1 2 3 + 4 5 6 7 + 8 9 10 11 + 12 13 14 15 + */ + + T mat[4]; + mat[0] = matrix[0]; + mat[1] = matrix[1]; + mat[2] = matrix[2]; + mat[3] = matrix[3]; + + matrix[0] = M[0]*mat[0] + M[4]*mat[1] + M[8]*mat[2] + M[12]*mat[3]; + matrix[1] = M[1]*mat[0] + M[5]*mat[1] + M[9]*mat[2] + M[13]*mat[3]; + matrix[2] = M[2]*mat[0] + M[6]*mat[1] + M[10]*mat[2] + M[14]*mat[3]; + matrix[3] = M[3]*mat[0] + M[7]*mat[1] + M[11]*mat[2] + M[15]*mat[3]; + } + + template + inline void CMatrix4::inverseTranslateVect( vector3df& vect ) const + { + vect.X = vect.X-M[12]; + vect.Y = vect.Y-M[13]; + vect.Z = vect.Z-M[14]; + } + + template + inline void CMatrix4::translateVect( vector3df& vect ) const + { + vect.X = vect.X+M[12]; + vect.Y = vect.Y+M[13]; + vect.Z = vect.Z+M[14]; + } + + + template + inline bool CMatrix4::getInverse(CMatrix4& out) const + { + /// Calculates the inverse of this Matrix + /// The inverse is calculated using Cramers rule. + /// If no inverse exists then 'false' is returned. + +#if defined ( USE_MATRIX_TEST ) + if ( this->isIdentity() ) + { + out=*this; + return true; + } +#endif + const CMatrix4 &m = *this; + + f32 d = (m[0] * m[5] - m[1] * m[4]) * (m[10] * m[15] - m[11] * m[14]) - + (m[0] * m[6] - m[2] * m[4]) * (m[9] * m[15] - m[11] * m[13]) + + (m[0] * m[7] - m[3] * m[4]) * (m[9] * m[14] - m[10] * m[13]) + + (m[1] * m[6] - m[2] * m[5]) * (m[8] * m[15] - m[11] * m[12]) - + (m[1] * m[7] - m[3] * m[5]) * (m[8] * m[14] - m[10] * m[12]) + + (m[2] * m[7] - m[3] * m[6]) * (m[8] * m[13] - m[9] * m[12]); + + if( core::iszero ( d, FLT_MIN ) ) + return false; + + d = core::reciprocal ( d ); + + out[0] = d * (m[5] * (m[10] * m[15] - m[11] * m[14]) + + m[6] * (m[11] * m[13] - m[9] * m[15]) + + m[7] * (m[9] * m[14] - m[10] * m[13])); + out[1] = d * (m[9] * (m[2] * m[15] - m[3] * m[14]) + + m[10] * (m[3] * m[13] - m[1] * m[15]) + + m[11] * (m[1] * m[14] - m[2] * m[13])); + out[2] = d * (m[13] * (m[2] * m[7] - m[3] * m[6]) + + m[14] * (m[3] * m[5] - m[1] * m[7]) + + m[15] * (m[1] * m[6] - m[2] * m[5])); + out[3] = d * (m[1] * (m[7] * m[10] - m[6] * m[11]) + + m[2] * (m[5] * m[11] - m[7] * m[9]) + + m[3] * (m[6] * m[9] - m[5] * m[10])); + out[4] = d * (m[6] * (m[8] * m[15] - m[11] * m[12]) + + m[7] * (m[10] * m[12] - m[8] * m[14]) + + m[4] * (m[11] * m[14] - m[10] * m[15])); + out[5] = d * (m[10] * (m[0] * m[15] - m[3] * m[12]) + + m[11] * (m[2] * m[12] - m[0] * m[14]) + + m[8] * (m[3] * m[14] - m[2] * m[15])); + out[6] = d * (m[14] * (m[0] * m[7] - m[3] * m[4]) + + m[15] * (m[2] * m[4] - m[0] * m[6]) + + m[12] * (m[3] * m[6] - m[2] * m[7])); + out[7] = d * (m[2] * (m[7] * m[8] - m[4] * m[11]) + + m[3] * (m[4] * m[10] - m[6] * m[8]) + + m[0] * (m[6] * m[11] - m[7] * m[10])); + out[8] = d * (m[7] * (m[8] * m[13] - m[9] * m[12]) + + m[4] * (m[9] * m[15] - m[11] * m[13]) + + m[5] * (m[11] * m[12] - m[8] * m[15])); + out[9] = d * (m[11] * (m[0] * m[13] - m[1] * m[12]) + + m[8] * (m[1] * m[15] - m[3] * m[13]) + + m[9] * (m[3] * m[12] - m[0] * m[15])); + out[10] = d * (m[15] * (m[0] * m[5] - m[1] * m[4]) + + m[12] * (m[1] * m[7] - m[3] * m[5]) + + m[13] * (m[3] * m[4] - m[0] * m[7])); + out[11] = d * (m[3] * (m[5] * m[8] - m[4] * m[9]) + + m[0] * (m[7] * m[9] - m[5] * m[11]) + + m[1] * (m[4] * m[11] - m[7] * m[8])); + out[12] = d * (m[4] * (m[10] * m[13] - m[9] * m[14]) + + m[5] * (m[8] * m[14] - m[10] * m[12]) + + m[6] * (m[9] * m[12] - m[8] * m[13])); + out[13] = d * (m[8] * (m[2] * m[13] - m[1] * m[14]) + + m[9] * (m[0] * m[14] - m[2] * m[12]) + + m[10] * (m[1] * m[12] - m[0] * m[13])); + out[14] = d * (m[12] * (m[2] * m[5] - m[1] * m[6]) + + m[13] * (m[0] * m[6] - m[2] * m[4]) + + m[14] * (m[1] * m[4] - m[0] * m[5])); + out[15] = d * (m[0] * (m[5] * m[10] - m[6] * m[9]) + + m[1] * (m[6] * m[8] - m[4] * m[10]) + + m[2] * (m[4] * m[9] - m[5] * m[8])); + +#if defined ( USE_MATRIX_TEST ) + out.definitelyIdentityMatrix = definitelyIdentityMatrix; +#endif + return true; + } + + + //! Inverts a primitive matrix which only contains a translation and a rotation + //! \param out: where result matrix is written to. + template + inline bool CMatrix4::getInversePrimitive ( CMatrix4& out ) const + { + out.M[0 ] = M[0]; + out.M[1 ] = M[4]; + out.M[2 ] = M[8]; + out.M[3 ] = 0; + + out.M[4 ] = M[1]; + out.M[5 ] = M[5]; + out.M[6 ] = M[9]; + out.M[7 ] = 0; + + out.M[8 ] = M[2]; + out.M[9 ] = M[6]; + out.M[10] = M[10]; + out.M[11] = 0; + + out.M[12] = (T)-(M[12]*M[0] + M[13]*M[1] + M[14]*M[2]); + out.M[13] = (T)-(M[12]*M[4] + M[13]*M[5] + M[14]*M[6]); + out.M[14] = (T)-(M[12]*M[8] + M[13]*M[9] + M[14]*M[10]); + out.M[15] = 1; + +#if defined ( USE_MATRIX_TEST ) + out.definitelyIdentityMatrix = definitelyIdentityMatrix; +#endif + return true; + } + + /*! + */ + template + inline bool CMatrix4::makeInverse() + { +#if defined ( USE_MATRIX_TEST ) + if (definitelyIdentityMatrix) + return true; +#endif + CMatrix4 temp ( EM4CONST_NOTHING ); + + if (getInverse(temp)) + { + *this = temp; + return true; + } + + return false; + } + + + template + inline CMatrix4& CMatrix4::operator=(const CMatrix4 &other) + { + if (this==&other) + return *this; + memcpy(M, other.M, 16*sizeof(T)); +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=other.definitelyIdentityMatrix; +#endif + return *this; + } + + + template + inline CMatrix4& CMatrix4::operator=(const T& scalar) + { + for (s32 i = 0; i < 16; ++i) + M[i]=scalar; + +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + + template + inline bool CMatrix4::operator==(const CMatrix4 &other) const + { +#if defined ( USE_MATRIX_TEST ) + if (definitelyIdentityMatrix && other.definitelyIdentityMatrix) + return true; +#endif + for (s32 i = 0; i < 16; ++i) + if (M[i] != other.M[i]) + return false; + + return true; + } + + + template + inline bool CMatrix4::operator!=(const CMatrix4 &other) const + { + return !(*this == other); + } + + + // Builds a right-handed perspective projection matrix based on a field of view + template + inline CMatrix4& CMatrix4::buildProjectionMatrixPerspectiveFovRH( + f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero) + { + const f64 h = reciprocal(tan(fieldOfViewRadians*0.5)); + _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero + const T w = static_cast(h / aspectRatio); + + _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero + M[0] = w; + M[1] = 0; + M[2] = 0; + M[3] = 0; + + M[4] = 0; + M[5] = (T)h; + M[6] = 0; + M[7] = 0; + + M[8] = 0; + M[9] = 0; + //M[10] + M[11] = -1; + + M[12] = 0; + M[13] = 0; + //M[14] + M[15] = 0; + + if ( zClipFromZero ) // DirectX version + { + M[10] = (T)(zFar/(zNear-zFar)); + M[14] = (T)(zNear*zFar/(zNear-zFar)); + } + else // OpenGL version + { + M[10] = (T)((zFar+zNear)/(zNear-zFar)); + M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar)); + } + +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + + // Builds a left-handed perspective projection matrix based on a field of view + template + inline CMatrix4& CMatrix4::buildProjectionMatrixPerspectiveFovLH( + f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero) + { + const f64 h = reciprocal(tan(fieldOfViewRadians*0.5)); + _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero + const T w = static_cast(h / aspectRatio); + + _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero + M[0] = w; + M[1] = 0; + M[2] = 0; + M[3] = 0; + + M[4] = 0; + M[5] = (T)h; + M[6] = 0; + M[7] = 0; + + M[8] = 0; + M[9] = 0; + //M[10] + M[11] = 1; + + M[12] = 0; + M[13] = 0; + //M[14] + M[15] = 0; + + if ( zClipFromZero ) // DirectX version + { + M[10] = (T)(zFar/(zFar-zNear)); + M[14] = (T)(-zNear*zFar/(zFar-zNear)); + } + else // OpenGL version + { + M[10] = (T)((zFar+zNear)/(zFar-zNear)); + M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar)); + } + +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + + // Builds a left-handed perspective projection matrix based on a field of view, with far plane culling at infinity + template + inline CMatrix4& CMatrix4::buildProjectionMatrixPerspectiveFovInfinityLH( + f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon) + { + const f64 h = reciprocal(tan(fieldOfViewRadians*0.5)); + _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero + const T w = static_cast(h / aspectRatio); + + M[0] = w; + M[1] = 0; + M[2] = 0; + M[3] = 0; + + M[4] = 0; + M[5] = (T)h; + M[6] = 0; + M[7] = 0; + + M[8] = 0; + M[9] = 0; + M[10] = (T)(1.f-epsilon); + M[11] = 1; + + M[12] = 0; + M[13] = 0; + M[14] = (T)(zNear*(epsilon-1.f)); + M[15] = 0; + +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + + // Builds a left-handed orthogonal projection matrix. + template + inline CMatrix4& CMatrix4::buildProjectionMatrixOrthoLH( + f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero) + { + _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero + _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero + _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero + M[0] = (T)(2/widthOfViewVolume); + M[1] = 0; + M[2] = 0; + M[3] = 0; + + M[4] = 0; + M[5] = (T)(2/heightOfViewVolume); + M[6] = 0; + M[7] = 0; + + M[8] = 0; + M[9] = 0; + // M[10] + M[11] = 0; + + M[12] = 0; + M[13] = 0; + // M[14] + M[15] = 1; + + if ( zClipFromZero ) + { + M[10] = (T)(1/(zFar-zNear)); + M[14] = (T)(zNear/(zNear-zFar)); + } + else + { + M[10] = (T)(2/(zFar-zNear)); + M[14] = (T)-(zFar+zNear)/(zFar-zNear); + } + +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + + // Builds a right-handed orthogonal projection matrix. + template + inline CMatrix4& CMatrix4::buildProjectionMatrixOrthoRH( + f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero) + { + _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero + _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero + _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero + M[0] = (T)(2/widthOfViewVolume); + M[1] = 0; + M[2] = 0; + M[3] = 0; + + M[4] = 0; + M[5] = (T)(2/heightOfViewVolume); + M[6] = 0; + M[7] = 0; + + M[8] = 0; + M[9] = 0; + // M[10] + M[11] = 0; + + M[12] = 0; + M[13] = 0; + // M[14] + M[15] = 1; + + if ( zClipFromZero ) + { + M[10] = (T)(1/(zNear-zFar)); + M[14] = (T)(zNear/(zNear-zFar)); + } + else + { + M[10] = (T)(2/(zNear-zFar)); + M[14] = (T)-(zFar+zNear)/(zFar-zNear); + } + +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + + // Builds a right-handed perspective projection matrix. + template + inline CMatrix4& CMatrix4::buildProjectionMatrixPerspectiveRH( + f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero) + { + _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero + _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero + _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero + M[0] = (T)(2*zNear/widthOfViewVolume); + M[1] = 0; + M[2] = 0; + M[3] = 0; + + M[4] = 0; + M[5] = (T)(2*zNear/heightOfViewVolume); + M[6] = 0; + M[7] = 0; + + M[8] = 0; + M[9] = 0; + //M[10] + M[11] = -1; + + M[12] = 0; + M[13] = 0; + //M[14] + M[15] = 0; + + if ( zClipFromZero ) // DirectX version + { + M[10] = (T)(zFar/(zNear-zFar)); + M[14] = (T)(zNear*zFar/(zNear-zFar)); + } + else // OpenGL version + { + M[10] = (T)((zFar+zNear)/(zNear-zFar)); + M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar)); + } + +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + + // Builds a left-handed perspective projection matrix. + template + inline CMatrix4& CMatrix4::buildProjectionMatrixPerspectiveLH( + f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero) + { + _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero + _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero + _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero + M[0] = (T)(2*zNear/widthOfViewVolume); + M[1] = 0; + M[2] = 0; + M[3] = 0; + + M[4] = 0; + M[5] = (T)(2*zNear/heightOfViewVolume); + M[6] = 0; + M[7] = 0; + + M[8] = 0; + M[9] = 0; + //M[10] + M[11] = 1; + + M[12] = 0; + M[13] = 0; + //M[14] = (T)(zNear*zFar/(zNear-zFar)); + M[15] = 0; + + if ( zClipFromZero ) // DirectX version + { + M[10] = (T)(zFar/(zFar-zNear)); + M[14] = (T)(zNear*zFar/(zNear-zFar)); + } + else // OpenGL version + { + M[10] = (T)((zFar+zNear)/(zFar-zNear)); + M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar)); + } + +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + + // Builds a matrix that flattens geometry into a plane. + template + inline CMatrix4& CMatrix4::buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point) + { + plane.Normal.normalize(); + const f32 d = plane.Normal.dotProduct(light); + + M[ 0] = (T)(-plane.Normal.X * light.X + d); + M[ 1] = (T)(-plane.Normal.X * light.Y); + M[ 2] = (T)(-plane.Normal.X * light.Z); + M[ 3] = (T)(-plane.Normal.X * point); + + M[ 4] = (T)(-plane.Normal.Y * light.X); + M[ 5] = (T)(-plane.Normal.Y * light.Y + d); + M[ 6] = (T)(-plane.Normal.Y * light.Z); + M[ 7] = (T)(-plane.Normal.Y * point); + + M[ 8] = (T)(-plane.Normal.Z * light.X); + M[ 9] = (T)(-plane.Normal.Z * light.Y); + M[10] = (T)(-plane.Normal.Z * light.Z + d); + M[11] = (T)(-plane.Normal.Z * point); + + M[12] = (T)(-plane.D * light.X); + M[13] = (T)(-plane.D * light.Y); + M[14] = (T)(-plane.D * light.Z); + M[15] = (T)(-plane.D * point + d); +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + // Builds a left-handed look-at matrix. + template + inline CMatrix4& CMatrix4::buildCameraLookAtMatrixLH( + const vector3df& position, + const vector3df& target, + const vector3df& upVector) + { + vector3df zaxis = target - position; + zaxis.normalize(); + + vector3df xaxis = upVector.crossProduct(zaxis); + xaxis.normalize(); + + vector3df yaxis = zaxis.crossProduct(xaxis); + + M[0] = (T)xaxis.X; + M[1] = (T)yaxis.X; + M[2] = (T)zaxis.X; + M[3] = 0; + + M[4] = (T)xaxis.Y; + M[5] = (T)yaxis.Y; + M[6] = (T)zaxis.Y; + M[7] = 0; + + M[8] = (T)xaxis.Z; + M[9] = (T)yaxis.Z; + M[10] = (T)zaxis.Z; + M[11] = 0; + + M[12] = (T)-xaxis.dotProduct(position); + M[13] = (T)-yaxis.dotProduct(position); + M[14] = (T)-zaxis.dotProduct(position); + M[15] = 1; +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + + // Builds a right-handed look-at matrix. + template + inline CMatrix4& CMatrix4::buildCameraLookAtMatrixRH( + const vector3df& position, + const vector3df& target, + const vector3df& upVector) + { + vector3df zaxis = position - target; + zaxis.normalize(); + + vector3df xaxis = upVector.crossProduct(zaxis); + xaxis.normalize(); + + vector3df yaxis = zaxis.crossProduct(xaxis); + + M[0] = (T)xaxis.X; + M[1] = (T)yaxis.X; + M[2] = (T)zaxis.X; + M[3] = 0; + + M[4] = (T)xaxis.Y; + M[5] = (T)yaxis.Y; + M[6] = (T)zaxis.Y; + M[7] = 0; + + M[8] = (T)xaxis.Z; + M[9] = (T)yaxis.Z; + M[10] = (T)zaxis.Z; + M[11] = 0; + + M[12] = (T)-xaxis.dotProduct(position); + M[13] = (T)-yaxis.dotProduct(position); + M[14] = (T)-zaxis.dotProduct(position); + M[15] = 1; +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + + // creates a new matrix as interpolated matrix from this and the passed one. + template + inline CMatrix4 CMatrix4::interpolate(const core::CMatrix4& b, f32 time) const + { + CMatrix4 mat ( EM4CONST_NOTHING ); + + for (u32 i=0; i < 16; i += 4) + { + mat.M[i+0] = (T)(M[i+0] + ( b.M[i+0] - M[i+0] ) * time); + mat.M[i+1] = (T)(M[i+1] + ( b.M[i+1] - M[i+1] ) * time); + mat.M[i+2] = (T)(M[i+2] + ( b.M[i+2] - M[i+2] ) * time); + mat.M[i+3] = (T)(M[i+3] + ( b.M[i+3] - M[i+3] ) * time); + } + return mat; + } + + + // returns transposed matrix + template + inline CMatrix4 CMatrix4::getTransposed() const + { + CMatrix4 t ( EM4CONST_NOTHING ); + getTransposed ( t ); + return t; + } + + + // returns transposed matrix + template + inline void CMatrix4::getTransposed( CMatrix4& o ) const + { + o[ 0] = M[ 0]; + o[ 1] = M[ 4]; + o[ 2] = M[ 8]; + o[ 3] = M[12]; + + o[ 4] = M[ 1]; + o[ 5] = M[ 5]; + o[ 6] = M[ 9]; + o[ 7] = M[13]; + + o[ 8] = M[ 2]; + o[ 9] = M[ 6]; + o[10] = M[10]; + o[11] = M[14]; + + o[12] = M[ 3]; + o[13] = M[ 7]; + o[14] = M[11]; + o[15] = M[15]; +#if defined ( USE_MATRIX_TEST ) + o.definitelyIdentityMatrix=definitelyIdentityMatrix; +#endif + } + + + // used to scale <-1,-1><1,1> to viewport + template + inline CMatrix4& CMatrix4::buildNDCToDCMatrix( const core::rect& viewport, f32 zScale) + { + const f32 scaleX = (viewport.getWidth() - 0.75f ) * 0.5f; + const f32 scaleY = -(viewport.getHeight() - 0.75f ) * 0.5f; + + const f32 dx = -0.5f + ( (viewport.UpperLeftCorner.X + viewport.LowerRightCorner.X ) * 0.5f ); + const f32 dy = -0.5f + ( (viewport.UpperLeftCorner.Y + viewport.LowerRightCorner.Y ) * 0.5f ); + + makeIdentity(); + M[12] = (T)dx; + M[13] = (T)dy; + return setScale(core::vector3d((T)scaleX, (T)scaleY, (T)zScale)); + } + + //! Builds a matrix that rotates from one vector to another + /** \param from: vector to rotate from + \param to: vector to rotate to + + http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToMatrix/index.htm + */ + template + inline CMatrix4& CMatrix4::buildRotateFromTo(const core::vector3df& from, const core::vector3df& to) + { + // unit vectors + core::vector3df f(from); + core::vector3df t(to); + f.normalize(); + t.normalize(); + + // axis multiplication by sin + core::vector3df vs(t.crossProduct(f)); + + // axis of rotation + core::vector3df v(vs); + v.normalize(); + + // cosinus angle + T ca = f.dotProduct(t); + + core::vector3df vt(v * (1 - ca)); + + M[0] = vt.X * v.X + ca; + M[5] = vt.Y * v.Y + ca; + M[10] = vt.Z * v.Z + ca; + + vt.X *= v.Y; + vt.Z *= v.X; + vt.Y *= v.Z; + + M[1] = vt.X - vs.Z; + M[2] = vt.Z + vs.Y; + M[3] = 0; + + M[4] = vt.X + vs.Z; + M[6] = vt.Y - vs.X; + M[7] = 0; + + M[8] = vt.Z - vs.Y; + M[9] = vt.Y + vs.X; + M[11] = 0; + + M[12] = 0; + M[13] = 0; + M[14] = 0; + M[15] = 1; + + return *this; + } + + //! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis + /** \param camPos: viewer position in world coord + \param center: object position in world-coord, rotation pivot + \param translation: object final translation from center + \param axis: axis to rotate about + \param from: source vector to rotate from + */ + template + inline void CMatrix4::buildAxisAlignedBillboard( + const core::vector3df& camPos, + const core::vector3df& center, + const core::vector3df& translation, + const core::vector3df& axis, + const core::vector3df& from) + { + // axis of rotation + core::vector3df up = axis; + up.normalize(); + const core::vector3df forward = (camPos - center).normalize(); + const core::vector3df right = up.crossProduct(forward).normalize(); + + // correct look vector + const core::vector3df look = right.crossProduct(up); + + // rotate from to + // axis multiplication by sin + const core::vector3df vs = look.crossProduct(from); + + // cosinus angle + const f32 ca = from.dotProduct(look); + + core::vector3df vt(up * (1.f - ca)); + + M[0] = static_cast(vt.X * up.X + ca); + M[5] = static_cast(vt.Y * up.Y + ca); + M[10] = static_cast(vt.Z * up.Z + ca); + + vt.X *= up.Y; + vt.Z *= up.X; + vt.Y *= up.Z; + + M[1] = static_cast(vt.X - vs.Z); + M[2] = static_cast(vt.Z + vs.Y); + M[3] = 0; + + M[4] = static_cast(vt.X + vs.Z); + M[6] = static_cast(vt.Y - vs.X); + M[7] = 0; + + M[8] = static_cast(vt.Z - vs.Y); + M[9] = static_cast(vt.Y + vs.X); + M[11] = 0; + + setRotationCenter(center, translation); + } + + + //! Builds a combined matrix which translate to a center before rotation and translate afterward + template + inline void CMatrix4::setRotationCenter(const core::vector3df& center, const core::vector3df& translation) + { + M[12] = -M[0]*center.X - M[4]*center.Y - M[8]*center.Z + (center.X - translation.X ); + M[13] = -M[1]*center.X - M[5]*center.Y - M[9]*center.Z + (center.Y - translation.Y ); + M[14] = -M[2]*center.X - M[6]*center.Y - M[10]*center.Z + (center.Z - translation.Z ); + M[15] = (T) 1.0; +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + } + + /*! + Generate texture coordinates as linear functions so that: + u = Ux*x + Uy*y + Uz*z + Uw + v = Vx*x + Vy*y + Vz*z + Vw + The matrix M for this case is: + Ux Vx 0 0 + Uy Vy 0 0 + Uz Vz 0 0 + Uw Vw 0 0 + */ + + + template + inline CMatrix4& CMatrix4::buildTextureTransform( f32 rotateRad, + const core::vector2df &rotatecenter, + const core::vector2df &translate, + const core::vector2df &scale) + { + const f32 c = cosf(rotateRad); + const f32 s = sinf(rotateRad); + + M[0] = (T)(c * scale.X); + M[1] = (T)(s * scale.Y); + M[2] = 0; + M[3] = 0; + + M[4] = (T)(-s * scale.X); + M[5] = (T)(c * scale.Y); + M[6] = 0; + M[7] = 0; + + M[8] = (T)(c * scale.X * rotatecenter.X + -s * rotatecenter.Y + translate.X); + M[9] = (T)(s * scale.Y * rotatecenter.X + c * rotatecenter.Y + translate.Y); + M[10] = 1; + M[11] = 0; + + M[12] = 0; + M[13] = 0; + M[14] = 0; + M[15] = 1; +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + + // rotate about z axis, center ( 0.5, 0.5 ) + template + inline CMatrix4& CMatrix4::setTextureRotationCenter( f32 rotateRad ) + { + const f32 c = cosf(rotateRad); + const f32 s = sinf(rotateRad); + M[0] = (T)c; + M[1] = (T)s; + + M[4] = (T)-s; + M[5] = (T)c; + + M[8] = (T)(0.5f * ( s - c) + 0.5f); + M[9] = (T)(-0.5f * ( s + c) + 0.5f); + +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix = definitelyIdentityMatrix && (rotateRad==0.0f); +#endif + return *this; + } + + + template + inline CMatrix4& CMatrix4::setTextureTranslate ( f32 x, f32 y ) + { + M[8] = (T)x; + M[9] = (T)y; + +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f); +#endif + return *this; + } + + template + inline void CMatrix4::getTextureTranslate(f32& x, f32& y) const + { + x = (f32)M[8]; + y = (f32)M[9]; + } + + template + inline CMatrix4& CMatrix4::setTextureTranslateTransposed ( f32 x, f32 y ) + { + M[2] = (T)x; + M[6] = (T)y; + +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f); +#endif + return *this; + } + + template + inline CMatrix4& CMatrix4::setTextureScale ( f32 sx, f32 sy ) + { + M[0] = (T)sx; + M[5] = (T)sy; +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f); +#endif + return *this; + } + + template + inline void CMatrix4::getTextureScale ( f32& sx, f32& sy ) const + { + sx = (f32)M[0]; + sy = (f32)M[5]; + } + + template + inline CMatrix4& CMatrix4::setTextureScaleCenter( f32 sx, f32 sy ) + { + M[0] = (T)sx; + M[5] = (T)sy; + M[8] = (T)(0.5f - 0.5f * sx); + M[9] = (T)(0.5f - 0.5f * sy); + +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f); +#endif + return *this; + } + + + // sets all matrix data members at once + template + inline CMatrix4& CMatrix4::setM(const T* data) + { + memcpy(M,data, 16*sizeof(T)); + +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix=false; +#endif + return *this; + } + + + // sets if the matrix is definitely identity matrix + template + inline void CMatrix4::setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix) + { +#if defined ( USE_MATRIX_TEST ) + definitelyIdentityMatrix = isDefinitelyIdentityMatrix; +#else + (void)isDefinitelyIdentityMatrix; // prevent compiler warning +#endif + } + + + // gets if the matrix is definitely identity matrix + template + inline bool CMatrix4::getDefinitelyIdentityMatrix() const + { +#if defined ( USE_MATRIX_TEST ) + return definitelyIdentityMatrix; +#else + return false; +#endif + } + + + //! Compare two matrices using the equal method + template + inline bool CMatrix4::equals(const core::CMatrix4& other, const T tolerance) const + { +#if defined ( USE_MATRIX_TEST ) + if (definitelyIdentityMatrix && other.definitelyIdentityMatrix) + return true; +#endif + for (s32 i = 0; i < 16; ++i) + if (!core::equals(M[i],other.M[i], tolerance)) + return false; + + return true; + } + + + // Multiply by scalar. + template + inline CMatrix4 operator*(const T scalar, const CMatrix4& mat) + { + return mat*scalar; + } + + + //! Typedef for f32 matrix + typedef CMatrix4 matrix4; + + //! global const identity matrix + IRRLICHT_API extern const matrix4 IdentityMatrix; + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/include/path.h b/include/path.h new file mode 100644 index 00000000..b5379877 --- /dev/null +++ b/include/path.h @@ -0,0 +1,88 @@ +// Copyright (C) 2002-2012 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 + +#ifndef __IRR_PATH_H_INCLUDED__ +#define __IRR_PATH_H_INCLUDED__ + +#include "irrString.h" + +namespace irr +{ +namespace io +{ + +//! Type used for all file system related strings. +/** This type will transparently handle different file system encodings. */ +typedef core::string path; + +//! Used in places where we identify objects by a filename, but don't actually work with the real filename +/** Irrlicht is internally not case-sensitive when it comes to names. + Also this class is a first step towards support for correctly serializing renamed objects. +*/ +struct SNamedPath +{ + //! Constructor + SNamedPath() {} + + //! Constructor + SNamedPath(const path& p) : Path(p), InternalName( PathToName(p) ) + { + } + + //! Is smaller comparator + bool operator <(const SNamedPath& other) const + { + return InternalName < other.InternalName; + } + + //! Set the path. + void setPath(const path& p) + { + Path = p; + InternalName = PathToName(p); + } + + //! Get the path. + const path& getPath() const + { + return Path; + }; + + //! Get the name which is used to identify the file. + //! This string is similar to the names and filenames used before Irrlicht 1.7 + const path& getInternalName() const + { + return InternalName; + } + + //! Implicit cast to io::path + operator core::stringc() const + { + return core::stringc(getPath()); + } + //! Implicit cast to io::path + operator core::stringw() const + { + return core::stringw(getPath()); + } + +protected: + // convert the given path string to a name string. + path PathToName(const path& p) const + { + path name(p); + name.replace( '\\', '/' ); + name.make_lower(); + return name; + } + +private: + path Path; + path InternalName; +}; + +} // io +} // irr + +#endif // __IRR_PATH_H_INCLUDED__ diff --git a/include/plane3d.h b/include/plane3d.h new file mode 100644 index 00000000..21701f04 --- /dev/null +++ b/include/plane3d.h @@ -0,0 +1,245 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_PLANE_3D_H_INCLUDED__ +#define __IRR_PLANE_3D_H_INCLUDED__ + +#include "irrMath.h" +#include "vector3d.h" + +namespace irr +{ +namespace core +{ + +//! Enumeration for intersection relations of 3d objects +enum EIntersectionRelation3D +{ + ISREL3D_FRONT = 0, + ISREL3D_BACK, + ISREL3D_PLANAR, + ISREL3D_SPANNING, + ISREL3D_CLIPPED +}; + +//! Template plane class with some intersection testing methods. +/** It has to be ensured, that the normal is always normalized. The constructors + and setters of this class will not ensure this automatically. So any normal + passed in has to be normalized in advance. No change to the normal will be + made by any of the class methods. +*/ +template +class plane3d +{ + public: + + // Constructors + + plane3d(): Normal(0,1,0) { recalculateD(vector3d(0,0,0)); } + + plane3d(const vector3d& MPoint, const vector3d& Normal) : Normal(Normal) { recalculateD(MPoint); } + + plane3d(T px, T py, T pz, T nx, T ny, T nz) : Normal(nx, ny, nz) { recalculateD(vector3d(px, py, pz)); } + + plane3d(const vector3d& point1, const vector3d& point2, const vector3d& point3) + { setPlane(point1, point2, point3); } + + plane3d(const vector3d & normal, const T d) : Normal(normal), D(d) { } + + // operators + + inline bool operator==(const plane3d& other) const { return (equals(D, other.D) && Normal==other.Normal);} + + inline bool operator!=(const plane3d& other) const { return !(*this == other);} + + // functions + + void setPlane(const vector3d& point, const vector3d& nvector) + { + Normal = nvector; + recalculateD(point); + } + + void setPlane(const vector3d& nvect, T d) + { + Normal = nvect; + D = d; + } + + void setPlane(const vector3d& point1, const vector3d& point2, const vector3d& point3) + { + // creates the plane from 3 memberpoints + Normal = (point2 - point1).crossProduct(point3 - point1); + Normal.normalize(); + + recalculateD(point1); + } + + + //! Get an intersection with a 3d line. + /** \param lineVect Vector of the line to intersect with. + \param linePoint Point of the line to intersect with. + \param outIntersection Place to store the intersection point, if there is one. + \return True if there was an intersection, false if there was not. + */ + bool getIntersectionWithLine(const vector3d& linePoint, + const vector3d& lineVect, + vector3d& outIntersection) const + { + T t2 = Normal.dotProduct(lineVect); + + if (t2 == 0) + return false; + + T t =- (Normal.dotProduct(linePoint) + D) / t2; + outIntersection = linePoint + (lineVect * t); + return true; + } + + //! Get percentage of line between two points where an intersection with this plane happens. + /** Only useful if known that there is an intersection. + \param linePoint1 Point1 of the line to intersect with. + \param linePoint2 Point2 of the line to intersect with. + \return Where on a line between two points an intersection with this plane happened. + For example, 0.5 is returned if the intersection happened exactly in the middle of the two points. + */ + f32 getKnownIntersectionWithLine(const vector3d& linePoint1, + const vector3d& linePoint2) const + { + vector3d vect = linePoint2 - linePoint1; + T t2 = (f32)Normal.dotProduct(vect); + return (f32)-((Normal.dotProduct(linePoint1) + D) / t2); + } + + //! Get an intersection with a 3d line, limited between two 3d points. + /** \param linePoint1 Point 1 of the line. + \param linePoint2 Point 2 of the line. + \param outIntersection Place to store the intersection point, if there is one. + \return True if there was an intersection, false if there was not. + */ + bool getIntersectionWithLimitedLine( + const vector3d& linePoint1, + const vector3d& linePoint2, + vector3d& outIntersection) const + { + return (getIntersectionWithLine(linePoint1, linePoint2 - linePoint1, outIntersection) && + outIntersection.isBetweenPoints(linePoint1, linePoint2)); + } + + //! Classifies the relation of a point to this plane. + /** \param point Point to classify its relation. + \return ISREL3D_FRONT if the point is in front of the plane, + ISREL3D_BACK if the point is behind of the plane, and + ISREL3D_PLANAR if the point is within the plane. */ + EIntersectionRelation3D classifyPointRelation(const vector3d& point) const + { + const T d = Normal.dotProduct(point) + D; + + if (d < -ROUNDING_ERROR_f32) + return ISREL3D_BACK; + + if (d > ROUNDING_ERROR_f32) + return ISREL3D_FRONT; + + return ISREL3D_PLANAR; + } + + //! Recalculates the distance from origin by applying a new member point to the plane. + void recalculateD(const vector3d& MPoint) + { + D = - MPoint.dotProduct(Normal); + } + + //! Gets a member point of the plane. + vector3d getMemberPoint() const + { + return Normal * -D; + } + + //! Tests if there is an intersection with the other plane + /** \return True if there is a intersection. */ + bool existsIntersection(const plane3d& other) const + { + vector3d cross = other.Normal.crossProduct(Normal); + return cross.getLength() > core::ROUNDING_ERROR_f32; + } + + //! Intersects this plane with another. + /** \param other Other plane to intersect with. + \param outLinePoint Base point of intersection line. + \param outLineVect Vector of intersection. + \return True if there is a intersection, false if not. */ + bool getIntersectionWithPlane(const plane3d& other, + vector3d& outLinePoint, + vector3d& outLineVect) const + { + const T fn00 = Normal.getLength(); + const T fn01 = Normal.dotProduct(other.Normal); + const T fn11 = other.Normal.getLength(); + const f64 det = fn00*fn11 - fn01*fn01; + + if (fabs(det) < ROUNDING_ERROR_f64 ) + return false; + + const f64 invdet = 1.0 / det; + const f64 fc0 = (fn11*-D + fn01*other.D) * invdet; + const f64 fc1 = (fn00*-other.D + fn01*D) * invdet; + + outLineVect = Normal.crossProduct(other.Normal); + outLinePoint = Normal*(T)fc0 + other.Normal*(T)fc1; + return true; + } + + //! Get the intersection point with two other planes if there is one. + bool getIntersectionWithPlanes(const plane3d& o1, + const plane3d& o2, vector3d& outPoint) const + { + vector3d linePoint, lineVect; + if (getIntersectionWithPlane(o1, linePoint, lineVect)) + return o2.getIntersectionWithLine(linePoint, lineVect, outPoint); + + return false; + } + + //! Test if the triangle would be front or backfacing from any point. + /** Thus, this method assumes a camera position from + which the triangle is definitely visible when looking into + the given direction. + Note that this only works if the normal is Normalized. + Do not use this method with points as it will give wrong results! + \param lookDirection: Look direction. + \return True if the plane is front facing and + false if it is backfacing. */ + bool isFrontFacing(const vector3d& lookDirection) const + { + const f32 d = Normal.dotProduct(lookDirection); + return F32_LOWER_EQUAL_0 ( d ); + } + + //! Get the distance to a point. + /** Note that this only works if the normal is normalized. */ + T getDistanceTo(const vector3d& point) const + { + return point.dotProduct(Normal) + D; + } + + //! Normal vector of the plane. + vector3d Normal; + + //! Distance from origin. + T D; +}; + + +//! Typedef for a f32 3d plane. +typedef plane3d plane3df; + +//! Typedef for an integer 3d plane. +typedef plane3d plane3di; + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/include/position2d.h b/include/position2d.h new file mode 100644 index 00000000..63275d2c --- /dev/null +++ b/include/position2d.h @@ -0,0 +1,32 @@ +// Copyright (C) 2002-2012 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 "vector2d.h" + +namespace irr +{ +namespace core +{ + +// Use typedefs where possible as they are more explicit... + +//! \deprecated position2d is now a synonym for vector2d, but vector2d should be used directly. +typedef vector2d position2df; + +//! \deprecated position2d is now a synonym for vector2d, but vector2d should be used directly. +typedef vector2d position2di; +} // namespace core +} // namespace irr + +// ...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 new file mode 100644 index 00000000..5fdff798 --- /dev/null +++ b/include/quaternion.h @@ -0,0 +1,771 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_QUATERNION_H_INCLUDED__ +#define __IRR_QUATERNION_H_INCLUDED__ + +#include "irrTypes.h" +#include "irrMath.h" +#include "matrix4.h" +#include "vector3d.h" + +// NOTE: You *only* need this when updating an application from Irrlicht before 1.8 to Irrlicht 1.8 or later. +// Between Irrlicht 1.7 and Irrlicht 1.8 the quaternion-matrix conversions changed. +// Before the fix they had mixed left- and right-handed rotations. +// To test if your code was affected by the change enable IRR_TEST_BROKEN_QUATERNION_USE and try to compile your application. +// This defines removes those functions so you get compile errors anywhere you use them in your code. +// For every line with a compile-errors you have to change the corresponding lines like that: +// - When you pass the matrix to the quaternion constructor then replace the matrix by the transposed matrix. +// - For uses of getMatrix() you have to use quaternion::getMatrix_transposed instead. +// #define IRR_TEST_BROKEN_QUATERNION_USE + +namespace irr +{ +namespace core +{ + +//! Quaternion class for representing rotations. +/** It provides cheap combinations and avoids gimbal locks. +Also useful for interpolations. */ +class quaternion +{ + public: + + //! Default Constructor + quaternion() : X(0.0f), Y(0.0f), Z(0.0f), W(1.0f) {} + + //! Constructor + quaternion(f32 x, f32 y, f32 z, f32 w) : X(x), Y(y), Z(z), W(w) { } + + //! Constructor which converts Euler angles (radians) to a quaternion + quaternion(f32 x, f32 y, f32 z); + + //! Constructor which converts Euler angles (radians) to a quaternion + quaternion(const vector3df& vec); + +#ifndef IRR_TEST_BROKEN_QUATERNION_USE + //! Constructor which converts a matrix to a quaternion + quaternion(const matrix4& mat); +#endif + + //! Equality operator + bool operator==(const quaternion& other) const; + + //! inequality operator + bool operator!=(const quaternion& other) const; + + //! Assignment operator + inline quaternion& operator=(const quaternion& other); + +#ifndef IRR_TEST_BROKEN_QUATERNION_USE + //! Matrix assignment operator + inline quaternion& operator=(const matrix4& other); +#endif + + //! Add operator + quaternion operator+(const quaternion& other) const; + + //! Multiplication operator + //! Be careful, unfortunately the operator order here is opposite of that in CMatrix4::operator* + quaternion operator*(const quaternion& other) const; + + //! Multiplication operator with scalar + quaternion operator*(f32 s) const; + + //! Multiplication operator with scalar + quaternion& operator*=(f32 s); + + //! Multiplication operator + vector3df operator*(const vector3df& v) const; + + //! Multiplication operator + quaternion& operator*=(const quaternion& other); + + //! Calculates the dot product + inline f32 dotProduct(const quaternion& other) const; + + //! Sets new quaternion + inline quaternion& set(f32 x, f32 y, f32 z, f32 w); + + //! Sets new quaternion based on Euler angles (radians) + inline quaternion& set(f32 x, f32 y, f32 z); + + //! Sets new quaternion based on Euler angles (radians) + inline quaternion& set(const core::vector3df& vec); + + //! Sets new quaternion from other quaternion + inline quaternion& set(const core::quaternion& quat); + + //! returns if this quaternion equals the other one, taking floating point rounding errors into account + inline bool equals(const quaternion& other, + const f32 tolerance = ROUNDING_ERROR_f32 ) const; + + //! Normalizes the quaternion + inline quaternion& normalize(); + +#ifndef IRR_TEST_BROKEN_QUATERNION_USE + //! Creates a matrix from this quaternion + matrix4 getMatrix() const; +#endif + //! Faster method to create a rotation matrix, you should normalize the quaternion before! + void getMatrixFast(matrix4 &dest) const; + + //! Creates a matrix from this quaternion + void getMatrix( matrix4 &dest, const core::vector3df &translation=core::vector3df() ) const; + + /*! + Creates a matrix from this quaternion + Rotate about a center point + shortcut for + core::quaternion q; + q.rotationFromTo ( vin[i].Normal, forward ); + q.getMatrixCenter ( lookat, center, newPos ); + + core::matrix4 m2; + m2.setInverseTranslation ( center ); + lookat *= m2; + + core::matrix4 m3; + m2.setTranslation ( newPos ); + lookat *= m3; + + */ + void getMatrixCenter( matrix4 &dest, const core::vector3df ¢er, const core::vector3df &translation ) const; + + //! Creates a matrix from this quaternion + inline void getMatrix_transposed( matrix4 &dest ) const; + + //! Inverts this quaternion + quaternion& makeInverse(); + + //! Set this quaternion to the linear interpolation between two quaternions + /** NOTE: lerp result is *not* a normalized quaternion. In most cases + you will want to use lerpN instead as most other quaternion functions expect + to work with a normalized quaternion. + \param q1 First quaternion to be interpolated. + \param q2 Second quaternion to be interpolated. + \param time Progress of interpolation. For time=0 the result is + q1, for time=1 the result is q2. Otherwise interpolation + between q1 and q2. Result is not normalized. + */ + quaternion& lerp(quaternion q1, quaternion q2, f32 time); + + //! Set this quaternion to the linear interpolation between two quaternions and normalize the result + /** + \param q1 First quaternion to be interpolated. + \param q2 Second quaternion to be interpolated. + \param time Progress of interpolation. For time=0 the result is + q1, for time=1 the result is q2. Otherwise interpolation + between q1 and q2. Result is normalized. + */ + quaternion& lerpN(quaternion q1, quaternion q2, f32 time); + + //! Set this quaternion to the result of the spherical interpolation between two quaternions + /** \param q1 First quaternion to be interpolated. + \param q2 Second quaternion to be interpolated. + \param time Progress of interpolation. For time=0 the result is + q1, for time=1 the result is q2. Otherwise interpolation + between q1 and q2. + \param threshold To avoid inaccuracies at the end (time=1) the + interpolation switches to linear interpolation at some point. + This value defines how much of the remaining interpolation will + be calculated with lerp. Everything from 1-threshold up will be + linear interpolation. + */ + quaternion& slerp(quaternion q1, quaternion q2, + f32 time, f32 threshold=.05f); + + //! Set this quaternion to represent a rotation from angle and axis. + /** Axis must be unit length. + The quaternion representing the rotation is + q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k). + \param angle Rotation Angle in radians. + \param axis Rotation axis. */ + quaternion& fromAngleAxis (f32 angle, const vector3df& axis); + + //! Fills an angle (radians) around an axis (unit vector) + void toAngleAxis (f32 &angle, core::vector3df& axis) const; + + //! Output this quaternion to an Euler angle (radians) + void toEuler(vector3df& euler) const; + + //! Set quaternion to identity + quaternion& makeIdentity(); + + //! Set quaternion to represent a rotation from one vector to another. + quaternion& rotationFromTo(const vector3df& from, const vector3df& to); + + //! Quaternion elements. + f32 X; // vectorial (imaginary) part + f32 Y; + f32 Z; + f32 W; // real part +}; + + +// Constructor which converts Euler angles to a quaternion +inline quaternion::quaternion(f32 x, f32 y, f32 z) +{ + set(x,y,z); +} + + +// Constructor which converts Euler angles to a quaternion +inline quaternion::quaternion(const vector3df& vec) +{ + set(vec.X,vec.Y,vec.Z); +} + +#ifndef IRR_TEST_BROKEN_QUATERNION_USE +// Constructor which converts a matrix to a quaternion +inline quaternion::quaternion(const matrix4& mat) +{ + (*this) = mat; +} +#endif + +// equal operator +inline bool quaternion::operator==(const quaternion& other) const +{ + return ((X == other.X) && + (Y == other.Y) && + (Z == other.Z) && + (W == other.W)); +} + +// inequality operator +inline bool quaternion::operator!=(const quaternion& other) const +{ + return !(*this == other); +} + +// assignment operator +inline quaternion& quaternion::operator=(const quaternion& other) +{ + X = other.X; + Y = other.Y; + Z = other.Z; + W = other.W; + return *this; +} + +#ifndef IRR_TEST_BROKEN_QUATERNION_USE +// matrix assignment operator +inline quaternion& quaternion::operator=(const matrix4& m) +{ + const f32 diag = m[0] + m[5] + m[10] + 1; + + if( diag > 0.0f ) + { + const f32 scale = sqrtf(diag) * 2.0f; // get scale from diagonal + + // TODO: speed this up + X = (m[6] - m[9]) / scale; + Y = (m[8] - m[2]) / scale; + Z = (m[1] - m[4]) / scale; + W = 0.25f * scale; + } + else + { + if (m[0]>m[5] && m[0]>m[10]) + { + // 1st element of diag is greatest value + // find scale according to 1st element, and double it + const f32 scale = sqrtf(1.0f + m[0] - m[5] - m[10]) * 2.0f; + + // TODO: speed this up + X = 0.25f * scale; + Y = (m[4] + m[1]) / scale; + Z = (m[2] + m[8]) / scale; + W = (m[6] - m[9]) / scale; + } + else if (m[5]>m[10]) + { + // 2nd element of diag is greatest value + // find scale according to 2nd element, and double it + const f32 scale = sqrtf(1.0f + m[5] - m[0] - m[10]) * 2.0f; + + // TODO: speed this up + X = (m[4] + m[1]) / scale; + Y = 0.25f * scale; + Z = (m[9] + m[6]) / scale; + W = (m[8] - m[2]) / scale; + } + else + { + // 3rd element of diag is greatest value + // find scale according to 3rd element, and double it + const f32 scale = sqrtf(1.0f + m[10] - m[0] - m[5]) * 2.0f; + + // TODO: speed this up + X = (m[8] + m[2]) / scale; + Y = (m[9] + m[6]) / scale; + Z = 0.25f * scale; + W = (m[1] - m[4]) / scale; + } + } + + return normalize(); +} +#endif + + +// multiplication operator +inline quaternion quaternion::operator*(const quaternion& other) const +{ + quaternion tmp; + + tmp.W = (other.W * W) - (other.X * X) - (other.Y * Y) - (other.Z * Z); + tmp.X = (other.W * X) + (other.X * W) + (other.Y * Z) - (other.Z * Y); + tmp.Y = (other.W * Y) + (other.Y * W) + (other.Z * X) - (other.X * Z); + tmp.Z = (other.W * Z) + (other.Z * W) + (other.X * Y) - (other.Y * X); + + return tmp; +} + + +// multiplication operator +inline quaternion quaternion::operator*(f32 s) const +{ + return quaternion(s*X, s*Y, s*Z, s*W); +} + + +// multiplication operator +inline quaternion& quaternion::operator*=(f32 s) +{ + X*=s; + Y*=s; + Z*=s; + W*=s; + return *this; +} + +// multiplication operator +inline quaternion& quaternion::operator*=(const quaternion& other) +{ + return (*this = other * (*this)); +} + +// add operator +inline quaternion quaternion::operator+(const quaternion& b) const +{ + return quaternion(X+b.X, Y+b.Y, Z+b.Z, W+b.W); +} + +#ifndef IRR_TEST_BROKEN_QUATERNION_USE +// Creates a matrix from this quaternion +inline matrix4 quaternion::getMatrix() const +{ + core::matrix4 m; + getMatrix(m); + return m; +} +#endif + +//! Faster method to create a rotation matrix, you should normalize the quaternion before! +inline void quaternion::getMatrixFast( matrix4 &dest) const +{ + // TODO: + // gpu quaternion skinning => fast Bones transform chain O_O YEAH! + // http://www.mrelusive.com/publications/papers/SIMD-From-Quaternion-to-Matrix-and-Back.pdf + dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z; + dest[1] = 2.0f*X*Y + 2.0f*Z*W; + dest[2] = 2.0f*X*Z - 2.0f*Y*W; + dest[3] = 0.0f; + + dest[4] = 2.0f*X*Y - 2.0f*Z*W; + dest[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z; + dest[6] = 2.0f*Z*Y + 2.0f*X*W; + dest[7] = 0.0f; + + dest[8] = 2.0f*X*Z + 2.0f*Y*W; + dest[9] = 2.0f*Z*Y - 2.0f*X*W; + dest[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y; + dest[11] = 0.0f; + + dest[12] = 0.f; + dest[13] = 0.f; + dest[14] = 0.f; + dest[15] = 1.f; + + dest.setDefinitelyIdentityMatrix(false); +} + +/*! + Creates a matrix from this quaternion +*/ +inline void quaternion::getMatrix(matrix4 &dest, + const core::vector3df ¢er) const +{ + // ok creating a copy may be slower, but at least avoid internal + // state chance (also because otherwise we cannot keep this method "const"). + + quaternion q( *this); + q.normalize(); + f32 X = q.X; + f32 Y = q.Y; + f32 Z = q.Z; + f32 W = q.W; + + dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z; + dest[1] = 2.0f*X*Y + 2.0f*Z*W; + dest[2] = 2.0f*X*Z - 2.0f*Y*W; + dest[3] = 0.0f; + + dest[4] = 2.0f*X*Y - 2.0f*Z*W; + dest[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z; + dest[6] = 2.0f*Z*Y + 2.0f*X*W; + dest[7] = 0.0f; + + dest[8] = 2.0f*X*Z + 2.0f*Y*W; + dest[9] = 2.0f*Z*Y - 2.0f*X*W; + dest[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y; + dest[11] = 0.0f; + + dest[12] = center.X; + dest[13] = center.Y; + dest[14] = center.Z; + dest[15] = 1.f; + + dest.setDefinitelyIdentityMatrix ( false ); +} + + +/*! + Creates a matrix from this quaternion + Rotate about a center point + shortcut for + core::quaternion q; + q.rotationFromTo(vin[i].Normal, forward); + q.getMatrix(lookat, center); + + core::matrix4 m2; + m2.setInverseTranslation(center); + lookat *= m2; +*/ +inline void quaternion::getMatrixCenter(matrix4 &dest, + const core::vector3df ¢er, + const core::vector3df &translation) const +{ + quaternion q(*this); + q.normalize(); + f32 X = q.X; + f32 Y = q.Y; + f32 Z = q.Z; + f32 W = q.W; + + dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z; + dest[1] = 2.0f*X*Y + 2.0f*Z*W; + dest[2] = 2.0f*X*Z - 2.0f*Y*W; + dest[3] = 0.0f; + + dest[4] = 2.0f*X*Y - 2.0f*Z*W; + dest[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z; + dest[6] = 2.0f*Z*Y + 2.0f*X*W; + dest[7] = 0.0f; + + dest[8] = 2.0f*X*Z + 2.0f*Y*W; + dest[9] = 2.0f*Z*Y - 2.0f*X*W; + dest[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y; + dest[11] = 0.0f; + + dest.setRotationCenter ( center, translation ); +} + +// Creates a matrix from this quaternion +inline void quaternion::getMatrix_transposed(matrix4 &dest) const +{ + quaternion q(*this); + q.normalize(); + f32 X = q.X; + f32 Y = q.Y; + f32 Z = q.Z; + f32 W = q.W; + + dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z; + dest[4] = 2.0f*X*Y + 2.0f*Z*W; + dest[8] = 2.0f*X*Z - 2.0f*Y*W; + dest[12] = 0.0f; + + dest[1] = 2.0f*X*Y - 2.0f*Z*W; + dest[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z; + dest[9] = 2.0f*Z*Y + 2.0f*X*W; + dest[13] = 0.0f; + + dest[2] = 2.0f*X*Z + 2.0f*Y*W; + dest[6] = 2.0f*Z*Y - 2.0f*X*W; + dest[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y; + dest[14] = 0.0f; + + dest[3] = 0.f; + dest[7] = 0.f; + dest[11] = 0.f; + dest[15] = 1.f; + + dest.setDefinitelyIdentityMatrix(false); +} + + +// Inverts this quaternion +inline quaternion& quaternion::makeInverse() +{ + X = -X; Y = -Y; Z = -Z; + return *this; +} + + +// sets new quaternion +inline quaternion& quaternion::set(f32 x, f32 y, f32 z, f32 w) +{ + X = x; + Y = y; + Z = z; + W = w; + return *this; +} + + +// sets new quaternion based on Euler angles +inline quaternion& quaternion::set(f32 x, f32 y, f32 z) +{ + f64 angle; + + angle = x * 0.5; + const f64 sr = sin(angle); + const f64 cr = cos(angle); + + angle = y * 0.5; + const f64 sp = sin(angle); + const f64 cp = cos(angle); + + angle = z * 0.5; + const f64 sy = sin(angle); + const f64 cy = cos(angle); + + const f64 cpcy = cp * cy; + const f64 spcy = sp * cy; + const f64 cpsy = cp * sy; + const f64 spsy = sp * sy; + + X = (f32)(sr * cpcy - cr * spsy); + Y = (f32)(cr * spcy + sr * cpsy); + Z = (f32)(cr * cpsy - sr * spcy); + W = (f32)(cr * cpcy + sr * spsy); + + return normalize(); +} + +// sets new quaternion based on Euler angles +inline quaternion& quaternion::set(const core::vector3df& vec) +{ + return set( vec.X, vec.Y, vec.Z); +} + +// sets new quaternion based on other quaternion +inline quaternion& quaternion::set(const core::quaternion& quat) +{ + return (*this=quat); +} + + +//! returns if this quaternion equals the other one, taking floating point rounding errors into account +inline bool quaternion::equals(const quaternion& other, const f32 tolerance) const +{ + return core::equals( X, other.X, tolerance) && + core::equals( Y, other.Y, tolerance) && + core::equals( Z, other.Z, tolerance) && + core::equals( W, other.W, tolerance); +} + + +// normalizes the quaternion +inline quaternion& quaternion::normalize() +{ + // removed conditional branch since it may slow down and anyway the condition was + // false even after normalization in some cases. + return (*this *= (f32)reciprocal_squareroot ( (f64)(X*X + Y*Y + Z*Z + W*W) )); +} + +// Set this quaternion to the result of the linear interpolation between two quaternions +inline quaternion& quaternion::lerp( quaternion q1, quaternion q2, f32 time) +{ + const f32 scale = 1.0f - time; + return (*this = (q1*scale) + (q2*time)); +} + +// Set this quaternion to the result of the linear interpolation between two quaternions and normalize the result +inline quaternion& quaternion::lerpN( quaternion q1, quaternion q2, f32 time) +{ + const f32 scale = 1.0f - time; + return (*this = ((q1*scale) + (q2*time)).normalize() ); +} + +// set this quaternion to the result of the interpolation between two quaternions +inline quaternion& quaternion::slerp( quaternion q1, quaternion q2, f32 time, f32 threshold) +{ + f32 angle = q1.dotProduct(q2); + + // make sure we use the short rotation + if (angle < 0.0f) + { + q1 *= -1.0f; + angle *= -1.0f; + } + + if (angle <= (1-threshold)) // spherical interpolation + { + const f32 theta = acosf(angle); + const f32 invsintheta = reciprocal(sinf(theta)); + const f32 scale = sinf(theta * (1.0f-time)) * invsintheta; + const f32 invscale = sinf(theta * time) * invsintheta; + return (*this = (q1*scale) + (q2*invscale)); + } + else // linear interpolation + return lerpN(q1,q2,time); +} + + +// calculates the dot product +inline f32 quaternion::dotProduct(const quaternion& q2) const +{ + return (X * q2.X) + (Y * q2.Y) + (Z * q2.Z) + (W * q2.W); +} + + +//! axis must be unit length, angle in radians +inline quaternion& quaternion::fromAngleAxis(f32 angle, const vector3df& axis) +{ + const f32 fHalfAngle = 0.5f*angle; + const f32 fSin = sinf(fHalfAngle); + W = cosf(fHalfAngle); + X = fSin*axis.X; + Y = fSin*axis.Y; + Z = fSin*axis.Z; + return *this; +} + + +inline void quaternion::toAngleAxis(f32 &angle, core::vector3df &axis) const +{ + const f32 scale = sqrtf(X*X + Y*Y + Z*Z); + + if (core::iszero(scale) || W > 1.0f || W < -1.0f) + { + angle = 0.0f; + axis.X = 0.0f; + axis.Y = 1.0f; + axis.Z = 0.0f; + } + else + { + const f32 invscale = reciprocal(scale); + angle = 2.0f * acosf(W); + axis.X = X * invscale; + axis.Y = Y * invscale; + axis.Z = Z * invscale; + } +} + +inline void quaternion::toEuler(vector3df& euler) const +{ + const f64 sqw = W*W; + const f64 sqx = X*X; + const f64 sqy = Y*Y; + const f64 sqz = Z*Z; + const f64 test = 2.0 * (Y*W - X*Z); + + if (core::equals(test, 1.0, 0.000001)) + { + // heading = rotation about z-axis + euler.Z = (f32) (-2.0*atan2(X, W)); + // bank = rotation about x-axis + euler.X = 0; + // attitude = rotation about y-axis + euler.Y = (f32) (core::PI64/2.0); + } + else if (core::equals(test, -1.0, 0.000001)) + { + // heading = rotation about z-axis + euler.Z = (f32) (2.0*atan2(X, W)); + // bank = rotation about x-axis + euler.X = 0; + // attitude = rotation about y-axis + euler.Y = (f32) (core::PI64/-2.0); + } + else + { + // heading = rotation about z-axis + euler.Z = (f32) atan2(2.0 * (X*Y +Z*W),(sqx - sqy - sqz + sqw)); + // bank = rotation about x-axis + euler.X = (f32) atan2(2.0 * (Y*Z +X*W),(-sqx - sqy + sqz + sqw)); + // attitude = rotation about y-axis + euler.Y = (f32) asin( clamp(test, -1.0, 1.0) ); + } +} + + +inline vector3df quaternion::operator* (const vector3df& v) const +{ + // nVidia SDK implementation + + vector3df uv, uuv; + const vector3df qvec(X, Y, Z); + uv = qvec.crossProduct(v); + uuv = qvec.crossProduct(uv); + uv *= (2.0f * W); + uuv *= 2.0f; + + return v + uv + uuv; +} + +// set quaternion to identity +inline core::quaternion& quaternion::makeIdentity() +{ + W = 1.f; + X = 0.f; + Y = 0.f; + Z = 0.f; + return *this; +} + +inline core::quaternion& quaternion::rotationFromTo(const vector3df& from, const vector3df& to) +{ + // Based on Stan Melax's article in Game Programming Gems + // Copy, since cannot modify local + vector3df v0 = from; + vector3df v1 = to; + v0.normalize(); + v1.normalize(); + + const f32 d = v0.dotProduct(v1); + if (d >= 1.0f) // If dot == 1, vectors are the same + { + return makeIdentity(); + } + else if (d <= -1.0f) // exactly opposite + { + core::vector3df axis(1.0f, 0.f, 0.f); + axis = axis.crossProduct(v0); + if (axis.getLength()==0) + { + axis.set(0.f,1.f,0.f); + axis = axis.crossProduct(v0); + } + // same as fromAngleAxis(core::PI, axis).normalize(); + return set(axis.X, axis.Y, axis.Z, 0).normalize(); + } + + const f32 s = sqrtf( (1+d)*2 ); // optimize inv_sqrt + const f32 invs = 1.f / s; + const vector3df c = v0.crossProduct(v1)*invs; + return set(c.X, c.Y, c.Z, s * 0.5f).normalize(); +} + + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/include/rect.h b/include/rect.h new file mode 100644 index 00000000..aeb9cc5f --- /dev/null +++ b/include/rect.h @@ -0,0 +1,284 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_RECT_H_INCLUDED__ +#define __IRR_RECT_H_INCLUDED__ + +#include "irrTypes.h" +#include "dimension2d.h" +#include "position2d.h" + +namespace irr +{ +namespace core +{ + + //! Rectangle template. + /** Mostly used by 2D GUI elements and for 2D drawing methods. + It has 2 positions instead of position and dimension and a fast + method for collision detection with other rectangles and points. + + Coordinates are (0,0) for top-left corner, and increasing to the right + and to the bottom. + */ + template + class rect + { + public: + + //! Default constructor creating empty rectangle at (0,0) + rect() : UpperLeftCorner(0,0), LowerRightCorner(0,0) {} + + //! Constructor with two corners + rect(T x, T y, T x2, T y2) + : UpperLeftCorner(x,y), LowerRightCorner(x2,y2) {} + + //! Constructor with two corners + rect(const position2d& upperLeft, const position2d& lowerRight) + : UpperLeftCorner(upperLeft), LowerRightCorner(lowerRight) {} + + //! Constructor with upper left corner and dimension + template + rect(const position2d& pos, const dimension2d& size) + : UpperLeftCorner(pos), LowerRightCorner(pos.X + size.Width, pos.Y + size.Height) {} + + //! Constructor with upper left at 0,0 and lower right using dimension + template + explicit rect(const dimension2d& size) + : UpperLeftCorner(0,0), LowerRightCorner(size.Width, size.Height) {} + + //! move right by given numbers + rect operator+(const position2d& pos) const + { + rect ret(*this); + return ret+=pos; + } + + //! move right by given numbers + rect& operator+=(const position2d& pos) + { + UpperLeftCorner += pos; + LowerRightCorner += pos; + return *this; + } + + //! move left by given numbers + rect operator-(const position2d& pos) const + { + rect ret(*this); + return ret-=pos; + } + + //! move left by given numbers + rect& operator-=(const position2d& pos) + { + UpperLeftCorner -= pos; + LowerRightCorner -= pos; + return *this; + } + + //! equality operator + bool operator==(const rect& other) const + { + return (UpperLeftCorner == other.UpperLeftCorner && + LowerRightCorner == other.LowerRightCorner); + } + + //! inequality operator + bool operator!=(const rect& other) const + { + return (UpperLeftCorner != other.UpperLeftCorner || + LowerRightCorner != other.LowerRightCorner); + } + + //! compares size of rectangles + bool operator<(const rect& other) const + { + return getArea() < other.getArea(); + } + + //! Returns size of rectangle + T getArea() const + { + return getWidth() * getHeight(); + } + + //! Returns if a 2d point is within this rectangle. + /** \param pos Position to test if it lies within this rectangle. + \return True if the position is within the rectangle, false if not. */ + bool isPointInside(const position2d& pos) const + { + return (UpperLeftCorner.X <= pos.X && + UpperLeftCorner.Y <= pos.Y && + LowerRightCorner.X >= pos.X && + LowerRightCorner.Y >= pos.Y); + } + + //! Check if the rectangle collides with another rectangle. + /** \param other Rectangle to test collision with + \return True if the rectangles collide. */ + bool isRectCollided(const rect& other) const + { + return (LowerRightCorner.Y > other.UpperLeftCorner.Y && + UpperLeftCorner.Y < other.LowerRightCorner.Y && + LowerRightCorner.X > other.UpperLeftCorner.X && + UpperLeftCorner.X < other.LowerRightCorner.X); + } + + //! Clips this rectangle with another one. + /** \param other Rectangle to clip with */ + void clipAgainst(const rect& other) + { + if (other.LowerRightCorner.X < LowerRightCorner.X) + LowerRightCorner.X = other.LowerRightCorner.X; + if (other.LowerRightCorner.Y < LowerRightCorner.Y) + LowerRightCorner.Y = other.LowerRightCorner.Y; + + if (other.UpperLeftCorner.X > UpperLeftCorner.X) + UpperLeftCorner.X = other.UpperLeftCorner.X; + if (other.UpperLeftCorner.Y > UpperLeftCorner.Y) + UpperLeftCorner.Y = other.UpperLeftCorner.Y; + + // correct possible invalid rect resulting from clipping + if (UpperLeftCorner.Y > LowerRightCorner.Y) + UpperLeftCorner.Y = LowerRightCorner.Y; + if (UpperLeftCorner.X > LowerRightCorner.X) + UpperLeftCorner.X = LowerRightCorner.X; + } + + //! Moves this rectangle to fit inside another one. + /** \return True on success, false if not possible */ + bool constrainTo(const rect& other) + { + if (other.getWidth() < getWidth() || other.getHeight() < getHeight()) + return false; + + T diff = other.LowerRightCorner.X - LowerRightCorner.X; + if (diff < 0) + { + LowerRightCorner.X += diff; + UpperLeftCorner.X += diff; + } + + diff = other.LowerRightCorner.Y - LowerRightCorner.Y; + if (diff < 0) + { + LowerRightCorner.Y += diff; + UpperLeftCorner.Y += diff; + } + + diff = UpperLeftCorner.X - other.UpperLeftCorner.X; + if (diff < 0) + { + UpperLeftCorner.X -= diff; + LowerRightCorner.X -= diff; + } + + diff = UpperLeftCorner.Y - other.UpperLeftCorner.Y; + if (diff < 0) + { + UpperLeftCorner.Y -= diff; + LowerRightCorner.Y -= diff; + } + + return true; + } + + //! Get width of rectangle. + T getWidth() const + { + return LowerRightCorner.X - UpperLeftCorner.X; + } + + //! Get height of rectangle. + T getHeight() const + { + return LowerRightCorner.Y - UpperLeftCorner.Y; + } + + //! If the lower right corner of the rect is smaller then the upper left, the points are swapped. + void repair() + { + if (LowerRightCorner.X < UpperLeftCorner.X) + { + T t = LowerRightCorner.X; + LowerRightCorner.X = UpperLeftCorner.X; + UpperLeftCorner.X = t; + } + + if (LowerRightCorner.Y < UpperLeftCorner.Y) + { + T t = LowerRightCorner.Y; + LowerRightCorner.Y = UpperLeftCorner.Y; + UpperLeftCorner.Y = t; + } + } + + //! Returns if the rect is valid to draw. + /** It would be invalid if the UpperLeftCorner is lower or more + right than the LowerRightCorner. */ + bool isValid() const + { + return ((LowerRightCorner.X >= UpperLeftCorner.X) && + (LowerRightCorner.Y >= UpperLeftCorner.Y)); + } + + //! Get the center of the rectangle + position2d getCenter() const + { + return position2d( + (UpperLeftCorner.X + LowerRightCorner.X) / 2, + (UpperLeftCorner.Y + LowerRightCorner.Y) / 2); + } + + //! Get the dimensions of the rectangle + dimension2d getSize() const + { + return dimension2d(getWidth(), getHeight()); + } + + + //! Adds a point to the rectangle + /** Causes the rectangle to grow bigger if point is outside of + the box + \param p Point to add to the box. */ + void addInternalPoint(const position2d& p) + { + addInternalPoint(p.X, p.Y); + } + + //! Adds a point to the bounding rectangle + /** Causes the rectangle to grow bigger if point is outside of + the box + \param x X-Coordinate of the point to add to this box. + \param y Y-Coordinate of the point to add to this box. */ + void addInternalPoint(T x, T y) + { + if (x>LowerRightCorner.X) + LowerRightCorner.X = x; + if (y>LowerRightCorner.Y) + LowerRightCorner.Y = y; + + if (x UpperLeftCorner; + //! Lower right corner + position2d LowerRightCorner; + }; + + //! Rectangle with float values + typedef rect rectf; + //! Rectangle with int values + typedef rect recti; + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/include/triangle3d.h b/include/triangle3d.h new file mode 100644 index 00000000..61d23a4b --- /dev/null +++ b/include/triangle3d.h @@ -0,0 +1,279 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_TRIANGLE_3D_H_INCLUDED__ +#define __IRR_TRIANGLE_3D_H_INCLUDED__ + +#include "vector3d.h" +#include "line3d.h" +#include "plane3d.h" +#include "aabbox3d.h" + +namespace irr +{ +namespace core +{ + + //! 3d triangle template class for doing collision detection and other things. + template + class triangle3d + { + public: + + //! Constructor for an all 0 triangle + triangle3d() {} + //! Constructor for triangle with given three vertices + triangle3d(const vector3d& v1, const vector3d& v2, const vector3d& v3) : pointA(v1), pointB(v2), pointC(v3) {} + + //! Equality operator + bool operator==(const triangle3d& other) const + { + return other.pointA==pointA && other.pointB==pointB && other.pointC==pointC; + } + + //! Inequality operator + bool operator!=(const triangle3d& other) const + { + return !(*this==other); + } + + //! Determines if the triangle is totally inside a bounding box. + /** \param box Box to check. + \return True if triangle is within the box, otherwise false. */ + bool isTotalInsideBox(const aabbox3d& box) const + { + return (box.isPointInside(pointA) && + box.isPointInside(pointB) && + box.isPointInside(pointC)); + } + + //! Determines if the triangle is totally outside a bounding box. + /** \param box Box to check. + \return True if triangle is outside the box, otherwise false. */ + bool isTotalOutsideBox(const aabbox3d& box) const + { + return ((pointA.X > box.MaxEdge.X && pointB.X > box.MaxEdge.X && pointC.X > box.MaxEdge.X) || + + (pointA.Y > box.MaxEdge.Y && pointB.Y > box.MaxEdge.Y && pointC.Y > box.MaxEdge.Y) || + (pointA.Z > box.MaxEdge.Z && pointB.Z > box.MaxEdge.Z && pointC.Z > box.MaxEdge.Z) || + (pointA.X < box.MinEdge.X && pointB.X < box.MinEdge.X && pointC.X < box.MinEdge.X) || + (pointA.Y < box.MinEdge.Y && pointB.Y < box.MinEdge.Y && pointC.Y < box.MinEdge.Y) || + (pointA.Z < box.MinEdge.Z && pointB.Z < box.MinEdge.Z && pointC.Z < box.MinEdge.Z)); + } + + //! Get the closest point on a triangle to a point on the same plane. + /** \param p Point which must be on the same plane as the triangle. + \return The closest point of the triangle */ + core::vector3d closestPointOnTriangle(const core::vector3d& p) const + { + const core::vector3d rab = line3d(pointA, pointB).getClosestPoint(p); + const core::vector3d rbc = line3d(pointB, pointC).getClosestPoint(p); + const core::vector3d rca = line3d(pointC, pointA).getClosestPoint(p); + + const T d1 = rab.getDistanceFrom(p); + const T d2 = rbc.getDistanceFrom(p); + const T d3 = rca.getDistanceFrom(p); + + if (d1 < d2) + return d1 < d3 ? rab : rca; + + return d2 < d3 ? rbc : rca; + } + + //! Check if a point is inside the triangle (border-points count also as inside) + /* + \param p Point to test. Assumes that this point is already + on the plane of the triangle. + \return True if the point is inside the triangle, otherwise false. */ + bool isPointInside(const vector3d& p) const + { + vector3d af64((f64)pointA.X, (f64)pointA.Y, (f64)pointA.Z); + vector3d bf64((f64)pointB.X, (f64)pointB.Y, (f64)pointB.Z); + vector3d cf64((f64)pointC.X, (f64)pointC.Y, (f64)pointC.Z); + vector3d pf64((f64)p.X, (f64)p.Y, (f64)p.Z); + return (isOnSameSide(pf64, af64, bf64, cf64) && + isOnSameSide(pf64, bf64, af64, cf64) && + isOnSameSide(pf64, cf64, af64, bf64)); + } + + //! Check if a point is inside the triangle (border-points count also as inside) + /** This method uses a barycentric coordinate system. + It is faster than isPointInside but is more susceptible to floating point rounding + errors. This will especially be noticeable when the FPU is in single precision mode + (which is for example set on default by Direct3D). + \param p Point to test. Assumes that this point is already + on the plane of the triangle. + \return True if point is inside the triangle, otherwise false. */ + bool isPointInsideFast(const vector3d& p) const + { + const vector3d a = pointC - pointA; + const vector3d b = pointB - pointA; + const vector3d c = p - pointA; + + const f64 dotAA = a.dotProduct( a); + const f64 dotAB = a.dotProduct( b); + const f64 dotAC = a.dotProduct( c); + const f64 dotBB = b.dotProduct( b); + const f64 dotBC = b.dotProduct( c); + + // get coordinates in barycentric coordinate system + const f64 invDenom = 1/(dotAA * dotBB - dotAB * dotAB); + const f64 u = (dotBB * dotAC - dotAB * dotBC) * invDenom; + const f64 v = (dotAA * dotBC - dotAB * dotAC ) * invDenom; + + // We count border-points as inside to keep downward compatibility. + // Rounding-error also needed for some test-cases. + return (u > -ROUNDING_ERROR_f32) && (v >= 0) && (u + v < 1+ROUNDING_ERROR_f32); + + } + + + //! Get an intersection with a 3d line. + /** \param line Line to intersect with. + \param outIntersection Place to store the intersection point, if there is one. + \return True if there was an intersection, false if not. */ + bool getIntersectionWithLimitedLine(const line3d& line, + vector3d& outIntersection) const + { + return getIntersectionWithLine(line.start, + line.getVector(), outIntersection) && + outIntersection.isBetweenPoints(line.start, line.end); + } + + + //! Get an intersection with a 3d line. + /** Please note that also points are returned as intersection which + are on the line, but not between the start and end point of the line. + If you want the returned point be between start and end + use getIntersectionWithLimitedLine(). + \param linePoint Point of the line to intersect with. + \param lineVect Vector of the line to intersect with. + \param outIntersection Place to store the intersection point, if there is one. + \return True if there was an intersection, false if there was not. */ + bool getIntersectionWithLine(const vector3d& linePoint, + const vector3d& lineVect, vector3d& outIntersection) const + { + if (getIntersectionOfPlaneWithLine(linePoint, lineVect, outIntersection)) + return isPointInside(outIntersection); + + return false; + } + + + //! Calculates the intersection between a 3d line and the plane the triangle is on. + /** \param lineVect Vector of the line to intersect with. + \param linePoint Point of the line to intersect with. + \param outIntersection Place to store the intersection point, if there is one. + \return True if there was an intersection, else false. */ + bool getIntersectionOfPlaneWithLine(const vector3d& linePoint, + const vector3d& lineVect, vector3d& outIntersection) const + { + // Work with f64 to get more precise results (makes enough difference to be worth the casts). + const vector3d linePointf64(linePoint.X, linePoint.Y, linePoint.Z); + const vector3d lineVectf64(lineVect.X, lineVect.Y, lineVect.Z); + vector3d outIntersectionf64; + + core::triangle3d trianglef64(vector3d((f64)pointA.X, (f64)pointA.Y, (f64)pointA.Z) + ,vector3d((f64)pointB.X, (f64)pointB.Y, (f64)pointB.Z) + , vector3d((f64)pointC.X, (f64)pointC.Y, (f64)pointC.Z)); + const vector3d normalf64 = trianglef64.getNormal().normalize(); + f64 t2; + + if ( core::iszero ( t2 = normalf64.dotProduct(lineVectf64) ) ) + return false; + + f64 d = trianglef64.pointA.dotProduct(normalf64); + f64 t = -(normalf64.dotProduct(linePointf64) - d) / t2; + outIntersectionf64 = linePointf64 + (lineVectf64 * t); + + outIntersection.X = (T)outIntersectionf64.X; + outIntersection.Y = (T)outIntersectionf64.Y; + outIntersection.Z = (T)outIntersectionf64.Z; + return true; + } + + + //! Get the normal of the triangle. + /** Please note: The normal is not always normalized. */ + vector3d getNormal() const + { + return (pointB - pointA).crossProduct(pointC - pointA); + } + + //! Test if the triangle would be front or backfacing from any point. + /** Thus, this method assumes a camera position from which the + triangle is definitely visible when looking at the given direction. + Do not use this method with points as it will give wrong results! + \param lookDirection Look direction. + \return True if the plane is front facing and false if it is backfacing. */ + bool isFrontFacing(const vector3d& lookDirection) const + { + const vector3d n = getNormal().normalize(); + const f32 d = (f32)n.dotProduct(lookDirection); + return F32_LOWER_EQUAL_0(d); + } + + //! Get the plane of this triangle. + plane3d getPlane() const + { + return plane3d(pointA, pointB, pointC); + } + + //! Get the area of the triangle + T getArea() const + { + return (pointB - pointA).crossProduct(pointC - pointA).getLength() * 0.5f; + + } + + //! sets the triangle's points + void set(const core::vector3d& a, const core::vector3d& b, const core::vector3d& c) + { + pointA = a; + pointB = b; + pointC = c; + } + + //! the three points of the triangle + vector3d pointA; + vector3d pointB; + vector3d pointC; + + private: + // Using f64 instead of to avoid integer overflows when T=int (maybe also less floating point troubles). + bool isOnSameSide(const vector3d& p1, const vector3d& p2, + const vector3d& a, const vector3d& b) const + { + vector3d bminusa = b - a; + vector3d cp1 = bminusa.crossProduct(p1 - a); + vector3d cp2 = bminusa.crossProduct(p2 - a); + f64 res = cp1.dotProduct(cp2); + if ( res < 0 ) + { + // This catches some floating point troubles. + // Unfortunately slightly expensive and we don't really know the best epsilon for iszero. + vector3d cp1n = bminusa.normalize().crossProduct((p1 - a).normalize()); + if (core::iszero(cp1n.X, (f64)ROUNDING_ERROR_f32) + && core::iszero(cp1n.Y, (f64)ROUNDING_ERROR_f32) + && core::iszero(cp1n.Z, (f64)ROUNDING_ERROR_f32) ) + { + res = 0.f; + } + } + return (res >= 0.0f); + } + }; + + + //! Typedef for a f32 3d triangle. + typedef triangle3d triangle3df; + + //! Typedef for an integer 3d triangle. + typedef triangle3d triangle3di; + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/include/vector2d.h b/include/vector2d.h new file mode 100644 index 00000000..2d28ce72 --- /dev/null +++ b/include/vector2d.h @@ -0,0 +1,422 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_POINT_2D_H_INCLUDED__ +#define __IRR_POINT_2D_H_INCLUDED__ + +#include "irrMath.h" +#include "dimension2d.h" + +namespace irr +{ +namespace core +{ + + +//! 2d vector template class with lots of operators and methods. +/** As of Irrlicht 1.6, this class supersedes position2d, which should + be considered deprecated. */ +template +class vector2d +{ +public: + //! Default constructor (null vector) + vector2d() : X(0), Y(0) {} + //! Constructor with two different values + vector2d(T nx, T ny) : X(nx), Y(ny) {} + //! Constructor with the same value for both members + explicit vector2d(T n) : X(n), Y(n) {} + //! 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.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 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; } + 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 vector2d& other) const { return vector2d(X / other.X, Y / other.Y); } + 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; } + + T& operator [](u32 index) + { + _IRR_DEBUG_BREAK_IF(index>1) // access violation + + return *(&X+index); + } + + const T& operator [](u32 index) const + { + _IRR_DEBUG_BREAK_IF(index>1) // access violation + + return *(&X+index); + } + + //! sort in order X, Y. Equality with rounding tolerance. + bool operator<=(const vector2d&other) const + { + return (X=(const vector2d&other) const + { + return (X>other.X || core::equals(X, other.X)) || + (core::equals(X, other.X) && (Y>other.Y || core::equals(Y, other.Y))); + } + + //! sort in order X, Y. Difference must be above rounding tolerance. + bool operator<(const vector2d&other) const + { + return (X(const vector2d&other) const + { + return (X>other.X && !core::equals(X, other.X)) || + (core::equals(X, other.X) && Y>other.Y && !core::equals(Y, other.Y)); + } + + bool operator==(const vector2d& other) const { return equals(other); } + bool operator!=(const vector2d& other) const { return !equals(other); } + + // functions + + //! Checks if this vector equals the other one. + /** Takes floating point rounding errors into account. + \param other Vector to compare with. + \param tolerance Epsilon value for both - comparing X and Y. + \return True if the two vector are (almost) equal, else false. */ + bool equals(const vector2d& other, const T tolerance = (T)ROUNDING_ERROR_f32 ) const + { + return core::equals(X, other.X, tolerance) && core::equals(Y, other.Y, tolerance); + } + + vector2d& set(T nx, T ny) {X=nx; Y=ny; return *this; } + vector2d& set(const vector2d& p) { X=p.X; Y=p.Y; return *this; } + + //! Gets the length of the vector. + /** \return The length of the vector. */ + T getLength() const { return core::squareroot( X*X + Y*Y ); } + + //! Get the squared length of this vector + /** This is useful because it is much faster than getLength(). + \return The squared length of the vector. */ + T getLengthSQ() const { return X*X + Y*Y; } + + //! Get the dot product of this vector with another. + /** \param other Other vector to take dot product with. + \return The dot product of the two vectors. */ + T dotProduct(const vector2d& other) const + { + return X*other.X + Y*other.Y; + } + + //! check if this vector is parallel to another vector + bool nearlyParallel( const vector2d & other, const T factor = relativeErrorFactor()) const + { + // https://eagergames.wordpress.com/2017/04/01/fast-parallel-lines-and-vectors-test/ + // if a || b then a.x/a.y = b.x/b.y (similiar triangles) + // if a || b then either both x are 0 or both y are 0. + + return equalsRelative( X*other.Y, other.X* Y, factor) + && // a bit counterintuitive, but makes sure that + // only y or only x are 0, and at same time deals + // with the case where one vector is zero vector. + (X*other.X + Y*other.Y) != 0; + } + + //! Gets distance from another point. + /** Here, the vector is interpreted as a point in 2-dimensional space. + \param other Other vector to measure from. + \return Distance from other point. */ + T getDistanceFrom(const vector2d& other) const + { + return vector2d(X - other.X, Y - other.Y).getLength(); + } + + //! Returns squared distance from another point. + /** Here, the vector is interpreted as a point in 2-dimensional space. + \param other Other vector to measure from. + \return Squared distance from other point. */ + T getDistanceFromSQ(const vector2d& other) const + { + return vector2d(X - other.X, Y - other.Y).getLengthSQ(); + } + + //! rotates the point anticlockwise around a center by an amount of degrees. + /** \param degrees Amount of degrees to rotate by, anticlockwise. + \param center Rotation center. + \return This vector after transformation. */ + vector2d& rotateBy(f64 degrees, const vector2d& center=vector2d()) + { + degrees *= DEGTORAD64; + const f64 cs = cos(degrees); + const f64 sn = sin(degrees); + + X -= center.X; + Y -= center.Y; + + set((T)(X*cs - Y*sn), (T)(X*sn + Y*cs)); + + X += center.X; + Y += center.Y; + return *this; + } + + //! Normalize the vector. + /** The null vector is left untouched. + \return Reference to this vector, after normalization. */ + vector2d& normalize() + { + f32 length = (f32)(X*X + Y*Y); + if ( length == 0 ) + return *this; + length = core::reciprocal_squareroot ( length ); + X = (T)(X * length); + Y = (T)(Y * length); + return *this; + } + + //! Calculates the angle of this vector in degrees in the trigonometric sense. + /** 0 is to the right (3 o'clock), values increase counter-clockwise. + This method has been suggested by Pr3t3nd3r. + \return Returns a value between 0 and 360. */ + f64 getAngleTrig() const + { + if (Y == 0) + return X < 0 ? 180 : 0; + else + if (X == 0) + return Y < 0 ? 270 : 90; + + if ( Y > 0) + if (X > 0) + return atan((irr::f64)Y/(irr::f64)X) * RADTODEG64; + else + return 180.0-atan((irr::f64)Y/-(irr::f64)X) * RADTODEG64; + else + if (X > 0) + return 360.0-atan(-(irr::f64)Y/(irr::f64)X) * RADTODEG64; + else + return 180.0+atan(-(irr::f64)Y/-(irr::f64)X) * RADTODEG64; + } + + //! Calculates the angle of this vector in degrees in the counter trigonometric sense. + /** 0 is to the right (3 o'clock), values increase clockwise. + \return Returns a value between 0 and 360. */ + inline f64 getAngle() const + { + if (Y == 0) // corrected thanks to a suggestion by Jox + return X < 0 ? 180 : 0; + else if (X == 0) + return Y < 0 ? 90 : 270; + + // don't use getLength here to avoid precision loss with s32 vectors + // avoid floating-point trouble as sqrt(y*y) is occasionally larger than y, so clamp + const f64 tmp = core::clamp(Y / sqrt((f64)(X*X + Y*Y)), -1.0, 1.0); + const f64 angle = atan( core::squareroot(1 - tmp*tmp) / tmp) * RADTODEG64; + + if (X>0 && Y>0) + return angle + 270; + else + if (X>0 && Y<0) + return angle + 90; + else + if (X<0 && Y<0) + return 90 - angle; + else + if (X<0 && Y>0) + return 270 - angle; + + return angle; + } + + //! Calculates the angle between this vector and another one in degree. + /** \param b Other vector to test with. + \return Returns a value between 0 and 90. */ + inline f64 getAngleWith(const vector2d& b) const + { + f64 tmp = (f64)(X*b.X + Y*b.Y); + + if (tmp == 0.0) + return 90.0; + + tmp = tmp / core::squareroot((f64)((X*X + Y*Y) * (b.X*b.X + b.Y*b.Y))); + if (tmp < 0.0) + tmp = -tmp; + if ( tmp > 1.0 ) // avoid floating-point trouble + tmp = 1.0; + + return atan(sqrt(1 - tmp*tmp) / tmp) * RADTODEG64; + } + + //! Returns if this vector interpreted as a point is on a line between two other points. + /** It is assumed that the point is on the line. + \param begin Beginning vector to compare between. + \param end Ending vector to compare between. + \return True if this vector is between begin and end, false if not. */ + bool isBetweenPoints(const vector2d& begin, const vector2d& end) const + { + // . end + // / + // / + // / + // . begin + // - + // - + // . this point (am I inside or outside)? + // + if (begin.X != end.X) + { + return ((begin.X <= X && X <= end.X) || + (begin.X >= X && X >= end.X)); + } + else + { + return ((begin.Y <= Y && Y <= end.Y) || + (begin.Y >= Y && Y >= end.Y)); + } + } + + //! Creates an interpolated vector between this vector and another vector. + /** \param other The other vector to interpolate with. + \param d Interpolation value between 0.0f (all the other vector) and 1.0f (all this vector). + Note that this is the opposite direction of interpolation to getInterpolated_quadratic() + \return An interpolated vector. This vector is not modified. */ + vector2d getInterpolated(const vector2d& other, f64 d) const + { + const f64 inv = 1.0f - d; + return vector2d((T)(other.X*inv + X*d), (T)(other.Y*inv + Y*d)); + } + + //! Creates a quadratically interpolated vector between this and two other vectors. + /** \param v2 Second vector to interpolate with. + \param v3 Third vector to interpolate with (maximum at 1.0f) + \param d Interpolation value between 0.0f (all this vector) and 1.0f (all the 3rd vector). + Note that this is the opposite direction of interpolation to getInterpolated() and interpolate() + \return An interpolated vector. This vector is not modified. */ + vector2d getInterpolated_quadratic(const vector2d& v2, const vector2d& v3, f64 d) const + { + // this*(1-d)*(1-d) + 2 * v2 * (1-d) + v3 * d * d; + const f64 inv = 1.0f - d; + const f64 mul0 = inv * inv; + const f64 mul1 = 2.0f * d * inv; + const f64 mul2 = d * d; + + return vector2d ( (T)(X * mul0 + v2.X * mul1 + v3.X * mul2), + (T)(Y * mul0 + v2.Y * mul1 + v3.Y * mul2)); + } + + /*! Test if this point and another 2 points taken as triplet + are colinear, clockwise, anticlockwise. This can be used also + to check winding order in triangles for 2D meshes. + \return 0 if points are colinear, 1 if clockwise, 2 if anticlockwise + */ + s32 checkOrientation( const vector2d & b, const vector2d & c) const + { + // Example of clockwise points + // + // ^ Y + // | A + // | . . + // | . . + // | C.....B + // +---------------> X + + T val = (b.Y - Y) * (c.X - b.X) - + (b.X - X) * (c.Y - b.Y); + + if (val == 0) return 0; // colinear + + return (val > 0) ? 1 : 2; // clock or counterclock wise + } + + /*! Returns true if points (a,b,c) are clockwise on the X,Y plane*/ + inline bool areClockwise( const vector2d & b, const vector2d & c) const + { + T val = (b.Y - Y) * (c.X - b.X) - + (b.X - X) * (c.Y - b.Y); + + return val > 0; + } + + /*! Returns true if points (a,b,c) are counterclockwise on the X,Y plane*/ + inline bool areCounterClockwise( const vector2d & b, const vector2d & c) const + { + T val = (b.Y - Y) * (c.X - b.X) - + (b.X - X) * (c.Y - b.Y); + + return val < 0; + } + + //! Sets this vector to the linearly interpolated vector between a and b. + /** \param a first vector to interpolate with, maximum at 1.0f + \param b second vector to interpolate with, maximum at 0.0f + \param d Interpolation value between 0.0f (all vector b) and 1.0f (all vector a) + Note that this is the opposite direction of interpolation to getInterpolated_quadratic() + */ + vector2d& interpolate( const vector2d& a, const vector2d& b, f64 d) + { + X = (T)((f64)b.X + ( ( a.X - b.X ) * d )); + Y = (T)((f64)b.Y + ( ( a.Y - b.Y ) * d )); + return *this; + } + + //! X coordinate of vector. + T X; + + //! Y coordinate of vector. + T Y; +}; + + //! Typedef for f32 2d vector. + typedef vector2d vector2df; + + //! Typedef for integer 2d vector. + typedef vector2d vector2di; + + 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 + +#endif + diff --git a/include/vector3d.h b/include/vector3d.h new file mode 100644 index 00000000..5f4f6133 --- /dev/null +++ b/include/vector3d.h @@ -0,0 +1,474 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_POINT_3D_H_INCLUDED__ +#define __IRR_POINT_3D_H_INCLUDED__ + +#include "irrMath.h" + +namespace irr +{ +namespace core +{ + + //! 3d vector template class with lots of operators and methods. + /** The vector3d class is used in Irrlicht for three main purposes: + 1) As a direction vector (most of the methods assume this). + 2) As a position in 3d space (which is synonymous with a direction vector from the origin to this position). + 3) To hold three Euler rotations, where X is pitch, Y is yaw and Z is roll. + */ + template + class vector3d + { + public: + //! Default constructor (null vector). + vector3d() : X(0), Y(0), Z(0) {} + //! Constructor with three different values + vector3d(T nx, T ny, T nz) : X(nx), Y(ny), Z(nz) {} + //! Constructor with the same value for all elements + explicit vector3d(T n) : X(n), Y(n), Z(n) {} + //! Copy constructor + vector3d(const vector3d& other) : X(other.X), Y(other.Y), Z(other.Z) {} + + // operators + + vector3d operator-() const { return vector3d(-X, -Y, -Z); } + + vector3d& operator=(const vector3d& other) { X = other.X; Y = other.Y; Z = other.Z; return *this; } + + vector3d operator+(const vector3d& other) const { return vector3d(X + other.X, Y + other.Y, Z + other.Z); } + vector3d& operator+=(const vector3d& other) { X+=other.X; Y+=other.Y; Z+=other.Z; return *this; } + vector3d operator+(const T val) const { return vector3d(X + val, Y + val, Z + val); } + vector3d& operator+=(const T val) { X+=val; Y+=val; Z+=val; return *this; } + + vector3d operator-(const vector3d& other) const { return vector3d(X - other.X, Y - other.Y, Z - other.Z); } + vector3d& operator-=(const vector3d& other) { X-=other.X; Y-=other.Y; Z-=other.Z; return *this; } + vector3d operator-(const T val) const { return vector3d(X - val, Y - val, Z - val); } + vector3d& operator-=(const T val) { X-=val; Y-=val; Z-=val; return *this; } + + vector3d operator*(const vector3d& other) const { return vector3d(X * other.X, Y * other.Y, Z * other.Z); } + vector3d& operator*=(const vector3d& other) { X*=other.X; Y*=other.Y; Z*=other.Z; return *this; } + vector3d operator*(const T v) const { return vector3d(X * v, Y * v, Z * v); } + vector3d& operator*=(const T v) { X*=v; Y*=v; Z*=v; return *this; } + + vector3d operator/(const vector3d& other) const { return vector3d(X / other.X, Y / other.Y, Z / other.Z); } + vector3d& operator/=(const vector3d& other) { X/=other.X; Y/=other.Y; Z/=other.Z; return *this; } + vector3d operator/(const T v) const { T i=(T)1.0/v; return vector3d(X * i, Y * i, Z * i); } + vector3d& operator/=(const T v) { T i=(T)1.0/v; X*=i; Y*=i; Z*=i; return *this; } + + T& operator [](u32 index) + { + _IRR_DEBUG_BREAK_IF(index>2) // access violation + + return *(&X+index); + } + + const T& operator [](u32 index) const + { + _IRR_DEBUG_BREAK_IF(index>2) // access violation + + return *(&X+index); + } + + //! sort in order X, Y, Z. Equality with rounding tolerance. + bool operator<=(const vector3d&other) const + { + return (X=(const vector3d&other) const + { + return (X>other.X || core::equals(X, other.X)) || + (core::equals(X, other.X) && (Y>other.Y || core::equals(Y, other.Y))) || + (core::equals(X, other.X) && core::equals(Y, other.Y) && (Z>other.Z || core::equals(Z, other.Z))); + } + + //! sort in order X, Y, Z. Difference must be above rounding tolerance. + bool operator<(const vector3d&other) const + { + return (X(const vector3d&other) const + { + return (X>other.X && !core::equals(X, other.X)) || + (core::equals(X, other.X) && Y>other.Y && !core::equals(Y, other.Y)) || + (core::equals(X, other.X) && core::equals(Y, other.Y) && Z>other.Z && !core::equals(Z, other.Z)); + } + + //! use weak float compare + bool operator==(const vector3d& other) const + { + return this->equals(other); + } + + bool operator!=(const vector3d& other) const + { + return !this->equals(other); + } + + // functions + + //! returns if this vector equals the other one, taking floating point rounding errors into account + bool equals(const vector3d& other, const T tolerance = (T)ROUNDING_ERROR_f32 ) const + { + return core::equals(X, other.X, tolerance) && + core::equals(Y, other.Y, tolerance) && + core::equals(Z, other.Z, tolerance); + } + + vector3d& set(const T nx, const T ny, const T nz) {X=nx; Y=ny; Z=nz; return *this;} + vector3d& set(const vector3d& p) {X=p.X; Y=p.Y; Z=p.Z;return *this;} + + //! Get length of the vector. + T getLength() const { return core::squareroot( X*X + Y*Y + Z*Z ); } + + //! Get squared length of the vector. + /** This is useful because it is much faster than getLength(). + \return Squared length of the vector. */ + T getLengthSQ() const { return X*X + Y*Y + Z*Z; } + + //! Get the dot product with another vector. + T dotProduct(const vector3d& other) const + { + return X*other.X + Y*other.Y + Z*other.Z; + } + + //! Get distance from another point. + /** Here, the vector is interpreted as point in 3 dimensional space. */ + T getDistanceFrom(const vector3d& other) const + { + return vector3d(X - other.X, Y - other.Y, Z - other.Z).getLength(); + } + + //! Returns squared distance from another point. + /** Here, the vector is interpreted as point in 3 dimensional space. */ + T getDistanceFromSQ(const vector3d& other) const + { + return vector3d(X - other.X, Y - other.Y, Z - other.Z).getLengthSQ(); + } + + //! Calculates the cross product with another vector. + /** \param p Vector to multiply with. + \return Crossproduct of this vector with p. */ + vector3d crossProduct(const vector3d& p) const + { + return vector3d(Y * p.Z - Z * p.Y, Z * p.X - X * p.Z, X * p.Y - Y * p.X); + } + + //! Returns if this vector interpreted as a point is on a line between two other points. + /** It is assumed that the point is on the line. + \param begin Beginning vector to compare between. + \param end Ending vector to compare between. + \return True if this vector is between begin and end, false if not. */ + bool isBetweenPoints(const vector3d& begin, const vector3d& end) const + { + const T f = (end - begin).getLengthSQ(); + return getDistanceFromSQ(begin) <= f && + getDistanceFromSQ(end) <= f; + } + + //! Normalizes the vector. + /** In case of the 0 vector the result is still 0, otherwise + the length of the vector will be 1. + \return Reference to this vector after normalization. */ + vector3d& normalize() + { + f64 length = X*X + Y*Y + Z*Z; + if (length == 0 ) // this check isn't an optimization but prevents getting NAN in the sqrt. + return *this; + length = core::reciprocal_squareroot(length); + + X = (T)(X * length); + Y = (T)(Y * length); + Z = (T)(Z * length); + return *this; + } + + //! Sets the length of the vector to a new value + vector3d& setLength(T newlength) + { + normalize(); + return (*this *= newlength); + } + + //! Inverts the vector. + vector3d& invert() + { + X *= -1; + Y *= -1; + Z *= -1; + return *this; + } + + //! Rotates the vector by a specified number of degrees around the Y axis and the specified center. + /** \param degrees Number of degrees to rotate around the Y axis. + \param center The center of the rotation. */ + void rotateXZBy(f64 degrees, const vector3d& center=vector3d()) + { + degrees *= DEGTORAD64; + f64 cs = cos(degrees); + f64 sn = sin(degrees); + X -= center.X; + Z -= center.Z; + set((T)(X*cs - Z*sn), Y, (T)(X*sn + Z*cs)); + X += center.X; + Z += center.Z; + } + + //! Rotates the vector by a specified number of degrees around the Z axis and the specified center. + /** \param degrees: Number of degrees to rotate around the Z axis. + \param center: The center of the rotation. */ + void rotateXYBy(f64 degrees, const vector3d& center=vector3d()) + { + degrees *= DEGTORAD64; + f64 cs = cos(degrees); + f64 sn = sin(degrees); + X -= center.X; + Y -= center.Y; + set((T)(X*cs - Y*sn), (T)(X*sn + Y*cs), Z); + X += center.X; + Y += center.Y; + } + + //! Rotates the vector by a specified number of degrees around the X axis and the specified center. + /** \param degrees: Number of degrees to rotate around the X axis. + \param center: The center of the rotation. */ + void rotateYZBy(f64 degrees, const vector3d& center=vector3d()) + { + degrees *= DEGTORAD64; + f64 cs = cos(degrees); + f64 sn = sin(degrees); + Z -= center.Z; + Y -= center.Y; + set(X, (T)(Y*cs - Z*sn), (T)(Y*sn + Z*cs)); + Z += center.Z; + Y += center.Y; + } + + //! Creates an interpolated vector between this vector and another vector. + /** \param other The other vector to interpolate with. + \param d Interpolation value between 0.0f (all the other vector) and 1.0f (all this vector). + Note that this is the opposite direction of interpolation to getInterpolated_quadratic() + \return An interpolated vector. This vector is not modified. */ + vector3d getInterpolated(const vector3d& other, f64 d) const + { + const f64 inv = 1.0 - d; + return vector3d((T)(other.X*inv + X*d), (T)(other.Y*inv + Y*d), (T)(other.Z*inv + Z*d)); + } + + //! Creates a quadratically interpolated vector between this and two other vectors. + /** \param v2 Second vector to interpolate with. + \param v3 Third vector to interpolate with (maximum at 1.0f) + \param d Interpolation value between 0.0f (all this vector) and 1.0f (all the 3rd vector). + Note that this is the opposite direction of interpolation to getInterpolated() and interpolate() + \return An interpolated vector. This vector is not modified. */ + vector3d getInterpolated_quadratic(const vector3d& v2, const vector3d& v3, f64 d) const + { + // this*(1-d)*(1-d) + 2 * v2 * (1-d) + v3 * d * d; + const f64 inv = (T) 1.0 - d; + const f64 mul0 = inv * inv; + const f64 mul1 = (T) 2.0 * d * inv; + const f64 mul2 = d * d; + + return vector3d ((T)(X * mul0 + v2.X * mul1 + v3.X * mul2), + (T)(Y * mul0 + v2.Y * mul1 + v3.Y * mul2), + (T)(Z * mul0 + v2.Z * mul1 + v3.Z * mul2)); + } + + //! Sets this vector to the linearly interpolated vector between a and b. + /** \param a first vector to interpolate with, maximum at 1.0f + \param b second vector to interpolate with, maximum at 0.0f + \param d Interpolation value between 0.0f (all vector b) and 1.0f (all vector a) + Note that this is the opposite direction of interpolation to getInterpolated_quadratic() + */ + vector3d& interpolate(const vector3d& a, const vector3d& b, f64 d) + { + X = (T)((f64)b.X + ( ( a.X - b.X ) * d )); + Y = (T)((f64)b.Y + ( ( a.Y - b.Y ) * d )); + Z = (T)((f64)b.Z + ( ( a.Z - b.Z ) * d )); + return *this; + } + + + //! Get the rotations that would make a (0,0,1) direction vector point in the same direction as this direction vector. + /** Thanks to Arras on the Irrlicht forums for this method. This utility method is very useful for + orienting scene nodes towards specific targets. For example, if this vector represents the difference + between two scene nodes, then applying the result of getHorizontalAngle() to one scene node will point + it at the other one. + Example code: + // Where target and seeker are of type ISceneNode* + const vector3df toTarget(target->getAbsolutePosition() - seeker->getAbsolutePosition()); + const vector3df requiredRotation = toTarget.getHorizontalAngle(); + seeker->setRotation(requiredRotation); + + \return A rotation vector containing the X (pitch) and Y (raw) rotations (in degrees) that when applied to a + +Z (e.g. 0, 0, 1) direction vector would make it point in the same direction as this vector. The Z (roll) rotation + is always 0, since two Euler rotations are sufficient to point in any given direction. */ + vector3d getHorizontalAngle() const + { + vector3d angle; + + // tmp avoids some precision troubles on some compilers when working with T=s32 + f64 tmp = (atan2((f64)X, (f64)Z) * RADTODEG64); + angle.Y = (T)tmp; + + if (angle.Y < 0) + angle.Y += 360; + if (angle.Y >= 360) + angle.Y -= 360; + + const f64 z1 = core::squareroot(X*X + Z*Z); + + tmp = (atan2((f64)z1, (f64)Y) * RADTODEG64 - 90.0); + angle.X = (T)tmp; + + if (angle.X < 0) + angle.X += 360; + if (angle.X >= 360) + angle.X -= 360; + + return angle; + } + + //! Get the spherical coordinate angles + /** This returns Euler degrees for the point represented by + this vector. The calculation assumes the pole at (0,1,0) and + returns the angles in X and Y. + */ + vector3d getSphericalCoordinateAngles() const + { + vector3d angle; + const f64 length = X*X + Y*Y + Z*Z; + + if (length) + { + if (X!=0) + { + angle.Y = (T)(atan2((f64)Z,(f64)X) * RADTODEG64); + } + else if (Z<0) + angle.Y=180; + + angle.X = (T)(acos(Y * core::reciprocal_squareroot(length)) * RADTODEG64); + } + return angle; + } + + //! Builds a direction vector from (this) rotation vector. + /** This vector is assumed to be a rotation vector composed of 3 Euler angle rotations, in degrees. + The implementation performs the same calculations as using a matrix to do the rotation. + + \param[in] forwards The direction representing "forwards" which will be rotated by this vector. + If you do not provide a direction, then the +Z axis (0, 0, 1) will be assumed to be forwards. + \return A direction vector calculated by rotating the forwards direction by the 3 Euler angles + (in degrees) represented by this vector. */ + vector3d rotationToDirection(const vector3d & forwards = vector3d(0, 0, 1)) const + { + const f64 cr = cos( core::DEGTORAD64 * X ); + const f64 sr = sin( core::DEGTORAD64 * X ); + const f64 cp = cos( core::DEGTORAD64 * Y ); + const f64 sp = sin( core::DEGTORAD64 * Y ); + const f64 cy = cos( core::DEGTORAD64 * Z ); + const f64 sy = sin( core::DEGTORAD64 * Z ); + + const f64 srsp = sr*sp; + const f64 crsp = cr*sp; + + const f64 pseudoMatrix[] = { + ( cp*cy ), ( cp*sy ), ( -sp ), + ( srsp*cy-cr*sy ), ( srsp*sy+cr*cy ), ( sr*cp ), + ( crsp*cy+sr*sy ), ( crsp*sy-sr*cy ), ( cr*cp )}; + + return vector3d( + (T)(forwards.X * pseudoMatrix[0] + + forwards.Y * pseudoMatrix[3] + + forwards.Z * pseudoMatrix[6]), + (T)(forwards.X * pseudoMatrix[1] + + forwards.Y * pseudoMatrix[4] + + forwards.Z * pseudoMatrix[7]), + (T)(forwards.X * pseudoMatrix[2] + + forwards.Y * pseudoMatrix[5] + + forwards.Z * pseudoMatrix[8])); + } + + //! Fills an array of 4 values with the vector data (usually floats). + /** Useful for setting in shader constants for example. The fourth value + will always be 0. */ + void getAs4Values(T* array) const + { + array[0] = X; + array[1] = Y; + array[2] = Z; + array[3] = 0; + } + + //! Fills an array of 3 values with the vector data (usually floats). + /** Useful for setting in shader constants for example.*/ + void getAs3Values(T* array) const + { + array[0] = X; + array[1] = Y; + array[2] = Z; + } + + + //! X coordinate of the vector + T X; + + //! Y coordinate of the vector + T Y; + + //! Z coordinate of the vector + T Z; + }; + + //! partial specialization for integer vectors + // Implementer note: inline keyword needed due to template specialization for s32. Otherwise put specialization into a .cpp + template <> + inline vector3d vector3d::operator /(s32 val) const {return core::vector3d(X/val,Y/val,Z/val);} + template <> + inline vector3d& vector3d::operator /=(s32 val) {X/=val;Y/=val;Z/=val; return *this;} + + template <> + inline vector3d vector3d::getSphericalCoordinateAngles() const + { + vector3d angle; + const f64 length = X*X + Y*Y + Z*Z; + + if (length) + { + if (X!=0) + { + angle.Y = round32((f32)(atan2((f64)Z,(f64)X) * RADTODEG64)); + } + else if (Z<0) + angle.Y=180; + + angle.X = round32((f32)(acos(Y * core::reciprocal_squareroot(length)) * RADTODEG64)); + } + return angle; + } + + //! Typedef for a f32 3d vector. + typedef vector3d vector3df; + + //! Typedef for an integer 3d vector. + typedef vector3d vector3di; + + //! Function multiplying a scalar and a vector component-wise. + template + vector3d operator*(const S scalar, const vector3d& vector) { return vector*scalar; } + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/lib/Linux/readme.txt b/lib/Linux/readme.txt new file mode 100644 index 00000000..40bad90a --- /dev/null +++ b/lib/Linux/readme.txt @@ -0,0 +1,2 @@ +You might have to recompile the engine to get library files in here. +Check the readme.txt in the corresponding bin folders for more information. diff --git a/lib/OSX/readme.txt b/lib/OSX/readme.txt new file mode 100644 index 00000000..40bad90a --- /dev/null +++ b/lib/OSX/readme.txt @@ -0,0 +1,2 @@ +You might have to recompile the engine to get library files in here. +Check the readme.txt in the corresponding bin folders for more information. diff --git a/lib/Win32-gcc/readme.txt b/lib/Win32-gcc/readme.txt new file mode 100644 index 00000000..40bad90a --- /dev/null +++ b/lib/Win32-gcc/readme.txt @@ -0,0 +1,2 @@ +You might have to recompile the engine to get library files in here. +Check the readme.txt in the corresponding bin folders for more information. diff --git a/lib/Win32-visualstudio/readme.txt b/lib/Win32-visualstudio/readme.txt new file mode 100644 index 00000000..40bad90a --- /dev/null +++ b/lib/Win32-visualstudio/readme.txt @@ -0,0 +1,2 @@ +You might have to recompile the engine to get library files in here. +Check the readme.txt in the corresponding bin folders for more information. diff --git a/lib/Win64-visualStudio/readme.txt b/lib/Win64-visualStudio/readme.txt new file mode 100644 index 00000000..40bad90a --- /dev/null +++ b/lib/Win64-visualStudio/readme.txt @@ -0,0 +1,2 @@ +You might have to recompile the engine to get library files in here. +Check the readme.txt in the corresponding bin folders for more information. diff --git a/media/2ddemo.png b/media/2ddemo.png new file mode 100644 index 00000000..5084114e Binary files /dev/null and b/media/2ddemo.png differ diff --git a/media/Faerie5.BMP b/media/Faerie5.BMP new file mode 100644 index 00000000..2a85c5a0 Binary files /dev/null and b/media/Faerie5.BMP differ diff --git a/media/IrrlichtTheme.ogg b/media/IrrlichtTheme.ogg new file mode 100644 index 00000000..27d028f1 Binary files /dev/null and b/media/IrrlichtTheme.ogg differ diff --git a/media/Particle.tga b/media/Particle.tga new file mode 100644 index 00000000..aec06071 Binary files /dev/null and b/media/Particle.tga differ diff --git a/media/Shaders/COGLES2DetailMap.fsh b/media/Shaders/COGLES2DetailMap.fsh new file mode 100644 index 00000000..b27b4b57 --- /dev/null +++ b/media/Shaders/COGLES2DetailMap.fsh @@ -0,0 +1,70 @@ +precision mediump float; + +/* Uniforms */ + +uniform int uTextureUsage0; +uniform int uTextureUsage1; +uniform sampler2D uTextureUnit0; +uniform sampler2D uTextureUnit1; +uniform int uFogEnable; +uniform int uFogType; +uniform vec4 uFogColor; +uniform float uFogStart; +uniform float uFogEnd; +uniform float uFogDensity; + +/* Varyings */ + +varying vec2 vTextureCoord0; +varying vec2 vTextureCoord1; +varying vec4 vVertexColor; +varying vec4 vSpecularColor; +varying float vFogCoord; + +float computeFog() +{ + const float LOG2 = 1.442695; + float FogFactor = 0.0; + + if (uFogType == 0) // Exp + { + FogFactor = exp2(-uFogDensity * vFogCoord * LOG2); + } + else if (uFogType == 1) // Linear + { + float Scale = 1.0 / (uFogEnd - uFogStart); + FogFactor = (uFogEnd - vFogCoord) * Scale; + } + else if (uFogType == 2) // Exp2 + { + FogFactor = exp2(-uFogDensity * uFogDensity * vFogCoord * vFogCoord * LOG2); + } + + FogFactor = clamp(FogFactor, 0.0, 1.0); + + return FogFactor; +} + +void main() +{ + vec4 Color0 = vec4(1.0, 1.0, 1.0, 1.0); + vec4 Color1 = vec4(1.0, 1.0, 1.0, 1.0); + + if (bool(uTextureUsage0)) + Color0 = texture2D(uTextureUnit0, vTextureCoord0); + + if (bool(uTextureUsage1)) + Color1 = texture2D(uTextureUnit1, vTextureCoord1); + + vec4 FinalColor = vec4(Color0 + (Color1 - 0.5)) * vVertexColor + vSpecularColor; + + if (bool(uFogEnable)) + { + float FogFactor = computeFog(); + vec4 FogColor = uFogColor; + FogColor.a = 1.0; + FinalColor = mix(FogColor, FinalColor, FogFactor); + } + + gl_FragColor = FinalColor; +} diff --git a/media/Shaders/COGLES2LightmapAdd.fsh b/media/Shaders/COGLES2LightmapAdd.fsh new file mode 100644 index 00000000..3bf2343a --- /dev/null +++ b/media/Shaders/COGLES2LightmapAdd.fsh @@ -0,0 +1,70 @@ +precision mediump float; + +/* Uniforms */ + +uniform int uTextureUsage0; +uniform int uTextureUsage1; +uniform sampler2D uTextureUnit0; +uniform sampler2D uTextureUnit1; +uniform int uFogEnable; +uniform int uFogType; +uniform vec4 uFogColor; +uniform float uFogStart; +uniform float uFogEnd; +uniform float uFogDensity; + +/* Varyings */ + +varying vec2 vTextureCoord0; +varying vec2 vTextureCoord1; +varying vec4 vVertexColor; +varying vec4 vSpecularColor; +varying float vFogCoord; + +float computeFog() +{ + const float LOG2 = 1.442695; + float FogFactor = 0.0; + + if (uFogType == 0) // Exp + { + FogFactor = exp2(-uFogDensity * vFogCoord * LOG2); + } + else if (uFogType == 1) // Linear + { + float Scale = 1.0 / (uFogEnd - uFogStart); + FogFactor = (uFogEnd - vFogCoord) * Scale; + } + else if (uFogType == 2) // Exp2 + { + FogFactor = exp2(-uFogDensity * uFogDensity * vFogCoord * vFogCoord * LOG2); + } + + FogFactor = clamp(FogFactor, 0.0, 1.0); + + return FogFactor; +} + +void main() +{ + vec4 Color0 = vec4(1.0, 1.0, 1.0, 1.0); + vec4 Color1 = vec4(1.0, 1.0, 1.0, 1.0); + + if (bool(uTextureUsage0)) + Color0 = texture2D(uTextureUnit0, vTextureCoord0); + + if (bool(uTextureUsage1)) + Color1 = texture2D(uTextureUnit1, vTextureCoord1); + + vec4 FinalColor = (Color0 + Color1) * vVertexColor + vSpecularColor; + + if (bool(uFogEnable)) + { + float FogFactor = computeFog(); + vec4 FogColor = uFogColor; + FogColor.a = 1.0; + FinalColor = mix(FogColor, FinalColor, FogFactor); + } + + gl_FragColor = FinalColor; +} diff --git a/media/Shaders/COGLES2LightmapModulate.fsh b/media/Shaders/COGLES2LightmapModulate.fsh new file mode 100644 index 00000000..e76c033c --- /dev/null +++ b/media/Shaders/COGLES2LightmapModulate.fsh @@ -0,0 +1,72 @@ +precision mediump float; + +/* Uniforms */ + +uniform float uModulate; +uniform int uTextureUsage0; +uniform int uTextureUsage1; +uniform sampler2D uTextureUnit0; +uniform sampler2D uTextureUnit1; +uniform int uFogEnable; +uniform int uFogType; +uniform vec4 uFogColor; +uniform float uFogStart; +uniform float uFogEnd; +uniform float uFogDensity; + +/* Varyings */ + +varying vec2 vTextureCoord0; +varying vec2 vTextureCoord1; +varying vec4 vVertexColor; +varying vec4 vSpecularColor; +varying float vFogCoord; + +float computeFog() +{ + const float LOG2 = 1.442695; + float FogFactor = 0.0; + + if (uFogType == 0) // Exp + { + FogFactor = exp2(-uFogDensity * vFogCoord * LOG2); + } + else if (uFogType == 1) // Linear + { + float Scale = 1.0 / (uFogEnd - uFogStart); + FogFactor = (uFogEnd - vFogCoord) * Scale; + } + else if (uFogType == 2) // Exp2 + { + FogFactor = exp2(-uFogDensity * uFogDensity * vFogCoord * vFogCoord * LOG2); + } + + FogFactor = clamp(FogFactor, 0.0, 1.0); + + return FogFactor; +} + +void main() +{ + vec4 Color0 = vec4(1.0, 1.0, 1.0, 1.0); + vec4 Color1 = vec4(1.0, 1.0, 1.0, 1.0); + + if (bool(uTextureUsage0)) + Color0 = texture2D(uTextureUnit0, vTextureCoord0); + + if (bool(uTextureUsage1)) + Color1 = texture2D(uTextureUnit1, vTextureCoord1); + + vec4 FinalColor = (Color0 * Color1 * uModulate) * vVertexColor; + FinalColor += vSpecularColor; + + if (bool(uFogEnable)) + { + float FogFactor = computeFog(); + vec4 FogColor = uFogColor; + FogColor.a = 1.0; + FinalColor = mix(FogColor, FinalColor, FogFactor); + } + + gl_FragColor = FinalColor; +} diff --git a/media/Shaders/COGLES2NormalMap.fsh b/media/Shaders/COGLES2NormalMap.fsh new file mode 100644 index 00000000..fb65dc36 --- /dev/null +++ b/media/Shaders/COGLES2NormalMap.fsh @@ -0,0 +1,74 @@ +#define MAX_LIGHTS 2 + +precision mediump float; + +/* Uniforms */ + +uniform sampler2D uTextureUnit0; +uniform sampler2D uTextureUnit1; +uniform int uFogEnable; +uniform int uFogType; +uniform vec4 uFogColor; +uniform float uFogStart; +uniform float uFogEnd; +uniform float uFogDensity; + +/* Varyings */ + +varying vec2 vTexCoord; +varying vec3 vLightVector[MAX_LIGHTS]; +varying vec4 vLightColor[MAX_LIGHTS]; +varying float vFogCoord; + +float computeFog() +{ + const float LOG2 = 1.442695; + float FogFactor = 0.0; + + if (uFogType == 0) // Exp + { + FogFactor = exp2(-uFogDensity * vFogCoord * LOG2); + } + else if (uFogType == 1) // Linear + { + float Scale = 1.0 / (uFogEnd - uFogStart); + FogFactor = (uFogEnd - vFogCoord) * Scale; + } + else if (uFogType == 2) // Exp2 + { + FogFactor = exp2(-uFogDensity * uFogDensity * vFogCoord * vFogCoord * LOG2); + } + + FogFactor = clamp(FogFactor, 0.0, 1.0); + + return FogFactor; +} + +void main() +{ + vec4 Color = texture2D(uTextureUnit0, vTexCoord); + vec3 Normal = texture2D(uTextureUnit1, vTexCoord).xyz * 2.0 - 1.0; + + vec4 FinalColor = vec4(0.0, 0.0, 0.0, 0.0); + + for (int i = 0; i < int(MAX_LIGHTS); i++) + { + vec3 LightVector = normalize(vLightVector[i]); + + float Lambert = max(dot(LightVector, Normal), 0.0); + FinalColor += vec4(Lambert) * vLightColor[i]; + } + + FinalColor *= Color; + FinalColor.w = vLightColor[0].w; + + if (bool(uFogEnable)) + { + float FogFactor = computeFog(); + vec4 FogColor = uFogColor; + FogColor.a = 1.0; + FinalColor = mix(FogColor, FinalColor, FogFactor); + } + + gl_FragColor = FinalColor; +} diff --git a/media/Shaders/COGLES2NormalMap.vsh b/media/Shaders/COGLES2NormalMap.vsh new file mode 100644 index 00000000..5934acfc --- /dev/null +++ b/media/Shaders/COGLES2NormalMap.vsh @@ -0,0 +1,52 @@ +#define MAX_LIGHTS 2 + +/* Attributes */ + +attribute vec3 inVertexPosition; +attribute vec3 inVertexNormal; +attribute vec3 inVertexTangent; +attribute vec3 inVertexBinormal; +attribute vec4 inVertexColor; +attribute vec2 inTexCoord0; + +/* Uniforms */ + +uniform mat4 uWVPMatrix; +uniform mat4 uWVMatrix; +uniform vec3 uLightPosition[MAX_LIGHTS]; +uniform vec4 uLightColor[MAX_LIGHTS]; + +/* Varyings */ + +varying vec2 vTexCoord; +varying vec3 vLightVector[MAX_LIGHTS]; +varying vec4 vLightColor[MAX_LIGHTS]; +varying float vFogCoord; + +void main() +{ + gl_Position = uWVPMatrix * vec4(inVertexPosition, 1.0); + + vTexCoord = inTexCoord0; + + for (int i = 0; i < int(MAX_LIGHTS); i++) + { + vec3 LightVector = uLightPosition[i] - inVertexPosition; + + vLightVector[i].x = dot(inVertexTangent, LightVector); + vLightVector[i].y = dot(inVertexBinormal, LightVector); + vLightVector[i].z = dot(inVertexNormal, LightVector); + + vLightColor[i].x = dot(LightVector, LightVector); + vLightColor[i].x *= uLightColor[i].a; + vLightColor[i] = vec4(inversesqrt(vLightColor[i].x)); + vLightColor[i] *= uLightColor[i]; + vLightColor[i].a = inVertexColor.a; + + vLightColor[i].x = clamp(vLightColor[i].x, 0.0, 1.0); + vLightColor[i].y = clamp(vLightColor[i].y, 0.0, 1.0); + vLightColor[i].z = clamp(vLightColor[i].z, 0.0, 1.0); + } + + vFogCoord = length((uWVMatrix * vec4(inVertexPosition, 1.0)).xyz); +} diff --git a/media/Shaders/COGLES2OneTextureBlend.fsh b/media/Shaders/COGLES2OneTextureBlend.fsh new file mode 100644 index 00000000..1a676c58 --- /dev/null +++ b/media/Shaders/COGLES2OneTextureBlend.fsh @@ -0,0 +1,75 @@ +precision mediump float; + +/* Uniforms */ + +uniform int uTextureUsage0; +uniform sampler2D uTextureUnit0; +uniform int uBlendType; +uniform int uFogEnable; +uniform int uFogType; +uniform vec4 uFogColor; +uniform float uFogStart; +uniform float uFogEnd; +uniform float uFogDensity; + +/* Varyings */ + +varying vec2 vTextureCoord0; +varying vec4 vVertexColor; +varying vec4 vSpecularColor; +varying float vFogCoord; + +float computeFog() +{ + const float LOG2 = 1.442695; + float FogFactor = 0.0; + + if (uFogType == 0) // Exp + { + FogFactor = exp2(-uFogDensity * vFogCoord * LOG2); + } + else if (uFogType == 1) // Linear + { + float Scale = 1.0 / (uFogEnd - uFogStart); + FogFactor = (uFogEnd - vFogCoord) * Scale; + } + else if (uFogType == 2) // Exp2 + { + FogFactor = exp2(-uFogDensity * uFogDensity * vFogCoord * vFogCoord * LOG2); + } + + FogFactor = clamp(FogFactor, 0.0, 1.0); + + return FogFactor; +} + +void main() +{ + vec4 Color0 = vVertexColor; + vec4 Color1 = vec4(1.0, 1.0, 1.0, 1.0); + + if (bool(uTextureUsage0)) + Color1 = texture2D(uTextureUnit0, vTextureCoord0); + + vec4 FinalColor = Color0 * Color1; + FinalColor += vSpecularColor; + + if (uBlendType == 1) + { + FinalColor.w = Color0.w; + } + else if (uBlendType == 2) + { + FinalColor.w = Color1.w; + } + + if (bool(uFogEnable)) + { + float FogFactor = computeFog(); + vec4 FogColor = uFogColor; + FogColor.a = 1.0; + FinalColor = mix(FogColor, FinalColor, FogFactor); + } + + gl_FragColor = FinalColor; +} diff --git a/media/Shaders/COGLES2ParallaxMap.fsh b/media/Shaders/COGLES2ParallaxMap.fsh new file mode 100644 index 00000000..311adab8 --- /dev/null +++ b/media/Shaders/COGLES2ParallaxMap.fsh @@ -0,0 +1,82 @@ +#define MAX_LIGHTS 2 + +precision mediump float; + +/* Uniforms */ + +uniform float uFactor; +uniform sampler2D uTextureUnit0; +uniform sampler2D uTextureUnit1; +uniform int uFogEnable; +uniform int uFogType; +uniform vec4 uFogColor; +uniform float uFogStart; +uniform float uFogEnd; +uniform float uFogDensity; + +/* Varyings */ + +varying vec2 vTexCoord; +varying vec3 vEyeVector; +varying vec3 vLightVector[MAX_LIGHTS]; +varying vec4 vLightColor[MAX_LIGHTS]; +varying float vFogCoord; + +float computeFog() +{ + const float LOG2 = 1.442695; + float FogFactor = 0.0; + + if (uFogType == 0) // Exp + { + FogFactor = exp2(-uFogDensity * vFogCoord * LOG2); + } + else if (uFogType == 1) // Linear + { + float Scale = 1.0 / (uFogEnd - uFogStart); + FogFactor = (uFogEnd - vFogCoord) * Scale; + } + else if (uFogType == 2) // Exp2 + { + FogFactor = exp2(-uFogDensity * uFogDensity * vFogCoord * vFogCoord * LOG2); + } + + FogFactor = clamp(FogFactor, 0.0, 1.0); + + return FogFactor; +} + +void main() +{ + vec4 TempFetch = texture2D(uTextureUnit1, vTexCoord) * 2.0 - 1.0; + TempFetch *= uFactor; + + vec3 EyeVector = normalize(vEyeVector); + vec2 TexCoord = EyeVector.xy * TempFetch.w + vTexCoord; + + vec4 Color = texture2D(uTextureUnit0, TexCoord); + vec3 Normal = texture2D(uTextureUnit1, TexCoord).xyz * 2.0 - 1.0; + + vec4 FinalColor = vec4(0.0, 0.0, 0.0, 0.0); + + for (int i = 0; i < int(MAX_LIGHTS); i++) + { + vec3 LightVector = normalize(vLightVector[i]); + + float Lambert = max(dot(LightVector, Normal), 0.0); + FinalColor += vec4(Lambert) * vLightColor[i]; + } + + FinalColor *= Color; + FinalColor.w = vLightColor[0].w; + + if (bool(uFogEnable)) + { + float FogFactor = computeFog(); + vec4 FogColor = uFogColor; + FogColor.a = 1.0; + FinalColor = mix(FogColor, FinalColor, FogFactor); + } + + gl_FragColor = FinalColor; +} diff --git a/media/Shaders/COGLES2ParallaxMap.vsh b/media/Shaders/COGLES2ParallaxMap.vsh new file mode 100644 index 00000000..97a333dc --- /dev/null +++ b/media/Shaders/COGLES2ParallaxMap.vsh @@ -0,0 +1,61 @@ +#define MAX_LIGHTS 2 + +/* Attributes */ + +attribute vec3 inVertexPosition; +attribute vec3 inVertexNormal; +attribute vec3 inVertexTangent; +attribute vec3 inVertexBinormal; +attribute vec4 inVertexColor; +attribute vec2 inTexCoord0; + +/* Uniforms */ + +uniform mat4 uWVPMatrix; +uniform mat4 uWVMatrix; +uniform vec3 uEyePosition; +uniform vec3 uLightPosition[MAX_LIGHTS]; +uniform vec4 uLightColor[MAX_LIGHTS]; + +/* Varyings */ + +varying vec2 vTexCoord; +varying vec3 vEyeVector; +varying vec3 vLightVector[MAX_LIGHTS]; +varying vec4 vLightColor[MAX_LIGHTS]; +varying float vFogCoord; + +void main() +{ + gl_Position = uWVPMatrix * vec4(inVertexPosition, 1.0); + + vTexCoord = inTexCoord0; + + vec3 EyeVector = uEyePosition - inVertexPosition; + + vEyeVector.x = dot(inVertexTangent, EyeVector); + vEyeVector.y = dot(inVertexBinormal, EyeVector); + vEyeVector.z = dot(inVertexNormal, EyeVector); + vEyeVector *= vec3(1.0, -1.0, -1.0); + + for (int i = 0; i < int(MAX_LIGHTS); i++) + { + vec3 LightVector = uLightPosition[i] - inVertexPosition; + + vLightVector[i].x = dot(inVertexTangent, LightVector); + vLightVector[i].y = dot(inVertexBinormal, LightVector); + vLightVector[i].z = dot(inVertexNormal, LightVector); + + vLightColor[i].x = dot(LightVector, LightVector); + vLightColor[i].x *= uLightColor[i].a; + vLightColor[i] = vec4(inversesqrt(vLightColor[i].x)); + vLightColor[i] *= uLightColor[i]; + vLightColor[i].a = inVertexColor.a; + + vLightColor[i].x = clamp(vLightColor[i].x, 0.0, 1.0); + vLightColor[i].y = clamp(vLightColor[i].y, 0.0, 1.0); + vLightColor[i].z = clamp(vLightColor[i].z, 0.0, 1.0); + } + + vFogCoord = length((uWVMatrix * vec4(inVertexPosition, 1.0)).xyz); +} diff --git a/media/Shaders/COGLES2Reflection2Layer.fsh b/media/Shaders/COGLES2Reflection2Layer.fsh new file mode 100644 index 00000000..7a3309c1 --- /dev/null +++ b/media/Shaders/COGLES2Reflection2Layer.fsh @@ -0,0 +1,70 @@ +precision mediump float; + +/* Uniforms */ + +uniform int uTextureUsage0; +uniform int uTextureUsage1; +uniform sampler2D uTextureUnit0; +uniform sampler2D uTextureUnit1; +uniform int uFogEnable; +uniform int uFogType; +uniform vec4 uFogColor; +uniform float uFogStart; +uniform float uFogEnd; +uniform float uFogDensity; + +/* Varyings */ + +varying vec2 vTextureCoord0; +varying vec2 vTextureCoord1; +varying vec4 vVertexColor; +varying vec4 vSpecularColor; +varying float vFogCoord; + +float computeFog() +{ + const float LOG2 = 1.442695; + float FogFactor = 0.0; + + if (uFogType == 0) // Exp + { + FogFactor = exp2(-uFogDensity * vFogCoord * LOG2); + } + else if (uFogType == 1) // Linear + { + float Scale = 1.0 / (uFogEnd - uFogStart); + FogFactor = (uFogEnd - vFogCoord) * Scale; + } + else if (uFogType == 2) // Exp2 + { + FogFactor = exp2(-uFogDensity * uFogDensity * vFogCoord * vFogCoord * LOG2); + } + + FogFactor = clamp(FogFactor, 0.0, 1.0); + + return FogFactor; +} + +void main() +{ + vec4 Color0 = vec4(1.0, 1.0, 1.0, 1.0); + vec4 Color1 = vec4(1.0, 1.0, 1.0, 1.0); + + if (bool(uTextureUsage0)) + Color0 = texture2D(uTextureUnit0, vTextureCoord0); + + if (bool(uTextureUsage1)) + Color1 = texture2D(uTextureUnit1, vTextureCoord1); + + vec4 FinalColor = (Color0 * Color1) * vVertexColor + vSpecularColor; + + if (bool(uFogEnable)) + { + float FogFactor = computeFog(); + vec4 FogColor = uFogColor; + FogColor.a = 1.0; + FinalColor = mix(FogColor, FinalColor, FogFactor); + } + + gl_FragColor = FinalColor; +} diff --git a/media/Shaders/COGLES2Reflection2Layer.vsh b/media/Shaders/COGLES2Reflection2Layer.vsh new file mode 100644 index 00000000..069fac31 --- /dev/null +++ b/media/Shaders/COGLES2Reflection2Layer.vsh @@ -0,0 +1,159 @@ +#define MAX_LIGHTS 8 + +/* Attributes */ + +attribute vec3 inVertexPosition; +attribute vec3 inVertexNormal; +attribute vec4 inVertexColor; +attribute vec2 inTexCoord0; +attribute vec2 inTexCoord1; + +/* Uniforms */ + +uniform mat4 uWVPMatrix; +uniform mat4 uWVMatrix; +uniform mat4 uNMatrix; +uniform mat4 uTMatrix0; + +uniform vec4 uGlobalAmbient; +uniform vec4 uMaterialAmbient; +uniform vec4 uMaterialDiffuse; +uniform vec4 uMaterialEmissive; +uniform vec4 uMaterialSpecular; +uniform float uMaterialShininess; + +uniform int uLightCount; +uniform int uLightType[MAX_LIGHTS]; +uniform vec3 uLightPosition[MAX_LIGHTS]; +uniform vec3 uLightDirection[MAX_LIGHTS]; +uniform vec3 uLightAttenuation[MAX_LIGHTS]; +uniform vec4 uLightAmbient[MAX_LIGHTS]; +uniform vec4 uLightDiffuse[MAX_LIGHTS]; +uniform vec4 uLightSpecular[MAX_LIGHTS]; + +uniform float uThickness; + +/* Varyings */ + +varying vec2 vTextureCoord0; +varying vec2 vTextureCoord1; +varying vec4 vVertexColor; +varying vec4 vSpecularColor; +varying float vFogCoord; + +void dirLight(in int index, in vec3 position, in vec3 normal, inout vec4 ambient, inout vec4 diffuse, inout vec4 specular) +{ + vec3 L = normalize(-(uNMatrix * vec4(uLightDirection[index], 0.0)).xyz); + + ambient += uLightAmbient[index]; + + float NdotL = dot(normal, L); + + if (NdotL > 0.0) + { + diffuse += uLightDiffuse[index] * NdotL; + + vec3 E = normalize(-position); + vec3 HalfVector = normalize(L + E); + float NdotH = max(0.0, dot(normal, HalfVector)); + + float SpecularFactor = pow(NdotH, uMaterialShininess); + specular += uLightSpecular[index] * SpecularFactor; + } +} + +void pointLight(in int index, in vec3 position, in vec3 normal, inout vec4 ambient, inout vec4 diffuse, inout vec4 specular) +{ + vec3 L = uLightPosition[index] - position; + float D = length(L); + L = normalize(L); + + float Attenuation = 1.0 / (uLightAttenuation[index].x + uLightAttenuation[index].y * D + + uLightAttenuation[index].z * D * D); + + ambient += uLightAmbient[index] * Attenuation; + + float NdotL = dot(normal, L); + + if (NdotL > 0.0) + { + diffuse += uLightDiffuse[index] * NdotL * Attenuation; + + vec3 E = normalize(-position); + vec3 HalfVector = normalize(L + E); + float NdotH = max(0.0, dot(normal, HalfVector)); + + float SpecularFactor = pow(NdotH, uMaterialShininess); + specular += uLightSpecular[index] * SpecularFactor * Attenuation; + } +} + +void spotLight(in int index, in vec3 position, in vec3 normal, inout vec4 ambient, inout vec4 diffuse, inout vec4 specular) +{ + // TO-DO +} + +void main() +{ + gl_Position = uWVPMatrix * vec4(inVertexPosition, 1.0); + gl_PointSize = uThickness; + + vec4 TextureCoord0 = vec4(inTexCoord0.x, inTexCoord0.y, 1.0, 1.0); + vTextureCoord0 = vec4(uTMatrix0 * TextureCoord0).xy; + + vec3 Position = (uWVMatrix * vec4(inVertexPosition, 1.0)).xyz; + vec3 P = normalize(Position); + vec3 N = normalize(vec4(uNMatrix * vec4(inVertexNormal, 0.0)).xyz); + vec3 R = reflect(P, N); + + float V = 2.0 * sqrt(R.x*R.x + R.y*R.y + (R.z+1.0)*(R.z+1.0)); + vTextureCoord1 = vec2(R.x/V + 0.5, R.y/V + 0.5); + + vVertexColor = inVertexColor.bgra; + vSpecularColor = vec4(0.0, 0.0, 0.0, 0.0); + + if (uLightCount > 0) + { + vec3 Normal = normalize((uNMatrix * vec4(inVertexNormal, 0.0)).xyz); + + vec4 Ambient = vec4(0.0, 0.0, 0.0, 0.0); + vec4 Diffuse = vec4(0.0, 0.0, 0.0, 0.0); + + for (int i = 0; i < int(MAX_LIGHTS); i++) + { + if( i >= uLightCount ) // can't use uniform as loop-counter directly in glsl + break; + if (uLightType[i] == 0) + pointLight(i, Position, Normal, Ambient, Diffuse, vSpecularColor); + } + + for (int i = 0; i < int(MAX_LIGHTS); i++) + { + if( i >= uLightCount ) + break; + if (uLightType[i] == 1) + spotLight(i, Position, Normal, Ambient, Diffuse, vSpecularColor); + } + + for (int i = 0; i < int(MAX_LIGHTS); i++) + { + if( i >= uLightCount ) + break; + if (uLightType[i] == 2) + dirLight(i, Position, Normal, Ambient, Diffuse, vSpecularColor); + } + + vec4 LightColor = Ambient * uMaterialAmbient + Diffuse * uMaterialDiffuse; + LightColor = clamp(LightColor, 0.0, 1.0); + LightColor.w = 1.0; + + vVertexColor *= LightColor; + vVertexColor += uMaterialEmissive; + vVertexColor += uGlobalAmbient * uMaterialAmbient; + vVertexColor = clamp(vVertexColor, 0.0, 1.0); + + vSpecularColor *= uMaterialSpecular; + } + + vFogCoord = length(Position); +} diff --git a/media/Shaders/COGLES2Renderer2D.fsh b/media/Shaders/COGLES2Renderer2D.fsh new file mode 100644 index 00000000..50f1b7da --- /dev/null +++ b/media/Shaders/COGLES2Renderer2D.fsh @@ -0,0 +1,21 @@ +precision mediump float; + +/* Uniforms */ + +uniform int uTextureUsage; +uniform sampler2D uTextureUnit; + +/* Varyings */ + +varying vec2 vTextureCoord; +varying vec4 vVertexColor; + +void main() +{ + vec4 Color = vVertexColor; + + if (bool(uTextureUsage)) + Color *= texture2D(uTextureUnit, vTextureCoord); + + gl_FragColor = Color; +} diff --git a/media/Shaders/COGLES2Renderer2D.vsh b/media/Shaders/COGLES2Renderer2D.vsh new file mode 100644 index 00000000..229d9ae9 --- /dev/null +++ b/media/Shaders/COGLES2Renderer2D.vsh @@ -0,0 +1,22 @@ +/* Attributes */ + +attribute vec4 inVertexPosition; +attribute vec4 inVertexColor; +attribute vec2 inTexCoord0; + +/* Uniforms */ + +uniform float uThickness; + +/* Varyings */ + +varying vec2 vTextureCoord; +varying vec4 vVertexColor; + +void main() +{ + gl_Position = inVertexPosition; + gl_PointSize = uThickness; + vTextureCoord = inTexCoord0; + vVertexColor = inVertexColor.bgra; +} diff --git a/media/Shaders/COGLES2Renderer2D_noTex.fsh b/media/Shaders/COGLES2Renderer2D_noTex.fsh new file mode 100644 index 00000000..5233a4b6 --- /dev/null +++ b/media/Shaders/COGLES2Renderer2D_noTex.fsh @@ -0,0 +1,9 @@ +precision mediump float; + +/* Varyings */ +varying vec4 vVertexColor; + +void main() +{ + gl_FragColor = vVertexColor; +} diff --git a/media/Shaders/COGLES2Solid.fsh b/media/Shaders/COGLES2Solid.fsh new file mode 100644 index 00000000..05f54c5b --- /dev/null +++ b/media/Shaders/COGLES2Solid.fsh @@ -0,0 +1,62 @@ +precision mediump float; + +/* Uniforms */ + +uniform int uTextureUsage0; +uniform sampler2D uTextureUnit0; +uniform int uFogEnable; +uniform int uFogType; +uniform vec4 uFogColor; +uniform float uFogStart; +uniform float uFogEnd; +uniform float uFogDensity; + +/* Varyings */ + +varying vec2 vTextureCoord0; +varying vec4 vVertexColor; +varying vec4 vSpecularColor; +varying float vFogCoord; + +float computeFog() +{ + const float LOG2 = 1.442695; + float FogFactor = 0.0; + + if (uFogType == 0) // Exp + { + FogFactor = exp2(-uFogDensity * vFogCoord * LOG2); + } + else if (uFogType == 1) // Linear + { + float Scale = 1.0 / (uFogEnd - uFogStart); + FogFactor = (uFogEnd - vFogCoord) * Scale; + } + else if (uFogType == 2) // Exp2 + { + FogFactor = exp2(-uFogDensity * uFogDensity * vFogCoord * vFogCoord * LOG2); + } + + FogFactor = clamp(FogFactor, 0.0, 1.0); + + return FogFactor; +} + +void main() +{ + vec4 Color = vVertexColor; + + if (bool(uTextureUsage0)) + Color *= texture2D(uTextureUnit0, vTextureCoord0); + Color += vSpecularColor; + + if (bool(uFogEnable)) + { + float FogFactor = computeFog(); + vec4 FogColor = uFogColor; + FogColor.a = 1.0; + Color = mix(FogColor, Color, FogFactor); + } + + gl_FragColor = Color; +} diff --git a/media/Shaders/COGLES2Solid.vsh b/media/Shaders/COGLES2Solid.vsh new file mode 100644 index 00000000..98824c48 --- /dev/null +++ b/media/Shaders/COGLES2Solid.vsh @@ -0,0 +1,151 @@ +#define MAX_LIGHTS 8 + +/* Attributes */ + +attribute vec3 inVertexPosition; +attribute vec3 inVertexNormal; +attribute vec4 inVertexColor; +attribute vec2 inTexCoord0; + +/* Uniforms */ + +uniform mat4 uWVPMatrix; +uniform mat4 uWVMatrix; +uniform mat4 uNMatrix; +uniform mat4 uTMatrix0; + +uniform vec4 uGlobalAmbient; +uniform vec4 uMaterialAmbient; +uniform vec4 uMaterialDiffuse; +uniform vec4 uMaterialEmissive; +uniform vec4 uMaterialSpecular; +uniform float uMaterialShininess; + +uniform int uLightCount; +uniform int uLightType[MAX_LIGHTS]; +uniform vec3 uLightPosition[MAX_LIGHTS]; +uniform vec3 uLightDirection[MAX_LIGHTS]; +uniform vec3 uLightAttenuation[MAX_LIGHTS]; +uniform vec4 uLightAmbient[MAX_LIGHTS]; +uniform vec4 uLightDiffuse[MAX_LIGHTS]; +uniform vec4 uLightSpecular[MAX_LIGHTS]; + +uniform float uThickness; + +/* Varyings */ + +varying vec2 vTextureCoord0; +varying vec4 vVertexColor; +varying vec4 vSpecularColor; +varying float vFogCoord; + +void dirLight(in int index, in vec3 position, in vec3 normal, inout vec4 ambient, inout vec4 diffuse, inout vec4 specular) +{ + vec3 L = normalize(-(uNMatrix * vec4(uLightDirection[index], 0.0)).xyz); + + ambient += uLightAmbient[index]; + + float NdotL = dot(normal, L); + + if (NdotL > 0.0) + { + diffuse += uLightDiffuse[index] * NdotL; + + vec3 E = normalize(-position); + vec3 HalfVector = normalize(L + E); + float NdotH = max(0.0, dot(normal, HalfVector)); + + float SpecularFactor = pow(NdotH, uMaterialShininess); + specular += uLightSpecular[index] * SpecularFactor; + } +} + +void pointLight(in int index, in vec3 position, in vec3 normal, inout vec4 ambient, inout vec4 diffuse, inout vec4 specular) +{ + vec3 L = uLightPosition[index] - position; + float D = length(L); + L = normalize(L); + + float Attenuation = 1.0 / (uLightAttenuation[index].x + uLightAttenuation[index].y * D + + uLightAttenuation[index].z * D * D); + + ambient += uLightAmbient[index] * Attenuation; + + float NdotL = dot(normal, L); + + if (NdotL > 0.0) + { + diffuse += uLightDiffuse[index] * NdotL * Attenuation; + + vec3 E = normalize(-position); + vec3 HalfVector = normalize(L + E); + float NdotH = max(0.0, dot(normal, HalfVector)); + + float SpecularFactor = pow(NdotH, uMaterialShininess); + specular += uLightSpecular[index] * SpecularFactor * Attenuation; + } +} + +void spotLight(in int index, in vec3 position, in vec3 normal, inout vec4 ambient, inout vec4 diffuse, inout vec4 specular) +{ + // TO-DO +} + +void main() +{ + gl_Position = uWVPMatrix * vec4(inVertexPosition, 1.0); + gl_PointSize = uThickness; + + vec4 TextureCoord0 = vec4(inTexCoord0.x, inTexCoord0.y, 1.0, 1.0); + vTextureCoord0 = vec4(uTMatrix0 * TextureCoord0).xy; + + vVertexColor = inVertexColor.bgra; + vSpecularColor = vec4(0.0, 0.0, 0.0, 0.0); + + vec3 Position = (uWVMatrix * vec4(inVertexPosition, 1.0)).xyz; + + if (uLightCount > 0) + { + vec3 Normal = normalize((uNMatrix * vec4(inVertexNormal, 0.0)).xyz); + + vec4 Ambient = vec4(0.0, 0.0, 0.0, 0.0); + vec4 Diffuse = vec4(0.0, 0.0, 0.0, 0.0); + + for (int i = 0; i < int(MAX_LIGHTS); i++) + { + if( i >= uLightCount ) // can't use uniform as loop-counter directly in glsl + break; + if (uLightType[i] == 0) + pointLight(i, Position, Normal, Ambient, Diffuse, vSpecularColor); + } + + for (int i = 0; i < int(MAX_LIGHTS); i++) + { + if( i >= uLightCount ) + break; + if (uLightType[i] == 1) + spotLight(i, Position, Normal, Ambient, Diffuse, vSpecularColor); + } + + for (int i = 0; i < int(MAX_LIGHTS); i++) + { + if( i >= uLightCount ) + break; + if (uLightType[i] == 2) + dirLight(i, Position, Normal, Ambient, Diffuse, vSpecularColor); + } + + vec4 LightColor = Ambient * uMaterialAmbient + Diffuse * uMaterialDiffuse; + LightColor = clamp(LightColor, 0.0, 1.0); + LightColor.w = 1.0; + + vVertexColor *= LightColor; + vVertexColor += uMaterialEmissive; + vVertexColor += uGlobalAmbient * uMaterialAmbient; + vVertexColor = clamp(vVertexColor, 0.0, 1.0); + + vSpecularColor *= uMaterialSpecular; + } + + vFogCoord = length(Position); +} diff --git a/media/Shaders/COGLES2Solid2.vsh b/media/Shaders/COGLES2Solid2.vsh new file mode 100644 index 00000000..4575d170 --- /dev/null +++ b/media/Shaders/COGLES2Solid2.vsh @@ -0,0 +1,157 @@ +#define MAX_LIGHTS 8 + +/* Attributes */ + +attribute vec3 inVertexPosition; +attribute vec3 inVertexNormal; +attribute vec4 inVertexColor; +attribute vec2 inTexCoord0; +attribute vec2 inTexCoord1; + +/* Uniforms */ + +uniform mat4 uWVPMatrix; +uniform mat4 uWVMatrix; +uniform mat4 uNMatrix; +uniform mat4 uTMatrix0; +uniform mat4 uTMatrix1; + +uniform vec4 uGlobalAmbient; +uniform vec4 uMaterialAmbient; +uniform vec4 uMaterialDiffuse; +uniform vec4 uMaterialEmissive; +uniform vec4 uMaterialSpecular; +uniform float uMaterialShininess; + +uniform int uLightCount; +uniform int uLightType[MAX_LIGHTS]; +uniform vec3 uLightPosition[MAX_LIGHTS]; +uniform vec3 uLightDirection[MAX_LIGHTS]; +uniform vec3 uLightAttenuation[MAX_LIGHTS]; +uniform vec4 uLightAmbient[MAX_LIGHTS]; +uniform vec4 uLightDiffuse[MAX_LIGHTS]; +uniform vec4 uLightSpecular[MAX_LIGHTS]; + +uniform float uThickness; + +/* Varyings */ + +varying vec2 vTextureCoord0; +varying vec2 vTextureCoord1; +varying vec4 vVertexColor; +varying vec4 vSpecularColor; +varying float vFogCoord; + +void dirLight(in int index, in vec3 position, in vec3 normal, inout vec4 ambient, inout vec4 diffuse, inout vec4 specular) +{ + vec3 L = normalize(-(uNMatrix * vec4(uLightDirection[index], 0.0)).xyz); + + ambient += uLightAmbient[index]; + + float NdotL = dot(normal, L); + + if (NdotL > 0.0) + { + diffuse += uLightDiffuse[index] * NdotL; + + vec3 E = normalize(-position); + vec3 HalfVector = normalize(L + E); + float NdotH = max(0.0, dot(normal, HalfVector)); + + float SpecularFactor = pow(NdotH, uMaterialShininess); + specular += uLightSpecular[index] * SpecularFactor; + } +} + +void pointLight(in int index, in vec3 position, in vec3 normal, inout vec4 ambient, inout vec4 diffuse, inout vec4 specular) +{ + vec3 L = uLightPosition[index] - position; + float D = length(L); + L = normalize(L); + + float Attenuation = 1.0 / (uLightAttenuation[index].x + uLightAttenuation[index].y * D + + uLightAttenuation[index].z * D * D); + + ambient += uLightAmbient[index] * Attenuation; + + float NdotL = dot(normal, L); + + if (NdotL > 0.0) + { + diffuse += uLightDiffuse[index] * NdotL * Attenuation; + + vec3 E = normalize(-position); + vec3 HalfVector = normalize(L + E); + float NdotH = max(0.0, dot(normal, HalfVector)); + + float SpecularFactor = pow(NdotH, uMaterialShininess); + specular += uLightSpecular[index] * SpecularFactor * Attenuation; + } +} + +void spotLight(in int index, in vec3 position, in vec3 normal, inout vec4 ambient, inout vec4 diffuse, inout vec4 specular) +{ + // TO-DO +} + +void main() +{ + gl_Position = uWVPMatrix * vec4(inVertexPosition, 1.0); + gl_PointSize = uThickness; + + vec4 TextureCoord0 = vec4(inTexCoord0.x, inTexCoord0.y, 1.0, 1.0); + vTextureCoord0 = vec4(uTMatrix0 * TextureCoord0).xy; + + vec4 TextureCoord1 = vec4(inTexCoord1.x, inTexCoord1.y, 1.0, 1.0); + vTextureCoord1 = vec4(uTMatrix1 * TextureCoord1).xy; + + vVertexColor = inVertexColor.bgra; + vSpecularColor = vec4(0.0, 0.0, 0.0, 0.0); + + vec3 Position = (uWVMatrix * vec4(inVertexPosition, 1.0)).xyz; + + if (uLightCount > 0) + { + vec3 Normal = normalize((uNMatrix * vec4(inVertexNormal, 0.0)).xyz); + + vec4 Ambient = vec4(0.0, 0.0, 0.0, 0.0); + vec4 Diffuse = vec4(0.0, 0.0, 0.0, 0.0); + + for (int i = 0; i < int(MAX_LIGHTS); i++) + { + if( i >= uLightCount ) // can't use uniform as loop-counter directly in glsl + break; + if (uLightType[i] == 0) + pointLight(i, Position, Normal, Ambient, Diffuse, vSpecularColor); + } + + for (int i = 0; i < int(MAX_LIGHTS); i++) + { + if( i >= uLightCount ) + break; + if (uLightType[i] == 1) + spotLight(i, Position, Normal, Ambient, Diffuse, vSpecularColor); + } + + for (int i = 0; i < int(MAX_LIGHTS); i++) + { + if( i >= uLightCount ) + break; + if (uLightType[i] == 2) + dirLight(i, Position, Normal, Ambient, Diffuse, vSpecularColor); + } + + vec4 LightColor = Ambient * uMaterialAmbient + Diffuse * uMaterialDiffuse; + LightColor = clamp(LightColor, 0.0, 1.0); + LightColor.w = 1.0; + + vVertexColor *= LightColor; + vVertexColor += uMaterialEmissive; + vVertexColor += uGlobalAmbient * uMaterialAmbient; + vVertexColor = clamp(vVertexColor, 0.0, 1.0); + + vSpecularColor *= uMaterialSpecular; + } + + vFogCoord = length(Position); +} diff --git a/media/Shaders/COGLES2Solid2Layer.fsh b/media/Shaders/COGLES2Solid2Layer.fsh new file mode 100644 index 00000000..f6a1340f --- /dev/null +++ b/media/Shaders/COGLES2Solid2Layer.fsh @@ -0,0 +1,72 @@ +precision mediump float; + +/* Uniforms */ + +uniform int uTextureUsage0; +uniform int uTextureUsage1; +uniform sampler2D uTextureUnit0; +uniform sampler2D uTextureUnit1; +uniform int uFogEnable; +uniform int uFogType; +uniform vec4 uFogColor; +uniform float uFogStart; +uniform float uFogEnd; +uniform float uFogDensity; + +/* Varyings */ + +varying vec2 vTextureCoord0; +varying vec2 vTextureCoord1; +varying vec4 vVertexColor; +varying vec4 vSpecularColor; +varying float vFogCoord; + +float computeFog() +{ + const float LOG2 = 1.442695; + float FogFactor = 0.0; + + if (uFogType == 0) // Exp + { + FogFactor = exp2(-uFogDensity * vFogCoord * LOG2); + } + else if (uFogType == 1) // Linear + { + float Scale = 1.0 / (uFogEnd - uFogStart); + FogFactor = (uFogEnd - vFogCoord) * Scale; + } + else if (uFogType == 2) // Exp2 + { + FogFactor = exp2(-uFogDensity * uFogDensity * vFogCoord * vFogCoord * LOG2); + } + + FogFactor = clamp(FogFactor, 0.0, 1.0); + + return FogFactor; +} + +void main() +{ + vec4 Color0 = vec4(1.0, 1.0, 1.0, 1.0); + vec4 Color1 = vec4(1.0, 1.0, 1.0, 1.0); + + if (bool(uTextureUsage0)) + Color0 = texture2D(uTextureUnit0, vTextureCoord0); + + if (bool(uTextureUsage1)) + Color1 = texture2D(uTextureUnit1, vTextureCoord1); + + vec4 FinalColor = (Color0 * vVertexColor.a + Color1 * (1.0 - vVertexColor.a)) * vVertexColor; + FinalColor += vSpecularColor; + + if (bool(uFogEnable)) + { + float FogFactor = computeFog(); + vec4 FogColor = uFogColor; + FogColor.a = 1.0; + FinalColor = mix(FogColor, FinalColor, FogFactor); + } + + gl_FragColor = FinalColor; + +} diff --git a/media/Shaders/COGLES2SphereMap.fsh b/media/Shaders/COGLES2SphereMap.fsh new file mode 100644 index 00000000..05f54c5b --- /dev/null +++ b/media/Shaders/COGLES2SphereMap.fsh @@ -0,0 +1,62 @@ +precision mediump float; + +/* Uniforms */ + +uniform int uTextureUsage0; +uniform sampler2D uTextureUnit0; +uniform int uFogEnable; +uniform int uFogType; +uniform vec4 uFogColor; +uniform float uFogStart; +uniform float uFogEnd; +uniform float uFogDensity; + +/* Varyings */ + +varying vec2 vTextureCoord0; +varying vec4 vVertexColor; +varying vec4 vSpecularColor; +varying float vFogCoord; + +float computeFog() +{ + const float LOG2 = 1.442695; + float FogFactor = 0.0; + + if (uFogType == 0) // Exp + { + FogFactor = exp2(-uFogDensity * vFogCoord * LOG2); + } + else if (uFogType == 1) // Linear + { + float Scale = 1.0 / (uFogEnd - uFogStart); + FogFactor = (uFogEnd - vFogCoord) * Scale; + } + else if (uFogType == 2) // Exp2 + { + FogFactor = exp2(-uFogDensity * uFogDensity * vFogCoord * vFogCoord * LOG2); + } + + FogFactor = clamp(FogFactor, 0.0, 1.0); + + return FogFactor; +} + +void main() +{ + vec4 Color = vVertexColor; + + if (bool(uTextureUsage0)) + Color *= texture2D(uTextureUnit0, vTextureCoord0); + Color += vSpecularColor; + + if (bool(uFogEnable)) + { + float FogFactor = computeFog(); + vec4 FogColor = uFogColor; + FogColor.a = 1.0; + Color = mix(FogColor, Color, FogFactor); + } + + gl_FragColor = Color; +} diff --git a/media/Shaders/COGLES2SphereMap.vsh b/media/Shaders/COGLES2SphereMap.vsh new file mode 100644 index 00000000..a178bb6d --- /dev/null +++ b/media/Shaders/COGLES2SphereMap.vsh @@ -0,0 +1,154 @@ +#define MAX_LIGHTS 8 + +/* Attributes */ + +attribute vec3 inVertexPosition; +attribute vec3 inVertexNormal; +attribute vec4 inVertexColor; +attribute vec2 inTexCoord0; +attribute vec2 inTexCoord1; + +/* Uniforms */ + +uniform mat4 uWVPMatrix; +uniform mat4 uWVMatrix; +uniform mat4 uNMatrix; + +uniform vec4 uGlobalAmbient; +uniform vec4 uMaterialAmbient; +uniform vec4 uMaterialDiffuse; +uniform vec4 uMaterialEmissive; +uniform vec4 uMaterialSpecular; +uniform float uMaterialShininess; + +uniform int uLightCount; +uniform int uLightType[MAX_LIGHTS]; +uniform vec3 uLightPosition[MAX_LIGHTS]; +uniform vec3 uLightDirection[MAX_LIGHTS]; +uniform vec3 uLightAttenuation[MAX_LIGHTS]; +uniform vec4 uLightAmbient[MAX_LIGHTS]; +uniform vec4 uLightDiffuse[MAX_LIGHTS]; +uniform vec4 uLightSpecular[MAX_LIGHTS]; + +uniform float uThickness; + +/* Varyings */ + +varying vec2 vTextureCoord0; +varying vec4 vVertexColor; +varying vec4 vSpecularColor; +varying float vFogCoord; + +void dirLight(in int index, in vec3 position, in vec3 normal, inout vec4 ambient, inout vec4 diffuse, inout vec4 specular) +{ + vec3 L = normalize(-(uNMatrix * vec4(uLightDirection[index], 0.0)).xyz); + + ambient += uLightAmbient[index]; + + float NdotL = dot(normal, L); + + if (NdotL > 0.0) + { + diffuse += uLightDiffuse[index] * NdotL; + + vec3 E = normalize(-position); + vec3 HalfVector = normalize(L + E); + float NdotH = max(0.0, dot(normal, HalfVector)); + + float SpecularFactor = pow(NdotH, uMaterialShininess); + specular += uLightSpecular[index] * SpecularFactor; + } +} + +void pointLight(in int index, in vec3 position, in vec3 normal, inout vec4 ambient, inout vec4 diffuse, inout vec4 specular) +{ + vec3 L = uLightPosition[index] - position; + float D = length(L); + L = normalize(L); + + float Attenuation = 1.0 / (uLightAttenuation[index].x + uLightAttenuation[index].y * D + + uLightAttenuation[index].z * D * D); + + ambient += uLightAmbient[index] * Attenuation; + + float NdotL = dot(normal, L); + + if (NdotL > 0.0) + { + diffuse += uLightDiffuse[index] * NdotL * Attenuation; + + vec3 E = normalize(-position); + vec3 HalfVector = normalize(L + E); + float NdotH = max(0.0, dot(normal, HalfVector)); + + float SpecularFactor = pow(NdotH, uMaterialShininess); + specular += uLightSpecular[index] * SpecularFactor * Attenuation; + } +} + +void spotLight(in int index, in vec3 position, in vec3 normal, inout vec4 ambient, inout vec4 diffuse, inout vec4 specular) +{ + // TO-DO +} + +void main() +{ + gl_Position = uWVPMatrix * vec4(inVertexPosition, 1.0); + gl_PointSize = uThickness; + + vec3 Position = (uWVMatrix * vec4(inVertexPosition, 1.0)).xyz; + vec3 P = normalize(Position); + vec3 N = normalize(vec4(uNMatrix * vec4(inVertexNormal, 0.0)).xyz); + vec3 R = reflect(P, N); + + float V = 2.0 * sqrt(R.x*R.x + R.y*R.y + (R.z+1.0)*(R.z+1.0)); + vTextureCoord0 = vec2(R.x/V + 0.5, R.y/V + 0.5); + + vVertexColor = inVertexColor.bgra; + vSpecularColor = vec4(0.0, 0.0, 0.0, 0.0); + + if (uLightCount > 0) + { + vec3 Normal = normalize((uNMatrix * vec4(inVertexNormal, 0.0)).xyz); + + vec4 Ambient = vec4(0.0, 0.0, 0.0, 0.0); + vec4 Diffuse = vec4(0.0, 0.0, 0.0, 0.0); + + for (int i = 0; i < int(MAX_LIGHTS); i++) + { + if( i >= uLightCount ) // can't use uniform as loop-counter directly in glsl + break; + if (uLightType[i] == 0) + pointLight(i, Position, Normal, Ambient, Diffuse, vSpecularColor); + } + + for (int i = 0; i < int(MAX_LIGHTS); i++) + { + if( i >= uLightCount ) + break; + if (uLightType[i] == 1) + spotLight(i, Position, Normal, Ambient, Diffuse, vSpecularColor); + } + + for (int i = 0; i < int(MAX_LIGHTS); i++) + { + if( i >= uLightCount ) + break; + if (uLightType[i] == 2) + dirLight(i, Position, Normal, Ambient, Diffuse, vSpecularColor); + } + + vec4 LightColor = Ambient * uMaterialAmbient + Diffuse * uMaterialDiffuse; + LightColor = clamp(LightColor, 0.0, 1.0); + LightColor.w = 1.0; + + vVertexColor *= LightColor; + vVertexColor += uMaterialEmissive; + vVertexColor += uGlobalAmbient * uMaterialAmbient; + vVertexColor = clamp(vVertexColor, 0.0, 1.0); + + vSpecularColor *= uMaterialSpecular; + } + + vFogCoord = length(Position); +} diff --git a/media/Shaders/COGLES2TransparentAlphaChannel.fsh b/media/Shaders/COGLES2TransparentAlphaChannel.fsh new file mode 100644 index 00000000..2a4f91f8 --- /dev/null +++ b/media/Shaders/COGLES2TransparentAlphaChannel.fsh @@ -0,0 +1,69 @@ +precision mediump float; + +/* Uniforms */ + +uniform float uAlphaRef; +uniform int uTextureUsage0; +uniform sampler2D uTextureUnit0; +uniform int uFogEnable; +uniform int uFogType; +uniform vec4 uFogColor; +uniform float uFogStart; +uniform float uFogEnd; +uniform float uFogDensity; + +/* Varyings */ + +varying vec2 vTextureCoord0; +varying vec4 vVertexColor; +varying vec4 vSpecularColor; +varying float vFogCoord; + +float computeFog() +{ + const float LOG2 = 1.442695; + float FogFactor = 0.0; + + if (uFogType == 0) // Exp + { + FogFactor = exp2(-uFogDensity * vFogCoord * LOG2); + } + else if (uFogType == 1) // Linear + { + float Scale = 1.0 / (uFogEnd - uFogStart); + FogFactor = (uFogEnd - vFogCoord) * Scale; + } + else if (uFogType == 2) // Exp2 + { + FogFactor = exp2(-uFogDensity * uFogDensity * vFogCoord * vFogCoord * LOG2); + } + + FogFactor = clamp(FogFactor, 0.0, 1.0); + + return FogFactor; +} + +void main() +{ + vec4 Color = vVertexColor; + + if (bool(uTextureUsage0)) + { + Color *= texture2D(uTextureUnit0, vTextureCoord0); + + // TODO: uAlphaRef should rather control sharpness of alpha, don't know how to do that right now and this works in most cases. + if (Color.a < uAlphaRef) + discard; + } + Color += vSpecularColor; + + if (bool(uFogEnable)) + { + float FogFactor = computeFog(); + vec4 FogColor = uFogColor; + FogColor.a = 1.0; + Color = mix(FogColor, Color, FogFactor); + } + + gl_FragColor = Color; +} diff --git a/media/Shaders/COGLES2TransparentAlphaChannelRef.fsh b/media/Shaders/COGLES2TransparentAlphaChannelRef.fsh new file mode 100644 index 00000000..fbb1ff9d --- /dev/null +++ b/media/Shaders/COGLES2TransparentAlphaChannelRef.fsh @@ -0,0 +1,67 @@ +precision mediump float; + +/* Uniforms */ + +uniform float uAlphaRef; +uniform int uTextureUsage0; +uniform sampler2D uTextureUnit0; +uniform int uFogEnable; +uniform int uFogType; +uniform vec4 uFogColor; +uniform float uFogStart; +uniform float uFogEnd; +uniform float uFogDensity; + +/* Varyings */ + +varying vec2 vTextureCoord0; +varying vec4 vVertexColor; +varying vec4 vSpecularColor; +varying float vFogCoord; + +float computeFog() +{ + const float LOG2 = 1.442695; + float FogFactor = 0.0; + + if (uFogType == 0) // Exp + { + FogFactor = exp2(-uFogDensity * vFogCoord * LOG2); + } + else if (uFogType == 1) // Linear + { + float Scale = 1.0 / (uFogEnd - uFogStart); + FogFactor = (uFogEnd - vFogCoord) * Scale; + } + else if (uFogType == 2) // Exp2 + { + FogFactor = exp2(-uFogDensity * uFogDensity * vFogCoord * vFogCoord * LOG2); + } + + FogFactor = clamp(FogFactor, 0.0, 1.0); + + return FogFactor; +} + +void main() +{ + vec4 Color = vVertexColor; + + if (bool(uTextureUsage0)) + Color *= texture2D(uTextureUnit0, vTextureCoord0); + + if (Color.a < uAlphaRef) + discard; + + Color += vSpecularColor; + + if (bool(uFogEnable)) + { + float FogFactor = computeFog(); + vec4 FogColor = uFogColor; + FogColor.a = 1.0; + Color = mix(FogColor, Color, FogFactor); + } + + gl_FragColor = Color; +} diff --git a/media/Shaders/COGLES2TransparentVertexAlpha.fsh b/media/Shaders/COGLES2TransparentVertexAlpha.fsh new file mode 100644 index 00000000..05f54c5b --- /dev/null +++ b/media/Shaders/COGLES2TransparentVertexAlpha.fsh @@ -0,0 +1,62 @@ +precision mediump float; + +/* Uniforms */ + +uniform int uTextureUsage0; +uniform sampler2D uTextureUnit0; +uniform int uFogEnable; +uniform int uFogType; +uniform vec4 uFogColor; +uniform float uFogStart; +uniform float uFogEnd; +uniform float uFogDensity; + +/* Varyings */ + +varying vec2 vTextureCoord0; +varying vec4 vVertexColor; +varying vec4 vSpecularColor; +varying float vFogCoord; + +float computeFog() +{ + const float LOG2 = 1.442695; + float FogFactor = 0.0; + + if (uFogType == 0) // Exp + { + FogFactor = exp2(-uFogDensity * vFogCoord * LOG2); + } + else if (uFogType == 1) // Linear + { + float Scale = 1.0 / (uFogEnd - uFogStart); + FogFactor = (uFogEnd - vFogCoord) * Scale; + } + else if (uFogType == 2) // Exp2 + { + FogFactor = exp2(-uFogDensity * uFogDensity * vFogCoord * vFogCoord * LOG2); + } + + FogFactor = clamp(FogFactor, 0.0, 1.0); + + return FogFactor; +} + +void main() +{ + vec4 Color = vVertexColor; + + if (bool(uTextureUsage0)) + Color *= texture2D(uTextureUnit0, vTextureCoord0); + Color += vSpecularColor; + + if (bool(uFogEnable)) + { + float FogFactor = computeFog(); + vec4 FogColor = uFogColor; + FogColor.a = 1.0; + Color = mix(FogColor, Color, FogFactor); + } + + gl_FragColor = Color; +} diff --git a/media/axe.jpg b/media/axe.jpg new file mode 100644 index 00000000..2222cc95 Binary files /dev/null and b/media/axe.jpg differ diff --git a/media/ball.wav b/media/ball.wav new file mode 100644 index 00000000..24094eee Binary files /dev/null and b/media/ball.wav differ diff --git a/media/bigfont.png b/media/bigfont.png new file mode 100644 index 00000000..ca8d948c Binary files /dev/null and b/media/bigfont.png differ diff --git a/media/burninglogo.png b/media/burninglogo.png new file mode 100644 index 00000000..19cf8b39 Binary files /dev/null and b/media/burninglogo.png differ diff --git a/media/config.xml b/media/config.xml new file mode 100644 index 00000000..d8ff5e0d --- /dev/null +++ b/media/config.xml @@ -0,0 +1,29 @@ + + + + +Welcome to the Mesh Viewer of the "Irrlicht Engine"!. +This program is able to load and display all 3D geometry and models the Irrlicht Engine can. +Controls: Left mouse to rotate, right mouse to move, both buttons to zoom. Escape to Stop FPS Camera + +Supported formats are: +- Irrlicht scene and mesh formats (.irr, .irrmesh, .xml) +- 3D Studio (.3ds) +- Blitz3D (.b3d) +- COLLADA 1.2/1.3 (.dae, .xml) +- Cartography shop 4 (.csm) +- DirectX (.x) +- DeleD (.dmf) +- Maya (.obj) +- Milkshape (.ms3d) +- My3D (.my3D) +- OCT (.oct) +- Ogre3d (.mesh) +- Pulsar LMTools (.lmts) +- Quake 3 levels (.bsp) +- Quake 2 models (.md2) +- Stanford Triangle (.ply) +- Stereolithography format (.stl) + + + diff --git a/media/cubeMapReflection.frag b/media/cubeMapReflection.frag new file mode 100644 index 00000000..f1a4a1fc --- /dev/null +++ b/media/cubeMapReflection.frag @@ -0,0 +1,12 @@ +uniform samplerCube cubeTex; +uniform float Roughness; + +void main( void ) +{ +// gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + vec3 uvw = vec3(gl_TexCoord[0]); + //gl_FragColor = textureCube( cubeTex, uvw ); + gl_FragColor = textureLod( cubeTex, uvw, Roughness ); + //gl_FragColor = textureCube( cubeTex, uvw, Roughness ); +} + diff --git a/media/cubeMapReflection.vert b/media/cubeMapReflection.vert new file mode 100644 index 00000000..97f9ac5b --- /dev/null +++ b/media/cubeMapReflection.vert @@ -0,0 +1,27 @@ +uniform int StyleUVW ; // 0 = specular reflection, 1 = diffuse reflection, 2 = use model vertex coordinates for uvw. +uniform vec3 CameraPos; +uniform mat4 World; + +void main(void) +{ + gl_Position = ftransform(); // same as gl_ModelViewProjectionMatrix * gl_Vertex; + + // compute the reflection vector, and assign it to texcoord 0 + if ( StyleUVW == 0 ) + { + vec4 worldPos = World*gl_Vertex; + vec3 viewNormal = normalize(worldPos.xyz - CameraPos); // view vector + + gl_TexCoord[0] = vec4( reflect( viewNormal, normalize(gl_Normal) ), 1.0 ); + } + else if ( StyleUVW == 1 ) + { + // just use the normal for the reflection vector + gl_TexCoord[0] = vec4(normalize(gl_Normal), 1.0); + } + else if ( StyleUVW == 2 ) + { + // use vertex-coordinates for texture coordinates + gl_TexCoord[0] = normalize(gl_Vertex); + } +} diff --git a/media/cubeMapReflectionPS.hlsl b/media/cubeMapReflectionPS.hlsl new file mode 100644 index 00000000..179979dc --- /dev/null +++ b/media/cubeMapReflectionPS.hlsl @@ -0,0 +1,10 @@ +sampler cubeTex: register(s0); +float Roughness; + +float4 PS( float4 uvwTex : TEXCOORD0 ) : COLOR +{ + uvwTex.w = Roughness; + //return texCUBEbias( cubeTex, uvwTex); + return texCUBElod( cubeTex, uvwTex); + //return texCUBE( cubeTex, uvwTex); +} diff --git a/media/cubeMapReflectionVS.hlsl b/media/cubeMapReflectionVS.hlsl new file mode 100644 index 00000000..64033060 --- /dev/null +++ b/media/cubeMapReflectionVS.hlsl @@ -0,0 +1,38 @@ +int StyleUVW ; // 0 = specular reflection, 1 = diffuse reflection, 2 = use model vertex coordinates for uvw. +float4x4 WorldViewProj; +float4x4 World; +float3 CameraPos; + +// Vertex Shader +void VS( + in float4 VPos : POSITION, + in float3 VNorm : NORMAL, + in float3 VTex : TEXCOORD0, + out float4 outPos : POSITION, + out float4 outTex : TEXCOORD0 ) +{ + // vertex position from model-space to view-space + outPos = mul( VPos, WorldViewProj ); + + if ( StyleUVW == 0 ) + { + // create ray from camera position to the vertex, in world space + float4 worldPos = mul(float4(VPos.x, VPos.y, VPos.z, 1.0), World); + float3 view = CameraPos - worldPos.xyz; + + float4 normWorld = normalize(mul(float4(VNorm.x, VNorm.y, VNorm.z, 0.0), World)); // TODO: when objects are scaled non-uniform we need to multiply by WorldInverseTranspose instead + + // compute the reflection vector, and assign it to texcoord 0 + outTex.xyz = reflect( -normalize(view), normWorld.xyz ); + } + else if ( StyleUVW == 1 ) + { + // just use the normal for the reflection vector + outTex.xyz = normalize(VNorm); + } + else if ( StyleUVW == 2 ) + { + // use vertex-coordinates for texture coordinates + outTex.xyz = VPos.xyz; + } +} diff --git a/media/cubemap_license.txt b/media/cubemap_license.txt new file mode 100644 index 00000000..2bfb4a5a --- /dev/null +++ b/media/cubemap_license.txt @@ -0,0 +1,18 @@ +License for the cubemap_*.jpg files in this folder. + +Author +====== + +This is the work of Emil Persson, aka Humus. +http://www.humus.name + +License +======= + +This work is licensed under a Creative Commons Attribution 3.0 Unported License. +http://creativecommons.org/licenses/by/3.0/ + + +Changes +======= +For the Irrlicht engine we downscaled the images to 512x512. Get the full 2048x2048 resolution at http://www.humus.name diff --git a/media/cubemap_negx.jpg b/media/cubemap_negx.jpg new file mode 100644 index 00000000..abb77ce1 Binary files /dev/null and b/media/cubemap_negx.jpg differ diff --git a/media/cubemap_negy.jpg b/media/cubemap_negy.jpg new file mode 100644 index 00000000..740c536d Binary files /dev/null and b/media/cubemap_negy.jpg differ diff --git a/media/cubemap_negz.jpg b/media/cubemap_negz.jpg new file mode 100644 index 00000000..057d3f1e Binary files /dev/null and b/media/cubemap_negz.jpg differ diff --git a/media/cubemap_posx.jpg b/media/cubemap_posx.jpg new file mode 100644 index 00000000..6c32969b Binary files /dev/null and b/media/cubemap_posx.jpg differ diff --git a/media/cubemap_posy.jpg b/media/cubemap_posy.jpg new file mode 100644 index 00000000..e343c3fa Binary files /dev/null and b/media/cubemap_posy.jpg differ diff --git a/media/cubemap_posz.jpg b/media/cubemap_posz.jpg new file mode 100644 index 00000000..2d28e44e Binary files /dev/null and b/media/cubemap_posz.jpg differ diff --git a/media/d3d9.hlsl b/media/d3d9.hlsl new file mode 100644 index 00000000..07809e5f --- /dev/null +++ b/media/d3d9.hlsl @@ -0,0 +1,84 @@ +// Part of the Irrlicht Engine Shader example. +// These simple Direct3D9 pixel and vertex shaders will be loaded by the shaders +// example. Please note that these example shaders don't do anything really useful. +// They only demonstrate that shaders can be used in Irrlicht. + +//----------------------------------------------------------------------------- +// Global variables +//----------------------------------------------------------------------------- +float4x4 mWorldViewProj; // World * View * Projection transformation +float4x4 mInvWorld; // Inverted world matrix +float4x4 mTransWorld; // Transposed world matrix +float3 mLightPos; // Light position (actually just camera-pos in this case) +float4 mLightColor; // Light color + + +// Vertex shader output structure +struct VS_OUTPUT +{ + float4 Position : POSITION; // vertex position + float4 Diffuse : COLOR0; // vertex diffuse color + float2 TexCoord : TEXCOORD0; // tex coords +}; + + +VS_OUTPUT vertexMain(in float4 vPosition : POSITION, + in float3 vNormal : NORMAL, + float2 texCoord : TEXCOORD0 ) +{ + VS_OUTPUT Output; + + // transform position to clip space + Output.Position = mul(vPosition, mWorldViewProj); + + // transform normal somehow (NOTE: for the real vertex normal you would use an inverse-transpose world matrix instead of mInvWorld) + float3 normal = mul(float4(vNormal,0.0), mInvWorld); + + // renormalize normal + normal = normalize(normal); + + // position in world coordinates (NOTE: not sure why transposed world is used instead of world?) + float3 worldpos = mul(mTransWorld, vPosition); + + // calculate light vector, vtxpos - lightpos + float3 lightVector = worldpos - mLightPos; + + // normalize light vector + lightVector = normalize(lightVector); + + // calculate light color + float3 tmp = dot(-lightVector, normal); + tmp = lit(tmp.x, tmp.y, 1.0); + + tmp = mLightColor * tmp.y; + Output.Diffuse = float4(tmp.x, tmp.y, tmp.z, 0); + Output.TexCoord = texCoord; + + return Output; +} + + +// Pixel shader output structure +struct PS_OUTPUT +{ + float4 RGBColor : COLOR0; // Pixel color +}; + + +sampler2D myTexture; + +PS_OUTPUT pixelMain(float2 TexCoord : TEXCOORD0, + float4 Position : POSITION, + float4 Diffuse : COLOR0 ) +{ + PS_OUTPUT Output; + + float4 col = tex2D( myTexture, TexCoord ); // sample color map + + // multiply with diffuse and do other senseless operations + Output.RGBColor = Diffuse * col; + Output.RGBColor *= 4.0; + + return Output; +} + diff --git a/media/d3d9.psh b/media/d3d9.psh new file mode 100644 index 00000000..8286eb86 --- /dev/null +++ b/media/d3d9.psh @@ -0,0 +1,11 @@ +; part of the Irrlicht Engine Shader example. +; This simple Direct3D9 pixel shader will be loaded by the engine. +; Please note that these example shaders don't do anything really useful. +; They only demonstrate that shaders can be used in Irrlicht. + +ps.1.1 + +tex t0 ; sample color map +add r0, v0, v0 ; mulitply with color +mul t0, t0, r0 ; mulitply with color +add r0, t0, t0 ; make it brighter and store result diff --git a/media/d3d9.vsh b/media/d3d9.vsh new file mode 100644 index 00000000..0d1dfe9f --- /dev/null +++ b/media/d3d9.vsh @@ -0,0 +1,42 @@ +; part of the Irrlicht Engine Shader example. +; This Direct3D9 vertex shader will be loaded by the engine. +; Please note that these example shaders don't do anything really useful. +; They only demonstrate that shaders can be used in Irrlicht. + +vs.1.1 + +dcl_position v0; ; declare position +dcl_normal v1; ; declare normal +dcl_color v2; ; declare color +dcl_texcoord0 v3; ; declare texture coordinate + +; transpose and transform position to clip space +mul r0, v0.x, c4 +mad r0, v0.y, c5, r0 +mad r0, v0.z, c6, r0 +add oPos, c7, r0 + +; transform normal +dp3 r1.x, v1, c0 +dp3 r1.y, v1, c1 +dp3 r1.z, v1, c2 + +; renormalize normal +dp3 r1.w, r1, r1 +rsq r1.w, r1.w +mul r1, r1, r1.w + +; calculate light vector +m4x4 r6, v0, c10 ; vertex into world position +add r2, c8, -r6 ; vtxpos - lightpos + +; normalize light vector +dp3 r2.w, r2, r2 +rsq r2.w, r2.w +mul r2, r2, r2.w + +; calculate light color +dp3 r3, r1, r2 ; dp3 with negative light vector +lit r5, r3 ; clamp to zero if r3 < 0, r5 has diffuce component in r5.y +mul oD0, r5.y, c9 ; ouput diffuse color +mov oT0, v3 ; store texture coordinates \ No newline at end of file diff --git a/media/demoback.jpg b/media/demoback.jpg new file mode 100644 index 00000000..dec609cc Binary files /dev/null and b/media/demoback.jpg differ diff --git a/media/detailmap3.jpg b/media/detailmap3.jpg new file mode 100644 index 00000000..acf5f41d Binary files /dev/null and b/media/detailmap3.jpg differ diff --git a/media/directxlogo.png b/media/directxlogo.png new file mode 100644 index 00000000..db5eff70 Binary files /dev/null and b/media/directxlogo.png differ diff --git a/media/dotnetback.jpg b/media/dotnetback.jpg new file mode 100644 index 00000000..9ac13cff Binary files /dev/null and b/media/dotnetback.jpg differ diff --git a/media/dwarf-Read-Me.txt b/media/dwarf-Read-Me.txt new file mode 100644 index 00000000..ad158375 --- /dev/null +++ b/media/dwarf-Read-Me.txt @@ -0,0 +1,51 @@ +Dwarf lowpoly model Pack +Copyright 2004, Psionic Design +e-mail: psionic@blueyonder.co.uk + + + +INSTALLATION INSTRUCTIONS: + +To install, simply unzip to your hard drive with the "Use Folder Names" option turned on. And that's it you're ready to go! + + + +USAGE INFORMATION: + +Each zip contains the models, textures and animation info for that particular format! + +Please Read the "animationinfo.txt" file included in each zip for the exact frames of animation to use + +Credits to me "Psionic" are really appreciated but are not essential ;-) + +Any questions, screenshots of him in use etc drop by my site or email me at:- + +website: http://www.psionic3d.co.uk +email: psionic@blueyonder.co.uk + + + + +WHAT'S INCLUDED IN THE ZIP: + +ReadMe.txt - This file +b3d.zip - Blitz 3D Format models and textures +ms3d.zip - Milkshape 3D Format models and textures +x.zip - DarkBasic Direct X 8 Format models and textures + + + +RESTRICTIONS: + +This model pack is available for use in freeware, shareware, commercial games/software with the following restrictions:- + +**You may not sell/re-sell this model pack or claim it as your own. +***You may not redistribute this pack in some other model pack through a website or on a compilation CD of any kind, without my written consent. + + +Psi +http://www.psionic3d.co.uk + + + + diff --git a/media/dwarf.jpg b/media/dwarf.jpg new file mode 100644 index 00000000..430d83e7 Binary files /dev/null and b/media/dwarf.jpg differ diff --git a/media/dwarf.x b/media/dwarf.x new file mode 100644 index 00000000..c10769bc --- /dev/null +++ b/media/dwarf.x @@ -0,0 +1,18468 @@ +xof 0303txt 0032 + +// DirectX - from MilkShape3D + +template XSkinMeshHeader +{ + <3CF169CE-FF7C-44AB-93C0-F78F62D172E2> + WORD nMaxSkinWeightsPerVertex; + WORD nMaxSkinWeightsPerFace; + WORD nBones; +} + +template VertexDuplicationIndices +{ + + DWORD nIndices; + DWORD nOriginalVertices; + array DWORD indices[nIndices]; +} + +template SkinWeights +{ + <6F0D123B-BAD2-4167-A0D0-80224F25FABB> + CSTRING transformNodeName; + DWORD nWeights; + array DWORD vertexIndices[nWeights]; + array FLOAT weights[nWeights]; + Matrix4x4 matrixOffset; +} + +Frame base +{ + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 0.011608,-0.015192,0.000000,1.000000;; + } + + Frame middle + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 0.173034,30.221760,0.000000,1.000000;; + } + + Frame lhip + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -5.191007,-3.469861,0.000000,1.000000;; + } + + Frame lknee + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -1.903369,-8.817497,0.000000,1.000000;; + } + + Frame lankle + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -1.557302,-12.873290,3.507543,1.000000;; + } + + Frame ltoe + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -0.083542,-2.837912,-5.268192,1.000000;; + } + } + } + } + } + + Frame rhip + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 5.883141,-2.951185,0.000000,1.000000;; + } + + Frame rknee + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 1.557302,-9.681957,0.000000,1.000000;; + } + + Frame rankle + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 1.038201,-13.046183,3.507543,1.000000;; + } + + Frame rtoe + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 0.161076,-2.268395,-5.055357,1.000000;; + } + } + } + } + } + + Frame spine2 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -0.008257,4.071795,0.000000,1.000000;; + } + + Frame Joint75 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -0.007980,5.843795,0.000000,1.000000;; + } + + Frame Joint76 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -0.033215,5.642583,0.000000,1.000000;; + } + + Frame spine1 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -0.057544,3.129822,0.000000,1.000000;; + } + + Frame head + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 0.000000,4.183402,0.000000,1.000000;; + } + + Frame Joint36 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 2.351048,-2.969238,-5.128667,1.000000;; + } + + Frame Joint39 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 2.521163,-4.102684,-2.779583,1.000000;; + } + + Frame Joint40 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 1.543145,-3.721243,-0.884647,1.000000;; + } + + Frame Joint41 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 0.857303,-3.157324,-0.940437,1.000000;; + } + } + } + } + } + + Frame Joint37 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -2.844125,-3.130046,-5.128667,1.000000;; + } + + Frame Joint38 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -2.314107,-4.198860,-2.779583,1.000000;; + } + + Frame Joint42 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -1.200224,-3.209697,-0.885387,1.000000;; + } + + Frame Joint43 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -1.285954,-3.696030,-0.939697,1.000000;; + } + } + } + } + } + + Frame top + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -0.311274,14.438549,-1.107615,1.000000;; + } + } + } + + Frame pad2 + { + FrameTransformMatrix + { + 0.986286,0.165048,0.000000,0.000000, + -0.159424,0.952679,0.258819,0.000000, + 0.042717,-0.255270,0.965926,0.000000, + -6.280235,3.399014,0.000000,1.000000;; + } + } + + Frame pad1 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 5.233529,3.529747,0.000000,1.000000;; + } + } + + Frame lsholda + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -10.711074,-1.732187,3.529744,1.000000;; + } + + Frame lelbo + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -6.541911,-5.098517,0.705949,1.000000;; + } + + Frame lwrist + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -7.850295,-6.405833,0.000000,1.000000;; + } + + Frame Joint17 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -3.663469,-3.660475,0.000000,1.000000;; + } + + Frame Joint18 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -1.046706,-2.091701,0.000000,1.000000;; + } + + Frame Joint19 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -0.130838,-3.137549,0.000000,1.000000;; + } + } + } + } + + Frame Joint20 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -0.261676,-4.314132,-3.481931,1.000000;; + } + + Frame Joint21 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -1.046704,-2.483894,0.000000,1.000000;; + } + } + } + } + } + } + + Frame rsholda + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 9.986465,-1.438042,3.529744,1.000000;; + } + + Frame relbo + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 6.803588,-5.359982,0.705949,1.000000;; + } + + Frame rwrist + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 8.373647,-6.798027,0.000000,1.000000;; + } + + Frame Joint25 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 3.663469,-3.137551,0.000000,1.000000;; + } + + Frame Joint26 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 1.046706,-2.353162,0.000000,1.000000;; + } + + Frame Joint27 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -0.261676,-2.876088,0.000000,1.000000;; + } + } + } + } + + Frame Joint28 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -0.785030,-4.183402,-2.034320,1.000000;; + } + + Frame Joint29 + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 0.261676,-2.483894,0.000000,1.000000;; + } + } + } + + Frame weapon + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 1.700897,-4.837056,0.000000,1.000000;; + } + + Frame end + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 0.179647,0.498486,-36.421711,1.000000;; + } + + Frame hit + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 9.751877,-17.324219,-0.896412,1.000000;; + } + } + } + } + } + } + } + } + } + } + } + } + + Frame Body + { + FrameTransformMatrix + { + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 0.000000,0.000000,0.000000,1.000000;; + } + + Mesh test2Mesh + { + 1479; + 9.163393;52.592094;5.311051;, + 9.238389;48.717903;7.829298;, + 4.414237;48.688927;8.841169;, + 3.635573;52.340664;5.854128;, + 9.163393;53.140781;0.434684;, + 4.689968;52.717564;0.392938;, + 9.088393;49.163322;-4.030602;, + 4.688091;48.439060;-3.863904;, + 9.163393;53.331882;5.609362;, + 9.238389;49.283154;8.325875;, + 11.722147;50.016842;7.103333;, + 14.414900;52.402100;5.129919;, + 9.163393;53.906952;0.104077;, + 14.609170;52.948395;0.154898;, + 9.088393;49.657726;-4.596818;, + 12.538961;51.131771;-3.441837;, + 11.743780;49.455685;6.606065;, + 3.657926;53.078899;6.152925;, + 4.392604;49.250080;9.338439;, + 14.392547;51.663868;4.831122;, + 4.714078;53.482971;0.062556;, + 14.585064;52.182983;0.485280;, + 4.665834;48.929771;-4.430783;, + 12.561217;50.641060;-2.874957;, + -3.841073;48.688927;8.841169;, + -8.665230;48.717903;7.829298;, + -8.590232;52.592094;5.311051;, + -3.062412;52.340664;5.854128;, + -8.590232;53.140781;0.434684;, + -4.116807;52.717564;0.392938;, + -8.515234;49.163322;-4.030602;, + -4.114926;48.439060;-3.863904;, + -11.148983;50.016842;7.103333;, + -8.665230;49.283154;8.325875;, + -8.590232;53.331882;5.609362;, + -13.841740;52.402100;5.129919;, + -8.590232;53.906952;0.104077;, + -14.036011;52.948395;0.154898;, + -8.515234;49.657726;-4.596818;, + -11.965799;51.131771;-3.441837;, + -11.170617;49.455685;6.606065;, + -3.084766;53.078899;6.152925;, + -3.819439;49.250080;9.338439;, + -13.819386;51.663868;4.831122;, + -4.140916;53.482971;0.062556;, + -14.011902;52.182983;0.485280;, + -4.092670;48.929771;-4.430783;, + -11.988054;50.641060;-2.874957;, + 4.242009;58.884743;2.570855;, + 1.719232;58.884743;4.326951;, + 1.719237;56.180134;3.868141;, + 4.136295;56.180134;2.112046;, + 4.610723;58.899246;1.076627;, + 4.437895;58.255383;1.427657;, + 5.073560;57.831852;-0.831290;, + 5.188532;58.921978;-0.146142;, + 2.365810;57.220150;-5.311353;, + 2.389302;57.854408;-5.411583;, + 3.446397;57.361095;-4.919837;, + 1.418339;57.462894;-5.428807;, + 1.960295;58.125488;-6.407607;, + 3.297620;58.189804;-5.624568;, + 0.916452;57.514851;-5.702876;, + 0.196953;57.775261;-6.329302;, + 0.196953;58.155617;-6.759973;, + 0.564816;57.560535;-6.329302;, + 0.196953;56.507580;-7.229795;, + 0.708737;56.429287;-6.994888;, + 4.421278;57.862228;-4.019349;, + 1.112585;56.335316;-6.608064;, + 0.196953;55.849838;-7.151498;, + 0.582964;55.818516;-6.994890;, + 0.896177;55.674747;-6.525379;, + 1.417937;56.238544;-6.527757;, + 1.563801;56.421631;-5.875276;, + 1.501053;55.516430;-5.925784;, + 1.252991;55.717010;-6.405910;, + 1.410475;56.510334;-5.864188;, + 3.431264;58.838142;-5.428817;, + 4.623211;58.867786;-3.862747;, + 1.890343;58.877293;-6.329304;, + 0.196953;58.892124;-6.759975;, + 0.196953;55.386570;-6.432980;, + 1.338982;55.451138;-5.933945;, + 0.777895;55.360485;-5.945277;, + 1.571026;56.366024;-5.339862;, + 1.571026;55.436707;-5.446356;, + 1.861757;55.585438;-5.471374;, + 1.884718;56.220394;-5.389740;, + 2.329635;56.396385;-5.213789;, + 2.469955;55.050526;-5.128000;, + 3.372011;56.456528;-4.812878;, + 3.374272;54.561684;-4.943109;, + 4.306293;56.502014;-3.484852;, + 3.994818;55.254379;-3.108994;, + 4.901477;58.929310;-2.285047;, + 4.795761;57.729420;-2.282111;, + 4.617773;56.512859;-2.432453;, + 1.247561;54.160404;-6.036166;, + 1.628837;53.851963;-5.425615;, + 1.488684;53.503712;-5.567427;, + 1.076976;53.568111;-6.080726;, + 0.196953;54.323627;-6.546213;, + 0.196953;53.731537;-6.538884;, + 0.196953;55.284870;-6.817455;, + 0.951778;55.293880;-6.407505;, + 1.324306;54.522755;-6.402828;, + 0.196953;54.639961;-6.854869;, + 1.651121;55.311077;-5.924803;, + 1.872430;54.120838;-6.092515;, + 2.486549;54.906082;-5.613785;, + 1.896263;53.393780;-5.016593;, + 3.004211;54.377865;-5.643836;, + 2.416372;53.485512;-6.018716;, + 4.294228;53.059486;-5.110569;, + 4.603637;53.194355;-4.556661;, + 3.353439;52.269436;-6.323624;, + 3.164008;52.026455;-5.518155;, + 2.831037;52.120289;-6.667702;, + 1.427815;53.126896;-6.581466;, + 0.196953;53.319347;-7.071489;, + 4.258074;51.279964;-6.929201;, + 0.196953;51.218552;-7.671501;, + 1.286211;51.037498;-7.819720;, + 0.196953;48.516830;-4.831125;, + 0.906312;47.223148;-6.323102;, + 2.390713;50.135826;-8.501509;, + 5.147715;49.761192;-2.113228;, + 5.483280;49.024506;-7.912204;, + 3.519759;47.640644;-8.922348;, + 2.230943;45.983410;-6.837262;, + 5.862195;46.566502;-7.827096;, + 6.063165;47.270485;-4.336467;, + 5.817128;46.143192;-6.768289;, + 4.771815;46.200104;-8.748175;, + 4.112585;45.550518;-7.827313;, + 5.082815;53.401516;-0.452015;, + 5.082815;55.802074;-0.757885;, + 6.278196;45.850166;-8.067322;, + 6.233131;45.426857;-7.008514;, + 5.187818;45.483761;-8.988400;, + 4.528587;44.834175;-8.067539;, + 7.751843;45.219013;-8.465691;, + 7.664405;44.397705;-6.411367;, + 5.636263;44.508118;-10.252790;, + 4.357210;43.247772;-8.466115;, + 7.991459;42.205650;-8.873802;, + 7.938428;41.592506;-7.636380;, + 6.708311;41.659477;-9.966291;, + 5.932536;40.895046;-8.882633;, + 7.677983;38.542618;-9.851732;, + 0.196953;58.884743;4.326951;, + 0.196953;56.180134;3.868141;, + 4.401065;56.646732;1.280575;, + 4.430346;55.772125;0.639352;, + 0.196953;53.862251;5.027995;, + 2.420499;53.751408;4.068233;, + 4.104025;53.089230;2.761263;, + 4.926210;51.548302;1.105534;, + 0.196953;51.306179;5.766455;, + 2.537956;50.579800;4.794079;, + 4.280571;49.732357;3.256207;, + 5.337671;48.582260;0.821585;, + 5.337671;47.371635;-1.636148;, + 0.196953;59.059555;4.940836;, + 1.877897;59.059555;4.940958;, + 5.022821;59.059555;2.991112;, + 5.431325;59.075630;1.332422;, + 6.073157;59.100891;-0.026047;, + 5.753413;59.109047;-2.406004;, + 5.444712;59.040668;-4.160086;, + 4.124426;59.007809;-5.896048;, + 2.070525;59.051250;-6.894945;, + 0.196953;59.067738;-7.373756;, + 0.196953;60.034519;4.932486;, + 1.875382;60.034519;4.933323;, + 5.012119;60.034527;2.990359;, + 5.413950;60.050449;1.339854;, + 6.055133;60.075699;-0.018468;, + 5.730547;60.083881;-2.419671;, + 5.424481;60.015327;-4.181113;, + 4.127413;59.982983;-5.894018;, + 2.082769;60.026131;-6.883855;, + 0.196953;60.042675;-7.364650;, + 0.196953;61.891335;4.474140;, + 2.119642;61.891335;4.476328;, + 4.312335;61.891335;2.701971;, + 4.631948;61.891903;1.199314;, + 5.159706;61.892818;-0.050380;, + 4.883253;61.893120;-2.302159;, + 4.635466;61.890621;-3.937706;, + 3.606839;61.889484;-5.468257;, + 2.316901;61.891026;-6.361181;, + 0.196953;61.891628;-6.807594;, + 0.196953;63.485386;2.934556;, + 1.273063;63.485386;2.936174;, + 2.932324;63.485386;1.646364;, + 3.173945;63.485817;0.554150;, + 3.573367;63.486504;-0.354457;, + 3.363917;63.486732;-1.992494;, + 3.176482;63.484837;-3.181942;, + 2.398919;63.483986;-4.293848;, + 1.422985;63.485149;-4.942707;, + 0.196953;63.485607;-5.267362;, + 0.196953;64.502686;-1.390165;, + -1.325331;58.884743;4.326951;, + -3.848105;58.884743;2.570855;, + -3.742393;56.180134;2.112046;, + -1.325334;56.180134;3.868141;, + -4.043993;58.255383;1.427657;, + -4.216822;58.899246;1.076627;, + -4.794626;58.921978;-0.146142;, + -4.679657;57.831852;-0.831290;, + -3.052497;57.361095;-4.919837;, + -1.995399;57.854408;-5.411583;, + -1.971910;57.220150;-5.311353;, + -1.024434;57.462894;-5.428807;, + -2.903716;58.189804;-5.624568;, + -1.566390;58.125488;-6.407607;, + -0.522547;57.514851;-5.702876;, + -0.170911;57.560535;-6.329302;, + -0.314837;56.429287;-6.994888;, + -4.027374;57.862228;-4.019349;, + -0.718680;56.335316;-6.608064;, + -0.189061;55.818516;-6.994890;, + -0.502274;55.674747;-6.525379;, + -1.169898;56.421631;-5.875276;, + -1.024032;56.238544;-6.527757;, + -0.859088;55.717010;-6.405910;, + -1.107148;55.516430;-5.925784;, + -1.016574;56.510334;-5.864188;, + -4.229308;58.867786;-3.862747;, + -3.037360;58.838142;-5.428817;, + -1.496442;58.877293;-6.329304;, + -0.383995;55.360485;-5.945277;, + -0.945081;55.451138;-5.933945;, + -1.177125;55.436707;-5.446356;, + -1.177123;56.366024;-5.339862;, + -1.490817;56.220394;-5.389740;, + -1.467852;55.585438;-5.471374;, + -1.935732;56.396385;-5.213789;, + -2.076050;55.050526;-5.128000;, + -2.978111;56.456528;-4.812878;, + -2.980371;54.561684;-4.943109;, + -3.912392;56.502014;-3.484852;, + -3.600917;55.254379;-3.108994;, + -4.507572;58.929310;-2.285047;, + -4.401859;57.729420;-2.282111;, + -4.223874;56.512859;-2.432453;, + -1.234934;53.851963;-5.425615;, + -0.853661;54.160404;-6.036166;, + -0.683076;53.568111;-6.080726;, + -1.094784;53.503712;-5.567427;, + -0.557873;55.293880;-6.407505;, + -0.930401;54.522755;-6.402828;, + -1.257221;55.311077;-5.924803;, + -1.478527;54.120838;-6.092515;, + -2.092644;54.906082;-5.613785;, + -1.502358;53.393780;-5.016593;, + -2.022469;53.485512;-6.018716;, + -2.610310;54.377865;-5.643836;, + -3.900326;53.059486;-5.110569;, + -4.209735;53.194355;-4.556661;, + -2.959539;52.269436;-6.323624;, + -2.770105;52.026455;-5.518155;, + -1.033910;53.126896;-6.581466;, + -2.437134;52.120289;-6.667702;, + -3.864171;51.279964;-6.929201;, + -0.892305;51.037498;-7.819720;, + -0.512412;47.223148;-6.323102;, + -1.996812;50.135826;-8.501509;, + -4.753813;49.761192;-2.113228;, + -5.089376;49.024506;-7.912204;, + -3.125859;47.640644;-8.922348;, + -1.837040;45.983410;-6.837262;, + -5.468292;46.566502;-7.827096;, + -5.423228;46.143192;-6.768289;, + -5.669262;47.270485;-4.336467;, + -4.377913;46.200104;-8.748175;, + -3.718686;45.550518;-7.827313;, + -4.688914;53.401516;-0.452015;, + -4.688914;55.802074;-0.757885;, + -5.884295;45.850166;-8.067322;, + -5.839230;45.426857;-7.008514;, + -4.793914;45.483761;-8.988400;, + -4.134687;44.834175;-8.067539;, + -7.357939;45.219013;-8.465691;, + -7.270504;44.397705;-6.411367;, + -5.242361;44.508118;-10.252790;, + -3.963310;43.247772;-8.466115;, + -7.597560;42.205650;-8.873802;, + -7.544526;41.592506;-7.636380;, + -6.314410;41.659477;-9.966291;, + -5.538635;40.895046;-8.882633;, + -7.284081;38.542618;-9.851732;, + -4.036447;55.772125;0.639352;, + -4.007164;56.646732;1.280575;, + -2.026598;53.751408;4.068233;, + -4.532308;51.548302;1.105534;, + -3.710120;53.089230;2.761263;, + -2.144051;50.579800;4.794079;, + -3.886670;49.732357;3.256207;, + -4.943766;48.582260;0.821585;, + -4.943766;47.371635;-1.636148;, + -1.483993;59.059555;4.940958;, + -4.628918;59.059555;2.991112;, + -5.037425;59.075630;1.332422;, + -5.679255;59.100891;-0.026047;, + -5.359512;59.109047;-2.406004;, + -5.050810;59.040668;-4.160086;, + -3.730523;59.007809;-5.896048;, + -1.676620;59.051250;-6.894945;, + -1.481479;60.034519;4.933323;, + -4.618215;60.034527;2.990359;, + -5.020047;60.050449;1.339854;, + -5.661230;60.075699;-0.018468;, + -5.336645;60.083881;-2.419671;, + -5.030577;60.015327;-4.181113;, + -3.733512;59.982983;-5.894018;, + -1.688867;60.026131;-6.883855;, + -1.725740;61.891335;4.476328;, + -3.918436;61.891335;2.701971;, + -4.238046;61.891903;1.199314;, + -4.765804;61.892818;-0.050380;, + -4.489351;61.893120;-2.302159;, + -4.241562;61.890621;-3.937706;, + -3.212934;61.889484;-5.468257;, + -1.923000;61.891026;-6.361181;, + -0.879161;63.485386;2.936174;, + -2.538420;63.485386;1.646364;, + -2.780046;63.485817;0.554150;, + -3.179467;63.486504;-0.354457;, + -2.970013;63.486732;-1.992494;, + -2.782579;63.484837;-3.181942;, + -2.005019;63.483986;-4.293848;, + -1.029080;63.485149;-4.942707;, + -0.192284;65.158386;-0.267689;, + -0.617771;65.158386;-1.004657;, + -0.014429;64.035477;-1.004657;, + 0.109390;64.035477;-0.790199;, + 0.234013;67.669022;-1.022976;, + 0.658695;65.158386;-0.267689;, + 0.357023;64.035477;-0.790199;, + 1.084181;65.158386;-1.004657;, + 0.480839;64.035477;-1.004657;, + 0.658695;65.158386;-1.741625;, + 0.357023;64.035477;-1.219115;, + -0.192284;65.158386;-1.741625;, + 0.109390;64.035477;-1.219115;, + 7.321572;63.560955;-0.055478;, + 7.050604;63.754948;-1.851895;, + 2.748468;63.025620;-1.582111;, + 2.822511;62.793049;0.228580;, + 7.863518;62.050617;0.503212;, + 2.702447;60.765869;0.971560;, + 8.134492;60.734272;-0.734516;, + 2.776194;59.416355;-0.247001;, + 7.863518;60.928257;-2.530933;, + 2.702447;59.647991;-2.050448;, + 7.321572;62.438591;-3.089625;, + 2.822511;61.670685;-2.805565;, + 9.181485;64.333855;-2.066042;, + 9.632345;64.462769;-1.100490;, + 10.534081;64.061180;-0.951941;, + 10.984941;63.530704;-1.768948;, + 10.534077;63.401791;-2.734500;, + 9.632351;63.803379;-2.883049;, + 10.870568;67.072159;-2.811351;, + 11.125603;67.210205;-2.340091;, + 11.635665;67.146370;-2.316478;, + 11.890695;66.944496;-2.764128;, + 11.635665;66.806458;-3.235387;, + 11.125603;66.870285;-3.259001;, + 10.770185;70.864441;-4.091156;, + -2.175307;63.025620;-1.582111;, + -6.477442;63.754936;-1.851895;, + -6.748413;63.560955;-0.055478;, + -2.249351;62.793049;0.228580;, + -7.290359;62.050617;0.503212;, + -2.129283;60.765858;0.971560;, + -7.561328;60.734272;-0.734516;, + -2.203030;59.416344;-0.247001;, + -7.290359;60.928257;-2.530933;, + -2.129283;59.647991;-2.050448;, + -6.748413;62.438591;-3.089625;, + -2.249351;61.670685;-2.805565;, + -8.608323;64.333855;-2.066042;, + -9.059186;64.462769;-1.100490;, + -9.960917;64.061180;-0.951941;, + -10.411779;63.530704;-1.768948;, + -9.960917;63.401791;-2.734500;, + -9.059186;63.803379;-2.883049;, + -10.297409;67.072159;-2.811351;, + -10.552441;67.210205;-2.340091;, + -11.062504;67.146370;-2.316479;, + -11.317535;66.944496;-2.764129;, + -11.062504;66.806458;-3.235389;, + -10.552441;66.870285;-3.259001;, + -10.197022;70.864441;-4.091156;, + 9.278677;42.422218;6.029630;, + 3.269274;42.720932;10.305261;, + 3.727235;37.106018;10.305261;, + 8.567321;37.947166;6.627038;, + 3.076538;53.204800;4.651457;, + 0.063876;53.173985;0.844661;, + 1.636344;53.091850;6.132280;, + 10.371579;42.720932;0.675551;, + 10.590998;38.832512;-0.519268;, + 4.213577;53.047283;0.988064;, + 8.567321;42.720932;-4.893595;, + 8.567321;40.015377;-5.275937;, + 3.118487;52.304691;-0.871308;, + 3.269272;42.644463;-8.265944;, + 3.269272;40.303337;-8.724752;, + 1.678248;51.885815;-2.496562;, + 0.063876;40.303337;-8.724752;, + 0.063876;42.644463;-8.265944;, + 8.092727;46.706837;7.085848;, + 4.030234;47.533649;9.387641;, + 7.498330;46.932663;-3.808702;, + 9.269650;46.553898;-0.745430;, + 2.860954;47.304241;-6.201300;, + 0.063876;47.304241;-6.201299;, + 6.308704;51.898582;5.810977;, + 2.260517;51.022770;7.858276;, + 6.308704;51.061012;-1.528991;, + 7.708933;51.749233;0.002558;, + 2.260515;49.875748;-3.830782;, + 0.063876;53.091850;6.132280;, + 0.063876;51.405113;7.858276;, + 0.063876;42.720932;10.305261;, + 0.063876;37.106018;10.305261;, + 0.063876;51.885815;-2.496561;, + 0.063876;47.533646;9.378681;, + 0.063876;49.952217;-4.021954;, + 9.563355;51.572124;5.130688;, + 10.424463;51.137897;0.771196;, + -3.599484;37.106018;10.305261;, + -3.141526;42.720932;10.305261;, + -9.150930;42.422218;6.029630;, + -8.439575;37.947166;6.627038;, + -1.508598;53.091850;6.132280;, + -2.948791;53.204800;4.651457;, + -10.243833;42.720932;0.675551;, + -10.463250;38.832512;-0.519268;, + -4.085828;53.047283;0.988064;, + -8.439575;42.720932;-4.893595;, + -8.439575;40.015377;-5.275937;, + -2.990738;52.304691;-0.871308;, + -3.141523;42.644463;-8.265944;, + -3.141523;40.303337;-8.724752;, + -1.550497;51.885815;-2.496562;, + -3.902486;47.533649;9.387641;, + -7.964980;46.706837;7.085848;, + -9.141901;46.553898;-0.745430;, + -7.370583;46.932663;-3.808702;, + -2.733205;47.304241;-6.201300;, + -2.132767;51.022770;7.858276;, + -6.180955;51.898582;5.810977;, + -7.581183;51.749233;0.002558;, + -6.180955;51.061012;-1.528991;, + -2.132767;49.875748;-3.830782;, + -9.435607;51.572124;5.130688;, + -10.296713;51.137897;0.771196;, + 26.442608;31.439417;2.804749;, + 27.750952;33.479103;1.464946;, + 28.644909;31.793991;1.543602;, + 27.650051;30.546118;1.966592;, + 27.962191;30.422531;4.730635;, + 25.291662;35.616783;6.993527;, + 23.804535;33.790108;6.865523;, + 28.113920;30.947910;7.563584;, + 29.418135;32.175655;7.563584;, + 26.276403;37.035873;5.267626;, + 29.144712;26.626286;4.498936;, + 30.605154;26.898275;4.811452;, + 30.184065;26.943773;6.619426;, + 29.278811;26.812195;6.619426;, + 23.970884;33.278522;4.380921;, + 26.921537;36.568802;3.461252;, + 25.464495;35.399422;1.973382;, + 29.121349;26.822264;2.423525;, + 29.903082;27.052881;2.157598;, + 23.995649;32.729515;1.987316;, + 25.637072;33.964241;0.536960;, + 25.396690;32.550930;-0.123384;, + 24.000338;31.858027;1.237716;, + 24.161800;33.391464;3.241510;, + 29.999184;32.499008;5.227734;, + 26.998781;32.694099;1.064689;, + 25.652718;30.935171;2.198134;, + 25.432625;28.413658;0.334064;, + 26.032991;29.244349;-0.349298;, + 26.852461;29.841438;0.779249;, + 26.386019;28.977617;1.267885;, + 26.512205;31.188791;1.184134;, + 25.206884;31.094601;-0.305392;, + 23.991529;30.626995;0.930952;, + 30.933636;29.712465;5.072928;, + 30.310335;29.777977;7.264207;, + 28.988699;28.980301;7.299366;, + 28.432882;29.246729;4.638216;, + 29.648125;29.915192;1.703345;, + 28.309542;29.520292;2.073250;, + 6.755167;0.046006;8.013719;, + 5.431096;0.088037;3.223917;, + 12.250779;0.088037;3.300384;, + 5.309235;0.894232;2.923214;, + 12.009439;0.731735;2.923214;, + 4.846424;0.413626;-6.580339;, + 7.194882;0.034675;-8.202744;, + 10.442262;0.175008;-8.276375;, + 5.897818;0.168155;0.023152;, + 11.833355;0.047754;-6.787080;, + 12.240962;0.175049;0.374328;, + 6.753324;1.573865;7.859301;, + 5.310324;1.516512;3.522007;, + 10.324868;0.327974;8.243123;, + 10.323023;1.855839;8.088705;, + 12.010524;1.354014;3.522007;, + 7.195130;0.874356;-8.201875;, + 10.442509;1.014684;-8.275504;, + 4.846746;1.253311;-6.580090;, + 11.833675;0.887438;-6.786831;, + 5.898684;1.007790;0.014234;, + 12.241827;1.014688;0.365411;, + 8.078106;3.698104;-7.581497;, + 11.428559;3.021991;-6.440265;, + 5.468536;3.167656;-5.998088;, + 5.238337;3.089141;-2.541014;, + 11.932255;2.791543;-3.152129;, + 8.602904;5.932668;-0.505548;, + 11.133778;5.817454;1.389889;, + 8.140334;4.399764;-4.469068;, + 8.224634;5.036399;-2.774021;, + 11.898876;5.830766;3.514578;, + 5.863575;5.809277;1.057280;, + 4.953313;5.817947;3.744911;, + 5.601276;5.822373;6.464175;, + 7.258355;5.792872;6.393783;, + 10.561975;5.836313;6.220846;, + 3.714457;19.327164;5.891222;, + 2.395580;19.017778;1.623937;, + 2.663392;17.355799;1.982380;, + 3.977465;17.241997;5.800620;, + 6.098813;19.432480;7.503632;, + 6.110166;17.147745;7.382187;, + 9.150031;20.134617;6.603466;, + 9.390180;17.139515;5.800619;, + 12.296237;20.290672;1.623937;, + 12.022444;17.723486;1.982380;, + 9.151049;19.982052;-2.746684;, + 9.045196;17.139517;-1.835862;, + 6.099829;19.279917;-4.705683;, + 6.618869;17.147745;-3.417428;, + 3.568517;19.174599;-2.746683;, + 3.743971;17.241997;-1.835860;, + 2.744522;21.981775;7.255371;, + 0.781750;21.713270;1.998527;, + 5.311180;23.393459;9.200554;, + 8.947892;24.840387;7.668663;, + 12.009036;25.446686;1.982380;, + 8.947892;24.362463;-3.649055;, + 5.311180;22.915539;-6.179790;, + 2.633436;21.656416;-3.632905;, + 1.563167;23.850784;8.223292;, + 0.063876;23.353767;1.793407;, + 9.435429;28.020374;7.743168;, + 8.477934;28.887068;-4.569030;, + 11.027375;30.391527;0.493318;, + 3.810796;27.047464;-6.897249;, + 0.063876;24.272585;-4.193496;, + 13.090539;50.522636;1.384549;, + 13.041045;50.467754;5.078930;, + 15.039926;48.268642;5.106739;, + 15.654872;48.436718;2.094133;, + 9.371727;37.438923;7.067486;, + 4.033619;36.444157;10.870089;, + 11.587032;38.454742;-0.613277;, + 9.381097;39.704651;-5.891787;, + 3.585032;40.004971;-9.656940;, + 0.063876;40.004971;-9.656940;, + 8.947521;33.780930;6.792171;, + 4.207292;33.892616;11.120209;, + 11.152753;32.194057;-0.597313;, + 9.604399;31.258600;-5.890305;, + 3.468354;30.257090;-9.461814;, + 0.063876;30.257090;-9.461814;, + 8.336151;33.208889;6.506425;, + 3.972105;33.252815;10.523578;, + 10.880808;31.578617;-0.480340;, + 8.391865;30.899374;-5.411129;, + 3.229546;29.783400;-8.733105;, + 0.063876;29.783400;-8.733105;, + 8.763739;31.230478;7.043343;, + 0.063876;25.862223;-6.032537;, + 0.063876;36.444157;10.870090;, + 0.063876;33.892616;11.120211;, + 0.063876;33.252815;10.523581;, + 0.063876;24.095449;8.763750;, + 0.063876;25.246412;10.275227;, + 0.063876;31.503160;10.970792;, + 4.717443;31.494150;10.284621;, + 0.063876;27.969845;11.631809;, + 5.059318;27.174917;10.768083;, + 3.292733;13.614117;8.688048;, + 2.012897;13.266646;2.479012;, + 7.391886;13.045812;9.537921;, + 9.592052;13.108393;8.535723;, + 13.927161;13.699846;2.063019;, + 11.253488;12.661762;-3.185383;, + 7.687788;12.915033;-4.890432;, + 3.292731;13.091016;-3.337706;, + 4.909685;14.315273;6.833395;, + 3.449045;14.019177;2.395389;, + 7.335181;13.898731;7.254448;, + 8.640161;14.192272;6.638759;, + 12.054080;14.385403;1.847208;, + 10.983072;13.852963;-1.636501;, + 7.731716;13.866605;-2.741714;, + 4.956770;13.926673;-1.904490;, + 4.622008;12.070519;7.351222;, + 3.704210;12.065571;2.885277;, + 7.193317;12.063840;7.696905;, + 9.864344;12.084161;6.936748;, + 12.660480;12.906409;2.302423;, + 11.551223;11.698577;-0.567342;, + 7.725829;10.867992;-1.832680;, + 5.002745;10.862820;-0.929778;, + 12.585479;45.664989;7.008708;, + 12.874625;45.344864;-1.512470;, + 15.109089;43.486977;7.253585;, + 13.087454;40.435127;5.464614;, + 13.795866;40.778912;1.743529;, + 15.452188;43.225502;-0.514091;, + 16.849886;45.784691;5.345008;, + 17.423424;46.063019;2.332403;, + 16.609575;42.436638;6.842184;, + 14.607471;39.414421;5.619863;, + 15.315888;39.758205;1.898780;, + 16.952673;42.175163;0.809246;, + 18.329708;44.705509;5.492955;, + 18.903246;44.983837;2.480351;, + 18.144800;40.845119;8.897065;, + 14.914027;35.968437;6.910757;, + 16.068686;36.528782;0.845695;, + 18.704021;40.418938;-0.936131;, + 20.914110;44.495216;6.691762;, + 21.848928;44.948868;1.781464;, + 18.167065;40.766296;8.049853;, + 15.450755;36.687752;6.384915;, + 16.415583;37.133137;1.422668;, + 18.616444;40.429634;-0.082681;, + 20.535810;43.903175;6.157079;, + 21.299704;44.256214;2.222467;, + 20.548147;39.083851;7.840796;, + 18.160057;35.498848;6.365007;, + 19.018757;35.895241;1.948607;, + 20.948095;38.784222;0.303311;, + 22.625053;41.832062;6.150033;, + 23.304918;42.146267;2.648228;, + 23.432049;37.018097;6.817175;, + 21.932474;34.767567;5.880031;, + 23.302208;36.315411;2.154666;, + 22.480751;35.020664;3.060161;, + 24.731340;38.735447;5.732314;, + 25.165438;38.936066;3.496411;, + 23.626654;36.826782;1.797030;, + -28.517160;31.793991;1.543602;, + -27.623203;33.479103;1.464946;, + -26.314863;31.439417;2.804749;, + -27.522303;30.546118;1.966592;, + -27.834438;30.422531;4.730635;, + -27.986174;30.947910;7.563584;, + -23.676790;33.790108;6.865523;, + -25.163914;35.616783;6.993527;, + -29.290388;32.175655;7.563584;, + -26.148655;37.035873;5.267626;, + -30.056318;26.943773;6.619426;, + -30.477406;26.898275;4.811452;, + -29.016966;26.626286;4.498936;, + -29.151058;26.812195;6.619426;, + -23.843136;33.278522;4.380921;, + -25.336742;35.399422;1.973382;, + -26.793785;36.568802;3.461252;, + -29.775337;27.052881;2.157598;, + -28.993601;26.822264;2.423525;, + -25.268938;32.550930;-0.123384;, + -25.509323;33.964241;0.536960;, + -23.867901;32.729515;1.987316;, + -23.872589;31.858027;1.237716;, + -24.034052;33.391464;3.241510;, + -29.871441;32.499008;5.227734;, + -26.871038;32.694099;1.064689;, + -25.524969;30.935171;2.198134;, + -26.724709;29.841438;0.779249;, + -25.905239;29.244349;-0.349298;, + -25.304882;28.413658;0.334064;, + -26.258276;28.977617;1.267885;, + -25.079140;31.094601;-0.305392;, + -26.384459;31.188791;1.184134;, + -23.863787;30.626995;0.930952;, + -30.805887;29.712465;5.072928;, + -30.182587;29.777977;7.264207;, + -28.860950;28.980301;7.299366;, + -28.305138;29.246729;4.638216;, + -29.520382;29.915192;1.703345;, + -28.181793;29.520292;2.073250;, + -12.123036;0.088037;3.300384;, + -5.303345;0.088037;3.223917;, + -6.627419;0.046006;8.013719;, + -11.881689;0.731735;2.923214;, + -5.181487;0.894232;2.923214;, + -10.314516;0.175008;-8.276375;, + -7.067134;0.034675;-8.202744;, + -4.718675;0.413626;-6.580339;, + -11.705606;0.047754;-6.787080;, + -5.770067;0.168155;0.023152;, + -12.113213;0.175049;0.374328;, + -5.182574;1.516512;3.522007;, + -6.625576;1.573865;7.859301;, + -10.195277;1.855839;8.088705;, + -10.197120;0.327974;8.243123;, + -11.882777;1.354014;3.522007;, + -10.314760;1.014684;-8.275504;, + -7.067381;0.874356;-8.201875;, + -4.718995;1.253311;-6.580090;, + -11.705929;0.887438;-6.786831;, + -5.770934;1.007790;0.014234;, + -12.114079;1.014688;0.365411;, + -11.300814;3.021991;-6.440265;, + -7.950356;3.698104;-7.581497;, + -5.340785;3.167656;-5.998088;, + -5.110586;3.089141;-2.541014;, + -11.804509;2.791543;-3.152129;, + -11.006028;5.817454;1.389889;, + -8.475157;5.932668;-0.505548;, + -8.096884;5.036399;-2.774021;, + -8.012587;4.399764;-4.469068;, + -11.771126;5.830766;3.514578;, + -5.735826;5.809277;1.057280;, + -4.825563;5.817947;3.744911;, + -5.473527;5.822373;6.464175;, + -7.130609;5.792872;6.393783;, + -10.434228;5.836313;6.220846;, + -2.535641;17.355799;1.982380;, + -2.267831;19.017778;1.623937;, + -3.586708;19.327164;5.891222;, + -3.849715;17.241997;5.800620;, + -5.971066;19.432480;7.503632;, + -5.982419;17.147745;7.382187;, + -9.022285;20.134617;6.603466;, + -9.262430;17.139515;5.800619;, + -12.168489;20.290672;1.623937;, + -11.894694;17.723486;1.982380;, + -9.023302;19.982052;-2.746684;, + -8.917446;17.139517;-1.835862;, + -5.972082;19.279917;-4.705683;, + -6.491119;17.147745;-3.417428;, + -3.440768;19.174599;-2.746683;, + -3.616219;17.241997;-1.835860;, + -0.653999;21.713270;1.998527;, + -2.616775;21.981775;7.255371;, + -5.183431;23.393459;9.200554;, + -8.820147;24.840387;7.668663;, + -11.881289;25.446686;1.982380;, + -8.820147;24.362463;-3.649055;, + -5.183429;22.915539;-6.179790;, + -2.505685;21.656416;-3.632905;, + -1.435419;23.850784;8.223292;, + -9.307683;28.020374;7.743168;, + -10.899626;30.391527;0.493318;, + -8.350187;28.887068;-4.569030;, + -3.683043;27.047464;-6.897249;, + -14.912179;48.268642;5.106739;, + -12.913298;50.467754;5.078930;, + -12.962790;50.522636;1.384549;, + -15.527129;48.436718;2.094133;, + -9.243979;37.438923;7.067486;, + -3.905869;36.444157;10.870089;, + -11.459283;38.454742;-0.613277;, + -9.253351;39.704651;-5.891787;, + -3.457279;40.004971;-9.656940;, + -8.819773;33.780930;6.792171;, + -4.079543;33.892616;11.120209;, + -11.025005;32.194057;-0.597313;, + -9.476652;31.258600;-5.890305;, + -3.340604;30.257090;-9.461814;, + -8.208400;33.208889;6.506425;, + -3.844355;33.252815;10.523578;, + -10.753060;31.578617;-0.480340;, + -8.264114;30.899374;-5.411129;, + -3.101796;29.783400;-8.733105;, + -8.635990;31.230478;7.043343;, + -4.589693;31.494150;10.284621;, + -4.931572;27.174917;10.768083;, + -3.164983;13.614117;8.688048;, + -1.885150;13.266646;2.479012;, + -7.264134;13.045812;9.537921;, + -9.464302;13.108393;8.535723;, + -13.799416;13.699846;2.063019;, + -11.125739;12.661762;-3.185383;, + -7.560040;12.915033;-4.890432;, + -3.164983;13.091016;-3.337706;, + -4.781938;14.315273;6.833395;, + -3.321296;14.019177;2.395389;, + -7.207436;13.898731;7.254448;, + -8.512415;14.192272;6.638759;, + -11.926332;14.385403;1.847208;, + -10.855326;13.852963;-1.636501;, + -7.603969;13.866605;-2.741714;, + -4.829021;13.926673;-1.904490;, + -4.494260;12.070519;7.351222;, + -3.576463;12.065571;2.885277;, + -7.065567;12.063840;7.696905;, + -9.736598;12.084161;6.936748;, + -12.532731;12.906409;2.302423;, + -11.423474;11.698577;-0.567342;, + -7.598082;10.867992;-1.832680;, + -4.874997;10.862820;-0.929778;, + -12.457731;45.664989;7.008708;, + -12.746877;45.344864;-1.512470;, + -14.981347;43.486977;7.253585;, + -12.959704;40.435127;5.464614;, + -13.668120;40.778912;1.743529;, + -15.324445;43.225502;-0.514091;, + -16.722143;45.784691;5.345008;, + -17.295679;46.063019;2.332403;, + -16.481831;42.436638;6.842184;, + -14.479725;39.414421;5.619863;, + -15.188142;39.758205;1.898780;, + -16.824930;42.175163;0.809246;, + -18.201963;44.705509;5.492955;, + -18.775501;44.983837;2.480351;, + -18.017056;40.845119;8.897065;, + -14.786280;35.968437;6.910757;, + -15.940937;36.528782;0.845695;, + -18.576277;40.418938;-0.936131;, + -20.786366;44.495216;6.691762;, + -21.721182;44.948868;1.781464;, + -18.039320;40.766296;8.049853;, + -15.323012;36.687752;6.384915;, + -16.287840;37.133137;1.422668;, + -18.488697;40.429634;-0.082681;, + -20.408064;43.903175;6.157079;, + -21.171957;44.256214;2.222467;, + -20.420401;39.083851;7.840796;, + -18.032312;35.498848;6.365007;, + -18.891008;35.895241;1.948607;, + -20.820349;38.784222;0.303311;, + -22.497307;41.832062;6.150033;, + -23.177174;42.146267;2.648228;, + -23.304302;37.018097;6.817175;, + -21.804729;34.767567;5.880031;, + -22.353006;35.020664;3.060161;, + -23.174463;36.315411;2.154666;, + -24.603598;38.735447;5.732314;, + -25.037689;38.936066;3.496411;, + -23.498907;36.826782;1.797030;, + 32.573399;20.998508;-13.993474;, + 31.347282;21.510612;-18.896196;, + 32.212158;19.942856;-22.086969;, + 34.386311;17.725908;-19.577688;, + 32.721909;19.000187;-25.473017;, + 35.309505;16.038933;-24.075357;, + 32.861069;18.711260;-28.951471;, + 35.487915;15.668485;-28.535112;, + 32.625397;19.084837;-32.416637;, + 35.185760;16.147453;-32.977818;, + 32.022045;20.109577;-35.763229;, + 34.412201;17.461275;-37.268509;, + 31.069363;21.754337;-38.889565;, + 33.190762;19.570044;-41.276810;, + 30.172787;23.316404;-40.686150;, + 30.727213;23.864517;-46.026169;, + 26.799459;29.484686;-23.919806;, + 26.588755;29.721081;-34.907444;, + 28.314373;26.659443;-35.908363;, + 28.665804;26.196402;-23.140169;, + 29.684425;24.219271;-37.460514;, + 30.009434;23.747953;-29.136843;, + 30.314682;23.305275;-21.319128;, + 33.628345;20.744303;-22.096889;, + 32.763477;22.312052;-18.906120;, + 34.138103;19.801640;-25.482931;, + 34.277260;19.512701;-28.961386;, + 34.041592;19.886280;-32.426556;, + 33.438240;20.911032;-35.773148;, + 32.485558;22.555790;-38.899498;, + 31.588987;24.117847;-40.696075;, + 29.730568;27.460878;-35.918262;, + 28.004946;30.522528;-34.917355;, + 28.215664;30.286123;-23.929716;, + 30.082003;26.997847;-23.150089;, + 31.425623;24.549398;-29.146767;, + 31.100611;25.020727;-37.470440;, + 31.730875;24.106718;-21.329044;, + 28.887688;30.497171;16.516956;, + 28.264534;31.576502;16.538700;, + 27.273039;30.284517;16.527586;, + 28.868330;30.531387;14.265285;, + 28.245173;31.610723;14.287043;, + 28.430216;31.305752;-36.706051;, + 26.815575;31.093081;-36.695400;, + 27.807066;32.385075;-36.684288;, + 28.565001;29.293274;16.501442;, + 28.545649;29.327480;14.249776;, + 28.107540;30.101837;-36.721565;, + 27.485502;28.670019;16.501251;, + 27.466146;28.704229;14.249575;, + 27.028032;29.478594;-36.721748;, + 26.281548;28.992525;16.516499;, + 26.262192;29.026735;14.264828;, + 25.824083;29.801088;-36.706490;, + 25.658390;30.071863;16.538246;, + 25.639032;30.106077;14.286580;, + 25.200922;30.880438;-36.684742;, + 25.981071;31.275770;16.553751;, + 25.961720;31.309975;14.302090;, + 25.523605;32.084339;-36.669224;, + 27.060581;31.899025;16.553940;, + 27.041225;31.933235;14.302281;, + 26.603115;32.707592;-36.669060;, + 28.548414;31.096832;-22.954752;, + 27.925262;32.176163;-22.932991;, + 28.111961;31.846174;-1.211521;, + 28.735117;30.766836;-1.233276;, + 28.225733;29.892931;-22.970266;, + 28.412436;29.562933;-1.248788;, + 27.146231;29.269676;-22.970453;, + 27.332933;28.939684;-1.248984;, + 25.942278;29.592182;-22.955206;, + 26.128983;29.262184;-1.233739;, + 25.319118;30.671524;-22.933453;, + 25.505823;30.341524;-1.211982;, + 25.641800;31.875427;-22.917944;, + 25.828506;31.545427;-1.196465;, + 26.721312;32.498676;-22.917738;, + 26.908014;32.168686;-1.196282;, + 29.272268;30.830444;-0.798965;, + 28.443258;32.266331;-0.770020;, + 28.568949;32.044174;13.852868;, + 29.397957;30.608292;13.823928;, + 28.842997;29.228819;-0.819599;, + 28.968679;29.006672;13.803288;, + 27.406893;28.399687;-0.819852;, + 27.532579;28.177542;13.803031;, + 25.805210;28.828726;-0.799567;, + 25.930891;28.606585;13.823323;, + 24.976185;30.264614;-0.770632;, + 25.101870;30.042463;13.852263;, + 25.405474;31.866238;-0.749988;, + 25.531157;31.644094;13.872904;, + 26.841581;32.695370;-0.749732;, + 26.967262;32.473228;13.873165;, + 27.815252;32.370605;-35.731056;, + 28.438414;31.291262;-35.752815;, + 28.115726;30.087366;-35.768326;, + 27.036226;29.464113;-35.768520;, + 25.832272;29.786617;-35.753273;, + 25.209120;30.865946;-35.731510;, + 25.531799;32.069855;-35.715992;, + 26.611311;32.693104;-35.715794;, + 29.151377;31.385166;-35.757492;, + 28.253050;32.941086;-35.726151;, + 28.363062;32.746647;-22.928093;, + 29.261381;31.190737;-22.959444;, + 28.686214;29.649672;-35.779873;, + 28.796217;29.455244;-22.981829;, + 27.130047;28.751215;-35.780151;, + 27.240047;28.556789;-22.982094;, + 25.394470;29.216141;-35.758179;, + 25.504477;29.021709;-22.960121;, + 24.496161;30.772045;-35.726803;, + 24.606161;30.577616;-22.928751;, + 24.961311;32.507545;-35.704453;, + 25.071318;32.313114;-22.906395;, + 26.517492;33.405987;-35.704166;, + 26.627487;33.211575;-22.906115;, + 4.623211;58.867786;-3.862747;, + 4.421278;57.862228;-4.019349;, + 4.306293;56.502014;-3.484852;, + 3.994818;55.254379;-3.108994;, + 5.147715;49.761192;-2.113228;, + 6.278196;45.850166;-8.067322;, + 6.233131;45.426857;-7.008514;, + 7.751843;45.219013;-8.465691;, + 4.528587;44.834175;-8.067539;, + 5.187818;45.483761;-8.988400;, + 5.636263;44.508118;-10.252790;, + 7.664405;44.397705;-6.411367;, + 4.357210;43.247772;-8.466115;, + 7.991459;42.205650;-8.873802;, + 6.708311;41.659477;-9.966291;, + 7.938428;41.592506;-7.636380;, + 5.932536;40.895046;-8.882633;, + 7.677983;38.542618;-9.851732;, + 7.677983;38.542618;-9.851732;, + 4.401065;56.646732;1.280575;, + 4.437895;58.255383;1.427657;, + 4.430346;55.772125;0.639352;, + 5.337671;47.371635;-1.636148;, + 4.610723;58.899246;1.076627;, + 0.196953;58.884743;4.326951;, + 1.719232;58.884743;4.326951;, + 4.242009;58.884743;2.570855;, + 4.610723;58.899246;1.076627;, + 5.188532;58.921978;-0.146142;, + 4.901477;58.929310;-2.285047;, + 4.623211;58.867786;-3.862747;, + 3.431264;58.838142;-5.428817;, + 1.890343;58.877293;-6.329304;, + 0.196953;58.892124;-6.759975;, + 0.196953;61.891335;4.474140;, + 2.119642;61.891335;4.476328;, + 4.312335;61.891335;2.701971;, + 4.631948;61.891903;1.199314;, + 5.159706;61.892818;-0.050380;, + 4.883253;61.893120;-2.302159;, + 4.635466;61.890621;-3.937706;, + 3.606839;61.889484;-5.468257;, + 2.316901;61.891026;-6.361181;, + 0.196953;61.891628;-6.807594;, + -4.753813;49.761192;-2.113228;, + -5.884295;45.850166;-8.067322;, + -5.839230;45.426857;-7.008514;, + -7.357939;45.219013;-8.465691;, + -4.134687;44.834175;-8.067539;, + -5.242361;44.508118;-10.252790;, + -4.793914;45.483761;-8.988400;, + -7.270504;44.397705;-6.411367;, + -3.963310;43.247772;-8.466115;, + -7.597560;42.205650;-8.873802;, + -6.314410;41.659477;-9.966291;, + -7.544526;41.592506;-7.636380;, + -5.538635;40.895046;-8.882633;, + -7.284081;38.542618;-9.851732;, + -7.284081;38.542618;-9.851732;, + -4.043993;58.255383;1.427657;, + -4.007164;56.646732;1.280575;, + -4.036447;55.772125;0.639352;, + -4.943766;47.371635;-1.636148;, + -4.216822;58.899246;1.076627;, + 0.196953;58.884743;4.326951;, + 0.196953;59.059555;4.940836;, + -1.325331;58.884743;4.326951;, + -3.848105;58.884743;2.570855;, + -4.216822;58.899246;1.076627;, + -4.794626;58.921978;-0.146142;, + -4.507572;58.929310;-2.285047;, + -4.229308;58.867786;-3.862747;, + -3.037360;58.838142;-5.428817;, + -1.496442;58.877293;-6.329304;, + 0.196953;60.034519;4.932486;, + 0.196953;61.891335;4.474140;, + -1.725740;61.891335;4.476328;, + -3.918436;61.891335;2.701971;, + -4.238046;61.891903;1.199314;, + -4.765804;61.892818;-0.050380;, + -4.489351;61.893120;-2.302159;, + -4.241562;61.890621;-3.937706;, + -3.212934;61.889484;-5.468257;, + -1.923000;61.891026;-6.361181;, + -0.192284;65.158386;-0.267689;, + 0.109390;64.035477;-0.790199;, + 0.234013;67.669022;-1.022976;, + 0.658695;65.158386;-0.267689;, + 0.357023;64.035477;-0.790199;, + 0.658695;65.158386;-1.741625;, + 0.357023;64.035477;-1.219115;, + -0.192284;65.158386;-1.741625;, + 0.234013;67.669022;-1.022976;, + 7.050604;63.754948;-1.851895;, + 2.748468;63.025620;-1.582111;, + 9.181485;64.333855;-2.066042;, + 10.870568;67.072159;-2.811351;, + -6.477442;63.754936;-1.851895;, + -2.175307;63.025620;-1.582111;, + -8.608323;64.333855;-2.066042;, + -10.297409;67.072159;-2.811351;, + 9.278677;42.422218;6.029630;, + 8.567321;37.947166;6.627038;, + 10.371579;42.720932;0.675551;, + 10.590998;38.832512;-0.519268;, + 0.063876;53.173985;0.844661;, + 4.213577;53.047283;0.988064;, + 9.269650;46.553898;-0.745430;, + 6.308704;51.061012;-1.528991;, + 7.708933;51.749233;0.002558;, + 7.708933;51.749233;0.002558;, + 6.308704;51.898582;5.810977;, + 8.092727;46.706837;7.085848;, + 0.063876;53.173985;0.844661;, + -8.439575;37.947166;6.627038;, + -9.150930;42.422218;6.029630;, + -10.463250;38.832512;-0.519268;, + -10.243833;42.720932;0.675551;, + -4.085828;53.047283;0.988064;, + -9.141901;46.553898;-0.745430;, + -6.180955;51.061012;-1.528991;, + 0.063876;51.405113;7.858276;, + 0.063876;53.091850;6.132280;, + -7.581183;51.749233;0.002558;, + -7.581183;51.749233;0.002558;, + 0.063876;42.720932;10.305261;, + 0.063876;37.106018;10.305261;, + 0.063876;47.533646;9.378681;, + -7.964980;46.706837;7.085848;, + -6.180955;51.898582;5.810977;, + 26.442608;31.439417;2.804749;, + 28.644909;31.793991;1.543602;, + 27.650051;30.546118;1.966592;, + 29.418135;32.175655;7.563584;, + 25.291662;35.616783;6.993527;, + 28.113920;30.947910;7.563584;, + 23.804535;33.790108;6.865523;, + 23.995649;32.729515;1.987316;, + 24.161800;33.391464;3.241510;, + 25.464495;35.399422;1.973382;, + 30.310335;29.777977;7.264207;, + 28.988699;28.980301;7.299366;, + 29.648125;29.915192;1.703345;, + 28.309542;29.520292;2.073250;, + 30.184065;26.943773;6.619426;, + 29.278811;26.812195;6.619426;, + 29.121349;26.822264;2.423525;, + 29.903082;27.052881;2.157598;, + 6.755167;0.046006;8.013719;, + 12.250779;0.088037;3.300384;, + 12.009439;0.731735;2.923214;, + 5.309235;0.894232;2.923214;, + 5.431096;0.088037;3.223917;, + 7.194882;0.034675;-8.202744;, + 4.846424;0.413626;-6.580339;, + 10.442262;0.175008;-8.276375;, + 5.897818;0.168155;0.023152;, + 11.833355;0.047754;-6.787080;, + 12.240962;0.175049;0.374328;, + 10.442509;1.014684;-8.275504;, + 4.846746;1.253311;-6.580090;, + 7.195130;0.874356;-8.201875;, + 5.468536;3.167656;-5.998088;, + 4.846746;1.253311;-6.580090;, + 11.428559;3.021991;-6.440265;, + 12.241827;1.014688;0.365411;, + 11.833675;0.887438;-6.786831;, + 11.932255;2.791543;-3.152129;, + 11.133778;5.817454;1.389889;, + 12.010524;1.354014;3.522007;, + 5.898684;1.007790;0.014234;, + 5.310324;1.516512;3.522007;, + 6.753324;1.573865;7.859301;, + 5.601276;5.822373;6.464175;, + 10.323023;1.855839;8.088705;, + 5.238337;3.089141;-2.541014;, + 5.863575;5.809277;1.057280;, + 2.395580;19.017778;1.623937;, + 2.663392;17.355799;1.982380;, + 0.781750;21.713270;1.998527;, + 0.063876;23.353767;1.793407;, + 8.567321;37.947166;6.627038;, + 3.727235;37.106018;10.305261;, + 10.590998;38.832512;-0.519268;, + 8.567321;40.015377;-5.275937;, + 3.269272;40.303337;-8.724752;, + 0.063876;40.303337;-8.724752;, + 10.880808;31.578617;-0.480340;, + 8.336151;33.208889;6.506425;, + 8.391865;30.899374;-5.411129;, + 3.229546;29.783400;-8.733105;, + 0.063876;29.783400;-8.733105;, + 0.063876;37.106018;10.305261;, + 3.972105;33.252815;10.523578;, + 0.063876;33.252815;10.523581;, + 3.977465;17.241997;5.800620;, + 2.663392;17.355799;1.982380;, + 6.110166;17.147745;7.382187;, + 9.390180;17.139515;5.800619;, + 6.110166;17.147745;7.382187;, + 7.391886;13.045812;9.537921;, + 12.022444;17.723486;1.982380;, + 9.045196;17.139517;-1.835862;, + 6.618869;17.147745;-3.417428;, + 3.743971;17.241997;-1.835860;, + 3.743971;17.241997;-1.835860;, + 3.292731;13.091016;-3.337706;, + 7.335181;13.898731;7.254448;, + 4.956770;13.926673;-1.904490;, + 4.909685;14.315273;6.833395;, + 3.449045;14.019177;2.395389;, + 7.335181;13.898731;7.254448;, + 4.909685;14.315273;6.833395;, + 4.622008;12.070519;7.351222;, + 8.640161;14.192272;6.638759;, + 12.054080;14.385403;1.847208;, + 8.640161;14.192272;6.638759;, + 9.864344;12.084161;6.936748;, + 10.983072;13.852963;-1.636501;, + 7.731716;13.866605;-2.741714;, + 10.983072;13.852963;-1.636501;, + 11.551223;11.698577;-0.567342;, + 4.956770;13.926673;-1.904490;, + 4.956770;13.926673;-1.904490;, + 5.002745;10.862820;-0.929778;, + 5.601276;5.822373;6.464175;, + 7.258355;5.792872;6.393783;, + 10.561975;5.836313;6.220846;, + 11.898876;5.830766;3.514578;, + 11.133778;5.817454;1.389889;, + 8.602904;5.932668;-0.505548;, + 4.953313;5.817947;3.744911;, + 8.078106;3.698104;-7.581497;, + 5.468536;3.167656;-5.998088;, + 10.323023;1.855839;8.088705;, + 10.561975;5.836313;6.220846;, + 11.428559;3.021991;-6.440265;, + 10.324868;0.327974;8.243123;, + 11.833675;0.887438;-6.786831;, + 6.753324;1.573865;7.859301;, + 5.601276;5.822373;6.464175;, + 10.561975;5.836313;6.220846;, + 11.133778;5.817454;1.389889;, + 10.371579;42.720932;0.675551;, + 9.278677;42.422218;6.029630;, + 10.371579;42.720932;0.675551;, + 13.795866;40.778912;1.743529;, + 15.315888;39.758205;1.898780;, + 16.609575;42.436638;6.842184;, + 14.607471;39.414421;5.619863;, + 15.315888;39.758205;1.898780;, + 16.952673;42.175163;0.809246;, + 14.914027;35.968437;6.910757;, + 14.607471;39.414421;5.619863;, + 18.329708;44.705509;5.492955;, + 18.144800;40.845119;8.897065;, + 18.903246;44.983837;2.480351;, + 15.450755;36.687752;6.384915;, + 18.167065;40.766296;8.049853;, + 18.160057;35.498848;6.365007;, + 21.932474;34.767567;5.880031;, + 25.291662;35.616783;6.993527;, + 23.804535;33.790108;6.865523;, + 23.970884;33.278522;4.380921;, + 23.804535;33.790108;6.865523;, + 26.276403;37.035873;5.267626;, + 26.921537;36.568802;3.461252;, + -25.163914;35.616783;6.993527;, + -29.290388;32.175655;7.563584;, + -23.676790;33.790108;6.865523;, + -27.986174;30.947910;7.563584;, + -25.336742;35.399422;1.973382;, + -24.034052;33.391464;3.241510;, + -23.867901;32.729515;1.987316;, + -30.182587;29.777977;7.264207;, + -28.860950;28.980301;7.299366;, + -30.056318;26.943773;6.619426;, + -29.151058;26.812195;6.619426;, + -6.627419;0.046006;8.013719;, + -12.123036;0.088037;3.300384;, + -11.881689;0.731735;2.923214;, + -5.303345;0.088037;3.223917;, + -5.181487;0.894232;2.923214;, + -7.067134;0.034675;-8.202744;, + -4.718675;0.413626;-6.580339;, + -10.314516;0.175008;-8.276375;, + -5.770067;0.168155;0.023152;, + -11.705606;0.047754;-6.787080;, + -12.113213;0.175049;0.374328;, + -10.314760;1.014684;-8.275504;, + -7.067381;0.874356;-8.201875;, + -4.718995;1.253311;-6.580090;, + -4.718995;1.253311;-6.580090;, + -5.340785;3.167656;-5.998088;, + -12.114079;1.014688;0.365411;, + -11.300814;3.021991;-6.440265;, + -11.705929;0.887438;-6.786831;, + -11.804509;2.791543;-3.152129;, + -11.882777;1.354014;3.522007;, + -11.006028;5.817454;1.389889;, + -5.770934;1.007790;0.014234;, + -5.182574;1.516512;3.522007;, + -5.473527;5.822373;6.464175;, + -6.625576;1.573865;7.859301;, + -10.195277;1.855839;8.088705;, + -5.735826;5.809277;1.057280;, + -5.110586;3.089141;-2.541014;, + -2.267831;19.017778;1.623937;, + -2.535641;17.355799;1.982380;, + -0.653999;21.713270;1.998527;, + -3.599484;37.106018;10.305261;, + -8.439575;37.947166;6.627038;, + -10.463250;38.832512;-0.519268;, + -8.439575;40.015377;-5.275937;, + -3.141523;40.303337;-8.724752;, + -8.208400;33.208889;6.506425;, + -10.753060;31.578617;-0.480340;, + -8.264114;30.899374;-5.411129;, + -3.101796;29.783400;-8.733105;, + -3.844355;33.252815;10.523578;, + -2.535641;17.355799;1.982380;, + -3.849715;17.241997;5.800620;, + -5.982419;17.147745;7.382187;, + -5.982419;17.147745;7.382187;, + -9.262430;17.139515;5.800619;, + -7.264134;13.045812;9.537921;, + -11.894694;17.723486;1.982380;, + -8.917446;17.139517;-1.835862;, + -6.491119;17.147745;-3.417428;, + -3.616219;17.241997;-1.835860;, + -3.616219;17.241997;-1.835860;, + -3.164983;13.091016;-3.337706;, + -7.207436;13.898731;7.254448;, + -4.829021;13.926673;-1.904490;, + -3.321296;14.019177;2.395389;, + -4.781938;14.315273;6.833395;, + -4.781938;14.315273;6.833395;, + -7.207436;13.898731;7.254448;, + -4.494260;12.070519;7.351222;, + -8.512415;14.192272;6.638759;, + -8.512415;14.192272;6.638759;, + -11.926332;14.385403;1.847208;, + -9.736598;12.084161;6.936748;, + -10.855326;13.852963;-1.636501;, + -10.855326;13.852963;-1.636501;, + -7.603969;13.866605;-2.741714;, + -11.423474;11.698577;-0.567342;, + -4.829021;13.926673;-1.904490;, + -4.829021;13.926673;-1.904490;, + -4.874997;10.862820;-0.929778;, + -5.473527;5.822373;6.464175;, + -7.130609;5.792872;6.393783;, + -10.434228;5.836313;6.220846;, + -11.771126;5.830766;3.514578;, + -11.006028;5.817454;1.389889;, + -8.475157;5.932668;-0.505548;, + -4.825563;5.817947;3.744911;, + -5.340785;3.167656;-5.998088;, + -7.950356;3.698104;-7.581497;, + -10.434228;5.836313;6.220846;, + -10.195277;1.855839;8.088705;, + -11.300814;3.021991;-6.440265;, + -10.197120;0.327974;8.243123;, + -11.705929;0.887438;-6.786831;, + -6.625576;1.573865;7.859301;, + -5.473527;5.822373;6.464175;, + -10.434228;5.836313;6.220846;, + -11.006028;5.817454;1.389889;, + -10.243833;42.720932;0.675551;, + -9.150930;42.422218;6.029630;, + -10.243833;42.720932;0.675551;, + -13.668120;40.778912;1.743529;, + -15.188142;39.758205;1.898780;, + -14.479725;39.414421;5.619863;, + -16.481831;42.436638;6.842184;, + -16.824930;42.175163;0.809246;, + -15.188142;39.758205;1.898780;, + -14.479725;39.414421;5.619863;, + -14.786280;35.968437;6.910757;, + -18.201963;44.705509;5.492955;, + -18.017056;40.845119;8.897065;, + -18.775501;44.983837;2.480351;, + -15.323012;36.687752;6.384915;, + -18.039320;40.766296;8.049853;, + -18.032312;35.498848;6.365007;, + -21.804729;34.767567;5.880031;, + -25.163914;35.616783;6.993527;, + -23.676790;33.790108;6.865523;, + -23.676790;33.790108;6.865523;, + -23.843136;33.278522;4.380921;, + -26.148655;37.035873;5.267626;, + -26.793785;36.568802;3.461252;, + 32.763477;22.312052;-18.906120;, + 31.347282;21.510612;-18.896196;, + 32.573399;20.998508;-13.993474;, + 31.588987;24.117847;-40.696075;, + 30.727213;23.864517;-46.026169;, + 30.172787;23.316404;-40.686150;, + 28.004946;30.522528;-34.917355;, + 26.588755;29.721081;-34.907444;, + 26.799459;29.484686;-23.919806;, + 28.215664;30.286123;-23.929716;, + 29.730568;27.460878;-35.918262;, + 28.314373;26.659443;-35.908363;, + 28.665804;26.196402;-23.140169;, + 30.082003;26.997847;-23.150089;, + 31.100611;25.020727;-37.470440;, + 29.684425;24.219271;-37.460514;, + 30.314682;23.305275;-21.319128;, + 31.730875;24.106718;-21.329044;, + 28.264534;31.576502;16.538700;, + 28.887688;30.497171;16.516956;, + 28.565001;29.293274;16.501442;, + 27.485502;28.670019;16.501251;, + 26.281548;28.992525;16.516499;, + 25.658390;30.071863;16.538246;, + 25.981071;31.275770;16.553751;, + 25.961720;31.309975;14.302090;, + 25.981071;31.275770;16.553751;, + 27.060581;31.899025;16.553940;, + 25.641800;31.875427;-22.917944;, + 25.828506;31.545427;-1.196465;, + 25.405474;31.866238;-0.749988;, + 25.531157;31.644094;13.872904;, + 28.430216;31.305752;-36.706051;, + 27.807066;32.385075;-36.684288;, + 28.107540;30.101837;-36.721565;, + 27.028032;29.478594;-36.721748;, + 25.824083;29.801088;-36.706490;, + 25.200922;30.880438;-36.684742;, + 25.523605;32.084339;-36.669224;, + 26.603115;32.707592;-36.669060;, + 25.523605;32.084339;-36.669224;, + 25.531799;32.069855;-35.715992;, + 24.961311;32.507545;-35.704453;, + 25.071318;32.313114;-22.906395;, + 29.151377;31.385166;-35.757492;, + 28.438414;31.291262;-35.752815;, + 27.815252;32.370605;-35.731056;, + 28.253050;32.941086;-35.726151;, + 28.363062;32.746647;-22.928093;, + 27.925262;32.176163;-22.932991;, + 28.548414;31.096832;-22.954752;, + 29.261381;31.190737;-22.959444;, + 28.686214;29.649672;-35.779873;, + 28.115726;30.087366;-35.768326;, + 28.225733;29.892931;-22.970266;, + 28.796217;29.455244;-22.981829;, + 27.130047;28.751215;-35.780151;, + 27.036226;29.464113;-35.768520;, + 27.146231;29.269676;-22.970453;, + 27.240047;28.556789;-22.982094;, + 25.394470;29.216141;-35.758179;, + 25.832272;29.786617;-35.753273;, + 25.942278;29.592182;-22.955206;, + 25.504477;29.021709;-22.960121;, + 24.496161;30.772045;-35.726803;, + 25.209120;30.865946;-35.731510;, + 25.319118;30.671524;-22.933453;, + 24.606161;30.577616;-22.928751;, + 24.961311;32.507545;-35.704453;, + 25.531799;32.069855;-35.715992;, + 25.641800;31.875427;-22.917944;, + 25.071318;32.313114;-22.906395;, + 26.517492;33.405987;-35.704166;, + 26.611311;32.693104;-35.715794;, + 26.721312;32.498676;-22.917738;, + 26.627487;33.211575;-22.906115;, + 29.272268;30.830444;-0.798965;, + 28.735117;30.766836;-1.233276;, + 28.111961;31.846174;-1.211521;, + 28.443258;32.266331;-0.770020;, + 28.568949;32.044174;13.852868;, + 28.245173;31.610723;14.287043;, + 28.868330;30.531387;14.265285;, + 29.397957;30.608292;13.823928;, + 28.842997;29.228819;-0.819599;, + 28.412436;29.562933;-1.248788;, + 28.545649;29.327480;14.249776;, + 28.968679;29.006672;13.803288;, + 27.406893;28.399687;-0.819852;, + 27.332933;28.939684;-1.248984;, + 27.466146;28.704229;14.249575;, + 27.532579;28.177542;13.803031;, + 25.805210;28.828726;-0.799567;, + 26.128983;29.262184;-1.233739;, + 26.262192;29.026735;14.264828;, + 25.930891;28.606585;13.823323;, + 24.976185;30.264614;-0.770632;, + 25.505823;30.341524;-1.211982;, + 25.639032;30.106077;14.286580;, + 25.101870;30.042463;13.852263;, + 25.405474;31.866238;-0.749988;, + 25.828506;31.545427;-1.196465;, + 25.961720;31.309975;14.302090;, + 25.531157;31.644094;13.872904;, + 26.841581;32.695370;-0.749732;, + 26.908014;32.168686;-1.196282;, + 27.041225;31.933235;14.302281;, + 26.967262;32.473228;13.873165;; + 1896; + 3;0,1,2;, + 3;3,0,2;, + 3;4,0,3;, + 3;5,4,3;, + 3;6,4,5;, + 3;7,6,5;, + 3;8,9,10;, + 3;11,8,10;, + 3;12,8,11;, + 3;13,12,11;, + 3;14,12,13;, + 3;15,14,13;, + 3;9,1,16;, + 3;10,9,16;, + 3;17,3,2;, + 3;18,17,2;, + 3;10,16,19;, + 3;11,10,19;, + 3;20,5,3;, + 3;17,20,3;, + 3;11,19,21;, + 3;13,11,21;, + 3;22,7,5;, + 3;20,22,5;, + 3;14,6,7;, + 3;22,14,7;, + 3;13,21,23;, + 3;15,13,23;, + 3;19,16,1;, + 3;0,19,1;, + 3;21,19,0;, + 3;4,21,0;, + 3;23,21,4;, + 3;6,23,4;, + 3;17,18,9;, + 3;8,17,9;, + 3;20,17,8;, + 3;12,20,8;, + 3;22,20,12;, + 3;14,22,12;, + 3;18,2,1;, + 3;9,18,1;, + 3;15,23,6;, + 3;14,15,6;, + 3;24,25,26;, + 3;24,26,27;, + 3;27,26,28;, + 3;27,28,29;, + 3;29,28,30;, + 3;29,30,31;, + 3;32,33,34;, + 3;32,34,35;, + 3;35,34,36;, + 3;35,36,37;, + 3;37,36,38;, + 3;37,38,39;, + 3;40,25,33;, + 3;40,33,32;, + 3;24,27,41;, + 3;24,41,42;, + 3;43,40,32;, + 3;43,32,35;, + 3;27,29,44;, + 3;27,44,41;, + 3;45,43,35;, + 3;45,35,37;, + 3;29,31,46;, + 3;29,46,44;, + 3;31,30,38;, + 3;31,38,46;, + 3;47,45,37;, + 3;47,37,39;, + 3;25,40,43;, + 3;25,43,26;, + 3;26,43,45;, + 3;26,45,28;, + 3;28,45,47;, + 3;28,47,30;, + 3;33,42,41;, + 3;33,41,34;, + 3;34,41,44;, + 3;34,44,36;, + 3;36,44,46;, + 3;36,46,38;, + 3;25,24,42;, + 3;25,42,33;, + 3;30,47,39;, + 3;30,39,38;, + 3;48,49,50;, + 3;51,48,50;, + 3;52,53,54;, + 3;55,52,54;, + 3;56,57,58;, + 3;59,57,56;, + 3;57,60,61;, + 3;62,60,57;, + 3;59,62,57;, + 3;63,64,65;, + 3;65,60,62;, + 3;64,60,65;, + 3;66,63,65;, + 3;67,66,65;, + 3;61,68,58;, + 3;67,65,62;, + 3;69,67,62;, + 3;70,66,67;, + 3;71,70,67;, + 3;67,69,72;, + 3;71,67,72;, + 3;73,74,75;, + 3;76,73,75;, + 3;62,77,69;, + 3;78,79,68;, + 3;61,78,68;, + 3;80,78,61;, + 3;60,80,61;, + 3;64,81,80;, + 3;71,72,82;, + 3;70,71,82;, + 3;83,84,82;, + 3;72,83,82;, + 3;72,69,73;, + 3;76,72,73;, + 3;69,77,74;, + 3;73,69,74;, + 3;85,86,87;, + 3;88,85,87;, + 3;86,83,75;, + 3;87,86,75;, + 3;59,56,89;, + 3;85,59,89;, + 3;85,89,90;, + 3;86,85,90;, + 3;89,56,58;, + 3;91,89,58;, + 3;90,89,91;, + 3;92,90,91;, + 3;74,88,87;, + 3;75,74,87;, + 3;59,85,77;, + 3;62,59,77;, + 3;84,83,86;, + 3;77,85,88;, + 3;74,77,88;, + 3;83,72,76;, + 3;75,83,76;, + 3;91,58,68;, + 3;93,91,68;, + 3;92,91,93;, + 3;94,92,93;, + 3;979,95,96;, + 3;980,979,96;, + 3;980,96,97;, + 3;981,980,97;, + 3;981,97,982;, + 3;61,58,57;, + 3;98,99,100;, + 3;101,98,100;, + 3;102,98,101;, + 3;103,102,101;, + 3;104,105,106;, + 3;107,104,106;, + 3;105,108,109;, + 3;106,105,109;, + 3;108,110,109;, + 3;100,99,111;, + 3;109,110,112;, + 3;113,109,112;, + 3;104,82,84;, + 3;105,104,84;, + 3;106,98,102;, + 3;107,106,102;, + 3;105,84,86;, + 3;108,105,86;, + 3;109,99,98;, + 3;106,109,98;, + 3;108,86,90;, + 3;110,108,90;, + 3;110,90,92;, + 3;112,110,92;, + 3;113,111,99;, + 3;109,113,99;, + 3;114,112,92;, + 3;115,114,92;, + 3;116,113,112;, + 3;114,116,112;, + 3;117,111,113;, + 3;116,117,113;, + 3;92,94,115;, + 3;111,117,118;, + 3;119,111,118;, + 3;100,111,119;, + 3;101,100,119;, + 3;103,101,119;, + 3;120,103,119;, + 3;117,116,121;, + 3;118,117,121;, + 3;122,120,119;, + 3;123,122,119;, + 3;124,122,123;, + 3;125,124,123;, + 3;119,118,123;, + 3;126,123,118;, + 3;121,126,118;, + 3;125,123,126;, + 3;114,115,127;, + 3;116,114,127;, + 3;121,116,127;, + 3;128,121,127;, + 3;126,121,128;, + 3;129,126,128;, + 3;125,126,129;, + 3;130,125,129;, + 3;131,128,132;, + 3;133,131,132;, + 3;134,129,128;, + 3;131,134,128;, + 3;135,130,129;, + 3;134,135,129;, + 3;133,132,130;, + 3;135,133,130;, + 3;127,132,128;, + 3;127,115,94;, + 3;136,983,982;, + 3;95,55,54;, + 3;96,95,54;, + 3;96,54,137;, + 3;97,96,137;, + 3;97,137,136;, + 3;982,97,136;, + 3;138,131,133;, + 3;139,138,133;, + 3;140,134,131;, + 3;138,140,131;, + 3;141,135,134;, + 3;140,141,134;, + 3;139,133,135;, + 3;141,139,135;, + 3;142,984,985;, + 3;143,142,985;, + 3;144,140,138;, + 3;986,144,138;, + 3;145,987,988;, + 3;989,145,988;, + 3;990,139,141;, + 3;991,990,141;, + 3;146,142,143;, + 3;147,146,143;, + 3;148,144,986;, + 3;992,148,986;, + 3;149,145,989;, + 3;993,149,989;, + 3;994,990,991;, + 3;995,994,991;, + 3;150,146,147;, + 3;996,148,992;, + 3;997,149,993;, + 3;996,994,995;, + 3;50,49,151;, + 3;152,50,151;, + 3;153,154,137;, + 3;54,153,137;, + 3;998,999,48;, + 3;51,998,48;, + 3;51,50,155;, + 3;156,51,155;, + 3;156,1000,51;, + 3;136,137,157;, + 3;158,136,157;, + 3;983,136,158;, + 3;50,152,155;, + 3;156,155,159;, + 3;160,156,159;, + 3;157,156,160;, + 3;161,157,160;, + 3;158,157,161;, + 3;162,158,161;, + 3;983,158,162;, + 3;163,983,162;, + 3;132,127,1001;, + 3;999,1002,48;, + 3;1000,998,51;, + 3;53,153,54;, + 3;157,137,154;, + 3;156,157,1000;, + 3;164,1003,1004;, + 3;165,164,1004;, + 3;165,1004,1005;, + 3;166,165,1005;, + 3;166,1005,1006;, + 3;167,166,1006;, + 3;167,1006,1007;, + 3;168,167,1007;, + 3;168,1007,1008;, + 3;169,168,1008;, + 3;169,1008,1009;, + 3;170,169,1009;, + 3;170,1009,1010;, + 3;171,170,1010;, + 3;171,1010,1011;, + 3;172,171,1011;, + 3;172,1011,1012;, + 3;173,172,1012;, + 3;174,164,165;, + 3;175,174,165;, + 3;175,165,166;, + 3;176,175,166;, + 3;176,166,167;, + 3;177,176,167;, + 3;177,167,168;, + 3;178,177,168;, + 3;178,168,169;, + 3;179,178,169;, + 3;179,169,170;, + 3;180,179,170;, + 3;180,170,171;, + 3;181,180,171;, + 3;181,171,172;, + 3;182,181,172;, + 3;182,172,173;, + 3;183,182,173;, + 3;184,174,175;, + 3;185,184,175;, + 3;185,175,176;, + 3;186,185,176;, + 3;186,176,177;, + 3;187,186,177;, + 3;187,177,178;, + 3;188,187,178;, + 3;188,178,179;, + 3;189,188,179;, + 3;189,179,180;, + 3;190,189,180;, + 3;190,180,181;, + 3;191,190,181;, + 3;191,181,182;, + 3;192,191,182;, + 3;192,182,183;, + 3;193,192,183;, + 3;194,1013,1014;, + 3;195,194,1014;, + 3;195,1014,1015;, + 3;196,195,1015;, + 3;196,1015,1016;, + 3;197,196,1016;, + 3;197,1016,1017;, + 3;198,197,1017;, + 3;198,1017,1018;, + 3;199,198,1018;, + 3;199,1018,1019;, + 3;200,199,1019;, + 3;200,1019,1020;, + 3;201,200,1020;, + 3;201,1020,1021;, + 3;202,201,1021;, + 3;202,1021,1022;, + 3;203,202,1022;, + 3;204,194,195;, + 3;204,195,196;, + 3;204,196,197;, + 3;204,197,198;, + 3;204,198,199;, + 3;204,199,200;, + 3;204,200,201;, + 3;204,201,202;, + 3;204,202,203;, + 3;80,60,64;, + 3;205,206,207;, + 3;208,205,207;, + 3;209,210,211;, + 3;212,209,211;, + 3;213,214,215;, + 3;215,214,216;, + 3;217,218,214;, + 3;218,219,216;, + 3;214,218,216;, + 3;220,64,63;, + 3;219,218,220;, + 3;220,218,64;, + 3;63,66,221;, + 3;220,63,221;, + 3;213,222,217;, + 3;220,221,223;, + 3;219,220,223;, + 3;66,70,224;, + 3;221,66,224;, + 3;223,221,224;, + 3;225,223,224;, + 3;226,227,228;, + 3;229,226,228;, + 3;223,230,219;, + 3;231,232,217;, + 3;222,231,217;, + 3;232,233,218;, + 3;217,232,218;, + 3;233,81,64;, + 3;82,225,224;, + 3;82,224,70;, + 3;234,235,225;, + 3;82,234,225;, + 3;223,225,228;, + 3;227,223,228;, + 3;230,223,227;, + 3;226,230,227;, + 3;236,237,238;, + 3;239,236,238;, + 3;235,236,239;, + 3;229,235,239;, + 3;215,216,237;, + 3;240,215,237;, + 3;240,237,236;, + 3;241,240,236;, + 3;215,240,242;, + 3;213,215,242;, + 3;240,241,243;, + 3;242,240,243;, + 3;238,226,229;, + 3;239,238,229;, + 3;230,237,216;, + 3;230,216,219;, + 3;236,235,234;, + 3;237,230,226;, + 3;238,237,226;, + 3;225,235,229;, + 3;228,225,229;, + 3;213,242,244;, + 3;222,213,244;, + 3;242,243,245;, + 3;244,242,245;, + 3;246,231,222;, + 3;247,246,222;, + 3;247,222,244;, + 3;248,247,244;, + 3;245,248,244;, + 3;214,213,217;, + 3;249,250,251;, + 3;252,249,251;, + 3;250,102,103;, + 3;251,250,103;, + 3;253,104,107;, + 3;254,253,107;, + 3;255,253,254;, + 3;256,255,254;, + 3;256,257,255;, + 3;258,249,252;, + 3;257,256,259;, + 3;260,257,259;, + 3;82,104,253;, + 3;234,82,253;, + 3;250,254,107;, + 3;102,250,107;, + 3;234,253,255;, + 3;236,234,255;, + 3;249,256,254;, + 3;250,249,254;, + 3;236,255,257;, + 3;241,236,257;, + 3;241,257,260;, + 3;243,241,260;, + 3;258,259,256;, + 3;249,258,256;, + 3;260,261,262;, + 3;243,260,262;, + 3;259,263,261;, + 3;260,259,261;, + 3;258,264,263;, + 3;259,258,263;, + 3;262,245,243;, + 3;264,258,265;, + 3;266,264,265;, + 3;265,258,252;, + 3;265,252,251;, + 3;251,103,120;, + 3;265,251,120;, + 3;267,263,264;, + 3;267,264,266;, + 3;120,122,268;, + 3;265,120,268;, + 3;122,124,269;, + 3;268,122,269;, + 3;268,266,265;, + 3;268,270,267;, + 3;266,268,267;, + 3;270,268,269;, + 3;271,262,261;, + 3;261,263,267;, + 3;271,261,267;, + 3;271,267,272;, + 3;267,270,273;, + 3;272,267,273;, + 3;270,269,274;, + 3;273,270,274;, + 3;272,275,276;, + 3;277,272,276;, + 3;273,278,275;, + 3;272,273,275;, + 3;274,279,278;, + 3;273,274,278;, + 3;277,276,279;, + 3;274,277,279;, + 3;272,277,271;, + 3;1023,280,245;, + 3;245,262,271;, + 3;211,246,247;, + 3;212,211,247;, + 3;212,247,248;, + 3;281,212,248;, + 3;281,248,245;, + 3;280,281,245;, + 3;275,282,283;, + 3;276,275,283;, + 3;278,284,282;, + 3;275,278,282;, + 3;279,285,284;, + 3;278,279,284;, + 3;276,283,285;, + 3;279,276,285;, + 3;1024,286,287;, + 3;1025,1024,287;, + 3;284,288,1026;, + 3;282,284,1026;, + 3;1027,289,1028;, + 3;1029,1027,1028;, + 3;283,1030,1031;, + 3;285,283,1031;, + 3;286,290,291;, + 3;287,286,291;, + 3;288,292,1032;, + 3;1026,288,1032;, + 3;289,293,1033;, + 3;1028,289,1033;, + 3;1030,1034,1035;, + 3;1031,1030,1035;, + 3;291,290,294;, + 3;1032,292,1036;, + 3;1033,293,1037;, + 3;1035,1034,1036;, + 3;205,208,152;, + 3;151,205,152;, + 3;295,296,212;, + 3;281,295,212;, + 3;1038,1039,207;, + 3;206,1038,207;, + 3;208,207,297;, + 3;155,208,297;, + 3;207,1040,297;, + 3;281,280,298;, + 3;299,281,298;, + 3;298,280,1023;, + 3;155,152,208;, + 3;155,297,300;, + 3;159,155,300;, + 3;297,299,301;, + 3;300,297,301;, + 3;299,298,302;, + 3;301,299,302;, + 3;302,298,1023;, + 3;302,1023,303;, + 3;1041,271,277;, + 3;206,1042,1038;, + 3;207,1039,1040;, + 3;212,296,209;, + 3;295,281,299;, + 3;1040,299,297;, + 3;1043,1044,304;, + 3;1045,1043,304;, + 3;1045,304,305;, + 3;1046,1045,305;, + 3;1046,305,306;, + 3;1047,1046,306;, + 3;1047,306,307;, + 3;1048,1047,307;, + 3;1048,307,308;, + 3;1049,1048,308;, + 3;1049,308,309;, + 3;1050,1049,309;, + 3;1050,309,310;, + 3;1051,1050,310;, + 3;1051,310,311;, + 3;1052,1051,311;, + 3;1052,311,173;, + 3;1012,1052,173;, + 3;1044,1053,312;, + 3;304,1044,312;, + 3;304,312,313;, + 3;305,304,313;, + 3;305,313,314;, + 3;306,305,314;, + 3;306,314,315;, + 3;307,306,315;, + 3;307,315,316;, + 3;308,307,316;, + 3;308,316,317;, + 3;309,308,317;, + 3;309,317,318;, + 3;310,309,318;, + 3;310,318,319;, + 3;311,310,319;, + 3;311,319,183;, + 3;173,311,183;, + 3;1053,1054,320;, + 3;312,1053,320;, + 3;312,320,321;, + 3;313,312,321;, + 3;313,321,322;, + 3;314,313,322;, + 3;314,322,323;, + 3;315,314,323;, + 3;315,323,324;, + 3;316,315,324;, + 3;316,324,325;, + 3;317,316,325;, + 3;317,325,326;, + 3;318,317,326;, + 3;318,326,327;, + 3;319,318,327;, + 3;319,327,193;, + 3;183,319,193;, + 3;1013,194,328;, + 3;1055,1013,328;, + 3;1055,328,329;, + 3;1056,1055,329;, + 3;1056,329,330;, + 3;1057,1056,330;, + 3;1057,330,331;, + 3;1058,1057,331;, + 3;1058,331,332;, + 3;1059,1058,332;, + 3;1059,332,333;, + 3;1060,1059,333;, + 3;1060,333,334;, + 3;1061,1060,334;, + 3;1061,334,335;, + 3;1062,1061,335;, + 3;1062,335,203;, + 3;1022,1062,203;, + 3;328,194,204;, + 3;329,328,204;, + 3;330,329,204;, + 3;331,330,204;, + 3;332,331,204;, + 3;333,332,204;, + 3;334,333,204;, + 3;335,334,204;, + 3;203,335,204;, + 3;64,218,233;, + 3;336,337,338;, + 3;339,336,338;, + 3;336,340,337;, + 3;341,1063,1064;, + 3;342,341,1064;, + 3;341,1065,1063;, + 3;343,1066,1067;, + 3;344,343,1067;, + 3;343,340,1066;, + 3;345,343,344;, + 3;346,345,344;, + 3;345,340,343;, + 3;347,1068,1069;, + 3;348,1070,346;, + 3;347,1071,1068;, + 3;337,1070,348;, + 3;338,337,348;, + 3;337,340,1070;, + 3;349,350,351;, + 3;352,349,351;, + 3;353,349,352;, + 3;354,353,352;, + 3;355,353,354;, + 3;356,355,354;, + 3;357,355,356;, + 3;358,357,356;, + 3;359,357,358;, + 3;360,359,358;, + 3;1072,359,360;, + 3;1073,1072,360;, + 3;361,350,349;, + 3;362,361,349;, + 3;362,349,353;, + 3;363,362,353;, + 3;363,353,355;, + 3;364,363,355;, + 3;364,355,357;, + 3;365,364,357;, + 3;365,357,359;, + 3;366,365,359;, + 3;366,359,1072;, + 3;1074,366,1072;, + 3;367,361,362;, + 3;368,367,362;, + 3;368,362,363;, + 3;369,368,363;, + 3;369,363,364;, + 3;370,369,364;, + 3;370,364,365;, + 3;371,370,365;, + 3;371,365,366;, + 3;372,371,366;, + 3;372,366,1074;, + 3;1075,372,1074;, + 3;373,367,368;, + 3;373,368,369;, + 3;373,369,370;, + 3;373,370,371;, + 3;373,371,372;, + 3;373,372,1075;, + 3;374,375,376;, + 3;374,376,377;, + 3;377,376,378;, + 3;377,378,379;, + 3;379,378,380;, + 3;379,380,381;, + 3;381,380,382;, + 3;381,382,383;, + 3;383,382,384;, + 3;383,384,385;, + 3;385,384,1076;, + 3;385,1076,1077;, + 3;376,375,386;, + 3;376,386,387;, + 3;378,376,387;, + 3;378,387,388;, + 3;380,378,388;, + 3;380,388,389;, + 3;382,380,389;, + 3;382,389,390;, + 3;384,382,390;, + 3;384,390,391;, + 3;1076,384,391;, + 3;1076,391,1078;, + 3;387,386,392;, + 3;387,392,393;, + 3;388,387,393;, + 3;388,393,394;, + 3;389,388,394;, + 3;389,394,395;, + 3;390,389,395;, + 3;390,395,396;, + 3;391,390,396;, + 3;391,396,397;, + 3;1078,391,397;, + 3;1078,397,1079;, + 3;393,392,398;, + 3;394,393,398;, + 3;395,394,398;, + 3;396,395,398;, + 3;397,396,398;, + 3;1079,397,398;, + 3;399,400,401;, + 3;402,399,401;, + 3;403,404,405;, + 3;406,1080,1081;, + 3;407,406,1081;, + 3;408,404,403;, + 3;409,1082,1083;, + 3;410,409,1083;, + 3;411,1084,1085;, + 3;412,409,410;, + 3;413,412,410;, + 3;414,1084,411;, + 3;415,416,412;, + 3;413,415,412;, + 3;417,418,400;, + 3;399,417,400;, + 3;419,420,1082;, + 3;409,419,1082;, + 3;421,419,409;, + 3;412,421,409;, + 3;416,422,421;, + 3;412,416,421;, + 3;423,424,418;, + 3;417,423,418;, + 3;425,426,1086;, + 3;419,1087,420;, + 3;427,1087,419;, + 3;421,427,419;, + 3;428,429,424;, + 3;405,428,424;, + 3;405,424,423;, + 3;403,405,423;, + 3;403,423,1088;, + 3;408,403,1088;, + 3;1085,1089,1087;, + 3;411,1085,1087;, + 3;411,1087,427;, + 3;414,411,427;, + 3;401,400,430;, + 3;431,401,430;, + 3;404,428,405;, + 3;432,1084,414;, + 3;400,418,433;, + 3;430,400,433;, + 3;418,424,429;, + 3;433,418,429;, + 3;434,432,414;, + 3;427,434,414;, + 3;422,434,427;, + 3;421,422,427;, + 3;435,1090,1091;, + 3;436,426,1090;, + 3;435,436,1090;, + 3;437,438,439;, + 3;437,439,440;, + 3;441,1092,442;, + 3;1093,1094,443;, + 3;1093,443,444;, + 3;442,1092,445;, + 3;1095,1096,446;, + 3;1095,446,447;, + 3;1097,1084,448;, + 3;447,446,449;, + 3;447,449,450;, + 3;448,1084,451;, + 3;449,416,415;, + 3;449,415,450;, + 3;438,452,453;, + 3;438,453,439;, + 3;1096,454,455;, + 3;1096,455,446;, + 3;446,455,456;, + 3;446,456,449;, + 3;456,422,416;, + 3;456,416,449;, + 3;452,457,458;, + 3;452,458,453;, + 3;1098,459,460;, + 3;454,1099,455;, + 3;455,1099,461;, + 3;455,461,456;, + 3;457,1100,1101;, + 3;457,1101,441;, + 3;458,457,441;, + 3;458,441,442;, + 3;1102,458,442;, + 3;1102,442,445;, + 3;1099,1103,1097;, + 3;1099,1097,448;, + 3;461,1099,448;, + 3;461,448,451;, + 3;1104,438,437;, + 3;1104,437,1105;, + 3;441,1101,1092;, + 3;451,1084,432;, + 3;1106,452,438;, + 3;1106,438,1104;, + 3;1100,457,452;, + 3;1100,452,1106;, + 3;451,432,434;, + 3;451,434,461;, + 3;461,434,422;, + 3;461,422,456;, + 3;1107,1108,462;, + 3;1108,459,463;, + 3;1108,463,462;, + 3;463,459,1098;, + 3;464,465,466;, + 3;467,1109,1110;, + 3;468,464,1111;, + 3;469,470,471;, + 3;472,469,471;, + 3;1112,473,1113;, + 3;474,475,476;, + 3;477,474,476;, + 3;1114,1115,478;, + 3;468,1114,478;, + 3;479,465,480;, + 3;481,482,475;, + 3;474,481,475;, + 3;483,484,485;, + 3;486,483,485;, + 3;478,487,464;, + 3;468,478,464;, + 3;488,466,465;, + 3;479,488,465;, + 3;484,489,485;, + 3;1116,1117,1118;, + 3;487,490,464;, + 3;490,489,465;, + 3;464,490,465;, + 3;480,465,489;, + 3;484,480,489;, + 3;483,486,490;, + 3;487,483,490;, + 3;491,492,493;, + 3;494,491,493;, + 3;495,496,485;, + 3;489,495,485;, + 3;496,497,486;, + 3;485,496,486;, + 3;486,497,490;, + 3;490,495,489;, + 3;493,492,496;, + 3;495,493,496;, + 3;492,491,497;, + 3;496,492,497;, + 3;491,494,490;, + 3;497,491,490;, + 3;494,493,495;, + 3;490,494,495;, + 3;498,488,1112;, + 3;499,498,1112;, + 3;500,1114,468;, + 3;501,500,468;, + 3;1119,472,471;, + 3;1120,1119,471;, + 3;502,466,488;, + 3;498,502,488;, + 3;503,467,1110;, + 3;1121,503,1110;, + 3;501,468,1111;, + 3;1122,501,1111;, + 3;475,498,499;, + 3;476,475,499;, + 3;477,500,501;, + 3;474,477,501;, + 3;1123,1119,1120;, + 3;1124,1123,1120;, + 3;482,502,498;, + 3;475,482,498;, + 3;1125,503,1121;, + 3;1126,1125,1121;, + 3;474,501,1122;, + 3;481,474,1122;, + 3;504,505,506;, + 3;507,508,506;, + 3;509,510,511;, + 3;512,509,513;, + 3;507,512,514;, + 3;1127,515,516;, + 3;517,518,515;, + 3;1128,519,518;, + 3;1128,1129,519;, + 3;1130,1131,516;, + 3;1132,520,521;, + 3;1133,522,520;, + 3;1134,521,523;, + 3;1135,524,522;, + 3;1136,523,525;, + 3;1130,516,524;, + 3;1137,525,519;, + 3;1138,526,527;, + 3;1139,528,1140;, + 3;529,1141,1142;, + 3;1143,530,1144;, + 3;1138,527,1145;, + 3;1146,531,532;, + 3;533,534,1146;, + 3;1147,535,1148;, + 3;530,1147,1144;, + 3;1149,536,529;, + 3;537,536,1149;, + 3;538,537,1150;, + 3;1151,539,1152;, + 3;535,540,1153;, + 3;1154,1155,531;, + 3;541,542,543;, + 3;544,541,543;, + 3;545,541,544;, + 3;546,545,544;, + 3;547,545,546;, + 3;548,547,546;, + 3;549,547,548;, + 3;550,549,548;, + 3;551,549,550;, + 3;552,551,550;, + 3;553,551,552;, + 3;554,553,552;, + 3;555,553,554;, + 3;556,555,554;, + 3;1156,555,556;, + 3;1157,1156,556;, + 3;557,558,542;, + 3;541,557,542;, + 3;559,557,541;, + 3;545,559,541;, + 3;560,559,545;, + 3;547,560,545;, + 3;561,560,547;, + 3;549,561,547;, + 3;562,561,549;, + 3;551,562,549;, + 3;563,562,551;, + 3;553,563,551;, + 3;564,563,553;, + 3;555,564,553;, + 3;1158,564,555;, + 3;1156,1158,555;, + 3;565,566,558;, + 3;557,565,558;, + 3;561,567,560;, + 3;568,569,561;, + 3;562,568,561;, + 3;570,568,562;, + 3;563,570,562;, + 3;571,570,563;, + 3;1159,571,564;, + 3;1158,1159,564;, + 3;572,573,574;, + 3;575,572,574;, + 3;436,435,573;, + 3;572,436,573;, + 3;576,1160,1161;, + 3;577,576,1161;, + 3;578,1162,1160;, + 3;576,578,1160;, + 3;579,1163,1162;, + 3;578,579,1162;, + 3;580,1164,1163;, + 3;579,580,1163;, + 3;581,1165,1164;, + 3;580,581,1164;, + 3;582,576,577;, + 3;583,582,577;, + 3;584,578,576;, + 3;582,584,576;, + 3;585,579,578;, + 3;584,585,578;, + 3;586,580,579;, + 3;585,586,579;, + 3;587,581,580;, + 3;586,587,580;, + 3;588,582,583;, + 3;589,588,583;, + 3;590,584,582;, + 3;588,590,582;, + 3;591,585,584;, + 3;590,591,584;, + 3;592,586,585;, + 3;591,592,585;, + 3;593,587,586;, + 3;592,593,586;, + 3;569,1166,1167;, + 3;594,569,1167;, + 3;568,1168,1166;, + 3;569,568,1166;, + 3;570,1169,1168;, + 3;568,570,1168;, + 3;595,1170,1169;, + 3;570,595,1169;, + 3;571,595,570;, + 3;577,1161,1171;, + 3;596,577,1171;, + 3;583,577,596;, + 3;597,583,596;, + 3;589,583,597;, + 3;598,589,597;, + 3;566,565,599;, + 3;599,565,600;, + 3;1172,1173,601;, + 3;602,1172,601;, + 3;1167,1172,602;, + 3;594,1167,602;, + 3;557,559,565;, + 3;602,601,603;, + 3;604,602,603;, + 3;569,594,567;, + 3;561,569,567;, + 3;594,602,604;, + 3;567,594,604;, + 3;560,567,604;, + 3;559,604,565;, + 3;604,603,600;, + 3;605,1174,1175;, + 3;606,605,1175;, + 3;607,1176,1174;, + 3;605,607,1174;, + 3;608,1177,1178;, + 3;1179,608,1178;, + 3;609,1180,1177;, + 3;608,609,1177;, + 3;610,1181,1180;, + 3;609,610,1180;, + 3;611,1182,1181;, + 3;610,611,1181;, + 3;612,1183,1182;, + 3;611,612,1182;, + 3;606,1175,1184;, + 3;1185,606,1184;, + 3;613,605,606;, + 3;614,613,606;, + 3;615,607,605;, + 3;613,615,605;, + 3;616,608,1179;, + 3;1186,616,1179;, + 3;617,609,608;, + 3;616,617,608;, + 3;618,610,609;, + 3;617,618,609;, + 3;619,611,610;, + 3;618,619,610;, + 3;620,612,611;, + 3;619,620,611;, + 3;614,606,1185;, + 3;1187,614,1185;, + 3;621,1188,1189;, + 3;622,621,1189;, + 3;623,1190,1191;, + 3;1192,623,1191;, + 3;624,1193,1190;, + 3;623,624,1190;, + 3;625,1194,1195;, + 3;1196,625,1195;, + 3;626,1197,1194;, + 3;625,626,1194;, + 3;627,1198,1199;, + 3;1200,627,1199;, + 3;628,1201,1198;, + 3;627,628,1198;, + 3;622,1189,1202;, + 3;1203,622,1202;, + 3;1204,621,622;, + 3;1205,623,1192;, + 3;1206,624,623;, + 3;1207,625,1196;, + 3;1208,626,625;, + 3;1209,627,1200;, + 3;1155,628,627;, + 3;1210,622,1203;, + 3;564,571,563;, + 3;565,604,600;, + 3;533,1211,1212;, + 3;1213,1214,539;, + 3;1151,1213,539;, + 3;531,534,1154;, + 3;1140,528,526;, + 3;1138,1140,526;, + 3;534,533,1154;, + 3;1211,533,1215;, + 3;531,1146,534;, + 3;1216,504,506;, + 3;505,507,506;, + 3;513,509,511;, + 3;514,512,513;, + 3;508,507,514;, + 3;1131,1127,516;, + 3;1127,517,515;, + 3;517,1128,518;, + 3;1134,1132,521;, + 3;1132,1133,520;, + 3;1136,1134,523;, + 3;1133,1135,522;, + 3;1137,1136,525;, + 3;1135,1130,524;, + 3;1129,1137,519;, + 3;1149,529,1142;, + 3;1217,1143,1144;, + 3;1215,533,1146;, + 3;1144,1147,1148;, + 3;1150,537,1149;, + 3;1218,538,1150;, + 3;1148,535,1153;, + 3;1210,1204,622;, + 3;1219,1205,1192;, + 3;1205,1206,623;, + 3;1220,1207,1196;, + 3;1207,1208,625;, + 3;1221,1209,1200;, + 3;1209,1155,627;, + 3;1155,1210,1203;, + 3;1154,533,1212;, + 3;604,559,560;, + 3;573,629,574;, + 3;1086,630,1222;, + 3;573,435,1091;, + 3;436,572,1086;, + 3;1091,1223,629;, + 3;573,1091,629;, + 3;572,575,630;, + 3;1086,572,630;, + 3;631,629,1223;, + 3;632,631,1223;, + 3;633,1222,630;, + 3;634,633,630;, + 3;632,1223,1224;, + 3;1225,632,1224;, + 3;635,574,629;, + 3;631,635,629;, + 3;636,575,574;, + 3;635,636,574;, + 3;634,630,575;, + 3;636,634,575;, + 3;637,631,632;, + 3;638,637,632;, + 3;639,633,634;, + 3;640,639,634;, + 3;638,632,1225;, + 3;1226,638,1225;, + 3;641,635,631;, + 3;637,641,631;, + 3;642,636,635;, + 3;641,642,635;, + 3;640,634,636;, + 3;642,640,636;, + 3;643,1227,1228;, + 3;644,643,1228;, + 3;645,1229,1230;, + 3;646,645,1230;, + 3;1231,1232,1229;, + 3;645,1231,1229;, + 3;647,1233,1227;, + 3;1234,647,1227;, + 3;648,1235,1233;, + 3;647,648,1233;, + 3;646,1230,1235;, + 3;648,646,1235;, + 3;649,643,644;, + 3;650,649,644;, + 3;651,645,646;, + 3;652,651,646;, + 3;1236,1231,645;, + 3;651,1236,645;, + 3;653,647,1234;, + 3;1237,653,1234;, + 3;654,648,647;, + 3;653,654,647;, + 3;652,646,648;, + 3;654,652,648;, + 3;655,649,650;, + 3;656,655,650;, + 3;657,651,652;, + 3;658,657,652;, + 3;1238,1236,651;, + 3;657,1238,651;, + 3;659,653,1237;, + 3;655,659,1237;, + 3;660,654,653;, + 3;659,660,653;, + 3;658,652,654;, + 3;660,658,654;, + 3;661,655,656;, + 3;662,661,656;, + 3;657,663,664;, + 3;1239,1238,657;, + 3;664,1239,657;, + 3;665,659,655;, + 3;661,665,655;, + 3;666,660,659;, + 3;665,666,659;, + 3;667,658,660;, + 3;666,667,660;, + 3;1240,661,662;, + 3;1241,1240,662;, + 3;1118,663,667;, + 3;1239,1242,1243;, + 3;1244,665,661;, + 3;1240,1244,661;, + 3;1245,666,665;, + 3;1244,1245,665;, + 3;1118,667,666;, + 3;1245,1118,666;, + 3;1086,426,436;, + 3;488,479,473;, + 3;1112,488,473;, + 3;658,667,663;, + 3;657,658,663;, + 3;1117,664,663;, + 3;1118,1117,663;, + 3;664,1117,1242;, + 3;1239,664,1242;, + 3;484,483,480;, + 3;668,669,670;, + 3;668,670,671;, + 3;671,670,672;, + 3;673,674,675;, + 3;673,675,676;, + 3;1246,677,1247;, + 3;678,679,680;, + 3;678,680,681;, + 3;682,1248,1249;, + 3;682,1249,672;, + 3;683,669,684;, + 3;679,685,686;, + 3;679,686,680;, + 3;687,688,689;, + 3;687,689,690;, + 3;670,691,682;, + 3;670,682,672;, + 3;669,668,692;, + 3;669,692,684;, + 3;687,693,688;, + 3;1250,1251,1252;, + 3;670,694,691;, + 3;669,693,694;, + 3;669,694,670;, + 3;693,669,683;, + 3;693,683,688;, + 3;694,690,689;, + 3;694,689,691;, + 3;695,696,697;, + 3;695,697,698;, + 3;687,699,700;, + 3;687,700,693;, + 3;690,701,699;, + 3;690,699,687;, + 3;694,701,690;, + 3;693,700,694;, + 3;699,696,695;, + 3;699,695,700;, + 3;701,697,696;, + 3;701,696,699;, + 3;694,698,697;, + 3;694,697,701;, + 3;700,695,698;, + 3;700,698,694;, + 3;1247,692,702;, + 3;1247,702,703;, + 3;672,1249,704;, + 3;672,704,705;, + 3;673,676,1253;, + 3;673,1253,1254;, + 3;692,668,706;, + 3;692,706,702;, + 3;668,671,707;, + 3;668,707,706;, + 3;671,672,705;, + 3;671,705,707;, + 3;703,702,679;, + 3;703,679,678;, + 3;705,704,681;, + 3;705,681,680;, + 3;1254,1253,1255;, + 3;1254,1255,1256;, + 3;702,706,685;, + 3;702,685,679;, + 3;706,707,686;, + 3;706,686,685;, + 3;707,705,680;, + 3;707,680,686;, + 3;708,709,710;, + 3;708,711,712;, + 3;713,714,715;, + 3;716,715,717;, + 3;718,717,712;, + 3;719,720,1257;, + 3;720,721,722;, + 3;721,723,1258;, + 3;723,1259,1258;, + 3;719,1260,1261;, + 3;724,725,1262;, + 3;725,726,1263;, + 3;727,724,1264;, + 3;726,728,1265;, + 3;729,727,1266;, + 3;728,719,1261;, + 3;723,729,1267;, + 3;730,731,1268;, + 3;1269,732,1270;, + 3;1271,1272,733;, + 3;1273,734,1274;, + 3;1275,730,1268;, + 3;735,736,1276;, + 3;1276,737,738;, + 3;1277,739,1278;, + 3;1273,1278,734;, + 3;733,740,1279;, + 3;1279,740,741;, + 3;1280,741,742;, + 3;1281,743,1282;, + 3;1283,744,739;, + 3;736,1284,1285;, + 3;745,746,747;, + 3;745,747,748;, + 3;748,747,749;, + 3;748,749,750;, + 3;750,749,751;, + 3;750,751,752;, + 3;752,751,753;, + 3;752,753,754;, + 3;754,753,755;, + 3;754,755,756;, + 3;756,755,757;, + 3;756,757,758;, + 3;758,757,759;, + 3;758,759,760;, + 3;760,759,1286;, + 3;760,1286,1287;, + 3;746,761,762;, + 3;746,762,747;, + 3;747,762,763;, + 3;747,763,749;, + 3;749,763,764;, + 3;749,764,751;, + 3;751,764,765;, + 3;751,765,753;, + 3;753,765,766;, + 3;753,766,755;, + 3;755,766,767;, + 3;755,767,757;, + 3;757,767,768;, + 3;757,768,759;, + 3;759,768,1288;, + 3;759,1288,1286;, + 3;761,566,769;, + 3;761,769,762;, + 3;764,770,765;, + 3;765,771,772;, + 3;765,772,766;, + 3;766,772,773;, + 3;766,773,767;, + 3;767,773,571;, + 3;768,571,1159;, + 3;768,1159,1288;, + 3;774,775,776;, + 3;774,776,777;, + 3;775,462,463;, + 3;775,463,776;, + 3;1289,1290,778;, + 3;1289,778,779;, + 3;1290,1291,780;, + 3;1290,780,778;, + 3;1291,1292,781;, + 3;1291,781,780;, + 3;1292,1293,782;, + 3;1292,782,781;, + 3;1293,1165,581;, + 3;1293,581,782;, + 3;779,778,783;, + 3;779,783,784;, + 3;778,780,785;, + 3;778,785,783;, + 3;780,781,786;, + 3;780,786,785;, + 3;781,782,787;, + 3;781,787,786;, + 3;782,581,587;, + 3;782,587,787;, + 3;784,783,788;, + 3;784,788,789;, + 3;783,785,790;, + 3;783,790,788;, + 3;785,786,791;, + 3;785,791,790;, + 3;786,787,792;, + 3;786,792,791;, + 3;787,587,593;, + 3;787,593,792;, + 3;1294,1295,771;, + 3;1294,771,793;, + 3;1295,1296,772;, + 3;1295,772,771;, + 3;1296,1297,773;, + 3;1296,773,772;, + 3;1297,1170,595;, + 3;1297,595,773;, + 3;773,595,571;, + 3;1171,1289,779;, + 3;1171,779,596;, + 3;596,779,784;, + 3;596,784,597;, + 3;597,784,789;, + 3;597,789,598;, + 3;599,769,566;, + 3;600,769,599;, + 3;601,1173,1298;, + 3;601,1298,794;, + 3;794,1298,1294;, + 3;794,1294,793;, + 3;769,763,762;, + 3;603,601,794;, + 3;603,794,795;, + 3;770,793,771;, + 3;770,771,765;, + 3;795,794,793;, + 3;795,793,770;, + 3;795,770,764;, + 3;769,795,763;, + 3;600,603,795;, + 3;1299,1300,796;, + 3;1299,796,797;, + 3;1300,1301,798;, + 3;1300,798,796;, + 3;1302,1303,799;, + 3;1302,799,1304;, + 3;1303,1305,800;, + 3;1303,800,799;, + 3;1305,1306,801;, + 3;1305,801,800;, + 3;1306,1307,802;, + 3;1306,802,801;, + 3;1307,1308,803;, + 3;1307,803,802;, + 3;1309,1299,797;, + 3;1309,797,1310;, + 3;797,796,804;, + 3;797,804,805;, + 3;796,798,806;, + 3;796,806,804;, + 3;1304,799,807;, + 3;1304,807,1311;, + 3;799,800,808;, + 3;799,808,807;, + 3;800,801,809;, + 3;800,809,808;, + 3;801,802,810;, + 3;801,810,809;, + 3;802,803,811;, + 3;802,811,810;, + 3;1310,797,805;, + 3;1310,805,1312;, + 3;1313,1314,812;, + 3;1313,812,813;, + 3;1315,1316,814;, + 3;1315,814,1317;, + 3;1316,1318,815;, + 3;1316,815,814;, + 3;1319,1320,816;, + 3;1319,816,1321;, + 3;1320,1322,817;, + 3;1320,817,816;, + 3;1323,1324,818;, + 3;1323,818,1325;, + 3;1324,1326,819;, + 3;1324,819,818;, + 3;1327,1313,813;, + 3;1327,813,1328;, + 3;813,812,1329;, + 3;1317,814,1330;, + 3;814,815,1331;, + 3;1321,816,1332;, + 3;816,817,1333;, + 3;1325,818,1334;, + 3;818,819,1284;, + 3;1328,813,1335;, + 3;767,571,768;, + 3;600,795,769;, + 3;1336,1337,738;, + 3;743,1338,1339;, + 3;743,1339,1282;, + 3;1285,737,736;, + 3;731,732,1269;, + 3;731,1269,1268;, + 3;1285,738,737;, + 3;1340,738,1337;, + 3;737,1276,736;, + 3;708,710,1341;, + 3;708,712,709;, + 3;713,715,716;, + 3;716,717,718;, + 3;718,712,711;, + 3;719,1257,1260;, + 3;720,722,1257;, + 3;721,1258,722;, + 3;724,1262,1264;, + 3;725,1263,1262;, + 3;727,1264,1266;, + 3;726,1265,1263;, + 3;729,1266,1267;, + 3;728,1261,1265;, + 3;723,1267,1259;, + 3;1271,733,1279;, + 3;1273,1274,1342;, + 3;1276,738,1340;, + 3;1277,1278,1273;, + 3;1279,741,1280;, + 3;1280,742,1343;, + 3;1283,739,1277;, + 3;813,1329,1335;, + 3;1317,1330,1344;, + 3;814,1331,1330;, + 3;1321,1332,1345;, + 3;816,1333,1332;, + 3;1325,1334,1346;, + 3;818,1284,1334;, + 3;1328,1335,1284;, + 3;1336,738,1285;, + 3;764,763,795;, + 3;774,820,775;, + 3;1347,821,1098;, + 3;1107,462,775;, + 3;1098,776,463;, + 3;820,1348,1107;, + 3;820,1107,775;, + 3;821,777,776;, + 3;821,776,1098;, + 3;1348,820,822;, + 3;1348,822,823;, + 3;821,1347,824;, + 3;821,824,825;, + 3;1349,1348,823;, + 3;1349,823,1350;, + 3;820,774,826;, + 3;820,826,822;, + 3;774,777,827;, + 3;774,827,826;, + 3;777,821,825;, + 3;777,825,827;, + 3;823,822,828;, + 3;823,828,829;, + 3;825,824,830;, + 3;825,830,831;, + 3;1350,823,829;, + 3;1350,829,1351;, + 3;822,826,832;, + 3;822,832,828;, + 3;826,827,833;, + 3;826,833,832;, + 3;827,825,831;, + 3;827,831,833;, + 3;1352,1353,834;, + 3;1352,834,835;, + 3;1354,1355,836;, + 3;1354,836,837;, + 3;1355,1356,1357;, + 3;1355,1357,836;, + 3;1353,1358,838;, + 3;1353,838,1359;, + 3;1358,1360,839;, + 3;1358,839,838;, + 3;1360,1354,837;, + 3;1360,837,839;, + 3;835,834,840;, + 3;835,840,841;, + 3;837,836,842;, + 3;837,842,843;, + 3;836,1357,1361;, + 3;836,1361,842;, + 3;1359,838,844;, + 3;1359,844,1362;, + 3;838,839,845;, + 3;838,845,844;, + 3;839,837,843;, + 3;839,843,845;, + 3;841,840,846;, + 3;841,846,847;, + 3;843,842,848;, + 3;843,848,849;, + 3;842,1361,1363;, + 3;842,1363,848;, + 3;1362,844,850;, + 3;1362,850,846;, + 3;844,845,851;, + 3;844,851,850;, + 3;845,843,849;, + 3;845,849,851;, + 3;847,846,852;, + 3;847,852,853;, + 3;854,855,848;, + 3;848,1363,1364;, + 3;848,1364,854;, + 3;846,850,856;, + 3;846,856,852;, + 3;850,851,857;, + 3;850,857,856;, + 3;851,849,858;, + 3;851,858,857;, + 3;853,852,1365;, + 3;853,1365,1366;, + 3;858,855,1250;, + 3;1367,1368,1364;, + 3;852,856,1369;, + 3;852,1369,1365;, + 3;856,857,1370;, + 3;856,1370,1369;, + 3;857,858,1250;, + 3;857,1250,1370;, + 3;677,684,692;, + 3;677,692,1247;, + 3;855,858,849;, + 3;855,849,848;, + 3;855,854,1251;, + 3;855,1251,1250;, + 3;1368,1251,854;, + 3;1368,854,1364;, + 3;683,689,688;, + 3;859,860,861;, + 3;862,859,861;, + 3;862,861,863;, + 3;864,862,863;, + 3;864,863,865;, + 3;866,864,865;, + 3;866,865,867;, + 3;868,866,867;, + 3;868,867,869;, + 3;870,868,869;, + 3;870,869,871;, + 3;872,870,871;, + 3;872,871,873;, + 3;874,872,873;, + 3;875,876,877;, + 3;878,875,877;, + 3;879,880,877;, + 3;880,881,878;, + 3;880,878,877;, + 3;880,863,861;, + 3;879,873,871;, + 3;879,871,869;, + 3;880,879,869;, + 3;880,869,867;, + 3;880,867,865;, + 3;880,865,863;, + 3;880,861,881;, + 3;881,861,860;, + 3;882,883,859;, + 3;862,882,859;, + 3;884,882,862;, + 3;864,884,862;, + 3;885,884,864;, + 3;866,885,864;, + 3;886,885,866;, + 3;868,886,866;, + 3;887,886,868;, + 3;870,887,868;, + 3;888,887,870;, + 3;872,888,870;, + 3;889,888,872;, + 3;874,889,872;, + 3;890,891,892;, + 3;893,890,892;, + 3;890,894,895;, + 3;893,896,894;, + 3;890,893,894;, + 3;882,884,894;, + 3;888,889,895;, + 3;887,888,895;, + 3;894,887,895;, + 3;886,887,894;, + 3;885,886,894;, + 3;884,885,894;, + 3;896,882,894;, + 3;883,882,896;, + 3;1371,1372,1373;, + 3;1374,1375,1376;, + 3;1377,1378,1379;, + 3;1380,1377,1379;, + 3;1381,1382,1378;, + 3;1377,1381,1378;, + 3;1380,1379,1383;, + 3;1384,1380,1383;, + 3;1385,1386,1382;, + 3;1381,1385,1382;, + 3;1384,1383,1387;, + 3;1388,1384,1387;, + 3;1374,1376,1386;, + 3;1385,1374,1386;, + 3;1388,1387,1372;, + 3;1371,1388,1372;, + 3;897,898,899;, + 3;900,901,1389;, + 3;1390,900,1389;, + 3;902,903,904;, + 3;905,897,899;, + 3;906,900,1390;, + 3;1391,906,1390;, + 3;907,903,902;, + 3;908,905,899;, + 3;909,906,1391;, + 3;1392,909,1391;, + 3;910,903,907;, + 3;911,908,899;, + 3;912,909,1392;, + 3;1393,912,1392;, + 3;913,903,910;, + 3;914,911,899;, + 3;915,912,1393;, + 3;1394,915,1393;, + 3;916,903,913;, + 3;917,914,899;, + 3;918,915,1394;, + 3;1395,918,1394;, + 3;919,903,916;, + 3;920,917,899;, + 3;921,1396,1397;, + 3;1398,921,1397;, + 3;922,903,919;, + 3;898,920,899;, + 3;901,921,1398;, + 3;1389,901,1398;, + 3;904,903,922;, + 3;923,924,925;, + 3;926,923,925;, + 3;927,923,926;, + 3;928,927,926;, + 3;929,927,928;, + 3;930,929,928;, + 3;931,929,930;, + 3;932,931,930;, + 3;933,931,932;, + 3;934,933,932;, + 3;935,933,934;, + 3;936,935,934;, + 3;937,1399,1400;, + 3;938,937,1400;, + 3;924,937,938;, + 3;925,924,938;, + 3;939,940,941;, + 3;942,939,941;, + 3;943,939,942;, + 3;944,943,942;, + 3;945,943,944;, + 3;946,945,944;, + 3;947,945,946;, + 3;948,947,946;, + 3;949,947,948;, + 3;950,949,948;, + 3;951,949,950;, + 3;952,951,950;, + 3;953,1401,1402;, + 3;954,953,1402;, + 3;940,953,954;, + 3;941,940,954;, + 3;1403,1404,955;, + 3;956,1403,955;, + 3;1405,1403,956;, + 3;957,1405,956;, + 3;1406,1405,957;, + 3;958,1406,957;, + 3;1407,1406,958;, + 3;959,1407,958;, + 3;1408,1407,959;, + 3;960,1408,959;, + 3;1409,1408,960;, + 3;961,1409,960;, + 3;1410,1411,1412;, + 3;962,1410,1412;, + 3;1404,1410,962;, + 3;955,1404,962;, + 3;963,964,965;, + 3;966,963,965;, + 3;967,963,966;, + 3;968,967,966;, + 3;969,967,968;, + 3;970,969,968;, + 3;971,969,970;, + 3;972,971,970;, + 3;973,971,972;, + 3;974,973,972;, + 3;975,973,974;, + 3;976,975,974;, + 3;977,1413,1414;, + 3;978,977,1414;, + 3;964,977,978;, + 3;965,964,978;, + 3;1415,1416,1417;, + 3;1418,1415,1417;, + 3;1419,1420,1421;, + 3;1422,1419,1421;, + 3;1423,1424,1416;, + 3;1415,1423,1416;, + 3;1422,1421,1425;, + 3;1426,1422,1425;, + 3;1427,1428,1424;, + 3;1423,1427,1424;, + 3;1426,1425,1429;, + 3;1430,1426,1429;, + 3;1431,1432,1428;, + 3;1427,1431,1428;, + 3;1430,1429,1433;, + 3;1434,1430,1433;, + 3;1435,1436,1432;, + 3;1431,1435,1432;, + 3;1434,1433,1437;, + 3;1438,1434,1437;, + 3;1439,1440,1436;, + 3;1435,1439,1436;, + 3;1438,1437,1441;, + 3;1442,1438,1441;, + 3;1443,1444,1440;, + 3;1439,1443,1440;, + 3;1442,1441,1445;, + 3;1446,1442,1445;, + 3;1418,1417,1444;, + 3;1443,1418,1444;, + 3;1446,1445,1420;, + 3;1419,1446,1420;, + 3;1447,1448,1449;, + 3;1450,1447,1449;, + 3;1451,1452,1453;, + 3;1454,1451,1453;, + 3;1455,1456,1448;, + 3;1447,1455,1448;, + 3;1454,1453,1457;, + 3;1458,1454,1457;, + 3;1459,1460,1456;, + 3;1455,1459,1456;, + 3;1458,1457,1461;, + 3;1462,1458,1461;, + 3;1463,1464,1460;, + 3;1459,1463,1460;, + 3;1462,1461,1465;, + 3;1466,1462,1465;, + 3;1467,1468,1464;, + 3;1463,1467,1464;, + 3;1466,1465,1469;, + 3;1470,1466,1469;, + 3;1471,1472,1468;, + 3;1467,1471,1468;, + 3;1470,1469,1473;, + 3;1474,1470,1473;, + 3;1475,1476,1472;, + 3;1471,1475,1472;, + 3;1474,1473,1477;, + 3;1478,1474,1477;, + 3;1450,1449,1476;, + 3;1475,1450,1476;, + 3;1478,1477,1452;, + 3;1451,1478,1452;; + + MeshNormals + { + 979; + -0.129816;-0.852990;-0.505525;, + 0.036964;-0.991876;-0.121718;, + -0.698699;-0.688078;-0.195877;, + -0.708337;-0.651960;-0.270567;, + -0.006954;-0.960460;0.278330;, + -0.700324;-0.650018;0.294997;, + 0.302430;-0.952051;0.046201;, + -0.276584;-0.929242;-0.244971;, + 0.094428;0.853934;0.511742;, + 0.336283;-0.009104;0.941717;, + 0.556489;-0.055914;0.828972;, + 0.759730;0.498962;0.416950;, + 0.034747;0.947415;-0.318114;, + 0.731470;0.541587;-0.414288;, + 0.105400;0.061590;-0.992521;, + 0.621131;-0.303408;-0.722592;, + 0.541167;-0.749736;0.380833;, + -0.709843;0.544304;0.447052;, + -0.207902;-0.308447;0.928244;, + 0.546967;-0.813260;-0.198582;, + -0.735620;0.642658;-0.214135;, + 0.607416;-0.793959;-0.025956;, + -0.702457;0.230287;-0.673440;, + 0.609483;-0.790811;-0.056108;, + 0.698700;-0.688078;-0.195877;, + -0.036964;-0.991876;-0.121718;, + 0.129816;-0.852990;-0.505525;, + 0.708337;-0.651961;-0.270567;, + 0.006954;-0.960460;0.278330;, + 0.700323;-0.650018;0.294997;, + -0.302430;-0.952051;0.046201;, + 0.276584;-0.929242;-0.244970;, + -0.556488;-0.055914;0.828972;, + -0.336283;-0.009104;0.941717;, + -0.094428;0.853934;0.511742;, + -0.759730;0.498962;0.416950;, + -0.034747;0.947415;-0.318114;, + -0.731472;0.541585;-0.414288;, + -0.105400;0.061590;-0.992521;, + -0.621131;-0.303409;-0.722592;, + -0.541168;-0.749736;0.380833;, + 0.709843;0.544305;0.447052;, + 0.207903;-0.308447;0.928244;, + -0.546967;-0.813260;-0.198581;, + 0.735620;0.642658;-0.214134;, + -0.607415;-0.793960;-0.025956;, + 0.702458;0.230287;-0.673439;, + -0.609482;-0.790812;-0.056107;, + 0.715168;-0.546642;0.435566;, + 0.174589;-0.765639;0.619125;, + 0.311507;-0.029519;0.949785;, + 0.802549;-0.063801;0.593165;, + 0.674954;-0.705769;0.215238;, + 0.965425;-0.079199;0.248359;, + 0.989682;-0.086167;0.114472;, + 0.589572;-0.802548;0.091222;, + 0.222087;-0.142281;-0.964590;, + 0.239432;-0.628781;-0.739802;, + 0.451846;-0.276668;-0.848110;, + 0.400719;-0.107309;-0.909895;, + 0.345620;-0.589510;-0.730086;, + 0.552622;-0.313025;-0.772414;, + 0.714052;-0.151501;-0.683504;, + -0.111976;0.059755;-0.991913;, + 0.000000;-0.303073;-0.952967;, + 0.408905;-0.168156;-0.896951;, + -0.008987;0.245821;-0.969274;, + 0.637596;0.116274;-0.761545;, + 0.862761;-0.168404;-0.476742;, + 0.607110;0.434795;-0.665110;, + 0.093622;-0.452750;-0.886709;, + 0.454447;-0.542535;-0.706493;, + 0.433850;-0.537110;-0.723386;, + 0.668027;-0.011998;-0.744040;, + 0.770806;0.495623;-0.400270;, + 0.695970;-0.572016;-0.434078;, + 0.452755;-0.608582;-0.651645;, + 0.678173;0.659980;-0.323276;, + 0.561443;-0.626268;-0.540898;, + 0.695491;-0.680703;-0.230080;, + 0.320057;-0.465858;-0.824948;, + 0.015522;-0.721373;-0.692373;, + 0.025936;-0.639799;-0.768104;, + 0.267999;-0.896130;-0.353734;, + 0.429871;0.677744;-0.596552;, + 0.870887;0.286101;-0.399627;, + 0.899576;0.029925;-0.435739;, + 0.877351;-0.421108;0.230049;, + 0.727191;0.647472;0.227974;, + 0.251564;-0.085554;-0.964052;, + 0.443688;0.461641;-0.768133;, + 0.574683;-0.083305;-0.814125;, + 0.736077;0.391009;-0.552541;, + 0.899391;-0.211232;-0.382723;, + 0.958834;0.021238;-0.283171;, + 0.746330;-0.655766;-0.113851;, + 0.972458;-0.091984;-0.214160;, + 0.939346;-0.154664;-0.306116;, + 0.394895;-0.519206;-0.757947;, + 0.079536;-0.698997;-0.710688;, + 0.793478;0.264078;-0.548321;, + 0.593612;0.315377;-0.740379;, + 0.122186;-0.410372;-0.903696;, + -0.025452;0.456614;-0.889301;, + 0.117224;0.694033;-0.710336;, + 0.364145;0.733069;-0.574464;, + 0.345959;-0.296498;-0.890169;, + -0.135622;-0.348879;-0.927303;, + 0.466699;0.709807;-0.527604;, + 0.226468;-0.163193;-0.960250;, + 0.506498;0.620402;-0.598799;, + 0.485375;0.342365;-0.804486;, + 0.470753;0.400109;-0.786323;, + -0.507537;-0.402332;-0.761929;, + 0.800830;0.191458;-0.567463;, + 0.889577;0.287018;-0.355350;, + 0.266019;0.013318;-0.963876;, + -0.642198;0.006037;-0.766515;, + 0.425486;0.746189;-0.512018;, + 0.409779;0.681736;-0.606067;, + -0.058171;0.604638;-0.794374;, + 0.508624;0.701385;-0.499359;, + 0.286727;-0.054946;-0.956435;, + -0.316097;0.145690;-0.937474;, + -0.114483;-0.612880;-0.781838;, + -0.732130;-0.218041;-0.645325;, + -0.077040;0.341658;-0.936662;, + 0.982790;0.168633;-0.075412;, + 0.736791;0.340065;-0.584375;, + -0.327315;-0.220940;-0.918722;, + -0.356933;-0.916762;-0.179292;, + 0.858059;0.295560;-0.419974;, + 0.982755;-0.116030;0.143980;, + 0.686546;-0.436660;0.581362;, + -0.114684;-0.032216;-0.992880;, + -0.610499;-0.792017;0.000055;, + 0.997650;0.023444;-0.064385;, + 0.994914;-0.019735;0.098779;, + 0.607825;0.764607;-0.214302;, + 0.169187;0.272448;0.947179;, + -0.308242;0.468162;-0.828137;, + -0.945384;-0.259556;0.197182;, + 0.724385;0.622190;-0.296892;, + 0.338665;0.069750;0.938318;, + -0.281176;0.325935;-0.902611;, + -0.944702;-0.225837;0.237773;, + 0.943751;0.081290;-0.320510;, + 0.309733;-0.452451;0.836274;, + 0.122451;-0.025404;-0.992149;, + -0.820495;-0.556147;-0.132241;, + 0.521386;-0.621684;-0.584522;, + 0.000004;-0.667404;0.744696;, + 0.000000;0.082569;0.996585;, + 0.955176;-0.093355;0.280935;, + 0.907373;-0.032566;0.419063;, + 0.017997;0.304606;0.952308;, + 0.611072;0.197838;0.766453;, + 0.839507;0.190096;0.509010;, + 0.969844;0.099854;0.222331;, + 0.141318;0.262440;0.954544;, + 0.596370;0.185083;0.781081;, + 0.866160;0.114817;0.486400;, + 0.988906;0.103392;0.106655;, + 0.988842;0.100552;0.109915;, + 0.000104;-0.599228;0.800578;, + 0.173663;-0.620057;0.765095;, + 0.570753;-0.654192;0.496260;, + 0.741579;-0.628361;0.234997;, + 0.750948;-0.640212;0.161879;, + 0.775887;-0.622672;-0.101386;, + 0.726861;-0.637107;-0.256451;, + 0.518488;-0.628231;-0.580083;, + 0.282637;-0.599455;-0.748846;, + 0.039464;-0.606899;-0.793799;, + 0.000173;0.124733;0.992190;, + 0.273998;0.111428;0.955253;, + 0.810070;0.159410;0.564247;, + 0.923389;0.204059;0.325134;, + 0.963267;0.228823;0.140559;, + 0.961478;0.230312;-0.150056;, + 0.893601;0.214711;-0.394178;, + 0.628384;0.178155;-0.757228;, + 0.365227;0.121643;-0.922937;, + -0.008183;0.142392;-0.989776;, + 0.000103;0.483720;0.875223;, + 0.277107;0.511871;0.813142;, + 0.698315;0.579992;0.419483;, + 0.784868;0.562838;0.259223;, + 0.803441;0.586284;0.103699;, + 0.816344;0.565091;-0.119395;, + 0.765667;0.558811;-0.318567;, + 0.582400;0.519613;-0.625150;, + 0.339503;0.496872;-0.798658;, + -0.010072;0.503689;-0.863826;, + -0.000170;0.838829;0.544394;, + 0.209122;0.860779;0.464035;, + 0.472183;0.850685;0.231037;, + 0.524210;0.831400;0.184332;, + 0.548334;0.835391;0.038098;, + 0.560725;0.823931;-0.082001;, + 0.493044;0.839080;-0.229897;, + 0.356599;0.845126;-0.398246;, + 0.193906;0.838344;-0.509490;, + -0.030005;0.838012;-0.544826;, + 0.000000;0.999889;-0.014920;, + -0.247610;-0.617187;0.746839;, + -0.640144;-0.698513;0.319837;, + -0.845216;-0.109792;0.523025;, + -0.332309;0.120583;0.935431;, + -0.951232;-0.100313;0.291711;, + -0.607708;-0.765854;0.210140;, + -0.794975;-0.601716;0.077149;, + -0.992358;-0.084286;0.090118;, + -0.540786;-0.310747;-0.781657;, + -0.243635;-0.604159;-0.758705;, + -0.239575;-0.129408;-0.962215;, + -0.457699;-0.311417;-0.832785;, + -0.601820;-0.346641;-0.719481;, + -0.372432;-0.542919;-0.752685;, + -0.727575;-0.138985;-0.671802;, + -0.462077;-0.172950;-0.869812;, + -0.526055;0.267394;-0.807321;, + -0.889688;-0.200487;-0.410196;, + -0.661906;0.183020;-0.726900;, + -0.482780;-0.428287;-0.763868;, + -0.368326;-0.722170;-0.585497;, + -0.844542;0.459938;-0.274236;, + -0.681525;0.387393;-0.620847;, + -0.605303;-0.397304;-0.689752;, + -0.673388;-0.491201;-0.552514;, + -0.657816;0.645924;-0.387376;, + -0.662135;-0.671377;-0.332913;, + -0.486791;-0.582794;-0.650681;, + -0.258785;-0.568614;-0.780839;, + -0.513083;0.131989;-0.848130;, + -0.297505;-0.905023;-0.304014;, + -0.895981;0.262607;-0.358127;, + -0.675033;0.466963;-0.571206;, + -0.901019;0.266881;0.341965;, + -0.680425;-0.732688;-0.013786;, + -0.259518;-0.023921;-0.965442;, + -0.514018;0.532502;-0.672478;, + -0.645404;-0.118674;-0.754566;, + -0.641496;0.340399;-0.687468;, + -0.875472;-0.233593;-0.423064;, + -0.941780;-0.006383;-0.336169;, + -0.729762;-0.674587;-0.111267;, + -0.974729;-0.092161;-0.203496;, + -0.948685;-0.159768;-0.272894;, + -0.413516;-0.551069;-0.724795;, + -0.452430;-0.424111;-0.784497;, + -0.633631;0.387785;-0.669429;, + -0.759347;0.388122;-0.522258;, + -0.349670;0.699505;-0.623236;, + -0.367983;-0.326177;-0.870745;, + -0.426287;0.691018;-0.583758;, + 0.024608;-0.361630;-0.931997;, + -0.506095;0.593595;-0.625710;, + 0.205299;-0.327376;-0.922321;, + -0.019213;0.001677;-0.999814;, + -0.592122;0.499030;-0.632740;, + -0.705863;0.322617;-0.630616;, + -0.858342;0.333085;-0.390262;, + 0.520378;-0.115323;-0.846113;, + -0.098311;0.739985;-0.665400;, + -0.505485;0.718564;-0.477651;, + -0.429291;0.753222;-0.498363;, + -0.436628;0.579844;-0.687850;, + -0.018955;0.315468;-0.948747;, + 0.628680;-0.297343;-0.718574;, + 0.340473;0.081313;-0.936732;, + -0.987372;0.150062;-0.050767;, + -0.879193;0.307819;-0.363685;, + -0.071334;0.098893;-0.992538;, + 0.552973;-0.594293;-0.583984;, + -0.838304;0.391818;-0.379111;, + -0.660024;-0.355125;0.662008;, + -0.878202;-0.379715;0.290821;, + 0.063977;0.037528;-0.997245;, + 0.565936;-0.819042;-0.094270;, + -0.991440;0.023648;-0.128400;, + -0.999073;0.010052;0.041867;, + -0.576121;0.786004;-0.224237;, + -0.253102;0.252826;0.933819;, + 0.335569;0.443367;-0.831155;, + 0.943943;-0.232201;0.234638;, + -0.746213;0.592914;-0.302686;, + -0.189845;0.217076;0.957516;, + 0.237934;0.300377;-0.923667;, + 0.932614;-0.306696;0.190181;, + -0.854338;0.099672;-0.510071;, + -0.759448;-0.294301;0.580194;, + 0.213648;-0.150954;-0.965177;, + 0.739086;-0.584441;0.334935;, + -0.521385;-0.621686;-0.584521;, + -0.921296;-0.000592;0.388863;, + -0.962588;-0.092104;0.254837;, + -0.643832;0.151144;0.750091;, + -0.980272;0.070344;0.184714;, + -0.849418;0.188211;0.493017;, + -0.517473;0.220460;0.826812;, + -0.775120;0.146862;0.614508;, + -0.979260;0.103055;0.174438;, + -0.988842;0.100551;0.109916;, + -0.257131;-0.613480;0.746677;, + -0.655025;-0.643192;0.396543;, + -0.729698;-0.628342;0.269680;, + -0.767211;-0.638569;0.060144;, + -0.773397;-0.623118;-0.116540;, + -0.694093;-0.641310;-0.327041;, + -0.455929;-0.638307;-0.620236;, + -0.253991;-0.603628;-0.755726;, + -0.290181;0.120439;0.949363;, + -0.790874;0.202403;0.577539;, + -0.923458;0.210735;0.320651;, + -0.959298;0.234558;0.157257;, + -0.963277;0.224319;-0.147576;, + -0.900844;0.202218;-0.384172;, + -0.646321;0.146493;-0.748871;, + -0.336180;0.122826;-0.933754;, + -0.268545;0.501480;0.822436;, + -0.701566;0.531626;0.474529;, + -0.791663;0.556265;0.252664;, + -0.805765;0.578042;0.128881;, + -0.812528;0.571712;-0.113773;, + -0.760729;0.577526;-0.296236;, + -0.589180;0.554444;-0.587757;, + -0.331045;0.502521;-0.798675;, + -0.118111;0.855986;0.503326;, + -0.413323;0.856582;0.308919;, + -0.532739;0.831452;0.157727;, + -0.535078;0.837140;0.113529;, + -0.562623;0.823042;-0.077821;, + -0.522170;0.835158;-0.172769;, + -0.396124;0.843506;-0.362744;, + -0.243647;0.844427;-0.477053;, + -0.585560;-0.168913;0.792836;, + -0.979025;-0.171040;-0.110706;, + -0.868505;-0.466650;0.167143;, + -0.289501;-0.466650;0.835720;, + 0.000148;0.999994;-0.003359;, + 0.394045;-0.169028;0.903414;, + 0.579005;-0.466650;0.668574;, + 0.979037;-0.171271;0.110238;, + 0.868506;-0.466648;-0.167143;, + 0.584817;-0.173401;-0.792415;, + 0.289503;-0.466649;-0.835719;, + -0.393644;-0.173286;-0.902783;, + -0.579003;-0.466649;-0.668576;, + -0.130098;0.890443;0.436104;, + -0.236889;0.850100;-0.470334;, + -0.175642;0.968564;-0.176161;, + -0.060805;0.637960;0.767665;, + 0.235836;0.103418;0.966274;, + 0.172266;-0.360525;0.916704;, + 0.503507;-0.734161;0.455509;, + 0.250506;-0.953163;0.169488;, + 0.379678;-0.782095;-0.494138;, + 0.086510;-0.635228;-0.767464;, + -0.026852;0.043388;-0.998697;, + -0.120815;0.369417;-0.921377;, + -0.615710;0.743650;-0.260549;, + -0.318016;0.682023;0.658567;, + 0.454590;0.074146;0.887610;, + 0.872061;-0.456119;0.177383;, + 0.544687;-0.374159;-0.750547;, + -0.205593;0.244510;-0.947600;, + -0.947918;0.318514;-0.000749;, + -0.382719;0.448240;0.807841;, + 0.611759;0.246959;0.751507;, + 0.993888;-0.069640;-0.085659;, + 0.432662;-0.176959;-0.884019;, + -0.548317;0.022330;-0.835973;, + -0.007283;0.942541;-0.334010;, + 0.175641;0.968564;-0.176163;, + 0.236889;0.850100;-0.470334;, + 0.130099;0.890443;0.436103;, + 0.060805;0.637960;0.767665;, + -0.235836;0.103418;0.966274;, + -0.172267;-0.360525;0.916704;, + -0.503507;-0.734161;0.455508;, + -0.250507;-0.953164;0.169486;, + -0.379678;-0.782095;-0.494138;, + -0.086509;-0.635227;-0.767465;, + 0.026852;0.043389;-0.998697;, + 0.120815;0.369418;-0.921376;, + 0.615711;0.743650;-0.260548;, + 0.318016;0.682023;0.658567;, + -0.454590;0.074146;0.887609;, + -0.872061;-0.456119;0.177385;, + -0.544687;-0.374159;-0.750547;, + 0.205595;0.244511;-0.947600;, + 0.947918;0.318513;-0.000749;, + 0.382720;0.448240;0.807841;, + -0.611758;0.246959;0.751507;, + -0.993888;-0.069640;-0.085659;, + -0.432660;-0.176959;-0.884020;, + 0.548319;0.022332;-0.835971;, + 0.007296;0.942541;-0.334010;, + 0.326102;-0.301915;0.895826;, + 0.290390;0.081714;0.953413;, + 0.282586;0.359266;0.889423;, + 0.732955;0.505070;0.455721;, + 0.196255;0.976233;0.091942;, + 0.000000;0.983658;-0.180048;, + 0.092154;0.912052;0.399586;, + 0.685876;-0.491759;-0.536421;, + 0.803250;0.595471;-0.014278;, + 0.173689;0.943714;-0.281490;, + 0.755928;0.238778;-0.609556;, + 0.573852;0.647817;-0.501026;, + 0.218078;0.832084;-0.509980;, + 0.273387;0.254330;-0.927672;, + 0.177185;0.758963;-0.626563;, + 0.152142;0.771846;-0.617338;, + 0.000000;0.507928;-0.861399;, + -0.000000;0.336033;-0.941850;, + 0.302092;0.176073;0.936877;, + 0.240533;0.336563;0.910422;, + 0.663467;0.421496;-0.618184;, + 0.427727;0.228952;-0.874432;, + 0.230252;0.500003;-0.834854;, + 0.000000;0.578617;-0.815600;, + 0.307879;0.805978;0.505580;, + 0.145346;0.598582;0.787765;, + 0.405591;0.657823;-0.634638;, + 0.402621;0.826286;-0.393887;, + 0.226398;0.640557;-0.733779;, + 0.000000;0.846676;0.532109;, + 0.000000;0.512865;0.858469;, + 0.000000;0.063273;0.997996;, + 0.000000;0.457798;0.889057;, + -0.000000;0.804821;-0.593518;, + -0.000000;0.248350;0.968670;, + 0.000000;0.609069;-0.793118;, + 0.227767;0.807947;0.543456;, + 0.281507;0.877647;-0.387930;, + -0.282586;0.359266;0.889423;, + -0.290390;0.081714;0.953413;, + -0.326102;-0.301915;0.895826;, + -0.732955;0.505070;0.455721;, + -0.092154;0.912052;0.399586;, + -0.196255;0.976233;0.091942;, + -0.685876;-0.491759;-0.536421;, + -0.803250;0.595471;-0.014278;, + -0.173689;0.943714;-0.281490;, + -0.755928;0.238778;-0.609556;, + -0.573852;0.647817;-0.501026;, + -0.218077;0.832084;-0.509980;, + -0.273387;0.254330;-0.927672;, + -0.177185;0.758963;-0.626563;, + -0.152141;0.771846;-0.617338;, + -0.240533;0.336564;0.910422;, + -0.302092;0.176073;0.936877;, + -0.427727;0.228952;-0.874432;, + -0.663467;0.421497;-0.618184;, + -0.230252;0.500003;-0.834854;, + -0.145346;0.598582;0.787765;, + -0.307879;0.805978;0.505580;, + -0.402622;0.826286;-0.393887;, + -0.405591;0.657823;-0.634638;, + -0.226397;0.640557;-0.733779;, + -0.227767;0.807947;0.543456;, + -0.281507;0.877647;-0.387931;, + -0.519282;-0.801856;-0.295590;, + 0.628811;0.048486;-0.776045;, + 0.075597;0.061964;-0.995211;, + -0.768733;-0.464430;-0.439722;, + -0.776444;-0.621408;0.104819;, + -0.008636;0.241742;0.970302;, + -0.519681;-0.462756;0.718184;, + -0.392286;-0.395655;0.830403;, + 0.606488;0.362636;0.707578;, + 0.634201;0.590890;0.498637;, + -0.532226;-0.846074;0.029908;, + 0.733299;-0.679627;0.019472;, + 0.395655;-0.688028;0.608338;, + -0.626298;-0.623654;0.467767;, + -0.615564;-0.788001;-0.011651;, + 0.737398;0.614678;-0.280025;, + -0.020657;0.352402;-0.935621;, + -0.283460;-0.739558;-0.610496;, + 0.671011;-0.430239;-0.603853;, + -0.978692;0.134618;-0.155050;, + -0.093467;0.573633;-0.813763;, + -0.077464;0.247205;-0.965862;, + -0.990913;0.025340;-0.132096;, + -0.772378;-0.597866;-0.214449;, + 0.872971;0.472486;-0.121157;, + 0.815150;0.020096;-0.578901;, + -0.017212;-0.667549;0.744367;, + -0.025443;-0.997470;0.066387;, + 0.063832;-0.326004;-0.943211;, + 0.938699;-0.157979;-0.306408;, + 0.658994;-0.420980;0.623300;, + 0.999001;-0.033016;-0.030116;, + 0.005130;0.183809;-0.982949;, + -0.933054;-0.303730;-0.192764;, + 0.991412;0.128365;-0.025012;, + 0.649195;-0.068635;0.757519;, + -0.555420;-0.356113;0.751460;, + -0.937074;-0.338487;0.085549;, + 0.447515;0.045262;-0.893130;, + -0.705682;-0.354669;-0.613370;, + -0.592644;-0.622931;0.510618;, + -0.752771;-0.619673;-0.222128;, + 0.720371;-0.617368;-0.316104;, + -0.683253;-0.627919;-0.372670;, + 0.769514;-0.558111;-0.310419;, + -0.562589;-0.760251;-0.324828;, + -0.204878;-0.344714;-0.916077;, + 0.446447;-0.607871;-0.656642;, + -0.711056;-0.698405;0.081424;, + 0.643951;-0.736522;-0.207031;, + 0.686779;-0.713298;0.139789;, + -0.413593;0.147648;0.898410;, + -0.990075;-0.050814;0.131034;, + 0.321552;-0.282128;0.903885;, + 0.624392;0.208123;0.752874;, + 0.996072;0.072527;0.050800;, + -0.386575;0.167860;-0.906853;, + 0.318836;0.181672;-0.930236;, + -0.965362;0.116386;-0.233516;, + 0.885875;0.093258;-0.454453;, + -0.998737;-0.000577;-0.050239;, + 0.997215;0.069558;-0.026922;, + -0.059927;0.707805;-0.703861;, + 0.750455;0.543429;-0.376168;, + -0.617940;0.665192;-0.419130;, + -0.803206;0.582659;-0.123972;, + 0.704325;0.662368;-0.255334;, + 0.082622;0.499858;-0.862158;, + 0.931934;0.103939;-0.347414;, + -0.027959;0.981500;-0.189407;, + -0.050360;0.933873;-0.354042;, + 0.981209;0.015725;0.192306;, + -0.827387;-0.039311;-0.560255;, + -0.986340;-0.131712;-0.098922;, + -0.787094;-0.082947;0.611231;, + -0.006351;0.094118;0.995541;, + 0.498810;0.079278;0.863078;, + -0.740122;-0.312903;0.595240;, + -0.938230;-0.345002;0.026413;, + -0.993493;0.048503;0.103045;, + -0.673953;0.185181;0.715189;, + -0.108392;-0.207274;0.972260;, + 0.051154;0.195171;0.979434;, + 0.639562;-0.102929;0.761818;, + 0.704736;0.180554;0.686111;, + 0.998869;-0.047538;-0.000576;, + 0.958935;0.173981;-0.223994;, + 0.698266;-0.181001;-0.692577;, + 0.620972;0.089948;-0.778655;, + 0.016398;-0.443063;-0.896341;, + -0.144390;-0.065290;-0.987365;, + -0.728851;-0.441912;-0.522963;, + -0.871827;-0.033825;-0.488645;, + -0.626805;-0.572093;0.528985;, + -0.871386;-0.490489;0.010370;, + -0.076929;-0.452265;0.888559;, + 0.626649;-0.191510;0.755404;, + 0.998179;0.029379;0.052680;, + 0.721135;-0.035727;-0.691873;, + 0.076054;-0.310273;-0.947600;, + -0.686595;-0.525811;-0.502105;, + -0.330716;-0.736732;0.589791;, + -0.000000;-0.999826;-0.018662;, + 0.814386;0.118924;0.568007;, + 0.793032;-0.131439;-0.594831;, + 0.983958;0.171788;0.048122;, + 0.282352;-0.374795;-0.883066;, + -0.000000;-0.704137;-0.710064;, + 0.479848;0.732180;-0.483382;, + 0.372803;0.739708;0.560223;, + 0.661563;0.611093;0.434626;, + 0.699606;0.569916;-0.430984;, + 0.710696;0.422097;0.562801;, + 0.295926;0.387851;0.872926;, + 0.837365;0.545835;0.029727;, + 0.634042;0.611621;-0.473192;, + 0.202625;0.600191;-0.773766;, + 0.000000;0.760465;-0.649379;, + 0.746427;-0.359817;0.559803;, + 0.315278;-0.350053;0.882078;, + 0.925014;-0.373716;0.068452;, + 0.702484;-0.584123;-0.406592;, + 0.277977;-0.495656;-0.822833;, + 0.000000;-0.326323;-0.945258;, + 0.788118;-0.183645;0.587491;, + 0.253204;-0.328259;0.910019;, + 0.953596;-0.298213;-0.041519;, + 0.649818;-0.613601;-0.448587;, + 0.213921;-0.752172;-0.623277;, + 0.000000;-0.760910;-0.648858;, + 0.750713;0.268051;0.603803;, + 0.000000;-0.632247;-0.774767;, + 0.000000;0.293377;0.955997;, + 0.000000;-0.458024;0.888940;, + 0.000000;-0.247527;0.968881;, + -0.000000;-0.929061;0.369927;, + 0.000000;-0.674749;0.738047;, + 0.000000;0.121068;0.992644;, + 0.413319;0.153508;0.897554;, + 0.000000;-0.048684;0.998814;, + 0.333509;-0.199190;0.921464;, + -0.715206;-0.667542;0.207047;, + -0.578980;-0.808463;-0.105693;, + -0.254152;-0.724281;0.640955;, + 0.350123;-0.705733;0.615918;, + 0.521829;-0.685532;0.507681;, + 0.582105;-0.748288;-0.318149;, + 0.259672;-0.758109;-0.598199;, + -0.324676;-0.788502;-0.522351;, + -0.164580;-0.761217;0.627266;, + -0.489043;-0.865249;0.110364;, + 0.147015;-0.759744;0.633384;, + 0.605120;-0.686438;0.403277;, + 0.602435;-0.766434;-0.222825;, + 0.157318;-0.949324;-0.272095;, + -0.166899;-0.916412;-0.363778;, + -0.427237;-0.891048;-0.153303;, + -0.649900;-0.035036;0.759212;, + -0.985761;-0.163298;-0.040116;, + 0.036046;0.034905;0.998740;, + 0.608077;0.178337;0.773588;, + 0.981662;0.163987;0.097203;, + 0.740908;-0.121535;-0.660519;, + -0.006847;-0.316355;-0.948616;, + -0.687977;-0.293549;-0.663714;, + 0.152727;0.197261;0.968381;, + 0.101821;-0.074160;-0.992035;, + 0.114730;0.027382;0.993019;, + -0.400147;-0.785877;0.471465;, + -0.373140;-0.766605;-0.522573;, + 0.346292;-0.166438;-0.923244;, + 0.519780;0.635299;0.571160;, + 0.747186;0.566650;-0.347307;, + -0.236063;0.200824;0.950760;, + -0.838795;-0.373110;0.396500;, + -0.651438;-0.450605;-0.610396;, + -0.031669;0.154102;-0.987547;, + 0.201281;0.810006;0.550796;, + 0.239147;0.872811;-0.425453;, + 0.299406;-0.276504;0.913182;, + -0.090325;-0.956867;0.276130;, + 0.102216;-0.745525;-0.658593;, + 0.569936;-0.148382;-0.808181;, + 0.711459;0.196812;0.674605;, + 0.934562;0.328093;-0.137656;, + 0.670078;-0.315307;0.671995;, + 0.433905;-0.762868;0.479331;, + 0.392697;-0.891971;-0.224004;, + 0.619791;-0.530830;-0.577995;, + 0.937105;-0.010824;0.348879;, + 0.942842;-0.125596;-0.308665;, + 0.179838;-0.052199;0.982310;, + -0.225765;-0.835864;0.500361;, + -0.124005;-0.775689;-0.618813;, + 0.254434;-0.153439;-0.954840;, + 0.632262;0.479231;0.608755;, + 0.779351;0.507865;-0.366995;, + 0.211083;-0.007310;0.977441;, + -0.425351;-0.766520;0.481169;, + -0.099996;-0.506703;-0.856302;, + -0.397481;-0.777098;-0.487983;, + 0.691760;0.435659;0.575908;, + 0.783622;0.512593;-0.350976;, + 0.312687;-0.071199;-0.947184;, + -0.075596;0.061964;-0.995211;, + -0.628811;0.048486;-0.776045;, + 0.519283;-0.801855;-0.295591;, + 0.768732;-0.464431;-0.439721;, + 0.776443;-0.621410;0.104818;, + 0.392286;-0.395655;0.830403;, + 0.519681;-0.462756;0.718184;, + 0.008636;0.241742;0.970302;, + -0.606488;0.362636;0.707579;, + -0.634201;0.590890;0.498637;, + -0.395655;-0.688028;0.608338;, + -0.733299;-0.679627;0.019472;, + 0.532226;-0.846074;0.029908;, + 0.626299;-0.623654;0.467766;, + 0.615564;-0.788001;-0.011651;, + 0.020657;0.352402;-0.935621;, + -0.737398;0.614678;-0.280026;, + -0.671012;-0.430239;-0.603852;, + 0.283460;-0.739558;-0.610496;, + 0.077465;0.247205;-0.965862;, + 0.093468;0.573633;-0.813762;, + 0.978692;0.134617;-0.155050;, + 0.990913;0.025337;-0.132097;, + 0.772378;-0.597866;-0.214449;, + -0.872971;0.472486;-0.121157;, + -0.815150;0.020096;-0.578901;, + 0.017212;-0.667549;0.744367;, + -0.938699;-0.157978;-0.306411;, + -0.063832;-0.326003;-0.943211;, + 0.025442;-0.997470;0.066384;, + -0.658998;-0.420978;0.623297;, + -0.005131;0.183808;-0.982949;, + -0.999001;-0.033016;-0.030117;, + 0.933054;-0.303731;-0.192763;, + -0.991412;0.128365;-0.025011;, + -0.649195;-0.068635;0.757519;, + 0.555420;-0.356114;0.751459;, + 0.937074;-0.338488;0.085548;, + -0.447516;0.045263;-0.893130;, + 0.705682;-0.354669;-0.613370;, + -0.720371;-0.617367;-0.316106;, + 0.752772;-0.619672;-0.222130;, + 0.592644;-0.622930;0.510618;, + -0.769512;-0.558113;-0.310422;, + 0.683253;-0.627918;-0.372671;, + -0.446447;-0.607871;-0.656642;, + 0.204878;-0.344714;-0.916077;, + 0.562588;-0.760251;-0.324828;, + -0.643951;-0.736523;-0.207031;, + 0.711056;-0.698405;0.081424;, + -0.686777;-0.713299;0.139789;, + 0.990075;-0.050814;0.131033;, + 0.413593;0.147648;0.898410;, + -0.624392;0.208124;0.752874;, + -0.321551;-0.282128;0.903885;, + -0.996072;0.072527;0.050799;, + -0.318836;0.181672;-0.930236;, + 0.386574;0.167859;-0.906854;, + 0.965362;0.116386;-0.233516;, + -0.885875;0.093257;-0.454453;, + 0.998737;-0.000577;-0.050239;, + -0.997215;0.069557;-0.026922;, + -0.750455;0.543429;-0.376168;, + 0.059927;0.707805;-0.703862;, + 0.617939;0.665192;-0.419130;, + 0.803206;0.582659;-0.123972;, + -0.704325;0.662368;-0.255334;, + -0.931934;0.103939;-0.347414;, + -0.082622;0.499858;-0.862158;, + 0.050360;0.933873;-0.354042;, + 0.027959;0.981500;-0.189407;, + -0.981209;0.015725;0.192306;, + 0.827387;-0.039311;-0.560255;, + 0.986340;-0.131712;-0.098922;, + 0.787094;-0.082947;0.611231;, + 0.006351;0.094118;0.995541;, + -0.498810;0.079278;0.863078;, + 0.993493;0.048503;0.103045;, + 0.938231;-0.345001;0.026413;, + 0.740122;-0.312902;0.595241;, + 0.673953;0.185182;0.715189;, + 0.108392;-0.207274;0.972260;, + -0.051154;0.195171;0.979434;, + -0.639562;-0.102930;0.761817;, + -0.704736;0.180553;0.686111;, + -0.998869;-0.047539;-0.000576;, + -0.958935;0.173981;-0.223994;, + -0.698266;-0.181001;-0.692577;, + -0.620972;0.089947;-0.778655;, + -0.016398;-0.443063;-0.896341;, + 0.144390;-0.065289;-0.987365;, + 0.728851;-0.441912;-0.522963;, + 0.871827;-0.033824;-0.488645;, + 0.871385;-0.490489;0.010371;, + 0.626805;-0.572093;0.528985;, + 0.076929;-0.452265;0.888559;, + -0.626649;-0.191510;0.755404;, + -0.998179;0.029379;0.052679;, + -0.721134;-0.035727;-0.691873;, + -0.076054;-0.310273;-0.947600;, + 0.686595;-0.525811;-0.502105;, + 0.330715;-0.736732;0.589791;, + -0.814386;0.118924;0.568007;, + -0.983958;0.171789;0.048122;, + -0.793032;-0.131439;-0.594831;, + -0.282352;-0.374795;-0.883067;, + -0.661563;0.611093;0.434626;, + -0.372803;0.739708;0.560223;, + -0.479848;0.732180;-0.483382;, + -0.699606;0.569916;-0.430984;, + -0.710696;0.422097;0.562801;, + -0.295926;0.387851;0.872926;, + -0.837365;0.545835;0.029728;, + -0.634042;0.611621;-0.473192;, + -0.202625;0.600190;-0.773766;, + -0.746426;-0.359818;0.559803;, + -0.315278;-0.350053;0.882078;, + -0.925014;-0.373716;0.068452;, + -0.702484;-0.584123;-0.406592;, + -0.277977;-0.495656;-0.822833;, + -0.788117;-0.183645;0.587491;, + -0.253204;-0.328259;0.910019;, + -0.953596;-0.298213;-0.041519;, + -0.649818;-0.613601;-0.448587;, + -0.213921;-0.752172;-0.623277;, + -0.750713;0.268052;0.603803;, + -0.413319;0.153508;0.897554;, + -0.333508;-0.199190;0.921464;, + 0.715206;-0.667542;0.207047;, + 0.578979;-0.808463;-0.105693;, + 0.254151;-0.724281;0.640956;, + -0.350122;-0.705733;0.615918;, + -0.521829;-0.685532;0.507682;, + -0.582105;-0.748288;-0.318149;, + -0.259672;-0.758109;-0.598199;, + 0.324675;-0.788502;-0.522351;, + 0.164580;-0.761216;0.627266;, + 0.489043;-0.865250;0.110364;, + -0.147015;-0.759744;0.633384;, + -0.605120;-0.686438;0.403277;, + -0.602435;-0.766434;-0.222825;, + -0.157318;-0.949324;-0.272095;, + 0.166899;-0.916412;-0.363778;, + 0.427237;-0.891048;-0.153303;, + 0.649900;-0.035037;0.759212;, + 0.985761;-0.163298;-0.040116;, + -0.036046;0.034905;0.998740;, + -0.608077;0.178337;0.773588;, + -0.981662;0.163987;0.097202;, + -0.740908;-0.121535;-0.660518;, + 0.006847;-0.316355;-0.948616;, + 0.687977;-0.293549;-0.663714;, + -0.152727;0.197261;0.968381;, + -0.101821;-0.074160;-0.992035;, + -0.114730;0.027382;0.993019;, + 0.400147;-0.785877;0.471465;, + 0.373140;-0.766605;-0.522573;, + -0.346292;-0.166438;-0.923244;, + -0.519779;0.635300;0.571160;, + -0.747186;0.566650;-0.347306;, + 0.236063;0.200824;0.950760;, + 0.838795;-0.373110;0.396500;, + 0.651438;-0.450605;-0.610396;, + 0.031669;0.154102;-0.987547;, + -0.201281;0.810006;0.550796;, + -0.239147;0.872811;-0.425453;, + -0.299406;-0.276504;0.913182;, + 0.090326;-0.956866;0.276132;, + -0.102213;-0.745525;-0.658593;, + -0.569935;-0.148383;-0.808181;, + -0.711459;0.196812;0.674605;, + -0.934562;0.328093;-0.137655;, + -0.670077;-0.315307;0.671995;, + -0.433903;-0.762869;0.479331;, + -0.392695;-0.891971;-0.224004;, + -0.619791;-0.530830;-0.577995;, + -0.937105;-0.010824;0.348879;, + -0.942842;-0.125596;-0.308665;, + -0.179838;-0.052199;0.982310;, + 0.225766;-0.835864;0.500361;, + 0.124006;-0.775689;-0.618813;, + -0.254434;-0.153439;-0.954840;, + -0.632263;0.479231;0.608754;, + -0.779351;0.507865;-0.366995;, + -0.211083;-0.007311;0.977441;, + 0.425351;-0.766520;0.481169;, + 0.397482;-0.777098;-0.487983;, + 0.099996;-0.506703;-0.856302;, + -0.691761;0.435659;0.575907;, + -0.783623;0.512593;-0.350976;, + -0.312688;-0.071199;-0.947184;, + -0.158440;0.272260;0.949090;, + -0.826805;0.300613;0.475422;, + -0.818240;-0.572323;0.054124;, + 0.443455;-0.793006;0.417718;, + -0.807686;-0.588428;0.037363;, + 0.478308;-0.856915;0.192140;, + -0.806374;-0.591350;0.008141;, + 0.485289;-0.872612;-0.055172;, + -0.805965;-0.591697;-0.017746;, + 0.466843;-0.842931;-0.267441;, + -0.819948;-0.571396;-0.034540;, + 0.428416;-0.777562;-0.460280;, + -0.815220;-0.575410;-0.065729;, + 0.362499;-0.663593;-0.654400;, + -0.987557;-0.002703;-0.157237;, + -0.465064;0.808835;-0.359864;, + -0.895193;0.296505;0.332738;, + -0.621376;0.321019;-0.714730;, + -0.823363;-0.179475;-0.538388;, + -0.717959;-0.165741;0.676065;, + -0.954361;0.021745;-0.297862;, + -0.870287;-0.492508;0.006093;, + -0.818024;0.006369;0.575148;, + 0.915007;0.400877;0.045386;, + 0.362063;0.859195;0.361516;, + 0.923704;0.382121;0.027477;, + 0.925341;0.379116;-0.003806;, + 0.925113;0.378382;-0.031514;, + 0.914133;0.402378;-0.049520;, + 0.914701;0.395544;-0.082872;, + 0.318704;0.921135;-0.223467;, + 0.592761;0.573307;-0.565644;, + -0.096115;0.933726;-0.344844;, + 0.336545;0.702533;0.627045;, + 0.486292;0.591434;0.643216;, + 0.870287;0.492508;-0.006093;, + 0.516008;0.743904;-0.424667;, + 0.388701;0.765725;0.512422;, + 0.818479;-0.013906;0.574368;, + 0.583881;0.562753;0.585143;, + 0.008591;-0.015184;0.999848;, + 0.871568;0.231819;0.432006;, + 0.448861;0.775548;0.443902;, + 0.779452;0.224370;-0.584904;, + -0.008598;0.015187;-0.999848;, + 0.397356;0.715862;-0.574151;, + 0.576552;-0.587596;0.567732;, + 0.785924;-0.451591;0.422360;, + 0.702038;-0.393393;-0.593620;, + -0.000186;-0.822252;0.569124;, + 0.242090;-0.874344;0.420613;, + 0.210446;-0.775533;-0.595199;, + -0.573887;-0.580416;0.577729;, + -0.441362;-0.788795;0.427788;, + -0.407347;-0.698201;-0.588713;, + -0.808485;-0.003753;0.588505;, + -0.864073;-0.245059;0.439687;, + -0.789452;-0.206700;-0.577963;, + -0.566558;0.569931;0.595139;, + -0.778428;0.438345;0.449336;, + -0.712039;0.411053;-0.569242;, + 0.010185;0.804586;0.593749;, + -0.234597;0.861095;0.451087;, + -0.220443;0.793196;-0.567667;, + 0.663953;0.169591;0.728289;, + 0.343613;0.581657;0.737296;, + 0.636660;0.638950;-0.431748;, + 0.896190;0.001007;-0.443670;, + 0.599051;-0.348328;0.720975;, + 0.628552;-0.633648;-0.451012;, + 0.186915;-0.668706;0.719650;, + -0.009479;-0.893246;-0.449468;, + -0.331041;-0.603875;0.725084;, + -0.644150;-0.625711;-0.439950;, + -0.651388;-0.191809;0.734100;, + -0.903681;0.012237;-0.428031;, + -0.586482;0.326109;0.741412;, + -0.636045;0.646893;-0.420685;, + -0.174343;0.646491;0.742734;, + 0.001989;0.906490;-0.422223;, + 0.864073;0.245061;-0.439686;, + 0.441363;0.788793;-0.427789;, + 0.644155;0.625710;0.439944;, + 0.903685;-0.012232;0.428023;, + 0.778430;-0.438345;-0.449333;, + 0.636046;-0.646894;0.420683;, + 0.234598;-0.861099;-0.451080;, + -0.001986;-0.906489;0.422225;, + -0.448852;-0.775554;-0.443902;, + -0.636655;-0.638956;0.431746;, + -0.871564;-0.231820;-0.432014;, + -0.896188;-0.001007;0.443673;, + -0.785920;0.451591;-0.422368;, + -0.628551;0.633646;0.451017;, + -0.242090;0.874344;-0.420613;, + 0.009483;0.893244;0.449471;, + 0.479045;0.490319;-0.728082;, + 0.675735;0.006858;-0.737113;, + 0.472902;-0.474122;-0.742679;, + -0.010626;-0.670850;-0.741517;, + -0.491614;-0.468095;-0.734304;, + -0.688295;0.015361;-0.725268;, + -0.485460;0.496332;-0.719711;, + -0.001936;0.693063;-0.720874;, + 0.651394;0.191812;-0.734094;, + 0.331038;0.603871;-0.725089;, + 0.491611;0.468102;0.734302;, + 0.688292;-0.015363;0.725271;, + 0.586489;-0.326107;-0.741407;, + 0.485471;-0.496336;0.719700;, + 0.174344;-0.646489;-0.742736;, + 0.001936;-0.693068;0.720870;, + -0.343609;-0.581653;-0.737301;, + -0.479044;-0.490321;0.728081;, + -0.663957;-0.169592;-0.728286;, + -0.675725;-0.006857;0.737122;, + -0.599047;0.348320;-0.720982;, + -0.472901;0.474118;0.742682;, + -0.186907;0.668699;-0.719658;, + 0.010630;0.670854;0.741513;; + 1896; + 3;0,1,2;, + 3;3,0,2;, + 3;4,0,3;, + 3;5,4,3;, + 3;6,4,5;, + 3;7,6,5;, + 3;8,9,10;, + 3;11,8,10;, + 3;12,8,11;, + 3;13,12,11;, + 3;14,12,13;, + 3;15,14,13;, + 3;9,1,16;, + 3;10,9,16;, + 3;17,3,2;, + 3;18,17,2;, + 3;10,16,19;, + 3;11,10,19;, + 3;20,5,3;, + 3;17,20,3;, + 3;11,19,21;, + 3;13,11,21;, + 3;22,7,5;, + 3;20,22,5;, + 3;14,6,7;, + 3;22,14,7;, + 3;13,21,23;, + 3;15,13,23;, + 3;19,16,1;, + 3;0,19,1;, + 3;21,19,0;, + 3;4,21,0;, + 3;23,21,4;, + 3;6,23,4;, + 3;17,18,9;, + 3;8,17,9;, + 3;20,17,8;, + 3;12,20,8;, + 3;22,20,12;, + 3;14,22,12;, + 3;18,2,1;, + 3;9,18,1;, + 3;15,23,6;, + 3;14,15,6;, + 3;24,25,26;, + 3;24,26,27;, + 3;27,26,28;, + 3;27,28,29;, + 3;29,28,30;, + 3;29,30,31;, + 3;32,33,34;, + 3;32,34,35;, + 3;35,34,36;, + 3;35,36,37;, + 3;37,36,38;, + 3;37,38,39;, + 3;40,25,33;, + 3;40,33,32;, + 3;24,27,41;, + 3;24,41,42;, + 3;43,40,32;, + 3;43,32,35;, + 3;27,29,44;, + 3;27,44,41;, + 3;45,43,35;, + 3;45,35,37;, + 3;29,31,46;, + 3;29,46,44;, + 3;31,30,38;, + 3;31,38,46;, + 3;47,45,37;, + 3;47,37,39;, + 3;25,40,43;, + 3;25,43,26;, + 3;26,43,45;, + 3;26,45,28;, + 3;28,45,47;, + 3;28,47,30;, + 3;33,42,41;, + 3;33,41,34;, + 3;34,41,44;, + 3;34,44,36;, + 3;36,44,46;, + 3;36,46,38;, + 3;25,24,42;, + 3;25,42,33;, + 3;30,47,39;, + 3;30,39,38;, + 3;48,49,50;, + 3;51,48,50;, + 3;52,53,54;, + 3;55,52,54;, + 3;56,57,58;, + 3;59,57,56;, + 3;57,60,61;, + 3;62,60,57;, + 3;59,62,57;, + 3;63,64,65;, + 3;65,60,62;, + 3;64,60,65;, + 3;66,63,65;, + 3;67,66,65;, + 3;61,68,58;, + 3;67,65,62;, + 3;69,67,62;, + 3;70,66,67;, + 3;71,70,67;, + 3;67,69,72;, + 3;71,67,72;, + 3;73,74,75;, + 3;76,73,75;, + 3;62,77,69;, + 3;78,79,68;, + 3;61,78,68;, + 3;80,78,61;, + 3;60,80,61;, + 3;64,81,80;, + 3;71,72,82;, + 3;70,71,82;, + 3;83,84,82;, + 3;72,83,82;, + 3;72,69,73;, + 3;76,72,73;, + 3;69,77,74;, + 3;73,69,74;, + 3;85,86,87;, + 3;88,85,87;, + 3;86,83,75;, + 3;87,86,75;, + 3;59,56,89;, + 3;85,59,89;, + 3;85,89,90;, + 3;86,85,90;, + 3;89,56,58;, + 3;91,89,58;, + 3;90,89,91;, + 3;92,90,91;, + 3;74,88,87;, + 3;75,74,87;, + 3;59,85,77;, + 3;62,59,77;, + 3;84,83,86;, + 3;77,85,88;, + 3;74,77,88;, + 3;83,72,76;, + 3;75,83,76;, + 3;91,58,68;, + 3;93,91,68;, + 3;92,91,93;, + 3;94,92,93;, + 3;79,95,96;, + 3;68,79,96;, + 3;68,96,97;, + 3;93,68,97;, + 3;93,97,94;, + 3;61,58,57;, + 3;98,99,100;, + 3;101,98,100;, + 3;102,98,101;, + 3;103,102,101;, + 3;104,105,106;, + 3;107,104,106;, + 3;105,108,109;, + 3;106,105,109;, + 3;108,110,109;, + 3;100,99,111;, + 3;109,110,112;, + 3;113,109,112;, + 3;104,82,84;, + 3;105,104,84;, + 3;106,98,102;, + 3;107,106,102;, + 3;105,84,86;, + 3;108,105,86;, + 3;109,99,98;, + 3;106,109,98;, + 3;108,86,90;, + 3;110,108,90;, + 3;110,90,92;, + 3;112,110,92;, + 3;113,111,99;, + 3;109,113,99;, + 3;114,112,92;, + 3;115,114,92;, + 3;116,113,112;, + 3;114,116,112;, + 3;117,111,113;, + 3;116,117,113;, + 3;92,94,115;, + 3;111,117,118;, + 3;119,111,118;, + 3;100,111,119;, + 3;101,100,119;, + 3;103,101,119;, + 3;120,103,119;, + 3;117,116,121;, + 3;118,117,121;, + 3;122,120,119;, + 3;123,122,119;, + 3;124,122,123;, + 3;125,124,123;, + 3;119,118,123;, + 3;126,123,118;, + 3;121,126,118;, + 3;125,123,126;, + 3;114,115,127;, + 3;116,114,127;, + 3;121,116,127;, + 3;128,121,127;, + 3;126,121,128;, + 3;129,126,128;, + 3;125,126,129;, + 3;130,125,129;, + 3;131,128,132;, + 3;133,131,132;, + 3;134,129,128;, + 3;131,134,128;, + 3;135,130,129;, + 3;134,135,129;, + 3;133,132,130;, + 3;135,133,130;, + 3;127,132,128;, + 3;127,115,94;, + 3;136,127,94;, + 3;95,55,54;, + 3;96,95,54;, + 3;96,54,137;, + 3;97,96,137;, + 3;97,137,136;, + 3;94,97,136;, + 3;138,131,133;, + 3;139,138,133;, + 3;140,134,131;, + 3;138,140,131;, + 3;141,135,134;, + 3;140,141,134;, + 3;139,133,135;, + 3;141,139,135;, + 3;142,138,139;, + 3;143,142,139;, + 3;144,140,138;, + 3;142,144,138;, + 3;145,141,140;, + 3;144,145,140;, + 3;143,139,141;, + 3;145,143,141;, + 3;146,142,143;, + 3;147,146,143;, + 3;148,144,142;, + 3;146,148,142;, + 3;149,145,144;, + 3;148,149,144;, + 3;147,143,145;, + 3;149,147,145;, + 3;150,146,147;, + 3;150,148,146;, + 3;150,149,148;, + 3;150,147,149;, + 3;50,49,151;, + 3;152,50,151;, + 3;153,154,137;, + 3;54,153,137;, + 3;153,53,48;, + 3;51,153,48;, + 3;51,50,155;, + 3;156,51,155;, + 3;156,154,51;, + 3;136,137,157;, + 3;158,136,157;, + 3;127,136,158;, + 3;50,152,155;, + 3;156,155,159;, + 3;160,156,159;, + 3;157,156,160;, + 3;161,157,160;, + 3;158,157,161;, + 3;162,158,161;, + 3;127,158,162;, + 3;163,127,162;, + 3;132,127,163;, + 3;53,52,48;, + 3;154,153,51;, + 3;53,153,54;, + 3;157,137,154;, + 3;156,157,154;, + 3;164,151,49;, + 3;165,164,49;, + 3;165,49,48;, + 3;166,165,48;, + 3;166,48,52;, + 3;167,166,52;, + 3;167,52,55;, + 3;168,167,55;, + 3;168,55,95;, + 3;169,168,95;, + 3;169,95,79;, + 3;170,169,79;, + 3;170,79,78;, + 3;171,170,78;, + 3;171,78,80;, + 3;172,171,80;, + 3;172,80,81;, + 3;173,172,81;, + 3;174,164,165;, + 3;175,174,165;, + 3;175,165,166;, + 3;176,175,166;, + 3;176,166,167;, + 3;177,176,167;, + 3;177,167,168;, + 3;178,177,168;, + 3;178,168,169;, + 3;179,178,169;, + 3;179,169,170;, + 3;180,179,170;, + 3;180,170,171;, + 3;181,180,171;, + 3;181,171,172;, + 3;182,181,172;, + 3;182,172,173;, + 3;183,182,173;, + 3;184,174,175;, + 3;185,184,175;, + 3;185,175,176;, + 3;186,185,176;, + 3;186,176,177;, + 3;187,186,177;, + 3;187,177,178;, + 3;188,187,178;, + 3;188,178,179;, + 3;189,188,179;, + 3;189,179,180;, + 3;190,189,180;, + 3;190,180,181;, + 3;191,190,181;, + 3;191,181,182;, + 3;192,191,182;, + 3;192,182,183;, + 3;193,192,183;, + 3;194,184,185;, + 3;195,194,185;, + 3;195,185,186;, + 3;196,195,186;, + 3;196,186,187;, + 3;197,196,187;, + 3;197,187,188;, + 3;198,197,188;, + 3;198,188,189;, + 3;199,198,189;, + 3;199,189,190;, + 3;200,199,190;, + 3;200,190,191;, + 3;201,200,191;, + 3;201,191,192;, + 3;202,201,192;, + 3;202,192,193;, + 3;203,202,193;, + 3;204,194,195;, + 3;204,195,196;, + 3;204,196,197;, + 3;204,197,198;, + 3;204,198,199;, + 3;204,199,200;, + 3;204,200,201;, + 3;204,201,202;, + 3;204,202,203;, + 3;80,60,64;, + 3;205,206,207;, + 3;208,205,207;, + 3;209,210,211;, + 3;212,209,211;, + 3;213,214,215;, + 3;215,214,216;, + 3;217,218,214;, + 3;218,219,216;, + 3;214,218,216;, + 3;220,64,63;, + 3;219,218,220;, + 3;220,218,64;, + 3;63,66,221;, + 3;220,63,221;, + 3;213,222,217;, + 3;220,221,223;, + 3;219,220,223;, + 3;66,70,224;, + 3;221,66,224;, + 3;223,221,224;, + 3;225,223,224;, + 3;226,227,228;, + 3;229,226,228;, + 3;223,230,219;, + 3;231,232,217;, + 3;222,231,217;, + 3;232,233,218;, + 3;217,232,218;, + 3;233,81,64;, + 3;82,225,224;, + 3;82,224,70;, + 3;234,235,225;, + 3;82,234,225;, + 3;223,225,228;, + 3;227,223,228;, + 3;230,223,227;, + 3;226,230,227;, + 3;236,237,238;, + 3;239,236,238;, + 3;235,236,239;, + 3;229,235,239;, + 3;215,216,237;, + 3;240,215,237;, + 3;240,237,236;, + 3;241,240,236;, + 3;215,240,242;, + 3;213,215,242;, + 3;240,241,243;, + 3;242,240,243;, + 3;238,226,229;, + 3;239,238,229;, + 3;230,237,216;, + 3;230,216,219;, + 3;236,235,234;, + 3;237,230,226;, + 3;238,237,226;, + 3;225,235,229;, + 3;228,225,229;, + 3;213,242,244;, + 3;222,213,244;, + 3;242,243,245;, + 3;244,242,245;, + 3;246,231,222;, + 3;247,246,222;, + 3;247,222,244;, + 3;248,247,244;, + 3;245,248,244;, + 3;214,213,217;, + 3;249,250,251;, + 3;252,249,251;, + 3;250,102,103;, + 3;251,250,103;, + 3;253,104,107;, + 3;254,253,107;, + 3;255,253,254;, + 3;256,255,254;, + 3;256,257,255;, + 3;258,249,252;, + 3;257,256,259;, + 3;260,257,259;, + 3;82,104,253;, + 3;234,82,253;, + 3;250,254,107;, + 3;102,250,107;, + 3;234,253,255;, + 3;236,234,255;, + 3;249,256,254;, + 3;250,249,254;, + 3;236,255,257;, + 3;241,236,257;, + 3;241,257,260;, + 3;243,241,260;, + 3;258,259,256;, + 3;249,258,256;, + 3;260,261,262;, + 3;243,260,262;, + 3;259,263,261;, + 3;260,259,261;, + 3;258,264,263;, + 3;259,258,263;, + 3;262,245,243;, + 3;264,258,265;, + 3;266,264,265;, + 3;265,258,252;, + 3;265,252,251;, + 3;251,103,120;, + 3;265,251,120;, + 3;267,263,264;, + 3;267,264,266;, + 3;120,122,268;, + 3;265,120,268;, + 3;122,124,269;, + 3;268,122,269;, + 3;268,266,265;, + 3;268,270,267;, + 3;266,268,267;, + 3;270,268,269;, + 3;271,262,261;, + 3;261,263,267;, + 3;271,261,267;, + 3;271,267,272;, + 3;267,270,273;, + 3;272,267,273;, + 3;270,269,274;, + 3;273,270,274;, + 3;272,275,276;, + 3;277,272,276;, + 3;273,278,275;, + 3;272,273,275;, + 3;274,279,278;, + 3;273,274,278;, + 3;277,276,279;, + 3;274,277,279;, + 3;272,277,271;, + 3;271,280,245;, + 3;245,262,271;, + 3;211,246,247;, + 3;212,211,247;, + 3;212,247,248;, + 3;281,212,248;, + 3;281,248,245;, + 3;280,281,245;, + 3;275,282,283;, + 3;276,275,283;, + 3;278,284,282;, + 3;275,278,282;, + 3;279,285,284;, + 3;278,279,284;, + 3;276,283,285;, + 3;279,276,285;, + 3;282,286,287;, + 3;283,282,287;, + 3;284,288,286;, + 3;282,284,286;, + 3;285,289,288;, + 3;284,285,288;, + 3;283,287,289;, + 3;285,283,289;, + 3;286,290,291;, + 3;287,286,291;, + 3;288,292,290;, + 3;286,288,290;, + 3;289,293,292;, + 3;288,289,292;, + 3;287,291,293;, + 3;289,287,293;, + 3;291,290,294;, + 3;290,292,294;, + 3;292,293,294;, + 3;293,291,294;, + 3;205,208,152;, + 3;151,205,152;, + 3;295,296,212;, + 3;281,295,212;, + 3;209,296,207;, + 3;206,209,207;, + 3;208,207,297;, + 3;155,208,297;, + 3;207,295,297;, + 3;281,280,298;, + 3;299,281,298;, + 3;298,280,271;, + 3;155,152,208;, + 3;155,297,300;, + 3;159,155,300;, + 3;297,299,301;, + 3;300,297,301;, + 3;299,298,302;, + 3;301,299,302;, + 3;302,298,271;, + 3;302,271,303;, + 3;303,271,277;, + 3;206,210,209;, + 3;207,296,295;, + 3;212,296,209;, + 3;295,281,299;, + 3;295,299,297;, + 3;151,164,304;, + 3;205,151,304;, + 3;205,304,305;, + 3;206,205,305;, + 3;206,305,306;, + 3;210,206,306;, + 3;210,306,307;, + 3;211,210,307;, + 3;211,307,308;, + 3;246,211,308;, + 3;246,308,309;, + 3;231,246,309;, + 3;231,309,310;, + 3;232,231,310;, + 3;232,310,311;, + 3;233,232,311;, + 3;233,311,173;, + 3;81,233,173;, + 3;164,174,312;, + 3;304,164,312;, + 3;304,312,313;, + 3;305,304,313;, + 3;305,313,314;, + 3;306,305,314;, + 3;306,314,315;, + 3;307,306,315;, + 3;307,315,316;, + 3;308,307,316;, + 3;308,316,317;, + 3;309,308,317;, + 3;309,317,318;, + 3;310,309,318;, + 3;310,318,319;, + 3;311,310,319;, + 3;311,319,183;, + 3;173,311,183;, + 3;174,184,320;, + 3;312,174,320;, + 3;312,320,321;, + 3;313,312,321;, + 3;313,321,322;, + 3;314,313,322;, + 3;314,322,323;, + 3;315,314,323;, + 3;315,323,324;, + 3;316,315,324;, + 3;316,324,325;, + 3;317,316,325;, + 3;317,325,326;, + 3;318,317,326;, + 3;318,326,327;, + 3;319,318,327;, + 3;319,327,193;, + 3;183,319,193;, + 3;184,194,328;, + 3;320,184,328;, + 3;320,328,329;, + 3;321,320,329;, + 3;321,329,330;, + 3;322,321,330;, + 3;322,330,331;, + 3;323,322,331;, + 3;323,331,332;, + 3;324,323,332;, + 3;324,332,333;, + 3;325,324,333;, + 3;325,333,334;, + 3;326,325,334;, + 3;326,334,335;, + 3;327,326,335;, + 3;327,335,203;, + 3;193,327,203;, + 3;328,194,204;, + 3;329,328,204;, + 3;330,329,204;, + 3;331,330,204;, + 3;332,331,204;, + 3;333,332,204;, + 3;334,333,204;, + 3;335,334,204;, + 3;203,335,204;, + 3;64,218,233;, + 3;336,337,338;, + 3;339,336,338;, + 3;336,340,337;, + 3;341,336,339;, + 3;342,341,339;, + 3;341,340,336;, + 3;343,341,342;, + 3;344,343,342;, + 3;343,340,341;, + 3;345,343,344;, + 3;346,345,344;, + 3;345,340,343;, + 3;347,345,346;, + 3;348,347,346;, + 3;347,340,345;, + 3;337,347,348;, + 3;338,337,348;, + 3;337,340,347;, + 3;349,350,351;, + 3;352,349,351;, + 3;353,349,352;, + 3;354,353,352;, + 3;355,353,354;, + 3;356,355,354;, + 3;357,355,356;, + 3;358,357,356;, + 3;359,357,358;, + 3;360,359,358;, + 3;350,359,360;, + 3;351,350,360;, + 3;361,350,349;, + 3;362,361,349;, + 3;362,349,353;, + 3;363,362,353;, + 3;363,353,355;, + 3;364,363,355;, + 3;364,355,357;, + 3;365,364,357;, + 3;365,357,359;, + 3;366,365,359;, + 3;366,359,350;, + 3;361,366,350;, + 3;367,361,362;, + 3;368,367,362;, + 3;368,362,363;, + 3;369,368,363;, + 3;369,363,364;, + 3;370,369,364;, + 3;370,364,365;, + 3;371,370,365;, + 3;371,365,366;, + 3;372,371,366;, + 3;372,366,361;, + 3;367,372,361;, + 3;373,367,368;, + 3;373,368,369;, + 3;373,369,370;, + 3;373,370,371;, + 3;373,371,372;, + 3;373,372,367;, + 3;374,375,376;, + 3;374,376,377;, + 3;377,376,378;, + 3;377,378,379;, + 3;379,378,380;, + 3;379,380,381;, + 3;381,380,382;, + 3;381,382,383;, + 3;383,382,384;, + 3;383,384,385;, + 3;385,384,375;, + 3;385,375,374;, + 3;376,375,386;, + 3;376,386,387;, + 3;378,376,387;, + 3;378,387,388;, + 3;380,378,388;, + 3;380,388,389;, + 3;382,380,389;, + 3;382,389,390;, + 3;384,382,390;, + 3;384,390,391;, + 3;375,384,391;, + 3;375,391,386;, + 3;387,386,392;, + 3;387,392,393;, + 3;388,387,393;, + 3;388,393,394;, + 3;389,388,394;, + 3;389,394,395;, + 3;390,389,395;, + 3;390,395,396;, + 3;391,390,396;, + 3;391,396,397;, + 3;386,391,397;, + 3;386,397,392;, + 3;393,392,398;, + 3;394,393,398;, + 3;395,394,398;, + 3;396,395,398;, + 3;397,396,398;, + 3;392,397,398;, + 3;399,400,401;, + 3;402,399,401;, + 3;403,404,405;, + 3;406,399,402;, + 3;407,406,402;, + 3;408,404,403;, + 3;409,406,407;, + 3;410,409,407;, + 3;411,404,408;, + 3;412,409,410;, + 3;413,412,410;, + 3;414,404,411;, + 3;415,416,412;, + 3;413,415,412;, + 3;417,418,400;, + 3;399,417,400;, + 3;419,420,406;, + 3;409,419,406;, + 3;421,419,409;, + 3;412,421,409;, + 3;416,422,421;, + 3;412,416,421;, + 3;423,424,418;, + 3;417,423,418;, + 3;425,426,420;, + 3;419,425,420;, + 3;427,425,419;, + 3;421,427,419;, + 3;428,429,424;, + 3;405,428,424;, + 3;405,424,423;, + 3;403,405,423;, + 3;403,423,426;, + 3;408,403,426;, + 3;408,426,425;, + 3;411,408,425;, + 3;411,425,427;, + 3;414,411,427;, + 3;401,400,430;, + 3;431,401,430;, + 3;404,428,405;, + 3;432,404,414;, + 3;400,418,433;, + 3;430,400,433;, + 3;418,424,429;, + 3;433,418,429;, + 3;434,432,414;, + 3;427,434,414;, + 3;422,434,427;, + 3;421,422,427;, + 3;435,423,417;, + 3;436,426,423;, + 3;435,436,423;, + 3;437,438,439;, + 3;437,439,440;, + 3;441,404,442;, + 3;440,439,443;, + 3;440,443,444;, + 3;442,404,445;, + 3;444,443,446;, + 3;444,446,447;, + 3;445,404,448;, + 3;447,446,449;, + 3;447,449,450;, + 3;448,404,451;, + 3;449,416,415;, + 3;449,415,450;, + 3;438,452,453;, + 3;438,453,439;, + 3;443,454,455;, + 3;443,455,446;, + 3;446,455,456;, + 3;446,456,449;, + 3;456,422,416;, + 3;456,416,449;, + 3;452,457,458;, + 3;452,458,453;, + 3;454,459,460;, + 3;454,460,455;, + 3;455,460,461;, + 3;455,461,456;, + 3;457,429,428;, + 3;457,428,441;, + 3;458,457,441;, + 3;458,441,442;, + 3;459,458,442;, + 3;459,442,445;, + 3;460,459,445;, + 3;460,445,448;, + 3;461,460,448;, + 3;461,448,451;, + 3;430,438,437;, + 3;430,437,431;, + 3;441,428,404;, + 3;451,404,432;, + 3;433,452,438;, + 3;433,438,430;, + 3;429,457,452;, + 3;429,452,433;, + 3;451,432,434;, + 3;451,434,461;, + 3;461,434,422;, + 3;461,422,456;, + 3;453,458,462;, + 3;458,459,463;, + 3;458,463,462;, + 3;463,459,454;, + 3;464,465,466;, + 3;467,464,466;, + 3;468,464,467;, + 3;469,470,471;, + 3;472,469,471;, + 3;472,473,469;, + 3;474,475,476;, + 3;477,474,476;, + 3;471,470,478;, + 3;468,471,478;, + 3;479,465,480;, + 3;481,482,475;, + 3;474,481,475;, + 3;483,484,485;, + 3;486,483,485;, + 3;478,487,464;, + 3;468,478,464;, + 3;488,466,465;, + 3;479,488,465;, + 3;484,489,485;, + 3;483,487,480;, + 3;487,490,464;, + 3;490,489,465;, + 3;464,490,465;, + 3;480,465,489;, + 3;484,480,489;, + 3;483,486,490;, + 3;487,483,490;, + 3;491,492,493;, + 3;494,491,493;, + 3;495,496,485;, + 3;489,495,485;, + 3;496,497,486;, + 3;485,496,486;, + 3;486,497,490;, + 3;490,495,489;, + 3;493,492,496;, + 3;495,493,496;, + 3;492,491,497;, + 3;496,492,497;, + 3;491,494,490;, + 3;497,491,490;, + 3;494,493,495;, + 3;490,494,495;, + 3;498,488,472;, + 3;499,498,472;, + 3;500,471,468;, + 3;501,500,468;, + 3;499,472,471;, + 3;500,499,471;, + 3;502,466,488;, + 3;498,502,488;, + 3;503,467,466;, + 3;502,503,466;, + 3;501,468,467;, + 3;503,501,467;, + 3;475,498,499;, + 3;476,475,499;, + 3;477,500,501;, + 3;474,477,501;, + 3;476,499,500;, + 3;477,476,500;, + 3;482,502,498;, + 3;475,482,498;, + 3;481,503,502;, + 3;482,481,502;, + 3;474,501,503;, + 3;481,474,503;, + 3;504,505,506;, + 3;507,508,506;, + 3;509,510,511;, + 3;512,509,513;, + 3;507,512,514;, + 3;504,515,516;, + 3;517,518,515;, + 3;506,519,518;, + 3;506,508,519;, + 3;507,505,516;, + 3;510,520,521;, + 3;509,522,520;, + 3;511,521,523;, + 3;512,524,522;, + 3;513,523,525;, + 3;507,516,524;, + 3;514,525,519;, + 3;521,526,527;, + 3;522,528,520;, + 3;529,528,522;, + 3;527,530,525;, + 3;521,527,523;, + 3;530,531,532;, + 3;533,534,530;, + 3;532,535,519;, + 3;530,532,525;, + 3;524,536,529;, + 3;537,536,524;, + 3;538,537,516;, + 3;515,539,538;, + 3;535,540,518;, + 3;529,536,531;, + 3;541,542,543;, + 3;544,541,543;, + 3;545,541,544;, + 3;546,545,544;, + 3;547,545,546;, + 3;548,547,546;, + 3;549,547,548;, + 3;550,549,548;, + 3;551,549,550;, + 3;552,551,550;, + 3;553,551,552;, + 3;554,553,552;, + 3;555,553,554;, + 3;556,555,554;, + 3;542,555,556;, + 3;543,542,556;, + 3;557,558,542;, + 3;541,557,542;, + 3;559,557,541;, + 3;545,559,541;, + 3;560,559,545;, + 3;547,560,545;, + 3;561,560,547;, + 3;549,561,547;, + 3;562,561,549;, + 3;551,562,549;, + 3;563,562,551;, + 3;553,563,551;, + 3;564,563,553;, + 3;555,564,553;, + 3;558,564,555;, + 3;542,558,555;, + 3;565,566,558;, + 3;557,565,558;, + 3;561,567,560;, + 3;568,569,561;, + 3;562,568,561;, + 3;570,568,562;, + 3;563,570,562;, + 3;571,570,563;, + 3;566,571,564;, + 3;558,566,564;, + 3;572,573,574;, + 3;575,572,574;, + 3;436,435,573;, + 3;572,436,573;, + 3;576,402,401;, + 3;577,576,401;, + 3;578,407,402;, + 3;576,578,402;, + 3;579,410,407;, + 3;578,579,407;, + 3;580,413,410;, + 3;579,580,410;, + 3;581,415,413;, + 3;580,581,413;, + 3;582,576,577;, + 3;583,582,577;, + 3;584,578,576;, + 3;582,584,576;, + 3;585,579,578;, + 3;584,585,578;, + 3;586,580,579;, + 3;585,586,579;, + 3;587,581,580;, + 3;586,587,580;, + 3;588,582,583;, + 3;589,588,583;, + 3;590,584,582;, + 3;588,590,582;, + 3;591,585,584;, + 3;590,591,584;, + 3;592,586,585;, + 3;591,592,585;, + 3;593,587,586;, + 3;592,593,586;, + 3;569,590,588;, + 3;594,569,588;, + 3;568,591,590;, + 3;569,568,590;, + 3;570,592,591;, + 3;568,570,591;, + 3;595,593,592;, + 3;570,595,592;, + 3;571,595,570;, + 3;577,401,431;, + 3;596,577,431;, + 3;583,577,596;, + 3;597,583,596;, + 3;589,583,597;, + 3;598,589,597;, + 3;566,565,599;, + 3;599,565,600;, + 3;589,598,601;, + 3;602,589,601;, + 3;588,589,602;, + 3;594,588,602;, + 3;557,559,565;, + 3;602,601,603;, + 3;604,602,603;, + 3;569,594,567;, + 3;561,569,567;, + 3;594,602,604;, + 3;567,594,604;, + 3;560,567,604;, + 3;559,604,565;, + 3;604,603,600;, + 3;605,544,543;, + 3;606,605,543;, + 3;607,546,544;, + 3;605,607,544;, + 3;608,548,546;, + 3;607,608,546;, + 3;609,550,548;, + 3;608,609,548;, + 3;610,552,550;, + 3;609,610,550;, + 3;611,554,552;, + 3;610,611,552;, + 3;612,556,554;, + 3;611,612,554;, + 3;606,543,556;, + 3;612,606,556;, + 3;613,605,606;, + 3;614,613,606;, + 3;615,607,605;, + 3;613,615,605;, + 3;616,608,607;, + 3;615,616,607;, + 3;617,609,608;, + 3;616,617,608;, + 3;618,610,609;, + 3;617,618,609;, + 3;619,611,610;, + 3;618,619,610;, + 3;620,612,611;, + 3;619,620,611;, + 3;614,606,612;, + 3;620,614,612;, + 3;621,613,614;, + 3;622,621,614;, + 3;623,615,613;, + 3;621,623,613;, + 3;624,616,615;, + 3;623,624,615;, + 3;625,617,616;, + 3;624,625,616;, + 3;626,618,617;, + 3;625,626,617;, + 3;627,619,618;, + 3;626,627,618;, + 3;628,620,619;, + 3;627,628,619;, + 3;622,614,620;, + 3;628,622,620;, + 3;538,621,622;, + 3;539,623,621;, + 3;540,624,623;, + 3;535,625,624;, + 3;532,626,625;, + 3;531,627,626;, + 3;536,628,627;, + 3;537,622,628;, + 3;564,571,563;, + 3;565,604,600;, + 3;533,526,528;, + 3;518,540,539;, + 3;515,518,539;, + 3;531,534,529;, + 3;520,528,526;, + 3;521,520,526;, + 3;534,533,529;, + 3;526,533,527;, + 3;531,530,534;, + 3;517,504,506;, + 3;505,507,506;, + 3;513,509,511;, + 3;514,512,513;, + 3;508,507,514;, + 3;505,504,516;, + 3;504,517,515;, + 3;517,506,518;, + 3;511,510,521;, + 3;510,509,520;, + 3;513,511,523;, + 3;509,512,522;, + 3;514,513,525;, + 3;512,507,524;, + 3;508,514,519;, + 3;524,529,522;, + 3;523,527,525;, + 3;527,533,530;, + 3;525,532,519;, + 3;516,537,524;, + 3;515,538,516;, + 3;519,535,518;, + 3;537,538,622;, + 3;538,539,621;, + 3;539,540,623;, + 3;540,535,624;, + 3;535,532,625;, + 3;532,531,626;, + 3;531,536,627;, + 3;536,537,628;, + 3;529,533,528;, + 3;604,559,560;, + 3;573,629,574;, + 3;420,630,406;, + 3;573,435,417;, + 3;436,572,420;, + 3;417,399,629;, + 3;573,417,629;, + 3;572,575,630;, + 3;420,572,630;, + 3;631,629,399;, + 3;632,631,399;, + 3;633,406,630;, + 3;634,633,630;, + 3;632,399,406;, + 3;633,632,406;, + 3;635,574,629;, + 3;631,635,629;, + 3;636,575,574;, + 3;635,636,574;, + 3;634,630,575;, + 3;636,634,575;, + 3;637,631,632;, + 3;638,637,632;, + 3;639,633,634;, + 3;640,639,634;, + 3;638,632,633;, + 3;639,638,633;, + 3;641,635,631;, + 3;637,641,631;, + 3;642,636,635;, + 3;641,642,635;, + 3;640,634,636;, + 3;642,640,636;, + 3;643,637,638;, + 3;644,643,638;, + 3;645,639,640;, + 3;646,645,640;, + 3;644,638,639;, + 3;645,644,639;, + 3;647,641,637;, + 3;643,647,637;, + 3;648,642,641;, + 3;647,648,641;, + 3;646,640,642;, + 3;648,646,642;, + 3;649,643,644;, + 3;650,649,644;, + 3;651,645,646;, + 3;652,651,646;, + 3;650,644,645;, + 3;651,650,645;, + 3;653,647,643;, + 3;649,653,643;, + 3;654,648,647;, + 3;653,654,647;, + 3;652,646,648;, + 3;654,652,648;, + 3;655,649,650;, + 3;656,655,650;, + 3;657,651,652;, + 3;658,657,652;, + 3;656,650,651;, + 3;657,656,651;, + 3;659,653,649;, + 3;655,659,649;, + 3;660,654,653;, + 3;659,660,653;, + 3;658,652,654;, + 3;660,658,654;, + 3;661,655,656;, + 3;662,661,656;, + 3;657,663,664;, + 3;662,656,657;, + 3;664,662,657;, + 3;665,659,655;, + 3;661,665,655;, + 3;666,660,659;, + 3;665,666,659;, + 3;667,658,660;, + 3;666,667,660;, + 3;469,661,662;, + 3;470,469,662;, + 3;480,663,667;, + 3;662,478,470;, + 3;473,665,661;, + 3;469,473,661;, + 3;479,666,665;, + 3;473,479,665;, + 3;480,667,666;, + 3;479,480,666;, + 3;420,426,436;, + 3;488,479,473;, + 3;472,488,473;, + 3;658,667,663;, + 3;657,658,663;, + 3;487,664,663;, + 3;480,487,663;, + 3;664,487,478;, + 3;662,664,478;, + 3;484,483,480;, + 3;668,669,670;, + 3;668,670,671;, + 3;671,670,672;, + 3;673,674,675;, + 3;673,675,676;, + 3;675,677,676;, + 3;678,679,680;, + 3;678,680,681;, + 3;682,674,673;, + 3;682,673,672;, + 3;683,669,684;, + 3;679,685,686;, + 3;679,686,680;, + 3;687,688,689;, + 3;687,689,690;, + 3;670,691,682;, + 3;670,682,672;, + 3;669,668,692;, + 3;669,692,684;, + 3;687,693,688;, + 3;683,691,689;, + 3;670,694,691;, + 3;669,693,694;, + 3;669,694,670;, + 3;693,669,683;, + 3;693,683,688;, + 3;694,690,689;, + 3;694,689,691;, + 3;695,696,697;, + 3;695,697,698;, + 3;687,699,700;, + 3;687,700,693;, + 3;690,701,699;, + 3;690,699,687;, + 3;694,701,690;, + 3;693,700,694;, + 3;699,696,695;, + 3;699,695,700;, + 3;701,697,696;, + 3;701,696,699;, + 3;694,698,697;, + 3;694,697,701;, + 3;700,695,698;, + 3;700,698,694;, + 3;676,692,702;, + 3;676,702,703;, + 3;672,673,704;, + 3;672,704,705;, + 3;673,676,703;, + 3;673,703,704;, + 3;692,668,706;, + 3;692,706,702;, + 3;668,671,707;, + 3;668,707,706;, + 3;671,672,705;, + 3;671,705,707;, + 3;703,702,679;, + 3;703,679,678;, + 3;705,704,681;, + 3;705,681,680;, + 3;704,703,678;, + 3;704,678,681;, + 3;702,706,685;, + 3;702,685,679;, + 3;706,707,686;, + 3;706,686,685;, + 3;707,705,680;, + 3;707,680,686;, + 3;708,709,710;, + 3;708,711,712;, + 3;713,714,715;, + 3;716,715,717;, + 3;718,717,712;, + 3;719,720,710;, + 3;720,721,722;, + 3;721,723,708;, + 3;723,711,708;, + 3;719,709,712;, + 3;724,725,714;, + 3;725,726,715;, + 3;727,724,713;, + 3;726,728,717;, + 3;729,727,716;, + 3;728,719,712;, + 3;723,729,718;, + 3;730,731,724;, + 3;725,732,726;, + 3;726,732,733;, + 3;729,734,730;, + 3;727,730,724;, + 3;735,736,734;, + 3;734,737,738;, + 3;723,739,735;, + 3;729,735,734;, + 3;733,740,728;, + 3;728,740,741;, + 3;719,741,742;, + 3;742,743,720;, + 3;721,744,739;, + 3;736,740,733;, + 3;745,746,747;, + 3;745,747,748;, + 3;748,747,749;, + 3;748,749,750;, + 3;750,749,751;, + 3;750,751,752;, + 3;752,751,753;, + 3;752,753,754;, + 3;754,753,755;, + 3;754,755,756;, + 3;756,755,757;, + 3;756,757,758;, + 3;758,757,759;, + 3;758,759,760;, + 3;760,759,746;, + 3;760,746,745;, + 3;746,761,762;, + 3;746,762,747;, + 3;747,762,763;, + 3;747,763,749;, + 3;749,763,764;, + 3;749,764,751;, + 3;751,764,765;, + 3;751,765,753;, + 3;753,765,766;, + 3;753,766,755;, + 3;755,766,767;, + 3;755,767,757;, + 3;757,767,768;, + 3;757,768,759;, + 3;759,768,761;, + 3;759,761,746;, + 3;761,566,769;, + 3;761,769,762;, + 3;764,770,765;, + 3;765,771,772;, + 3;765,772,766;, + 3;766,772,773;, + 3;766,773,767;, + 3;767,773,571;, + 3;768,571,566;, + 3;768,566,761;, + 3;774,775,776;, + 3;774,776,777;, + 3;775,462,463;, + 3;775,463,776;, + 3;437,440,778;, + 3;437,778,779;, + 3;440,444,780;, + 3;440,780,778;, + 3;444,447,781;, + 3;444,781,780;, + 3;447,450,782;, + 3;447,782,781;, + 3;450,415,581;, + 3;450,581,782;, + 3;779,778,783;, + 3;779,783,784;, + 3;778,780,785;, + 3;778,785,783;, + 3;780,781,786;, + 3;780,786,785;, + 3;781,782,787;, + 3;781,787,786;, + 3;782,581,587;, + 3;782,587,787;, + 3;784,783,788;, + 3;784,788,789;, + 3;783,785,790;, + 3;783,790,788;, + 3;785,786,791;, + 3;785,791,790;, + 3;786,787,792;, + 3;786,792,791;, + 3;787,587,593;, + 3;787,593,792;, + 3;788,790,771;, + 3;788,771,793;, + 3;790,791,772;, + 3;790,772,771;, + 3;791,792,773;, + 3;791,773,772;, + 3;792,593,595;, + 3;792,595,773;, + 3;773,595,571;, + 3;431,437,779;, + 3;431,779,596;, + 3;596,779,784;, + 3;596,784,597;, + 3;597,784,789;, + 3;597,789,598;, + 3;599,769,566;, + 3;600,769,599;, + 3;601,598,789;, + 3;601,789,794;, + 3;794,789,788;, + 3;794,788,793;, + 3;769,763,762;, + 3;603,601,794;, + 3;603,794,795;, + 3;770,793,771;, + 3;770,771,765;, + 3;795,794,793;, + 3;795,793,770;, + 3;795,770,764;, + 3;769,795,763;, + 3;600,603,795;, + 3;745,748,796;, + 3;745,796,797;, + 3;748,750,798;, + 3;748,798,796;, + 3;750,752,799;, + 3;750,799,798;, + 3;752,754,800;, + 3;752,800,799;, + 3;754,756,801;, + 3;754,801,800;, + 3;756,758,802;, + 3;756,802,801;, + 3;758,760,803;, + 3;758,803,802;, + 3;760,745,797;, + 3;760,797,803;, + 3;797,796,804;, + 3;797,804,805;, + 3;796,798,806;, + 3;796,806,804;, + 3;798,799,807;, + 3;798,807,806;, + 3;799,800,808;, + 3;799,808,807;, + 3;800,801,809;, + 3;800,809,808;, + 3;801,802,810;, + 3;801,810,809;, + 3;802,803,811;, + 3;802,811,810;, + 3;803,797,805;, + 3;803,805,811;, + 3;805,804,812;, + 3;805,812,813;, + 3;804,806,814;, + 3;804,814,812;, + 3;806,807,815;, + 3;806,815,814;, + 3;807,808,816;, + 3;807,816,815;, + 3;808,809,817;, + 3;808,817,816;, + 3;809,810,818;, + 3;809,818,817;, + 3;810,811,819;, + 3;810,819,818;, + 3;811,805,813;, + 3;811,813,819;, + 3;813,812,742;, + 3;812,814,743;, + 3;814,815,744;, + 3;815,816,739;, + 3;816,817,735;, + 3;817,818,736;, + 3;818,819,740;, + 3;819,813,741;, + 3;767,571,768;, + 3;600,795,769;, + 3;732,731,738;, + 3;743,744,721;, + 3;743,721,720;, + 3;733,737,736;, + 3;731,732,725;, + 3;731,725,724;, + 3;733,738,737;, + 3;730,738,731;, + 3;737,734,736;, + 3;708,710,722;, + 3;708,712,709;, + 3;713,715,716;, + 3;716,717,718;, + 3;718,712,711;, + 3;719,710,709;, + 3;720,722,710;, + 3;721,708,722;, + 3;724,714,713;, + 3;725,715,714;, + 3;727,713,716;, + 3;726,717,715;, + 3;729,716,718;, + 3;728,712,717;, + 3;723,718,711;, + 3;726,733,728;, + 3;729,730,727;, + 3;734,738,730;, + 3;723,735,729;, + 3;728,741,719;, + 3;719,742,720;, + 3;721,739,723;, + 3;813,742,741;, + 3;812,743,742;, + 3;814,744,743;, + 3;815,739,744;, + 3;816,735,739;, + 3;817,736,735;, + 3;818,740,736;, + 3;819,741,740;, + 3;732,738,733;, + 3;764,763,795;, + 3;774,820,775;, + 3;443,821,454;, + 3;453,462,775;, + 3;454,776,463;, + 3;820,439,453;, + 3;820,453,775;, + 3;821,777,776;, + 3;821,776,454;, + 3;439,820,822;, + 3;439,822,823;, + 3;821,443,824;, + 3;821,824,825;, + 3;443,439,823;, + 3;443,823,824;, + 3;820,774,826;, + 3;820,826,822;, + 3;774,777,827;, + 3;774,827,826;, + 3;777,821,825;, + 3;777,825,827;, + 3;823,822,828;, + 3;823,828,829;, + 3;825,824,830;, + 3;825,830,831;, + 3;824,823,829;, + 3;824,829,830;, + 3;822,826,832;, + 3;822,832,828;, + 3;826,827,833;, + 3;826,833,832;, + 3;827,825,831;, + 3;827,831,833;, + 3;829,828,834;, + 3;829,834,835;, + 3;831,830,836;, + 3;831,836,837;, + 3;830,829,835;, + 3;830,835,836;, + 3;828,832,838;, + 3;828,838,834;, + 3;832,833,839;, + 3;832,839,838;, + 3;833,831,837;, + 3;833,837,839;, + 3;835,834,840;, + 3;835,840,841;, + 3;837,836,842;, + 3;837,842,843;, + 3;836,835,841;, + 3;836,841,842;, + 3;834,838,844;, + 3;834,844,840;, + 3;838,839,845;, + 3;838,845,844;, + 3;839,837,843;, + 3;839,843,845;, + 3;841,840,846;, + 3;841,846,847;, + 3;843,842,848;, + 3;843,848,849;, + 3;842,841,847;, + 3;842,847,848;, + 3;840,844,850;, + 3;840,850,846;, + 3;844,845,851;, + 3;844,851,850;, + 3;845,843,849;, + 3;845,849,851;, + 3;847,846,852;, + 3;847,852,853;, + 3;854,855,848;, + 3;848,847,853;, + 3;848,853,854;, + 3;846,850,856;, + 3;846,856,852;, + 3;850,851,857;, + 3;850,857,856;, + 3;851,849,858;, + 3;851,858,857;, + 3;853,852,675;, + 3;853,675,674;, + 3;858,855,683;, + 3;674,682,853;, + 3;852,856,677;, + 3;852,677,675;, + 3;856,857,684;, + 3;856,684,677;, + 3;857,858,683;, + 3;857,683,684;, + 3;677,684,692;, + 3;677,692,676;, + 3;855,858,849;, + 3;855,849,848;, + 3;855,854,691;, + 3;855,691,683;, + 3;682,691,854;, + 3;682,854,853;, + 3;683,689,688;, + 3;859,860,861;, + 3;862,859,861;, + 3;862,861,863;, + 3;864,862,863;, + 3;864,863,865;, + 3;866,864,865;, + 3;866,865,867;, + 3;868,866,867;, + 3;868,867,869;, + 3;870,868,869;, + 3;870,869,871;, + 3;872,870,871;, + 3;872,871,873;, + 3;874,872,873;, + 3;875,876,877;, + 3;878,875,877;, + 3;879,880,877;, + 3;880,881,878;, + 3;880,878,877;, + 3;880,863,861;, + 3;879,873,871;, + 3;879,871,869;, + 3;880,879,869;, + 3;880,869,867;, + 3;880,867,865;, + 3;880,865,863;, + 3;880,861,881;, + 3;881,861,860;, + 3;882,883,859;, + 3;862,882,859;, + 3;884,882,862;, + 3;864,884,862;, + 3;885,884,864;, + 3;866,885,864;, + 3;886,885,866;, + 3;868,886,866;, + 3;887,886,868;, + 3;870,887,868;, + 3;888,887,870;, + 3;872,888,870;, + 3;889,888,872;, + 3;874,889,872;, + 3;890,891,892;, + 3;893,890,892;, + 3;890,894,895;, + 3;893,896,894;, + 3;890,893,894;, + 3;882,884,894;, + 3;888,889,895;, + 3;887,888,895;, + 3;894,887,895;, + 3;886,887,894;, + 3;885,886,894;, + 3;884,885,894;, + 3;896,882,894;, + 3;883,882,896;, + 3;883,860,859;, + 3;889,874,873;, + 3;891,876,875;, + 3;892,891,875;, + 3;890,877,876;, + 3;891,890,876;, + 3;892,875,878;, + 3;893,892,878;, + 3;895,879,877;, + 3;890,895,877;, + 3;893,878,881;, + 3;896,893,881;, + 3;889,873,879;, + 3;895,889,879;, + 3;896,881,860;, + 3;883,896,860;, + 3;897,898,899;, + 3;900,901,898;, + 3;897,900,898;, + 3;902,903,904;, + 3;905,897,899;, + 3;906,900,897;, + 3;905,906,897;, + 3;907,903,902;, + 3;908,905,899;, + 3;909,906,905;, + 3;908,909,905;, + 3;910,903,907;, + 3;911,908,899;, + 3;912,909,908;, + 3;911,912,908;, + 3;913,903,910;, + 3;914,911,899;, + 3;915,912,911;, + 3;914,915,911;, + 3;916,903,913;, + 3;917,914,899;, + 3;918,915,914;, + 3;917,918,914;, + 3;919,903,916;, + 3;920,917,899;, + 3;921,918,917;, + 3;920,921,917;, + 3;922,903,919;, + 3;898,920,899;, + 3;901,921,920;, + 3;898,901,920;, + 3;904,903,922;, + 3;923,924,925;, + 3;926,923,925;, + 3;927,923,926;, + 3;928,927,926;, + 3;929,927,928;, + 3;930,929,928;, + 3;931,929,930;, + 3;932,931,930;, + 3;933,931,932;, + 3;934,933,932;, + 3;935,933,934;, + 3;936,935,934;, + 3;937,935,936;, + 3;938,937,936;, + 3;924,937,938;, + 3;925,924,938;, + 3;939,940,941;, + 3;942,939,941;, + 3;943,939,942;, + 3;944,943,942;, + 3;945,943,944;, + 3;946,945,944;, + 3;947,945,946;, + 3;948,947,946;, + 3;949,947,948;, + 3;950,949,948;, + 3;951,949,950;, + 3;952,951,950;, + 3;953,951,952;, + 3;954,953,952;, + 3;940,953,954;, + 3;941,940,954;, + 3;902,904,955;, + 3;956,902,955;, + 3;907,902,956;, + 3;957,907,956;, + 3;910,907,957;, + 3;958,910,957;, + 3;913,910,958;, + 3;959,913,958;, + 3;916,913,959;, + 3;960,916,959;, + 3;919,916,960;, + 3;961,919,960;, + 3;922,919,961;, + 3;962,922,961;, + 3;904,922,962;, + 3;955,904,962;, + 3;963,964,965;, + 3;966,963,965;, + 3;967,963,966;, + 3;968,967,966;, + 3;969,967,968;, + 3;970,969,968;, + 3;971,969,970;, + 3;972,971,970;, + 3;973,971,972;, + 3;974,973,972;, + 3;975,973,974;, + 3;976,975,974;, + 3;977,975,976;, + 3;978,977,976;, + 3;964,977,978;, + 3;965,964,978;, + 3;963,956,955;, + 3;964,963,955;, + 3;965,924,923;, + 3;966,965,923;, + 3;967,957,956;, + 3;963,967,956;, + 3;966,923,927;, + 3;968,966,927;, + 3;969,958,957;, + 3;967,969,957;, + 3;968,927,929;, + 3;970,968,929;, + 3;971,959,958;, + 3;969,971,958;, + 3;970,929,931;, + 3;972,970,931;, + 3;973,960,959;, + 3;971,973,959;, + 3;972,931,933;, + 3;974,972,933;, + 3;975,961,960;, + 3;973,975,960;, + 3;974,933,935;, + 3;976,974,935;, + 3;977,962,961;, + 3;975,977,961;, + 3;976,935,937;, + 3;978,976,937;, + 3;964,955,962;, + 3;977,964,962;, + 3;978,937,924;, + 3;965,978,924;, + 3;939,926,925;, + 3;940,939,925;, + 3;941,901,900;, + 3;942,941,900;, + 3;943,928,926;, + 3;939,943,926;, + 3;942,900,906;, + 3;944,942,906;, + 3;945,930,928;, + 3;943,945,928;, + 3;944,906,909;, + 3;946,944,909;, + 3;947,932,930;, + 3;945,947,930;, + 3;946,909,912;, + 3;948,946,912;, + 3;949,934,932;, + 3;947,949,932;, + 3;948,912,915;, + 3;950,948,915;, + 3;951,936,934;, + 3;949,951,934;, + 3;950,915,918;, + 3;952,950,918;, + 3;953,938,936;, + 3;951,953,936;, + 3;952,918,921;, + 3;954,952,921;, + 3;940,925,938;, + 3;953,940,938;, + 3;954,921,901;, + 3;941,954,901;; + } + + MeshTextureCoords + { + 1479; + 0.280615;0.558309;, + 0.352344;0.554924;, + 0.369747;0.634334;, + 0.289371;0.647432;, + 0.201996;0.558309;, + 0.201322;0.630433;, + 0.106905;0.558899;, + 0.111895;0.631083;, + 0.285424;0.558309;, + 0.345657;0.555196;, + 0.330844;0.522226;, + 0.271138;0.475430;, + 0.196666;0.558309;, + 0.197484;0.478011;, + 0.117133;0.559519;, + 0.134823;0.506295;, + 0.334255;0.513986;, + 0.294188;0.647073;, + 0.355995;0.630874;, + 0.277231;0.467783;, + 0.195995;0.630044;, + 0.198470;0.465449;, + 0.120283;0.629581;, + 0.129080;0.494225;, + 0.369747;0.634334;, + 0.352344;0.554924;, + 0.280615;0.558309;, + 0.289371;0.647432;, + 0.201996;0.558309;, + 0.201322;0.630433;, + 0.106905;0.558899;, + 0.111895;0.631083;, + 0.330844;0.522226;, + 0.345657;0.555196;, + 0.285424;0.558309;, + 0.271138;0.475430;, + 0.196666;0.558309;, + 0.197484;0.478011;, + 0.117133;0.559519;, + 0.134823;0.506295;, + 0.334255;0.513986;, + 0.294188;0.647073;, + 0.355995;0.630874;, + 0.277231;0.467783;, + 0.195995;0.630044;, + 0.198470;0.465449;, + 0.120283;0.629581;, + 0.129080;0.494225;, + 0.883088;0.082413;, + 0.952602;0.082413;, + 0.952602;0.124822;, + 0.886670;0.125688;, + 0.845982;0.082413;, + 0.853762;0.092854;, + 0.803697;0.099653;, + 0.818882;0.082413;, + 0.550187;0.108550;, + 0.549541;0.099912;, + 0.521198;0.108242;, + 0.570984;0.105166;, + 0.559898;0.090185;, + 0.524569;0.093462;, + 0.590036;0.104329;, + 0.609816;0.100136;, + 0.609816;0.094012;, + 0.599702;0.103594;, + 0.609816;0.120548;, + 0.595746;0.121809;, + 0.488608;0.098736;, + 0.584643;0.123322;, + 0.609816;0.131139;, + 0.599203;0.131643;, + 0.590592;0.133959;, + 0.576247;0.124880;, + 0.572237;0.121932;, + 0.573963;0.136508;, + 0.580782;0.133278;, + 0.576453;0.120504;, + 0.520895;0.082413;, + 0.488125;0.082413;, + 0.563259;0.082413;, + 0.609816;0.082413;, + 0.609816;0.138599;, + 0.578418;0.137559;, + 0.593845;0.139019;, + 0.572039;0.122828;, + 0.572039;0.137791;, + 0.564045;0.135397;, + 0.563414;0.125172;, + 0.551182;0.122339;, + 0.547324;0.144010;, + 0.522523;0.121370;, + 0.522461;0.151881;, + 0.491771;0.120638;, + 0.485200;0.143898;, + 0.771477;0.082413;, + 0.771542;0.101298;, + 0.768210;0.120830;, + 0.580931;0.158343;, + 0.570449;0.163309;, + 0.574303;0.168917;, + 0.585622;0.167880;, + 0.609816;0.155714;, + 0.609816;0.165248;, + 0.609816;0.140236;, + 0.589064;0.140091;, + 0.578822;0.152508;, + 0.609816;0.150620;, + 0.569837;0.139814;, + 0.563751;0.158980;, + 0.546868;0.146335;, + 0.563096;0.170687;, + 0.532636;0.154841;, + 0.548798;0.169209;, + 0.497169;0.176069;, + 0.488662;0.173898;, + 0.525106;0.183955;, + 0.528242;0.192703;, + 0.537397;0.191192;, + 0.575976;0.174984;, + 0.609816;0.171885;, + 0.502307;0.209559;, + 0.609816;0.205712;, + 0.579870;0.208627;, + 0.609816;0.249215;, + 0.590314;0.270046;, + 0.549502;0.223146;, + 0.443436;0.224306;, + 0.480367;0.239659;, + 0.518461;0.263323;, + 0.553895;0.290008;, + 0.454060;0.280620;, + 0.433337;0.267212;, + 0.451713;0.279666;, + 0.484038;0.286519;, + 0.502163;0.296979;, + 0.812102;0.170782;, + 0.805323;0.132241;, + 0.442623;0.287970;, + 0.444460;0.290005;, + 0.472601;0.298053;, + 0.490726;0.308513;, + 0.820616;0.294451;, + 0.872608;0.298270;, + 0.460271;0.313764;, + 0.865127;0.329289;, + 0.830969;0.345938;, + 0.863058;0.350187;, + 0.430798;0.359632;, + 0.855289;0.369545;, + 0.832614;0.410798;, + 0.977253;0.082413;, + 0.977253;0.124822;, + 0.850503;0.118681;, + 0.836291;0.132722;, + 0.977253;0.162733;, + 0.937459;0.164546;, + 0.893619;0.175809;, + 0.846623;0.200535;, + 0.977253;0.204540;, + 0.934116;0.216421;, + 0.894289;0.229689;, + 0.840330;0.248155;, + 0.785859;0.267591;, + 0.488679;0.064671;, + 0.509745;0.064671;, + 0.558410;0.064671;, + 0.577029;0.064671;, + 0.597051;0.064671;, + 0.629523;0.064671;, + 0.653262;0.064671;, + 0.681827;0.064671;, + 0.711831;0.064671;, + 0.737024;0.064671;, + 0.488679;0.034046;, + 0.509740;0.034046;, + 0.558329;0.034046;, + 0.576834;0.034046;, + 0.596904;0.034046;, + 0.629776;0.034046;, + 0.653633;0.034046;, + 0.681781;0.034046;, + 0.711631;0.034046;, + 0.737024;0.034046;, + 0.488679;0.004105;, + 0.514426;0.004105;, + 0.554945;0.004105;, + 0.573423;0.004093;, + 0.594608;0.004075;, + 0.630847;0.004069;, + 0.656329;0.004118;, + 0.683589;0.004140;, + 0.706125;0.004111;, + 0.737024;0.004098;, + 0.611020;0.319170;, + 0.589653;0.319147;, + 0.556708;0.337698;, + 0.551911;0.353407;, + 0.543980;0.366476;, + 0.548138;0.390036;, + 0.551860;0.407144;, + 0.567299;0.423136;, + 0.586676;0.432468;, + 0.611020;0.437138;, + 0.611020;0.381372;, + 0.952552;0.082413;, + 0.883037;0.082413;, + 0.886620;0.125688;, + 0.952552;0.124822;, + 0.853762;0.092854;, + 0.845982;0.082413;, + 0.818882;0.082413;, + 0.803697;0.099653;, + 0.698437;0.106805;, + 0.668654;0.099194;, + 0.669447;0.108550;, + 0.650225;0.105166;, + 0.695064;0.093462;, + 0.656860;0.093779;, + 0.629597;0.104329;, + 0.619931;0.103594;, + 0.623887;0.121809;, + 0.733040;0.099166;, + 0.634991;0.123322;, + 0.620430;0.131643;, + 0.629041;0.133959;, + 0.647396;0.121932;, + 0.643386;0.124880;, + 0.638851;0.133278;, + 0.645671;0.136508;, + 0.643180;0.120504;, + 0.736511;0.082413;, + 0.698740;0.082413;, + 0.656374;0.082413;, + 0.625788;0.139019;, + 0.641215;0.137559;, + 0.647594;0.137791;, + 0.647594;0.122828;, + 0.656219;0.125172;, + 0.655588;0.135397;, + 0.665576;0.120182;, + 0.672309;0.144010;, + 0.692798;0.120651;, + 0.697172;0.151881;, + 0.731433;0.119786;, + 0.744808;0.142253;, + 0.771477;0.082413;, + 0.771542;0.101298;, + 0.768210;0.120830;, + 0.649184;0.163309;, + 0.638702;0.158343;, + 0.634011;0.167880;, + 0.645330;0.168917;, + 0.630569;0.140091;, + 0.640811;0.152508;, + 0.649796;0.139814;, + 0.655882;0.158980;, + 0.672766;0.146335;, + 0.656537;0.170687;, + 0.670836;0.169209;, + 0.686998;0.154841;, + 0.720784;0.179724;, + 0.729290;0.177552;, + 0.696600;0.188791;, + 0.691392;0.192703;, + 0.643657;0.174984;, + 0.682237;0.191192;, + 0.710804;0.204162;, + 0.639763;0.208627;, + 0.629319;0.270046;, + 0.670131;0.223146;, + 0.774517;0.229178;, + 0.739679;0.241380;, + 0.711278;0.259955;, + 0.665739;0.290008;, + 0.766770;0.280022;, + 0.760151;0.282057;, + 0.771099;0.269284;, + 0.735595;0.286519;, + 0.717471;0.296979;, + 0.812102;0.170782;, + 0.805323;0.132241;, + 0.775600;0.289980;, + 0.771064;0.292089;, + 0.747034;0.300317;, + 0.728909;0.308513;, + 0.820616;0.294451;, + 0.872608;0.298270;, + 0.759362;0.313764;, + 0.865127;0.329289;, + 0.830969;0.345938;, + 0.863058;0.350187;, + 0.788837;0.359632;, + 0.855289;0.369545;, + 0.832614;0.410798;, + 0.836291;0.132722;, + 0.850503;0.118681;, + 0.937408;0.164546;, + 0.846623;0.200535;, + 0.893619;0.175809;, + 0.934066;0.216421;, + 0.894289;0.229689;, + 0.840330;0.248155;, + 0.785859;0.267591;, + 0.964301;0.064671;, + 0.917764;0.064671;, + 0.897016;0.064671;, + 0.876995;0.064671;, + 0.844523;0.064671;, + 0.820785;0.064671;, + 0.792219;0.064671;, + 0.762215;0.064671;, + 0.964306;0.034046;, + 0.917844;0.034046;, + 0.897212;0.034046;, + 0.877141;0.034046;, + 0.844270;0.034046;, + 0.820414;0.034046;, + 0.792265;0.034046;, + 0.762416;0.034046;, + 0.959620;0.004105;, + 0.921228;0.004105;, + 0.900623;0.004093;, + 0.879437;0.004075;, + 0.843198;0.004069;, + 0.817717;0.004118;, + 0.790457;0.004140;, + 0.767920;0.004111;, + 0.632386;0.319147;, + 0.665331;0.337698;, + 0.670129;0.353407;, + 0.678059;0.366476;, + 0.673901;0.390036;, + 0.670179;0.407144;, + 0.654740;0.423136;, + 0.635362;0.432468;, + 0.391029;0.473726;, + 0.369726;0.473726;, + 0.369726;0.506185;, + 0.375924;0.506185;, + 0.369196;0.401156;, + 0.348048;0.473726;, + 0.363152;0.506185;, + 0.369726;0.473726;, + 0.369726;0.506185;, + 0.348424;0.473726;, + 0.363527;0.506185;, + 0.389704;0.473726;, + 0.363527;0.506185;, + 0.371565;0.129504;, + 0.355624;0.129504;, + 0.355624;0.175198;, + 0.368648;0.175198;, + 0.386154;0.129504;, + 0.386565;0.175198;, + 0.401455;0.129504;, + 0.401455;0.175198;, + 0.416757;0.129504;, + 0.416346;0.175198;, + 0.431346;0.129504;, + 0.434263;0.175198;, + 0.355624;0.086776;, + 0.369098;0.086776;, + 0.383421;0.086776;, + 0.397779;0.086776;, + 0.416817;0.086776;, + 0.431140;0.086776;, + 0.355571;0.048160;, + 0.371528;0.048160;, + 0.383328;0.048160;, + 0.398025;0.048160;, + 0.411409;0.048160;, + 0.429026;0.048160;, + 0.400607;0.010969;, + 0.355624;0.175198;, + 0.355624;0.129504;, + 0.371565;0.129504;, + 0.368648;0.175198;, + 0.386154;0.129504;, + 0.386565;0.175198;, + 0.401455;0.129504;, + 0.401455;0.175198;, + 0.416757;0.129504;, + 0.416346;0.175198;, + 0.431346;0.129504;, + 0.434263;0.175198;, + 0.355624;0.086776;, + 0.369098;0.086776;, + 0.383421;0.086776;, + 0.397779;0.086776;, + 0.416817;0.086776;, + 0.431140;0.086776;, + 0.355571;0.048160;, + 0.371528;0.048160;, + 0.383328;0.048160;, + 0.398025;0.048160;, + 0.411409;0.048160;, + 0.429026;0.048160;, + 0.400607;0.010969;, + 0.517951;0.890433;, + 0.427137;0.883950;, + 0.435186;0.982633;, + 0.510383;0.975251;, + 0.415278;0.689727;, + 0.370135;0.659013;, + 0.391969;0.701679;, + 0.572844;0.892869;, + 0.567696;0.972005;, + 0.425793;0.670568;, + 0.625334;0.894379;, + 0.629035;0.955158;, + 0.715766;0.705303;, + 0.712791;0.895888;, + 0.712791;0.942076;, + 0.744180;0.713567;, + 0.777555;0.942076;, + 0.777555;0.895888;, + 0.503275;0.813897;, + 0.440512;0.799365;, + 0.629357;0.811287;, + 0.584542;0.818759;, + 0.720847;0.803956;, + 0.777555;0.803956;, + 0.480556;0.722650;, + 0.402939;0.738043;, + 0.900980;0.491809;, + 0.873420;0.492783;, + 0.732693;0.753223;, + 0.370135;0.701679;, + 0.370135;0.731323;, + 0.370135;0.883950;, + 0.370135;0.982633;, + 0.777555;0.713567;, + 0.370135;0.799365;, + 0.777555;0.751715;, + 0.836156;0.510838;, + 0.873268;0.519740;, + 0.305207;0.982633;, + 0.313256;0.883950;, + 0.222442;0.890433;, + 0.230010;0.975251;, + 0.343249;0.701679;, + 0.325115;0.689727;, + 0.176734;0.894092;, + 0.180046;0.971166;, + 0.314600;0.670568;, + 0.935726;0.894379;, + 0.942692;0.955158;, + 0.838894;0.705303;, + 0.841869;0.895888;, + 0.841869;0.942076;, + 0.810480;0.713567;, + 0.299881;0.799365;, + 0.237118;0.813897;, + 0.970118;0.818759;, + 0.914636;0.811287;, + 0.833813;0.803956;, + 0.332279;0.738043;, + 0.259837;0.722650;, + 0.873420;0.492783;, + 0.900980;0.491809;, + 0.821967;0.753223;, + 0.836156;0.510838;, + 0.873268;0.519740;, + 0.918959;0.405681;, + 0.898498;0.429269;, + 0.894966;0.400969;, + 0.990199;0.426294;, + 0.947165;0.384354;, + 0.971267;0.413782;, + 0.956838;0.417097;, + 0.967154;0.447736;, + 0.978365;0.446699;, + 0.955778;0.486085;, + 0.940586;0.319616;, + 0.944732;0.317124;, + 0.975241;0.318740;, + 0.975564;0.320794;, + 0.943364;0.442528;, + 0.928589;0.476796;, + 0.906900;0.466579;, + 0.904555;0.321383;, + 0.903345;0.321307;, + 0.907629;0.434826;, + 0.885399;0.445480;, + 0.875628;0.426406;, + 0.896440;0.422435;, + 0.926290;0.443429;, + 0.953860;0.405111;, + 0.892791;0.421365;, + 0.910186;0.401974;, + 0.882443;0.367108;, + 0.872030;0.376435;, + 0.888582;0.381286;, + 0.896041;0.370924;, + 0.894747;0.401967;, + 0.872978;0.406447;, + 0.891864;0.404921;, + 0.951217;0.361266;, + 0.986172;0.364345;, + 0.987166;0.358691;, + 0.945619;0.365525;, + 0.896655;0.370095;, + 0.987594;0.438274;, + 0.063348;0.627819;, + 0.077953;0.584320;, + 0.011718;0.584154;, + 0.079060;0.581589;, + 0.013910;0.580729;, + 0.080683;0.486679;, + 0.059355;0.473666;, + 0.029863;0.472997;, + 0.071135;0.548371;, + 0.009488;0.486523;, + 0.010087;0.551560;, + 0.100741;0.470991;, + 0.097934;0.479430;, + 0.107691;0.470245;, + 0.107687;0.470545;, + 0.110970;0.479430;, + 0.101601;0.502242;, + 0.107919;0.502385;, + 0.097032;0.499086;, + 0.110626;0.499488;, + 0.099079;0.486255;, + 0.111420;0.485572;, + 0.106250;0.421203;, + 0.078698;0.426763;, + 0.127709;0.425565;, + 0.172089;0.424328;, + 0.166487;0.427056;, + 0.050569;0.412161;, + 0.035610;0.406526;, + 0.052377;0.444396;, + 0.051832;0.429629;, + 0.227606;0.399193;, + 0.205078;0.399390;, + 0.229717;0.399311;, + 0.254647;0.399270;, + 0.272080;0.399407;, + 0.252416;0.399142;, + 0.070362;0.287393;, + 0.016046;0.293476;, + 0.016046;0.324669;, + 0.072292;0.324669;, + 0.113194;0.285322;, + 0.113279;0.324669;, + 0.158180;0.271515;, + 0.163873;0.324669;, + 0.206640;0.268446;, + 0.206640;0.324669;, + 0.247941;0.274515;, + 0.242835;0.324669;, + 0.283810;0.288322;, + 0.278594;0.324669;, + 0.311221;0.290393;, + 0.315308;0.324669;, + 0.068945;0.235193;, + 0.016046;0.240473;, + 0.108219;0.207433;, + 0.152927;0.178981;, + 0.206640;0.167059;, + 0.252867;0.175304;, + 0.288891;0.212805;, + 0.318162;0.231991;, + 0.065705;0.198441;, + 0.016046;0.208214;, + 0.155878;0.116450;, + 0.260626;0.086608;, + 0.206640;0.069824;, + 0.297131;0.129663;, + 0.334772;0.190121;, + 0.877720;0.549659;, + 0.835118;0.546998;, + 0.835052;0.586744;, + 0.876715;0.589598;, + 0.068252;0.887184;, + 0.089066;0.958830;, + 0.046998;0.832490;, + 0.029357;0.785551;, + 0.023073;0.712469;, + 0.023073;0.674844;, + 0.145853;0.888391;, + 0.143516;0.958116;, + 0.177991;0.831961;, + 0.197564;0.786458;, + 0.213185;0.711950;, + 0.215318;0.674844;, + 0.157821;0.890682;, + 0.156902;0.959254;, + 0.190868;0.832283;, + 0.205079;0.782164;, + 0.223096;0.710534;, + 0.225229;0.674844;, + 0.153638;0.053327;, + 0.334772;0.160303;, + 0.086938;0.892203;, + 0.143516;0.891840;, + 0.156902;0.892732;, + 0.055189;0.189485;, + 0.065223;0.170997;, + 0.067039;0.047965;, + 0.105565;0.048142;, + 0.068508;0.117444;, + 0.107800;0.133075;, + 0.343109;0.380090;, + 0.323832;0.383288;, + 0.355057;0.385320;, + 0.206829;0.384744;, + 0.234567;0.382514;, + 0.257187;0.388855;, + 0.276919;0.382594;, + 0.298064;0.380974;, + 0.344860;0.373637;, + 0.325680;0.376362;, + 0.354260;0.377471;, + 0.204463;0.374769;, + 0.233180;0.376205;, + 0.251611;0.377892;, + 0.277423;0.373836;, + 0.298171;0.373284;, + 0.140035;0.355838;, + 0.100853;0.355882;, + 0.154296;0.355147;, + 0.169423;0.354964;, + 0.097884;0.347432;, + 0.078303;0.359102;, + 0.054330;0.360424;, + 0.076810;0.360458;, + 0.784640;0.576144;, + 0.931041;0.562636;, + 0.783145;0.623006;, + 0.702517;0.610617;, + 0.985871;0.600609;, + 0.931288;0.605739;, + 0.844017;0.627798;, + 0.881038;0.614886;, + 0.782830;0.648292;, + 0.697657;0.637050;, + 0.985871;0.627042;, + 0.929760;0.623529;, + 0.843533;0.654056;, + 0.883177;0.641144;, + 0.454991;0.524293;, + 0.410274;0.510212;, + 0.603777;0.507259;, + 0.564440;0.512230;, + 0.487397;0.524067;, + 0.520078;0.523358;, + 0.455289;0.523505;, + 0.409861;0.511667;, + 0.604047;0.509031;, + 0.564126;0.512622;, + 0.488686;0.521909;, + 0.523239;0.524440;, + 0.449119;0.565596;, + 0.407333;0.554503;, + 0.605049;0.554831;, + 0.569952;0.558712;, + 0.492583;0.572056;, + 0.526891;0.572306;, + 0.436540;0.611713;, + 0.402027;0.604724;, + 0.585826;0.605834;, + 0.606428;0.604934;, + 0.491624;0.615716;, + 0.535771;0.615875;, + 0.577581;0.606189;, + 0.894966;0.400969;, + 0.898498;0.429269;, + 0.918959;0.405681;, + 0.902644;0.387762;, + 0.947165;0.384354;, + 0.969630;0.436914;, + 0.966359;0.469649;, + 0.985675;0.467648;, + 0.988300;0.434689;, + 0.955778;0.486085;, + 0.975241;0.318740;, + 0.944732;0.317124;, + 0.940586;0.319616;, + 0.975564;0.320794;, + 0.943364;0.442528;, + 0.906900;0.466579;, + 0.928589;0.476796;, + 0.903345;0.321307;, + 0.903853;0.322786;, + 0.875628;0.426406;, + 0.885399;0.445480;, + 0.907629;0.434826;, + 0.896440;0.422435;, + 0.926290;0.443429;, + 0.953860;0.405111;, + 0.892791;0.421365;, + 0.910186;0.401974;, + 0.888582;0.381286;, + 0.872030;0.376435;, + 0.882443;0.367108;, + 0.896041;0.370924;, + 0.872978;0.406447;, + 0.894747;0.401967;, + 0.891864;0.404921;, + 0.951217;0.361266;, + 0.986172;0.364345;, + 0.987166;0.358691;, + 0.945619;0.365525;, + 0.896655;0.370095;, + 0.899278;0.370234;, + 0.011718;0.584154;, + 0.077953;0.584320;, + 0.063348;0.627819;, + 0.013910;0.580729;, + 0.079060;0.581589;, + 0.029863;0.472997;, + 0.059355;0.473666;, + 0.080683;0.486679;, + 0.009488;0.486523;, + 0.071135;0.548371;, + 0.010087;0.551560;, + 0.097961;0.479430;, + 0.100768;0.470991;, + 0.107714;0.470545;, + 0.107717;0.470245;, + 0.110997;0.479430;, + 0.107946;0.502385;, + 0.101628;0.502242;, + 0.097059;0.499086;, + 0.110653;0.499488;, + 0.099105;0.486255;, + 0.111447;0.485572;, + 0.078698;0.426763;, + 0.106250;0.421203;, + 0.127709;0.425565;, + 0.172089;0.424328;, + 0.166487;0.427056;, + 0.035610;0.406526;, + 0.050569;0.412161;, + 0.051832;0.429629;, + 0.052377;0.444396;, + 0.227606;0.399193;, + 0.205078;0.399390;, + 0.229717;0.399311;, + 0.254647;0.399270;, + 0.272080;0.399407;, + 0.252416;0.399142;, + 0.016046;0.324669;, + 0.016046;0.293476;, + 0.070362;0.287393;, + 0.072292;0.324669;, + 0.113194;0.285322;, + 0.113279;0.324669;, + 0.158180;0.271515;, + 0.163873;0.324669;, + 0.206640;0.268446;, + 0.206640;0.324669;, + 0.247941;0.274515;, + 0.242835;0.324669;, + 0.283810;0.288322;, + 0.278594;0.324669;, + 0.311221;0.290393;, + 0.315308;0.324669;, + 0.016046;0.240473;, + 0.068945;0.235193;, + 0.108219;0.207433;, + 0.152927;0.178981;, + 0.206640;0.167059;, + 0.252867;0.175304;, + 0.288891;0.212805;, + 0.318162;0.231991;, + 0.065705;0.198441;, + 0.155878;0.116450;, + 0.206640;0.069824;, + 0.260626;0.086608;, + 0.297131;0.129663;, + 0.835052;0.586744;, + 0.835118;0.546998;, + 0.877720;0.549659;, + 0.876715;0.589598;, + 0.068252;0.887184;, + 0.089066;0.958830;, + 0.046998;0.832490;, + 0.029357;0.785551;, + 0.023073;0.712469;, + 0.145853;0.888391;, + 0.143516;0.958116;, + 0.177991;0.831961;, + 0.197564;0.786458;, + 0.213185;0.711950;, + 0.157821;0.890682;, + 0.156902;0.959254;, + 0.190868;0.832283;, + 0.205079;0.782164;, + 0.223096;0.710534;, + 0.153638;0.053327;, + 0.105565;0.048142;, + 0.107800;0.133075;, + 0.343109;0.380090;, + 0.323832;0.383288;, + 0.355057;0.385320;, + 0.206829;0.384744;, + 0.234567;0.382514;, + 0.257187;0.388855;, + 0.276919;0.382594;, + 0.298064;0.380974;, + 0.344860;0.373637;, + 0.325680;0.376362;, + 0.354260;0.377471;, + 0.204463;0.374769;, + 0.233180;0.376205;, + 0.251611;0.377892;, + 0.277423;0.373836;, + 0.298171;0.373284;, + 0.140035;0.355838;, + 0.100853;0.355882;, + 0.154296;0.355147;, + 0.169423;0.354964;, + 0.097884;0.347432;, + 0.078303;0.359102;, + 0.054330;0.360424;, + 0.076810;0.360458;, + 0.784640;0.576144;, + 0.931041;0.562636;, + 0.783145;0.623006;, + 0.702517;0.610617;, + 0.985871;0.600609;, + 0.931288;0.605739;, + 0.844017;0.627798;, + 0.881038;0.614886;, + 0.782830;0.648292;, + 0.697657;0.637050;, + 0.985871;0.627042;, + 0.929760;0.623529;, + 0.843533;0.654056;, + 0.883177;0.641144;, + 0.454991;0.524293;, + 0.410274;0.510212;, + 0.603777;0.507259;, + 0.564440;0.512230;, + 0.487397;0.524067;, + 0.520078;0.523358;, + 0.455289;0.523505;, + 0.409861;0.511667;, + 0.604047;0.509031;, + 0.564126;0.512622;, + 0.488686;0.521909;, + 0.523239;0.524440;, + 0.449119;0.565596;, + 0.407333;0.554503;, + 0.605049;0.554831;, + 0.569952;0.558712;, + 0.492583;0.572056;, + 0.526891;0.572306;, + 0.436540;0.611713;, + 0.402027;0.604724;, + 0.606428;0.604934;, + 0.585826;0.605834;, + 0.491624;0.615716;, + 0.535771;0.615875;, + 0.577581;0.606189;, + 0.225629;0.906647;, + 0.257118;0.770403;, + 0.196806;0.682930;, + 0.100224;0.753850;, + 0.159871;0.589702;, + 0.034839;0.630259;, + 0.147435;0.493553;, + 0.018893;0.506986;, + 0.159871;0.397404;, + 0.034839;0.383712;, + 0.196806;0.304177;, + 0.082196;0.264183;, + 0.257118;0.216703;, + 0.159520;0.152032;, + 0.314932;0.166093;, + 0.318555;0.018152;, + 0.554152;0.626886;, + 0.557998;0.322535;, + 0.442610;0.296521;, + 0.431074;0.650296;, + 0.350303;0.254902;, + 0.336420;0.485623;, + 0.323379;0.702323;, + 0.196806;0.682655;, + 0.257118;0.770128;, + 0.159871;0.589427;, + 0.147435;0.493278;, + 0.159871;0.397130;, + 0.196806;0.303901;, + 0.257118;0.216428;, + 0.314932;0.165818;, + 0.442610;0.296246;, + 0.557998;0.322260;, + 0.554152;0.626611;, + 0.431074;0.650021;, + 0.336420;0.485348;, + 0.350303;0.254627;, + 0.323379;0.702048;, + 0.438450;0.893948;, + 0.393391;0.912613;, + 0.393391;0.848889;, + 0.731679;0.669200;, + 0.682021;0.669200;, + 0.496696;0.202288;, + 0.450065;0.155657;, + 0.450065;0.221604;, + 0.457115;0.848889;, + 0.781335;0.669200;, + 0.516012;0.155657;, + 0.438450;0.803826;, + 0.830993;0.669200;, + 0.496696;0.109022;, + 0.393391;0.785161;, + 0.880650;0.669200;, + 0.450065;0.089706;, + 0.348331;0.803826;, + 0.930304;0.669200;, + 0.403431;0.109022;, + 0.329666;0.848889;, + 0.979961;0.669200;, + 0.384118;0.155657;, + 0.348331;0.893948;, + 0.632365;0.669200;, + 0.403431;0.202288;, + 0.731679;0.199240;, + 0.682021;0.199240;, + 0.682021;0.474517;, + 0.731679;0.474517;, + 0.781335;0.199240;, + 0.781335;0.474517;, + 0.830993;0.199240;, + 0.830993;0.474517;, + 0.880650;0.199240;, + 0.880650;0.474517;, + 0.930304;0.199240;, + 0.930304;0.474517;, + 0.979961;0.199240;, + 0.979961;0.474517;, + 0.632365;0.199240;, + 0.632365;0.474517;, + 0.731679;0.480018;, + 0.682021;0.480018;, + 0.682021;0.663701;, + 0.731679;0.663701;, + 0.781335;0.480018;, + 0.781335;0.663701;, + 0.830993;0.480018;, + 0.830993;0.663701;, + 0.880650;0.480018;, + 0.880650;0.663701;, + 0.930304;0.480018;, + 0.930304;0.663701;, + 0.979961;0.480018;, + 0.979961;0.663701;, + 0.632365;0.480018;, + 0.632365;0.663701;, + 0.682021;0.038480;, + 0.731679;0.038480;, + 0.781335;0.038480;, + 0.830993;0.038480;, + 0.880650;0.038480;, + 0.930304;0.038480;, + 0.979961;0.038480;, + 0.632365;0.038480;, + 0.731679;0.038480;, + 0.682021;0.038480;, + 0.682021;0.199240;, + 0.731679;0.199240;, + 0.781335;0.038480;, + 0.781335;0.199240;, + 0.830993;0.038480;, + 0.830993;0.199240;, + 0.880650;0.038480;, + 0.880650;0.199240;, + 0.930304;0.038480;, + 0.930304;0.199240;, + 0.979961;0.038480;, + 0.979961;0.199240;, + 0.632365;0.038480;, + 0.632365;0.199240;, + 0.736511;0.082413;, + 0.733040;0.099166;, + 0.731433;0.119786;, + 0.744808;0.142253;, + 0.775285;0.229227;, + 0.825553;0.282190;, + 0.852349;0.284159;, + 0.402107;0.302317;, + 0.874543;0.302145;, + 0.852790;0.291030;, + 0.822925;0.307724;, + 0.404511;0.315541;, + 0.495438;0.334057;, + 0.395519;0.350837;, + 0.829692;0.356466;, + 0.396977;0.360710;, + 0.452126;0.371941;, + 0.404138;0.409819;, + 0.832399;0.409796;, + 0.850805;0.118056;, + 0.854157;0.093477;, + 0.836994;0.132361;, + 0.426443;0.264001;, + 0.846071;0.082413;, + 0.488679;0.071330;, + 0.509864;0.071330;, + 0.561990;0.071330;, + 0.574974;0.071330;, + 0.596153;0.071330;, + 0.630507;0.071330;, + 0.655447;0.071330;, + 0.685261;0.071330;, + 0.711741;0.071330;, + 0.737024;0.071330;, + 0.611020;0.297027;, + 0.572843;0.296995;, + 0.529308;0.322515;, + 0.522962;0.344128;, + 0.512484;0.362103;, + 0.517972;0.394490;, + 0.522892;0.418014;, + 0.543315;0.440027;, + 0.568927;0.452870;, + 0.611020;0.459291;, + 0.775285;0.229227;, + 0.825553;0.282190;, + 0.852349;0.284159;, + 0.817527;0.302317;, + 0.874543;0.302145;, + 0.822925;0.307724;, + 0.852790;0.291030;, + 0.815123;0.315541;, + 0.724198;0.334057;, + 0.824114;0.350837;, + 0.829692;0.356466;, + 0.822656;0.360710;, + 0.767508;0.371941;, + 0.815497;0.409819;, + 0.832399;0.409796;, + 0.854106;0.093477;, + 0.850754;0.118056;, + 0.836944;0.132361;, + 0.784785;0.267655;, + 0.846020;0.082413;, + 0.985368;0.071330;, + 0.985368;0.064671;, + 0.964181;0.071330;, + 0.920566;0.071330;, + 0.899072;0.071330;, + 0.877892;0.071330;, + 0.843538;0.071330;, + 0.818598;0.071330;, + 0.788785;0.071330;, + 0.762305;0.071330;, + 0.985368;0.034046;, + 0.985368;0.004105;, + 0.649194;0.296995;, + 0.692732;0.322515;, + 0.699077;0.344128;, + 0.709556;0.362103;, + 0.704068;0.394490;, + 0.699148;0.418014;, + 0.678724;0.440027;, + 0.653112;0.452870;, + 0.348048;0.473726;, + 0.363152;0.506185;, + 0.369880;0.401156;, + 0.391029;0.473726;, + 0.375924;0.506185;, + 0.389704;0.473726;, + 0.374601;0.506185;, + 0.348424;0.473726;, + 0.368932;0.401156;, + 0.452400;0.129504;, + 0.452400;0.175198;, + 0.452400;0.086776;, + 0.452347;0.048160;, + 0.452400;0.129504;, + 0.452400;0.175198;, + 0.452400;0.086776;, + 0.452347;0.048160;, + 0.517436;0.890028;, + 0.510531;0.976844;, + 0.572671;0.894379;, + 0.568342;0.971093;, + 0.777555;0.678284;, + 0.694161;0.680784;, + 0.930651;0.528982;, + 0.636790;0.729840;, + 0.497690;0.695873;, + 0.625202;0.706393;, + 0.829864;0.489448;, + 0.791888;0.522384;, + 0.370258;0.659013;, + 0.230175;0.975238;, + 0.222812;0.890877;, + 0.990199;0.971093;, + 0.985870;0.894379;, + 0.860499;0.680784;, + 0.930651;0.528982;, + 0.917870;0.729840;, + 0.370258;0.731323;, + 0.370258;0.701679;, + 0.242703;0.695873;, + 0.929458;0.706393;, + 0.370258;0.883950;, + 0.370258;0.982633;, + 0.370258;0.799365;, + 0.791888;0.522384;, + 0.829864;0.489448;, + 0.986396;0.412257;, + 0.975310;0.418268;, + 0.902644;0.387762;, + 0.994669;0.402101;, + 0.981890;0.469917;, + 0.995134;0.390231;, + 0.984220;0.450300;, + 0.603782;0.643446;, + 0.609341;0.643446;, + 0.582531;0.643446;, + 0.973521;0.462071;, + 0.963886;0.460904;, + 0.973851;0.440898;, + 0.899278;0.370234;, + 0.961957;0.475718;, + 0.956964;0.472868;, + 0.985692;0.467093;, + 0.973104;0.465610;, + 0.100745;0.470691;, + 0.111438;0.479862;, + 0.110968;0.480595;, + 0.097932;0.480595;, + 0.098169;0.480010;, + 0.101601;0.502243;, + 0.097031;0.499087;, + 0.107919;0.502387;, + 0.099077;0.486238;, + 0.110626;0.499489;, + 0.111419;0.485555;, + 0.086807;0.443269;, + 0.132822;0.441307;, + 0.113511;0.444424;, + 0.140395;0.423608;, + 0.135060;0.441158;, + 0.136342;0.424943;, + 0.198735;0.443346;, + 0.075366;0.444316;, + 0.027868;0.432074;, + 0.208127;0.399315;, + 0.227674;0.440235;, + 0.195515;0.443409;, + 0.227674;0.438745;, + 0.267237;0.439863;, + 0.256190;0.399124;, + 0.269540;0.435635;, + 0.071134;0.428124;, + 0.066616;0.410202;, + 0.367433;0.293476;, + 0.367433;0.324669;, + 0.367433;0.240473;, + 0.367433;0.208214;, + 0.057618;0.889801;, + 0.075217;0.960259;, + 0.039094;0.831536;, + 0.022855;0.783300;, + 0.016830;0.710664;, + 0.016830;0.674844;, + 0.206640;0.029904;, + 0.152154;0.014424;, + 0.263299;0.059838;, + 0.297418;0.072112;, + 0.334772;0.081782;, + 0.073089;0.893078;, + 0.101798;0.013560;, + 0.065925;0.013560;, + 0.339698;0.346140;, + 0.322500;0.345093;, + 0.349771;0.347008;, + 0.206286;0.347083;, + 0.187234;0.346447;, + 0.192520;0.385320;, + 0.233624;0.344280;, + 0.264945;0.347083;, + 0.283942;0.347008;, + 0.302605;0.346140;, + 0.302349;0.346140;, + 0.297808;0.380974;, + 0.191723;0.377471;, + 0.297916;0.373284;, + 0.141389;0.337516;, + 0.096555;0.337516;, + 0.155781;0.337516;, + 0.141143;0.337516;, + 0.139486;0.355087;, + 0.169423;0.337516;, + 0.094962;0.337516;, + 0.139682;0.337516;, + 0.139079;0.356255;, + 0.070832;0.337516;, + 0.059451;0.337516;, + 0.037745;0.337516;, + 0.034063;0.355263;, + 0.069376;0.337516;, + 0.070089;0.337516;, + 0.078341;0.360000;, + 0.140295;0.410202;, + 0.154671;0.410202;, + 0.169423;0.410202;, + 0.106374;0.410202;, + 0.066616;0.410202;, + 0.050267;0.412054;, + 0.108395;0.410202;, + 0.052779;0.459751;, + 0.069646;0.449516;, + 0.301467;0.437159;, + 0.303759;0.398990;, + 0.031124;0.452374;, + 0.027488;0.628182;, + 0.133164;0.444513;, + 0.267437;0.438220;, + 0.140673;0.410202;, + 0.138160;0.410202;, + 0.035715;0.406444;, + 0.983283;0.552269;, + 0.717768;0.549735;, + 0.665848;0.551563;, + 0.665848;0.603961;, + 0.665848;0.624999;, + 0.465080;0.495146;, + 0.416895;0.485971;, + 0.596048;0.486003;, + 0.554443;0.490049;, + 0.648116;0.507207;, + 0.653986;0.485971;, + 0.495199;0.500632;, + 0.453668;0.524293;, + 0.520895;0.500658;, + 0.647703;0.508662;, + 0.453966;0.523505;, + 0.644424;0.554503;, + 0.639118;0.604724;, + 0.427648;0.643446;, + 0.408566;0.643446;, + 0.620138;0.643446;, + 0.645657;0.643446;, + 0.510273;0.643446;, + 0.560244;0.643446;, + 0.981890;0.469917;, + 0.994669;0.402101;, + 0.984220;0.450300;, + 0.995134;0.390231;, + 0.582531;0.643446;, + 0.609341;0.643446;, + 0.603782;0.643446;, + 0.987227;0.416442;, + 0.963436;0.423164;, + 0.960557;0.404342;, + 0.955628;0.408440;, + 0.100772;0.470691;, + 0.111465;0.479862;, + 0.110995;0.480595;, + 0.098196;0.480010;, + 0.097958;0.480595;, + 0.101627;0.502243;, + 0.097058;0.499087;, + 0.107946;0.502387;, + 0.099104;0.486238;, + 0.110652;0.499489;, + 0.111445;0.485555;, + 0.086807;0.443269;, + 0.113511;0.444424;, + 0.132822;0.441307;, + 0.135060;0.441158;, + 0.140395;0.423608;, + 0.198735;0.443346;, + 0.136342;0.424943;, + 0.075366;0.444316;, + 0.027868;0.432074;, + 0.227674;0.440235;, + 0.208127;0.399315;, + 0.195515;0.443409;, + 0.227674;0.438745;, + 0.256190;0.399124;, + 0.267237;0.439863;, + 0.269540;0.435635;, + 0.066616;0.410202;, + 0.071134;0.428124;, + 0.367433;0.293476;, + 0.367433;0.324669;, + 0.367433;0.240473;, + 0.075217;0.960259;, + 0.057618;0.889801;, + 0.039094;0.831536;, + 0.022855;0.783300;, + 0.016830;0.710664;, + 0.152154;0.014424;, + 0.206640;0.029904;, + 0.263299;0.059838;, + 0.297418;0.072112;, + 0.101798;0.013560;, + 0.322500;0.345093;, + 0.339698;0.346140;, + 0.349771;0.347008;, + 0.187234;0.346447;, + 0.206286;0.347083;, + 0.192520;0.385320;, + 0.233624;0.344280;, + 0.264945;0.347083;, + 0.283942;0.347008;, + 0.302605;0.346140;, + 0.302349;0.346140;, + 0.297808;0.380974;, + 0.191723;0.377471;, + 0.297916;0.373284;, + 0.096555;0.337516;, + 0.141389;0.337516;, + 0.141143;0.337516;, + 0.155781;0.337516;, + 0.139486;0.355087;, + 0.169423;0.337516;, + 0.139682;0.337516;, + 0.094962;0.337516;, + 0.139079;0.356255;, + 0.070832;0.337516;, + 0.037745;0.337516;, + 0.059451;0.337516;, + 0.034063;0.355263;, + 0.069376;0.337516;, + 0.070089;0.337516;, + 0.078341;0.360000;, + 0.140295;0.410202;, + 0.154671;0.410202;, + 0.169423;0.410202;, + 0.106374;0.410202;, + 0.066616;0.410202;, + 0.050267;0.412054;, + 0.108395;0.410202;, + 0.069646;0.449516;, + 0.052779;0.459751;, + 0.303759;0.398990;, + 0.301467;0.437159;, + 0.031124;0.452374;, + 0.027488;0.628182;, + 0.133164;0.444513;, + 0.267437;0.438220;, + 0.140673;0.410202;, + 0.138160;0.410202;, + 0.035715;0.406444;, + 0.983283;0.552269;, + 0.717768;0.549735;, + 0.665848;0.551563;, + 0.665848;0.603961;, + 0.665848;0.624999;, + 0.416895;0.485971;, + 0.465080;0.495146;, + 0.554443;0.490049;, + 0.596048;0.486003;, + 0.653986;0.485971;, + 0.648116;0.507207;, + 0.495199;0.500632;, + 0.453668;0.524293;, + 0.520895;0.500658;, + 0.647703;0.508662;, + 0.453966;0.523505;, + 0.644424;0.554503;, + 0.639118;0.604724;, + 0.427648;0.643446;, + 0.408566;0.643446;, + 0.645657;0.643446;, + 0.620138;0.643446;, + 0.510273;0.643446;, + 0.560244;0.643446;, + 0.664199;0.736052;, + 0.664199;0.796555;, + 0.531908;0.770624;, + 0.708835;0.738811;, + 0.532529;0.770158;, + 0.708835;0.799314;, + 0.971027;0.739715;, + 0.971027;0.800221;, + 0.967319;0.797731;, + 0.967319;0.737225;, + 0.859756;0.739928;, + 0.859756;0.800434;, + 0.848628;0.797539;, + 0.848628;0.737033;, + 0.768886;0.740271;, + 0.768886;0.800774;, + 0.716979;0.794925;, + 0.716979;0.734422;, + 0.682021;0.697485;, + 0.731679;0.697485;, + 0.781335;0.697485;, + 0.830993;0.697485;, + 0.880650;0.697485;, + 0.930304;0.697485;, + 0.979961;0.697485;, + 0.582708;0.669200;, + 0.582708;0.697485;, + 0.632365;0.697485;, + 0.582708;0.199240;, + 0.582708;0.474517;, + 0.582708;0.480018;, + 0.582708;0.663701;, + 0.731679;0.028928;, + 0.682021;0.028928;, + 0.781335;0.028928;, + 0.830993;0.028928;, + 0.880650;0.028928;, + 0.930304;0.028928;, + 0.979961;0.028928;, + 0.632365;0.028928;, + 0.582708;0.028928;, + 0.582708;0.038480;, + 0.582708;0.038480;, + 0.582708;0.199240;, + 0.525596;0.231189;, + 0.496696;0.202288;, + 0.450065;0.221604;, + 0.450065;0.262474;, + 0.393391;0.955706;, + 0.393391;0.912613;, + 0.438450;0.893948;, + 0.468922;0.924421;, + 0.556881;0.155657;, + 0.516012;0.155657;, + 0.457115;0.848889;, + 0.500207;0.848889;, + 0.525596;0.080125;, + 0.496696;0.109022;, + 0.438450;0.803826;, + 0.468922;0.773357;, + 0.450065;0.048836;, + 0.450065;0.089706;, + 0.393391;0.785161;, + 0.393391;0.742068;, + 0.374533;0.080125;, + 0.403431;0.109022;, + 0.348331;0.803826;, + 0.317859;0.773357;, + 0.343249;0.155657;, + 0.384118;0.155657;, + 0.329666;0.848889;, + 0.286574;0.848889;, + 0.374533;0.231189;, + 0.403431;0.202288;, + 0.348331;0.893948;, + 0.317859;0.924421;, + 0.519767;0.225363;, + 0.496696;0.202288;, + 0.450065;0.221604;, + 0.450065;0.254234;, + 0.393391;0.947466;, + 0.393391;0.912613;, + 0.438450;0.893948;, + 0.463096;0.918595;, + 0.548641;0.155657;, + 0.516012;0.155657;, + 0.457115;0.848889;, + 0.491967;0.848889;, + 0.519767;0.085951;, + 0.496696;0.109022;, + 0.438450;0.803826;, + 0.463096;0.779183;, + 0.450065;0.057076;, + 0.450065;0.089706;, + 0.393391;0.785161;, + 0.393391;0.750308;, + 0.380359;0.085951;, + 0.403431;0.109022;, + 0.348331;0.803826;, + 0.323688;0.779183;, + 0.351488;0.155657;, + 0.384118;0.155657;, + 0.329666;0.848889;, + 0.294813;0.848889;, + 0.380359;0.225363;, + 0.403431;0.202288;, + 0.348331;0.893948;, + 0.323688;0.918595;; + } + + VertexDuplicationIndices + { + 1479; + 979; + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 139, + 140, + 141, + 142, + 143, + 144, + 145, + 146, + 147, + 148, + 149, + 150, + 151, + 152, + 153, + 154, + 155, + 156, + 157, + 158, + 159, + 160, + 161, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 171, + 172, + 173, + 174, + 175, + 176, + 177, + 178, + 179, + 180, + 181, + 182, + 183, + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 209, + 210, + 211, + 212, + 213, + 214, + 215, + 216, + 217, + 218, + 219, + 220, + 221, + 222, + 223, + 224, + 225, + 226, + 227, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 235, + 236, + 237, + 238, + 239, + 240, + 241, + 242, + 243, + 244, + 245, + 246, + 247, + 248, + 249, + 250, + 251, + 252, + 253, + 254, + 255, + 256, + 257, + 258, + 259, + 260, + 261, + 262, + 263, + 264, + 265, + 266, + 267, + 268, + 269, + 270, + 271, + 272, + 273, + 274, + 275, + 276, + 277, + 278, + 279, + 280, + 281, + 282, + 283, + 284, + 285, + 286, + 287, + 288, + 289, + 290, + 291, + 292, + 293, + 294, + 295, + 296, + 297, + 298, + 299, + 300, + 301, + 302, + 303, + 304, + 305, + 306, + 307, + 308, + 309, + 310, + 311, + 312, + 313, + 314, + 315, + 316, + 317, + 318, + 319, + 320, + 321, + 322, + 323, + 324, + 325, + 326, + 327, + 328, + 329, + 330, + 331, + 332, + 333, + 334, + 335, + 336, + 337, + 338, + 339, + 340, + 341, + 342, + 343, + 344, + 345, + 346, + 347, + 348, + 349, + 350, + 351, + 352, + 353, + 354, + 355, + 356, + 357, + 358, + 359, + 360, + 361, + 362, + 363, + 364, + 365, + 366, + 367, + 368, + 369, + 370, + 371, + 372, + 373, + 374, + 375, + 376, + 377, + 378, + 379, + 380, + 381, + 382, + 383, + 384, + 385, + 386, + 387, + 388, + 389, + 390, + 391, + 392, + 393, + 394, + 395, + 396, + 397, + 398, + 399, + 400, + 401, + 402, + 403, + 404, + 405, + 406, + 407, + 408, + 409, + 410, + 411, + 412, + 413, + 414, + 415, + 416, + 417, + 418, + 419, + 420, + 421, + 422, + 423, + 424, + 425, + 426, + 427, + 428, + 429, + 430, + 431, + 432, + 433, + 434, + 435, + 436, + 437, + 438, + 439, + 440, + 441, + 442, + 443, + 444, + 445, + 446, + 447, + 448, + 449, + 450, + 451, + 452, + 453, + 454, + 455, + 456, + 457, + 458, + 459, + 460, + 461, + 462, + 463, + 464, + 465, + 466, + 467, + 468, + 469, + 470, + 471, + 472, + 473, + 474, + 475, + 476, + 477, + 478, + 479, + 480, + 481, + 482, + 483, + 484, + 485, + 486, + 487, + 488, + 489, + 490, + 491, + 492, + 493, + 494, + 495, + 496, + 497, + 498, + 499, + 500, + 501, + 502, + 503, + 504, + 505, + 506, + 507, + 508, + 509, + 510, + 511, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520, + 521, + 522, + 523, + 524, + 525, + 526, + 527, + 528, + 529, + 530, + 531, + 532, + 533, + 534, + 535, + 536, + 537, + 538, + 539, + 540, + 541, + 542, + 543, + 544, + 545, + 546, + 547, + 548, + 549, + 550, + 551, + 552, + 553, + 554, + 555, + 556, + 557, + 558, + 559, + 560, + 561, + 562, + 563, + 564, + 565, + 566, + 567, + 568, + 569, + 570, + 571, + 572, + 573, + 574, + 575, + 576, + 577, + 578, + 579, + 580, + 581, + 582, + 583, + 584, + 585, + 586, + 587, + 588, + 589, + 590, + 591, + 592, + 593, + 594, + 595, + 596, + 597, + 598, + 599, + 600, + 601, + 602, + 603, + 604, + 605, + 606, + 607, + 608, + 609, + 610, + 611, + 612, + 613, + 614, + 615, + 616, + 617, + 618, + 619, + 620, + 621, + 622, + 623, + 624, + 625, + 626, + 627, + 628, + 629, + 630, + 631, + 632, + 633, + 634, + 635, + 636, + 637, + 638, + 639, + 640, + 641, + 642, + 643, + 644, + 645, + 646, + 647, + 648, + 649, + 650, + 651, + 652, + 653, + 654, + 655, + 656, + 657, + 658, + 659, + 660, + 661, + 662, + 663, + 664, + 665, + 666, + 667, + 668, + 669, + 670, + 671, + 672, + 673, + 674, + 675, + 676, + 677, + 678, + 679, + 680, + 681, + 682, + 683, + 684, + 685, + 686, + 687, + 688, + 689, + 690, + 691, + 692, + 693, + 694, + 695, + 696, + 697, + 698, + 699, + 700, + 701, + 702, + 703, + 704, + 705, + 706, + 707, + 708, + 709, + 710, + 711, + 712, + 713, + 714, + 715, + 716, + 717, + 718, + 719, + 720, + 721, + 722, + 723, + 724, + 725, + 726, + 727, + 728, + 729, + 730, + 731, + 732, + 733, + 734, + 735, + 736, + 737, + 738, + 739, + 740, + 741, + 742, + 743, + 744, + 745, + 746, + 747, + 748, + 749, + 750, + 751, + 752, + 753, + 754, + 755, + 756, + 757, + 758, + 759, + 760, + 761, + 762, + 763, + 764, + 765, + 766, + 767, + 768, + 769, + 770, + 771, + 772, + 773, + 774, + 775, + 776, + 777, + 778, + 779, + 780, + 781, + 782, + 783, + 784, + 785, + 786, + 787, + 788, + 789, + 790, + 791, + 792, + 793, + 794, + 795, + 796, + 797, + 798, + 799, + 800, + 801, + 802, + 803, + 804, + 805, + 806, + 807, + 808, + 809, + 810, + 811, + 812, + 813, + 814, + 815, + 816, + 817, + 818, + 819, + 820, + 821, + 822, + 823, + 824, + 825, + 826, + 827, + 828, + 829, + 830, + 831, + 832, + 833, + 834, + 835, + 836, + 837, + 838, + 839, + 840, + 841, + 842, + 843, + 844, + 845, + 846, + 847, + 848, + 849, + 850, + 851, + 852, + 853, + 854, + 855, + 856, + 857, + 858, + 859, + 860, + 861, + 862, + 863, + 864, + 865, + 866, + 867, + 868, + 869, + 870, + 871, + 872, + 873, + 874, + 875, + 876, + 877, + 878, + 879, + 880, + 881, + 882, + 883, + 884, + 885, + 886, + 887, + 888, + 889, + 890, + 891, + 892, + 893, + 894, + 895, + 896, + 897, + 898, + 899, + 900, + 901, + 902, + 903, + 904, + 905, + 906, + 907, + 908, + 909, + 910, + 911, + 912, + 913, + 914, + 915, + 916, + 917, + 918, + 919, + 920, + 921, + 922, + 923, + 924, + 925, + 926, + 927, + 928, + 929, + 930, + 931, + 932, + 933, + 934, + 935, + 936, + 937, + 938, + 939, + 940, + 941, + 942, + 943, + 944, + 945, + 946, + 947, + 948, + 949, + 950, + 951, + 952, + 953, + 954, + 955, + 956, + 957, + 958, + 959, + 960, + 961, + 962, + 963, + 964, + 965, + 966, + 967, + 968, + 969, + 970, + 971, + 972, + 973, + 974, + 975, + 976, + 977, + 978; + 79, + 68, + 93, + 94, + 127, + 138, + 139, + 142, + 141, + 140, + 144, + 143, + 145, + 146, + 148, + 147, + 149, + 150, + 150, + 153, + 53, + 154, + 163, + 52, + 151, + 49, + 48, + 52, + 55, + 95, + 79, + 78, + 80, + 81, + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 193, + 271, + 282, + 283, + 286, + 285, + 288, + 284, + 287, + 289, + 290, + 292, + 291, + 293, + 294, + 294, + 209, + 296, + 295, + 303, + 210, + 151, + 164, + 205, + 206, + 210, + 211, + 246, + 231, + 232, + 233, + 174, + 184, + 320, + 321, + 322, + 323, + 324, + 325, + 326, + 327, + 336, + 339, + 340, + 341, + 342, + 345, + 346, + 347, + 340, + 350, + 351, + 361, + 367, + 375, + 374, + 386, + 392, + 399, + 402, + 406, + 407, + 404, + 408, + 420, + 425, + 426, + 426, + 423, + 417, + 404, + 440, + 439, + 444, + 443, + 445, + 454, + 460, + 429, + 428, + 459, + 459, + 430, + 431, + 433, + 453, + 458, + 464, + 466, + 467, + 472, + 469, + 471, + 470, + 483, + 487, + 480, + 499, + 500, + 502, + 503, + 476, + 477, + 481, + 482, + 504, + 506, + 508, + 507, + 505, + 510, + 509, + 511, + 512, + 513, + 514, + 521, + 522, + 520, + 528, + 522, + 527, + 525, + 523, + 530, + 532, + 519, + 524, + 516, + 515, + 538, + 518, + 529, + 536, + 542, + 543, + 558, + 566, + 402, + 401, + 407, + 410, + 413, + 415, + 590, + 588, + 591, + 592, + 593, + 431, + 589, + 598, + 544, + 543, + 546, + 548, + 546, + 607, + 550, + 552, + 554, + 556, + 556, + 612, + 615, + 620, + 613, + 614, + 615, + 613, + 621, + 616, + 617, + 616, + 624, + 618, + 619, + 618, + 626, + 620, + 620, + 628, + 538, + 539, + 540, + 535, + 532, + 531, + 537, + 526, + 528, + 518, + 540, + 527, + 517, + 523, + 515, + 538, + 540, + 532, + 406, + 399, + 406, + 633, + 639, + 637, + 638, + 639, + 640, + 644, + 638, + 641, + 643, + 642, + 650, + 649, + 656, + 662, + 469, + 470, + 478, + 470, + 473, + 479, + 675, + 676, + 674, + 673, + 683, + 691, + 689, + 703, + 704, + 678, + 681, + 710, + 708, + 711, + 709, + 712, + 714, + 715, + 713, + 717, + 716, + 718, + 724, + 725, + 726, + 726, + 732, + 729, + 730, + 727, + 734, + 723, + 735, + 728, + 719, + 742, + 720, + 721, + 740, + 733, + 746, + 745, + 761, + 437, + 440, + 444, + 447, + 450, + 788, + 790, + 791, + 792, + 789, + 745, + 748, + 750, + 750, + 752, + 798, + 754, + 756, + 758, + 760, + 760, + 803, + 806, + 811, + 805, + 804, + 804, + 806, + 812, + 807, + 807, + 808, + 815, + 809, + 809, + 810, + 817, + 811, + 811, + 819, + 742, + 743, + 744, + 739, + 735, + 736, + 741, + 732, + 731, + 744, + 721, + 730, + 722, + 727, + 720, + 742, + 744, + 735, + 443, + 439, + 443, + 824, + 830, + 829, + 828, + 831, + 830, + 829, + 835, + 832, + 834, + 833, + 841, + 840, + 847, + 853, + 675, + 674, + 674, + 682, + 677, + 684, + 883, + 860, + 859, + 889, + 874, + 873, + 891, + 876, + 875, + 892, + 890, + 877, + 878, + 893, + 895, + 879, + 881, + 896, + 898, + 897, + 905, + 908, + 911, + 914, + 917, + 918, + 917, + 920, + 935, + 936, + 951, + 952, + 902, + 904, + 907, + 910, + 913, + 916, + 919, + 922, + 919, + 961, + 975, + 976, + 963, + 956, + 955, + 964, + 965, + 924, + 923, + 966, + 967, + 957, + 927, + 968, + 969, + 958, + 929, + 970, + 971, + 959, + 931, + 972, + 973, + 960, + 933, + 974, + 975, + 961, + 935, + 976, + 977, + 962, + 937, + 978, + 939, + 926, + 925, + 940, + 941, + 901, + 900, + 942, + 943, + 928, + 906, + 944, + 945, + 930, + 909, + 946, + 947, + 932, + 912, + 948, + 949, + 934, + 915, + 950, + 951, + 936, + 918, + 952, + 953, + 938, + 921, + 954; + } + + MeshMaterialList + { + 2; + 1896; + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0; + + Material Material0 + { + 0.800000;0.800000;0.800000;1.000000;; + 0.000000; + 0.000000;0.000000;0.000000;; + 0.364706;0.364706;0.364706;; + + TextureFileName + { + "axe.jpg"; + } + } + + Material Material1 + { + 0.800000;0.800000;0.800000;1.000000;; + 0.000000; + 0.000000;0.000000;0.000000;; + 0.305882;0.305882;0.305882;; + + TextureFileName + { + "dwarf.jpg"; + } + } + + } + + XSkinMeshHeader + { + 1; + 3; + 40; + } + + SkinWeights + { + "middle"; + 19; + 565, + 566, + 567, + 568, + 569, + 570, + 571, + 595, + 599, + 600, + 603, + 604, + 769, + 770, + 771, + 772, + 773, + 795, + 1159; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -0.184641,-30.206568,0.000000,1.000000;; + } + + SkinWeights + { + "lhip"; + 18; + 746, + 747, + 749, + 751, + 753, + 755, + 757, + 759, + 761, + 762, + 763, + 764, + 765, + 766, + 767, + 768, + 1286, + 1288; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 5.006365,-26.736708,0.000000,1.000000;; + } + + SkinWeights + { + "lknee"; + 85; + 735, + 736, + 739, + 740, + 741, + 742, + 743, + 744, + 745, + 748, + 750, + 752, + 754, + 756, + 758, + 760, + 796, + 797, + 798, + 799, + 800, + 801, + 802, + 803, + 804, + 805, + 806, + 807, + 808, + 809, + 810, + 811, + 812, + 813, + 814, + 815, + 816, + 817, + 818, + 819, + 1278, + 1281, + 1284, + 1287, + 1299, + 1300, + 1301, + 1302, + 1303, + 1304, + 1305, + 1306, + 1307, + 1308, + 1309, + 1310, + 1311, + 1312, + 1313, + 1314, + 1315, + 1316, + 1317, + 1318, + 1319, + 1320, + 1321, + 1322, + 1323, + 1324, + 1325, + 1326, + 1327, + 1328, + 1329, + 1330, + 1331, + 1332, + 1333, + 1334, + 1335, + 1338, + 1344, + 1345, + 1346; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 6.909735,-17.919210,0.000000,1.000000;; + } + + SkinWeights + { + "lankle"; + 30; + 708, + 709, + 710, + 711, + 712, + 717, + 718, + 719, + 720, + 721, + 722, + 723, + 728, + 729, + 1257, + 1258, + 1259, + 1260, + 1261, + 1265, + 1267, + 1273, + 1277, + 1279, + 1280, + 1282, + 1283, + 1339, + 1341, + 1343; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 8.467036,-5.045920,-3.507543,1.000000;; + } + + SkinWeights + { + "ltoe"; + 32; + 713, + 714, + 715, + 716, + 724, + 725, + 726, + 727, + 730, + 731, + 732, + 733, + 734, + 737, + 738, + 1262, + 1263, + 1264, + 1266, + 1268, + 1269, + 1270, + 1271, + 1272, + 1274, + 1275, + 1276, + 1285, + 1336, + 1337, + 1340, + 1342; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 8.550578,-2.208009,1.760649,1.000000;; + } + + SkinWeights + { + "rhip"; + 37; + 541, + 542, + 543, + 544, + 545, + 546, + 547, + 548, + 549, + 550, + 551, + 552, + 553, + 554, + 555, + 556, + 557, + 558, + 559, + 560, + 561, + 562, + 563, + 564, + 1156, + 1157, + 1158, + 1174, + 1175, + 1176, + 1177, + 1178, + 1180, + 1181, + 1182, + 1183, + 1184; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -6.067782,-27.255383,0.000000,1.000000;; + } + + SkinWeights + { + "rknee"; + 66; + 531, + 532, + 535, + 536, + 537, + 538, + 539, + 540, + 605, + 606, + 607, + 608, + 609, + 610, + 611, + 612, + 613, + 614, + 615, + 616, + 617, + 618, + 619, + 620, + 621, + 622, + 623, + 624, + 625, + 626, + 627, + 628, + 1147, + 1152, + 1155, + 1179, + 1185, + 1186, + 1187, + 1188, + 1189, + 1190, + 1191, + 1192, + 1193, + 1194, + 1195, + 1196, + 1197, + 1198, + 1199, + 1200, + 1201, + 1202, + 1203, + 1204, + 1205, + 1206, + 1207, + 1208, + 1209, + 1210, + 1214, + 1219, + 1220, + 1221; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -7.625084,-17.573425,0.000000,1.000000;; + } + + SkinWeights + { + "rankle"; + 30; + 504, + 505, + 506, + 507, + 508, + 512, + 514, + 515, + 516, + 517, + 518, + 519, + 524, + 525, + 1127, + 1128, + 1129, + 1130, + 1131, + 1135, + 1137, + 1144, + 1148, + 1149, + 1150, + 1151, + 1153, + 1213, + 1216, + 1218; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -8.663285,-4.527243,-3.507543,1.000000;; + } + + SkinWeights + { + "rtoe"; + 32; + 509, + 510, + 511, + 513, + 520, + 521, + 522, + 523, + 526, + 527, + 528, + 529, + 530, + 533, + 534, + 1132, + 1133, + 1134, + 1136, + 1138, + 1139, + 1140, + 1141, + 1142, + 1143, + 1145, + 1146, + 1154, + 1211, + 1212, + 1215, + 1217; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -8.824361,-2.258848,1.547814,1.000000;; + } + + SkinWeights + { + "spine2"; + 82; + 401, + 402, + 407, + 410, + 413, + 415, + 431, + 437, + 440, + 444, + 447, + 450, + 576, + 577, + 578, + 579, + 580, + 581, + 582, + 583, + 584, + 585, + 586, + 587, + 588, + 589, + 590, + 591, + 592, + 593, + 594, + 596, + 597, + 598, + 601, + 602, + 778, + 779, + 780, + 781, + 782, + 783, + 784, + 785, + 786, + 787, + 788, + 789, + 790, + 791, + 792, + 793, + 794, + 1081, + 1083, + 1093, + 1095, + 1105, + 1160, + 1161, + 1162, + 1163, + 1164, + 1165, + 1166, + 1167, + 1168, + 1169, + 1170, + 1171, + 1172, + 1173, + 1289, + 1290, + 1291, + 1292, + 1293, + 1294, + 1295, + 1296, + 1297, + 1298; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -0.176384,-34.278362,0.000000,1.000000;; + } + + SkinWeights + { + "Joint76"; + 23; + 399, + 400, + 406, + 409, + 412, + 416, + 430, + 438, + 439, + 443, + 446, + 449, + 1080, + 1082, + 1094, + 1096, + 1104, + 1222, + 1223, + 1224, + 1347, + 1348, + 1349; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -0.135189,-45.764740,0.000000,1.000000;; + } + + SkinWeights + { + "spine1"; + 58; + 403, + 404, + 405, + 408, + 411, + 414, + 417, + 418, + 419, + 420, + 421, + 422, + 423, + 424, + 425, + 426, + 427, + 428, + 429, + 432, + 433, + 434, + 441, + 442, + 445, + 448, + 451, + 452, + 453, + 454, + 455, + 456, + 457, + 458, + 459, + 460, + 461, + 462, + 463, + 1084, + 1085, + 1086, + 1087, + 1088, + 1089, + 1090, + 1091, + 1092, + 1097, + 1098, + 1099, + 1100, + 1101, + 1102, + 1103, + 1106, + 1107, + 1108; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -0.077645,-48.894562,0.000000,1.000000;; + } + + SkinWeights + { + "head"; + 372; + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 127, + 136, + 137, + 151, + 152, + 153, + 154, + 155, + 156, + 157, + 158, + 159, + 160, + 161, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 171, + 172, + 173, + 174, + 175, + 176, + 177, + 178, + 179, + 180, + 181, + 182, + 183, + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 209, + 210, + 211, + 212, + 213, + 214, + 215, + 216, + 217, + 218, + 219, + 220, + 221, + 222, + 223, + 224, + 225, + 226, + 227, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 235, + 236, + 237, + 238, + 239, + 240, + 241, + 242, + 243, + 244, + 245, + 246, + 247, + 248, + 249, + 250, + 251, + 252, + 253, + 254, + 255, + 256, + 257, + 258, + 259, + 260, + 261, + 262, + 263, + 264, + 265, + 266, + 271, + 280, + 281, + 295, + 296, + 297, + 298, + 299, + 300, + 301, + 302, + 303, + 304, + 305, + 306, + 307, + 308, + 309, + 310, + 311, + 312, + 313, + 314, + 315, + 316, + 317, + 318, + 319, + 320, + 321, + 322, + 323, + 324, + 325, + 326, + 327, + 328, + 329, + 330, + 331, + 332, + 333, + 334, + 335, + 336, + 337, + 338, + 339, + 340, + 341, + 342, + 343, + 344, + 345, + 346, + 347, + 348, + 349, + 350, + 351, + 352, + 353, + 354, + 355, + 356, + 357, + 358, + 359, + 360, + 361, + 362, + 363, + 364, + 365, + 366, + 367, + 368, + 369, + 370, + 371, + 372, + 373, + 374, + 375, + 376, + 377, + 378, + 379, + 380, + 381, + 382, + 383, + 384, + 385, + 386, + 387, + 388, + 389, + 390, + 391, + 392, + 393, + 394, + 395, + 396, + 397, + 398, + 979, + 980, + 981, + 982, + 983, + 998, + 999, + 1000, + 1001, + 1002, + 1003, + 1004, + 1005, + 1006, + 1007, + 1008, + 1009, + 1010, + 1011, + 1012, + 1013, + 1014, + 1015, + 1016, + 1017, + 1018, + 1019, + 1020, + 1021, + 1022, + 1023, + 1038, + 1039, + 1040, + 1041, + 1042, + 1043, + 1044, + 1045, + 1046, + 1047, + 1048, + 1049, + 1050, + 1051, + 1052, + 1053, + 1054, + 1055, + 1056, + 1057, + 1058, + 1059, + 1060, + 1061, + 1062, + 1063, + 1064, + 1065, + 1066, + 1067, + 1068, + 1069, + 1070, + 1071, + 1072, + 1073, + 1074, + 1075, + 1076, + 1077, + 1078, + 1079; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -0.077645,-53.077965,0.000000,1.000000;; + } + + SkinWeights + { + "Joint36"; + 9; + 121, + 122, + 123, + 124, + 125, + 126, + 128, + 129, + 132; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -2.428693,-50.108727,5.128667,1.000000;; + } + + SkinWeights + { + "Joint39"; + 19; + 130, + 131, + 133, + 134, + 135, + 138, + 139, + 140, + 141, + 142, + 143, + 144, + 984, + 985, + 986, + 987, + 988, + 989, + 990; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -4.949857,-46.006042,7.908250,1.000000;; + } + + SkinWeights + { + "Joint40"; + 10; + 145, + 146, + 147, + 148, + 149, + 991, + 992, + 993, + 994, + 995; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -6.493002,-42.284798,8.792897,1.000000;; + } + + SkinWeights + { + "Joint41"; + 3; + 150, + 996, + 997; + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -7.350305,-39.127472,9.733334,1.000000;; + } + + SkinWeights + { + "Joint37"; + 6; + 267, + 268, + 269, + 270, + 272, + 277; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 2.766480,-49.947918,5.128667,1.000000;; + } + + SkinWeights + { + "Joint38"; + 20; + 273, + 274, + 275, + 276, + 278, + 279, + 282, + 283, + 284, + 285, + 286, + 287, + 288, + 1024, + 1025, + 1026, + 1027, + 1028, + 1029, + 1030; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 5.080586,-45.749058,7.908250,1.000000;; + } + + SkinWeights + { + "Joint42"; + 10; + 289, + 290, + 291, + 292, + 293, + 1031, + 1032, + 1033, + 1034, + 1035; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 6.280811,-42.539360,8.793637,1.000000;; + } + + SkinWeights + { + "Joint43"; + 3; + 294, + 1036, + 1037; + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 7.566765,-38.843330,9.733334,1.000000;; + } + + SkinWeights + { + "pad2"; + 24; + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 0.986286,-0.159424,0.042717,0.000000, + 0.165048,0.952679,-0.255270,0.000000, + 0.000000,0.258819,0.965926,0.000000, + -2.513408,-50.807816,13.613914,1.000000;; + } + + SkinWeights + { + "pad1"; + 24; + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -5.311174,-52.424309,0.000000,1.000000;; + } + + SkinWeights + { + "lsholda"; + 13; + 774, + 775, + 776, + 777, + 820, + 821, + 822, + 823, + 824, + 825, + 826, + 827, + 1350; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 10.633429,-47.162376,-3.529744,1.000000;; + } + + SkinWeights + { + "lelbo"; + 62; + 674, + 675, + 677, + 682, + 683, + 684, + 691, + 828, + 829, + 830, + 831, + 832, + 833, + 834, + 835, + 836, + 837, + 838, + 839, + 840, + 841, + 842, + 843, + 844, + 845, + 846, + 847, + 848, + 849, + 850, + 851, + 852, + 853, + 854, + 855, + 856, + 857, + 858, + 1246, + 1248, + 1250, + 1251, + 1351, + 1352, + 1353, + 1354, + 1355, + 1356, + 1357, + 1358, + 1359, + 1360, + 1361, + 1362, + 1363, + 1364, + 1365, + 1366, + 1367, + 1368, + 1369, + 1370; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 17.175339,-42.063858,-4.235693,1.000000;; + } + + SkinWeights + { + "lwrist"; + 2; + 669, + 670; + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 25.025633,-35.658024,-4.235693,1.000000;; + } + + SkinWeights + { + "Joint17"; + 8; + 668, + 671, + 672, + 673, + 676, + 692, + 1247, + 1249; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 28.689102,-31.997549,-4.235693,1.000000;; + } + + SkinWeights + { + "Joint18"; + 8; + 702, + 703, + 704, + 705, + 706, + 707, + 1253, + 1254; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 29.735809,-29.905848,-4.235693,1.000000;; + } + + SkinWeights + { + "Joint19"; + 8; + 678, + 679, + 680, + 681, + 685, + 686, + 1255, + 1256; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 29.866648,-26.768299,-4.235693,1.000000;; + } + + SkinWeights + { + "Joint20"; + 10; + 687, + 688, + 689, + 690, + 693, + 694, + 699, + 700, + 701, + 1252; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 25.287310,-31.343891,-0.753762,1.000000;; + } + + SkinWeights + { + "Joint21"; + 4; + 695, + 696, + 697, + 698; + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + 26.334013,-28.859997,-0.753762,1.000000;; + } + + SkinWeights + { + "rsholda"; + 15; + 435, + 436, + 572, + 573, + 574, + 575, + 629, + 630, + 631, + 632, + 633, + 634, + 635, + 636, + 1225; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -10.064111,-47.456520,-3.529744,1.000000;; + } + + SkinWeights + { + "relbo"; + 62; + 469, + 470, + 473, + 478, + 479, + 480, + 487, + 637, + 638, + 639, + 640, + 641, + 642, + 643, + 644, + 645, + 646, + 647, + 648, + 649, + 650, + 651, + 652, + 653, + 654, + 655, + 656, + 657, + 658, + 659, + 660, + 661, + 662, + 663, + 664, + 665, + 666, + 667, + 1113, + 1115, + 1117, + 1118, + 1226, + 1227, + 1228, + 1229, + 1230, + 1231, + 1232, + 1233, + 1234, + 1235, + 1236, + 1237, + 1238, + 1239, + 1240, + 1241, + 1242, + 1243, + 1244, + 1245; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -16.867699,-42.096539,-4.235693,1.000000;; + } + + SkinWeights + { + "rwrist"; + 3; + 464, + 465, + 1109; + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -25.241344,-35.298512,-4.235693,1.000000;; + } + + SkinWeights + { + "Joint25"; + 10; + 466, + 467, + 468, + 471, + 472, + 488, + 1110, + 1111, + 1112, + 1114; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -28.904814,-32.160961,-4.235693,1.000000;; + } + + SkinWeights + { + "Joint26"; + 10; + 498, + 499, + 500, + 501, + 502, + 503, + 1119, + 1120, + 1121, + 1122; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -29.951521,-29.807800,-4.235693,1.000000;; + } + + SkinWeights + { + "Joint27"; + 10; + 474, + 475, + 476, + 477, + 481, + 482, + 1123, + 1124, + 1125, + 1126; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -29.689844,-26.931713,-4.235693,1.000000;; + } + + SkinWeights + { + "Joint28"; + 7; + 483, + 484, + 485, + 486, + 489, + 490, + 1116; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -24.456314,-31.115110,-2.201373,1.000000;; + } + + SkinWeights + { + "Joint29"; + 7; + 491, + 492, + 493, + 494, + 495, + 496, + 497; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -24.717991,-28.631216,-2.201373,1.000000;; + } + + SkinWeights + { + "weapon"; + 228; + 859, + 860, + 861, + 862, + 863, + 864, + 865, + 866, + 867, + 868, + 869, + 870, + 871, + 872, + 873, + 874, + 875, + 876, + 877, + 878, + 879, + 880, + 881, + 882, + 883, + 884, + 885, + 886, + 887, + 888, + 889, + 890, + 891, + 892, + 893, + 894, + 895, + 896, + 897, + 898, + 899, + 900, + 901, + 902, + 903, + 904, + 905, + 906, + 907, + 908, + 909, + 910, + 911, + 912, + 913, + 914, + 915, + 916, + 917, + 918, + 919, + 920, + 921, + 922, + 923, + 924, + 925, + 926, + 927, + 928, + 929, + 930, + 931, + 932, + 933, + 934, + 935, + 936, + 937, + 938, + 939, + 940, + 941, + 942, + 943, + 944, + 945, + 946, + 947, + 948, + 949, + 950, + 951, + 952, + 953, + 954, + 955, + 956, + 957, + 958, + 959, + 960, + 961, + 962, + 963, + 964, + 965, + 966, + 967, + 968, + 969, + 970, + 971, + 972, + 973, + 974, + 975, + 976, + 977, + 978, + 1371, + 1372, + 1373, + 1374, + 1375, + 1376, + 1377, + 1378, + 1379, + 1380, + 1381, + 1382, + 1383, + 1384, + 1385, + 1386, + 1387, + 1388, + 1389, + 1390, + 1391, + 1392, + 1393, + 1394, + 1395, + 1396, + 1397, + 1398, + 1399, + 1400, + 1401, + 1402, + 1403, + 1404, + 1405, + 1406, + 1407, + 1408, + 1409, + 1410, + 1411, + 1412, + 1413, + 1414, + 1415, + 1416, + 1417, + 1418, + 1419, + 1420, + 1421, + 1422, + 1423, + 1424, + 1425, + 1426, + 1427, + 1428, + 1429, + 1430, + 1431, + 1432, + 1433, + 1434, + 1435, + 1436, + 1437, + 1438, + 1439, + 1440, + 1441, + 1442, + 1443, + 1444, + 1445, + 1446, + 1447, + 1448, + 1449, + 1450, + 1451, + 1452, + 1453, + 1454, + 1455, + 1456, + 1457, + 1458, + 1459, + 1460, + 1461, + 1462, + 1463, + 1464, + 1465, + 1466, + 1467, + 1468, + 1469, + 1470, + 1471, + 1472, + 1473, + 1474, + 1475, + 1476, + 1477, + 1478; + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000, + 1.000000; + 1.000000,0.000000,0.000000,0.000000, + 0.000000,1.000000,0.000000,0.000000, + 0.000000,0.000000,1.000000,0.000000, + -26.942242,-30.461456,-4.235693,1.000000;; + } + } + } +} + +AnimationSet AnimationSet0 +{ + Animation baseAnimation + { + {base} + + AnimationKey + { + 2; + 23; + 0;3;0.011608,-0.015192,0.000000;;, + 1;3;0.011608,-0.015192,0.000000;;, + 2;3;0.011608,-0.015192,0.000000;;, + 3;3;0.011608,-0.015192,0.000000;;, + 4;3;0.011608,-0.015192,0.000000;;, + 5;3;0.011608,-0.015192,0.000000;;, + 12;3;0.011608,-0.015192,0.000000;;, + 14;3;0.011608,-0.015192,0.000000;;, + 15;3;0.011608,-0.015192,0.000000;;, + 16;3;0.011608,-0.015192,0.000000;;, + 17;3;0.011608,-0.015192,0.000000;;, + 18;3;0.011608,-0.015192,0.000000;;, + 19;3;0.011608,-0.015192,0.000000;;, + 20;3;0.011608,-0.015192,0.000000;;, + 27;3;0.011608,-0.015192,0.000000;;, + 33;3;0.011608,-0.015192,0.000000;;, + 34;3;0.011608,-0.015192,0.000000;;, + 35;3;0.011608,-0.015192,0.000000;;, + 41;3;0.011608,-0.015192,0.000000;;, + 43;3;0.011608,-0.015192,0.000000;;, + 50;3;0.011608,-0.015192,0.000000;;, + 53;3;0.011608,-0.015192,0.000000;;, + 55;3;0.011608,-0.015192,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation middleAnimation + { + {middle} + + AnimationKey + { + 2; + 25; + 0;3;0.173034,30.221760,0.000000;;, + 1;3;0.173034,30.221760,0.000000;;, + 2;3;0.173034,27.773420,0.372200;;, + 3;3;0.173034,24.919014,0.806130;;, + 4;3;0.173034,22.482626,1.176512;;, + 5;3;0.173034,22.482626,1.176512;;, + 12;3;0.173034,22.482626,1.176512;;, + 14;3;0.173034,22.482626,1.176512;;, + 15;3;0.173034,22.482626,1.176512;;, + 16;3;0.173034,24.272297,0.904444;;, + 17;3;0.173034,26.344128,0.589482;;, + 18;3;0.173034,28.455601,0.268494;;, + 19;3;0.173034,30.221760,0.000000;;, + 20;3;0.173034,30.221760,0.000000;;, + 24;3;0.173034,29.353209,0.000000;;, + 27;3;0.173034,29.520485,0.000000;;, + 33;3;0.173034,30.221760,0.000000;;, + 34;3;0.173034,30.221760,0.000000;;, + 35;3;0.173034,30.221760,0.000000;;, + 41;3;0.173034,28.753119,0.000000;;, + 43;3;0.173034,28.285614,0.000000;;, + 45;3;0.173034,28.050383,0.000000;;, + 50;3;0.173034,28.889324,0.000000;;, + 53;3;0.173034,29.697077,0.000000;;, + 55;3;0.173034,30.221760,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 25; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 24;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 45;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation lhipAnimation + { + {lhip} + + AnimationKey + { + 2; + 23; + 0;3;-5.191007,-3.469861,0.000000;;, + 1;3;-5.191007,-3.469861,0.000000;;, + 2;3;-5.191007,-3.469861,0.000000;;, + 3;3;-5.191007,-3.469861,0.000000;;, + 4;3;-5.191007,-3.469861,0.000000;;, + 5;3;-5.191007,-3.469861,0.000000;;, + 12;3;-5.191007,-3.469861,0.000000;;, + 14;3;-5.191007,-3.469861,0.000000;;, + 15;3;-5.191007,-3.469861,0.000000;;, + 16;3;-5.191007,-3.469861,0.000000;;, + 17;3;-5.191007,-3.469861,0.000000;;, + 18;3;-5.191007,-3.469861,0.000000;;, + 19;3;-5.191007,-3.469861,0.000000;;, + 20;3;-5.191007,-3.469861,0.000000;;, + 27;3;-5.191007,-3.469861,0.000000;;, + 33;3;-5.191007,-3.469861,0.000000;;, + 34;3;-5.191007,-3.469861,0.000000;;, + 35;3;-5.191007,-3.469861,0.000000;;, + 41;3;-5.191007,-3.469861,0.000000;;, + 43;3;-5.191007,-3.469861,0.000000;;, + 50;3;-5.191007,-3.469861,0.000000;;, + 53;3;-5.191007,-3.469861,0.000000;;, + 55;3;-5.191007,-3.469861,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;0.933591,-0.357025,0.029033,0.009857;;, + 3;4;0.833984,-0.551409,0.020009,0.004259;;, + 4;4;0.751840,-0.659346,0.000000,0.000000;;, + 5;4;0.751840,-0.659346,0.000000,0.000000;;, + 12;4;0.751840,-0.659346,0.000000,0.000000;;, + 14;4;0.751840,-0.659346,0.000000,0.000000;;, + 15;4;0.751840,-0.659346,0.000000,0.000000;;, + 16;4;0.815325,-0.578790,0.015233,0.003854;;, + 17;4;0.880134,-0.473717,0.030180,0.006729;;, + 18;4;0.961855,-0.272346,0.024861,0.006633;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation lkneeAnimation + { + {lknee} + + AnimationKey + { + 2; + 25; + 0;3;-1.903369,-8.817497,0.000000;;, + 1;3;-1.903369,-8.817497,0.000000;;, + 2;3;-1.903369,-8.817497,0.000000;;, + 3;3;-1.903369,-8.817497,0.000000;;, + 4;3;-1.903369,-8.817497,0.000000;;, + 5;3;-1.903369,-8.817497,0.000000;;, + 12;3;-1.903369,-8.817497,0.000000;;, + 14;3;-1.903369,-8.817497,0.000000;;, + 15;3;-1.903369,-8.817497,0.000000;;, + 16;3;-1.903369,-8.817497,0.000000;;, + 17;3;-1.903369,-8.817497,0.000000;;, + 18;3;-1.903369,-8.817497,0.000000;;, + 19;3;-1.903369,-8.817497,0.000000;;, + 20;3;-1.903369,-8.817497,0.000000;;, + 24;3;-1.903369,-8.527980,0.000000;;, + 27;3;-1.903369,-8.583739,0.000000;;, + 33;3;-1.903369,-8.817497,0.000000;;, + 34;3;-1.903369,-8.817497,0.000000;;, + 35;3;-1.903369,-8.817497,0.000000;;, + 41;3;-1.903369,-8.034223,0.000000;;, + 43;3;-1.903369,-7.784886,0.000000;;, + 45;3;-1.903369,-7.659429,0.000000;;, + 50;3;-1.903369,-8.106865,0.000000;;, + 53;3;-1.903369,-8.537666,0.000000;;, + 55;3;-1.903369,-8.817497,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 25; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;0.936175,0.350946,-0.020210,-0.002106;;, + 3;4;0.832879,0.553271,-0.014218,0.001102;;, + 4;4;0.754710,0.656059,0.000000,0.000000;;, + 5;4;0.754710,0.656059,0.000000,0.000000;;, + 12;4;0.754709,0.656059,0.000000,0.000000;;, + 14;4;0.754710,0.656059,0.000000,0.000000;;, + 15;4;0.754710,0.656059,0.000000,0.000000;;, + 16;4;0.817547,0.575786,-0.009196,0.001689;;, + 17;4;0.867357,0.497283,-0.018216,0.008324;;, + 18;4;0.954530,0.297619,-0.015169,0.008102;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 24;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 45;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation lankleAnimation + { + {lankle} + + AnimationKey + { + 2; + 25; + 0;3;-1.557302,-12.873290,3.507543;;, + 1;3;-1.557302,-12.873290,3.507543;;, + 2;3;-1.557302,-12.873290,3.507543;;, + 3;3;-1.557302,-12.873290,3.507543;;, + 4;3;-1.557302,-12.873290,3.507543;;, + 5;3;-1.557302,-12.873290,3.507543;;, + 12;3;-1.557302,-12.873290,3.507543;;, + 14;3;-1.557302,-12.873290,3.507543;;, + 15;3;-1.557302,-12.873290,3.507543;;, + 16;3;-1.557302,-12.873290,3.507543;;, + 17;3;-1.557302,-12.873290,3.507543;;, + 18;3;-1.557302,-12.873290,3.507543;;, + 19;3;-1.557302,-12.873290,3.507543;;, + 20;3;-1.557302,-12.873290,3.507543;;, + 24;3;-1.557302,-12.294256,3.507543;;, + 27;3;-1.557302,-12.405774,3.507543;;, + 33;3;-1.557302,-12.873290,3.507543;;, + 34;3;-1.557302,-12.873290,3.507543;;, + 35;3;-1.557302,-12.873290,3.507543;;, + 41;3;-1.557302,-12.187924,3.507543;;, + 43;3;-1.557302,-11.969755,3.507543;;, + 45;3;-1.557302,-11.859981,3.507543;;, + 50;3;-1.557302,-12.251487,3.507543;;, + 53;3;-1.557302,-12.628438,3.507543;;, + 55;3;-1.557302,-12.873290,3.507543;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 25; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;0.999476,-0.032322,0.001562,-0.000284;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 24;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 45;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation ltoeAnimation + { + {ltoe} + + AnimationKey + { + 2; + 23; + 0;3;-0.083542,-2.837912,-5.268192;;, + 1;3;-0.083542,-2.837912,-5.268192;;, + 2;3;-0.083542,-2.837912,-5.268192;;, + 3;3;-0.083542,-2.837912,-5.268192;;, + 4;3;-0.083542,-2.837912,-5.268192;;, + 5;3;-0.083542,-2.837912,-5.268192;;, + 12;3;-0.083542,-2.837912,-5.268192;;, + 14;3;-0.083542,-2.837912,-5.268192;;, + 15;3;-0.083542,-2.837912,-5.268192;;, + 16;3;-0.083542,-2.837912,-5.268192;;, + 17;3;-0.083542,-2.837912,-5.268192;;, + 18;3;-0.083542,-2.837912,-5.268192;;, + 19;3;-0.083542,-2.837912,-5.268192;;, + 20;3;-0.083542,-2.837912,-5.268192;;, + 27;3;-0.083542,-2.837912,-5.268192;;, + 33;3;-0.083542,-2.837912,-5.268192;;, + 34;3;-0.083542,-2.837912,-5.268192;;, + 35;3;-0.083542,-2.837912,-5.268192;;, + 41;3;-0.083542,-2.837912,-5.268192;;, + 43;3;-0.083542,-2.837912,-5.268192;;, + 50;3;-0.083542,-2.837912,-5.268192;;, + 53;3;-0.083542,-2.837912,-5.268192;;, + 55;3;-0.083542,-2.837912,-5.268192;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation rhipAnimation + { + {rhip} + + AnimationKey + { + 2; + 23; + 0;3;5.883141,-2.951185,0.000000;;, + 1;3;5.883141,-2.951185,0.000000;;, + 2;3;5.883141,-2.951185,0.000000;;, + 3;3;5.883141,-2.951185,0.000000;;, + 4;3;5.883141,-2.951185,0.000000;;, + 5;3;5.883141,-2.951185,0.000000;;, + 12;3;5.883141,-2.951185,0.000000;;, + 14;3;5.883141,-2.951185,0.000000;;, + 15;3;5.883141,-2.951185,0.000000;;, + 16;3;5.883141,-2.951185,0.000000;;, + 17;3;5.883141,-2.951185,0.000000;;, + 18;3;5.883141,-2.951185,0.000000;;, + 19;3;5.883141,-2.951185,0.000000;;, + 20;3;5.883141,-2.951185,0.000000;;, + 27;3;5.883141,-2.951185,0.000000;;, + 33;3;5.883141,-2.951185,0.000000;;, + 34;3;5.883141,-2.951185,0.000000;;, + 35;3;5.883141,-2.951185,0.000000;;, + 41;3;5.883141,-2.951185,0.000000;;, + 43;3;5.883141,-2.951185,0.000000;;, + 50;3;5.883141,-2.951185,0.000000;;, + 53;3;5.883141,-2.951185,0.000000;;, + 55;3;5.883141,-2.951185,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;0.997921,0.064448,0.000411,-0.000559;;, + 3;4;0.990580,0.136931,0.000703,-0.000957;;, + 4;4;0.982450,0.186524,0.000000,0.000000;;, + 5;4;0.982450,0.186524,0.000000,0.000000;;, + 12;4;0.982450,0.186524,0.000000,0.000000;;, + 14;4;0.982450,0.186524,0.000000,0.000000;;, + 15;4;0.982450,0.186524,0.000000,0.000000;;, + 16;4;0.988892,0.148634,-0.000027,-0.001179;;, + 17;4;0.995206,0.097793,-0.000021,-0.000940;;, + 18;4;0.999001,0.044690,-0.000010,-0.000451;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation rkneeAnimation + { + {rknee} + + AnimationKey + { + 2; + 25; + 0;3;1.557302,-9.681957,0.000000;;, + 1;3;1.557302,-9.681957,0.000000;;, + 2;3;1.557302,-9.681957,0.000000;;, + 3;3;1.557302,-9.681957,0.000000;;, + 4;3;1.557302,-9.681957,0.000000;;, + 5;3;1.557302,-9.681957,0.000000;;, + 12;3;1.557302,-9.681957,0.000000;;, + 14;3;1.557302,-9.681957,0.000000;;, + 15;3;1.557302,-9.681957,0.000000;;, + 16;3;1.557302,-9.681957,0.000000;;, + 17;3;1.557302,-9.681957,0.000000;;, + 18;3;1.557302,-9.681957,0.000000;;, + 19;3;1.557302,-9.681957,0.000000;;, + 20;3;1.557302,-9.681957,0.000000;;, + 24;3;1.557302,-9.392440,0.000000;;, + 27;3;1.557302,-9.448199,0.000000;;, + 33;3;1.557302,-9.681957,0.000000;;, + 34;3;1.557302,-9.681957,0.000000;;, + 35;3;1.557302,-9.681957,0.000000;;, + 41;3;1.557302,-8.898683,0.000000;;, + 43;3;1.557302,-8.649346,0.000000;;, + 45;3;1.557302,-8.523890,0.000000;;, + 50;3;1.557302,-8.971325,0.000000;;, + 53;3;1.557302,-9.402126,0.000000;;, + 55;3;1.557302,-9.681957,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 25; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;0.963221,0.268544,0.008625,-0.003828;;, + 3;4;0.881291,0.472453,0.010177,-0.003199;;, + 4;4;0.859406,0.511293,0.000000,0.000000;;, + 5;4;0.859406,0.511293,0.000000,0.000000;;, + 12;4;0.859406,0.511293,0.000000,0.000000;;, + 14;4;0.859406,0.511293,0.000000,0.000000;;, + 15;4;0.859406,0.511293,0.000000,0.000000;;, + 16;4;0.882421,0.470414,0.005475,-0.003796;;, + 17;4;0.936363,0.350938,0.006628,-0.004836;;, + 18;4;0.982689,0.185165,0.005005,-0.003385;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 24;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 45;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation rankleAnimation + { + {rankle} + + AnimationKey + { + 2; + 25; + 0;3;1.038201,-13.046183,3.507543;;, + 1;3;1.038201,-13.046183,3.507543;;, + 2;3;1.038201,-13.046183,3.507543;;, + 3;3;1.038201,-13.046183,3.507543;;, + 4;3;1.038201,-13.046183,3.507543;;, + 5;3;1.038201,-13.046183,3.507543;;, + 12;3;1.038201,-13.046183,3.507543;;, + 14;3;1.038201,-13.046183,3.507543;;, + 15;3;1.038201,-13.046183,3.507543;;, + 16;3;1.038201,-13.046183,3.507543;;, + 17;3;1.038201,-13.046183,3.507543;;, + 18;3;1.038201,-13.046183,3.507543;;, + 19;3;1.038201,-13.046183,3.507543;;, + 20;3;1.038201,-13.046183,3.507543;;, + 24;3;1.038201,-12.467149,3.507543;;, + 27;3;1.038201,-12.578667,3.507543;;, + 33;3;1.038201,-13.046183,3.507543;;, + 34;3;1.038201,-13.046183,3.507543;;, + 35;3;1.038201,-13.046183,3.507543;;, + 41;3;1.038201,-12.360817,3.507543;;, + 43;3;1.038201,-12.142648,3.507543;;, + 45;3;1.038201,-12.032873,3.507543;;, + 50;3;1.038201,-12.424379,3.507543;;, + 53;3;1.038201,-12.801331,3.507543;;, + 55;3;1.038201,-13.046183,3.507543;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 25; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;0.978731,-0.205059,-0.003273,-0.005028;;, + 3;4;0.979297,-0.202354,-0.000456,-0.005571;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;0.981401,-0.191782,-0.008166,-0.002302;;, + 17;4;0.967608,-0.252304,-0.007780,-0.004084;;, + 18;4;0.984134,-0.177321,-0.005444,-0.002966;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 24;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 45;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation rtoeAnimation + { + {rtoe} + + AnimationKey + { + 2; + 23; + 0;3;0.161076,-2.268395,-5.055357;;, + 1;3;0.161076,-2.268395,-5.055357;;, + 2;3;0.161076,-2.268395,-5.055357;;, + 3;3;0.161076,-2.268395,-5.055357;;, + 4;3;0.161076,-2.268395,-5.055357;;, + 5;3;0.161076,-2.268395,-5.055357;;, + 12;3;0.161076,-2.268395,-5.055357;;, + 14;3;0.161076,-2.268395,-5.055357;;, + 15;3;0.161076,-2.268395,-5.055357;;, + 16;3;0.161076,-2.268395,-5.055357;;, + 17;3;0.161076,-2.268395,-5.055357;;, + 18;3;0.161076,-2.268395,-5.055357;;, + 19;3;0.161076,-2.268395,-5.055357;;, + 20;3;0.161076,-2.268395,-5.055357;;, + 27;3;0.161076,-2.268395,-5.055357;;, + 33;3;0.161076,-2.268395,-5.055357;;, + 34;3;0.161076,-2.268395,-5.055357;;, + 35;3;0.161076,-2.268395,-5.055357;;, + 41;3;0.161076,-2.268395,-5.055357;;, + 43;3;0.161076,-2.268395,-5.055357;;, + 50;3;0.161076,-2.268395,-5.055357;;, + 53;3;0.161076,-2.268395,-5.055357;;, + 55;3;0.161076,-2.268395,-5.055357;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation spine2Animation + { + {spine2} + + AnimationKey + { + 2; + 23; + 0;3;-0.008257,4.071795,0.000000;;, + 1;3;-0.008257,4.071795,0.000000;;, + 2;3;-0.008257,4.071795,0.000000;;, + 3;3;-0.008257,4.071795,0.000000;;, + 4;3;-0.008257,4.071795,0.000000;;, + 5;3;-0.008257,4.071795,0.000000;;, + 12;3;-0.008257,4.071795,0.000000;;, + 14;3;-0.008257,4.071795,0.000000;;, + 15;3;-0.008257,4.071795,0.000000;;, + 16;3;-0.008257,4.071795,0.000000;;, + 17;3;-0.008257,4.071795,0.000000;;, + 18;3;-0.008257,4.071795,0.000000;;, + 19;3;-0.008257,4.071795,0.000000;;, + 20;3;-0.008257,4.071795,0.000000;;, + 27;3;-0.008257,4.071795,0.000000;;, + 33;3;-0.008257,4.071795,0.000000;;, + 34;3;-0.008257,4.071795,0.000000;;, + 35;3;-0.008257,4.071795,0.000000;;, + 41;3;-0.008257,4.071795,0.000000;;, + 43;3;-0.008257,4.071795,0.000000;;, + 50;3;-0.008257,4.071795,0.000000;;, + 53;3;-0.008257,4.071795,0.000000;;, + 55;3;-0.008257,4.071795,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;0.999391,0.000000,0.034899,0.000000;;, + 43;4;0.999406,0.000000,0.034456,0.000000;;, + 50;4;0.999888,0.000000,0.014985,0.000000;;, + 53;4;0.999982,0.000000,0.005995,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint75Animation + { + {Joint75} + + AnimationKey + { + 2; + 23; + 0;3;-0.007980,5.843795,0.000000;;, + 1;3;-0.007980,5.843795,0.000000;;, + 2;3;-0.007980,5.625298,-0.076575;;, + 3;3;-0.007980,5.370562,-0.165850;;, + 4;3;-0.007980,5.153131,-0.242051;;, + 5;3;-0.007980,5.153131,-0.242051;;, + 12;3;-0.007980,5.153131,-0.242051;;, + 14;3;-0.007980,5.153131,-0.242051;;, + 15;3;-0.007980,5.153131,-0.242051;;, + 16;3;-0.007980,5.312847,-0.186077;;, + 17;3;-0.007980,5.497743,-0.121278;;, + 18;3;-0.007980,5.686178,-0.055239;;, + 19;3;-0.007980,5.843795,0.000000;;, + 20;3;-0.007980,5.843795,0.000000;;, + 27;3;-0.007980,5.843795,0.000000;;, + 33;3;-0.007980,5.843795,0.000000;;, + 34;3;-0.007980,5.843795,0.000000;;, + 35;3;-0.007980,5.843795,0.000000;;, + 41;3;-0.007980,5.843795,0.000000;;, + 43;3;-0.007980,5.975956,-0.018574;;, + 50;3;-0.007980,6.482687,-0.089789;;, + 53;3;-0.007980,6.140066,-0.041637;;, + 55;3;-0.007980,5.843795,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;0.997564,0.069757,0.000000,0.000000;;, + 1;4;0.997564,0.069757,0.000000,0.000000;;, + 2;4;0.997564,0.069755,0.000000,0.000000;;, + 3;4;0.997564,0.069755,0.000000,0.000000;;, + 4;4;0.997564,0.069757,0.000000,0.000000;;, + 5;4;0.997564,0.069757,0.000000,0.000000;;, + 12;4;0.997564,0.069755,0.000000,0.000000;;, + 14;4;0.997564,0.069757,0.000000,0.000000;;, + 15;4;0.997564,0.069757,0.000000,0.000000;;, + 16;4;0.997564,0.069755,0.000000,0.000000;;, + 17;4;0.997564,0.069755,0.000000,0.000000;;, + 18;4;0.997564,0.069755,0.000000,0.000000;;, + 19;4;0.997564,0.069757,0.000000,0.000000;;, + 20;4;0.997564,0.069757,0.000000,0.000000;;, + 27;4;0.990866,0.134849,0.000000,0.000000;;, + 33;4;0.997564,0.069757,0.000000,0.000000;;, + 34;4;0.997564,0.069757,0.000000,0.000000;;, + 35;4;0.997564,0.069757,0.000000,0.000000;;, + 41;4;0.993768,0.069490,0.086944,-0.006080;;, + 43;4;0.995824,0.069634,0.058902,-0.004119;;, + 50;4;0.993213,0.069451,-0.093073,0.006508;;, + 53;4;0.996487,0.069680,-0.046335,0.003240;;, + 55;4;0.997564,0.069757,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint76Animation + { + {Joint76} + + AnimationKey + { + 2; + 23; + 0;3;-0.033215,5.642583,0.000000;;, + 1;3;-0.033215,5.642583,0.000000;;, + 2;3;-0.033215,5.390897,-0.199987;;, + 3;3;-0.033215,5.097469,-0.433143;;, + 4;3;-0.033215,4.847012,-0.632154;;, + 5;3;-0.033215,4.847012,-0.632154;;, + 12;3;-0.033215,4.847012,-0.632154;;, + 14;3;-0.033215,4.847012,-0.632154;;, + 15;3;-0.033215,4.847012,-0.632154;;, + 16;3;-0.033215,5.030987,-0.485969;;, + 17;3;-0.033215,5.243968,-0.316736;;, + 18;3;-0.033215,5.461024,-0.144265;;, + 19;3;-0.033215,5.642583,0.000000;;, + 20;3;-0.033215,5.642583,0.000000;;, + 27;3;-0.033215,5.642583,0.000000;;, + 33;3;-0.033215,5.642583,0.000000;;, + 34;3;-0.033215,5.642583,0.000000;;, + 35;3;-0.033215,5.642583,0.000000;;, + 41;3;-0.033215,5.642583,0.000000;;, + 43;3;-0.033215,5.642583,0.000000;;, + 50;3;-0.033215,5.642583,0.000000;;, + 53;3;-0.033215,5.642583,0.000000;;, + 55;3;-0.033215,5.642583,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;0.999391,0.034899,0.000000,0.000000;;, + 1;4;0.999391,0.034899,0.000000,0.000000;;, + 2;4;0.999391,0.034899,0.000000,0.000000;;, + 3;4;0.999391,0.034899,0.000000,0.000000;;, + 4;4;0.999391,0.034899,0.000000,0.000000;;, + 5;4;0.999391,0.034899,0.000000,0.000000;;, + 12;4;0.999381,0.034899,0.004361,-0.000152;;, + 14;4;0.999391,0.034899,0.000000,0.000000;;, + 15;4;0.999391,0.034899,0.000000,0.000000;;, + 16;4;0.999391,0.034899,0.000000,0.000000;;, + 17;4;0.999391,0.034899,0.000000,0.000000;;, + 18;4;0.999391,0.034899,0.000000,0.000000;;, + 19;4;0.999391,0.034899,0.000000,0.000000;;, + 20;4;0.999391,0.034899,0.000000,0.000000;;, + 27;4;0.999391,0.034899,0.000000,0.000000;;, + 33;4;0.999391,0.034899,0.000000,0.000000;;, + 34;4;0.999391,0.034899,0.000000,0.000000;;, + 35;4;0.999391,0.034899,0.000000,0.000000;;, + 41;4;0.996956,0.034814,0.069714,-0.002434;;, + 43;4;0.998051,0.034853,0.051723,-0.001806;;, + 50;4;0.997991,0.034850,-0.052875,0.001846;;, + 53;4;0.999025,0.034886,-0.027035,0.000944;;, + 55;4;0.999391,0.034899,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation spine1Animation + { + {spine1} + + AnimationKey + { + 2; + 23; + 0;3;-0.057544,3.129822,0.000000;;, + 1;3;-0.057544,3.129822,0.000000;;, + 2;3;-0.057544,3.129822,0.000000;;, + 3;3;-0.057544,3.129822,0.000000;;, + 4;3;-0.057544,3.129822,0.000000;;, + 5;3;-0.057544,3.129822,0.000000;;, + 12;3;-0.057544,3.129822,0.000000;;, + 14;3;-0.057544,3.129822,0.000000;;, + 15;3;-0.057544,3.129822,0.000000;;, + 16;3;-0.057544,3.129822,0.000000;;, + 17;3;-0.057544,3.129822,0.000000;;, + 18;3;-0.057544,3.129822,0.000000;;, + 19;3;-0.057544,3.129822,0.000000;;, + 20;3;-0.057544,3.129822,0.000000;;, + 27;3;-0.057544,3.129822,0.000000;;, + 33;3;-0.057544,3.129822,0.000000;;, + 34;3;-0.057544,3.129822,0.000000;;, + 35;3;-0.057544,3.129822,0.000000;;, + 41;3;-0.057544,3.129822,0.000000;;, + 43;3;-0.057544,3.129822,0.000000;;, + 50;3;-0.057544,3.129822,0.000000;;, + 53;3;-0.057544,3.129822,0.000000;;, + 55;3;-0.057544,3.129822,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;0.999229,0.039260,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;0.999229,0.000000,0.039260,0.000000;;, + 43;4;0.999248,0.000000,0.038762,0.000000;;, + 50;4;0.999858,0.000000,0.016858,0.000000;;, + 53;4;0.999977,0.000000,0.006743,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation headAnimation + { + {head} + + AnimationKey + { + 2; + 27; + 0;3;0.000000,4.183402,0.000000;;, + 1;3;0.000000,4.183402,0.000000;;, + 2;3;0.000000,4.191365,-0.387104;;, + 3;3;0.000000,4.200649,-0.838410;;, + 4;3;0.000000,4.208574,-1.223624;;, + 5;3;0.000000,4.208574,-1.223624;;, + 7;3;0.000000,4.208574,-1.223624;;, + 12;3;0.000000,4.208574,-1.223624;;, + 14;3;0.000000,4.208574,-1.223624;;, + 15;3;0.000000,4.208574,-1.223624;;, + 16;3;0.000000,4.202753,-0.940661;;, + 17;3;0.000000,4.196014,-0.613087;;, + 18;3;0.000000,4.189146,-0.279245;;, + 19;3;0.000000,4.183402,0.000000;;, + 20;3;0.000000,4.183402,0.000000;;, + 23;3;0.000000,4.183402,0.000000;;, + 27;3;0.000000,4.183402,0.000000;;, + 29;3;0.000000,4.183402,0.000000;;, + 33;3;0.000000,4.183402,0.000000;;, + 34;3;0.000000,4.183402,0.000000;;, + 35;3;0.000000,4.183402,0.000000;;, + 41;3;0.000000,4.183402,0.000000;;, + 43;3;0.000000,4.183402,0.000000;;, + 45;3;0.000000,4.183402,0.000000;;, + 50;3;0.000000,4.183402,0.000000;;, + 53;3;0.000000,4.183402,0.000000;;, + 55;3;0.000000,4.183402,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 27; + 0;4;0.998392,-0.056693,0.000000,0.000000;;, + 1;4;0.998392,-0.056693,0.000000,0.000000;;, + 2;4;0.998178,-0.056679,0.001174,-0.020671;;, + 3;4;0.997388,-0.056635,0.002542,-0.044758;;, + 4;4;0.996254,-0.056570,0.003708,-0.065298;;, + 5;4;0.996254,-0.056570,0.003708,-0.065298;;, + 7;4;0.995518,-0.058815,0.038474,-0.063284;;, + 12;4;0.996114,-0.057445,0.017139,-0.064530;;, + 14;4;0.996254,-0.056570,0.003708,-0.065298;;, + 15;4;0.996254,-0.056570,0.003708,-0.065298;;, + 16;4;0.997128,-0.056620,0.002851,-0.050213;;, + 17;4;0.997855,-0.056661,0.001859,-0.032735;;, + 18;4;0.998280,-0.056685,0.000847,-0.014912;;, + 19;4;0.998392,-0.056693,0.000000,0.000000;;, + 20;4;0.998392,-0.056693,0.000000,0.000000;;, + 23;4;0.993540,-0.095666,0.060767,0.005851;;, + 27;4;0.992410,-0.122909,0.003406,-0.001945;;, + 29;4;0.992114,-0.123201,-0.022487,-0.005039;;, + 33;4;0.998392,-0.056693,0.000000,0.000000;;, + 34;4;0.998392,-0.056693,0.000000,0.000000;;, + 35;4;0.998392,-0.056693,0.000000,0.000000;;, + 41;4;0.994963,-0.056497,0.082675,0.004695;;, + 43;4;0.996303,-0.056573,0.064552,0.003665;;, + 45;4;0.985311,-0.055949,-0.161087,-0.009147;;, + 50;4;0.997274,-0.056628,-0.047219,-0.002681;;, + 53;4;0.994336,-0.056461,0.089900,0.005105;;, + 55;4;0.998392,-0.056693,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint36Animation + { + {Joint36} + + AnimationKey + { + 2; + 23; + 0;3;2.351048,-2.969238,-5.128667;;, + 1;3;2.351048,-2.969238,-5.128667;;, + 2;3;2.351048,-2.969238,-5.128667;;, + 3;3;2.351048,-2.969238,-5.128667;;, + 4;3;2.351048,-2.969238,-5.128667;;, + 5;3;2.351048,-2.969238,-5.128667;;, + 12;3;2.351048,-2.969238,-5.128667;;, + 14;3;2.351048,-2.969238,-5.128667;;, + 15;3;2.351048,-2.969238,-5.128667;;, + 16;3;2.351048,-2.969238,-5.128667;;, + 17;3;2.351048,-2.969238,-5.128667;;, + 18;3;2.351048,-2.969238,-5.128667;;, + 19;3;2.351048,-2.969238,-5.128667;;, + 20;3;2.351048,-2.969238,-5.128667;;, + 27;3;2.351048,-2.969238,-5.128667;;, + 33;3;2.351048,-2.969238,-5.128667;;, + 34;3;2.351048,-2.969238,-5.128667;;, + 35;3;2.351048,-2.969238,-5.128667;;, + 41;3;2.351048,-2.969238,-5.128667;;, + 43;3;2.351048,-2.969238,-5.128667;;, + 50;3;2.351048,-2.969238,-5.128667;;, + 53;3;2.351048,-2.969238,-5.128667;;, + 55;3;2.351048,-2.969238,-5.128667;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;0.999936,0.006365,-0.001014,0.009261;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;0.999825,0.002850,-0.006074,0.017471;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint39Animation + { + {Joint39} + + AnimationKey + { + 2; + 23; + 0;3;2.521163,-4.102684,-2.779583;;, + 1;3;2.521163,-4.102684,-2.779583;;, + 2;3;2.521163,-4.102684,-2.779583;;, + 3;3;2.521163,-4.102684,-2.779583;;, + 4;3;2.521163,-4.102684,-2.779583;;, + 5;3;2.521163,-4.102684,-2.779583;;, + 12;3;2.521163,-4.102684,-2.779583;;, + 14;3;2.521163,-4.102684,-2.779583;;, + 15;3;2.521163,-4.102684,-2.779583;;, + 16;3;2.521163,-4.102684,-2.779583;;, + 17;3;2.521163,-4.102684,-2.779583;;, + 18;3;2.521163,-4.102684,-2.779583;;, + 19;3;2.521163,-4.102684,-2.779583;;, + 20;3;2.521163,-4.102684,-2.779583;;, + 27;3;2.521163,-4.102684,-2.779583;;, + 33;3;2.521163,-4.102684,-2.779583;;, + 34;3;2.521163,-4.102684,-2.779583;;, + 35;3;2.521163,-4.102684,-2.779583;;, + 41;3;2.521163,-4.102684,-2.779583;;, + 43;3;2.521163,-4.102684,-2.779583;;, + 50;3;2.521163,-4.102684,-2.779583;;, + 53;3;2.521163,-4.102684,-2.779583;;, + 55;3;2.521163,-4.102684,-2.779583;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;0.999181,0.023935,-0.000402,0.032630;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;0.993880,0.004998,-0.009988,0.109898;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint40Animation + { + {Joint40} + + AnimationKey + { + 2; + 23; + 0;3;1.543145,-3.721243,-0.884647;;, + 1;3;1.543145,-3.721243,-0.884647;;, + 2;3;1.543145,-3.721243,-0.884647;;, + 3;3;1.543145,-3.721243,-0.884647;;, + 4;3;1.543145,-3.721243,-0.884647;;, + 5;3;1.543145,-3.721243,-0.884647;;, + 12;3;1.543145,-3.721243,-0.884647;;, + 14;3;1.543145,-3.721243,-0.884647;;, + 15;3;1.543145,-3.721243,-0.884647;;, + 16;3;1.543145,-3.721243,-0.884647;;, + 17;3;1.543145,-3.721243,-0.884647;;, + 18;3;1.543145,-3.721243,-0.884647;;, + 19;3;1.543145,-3.721243,-0.884647;;, + 20;3;1.543145,-3.721243,-0.884647;;, + 27;3;1.543145,-3.721243,-0.884647;;, + 33;3;1.543145,-3.721243,-0.884647;;, + 34;3;1.543145,-3.721243,-0.884647;;, + 35;3;1.543145,-3.721243,-0.884647;;, + 41;3;1.543145,-3.721243,-0.884647;;, + 43;3;1.543145,-3.721243,-0.884647;;, + 50;3;1.543145,-3.721243,-0.884647;;, + 53;3;1.543145,-3.721243,-0.884647;;, + 55;3;1.543145,-3.721243,-0.884647;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;0.997151,0.043421,-0.006512,0.061340;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;0.991531,0.009387,-0.014839,0.128675;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint41Animation + { + {Joint41} + + AnimationKey + { + 2; + 23; + 0;3;0.857303,-3.157324,-0.940437;;, + 1;3;0.857303,-3.157324,-0.940437;;, + 2;3;0.857303,-3.157324,-0.940437;;, + 3;3;0.857303,-3.157324,-0.940437;;, + 4;3;0.857303,-3.157324,-0.940437;;, + 5;3;0.857303,-3.157324,-0.940437;;, + 12;3;0.857303,-3.157324,-0.940437;;, + 14;3;0.857303,-3.157324,-0.940437;;, + 15;3;0.857303,-3.157324,-0.940437;;, + 16;3;0.857303,-3.157324,-0.940437;;, + 17;3;0.857303,-3.157324,-0.940437;;, + 18;3;0.857303,-3.157324,-0.940437;;, + 19;3;0.857303,-3.157324,-0.940437;;, + 20;3;0.857303,-3.157324,-0.940437;;, + 27;3;0.857303,-3.157324,-0.940437;;, + 33;3;0.857303,-3.157324,-0.940437;;, + 34;3;0.857303,-3.157324,-0.940437;;, + 35;3;0.857303,-3.157324,-0.940437;;, + 41;3;0.857303,-3.157324,-0.940437;;, + 43;3;0.857303,-3.157324,-0.940437;;, + 50;3;0.857303,-3.157324,-0.940437;;, + 53;3;0.857303,-3.157324,-0.940437;;, + 55;3;0.857303,-3.157324,-0.940437;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint37Animation + { + {Joint37} + + AnimationKey + { + 2; + 23; + 0;3;-2.844125,-3.130046,-5.128667;;, + 1;3;-2.844125,-3.130046,-5.128667;;, + 2;3;-2.844125,-3.130046,-5.128667;;, + 3;3;-2.844125,-3.130046,-5.128667;;, + 4;3;-2.844125,-3.130046,-5.128667;;, + 5;3;-2.844125,-3.130046,-5.128667;;, + 12;3;-2.844125,-3.130046,-5.128667;;, + 14;3;-2.844125,-3.130046,-5.128667;;, + 15;3;-2.844125,-3.130046,-5.128667;;, + 16;3;-2.844125,-3.130046,-5.128667;;, + 17;3;-2.844125,-3.130046,-5.128667;;, + 18;3;-2.844125,-3.130046,-5.128667;;, + 19;3;-2.844125,-3.130046,-5.128667;;, + 20;3;-2.844125,-3.130046,-5.128667;;, + 27;3;-2.844125,-3.130046,-5.128667;;, + 33;3;-2.844125,-3.130046,-5.128667;;, + 34;3;-2.844125,-3.130046,-5.128667;;, + 35;3;-2.844125,-3.130046,-5.128667;;, + 41;3;-2.844125,-3.130046,-5.128667;;, + 43;3;-2.844125,-3.130046,-5.128667;;, + 50;3;-2.844125,-3.130046,-5.128667;;, + 53;3;-2.844125,-3.130046,-5.128667;;, + 55;3;-2.844125,-3.130046,-5.128667;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;0.999521,0.014638,-0.017367,0.021010;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;0.996793,0.039942,-0.049084,0.048974;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint38Animation + { + {Joint38} + + AnimationKey + { + 2; + 23; + 0;3;-2.314107,-4.198860,-2.779583;;, + 1;3;-2.314107,-4.198860,-2.779583;;, + 2;3;-2.314107,-4.198860,-2.779583;;, + 3;3;-2.314107,-4.198860,-2.779583;;, + 4;3;-2.314107,-4.198860,-2.779583;;, + 5;3;-2.314107,-4.198860,-2.779583;;, + 12;3;-2.314107,-4.198860,-2.779583;;, + 14;3;-2.314107,-4.198860,-2.779583;;, + 15;3;-2.314107,-4.198860,-2.779583;;, + 16;3;-2.314107,-4.198860,-2.779583;;, + 17;3;-2.314107,-4.198860,-2.779583;;, + 18;3;-2.314107,-4.198860,-2.779583;;, + 19;3;-2.314107,-4.198860,-2.779583;;, + 20;3;-2.314107,-4.198860,-2.779583;;, + 27;3;-2.314107,-4.198860,-2.779583;;, + 33;3;-2.314107,-4.198860,-2.779583;;, + 34;3;-2.314107,-4.198860,-2.779583;;, + 35;3;-2.314107,-4.198860,-2.779583;;, + 41;3;-2.314107,-4.198860,-2.779583;;, + 43;3;-2.314107,-4.198860,-2.779583;;, + 50;3;-2.314107,-4.198860,-2.779583;;, + 53;3;-2.314107,-4.198860,-2.779583;;, + 55;3;-2.314107,-4.198860,-2.779583;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;0.997118,0.039292,-0.030553,0.057264;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;0.991578,-0.066684,-0.003497,0.110966;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint42Animation + { + {Joint42} + + AnimationKey + { + 2; + 23; + 0;3;-1.200224,-3.209697,-0.885387;;, + 1;3;-1.200224,-3.209697,-0.885387;;, + 2;3;-1.200224,-3.209697,-0.885387;;, + 3;3;-1.200224,-3.209697,-0.885387;;, + 4;3;-1.200224,-3.209697,-0.885387;;, + 5;3;-1.200224,-3.209697,-0.885387;;, + 12;3;-1.200224,-3.209697,-0.885387;;, + 14;3;-1.200224,-3.209697,-0.885387;;, + 15;3;-1.200224,-3.209697,-0.885387;;, + 16;3;-1.200224,-3.209697,-0.885387;;, + 17;3;-1.200224,-3.209697,-0.885387;;, + 18;3;-1.200224,-3.209697,-0.885387;;, + 19;3;-1.200224,-3.209697,-0.885387;;, + 20;3;-1.200224,-3.209697,-0.885387;;, + 27;3;-1.200224,-3.209697,-0.885387;;, + 33;3;-1.200224,-3.209697,-0.885387;;, + 34;3;-1.200224,-3.209697,-0.885387;;, + 35;3;-1.200224,-3.209697,-0.885387;;, + 41;3;-1.200224,-3.209697,-0.885387;;, + 43;3;-1.200224,-3.209697,-0.885387;;, + 50;3;-1.200224,-3.209697,-0.885387;;, + 53;3;-1.200224,-3.209697,-0.885387;;, + 55;3;-1.200224,-3.209697,-0.885387;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint43Animation + { + {Joint43} + + AnimationKey + { + 2; + 23; + 0;3;-1.285954,-3.696030,-0.939697;;, + 1;3;-1.285954,-3.696030,-0.939697;;, + 2;3;-1.285954,-3.696030,-0.939697;;, + 3;3;-1.285954,-3.696030,-0.939697;;, + 4;3;-1.285954,-3.696030,-0.939697;;, + 5;3;-1.285954,-3.696030,-0.939697;;, + 12;3;-1.285954,-3.696030,-0.939697;;, + 14;3;-1.285954,-3.696030,-0.939697;;, + 15;3;-1.285954,-3.696030,-0.939697;;, + 16;3;-1.285954,-3.696030,-0.939697;;, + 17;3;-1.285954,-3.696030,-0.939697;;, + 18;3;-1.285954,-3.696030,-0.939697;;, + 19;3;-1.285954,-3.696030,-0.939697;;, + 20;3;-1.285954,-3.696030,-0.939697;;, + 27;3;-1.285954,-3.696030,-0.939697;;, + 33;3;-1.285954,-3.696030,-0.939697;;, + 34;3;-1.285954,-3.696030,-0.939697;;, + 35;3;-1.285954,-3.696030,-0.939697;;, + 41;3;-1.285954,-3.696030,-0.939697;;, + 43;3;-1.285954,-3.696030,-0.939697;;, + 50;3;-1.285954,-3.696030,-0.939697;;, + 53;3;-1.285954,-3.696030,-0.939697;;, + 55;3;-1.285954,-3.696030,-0.939697;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation topAnimation + { + {top} + + AnimationKey + { + 2; + 23; + 0;3;-0.311274,14.438549,-1.107615;;, + 1;3;-0.311274,14.438549,-1.107615;;, + 2;3;-0.311274,14.438549,-1.107615;;, + 3;3;-0.311274,14.438549,-1.107615;;, + 4;3;-0.311274,14.438549,-1.107615;;, + 5;3;-0.311274,14.438549,-1.107615;;, + 12;3;-0.311274,14.438549,-1.107615;;, + 14;3;-0.311274,14.438549,-1.107615;;, + 15;3;-0.311274,14.438549,-1.107615;;, + 16;3;-0.311274,14.438549,-1.107615;;, + 17;3;-0.311274,14.438549,-1.107615;;, + 18;3;-0.311274,14.438549,-1.107615;;, + 19;3;-0.311274,14.438549,-1.107615;;, + 20;3;-0.311274,14.438549,-1.107615;;, + 27;3;-0.311274,14.438549,-1.107615;;, + 33;3;-0.311274,14.438549,-1.107615;;, + 34;3;-0.311274,14.438549,-1.107615;;, + 35;3;-0.311274,14.438549,-1.107615;;, + 41;3;-0.311274,14.438549,-1.107615;;, + 43;3;-0.311274,14.438549,-1.107615;;, + 50;3;-0.311274,14.438549,-1.107615;;, + 53;3;-0.311274,14.438549,-1.107615;;, + 55;3;-0.311274,14.438549,-1.107615;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation pad2Animation + { + {pad2} + + AnimationKey + { + 2; + 23; + 0;3;-6.280235,3.399014,0.000000;;, + 1;3;-6.280235,3.399014,0.000000;;, + 2;3;-6.280235,3.399014,0.000000;;, + 3;3;-6.280235,3.399014,0.000000;;, + 4;3;-6.280235,3.399014,0.000000;;, + 5;3;-6.280235,3.399014,0.000000;;, + 12;3;-6.280235,3.399014,0.000000;;, + 14;3;-6.280235,3.399014,0.000000;;, + 15;3;-6.280235,3.399014,0.000000;;, + 16;3;-6.280235,3.399014,0.000000;;, + 17;3;-6.280235,3.399014,0.000000;;, + 18;3;-6.280235,3.399014,0.000000;;, + 19;3;-6.280235,3.399014,0.000000;;, + 20;3;-6.280235,3.399014,0.000000;;, + 27;3;-6.280235,3.399014,0.000000;;, + 33;3;-6.280235,3.399014,0.000000;;, + 34;3;-6.280235,3.399014,0.000000;;, + 35;3;-6.280235,3.399014,0.000000;;, + 41;3;-6.280235,3.399014,0.000000;;, + 43;3;-6.280235,3.399014,0.000000;;, + 50;3;-6.280235,3.399014,0.000000;;, + 53;3;-6.280235,3.399014,0.000000;;, + 55;3;-6.280235,3.399014,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 1;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 2;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 3;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 4;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 5;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 12;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 14;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 15;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 16;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 17;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 18;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 19;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 20;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 27;4;0.989850,-0.129750,-0.014210,-0.056208;;, + 33;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 34;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 35;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 41;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 43;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 50;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 53;4;0.988040,-0.130078,-0.010809,-0.082100;;, + 55;4;0.988040,-0.130078,-0.010809,-0.082100;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation pad1Animation + { + {pad1} + + AnimationKey + { + 2; + 23; + 0;3;5.233529,3.529747,0.000000;;, + 1;3;5.233529,3.529747,0.000000;;, + 2;3;5.233529,3.529747,0.000000;;, + 3;3;5.233529,3.529747,0.000000;;, + 4;3;5.233529,3.529747,0.000000;;, + 5;3;5.233529,3.529747,0.000000;;, + 12;3;5.233529,3.529747,0.000000;;, + 14;3;5.233529,3.529747,0.000000;;, + 15;3;5.233529,3.529747,0.000000;;, + 16;3;5.233529,3.529747,0.000000;;, + 17;3;5.233529,3.529747,0.000000;;, + 18;3;5.233529,3.529747,0.000000;;, + 19;3;5.233529,3.529747,0.000000;;, + 20;3;5.233529,3.529747,0.000000;;, + 27;3;5.233529,3.529747,0.000000;;, + 33;3;5.233529,3.529747,0.000000;;, + 34;3;5.233529,3.529747,0.000000;;, + 35;3;5.233529,3.529747,0.000000;;, + 41;3;5.233529,3.529747,0.000000;;, + 43;3;5.233529,3.529747,0.000000;;, + 50;3;5.233529,3.529747,0.000000;;, + 53;3;5.233529,3.529747,0.000000;;, + 55;3;5.233529,3.529747,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;0.998135,0.000000,0.000000,-0.061049;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation lsholdaAnimation + { + {lsholda} + + AnimationKey + { + 2; + 23; + 0;3;-10.711074,-1.732187,3.529744;;, + 1;3;-10.711074,-1.732187,3.529744;;, + 2;3;-10.711074,-1.732187,3.529744;;, + 3;3;-10.711074,-1.732187,3.529744;;, + 4;3;-10.711074,-1.732187,3.529744;;, + 5;3;-10.711074,-1.732187,3.529744;;, + 12;3;-10.711074,-1.732187,3.529744;;, + 14;3;-10.711074,-1.732187,3.529744;;, + 15;3;-10.711074,-1.732187,3.529744;;, + 16;3;-10.711074,-1.732187,3.529744;;, + 17;3;-10.711074,-1.732187,3.529744;;, + 18;3;-10.711074,-1.732187,3.529744;;, + 19;3;-10.711074,-1.732187,3.529744;;, + 20;3;-10.711074,-1.732187,3.529744;;, + 27;3;-10.711074,-1.732187,3.529744;;, + 33;3;-10.711074,-1.732187,3.529744;;, + 34;3;-10.711074,-1.732187,3.529744;;, + 35;3;-10.711074,-1.732187,3.529744;;, + 41;3;-10.711074,-1.732187,3.529744;;, + 43;3;-10.711074,-1.732187,3.529744;;, + 50;3;-10.711074,-1.732187,3.529744;;, + 53;3;-10.711074,-1.732187,3.529744;;, + 55;3;-10.711074,-1.732187,3.529744;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;0.992262,-0.004035,-0.002900,-0.124058;;, + 1;4;0.992262,-0.004035,-0.002900,-0.124058;;, + 2;4;0.984948,-0.092375,0.080710,-0.121780;;, + 3;4;0.957969,-0.193544,0.176588,-0.116845;;, + 4;4;0.919617,-0.276885,0.255679,-0.110761;;, + 5;4;0.919617,-0.276885,0.255679,-0.110761;;, + 12;4;0.919617,-0.276885,0.255679,-0.110761;;, + 14;4;0.919617,-0.276885,0.255679,-0.110761;;, + 15;4;0.919617,-0.276885,0.255679,-0.110761;;, + 16;4;0.949143,-0.215995,0.197884,-0.115394;;, + 17;4;0.973899,-0.143396,0.129045,-0.119611;;, + 18;4;0.988465,-0.067843,0.057481,-0.122598;;, + 19;4;0.992262,-0.004035,-0.002900,-0.124058;;, + 20;4;0.992262,-0.004035,-0.002900,-0.124058;;, + 27;4;0.980361,0.117258,0.064506,-0.144851;;, + 33;4;0.992262,-0.004035,-0.002900,-0.124058;;, + 34;4;0.992262,-0.004035,-0.002900,-0.124058;;, + 35;4;0.992262,-0.004035,-0.002900,-0.124058;;, + 41;4;0.987041,-0.061321,0.042727,-0.142002;;, + 43;4;0.984145,-0.079780,0.057436,-0.147634;;, + 50;4;0.975443,-0.121280,0.090521,-0.160025;;, + 53;4;0.987695,-0.056533,0.038912,-0.140529;;, + 55;4;0.992262,-0.004035,-0.002900,-0.124058;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation lelboAnimation + { + {lelbo} + + AnimationKey + { + 2; + 23; + 0;3;-6.541911,-5.098517,0.705949;;, + 1;3;-6.541911,-5.098517,0.705949;;, + 2;3;-6.541911,-5.098517,0.705949;;, + 3;3;-6.541911,-5.098517,0.705949;;, + 4;3;-6.541911,-5.098517,0.705949;;, + 5;3;-6.541911,-5.098517,0.705949;;, + 12;3;-6.541911,-5.098517,0.705949;;, + 14;3;-6.541911,-5.098517,0.705949;;, + 15;3;-6.541911,-5.098517,0.705949;;, + 16;3;-6.541911,-5.098517,0.705949;;, + 17;3;-6.541911,-5.098517,0.705949;;, + 18;3;-6.541911,-5.098517,0.705949;;, + 19;3;-6.541911,-5.098517,0.705949;;, + 20;3;-6.541911,-5.098517,0.705949;;, + 27;3;-6.541911,-5.098517,0.705949;;, + 33;3;-6.541911,-5.098517,0.705949;;, + 34;3;-6.541911,-5.098517,0.705949;;, + 35;3;-6.541911,-5.098517,0.705949;;, + 41;3;-6.541911,-5.098517,0.705949;;, + 43;3;-6.541911,-5.098517,0.705949;;, + 50;3;-6.541911,-5.098517,0.705949;;, + 53;3;-6.541911,-5.098517,0.705949;;, + 55;3;-6.541911,-5.098517,0.705949;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;0.938931,-0.301990,0.116244,-0.117037;;, + 1;4;0.938931,-0.301990,0.116244,-0.117037;;, + 2;4;0.939499,-0.269250,0.068390,-0.200421;;, + 3;4;0.927931,-0.227598,0.011743,-0.294966;;, + 4;4;0.907758,-0.189498,-0.036768,-0.372443;;, + 5;4;0.907758,-0.189498,-0.036768,-0.372443;;, + 12;4;0.907815,-0.196434,-0.033361,-0.369017;;, + 14;4;0.907758,-0.189498,-0.036768,-0.372443;;, + 15;4;0.907758,-0.189498,-0.036768,-0.372443;;, + 16;4;0.923494,-0.217696,-0.001142,-0.315858;;, + 17;4;0.935347,-0.248829,0.040096,-0.248198;;, + 18;4;0.940317,-0.278666,0.081816,-0.177359;;, + 19;4;0.938931,-0.301990,0.116244,-0.117037;;, + 20;4;0.938931,-0.301990,0.116244,-0.117037;;, + 27;4;0.969755,-0.235046,0.020216,-0.062603;;, + 33;4;0.938931,-0.301990,0.116244,-0.117037;;, + 34;4;0.938931,-0.301990,0.116244,-0.117037;;, + 35;4;0.938931,-0.301990,0.116244,-0.117037;;, + 41;4;0.907794,-0.355022,0.176137,-0.137281;;, + 43;4;0.896205,-0.371593,0.195226,-0.143604;;, + 50;4;0.867362,-0.407890,0.237736,-0.157448;;, + 53;4;0.910675,-0.350682,0.171168,-0.135625;;, + 55;4;0.938931,-0.301990,0.116244,-0.117037;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation lwristAnimation + { + {lwrist} + + AnimationKey + { + 2; + 23; + 0;3;-7.850295,-6.405833,0.000000;;, + 1;3;-7.850295,-6.405833,0.000000;;, + 2;3;-7.850295,-6.405833,0.000000;;, + 3;3;-7.850295,-6.405833,0.000000;;, + 4;3;-7.850295,-6.405833,0.000000;;, + 5;3;-7.850295,-6.405833,0.000000;;, + 12;3;-7.850295,-6.405833,0.000000;;, + 14;3;-7.850295,-6.405833,0.000000;;, + 15;3;-7.850295,-6.405833,0.000000;;, + 16;3;-7.850295,-6.405833,0.000000;;, + 17;3;-7.850295,-6.405833,0.000000;;, + 18;3;-7.850295,-6.405833,0.000000;;, + 19;3;-7.850295,-6.405833,0.000000;;, + 20;3;-7.850295,-6.405833,0.000000;;, + 27;3;-7.850295,-6.405833,0.000000;;, + 33;3;-7.850295,-6.405833,0.000000;;, + 34;3;-7.850295,-6.405833,0.000000;;, + 35;3;-7.850295,-6.405833,0.000000;;, + 41;3;-7.850295,-6.405833,0.000000;;, + 43;3;-7.850295,-6.405833,0.000000;;, + 50;3;-7.850295,-6.405833,0.000000;;, + 53;3;-7.850295,-6.405833,0.000000;;, + 55;3;-7.850295,-6.405833,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint17Animation + { + {Joint17} + + AnimationKey + { + 2; + 23; + 0;3;-3.663469,-3.660475,0.000000;;, + 1;3;-3.663469,-3.660475,0.000000;;, + 2;3;-3.663469,-3.660475,0.000000;;, + 3;3;-3.663469,-3.660475,0.000000;;, + 4;3;-3.663469,-3.660475,0.000000;;, + 5;3;-3.663469,-3.660475,0.000000;;, + 12;3;-3.663469,-3.660475,0.000000;;, + 14;3;-3.663469,-3.660475,0.000000;;, + 15;3;-3.663469,-3.660475,0.000000;;, + 16;3;-3.663469,-3.660475,0.000000;;, + 17;3;-3.663469,-3.660475,0.000000;;, + 18;3;-3.663469,-3.660475,0.000000;;, + 19;3;-3.663469,-3.660475,0.000000;;, + 20;3;-3.663469,-3.660475,0.000000;;, + 27;3;-3.663469,-3.660475,0.000000;;, + 33;3;-3.663469,-3.660475,0.000000;;, + 34;3;-3.663469,-3.660475,0.000000;;, + 35;3;-3.663469,-3.660475,0.000000;;, + 41;3;-3.663469,-3.660475,0.000000;;, + 43;3;-3.663469,-3.660475,0.000000;;, + 50;3;-3.663469,-3.660475,0.000000;;, + 53;3;-3.663469,-3.660475,0.000000;;, + 55;3;-3.663469,-3.660475,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint18Animation + { + {Joint18} + + AnimationKey + { + 2; + 23; + 0;3;-1.046706,-2.091701,0.000000;;, + 1;3;-1.046706,-2.091701,0.000000;;, + 2;3;-1.046706,-2.091701,0.000000;;, + 3;3;-1.046706,-2.091701,0.000000;;, + 4;3;-1.046706,-2.091701,0.000000;;, + 5;3;-1.046706,-2.091701,0.000000;;, + 12;3;-1.046706,-2.091701,0.000000;;, + 14;3;-1.046706,-2.091701,0.000000;;, + 15;3;-1.046706,-2.091701,0.000000;;, + 16;3;-1.046706,-2.091701,0.000000;;, + 17;3;-1.046706,-2.091701,0.000000;;, + 18;3;-1.046706,-2.091701,0.000000;;, + 19;3;-1.046706,-2.091701,0.000000;;, + 20;3;-1.046706,-2.091701,0.000000;;, + 27;3;-1.046706,-2.091701,0.000000;;, + 33;3;-1.046706,-2.091701,0.000000;;, + 34;3;-1.046706,-2.091701,0.000000;;, + 35;3;-1.046706,-2.091701,0.000000;;, + 41;3;-1.046706,-2.091701,0.000000;;, + 43;3;-1.046706,-2.091701,0.000000;;, + 50;3;-1.046706,-2.091701,0.000000;;, + 53;3;-1.046706,-2.091701,0.000000;;, + 55;3;-1.046706,-2.091701,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;0.938191,0.000000,0.000000,-0.346117;;, + 1;4;0.938191,0.000000,0.000000,-0.346117;;, + 2;4;0.938191,0.000000,0.000000,-0.346117;;, + 3;4;0.938191,0.000000,0.000000,-0.346117;;, + 4;4;0.938191,0.000000,0.000000,-0.346117;;, + 5;4;0.938191,0.000000,0.000000,-0.346117;;, + 12;4;0.938191,0.000000,0.000000,-0.346117;;, + 14;4;0.938191,0.000000,0.000000,-0.346117;;, + 15;4;0.938191,0.000000,0.000000,-0.346117;;, + 16;4;0.938191,0.000000,0.000000,-0.346117;;, + 17;4;0.938191,0.000000,0.000000,-0.346117;;, + 18;4;0.938191,0.000000,0.000000,-0.346117;;, + 19;4;0.938191,0.000000,0.000000,-0.346117;;, + 20;4;0.938191,0.000000,0.000000,-0.346117;;, + 27;4;0.938191,0.000000,0.000000,-0.346117;;, + 33;4;0.938191,0.000000,0.000000,-0.346117;;, + 34;4;0.938191,0.000000,0.000000,-0.346117;;, + 35;4;0.938191,0.000000,0.000000,-0.346117;;, + 41;4;0.938191,0.000000,0.000000,-0.346117;;, + 43;4;0.938191,0.000000,0.000000,-0.346117;;, + 50;4;0.938191,0.000000,0.000000,-0.346117;;, + 53;4;0.938191,0.000000,0.000000,-0.346117;;, + 55;4;0.938191,0.000000,0.000000,-0.346117;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint19Animation + { + {Joint19} + + AnimationKey + { + 2; + 23; + 0;3;-0.130838,-3.137549,0.000000;;, + 1;3;-0.130838,-3.137549,0.000000;;, + 2;3;-0.130838,-3.137549,0.000000;;, + 3;3;-0.130838,-3.137549,0.000000;;, + 4;3;-0.130838,-3.137549,0.000000;;, + 5;3;-0.130838,-3.137549,0.000000;;, + 12;3;-0.130838,-3.137549,0.000000;;, + 14;3;-0.130838,-3.137549,0.000000;;, + 15;3;-0.130838,-3.137549,0.000000;;, + 16;3;-0.130838,-3.137549,0.000000;;, + 17;3;-0.130838,-3.137549,0.000000;;, + 18;3;-0.130838,-3.137549,0.000000;;, + 19;3;-0.130838,-3.137549,0.000000;;, + 20;3;-0.130838,-3.137549,0.000000;;, + 27;3;-0.130838,-3.137549,0.000000;;, + 33;3;-0.130838,-3.137549,0.000000;;, + 34;3;-0.130838,-3.137549,0.000000;;, + 35;3;-0.130838,-3.137549,0.000000;;, + 41;3;-0.130838,-3.137549,0.000000;;, + 43;3;-0.130838,-3.137549,0.000000;;, + 50;3;-0.130838,-3.137549,0.000000;;, + 53;3;-0.130838,-3.137549,0.000000;;, + 55;3;-0.130838,-3.137549,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint20Animation + { + {Joint20} + + AnimationKey + { + 2; + 23; + 0;3;-1.416095,-4.359032,-3.203176;;, + 1;3;-1.416095,-4.359032,-3.203176;;, + 2;3;-1.416095,-4.359032,-3.203176;;, + 3;3;-1.416095,-4.359032,-3.203176;;, + 4;3;-1.416095,-4.359032,-3.203176;;, + 5;3;-1.416095,-4.359032,-3.203176;;, + 12;3;-1.416095,-4.359032,-3.203176;;, + 14;3;-1.416095,-4.359032,-3.203176;;, + 15;3;-1.416095,-4.359032,-3.203176;;, + 16;3;-1.416095,-4.359032,-3.203176;;, + 17;3;-1.416095,-4.359032,-3.203176;;, + 18;3;-1.416095,-4.359032,-3.203176;;, + 19;3;-1.416095,-4.359032,-3.203176;;, + 20;3;-1.416095,-4.359032,-3.203176;;, + 27;3;-1.416095,-4.359032,-3.203176;;, + 33;3;-1.416095,-4.359032,-3.203176;;, + 34;3;-1.416095,-4.359032,-3.203176;;, + 35;3;-1.416095,-4.359032,-3.203176;;, + 41;3;-1.416095,-4.359032,-3.203176;;, + 43;3;-1.416095,-4.359032,-3.203176;;, + 50;3;-1.416095,-4.359032,-3.203176;;, + 53;3;-1.416095,-4.359032,-3.203176;;, + 55;3;-1.416095,-4.359032,-3.203176;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint21Animation + { + {Joint21} + + AnimationKey + { + 2; + 23; + 0;3;-1.046704,-2.483894,0.000000;;, + 1;3;-1.046704,-2.483894,0.000000;;, + 2;3;-1.046704,-2.483894,0.000000;;, + 3;3;-1.046704,-2.483894,0.000000;;, + 4;3;-1.046704,-2.483894,0.000000;;, + 5;3;-1.046704,-2.483894,0.000000;;, + 12;3;-1.046704,-2.483894,0.000000;;, + 14;3;-1.046704,-2.483894,0.000000;;, + 15;3;-1.046704,-2.483894,0.000000;;, + 16;3;-1.046704,-2.483894,0.000000;;, + 17;3;-1.046704,-2.483894,0.000000;;, + 18;3;-1.046704,-2.483894,0.000000;;, + 19;3;-1.046704,-2.483894,0.000000;;, + 20;3;-1.046704,-2.483894,0.000000;;, + 27;3;-1.046704,-2.483894,0.000000;;, + 33;3;-1.046704,-2.483894,0.000000;;, + 34;3;-1.046704,-2.483894,0.000000;;, + 35;3;-1.046704,-2.483894,0.000000;;, + 41;3;-1.046704,-2.483894,0.000000;;, + 43;3;-1.046704,-2.483894,0.000000;;, + 50;3;-1.046704,-2.483894,0.000000;;, + 53;3;-1.046704,-2.483894,0.000000;;, + 55;3;-1.046704,-2.483894,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation rsholdaAnimation + { + {rsholda} + + AnimationKey + { + 2; + 23; + 0;3;9.986465,-1.438042,3.529744;;, + 1;3;9.986465,-1.438042,3.529744;;, + 2;3;9.986465,-1.438042,3.529744;;, + 3;3;9.986465,-1.438042,3.529744;;, + 4;3;9.986465,-1.438042,3.529744;;, + 5;3;9.986465,-1.438042,3.529744;;, + 12;3;9.986465,-1.438042,3.529744;;, + 14;3;9.986465,-1.438042,3.529744;;, + 15;3;9.986465,-1.438042,3.529744;;, + 16;3;9.986465,-1.438042,3.529744;;, + 17;3;9.986465,-1.438042,3.529744;;, + 18;3;9.986465,-1.438042,3.529744;;, + 19;3;9.986465,-1.438042,3.529744;;, + 20;3;9.986465,-1.438042,3.529744;;, + 27;3;9.986465,-1.438042,3.529744;;, + 33;3;9.986465,-1.438042,3.529744;;, + 34;3;9.986465,-1.438042,3.529744;;, + 35;3;9.986465,-1.438042,3.529744;;, + 41;3;9.986465,-1.438042,3.529744;;, + 43;3;9.986465,-1.438042,3.529744;;, + 50;3;9.986465,-1.438042,3.529744;;, + 53;3;9.986465,-1.438042,3.529744;;, + 55;3;9.986465,-1.438042,3.529744;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;0.993880,-0.002269,0.003388,0.110387;;, + 1;4;0.993880,-0.002269,0.003388,0.110387;;, + 2;4;0.993765,-0.003650,0.000223,0.111434;;, + 3;4;0.993637,-0.005031,-0.002942,0.112479;;, + 4;4;0.993496,-0.006413,-0.006107,0.113522;;, + 5;4;0.993496,-0.006413,-0.006107,0.113522;;, + 12;4;0.993496,-0.006413,-0.006107,0.113523;;, + 14;4;0.993496,-0.006413,-0.006107,0.113522;;, + 15;4;0.993496,-0.006413,-0.006107,0.113522;;, + 16;4;0.993603,-0.005377,-0.003733,0.112740;;, + 17;4;0.993703,-0.004341,-0.001359,0.111957;;, + 18;4;0.993795,-0.003305,0.001014,0.111173;;, + 19;4;0.993880,-0.002269,0.003388,0.110387;;, + 20;4;0.993880,-0.002269,0.003388,0.110387;;, + 27;4;0.973729,-0.204525,0.026684,0.096484;;, + 33;4;0.993880,-0.002269,0.003388,0.110387;;, + 34;4;0.993880,-0.002269,0.003388,0.110387;;, + 35;4;0.993880,-0.002269,0.003388,0.110387;;, + 41;4;0.994023,-0.003923,0.001453,0.109093;;, + 43;4;0.993957,-0.002996,-0.000780,0.109727;;, + 50;4;0.993678,0.000249,-0.008594,0.111941;;, + 53;4;0.993801,-0.001051,-0.002101,0.111149;;, + 55;4;0.993880,-0.002269,0.003388,0.110387;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation relboAnimation + { + {relbo} + + AnimationKey + { + 2; + 23; + 0;3;6.803588,-5.359982,0.705949;;, + 1;3;6.803588,-5.359982,0.705949;;, + 2;3;6.803588,-5.359982,0.705949;;, + 3;3;6.803588,-5.359982,0.705949;;, + 4;3;6.803588,-5.359982,0.705949;;, + 5;3;6.803588,-5.359982,0.705949;;, + 12;3;6.803588,-5.359982,0.705949;;, + 14;3;6.803588,-5.359982,0.705949;;, + 15;3;6.803588,-5.359982,0.705949;;, + 16;3;6.803588,-5.359982,0.705949;;, + 17;3;6.803588,-5.359982,0.705949;;, + 18;3;6.803588,-5.359982,0.705949;;, + 19;3;6.803588,-5.359982,0.705949;;, + 20;3;6.803588,-5.359982,0.705949;;, + 27;3;6.803588,-5.359982,0.705949;;, + 33;3;6.803588,-5.359982,0.705949;;, + 34;3;6.803588,-5.359982,0.705949;;, + 35;3;6.803588,-5.359982,0.705949;;, + 41;3;6.803588,-5.359982,0.705949;;, + 43;3;6.803588,-5.359982,0.705949;;, + 50;3;6.803588,-5.359982,0.705949;;, + 53;3;6.803588,-5.359982,0.705949;;, + 55;3;6.803588,-5.359982,0.705949;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;0.959847,-0.255150,-0.080990,0.083865;;, + 1;4;0.959847,-0.255150,-0.080990,0.083865;;, + 2;4;0.962470,-0.246054,-0.075922,0.085704;;, + 3;4;0.965384,-0.235411,-0.070003,0.087834;;, + 4;4;0.967748,-0.226298,-0.064941,0.089641;;, + 5;4;0.967748,-0.226298,-0.064941,0.089641;;, + 12;4;0.967748,-0.226298,-0.064941,0.089641;;, + 14;4;0.967748,-0.226298,-0.064941,0.089641;;, + 15;4;0.967748,-0.226298,-0.064941,0.089641;;, + 16;4;0.966023,-0.232995,-0.068660,0.088315;;, + 17;4;0.964039,-0.240399,-0.072776,0.086838;;, + 18;4;0.961805,-0.248399,-0.077228,0.085231;;, + 19;4;0.959847,-0.255150,-0.080990,0.083865;;, + 20;4;0.959847,-0.255150,-0.080990,0.083865;;, + 27;4;0.959350,-0.261136,-0.082412,0.068295;;, + 33;4;0.959847,-0.255150,-0.080990,0.083865;;, + 34;4;0.959847,-0.255150,-0.080990,0.083865;;, + 35;4;0.959847,-0.255150,-0.080990,0.083865;;, + 41;4;0.958063,-0.263775,-0.077544,0.080776;;, + 43;4;0.957289,-0.265983,-0.080054,0.080258;;, + 50;4;0.955168,-0.270038,-0.091428,0.079837;;, + 53;4;0.957785,-0.261756,-0.085958,0.082112;;, + 55;4;0.959847,-0.255150,-0.080990,0.083865;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation rwristAnimation + { + {rwrist} + + AnimationKey + { + 2; + 24; + 0;3;8.373647,-6.798027,0.000000;;, + 1;3;8.373647,-6.798027,0.000000;;, + 2;3;8.373647,-6.798027,0.000000;;, + 3;3;8.373647,-6.798027,0.000000;;, + 4;3;8.373647,-6.798027,0.000000;;, + 5;3;8.373647,-6.798027,0.000000;;, + 12;3;8.373647,-6.798027,0.000000;;, + 14;3;8.373647,-6.798027,0.000000;;, + 15;3;8.373647,-6.798027,0.000000;;, + 16;3;8.373647,-6.798027,0.000000;;, + 17;3;8.373647,-6.798027,0.000000;;, + 18;3;8.373647,-6.798027,0.000000;;, + 19;3;8.373647,-6.798027,0.000000;;, + 20;3;8.373647,-6.798027,0.000000;;, + 27;3;8.373647,-6.798027,0.000000;;, + 29;3;8.373647,-6.798027,0.000000;;, + 33;3;8.373647,-6.798027,0.000000;;, + 34;3;8.373647,-6.798027,0.000000;;, + 35;3;8.373647,-6.798027,0.000000;;, + 41;3;8.373647,-6.798027,0.000000;;, + 43;3;8.373647,-6.798027,0.000000;;, + 50;3;8.373647,-6.798027,0.000000;;, + 53;3;8.373647,-6.798027,0.000000;;, + 55;3;8.373647,-6.798027,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 24; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;0.999709,0.020471,0.012692,-0.001586;;, + 3;4;0.998633,0.044321,0.027480,-0.003434;;, + 4;4;0.997090,0.064652,0.040085,-0.005009;;, + 5;4;0.997090,0.064652,0.040085,-0.005009;;, + 12;4;0.997090,0.064652,0.040085,-0.005009;;, + 14;4;0.997090,0.064652,0.040085,-0.005009;;, + 15;4;0.997090,0.064652,0.040085,-0.005009;;, + 16;4;0.998280,0.049721,0.030828,-0.003852;;, + 17;4;0.999269,0.032417,0.020099,-0.002511;;, + 18;4;0.999848,0.014768,0.009157,-0.001144;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;0.996917,0.078459,0.000000,0.000000;;, + 29;4;0.992822,0.119601,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;0.999329,-0.002870,0.035216,-0.009610;;, + 43;4;0.999253,-0.000181,0.037154,-0.010592;;, + 50;4;0.999533,0.011592,0.026653,-0.009464;;, + 53;4;0.999915,0.005480,0.011096,-0.004044;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint25Animation + { + {Joint25} + + AnimationKey + { + 2; + 23; + 0;3;3.663469,-3.137551,0.000000;;, + 1;3;3.663469,-3.137551,0.000000;;, + 2;3;3.663469,-3.137551,0.000000;;, + 3;3;3.663469,-3.137551,0.000000;;, + 4;3;3.663469,-3.137551,0.000000;;, + 5;3;3.663469,-3.137551,0.000000;;, + 12;3;3.663469,-3.137551,0.000000;;, + 14;3;3.663469,-3.137551,0.000000;;, + 15;3;3.663469,-3.137551,0.000000;;, + 16;3;3.663469,-3.137551,0.000000;;, + 17;3;3.663469,-3.137551,0.000000;;, + 18;3;3.663469,-3.137551,0.000000;;, + 19;3;3.663469,-3.137551,0.000000;;, + 20;3;3.663469,-3.137551,0.000000;;, + 27;3;3.663469,-3.137551,0.000000;;, + 33;3;3.663469,-3.137551,0.000000;;, + 34;3;3.663469,-3.137551,0.000000;;, + 35;3;3.663469,-3.137551,0.000000;;, + 41;3;3.663469,-3.137551,0.000000;;, + 43;3;3.663469,-3.137551,0.000000;;, + 50;3;3.663469,-3.137551,0.000000;;, + 53;3;3.663469,-3.137551,0.000000;;, + 55;3;3.663469,-3.137551,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint26Animation + { + {Joint26} + + AnimationKey + { + 2; + 23; + 0;3;1.046706,-2.353162,0.000000;;, + 1;3;1.046706,-2.353162,0.000000;;, + 2;3;1.046706,-2.353162,0.000000;;, + 3;3;1.046706,-2.353162,0.000000;;, + 4;3;1.046706,-2.353162,0.000000;;, + 5;3;1.046706,-2.353162,0.000000;;, + 12;3;1.046706,-2.353162,0.000000;;, + 14;3;1.046706,-2.353162,0.000000;;, + 15;3;1.046706,-2.353162,0.000000;;, + 16;3;1.046706,-2.353162,0.000000;;, + 17;3;1.046706,-2.353162,0.000000;;, + 18;3;1.046706,-2.353162,0.000000;;, + 19;3;1.046706,-2.353162,0.000000;;, + 20;3;1.046706,-2.353162,0.000000;;, + 27;3;1.046706,-2.353162,0.000000;;, + 33;3;1.046706,-2.353162,0.000000;;, + 34;3;1.046706,-2.353162,0.000000;;, + 35;3;1.046706,-2.353162,0.000000;;, + 41;3;1.046706,-2.353162,0.000000;;, + 43;3;1.046706,-2.353162,0.000000;;, + 50;3;1.046706,-2.353162,0.000000;;, + 53;3;1.046706,-2.353162,0.000000;;, + 55;3;1.046706,-2.353162,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;0.878817,0.000000,0.000000,0.477159;;, + 1;4;0.878817,0.000000,0.000000,0.477159;;, + 2;4;0.878817,0.000000,0.000000,0.477159;;, + 3;4;0.878817,0.000000,0.000000,0.477159;;, + 4;4;0.878817,0.000000,0.000000,0.477159;;, + 5;4;0.878817,0.000000,0.000000,0.477159;;, + 12;4;0.878817,0.000000,0.000000,0.477159;;, + 14;4;0.878817,0.000000,0.000000,0.477159;;, + 15;4;0.878817,0.000000,0.000000,0.477159;;, + 16;4;0.878817,0.000000,0.000000,0.477159;;, + 17;4;0.878817,0.000000,0.000000,0.477159;;, + 18;4;0.878817,0.000000,0.000000,0.477159;;, + 19;4;0.878817,0.000000,0.000000,0.477159;;, + 20;4;0.878817,0.000000,0.000000,0.477159;;, + 27;4;0.878817,0.000000,0.000000,0.477159;;, + 33;4;0.878817,0.000000,0.000000,0.477159;;, + 34;4;0.878817,0.000000,0.000000,0.477159;;, + 35;4;0.878817,0.000000,0.000000,0.477159;;, + 41;4;0.878817,0.000000,0.000000,0.477159;;, + 43;4;0.878817,0.000000,0.000000,0.477159;;, + 50;4;0.878817,0.000000,0.000000,0.477159;;, + 53;4;0.878817,0.000000,0.000000,0.477159;;, + 55;4;0.878817,0.000000,0.000000,0.477159;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint27Animation + { + {Joint27} + + AnimationKey + { + 2; + 23; + 0;3;-0.261676,-2.876088,0.000000;;, + 1;3;-0.261676,-2.876088,0.000000;;, + 2;3;-0.261676,-2.876088,0.000000;;, + 3;3;-0.261676,-2.876088,0.000000;;, + 4;3;-0.261676,-2.876088,0.000000;;, + 5;3;-0.261676,-2.876088,0.000000;;, + 12;3;-0.261676,-2.876088,0.000000;;, + 14;3;-0.261676,-2.876088,0.000000;;, + 15;3;-0.261676,-2.876088,0.000000;;, + 16;3;-0.261676,-2.876088,0.000000;;, + 17;3;-0.261676,-2.876088,0.000000;;, + 18;3;-0.261676,-2.876088,0.000000;;, + 19;3;-0.261676,-2.876088,0.000000;;, + 20;3;-0.261676,-2.876088,0.000000;;, + 27;3;-0.261676,-2.876088,0.000000;;, + 33;3;-0.261676,-2.876088,0.000000;;, + 34;3;-0.261676,-2.876088,0.000000;;, + 35;3;-0.261676,-2.876088,0.000000;;, + 41;3;-0.261676,-2.876088,0.000000;;, + 43;3;-0.261676,-2.876088,0.000000;;, + 50;3;-0.261676,-2.876088,0.000000;;, + 53;3;-0.261676,-2.876088,0.000000;;, + 55;3;-0.261676,-2.876088,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint28Animation + { + {Joint28} + + AnimationKey + { + 2; + 23; + 0;3;-0.785030,-4.183402,-2.034320;;, + 1;3;-0.785030,-4.183402,-2.034320;;, + 2;3;-0.785030,-4.183402,-2.034320;;, + 3;3;-0.785030,-4.183402,-2.034320;;, + 4;3;-0.785030,-4.183402,-2.034320;;, + 5;3;-0.785030,-4.183402,-2.034320;;, + 12;3;-0.785030,-4.183402,-2.034320;;, + 14;3;-0.785030,-4.183402,-2.034320;;, + 15;3;-0.785030,-4.183402,-2.034320;;, + 16;3;-0.785030,-4.183402,-2.034320;;, + 17;3;-0.785030,-4.183402,-2.034320;;, + 18;3;-0.785030,-4.183402,-2.034320;;, + 19;3;-0.785030,-4.183402,-2.034320;;, + 20;3;-0.785030,-4.183402,-2.034320;;, + 27;3;-0.785030,-4.183402,-2.034320;;, + 33;3;-0.785030,-4.183402,-2.034320;;, + 34;3;-0.785030,-4.183402,-2.034320;;, + 35;3;-0.785030,-4.183402,-2.034320;;, + 41;3;-0.785030,-4.183402,-2.034320;;, + 43;3;-0.785030,-4.183402,-2.034320;;, + 50;3;-0.785030,-4.183402,-2.034320;;, + 53;3;-0.785030,-4.183402,-2.034320;;, + 55;3;-0.785030,-4.183402,-2.034320;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;0.971342,0.000000,0.000000,0.237686;;, + 1;4;0.971342,0.000000,0.000000,0.237686;;, + 2;4;0.971342,0.000000,0.000000,0.237686;;, + 3;4;0.971342,0.000000,0.000000,0.237686;;, + 4;4;0.971342,0.000000,0.000000,0.237686;;, + 5;4;0.971342,0.000000,0.000000,0.237686;;, + 12;4;0.971342,0.000000,0.000000,0.237686;;, + 14;4;0.971342,0.000000,0.000000,0.237686;;, + 15;4;0.971342,0.000000,0.000000,0.237686;;, + 16;4;0.971342,0.000000,0.000000,0.237686;;, + 17;4;0.971342,0.000000,0.000000,0.237686;;, + 18;4;0.971342,0.000000,0.000000,0.237686;;, + 19;4;0.971342,0.000000,0.000000,0.237686;;, + 20;4;0.971342,0.000000,0.000000,0.237686;;, + 27;4;0.971342,0.000000,0.000000,0.237686;;, + 33;4;0.971342,0.000000,0.000000,0.237686;;, + 34;4;0.971342,0.000000,0.000000,0.237686;;, + 35;4;0.971342,0.000000,0.000000,0.237686;;, + 41;4;0.971342,0.000000,0.000000,0.237686;;, + 43;4;0.971342,0.000000,0.000000,0.237686;;, + 50;4;0.971342,0.000000,0.000000,0.237686;;, + 53;4;0.971342,0.000000,0.000000,0.237686;;, + 55;4;0.971342,0.000000,0.000000,0.237686;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation Joint29Animation + { + {Joint29} + + AnimationKey + { + 2; + 23; + 0;3;0.261676,-2.483894,0.000000;;, + 1;3;0.261676,-2.483894,0.000000;;, + 2;3;0.261676,-2.483894,0.000000;;, + 3;3;0.261676,-2.483894,0.000000;;, + 4;3;0.261676,-2.483894,0.000000;;, + 5;3;0.261676,-2.483894,0.000000;;, + 12;3;0.261676,-2.483894,0.000000;;, + 14;3;0.261676,-2.483894,0.000000;;, + 15;3;0.261676,-2.483894,0.000000;;, + 16;3;0.261676,-2.483894,0.000000;;, + 17;3;0.261676,-2.483894,0.000000;;, + 18;3;0.261676,-2.483894,0.000000;;, + 19;3;0.261676,-2.483894,0.000000;;, + 20;3;0.261676,-2.483894,0.000000;;, + 27;3;0.261676,-2.483894,0.000000;;, + 33;3;0.261676,-2.483894,0.000000;;, + 34;3;0.261676,-2.483894,0.000000;;, + 35;3;0.261676,-2.483894,0.000000;;, + 41;3;0.261676,-2.483894,0.000000;;, + 43;3;0.261676,-2.483894,0.000000;;, + 50;3;0.261676,-2.483894,0.000000;;, + 53;3;0.261676,-2.483894,0.000000;;, + 55;3;0.261676,-2.483894,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation weaponAnimation + { + {weapon} + + AnimationKey + { + 2; + 23; + 0;3;1.700897,-4.837056,0.000000;;, + 1;3;1.700897,-4.837056,0.000000;;, + 2;3;1.700897,-4.837056,0.000000;;, + 3;3;1.700897,-4.837056,0.000000;;, + 4;3;1.700897,-4.837056,0.000000;;, + 5;3;1.700897,-4.837056,0.000000;;, + 12;3;1.700897,-4.837056,0.000000;;, + 14;3;1.700897,-4.837056,0.000000;;, + 15;3;1.700897,-4.837056,0.000000;;, + 16;3;1.700897,-4.837056,0.000000;;, + 17;3;1.700897,-4.837056,0.000000;;, + 18;3;1.700897,-4.837056,0.000000;;, + 19;3;1.700897,-4.837056,0.000000;;, + 20;3;1.700897,-4.837056,0.000000;;, + 27;3;1.700897,-4.837056,0.000000;;, + 33;3;1.700897,-4.837056,0.000000;;, + 34;3;1.700897,-4.837056,0.000000;;, + 35;3;1.700897,-4.837056,0.000000;;, + 41;3;1.700897,-4.837056,0.000000;;, + 43;3;1.700897,-4.837056,0.000000;;, + 50;3;1.700897,-4.837056,0.000000;;, + 53;3;1.700897,-4.837056,0.000000;;, + 55;3;1.700897,-4.837056,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;0.999743,0.021683,0.006609,-0.000572;;, + 3;4;0.998794,0.046948,0.014309,-0.001238;;, + 4;4;0.997432,0.068488,0.020874,-0.001806;;, + 5;4;0.997432,0.068488,0.020874,-0.001806;;, + 12;4;0.997432,0.068488,0.020874,-0.001806;;, + 14;4;0.997432,0.068488,0.020874,-0.001806;;, + 15;4;0.997432,0.068488,0.020874,-0.001806;;, + 16;4;0.998482,0.052668,0.016052,-0.001389;;, + 17;4;0.999355,0.034337,0.010465,-0.000906;;, + 18;4;0.999866,0.015644,0.004768,-0.000413;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;0.991577,-0.013382,0.128747,-0.004423;;, + 43;4;0.988533,-0.009191,0.150627,-0.005432;;, + 50;4;0.995744,0.045103,0.080265,-0.004060;;, + 53;4;0.999255,0.021677,0.031875,-0.001700;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation endAnimation + { + {end} + + AnimationKey + { + 2; + 23; + 0;3;0.179647,0.498486,-36.421711;;, + 1;3;0.179647,0.498486,-36.421711;;, + 2;3;0.179647,0.498486,-36.421711;;, + 3;3;0.179647,0.498486,-36.421711;;, + 4;3;0.179647,0.498486,-36.421711;;, + 5;3;0.179647,0.498486,-36.421711;;, + 12;3;0.179647,0.498486,-36.421711;;, + 14;3;0.179647,0.498486,-36.421711;;, + 15;3;0.179647,0.498486,-36.421711;;, + 16;3;0.179647,0.498486,-36.421711;;, + 17;3;0.179647,0.498486,-36.421711;;, + 18;3;0.179647,0.498486,-36.421711;;, + 19;3;0.179647,0.498486,-36.421711;;, + 20;3;0.179647,0.498486,-36.421711;;, + 27;3;0.179647,0.498486,-36.421711;;, + 33;3;0.179647,0.498486,-36.421711;;, + 34;3;0.179647,0.498486,-36.421711;;, + 35;3;0.179647,0.498486,-36.421711;;, + 41;3;0.179647,0.498486,-36.421711;;, + 43;3;0.179647,0.498486,-36.421711;;, + 50;3;0.179647,0.498486,-36.421711;;, + 53;3;0.179647,0.498486,-36.421711;;, + 55;3;0.179647,0.498486,-36.421711;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } + + Animation hitAnimation + { + {hit} + + AnimationKey + { + 2; + 23; + 0;3;9.751877,-17.324219,-0.896412;;, + 1;3;9.751877,-17.324219,-0.896412;;, + 2;3;9.751877,-17.324219,-0.896412;;, + 3;3;9.751877,-17.324219,-0.896412;;, + 4;3;9.751877,-17.324219,-0.896412;;, + 5;3;9.751877,-17.324219,-0.896412;;, + 12;3;9.751877,-17.324219,-0.896412;;, + 14;3;9.751877,-17.324219,-0.896412;;, + 15;3;9.751877,-17.324219,-0.896412;;, + 16;3;9.751877,-17.324219,-0.896412;;, + 17;3;9.751877,-17.324219,-0.896412;;, + 18;3;9.751877,-17.324219,-0.896412;;, + 19;3;9.751877,-17.324219,-0.896412;;, + 20;3;9.751877,-17.324219,-0.896412;;, + 27;3;9.751877,-17.324219,-0.896412;;, + 33;3;9.751877,-17.324219,-0.896412;;, + 34;3;9.751877,-17.324219,-0.896412;;, + 35;3;9.751877,-17.324219,-0.896412;;, + 41;3;9.751877,-17.324219,-0.896412;;, + 43;3;9.751877,-17.324219,-0.896412;;, + 50;3;9.751877,-17.324219,-0.896412;;, + 53;3;9.751877,-17.324219,-0.896412;;, + 55;3;9.751877,-17.324219,-0.896412;;; + } + + AnimationOptions + { + 1; + 1; + } + + AnimationKey + { + 0; + 23; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationOptions + { + 1; + 1; + } + } +} diff --git a/media/earth.jpg b/media/earth.jpg new file mode 100644 index 00000000..df0e9aae Binary files /dev/null and b/media/earth.jpg differ diff --git a/media/earth.x b/media/earth.x new file mode 100644 index 00000000..01f2827e --- /dev/null +++ b/media/earth.x @@ -0,0 +1,20711 @@ +xof 0303txt 0032 + +Frame Frame_SCENE_ROOT { + + + FrameTransformMatrix { + 1.000000,0.000000,0.000000,0.000000,0.000000,1.000000,0.000000,0.000000,0.000000,0.000000,1.000000,0.000000,0.000000,0.000000,0.000000,1.000000;; + } + + Frame Frame1_sphere_lwo_layer1 { + + + FrameTransformMatrix { + 1.000000,0.000000,0.000000,0.000000,0.000000,1.000000,0.000000,0.000000,0.000000,0.000000,1.000000,0.000000,0.000000,0.000000,0.000000,1.000000;; + } + + Mesh Mesh_sphere_lwo_Layer1 { + 2307; + -0.032702;0.997859;-0.056641;, + -0.039815;0.997859;-0.051888;, + 0.000000;1.000000;0.000000;, + -0.065263;0.991445;-0.113039;, + -0.079459;0.991445;-0.103553;, + -0.046247;0.997859;-0.046247;, + 0.000000;1.000000;0.000000;, + -0.025029;0.997859;-0.060425;, + -0.049950;0.991445;-0.120590;, + -0.074658;0.980785;-0.180240;, + -0.097545;0.980785;-0.168953;, + -0.118763;0.980785;-0.154776;, + -0.092296;0.991445;-0.092296;, + -0.016928;0.997859;-0.063175;, + -0.033783;0.991445;-0.126079;, + -0.050493;0.980785;-0.188443;, + -0.066987;0.965926;-0.250000;, + -0.099046;0.965926;-0.239118;, + -0.129410;0.965926;-0.224144;, + -0.008537;0.997859;-0.064844;, + -0.017037;0.991445;-0.129410;, + -0.025464;0.980785;-0.193421;, + -0.033783;0.965926;-0.256605;, + -0.041956;0.946930;-0.318689;, + -0.083195;0.946930;-0.310487;, + 0.000000;0.997859;-0.065403;, + 0.000000;0.991445;-0.130526;, + 0.000000;0.980785;-0.195090;, + 0.000000;0.965926;-0.258819;, + 0.000000;0.946930;-0.321439;, + 0.008537;0.997859;-0.064844;, + 0.017037;0.991445;-0.129410;, + 0.025464;0.980785;-0.193421;, + 0.033783;0.965926;-0.256605;, + 0.041956;0.946930;-0.318689;, + 0.000000;0.923880;-0.382683;, + 0.016928;0.997859;-0.063175;, + 0.033783;0.991445;-0.126079;, + 0.050493;0.980785;-0.188443;, + 0.066987;0.965926;-0.250000;, + 0.083195;0.946930;-0.310487;, + 0.049950;0.923880;-0.379410;, + 0.025029;0.997859;-0.060425;, + 0.049950;0.991445;-0.120590;, + 0.074658;0.980785;-0.180240;, + 0.099046;0.965926;-0.239118;, + 0.123010;0.946930;-0.296971;, + 0.099046;0.923880;-0.369644;, + 0.032702;0.997859;-0.056641;, + 0.065263;0.991445;-0.113039;, + 0.097545;0.980785;-0.168953;, + 0.129410;0.965926;-0.224144;, + 0.160720;0.946930;-0.278375;, + 0.146447;0.923880;-0.353553;, + 0.039815;0.997859;-0.051888;, + 0.079459;0.991445;-0.103553;, + 0.118763;0.980785;-0.154776;, + 0.157559;0.965926;-0.205335;, + 0.195680;0.946930;-0.255015;, + 0.191342;0.923880;-0.331414;, + 0.046247;0.997859;-0.046247;, + 0.092296;0.991445;-0.092296;, + 0.137950;0.980785;-0.137950;, + 0.183013;0.965926;-0.183013;, + 0.227292;0.946930;-0.227292;, + 0.232963;0.923880;-0.303603;, + 0.051888;0.997859;-0.039815;, + 0.103553;0.991445;-0.079459;, + 0.154776;0.980785;-0.118763;, + 0.205335;0.965926;-0.157559;, + 0.255015;0.946930;-0.195680;, + 0.270598;0.923880;-0.270598;, + 0.056641;0.997859;-0.032702;, + 0.113039;0.991445;-0.065263;, + 0.168953;0.980785;-0.097545;, + 0.224144;0.965926;-0.129410;, + 0.278375;0.946930;-0.160720;, + 0.303603;0.923880;-0.232963;, + 0.060425;0.997859;-0.025029;, + 0.120590;0.991445;-0.049950;, + 0.180240;0.980785;-0.074658;, + 0.239118;0.965926;-0.099046;, + 0.296971;0.946930;-0.123010;, + 0.331414;0.923880;-0.191342;, + 0.063175;0.997859;-0.016928;, + 0.126079;0.991445;-0.033783;, + 0.188443;0.980785;-0.050493;, + 0.250000;0.965926;-0.066987;, + 0.310487;0.946930;-0.083195;, + 0.353553;0.923880;-0.146447;, + 0.064844;0.997859;-0.008537;, + 0.129410;0.991445;-0.017037;, + 0.193421;0.980785;-0.025464;, + 0.256605;0.965926;-0.033783;, + 0.318689;0.946930;-0.041956;, + 0.369644;0.923880;-0.099046;, + 0.065403;0.997859;0.000000;, + 0.130526;0.991445;0.000000;, + 0.195090;0.980785;0.000000;, + 0.258819;0.965926;0.000000;, + 0.321439;0.946930;0.000000;, + 0.379410;0.923880;-0.049950;, + 0.064844;0.997859;0.008537;, + 0.129410;0.991445;0.017037;, + 0.193421;0.980785;0.025464;, + 0.256605;0.965926;0.033783;, + 0.318689;0.946930;0.041956;, + 0.382683;0.923880;0.000000;, + 0.063175;0.997859;0.016928;, + 0.126079;0.991445;0.033783;, + 0.188443;0.980785;0.050493;, + 0.250000;0.965926;0.066987;, + 0.310487;0.946930;0.083195;, + 0.379410;0.923880;0.049950;, + 0.060425;0.997859;0.025029;, + 0.120590;0.991445;0.049950;, + 0.180240;0.980785;0.074658;, + 0.239118;0.965926;0.099046;, + 0.296971;0.946930;0.123010;, + 0.369644;0.923880;0.099046;, + 0.056641;0.997859;0.032702;, + 0.113039;0.991445;0.065263;, + 0.168953;0.980785;0.097545;, + 0.224144;0.965926;0.129410;, + 0.278375;0.946930;0.160720;, + 0.353553;0.923880;0.146447;, + 0.051888;0.997859;0.039815;, + 0.103553;0.991445;0.079459;, + 0.154776;0.980785;0.118763;, + 0.205335;0.965926;0.157559;, + 0.255015;0.946930;0.195680;, + 0.331414;0.923880;0.191342;, + 0.046247;0.997859;0.046247;, + 0.092296;0.991445;0.092296;, + 0.137950;0.980785;0.137950;, + 0.183013;0.965926;0.183013;, + 0.227292;0.946930;0.227292;, + 0.303603;0.923880;0.232963;, + 0.039815;0.997859;0.051888;, + 0.079459;0.991445;0.103553;, + 0.118763;0.980785;0.154776;, + 0.157559;0.965926;0.205335;, + 0.195680;0.946930;0.255015;, + 0.270598;0.923880;0.270598;, + 0.032702;0.997859;0.056641;, + 0.065263;0.991445;0.113039;, + 0.097545;0.980785;0.168953;, + 0.129410;0.965926;0.224144;, + 0.160720;0.946930;0.278375;, + 0.232963;0.923880;0.303603;, + 0.025029;0.997859;0.060425;, + 0.049950;0.991445;0.120590;, + 0.074658;0.980785;0.180240;, + 0.099046;0.965926;0.239118;, + 0.123010;0.946930;0.296971;, + 0.191342;0.923880;0.331414;, + 0.016928;0.997859;0.063175;, + 0.033783;0.991445;0.126079;, + 0.050493;0.980785;0.188443;, + 0.066987;0.965926;0.250000;, + 0.083195;0.946930;0.310487;, + 0.146447;0.923880;0.353553;, + 0.008537;0.997859;0.064844;, + 0.017037;0.991445;0.129410;, + 0.025464;0.980785;0.193421;, + 0.033783;0.965926;0.256605;, + 0.041956;0.946930;0.318689;, + 0.099046;0.923880;0.369644;, + 0.000000;0.997859;0.065403;, + 0.000000;0.991445;0.130526;, + 0.000000;0.980785;0.195090;, + 0.000000;0.965926;0.258819;, + 0.000000;0.946930;0.321439;, + 0.049950;0.923880;0.379410;, + 0.114473;0.896873;0.427218;, + 0.169257;0.896873;0.408621;, + 0.221144;0.896873;0.383033;, + 0.000000;0.923880;0.382683;, + 0.057730;0.896873;0.438505;, + 0.129410;0.866025;0.482963;, + 0.191342;0.866025;0.461940;, + 0.250000;0.866025;0.433013;, + 0.304381;0.866025;0.396677;, + 0.269248;0.896873;0.350891;, + 0.000000;0.896873;0.442289;, + 0.065263;0.866025;0.495722;, + 0.143792;0.831470;0.536640;, + 0.212608;0.831470;0.513280;, + 0.277785;0.831470;0.481138;, + 0.338210;0.831470;0.440764;, + 0.000000;0.866025;0.500000;, + 0.072516;0.831470;0.550817;, + 0.157559;0.793353;0.588018;, + 0.232963;0.793353;0.562422;, + 0.304381;0.793353;0.527203;, + 0.370590;0.793353;0.482963;, + 0.000000;0.831470;0.555570;, + 0.079459;0.793353;0.603553;, + 0.170651;0.751840;0.636879;, + 0.252321;0.751840;0.609156;, + 0.329673;0.751840;0.571010;, + 0.401384;0.751840;0.523094;, + 0.000000;0.793353;0.608761;, + 0.086062;0.751840;0.653705;, + 0.183013;0.707107;0.683013;, + 0.270598;0.707107;0.653282;, + 0.353553;0.707107;0.612372;, + 0.430459;0.707107;0.560986;, + 0.000000;0.751840;0.659346;, + 0.092296;0.707107;0.701057;, + 0.194590;0.659346;0.726222;, + 0.287717;0.659346;0.694609;, + 0.375920;0.659346;0.651112;, + 0.457691;0.659346;0.596475;, + 0.000000;0.707107;0.707107;, + 0.098135;0.659346;0.745408;, + 0.205335;0.608761;0.766320;, + 0.303603;0.608761;0.732963;, + 0.396677;0.608761;0.687064;, + 0.482963;0.608761;0.629410;, + 0.000000;0.659346;0.751840;, + 0.103553;0.608761;0.786566;, + 0.215200;0.555570;0.803138;, + 0.318190;0.555570;0.768178;, + 0.415735;0.555570;0.720074;, + 0.506167;0.555570;0.659649;, + 0.000000;0.608761;0.793353;, + 0.108529;0.555570;0.824356;, + 0.224144;0.500000;0.836516;, + 0.331414;0.500000;0.800103;, + 0.433013;0.500000;0.750000;, + 0.527203;0.500000;0.687064;, + 0.000000;0.555570;0.831470;, + 0.113039;0.500000;0.858616;, + 0.232128;0.442289;0.866313;, + 0.343218;0.442289;0.828602;, + 0.448436;0.442289;0.776715;, + 0.545982;0.442289;0.711537;, + 0.000000;0.500000;0.866025;, + 0.117065;0.442289;0.889200;, + 0.239118;0.382683;0.892399;, + 0.353553;0.382683;0.853553;, + 0.461940;0.382683;0.800103;, + 0.562422;0.382683;0.732963;, + 0.000000;0.442289;0.896873;, + 0.120590;0.382683;0.915976;, + 0.245084;0.321439;0.914664;, + 0.362374;0.321439;0.874849;, + 0.473465;0.321439;0.820066;, + 0.576455;0.321439;0.751250;, + 0.000000;0.382683;0.923880;, + 0.123599;0.321439;0.938829;, + 0.250000;0.258819;0.933013;, + 0.369644;0.258819;0.892399;, + 0.482963;0.258819;0.836516;, + 0.588018;0.258819;0.766320;, + 0.000000;0.321439;0.946930;, + 0.126079;0.258819;0.957662;, + 0.253846;0.195090;0.947366;, + 0.375330;0.195090;0.906127;, + 0.490393;0.195090;0.849385;, + 0.597064;0.195090;0.778109;, + 0.000000;0.258819;0.965926;, + 0.128018;0.195090;0.972395;, + 0.256605;0.130526;0.957662;, + 0.379410;0.130526;0.915976;, + 0.495722;0.130526;0.858616;, + 0.603553;0.130526;0.786566;, + 0.000000;0.195090;0.980785;, + 0.129410;0.130526;0.982963;, + 0.258265;0.065403;0.963858;, + 0.381864;0.065403;0.921901;, + 0.498929;0.065403;0.864171;, + 0.607458;0.065403;0.791655;, + 0.000000;0.130526;0.991445;, + 0.130247;0.065403;0.989322;, + 0.258819;0.000000;0.965926;, + 0.382683;0.000000;0.923880;, + 0.500000;0.000000;0.866025;, + 0.608761;0.000000;0.793353;, + 0.000000;0.065403;0.997859;, + 0.130526;0.000000;0.991445;, + 0.258265;-0.065403;0.963858;, + 0.381864;-0.065403;0.921901;, + 0.498929;-0.065403;0.864171;, + 0.607458;-0.065403;0.791655;, + 0.000000;0.000000;1.000000;, + 0.130247;-0.065403;0.989322;, + 0.256605;-0.130526;0.957662;, + 0.379410;-0.130526;0.915976;, + 0.495722;-0.130526;0.858616;, + 0.603553;-0.130526;0.786566;, + 0.000000;-0.065403;0.997859;, + 0.129410;-0.130526;0.982963;, + 0.253846;-0.195090;0.947366;, + 0.375330;-0.195090;0.906127;, + 0.490393;-0.195090;0.849385;, + 0.597064;-0.195090;0.778109;, + 0.000000;-0.130526;0.991445;, + 0.128018;-0.195090;0.972395;, + 0.250000;-0.258819;0.933013;, + 0.369644;-0.258819;0.892399;, + 0.482963;-0.258819;0.836516;, + 0.588018;-0.258819;0.766320;, + 0.000000;-0.195090;0.980785;, + 0.126079;-0.258819;0.957662;, + 0.245084;-0.321439;0.914664;, + 0.362374;-0.321439;0.874849;, + 0.473465;-0.321439;0.820066;, + 0.576455;-0.321439;0.751250;, + 0.000000;-0.258819;0.965926;, + 0.123599;-0.321439;0.938829;, + 0.239118;-0.382683;0.892399;, + 0.353553;-0.382683;0.853553;, + 0.461940;-0.382683;0.800103;, + 0.562422;-0.382683;0.732963;, + 0.000000;-0.321439;0.946930;, + 0.120590;-0.382683;0.915976;, + 0.232128;-0.442289;0.866313;, + 0.343218;-0.442289;0.828602;, + 0.448436;-0.442289;0.776715;, + 0.545982;-0.442289;0.711537;, + 0.000000;-0.382683;0.923880;, + 0.117065;-0.442289;0.889200;, + 0.224144;-0.500000;0.836516;, + 0.331414;-0.500000;0.800103;, + 0.433013;-0.500000;0.750000;, + 0.527203;-0.500000;0.687064;, + 0.000000;-0.442289;0.896873;, + 0.113039;-0.500000;0.858616;, + 0.215200;-0.555570;0.803138;, + 0.318190;-0.555570;0.768178;, + 0.415735;-0.555570;0.720074;, + 0.506167;-0.555570;0.659649;, + 0.000000;-0.500000;0.866025;, + 0.108529;-0.555570;0.824356;, + 0.205335;-0.608761;0.766320;, + 0.303603;-0.608761;0.732963;, + 0.396677;-0.608761;0.687064;, + 0.482963;-0.608761;0.629410;, + 0.000000;-0.555570;0.831470;, + 0.103553;-0.608761;0.786566;, + 0.194590;-0.659346;0.726222;, + 0.287717;-0.659346;0.694609;, + 0.375920;-0.659346;0.651112;, + 0.457691;-0.659346;0.596475;, + 0.000000;-0.608761;0.793353;, + 0.098135;-0.659346;0.745408;, + 0.183013;-0.707107;0.683013;, + 0.270598;-0.707107;0.653282;, + 0.353553;-0.707107;0.612372;, + 0.430459;-0.707107;0.560986;, + 0.000000;-0.659346;0.751840;, + 0.092296;-0.707107;0.701057;, + 0.170651;-0.751840;0.636879;, + 0.252321;-0.751840;0.609156;, + 0.329673;-0.751840;0.571010;, + 0.401384;-0.751840;0.523094;, + 0.000000;-0.707107;0.707107;, + 0.086062;-0.751840;0.653705;, + 0.157559;-0.793353;0.588018;, + 0.232963;-0.793353;0.562422;, + 0.304381;-0.793353;0.527203;, + 0.370590;-0.793353;0.482963;, + 0.000000;-0.751840;0.659346;, + 0.079459;-0.793353;0.603553;, + 0.143792;-0.831470;0.536640;, + 0.212608;-0.831470;0.513280;, + 0.277785;-0.831470;0.481138;, + 0.338210;-0.831470;0.440764;, + 0.000000;-0.793353;0.608761;, + 0.072516;-0.831470;0.550817;, + 0.129410;-0.866025;0.482963;, + 0.191342;-0.866025;0.461940;, + 0.250000;-0.866025;0.433013;, + 0.304381;-0.866025;0.396677;, + 0.000000;-0.831470;0.555570;, + 0.065263;-0.866025;0.495722;, + 0.114473;-0.896873;0.427218;, + 0.169257;-0.896873;0.408621;, + 0.221144;-0.896873;0.383033;, + 0.269248;-0.896873;0.350891;, + 0.000000;-0.866025;0.500000;, + 0.057730;-0.896873;0.438505;, + 0.099046;-0.923880;0.369644;, + 0.146447;-0.923880;0.353553;, + 0.191342;-0.923880;0.331414;, + 0.232963;-0.923880;0.303603;, + 0.000000;-0.896873;0.442289;, + 0.049950;-0.923880;0.379410;, + 0.083195;-0.946930;0.310487;, + 0.123010;-0.946930;0.296971;, + 0.160720;-0.946930;0.278375;, + 0.195680;-0.946930;0.255015;, + 0.000000;-0.923880;0.382683;, + 0.041956;-0.946930;0.318689;, + 0.066987;-0.965926;0.250000;, + 0.099046;-0.965926;0.239118;, + 0.129410;-0.965926;0.224144;, + 0.157559;-0.965926;0.205335;, + 0.000000;-0.946930;0.321439;, + 0.033783;-0.965926;0.256605;, + 0.050493;-0.980785;0.188443;, + 0.074658;-0.980785;0.180240;, + 0.097545;-0.980785;0.168953;, + 0.118763;-0.980785;0.154776;, + 0.000000;-0.965926;0.258819;, + 0.025464;-0.980785;0.193421;, + 0.033783;-0.991445;0.126079;, + 0.049950;-0.991445;0.120590;, + 0.065263;-0.991445;0.113039;, + 0.079459;-0.991445;0.103553;, + 0.000000;-0.980785;0.195090;, + 0.017037;-0.991445;0.129410;, + 0.016928;-0.997859;0.063175;, + 0.025029;-0.997859;0.060425;, + 0.032702;-0.997859;0.056641;, + 0.039815;-0.997859;0.051888;, + 0.000000;-0.991445;0.130526;, + 0.008537;-0.997859;0.064844;, + 0.000000;-1.000000;0.000000;, + 0.046247;-0.997859;0.046247;, + 0.092296;-0.991445;0.092296;, + 0.000000;-0.997859;0.065403;, + 0.137950;-0.980785;0.137950;, + 0.103553;-0.991445;0.079459;, + 0.154776;-0.980785;0.118763;, + 0.183013;-0.965926;0.183013;, + 0.051888;-0.997859;0.039815;, + 0.056641;-0.997859;0.032702;, + 0.113039;-0.991445;0.065263;, + 0.168953;-0.980785;0.097545;, + 0.205335;-0.965926;0.157559;, + 0.060425;-0.997859;0.025029;, + 0.120590;-0.991445;0.049950;, + 0.180240;-0.980785;0.074658;, + 0.224144;-0.965926;0.129410;, + 0.255015;-0.946930;0.195680;, + 0.227292;-0.946930;0.227292;, + 0.063175;-0.997859;0.016928;, + 0.126079;-0.991445;0.033783;, + 0.188443;-0.980785;0.050493;, + 0.239118;-0.965926;0.099046;, + 0.278375;-0.946930;0.160720;, + 0.064844;-0.997859;0.008537;, + 0.129410;-0.991445;0.017037;, + 0.193421;-0.980785;0.025464;, + 0.250000;-0.965926;0.066987;, + 0.296971;-0.946930;0.123010;, + 0.065403;-0.997859;0.000000;, + 0.130526;-0.991445;0.000000;, + 0.195090;-0.980785;0.000000;, + 0.256605;-0.965926;0.033783;, + 0.310487;-0.946930;0.083195;, + 0.064844;-0.997859;-0.008537;, + 0.129410;-0.991445;-0.017037;, + 0.193421;-0.980785;-0.025464;, + 0.258819;-0.965926;0.000000;, + 0.318689;-0.946930;0.041956;, + 0.063175;-0.997859;-0.016928;, + 0.126079;-0.991445;-0.033783;, + 0.188443;-0.980785;-0.050493;, + 0.256605;-0.965926;-0.033783;, + 0.321439;-0.946930;0.000000;, + 0.060425;-0.997859;-0.025029;, + 0.120590;-0.991445;-0.049950;, + 0.180240;-0.980785;-0.074658;, + 0.250000;-0.965926;-0.066987;, + 0.318689;-0.946930;-0.041956;, + 0.056641;-0.997859;-0.032702;, + 0.113039;-0.991445;-0.065263;, + 0.168953;-0.980785;-0.097545;, + 0.239118;-0.965926;-0.099046;, + 0.310487;-0.946930;-0.083195;, + 0.051888;-0.997859;-0.039815;, + 0.103553;-0.991445;-0.079459;, + 0.154776;-0.980785;-0.118763;, + 0.224144;-0.965926;-0.129410;, + 0.296971;-0.946930;-0.123010;, + 0.046247;-0.997859;-0.046247;, + 0.092296;-0.991445;-0.092296;, + 0.137950;-0.980785;-0.137950;, + 0.205335;-0.965926;-0.157559;, + 0.278375;-0.946930;-0.160720;, + 0.039815;-0.997859;-0.051888;, + 0.079459;-0.991445;-0.103553;, + 0.118763;-0.980785;-0.154776;, + 0.183013;-0.965926;-0.183013;, + 0.255015;-0.946930;-0.195680;, + 0.032702;-0.997859;-0.056641;, + 0.065263;-0.991445;-0.113039;, + 0.097545;-0.980785;-0.168953;, + 0.157559;-0.965926;-0.205335;, + 0.227292;-0.946930;-0.227292;, + 0.025029;-0.997859;-0.060425;, + 0.049950;-0.991445;-0.120590;, + 0.074658;-0.980785;-0.180240;, + 0.129410;-0.965926;-0.224144;, + 0.195680;-0.946930;-0.255015;, + 0.016928;-0.997859;-0.063175;, + 0.033783;-0.991445;-0.126079;, + 0.050493;-0.980785;-0.188443;, + 0.099046;-0.965926;-0.239118;, + 0.160720;-0.946930;-0.278375;, + 0.008537;-0.997859;-0.064844;, + 0.017037;-0.991445;-0.129410;, + 0.025464;-0.980785;-0.193421;, + 0.066987;-0.965926;-0.250000;, + 0.123010;-0.946930;-0.296971;, + 0.000000;-0.997859;-0.065403;, + 0.000000;-0.991445;-0.130526;, + 0.000000;-0.980785;-0.195090;, + 0.033783;-0.965926;-0.256605;, + 0.083195;-0.946930;-0.310487;, + 0.146447;-0.923880;-0.353553;, + 0.191342;-0.923880;-0.331414;, + -0.017037;-0.991445;-0.129410;, + -0.025464;-0.980785;-0.193421;, + -0.033783;-0.965926;-0.256605;, + 0.000000;-0.965926;-0.258819;, + 0.041956;-0.946930;-0.318689;, + 0.099046;-0.923880;-0.369644;, + -0.008537;-0.997859;-0.064844;, + -0.033783;-0.991445;-0.126079;, + -0.050493;-0.980785;-0.188443;, + -0.066987;-0.965926;-0.250000;, + -0.083195;-0.946930;-0.310487;, + -0.041956;-0.946930;-0.318689;, + 0.000000;-1.000000;0.000000;, + -0.016928;-0.997859;-0.063175;, + -0.049950;-0.991445;-0.120590;, + -0.074658;-0.980785;-0.180240;, + -0.099046;-0.965926;-0.239118;, + -0.123010;-0.946930;-0.296971;, + -0.025029;-0.997859;-0.060425;, + -0.065263;-0.991445;-0.113039;, + -0.097545;-0.980785;-0.168953;, + -0.129410;-0.965926;-0.224144;, + -0.160720;-0.946930;-0.278375;, + -0.032702;-0.997859;-0.056641;, + -0.079459;-0.991445;-0.103553;, + -0.118763;-0.980785;-0.154776;, + -0.157559;-0.965926;-0.205335;, + -0.195680;-0.946930;-0.255015;, + -0.039815;-0.997859;-0.051888;, + -0.092296;-0.991445;-0.092296;, + -0.137950;-0.980785;-0.137950;, + -0.183013;-0.965926;-0.183013;, + -0.227292;-0.946930;-0.227292;, + -0.046247;-0.997859;-0.046247;, + -0.103553;-0.991445;-0.079459;, + -0.154776;-0.980785;-0.118763;, + -0.205335;-0.965926;-0.157559;, + -0.255015;-0.946930;-0.195680;, + -0.051888;-0.997859;-0.039815;, + -0.113039;-0.991445;-0.065263;, + -0.168953;-0.980785;-0.097545;, + -0.224144;-0.965926;-0.129410;, + -0.278375;-0.946930;-0.160720;, + -0.056641;-0.997859;-0.032702;, + -0.120590;-0.991445;-0.049950;, + -0.180240;-0.980785;-0.074658;, + -0.239118;-0.965926;-0.099046;, + -0.296971;-0.946930;-0.123010;, + -0.060425;-0.997859;-0.025029;, + -0.126079;-0.991445;-0.033783;, + -0.188443;-0.980785;-0.050493;, + -0.250000;-0.965926;-0.066987;, + -0.310487;-0.946930;-0.083195;, + -0.063175;-0.997859;-0.016928;, + -0.129410;-0.991445;-0.017037;, + -0.193421;-0.980785;-0.025464;, + -0.256605;-0.965926;-0.033783;, + -0.318689;-0.946930;-0.041956;, + -0.064844;-0.997859;-0.008537;, + -0.130526;-0.991445;0.000000;, + -0.195090;-0.980785;0.000000;, + -0.258819;-0.965926;0.000000;, + -0.321439;-0.946930;0.000000;, + -0.065403;-0.997859;0.000000;, + -0.129410;-0.991445;0.017037;, + -0.193421;-0.980785;0.025464;, + -0.256605;-0.965926;0.033783;, + -0.318689;-0.946930;0.041956;, + -0.064844;-0.997859;0.008537;, + -0.126079;-0.991445;0.033783;, + -0.188443;-0.980785;0.050493;, + -0.250000;-0.965926;0.066987;, + -0.310487;-0.946930;0.083195;, + -0.063175;-0.997859;0.016928;, + -0.120590;-0.991445;0.049950;, + -0.180240;-0.980785;0.074658;, + -0.239118;-0.965926;0.099046;, + -0.296971;-0.946930;0.123010;, + -0.060425;-0.997859;0.025029;, + -0.113039;-0.991445;0.065263;, + -0.168953;-0.980785;0.097545;, + -0.224144;-0.965926;0.129410;, + -0.278375;-0.946930;0.160720;, + -0.056641;-0.997859;0.032702;, + -0.103553;-0.991445;0.079459;, + -0.154776;-0.980785;0.118763;, + -0.205335;-0.965926;0.157559;, + -0.255015;-0.946930;0.195680;, + -0.051888;-0.997859;0.039815;, + -0.092296;-0.991445;0.092296;, + -0.137950;-0.980785;0.137950;, + -0.183013;-0.965926;0.183013;, + -0.227292;-0.946930;0.227292;, + -0.046247;-0.997859;0.046247;, + -0.079459;-0.991445;0.103553;, + -0.118763;-0.980785;0.154776;, + -0.157559;-0.965926;0.205335;, + -0.195680;-0.946930;0.255015;, + -0.039815;-0.997859;0.051888;, + -0.065263;-0.991445;0.113039;, + -0.097545;-0.980785;0.168953;, + -0.129410;-0.965926;0.224144;, + -0.160720;-0.946930;0.278375;, + -0.032702;-0.997859;0.056641;, + -0.049950;-0.991445;0.120590;, + -0.074658;-0.980785;0.180240;, + -0.099046;-0.965926;0.239118;, + -0.123010;-0.946930;0.296971;, + -0.025029;-0.997859;0.060425;, + -0.033783;-0.991445;0.126079;, + -0.050493;-0.980785;0.188443;, + -0.066987;-0.965926;0.250000;, + -0.083195;-0.946930;0.310487;, + -0.016928;-0.997859;0.063175;, + -0.017037;-0.991445;0.129410;, + -0.025464;-0.980785;0.193421;, + -0.033783;-0.965926;0.256605;, + -0.041956;-0.946930;0.318689;, + -0.008537;-0.997859;0.064844;, + 0.000000;-0.991445;0.130526;, + 0.000000;-0.980785;0.195090;, + 0.000000;-0.965926;0.258819;, + 0.000000;-0.946930;0.321439;, + 0.000000;-0.997859;0.065403;, + 0.000000;-0.923880;0.382683;, + -0.049950;-0.923880;0.379410;, + -0.099046;-0.923880;0.369644;, + -0.146447;-0.923880;0.353553;, + 0.000000;-0.896873;0.442289;, + -0.057730;-0.896873;0.438505;, + -0.114473;-0.896873;0.427218;, + -0.169257;-0.896873;0.408621;, + -0.191342;-0.923880;0.331414;, + -0.232963;-0.923880;0.303603;, + 0.000000;-0.866025;0.500000;, + -0.065263;-0.866025;0.495722;, + -0.129410;-0.866025;0.482963;, + -0.191342;-0.866025;0.461940;, + -0.221144;-0.896873;0.383033;, + -0.269248;-0.896873;0.350891;, + -0.270598;-0.923880;0.270598;, + 0.000000;-0.831470;0.555570;, + -0.072516;-0.831470;0.550817;, + -0.143792;-0.831470;0.536640;, + -0.212608;-0.831470;0.513280;, + -0.250000;-0.866025;0.433013;, + -0.304381;-0.866025;0.396677;, + -0.312745;-0.896873;0.312745;, + 0.000000;-0.793353;0.608761;, + -0.079459;-0.793353;0.603553;, + -0.157559;-0.793353;0.588018;, + -0.232963;-0.793353;0.562422;, + -0.277785;-0.831470;0.481138;, + -0.338210;-0.831470;0.440764;, + -0.353553;-0.866025;0.353553;, + 0.000000;-0.751840;0.659346;, + -0.086062;-0.751840;0.653705;, + -0.170651;-0.751840;0.636879;, + -0.252321;-0.751840;0.609156;, + -0.304381;-0.793353;0.527203;, + -0.370590;-0.793353;0.482963;, + -0.392847;-0.831470;0.392847;, + 0.000000;-0.707107;0.707107;, + -0.092296;-0.707107;0.701057;, + -0.183013;-0.707107;0.683013;, + -0.270598;-0.707107;0.653282;, + -0.329673;-0.751840;0.571010;, + -0.401384;-0.751840;0.523094;, + -0.430459;-0.793353;0.430459;, + 0.000000;-0.659346;0.751840;, + -0.098135;-0.659346;0.745408;, + -0.194590;-0.659346;0.726222;, + -0.287717;-0.659346;0.694609;, + -0.353553;-0.707107;0.612372;, + -0.430459;-0.707107;0.560986;, + -0.466228;-0.751840;0.466228;, + 0.000000;-0.608761;0.793353;, + -0.103553;-0.608761;0.786566;, + -0.205335;-0.608761;0.766320;, + -0.303603;-0.608761;0.732963;, + -0.375920;-0.659346;0.651112;, + -0.457691;-0.659346;0.596475;, + -0.500000;-0.707107;0.500000;, + 0.000000;-0.555570;0.831470;, + -0.108529;-0.555570;0.824356;, + -0.215200;-0.555570;0.803138;, + -0.318190;-0.555570;0.768178;, + -0.396677;-0.608761;0.687064;, + -0.482963;-0.608761;0.629410;, + -0.531631;-0.659346;0.531631;, + 0.000000;-0.500000;0.866025;, + -0.113039;-0.500000;0.858616;, + -0.224144;-0.500000;0.836516;, + -0.331414;-0.500000;0.800103;, + -0.415735;-0.555570;0.720074;, + -0.506167;-0.555570;0.659649;, + -0.560986;-0.608761;0.560986;, + 0.000000;-0.442289;0.896873;, + -0.117065;-0.442289;0.889200;, + -0.232128;-0.442289;0.866313;, + -0.343218;-0.442289;0.828602;, + -0.433013;-0.500000;0.750000;, + -0.527203;-0.500000;0.687064;, + -0.587938;-0.555570;0.587938;, + 0.000000;-0.382683;0.923880;, + -0.120590;-0.382683;0.915976;, + -0.239118;-0.382683;0.892399;, + -0.353553;-0.382683;0.853553;, + -0.448436;-0.442289;0.776715;, + -0.545982;-0.442289;0.711537;, + -0.612372;-0.500000;0.612372;, + 0.000000;-0.321439;0.946930;, + -0.123599;-0.321439;0.938829;, + -0.245084;-0.321439;0.914664;, + -0.362374;-0.321439;0.874849;, + -0.461940;-0.382683;0.800103;, + -0.562422;-0.382683;0.732963;, + -0.634185;-0.442289;0.634185;, + 0.000000;-0.258819;0.965926;, + -0.126079;-0.258819;0.957662;, + -0.250000;-0.258819;0.933013;, + -0.369644;-0.258819;0.892399;, + -0.473465;-0.321439;0.820066;, + -0.576455;-0.321439;0.751250;, + -0.653282;-0.382683;0.653282;, + 0.000000;-0.195090;0.980785;, + -0.128018;-0.195090;0.972395;, + -0.253846;-0.195090;0.947366;, + -0.375330;-0.195090;0.906127;, + -0.482963;-0.258819;0.836516;, + -0.588018;-0.258819;0.766320;, + -0.669581;-0.321439;0.669581;, + 0.000000;-0.130526;0.991445;, + -0.129410;-0.130526;0.982963;, + -0.256605;-0.130526;0.957662;, + -0.379410;-0.130526;0.915976;, + -0.490393;-0.195090;0.849385;, + -0.597064;-0.195090;0.778109;, + -0.683013;-0.258819;0.683013;, + 0.000000;-0.065403;0.997859;, + -0.130247;-0.065403;0.989322;, + -0.258265;-0.065403;0.963858;, + -0.381864;-0.065403;0.921901;, + -0.495722;-0.130526;0.858616;, + -0.603553;-0.130526;0.786566;, + -0.693520;-0.195090;0.693520;, + 0.000000;0.000000;1.000000;, + -0.130526;0.000000;0.991445;, + -0.258819;0.000000;0.965926;, + -0.382683;0.000000;0.923880;, + -0.498929;-0.065403;0.864171;, + -0.607458;-0.065403;0.791655;, + -0.701057;-0.130526;0.701057;, + 0.000000;0.065403;0.997859;, + -0.130247;0.065403;0.989322;, + -0.258265;0.065403;0.963858;, + -0.381864;0.065403;0.921901;, + -0.500000;0.000000;0.866025;, + -0.608761;0.000000;0.793353;, + -0.705593;-0.065403;0.705593;, + 0.000000;0.130526;0.991445;, + -0.129410;0.130526;0.982963;, + -0.256605;0.130526;0.957662;, + -0.379410;0.130526;0.915976;, + -0.498929;0.065403;0.864171;, + -0.607458;0.065403;0.791655;, + -0.707107;0.000000;0.707107;, + 0.000000;0.195090;0.980785;, + -0.128018;0.195090;0.972395;, + -0.253846;0.195090;0.947366;, + -0.375330;0.195090;0.906127;, + -0.495722;0.130526;0.858616;, + -0.603553;0.130526;0.786566;, + -0.705593;0.065403;0.705593;, + 0.000000;0.258819;0.965926;, + -0.126079;0.258819;0.957662;, + -0.250000;0.258819;0.933013;, + -0.369644;0.258819;0.892399;, + -0.490393;0.195090;0.849385;, + -0.597064;0.195090;0.778109;, + -0.701057;0.130526;0.701057;, + 0.000000;0.321439;0.946930;, + -0.123599;0.321439;0.938829;, + -0.245084;0.321439;0.914664;, + -0.362374;0.321439;0.874849;, + -0.482963;0.258819;0.836516;, + -0.588018;0.258819;0.766320;, + -0.693520;0.195090;0.693520;, + 0.000000;0.382683;0.923880;, + -0.120590;0.382683;0.915976;, + -0.239118;0.382683;0.892399;, + -0.353553;0.382683;0.853553;, + -0.473465;0.321439;0.820066;, + -0.576455;0.321439;0.751250;, + -0.683013;0.258819;0.683013;, + 0.000000;0.442289;0.896873;, + -0.117065;0.442289;0.889200;, + -0.232128;0.442289;0.866313;, + -0.343218;0.442289;0.828602;, + -0.461940;0.382683;0.800103;, + -0.562422;0.382683;0.732963;, + -0.669581;0.321439;0.669581;, + 0.000000;0.500000;0.866025;, + -0.113039;0.500000;0.858616;, + -0.224144;0.500000;0.836516;, + -0.331414;0.500000;0.800103;, + -0.448436;0.442289;0.776715;, + -0.545982;0.442289;0.711537;, + -0.653282;0.382683;0.653282;, + 0.000000;0.555570;0.831470;, + -0.108529;0.555570;0.824356;, + -0.215200;0.555570;0.803138;, + -0.318190;0.555570;0.768178;, + -0.433013;0.500000;0.750000;, + -0.527203;0.500000;0.687064;, + -0.634185;0.442289;0.634185;, + 0.000000;0.608761;0.793353;, + -0.103553;0.608761;0.786566;, + -0.205335;0.608761;0.766320;, + -0.303603;0.608761;0.732963;, + -0.415735;0.555570;0.720074;, + -0.506167;0.555570;0.659649;, + -0.612372;0.500000;0.612372;, + 0.000000;0.659346;0.751840;, + -0.098135;0.659346;0.745408;, + -0.194590;0.659346;0.726222;, + -0.287717;0.659346;0.694609;, + -0.396677;0.608761;0.687064;, + -0.482963;0.608761;0.629410;, + -0.587938;0.555570;0.587938;, + 0.000000;0.707107;0.707107;, + -0.092296;0.707107;0.701057;, + -0.183013;0.707107;0.683013;, + -0.270598;0.707107;0.653282;, + -0.375920;0.659346;0.651112;, + -0.457691;0.659346;0.596475;, + -0.560986;0.608761;0.560986;, + 0.000000;0.751840;0.659346;, + -0.086062;0.751840;0.653705;, + -0.170651;0.751840;0.636879;, + -0.252321;0.751840;0.609156;, + -0.353553;0.707107;0.612372;, + -0.430459;0.707107;0.560986;, + -0.531631;0.659346;0.531631;, + 0.000000;0.793353;0.608761;, + -0.079459;0.793353;0.603553;, + -0.157559;0.793353;0.588018;, + -0.232963;0.793353;0.562422;, + -0.329673;0.751840;0.571010;, + -0.401384;0.751840;0.523094;, + -0.500000;0.707107;0.500000;, + 0.000000;0.831470;0.555570;, + -0.072516;0.831470;0.550817;, + -0.143792;0.831470;0.536640;, + -0.212608;0.831470;0.513280;, + -0.304381;0.793353;0.527203;, + -0.370590;0.793353;0.482963;, + -0.466228;0.751840;0.466228;, + 0.000000;0.866025;0.500000;, + -0.065263;0.866025;0.495722;, + -0.129410;0.866025;0.482963;, + -0.191342;0.866025;0.461940;, + -0.277785;0.831470;0.481138;, + -0.338210;0.831470;0.440764;, + -0.430459;0.793353;0.430459;, + 0.000000;0.896873;0.442289;, + -0.057730;0.896873;0.438505;, + -0.114473;0.896873;0.427218;, + -0.169257;0.896873;0.408621;, + -0.250000;0.866025;0.433013;, + -0.304381;0.866025;0.396677;, + -0.392847;0.831470;0.392847;, + 0.000000;0.923880;0.382683;, + -0.049950;0.923880;0.379410;, + -0.099046;0.923880;0.369644;, + -0.146447;0.923880;0.353553;, + -0.221144;0.896873;0.383033;, + -0.269248;0.896873;0.350891;, + -0.353553;0.866025;0.353553;, + 0.000000;0.946930;0.321439;, + -0.041956;0.946930;0.318689;, + -0.083195;0.946930;0.310487;, + -0.123010;0.946930;0.296971;, + -0.191342;0.923880;0.331414;, + -0.232963;0.923880;0.303603;, + -0.312745;0.896873;0.312745;, + 0.000000;0.965926;0.258819;, + -0.033783;0.965926;0.256605;, + -0.066987;0.965926;0.250000;, + -0.099046;0.965926;0.239118;, + -0.160720;0.946930;0.278375;, + -0.195680;0.946930;0.255015;, + -0.270598;0.923880;0.270598;, + 0.000000;0.980785;0.195090;, + -0.025464;0.980785;0.193421;, + -0.050493;0.980785;0.188443;, + -0.074658;0.980785;0.180240;, + -0.129410;0.965926;0.224144;, + -0.157559;0.965926;0.205335;, + -0.227292;0.946930;0.227292;, + 0.000000;0.991445;0.130526;, + -0.017037;0.991445;0.129410;, + -0.033783;0.991445;0.126079;, + -0.049950;0.991445;0.120590;, + -0.097545;0.980785;0.168953;, + -0.118763;0.980785;0.154776;, + -0.183013;0.965926;0.183013;, + 0.000000;0.997859;0.065403;, + -0.008537;0.997859;0.064844;, + -0.016928;0.997859;0.063175;, + -0.025029;0.997859;0.060425;, + -0.065263;0.991445;0.113039;, + -0.079459;0.991445;0.103553;, + -0.137950;0.980785;0.137950;, + -0.032702;0.997859;0.056641;, + -0.039815;0.997859;0.051888;, + -0.092296;0.991445;0.092296;, + -0.154776;0.980785;0.118763;, + -0.205335;0.965926;0.157559;, + -0.046247;0.997859;0.046247;, + -0.103553;0.991445;0.079459;, + -0.168953;0.980785;0.097545;, + -0.224144;0.965926;0.129410;, + -0.278375;0.946930;0.160720;, + -0.255015;0.946930;0.195680;, + -0.051888;0.997859;0.039815;, + -0.113039;0.991445;0.065263;, + -0.180240;0.980785;0.074658;, + -0.239118;0.965926;0.099046;, + -0.296971;0.946930;0.123010;, + -0.056641;0.997859;0.032702;, + -0.120590;0.991445;0.049950;, + -0.188443;0.980785;0.050493;, + -0.250000;0.965926;0.066987;, + -0.310487;0.946930;0.083195;, + -0.060425;0.997859;0.025029;, + -0.126079;0.991445;0.033783;, + -0.193421;0.980785;0.025464;, + -0.256605;0.965926;0.033783;, + -0.318689;0.946930;0.041956;, + -0.063175;0.997859;0.016928;, + -0.129410;0.991445;0.017037;, + -0.195090;0.980785;0.000000;, + -0.258819;0.965926;0.000000;, + -0.321439;0.946930;0.000000;, + -0.064844;0.997859;0.008537;, + -0.130526;0.991445;0.000000;, + -0.193421;0.980785;-0.025464;, + -0.256605;0.965926;-0.033783;, + -0.318689;0.946930;-0.041956;, + -0.065403;0.997859;0.000000;, + -0.129410;0.991445;-0.017037;, + -0.188443;0.980785;-0.050493;, + -0.250000;0.965926;-0.066987;, + -0.310487;0.946930;-0.083195;, + -0.064844;0.997859;-0.008537;, + -0.126079;0.991445;-0.033783;, + -0.180240;0.980785;-0.074658;, + -0.239118;0.965926;-0.099046;, + -0.296971;0.946930;-0.123010;, + -0.063175;0.997859;-0.016928;, + -0.120590;0.991445;-0.049950;, + -0.168953;0.980785;-0.097545;, + -0.224144;0.965926;-0.129410;, + -0.278375;0.946930;-0.160720;, + -0.060425;0.997859;-0.025029;, + -0.113039;0.991445;-0.065263;, + -0.154776;0.980785;-0.118763;, + -0.205335;0.965926;-0.157559;, + -0.255015;0.946930;-0.195680;, + -0.056641;0.997859;-0.032702;, + -0.103553;0.991445;-0.079459;, + -0.137950;0.980785;-0.137950;, + -0.183013;0.965926;-0.183013;, + -0.227292;0.946930;-0.227292;, + -0.051888;0.997859;-0.039815;, + -0.157559;0.965926;-0.205335;, + -0.195680;0.946930;-0.255015;, + -0.160720;0.946930;-0.278375;, + -0.191342;0.923880;-0.331414;, + -0.232963;0.923880;-0.303603;, + -0.270598;0.923880;-0.270598;, + -0.123010;0.946930;-0.296971;, + -0.146447;0.923880;-0.353553;, + -0.169257;0.896873;-0.408621;, + -0.221144;0.896873;-0.383033;, + -0.269248;0.896873;-0.350891;, + -0.099046;0.923880;-0.369644;, + -0.114473;0.896873;-0.427218;, + -0.129410;0.866025;-0.482963;, + -0.191342;0.866025;-0.461940;, + -0.250000;0.866025;-0.433013;, + -0.049950;0.923880;-0.379410;, + -0.057730;0.896873;-0.438505;, + -0.065263;0.866025;-0.495722;, + -0.072516;0.831470;-0.550817;, + -0.143792;0.831470;-0.536640;, + -0.212608;0.831470;-0.513280;, + 0.000000;0.896873;-0.442289;, + 0.000000;0.866025;-0.500000;, + 0.000000;0.831470;-0.555570;, + 0.000000;0.793353;-0.608761;, + -0.079459;0.793353;-0.603553;, + -0.157559;0.793353;-0.588018;, + 0.057730;0.896873;-0.438505;, + 0.065263;0.866025;-0.495722;, + 0.072516;0.831470;-0.550817;, + 0.079459;0.793353;-0.603553;, + 0.000000;0.751840;-0.659346;, + -0.086062;0.751840;-0.653705;, + 0.114473;0.896873;-0.427218;, + 0.129410;0.866025;-0.482963;, + 0.143792;0.831470;-0.536640;, + 0.157559;0.793353;-0.588018;, + 0.086062;0.751840;-0.653705;, + 0.000000;0.707107;-0.707107;, + 0.169257;0.896873;-0.408621;, + 0.191342;0.866025;-0.461940;, + 0.212608;0.831470;-0.513280;, + 0.232963;0.793353;-0.562422;, + 0.170651;0.751840;-0.636879;, + 0.092296;0.707107;-0.701057;, + 0.221144;0.896873;-0.383033;, + 0.250000;0.866025;-0.433013;, + 0.277785;0.831470;-0.481138;, + 0.304381;0.793353;-0.527203;, + 0.252321;0.751840;-0.609156;, + 0.183013;0.707107;-0.683013;, + 0.269248;0.896873;-0.350891;, + 0.304381;0.866025;-0.396677;, + 0.338210;0.831470;-0.440764;, + 0.370590;0.793353;-0.482963;, + 0.329673;0.751840;-0.571010;, + 0.270598;0.707107;-0.653282;, + 0.312745;0.896873;-0.312745;, + 0.353553;0.866025;-0.353553;, + 0.392847;0.831470;-0.392847;, + 0.430459;0.793353;-0.430459;, + 0.401384;0.751840;-0.523094;, + 0.353553;0.707107;-0.612372;, + 0.350891;0.896873;-0.269248;, + 0.396677;0.866025;-0.304381;, + 0.440764;0.831470;-0.338210;, + 0.482963;0.793353;-0.370590;, + 0.466228;0.751840;-0.466228;, + 0.430459;0.707107;-0.560986;, + 0.383033;0.896873;-0.221144;, + 0.433013;0.866025;-0.250000;, + 0.481138;0.831470;-0.277785;, + 0.527203;0.793353;-0.304381;, + 0.523094;0.751840;-0.401384;, + 0.500000;0.707107;-0.500000;, + 0.408621;0.896873;-0.169257;, + 0.461940;0.866025;-0.191342;, + 0.513280;0.831470;-0.212608;, + 0.562422;0.793353;-0.232963;, + 0.571010;0.751840;-0.329673;, + 0.560986;0.707107;-0.430459;, + 0.427218;0.896873;-0.114473;, + 0.482963;0.866025;-0.129410;, + 0.536640;0.831470;-0.143792;, + 0.588018;0.793353;-0.157559;, + 0.609156;0.751840;-0.252321;, + 0.612372;0.707107;-0.353553;, + 0.438505;0.896873;-0.057730;, + 0.495722;0.866025;-0.065263;, + 0.550817;0.831470;-0.072516;, + 0.603553;0.793353;-0.079459;, + 0.636879;0.751840;-0.170651;, + 0.653282;0.707107;-0.270598;, + 0.442289;0.896873;0.000000;, + 0.500000;0.866025;0.000000;, + 0.555570;0.831470;0.000000;, + 0.608761;0.793353;0.000000;, + 0.653705;0.751840;-0.086062;, + 0.683013;0.707107;-0.183013;, + 0.438505;0.896873;0.057730;, + 0.495722;0.866025;0.065263;, + 0.550817;0.831470;0.072516;, + 0.603553;0.793353;0.079459;, + 0.659346;0.751840;0.000000;, + 0.701057;0.707107;-0.092296;, + 0.427218;0.896873;0.114473;, + 0.482963;0.866025;0.129410;, + 0.536640;0.831470;0.143792;, + 0.588018;0.793353;0.157559;, + 0.653705;0.751840;0.086062;, + 0.707107;0.707107;0.000000;, + 0.408621;0.896873;0.169257;, + 0.461940;0.866025;0.191342;, + 0.513280;0.831470;0.212608;, + 0.562422;0.793353;0.232963;, + 0.636879;0.751840;0.170651;, + 0.701057;0.707107;0.092296;, + 0.383033;0.896873;0.221144;, + 0.433013;0.866025;0.250000;, + 0.481138;0.831470;0.277785;, + 0.527203;0.793353;0.304381;, + 0.609156;0.751840;0.252321;, + 0.683013;0.707107;0.183013;, + 0.350891;0.896873;0.269248;, + 0.396677;0.866025;0.304381;, + 0.440764;0.831470;0.338210;, + 0.482963;0.793353;0.370590;, + 0.571010;0.751840;0.329673;, + 0.653282;0.707107;0.270598;, + 0.312745;0.896873;0.312745;, + 0.353553;0.866025;0.353553;, + 0.392847;0.831470;0.392847;, + 0.430459;0.793353;0.430459;, + 0.523094;0.751840;0.401384;, + 0.612372;0.707107;0.353553;, + 0.466228;0.751840;0.466228;, + 0.560986;0.707107;0.430459;, + 0.651112;0.659346;0.375920;, + 0.694609;0.659346;0.287717;, + 0.726222;0.659346;0.194590;, + 0.500000;0.707107;0.500000;, + 0.596475;0.659346;0.457691;, + 0.687064;0.608761;0.396677;, + 0.732963;0.608761;0.303603;, + 0.766320;0.608761;0.205335;, + 0.531631;0.659346;0.531631;, + 0.629410;0.608761;0.482963;, + 0.720074;0.555570;0.415735;, + 0.768178;0.555570;0.318190;, + 0.803138;0.555570;0.215200;, + 0.560986;0.608761;0.560986;, + 0.659649;0.555570;0.506167;, + 0.750000;0.500000;0.433013;, + 0.800103;0.500000;0.331414;, + 0.836516;0.500000;0.224144;, + 0.587938;0.555570;0.587938;, + 0.687064;0.500000;0.527203;, + 0.776715;0.442289;0.448436;, + 0.828602;0.442289;0.343218;, + 0.866313;0.442289;0.232128;, + 0.612372;0.500000;0.612372;, + 0.711537;0.442289;0.545982;, + 0.800103;0.382683;0.461940;, + 0.853553;0.382683;0.353553;, + 0.892399;0.382683;0.239118;, + 0.634185;0.442289;0.634185;, + 0.732963;0.382683;0.562422;, + 0.820066;0.321439;0.473465;, + 0.874849;0.321439;0.362374;, + 0.914664;0.321439;0.245084;, + 0.653282;0.382683;0.653282;, + 0.751250;0.321439;0.576455;, + 0.836516;0.258819;0.482963;, + 0.892399;0.258819;0.369644;, + 0.933013;0.258819;0.250000;, + 0.669581;0.321439;0.669581;, + 0.766320;0.258819;0.588018;, + 0.849385;0.195090;0.490393;, + 0.906127;0.195090;0.375330;, + 0.947366;0.195090;0.253846;, + 0.683013;0.258819;0.683013;, + 0.778109;0.195090;0.597064;, + 0.858616;0.130526;0.495722;, + 0.915976;0.130526;0.379410;, + 0.957662;0.130526;0.256605;, + 0.693520;0.195090;0.693520;, + 0.786566;0.130526;0.603553;, + 0.864171;0.065403;0.498929;, + 0.921901;0.065403;0.381864;, + 0.963858;0.065403;0.258265;, + 0.701057;0.130526;0.701057;, + 0.791655;0.065403;0.607458;, + 0.866025;0.000000;0.500000;, + 0.923880;0.000000;0.382683;, + 0.965926;0.000000;0.258819;, + 0.705593;0.065403;0.705593;, + 0.793353;0.000000;0.608761;, + 0.864171;-0.065403;0.498929;, + 0.921901;-0.065403;0.381864;, + 0.963858;-0.065403;0.258265;, + 0.707107;0.000000;0.707107;, + 0.791655;-0.065403;0.607458;, + 0.858616;-0.130526;0.495722;, + 0.915976;-0.130526;0.379410;, + 0.957662;-0.130526;0.256605;, + 0.705593;-0.065403;0.705593;, + 0.786566;-0.130526;0.603553;, + 0.849385;-0.195090;0.490393;, + 0.906127;-0.195090;0.375330;, + 0.947366;-0.195090;0.253846;, + 0.701057;-0.130526;0.701057;, + 0.778109;-0.195090;0.597064;, + 0.836516;-0.258819;0.482963;, + 0.892399;-0.258819;0.369644;, + 0.933013;-0.258819;0.250000;, + 0.693520;-0.195090;0.693520;, + 0.766320;-0.258819;0.588018;, + 0.820066;-0.321439;0.473465;, + 0.874849;-0.321439;0.362374;, + 0.914664;-0.321439;0.245084;, + 0.683013;-0.258819;0.683013;, + 0.751250;-0.321439;0.576455;, + 0.800103;-0.382683;0.461940;, + 0.853553;-0.382683;0.353553;, + 0.892399;-0.382683;0.239118;, + 0.669581;-0.321439;0.669581;, + 0.732963;-0.382683;0.562422;, + 0.776715;-0.442289;0.448436;, + 0.828602;-0.442289;0.343218;, + 0.866313;-0.442289;0.232128;, + 0.653282;-0.382683;0.653282;, + 0.711537;-0.442289;0.545982;, + 0.750000;-0.500000;0.433013;, + 0.800103;-0.500000;0.331414;, + 0.836516;-0.500000;0.224144;, + 0.634185;-0.442289;0.634185;, + 0.687064;-0.500000;0.527203;, + 0.720074;-0.555570;0.415735;, + 0.768178;-0.555570;0.318190;, + 0.803138;-0.555570;0.215200;, + 0.612372;-0.500000;0.612372;, + 0.659649;-0.555570;0.506167;, + 0.687064;-0.608761;0.396677;, + 0.732963;-0.608761;0.303603;, + 0.766320;-0.608761;0.205335;, + 0.587938;-0.555570;0.587938;, + 0.629410;-0.608761;0.482963;, + 0.651112;-0.659346;0.375920;, + 0.694609;-0.659346;0.287717;, + 0.726222;-0.659346;0.194590;, + 0.560986;-0.608761;0.560986;, + 0.596475;-0.659346;0.457691;, + 0.612372;-0.707107;0.353553;, + 0.653282;-0.707107;0.270598;, + 0.683013;-0.707107;0.183013;, + 0.531631;-0.659346;0.531631;, + 0.560986;-0.707107;0.430459;, + 0.571010;-0.751840;0.329673;, + 0.609156;-0.751840;0.252321;, + 0.636879;-0.751840;0.170651;, + 0.500000;-0.707107;0.500000;, + 0.523094;-0.751840;0.401384;, + 0.527203;-0.793353;0.304381;, + 0.562422;-0.793353;0.232963;, + 0.588018;-0.793353;0.157559;, + 0.466228;-0.751840;0.466228;, + 0.482963;-0.793353;0.370590;, + 0.481138;-0.831470;0.277785;, + 0.513280;-0.831470;0.212608;, + 0.536640;-0.831470;0.143792;, + 0.430459;-0.793353;0.430459;, + 0.440764;-0.831470;0.338210;, + 0.433013;-0.866025;0.250000;, + 0.461940;-0.866025;0.191342;, + 0.482963;-0.866025;0.129410;, + 0.392847;-0.831470;0.392847;, + 0.396677;-0.866025;0.304381;, + 0.383033;-0.896873;0.221144;, + 0.408621;-0.896873;0.169257;, + 0.427218;-0.896873;0.114473;, + 0.353553;-0.866025;0.353553;, + 0.350891;-0.896873;0.269248;, + 0.331414;-0.923880;0.191342;, + 0.353553;-0.923880;0.146447;, + 0.369644;-0.923880;0.099046;, + 0.312745;-0.896873;0.312745;, + 0.303603;-0.923880;0.232963;, + 0.270598;-0.923880;0.270598;, + 0.379410;-0.923880;0.049950;, + 0.438505;-0.896873;0.057730;, + 0.495722;-0.866025;0.065263;, + 0.382683;-0.923880;0.000000;, + 0.442289;-0.896873;0.000000;, + 0.500000;-0.866025;0.000000;, + 0.550817;-0.831470;0.072516;, + 0.603553;-0.793353;0.079459;, + 0.379410;-0.923880;-0.049950;, + 0.438505;-0.896873;-0.057730;, + 0.495722;-0.866025;-0.065263;, + 0.555570;-0.831470;0.000000;, + 0.608761;-0.793353;0.000000;, + 0.653705;-0.751840;0.086062;, + 0.369644;-0.923880;-0.099046;, + 0.427218;-0.896873;-0.114473;, + 0.482963;-0.866025;-0.129410;, + 0.550817;-0.831470;-0.072516;, + 0.603553;-0.793353;-0.079459;, + 0.659346;-0.751840;0.000000;, + 0.353553;-0.923880;-0.146447;, + 0.408621;-0.896873;-0.169257;, + 0.461940;-0.866025;-0.191342;, + 0.536640;-0.831470;-0.143792;, + 0.588018;-0.793353;-0.157559;, + 0.653705;-0.751840;-0.086062;, + 0.331414;-0.923880;-0.191342;, + 0.383033;-0.896873;-0.221144;, + 0.433013;-0.866025;-0.250000;, + 0.513280;-0.831470;-0.212608;, + 0.562422;-0.793353;-0.232963;, + 0.636879;-0.751840;-0.170651;, + 0.303603;-0.923880;-0.232963;, + 0.350891;-0.896873;-0.269248;, + 0.396677;-0.866025;-0.304381;, + 0.481138;-0.831470;-0.277785;, + 0.527203;-0.793353;-0.304381;, + 0.609156;-0.751840;-0.252321;, + 0.270598;-0.923880;-0.270598;, + 0.312745;-0.896873;-0.312745;, + 0.353553;-0.866025;-0.353553;, + 0.440764;-0.831470;-0.338210;, + 0.482963;-0.793353;-0.370590;, + 0.571010;-0.751840;-0.329673;, + 0.232963;-0.923880;-0.303603;, + 0.269248;-0.896873;-0.350891;, + 0.304381;-0.866025;-0.396677;, + 0.392847;-0.831470;-0.392847;, + 0.430459;-0.793353;-0.430459;, + 0.523094;-0.751840;-0.401384;, + 0.221144;-0.896873;-0.383033;, + 0.250000;-0.866025;-0.433013;, + 0.338210;-0.831470;-0.440764;, + 0.370590;-0.793353;-0.482963;, + 0.466228;-0.751840;-0.466228;, + 0.169257;-0.896873;-0.408621;, + 0.191342;-0.866025;-0.461940;, + 0.277785;-0.831470;-0.481138;, + 0.304381;-0.793353;-0.527203;, + 0.401384;-0.751840;-0.523094;, + 0.114473;-0.896873;-0.427218;, + 0.129410;-0.866025;-0.482963;, + 0.212608;-0.831470;-0.513280;, + 0.232963;-0.793353;-0.562422;, + 0.329673;-0.751840;-0.571010;, + 0.049950;-0.923880;-0.379410;, + 0.057730;-0.896873;-0.438505;, + 0.065263;-0.866025;-0.495722;, + 0.143792;-0.831470;-0.536640;, + 0.157559;-0.793353;-0.588018;, + 0.252321;-0.751840;-0.609156;, + 0.000000;-0.946930;-0.321439;, + 0.000000;-0.923880;-0.382683;, + 0.000000;-0.896873;-0.442289;, + 0.000000;-0.866025;-0.500000;, + 0.072516;-0.831470;-0.550817;, + -0.049950;-0.923880;-0.379410;, + -0.057730;-0.896873;-0.438505;, + -0.065263;-0.866025;-0.495722;, + -0.072516;-0.831470;-0.550817;, + 0.000000;-0.831470;-0.555570;, + 0.079459;-0.793353;-0.603553;, + -0.099046;-0.923880;-0.369644;, + -0.114473;-0.896873;-0.427218;, + -0.129410;-0.866025;-0.482963;, + -0.143792;-0.831470;-0.536640;, + -0.157559;-0.793353;-0.588018;, + -0.079459;-0.793353;-0.603553;, + -0.146447;-0.923880;-0.353553;, + -0.169257;-0.896873;-0.408621;, + -0.191342;-0.866025;-0.461940;, + -0.212608;-0.831470;-0.513280;, + -0.232963;-0.793353;-0.562422;, + -0.191342;-0.923880;-0.331414;, + -0.221144;-0.896873;-0.383033;, + -0.250000;-0.866025;-0.433013;, + -0.277785;-0.831470;-0.481138;, + -0.304381;-0.793353;-0.527203;, + -0.232963;-0.923880;-0.303603;, + -0.269248;-0.896873;-0.350891;, + -0.304381;-0.866025;-0.396677;, + -0.338210;-0.831470;-0.440764;, + -0.370590;-0.793353;-0.482963;, + -0.270598;-0.923880;-0.270598;, + -0.312745;-0.896873;-0.312745;, + -0.353553;-0.866025;-0.353553;, + -0.392847;-0.831470;-0.392847;, + -0.430459;-0.793353;-0.430459;, + -0.303603;-0.923880;-0.232963;, + -0.350891;-0.896873;-0.269248;, + -0.396677;-0.866025;-0.304381;, + -0.440764;-0.831470;-0.338210;, + -0.482963;-0.793353;-0.370590;, + -0.331414;-0.923880;-0.191342;, + -0.383033;-0.896873;-0.221144;, + -0.433013;-0.866025;-0.250000;, + -0.481138;-0.831470;-0.277785;, + -0.527203;-0.793353;-0.304381;, + -0.353553;-0.923880;-0.146447;, + -0.408621;-0.896873;-0.169257;, + -0.461940;-0.866025;-0.191342;, + -0.513280;-0.831470;-0.212608;, + -0.562422;-0.793353;-0.232963;, + -0.369644;-0.923880;-0.099046;, + -0.427218;-0.896873;-0.114473;, + -0.482963;-0.866025;-0.129410;, + -0.536640;-0.831470;-0.143792;, + -0.588018;-0.793353;-0.157559;, + -0.379410;-0.923880;-0.049950;, + -0.438505;-0.896873;-0.057730;, + -0.495722;-0.866025;-0.065263;, + -0.550817;-0.831470;-0.072516;, + -0.603553;-0.793353;-0.079459;, + -0.382683;-0.923880;0.000000;, + -0.442289;-0.896873;0.000000;, + -0.500000;-0.866025;0.000000;, + -0.555570;-0.831470;0.000000;, + -0.608761;-0.793353;0.000000;, + -0.379410;-0.923880;0.049950;, + -0.438505;-0.896873;0.057730;, + -0.495722;-0.866025;0.065263;, + -0.550817;-0.831470;0.072516;, + -0.603553;-0.793353;0.079459;, + -0.369644;-0.923880;0.099046;, + -0.427218;-0.896873;0.114473;, + -0.482963;-0.866025;0.129410;, + -0.536640;-0.831470;0.143792;, + -0.588018;-0.793353;0.157559;, + -0.353553;-0.923880;0.146447;, + -0.408621;-0.896873;0.169257;, + -0.461940;-0.866025;0.191342;, + -0.513280;-0.831470;0.212608;, + -0.562422;-0.793353;0.232963;, + -0.331414;-0.923880;0.191342;, + -0.383033;-0.896873;0.221144;, + -0.433013;-0.866025;0.250000;, + -0.481138;-0.831470;0.277785;, + -0.527203;-0.793353;0.304381;, + -0.303603;-0.923880;0.232963;, + -0.350891;-0.896873;0.269248;, + -0.396677;-0.866025;0.304381;, + -0.440764;-0.831470;0.338210;, + -0.482963;-0.793353;0.370590;, + -0.523094;-0.751840;0.401384;, + -0.571010;-0.751840;0.329673;, + -0.609156;-0.751840;0.252321;, + -0.560986;-0.707107;0.430459;, + -0.612372;-0.707107;0.353553;, + -0.653282;-0.707107;0.270598;, + -0.636879;-0.751840;0.170651;, + -0.653705;-0.751840;0.086062;, + -0.596475;-0.659346;0.457691;, + -0.651112;-0.659346;0.375920;, + -0.694609;-0.659346;0.287717;, + -0.683013;-0.707107;0.183013;, + -0.701057;-0.707107;0.092296;, + -0.659346;-0.751840;0.000000;, + -0.629410;-0.608761;0.482963;, + -0.687064;-0.608761;0.396677;, + -0.732963;-0.608761;0.303603;, + -0.726222;-0.659346;0.194590;, + -0.745408;-0.659346;0.098135;, + -0.707107;-0.707107;0.000000;, + -0.659649;-0.555570;0.506167;, + -0.720074;-0.555570;0.415735;, + -0.768178;-0.555570;0.318190;, + -0.766320;-0.608761;0.205335;, + -0.786566;-0.608761;0.103553;, + -0.751840;-0.659346;0.000000;, + -0.687064;-0.500000;0.527203;, + -0.750000;-0.500000;0.433013;, + -0.800103;-0.500000;0.331414;, + -0.803138;-0.555570;0.215200;, + -0.824356;-0.555570;0.108529;, + -0.793353;-0.608761;0.000000;, + -0.711537;-0.442289;0.545982;, + -0.776715;-0.442289;0.448436;, + -0.828602;-0.442289;0.343218;, + -0.836516;-0.500000;0.224144;, + -0.858616;-0.500000;0.113039;, + -0.831470;-0.555570;0.000000;, + -0.732963;-0.382683;0.562422;, + -0.800103;-0.382683;0.461940;, + -0.853553;-0.382683;0.353553;, + -0.866313;-0.442289;0.232128;, + -0.889200;-0.442289;0.117065;, + -0.866025;-0.500000;0.000000;, + -0.751250;-0.321439;0.576455;, + -0.820066;-0.321439;0.473465;, + -0.874849;-0.321439;0.362374;, + -0.892399;-0.382683;0.239118;, + -0.915976;-0.382683;0.120590;, + -0.896873;-0.442289;0.000000;, + -0.766320;-0.258819;0.588018;, + -0.836516;-0.258819;0.482963;, + -0.892399;-0.258819;0.369644;, + -0.914664;-0.321439;0.245084;, + -0.938829;-0.321439;0.123599;, + -0.923880;-0.382683;0.000000;, + -0.778109;-0.195090;0.597064;, + -0.849385;-0.195090;0.490393;, + -0.906127;-0.195090;0.375330;, + -0.933013;-0.258819;0.250000;, + -0.957662;-0.258819;0.126079;, + -0.946930;-0.321439;0.000000;, + -0.786566;-0.130526;0.603553;, + -0.858616;-0.130526;0.495722;, + -0.915976;-0.130526;0.379410;, + -0.947366;-0.195090;0.253846;, + -0.972395;-0.195090;0.128018;, + -0.965926;-0.258819;0.000000;, + -0.791655;-0.065403;0.607458;, + -0.864171;-0.065403;0.498929;, + -0.921901;-0.065403;0.381864;, + -0.957662;-0.130526;0.256605;, + -0.982963;-0.130526;0.129410;, + -0.980785;-0.195090;0.000000;, + -0.793353;0.000000;0.608761;, + -0.866025;0.000000;0.500000;, + -0.923880;0.000000;0.382683;, + -0.963858;-0.065403;0.258265;, + -0.989322;-0.065403;0.130247;, + -0.991445;-0.130526;0.000000;, + -0.791655;0.065403;0.607458;, + -0.864171;0.065403;0.498929;, + -0.921901;0.065403;0.381864;, + -0.965926;0.000000;0.258819;, + -0.991445;0.000000;0.130526;, + -0.997859;-0.065403;0.000000;, + -0.786566;0.130526;0.603553;, + -0.858616;0.130526;0.495722;, + -0.915976;0.130526;0.379410;, + -0.963858;0.065403;0.258265;, + -0.989322;0.065403;0.130247;, + -1.000000;0.000000;0.000000;, + -0.778109;0.195090;0.597064;, + -0.849385;0.195090;0.490393;, + -0.906127;0.195090;0.375330;, + -0.957662;0.130526;0.256605;, + -0.982963;0.130526;0.129410;, + -0.997859;0.065403;0.000000;, + -0.766320;0.258819;0.588018;, + -0.836516;0.258819;0.482963;, + -0.892399;0.258819;0.369644;, + -0.947366;0.195090;0.253846;, + -0.972395;0.195090;0.128018;, + -0.991445;0.130526;0.000000;, + -0.751250;0.321439;0.576455;, + -0.820066;0.321439;0.473465;, + -0.874849;0.321439;0.362374;, + -0.933013;0.258819;0.250000;, + -0.957662;0.258819;0.126079;, + -0.980785;0.195090;0.000000;, + -0.732963;0.382683;0.562422;, + -0.800103;0.382683;0.461940;, + -0.853553;0.382683;0.353553;, + -0.914664;0.321439;0.245084;, + -0.938829;0.321439;0.123599;, + -0.965926;0.258819;0.000000;, + -0.711537;0.442289;0.545982;, + -0.776715;0.442289;0.448436;, + -0.828602;0.442289;0.343218;, + -0.892399;0.382683;0.239118;, + -0.915976;0.382683;0.120590;, + -0.946930;0.321439;0.000000;, + -0.687064;0.500000;0.527203;, + -0.750000;0.500000;0.433013;, + -0.800103;0.500000;0.331414;, + -0.866313;0.442289;0.232128;, + -0.889200;0.442289;0.117065;, + -0.923880;0.382683;0.000000;, + -0.659649;0.555570;0.506167;, + -0.720074;0.555570;0.415735;, + -0.768178;0.555570;0.318190;, + -0.836516;0.500000;0.224144;, + -0.858616;0.500000;0.113039;, + -0.896873;0.442289;0.000000;, + -0.629410;0.608761;0.482963;, + -0.687064;0.608761;0.396677;, + -0.732963;0.608761;0.303603;, + -0.803138;0.555570;0.215200;, + -0.824356;0.555570;0.108529;, + -0.866025;0.500000;0.000000;, + -0.596475;0.659346;0.457691;, + -0.651112;0.659346;0.375920;, + -0.694609;0.659346;0.287717;, + -0.766320;0.608761;0.205335;, + -0.786566;0.608761;0.103553;, + -0.831470;0.555570;0.000000;, + -0.560986;0.707107;0.430459;, + -0.612372;0.707107;0.353553;, + -0.653282;0.707107;0.270598;, + -0.726222;0.659346;0.194590;, + -0.745408;0.659346;0.098135;, + -0.793353;0.608761;0.000000;, + -0.523094;0.751840;0.401384;, + -0.571010;0.751840;0.329673;, + -0.609156;0.751840;0.252321;, + -0.683013;0.707107;0.183013;, + -0.701057;0.707107;0.092296;, + -0.751840;0.659346;0.000000;, + -0.482963;0.793353;0.370590;, + -0.527203;0.793353;0.304381;, + -0.562422;0.793353;0.232963;, + -0.636879;0.751840;0.170651;, + -0.653705;0.751840;0.086062;, + -0.707107;0.707107;0.000000;, + -0.440764;0.831470;0.338210;, + -0.481138;0.831470;0.277785;, + -0.513280;0.831470;0.212608;, + -0.588018;0.793353;0.157559;, + -0.603553;0.793353;0.079459;, + -0.659346;0.751840;0.000000;, + -0.396677;0.866025;0.304381;, + -0.433013;0.866025;0.250000;, + -0.461940;0.866025;0.191342;, + -0.536640;0.831470;0.143792;, + -0.550817;0.831470;0.072516;, + -0.608761;0.793353;0.000000;, + -0.350891;0.896873;0.269248;, + -0.383033;0.896873;0.221144;, + -0.408621;0.896873;0.169257;, + -0.482963;0.866025;0.129410;, + -0.495722;0.866025;0.065263;, + -0.555570;0.831470;0.000000;, + -0.303603;0.923880;0.232963;, + -0.331414;0.923880;0.191342;, + -0.353553;0.923880;0.146447;, + -0.427218;0.896873;0.114473;, + -0.438505;0.896873;0.057730;, + -0.500000;0.866025;0.000000;, + -0.369644;0.923880;0.099046;, + -0.379410;0.923880;0.049950;, + -0.442289;0.896873;0.000000;, + -0.495722;0.866025;-0.065263;, + -0.550817;0.831470;-0.072516;, + -0.382683;0.923880;0.000000;, + -0.438505;0.896873;-0.057730;, + -0.482963;0.866025;-0.129410;, + -0.536640;0.831470;-0.143792;, + -0.588018;0.793353;-0.157559;, + -0.603553;0.793353;-0.079459;, + -0.379410;0.923880;-0.049950;, + -0.427218;0.896873;-0.114473;, + -0.461940;0.866025;-0.191342;, + -0.513280;0.831470;-0.212608;, + -0.562422;0.793353;-0.232963;, + -0.369644;0.923880;-0.099046;, + -0.408621;0.896873;-0.169257;, + -0.433013;0.866025;-0.250000;, + -0.481138;0.831470;-0.277785;, + -0.527203;0.793353;-0.304381;, + -0.353553;0.923880;-0.146447;, + -0.383033;0.896873;-0.221144;, + -0.396677;0.866025;-0.304381;, + -0.440764;0.831470;-0.338210;, + -0.482963;0.793353;-0.370590;, + -0.331414;0.923880;-0.191342;, + -0.350891;0.896873;-0.269248;, + -0.353553;0.866025;-0.353553;, + -0.392847;0.831470;-0.392847;, + -0.430459;0.793353;-0.430459;, + -0.303603;0.923880;-0.232963;, + -0.312745;0.896873;-0.312745;, + -0.304381;0.866025;-0.396677;, + -0.338210;0.831470;-0.440764;, + -0.370590;0.793353;-0.482963;, + -0.277785;0.831470;-0.481138;, + -0.304381;0.793353;-0.527203;, + -0.329673;0.751840;-0.571010;, + -0.401384;0.751840;-0.523094;, + -0.466228;0.751840;-0.466228;, + -0.232963;0.793353;-0.562422;, + -0.252321;0.751840;-0.609156;, + -0.270598;0.707107;-0.653282;, + -0.353553;0.707107;-0.612372;, + -0.430459;0.707107;-0.560986;, + -0.170651;0.751840;-0.636879;, + -0.183013;0.707107;-0.683013;, + -0.194590;0.659346;-0.726222;, + -0.287717;0.659346;-0.694609;, + -0.375920;0.659346;-0.651112;, + -0.092296;0.707107;-0.701057;, + -0.098135;0.659346;-0.745408;, + -0.103553;0.608761;-0.786566;, + -0.205335;0.608761;-0.766320;, + -0.303603;0.608761;-0.732963;, + 0.000000;0.659346;-0.751840;, + 0.000000;0.608761;-0.793353;, + 0.000000;0.555570;-0.831470;, + -0.108529;0.555570;-0.824356;, + -0.215200;0.555570;-0.803138;, + 0.098135;0.659346;-0.745408;, + 0.103553;0.608761;-0.786566;, + 0.108529;0.555570;-0.824356;, + 0.000000;0.500000;-0.866025;, + -0.113039;0.500000;-0.858616;, + 0.194590;0.659346;-0.726222;, + 0.205335;0.608761;-0.766320;, + 0.215200;0.555570;-0.803138;, + 0.113039;0.500000;-0.858616;, + 0.000000;0.442289;-0.896873;, + 0.287717;0.659346;-0.694609;, + 0.303603;0.608761;-0.732963;, + 0.318190;0.555570;-0.768178;, + 0.224144;0.500000;-0.836516;, + 0.117065;0.442289;-0.889200;, + 0.375920;0.659346;-0.651112;, + 0.396677;0.608761;-0.687064;, + 0.415735;0.555570;-0.720074;, + 0.331414;0.500000;-0.800103;, + 0.232128;0.442289;-0.866313;, + 0.457691;0.659346;-0.596475;, + 0.482963;0.608761;-0.629410;, + 0.506167;0.555570;-0.659649;, + 0.433013;0.500000;-0.750000;, + 0.343218;0.442289;-0.828602;, + 0.531631;0.659346;-0.531631;, + 0.560986;0.608761;-0.560986;, + 0.587938;0.555570;-0.587938;, + 0.527203;0.500000;-0.687064;, + 0.448436;0.442289;-0.776715;, + 0.596475;0.659346;-0.457691;, + 0.629410;0.608761;-0.482963;, + 0.659649;0.555570;-0.506167;, + 0.612372;0.500000;-0.612372;, + 0.545982;0.442289;-0.711537;, + 0.651112;0.659346;-0.375920;, + 0.687064;0.608761;-0.396677;, + 0.720074;0.555570;-0.415735;, + 0.687064;0.500000;-0.527203;, + 0.634185;0.442289;-0.634185;, + 0.694609;0.659346;-0.287717;, + 0.732963;0.608761;-0.303603;, + 0.768178;0.555570;-0.318190;, + 0.750000;0.500000;-0.433013;, + 0.711537;0.442289;-0.545982;, + 0.726222;0.659346;-0.194590;, + 0.766320;0.608761;-0.205335;, + 0.803138;0.555570;-0.215200;, + 0.800103;0.500000;-0.331414;, + 0.776715;0.442289;-0.448436;, + 0.745408;0.659346;-0.098135;, + 0.786566;0.608761;-0.103553;, + 0.824356;0.555570;-0.108529;, + 0.836516;0.500000;-0.224144;, + 0.828602;0.442289;-0.343218;, + 0.751840;0.659346;0.000000;, + 0.793353;0.608761;0.000000;, + 0.831470;0.555570;0.000000;, + 0.858616;0.500000;-0.113039;, + 0.866313;0.442289;-0.232128;, + 0.745408;0.659346;0.098135;, + 0.786566;0.608761;0.103553;, + 0.824356;0.555570;0.108529;, + 0.866025;0.500000;0.000000;, + 0.889200;0.442289;-0.117065;, + 0.858616;0.500000;0.113039;, + 0.896873;0.442289;0.000000;, + 0.915976;0.382683;-0.120590;, + 0.892399;0.382683;-0.239118;, + 0.853553;0.382683;-0.353553;, + 0.889200;0.442289;0.117065;, + 0.923880;0.382683;0.000000;, + 0.938829;0.321439;-0.123599;, + 0.914664;0.321439;-0.245084;, + 0.874849;0.321439;-0.362374;, + 0.915976;0.382683;0.120590;, + 0.946930;0.321439;0.000000;, + 0.957662;0.258819;-0.126079;, + 0.933013;0.258819;-0.250000;, + 0.892399;0.258819;-0.369644;, + 0.938829;0.321439;0.123599;, + 0.965926;0.258819;0.000000;, + 0.972395;0.195090;-0.128018;, + 0.947366;0.195090;-0.253846;, + 0.906127;0.195090;-0.375330;, + 0.957662;0.258819;0.126079;, + 0.980785;0.195090;0.000000;, + 0.982963;0.130526;-0.129410;, + 0.957662;0.130526;-0.256605;, + 0.915976;0.130526;-0.379410;, + 0.972395;0.195090;0.128018;, + 0.991445;0.130526;0.000000;, + 0.989322;0.065403;-0.130247;, + 0.963858;0.065403;-0.258265;, + 0.921901;0.065403;-0.381864;, + 0.982963;0.130526;0.129410;, + 0.997859;0.065403;0.000000;, + 0.991445;0.000000;-0.130526;, + 0.965926;0.000000;-0.258819;, + 0.923880;0.000000;-0.382683;, + 0.989322;0.065403;0.130247;, + 1.000000;0.000000;0.000000;, + 0.989322;-0.065403;-0.130247;, + 0.963858;-0.065403;-0.258265;, + 0.921901;-0.065403;-0.381864;, + 0.991445;0.000000;0.130526;, + 0.997859;-0.065403;0.000000;, + 0.982963;-0.130526;-0.129410;, + 0.957662;-0.130526;-0.256605;, + 0.915976;-0.130526;-0.379410;, + 0.989322;-0.065403;0.130247;, + 0.991445;-0.130526;0.000000;, + 0.972395;-0.195090;-0.128018;, + 0.947366;-0.195090;-0.253846;, + 0.906127;-0.195090;-0.375330;, + 0.982963;-0.130526;0.129410;, + 0.980785;-0.195090;0.000000;, + 0.957662;-0.258819;-0.126079;, + 0.933013;-0.258819;-0.250000;, + 0.892399;-0.258819;-0.369644;, + 0.972395;-0.195090;0.128018;, + 0.965926;-0.258819;0.000000;, + 0.938829;-0.321439;-0.123599;, + 0.914664;-0.321439;-0.245084;, + 0.874849;-0.321439;-0.362374;, + 0.957662;-0.258819;0.126079;, + 0.946930;-0.321439;0.000000;, + 0.915976;-0.382683;-0.120590;, + 0.892399;-0.382683;-0.239118;, + 0.853553;-0.382683;-0.353553;, + 0.938829;-0.321439;0.123599;, + 0.923880;-0.382683;0.000000;, + 0.889200;-0.442289;-0.117065;, + 0.866313;-0.442289;-0.232128;, + 0.828602;-0.442289;-0.343218;, + 0.915976;-0.382683;0.120590;, + 0.896873;-0.442289;0.000000;, + 0.858616;-0.500000;-0.113039;, + 0.836516;-0.500000;-0.224144;, + 0.800103;-0.500000;-0.331414;, + 0.889200;-0.442289;0.117065;, + 0.866025;-0.500000;0.000000;, + 0.824356;-0.555570;-0.108529;, + 0.803138;-0.555570;-0.215200;, + 0.768178;-0.555570;-0.318190;, + 0.858616;-0.500000;0.113039;, + 0.831470;-0.555570;0.000000;, + 0.786566;-0.608761;-0.103553;, + 0.766320;-0.608761;-0.205335;, + 0.732963;-0.608761;-0.303603;, + 0.824356;-0.555570;0.108529;, + 0.793353;-0.608761;0.000000;, + 0.745408;-0.659346;-0.098135;, + 0.726222;-0.659346;-0.194590;, + 0.694609;-0.659346;-0.287717;, + 0.786566;-0.608761;0.103553;, + 0.751840;-0.659346;0.000000;, + 0.701057;-0.707107;-0.092296;, + 0.683013;-0.707107;-0.183013;, + 0.653282;-0.707107;-0.270598;, + 0.745408;-0.659346;0.098135;, + 0.707107;-0.707107;0.000000;, + 0.701057;-0.707107;0.092296;, + 0.612372;-0.707107;-0.353553;, + 0.651112;-0.659346;-0.375920;, + 0.687064;-0.608761;-0.396677;, + 0.560986;-0.707107;-0.430459;, + 0.596475;-0.659346;-0.457691;, + 0.629410;-0.608761;-0.482963;, + 0.720074;-0.555570;-0.415735;, + 0.750000;-0.500000;-0.433013;, + 0.500000;-0.707107;-0.500000;, + 0.531631;-0.659346;-0.531631;, + 0.560986;-0.608761;-0.560986;, + 0.659649;-0.555570;-0.506167;, + 0.687064;-0.500000;-0.527203;, + 0.776715;-0.442289;-0.448436;, + 0.430459;-0.707107;-0.560986;, + 0.457691;-0.659346;-0.596475;, + 0.482963;-0.608761;-0.629410;, + 0.587938;-0.555570;-0.587938;, + 0.612372;-0.500000;-0.612372;, + 0.711537;-0.442289;-0.545982;, + 0.353553;-0.707107;-0.612372;, + 0.375920;-0.659346;-0.651112;, + 0.396677;-0.608761;-0.687064;, + 0.506167;-0.555570;-0.659649;, + 0.527203;-0.500000;-0.687064;, + 0.634185;-0.442289;-0.634185;, + 0.270598;-0.707107;-0.653282;, + 0.287717;-0.659346;-0.694609;, + 0.303603;-0.608761;-0.732963;, + 0.415735;-0.555570;-0.720074;, + 0.433013;-0.500000;-0.750000;, + 0.545982;-0.442289;-0.711537;, + 0.170651;-0.751840;-0.636879;, + 0.183013;-0.707107;-0.683013;, + 0.194590;-0.659346;-0.726222;, + 0.205335;-0.608761;-0.766320;, + 0.318190;-0.555570;-0.768178;, + 0.086062;-0.751840;-0.653705;, + 0.092296;-0.707107;-0.701057;, + 0.098135;-0.659346;-0.745408;, + 0.103553;-0.608761;-0.786566;, + 0.215200;-0.555570;-0.803138;, + 0.331414;-0.500000;-0.800103;, + 0.000000;-0.793353;-0.608761;, + 0.000000;-0.751840;-0.659346;, + 0.000000;-0.707107;-0.707107;, + 0.000000;-0.659346;-0.751840;, + 0.000000;-0.608761;-0.793353;, + 0.108529;-0.555570;-0.824356;, + -0.086062;-0.751840;-0.653705;, + -0.092296;-0.707107;-0.701057;, + -0.098135;-0.659346;-0.745408;, + -0.103553;-0.608761;-0.786566;, + -0.108529;-0.555570;-0.824356;, + 0.000000;-0.555570;-0.831470;, + -0.170651;-0.751840;-0.636879;, + -0.183013;-0.707107;-0.683013;, + -0.194590;-0.659346;-0.726222;, + -0.205335;-0.608761;-0.766320;, + -0.215200;-0.555570;-0.803138;, + -0.252321;-0.751840;-0.609156;, + -0.270598;-0.707107;-0.653282;, + -0.287717;-0.659346;-0.694609;, + -0.303603;-0.608761;-0.732963;, + -0.318190;-0.555570;-0.768178;, + -0.329673;-0.751840;-0.571010;, + -0.353553;-0.707107;-0.612372;, + -0.375920;-0.659346;-0.651112;, + -0.396677;-0.608761;-0.687064;, + -0.415735;-0.555570;-0.720074;, + -0.401384;-0.751840;-0.523094;, + -0.430459;-0.707107;-0.560986;, + -0.457691;-0.659346;-0.596475;, + -0.482963;-0.608761;-0.629410;, + -0.506167;-0.555570;-0.659649;, + -0.466228;-0.751840;-0.466228;, + -0.500000;-0.707107;-0.500000;, + -0.531631;-0.659346;-0.531631;, + -0.560986;-0.608761;-0.560986;, + -0.587938;-0.555570;-0.587938;, + -0.523094;-0.751840;-0.401384;, + -0.560986;-0.707107;-0.430459;, + -0.596475;-0.659346;-0.457691;, + -0.629410;-0.608761;-0.482963;, + -0.659649;-0.555570;-0.506167;, + -0.571010;-0.751840;-0.329673;, + -0.612372;-0.707107;-0.353553;, + -0.651112;-0.659346;-0.375920;, + -0.687064;-0.608761;-0.396677;, + -0.720074;-0.555570;-0.415735;, + -0.609156;-0.751840;-0.252321;, + -0.653282;-0.707107;-0.270598;, + -0.694609;-0.659346;-0.287717;, + -0.732963;-0.608761;-0.303603;, + -0.768178;-0.555570;-0.318190;, + -0.636879;-0.751840;-0.170651;, + -0.683013;-0.707107;-0.183013;, + -0.726222;-0.659346;-0.194590;, + -0.766320;-0.608761;-0.205335;, + -0.803138;-0.555570;-0.215200;, + -0.653705;-0.751840;-0.086062;, + -0.701057;-0.707107;-0.092296;, + -0.745408;-0.659346;-0.098135;, + -0.786566;-0.608761;-0.103553;, + -0.824356;-0.555570;-0.108529;, + -0.858616;-0.500000;-0.113039;, + -0.836516;-0.500000;-0.224144;, + -0.800103;-0.500000;-0.331414;, + -0.889200;-0.442289;-0.117065;, + -0.866313;-0.442289;-0.232128;, + -0.828602;-0.442289;-0.343218;, + -0.750000;-0.500000;-0.433013;, + -0.687064;-0.500000;-0.527203;, + -0.915976;-0.382683;-0.120590;, + -0.892399;-0.382683;-0.239118;, + -0.853553;-0.382683;-0.353553;, + -0.776715;-0.442289;-0.448436;, + -0.711537;-0.442289;-0.545982;, + -0.612372;-0.500000;-0.612372;, + -0.938829;-0.321439;-0.123599;, + -0.914664;-0.321439;-0.245084;, + -0.874849;-0.321439;-0.362374;, + -0.800103;-0.382683;-0.461940;, + -0.732963;-0.382683;-0.562422;, + -0.634185;-0.442289;-0.634185;, + -0.957662;-0.258819;-0.126079;, + -0.933013;-0.258819;-0.250000;, + -0.892399;-0.258819;-0.369644;, + -0.820066;-0.321439;-0.473465;, + -0.751250;-0.321439;-0.576455;, + -0.653282;-0.382683;-0.653282;, + -0.972395;-0.195090;-0.128018;, + -0.947366;-0.195090;-0.253846;, + -0.906127;-0.195090;-0.375330;, + -0.836516;-0.258819;-0.482963;, + -0.766320;-0.258819;-0.588018;, + -0.669581;-0.321439;-0.669581;, + -0.982963;-0.130526;-0.129410;, + -0.957662;-0.130526;-0.256605;, + -0.915976;-0.130526;-0.379410;, + -0.849385;-0.195090;-0.490393;, + -0.778109;-0.195090;-0.597064;, + -0.683013;-0.258819;-0.683013;, + -0.989322;-0.065403;-0.130247;, + -0.963858;-0.065403;-0.258265;, + -0.921901;-0.065403;-0.381864;, + -0.858616;-0.130526;-0.495722;, + -0.786566;-0.130526;-0.603553;, + -0.693520;-0.195090;-0.693520;, + -0.991445;0.000000;-0.130526;, + -0.965926;0.000000;-0.258819;, + -0.923880;0.000000;-0.382683;, + -0.864171;-0.065403;-0.498929;, + -0.791655;-0.065403;-0.607458;, + -0.701057;-0.130526;-0.701057;, + -0.989322;0.065403;-0.130247;, + -0.963858;0.065403;-0.258265;, + -0.921901;0.065403;-0.381864;, + -0.866025;0.000000;-0.500000;, + -0.793353;0.000000;-0.608761;, + -0.705593;-0.065403;-0.705593;, + -0.982963;0.130526;-0.129410;, + -0.957662;0.130526;-0.256605;, + -0.915976;0.130526;-0.379410;, + -0.864171;0.065403;-0.498929;, + -0.791655;0.065403;-0.607458;, + -0.707107;0.000000;-0.707107;, + -0.972395;0.195090;-0.128018;, + -0.947366;0.195090;-0.253846;, + -0.906127;0.195090;-0.375330;, + -0.858616;0.130526;-0.495722;, + -0.786566;0.130526;-0.603553;, + -0.705593;0.065403;-0.705593;, + -0.957662;0.258819;-0.126079;, + -0.933013;0.258819;-0.250000;, + -0.892399;0.258819;-0.369644;, + -0.849385;0.195090;-0.490393;, + -0.778109;0.195090;-0.597064;, + -0.701057;0.130526;-0.701057;, + -0.938829;0.321439;-0.123599;, + -0.914664;0.321439;-0.245084;, + -0.874849;0.321439;-0.362374;, + -0.836516;0.258819;-0.482963;, + -0.766320;0.258819;-0.588018;, + -0.693520;0.195090;-0.693520;, + -0.915976;0.382683;-0.120590;, + -0.892399;0.382683;-0.239118;, + -0.853553;0.382683;-0.353553;, + -0.820066;0.321439;-0.473465;, + -0.751250;0.321439;-0.576455;, + -0.683013;0.258819;-0.683013;, + -0.889200;0.442289;-0.117065;, + -0.866313;0.442289;-0.232128;, + -0.828602;0.442289;-0.343218;, + -0.800103;0.382683;-0.461940;, + -0.732963;0.382683;-0.562422;, + -0.669581;0.321439;-0.669581;, + -0.858616;0.500000;-0.113039;, + -0.836516;0.500000;-0.224144;, + -0.800103;0.500000;-0.331414;, + -0.776715;0.442289;-0.448436;, + -0.711537;0.442289;-0.545982;, + -0.653282;0.382683;-0.653282;, + -0.824356;0.555570;-0.108529;, + -0.803138;0.555570;-0.215200;, + -0.768178;0.555570;-0.318190;, + -0.750000;0.500000;-0.433013;, + -0.687064;0.500000;-0.527203;, + -0.634185;0.442289;-0.634185;, + -0.786566;0.608761;-0.103553;, + -0.766320;0.608761;-0.205335;, + -0.732963;0.608761;-0.303603;, + -0.720074;0.555570;-0.415735;, + -0.659649;0.555570;-0.506167;, + -0.612372;0.500000;-0.612372;, + -0.745408;0.659346;-0.098135;, + -0.726222;0.659346;-0.194590;, + -0.694609;0.659346;-0.287717;, + -0.687064;0.608761;-0.396677;, + -0.629410;0.608761;-0.482963;, + -0.587938;0.555570;-0.587938;, + -0.701057;0.707107;-0.092296;, + -0.683013;0.707107;-0.183013;, + -0.653282;0.707107;-0.270598;, + -0.651112;0.659346;-0.375920;, + -0.596475;0.659346;-0.457691;, + -0.560986;0.608761;-0.560986;, + -0.653705;0.751840;-0.086062;, + -0.636879;0.751840;-0.170651;, + -0.609156;0.751840;-0.252321;, + -0.612372;0.707107;-0.353553;, + -0.560986;0.707107;-0.430459;, + -0.531631;0.659346;-0.531631;, + -0.571010;0.751840;-0.329673;, + -0.523094;0.751840;-0.401384;, + -0.500000;0.707107;-0.500000;, + -0.457691;0.659346;-0.596475;, + -0.482963;0.608761;-0.629410;, + -0.396677;0.608761;-0.687064;, + -0.415735;0.555570;-0.720074;, + -0.506167;0.555570;-0.659649;, + -0.527203;0.500000;-0.687064;, + -0.318190;0.555570;-0.768178;, + -0.331414;0.500000;-0.800103;, + -0.433013;0.500000;-0.750000;, + -0.448436;0.442289;-0.776715;, + -0.545982;0.442289;-0.711537;, + -0.224144;0.500000;-0.836516;, + -0.232128;0.442289;-0.866313;, + -0.343218;0.442289;-0.828602;, + -0.353553;0.382683;-0.853553;, + -0.461940;0.382683;-0.800103;, + -0.562422;0.382683;-0.732963;, + -0.117065;0.442289;-0.889200;, + -0.120590;0.382683;-0.915976;, + -0.239118;0.382683;-0.892399;, + -0.245084;0.321439;-0.914664;, + -0.362374;0.321439;-0.874849;, + -0.473465;0.321439;-0.820066;, + 0.000000;0.382683;-0.923880;, + 0.000000;0.321439;-0.946930;, + -0.123599;0.321439;-0.938829;, + -0.126079;0.258819;-0.957662;, + -0.250000;0.258819;-0.933013;, + -0.369644;0.258819;-0.892399;, + 0.120590;0.382683;-0.915976;, + 0.123599;0.321439;-0.938829;, + 0.000000;0.258819;-0.965926;, + 0.000000;0.195090;-0.980785;, + -0.128018;0.195090;-0.972395;, + -0.253846;0.195090;-0.947366;, + 0.239118;0.382683;-0.892399;, + 0.245084;0.321439;-0.914664;, + 0.126079;0.258819;-0.957662;, + 0.128018;0.195090;-0.972395;, + 0.000000;0.130526;-0.991445;, + -0.129410;0.130526;-0.982963;, + 0.353553;0.382683;-0.853553;, + 0.362374;0.321439;-0.874849;, + 0.250000;0.258819;-0.933013;, + 0.253846;0.195090;-0.947366;, + 0.129410;0.130526;-0.982963;, + 0.000000;0.065403;-0.997859;, + 0.461940;0.382683;-0.800103;, + 0.473465;0.321439;-0.820066;, + 0.369644;0.258819;-0.892399;, + 0.375330;0.195090;-0.906127;, + 0.256605;0.130526;-0.957662;, + 0.130247;0.065403;-0.989322;, + 0.562422;0.382683;-0.732963;, + 0.576455;0.321439;-0.751250;, + 0.482963;0.258819;-0.836516;, + 0.490393;0.195090;-0.849385;, + 0.379410;0.130526;-0.915976;, + 0.258265;0.065403;-0.963858;, + 0.653282;0.382683;-0.653282;, + 0.669581;0.321439;-0.669581;, + 0.588018;0.258819;-0.766320;, + 0.597064;0.195090;-0.778109;, + 0.495722;0.130526;-0.858616;, + 0.381864;0.065403;-0.921901;, + 0.732963;0.382683;-0.562422;, + 0.751250;0.321439;-0.576455;, + 0.683013;0.258819;-0.683013;, + 0.693520;0.195090;-0.693520;, + 0.603553;0.130526;-0.786566;, + 0.498929;0.065403;-0.864171;, + 0.800103;0.382683;-0.461940;, + 0.820066;0.321439;-0.473465;, + 0.766320;0.258819;-0.588018;, + 0.778109;0.195090;-0.597064;, + 0.701057;0.130526;-0.701057;, + 0.607458;0.065403;-0.791655;, + 0.836516;0.258819;-0.482963;, + 0.849385;0.195090;-0.490393;, + 0.786566;0.130526;-0.603553;, + 0.705593;0.065403;-0.705593;, + 0.608761;0.000000;-0.793353;, + 0.500000;0.000000;-0.866025;, + 0.858616;0.130526;-0.495722;, + 0.791655;0.065403;-0.607458;, + 0.707107;0.000000;-0.707107;, + 0.607458;-0.065403;-0.791655;, + 0.498929;-0.065403;-0.864171;, + 0.864171;0.065403;-0.498929;, + 0.793353;0.000000;-0.608761;, + 0.705593;-0.065403;-0.705593;, + 0.603553;-0.130526;-0.786566;, + 0.495722;-0.130526;-0.858616;, + 0.866025;0.000000;-0.500000;, + 0.791655;-0.065403;-0.607458;, + 0.701057;-0.130526;-0.701057;, + 0.597064;-0.195090;-0.778109;, + 0.490393;-0.195090;-0.849385;, + 0.864171;-0.065403;-0.498929;, + 0.786566;-0.130526;-0.603553;, + 0.693520;-0.195090;-0.693520;, + 0.588018;-0.258819;-0.766320;, + 0.482963;-0.258819;-0.836516;, + 0.858616;-0.130526;-0.495722;, + 0.778109;-0.195090;-0.597064;, + 0.683013;-0.258819;-0.683013;, + 0.576455;-0.321439;-0.751250;, + 0.473465;-0.321439;-0.820066;, + 0.849385;-0.195090;-0.490393;, + 0.766320;-0.258819;-0.588018;, + 0.669581;-0.321439;-0.669581;, + 0.562422;-0.382683;-0.732963;, + 0.461940;-0.382683;-0.800103;, + 0.836516;-0.258819;-0.482963;, + 0.751250;-0.321439;-0.576455;, + 0.653282;-0.382683;-0.653282;, + 0.448436;-0.442289;-0.776715;, + 0.820066;-0.321439;-0.473465;, + 0.732963;-0.382683;-0.562422;, + 0.800103;-0.382683;-0.461940;, + 0.343218;-0.442289;-0.828602;, + 0.353553;-0.382683;-0.853553;, + 0.362374;-0.321439;-0.874849;, + 0.224144;-0.500000;-0.836516;, + 0.232128;-0.442289;-0.866313;, + 0.239118;-0.382683;-0.892399;, + 0.245084;-0.321439;-0.914664;, + 0.369644;-0.258819;-0.892399;, + 0.113039;-0.500000;-0.858616;, + 0.117065;-0.442289;-0.889200;, + 0.120590;-0.382683;-0.915976;, + 0.123599;-0.321439;-0.938829;, + 0.250000;-0.258819;-0.933013;, + 0.375330;-0.195090;-0.906127;, + 0.000000;-0.500000;-0.866025;, + 0.000000;-0.442289;-0.896873;, + 0.000000;-0.382683;-0.923880;, + 0.000000;-0.321439;-0.946930;, + 0.126079;-0.258819;-0.957662;, + 0.253846;-0.195090;-0.947366;, + -0.113039;-0.500000;-0.858616;, + -0.117065;-0.442289;-0.889200;, + -0.120590;-0.382683;-0.915976;, + -0.123599;-0.321439;-0.938829;, + -0.126079;-0.258819;-0.957662;, + 0.000000;-0.258819;-0.965926;, + -0.224144;-0.500000;-0.836516;, + -0.232128;-0.442289;-0.866313;, + -0.239118;-0.382683;-0.892399;, + -0.245084;-0.321439;-0.914664;, + -0.250000;-0.258819;-0.933013;, + -0.331414;-0.500000;-0.800103;, + -0.343218;-0.442289;-0.828602;, + -0.353553;-0.382683;-0.853553;, + -0.362374;-0.321439;-0.874849;, + -0.369644;-0.258819;-0.892399;, + -0.433013;-0.500000;-0.750000;, + -0.448436;-0.442289;-0.776715;, + -0.461940;-0.382683;-0.800103;, + -0.473465;-0.321439;-0.820066;, + -0.482963;-0.258819;-0.836516;, + -0.527203;-0.500000;-0.687064;, + -0.545982;-0.442289;-0.711537;, + -0.562422;-0.382683;-0.732963;, + -0.576455;-0.321439;-0.751250;, + -0.588018;-0.258819;-0.766320;, + -0.597064;-0.195090;-0.778109;, + -0.490393;-0.195090;-0.849385;, + -0.375330;-0.195090;-0.906127;, + -0.603553;-0.130526;-0.786566;, + -0.495722;-0.130526;-0.858616;, + -0.379410;-0.130526;-0.915976;, + -0.253846;-0.195090;-0.947366;, + -0.128018;-0.195090;-0.972395;, + -0.607458;-0.065403;-0.791655;, + -0.498929;-0.065403;-0.864171;, + -0.381864;-0.065403;-0.921901;, + -0.256605;-0.130526;-0.957662;, + -0.129410;-0.130526;-0.982963;, + 0.000000;-0.195090;-0.980785;, + -0.608761;0.000000;-0.793353;, + -0.500000;0.000000;-0.866025;, + -0.382683;0.000000;-0.923880;, + -0.258265;-0.065403;-0.963858;, + -0.130247;-0.065403;-0.989322;, + 0.000000;-0.130526;-0.991445;, + -0.607458;0.065403;-0.791655;, + -0.498929;0.065403;-0.864171;, + -0.381864;0.065403;-0.921901;, + -0.258819;0.000000;-0.965926;, + -0.130526;0.000000;-0.991445;, + 0.000000;-0.065403;-0.997859;, + -0.603553;0.130526;-0.786566;, + -0.495722;0.130526;-0.858616;, + -0.379410;0.130526;-0.915976;, + -0.258265;0.065403;-0.963858;, + -0.130247;0.065403;-0.989322;, + 0.000000;0.000000;-1.000000;, + -0.597064;0.195090;-0.778109;, + -0.490393;0.195090;-0.849385;, + -0.375330;0.195090;-0.906127;, + -0.256605;0.130526;-0.957662;, + -0.588018;0.258819;-0.766320;, + -0.482963;0.258819;-0.836516;, + -0.576455;0.321439;-0.751250;, + 0.130526;0.000000;-0.991445;, + 0.130247;-0.065403;-0.989322;, + 0.129410;-0.130526;-0.982963;, + 0.258819;0.000000;-0.965926;, + 0.258265;-0.065403;-0.963858;, + 0.256605;-0.130526;-0.957662;, + 0.128018;-0.195090;-0.972395;, + 0.382683;0.000000;-0.923880;, + 0.381864;-0.065403;-0.921901;, + 0.379410;-0.130526;-0.915976;; + 4512; + 3;0,1,2;, + 3;3,1,0;, + 3;3,4,1;, + 3;4,5,1;, + 3;1,5,6;, + 3;7,0,2;, + 3;8,0,7;, + 3;8,3,0;, + 3;9,3,8;, + 3;9,10,3;, + 3;10,4,3;, + 3;10,11,4;, + 3;11,12,4;, + 3;4,12,5;, + 3;13,7,2;, + 3;14,7,13;, + 3;14,8,7;, + 3;15,8,14;, + 3;15,9,8;, + 3;16,9,15;, + 3;16,17,9;, + 3;17,10,9;, + 3;17,18,10;, + 3;18,11,10;, + 3;19,13,2;, + 3;20,13,19;, + 3;20,14,13;, + 3;21,14,20;, + 3;21,15,14;, + 3;22,15,21;, + 3;22,16,15;, + 3;23,16,22;, + 3;23,24,16;, + 3;24,17,16;, + 3;25,19,2;, + 3;26,19,25;, + 3;26,20,19;, + 3;27,20,26;, + 3;27,21,20;, + 3;28,21,27;, + 3;28,22,21;, + 3;29,22,28;, + 3;29,23,22;, + 3;25,2,30;, + 3;26,25,30;, + 3;26,30,31;, + 3;27,26,31;, + 3;27,31,32;, + 3;28,27,32;, + 3;28,32,33;, + 3;29,28,33;, + 3;29,33,34;, + 3;35,29,34;, + 3;35,23,29;, + 3;30,2,36;, + 3;31,30,36;, + 3;31,36,37;, + 3;32,31,37;, + 3;32,37,38;, + 3;33,32,38;, + 3;33,38,39;, + 3;34,33,39;, + 3;34,39,40;, + 3;41,34,40;, + 3;35,34,41;, + 3;36,2,42;, + 3;37,36,42;, + 3;37,42,43;, + 3;38,37,43;, + 3;38,43,44;, + 3;39,38,44;, + 3;39,44,45;, + 3;40,39,45;, + 3;40,45,46;, + 3;47,40,46;, + 3;41,40,47;, + 3;42,2,48;, + 3;43,42,48;, + 3;43,48,49;, + 3;44,43,49;, + 3;44,49,50;, + 3;45,44,50;, + 3;45,50,51;, + 3;46,45,51;, + 3;46,51,52;, + 3;53,46,52;, + 3;47,46,53;, + 3;48,2,54;, + 3;49,48,54;, + 3;49,54,55;, + 3;50,49,55;, + 3;50,55,56;, + 3;51,50,56;, + 3;51,56,57;, + 3;52,51,57;, + 3;52,57,58;, + 3;59,52,58;, + 3;53,52,59;, + 3;54,2,60;, + 3;55,54,60;, + 3;55,60,61;, + 3;56,55,61;, + 3;56,61,62;, + 3;57,56,62;, + 3;57,62,63;, + 3;58,57,63;, + 3;58,63,64;, + 3;65,58,64;, + 3;59,58,65;, + 3;60,2,66;, + 3;61,60,66;, + 3;61,66,67;, + 3;62,61,67;, + 3;62,67,68;, + 3;63,62,68;, + 3;63,68,69;, + 3;64,63,69;, + 3;64,69,70;, + 3;71,64,70;, + 3;65,64,71;, + 3;66,2,72;, + 3;67,66,72;, + 3;67,72,73;, + 3;68,67,73;, + 3;68,73,74;, + 3;69,68,74;, + 3;69,74,75;, + 3;70,69,75;, + 3;70,75,76;, + 3;77,70,76;, + 3;71,70,77;, + 3;72,2,78;, + 3;73,72,78;, + 3;73,78,79;, + 3;74,73,79;, + 3;74,79,80;, + 3;75,74,80;, + 3;75,80,81;, + 3;76,75,81;, + 3;76,81,82;, + 3;83,76,82;, + 3;77,76,83;, + 3;78,2,84;, + 3;79,78,84;, + 3;79,84,85;, + 3;80,79,85;, + 3;80,85,86;, + 3;81,80,86;, + 3;81,86,87;, + 3;82,81,87;, + 3;82,87,88;, + 3;89,82,88;, + 3;83,82,89;, + 3;84,2,90;, + 3;85,84,90;, + 3;85,90,91;, + 3;86,85,91;, + 3;86,91,92;, + 3;87,86,92;, + 3;87,92,93;, + 3;88,87,93;, + 3;88,93,94;, + 3;95,88,94;, + 3;89,88,95;, + 3;90,2,96;, + 3;91,90,96;, + 3;91,96,97;, + 3;92,91,97;, + 3;92,97,98;, + 3;93,92,98;, + 3;93,98,99;, + 3;94,93,99;, + 3;94,99,100;, + 3;101,94,100;, + 3;95,94,101;, + 3;96,2,102;, + 3;97,96,102;, + 3;97,102,103;, + 3;98,97,103;, + 3;98,103,104;, + 3;99,98,104;, + 3;99,104,105;, + 3;100,99,105;, + 3;100,105,106;, + 3;107,100,106;, + 3;101,100,107;, + 3;102,2,108;, + 3;103,102,108;, + 3;103,108,109;, + 3;104,103,109;, + 3;104,109,110;, + 3;105,104,110;, + 3;105,110,111;, + 3;106,105,111;, + 3;106,111,112;, + 3;113,106,112;, + 3;107,106,113;, + 3;108,2,114;, + 3;109,108,114;, + 3;109,114,115;, + 3;110,109,115;, + 3;110,115,116;, + 3;111,110,116;, + 3;111,116,117;, + 3;112,111,117;, + 3;112,117,118;, + 3;119,112,118;, + 3;113,112,119;, + 3;114,2,120;, + 3;115,114,120;, + 3;115,120,121;, + 3;116,115,121;, + 3;116,121,122;, + 3;117,116,122;, + 3;117,122,123;, + 3;118,117,123;, + 3;118,123,124;, + 3;125,118,124;, + 3;119,118,125;, + 3;120,2,126;, + 3;121,120,126;, + 3;121,126,127;, + 3;122,121,127;, + 3;122,127,128;, + 3;123,122,128;, + 3;123,128,129;, + 3;124,123,129;, + 3;124,129,130;, + 3;131,124,130;, + 3;125,124,131;, + 3;126,2,132;, + 3;127,126,132;, + 3;127,132,133;, + 3;128,127,133;, + 3;128,133,134;, + 3;129,128,134;, + 3;129,134,135;, + 3;130,129,135;, + 3;130,135,136;, + 3;137,130,136;, + 3;131,130,137;, + 3;132,2,138;, + 3;133,132,138;, + 3;133,138,139;, + 3;134,133,139;, + 3;134,139,140;, + 3;135,134,140;, + 3;135,140,141;, + 3;136,135,141;, + 3;136,141,142;, + 3;143,136,142;, + 3;137,136,143;, + 3;138,2,144;, + 3;139,138,144;, + 3;139,144,145;, + 3;140,139,145;, + 3;140,145,146;, + 3;141,140,146;, + 3;141,146,147;, + 3;142,141,147;, + 3;142,147,148;, + 3;149,142,148;, + 3;143,142,149;, + 3;144,2,150;, + 3;145,144,150;, + 3;145,150,151;, + 3;146,145,151;, + 3;146,151,152;, + 3;147,146,152;, + 3;147,152,153;, + 3;148,147,153;, + 3;148,153,154;, + 3;155,148,154;, + 3;149,148,155;, + 3;150,2,156;, + 3;151,150,156;, + 3;151,156,157;, + 3;152,151,157;, + 3;152,157,158;, + 3;153,152,158;, + 3;153,158,159;, + 3;154,153,159;, + 3;154,159,160;, + 3;161,154,160;, + 3;155,154,161;, + 3;156,2,162;, + 3;157,156,162;, + 3;157,162,163;, + 3;158,157,163;, + 3;158,163,164;, + 3;159,158,164;, + 3;159,164,165;, + 3;160,159,165;, + 3;160,165,166;, + 3;167,160,166;, + 3;161,160,167;, + 3;162,2,168;, + 3;163,162,168;, + 3;163,168,169;, + 3;164,163,169;, + 3;164,169,170;, + 3;165,164,170;, + 3;165,170,171;, + 3;166,165,171;, + 3;166,171,172;, + 3;173,166,172;, + 3;167,166,173;, + 3;174,167,173;, + 3;175,167,174;, + 3;175,161,167;, + 3;176,161,175;, + 3;176,155,161;, + 3;173,172,177;, + 3;178,173,177;, + 3;174,173,178;, + 3;179,174,178;, + 3;180,174,179;, + 3;180,175,174;, + 3;181,175,180;, + 3;181,176,175;, + 3;182,176,181;, + 3;182,183,176;, + 3;183,155,176;, + 3;183,149,155;, + 3;178,177,184;, + 3;185,178,184;, + 3;179,178,185;, + 3;186,179,185;, + 3;187,179,186;, + 3;187,180,179;, + 3;188,180,187;, + 3;188,181,180;, + 3;189,181,188;, + 3;189,182,181;, + 3;185,184,190;, + 3;191,185,190;, + 3;186,185,191;, + 3;192,186,191;, + 3;193,186,192;, + 3;193,187,186;, + 3;194,187,193;, + 3;194,188,187;, + 3;195,188,194;, + 3;195,189,188;, + 3;191,190,196;, + 3;197,191,196;, + 3;192,191,197;, + 3;198,192,197;, + 3;199,192,198;, + 3;199,193,192;, + 3;200,193,199;, + 3;200,194,193;, + 3;201,194,200;, + 3;201,195,194;, + 3;197,196,202;, + 3;203,197,202;, + 3;198,197,203;, + 3;204,198,203;, + 3;205,198,204;, + 3;205,199,198;, + 3;206,199,205;, + 3;206,200,199;, + 3;207,200,206;, + 3;207,201,200;, + 3;203,202,208;, + 3;209,203,208;, + 3;204,203,209;, + 3;210,204,209;, + 3;211,204,210;, + 3;211,205,204;, + 3;212,205,211;, + 3;212,206,205;, + 3;213,206,212;, + 3;213,207,206;, + 3;209,208,214;, + 3;215,209,214;, + 3;210,209,215;, + 3;216,210,215;, + 3;217,210,216;, + 3;217,211,210;, + 3;218,211,217;, + 3;218,212,211;, + 3;219,212,218;, + 3;219,213,212;, + 3;215,214,220;, + 3;221,215,220;, + 3;216,215,221;, + 3;222,216,221;, + 3;223,216,222;, + 3;223,217,216;, + 3;224,217,223;, + 3;224,218,217;, + 3;225,218,224;, + 3;225,219,218;, + 3;221,220,226;, + 3;227,221,226;, + 3;222,221,227;, + 3;228,222,227;, + 3;229,222,228;, + 3;229,223,222;, + 3;230,223,229;, + 3;230,224,223;, + 3;231,224,230;, + 3;231,225,224;, + 3;227,226,232;, + 3;233,227,232;, + 3;228,227,233;, + 3;234,228,233;, + 3;235,228,234;, + 3;235,229,228;, + 3;236,229,235;, + 3;236,230,229;, + 3;237,230,236;, + 3;237,231,230;, + 3;233,232,238;, + 3;239,233,238;, + 3;234,233,239;, + 3;240,234,239;, + 3;241,234,240;, + 3;241,235,234;, + 3;242,235,241;, + 3;242,236,235;, + 3;243,236,242;, + 3;243,237,236;, + 3;239,238,244;, + 3;245,239,244;, + 3;240,239,245;, + 3;246,240,245;, + 3;247,240,246;, + 3;247,241,240;, + 3;248,241,247;, + 3;248,242,241;, + 3;249,242,248;, + 3;249,243,242;, + 3;245,244,250;, + 3;251,245,250;, + 3;246,245,251;, + 3;252,246,251;, + 3;253,246,252;, + 3;253,247,246;, + 3;254,247,253;, + 3;254,248,247;, + 3;255,248,254;, + 3;255,249,248;, + 3;251,250,256;, + 3;257,251,256;, + 3;252,251,257;, + 3;258,252,257;, + 3;259,252,258;, + 3;259,253,252;, + 3;260,253,259;, + 3;260,254,253;, + 3;261,254,260;, + 3;261,255,254;, + 3;257,256,262;, + 3;263,257,262;, + 3;258,257,263;, + 3;264,258,263;, + 3;265,258,264;, + 3;265,259,258;, + 3;266,259,265;, + 3;266,260,259;, + 3;267,260,266;, + 3;267,261,260;, + 3;263,262,268;, + 3;269,263,268;, + 3;264,263,269;, + 3;270,264,269;, + 3;271,264,270;, + 3;271,265,264;, + 3;272,265,271;, + 3;272,266,265;, + 3;273,266,272;, + 3;273,267,266;, + 3;269,268,274;, + 3;275,269,274;, + 3;270,269,275;, + 3;276,270,275;, + 3;277,270,276;, + 3;277,271,270;, + 3;278,271,277;, + 3;278,272,271;, + 3;279,272,278;, + 3;279,273,272;, + 3;275,274,280;, + 3;281,275,280;, + 3;276,275,281;, + 3;282,276,281;, + 3;283,276,282;, + 3;283,277,276;, + 3;284,277,283;, + 3;284,278,277;, + 3;285,278,284;, + 3;285,279,278;, + 3;281,280,286;, + 3;287,281,286;, + 3;282,281,287;, + 3;288,282,287;, + 3;289,282,288;, + 3;289,283,282;, + 3;290,283,289;, + 3;290,284,283;, + 3;291,284,290;, + 3;291,285,284;, + 3;287,286,292;, + 3;293,287,292;, + 3;288,287,293;, + 3;294,288,293;, + 3;295,288,294;, + 3;295,289,288;, + 3;296,289,295;, + 3;296,290,289;, + 3;297,290,296;, + 3;297,291,290;, + 3;293,292,298;, + 3;299,293,298;, + 3;294,293,299;, + 3;300,294,299;, + 3;301,294,300;, + 3;301,295,294;, + 3;302,295,301;, + 3;302,296,295;, + 3;303,296,302;, + 3;303,297,296;, + 3;299,298,304;, + 3;305,299,304;, + 3;300,299,305;, + 3;306,300,305;, + 3;307,300,306;, + 3;307,301,300;, + 3;308,301,307;, + 3;308,302,301;, + 3;309,302,308;, + 3;309,303,302;, + 3;305,304,310;, + 3;311,305,310;, + 3;306,305,311;, + 3;312,306,311;, + 3;313,306,312;, + 3;313,307,306;, + 3;314,307,313;, + 3;314,308,307;, + 3;315,308,314;, + 3;315,309,308;, + 3;311,310,316;, + 3;317,311,316;, + 3;312,311,317;, + 3;318,312,317;, + 3;319,312,318;, + 3;319,313,312;, + 3;320,313,319;, + 3;320,314,313;, + 3;321,314,320;, + 3;321,315,314;, + 3;317,316,322;, + 3;323,317,322;, + 3;318,317,323;, + 3;324,318,323;, + 3;325,318,324;, + 3;325,319,318;, + 3;326,319,325;, + 3;326,320,319;, + 3;327,320,326;, + 3;327,321,320;, + 3;323,322,328;, + 3;329,323,328;, + 3;324,323,329;, + 3;330,324,329;, + 3;331,324,330;, + 3;331,325,324;, + 3;332,325,331;, + 3;332,326,325;, + 3;333,326,332;, + 3;333,327,326;, + 3;329,328,334;, + 3;335,329,334;, + 3;330,329,335;, + 3;336,330,335;, + 3;337,330,336;, + 3;337,331,330;, + 3;338,331,337;, + 3;338,332,331;, + 3;339,332,338;, + 3;339,333,332;, + 3;335,334,340;, + 3;341,335,340;, + 3;336,335,341;, + 3;342,336,341;, + 3;343,336,342;, + 3;343,337,336;, + 3;344,337,343;, + 3;344,338,337;, + 3;345,338,344;, + 3;345,339,338;, + 3;341,340,346;, + 3;347,341,346;, + 3;342,341,347;, + 3;348,342,347;, + 3;349,342,348;, + 3;349,343,342;, + 3;350,343,349;, + 3;350,344,343;, + 3;351,344,350;, + 3;351,345,344;, + 3;347,346,352;, + 3;353,347,352;, + 3;348,347,353;, + 3;354,348,353;, + 3;355,348,354;, + 3;355,349,348;, + 3;356,349,355;, + 3;356,350,349;, + 3;357,350,356;, + 3;357,351,350;, + 3;353,352,358;, + 3;359,353,358;, + 3;354,353,359;, + 3;360,354,359;, + 3;361,354,360;, + 3;361,355,354;, + 3;362,355,361;, + 3;362,356,355;, + 3;363,356,362;, + 3;363,357,356;, + 3;359,358,364;, + 3;365,359,364;, + 3;360,359,365;, + 3;366,360,365;, + 3;367,360,366;, + 3;367,361,360;, + 3;368,361,367;, + 3;368,362,361;, + 3;369,362,368;, + 3;369,363,362;, + 3;365,364,370;, + 3;371,365,370;, + 3;366,365,371;, + 3;372,366,371;, + 3;373,366,372;, + 3;373,367,366;, + 3;374,367,373;, + 3;374,368,367;, + 3;375,368,374;, + 3;375,369,368;, + 3;371,370,376;, + 3;377,371,376;, + 3;372,371,377;, + 3;378,372,377;, + 3;379,372,378;, + 3;379,373,372;, + 3;380,373,379;, + 3;380,374,373;, + 3;381,374,380;, + 3;381,375,374;, + 3;377,376,382;, + 3;383,377,382;, + 3;378,377,383;, + 3;384,378,383;, + 3;385,378,384;, + 3;385,379,378;, + 3;386,379,385;, + 3;386,380,379;, + 3;387,380,386;, + 3;387,381,380;, + 3;383,382,388;, + 3;389,383,388;, + 3;384,383,389;, + 3;390,384,389;, + 3;391,384,390;, + 3;391,385,384;, + 3;392,385,391;, + 3;392,386,385;, + 3;393,386,392;, + 3;393,387,386;, + 3;389,388,394;, + 3;395,389,394;, + 3;390,389,395;, + 3;396,390,395;, + 3;397,390,396;, + 3;397,391,390;, + 3;398,391,397;, + 3;398,392,391;, + 3;399,392,398;, + 3;399,393,392;, + 3;395,394,400;, + 3;401,395,400;, + 3;396,395,401;, + 3;402,396,401;, + 3;403,396,402;, + 3;403,397,396;, + 3;404,397,403;, + 3;404,398,397;, + 3;405,398,404;, + 3;405,399,398;, + 3;401,400,406;, + 3;407,401,406;, + 3;402,401,407;, + 3;408,402,407;, + 3;409,402,408;, + 3;409,403,402;, + 3;410,403,409;, + 3;410,404,403;, + 3;411,404,410;, + 3;411,405,404;, + 3;407,406,412;, + 3;413,407,412;, + 3;408,407,413;, + 3;414,408,413;, + 3;415,408,414;, + 3;415,409,408;, + 3;416,409,415;, + 3;416,410,409;, + 3;417,410,416;, + 3;417,411,410;, + 3;413,412,418;, + 3;419,413,418;, + 3;414,413,419;, + 3;420,414,419;, + 3;420,415,414;, + 3;420,416,415;, + 3;420,417,416;, + 3;420,421,417;, + 3;421,411,417;, + 3;421,422,411;, + 3;422,405,411;, + 3;419,418,423;, + 3;420,419,423;, + 3;422,424,405;, + 3;425,424,422;, + 3;425,426,424;, + 3;426,427,424;, + 3;424,427,399;, + 3;424,399,405;, + 3;428,425,422;, + 3;429,425,428;, + 3;429,430,425;, + 3;430,426,425;, + 3;430,431,426;, + 3;431,432,426;, + 3;426,432,427;, + 3;428,422,421;, + 3;420,428,421;, + 3;420,429,428;, + 3;420,433,429;, + 3;433,430,429;, + 3;433,434,430;, + 3;434,431,430;, + 3;434,435,431;, + 3;435,436,431;, + 3;431,436,432;, + 3;436,437,432;, + 3;432,437,438;, + 3;432,438,427;, + 3;420,439,433;, + 3;439,434,433;, + 3;439,440,434;, + 3;440,435,434;, + 3;440,441,435;, + 3;441,442,435;, + 3;435,442,436;, + 3;442,443,436;, + 3;436,443,437;, + 3;420,444,439;, + 3;444,440,439;, + 3;444,445,440;, + 3;445,441,440;, + 3;445,446,441;, + 3;446,447,441;, + 3;441,447,442;, + 3;447,448,442;, + 3;442,448,443;, + 3;420,449,444;, + 3;449,445,444;, + 3;449,450,445;, + 3;450,446,445;, + 3;450,451,446;, + 3;451,452,446;, + 3;446,452,447;, + 3;452,453,447;, + 3;447,453,448;, + 3;420,454,449;, + 3;454,450,449;, + 3;454,455,450;, + 3;455,451,450;, + 3;455,456,451;, + 3;456,457,451;, + 3;451,457,452;, + 3;457,458,452;, + 3;452,458,453;, + 3;420,459,454;, + 3;459,455,454;, + 3;459,460,455;, + 3;460,456,455;, + 3;460,461,456;, + 3;461,462,456;, + 3;456,462,457;, + 3;462,463,457;, + 3;457,463,458;, + 3;420,464,459;, + 3;464,460,459;, + 3;464,465,460;, + 3;465,461,460;, + 3;465,466,461;, + 3;466,467,461;, + 3;461,467,462;, + 3;467,468,462;, + 3;462,468,463;, + 3;420,469,464;, + 3;469,465,464;, + 3;469,470,465;, + 3;470,466,465;, + 3;470,471,466;, + 3;471,472,466;, + 3;466,472,467;, + 3;472,473,467;, + 3;467,473,468;, + 3;420,474,469;, + 3;474,470,469;, + 3;474,475,470;, + 3;475,471,470;, + 3;475,476,471;, + 3;476,477,471;, + 3;471,477,472;, + 3;477,478,472;, + 3;472,478,473;, + 3;420,479,474;, + 3;479,475,474;, + 3;479,480,475;, + 3;480,476,475;, + 3;480,481,476;, + 3;481,482,476;, + 3;476,482,477;, + 3;482,483,477;, + 3;477,483,478;, + 3;420,484,479;, + 3;484,480,479;, + 3;484,485,480;, + 3;485,481,480;, + 3;485,486,481;, + 3;486,487,481;, + 3;481,487,482;, + 3;487,488,482;, + 3;482,488,483;, + 3;420,489,484;, + 3;489,485,484;, + 3;489,490,485;, + 3;490,486,485;, + 3;490,491,486;, + 3;491,492,486;, + 3;486,492,487;, + 3;492,493,487;, + 3;487,493,488;, + 3;420,494,489;, + 3;494,490,489;, + 3;494,495,490;, + 3;495,491,490;, + 3;495,496,491;, + 3;496,497,491;, + 3;491,497,492;, + 3;497,498,492;, + 3;492,498,493;, + 3;420,499,494;, + 3;499,495,494;, + 3;499,500,495;, + 3;500,496,495;, + 3;500,501,496;, + 3;501,502,496;, + 3;496,502,497;, + 3;502,503,497;, + 3;497,503,498;, + 3;420,504,499;, + 3;504,500,499;, + 3;504,505,500;, + 3;505,501,500;, + 3;505,506,501;, + 3;506,507,501;, + 3;501,507,502;, + 3;507,508,502;, + 3;502,508,503;, + 3;420,509,504;, + 3;509,505,504;, + 3;509,510,505;, + 3;510,506,505;, + 3;510,511,506;, + 3;511,512,506;, + 3;506,512,507;, + 3;512,513,507;, + 3;507,513,508;, + 3;513,514,508;, + 3;508,514,515;, + 3;508,515,503;, + 3;509,516,510;, + 3;510,516,517;, + 3;510,517,511;, + 3;511,517,518;, + 3;511,518,519;, + 3;511,519,512;, + 3;519,520,512;, + 3;512,520,513;, + 3;520,521,513;, + 3;513,521,514;, + 3;509,522,516;, + 3;522,523,516;, + 3;516,523,524;, + 3;516,524,517;, + 3;517,524,525;, + 3;517,525,518;, + 3;518,525,526;, + 3;518,526,527;, + 3;519,518,527;, + 3;528,522,509;, + 3;528,529,522;, + 3;522,529,523;, + 3;529,530,523;, + 3;523,530,531;, + 3;523,531,524;, + 3;524,531,532;, + 3;524,532,525;, + 3;525,532,533;, + 3;525,533,526;, + 3;528,534,529;, + 3;529,534,530;, + 3;534,535,530;, + 3;530,535,536;, + 3;530,536,531;, + 3;531,536,537;, + 3;531,537,532;, + 3;532,537,538;, + 3;532,538,533;, + 3;528,539,534;, + 3;534,539,535;, + 3;539,540,535;, + 3;535,540,541;, + 3;535,541,536;, + 3;536,541,542;, + 3;536,542,537;, + 3;537,542,543;, + 3;537,543,538;, + 3;528,544,539;, + 3;539,544,540;, + 3;544,545,540;, + 3;540,545,546;, + 3;540,546,541;, + 3;541,546,547;, + 3;541,547,542;, + 3;542,547,548;, + 3;542,548,543;, + 3;528,549,544;, + 3;544,549,545;, + 3;549,550,545;, + 3;545,550,551;, + 3;545,551,546;, + 3;546,551,552;, + 3;546,552,547;, + 3;547,552,553;, + 3;547,553,548;, + 3;528,554,549;, + 3;549,554,550;, + 3;554,555,550;, + 3;550,555,556;, + 3;550,556,551;, + 3;551,556,557;, + 3;551,557,552;, + 3;552,557,558;, + 3;552,558,553;, + 3;528,559,554;, + 3;554,559,555;, + 3;559,560,555;, + 3;555,560,561;, + 3;555,561,556;, + 3;556,561,562;, + 3;556,562,557;, + 3;557,562,563;, + 3;557,563,558;, + 3;528,564,559;, + 3;559,564,560;, + 3;564,565,560;, + 3;560,565,566;, + 3;560,566,561;, + 3;561,566,567;, + 3;561,567,562;, + 3;562,567,568;, + 3;562,568,563;, + 3;528,569,564;, + 3;564,569,565;, + 3;569,570,565;, + 3;565,570,571;, + 3;565,571,566;, + 3;566,571,572;, + 3;566,572,567;, + 3;567,572,573;, + 3;567,573,568;, + 3;528,574,569;, + 3;569,574,570;, + 3;574,575,570;, + 3;570,575,576;, + 3;570,576,571;, + 3;571,576,577;, + 3;571,577,572;, + 3;572,577,578;, + 3;572,578,573;, + 3;528,579,574;, + 3;574,579,575;, + 3;579,580,575;, + 3;575,580,581;, + 3;575,581,576;, + 3;576,581,582;, + 3;576,582,577;, + 3;577,582,583;, + 3;577,583,578;, + 3;528,584,579;, + 3;579,584,580;, + 3;584,585,580;, + 3;580,585,586;, + 3;580,586,581;, + 3;581,586,587;, + 3;581,587,582;, + 3;582,587,588;, + 3;582,588,583;, + 3;528,589,584;, + 3;584,589,585;, + 3;589,590,585;, + 3;585,590,591;, + 3;585,591,586;, + 3;586,591,592;, + 3;586,592,587;, + 3;587,592,593;, + 3;587,593,588;, + 3;528,594,589;, + 3;589,594,590;, + 3;594,595,590;, + 3;590,595,596;, + 3;590,596,591;, + 3;591,596,597;, + 3;591,597,592;, + 3;592,597,598;, + 3;592,598,593;, + 3;528,599,594;, + 3;594,599,595;, + 3;599,600,595;, + 3;595,600,601;, + 3;595,601,596;, + 3;596,601,602;, + 3;596,602,597;, + 3;597,602,603;, + 3;597,603,598;, + 3;528,604,599;, + 3;599,604,600;, + 3;604,605,600;, + 3;600,605,606;, + 3;600,606,601;, + 3;601,606,607;, + 3;601,607,602;, + 3;602,607,608;, + 3;602,608,603;, + 3;528,609,604;, + 3;604,609,605;, + 3;609,610,605;, + 3;605,610,611;, + 3;605,611,606;, + 3;606,611,612;, + 3;606,612,607;, + 3;607,612,613;, + 3;607,613,608;, + 3;528,614,609;, + 3;609,614,610;, + 3;614,615,610;, + 3;610,615,616;, + 3;610,616,611;, + 3;611,616,617;, + 3;611,617,612;, + 3;612,617,618;, + 3;612,618,613;, + 3;528,619,614;, + 3;614,619,615;, + 3;619,620,615;, + 3;615,620,621;, + 3;615,621,616;, + 3;616,621,622;, + 3;616,622,617;, + 3;617,622,623;, + 3;617,623,618;, + 3;528,624,619;, + 3;619,624,620;, + 3;624,625,620;, + 3;620,625,626;, + 3;620,626,621;, + 3;621,626,627;, + 3;621,627,622;, + 3;622,627,628;, + 3;622,628,623;, + 3;528,629,624;, + 3;624,629,625;, + 3;629,630,625;, + 3;625,630,631;, + 3;625,631,626;, + 3;626,631,632;, + 3;626,632,627;, + 3;627,632,633;, + 3;627,633,628;, + 3;528,634,629;, + 3;629,634,630;, + 3;634,635,630;, + 3;630,635,636;, + 3;630,636,631;, + 3;631,636,637;, + 3;631,637,632;, + 3;632,637,638;, + 3;632,638,633;, + 3;528,639,634;, + 3;634,639,635;, + 3;633,638,640;, + 3;633,640,641;, + 3;628,633,641;, + 3;628,641,642;, + 3;623,628,642;, + 3;623,642,643;, + 3;618,623,643;, + 3;641,640,644;, + 3;641,644,645;, + 3;642,641,645;, + 3;642,645,646;, + 3;643,642,646;, + 3;643,646,647;, + 3;648,643,647;, + 3;618,643,648;, + 3;613,618,648;, + 3;613,648,649;, + 3;608,613,649;, + 3;645,644,650;, + 3;645,650,651;, + 3;646,645,651;, + 3;646,651,652;, + 3;647,646,652;, + 3;647,652,653;, + 3;654,647,653;, + 3;648,647,654;, + 3;649,648,654;, + 3;649,654,655;, + 3;656,649,655;, + 3;608,649,656;, + 3;603,608,656;, + 3;651,650,657;, + 3;651,657,658;, + 3;652,651,658;, + 3;652,658,659;, + 3;653,652,659;, + 3;653,659,660;, + 3;661,653,660;, + 3;654,653,661;, + 3;655,654,661;, + 3;655,661,662;, + 3;663,655,662;, + 3;656,655,663;, + 3;658,657,664;, + 3;658,664,665;, + 3;659,658,665;, + 3;659,665,666;, + 3;660,659,666;, + 3;660,666,667;, + 3;668,660,667;, + 3;661,660,668;, + 3;662,661,668;, + 3;662,668,669;, + 3;670,662,669;, + 3;663,662,670;, + 3;665,664,671;, + 3;665,671,672;, + 3;666,665,672;, + 3;666,672,673;, + 3;667,666,673;, + 3;667,673,674;, + 3;675,667,674;, + 3;668,667,675;, + 3;669,668,675;, + 3;669,675,676;, + 3;677,669,676;, + 3;670,669,677;, + 3;672,671,678;, + 3;672,678,679;, + 3;673,672,679;, + 3;673,679,680;, + 3;674,673,680;, + 3;674,680,681;, + 3;682,674,681;, + 3;675,674,682;, + 3;676,675,682;, + 3;676,682,683;, + 3;684,676,683;, + 3;677,676,684;, + 3;679,678,685;, + 3;679,685,686;, + 3;680,679,686;, + 3;680,686,687;, + 3;681,680,687;, + 3;681,687,688;, + 3;689,681,688;, + 3;682,681,689;, + 3;683,682,689;, + 3;683,689,690;, + 3;691,683,690;, + 3;684,683,691;, + 3;686,685,692;, + 3;686,692,693;, + 3;687,686,693;, + 3;687,693,694;, + 3;688,687,694;, + 3;688,694,695;, + 3;696,688,695;, + 3;689,688,696;, + 3;690,689,696;, + 3;690,696,697;, + 3;698,690,697;, + 3;691,690,698;, + 3;693,692,699;, + 3;693,699,700;, + 3;694,693,700;, + 3;694,700,701;, + 3;695,694,701;, + 3;695,701,702;, + 3;703,695,702;, + 3;696,695,703;, + 3;697,696,703;, + 3;697,703,704;, + 3;705,697,704;, + 3;698,697,705;, + 3;700,699,706;, + 3;700,706,707;, + 3;701,700,707;, + 3;701,707,708;, + 3;702,701,708;, + 3;702,708,709;, + 3;710,702,709;, + 3;703,702,710;, + 3;704,703,710;, + 3;704,710,711;, + 3;712,704,711;, + 3;705,704,712;, + 3;707,706,713;, + 3;707,713,714;, + 3;708,707,714;, + 3;708,714,715;, + 3;709,708,715;, + 3;709,715,716;, + 3;717,709,716;, + 3;710,709,717;, + 3;711,710,717;, + 3;711,717,718;, + 3;719,711,718;, + 3;712,711,719;, + 3;714,713,720;, + 3;714,720,721;, + 3;715,714,721;, + 3;715,721,722;, + 3;716,715,722;, + 3;716,722,723;, + 3;724,716,723;, + 3;717,716,724;, + 3;718,717,724;, + 3;718,724,725;, + 3;726,718,725;, + 3;719,718,726;, + 3;721,720,727;, + 3;721,727,728;, + 3;722,721,728;, + 3;722,728,729;, + 3;723,722,729;, + 3;723,729,730;, + 3;731,723,730;, + 3;724,723,731;, + 3;725,724,731;, + 3;725,731,732;, + 3;733,725,732;, + 3;726,725,733;, + 3;728,727,734;, + 3;728,734,735;, + 3;729,728,735;, + 3;729,735,736;, + 3;730,729,736;, + 3;730,736,737;, + 3;738,730,737;, + 3;731,730,738;, + 3;732,731,738;, + 3;732,738,739;, + 3;740,732,739;, + 3;733,732,740;, + 3;735,734,741;, + 3;735,741,742;, + 3;736,735,742;, + 3;736,742,743;, + 3;737,736,743;, + 3;737,743,744;, + 3;745,737,744;, + 3;738,737,745;, + 3;739,738,745;, + 3;739,745,746;, + 3;747,739,746;, + 3;740,739,747;, + 3;742,741,748;, + 3;742,748,749;, + 3;743,742,749;, + 3;743,749,750;, + 3;744,743,750;, + 3;744,750,751;, + 3;752,744,751;, + 3;745,744,752;, + 3;746,745,752;, + 3;746,752,753;, + 3;754,746,753;, + 3;747,746,754;, + 3;749,748,755;, + 3;749,755,756;, + 3;750,749,756;, + 3;750,756,757;, + 3;751,750,757;, + 3;751,757,758;, + 3;759,751,758;, + 3;752,751,759;, + 3;753,752,759;, + 3;753,759,760;, + 3;761,753,760;, + 3;754,753,761;, + 3;756,755,762;, + 3;756,762,763;, + 3;757,756,763;, + 3;757,763,764;, + 3;758,757,764;, + 3;758,764,765;, + 3;766,758,765;, + 3;759,758,766;, + 3;760,759,766;, + 3;760,766,767;, + 3;768,760,767;, + 3;761,760,768;, + 3;763,762,769;, + 3;763,769,770;, + 3;764,763,770;, + 3;764,770,771;, + 3;765,764,771;, + 3;765,771,772;, + 3;773,765,772;, + 3;766,765,773;, + 3;767,766,773;, + 3;767,773,774;, + 3;775,767,774;, + 3;768,767,775;, + 3;770,769,776;, + 3;770,776,777;, + 3;771,770,777;, + 3;771,777,778;, + 3;772,771,778;, + 3;772,778,779;, + 3;780,772,779;, + 3;773,772,780;, + 3;774,773,780;, + 3;774,780,781;, + 3;782,774,781;, + 3;775,774,782;, + 3;777,776,783;, + 3;777,783,784;, + 3;778,777,784;, + 3;778,784,785;, + 3;779,778,785;, + 3;779,785,786;, + 3;787,779,786;, + 3;780,779,787;, + 3;781,780,787;, + 3;781,787,788;, + 3;789,781,788;, + 3;782,781,789;, + 3;784,783,790;, + 3;784,790,791;, + 3;785,784,791;, + 3;785,791,792;, + 3;786,785,792;, + 3;786,792,793;, + 3;794,786,793;, + 3;787,786,794;, + 3;788,787,794;, + 3;788,794,795;, + 3;796,788,795;, + 3;789,788,796;, + 3;791,790,797;, + 3;791,797,798;, + 3;792,791,798;, + 3;792,798,799;, + 3;793,792,799;, + 3;793,799,800;, + 3;801,793,800;, + 3;794,793,801;, + 3;795,794,801;, + 3;795,801,802;, + 3;803,795,802;, + 3;796,795,803;, + 3;798,797,804;, + 3;798,804,805;, + 3;799,798,805;, + 3;799,805,806;, + 3;800,799,806;, + 3;800,806,807;, + 3;808,800,807;, + 3;801,800,808;, + 3;802,801,808;, + 3;802,808,809;, + 3;810,802,809;, + 3;803,802,810;, + 3;805,804,811;, + 3;805,811,812;, + 3;806,805,812;, + 3;806,812,813;, + 3;807,806,813;, + 3;807,813,814;, + 3;815,807,814;, + 3;808,807,815;, + 3;809,808,815;, + 3;809,815,816;, + 3;817,809,816;, + 3;810,809,817;, + 3;812,811,818;, + 3;812,818,819;, + 3;813,812,819;, + 3;813,819,820;, + 3;814,813,820;, + 3;814,820,821;, + 3;822,814,821;, + 3;815,814,822;, + 3;816,815,822;, + 3;816,822,823;, + 3;824,816,823;, + 3;817,816,824;, + 3;819,818,825;, + 3;819,825,826;, + 3;820,819,826;, + 3;820,826,827;, + 3;821,820,827;, + 3;821,827,828;, + 3;829,821,828;, + 3;822,821,829;, + 3;823,822,829;, + 3;823,829,830;, + 3;831,823,830;, + 3;824,823,831;, + 3;826,825,832;, + 3;826,832,833;, + 3;827,826,833;, + 3;827,833,834;, + 3;828,827,834;, + 3;828,834,835;, + 3;836,828,835;, + 3;829,828,836;, + 3;830,829,836;, + 3;830,836,837;, + 3;838,830,837;, + 3;831,830,838;, + 3;833,832,839;, + 3;833,839,840;, + 3;834,833,840;, + 3;834,840,841;, + 3;835,834,841;, + 3;835,841,842;, + 3;843,835,842;, + 3;836,835,843;, + 3;837,836,843;, + 3;837,843,844;, + 3;845,837,844;, + 3;838,837,845;, + 3;840,839,846;, + 3;840,846,847;, + 3;841,840,847;, + 3;841,847,848;, + 3;842,841,848;, + 3;842,848,849;, + 3;850,842,849;, + 3;843,842,850;, + 3;844,843,850;, + 3;844,850,851;, + 3;852,844,851;, + 3;845,844,852;, + 3;847,846,853;, + 3;847,853,854;, + 3;848,847,854;, + 3;848,854,855;, + 3;849,848,855;, + 3;849,855,856;, + 3;857,849,856;, + 3;850,849,857;, + 3;851,850,857;, + 3;851,857,858;, + 3;859,851,858;, + 3;852,851,859;, + 3;854,853,860;, + 3;854,860,861;, + 3;855,854,861;, + 3;855,861,862;, + 3;856,855,862;, + 3;856,862,863;, + 3;864,856,863;, + 3;857,856,864;, + 3;858,857,864;, + 3;858,864,865;, + 3;866,858,865;, + 3;859,858,866;, + 3;861,860,867;, + 3;861,867,868;, + 3;862,861,868;, + 3;862,868,869;, + 3;863,862,869;, + 3;863,869,870;, + 3;871,863,870;, + 3;864,863,871;, + 3;865,864,871;, + 3;865,871,872;, + 3;873,865,872;, + 3;866,865,873;, + 3;868,867,874;, + 3;868,874,875;, + 3;869,868,875;, + 3;869,875,876;, + 3;870,869,876;, + 3;870,876,877;, + 3;878,870,877;, + 3;871,870,878;, + 3;872,871,878;, + 3;872,878,879;, + 3;880,872,879;, + 3;873,872,880;, + 3;875,874,881;, + 3;875,881,882;, + 3;876,875,882;, + 3;876,882,883;, + 3;877,876,883;, + 3;877,883,884;, + 3;885,877,884;, + 3;878,877,885;, + 3;879,878,885;, + 3;879,885,886;, + 3;887,879,886;, + 3;880,879,887;, + 3;882,881,888;, + 3;882,888,889;, + 3;883,882,889;, + 3;883,889,890;, + 3;884,883,890;, + 3;884,890,891;, + 3;892,884,891;, + 3;885,884,892;, + 3;886,885,892;, + 3;886,892,893;, + 3;894,886,893;, + 3;887,886,894;, + 3;889,888,895;, + 3;889,895,896;, + 3;890,889,896;, + 3;890,896,897;, + 3;891,890,897;, + 3;891,897,898;, + 3;899,891,898;, + 3;892,891,899;, + 3;893,892,899;, + 3;893,899,900;, + 3;901,893,900;, + 3;894,893,901;, + 3;896,895,902;, + 3;896,902,903;, + 3;897,896,903;, + 3;897,903,904;, + 3;898,897,904;, + 3;898,904,905;, + 3;906,898,905;, + 3;899,898,906;, + 3;900,899,906;, + 3;900,906,907;, + 3;908,900,907;, + 3;901,900,908;, + 3;903,902,909;, + 3;903,909,910;, + 3;904,903,910;, + 3;904,910,911;, + 3;905,904,911;, + 3;905,911,912;, + 3;913,905,912;, + 3;906,905,913;, + 3;907,906,913;, + 3;907,913,914;, + 3;915,907,914;, + 3;908,907,915;, + 3;910,909,916;, + 3;910,916,917;, + 3;911,910,917;, + 3;911,917,918;, + 3;912,911,918;, + 3;912,918,919;, + 3;920,912,919;, + 3;913,912,920;, + 3;914,913,920;, + 3;914,920,921;, + 3;922,914,921;, + 3;915,914,922;, + 3;917,916,923;, + 3;917,923,924;, + 3;918,917,924;, + 3;918,924,925;, + 3;919,918,925;, + 3;919,925,926;, + 3;927,919,926;, + 3;920,919,927;, + 3;921,920,927;, + 3;921,927,928;, + 3;929,921,928;, + 3;922,921,929;, + 3;924,923,6;, + 3;925,924,6;, + 3;926,925,6;, + 3;930,926,6;, + 3;927,926,930;, + 3;928,927,930;, + 3;928,930,931;, + 3;932,928,931;, + 3;929,928,932;, + 3;933,929,932;, + 3;934,929,933;, + 3;934,922,929;, + 3;931,930,6;, + 3;935,931,6;, + 3;932,931,935;, + 3;936,932,935;, + 3;933,932,936;, + 3;937,933,936;, + 3;938,933,937;, + 3;938,934,933;, + 3;939,934,938;, + 3;939,940,934;, + 3;940,922,934;, + 3;940,915,922;, + 3;941,935,6;, + 3;936,935,941;, + 3;942,936,941;, + 3;937,936,942;, + 3;943,937,942;, + 3;944,937,943;, + 3;944,938,937;, + 3;945,938,944;, + 3;945,939,938;, + 3;946,941,6;, + 3;942,941,946;, + 3;947,942,946;, + 3;943,942,947;, + 3;948,943,947;, + 3;949,943,948;, + 3;949,944,943;, + 3;950,944,949;, + 3;950,945,944;, + 3;951,946,6;, + 3;947,946,951;, + 3;952,947,951;, + 3;948,947,952;, + 3;953,948,952;, + 3;954,948,953;, + 3;954,949,948;, + 3;955,949,954;, + 3;955,950,949;, + 3;956,951,6;, + 3;952,951,956;, + 3;957,952,956;, + 3;953,952,957;, + 3;958,953,957;, + 3;959,953,958;, + 3;959,954,953;, + 3;960,954,959;, + 3;960,955,954;, + 3;961,956,6;, + 3;957,956,961;, + 3;962,957,961;, + 3;958,957,962;, + 3;963,958,962;, + 3;964,958,963;, + 3;964,959,958;, + 3;965,959,964;, + 3;965,960,959;, + 3;966,961,6;, + 3;962,961,966;, + 3;967,962,966;, + 3;963,962,967;, + 3;968,963,967;, + 3;969,963,968;, + 3;969,964,963;, + 3;970,964,969;, + 3;970,965,964;, + 3;971,966,6;, + 3;967,966,971;, + 3;972,967,971;, + 3;968,967,972;, + 3;973,968,972;, + 3;974,968,973;, + 3;974,969,968;, + 3;975,969,974;, + 3;975,970,969;, + 3;976,971,6;, + 3;972,971,976;, + 3;977,972,976;, + 3;973,972,977;, + 3;978,973,977;, + 3;979,973,978;, + 3;979,974,973;, + 3;980,974,979;, + 3;980,975,974;, + 3;981,976,6;, + 3;977,976,981;, + 3;982,977,981;, + 3;978,977,982;, + 3;983,978,982;, + 3;984,978,983;, + 3;984,979,978;, + 3;985,979,984;, + 3;985,980,979;, + 3;986,981,6;, + 3;982,981,986;, + 3;987,982,986;, + 3;983,982,987;, + 3;988,983,987;, + 3;989,983,988;, + 3;989,984,983;, + 3;990,984,989;, + 3;990,985,984;, + 3;991,986,6;, + 3;987,986,991;, + 3;12,987,991;, + 3;988,987,12;, + 3;11,988,12;, + 3;992,988,11;, + 3;992,989,988;, + 3;993,989,992;, + 3;993,990,989;, + 3;5,991,6;, + 3;12,991,5;, + 3;18,992,11;, + 3;994,992,18;, + 3;994,993,992;, + 3;995,993,994;, + 3;995,996,993;, + 3;996,990,993;, + 3;996,997,990;, + 3;997,985,990;, + 3;998,994,18;, + 3;999,994,998;, + 3;999,995,994;, + 3;1000,995,999;, + 3;1000,1001,995;, + 3;1001,996,995;, + 3;1001,1002,996;, + 3;1002,997,996;, + 3;998,18,17;, + 3;24,998,17;, + 3;1003,998,24;, + 3;1003,999,998;, + 3;1004,999,1003;, + 3;1004,1000,999;, + 3;1005,1000,1004;, + 3;1005,1006,1000;, + 3;1006,1001,1000;, + 3;1006,1007,1001;, + 3;1007,1002,1001;, + 3;1008,1003,24;, + 3;1009,1003,1008;, + 3;1009,1004,1003;, + 3;1010,1004,1009;, + 3;1010,1005,1004;, + 3;1011,1005,1010;, + 3;1011,1012,1005;, + 3;1012,1006,1005;, + 3;1012,1013,1006;, + 3;1013,1007,1006;, + 3;1008,24,23;, + 3;35,1008,23;, + 3;1014,1008,35;, + 3;1014,1009,1008;, + 3;1015,1009,1014;, + 3;1015,1010,1009;, + 3;1016,1010,1015;, + 3;1016,1011,1010;, + 3;1017,1011,1016;, + 3;1017,1018,1011;, + 3;1018,1012,1011;, + 3;1018,1019,1012;, + 3;1019,1013,1012;, + 3;1014,35,41;, + 3;1014,41,1020;, + 3;1015,1014,1020;, + 3;1015,1020,1021;, + 3;1016,1015,1021;, + 3;1016,1021,1022;, + 3;1017,1016,1022;, + 3;1017,1022,1023;, + 3;1024,1017,1023;, + 3;1024,1018,1017;, + 3;1024,1025,1018;, + 3;1025,1019,1018;, + 3;1020,41,47;, + 3;1020,47,1026;, + 3;1021,1020,1026;, + 3;1021,1026,1027;, + 3;1022,1021,1027;, + 3;1022,1027,1028;, + 3;1023,1022,1028;, + 3;1023,1028,1029;, + 3;1030,1023,1029;, + 3;1024,1023,1030;, + 3;1031,1024,1030;, + 3;1031,1025,1024;, + 3;1026,47,53;, + 3;1026,53,1032;, + 3;1027,1026,1032;, + 3;1027,1032,1033;, + 3;1028,1027,1033;, + 3;1028,1033,1034;, + 3;1029,1028,1034;, + 3;1029,1034,1035;, + 3;1036,1029,1035;, + 3;1030,1029,1036;, + 3;1037,1030,1036;, + 3;1031,1030,1037;, + 3;1032,53,59;, + 3;1032,59,1038;, + 3;1033,1032,1038;, + 3;1033,1038,1039;, + 3;1034,1033,1039;, + 3;1034,1039,1040;, + 3;1035,1034,1040;, + 3;1035,1040,1041;, + 3;1042,1035,1041;, + 3;1036,1035,1042;, + 3;1043,1036,1042;, + 3;1037,1036,1043;, + 3;1038,59,65;, + 3;1038,65,1044;, + 3;1039,1038,1044;, + 3;1039,1044,1045;, + 3;1040,1039,1045;, + 3;1040,1045,1046;, + 3;1041,1040,1046;, + 3;1041,1046,1047;, + 3;1048,1041,1047;, + 3;1042,1041,1048;, + 3;1049,1042,1048;, + 3;1043,1042,1049;, + 3;1044,65,71;, + 3;1044,71,1050;, + 3;1045,1044,1050;, + 3;1045,1050,1051;, + 3;1046,1045,1051;, + 3;1046,1051,1052;, + 3;1047,1046,1052;, + 3;1047,1052,1053;, + 3;1054,1047,1053;, + 3;1048,1047,1054;, + 3;1055,1048,1054;, + 3;1049,1048,1055;, + 3;1050,71,77;, + 3;1050,77,1056;, + 3;1051,1050,1056;, + 3;1051,1056,1057;, + 3;1052,1051,1057;, + 3;1052,1057,1058;, + 3;1053,1052,1058;, + 3;1053,1058,1059;, + 3;1060,1053,1059;, + 3;1054,1053,1060;, + 3;1061,1054,1060;, + 3;1055,1054,1061;, + 3;1056,77,83;, + 3;1056,83,1062;, + 3;1057,1056,1062;, + 3;1057,1062,1063;, + 3;1058,1057,1063;, + 3;1058,1063,1064;, + 3;1059,1058,1064;, + 3;1059,1064,1065;, + 3;1066,1059,1065;, + 3;1060,1059,1066;, + 3;1067,1060,1066;, + 3;1061,1060,1067;, + 3;1062,83,89;, + 3;1062,89,1068;, + 3;1063,1062,1068;, + 3;1063,1068,1069;, + 3;1064,1063,1069;, + 3;1064,1069,1070;, + 3;1065,1064,1070;, + 3;1065,1070,1071;, + 3;1072,1065,1071;, + 3;1066,1065,1072;, + 3;1073,1066,1072;, + 3;1067,1066,1073;, + 3;1068,89,95;, + 3;1068,95,1074;, + 3;1069,1068,1074;, + 3;1069,1074,1075;, + 3;1070,1069,1075;, + 3;1070,1075,1076;, + 3;1071,1070,1076;, + 3;1071,1076,1077;, + 3;1078,1071,1077;, + 3;1072,1071,1078;, + 3;1079,1072,1078;, + 3;1073,1072,1079;, + 3;1074,95,101;, + 3;1074,101,1080;, + 3;1075,1074,1080;, + 3;1075,1080,1081;, + 3;1076,1075,1081;, + 3;1076,1081,1082;, + 3;1077,1076,1082;, + 3;1077,1082,1083;, + 3;1084,1077,1083;, + 3;1078,1077,1084;, + 3;1085,1078,1084;, + 3;1079,1078,1085;, + 3;1080,101,107;, + 3;1080,107,1086;, + 3;1081,1080,1086;, + 3;1081,1086,1087;, + 3;1082,1081,1087;, + 3;1082,1087,1088;, + 3;1083,1082,1088;, + 3;1083,1088,1089;, + 3;1090,1083,1089;, + 3;1084,1083,1090;, + 3;1091,1084,1090;, + 3;1085,1084,1091;, + 3;1086,107,113;, + 3;1086,113,1092;, + 3;1087,1086,1092;, + 3;1087,1092,1093;, + 3;1088,1087,1093;, + 3;1088,1093,1094;, + 3;1089,1088,1094;, + 3;1089,1094,1095;, + 3;1096,1089,1095;, + 3;1090,1089,1096;, + 3;1097,1090,1096;, + 3;1091,1090,1097;, + 3;1092,113,119;, + 3;1092,119,1098;, + 3;1093,1092,1098;, + 3;1093,1098,1099;, + 3;1094,1093,1099;, + 3;1094,1099,1100;, + 3;1095,1094,1100;, + 3;1095,1100,1101;, + 3;1102,1095,1101;, + 3;1096,1095,1102;, + 3;1103,1096,1102;, + 3;1097,1096,1103;, + 3;1098,119,125;, + 3;1098,125,1104;, + 3;1099,1098,1104;, + 3;1099,1104,1105;, + 3;1100,1099,1105;, + 3;1100,1105,1106;, + 3;1101,1100,1106;, + 3;1101,1106,1107;, + 3;1108,1101,1107;, + 3;1102,1101,1108;, + 3;1109,1102,1108;, + 3;1103,1102,1109;, + 3;1104,125,131;, + 3;1104,131,1110;, + 3;1105,1104,1110;, + 3;1105,1110,1111;, + 3;1106,1105,1111;, + 3;1106,1111,1112;, + 3;1107,1106,1112;, + 3;1107,1112,1113;, + 3;1114,1107,1113;, + 3;1108,1107,1114;, + 3;1115,1108,1114;, + 3;1109,1108,1115;, + 3;1110,131,137;, + 3;1110,137,1116;, + 3;1111,1110,1116;, + 3;1111,1116,1117;, + 3;1112,1111,1117;, + 3;1112,1117,1118;, + 3;1113,1112,1118;, + 3;1113,1118,1119;, + 3;1120,1113,1119;, + 3;1114,1113,1120;, + 3;1121,1114,1120;, + 3;1115,1114,1121;, + 3;1116,137,143;, + 3;1116,143,1122;, + 3;1117,1116,1122;, + 3;1117,1122,1123;, + 3;1118,1117,1123;, + 3;1118,1123,1124;, + 3;1119,1118,1124;, + 3;1119,1124,1125;, + 3;1126,1119,1125;, + 3;1120,1119,1126;, + 3;1127,1120,1126;, + 3;1121,1120,1127;, + 3;1122,143,149;, + 3;1122,149,183;, + 3;1123,1122,183;, + 3;1123,183,182;, + 3;1124,1123,182;, + 3;1124,182,189;, + 3;1125,1124,189;, + 3;1125,189,195;, + 3;1128,1125,195;, + 3;1126,1125,1128;, + 3;1129,1126,1128;, + 3;1127,1126,1129;, + 3;1130,1127,1129;, + 3;1131,1127,1130;, + 3;1131,1121,1127;, + 3;1132,1121,1131;, + 3;1132,1115,1121;, + 3;1128,195,201;, + 3;1133,1128,201;, + 3;1129,1128,1133;, + 3;1134,1129,1133;, + 3;1130,1129,1134;, + 3;1135,1130,1134;, + 3;1136,1130,1135;, + 3;1136,1131,1130;, + 3;1137,1131,1136;, + 3;1137,1132,1131;, + 3;1133,201,207;, + 3;1138,1133,207;, + 3;1134,1133,1138;, + 3;1139,1134,1138;, + 3;1135,1134,1139;, + 3;1140,1135,1139;, + 3;1141,1135,1140;, + 3;1141,1136,1135;, + 3;1142,1136,1141;, + 3;1142,1137,1136;, + 3;1138,207,213;, + 3;1143,1138,213;, + 3;1139,1138,1143;, + 3;1144,1139,1143;, + 3;1140,1139,1144;, + 3;1145,1140,1144;, + 3;1146,1140,1145;, + 3;1146,1141,1140;, + 3;1147,1141,1146;, + 3;1147,1142,1141;, + 3;1143,213,219;, + 3;1148,1143,219;, + 3;1144,1143,1148;, + 3;1149,1144,1148;, + 3;1145,1144,1149;, + 3;1150,1145,1149;, + 3;1151,1145,1150;, + 3;1151,1146,1145;, + 3;1152,1146,1151;, + 3;1152,1147,1146;, + 3;1148,219,225;, + 3;1153,1148,225;, + 3;1149,1148,1153;, + 3;1154,1149,1153;, + 3;1150,1149,1154;, + 3;1155,1150,1154;, + 3;1156,1150,1155;, + 3;1156,1151,1150;, + 3;1157,1151,1156;, + 3;1157,1152,1151;, + 3;1153,225,231;, + 3;1158,1153,231;, + 3;1154,1153,1158;, + 3;1159,1154,1158;, + 3;1155,1154,1159;, + 3;1160,1155,1159;, + 3;1161,1155,1160;, + 3;1161,1156,1155;, + 3;1162,1156,1161;, + 3;1162,1157,1156;, + 3;1158,231,237;, + 3;1163,1158,237;, + 3;1159,1158,1163;, + 3;1164,1159,1163;, + 3;1160,1159,1164;, + 3;1165,1160,1164;, + 3;1166,1160,1165;, + 3;1166,1161,1160;, + 3;1167,1161,1166;, + 3;1167,1162,1161;, + 3;1163,237,243;, + 3;1168,1163,243;, + 3;1164,1163,1168;, + 3;1169,1164,1168;, + 3;1165,1164,1169;, + 3;1170,1165,1169;, + 3;1171,1165,1170;, + 3;1171,1166,1165;, + 3;1172,1166,1171;, + 3;1172,1167,1166;, + 3;1168,243,249;, + 3;1173,1168,249;, + 3;1169,1168,1173;, + 3;1174,1169,1173;, + 3;1170,1169,1174;, + 3;1175,1170,1174;, + 3;1176,1170,1175;, + 3;1176,1171,1170;, + 3;1177,1171,1176;, + 3;1177,1172,1171;, + 3;1173,249,255;, + 3;1178,1173,255;, + 3;1174,1173,1178;, + 3;1179,1174,1178;, + 3;1175,1174,1179;, + 3;1180,1175,1179;, + 3;1181,1175,1180;, + 3;1181,1176,1175;, + 3;1182,1176,1181;, + 3;1182,1177,1176;, + 3;1178,255,261;, + 3;1183,1178,261;, + 3;1179,1178,1183;, + 3;1184,1179,1183;, + 3;1180,1179,1184;, + 3;1185,1180,1184;, + 3;1186,1180,1185;, + 3;1186,1181,1180;, + 3;1187,1181,1186;, + 3;1187,1182,1181;, + 3;1183,261,267;, + 3;1188,1183,267;, + 3;1184,1183,1188;, + 3;1189,1184,1188;, + 3;1185,1184,1189;, + 3;1190,1185,1189;, + 3;1191,1185,1190;, + 3;1191,1186,1185;, + 3;1192,1186,1191;, + 3;1192,1187,1186;, + 3;1188,267,273;, + 3;1193,1188,273;, + 3;1189,1188,1193;, + 3;1194,1189,1193;, + 3;1190,1189,1194;, + 3;1195,1190,1194;, + 3;1196,1190,1195;, + 3;1196,1191,1190;, + 3;1197,1191,1196;, + 3;1197,1192,1191;, + 3;1193,273,279;, + 3;1198,1193,279;, + 3;1194,1193,1198;, + 3;1199,1194,1198;, + 3;1195,1194,1199;, + 3;1200,1195,1199;, + 3;1201,1195,1200;, + 3;1201,1196,1195;, + 3;1202,1196,1201;, + 3;1202,1197,1196;, + 3;1198,279,285;, + 3;1203,1198,285;, + 3;1199,1198,1203;, + 3;1204,1199,1203;, + 3;1200,1199,1204;, + 3;1205,1200,1204;, + 3;1206,1200,1205;, + 3;1206,1201,1200;, + 3;1207,1201,1206;, + 3;1207,1202,1201;, + 3;1203,285,291;, + 3;1208,1203,291;, + 3;1204,1203,1208;, + 3;1209,1204,1208;, + 3;1205,1204,1209;, + 3;1210,1205,1209;, + 3;1211,1205,1210;, + 3;1211,1206,1205;, + 3;1212,1206,1211;, + 3;1212,1207,1206;, + 3;1208,291,297;, + 3;1213,1208,297;, + 3;1209,1208,1213;, + 3;1214,1209,1213;, + 3;1210,1209,1214;, + 3;1215,1210,1214;, + 3;1216,1210,1215;, + 3;1216,1211,1210;, + 3;1217,1211,1216;, + 3;1217,1212,1211;, + 3;1213,297,303;, + 3;1218,1213,303;, + 3;1214,1213,1218;, + 3;1219,1214,1218;, + 3;1215,1214,1219;, + 3;1220,1215,1219;, + 3;1221,1215,1220;, + 3;1221,1216,1215;, + 3;1222,1216,1221;, + 3;1222,1217,1216;, + 3;1218,303,309;, + 3;1223,1218,309;, + 3;1219,1218,1223;, + 3;1224,1219,1223;, + 3;1220,1219,1224;, + 3;1225,1220,1224;, + 3;1226,1220,1225;, + 3;1226,1221,1220;, + 3;1227,1221,1226;, + 3;1227,1222,1221;, + 3;1223,309,315;, + 3;1228,1223,315;, + 3;1224,1223,1228;, + 3;1229,1224,1228;, + 3;1225,1224,1229;, + 3;1230,1225,1229;, + 3;1231,1225,1230;, + 3;1231,1226,1225;, + 3;1232,1226,1231;, + 3;1232,1227,1226;, + 3;1228,315,321;, + 3;1233,1228,321;, + 3;1229,1228,1233;, + 3;1234,1229,1233;, + 3;1230,1229,1234;, + 3;1235,1230,1234;, + 3;1236,1230,1235;, + 3;1236,1231,1230;, + 3;1237,1231,1236;, + 3;1237,1232,1231;, + 3;1233,321,327;, + 3;1238,1233,327;, + 3;1234,1233,1238;, + 3;1239,1234,1238;, + 3;1235,1234,1239;, + 3;1240,1235,1239;, + 3;1241,1235,1240;, + 3;1241,1236,1235;, + 3;1242,1236,1241;, + 3;1242,1237,1236;, + 3;1238,327,333;, + 3;1243,1238,333;, + 3;1239,1238,1243;, + 3;1244,1239,1243;, + 3;1240,1239,1244;, + 3;1245,1240,1244;, + 3;1246,1240,1245;, + 3;1246,1241,1240;, + 3;1247,1241,1246;, + 3;1247,1242,1241;, + 3;1243,333,339;, + 3;1248,1243,339;, + 3;1244,1243,1248;, + 3;1249,1244,1248;, + 3;1245,1244,1249;, + 3;1250,1245,1249;, + 3;1251,1245,1250;, + 3;1251,1246,1245;, + 3;1252,1246,1251;, + 3;1252,1247,1246;, + 3;1248,339,345;, + 3;1253,1248,345;, + 3;1249,1248,1253;, + 3;1254,1249,1253;, + 3;1250,1249,1254;, + 3;1255,1250,1254;, + 3;1256,1250,1255;, + 3;1256,1251,1250;, + 3;1257,1251,1256;, + 3;1257,1252,1251;, + 3;1253,345,351;, + 3;1258,1253,351;, + 3;1254,1253,1258;, + 3;1259,1254,1258;, + 3;1255,1254,1259;, + 3;1260,1255,1259;, + 3;1261,1255,1260;, + 3;1261,1256,1255;, + 3;1262,1256,1261;, + 3;1262,1257,1256;, + 3;1258,351,357;, + 3;1263,1258,357;, + 3;1259,1258,1263;, + 3;1264,1259,1263;, + 3;1260,1259,1264;, + 3;1265,1260,1264;, + 3;1266,1260,1265;, + 3;1266,1261,1260;, + 3;1267,1261,1266;, + 3;1267,1262,1261;, + 3;1263,357,363;, + 3;1268,1263,363;, + 3;1264,1263,1268;, + 3;1269,1264,1268;, + 3;1265,1264,1269;, + 3;1270,1265,1269;, + 3;1271,1265,1270;, + 3;1271,1266,1265;, + 3;1272,1266,1271;, + 3;1272,1267,1266;, + 3;1268,363,369;, + 3;1273,1268,369;, + 3;1269,1268,1273;, + 3;1274,1269,1273;, + 3;1270,1269,1274;, + 3;1275,1270,1274;, + 3;1276,1270,1275;, + 3;1276,1271,1270;, + 3;1277,1271,1276;, + 3;1277,1272,1271;, + 3;1273,369,375;, + 3;1278,1273,375;, + 3;1274,1273,1278;, + 3;1279,1274,1278;, + 3;1275,1274,1279;, + 3;443,1275,1279;, + 3;448,1275,443;, + 3;448,1276,1275;, + 3;453,1276,448;, + 3;453,1277,1276;, + 3;1278,375,381;, + 3;1280,1278,381;, + 3;1279,1278,1280;, + 3;437,1279,1280;, + 3;443,1279,437;, + 3;1280,381,387;, + 3;438,1280,387;, + 3;437,1280,438;, + 3;438,387,393;, + 3;427,438,393;, + 3;427,393,399;, + 3;458,1277,453;, + 3;458,1281,1277;, + 3;1281,1272,1277;, + 3;1281,1282,1272;, + 3;1282,1267,1272;, + 3;1282,1283,1267;, + 3;1283,1262,1267;, + 3;463,1281,458;, + 3;463,1284,1281;, + 3;1284,1282,1281;, + 3;1284,1285,1282;, + 3;1285,1283,1282;, + 3;1285,1286,1283;, + 3;1286,1287,1283;, + 3;1283,1287,1262;, + 3;1287,1257,1262;, + 3;1287,1288,1257;, + 3;1288,1252,1257;, + 3;468,1284,463;, + 3;468,1289,1284;, + 3;1289,1285,1284;, + 3;1289,1290,1285;, + 3;1290,1286,1285;, + 3;1290,1291,1286;, + 3;1291,1292,1286;, + 3;1286,1292,1287;, + 3;1292,1288,1287;, + 3;1292,1293,1288;, + 3;1293,1294,1288;, + 3;1288,1294,1252;, + 3;1294,1247,1252;, + 3;473,1289,468;, + 3;473,1295,1289;, + 3;1295,1290,1289;, + 3;1295,1296,1290;, + 3;1296,1291,1290;, + 3;1296,1297,1291;, + 3;1297,1298,1291;, + 3;1291,1298,1292;, + 3;1298,1293,1292;, + 3;1298,1299,1293;, + 3;1299,1300,1293;, + 3;1293,1300,1294;, + 3;478,1295,473;, + 3;478,1301,1295;, + 3;1301,1296,1295;, + 3;1301,1302,1296;, + 3;1302,1297,1296;, + 3;1302,1303,1297;, + 3;1303,1304,1297;, + 3;1297,1304,1298;, + 3;1304,1299,1298;, + 3;1304,1305,1299;, + 3;1305,1306,1299;, + 3;1299,1306,1300;, + 3;483,1301,478;, + 3;483,1307,1301;, + 3;1307,1302,1301;, + 3;1307,1308,1302;, + 3;1308,1303,1302;, + 3;1308,1309,1303;, + 3;1309,1310,1303;, + 3;1303,1310,1304;, + 3;1310,1305,1304;, + 3;1310,1311,1305;, + 3;1311,1312,1305;, + 3;1305,1312,1306;, + 3;488,1307,483;, + 3;488,1313,1307;, + 3;1313,1308,1307;, + 3;1313,1314,1308;, + 3;1314,1309,1308;, + 3;1314,1315,1309;, + 3;1315,1316,1309;, + 3;1309,1316,1310;, + 3;1316,1311,1310;, + 3;1316,1317,1311;, + 3;1317,1318,1311;, + 3;1311,1318,1312;, + 3;493,1313,488;, + 3;493,1319,1313;, + 3;1319,1314,1313;, + 3;1319,1320,1314;, + 3;1320,1315,1314;, + 3;1320,1321,1315;, + 3;1321,1322,1315;, + 3;1315,1322,1316;, + 3;1322,1317,1316;, + 3;1322,1323,1317;, + 3;1323,1324,1317;, + 3;1317,1324,1318;, + 3;498,1319,493;, + 3;498,1325,1319;, + 3;1325,1320,1319;, + 3;1325,1326,1320;, + 3;1326,1321,1320;, + 3;1326,1327,1321;, + 3;1327,1328,1321;, + 3;1321,1328,1322;, + 3;1328,1323,1322;, + 3;1328,1329,1323;, + 3;1329,1330,1323;, + 3;1323,1330,1324;, + 3;503,1325,498;, + 3;503,515,1325;, + 3;515,1326,1325;, + 3;515,1331,1326;, + 3;1331,1327,1326;, + 3;1331,1332,1327;, + 3;1332,1333,1327;, + 3;1327,1333,1328;, + 3;1333,1329,1328;, + 3;1333,1334,1329;, + 3;1334,1335,1329;, + 3;1329,1335,1330;, + 3;514,1331,515;, + 3;514,1336,1331;, + 3;1336,1332,1331;, + 3;1336,1337,1332;, + 3;1337,1338,1332;, + 3;1332,1338,1333;, + 3;1338,1334,1333;, + 3;1338,1339,1334;, + 3;1339,1340,1334;, + 3;1334,1340,1335;, + 3;521,1336,514;, + 3;521,1341,1336;, + 3;1341,1337,1336;, + 3;1341,1342,1337;, + 3;1342,1343,1337;, + 3;1337,1343,1338;, + 3;1343,1339,1338;, + 3;1343,1344,1339;, + 3;1344,1345,1339;, + 3;1339,1345,1340;, + 3;1346,1341,521;, + 3;1346,1347,1341;, + 3;1347,1342,1341;, + 3;1347,1348,1342;, + 3;1348,1349,1342;, + 3;1342,1349,1343;, + 3;1349,1344,1343;, + 3;1349,1350,1344;, + 3;1350,1351,1344;, + 3;1344,1351,1345;, + 3;520,1346,521;, + 3;1352,1346,520;, + 3;1352,1353,1346;, + 3;1353,1347,1346;, + 3;1353,1354,1347;, + 3;1354,1348,1347;, + 3;1354,1355,1348;, + 3;1355,1356,1348;, + 3;1348,1356,1349;, + 3;1356,1350,1349;, + 3;519,1352,520;, + 3;519,527,1352;, + 3;1352,527,1357;, + 3;1352,1357,1353;, + 3;1353,1357,1358;, + 3;1353,1358,1354;, + 3;1354,1358,1359;, + 3;1354,1359,1355;, + 3;1355,1359,1360;, + 3;1355,1360,1361;, + 3;1355,1361,1356;, + 3;1361,1362,1356;, + 3;1356,1362,1350;, + 3;527,1363,1357;, + 3;1357,1363,1364;, + 3;1357,1364,1358;, + 3;1358,1364,1365;, + 3;1358,1365,1359;, + 3;1359,1365,1366;, + 3;1359,1366,1360;, + 3;1360,1366,1367;, + 3;1360,1367,1368;, + 3;1361,1360,1368;, + 3;527,526,1363;, + 3;526,1369,1363;, + 3;1363,1369,1370;, + 3;1363,1370,1364;, + 3;1364,1370,1371;, + 3;1364,1371,1365;, + 3;1365,1371,1372;, + 3;1365,1372,1366;, + 3;1366,1372,1373;, + 3;1366,1373,1367;, + 3;526,533,1369;, + 3;533,1374,1369;, + 3;1369,1374,1375;, + 3;1369,1375,1370;, + 3;1370,1375,1376;, + 3;1370,1376,1371;, + 3;1371,1376,1377;, + 3;1371,1377,1372;, + 3;1372,1377,1378;, + 3;1372,1378,1373;, + 3;533,538,1374;, + 3;538,1379,1374;, + 3;1374,1379,1380;, + 3;1374,1380,1375;, + 3;1375,1380,1381;, + 3;1375,1381,1376;, + 3;1376,1381,1382;, + 3;1376,1382,1377;, + 3;1377,1382,1383;, + 3;1377,1383,1378;, + 3;538,543,1379;, + 3;543,1384,1379;, + 3;1379,1384,1385;, + 3;1379,1385,1380;, + 3;1380,1385,1386;, + 3;1380,1386,1381;, + 3;1381,1386,1387;, + 3;1381,1387,1382;, + 3;1382,1387,1388;, + 3;1382,1388,1383;, + 3;543,548,1384;, + 3;548,1389,1384;, + 3;1384,1389,1390;, + 3;1384,1390,1385;, + 3;1385,1390,1391;, + 3;1385,1391,1386;, + 3;1386,1391,1392;, + 3;1386,1392,1387;, + 3;1387,1392,1393;, + 3;1387,1393,1388;, + 3;548,553,1389;, + 3;553,1394,1389;, + 3;1389,1394,1395;, + 3;1389,1395,1390;, + 3;1390,1395,1396;, + 3;1390,1396,1391;, + 3;1391,1396,1397;, + 3;1391,1397,1392;, + 3;1392,1397,1398;, + 3;1392,1398,1393;, + 3;553,558,1394;, + 3;558,1399,1394;, + 3;1394,1399,1400;, + 3;1394,1400,1395;, + 3;1395,1400,1401;, + 3;1395,1401,1396;, + 3;1396,1401,1402;, + 3;1396,1402,1397;, + 3;1397,1402,1403;, + 3;1397,1403,1398;, + 3;558,563,1399;, + 3;563,1404,1399;, + 3;1399,1404,1405;, + 3;1399,1405,1400;, + 3;1400,1405,1406;, + 3;1400,1406,1401;, + 3;1401,1406,1407;, + 3;1401,1407,1402;, + 3;1402,1407,1408;, + 3;1402,1408,1403;, + 3;563,568,1404;, + 3;568,1409,1404;, + 3;1404,1409,1410;, + 3;1404,1410,1405;, + 3;1405,1410,1411;, + 3;1405,1411,1406;, + 3;1406,1411,1412;, + 3;1406,1412,1407;, + 3;1407,1412,1413;, + 3;1407,1413,1408;, + 3;568,573,1409;, + 3;573,1414,1409;, + 3;1409,1414,1415;, + 3;1409,1415,1410;, + 3;1410,1415,1416;, + 3;1410,1416,1411;, + 3;1411,1416,1417;, + 3;1411,1417,1412;, + 3;1412,1417,1418;, + 3;1412,1418,1413;, + 3;573,578,1414;, + 3;578,1419,1414;, + 3;1414,1419,1420;, + 3;1414,1420,1415;, + 3;1415,1420,1421;, + 3;1415,1421,1416;, + 3;1416,1421,1422;, + 3;1416,1422,1417;, + 3;1417,1422,1423;, + 3;1417,1423,1418;, + 3;578,583,1419;, + 3;583,1424,1419;, + 3;1419,1424,1425;, + 3;1419,1425,1420;, + 3;1420,1425,1426;, + 3;1420,1426,1421;, + 3;1421,1426,1427;, + 3;1421,1427,1422;, + 3;1422,1427,1428;, + 3;1422,1428,1423;, + 3;583,588,1424;, + 3;588,1429,1424;, + 3;1424,1429,1430;, + 3;1424,1430,1425;, + 3;1425,1430,1431;, + 3;1425,1431,1426;, + 3;1426,1431,1432;, + 3;1426,1432,1427;, + 3;1427,1432,1433;, + 3;1427,1433,1428;, + 3;588,593,1429;, + 3;593,1434,1429;, + 3;1429,1434,1435;, + 3;1429,1435,1430;, + 3;1430,1435,1436;, + 3;1430,1436,1431;, + 3;1431,1436,1437;, + 3;1431,1437,1432;, + 3;1432,1437,1438;, + 3;1432,1438,1433;, + 3;593,598,1434;, + 3;598,1439,1434;, + 3;1434,1439,1440;, + 3;1434,1440,1435;, + 3;1435,1440,1441;, + 3;1435,1441,1436;, + 3;1436,1441,1442;, + 3;1436,1442,1437;, + 3;1437,1442,1443;, + 3;1437,1443,1438;, + 3;598,603,1439;, + 3;603,656,1439;, + 3;1439,656,663;, + 3;1439,663,1440;, + 3;1440,663,670;, + 3;1440,670,1441;, + 3;1441,670,677;, + 3;1441,677,1442;, + 3;1442,677,684;, + 3;1442,684,1443;, + 3;1443,684,691;, + 3;1443,691,1444;, + 3;1438,1443,1444;, + 3;1438,1444,1445;, + 3;1433,1438,1445;, + 3;1433,1445,1446;, + 3;1428,1433,1446;, + 3;1444,691,698;, + 3;1444,698,1447;, + 3;1445,1444,1447;, + 3;1445,1447,1448;, + 3;1446,1445,1448;, + 3;1446,1448,1449;, + 3;1450,1446,1449;, + 3;1428,1446,1450;, + 3;1423,1428,1450;, + 3;1423,1450,1451;, + 3;1418,1423,1451;, + 3;1447,698,705;, + 3;1447,705,1452;, + 3;1448,1447,1452;, + 3;1448,1452,1453;, + 3;1449,1448,1453;, + 3;1449,1453,1454;, + 3;1455,1449,1454;, + 3;1450,1449,1455;, + 3;1451,1450,1455;, + 3;1451,1455,1456;, + 3;1457,1451,1456;, + 3;1418,1451,1457;, + 3;1413,1418,1457;, + 3;1452,705,712;, + 3;1452,712,1458;, + 3;1453,1452,1458;, + 3;1453,1458,1459;, + 3;1454,1453,1459;, + 3;1454,1459,1460;, + 3;1461,1454,1460;, + 3;1455,1454,1461;, + 3;1456,1455,1461;, + 3;1456,1461,1462;, + 3;1463,1456,1462;, + 3;1457,1456,1463;, + 3;1458,712,719;, + 3;1458,719,1464;, + 3;1459,1458,1464;, + 3;1459,1464,1465;, + 3;1460,1459,1465;, + 3;1460,1465,1466;, + 3;1467,1460,1466;, + 3;1461,1460,1467;, + 3;1462,1461,1467;, + 3;1462,1467,1468;, + 3;1469,1462,1468;, + 3;1463,1462,1469;, + 3;1464,719,726;, + 3;1464,726,1470;, + 3;1465,1464,1470;, + 3;1465,1470,1471;, + 3;1466,1465,1471;, + 3;1466,1471,1472;, + 3;1473,1466,1472;, + 3;1467,1466,1473;, + 3;1468,1467,1473;, + 3;1468,1473,1474;, + 3;1475,1468,1474;, + 3;1469,1468,1475;, + 3;1470,726,733;, + 3;1470,733,1476;, + 3;1471,1470,1476;, + 3;1471,1476,1477;, + 3;1472,1471,1477;, + 3;1472,1477,1478;, + 3;1479,1472,1478;, + 3;1473,1472,1479;, + 3;1474,1473,1479;, + 3;1474,1479,1480;, + 3;1481,1474,1480;, + 3;1475,1474,1481;, + 3;1476,733,740;, + 3;1476,740,1482;, + 3;1477,1476,1482;, + 3;1477,1482,1483;, + 3;1478,1477,1483;, + 3;1478,1483,1484;, + 3;1485,1478,1484;, + 3;1479,1478,1485;, + 3;1480,1479,1485;, + 3;1480,1485,1486;, + 3;1487,1480,1486;, + 3;1481,1480,1487;, + 3;1482,740,747;, + 3;1482,747,1488;, + 3;1483,1482,1488;, + 3;1483,1488,1489;, + 3;1484,1483,1489;, + 3;1484,1489,1490;, + 3;1491,1484,1490;, + 3;1485,1484,1491;, + 3;1486,1485,1491;, + 3;1486,1491,1492;, + 3;1493,1486,1492;, + 3;1487,1486,1493;, + 3;1488,747,754;, + 3;1488,754,1494;, + 3;1489,1488,1494;, + 3;1489,1494,1495;, + 3;1490,1489,1495;, + 3;1490,1495,1496;, + 3;1497,1490,1496;, + 3;1491,1490,1497;, + 3;1492,1491,1497;, + 3;1492,1497,1498;, + 3;1499,1492,1498;, + 3;1493,1492,1499;, + 3;1494,754,761;, + 3;1494,761,1500;, + 3;1495,1494,1500;, + 3;1495,1500,1501;, + 3;1496,1495,1501;, + 3;1496,1501,1502;, + 3;1503,1496,1502;, + 3;1497,1496,1503;, + 3;1498,1497,1503;, + 3;1498,1503,1504;, + 3;1505,1498,1504;, + 3;1499,1498,1505;, + 3;1500,761,768;, + 3;1500,768,1506;, + 3;1501,1500,1506;, + 3;1501,1506,1507;, + 3;1502,1501,1507;, + 3;1502,1507,1508;, + 3;1509,1502,1508;, + 3;1503,1502,1509;, + 3;1504,1503,1509;, + 3;1504,1509,1510;, + 3;1511,1504,1510;, + 3;1505,1504,1511;, + 3;1506,768,775;, + 3;1506,775,1512;, + 3;1507,1506,1512;, + 3;1507,1512,1513;, + 3;1508,1507,1513;, + 3;1508,1513,1514;, + 3;1515,1508,1514;, + 3;1509,1508,1515;, + 3;1510,1509,1515;, + 3;1510,1515,1516;, + 3;1517,1510,1516;, + 3;1511,1510,1517;, + 3;1512,775,782;, + 3;1512,782,1518;, + 3;1513,1512,1518;, + 3;1513,1518,1519;, + 3;1514,1513,1519;, + 3;1514,1519,1520;, + 3;1521,1514,1520;, + 3;1515,1514,1521;, + 3;1516,1515,1521;, + 3;1516,1521,1522;, + 3;1523,1516,1522;, + 3;1517,1516,1523;, + 3;1518,782,789;, + 3;1518,789,1524;, + 3;1519,1518,1524;, + 3;1519,1524,1525;, + 3;1520,1519,1525;, + 3;1520,1525,1526;, + 3;1527,1520,1526;, + 3;1521,1520,1527;, + 3;1522,1521,1527;, + 3;1522,1527,1528;, + 3;1529,1522,1528;, + 3;1523,1522,1529;, + 3;1524,789,796;, + 3;1524,796,1530;, + 3;1525,1524,1530;, + 3;1525,1530,1531;, + 3;1526,1525,1531;, + 3;1526,1531,1532;, + 3;1533,1526,1532;, + 3;1527,1526,1533;, + 3;1528,1527,1533;, + 3;1528,1533,1534;, + 3;1535,1528,1534;, + 3;1529,1528,1535;, + 3;1530,796,803;, + 3;1530,803,1536;, + 3;1531,1530,1536;, + 3;1531,1536,1537;, + 3;1532,1531,1537;, + 3;1532,1537,1538;, + 3;1539,1532,1538;, + 3;1533,1532,1539;, + 3;1534,1533,1539;, + 3;1534,1539,1540;, + 3;1541,1534,1540;, + 3;1535,1534,1541;, + 3;1536,803,810;, + 3;1536,810,1542;, + 3;1537,1536,1542;, + 3;1537,1542,1543;, + 3;1538,1537,1543;, + 3;1538,1543,1544;, + 3;1545,1538,1544;, + 3;1539,1538,1545;, + 3;1540,1539,1545;, + 3;1540,1545,1546;, + 3;1547,1540,1546;, + 3;1541,1540,1547;, + 3;1542,810,817;, + 3;1542,817,1548;, + 3;1543,1542,1548;, + 3;1543,1548,1549;, + 3;1544,1543,1549;, + 3;1544,1549,1550;, + 3;1551,1544,1550;, + 3;1545,1544,1551;, + 3;1546,1545,1551;, + 3;1546,1551,1552;, + 3;1553,1546,1552;, + 3;1547,1546,1553;, + 3;1548,817,824;, + 3;1548,824,1554;, + 3;1549,1548,1554;, + 3;1549,1554,1555;, + 3;1550,1549,1555;, + 3;1550,1555,1556;, + 3;1557,1550,1556;, + 3;1551,1550,1557;, + 3;1552,1551,1557;, + 3;1552,1557,1558;, + 3;1559,1552,1558;, + 3;1553,1552,1559;, + 3;1554,824,831;, + 3;1554,831,1560;, + 3;1555,1554,1560;, + 3;1555,1560,1561;, + 3;1556,1555,1561;, + 3;1556,1561,1562;, + 3;1563,1556,1562;, + 3;1557,1556,1563;, + 3;1558,1557,1563;, + 3;1558,1563,1564;, + 3;1565,1558,1564;, + 3;1559,1558,1565;, + 3;1560,831,838;, + 3;1560,838,1566;, + 3;1561,1560,1566;, + 3;1561,1566,1567;, + 3;1562,1561,1567;, + 3;1562,1567,1568;, + 3;1569,1562,1568;, + 3;1563,1562,1569;, + 3;1564,1563,1569;, + 3;1564,1569,1570;, + 3;1571,1564,1570;, + 3;1565,1564,1571;, + 3;1566,838,845;, + 3;1566,845,1572;, + 3;1567,1566,1572;, + 3;1567,1572,1573;, + 3;1568,1567,1573;, + 3;1568,1573,1574;, + 3;1575,1568,1574;, + 3;1569,1568,1575;, + 3;1570,1569,1575;, + 3;1570,1575,1576;, + 3;1577,1570,1576;, + 3;1571,1570,1577;, + 3;1572,845,852;, + 3;1572,852,1578;, + 3;1573,1572,1578;, + 3;1573,1578,1579;, + 3;1574,1573,1579;, + 3;1574,1579,1580;, + 3;1581,1574,1580;, + 3;1575,1574,1581;, + 3;1576,1575,1581;, + 3;1576,1581,1582;, + 3;1583,1576,1582;, + 3;1577,1576,1583;, + 3;1578,852,859;, + 3;1578,859,1584;, + 3;1579,1578,1584;, + 3;1579,1584,1585;, + 3;1580,1579,1585;, + 3;1580,1585,1586;, + 3;1587,1580,1586;, + 3;1581,1580,1587;, + 3;1582,1581,1587;, + 3;1582,1587,1588;, + 3;1589,1582,1588;, + 3;1583,1582,1589;, + 3;1584,859,866;, + 3;1584,866,1590;, + 3;1585,1584,1590;, + 3;1585,1590,1591;, + 3;1586,1585,1591;, + 3;1586,1591,1592;, + 3;1593,1586,1592;, + 3;1587,1586,1593;, + 3;1588,1587,1593;, + 3;1588,1593,1594;, + 3;1595,1588,1594;, + 3;1589,1588,1595;, + 3;1590,866,873;, + 3;1590,873,1596;, + 3;1591,1590,1596;, + 3;1591,1596,1597;, + 3;1592,1591,1597;, + 3;1592,1597,1598;, + 3;1599,1592,1598;, + 3;1593,1592,1599;, + 3;1594,1593,1599;, + 3;1594,1599,1600;, + 3;1601,1594,1600;, + 3;1595,1594,1601;, + 3;1596,873,880;, + 3;1596,880,1602;, + 3;1597,1596,1602;, + 3;1597,1602,1603;, + 3;1598,1597,1603;, + 3;1598,1603,1604;, + 3;1605,1598,1604;, + 3;1599,1598,1605;, + 3;1600,1599,1605;, + 3;1600,1605,1606;, + 3;1607,1600,1606;, + 3;1601,1600,1607;, + 3;1602,880,887;, + 3;1602,887,1608;, + 3;1603,1602,1608;, + 3;1603,1608,1609;, + 3;1604,1603,1609;, + 3;1604,1609,1610;, + 3;1611,1604,1610;, + 3;1605,1604,1611;, + 3;1606,1605,1611;, + 3;1606,1611,1612;, + 3;1613,1606,1612;, + 3;1607,1606,1613;, + 3;1608,887,894;, + 3;1608,894,1614;, + 3;1609,1608,1614;, + 3;1609,1614,1615;, + 3;1610,1609,1615;, + 3;1610,1615,1616;, + 3;1617,1610,1616;, + 3;1611,1610,1617;, + 3;1612,1611,1617;, + 3;1612,1617,1618;, + 3;1619,1612,1618;, + 3;1613,1612,1619;, + 3;1614,894,901;, + 3;1614,901,1620;, + 3;1615,1614,1620;, + 3;1615,1620,1621;, + 3;1616,1615,1621;, + 3;1616,1621,1622;, + 3;1623,1616,1622;, + 3;1617,1616,1623;, + 3;1618,1617,1623;, + 3;1618,1623,1624;, + 3;1625,1618,1624;, + 3;1619,1618,1625;, + 3;1620,901,908;, + 3;1620,908,1626;, + 3;1621,1620,1626;, + 3;1621,1626,1627;, + 3;1622,1621,1627;, + 3;1622,1627,1628;, + 3;1629,1622,1628;, + 3;1623,1622,1629;, + 3;1624,1623,1629;, + 3;1624,1629,1630;, + 3;1631,1624,1630;, + 3;1625,1624,1631;, + 3;1626,908,915;, + 3;1626,915,940;, + 3;1627,1626,940;, + 3;1627,940,939;, + 3;1628,1627,939;, + 3;1628,939,945;, + 3;1632,1628,945;, + 3;1629,1628,1632;, + 3;1630,1629,1632;, + 3;1630,1632,1633;, + 3;1634,1630,1633;, + 3;1631,1630,1634;, + 3;1635,1631,1634;, + 3;1636,1631,1635;, + 3;1636,1625,1631;, + 3;1632,945,950;, + 3;1633,1632,950;, + 3;1633,950,955;, + 3;1637,1633,955;, + 3;1634,1633,1637;, + 3;1638,1634,1637;, + 3;1635,1634,1638;, + 3;1639,1635,1638;, + 3;1640,1635,1639;, + 3;1640,1636,1635;, + 3;1641,1636,1640;, + 3;1641,1642,1636;, + 3;1642,1625,1636;, + 3;1642,1619,1625;, + 3;1637,955,960;, + 3;1643,1637,960;, + 3;1638,1637,1643;, + 3;1644,1638,1643;, + 3;1639,1638,1644;, + 3;1645,1639,1644;, + 3;1646,1639,1645;, + 3;1646,1640,1639;, + 3;1647,1640,1646;, + 3;1647,1641,1640;, + 3;1643,960,965;, + 3;1648,1643,965;, + 3;1644,1643,1648;, + 3;1649,1644,1648;, + 3;1645,1644,1649;, + 3;1650,1645,1649;, + 3;1651,1645,1650;, + 3;1651,1646,1645;, + 3;1652,1646,1651;, + 3;1652,1647,1646;, + 3;1648,965,970;, + 3;1653,1648,970;, + 3;1649,1648,1653;, + 3;1654,1649,1653;, + 3;1650,1649,1654;, + 3;1655,1650,1654;, + 3;1656,1650,1655;, + 3;1656,1651,1650;, + 3;1657,1651,1656;, + 3;1657,1652,1651;, + 3;1653,970,975;, + 3;1658,1653,975;, + 3;1654,1653,1658;, + 3;1659,1654,1658;, + 3;1655,1654,1659;, + 3;1660,1655,1659;, + 3;1661,1655,1660;, + 3;1661,1656,1655;, + 3;1662,1656,1661;, + 3;1662,1657,1656;, + 3;1658,975,980;, + 3;1663,1658,980;, + 3;1659,1658,1663;, + 3;1664,1659,1663;, + 3;1660,1659,1664;, + 3;1665,1660,1664;, + 3;1666,1660,1665;, + 3;1666,1661,1660;, + 3;1667,1661,1666;, + 3;1667,1662,1661;, + 3;1663,980,985;, + 3;997,1663,985;, + 3;1664,1663,997;, + 3;1002,1664,997;, + 3;1665,1664,1002;, + 3;1007,1665,1002;, + 3;1668,1665,1007;, + 3;1668,1666,1665;, + 3;1669,1666,1668;, + 3;1669,1667,1666;, + 3;1670,1667,1669;, + 3;1670,1671,1667;, + 3;1671,1662,1667;, + 3;1671,1672,1662;, + 3;1672,1657,1662;, + 3;1013,1668,1007;, + 3;1673,1668,1013;, + 3;1673,1669,1668;, + 3;1674,1669,1673;, + 3;1674,1670,1669;, + 3;1675,1670,1674;, + 3;1675,1676,1670;, + 3;1676,1671,1670;, + 3;1676,1677,1671;, + 3;1677,1672,1671;, + 3;1019,1673,1013;, + 3;1678,1673,1019;, + 3;1678,1674,1673;, + 3;1679,1674,1678;, + 3;1679,1675,1674;, + 3;1680,1675,1679;, + 3;1680,1681,1675;, + 3;1681,1676,1675;, + 3;1681,1682,1676;, + 3;1682,1677,1676;, + 3;1025,1678,1019;, + 3;1683,1678,1025;, + 3;1683,1679,1678;, + 3;1684,1679,1683;, + 3;1684,1680,1679;, + 3;1685,1680,1684;, + 3;1685,1686,1680;, + 3;1686,1681,1680;, + 3;1686,1687,1681;, + 3;1687,1682,1681;, + 3;1031,1683,1025;, + 3;1688,1683,1031;, + 3;1688,1684,1683;, + 3;1689,1684,1688;, + 3;1689,1685,1684;, + 3;1690,1685,1689;, + 3;1690,1691,1685;, + 3;1691,1686,1685;, + 3;1691,1692,1686;, + 3;1692,1687,1686;, + 3;1688,1031,1037;, + 3;1688,1037,1693;, + 3;1689,1688,1693;, + 3;1689,1693,1694;, + 3;1690,1689,1694;, + 3;1690,1694,1695;, + 3;1696,1690,1695;, + 3;1696,1691,1690;, + 3;1696,1697,1691;, + 3;1697,1692,1691;, + 3;1693,1037,1043;, + 3;1693,1043,1698;, + 3;1694,1693,1698;, + 3;1694,1698,1699;, + 3;1695,1694,1699;, + 3;1695,1699,1700;, + 3;1701,1695,1700;, + 3;1696,1695,1701;, + 3;1702,1696,1701;, + 3;1702,1697,1696;, + 3;1698,1043,1049;, + 3;1698,1049,1703;, + 3;1699,1698,1703;, + 3;1699,1703,1704;, + 3;1700,1699,1704;, + 3;1700,1704,1705;, + 3;1706,1700,1705;, + 3;1701,1700,1706;, + 3;1707,1701,1706;, + 3;1702,1701,1707;, + 3;1703,1049,1055;, + 3;1703,1055,1708;, + 3;1704,1703,1708;, + 3;1704,1708,1709;, + 3;1705,1704,1709;, + 3;1705,1709,1710;, + 3;1711,1705,1710;, + 3;1706,1705,1711;, + 3;1712,1706,1711;, + 3;1707,1706,1712;, + 3;1708,1055,1061;, + 3;1708,1061,1713;, + 3;1709,1708,1713;, + 3;1709,1713,1714;, + 3;1710,1709,1714;, + 3;1710,1714,1715;, + 3;1716,1710,1715;, + 3;1711,1710,1716;, + 3;1717,1711,1716;, + 3;1712,1711,1717;, + 3;1713,1061,1067;, + 3;1713,1067,1718;, + 3;1714,1713,1718;, + 3;1714,1718,1719;, + 3;1715,1714,1719;, + 3;1715,1719,1720;, + 3;1721,1715,1720;, + 3;1716,1715,1721;, + 3;1722,1716,1721;, + 3;1717,1716,1722;, + 3;1718,1067,1073;, + 3;1718,1073,1723;, + 3;1719,1718,1723;, + 3;1719,1723,1724;, + 3;1720,1719,1724;, + 3;1720,1724,1725;, + 3;1726,1720,1725;, + 3;1721,1720,1726;, + 3;1727,1721,1726;, + 3;1722,1721,1727;, + 3;1723,1073,1079;, + 3;1723,1079,1728;, + 3;1724,1723,1728;, + 3;1724,1728,1729;, + 3;1725,1724,1729;, + 3;1725,1729,1730;, + 3;1731,1725,1730;, + 3;1726,1725,1731;, + 3;1732,1726,1731;, + 3;1727,1726,1732;, + 3;1728,1079,1085;, + 3;1728,1085,1733;, + 3;1729,1728,1733;, + 3;1729,1733,1734;, + 3;1730,1729,1734;, + 3;1730,1734,1735;, + 3;1736,1730,1735;, + 3;1731,1730,1736;, + 3;1737,1731,1736;, + 3;1732,1731,1737;, + 3;1733,1085,1091;, + 3;1733,1091,1738;, + 3;1734,1733,1738;, + 3;1734,1738,1739;, + 3;1735,1734,1739;, + 3;1735,1739,1740;, + 3;1741,1735,1740;, + 3;1736,1735,1741;, + 3;1742,1736,1741;, + 3;1737,1736,1742;, + 3;1738,1091,1097;, + 3;1738,1097,1743;, + 3;1739,1738,1743;, + 3;1739,1743,1744;, + 3;1740,1739,1744;, + 3;1740,1744,1745;, + 3;1746,1740,1745;, + 3;1741,1740,1746;, + 3;1747,1741,1746;, + 3;1742,1741,1747;, + 3;1743,1097,1103;, + 3;1743,1103,1748;, + 3;1744,1743,1748;, + 3;1744,1748,1749;, + 3;1745,1744,1749;, + 3;1745,1749,1750;, + 3;1751,1745,1750;, + 3;1746,1745,1751;, + 3;1752,1746,1751;, + 3;1747,1746,1752;, + 3;1748,1103,1109;, + 3;1748,1109,1753;, + 3;1749,1748,1753;, + 3;1749,1753,1754;, + 3;1750,1749,1754;, + 3;1750,1754,1755;, + 3;1756,1750,1755;, + 3;1751,1750,1756;, + 3;1757,1751,1756;, + 3;1752,1751,1757;, + 3;1753,1109,1115;, + 3;1753,1115,1132;, + 3;1754,1753,1132;, + 3;1754,1132,1137;, + 3;1755,1754,1137;, + 3;1755,1137,1142;, + 3;1758,1755,1142;, + 3;1756,1755,1758;, + 3;1759,1756,1758;, + 3;1757,1756,1759;, + 3;1760,1757,1759;, + 3;1761,1757,1760;, + 3;1761,1752,1757;, + 3;1762,1752,1761;, + 3;1762,1747,1752;, + 3;1758,1142,1147;, + 3;1763,1758,1147;, + 3;1759,1758,1763;, + 3;1764,1759,1763;, + 3;1760,1759,1764;, + 3;1765,1760,1764;, + 3;1766,1760,1765;, + 3;1766,1761,1760;, + 3;1767,1761,1766;, + 3;1767,1762,1761;, + 3;1763,1147,1152;, + 3;1768,1763,1152;, + 3;1764,1763,1768;, + 3;1769,1764,1768;, + 3;1765,1764,1769;, + 3;1770,1765,1769;, + 3;1771,1765,1770;, + 3;1771,1766,1765;, + 3;1772,1766,1771;, + 3;1772,1767,1766;, + 3;1768,1152,1157;, + 3;1773,1768,1157;, + 3;1769,1768,1773;, + 3;1774,1769,1773;, + 3;1770,1769,1774;, + 3;1775,1770,1774;, + 3;1776,1770,1775;, + 3;1776,1771,1770;, + 3;1777,1771,1776;, + 3;1777,1772,1771;, + 3;1773,1157,1162;, + 3;1778,1773,1162;, + 3;1774,1773,1778;, + 3;1779,1774,1778;, + 3;1775,1774,1779;, + 3;1780,1775,1779;, + 3;1781,1775,1780;, + 3;1781,1776,1775;, + 3;1782,1776,1781;, + 3;1782,1777,1776;, + 3;1778,1162,1167;, + 3;1783,1778,1167;, + 3;1779,1778,1783;, + 3;1784,1779,1783;, + 3;1780,1779,1784;, + 3;1785,1780,1784;, + 3;1786,1780,1785;, + 3;1786,1781,1780;, + 3;1787,1781,1786;, + 3;1787,1782,1781;, + 3;1783,1167,1172;, + 3;1788,1783,1172;, + 3;1784,1783,1788;, + 3;1789,1784,1788;, + 3;1785,1784,1789;, + 3;1790,1785,1789;, + 3;1791,1785,1790;, + 3;1791,1786,1785;, + 3;1792,1786,1791;, + 3;1792,1787,1786;, + 3;1788,1172,1177;, + 3;1793,1788,1177;, + 3;1789,1788,1793;, + 3;1794,1789,1793;, + 3;1790,1789,1794;, + 3;1795,1790,1794;, + 3;1796,1790,1795;, + 3;1796,1791,1790;, + 3;1797,1791,1796;, + 3;1797,1792,1791;, + 3;1793,1177,1182;, + 3;1798,1793,1182;, + 3;1794,1793,1798;, + 3;1799,1794,1798;, + 3;1795,1794,1799;, + 3;1800,1795,1799;, + 3;1801,1795,1800;, + 3;1801,1796,1795;, + 3;1802,1796,1801;, + 3;1802,1797,1796;, + 3;1798,1182,1187;, + 3;1803,1798,1187;, + 3;1799,1798,1803;, + 3;1804,1799,1803;, + 3;1800,1799,1804;, + 3;1805,1800,1804;, + 3;1806,1800,1805;, + 3;1806,1801,1800;, + 3;1807,1801,1806;, + 3;1807,1802,1801;, + 3;1803,1187,1192;, + 3;1808,1803,1192;, + 3;1804,1803,1808;, + 3;1809,1804,1808;, + 3;1805,1804,1809;, + 3;1810,1805,1809;, + 3;1811,1805,1810;, + 3;1811,1806,1805;, + 3;1812,1806,1811;, + 3;1812,1807,1806;, + 3;1808,1192,1197;, + 3;1813,1808,1197;, + 3;1809,1808,1813;, + 3;1814,1809,1813;, + 3;1810,1809,1814;, + 3;1815,1810,1814;, + 3;1816,1810,1815;, + 3;1816,1811,1810;, + 3;1817,1811,1816;, + 3;1817,1812,1811;, + 3;1813,1197,1202;, + 3;1818,1813,1202;, + 3;1814,1813,1818;, + 3;1819,1814,1818;, + 3;1815,1814,1819;, + 3;1820,1815,1819;, + 3;1821,1815,1820;, + 3;1821,1816,1815;, + 3;1822,1816,1821;, + 3;1822,1817,1816;, + 3;1818,1202,1207;, + 3;1823,1818,1207;, + 3;1819,1818,1823;, + 3;1824,1819,1823;, + 3;1820,1819,1824;, + 3;1825,1820,1824;, + 3;1826,1820,1825;, + 3;1826,1821,1820;, + 3;1827,1821,1826;, + 3;1827,1822,1821;, + 3;1823,1207,1212;, + 3;1828,1823,1212;, + 3;1824,1823,1828;, + 3;1829,1824,1828;, + 3;1825,1824,1829;, + 3;1830,1825,1829;, + 3;1831,1825,1830;, + 3;1831,1826,1825;, + 3;1832,1826,1831;, + 3;1832,1827,1826;, + 3;1828,1212,1217;, + 3;1833,1828,1217;, + 3;1829,1828,1833;, + 3;1834,1829,1833;, + 3;1830,1829,1834;, + 3;1835,1830,1834;, + 3;1836,1830,1835;, + 3;1836,1831,1830;, + 3;1837,1831,1836;, + 3;1837,1832,1831;, + 3;1833,1217,1222;, + 3;1838,1833,1222;, + 3;1834,1833,1838;, + 3;1839,1834,1838;, + 3;1835,1834,1839;, + 3;1840,1835,1839;, + 3;1841,1835,1840;, + 3;1841,1836,1835;, + 3;1842,1836,1841;, + 3;1842,1837,1836;, + 3;1838,1222,1227;, + 3;1843,1838,1227;, + 3;1839,1838,1843;, + 3;1844,1839,1843;, + 3;1840,1839,1844;, + 3;1845,1840,1844;, + 3;1846,1840,1845;, + 3;1846,1841,1840;, + 3;1847,1841,1846;, + 3;1847,1842,1841;, + 3;1843,1227,1232;, + 3;1848,1843,1232;, + 3;1844,1843,1848;, + 3;1849,1844,1848;, + 3;1845,1844,1849;, + 3;1850,1845,1849;, + 3;1851,1845,1850;, + 3;1851,1846,1845;, + 3;1852,1846,1851;, + 3;1852,1847,1846;, + 3;1848,1232,1237;, + 3;1853,1848,1237;, + 3;1849,1848,1853;, + 3;1854,1849,1853;, + 3;1850,1849,1854;, + 3;1306,1850,1854;, + 3;1312,1850,1306;, + 3;1312,1851,1850;, + 3;1318,1851,1312;, + 3;1318,1852,1851;, + 3;1853,1237,1242;, + 3;1855,1853,1242;, + 3;1854,1853,1855;, + 3;1300,1854,1855;, + 3;1306,1854,1300;, + 3;1855,1242,1247;, + 3;1294,1855,1247;, + 3;1300,1855,1294;, + 3;1324,1852,1318;, + 3;1324,1856,1852;, + 3;1856,1847,1852;, + 3;1856,1857,1847;, + 3;1857,1842,1847;, + 3;1857,1858,1842;, + 3;1858,1837,1842;, + 3;1330,1856,1324;, + 3;1330,1859,1856;, + 3;1859,1857,1856;, + 3;1859,1860,1857;, + 3;1860,1858,1857;, + 3;1860,1861,1858;, + 3;1861,1862,1858;, + 3;1858,1862,1837;, + 3;1862,1832,1837;, + 3;1862,1863,1832;, + 3;1863,1827,1832;, + 3;1335,1859,1330;, + 3;1335,1864,1859;, + 3;1864,1860,1859;, + 3;1864,1865,1860;, + 3;1865,1861,1860;, + 3;1865,1866,1861;, + 3;1866,1867,1861;, + 3;1861,1867,1862;, + 3;1867,1863,1862;, + 3;1867,1868,1863;, + 3;1868,1869,1863;, + 3;1863,1869,1827;, + 3;1869,1822,1827;, + 3;1340,1864,1335;, + 3;1340,1870,1864;, + 3;1870,1865,1864;, + 3;1870,1871,1865;, + 3;1871,1866,1865;, + 3;1871,1872,1866;, + 3;1872,1873,1866;, + 3;1866,1873,1867;, + 3;1873,1868,1867;, + 3;1873,1874,1868;, + 3;1874,1875,1868;, + 3;1868,1875,1869;, + 3;1345,1870,1340;, + 3;1345,1876,1870;, + 3;1876,1871,1870;, + 3;1876,1877,1871;, + 3;1877,1872,1871;, + 3;1877,1878,1872;, + 3;1878,1879,1872;, + 3;1872,1879,1873;, + 3;1879,1874,1873;, + 3;1879,1880,1874;, + 3;1880,1881,1874;, + 3;1874,1881,1875;, + 3;1351,1876,1345;, + 3;1351,1882,1876;, + 3;1882,1877,1876;, + 3;1882,1883,1877;, + 3;1883,1878,1877;, + 3;1883,1884,1878;, + 3;1884,1885,1878;, + 3;1878,1885,1879;, + 3;1885,1880,1879;, + 3;1885,1886,1880;, + 3;1886,1887,1880;, + 3;1880,1887,1881;, + 3;1888,1882,1351;, + 3;1888,1889,1882;, + 3;1889,1883,1882;, + 3;1889,1890,1883;, + 3;1890,1884,1883;, + 3;1890,1891,1884;, + 3;1891,1892,1884;, + 3;1884,1892,1885;, + 3;1892,1886,1885;, + 3;1350,1888,1351;, + 3;1362,1888,1350;, + 3;1362,1893,1888;, + 3;1893,1889,1888;, + 3;1893,1894,1889;, + 3;1894,1890,1889;, + 3;1894,1895,1890;, + 3;1895,1891,1890;, + 3;1895,1896,1891;, + 3;1896,1897,1891;, + 3;1891,1897,1892;, + 3;1897,1898,1892;, + 3;1892,1898,1886;, + 3;1899,1893,1362;, + 3;1899,1900,1893;, + 3;1900,1894,1893;, + 3;1900,1901,1894;, + 3;1901,1895,1894;, + 3;1901,1902,1895;, + 3;1902,1896,1895;, + 3;1902,1903,1896;, + 3;1903,1904,1896;, + 3;1896,1904,1897;, + 3;1361,1899,1362;, + 3;1361,1368,1899;, + 3;1899,1368,1905;, + 3;1899,1905,1900;, + 3;1900,1905,1906;, + 3;1900,1906,1901;, + 3;1901,1906,1907;, + 3;1901,1907,1902;, + 3;1902,1907,1908;, + 3;1902,1908,1903;, + 3;1903,1908,1909;, + 3;1903,1909,1910;, + 3;1903,1910,1904;, + 3;1368,1911,1905;, + 3;1905,1911,1912;, + 3;1905,1912,1906;, + 3;1906,1912,1913;, + 3;1906,1913,1907;, + 3;1907,1913,1914;, + 3;1907,1914,1908;, + 3;1908,1914,1915;, + 3;1908,1915,1909;, + 3;1368,1367,1911;, + 3;1367,1916,1911;, + 3;1911,1916,1917;, + 3;1911,1917,1912;, + 3;1912,1917,1918;, + 3;1912,1918,1913;, + 3;1913,1918,1919;, + 3;1913,1919,1914;, + 3;1914,1919,1920;, + 3;1914,1920,1915;, + 3;1367,1373,1916;, + 3;1373,1921,1916;, + 3;1916,1921,1922;, + 3;1916,1922,1917;, + 3;1917,1922,1923;, + 3;1917,1923,1918;, + 3;1918,1923,1924;, + 3;1918,1924,1919;, + 3;1919,1924,1925;, + 3;1919,1925,1920;, + 3;1373,1378,1921;, + 3;1378,1926,1921;, + 3;1921,1926,1927;, + 3;1921,1927,1922;, + 3;1922,1927,1928;, + 3;1922,1928,1923;, + 3;1923,1928,1929;, + 3;1923,1929,1924;, + 3;1924,1929,1930;, + 3;1924,1930,1925;, + 3;1378,1383,1926;, + 3;1383,1931,1926;, + 3;1926,1931,1932;, + 3;1926,1932,1927;, + 3;1927,1932,1933;, + 3;1927,1933,1928;, + 3;1928,1933,1934;, + 3;1928,1934,1929;, + 3;1929,1934,1935;, + 3;1929,1935,1930;, + 3;1383,1388,1931;, + 3;1388,1936,1931;, + 3;1931,1936,1937;, + 3;1931,1937,1932;, + 3;1932,1937,1938;, + 3;1932,1938,1933;, + 3;1933,1938,1939;, + 3;1933,1939,1934;, + 3;1934,1939,1940;, + 3;1934,1940,1935;, + 3;1388,1393,1936;, + 3;1393,1941,1936;, + 3;1936,1941,1942;, + 3;1936,1942,1937;, + 3;1937,1942,1943;, + 3;1937,1943,1938;, + 3;1938,1943,1944;, + 3;1938,1944,1939;, + 3;1939,1944,1945;, + 3;1939,1945,1940;, + 3;1393,1398,1941;, + 3;1398,1946,1941;, + 3;1941,1946,1947;, + 3;1941,1947,1942;, + 3;1942,1947,1948;, + 3;1942,1948,1943;, + 3;1943,1948,1949;, + 3;1943,1949,1944;, + 3;1944,1949,1950;, + 3;1944,1950,1945;, + 3;1398,1403,1946;, + 3;1403,1951,1946;, + 3;1946,1951,1952;, + 3;1946,1952,1947;, + 3;1947,1952,1953;, + 3;1947,1953,1948;, + 3;1948,1953,1954;, + 3;1948,1954,1949;, + 3;1949,1954,1955;, + 3;1949,1955,1950;, + 3;1403,1408,1951;, + 3;1408,1956,1951;, + 3;1951,1956,1957;, + 3;1951,1957,1952;, + 3;1952,1957,1958;, + 3;1952,1958,1953;, + 3;1953,1958,1959;, + 3;1953,1959,1954;, + 3;1954,1959,1960;, + 3;1954,1960,1955;, + 3;1408,1413,1956;, + 3;1413,1457,1956;, + 3;1956,1457,1463;, + 3;1956,1463,1957;, + 3;1957,1463,1469;, + 3;1957,1469,1958;, + 3;1958,1469,1475;, + 3;1958,1475,1959;, + 3;1959,1475,1481;, + 3;1959,1481,1960;, + 3;1960,1481,1487;, + 3;1960,1487,1961;, + 3;1955,1960,1961;, + 3;1955,1961,1962;, + 3;1950,1955,1962;, + 3;1950,1962,1963;, + 3;1945,1950,1963;, + 3;1961,1487,1493;, + 3;1961,1493,1964;, + 3;1962,1961,1964;, + 3;1962,1964,1965;, + 3;1963,1962,1965;, + 3;1963,1965,1966;, + 3;1967,1963,1966;, + 3;1945,1963,1967;, + 3;1940,1945,1967;, + 3;1940,1967,1968;, + 3;1935,1940,1968;, + 3;1964,1493,1499;, + 3;1964,1499,1969;, + 3;1965,1964,1969;, + 3;1965,1969,1970;, + 3;1966,1965,1970;, + 3;1966,1970,1971;, + 3;1972,1966,1971;, + 3;1967,1966,1972;, + 3;1968,1967,1972;, + 3;1968,1972,1973;, + 3;1974,1968,1973;, + 3;1935,1968,1974;, + 3;1930,1935,1974;, + 3;1969,1499,1505;, + 3;1969,1505,1975;, + 3;1970,1969,1975;, + 3;1970,1975,1976;, + 3;1971,1970,1976;, + 3;1971,1976,1977;, + 3;1978,1971,1977;, + 3;1972,1971,1978;, + 3;1973,1972,1978;, + 3;1973,1978,1979;, + 3;1980,1973,1979;, + 3;1974,1973,1980;, + 3;1975,1505,1511;, + 3;1975,1511,1981;, + 3;1976,1975,1981;, + 3;1976,1981,1982;, + 3;1977,1976,1982;, + 3;1977,1982,1983;, + 3;1984,1977,1983;, + 3;1978,1977,1984;, + 3;1979,1978,1984;, + 3;1979,1984,1985;, + 3;1986,1979,1985;, + 3;1980,1979,1986;, + 3;1981,1511,1517;, + 3;1981,1517,1987;, + 3;1982,1981,1987;, + 3;1982,1987,1988;, + 3;1983,1982,1988;, + 3;1983,1988,1989;, + 3;1990,1983,1989;, + 3;1984,1983,1990;, + 3;1985,1984,1990;, + 3;1985,1990,1991;, + 3;1992,1985,1991;, + 3;1986,1985,1992;, + 3;1987,1517,1523;, + 3;1987,1523,1993;, + 3;1988,1987,1993;, + 3;1988,1993,1994;, + 3;1989,1988,1994;, + 3;1989,1994,1995;, + 3;1996,1989,1995;, + 3;1990,1989,1996;, + 3;1991,1990,1996;, + 3;1991,1996,1997;, + 3;1998,1991,1997;, + 3;1992,1991,1998;, + 3;1993,1523,1529;, + 3;1993,1529,1999;, + 3;1994,1993,1999;, + 3;1994,1999,2000;, + 3;1995,1994,2000;, + 3;1995,2000,2001;, + 3;2002,1995,2001;, + 3;1996,1995,2002;, + 3;1997,1996,2002;, + 3;1997,2002,2003;, + 3;2004,1997,2003;, + 3;1998,1997,2004;, + 3;1999,1529,1535;, + 3;1999,1535,2005;, + 3;2000,1999,2005;, + 3;2000,2005,2006;, + 3;2001,2000,2006;, + 3;2001,2006,2007;, + 3;2008,2001,2007;, + 3;2002,2001,2008;, + 3;2003,2002,2008;, + 3;2003,2008,2009;, + 3;2010,2003,2009;, + 3;2004,2003,2010;, + 3;2005,1535,1541;, + 3;2005,1541,2011;, + 3;2006,2005,2011;, + 3;2006,2011,2012;, + 3;2007,2006,2012;, + 3;2007,2012,2013;, + 3;2014,2007,2013;, + 3;2008,2007,2014;, + 3;2009,2008,2014;, + 3;2009,2014,2015;, + 3;2016,2009,2015;, + 3;2010,2009,2016;, + 3;2011,1541,1547;, + 3;2011,1547,2017;, + 3;2012,2011,2017;, + 3;2012,2017,2018;, + 3;2013,2012,2018;, + 3;2013,2018,2019;, + 3;2020,2013,2019;, + 3;2014,2013,2020;, + 3;2015,2014,2020;, + 3;2015,2020,2021;, + 3;2022,2015,2021;, + 3;2016,2015,2022;, + 3;2017,1547,1553;, + 3;2017,1553,2023;, + 3;2018,2017,2023;, + 3;2018,2023,2024;, + 3;2019,2018,2024;, + 3;2019,2024,2025;, + 3;2026,2019,2025;, + 3;2020,2019,2026;, + 3;2021,2020,2026;, + 3;2021,2026,2027;, + 3;2028,2021,2027;, + 3;2022,2021,2028;, + 3;2023,1553,1559;, + 3;2023,1559,2029;, + 3;2024,2023,2029;, + 3;2024,2029,2030;, + 3;2025,2024,2030;, + 3;2025,2030,2031;, + 3;2032,2025,2031;, + 3;2026,2025,2032;, + 3;2027,2026,2032;, + 3;2027,2032,2033;, + 3;2034,2027,2033;, + 3;2028,2027,2034;, + 3;2029,1559,1565;, + 3;2029,1565,2035;, + 3;2030,2029,2035;, + 3;2030,2035,2036;, + 3;2031,2030,2036;, + 3;2031,2036,2037;, + 3;2038,2031,2037;, + 3;2032,2031,2038;, + 3;2033,2032,2038;, + 3;2033,2038,2039;, + 3;2040,2033,2039;, + 3;2034,2033,2040;, + 3;2035,1565,1571;, + 3;2035,1571,2041;, + 3;2036,2035,2041;, + 3;2036,2041,2042;, + 3;2037,2036,2042;, + 3;2037,2042,2043;, + 3;2044,2037,2043;, + 3;2038,2037,2044;, + 3;2039,2038,2044;, + 3;2039,2044,2045;, + 3;2046,2039,2045;, + 3;2040,2039,2046;, + 3;2041,1571,1577;, + 3;2041,1577,2047;, + 3;2042,2041,2047;, + 3;2042,2047,2048;, + 3;2043,2042,2048;, + 3;2043,2048,2049;, + 3;2050,2043,2049;, + 3;2044,2043,2050;, + 3;2045,2044,2050;, + 3;2045,2050,2051;, + 3;2052,2045,2051;, + 3;2046,2045,2052;, + 3;2047,1577,1583;, + 3;2047,1583,2053;, + 3;2048,2047,2053;, + 3;2048,2053,2054;, + 3;2049,2048,2054;, + 3;2049,2054,2055;, + 3;2056,2049,2055;, + 3;2050,2049,2056;, + 3;2051,2050,2056;, + 3;2051,2056,2057;, + 3;2058,2051,2057;, + 3;2052,2051,2058;, + 3;2053,1583,1589;, + 3;2053,1589,2059;, + 3;2054,2053,2059;, + 3;2054,2059,2060;, + 3;2055,2054,2060;, + 3;2055,2060,2061;, + 3;2062,2055,2061;, + 3;2056,2055,2062;, + 3;2057,2056,2062;, + 3;2057,2062,2063;, + 3;2064,2057,2063;, + 3;2058,2057,2064;, + 3;2059,1589,1595;, + 3;2059,1595,2065;, + 3;2060,2059,2065;, + 3;2060,2065,2066;, + 3;2061,2060,2066;, + 3;2061,2066,2067;, + 3;2068,2061,2067;, + 3;2062,2061,2068;, + 3;2063,2062,2068;, + 3;2063,2068,2069;, + 3;2070,2063,2069;, + 3;2064,2063,2070;, + 3;2065,1595,1601;, + 3;2065,1601,2071;, + 3;2066,2065,2071;, + 3;2066,2071,2072;, + 3;2067,2066,2072;, + 3;2067,2072,2073;, + 3;2074,2067,2073;, + 3;2068,2067,2074;, + 3;2069,2068,2074;, + 3;2069,2074,2075;, + 3;2076,2069,2075;, + 3;2070,2069,2076;, + 3;2071,1601,1607;, + 3;2071,1607,2077;, + 3;2072,2071,2077;, + 3;2072,2077,2078;, + 3;2073,2072,2078;, + 3;2073,2078,2079;, + 3;2080,2073,2079;, + 3;2074,2073,2080;, + 3;2075,2074,2080;, + 3;2075,2080,2081;, + 3;2082,2075,2081;, + 3;2076,2075,2082;, + 3;2077,1607,1613;, + 3;2077,1613,2083;, + 3;2078,2077,2083;, + 3;2078,2083,2084;, + 3;2079,2078,2084;, + 3;2079,2084,2085;, + 3;2086,2079,2085;, + 3;2080,2079,2086;, + 3;2081,2080,2086;, + 3;2081,2086,2087;, + 3;2088,2081,2087;, + 3;2082,2081,2088;, + 3;2083,1613,1619;, + 3;2083,1619,1642;, + 3;2084,2083,1642;, + 3;2084,1642,1641;, + 3;2085,2084,1641;, + 3;2085,1641,1647;, + 3;2089,2085,1647;, + 3;2086,2085,2089;, + 3;2087,2086,2089;, + 3;2087,2089,2090;, + 3;2091,2087,2090;, + 3;2088,2087,2091;, + 3;2092,2088,2091;, + 3;2093,2088,2092;, + 3;2093,2082,2088;, + 3;2089,1647,1652;, + 3;2090,2089,1652;, + 3;2090,1652,1657;, + 3;1672,2090,1657;, + 3;2091,2090,1672;, + 3;1677,2091,1672;, + 3;2092,2091,1677;, + 3;1682,2092,1677;, + 3;2094,2092,1682;, + 3;2094,2093,2092;, + 3;2095,2093,2094;, + 3;2095,2096,2093;, + 3;2096,2082,2093;, + 3;2096,2076,2082;, + 3;2097,2076,2096;, + 3;2097,2070,2076;, + 3;1687,2094,1682;, + 3;2098,2094,1687;, + 3;2098,2095,2094;, + 3;2099,2095,2098;, + 3;2099,2100,2095;, + 3;2100,2096,2095;, + 3;2100,2097,2096;, + 3;2101,2097,2100;, + 3;2101,2102,2097;, + 3;2102,2070,2097;, + 3;2102,2064,2070;, + 3;1692,2098,1687;, + 3;2103,2098,1692;, + 3;2103,2099,2098;, + 3;2104,2099,2103;, + 3;2104,2105,2099;, + 3;2105,2100,2099;, + 3;2105,2101,2100;, + 3;2106,2101,2105;, + 3;2106,2107,2101;, + 3;2107,2102,2101;, + 3;2107,2108,2102;, + 3;2108,2064,2102;, + 3;2108,2058,2064;, + 3;1697,2103,1692;, + 3;2109,2103,1697;, + 3;2109,2104,2103;, + 3;2110,2104,2109;, + 3;2110,2111,2104;, + 3;2111,2105,2104;, + 3;2111,2106,2105;, + 3;2112,2106,2111;, + 3;2112,2113,2106;, + 3;2113,2107,2106;, + 3;2113,2114,2107;, + 3;2114,2108,2107;, + 3;1702,2109,1697;, + 3;2115,2109,1702;, + 3;2115,2110,2109;, + 3;2116,2110,2115;, + 3;2116,2117,2110;, + 3;2117,2111,2110;, + 3;2117,2112,2111;, + 3;2118,2112,2117;, + 3;2118,2119,2112;, + 3;2119,2113,2112;, + 3;2119,2120,2113;, + 3;2120,2114,2113;, + 3;2115,1702,1707;, + 3;2115,1707,2121;, + 3;2116,2115,2121;, + 3;2116,2121,2122;, + 3;2123,2116,2122;, + 3;2123,2117,2116;, + 3;2123,2118,2117;, + 3;2124,2118,2123;, + 3;2124,2125,2118;, + 3;2125,2119,2118;, + 3;2125,2126,2119;, + 3;2126,2120,2119;, + 3;2121,1707,1712;, + 3;2121,1712,2127;, + 3;2122,2121,2127;, + 3;2122,2127,2128;, + 3;2129,2122,2128;, + 3;2123,2122,2129;, + 3;2124,2123,2129;, + 3;2124,2129,2130;, + 3;2131,2124,2130;, + 3;2131,2125,2124;, + 3;2131,2132,2125;, + 3;2132,2126,2125;, + 3;2127,1712,1717;, + 3;2127,1717,2133;, + 3;2128,2127,2133;, + 3;2128,2133,2134;, + 3;2135,2128,2134;, + 3;2129,2128,2135;, + 3;2130,2129,2135;, + 3;2130,2135,2136;, + 3;2137,2130,2136;, + 3;2131,2130,2137;, + 3;2138,2131,2137;, + 3;2138,2132,2131;, + 3;2133,1717,1722;, + 3;2133,1722,2139;, + 3;2134,2133,2139;, + 3;2134,2139,2140;, + 3;2141,2134,2140;, + 3;2135,2134,2141;, + 3;2136,2135,2141;, + 3;2136,2141,2142;, + 3;2143,2136,2142;, + 3;2137,2136,2143;, + 3;2144,2137,2143;, + 3;2138,2137,2144;, + 3;2139,1722,1727;, + 3;2139,1727,2145;, + 3;2140,2139,2145;, + 3;2140,2145,2146;, + 3;2147,2140,2146;, + 3;2141,2140,2147;, + 3;2142,2141,2147;, + 3;2142,2147,2148;, + 3;2149,2142,2148;, + 3;2143,2142,2149;, + 3;2150,2143,2149;, + 3;2144,2143,2150;, + 3;2145,1727,1732;, + 3;2145,1732,2151;, + 3;2146,2145,2151;, + 3;2146,2151,2152;, + 3;2153,2146,2152;, + 3;2147,2146,2153;, + 3;2148,2147,2153;, + 3;2148,2153,2154;, + 3;2155,2148,2154;, + 3;2149,2148,2155;, + 3;2156,2149,2155;, + 3;2150,2149,2156;, + 3;2151,1732,1737;, + 3;2151,1737,2157;, + 3;2152,2151,2157;, + 3;2152,2157,2158;, + 3;2159,2152,2158;, + 3;2153,2152,2159;, + 3;2154,2153,2159;, + 3;2154,2159,2160;, + 3;2161,2154,2160;, + 3;2155,2154,2161;, + 3;2162,2155,2161;, + 3;2156,2155,2162;, + 3;2157,1737,1742;, + 3;2157,1742,2163;, + 3;2158,2157,2163;, + 3;2158,2163,2164;, + 3;2165,2158,2164;, + 3;2159,2158,2165;, + 3;2160,2159,2165;, + 3;2160,2165,2166;, + 3;2167,2160,2166;, + 3;2161,2160,2167;, + 3;2168,2161,2167;, + 3;2162,2161,2168;, + 3;2163,1742,1747;, + 3;2163,1747,1762;, + 3;2164,2163,1762;, + 3;2164,1762,1767;, + 3;2169,2164,1767;, + 3;2165,2164,2169;, + 3;2166,2165,2169;, + 3;2166,2169,2170;, + 3;2171,2166,2170;, + 3;2167,2166,2171;, + 3;2172,2167,2171;, + 3;2168,2167,2172;, + 3;2173,2168,2172;, + 3;2174,2168,2173;, + 3;2174,2162,2168;, + 3;2169,1767,1772;, + 3;2170,2169,1772;, + 3;2170,1772,1777;, + 3;2175,2170,1777;, + 3;2171,2170,2175;, + 3;2176,2171,2175;, + 3;2172,2171,2176;, + 3;2177,2172,2176;, + 3;2173,2172,2177;, + 3;2178,2173,2177;, + 3;2179,2173,2178;, + 3;2179,2174,2173;, + 3;2175,1777,1782;, + 3;2180,2175,1782;, + 3;2176,2175,2180;, + 3;2181,2176,2180;, + 3;2177,2176,2181;, + 3;2182,2177,2181;, + 3;2178,2177,2182;, + 3;2183,2178,2182;, + 3;2184,2178,2183;, + 3;2184,2179,2178;, + 3;2180,1782,1787;, + 3;2185,2180,1787;, + 3;2181,2180,2185;, + 3;2186,2181,2185;, + 3;2182,2181,2186;, + 3;2187,2182,2186;, + 3;2183,2182,2187;, + 3;2188,2183,2187;, + 3;2189,2183,2188;, + 3;2189,2184,2183;, + 3;2185,1787,1792;, + 3;2190,2185,1792;, + 3;2186,2185,2190;, + 3;2191,2186,2190;, + 3;2187,2186,2191;, + 3;2192,2187,2191;, + 3;2188,2187,2192;, + 3;2193,2188,2192;, + 3;2194,2188,2193;, + 3;2194,2189,2188;, + 3;2190,1792,1797;, + 3;2195,2190,1797;, + 3;2191,2190,2195;, + 3;2196,2191,2195;, + 3;2192,2191,2196;, + 3;2197,2192,2196;, + 3;2193,2192,2197;, + 3;2198,2193,2197;, + 3;2199,2193,2198;, + 3;2199,2194,2193;, + 3;2195,1797,1802;, + 3;2200,2195,1802;, + 3;2196,2195,2200;, + 3;2201,2196,2200;, + 3;2197,2196,2201;, + 3;2202,2197,2201;, + 3;2198,2197,2202;, + 3;2203,2198,2202;, + 3;2204,2198,2203;, + 3;2204,2199,2198;, + 3;2200,1802,1807;, + 3;2205,2200,1807;, + 3;2201,2200,2205;, + 3;2206,2201,2205;, + 3;2202,2201,2206;, + 3;2207,2202,2206;, + 3;2203,2202,2207;, + 3;1887,2203,2207;, + 3;2208,2203,1887;, + 3;2208,2204,2203;, + 3;2205,1807,1812;, + 3;2209,2205,1812;, + 3;2206,2205,2209;, + 3;2210,2206,2209;, + 3;2207,2206,2210;, + 3;1881,2207,2210;, + 3;1887,2207,1881;, + 3;2209,1812,1817;, + 3;2211,2209,1817;, + 3;2210,2209,2211;, + 3;1875,2210,2211;, + 3;1881,2210,1875;, + 3;2211,1817,1822;, + 3;1869,2211,1822;, + 3;1875,2211,1869;, + 3;1886,2208,1887;, + 3;1898,2208,1886;, + 3;1898,2212,2208;, + 3;2212,2204,2208;, + 3;2212,2213,2204;, + 3;2213,2199,2204;, + 3;2213,2214,2199;, + 3;2214,2194,2199;, + 3;2215,2212,1898;, + 3;2215,2216,2212;, + 3;2216,2213,2212;, + 3;2216,2217,2213;, + 3;2217,2214,2213;, + 3;2217,2218,2214;, + 3;2218,2219,2214;, + 3;2214,2219,2194;, + 3;2219,2189,2194;, + 3;1897,2215,1898;, + 3;1904,2215,1897;, + 3;1904,2220,2215;, + 3;2220,2216,2215;, + 3;2220,2221,2216;, + 3;2221,2217,2216;, + 3;2221,2222,2217;, + 3;2222,2218,2217;, + 3;2222,2223,2218;, + 3;2223,2224,2218;, + 3;2218,2224,2219;, + 3;2224,2225,2219;, + 3;2219,2225,2189;, + 3;2225,2184,2189;, + 3;1910,2220,1904;, + 3;1910,2226,2220;, + 3;2226,2221,2220;, + 3;2226,2227,2221;, + 3;2227,2222,2221;, + 3;2227,2228,2222;, + 3;2228,2223,2222;, + 3;2228,2229,2223;, + 3;2229,2230,2223;, + 3;2223,2230,2224;, + 3;2230,2231,2224;, + 3;2224,2231,2225;, + 3;1910,2232,2226;, + 3;2226,2232,2233;, + 3;2226,2233,2227;, + 3;2227,2233,2234;, + 3;2227,2234,2228;, + 3;2228,2234,2235;, + 3;2228,2235,2229;, + 3;2229,2235,2236;, + 3;2229,2236,2237;, + 3;2229,2237,2230;, + 3;1910,1909,2232;, + 3;1909,2238,2232;, + 3;2232,2238,2239;, + 3;2232,2239,2233;, + 3;2233,2239,2240;, + 3;2233,2240,2234;, + 3;2234,2240,2241;, + 3;2234,2241,2235;, + 3;2235,2241,2242;, + 3;2235,2242,2236;, + 3;1909,1915,2238;, + 3;1915,2243,2238;, + 3;2238,2243,2244;, + 3;2238,2244,2239;, + 3;2239,2244,2245;, + 3;2239,2245,2240;, + 3;2240,2245,2246;, + 3;2240,2246,2241;, + 3;2241,2246,2247;, + 3;2241,2247,2242;, + 3;1915,1920,2243;, + 3;1920,2248,2243;, + 3;2243,2248,2249;, + 3;2243,2249,2244;, + 3;2244,2249,2250;, + 3;2244,2250,2245;, + 3;2245,2250,2251;, + 3;2245,2251,2246;, + 3;2246,2251,2252;, + 3;2246,2252,2247;, + 3;1920,1925,2248;, + 3;1925,2253,2248;, + 3;2248,2253,2254;, + 3;2248,2254,2249;, + 3;2249,2254,2255;, + 3;2249,2255,2250;, + 3;2250,2255,2256;, + 3;2250,2256,2251;, + 3;2251,2256,2257;, + 3;2251,2257,2252;, + 3;1925,1930,2253;, + 3;1930,1974,2253;, + 3;2253,1974,1980;, + 3;2253,1980,2254;, + 3;2254,1980,1986;, + 3;2254,1986,2255;, + 3;2255,1986,1992;, + 3;2255,1992,2256;, + 3;2256,1992,1998;, + 3;2256,1998,2257;, + 3;2257,1998,2004;, + 3;2257,2004,2258;, + 3;2252,2257,2258;, + 3;2252,2258,2259;, + 3;2247,2252,2259;, + 3;2247,2259,2260;, + 3;2242,2247,2260;, + 3;2258,2004,2010;, + 3;2258,2010,2261;, + 3;2259,2258,2261;, + 3;2259,2261,2262;, + 3;2260,2259,2262;, + 3;2260,2262,2263;, + 3;2264,2260,2263;, + 3;2242,2260,2264;, + 3;2236,2242,2264;, + 3;2236,2264,2265;, + 3;2237,2236,2265;, + 3;2261,2010,2016;, + 3;2261,2016,2266;, + 3;2262,2261,2266;, + 3;2262,2266,2267;, + 3;2263,2262,2267;, + 3;2263,2267,2268;, + 3;2269,2263,2268;, + 3;2264,2263,2269;, + 3;2265,2264,2269;, + 3;2265,2269,2270;, + 3;2271,2265,2270;, + 3;2237,2265,2271;, + 3;2266,2016,2022;, + 3;2266,2022,2272;, + 3;2267,2266,2272;, + 3;2267,2272,2273;, + 3;2268,2267,2273;, + 3;2268,2273,2274;, + 3;2275,2268,2274;, + 3;2269,2268,2275;, + 3;2270,2269,2275;, + 3;2270,2275,2276;, + 3;2277,2270,2276;, + 3;2271,2270,2277;, + 3;2272,2022,2028;, + 3;2272,2028,2278;, + 3;2273,2272,2278;, + 3;2273,2278,2279;, + 3;2274,2273,2279;, + 3;2274,2279,2280;, + 3;2281,2274,2280;, + 3;2275,2274,2281;, + 3;2276,2275,2281;, + 3;2276,2281,2282;, + 3;2283,2276,2282;, + 3;2277,2276,2283;, + 3;2278,2028,2034;, + 3;2278,2034,2284;, + 3;2279,2278,2284;, + 3;2279,2284,2285;, + 3;2280,2279,2285;, + 3;2280,2285,2286;, + 3;2287,2280,2286;, + 3;2281,2280,2287;, + 3;2282,2281,2287;, + 3;2282,2287,2288;, + 3;2289,2282,2288;, + 3;2283,2282,2289;, + 3;2284,2034,2040;, + 3;2284,2040,2290;, + 3;2285,2284,2290;, + 3;2285,2290,2291;, + 3;2286,2285,2291;, + 3;2286,2291,2292;, + 3;2293,2286,2292;, + 3;2287,2286,2293;, + 3;2288,2287,2293;, + 3;2288,2293,2132;, + 3;2138,2288,2132;, + 3;2289,2288,2138;, + 3;2290,2040,2046;, + 3;2290,2046,2294;, + 3;2291,2290,2294;, + 3;2291,2294,2295;, + 3;2292,2291,2295;, + 3;2292,2295,2120;, + 3;2126,2292,2120;, + 3;2293,2292,2126;, + 3;2132,2293,2126;, + 3;2294,2046,2052;, + 3;2294,2052,2296;, + 3;2295,2294,2296;, + 3;2295,2296,2114;, + 3;2120,2295,2114;, + 3;2296,2052,2058;, + 3;2296,2058,2108;, + 3;2114,2296,2108;, + 3;2289,2138,2144;, + 3;2289,2144,2297;, + 3;2283,2289,2297;, + 3;2283,2297,2298;, + 3;2277,2283,2298;, + 3;2277,2298,2299;, + 3;2271,2277,2299;, + 3;2297,2144,2150;, + 3;2297,2150,2300;, + 3;2298,2297,2300;, + 3;2298,2300,2301;, + 3;2299,2298,2301;, + 3;2299,2301,2302;, + 3;2303,2299,2302;, + 3;2271,2299,2303;, + 3;2237,2271,2303;, + 3;2237,2303,2230;, + 3;2230,2303,2231;, + 3;2300,2150,2156;, + 3;2300,2156,2304;, + 3;2301,2300,2304;, + 3;2301,2304,2305;, + 3;2302,2301,2305;, + 3;2302,2305,2306;, + 3;2231,2302,2306;, + 3;2303,2302,2231;, + 3;2304,2156,2162;, + 3;2304,2162,2174;, + 3;2305,2304,2174;, + 3;2305,2174,2179;, + 3;2306,2305,2179;, + 3;2306,2179,2184;, + 3;2225,2306,2184;, + 3;2231,2306,2225;; + + MeshNormals { + 2307; + -0.036282;0.997085;-0.067122;, + -0.044735;0.997085;-0.061811;, + 0.015507;0.999866;-0.005264;, + -0.066112;0.990719;-0.118761;, + -0.081047;0.990720;-0.109116;, + -0.052418;0.997085;-0.055445;, + -0.023664;0.999688;0.008033;, + -0.027213;0.997085;-0.071283;, + -0.050046;0.990719;-0.126374;, + -0.074061;0.980077;-0.184295;, + -0.097484;0.980077;-0.173051;, + -0.119235;0.980077;-0.158848;, + -0.094596;0.990720;-0.097603;, + -0.017674;0.997085;-0.074225;, + -0.033123;0.990719;-0.131825;, + -0.049373;0.980077;-0.192386;, + -0.065651;0.965231;-0.253022;, + -0.098117;0.965231;-0.242287;, + -0.128902;0.965231;-0.227407;, + -0.007831;0.997085;-0.075897;, + -0.015630;0.990719;-0.135021;, + -0.023837;0.980077;-0.197185;, + -0.032065;0.965230;-0.259427;, + -0.040200;0.946251;-0.320926;, + -0.081747;0.946251;-0.312932;, + -0.000000;0.997859;-0.065402;, + 0.000000;0.992279;-0.124023;, + -0.000000;0.982353;-0.187038;, + 0.000000;0.968207;-0.250151;, + 0.000000;0.949908;-0.312529;, + 0.007831;0.997085;-0.075897;, + 0.015630;0.990719;-0.135021;, + 0.023837;0.980077;-0.197185;, + 0.032065;0.965230;-0.259427;, + 0.040200;0.946251;-0.320926;, + 0.000000;0.927544;-0.373713;, + 0.017674;0.997085;-0.074225;, + 0.033123;0.990719;-0.131825;, + 0.049373;0.980077;-0.192386;, + 0.065651;0.965231;-0.253022;, + 0.081747;0.946251;-0.312932;, + 0.048191;0.923218;-0.381243;, + 0.027213;0.997085;-0.071283;, + 0.050046;0.990719;-0.126374;, + 0.074061;0.980077;-0.184295;, + 0.098117;0.965231;-0.242287;, + 0.121896;0.946250;-0.299586;, + 0.097546;0.923217;-0.371692;, + 0.036282;0.997085;-0.067122;, + 0.066112;0.990720;-0.118761;, + 0.097484;0.980077;-0.173051;, + 0.128902;0.965231;-0.227407;, + 0.159955;0.946251;-0.281112;, + 0.145224;0.923217;-0.355781;, + 0.044735;0.997085;-0.061811;, + 0.081047;0.990720;-0.109116;, + 0.119235;0.980077;-0.158848;, + 0.157482;0.965231;-0.208637;, + 0.195281;0.946250;-0.257828;, + 0.190422;0.923217;-0.333781;, + 0.052418;0.997085;-0.055445;, + 0.094596;0.990720;-0.097603;, + 0.138951;0.980077;-0.141924;, + 0.183368;0.965231;-0.186296;, + 0.227264;0.946250;-0.230134;, + 0.232361;0.923217;-0.306070;, + 0.059207;0.997085;-0.048128;, + 0.106528;0.990720;-0.084420;, + 0.156288;0.980077;-0.122572;, + 0.206116;0.965231;-0.160768;, + 0.255356;0.946251;-0.198503;, + 0.270322;0.923217;-0.273123;, + 0.064982;0.997085;-0.039990;, + 0.116635;0.990719;-0.069793;, + 0.170949;0.980077;-0.101125;, + 0.225334;0.965231;-0.132491;, + 0.279081;0.946251;-0.163473;, + 0.303658;0.923217;-0.235504;, + 0.069647;0.997085;-0.031164;, + 0.124746;0.990719;-0.053975;, + 0.182685;0.980077;-0.077949;, + 0.240703;0.965231;-0.101942;, + 0.298033;0.946250;-0.125645;, + 0.331801;0.923217;-0.193852;, + 0.073117;0.997085;-0.021808;, + 0.130724;0.990720;-0.037231;, + 0.191299;0.980076;-0.053433;, + 0.251949;0.965231;-0.069654;, + 0.311882;0.946251;-0.085671;, + 0.354265;0.923217;-0.148886;, + 0.075339;0.997085;-0.012075;, + 0.134466;0.990719;-0.019844;, + 0.196636;0.980077;-0.028007;, + 0.258885;0.965231;-0.036171;, + 0.320396;0.946251;-0.044227;, + 0.370666;0.923218;-0.101372;, + 0.076271;0.997085;-0.002138;, + 0.135906;0.990719;-0.002126;, + 0.198609;0.980077;-0.002103;, + 0.261392;0.965230;-0.002071;, + 0.323428;0.946250;-0.002029;, + 0.380726;0.923218;-0.052120;, + 0.075897;0.997085;0.007831;, + 0.135021;0.990719;0.015630;, + 0.197185;0.980077;0.023837;, + 0.259427;0.965230;0.032065;, + 0.320926;0.946251;0.040200;, + 0.384271;0.923218;-0.001981;, + 0.074225;0.997085;0.017674;, + 0.131825;0.990719;0.033123;, + 0.192386;0.980077;0.049373;, + 0.253022;0.965231;0.065651;, + 0.312932;0.946251;0.081747;, + 0.381243;0.923218;0.048191;, + 0.071283;0.997085;0.027213;, + 0.126374;0.990719;0.050046;, + 0.184295;0.980077;0.074061;, + 0.242287;0.965231;0.098117;, + 0.299586;0.946250;0.121896;, + 0.371692;0.923217;0.097546;, + 0.067122;0.997085;0.036282;, + 0.118761;0.990720;0.066112;, + 0.173051;0.980077;0.097484;, + 0.227407;0.965231;0.128902;, + 0.281112;0.946251;0.159955;, + 0.355781;0.923217;0.145224;, + 0.061811;0.997085;0.044735;, + 0.109116;0.990720;0.081047;, + 0.158848;0.980077;0.119235;, + 0.208637;0.965231;0.157482;, + 0.257828;0.946250;0.195281;, + 0.333781;0.923217;0.190422;, + 0.055445;0.997085;0.052418;, + 0.097603;0.990720;0.094596;, + 0.141924;0.980077;0.138951;, + 0.186296;0.965231;0.183368;, + 0.230134;0.946250;0.227264;, + 0.306070;0.923217;0.232361;, + 0.048128;0.997085;0.059207;, + 0.084420;0.990720;0.106528;, + 0.122572;0.980077;0.156288;, + 0.160768;0.965231;0.206116;, + 0.198503;0.946251;0.255356;, + 0.273123;0.923217;0.270322;, + 0.039990;0.997085;0.064982;, + 0.069793;0.990719;0.116635;, + 0.101125;0.980077;0.170949;, + 0.132491;0.965231;0.225334;, + 0.163473;0.946251;0.279081;, + 0.235504;0.923217;0.303658;, + 0.031164;0.997085;0.069647;, + 0.053975;0.990719;0.124746;, + 0.077949;0.980077;0.182685;, + 0.101942;0.965231;0.240703;, + 0.125645;0.946250;0.298033;, + 0.193852;0.923217;0.331801;, + 0.021808;0.997085;0.073117;, + 0.037231;0.990720;0.130724;, + 0.053433;0.980076;0.191299;, + 0.069654;0.965231;0.251949;, + 0.085671;0.946251;0.311882;, + 0.148886;0.923217;0.354265;, + 0.012075;0.997085;0.075339;, + 0.019844;0.990719;0.134466;, + 0.028007;0.980077;0.196636;, + 0.036171;0.965231;0.258885;, + 0.044227;0.946251;0.320396;, + 0.101372;0.923218;0.370666;, + 0.005351;0.996642;0.081706;, + 0.009461;0.989475;0.144392;, + 0.013623;0.978065;0.207855;, + 0.017753;0.962452;0.270871;, + 0.021817;0.942711;0.332897;, + 0.052120;0.923218;0.380726;, + 0.116669;0.896227;0.427978;, + 0.171533;0.896228;0.409087;, + 0.223461;0.896227;0.383200;, + 0.025794;0.918920;0.393599;, + 0.059806;0.896226;0.439547;, + 0.131478;0.865405;0.483515;, + 0.193466;0.865406;0.462216;, + 0.252141;0.865406;0.433009;, + 0.306506;0.865407;0.396390;, + 0.271569;0.896227;0.350753;, + 0.029671;0.891186;0.452667;, + 0.067243;0.865405;0.496541;, + 0.145742;0.830873;0.537037;, + 0.214595;0.830874;0.513418;, + 0.279773;0.830874;0.481016;, + 0.340167;0.830873;0.440382;, + 0.033417;0.859642;0.509802;, + 0.074399;0.830873;0.551465;, + 0.159392;0.792784;0.588293;, + 0.234816;0.792783;0.562455;, + 0.306224;0.792784;0.526992;, + 0.372390;0.792784;0.482514;, + 0.037018;0.824409;0.564783;, + 0.081242;0.792785;0.604062;, + 0.172365;0.751306;0.637047;, + 0.254044;0.751305;0.609100;, + 0.331374;0.751303;0.570733;, + 0.403034;0.751304;0.522596;, + 0.040463;0.785659;0.617335;, + 0.087739;0.751305;0.654097;, + 0.184607;0.706601;0.683108;, + 0.272194;0.706601;0.653166;, + 0.355118;0.706601;0.612051;, + 0.431968;0.706602;0.560462;, + 0.043736;0.743547;0.667252;, + 0.093865;0.706602;0.701358;, + 0.196064;0.658871;0.726257;, + 0.289183;0.658871;0.694451;, + 0.377350;0.658873;0.650764;, + 0.459062;0.658874;0.595942;, + 0.046821;0.698262;0.714310;, + 0.099591;0.658871;0.745634;, + 0.206681;0.608323;0.766307;, + 0.304936;0.608326;0.732771;, + 0.397973;0.608326;0.686700;, + 0.484200;0.608324;0.628882;, + 0.049701;0.649993;0.758313;, + 0.104891;0.608323;0.786728;, + 0.216418;0.555175;0.803084;, + 0.319390;0.555175;0.767966;, + 0.416899;0.555175;0.719705;, + 0.507274;0.555172;0.659134;, + 0.052373;0.598970;0.799057;, + 0.109744;0.555174;0.824462;, + 0.225232;0.499645;0.836436;, + 0.332481;0.499641;0.799885;, + 0.434044;0.499644;0.749641;, + 0.528179;0.499647;0.686571;, + 0.054823;0.545394;0.836385;, + 0.114128;0.499645;0.858679;, + 0.233085;0.441973;0.866216;, + 0.344154;0.441970;0.828384;, + 0.449335;0.441969;0.776377;, + 0.546828;0.441972;0.711084;, + 0.057032;0.489503;0.870135;, + 0.118026;0.441975;0.889229;, + 0.239941;0.382406;0.892297;, + 0.354355;0.382407;0.853345;, + 0.462705;0.382409;0.799792;, + 0.563141;0.382406;0.732556;, + 0.059001;0.431530;0.900167;, + 0.121420;0.382407;0.915981;, + 0.245771;0.321212;0.914560;, + 0.363041;0.321211;0.874657;, + 0.474099;0.321208;0.819790;, + 0.577048;0.321209;0.750893;, + 0.060717;0.371721;0.926357;, + 0.124292;0.321208;0.938817;, + 0.250550;0.258635;0.932916;, + 0.370176;0.258636;0.892232;, + 0.483469;0.258636;0.836281;, + 0.588488;0.258630;0.766024;, + 0.062174;0.310348;0.948588;, + 0.126635;0.258637;0.957638;, + 0.254258;0.194952;0.947284;, + 0.375729;0.194951;0.905992;, + 0.490768;0.194948;0.849201;, + 0.597414;0.194952;0.777876;, + 0.063366;0.247660;0.966773;, + 0.128436;0.194950;0.972368;, + 0.256879;0.130431;0.957602;, + 0.379675;0.130433;0.915879;, + 0.495971;0.130434;0.858487;, + 0.603783;0.130436;0.786405;, + 0.064284;0.183916;0.980838;, + 0.129688;0.130433;0.982939;, + 0.258402;0.065359;0.963824;, + 0.381996;0.065356;0.921850;, + 0.499052;0.065353;0.864104;, + 0.607569;0.065356;0.791574;, + 0.064936;0.119402;0.990720;, + 0.130385;0.065356;0.989307;, + 0.258819;-0.000002;0.965926;, + 0.382685;-0.000000;0.923879;, + 0.500001;0.000003;0.866025;, + 0.608759;-0.000000;0.793355;, + 0.065307;0.054380;0.996383;, + 0.130525;0.000000;0.991445;, + 0.258130;-0.065356;0.963897;, + 0.381738;-0.065355;0.921957;, + 0.498808;-0.065361;0.864245;, + 0.607348;-0.065357;0.791743;, + 0.065399;-0.010874;0.997800;, + 0.130108;-0.065357;0.989343;, + 0.256337;-0.130436;0.957746;, + 0.379157;-0.130433;0.916094;, + 0.495489;-0.130428;0.858766;, + 0.603337;-0.130435;0.786747;, + 0.065214;-0.076077;0.994967;, + 0.129135;-0.130430;0.983012;, + 0.253453;-0.194947;0.947501;, + 0.374954;-0.194954;0.906313;, + 0.490045;-0.194952;0.849617;, + 0.596748;-0.194949;0.778387;, + 0.064748;-0.140963;0.987895;, + 0.127605;-0.194953;0.972476;, + 0.249477;-0.258638;0.933203;, + 0.369151;-0.258633;0.892657;, + 0.482508;-0.258631;0.836837;, + 0.587607;-0.258633;0.766698;, + 0.064008;-0.205253;0.976614;, + 0.125534;-0.258637;0.957783;, + 0.244439;-0.321212;0.914917;, + 0.361766;-0.321215;0.875184;, + 0.472906;-0.321211;0.820478;, + 0.575955;-0.321206;0.751733;, + 0.063000;-0.268669;0.961170;, + 0.122927;-0.321209;0.938996;, + 0.238358;-0.382404;0.892722;, + 0.352839;-0.382407;0.853973;, + 0.461284;-0.382408;0.800613;, + 0.561839;-0.382409;0.733553;, + 0.061717;-0.330950;0.941628;, + 0.119793;-0.382405;0.916197;, + 0.231253;-0.441972;0.866708;, + 0.342404;-0.441968;0.829110;, + 0.447691;-0.441971;0.777325;, + 0.545324;-0.441973;0.712237;, + 0.060174;-0.391830;0.918068;, + 0.116144;-0.441976;0.889476;, + 0.223159;-0.499646;0.836991;, + 0.330502;-0.499642;0.800703;, + 0.432187;-0.499643;0.750714;, + 0.526478;-0.499643;0.687879;, + 0.058373;-0.451058;0.890584;, + 0.112002;-0.499646;0.858958;, + 0.214116;-0.555175;0.803701;, + 0.317189;-0.555175;0.768877;, + 0.414835;-0.555174;0.720898;, + 0.505383;-0.555172;0.660585;, + 0.056323;-0.508359;0.859301;, + 0.107383;-0.555173;0.824774;, + 0.204161;-0.608324;0.766981;, + 0.302523;-0.608328;0.733769;, + 0.395711;-0.608327;0.688005;, + 0.482130;-0.608326;0.630469;, + 0.054033;-0.563506;0.824343;, + 0.102304;-0.608323;0.787069;, + 0.193335;-0.658867;0.726991;, + 0.286572;-0.658870;0.695534;, + 0.374900;-0.658874;0.652178;, + 0.456820;-0.658873;0.597664;, + 0.051507;-0.616255;0.785861;, + 0.096785;-0.658872;0.746003;, + 0.181676;-0.706604;0.683890;, + 0.269394;-0.706599;0.654327;, + 0.352493;-0.706600;0.613567;, + 0.429560;-0.706603;0.562309;, + 0.048766;-0.666386;0.744010;, + 0.090858;-0.706602;0.701754;, + 0.169250;-0.751305;0.637883;, + 0.251063;-0.751305;0.610334;, + 0.328585;-0.751302;0.572344;, + 0.400474;-0.751305;0.524559;, + 0.045817;-0.713678;0.698974;, + 0.084545;-0.751304;0.654519;, + 0.156107;-0.792784;0.589173;, + 0.231672;-0.792785;0.563756;, + 0.303277;-0.792784;0.528694;, + 0.369695;-0.792783;0.484584;, + 0.042666;-0.757931;0.650938;, + 0.077869;-0.792785;0.604507;, + 0.142299;-0.830873;0.537960;, + 0.211301;-0.830873;0.514784;, + 0.276683;-0.830874;0.482799;, + 0.337339;-0.830873;0.442552;, + 0.039335;-0.798935;0.600129;, + 0.070862;-0.830874;0.551930;, + 0.127890;-0.865406;0.484475;, + 0.190035;-0.865406;0.463636;, + 0.248926;-0.865406;0.434865;, + 0.303559;-0.865406;0.398653;, + 0.035837;-0.836535;0.546741;, + 0.063562;-0.865405;0.497025;, + 0.112953;-0.896227;0.428975;, + 0.167978;-0.896227;0.410561;, + 0.220132;-0.896227;0.385123;, + 0.268515;-0.896228;0.353095;, + 0.032187;-0.870547;0.491031;, + 0.055996;-0.896226;0.440050;, + 0.097546;-0.923217;0.371692;, + 0.145224;-0.923217;0.355781;, + 0.190422;-0.923217;0.333781;, + 0.232361;-0.923217;0.306070;, + 0.028394;-0.900836;0.433231;, + 0.048191;-0.923218;0.381242;, + 0.081747;-0.946251;0.312932;, + 0.121896;-0.946250;0.299586;, + 0.159955;-0.946251;0.281112;, + 0.195281;-0.946250;0.257828;, + 0.024483;-0.927266;0.373601;, + 0.040200;-0.946251;0.320926;, + 0.065651;-0.965231;0.253022;, + 0.098117;-0.965231;0.242287;, + 0.128902;-0.965231;0.227407;, + 0.157482;-0.965231;0.208637;, + 0.020480;-0.949709;0.312464;, + 0.032065;-0.965230;0.259427;, + 0.049373;-0.980077;0.192386;, + 0.074061;-0.980077;0.184295;, + 0.097484;-0.980077;0.173051;, + 0.119235;-0.980077;0.158848;, + 0.016392;-0.968077;0.250117;, + 0.023837;-0.980077;0.197185;, + 0.033123;-0.990719;0.131825;, + 0.050046;-0.990719;0.126374;, + 0.066112;-0.990719;0.118761;, + 0.081047;-0.990720;0.109116;, + 0.012257;-0.982279;0.187024;, + 0.015630;-0.990719;0.135021;, + 0.017674;-0.997085;0.074225;, + 0.027213;-0.997085;0.071283;, + 0.036282;-0.997085;0.067122;, + 0.044735;-0.997085;0.061811;, + 0.008123;-0.992247;0.124019;, + 0.007831;-0.997085;0.075897;, + 0.020895;-0.999782;0.000000;, + 0.052418;-0.997085;0.055445;, + 0.094596;-0.990720;0.097603;, + 0.004282;-0.997850;0.065402;, + 0.138951;-0.980077;0.141924;, + 0.106528;-0.990719;0.084420;, + 0.156288;-0.980077;0.122572;, + 0.183368;-0.965231;0.186296;, + 0.059207;-0.997085;0.048128;, + 0.064982;-0.997085;0.039990;, + 0.116635;-0.990719;0.069793;, + 0.170949;-0.980077;0.101125;, + 0.206116;-0.965231;0.160768;, + 0.069647;-0.997085;0.031164;, + 0.124746;-0.990719;0.053975;, + 0.182685;-0.980077;0.077949;, + 0.225334;-0.965231;0.132491;, + 0.255356;-0.946251;0.198503;, + 0.227264;-0.946250;0.230134;, + 0.073117;-0.997085;0.021808;, + 0.130724;-0.990720;0.037231;, + 0.191299;-0.980076;0.053433;, + 0.240703;-0.965231;0.101942;, + 0.279081;-0.946251;0.163473;, + 0.075339;-0.997085;0.012075;, + 0.134466;-0.990719;0.019844;, + 0.196636;-0.980077;0.028007;, + 0.251949;-0.965231;0.069654;, + 0.298033;-0.946250;0.125645;, + 0.076271;-0.997085;0.002138;, + 0.135906;-0.990719;0.002126;, + 0.198609;-0.980077;0.002103;, + 0.258885;-0.965231;0.036171;, + 0.311882;-0.946251;0.085671;, + 0.075897;-0.997085;-0.007831;, + 0.135021;-0.990719;-0.015630;, + 0.197185;-0.980077;-0.023837;, + 0.261392;-0.965230;0.002071;, + 0.320396;-0.946251;0.044227;, + 0.074225;-0.997085;-0.017674;, + 0.131825;-0.990719;-0.033123;, + 0.192386;-0.980077;-0.049373;, + 0.259427;-0.965230;-0.032065;, + 0.323428;-0.946250;0.002029;, + 0.071283;-0.997085;-0.027213;, + 0.126374;-0.990719;-0.050046;, + 0.184295;-0.980077;-0.074061;, + 0.253022;-0.965231;-0.065651;, + 0.320926;-0.946251;-0.040200;, + 0.067122;-0.997085;-0.036282;, + 0.118761;-0.990720;-0.066112;, + 0.173051;-0.980077;-0.097484;, + 0.242287;-0.965231;-0.098117;, + 0.312932;-0.946251;-0.081747;, + 0.061811;-0.997085;-0.044735;, + 0.109116;-0.990720;-0.081047;, + 0.158848;-0.980077;-0.119235;, + 0.227407;-0.965231;-0.128902;, + 0.299586;-0.946250;-0.121896;, + 0.055445;-0.997085;-0.052418;, + 0.097603;-0.990720;-0.094596;, + 0.141924;-0.980077;-0.138951;, + 0.208637;-0.965231;-0.157482;, + 0.281112;-0.946251;-0.159955;, + 0.048128;-0.997085;-0.059207;, + 0.084420;-0.990719;-0.106528;, + 0.122572;-0.980077;-0.156288;, + 0.186296;-0.965231;-0.183368;, + 0.257828;-0.946250;-0.195281;, + 0.039990;-0.997085;-0.064982;, + 0.069793;-0.990719;-0.116635;, + 0.101125;-0.980077;-0.170949;, + 0.160768;-0.965231;-0.206116;, + 0.230134;-0.946250;-0.227264;, + 0.031164;-0.997085;-0.069647;, + 0.053975;-0.990719;-0.124746;, + 0.077949;-0.980077;-0.182685;, + 0.132491;-0.965231;-0.225334;, + 0.198503;-0.946251;-0.255356;, + 0.021808;-0.997085;-0.073117;, + 0.037231;-0.990720;-0.130724;, + 0.053433;-0.980076;-0.191299;, + 0.101942;-0.965231;-0.240703;, + 0.163473;-0.946251;-0.279081;, + 0.012075;-0.997085;-0.075339;, + 0.019844;-0.990719;-0.134466;, + 0.028007;-0.980077;-0.196636;, + 0.069654;-0.965231;-0.251949;, + 0.125645;-0.946250;-0.298033;, + -0.000000;-0.996656;-0.081707;, + 0.000000;-0.989520;-0.144398;, + 0.000000;-0.978156;-0.207874;, + 0.036171;-0.965231;-0.258885;, + 0.085671;-0.946250;-0.311882;, + 0.148886;-0.923217;-0.354265;, + 0.193852;-0.923217;-0.331801;, + -0.019844;-0.990719;-0.134466;, + -0.028007;-0.980077;-0.196636;, + -0.036171;-0.965231;-0.258885;, + 0.000000;-0.962604;-0.270914;, + 0.044227;-0.946251;-0.320396;, + 0.101372;-0.923218;-0.370666;, + -0.012075;-0.997085;-0.075339;, + -0.037231;-0.990720;-0.130724;, + -0.053433;-0.980076;-0.191299;, + -0.069654;-0.965231;-0.251949;, + -0.085671;-0.946251;-0.311882;, + -0.044227;-0.946251;-0.320396;, + -0.020895;-0.999782;0.000000;, + -0.021808;-0.997085;-0.073117;, + -0.053975;-0.990719;-0.124746;, + -0.077949;-0.980077;-0.182685;, + -0.101942;-0.965231;-0.240703;, + -0.125645;-0.946250;-0.298033;, + -0.031164;-0.997085;-0.069647;, + -0.069793;-0.990719;-0.116635;, + -0.101125;-0.980077;-0.170949;, + -0.132491;-0.965231;-0.225334;, + -0.163473;-0.946251;-0.279081;, + -0.039990;-0.997085;-0.064982;, + -0.084420;-0.990719;-0.106528;, + -0.122572;-0.980077;-0.156288;, + -0.160768;-0.965231;-0.206116;, + -0.198503;-0.946251;-0.255356;, + -0.048128;-0.997085;-0.059207;, + -0.097603;-0.990720;-0.094596;, + -0.141924;-0.980077;-0.138951;, + -0.186296;-0.965231;-0.183368;, + -0.230134;-0.946250;-0.227264;, + -0.055445;-0.997085;-0.052418;, + -0.109116;-0.990720;-0.081047;, + -0.158848;-0.980077;-0.119235;, + -0.208637;-0.965231;-0.157482;, + -0.257828;-0.946250;-0.195281;, + -0.061811;-0.997085;-0.044735;, + -0.118761;-0.990720;-0.066112;, + -0.173051;-0.980077;-0.097484;, + -0.227407;-0.965231;-0.128902;, + -0.281112;-0.946251;-0.159955;, + -0.067122;-0.997085;-0.036282;, + -0.126374;-0.990719;-0.050046;, + -0.184295;-0.980077;-0.074061;, + -0.242287;-0.965231;-0.098117;, + -0.299586;-0.946250;-0.121896;, + -0.071283;-0.997085;-0.027213;, + -0.131825;-0.990719;-0.033123;, + -0.192386;-0.980077;-0.049373;, + -0.253022;-0.965231;-0.065651;, + -0.312932;-0.946251;-0.081747;, + -0.074225;-0.997085;-0.017674;, + -0.135021;-0.990719;-0.015630;, + -0.197185;-0.980077;-0.023837;, + -0.259427;-0.965230;-0.032065;, + -0.320926;-0.946251;-0.040200;, + -0.075897;-0.997085;-0.007831;, + -0.135906;-0.990719;0.002126;, + -0.198609;-0.980077;0.002103;, + -0.261392;-0.965230;0.002071;, + -0.323428;-0.946250;0.002029;, + -0.076271;-0.997085;0.002138;, + -0.134466;-0.990719;0.019844;, + -0.196636;-0.980077;0.028007;, + -0.258885;-0.965231;0.036171;, + -0.320396;-0.946251;0.044227;, + -0.075339;-0.997085;0.012075;, + -0.130724;-0.990720;0.037231;, + -0.191299;-0.980076;0.053433;, + -0.251949;-0.965231;0.069654;, + -0.311882;-0.946251;0.085671;, + -0.073117;-0.997085;0.021808;, + -0.124746;-0.990719;0.053975;, + -0.182685;-0.980077;0.077949;, + -0.240703;-0.965231;0.101942;, + -0.298033;-0.946250;0.125645;, + -0.069647;-0.997085;0.031164;, + -0.116635;-0.990719;0.069793;, + -0.170949;-0.980077;0.101125;, + -0.225334;-0.965231;0.132491;, + -0.279081;-0.946251;0.163473;, + -0.064982;-0.997085;0.039990;, + -0.106528;-0.990719;0.084420;, + -0.156288;-0.980077;0.122572;, + -0.206116;-0.965231;0.160768;, + -0.255356;-0.946251;0.198503;, + -0.059207;-0.997085;0.048128;, + -0.094596;-0.990720;0.097603;, + -0.138951;-0.980077;0.141924;, + -0.183368;-0.965231;0.186296;, + -0.227264;-0.946250;0.230134;, + -0.052418;-0.997085;0.055445;, + -0.081047;-0.990720;0.109116;, + -0.119235;-0.980077;0.158848;, + -0.157482;-0.965231;0.208637;, + -0.195281;-0.946250;0.257828;, + -0.044735;-0.997085;0.061811;, + -0.066112;-0.990720;0.118761;, + -0.097484;-0.980077;0.173051;, + -0.128902;-0.965231;0.227407;, + -0.159955;-0.946251;0.281112;, + -0.036282;-0.997085;0.067122;, + -0.050046;-0.990719;0.126374;, + -0.074061;-0.980077;0.184295;, + -0.098117;-0.965231;0.242287;, + -0.121896;-0.946250;0.299586;, + -0.027213;-0.997085;0.071283;, + -0.033123;-0.990719;0.131825;, + -0.049373;-0.980077;0.192386;, + -0.065651;-0.965231;0.253022;, + -0.081747;-0.946251;0.312932;, + -0.017674;-0.997085;0.074225;, + -0.015630;-0.990719;0.135021;, + -0.023837;-0.980077;0.197185;, + -0.032065;-0.965230;0.259427;, + -0.040200;-0.946251;0.320926;, + -0.007831;-0.997085;0.075897;, + -0.008123;-0.992247;0.124019;, + -0.012257;-0.982279;0.187024;, + -0.016392;-0.968077;0.250117;, + -0.020480;-0.949709;0.312464;, + -0.004282;-0.997850;0.065402;, + -0.024483;-0.927266;0.373601;, + -0.048191;-0.923218;0.381243;, + -0.097546;-0.923217;0.371692;, + -0.145224;-0.923217;0.355781;, + -0.028394;-0.900836;0.433231;, + -0.055996;-0.896226;0.440050;, + -0.112953;-0.896227;0.428975;, + -0.167978;-0.896227;0.410561;, + -0.190422;-0.923217;0.333781;, + -0.232361;-0.923217;0.306070;, + -0.032187;-0.870547;0.491031;, + -0.063562;-0.865405;0.497025;, + -0.127890;-0.865406;0.484475;, + -0.190035;-0.865406;0.463636;, + -0.220132;-0.896227;0.385123;, + -0.268515;-0.896228;0.353095;, + -0.270322;-0.923217;0.273123;, + -0.035837;-0.836535;0.546741;, + -0.070862;-0.830874;0.551930;, + -0.142299;-0.830873;0.537960;, + -0.211301;-0.830873;0.514784;, + -0.248926;-0.865406;0.434865;, + -0.303559;-0.865406;0.398653;, + -0.312308;-0.896227;0.315026;, + -0.039335;-0.798935;0.600129;, + -0.077869;-0.792785;0.604507;, + -0.156107;-0.792784;0.589173;, + -0.231672;-0.792785;0.563756;, + -0.276683;-0.830874;0.482799;, + -0.337339;-0.830873;0.442552;, + -0.352997;-0.865406;0.355621;, + -0.042666;-0.757931;0.650938;, + -0.084545;-0.751304;0.654519;, + -0.169250;-0.751305;0.637883;, + -0.251063;-0.751305;0.610334;, + -0.303277;-0.792784;0.528694;, + -0.369695;-0.792783;0.484584;, + -0.392214;-0.830874;0.394737;, + -0.045817;-0.713678;0.698974;, + -0.090858;-0.706602;0.701754;, + -0.181676;-0.706604;0.683890;, + -0.269394;-0.706599;0.654327;, + -0.328585;-0.751302;0.572344;, + -0.400474;-0.751305;0.524559;, + -0.429776;-0.792785;0.432185;, + -0.048766;-0.666386;0.744010;, + -0.096785;-0.658872;0.746003;, + -0.193335;-0.658867;0.726991;, + -0.286572;-0.658870;0.695534;, + -0.352493;-0.706600;0.613567;, + -0.429560;-0.706603;0.562309;, + -0.465517;-0.751305;0.467797;, + -0.051507;-0.616255;0.785861;, + -0.102304;-0.608323;0.787069;, + -0.204161;-0.608324;0.766981;, + -0.302523;-0.608328;0.733769;, + -0.374900;-0.658874;0.652178;, + -0.456820;-0.658873;0.597663;, + -0.499285;-0.706601;0.501428;, + -0.054033;-0.563506;0.824343;, + -0.107383;-0.555173;0.824774;, + -0.214116;-0.555175;0.803701;, + -0.317189;-0.555175;0.768877;, + -0.395711;-0.608327;0.688005;, + -0.482130;-0.608326;0.630469;, + -0.530922;-0.658874;0.532923;, + -0.056323;-0.508359;0.859301;, + -0.112002;-0.499646;0.858958;, + -0.223159;-0.499646;0.836991;, + -0.330502;-0.499642;0.800703;, + -0.414835;-0.555174;0.720898;, + -0.505383;-0.555172;0.660585;, + -0.560298;-0.608326;0.562144;, + -0.058373;-0.451058;0.890584;, + -0.116144;-0.441976;0.889476;, + -0.231253;-0.441972;0.866708;, + -0.342404;-0.441968;0.829110;, + -0.432187;-0.499643;0.750714;, + -0.526478;-0.499643;0.687879;, + -0.587285;-0.555169;0.588968;, + -0.060174;-0.391829;0.918068;, + -0.119793;-0.382405;0.916197;, + -0.238358;-0.382404;0.892722;, + -0.352839;-0.382407;0.853973;, + -0.447691;-0.441971;0.777325;, + -0.545324;-0.441973;0.712237;, + -0.611759;-0.499645;0.613275;, + -0.061717;-0.330950;0.941628;, + -0.122927;-0.321209;0.938996;, + -0.244439;-0.321212;0.914917;, + -0.361766;-0.321215;0.875184;, + -0.461284;-0.382408;0.800613;, + -0.561839;-0.382409;0.733553;, + -0.633621;-0.441977;0.634965;, + -0.063000;-0.268669;0.961170;, + -0.125534;-0.258637;0.957783;, + -0.249477;-0.258638;0.933203;, + -0.369151;-0.258633;0.892657;, + -0.472906;-0.321211;0.820478;, + -0.575955;-0.321206;0.751733;, + -0.652782;-0.382408;0.653942;, + -0.064008;-0.205253;0.976614;, + -0.127605;-0.194953;0.972476;, + -0.253453;-0.194947;0.947501;, + -0.374954;-0.194954;0.906313;, + -0.482508;-0.258631;0.836837;, + -0.587607;-0.258633;0.766698;, + -0.669148;-0.321208;0.670124;, + -0.064748;-0.140963;0.987895;, + -0.129135;-0.130430;0.983012;, + -0.256337;-0.130436;0.957746;, + -0.379157;-0.130433;0.916094;, + -0.490046;-0.194952;0.849617;, + -0.596748;-0.194949;0.778387;, + -0.682655;-0.258632;0.683441;, + -0.065214;-0.076077;0.994967;, + -0.130108;-0.065357;0.989343;, + -0.258130;-0.065356;0.963897;, + -0.381738;-0.065355;0.921957;, + -0.495489;-0.130428;0.858766;, + -0.603337;-0.130435;0.786747;, + -0.693245;-0.194947;0.693835;, + -0.065399;-0.010874;0.997800;, + -0.130525;0.000000;0.991445;, + -0.258819;-0.000002;0.965926;, + -0.382685;-0.000000;0.923879;, + -0.498808;-0.065361;0.864244;, + -0.607348;-0.065357;0.791743;, + -0.700868;-0.130435;0.701263;, + -0.065307;0.054380;0.996382;, + -0.130385;0.065356;0.989307;, + -0.258402;0.065359;0.963824;, + -0.381996;0.065356;0.921850;, + -0.500001;0.000003;0.866025;, + -0.608759;-0.000000;0.793355;, + -0.705495;-0.065360;0.705695;, + -0.064936;0.119402;0.990720;, + -0.129688;0.130433;0.982939;, + -0.256879;0.130431;0.957602;, + -0.379675;0.130433;0.915879;, + -0.499052;0.065353;0.864104;, + -0.607569;0.065356;0.791574;, + -0.707107;0.000000;0.707107;, + -0.064284;0.183916;0.980838;, + -0.128436;0.194951;0.972368;, + -0.254258;0.194952;0.947284;, + -0.375729;0.194951;0.905992;, + -0.495971;0.130434;0.858487;, + -0.603783;0.130436;0.786405;, + -0.705695;0.065360;0.705495;, + -0.063366;0.247660;0.966773;, + -0.126635;0.258637;0.957638;, + -0.250550;0.258635;0.932916;, + -0.370176;0.258636;0.892232;, + -0.490768;0.194948;0.849201;, + -0.597414;0.194952;0.777876;, + -0.701263;0.130435;0.700868;, + -0.062174;0.310348;0.948588;, + -0.124292;0.321208;0.938817;, + -0.245771;0.321212;0.914560;, + -0.363040;0.321211;0.874657;, + -0.483469;0.258636;0.836281;, + -0.588488;0.258630;0.766024;, + -0.693835;0.194947;0.693245;, + -0.060717;0.371721;0.926357;, + -0.121420;0.382407;0.915981;, + -0.239941;0.382406;0.892297;, + -0.354355;0.382407;0.853345;, + -0.474099;0.321208;0.819790;, + -0.577047;0.321209;0.750893;, + -0.683441;0.258632;0.682655;, + -0.059001;0.431530;0.900167;, + -0.118026;0.441975;0.889229;, + -0.233086;0.441973;0.866216;, + -0.344154;0.441970;0.828384;, + -0.462705;0.382409;0.799792;, + -0.563141;0.382406;0.732556;, + -0.670124;0.321208;0.669148;, + -0.057032;0.489503;0.870135;, + -0.114128;0.499645;0.858679;, + -0.225232;0.499645;0.836436;, + -0.332481;0.499641;0.799885;, + -0.449335;0.441969;0.776377;, + -0.546828;0.441972;0.711084;, + -0.653942;0.382408;0.652782;, + -0.054823;0.545394;0.836385;, + -0.109745;0.555174;0.824462;, + -0.216418;0.555175;0.803084;, + -0.319390;0.555175;0.767966;, + -0.434044;0.499644;0.749641;, + -0.528179;0.499647;0.686571;, + -0.634965;0.441977;0.633621;, + -0.052373;0.598970;0.799057;, + -0.104891;0.608323;0.786728;, + -0.206681;0.608323;0.766307;, + -0.304936;0.608326;0.732771;, + -0.416899;0.555175;0.719705;, + -0.507273;0.555172;0.659134;, + -0.613275;0.499645;0.611759;, + -0.049701;0.649993;0.758313;, + -0.099591;0.658871;0.745634;, + -0.196064;0.658871;0.726257;, + -0.289183;0.658871;0.694451;, + -0.397973;0.608326;0.686700;, + -0.484200;0.608324;0.628882;, + -0.588968;0.555169;0.587285;, + -0.046821;0.698262;0.714310;, + -0.093865;0.706602;0.701358;, + -0.184607;0.706601;0.683108;, + -0.272194;0.706601;0.653166;, + -0.377350;0.658873;0.650764;, + -0.459062;0.658874;0.595942;, + -0.562144;0.608326;0.560298;, + -0.043736;0.743547;0.667252;, + -0.087739;0.751305;0.654097;, + -0.172365;0.751306;0.637047;, + -0.254044;0.751305;0.609100;, + -0.355118;0.706601;0.612051;, + -0.431968;0.706602;0.560462;, + -0.532922;0.658874;0.530923;, + -0.040463;0.785659;0.617335;, + -0.081242;0.792785;0.604062;, + -0.159392;0.792784;0.588293;, + -0.234816;0.792783;0.562455;, + -0.331374;0.751303;0.570733;, + -0.403034;0.751304;0.522596;, + -0.501428;0.706601;0.499285;, + -0.037018;0.824409;0.564783;, + -0.074399;0.830873;0.551465;, + -0.145742;0.830873;0.537037;, + -0.214595;0.830874;0.513418;, + -0.306224;0.792784;0.526992;, + -0.372390;0.792784;0.482514;, + -0.467797;0.751305;0.465517;, + -0.033417;0.859642;0.509802;, + -0.067243;0.865405;0.496541;, + -0.131478;0.865405;0.483515;, + -0.193466;0.865406;0.462216;, + -0.279773;0.830874;0.481016;, + -0.340167;0.830873;0.440382;, + -0.432185;0.792785;0.429776;, + -0.029671;0.891186;0.452667;, + -0.059806;0.896226;0.439547;, + -0.116669;0.896227;0.427978;, + -0.171533;0.896228;0.409087;, + -0.252141;0.865406;0.433009;, + -0.306506;0.865407;0.396390;, + -0.394737;0.830874;0.392214;, + -0.025794;0.918920;0.393599;, + -0.052120;0.923218;0.380726;, + -0.101372;0.923218;0.370666;, + -0.148886;0.923217;0.354265;, + -0.223461;0.896227;0.383200;, + -0.271569;0.896227;0.350753;, + -0.355621;0.865406;0.352997;, + -0.021817;0.942711;0.332897;, + -0.044227;0.946251;0.320396;, + -0.085671;0.946251;0.311882;, + -0.125645;0.946250;0.298033;, + -0.193852;0.923217;0.331801;, + -0.235504;0.923217;0.303658;, + -0.315026;0.896227;0.312308;, + -0.017753;0.962452;0.270871;, + -0.036171;0.965231;0.258885;, + -0.069654;0.965231;0.251949;, + -0.101942;0.965231;0.240703;, + -0.163473;0.946251;0.279081;, + -0.198503;0.946251;0.255356;, + -0.273123;0.923217;0.270322;, + -0.013623;0.978065;0.207855;, + -0.028007;0.980076;0.196636;, + -0.053433;0.980076;0.191299;, + -0.077949;0.980077;0.182685;, + -0.132491;0.965231;0.225335;, + -0.160768;0.965231;0.206116;, + -0.230134;0.946250;0.227264;, + -0.009461;0.989475;0.144392;, + -0.019844;0.990719;0.134466;, + -0.037231;0.990720;0.130724;, + -0.053975;0.990719;0.124746;, + -0.101125;0.980077;0.170949;, + -0.122572;0.980077;0.156288;, + -0.186296;0.965231;0.183368;, + -0.005351;0.996642;0.081706;, + -0.012075;0.997085;0.075339;, + -0.021808;0.997085;0.073117;, + -0.031164;0.997085;0.069647;, + -0.069793;0.990719;0.116635;, + -0.084420;0.990719;0.106528;, + -0.141924;0.980077;0.138951;, + -0.039990;0.997085;0.064982;, + -0.048128;0.997085;0.059207;, + -0.097603;0.990720;0.094596;, + -0.158848;0.980077;0.119235;, + -0.208637;0.965231;0.157482;, + -0.055445;0.997085;0.052418;, + -0.109116;0.990720;0.081047;, + -0.173051;0.980077;0.097484;, + -0.227407;0.965231;0.128902;, + -0.281112;0.946251;0.159955;, + -0.257828;0.946250;0.195281;, + -0.061811;0.997085;0.044735;, + -0.118761;0.990720;0.066112;, + -0.184295;0.980077;0.074061;, + -0.242287;0.965231;0.098117;, + -0.299586;0.946250;0.121896;, + -0.067122;0.997085;0.036282;, + -0.126374;0.990719;0.050046;, + -0.192386;0.980077;0.049373;, + -0.253022;0.965231;0.065651;, + -0.312932;0.946251;0.081747;, + -0.071283;0.997085;0.027213;, + -0.131825;0.990719;0.033123;, + -0.197185;0.980077;0.023837;, + -0.259427;0.965230;0.032065;, + -0.320926;0.946251;0.040200;, + -0.074225;0.997085;0.017674;, + -0.135021;0.990719;0.015630;, + -0.198609;0.980077;-0.002103;, + -0.261392;0.965230;-0.002071;, + -0.323428;0.946250;-0.002029;, + -0.075897;0.997085;0.007831;, + -0.135906;0.990719;-0.002126;, + -0.196636;0.980077;-0.028007;, + -0.258885;0.965231;-0.036171;, + -0.320396;0.946251;-0.044227;, + -0.076271;0.997085;-0.002138;, + -0.134466;0.990719;-0.019844;, + -0.191299;0.980076;-0.053433;, + -0.251949;0.965231;-0.069654;, + -0.311882;0.946251;-0.085671;, + -0.075339;0.997085;-0.012075;, + -0.130724;0.990720;-0.037231;, + -0.182685;0.980077;-0.077949;, + -0.240703;0.965231;-0.101942;, + -0.298033;0.946250;-0.125645;, + -0.073117;0.997085;-0.021808;, + -0.124746;0.990719;-0.053975;, + -0.170949;0.980077;-0.101125;, + -0.225334;0.965231;-0.132491;, + -0.279081;0.946251;-0.163473;, + -0.069647;0.997085;-0.031164;, + -0.116635;0.990719;-0.069793;, + -0.156288;0.980077;-0.122572;, + -0.206116;0.965231;-0.160768;, + -0.255356;0.946251;-0.198503;, + -0.064982;0.997085;-0.039990;, + -0.106528;0.990719;-0.084420;, + -0.138951;0.980077;-0.141924;, + -0.183368;0.965231;-0.186296;, + -0.227264;0.946250;-0.230134;, + -0.059207;0.997085;-0.048128;, + -0.157482;0.965231;-0.208637;, + -0.195281;0.946250;-0.257828;, + -0.159955;0.946251;-0.281112;, + -0.190422;0.923217;-0.333781;, + -0.232361;0.923217;-0.306070;, + -0.270322;0.923217;-0.273123;, + -0.121896;0.946250;-0.299586;, + -0.145224;0.923217;-0.355781;, + -0.167978;0.896227;-0.410561;, + -0.220132;0.896227;-0.385123;, + -0.268515;0.896228;-0.353095;, + -0.097546;0.923217;-0.371692;, + -0.112953;0.896227;-0.428975;, + -0.127890;0.865406;-0.484475;, + -0.190035;0.865406;-0.463636;, + -0.248926;0.865406;-0.434865;, + -0.048191;0.923218;-0.381242;, + -0.055996;0.896226;-0.440050;, + -0.063562;0.865405;-0.497025;, + -0.070862;0.830874;-0.551930;, + -0.142299;0.830873;-0.537960;, + -0.211301;0.830873;-0.514784;, + 0.000000;0.901199;-0.433406;, + -0.000000;0.870999;-0.491286;, + 0.000000;0.837073;-0.547092;, + 0.000000;0.799554;-0.600594;, + -0.077869;0.792785;-0.604507;, + -0.156107;0.792784;-0.589173;, + 0.055996;0.896226;-0.440050;, + 0.063562;0.865405;-0.497025;, + 0.070862;0.830874;-0.551930;, + 0.077869;0.792785;-0.604507;, + 0.000000;0.758621;-0.651532;, + -0.084545;0.751304;-0.654519;, + 0.112953;0.896227;-0.428975;, + 0.127890;0.865406;-0.484475;, + 0.142299;0.830873;-0.537960;, + 0.156107;0.792784;-0.589173;, + 0.084545;0.751304;-0.654519;, + 0.000000;0.714428;-0.699709;, + 0.167978;0.896227;-0.410561;, + 0.190035;0.865406;-0.463636;, + 0.211301;0.830873;-0.514784;, + 0.231672;0.792785;-0.563756;, + 0.169250;0.751305;-0.637883;, + 0.090858;0.706602;-0.701754;, + 0.220132;0.896227;-0.385123;, + 0.248926;0.865406;-0.434865;, + 0.276683;0.830874;-0.482799;, + 0.303277;0.792784;-0.528694;, + 0.251063;0.751305;-0.610334;, + 0.181676;0.706604;-0.683890;, + 0.268515;0.896228;-0.353095;, + 0.303559;0.865406;-0.398653;, + 0.337339;0.830873;-0.442552;, + 0.369695;0.792783;-0.484584;, + 0.328585;0.751302;-0.572344;, + 0.269394;0.706599;-0.654327;, + 0.312308;0.896227;-0.315026;, + 0.352997;0.865406;-0.355621;, + 0.392214;0.830874;-0.394737;, + 0.429776;0.792785;-0.432185;, + 0.400474;0.751305;-0.524559;, + 0.352493;0.706600;-0.613567;, + 0.350753;0.896227;-0.271569;, + 0.396390;0.865407;-0.306506;, + 0.440382;0.830873;-0.340167;, + 0.482514;0.792784;-0.372390;, + 0.465517;0.751305;-0.467797;, + 0.429560;0.706603;-0.562309;, + 0.383200;0.896227;-0.223461;, + 0.433009;0.865406;-0.252141;, + 0.481016;0.830874;-0.279773;, + 0.526992;0.792784;-0.306224;, + 0.522596;0.751304;-0.403034;, + 0.499285;0.706601;-0.501428;, + 0.409087;0.896228;-0.171533;, + 0.462216;0.865406;-0.193466;, + 0.513418;0.830874;-0.214595;, + 0.562455;0.792783;-0.234816;, + 0.570733;0.751303;-0.331374;, + 0.560462;0.706602;-0.431968;, + 0.427978;0.896227;-0.116669;, + 0.483515;0.865405;-0.131478;, + 0.537037;0.830873;-0.145742;, + 0.588293;0.792784;-0.159392;, + 0.609100;0.751305;-0.254044;, + 0.612051;0.706601;-0.355118;, + 0.439547;0.896226;-0.059806;, + 0.496541;0.865405;-0.067243;, + 0.551465;0.830873;-0.074399;, + 0.604062;0.792785;-0.081242;, + 0.637047;0.751306;-0.172365;, + 0.653166;0.706601;-0.272194;, + 0.443592;0.896227;-0.001925;, + 0.501070;0.865405;-0.001856;, + 0.556458;0.830874;-0.001782;, + 0.609498;0.792786;-0.001701;, + 0.654097;0.751305;-0.087739;, + 0.683108;0.706601;-0.184607;, + 0.440050;0.896226;0.055996;, + 0.497025;0.865405;0.063562;, + 0.551930;0.830874;0.070862;, + 0.604507;0.792785;0.077869;, + 0.659953;0.751305;-0.001613;, + 0.701358;0.706602;-0.093865;, + 0.428975;0.896227;0.112953;, + 0.484475;0.865406;0.127890;, + 0.537960;0.830873;0.142299;, + 0.589173;0.792784;0.156107;, + 0.654519;0.751304;0.084545;, + 0.707610;0.706601;-0.001516;, + 0.410561;0.896227;0.167978;, + 0.463636;0.865406;0.190035;, + 0.514784;0.830873;0.211301;, + 0.563756;0.792785;0.231672;, + 0.637883;0.751305;0.169250;, + 0.701754;0.706602;0.090858;, + 0.385123;0.896227;0.220132;, + 0.434865;0.865406;0.248926;, + 0.482799;0.830874;0.276683;, + 0.528694;0.792784;0.303277;, + 0.610334;0.751305;0.251063;, + 0.683890;0.706604;0.181676;, + 0.353095;0.896228;0.268515;, + 0.398653;0.865406;0.303559;, + 0.442552;0.830873;0.337339;, + 0.484584;0.792783;0.369695;, + 0.572344;0.751302;0.328585;, + 0.654327;0.706599;0.269394;, + 0.315026;0.896227;0.312308;, + 0.355621;0.865406;0.352997;, + 0.394737;0.830874;0.392214;, + 0.432185;0.792785;0.429776;, + 0.524559;0.751305;0.400474;, + 0.613567;0.706600;0.352493;, + 0.467797;0.751305;0.465517;, + 0.562309;0.706603;0.429560;, + 0.652178;0.658874;0.374900;, + 0.695534;0.658870;0.286572;, + 0.726991;0.658867;0.193335;, + 0.501428;0.706601;0.499285;, + 0.597663;0.658873;0.456820;, + 0.688005;0.608327;0.395711;, + 0.733769;0.608328;0.302523;, + 0.766981;0.608324;0.204161;, + 0.532923;0.658874;0.530922;, + 0.630469;0.608326;0.482130;, + 0.720898;0.555174;0.414835;, + 0.768877;0.555175;0.317189;, + 0.803701;0.555175;0.214116;, + 0.562144;0.608326;0.560298;, + 0.660585;0.555172;0.505383;, + 0.750714;0.499643;0.432187;, + 0.800703;0.499642;0.330502;, + 0.836991;0.499647;0.223159;, + 0.588968;0.555169;0.587285;, + 0.687879;0.499643;0.526478;, + 0.777325;0.441971;0.447691;, + 0.829110;0.441968;0.342404;, + 0.866708;0.441972;0.231253;, + 0.613275;0.499645;0.611759;, + 0.712237;0.441973;0.545324;, + 0.800613;0.382408;0.461284;, + 0.853973;0.382407;0.352839;, + 0.892722;0.382404;0.238358;, + 0.634965;0.441977;0.633621;, + 0.733553;0.382409;0.561839;, + 0.820478;0.321211;0.472906;, + 0.875184;0.321215;0.361766;, + 0.914917;0.321212;0.244439;, + 0.653942;0.382408;0.652782;, + 0.751733;0.321206;0.575955;, + 0.836837;0.258631;0.482508;, + 0.892657;0.258633;0.369151;, + 0.933203;0.258638;0.249477;, + 0.670124;0.321208;0.669148;, + 0.766698;0.258633;0.587607;, + 0.849617;0.194952;0.490046;, + 0.906313;0.194954;0.374954;, + 0.947501;0.194947;0.253453;, + 0.683441;0.258632;0.682655;, + 0.778387;0.194949;0.596748;, + 0.858766;0.130428;0.495489;, + 0.916094;0.130433;0.379157;, + 0.957746;0.130436;0.256337;, + 0.693835;0.194947;0.693245;, + 0.786747;0.130435;0.603337;, + 0.864245;0.065361;0.498808;, + 0.921957;0.065355;0.381738;, + 0.963897;0.065356;0.258130;, + 0.701263;0.130435;0.700868;, + 0.791743;0.065357;0.607348;, + 0.866025;-0.000003;0.500001;, + 0.923879;0.000000;0.382685;, + 0.965926;0.000002;0.258819;, + 0.705695;0.065360;0.705495;, + 0.793355;0.000000;0.608759;, + 0.864104;-0.065353;0.499052;, + 0.921850;-0.065356;0.381996;, + 0.963824;-0.065359;0.258402;, + 0.707107;0.000000;0.707107;, + 0.791574;-0.065356;0.607569;, + 0.858487;-0.130434;0.495971;, + 0.915879;-0.130433;0.379675;, + 0.957602;-0.130431;0.256879;, + 0.705495;-0.065360;0.705695;, + 0.786405;-0.130436;0.603783;, + 0.849201;-0.194948;0.490768;, + 0.905992;-0.194951;0.375729;, + 0.947284;-0.194952;0.254258;, + 0.700868;-0.130435;0.701263;, + 0.777876;-0.194952;0.597414;, + 0.836281;-0.258636;0.483469;, + 0.892232;-0.258636;0.370176;, + 0.932916;-0.258635;0.250550;, + 0.693245;-0.194947;0.693835;, + 0.766024;-0.258630;0.588488;, + 0.819790;-0.321208;0.474100;, + 0.874657;-0.321211;0.363041;, + 0.914560;-0.321212;0.245771;, + 0.682655;-0.258632;0.683441;, + 0.750893;-0.321209;0.577047;, + 0.799792;-0.382409;0.462705;, + 0.853345;-0.382408;0.354355;, + 0.892297;-0.382406;0.239941;, + 0.669148;-0.321208;0.670124;, + 0.732556;-0.382406;0.563141;, + 0.776377;-0.441969;0.449335;, + 0.828384;-0.441970;0.344154;, + 0.866216;-0.441973;0.233086;, + 0.652782;-0.382408;0.653942;, + 0.711084;-0.441972;0.546828;, + 0.749641;-0.499644;0.434044;, + 0.799885;-0.499641;0.332481;, + 0.836436;-0.499645;0.225232;, + 0.633621;-0.441977;0.634965;, + 0.686571;-0.499647;0.528179;, + 0.719705;-0.555175;0.416899;, + 0.767966;-0.555175;0.319390;, + 0.803084;-0.555175;0.216418;, + 0.611759;-0.499645;0.613275;, + 0.659135;-0.555172;0.507274;, + 0.686700;-0.608326;0.397973;, + 0.732771;-0.608326;0.304936;, + 0.766307;-0.608323;0.206681;, + 0.587285;-0.555169;0.588968;, + 0.628882;-0.608324;0.484200;, + 0.650764;-0.658873;0.377350;, + 0.694451;-0.658871;0.289183;, + 0.726257;-0.658871;0.196064;, + 0.560298;-0.608326;0.562144;, + 0.595942;-0.658874;0.459062;, + 0.612051;-0.706601;0.355118;, + 0.653166;-0.706601;0.272194;, + 0.683108;-0.706601;0.184607;, + 0.530923;-0.658874;0.532923;, + 0.560462;-0.706602;0.431968;, + 0.570733;-0.751303;0.331374;, + 0.609100;-0.751305;0.254044;, + 0.637047;-0.751306;0.172365;, + 0.499285;-0.706601;0.501428;, + 0.522596;-0.751304;0.403034;, + 0.526992;-0.792784;0.306224;, + 0.562455;-0.792783;0.234816;, + 0.588293;-0.792784;0.159392;, + 0.465517;-0.751305;0.467797;, + 0.482514;-0.792784;0.372390;, + 0.481016;-0.830874;0.279773;, + 0.513418;-0.830874;0.214595;, + 0.537037;-0.830873;0.145742;, + 0.429776;-0.792785;0.432185;, + 0.440382;-0.830873;0.340167;, + 0.433009;-0.865406;0.252141;, + 0.462216;-0.865406;0.193466;, + 0.483515;-0.865405;0.131478;, + 0.392214;-0.830874;0.394737;, + 0.396390;-0.865407;0.306506;, + 0.383200;-0.896227;0.223461;, + 0.409087;-0.896228;0.171533;, + 0.427979;-0.896227;0.116669;, + 0.352997;-0.865406;0.355621;, + 0.350753;-0.896227;0.271569;, + 0.331801;-0.923217;0.193852;, + 0.354265;-0.923217;0.148886;, + 0.370666;-0.923218;0.101372;, + 0.312308;-0.896227;0.315026;, + 0.303658;-0.923217;0.235504;, + 0.270322;-0.923217;0.273123;, + 0.380726;-0.923218;0.052120;, + 0.439547;-0.896226;0.059806;, + 0.496541;-0.865405;0.067243;, + 0.384271;-0.923218;0.001981;, + 0.443592;-0.896227;0.001925;, + 0.501070;-0.865405;0.001856;, + 0.551465;-0.830873;0.074399;, + 0.604062;-0.792785;0.081242;, + 0.381243;-0.923218;-0.048191;, + 0.440050;-0.896226;-0.055996;, + 0.497025;-0.865405;-0.063562;, + 0.556458;-0.830874;0.001782;, + 0.609498;-0.792786;0.001701;, + 0.654097;-0.751305;0.087739;, + 0.371692;-0.923217;-0.097546;, + 0.428975;-0.896227;-0.112953;, + 0.484475;-0.865406;-0.127890;, + 0.551930;-0.830874;-0.070862;, + 0.604507;-0.792785;-0.077869;, + 0.659953;-0.751305;0.001613;, + 0.355781;-0.923217;-0.145224;, + 0.410561;-0.896227;-0.167978;, + 0.463636;-0.865406;-0.190035;, + 0.537960;-0.830873;-0.142299;, + 0.589173;-0.792784;-0.156107;, + 0.654519;-0.751304;-0.084545;, + 0.333781;-0.923217;-0.190422;, + 0.385123;-0.896227;-0.220132;, + 0.434865;-0.865406;-0.248926;, + 0.514784;-0.830873;-0.211301;, + 0.563756;-0.792785;-0.231672;, + 0.637883;-0.751305;-0.169250;, + 0.306070;-0.923217;-0.232361;, + 0.353095;-0.896228;-0.268515;, + 0.398653;-0.865406;-0.303559;, + 0.482799;-0.830874;-0.276683;, + 0.528694;-0.792784;-0.303277;, + 0.610334;-0.751305;-0.251063;, + 0.273123;-0.923217;-0.270322;, + 0.315026;-0.896227;-0.312308;, + 0.355621;-0.865406;-0.352997;, + 0.442552;-0.830873;-0.337339;, + 0.484584;-0.792783;-0.369695;, + 0.572344;-0.751302;-0.328585;, + 0.235504;-0.923217;-0.303657;, + 0.271569;-0.896227;-0.350753;, + 0.306506;-0.865407;-0.396390;, + 0.394737;-0.830874;-0.392214;, + 0.432185;-0.792785;-0.429776;, + 0.524559;-0.751305;-0.400474;, + 0.223461;-0.896227;-0.383200;, + 0.252141;-0.865406;-0.433009;, + 0.340167;-0.830873;-0.440382;, + 0.372390;-0.792784;-0.482514;, + 0.467797;-0.751305;-0.465517;, + 0.171533;-0.896228;-0.409087;, + 0.193466;-0.865406;-0.462216;, + 0.279773;-0.830874;-0.481016;, + 0.306224;-0.792784;-0.526992;, + 0.403034;-0.751304;-0.522596;, + 0.116669;-0.896227;-0.427978;, + 0.131478;-0.865405;-0.483515;, + 0.214595;-0.830874;-0.513418;, + 0.234816;-0.792783;-0.562455;, + 0.331374;-0.751303;-0.570733;, + 0.052120;-0.923218;-0.380726;, + 0.059806;-0.896226;-0.439547;, + 0.067243;-0.865405;-0.496541;, + 0.145742;-0.830873;-0.537037;, + 0.159392;-0.792784;-0.588293;, + 0.254044;-0.751305;-0.609100;, + -0.000000;-0.942935;-0.332977;, + -0.000000;-0.919226;-0.393730;, + -0.000000;-0.891578;-0.452867;, + 0.000000;-0.860123;-0.510087;, + 0.074399;-0.830873;-0.551465;, + -0.052120;-0.923218;-0.380726;, + -0.059806;-0.896226;-0.439547;, + -0.067243;-0.865405;-0.496541;, + -0.074399;-0.830873;-0.551465;, + 0.000000;-0.824974;-0.565170;, + 0.081242;-0.792785;-0.604062;, + -0.101372;-0.923218;-0.370666;, + -0.116669;-0.896227;-0.427978;, + -0.131478;-0.865405;-0.483515;, + -0.145742;-0.830873;-0.537037;, + -0.159392;-0.792784;-0.588293;, + -0.081242;-0.792785;-0.604062;, + -0.148886;-0.923217;-0.354265;, + -0.171533;-0.896228;-0.409087;, + -0.193466;-0.865406;-0.462216;, + -0.214595;-0.830874;-0.513418;, + -0.234816;-0.792783;-0.562455;, + -0.193852;-0.923217;-0.331801;, + -0.223461;-0.896227;-0.383200;, + -0.252141;-0.865406;-0.433009;, + -0.279773;-0.830874;-0.481016;, + -0.306224;-0.792784;-0.526992;, + -0.235504;-0.923217;-0.303658;, + -0.271569;-0.896227;-0.350753;, + -0.306506;-0.865407;-0.396390;, + -0.340167;-0.830873;-0.440382;, + -0.372390;-0.792784;-0.482514;, + -0.273123;-0.923217;-0.270322;, + -0.315026;-0.896227;-0.312308;, + -0.355621;-0.865406;-0.352997;, + -0.394737;-0.830874;-0.392214;, + -0.432185;-0.792785;-0.429776;, + -0.306070;-0.923217;-0.232361;, + -0.353095;-0.896228;-0.268515;, + -0.398653;-0.865406;-0.303559;, + -0.442552;-0.830873;-0.337339;, + -0.484584;-0.792783;-0.369695;, + -0.333781;-0.923217;-0.190422;, + -0.385123;-0.896227;-0.220132;, + -0.434865;-0.865406;-0.248926;, + -0.482799;-0.830874;-0.276683;, + -0.528694;-0.792784;-0.303277;, + -0.355781;-0.923217;-0.145224;, + -0.410561;-0.896227;-0.167978;, + -0.463636;-0.865406;-0.190035;, + -0.514784;-0.830873;-0.211301;, + -0.563756;-0.792785;-0.231672;, + -0.371692;-0.923217;-0.097546;, + -0.428975;-0.896227;-0.112953;, + -0.484475;-0.865406;-0.127890;, + -0.537960;-0.830873;-0.142299;, + -0.589173;-0.792784;-0.156107;, + -0.381242;-0.923218;-0.048191;, + -0.440050;-0.896226;-0.055996;, + -0.497025;-0.865405;-0.063562;, + -0.551930;-0.830874;-0.070862;, + -0.604507;-0.792785;-0.077869;, + -0.384271;-0.923218;0.001981;, + -0.443592;-0.896227;0.001925;, + -0.501070;-0.865405;0.001856;, + -0.556458;-0.830874;0.001782;, + -0.609498;-0.792786;0.001701;, + -0.380726;-0.923218;0.052120;, + -0.439547;-0.896226;0.059806;, + -0.496541;-0.865405;0.067243;, + -0.551465;-0.830873;0.074399;, + -0.604062;-0.792785;0.081242;, + -0.370666;-0.923218;0.101372;, + -0.427978;-0.896227;0.116669;, + -0.483515;-0.865405;0.131478;, + -0.537037;-0.830873;0.145742;, + -0.588293;-0.792784;0.159392;, + -0.354265;-0.923217;0.148886;, + -0.409087;-0.896228;0.171533;, + -0.462216;-0.865406;0.193466;, + -0.513418;-0.830874;0.214595;, + -0.562455;-0.792783;0.234816;, + -0.331801;-0.923217;0.193852;, + -0.383200;-0.896227;0.223461;, + -0.433009;-0.865406;0.252141;, + -0.481016;-0.830874;0.279773;, + -0.526992;-0.792784;0.306224;, + -0.303658;-0.923217;0.235504;, + -0.350753;-0.896227;0.271569;, + -0.396390;-0.865407;0.306506;, + -0.440382;-0.830873;0.340167;, + -0.482514;-0.792784;0.372390;, + -0.522596;-0.751304;0.403034;, + -0.570733;-0.751303;0.331374;, + -0.609100;-0.751305;0.254044;, + -0.560462;-0.706602;0.431968;, + -0.612051;-0.706601;0.355118;, + -0.653166;-0.706601;0.272194;, + -0.637047;-0.751306;0.172365;, + -0.654097;-0.751305;0.087739;, + -0.595942;-0.658874;0.459062;, + -0.650764;-0.658873;0.377350;, + -0.694451;-0.658871;0.289183;, + -0.683108;-0.706601;0.184607;, + -0.701358;-0.706602;0.093865;, + -0.659953;-0.751305;0.001613;, + -0.628882;-0.608324;0.484200;, + -0.686700;-0.608326;0.397973;, + -0.732771;-0.608326;0.304936;, + -0.726257;-0.658871;0.196064;, + -0.745634;-0.658871;0.099591;, + -0.707610;-0.706601;0.001516;, + -0.659134;-0.555172;0.507274;, + -0.719705;-0.555175;0.416899;, + -0.767965;-0.555175;0.319390;, + -0.766307;-0.608323;0.206681;, + -0.786728;-0.608323;0.104891;, + -0.752255;-0.658870;0.001413;, + -0.686571;-0.499647;0.528179;, + -0.749641;-0.499644;0.434044;, + -0.799885;-0.499641;0.332481;, + -0.803084;-0.555175;0.216418;, + -0.824462;-0.555174;0.109745;, + -0.793687;-0.608325;0.001306;, + -0.711084;-0.441972;0.546828;, + -0.776377;-0.441969;0.449335;, + -0.828384;-0.441970;0.344154;, + -0.836436;-0.499645;0.225232;, + -0.858679;-0.499645;0.114128;, + -0.831734;-0.555173;0.001192;, + -0.732556;-0.382406;0.563141;, + -0.799792;-0.382409;0.462705;, + -0.853345;-0.382408;0.354355;, + -0.866216;-0.441973;0.233086;, + -0.889229;-0.441975;0.118026;, + -0.866230;-0.499644;0.001071;, + -0.750893;-0.321209;0.577048;, + -0.819790;-0.321208;0.474099;, + -0.874657;-0.321211;0.363041;, + -0.892297;-0.382406;0.239941;, + -0.915981;-0.382408;0.121421;, + -0.897026;-0.441977;0.000949;, + -0.766024;-0.258630;0.588488;, + -0.836281;-0.258636;0.483469;, + -0.892232;-0.258636;0.370176;, + -0.914560;-0.321212;0.245771;, + -0.938817;-0.321208;0.124292;, + -0.923994;-0.382406;0.000820;, + -0.777876;-0.194952;0.597414;, + -0.849201;-0.194948;0.490768;, + -0.905992;-0.194951;0.375729;, + -0.932916;-0.258635;0.250550;, + -0.957638;-0.258637;0.126635;, + -0.947008;-0.321208;0.000690;, + -0.786405;-0.130436;0.603783;, + -0.858487;-0.130434;0.495971;, + -0.915879;-0.130433;0.379675;, + -0.947284;-0.194952;0.254258;, + -0.972368;-0.194951;0.128436;, + -0.965975;-0.258635;0.000554;, + -0.791574;-0.065356;0.607569;, + -0.864104;-0.065353;0.499052;, + -0.921850;-0.065356;0.381996;, + -0.957602;-0.130431;0.256879;, + -0.982939;-0.130433;0.129688;, + -0.980813;-0.194951;0.000418;, + -0.793355;0.000000;0.608759;, + -0.866025;-0.000003;0.500001;, + -0.923879;0.000000;0.382685;, + -0.963824;-0.065359;0.258402;, + -0.989307;-0.065356;0.130385;, + -0.991457;-0.130434;0.000281;, + -0.791743;0.065357;0.607348;, + -0.864244;0.065361;0.498808;, + -0.921957;0.065355;0.381738;, + -0.965926;0.000002;0.258819;, + -0.991445;-0.000000;0.130525;, + -0.997862;-0.065356;0.000140;, + -0.786747;0.130435;0.603337;, + -0.858766;0.130428;0.495489;, + -0.916094;0.130433;0.379157;, + -0.963897;0.065356;0.258130;, + -0.989343;0.065357;0.130108;, + -1.000000;-0.000000;-0.000000;, + -0.778387;0.194949;0.596748;, + -0.849617;0.194952;0.490046;, + -0.906313;0.194954;0.374954;, + -0.957746;0.130436;0.256337;, + -0.983012;0.130430;0.129135;, + -0.997862;0.065356;-0.000140;, + -0.766698;0.258633;0.587607;, + -0.836837;0.258631;0.482508;, + -0.892657;0.258633;0.369151;, + -0.947501;0.194947;0.253453;, + -0.972476;0.194953;0.127605;, + -0.991457;0.130434;-0.000281;, + -0.751733;0.321206;0.575955;, + -0.820478;0.321211;0.472906;, + -0.875184;0.321215;0.361766;, + -0.933203;0.258638;0.249477;, + -0.957783;0.258637;0.125534;, + -0.980813;0.194951;-0.000418;, + -0.733553;0.382409;0.561839;, + -0.800613;0.382408;0.461284;, + -0.853973;0.382407;0.352839;, + -0.914917;0.321212;0.244439;, + -0.938996;0.321209;0.122927;, + -0.965975;0.258635;-0.000554;, + -0.712237;0.441973;0.545324;, + -0.777325;0.441971;0.447691;, + -0.829110;0.441968;0.342404;, + -0.892722;0.382404;0.238358;, + -0.916197;0.382405;0.119793;, + -0.947008;0.321208;-0.000690;, + -0.687879;0.499643;0.526478;, + -0.750714;0.499643;0.432187;, + -0.800703;0.499642;0.330502;, + -0.866708;0.441972;0.231253;, + -0.889476;0.441976;0.116144;, + -0.923994;0.382406;-0.000820;, + -0.660585;0.555172;0.505383;, + -0.720898;0.555174;0.414835;, + -0.768877;0.555175;0.317189;, + -0.836991;0.499647;0.223159;, + -0.858958;0.499646;0.112002;, + -0.897026;0.441977;-0.000949;, + -0.630469;0.608326;0.482130;, + -0.688005;0.608327;0.395711;, + -0.733769;0.608328;0.302523;, + -0.803701;0.555175;0.214116;, + -0.824774;0.555173;0.107383;, + -0.866230;0.499645;-0.001071;, + -0.597664;0.658873;0.456820;, + -0.652178;0.658874;0.374900;, + -0.695534;0.658870;0.286572;, + -0.766981;0.608324;0.204161;, + -0.787069;0.608323;0.102304;, + -0.831734;0.555173;-0.001192;, + -0.562309;0.706603;0.429560;, + -0.613567;0.706600;0.352493;, + -0.654327;0.706599;0.269394;, + -0.726991;0.658867;0.193335;, + -0.746003;0.658872;0.096785;, + -0.793687;0.608325;-0.001306;, + -0.524559;0.751305;0.400474;, + -0.572344;0.751302;0.328585;, + -0.610334;0.751305;0.251063;, + -0.683890;0.706604;0.181676;, + -0.701754;0.706602;0.090858;, + -0.752255;0.658870;-0.001413;, + -0.484584;0.792783;0.369695;, + -0.528694;0.792784;0.303277;, + -0.563756;0.792785;0.231672;, + -0.637883;0.751305;0.169250;, + -0.654519;0.751304;0.084545;, + -0.707610;0.706601;-0.001516;, + -0.442552;0.830874;0.337339;, + -0.482799;0.830874;0.276683;, + -0.514784;0.830873;0.211301;, + -0.589173;0.792784;0.156107;, + -0.604507;0.792785;0.077869;, + -0.659953;0.751305;-0.001613;, + -0.398653;0.865406;0.303559;, + -0.434865;0.865406;0.248926;, + -0.463636;0.865406;0.190035;, + -0.537960;0.830873;0.142299;, + -0.551930;0.830874;0.070862;, + -0.609498;0.792786;-0.001701;, + -0.353095;0.896228;0.268515;, + -0.385123;0.896227;0.220132;, + -0.410561;0.896227;0.167978;, + -0.484475;0.865406;0.127890;, + -0.497025;0.865405;0.063562;, + -0.556458;0.830874;-0.001782;, + -0.306070;0.923217;0.232361;, + -0.333781;0.923217;0.190422;, + -0.355781;0.923217;0.145224;, + -0.428975;0.896227;0.112953;, + -0.440050;0.896226;0.055996;, + -0.501070;0.865405;-0.001856;, + -0.371692;0.923217;0.097546;, + -0.381242;0.923218;0.048191;, + -0.443592;0.896227;-0.001925;, + -0.496541;0.865405;-0.067243;, + -0.551465;0.830873;-0.074399;, + -0.384271;0.923218;-0.001981;, + -0.439547;0.896226;-0.059806;, + -0.483515;0.865405;-0.131478;, + -0.537037;0.830873;-0.145742;, + -0.588293;0.792784;-0.159392;, + -0.604062;0.792785;-0.081242;, + -0.380726;0.923218;-0.052120;, + -0.427978;0.896227;-0.116669;, + -0.462216;0.865406;-0.193466;, + -0.513418;0.830874;-0.214595;, + -0.562455;0.792783;-0.234816;, + -0.370666;0.923218;-0.101372;, + -0.409087;0.896228;-0.171533;, + -0.433009;0.865406;-0.252141;, + -0.481016;0.830874;-0.279773;, + -0.526992;0.792784;-0.306224;, + -0.354265;0.923217;-0.148886;, + -0.383200;0.896227;-0.223461;, + -0.396390;0.865407;-0.306506;, + -0.440382;0.830873;-0.340167;, + -0.482514;0.792784;-0.372390;, + -0.331801;0.923217;-0.193852;, + -0.350753;0.896227;-0.271569;, + -0.352997;0.865406;-0.355621;, + -0.392214;0.830874;-0.394737;, + -0.429776;0.792785;-0.432185;, + -0.303658;0.923217;-0.235504;, + -0.312308;0.896227;-0.315026;, + -0.303559;0.865406;-0.398653;, + -0.337339;0.830873;-0.442552;, + -0.369695;0.792783;-0.484584;, + -0.276683;0.830874;-0.482799;, + -0.303277;0.792784;-0.528694;, + -0.328585;0.751302;-0.572344;, + -0.400474;0.751305;-0.524559;, + -0.465517;0.751305;-0.467797;, + -0.231672;0.792785;-0.563756;, + -0.251063;0.751305;-0.610334;, + -0.269394;0.706599;-0.654327;, + -0.352493;0.706600;-0.613567;, + -0.429560;0.706603;-0.562309;, + -0.169250;0.751305;-0.637883;, + -0.181676;0.706604;-0.683890;, + -0.193335;0.658867;-0.726991;, + -0.286572;0.658870;-0.695534;, + -0.374900;0.658874;-0.652178;, + -0.090858;0.706602;-0.701754;, + -0.096785;0.658872;-0.746003;, + -0.102304;0.608323;-0.787069;, + -0.204161;0.608324;-0.766981;, + -0.302523;0.608328;-0.733769;, + 0.000000;0.667180;-0.744897;, + 0.000000;0.617074;-0.786905;, + 0.000000;0.564331;-0.825549;, + -0.107383;0.555173;-0.824774;, + -0.214116;0.555175;-0.803701;, + 0.096785;0.658872;-0.746003;, + 0.102304;0.608323;-0.787069;, + 0.107383;0.555173;-0.824774;, + 0.000000;0.509167;-0.860668;, + -0.112002;0.499646;-0.858958;, + 0.193335;0.658867;-0.726991;, + 0.204161;0.608324;-0.766981;, + 0.214116;0.555175;-0.803701;, + 0.112002;0.499646;-0.858958;, + 0.000000;0.451828;-0.892105;, + 0.286572;0.658870;-0.695534;, + 0.302523;0.608328;-0.733769;, + 0.317189;0.555175;-0.768877;, + 0.223159;0.499646;-0.836991;, + 0.116144;0.441976;-0.889476;, + 0.374900;0.658874;-0.652178;, + 0.395711;0.608327;-0.688005;, + 0.414835;0.555174;-0.720898;, + 0.330502;0.499642;-0.800703;, + 0.231253;0.441972;-0.866708;, + 0.456820;0.658873;-0.597663;, + 0.482130;0.608326;-0.630469;, + 0.505383;0.555172;-0.660585;, + 0.432187;0.499643;-0.750714;, + 0.342404;0.441968;-0.829110;, + 0.530923;0.658874;-0.532923;, + 0.560298;0.608326;-0.562144;, + 0.587285;0.555169;-0.588968;, + 0.526478;0.499643;-0.687879;, + 0.447691;0.441971;-0.777325;, + 0.595942;0.658874;-0.459062;, + 0.628882;0.608324;-0.484200;, + 0.659134;0.555172;-0.507274;, + 0.611759;0.499645;-0.613275;, + 0.545324;0.441973;-0.712237;, + 0.650764;0.658873;-0.377350;, + 0.686700;0.608326;-0.397973;, + 0.719705;0.555175;-0.416899;, + 0.686571;0.499647;-0.528179;, + 0.633621;0.441977;-0.634965;, + 0.694451;0.658871;-0.289183;, + 0.732771;0.608326;-0.304936;, + 0.767966;0.555175;-0.319390;, + 0.749641;0.499644;-0.434044;, + 0.711084;0.441972;-0.546828;, + 0.726257;0.658871;-0.196064;, + 0.766307;0.608323;-0.206681;, + 0.803084;0.555175;-0.216418;, + 0.799885;0.499641;-0.332481;, + 0.776377;0.441969;-0.449335;, + 0.745634;0.658871;-0.099591;, + 0.786728;0.608323;-0.104891;, + 0.824462;0.555174;-0.109744;, + 0.836436;0.499645;-0.225232;, + 0.828384;0.441970;-0.344154;, + 0.752255;0.658870;-0.001413;, + 0.793687;0.608325;-0.001306;, + 0.831734;0.555173;-0.001192;, + 0.858679;0.499645;-0.114128;, + 0.866216;0.441973;-0.233085;, + 0.746003;0.658872;0.096785;, + 0.787069;0.608323;0.102304;, + 0.824774;0.555173;0.107383;, + 0.866230;0.499645;-0.001071;, + 0.889229;0.441975;-0.118026;, + 0.858958;0.499646;0.112002;, + 0.897026;0.441977;-0.000949;, + 0.915981;0.382407;-0.121420;, + 0.892297;0.382406;-0.239941;, + 0.853345;0.382407;-0.354355;, + 0.889476;0.441976;0.116144;, + 0.923994;0.382406;-0.000820;, + 0.938817;0.321208;-0.124292;, + 0.914560;0.321212;-0.245771;, + 0.874657;0.321211;-0.363041;, + 0.916197;0.382405;0.119793;, + 0.947008;0.321208;-0.000690;, + 0.957638;0.258637;-0.126635;, + 0.932916;0.258635;-0.250550;, + 0.892232;0.258636;-0.370176;, + 0.938996;0.321209;0.122927;, + 0.965975;0.258635;-0.000554;, + 0.972368;0.194951;-0.128436;, + 0.947284;0.194952;-0.254258;, + 0.905992;0.194951;-0.375729;, + 0.957783;0.258637;0.125534;, + 0.980813;0.194951;-0.000418;, + 0.982939;0.130433;-0.129688;, + 0.957602;0.130431;-0.256879;, + 0.915879;0.130433;-0.379675;, + 0.972476;0.194953;0.127605;, + 0.991457;0.130434;-0.000281;, + 0.989307;0.065356;-0.130385;, + 0.963824;0.065359;-0.258402;, + 0.921850;0.065356;-0.381996;, + 0.983012;0.130430;0.129135;, + 0.997862;0.065356;-0.000140;, + 0.991445;0.000000;-0.130525;, + 0.965926;-0.000002;-0.258819;, + 0.923879;-0.000000;-0.382685;, + 0.989343;0.065357;0.130108;, + 1.000000;0.000000;0.000000;, + 0.989343;-0.065357;-0.130108;, + 0.963897;-0.065356;-0.258130;, + 0.921957;-0.065355;-0.381738;, + 0.991445;-0.000000;0.130525;, + 0.997862;-0.065356;0.000140;, + 0.983012;-0.130430;-0.129135;, + 0.957746;-0.130436;-0.256337;, + 0.916094;-0.130433;-0.379157;, + 0.989307;-0.065356;0.130385;, + 0.991457;-0.130434;0.000281;, + 0.972476;-0.194953;-0.127605;, + 0.947501;-0.194947;-0.253453;, + 0.906313;-0.194954;-0.374954;, + 0.982939;-0.130433;0.129688;, + 0.980813;-0.194951;0.000418;, + 0.957783;-0.258637;-0.125534;, + 0.933203;-0.258638;-0.249477;, + 0.892657;-0.258633;-0.369151;, + 0.972368;-0.194951;0.128436;, + 0.965975;-0.258635;0.000554;, + 0.938996;-0.321209;-0.122927;, + 0.914917;-0.321212;-0.244439;, + 0.875184;-0.321215;-0.361766;, + 0.957638;-0.258637;0.126635;, + 0.947008;-0.321208;0.000690;, + 0.916197;-0.382405;-0.119793;, + 0.892722;-0.382404;-0.238358;, + 0.853973;-0.382407;-0.352839;, + 0.938817;-0.321208;0.124292;, + 0.923994;-0.382406;0.000820;, + 0.889476;-0.441976;-0.116144;, + 0.866708;-0.441972;-0.231253;, + 0.829110;-0.441968;-0.342404;, + 0.915981;-0.382407;0.121420;, + 0.897026;-0.441977;0.000949;, + 0.858958;-0.499646;-0.112002;, + 0.836991;-0.499646;-0.223159;, + 0.800703;-0.499642;-0.330502;, + 0.889229;-0.441975;0.118026;, + 0.866230;-0.499644;0.001071;, + 0.824774;-0.555173;-0.107383;, + 0.803701;-0.555175;-0.214116;, + 0.768877;-0.555175;-0.317189;, + 0.858679;-0.499645;0.114128;, + 0.831734;-0.555173;0.001192;, + 0.787069;-0.608323;-0.102304;, + 0.766981;-0.608324;-0.204161;, + 0.733769;-0.608328;-0.302523;, + 0.824462;-0.555174;0.109745;, + 0.793687;-0.608325;0.001306;, + 0.746003;-0.658872;-0.096785;, + 0.726991;-0.658867;-0.193335;, + 0.695534;-0.658870;-0.286572;, + 0.786728;-0.608323;0.104891;, + 0.752255;-0.658870;0.001413;, + 0.701754;-0.706602;-0.090858;, + 0.683890;-0.706604;-0.181676;, + 0.654327;-0.706599;-0.269394;, + 0.745634;-0.658871;0.099591;, + 0.707610;-0.706601;0.001516;, + 0.701358;-0.706602;0.093865;, + 0.613567;-0.706600;-0.352493;, + 0.652178;-0.658874;-0.374900;, + 0.688005;-0.608327;-0.395711;, + 0.562309;-0.706603;-0.429560;, + 0.597664;-0.658873;-0.456820;, + 0.630469;-0.608326;-0.482130;, + 0.720898;-0.555174;-0.414835;, + 0.750714;-0.499643;-0.432187;, + 0.501428;-0.706601;-0.499285;, + 0.532923;-0.658874;-0.530922;, + 0.562144;-0.608326;-0.560298;, + 0.660585;-0.555172;-0.505383;, + 0.687879;-0.499643;-0.526478;, + 0.777325;-0.441971;-0.447691;, + 0.431968;-0.706602;-0.560462;, + 0.459062;-0.658874;-0.595942;, + 0.484200;-0.608324;-0.628882;, + 0.588968;-0.555169;-0.587285;, + 0.613275;-0.499645;-0.611759;, + 0.712237;-0.441973;-0.545324;, + 0.355118;-0.706601;-0.612051;, + 0.377350;-0.658873;-0.650764;, + 0.397973;-0.608326;-0.686700;, + 0.507273;-0.555172;-0.659134;, + 0.528179;-0.499647;-0.686571;, + 0.634965;-0.441977;-0.633621;, + 0.272194;-0.706601;-0.653166;, + 0.289183;-0.658871;-0.694451;, + 0.304936;-0.608326;-0.732771;, + 0.416899;-0.555175;-0.719705;, + 0.434044;-0.499644;-0.749641;, + 0.546828;-0.441972;-0.711084;, + 0.172365;-0.751306;-0.637047;, + 0.184607;-0.706601;-0.683108;, + 0.196064;-0.658871;-0.726257;, + 0.206681;-0.608323;-0.766307;, + 0.319390;-0.555175;-0.767966;, + 0.087739;-0.751305;-0.654097;, + 0.093865;-0.706602;-0.701358;, + 0.099591;-0.658871;-0.745634;, + 0.104891;-0.608323;-0.786728;, + 0.216418;-0.555175;-0.803084;, + 0.332481;-0.499641;-0.799885;, + 0.000000;-0.786303;-0.617841;, + -0.000000;-0.744259;-0.667891;, + 0.000000;-0.699029;-0.715094;, + 0.000000;-0.650798;-0.759251;, + 0.000000;-0.599793;-0.800155;, + 0.109745;-0.555174;-0.824462;, + -0.087739;-0.751305;-0.654097;, + -0.093865;-0.706602;-0.701358;, + -0.099591;-0.658871;-0.745634;, + -0.104891;-0.608323;-0.786728;, + -0.109745;-0.555174;-0.824462;, + 0.000000;-0.546215;-0.837645;, + -0.172365;-0.751306;-0.637047;, + -0.184607;-0.706601;-0.683108;, + -0.196064;-0.658871;-0.726257;, + -0.206681;-0.608323;-0.766307;, + -0.216418;-0.555175;-0.803084;, + -0.254044;-0.751305;-0.609100;, + -0.272194;-0.706601;-0.653166;, + -0.289183;-0.658871;-0.694451;, + -0.304936;-0.608326;-0.732771;, + -0.319390;-0.555175;-0.767966;, + -0.331374;-0.751303;-0.570733;, + -0.355118;-0.706601;-0.612051;, + -0.377350;-0.658873;-0.650764;, + -0.397973;-0.608326;-0.686700;, + -0.416899;-0.555175;-0.719705;, + -0.403034;-0.751304;-0.522596;, + -0.431968;-0.706602;-0.560462;, + -0.459062;-0.658874;-0.595942;, + -0.484200;-0.608324;-0.628882;, + -0.507274;-0.555171;-0.659134;, + -0.467797;-0.751305;-0.465517;, + -0.501428;-0.706601;-0.499285;, + -0.532922;-0.658874;-0.530922;, + -0.562144;-0.608326;-0.560298;, + -0.588968;-0.555169;-0.587285;, + -0.524559;-0.751305;-0.400474;, + -0.562309;-0.706603;-0.429560;, + -0.597663;-0.658873;-0.456820;, + -0.630469;-0.608326;-0.482130;, + -0.660585;-0.555172;-0.505383;, + -0.572344;-0.751302;-0.328585;, + -0.613567;-0.706600;-0.352493;, + -0.652178;-0.658874;-0.374900;, + -0.688005;-0.608327;-0.395711;, + -0.720898;-0.555174;-0.414835;, + -0.610334;-0.751305;-0.251063;, + -0.654327;-0.706599;-0.269394;, + -0.695534;-0.658870;-0.286572;, + -0.733769;-0.608328;-0.302523;, + -0.768877;-0.555175;-0.317189;, + -0.637883;-0.751305;-0.169250;, + -0.683890;-0.706604;-0.181676;, + -0.726991;-0.658867;-0.193335;, + -0.766981;-0.608324;-0.204161;, + -0.803701;-0.555175;-0.214116;, + -0.654519;-0.751304;-0.084545;, + -0.701754;-0.706602;-0.090858;, + -0.746003;-0.658872;-0.096785;, + -0.787069;-0.608323;-0.102304;, + -0.824774;-0.555173;-0.107383;, + -0.858958;-0.499646;-0.112002;, + -0.836991;-0.499646;-0.223159;, + -0.800703;-0.499642;-0.330502;, + -0.889476;-0.441976;-0.116144;, + -0.866708;-0.441972;-0.231253;, + -0.829110;-0.441968;-0.342404;, + -0.750714;-0.499643;-0.432187;, + -0.687879;-0.499643;-0.526478;, + -0.916197;-0.382405;-0.119793;, + -0.892722;-0.382404;-0.238358;, + -0.853973;-0.382407;-0.352839;, + -0.777325;-0.441971;-0.447691;, + -0.712237;-0.441973;-0.545324;, + -0.613275;-0.499645;-0.611759;, + -0.938996;-0.321209;-0.122927;, + -0.914917;-0.321212;-0.244439;, + -0.875184;-0.321215;-0.361766;, + -0.800613;-0.382408;-0.461284;, + -0.733553;-0.382409;-0.561839;, + -0.634965;-0.441977;-0.633621;, + -0.957783;-0.258637;-0.125534;, + -0.933203;-0.258638;-0.249477;, + -0.892657;-0.258633;-0.369151;, + -0.820478;-0.321211;-0.472906;, + -0.751733;-0.321206;-0.575955;, + -0.653942;-0.382408;-0.652782;, + -0.972476;-0.194953;-0.127605;, + -0.947501;-0.194947;-0.253453;, + -0.906313;-0.194954;-0.374954;, + -0.836837;-0.258631;-0.482508;, + -0.766698;-0.258633;-0.587607;, + -0.670124;-0.321208;-0.669148;, + -0.983012;-0.130430;-0.129135;, + -0.957746;-0.130436;-0.256337;, + -0.916094;-0.130433;-0.379157;, + -0.849617;-0.194952;-0.490046;, + -0.778387;-0.194949;-0.596748;, + -0.683441;-0.258632;-0.682655;, + -0.989343;-0.065357;-0.130108;, + -0.963897;-0.065356;-0.258130;, + -0.921957;-0.065355;-0.381738;, + -0.858766;-0.130428;-0.495489;, + -0.786747;-0.130435;-0.603337;, + -0.693835;-0.194947;-0.693245;, + -0.991445;0.000000;-0.130525;, + -0.965926;-0.000002;-0.258819;, + -0.923879;-0.000000;-0.382685;, + -0.864244;-0.065361;-0.498808;, + -0.791743;-0.065357;-0.607348;, + -0.701263;-0.130435;-0.700868;, + -0.989307;0.065356;-0.130385;, + -0.963824;0.065359;-0.258402;, + -0.921850;0.065356;-0.381996;, + -0.866025;0.000003;-0.500001;, + -0.793355;-0.000000;-0.608759;, + -0.705695;-0.065360;-0.705495;, + -0.982939;0.130433;-0.129688;, + -0.957602;0.130431;-0.256879;, + -0.915879;0.130433;-0.379675;, + -0.864104;0.065353;-0.499052;, + -0.791574;0.065356;-0.607569;, + -0.707107;0.000000;-0.707107;, + -0.972368;0.194951;-0.128436;, + -0.947284;0.194952;-0.254258;, + -0.905992;0.194951;-0.375729;, + -0.858487;0.130434;-0.495971;, + -0.786405;0.130436;-0.603783;, + -0.705495;0.065360;-0.705695;, + -0.957638;0.258637;-0.126635;, + -0.932916;0.258635;-0.250550;, + -0.892232;0.258636;-0.370176;, + -0.849201;0.194948;-0.490768;, + -0.777876;0.194952;-0.597414;, + -0.700868;0.130435;-0.701263;, + -0.938817;0.321208;-0.124292;, + -0.914560;0.321212;-0.245771;, + -0.874657;0.321211;-0.363040;, + -0.836281;0.258636;-0.483469;, + -0.766024;0.258630;-0.588488;, + -0.693245;0.194947;-0.693835;, + -0.915981;0.382407;-0.121420;, + -0.892297;0.382406;-0.239941;, + -0.853345;0.382407;-0.354355;, + -0.819790;0.321208;-0.474099;, + -0.750893;0.321209;-0.577047;, + -0.682655;0.258632;-0.683441;, + -0.889229;0.441975;-0.118026;, + -0.866216;0.441973;-0.233086;, + -0.828384;0.441970;-0.344154;, + -0.799792;0.382409;-0.462705;, + -0.732556;0.382406;-0.563141;, + -0.669148;0.321208;-0.670124;, + -0.858679;0.499645;-0.114128;, + -0.836436;0.499645;-0.225232;, + -0.799885;0.499641;-0.332481;, + -0.776377;0.441969;-0.449335;, + -0.711084;0.441972;-0.546828;, + -0.652782;0.382408;-0.653942;, + -0.824462;0.555174;-0.109745;, + -0.803084;0.555175;-0.216418;, + -0.767966;0.555175;-0.319390;, + -0.749641;0.499644;-0.434044;, + -0.686571;0.499647;-0.528179;, + -0.633621;0.441977;-0.634965;, + -0.786728;0.608323;-0.104891;, + -0.766307;0.608323;-0.206681;, + -0.732771;0.608326;-0.304936;, + -0.719705;0.555175;-0.416899;, + -0.659134;0.555172;-0.507273;, + -0.611759;0.499645;-0.613275;, + -0.745634;0.658871;-0.099591;, + -0.726257;0.658871;-0.196064;, + -0.694451;0.658871;-0.289183;, + -0.686700;0.608326;-0.397973;, + -0.628882;0.608324;-0.484200;, + -0.587285;0.555169;-0.588968;, + -0.701358;0.706602;-0.093865;, + -0.683108;0.706601;-0.184607;, + -0.653166;0.706601;-0.272194;, + -0.650764;0.658873;-0.377350;, + -0.595942;0.658874;-0.459062;, + -0.560298;0.608326;-0.562144;, + -0.654097;0.751305;-0.087739;, + -0.637047;0.751306;-0.172365;, + -0.609100;0.751305;-0.254044;, + -0.612051;0.706601;-0.355118;, + -0.560462;0.706602;-0.431968;, + -0.530923;0.658874;-0.532922;, + -0.570733;0.751303;-0.331374;, + -0.522596;0.751304;-0.403034;, + -0.499285;0.706601;-0.501428;, + -0.456820;0.658873;-0.597663;, + -0.482130;0.608326;-0.630469;, + -0.395711;0.608327;-0.688005;, + -0.414835;0.555174;-0.720898;, + -0.505383;0.555172;-0.660585;, + -0.526478;0.499643;-0.687879;, + -0.317189;0.555175;-0.768877;, + -0.330502;0.499642;-0.800703;, + -0.432187;0.499643;-0.750714;, + -0.447691;0.441971;-0.777325;, + -0.545324;0.441973;-0.712237;, + -0.223159;0.499647;-0.836991;, + -0.231253;0.441972;-0.866708;, + -0.342404;0.441968;-0.829110;, + -0.352839;0.382407;-0.853973;, + -0.461284;0.382408;-0.800613;, + -0.561839;0.382409;-0.733553;, + -0.116144;0.441976;-0.889476;, + -0.119793;0.382405;-0.916197;, + -0.238358;0.382404;-0.892722;, + -0.244439;0.321212;-0.914917;, + -0.361766;0.321215;-0.875184;, + -0.472906;0.321211;-0.820478;, + 0.000000;0.392541;-0.919735;, + -0.000000;0.331582;-0.943426;, + -0.122927;0.321209;-0.938996;, + -0.125534;0.258637;-0.957783;, + -0.249477;0.258638;-0.933203;, + -0.369151;0.258633;-0.892657;, + 0.119793;0.382405;-0.916197;, + 0.122927;0.321209;-0.938996;, + 0.000000;0.269204;-0.963083;, + -0.000000;0.205675;-0.978620;, + -0.127605;0.194953;-0.972476;, + -0.253453;0.194947;-0.947501;, + 0.238358;0.382404;-0.892722;, + 0.244439;0.321212;-0.914917;, + 0.125534;0.258637;-0.957783;, + 0.127605;0.194953;-0.972476;, + 0.000000;0.141259;-0.989973;, + -0.129135;0.130430;-0.983012;, + 0.352839;0.382407;-0.853973;, + 0.361766;0.321215;-0.875184;, + 0.249477;0.258638;-0.933203;, + 0.253453;0.194947;-0.947501;, + 0.129135;0.130430;-0.983012;, + 0.000000;0.076239;-0.997090;, + 0.461284;0.382408;-0.800613;, + 0.472906;0.321211;-0.820478;, + 0.369151;0.258633;-0.892657;, + 0.374954;0.194954;-0.906313;, + 0.256337;0.130436;-0.957746;, + 0.130108;0.065357;-0.989343;, + 0.561839;0.382409;-0.733553;, + 0.575955;0.321206;-0.751733;, + 0.482508;0.258631;-0.836837;, + 0.490046;0.194952;-0.849617;, + 0.379157;0.130433;-0.916094;, + 0.258130;0.065356;-0.963897;, + 0.652782;0.382408;-0.653942;, + 0.669148;0.321208;-0.670124;, + 0.587607;0.258633;-0.766698;, + 0.596748;0.194949;-0.778387;, + 0.495489;0.130428;-0.858766;, + 0.381738;0.065355;-0.921957;, + 0.732556;0.382406;-0.563141;, + 0.750893;0.321209;-0.577048;, + 0.682655;0.258632;-0.683441;, + 0.693245;0.194947;-0.693835;, + 0.603337;0.130435;-0.786747;, + 0.498808;0.065361;-0.864245;, + 0.799792;0.382409;-0.462705;, + 0.819790;0.321208;-0.474099;, + 0.766024;0.258630;-0.588488;, + 0.777876;0.194952;-0.597414;, + 0.700868;0.130435;-0.701263;, + 0.607348;0.065357;-0.791743;, + 0.836281;0.258636;-0.483469;, + 0.849201;0.194948;-0.490768;, + 0.786405;0.130436;-0.603783;, + 0.705495;0.065360;-0.705695;, + 0.608759;0.000000;-0.793355;, + 0.500001;-0.000003;-0.866025;, + 0.858487;0.130434;-0.495971;, + 0.791574;0.065356;-0.607569;, + 0.707107;0.000000;-0.707107;, + 0.607569;-0.065356;-0.791574;, + 0.499052;-0.065353;-0.864104;, + 0.864104;0.065353;-0.499053;, + 0.793355;-0.000000;-0.608759;, + 0.705695;-0.065360;-0.705495;, + 0.603783;-0.130436;-0.786405;, + 0.495971;-0.130434;-0.858487;, + 0.866025;0.000003;-0.500001;, + 0.791743;-0.065357;-0.607348;, + 0.701263;-0.130435;-0.700868;, + 0.597414;-0.194952;-0.777876;, + 0.490768;-0.194948;-0.849201;, + 0.864244;-0.065361;-0.498808;, + 0.786747;-0.130435;-0.603337;, + 0.693835;-0.194947;-0.693245;, + 0.588488;-0.258630;-0.766024;, + 0.483469;-0.258636;-0.836280;, + 0.858766;-0.130428;-0.495489;, + 0.778387;-0.194949;-0.596748;, + 0.683441;-0.258632;-0.682655;, + 0.577048;-0.321209;-0.750893;, + 0.474099;-0.321208;-0.819790;, + 0.849617;-0.194952;-0.490046;, + 0.766698;-0.258633;-0.587607;, + 0.670124;-0.321208;-0.669148;, + 0.563141;-0.382406;-0.732556;, + 0.462705;-0.382409;-0.799792;, + 0.836837;-0.258631;-0.482508;, + 0.751733;-0.321206;-0.575955;, + 0.653942;-0.382408;-0.652782;, + 0.449335;-0.441969;-0.776377;, + 0.820478;-0.321211;-0.472906;, + 0.733553;-0.382409;-0.561839;, + 0.800613;-0.382408;-0.461284;, + 0.344154;-0.441970;-0.828384;, + 0.354355;-0.382408;-0.853345;, + 0.363041;-0.321211;-0.874657;, + 0.225232;-0.499645;-0.836436;, + 0.233086;-0.441973;-0.866216;, + 0.239941;-0.382406;-0.892297;, + 0.245771;-0.321212;-0.914560;, + 0.370176;-0.258636;-0.892232;, + 0.114128;-0.499645;-0.858679;, + 0.118026;-0.441975;-0.889229;, + 0.121420;-0.382407;-0.915981;, + 0.124292;-0.321208;-0.938817;, + 0.250550;-0.258635;-0.932916;, + 0.375729;-0.194951;-0.905992;, + 0.000000;-0.490301;-0.871553;, + -0.000000;-0.432283;-0.901738;, + 0.000000;-0.372408;-0.928069;, + 0.000000;-0.310949;-0.950427;, + 0.126635;-0.258637;-0.957638;, + 0.254258;-0.194952;-0.947284;, + -0.114128;-0.499645;-0.858679;, + -0.118026;-0.441975;-0.889229;, + -0.121420;-0.382407;-0.915981;, + -0.124292;-0.321208;-0.938817;, + -0.126635;-0.258637;-0.957638;, + -0.000000;-0.248158;-0.968720;, + -0.225232;-0.499645;-0.836436;, + -0.233086;-0.441973;-0.866216;, + -0.239941;-0.382406;-0.892297;, + -0.245771;-0.321212;-0.914560;, + -0.250550;-0.258635;-0.932916;, + -0.332481;-0.499641;-0.799885;, + -0.344154;-0.441970;-0.828384;, + -0.354355;-0.382407;-0.853345;, + -0.363041;-0.321211;-0.874657;, + -0.370176;-0.258636;-0.892232;, + -0.434044;-0.499644;-0.749641;, + -0.449335;-0.441969;-0.776377;, + -0.462705;-0.382409;-0.799792;, + -0.474099;-0.321208;-0.819790;, + -0.483469;-0.258636;-0.836281;, + -0.528179;-0.499647;-0.686571;, + -0.546828;-0.441972;-0.711084;, + -0.563141;-0.382406;-0.732556;, + -0.577047;-0.321209;-0.750893;, + -0.588488;-0.258630;-0.766024;, + -0.597414;-0.194952;-0.777876;, + -0.490768;-0.194948;-0.849201;, + -0.375729;-0.194951;-0.905992;, + -0.603783;-0.130436;-0.786405;, + -0.495971;-0.130434;-0.858487;, + -0.379675;-0.130433;-0.915879;, + -0.254258;-0.194952;-0.947284;, + -0.128436;-0.194951;-0.972368;, + -0.607569;-0.065356;-0.791574;, + -0.499052;-0.065353;-0.864104;, + -0.381996;-0.065356;-0.921850;, + -0.256879;-0.130431;-0.957602;, + -0.129688;-0.130433;-0.982939;, + 0.000000;-0.184298;-0.982871;, + -0.608759;0.000000;-0.793355;, + -0.500001;-0.000003;-0.866025;, + -0.382685;0.000000;-0.923879;, + -0.258402;-0.065359;-0.963824;, + -0.130385;-0.065356;-0.989307;, + 0.000000;-0.119654;-0.992816;, + -0.607348;0.065357;-0.791743;, + -0.498808;0.065361;-0.864244;, + -0.381738;0.065355;-0.921957;, + -0.258819;0.000002;-0.965926;, + -0.130525;-0.000000;-0.991445;, + 0.000000;-0.054496;-0.998514;, + -0.603337;0.130435;-0.786747;, + -0.495489;0.130428;-0.858766;, + -0.379157;0.130433;-0.916094;, + -0.258130;0.065356;-0.963897;, + -0.130108;0.065357;-0.989343;, + 0.000000;0.010897;-0.999941;, + -0.596748;0.194949;-0.778387;, + -0.490046;0.194952;-0.849617;, + -0.374954;0.194954;-0.906313;, + -0.256337;0.130436;-0.957746;, + -0.587607;0.258633;-0.766698;, + -0.482508;0.258631;-0.836837;, + -0.575955;0.321206;-0.751733;, + 0.130525;-0.000000;-0.991445;, + 0.130385;-0.065356;-0.989307;, + 0.129688;-0.130433;-0.982939;, + 0.258819;0.000002;-0.965926;, + 0.258402;-0.065359;-0.963824;, + 0.256879;-0.130431;-0.957602;, + 0.128436;-0.194951;-0.972368;, + 0.382685;0.000000;-0.923879;, + 0.381996;-0.065356;-0.921850;, + 0.379675;-0.130433;-0.915879;; + 4512; + 3;0,1,2;, + 3;3,1,0;, + 3;3,4,1;, + 3;4,5,1;, + 3;1,5,6;, + 3;7,0,2;, + 3;8,0,7;, + 3;8,3,0;, + 3;9,3,8;, + 3;9,10,3;, + 3;10,4,3;, + 3;10,11,4;, + 3;11,12,4;, + 3;4,12,5;, + 3;13,7,2;, + 3;14,7,13;, + 3;14,8,7;, + 3;15,8,14;, + 3;15,9,8;, + 3;16,9,15;, + 3;16,17,9;, + 3;17,10,9;, + 3;17,18,10;, + 3;18,11,10;, + 3;19,13,2;, + 3;20,13,19;, + 3;20,14,13;, + 3;21,14,20;, + 3;21,15,14;, + 3;22,15,21;, + 3;22,16,15;, + 3;23,16,22;, + 3;23,24,16;, + 3;24,17,16;, + 3;25,19,2;, + 3;26,19,25;, + 3;26,20,19;, + 3;27,20,26;, + 3;27,21,20;, + 3;28,21,27;, + 3;28,22,21;, + 3;29,22,28;, + 3;29,23,22;, + 3;25,2,30;, + 3;26,25,30;, + 3;26,30,31;, + 3;27,26,31;, + 3;27,31,32;, + 3;28,27,32;, + 3;28,32,33;, + 3;29,28,33;, + 3;29,33,34;, + 3;35,29,34;, + 3;35,23,29;, + 3;30,2,36;, + 3;31,30,36;, + 3;31,36,37;, + 3;32,31,37;, + 3;32,37,38;, + 3;33,32,38;, + 3;33,38,39;, + 3;34,33,39;, + 3;34,39,40;, + 3;41,34,40;, + 3;35,34,41;, + 3;36,2,42;, + 3;37,36,42;, + 3;37,42,43;, + 3;38,37,43;, + 3;38,43,44;, + 3;39,38,44;, + 3;39,44,45;, + 3;40,39,45;, + 3;40,45,46;, + 3;47,40,46;, + 3;41,40,47;, + 3;42,2,48;, + 3;43,42,48;, + 3;43,48,49;, + 3;44,43,49;, + 3;44,49,50;, + 3;45,44,50;, + 3;45,50,51;, + 3;46,45,51;, + 3;46,51,52;, + 3;53,46,52;, + 3;47,46,53;, + 3;48,2,54;, + 3;49,48,54;, + 3;49,54,55;, + 3;50,49,55;, + 3;50,55,56;, + 3;51,50,56;, + 3;51,56,57;, + 3;52,51,57;, + 3;52,57,58;, + 3;59,52,58;, + 3;53,52,59;, + 3;54,2,60;, + 3;55,54,60;, + 3;55,60,61;, + 3;56,55,61;, + 3;56,61,62;, + 3;57,56,62;, + 3;57,62,63;, + 3;58,57,63;, + 3;58,63,64;, + 3;65,58,64;, + 3;59,58,65;, + 3;60,2,66;, + 3;61,60,66;, + 3;61,66,67;, + 3;62,61,67;, + 3;62,67,68;, + 3;63,62,68;, + 3;63,68,69;, + 3;64,63,69;, + 3;64,69,70;, + 3;71,64,70;, + 3;65,64,71;, + 3;66,2,72;, + 3;67,66,72;, + 3;67,72,73;, + 3;68,67,73;, + 3;68,73,74;, + 3;69,68,74;, + 3;69,74,75;, + 3;70,69,75;, + 3;70,75,76;, + 3;77,70,76;, + 3;71,70,77;, + 3;72,2,78;, + 3;73,72,78;, + 3;73,78,79;, + 3;74,73,79;, + 3;74,79,80;, + 3;75,74,80;, + 3;75,80,81;, + 3;76,75,81;, + 3;76,81,82;, + 3;83,76,82;, + 3;77,76,83;, + 3;78,2,84;, + 3;79,78,84;, + 3;79,84,85;, + 3;80,79,85;, + 3;80,85,86;, + 3;81,80,86;, + 3;81,86,87;, + 3;82,81,87;, + 3;82,87,88;, + 3;89,82,88;, + 3;83,82,89;, + 3;84,2,90;, + 3;85,84,90;, + 3;85,90,91;, + 3;86,85,91;, + 3;86,91,92;, + 3;87,86,92;, + 3;87,92,93;, + 3;88,87,93;, + 3;88,93,94;, + 3;95,88,94;, + 3;89,88,95;, + 3;90,2,96;, + 3;91,90,96;, + 3;91,96,97;, + 3;92,91,97;, + 3;92,97,98;, + 3;93,92,98;, + 3;93,98,99;, + 3;94,93,99;, + 3;94,99,100;, + 3;101,94,100;, + 3;95,94,101;, + 3;96,2,102;, + 3;97,96,102;, + 3;97,102,103;, + 3;98,97,103;, + 3;98,103,104;, + 3;99,98,104;, + 3;99,104,105;, + 3;100,99,105;, + 3;100,105,106;, + 3;107,100,106;, + 3;101,100,107;, + 3;102,2,108;, + 3;103,102,108;, + 3;103,108,109;, + 3;104,103,109;, + 3;104,109,110;, + 3;105,104,110;, + 3;105,110,111;, + 3;106,105,111;, + 3;106,111,112;, + 3;113,106,112;, + 3;107,106,113;, + 3;108,2,114;, + 3;109,108,114;, + 3;109,114,115;, + 3;110,109,115;, + 3;110,115,116;, + 3;111,110,116;, + 3;111,116,117;, + 3;112,111,117;, + 3;112,117,118;, + 3;119,112,118;, + 3;113,112,119;, + 3;114,2,120;, + 3;115,114,120;, + 3;115,120,121;, + 3;116,115,121;, + 3;116,121,122;, + 3;117,116,122;, + 3;117,122,123;, + 3;118,117,123;, + 3;118,123,124;, + 3;125,118,124;, + 3;119,118,125;, + 3;120,2,126;, + 3;121,120,126;, + 3;121,126,127;, + 3;122,121,127;, + 3;122,127,128;, + 3;123,122,128;, + 3;123,128,129;, + 3;124,123,129;, + 3;124,129,130;, + 3;131,124,130;, + 3;125,124,131;, + 3;126,2,132;, + 3;127,126,132;, + 3;127,132,133;, + 3;128,127,133;, + 3;128,133,134;, + 3;129,128,134;, + 3;129,134,135;, + 3;130,129,135;, + 3;130,135,136;, + 3;137,130,136;, + 3;131,130,137;, + 3;132,2,138;, + 3;133,132,138;, + 3;133,138,139;, + 3;134,133,139;, + 3;134,139,140;, + 3;135,134,140;, + 3;135,140,141;, + 3;136,135,141;, + 3;136,141,142;, + 3;143,136,142;, + 3;137,136,143;, + 3;138,2,144;, + 3;139,138,144;, + 3;139,144,145;, + 3;140,139,145;, + 3;140,145,146;, + 3;141,140,146;, + 3;141,146,147;, + 3;142,141,147;, + 3;142,147,148;, + 3;149,142,148;, + 3;143,142,149;, + 3;144,2,150;, + 3;145,144,150;, + 3;145,150,151;, + 3;146,145,151;, + 3;146,151,152;, + 3;147,146,152;, + 3;147,152,153;, + 3;148,147,153;, + 3;148,153,154;, + 3;155,148,154;, + 3;149,148,155;, + 3;150,2,156;, + 3;151,150,156;, + 3;151,156,157;, + 3;152,151,157;, + 3;152,157,158;, + 3;153,152,158;, + 3;153,158,159;, + 3;154,153,159;, + 3;154,159,160;, + 3;161,154,160;, + 3;155,154,161;, + 3;156,2,162;, + 3;157,156,162;, + 3;157,162,163;, + 3;158,157,163;, + 3;158,163,164;, + 3;159,158,164;, + 3;159,164,165;, + 3;160,159,165;, + 3;160,165,166;, + 3;167,160,166;, + 3;161,160,167;, + 3;162,2,168;, + 3;163,162,168;, + 3;163,168,169;, + 3;164,163,169;, + 3;164,169,170;, + 3;165,164,170;, + 3;165,170,171;, + 3;166,165,171;, + 3;166,171,172;, + 3;173,166,172;, + 3;167,166,173;, + 3;174,167,173;, + 3;175,167,174;, + 3;175,161,167;, + 3;176,161,175;, + 3;176,155,161;, + 3;173,172,177;, + 3;178,173,177;, + 3;174,173,178;, + 3;179,174,178;, + 3;180,174,179;, + 3;180,175,174;, + 3;181,175,180;, + 3;181,176,175;, + 3;182,176,181;, + 3;182,183,176;, + 3;183,155,176;, + 3;183,149,155;, + 3;178,177,184;, + 3;185,178,184;, + 3;179,178,185;, + 3;186,179,185;, + 3;187,179,186;, + 3;187,180,179;, + 3;188,180,187;, + 3;188,181,180;, + 3;189,181,188;, + 3;189,182,181;, + 3;185,184,190;, + 3;191,185,190;, + 3;186,185,191;, + 3;192,186,191;, + 3;193,186,192;, + 3;193,187,186;, + 3;194,187,193;, + 3;194,188,187;, + 3;195,188,194;, + 3;195,189,188;, + 3;191,190,196;, + 3;197,191,196;, + 3;192,191,197;, + 3;198,192,197;, + 3;199,192,198;, + 3;199,193,192;, + 3;200,193,199;, + 3;200,194,193;, + 3;201,194,200;, + 3;201,195,194;, + 3;197,196,202;, + 3;203,197,202;, + 3;198,197,203;, + 3;204,198,203;, + 3;205,198,204;, + 3;205,199,198;, + 3;206,199,205;, + 3;206,200,199;, + 3;207,200,206;, + 3;207,201,200;, + 3;203,202,208;, + 3;209,203,208;, + 3;204,203,209;, + 3;210,204,209;, + 3;211,204,210;, + 3;211,205,204;, + 3;212,205,211;, + 3;212,206,205;, + 3;213,206,212;, + 3;213,207,206;, + 3;209,208,214;, + 3;215,209,214;, + 3;210,209,215;, + 3;216,210,215;, + 3;217,210,216;, + 3;217,211,210;, + 3;218,211,217;, + 3;218,212,211;, + 3;219,212,218;, + 3;219,213,212;, + 3;215,214,220;, + 3;221,215,220;, + 3;216,215,221;, + 3;222,216,221;, + 3;223,216,222;, + 3;223,217,216;, + 3;224,217,223;, + 3;224,218,217;, + 3;225,218,224;, + 3;225,219,218;, + 3;221,220,226;, + 3;227,221,226;, + 3;222,221,227;, + 3;228,222,227;, + 3;229,222,228;, + 3;229,223,222;, + 3;230,223,229;, + 3;230,224,223;, + 3;231,224,230;, + 3;231,225,224;, + 3;227,226,232;, + 3;233,227,232;, + 3;228,227,233;, + 3;234,228,233;, + 3;235,228,234;, + 3;235,229,228;, + 3;236,229,235;, + 3;236,230,229;, + 3;237,230,236;, + 3;237,231,230;, + 3;233,232,238;, + 3;239,233,238;, + 3;234,233,239;, + 3;240,234,239;, + 3;241,234,240;, + 3;241,235,234;, + 3;242,235,241;, + 3;242,236,235;, + 3;243,236,242;, + 3;243,237,236;, + 3;239,238,244;, + 3;245,239,244;, + 3;240,239,245;, + 3;246,240,245;, + 3;247,240,246;, + 3;247,241,240;, + 3;248,241,247;, + 3;248,242,241;, + 3;249,242,248;, + 3;249,243,242;, + 3;245,244,250;, + 3;251,245,250;, + 3;246,245,251;, + 3;252,246,251;, + 3;253,246,252;, + 3;253,247,246;, + 3;254,247,253;, + 3;254,248,247;, + 3;255,248,254;, + 3;255,249,248;, + 3;251,250,256;, + 3;257,251,256;, + 3;252,251,257;, + 3;258,252,257;, + 3;259,252,258;, + 3;259,253,252;, + 3;260,253,259;, + 3;260,254,253;, + 3;261,254,260;, + 3;261,255,254;, + 3;257,256,262;, + 3;263,257,262;, + 3;258,257,263;, + 3;264,258,263;, + 3;265,258,264;, + 3;265,259,258;, + 3;266,259,265;, + 3;266,260,259;, + 3;267,260,266;, + 3;267,261,260;, + 3;263,262,268;, + 3;269,263,268;, + 3;264,263,269;, + 3;270,264,269;, + 3;271,264,270;, + 3;271,265,264;, + 3;272,265,271;, + 3;272,266,265;, + 3;273,266,272;, + 3;273,267,266;, + 3;269,268,274;, + 3;275,269,274;, + 3;270,269,275;, + 3;276,270,275;, + 3;277,270,276;, + 3;277,271,270;, + 3;278,271,277;, + 3;278,272,271;, + 3;279,272,278;, + 3;279,273,272;, + 3;275,274,280;, + 3;281,275,280;, + 3;276,275,281;, + 3;282,276,281;, + 3;283,276,282;, + 3;283,277,276;, + 3;284,277,283;, + 3;284,278,277;, + 3;285,278,284;, + 3;285,279,278;, + 3;281,280,286;, + 3;287,281,286;, + 3;282,281,287;, + 3;288,282,287;, + 3;289,282,288;, + 3;289,283,282;, + 3;290,283,289;, + 3;290,284,283;, + 3;291,284,290;, + 3;291,285,284;, + 3;287,286,292;, + 3;293,287,292;, + 3;288,287,293;, + 3;294,288,293;, + 3;295,288,294;, + 3;295,289,288;, + 3;296,289,295;, + 3;296,290,289;, + 3;297,290,296;, + 3;297,291,290;, + 3;293,292,298;, + 3;299,293,298;, + 3;294,293,299;, + 3;300,294,299;, + 3;301,294,300;, + 3;301,295,294;, + 3;302,295,301;, + 3;302,296,295;, + 3;303,296,302;, + 3;303,297,296;, + 3;299,298,304;, + 3;305,299,304;, + 3;300,299,305;, + 3;306,300,305;, + 3;307,300,306;, + 3;307,301,300;, + 3;308,301,307;, + 3;308,302,301;, + 3;309,302,308;, + 3;309,303,302;, + 3;305,304,310;, + 3;311,305,310;, + 3;306,305,311;, + 3;312,306,311;, + 3;313,306,312;, + 3;313,307,306;, + 3;314,307,313;, + 3;314,308,307;, + 3;315,308,314;, + 3;315,309,308;, + 3;311,310,316;, + 3;317,311,316;, + 3;312,311,317;, + 3;318,312,317;, + 3;319,312,318;, + 3;319,313,312;, + 3;320,313,319;, + 3;320,314,313;, + 3;321,314,320;, + 3;321,315,314;, + 3;317,316,322;, + 3;323,317,322;, + 3;318,317,323;, + 3;324,318,323;, + 3;325,318,324;, + 3;325,319,318;, + 3;326,319,325;, + 3;326,320,319;, + 3;327,320,326;, + 3;327,321,320;, + 3;323,322,328;, + 3;329,323,328;, + 3;324,323,329;, + 3;330,324,329;, + 3;331,324,330;, + 3;331,325,324;, + 3;332,325,331;, + 3;332,326,325;, + 3;333,326,332;, + 3;333,327,326;, + 3;329,328,334;, + 3;335,329,334;, + 3;330,329,335;, + 3;336,330,335;, + 3;337,330,336;, + 3;337,331,330;, + 3;338,331,337;, + 3;338,332,331;, + 3;339,332,338;, + 3;339,333,332;, + 3;335,334,340;, + 3;341,335,340;, + 3;336,335,341;, + 3;342,336,341;, + 3;343,336,342;, + 3;343,337,336;, + 3;344,337,343;, + 3;344,338,337;, + 3;345,338,344;, + 3;345,339,338;, + 3;341,340,346;, + 3;347,341,346;, + 3;342,341,347;, + 3;348,342,347;, + 3;349,342,348;, + 3;349,343,342;, + 3;350,343,349;, + 3;350,344,343;, + 3;351,344,350;, + 3;351,345,344;, + 3;347,346,352;, + 3;353,347,352;, + 3;348,347,353;, + 3;354,348,353;, + 3;355,348,354;, + 3;355,349,348;, + 3;356,349,355;, + 3;356,350,349;, + 3;357,350,356;, + 3;357,351,350;, + 3;353,352,358;, + 3;359,353,358;, + 3;354,353,359;, + 3;360,354,359;, + 3;361,354,360;, + 3;361,355,354;, + 3;362,355,361;, + 3;362,356,355;, + 3;363,356,362;, + 3;363,357,356;, + 3;359,358,364;, + 3;365,359,364;, + 3;360,359,365;, + 3;366,360,365;, + 3;367,360,366;, + 3;367,361,360;, + 3;368,361,367;, + 3;368,362,361;, + 3;369,362,368;, + 3;369,363,362;, + 3;365,364,370;, + 3;371,365,370;, + 3;366,365,371;, + 3;372,366,371;, + 3;373,366,372;, + 3;373,367,366;, + 3;374,367,373;, + 3;374,368,367;, + 3;375,368,374;, + 3;375,369,368;, + 3;371,370,376;, + 3;377,371,376;, + 3;372,371,377;, + 3;378,372,377;, + 3;379,372,378;, + 3;379,373,372;, + 3;380,373,379;, + 3;380,374,373;, + 3;381,374,380;, + 3;381,375,374;, + 3;377,376,382;, + 3;383,377,382;, + 3;378,377,383;, + 3;384,378,383;, + 3;385,378,384;, + 3;385,379,378;, + 3;386,379,385;, + 3;386,380,379;, + 3;387,380,386;, + 3;387,381,380;, + 3;383,382,388;, + 3;389,383,388;, + 3;384,383,389;, + 3;390,384,389;, + 3;391,384,390;, + 3;391,385,384;, + 3;392,385,391;, + 3;392,386,385;, + 3;393,386,392;, + 3;393,387,386;, + 3;389,388,394;, + 3;395,389,394;, + 3;390,389,395;, + 3;396,390,395;, + 3;397,390,396;, + 3;397,391,390;, + 3;398,391,397;, + 3;398,392,391;, + 3;399,392,398;, + 3;399,393,392;, + 3;395,394,400;, + 3;401,395,400;, + 3;396,395,401;, + 3;402,396,401;, + 3;403,396,402;, + 3;403,397,396;, + 3;404,397,403;, + 3;404,398,397;, + 3;405,398,404;, + 3;405,399,398;, + 3;401,400,406;, + 3;407,401,406;, + 3;402,401,407;, + 3;408,402,407;, + 3;409,402,408;, + 3;409,403,402;, + 3;410,403,409;, + 3;410,404,403;, + 3;411,404,410;, + 3;411,405,404;, + 3;407,406,412;, + 3;413,407,412;, + 3;408,407,413;, + 3;414,408,413;, + 3;415,408,414;, + 3;415,409,408;, + 3;416,409,415;, + 3;416,410,409;, + 3;417,410,416;, + 3;417,411,410;, + 3;413,412,418;, + 3;419,413,418;, + 3;414,413,419;, + 3;420,414,419;, + 3;420,415,414;, + 3;420,416,415;, + 3;420,417,416;, + 3;420,421,417;, + 3;421,411,417;, + 3;421,422,411;, + 3;422,405,411;, + 3;419,418,423;, + 3;420,419,423;, + 3;422,424,405;, + 3;425,424,422;, + 3;425,426,424;, + 3;426,427,424;, + 3;424,427,399;, + 3;424,399,405;, + 3;428,425,422;, + 3;429,425,428;, + 3;429,430,425;, + 3;430,426,425;, + 3;430,431,426;, + 3;431,432,426;, + 3;426,432,427;, + 3;428,422,421;, + 3;420,428,421;, + 3;420,429,428;, + 3;420,433,429;, + 3;433,430,429;, + 3;433,434,430;, + 3;434,431,430;, + 3;434,435,431;, + 3;435,436,431;, + 3;431,436,432;, + 3;436,437,432;, + 3;432,437,438;, + 3;432,438,427;, + 3;420,439,433;, + 3;439,434,433;, + 3;439,440,434;, + 3;440,435,434;, + 3;440,441,435;, + 3;441,442,435;, + 3;435,442,436;, + 3;442,443,436;, + 3;436,443,437;, + 3;420,444,439;, + 3;444,440,439;, + 3;444,445,440;, + 3;445,441,440;, + 3;445,446,441;, + 3;446,447,441;, + 3;441,447,442;, + 3;447,448,442;, + 3;442,448,443;, + 3;420,449,444;, + 3;449,445,444;, + 3;449,450,445;, + 3;450,446,445;, + 3;450,451,446;, + 3;451,452,446;, + 3;446,452,447;, + 3;452,453,447;, + 3;447,453,448;, + 3;420,454,449;, + 3;454,450,449;, + 3;454,455,450;, + 3;455,451,450;, + 3;455,456,451;, + 3;456,457,451;, + 3;451,457,452;, + 3;457,458,452;, + 3;452,458,453;, + 3;420,459,454;, + 3;459,455,454;, + 3;459,460,455;, + 3;460,456,455;, + 3;460,461,456;, + 3;461,462,456;, + 3;456,462,457;, + 3;462,463,457;, + 3;457,463,458;, + 3;420,464,459;, + 3;464,460,459;, + 3;464,465,460;, + 3;465,461,460;, + 3;465,466,461;, + 3;466,467,461;, + 3;461,467,462;, + 3;467,468,462;, + 3;462,468,463;, + 3;420,469,464;, + 3;469,465,464;, + 3;469,470,465;, + 3;470,466,465;, + 3;470,471,466;, + 3;471,472,466;, + 3;466,472,467;, + 3;472,473,467;, + 3;467,473,468;, + 3;420,474,469;, + 3;474,470,469;, + 3;474,475,470;, + 3;475,471,470;, + 3;475,476,471;, + 3;476,477,471;, + 3;471,477,472;, + 3;477,478,472;, + 3;472,478,473;, + 3;420,479,474;, + 3;479,475,474;, + 3;479,480,475;, + 3;480,476,475;, + 3;480,481,476;, + 3;481,482,476;, + 3;476,482,477;, + 3;482,483,477;, + 3;477,483,478;, + 3;420,484,479;, + 3;484,480,479;, + 3;484,485,480;, + 3;485,481,480;, + 3;485,486,481;, + 3;486,487,481;, + 3;481,487,482;, + 3;487,488,482;, + 3;482,488,483;, + 3;420,489,484;, + 3;489,485,484;, + 3;489,490,485;, + 3;490,486,485;, + 3;490,491,486;, + 3;491,492,486;, + 3;486,492,487;, + 3;492,493,487;, + 3;487,493,488;, + 3;420,494,489;, + 3;494,490,489;, + 3;494,495,490;, + 3;495,491,490;, + 3;495,496,491;, + 3;496,497,491;, + 3;491,497,492;, + 3;497,498,492;, + 3;492,498,493;, + 3;420,499,494;, + 3;499,495,494;, + 3;499,500,495;, + 3;500,496,495;, + 3;500,501,496;, + 3;501,502,496;, + 3;496,502,497;, + 3;502,503,497;, + 3;497,503,498;, + 3;420,504,499;, + 3;504,500,499;, + 3;504,505,500;, + 3;505,501,500;, + 3;505,506,501;, + 3;506,507,501;, + 3;501,507,502;, + 3;507,508,502;, + 3;502,508,503;, + 3;420,509,504;, + 3;509,505,504;, + 3;509,510,505;, + 3;510,506,505;, + 3;510,511,506;, + 3;511,512,506;, + 3;506,512,507;, + 3;512,513,507;, + 3;507,513,508;, + 3;513,514,508;, + 3;508,514,515;, + 3;508,515,503;, + 3;509,516,510;, + 3;510,516,517;, + 3;510,517,511;, + 3;511,517,518;, + 3;511,518,519;, + 3;511,519,512;, + 3;519,520,512;, + 3;512,520,513;, + 3;520,521,513;, + 3;513,521,514;, + 3;509,522,516;, + 3;522,523,516;, + 3;516,523,524;, + 3;516,524,517;, + 3;517,524,525;, + 3;517,525,518;, + 3;518,525,526;, + 3;518,526,527;, + 3;519,518,527;, + 3;528,522,509;, + 3;528,529,522;, + 3;522,529,523;, + 3;529,530,523;, + 3;523,530,531;, + 3;523,531,524;, + 3;524,531,532;, + 3;524,532,525;, + 3;525,532,533;, + 3;525,533,526;, + 3;528,534,529;, + 3;529,534,530;, + 3;534,535,530;, + 3;530,535,536;, + 3;530,536,531;, + 3;531,536,537;, + 3;531,537,532;, + 3;532,537,538;, + 3;532,538,533;, + 3;528,539,534;, + 3;534,539,535;, + 3;539,540,535;, + 3;535,540,541;, + 3;535,541,536;, + 3;536,541,542;, + 3;536,542,537;, + 3;537,542,543;, + 3;537,543,538;, + 3;528,544,539;, + 3;539,544,540;, + 3;544,545,540;, + 3;540,545,546;, + 3;540,546,541;, + 3;541,546,547;, + 3;541,547,542;, + 3;542,547,548;, + 3;542,548,543;, + 3;528,549,544;, + 3;544,549,545;, + 3;549,550,545;, + 3;545,550,551;, + 3;545,551,546;, + 3;546,551,552;, + 3;546,552,547;, + 3;547,552,553;, + 3;547,553,548;, + 3;528,554,549;, + 3;549,554,550;, + 3;554,555,550;, + 3;550,555,556;, + 3;550,556,551;, + 3;551,556,557;, + 3;551,557,552;, + 3;552,557,558;, + 3;552,558,553;, + 3;528,559,554;, + 3;554,559,555;, + 3;559,560,555;, + 3;555,560,561;, + 3;555,561,556;, + 3;556,561,562;, + 3;556,562,557;, + 3;557,562,563;, + 3;557,563,558;, + 3;528,564,559;, + 3;559,564,560;, + 3;564,565,560;, + 3;560,565,566;, + 3;560,566,561;, + 3;561,566,567;, + 3;561,567,562;, + 3;562,567,568;, + 3;562,568,563;, + 3;528,569,564;, + 3;564,569,565;, + 3;569,570,565;, + 3;565,570,571;, + 3;565,571,566;, + 3;566,571,572;, + 3;566,572,567;, + 3;567,572,573;, + 3;567,573,568;, + 3;528,574,569;, + 3;569,574,570;, + 3;574,575,570;, + 3;570,575,576;, + 3;570,576,571;, + 3;571,576,577;, + 3;571,577,572;, + 3;572,577,578;, + 3;572,578,573;, + 3;528,579,574;, + 3;574,579,575;, + 3;579,580,575;, + 3;575,580,581;, + 3;575,581,576;, + 3;576,581,582;, + 3;576,582,577;, + 3;577,582,583;, + 3;577,583,578;, + 3;528,584,579;, + 3;579,584,580;, + 3;584,585,580;, + 3;580,585,586;, + 3;580,586,581;, + 3;581,586,587;, + 3;581,587,582;, + 3;582,587,588;, + 3;582,588,583;, + 3;528,589,584;, + 3;584,589,585;, + 3;589,590,585;, + 3;585,590,591;, + 3;585,591,586;, + 3;586,591,592;, + 3;586,592,587;, + 3;587,592,593;, + 3;587,593,588;, + 3;528,594,589;, + 3;589,594,590;, + 3;594,595,590;, + 3;590,595,596;, + 3;590,596,591;, + 3;591,596,597;, + 3;591,597,592;, + 3;592,597,598;, + 3;592,598,593;, + 3;528,599,594;, + 3;594,599,595;, + 3;599,600,595;, + 3;595,600,601;, + 3;595,601,596;, + 3;596,601,602;, + 3;596,602,597;, + 3;597,602,603;, + 3;597,603,598;, + 3;528,604,599;, + 3;599,604,600;, + 3;604,605,600;, + 3;600,605,606;, + 3;600,606,601;, + 3;601,606,607;, + 3;601,607,602;, + 3;602,607,608;, + 3;602,608,603;, + 3;528,609,604;, + 3;604,609,605;, + 3;609,610,605;, + 3;605,610,611;, + 3;605,611,606;, + 3;606,611,612;, + 3;606,612,607;, + 3;607,612,613;, + 3;607,613,608;, + 3;528,614,609;, + 3;609,614,610;, + 3;614,615,610;, + 3;610,615,616;, + 3;610,616,611;, + 3;611,616,617;, + 3;611,617,612;, + 3;612,617,618;, + 3;612,618,613;, + 3;528,619,614;, + 3;614,619,615;, + 3;619,620,615;, + 3;615,620,621;, + 3;615,621,616;, + 3;616,621,622;, + 3;616,622,617;, + 3;617,622,623;, + 3;617,623,618;, + 3;528,624,619;, + 3;619,624,620;, + 3;624,625,620;, + 3;620,625,626;, + 3;620,626,621;, + 3;621,626,627;, + 3;621,627,622;, + 3;622,627,628;, + 3;622,628,623;, + 3;528,629,624;, + 3;624,629,625;, + 3;629,630,625;, + 3;625,630,631;, + 3;625,631,626;, + 3;626,631,632;, + 3;626,632,627;, + 3;627,632,633;, + 3;627,633,628;, + 3;528,634,629;, + 3;629,634,630;, + 3;634,635,630;, + 3;630,635,636;, + 3;630,636,631;, + 3;631,636,637;, + 3;631,637,632;, + 3;632,637,638;, + 3;632,638,633;, + 3;528,639,634;, + 3;634,639,635;, + 3;633,638,640;, + 3;633,640,641;, + 3;628,633,641;, + 3;628,641,642;, + 3;623,628,642;, + 3;623,642,643;, + 3;618,623,643;, + 3;641,640,644;, + 3;641,644,645;, + 3;642,641,645;, + 3;642,645,646;, + 3;643,642,646;, + 3;643,646,647;, + 3;648,643,647;, + 3;618,643,648;, + 3;613,618,648;, + 3;613,648,649;, + 3;608,613,649;, + 3;645,644,650;, + 3;645,650,651;, + 3;646,645,651;, + 3;646,651,652;, + 3;647,646,652;, + 3;647,652,653;, + 3;654,647,653;, + 3;648,647,654;, + 3;649,648,654;, + 3;649,654,655;, + 3;656,649,655;, + 3;608,649,656;, + 3;603,608,656;, + 3;651,650,657;, + 3;651,657,658;, + 3;652,651,658;, + 3;652,658,659;, + 3;653,652,659;, + 3;653,659,660;, + 3;661,653,660;, + 3;654,653,661;, + 3;655,654,661;, + 3;655,661,662;, + 3;663,655,662;, + 3;656,655,663;, + 3;658,657,664;, + 3;658,664,665;, + 3;659,658,665;, + 3;659,665,666;, + 3;660,659,666;, + 3;660,666,667;, + 3;668,660,667;, + 3;661,660,668;, + 3;662,661,668;, + 3;662,668,669;, + 3;670,662,669;, + 3;663,662,670;, + 3;665,664,671;, + 3;665,671,672;, + 3;666,665,672;, + 3;666,672,673;, + 3;667,666,673;, + 3;667,673,674;, + 3;675,667,674;, + 3;668,667,675;, + 3;669,668,675;, + 3;669,675,676;, + 3;677,669,676;, + 3;670,669,677;, + 3;672,671,678;, + 3;672,678,679;, + 3;673,672,679;, + 3;673,679,680;, + 3;674,673,680;, + 3;674,680,681;, + 3;682,674,681;, + 3;675,674,682;, + 3;676,675,682;, + 3;676,682,683;, + 3;684,676,683;, + 3;677,676,684;, + 3;679,678,685;, + 3;679,685,686;, + 3;680,679,686;, + 3;680,686,687;, + 3;681,680,687;, + 3;681,687,688;, + 3;689,681,688;, + 3;682,681,689;, + 3;683,682,689;, + 3;683,689,690;, + 3;691,683,690;, + 3;684,683,691;, + 3;686,685,692;, + 3;686,692,693;, + 3;687,686,693;, + 3;687,693,694;, + 3;688,687,694;, + 3;688,694,695;, + 3;696,688,695;, + 3;689,688,696;, + 3;690,689,696;, + 3;690,696,697;, + 3;698,690,697;, + 3;691,690,698;, + 3;693,692,699;, + 3;693,699,700;, + 3;694,693,700;, + 3;694,700,701;, + 3;695,694,701;, + 3;695,701,702;, + 3;703,695,702;, + 3;696,695,703;, + 3;697,696,703;, + 3;697,703,704;, + 3;705,697,704;, + 3;698,697,705;, + 3;700,699,706;, + 3;700,706,707;, + 3;701,700,707;, + 3;701,707,708;, + 3;702,701,708;, + 3;702,708,709;, + 3;710,702,709;, + 3;703,702,710;, + 3;704,703,710;, + 3;704,710,711;, + 3;712,704,711;, + 3;705,704,712;, + 3;707,706,713;, + 3;707,713,714;, + 3;708,707,714;, + 3;708,714,715;, + 3;709,708,715;, + 3;709,715,716;, + 3;717,709,716;, + 3;710,709,717;, + 3;711,710,717;, + 3;711,717,718;, + 3;719,711,718;, + 3;712,711,719;, + 3;714,713,720;, + 3;714,720,721;, + 3;715,714,721;, + 3;715,721,722;, + 3;716,715,722;, + 3;716,722,723;, + 3;724,716,723;, + 3;717,716,724;, + 3;718,717,724;, + 3;718,724,725;, + 3;726,718,725;, + 3;719,718,726;, + 3;721,720,727;, + 3;721,727,728;, + 3;722,721,728;, + 3;722,728,729;, + 3;723,722,729;, + 3;723,729,730;, + 3;731,723,730;, + 3;724,723,731;, + 3;725,724,731;, + 3;725,731,732;, + 3;733,725,732;, + 3;726,725,733;, + 3;728,727,734;, + 3;728,734,735;, + 3;729,728,735;, + 3;729,735,736;, + 3;730,729,736;, + 3;730,736,737;, + 3;738,730,737;, + 3;731,730,738;, + 3;732,731,738;, + 3;732,738,739;, + 3;740,732,739;, + 3;733,732,740;, + 3;735,734,741;, + 3;735,741,742;, + 3;736,735,742;, + 3;736,742,743;, + 3;737,736,743;, + 3;737,743,744;, + 3;745,737,744;, + 3;738,737,745;, + 3;739,738,745;, + 3;739,745,746;, + 3;747,739,746;, + 3;740,739,747;, + 3;742,741,748;, + 3;742,748,749;, + 3;743,742,749;, + 3;743,749,750;, + 3;744,743,750;, + 3;744,750,751;, + 3;752,744,751;, + 3;745,744,752;, + 3;746,745,752;, + 3;746,752,753;, + 3;754,746,753;, + 3;747,746,754;, + 3;749,748,755;, + 3;749,755,756;, + 3;750,749,756;, + 3;750,756,757;, + 3;751,750,757;, + 3;751,757,758;, + 3;759,751,758;, + 3;752,751,759;, + 3;753,752,759;, + 3;753,759,760;, + 3;761,753,760;, + 3;754,753,761;, + 3;756,755,762;, + 3;756,762,763;, + 3;757,756,763;, + 3;757,763,764;, + 3;758,757,764;, + 3;758,764,765;, + 3;766,758,765;, + 3;759,758,766;, + 3;760,759,766;, + 3;760,766,767;, + 3;768,760,767;, + 3;761,760,768;, + 3;763,762,769;, + 3;763,769,770;, + 3;764,763,770;, + 3;764,770,771;, + 3;765,764,771;, + 3;765,771,772;, + 3;773,765,772;, + 3;766,765,773;, + 3;767,766,773;, + 3;767,773,774;, + 3;775,767,774;, + 3;768,767,775;, + 3;770,769,776;, + 3;770,776,777;, + 3;771,770,777;, + 3;771,777,778;, + 3;772,771,778;, + 3;772,778,779;, + 3;780,772,779;, + 3;773,772,780;, + 3;774,773,780;, + 3;774,780,781;, + 3;782,774,781;, + 3;775,774,782;, + 3;777,776,783;, + 3;777,783,784;, + 3;778,777,784;, + 3;778,784,785;, + 3;779,778,785;, + 3;779,785,786;, + 3;787,779,786;, + 3;780,779,787;, + 3;781,780,787;, + 3;781,787,788;, + 3;789,781,788;, + 3;782,781,789;, + 3;784,783,790;, + 3;784,790,791;, + 3;785,784,791;, + 3;785,791,792;, + 3;786,785,792;, + 3;786,792,793;, + 3;794,786,793;, + 3;787,786,794;, + 3;788,787,794;, + 3;788,794,795;, + 3;796,788,795;, + 3;789,788,796;, + 3;791,790,797;, + 3;791,797,798;, + 3;792,791,798;, + 3;792,798,799;, + 3;793,792,799;, + 3;793,799,800;, + 3;801,793,800;, + 3;794,793,801;, + 3;795,794,801;, + 3;795,801,802;, + 3;803,795,802;, + 3;796,795,803;, + 3;798,797,804;, + 3;798,804,805;, + 3;799,798,805;, + 3;799,805,806;, + 3;800,799,806;, + 3;800,806,807;, + 3;808,800,807;, + 3;801,800,808;, + 3;802,801,808;, + 3;802,808,809;, + 3;810,802,809;, + 3;803,802,810;, + 3;805,804,811;, + 3;805,811,812;, + 3;806,805,812;, + 3;806,812,813;, + 3;807,806,813;, + 3;807,813,814;, + 3;815,807,814;, + 3;808,807,815;, + 3;809,808,815;, + 3;809,815,816;, + 3;817,809,816;, + 3;810,809,817;, + 3;812,811,818;, + 3;812,818,819;, + 3;813,812,819;, + 3;813,819,820;, + 3;814,813,820;, + 3;814,820,821;, + 3;822,814,821;, + 3;815,814,822;, + 3;816,815,822;, + 3;816,822,823;, + 3;824,816,823;, + 3;817,816,824;, + 3;819,818,825;, + 3;819,825,826;, + 3;820,819,826;, + 3;820,826,827;, + 3;821,820,827;, + 3;821,827,828;, + 3;829,821,828;, + 3;822,821,829;, + 3;823,822,829;, + 3;823,829,830;, + 3;831,823,830;, + 3;824,823,831;, + 3;826,825,832;, + 3;826,832,833;, + 3;827,826,833;, + 3;827,833,834;, + 3;828,827,834;, + 3;828,834,835;, + 3;836,828,835;, + 3;829,828,836;, + 3;830,829,836;, + 3;830,836,837;, + 3;838,830,837;, + 3;831,830,838;, + 3;833,832,839;, + 3;833,839,840;, + 3;834,833,840;, + 3;834,840,841;, + 3;835,834,841;, + 3;835,841,842;, + 3;843,835,842;, + 3;836,835,843;, + 3;837,836,843;, + 3;837,843,844;, + 3;845,837,844;, + 3;838,837,845;, + 3;840,839,846;, + 3;840,846,847;, + 3;841,840,847;, + 3;841,847,848;, + 3;842,841,848;, + 3;842,848,849;, + 3;850,842,849;, + 3;843,842,850;, + 3;844,843,850;, + 3;844,850,851;, + 3;852,844,851;, + 3;845,844,852;, + 3;847,846,853;, + 3;847,853,854;, + 3;848,847,854;, + 3;848,854,855;, + 3;849,848,855;, + 3;849,855,856;, + 3;857,849,856;, + 3;850,849,857;, + 3;851,850,857;, + 3;851,857,858;, + 3;859,851,858;, + 3;852,851,859;, + 3;854,853,860;, + 3;854,860,861;, + 3;855,854,861;, + 3;855,861,862;, + 3;856,855,862;, + 3;856,862,863;, + 3;864,856,863;, + 3;857,856,864;, + 3;858,857,864;, + 3;858,864,865;, + 3;866,858,865;, + 3;859,858,866;, + 3;861,860,867;, + 3;861,867,868;, + 3;862,861,868;, + 3;862,868,869;, + 3;863,862,869;, + 3;863,869,870;, + 3;871,863,870;, + 3;864,863,871;, + 3;865,864,871;, + 3;865,871,872;, + 3;873,865,872;, + 3;866,865,873;, + 3;868,867,874;, + 3;868,874,875;, + 3;869,868,875;, + 3;869,875,876;, + 3;870,869,876;, + 3;870,876,877;, + 3;878,870,877;, + 3;871,870,878;, + 3;872,871,878;, + 3;872,878,879;, + 3;880,872,879;, + 3;873,872,880;, + 3;875,874,881;, + 3;875,881,882;, + 3;876,875,882;, + 3;876,882,883;, + 3;877,876,883;, + 3;877,883,884;, + 3;885,877,884;, + 3;878,877,885;, + 3;879,878,885;, + 3;879,885,886;, + 3;887,879,886;, + 3;880,879,887;, + 3;882,881,888;, + 3;882,888,889;, + 3;883,882,889;, + 3;883,889,890;, + 3;884,883,890;, + 3;884,890,891;, + 3;892,884,891;, + 3;885,884,892;, + 3;886,885,892;, + 3;886,892,893;, + 3;894,886,893;, + 3;887,886,894;, + 3;889,888,895;, + 3;889,895,896;, + 3;890,889,896;, + 3;890,896,897;, + 3;891,890,897;, + 3;891,897,898;, + 3;899,891,898;, + 3;892,891,899;, + 3;893,892,899;, + 3;893,899,900;, + 3;901,893,900;, + 3;894,893,901;, + 3;896,895,902;, + 3;896,902,903;, + 3;897,896,903;, + 3;897,903,904;, + 3;898,897,904;, + 3;898,904,905;, + 3;906,898,905;, + 3;899,898,906;, + 3;900,899,906;, + 3;900,906,907;, + 3;908,900,907;, + 3;901,900,908;, + 3;903,902,909;, + 3;903,909,910;, + 3;904,903,910;, + 3;904,910,911;, + 3;905,904,911;, + 3;905,911,912;, + 3;913,905,912;, + 3;906,905,913;, + 3;907,906,913;, + 3;907,913,914;, + 3;915,907,914;, + 3;908,907,915;, + 3;910,909,916;, + 3;910,916,917;, + 3;911,910,917;, + 3;911,917,918;, + 3;912,911,918;, + 3;912,918,919;, + 3;920,912,919;, + 3;913,912,920;, + 3;914,913,920;, + 3;914,920,921;, + 3;922,914,921;, + 3;915,914,922;, + 3;917,916,923;, + 3;917,923,924;, + 3;918,917,924;, + 3;918,924,925;, + 3;919,918,925;, + 3;919,925,926;, + 3;927,919,926;, + 3;920,919,927;, + 3;921,920,927;, + 3;921,927,928;, + 3;929,921,928;, + 3;922,921,929;, + 3;924,923,6;, + 3;925,924,6;, + 3;926,925,6;, + 3;930,926,6;, + 3;927,926,930;, + 3;928,927,930;, + 3;928,930,931;, + 3;932,928,931;, + 3;929,928,932;, + 3;933,929,932;, + 3;934,929,933;, + 3;934,922,929;, + 3;931,930,6;, + 3;935,931,6;, + 3;932,931,935;, + 3;936,932,935;, + 3;933,932,936;, + 3;937,933,936;, + 3;938,933,937;, + 3;938,934,933;, + 3;939,934,938;, + 3;939,940,934;, + 3;940,922,934;, + 3;940,915,922;, + 3;941,935,6;, + 3;936,935,941;, + 3;942,936,941;, + 3;937,936,942;, + 3;943,937,942;, + 3;944,937,943;, + 3;944,938,937;, + 3;945,938,944;, + 3;945,939,938;, + 3;946,941,6;, + 3;942,941,946;, + 3;947,942,946;, + 3;943,942,947;, + 3;948,943,947;, + 3;949,943,948;, + 3;949,944,943;, + 3;950,944,949;, + 3;950,945,944;, + 3;951,946,6;, + 3;947,946,951;, + 3;952,947,951;, + 3;948,947,952;, + 3;953,948,952;, + 3;954,948,953;, + 3;954,949,948;, + 3;955,949,954;, + 3;955,950,949;, + 3;956,951,6;, + 3;952,951,956;, + 3;957,952,956;, + 3;953,952,957;, + 3;958,953,957;, + 3;959,953,958;, + 3;959,954,953;, + 3;960,954,959;, + 3;960,955,954;, + 3;961,956,6;, + 3;957,956,961;, + 3;962,957,961;, + 3;958,957,962;, + 3;963,958,962;, + 3;964,958,963;, + 3;964,959,958;, + 3;965,959,964;, + 3;965,960,959;, + 3;966,961,6;, + 3;962,961,966;, + 3;967,962,966;, + 3;963,962,967;, + 3;968,963,967;, + 3;969,963,968;, + 3;969,964,963;, + 3;970,964,969;, + 3;970,965,964;, + 3;971,966,6;, + 3;967,966,971;, + 3;972,967,971;, + 3;968,967,972;, + 3;973,968,972;, + 3;974,968,973;, + 3;974,969,968;, + 3;975,969,974;, + 3;975,970,969;, + 3;976,971,6;, + 3;972,971,976;, + 3;977,972,976;, + 3;973,972,977;, + 3;978,973,977;, + 3;979,973,978;, + 3;979,974,973;, + 3;980,974,979;, + 3;980,975,974;, + 3;981,976,6;, + 3;977,976,981;, + 3;982,977,981;, + 3;978,977,982;, + 3;983,978,982;, + 3;984,978,983;, + 3;984,979,978;, + 3;985,979,984;, + 3;985,980,979;, + 3;986,981,6;, + 3;982,981,986;, + 3;987,982,986;, + 3;983,982,987;, + 3;988,983,987;, + 3;989,983,988;, + 3;989,984,983;, + 3;990,984,989;, + 3;990,985,984;, + 3;991,986,6;, + 3;987,986,991;, + 3;12,987,991;, + 3;988,987,12;, + 3;11,988,12;, + 3;992,988,11;, + 3;992,989,988;, + 3;993,989,992;, + 3;993,990,989;, + 3;5,991,6;, + 3;12,991,5;, + 3;18,992,11;, + 3;994,992,18;, + 3;994,993,992;, + 3;995,993,994;, + 3;995,996,993;, + 3;996,990,993;, + 3;996,997,990;, + 3;997,985,990;, + 3;998,994,18;, + 3;999,994,998;, + 3;999,995,994;, + 3;1000,995,999;, + 3;1000,1001,995;, + 3;1001,996,995;, + 3;1001,1002,996;, + 3;1002,997,996;, + 3;998,18,17;, + 3;24,998,17;, + 3;1003,998,24;, + 3;1003,999,998;, + 3;1004,999,1003;, + 3;1004,1000,999;, + 3;1005,1000,1004;, + 3;1005,1006,1000;, + 3;1006,1001,1000;, + 3;1006,1007,1001;, + 3;1007,1002,1001;, + 3;1008,1003,24;, + 3;1009,1003,1008;, + 3;1009,1004,1003;, + 3;1010,1004,1009;, + 3;1010,1005,1004;, + 3;1011,1005,1010;, + 3;1011,1012,1005;, + 3;1012,1006,1005;, + 3;1012,1013,1006;, + 3;1013,1007,1006;, + 3;1008,24,23;, + 3;35,1008,23;, + 3;1014,1008,35;, + 3;1014,1009,1008;, + 3;1015,1009,1014;, + 3;1015,1010,1009;, + 3;1016,1010,1015;, + 3;1016,1011,1010;, + 3;1017,1011,1016;, + 3;1017,1018,1011;, + 3;1018,1012,1011;, + 3;1018,1019,1012;, + 3;1019,1013,1012;, + 3;1014,35,41;, + 3;1014,41,1020;, + 3;1015,1014,1020;, + 3;1015,1020,1021;, + 3;1016,1015,1021;, + 3;1016,1021,1022;, + 3;1017,1016,1022;, + 3;1017,1022,1023;, + 3;1024,1017,1023;, + 3;1024,1018,1017;, + 3;1024,1025,1018;, + 3;1025,1019,1018;, + 3;1020,41,47;, + 3;1020,47,1026;, + 3;1021,1020,1026;, + 3;1021,1026,1027;, + 3;1022,1021,1027;, + 3;1022,1027,1028;, + 3;1023,1022,1028;, + 3;1023,1028,1029;, + 3;1030,1023,1029;, + 3;1024,1023,1030;, + 3;1031,1024,1030;, + 3;1031,1025,1024;, + 3;1026,47,53;, + 3;1026,53,1032;, + 3;1027,1026,1032;, + 3;1027,1032,1033;, + 3;1028,1027,1033;, + 3;1028,1033,1034;, + 3;1029,1028,1034;, + 3;1029,1034,1035;, + 3;1036,1029,1035;, + 3;1030,1029,1036;, + 3;1037,1030,1036;, + 3;1031,1030,1037;, + 3;1032,53,59;, + 3;1032,59,1038;, + 3;1033,1032,1038;, + 3;1033,1038,1039;, + 3;1034,1033,1039;, + 3;1034,1039,1040;, + 3;1035,1034,1040;, + 3;1035,1040,1041;, + 3;1042,1035,1041;, + 3;1036,1035,1042;, + 3;1043,1036,1042;, + 3;1037,1036,1043;, + 3;1038,59,65;, + 3;1038,65,1044;, + 3;1039,1038,1044;, + 3;1039,1044,1045;, + 3;1040,1039,1045;, + 3;1040,1045,1046;, + 3;1041,1040,1046;, + 3;1041,1046,1047;, + 3;1048,1041,1047;, + 3;1042,1041,1048;, + 3;1049,1042,1048;, + 3;1043,1042,1049;, + 3;1044,65,71;, + 3;1044,71,1050;, + 3;1045,1044,1050;, + 3;1045,1050,1051;, + 3;1046,1045,1051;, + 3;1046,1051,1052;, + 3;1047,1046,1052;, + 3;1047,1052,1053;, + 3;1054,1047,1053;, + 3;1048,1047,1054;, + 3;1055,1048,1054;, + 3;1049,1048,1055;, + 3;1050,71,77;, + 3;1050,77,1056;, + 3;1051,1050,1056;, + 3;1051,1056,1057;, + 3;1052,1051,1057;, + 3;1052,1057,1058;, + 3;1053,1052,1058;, + 3;1053,1058,1059;, + 3;1060,1053,1059;, + 3;1054,1053,1060;, + 3;1061,1054,1060;, + 3;1055,1054,1061;, + 3;1056,77,83;, + 3;1056,83,1062;, + 3;1057,1056,1062;, + 3;1057,1062,1063;, + 3;1058,1057,1063;, + 3;1058,1063,1064;, + 3;1059,1058,1064;, + 3;1059,1064,1065;, + 3;1066,1059,1065;, + 3;1060,1059,1066;, + 3;1067,1060,1066;, + 3;1061,1060,1067;, + 3;1062,83,89;, + 3;1062,89,1068;, + 3;1063,1062,1068;, + 3;1063,1068,1069;, + 3;1064,1063,1069;, + 3;1064,1069,1070;, + 3;1065,1064,1070;, + 3;1065,1070,1071;, + 3;1072,1065,1071;, + 3;1066,1065,1072;, + 3;1073,1066,1072;, + 3;1067,1066,1073;, + 3;1068,89,95;, + 3;1068,95,1074;, + 3;1069,1068,1074;, + 3;1069,1074,1075;, + 3;1070,1069,1075;, + 3;1070,1075,1076;, + 3;1071,1070,1076;, + 3;1071,1076,1077;, + 3;1078,1071,1077;, + 3;1072,1071,1078;, + 3;1079,1072,1078;, + 3;1073,1072,1079;, + 3;1074,95,101;, + 3;1074,101,1080;, + 3;1075,1074,1080;, + 3;1075,1080,1081;, + 3;1076,1075,1081;, + 3;1076,1081,1082;, + 3;1077,1076,1082;, + 3;1077,1082,1083;, + 3;1084,1077,1083;, + 3;1078,1077,1084;, + 3;1085,1078,1084;, + 3;1079,1078,1085;, + 3;1080,101,107;, + 3;1080,107,1086;, + 3;1081,1080,1086;, + 3;1081,1086,1087;, + 3;1082,1081,1087;, + 3;1082,1087,1088;, + 3;1083,1082,1088;, + 3;1083,1088,1089;, + 3;1090,1083,1089;, + 3;1084,1083,1090;, + 3;1091,1084,1090;, + 3;1085,1084,1091;, + 3;1086,107,113;, + 3;1086,113,1092;, + 3;1087,1086,1092;, + 3;1087,1092,1093;, + 3;1088,1087,1093;, + 3;1088,1093,1094;, + 3;1089,1088,1094;, + 3;1089,1094,1095;, + 3;1096,1089,1095;, + 3;1090,1089,1096;, + 3;1097,1090,1096;, + 3;1091,1090,1097;, + 3;1092,113,119;, + 3;1092,119,1098;, + 3;1093,1092,1098;, + 3;1093,1098,1099;, + 3;1094,1093,1099;, + 3;1094,1099,1100;, + 3;1095,1094,1100;, + 3;1095,1100,1101;, + 3;1102,1095,1101;, + 3;1096,1095,1102;, + 3;1103,1096,1102;, + 3;1097,1096,1103;, + 3;1098,119,125;, + 3;1098,125,1104;, + 3;1099,1098,1104;, + 3;1099,1104,1105;, + 3;1100,1099,1105;, + 3;1100,1105,1106;, + 3;1101,1100,1106;, + 3;1101,1106,1107;, + 3;1108,1101,1107;, + 3;1102,1101,1108;, + 3;1109,1102,1108;, + 3;1103,1102,1109;, + 3;1104,125,131;, + 3;1104,131,1110;, + 3;1105,1104,1110;, + 3;1105,1110,1111;, + 3;1106,1105,1111;, + 3;1106,1111,1112;, + 3;1107,1106,1112;, + 3;1107,1112,1113;, + 3;1114,1107,1113;, + 3;1108,1107,1114;, + 3;1115,1108,1114;, + 3;1109,1108,1115;, + 3;1110,131,137;, + 3;1110,137,1116;, + 3;1111,1110,1116;, + 3;1111,1116,1117;, + 3;1112,1111,1117;, + 3;1112,1117,1118;, + 3;1113,1112,1118;, + 3;1113,1118,1119;, + 3;1120,1113,1119;, + 3;1114,1113,1120;, + 3;1121,1114,1120;, + 3;1115,1114,1121;, + 3;1116,137,143;, + 3;1116,143,1122;, + 3;1117,1116,1122;, + 3;1117,1122,1123;, + 3;1118,1117,1123;, + 3;1118,1123,1124;, + 3;1119,1118,1124;, + 3;1119,1124,1125;, + 3;1126,1119,1125;, + 3;1120,1119,1126;, + 3;1127,1120,1126;, + 3;1121,1120,1127;, + 3;1122,143,149;, + 3;1122,149,183;, + 3;1123,1122,183;, + 3;1123,183,182;, + 3;1124,1123,182;, + 3;1124,182,189;, + 3;1125,1124,189;, + 3;1125,189,195;, + 3;1128,1125,195;, + 3;1126,1125,1128;, + 3;1129,1126,1128;, + 3;1127,1126,1129;, + 3;1130,1127,1129;, + 3;1131,1127,1130;, + 3;1131,1121,1127;, + 3;1132,1121,1131;, + 3;1132,1115,1121;, + 3;1128,195,201;, + 3;1133,1128,201;, + 3;1129,1128,1133;, + 3;1134,1129,1133;, + 3;1130,1129,1134;, + 3;1135,1130,1134;, + 3;1136,1130,1135;, + 3;1136,1131,1130;, + 3;1137,1131,1136;, + 3;1137,1132,1131;, + 3;1133,201,207;, + 3;1138,1133,207;, + 3;1134,1133,1138;, + 3;1139,1134,1138;, + 3;1135,1134,1139;, + 3;1140,1135,1139;, + 3;1141,1135,1140;, + 3;1141,1136,1135;, + 3;1142,1136,1141;, + 3;1142,1137,1136;, + 3;1138,207,213;, + 3;1143,1138,213;, + 3;1139,1138,1143;, + 3;1144,1139,1143;, + 3;1140,1139,1144;, + 3;1145,1140,1144;, + 3;1146,1140,1145;, + 3;1146,1141,1140;, + 3;1147,1141,1146;, + 3;1147,1142,1141;, + 3;1143,213,219;, + 3;1148,1143,219;, + 3;1144,1143,1148;, + 3;1149,1144,1148;, + 3;1145,1144,1149;, + 3;1150,1145,1149;, + 3;1151,1145,1150;, + 3;1151,1146,1145;, + 3;1152,1146,1151;, + 3;1152,1147,1146;, + 3;1148,219,225;, + 3;1153,1148,225;, + 3;1149,1148,1153;, + 3;1154,1149,1153;, + 3;1150,1149,1154;, + 3;1155,1150,1154;, + 3;1156,1150,1155;, + 3;1156,1151,1150;, + 3;1157,1151,1156;, + 3;1157,1152,1151;, + 3;1153,225,231;, + 3;1158,1153,231;, + 3;1154,1153,1158;, + 3;1159,1154,1158;, + 3;1155,1154,1159;, + 3;1160,1155,1159;, + 3;1161,1155,1160;, + 3;1161,1156,1155;, + 3;1162,1156,1161;, + 3;1162,1157,1156;, + 3;1158,231,237;, + 3;1163,1158,237;, + 3;1159,1158,1163;, + 3;1164,1159,1163;, + 3;1160,1159,1164;, + 3;1165,1160,1164;, + 3;1166,1160,1165;, + 3;1166,1161,1160;, + 3;1167,1161,1166;, + 3;1167,1162,1161;, + 3;1163,237,243;, + 3;1168,1163,243;, + 3;1164,1163,1168;, + 3;1169,1164,1168;, + 3;1165,1164,1169;, + 3;1170,1165,1169;, + 3;1171,1165,1170;, + 3;1171,1166,1165;, + 3;1172,1166,1171;, + 3;1172,1167,1166;, + 3;1168,243,249;, + 3;1173,1168,249;, + 3;1169,1168,1173;, + 3;1174,1169,1173;, + 3;1170,1169,1174;, + 3;1175,1170,1174;, + 3;1176,1170,1175;, + 3;1176,1171,1170;, + 3;1177,1171,1176;, + 3;1177,1172,1171;, + 3;1173,249,255;, + 3;1178,1173,255;, + 3;1174,1173,1178;, + 3;1179,1174,1178;, + 3;1175,1174,1179;, + 3;1180,1175,1179;, + 3;1181,1175,1180;, + 3;1181,1176,1175;, + 3;1182,1176,1181;, + 3;1182,1177,1176;, + 3;1178,255,261;, + 3;1183,1178,261;, + 3;1179,1178,1183;, + 3;1184,1179,1183;, + 3;1180,1179,1184;, + 3;1185,1180,1184;, + 3;1186,1180,1185;, + 3;1186,1181,1180;, + 3;1187,1181,1186;, + 3;1187,1182,1181;, + 3;1183,261,267;, + 3;1188,1183,267;, + 3;1184,1183,1188;, + 3;1189,1184,1188;, + 3;1185,1184,1189;, + 3;1190,1185,1189;, + 3;1191,1185,1190;, + 3;1191,1186,1185;, + 3;1192,1186,1191;, + 3;1192,1187,1186;, + 3;1188,267,273;, + 3;1193,1188,273;, + 3;1189,1188,1193;, + 3;1194,1189,1193;, + 3;1190,1189,1194;, + 3;1195,1190,1194;, + 3;1196,1190,1195;, + 3;1196,1191,1190;, + 3;1197,1191,1196;, + 3;1197,1192,1191;, + 3;1193,273,279;, + 3;1198,1193,279;, + 3;1194,1193,1198;, + 3;1199,1194,1198;, + 3;1195,1194,1199;, + 3;1200,1195,1199;, + 3;1201,1195,1200;, + 3;1201,1196,1195;, + 3;1202,1196,1201;, + 3;1202,1197,1196;, + 3;1198,279,285;, + 3;1203,1198,285;, + 3;1199,1198,1203;, + 3;1204,1199,1203;, + 3;1200,1199,1204;, + 3;1205,1200,1204;, + 3;1206,1200,1205;, + 3;1206,1201,1200;, + 3;1207,1201,1206;, + 3;1207,1202,1201;, + 3;1203,285,291;, + 3;1208,1203,291;, + 3;1204,1203,1208;, + 3;1209,1204,1208;, + 3;1205,1204,1209;, + 3;1210,1205,1209;, + 3;1211,1205,1210;, + 3;1211,1206,1205;, + 3;1212,1206,1211;, + 3;1212,1207,1206;, + 3;1208,291,297;, + 3;1213,1208,297;, + 3;1209,1208,1213;, + 3;1214,1209,1213;, + 3;1210,1209,1214;, + 3;1215,1210,1214;, + 3;1216,1210,1215;, + 3;1216,1211,1210;, + 3;1217,1211,1216;, + 3;1217,1212,1211;, + 3;1213,297,303;, + 3;1218,1213,303;, + 3;1214,1213,1218;, + 3;1219,1214,1218;, + 3;1215,1214,1219;, + 3;1220,1215,1219;, + 3;1221,1215,1220;, + 3;1221,1216,1215;, + 3;1222,1216,1221;, + 3;1222,1217,1216;, + 3;1218,303,309;, + 3;1223,1218,309;, + 3;1219,1218,1223;, + 3;1224,1219,1223;, + 3;1220,1219,1224;, + 3;1225,1220,1224;, + 3;1226,1220,1225;, + 3;1226,1221,1220;, + 3;1227,1221,1226;, + 3;1227,1222,1221;, + 3;1223,309,315;, + 3;1228,1223,315;, + 3;1224,1223,1228;, + 3;1229,1224,1228;, + 3;1225,1224,1229;, + 3;1230,1225,1229;, + 3;1231,1225,1230;, + 3;1231,1226,1225;, + 3;1232,1226,1231;, + 3;1232,1227,1226;, + 3;1228,315,321;, + 3;1233,1228,321;, + 3;1229,1228,1233;, + 3;1234,1229,1233;, + 3;1230,1229,1234;, + 3;1235,1230,1234;, + 3;1236,1230,1235;, + 3;1236,1231,1230;, + 3;1237,1231,1236;, + 3;1237,1232,1231;, + 3;1233,321,327;, + 3;1238,1233,327;, + 3;1234,1233,1238;, + 3;1239,1234,1238;, + 3;1235,1234,1239;, + 3;1240,1235,1239;, + 3;1241,1235,1240;, + 3;1241,1236,1235;, + 3;1242,1236,1241;, + 3;1242,1237,1236;, + 3;1238,327,333;, + 3;1243,1238,333;, + 3;1239,1238,1243;, + 3;1244,1239,1243;, + 3;1240,1239,1244;, + 3;1245,1240,1244;, + 3;1246,1240,1245;, + 3;1246,1241,1240;, + 3;1247,1241,1246;, + 3;1247,1242,1241;, + 3;1243,333,339;, + 3;1248,1243,339;, + 3;1244,1243,1248;, + 3;1249,1244,1248;, + 3;1245,1244,1249;, + 3;1250,1245,1249;, + 3;1251,1245,1250;, + 3;1251,1246,1245;, + 3;1252,1246,1251;, + 3;1252,1247,1246;, + 3;1248,339,345;, + 3;1253,1248,345;, + 3;1249,1248,1253;, + 3;1254,1249,1253;, + 3;1250,1249,1254;, + 3;1255,1250,1254;, + 3;1256,1250,1255;, + 3;1256,1251,1250;, + 3;1257,1251,1256;, + 3;1257,1252,1251;, + 3;1253,345,351;, + 3;1258,1253,351;, + 3;1254,1253,1258;, + 3;1259,1254,1258;, + 3;1255,1254,1259;, + 3;1260,1255,1259;, + 3;1261,1255,1260;, + 3;1261,1256,1255;, + 3;1262,1256,1261;, + 3;1262,1257,1256;, + 3;1258,351,357;, + 3;1263,1258,357;, + 3;1259,1258,1263;, + 3;1264,1259,1263;, + 3;1260,1259,1264;, + 3;1265,1260,1264;, + 3;1266,1260,1265;, + 3;1266,1261,1260;, + 3;1267,1261,1266;, + 3;1267,1262,1261;, + 3;1263,357,363;, + 3;1268,1263,363;, + 3;1264,1263,1268;, + 3;1269,1264,1268;, + 3;1265,1264,1269;, + 3;1270,1265,1269;, + 3;1271,1265,1270;, + 3;1271,1266,1265;, + 3;1272,1266,1271;, + 3;1272,1267,1266;, + 3;1268,363,369;, + 3;1273,1268,369;, + 3;1269,1268,1273;, + 3;1274,1269,1273;, + 3;1270,1269,1274;, + 3;1275,1270,1274;, + 3;1276,1270,1275;, + 3;1276,1271,1270;, + 3;1277,1271,1276;, + 3;1277,1272,1271;, + 3;1273,369,375;, + 3;1278,1273,375;, + 3;1274,1273,1278;, + 3;1279,1274,1278;, + 3;1275,1274,1279;, + 3;443,1275,1279;, + 3;448,1275,443;, + 3;448,1276,1275;, + 3;453,1276,448;, + 3;453,1277,1276;, + 3;1278,375,381;, + 3;1280,1278,381;, + 3;1279,1278,1280;, + 3;437,1279,1280;, + 3;443,1279,437;, + 3;1280,381,387;, + 3;438,1280,387;, + 3;437,1280,438;, + 3;438,387,393;, + 3;427,438,393;, + 3;427,393,399;, + 3;458,1277,453;, + 3;458,1281,1277;, + 3;1281,1272,1277;, + 3;1281,1282,1272;, + 3;1282,1267,1272;, + 3;1282,1283,1267;, + 3;1283,1262,1267;, + 3;463,1281,458;, + 3;463,1284,1281;, + 3;1284,1282,1281;, + 3;1284,1285,1282;, + 3;1285,1283,1282;, + 3;1285,1286,1283;, + 3;1286,1287,1283;, + 3;1283,1287,1262;, + 3;1287,1257,1262;, + 3;1287,1288,1257;, + 3;1288,1252,1257;, + 3;468,1284,463;, + 3;468,1289,1284;, + 3;1289,1285,1284;, + 3;1289,1290,1285;, + 3;1290,1286,1285;, + 3;1290,1291,1286;, + 3;1291,1292,1286;, + 3;1286,1292,1287;, + 3;1292,1288,1287;, + 3;1292,1293,1288;, + 3;1293,1294,1288;, + 3;1288,1294,1252;, + 3;1294,1247,1252;, + 3;473,1289,468;, + 3;473,1295,1289;, + 3;1295,1290,1289;, + 3;1295,1296,1290;, + 3;1296,1291,1290;, + 3;1296,1297,1291;, + 3;1297,1298,1291;, + 3;1291,1298,1292;, + 3;1298,1293,1292;, + 3;1298,1299,1293;, + 3;1299,1300,1293;, + 3;1293,1300,1294;, + 3;478,1295,473;, + 3;478,1301,1295;, + 3;1301,1296,1295;, + 3;1301,1302,1296;, + 3;1302,1297,1296;, + 3;1302,1303,1297;, + 3;1303,1304,1297;, + 3;1297,1304,1298;, + 3;1304,1299,1298;, + 3;1304,1305,1299;, + 3;1305,1306,1299;, + 3;1299,1306,1300;, + 3;483,1301,478;, + 3;483,1307,1301;, + 3;1307,1302,1301;, + 3;1307,1308,1302;, + 3;1308,1303,1302;, + 3;1308,1309,1303;, + 3;1309,1310,1303;, + 3;1303,1310,1304;, + 3;1310,1305,1304;, + 3;1310,1311,1305;, + 3;1311,1312,1305;, + 3;1305,1312,1306;, + 3;488,1307,483;, + 3;488,1313,1307;, + 3;1313,1308,1307;, + 3;1313,1314,1308;, + 3;1314,1309,1308;, + 3;1314,1315,1309;, + 3;1315,1316,1309;, + 3;1309,1316,1310;, + 3;1316,1311,1310;, + 3;1316,1317,1311;, + 3;1317,1318,1311;, + 3;1311,1318,1312;, + 3;493,1313,488;, + 3;493,1319,1313;, + 3;1319,1314,1313;, + 3;1319,1320,1314;, + 3;1320,1315,1314;, + 3;1320,1321,1315;, + 3;1321,1322,1315;, + 3;1315,1322,1316;, + 3;1322,1317,1316;, + 3;1322,1323,1317;, + 3;1323,1324,1317;, + 3;1317,1324,1318;, + 3;498,1319,493;, + 3;498,1325,1319;, + 3;1325,1320,1319;, + 3;1325,1326,1320;, + 3;1326,1321,1320;, + 3;1326,1327,1321;, + 3;1327,1328,1321;, + 3;1321,1328,1322;, + 3;1328,1323,1322;, + 3;1328,1329,1323;, + 3;1329,1330,1323;, + 3;1323,1330,1324;, + 3;503,1325,498;, + 3;503,515,1325;, + 3;515,1326,1325;, + 3;515,1331,1326;, + 3;1331,1327,1326;, + 3;1331,1332,1327;, + 3;1332,1333,1327;, + 3;1327,1333,1328;, + 3;1333,1329,1328;, + 3;1333,1334,1329;, + 3;1334,1335,1329;, + 3;1329,1335,1330;, + 3;514,1331,515;, + 3;514,1336,1331;, + 3;1336,1332,1331;, + 3;1336,1337,1332;, + 3;1337,1338,1332;, + 3;1332,1338,1333;, + 3;1338,1334,1333;, + 3;1338,1339,1334;, + 3;1339,1340,1334;, + 3;1334,1340,1335;, + 3;521,1336,514;, + 3;521,1341,1336;, + 3;1341,1337,1336;, + 3;1341,1342,1337;, + 3;1342,1343,1337;, + 3;1337,1343,1338;, + 3;1343,1339,1338;, + 3;1343,1344,1339;, + 3;1344,1345,1339;, + 3;1339,1345,1340;, + 3;1346,1341,521;, + 3;1346,1347,1341;, + 3;1347,1342,1341;, + 3;1347,1348,1342;, + 3;1348,1349,1342;, + 3;1342,1349,1343;, + 3;1349,1344,1343;, + 3;1349,1350,1344;, + 3;1350,1351,1344;, + 3;1344,1351,1345;, + 3;520,1346,521;, + 3;1352,1346,520;, + 3;1352,1353,1346;, + 3;1353,1347,1346;, + 3;1353,1354,1347;, + 3;1354,1348,1347;, + 3;1354,1355,1348;, + 3;1355,1356,1348;, + 3;1348,1356,1349;, + 3;1356,1350,1349;, + 3;519,1352,520;, + 3;519,527,1352;, + 3;1352,527,1357;, + 3;1352,1357,1353;, + 3;1353,1357,1358;, + 3;1353,1358,1354;, + 3;1354,1358,1359;, + 3;1354,1359,1355;, + 3;1355,1359,1360;, + 3;1355,1360,1361;, + 3;1355,1361,1356;, + 3;1361,1362,1356;, + 3;1356,1362,1350;, + 3;527,1363,1357;, + 3;1357,1363,1364;, + 3;1357,1364,1358;, + 3;1358,1364,1365;, + 3;1358,1365,1359;, + 3;1359,1365,1366;, + 3;1359,1366,1360;, + 3;1360,1366,1367;, + 3;1360,1367,1368;, + 3;1361,1360,1368;, + 3;527,526,1363;, + 3;526,1369,1363;, + 3;1363,1369,1370;, + 3;1363,1370,1364;, + 3;1364,1370,1371;, + 3;1364,1371,1365;, + 3;1365,1371,1372;, + 3;1365,1372,1366;, + 3;1366,1372,1373;, + 3;1366,1373,1367;, + 3;526,533,1369;, + 3;533,1374,1369;, + 3;1369,1374,1375;, + 3;1369,1375,1370;, + 3;1370,1375,1376;, + 3;1370,1376,1371;, + 3;1371,1376,1377;, + 3;1371,1377,1372;, + 3;1372,1377,1378;, + 3;1372,1378,1373;, + 3;533,538,1374;, + 3;538,1379,1374;, + 3;1374,1379,1380;, + 3;1374,1380,1375;, + 3;1375,1380,1381;, + 3;1375,1381,1376;, + 3;1376,1381,1382;, + 3;1376,1382,1377;, + 3;1377,1382,1383;, + 3;1377,1383,1378;, + 3;538,543,1379;, + 3;543,1384,1379;, + 3;1379,1384,1385;, + 3;1379,1385,1380;, + 3;1380,1385,1386;, + 3;1380,1386,1381;, + 3;1381,1386,1387;, + 3;1381,1387,1382;, + 3;1382,1387,1388;, + 3;1382,1388,1383;, + 3;543,548,1384;, + 3;548,1389,1384;, + 3;1384,1389,1390;, + 3;1384,1390,1385;, + 3;1385,1390,1391;, + 3;1385,1391,1386;, + 3;1386,1391,1392;, + 3;1386,1392,1387;, + 3;1387,1392,1393;, + 3;1387,1393,1388;, + 3;548,553,1389;, + 3;553,1394,1389;, + 3;1389,1394,1395;, + 3;1389,1395,1390;, + 3;1390,1395,1396;, + 3;1390,1396,1391;, + 3;1391,1396,1397;, + 3;1391,1397,1392;, + 3;1392,1397,1398;, + 3;1392,1398,1393;, + 3;553,558,1394;, + 3;558,1399,1394;, + 3;1394,1399,1400;, + 3;1394,1400,1395;, + 3;1395,1400,1401;, + 3;1395,1401,1396;, + 3;1396,1401,1402;, + 3;1396,1402,1397;, + 3;1397,1402,1403;, + 3;1397,1403,1398;, + 3;558,563,1399;, + 3;563,1404,1399;, + 3;1399,1404,1405;, + 3;1399,1405,1400;, + 3;1400,1405,1406;, + 3;1400,1406,1401;, + 3;1401,1406,1407;, + 3;1401,1407,1402;, + 3;1402,1407,1408;, + 3;1402,1408,1403;, + 3;563,568,1404;, + 3;568,1409,1404;, + 3;1404,1409,1410;, + 3;1404,1410,1405;, + 3;1405,1410,1411;, + 3;1405,1411,1406;, + 3;1406,1411,1412;, + 3;1406,1412,1407;, + 3;1407,1412,1413;, + 3;1407,1413,1408;, + 3;568,573,1409;, + 3;573,1414,1409;, + 3;1409,1414,1415;, + 3;1409,1415,1410;, + 3;1410,1415,1416;, + 3;1410,1416,1411;, + 3;1411,1416,1417;, + 3;1411,1417,1412;, + 3;1412,1417,1418;, + 3;1412,1418,1413;, + 3;573,578,1414;, + 3;578,1419,1414;, + 3;1414,1419,1420;, + 3;1414,1420,1415;, + 3;1415,1420,1421;, + 3;1415,1421,1416;, + 3;1416,1421,1422;, + 3;1416,1422,1417;, + 3;1417,1422,1423;, + 3;1417,1423,1418;, + 3;578,583,1419;, + 3;583,1424,1419;, + 3;1419,1424,1425;, + 3;1419,1425,1420;, + 3;1420,1425,1426;, + 3;1420,1426,1421;, + 3;1421,1426,1427;, + 3;1421,1427,1422;, + 3;1422,1427,1428;, + 3;1422,1428,1423;, + 3;583,588,1424;, + 3;588,1429,1424;, + 3;1424,1429,1430;, + 3;1424,1430,1425;, + 3;1425,1430,1431;, + 3;1425,1431,1426;, + 3;1426,1431,1432;, + 3;1426,1432,1427;, + 3;1427,1432,1433;, + 3;1427,1433,1428;, + 3;588,593,1429;, + 3;593,1434,1429;, + 3;1429,1434,1435;, + 3;1429,1435,1430;, + 3;1430,1435,1436;, + 3;1430,1436,1431;, + 3;1431,1436,1437;, + 3;1431,1437,1432;, + 3;1432,1437,1438;, + 3;1432,1438,1433;, + 3;593,598,1434;, + 3;598,1439,1434;, + 3;1434,1439,1440;, + 3;1434,1440,1435;, + 3;1435,1440,1441;, + 3;1435,1441,1436;, + 3;1436,1441,1442;, + 3;1436,1442,1437;, + 3;1437,1442,1443;, + 3;1437,1443,1438;, + 3;598,603,1439;, + 3;603,656,1439;, + 3;1439,656,663;, + 3;1439,663,1440;, + 3;1440,663,670;, + 3;1440,670,1441;, + 3;1441,670,677;, + 3;1441,677,1442;, + 3;1442,677,684;, + 3;1442,684,1443;, + 3;1443,684,691;, + 3;1443,691,1444;, + 3;1438,1443,1444;, + 3;1438,1444,1445;, + 3;1433,1438,1445;, + 3;1433,1445,1446;, + 3;1428,1433,1446;, + 3;1444,691,698;, + 3;1444,698,1447;, + 3;1445,1444,1447;, + 3;1445,1447,1448;, + 3;1446,1445,1448;, + 3;1446,1448,1449;, + 3;1450,1446,1449;, + 3;1428,1446,1450;, + 3;1423,1428,1450;, + 3;1423,1450,1451;, + 3;1418,1423,1451;, + 3;1447,698,705;, + 3;1447,705,1452;, + 3;1448,1447,1452;, + 3;1448,1452,1453;, + 3;1449,1448,1453;, + 3;1449,1453,1454;, + 3;1455,1449,1454;, + 3;1450,1449,1455;, + 3;1451,1450,1455;, + 3;1451,1455,1456;, + 3;1457,1451,1456;, + 3;1418,1451,1457;, + 3;1413,1418,1457;, + 3;1452,705,712;, + 3;1452,712,1458;, + 3;1453,1452,1458;, + 3;1453,1458,1459;, + 3;1454,1453,1459;, + 3;1454,1459,1460;, + 3;1461,1454,1460;, + 3;1455,1454,1461;, + 3;1456,1455,1461;, + 3;1456,1461,1462;, + 3;1463,1456,1462;, + 3;1457,1456,1463;, + 3;1458,712,719;, + 3;1458,719,1464;, + 3;1459,1458,1464;, + 3;1459,1464,1465;, + 3;1460,1459,1465;, + 3;1460,1465,1466;, + 3;1467,1460,1466;, + 3;1461,1460,1467;, + 3;1462,1461,1467;, + 3;1462,1467,1468;, + 3;1469,1462,1468;, + 3;1463,1462,1469;, + 3;1464,719,726;, + 3;1464,726,1470;, + 3;1465,1464,1470;, + 3;1465,1470,1471;, + 3;1466,1465,1471;, + 3;1466,1471,1472;, + 3;1473,1466,1472;, + 3;1467,1466,1473;, + 3;1468,1467,1473;, + 3;1468,1473,1474;, + 3;1475,1468,1474;, + 3;1469,1468,1475;, + 3;1470,726,733;, + 3;1470,733,1476;, + 3;1471,1470,1476;, + 3;1471,1476,1477;, + 3;1472,1471,1477;, + 3;1472,1477,1478;, + 3;1479,1472,1478;, + 3;1473,1472,1479;, + 3;1474,1473,1479;, + 3;1474,1479,1480;, + 3;1481,1474,1480;, + 3;1475,1474,1481;, + 3;1476,733,740;, + 3;1476,740,1482;, + 3;1477,1476,1482;, + 3;1477,1482,1483;, + 3;1478,1477,1483;, + 3;1478,1483,1484;, + 3;1485,1478,1484;, + 3;1479,1478,1485;, + 3;1480,1479,1485;, + 3;1480,1485,1486;, + 3;1487,1480,1486;, + 3;1481,1480,1487;, + 3;1482,740,747;, + 3;1482,747,1488;, + 3;1483,1482,1488;, + 3;1483,1488,1489;, + 3;1484,1483,1489;, + 3;1484,1489,1490;, + 3;1491,1484,1490;, + 3;1485,1484,1491;, + 3;1486,1485,1491;, + 3;1486,1491,1492;, + 3;1493,1486,1492;, + 3;1487,1486,1493;, + 3;1488,747,754;, + 3;1488,754,1494;, + 3;1489,1488,1494;, + 3;1489,1494,1495;, + 3;1490,1489,1495;, + 3;1490,1495,1496;, + 3;1497,1490,1496;, + 3;1491,1490,1497;, + 3;1492,1491,1497;, + 3;1492,1497,1498;, + 3;1499,1492,1498;, + 3;1493,1492,1499;, + 3;1494,754,761;, + 3;1494,761,1500;, + 3;1495,1494,1500;, + 3;1495,1500,1501;, + 3;1496,1495,1501;, + 3;1496,1501,1502;, + 3;1503,1496,1502;, + 3;1497,1496,1503;, + 3;1498,1497,1503;, + 3;1498,1503,1504;, + 3;1505,1498,1504;, + 3;1499,1498,1505;, + 3;1500,761,768;, + 3;1500,768,1506;, + 3;1501,1500,1506;, + 3;1501,1506,1507;, + 3;1502,1501,1507;, + 3;1502,1507,1508;, + 3;1509,1502,1508;, + 3;1503,1502,1509;, + 3;1504,1503,1509;, + 3;1504,1509,1510;, + 3;1511,1504,1510;, + 3;1505,1504,1511;, + 3;1506,768,775;, + 3;1506,775,1512;, + 3;1507,1506,1512;, + 3;1507,1512,1513;, + 3;1508,1507,1513;, + 3;1508,1513,1514;, + 3;1515,1508,1514;, + 3;1509,1508,1515;, + 3;1510,1509,1515;, + 3;1510,1515,1516;, + 3;1517,1510,1516;, + 3;1511,1510,1517;, + 3;1512,775,782;, + 3;1512,782,1518;, + 3;1513,1512,1518;, + 3;1513,1518,1519;, + 3;1514,1513,1519;, + 3;1514,1519,1520;, + 3;1521,1514,1520;, + 3;1515,1514,1521;, + 3;1516,1515,1521;, + 3;1516,1521,1522;, + 3;1523,1516,1522;, + 3;1517,1516,1523;, + 3;1518,782,789;, + 3;1518,789,1524;, + 3;1519,1518,1524;, + 3;1519,1524,1525;, + 3;1520,1519,1525;, + 3;1520,1525,1526;, + 3;1527,1520,1526;, + 3;1521,1520,1527;, + 3;1522,1521,1527;, + 3;1522,1527,1528;, + 3;1529,1522,1528;, + 3;1523,1522,1529;, + 3;1524,789,796;, + 3;1524,796,1530;, + 3;1525,1524,1530;, + 3;1525,1530,1531;, + 3;1526,1525,1531;, + 3;1526,1531,1532;, + 3;1533,1526,1532;, + 3;1527,1526,1533;, + 3;1528,1527,1533;, + 3;1528,1533,1534;, + 3;1535,1528,1534;, + 3;1529,1528,1535;, + 3;1530,796,803;, + 3;1530,803,1536;, + 3;1531,1530,1536;, + 3;1531,1536,1537;, + 3;1532,1531,1537;, + 3;1532,1537,1538;, + 3;1539,1532,1538;, + 3;1533,1532,1539;, + 3;1534,1533,1539;, + 3;1534,1539,1540;, + 3;1541,1534,1540;, + 3;1535,1534,1541;, + 3;1536,803,810;, + 3;1536,810,1542;, + 3;1537,1536,1542;, + 3;1537,1542,1543;, + 3;1538,1537,1543;, + 3;1538,1543,1544;, + 3;1545,1538,1544;, + 3;1539,1538,1545;, + 3;1540,1539,1545;, + 3;1540,1545,1546;, + 3;1547,1540,1546;, + 3;1541,1540,1547;, + 3;1542,810,817;, + 3;1542,817,1548;, + 3;1543,1542,1548;, + 3;1543,1548,1549;, + 3;1544,1543,1549;, + 3;1544,1549,1550;, + 3;1551,1544,1550;, + 3;1545,1544,1551;, + 3;1546,1545,1551;, + 3;1546,1551,1552;, + 3;1553,1546,1552;, + 3;1547,1546,1553;, + 3;1548,817,824;, + 3;1548,824,1554;, + 3;1549,1548,1554;, + 3;1549,1554,1555;, + 3;1550,1549,1555;, + 3;1550,1555,1556;, + 3;1557,1550,1556;, + 3;1551,1550,1557;, + 3;1552,1551,1557;, + 3;1552,1557,1558;, + 3;1559,1552,1558;, + 3;1553,1552,1559;, + 3;1554,824,831;, + 3;1554,831,1560;, + 3;1555,1554,1560;, + 3;1555,1560,1561;, + 3;1556,1555,1561;, + 3;1556,1561,1562;, + 3;1563,1556,1562;, + 3;1557,1556,1563;, + 3;1558,1557,1563;, + 3;1558,1563,1564;, + 3;1565,1558,1564;, + 3;1559,1558,1565;, + 3;1560,831,838;, + 3;1560,838,1566;, + 3;1561,1560,1566;, + 3;1561,1566,1567;, + 3;1562,1561,1567;, + 3;1562,1567,1568;, + 3;1569,1562,1568;, + 3;1563,1562,1569;, + 3;1564,1563,1569;, + 3;1564,1569,1570;, + 3;1571,1564,1570;, + 3;1565,1564,1571;, + 3;1566,838,845;, + 3;1566,845,1572;, + 3;1567,1566,1572;, + 3;1567,1572,1573;, + 3;1568,1567,1573;, + 3;1568,1573,1574;, + 3;1575,1568,1574;, + 3;1569,1568,1575;, + 3;1570,1569,1575;, + 3;1570,1575,1576;, + 3;1577,1570,1576;, + 3;1571,1570,1577;, + 3;1572,845,852;, + 3;1572,852,1578;, + 3;1573,1572,1578;, + 3;1573,1578,1579;, + 3;1574,1573,1579;, + 3;1574,1579,1580;, + 3;1581,1574,1580;, + 3;1575,1574,1581;, + 3;1576,1575,1581;, + 3;1576,1581,1582;, + 3;1583,1576,1582;, + 3;1577,1576,1583;, + 3;1578,852,859;, + 3;1578,859,1584;, + 3;1579,1578,1584;, + 3;1579,1584,1585;, + 3;1580,1579,1585;, + 3;1580,1585,1586;, + 3;1587,1580,1586;, + 3;1581,1580,1587;, + 3;1582,1581,1587;, + 3;1582,1587,1588;, + 3;1589,1582,1588;, + 3;1583,1582,1589;, + 3;1584,859,866;, + 3;1584,866,1590;, + 3;1585,1584,1590;, + 3;1585,1590,1591;, + 3;1586,1585,1591;, + 3;1586,1591,1592;, + 3;1593,1586,1592;, + 3;1587,1586,1593;, + 3;1588,1587,1593;, + 3;1588,1593,1594;, + 3;1595,1588,1594;, + 3;1589,1588,1595;, + 3;1590,866,873;, + 3;1590,873,1596;, + 3;1591,1590,1596;, + 3;1591,1596,1597;, + 3;1592,1591,1597;, + 3;1592,1597,1598;, + 3;1599,1592,1598;, + 3;1593,1592,1599;, + 3;1594,1593,1599;, + 3;1594,1599,1600;, + 3;1601,1594,1600;, + 3;1595,1594,1601;, + 3;1596,873,880;, + 3;1596,880,1602;, + 3;1597,1596,1602;, + 3;1597,1602,1603;, + 3;1598,1597,1603;, + 3;1598,1603,1604;, + 3;1605,1598,1604;, + 3;1599,1598,1605;, + 3;1600,1599,1605;, + 3;1600,1605,1606;, + 3;1607,1600,1606;, + 3;1601,1600,1607;, + 3;1602,880,887;, + 3;1602,887,1608;, + 3;1603,1602,1608;, + 3;1603,1608,1609;, + 3;1604,1603,1609;, + 3;1604,1609,1610;, + 3;1611,1604,1610;, + 3;1605,1604,1611;, + 3;1606,1605,1611;, + 3;1606,1611,1612;, + 3;1613,1606,1612;, + 3;1607,1606,1613;, + 3;1608,887,894;, + 3;1608,894,1614;, + 3;1609,1608,1614;, + 3;1609,1614,1615;, + 3;1610,1609,1615;, + 3;1610,1615,1616;, + 3;1617,1610,1616;, + 3;1611,1610,1617;, + 3;1612,1611,1617;, + 3;1612,1617,1618;, + 3;1619,1612,1618;, + 3;1613,1612,1619;, + 3;1614,894,901;, + 3;1614,901,1620;, + 3;1615,1614,1620;, + 3;1615,1620,1621;, + 3;1616,1615,1621;, + 3;1616,1621,1622;, + 3;1623,1616,1622;, + 3;1617,1616,1623;, + 3;1618,1617,1623;, + 3;1618,1623,1624;, + 3;1625,1618,1624;, + 3;1619,1618,1625;, + 3;1620,901,908;, + 3;1620,908,1626;, + 3;1621,1620,1626;, + 3;1621,1626,1627;, + 3;1622,1621,1627;, + 3;1622,1627,1628;, + 3;1629,1622,1628;, + 3;1623,1622,1629;, + 3;1624,1623,1629;, + 3;1624,1629,1630;, + 3;1631,1624,1630;, + 3;1625,1624,1631;, + 3;1626,908,915;, + 3;1626,915,940;, + 3;1627,1626,940;, + 3;1627,940,939;, + 3;1628,1627,939;, + 3;1628,939,945;, + 3;1632,1628,945;, + 3;1629,1628,1632;, + 3;1630,1629,1632;, + 3;1630,1632,1633;, + 3;1634,1630,1633;, + 3;1631,1630,1634;, + 3;1635,1631,1634;, + 3;1636,1631,1635;, + 3;1636,1625,1631;, + 3;1632,945,950;, + 3;1633,1632,950;, + 3;1633,950,955;, + 3;1637,1633,955;, + 3;1634,1633,1637;, + 3;1638,1634,1637;, + 3;1635,1634,1638;, + 3;1639,1635,1638;, + 3;1640,1635,1639;, + 3;1640,1636,1635;, + 3;1641,1636,1640;, + 3;1641,1642,1636;, + 3;1642,1625,1636;, + 3;1642,1619,1625;, + 3;1637,955,960;, + 3;1643,1637,960;, + 3;1638,1637,1643;, + 3;1644,1638,1643;, + 3;1639,1638,1644;, + 3;1645,1639,1644;, + 3;1646,1639,1645;, + 3;1646,1640,1639;, + 3;1647,1640,1646;, + 3;1647,1641,1640;, + 3;1643,960,965;, + 3;1648,1643,965;, + 3;1644,1643,1648;, + 3;1649,1644,1648;, + 3;1645,1644,1649;, + 3;1650,1645,1649;, + 3;1651,1645,1650;, + 3;1651,1646,1645;, + 3;1652,1646,1651;, + 3;1652,1647,1646;, + 3;1648,965,970;, + 3;1653,1648,970;, + 3;1649,1648,1653;, + 3;1654,1649,1653;, + 3;1650,1649,1654;, + 3;1655,1650,1654;, + 3;1656,1650,1655;, + 3;1656,1651,1650;, + 3;1657,1651,1656;, + 3;1657,1652,1651;, + 3;1653,970,975;, + 3;1658,1653,975;, + 3;1654,1653,1658;, + 3;1659,1654,1658;, + 3;1655,1654,1659;, + 3;1660,1655,1659;, + 3;1661,1655,1660;, + 3;1661,1656,1655;, + 3;1662,1656,1661;, + 3;1662,1657,1656;, + 3;1658,975,980;, + 3;1663,1658,980;, + 3;1659,1658,1663;, + 3;1664,1659,1663;, + 3;1660,1659,1664;, + 3;1665,1660,1664;, + 3;1666,1660,1665;, + 3;1666,1661,1660;, + 3;1667,1661,1666;, + 3;1667,1662,1661;, + 3;1663,980,985;, + 3;997,1663,985;, + 3;1664,1663,997;, + 3;1002,1664,997;, + 3;1665,1664,1002;, + 3;1007,1665,1002;, + 3;1668,1665,1007;, + 3;1668,1666,1665;, + 3;1669,1666,1668;, + 3;1669,1667,1666;, + 3;1670,1667,1669;, + 3;1670,1671,1667;, + 3;1671,1662,1667;, + 3;1671,1672,1662;, + 3;1672,1657,1662;, + 3;1013,1668,1007;, + 3;1673,1668,1013;, + 3;1673,1669,1668;, + 3;1674,1669,1673;, + 3;1674,1670,1669;, + 3;1675,1670,1674;, + 3;1675,1676,1670;, + 3;1676,1671,1670;, + 3;1676,1677,1671;, + 3;1677,1672,1671;, + 3;1019,1673,1013;, + 3;1678,1673,1019;, + 3;1678,1674,1673;, + 3;1679,1674,1678;, + 3;1679,1675,1674;, + 3;1680,1675,1679;, + 3;1680,1681,1675;, + 3;1681,1676,1675;, + 3;1681,1682,1676;, + 3;1682,1677,1676;, + 3;1025,1678,1019;, + 3;1683,1678,1025;, + 3;1683,1679,1678;, + 3;1684,1679,1683;, + 3;1684,1680,1679;, + 3;1685,1680,1684;, + 3;1685,1686,1680;, + 3;1686,1681,1680;, + 3;1686,1687,1681;, + 3;1687,1682,1681;, + 3;1031,1683,1025;, + 3;1688,1683,1031;, + 3;1688,1684,1683;, + 3;1689,1684,1688;, + 3;1689,1685,1684;, + 3;1690,1685,1689;, + 3;1690,1691,1685;, + 3;1691,1686,1685;, + 3;1691,1692,1686;, + 3;1692,1687,1686;, + 3;1688,1031,1037;, + 3;1688,1037,1693;, + 3;1689,1688,1693;, + 3;1689,1693,1694;, + 3;1690,1689,1694;, + 3;1690,1694,1695;, + 3;1696,1690,1695;, + 3;1696,1691,1690;, + 3;1696,1697,1691;, + 3;1697,1692,1691;, + 3;1693,1037,1043;, + 3;1693,1043,1698;, + 3;1694,1693,1698;, + 3;1694,1698,1699;, + 3;1695,1694,1699;, + 3;1695,1699,1700;, + 3;1701,1695,1700;, + 3;1696,1695,1701;, + 3;1702,1696,1701;, + 3;1702,1697,1696;, + 3;1698,1043,1049;, + 3;1698,1049,1703;, + 3;1699,1698,1703;, + 3;1699,1703,1704;, + 3;1700,1699,1704;, + 3;1700,1704,1705;, + 3;1706,1700,1705;, + 3;1701,1700,1706;, + 3;1707,1701,1706;, + 3;1702,1701,1707;, + 3;1703,1049,1055;, + 3;1703,1055,1708;, + 3;1704,1703,1708;, + 3;1704,1708,1709;, + 3;1705,1704,1709;, + 3;1705,1709,1710;, + 3;1711,1705,1710;, + 3;1706,1705,1711;, + 3;1712,1706,1711;, + 3;1707,1706,1712;, + 3;1708,1055,1061;, + 3;1708,1061,1713;, + 3;1709,1708,1713;, + 3;1709,1713,1714;, + 3;1710,1709,1714;, + 3;1710,1714,1715;, + 3;1716,1710,1715;, + 3;1711,1710,1716;, + 3;1717,1711,1716;, + 3;1712,1711,1717;, + 3;1713,1061,1067;, + 3;1713,1067,1718;, + 3;1714,1713,1718;, + 3;1714,1718,1719;, + 3;1715,1714,1719;, + 3;1715,1719,1720;, + 3;1721,1715,1720;, + 3;1716,1715,1721;, + 3;1722,1716,1721;, + 3;1717,1716,1722;, + 3;1718,1067,1073;, + 3;1718,1073,1723;, + 3;1719,1718,1723;, + 3;1719,1723,1724;, + 3;1720,1719,1724;, + 3;1720,1724,1725;, + 3;1726,1720,1725;, + 3;1721,1720,1726;, + 3;1727,1721,1726;, + 3;1722,1721,1727;, + 3;1723,1073,1079;, + 3;1723,1079,1728;, + 3;1724,1723,1728;, + 3;1724,1728,1729;, + 3;1725,1724,1729;, + 3;1725,1729,1730;, + 3;1731,1725,1730;, + 3;1726,1725,1731;, + 3;1732,1726,1731;, + 3;1727,1726,1732;, + 3;1728,1079,1085;, + 3;1728,1085,1733;, + 3;1729,1728,1733;, + 3;1729,1733,1734;, + 3;1730,1729,1734;, + 3;1730,1734,1735;, + 3;1736,1730,1735;, + 3;1731,1730,1736;, + 3;1737,1731,1736;, + 3;1732,1731,1737;, + 3;1733,1085,1091;, + 3;1733,1091,1738;, + 3;1734,1733,1738;, + 3;1734,1738,1739;, + 3;1735,1734,1739;, + 3;1735,1739,1740;, + 3;1741,1735,1740;, + 3;1736,1735,1741;, + 3;1742,1736,1741;, + 3;1737,1736,1742;, + 3;1738,1091,1097;, + 3;1738,1097,1743;, + 3;1739,1738,1743;, + 3;1739,1743,1744;, + 3;1740,1739,1744;, + 3;1740,1744,1745;, + 3;1746,1740,1745;, + 3;1741,1740,1746;, + 3;1747,1741,1746;, + 3;1742,1741,1747;, + 3;1743,1097,1103;, + 3;1743,1103,1748;, + 3;1744,1743,1748;, + 3;1744,1748,1749;, + 3;1745,1744,1749;, + 3;1745,1749,1750;, + 3;1751,1745,1750;, + 3;1746,1745,1751;, + 3;1752,1746,1751;, + 3;1747,1746,1752;, + 3;1748,1103,1109;, + 3;1748,1109,1753;, + 3;1749,1748,1753;, + 3;1749,1753,1754;, + 3;1750,1749,1754;, + 3;1750,1754,1755;, + 3;1756,1750,1755;, + 3;1751,1750,1756;, + 3;1757,1751,1756;, + 3;1752,1751,1757;, + 3;1753,1109,1115;, + 3;1753,1115,1132;, + 3;1754,1753,1132;, + 3;1754,1132,1137;, + 3;1755,1754,1137;, + 3;1755,1137,1142;, + 3;1758,1755,1142;, + 3;1756,1755,1758;, + 3;1759,1756,1758;, + 3;1757,1756,1759;, + 3;1760,1757,1759;, + 3;1761,1757,1760;, + 3;1761,1752,1757;, + 3;1762,1752,1761;, + 3;1762,1747,1752;, + 3;1758,1142,1147;, + 3;1763,1758,1147;, + 3;1759,1758,1763;, + 3;1764,1759,1763;, + 3;1760,1759,1764;, + 3;1765,1760,1764;, + 3;1766,1760,1765;, + 3;1766,1761,1760;, + 3;1767,1761,1766;, + 3;1767,1762,1761;, + 3;1763,1147,1152;, + 3;1768,1763,1152;, + 3;1764,1763,1768;, + 3;1769,1764,1768;, + 3;1765,1764,1769;, + 3;1770,1765,1769;, + 3;1771,1765,1770;, + 3;1771,1766,1765;, + 3;1772,1766,1771;, + 3;1772,1767,1766;, + 3;1768,1152,1157;, + 3;1773,1768,1157;, + 3;1769,1768,1773;, + 3;1774,1769,1773;, + 3;1770,1769,1774;, + 3;1775,1770,1774;, + 3;1776,1770,1775;, + 3;1776,1771,1770;, + 3;1777,1771,1776;, + 3;1777,1772,1771;, + 3;1773,1157,1162;, + 3;1778,1773,1162;, + 3;1774,1773,1778;, + 3;1779,1774,1778;, + 3;1775,1774,1779;, + 3;1780,1775,1779;, + 3;1781,1775,1780;, + 3;1781,1776,1775;, + 3;1782,1776,1781;, + 3;1782,1777,1776;, + 3;1778,1162,1167;, + 3;1783,1778,1167;, + 3;1779,1778,1783;, + 3;1784,1779,1783;, + 3;1780,1779,1784;, + 3;1785,1780,1784;, + 3;1786,1780,1785;, + 3;1786,1781,1780;, + 3;1787,1781,1786;, + 3;1787,1782,1781;, + 3;1783,1167,1172;, + 3;1788,1783,1172;, + 3;1784,1783,1788;, + 3;1789,1784,1788;, + 3;1785,1784,1789;, + 3;1790,1785,1789;, + 3;1791,1785,1790;, + 3;1791,1786,1785;, + 3;1792,1786,1791;, + 3;1792,1787,1786;, + 3;1788,1172,1177;, + 3;1793,1788,1177;, + 3;1789,1788,1793;, + 3;1794,1789,1793;, + 3;1790,1789,1794;, + 3;1795,1790,1794;, + 3;1796,1790,1795;, + 3;1796,1791,1790;, + 3;1797,1791,1796;, + 3;1797,1792,1791;, + 3;1793,1177,1182;, + 3;1798,1793,1182;, + 3;1794,1793,1798;, + 3;1799,1794,1798;, + 3;1795,1794,1799;, + 3;1800,1795,1799;, + 3;1801,1795,1800;, + 3;1801,1796,1795;, + 3;1802,1796,1801;, + 3;1802,1797,1796;, + 3;1798,1182,1187;, + 3;1803,1798,1187;, + 3;1799,1798,1803;, + 3;1804,1799,1803;, + 3;1800,1799,1804;, + 3;1805,1800,1804;, + 3;1806,1800,1805;, + 3;1806,1801,1800;, + 3;1807,1801,1806;, + 3;1807,1802,1801;, + 3;1803,1187,1192;, + 3;1808,1803,1192;, + 3;1804,1803,1808;, + 3;1809,1804,1808;, + 3;1805,1804,1809;, + 3;1810,1805,1809;, + 3;1811,1805,1810;, + 3;1811,1806,1805;, + 3;1812,1806,1811;, + 3;1812,1807,1806;, + 3;1808,1192,1197;, + 3;1813,1808,1197;, + 3;1809,1808,1813;, + 3;1814,1809,1813;, + 3;1810,1809,1814;, + 3;1815,1810,1814;, + 3;1816,1810,1815;, + 3;1816,1811,1810;, + 3;1817,1811,1816;, + 3;1817,1812,1811;, + 3;1813,1197,1202;, + 3;1818,1813,1202;, + 3;1814,1813,1818;, + 3;1819,1814,1818;, + 3;1815,1814,1819;, + 3;1820,1815,1819;, + 3;1821,1815,1820;, + 3;1821,1816,1815;, + 3;1822,1816,1821;, + 3;1822,1817,1816;, + 3;1818,1202,1207;, + 3;1823,1818,1207;, + 3;1819,1818,1823;, + 3;1824,1819,1823;, + 3;1820,1819,1824;, + 3;1825,1820,1824;, + 3;1826,1820,1825;, + 3;1826,1821,1820;, + 3;1827,1821,1826;, + 3;1827,1822,1821;, + 3;1823,1207,1212;, + 3;1828,1823,1212;, + 3;1824,1823,1828;, + 3;1829,1824,1828;, + 3;1825,1824,1829;, + 3;1830,1825,1829;, + 3;1831,1825,1830;, + 3;1831,1826,1825;, + 3;1832,1826,1831;, + 3;1832,1827,1826;, + 3;1828,1212,1217;, + 3;1833,1828,1217;, + 3;1829,1828,1833;, + 3;1834,1829,1833;, + 3;1830,1829,1834;, + 3;1835,1830,1834;, + 3;1836,1830,1835;, + 3;1836,1831,1830;, + 3;1837,1831,1836;, + 3;1837,1832,1831;, + 3;1833,1217,1222;, + 3;1838,1833,1222;, + 3;1834,1833,1838;, + 3;1839,1834,1838;, + 3;1835,1834,1839;, + 3;1840,1835,1839;, + 3;1841,1835,1840;, + 3;1841,1836,1835;, + 3;1842,1836,1841;, + 3;1842,1837,1836;, + 3;1838,1222,1227;, + 3;1843,1838,1227;, + 3;1839,1838,1843;, + 3;1844,1839,1843;, + 3;1840,1839,1844;, + 3;1845,1840,1844;, + 3;1846,1840,1845;, + 3;1846,1841,1840;, + 3;1847,1841,1846;, + 3;1847,1842,1841;, + 3;1843,1227,1232;, + 3;1848,1843,1232;, + 3;1844,1843,1848;, + 3;1849,1844,1848;, + 3;1845,1844,1849;, + 3;1850,1845,1849;, + 3;1851,1845,1850;, + 3;1851,1846,1845;, + 3;1852,1846,1851;, + 3;1852,1847,1846;, + 3;1848,1232,1237;, + 3;1853,1848,1237;, + 3;1849,1848,1853;, + 3;1854,1849,1853;, + 3;1850,1849,1854;, + 3;1306,1850,1854;, + 3;1312,1850,1306;, + 3;1312,1851,1850;, + 3;1318,1851,1312;, + 3;1318,1852,1851;, + 3;1853,1237,1242;, + 3;1855,1853,1242;, + 3;1854,1853,1855;, + 3;1300,1854,1855;, + 3;1306,1854,1300;, + 3;1855,1242,1247;, + 3;1294,1855,1247;, + 3;1300,1855,1294;, + 3;1324,1852,1318;, + 3;1324,1856,1852;, + 3;1856,1847,1852;, + 3;1856,1857,1847;, + 3;1857,1842,1847;, + 3;1857,1858,1842;, + 3;1858,1837,1842;, + 3;1330,1856,1324;, + 3;1330,1859,1856;, + 3;1859,1857,1856;, + 3;1859,1860,1857;, + 3;1860,1858,1857;, + 3;1860,1861,1858;, + 3;1861,1862,1858;, + 3;1858,1862,1837;, + 3;1862,1832,1837;, + 3;1862,1863,1832;, + 3;1863,1827,1832;, + 3;1335,1859,1330;, + 3;1335,1864,1859;, + 3;1864,1860,1859;, + 3;1864,1865,1860;, + 3;1865,1861,1860;, + 3;1865,1866,1861;, + 3;1866,1867,1861;, + 3;1861,1867,1862;, + 3;1867,1863,1862;, + 3;1867,1868,1863;, + 3;1868,1869,1863;, + 3;1863,1869,1827;, + 3;1869,1822,1827;, + 3;1340,1864,1335;, + 3;1340,1870,1864;, + 3;1870,1865,1864;, + 3;1870,1871,1865;, + 3;1871,1866,1865;, + 3;1871,1872,1866;, + 3;1872,1873,1866;, + 3;1866,1873,1867;, + 3;1873,1868,1867;, + 3;1873,1874,1868;, + 3;1874,1875,1868;, + 3;1868,1875,1869;, + 3;1345,1870,1340;, + 3;1345,1876,1870;, + 3;1876,1871,1870;, + 3;1876,1877,1871;, + 3;1877,1872,1871;, + 3;1877,1878,1872;, + 3;1878,1879,1872;, + 3;1872,1879,1873;, + 3;1879,1874,1873;, + 3;1879,1880,1874;, + 3;1880,1881,1874;, + 3;1874,1881,1875;, + 3;1351,1876,1345;, + 3;1351,1882,1876;, + 3;1882,1877,1876;, + 3;1882,1883,1877;, + 3;1883,1878,1877;, + 3;1883,1884,1878;, + 3;1884,1885,1878;, + 3;1878,1885,1879;, + 3;1885,1880,1879;, + 3;1885,1886,1880;, + 3;1886,1887,1880;, + 3;1880,1887,1881;, + 3;1888,1882,1351;, + 3;1888,1889,1882;, + 3;1889,1883,1882;, + 3;1889,1890,1883;, + 3;1890,1884,1883;, + 3;1890,1891,1884;, + 3;1891,1892,1884;, + 3;1884,1892,1885;, + 3;1892,1886,1885;, + 3;1350,1888,1351;, + 3;1362,1888,1350;, + 3;1362,1893,1888;, + 3;1893,1889,1888;, + 3;1893,1894,1889;, + 3;1894,1890,1889;, + 3;1894,1895,1890;, + 3;1895,1891,1890;, + 3;1895,1896,1891;, + 3;1896,1897,1891;, + 3;1891,1897,1892;, + 3;1897,1898,1892;, + 3;1892,1898,1886;, + 3;1899,1893,1362;, + 3;1899,1900,1893;, + 3;1900,1894,1893;, + 3;1900,1901,1894;, + 3;1901,1895,1894;, + 3;1901,1902,1895;, + 3;1902,1896,1895;, + 3;1902,1903,1896;, + 3;1903,1904,1896;, + 3;1896,1904,1897;, + 3;1361,1899,1362;, + 3;1361,1368,1899;, + 3;1899,1368,1905;, + 3;1899,1905,1900;, + 3;1900,1905,1906;, + 3;1900,1906,1901;, + 3;1901,1906,1907;, + 3;1901,1907,1902;, + 3;1902,1907,1908;, + 3;1902,1908,1903;, + 3;1903,1908,1909;, + 3;1903,1909,1910;, + 3;1903,1910,1904;, + 3;1368,1911,1905;, + 3;1905,1911,1912;, + 3;1905,1912,1906;, + 3;1906,1912,1913;, + 3;1906,1913,1907;, + 3;1907,1913,1914;, + 3;1907,1914,1908;, + 3;1908,1914,1915;, + 3;1908,1915,1909;, + 3;1368,1367,1911;, + 3;1367,1916,1911;, + 3;1911,1916,1917;, + 3;1911,1917,1912;, + 3;1912,1917,1918;, + 3;1912,1918,1913;, + 3;1913,1918,1919;, + 3;1913,1919,1914;, + 3;1914,1919,1920;, + 3;1914,1920,1915;, + 3;1367,1373,1916;, + 3;1373,1921,1916;, + 3;1916,1921,1922;, + 3;1916,1922,1917;, + 3;1917,1922,1923;, + 3;1917,1923,1918;, + 3;1918,1923,1924;, + 3;1918,1924,1919;, + 3;1919,1924,1925;, + 3;1919,1925,1920;, + 3;1373,1378,1921;, + 3;1378,1926,1921;, + 3;1921,1926,1927;, + 3;1921,1927,1922;, + 3;1922,1927,1928;, + 3;1922,1928,1923;, + 3;1923,1928,1929;, + 3;1923,1929,1924;, + 3;1924,1929,1930;, + 3;1924,1930,1925;, + 3;1378,1383,1926;, + 3;1383,1931,1926;, + 3;1926,1931,1932;, + 3;1926,1932,1927;, + 3;1927,1932,1933;, + 3;1927,1933,1928;, + 3;1928,1933,1934;, + 3;1928,1934,1929;, + 3;1929,1934,1935;, + 3;1929,1935,1930;, + 3;1383,1388,1931;, + 3;1388,1936,1931;, + 3;1931,1936,1937;, + 3;1931,1937,1932;, + 3;1932,1937,1938;, + 3;1932,1938,1933;, + 3;1933,1938,1939;, + 3;1933,1939,1934;, + 3;1934,1939,1940;, + 3;1934,1940,1935;, + 3;1388,1393,1936;, + 3;1393,1941,1936;, + 3;1936,1941,1942;, + 3;1936,1942,1937;, + 3;1937,1942,1943;, + 3;1937,1943,1938;, + 3;1938,1943,1944;, + 3;1938,1944,1939;, + 3;1939,1944,1945;, + 3;1939,1945,1940;, + 3;1393,1398,1941;, + 3;1398,1946,1941;, + 3;1941,1946,1947;, + 3;1941,1947,1942;, + 3;1942,1947,1948;, + 3;1942,1948,1943;, + 3;1943,1948,1949;, + 3;1943,1949,1944;, + 3;1944,1949,1950;, + 3;1944,1950,1945;, + 3;1398,1403,1946;, + 3;1403,1951,1946;, + 3;1946,1951,1952;, + 3;1946,1952,1947;, + 3;1947,1952,1953;, + 3;1947,1953,1948;, + 3;1948,1953,1954;, + 3;1948,1954,1949;, + 3;1949,1954,1955;, + 3;1949,1955,1950;, + 3;1403,1408,1951;, + 3;1408,1956,1951;, + 3;1951,1956,1957;, + 3;1951,1957,1952;, + 3;1952,1957,1958;, + 3;1952,1958,1953;, + 3;1953,1958,1959;, + 3;1953,1959,1954;, + 3;1954,1959,1960;, + 3;1954,1960,1955;, + 3;1408,1413,1956;, + 3;1413,1457,1956;, + 3;1956,1457,1463;, + 3;1956,1463,1957;, + 3;1957,1463,1469;, + 3;1957,1469,1958;, + 3;1958,1469,1475;, + 3;1958,1475,1959;, + 3;1959,1475,1481;, + 3;1959,1481,1960;, + 3;1960,1481,1487;, + 3;1960,1487,1961;, + 3;1955,1960,1961;, + 3;1955,1961,1962;, + 3;1950,1955,1962;, + 3;1950,1962,1963;, + 3;1945,1950,1963;, + 3;1961,1487,1493;, + 3;1961,1493,1964;, + 3;1962,1961,1964;, + 3;1962,1964,1965;, + 3;1963,1962,1965;, + 3;1963,1965,1966;, + 3;1967,1963,1966;, + 3;1945,1963,1967;, + 3;1940,1945,1967;, + 3;1940,1967,1968;, + 3;1935,1940,1968;, + 3;1964,1493,1499;, + 3;1964,1499,1969;, + 3;1965,1964,1969;, + 3;1965,1969,1970;, + 3;1966,1965,1970;, + 3;1966,1970,1971;, + 3;1972,1966,1971;, + 3;1967,1966,1972;, + 3;1968,1967,1972;, + 3;1968,1972,1973;, + 3;1974,1968,1973;, + 3;1935,1968,1974;, + 3;1930,1935,1974;, + 3;1969,1499,1505;, + 3;1969,1505,1975;, + 3;1970,1969,1975;, + 3;1970,1975,1976;, + 3;1971,1970,1976;, + 3;1971,1976,1977;, + 3;1978,1971,1977;, + 3;1972,1971,1978;, + 3;1973,1972,1978;, + 3;1973,1978,1979;, + 3;1980,1973,1979;, + 3;1974,1973,1980;, + 3;1975,1505,1511;, + 3;1975,1511,1981;, + 3;1976,1975,1981;, + 3;1976,1981,1982;, + 3;1977,1976,1982;, + 3;1977,1982,1983;, + 3;1984,1977,1983;, + 3;1978,1977,1984;, + 3;1979,1978,1984;, + 3;1979,1984,1985;, + 3;1986,1979,1985;, + 3;1980,1979,1986;, + 3;1981,1511,1517;, + 3;1981,1517,1987;, + 3;1982,1981,1987;, + 3;1982,1987,1988;, + 3;1983,1982,1988;, + 3;1983,1988,1989;, + 3;1990,1983,1989;, + 3;1984,1983,1990;, + 3;1985,1984,1990;, + 3;1985,1990,1991;, + 3;1992,1985,1991;, + 3;1986,1985,1992;, + 3;1987,1517,1523;, + 3;1987,1523,1993;, + 3;1988,1987,1993;, + 3;1988,1993,1994;, + 3;1989,1988,1994;, + 3;1989,1994,1995;, + 3;1996,1989,1995;, + 3;1990,1989,1996;, + 3;1991,1990,1996;, + 3;1991,1996,1997;, + 3;1998,1991,1997;, + 3;1992,1991,1998;, + 3;1993,1523,1529;, + 3;1993,1529,1999;, + 3;1994,1993,1999;, + 3;1994,1999,2000;, + 3;1995,1994,2000;, + 3;1995,2000,2001;, + 3;2002,1995,2001;, + 3;1996,1995,2002;, + 3;1997,1996,2002;, + 3;1997,2002,2003;, + 3;2004,1997,2003;, + 3;1998,1997,2004;, + 3;1999,1529,1535;, + 3;1999,1535,2005;, + 3;2000,1999,2005;, + 3;2000,2005,2006;, + 3;2001,2000,2006;, + 3;2001,2006,2007;, + 3;2008,2001,2007;, + 3;2002,2001,2008;, + 3;2003,2002,2008;, + 3;2003,2008,2009;, + 3;2010,2003,2009;, + 3;2004,2003,2010;, + 3;2005,1535,1541;, + 3;2005,1541,2011;, + 3;2006,2005,2011;, + 3;2006,2011,2012;, + 3;2007,2006,2012;, + 3;2007,2012,2013;, + 3;2014,2007,2013;, + 3;2008,2007,2014;, + 3;2009,2008,2014;, + 3;2009,2014,2015;, + 3;2016,2009,2015;, + 3;2010,2009,2016;, + 3;2011,1541,1547;, + 3;2011,1547,2017;, + 3;2012,2011,2017;, + 3;2012,2017,2018;, + 3;2013,2012,2018;, + 3;2013,2018,2019;, + 3;2020,2013,2019;, + 3;2014,2013,2020;, + 3;2015,2014,2020;, + 3;2015,2020,2021;, + 3;2022,2015,2021;, + 3;2016,2015,2022;, + 3;2017,1547,1553;, + 3;2017,1553,2023;, + 3;2018,2017,2023;, + 3;2018,2023,2024;, + 3;2019,2018,2024;, + 3;2019,2024,2025;, + 3;2026,2019,2025;, + 3;2020,2019,2026;, + 3;2021,2020,2026;, + 3;2021,2026,2027;, + 3;2028,2021,2027;, + 3;2022,2021,2028;, + 3;2023,1553,1559;, + 3;2023,1559,2029;, + 3;2024,2023,2029;, + 3;2024,2029,2030;, + 3;2025,2024,2030;, + 3;2025,2030,2031;, + 3;2032,2025,2031;, + 3;2026,2025,2032;, + 3;2027,2026,2032;, + 3;2027,2032,2033;, + 3;2034,2027,2033;, + 3;2028,2027,2034;, + 3;2029,1559,1565;, + 3;2029,1565,2035;, + 3;2030,2029,2035;, + 3;2030,2035,2036;, + 3;2031,2030,2036;, + 3;2031,2036,2037;, + 3;2038,2031,2037;, + 3;2032,2031,2038;, + 3;2033,2032,2038;, + 3;2033,2038,2039;, + 3;2040,2033,2039;, + 3;2034,2033,2040;, + 3;2035,1565,1571;, + 3;2035,1571,2041;, + 3;2036,2035,2041;, + 3;2036,2041,2042;, + 3;2037,2036,2042;, + 3;2037,2042,2043;, + 3;2044,2037,2043;, + 3;2038,2037,2044;, + 3;2039,2038,2044;, + 3;2039,2044,2045;, + 3;2046,2039,2045;, + 3;2040,2039,2046;, + 3;2041,1571,1577;, + 3;2041,1577,2047;, + 3;2042,2041,2047;, + 3;2042,2047,2048;, + 3;2043,2042,2048;, + 3;2043,2048,2049;, + 3;2050,2043,2049;, + 3;2044,2043,2050;, + 3;2045,2044,2050;, + 3;2045,2050,2051;, + 3;2052,2045,2051;, + 3;2046,2045,2052;, + 3;2047,1577,1583;, + 3;2047,1583,2053;, + 3;2048,2047,2053;, + 3;2048,2053,2054;, + 3;2049,2048,2054;, + 3;2049,2054,2055;, + 3;2056,2049,2055;, + 3;2050,2049,2056;, + 3;2051,2050,2056;, + 3;2051,2056,2057;, + 3;2058,2051,2057;, + 3;2052,2051,2058;, + 3;2053,1583,1589;, + 3;2053,1589,2059;, + 3;2054,2053,2059;, + 3;2054,2059,2060;, + 3;2055,2054,2060;, + 3;2055,2060,2061;, + 3;2062,2055,2061;, + 3;2056,2055,2062;, + 3;2057,2056,2062;, + 3;2057,2062,2063;, + 3;2064,2057,2063;, + 3;2058,2057,2064;, + 3;2059,1589,1595;, + 3;2059,1595,2065;, + 3;2060,2059,2065;, + 3;2060,2065,2066;, + 3;2061,2060,2066;, + 3;2061,2066,2067;, + 3;2068,2061,2067;, + 3;2062,2061,2068;, + 3;2063,2062,2068;, + 3;2063,2068,2069;, + 3;2070,2063,2069;, + 3;2064,2063,2070;, + 3;2065,1595,1601;, + 3;2065,1601,2071;, + 3;2066,2065,2071;, + 3;2066,2071,2072;, + 3;2067,2066,2072;, + 3;2067,2072,2073;, + 3;2074,2067,2073;, + 3;2068,2067,2074;, + 3;2069,2068,2074;, + 3;2069,2074,2075;, + 3;2076,2069,2075;, + 3;2070,2069,2076;, + 3;2071,1601,1607;, + 3;2071,1607,2077;, + 3;2072,2071,2077;, + 3;2072,2077,2078;, + 3;2073,2072,2078;, + 3;2073,2078,2079;, + 3;2080,2073,2079;, + 3;2074,2073,2080;, + 3;2075,2074,2080;, + 3;2075,2080,2081;, + 3;2082,2075,2081;, + 3;2076,2075,2082;, + 3;2077,1607,1613;, + 3;2077,1613,2083;, + 3;2078,2077,2083;, + 3;2078,2083,2084;, + 3;2079,2078,2084;, + 3;2079,2084,2085;, + 3;2086,2079,2085;, + 3;2080,2079,2086;, + 3;2081,2080,2086;, + 3;2081,2086,2087;, + 3;2088,2081,2087;, + 3;2082,2081,2088;, + 3;2083,1613,1619;, + 3;2083,1619,1642;, + 3;2084,2083,1642;, + 3;2084,1642,1641;, + 3;2085,2084,1641;, + 3;2085,1641,1647;, + 3;2089,2085,1647;, + 3;2086,2085,2089;, + 3;2087,2086,2089;, + 3;2087,2089,2090;, + 3;2091,2087,2090;, + 3;2088,2087,2091;, + 3;2092,2088,2091;, + 3;2093,2088,2092;, + 3;2093,2082,2088;, + 3;2089,1647,1652;, + 3;2090,2089,1652;, + 3;2090,1652,1657;, + 3;1672,2090,1657;, + 3;2091,2090,1672;, + 3;1677,2091,1672;, + 3;2092,2091,1677;, + 3;1682,2092,1677;, + 3;2094,2092,1682;, + 3;2094,2093,2092;, + 3;2095,2093,2094;, + 3;2095,2096,2093;, + 3;2096,2082,2093;, + 3;2096,2076,2082;, + 3;2097,2076,2096;, + 3;2097,2070,2076;, + 3;1687,2094,1682;, + 3;2098,2094,1687;, + 3;2098,2095,2094;, + 3;2099,2095,2098;, + 3;2099,2100,2095;, + 3;2100,2096,2095;, + 3;2100,2097,2096;, + 3;2101,2097,2100;, + 3;2101,2102,2097;, + 3;2102,2070,2097;, + 3;2102,2064,2070;, + 3;1692,2098,1687;, + 3;2103,2098,1692;, + 3;2103,2099,2098;, + 3;2104,2099,2103;, + 3;2104,2105,2099;, + 3;2105,2100,2099;, + 3;2105,2101,2100;, + 3;2106,2101,2105;, + 3;2106,2107,2101;, + 3;2107,2102,2101;, + 3;2107,2108,2102;, + 3;2108,2064,2102;, + 3;2108,2058,2064;, + 3;1697,2103,1692;, + 3;2109,2103,1697;, + 3;2109,2104,2103;, + 3;2110,2104,2109;, + 3;2110,2111,2104;, + 3;2111,2105,2104;, + 3;2111,2106,2105;, + 3;2112,2106,2111;, + 3;2112,2113,2106;, + 3;2113,2107,2106;, + 3;2113,2114,2107;, + 3;2114,2108,2107;, + 3;1702,2109,1697;, + 3;2115,2109,1702;, + 3;2115,2110,2109;, + 3;2116,2110,2115;, + 3;2116,2117,2110;, + 3;2117,2111,2110;, + 3;2117,2112,2111;, + 3;2118,2112,2117;, + 3;2118,2119,2112;, + 3;2119,2113,2112;, + 3;2119,2120,2113;, + 3;2120,2114,2113;, + 3;2115,1702,1707;, + 3;2115,1707,2121;, + 3;2116,2115,2121;, + 3;2116,2121,2122;, + 3;2123,2116,2122;, + 3;2123,2117,2116;, + 3;2123,2118,2117;, + 3;2124,2118,2123;, + 3;2124,2125,2118;, + 3;2125,2119,2118;, + 3;2125,2126,2119;, + 3;2126,2120,2119;, + 3;2121,1707,1712;, + 3;2121,1712,2127;, + 3;2122,2121,2127;, + 3;2122,2127,2128;, + 3;2129,2122,2128;, + 3;2123,2122,2129;, + 3;2124,2123,2129;, + 3;2124,2129,2130;, + 3;2131,2124,2130;, + 3;2131,2125,2124;, + 3;2131,2132,2125;, + 3;2132,2126,2125;, + 3;2127,1712,1717;, + 3;2127,1717,2133;, + 3;2128,2127,2133;, + 3;2128,2133,2134;, + 3;2135,2128,2134;, + 3;2129,2128,2135;, + 3;2130,2129,2135;, + 3;2130,2135,2136;, + 3;2137,2130,2136;, + 3;2131,2130,2137;, + 3;2138,2131,2137;, + 3;2138,2132,2131;, + 3;2133,1717,1722;, + 3;2133,1722,2139;, + 3;2134,2133,2139;, + 3;2134,2139,2140;, + 3;2141,2134,2140;, + 3;2135,2134,2141;, + 3;2136,2135,2141;, + 3;2136,2141,2142;, + 3;2143,2136,2142;, + 3;2137,2136,2143;, + 3;2144,2137,2143;, + 3;2138,2137,2144;, + 3;2139,1722,1727;, + 3;2139,1727,2145;, + 3;2140,2139,2145;, + 3;2140,2145,2146;, + 3;2147,2140,2146;, + 3;2141,2140,2147;, + 3;2142,2141,2147;, + 3;2142,2147,2148;, + 3;2149,2142,2148;, + 3;2143,2142,2149;, + 3;2150,2143,2149;, + 3;2144,2143,2150;, + 3;2145,1727,1732;, + 3;2145,1732,2151;, + 3;2146,2145,2151;, + 3;2146,2151,2152;, + 3;2153,2146,2152;, + 3;2147,2146,2153;, + 3;2148,2147,2153;, + 3;2148,2153,2154;, + 3;2155,2148,2154;, + 3;2149,2148,2155;, + 3;2156,2149,2155;, + 3;2150,2149,2156;, + 3;2151,1732,1737;, + 3;2151,1737,2157;, + 3;2152,2151,2157;, + 3;2152,2157,2158;, + 3;2159,2152,2158;, + 3;2153,2152,2159;, + 3;2154,2153,2159;, + 3;2154,2159,2160;, + 3;2161,2154,2160;, + 3;2155,2154,2161;, + 3;2162,2155,2161;, + 3;2156,2155,2162;, + 3;2157,1737,1742;, + 3;2157,1742,2163;, + 3;2158,2157,2163;, + 3;2158,2163,2164;, + 3;2165,2158,2164;, + 3;2159,2158,2165;, + 3;2160,2159,2165;, + 3;2160,2165,2166;, + 3;2167,2160,2166;, + 3;2161,2160,2167;, + 3;2168,2161,2167;, + 3;2162,2161,2168;, + 3;2163,1742,1747;, + 3;2163,1747,1762;, + 3;2164,2163,1762;, + 3;2164,1762,1767;, + 3;2169,2164,1767;, + 3;2165,2164,2169;, + 3;2166,2165,2169;, + 3;2166,2169,2170;, + 3;2171,2166,2170;, + 3;2167,2166,2171;, + 3;2172,2167,2171;, + 3;2168,2167,2172;, + 3;2173,2168,2172;, + 3;2174,2168,2173;, + 3;2174,2162,2168;, + 3;2169,1767,1772;, + 3;2170,2169,1772;, + 3;2170,1772,1777;, + 3;2175,2170,1777;, + 3;2171,2170,2175;, + 3;2176,2171,2175;, + 3;2172,2171,2176;, + 3;2177,2172,2176;, + 3;2173,2172,2177;, + 3;2178,2173,2177;, + 3;2179,2173,2178;, + 3;2179,2174,2173;, + 3;2175,1777,1782;, + 3;2180,2175,1782;, + 3;2176,2175,2180;, + 3;2181,2176,2180;, + 3;2177,2176,2181;, + 3;2182,2177,2181;, + 3;2178,2177,2182;, + 3;2183,2178,2182;, + 3;2184,2178,2183;, + 3;2184,2179,2178;, + 3;2180,1782,1787;, + 3;2185,2180,1787;, + 3;2181,2180,2185;, + 3;2186,2181,2185;, + 3;2182,2181,2186;, + 3;2187,2182,2186;, + 3;2183,2182,2187;, + 3;2188,2183,2187;, + 3;2189,2183,2188;, + 3;2189,2184,2183;, + 3;2185,1787,1792;, + 3;2190,2185,1792;, + 3;2186,2185,2190;, + 3;2191,2186,2190;, + 3;2187,2186,2191;, + 3;2192,2187,2191;, + 3;2188,2187,2192;, + 3;2193,2188,2192;, + 3;2194,2188,2193;, + 3;2194,2189,2188;, + 3;2190,1792,1797;, + 3;2195,2190,1797;, + 3;2191,2190,2195;, + 3;2196,2191,2195;, + 3;2192,2191,2196;, + 3;2197,2192,2196;, + 3;2193,2192,2197;, + 3;2198,2193,2197;, + 3;2199,2193,2198;, + 3;2199,2194,2193;, + 3;2195,1797,1802;, + 3;2200,2195,1802;, + 3;2196,2195,2200;, + 3;2201,2196,2200;, + 3;2197,2196,2201;, + 3;2202,2197,2201;, + 3;2198,2197,2202;, + 3;2203,2198,2202;, + 3;2204,2198,2203;, + 3;2204,2199,2198;, + 3;2200,1802,1807;, + 3;2205,2200,1807;, + 3;2201,2200,2205;, + 3;2206,2201,2205;, + 3;2202,2201,2206;, + 3;2207,2202,2206;, + 3;2203,2202,2207;, + 3;1887,2203,2207;, + 3;2208,2203,1887;, + 3;2208,2204,2203;, + 3;2205,1807,1812;, + 3;2209,2205,1812;, + 3;2206,2205,2209;, + 3;2210,2206,2209;, + 3;2207,2206,2210;, + 3;1881,2207,2210;, + 3;1887,2207,1881;, + 3;2209,1812,1817;, + 3;2211,2209,1817;, + 3;2210,2209,2211;, + 3;1875,2210,2211;, + 3;1881,2210,1875;, + 3;2211,1817,1822;, + 3;1869,2211,1822;, + 3;1875,2211,1869;, + 3;1886,2208,1887;, + 3;1898,2208,1886;, + 3;1898,2212,2208;, + 3;2212,2204,2208;, + 3;2212,2213,2204;, + 3;2213,2199,2204;, + 3;2213,2214,2199;, + 3;2214,2194,2199;, + 3;2215,2212,1898;, + 3;2215,2216,2212;, + 3;2216,2213,2212;, + 3;2216,2217,2213;, + 3;2217,2214,2213;, + 3;2217,2218,2214;, + 3;2218,2219,2214;, + 3;2214,2219,2194;, + 3;2219,2189,2194;, + 3;1897,2215,1898;, + 3;1904,2215,1897;, + 3;1904,2220,2215;, + 3;2220,2216,2215;, + 3;2220,2221,2216;, + 3;2221,2217,2216;, + 3;2221,2222,2217;, + 3;2222,2218,2217;, + 3;2222,2223,2218;, + 3;2223,2224,2218;, + 3;2218,2224,2219;, + 3;2224,2225,2219;, + 3;2219,2225,2189;, + 3;2225,2184,2189;, + 3;1910,2220,1904;, + 3;1910,2226,2220;, + 3;2226,2221,2220;, + 3;2226,2227,2221;, + 3;2227,2222,2221;, + 3;2227,2228,2222;, + 3;2228,2223,2222;, + 3;2228,2229,2223;, + 3;2229,2230,2223;, + 3;2223,2230,2224;, + 3;2230,2231,2224;, + 3;2224,2231,2225;, + 3;1910,2232,2226;, + 3;2226,2232,2233;, + 3;2226,2233,2227;, + 3;2227,2233,2234;, + 3;2227,2234,2228;, + 3;2228,2234,2235;, + 3;2228,2235,2229;, + 3;2229,2235,2236;, + 3;2229,2236,2237;, + 3;2229,2237,2230;, + 3;1910,1909,2232;, + 3;1909,2238,2232;, + 3;2232,2238,2239;, + 3;2232,2239,2233;, + 3;2233,2239,2240;, + 3;2233,2240,2234;, + 3;2234,2240,2241;, + 3;2234,2241,2235;, + 3;2235,2241,2242;, + 3;2235,2242,2236;, + 3;1909,1915,2238;, + 3;1915,2243,2238;, + 3;2238,2243,2244;, + 3;2238,2244,2239;, + 3;2239,2244,2245;, + 3;2239,2245,2240;, + 3;2240,2245,2246;, + 3;2240,2246,2241;, + 3;2241,2246,2247;, + 3;2241,2247,2242;, + 3;1915,1920,2243;, + 3;1920,2248,2243;, + 3;2243,2248,2249;, + 3;2243,2249,2244;, + 3;2244,2249,2250;, + 3;2244,2250,2245;, + 3;2245,2250,2251;, + 3;2245,2251,2246;, + 3;2246,2251,2252;, + 3;2246,2252,2247;, + 3;1920,1925,2248;, + 3;1925,2253,2248;, + 3;2248,2253,2254;, + 3;2248,2254,2249;, + 3;2249,2254,2255;, + 3;2249,2255,2250;, + 3;2250,2255,2256;, + 3;2250,2256,2251;, + 3;2251,2256,2257;, + 3;2251,2257,2252;, + 3;1925,1930,2253;, + 3;1930,1974,2253;, + 3;2253,1974,1980;, + 3;2253,1980,2254;, + 3;2254,1980,1986;, + 3;2254,1986,2255;, + 3;2255,1986,1992;, + 3;2255,1992,2256;, + 3;2256,1992,1998;, + 3;2256,1998,2257;, + 3;2257,1998,2004;, + 3;2257,2004,2258;, + 3;2252,2257,2258;, + 3;2252,2258,2259;, + 3;2247,2252,2259;, + 3;2247,2259,2260;, + 3;2242,2247,2260;, + 3;2258,2004,2010;, + 3;2258,2010,2261;, + 3;2259,2258,2261;, + 3;2259,2261,2262;, + 3;2260,2259,2262;, + 3;2260,2262,2263;, + 3;2264,2260,2263;, + 3;2242,2260,2264;, + 3;2236,2242,2264;, + 3;2236,2264,2265;, + 3;2237,2236,2265;, + 3;2261,2010,2016;, + 3;2261,2016,2266;, + 3;2262,2261,2266;, + 3;2262,2266,2267;, + 3;2263,2262,2267;, + 3;2263,2267,2268;, + 3;2269,2263,2268;, + 3;2264,2263,2269;, + 3;2265,2264,2269;, + 3;2265,2269,2270;, + 3;2271,2265,2270;, + 3;2237,2265,2271;, + 3;2266,2016,2022;, + 3;2266,2022,2272;, + 3;2267,2266,2272;, + 3;2267,2272,2273;, + 3;2268,2267,2273;, + 3;2268,2273,2274;, + 3;2275,2268,2274;, + 3;2269,2268,2275;, + 3;2270,2269,2275;, + 3;2270,2275,2276;, + 3;2277,2270,2276;, + 3;2271,2270,2277;, + 3;2272,2022,2028;, + 3;2272,2028,2278;, + 3;2273,2272,2278;, + 3;2273,2278,2279;, + 3;2274,2273,2279;, + 3;2274,2279,2280;, + 3;2281,2274,2280;, + 3;2275,2274,2281;, + 3;2276,2275,2281;, + 3;2276,2281,2282;, + 3;2283,2276,2282;, + 3;2277,2276,2283;, + 3;2278,2028,2034;, + 3;2278,2034,2284;, + 3;2279,2278,2284;, + 3;2279,2284,2285;, + 3;2280,2279,2285;, + 3;2280,2285,2286;, + 3;2287,2280,2286;, + 3;2281,2280,2287;, + 3;2282,2281,2287;, + 3;2282,2287,2288;, + 3;2289,2282,2288;, + 3;2283,2282,2289;, + 3;2284,2034,2040;, + 3;2284,2040,2290;, + 3;2285,2284,2290;, + 3;2285,2290,2291;, + 3;2286,2285,2291;, + 3;2286,2291,2292;, + 3;2293,2286,2292;, + 3;2287,2286,2293;, + 3;2288,2287,2293;, + 3;2288,2293,2132;, + 3;2138,2288,2132;, + 3;2289,2288,2138;, + 3;2290,2040,2046;, + 3;2290,2046,2294;, + 3;2291,2290,2294;, + 3;2291,2294,2295;, + 3;2292,2291,2295;, + 3;2292,2295,2120;, + 3;2126,2292,2120;, + 3;2293,2292,2126;, + 3;2132,2293,2126;, + 3;2294,2046,2052;, + 3;2294,2052,2296;, + 3;2295,2294,2296;, + 3;2295,2296,2114;, + 3;2120,2295,2114;, + 3;2296,2052,2058;, + 3;2296,2058,2108;, + 3;2114,2296,2108;, + 3;2289,2138,2144;, + 3;2289,2144,2297;, + 3;2283,2289,2297;, + 3;2283,2297,2298;, + 3;2277,2283,2298;, + 3;2277,2298,2299;, + 3;2271,2277,2299;, + 3;2297,2144,2150;, + 3;2297,2150,2300;, + 3;2298,2297,2300;, + 3;2298,2300,2301;, + 3;2299,2298,2301;, + 3;2299,2301,2302;, + 3;2303,2299,2302;, + 3;2271,2299,2303;, + 3;2237,2271,2303;, + 3;2237,2303,2230;, + 3;2230,2303,2231;, + 3;2300,2150,2156;, + 3;2300,2156,2304;, + 3;2301,2300,2304;, + 3;2301,2304,2305;, + 3;2302,2301,2305;, + 3;2302,2305,2306;, + 3;2231,2302,2306;, + 3;2303,2302,2231;, + 3;2304,2156,2162;, + 3;2304,2162,2174;, + 3;2305,2304,2174;, + 3;2305,2174,2179;, + 3;2306,2305,2179;, + 3;2306,2179,2184;, + 3;2225,2306,2184;, + 3;2231,2306,2225;; + } + + MeshTextureCoords { + 2307; + 0.281886;0.010641;, + 0.257541;0.012708;, + 1.000000;0.015902;, + 0.372241;0.029051;, + 0.344386;0.030669;, + 0.237113;0.014790;, + 0.000000;0.015902;, + 0.312811;0.008647;, + 0.401990;0.027694;, + 0.417159;0.048346;, + 0.390687;0.049523;, + 0.365054;0.050960;, + 0.318390;0.032482;, + 0.355259;0.006841;, + 0.433490;0.026663;, + 0.444339;0.047471;, + 0.448562;0.068432;, + 0.423216;0.069238;, + 0.398287;0.070330;, + 0.416933;0.005462;, + 0.466364;0.026017;, + 0.472034;0.046932;, + 0.474204;0.067938;, + 0.475347;0.089019;, + 0.450799;0.089485;, + 0.500000;0.004913;, + 0.500000;0.025797;, + 0.500000;0.046749;, + 0.500000;0.067771;, + 0.500000;0.088861;, + 0.583067;0.005462;, + 0.533636;0.026017;, + 0.527966;0.046932;, + 0.525796;0.067938;, + 0.524653;0.089019;, + 0.500000;0.110020;, + 0.644741;0.006841;, + 0.566510;0.026663;, + 0.555661;0.047471;, + 0.551438;0.068432;, + 0.549201;0.089485;, + 0.523951;0.110170;, + 0.687189;0.008647;, + 0.598010;0.027694;, + 0.582841;0.048346;, + 0.576784;0.069238;, + 0.573546;0.090248;, + 0.547823;0.110616;, + 0.718114;0.010641;, + 0.627759;0.029051;, + 0.609313;0.049523;, + 0.601713;0.070330;, + 0.597600;0.091285;, + 0.571540;0.111345;, + 0.742459;0.012708;, + 0.655614;0.030669;, + 0.634946;0.050960;, + 0.626131;0.071676;, + 0.621293;0.092568;, + 0.595036;0.112338;, + 0.762887;0.014790;, + 0.681610;0.032482;, + 0.659668;0.052612;, + 0.649974;0.073236;, + 0.644570;0.094062;, + 0.618253;0.113568;, + 0.780848;0.016852;, + 0.705888;0.034431;, + 0.683460;0.054429;, + 0.673204;0.074969;, + 0.667396;0.095730;, + 0.641145;0.115005;, + 0.797175;0.018870;, + 0.728639;0.036461;, + 0.706341;0.056366;, + 0.695811;0.076835;, + 0.689751;0.097534;, + 0.663681;0.116615;, + 0.812371;0.020826;, + 0.750066;0.038527;, + 0.728361;0.058378;, + 0.717802;0.078789;, + 0.711633;0.099434;, + 0.685841;0.118360;, + 0.826757;0.022708;, + 0.770360;0.040590;, + 0.749584;0.060422;, + 0.739202;0.080794;, + 0.733049;0.101391;, + 0.707615;0.120203;, + 0.840545;0.024503;, + 0.789695;0.042618;, + 0.770082;0.062463;, + 0.760045;0.082810;, + 0.754016;0.103368;, + 0.729005;0.122107;, + 0.853882;0.026202;, + 0.808222;0.044582;, + 0.789931;0.064466;, + 0.780372;0.084803;, + 0.774560;0.105330;, + 0.750021;0.124036;, + 0.866872;0.027795;, + 0.826070;0.046459;, + 0.809204;0.066402;, + 0.800228;0.086742;, + 0.794709;0.107246;, + 0.770677;0.125955;, + 0.879590;0.029275;, + 0.843348;0.048229;, + 0.827973;0.068246;, + 0.819659;0.088598;, + 0.814496;0.109087;, + 0.790996;0.127833;, + 0.892093;0.030635;, + 0.860148;0.049874;, + 0.846302;0.069974;, + 0.838711;0.090346;, + 0.833956;0.110825;, + 0.811000;0.129641;, + 0.904426;0.031868;, + 0.876550;0.051381;, + 0.864251;0.071568;, + 0.857429;0.091964;, + 0.853123;0.112439;, + 0.830717;0.131351;, + 0.916623;0.032969;, + 0.892622;0.052737;, + 0.881877;0.073010;, + 0.875857;0.093434;, + 0.872033;0.113908;, + 0.850174;0.132942;, + 0.928710;0.033933;, + 0.908422;0.053932;, + 0.899229;0.074287;, + 0.894037;0.094739;, + 0.890720;0.115214;, + 0.869402;0.134391;, + 0.940711;0.034756;, + 0.923999;0.054956;, + 0.916354;0.075386;, + 0.912007;0.095865;, + 0.909217;0.116343;, + 0.888428;0.135682;, + 0.952644;0.035434;, + 0.939401;0.055804;, + 0.933296;0.076298;, + 0.929807;0.096802;, + 0.927558;0.117283;, + 0.907284;0.136798;, + 0.964526;0.035964;, + 0.954665;0.056469;, + 0.950095;0.077015;, + 0.947471;0.097539;, + 0.945776;0.118023;, + 0.925996;0.137728;, + 0.976370;0.036345;, + 0.969831;0.056947;, + 0.966788;0.077531;, + 0.965036;0.098071;, + 0.963902;0.118558;, + 0.944596;0.138462;, + 0.988191;0.036574;, + 0.984932;0.057235;, + 0.983411;0.077843;, + 0.982534;0.098391;, + 0.981966;0.118881;, + 0.963111;0.138991;, + 1.000000;0.036650;, + 1.000000;0.057331;, + 1.000000;0.077947;, + 1.000000;0.098499;, + 1.000000;0.118988;, + 0.981569;0.139311;, + 0.962531;0.159371;, + 0.943731;0.158852;, + 0.924853;0.158133;, + 1.000000;0.139418;, + 0.981278;0.159685;, + 0.962089;0.179699;, + 0.943073;0.179195;, + 0.923985;0.178497;, + 0.904800;0.177612;, + 0.905871;0.157222;, + 1.000000;0.159790;, + 0.981057;0.180004;, + 0.961744;0.199977;, + 0.942559;0.199491;, + 0.923307;0.198818;, + 0.903965;0.197965;, + 1.000000;0.180106;, + 0.980883;0.200270;, + 0.961468;0.220206;, + 0.942148;0.219742;, + 0.922766;0.219098;, + 0.903299;0.218283;, + 1.000000;0.200369;, + 0.980744;0.220487;, + 0.961244;0.240390;, + 0.941815;0.239949;, + 0.922327;0.239339;, + 0.902759;0.238566;, + 1.000000;0.220581;, + 0.980632;0.240656;, + 0.961060;0.260531;, + 0.941542;0.260116;, + 0.921967;0.259542;, + 0.902317;0.258815;, + 1.000000;0.240746;, + 0.980539;0.260782;, + 0.960907;0.280632;, + 0.941315;0.280245;, + 0.921669;0.279710;, + 0.901951;0.279031;, + 1.000000;0.260865;, + 0.980463;0.280865;, + 0.960780;0.300695;, + 0.941127;0.300339;, + 0.921421;0.299845;, + 0.901646;0.299219;, + 1.000000;0.280944;, + 0.980399;0.300911;, + 0.960674;0.320725;, + 0.940969;0.320400;, + 0.921214;0.319949;, + 0.901392;0.319378;, + 1.000000;0.300983;, + 0.980346;0.320921;, + 0.960586;0.340723;, + 0.940838;0.340431;, + 0.921041;0.340026;, + 0.901180;0.339512;, + 1.000000;0.320987;, + 0.980301;0.340900;, + 0.960512;0.360694;, + 0.940729;0.360436;, + 0.920898;0.360078;, + 0.901004;0.359624;, + 1.000000;0.340959;, + 0.980264;0.360851;, + 0.960452;0.380641;, + 0.940639;0.380417;, + 0.920780;0.380108;, + 0.900859;0.379715;, + 1.000000;0.360903;, + 0.980234;0.380776;, + 0.960403;0.400566;, + 0.940566;0.400379;, + 0.920684;0.400119;, + 0.900742;0.399789;, + 1.000000;0.380821;, + 0.980209;0.400680;, + 0.960364;0.420474;, + 0.940508;0.420323;, + 0.920608;0.420114;, + 0.900649;0.419849;, + 1.000000;0.400718;, + 0.980190;0.420565;, + 0.960335;0.440368;, + 0.940465;0.440254;, + 0.920551;0.440097;, + 0.900579;0.439897;, + 1.000000;0.420596;, + 0.980175;0.440437;, + 0.960314;0.460251;, + 0.940435;0.460175;, + 0.920511;0.460070;, + 0.900530;0.459936;, + 1.000000;0.440460;, + 0.980164;0.460297;, + 0.960302;0.480127;, + 0.940416;0.480089;, + 0.920488;0.480037;, + 0.900501;0.479970;, + 1.000000;0.460313;, + 0.980158;0.480150;, + 0.960298;0.500000;, + 0.940410;0.500000;, + 0.920480;0.500000;, + 0.900492;0.500000;, + 1.000000;0.480158;, + 0.980156;0.500000;, + 0.960302;0.519873;, + 0.940416;0.519911;, + 0.920488;0.519963;, + 0.900501;0.520030;, + 1.000000;0.500000;, + 0.980158;0.519850;, + 0.960314;0.539749;, + 0.940435;0.539825;, + 0.920511;0.539930;, + 0.900530;0.540064;, + 1.000000;0.519842;, + 0.980164;0.539703;, + 0.960335;0.559632;, + 0.940465;0.559746;, + 0.920551;0.559903;, + 0.900579;0.560103;, + 1.000000;0.539687;, + 0.980175;0.559563;, + 0.960364;0.579526;, + 0.940508;0.579677;, + 0.920608;0.579886;, + 0.900649;0.580151;, + 1.000000;0.559540;, + 0.980190;0.579435;, + 0.960403;0.599434;, + 0.940566;0.599621;, + 0.920684;0.599881;, + 0.900742;0.600211;, + 1.000000;0.579404;, + 0.980209;0.599320;, + 0.960452;0.619359;, + 0.940639;0.619583;, + 0.920780;0.619892;, + 0.900859;0.620285;, + 1.000000;0.599282;, + 0.980234;0.619224;, + 0.960512;0.639306;, + 0.940729;0.639564;, + 0.920898;0.639922;, + 0.901004;0.640376;, + 1.000000;0.619179;, + 0.980264;0.639149;, + 0.960586;0.659277;, + 0.940838;0.659569;, + 0.921041;0.659974;, + 0.901180;0.660488;, + 1.000000;0.639097;, + 0.980301;0.659100;, + 0.960674;0.679275;, + 0.940969;0.679600;, + 0.921214;0.680051;, + 0.901392;0.680622;, + 1.000000;0.659041;, + 0.980346;0.679079;, + 0.960780;0.699305;, + 0.941127;0.699661;, + 0.921421;0.700155;, + 0.901646;0.700781;, + 1.000000;0.679013;, + 0.980399;0.699089;, + 0.960907;0.719368;, + 0.941315;0.719755;, + 0.921669;0.720290;, + 0.901951;0.720969;, + 1.000000;0.699017;, + 0.980463;0.719135;, + 0.961060;0.739469;, + 0.941542;0.739884;, + 0.921967;0.740458;, + 0.902317;0.741186;, + 1.000000;0.719056;, + 0.980539;0.739218;, + 0.961244;0.759610;, + 0.941815;0.760051;, + 0.922327;0.760661;, + 0.902759;0.761434;, + 1.000000;0.739135;, + 0.980632;0.759344;, + 0.961468;0.779794;, + 0.942148;0.780258;, + 0.922766;0.780902;, + 0.903299;0.781717;, + 1.000000;0.759254;, + 0.980744;0.779513;, + 0.961744;0.800023;, + 0.942559;0.800509;, + 0.923307;0.801182;, + 0.903965;0.802035;, + 1.000000;0.779419;, + 0.980883;0.799730;, + 0.962089;0.820301;, + 0.943073;0.820805;, + 0.923985;0.821503;, + 0.904800;0.822388;, + 1.000000;0.799631;, + 0.981057;0.819996;, + 0.962531;0.840629;, + 0.943731;0.841148;, + 0.924853;0.841867;, + 0.905871;0.842778;, + 1.000000;0.819894;, + 0.981278;0.840315;, + 0.963111;0.861009;, + 0.944596;0.861538;, + 0.925996;0.862272;, + 0.907284;0.863202;, + 1.000000;0.840210;, + 0.981569;0.860689;, + 0.963902;0.881442;, + 0.945776;0.881977;, + 0.927558;0.882717;, + 0.909217;0.883657;, + 1.000000;0.860582;, + 0.981966;0.881119;, + 0.965036;0.901929;, + 0.947471;0.902461;, + 0.929807;0.903198;, + 0.912007;0.904135;, + 1.000000;0.881012;, + 0.982534;0.901609;, + 0.966788;0.922469;, + 0.950095;0.922985;, + 0.933296;0.923702;, + 0.916354;0.924614;, + 1.000000;0.901501;, + 0.983411;0.922157;, + 0.969831;0.943053;, + 0.954665;0.943531;, + 0.939401;0.944196;, + 0.923999;0.945044;, + 1.000000;0.922053;, + 0.984932;0.942765;, + 0.976370;0.963655;, + 0.964526;0.964036;, + 0.952644;0.964566;, + 0.940711;0.965244;, + 1.000000;0.942669;, + 0.988191;0.963426;, + 1.000000;0.984098;, + 0.928710;0.966067;, + 0.908422;0.946068;, + 1.000000;0.963350;, + 0.899229;0.925713;, + 0.892622;0.947263;, + 0.881877;0.926990;, + 0.894037;0.905261;, + 0.916623;0.967031;, + 0.904426;0.968132;, + 0.876550;0.948619;, + 0.864251;0.928432;, + 0.875857;0.906566;, + 0.892093;0.969365;, + 0.860148;0.950126;, + 0.846302;0.930026;, + 0.857429;0.908036;, + 0.872033;0.886092;, + 0.890720;0.884786;, + 0.879590;0.970725;, + 0.843348;0.951772;, + 0.827973;0.931754;, + 0.838711;0.909654;, + 0.853123;0.887561;, + 0.866872;0.972205;, + 0.826070;0.953541;, + 0.809204;0.933598;, + 0.819659;0.911402;, + 0.833956;0.889175;, + 0.853882;0.973798;, + 0.808222;0.955418;, + 0.789931;0.935534;, + 0.800228;0.913258;, + 0.814496;0.890913;, + 0.840545;0.975497;, + 0.789695;0.957382;, + 0.770082;0.937537;, + 0.780372;0.915197;, + 0.794709;0.892754;, + 0.826757;0.977292;, + 0.770360;0.959410;, + 0.749584;0.939578;, + 0.760045;0.917190;, + 0.774560;0.894670;, + 0.812371;0.979174;, + 0.750066;0.961473;, + 0.728361;0.941622;, + 0.739202;0.919206;, + 0.754016;0.896632;, + 0.797175;0.981130;, + 0.728639;0.963539;, + 0.706341;0.943634;, + 0.717802;0.921211;, + 0.733049;0.898609;, + 0.780848;0.983148;, + 0.705888;0.965569;, + 0.683460;0.945571;, + 0.695811;0.923165;, + 0.711633;0.900566;, + 0.762887;0.985210;, + 0.681610;0.967518;, + 0.659668;0.947388;, + 0.673204;0.925031;, + 0.689751;0.902466;, + 0.742459;0.987292;, + 0.655614;0.969331;, + 0.634946;0.949040;, + 0.649974;0.926764;, + 0.667396;0.904270;, + 0.718114;0.989359;, + 0.627759;0.970949;, + 0.609313;0.950477;, + 0.626131;0.928324;, + 0.644570;0.905938;, + 0.687189;0.991353;, + 0.598010;0.972307;, + 0.582841;0.951654;, + 0.601713;0.929670;, + 0.621293;0.907432;, + 0.644741;0.993159;, + 0.566510;0.973337;, + 0.555661;0.952529;, + 0.576784;0.930762;, + 0.597600;0.908715;, + 0.583067;0.994538;, + 0.533636;0.973983;, + 0.527966;0.953068;, + 0.551438;0.931568;, + 0.573546;0.909752;, + 0.500000;0.995087;, + 0.500000;0.974203;, + 0.500000;0.953251;, + 0.525796;0.932062;, + 0.549201;0.910515;, + 0.571540;0.888655;, + 0.595036;0.887662;, + 0.466364;0.973983;, + 0.472034;0.953068;, + 0.474204;0.932062;, + 0.500000;0.932229;, + 0.524653;0.910981;, + 0.547823;0.889384;, + 0.416933;0.994538;, + 0.433490;0.973337;, + 0.444339;0.952529;, + 0.448562;0.931568;, + 0.450799;0.910515;, + 0.475347;0.910981;, + 0.000000;0.984098;, + 0.355259;0.993159;, + 0.401990;0.972307;, + 0.417159;0.951654;, + 0.423216;0.930762;, + 0.426454;0.909752;, + 0.312811;0.991353;, + 0.372241;0.970949;, + 0.390687;0.950477;, + 0.398287;0.929670;, + 0.402400;0.908715;, + 0.281886;0.989359;, + 0.344386;0.969331;, + 0.365054;0.949040;, + 0.373869;0.928324;, + 0.378707;0.907432;, + 0.257541;0.987292;, + 0.318390;0.967518;, + 0.340332;0.947388;, + 0.350026;0.926764;, + 0.355430;0.905938;, + 0.237113;0.985210;, + 0.294112;0.965569;, + 0.316540;0.945571;, + 0.326796;0.925031;, + 0.332604;0.904270;, + 0.219152;0.983148;, + 0.271361;0.963539;, + 0.293659;0.943634;, + 0.304189;0.923165;, + 0.310249;0.902466;, + 0.202825;0.981130;, + 0.249934;0.961473;, + 0.271639;0.941622;, + 0.282198;0.921211;, + 0.288367;0.900566;, + 0.187629;0.979174;, + 0.229640;0.959410;, + 0.250416;0.939578;, + 0.260798;0.919206;, + 0.266951;0.898609;, + 0.173243;0.977292;, + 0.210305;0.957382;, + 0.229918;0.937537;, + 0.239955;0.917190;, + 0.245984;0.896632;, + 0.159455;0.975497;, + 0.191778;0.955418;, + 0.210069;0.935534;, + 0.219628;0.915197;, + 0.225440;0.894670;, + 0.146118;0.973798;, + 0.173930;0.953541;, + 0.190796;0.933598;, + 0.199772;0.913258;, + 0.205291;0.892754;, + 0.133128;0.972205;, + 0.156652;0.951772;, + 0.172027;0.931754;, + 0.180341;0.911402;, + 0.185504;0.890913;, + 0.120410;0.970725;, + 0.139852;0.950126;, + 0.153698;0.930026;, + 0.161289;0.909654;, + 0.166044;0.889175;, + 0.107907;0.969365;, + 0.123450;0.948619;, + 0.135749;0.928432;, + 0.142571;0.908036;, + 0.146877;0.887561;, + 0.095574;0.968132;, + 0.107378;0.947263;, + 0.118123;0.926990;, + 0.124143;0.906566;, + 0.127967;0.886092;, + 0.083377;0.967031;, + 0.091578;0.946068;, + 0.100771;0.925713;, + 0.105963;0.905261;, + 0.109280;0.884786;, + 0.071290;0.966067;, + 0.076001;0.945044;, + 0.083646;0.924614;, + 0.087993;0.904135;, + 0.090783;0.883657;, + 0.059289;0.965244;, + 0.060599;0.944196;, + 0.066704;0.923702;, + 0.070193;0.903198;, + 0.072442;0.882717;, + 0.047356;0.964566;, + 0.045335;0.943531;, + 0.049905;0.922985;, + 0.052529;0.902461;, + 0.054224;0.881977;, + 0.035474;0.964036;, + 0.030169;0.943053;, + 0.033212;0.922469;, + 0.034964;0.901929;, + 0.036098;0.881442;, + 0.023630;0.963655;, + 0.015068;0.942765;, + 0.016589;0.922157;, + 0.017466;0.901609;, + 0.018034;0.881119;, + 0.011809;0.963426;, + 0.000000;0.942669;, + 0.000000;0.922053;, + 0.000000;0.901501;, + 0.000000;0.881012;, + 0.000000;0.963350;, + 0.000000;0.860582;, + 0.018431;0.860689;, + 0.036889;0.861009;, + 0.055404;0.861538;, + 0.000000;0.840210;, + 0.018722;0.840315;, + 0.037469;0.840629;, + 0.056269;0.841148;, + 0.074004;0.862272;, + 0.092716;0.863202;, + 0.000000;0.819894;, + 0.018943;0.819996;, + 0.037911;0.820301;, + 0.056927;0.820805;, + 0.075147;0.841867;, + 0.094129;0.842778;, + 0.111572;0.864319;, + 0.000000;0.799631;, + 0.019117;0.799730;, + 0.038256;0.800023;, + 0.057441;0.800509;, + 0.076015;0.821503;, + 0.095200;0.822388;, + 0.113241;0.843871;, + 0.000000;0.779419;, + 0.019256;0.779513;, + 0.038532;0.779794;, + 0.057852;0.780258;, + 0.076693;0.801182;, + 0.096035;0.802035;, + 0.114505;0.823449;, + 0.000000;0.759254;, + 0.019368;0.759344;, + 0.038756;0.759610;, + 0.058185;0.760051;, + 0.077234;0.780902;, + 0.096701;0.781717;, + 0.115489;0.803057;, + 0.000000;0.739135;, + 0.019461;0.739218;, + 0.038940;0.739469;, + 0.058458;0.739884;, + 0.077673;0.760661;, + 0.097241;0.761434;, + 0.116273;0.782694;, + 0.000000;0.719056;, + 0.019537;0.719135;, + 0.039093;0.719368;, + 0.058685;0.719755;, + 0.078033;0.740458;, + 0.097683;0.741186;, + 0.116907;0.762362;, + 0.000000;0.699017;, + 0.019601;0.699089;, + 0.039220;0.699305;, + 0.058873;0.699661;, + 0.078331;0.720290;, + 0.098049;0.720969;, + 0.117427;0.742058;, + 0.000000;0.679013;, + 0.019654;0.679079;, + 0.039326;0.679275;, + 0.059031;0.679600;, + 0.078579;0.700155;, + 0.098354;0.700781;, + 0.117857;0.721782;, + 0.000000;0.659041;, + 0.019699;0.659100;, + 0.039414;0.659277;, + 0.059162;0.659569;, + 0.078786;0.680051;, + 0.098608;0.680622;, + 0.118214;0.701532;, + 0.000000;0.639097;, + 0.019736;0.639149;, + 0.039488;0.639306;, + 0.059271;0.639564;, + 0.078959;0.659974;, + 0.098820;0.660488;, + 0.118512;0.681307;, + 0.000000;0.619179;, + 0.019766;0.619224;, + 0.039548;0.619359;, + 0.059361;0.619583;, + 0.079102;0.639922;, + 0.098996;0.640376;, + 0.118761;0.661104;, + 0.000000;0.599282;, + 0.019791;0.599320;, + 0.039597;0.599434;, + 0.059434;0.599621;, + 0.079220;0.619892;, + 0.099141;0.620285;, + 0.118967;0.640921;, + 0.000000;0.579404;, + 0.019811;0.579435;, + 0.039636;0.579526;, + 0.059492;0.579677;, + 0.079316;0.599881;, + 0.099258;0.600211;, + 0.119137;0.620755;, + 0.000000;0.559540;, + 0.019825;0.559563;, + 0.039665;0.559632;, + 0.059535;0.559746;, + 0.079392;0.579886;, + 0.099351;0.580151;, + 0.119274;0.600606;, + 0.000000;0.539687;, + 0.019836;0.539703;, + 0.039686;0.539749;, + 0.059565;0.539825;, + 0.079449;0.559903;, + 0.099421;0.560103;, + 0.119383;0.580469;, + 0.000000;0.519842;, + 0.019842;0.519850;, + 0.039698;0.519873;, + 0.059584;0.519911;, + 0.079489;0.539930;, + 0.099470;0.540064;, + 0.119465;0.560342;, + 0.000000;0.500000;, + 0.019844;0.500000;, + 0.039702;0.500000;, + 0.059589;0.500000;, + 0.079512;0.519963;, + 0.099499;0.520030;, + 0.119522;0.540224;, + 0.000000;0.480158;, + 0.019842;0.480150;, + 0.039698;0.480127;, + 0.059584;0.480089;, + 0.079520;0.500000;, + 0.099508;0.500000;, + 0.119556;0.520111;, + 0.000000;0.460313;, + 0.019836;0.460297;, + 0.039686;0.460251;, + 0.059565;0.460175;, + 0.079512;0.480037;, + 0.099499;0.479970;, + 0.119567;0.500000;, + 0.000000;0.440460;, + 0.019825;0.440437;, + 0.039665;0.440368;, + 0.059535;0.440254;, + 0.079489;0.460070;, + 0.099470;0.459936;, + 0.119556;0.479889;, + 0.000000;0.420596;, + 0.019811;0.420565;, + 0.039636;0.420474;, + 0.059492;0.420323;, + 0.079449;0.440097;, + 0.099421;0.439897;, + 0.119522;0.459776;, + 0.000000;0.400718;, + 0.019791;0.400680;, + 0.039597;0.400566;, + 0.059434;0.400379;, + 0.079392;0.420114;, + 0.099351;0.419849;, + 0.119465;0.439658;, + 0.000000;0.380821;, + 0.019766;0.380776;, + 0.039548;0.380641;, + 0.059361;0.380417;, + 0.079316;0.400119;, + 0.099258;0.399789;, + 0.119383;0.419531;, + 0.000000;0.360903;, + 0.019736;0.360851;, + 0.039488;0.360694;, + 0.059271;0.360436;, + 0.079220;0.380108;, + 0.099141;0.379715;, + 0.119274;0.399394;, + 0.000000;0.340959;, + 0.019699;0.340900;, + 0.039414;0.340723;, + 0.059162;0.340431;, + 0.079102;0.360078;, + 0.098996;0.359624;, + 0.119137;0.379245;, + 0.000000;0.320987;, + 0.019654;0.320921;, + 0.039326;0.320725;, + 0.059031;0.320400;, + 0.078959;0.340026;, + 0.098820;0.339512;, + 0.118967;0.359079;, + 0.000000;0.300983;, + 0.019601;0.300911;, + 0.039220;0.300695;, + 0.058873;0.300339;, + 0.078786;0.319949;, + 0.098608;0.319378;, + 0.118761;0.338896;, + 0.000000;0.280944;, + 0.019537;0.280865;, + 0.039093;0.280632;, + 0.058685;0.280245;, + 0.078579;0.299845;, + 0.098354;0.299219;, + 0.118512;0.318693;, + 0.000000;0.260865;, + 0.019461;0.260782;, + 0.038940;0.260531;, + 0.058458;0.260116;, + 0.078331;0.279710;, + 0.098049;0.279031;, + 0.118214;0.298468;, + 0.000000;0.240746;, + 0.019368;0.240656;, + 0.038756;0.240390;, + 0.058185;0.239949;, + 0.078033;0.259542;, + 0.097683;0.258815;, + 0.117857;0.278218;, + 0.000000;0.220581;, + 0.019256;0.220487;, + 0.038532;0.220206;, + 0.057852;0.219742;, + 0.077673;0.239339;, + 0.097241;0.238566;, + 0.117427;0.257942;, + 0.000000;0.200369;, + 0.019117;0.200270;, + 0.038256;0.199977;, + 0.057441;0.199491;, + 0.077234;0.219098;, + 0.096701;0.218283;, + 0.116907;0.237638;, + 0.000000;0.180106;, + 0.018943;0.180004;, + 0.037911;0.179699;, + 0.056927;0.179195;, + 0.076693;0.198818;, + 0.096035;0.197965;, + 0.116273;0.217306;, + 0.000000;0.159790;, + 0.018722;0.159685;, + 0.037469;0.159371;, + 0.056269;0.158852;, + 0.076015;0.178497;, + 0.095200;0.177612;, + 0.115489;0.196943;, + 0.000000;0.139418;, + 0.018431;0.139311;, + 0.036889;0.138991;, + 0.055404;0.138462;, + 0.075147;0.158133;, + 0.094129;0.157222;, + 0.114505;0.176551;, + 0.000000;0.118988;, + 0.018034;0.118881;, + 0.036098;0.118558;, + 0.054224;0.118023;, + 0.074004;0.137728;, + 0.092716;0.136798;, + 0.113241;0.156129;, + 0.000000;0.098499;, + 0.017466;0.098391;, + 0.034964;0.098071;, + 0.052529;0.097539;, + 0.072442;0.117283;, + 0.090783;0.116343;, + 0.111572;0.135682;, + 0.000000;0.077947;, + 0.016589;0.077843;, + 0.033212;0.077531;, + 0.049905;0.077015;, + 0.070193;0.096802;, + 0.087993;0.095865;, + 0.109280;0.115214;, + 0.000000;0.057331;, + 0.015068;0.057235;, + 0.030169;0.056947;, + 0.045335;0.056469;, + 0.066704;0.076298;, + 0.083646;0.075386;, + 0.105963;0.094739;, + 0.000000;0.036650;, + 0.011809;0.036574;, + 0.023630;0.036345;, + 0.035474;0.035964;, + 0.060599;0.055804;, + 0.076001;0.054956;, + 0.100771;0.074287;, + 0.047356;0.035434;, + 0.059289;0.034756;, + 0.091578;0.053932;, + 0.118123;0.073010;, + 0.124143;0.093434;, + 0.071290;0.033933;, + 0.107378;0.052737;, + 0.135749;0.071568;, + 0.142571;0.091964;, + 0.146877;0.112439;, + 0.127967;0.113908;, + 0.083377;0.032969;, + 0.123450;0.051381;, + 0.153698;0.069974;, + 0.161289;0.090346;, + 0.166044;0.110825;, + 0.095574;0.031868;, + 0.139852;0.049874;, + 0.172027;0.068246;, + 0.180341;0.088598;, + 0.185504;0.109087;, + 0.107907;0.030635;, + 0.156652;0.048229;, + 0.190796;0.066402;, + 0.199772;0.086742;, + 0.205291;0.107246;, + 0.120410;0.029275;, + 0.173930;0.046459;, + 0.210069;0.064466;, + 0.219628;0.084803;, + 0.225440;0.105330;, + 0.133128;0.027795;, + 0.191778;0.044582;, + 0.229918;0.062463;, + 0.239955;0.082810;, + 0.245984;0.103368;, + 0.146118;0.026202;, + 0.210305;0.042618;, + 0.250416;0.060422;, + 0.260798;0.080794;, + 0.266951;0.101391;, + 0.159455;0.024503;, + 0.229640;0.040590;, + 0.271639;0.058378;, + 0.282198;0.078789;, + 0.288367;0.099434;, + 0.173243;0.022708;, + 0.249934;0.038527;, + 0.293659;0.056366;, + 0.304189;0.076835;, + 0.310249;0.097534;, + 0.187629;0.020826;, + 0.271361;0.036461;, + 0.316540;0.054429;, + 0.326796;0.074969;, + 0.332604;0.095730;, + 0.202825;0.018870;, + 0.294112;0.034431;, + 0.340332;0.052612;, + 0.350026;0.073236;, + 0.355430;0.094062;, + 0.219152;0.016852;, + 0.373869;0.071676;, + 0.378707;0.092568;, + 0.402400;0.091285;, + 0.404964;0.112338;, + 0.381747;0.113568;, + 0.358855;0.115005;, + 0.426454;0.090248;, + 0.428460;0.111345;, + 0.429818;0.132516;, + 0.406707;0.133469;, + 0.383824;0.134651;, + 0.452177;0.110616;, + 0.453108;0.131817;, + 0.453775;0.153086;, + 0.430793;0.153755;, + 0.407963;0.154668;, + 0.476049;0.110170;, + 0.476522;0.131390;, + 0.476861;0.152677;, + 0.477114;0.174028;, + 0.454274;0.174419;, + 0.431524;0.175059;, + 0.500000;0.131247;, + 0.500000;0.152539;, + 0.500000;0.173897;, + 0.500000;0.195318;, + 0.477309;0.195442;, + 0.454659;0.195814;, + 0.523478;0.131390;, + 0.523139;0.152677;, + 0.522886;0.174028;, + 0.522691;0.195442;, + 0.500000;0.216799;, + 0.477463;0.216917;, + 0.546892;0.131817;, + 0.546225;0.153086;, + 0.545726;0.174419;, + 0.545341;0.195814;, + 0.522537;0.216917;, + 0.500000;0.238339;, + 0.570182;0.132516;, + 0.569207;0.153755;, + 0.568476;0.175059;, + 0.567911;0.196423;, + 0.545037;0.217269;, + 0.522413;0.238450;, + 0.593293;0.133469;, + 0.592037;0.154668;, + 0.591094;0.175932;, + 0.590365;0.197254;, + 0.567465;0.217845;, + 0.544793;0.238780;, + 0.616176;0.134651;, + 0.614675;0.155803;, + 0.613546;0.177017;, + 0.612671;0.198287;, + 0.589789;0.218632;, + 0.567106;0.239322;, + 0.638793;0.136034;, + 0.637087;0.157131;, + 0.635800;0.178288;, + 0.634801;0.199498;, + 0.611978;0.219610;, + 0.589325;0.240062;, + 0.661115;0.137586;, + 0.659247;0.158623;, + 0.657833;0.179716;, + 0.656733;0.200859;, + 0.634008;0.220756;, + 0.611420;0.240982;, + 0.683123;0.139271;, + 0.681135;0.160245;, + 0.679627;0.181271;, + 0.678451;0.202340;, + 0.655859;0.222045;, + 0.633369;0.242060;, + 0.704806;0.141054;, + 0.702742;0.161963;, + 0.701172;0.182918;, + 0.699943;0.203911;, + 0.677514;0.223449;, + 0.655153;0.243272;, + 0.726161;0.142899;, + 0.724064;0.163742;, + 0.722462;0.184626;, + 0.721206;0.205540;, + 0.698964;0.224937;, + 0.676757;0.244592;, + 0.747195;0.144771;, + 0.745101;0.165550;, + 0.743498;0.186361;, + 0.742238;0.207196;, + 0.720203;0.226481;, + 0.698170;0.245992;, + 0.767916;0.146637;, + 0.765863;0.167353;, + 0.764285;0.188094;, + 0.763043;0.208850;, + 0.741229;0.228051;, + 0.719389;0.247445;, + 0.788341;0.148465;, + 0.786360;0.169122;, + 0.784833;0.189794;, + 0.783628;0.210474;, + 0.762046;0.229619;, + 0.740410;0.248922;, + 0.808489;0.150227;, + 0.806608;0.170828;, + 0.805155;0.191434;, + 0.804006;0.212041;, + 0.782660;0.231158;, + 0.761235;0.250397;, + 0.828380;0.151896;, + 0.826625;0.172445;, + 0.825265;0.192990;, + 0.824188;0.213528;, + 0.803081;0.232644;, + 0.781871;0.251845;, + 0.848039;0.153450;, + 0.846431;0.173951;, + 0.845182;0.194440;, + 0.844191;0.214913;, + 0.823319;0.234055;, + 0.802326;0.253243;, + 0.867491;0.154866;, + 0.866047;0.175325;, + 0.864924;0.195763;, + 0.864031;0.216178;, + 0.843390;0.235368;, + 0.822610;0.254570;, + 0.886759;0.156129;, + 0.885495;0.176551;, + 0.884511;0.196943;, + 0.883727;0.217306;, + 0.863309;0.236568;, + 0.842736;0.255806;, + 0.883093;0.237638;, + 0.862718;0.256935;, + 0.842196;0.276227;, + 0.822025;0.275074;, + 0.801704;0.273836;, + 0.882573;0.257942;, + 0.862230;0.277279;, + 0.841747;0.296630;, + 0.821539;0.295565;, + 0.801189;0.294423;, + 0.882143;0.278218;, + 0.861824;0.297601;, + 0.841373;0.317016;, + 0.821135;0.316045;, + 0.800760;0.315003;, + 0.881786;0.298468;, + 0.861486;0.317903;, + 0.841062;0.337388;, + 0.820798;0.336514;, + 0.800403;0.335576;, + 0.881488;0.318693;, + 0.861205;0.338185;, + 0.840804;0.357746;, + 0.820519;0.356973;, + 0.800107;0.356144;, + 0.881239;0.338896;, + 0.860971;0.358451;, + 0.840591;0.378091;, + 0.820290;0.377423;, + 0.799864;0.376706;, + 0.881033;0.359079;, + 0.860778;0.378701;, + 0.840419;0.398426;, + 0.820104;0.397865;, + 0.799668;0.397263;, + 0.880863;0.379245;, + 0.860623;0.398938;, + 0.840284;0.418752;, + 0.819958;0.418300;, + 0.799513;0.417815;, + 0.880726;0.399394;, + 0.860500;0.419164;, + 0.840181;0.439070;, + 0.819847;0.438730;, + 0.799396;0.438365;, + 0.880617;0.419531;, + 0.860407;0.439381;, + 0.840109;0.459383;, + 0.819770;0.459156;, + 0.799314;0.458911;, + 0.880535;0.439658;, + 0.860342;0.459591;, + 0.840067;0.479693;, + 0.819724;0.479579;, + 0.799265;0.479456;, + 0.880478;0.459776;, + 0.860303;0.479797;, + 0.840053;0.500000;, + 0.819709;0.500000;, + 0.799249;0.500000;, + 0.880444;0.479889;, + 0.860290;0.500000;, + 0.840067;0.520307;, + 0.819724;0.520421;, + 0.799265;0.520544;, + 0.880433;0.500000;, + 0.860303;0.520203;, + 0.840109;0.540617;, + 0.819770;0.540844;, + 0.799314;0.541089;, + 0.880444;0.520111;, + 0.860342;0.540409;, + 0.840181;0.560930;, + 0.819847;0.561270;, + 0.799396;0.561636;, + 0.880478;0.540224;, + 0.860407;0.560619;, + 0.840284;0.581248;, + 0.819958;0.581700;, + 0.799513;0.582185;, + 0.880535;0.560342;, + 0.860500;0.580836;, + 0.840419;0.601574;, + 0.820104;0.602135;, + 0.799668;0.602738;, + 0.880617;0.580469;, + 0.860623;0.601062;, + 0.840591;0.621909;, + 0.820290;0.622577;, + 0.799864;0.623294;, + 0.880726;0.600606;, + 0.860778;0.621299;, + 0.840804;0.642254;, + 0.820519;0.643027;, + 0.800107;0.643856;, + 0.880863;0.620755;, + 0.860971;0.641549;, + 0.841062;0.662612;, + 0.820798;0.663486;, + 0.800403;0.664424;, + 0.881033;0.640921;, + 0.861205;0.661815;, + 0.841373;0.682984;, + 0.821135;0.683955;, + 0.800760;0.684997;, + 0.881239;0.661104;, + 0.861486;0.682097;, + 0.841747;0.703370;, + 0.821539;0.704435;, + 0.801189;0.705577;, + 0.881488;0.681307;, + 0.861824;0.702399;, + 0.842196;0.723773;, + 0.822025;0.724926;, + 0.801704;0.726164;, + 0.881786;0.701532;, + 0.862230;0.722721;, + 0.842736;0.744194;, + 0.822610;0.745430;, + 0.802326;0.746757;, + 0.882143;0.721782;, + 0.862718;0.743065;, + 0.843390;0.764631;, + 0.823319;0.765945;, + 0.803081;0.767355;, + 0.882573;0.742058;, + 0.863309;0.763432;, + 0.844191;0.785087;, + 0.824188;0.786472;, + 0.804006;0.787959;, + 0.883093;0.762362;, + 0.864031;0.783822;, + 0.845182;0.805560;, + 0.825265;0.807010;, + 0.805155;0.808566;, + 0.883727;0.782694;, + 0.864924;0.804237;, + 0.846431;0.826049;, + 0.826625;0.827555;, + 0.806608;0.829172;, + 0.884511;0.803057;, + 0.866047;0.824675;, + 0.848039;0.846550;, + 0.828380;0.848104;, + 0.808489;0.849773;, + 0.885495;0.823449;, + 0.867491;0.845134;, + 0.850174;0.867058;, + 0.830717;0.868649;, + 0.811000;0.870359;, + 0.886759;0.843871;, + 0.869402;0.865609;, + 0.888428;0.864319;, + 0.790996;0.872167;, + 0.788341;0.851535;, + 0.786360;0.830878;, + 0.770677;0.874045;, + 0.767916;0.853363;, + 0.765863;0.832647;, + 0.784833;0.810206;, + 0.783628;0.789526;, + 0.750021;0.875964;, + 0.747195;0.855229;, + 0.745101;0.834450;, + 0.764285;0.811906;, + 0.763043;0.791150;, + 0.782660;0.768842;, + 0.729005;0.877893;, + 0.726161;0.857101;, + 0.724064;0.836258;, + 0.743498;0.813639;, + 0.742238;0.792804;, + 0.762046;0.770381;, + 0.707615;0.879797;, + 0.704806;0.858946;, + 0.702742;0.838037;, + 0.722462;0.815374;, + 0.721206;0.794460;, + 0.741229;0.771949;, + 0.685841;0.881640;, + 0.683123;0.860729;, + 0.681135;0.839755;, + 0.701172;0.817082;, + 0.699943;0.796089;, + 0.720203;0.773519;, + 0.663681;0.883385;, + 0.661115;0.862414;, + 0.659247;0.841377;, + 0.679627;0.818729;, + 0.678451;0.797660;, + 0.698964;0.775063;, + 0.641145;0.884995;, + 0.638793;0.863966;, + 0.637087;0.842869;, + 0.657833;0.820284;, + 0.656733;0.799141;, + 0.677514;0.776551;, + 0.618253;0.886432;, + 0.616176;0.865349;, + 0.614675;0.844197;, + 0.635800;0.821712;, + 0.634801;0.800502;, + 0.655859;0.777955;, + 0.593293;0.866532;, + 0.592037;0.845332;, + 0.613546;0.822983;, + 0.612671;0.801713;, + 0.634008;0.779244;, + 0.570182;0.867484;, + 0.569207;0.846245;, + 0.591094;0.824068;, + 0.590365;0.802746;, + 0.611978;0.780390;, + 0.546892;0.868183;, + 0.546225;0.846914;, + 0.568476;0.824941;, + 0.567911;0.803577;, + 0.589789;0.781368;, + 0.523951;0.889830;, + 0.523478;0.868610;, + 0.523139;0.847323;, + 0.545726;0.825581;, + 0.545341;0.804186;, + 0.567465;0.782155;, + 0.500000;0.911139;, + 0.500000;0.889980;, + 0.500000;0.868753;, + 0.500000;0.847461;, + 0.522886;0.825972;, + 0.476049;0.889830;, + 0.476522;0.868610;, + 0.476861;0.847323;, + 0.477114;0.825972;, + 0.500000;0.826103;, + 0.522691;0.804558;, + 0.452177;0.889384;, + 0.453108;0.868183;, + 0.453775;0.846914;, + 0.454274;0.825581;, + 0.454659;0.804186;, + 0.477309;0.804558;, + 0.428460;0.888655;, + 0.429818;0.867484;, + 0.430793;0.846245;, + 0.431524;0.824941;, + 0.432089;0.803577;, + 0.404964;0.887662;, + 0.406707;0.866532;, + 0.407963;0.845332;, + 0.408906;0.824068;, + 0.409635;0.802746;, + 0.381747;0.886432;, + 0.383824;0.865349;, + 0.385325;0.844197;, + 0.386454;0.822983;, + 0.387329;0.801713;, + 0.358855;0.884995;, + 0.361207;0.863966;, + 0.362913;0.842869;, + 0.364200;0.821712;, + 0.365199;0.800502;, + 0.336319;0.883385;, + 0.338885;0.862414;, + 0.340753;0.841377;, + 0.342167;0.820284;, + 0.343267;0.799141;, + 0.314159;0.881640;, + 0.316877;0.860729;, + 0.318865;0.839755;, + 0.320373;0.818729;, + 0.321549;0.797660;, + 0.292385;0.879797;, + 0.295194;0.858946;, + 0.297258;0.838037;, + 0.298828;0.817082;, + 0.300057;0.796089;, + 0.270995;0.877893;, + 0.273839;0.857101;, + 0.275936;0.836258;, + 0.277538;0.815374;, + 0.278794;0.794460;, + 0.249979;0.875964;, + 0.252805;0.855229;, + 0.254899;0.834450;, + 0.256502;0.813639;, + 0.257762;0.792804;, + 0.229323;0.874045;, + 0.232084;0.853363;, + 0.234137;0.832647;, + 0.235715;0.811906;, + 0.236957;0.791150;, + 0.209004;0.872167;, + 0.211659;0.851535;, + 0.213640;0.830878;, + 0.215167;0.810206;, + 0.216372;0.789526;, + 0.189000;0.870359;, + 0.191511;0.849773;, + 0.193392;0.829172;, + 0.194845;0.808566;, + 0.195994;0.787959;, + 0.169283;0.868649;, + 0.171620;0.848104;, + 0.173375;0.827555;, + 0.174735;0.807010;, + 0.175812;0.786472;, + 0.149825;0.867058;, + 0.151961;0.846550;, + 0.153569;0.826049;, + 0.154818;0.805560;, + 0.155809;0.785087;, + 0.130598;0.865609;, + 0.132509;0.845134;, + 0.133953;0.824675;, + 0.135076;0.804237;, + 0.135969;0.783822;, + 0.136691;0.763432;, + 0.156610;0.764631;, + 0.176681;0.765945;, + 0.137282;0.743065;, + 0.157264;0.744194;, + 0.177390;0.745430;, + 0.196919;0.767355;, + 0.217340;0.768842;, + 0.137770;0.722721;, + 0.157805;0.723773;, + 0.177975;0.724926;, + 0.197674;0.746757;, + 0.218129;0.748155;, + 0.237954;0.770381;, + 0.138176;0.702399;, + 0.158253;0.703370;, + 0.178461;0.704435;, + 0.198296;0.726164;, + 0.218778;0.727468;, + 0.238765;0.749603;, + 0.138514;0.682097;, + 0.158627;0.682984;, + 0.178865;0.683955;, + 0.198811;0.705577;, + 0.219316;0.706781;, + 0.239431;0.728819;, + 0.138795;0.661815;, + 0.158938;0.662612;, + 0.179202;0.663486;, + 0.199240;0.684997;, + 0.219763;0.686096;, + 0.239983;0.708029;, + 0.139029;0.641549;, + 0.159196;0.642254;, + 0.179481;0.643027;, + 0.199597;0.664424;, + 0.220134;0.665413;, + 0.240441;0.687235;, + 0.139222;0.621299;, + 0.159409;0.621909;, + 0.179710;0.622577;, + 0.199893;0.643856;, + 0.220442;0.644731;, + 0.240821;0.666437;, + 0.139377;0.601062;, + 0.159581;0.601574;, + 0.179896;0.602135;, + 0.200136;0.623294;, + 0.220695;0.624051;, + 0.241136;0.645638;, + 0.139500;0.580836;, + 0.159716;0.581248;, + 0.180042;0.581700;, + 0.200332;0.602738;, + 0.220899;0.603373;, + 0.241395;0.624836;, + 0.139593;0.560619;, + 0.159819;0.560930;, + 0.180153;0.561270;, + 0.200487;0.582185;, + 0.221061;0.582696;, + 0.241604;0.604032;, + 0.139658;0.540409;, + 0.159891;0.540617;, + 0.180230;0.540844;, + 0.200604;0.561636;, + 0.221182;0.562021;, + 0.241769;0.583227;, + 0.139697;0.520203;, + 0.159933;0.520307;, + 0.180276;0.520421;, + 0.200686;0.541089;, + 0.221267;0.541347;, + 0.241893;0.562421;, + 0.139710;0.500000;, + 0.159947;0.500000;, + 0.180291;0.500000;, + 0.200735;0.520544;, + 0.221318;0.520673;, + 0.241980;0.541614;, + 0.139697;0.479797;, + 0.159933;0.479693;, + 0.180276;0.479579;, + 0.200751;0.500000;, + 0.221334;0.500000;, + 0.242032;0.520807;, + 0.139658;0.459591;, + 0.159891;0.459383;, + 0.180230;0.459156;, + 0.200735;0.479456;, + 0.221318;0.479327;, + 0.242049;0.500000;, + 0.139593;0.439381;, + 0.159819;0.439070;, + 0.180153;0.438730;, + 0.200686;0.458911;, + 0.221267;0.458653;, + 0.242032;0.479193;, + 0.139500;0.419164;, + 0.159716;0.418752;, + 0.180042;0.418300;, + 0.200604;0.438365;, + 0.221182;0.437979;, + 0.241980;0.458386;, + 0.139377;0.398938;, + 0.159581;0.398426;, + 0.179896;0.397865;, + 0.200487;0.417815;, + 0.221061;0.417304;, + 0.241893;0.437579;, + 0.139222;0.378701;, + 0.159409;0.378091;, + 0.179710;0.377423;, + 0.200332;0.397263;, + 0.220899;0.396627;, + 0.241769;0.416773;, + 0.139029;0.358451;, + 0.159196;0.357746;, + 0.179481;0.356973;, + 0.200136;0.376706;, + 0.220695;0.375949;, + 0.241604;0.395968;, + 0.138795;0.338185;, + 0.158938;0.337388;, + 0.179202;0.336514;, + 0.199893;0.356144;, + 0.220442;0.355269;, + 0.241395;0.375165;, + 0.138514;0.317903;, + 0.158627;0.317016;, + 0.178865;0.316045;, + 0.199597;0.335576;, + 0.220134;0.334587;, + 0.241136;0.354362;, + 0.138176;0.297601;, + 0.158253;0.296630;, + 0.178461;0.295565;, + 0.199240;0.315003;, + 0.219763;0.313904;, + 0.240821;0.333563;, + 0.137770;0.277279;, + 0.157805;0.276227;, + 0.177975;0.275074;, + 0.198811;0.294423;, + 0.219316;0.293219;, + 0.240441;0.312765;, + 0.137282;0.256935;, + 0.157264;0.255806;, + 0.177390;0.254570;, + 0.198296;0.273836;, + 0.218778;0.272532;, + 0.239983;0.291971;, + 0.136691;0.236568;, + 0.156610;0.235368;, + 0.176681;0.234055;, + 0.197674;0.253243;, + 0.218129;0.251845;, + 0.239431;0.271181;, + 0.135969;0.216178;, + 0.155809;0.214913;, + 0.175812;0.213528;, + 0.196919;0.232644;, + 0.217340;0.231158;, + 0.238765;0.250397;, + 0.135076;0.195763;, + 0.154818;0.194440;, + 0.174735;0.192990;, + 0.195994;0.212041;, + 0.216372;0.210474;, + 0.237954;0.229619;, + 0.133953;0.175325;, + 0.153569;0.173951;, + 0.173375;0.172445;, + 0.194845;0.191434;, + 0.215167;0.189794;, + 0.236957;0.208850;, + 0.132509;0.154866;, + 0.151961;0.153450;, + 0.171620;0.151896;, + 0.193392;0.170828;, + 0.213640;0.169122;, + 0.235715;0.188094;, + 0.130598;0.134391;, + 0.149825;0.132942;, + 0.169283;0.131351;, + 0.191511;0.150227;, + 0.211659;0.148465;, + 0.234137;0.167353;, + 0.189000;0.129641;, + 0.209004;0.127833;, + 0.232084;0.146637;, + 0.254899;0.165550;, + 0.256502;0.186361;, + 0.229323;0.125955;, + 0.252805;0.144771;, + 0.275936;0.163742;, + 0.277538;0.184626;, + 0.278794;0.205540;, + 0.257762;0.207196;, + 0.249979;0.124036;, + 0.273839;0.142899;, + 0.297258;0.161963;, + 0.298828;0.182918;, + 0.300057;0.203911;, + 0.270995;0.122107;, + 0.295194;0.141054;, + 0.318865;0.160245;, + 0.320373;0.181271;, + 0.321549;0.202340;, + 0.292385;0.120203;, + 0.316877;0.139271;, + 0.340753;0.158623;, + 0.342167;0.179716;, + 0.343267;0.200859;, + 0.314159;0.118360;, + 0.338885;0.137586;, + 0.362913;0.157131;, + 0.364200;0.178288;, + 0.365199;0.199498;, + 0.336319;0.116615;, + 0.361207;0.136034;, + 0.385325;0.155803;, + 0.386454;0.177017;, + 0.387329;0.198287;, + 0.408906;0.175932;, + 0.409635;0.197254;, + 0.410211;0.218632;, + 0.388022;0.219610;, + 0.365992;0.220756;, + 0.432089;0.196423;, + 0.432535;0.217845;, + 0.432894;0.239322;, + 0.410675;0.240062;, + 0.388580;0.240982;, + 0.454963;0.217269;, + 0.455207;0.238780;, + 0.455406;0.260346;, + 0.433185;0.260851;, + 0.411053;0.261541;, + 0.477587;0.238450;, + 0.477688;0.260038;, + 0.477770;0.281677;, + 0.455569;0.281962;, + 0.433425;0.282429;, + 0.500000;0.259934;, + 0.500000;0.281581;, + 0.500000;0.303277;, + 0.477838;0.303364;, + 0.455704;0.303625;, + 0.522312;0.260038;, + 0.522230;0.281677;, + 0.522162;0.303364;, + 0.500000;0.325017;, + 0.477894;0.325096;, + 0.544594;0.260346;, + 0.544431;0.281962;, + 0.544296;0.303625;, + 0.522106;0.325096;, + 0.500000;0.346798;, + 0.566815;0.260851;, + 0.566575;0.282429;, + 0.566377;0.304051;, + 0.544185;0.325331;, + 0.522059;0.346868;, + 0.588947;0.261541;, + 0.588636;0.283066;, + 0.588380;0.304633;, + 0.566214;0.325715;, + 0.544094;0.347076;, + 0.610965;0.262399;, + 0.610591;0.283859;, + 0.610282;0.305358;, + 0.588168;0.326240;, + 0.566079;0.347416;, + 0.632847;0.263405;, + 0.632418;0.284788;, + 0.632063;0.306206;, + 0.610026;0.326892;, + 0.587993;0.347881;, + 0.654576;0.264536;, + 0.654101;0.285833;, + 0.653708;0.307160;, + 0.631770;0.327657;, + 0.609816;0.348458;, + 0.676137;0.265767;, + 0.675627;0.286970;, + 0.675204;0.308199;, + 0.653383;0.328516;, + 0.631528;0.349135;, + 0.697521;0.267073;, + 0.696985;0.288177;, + 0.696541;0.309301;, + 0.674854;0.329452;, + 0.653115;0.349896;, + 0.718721;0.268428;, + 0.718170;0.289428;, + 0.717713;0.310444;, + 0.696173;0.330444;, + 0.674565;0.350725;, + 0.739737;0.269805;, + 0.739181;0.290700;, + 0.738719;0.311605;, + 0.717334;0.331473;, + 0.695868;0.351603;, + 0.760569;0.271181;, + 0.760017;0.291971;, + 0.759559;0.312765;, + 0.738336;0.332518;, + 0.717021;0.352513;, + 0.781222;0.272532;, + 0.780684;0.293219;, + 0.780237;0.313904;, + 0.759179;0.333563;, + 0.738019;0.353439;, + 0.779866;0.334587;, + 0.758864;0.354362;, + 0.737759;0.374365;, + 0.716764;0.373564;, + 0.695619;0.372776;, + 0.779558;0.355269;, + 0.758605;0.375165;, + 0.737549;0.395297;, + 0.716556;0.394624;, + 0.695418;0.393961;, + 0.779305;0.375949;, + 0.758396;0.395968;, + 0.737383;0.416232;, + 0.716392;0.415690;, + 0.695259;0.415157;, + 0.779101;0.396627;, + 0.758231;0.416773;, + 0.737258;0.437171;, + 0.716269;0.436763;, + 0.695139;0.436360;, + 0.778939;0.417304;, + 0.758107;0.437579;, + 0.737170;0.458113;, + 0.716182;0.457839;, + 0.695056;0.457570;, + 0.778818;0.437979;, + 0.758020;0.458386;, + 0.737119;0.479056;, + 0.716131;0.478919;, + 0.695006;0.478784;, + 0.778733;0.458653;, + 0.757968;0.479193;, + 0.737102;0.500000;, + 0.716115;0.500000;, + 0.694990;0.500000;, + 0.778682;0.479327;, + 0.757951;0.500000;, + 0.737119;0.520944;, + 0.716131;0.521081;, + 0.695006;0.521216;, + 0.778665;0.500000;, + 0.757968;0.520807;, + 0.737170;0.541887;, + 0.716182;0.542161;, + 0.695056;0.542430;, + 0.778682;0.520673;, + 0.758020;0.541614;, + 0.737258;0.562829;, + 0.716269;0.563237;, + 0.695139;0.563639;, + 0.778733;0.541347;, + 0.758107;0.562421;, + 0.737383;0.583768;, + 0.716392;0.584310;, + 0.695259;0.584843;, + 0.778818;0.562021;, + 0.758231;0.583227;, + 0.737549;0.604703;, + 0.716556;0.605376;, + 0.695418;0.606039;, + 0.778939;0.582696;, + 0.758396;0.604032;, + 0.737759;0.625635;, + 0.716764;0.626436;, + 0.695619;0.627224;, + 0.779101;0.603373;, + 0.758605;0.624836;, + 0.738019;0.646561;, + 0.717021;0.647487;, + 0.695868;0.648397;, + 0.779305;0.624051;, + 0.758864;0.645638;, + 0.738336;0.667482;, + 0.717334;0.668528;, + 0.696173;0.669556;, + 0.779558;0.644731;, + 0.759179;0.666437;, + 0.738719;0.688395;, + 0.717713;0.689556;, + 0.696541;0.690699;, + 0.779866;0.665413;, + 0.759559;0.687235;, + 0.739181;0.709299;, + 0.718170;0.710572;, + 0.696985;0.711823;, + 0.780237;0.686096;, + 0.760017;0.708029;, + 0.739737;0.730195;, + 0.718721;0.731572;, + 0.697521;0.732927;, + 0.780684;0.706781;, + 0.760569;0.728819;, + 0.740410;0.751078;, + 0.719389;0.752555;, + 0.698170;0.754008;, + 0.781222;0.727468;, + 0.761235;0.749603;, + 0.781871;0.748155;, + 0.676757;0.755408;, + 0.676137;0.734233;, + 0.675627;0.713030;, + 0.655153;0.756728;, + 0.654576;0.735464;, + 0.654101;0.714167;, + 0.675204;0.691801;, + 0.674854;0.670548;, + 0.633369;0.757940;, + 0.632847;0.736595;, + 0.632418;0.715212;, + 0.653708;0.692839;, + 0.653383;0.671484;, + 0.674565;0.649275;, + 0.611420;0.759018;, + 0.610965;0.737601;, + 0.610591;0.716141;, + 0.632063;0.693794;, + 0.631770;0.672343;, + 0.653115;0.650104;, + 0.589325;0.759938;, + 0.588947;0.738459;, + 0.588636;0.716934;, + 0.610282;0.694642;, + 0.610026;0.673108;, + 0.631528;0.650865;, + 0.567106;0.760678;, + 0.566815;0.739149;, + 0.566575;0.717571;, + 0.588380;0.695367;, + 0.588168;0.673760;, + 0.609816;0.651542;, + 0.545037;0.782731;, + 0.544793;0.761220;, + 0.544594;0.739654;, + 0.544431;0.718038;, + 0.566377;0.695949;, + 0.522537;0.783083;, + 0.522413;0.761550;, + 0.522312;0.739962;, + 0.522230;0.718323;, + 0.544296;0.696375;, + 0.566214;0.674285;, + 0.500000;0.804682;, + 0.500000;0.783201;, + 0.500000;0.761661;, + 0.500000;0.740066;, + 0.500000;0.718419;, + 0.522162;0.696636;, + 0.477463;0.783083;, + 0.477587;0.761550;, + 0.477688;0.739962;, + 0.477770;0.718323;, + 0.477838;0.696636;, + 0.500000;0.696723;, + 0.454963;0.782731;, + 0.455207;0.761220;, + 0.455406;0.739654;, + 0.455569;0.718038;, + 0.455704;0.696375;, + 0.432535;0.782155;, + 0.432894;0.760678;, + 0.433185;0.739149;, + 0.433425;0.717571;, + 0.433623;0.695949;, + 0.410211;0.781368;, + 0.410675;0.759938;, + 0.411053;0.738459;, + 0.411364;0.716934;, + 0.411620;0.695367;, + 0.388022;0.780390;, + 0.388580;0.759018;, + 0.389035;0.737601;, + 0.389409;0.716141;, + 0.389718;0.694642;, + 0.365992;0.779244;, + 0.366631;0.757940;, + 0.367153;0.736595;, + 0.367582;0.715212;, + 0.367937;0.693794;, + 0.344141;0.777955;, + 0.344847;0.756728;, + 0.345424;0.735464;, + 0.345899;0.714167;, + 0.346292;0.692839;, + 0.322486;0.776551;, + 0.323243;0.755408;, + 0.323863;0.734233;, + 0.324373;0.713030;, + 0.324796;0.691801;, + 0.301036;0.775063;, + 0.301830;0.754008;, + 0.302479;0.732927;, + 0.303015;0.711823;, + 0.303459;0.690699;, + 0.279797;0.773519;, + 0.280611;0.752555;, + 0.281279;0.731572;, + 0.281830;0.710572;, + 0.282287;0.689556;, + 0.258771;0.771949;, + 0.259590;0.751078;, + 0.260263;0.730195;, + 0.260819;0.709299;, + 0.261281;0.688395;, + 0.261664;0.667482;, + 0.282666;0.668528;, + 0.303827;0.669556;, + 0.261981;0.646561;, + 0.282979;0.647487;, + 0.304132;0.648397;, + 0.325146;0.670548;, + 0.346617;0.671484;, + 0.262241;0.625635;, + 0.283236;0.626436;, + 0.304381;0.627224;, + 0.325435;0.649275;, + 0.346885;0.650104;, + 0.368230;0.672343;, + 0.262451;0.604703;, + 0.283444;0.605376;, + 0.304582;0.606039;, + 0.325672;0.627984;, + 0.347105;0.628701;, + 0.368472;0.650865;, + 0.262617;0.583768;, + 0.283608;0.584310;, + 0.304741;0.584843;, + 0.325864;0.606678;, + 0.347282;0.607280;, + 0.368670;0.629360;, + 0.262742;0.562829;, + 0.283731;0.563237;, + 0.304861;0.563639;, + 0.326014;0.585358;, + 0.347422;0.585843;, + 0.368830;0.607834;, + 0.262830;0.541887;, + 0.283818;0.542161;, + 0.304944;0.542430;, + 0.326128;0.564028;, + 0.347527;0.564394;, + 0.368956;0.586290;, + 0.262881;0.520944;, + 0.283869;0.521081;, + 0.304994;0.521216;, + 0.326207;0.542689;, + 0.347601;0.542935;, + 0.369051;0.564730;, + 0.262898;0.500000;, + 0.283886;0.500000;, + 0.305010;0.500000;, + 0.326254;0.521346;, + 0.347644;0.521469;, + 0.369117;0.543160;, + 0.262881;0.479056;, + 0.283869;0.478919;, + 0.304994;0.478784;, + 0.326270;0.500000;, + 0.347659;0.500000;, + 0.369156;0.521582;, + 0.262830;0.458113;, + 0.283818;0.457839;, + 0.304944;0.457570;, + 0.326254;0.478654;, + 0.347644;0.478531;, + 0.369169;0.500000;, + 0.262742;0.437171;, + 0.283731;0.436763;, + 0.304861;0.436360;, + 0.326207;0.457311;, + 0.347601;0.457065;, + 0.369156;0.478418;, + 0.262617;0.416232;, + 0.283608;0.415690;, + 0.304741;0.415157;, + 0.326128;0.435972;, + 0.347527;0.435606;, + 0.369117;0.456840;, + 0.262451;0.395297;, + 0.283444;0.394624;, + 0.304582;0.393961;, + 0.326014;0.414642;, + 0.347422;0.414157;, + 0.369051;0.435270;, + 0.262241;0.374365;, + 0.283236;0.373564;, + 0.304381;0.372776;, + 0.325864;0.393322;, + 0.347282;0.392720;, + 0.368956;0.413710;, + 0.261981;0.353439;, + 0.282979;0.352513;, + 0.304132;0.351603;, + 0.325672;0.372016;, + 0.347105;0.371299;, + 0.368830;0.392166;, + 0.261664;0.332518;, + 0.282666;0.331473;, + 0.303827;0.330444;, + 0.325435;0.350725;, + 0.346885;0.349896;, + 0.368670;0.370640;, + 0.261281;0.311605;, + 0.282287;0.310444;, + 0.303459;0.309301;, + 0.325146;0.329452;, + 0.346617;0.328516;, + 0.368472;0.349135;, + 0.260819;0.290700;, + 0.281830;0.289428;, + 0.303015;0.288177;, + 0.324796;0.308199;, + 0.346292;0.307160;, + 0.368230;0.327657;, + 0.260263;0.269805;, + 0.281279;0.268428;, + 0.302479;0.267073;, + 0.324373;0.286970;, + 0.345899;0.285833;, + 0.367937;0.306206;, + 0.259590;0.248922;, + 0.280611;0.247445;, + 0.301830;0.245992;, + 0.323863;0.265767;, + 0.345424;0.264536;, + 0.367582;0.284788;, + 0.258771;0.228051;, + 0.279797;0.226481;, + 0.301036;0.224937;, + 0.323243;0.244592;, + 0.344847;0.243272;, + 0.367153;0.263405;, + 0.322486;0.223449;, + 0.344141;0.222045;, + 0.366631;0.242060;, + 0.389035;0.262399;, + 0.389409;0.283859;, + 0.411364;0.283066;, + 0.411620;0.304633;, + 0.389718;0.305358;, + 0.389974;0.326892;, + 0.433623;0.304051;, + 0.433786;0.325715;, + 0.411832;0.326240;, + 0.412007;0.347881;, + 0.390184;0.348458;, + 0.455815;0.325331;, + 0.455906;0.347076;, + 0.433921;0.347416;, + 0.434031;0.369151;, + 0.412149;0.369553;, + 0.390357;0.370053;, + 0.477941;0.346868;, + 0.477979;0.368676;, + 0.455981;0.368856;, + 0.456042;0.390666;, + 0.434120;0.390914;, + 0.412265;0.391252;, + 0.500000;0.368615;, + 0.500000;0.390464;, + 0.478009;0.390515;, + 0.478033;0.412380;, + 0.456089;0.412502;, + 0.434189;0.412701;, + 0.522021;0.368676;, + 0.521991;0.390515;, + 0.500000;0.412339;, + 0.500000;0.434235;, + 0.478051;0.434266;, + 0.456125;0.434358;, + 0.544019;0.368856;, + 0.543958;0.390666;, + 0.521967;0.412380;, + 0.521949;0.434266;, + 0.500000;0.456148;, + 0.478064;0.456168;, + 0.565969;0.369151;, + 0.565880;0.390914;, + 0.543911;0.412502;, + 0.543875;0.434358;, + 0.521936;0.456168;, + 0.500000;0.478071;, + 0.587851;0.369553;, + 0.587735;0.391252;, + 0.565811;0.412701;, + 0.565758;0.434509;, + 0.543850;0.456230;, + 0.521929;0.478081;, + 0.609643;0.370053;, + 0.609504;0.391673;, + 0.587645;0.412974;, + 0.587577;0.434714;, + 0.565721;0.456331;, + 0.543836;0.478112;, + 0.631330;0.370640;, + 0.631170;0.392166;, + 0.609395;0.413313;, + 0.609312;0.434970;, + 0.587529;0.456469;, + 0.565700;0.478163;, + 0.652895;0.371299;, + 0.652718;0.392720;, + 0.631044;0.413710;, + 0.630949;0.435270;, + 0.609255;0.456640;, + 0.587501;0.478232;, + 0.674328;0.372016;, + 0.674136;0.393322;, + 0.652578;0.414157;, + 0.652473;0.435606;, + 0.630883;0.456840;, + 0.609221;0.478318;, + 0.673986;0.414642;, + 0.673872;0.435972;, + 0.652399;0.457065;, + 0.630844;0.478418;, + 0.609209;0.500000;, + 0.587491;0.500000;, + 0.673793;0.457311;, + 0.652356;0.478531;, + 0.630831;0.500000;, + 0.609221;0.521682;, + 0.587501;0.521768;, + 0.673746;0.478654;, + 0.652341;0.500000;, + 0.630844;0.521582;, + 0.609255;0.543360;, + 0.587529;0.543531;, + 0.673730;0.500000;, + 0.652356;0.521469;, + 0.630883;0.543160;, + 0.609312;0.565030;, + 0.587577;0.565286;, + 0.673746;0.521346;, + 0.652399;0.542935;, + 0.630949;0.564730;, + 0.609395;0.586687;, + 0.587645;0.587026;, + 0.673793;0.542689;, + 0.652473;0.564394;, + 0.631044;0.586290;, + 0.609504;0.608327;, + 0.587735;0.608748;, + 0.673872;0.564028;, + 0.652578;0.585843;, + 0.631170;0.607834;, + 0.609643;0.629947;, + 0.587851;0.630447;, + 0.673986;0.585358;, + 0.652718;0.607280;, + 0.631330;0.629360;, + 0.587993;0.652119;, + 0.674136;0.606678;, + 0.652895;0.628701;, + 0.674328;0.627984;, + 0.566079;0.652584;, + 0.565969;0.630849;, + 0.565880;0.609086;, + 0.544185;0.674669;, + 0.544094;0.652924;, + 0.544019;0.631144;, + 0.543958;0.609334;, + 0.565811;0.587299;, + 0.522106;0.674904;, + 0.522059;0.653132;, + 0.522021;0.631324;, + 0.521991;0.609485;, + 0.543911;0.587498;, + 0.565758;0.565491;, + 0.500000;0.674983;, + 0.500000;0.653202;, + 0.500000;0.631385;, + 0.500000;0.609536;, + 0.521967;0.587620;, + 0.543875;0.565642;, + 0.477894;0.674904;, + 0.477941;0.653132;, + 0.477979;0.631324;, + 0.478009;0.609485;, + 0.478033;0.587620;, + 0.500000;0.587661;, + 0.455815;0.674669;, + 0.455906;0.652924;, + 0.455981;0.631144;, + 0.456042;0.609334;, + 0.456089;0.587498;, + 0.433786;0.674285;, + 0.433921;0.652584;, + 0.434031;0.630849;, + 0.434120;0.609086;, + 0.434189;0.587299;, + 0.411832;0.673760;, + 0.412007;0.652119;, + 0.412149;0.630447;, + 0.412265;0.608748;, + 0.412355;0.587026;, + 0.389974;0.673108;, + 0.390184;0.651542;, + 0.390357;0.629947;, + 0.390496;0.608327;, + 0.390605;0.586687;, + 0.390688;0.565030;, + 0.412423;0.565286;, + 0.434242;0.565491;, + 0.390745;0.543360;, + 0.412471;0.543531;, + 0.434279;0.543669;, + 0.456125;0.565642;, + 0.478051;0.565734;, + 0.390779;0.521682;, + 0.412499;0.521768;, + 0.434300;0.521837;, + 0.456150;0.543770;, + 0.478064;0.543832;, + 0.500000;0.565765;, + 0.390791;0.500000;, + 0.412509;0.500000;, + 0.434308;0.500000;, + 0.456164;0.521888;, + 0.478071;0.521919;, + 0.500000;0.543852;, + 0.390779;0.478318;, + 0.412499;0.478232;, + 0.434300;0.478163;, + 0.456169;0.500000;, + 0.478074;0.500000;, + 0.500000;0.521929;, + 0.390745;0.456640;, + 0.412471;0.456469;, + 0.434279;0.456331;, + 0.456164;0.478112;, + 0.478071;0.478081;, + 0.500000;0.500000;, + 0.390688;0.434970;, + 0.412423;0.434714;, + 0.434242;0.434509;, + 0.456150;0.456230;, + 0.390605;0.413313;, + 0.412355;0.412974;, + 0.390496;0.391673;, + 0.521926;0.500000;, + 0.521929;0.521919;, + 0.521936;0.543832;, + 0.543831;0.500000;, + 0.543836;0.521888;, + 0.543850;0.543770;, + 0.521949;0.565734;, + 0.565692;0.500000;, + 0.565700;0.521837;, + 0.565721;0.543669;; + } + + MeshMaterialList { + 1; + 4512; + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0; + + Material { + 1.000000;1.000000;1.000000;1.000000;; + 51.200000; + 0.000000;0.000000;0.000000;; + 0.000000;0.000000;0.000000;; + + TextureFilename { + "earth.jpg"; + } + } + } + } + } +} + +AnimationSet AnimationSet_sphere { + + + Animation { + + + AnimationKey { + 0; + 61; + 0;4;1.000000,0.000000,0.000000,0.000000;;, + 1;4;1.000000,0.000000,0.000000,0.000000;;, + 2;4;1.000000,0.000000,0.000000,0.000000;;, + 3;4;1.000000,0.000000,0.000000,0.000000;;, + 4;4;1.000000,0.000000,0.000000,0.000000;;, + 5;4;1.000000,0.000000,0.000000,0.000000;;, + 6;4;1.000000,0.000000,0.000000,0.000000;;, + 7;4;1.000000,0.000000,0.000000,0.000000;;, + 8;4;1.000000,0.000000,0.000000,0.000000;;, + 9;4;1.000000,0.000000,0.000000,0.000000;;, + 10;4;1.000000,0.000000,0.000000,0.000000;;, + 11;4;1.000000,0.000000,0.000000,0.000000;;, + 12;4;1.000000,0.000000,0.000000,0.000000;;, + 13;4;1.000000,0.000000,0.000000,0.000000;;, + 14;4;1.000000,0.000000,0.000000,0.000000;;, + 15;4;1.000000,0.000000,0.000000,0.000000;;, + 16;4;1.000000,0.000000,0.000000,0.000000;;, + 17;4;1.000000,0.000000,0.000000,0.000000;;, + 18;4;1.000000,0.000000,0.000000,0.000000;;, + 19;4;1.000000,0.000000,0.000000,0.000000;;, + 20;4;1.000000,0.000000,0.000000,0.000000;;, + 21;4;1.000000,0.000000,0.000000,0.000000;;, + 22;4;1.000000,0.000000,0.000000,0.000000;;, + 23;4;1.000000,0.000000,0.000000,0.000000;;, + 24;4;1.000000,0.000000,0.000000,0.000000;;, + 25;4;1.000000,0.000000,0.000000,0.000000;;, + 26;4;1.000000,0.000000,0.000000,0.000000;;, + 27;4;1.000000,0.000000,0.000000,0.000000;;, + 28;4;1.000000,0.000000,0.000000,0.000000;;, + 29;4;1.000000,0.000000,0.000000,0.000000;;, + 30;4;1.000000,0.000000,0.000000,0.000000;;, + 31;4;1.000000,0.000000,0.000000,0.000000;;, + 32;4;1.000000,0.000000,0.000000,0.000000;;, + 33;4;1.000000,0.000000,0.000000,0.000000;;, + 34;4;1.000000,0.000000,0.000000,0.000000;;, + 35;4;1.000000,0.000000,0.000000,0.000000;;, + 36;4;1.000000,0.000000,0.000000,0.000000;;, + 37;4;1.000000,0.000000,0.000000,0.000000;;, + 38;4;1.000000,0.000000,0.000000,0.000000;;, + 39;4;1.000000,0.000000,0.000000,0.000000;;, + 40;4;1.000000,0.000000,0.000000,0.000000;;, + 41;4;1.000000,0.000000,0.000000,0.000000;;, + 42;4;1.000000,0.000000,0.000000,0.000000;;, + 43;4;1.000000,0.000000,0.000000,0.000000;;, + 44;4;1.000000,0.000000,0.000000,0.000000;;, + 45;4;1.000000,0.000000,0.000000,0.000000;;, + 46;4;1.000000,0.000000,0.000000,0.000000;;, + 47;4;1.000000,0.000000,0.000000,0.000000;;, + 48;4;1.000000,0.000000,0.000000,0.000000;;, + 49;4;1.000000,0.000000,0.000000,0.000000;;, + 50;4;1.000000,0.000000,0.000000,0.000000;;, + 51;4;1.000000,0.000000,0.000000,0.000000;;, + 52;4;1.000000,0.000000,0.000000,0.000000;;, + 53;4;1.000000,0.000000,0.000000,0.000000;;, + 54;4;1.000000,0.000000,0.000000,0.000000;;, + 55;4;1.000000,0.000000,0.000000,0.000000;;, + 56;4;1.000000,0.000000,0.000000,0.000000;;, + 57;4;1.000000,0.000000,0.000000,0.000000;;, + 58;4;1.000000,0.000000,0.000000,0.000000;;, + 59;4;1.000000,0.000000,0.000000,0.000000;;, + 60;4;1.000000,0.000000,0.000000,0.000000;;; + } + + AnimationKey { + 1; + 61; + 0;3;1.000000,1.000000,1.000000;;, + 1;3;1.000000,1.000000,1.000000;;, + 2;3;1.000000,1.000000,1.000000;;, + 3;3;1.000000,1.000000,1.000000;;, + 4;3;1.000000,1.000000,1.000000;;, + 5;3;1.000000,1.000000,1.000000;;, + 6;3;1.000000,1.000000,1.000000;;, + 7;3;1.000000,1.000000,1.000000;;, + 8;3;1.000000,1.000000,1.000000;;, + 9;3;1.000000,1.000000,1.000000;;, + 10;3;1.000000,1.000000,1.000000;;, + 11;3;1.000000,1.000000,1.000000;;, + 12;3;1.000000,1.000000,1.000000;;, + 13;3;1.000000,1.000000,1.000000;;, + 14;3;1.000000,1.000000,1.000000;;, + 15;3;1.000000,1.000000,1.000000;;, + 16;3;1.000000,1.000000,1.000000;;, + 17;3;1.000000,1.000000,1.000000;;, + 18;3;1.000000,1.000000,1.000000;;, + 19;3;1.000000,1.000000,1.000000;;, + 20;3;1.000000,1.000000,1.000000;;, + 21;3;1.000000,1.000000,1.000000;;, + 22;3;1.000000,1.000000,1.000000;;, + 23;3;1.000000,1.000000,1.000000;;, + 24;3;1.000000,1.000000,1.000000;;, + 25;3;1.000000,1.000000,1.000000;;, + 26;3;1.000000,1.000000,1.000000;;, + 27;3;1.000000,1.000000,1.000000;;, + 28;3;1.000000,1.000000,1.000000;;, + 29;3;1.000000,1.000000,1.000000;;, + 30;3;1.000000,1.000000,1.000000;;, + 31;3;1.000000,1.000000,1.000000;;, + 32;3;1.000000,1.000000,1.000000;;, + 33;3;1.000000,1.000000,1.000000;;, + 34;3;1.000000,1.000000,1.000000;;, + 35;3;1.000000,1.000000,1.000000;;, + 36;3;1.000000,1.000000,1.000000;;, + 37;3;1.000000,1.000000,1.000000;;, + 38;3;1.000000,1.000000,1.000000;;, + 39;3;1.000000,1.000000,1.000000;;, + 40;3;1.000000,1.000000,1.000000;;, + 41;3;1.000000,1.000000,1.000000;;, + 42;3;1.000000,1.000000,1.000000;;, + 43;3;1.000000,1.000000,1.000000;;, + 44;3;1.000000,1.000000,1.000000;;, + 45;3;1.000000,1.000000,1.000000;;, + 46;3;1.000000,1.000000,1.000000;;, + 47;3;1.000000,1.000000,1.000000;;, + 48;3;1.000000,1.000000,1.000000;;, + 49;3;1.000000,1.000000,1.000000;;, + 50;3;1.000000,1.000000,1.000000;;, + 51;3;1.000000,1.000000,1.000000;;, + 52;3;1.000000,1.000000,1.000000;;, + 53;3;1.000000,1.000000,1.000000;;, + 54;3;1.000000,1.000000,1.000000;;, + 55;3;1.000000,1.000000,1.000000;;, + 56;3;1.000000,1.000000,1.000000;;, + 57;3;1.000000,1.000000,1.000000;;, + 58;3;1.000000,1.000000,1.000000;;, + 59;3;1.000000,1.000000,1.000000;;, + 60;3;1.000000,1.000000,1.000000;;; + } + + AnimationKey { + 2; + 61; + 0;3;0.000000,0.000000,0.000000;;, + 1;3;0.000000,0.000000,0.000000;;, + 2;3;0.000000,0.000000,0.000000;;, + 3;3;0.000000,0.000000,0.000000;;, + 4;3;0.000000,0.000000,0.000000;;, + 5;3;0.000000,0.000000,0.000000;;, + 6;3;0.000000,0.000000,0.000000;;, + 7;3;0.000000,0.000000,0.000000;;, + 8;3;0.000000,0.000000,0.000000;;, + 9;3;0.000000,0.000000,0.000000;;, + 10;3;0.000000,0.000000,0.000000;;, + 11;3;0.000000,0.000000,0.000000;;, + 12;3;0.000000,0.000000,0.000000;;, + 13;3;0.000000,0.000000,0.000000;;, + 14;3;0.000000,0.000000,0.000000;;, + 15;3;0.000000,0.000000,0.000000;;, + 16;3;0.000000,0.000000,0.000000;;, + 17;3;0.000000,0.000000,0.000000;;, + 18;3;0.000000,0.000000,0.000000;;, + 19;3;0.000000,0.000000,0.000000;;, + 20;3;0.000000,0.000000,0.000000;;, + 21;3;0.000000,0.000000,0.000000;;, + 22;3;0.000000,0.000000,0.000000;;, + 23;3;0.000000,0.000000,0.000000;;, + 24;3;0.000000,0.000000,0.000000;;, + 25;3;0.000000,0.000000,0.000000;;, + 26;3;0.000000,0.000000,0.000000;;, + 27;3;0.000000,0.000000,0.000000;;, + 28;3;0.000000,0.000000,0.000000;;, + 29;3;0.000000,0.000000,0.000000;;, + 30;3;0.000000,0.000000,0.000000;;, + 31;3;0.000000,0.000000,0.000000;;, + 32;3;0.000000,0.000000,0.000000;;, + 33;3;0.000000,0.000000,0.000000;;, + 34;3;0.000000,0.000000,0.000000;;, + 35;3;0.000000,0.000000,0.000000;;, + 36;3;0.000000,0.000000,0.000000;;, + 37;3;0.000000,0.000000,0.000000;;, + 38;3;0.000000,0.000000,0.000000;;, + 39;3;0.000000,0.000000,0.000000;;, + 40;3;0.000000,0.000000,0.000000;;, + 41;3;0.000000,0.000000,0.000000;;, + 42;3;0.000000,0.000000,0.000000;;, + 43;3;0.000000,0.000000,0.000000;;, + 44;3;0.000000,0.000000,0.000000;;, + 45;3;0.000000,0.000000,0.000000;;, + 46;3;0.000000,0.000000,0.000000;;, + 47;3;0.000000,0.000000,0.000000;;, + 48;3;0.000000,0.000000,0.000000;;, + 49;3;0.000000,0.000000,0.000000;;, + 50;3;0.000000,0.000000,0.000000;;, + 51;3;0.000000,0.000000,0.000000;;, + 52;3;0.000000,0.000000,0.000000;;, + 53;3;0.000000,0.000000,0.000000;;, + 54;3;0.000000,0.000000,0.000000;;, + 55;3;0.000000,0.000000,0.000000;;, + 56;3;0.000000,0.000000,0.000000;;, + 57;3;0.000000,0.000000,0.000000;;, + 58;3;0.000000,0.000000,0.000000;;, + 59;3;0.000000,0.000000,0.000000;;, + 60;3;0.000000,0.000000,0.000000;;; + } + { Frame1_sphere_lwo_layer1 } + } +} diff --git a/media/earthbump.jpg b/media/earthbump.jpg new file mode 100644 index 00000000..feb5ae48 Binary files /dev/null and b/media/earthbump.jpg differ diff --git a/media/enano.jpg b/media/enano.jpg new file mode 100644 index 00000000..b749eb95 Binary files /dev/null and b/media/enano.jpg differ diff --git a/media/example.irr b/media/example.irr new file mode 100644 index 00000000..4035bd5b Binary files /dev/null and b/media/example.irr differ diff --git a/media/example_screenshots/001shot.jpg b/media/example_screenshots/001shot.jpg new file mode 100644 index 00000000..b7438d61 Binary files /dev/null and b/media/example_screenshots/001shot.jpg differ diff --git a/media/example_screenshots/002shot.jpg b/media/example_screenshots/002shot.jpg new file mode 100644 index 00000000..a8659aa4 Binary files /dev/null and b/media/example_screenshots/002shot.jpg differ diff --git a/media/example_screenshots/003shot.jpg b/media/example_screenshots/003shot.jpg new file mode 100644 index 00000000..c4865f1b Binary files /dev/null and b/media/example_screenshots/003shot.jpg differ diff --git a/media/example_screenshots/004shot.jpg b/media/example_screenshots/004shot.jpg new file mode 100644 index 00000000..20091c24 Binary files /dev/null and b/media/example_screenshots/004shot.jpg differ diff --git a/media/example_screenshots/005shot.jpg b/media/example_screenshots/005shot.jpg new file mode 100644 index 00000000..9d1c975a Binary files /dev/null and b/media/example_screenshots/005shot.jpg differ diff --git a/media/example_screenshots/006shot.jpg b/media/example_screenshots/006shot.jpg new file mode 100644 index 00000000..8044e075 Binary files /dev/null and b/media/example_screenshots/006shot.jpg differ diff --git a/media/example_screenshots/007shot.jpg b/media/example_screenshots/007shot.jpg new file mode 100644 index 00000000..24ce868f Binary files /dev/null and b/media/example_screenshots/007shot.jpg differ diff --git a/media/example_screenshots/008shot.jpg b/media/example_screenshots/008shot.jpg new file mode 100644 index 00000000..529174ba Binary files /dev/null and b/media/example_screenshots/008shot.jpg differ diff --git a/media/example_screenshots/009shot.jpg b/media/example_screenshots/009shot.jpg new file mode 100644 index 00000000..9bfa1958 Binary files /dev/null and b/media/example_screenshots/009shot.jpg differ diff --git a/media/example_screenshots/010shot.jpg b/media/example_screenshots/010shot.jpg new file mode 100644 index 00000000..0e798d3f Binary files /dev/null and b/media/example_screenshots/010shot.jpg differ diff --git a/media/example_screenshots/011shot.jpg b/media/example_screenshots/011shot.jpg new file mode 100644 index 00000000..840a599c Binary files /dev/null and b/media/example_screenshots/011shot.jpg differ diff --git a/media/example_screenshots/012shot.jpg b/media/example_screenshots/012shot.jpg new file mode 100644 index 00000000..aefd2613 Binary files /dev/null and b/media/example_screenshots/012shot.jpg differ diff --git a/media/example_screenshots/013shot.jpg b/media/example_screenshots/013shot.jpg new file mode 100644 index 00000000..49640195 Binary files /dev/null and b/media/example_screenshots/013shot.jpg differ diff --git a/media/example_screenshots/014shot.jpg b/media/example_screenshots/014shot.jpg new file mode 100644 index 00000000..af6b7c65 Binary files /dev/null and b/media/example_screenshots/014shot.jpg differ diff --git a/media/example_screenshots/015shot.jpg b/media/example_screenshots/015shot.jpg new file mode 100644 index 00000000..9de0f8bf Binary files /dev/null and b/media/example_screenshots/015shot.jpg differ diff --git a/media/example_screenshots/016shot.jpg b/media/example_screenshots/016shot.jpg new file mode 100644 index 00000000..58f450f2 Binary files /dev/null and b/media/example_screenshots/016shot.jpg differ diff --git a/media/example_screenshots/017shot.jpg b/media/example_screenshots/017shot.jpg new file mode 100644 index 00000000..0ff80d2b Binary files /dev/null and b/media/example_screenshots/017shot.jpg differ diff --git a/media/example_screenshots/018shot.jpg b/media/example_screenshots/018shot.jpg new file mode 100644 index 00000000..0cba94ce Binary files /dev/null and b/media/example_screenshots/018shot.jpg differ diff --git a/media/example_screenshots/019shot.jpg b/media/example_screenshots/019shot.jpg new file mode 100644 index 00000000..8faa9157 Binary files /dev/null and b/media/example_screenshots/019shot.jpg differ diff --git a/media/example_screenshots/020shot.jpg b/media/example_screenshots/020shot.jpg new file mode 100644 index 00000000..da5d98b8 Binary files /dev/null and b/media/example_screenshots/020shot.jpg differ diff --git a/media/example_screenshots/021shot.jpg b/media/example_screenshots/021shot.jpg new file mode 100644 index 00000000..48b28d7f Binary files /dev/null and b/media/example_screenshots/021shot.jpg differ diff --git a/media/example_screenshots/022shot.jpg b/media/example_screenshots/022shot.jpg new file mode 100644 index 00000000..c2821974 Binary files /dev/null and b/media/example_screenshots/022shot.jpg differ diff --git a/media/example_screenshots/023shot.jpg b/media/example_screenshots/023shot.jpg new file mode 100644 index 00000000..2be47ce4 Binary files /dev/null and b/media/example_screenshots/023shot.jpg differ diff --git a/media/example_screenshots/024shot.jpg b/media/example_screenshots/024shot.jpg new file mode 100644 index 00000000..9cfc0d18 Binary files /dev/null and b/media/example_screenshots/024shot.jpg differ diff --git a/media/example_screenshots/025shot.jpg b/media/example_screenshots/025shot.jpg new file mode 100644 index 00000000..91c81160 Binary files /dev/null and b/media/example_screenshots/025shot.jpg differ diff --git a/media/example_screenshots/026shot.jpg b/media/example_screenshots/026shot.jpg new file mode 100644 index 00000000..b2acfcf0 Binary files /dev/null and b/media/example_screenshots/026shot.jpg differ diff --git a/media/example_screenshots/027shot.jpg b/media/example_screenshots/027shot.jpg new file mode 100644 index 00000000..274bada7 Binary files /dev/null and b/media/example_screenshots/027shot.jpg differ diff --git a/media/example_screenshots/028shot.jpg b/media/example_screenshots/028shot.jpg new file mode 100644 index 00000000..84ee7f31 Binary files /dev/null and b/media/example_screenshots/028shot.jpg differ diff --git a/media/faerie.md2 b/media/faerie.md2 new file mode 100644 index 00000000..74ce5a8d Binary files /dev/null and b/media/faerie.md2 differ diff --git a/media/faerie2.bmp b/media/faerie2.bmp new file mode 100644 index 00000000..56a486a6 Binary files /dev/null and b/media/faerie2.bmp differ diff --git a/media/fire.bmp b/media/fire.bmp new file mode 100644 index 00000000..c33be5ce Binary files /dev/null and b/media/fire.bmp differ diff --git a/media/fireball.bmp b/media/fireball.bmp new file mode 100644 index 00000000..f14bdc1e Binary files /dev/null and b/media/fireball.bmp differ diff --git a/media/fontcourier.bmp b/media/fontcourier.bmp new file mode 100644 index 00000000..e6dae7e4 Binary files /dev/null and b/media/fontcourier.bmp differ diff --git a/media/fonthaettenschweiler.bmp b/media/fonthaettenschweiler.bmp new file mode 100644 index 00000000..d2786d8e Binary files /dev/null and b/media/fonthaettenschweiler.bmp differ diff --git a/media/fontlucida.png b/media/fontlucida.png new file mode 100644 index 00000000..b81ec9f3 Binary files /dev/null and b/media/fontlucida.png differ diff --git a/media/gun.jpg b/media/gun.jpg new file mode 100644 index 00000000..0e954982 Binary files /dev/null and b/media/gun.jpg differ diff --git a/media/gun.md2 b/media/gun.md2 new file mode 100644 index 00000000..082d07c7 Binary files /dev/null and b/media/gun.md2 differ diff --git a/media/help.png b/media/help.png new file mode 100644 index 00000000..f0b909aa Binary files /dev/null and b/media/help.png differ diff --git a/media/icon_crosshairs16x16bw1.png b/media/icon_crosshairs16x16bw1.png new file mode 100644 index 00000000..314bb0f7 Binary files /dev/null and b/media/icon_crosshairs16x16bw1.png differ diff --git a/media/icon_crosshairs16x16bw2.png b/media/icon_crosshairs16x16bw2.png new file mode 100644 index 00000000..7aca0717 Binary files /dev/null and b/media/icon_crosshairs16x16bw2.png differ diff --git a/media/icon_crosshairs16x16bw3.png b/media/icon_crosshairs16x16bw3.png new file mode 100644 index 00000000..0f82a883 Binary files /dev/null and b/media/icon_crosshairs16x16bw3.png differ diff --git a/media/icon_crosshairs16x16col.png b/media/icon_crosshairs16x16col.png new file mode 100644 index 00000000..335ee10e Binary files /dev/null and b/media/icon_crosshairs16x16col.png differ diff --git a/media/iconlist.png b/media/iconlist.png new file mode 100644 index 00000000..e22ce8bf Binary files /dev/null and b/media/iconlist.png differ diff --git a/media/impact.wav b/media/impact.wav new file mode 100644 index 00000000..36396179 Binary files /dev/null and b/media/impact.wav differ diff --git a/media/info_ios.plist b/media/info_ios.plist new file mode 100644 index 00000000..bbd8066e --- /dev/null +++ b/media/info_ios.plist @@ -0,0 +1,46 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UIRequiresFullScreen + + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/media/info_osx.plist b/media/info_osx.plist new file mode 100644 index 00000000..908cdd4d --- /dev/null +++ b/media/info_osx.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSPrincipalClass + NSApplication + + diff --git a/media/irr.ico b/media/irr.ico new file mode 100644 index 00000000..49f8eabb Binary files /dev/null and b/media/irr.ico differ diff --git a/media/irrlicht.dat b/media/irrlicht.dat new file mode 100644 index 00000000..30178bd0 Binary files /dev/null and b/media/irrlicht.dat differ diff --git a/media/irrlicht2_bk.jpg b/media/irrlicht2_bk.jpg new file mode 100644 index 00000000..509446b8 Binary files /dev/null and b/media/irrlicht2_bk.jpg differ diff --git a/media/irrlicht2_dn.jpg b/media/irrlicht2_dn.jpg new file mode 100644 index 00000000..4735dbee Binary files /dev/null and b/media/irrlicht2_dn.jpg differ diff --git a/media/irrlicht2_ft.jpg b/media/irrlicht2_ft.jpg new file mode 100644 index 00000000..fdfae236 Binary files /dev/null and b/media/irrlicht2_ft.jpg differ diff --git a/media/irrlicht2_lf.jpg b/media/irrlicht2_lf.jpg new file mode 100644 index 00000000..384b269d Binary files /dev/null and b/media/irrlicht2_lf.jpg differ diff --git a/media/irrlicht2_rt.jpg b/media/irrlicht2_rt.jpg new file mode 100644 index 00000000..b29e01af Binary files /dev/null and b/media/irrlicht2_rt.jpg differ diff --git a/media/irrlicht2_up.jpg b/media/irrlicht2_up.jpg new file mode 100644 index 00000000..80f30687 Binary files /dev/null and b/media/irrlicht2_up.jpg differ diff --git a/media/irrlichtlogo.BMP b/media/irrlichtlogo.BMP new file mode 100644 index 00000000..33193830 Binary files /dev/null and b/media/irrlichtlogo.BMP differ diff --git a/media/irrlichtlogo.jpg b/media/irrlichtlogo.jpg new file mode 100644 index 00000000..d33c926c Binary files /dev/null and b/media/irrlichtlogo.jpg differ diff --git a/media/irrlichtlogo2.png b/media/irrlichtlogo2.png new file mode 100644 index 00000000..9086b122 Binary files /dev/null and b/media/irrlichtlogo2.png differ diff --git a/media/irrlichtlogo3.png b/media/irrlichtlogo3.png new file mode 100644 index 00000000..255b3ac0 Binary files /dev/null and b/media/irrlichtlogo3.png differ diff --git a/media/irrlichtlogoaligned.jpg b/media/irrlichtlogoaligned.jpg new file mode 100644 index 00000000..ea6deafa Binary files /dev/null and b/media/irrlichtlogoaligned.jpg differ diff --git a/media/irrlichtlogoalpha.tga b/media/irrlichtlogoalpha.tga new file mode 100644 index 00000000..5f58885b Binary files /dev/null and b/media/irrlichtlogoalpha.tga differ diff --git a/media/irrlichtlogoalpha2.tga b/media/irrlichtlogoalpha2.tga new file mode 100644 index 00000000..faa6c1a5 Binary files /dev/null and b/media/irrlichtlogoalpha2.tga differ diff --git a/media/lightFalloff.png b/media/lightFalloff.png new file mode 100644 index 00000000..21b2142a Binary files /dev/null and b/media/lightFalloff.png differ diff --git a/media/lucida.xml b/media/lucida.xml new file mode 100644 index 00000000..3d18bdab Binary files /dev/null and b/media/lucida.xml differ diff --git a/media/lucida0.png b/media/lucida0.png new file mode 100644 index 00000000..3c176889 Binary files /dev/null and b/media/lucida0.png differ diff --git a/media/map-20kdm2.pk3 b/media/map-20kdm2.pk3 new file mode 100644 index 00000000..d86083ef Binary files /dev/null and b/media/map-20kdm2.pk3 differ diff --git a/media/map-20kdm2.txt b/media/map-20kdm2.txt new file mode 100644 index 00000000..6db34ffa --- /dev/null +++ b/media/map-20kdm2.txt @@ -0,0 +1,50 @@ + +-=( Map Information )=- ----------------------------------------------- + + : Return to Castle: Quake +<Date> : 02/02/02 - ren 11/17/2002 +<Filename> : map-20kdm2.pk3 +<Author> : Michael "<|3FG20K>" Cook +<Email Address> : bfg20k@nycap.rr.com / bfg20k@planetquake.com +<Website> : http://www.planetquake.com/bfg20k +<Description> : This is an Evil7 Castle! It has three tiers, + tight spaces, and plenty of room for various + battles. + +<Additional Credits> : [HFX]Evil, for making great textures. + +-=( Construction )=- -------------------------------------------------- + +<Base> : None. +<Editor(s) Used> : Q3Radiant - Build 202 & Q3Build +<Known Bugs> : This isn't really a bug, but an added feature; + you can walk on top of the battlements. +<Construction Time> : 3 weeks. +<Compile Machine> : 866mhz PIII, 512mb RAM + +-=( Play Information )=- ---------------------------------------------- + +<Mod> : A good one. +<Players> : 2-8 Players +<Bots> : Duh! wait, I THINK they're smarter than Forrest + Gump... You'll have to clarify that for me =). + +-={ Installation }=- -------------------------------------------------- + +<Installation> : Unzip the the zip file map-20kdm2.zip into + your "Quake III Arena\baseq3" directory + Run Quake III Arena, and under console type + "/map 20kdm2" or select under Skirmish in + SIngle Player mode. + +-=( Copyright / Permissions )=- --------------------------------------- + +<Copyright> : You not include or distribute this map in any + sort of commercial product without permission + from the author. You may not mass distribute + this level via any non-electronic means + including but not limited to compact disks, + and floppy disks without permission from the + author. + +-=( This is the End )=- ----------------------------------------------- diff --git a/media/ninja animation ranges.txt b/media/ninja animation ranges.txt new file mode 100644 index 00000000..eaf12fef --- /dev/null +++ b/media/ninja animation ranges.txt @@ -0,0 +1,36 @@ +hey guys heres all the ranges for the ninja model, 20 ranges and 300 frames....Phew!! + +you may need to scale or rotate the model and change animation speeds for various 3D game engines... + +Please check the numbers carefully cus they dont follow any order and in between ranges often skip a few frames, this as how I achieved certain moves in Character FX its not a mistake :) + +1-14 Walk (normal) +15-30 Stealth Walk +32-44 Punch and swipe sword +45-59 Swipe and spin sword +60-68 Overhead twohanded downswipe +69-72 Up to block position (play backwards to lower sword if you want) +73-83 Forward kick +84-93 Pick up from floor (or down to crouch at frame 87) +94-102 Jump +103-111 Jump without height (for programmer controlled jumps) +112-125 High jump to Sword Kill (Finish em off move??) +126-133 Side Kick +134-145 Spinning Sword attack (might wanna speed this up in game) +146-158 Backflip +159-165 Climb wall +166-173 Death 1 - Fall back onto ground +174-182 Death 2 - Fall forward onto ground +184-205 Idle 1 - Breathe heavily +206-250 Idle 2 +251-300 Idle 3 + +Ok there it is, have fun and maybe drop by my forums hang out, ask questions, post your own work etc + +Feel free to use however you like, commercial etc, credits are Appreciated as a LOT of work went into this! ;-) + +Psionic + +http://www.psionic3d.co.uk + +Note for Irrlicht: Irrlicht uses a 0-based frame index. So subtract 1 from each of the loops! \ No newline at end of file diff --git a/media/ninja.b3d b/media/ninja.b3d new file mode 100644 index 00000000..fbc78724 Binary files /dev/null and b/media/ninja.b3d differ diff --git a/media/nskinbl.jpg b/media/nskinbl.jpg new file mode 100644 index 00000000..b701adb9 Binary files /dev/null and b/media/nskinbl.jpg differ diff --git a/media/nskinrd.jpg b/media/nskinrd.jpg new file mode 100644 index 00000000..458dbfcd Binary files /dev/null and b/media/nskinrd.jpg differ diff --git a/media/ogles2.frag b/media/ogles2.frag new file mode 100644 index 00000000..e0a03cda --- /dev/null +++ b/media/ogles2.frag @@ -0,0 +1,13 @@ +precision mediump float; + +varying vec2 v_texCoord; +varying vec4 v_color; + +uniform sampler2D myTexture; + +void main (void) +{ + vec4 col = texture2D(myTexture, v_texCoord); + col *= v_color; + gl_FragColor = col * 4.0; +} diff --git a/media/ogles2.vert b/media/ogles2.vert new file mode 100644 index 00000000..6007c83c --- /dev/null +++ b/media/ogles2.vert @@ -0,0 +1,34 @@ +attribute vec3 inVertexPosition; +attribute vec3 inVertexNormal; +attribute vec4 inVertexColor; +attribute vec2 inTexCoord0; + +uniform mat4 mWorldViewProj; +uniform mat4 mInvWorld; +uniform mat4 mTransWorld; +uniform vec3 mLightPos; +uniform vec4 mLightColor; + +varying mediump vec4 v_color; +varying mediump vec2 v_texCoord; + +void main(void) +{ + gl_Position = mWorldViewProj * vec4(inVertexPosition,1.0); + + vec4 normal = vec4(inVertexNormal, 0.0); + normal = mInvWorld * normal; + normal = normalize(normal); + + vec4 worldpos = vec4(inVertexPosition,1.0) * mTransWorld; + + vec4 lightVector = worldpos - vec4(mLightPos,1.0); + lightVector = normalize(lightVector); + + float tmp2 = dot(-lightVector, normal); + + vec4 tmp = mLightColor * tmp2; + v_color = vec4(tmp.x, tmp.y, tmp.z, 0.0); + + v_texCoord = inTexCoord0; +} diff --git a/media/open.png b/media/open.png new file mode 100644 index 00000000..b85229d2 Binary files /dev/null and b/media/open.png differ diff --git a/media/opengl.frag b/media/opengl.frag new file mode 100644 index 00000000..82c3d5c9 --- /dev/null +++ b/media/opengl.frag @@ -0,0 +1,9 @@ + +uniform sampler2D myTexture; + +void main (void) +{ + vec4 col = texture2D(myTexture, vec2(gl_TexCoord[0])); + col *= gl_Color; + gl_FragColor = col * 4.0; +} diff --git a/media/opengl.psh b/media/opengl.psh new file mode 100644 index 00000000..9f9d03bb --- /dev/null +++ b/media/opengl.psh @@ -0,0 +1,22 @@ +!!ARBfp1.0 +# part of the Irrlicht Engine Shader example. +# Please note that these example shaders don't do anything really useful. +# They only demonstrate that shaders can be used in Irrlicht. + +#Input +ATTRIB inTexCoord = fragment.texcoord; # texture coordinates +ATTRIB inColor = fragment.color.primary; # interpolated diffuse color + +#Output +OUTPUT outColor = result.color; + +TEMP texelColor; +TEMP tmp; +TXP texelColor, inTexCoord, texture, 2D; + +ADD tmp, inColor, inColor; # mulitply with color +MUL texelColor, texelColor, tmp; # mulitply with color +ADD outColor, texelColor, texelColor; # make it brighter and store result + +END + diff --git a/media/opengl.vert b/media/opengl.vert new file mode 100644 index 00000000..9a15dd04 --- /dev/null +++ b/media/opengl.vert @@ -0,0 +1,34 @@ +// Part of the Irrlicht Engine Shader example. +// Simple GLSL vertex shader +// Please note that these example shaders don't do anything really useful. +// They only demonstrate that shaders can be used in Irrlicht. + + +uniform mat4 mWorldViewProj; +uniform mat4 mInvWorld; +uniform mat4 mTransWorld; +uniform vec3 mLightPos; // actually just camera-pos in this case +uniform vec4 mLightColor; + +void main(void) +{ + gl_Position = mWorldViewProj * gl_Vertex; + + // transform normal somehow (NOTE: for the real vertex normal you would use an inverse-transpose world matrix instead of mInvWorld) + vec4 normal = vec4(gl_Normal, 0.0); + normal = mInvWorld * normal; + normal = normalize(normal); + + // (NOTE: not sure why transposed world is used instead of world?) + vec4 worldpos = gl_Vertex * mTransWorld; + + vec4 lightVector = worldpos - vec4(mLightPos,1.0); + lightVector = normalize(lightVector); + + float tmp2 = dot(-lightVector, normal); + + vec4 tmp = mLightColor * tmp2; + gl_FrontColor = gl_BackColor = vec4(tmp.x, tmp.y, tmp.z, 0.0); + + gl_TexCoord[0] = gl_MultiTexCoord0; +} diff --git a/media/opengl.vsh b/media/opengl.vsh new file mode 100644 index 00000000..9cd71bf2 --- /dev/null +++ b/media/opengl.vsh @@ -0,0 +1,60 @@ +!!ARBvp1.0 +# part of the Irrlicht Engine Shader example. +# Please note that these example shaders don't do anything really useful. +# They only demonstrate that shaders can be used in Irrlicht. + +#input +ATTRIB InPos = vertex.position; +ATTRIB InColor = vertex.color; +ATTRIB InNormal = vertex.normal; +ATTRIB InTexCoord = vertex.texcoord; + +#output +OUTPUT OutPos = result.position; +OUTPUT OutColor = result.color; +OUTPUT OutTexCoord = result.texcoord; + +PARAM MVP[4] = { state.matrix.mvp }; # modelViewProjection matrix. +TEMP Temp; +TEMP TempColor; +TEMP TempNormal; +TEMP TempPos; + +#transform position to clip space +DP4 Temp.x, MVP[0], InPos; +DP4 Temp.y, MVP[1], InPos; +DP4 Temp.z, MVP[2], InPos; +DP4 Temp.w, MVP[3], InPos; + +#transform normal +DP3 TempNormal.x, InNormal.x, program.local[0]; +DP3 TempNormal.y, InNormal.y, program.local[1]; +DP3 TempNormal.z, InNormal.z, program.local[2]; + +#renormalize normal +DP3 TempNormal.w, TempNormal, TempNormal; +RSQ TempNormal.w, TempNormal.w; +MUL TempNormal, TempNormal, TempNormal.w; + +# calculate light vector +DP4 TempPos.x, InPos, program.local[10]; # vertex into world position +DP4 TempPos.y, InPos, program.local[11]; +DP4 TempPos.z, InPos, program.local[12]; +DP4 TempPos.w, InPos, program.local[13]; + +ADD TempPos, program.local[8], -TempPos; # vtxpos - lightpos + +# normalize light vector +DP3 TempPos.w, TempPos, TempPos; +RSQ TempPos.w, TempPos.w; +MUL TempPos, TempPos, TempPos.w; + +# calculate light color +DP3 TempColor, TempNormal, TempPos; # dp3 with negative light vector +LIT OutColor, TempColor; # clamp to zero if r3 < 0, r5 has diffuce component in r5.y +MUL OutColor, TempColor.y, program.local[9]; # ouput diffuse color +MOV OutColor.w, 1.0; # we want alpha to be always 1 +MOV OutTexCoord, InTexCoord; # store texture coordinate +MOV OutPos, Temp; + +END \ No newline at end of file diff --git a/media/opengllogo.png b/media/opengllogo.png new file mode 100644 index 00000000..2e837263 Binary files /dev/null and b/media/opengllogo.png differ diff --git a/media/particle.bmp b/media/particle.bmp new file mode 100644 index 00000000..b92a7f9a Binary files /dev/null and b/media/particle.bmp differ diff --git a/media/particlegreen.jpg b/media/particlegreen.jpg new file mode 100644 index 00000000..b39f171c Binary files /dev/null and b/media/particlegreen.jpg differ diff --git a/media/particlered.bmp b/media/particlered.bmp new file mode 100644 index 00000000..1a542145 Binary files /dev/null and b/media/particlered.bmp differ diff --git a/media/particlewhite.bmp b/media/particlewhite.bmp new file mode 100644 index 00000000..267845da Binary files /dev/null and b/media/particlewhite.bmp differ diff --git a/media/portal1.bmp b/media/portal1.bmp new file mode 100644 index 00000000..8bd032e3 Binary files /dev/null and b/media/portal1.bmp differ diff --git a/media/portal2.bmp b/media/portal2.bmp new file mode 100644 index 00000000..85f33228 Binary files /dev/null and b/media/portal2.bmp differ diff --git a/media/portal3.bmp b/media/portal3.bmp new file mode 100644 index 00000000..6d174ac1 Binary files /dev/null and b/media/portal3.bmp differ diff --git a/media/portal4.bmp b/media/portal4.bmp new file mode 100644 index 00000000..5e7fa352 Binary files /dev/null and b/media/portal4.bmp differ diff --git a/media/portal5.bmp b/media/portal5.bmp new file mode 100644 index 00000000..36f573f5 Binary files /dev/null and b/media/portal5.bmp differ diff --git a/media/portal6.bmp b/media/portal6.bmp new file mode 100644 index 00000000..972d053e Binary files /dev/null and b/media/portal6.bmp differ diff --git a/media/portal7.bmp b/media/portal7.bmp new file mode 100644 index 00000000..d9e54056 Binary files /dev/null and b/media/portal7.bmp differ diff --git a/media/pp_d3d9.hlsl b/media/pp_d3d9.hlsl new file mode 100644 index 00000000..33d47ec9 --- /dev/null +++ b/media/pp_d3d9.hlsl @@ -0,0 +1,43 @@ + +// Texture size to calculate texel center +float2 TextureSize; + +// Vertex shader output struct +struct VS_OUTPUT +{ + float4 Position : POSITION0; + float2 TexCoords : TEXCOORD0; +}; + +VS_OUTPUT vertexMain( + float4 Position : POSITION0, + float2 TexCoords : TEXCOORD0 + ) +{ + VS_OUTPUT OUT; + OUT.Position = Position; + + // In practice, instead of passing in TextureSize, + // pass 1.0 / TextureSize for better performance + + // TexCoords is set to the texel center + OUT.TexCoords = TexCoords + 1.0 / TextureSize / 2.0; + + return OUT; +} + +// Texture sampler +sampler2D TextureSampler; + +float4 pixelMain ( float2 Texcoords : TEXCOORD0 ) : COLOR0 +{ + // Texture is sampled at Texcoords using tex2D + float4 Color = tex2D(TextureSampler, Texcoords); + + // Change Texcoords to sample pixels around + + // Inverse the color to produce negative image effect + Color.rgb = 1.0 - Color.rgb; + + return Color; +}; diff --git a/media/pp_opengl.frag b/media/pp_opengl.frag new file mode 100644 index 00000000..85ab768a --- /dev/null +++ b/media/pp_opengl.frag @@ -0,0 +1,17 @@ + +// Texture sampler +uniform sampler2D TextureSampler; + +// TexCoords from vertex shader +varying vec2 TexCoords; + +void main (void) +{ + // Texture is sampled at Texcoords using texture2D + vec4 Color = texture2D(TextureSampler, TexCoords); + + // Inverse the color to produce negative image effect + Color.rgb = 1.0 - Color.rgb; + + gl_FragColor = Color; +} \ No newline at end of file diff --git a/media/pp_opengl.vert b/media/pp_opengl.vert new file mode 100644 index 00000000..d1c9ae66 --- /dev/null +++ b/media/pp_opengl.vert @@ -0,0 +1,24 @@ + +// Pass to fragment shader with the same name +varying vec2 TexCoords; + +void main(void) +{ + gl_Position = gl_Vertex; + + // The origin of the texture coordinates locates at bottom-left + // corner rather than top-left corner as defined on screen quad. + // Instead of using texture coordinates passed in by OpenGL, we + // calculate TexCoords based on vertex position as follows. + // + // Vertex[0] (-1, -1) to (0, 0) + // Vertex[1] (-1, 1) to (0, 1) + // Vertex[2] ( 1, 1) to (1, 1) + // Vertex[3] ( 1, -1) to (1, 0) + // + // Texture coordinate system in OpenGL operates differently from + // DirectX 3D. It is not necessary to offset TexCoords to texel + // center by adding 1.0 / TextureSize / 2.0 + + TexCoords = (gl_Vertex.xy * 0.5 + 0.5); +} diff --git a/media/rockwall.jpg b/media/rockwall.jpg new file mode 100644 index 00000000..85a7dd72 Binary files /dev/null and b/media/rockwall.jpg differ diff --git a/media/rockwall_height.bmp b/media/rockwall_height.bmp new file mode 100644 index 00000000..90f4d7bd Binary files /dev/null and b/media/rockwall_height.bmp differ diff --git a/media/room.3ds b/media/room.3ds new file mode 100644 index 00000000..f0bfbe63 Binary files /dev/null and b/media/room.3ds differ diff --git a/media/rsptnback.jpg b/media/rsptnback.jpg new file mode 100644 index 00000000..9984dcd7 Binary files /dev/null and b/media/rsptnback.jpg differ diff --git a/media/skydome.jpg b/media/skydome.jpg new file mode 100644 index 00000000..74815130 Binary files /dev/null and b/media/skydome.jpg differ diff --git a/media/skydome2.jpg b/media/skydome2.jpg new file mode 100644 index 00000000..7bfe713f Binary files /dev/null and b/media/skydome2.jpg differ diff --git a/media/smoke.bmp b/media/smoke.bmp new file mode 100644 index 00000000..64949888 Binary files /dev/null and b/media/smoke.bmp differ diff --git a/media/smoke2.jpg b/media/smoke2.jpg new file mode 100644 index 00000000..3d169de6 Binary files /dev/null and b/media/smoke2.jpg differ diff --git a/media/smoke3.jpg b/media/smoke3.jpg new file mode 100644 index 00000000..5dee86bf Binary files /dev/null and b/media/smoke3.jpg differ diff --git a/media/spheremap.jpg b/media/spheremap.jpg new file mode 100644 index 00000000..6b785fbf Binary files /dev/null and b/media/spheremap.jpg differ diff --git a/media/stones.jpg b/media/stones.jpg new file mode 100644 index 00000000..99ce6f41 Binary files /dev/null and b/media/stones.jpg differ diff --git a/media/sydney.bmp b/media/sydney.bmp new file mode 100644 index 00000000..0ba9aad9 Binary files /dev/null and b/media/sydney.bmp differ diff --git a/media/sydney.md2 b/media/sydney.md2 new file mode 100644 index 00000000..7d3521dd Binary files /dev/null and b/media/sydney.md2 differ diff --git a/media/t351sml.jpg b/media/t351sml.jpg new file mode 100644 index 00000000..e3561f37 Binary files /dev/null and b/media/t351sml.jpg differ diff --git a/media/terrain-heightmap.bmp b/media/terrain-heightmap.bmp new file mode 100644 index 00000000..a4753df3 Binary files /dev/null and b/media/terrain-heightmap.bmp differ diff --git a/media/terrain-texture.jpg b/media/terrain-texture.jpg new file mode 100644 index 00000000..fdfe7c6f Binary files /dev/null and b/media/terrain-texture.jpg differ diff --git a/media/tools.png b/media/tools.png new file mode 100644 index 00000000..b7e86c93 Binary files /dev/null and b/media/tools.png differ diff --git a/media/vc6include.jpg b/media/vc6include.jpg new file mode 100644 index 00000000..d3e65eae Binary files /dev/null and b/media/vc6include.jpg differ diff --git a/media/vc6optionsdir.jpg b/media/vc6optionsdir.jpg new file mode 100644 index 00000000..c745d83b Binary files /dev/null and b/media/vc6optionsdir.jpg differ diff --git a/media/vcnetinclude.jpg b/media/vcnetinclude.jpg new file mode 100644 index 00000000..ce37fcb3 Binary files /dev/null and b/media/vcnetinclude.jpg differ diff --git a/media/wall.bmp b/media/wall.bmp new file mode 100644 index 00000000..ff1a8c14 Binary files /dev/null and b/media/wall.bmp differ diff --git a/media/wall.jpg b/media/wall.jpg new file mode 100644 index 00000000..b63c2260 Binary files /dev/null and b/media/wall.jpg differ diff --git a/media/water.jpg b/media/water.jpg new file mode 100644 index 00000000..47c0599a Binary files /dev/null and b/media/water.jpg differ diff --git a/media/yodan mdl - readme.txt b/media/yodan mdl - readme.txt new file mode 100644 index 00000000..53c72a3d --- /dev/null +++ b/media/yodan mdl - readme.txt @@ -0,0 +1,53 @@ +Yodan the Silencer + +Experiment 2 + +Can I add elements to the construction of the Biped and also extra external bones? + +Well, yes and no. + +I discovered that it is possible to add both extra links and extra bones without any detremental effects. However, with the exaggerated biped deformation, I came across a problem that hadn't been that obvious on Knute and Bolte. most weapons are rigid non-deformable objects, however the Egon reference model is actually physiqued to a humanoid biped the same way as the player model mesh is. This means that when you deform the biped, it will in turn deform the Egon. It is possible to adjust the Egon model to fit Yodan, but that would mean including the altered Egon gun with the model which would replace the standard one. It would then screw up on standard models, defeating the whole point. + +So, the Egon gun screws up on Yodan. Nothing I can do about it. I also didn't account for his spikes so one of them impales the pack aswell. Oh well! + +Beyond this, I feel the lupine legs and tail work quite well, though I realised that the legs are allready quite 'crouched' in the standing position which didn't leave much room for actual crouching =( However, the root Bip 01 bone is in the same place as the standard Human ones when standing and crouching. + +I have totally re-animated all of the sequences, but largely based those animations on the Valve ones so no points for originality. However, I have made him fire most weapons, including the missile launcher one-handed, I felt it kind of suited him =) + +So I present to you, chunk the second of my planned three-chunk experiment with Halflife modelling. + + +'Yodan the silencer' PPM for Half-Life + +to install: + +unzip the zipfile into the path: Sierra/half-life/valve/models/player +it will automatically create a folder called 'Yodan' and place the mdl and bmp files inside. + +skins: 1x255x255x255colour bmp. +Chrome: no +Team colours: no +triangles: 505 +animations: Custom + +Thanks to: + +Alexis for the constructive criticism. +Chris for the original name, 'Hugo the Silencer' from which Yodan is derived +Raxogg,DaBalrog and Spine[TDA3] for nagging me +White Dragon, Ian Waugh and Nsi among others, for being competent and friendly competition =) +White Dragon, Raxogg and Mist for testing the model for me. +George Lucas, Gene Roddenberry, Wolfgang Amadeus Motzart, Bruce Li and the Pixies for the background noise =) +The Spanish for their onions + +See chunk the first, 'Knute and Bolte' at all good PPM websites near you =) + +also available on my web-site + +http://dspace.dial.pipex.com/scarecrow + +or E-Mail me with questions, advice, complaints etc... + +Scarecrow@dial.pipex.com + +Please note - I don't have time to make clan models or to commit myself to a mod or TC unless you are offering large sums of cash =) \ No newline at end of file diff --git a/media/yodan.mdl b/media/yodan.mdl new file mode 100644 index 00000000..543c1596 Binary files /dev/null and b/media/yodan.mdl differ diff --git a/media/zip.png b/media/zip.png new file mode 100644 index 00000000..c4f9dde5 Binary files /dev/null and b/media/zip.png differ diff --git a/ogles-readme.txt b/ogles-readme.txt new file mode 100644 index 00000000..75630f44 --- /dev/null +++ b/ogles-readme.txt @@ -0,0 +1,6 @@ +This branch is used for development of the OpenGL-ES drivers for Irrlicht. +There will be drivers for ogl-es 1.x and 2.x at some time, but we'll start +with 1.x first. Both drivers will be separate drivers, loosely based on the +OpenGL driver. +The branch is based on SVN/trunk and will be updated only very slowly. It's +not intended for regular use besides when working with ogl-es development. diff --git a/readme.txt b/readme.txt new file mode 100644 index 00000000..868432bc --- /dev/null +++ b/readme.txt @@ -0,0 +1,235 @@ +========================================================================== +The Irrlicht Engine SDK version 1.9 +========================================================================== + + Welcome to the Irrlicht Engine SDK. + + Content of this file: + + 1. Directory Structure Overview + 2. How To Start + 3. Requirements + 4. Release Notes + 5. License + 6. Contact + + +========================================================================== +1. Directory Structure Overview +========================================================================== + + You will find some directories after uncompressing the archive of the + SDK. These are: + + \bin The compiled library Irrlicht.DLL and some compiled demo + and example applications, just start them to see the + Irrlicht Engine in action. Windows only. + \doc Documentation of the Irrlicht Engine. + \examples Examples and tutorials showing how to use the engine with + C++. + \include Header files to include when programming with the engine. + \lib Libs to link with your programs when using the engine. + \media Graphics and sound resources for the demo applications and + examples. + \source The source code of the Irrlicht Engine. This code is + not needed to develop applications with the engine, + but it is included to enable recompilation and + debugging, if necessary. + \tools Useful tools (with sourcecode) for the engine. + + + +========================================================================== +2. How to start +========================================================================== + + To see the engine in action in Windows, just go to the \bin\Win32-VisualStudio + directory, and start some applications. There should also be an + application named Demo.exe which should show the most + interesting features of Irrlicht. + + To start developing own applications and games with the engine take + a look at the 01.HelloWorld example in the \examples directory. + There is also a .html file with a tutorial which should be + easily comprehensible. + + The Irrlicht Engine is a static lib under linux. A precompiled version can be + generated from the sources using the Makefile in source/Irrlicht. Run 'make' in + that subfolder. After this you should be able to 'make' all + example applications in /examples by calling the buildAllExamples script. You + can run the examples then from the bin folder. + + It is also possible to use Irrlicht as shared object + (libIrrlicht.so.versionNumber). Use the proper makefile target for this by + running 'make sharedlib' in the source folder. See the Makefile for details. + + For OSX you can find an XCode project file in source/Irrlicht/MacOSX. This will + build the libIrrlicht.a library necessary to create the apps. + +========================================================================== +3. Requirements +========================================================================== + + You can use one of the following compilers/IDEs to develop applications + with Irrlicht or recompile the engine. However, other compilers/IDEs may + work as well, we simply didn't test them. + + * gcc 4.x + * Visual Studio 2010(10.0)-2013(12.0) + * Code::Blocks (& gcc or visual studio toolkit) + + If you ever want to (re)compile the engine yourself (which means you don't + want to use the precompiled version) you need the following: + + * Windows: + * Needed: PlatformSDK (which usually comes with all IDEs, download + it separately for MSVC Express 2005) + * Optional: DirectX SDK, for D3D9 support + * Optional: DirectX SDK prior to May 2006, for D3D8 support + + * Linux: + * Needed: XServer with include files + * Optional: OpenGL headers and libraries (libGL.so) for OpenGL support + GLX + + XF86VidMode [package x11proto-xf86vidmode-dev] or XRandr + (X11 support libraries, the latter two for fullscreen mode) + + * OSX: + * Needed: XCode and Cocoa framework + * Needed: OpenGL headers and libraries + +========================================================================== +4. Release Notes +========================================================================== + + Informations about changes in this new version of the engine can be + found in changes.txt. + + Please note that the textures, 3D models and levels are copyright + by their authors and not covered by the Irrlicht engine license. + +========================================================================== +5. License +========================================================================== + + The license of the Irrlicht Engine is based on the zlib/libpng license. + Even though this license does not require you to mention that you are + using the Irrlicht Engine in your product, an acknowledgement + would be highly appreciated. + + Please note that the Irrlicht Engine is based in part on the work of + the Independent JPEG Group, the zlib, and libpng. This means that if you use + the Irrlicht Engine in your product, you must acknowledge somewhere + in your documentation that you've used the IJG code and libpng. It would + also be nice to mention that you use the Irrlicht Engine and the zlib. + See the README files in the jpeglib and the zlib for + further informations. + + + The Irrlicht Engine License + =========================== + + Copyright (C) 2002-2012 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 + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgement in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be clearly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + +========================================================================== +6. Contact +========================================================================== + + If you have problems, questions or suggestions, please visit the + official homepage of the Irrlicht Engine: + + http://irrlicht.sourceforge.net + + You will find forums, bugtrackers, patches, tutorials, and other stuff + which will help you out. + + If want to contact the team of the engine, please send an email to + Nikolaus Gebhardt: + + irrlicht@users.sourceforge.net + + Please also not that parts of the engine have been written or contributed + by other people. Especially: (There are probably more people, sorry if I forgot one. + See http://irrlicht.sourceforge.net/author.html for more informations) + + Christian Stehno (hybrid) Contribution Coordinator/Developer + Michael Zeilfelder (cutealien) Developer + Patryk Nadrowski (Nadro) Developer + Yoran Bosman (Yoran) Webserver administrator + Gareth Davidson (bitplane) Developer/ Forum admin + Thomas Alten (burningwater) Wrote the burningsvideo software rasterizer + Luke P. Hoschke (luke) Wrote the b3d loader, the new animation system, VBOs and other things + Colin MacDonald (rogerborg) All hands person + Ahmed Hilali (blindside) The shader and advanced effects man + Dean Wadsworth (varmint) OSX port maintainer and game developer + Alvaro F. Celis (afecelis) Lots of work in the community, for example video tutorials about Irrlicht, forum admin + John Goewert (Saigumi) Wrote some tutorials for the Irrlicht Engine and doing admin stuff + Jam Takes care of moderating the forums and keeps them clean from those evil spammers. + + Many others (this list hasn't been updated in a while, but they are often mentioned in changes.txt) + Etienne Petitjean wrote the MacPort of the engine + Mark Jeacocke Wrote lots of helpful comments and ideas in the forums and per email. + Julio Gorg Created the 'Unofficial DirectX 9.0 Driver for the Irrlicht Engine' + Andy Spurgeon Wrote the Dev-Cpp tutorial. + Andr Simon Wrote the Codewarrior tutorial. + KnightToFlight Created the unoffical terrain renderer addon for the Irrlicht Engine. + Jon Pry Wrote the code to load compressed TGA files. + Matthew Couch Wrote the tokamak integration tutorial. + Max Winkel Wrote the splitscreen tutorial. + Gorgon Zola Wrote the ODE integration tutorial. + Dean P. Macri Sent in code for curved surfaces and PCX Loading. + Sirshane Made several bug fixes, sent in code for making the mouse cursor invisible in Linux. + Matthias Gall Sent in code for a spline scene node animator and reported lots of bugs. + Mario Gruber Suggested triangle fan drawing and sent in code for this. + Ariaci Spotted out a bug in the ATI driver. + Dr Andros C Bragianos Improved texture mapping in cube scene node. + Philipp Dortmann Sent in code for stencil buffer support for OpenGL. + Jerome Nichols Created the Irrlicht/Ruby interface located at irr.rubyforge.org + Vash TheStampede Sent code for missing Draw2DLine() implementations + MattyBoy XBOX support suggestions + Oliver Klems createImageFromData() method suggestion/implementation + Jox really, really a lot of bug fixes, and the LMTS file loader + Zola Quaternion method additions + Tomasz Nowakowski various bug fixes + Nicholas Bray stencil shadow bug fixes with OpenGL + REAPER mouswheel events for scrollbar + Calimero various bug fixes like vector2d operators + Haddock bugfix in the linked list + G.o.D XML parser fix + Erik Zilli Translated some of the tutorials from my stuttering english into real english. :) + Martin Piskernig Linux bugfixing and testing + Soconne Wrote the original terrain renderer were Irrlichts terrain renderer of Irrlicht is based on it. + Spintz GeoMipMap scene node, terrain renderer of Irrlicht is based on it. + Murphy McCauley OCT file loader, MIM tools + Saurav Mohapatra IrrCSM, and lots of addons, suggestions and bug reports + Zhuck Dimitry My3D Tools + Terry Welsh Allowed me to use the textures of his 'Parallax Mapping with Offset Limiting' paper for the parallax demo of Irrlicht + rt Wrote the original .png loader for Irrlicht + Salvatore Russo Wrote the original .dmf loader for Irrlicht + Vox Various bug reports and fixes + atomice Contributed code for a ms3d loader enhancement + William Finlayson OpenGL RTT, GLSL support and the reflection 2 layer material for OpenGL. + Delight Various code contributions for Irrlicht.NET (particle system, basic shader support and more) + Michael Zoech Improved GLSL support + Jean-loup Gailly, Mark Adler Created the zlib and libpng + Guy Eric Schalnat, Andreas Dilger, Glenn Randers-Pehrson and others Created libpng + The Independent JPEG Group Created JPEG lib + Dr Brian Gladman AES Created aesGladman + diff --git a/scripts/doc/doxygen.exe b/scripts/doc/doxygen.exe new file mode 100644 index 00000000..5c466e97 Binary files /dev/null and b/scripts/doc/doxygen.exe differ diff --git a/scripts/doc/irrlicht/doxygen-pdf.cfg b/scripts/doc/irrlicht/doxygen-pdf.cfg new file mode 100644 index 00000000..8175b558 --- /dev/null +++ b/scripts/doc/irrlicht/doxygen-pdf.cfg @@ -0,0 +1,1760 @@ +# Doxyfile 1.7.5.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = "Irrlicht 3D Engine" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = irrlichtlogo.png + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../../../doctemp + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = YES + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = YES + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = NO + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = irrlicht + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../../../include/ \ + tut.txt + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.h \ + *.cpp + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to directory from which doxygen is run. + +EXCLUDE = YES + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = ../../../media +IMAGE_PATH += ../../../media/example_screenshots + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = NO + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is adviced to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = footer.html + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 237 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = YES + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = irrlicht.chm + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = ..\hhc.exe + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = YES + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> +# Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> +# Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = YES + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the +# mathjax.org site, so you can quickly see the result without installing +# MathJax, but it is strongly recommended to install a local copy of MathJax +# before deployment. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = YES + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/scripts/doc/irrlicht/doxygen.cfg b/scripts/doc/irrlicht/doxygen.cfg new file mode 100644 index 00000000..2e80f8cb --- /dev/null +++ b/scripts/doc/irrlicht/doxygen.cfg @@ -0,0 +1,1760 @@ +# Doxyfile 1.7.5.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = "Irrlicht 3D Engine" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = irrlichtlogo.png + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../../../doctemp + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = YES + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = YES + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = NO + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = irrlicht + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../../../include/ \ + tut.txt + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.h \ + *.cpp + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to directory from which doxygen is run. + +EXCLUDE = YES + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = ../../../media +IMAGE_PATH += ../../../media/example_screenshots + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is adviced to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = footer.html + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 237 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = YES + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = irrlicht.chm + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = ..\hhc.exe + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = YES + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> +# Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> +# Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = YES + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the +# mathjax.org site, so you can quickly see the result without installing +# MathJax, but it is strongly recommended to install a local copy of MathJax +# before deployment. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = YES + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/scripts/doc/irrlicht/footer.html b/scripts/doc/irrlicht/footer.html new file mode 100644 index 00000000..f1ad5d3d --- /dev/null +++ b/scripts/doc/irrlicht/footer.html @@ -0,0 +1,18 @@ +<!--BEGIN GENERATE_TREEVIEW--> + <li class="footer"> +<a href="http://irrlicht.sourceforge.net" target="_blank">Irrlicht +Engine</a> Documentation © 2003-2019 by Nikolaus Gebhardt. $generatedby +<a href="http://www.doxygen.org/index.html" target="_blank">Doxygen</a> $doxygenversion </li> + </ul> + </div> +<!--END GENERATE_TREEVIEW--> +<!--BEGIN !GENERATE_TREEVIEW--> +<hr class="footer"/><address class="footer"><small> +<a href="http://irrlicht.sourceforge.net" target="_blank">Irrlicht +Engine</a> Documentation © 2003-2019 by Nikolaus Gebhardt. $generatedby +<a href="http://www.doxygen.org/index.html" target="_blank">Doxygen +</a> $doxygenversion +</small></address> +<!--END !GENERATE_TREEVIEW--> +</body> +</html> diff --git a/scripts/doc/irrlicht/irrlicht.png b/scripts/doc/irrlicht/irrlicht.png new file mode 100644 index 00000000..f8534cf3 Binary files /dev/null and b/scripts/doc/irrlicht/irrlicht.png differ diff --git a/scripts/doc/irrlicht/irrlichtlogo.png b/scripts/doc/irrlicht/irrlichtlogo.png new file mode 100644 index 00000000..a63b3fcf Binary files /dev/null and b/scripts/doc/irrlicht/irrlichtlogo.png differ diff --git a/scripts/doc/irrlicht/logobig.png b/scripts/doc/irrlicht/logobig.png new file mode 100644 index 00000000..2505ecd5 Binary files /dev/null and b/scripts/doc/irrlicht/logobig.png differ diff --git a/scripts/doc/irrlicht/makedocumentation.bat b/scripts/doc/irrlicht/makedocumentation.bat new file mode 100644 index 00000000..80793a98 --- /dev/null +++ b/scripts/doc/irrlicht/makedocumentation.bat @@ -0,0 +1,44 @@ +mkdir ..\..\..\doctemp +mkdir ..\..\..\doctemp\html +copy doxygen.css ..\..\..\doctemp\html +copy irrlicht.png ..\..\..\doctemp\html +copy logobig.png ..\..\..\doctemp\html + +rem enable following line for skipping tutorial generation (can be used for faster testing documentation layout) +rem goto SKIP_TUTS + +rem for /F %%i in ('dir ..\..\..\examples\[01]*\main.cpp') DO ..\sed.exe -f tutorials.sed %i >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\01.HelloWorld\main.cpp >tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\02.Quake3Map\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\03.CustomSceneNode\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\04.Movement\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\05.UserInterface\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\06.2DGraphics\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\07.Collision\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\08.SpecialFX\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\09.MeshViewer\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\10.Shaders\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\11.PerPixelLighting\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\12.TerrainRendering\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\13.RenderToTexture\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\14.Win32Window\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\15.LoadIrrFile\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\16.Quake3MapShader\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\17.HelloWorld_Mobile\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\18.SplitScreen\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\19.MouseAndJoystick\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\20.ManagedLights\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\21.Quake3Explorer\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\22.MaterialViewer\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\23.SMeshHandling\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\24.CursorControl\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\25.XmlHandling\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\26.OcclusionQuery\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\27.PostProcessing\main.cpp >>tut.txt +..\sed.exe -f tutorials.sed ..\..\..\examples\28.CubeMapping\main.cpp >>tut.txt + +:SKIP_TUTS + +..\doxygen.exe doxygen.cfg + +pause diff --git a/scripts/doc/irrlicht/makedocumentation.sh b/scripts/doc/irrlicht/makedocumentation.sh new file mode 100755 index 00000000..9a8052ec --- /dev/null +++ b/scripts/doc/irrlicht/makedocumentation.sh @@ -0,0 +1,11 @@ +rm tut.txt || true; + +mkdir ../../../doctemp +mkdir ../../../doctemp/html +cp doxygen.css irrlicht.png logobig.png ../../../doctemp/html + +for i in ../../../examples/[012]*/main.cpp; do + sed -f tutorials.sed $i >>tut.txt; +done + +doxygen doxygen.cfg diff --git a/scripts/doc/irrlicht/maketut.sed b/scripts/doc/irrlicht/maketut.sed new file mode 100644 index 00000000..8cc7b4d2 --- /dev/null +++ b/scripts/doc/irrlicht/maketut.sed @@ -0,0 +1,5 @@ +1,+18 d +s/src="/src="images\/tutorials\// +s/href="/href="docu\//g +s/\(.*\) <hr.*$/\1/ +/<addr/,$ d diff --git a/scripts/doc/irrlicht/maketutorial.bat b/scripts/doc/irrlicht/maketutorial.bat new file mode 100644 index 00000000..5479c308 --- /dev/null +++ b/scripts/doc/irrlicht/maketutorial.bat @@ -0,0 +1,4 @@ +type tut_head.html >%2 +..\sed.exe -f maketut.sed %1 >>%2 +type tut_end.html >>%2 + diff --git a/scripts/doc/irrlicht/maketutorial.sh b/scripts/doc/irrlicht/maketutorial.sh new file mode 100755 index 00000000..4b642add --- /dev/null +++ b/scripts/doc/irrlicht/maketutorial.sh @@ -0,0 +1,4 @@ +cat tut_head.html >$2 +sed -f maketut.sed $1 >>$2 +cat tut_end.html >>$2 + diff --git a/scripts/doc/irrlicht/tut_end.html b/scripts/doc/irrlicht/tut_end.html new file mode 100644 index 00000000..63fa4da0 --- /dev/null +++ b/scripts/doc/irrlicht/tut_end.html @@ -0,0 +1,14 @@ + </td> + </tr> + </table> + <p> </p></td> + </tr> + </table> + <div align="right"><br /> + <a href="http://validator.w3.org/check?uri=referer" target="_blank"><img src="images/general/valid-xhtml10.png" alt="Valid XHTML 1.0!" width="88" height="31" border="0" /></a> + <a href="http://jigsaw.w3.org/css-validator/" target="_blank"><img src="images/general/vcss.gif" alt="Valid CSS!" width="88" height="31" border="0" /></a></div> +</div> +<p class="copyrighttext"><br /> + Irrlicht Engine and Irrlicht Engine webpage © 2003-2010 by Nikolaus Gebhardt</p> +</body> +</html> diff --git a/scripts/doc/irrlicht/tut_head.html b/scripts/doc/irrlicht/tut_head.html new file mode 100644 index 00000000..1cce74b6 --- /dev/null +++ b/scripts/doc/irrlicht/tut_head.html @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>Irrlicht Engine - A free open source 3d engine + + + + + + + +

+ + + + + + + + + +
Irrlicht Engine logo
+ +
diff --git a/scripts/doc/irrlicht/tutorials.sed b/scripts/doc/irrlicht/tutorials.sed new file mode 100644 index 00000000..3b8b0e35 --- /dev/null +++ b/scripts/doc/irrlicht/tutorials.sed @@ -0,0 +1,13 @@ +# Page start and end are delimited by /** and **/ +# we keep the end unchanged, the header is extended +s/\/\*\* Example \(0*\)\([0-9]*\) \(.*\)$/\/\*\* \\page example\1\2 Tutorial \2: \3\n \\image html \"\1\2shot.jpg\"\n \\image latex \"\1\2shot.jpg\"/ + +# All other comments start and end code sections +s/\([^\*]\)\*\//\1\\code/ +s/^\*\//\\code/ + +s/\/\*\([^\*]\)/\\endcode \1/ +s/\/\*$/\\endcode\n/ + +#remove DOS line endings +s/\r//g diff --git a/scripts/doc/sed.exe b/scripts/doc/sed.exe new file mode 100644 index 00000000..f3f2e5e0 Binary files /dev/null and b/scripts/doc/sed.exe differ diff --git a/scripts/doc/sed.txt b/scripts/doc/sed.txt new file mode 100644 index 00000000..2b81f727 --- /dev/null +++ b/scripts/doc/sed.txt @@ -0,0 +1,9 @@ +GNU sed version 4.0.7 - compiled for Win32. +Native executable requires only the Microsoft +C runtime MSVCRT.DLL, not an emulation layer +like Cygwin. This .EXE file was obtained from +http://unxutils.sourceforge.net on 2003-10-21. +For documentation, GPL license, source code, +etc., visit http://unxutils.sourceforge.net. + +Downloaded from http://www.student.northpark.edu/pemente/sed/ diff --git a/scripts/libIrrlicht1.spec b/scripts/libIrrlicht1.spec new file mode 100644 index 00000000..7fae22d3 --- /dev/null +++ b/scripts/libIrrlicht1.spec @@ -0,0 +1,324 @@ +# Copyright (c) 2007-2011 oc2pus +# This file and all modifications and additions to the pristine +# package are under the same license as the package itself. +# +# Please submit bugfixes or comments to toni@links2linux.de + +# Packmangroup: Libraries +# Packmanpackagename: Irrlicht +# Packman: Toni Graffy + +# norootforbuild + +Name: libIrrlicht1 +Version: 1.9.0 +Release: 0.pm.1 +Summary: The Irrlicht Engine SDK +License: see readme.txt +Group: System/Libraries +URL: http://irrlicht.sourceforge.net/ +Source: irrlicht-%{version}.tar.bz2 +BuildRoot: %{_tmppath}/%{name}-%{version}-build +BuildRequires: freeglut-devel +BuildRequires: ImageMagick +BuildRequires: gcc-c++ +%if %suse_version >= 1020 +BuildRequires: Mesa-devel +%else +BuildRequires: xorg-x11-devel +%endif +BuildRequires: update-desktop-files + +%description +The Irrlicht Engine is an open source high performance realtime 3d engine +written and usable in C++. It is completely cross-platform, using D3D, OpenGL +and its own software renderer, and has all of the state-of-the-art features +which can be found in commercial 3d engines. + +We've got a huge active community, and there are lots of projects in +development that use the engine. You can find enhancements for Irrlicht all +over the web, like alternative terrain renderers, portal renderers, exporters, +world layers, tutorials, editors, language bindings for .NET, Java, Perl, Ruby, +Basic, Python, Lua, and so on. And best of all: It's completely free. + +%package -n libIrrlicht-devel +Summary: Development package for the Irrlicht library +Group: Development/Languages/C and C++ +Requires: libIrrlicht1 = %{version} +# Packmandepends: libIrrlicht1 + +%description -n libIrrlicht-devel +The Irrlicht Engine is an open source high performance realtime 3d engine +written and usable in C++. It is completely cross-platform, using D3D, OpenGL +and its own software renderer, and has all of the state-of-the-art features +which can be found in commercial 3d engines. + +We've got a huge active community, and there are lots of projects in +development that use the engine. You can find enhancements for Irrlicht all +over the web, like alternative terrain renderers, portal renderers, exporters, +world layers, tutorials, editors, language bindings for .NET, Java, Perl, Ruby, +Basic, Python, Lua, and so on. And best of all: It's completely free. + +%package -n Irrlicht-examples +Summary: Demos and examples for the Irrlicht-SDK +Group: Development/Tools/GUI Builders +Requires: libIrrlicht1 = %{version} +# Packmandepends: Irrlicht-media libIrrlicht1 + +%description -n Irrlicht-examples +The Irrlicht Engine is an open source high performance realtime 3d engine +written and usable in C++. It is completely cross-platform, using D3D, OpenGL +and its own software renderer, and has all of the state-of-the-art features +which can be found in commercial 3d engines. + +We've got a huge active community, and there are lots of projects in +development that use the engine. You can find enhancements for Irrlicht all +over the web, like alternative terrain renderers, portal renderers, exporters, +world layers, tutorials, editors, language bindings for .NET, Java, Perl, Ruby, +Basic, Python, Lua, and so on. And best of all: It's completely free. + +This package contains some demos and examples for the Irrlicht-SDK. + +%package -n Irrlicht-doc +Summary: User documentation for the Irrlicht SDK. +Group: Documentation/Other + +%description -n Irrlicht-doc +User documentation for the Irrlicht SDK. + +You need a chm-viewer to read the docs (e.g. kchmviewer). + +%package -n Irrlicht-tools +Summary: Some tools for the Irrlicht-SDK +Group: Development/Tools/GUI Builders +Requires: libIrrlicht1 = %{version} +Requires: Irrlicht-media +# Packmandepends: Irrlicht-media libIrrlicht1 + +%description -n Irrlicht-tools +Some tools for the Irrlicht-SDK. + +GUIEditor, FontTool and Meshviewer. + +%package -n Irrlicht-media +Summary: Some media files for Irrlicht SDK +Group: Development/Languages/C and C++ + +%description -n Irrlicht-media +Some media files for Irrlicht tools and demos. + +%debug_package + +%prep +%setup -q -n irrlicht-%{version} + +# only for windows-platform +%__rm -r examples/14.Win32Window + +# avoid irrKlang +%__sed -i -e 's|^#define USE_IRRKLANG|//#define USE_IRRKLANG|g' \ + examples/Demo/CDemo.h + +# adjust media path in examples +find ./examples -name *.cpp | xargs %__sed -i -e 's|../../media/|%{_datadir}/irrlicht/|g' +# adjust media path in tools +%__sed -i -e 's|../../media/|%{_datadir}/irrlicht/|g' \ + tools/GUIEditor/main.cpp + +# pack example-sources +tar cj \ + --exclude *.cbp \ + --exclude *.dev \ + --exclude *.dsp \ + --exclude *.dsw \ + --exclude *.html \ + --exclude *.sln \ + --exclude *.vcproj \ + -f irrlicht-examples-src.tar.bz2 examples/* + +%build +# create shared-lib first +pushd source/Irrlicht +%__make sharedlib %{?_smp_mflags} +popd + +# create necessary links to avoid linker-error for tools/examples +pushd lib/Linux +ln -s libIrrlicht.so.%{version} libIrrlicht.so.1 +ln -s libIrrlicht.so.%{version} libIrrlicht.so +popd + +# tools +pushd tools +cd GUIEditor +%__make %{?_smp_mflags} +cd .. +cd IrrFontTool/newFontTool +%__make %{?_smp_mflags} +cd ../.. +popd + +# examples +pushd examples +sh buildAllExamples.sh +popd + +# build static lib +pushd source/Irrlicht +%__make %{?_smp_mflags} +popd + +%install +%__install -dm 755 %{buildroot}%{_libdir} +%__install -m 644 lib/Linux/libIrrlicht.a \ + %{buildroot}%{_libdir} +%__install -m 644 lib/Linux/libIrrlicht.so.%{version} \ + %{buildroot}%{_libdir} + +pushd %{buildroot}%{_libdir} +ln -s libIrrlicht.so.%{version} libIrrlicht.so.1 +ln -s libIrrlicht.so.%{version} libIrrlicht.so +popd + +# includes +%__install -dm 755 %{buildroot}%{_includedir}/irrlicht +%__install -m 644 include/*.h \ + %{buildroot}%{_includedir}/irrlicht + +# tools +%__install -dm 755 %{buildroot}%{_bindir} +%__install -m 755 tools/GUIEditor/GUIEditor \ + %{buildroot}%{_bindir}/irrlicht-GUIEditor +%__install -m 755 bin/Linux/FontTool \ + %{buildroot}%{_bindir}/irrlicht-FontTool + +# examples +%__install -dm 755 %{buildroot}%{_bindir} +ex_list=`ls -1 bin/Linux/??.*` +for i in $ex_list; do + FE=`echo $i | awk 'BEGIN { FS="." }{ print $2 }'` + %__install -m 755 $i \ + %{buildroot}%{_bindir}/irrlicht-$FE +done + +# examples-docs +pushd examples +%__install -dm 755 %{buildroot}%{_docdir}/Irrlicht-examples +ex_dir=`find . -name tutorial.html` +for i in $ex_dir; do + dir_name=`dirname $i` + %__install -dm 755 %{buildroot}%{_docdir}/Irrlicht-examples/$dir_name + %__install -m 644 $i \ + %{buildroot}%{_docdir}/Irrlicht-examples/$dir_name +done +%__rm -r %{buildroot}%{_docdir}/Irrlicht-examples/09.Meshviewer +popd + +# examples sources +%__install -m 644 irrlicht-examples-src.tar.bz2 \ + %{buildroot}%{_docdir}/Irrlicht-examples + +# media +%__install -dm 755 %{buildroot}%{_datadir}/irrlicht +%__install -m 755 media/* \ + %{buildroot}%{_datadir}/irrlicht + +# icons +%__install -dm 755 %{buildroot}%{_datadir}/pixmaps +convert examples/09.Meshviewer/icon.ico -resize 48x48! \ + irrlicht-Meshviewer.png +convert bin/Win32-gcc/irrlicht.ico -resize 48x48! \ + irrlicht.png +%__install -m 644 irrlicht*.png \ + %{buildroot}%{_datadir}/pixmaps + +# menu-entries +%__cat > irrlicht-GUIEditor.desktop << EOF +[Desktop Entry] +Comment=Irrlicht GUI Editor +Name=Irrlicht GUI Editor +GenericName= +Type=Application +Exec=irrlicht-GUIEditor +Icon=irrlicht.png +DocPath= +Terminal=0 +EOF +%suse_update_desktop_file -i irrlicht-GUIEditor Development GUIDesigner + +%__cat > irrlicht-FontTool.desktop << EOF +[Desktop Entry] +Comment=Irrlicht-FontTool +Name=Irrlicht-FontTool +GenericName= +Type=Application +Exec=irrlicht-IrrFontTool +Icon=irrlicht.png +DocPath= +Terminal=0 +EOF +%suse_update_desktop_file -i irrlicht-FontTool Development GUIDesigner + +%__cat > irrlicht-Meshviewer.desktop << EOF +[Desktop Entry] +Comment=Irrlicht-Meshviewer +Name=Irrlicht-Meshviewer +GenericName= +Type=Application +Exec=irrlicht-Meshviewer +Icon=irrlicht-Meshviewer.png +DocPath= +Terminal=1 +EOF +%suse_update_desktop_file -i irrlicht-Meshviewer Graphics Viewer + +%clean +[ -d %{buildroot} -a "%{buildroot}" != "" ] && %__rm -rf %{buildroot} + +%files +%defattr(-, root, root) +%doc *.txt +%{_libdir}/lib*.so.* + +%files -n libIrrlicht-devel +%defattr(-, root, root) +%{_libdir}/lib*.so +%{_libdir}/lib*.a +%dir %{_includedir}/irrlicht +%{_includedir}/irrlicht/*.h + +%files -n Irrlicht-examples +%defattr(-, root, root) +%dir %{_docdir}/Irrlicht-examples +%{_docdir}/Irrlicht-examples/* +%exclude %{_bindir}/irrlicht-GUIEditor +%exclude %{_bindir}/irrlicht-FontTool +%exclude %{_bindir}/irrlicht-Meshviewer +%{_bindir}/irrlicht-* + +%files -n Irrlicht-tools +%defattr(-, root, root) +%doc examples/09.Meshviewer/tutorial.html +%{_bindir}/irrlicht-GUIEditor +%{_bindir}/irrlicht-FontTool +%{_bindir}/irrlicht-Meshviewer +%{_datadir}/applications/irrlicht-GUIEditor.desktop +%{_datadir}/applications/irrlicht-FontTool.desktop +%{_datadir}/applications/irrlicht-Meshviewer.desktop +%{_datadir}/pixmaps/irrlicht*.png + +%files -n Irrlicht-doc +%defattr(-, root, root) +%doc doc/irrlicht.chm +%doc doc/*.txt + +%files -n Irrlicht-media +%defattr(-, root, root) +%dir %{_datadir}/irrlicht +%{_datadir}/irrlicht/* + +%changelog +* Wed Jun 20 2007 Toni Graffy - 1.3.1-0.pm.1 +- update to 1.3.1 +* Sat Jun 16 2007 Toni Graffy - 1.3-0.pm.1 +- initial build 1.3 diff --git a/scripts/packages/OSX/Irrlicht.pmdoc/01irrlicht-contents.xml b/scripts/packages/OSX/Irrlicht.pmdoc/01irrlicht-contents.xml new file mode 100644 index 00000000..2a239178 --- /dev/null +++ b/scripts/packages/OSX/Irrlicht.pmdoc/01irrlicht-contents.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/scripts/packages/OSX/Irrlicht.pmdoc/01irrlicht.xml b/scripts/packages/OSX/Irrlicht.pmdoc/01irrlicht.xml new file mode 100644 index 00000000..04586ca2 --- /dev/null +++ b/scripts/packages/OSX/Irrlicht.pmdoc/01irrlicht.xml @@ -0,0 +1 @@ +org.irrlichtengine.irrlichtEngineV151.irrlicht.pkg1/Library/Frameworks/Irrlicht.framework/Library/FrameworksparentrequireAuthorizationextraFilesversioninstallToidentifier01irrlicht-contents.xml/CVS$/\.svn$/\.cvsignore$/\.cvspass$/\.DS_Store$ \ No newline at end of file diff --git a/scripts/packages/OSX/Irrlicht.pmdoc/02html-contents.xml b/scripts/packages/OSX/Irrlicht.pmdoc/02html-contents.xml new file mode 100644 index 00000000..b38a0d01 --- /dev/null +++ b/scripts/packages/OSX/Irrlicht.pmdoc/02html-contents.xml @@ -0,0 +1 @@ +modemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemode \ No newline at end of file diff --git a/scripts/packages/OSX/Irrlicht.pmdoc/02html.xml b/scripts/packages/OSX/Irrlicht.pmdoc/02html.xml new file mode 100644 index 00000000..ec6568ed --- /dev/null +++ b/scripts/packages/OSX/Irrlicht.pmdoc/02html.xml @@ -0,0 +1 @@ +com.irrlicht.irrlichtEngineV151.html.pkg1../../../doctemp/html/private/tmp/Irrlicht1.5.1-install/doc/parentscripts.postinstall.pathrequireAuthorizationinstallTo.isAbsoluteTypescripts.postinstall.isRelativeTypeinstallFrom.isRelativeTypeinstallTo.pathversioninstallTo02html-contents.xml/CVS$/\.svn$/\.cvsignore$/\.cvspass$/\.DS_Store$ \ No newline at end of file diff --git a/scripts/packages/OSX/Irrlicht.pmdoc/03media-contents.xml b/scripts/packages/OSX/Irrlicht.pmdoc/03media-contents.xml new file mode 100644 index 00000000..4c2675fc --- /dev/null +++ b/scripts/packages/OSX/Irrlicht.pmdoc/03media-contents.xml @@ -0,0 +1 @@ +modemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemode \ No newline at end of file diff --git a/scripts/packages/OSX/Irrlicht.pmdoc/03media.xml b/scripts/packages/OSX/Irrlicht.pmdoc/03media.xml new file mode 100644 index 00000000..4c288701 --- /dev/null +++ b/scripts/packages/OSX/Irrlicht.pmdoc/03media.xml @@ -0,0 +1 @@ +com.irrlicht.irrlichtEngineV151.media.pkg1/Users/gazdavidson/svn/irr1.5/media/private/tmp/Irrlicht1.5.1-install/media/parentinstallTo.pathinstallTo03media-contents.xml/CVS$/\.svn$/\.cvsignore$/\.cvspass$/\.DS_Store$ \ No newline at end of file diff --git a/scripts/packages/OSX/Irrlicht.pmdoc/04examples-contents.xml b/scripts/packages/OSX/Irrlicht.pmdoc/04examples-contents.xml new file mode 100644 index 00000000..53ff5d1d --- /dev/null +++ b/scripts/packages/OSX/Irrlicht.pmdoc/04examples-contents.xml @@ -0,0 +1 @@ +modemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemode \ No newline at end of file diff --git a/scripts/packages/OSX/Irrlicht.pmdoc/04examples.xml b/scripts/packages/OSX/Irrlicht.pmdoc/04examples.xml new file mode 100644 index 00000000..708581e8 --- /dev/null +++ b/scripts/packages/OSX/Irrlicht.pmdoc/04examples.xml @@ -0,0 +1 @@ +com.irrlicht.irrlichtEngineV151.examples.pkg1/Users/gazdavidson/svn/irr1.5/examples/private/tmp/Irrlicht1.5.1-install/examples/parentinstallTo.pathinstallTo04examples-contents.xml/CVS$/\.svn$/\.cvsignore$/\.cvspass$/\.DS_Store$ \ No newline at end of file diff --git a/scripts/packages/OSX/Irrlicht.pmdoc/05tools-contents.xml b/scripts/packages/OSX/Irrlicht.pmdoc/05tools-contents.xml new file mode 100644 index 00000000..938cdff3 --- /dev/null +++ b/scripts/packages/OSX/Irrlicht.pmdoc/05tools-contents.xml @@ -0,0 +1 @@ +modemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemodemode \ No newline at end of file diff --git a/scripts/packages/OSX/Irrlicht.pmdoc/05tools.xml b/scripts/packages/OSX/Irrlicht.pmdoc/05tools.xml new file mode 100644 index 00000000..3e6b72cf --- /dev/null +++ b/scripts/packages/OSX/Irrlicht.pmdoc/05tools.xml @@ -0,0 +1 @@ +com.irrlicht.irrlichtEngineV151.tools.pkg1/Users/gazdavidson/svn/irr1.5/tools/private/tmp/Irrlicht1.5.1-install/tools/parentinstallTo.pathinstallTo05tools-contents.xml/CVS$/\.svn$/\.cvsignore$/\.cvspass$/\.DS_Store$ \ No newline at end of file diff --git a/scripts/packages/OSX/Irrlicht.pmdoc/06source-contents.xml b/scripts/packages/OSX/Irrlicht.pmdoc/06source-contents.xml new file mode 100644 index 00000000..e76268a6 --- /dev/null +++ b/scripts/packages/OSX/Irrlicht.pmdoc/06source-contents.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/scripts/packages/OSX/Irrlicht.pmdoc/06source.xml b/scripts/packages/OSX/Irrlicht.pmdoc/06source.xml new file mode 100644 index 00000000..80b2d535 --- /dev/null +++ b/scripts/packages/OSX/Irrlicht.pmdoc/06source.xml @@ -0,0 +1 @@ +com.irrlicht.irrlichtEngineV151.source.pkg1/Users/gazdavidson/svn/irr1.5/source/private/tmp/Irrlicht1.5.1-install/source/parentinstallTo.pathinstallTo06source-contents.xml/CVS$/\.svn$/\.cvsignore$/\.cvspass$/\.DS_Store$ \ No newline at end of file diff --git a/scripts/packages/OSX/Irrlicht.pmdoc/07changes-contents.xml b/scripts/packages/OSX/Irrlicht.pmdoc/07changes-contents.xml new file mode 100644 index 00000000..fa2aafd7 --- /dev/null +++ b/scripts/packages/OSX/Irrlicht.pmdoc/07changes-contents.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/scripts/packages/OSX/Irrlicht.pmdoc/07changes.xml b/scripts/packages/OSX/Irrlicht.pmdoc/07changes.xml new file mode 100644 index 00000000..98229b57 --- /dev/null +++ b/scripts/packages/OSX/Irrlicht.pmdoc/07changes.xml @@ -0,0 +1 @@ +com.irrlicht.irrlichtEngineV151.changes.pkg1/Users/gazdavidson/svn/irr1.5/changes.txt/private/tmp/Irrlicht1.5.1-install/parentinstallTo.pathinstallTo07changes-contents.xml/CVS$/\.svn$/\.cvsignore$/\.cvspass$/\.DS_Store$ \ No newline at end of file diff --git a/scripts/packages/OSX/Irrlicht.pmdoc/08readme-contents.xml b/scripts/packages/OSX/Irrlicht.pmdoc/08readme-contents.xml new file mode 100644 index 00000000..8a4b0b7b --- /dev/null +++ b/scripts/packages/OSX/Irrlicht.pmdoc/08readme-contents.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/scripts/packages/OSX/Irrlicht.pmdoc/08readme.xml b/scripts/packages/OSX/Irrlicht.pmdoc/08readme.xml new file mode 100644 index 00000000..84b7b478 --- /dev/null +++ b/scripts/packages/OSX/Irrlicht.pmdoc/08readme.xml @@ -0,0 +1 @@ +com.irrlicht.irrlichtEngineV151.readme.pkg1/Users/gazdavidson/svn/irr1.5/readme.txt/private/tmp/Irrlicht1.5.1-install/parentscripts.postinstall.pathscripts.postupgrade.isRelativeTypescripts.postupgrade.pathinstallTo.pathinstallTomoveAll.shmoveAll.sh08readme-contents.xml/CVS$/\.svn$/\.cvsignore$/\.cvspass$/\.DS_Store$ \ No newline at end of file diff --git a/scripts/packages/OSX/Irrlicht.pmdoc/index.xml b/scripts/packages/OSX/Irrlicht.pmdoc/index.xml new file mode 100644 index 00000000..5cf8820f --- /dev/null +++ b/scripts/packages/OSX/Irrlicht.pmdoc/index.xml @@ -0,0 +1,47 @@ +Irrlicht Engine v1.5.1/Users/gazdavidson/Desktop/installer/Irrlicht v1.5.1.mpkgcom.irrlicht01irrlicht.xml02html.xml03media.xml04examples.xml05tools.xml06source.xml07changes.xml08readme.xmlproperties.userDomainproperties.systemDomainproperties.anywhereDomainproperties.customizeOptionextraFilesproperties.title \ No newline at end of file diff --git a/scripts/packages/OSX/moveAll.sh b/scripts/packages/OSX/moveAll.sh new file mode 100755 index 00000000..f461fceb --- /dev/null +++ b/scripts/packages/OSX/moveAll.sh @@ -0,0 +1,6 @@ +#!/bin/sh +mkdir -p $HOME/Irrlicht1.6.0/ +chmod a+rw $HOME/Irrlicht1.6.0 +find /private/tmp/Irrlicht1.6.0-install -exec chmod a+rw {} \; +cp -rfp /private/tmp/Irrlicht1.6.0-install/ $HOME/Irrlicht1.6.0/ +rm -Rf /private/tmp/Irrlicht1.6.0-install diff --git a/scripts/packages/OSX/readme.txt b/scripts/packages/OSX/readme.txt new file mode 100644 index 00000000..9e39c410 --- /dev/null +++ b/scripts/packages/OSX/readme.txt @@ -0,0 +1,28 @@ +This is the source package for the Irrlicht framework installer. + +Build steps are as follows- + +1) Remove the framework so you don't accidentally package more than one version, if you use the GUI to do this empty the trash so XCode doesn't build to the trash! It's best to run this command from the console: + + rm -Rf /Library/Frameworks/Irrlicht.framework + +2) Build the library and the binaries. + + * Navigate to source/Irrlicht/MacOSX and open the XCode project + + * Choose release mode and build Irrlicht.framework + + ** For the moment it's not worth installing the sample binaries, they can't be launched due to console input + +3) Build the documentation + + * Open the console and navigate to scripts/doc/irrlicht + + * Make sure you have doxygen installed. If you have Aptitude for OSX then type: + + sudo apt-get install doxygen + + * Now run the makedocumentation bash script: + ./makedocumentation.sh + +4) Now double click the package file and build it. diff --git a/source/Irrlicht/Android/CAndroidAssetFileArchive.cpp b/source/Irrlicht/Android/CAndroidAssetFileArchive.cpp new file mode 100644 index 00000000..53d06f8c --- /dev/null +++ b/source/Irrlicht/Android/CAndroidAssetFileArchive.cpp @@ -0,0 +1,110 @@ +// Copyright (C) 2002-2011 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" + +#ifdef _IRR_COMPILE_ANDROID_ASSET_READER_ + +#include "CAndroidAssetReader.h" + +#include "CReadFile.h" +#include "coreutil.h" +#include "CAndroidAssetFileArchive.h" +#include "CIrrDeviceAndroid.h" +#include "os.h" // for logging (just keep it in even when not needed right now as it's used all the time) + +#include +#include +#include + +namespace irr +{ +namespace io +{ + +CAndroidAssetFileArchive::CAndroidAssetFileArchive(AAssetManager *assetManager, bool ignoreCase, bool ignorePaths) + : CFileList("/asset", ignoreCase, ignorePaths), AssetManager(assetManager) +{ +} + + +CAndroidAssetFileArchive::~CAndroidAssetFileArchive() +{ +} + + +//! get the archive type +E_FILE_ARCHIVE_TYPE CAndroidAssetFileArchive::getType() const +{ + return EFAT_ANDROID_ASSET; +} + +const IFileList* CAndroidAssetFileArchive::getFileList() const +{ + // The assert_manager can not read directory names, so + // getFileList returns only files in folders which have been added. + return this; +} + + +//! opens a file by file name +IReadFile* CAndroidAssetFileArchive::createAndOpenFile(const io::path& filename) +{ + CAndroidAssetReader *reader = new CAndroidAssetReader(AssetManager, filename); + + if(reader->isOpen()) + return reader; + + reader->drop(); + return NULL; +} + +//! opens a file by index +IReadFile* CAndroidAssetFileArchive::createAndOpenFile(u32 index) +{ + const io::path& filename(getFullFileName(index)); + if ( filename.empty() ) + return 0; + + return createAndOpenFile(filename); +} + +void CAndroidAssetFileArchive::addDirectoryToFileList(const io::path &dirname_) +{ + io::path dirname(dirname_); + fschar_t lastChar = dirname.lastChar(); + if ( lastChar == '/' || lastChar == '\\' ) + dirname.erase(dirname.size()-1); + + // os::Printer::log("addDirectoryToFileList:", dirname.c_str(), ELL_DEBUG); + if (findFile(dirname, true) >= 0 ) + return; // was already added + + AAssetDir *dir = AAssetManager_openDir(AssetManager, core::stringc(dirname).c_str()); + if(!dir) + return; + + // add directory itself + addItem(dirname, 0, 0, /*isDir*/true, getFileCount()); + + // add all files in folder. + // Note: AAssetDir_getNextFileName does not return directory names (neither does any other NDK function) + while(const char *filename = AAssetDir_getNextFileName(dir)) + { + core::stringc full_filename= dirname=="" ? filename + : dirname+"/"+filename; + + // We can't get the size without opening the file - so for performance + // reasons we set the file size to 0. + // TODO: Does this really cost so much performance that it's worth losing this information? Dirs are usually just added once at startup... + addItem(full_filename, /*offet*/0, /*size*/0, /*isDir*/false, getFileCount()); + // os::Printer::log("addItem:", full_filename.c_str(), ELL_DEBUG); + } + AAssetDir_close(dir); +} + +} // end namespace io +} // end namespace irr + +#endif // _IRR_COMPILE_ANDROID_ASSET_READER_ diff --git a/source/Irrlicht/Android/CAndroidAssetFileArchive.h b/source/Irrlicht/Android/CAndroidAssetFileArchive.h new file mode 100644 index 00000000..7acf9f41 --- /dev/null +++ b/source/Irrlicht/Android/CAndroidAssetFileArchive.h @@ -0,0 +1,70 @@ +// Copyright (C) 2012 Joerg Henrichs +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_ANDROID_ASSET_FILE_ARCHIVE_H_INCLUDED__ +#define __C_ANDROID_ASSET_FILE_ARCHIVE_H_INCLUDED__ + + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_ANDROID_ASSET_READER_ + + +#include "IReadFile.h" +#include "IFileArchive.h" +#include "CFileList.h" + +#include + +namespace irr +{ +namespace io +{ + +/*! + Android asset file system written August 2012 by J.Henrichs (later reworked by others). +*/ + class CAndroidAssetFileArchive : public virtual IFileArchive, + virtual CFileList + { + public: + + //! constructor + CAndroidAssetFileArchive(AAssetManager *assetManager, bool ignoreCase, bool ignorePaths); + + //! destructor + virtual ~CAndroidAssetFileArchive(); + + //! opens a file by file name + virtual IReadFile* createAndOpenFile(const io::path& filename); + + //! opens a file by index + virtual IReadFile* createAndOpenFile(u32 index); + + //! returns the list of files + virtual const IFileList* getFileList() const; + + //! get the archive type + virtual E_FILE_ARCHIVE_TYPE getType() const; + + //! Add a directory to read files from. Since the Android + //! API does not return names of directories, they need to + //! be added manually. + virtual void addDirectoryToFileList(const io::path &filename); + + //! return the name (id) of the file Archive + virtual const io::path& getArchiveName() const _IRR_OVERRIDE_ {return Path;} + + protected: + //! Android's asset manager + AAssetManager *AssetManager; + + }; // CAndroidAssetFileArchive + +} // end namespace io +} // end namespace irr + +#endif // _IRR_COMPILE_ANDROID_ASSET_READER_ +#endif // __C_ANDROID_ASSET_READER_H_INCLUDED__ + diff --git a/source/Irrlicht/Android/CAndroidAssetReader.cpp b/source/Irrlicht/Android/CAndroidAssetReader.cpp new file mode 100644 index 00000000..ef1529be --- /dev/null +++ b/source/Irrlicht/Android/CAndroidAssetReader.cpp @@ -0,0 +1,73 @@ +// Copyright (C) 2002-2011 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" + +#ifdef _IRR_COMPILE_ANDROID_ASSET_READER_ + +#include "CAndroidAssetReader.h" + +#include "CReadFile.h" +#include "coreutil.h" +#include "CAndroidAssetReader.h" +#include "CIrrDeviceAndroid.h" + +#include +#include + +namespace irr +{ +namespace io +{ + +CAndroidAssetReader::CAndroidAssetReader(AAssetManager *assetManager, const io::path &filename) + : AssetManager(assetManager), Filename(filename) +{ + Asset = AAssetManager_open(AssetManager, + core::stringc(filename).c_str(), + AASSET_MODE_RANDOM); + +} + +CAndroidAssetReader::~CAndroidAssetReader() +{ + if(Asset) + AAsset_close(Asset); +} + +size_t CAndroidAssetReader::read(void* buffer, size_t sizeToRead) +{ + int readBytes = AAsset_read(Asset, buffer, sizeToRead); + if ( readBytes >= 0 ) + return size_t(readBytes); + return 0; // direct fd access is not possible (for example, if the asset is compressed). +} + +bool CAndroidAssetReader::seek(long finalPos, bool relativeMovement) +{ + off_t status = AAsset_seek(Asset, finalPos, relativeMovement ? SEEK_CUR : SEEK_SET); + + return status+1; +} + +long CAndroidAssetReader::getSize() const +{ + return AAsset_getLength(Asset); +} + +long CAndroidAssetReader::getPos() const +{ + return AAsset_getLength(Asset) - AAsset_getRemainingLength(Asset); +} + +const io::path& CAndroidAssetReader::getFileName() const +{ + return Filename; +} + + +} // end namespace io +} // end namespace irr + +#endif // _IRR_COMPILE_ANDROID_ASSET_READER_ diff --git a/source/Irrlicht/Android/CAndroidAssetReader.h b/source/Irrlicht/Android/CAndroidAssetReader.h new file mode 100644 index 00000000..c9d96a54 --- /dev/null +++ b/source/Irrlicht/Android/CAndroidAssetReader.h @@ -0,0 +1,75 @@ +// Copyright (C) 2012 Joerg Henrichs +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_ANDROID_ASSET_READER_H_INCLUDED__ +#define __C_ANDROID_ASSET_READER_H_INCLUDED__ + + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_ANDROID_ASSET_READER_ + + +#include "IReadFile.h" + +struct AAssetManager; +struct AAsset; +struct ANativeActivity; + +namespace irr +{ +namespace io +{ + + class CAndroidAssetReader : public virtual IReadFile + { + public: + CAndroidAssetReader(AAssetManager *assetManager, const io::path &filename); + + virtual ~CAndroidAssetReader(); + + //! Reads an amount of bytes from the file. + /** \param buffer Pointer to buffer where read bytes are written to. + \param sizeToRead Amount of bytes to read from the file. + \return How many bytes were read. */ + virtual size_t read(void* buffer, size_t sizeToRead); + + //! Changes position in file + /** \param finalPos Destination position in the file. + \param relativeMovement If set to true, the position in the file is + changed relative to current position. Otherwise the position is changed + from beginning of file. + \return True if successful, otherwise false. */ + virtual bool seek(long finalPos, bool relativeMovement = false); + + //! Get size of file. + /** \return Size of the file in bytes. */ + virtual long getSize() const; + + //! Get the current position in the file. + /** \return Current position in the file in bytes. */ + virtual long getPos() const; + + //! Get name of file. + /** \return File name as zero terminated character string. */ + virtual const io::path& getFileName() const; + + /** Return true if the file could be opened. */ + bool isOpen() const { return Asset!=NULL; } + + private: + //! Android's asset manager + AAssetManager *AssetManager; + + // An asset, i.e. file + AAsset *Asset; + path Filename; + }; + +} // end namespace io +} // end namespace irr + +#endif // _IRR_COMPILE_ANDROID_ASSET_READER_ +#endif // __C_ANDROID_ASSET_READER_H_INCLUDED__ + diff --git a/source/Irrlicht/Android/CIrrDeviceAndroid.cpp b/source/Irrlicht/Android/CIrrDeviceAndroid.cpp new file mode 100644 index 00000000..c88ee34d --- /dev/null +++ b/source/Irrlicht/Android/CIrrDeviceAndroid.cpp @@ -0,0 +1,869 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// Copyright (C) 2007-2011 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CIrrDeviceAndroid.h" + +#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_ + +#include "os.h" +#include "CFileSystem.h" +#include "CAndroidAssetReader.h" +#include "CAndroidAssetFileArchive.h" +#include "CKeyEventWrapper.h" +#include "CEGLManager.h" +#include "ISceneManager.h" +#include "IGUIEnvironment.h" +#include "CEGLManager.h" + +namespace irr +{ + namespace video + { + IVideoDriver* createOGLES1Driver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io, video::IContextManager* contextManager); + + IVideoDriver* createOGLES2Driver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io, video::IContextManager* contextManager); + } +} + +namespace irr +{ + +CIrrDeviceAndroid::CIrrDeviceAndroid(const SIrrlichtCreationParameters& param) + : CIrrDeviceStub(param), Accelerometer(0), Gyroscope(0), Focused(false), Initialized(false), Paused(true), JNIEnvAttachedToVM(0) +{ +#ifdef _DEBUG + setDebugName("CIrrDeviceAndroid"); +#endif + + // Get the interface to the native Android activity. + Android = (android_app*)(param.PrivateData); + + // Set the private data so we can use it in any static callbacks. + Android->userData = this; + + // Set the default command handler. This is a callback function that the Android + // OS invokes to send the native activity messages. + Android->onAppCmd = handleAndroidCommand; + + createKeyMap(); + + // Create a sensor manager to receive touch screen events from the java activity. + SensorManager = ASensorManager_getInstance(); + SensorEventQueue = ASensorManager_createEventQueue(SensorManager, Android->looper, LOOPER_ID_USER, 0, 0); + Android->onInputEvent = handleInput; + + // Create EGL manager. + ContextManager = new video::CEGLManager(); + + os::Printer::log("Waiting for Android activity window to be created.", ELL_DEBUG); + + do + { + s32 Events = 0; + android_poll_source* Source = 0; + + while ((ALooper_pollAll(((Focused && !Paused) || !Initialized) ? 0 : -1, 0, &Events, (void**)&Source)) >= 0) + { + if(Source) + Source->process(Android, Source); + } + } + while(!Initialized); +} + + +CIrrDeviceAndroid::~CIrrDeviceAndroid() +{ + if (GUIEnvironment) + { + GUIEnvironment->drop(); + GUIEnvironment = 0; + } + + if (SceneManager) + { + SceneManager->drop(); + SceneManager = 0; + } + + if (VideoDriver) + { + VideoDriver->drop(); + VideoDriver = 0; + } +} + +bool CIrrDeviceAndroid::run() +{ + if (!Initialized) + return false; + + os::Timer::tick(); + + s32 id; + s32 Events = 0; + android_poll_source* Source = 0; + + while ((id = ALooper_pollAll(((Focused && !Paused) || !Initialized) ? 0 : -1, 0, &Events, (void**)&Source)) >= 0) + { + if(Source) + Source->process(Android, Source); + + // if a sensor has data, we'll process it now. + if (id == LOOPER_ID_USER) + { + ASensorEvent sensorEvent; + while (ASensorEventQueue_getEvents(SensorEventQueue, &sensorEvent, 1) > 0) + { + switch (sensorEvent.type) + { + case ASENSOR_TYPE_ACCELEROMETER: + SEvent accEvent; + accEvent.EventType = EET_ACCELEROMETER_EVENT; + accEvent.AccelerometerEvent.X = sensorEvent.acceleration.x; + accEvent.AccelerometerEvent.Y = sensorEvent.acceleration.y; + accEvent.AccelerometerEvent.Z = sensorEvent.acceleration.z; + + postEventFromUser(accEvent); + break; + + case ASENSOR_TYPE_GYROSCOPE: + SEvent gyroEvent; + gyroEvent.EventType = EET_GYROSCOPE_EVENT; + gyroEvent.GyroscopeEvent.X = sensorEvent.vector.x; + gyroEvent.GyroscopeEvent.Y = sensorEvent.vector.y; + gyroEvent.GyroscopeEvent.Z = sensorEvent.vector.z; + + postEventFromUser(gyroEvent); + break; + default: + break; + } + } + } + + if(!Initialized) + break; + } + + return Initialized; +} + +void CIrrDeviceAndroid::yield() +{ + struct timespec ts = {0,1}; + nanosleep(&ts, NULL); +} + +void CIrrDeviceAndroid::sleep(u32 timeMs, bool pauseTimer) +{ + const bool wasStopped = Timer ? Timer->isStopped() : true; + + struct timespec ts; + ts.tv_sec = (time_t) (timeMs / 1000); + ts.tv_nsec = (long) (timeMs % 1000) * 1000000; + + if (pauseTimer && !wasStopped) + Timer->stop(); + + nanosleep(&ts, NULL); + + if (pauseTimer && !wasStopped) + Timer->start(); +} + +void CIrrDeviceAndroid::setWindowCaption(const wchar_t* text) +{ +} + +bool CIrrDeviceAndroid::present(video::IImage* surface, void* windowId, core::rect* srcClip) +{ + return true; +} + +bool CIrrDeviceAndroid::isWindowActive() const +{ + return (Focused && !Paused); +} + +bool CIrrDeviceAndroid::isWindowFocused() const +{ + return Focused; +} + +bool CIrrDeviceAndroid::isWindowMinimized() const +{ + return !Focused; +} + +void CIrrDeviceAndroid::closeDevice() +{ + ANativeActivity_finish(Android->activity); +} + +void CIrrDeviceAndroid::setResizable(bool resize) +{ +} + +void CIrrDeviceAndroid::minimizeWindow() +{ +} + +void CIrrDeviceAndroid::maximizeWindow() +{ +} + +void CIrrDeviceAndroid::restoreWindow() +{ +} + +core::position2di CIrrDeviceAndroid::getWindowPosition() +{ + return core::position2di(0, 0); +} + +E_DEVICE_TYPE CIrrDeviceAndroid::getType() const +{ + return EIDT_ANDROID; +} + +void CIrrDeviceAndroid::handleAndroidCommand(android_app* app, int32_t cmd) +{ + CIrrDeviceAndroid* device = (CIrrDeviceAndroid*)app->userData; + + SEvent event; + event.EventType = EET_SYSTEM_EVENT; + event.SystemEvent.EventType = ESET_ANDROID_CMD; + event.SystemEvent.AndroidCmd.Cmd = cmd; + if ( device->postEventFromUser(event) ) + return; + + switch (cmd) + { + case APP_CMD_INPUT_CHANGED: + os::Printer::log("Android command APP_CMD_INPUT_CHANGED", ELL_DEBUG); + break; + case APP_CMD_WINDOW_RESIZED: + os::Printer::log("Android command APP_CMD_WINDOW_RESIZED", ELL_DEBUG); + break; + case APP_CMD_WINDOW_REDRAW_NEEDED: + os::Printer::log("Android command APP_CMD_WINDOW_REDRAW_NEEDED", ELL_DEBUG); + break; + case APP_CMD_SAVE_STATE: + os::Printer::log("Android command APP_CMD_SAVE_STATE", ELL_DEBUG); + break; + case APP_CMD_CONTENT_RECT_CHANGED: + os::Printer::log("Android command APP_CMD_CONTENT_RECT_CHANGED", ELL_DEBUG); + break; + case APP_CMD_CONFIG_CHANGED: + os::Printer::log("Android command APP_CMD_CONFIG_CHANGED", ELL_DEBUG); + break; + case APP_CMD_LOW_MEMORY: + os::Printer::log("Android command APP_CMD_LOW_MEMORY", ELL_DEBUG); + break; + case APP_CMD_START: + os::Printer::log("Android command APP_CMD_START", ELL_DEBUG); + break; + case APP_CMD_INIT_WINDOW: + os::Printer::log("Android command APP_CMD_INIT_WINDOW", ELL_DEBUG); + device->getExposedVideoData().OGLESAndroid.Window = app->window; + + if (device->CreationParams.WindowSize.Width == 0 || device->CreationParams.WindowSize.Height == 0) + { + device->CreationParams.WindowSize.Width = ANativeWindow_getWidth(app->window); + device->CreationParams.WindowSize.Height = ANativeWindow_getHeight(app->window); + } + + device->getContextManager()->initialize(device->CreationParams, device->ExposedVideoData); + device->getContextManager()->generateSurface(); + device->getContextManager()->generateContext(); + device->getContextManager()->activateContext(device->getContextManager()->getContext()); + + if (!device->Initialized) + { + io::CAndroidAssetFileArchive* assets = new io::CAndroidAssetFileArchive( device->Android->activity->assetManager, false, false); + assets->addDirectoryToFileList(""); + device->FileSystem->addFileArchive(assets); + assets->drop(); + + device->createDriver(); + + if (device->VideoDriver) + device->createGUIAndScene(); + } + device->Initialized = true; + break; + case APP_CMD_TERM_WINDOW: + os::Printer::log("Android command APP_CMD_TERM_WINDOW", ELL_DEBUG); + device->getContextManager()->destroySurface(); + break; + case APP_CMD_GAINED_FOCUS: + os::Printer::log("Android command APP_CMD_GAINED_FOCUS", ELL_DEBUG); + device->Focused = true; + break; + case APP_CMD_LOST_FOCUS: + os::Printer::log("Android command APP_CMD_LOST_FOCUS", ELL_DEBUG); + device->Focused = false; + break; + case APP_CMD_DESTROY: + os::Printer::log("Android command APP_CMD_DESTROY", ELL_DEBUG); + if ( device->JNIEnvAttachedToVM ) + { + device->JNIEnvAttachedToVM = 0; + device->Android->activity->vm->DetachCurrentThread(); + } + device->Initialized = false; + break; + case APP_CMD_PAUSE: + os::Printer::log("Android command APP_CMD_PAUSE", ELL_DEBUG); + device->Paused = true; + break; + case APP_CMD_STOP: + os::Printer::log("Android command APP_CMD_STOP", ELL_DEBUG); + break; + case APP_CMD_RESUME: + os::Printer::log("Android command APP_CMD_RESUME", ELL_DEBUG); + device->Paused = false; + break; + default: + break; + } +} + +s32 CIrrDeviceAndroid::handleInput(android_app* app, AInputEvent* androidEvent) +{ + CIrrDeviceAndroid* device = (CIrrDeviceAndroid*)app->userData; + s32 status = 0; + + switch ( AInputEvent_getType(androidEvent) ) + { + case AINPUT_EVENT_TYPE_MOTION: + { + SEvent event; + event.EventType = EET_TOUCH_INPUT_EVENT; + + s32 eventAction = AMotionEvent_getAction(androidEvent); + s32 eventType = eventAction & AMOTION_EVENT_ACTION_MASK; + +#if 0 + // Useful for debugging. We might have to pass some of those infos on at some point. + // but preferably device independent (so iphone can use same irrlicht flags). + int32_t flags = AMotionEvent_getFlags(androidEvent); + os::Printer::log("flags: ", core::stringc(flags).c_str(), ELL_DEBUG); + int32_t metaState = AMotionEvent_getMetaState(androidEvent); + os::Printer::log("metaState: ", core::stringc(metaState).c_str(), ELL_DEBUG); + int32_t edgeFlags = AMotionEvent_getEdgeFlags(androidEvent); + os::Printer::log("edgeFlags: ", core::stringc(flags).c_str(), ELL_DEBUG); +#endif + + bool touchReceived = true; + + switch (eventType) + { + case AMOTION_EVENT_ACTION_DOWN: + case AMOTION_EVENT_ACTION_POINTER_DOWN: + event.TouchInput.Event = ETIE_PRESSED_DOWN; + break; + case AMOTION_EVENT_ACTION_MOVE: + event.TouchInput.Event = ETIE_MOVED; + break; + case AMOTION_EVENT_ACTION_UP: + case AMOTION_EVENT_ACTION_POINTER_UP: + case AMOTION_EVENT_ACTION_CANCEL: + event.TouchInput.Event = ETIE_LEFT_UP; + break; + default: + touchReceived = false; + break; + } + + if (touchReceived) + { + // Process all touches for move action. + if (event.TouchInput.Event == ETIE_MOVED) + { + s32 pointerCount = AMotionEvent_getPointerCount(androidEvent); + + for (s32 i = 0; i < pointerCount; ++i) + { + event.TouchInput.ID = AMotionEvent_getPointerId(androidEvent, i); + event.TouchInput.X = AMotionEvent_getX(androidEvent, i); + event.TouchInput.Y = AMotionEvent_getY(androidEvent, i); + + device->postEventFromUser(event); + } + } + else // Process one touch for other actions. + { + s32 pointerIndex = (eventAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + + event.TouchInput.ID = AMotionEvent_getPointerId(androidEvent, pointerIndex); + event.TouchInput.X = AMotionEvent_getX(androidEvent, pointerIndex); + event.TouchInput.Y = AMotionEvent_getY(androidEvent, pointerIndex); + + device->postEventFromUser(event); + } + + status = 1; + } + } + break; + case AINPUT_EVENT_TYPE_KEY: + { + SEvent event; + event.EventType = EET_KEY_INPUT_EVENT; + + int32_t keyCode = AKeyEvent_getKeyCode(androidEvent); + // os::Printer::log("keyCode: ", core::stringc(keyCode).c_str(), ELL_DEBUG); + + int32_t keyAction = AKeyEvent_getAction(androidEvent); + int32_t keyMetaState = AKeyEvent_getMetaState(androidEvent); + + if ( keyCode >= 0 && (u32)keyCode < device->KeyMap.size() ) + event.KeyInput.Key = device->KeyMap[keyCode]; + else + event.KeyInput.Key = KEY_UNKNOWN; + event.KeyInput.SystemKeyCode = (u32)keyCode; + if ( keyAction == AKEY_EVENT_ACTION_DOWN ) + event.KeyInput.PressedDown = true; + else if ( keyAction == AKEY_EVENT_ACTION_UP ) + event.KeyInput.PressedDown = false; + else if ( keyAction == AKEY_EVENT_ACTION_MULTIPLE ) + { + // TODO: Multiple duplicate key events have occurred in a row, + // or a complex string is being delivered. The repeat_count + // property of the key event contains the number of times the + // given key code should be executed. + // I guess this might necessary for more complicated i18n key input, + // but don't see yet how to handle this correctly. + } + + /* no use for meta keys so far. + if ( keyMetaState & AMETA_ALT_ON + || keyMetaState & AMETA_ALT_LEFT_ON + || keyMetaState & AMETA_ALT_RIGHT_ON ) + ; + // what is a sym? + if ( keyMetaState & AMETA_SYM_ON ) + ; + */ + if ( keyMetaState & AMETA_SHIFT_ON + || keyMetaState & AMETA_SHIFT_LEFT_ON + || keyMetaState & AMETA_SHIFT_RIGHT_ON ) + event.KeyInput.Shift = true; + else + event.KeyInput.Shift = false; + event.KeyInput.Control = false; + + // Having memory allocations + going through JNI for each key-press is pretty bad (slow). + // So we do it only for those keys which are likely text-characters and avoid it for all other keys. + // So it's fast for keys like game controller input and special keys. And text keys are typically + // only used or entering text and not for gaming on Android, so speed likely doesn't matter there too much. + if ( event.KeyInput.Key > 0 ) + { + // TODO: + // Not sure why we have to attach a JNIEnv here, but it won't work when doing that in the constructor or + // trying to use the activity->env. My best guess is that the event-handling happens in an own thread. + // It means JNIEnvAttachedToVM will never get detached as I don't know a safe way where to do that + // (we could attach & detach each time, but that would probably be slow) + // Also - it has to be each time as it get's invalid when the application mode changes. + if ( device->Initialized && device->Android && device->Android->activity && device->Android->activity->vm ) + { + JavaVMAttachArgs attachArgs; + attachArgs.version = JNI_VERSION_1_6; + attachArgs.name = 0; + attachArgs.group = NULL; + + // Not a big problem calling it each time - it's a no-op when the thread already is attached. + // And we have to do that as someone else can have detached the thread in the meantime. + jint result = device->Android->activity->vm->AttachCurrentThread(&device->JNIEnvAttachedToVM, &attachArgs); + if(result == JNI_ERR) + { + os::Printer::log("AttachCurrentThread for the JNI environment failed.", ELL_WARNING); + device->JNIEnvAttachedToVM = 0; + } + + if ( device->JNIEnvAttachedToVM ) + { + jni::CKeyEventWrapper * keyEventWrapper = new jni::CKeyEventWrapper(device->JNIEnvAttachedToVM, keyAction, keyCode); + event.KeyInput.Char = keyEventWrapper->getUnicodeChar(keyMetaState); + delete keyEventWrapper; + } + } + if ( event.KeyInput.Key == KEY_BACK ) + { + event.KeyInput.Char = 0x08; // same key-code as on other operating systems. Otherwise we have to handle too much system specific stuff in the editbox. + } + //os::Printer::log("char-code: ", core::stringc((int)event.KeyInput.Char).c_str(), ELL_DEBUG); + + } + else + { + // os::Printer::log("keyCode: ", core::stringc(keyCode).c_str(), ELL_DEBUG); + event.KeyInput.Char = 0; + } + + device->postEventFromUser(event); + } + break; + default: + break; + } + + return status; +} + +void CIrrDeviceAndroid::createDriver() +{ + switch(CreationParams.DriverType) + { + case video::EDT_OGLES1: +#ifdef _IRR_COMPILE_WITH_OGLES1_ + VideoDriver = video::createOGLES1Driver(CreationParams, FileSystem, ContextManager); +#else + os::Printer::log("No OpenGL ES 1.0 support compiled in.", ELL_ERROR); +#endif + break; + case video::EDT_OGLES2: +#ifdef _IRR_COMPILE_WITH_OGLES2_ + VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager); +#else + os::Printer::log("No OpenGL ES 2.0 support compiled in.", ELL_ERROR); +#endif + break; + case video::EDT_NULL: + VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize); + break; + case video::EDT_SOFTWARE: + case video::EDT_BURNINGSVIDEO: + case video::EDT_OPENGL: + case video::DEPRECATED_EDT_DIRECT3D8_NO_LONGER_EXISTS: + case video::EDT_DIRECT3D9: + os::Printer::log("This driver is not available in Android. Try OpenGL ES 1.0 or ES 2.0.", ELL_ERROR); + break; + default: + os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR); + break; + } +} + +video::SExposedVideoData& CIrrDeviceAndroid::getExposedVideoData() +{ + return ExposedVideoData; +} + +void CIrrDeviceAndroid::createKeyMap() +{ + KeyMap.set_used(223); + + KeyMap[0] = KEY_UNKNOWN; // AKEYCODE_UNKNOWN + KeyMap[1] = KEY_LBUTTON; // AKEYCODE_SOFT_LEFT + KeyMap[2] = KEY_RBUTTON; // AKEYCODE_SOFT_RIGHT + KeyMap[3] = KEY_HOME; // AKEYCODE_HOME + KeyMap[4] = KEY_BACK; // AKEYCODE_BACK + KeyMap[5] = KEY_UNKNOWN; // AKEYCODE_CALL + KeyMap[6] = KEY_UNKNOWN; // AKEYCODE_ENDCALL + KeyMap[7] = KEY_KEY_0; // AKEYCODE_0 + KeyMap[8] = KEY_KEY_1; // AKEYCODE_1 + KeyMap[9] = KEY_KEY_2; // AKEYCODE_2 + KeyMap[10] = KEY_KEY_3; // AKEYCODE_3 + KeyMap[11] = KEY_KEY_4; // AKEYCODE_4 + KeyMap[12] = KEY_KEY_5; // AKEYCODE_5 + KeyMap[13] = KEY_KEY_6; // AKEYCODE_6 + KeyMap[14] = KEY_KEY_7; // AKEYCODE_7 + KeyMap[15] = KEY_KEY_8; // AKEYCODE_8 + KeyMap[16] = KEY_KEY_9; // AKEYCODE_9 + KeyMap[17] = KEY_UNKNOWN; // AKEYCODE_STAR + KeyMap[18] = KEY_UNKNOWN; // AKEYCODE_POUND + KeyMap[19] = KEY_UP; // AKEYCODE_DPAD_UP + KeyMap[20] = KEY_DOWN; // AKEYCODE_DPAD_DOWN + KeyMap[21] = KEY_LEFT; // AKEYCODE_DPAD_LEFT + KeyMap[22] = KEY_RIGHT; // AKEYCODE_DPAD_RIGHT + KeyMap[23] = KEY_SELECT; // AKEYCODE_DPAD_CENTER + KeyMap[24] = KEY_VOLUME_DOWN; // AKEYCODE_VOLUME_UP + KeyMap[25] = KEY_VOLUME_UP; // AKEYCODE_VOLUME_DOWN + KeyMap[26] = KEY_UNKNOWN; // AKEYCODE_POWER + KeyMap[27] = KEY_UNKNOWN; // AKEYCODE_CAMERA + KeyMap[28] = KEY_CLEAR; // AKEYCODE_CLEAR + KeyMap[29] = KEY_KEY_A; // AKEYCODE_A + KeyMap[30] = KEY_KEY_B; // AKEYCODE_B + KeyMap[31] = KEY_KEY_C; // AKEYCODE_C + KeyMap[32] = KEY_KEY_D; // AKEYCODE_D + KeyMap[33] = KEY_KEY_E; // AKEYCODE_E + KeyMap[34] = KEY_KEY_F; // AKEYCODE_F + KeyMap[35] = KEY_KEY_G; // AKEYCODE_G + KeyMap[36] = KEY_KEY_H; // AKEYCODE_H + KeyMap[37] = KEY_KEY_I; // AKEYCODE_I + KeyMap[38] = KEY_KEY_J; // AKEYCODE_J + KeyMap[39] = KEY_KEY_K; // AKEYCODE_K + KeyMap[40] = KEY_KEY_L; // AKEYCODE_L + KeyMap[41] = KEY_KEY_M; // AKEYCODE_M + KeyMap[42] = KEY_KEY_N; // AKEYCODE_N + KeyMap[43] = KEY_KEY_O; // AKEYCODE_O + KeyMap[44] = KEY_KEY_P; // AKEYCODE_P + KeyMap[45] = KEY_KEY_Q; // AKEYCODE_Q + KeyMap[46] = KEY_KEY_R; // AKEYCODE_R + KeyMap[47] = KEY_KEY_S; // AKEYCODE_S + KeyMap[48] = KEY_KEY_T; // AKEYCODE_T + KeyMap[49] = KEY_KEY_U; // AKEYCODE_U + KeyMap[50] = KEY_KEY_V; // AKEYCODE_V + KeyMap[51] = KEY_KEY_W; // AKEYCODE_W + KeyMap[52] = KEY_KEY_X; // AKEYCODE_X + KeyMap[53] = KEY_KEY_Y; // AKEYCODE_Y + KeyMap[54] = KEY_KEY_Z; // AKEYCODE_Z + KeyMap[55] = KEY_COMMA; // AKEYCODE_COMMA + KeyMap[56] = KEY_PERIOD; // AKEYCODE_PERIOD + KeyMap[57] = KEY_MENU; // AKEYCODE_ALT_LEFT + KeyMap[58] = KEY_MENU; // AKEYCODE_ALT_RIGHT + KeyMap[59] = KEY_LSHIFT; // AKEYCODE_SHIFT_LEFT + KeyMap[60] = KEY_RSHIFT; // AKEYCODE_SHIFT_RIGHT + KeyMap[61] = KEY_TAB; // AKEYCODE_TAB + KeyMap[62] = KEY_SPACE; // AKEYCODE_SPACE + KeyMap[63] = KEY_UNKNOWN; // AKEYCODE_SYM + KeyMap[64] = KEY_UNKNOWN; // AKEYCODE_EXPLORER + KeyMap[65] = KEY_UNKNOWN; // AKEYCODE_ENVELOPE + KeyMap[66] = KEY_RETURN; // AKEYCODE_ENTER + KeyMap[67] = KEY_BACK; // AKEYCODE_DEL + KeyMap[68] = KEY_OEM_3; // AKEYCODE_GRAVE + KeyMap[69] = KEY_MINUS; // AKEYCODE_MINUS + KeyMap[70] = KEY_UNKNOWN; // AKEYCODE_EQUALS + KeyMap[71] = KEY_UNKNOWN; // AKEYCODE_LEFT_BRACKET + KeyMap[72] = KEY_UNKNOWN; // AKEYCODE_RIGHT_BRACKET + KeyMap[73] = KEY_UNKNOWN; // AKEYCODE_BACKSLASH + KeyMap[74] = KEY_UNKNOWN; // AKEYCODE_SEMICOLON + KeyMap[75] = KEY_UNKNOWN; // AKEYCODE_APOSTROPHE + KeyMap[76] = KEY_UNKNOWN; // AKEYCODE_SLASH + KeyMap[77] = KEY_UNKNOWN; // AKEYCODE_AT + KeyMap[78] = KEY_UNKNOWN; // AKEYCODE_NUM + KeyMap[79] = KEY_UNKNOWN; // AKEYCODE_HEADSETHOOK + KeyMap[80] = KEY_UNKNOWN; // AKEYCODE_FOCUS (*Camera* focus) + KeyMap[81] = KEY_PLUS; // AKEYCODE_PLUS + KeyMap[82] = KEY_MENU; // AKEYCODE_MENU + KeyMap[83] = KEY_UNKNOWN; // AKEYCODE_NOTIFICATION + KeyMap[84] = KEY_UNKNOWN; // AKEYCODE_SEARCH + KeyMap[85] = KEY_MEDIA_PLAY_PAUSE; // AKEYCODE_MEDIA_PLAY_PAUSE + KeyMap[86] = KEY_MEDIA_STOP; // AKEYCODE_MEDIA_STOP + KeyMap[87] = KEY_MEDIA_NEXT_TRACK; // AKEYCODE_MEDIA_NEXT + KeyMap[88] = KEY_MEDIA_PREV_TRACK; // AKEYCODE_MEDIA_PREVIOUS + KeyMap[89] = KEY_UNKNOWN; // AKEYCODE_MEDIA_REWIND + KeyMap[90] = KEY_UNKNOWN; // AKEYCODE_MEDIA_FAST_FORWARD + KeyMap[91] = KEY_VOLUME_MUTE; // AKEYCODE_MUTE + KeyMap[92] = KEY_PRIOR; // AKEYCODE_PAGE_UP + KeyMap[93] = KEY_NEXT; // AKEYCODE_PAGE_DOWN + KeyMap[94] = KEY_UNKNOWN; // AKEYCODE_PICTSYMBOLS + KeyMap[95] = KEY_UNKNOWN; // AKEYCODE_SWITCH_CHARSET + + // following look like controller inputs + KeyMap[96] = KEY_UNKNOWN; // AKEYCODE_BUTTON_A + KeyMap[97] = KEY_UNKNOWN; // AKEYCODE_BUTTON_B + KeyMap[98] = KEY_UNKNOWN; // AKEYCODE_BUTTON_C + KeyMap[99] = KEY_UNKNOWN; // AKEYCODE_BUTTON_X + KeyMap[100] = KEY_UNKNOWN; // AKEYCODE_BUTTON_Y + KeyMap[101] = KEY_UNKNOWN; // AKEYCODE_BUTTON_Z + KeyMap[102] = KEY_UNKNOWN; // AKEYCODE_BUTTON_L1 + KeyMap[103] = KEY_UNKNOWN; // AKEYCODE_BUTTON_R1 + KeyMap[104] = KEY_UNKNOWN; // AKEYCODE_BUTTON_L2 + KeyMap[105] = KEY_UNKNOWN; // AKEYCODE_BUTTON_R2 + KeyMap[106] = KEY_UNKNOWN; // AKEYCODE_BUTTON_THUMBL + KeyMap[107] = KEY_UNKNOWN; // AKEYCODE_BUTTON_THUMBR + KeyMap[108] = KEY_UNKNOWN; // AKEYCODE_BUTTON_START + KeyMap[109] = KEY_UNKNOWN; // AKEYCODE_BUTTON_SELECT + KeyMap[110] = KEY_UNKNOWN; // AKEYCODE_BUTTON_MODE + + KeyMap[111] = KEY_ESCAPE; // AKEYCODE_ESCAPE + KeyMap[112] = KEY_DELETE; // AKEYCODE_FORWARD_DEL + KeyMap[113] = KEY_CONTROL; // AKEYCODE_CTRL_LEFT + KeyMap[114] = KEY_CONTROL; // AKEYCODE_CTRL_RIGHT + KeyMap[115] = KEY_CAPITAL; // AKEYCODE_CAPS_LOCK + KeyMap[116] = KEY_SCROLL; // AKEYCODE_SCROLL_LOCK + KeyMap[117] = KEY_UNKNOWN; // AKEYCODE_META_LEFT + KeyMap[118] = KEY_UNKNOWN; // AKEYCODE_META_RIGHT + KeyMap[119] = KEY_UNKNOWN; // AKEYCODE_FUNCTION + KeyMap[120] = KEY_SNAPSHOT; // AKEYCODE_SYSRQ + KeyMap[121] = KEY_PAUSE; // AKEYCODE_BREAK + KeyMap[122] = KEY_HOME; // AKEYCODE_MOVE_HOME + KeyMap[123] = KEY_END; // AKEYCODE_MOVE_END + KeyMap[124] = KEY_INSERT; // AKEYCODE_INSERT + KeyMap[125] = KEY_UNKNOWN; // AKEYCODE_FORWARD + KeyMap[126] = KEY_PLAY; // AKEYCODE_MEDIA_PLAY + KeyMap[127] = KEY_MEDIA_PLAY_PAUSE; // AKEYCODE_MEDIA_PAUSE + KeyMap[128] = KEY_UNKNOWN; // AKEYCODE_MEDIA_CLOSE + KeyMap[129] = KEY_UNKNOWN; // AKEYCODE_MEDIA_EJECT + KeyMap[130] = KEY_UNKNOWN; // AKEYCODE_MEDIA_RECORD + KeyMap[131] = KEY_F1; // AKEYCODE_F1 + KeyMap[132] = KEY_F2; // AKEYCODE_F2 + KeyMap[133] = KEY_F3; // AKEYCODE_F3 + KeyMap[134] = KEY_F4; // AKEYCODE_F4 + KeyMap[135] = KEY_F5; // AKEYCODE_F5 + KeyMap[136] = KEY_F6; // AKEYCODE_F6 + KeyMap[137] = KEY_F7; // AKEYCODE_F7 + KeyMap[138] = KEY_F8; // AKEYCODE_F8 + KeyMap[139] = KEY_F9; // AKEYCODE_F9 + KeyMap[140] = KEY_F10; // AKEYCODE_F10 + KeyMap[141] = KEY_F11; // AKEYCODE_F11 + KeyMap[142] = KEY_F12; // AKEYCODE_F12 + KeyMap[143] = KEY_NUMLOCK; // AKEYCODE_NUM_LOCK + KeyMap[144] = KEY_NUMPAD0; // AKEYCODE_NUMPAD_0 + KeyMap[145] = KEY_NUMPAD1; // AKEYCODE_NUMPAD_1 + KeyMap[146] = KEY_NUMPAD2; // AKEYCODE_NUMPAD_2 + KeyMap[147] = KEY_NUMPAD3; // AKEYCODE_NUMPAD_3 + KeyMap[148] = KEY_NUMPAD4; // AKEYCODE_NUMPAD_4 + KeyMap[149] = KEY_NUMPAD5; // AKEYCODE_NUMPAD_5 + KeyMap[150] = KEY_NUMPAD6; // AKEYCODE_NUMPAD_6 + KeyMap[151] = KEY_NUMPAD7; // AKEYCODE_NUMPAD_7 + KeyMap[152] = KEY_NUMPAD8; // AKEYCODE_NUMPAD_8 + KeyMap[153] = KEY_NUMPAD9; // AKEYCODE_NUMPAD_9 + KeyMap[154] = KEY_DIVIDE; // AKEYCODE_NUMPAD_DIVIDE + KeyMap[155] = KEY_MULTIPLY; // AKEYCODE_NUMPAD_MULTIPLY + KeyMap[156] = KEY_SUBTRACT; // AKEYCODE_NUMPAD_SUBTRACT + KeyMap[157] = KEY_ADD; // AKEYCODE_NUMPAD_ADD + KeyMap[158] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_DOT + KeyMap[159] = KEY_COMMA; // AKEYCODE_NUMPAD_COMMA + KeyMap[160] = KEY_RETURN; // AKEYCODE_NUMPAD_ENTER + KeyMap[161] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_EQUALS + KeyMap[162] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_LEFT_PAREN + KeyMap[163] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_RIGHT_PAREN + KeyMap[164] = KEY_VOLUME_MUTE; // AKEYCODE_VOLUME_MUTE + KeyMap[165] = KEY_UNKNOWN; // AKEYCODE_INFO + KeyMap[166] = KEY_UNKNOWN; // AKEYCODE_CHANNEL_UP + KeyMap[167] = KEY_UNKNOWN; // AKEYCODE_CHANNEL_DOWN + KeyMap[168] = KEY_ZOOM; // AKEYCODE_ZOOM_IN + KeyMap[169] = KEY_UNKNOWN; // AKEYCODE_ZOOM_OUT + KeyMap[170] = KEY_UNKNOWN; // AKEYCODE_TV + KeyMap[171] = KEY_UNKNOWN; // AKEYCODE_WINDOW + KeyMap[172] = KEY_UNKNOWN; // AKEYCODE_GUIDE + KeyMap[173] = KEY_UNKNOWN; // AKEYCODE_DVR + KeyMap[174] = KEY_UNKNOWN; // AKEYCODE_BOOKMARK + KeyMap[175] = KEY_UNKNOWN; // AKEYCODE_CAPTIONS + KeyMap[176] = KEY_UNKNOWN; // AKEYCODE_SETTINGS + KeyMap[177] = KEY_UNKNOWN; // AKEYCODE_TV_POWER + KeyMap[178] = KEY_UNKNOWN; // AKEYCODE_TV_INPUT + KeyMap[179] = KEY_UNKNOWN; // AKEYCODE_STB_POWER + KeyMap[180] = KEY_UNKNOWN; // AKEYCODE_STB_INPUT + KeyMap[181] = KEY_UNKNOWN; // AKEYCODE_AVR_POWER + KeyMap[182] = KEY_UNKNOWN; // AKEYCODE_AVR_INPUT + KeyMap[183] = KEY_UNKNOWN; // AKEYCODE_PROG_RED + KeyMap[184] = KEY_UNKNOWN; // AKEYCODE_PROG_GREEN + KeyMap[185] = KEY_UNKNOWN; // AKEYCODE_PROG_YELLOW + KeyMap[186] = KEY_UNKNOWN; // AKEYCODE_PROG_BLUE + KeyMap[187] = KEY_UNKNOWN; // AKEYCODE_APP_SWITCH + KeyMap[188] = KEY_UNKNOWN; // AKEYCODE_BUTTON_1 + KeyMap[189] = KEY_UNKNOWN; // AKEYCODE_BUTTON_2 + KeyMap[190] = KEY_UNKNOWN; // AKEYCODE_BUTTON_3 + KeyMap[191] = KEY_UNKNOWN; // AKEYCODE_BUTTON_4 + KeyMap[192] = KEY_UNKNOWN; // AKEYCODE_BUTTON_5 + KeyMap[193] = KEY_UNKNOWN; // AKEYCODE_BUTTON_6 + KeyMap[194] = KEY_UNKNOWN; // AKEYCODE_BUTTON_7 + KeyMap[195] = KEY_UNKNOWN; // AKEYCODE_BUTTON_8 + KeyMap[196] = KEY_UNKNOWN; // AKEYCODE_BUTTON_9 + KeyMap[197] = KEY_UNKNOWN; // AKEYCODE_BUTTON_10 + KeyMap[198] = KEY_UNKNOWN; // AKEYCODE_BUTTON_11 + KeyMap[199] = KEY_UNKNOWN; // AKEYCODE_BUTTON_12 + KeyMap[200] = KEY_UNKNOWN; // AKEYCODE_BUTTON_13 + KeyMap[201] = KEY_UNKNOWN; // AKEYCODE_BUTTON_14 + KeyMap[202] = KEY_UNKNOWN; // AKEYCODE_BUTTON_15 + KeyMap[203] = KEY_UNKNOWN; // AKEYCODE_BUTTON_16 + KeyMap[204] = KEY_UNKNOWN; // AKEYCODE_LANGUAGE_SWITCH + KeyMap[205] = KEY_UNKNOWN; // AKEYCODE_MANNER_MODE + KeyMap[206] = KEY_UNKNOWN; // AKEYCODE_3D_MODE + KeyMap[207] = KEY_UNKNOWN; // AKEYCODE_CONTACTS + KeyMap[208] = KEY_UNKNOWN; // AKEYCODE_CALENDAR + KeyMap[209] = KEY_UNKNOWN; // AKEYCODE_MUSIC + KeyMap[210] = KEY_UNKNOWN; // AKEYCODE_CALCULATOR + KeyMap[211] = KEY_UNKNOWN; // AKEYCODE_ZENKAKU_HANKAKU + KeyMap[212] = KEY_UNKNOWN; // AKEYCODE_EISU + KeyMap[213] = KEY_UNKNOWN; // AKEYCODE_MUHENKAN + KeyMap[214] = KEY_UNKNOWN; // AKEYCODE_HENKAN + KeyMap[215] = KEY_UNKNOWN; // AKEYCODE_KATAKANA_HIRAGANA + KeyMap[216] = KEY_UNKNOWN; // AKEYCODE_YEN + KeyMap[217] = KEY_UNKNOWN; // AKEYCODE_RO + KeyMap[218] = KEY_UNKNOWN; // AKEYCODE_KANA + KeyMap[219] = KEY_UNKNOWN; // AKEYCODE_ASSIST + KeyMap[220] = KEY_UNKNOWN; // AKEYCODE_BRIGHTNESS_DOWN + KeyMap[221] = KEY_UNKNOWN; // AKEYCODE_BRIGHTNESS_UP , + KeyMap[222] = KEY_UNKNOWN; // AKEYCODE_MEDIA_AUDIO_TRACK +} + +bool CIrrDeviceAndroid::activateAccelerometer(float updateInterval) +{ + if (!isAccelerometerAvailable()) + return false; + + ASensorEventQueue_enableSensor(SensorEventQueue, Accelerometer); + ASensorEventQueue_setEventRate(SensorEventQueue, Accelerometer, (int32_t)(updateInterval*1000.f*1000.f)); // in microseconds + + os::Printer::log("Activated accelerometer", ELL_DEBUG); + return true; +} + +bool CIrrDeviceAndroid::deactivateAccelerometer() +{ + if (Accelerometer) + { + ASensorEventQueue_disableSensor(SensorEventQueue, Accelerometer); + Accelerometer = 0; + os::Printer::log("Deactivated accelerometer", ELL_DEBUG); + return true; + } + + return false; +} + +bool CIrrDeviceAndroid::isAccelerometerActive() +{ + return (Accelerometer != 0); +} + +bool CIrrDeviceAndroid::isAccelerometerAvailable() +{ + if (!Accelerometer) + Accelerometer = ASensorManager_getDefaultSensor(SensorManager, ASENSOR_TYPE_ACCELEROMETER); + + return (Accelerometer != 0); +} + +bool CIrrDeviceAndroid::activateGyroscope(float updateInterval) +{ + if (!isGyroscopeAvailable()) + return false; + + ASensorEventQueue_enableSensor(SensorEventQueue, Gyroscope); + ASensorEventQueue_setEventRate(SensorEventQueue, Gyroscope, (int32_t)(updateInterval*1000.f*1000.f)); // in microseconds + + os::Printer::log("Activated gyroscope", ELL_DEBUG); + return true; +} + +bool CIrrDeviceAndroid::deactivateGyroscope() +{ + if (Gyroscope) + { + ASensorEventQueue_disableSensor(SensorEventQueue, Gyroscope); + Gyroscope = 0; + os::Printer::log("Deactivated gyroscope", ELL_DEBUG); + return true; + } + + return false; +} + +bool CIrrDeviceAndroid::isGyroscopeActive() +{ + return (Gyroscope != 0); +} + +bool CIrrDeviceAndroid::isGyroscopeAvailable() +{ + if (!Gyroscope) + Gyroscope = ASensorManager_getDefaultSensor(SensorManager, ASENSOR_TYPE_GYROSCOPE); + + return (Gyroscope != 0); +} + +} // end namespace irr + +#endif diff --git a/source/Irrlicht/Android/CIrrDeviceAndroid.h b/source/Irrlicht/Android/CIrrDeviceAndroid.h new file mode 100644 index 00000000..b29a26e8 --- /dev/null +++ b/source/Irrlicht/Android/CIrrDeviceAndroid.h @@ -0,0 +1,107 @@ +// Copyright (C) 2002-2011 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_IRR_DEVICE_ANDROID_H_INCLUDED__ +#define __C_IRR_DEVICE_ANDROID_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_ + +#include "CIrrDeviceStub.h" +#include "IrrlichtDevice.h" +#include "IImagePresenter.h" +#include "ICursorControl.h" + +#include +#include + +namespace irr +{ + class CIrrDeviceAndroid : public CIrrDeviceStub, video::IImagePresenter + { + public: + CIrrDeviceAndroid(const SIrrlichtCreationParameters& param); + + virtual ~CIrrDeviceAndroid(); + + virtual bool run(); + + virtual void yield(); + + virtual void sleep(u32 timeMs, bool pauseTimer = false); + + virtual void setWindowCaption(const wchar_t* text); + + virtual bool present(video::IImage* surface, void* windowId, core::rect* srcClip); + + virtual bool isWindowActive() const; + + virtual bool isWindowFocused() const; + + virtual bool isWindowMinimized() const; + + virtual void closeDevice(); + + virtual void setResizable(bool resize = false); + + virtual void minimizeWindow(); + + virtual void maximizeWindow(); + + virtual void restoreWindow(); + + virtual core::position2di getWindowPosition(); + + virtual E_DEVICE_TYPE getType() const; + + virtual bool activateAccelerometer(float updateInterval); + + virtual bool deactivateAccelerometer(); + + virtual bool isAccelerometerActive(); + + virtual bool isAccelerometerAvailable(); + + virtual bool activateGyroscope(float updateInterval); + + virtual bool deactivateGyroscope(); + + virtual bool isGyroscopeActive(); + + virtual bool isGyroscopeAvailable(); + + private: + + static void handleAndroidCommand(android_app* app, int32_t cmd); + + static s32 handleInput(android_app* app, AInputEvent* event); + + void createDriver(); + + void createKeyMap(); + + video::SExposedVideoData& getExposedVideoData(); + + android_app* Android; + ASensorManager* SensorManager; + ASensorEventQueue* SensorEventQueue; + const ASensor* Accelerometer; + const ASensor* Gyroscope; + + bool Focused; + bool Initialized; + bool Paused; + + JNIEnv* JNIEnvAttachedToVM; + + video::SExposedVideoData ExposedVideoData; + + core::array KeyMap; + }; + +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_ANDROID_DEVICE_ +#endif // __C_IRR_DEVICE_ANDROID_H_INCLUDED__ diff --git a/source/Irrlicht/Android/CKeyEventWrapper.cpp b/source/Irrlicht/Android/CKeyEventWrapper.cpp new file mode 100644 index 00000000..4ca05b53 --- /dev/null +++ b/source/Irrlicht/Android/CKeyEventWrapper.cpp @@ -0,0 +1,63 @@ +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CKeyEventWrapper.h" + +#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_ + +#include "os.h" + +namespace irr +{ +namespace jni +{ + +jclass CKeyEventWrapper::Class_KeyEvent = 0; +jmethodID CKeyEventWrapper::Method_constructor = 0; +jmethodID CKeyEventWrapper::Method_getUnicodeChar = 0; + +CKeyEventWrapper::CKeyEventWrapper(JNIEnv* jniEnv, int action, int code) + : JniEnv(jniEnv), JniKeyEvent(0) +{ + if ( JniEnv ) + { + if (!Class_KeyEvent ) + { + // Find java classes & functions on first call + os::Printer::log("CKeyEventWrapper first initialize", ELL_DEBUG); + jclass localClass = JniEnv->FindClass("android/view/KeyEvent"); + if (localClass) + { + Class_KeyEvent = reinterpret_cast(JniEnv->NewGlobalRef(localClass)); + } + + Method_constructor = JniEnv->GetMethodID(Class_KeyEvent, "", "(II)V"); + Method_getUnicodeChar = JniEnv->GetMethodID(Class_KeyEvent, "getUnicodeChar", "(I)I"); + } + + if ( Class_KeyEvent && Method_constructor ) + { + JniKeyEvent = JniEnv->NewObject(Class_KeyEvent, Method_constructor, action, code); + } + else + { + os::Printer::log("CKeyEventWrapper didn't find JNI classes/methods", ELL_WARNING); + } + } +} + +CKeyEventWrapper::~CKeyEventWrapper() +{ + JniEnv->DeleteLocalRef(JniKeyEvent); +} + +int CKeyEventWrapper::getUnicodeChar(int metaState) +{ + return JniEnv->CallIntMethod(JniKeyEvent, Method_getUnicodeChar, metaState); +} + +} // namespace jni +} // namespace irr + + +#endif // _IRR_COMPILE_WITH_ANDROID_DEVICE_ diff --git a/source/Irrlicht/Android/CKeyEventWrapper.h b/source/Irrlicht/Android/CKeyEventWrapper.h new file mode 100644 index 00000000..bac23ad6 --- /dev/null +++ b/source/Irrlicht/Android/CKeyEventWrapper.h @@ -0,0 +1,43 @@ +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_IRR_KEY_EVENT_WRAPPER_H_INCLUDED__ +#define __C_IRR_KEY_EVENT_WRAPPER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_ + +#include + +struct android_app; + +namespace irr +{ +namespace jni +{ + +//! Minimal JNI wrapper class around android.view.KeyEvent +//! NOTE: Only functions we actually use in the engine are wrapped +//! This is currently not written to support multithreading - meaning threads are not attached/detached to the Java VM (to be discussed) +class CKeyEventWrapper +{ +public: + CKeyEventWrapper(JNIEnv* jniEnv, int action, int code); + ~CKeyEventWrapper(); + + int getUnicodeChar(int metaState); + +private: + static jclass Class_KeyEvent; + static jmethodID Method_getUnicodeChar; + static jmethodID Method_constructor; + JNIEnv* JniEnv; + jobject JniKeyEvent; // this object in java +}; + +} // namespace jni +} // namespace irr + +#endif // _IRR_COMPILE_WITH_ANDROID_DEVICE_ +#endif // __C_IRR_KEY_EVENT_WRAPPER_H_INCLUDED__ diff --git a/source/Irrlicht/Android/jni/Android.mk b/source/Irrlicht/Android/jni/Android.mk new file mode 100755 index 00000000..54fb245b --- /dev/null +++ b/source/Irrlicht/Android/jni/Android.mk @@ -0,0 +1,342 @@ +LOCAL_PATH := $(call my-dir)/../.. +IRRLICHT_LIB_PATH := $(LOCAL_PATH)/../../lib/Android + +include $(CLEAR_VARS) + +LOCAL_MODULE := Irrlicht +IRRLICHT_LIB_NAME := lib$(LOCAL_MODULE).a + +LOCAL_CFLAGS := -Wall -pipe -fno-exceptions -fno-rtti -fstrict-aliasing + +ifndef NDEBUG +LOCAL_CFLAGS += -g -D_DEBUG +else +LOCAL_CFLAGS += -fexpensive-optimizations -O3 +endif + +LOCAL_C_INCLUDES := ../../../include +LOCAL_C_INCLUDES += ../zlib ../jpeglib ../libpng + +LOCAL_SRC_FILES := \ + Android/CIrrDeviceAndroid.cpp \ + Android/CAndroidAssetReader.cpp \ + Android/CAndroidAssetFileArchive.cpp \ + Android/CKeyEventWrapper.cpp \ + aesGladman/aescrypt.cpp \ + aesGladman/aeskey.cpp \ + aesGladman/aestab.cpp \ + aesGladman/fileenc.cpp \ + aesGladman/hmac.cpp \ + aesGladman/prng.cpp \ + aesGladman/pwd2key.cpp \ + aesGladman/sha1.cpp \ + aesGladman/sha2.cpp \ + C3DSMeshFileLoader.cpp \ + CAnimatedMeshHalfLife.cpp \ + CAnimatedMeshMD2.cpp \ + CAnimatedMeshMD3.cpp \ + CAnimatedMeshSceneNode.cpp \ + CAttributes.cpp \ + CB3DMeshFileLoader.cpp \ + CB3DMeshWriter.cpp \ + CBillboardSceneNode.cpp \ + CBoneSceneNode.cpp \ + CBSPMeshFileLoader.cpp \ + CBurningShader_Raster_Reference.cpp \ + CCameraSceneNode.cpp \ + CColladaFileLoader.cpp \ + CColladaMeshWriter.cpp \ + CColorConverter.cpp \ + CCSMLoader.cpp \ + CCubeSceneNode.cpp \ + CD3D9Driver.cpp \ + CD3D9HLSLMaterialRenderer.cpp \ + CD3D9NormalMapRenderer.cpp \ + CD3D9ParallaxMapRenderer.cpp \ + CD3D9ShaderMaterialRenderer.cpp \ + CD3D9Texture.cpp \ + CDefaultGUIElementFactory.cpp \ + CDefaultSceneNodeAnimatorFactory.cpp \ + CDefaultSceneNodeFactory.cpp \ + CDepthBuffer.cpp \ + CDMFLoader.cpp \ + CDummyTransformationSceneNode.cpp \ + CEmptySceneNode.cpp \ + CFileList.cpp \ + CFileSystem.cpp \ + CFPSCounter.cpp \ + leakHunter.cpp \ + CGeometryCreator.cpp \ + CGUIButton.cpp \ + CGUICheckBox.cpp \ + CGUIColorSelectDialog.cpp \ + CGUIComboBox.cpp \ + CGUIContextMenu.cpp \ + CGUIEditBox.cpp \ + CGUIEnvironment.cpp \ + CGUIFileOpenDialog.cpp \ + CGUIFont.cpp \ + CGUIImage.cpp \ + CGUIImageList.cpp \ + CGUIInOutFader.cpp \ + CGUIListBox.cpp \ + CGUIMenu.cpp \ + CGUIMeshViewer.cpp \ + CGUIMessageBox.cpp \ + CGUIModalScreen.cpp \ + CGUIScrollBar.cpp \ + CGUISkin.cpp \ + CGUISpinBox.cpp \ + CGUISpriteBank.cpp \ + CGUIStaticText.cpp \ + CGUITabControl.cpp \ + CGUITable.cpp \ + CGUIToolBar.cpp \ + CGUITreeView.cpp \ + CGUIWindow.cpp \ + CGUIProfiler.cpp \ + CImage.cpp \ + CImageLoaderBMP.cpp \ + CImageLoaderDDS.cpp \ + CImageLoaderJPG.cpp \ + CImageLoaderPCX.cpp \ + CImageLoaderPNG.cpp \ + CImageLoaderPPM.cpp \ + CImageLoaderPSD.cpp \ + CImageLoaderRGB.cpp \ + CImageLoaderTGA.cpp \ + CImageLoaderWAL.cpp \ + CImageWriterBMP.cpp \ + CImageWriterJPG.cpp \ + CImageWriterPCX.cpp \ + CImageWriterPNG.cpp \ + CImageWriterPPM.cpp \ + CImageWriterPSD.cpp \ + CImageWriterTGA.cpp \ + CImageLoaderPVR.cpp \ + CIrrDeviceConsole.cpp \ + CIrrDeviceFB.cpp \ + CIrrDeviceLinux.cpp \ + CIrrDeviceSDL.cpp \ + CIrrDeviceStub.cpp \ + CIrrDeviceWin32.cpp \ + CIrrMeshFileLoader.cpp \ + CIrrMeshWriter.cpp \ + CLightSceneNode.cpp \ + CLimitReadFile.cpp \ + CLMTSMeshFileLoader.cpp \ + CLogger.cpp \ + CLWOMeshFileLoader.cpp \ + CMD2MeshFileLoader.cpp \ + CMD3MeshFileLoader.cpp \ + CMemoryFile.cpp \ + CMeshCache.cpp \ + CMeshManipulator.cpp \ + CMeshSceneNode.cpp \ + CMeshTextureLoader.cpp \ + CMetaTriangleSelector.cpp \ + CMountPointReader.cpp \ + CMS3DMeshFileLoader.cpp \ + CMY3DMeshFileLoader.cpp \ + CNPKReader.cpp \ + CNullDriver.cpp \ + COBJMeshFileLoader.cpp \ + COBJMeshWriter.cpp \ + COCTLoader.cpp \ + COctreeSceneNode.cpp \ + COctreeTriangleSelector.cpp \ + CEGLManager.cpp \ + COGLES2Driver.cpp \ + COGLES2ExtensionHandler.cpp \ + COGLES2MaterialRenderer.cpp \ + COGLES2FixedPipelineRenderer.cpp \ + COGLES2NormalMapRenderer.cpp \ + COGLES2ParallaxMapRenderer.cpp \ + COGLES2Renderer2D.cpp \ + COGLESDriver.cpp \ + COGLESExtensionHandler.cpp \ + COgreMeshFileLoader.cpp \ + COpenGLCacheHandler.cpp \ + COpenGLDriver.cpp \ + COpenGLExtensionHandler.cpp \ + COpenGLNormalMapRenderer.cpp \ + COpenGLParallaxMapRenderer.cpp \ + COpenGLShaderMaterialRenderer.cpp \ + COpenGLSLMaterialRenderer.cpp \ + COSOperator.cpp \ + CPakReader.cpp \ + CParticleAnimatedMeshSceneNodeEmitter.cpp \ + CParticleAttractionAffector.cpp \ + CParticleBoxEmitter.cpp \ + CParticleCylinderEmitter.cpp \ + CParticleFadeOutAffector.cpp \ + CParticleGravityAffector.cpp \ + CParticleMeshEmitter.cpp \ + CParticlePointEmitter.cpp \ + CParticleRingEmitter.cpp \ + CParticleRotationAffector.cpp \ + CParticleScaleAffector.cpp \ + CParticleSphereEmitter.cpp \ + CParticleSystemSceneNode.cpp \ + CPLYMeshFileLoader.cpp \ + CPLYMeshWriter.cpp \ + CProfiler.cpp \ + CQ3LevelMesh.cpp \ + CQuake3ShaderSceneNode.cpp \ + CReadFile.cpp \ + CSceneCollisionManager.cpp \ + CSceneLoaderIrr.cpp \ + CSceneManager.cpp \ + CSceneNodeAnimatorCameraFPS.cpp \ + CSceneNodeAnimatorCameraMaya.cpp \ + CSceneNodeAnimatorCollisionResponse.cpp \ + CSceneNodeAnimatorDelete.cpp \ + CSceneNodeAnimatorFlyCircle.cpp \ + CSceneNodeAnimatorFlyStraight.cpp \ + CSceneNodeAnimatorFollowSpline.cpp \ + CSceneNodeAnimatorRotation.cpp \ + CSceneNodeAnimatorTexture.cpp \ + CShadowVolumeSceneNode.cpp \ + CSkinnedMesh.cpp \ + CSkyBoxSceneNode.cpp \ + CSkyDomeSceneNode.cpp \ + CSMFMeshFileLoader.cpp \ + CSoftwareDriver.cpp \ + CSoftwareDriver2.cpp \ + CSoftwareTexture.cpp \ + CSoftwareTexture2.cpp \ + CSphereSceneNode.cpp \ + CSTLMeshFileLoader.cpp \ + CSTLMeshWriter.cpp \ + CTarReader.cpp \ + CTerrainSceneNode.cpp \ + CTerrainTriangleSelector.cpp \ + CTextSceneNode.cpp \ + CTRFlat.cpp \ + CTRFlatWire.cpp \ + CTRGouraud.cpp \ + CTRGouraud2.cpp \ + CTRGouraudAlpha2.cpp \ + CTRGouraudAlphaNoZ2.cpp \ + CTRGouraudWire.cpp \ + CTriangleBBSelector.cpp \ + CTriangleSelector.cpp \ + CTRNormalMap.cpp \ + CTRStencilShadow.cpp \ + CTRTextureBlend.cpp \ + CTRTextureDetailMap2.cpp \ + CTRTextureFlat.cpp \ + CTRTextureFlatWire.cpp \ + CTRTextureGouraud.cpp \ + CTRTextureGouraud2.cpp \ + CTRTextureGouraudAdd.cpp \ + CTRTextureGouraudAdd2.cpp \ + CTRTextureGouraudAddNoZ2.cpp \ + CTRTextureGouraudAlpha.cpp \ + CTRTextureGouraudAlphaNoZ.cpp \ + CTRTextureGouraudNoZ.cpp \ + CTRTextureGouraudNoZ2.cpp \ + CTRTextureGouraudVertexAlpha2.cpp \ + CTRTextureGouraudWire.cpp \ + CTRTextureLightMap2_Add.cpp \ + CTRTextureLightMap2_M1.cpp \ + CTRTextureLightMap2_M2.cpp \ + CTRTextureLightMap2_M4.cpp \ + CTRTextureLightMapGouraud2_M4.cpp \ + CTRTextureWire2.cpp \ + CVideoModeList.cpp \ + CVolumeLightSceneNode.cpp \ + CWADReader.cpp \ + CWaterSurfaceSceneNode.cpp \ + CWriteFile.cpp \ + CXMeshFileLoader.cpp \ + CXMLReader.cpp \ + CXMLWriter.cpp \ + CZBuffer.cpp \ + CZipReader.cpp \ + IBurningShader.cpp \ + Irrlicht.cpp \ + irrXML.cpp \ + os.cpp \ + bzip2/blocksort.c \ + bzip2/bzcompress.c \ + bzip2/bzlib.c \ + bzip2/crctable.c \ + bzip2/decompress.c \ + bzip2/huffman.c \ + bzip2/randtable.c \ + jpeglib/jaricom.c \ + jpeglib/jcapimin.c \ + jpeglib/jcapistd.c \ + jpeglib/jcarith.c \ + jpeglib/jccoefct.c \ + jpeglib/jccolor.c \ + jpeglib/jcdctmgr.c \ + jpeglib/jchuff.c \ + jpeglib/jcinit.c \ + jpeglib/jcmainct.c \ + jpeglib/jcmarker.c \ + jpeglib/jcmaster.c \ + jpeglib/jcomapi.c \ + jpeglib/jcparam.c \ + jpeglib/jcprepct.c \ + jpeglib/jcsample.c \ + jpeglib/jctrans.c \ + jpeglib/jdapimin.c \ + jpeglib/jdapistd.c \ + jpeglib/jdarith.c \ + jpeglib/jdatadst.c \ + jpeglib/jdatasrc.c \ + jpeglib/jdcoefct.c \ + jpeglib/jdcolor.c \ + jpeglib/jddctmgr.c \ + jpeglib/jdhuff.c \ + jpeglib/jdinput.c \ + jpeglib/jdmainct.c \ + jpeglib/jdmarker.c \ + jpeglib/jdmaster.c \ + jpeglib/jdmerge.c \ + jpeglib/jdpostct.c \ + jpeglib/jdsample.c \ + jpeglib/jdtrans.c \ + jpeglib/jerror.c \ + jpeglib/jfdctflt.c \ + jpeglib/jfdctfst.c \ + jpeglib/jfdctint.c \ + jpeglib/jidctflt.c \ + jpeglib/jidctfst.c \ + jpeglib/jidctint.c \ + jpeglib/jmemmgr.c \ + jpeglib/jmemnobs.c \ + jpeglib/jquant1.c \ + jpeglib/jquant2.c \ + jpeglib/jutils.c \ + libpng/png.c \ + libpng/pngerror.c \ + libpng/pngget.c \ + libpng/pngmem.c \ + libpng/pngpread.c \ + libpng/pngread.c \ + libpng/pngrio.c \ + libpng/pngrtran.c \ + libpng/pngrutil.c \ + libpng/pngset.c \ + libpng/pngtrans.c \ + libpng/pngwio.c \ + libpng/pngwrite.c \ + libpng/pngwtran.c \ + libpng/pngwutil.c \ + lzma/LzmaDec.c \ +zlib/adler32.c zlib/crc32.c zlib/gzclose.c zlib/gzread.c zlib/infback.c zlib/inflate.c zlib/trees.c zlib/zutil.c\ +zlib/compress.c zlib/deflate.c zlib/gzlib.c zlib/gzwrite.c zlib/inffast.c zlib/inftrees.c zlib/uncompr.c + +LOCAL_STATIC_LIBRARIES := android_native_app_glue + +include $(BUILD_STATIC_LIBRARY) + +$(call import-module,android/native_app_glue) + +all: $(IRRLICHT_LIB_PATH) +$(IRRLICHT_LIB_PATH) : $(TARGET_OUT)/$(IRRLICHT_LIB_NAME) + cp $< $@ + diff --git a/source/Irrlicht/Android/jni/Application.mk b/source/Irrlicht/Android/jni/Application.mk new file mode 100644 index 00000000..e58ac166 --- /dev/null +++ b/source/Irrlicht/Android/jni/Application.mk @@ -0,0 +1,2 @@ +APP_PLATFORM := android-10 +APP_MODULES := Irrlicht diff --git a/source/Irrlicht/BuiltInFont.h b/source/Irrlicht/BuiltInFont.h new file mode 100644 index 00000000..467a49d1 --- /dev/null +++ b/source/Irrlicht/BuiltInFont.h @@ -0,0 +1,1075 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __BUILD_IN_FONT_H_INCLUDED__ +#define __BUILD_IN_FONT_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +// header file generated by Bin2H, copyright 2002 by N.Gebhardt. +// Bin2H is Freeware. Download it freely from www.code3d.com. +// for the source bitmap, see builtInFont.bmp + +namespace irr +{ +namespace gui +{ +#ifdef _IRR_COMPILE_WITH_BMP_LOADER_ +const u8 BuiltInFontData[] = +{ + 0x42, 0x4d, 0x4a, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x63, 0x0b, + 0x00, 0x00, 0x63, 0x0b, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x18, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x12, 0x22, 0x21, 0x22, + 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x12, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x04, + 0x44, 0x44, 0x02, 0x04, 0x44, 0x44, 0x40, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x04, + 0x44, 0x44, 0x02, 0x04, 0x44, 0x44, 0x40, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, 0x04, + 0x44, 0x44, 0x02, 0x04, 0x44, 0x44, 0x40, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x44, 0x22, 0x44, 0x42, 0x04, + 0x44, 0x44, 0x02, 0x04, 0x44, 0x44, 0x40, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, 0x04, + 0x40, 0x00, 0x02, 0x00, 0x44, 0x00, 0x00, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x04, + 0x40, 0x40, 0x22, 0x20, 0x00, 0x02, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x04, + 0x40, 0x02, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, + 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x32, 0x22, 0x23, 0x22, 0x22, 0x32, + 0x22, 0x22, 0x22, 0x32, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x12, 0x22, + 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x12, 0x22, + 0x22, 0x22, 0x12, 0x22, 0x22, 0x22, 0x12, 0x22, + 0x21, 0x22, 0x22, 0x12, 0x22, 0x22, 0x22, 0x12, + 0x22, 0x22, 0x12, 0x22, 0x21, 0x22, 0x22, 0x12, + 0x22, 0x22, 0x12, 0x22, 0x22, 0x22, 0x21, 0x22, + 0x22, 0x22, 0x22, 0x12, 0x22, 0x22, 0x12, 0x22, + 0x22, 0x12, 0x22, 0x22, 0x22, 0x22, 0x12, 0x22, + 0x22, 0x22, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x22, 0x24, 0x22, 0x24, + 0x22, 0x22, 0x24, 0x42, 0x24, 0x42, 0x22, 0x22, + 0x22, 0x22, 0x42, 0x22, 0x24, 0x22, 0x24, 0x42, + 0x22, 0x24, 0x42, 0x44, 0x44, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x42, 0x42, 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x42, 0x44, 0x22, 0x44, + 0x42, 0x22, 0x22, 0x44, 0x22, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x42, 0x22, 0x24, 0x22, 0x22, 0x44, + 0x22, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, 0x22, 0x24, + 0x42, 0x44, 0x22, 0x22, 0x44, 0x42, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x42, 0x24, 0x42, 0x44, + 0x22, 0x44, 0x22, 0x22, 0x44, 0x42, 0x24, 0x42, + 0x44, 0x22, 0x22, 0x24, 0x42, 0x24, 0x22, 0x22, + 0x22, 0x22, 0x42, 0x22, 0x24, 0x44, 0x22, 0x24, + 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, + 0x44, 0x44, 0x22, 0x24, 0x44, 0x22, 0x22, 0x44, + 0x42, 0x44, 0x42, 0x24, 0x44, 0x44, 0x22, 0x24, + 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x24, 0x42, 0x22, 0x44, 0x22, 0x44, 0x22, 0x24, + 0x42, 0x24, 0x42, 0x22, 0x24, 0x22, 0x24, 0x22, + 0x24, 0x22, 0x22, 0x22, 0x44, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x44, 0x44, 0x44, 0x24, 0x22, 0x22, + 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, + 0x44, 0x42, 0x22, 0x44, 0x44, 0x42, 0x24, 0x44, + 0x42, 0x44, 0x44, 0x24, 0x42, 0x44, 0x42, 0x22, + 0x22, 0x22, 0x22, 0x44, 0x42, 0x22, 0x42, 0x22, + 0x44, 0x44, 0x24, 0x42, 0x24, 0x42, 0x22, 0x22, + 0x44, 0x22, 0x44, 0x24, 0x22, 0x24, 0x22, 0x24, + 0x22, 0x22, 0x22, 0x22, 0x24, 0x42, 0x22, 0x22, + 0x22, 0x22, 0x44, 0x44, 0x44, 0x24, 0x22, 0x24, + 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, + 0x44, 0x22, 0x24, 0x44, 0x44, 0x44, 0x22, 0x44, + 0x42, 0x44, 0x42, 0x24, 0x22, 0x24, 0x44, 0x22, + 0x24, 0x22, 0x22, 0x24, 0x22, 0x24, 0x44, 0x22, + 0x44, 0x44, 0x22, 0x44, 0x22, 0x44, 0x22, 0x24, + 0x42, 0x24, 0x42, 0x24, 0x42, 0x44, 0x22, 0x44, + 0x42, 0x22, 0x22, 0x22, 0x22, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x42, 0x22, 0x24, 0x22, 0x44, + 0x22, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, + 0x42, 0x44, 0x22, 0x22, 0x22, 0x22, 0x44, 0x22, + 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x24, 0x42, 0x22, 0x24, 0x42, 0x24, 0x42, 0x44, + 0x22, 0x44, 0x22, 0x22, 0x44, 0x42, 0x24, 0x42, + 0x44, 0x22, 0x22, 0x22, 0x22, 0x24, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x24, 0x42, + 0x22, 0x24, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x42, 0x42, 0x22, 0x22, 0x22, 0x22, 0x24, 0x24, + 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x24, 0x22, 0x24, 0x22, + 0x24, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x32, 0x22, 0x22, 0x22, 0x23, 0x22, + 0x22, 0x22, 0x22, 0x32, 0x22, 0x22, 0x23, 0x22, + 0x22, 0x22, 0x23, 0x22, 0x22, 0x22, 0x23, 0x22, + 0x22, 0x32, 0x22, 0x23, 0x22, 0x22, 0x22, 0x23, + 0x22, 0x22, 0x23, 0x22, 0x22, 0x32, 0x22, 0x23, + 0x22, 0x22, 0x23, 0x22, 0x22, 0x22, 0x22, 0x32, + 0x22, 0x22, 0x22, 0x23, 0x22, 0x22, 0x23, 0x22, + 0x22, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x12, 0x22, 0x21, 0x22, + 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, + 0x22, 0x12, 0x22, 0x21, 0x22, 0x22, 0x21, 0x22, + 0x22, 0x21, 0x22, 0x22, 0x21, 0x22, 0x22, 0x21, + 0x22, 0x22, 0x21, 0x22, 0x22, 0x12, 0x22, 0x22, + 0x12, 0x22, 0x21, 0x22, 0x22, 0x12, 0x22, 0x21, + 0x22, 0x22, 0x12, 0x22, 0x21, 0x22, 0x22, 0x12, + 0x22, 0x21, 0x22, 0x12, 0x22, 0x22, 0x22, 0x22, + 0x12, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x42, 0x22, 0x24, 0x22, 0x22, + 0x42, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x22, 0x24, 0x22, 0x22, + 0x24, 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, 0x24, + 0x22, 0x22, 0x22, 0x44, 0x22, 0x24, 0x42, 0x24, + 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x24, + 0x42, 0x22, 0x42, 0x42, 0x22, 0x44, 0x22, 0x22, + 0x44, 0x22, 0x22, 0x44, 0x22, 0x22, 0x44, 0x22, + 0x22, 0x44, 0x22, 0x22, 0x22, 0x22, 0x44, 0x42, + 0x22, 0x24, 0x42, 0x22, 0x44, 0x22, 0x24, 0x42, + 0x22, 0x44, 0x22, 0x24, 0x22, 0x24, 0x42, 0x22, + 0x24, 0x22, 0x24, 0x24, 0x22, 0x22, 0x22, 0x24, + 0x22, 0x22, 0x24, 0x22, 0x22, 0x42, 0x22, 0x24, + 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, + 0x24, 0x22, 0x42, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x24, 0x22, 0x42, 0x22, 0x42, 0x22, 0x44, 0x24, + 0x22, 0x42, 0x42, 0x24, 0x24, 0x22, 0x42, 0x42, + 0x24, 0x24, 0x22, 0x42, 0x42, 0x24, 0x24, 0x22, + 0x42, 0x42, 0x24, 0x24, 0x22, 0x22, 0x22, 0x24, + 0x22, 0x22, 0x24, 0x24, 0x22, 0x42, 0x42, 0x24, + 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x24, + 0x42, 0x22, 0x42, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x24, 0x22, 0x42, 0x24, 0x44, 0x22, 0x42, 0x44, + 0x22, 0x42, 0x42, 0x24, 0x24, 0x22, 0x42, 0x42, + 0x24, 0x24, 0x22, 0x42, 0x42, 0x24, 0x24, 0x22, + 0x42, 0x42, 0x24, 0x24, 0x22, 0x22, 0x22, 0x24, + 0x22, 0x22, 0x22, 0x42, 0x22, 0x24, 0x22, 0x24, + 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x22, + 0x42, 0x22, 0x44, 0x22, 0x22, 0x44, 0x22, 0x22, + 0x44, 0x22, 0x22, 0x44, 0x22, 0x22, 0x44, 0x22, + 0x22, 0x44, 0x22, 0x22, 0x42, 0x22, 0x24, 0x44, + 0x22, 0x42, 0x42, 0x24, 0x24, 0x22, 0x42, 0x42, + 0x24, 0x24, 0x22, 0x42, 0x42, 0x24, 0x42, 0x22, + 0x42, 0x42, 0x24, 0x24, 0x22, 0x22, 0x22, 0x24, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, + 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x24, 0x22, 0x22, 0x22, 0x24, + 0x22, 0x22, 0x24, 0x24, 0x22, 0x42, 0x42, 0x24, + 0x22, 0x42, 0x24, 0x24, 0x24, 0x24, 0x22, 0x22, + 0x22, 0x22, 0x44, 0x22, 0x22, 0x24, 0x22, 0x22, + 0x42, 0x22, 0x22, 0x42, 0x42, 0x22, 0x44, 0x22, + 0x24, 0x22, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x42, + 0x24, 0x24, 0x22, 0x24, 0x22, 0x22, 0x22, 0x22, + 0x42, 0x42, 0x24, 0x24, 0x44, 0x44, 0x44, 0x44, + 0x22, 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, 0x42, + 0x22, 0x24, 0x22, 0x42, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x42, 0x22, 0x42, 0x22, 0x22, + 0x24, 0x22, 0x22, 0x24, 0x22, 0x22, 0x24, 0x42, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x24, 0x22, 0x22, 0x24, 0x22, 0x24, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, + 0x22, 0x22, 0x32, 0x22, 0x23, 0x22, 0x22, 0x32, + 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, + 0x22, 0x23, 0x22, 0x22, 0x32, 0x22, 0x22, 0x32, + 0x22, 0x22, 0x32, 0x22, 0x22, 0x32, 0x22, 0x22, + 0x32, 0x22, 0x22, 0x32, 0x22, 0x23, 0x22, 0x22, + 0x23, 0x22, 0x22, 0x32, 0x22, 0x23, 0x22, 0x22, + 0x32, 0x22, 0x23, 0x22, 0x22, 0x32, 0x22, 0x23, + 0x22, 0x22, 0x32, 0x23, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x12, 0x22, 0x22, + 0x21, 0x22, 0x22, 0x12, 0x22, 0x22, 0x21, 0x22, + 0x22, 0x22, 0x12, 0x22, 0x22, 0x21, 0x22, 0x22, + 0x22, 0x12, 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, + 0x12, 0x22, 0x22, 0x12, 0x22, 0x22, 0x12, 0x22, + 0x21, 0x22, 0x22, 0x12, 0x22, 0x21, 0x22, 0x22, + 0x12, 0x22, 0x21, 0x22, 0x22, 0x12, 0x22, 0x22, + 0x21, 0x22, 0x22, 0x12, 0x22, 0x21, 0x22, 0x22, + 0x12, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x44, 0x42, 0x22, 0x24, 0x44, + 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x22, 0x22, + 0x44, 0x42, 0x22, 0x24, 0x44, 0x22, 0x22, 0x44, + 0x42, 0x22, 0x24, 0x44, 0x22, 0x22, 0x24, 0x22, + 0x22, 0x42, 0x22, 0x22, 0x42, 0x42, 0x22, 0x24, + 0x42, 0x22, 0x44, 0x22, 0x24, 0x42, 0x22, 0x44, + 0x22, 0x24, 0x42, 0x22, 0x44, 0x22, 0x44, 0x44, + 0x42, 0x22, 0x44, 0x22, 0x24, 0x42, 0x22, 0x44, + 0x22, 0x22, 0x24, 0x22, 0x24, 0x22, 0x42, 0x22, + 0x42, 0x24, 0x24, 0x22, 0x44, 0x22, 0x42, 0x24, + 0x22, 0x24, 0x22, 0x42, 0x22, 0x42, 0x24, 0x22, + 0x24, 0x22, 0x42, 0x22, 0x42, 0x22, 0x24, 0x22, + 0x22, 0x44, 0x42, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x42, 0x24, 0x24, 0x22, 0x42, 0x42, 0x24, 0x24, + 0x22, 0x42, 0x42, 0x24, 0x24, 0x22, 0x42, 0x44, + 0x22, 0x24, 0x22, 0x22, 0x42, 0x22, 0x24, 0x22, + 0x22, 0x22, 0x24, 0x22, 0x24, 0x22, 0x42, 0x22, + 0x42, 0x22, 0x42, 0x22, 0x42, 0x42, 0x42, 0x24, + 0x22, 0x24, 0x22, 0x42, 0x22, 0x42, 0x24, 0x22, + 0x24, 0x22, 0x42, 0x22, 0x42, 0x22, 0x24, 0x22, + 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x22, + 0x42, 0x22, 0x24, 0x22, 0x22, 0x42, 0x22, 0x24, + 0x22, 0x22, 0x42, 0x22, 0x24, 0x22, 0x22, 0x42, + 0x42, 0x24, 0x22, 0x22, 0x42, 0x42, 0x24, 0x24, + 0x22, 0x22, 0x24, 0x22, 0x24, 0x22, 0x42, 0x22, + 0x42, 0x24, 0x24, 0x22, 0x42, 0x42, 0x42, 0x24, + 0x22, 0x24, 0x22, 0x42, 0x22, 0x42, 0x24, 0x22, + 0x24, 0x22, 0x42, 0x22, 0x42, 0x22, 0x24, 0x22, + 0x22, 0x42, 0x24, 0x22, 0x44, 0x42, 0x22, 0x44, + 0x22, 0x24, 0x42, 0x22, 0x44, 0x22, 0x24, 0x42, + 0x22, 0x44, 0x22, 0x24, 0x42, 0x22, 0x44, 0x24, + 0x42, 0x22, 0x44, 0x22, 0x24, 0x22, 0x22, 0x42, + 0x22, 0x22, 0x24, 0x22, 0x24, 0x22, 0x42, 0x22, + 0x42, 0x22, 0x22, 0x22, 0x42, 0x24, 0x42, 0x24, + 0x22, 0x24, 0x22, 0x42, 0x22, 0x42, 0x24, 0x22, + 0x24, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x42, + 0x22, 0x44, 0x42, 0x22, 0x42, 0x42, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x44, 0x42, 0x22, 0x24, 0x44, + 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x42, 0x24, + 0x22, 0x24, 0x22, 0x42, 0x22, 0x42, 0x24, 0x22, + 0x24, 0x22, 0x42, 0x22, 0x42, 0x24, 0x22, 0x24, + 0x22, 0x42, 0x22, 0x22, 0x24, 0x22, 0x22, 0x24, + 0x22, 0x22, 0x42, 0x22, 0x42, 0x42, 0x24, 0x42, + 0x22, 0x42, 0x42, 0x24, 0x42, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, 0x42, + 0x22, 0x22, 0x22, 0x42, 0x42, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x24, 0x22, 0x22, 0x22, 0x42, 0x22, 0x22, 0x42, + 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x42, + 0x22, 0x22, 0x24, 0x22, 0x24, 0x22, 0x22, 0x44, + 0x22, 0x22, 0x22, 0x24, 0x42, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x24, 0x22, 0x22, 0x24, + 0x22, 0x22, 0x32, 0x24, 0x24, 0x23, 0x24, 0x24, + 0x22, 0x32, 0x22, 0x23, 0x22, 0x22, 0x22, 0x32, + 0x42, 0x22, 0x23, 0x22, 0x24, 0x22, 0x32, 0x24, + 0x22, 0x23, 0x24, 0x24, 0x22, 0x32, 0x22, 0x42, + 0x23, 0x22, 0x22, 0x23, 0x22, 0x22, 0x23, 0x22, + 0x22, 0x32, 0x22, 0x23, 0x22, 0x22, 0x32, 0x22, + 0x23, 0x22, 0x22, 0x32, 0x22, 0x23, 0x22, 0x22, + 0x22, 0x32, 0x22, 0x23, 0x22, 0x22, 0x32, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x12, 0x22, 0x22, + 0x21, 0x22, 0x22, 0x22, 0x12, 0x22, 0x22, 0x21, + 0x22, 0x22, 0x22, 0x12, 0x22, 0x22, 0x22, 0x21, + 0x22, 0x22, 0x21, 0x22, 0x22, 0x21, 0x22, 0x22, + 0x21, 0x22, 0x22, 0x21, 0x22, 0x22, 0x21, 0x22, + 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, + 0x22, 0x21, 0x22, 0x22, 0x22, 0x12, 0x22, 0x22, + 0x21, 0x22, 0x22, 0x22, 0x12, 0x22, 0x22, 0x21, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x24, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x22, 0x24, 0x22, 0x42, 0x22, + 0x42, 0x24, 0x22, 0x24, 0x22, 0x42, 0x22, 0x42, + 0x24, 0x22, 0x24, 0x22, 0x42, 0x24, 0x44, 0x42, + 0x22, 0x44, 0x22, 0x24, 0x44, 0x42, 0x24, 0x44, + 0x42, 0x24, 0x44, 0x42, 0x24, 0x44, 0x42, 0x24, + 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x44, + 0x44, 0x22, 0x24, 0x22, 0x24, 0x22, 0x24, 0x44, + 0x22, 0x22, 0x44, 0x42, 0x22, 0x24, 0x44, 0x22, + 0x22, 0x22, 0x24, 0x44, 0x44, 0x22, 0x44, 0x44, + 0x42, 0x24, 0x44, 0x44, 0x22, 0x44, 0x44, 0x42, + 0x24, 0x44, 0x44, 0x22, 0x44, 0x44, 0x22, 0x22, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x22, 0x24, 0x22, + 0x22, 0x24, 0x22, 0x22, 0x24, 0x22, 0x22, 0x24, + 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, + 0x22, 0x42, 0x24, 0x22, 0x24, 0x22, 0x42, 0x22, + 0x42, 0x24, 0x22, 0x24, 0x22, 0x42, 0x22, 0x42, + 0x22, 0x22, 0x22, 0x42, 0x42, 0x22, 0x24, 0x24, + 0x22, 0x22, 0x42, 0x42, 0x22, 0x24, 0x24, 0x22, + 0x22, 0x42, 0x42, 0x22, 0x24, 0x24, 0x22, 0x22, + 0x24, 0x22, 0x22, 0x24, 0x22, 0x22, 0x24, 0x22, + 0x22, 0x24, 0x22, 0x22, 0x24, 0x22, 0x22, 0x24, + 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, + 0x22, 0x42, 0x24, 0x22, 0x44, 0x22, 0x42, 0x22, + 0x42, 0x24, 0x22, 0x24, 0x22, 0x42, 0x22, 0x42, + 0x22, 0x22, 0x22, 0x42, 0x42, 0x22, 0x24, 0x24, + 0x22, 0x22, 0x42, 0x42, 0x22, 0x24, 0x24, 0x22, + 0x22, 0x42, 0x42, 0x22, 0x22, 0x44, 0x44, 0x42, + 0x24, 0x22, 0x22, 0x24, 0x44, 0x42, 0x24, 0x44, + 0x42, 0x24, 0x44, 0x42, 0x24, 0x44, 0x42, 0x24, + 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x24, 0x44, + 0x22, 0x42, 0x24, 0x24, 0x24, 0x22, 0x42, 0x22, + 0x42, 0x24, 0x22, 0x24, 0x22, 0x42, 0x22, 0x42, + 0x22, 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, 0x42, + 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, 0x42, 0x22, + 0x22, 0x24, 0x22, 0x22, 0x22, 0x44, 0x22, 0x22, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x22, 0x24, 0x22, + 0x22, 0x24, 0x22, 0x22, 0x24, 0x22, 0x22, 0x24, + 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, + 0x22, 0x42, 0x24, 0x42, 0x24, 0x22, 0x42, 0x22, + 0x42, 0x24, 0x22, 0x24, 0x22, 0x42, 0x22, 0x42, + 0x22, 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, 0x42, + 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, 0x42, 0x22, + 0x22, 0x24, 0x22, 0x22, 0x22, 0x24, 0x44, 0x42, + 0x22, 0x44, 0x22, 0x24, 0x44, 0x42, 0x24, 0x44, + 0x42, 0x24, 0x44, 0x42, 0x24, 0x44, 0x42, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, + 0x44, 0x22, 0x24, 0x22, 0x24, 0x22, 0x24, 0x44, + 0x22, 0x22, 0x44, 0x42, 0x22, 0x24, 0x44, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x22, 0x22, 0x24, 0x24, + 0x22, 0x22, 0x42, 0x42, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x42, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x24, 0x22, 0x22, 0x42, + 0x22, 0x22, 0x42, 0x42, 0x22, 0x22, 0x22, 0x24, + 0x22, 0x42, 0x24, 0x24, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x42, 0x42, 0x22, 0x22, 0x42, + 0x22, 0x22, 0x24, 0x22, 0x22, 0x24, 0x24, 0x22, + 0x22, 0x22, 0x32, 0x22, 0x42, 0x23, 0x22, 0x42, + 0x22, 0x32, 0x24, 0x24, 0x23, 0x24, 0x24, 0x22, + 0x32, 0x24, 0x22, 0x23, 0x22, 0x22, 0x22, 0x22, + 0x32, 0x22, 0x22, 0x32, 0x42, 0x22, 0x32, 0x24, + 0x22, 0x32, 0x24, 0x22, 0x34, 0x22, 0x42, 0x32, + 0x23, 0x24, 0x23, 0x42, 0x23, 0x24, 0x23, 0x22, + 0x22, 0x22, 0x32, 0x24, 0x24, 0x23, 0x24, 0x22, + 0x22, 0x32, 0x22, 0x42, 0x23, 0x22, 0x42, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x12, 0x22, 0x12, 0x22, + 0x22, 0x21, 0x22, 0x21, 0x22, 0x22, 0x21, 0x22, + 0x22, 0x21, 0x22, 0x12, 0x22, 0x22, 0x21, 0x22, + 0x22, 0x12, 0x21, 0x22, 0x22, 0x12, 0x21, 0x22, + 0x12, 0x21, 0x22, 0x22, 0x21, 0x22, 0x22, 0x12, + 0x21, 0x22, 0x21, 0x22, 0x12, 0x22, 0x12, 0x22, + 0x22, 0x12, 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, + 0x12, 0x22, 0x22, 0x21, 0x22, 0x22, 0x12, 0x22, + 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x24, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, 0x44, 0x22, + 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x24, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x42, 0x42, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x44, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x42, 0x42, 0x22, 0x44, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x42, + 0x42, 0x22, 0x42, 0x22, 0x42, 0x24, 0x22, 0x44, + 0x22, 0x42, 0x22, 0x42, 0x24, 0x22, 0x22, 0x42, + 0x22, 0x42, 0x22, 0x44, 0x22, 0x22, 0x22, 0x24, + 0x44, 0x22, 0x22, 0x22, 0x24, 0x24, 0x22, 0x22, + 0x22, 0x42, 0x22, 0x22, 0x24, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x24, 0x22, 0x22, 0x44, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, + 0x24, 0x22, 0x24, 0x24, 0x42, 0x22, 0x42, 0x44, + 0x22, 0x24, 0x24, 0x42, 0x22, 0x42, 0x22, 0x44, + 0x44, 0x42, 0x24, 0x24, 0x22, 0x22, 0x22, 0x42, + 0x22, 0x42, 0x24, 0x42, 0x22, 0x42, 0x42, 0x24, + 0x44, 0x42, 0x24, 0x22, 0x42, 0x22, 0x42, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x44, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x24, 0x22, 0x24, 0x44, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x22, 0x42, + 0x42, 0x22, 0x22, 0x42, 0x42, 0x22, 0x24, 0x22, + 0x22, 0x22, 0x42, 0x42, 0x22, 0x42, 0x22, 0x24, + 0x24, 0x22, 0x24, 0x42, 0x22, 0x22, 0x22, 0x42, + 0x42, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x42, 0x42, 0x42, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, 0x42, 0x24, + 0x22, 0x22, 0x24, 0x24, 0x22, 0x24, 0x44, 0x22, + 0x42, 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, 0x42, + 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, 0x22, 0x24, + 0x24, 0x22, 0x24, 0x24, 0x22, 0x22, 0x22, 0x42, + 0x22, 0x42, 0x24, 0x42, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, 0x42, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x42, 0x24, + 0x24, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x22, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x22, 0x42, 0x22, 0x42, 0x24, + 0x22, 0x44, 0x22, 0x42, 0x22, 0x42, 0x22, 0x22, + 0x42, 0x22, 0x22, 0x42, 0x24, 0x24, 0x22, 0x24, + 0x44, 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, 0x42, 0x24, + 0x22, 0x42, 0x22, 0x22, 0x22, 0x22, 0x44, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x22, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, 0x42, 0x22, + 0x22, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, + 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x42, 0x22, 0x32, 0x22, 0x23, 0x22, 0x23, 0x22, + 0x22, 0x22, 0x32, 0x22, 0x32, 0x22, 0x22, 0x32, + 0x22, 0x22, 0x32, 0x23, 0x22, 0x22, 0x22, 0x32, + 0x22, 0x23, 0x22, 0x32, 0x22, 0x23, 0x22, 0x32, + 0x23, 0x22, 0x32, 0x22, 0x22, 0x32, 0x22, 0x23, + 0x22, 0x32, 0x22, 0x32, 0x23, 0x22, 0x23, 0x22, + 0x22, 0x23, 0x22, 0x22, 0x22, 0x32, 0x22, 0x22, + 0x23, 0x22, 0x22, 0x22, 0x32, 0x22, 0x23, 0x24, + 0x22, 0x22, 0x22, 0x12, 0x21, 0x22, 0x12, 0x21, + 0x22, 0x12, 0x21, 0x22, 0x12, 0x21, 0x22, 0x12, + 0x21, 0x22, 0x12, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x12, 0x21, 0x22, 0x12, 0x21, 0x22, 0x12, 0x21, + 0x22, 0x12, 0x21, 0x22, 0x12, 0x21, 0x22, 0x12, + 0x21, 0x22, 0x12, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x12, 0x21, 0x22, 0x12, 0x21, 0x22, 0x22, 0x12, + 0x22, 0x22, 0x12, 0x22, 0x21, 0x22, 0x22, 0x12, + 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, 0x42, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x42, 0x22, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, + 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, + 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x22, 0x42, 0x22, 0x22, 0x42, 0x22, 0x44, 0x22, + 0x24, 0x44, 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, + 0x42, 0x22, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, + 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, + 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x22, 0x42, 0x22, 0x22, 0x42, 0x24, 0x22, 0x22, + 0x24, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x22, + 0x42, 0x22, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, + 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, + 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x22, 0x42, 0x22, 0x22, 0x42, 0x24, 0x22, 0x22, + 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, + 0x22, 0x22, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, + 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, + 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x22, 0x42, 0x22, 0x22, 0x22, 0x22, 0x44, 0x22, + 0x24, 0x22, 0x22, 0x42, 0x42, 0x24, 0x44, 0x22, + 0x42, 0x22, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, + 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, + 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x22, 0x42, 0x22, 0x22, 0x42, 0x22, 0x24, 0x22, + 0x24, 0x24, 0x22, 0x24, 0x22, 0x22, 0x42, 0x22, + 0x42, 0x22, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, + 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, + 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x22, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x42, 0x22, 0x42, 0x42, 0x24, 0x24, 0x22, + 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x32, 0x23, 0x22, 0x32, 0x23, 0x22, + 0x32, 0x23, 0x22, 0x32, 0x23, 0x22, 0x32, 0x23, + 0x22, 0x32, 0x23, 0x22, 0x32, 0x23, 0x22, 0x32, + 0x23, 0x22, 0x32, 0x23, 0x22, 0x32, 0x23, 0x22, + 0x32, 0x23, 0x22, 0x32, 0x23, 0x22, 0x32, 0x23, + 0x22, 0x32, 0x23, 0x22, 0x32, 0x23, 0x22, 0x32, + 0x23, 0x22, 0x32, 0x23, 0x22, 0x32, 0x22, 0x23, + 0x22, 0x22, 0x23, 0x22, 0x22, 0x32, 0x22, 0x23, + 0x22, 0x22, 0x22, 0x22, 0x12, 0x22, 0x12, 0x22, + 0x22, 0x12, 0x22, 0x21, 0x22, 0x12, 0x21, 0x22, + 0x22, 0x12, 0x21, 0x22, 0x22, 0x22, 0x12, 0x22, + 0x21, 0x22, 0x22, 0x21, 0x22, 0x22, 0x21, 0x22, + 0x22, 0x21, 0x22, 0x21, 0x22, 0x22, 0x12, 0x22, + 0x12, 0x22, 0x21, 0x22, 0x22, 0x12, 0x22, 0x22, + 0x21, 0x22, 0x22, 0x12, 0x22, 0x21, 0x22, 0x22, + 0x12, 0x22, 0x12, 0x21, 0x22, 0x21, 0x22, 0x22, + 0x12, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, + 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, + 0x22, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x24, 0x22, 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, + 0x22, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, + 0x22, 0x24, 0x22, 0x42, 0x24, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x44, 0x22, 0x42, 0x22, 0x24, + 0x44, 0x22, 0x42, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x24, 0x22, 0x42, 0x24, 0x24, 0x24, 0x22, 0x42, + 0x42, 0x22, 0x44, 0x22, 0x24, 0x44, 0x22, 0x22, + 0x44, 0x42, 0x24, 0x22, 0x24, 0x42, 0x22, 0x24, + 0x22, 0x24, 0x42, 0x22, 0x42, 0x22, 0x24, 0x24, + 0x22, 0x24, 0x24, 0x22, 0x24, 0x22, 0x24, 0x44, + 0x22, 0x24, 0x22, 0x42, 0x24, 0x22, 0x22, 0x22, + 0x22, 0x42, 0x24, 0x22, 0x22, 0x42, 0x22, 0x42, + 0x24, 0x22, 0x42, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x24, 0x22, 0x42, 0x24, 0x24, 0x24, 0x22, 0x42, + 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x22, 0x42, 0x24, 0x22, 0x22, 0x24, 0x22, 0x42, + 0x22, 0x42, 0x42, 0x22, 0x42, 0x22, 0x24, 0x24, + 0x22, 0x22, 0x42, 0x22, 0x42, 0x42, 0x24, 0x22, + 0x22, 0x24, 0x22, 0x42, 0x24, 0x22, 0x22, 0x22, + 0x22, 0x42, 0x24, 0x24, 0x22, 0x42, 0x22, 0x42, + 0x24, 0x22, 0x42, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x42, 0x22, 0x42, 0x24, 0x24, 0x24, 0x22, 0x42, + 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x22, 0x42, 0x24, 0x22, 0x24, 0x22, 0x22, 0x42, + 0x22, 0x42, 0x42, 0x24, 0x24, 0x22, 0x42, 0x42, + 0x42, 0x22, 0x42, 0x22, 0x42, 0x42, 0x22, 0x24, + 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x22, + 0x22, 0x42, 0x22, 0x42, 0x22, 0x44, 0x22, 0x24, + 0x44, 0x22, 0x44, 0x22, 0x24, 0x22, 0x42, 0x24, + 0x24, 0x22, 0x42, 0x24, 0x44, 0x42, 0x22, 0x44, + 0x22, 0x22, 0x44, 0x22, 0x24, 0x44, 0x22, 0x22, + 0x44, 0x42, 0x24, 0x42, 0x22, 0x44, 0x22, 0x44, + 0x22, 0x42, 0x42, 0x24, 0x24, 0x22, 0x42, 0x42, + 0x42, 0x24, 0x24, 0x22, 0x42, 0x42, 0x24, 0x44, + 0x22, 0x24, 0x22, 0x42, 0x24, 0x22, 0x22, 0x22, + 0x22, 0x42, 0x22, 0x22, 0x22, 0x42, 0x22, 0x22, + 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, 0x22, 0x24, + 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x42, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x42, + 0x22, 0x42, 0x22, 0x22, 0x22, 0x24, 0x22, 0x22, + 0x22, 0x22, 0x42, 0x22, 0x24, 0x22, 0x42, 0x24, + 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x24, 0x22, 0x42, 0x24, 0x22, 0x24, 0x24, + 0x22, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x32, 0x22, 0x23, 0x22, 0x23, 0x22, + 0x22, 0x23, 0x22, 0x22, 0x32, 0x23, 0x22, 0x32, + 0x22, 0x23, 0x22, 0x32, 0x22, 0x22, 0x23, 0x22, + 0x22, 0x32, 0x22, 0x22, 0x32, 0x22, 0x22, 0x32, + 0x22, 0x22, 0x32, 0x22, 0x32, 0x22, 0x23, 0x22, + 0x23, 0x22, 0x22, 0x32, 0x22, 0x23, 0x22, 0x22, + 0x22, 0x32, 0x22, 0x23, 0x22, 0x22, 0x32, 0x22, + 0x23, 0x22, 0x23, 0x22, 0x32, 0x22, 0x32, 0x22, + 0x23, 0x22, 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, + 0x12, 0x22, 0x22, 0x21, 0x22, 0x22, 0x21, 0x22, + 0x22, 0x21, 0x22, 0x22, 0x22, 0x12, 0x22, 0x22, + 0x21, 0x22, 0x22, 0x22, 0x22, 0x12, 0x22, 0x22, + 0x21, 0x22, 0x22, 0x22, 0x12, 0x22, 0x22, 0x12, + 0x22, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x21, + 0x22, 0x22, 0x21, 0x22, 0x21, 0x22, 0x22, 0x12, + 0x22, 0x22, 0x12, 0x22, 0x21, 0x22, 0x22, 0x21, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x44, 0x22, 0x22, 0x22, 0x44, 0x22, 0x22, 0x22, + 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, 0x44, 0x24, + 0x22, 0x42, 0x22, 0x42, 0x22, 0x44, 0x22, 0x22, + 0x42, 0x22, 0x22, 0x44, 0x42, 0x22, 0x22, 0x42, + 0x22, 0x22, 0x24, 0x24, 0x22, 0x22, 0x42, 0x22, + 0x42, 0x22, 0x24, 0x22, 0x22, 0x44, 0x44, 0x22, + 0x42, 0x22, 0x24, 0x22, 0x24, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x22, + 0x44, 0x42, 0x22, 0x24, 0x42, 0x22, 0x44, 0x42, + 0x22, 0x22, 0x24, 0x22, 0x22, 0x24, 0x22, 0x42, + 0x22, 0x42, 0x22, 0x42, 0x24, 0x22, 0x42, 0x22, + 0x42, 0x22, 0x24, 0x22, 0x24, 0x22, 0x22, 0x42, + 0x22, 0x22, 0x24, 0x24, 0x22, 0x22, 0x24, 0x24, + 0x22, 0x22, 0x24, 0x22, 0x22, 0x42, 0x22, 0x22, + 0x42, 0x22, 0x24, 0x22, 0x24, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x24, 0x22, + 0x42, 0x24, 0x22, 0x42, 0x22, 0x24, 0x22, 0x42, + 0x22, 0x22, 0x24, 0x44, 0x22, 0x24, 0x24, 0x24, + 0x22, 0x44, 0x44, 0x22, 0x22, 0x24, 0x22, 0x22, + 0x42, 0x22, 0x24, 0x22, 0x24, 0x22, 0x24, 0x24, + 0x22, 0x22, 0x42, 0x42, 0x42, 0x22, 0x22, 0x42, + 0x22, 0x22, 0x24, 0x22, 0x22, 0x24, 0x22, 0x22, + 0x42, 0x22, 0x24, 0x22, 0x24, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x22, + 0x42, 0x24, 0x22, 0x42, 0x22, 0x24, 0x22, 0x42, + 0x22, 0x22, 0x24, 0x22, 0x42, 0x24, 0x22, 0x24, + 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x22, + 0x42, 0x22, 0x24, 0x22, 0x24, 0x22, 0x24, 0x24, + 0x22, 0x22, 0x42, 0x42, 0x42, 0x22, 0x22, 0x42, + 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, 0x42, 0x22, + 0x42, 0x22, 0x42, 0x22, 0x24, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x42, 0x22, + 0x44, 0x42, 0x22, 0x24, 0x42, 0x22, 0x44, 0x42, + 0x22, 0x22, 0x24, 0x22, 0x42, 0x24, 0x22, 0x24, + 0x22, 0x42, 0x22, 0x42, 0x24, 0x22, 0x42, 0x22, + 0x42, 0x22, 0x24, 0x22, 0x24, 0x22, 0x42, 0x22, + 0x42, 0x24, 0x22, 0x22, 0x24, 0x22, 0x24, 0x24, + 0x22, 0x22, 0x42, 0x42, 0x22, 0x22, 0x24, 0x22, + 0x42, 0x22, 0x42, 0x22, 0x24, 0x22, 0x42, 0x42, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x42, + 0x22, 0x22, 0x24, 0x44, 0x22, 0x22, 0x44, 0x42, + 0x22, 0x44, 0x44, 0x22, 0x22, 0x44, 0x22, 0x44, + 0x44, 0x42, 0x24, 0x22, 0x24, 0x22, 0x42, 0x22, + 0x42, 0x24, 0x22, 0x22, 0x24, 0x22, 0x42, 0x22, + 0x42, 0x24, 0x22, 0x24, 0x22, 0x44, 0x44, 0x22, + 0x44, 0x22, 0x42, 0x22, 0x44, 0x22, 0x24, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, + 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x42, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x32, 0x22, 0x22, 0x32, 0x22, 0x22, + 0x23, 0x22, 0x22, 0x22, 0x32, 0x22, 0x22, 0x32, + 0x22, 0x22, 0x32, 0x22, 0x22, 0x23, 0x22, 0x22, + 0x22, 0x32, 0x22, 0x22, 0x22, 0x23, 0x22, 0x22, + 0x22, 0x32, 0x22, 0x22, 0x23, 0x22, 0x22, 0x23, + 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x22, + 0x32, 0x22, 0x22, 0x32, 0x22, 0x32, 0x22, 0x23, + 0x22, 0x22, 0x23, 0x22, 0x22, 0x32, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x12, 0x22, 0x21, 0x22, 0x22, + 0x12, 0x22, 0x21, 0x22, 0x22, 0x21, 0x22, 0x22, + 0x22, 0x22, 0x12, 0x22, 0x22, 0x21, 0x22, 0x22, + 0x22, 0x12, 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, + 0x12, 0x22, 0x22, 0x12, 0x22, 0x22, 0x12, 0x22, + 0x22, 0x21, 0x22, 0x22, 0x21, 0x22, 0x12, 0x22, + 0x21, 0x22, 0x22, 0x21, 0x22, 0x22, 0x12, 0x22, + 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x12, 0x22, + 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, + 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x22, 0x22, 0x42, 0x22, 0x22, + 0x22, 0x42, 0x22, 0x22, 0x42, 0x22, 0x22, 0x42, + 0x22, 0x22, 0x22, 0x42, 0x22, 0x42, 0x24, 0x44, + 0x42, 0x22, 0x24, 0x44, 0x22, 0x24, 0x44, 0x42, + 0x22, 0x44, 0x44, 0x22, 0x42, 0x22, 0x22, 0x24, + 0x44, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x44, + 0x22, 0x24, 0x22, 0x42, 0x24, 0x44, 0x22, 0x42, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x44, 0x22, 0x24, + 0x44, 0x22, 0x22, 0x22, 0x24, 0x22, 0x24, 0x44, + 0x22, 0x24, 0x22, 0x22, 0x22, 0x22, 0x24, 0x22, + 0x44, 0x42, 0x22, 0x42, 0x22, 0x42, 0x24, 0x22, + 0x24, 0x22, 0x42, 0x22, 0x42, 0x24, 0x22, 0x24, + 0x22, 0x42, 0x22, 0x22, 0x42, 0x22, 0x22, 0x42, + 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x42, 0x24, 0x24, 0x22, 0x24, 0x22, 0x22, 0x42, + 0x24, 0x22, 0x42, 0x24, 0x22, 0x44, 0x22, 0x42, + 0x22, 0x42, 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x42, 0x22, 0x42, 0x22, 0x24, 0x24, + 0x24, 0x24, 0x22, 0x24, 0x44, 0x22, 0x24, 0x22, + 0x24, 0x22, 0x42, 0x22, 0x22, 0x24, 0x22, 0x24, + 0x22, 0x42, 0x22, 0x22, 0x42, 0x22, 0x22, 0x42, + 0x24, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x22, + 0x42, 0x24, 0x42, 0x22, 0x24, 0x22, 0x22, 0x42, + 0x42, 0x42, 0x42, 0x24, 0x24, 0x24, 0x22, 0x42, + 0x22, 0x42, 0x24, 0x22, 0x24, 0x22, 0x24, 0x44, + 0x22, 0x24, 0x22, 0x22, 0x24, 0x22, 0x24, 0x22, + 0x42, 0x24, 0x22, 0x24, 0x24, 0x22, 0x24, 0x44, + 0x42, 0x22, 0x42, 0x22, 0x22, 0x24, 0x22, 0x24, + 0x22, 0x44, 0x42, 0x22, 0x44, 0x42, 0x22, 0x42, + 0x22, 0x22, 0x24, 0x44, 0x42, 0x24, 0x22, 0x22, + 0x42, 0x24, 0x42, 0x22, 0x24, 0x22, 0x22, 0x42, + 0x42, 0x42, 0x42, 0x24, 0x24, 0x24, 0x22, 0x42, + 0x22, 0x42, 0x22, 0x22, 0x22, 0x42, 0x22, 0x22, + 0x22, 0x42, 0x22, 0x24, 0x22, 0x42, 0x22, 0x42, + 0x22, 0x42, 0x22, 0x22, 0x42, 0x22, 0x24, 0x22, + 0x24, 0x22, 0x42, 0x22, 0x42, 0x24, 0x22, 0x24, + 0x22, 0x42, 0x22, 0x22, 0x42, 0x22, 0x22, 0x42, + 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x22, + 0x42, 0x24, 0x24, 0x22, 0x24, 0x22, 0x22, 0x44, + 0x22, 0x24, 0x42, 0x24, 0x42, 0x24, 0x22, 0x42, + 0x22, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x44, 0x22, 0x22, 0x24, + 0x44, 0x22, 0x22, 0x22, 0x42, 0x22, 0x24, 0x44, + 0x42, 0x22, 0x24, 0x44, 0x22, 0x24, 0x44, 0x42, + 0x22, 0x44, 0x44, 0x22, 0x44, 0x44, 0x22, 0x24, + 0x44, 0x22, 0x24, 0x22, 0x42, 0x24, 0x22, 0x22, + 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, 0x22, 0x44, + 0x22, 0x24, 0x42, 0x24, 0x42, 0x24, 0x22, 0x24, + 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x32, 0x23, 0x22, 0x22, 0x32, 0x22, + 0x23, 0x22, 0x22, 0x32, 0x22, 0x22, 0x32, 0x22, + 0x22, 0x22, 0x23, 0x22, 0x22, 0x22, 0x32, 0x22, + 0x22, 0x23, 0x22, 0x22, 0x22, 0x32, 0x22, 0x22, + 0x23, 0x22, 0x22, 0x23, 0x22, 0x22, 0x23, 0x22, + 0x22, 0x22, 0x32, 0x22, 0x22, 0x32, 0x23, 0x22, + 0x22, 0x32, 0x22, 0x22, 0x32, 0x22, 0x23, 0x22, + 0x22, 0x22, 0x22, 0x32, 0x22, 0x22, 0x23, 0x22, + 0x22, 0x22, 0x22, 0x12, 0x21, 0x22, 0x22, 0x12, + 0x22, 0x22, 0x21, 0x22, 0x22, 0x12, 0x22, 0x22, + 0x12, 0x22, 0x22, 0x12, 0x21, 0x22, 0x21, 0x22, + 0x21, 0x22, 0x21, 0x22, 0x22, 0x12, 0x21, 0x22, + 0x21, 0x22, 0x12, 0x22, 0x12, 0x22, 0x22, 0x12, + 0x22, 0x12, 0x22, 0x22, 0x12, 0x22, 0x22, 0x12, + 0x22, 0x22, 0x12, 0x22, 0x21, 0x22, 0x22, 0x21, + 0x22, 0x22, 0x12, 0x22, 0x22, 0x12, 0x22, 0x22, + 0x12, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x42, 0x24, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x22, 0x22, + 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, + 0x24, 0x24, 0x22, 0x24, 0x44, 0x22, 0x22, 0x44, + 0x22, 0x24, 0x24, 0x22, 0x22, 0x24, 0x22, 0x22, + 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, + 0x22, 0x24, 0x22, 0x42, 0x22, 0x24, 0x42, 0x22, + 0x24, 0x22, 0x44, 0x44, 0x22, 0x24, 0x42, 0x22, + 0x22, 0x42, 0x22, 0x44, 0x22, 0x22, 0x44, 0x22, + 0x22, 0x42, 0x22, 0x24, 0x42, 0x22, 0x24, 0x42, + 0x22, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x44, 0x44, 0x42, 0x22, 0x44, 0x22, 0x42, 0x44, + 0x22, 0x42, 0x42, 0x22, 0x22, 0x24, 0x22, 0x22, + 0x42, 0x22, 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x42, 0x22, 0x42, 0x24, 0x22, + 0x24, 0x22, 0x42, 0x22, 0x22, 0x42, 0x24, 0x22, + 0x44, 0x44, 0x22, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x22, 0x42, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, + 0x24, 0x24, 0x22, 0x22, 0x42, 0x22, 0x24, 0x22, + 0x22, 0x42, 0x44, 0x22, 0x22, 0x24, 0x22, 0x22, + 0x42, 0x22, 0x22, 0x24, 0x44, 0x22, 0x22, 0x24, + 0x42, 0x22, 0x22, 0x42, 0x22, 0x42, 0x24, 0x22, + 0x24, 0x22, 0x24, 0x42, 0x22, 0x22, 0x24, 0x22, + 0x42, 0x42, 0x22, 0x22, 0x42, 0x24, 0x22, 0x42, + 0x22, 0x42, 0x22, 0x42, 0x24, 0x22, 0x22, 0x24, + 0x22, 0x22, 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, + 0x24, 0x24, 0x22, 0x24, 0x42, 0x22, 0x22, 0x42, + 0x22, 0x24, 0x22, 0x22, 0x22, 0x24, 0x22, 0x22, + 0x42, 0x22, 0x22, 0x22, 0x42, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x22, 0x42, 0x24, 0x22, + 0x24, 0x22, 0x22, 0x24, 0x22, 0x22, 0x42, 0x22, + 0x24, 0x42, 0x22, 0x44, 0x22, 0x24, 0x44, 0x22, + 0x22, 0x42, 0x22, 0x24, 0x42, 0x22, 0x24, 0x44, + 0x22, 0x42, 0x22, 0x22, 0x42, 0x24, 0x24, 0x22, + 0x44, 0x44, 0x42, 0x24, 0x44, 0x22, 0x44, 0x24, + 0x22, 0x42, 0x42, 0x22, 0x42, 0x24, 0x22, 0x22, + 0x42, 0x24, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x22, 0x42, 0x24, 0x22, + 0x44, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, 0x22, + 0x24, 0x42, 0x22, 0x42, 0x22, 0x24, 0x22, 0x22, + 0x22, 0x24, 0x22, 0x42, 0x24, 0x22, 0x42, 0x24, + 0x22, 0x22, 0x22, 0x22, 0x42, 0x24, 0x24, 0x22, + 0x24, 0x24, 0x22, 0x22, 0x42, 0x22, 0x44, 0x22, + 0x22, 0x24, 0x22, 0x22, 0x42, 0x22, 0x42, 0x24, + 0x22, 0x24, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x22, 0x24, 0x42, 0x22, + 0x24, 0x22, 0x24, 0x42, 0x22, 0x24, 0x42, 0x22, + 0x22, 0x42, 0x22, 0x44, 0x42, 0x22, 0x44, 0x22, + 0x24, 0x44, 0x22, 0x24, 0x42, 0x22, 0x24, 0x42, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x31, 0x23, 0x22, 0x32, 0x22, 0x23, + 0x22, 0x22, 0x22, 0x32, 0x22, 0x23, 0x22, 0x22, + 0x23, 0x22, 0x22, 0x23, 0x22, 0x32, 0x22, 0x32, + 0x22, 0x32, 0x22, 0x32, 0x22, 0x23, 0x22, 0x32, + 0x22, 0x32, 0x23, 0x22, 0x23, 0x22, 0x22, 0x23, + 0x22, 0x23, 0x22, 0x22, 0x23, 0x22, 0x22, 0x23, + 0x22, 0x22, 0x23, 0x22, 0x22, 0x32, 0x22, 0x22, + 0x32, 0x22, 0x23, 0x22, 0x22, 0x23, 0x22, 0x22, + 0x23, 0x22 +}; + + const u32 BuiltInFontDataSize = sizeof(BuiltInFontData); + +#else // !defined(_IRR_COMPILE_WITH_BMP_LOADER_) + + // built-in font cannot be loaded if there is no BMP loader + + const u8 * const BuiltInFontData=0; + + const u32 BuiltInFontDataSize = 0; + +#endif +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif + diff --git a/source/Irrlicht/C3DSMeshFileLoader.cpp b/source/Irrlicht/C3DSMeshFileLoader.cpp new file mode 100644 index 00000000..1ac77cc2 --- /dev/null +++ b/source/Irrlicht/C3DSMeshFileLoader.cpp @@ -0,0 +1,1371 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_3DS_LOADER_ + +#include "C3DSMeshFileLoader.h" +#include "CMeshTextureLoader.h" +#include "os.h" +#include "SMeshBuffer.h" +#include "SAnimatedMesh.h" +#include "IReadFile.h" +#include "IVideoDriver.h" +#include "IMeshManipulator.h" + +#ifdef _DEBUG +#define _IRR_DEBUG_3DS_LOADER_ +#endif + +namespace irr +{ +namespace scene +{ + + +namespace +{ +enum e3DSChunk +{ + // Primary chunk + C3DS_MAIN3DS = 0x4D4D, + + // Main Chunks + C3DS_EDIT3DS = 0x3D3D, + C3DS_KEYF3DS = 0xB000, + C3DS_VERSION = 0x0002, + C3DS_MESHVERSION = 0x3D3E, + + // sub chunks of C3DS_EDIT3DS + C3DS_EDIT_MATERIAL = 0xAFFF, + C3DS_EDIT_OBJECT = 0x4000, + + // sub chunks of C3DS_EDIT_MATERIAL + C3DS_MATNAME = 0xA000, + C3DS_MATAMBIENT = 0xA010, + C3DS_MATDIFFUSE = 0xA020, + C3DS_MATSPECULAR = 0xA030, + C3DS_MATSHININESS = 0xA040, + C3DS_MATSHIN2PCT = 0xA041, + C3DS_TRANSPARENCY = 0xA050, + C3DS_TRANSPARENCY_FALLOFF = 0xA052, + C3DS_REFL_BLUR = 0xA053, + C3DS_TWO_SIDE = 0xA081, + C3DS_WIRE = 0xA085, + C3DS_SHADING = 0xA100, + C3DS_MATTEXMAP = 0xA200, + C3DS_MATSPECMAP = 0xA204, + C3DS_MATOPACMAP = 0xA210, + C3DS_MATREFLMAP = 0xA220, + C3DS_MATBUMPMAP = 0xA230, + C3DS_MATMAPFILE = 0xA300, + C3DS_MAT_TEXTILING = 0xA351, + C3DS_MAT_USCALE = 0xA354, + C3DS_MAT_VSCALE = 0xA356, + C3DS_MAT_UOFFSET = 0xA358, + C3DS_MAT_VOFFSET = 0xA35A, + + // subs of C3DS_EDIT_OBJECT + C3DS_OBJTRIMESH = 0x4100, + + // subs of C3DS_OBJTRIMESH + C3DS_TRIVERT = 0x4110, + C3DS_POINTFLAGARRAY= 0x4111, + C3DS_TRIFACE = 0x4120, + C3DS_TRIFACEMAT = 0x4130, + C3DS_TRIUV = 0x4140, + C3DS_TRISMOOTH = 0x4150, + C3DS_TRIMATRIX = 0x4160, + C3DS_MESHCOLOR = 0x4165, + C3DS_DIRECT_LIGHT = 0x4600, + C3DS_DL_INNER_RANGE= 0x4659, + C3DS_DL_OUTER_RANGE= 0x465A, + C3DS_DL_MULTIPLIER = 0x465B, + C3DS_CAMERA = 0x4700, + C3DS_CAM_SEE_CONE = 0x4710, + C3DS_CAM_RANGES = 0x4720, + + // subs of C3DS_KEYF3DS + C3DS_KF_HDR = 0xB00A, + C3DS_AMBIENT_TAG = 0xB001, + C3DS_OBJECT_TAG = 0xB002, + C3DS_CAMERA_TAG = 0xB003, + C3DS_TARGET_TAG = 0xB004, + C3DS_LIGHTNODE_TAG = 0xB005, + C3DS_KF_SEG = 0xB008, + C3DS_KF_CURTIME = 0xB009, + C3DS_KF_NODE_HDR = 0xB010, + C3DS_PIVOTPOINT = 0xB013, + C3DS_BOUNDBOX = 0xB014, + C3DS_MORPH_SMOOTH = 0xB015, + C3DS_POS_TRACK_TAG = 0xB020, + C3DS_ROT_TRACK_TAG = 0xB021, + C3DS_SCL_TRACK_TAG = 0xB022, + C3DS_NODE_ID = 0xB030, + + // Viewport definitions + C3DS_VIEWPORT_LAYOUT = 0x7001, + C3DS_VIEWPORT_DATA = 0x7011, + C3DS_VIEWPORT_DATA_3 = 0x7012, + C3DS_VIEWPORT_SIZE = 0x7020, + + // different color chunk types + C3DS_COL_RGB = 0x0010, + C3DS_COL_TRU = 0x0011, + C3DS_COL_LIN_24 = 0x0012, + C3DS_COL_LIN_F = 0x0013, + + // percentage chunk types + C3DS_PERCENTAGE_I = 0x0030, + C3DS_PERCENTAGE_F = 0x0031, + + C3DS_CHUNK_MAX = 0xFFFF +}; +} + + +//! Constructor +C3DSMeshFileLoader::C3DSMeshFileLoader(ISceneManager* smgr, io::IFileSystem* fs) +: SceneManager(smgr), FileSystem(fs), Vertices(0), Indices(0), SmoothingGroups(0), TCoords(0), + CountVertices(0), CountFaces(0), CountTCoords(0), Mesh(0) +{ + + #ifdef _DEBUG + setDebugName("C3DSMeshFileLoader"); + #endif + + if (FileSystem) + FileSystem->grab(); + + TextureLoader = new CMeshTextureLoader( FileSystem, SceneManager->getVideoDriver() ); +} + + +//! destructor +C3DSMeshFileLoader::~C3DSMeshFileLoader() +{ + cleanUp(); + + if (FileSystem) + FileSystem->drop(); + + if (Mesh) + Mesh->drop(); +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool C3DSMeshFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "3ds" ); +} + + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IReferenceCounted::drop() for more information. +IAnimatedMesh* C3DSMeshFileLoader::createMesh(io::IReadFile* file) +{ + if ( getMeshTextureLoader() ) + getMeshTextureLoader()->setMeshFile(file); + + ChunkData data; + + readChunkData(file, data); + + if (data.header.id != C3DS_MAIN3DS ) + return 0; + + CurrentMaterial.clear(); + Materials.clear(); + MeshBufferNames.clear(); + cleanUp(); + + if (Mesh) + Mesh->drop(); + + Mesh = new SMesh(); + + if (readChunk(file, &data)) + { + // success + + for (u32 i=0; igetMeshBufferCount(); ++i) + { + SMeshBuffer* mb = ((SMeshBuffer*)Mesh->getMeshBuffer(i)); + // drop empty buffers + if (mb->getIndexCount() == 0 || mb->getVertexCount() == 0) + { + Mesh->MeshBuffers.erase(i--); + mb->drop(); + } + else + { + if (mb->Material.MaterialType == video::EMT_PARALLAX_MAP_SOLID) + { + SMesh tmp; + tmp.addMeshBuffer(mb); + mb->drop(); + IMesh* tangentMesh = SceneManager->getMeshManipulator()->createMeshWithTangents(&tmp); + Mesh->MeshBuffers[i]=tangentMesh->getMeshBuffer(0); + // we need to grab because we replace the buffer manually. + Mesh->MeshBuffers[i]->grab(); + // clean up intermediate mesh struct + tangentMesh->drop(); + } + Mesh->MeshBuffers[i]->recalculateBoundingBox(); + } + } + + Mesh->recalculateBoundingBox(); + + SAnimatedMesh* am = new SAnimatedMesh(); + am->Type = EAMT_3DS; + am->addMesh(Mesh); + am->recalculateBoundingBox(); + Mesh->drop(); + Mesh = 0; + return am; + } + + Mesh->drop(); + Mesh = 0; + + return 0; +} + + +bool C3DSMeshFileLoader::readPercentageChunk(io::IReadFile* file, + ChunkData* chunk, f32& percentage) +{ +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load percentage chunk.", ELL_DEBUG); +#endif + + ChunkData data; + readChunkData(file, data); + + short intpercentage; + float fpercentage; + + switch(data.header.id) + { + case C3DS_PERCENTAGE_I: + { + // read short + file->read(&intpercentage, 2); +#ifdef __BIG_ENDIAN__ + intpercentage = os::Byteswap::byteswap(intpercentage); +#endif + percentage=intpercentage/100.0f; + data.read += 2; + } + break; + case C3DS_PERCENTAGE_F: + { + // read float + file->read(&fpercentage, sizeof(float)); + data.read += sizeof(float); +#ifdef __BIG_ENDIAN__ + percentage = os::Byteswap::byteswap(fpercentage); +#else + percentage = (f32)fpercentage; +#endif + } + break; + default: + { + // unknown percentage chunk + os::Printer::log("Unknown percentage chunk in 3Ds file.", ELL_WARNING); + file->seek(data.header.length - data.read, true); + data.read += data.header.length - data.read; + } + } + + chunk->read += data.read; + + return true; +} + +bool C3DSMeshFileLoader::readColorChunk(io::IReadFile* file, ChunkData* chunk, + video::SColor& out) +{ +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load color chunk.", ELL_DEBUG); +#endif + ChunkData data; + readChunkData(file, data); + + u8 c[3]; + f32 cf[3]; + + switch(data.header.id) + { + case C3DS_COL_TRU: + case C3DS_COL_LIN_24: + { + // read 8 bit data + file->read(c, sizeof(c)); + out.set(255, c[0], c[1], c[2]); + data.read += sizeof(c); + } + break; + case C3DS_COL_RGB: + case C3DS_COL_LIN_F: + { + // read float data + file->read(cf, sizeof(cf)); +#ifdef __BIG_ENDIAN__ + cf[0] = os::Byteswap::byteswap(cf[0]); + cf[1] = os::Byteswap::byteswap(cf[1]); + cf[2] = os::Byteswap::byteswap(cf[2]); +#endif + out.set(255, (s32)(cf[0]*255.0f), (s32)(cf[1]*255.0f), (s32)(cf[2]*255.0f)); + data.read += sizeof(cf); + } + break; + default: + { + // unknown color chunk size + os::Printer::log("Unknown size of color chunk in 3Ds file.", ELL_WARNING); + file->seek(data.header.length - data.read, true); + data.read += data.header.length - data.read; + } + } + + chunk->read += data.read; + + return true; +} + + +bool C3DSMeshFileLoader::readMaterialChunk(io::IReadFile* file, ChunkData* parent) +{ +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load material chunk.", ELL_DEBUG); +#endif + u16 matSection=0; + + while(parent->read < parent->header.length) + { + ChunkData data; + readChunkData(file, data); + + switch(data.header.id) + { + case C3DS_MATNAME: + { + c8* c = new c8[data.header.length - data.read]; + file->read(c, data.header.length - data.read); + + if (strlen(c)) + CurrentMaterial.Name = c; + + data.read += data.header.length - data.read; + delete [] c; + } + break; + case C3DS_MATAMBIENT: + readColorChunk(file, &data, CurrentMaterial.Material.AmbientColor); + break; + case C3DS_MATDIFFUSE: + readColorChunk(file, &data, CurrentMaterial.Material.DiffuseColor); + break; + case C3DS_MATSPECULAR: + readColorChunk(file, &data, CurrentMaterial.Material.SpecularColor); + break; + case C3DS_MATSHININESS: + readPercentageChunk(file, &data, CurrentMaterial.Material.Shininess); + CurrentMaterial.Material.Shininess = (1.f-CurrentMaterial.Material.Shininess)*128.f; + break; + case C3DS_TRANSPARENCY: + { + f32 percentage; + readPercentageChunk(file, &data, percentage); + if (percentage>0.0f) + { + CurrentMaterial.Material.MaterialTypeParam=percentage; + CurrentMaterial.Material.MaterialType=video::EMT_TRANSPARENT_VERTEX_ALPHA; + } + else + { + CurrentMaterial.Material.MaterialType=video::EMT_SOLID; + } + } + break; + case C3DS_WIRE: + CurrentMaterial.Material.Wireframe=true; + break; + case C3DS_TWO_SIDE: + CurrentMaterial.Material.BackfaceCulling=false; + break; + case C3DS_SHADING: + { + s16 flags; + file->read(&flags, 2); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + switch (flags) + { + case 0: + CurrentMaterial.Material.Wireframe=true; + break; + case 1: + CurrentMaterial.Material.Wireframe=false; + CurrentMaterial.Material.GouraudShading=false; + break; + case 2: + CurrentMaterial.Material.Wireframe=false; + CurrentMaterial.Material.GouraudShading=true; + break; + default: + // phong and metal missing + break; + } + data.read += data.header.length - data.read; + } + break; + case C3DS_MATTEXMAP: + case C3DS_MATSPECMAP: + case C3DS_MATOPACMAP: + case C3DS_MATREFLMAP: + case C3DS_MATBUMPMAP: + { + matSection=data.header.id; + // Should contain a percentage chunk, but does + // not always have it + s16 testval; + const long pos = file->getPos(); + file->read(&testval, 2); +#ifdef __BIG_ENDIAN__ + testval = os::Byteswap::byteswap(testval); +#endif + file->seek(pos, false); + if ((testval == C3DS_PERCENTAGE_I) || + (testval == C3DS_PERCENTAGE_F)) + switch (matSection) + { + case C3DS_MATTEXMAP: + readPercentageChunk(file, &data, CurrentMaterial.Strength[0]); + break; + case C3DS_MATSPECMAP: + readPercentageChunk(file, &data, CurrentMaterial.Strength[1]); + break; + case C3DS_MATOPACMAP: + readPercentageChunk(file, &data, CurrentMaterial.Strength[2]); + break; + case C3DS_MATBUMPMAP: + readPercentageChunk(file, &data, CurrentMaterial.Strength[4]); + break; + } + } + break; + case C3DS_MATMAPFILE: + { + // read texture file name + c8* c = new c8[data.header.length - data.read]; + file->read(c, data.header.length - data.read); + switch (matSection) + { + case C3DS_MATTEXMAP: + CurrentMaterial.Filename[0] = c; + break; + case C3DS_MATSPECMAP: + CurrentMaterial.Filename[1] = c; + break; + case C3DS_MATOPACMAP: + CurrentMaterial.Filename[2] = c; + break; + case C3DS_MATREFLMAP: + CurrentMaterial.Filename[3] = c; + break; + case C3DS_MATBUMPMAP: + CurrentMaterial.Filename[4] = c; + break; + } + data.read += data.header.length - data.read; + delete [] c; + } + break; + case C3DS_MAT_TEXTILING: + { + s16 flags; + file->read(&flags, 2); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + data.read += 2; + } + break; + case C3DS_MAT_USCALE: + case C3DS_MAT_VSCALE: + case C3DS_MAT_UOFFSET: + case C3DS_MAT_VOFFSET: + { + f32 value; + file->read(&value, 4); +#ifdef __BIG_ENDIAN__ + value = os::Byteswap::byteswap(value); +#endif + u32 i=0; + if (matSection != C3DS_MATTEXMAP) + i=1; + u32 j=0,k=0; + if (data.header.id == C3DS_MAT_VSCALE) + { + j=1; + k=1; + } + else if (data.header.id == C3DS_MAT_UOFFSET) + { + j=2; + k=0; + } + else if (data.header.id == C3DS_MAT_VOFFSET) + { + j=2; + k=1; + } + CurrentMaterial.Material.getTextureMatrix(i)(j,k)=value; + + data.read += 4; + } + break; + default: + // ignore chunk + file->seek(data.header.length - data.read, true); + data.read += data.header.length - data.read; + } + + parent->read += data.read; + } + + Materials.push_back(CurrentMaterial); + CurrentMaterial.clear(); + + return true; +} + + + +bool C3DSMeshFileLoader::readTrackChunk(io::IReadFile* file, ChunkData& data, + IMeshBuffer* mb, const core::vector3df& pivot) +{ +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load track chunk.", ELL_DEBUG); +#endif + u16 flags; + u32 flags2; + // Track flags + file->read(&flags, 2); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + file->read(&flags2, 4); +#ifdef __BIG_ENDIAN__ + flags2 = os::Byteswap::byteswap(flags2); +#endif + file->read(&flags2, 4); +#ifdef __BIG_ENDIAN__ + flags2 = os::Byteswap::byteswap(flags2); +#endif + // Num keys + file->read(&flags2, 4); +#ifdef __BIG_ENDIAN__ + flags2 = os::Byteswap::byteswap(flags2); +#endif + file->read(&flags2, 4); +#ifdef __BIG_ENDIAN__ + flags2 = os::Byteswap::byteswap(flags2); +#endif + // TCB flags + file->read(&flags, 2); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + data.read += 20; + + f32 angle=0.0f; + if (data.header.id== C3DS_ROT_TRACK_TAG) + { + // Angle + file->read(&angle, sizeof(f32)); +#ifdef __BIG_ENDIAN__ + angle = os::Byteswap::byteswap(angle); +#endif + data.read += sizeof(f32); + } + core::vector3df vec; + file->read(&vec.X, sizeof(f32)); + file->read(&vec.Y, sizeof(f32)); + file->read(&vec.Z, sizeof(f32)); +#ifdef __BIG_ENDIAN__ + vec.X = os::Byteswap::byteswap(vec.X); + vec.Y = os::Byteswap::byteswap(vec.Y); + vec.Z = os::Byteswap::byteswap(vec.Z); +#endif + data.read += 12; + vec-=pivot; + + // apply transformation to mesh buffer + if (false)//mb) + { + video::S3DVertex *vertices=(video::S3DVertex*)mb->getVertices(); + if (data.header.id==C3DS_POS_TRACK_TAG) + { + for (u32 i=0; igetVertexCount(); ++i) + vertices[i].Pos+=vec; + } + else if (data.header.id==C3DS_ROT_TRACK_TAG) + { + //TODO + } + else if (data.header.id==C3DS_SCL_TRACK_TAG) + { + //TODO + } + } + // skip further frames + file->seek(data.header.length - data.read, true); + data.read += data.header.length - data.read; + return true; +} + + +bool C3DSMeshFileLoader::readFrameChunk(io::IReadFile* file, ChunkData* parent) +{ +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load frame chunk.", ELL_DEBUG); +#endif + ChunkData data; + + //KF_HDR is always at the beginning + readChunkData(file, data); + if (data.header.id != C3DS_KF_HDR) + return false; + else + { +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load keyframe header.", ELL_DEBUG); +#endif + u16 version; + file->read(&version, 2); +#ifdef __BIG_ENDIAN__ + version = os::Byteswap::byteswap(version); +#endif + core::stringc name; + readString(file, data, name); + u32 flags; + file->read(&flags, 4); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + + data.read += 4; + parent->read += data.read; + } + data.read=0; + + IMeshBuffer* mb=0; + core::vector3df pivot,bboxCenter; + while(parent->read < parent->header.length) + { + readChunkData(file, data); + + switch(data.header.id) + { + case C3DS_OBJECT_TAG: + { +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load object tag.", ELL_DEBUG); +#endif + mb=0; + pivot.set(0.0f, 0.0f, 0.0f); + } + break; + case C3DS_KF_SEG: + { +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load keyframe segment.", ELL_DEBUG); +#endif + u32 flags; + file->read(&flags, 4); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + file->read(&flags, 4); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + data.read += 8; + } + break; + case C3DS_KF_NODE_HDR: + { +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load keyframe node header.", ELL_DEBUG); +#endif + s16 flags; + c8* c = new c8[data.header.length - data.read-6]; + file->read(c, data.header.length - data.read-6); + + // search mesh buffer to apply these transformations to + for (u32 i=0; igetMeshBuffer(i); + break; + } + } + + file->read(&flags, 2); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + file->read(&flags, 2); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + file->read(&flags, 2); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + data.read += data.header.length - data.read; + delete [] c; + } + break; + case C3DS_KF_CURTIME: + { +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load keyframe current time.", ELL_DEBUG); +#endif + u32 flags; + file->read(&flags, 4); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + data.read += 4; + } + break; + case C3DS_NODE_ID: + { +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load node ID.", ELL_DEBUG); +#endif + u16 flags; + file->read(&flags, 2); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + data.read += 2; + } + break; + case C3DS_PIVOTPOINT: + { +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load pivot point.", ELL_DEBUG); +#endif + file->read(&pivot.X, sizeof(f32)); + file->read(&pivot.Y, sizeof(f32)); + file->read(&pivot.Z, sizeof(f32)); +#ifdef __BIG_ENDIAN__ + pivot.X = os::Byteswap::byteswap(pivot.X); + pivot.Y = os::Byteswap::byteswap(pivot.Y); + pivot.Z = os::Byteswap::byteswap(pivot.Z); +#endif + data.read += 12; + } + break; + case C3DS_BOUNDBOX: + { +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load bounding box.", ELL_DEBUG); +#endif + core::aabbox3df bbox; + // abuse bboxCenter as temporary variable + file->read(&bboxCenter.X, sizeof(f32)); + file->read(&bboxCenter.Y, sizeof(f32)); + file->read(&bboxCenter.Z, sizeof(f32)); +#ifdef __BIG_ENDIAN__ + bboxCenter.X = os::Byteswap::byteswap(bboxCenter.X); + bboxCenter.Y = os::Byteswap::byteswap(bboxCenter.Y); + bboxCenter.Z = os::Byteswap::byteswap(bboxCenter.Z); +#endif + bbox.reset(bboxCenter); + file->read(&bboxCenter.X, sizeof(f32)); + file->read(&bboxCenter.Y, sizeof(f32)); + file->read(&bboxCenter.Z, sizeof(f32)); +#ifdef __BIG_ENDIAN__ + bboxCenter.X = os::Byteswap::byteswap(bboxCenter.X); + bboxCenter.Y = os::Byteswap::byteswap(bboxCenter.Y); + bboxCenter.Z = os::Byteswap::byteswap(bboxCenter.Z); +#endif + bbox.addInternalPoint(bboxCenter); + bboxCenter=bbox.getCenter(); + data.read += 24; + } + break; + case C3DS_MORPH_SMOOTH: + { +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load morph smooth.", ELL_DEBUG); +#endif + f32 flag; + file->read(&flag, 4); +#ifdef __BIG_ENDIAN__ + flag = os::Byteswap::byteswap(flag); +#endif + data.read += 4; + } + break; + case C3DS_POS_TRACK_TAG: + case C3DS_ROT_TRACK_TAG: + case C3DS_SCL_TRACK_TAG: + readTrackChunk(file, data, mb, bboxCenter-pivot); + break; + default: + // ignore chunk + file->seek(data.header.length - data.read, true); + data.read += data.header.length - data.read; + } + + parent->read += data.read; + data.read=0; + } + + return true; +} + + +bool C3DSMeshFileLoader::readChunk(io::IReadFile* file, ChunkData* parent) +{ + while(parent->read < parent->header.length) + { + ChunkData data; + readChunkData(file, data); + + switch(data.header.id) + { + case C3DS_VERSION: + { + u16 version; + file->read(&version, sizeof(u16)); +#ifdef __BIG_ENDIAN__ + version = os::Byteswap::byteswap(version); +#endif + file->seek(data.header.length - data.read - 2, true); + data.read += data.header.length - data.read; + if (version != 0x03) + os::Printer::log("3ds file version is other than 3.", ELL_ERROR); + } + break; + case C3DS_EDIT_MATERIAL: + readMaterialChunk(file, &data); + break; + case C3DS_KEYF3DS: + readFrameChunk(file, &data); + break; + case C3DS_EDIT3DS: + break; + case C3DS_MESHVERSION: + case 0x01: + { + u32 version; + file->read(&version, sizeof(u32)); +#ifdef __BIG_ENDIAN__ + version = os::Byteswap::byteswap(version); +#endif + data.read += sizeof(u32); + } + break; + case C3DS_EDIT_OBJECT: + { + core::stringc name; + readString(file, data, name); + readObjectChunk(file, &data); + composeObject(file, name); + } + break; + + default: + // ignore chunk + file->seek(data.header.length - data.read, true); + data.read += data.header.length - data.read; + } + + parent->read += data.read; + } + + return true; +} + + +bool C3DSMeshFileLoader::readObjectChunk(io::IReadFile* file, ChunkData* parent) +{ +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load object chunk.", ELL_DEBUG); +#endif + while(parent->read < parent->header.length) + { + ChunkData data; + readChunkData(file, data); + + switch(data.header.id) + { + case C3DS_OBJTRIMESH: + readObjectChunk(file, &data); + break; + + case C3DS_TRIVERT: + readVertices(file, data); + break; + + case C3DS_POINTFLAGARRAY: + { + u16 numVertex, flags; + file->read(&numVertex, sizeof(u16)); +#ifdef __BIG_ENDIAN__ + numVertex= os::Byteswap::byteswap(numVertex); +#endif + for (u16 i=0; iread(&flags, sizeof(u16)); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + } + data.read += (numVertex+1)*sizeof(u16); + } + break; + + case C3DS_TRIFACE: + readIndices(file, data); + readObjectChunk(file, &data); // read smooth and material groups + break; + + case C3DS_TRIFACEMAT: + readMaterialGroup(file, data); + break; + + case C3DS_TRIUV: // getting texture coordinates + readTextureCoords(file, data); + break; + + case C3DS_TRIMATRIX: + { + f32 mat[4][3]; + file->read(&mat, 12*sizeof(f32)); + TransformationMatrix.makeIdentity(); + for (int i=0; i<4; ++i) + { + for (int j=0; j<3; ++j) + { +#ifdef __BIG_ENDIAN__ + TransformationMatrix(i,j)=os::Byteswap::byteswap(mat[i][j]); +#else + TransformationMatrix(i,j)=mat[i][j]; +#endif + } + } + data.read += 12*sizeof(f32); + } + break; + case C3DS_MESHCOLOR: + { + u8 flag; + file->read(&flag, sizeof(u8)); + ++data.read; + } + break; + case C3DS_TRISMOOTH: // TODO + { + SmoothingGroups = new u32[CountFaces]; + file->read(SmoothingGroups, CountFaces*sizeof(u32)); +#ifdef __BIG_ENDIAN__ + for (u16 i=0; iseek(data.header.length - data.read, true); + data.read += data.header.length - data.read; + } + + parent->read += data.read; + } + + return true; +} + + +void C3DSMeshFileLoader::composeObject(io::IReadFile* file, const core::stringc& name) +{ +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Compose object.", ELL_DEBUG); +#endif + if (Mesh->getMeshBufferCount() != Materials.size()) + loadMaterials(file); + + if (MaterialGroups.empty()) + { + // no material group, so add all + SMaterialGroup group; + group.faceCount = CountFaces; + group.faces = new u16[group.faceCount]; + for (u16 i=0; iaddMeshBuffer(mb); + mb->getMaterial() = Materials[0].Material; + mb->drop(); + // add an empty mesh buffer name + MeshBufferNames.push_back(""); + } + } + + for (u32 i=0; igetVideoDriver()->getMaximalPrimitiveCount(), (u32)((1<<16)-1))-3; // currently hardcoded s16 max value for index pointers + + // find mesh buffer for this group + for (mbPos=0; mbPosgetMeshBuffer(mbPos); + mat=&Materials[mbPos].Material; + MeshBufferNames[mbPos]=name; + break; + } + } + + if (mb != 0) + { + // add geometry to the buffer. + + video::S3DVertex vtx; + core::vector3df vec; + vtx.Color=mat->DiffuseColor; + if (mat->MaterialType==video::EMT_TRANSPARENT_VERTEX_ALPHA) + { + vtx.Color.setAlpha((int)(255.0f*mat->MaterialTypeParam)); + } + vtx.Normal.set(0,0,0); + + for (s32 f=0; fVertices.size(); + if (vtxCount>maxPrimitives) + { + IMeshBuffer* tmp = mb; + mb = new SMeshBuffer(); + Mesh->addMeshBuffer(mb); + mb->drop(); + Mesh->MeshBuffers[mbPos] = Mesh->MeshBuffers.getLast(); + Mesh->MeshBuffers[Mesh->MeshBuffers.size()-1] = tmp; + mb->getMaterial() = tmp->getMaterial(); + vtxCount=0; + } + + for (s32 v=0; v<3; ++v) + { + s32 idx = Indices[MaterialGroups[i].faces[f]*4 +v]; + + if (CountVertices > idx) + { + vtx.Pos.X = Vertices[idx*3 + 0]; + vtx.Pos.Z = Vertices[idx*3 + 1]; + vtx.Pos.Y = Vertices[idx*3 + 2]; +// TransformationMatrix.transformVect(vtx.Pos); + } + + if (CountTCoords > idx) + { + vtx.TCoords.X = TCoords[idx*2 + 0]; + vtx.TCoords.Y = 1.0f -TCoords[idx*2 + 1]; + } + + mb->Vertices.push_back(vtx); + } + + // compute normal + core::plane3d pl(mb->Vertices[vtxCount].Pos, mb->Vertices[vtxCount+2].Pos, + mb->Vertices[vtxCount+1].Pos); + + mb->Vertices[vtxCount].Normal = pl.Normal; + mb->Vertices[vtxCount+1].Normal = pl.Normal; + mb->Vertices[vtxCount+2].Normal = pl.Normal; + + // add indices + + mb->Indices.push_back(vtxCount); + mb->Indices.push_back(vtxCount+2); + mb->Indices.push_back(vtxCount+1); + } + } + else + os::Printer::log("Found no matching material for Group in 3ds file.", ELL_WARNING); + } + + cleanUp(); +} + + +void C3DSMeshFileLoader::loadMaterials(io::IReadFile* file) +{ + if (Materials.empty()) + os::Printer::log("No materials found in 3ds file.", ELL_INFORMATION); + + // create a mesh buffer for every material + MeshBufferNames.reallocate(Materials.size()); + for (u32 i=0; iaddMeshBuffer(m); + + m->getMaterial() = Materials[i].Material; + if (Materials[i].Filename[0].size()) + { + video::ITexture* texture = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture(Materials[i].Filename[0]) : NULL; + if (!texture) + { + os::Printer::log("Could not load a texture for entry in 3ds file", + Materials[i].Filename[0].c_str(), ELL_WARNING); + } + else + m->getMaterial().setTexture(0, texture); + } + + if (Materials[i].Filename[2].size()) + { + video::ITexture* texture = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture(Materials[i].Filename[2]) : NULL; + if (!texture) + { + os::Printer::log("Could not load a texture for entry in 3ds file", + Materials[i].Filename[2].c_str(), ELL_WARNING); + } + else + { + m->getMaterial().setTexture(0, texture); + m->getMaterial().MaterialType = video::EMT_TRANSPARENT_ADD_COLOR; + } + } + + if (Materials[i].Filename[3].size()) + { + video::ITexture* texture = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture(Materials[i].Filename[3]) : NULL; + if (!texture) + { + os::Printer::log("Could not load a texture for entry in 3ds file", + Materials[i].Filename[3].c_str(), ELL_WARNING); + } + else + { + m->getMaterial().setTexture(1, m->getMaterial().getTexture(0)); + m->getMaterial().setTexture(0, texture); + m->getMaterial().MaterialType = video::EMT_REFLECTION_2_LAYER; + } + } + + if (Materials[i].Filename[4].size()) + { + video::ITexture* texture = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture(Materials[i].Filename[4]) : NULL; + if (!texture) + { + os::Printer::log("Could not load a texture for entry in 3ds file", + Materials[i].Filename[4].c_str(), ELL_WARNING); + } + else + { + m->getMaterial().setTexture(1, texture); + SceneManager->getVideoDriver()->makeNormalMapTexture(texture, Materials[i].Strength[4]*10.f); + m->getMaterial().MaterialType=video::EMT_PARALLAX_MAP_SOLID; + m->getMaterial().MaterialTypeParam=.035f; + } + } + + m->drop(); + } +} + + +void C3DSMeshFileLoader::cleanUp() +{ + delete [] Vertices; + CountVertices = 0; + Vertices = 0; + delete [] Indices; + Indices = 0; + CountFaces = 0; + delete [] SmoothingGroups; + SmoothingGroups = 0; + delete [] TCoords; + TCoords = 0; + CountTCoords = 0; + + MaterialGroups.clear(); +} + + +void C3DSMeshFileLoader::readTextureCoords(io::IReadFile* file, ChunkData& data) +{ +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load texture coords.", ELL_DEBUG); +#endif + file->read(&CountTCoords, sizeof(CountTCoords)); +#ifdef __BIG_ENDIAN__ + CountTCoords = os::Byteswap::byteswap(CountTCoords); +#endif + data.read += sizeof(CountTCoords); + + s32 tcoordsBufferByteSize = CountTCoords * sizeof(f32) * 2; + + if (data.header.length - data.read != tcoordsBufferByteSize) + { + os::Printer::log("Invalid size of tcoords found in 3ds file.", ELL_WARNING); + return; + } + + TCoords = new f32[CountTCoords * 3]; + file->read(TCoords, tcoordsBufferByteSize); +#ifdef __BIG_ENDIAN__ + for (int i=0;iread(&group.faceCount, sizeof(group.faceCount)); +#ifdef __BIG_ENDIAN__ + group.faceCount = os::Byteswap::byteswap(group.faceCount); +#endif + data.read += sizeof(group.faceCount); + + // read faces + group.faces = new u16[group.faceCount]; + file->read(group.faces, sizeof(u16) * group.faceCount); +#ifdef __BIG_ENDIAN__ + for (u32 i=0;iread(&CountFaces, sizeof(CountFaces)); +#ifdef __BIG_ENDIAN__ + CountFaces = os::Byteswap::byteswap(CountFaces); +#endif + data.read += sizeof(CountFaces); + + s32 indexBufferByteSize = CountFaces * sizeof(u16) * 4; + + // Indices are u16s. + // After every 3 Indices in the array, there follows an edge flag. + Indices = new u16[CountFaces * 4]; + file->read(Indices, indexBufferByteSize); +#ifdef __BIG_ENDIAN__ + for (int i=0;iread(&CountVertices, sizeof(CountVertices)); +#ifdef __BIG_ENDIAN__ + CountVertices = os::Byteswap::byteswap(CountVertices); +#endif + data.read += sizeof(CountVertices); + + const s32 vertexBufferByteSize = CountVertices * sizeof(f32) * 3; + + if (data.header.length - data.read != vertexBufferByteSize) + { + os::Printer::log("Invalid size of vertices found in 3ds file", core::stringc(CountVertices), ELL_ERROR); + return; + } + + Vertices = new f32[CountVertices * 3]; + file->read(Vertices, vertexBufferByteSize); +#ifdef __BIG_ENDIAN__ + for (int i=0;iread(&data.header, sizeof(ChunkHeader)); +#ifdef __BIG_ENDIAN__ + data.header.id = os::Byteswap::byteswap(data.header.id); + data.header.length = os::Byteswap::byteswap(data.header.length); +#endif + data.read += sizeof(ChunkHeader); +} + + +void C3DSMeshFileLoader::readString(io::IReadFile* file, ChunkData& data, core::stringc& out) +{ + c8 c = 1; + out = ""; + + while (c) + { + file->read(&c, sizeof(c8)); + if (c) + out.append(c); + } + data.read+=out.size()+1; +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_3DS_LOADER_ + diff --git a/source/Irrlicht/C3DSMeshFileLoader.h b/source/Irrlicht/C3DSMeshFileLoader.h new file mode 100644 index 00000000..93bc437c --- /dev/null +++ b/source/Irrlicht/C3DSMeshFileLoader.h @@ -0,0 +1,166 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_3DS_MESH_FILE_LOADER_H_INCLUDED__ +#define __C_3DS_MESH_FILE_LOADER_H_INCLUDED__ + +#include "IMeshLoader.h" +#include "IFileSystem.h" +#include "ISceneManager.h" +#include "irrString.h" +#include "SMesh.h" +#include "matrix4.h" + +namespace irr +{ +namespace scene +{ + +//! Meshloader capable of loading 3ds meshes. +class C3DSMeshFileLoader : public IMeshLoader +{ +public: + + //! Constructor + C3DSMeshFileLoader(ISceneManager* smgr, io::IFileSystem* fs); + + //! destructor + virtual ~C3DSMeshFileLoader(); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".cob") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! creates/loads an animated mesh from the file. + //! \return Pointer to the created mesh. Returns 0 if loading failed. + //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). + //! See IReferenceCounted::drop() for more information. + virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_; + +private: + +// byte-align structures +#include "irrpack.h" + + struct ChunkHeader + { + u16 id; + s32 length; + } PACK_STRUCT; + +// Default alignment +#include "irrunpack.h" + + struct ChunkData + { + ChunkData() : read(0) {} + + ChunkHeader header; + s32 read; + }; + + struct SCurrentMaterial + { + void clear() { + Material=video::SMaterial(); + Name=""; + Filename[0]=""; + Filename[1]=""; + Filename[2]=""; + Filename[3]=""; + Filename[4]=""; + Strength[0]=0.f; + Strength[1]=0.f; + Strength[2]=0.f; + Strength[3]=0.f; + Strength[4]=0.f; + } + + video::SMaterial Material; + core::stringc Name; + core::stringc Filename[5]; + f32 Strength[5]; + }; + + struct SMaterialGroup + { + SMaterialGroup() : faceCount(0), faces(0) {}; + + SMaterialGroup(const SMaterialGroup& o) + { + *this = o; + } + + ~SMaterialGroup() + { + clear(); + } + + void clear() + { + delete [] faces; + faces = 0; + faceCount = 0; + } + + void operator =(const SMaterialGroup& o) + { + MaterialName = o.MaterialName; + faceCount = o.faceCount; + faces = new u16[faceCount]; + for (u16 i=0; i TempIndices; + f32* TCoords; + u16 CountVertices; + u16 CountFaces; // = CountIndices/4 + u16 CountTCoords; + core::array MaterialGroups; + + SCurrentMaterial CurrentMaterial; + core::array Materials; + core::array MeshBufferNames; + core::matrix4 TransformationMatrix; + + SMesh* Mesh; +}; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CAnimatedMeshHalfLife.cpp b/source/Irrlicht/CAnimatedMeshHalfLife.cpp new file mode 100644 index 00000000..f8abfa8e --- /dev/null +++ b/source/Irrlicht/CAnimatedMeshHalfLife.cpp @@ -0,0 +1,1679 @@ +// Copyright (C) 2002-2012 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 + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_HALFLIFE_LOADER_ + +#include "CAnimatedMeshHalfLife.h" +#include "os.h" +#include "CColorConverter.h" +#include "CImage.h" +#include "coreutil.h" +#include "SMeshBuffer.h" +#include "IVideoDriver.h" +#include "IFileSystem.h" + +namespace irr +{ +namespace scene +{ + + using namespace video; + + void AngleQuaternion(const core::vector3df& angles, vec4_hl quaternion) + { + // FIXME: rescale the inputs to 1/2 angle + double angle = angles.Z * 0.5; + + const double sy = sin(angle); + const double cy = cos(angle); + angle = angles.Y * 0.5; + const double sp = sin(angle); + const double cp = cos(angle); + angle = angles.X * 0.5; + const double sr = sin(angle); + const double cr = cos(angle); + + quaternion[0] = (irr::f32)(sr*cp*cy-cr*sp*sy); // X + quaternion[1] = (irr::f32)(cr*sp*cy+sr*cp*sy); // Y + quaternion[2] = (irr::f32)(cr*cp*sy-sr*sp*cy); // Z + quaternion[3] = (irr::f32)(cr*cp*cy+sr*sp*sy); // W + } + + void QuaternionMatrix( const vec4_hl quaternion, f32 (*matrix)[4] ) + { + matrix[0][0] = 1.f - 2.f * quaternion[1] * quaternion[1] - 2.f * quaternion[2] * quaternion[2]; + matrix[1][0] = 2.f * quaternion[0] * quaternion[1] + 2.f * quaternion[3] * quaternion[2]; + matrix[2][0] = 2.f * quaternion[0] * quaternion[2] - 2.f * quaternion[3] * quaternion[1]; + + matrix[0][1] = 2.f * quaternion[0] * quaternion[1] - 2.f * quaternion[3] * quaternion[2]; + matrix[1][1] = 1.f - 2.f * quaternion[0] * quaternion[0] - 2.f * quaternion[2] * quaternion[2]; + matrix[2][1] = 2.f * quaternion[1] * quaternion[2] + 2.f * quaternion[3] * quaternion[0]; + + matrix[0][2] = 2.f * quaternion[0] * quaternion[2] + 2.f * quaternion[3] * quaternion[1]; + matrix[1][2] = 2.f * quaternion[1] * quaternion[2] - 2.f * quaternion[3] * quaternion[0]; + matrix[2][2] = 1.f - 2.f * quaternion[0] * quaternion[0] - 2.f * quaternion[1] * quaternion[1]; + } + + void QuaternionSlerp( const vec4_hl p, vec4_hl q, f32 t, vec4_hl qt ) + { + // decide if one of the quaternions is backwards + f32 a = 0; + f32 b = 0; + for (s32 i = 0; i < 4; i++) { + a += (p[i]-q[i])*(p[i]-q[i]); + b += (p[i]+q[i])*(p[i]+q[i]); + } + if (a > b) { + for (s32 i = 0; i < 4; i++) { + q[i] = -q[i]; + } + } + + double sclp, sclq; + const double cosom = p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3]; + + if ((1.f + cosom) > 0.00000001) { + if ((1.f - cosom) > 0.00000001) { + const double omega = acos( cosom ); + const double sinom = sin( omega ); + sclp = sin( (1.f - t)*omega) / sinom; + sclq = sin( t*omega ) / sinom; + } + else { + sclp = 1.f - t; + sclq = t; + } + for (s32 i = 0; i < 4; i++) { + qt[i] = f32(sclp * p[i] + sclq * q[i]); + } + } + else { + qt[0] = -p[1]; + qt[1] = p[0]; + qt[2] = -p[3]; + qt[3] = p[2]; + sclp = sin( (1.f - t) * 0.5f * core::PI); + sclq = sin( t * 0.5f * core::PI); + for (s32 i = 0; i < 3; i++) { + qt[i] = f32(sclp * p[i] + sclq * qt[i]); + } + } + } + + void R_ConcatTransforms (const f32 in1[3][4], const f32 in2[3][4], f32 out[3][4]) + { + out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0]; + out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1]; + out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2]; + out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + in1[0][2] * in2[2][3] + in1[0][3]; + out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0]; + out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1]; + out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2]; + out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + in1[1][2] * in2[2][3] + in1[1][3]; + out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0]; + out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1]; + out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2]; + out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3]; + } + + #define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) + + inline void VectorTransform(const vec3_hl in1, const f32 in2[3][4], core::vector3df& out) + { + out.X = DotProduct(in1, in2[0]) + in2[0][3]; + out.Z = DotProduct(in1, in2[1]) + in2[1][3]; + out.Y = DotProduct(in1, in2[2]) + in2[2][3]; + } + + static f32 BoneTransform[MAXSTUDIOBONES][3][4]; // bone transformation matrix + + void getBoneVector ( core::vector3df &out, u32 index ) + { + out.X = BoneTransform[index][0][3]; + out.Z = BoneTransform[index][1][3]; + out.Y = BoneTransform[index][2][3]; + } + + void getBoneBox ( core::aabbox3df &box, u32 index, f32 size = 0.5f ) + { + box.MinEdge.X = BoneTransform[index][0][3] - size; + box.MinEdge.Z = BoneTransform[index][1][3] - size; + box.MinEdge.Y = BoneTransform[index][2][3] - size; + + size *= 2.f; + box.MaxEdge.X = box.MinEdge.X + size; + box.MaxEdge.Y = box.MinEdge.Y + size; + box.MaxEdge.Z = box.MinEdge.Z + size; + } + + void getTransformedBoneVector ( core::vector3df &out, u32 index, const vec3_hl in) + { + out.X = DotProduct(in, BoneTransform[index][0]) + BoneTransform[index][0][3]; + out.Z = DotProduct(in, BoneTransform[index][1]) + BoneTransform[index][1][3]; + out.Y = DotProduct(in, BoneTransform[index][2]) + BoneTransform[index][2][3]; + + } + + +//! Constructor +CHalflifeMDLMeshFileLoader::CHalflifeMDLMeshFileLoader( + scene::ISceneManager* smgr) : SceneManager(smgr) +{ +#ifdef _DEBUG + setDebugName("CHalflifeMDLMeshFileLoader"); +#endif +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool CHalflifeMDLMeshFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension(filename, "mdl"); +} + + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IReferenceCounted::drop() for more information. +IAnimatedMesh* CHalflifeMDLMeshFileLoader::createMesh(io::IReadFile* file) +{ + CAnimatedMeshHalfLife* msh = new CAnimatedMeshHalfLife(); + if (msh) + { + if (msh->loadModelFile(file, SceneManager)) + return msh; + msh->drop(); + } + + return 0; +} + + +//! Constructor +CAnimatedMeshHalfLife::CAnimatedMeshHalfLife() + : FrameCount(0), MeshIPol(0), SceneManager(0), Header(0), TextureHeader(0), + OwnTexModel(false), SequenceIndex(0), CurrentFrame(0), FramesPerSecond(25.f), + SkinGroupSelection(0) +#ifdef HL_TEXTURE_ATLAS +// , TextureMaster(0) +#endif +{ +#ifdef _DEBUG + setDebugName("CAnimatedMeshHalfLife"); +#endif + initData(); +} + +/*! + loads a complete model +*/ +bool CAnimatedMeshHalfLife::loadModelFile(io::IReadFile* file, + ISceneManager* smgr) +{ + if (!file) + return false; + + SceneManager = smgr; + + if ( loadModel(file, file->getFileName()) ) + { + if ( postLoadModel ( file->getFileName() ) ) + { + initModel (); + //dumpModelInfo ( 1 ); + return true; + } + } + return false; +} + + +//! Destructor +CAnimatedMeshHalfLife::~CAnimatedMeshHalfLife() +{ + delete [] (u8*) Header; + if (OwnTexModel) + delete [] (u8*) TextureHeader; + + for (u32 i = 0; i < 32; ++i) + delete [] (u8*) AnimationHeader[i]; + + if (MeshIPol) + MeshIPol->drop(); +} + + +//! Returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh. +u32 CAnimatedMeshHalfLife::getFrameCount() const +{ + return FrameCount; +} + + +//! set the hardware mapping hint, for driver +void CAnimatedMeshHalfLife::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint,E_BUFFER_TYPE buffer) +{ +} + + +//! flags the meshbuffer as changed, reloads hardware buffers +void CAnimatedMeshHalfLife::setDirty(E_BUFFER_TYPE buffer) +{ +} + + +static core::vector3df TransformedVerts[MAXSTUDIOVERTS]; // transformed vertices +//static core::vector3df TransformedNormals[MAXSTUDIOVERTS]; // light surface normals + + +/*! +*/ +void CAnimatedMeshHalfLife::initModel() +{ + // init Sequences to Animation + KeyFrameInterpolation ipol; + ipol.Name.reserve ( 64 ); + + AnimList.clear(); + FrameCount = 0; + + const SHalflifeSequence *seq = (SHalflifeSequence*) ((u8*) Header + Header->seqindex); + for (u32 i = 0; i < Header->numseq; i++) + { + ipol.Name = seq[i].label; + ipol.StartFrame = FrameCount; + ipol.Frames = core::max_ ( 1, seq[i].numframes - 1 ); + ipol.EndFrame = ipol.StartFrame + ipol.Frames - 1; + ipol.FramesPerSecond = seq[i].fps; + ipol.AnimationType = seq[i].flags & STUDIO_LOOPING ? EAMT_LOOPING : EAMT_WAYPOINT; + AnimList.push_back ( ipol ); + + FrameCount += ipol.Frames; + } + + // initBoneControllers +/* + SHalflifeBoneController *bonecontroller = (SHalflifeBoneController *)((u8*) Header + Header->bonecontrollerindex); + for ( i = 0; i < Header->numbonecontrollers; i++) + { + printf ( "BoneController%d index:%d%s range:%f - %f\n", + i, + bonecontroller[i].index, bonecontroller[i].index == MOUTH_CONTROLLER ? " (Mouth)": "", + bonecontroller[i].start,bonecontroller[i].end + ); + } + + // initSkins + for (i = 0; i < TextureHeader->numskinfamilies; i++) + { + printf ( "Skin%d\n", i + 1); + } +*/ + + // initBodyparts + u32 meshBuffer = 0; + BodyList.clear(); + const SHalflifeBody *body = (const SHalflifeBody *) ((u8*) Header + Header->bodypartindex); + for (u32 i=0; i < Header->numbodyparts; ++i) + { + BodyPart part; + part.name = body[i].name; + part.defaultModel = core::max_ ( 0, (s32) body[i].base - 1 ); + + const SHalflifeModel * model = (SHalflifeModel *)((u8*) Header + body[i].modelindex); + for ( u32 g = 0; g < body[i].nummodels; ++g) + { + SubModel sub; + sub.name = model[g].name; + sub.startBuffer = meshBuffer; + sub.endBuffer = sub.startBuffer + model[g].nummesh; + sub.state = g == part.defaultModel; + part.model.push_back ( sub ); + meshBuffer += model[g].nummesh; + } + BodyList.push_back ( part ); + } + + SequenceIndex = 0; + CurrentFrame = 0.f; + + SetController(0, 0.f); + SetController(1, 0.f); + SetController(2, 0.f); + SetController(3, 0.f); + SetController(MOUTH_CONTROLLER, 0.f); + + SetSkin (0); + + // init Meshbuffers + const SHalflifeTexture *tex = (SHalflifeTexture *) ((u8*) TextureHeader + TextureHeader->textureindex); + const u16 *skinref = (u16 *)((u8*)TextureHeader + TextureHeader->skinindex); + if ((SkinGroupSelection != 0) && (SkinGroupSelection < TextureHeader->numskinfamilies)) + skinref += (SkinGroupSelection * TextureHeader->numskinref); + + core::vector2df tex_scale; + core::vector2di tex_trans ( 0, 0 ); + +#ifdef HL_TEXTURE_ATLAS + TextureAtlas.getScale(tex_scale); +#endif + + for (u32 bodypart=0 ; bodypart < Header->numbodyparts ; ++bodypart) + { + body = (const SHalflifeBody *)((u8*) Header + Header->bodypartindex) + bodypart; + + for (u32 modelnr = 0; modelnr < body->nummodels; ++modelnr) + { + const SHalflifeModel *model = (SHalflifeModel *)((u8*) Header + body->modelindex) + modelnr; +#if 0 + const vec3_hl *studioverts = (vec3_hl *)((u8*)Header + model->vertindex); + const vec3_hl *studionorms = (vec3_hl *)((u8*)Header + model->normindex); +#endif + for (u32 i = 0; i < model->nummesh; ++i) + { + const SHalflifeMesh *mesh = (SHalflifeMesh *)((u8*)Header + model->meshindex) + i; + const SHalflifeTexture *currentex = &tex[skinref[mesh->skinref]]; + +#ifdef HL_TEXTURE_ATLAS + TextureAtlas.getTranslation ( currentex->name, tex_trans ); +#else + tex_scale.X = 1.f/(f32)currentex->width; + tex_scale.Y = 1.f/(f32)currentex->height; +#endif + + SMeshBuffer * buffer = new SMeshBuffer(); + + // count index vertex size indexcount = mesh->numtris * 3 + u32 indexCount = 0; + u32 vertexCount = 0; + + const s16 *tricmd = (s16*)((u8*)Header + mesh->triindex); + s32 c; + while ( (c = *(tricmd++)) ) + { + if (c < 0) + c = -c; + + indexCount += ( c - 2 ) * 3; + vertexCount += c; + tricmd += ( 4 * c ); + } + + // indices + buffer->Indices.set_used ( indexCount ); + buffer->Vertices.set_used ( vertexCount ); + + // fill in static indices and vertex + u16 *index = buffer->Indices.pointer(); + video::S3DVertex * v = buffer->Vertices.pointer(); + + // blow up gl_triangle_fan/gl_triangle_strip to indexed triangle list + E_PRIMITIVE_TYPE type; + vertexCount = 0; + indexCount = 0; + tricmd = (s16*)((u8*)Header + mesh->triindex); + while ( (c = *(tricmd++)) ) + { + if (c < 0) + { + // triangle fan + c = -c; + type = EPT_TRIANGLE_FAN; + } + else + { + type = EPT_TRIANGLE_STRIP; + } + + for ( s32 g = 0; g < c; ++g, v += 1, tricmd += 4 ) + { + // fill vertex + #if 0 + const f32 *av = studioverts[tricmd[0]]; + v->Pos.X = av[0]; + v->Pos.Z = av[1]; + v->Pos.Y = av[2]; + + av = studionorms[tricmd[1]]; + v->Normal.X = av[0]; + v->Normal.Z = av[1]; + v->Normal.Y = av[2]; + + #endif + v->Normal.X = 0.f; + v->Normal.Z = 0.f; + v->Normal.Y = 1.f; + + v->TCoords.X = (tex_trans.X + tricmd[2])*tex_scale.X; + v->TCoords.Y = (tex_trans.Y + tricmd[3])*tex_scale.Y; + + v->Color.color = 0xFFFFFFFF; + + // fill index + if ( g < c - 2 ) + { + if ( type == EPT_TRIANGLE_FAN ) + { + index[indexCount+0] = vertexCount; + index[indexCount+1] = vertexCount+g+1; + index[indexCount+2] = vertexCount+g+2; + } + else + { + if ( g & 1 ) + { + index[indexCount+0] = vertexCount+g+1; + index[indexCount+1] = vertexCount+g+0; + index[indexCount+2] = vertexCount+g+2; + } + else + { + index[indexCount+0] = vertexCount+g+0; + index[indexCount+1] = vertexCount+g+1; + index[indexCount+2] = vertexCount+g+2; + } + } + + indexCount += 3; + } + } + + vertexCount += c; + } + + // material + video::SMaterial &m = buffer->getMaterial(); + + m.MaterialType = video::EMT_SOLID; + m.BackfaceCulling = true; + + if ( currentex->flags & STUDIO_NF_CHROME ) + { + // don't know what to do with chrome here + } + +#ifdef HL_TEXTURE_ATLAS + io::path store = TextureBaseName + "atlas"; +#else + io::path fname; + io::path ext; + core::splitFilename ( currentex->name, 0, &fname, &ext ); + io::path store = TextureBaseName + fname; +#endif + m.TextureLayer[0].Texture = SceneManager->getVideoDriver()->getTexture ( store ); + m.Lighting = false; + + MeshIPol->addMeshBuffer(buffer); + buffer->recalculateBoundingBox(); + buffer->drop(); + } // mesh + MeshIPol->recalculateBoundingBox(); + } // model + } // body part +} + + +/*! +*/ +void CAnimatedMeshHalfLife::buildVertices() +{ +/* + const u16 *skinref = (u16 *)((u8*)TextureHeader + TextureHeader->skinindex); + if (SkinGroupSelection != 0 && SkinGroupSelection < TextureHeader->numskinfamilies) + skinref += (SkinGroupSelection * TextureHeader->numskinref); +*/ + u32 meshBufferNr = 0; + for ( u32 bodypart = 0 ; bodypart < Header->numbodyparts; ++bodypart) + { + const SHalflifeBody *body = (SHalflifeBody *)((u8*) Header + Header->bodypartindex) + bodypart; + + for ( u32 modelnr = 0; modelnr < body->nummodels; ++modelnr ) + { + const SHalflifeModel *model = (SHalflifeModel *)((u8*) Header + body->modelindex) + modelnr; + + const u8 *vertbone = ((u8*)Header + model->vertinfoindex); + + const vec3_hl *studioverts = (vec3_hl *)((u8*)Header + model->vertindex); + + for (u32 i = 0; i < model->numverts; i++) + { + VectorTransform ( studioverts[i], BoneTransform[vertbone[i]], TransformedVerts[i] ); + } + /* + const u8 *normbone = ((u8*)Header + model->norminfoindex); + const vec3_hl *studionorms = (vec3_hl *)((u8*)Header + model->normindex); + for ( i = 0; i < model->numnorms; i++) + { + VectorTransform ( studionorms[i], BoneTransform[normbone[i]], TransformedNormals[i] ); + } + */ + for (u32 i = 0; i < model->nummesh; i++) + { + const SHalflifeMesh *mesh = (SHalflifeMesh *)((u8*)Header + model->meshindex) + i; + + IMeshBuffer * buffer = MeshIPol->getMeshBuffer ( meshBufferNr++ ); + video::S3DVertex* v = (video::S3DVertex* ) buffer->getVertices(); + + const s16 *tricmd = (s16*)((u8*)Header + mesh->triindex); + s32 c = 0; + while ( (c = *(tricmd++)) ) + { + if (c < 0) + c = -c; + + for (s32 g = 0; g < c; ++g, v += 1, tricmd += 4 ) + { + // fill vertex + const core::vector3df& av = TransformedVerts[tricmd[0]]; + v->Pos = av; + /* + const core::vector3df& an = TransformedNormals[tricmd[1]]; + v->Normal = an; + //v->Normal.normalize(); + */ + } + } // tricmd + } // nummesh + } // model + } // bodypart +} + + +/*! + render Bones +*/ +void CAnimatedMeshHalfLife::renderModel(u32 param, IVideoDriver * driver, const core::matrix4 &absoluteTransformation) +{ + const SHalflifeBone *bone = (SHalflifeBone *) ((u8 *) Header + Header->boneindex); + + const video::SColor blue(0xFF000080); + const video::SColor red(0xFF800000); + const video::SColor yellow(0xFF808000); + const video::SColor cyan(0xFF008080); + + core::aabbox3df box; + + for (u32 i = 0; i < Header->numbones; i++) + { + if (bone[i].parent >= 0) + { + getBoneVector ( box.MinEdge, bone[i].parent ); + getBoneVector ( box.MaxEdge, i ); + driver->draw3DLine ( box.MinEdge, box.MaxEdge, blue ); + + // draw parent bone node + if (bone[bone[i].parent].parent >=0 ) + { + getBoneBox ( box, bone[i].parent ); + driver->draw3DBox ( box, blue ); + } + getBoneBox ( box, i ); + driver->draw3DBox ( box, blue ); + } + else + { + // draw parent bone node + getBoneBox ( box, i, 1.f ); + driver->draw3DBox ( box , red ); + } + } + + // attachements + const SHalflifeAttachment *attach = (SHalflifeAttachment *) ((u8*) Header + Header->attachmentindex); + core::vector3df v[8]; + for (u32 i = 0; i < Header->numattachments; i++) + { + getTransformedBoneVector ( v[0],attach[i].bone,attach[i].org ); + getTransformedBoneVector ( v[1],attach[i].bone,attach[i].vectors[0] ); + getTransformedBoneVector ( v[2],attach[i].bone,attach[i].vectors[1] ); + getTransformedBoneVector ( v[3],attach[i].bone,attach[i].vectors[2] ); + driver->draw3DLine ( v[0], v[1], cyan ); + driver->draw3DLine ( v[0], v[2], cyan ); + driver->draw3DLine ( v[0], v[3], cyan ); + } + + // hit boxes + SHalflifeBBox *hitbox = (SHalflifeBBox *) ((u8*) Header + Header->hitboxindex); + vec3_hl v2[8]; + for (u32 i = 0; i < Header->numhitboxes; i++) + { + f32 *bbmin = hitbox[i].bbmin; + f32 *bbmax = hitbox[i].bbmax; + + v2[0][0] = bbmin[0]; + v2[0][1] = bbmax[1]; + v2[0][2] = bbmin[2]; + + v2[1][0] = bbmin[0]; + v2[1][1] = bbmin[1]; + v2[1][2] = bbmin[2]; + + v2[2][0] = bbmax[0]; + v2[2][1] = bbmax[1]; + v2[2][2] = bbmin[2]; + + v2[3][0] = bbmax[0]; + v2[3][1] = bbmin[1]; + v2[3][2] = bbmin[2]; + + v2[4][0] = bbmax[0]; + v2[4][1] = bbmax[1]; + v2[4][2] = bbmax[2]; + + v2[5][0] = bbmax[0]; + v2[5][1] = bbmin[1]; + v2[5][2] = bbmax[2]; + + v2[6][0] = bbmin[0]; + v2[6][1] = bbmax[1]; + v2[6][2] = bbmax[2]; + + v2[7][0] = bbmin[0]; + v2[7][1] = bbmin[1]; + v2[7][2] = bbmax[2]; + + for ( u32 g = 0; g < 8; ++g ) + getTransformedBoneVector ( v[g],hitbox[i].bone,v2[g] ); + + driver->draw3DLine(v[0], v[1], yellow); + driver->draw3DLine(v[1], v[3], yellow); + driver->draw3DLine(v[3], v[2], yellow); + driver->draw3DLine(v[2], v[0], yellow); + + driver->draw3DLine(v[4], v[5], yellow); + driver->draw3DLine(v[5], v[7], yellow); + driver->draw3DLine(v[7], v[6], yellow); + driver->draw3DLine(v[6], v[4], yellow); + + driver->draw3DLine(v[0], v[6], yellow); + driver->draw3DLine(v[1], v[7], yellow); + driver->draw3DLine(v[3], v[5], yellow); + driver->draw3DLine(v[2], v[4], yellow); + } +} + + +//! Returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. +IMesh* CAnimatedMeshHalfLife::getMesh(s32 frameInt, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) +{ + const f32 frame = frameInt + (detailLevel * 0.001f); + const u32 frameA = core::floor32 ( frame ); +// f32 blend = core::fract ( frame ); + + SHalflifeSequence *seq = (SHalflifeSequence*) ((u8*) Header + Header->seqindex); + + // find SequenceIndex from summed list + u32 frameCount = 0; + for (u32 i = 0; i < Header->numseq; ++i) + { + const u32 val = core::max_ ( 1, seq[i].numframes - 1 ); + if ( frameCount + val > frameA ) + { + SequenceIndex = i; + CurrentFrame = frame - frameCount; + break; + } + frameCount += val; + } + + seq += SequenceIndex; + + //SetBodyPart ( 1, 1 ); + setUpBones (); + buildVertices(); + + MeshIPol->BoundingBox.MinEdge.X = seq->bbmin[0]; + MeshIPol->BoundingBox.MinEdge.Z = seq->bbmin[1]; + MeshIPol->BoundingBox.MinEdge.Y = seq->bbmin[2]; + + MeshIPol->BoundingBox.MaxEdge.X = seq->bbmax[0]; + MeshIPol->BoundingBox.MaxEdge.Z = seq->bbmax[1]; + MeshIPol->BoundingBox.MaxEdge.Y = seq->bbmax[2]; + + return MeshIPol; +} + + +/*! +*/ +void CAnimatedMeshHalfLife::initData () +{ + Header = 0; + TextureHeader = 0; + OwnTexModel = false; + + for (u32 i = 0; i < 32; ++i ) + AnimationHeader[i] = 0; + + SequenceIndex = 0; + CurrentFrame = 0.f; + + for (u32 i = 0; i < 5; ++i ) + BoneController[i] = 0; + + for (u32 i = 0; i < 2; ++i ) + Blending[i] = 0; + + SkinGroupSelection = 0; + + AnimList.clear(); + FrameCount = 0; + + if (!MeshIPol) + MeshIPol = new SMesh(); + MeshIPol->clear(); + +#ifdef HL_TEXTURE_ATLAS + TextureAtlas.release(); +#endif +} + + +/*! +*/ +void STextureAtlas::release() +{ + for (u32 i = 0; i < atlas.size(); i++) + { + if ( atlas[i].image ) + { + atlas[i].image->drop(); + atlas[i].image = 0; + } + } + Master = 0; +} + + +/*! +*/ +void STextureAtlas::addSource ( const c8 * name, video::IImage * image ) +{ + TextureAtlasEntry entry; + entry.name = name; + entry.image = image; + entry.width = image->getDimension().Width; + entry.height = image->getDimension().Height; + entry.pos.X = 0; + entry.pos.Y = 0; + atlas.push_back ( entry ); +} + + +/*! +*/ +void STextureAtlas::getScale(core::vector2df& scale) +{ + for (s32 i = static_cast(atlas.size()) - 1; i >= 0; --i) + { + if ( atlas[i].name == "_merged_" ) + { + scale.X = 1.f / atlas[i].width; + scale.Y = 1.f / atlas[i].height; + return; + } + } + scale.X = 1.f; + scale.Y = 1.f; +} + + +/*! +*/ +void STextureAtlas::getTranslation(const c8* name, core::vector2di& pos) +{ + for ( u32 i = 0; i < atlas.size(); ++i) + { + if ( atlas[i].name == name ) + { + pos = atlas[i].pos; + return; + } + } +} + + +/*! +*/ +void STextureAtlas::create(u32 border, E_TEXTURE_CLAMP texmode) +{ + u32 w = 0; + u32 w2; + u32 h2; + u32 h; + u32 wsum; + u32 hsum = 0; + ECOLOR_FORMAT format = ECF_R8G8B8; + + const s32 frame = core::s32_max ( 0, (border - 1 ) / 2 ); + + // sort for biggest coming first + atlas.sort(); + + // split size + wsum = frame; + for (u32 i = 0; i < atlas.size(); i++) + { + // make space + w2 = atlas[i].width + border; + + // align + w2 = (w2 + 1) & ~1; + wsum += w2; + } + u32 splitsize = 256; + if ( wsum > 512 ) + splitsize = 512; + + wsum = frame; + hsum = frame; + w = frame; + h = 0; + for (u32 i = 0; i < atlas.size(); i++) + { + if ( atlas[i].image->getColorFormat() == ECF_A8R8G8B8 ) + { + format = ECF_A8R8G8B8; + } + + // make space + w2 = atlas[i].width + border; + h2 = atlas[i].height + border; + + // align + w2 = (w2 + 1) & ~1; + h2 = (h2 + 1) & ~1; + + h = core::s32_max ( h, h2 ); + + if ( w + w2 >= splitsize ) + { + hsum += h; + wsum = core::s32_max ( wsum, w ); + h = h2; + w = frame; + } + + atlas[i].pos.X = w; + atlas[i].pos.Y = hsum; + + w += w2; + + } + hsum += h; + wsum = core::s32_max ( wsum, w ); + + // build image + const core::dimension2d dim = core::dimension2d( wsum, hsum ).getOptimalSize(); + IImage* master = new CImage(format, dim); + master->fill(0); + + video::SColor col[2]; + + static const u8 wrap[][4] = + { + {1, 0}, // ETC_REPEAT + {0, 1}, // ETC_CLAMP + {0, 1}, // ETC_CLAMP_TO_EDGE + {0, 1} // ETC_MIRROR + }; + + for (u32 i = 0; i < atlas.size(); i++) + { + atlas[i].image->copyTo ( master, atlas[i].pos ); + + // clamp/wrap ( copy edges, filtering needs it ) + + for (s32 b = 0; b < frame; ++b ) + { + for (s32 a = 0 - b; a <= (s32) atlas[i].width + b; ++a ) + { + col[0] = atlas[i].image->getPixel ( core::s32_clamp ( a, 0, atlas[i].width - 1 ), 0 ); + col[1] = atlas[i].image->getPixel ( core::s32_clamp ( a, 0, atlas[i].width - 1 ), atlas[i].height - 1 ); + + master->setPixel ( atlas[i].pos.X + a, atlas[i].pos.Y + ( b + 1 ) * -1, col[wrap[texmode][0]] ); + master->setPixel ( atlas[i].pos.X + a, atlas[i].pos.Y + atlas[i].height - 1 + ( b + 1 ) * 1, col[wrap[texmode][1]] ); + } + + for (s32 a = -1 - b; a <= (s32) atlas[i].height + b; ++a ) + { + col[0] = atlas[i].image->getPixel ( 0, core::s32_clamp ( a, 0, atlas[i].height - 1 ) ); + col[1] = atlas[i].image->getPixel ( atlas[i].width - 1, core::s32_clamp ( a, 0, atlas[i].height - 1 ) ); + + master->setPixel ( atlas[i].pos.X + ( b + 1 ) * -1, atlas[i].pos.Y + a, col[wrap[texmode][0]] ); + master->setPixel ( atlas[i].pos.X + atlas[i].width + b, atlas[i].pos.Y + a, col[wrap[texmode][1]] ); + } + } + } + + addSource ( "_merged_", master ); + Master = master; +} + + +/*! +*/ +SHalflifeHeader* CAnimatedMeshHalfLife::loadModel(io::IReadFile* file, const io::path& filename) +{ + bool closefile = false; + + // if secondary files are needed, open here and mark for closing + if ( 0 == file ) + { + file = SceneManager->getFileSystem()->createAndOpenFile(filename); + closefile = true; + } + + if ( 0 == file ) + return 0; + + // read into memory + u8* pin = new u8[file->getSize()]; + file->read(pin, file->getSize()); + + SHalflifeHeader* header = (SHalflifeHeader*) pin; + + const bool idst = (0 == strncmp(header->id, "IDST", 4)); + const bool idsq = (0 == strncmp(header->id, "IDSQ", 4)); + + if ( (!idst && !idsq) || (idsq && !Header) ) + { + os::Printer::log("MDL Halflife Loader: Wrong file header", file->getFileName(), ELL_WARNING); + if ( closefile ) + { + file->drop(); + file = 0; + } + delete [] pin; + return 0; + } + + // don't know the real header.. idsg might be different + if (header->textureindex && idst ) + { + io::path path; + io::path fname; + io::path ext; + + core::splitFilename(file->getFileName(), &path, &fname, &ext); + TextureBaseName = path + fname + "_"; + + const SHalflifeTexture *tex = (SHalflifeTexture *)(pin + header->textureindex); + u32 *palette = new u32[256]; + for (u32 i = 0; i < header->numtextures; ++i) + { + const u8 *src = pin + tex[i].index; + + // convert rgb to argb palette + { + const u8 *pal = src + tex[i].width * tex[i].height; + for( u32 g=0; g<256; ++g ) + { + palette[g] = 0xFF000000 | pal[0] << 16 | pal[1] << 8 | pal[2]; + pal += 3; + } + } + + IImage* image = SceneManager->getVideoDriver()->createImage(ECF_R8G8B8, core::dimension2d(tex[i].width, tex[i].height)); + + CColorConverter::convert8BitTo24Bit(src, (u8*)image->getData(), tex[i].width, tex[i].height, (u8*) palette, 0, false); + +#ifdef HL_TEXTURE_ATLAS + TextureAtlas.addSource ( tex[i].name, image ); +#else + core::splitFilename ( tex[i].name, 0, &fname, &ext ); + SceneManager->getVideoDriver()->addTexture ( TextureBaseName + fname, image ); + image->drop(); +#endif + } + delete [] palette; + +#ifdef HL_TEXTURE_ATLAS + TextureAtlas.create ( 2 * 2 + 1, ETC_CLAMP ); + SceneManager->getVideoDriver()->addTexture ( TextureBaseName + "atlas", TextureAtlas.Master ); + TextureAtlas.release(); +#endif + } + + if (!Header) + Header = header; + + if ( closefile ) + { + file->drop(); + file = 0; + } + + return header; +} + + +/*! +*/ +f32 CAnimatedMeshHalfLife::SetController( s32 controllerIndex, f32 value ) +{ + if (!Header) + return 0.f; + + SHalflifeBoneController *bonecontroller = (SHalflifeBoneController *)((u8*) Header + Header->bonecontrollerindex); + + // find first controller that matches the index + u32 i; + for (i = 0; i < Header->numbonecontrollers; i++, bonecontroller++) + { + if (bonecontroller->index == controllerIndex) + break; + } + if (i >= Header->numbonecontrollers) + return value; + + // wrap 0..360 if it's a rotational controller + if (bonecontroller->type & (STUDIO_XR | STUDIO_YR | STUDIO_ZR)) + { + // ugly hack, invert value if end < start + if (bonecontroller->end < bonecontroller->start) + value = -value; + + // does the controller not wrap? + if (bonecontroller->start + 359.f >= bonecontroller->end) + { + if (value > ((bonecontroller->start + bonecontroller->end) / 2.f) + 180.f) + value = value - 360.f; + if (value < ((bonecontroller->start + bonecontroller->end) / 2.f) - 180.f) + value = value + 360.f; + } + else + { + if (value > 360.f) + value = value - (s32)(value / 360.f) * 360.f; + else if (value < 0.f) + value = value + (s32)((value / -360.f) + 1) * 360.f; + } + } + + const s32 range = controllerIndex == MOUTH_CONTROLLER ? 64 : 255; + + s32 setting = (s32) ( (f32) range * (value - bonecontroller->start) / (bonecontroller->end - bonecontroller->start)); + + if (setting < 0) setting = 0; + if (setting > range) setting = range; + + BoneController[controllerIndex] = setting; + + return setting * (1.f / (f32) range ) * (bonecontroller->end - bonecontroller->start) + bonecontroller->start; +} + + +/*! +*/ +u32 CAnimatedMeshHalfLife::SetSkin( u32 value ) +{ + if (value < Header->numskinfamilies) + SkinGroupSelection = value; + + return SkinGroupSelection; +} + + +/*! +*/ +bool CAnimatedMeshHalfLife::postLoadModel( const io::path &filename ) +{ + io::path path; + io::path texname; + io::path submodel; + + core::splitFilename ( filename ,&path, &texname, 0 ); + + // preload textures + // if no textures are stored in main file, use texfile + if (Header->numtextures == 0) + { + submodel = path + texname + "T.mdl"; + TextureHeader = loadModel(0, submodel); + if (!TextureHeader) + return false; + OwnTexModel = true; + } + else + { + TextureHeader = Header; + OwnTexModel = false; + } + + // preload animations + if (Header->numseqgroups > 1) + { + c8 seq[8]; + for (u32 i = 1; i < Header->numseqgroups; i++) + { + snprintf_irr( seq, 8, "%02u.mdl", i ); + submodel = path + texname + seq; + + AnimationHeader[i] = loadModel(0, submodel); + if (!AnimationHeader[i]) + return false; + } + } + + return true; +} + + +/*! +*/ +void CAnimatedMeshHalfLife::dumpModelInfo(u32 level) const +{ + const u8 *phdr = (const u8*) Header; + const SHalflifeHeader * hdr = Header; + + if (level == 0) + { + printf ( + "Bones: %u\n" + "Bone Controllers: %u\n" + "Hit Boxes: %u\n" + "Sequences: %u\n" + "Sequence Groups: %u\n", + hdr->numbones, + hdr->numbonecontrollers, + hdr->numhitboxes, + hdr->numseq, + hdr->numseqgroups + ); + printf ( + "Textures: %u\n" + "Skin Families: %u\n" + "Bodyparts: %u\n" + "Attachments: %u\n" + "Transitions: %d\n", + hdr->numtextures, + hdr->numskinfamilies, + hdr->numbodyparts, + hdr->numattachments, + hdr->numtransitions); + return; + } + + printf("id: %c%c%c%c\n", phdr[0], phdr[1], phdr[2], phdr[3]); + printf("version: %d\n", hdr->version); + printf("name: \"%s\"\n", hdr->name); + printf("length: %d\n\n", hdr->length); + + printf("eyeposition: %f %f %f\n", hdr->eyeposition[0], hdr->eyeposition[1], hdr->eyeposition[2]); + printf("min: %f %f %f\n", hdr->min[0], hdr->min[1], hdr->min[2]); + printf("max: %f %f %f\n", hdr->max[0], hdr->max[1], hdr->max[2]); + printf("bbmin: %f %f %f\n", hdr->bbmin[0], hdr->bbmin[1], hdr->bbmin[2]); + printf("bbmax: %f %f %f\n", hdr->bbmax[0], hdr->bbmax[1], hdr->bbmax[2]); + + printf("flags: %d\n\n", hdr->flags); + + printf("numbones: %u\n", hdr->numbones); + for (u32 i = 0; i < hdr->numbones; i++) + { + const SHalflifeBone *bone = (const SHalflifeBone *) (phdr + hdr->boneindex); + printf("bone %u.name: \"%s\"\n", i + 1, bone[i].name); + printf("bone %u.parent: %d\n", i + 1, bone[i].parent); + printf("bone %u.flags: %d\n", i + 1, bone[i].flags); + printf("bone %u.bonecontroller: %d %d %d %d %d %d\n", i + 1, bone[i].bonecontroller[0], bone[i].bonecontroller[1], bone[i].bonecontroller[2], bone[i].bonecontroller[3], bone[i].bonecontroller[4], bone[i].bonecontroller[5]); + printf("bone %u.value: %f %f %f %f %f %f\n", i + 1, bone[i].value[0], bone[i].value[1], bone[i].value[2], bone[i].value[3], bone[i].value[4], bone[i].value[5]); + printf("bone %u.scale: %f %f %f %f %f %f\n", i + 1, bone[i].scale[0], bone[i].scale[1], bone[i].scale[2], bone[i].scale[3], bone[i].scale[4], bone[i].scale[5]); + } + + printf("\nnumbonecontrollers: %u\n", hdr->numbonecontrollers); + const SHalflifeBoneController *bonecontrollers = (const SHalflifeBoneController *) (phdr + hdr->bonecontrollerindex); + for (u32 i = 0; i < hdr->numbonecontrollers; i++) + { + printf("bonecontroller %u.bone: %d\n", i + 1, bonecontrollers[i].bone); + printf("bonecontroller %u.type: %d\n", i + 1, bonecontrollers[i].type); + printf("bonecontroller %u.start: %f\n", i + 1, bonecontrollers[i].start); + printf("bonecontroller %u.end: %f\n", i + 1, bonecontrollers[i].end); + printf("bonecontroller %u.rest: %d\n", i + 1, bonecontrollers[i].rest); + printf("bonecontroller %u.index: %d\n", i + 1, bonecontrollers[i].index); + } + + printf("\nnumhitboxes: %u\n", hdr->numhitboxes); + const SHalflifeBBox *box = (const SHalflifeBBox *) (phdr + hdr->hitboxindex); + for (u32 i = 0; i < hdr->numhitboxes; i++) + { + printf("hitbox %u.bone: %d\n", i + 1, box[i].bone); + printf("hitbox %u.group: %d\n", i + 1, box[i].group); + printf("hitbox %u.bbmin: %f %f %f\n", i + 1, box[i].bbmin[0], box[i].bbmin[1], box[i].bbmin[2]); + printf("hitbox %u.bbmax: %f %f %f\n", i + 1, box[i].bbmax[0], box[i].bbmax[1], box[i].bbmax[2]); + } + + printf("\nnumseq: %u\n", hdr->numseq); + const SHalflifeSequence *seq = (const SHalflifeSequence *) (phdr + hdr->seqindex); + for (u32 i = 0; i < hdr->numseq; i++) + { + printf("seqdesc %u.label: \"%s\"\n", i + 1, seq[i].label); + printf("seqdesc %u.fps: %f\n", i + 1, seq[i].fps); + printf("seqdesc %u.flags: %d\n", i + 1, seq[i].flags); + printf("<...>\n"); + } + + printf("\nnumseqgroups: %u\n", hdr->numseqgroups); + for (u32 i = 0; i < hdr->numseqgroups; i++) + { + const SHalflifeSequenceGroup *group = (const SHalflifeSequenceGroup *) (phdr + hdr->seqgroupindex); + printf("\nseqgroup %u.label: \"%s\"\n", i + 1, group[i].label); + printf("\nseqgroup %u.namel: \"%s\"\n", i + 1, group[i].name); + printf("\nseqgroup %u.data: %d\n", i + 1, group[i].data); + } + + printf("\nnumskinref: %u\n", hdr->numskinref); + printf("numskinfamilies: %u\n", hdr->numskinfamilies); + + printf("\nnumbodyparts: %u\n", hdr->numbodyparts); + const SHalflifeBody *pbodyparts = (const SHalflifeBody*) ((const u8*) hdr + hdr->bodypartindex); + for (u32 i = 0; i < hdr->numbodyparts; i++) + { + printf("bodypart %u.name: \"%s\"\n", i + 1, pbodyparts[i].name); + printf("bodypart %u.nummodels: %u\n", i + 1, pbodyparts[i].nummodels); + printf("bodypart %u.base: %u\n", i + 1, pbodyparts[i].base); + printf("bodypart %u.modelindex: %u\n", i + 1, pbodyparts[i].modelindex); + } + + printf("\nnumattachments: %u\n", hdr->numattachments); + for (u32 i = 0; i < hdr->numattachments; i++) + { + const SHalflifeAttachment *attach = (const SHalflifeAttachment *) ((const u8*) hdr + hdr->attachmentindex); + printf("attachment %u.name: \"%s\"\n", i + 1, attach[i].name); + } + + hdr = TextureHeader; + printf("\nnumtextures: %u\n", hdr->numtextures); + printf("textureindex: %u\n", hdr->textureindex); + printf("texturedataindex: %u\n", hdr->texturedataindex); + const SHalflifeTexture *ptextures = (const SHalflifeTexture *) ((const u8*) hdr + hdr->textureindex); + for (u32 i = 0; i < hdr->numtextures; i++) + { + printf("texture %u.name: \"%s\"\n", i + 1, ptextures[i].name); + printf("texture %u.flags: %d\n", i + 1, ptextures[i].flags); + printf("texture %u.width: %d\n", i + 1, ptextures[i].width); + printf("texture %u.height: %d\n", i + 1, ptextures[i].height); + printf("texture %u.index: %d\n", i + 1, ptextures[i].index); + } +} + + +/*! +*/ +void CAnimatedMeshHalfLife::ExtractBbox(s32 sequence, core::aabbox3df &box) const +{ + const SHalflifeSequence *seq = (const SHalflifeSequence *)((const u8*)Header + Header->seqindex) + sequence; + + box.MinEdge.X = seq[0].bbmin[0]; + box.MinEdge.Y = seq[0].bbmin[1]; + box.MinEdge.Z = seq[0].bbmin[2]; + + box.MaxEdge.X = seq[0].bbmax[0]; + box.MaxEdge.Y = seq[0].bbmax[1]; + box.MaxEdge.Z = seq[0].bbmax[2]; +} + + +/*! +*/ +void CAnimatedMeshHalfLife::calcBoneAdj() +{ + const SHalflifeBoneController *bonecontroller = + (const SHalflifeBoneController *)((const u8*) Header + Header->bonecontrollerindex); + + for (u32 j = 0; j < Header->numbonecontrollers; j++) + { + const s32 i = bonecontroller[j].index; + // check for 360% wrapping + f32 value; + if (bonecontroller[j].type & STUDIO_RLOOP) + { + value = BoneController[i] * (360.f/256.f) + bonecontroller[j].start; + } + else + { + const f32 range = i <= 3 ? 255.f : 64.f; + value = core::clamp(BoneController[i] / range,0.f,1.f); + value = (1.f - value) * bonecontroller[j].start + value * bonecontroller[j].end; + } + + switch(bonecontroller[j].type & STUDIO_TYPES) + { + case STUDIO_XR: + case STUDIO_YR: + case STUDIO_ZR: + BoneAdj[j] = value * core::DEGTORAD; + break; + case STUDIO_X: + case STUDIO_Y: + case STUDIO_Z: + BoneAdj[j] = value; + break; + } + } +} + + +/*! +*/ +void CAnimatedMeshHalfLife::calcBoneQuaternion(const s32 frame, const SHalflifeBone * const bone, + SHalflifeAnimOffset *anim, const u32 j, f32& angle1, f32& angle2) const +{ + // three vector components + if (anim->offset[j+3] == 0) + { + angle2 = angle1 = bone->value[j+3]; // default + } + else + { + SHalflifeAnimationFrame *animvalue = (SHalflifeAnimationFrame *)((u8*)anim + anim->offset[j+3]); + s32 k = frame; + while (animvalue->num.total <= k) + { + k -= animvalue->num.total; + animvalue += animvalue->num.valid + 1; + } + // Bah, missing blend! + if (animvalue->num.valid > k) + { + angle1 = animvalue[k+1].value; + + if (animvalue->num.valid > k + 1) + { + angle2 = animvalue[k+2].value; + } + else + { + if (animvalue->num.total > k + 1) + angle2 = angle1; + else + angle2 = animvalue[animvalue->num.valid+2].value; + } + } + else + { + angle1 = animvalue[animvalue->num.valid].value; + if (animvalue->num.total > k + 1) + { + angle2 = angle1; + } + else + { + angle2 = animvalue[animvalue->num.valid + 2].value; + } + } + angle1 = bone->value[j+3] + angle1 * bone->scale[j+3]; + angle2 = bone->value[j+3] + angle2 * bone->scale[j+3]; + } + + if (bone->bonecontroller[j+3] != -1) + { + angle1 += BoneAdj[bone->bonecontroller[j+3]]; + angle2 += BoneAdj[bone->bonecontroller[j+3]]; + } +} + + +/*! +*/ +void CAnimatedMeshHalfLife::calcBonePosition(const s32 frame, f32 s, + const SHalflifeBone * const bone, SHalflifeAnimOffset *anim, f32 *pos) const +{ + for (s32 j = 0; j < 3; ++j) + { + pos[j] = bone->value[j]; // default; + if (anim->offset[j] != 0) + { + SHalflifeAnimationFrame *animvalue = (SHalflifeAnimationFrame *)((u8*)anim + anim->offset[j]); + + s32 k = frame; + // find span of values that includes the frame we want + while (animvalue->num.total <= k) + { + k -= animvalue->num.total; + animvalue += animvalue->num.valid + 1; + } + // if we're inside the span + if (animvalue->num.valid > k) + { + // and there's more data in the span + if (animvalue->num.valid > k + 1) + { + pos[j] += (animvalue[k+1].value * (1.f - s) + s * animvalue[k+2].value) * bone->scale[j]; + } + else + { + pos[j] += animvalue[k+1].value * bone->scale[j]; + } + } + else + { + // are we at the end of the repeating values section and there's another section with data? + if (animvalue->num.total <= k + 1) + { + pos[j] += (animvalue[animvalue->num.valid].value * (1.f - s) + s * animvalue[animvalue->num.valid + 2].value) * bone->scale[j]; + } + else + { + pos[j] += animvalue[animvalue->num.valid].value * bone->scale[j]; + } + } + } + if (bone->bonecontroller[j] != -1) + { + pos[j] += BoneAdj[bone->bonecontroller[j]]; + } + } +} + + +/*! +*/ +void CAnimatedMeshHalfLife::calcRotations(vec3_hl *pos, vec4_hl *q, + SHalflifeSequence *seq, SHalflifeAnimOffset *anim, f32 f) +{ + const s32 frame = (s32)f; + const f32 s = (f - frame); + + // add in programatic controllers + calcBoneAdj(); + + SHalflifeBone *bone = (SHalflifeBone *)((u8 *)Header + Header->boneindex); + for ( u32 i = 0; i < Header->numbones; i++, bone++, anim++) + { + core::vector3df angle1, angle2; + calcBoneQuaternion(frame, bone, anim, 0, angle1.X, angle2.X); + calcBoneQuaternion(frame, bone, anim, 1, angle1.Y, angle2.Y); + calcBoneQuaternion(frame, bone, anim, 2, angle1.Z, angle2.Z); + + if (!angle1.equals(angle2)) + { + vec4_hl q1, q2; + AngleQuaternion( angle1, q1 ); + AngleQuaternion( angle2, q2 ); + QuaternionSlerp( q1, q2, s, q[i] ); + } + else + { + AngleQuaternion( angle1, q[i] ); + } + + calcBonePosition(frame, s, bone, anim, pos[i]); + } + + if (seq->motiontype & STUDIO_X) + pos[seq->motionbone][0] = 0.f; + if (seq->motiontype & STUDIO_Y) + pos[seq->motionbone][1] = 0.f; + if (seq->motiontype & STUDIO_Z) + pos[seq->motionbone][2] = 0.f; +} + + +/*! +*/ +SHalflifeAnimOffset * CAnimatedMeshHalfLife::getAnim( SHalflifeSequence *seq ) +{ + SHalflifeSequenceGroup *seqgroup = (SHalflifeSequenceGroup *)((u8*)Header + Header->seqgroupindex) + seq->seqgroup; + + if (seq->seqgroup == 0) + { + return (SHalflifeAnimOffset *)((u8*)Header + seqgroup->data + seq->animindex); + } + + return (SHalflifeAnimOffset *)((u8*)AnimationHeader[seq->seqgroup] + seq->animindex); +} + + +/*! +*/ +void CAnimatedMeshHalfLife::slerpBones(vec4_hl q1[], vec3_hl pos1[], vec4_hl q2[], vec3_hl pos2[], f32 s) +{ + if (s < 0) + s = 0; + else if (s > 1.f) + s = 1.f; + + f32 s1 = 1.f - s; + + for ( u32 i = 0; i < Header->numbones; i++) + { + vec4_hl q3; + QuaternionSlerp( q1[i], q2[i], s, q3 ); + q1[i][0] = q3[0]; + q1[i][1] = q3[1]; + q1[i][2] = q3[2]; + q1[i][3] = q3[3]; + pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s; + pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s; + pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s; + } +} + + +/*! +*/ +void CAnimatedMeshHalfLife::setUpBones() +{ + static vec3_hl pos[MAXSTUDIOBONES]; + f32 bonematrix[3][4]; + static vec4_hl q[MAXSTUDIOBONES]; + + static vec3_hl pos2[MAXSTUDIOBONES]; + static vec4_hl q2[MAXSTUDIOBONES]; + static vec3_hl pos3[MAXSTUDIOBONES]; + static vec4_hl q3[MAXSTUDIOBONES]; + static vec3_hl pos4[MAXSTUDIOBONES]; + static vec4_hl q4[MAXSTUDIOBONES]; + + if (SequenceIndex >= Header->numseq) + SequenceIndex = 0; + + SHalflifeSequence *seq = (SHalflifeSequence *)((u8*) Header + Header->seqindex) + SequenceIndex; + + SHalflifeAnimOffset *anim = getAnim(seq); + calcRotations(pos, q, seq, anim, CurrentFrame); + + if (seq->numblends > 1) + { + anim += Header->numbones; + calcRotations( pos2, q2, seq, anim, CurrentFrame ); + f32 s = Blending[0] / 255.f; + + slerpBones( q, pos, q2, pos2, s ); + + if (seq->numblends == 4) + { + anim += Header->numbones; + calcRotations( pos3, q3, seq, anim, CurrentFrame ); + + anim += Header->numbones; + calcRotations( pos4, q4, seq, anim, CurrentFrame ); + + s = Blending[0] / 255.f; + slerpBones( q3, pos3, q4, pos4, s ); + + s = Blending[1] / 255.f; + slerpBones( q, pos, q3, pos3, s ); + } + } + + const SHalflifeBone *bone = (SHalflifeBone *)((u8*) Header + Header->boneindex); + + for (u32 i = 0; i < Header->numbones; i++) + { + QuaternionMatrix( q[i], bonematrix ); + + bonematrix[0][3] = pos[i][0]; + bonematrix[1][3] = pos[i][1]; + bonematrix[2][3] = pos[i][2]; + + if (bone[i].parent == -1) { + memcpy(BoneTransform[i], bonematrix, sizeof(f32) * 12); + } + else { + R_ConcatTransforms (BoneTransform[bone[i].parent], bonematrix, BoneTransform[i]); + } + } +} + + +//! Returns an axis aligned bounding box +const core::aabbox3d& CAnimatedMeshHalfLife::getBoundingBox() const +{ + return MeshIPol->BoundingBox; +} + + +//! Returns the type of the animated mesh. +E_ANIMATED_MESH_TYPE CAnimatedMeshHalfLife::getMeshType() const +{ + return EAMT_MDL_HALFLIFE; +} + + +//! returns amount of mesh buffers. +u32 CAnimatedMeshHalfLife::getMeshBufferCount() const +{ + return MeshIPol->getMeshBufferCount(); +} + + +//! returns pointer to a mesh buffer +IMeshBuffer* CAnimatedMeshHalfLife::getMeshBuffer(u32 nr) const +{ + return MeshIPol->getMeshBuffer(nr); +} + + +//! Returns pointer to a mesh buffer which fits a material +/** \param material: material to search for +\return Returns the pointer to the mesh buffer or +NULL if there is no such mesh buffer. */ +IMeshBuffer* CAnimatedMeshHalfLife::getMeshBuffer(const video::SMaterial &material) const +{ + return MeshIPol->getMeshBuffer(material); +} + + +void CAnimatedMeshHalfLife::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) +{ + MeshIPol->setMaterialFlag ( flag, newvalue ); +} + + +//! set user axis aligned bounding box +void CAnimatedMeshHalfLife::setBoundingBox(const core::aabbox3df& box) +{ + MeshIPol->setBoundingBox(box); +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_MD3_LOADER_ + diff --git a/source/Irrlicht/CAnimatedMeshHalfLife.h b/source/Irrlicht/CAnimatedMeshHalfLife.h new file mode 100644 index 00000000..19c14c00 --- /dev/null +++ b/source/Irrlicht/CAnimatedMeshHalfLife.h @@ -0,0 +1,630 @@ +// Copyright (C) 2002-2012 Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_ANIMATED_MESH_HALFLIFE_H_INCLUDED__ +#define __C_ANIMATED_MESH_HALFLIFE_H_INCLUDED__ + +#include "IAnimatedMesh.h" +#include "ISceneManager.h" +#include "irrArray.h" +#include "irrString.h" +#include "IMeshLoader.h" +#include "SMesh.h" +#include "IReadFile.h" + +namespace irr +{ +namespace scene +{ + + + // STUDIO MODELS, Copyright (c) 1998, Valve LLC. All rights reserved. + #define MAXSTUDIOTRIANGLES 20000 // TODO: tune this + #define MAXSTUDIOVERTS 2048 // TODO: tune this + #define MAXSTUDIOSEQUENCES 256 // total animation sequences + #define MAXSTUDIOSKINS 100 // total textures + #define MAXSTUDIOSRCBONES 512 // bones allowed at source movement + #define MAXSTUDIOBONES 128 // total bones actually used + #define MAXSTUDIOMODELS 32 // sub-models per model + #define MAXSTUDIOBODYPARTS 32 + #define MAXSTUDIOGROUPS 4 + #define MAXSTUDIOANIMATIONS 512 // per sequence + #define MAXSTUDIOMESHES 256 + #define MAXSTUDIOEVENTS 1024 + #define MAXSTUDIOPIVOTS 256 + #define MAXSTUDIOCONTROLLERS 8 + + typedef f32 vec3_hl[3]; // x,y,z + typedef f32 vec4_hl[4]; // x,y,z,w + +// byte-align structures +#include "irrpack.h" + + struct SHalflifeHeader + { + c8 id[4]; + s32 version; + + c8 name[64]; + s32 length; + + vec3_hl eyeposition; // ideal eye position + vec3_hl min; // ideal movement hull size + vec3_hl max; + + vec3_hl bbmin; // clipping bounding box + vec3_hl bbmax; + + s32 flags; + + u32 numbones; // bones + u32 boneindex; + + u32 numbonecontrollers; // bone controllers + u32 bonecontrollerindex; + + u32 numhitboxes; // complex bounding boxes + u32 hitboxindex; + + u32 numseq; // animation sequences + u32 seqindex; + + u32 numseqgroups; // demand loaded sequences + u32 seqgroupindex; + + u32 numtextures; // raw textures + u32 textureindex; + u32 texturedataindex; + + u32 numskinref; // replaceable textures + u32 numskinfamilies; + u32 skinindex; + + u32 numbodyparts; + u32 bodypartindex; + + u32 numattachments; // queryable attachable points + u32 attachmentindex; + + s32 soundtable; + s32 soundindex; + s32 soundgroups; + s32 soundgroupindex; + + s32 numtransitions; // animation node to animation node transition graph + s32 transitionindex; + } PACK_STRUCT; + + // header for demand loaded sequence group data + struct studioseqhdr_t + { + s32 id; + s32 version; + + c8 name[64]; + s32 length; + } PACK_STRUCT; + + // bones + struct SHalflifeBone + { + c8 name[32]; // bone name for symbolic links + s32 parent; // parent bone + s32 flags; // ?? + s32 bonecontroller[6]; // bone controller index, -1 == none + f32 value[6]; // default DoF values + f32 scale[6]; // scale for delta DoF values + } PACK_STRUCT; + + + // bone controllers + struct SHalflifeBoneController + { + s32 bone; // -1 == 0 + s32 type; // X, Y, Z, XR, YR, ZR, M + f32 start; + f32 end; + s32 rest; // byte index value at rest + s32 index; // 0-3 user set controller, 4 mouth + } PACK_STRUCT; + + // intersection boxes + struct SHalflifeBBox + { + s32 bone; + s32 group; // intersection group + vec3_hl bbmin; // bounding box + vec3_hl bbmax; + } PACK_STRUCT; + +#ifndef ZONE_H + // NOTE: this was a void*, but that crashes on 64bit. + // I have found no mdl format desc, so not sure what it's meant to be, but s32 at least works. + typedef s32 cache_user_t; +#endif + + // demand loaded sequence groups + struct SHalflifeSequenceGroup + { + c8 label[32]; // textual name + c8 name[64]; // file name + cache_user_t cache; // cache index pointer + s32 data; // hack for group 0 + } PACK_STRUCT; + + // sequence descriptions + struct SHalflifeSequence + { + c8 label[32]; // sequence label + + f32 fps; // frames per second + s32 flags; // looping/non-looping flags + + s32 activity; + s32 actweight; + + s32 numevents; + s32 eventindex; + + s32 numframes; // number of frames per sequence + + u32 numpivots; // number of foot pivots + u32 pivotindex; + + s32 motiontype; + s32 motionbone; + vec3_hl linearmovement; + s32 automoveposindex; + s32 automoveangleindex; + + vec3_hl bbmin; // per sequence bounding box + vec3_hl bbmax; + + s32 numblends; + s32 animindex; // SHalflifeAnimOffset pointer relative to start of sequence group data + // [blend][bone][X, Y, Z, XR, YR, ZR] + + s32 blendtype[2]; // X, Y, Z, XR, YR, ZR + f32 blendstart[2]; // starting value + f32 blendend[2]; // ending value + s32 blendparent; + + s32 seqgroup; // sequence group for demand loading + + s32 entrynode; // transition node at entry + s32 exitnode; // transition node at exit + s32 nodeflags; // transition rules + + s32 nextseq; // auto advancing sequences + } PACK_STRUCT; + + // events + struct mstudioevent_t + { + s32 frame; + s32 event; + s32 type; + c8 options[64]; + } PACK_STRUCT; + + + // pivots + struct mstudiopivot_t + { + vec3_hl org; // pivot point + s32 start; + s32 end; + } PACK_STRUCT; + + // attachment + struct SHalflifeAttachment + { + c8 name[32]; + s32 type; + s32 bone; + vec3_hl org; // attachment point + vec3_hl vectors[3]; + } PACK_STRUCT; + + struct SHalflifeAnimOffset + { + u16 offset[6]; + } PACK_STRUCT; + + // animation frames + union SHalflifeAnimationFrame + { + struct { + u8 valid; + u8 total; + } PACK_STRUCT num; + s16 value; + } PACK_STRUCT; + + + // body part index + struct SHalflifeBody + { + c8 name[64]; + u32 nummodels; + u32 base; + u32 modelindex; // index into models array + } PACK_STRUCT; + + + // skin info + struct SHalflifeTexture + { + c8 name[64]; + s32 flags; + s32 width; + s32 height; + s32 index; + } PACK_STRUCT; + + + // skin families + // short index[skinfamilies][skinref] + + // studio models + struct SHalflifeModel + { + c8 name[64]; + s32 type; + + f32 boundingradius; + + u32 nummesh; + u32 meshindex; + + u32 numverts; // number of unique vertices + u32 vertinfoindex; // vertex bone info + u32 vertindex; // vertex vec3_hl + u32 numnorms; // number of unique surface normals + u32 norminfoindex; // normal bone info + u32 normindex; // normal vec3_hl + + u32 numgroups; // deformation groups + u32 groupindex; + } PACK_STRUCT; + + + // meshes + struct SHalflifeMesh + { + u32 numtris; + u32 triindex; + u32 skinref; + u32 numnorms; // per mesh normals + u32 normindex; // normal vec3_hl + } PACK_STRUCT; + +// Default alignment +#include "irrunpack.h" + + // lighting options + #define STUDIO_NF_FLATSHADE 0x0001 + #define STUDIO_NF_CHROME 0x0002 + #define STUDIO_NF_FULLBRIGHT 0x0004 + + // motion flags + #define STUDIO_X 0x0001 + #define STUDIO_Y 0x0002 + #define STUDIO_Z 0x0004 + #define STUDIO_XR 0x0008 + #define STUDIO_YR 0x0010 + #define STUDIO_ZR 0x0020 + #define STUDIO_LX 0x0040 + #define STUDIO_LY 0x0080 + #define STUDIO_LZ 0x0100 + #define STUDIO_AX 0x0200 + #define STUDIO_AY 0x0400 + #define STUDIO_AZ 0x0800 + #define STUDIO_AXR 0x1000 + #define STUDIO_AYR 0x2000 + #define STUDIO_AZR 0x4000 + #define STUDIO_TYPES 0x7FFF + #define STUDIO_RLOOP 0x8000 // controller that wraps shortest distance + + // sequence flags + #define STUDIO_LOOPING 0x0001 + + // bone flags + #define STUDIO_HAS_NORMALS 0x0001 + #define STUDIO_HAS_VERTICES 0x0002 + #define STUDIO_HAS_BBOX 0x0004 + #define STUDIO_HAS_CHROME 0x0008 // if any of the textures have chrome on them + + #define RAD_TO_STUDIO (32768.0/M_PI) + #define STUDIO_TO_RAD (M_PI/32768.0) + + /*! + Textureatlas + Combine Source Images with arbitrary size and bithdepth to an Image with 2^n size + borders from the source images are copied around for allowing filtering ( bilinear, mipmap ) + */ + struct STextureAtlas + { + STextureAtlas () + { + release(); + } + + virtual ~STextureAtlas () + { + release (); + } + + void release (); + void addSource ( const c8 * name, video::IImage * image ); + void create ( u32 pixelborder, video::E_TEXTURE_CLAMP texmode ); + void getScale ( core::vector2df &scale ); + void getTranslation ( const c8 * name, core::vector2di &pos ); + + struct TextureAtlasEntry + { + io::path name; + u32 width; + u32 height; + + core::vector2di pos; + + video::IImage * image; + + bool operator < ( const TextureAtlasEntry & other ) + { + return height > other.height; + } + }; + + + core::array < TextureAtlasEntry > atlas; + video::IImage * Master; + }; + + + //! Possible types of Animation Type + enum E_ANIMATION_TYPE + { + //! No Animation + EAMT_STILL, + //! From Start to End, then Stop ( Limited Line ) + EAMT_WAYPOINT, + //! Linear Cycling Animation ( Sawtooth ) + EAMT_LOOPING, + //! Linear bobbing ( Triangle ) + EAMT_PINGPONG + }; + + //! Names for Animation Type + const c8* const MeshAnimationTypeNames[] = + { + "still", + "waypoint", + "looping", + "pingpong", + 0 + }; + + + //! Data for holding named Animation Info + struct KeyFrameInterpolation + { + core::stringc Name; // Name of the current Animation/Bone + E_ANIMATION_TYPE AnimationType; // Type of Animation ( looping, usw..) + + f32 CurrentFrame; // Current Frame + s32 NextFrame; // Frame which will be used next. For blending + + s32 StartFrame; // Absolute Frame where the current animation start + s32 Frames; // Relative Frames how much Frames this animation have + s32 LoopingFrames; // How much of Frames sould be looped + s32 EndFrame; // Absolute Frame where the current animation ends End = start + frames - 1 + + f32 FramesPerSecond; // Speed in Frames/Seconds the animation is played + f32 RelativeSpeed; // Factor Original fps is modified + + u32 BeginTime; // Animation started at this thime + u32 EndTime; // Animation end at this time + u32 LastTime; // Last Keyframe was done at this time + + KeyFrameInterpolation ( const c8 * name = "", s32 start = 0, s32 frames = 0, s32 loopingframes = 0, + f32 fps = 0.f, f32 relativefps = 1.f ) + : Name ( name ), AnimationType ( loopingframes ? EAMT_LOOPING : EAMT_WAYPOINT), + CurrentFrame ( (f32) start ), NextFrame ( start ), StartFrame ( start ), + Frames ( frames ), LoopingFrames ( loopingframes ), EndFrame ( start + frames - 1 ), + FramesPerSecond ( fps ), RelativeSpeed ( relativefps ), + BeginTime ( 0 ), EndTime ( 0 ), LastTime ( 0 ) + { + } + + // linear search + bool operator == ( const KeyFrameInterpolation & other ) const + { + return Name.equals_ignore_case ( other.Name ); + } + + }; + + + //! a List holding named Animations + typedef core::array < KeyFrameInterpolation > IAnimationList; + + //! a List holding named Skins + typedef core::array < core::stringc > ISkinList; + + + // Current Model per Body + struct SubModel + { + core::stringc name; + u32 startBuffer; + u32 endBuffer; + u32 state; + }; + + struct BodyPart + { + core::stringc name; + u32 defaultModel; + core::array < SubModel > model; + }; + //! a List holding named Models and SubModels + typedef core::array < BodyPart > IBodyList; + + + class CAnimatedMeshHalfLife : public IAnimatedMesh + { + public: + + //! constructor + CAnimatedMeshHalfLife(); + + //! destructor + virtual ~CAnimatedMeshHalfLife(); + + //! loads a Halflife mdl file + bool loadModelFile( io::IReadFile* file, ISceneManager * smgr ); + + //IAnimatedMesh + virtual u32 getFrameCount() const _IRR_OVERRIDE_; + virtual IMesh* getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) _IRR_OVERRIDE_; + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + virtual E_ANIMATED_MESH_TYPE getMeshType() const _IRR_OVERRIDE_; + void renderModel ( u32 param, video::IVideoDriver * driver, const core::matrix4 &absoluteTransformation); + + //! returns amount of mesh buffers. + virtual u32 getMeshBufferCount() const _IRR_OVERRIDE_; + //! returns pointer to a mesh buffer + virtual IMeshBuffer* getMeshBuffer(u32 nr) const _IRR_OVERRIDE_; + //! Returns pointer to a mesh buffer which fits a material + virtual IMeshBuffer* getMeshBuffer( const video::SMaterial &material) const _IRR_OVERRIDE_; + + virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) _IRR_OVERRIDE_; + + //! set the hardware mapping hint, for driver + virtual void setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_; + + //! flags the meshbuffer as changed, reloads hardware buffers + virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_; + + //! set user axis aligned bounding box + virtual void setBoundingBox(const core::aabbox3df& box) _IRR_OVERRIDE_; + + //! Gets the default animation speed of the animated mesh. + /** \return Amount of frames per second. If the amount is 0, it is a static, non animated mesh. */ + virtual f32 getAnimationSpeed() const _IRR_OVERRIDE_ + { + return FramesPerSecond; + } + + //! Gets the frame count of the animated mesh. + /** \param fps Frames per second to play the animation with. If the amount is 0, it is not animated. + The actual speed is set in the scene node the mesh is instantiated in.*/ + virtual void setAnimationSpeed(f32 fps) _IRR_OVERRIDE_ + { + FramesPerSecond=fps; + } + + //! Get the Animation List + IAnimationList* getAnimList () { return &AnimList; } + + //! Return the named Body List of this Animated Mesh + IBodyList *getBodyList() { return &BodyList; } + + private: + + // KeyFrame Animation List + IAnimationList AnimList; + // Sum of all sequences + u32 FrameCount; + + // Named meshes of the Body + IBodyList BodyList; + + //! return a Mesh per frame + SMesh* MeshIPol; + + ISceneManager *SceneManager; + + SHalflifeHeader *Header; + SHalflifeHeader *TextureHeader; + bool OwnTexModel; // do we have a modelT.mdl ? + SHalflifeHeader *AnimationHeader[32]; // sequences named model01.mdl, model02.mdl + + void initData (); + SHalflifeHeader * loadModel( io::IReadFile* file, const io::path &filename ); + bool postLoadModel( const io::path &filename ); + + u32 SequenceIndex; // sequence index + f32 CurrentFrame; // Current Frame + f32 FramesPerSecond; + + #define MOUTH_CONTROLLER 4 + u8 BoneController[4 + 1 ]; // bone controllers + mouth position + u8 Blending[2]; // animation blending + + vec4_hl BoneAdj; + f32 SetController( s32 controllerIndex, f32 value ); + + u32 SkinGroupSelection; // skin group selection + u32 SetSkin( u32 value ); + + void initModel(); + void dumpModelInfo(u32 level) const; + + void ExtractBbox(s32 sequence, core::aabbox3df &box) const; + + void setUpBones (); + SHalflifeAnimOffset * getAnim( SHalflifeSequence *seq ); + void slerpBones( vec4_hl q1[], vec3_hl pos1[], vec4_hl q2[], vec3_hl pos2[], f32 s ); + void calcRotations ( vec3_hl *pos, vec4_hl *q, SHalflifeSequence *seq, SHalflifeAnimOffset *anim, f32 f ); + + void calcBoneAdj(); + void calcBoneQuaternion(const s32 frame, const SHalflifeBone *bone, SHalflifeAnimOffset *anim, const u32 j, f32& angle1, f32& angle2) const; + void calcBonePosition(const s32 frame, f32 s, const SHalflifeBone *bone, SHalflifeAnimOffset *anim, f32 *pos ) const; + + void buildVertices (); + + io::path TextureBaseName; + +#define HL_TEXTURE_ATLAS + +#ifdef HL_TEXTURE_ATLAS + STextureAtlas TextureAtlas; +// video::ITexture *TextureMaster; +#endif + + }; + + + //! Meshloader capable of loading HalfLife Model files + class CHalflifeMDLMeshFileLoader : public IMeshLoader + { + public: + + //! Constructor + CHalflifeMDLMeshFileLoader( scene::ISceneManager* smgr ); + + //! returns true if the file maybe is able to be loaded by this class + /** based on the file extension (e.g. ".bsp") */ + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! creates/loads an animated mesh from the file. + /** \return Pointer to the created mesh. Returns 0 if loading failed. + If you no longer need the mesh, you should call IAnimatedMesh::drop(). + See IReferenceCounted::drop() for more information. + */ + virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_; + + private: + scene::ISceneManager* SceneManager; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CAnimatedMeshMD2.cpp b/source/Irrlicht/CAnimatedMeshMD2.cpp new file mode 100644 index 00000000..b97417ae --- /dev/null +++ b/source/Irrlicht/CAnimatedMeshMD2.cpp @@ -0,0 +1,465 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_MD2_LOADER_ + +#include "CAnimatedMeshMD2.h" +#include "SColor.h" +#include "irrMath.h" + +namespace irr +{ +namespace scene +{ + +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; + +static const f32 Q2_VERTEX_NORMAL_TABLE[Q2_VERTEX_NORMAL_TABLE_SIZE][3] = { + {-0.525731f, 0.000000f, 0.850651f}, + {-0.442863f, 0.238856f, 0.864188f}, + {-0.295242f, 0.000000f, 0.955423f}, + {-0.309017f, 0.500000f, 0.809017f}, + {-0.162460f, 0.262866f, 0.951056f}, + {0.000000f, 0.000000f, 1.000000f}, + {0.000000f, 0.850651f, 0.525731f}, + {-0.147621f, 0.716567f, 0.681718f}, + {0.147621f, 0.716567f, 0.681718f}, + {0.000000f, 0.525731f, 0.850651f}, + {0.309017f, 0.500000f, 0.809017f}, + {0.525731f, 0.000000f, 0.850651f}, + {0.295242f, 0.000000f, 0.955423f}, + {0.442863f, 0.238856f, 0.864188f}, + {0.162460f, 0.262866f, 0.951056f}, + {-0.681718f, 0.147621f, 0.716567f}, + {-0.809017f, 0.309017f, 0.500000f}, + {-0.587785f, 0.425325f, 0.688191f}, + {-0.850651f, 0.525731f, 0.000000f}, + {-0.864188f, 0.442863f, 0.238856f}, + {-0.716567f, 0.681718f, 0.147621f}, + {-0.688191f, 0.587785f, 0.425325f}, + {-0.500000f, 0.809017f, 0.309017f}, + {-0.238856f, 0.864188f, 0.442863f}, + {-0.425325f, 0.688191f, 0.587785f}, + {-0.716567f, 0.681718f, -0.147621f}, + {-0.500000f, 0.809017f, -0.309017f}, + {-0.525731f, 0.850651f, 0.000000f}, + {0.000000f, 0.850651f, -0.525731f}, + {-0.238856f, 0.864188f, -0.442863f}, + {0.000000f, 0.955423f, -0.295242f}, + {-0.262866f, 0.951056f, -0.162460f}, + {0.000000f, 1.000000f, 0.000000f}, + {0.000000f, 0.955423f, 0.295242f}, + {-0.262866f, 0.951056f, 0.162460f}, + {0.238856f, 0.864188f, 0.442863f}, + {0.262866f, 0.951056f, 0.162460f}, + {0.500000f, 0.809017f, 0.309017f}, + {0.238856f, 0.864188f, -0.442863f}, + {0.262866f, 0.951056f, -0.162460f}, + {0.500000f, 0.809017f, -0.309017f}, + {0.850651f, 0.525731f, 0.000000f}, + {0.716567f, 0.681718f, 0.147621f}, + {0.716567f, 0.681718f, -0.147621f}, + {0.525731f, 0.850651f, 0.000000f}, + {0.425325f, 0.688191f, 0.587785f}, + {0.864188f, 0.442863f, 0.238856f}, + {0.688191f, 0.587785f, 0.425325f}, + {0.809017f, 0.309017f, 0.500000f}, + {0.681718f, 0.147621f, 0.716567f}, + {0.587785f, 0.425325f, 0.688191f}, + {0.955423f, 0.295242f, 0.000000f}, + {1.000000f, 0.000000f, 0.000000f}, + {0.951056f, 0.162460f, 0.262866f}, + {0.850651f, -0.525731f, 0.000000f}, + {0.955423f, -0.295242f, 0.000000f}, + {0.864188f, -0.442863f, 0.238856f}, + {0.951056f, -0.162460f, 0.262866f}, + {0.809017f, -0.309017f, 0.500000f}, + {0.681718f, -0.147621f, 0.716567f}, + {0.850651f, 0.000000f, 0.525731f}, + {0.864188f, 0.442863f, -0.238856f}, + {0.809017f, 0.309017f, -0.500000f}, + {0.951056f, 0.162460f, -0.262866f}, + {0.525731f, 0.000000f, -0.850651f}, + {0.681718f, 0.147621f, -0.716567f}, + {0.681718f, -0.147621f, -0.716567f}, + {0.850651f, 0.000000f, -0.525731f}, + {0.809017f, -0.309017f, -0.500000f}, + {0.864188f, -0.442863f, -0.238856f}, + {0.951056f, -0.162460f, -0.262866f}, + {0.147621f, 0.716567f, -0.681718f}, + {0.309017f, 0.500000f, -0.809017f}, + {0.425325f, 0.688191f, -0.587785f}, + {0.442863f, 0.238856f, -0.864188f}, + {0.587785f, 0.425325f, -0.688191f}, + {0.688191f, 0.587785f, -0.425325f}, + {-0.147621f, 0.716567f, -0.681718f}, + {-0.309017f, 0.500000f, -0.809017f}, + {0.000000f, 0.525731f, -0.850651f}, + {-0.525731f, 0.000000f, -0.850651f}, + {-0.442863f, 0.238856f, -0.864188f}, + {-0.295242f, 0.000000f, -0.955423f}, + {-0.162460f, 0.262866f, -0.951056f}, + {0.000000f, 0.000000f, -1.000000f}, + {0.295242f, 0.000000f, -0.955423f}, + {0.162460f, 0.262866f, -0.951056f}, + {-0.442863f, -0.238856f, -0.864188f}, + {-0.309017f, -0.500000f, -0.809017f}, + {-0.162460f, -0.262866f, -0.951056f}, + {0.000000f, -0.850651f, -0.525731f}, + {-0.147621f, -0.716567f, -0.681718f}, + {0.147621f, -0.716567f, -0.681718f}, + {0.000000f, -0.525731f, -0.850651f}, + {0.309017f, -0.500000f, -0.809017f}, + {0.442863f, -0.238856f, -0.864188f}, + {0.162460f, -0.262866f, -0.951056f}, + {0.238856f, -0.864188f, -0.442863f}, + {0.500000f, -0.809017f, -0.309017f}, + {0.425325f, -0.688191f, -0.587785f}, + {0.716567f, -0.681718f, -0.147621f}, + {0.688191f, -0.587785f, -0.425325f}, + {0.587785f, -0.425325f, -0.688191f}, + {0.000000f, -0.955423f, -0.295242f}, + {0.000000f, -1.000000f, 0.000000f}, + {0.262866f, -0.951056f, -0.162460f}, + {0.000000f, -0.850651f, 0.525731f}, + {0.000000f, -0.955423f, 0.295242f}, + {0.238856f, -0.864188f, 0.442863f}, + {0.262866f, -0.951056f, 0.162460f}, + {0.500000f, -0.809017f, 0.309017f}, + {0.716567f, -0.681718f, 0.147621f}, + {0.525731f, -0.850651f, 0.000000f}, + {-0.238856f, -0.864188f, -0.442863f}, + {-0.500000f, -0.809017f, -0.309017f}, + {-0.262866f, -0.951056f, -0.162460f}, + {-0.850651f, -0.525731f, 0.000000f}, + {-0.716567f, -0.681718f, -0.147621f}, + {-0.716567f, -0.681718f, 0.147621f}, + {-0.525731f, -0.850651f, 0.000000f}, + {-0.500000f, -0.809017f, 0.309017f}, + {-0.238856f, -0.864188f, 0.442863f}, + {-0.262866f, -0.951056f, 0.162460f}, + {-0.864188f, -0.442863f, 0.238856f}, + {-0.809017f, -0.309017f, 0.500000f}, + {-0.688191f, -0.587785f, 0.425325f}, + {-0.681718f, -0.147621f, 0.716567f}, + {-0.442863f, -0.238856f, 0.864188f}, + {-0.587785f, -0.425325f, 0.688191f}, + {-0.309017f, -0.500000f, 0.809017f}, + {-0.147621f, -0.716567f, 0.681718f}, + {-0.425325f, -0.688191f, 0.587785f}, + {-0.162460f, -0.262866f, 0.951056f}, + {0.442863f, -0.238856f, 0.864188f}, + {0.162460f, -0.262866f, 0.951056f}, + {0.309017f, -0.500000f, 0.809017f}, + {0.147621f, -0.716567f, 0.681718f}, + {0.000000f, -0.525731f, 0.850651f}, + {0.425325f, -0.688191f, 0.587785f}, + {0.587785f, -0.425325f, 0.688191f}, + {0.688191f, -0.587785f, 0.425325f}, + {-0.955423f, 0.295242f, 0.000000f}, + {-0.951056f, 0.162460f, 0.262866f}, + {-1.000000f, 0.000000f, 0.000000f}, + {-0.850651f, 0.000000f, 0.525731f}, + {-0.955423f, -0.295242f, 0.000000f}, + {-0.951056f, -0.162460f, 0.262866f}, + {-0.864188f, 0.442863f, -0.238856f}, + {-0.951056f, 0.162460f, -0.262866f}, + {-0.809017f, 0.309017f, -0.500000f}, + {-0.864188f, -0.442863f, -0.238856f}, + {-0.951056f, -0.162460f, -0.262866f}, + {-0.809017f, -0.309017f, -0.500000f}, + {-0.681718f, 0.147621f, -0.716567f}, + {-0.681718f, -0.147621f, -0.716567f}, + {-0.850651f, 0.000000f, -0.525731f}, + {-0.688191f, 0.587785f, -0.425325f}, + {-0.587785f, 0.425325f, -0.688191f}, + {-0.425325f, 0.688191f, -0.587785f}, + {-0.425325f, -0.688191f, -0.587785f}, + {-0.587785f, -0.425325f, -0.688191f}, + {-0.688191f, -0.587785f, -0.425325f}, + }; + +struct SMD2AnimationType +{ + s32 begin; + s32 end; + s32 fps; +}; + +static const SMD2AnimationType MD2AnimationTypeList[21] = +{ + { 0, 39, 9}, // STAND + { 40, 45, 10}, // RUN + { 46, 53, 10}, // ATTACK + { 54, 57, 7}, // PAIN_A + { 58, 61, 7}, // PAIN_B + { 62, 65, 7}, // PAIN_C + { 66, 71, 7}, // JUMP + { 72, 83, 7}, // FLIP + { 84, 94, 7}, // SALUTE + { 95, 111, 10}, // FALLBACK + {112, 122, 7}, // WAVE + {123, 134, 6}, // POINT + {135, 153, 10}, // CROUCH_STAND + {154, 159, 7}, // CROUCH_WALK + {160, 168, 10}, // CROUCH_ATTACK + {169, 172, 7}, // CROUCH_PAIN + {173, 177, 5}, // CROUCH_DEATH + {178, 183, 7}, // DEATH_FALLBACK + {184, 189, 7}, // DEATH_FALLFORWARD + {190, 197, 7}, // DEATH_FALLBACKSLOW + {198, 198, 5}, // BOOM +}; + + +//! constructor +CAnimatedMeshMD2::CAnimatedMeshMD2() + : InterpolationBuffer(0), InterpolationFirstFrame(-1), InterpolationSecondFrame(-1), InterpolationFrameDiv(0.f) + , FrameList(0), FrameCount(0), FramesPerSecond((f32)(MD2AnimationTypeList[0].fps << MD2_FRAME_SHIFT)) +{ + #ifdef _DEBUG + IAnimatedMesh::setDebugName("CAnimatedMeshMD2 IAnimatedMesh"); + IMesh::setDebugName("CAnimatedMeshMD2 IMesh"); + #endif + InterpolationBuffer = new SMeshBuffer; +} + + +//! destructor +CAnimatedMeshMD2::~CAnimatedMeshMD2() +{ + delete [] FrameList; + if (InterpolationBuffer) + 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 +{ + return FrameCount< getFrameCount()) + frame = (frame % getFrameCount()); + + if (startFrameLoop == -1 && endFrameLoop == -1) + { + startFrameLoop = 0; + endFrameLoop = getFrameCount(); + } + + updateInterpolationBuffer(frame, startFrameLoop, endFrameLoop); + return this; +} + + +//! returns amount of mesh buffers. MD2 meshes only have one buffer +u32 CAnimatedMeshMD2::getMeshBufferCount() const +{ + return 1; +} + + +//! returns pointer to a mesh buffer +IMeshBuffer* CAnimatedMeshMD2::getMeshBuffer(u32 nr) const +{ + if (nr == 0) + return InterpolationBuffer; + else + return 0; +} + + +//! Returns pointer to a mesh buffer which fits a material +IMeshBuffer* CAnimatedMeshMD2::getMeshBuffer(const video::SMaterial &material) const +{ + if (InterpolationBuffer->Material == material) + return InterpolationBuffer; + else + return 0; +} + + +// updates the interpolation buffer +void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop, s32 endFrameLoop) +{ + u32 firstFrame, secondFrame; + f32 div; + + // TA: resolve missing ipol in loop between end-start + + if (endFrameLoop - startFrameLoop == 0) + { + firstFrame = frame>>MD2_FRAME_SHIFT; + secondFrame = frame>>MD2_FRAME_SHIFT; + div = 1.0f; + } + else + { + // key frames + u32 s = startFrameLoop >> MD2_FRAME_SHIFT; + u32 e = endFrameLoop >> MD2_FRAME_SHIFT; + + firstFrame = frame >> MD2_FRAME_SHIFT; + secondFrame = core::if_c_a_else_b(firstFrame + 1 > e, s, firstFrame + 1); + + firstFrame = core::s32_min(FrameCount - 1, firstFrame); + secondFrame = core::s32_min(FrameCount - 1, secondFrame); + + //div = (frame % (1<(InterpolationBuffer->getVertices()); + SMD2Vert* first = FrameList[firstFrame].pointer(); + SMD2Vert* second = FrameList[secondFrame].pointer(); + + // interpolate both frames + const u32 count = FrameList[firstFrame].size(); + for (u32 i=0; iPos.X) * FrameTransforms[firstFrame].scale.X + FrameTransforms[firstFrame].translate.X, + f32(first->Pos.Y) * FrameTransforms[firstFrame].scale.Y + FrameTransforms[firstFrame].translate.Y, + f32(first->Pos.Z) * FrameTransforms[firstFrame].scale.Z + FrameTransforms[firstFrame].translate.Z); + const core::vector3df two = core::vector3df(f32(second->Pos.X) * FrameTransforms[secondFrame].scale.X + FrameTransforms[secondFrame].translate.X, + f32(second->Pos.Y) * FrameTransforms[secondFrame].scale.Y + FrameTransforms[secondFrame].translate.Y, + f32(second->Pos.Z) * FrameTransforms[secondFrame].scale.Z + FrameTransforms[secondFrame].translate.Z); + target->Pos = two.getInterpolated(one, div); + const core::vector3df n1( + Q2_VERTEX_NORMAL_TABLE[first->NormalIdx][0], + Q2_VERTEX_NORMAL_TABLE[first->NormalIdx][2], + Q2_VERTEX_NORMAL_TABLE[first->NormalIdx][1]); + const core::vector3df n2( + Q2_VERTEX_NORMAL_TABLE[second->NormalIdx][0], + Q2_VERTEX_NORMAL_TABLE[second->NormalIdx][2], + Q2_VERTEX_NORMAL_TABLE[second->NormalIdx][1]); + target->Normal = n2.getInterpolated(n1, div); + ++target; + ++first; + ++second; + } + + //update bounding box + InterpolationBuffer->setBoundingBox(BoxList[secondFrame].getInterpolated(BoxList[firstFrame], div)); + InterpolationBuffer->setDirty(); + } +} + + +//! sets a flag of all contained materials to a new value +void CAnimatedMeshMD2::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) +{ + InterpolationBuffer->Material.setFlag(flag, newvalue); +} + + +//! set the hardware mapping hint, for driver +void CAnimatedMeshMD2::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, + E_BUFFER_TYPE buffer) +{ + InterpolationBuffer->setHardwareMappingHint(newMappingHint, buffer); +} + + +//! flags the meshbuffer as changed, reloads hardware buffers +void CAnimatedMeshMD2::setDirty(E_BUFFER_TYPE buffer) +{ + InterpolationBuffer->setDirty(buffer); +} + + +//! returns an axis aligned bounding box +const core::aabbox3d& CAnimatedMeshMD2::getBoundingBox() const +{ + return InterpolationBuffer->BoundingBox; +} + + +//! set user axis aligned bounding box +void CAnimatedMeshMD2::setBoundingBox(const core::aabbox3df& box) +{ + InterpolationBuffer->BoundingBox = box; +} + + +//! Returns the type of the animated mesh. +E_ANIMATED_MESH_TYPE CAnimatedMeshMD2::getMeshType() const +{ + return EAMT_MD2; +} + + +//! Returns frame loop data for a special MD2 animation type. +void CAnimatedMeshMD2::getFrameLoop(EMD2_ANIMATION_TYPE l, + s32& outBegin, s32& outEnd, s32& outFPS) const +{ + if (l < 0 || l >= EMAT_COUNT) + return; + + outBegin = MD2AnimationTypeList[l].begin << MD2_FRAME_SHIFT; + outEnd = MD2AnimationTypeList[l].end << MD2_FRAME_SHIFT; + + // correct to anim between last->first frame + outEnd += MD2_FRAME_SHIFT == 0 ? 1 : (1 << MD2_FRAME_SHIFT) - 1; + outFPS = MD2AnimationTypeList[l].fps << MD2_FRAME_SHIFT; +} + + +//! Returns frame loop data for a special MD2 animation type. +bool CAnimatedMeshMD2::getFrameLoop(const c8* name, + s32& outBegin, s32&outEnd, s32& outFPS) const +{ + for (u32 i=0; i < AnimationData.size(); ++i) + { + if (AnimationData[i].name == name) + { + outBegin = AnimationData[i].begin << MD2_FRAME_SHIFT; + outEnd = AnimationData[i].end << MD2_FRAME_SHIFT; + outEnd += MD2_FRAME_SHIFT == 0 ? 1 : (1 << MD2_FRAME_SHIFT) - 1; + outFPS = AnimationData[i].fps << MD2_FRAME_SHIFT; + return true; + } + } + + return false; +} + + +//! Returns amount of md2 animations in this file. +s32 CAnimatedMeshMD2::getAnimationCount() const +{ + return AnimationData.size(); +} + + +//! Returns name of md2 animation. +const c8* CAnimatedMeshMD2::getAnimationName(s32 nr) const +{ + if ((u32)nr >= AnimationData.size()) + return 0; + + return AnimationData[nr].name.c_str(); +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_MD2_LOADER_ diff --git a/source/Irrlicht/CAnimatedMeshMD2.h b/source/Irrlicht/CAnimatedMeshMD2.h new file mode 100644 index 00000000..a614f18a --- /dev/null +++ b/source/Irrlicht/CAnimatedMeshMD2.h @@ -0,0 +1,158 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_ANIMATED_MESH_MD2_H_INCLUDED__ +#define __C_ANIMATED_MESH_MD2_H_INCLUDED__ + +#include "IAnimatedMeshMD2.h" +#include "IMesh.h" +#include "CMeshBuffer.h" +#include "IReadFile.h" +#include "S3DVertex.h" +#include "irrArray.h" +#include "irrString.h" + +namespace irr +{ +namespace scene +{ + + class CAnimatedMeshMD2 : public IAnimatedMeshMD2 + { + public: + + //! constructor + CAnimatedMeshMD2(); + + //! destructor + virtual ~CAnimatedMeshMD2(); + + //! returns the amount of frames. If the amount is 1, it is a static (=non animated) mesh. + virtual u32 getFrameCount() const _IRR_OVERRIDE_; + + //! Gets the default animation speed of the animated mesh. + /** \return Amount of frames per second. If the amount is 0, it is a static, non animated mesh. */ + virtual f32 getAnimationSpeed() const _IRR_OVERRIDE_ + { + return FramesPerSecond; + } + + //! Gets the frame count of the animated mesh. + /** \param fps Frames per second to play the animation with. If the amount is 0, it is not animated. + The actual speed is set in the scene node the mesh is instantiated in.*/ + virtual void setAnimationSpeed(f32 fps) _IRR_OVERRIDE_ + { + FramesPerSecond=fps; + } + + //! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level. + virtual IMesh* getMesh(s32 frame, s32 detailLevel=255, s32 startFrameLoop=-1, s32 endFrameLoop=-1) _IRR_OVERRIDE_; + + //! returns amount of mesh buffers. + virtual u32 getMeshBufferCount() const _IRR_OVERRIDE_; + + //! returns pointer to a mesh buffer + virtual IMeshBuffer* getMeshBuffer(u32 nr) const _IRR_OVERRIDE_; + + //! Returns pointer to a mesh buffer which fits a material + /** \param material: material to search for + \return Returns the pointer to the mesh buffer or + NULL if there is no such mesh buffer. */ + virtual IMeshBuffer* getMeshBuffer( const video::SMaterial &material) const _IRR_OVERRIDE_; + + //! returns an axis aligned bounding box + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + //! set user axis aligned bounding box + virtual void setBoundingBox( const core::aabbox3df& box) _IRR_OVERRIDE_; + + //! sets a flag of all contained materials to a new value + virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) _IRR_OVERRIDE_; + + //! set the hardware mapping hint, for driver + virtual void setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_; + + //! flags the meshbuffer as changed, reloads hardware buffers + virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_; + + //! Returns the type of the animated mesh. + virtual E_ANIMATED_MESH_TYPE getMeshType() const _IRR_OVERRIDE_; + + //! Returns frame loop data for a special MD2 animation type. + virtual void getFrameLoop(EMD2_ANIMATION_TYPE, + s32& outBegin, s32& outEnd, s32& outFps) const _IRR_OVERRIDE_; + + //! Returns frame loop data for a special MD2 animation type. + virtual bool getFrameLoop(const c8* name, + s32& outBegin, s32& outEnd, s32& outFps) const _IRR_OVERRIDE_; + + //! Returns amount of md2 animations in this file. + virtual s32 getAnimationCount() const _IRR_OVERRIDE_; + + //! Returns name of md2 animation. + //! \param nr: Zero based index of animation. + virtual const c8* getAnimationName(s32 nr) const _IRR_OVERRIDE_; + + + // + // exposed for loader + // + + //! the buffer that contains the most recent animation + SMeshBuffer* InterpolationBuffer; + + //! Frames used to calculate InterpolationBuffer + u32 InterpolationFirstFrame, InterpolationSecondFrame; + f32 InterpolationFrameDiv; + + //! named animations + struct SAnimationData + { + core::stringc name; + s32 begin; + s32 end; + s32 fps; + }; + + //! 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; + + u32 FrameCount; + + private: + + //! updates the interpolation buffer + void updateInterpolationBuffer(s32 frame, s32 startFrame, s32 endFrame); + + f32 FramesPerSecond; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CAnimatedMeshMD3.cpp b/source/Irrlicht/CAnimatedMeshMD3.cpp new file mode 100644 index 00000000..0d3a091b --- /dev/null +++ b/source/Irrlicht/CAnimatedMeshMD3.cpp @@ -0,0 +1,468 @@ +// Copyright (C) 2002-2012 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 + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_MD3_LOADER_ + +#include "CAnimatedMeshMD3.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + + +// byte-align structures +#include "irrpack.h" + +//! General properties of a single animation frame. +struct SMD3Frame +{ + f32 mins[3]; // bounding box per frame + f32 maxs[3]; + f32 position[3]; // position of bounding box + f32 radius; // radius of bounding sphere + c8 creator[16]; // name of frame +} PACK_STRUCT; + + +//! An attachment point for another MD3 model. +struct SMD3Tag +{ + c8 Name[64]; //name of 'tag' as it's usually called in the md3 files try to see it as a sub-mesh/seperate mesh-part. + f32 position[3]; //relative position of tag + f32 rotationMatrix[9]; //3x3 rotation direction of tag +} PACK_STRUCT; + +//!Shader +struct SMD3Shader +{ + c8 name[64]; // name of shader + s32 shaderIndex; +} PACK_STRUCT; + +// Default alignment +#include "irrunpack.h" + + +//! Constructor +CAnimatedMeshMD3::CAnimatedMeshMD3() +:Mesh(0), IPolShift(0), LoopMode(0), Scaling(1.f)//, FramesPerSecond(25.f) +{ +#ifdef _DEBUG + setDebugName("CAnimatedMeshMD3"); +#endif + + Mesh = new SMD3Mesh(); + MeshIPol = new SMesh(); + setInterpolationShift(0, 0); +} + + +//! Destructor +CAnimatedMeshMD3::~CAnimatedMeshMD3() +{ + if (Mesh) + Mesh->drop(); + if (MeshIPol) + MeshIPol->drop(); +} + + +//! Returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh. +u32 CAnimatedMeshMD3::getFrameCount() const +{ + return Mesh->MD3Header.numFrames << IPolShift; +} + + +//! Rendering Hint +void CAnimatedMeshMD3::setInterpolationShift(u32 shift, u32 loopMode) +{ + IPolShift = shift; + LoopMode = loopMode; +} + + +//! returns amount of mesh buffers. +u32 CAnimatedMeshMD3::getMeshBufferCount() const +{ + return MeshIPol->getMeshBufferCount(); +} + + +//! returns pointer to a mesh buffer +IMeshBuffer* CAnimatedMeshMD3::getMeshBuffer(u32 nr) const +{ + return MeshIPol->getMeshBuffer(nr); +} + + +//! Returns pointer to a mesh buffer which fits a material +IMeshBuffer* CAnimatedMeshMD3::getMeshBuffer(const video::SMaterial &material) const +{ + return MeshIPol->getMeshBuffer(material); +} + + +void CAnimatedMeshMD3::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) +{ + MeshIPol->setMaterialFlag(flag, newvalue); +} + + +//! set the hardware mapping hint, for driver +void CAnimatedMeshMD3::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, + E_BUFFER_TYPE buffer) +{ + MeshIPol->setHardwareMappingHint(newMappingHint, buffer); +} + + +//! flags the meshbuffer as changed, reloads hardware buffers +void CAnimatedMeshMD3::setDirty(E_BUFFER_TYPE buffer) +{ + MeshIPol->setDirty(buffer); +} + + +//! set user axis aligned bounding box +void CAnimatedMeshMD3::setBoundingBox(const core::aabbox3df& box) +{ + MeshIPol->setBoundingBox(box); +} + + +//! Returns the animated tag list based on a detail level. 0 is the lowest, 255 the highest detail. +SMD3QuaternionTagList *CAnimatedMeshMD3::getTagList(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) +{ + if (0 == Mesh) + return 0; + + getMesh(frame, detailLevel, startFrameLoop, endFrameLoop); + return &TagListIPol; +} + + +//! Returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. +IMesh* CAnimatedMeshMD3::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) +{ + if (0 == Mesh) + return 0; + + //! check if we have the mesh in our private cache + SCacheInfo candidate(frame, startFrameLoop, endFrameLoop); + if (candidate == Current) + return MeshIPol; + + startFrameLoop = core::s32_max(0, startFrameLoop >> IPolShift); + endFrameLoop = core::if_c_a_else_b(endFrameLoop < 0, Mesh->MD3Header.numFrames - 1, endFrameLoop >> IPolShift); + + const u32 mask = 1 << IPolShift; + + s32 frameA; + s32 frameB; + f32 iPol; + + if (LoopMode) + { + // correct frame to "pixel center" + frame -= mask >> 1; + + // interpolation + iPol = f32(frame & (mask - 1)) * core::reciprocal(f32(mask)); + + // wrap anim + frame >>= IPolShift; + frameA = core::if_c_a_else_b(frame < startFrameLoop, endFrameLoop, frame); + frameB = core::if_c_a_else_b(frameA + 1 > endFrameLoop, startFrameLoop, frameA + 1); + } + else + { + // correct frame to "pixel center" + frame -= mask >> 1; + + iPol = f32(frame & (mask - 1)) * core::reciprocal(f32(mask)); + + // clamp anim + frame >>= IPolShift; + frameA = core::s32_clamp(frame, startFrameLoop, endFrameLoop); + frameB = core::s32_min(frameA + 1, endFrameLoop); + } + + // build current vertex + for (u32 i = 0; i!= Mesh->Buffer.size(); ++i) + { + buildVertexArray(frameA, frameB, iPol, + Mesh->Buffer[i], + (SMeshBufferLightMap*) MeshIPol->getMeshBuffer(i)); + } + MeshIPol->recalculateBoundingBox(); + + // build current tags + buildTagArray(frameA, frameB, iPol); + + Current = candidate; + return MeshIPol; +} + + +//! create a Irrlicht MeshBuffer for a MD3 MeshBuffer +IMeshBuffer * CAnimatedMeshMD3::createMeshBuffer(const SMD3MeshBuffer* source, + io::IFileSystem* fs, video::IVideoDriver * driver) +{ + SMeshBufferLightMap * dest = new SMeshBufferLightMap(); + dest->Vertices.set_used(source->MeshHeader.numVertices); + dest->Indices.set_used(source->Indices.size()); + + u32 i; + + // fill in static face info + for (i = 0; i < source->Indices.size(); i += 3) + { + dest->Indices[i + 0] = (u16) source->Indices[i + 0]; + dest->Indices[i + 1] = (u16) source->Indices[i + 1]; + dest->Indices[i + 2] = (u16) source->Indices[i + 2]; + } + + // fill in static vertex info + for (i = 0; i!= (u32)source->MeshHeader.numVertices; ++i) + { + video::S3DVertex2TCoords &v = dest->Vertices[i]; + v.Color = 0xFFFFFFFF; + v.TCoords.X = source->Tex[i].u; + v.TCoords.Y = source->Tex[i].v; + v.TCoords2.X = 0.f; + v.TCoords2.Y = 0.f; + } + + // load static texture + u32 pos = 0; + quake3::tTexArray textureArray; + quake3::getTextures(textureArray, source->Shader, pos, fs, driver); + dest->Material.MaterialType = video::EMT_SOLID; + dest->Material.setTexture(0, textureArray[0]); + dest->Material.Lighting = false; + + return dest; +} + + +//! build final mesh's vertices from frames frameA and frameB with linear interpolation. +void CAnimatedMeshMD3::buildVertexArray(u32 frameA, u32 frameB, f32 interpolate, + const SMD3MeshBuffer* source, + SMeshBufferLightMap* dest) +{ + const u32 frameOffsetA = frameA * source->MeshHeader.numVertices; + const u32 frameOffsetB = frameB * source->MeshHeader.numVertices; + const f32 scale = (1.f/ 64.f); + + for (s32 i = 0; i != source->MeshHeader.numVertices; ++i) + { + video::S3DVertex2TCoords &v = dest->Vertices [ i ]; + + const SMD3Vertex &vA = source->Vertices [ frameOffsetA + i ]; + const SMD3Vertex &vB = source->Vertices [ frameOffsetB + i ]; + + // position + v.Pos.X = scale * (vA.position[0] + interpolate * (vB.position[0] - vA.position[0])); + v.Pos.Y = scale * (vA.position[2] + interpolate * (vB.position[2] - vA.position[2])); + v.Pos.Z = scale * (vA.position[1] + interpolate * (vB.position[1] - vA.position[1])); + + // normal + const core::vector3df nA(quake3::getMD3Normal(vA.normal[0], vA.normal[1])); + const core::vector3df nB(quake3::getMD3Normal(vB.normal[0], vB.normal[1])); + + v.Normal.X = nA.X + interpolate * (nB.X - nA.X); + v.Normal.Y = nA.Z + interpolate * (nB.Z - nA.Z); + v.Normal.Z = nA.Y + interpolate * (nB.Y - nA.Y); + } + + dest->recalculateBoundingBox(); +} + + +//! build final mesh's tag from frames frameA and frameB with linear interpolation. +void CAnimatedMeshMD3::buildTagArray(u32 frameA, u32 frameB, f32 interpolate) +{ + const u32 frameOffsetA = frameA * Mesh->MD3Header.numTags; + const u32 frameOffsetB = frameB * Mesh->MD3Header.numTags; + + for (s32 i = 0; i != Mesh->MD3Header.numTags; ++i) + { + SMD3QuaternionTag &d = TagListIPol [ i ]; + + const SMD3QuaternionTag &qA = Mesh->TagList[ frameOffsetA + i]; + const SMD3QuaternionTag &qB = Mesh->TagList[ frameOffsetB + i]; + + // rotation + d.rotation.slerp(qA.rotation, qB.rotation, interpolate); + + // position + d.position.X = qA.position.X + interpolate * (qB.position.X - qA.position.X); + d.position.Y = qA.position.Y + interpolate * (qB.position.Y - qA.position.Y); + d.position.Z = qA.position.Z + interpolate * (qB.position.Z - qA.position.Z); + } +} + + +/*! + loads a model +*/ +bool CAnimatedMeshMD3::loadModelFile(u32 modelIndex, io::IReadFile* file, + io::IFileSystem* fs, video::IVideoDriver* driver) +{ + if (!file) + return false; + + //! Check MD3Header + { + file->read(&Mesh->MD3Header, sizeof(SMD3Header)); + + if (strncmp("IDP3", Mesh->MD3Header.headerID, 4)) + { + os::Printer::log("MD3 Loader: invalid header"); + return false; + } + } + + //! store model name + Mesh->Name = file->getFileName(); + + u32 i; + + //! Frame Data (ignore) +#if 0 + SMD3Frame frameImport; + file->seek(Mesh->MD3Header.frameStart); + for (i = 0; i != Mesh->MD3Header.numFrames; ++i) + { + file->read(&frameImport, sizeof(frameImport)); + } +#endif + + //! Tag Data + const u32 totalTags = Mesh->MD3Header.numTags * Mesh->MD3Header.numFrames; + + SMD3Tag import; + + file->seek(Mesh->MD3Header.tagStart); + Mesh->TagList.set_used(totalTags); + for (i = 0; i != totalTags; ++i) + { + file->read(&import, sizeof(import)); + + SMD3QuaternionTag &exp = Mesh->TagList[i]; + + //! tag name + exp.Name = import.Name; + + //! position + exp.position.X = import.position[0]; + exp.position.Y = import.position[2]; + exp.position.Z = import.position[1]; + + //! construct quaternion from a RH 3x3 Matrix + exp.rotation.set(import.rotationMatrix[7], + 0.f, + -import.rotationMatrix[6], + 1 + import.rotationMatrix[8]); + exp.rotation.normalize(); + } + + //! Meshes + u32 offset = Mesh->MD3Header.tagEnd; + + for (i = 0; i != (u32)Mesh->MD3Header.numMeshes; ++i) + { + //! construct a new mesh buffer + SMD3MeshBuffer * buf = new SMD3MeshBuffer(); + + // !read mesh header info + SMD3MeshHeader &meshHeader = buf->MeshHeader; + + //! read mesh info + file->seek(offset); + file->read(&meshHeader, sizeof(SMD3MeshHeader)); + + //! prepare memory + buf->Vertices.set_used(meshHeader.numVertices * Mesh->MD3Header.numFrames); + buf->Indices.set_used(meshHeader.numTriangles * 3); + buf->Tex.set_used(meshHeader.numVertices); + + //! read skins (shaders). should be 1 per meshbuffer + SMD3Shader skin; + file->seek(offset + buf->MeshHeader.offset_shaders); + for (s32 g = 0; g != buf->MeshHeader.numShader; ++g) + { + file->read(&skin, sizeof(skin)); + + io::path name; + cutFilenameExtension(name, skin.name); + name.replace('\\', '/'); + buf->Shader = name; + } + + //! read texture coordinates + file->seek(offset + buf->MeshHeader.offset_st); + file->read(buf->Tex.pointer(), buf->MeshHeader.numVertices * sizeof(SMD3TexCoord)); + + //! read vertices + file->seek(offset + meshHeader.vertexStart); + file->read(buf->Vertices.pointer(), Mesh->MD3Header.numFrames * meshHeader.numVertices * sizeof(SMD3Vertex)); + + //! read indices + file->seek(offset + meshHeader.offset_triangles); + file->read(buf->Indices.pointer(), meshHeader.numTriangles * sizeof(SMD3Face)); + + //! store meshBuffer + Mesh->Buffer.push_back(buf); + + offset += meshHeader.offset_end; + } + + // Init Mesh Interpolation + for (i = 0; i != Mesh->Buffer.size(); ++i) + { + IMeshBuffer * buffer = createMeshBuffer(Mesh->Buffer[i], fs, driver); + MeshIPol->addMeshBuffer(buffer); + buffer->drop(); + } + MeshIPol->recalculateBoundingBox(); + + // Init Tag Interpolation + for (i = 0; i != (u32)Mesh->MD3Header.numTags; ++i) + { + TagListIPol.push_back(Mesh->TagList[i]); + } + + return true; +} + + +SMD3Mesh * CAnimatedMeshMD3::getOriginalMesh() +{ + return Mesh; +} + + +//! Returns an axis aligned bounding box +const core::aabbox3d& CAnimatedMeshMD3::getBoundingBox() const +{ + return MeshIPol->BoundingBox; +} + + +//! Returns the type of the animated mesh. +E_ANIMATED_MESH_TYPE CAnimatedMeshMD3::getMeshType() const +{ + return EAMT_MD3; +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_MD3_LOADER_ diff --git a/source/Irrlicht/CAnimatedMeshMD3.h b/source/Irrlicht/CAnimatedMeshMD3.h new file mode 100644 index 00000000..cc96b58c --- /dev/null +++ b/source/Irrlicht/CAnimatedMeshMD3.h @@ -0,0 +1,135 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_ANIMATED_MESH_MD3_H_INCLUDED__ +#define __C_ANIMATED_MESH_MD3_H_INCLUDED__ + +#include "IAnimatedMeshMD3.h" +#include "IReadFile.h" +#include "IFileSystem.h" +#include "irrArray.h" +#include "irrString.h" +#include "SMesh.h" +#include "SMeshBuffer.h" +#include "IQ3Shader.h" + +namespace irr +{ +namespace scene +{ + + class CAnimatedMeshMD3 : public IAnimatedMeshMD3 + { + public: + + //! constructor + CAnimatedMeshMD3(); + + //! destructor + virtual ~CAnimatedMeshMD3(); + + //! loads a quake3 md3 file + bool loadModelFile(u32 modelIndex, io::IReadFile* file, + io::IFileSystem* fs, video::IVideoDriver* driver); + + // IAnimatedMeshMD3 + virtual void setInterpolationShift(u32 shift, u32 loopMode) _IRR_OVERRIDE_; + virtual SMD3Mesh* getOriginalMesh() _IRR_OVERRIDE_; + virtual SMD3QuaternionTagList* getTagList(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) _IRR_OVERRIDE_; + + //IAnimatedMesh + virtual u32 getFrameCount() const _IRR_OVERRIDE_; + + //! Gets the default animation speed of the animated mesh. + /** \return Amount of frames per second. If the amount is 0, it is a static, non animated mesh. */ + virtual f32 getAnimationSpeed() const _IRR_OVERRIDE_ + { + return FramesPerSecond; + } + + //! Gets the frame count of the animated mesh. + /** \param fps Frames per second to play the animation with. If the amount is 0, it is not animated. + The actual speed is set in the scene node the mesh is instantiated in.*/ + virtual void setAnimationSpeed(f32 fps) _IRR_OVERRIDE_ + { + FramesPerSecond=fps; + } + + virtual IMesh* getMesh(s32 frame, s32 detailLevel, + s32 startFrameLoop, s32 endFrameLoop) _IRR_OVERRIDE_; + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + virtual E_ANIMATED_MESH_TYPE getMeshType() const _IRR_OVERRIDE_; + + //! returns amount of mesh buffers. + virtual u32 getMeshBufferCount() const _IRR_OVERRIDE_; + + //! returns pointer to a mesh buffer + virtual IMeshBuffer* getMeshBuffer(u32 nr) const _IRR_OVERRIDE_; + + //! Returns pointer to a mesh buffer which fits a material + virtual IMeshBuffer* getMeshBuffer(const video::SMaterial &material) const _IRR_OVERRIDE_; + + virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) _IRR_OVERRIDE_; + + //! set user axis aligned bounding box + virtual void setBoundingBox(const core::aabbox3df& box) _IRR_OVERRIDE_; + + //! set the hardware mapping hint, for driver + virtual void setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_; + + //! flags the meshbuffer as changed, reloads hardware buffers + virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_; + + private: + //! animates one frame + inline void Animate(u32 frame); + + video::SMaterial Material; + + //! hold original compressed MD3 Info + SMD3Mesh *Mesh; + + u32 IPolShift; + u32 LoopMode; + f32 Scaling; + + //! Cache Info + struct SCacheInfo + { + SCacheInfo(s32 frame=-1, s32 start=-1, s32 end=-1 ) : + Frame(frame), startFrameLoop(start), + endFrameLoop(end) + {} + + bool operator == ( const SCacheInfo &other ) const + { + return 0 == memcmp ( this, &other, sizeof ( SCacheInfo ) ); + } + s32 Frame; + s32 startFrameLoop; + s32 endFrameLoop; + }; + SCacheInfo Current; + + //! return a Mesh per frame + SMesh* MeshIPol; + SMD3QuaternionTagList TagListIPol; + + IMeshBuffer* createMeshBuffer(const SMD3MeshBuffer* source, + io::IFileSystem* fs, video::IVideoDriver* driver); + + void buildVertexArray(u32 frameA, u32 frameB, f32 interpolate, + const SMD3MeshBuffer* source, + SMeshBufferLightMap* dest); + + void buildTagArray(u32 frameA, u32 frameB, f32 interpolate); + f32 FramesPerSecond; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CAnimatedMeshSceneNode.cpp b/source/Irrlicht/CAnimatedMeshSceneNode.cpp new file mode 100644 index 00000000..593496a4 --- /dev/null +++ b/source/Irrlicht/CAnimatedMeshSceneNode.cpp @@ -0,0 +1,1126 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CAnimatedMeshSceneNode.h" +#include "IVideoDriver.h" +#include "ISceneManager.h" +#include "S3DVertex.h" +#include "os.h" +#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ +#include "CShadowVolumeSceneNode.h" +#else +#include "IShadowVolumeSceneNode.h" +#endif // _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ +#include "IAnimatedMeshMD3.h" +#include "CSkinnedMesh.h" +#include "IDummyTransformationSceneNode.h" +#include "IBoneSceneNode.h" +#include "IMaterialRenderer.h" +#include "IMesh.h" +#include "IMeshCache.h" +#include "IAnimatedMesh.h" +#include "quaternion.h" + + +namespace irr +{ +namespace scene +{ + + +//! constructor +CAnimatedMeshSceneNode::CAnimatedMeshSceneNode(IAnimatedMesh* mesh, + ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position, + const core::vector3df& rotation, + const core::vector3df& scale) +: IAnimatedMeshSceneNode(parent, mgr, id, position, rotation, scale), Mesh(0), + StartFrame(0), EndFrame(0), FramesPerSecond(0.025f), + CurrentFrameNr(0.f), LastTimeMs(0), + TransitionTime(0), Transiting(0.f), TransitingBlend(0.f), + JointMode(EJUOR_NONE), JointsUsed(false), + Looping(true), ReadOnlyMaterials(false), RenderFromIdentity(false), + LoopCallBack(0), PassCount(0), Shadow(0), MD3Special(0) +{ + #ifdef _DEBUG + setDebugName("CAnimatedMeshSceneNode"); + #endif + + setMesh(mesh); +} + + +//! destructor +CAnimatedMeshSceneNode::~CAnimatedMeshSceneNode() +{ + if (MD3Special) + MD3Special->drop(); + + if (Mesh) + Mesh->drop(); + + if (Shadow) + Shadow->drop(); + + if (LoopCallBack) + LoopCallBack->drop(); +} + + +//! Sets the current frame. From now on the animation is played from this frame. +void CAnimatedMeshSceneNode::setCurrentFrame(f32 frame) +{ + // if you pass an out of range value, we just clamp it + CurrentFrameNr = core::clamp ( frame, (f32)StartFrame, (f32)EndFrame ); + + beginTransition(); //transit to this frame if enabled +} + + +//! Returns the currently displayed frame number. +f32 CAnimatedMeshSceneNode::getFrameNr() const +{ + return CurrentFrameNr; +} + + +//! Get CurrentFrameNr and update transiting settings +void CAnimatedMeshSceneNode::buildFrameNr(u32 timeMs) +{ + if (Transiting!=0.f) + { + TransitingBlend += (f32)(timeMs) * Transiting; + if (TransitingBlend > 1.f) + { + Transiting=0.f; + TransitingBlend=0.f; + } + } + + if (StartFrame==EndFrame) + { + CurrentFrameNr = (f32)StartFrame; //Support for non animated meshes + } + else if (Looping) + { + // play animation looped + CurrentFrameNr += timeMs * FramesPerSecond; + + // We have no interpolation between EndFrame and StartFrame, + // the last frame must be identical to first one with our current solution. + if (FramesPerSecond > 0.f) //forwards... + { + if (CurrentFrameNr > EndFrame) + CurrentFrameNr = StartFrame + fmod(CurrentFrameNr - StartFrame, (f32)(EndFrame-StartFrame)); + } + else //backwards... + { + if (CurrentFrameNr < StartFrame) + CurrentFrameNr = EndFrame - fmod(EndFrame - CurrentFrameNr, (f32)(EndFrame-StartFrame)); + } + } + else + { + // play animation non looped + + CurrentFrameNr += timeMs * FramesPerSecond; + if (FramesPerSecond > 0.f) //forwards... + { + if (CurrentFrameNr > (f32)EndFrame) + { + CurrentFrameNr = (f32)EndFrame; + if (LoopCallBack) + LoopCallBack->OnAnimationEnd(this); + } + } + else //backwards... + { + if (CurrentFrameNr < (f32)StartFrame) + { + CurrentFrameNr = (f32)StartFrame; + if (LoopCallBack) + LoopCallBack->OnAnimationEnd(this); + } + } + } +} + + +void CAnimatedMeshSceneNode::OnRegisterSceneNode() +{ + if (IsVisible && Mesh) + { + // because this node supports rendering of mixed mode meshes consisting of + // transparent and solid material at the same time, we need to go through all + // materials, check of what type they are and register this node for the right + // render pass according to that. + + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + + PassCount = 0; + int transparentCount = 0; + int solidCount = 0; + + // count transparent and solid materials in this scene node + const u32 numMaterials = ReadOnlyMaterials ? Mesh->getMeshBufferCount() : Materials.size(); + for (u32 i=0; igetMeshBuffer(i)->getMaterial() : Materials[i]; + + if ( driver->needsTransparentRenderPass(material) ) + ++transparentCount; + else + ++solidCount; + + if (solidCount && transparentCount) + break; + } + + // register according to material types counted + + if (solidCount) + SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID); + + if (transparentCount) + SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT); + + ISceneNode::OnRegisterSceneNode(); + } +} + +IMesh * CAnimatedMeshSceneNode::getMeshForCurrentFrame() +{ + if(Mesh->getMeshType() != EAMT_SKINNED) + { + s32 frameNr = (s32) getFrameNr(); + s32 frameBlend = (s32) (core::fract ( getFrameNr() ) * 1000.f); + return Mesh->getMesh(frameNr, frameBlend, StartFrame, EndFrame); + } + else + { +#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ + return 0; +#else + + // As multiple scene nodes may be sharing the same skinned mesh, we have to + // re-animate it every frame to ensure that this node gets the mesh that it needs. + + CSkinnedMesh* skinnedMesh = reinterpret_cast(Mesh); + + if (JointMode == EJUOR_CONTROL)//write to mesh + skinnedMesh->transferJointsToMesh(JointChildSceneNodes); + else + skinnedMesh->animateMesh(getFrameNr(), 1.0f); + + // Update the skinned mesh for the current joint transforms. + skinnedMesh->skinMesh(); + + if (JointMode == EJUOR_READ)//read from mesh + { + skinnedMesh->recoverJointsFromMesh(JointChildSceneNodes); + + //---slow--- + for (u32 n=0;ngetParent()==this) + { + JointChildSceneNodes[n]->updateAbsolutePositionOfAllChildren(); //temp, should be an option + } + } + + if(JointMode == EJUOR_CONTROL) + { + // For meshes other than EJUOR_CONTROL, this is done by calling animateMesh() + skinnedMesh->updateBoundingBox(); + } + + return skinnedMesh; +#endif + } +} + + +//! OnAnimate() is called just before rendering the whole scene. +void CAnimatedMeshSceneNode::OnAnimate(u32 timeMs) +{ + if (LastTimeMs==0) // first frame + { + LastTimeMs = timeMs; + } + + // set CurrentFrameNr + buildFrameNr(timeMs-LastTimeMs); + + // update bbox + if (Mesh) + { + scene::IMesh * mesh = getMeshForCurrentFrame(); + + if (mesh) + Box = mesh->getBoundingBox(); + } + LastTimeMs = timeMs; + + IAnimatedMeshSceneNode::OnAnimate(timeMs); +} + + +//! renders the node. +void CAnimatedMeshSceneNode::render() +{ + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + + if (!Mesh || !driver) + return; + + + const bool isTransparentPass = + SceneManager->getSceneNodeRenderPass() == scene::ESNRP_TRANSPARENT; + + ++PassCount; + + scene::IMesh* m = getMeshForCurrentFrame(); + + if(m) + { + Box = m->getBoundingBox(); + } + else + { + #ifdef _DEBUG + os::Printer::log("Animated Mesh returned no mesh to render.", Mesh->getDebugName(), ELL_WARNING); + #endif + } + + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + + if (Shadow && PassCount==1) + Shadow->updateShadowVolumes(); + + // for debug purposes only: + + bool renderMeshes = true; + video::SMaterial mat; + if (DebugDataVisible && PassCount==1) + { + // overwrite half transparency + if (DebugDataVisible & scene::EDS_HALF_TRANSPARENCY) + { + + for (u32 i=0; igetMeshBufferCount(); ++i) + { + scene::IMeshBuffer* mb = m->getMeshBuffer(i); + mat = ReadOnlyMaterials ? mb->getMaterial() : Materials[i]; + mat.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR; + if (RenderFromIdentity) + driver->setTransform(video::ETS_WORLD, core::IdentityMatrix ); + else if (Mesh->getMeshType() == EAMT_SKINNED) + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation * ((SSkinMeshBuffer*)mb)->Transformation); + + driver->setMaterial(mat); + driver->drawMeshBuffer(mb); + } + renderMeshes = false; + } + } + + // render original meshes + if (renderMeshes) + { + for (u32 i=0; igetMeshBufferCount(); ++i) + { + const bool transparent = driver->needsTransparentRenderPass(Materials[i]); + + // only render transparent buffer if this is the transparent render pass + // and solid only in solid pass + if (transparent == isTransparentPass) + { + scene::IMeshBuffer* mb = m->getMeshBuffer(i); + const video::SMaterial& material = ReadOnlyMaterials ? mb->getMaterial() : Materials[i]; + if (RenderFromIdentity) + driver->setTransform(video::ETS_WORLD, core::IdentityMatrix ); + else if (Mesh->getMeshType() == EAMT_SKINNED) + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation * ((SSkinMeshBuffer*)mb)->Transformation); + + driver->setMaterial(material); + driver->drawMeshBuffer(mb); + } + } + } + + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + + // for debug purposes only: + if (DebugDataVisible && PassCount==1) + { + video::SMaterial debug_mat; + debug_mat.Lighting = false; + debug_mat.AntiAliasing=0; + driver->setMaterial(debug_mat); + // show normals + if (DebugDataVisible & scene::EDS_NORMALS) + { + const f32 debugNormalLength = SceneManager->getParameters()->getAttributeAsFloat(DEBUG_NORMAL_LENGTH); + const video::SColor debugNormalColor = SceneManager->getParameters()->getAttributeAsColor(DEBUG_NORMAL_COLOR); + const u32 count = m->getMeshBufferCount(); + + // draw normals + for (u32 g=0; g < count; ++g) + { + scene::IMeshBuffer* mb = m->getMeshBuffer(g); + if (RenderFromIdentity) + driver->setTransform(video::ETS_WORLD, core::IdentityMatrix ); + else if (Mesh->getMeshType() == EAMT_SKINNED) + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation * ((SSkinMeshBuffer*)mb)->Transformation); + + driver->drawMeshBufferNormals(mb, debugNormalLength, debugNormalColor); + } + } + + debug_mat.ZBuffer = video::ECFN_DISABLED; + debug_mat.Lighting = false; + driver->setMaterial(debug_mat); + + if (DebugDataVisible & scene::EDS_BBOX) + driver->draw3DBox(Box, video::SColor(255,255,255,255)); + + // show bounding box + if (DebugDataVisible & scene::EDS_BBOX_BUFFERS) + { + for (u32 g=0; g< m->getMeshBufferCount(); ++g) + { + const IMeshBuffer* mb = m->getMeshBuffer(g); + + if (Mesh->getMeshType() == EAMT_SKINNED) + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation * ((SSkinMeshBuffer*)mb)->Transformation); + driver->draw3DBox(mb->getBoundingBox(), video::SColor(255,190,128,128)); + } + } + + // show skeleton + if (DebugDataVisible & scene::EDS_SKELETON) + { + if (Mesh->getMeshType() == EAMT_SKINNED) + { + // draw skeleton + + for (u32 g=0; g < ((ISkinnedMesh*)Mesh)->getAllJoints().size(); ++g) + { + ISkinnedMesh::SJoint *joint=((ISkinnedMesh*)Mesh)->getAllJoints()[g]; + + for (u32 n=0;nChildren.size();++n) + { + driver->draw3DLine(joint->GlobalAnimatedMatrix.getTranslation(), + joint->Children[n]->GlobalAnimatedMatrix.getTranslation(), + video::SColor(255,51,66,255)); + } + } + } + + // show tag for quake3 models + if (Mesh->getMeshType() == EAMT_MD3) + { + IAnimatedMesh * arrow = + SceneManager->addArrowMesh ( + "__tag_show", + 0xFF0000FF, 0xFF000088, + 4, 8, 5.f, 4.f, 0.5f, + 1.f); + if (!arrow) + { + arrow = SceneManager->getMesh ( "__tag_show" ); + } + IMesh *arrowMesh = arrow->getMesh(0); + + core::matrix4 matr; + + SMD3QuaternionTagList *taglist = ((IAnimatedMeshMD3*)Mesh)->getTagList( + (s32)getFrameNr(), 255, + getStartFrame(), getEndFrame()); + if (taglist) + { + for ( u32 ts = 0; ts != taglist->size(); ++ts ) + { + (*taglist)[ts].setto(matr); + + driver->setTransform(video::ETS_WORLD, matr ); + + for ( u32 a = 0; a != arrowMesh->getMeshBufferCount(); ++a ) + driver->drawMeshBuffer(arrowMesh->getMeshBuffer(a)); + } + } + } + } + + // show mesh + if (DebugDataVisible & scene::EDS_MESH_WIRE_OVERLAY) + { + debug_mat.Lighting = false; + debug_mat.Wireframe = true; + debug_mat.ZBuffer = video::ECFN_DISABLED; + driver->setMaterial(debug_mat); + + for (u32 g=0; ggetMeshBufferCount(); ++g) + { + const IMeshBuffer* mb = m->getMeshBuffer(g); + if (RenderFromIdentity) + driver->setTransform(video::ETS_WORLD, core::IdentityMatrix ); + else if (Mesh->getMeshType() == EAMT_SKINNED) + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation * ((SSkinMeshBuffer*)mb)->Transformation); + driver->drawMeshBuffer(mb); + } + } + } +} + + +//! Returns the current start frame number. +s32 CAnimatedMeshSceneNode::getStartFrame() const +{ + return StartFrame; +} + + +//! Returns the current start frame number. +s32 CAnimatedMeshSceneNode::getEndFrame() const +{ + return EndFrame; +} + + +//! sets the frames between the animation is looped. +//! the default is 0 - MaximalFrameCount of the mesh. +bool CAnimatedMeshSceneNode::setFrameLoop(s32 begin, s32 end) +{ + const s32 maxFrameCount = Mesh->getFrameCount() - 1; + if (end < begin) + { + StartFrame = core::s32_clamp(end, 0, maxFrameCount); + EndFrame = core::s32_clamp(begin, StartFrame, maxFrameCount); + } + else + { + StartFrame = core::s32_clamp(begin, 0, maxFrameCount); + EndFrame = core::s32_clamp(end, StartFrame, maxFrameCount); + } + if (FramesPerSecond < 0) + setCurrentFrame((f32)EndFrame); + else + setCurrentFrame((f32)StartFrame); + + return true; +} + + +//! sets the speed with witch the animation is played +void CAnimatedMeshSceneNode::setAnimationSpeed(f32 framesPerSecond) +{ + FramesPerSecond = framesPerSecond * 0.001f; +} + + +f32 CAnimatedMeshSceneNode::getAnimationSpeed() const +{ + return FramesPerSecond * 1000.f; +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CAnimatedMeshSceneNode::getBoundingBox() const +{ + return Box; +} + + +//! returns the material based on the zero based index i. +video::SMaterial& CAnimatedMeshSceneNode::getMaterial(u32 i) +{ + if (i >= Materials.size()) + return ISceneNode::getMaterial(i); + + return Materials[i]; +} + + + +//! returns amount of materials used by this scene node. +u32 CAnimatedMeshSceneNode::getMaterialCount() const +{ + return Materials.size(); +} + + +//! Creates shadow volume scene node as child of this node +//! and returns a pointer to it. +IShadowVolumeSceneNode* CAnimatedMeshSceneNode::addShadowVolumeSceneNode( + const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity) +{ +#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ + if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER)) + return 0; + + if (!shadowMesh) + shadowMesh = Mesh; // if null is given, use the mesh of node + + if (Shadow) + Shadow->drop(); + + Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity); + return Shadow; +#else + return 0; +#endif +} + +//! Returns a pointer to a child node, which has the same transformation as +//! the corresponding joint, if the mesh in this scene node is a skinned mesh. +IBoneSceneNode* CAnimatedMeshSceneNode::getJointNode(const c8* jointName) +{ +#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ + os::Printer::log("Compiled without _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_", ELL_WARNING); + return 0; +#else + + if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED) + { + os::Printer::log("No mesh, or mesh not of skinned mesh type", ELL_WARNING); + return 0; + } + + checkJoints(); + + ISkinnedMesh *skinnedMesh=(ISkinnedMesh*)Mesh; + + const s32 number = skinnedMesh->getJointNumber(jointName); + + if (number == -1) + { + os::Printer::log("Joint with specified name not found in skinned mesh", jointName, ELL_DEBUG); + return 0; + } + + if ((s32)JointChildSceneNodes.size() <= number) + { + os::Printer::log("Joint was found in mesh, but is not loaded into node", jointName, ELL_WARNING); + return 0; + } + + return JointChildSceneNodes[number]; +#endif +} + + + +//! Returns a pointer to a child node, which has the same transformation as +//! the corresponding joint, if the mesh in this scene node is a skinned mesh. +IBoneSceneNode* CAnimatedMeshSceneNode::getJointNode(u32 jointID) +{ +#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ + os::Printer::log("Compiled without _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_", ELL_WARNING); + return 0; +#else + + if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED) + { + os::Printer::log("No mesh, or mesh not of skinned mesh type", ELL_WARNING); + return 0; + } + + checkJoints(); + + if (JointChildSceneNodes.size() <= jointID) + { + os::Printer::log("Joint not loaded into node", ELL_WARNING); + return 0; + } + + return JointChildSceneNodes[jointID]; +#endif +} + +//! Gets joint count. +u32 CAnimatedMeshSceneNode::getJointCount() const +{ +#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ + return 0; +#else + + if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED) + return 0; + + ISkinnedMesh *skinnedMesh=(ISkinnedMesh*)Mesh; + + return skinnedMesh->getJointCount(); +#endif +} + + +//! Removes a child from this scene node. +//! Implemented here, to be able to remove the shadow properly, if there is one, +//! or to remove attached childs. +bool CAnimatedMeshSceneNode::removeChild(ISceneNode* child) +{ + if (child && Shadow == child) + { + Shadow->drop(); + Shadow = 0; + } + + if (ISceneNode::removeChild(child)) + { + if (JointsUsed) //stop weird bugs caused while changing parents as the joints are being created + { + for (u32 i=0; igetMeshType() != EAMT_MD2) + return false; + + IAnimatedMeshMD2* md = (IAnimatedMeshMD2*)Mesh; + + s32 begin, end, speed; + md->getFrameLoop(anim, begin, end, speed); + + setAnimationSpeed( f32(speed) ); + setFrameLoop(begin, end); + return true; +} + + +//! Starts a special MD2 animation. +bool CAnimatedMeshSceneNode::setMD2Animation(const c8* animationName) +{ + if (!Mesh || Mesh->getMeshType() != EAMT_MD2) + return false; + + IAnimatedMeshMD2* md = (IAnimatedMeshMD2*)Mesh; + + s32 begin, end, speed; + if (!md->getFrameLoop(animationName, begin, end, speed)) + return false; + + setAnimationSpeed( (f32)speed ); + setFrameLoop(begin, end); + return true; +} + + +//! Sets looping mode which is on by default. If set to false, +//! animations will not be looped. +void CAnimatedMeshSceneNode::setLoopMode(bool playAnimationLooped) +{ + Looping = playAnimationLooped; +} + +//! returns the current loop mode +bool CAnimatedMeshSceneNode::getLoopMode() const +{ + return Looping; +} + + +//! Sets a callback interface which will be called if an animation +//! playback has ended. Set this to 0 to disable the callback again. +void CAnimatedMeshSceneNode::setAnimationEndCallback(IAnimationEndCallBack* callback) +{ + if (callback == LoopCallBack) + return; + + if (LoopCallBack) + LoopCallBack->drop(); + + LoopCallBack = callback; + + if (LoopCallBack) + LoopCallBack->grab(); +} + + +//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style. +void CAnimatedMeshSceneNode::setReadOnlyMaterials(bool readonly) +{ + ReadOnlyMaterials = readonly; +} + + +//! Returns if the scene node should not copy the materials of the mesh but use them in a read only style +bool CAnimatedMeshSceneNode::isReadOnlyMaterials() const +{ + return ReadOnlyMaterials; +} + + +//! Writes attributes of the scene node. +void CAnimatedMeshSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + IAnimatedMeshSceneNode::serializeAttributes(out, options); + + if (options && (options->Flags&io::EARWF_USE_RELATIVE_PATHS) && options->Filename) + { + const io::path path = SceneManager->getFileSystem()->getRelativeFilename( + SceneManager->getFileSystem()->getAbsolutePath(SceneManager->getMeshCache()->getMeshName(Mesh).getPath()), + options->Filename); + out->addString("Mesh", path.c_str()); + } + else + out->addString("Mesh", SceneManager->getMeshCache()->getMeshName(Mesh).getPath().c_str()); + out->addBool("Looping", Looping); + out->addBool("ReadOnlyMaterials", ReadOnlyMaterials); + out->addFloat("FramesPerSecond", FramesPerSecond); + out->addInt("StartFrame", StartFrame); + out->addInt("EndFrame", EndFrame); +} + + +//! Reads attributes of the scene node. +void CAnimatedMeshSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + IAnimatedMeshSceneNode::deserializeAttributes(in, options); + + io::path oldMeshStr = SceneManager->getMeshCache()->getMeshName(Mesh); + io::path newMeshStr = in->getAttributeAsString("Mesh"); + + Looping = in->getAttributeAsBool("Looping"); + ReadOnlyMaterials = in->getAttributeAsBool("ReadOnlyMaterials"); + FramesPerSecond = in->getAttributeAsFloat("FramesPerSecond"); + StartFrame = in->getAttributeAsInt("StartFrame"); + EndFrame = in->getAttributeAsInt("EndFrame"); + + if (newMeshStr != "" && oldMeshStr != newMeshStr) + { + IAnimatedMesh* newAnimatedMesh = SceneManager->getMesh(newMeshStr.c_str()); + + if (newAnimatedMesh) + setMesh(newAnimatedMesh); + } + + // TODO: read animation names instead of frame begin and ends +} + + +//! Sets a new mesh +void CAnimatedMeshSceneNode::setMesh(IAnimatedMesh* mesh) +{ + if (!mesh) + return; // won't set null mesh + + if (Mesh != mesh) + { + if (Mesh) + Mesh->drop(); + + Mesh = mesh; + + // grab the mesh (it's non-null!) + Mesh->grab(); + } + + // get materials and bounding box + Box = Mesh->getBoundingBox(); + + IMesh* m = Mesh->getMesh(0,0); + if (m) + { + Materials.clear(); + Materials.reallocate(m->getMeshBufferCount()); + + for (u32 i=0; igetMeshBufferCount(); ++i) + { + IMeshBuffer* mb = m->getMeshBuffer(i); + if (mb) + Materials.push_back(mb->getMaterial()); + else + Materials.push_back(video::SMaterial()); + } + } + + // clean up joint nodes + if (JointsUsed) + { + JointsUsed=false; + checkJoints(); + } + + // get start and begin time + setAnimationSpeed(Mesh->getAnimationSpeed()); // NOTE: This had been commented out (but not removed!) in r3526. Which caused meshloader-values for speed to be ignored unless users specified explicitly. Missing a test-case where this could go wrong so I put the code back in. + setFrameLoop(0, Mesh->getFrameCount()-1); +} + + +// returns the absolute transformation for a special MD3 Tag if the mesh is a md3 mesh, +// or the absolutetransformation if it's a normal scenenode +const SMD3QuaternionTag* CAnimatedMeshSceneNode::getMD3TagTransformation(const core::stringc& tagname) +{ + return MD3Special ? MD3Special->AbsoluteTagList.get(tagname) : 0; +} + + +//! updates the absolute position based on the relative and the parents position +void CAnimatedMeshSceneNode::updateAbsolutePosition() +{ + IAnimatedMeshSceneNode::updateAbsolutePosition(); + + if (!Mesh || Mesh->getMeshType() != EAMT_MD3) + return; + + SMD3QuaternionTagList *taglist; + taglist = ( (IAnimatedMeshMD3*) Mesh )->getTagList ( (s32)getFrameNr(),255,getStartFrame (),getEndFrame () ); + if (taglist) + { + if (!MD3Special) + { + MD3Special = new SMD3Special(); + } + + SMD3QuaternionTag parent ( MD3Special->Tagname ); + if (Parent && Parent->getType() == ESNT_ANIMATED_MESH) + { + const SMD3QuaternionTag * p = ((IAnimatedMeshSceneNode*) Parent)->getMD3TagTransformation + ( MD3Special->Tagname ); + + if (p) + parent = *p; + } + + SMD3QuaternionTag relative( RelativeTranslation, RelativeRotation ); + + MD3Special->AbsoluteTagList.set_used ( taglist->size () ); + for ( u32 i=0; i!= taglist->size (); ++i ) + { + MD3Special->AbsoluteTagList[i].position = parent.position + (*taglist)[i].position + relative.position; + MD3Special->AbsoluteTagList[i].rotation = parent.rotation * (*taglist)[i].rotation * relative.rotation; + } + } +} + +//! Set the joint update mode (0-unused, 1-get joints only, 2-set joints only, 3-move and set) +void CAnimatedMeshSceneNode::setJointMode(E_JOINT_UPDATE_ON_RENDER mode) +{ + checkJoints(); + JointMode=mode; +} + +//! Sets the transition time in seconds (note: This needs to enable joints, and setJointmode maybe set to 2) +//! you must call animateJoints(), or the mesh will not animate +void CAnimatedMeshSceneNode::setTransitionTime(f32 time) +{ + const u32 ttime = (u32)core::floor32(time*1000.0f); + if (TransitionTime==ttime) + return; + TransitionTime = ttime; + if (ttime != 0) + setJointMode(EJUOR_CONTROL); + else + setJointMode(EJUOR_NONE); +} + + +//! render mesh ignoring its transformation. Used with ragdolls. (culling is unaffected) +void CAnimatedMeshSceneNode::setRenderFromIdentity(bool enable) +{ + RenderFromIdentity=enable; +} + + +//! updates the joint positions of this mesh +void CAnimatedMeshSceneNode::animateJoints(bool CalculateAbsolutePositions) +{ +#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ + return; +#else + if (Mesh && Mesh->getMeshType() == EAMT_SKINNED ) + { + checkJoints(); + const f32 frame = getFrameNr(); //old? + + CSkinnedMesh* skinnedMesh=reinterpret_cast(Mesh); + + skinnedMesh->transferOnlyJointsHintsToMesh( JointChildSceneNodes ); + skinnedMesh->animateMesh(frame, 1.0f); + skinnedMesh->recoverJointsFromMesh( JointChildSceneNodes); + + //----------------------------------------- + // Transition + //----------------------------------------- + + if (Transiting != 0.f) + { + // Init additional matrices + if (PretransitingSave.size()setPosition( + core::lerp( + PretransitingSave[n].getTranslation(), + JointChildSceneNodes[n]->getPosition(), + TransitingBlend)); + + //------Rotation------ + + //Code is slow, needs to be fixed up + + const core::quaternion RotationStart(PretransitingSave[n].getRotationDegrees()*core::DEGTORAD); + const core::quaternion RotationEnd(JointChildSceneNodes[n]->getRotation()*core::DEGTORAD); + + core::quaternion QRotation; + QRotation.slerp(RotationStart, RotationEnd, TransitingBlend); + + core::vector3df tmpVector; + QRotation.toEuler(tmpVector); + tmpVector*=core::RADTODEG; //convert from radians back to degrees + JointChildSceneNodes[n]->setRotation( tmpVector ); + + //------Scale------ + + //JointChildSceneNodes[n]->setScale( + // core::lerp( + // PretransitingSave[n].getScale(), + // JointChildSceneNodes[n]->getScale(), + // TransitingBlend)); + } + } + + if (CalculateAbsolutePositions) + { + //---slow--- + for (u32 n=0;ngetParent()==this) + { + JointChildSceneNodes[n]->updateAbsolutePositionOfAllChildren(); //temp, should be an option + } + } + } + } +#endif +} + +/*! +*/ +void CAnimatedMeshSceneNode::checkJoints() +{ +#ifndef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ + return; +#else + + if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED) + return; + + if (!JointsUsed) + { + for (u32 i=0; iaddJoints(JointChildSceneNodes, this, SceneManager); + ((CSkinnedMesh*)Mesh)->recoverJointsFromMesh(JointChildSceneNodes); + + JointsUsed=true; + JointMode=EJUOR_READ; + } +#endif +} + +/*! +*/ +void CAnimatedMeshSceneNode::beginTransition() +{ + if (!JointsUsed) + return; + + if (TransitionTime != 0) + { + //Check the array is big enough + if (PretransitingSave.size()getRelativeTransformation(); + + Transiting = core::reciprocal((f32)TransitionTime); + } + TransitingBlend = 0.f; +} + + +/*! +*/ +ISceneNode* CAnimatedMeshSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager) +{ + if (!newParent) + newParent = Parent; + if (!newManager) + newManager = SceneManager; + + CAnimatedMeshSceneNode* newNode = + new CAnimatedMeshSceneNode(Mesh, NULL, newManager, ID, RelativeTranslation, + RelativeRotation, RelativeScale); + + if (newParent) + { + newNode->setParent(newParent); // not in constructor because virtual overload for updateAbsolutePosition won't be called + newNode->drop(); + } + + newNode->cloneMembers(this, newManager); + + newNode->Materials = Materials; + newNode->Box = Box; + newNode->Mesh = Mesh; + newNode->StartFrame = StartFrame; + newNode->EndFrame = EndFrame; + newNode->FramesPerSecond = FramesPerSecond; + newNode->CurrentFrameNr = CurrentFrameNr; + newNode->JointMode = JointMode; + newNode->JointsUsed = JointsUsed; + newNode->TransitionTime = TransitionTime; + newNode->Transiting = Transiting; + newNode->TransitingBlend = TransitingBlend; + newNode->Looping = Looping; + newNode->ReadOnlyMaterials = ReadOnlyMaterials; + newNode->LoopCallBack = LoopCallBack; + if (newNode->LoopCallBack) + newNode->LoopCallBack->grab(); + newNode->PassCount = PassCount; + newNode->Shadow = Shadow; + if (newNode->Shadow) + newNode->Shadow->grab(); + newNode->JointChildSceneNodes = JointChildSceneNodes; + newNode->PretransitingSave = PretransitingSave; + newNode->RenderFromIdentity = RenderFromIdentity; + newNode->MD3Special = MD3Special; + + return newNode; +} + + +} // end namespace scene +} // end namespace irr diff --git a/source/Irrlicht/CAnimatedMeshSceneNode.h b/source/Irrlicht/CAnimatedMeshSceneNode.h new file mode 100644 index 00000000..6a5914e9 --- /dev/null +++ b/source/Irrlicht/CAnimatedMeshSceneNode.h @@ -0,0 +1,223 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_ANIMATED_MESH_SCENE_NODE_H_INCLUDED__ +#define __C_ANIMATED_MESH_SCENE_NODE_H_INCLUDED__ + +#include "IAnimatedMeshSceneNode.h" +#include "IAnimatedMesh.h" + +#include "matrix4.h" + + +namespace irr +{ +namespace scene +{ + class IDummyTransformationSceneNode; + + class CAnimatedMeshSceneNode : public IAnimatedMeshSceneNode + { + public: + + //! constructor + CAnimatedMeshSceneNode(IAnimatedMesh* mesh, ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)); + + //! destructor + virtual ~CAnimatedMeshSceneNode(); + + //! sets the current frame. from now on the animation is played from this frame. + virtual void setCurrentFrame(f32 frame) _IRR_OVERRIDE_; + + //! frame + virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; + + //! OnAnimate() is called just before rendering the whole scene. + virtual void OnAnimate(u32 timeMs) _IRR_OVERRIDE_; + + //! renders the node. + virtual void render() _IRR_OVERRIDE_; + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + //! sets the frames between the animation is looped. + //! the default is 0 - MaximalFrameCount of the mesh. + //! NOTE: setMesh will also change this value and set it to the full range of animations of the mesh + virtual bool setFrameLoop(s32 begin, s32 end) _IRR_OVERRIDE_; + + //! Sets looping mode which is on by default. If set to false, + //! animations will not be looped. + virtual void setLoopMode(bool playAnimationLooped) _IRR_OVERRIDE_; + + //! returns the current loop mode + virtual bool getLoopMode() const _IRR_OVERRIDE_; + + //! Sets a callback interface which will be called if an animation + //! playback has ended. Set this to 0 to disable the callback again. + virtual void setAnimationEndCallback(IAnimationEndCallBack* callback=0) _IRR_OVERRIDE_; + + //! sets the speed with which the animation is played + //! NOTE: setMesh will also change this value and set it to the default speed of the mesh + virtual void setAnimationSpeed(f32 framesPerSecond) _IRR_OVERRIDE_; + + //! gets the speed with which the animation is played + virtual f32 getAnimationSpeed() const _IRR_OVERRIDE_; + + //! returns the material based on the zero based index i. To get the amount + //! of materials used by this scene node, use getMaterialCount(). + //! This function is needed for inserting the node into the scene hierarchy on a + //! optimal position for minimizing renderstate changes, but can also be used + //! to directly modify the material of a scene node. + virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_; + + //! returns amount of materials used by this scene node. + virtual u32 getMaterialCount() const _IRR_OVERRIDE_; + + //! Creates shadow volume scene node as child of this node + //! and returns a pointer to it. + virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh, + s32 id, bool zfailmethod=true, f32 infinity=1000.0f) _IRR_OVERRIDE_; + + //! Returns a pointer to a child node, which has the same transformation as + //! the corresponding joint, if the mesh in this scene node is a skinned mesh. + virtual IBoneSceneNode* getJointNode(const c8* jointName) _IRR_OVERRIDE_; + + //! same as getJointNode(const c8* jointName), but based on id + virtual IBoneSceneNode* getJointNode(u32 jointID) _IRR_OVERRIDE_; + + //! Gets joint count. + virtual u32 getJointCount() const _IRR_OVERRIDE_; + + //! Removes a child from this scene node. + //! Implemented here, to be able to remove the shadow properly, if there is one, + //! or to remove attached child. + virtual bool removeChild(ISceneNode* child) _IRR_OVERRIDE_; + + //! Starts a MD2 animation. + virtual bool setMD2Animation(EMD2_ANIMATION_TYPE anim) _IRR_OVERRIDE_; + + //! Starts a special MD2 animation. + virtual bool setMD2Animation(const c8* animationName) _IRR_OVERRIDE_; + + //! Returns the current displayed frame number. + virtual f32 getFrameNr() const _IRR_OVERRIDE_; + //! Returns the current start frame number. + virtual s32 getStartFrame() const _IRR_OVERRIDE_; + //! Returns the current end frame number. + virtual s32 getEndFrame() const _IRR_OVERRIDE_; + + //! Sets if the scene node should not copy the materials of the mesh but use them in a read only style. + /* In this way it is possible to change the materials a mesh causing all mesh scene nodes + referencing this mesh to change too. */ + virtual void setReadOnlyMaterials(bool readonly) _IRR_OVERRIDE_; + + //! Returns if the scene node should not copy the materials of the mesh but use them in a read only style + virtual bool isReadOnlyMaterials() const _IRR_OVERRIDE_; + + //! Sets a new mesh + virtual void setMesh(IAnimatedMesh* mesh) _IRR_OVERRIDE_; + + //! Returns the current mesh + virtual IAnimatedMesh* getMesh(void) _IRR_OVERRIDE_ { return Mesh; } + + //! Writes attributes of the scene node. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_ANIMATED_MESH; } + + // returns the absolute transformation for a special MD3 Tag if the mesh is a md3 mesh, + // or the absolutetransformation if it's a normal scenenode + const SMD3QuaternionTag* getMD3TagTransformation( const core::stringc & tagname) _IRR_OVERRIDE_; + + //! updates the absolute position based on the relative and the parents position + virtual void updateAbsolutePosition() _IRR_OVERRIDE_; + + + //! Set the joint update mode (0-unused, 1-get joints only, 2-set joints only, 3-move and set) + virtual void setJointMode(E_JOINT_UPDATE_ON_RENDER mode) _IRR_OVERRIDE_; + + //! Sets the transition time in seconds (note: This needs to enable joints, and setJointmode maybe set to 2) + //! you must call animateJoints(), or the mesh will not animate + virtual void setTransitionTime(f32 Time) _IRR_OVERRIDE_; + + //! updates the joint positions of this mesh + virtual void animateJoints(bool CalculateAbsolutePositions=true) _IRR_OVERRIDE_; + + //! render mesh ignoring its transformation. Used with ragdolls. (culling is unaffected) + virtual void setRenderFromIdentity( bool On ) _IRR_OVERRIDE_; + + //! Creates a clone of this scene node and its children. + /** \param newParent An optional new parent. + \param newManager An optional new scene manager. + \return The newly created clone of this node. */ + virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + private: + + //! Get a static mesh for the current frame of this animated mesh + IMesh* getMeshForCurrentFrame(); + + void buildFrameNr(u32 timeMs); + void checkJoints(); + void beginTransition(); + + core::array Materials; + core::aabbox3d Box; + IAnimatedMesh* Mesh; + + s32 StartFrame; + s32 EndFrame; + f32 FramesPerSecond; + f32 CurrentFrameNr; + + u32 LastTimeMs; + u32 TransitionTime; //Transition time in millisecs + f32 Transiting; //is mesh transiting (plus cache of TransitionTime) + f32 TransitingBlend; //0-1, calculated on buildFrameNr + + //0-unused, 1-get joints only, 2-set joints only, 3-move and set + E_JOINT_UPDATE_ON_RENDER JointMode; + bool JointsUsed; + + bool Looping; + bool ReadOnlyMaterials; + bool RenderFromIdentity; + + IAnimationEndCallBack* LoopCallBack; + s32 PassCount; + + IShadowVolumeSceneNode* Shadow; + + core::array JointChildSceneNodes; + core::array PretransitingSave; + + // Quake3 Model + struct SMD3Special : public virtual IReferenceCounted + { + core::stringc Tagname; + SMD3QuaternionTagList AbsoluteTagList; + + SMD3Special & operator = (const SMD3Special & copyMe) + { + Tagname = copyMe.Tagname; + AbsoluteTagList = copyMe.AbsoluteTagList; + return *this; + } + }; + SMD3Special *MD3Special; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CAttributeImpl.h b/source/Irrlicht/CAttributeImpl.h new file mode 100644 index 00000000..3796fed9 --- /dev/null +++ b/source/Irrlicht/CAttributeImpl.h @@ -0,0 +1,2093 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CAttributes.h" +#include "fast_atof.h" +#include "ITexture.h" +#include "IVideoDriver.h" + +namespace irr +{ +namespace io +{ + +/* + Basic types, check documentation in IAttribute.h to see how they generally work. +*/ + +// Attribute implemented for boolean values +class CBoolAttribute : public IAttribute +{ +public: + + CBoolAttribute(const char* name, bool value) + { + Name = name; + setBool(value); + } + + virtual s32 getInt() const _IRR_OVERRIDE_ + { + return BoolValue ? 1 : 0; + } + + virtual f32 getFloat() const _IRR_OVERRIDE_ + { + return BoolValue ? 1.0f : 0.0f; + } + + virtual bool getBool() const _IRR_OVERRIDE_ + { + return BoolValue; + } + + virtual core::stringw getStringW() const _IRR_OVERRIDE_ + { + return core::stringw( BoolValue ? L"true" : L"false" ); + } + + virtual void setInt(s32 intValue) _IRR_OVERRIDE_ + { + BoolValue = (intValue != 0); + } + + virtual void setFloat(f32 floatValue) _IRR_OVERRIDE_ + { + BoolValue = (floatValue != 0); + } + + virtual void setBool(bool boolValue) _IRR_OVERRIDE_ + { + BoolValue = boolValue; + } + + virtual void setString(const char* string) _IRR_OVERRIDE_ + { + BoolValue = strcmp(string, "true") == 0; + } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_BOOL; + } + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"bool"; + } + + bool BoolValue; +}; + +// Attribute implemented for integers +class CIntAttribute : public IAttribute +{ +public: + + CIntAttribute(const char* name, s32 value) + { + Name = name; + setInt(value); + } + + virtual s32 getInt() const _IRR_OVERRIDE_ + { + return Value; + } + + virtual f32 getFloat() const _IRR_OVERRIDE_ + { + return (f32)Value; + } + + virtual bool getBool() const _IRR_OVERRIDE_ + { + return (Value != 0); + } + + virtual core::stringw getStringW() const _IRR_OVERRIDE_ + { + return core::stringw(Value); + } + + virtual void setInt(s32 intValue) _IRR_OVERRIDE_ + { + Value = intValue; + } + + virtual void setFloat(f32 floatValue) _IRR_OVERRIDE_ + { + Value = (s32)floatValue; + }; + + virtual void setString(const char* text) _IRR_OVERRIDE_ + { + Value = atoi(text); + } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_INT; + } + + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"int"; + } + + s32 Value; +}; + +// Attribute implemented for floats +class CFloatAttribute : public IAttribute +{ +public: + + CFloatAttribute(const char* name, f32 value) + { + Name = name; + setFloat(value); + } + + virtual s32 getInt() const _IRR_OVERRIDE_ + { + return (s32)Value; + } + + virtual f32 getFloat() const _IRR_OVERRIDE_ + { + return Value; + } + + virtual bool getBool() const _IRR_OVERRIDE_ + { + return (Value != 0); + } + + virtual core::stringw getStringW() const _IRR_OVERRIDE_ + { + return core::stringw((double)Value); + } + + virtual void setInt(s32 intValue) _IRR_OVERRIDE_ + { + Value = (f32)intValue; + } + + virtual void setFloat(f32 floatValue) _IRR_OVERRIDE_ + { + Value = floatValue; + } + + virtual void setString(const char* text) _IRR_OVERRIDE_ + { + Value = core::fast_atof(text); + } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_FLOAT; + } + + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"float"; + } + + f32 Value; +}; + + + +/* + Types which can be represented as a list of numbers +*/ + +// Base class for all attributes which are a list of numbers- +// vectors, colors, positions, triangles, etc +class CNumbersAttribute : public IAttribute +{ +public: + + CNumbersAttribute(const char* name, video::SColorf value) : + ValueI(), ValueF(), Count(4), IsFloat(true) + { + Name = name; + ValueF.push_back(value.r); + ValueF.push_back(value.g); + ValueF.push_back(value.b); + ValueF.push_back(value.a); + } + + CNumbersAttribute(const char* name, video::SColor value) : + ValueI(), ValueF(), Count(4), IsFloat(false) + { + Name = name; + ValueI.push_back(value.getRed()); + ValueI.push_back(value.getGreen()); + ValueI.push_back(value.getBlue()); + ValueI.push_back(value.getAlpha()); + } + + + CNumbersAttribute(const char* name, const core::vector3df& value) : + ValueI(), ValueF(), Count(3), IsFloat(true) + { + Name = name; + ValueF.push_back(value.X); + ValueF.push_back(value.Y); + ValueF.push_back(value.Z); + } + + CNumbersAttribute(const char* name, const core::rect& value) : + ValueI(), ValueF(), Count(4), IsFloat(false) + { + Name = name; + ValueI.push_back(value.UpperLeftCorner.X); + ValueI.push_back(value.UpperLeftCorner.Y); + ValueI.push_back(value.LowerRightCorner.X); + ValueI.push_back(value.LowerRightCorner.Y); + } + + CNumbersAttribute(const char* name, const core::rect& value) : + ValueI(), ValueF(), Count(4), IsFloat(true) + { + Name = name; + ValueF.push_back(value.UpperLeftCorner.X); + ValueF.push_back(value.UpperLeftCorner.Y); + ValueF.push_back(value.LowerRightCorner.X); + ValueF.push_back(value.LowerRightCorner.Y); + } + + CNumbersAttribute(const char* name, const core::matrix4& value) : + ValueI(), ValueF(), Count(16), IsFloat(true) + { + Name = name; + for (s32 r=0; r<4; ++r) + for (s32 c=0; c<4; ++c) + ValueF.push_back(value(r,c)); + } + + CNumbersAttribute(const char* name, const core::quaternion& value) : + ValueI(), ValueF(), Count(4), IsFloat(true) + { + Name = name; + ValueF.push_back(value.X); + ValueF.push_back(value.Y); + ValueF.push_back(value.Z); + ValueF.push_back(value.W); + } + + CNumbersAttribute(const char* name, const core::aabbox3d& value) : + ValueI(), ValueF(), Count(6), IsFloat(true) + { + Name = name; + ValueF.push_back(value.MinEdge.X); + ValueF.push_back(value.MinEdge.Y); + ValueF.push_back(value.MinEdge.Z); + ValueF.push_back(value.MaxEdge.X); + ValueF.push_back(value.MaxEdge.Y); + ValueF.push_back(value.MaxEdge.Z); + } + + CNumbersAttribute(const char* name, const core::plane3df& value) : + ValueI(), ValueF(), Count(4), IsFloat(true) + { + Name = name; + ValueF.push_back(value.Normal.X); + ValueF.push_back(value.Normal.Y); + ValueF.push_back(value.Normal.Z); + ValueF.push_back(value.D); + } + + CNumbersAttribute(const char* name, const core::triangle3df& value) : + ValueI(), ValueF(), Count(9), IsFloat(true) + { + Name = name; + ValueF.push_back(value.pointA.X); + ValueF.push_back(value.pointA.Y); + ValueF.push_back(value.pointA.Z); + ValueF.push_back(value.pointB.X); + ValueF.push_back(value.pointB.Y); + ValueF.push_back(value.pointB.Z); + ValueF.push_back(value.pointC.X); + ValueF.push_back(value.pointC.Y); + ValueF.push_back(value.pointC.Z); + } + + CNumbersAttribute(const char* name, const core::vector2df& value) : + ValueI(), ValueF(), Count(2), IsFloat(true) + { + Name = name; + ValueF.push_back(value.X); + ValueF.push_back(value.Y); + } + + CNumbersAttribute(const char* name, const core::vector2di& value) : + ValueI(), ValueF(), Count(2), IsFloat(false) + { + Name = name; + ValueI.push_back(value.X); + ValueI.push_back(value.Y); + } + + CNumbersAttribute(const char* name, const core::line2di& value) : + ValueI(), ValueF(), Count(4), IsFloat(false) + { + Name = name; + ValueI.push_back(value.start.X); + ValueI.push_back(value.start.Y); + ValueI.push_back(value.end.X); + ValueI.push_back(value.end.Y); + } + + CNumbersAttribute(const char* name, const core::line2df& value) : + ValueI(), ValueF(), Count(4), IsFloat(true) + { + Name = name; + ValueF.push_back(value.start.X); + ValueF.push_back(value.start.Y); + ValueF.push_back(value.end.X); + ValueF.push_back(value.end.Y); + } + + CNumbersAttribute(const char* name, const core::line3df& value) : + ValueI(), ValueF(), Count(6), IsFloat(true) + { + Name = name; + ValueF.push_back(value.start.X); + ValueF.push_back(value.start.Y); + ValueF.push_back(value.start.Z); + ValueF.push_back(value.end.X); + ValueF.push_back(value.end.Y); + ValueF.push_back(value.end.Z); + } + + CNumbersAttribute(const char* name, const core::dimension2du& value) : + ValueI(), ValueF(), Count(2), IsFloat(false) + { + Name = name; + ValueI.push_back(value.Width); + ValueI.push_back(value.Height); + } + + + CNumbersAttribute(const char* name, const core::dimension2df& value) : + ValueI(), ValueF(), Count(2), IsFloat(true) + { + Name = name; + ValueF.push_back(value.Width); + ValueF.push_back(value.Height); + } + + // getting values + virtual s32 getInt() const _IRR_OVERRIDE_ + { + if (Count==0) + return 0; + + if (IsFloat) + return (s32)ValueF[0]; + else + return ValueI[0]; + } + + virtual f32 getFloat() const _IRR_OVERRIDE_ + { + if (Count==0) + return 0.0f; + + if (IsFloat) + return ValueF[0]; + else + return (f32)ValueI[0]; + } + + virtual bool getBool() const _IRR_OVERRIDE_ + { + // 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) ) + { + ret=true; + break; + } + + return ret; + } + + + virtual core::stringc getString() const _IRR_OVERRIDE_ + { + core::stringc outstr; + + for (u32 i=0; i 0 ? ValueF[0] : 0); + p.Y = (s32)(Count > 1 ? ValueF[1] : 0); + } + else + { + p.X = Count > 0 ? ValueI[0] : 0; + p.Y = Count > 1 ? ValueI[1] : 0; + } + + return p; + } + + virtual core::vector3df getVector() const _IRR_OVERRIDE_ + { + core::vector3df v; + + if (IsFloat) + { + v.X = Count > 0 ? ValueF[0] : 0; + v.Y = Count > 1 ? ValueF[1] : 0; + v.Z = Count > 2 ? ValueF[2] : 0; + } + else + { + v.X = (f32)(Count > 0 ? ValueI[0] : 0); + v.Y = (f32)(Count > 1 ? ValueI[1] : 0); + v.Z = (f32)(Count > 2 ? ValueI[2] : 0); + } + + return v; + } + + virtual core::vector2df getVector2d() const _IRR_OVERRIDE_ + { + core::vector2df v; + + if (IsFloat) + { + v.X = Count > 0 ? ValueF[0] : 0; + v.Y = Count > 1 ? ValueF[1] : 0; + } + else + { + v.X = (f32)(Count > 0 ? ValueI[0] : 0); + v.Y = (f32)(Count > 1 ? ValueI[1] : 0); + } + + return v; + } + + virtual video::SColorf getColorf() const _IRR_OVERRIDE_ + { + video::SColorf c; + if (IsFloat) + { + c.setColorComponentValue(0, Count > 0 ? ValueF[0] : 0); + c.setColorComponentValue(1, Count > 1 ? ValueF[1] : 0); + c.setColorComponentValue(2, Count > 2 ? ValueF[2] : 0); + c.setColorComponentValue(3, Count > 3 ? ValueF[3] : 0); + } + else + { + c.setColorComponentValue(0, Count > 0 ? (f32)(ValueI[0]) / 255.0f : 0); + c.setColorComponentValue(1, Count > 1 ? (f32)(ValueI[1]) / 255.0f : 0); + c.setColorComponentValue(2, Count > 2 ? (f32)(ValueI[2]) / 255.0f : 0); + c.setColorComponentValue(3, Count > 3 ? (f32)(ValueI[3]) / 255.0f : 0); + } + + return c; + } + + virtual video::SColor getColor() const _IRR_OVERRIDE_ + { + return getColorf().toSColor(); + } + + + virtual core::rect getRect() const _IRR_OVERRIDE_ + { + core::rect r; + + if (IsFloat) + { + r.UpperLeftCorner.X = (s32)(Count > 0 ? ValueF[0] : 0); + r.UpperLeftCorner.Y = (s32)(Count > 1 ? ValueF[1] : 0); + r.LowerRightCorner.X = (s32)(Count > 2 ? ValueF[2] : r.UpperLeftCorner.X); + r.LowerRightCorner.Y = (s32)(Count > 3 ? ValueF[3] : r.UpperLeftCorner.Y); + } + else + { + r.UpperLeftCorner.X = Count > 0 ? ValueI[0] : 0; + r.UpperLeftCorner.Y = Count > 1 ? ValueI[1] : 0; + r.LowerRightCorner.X = Count > 2 ? ValueI[2] : r.UpperLeftCorner.X; + r.LowerRightCorner.Y = Count > 3 ? ValueI[3] : r.UpperLeftCorner.Y; + } + return r; + } + + virtual core::dimension2du getDimension2d() const _IRR_OVERRIDE_ + { + core::dimension2d dim; + + if (IsFloat) + { + dim.Width = (u32)(Count > 0 ? ValueF[0] : 0); + dim.Height = (u32)(Count > 1 ? ValueF[1] : 0); + } + else + { + dim.Width = (u32)(Count > 0 ? ValueI[0] : 0); + dim.Height = (u32)(Count > 1 ? ValueI[1] : 0); + } + return dim; + } + + virtual core::matrix4 getMatrix() const _IRR_OVERRIDE_ + { + core::matrix4 ret; + if (IsFloat) + { + for (u32 r=0; r<4; ++r) + for (u32 c=0; c<4; ++c) + 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) + ret(r,c) = (f32)ValueI[c+r*4]; + } + return ret; + } + + virtual core::quaternion getQuaternion() const _IRR_OVERRIDE_ + { + core::quaternion ret; + if (IsFloat) + { + ret.X = Count > 0 ? ValueF[0] : 0.0f; + ret.Y = Count > 1 ? ValueF[1] : 0.0f; + ret.Z = Count > 2 ? ValueF[2] : 0.0f; + ret.W = Count > 3 ? ValueF[3] : 0.0f; + } + else + { + ret.X = Count > 0 ? (f32)ValueI[0] : 0.0f; + ret.Y = Count > 1 ? (f32)ValueI[1] : 0.0f; + ret.Z = Count > 2 ? (f32)ValueI[2] : 0.0f; + ret.W = Count > 3 ? (f32)ValueI[3] : 0.0f; + } + return ret; + } + + virtual core::triangle3df getTriangle() const _IRR_OVERRIDE_ + { + core::triangle3df ret; + + if (IsFloat) + { + ret.pointA.X = Count > 0 ? ValueF[0] : 0.0f; + ret.pointA.Y = Count > 1 ? ValueF[1] : 0.0f; + ret.pointA.Z = Count > 2 ? ValueF[2] : 0.0f; + ret.pointB.X = Count > 3 ? ValueF[3] : 0.0f; + ret.pointB.Y = Count > 4 ? ValueF[4] : 0.0f; + ret.pointB.Z = Count > 5 ? ValueF[5] : 0.0f; + ret.pointC.X = Count > 6 ? ValueF[6] : 0.0f; + ret.pointC.Y = Count > 7 ? ValueF[7] : 0.0f; + ret.pointC.Z = Count > 8 ? ValueF[8] : 0.0f; + } + else + { + ret.pointA.X = Count > 0 ? (f32)ValueI[0] : 0.0f; + ret.pointA.Y = Count > 1 ? (f32)ValueI[1] : 0.0f; + ret.pointA.Z = Count > 2 ? (f32)ValueI[2] : 0.0f; + ret.pointB.X = Count > 3 ? (f32)ValueI[3] : 0.0f; + ret.pointB.Y = Count > 4 ? (f32)ValueI[4] : 0.0f; + ret.pointB.Z = Count > 5 ? (f32)ValueI[5] : 0.0f; + ret.pointC.X = Count > 6 ? (f32)ValueI[6] : 0.0f; + ret.pointC.Y = Count > 7 ? (f32)ValueI[7] : 0.0f; + ret.pointC.Z = Count > 8 ? (f32)ValueI[8] : 0.0f; + } + + return ret; + } + + virtual core::plane3df getPlane() const _IRR_OVERRIDE_ + { + core::plane3df ret; + + if (IsFloat) + { + ret.Normal.X = Count > 0 ? ValueF[0] : 0.0f; + ret.Normal.Y = Count > 1 ? ValueF[1] : 0.0f; + ret.Normal.Z = Count > 2 ? ValueF[2] : 0.0f; + ret.D = Count > 3 ? ValueF[3] : 0.0f; + } + else + { + ret.Normal.X = Count > 0 ? (f32)ValueI[0] : 0.0f; + ret.Normal.Y = Count > 1 ? (f32)ValueI[1] : 0.0f; + ret.Normal.Z = Count > 2 ? (f32)ValueI[2] : 0.0f; + ret.D = Count > 3 ? (f32)ValueI[3] : 0.0f; + } + + return ret; + } + + virtual core::aabbox3df getBBox() const _IRR_OVERRIDE_ + { + core::aabbox3df ret; + if (IsFloat) + { + ret.MinEdge.X = Count > 0 ? ValueF[0] : 0.0f; + ret.MinEdge.Y = Count > 1 ? ValueF[1] : 0.0f; + ret.MinEdge.Z = Count > 2 ? ValueF[2] : 0.0f; + ret.MaxEdge.X = Count > 3 ? ValueF[3] : 0.0f; + ret.MaxEdge.Y = Count > 4 ? ValueF[4] : 0.0f; + ret.MaxEdge.Z = Count > 5 ? ValueF[5] : 0.0f; + } + else + { + ret.MinEdge.X = Count > 0 ? (f32)ValueI[0] : 0.0f; + ret.MinEdge.Y = Count > 1 ? (f32)ValueI[1] : 0.0f; + ret.MinEdge.Z = Count > 2 ? (f32)ValueI[2] : 0.0f; + ret.MaxEdge.X = Count > 3 ? (f32)ValueI[3] : 0.0f; + ret.MaxEdge.Y = Count > 4 ? (f32)ValueI[4] : 0.0f; + ret.MaxEdge.Z = Count > 5 ? (f32)ValueI[5] : 0.0f; + } + return ret; + + } + + virtual core::line2df getLine2d() const _IRR_OVERRIDE_ + { + core::line2df ret; + if (IsFloat) + { + ret.start.X = Count > 0 ? ValueF[0] : 0.0f; + ret.start.Y = Count > 1 ? ValueF[1] : 0.0f; + ret.end.X = Count > 2 ? ValueF[2] : 0.0f; + ret.end.Y = Count > 3 ? ValueF[3] : 0.0f; + } + else + { + ret.start.X = Count > 0 ? (f32)ValueI[0] : 0.0f; + ret.start.Y = Count > 1 ? (f32)ValueI[1] : 0.0f; + ret.end.X = Count > 2 ? (f32)ValueI[2] : 0.0f; + ret.end.Y = Count > 3 ? (f32)ValueI[3] : 0.0f; + } + return ret; + } + + virtual core::line3df getLine3d() const _IRR_OVERRIDE_ + { + core::line3df ret; + if (IsFloat) + { + ret.start.X = Count > 0 ? ValueF[0] : 0.0f; + ret.start.Y = Count > 1 ? ValueF[1] : 0.0f; + ret.start.Z = Count > 2 ? ValueF[2] : 0.0f; + ret.end.X = Count > 3 ? ValueF[3] : 0.0f; + ret.end.Y = Count > 4 ? ValueF[4] : 0.0f; + ret.end.Z = Count > 5 ? ValueF[5] : 0.0f; + } + else + { + ret.start.X = Count > 0 ? (f32)ValueI[0] : 0.0f; + ret.start.Y = Count > 1 ? (f32)ValueI[1] : 0.0f; + ret.start.Z = Count > 2 ? (f32)ValueI[2] : 0.0f; + ret.end.X = Count > 3 ? (f32)ValueI[3] : 0.0f; + ret.end.Y = Count > 4 ? (f32)ValueI[4] : 0.0f; + ret.end.Z = Count > 5 ? (f32)ValueI[5] : 0.0f; + } + return ret; + } + + //! get float array + virtual core::array getFloatArray() + { + if (!IsFloat) + { + ValueF.clear(); + for (u32 i=0; i getIntArray() + { + if (IsFloat) + { + ValueI.clear(); + for (u32 i=0; i '9') ) ) + ++P; + + // set value + if ( *P) + { + if (IsFloat) + { + f32 c = 0; + P = core::fast_atof_move(P, c); + ValueF[i] = c; + } + else + { + // todo: fix this to read ints properly + f32 c = 0; + P = core::fast_atof_move(P, c); + ValueI[i] = (s32)c; + + } + } + } + // todo: warning message + //if (i < Count-1) + //{ + // + //} + } + + virtual void setPosition(const core::position2di& v) _IRR_OVERRIDE_ + { + reset(); + if (IsFloat) + { + if (Count > 0) ValueF[0] = (f32)v.X; + if (Count > 1) ValueF[1] = (f32)v.Y; + } + else + { + if (Count > 0) ValueI[0] = v.X; + if (Count > 1) ValueI[1] = v.Y; + } + } + + virtual void setVector(const core::vector3df& v) _IRR_OVERRIDE_ + { + reset(); + if (IsFloat) + { + if (Count > 0) ValueF[0] = v.X; + if (Count > 1) ValueF[1] = v.Y; + if (Count > 2) ValueF[2] = v.Z; + } + else + { + if (Count > 0) ValueI[0] = (s32)v.X; + if (Count > 1) ValueI[1] = (s32)v.Y; + if (Count > 2) ValueI[2] = (s32)v.Z; + } + } + + virtual void setColor(video::SColorf color) _IRR_OVERRIDE_ + { + reset(); + if (IsFloat) + { + if (Count > 0) ValueF[0] = color.r; + if (Count > 1) ValueF[1] = color.g; + if (Count > 2) ValueF[2] = color.b; + if (Count > 3) ValueF[3] = color.a; + } + else + { + if (Count > 0) ValueI[0] = (s32)(color.r * 255); + if (Count > 1) ValueI[1] = (s32)(color.g * 255); + if (Count > 2) ValueI[2] = (s32)(color.b * 255); + if (Count > 3) ValueI[3] = (s32)(color.a * 255); + } + + } + + virtual void setColor(video::SColor color) _IRR_OVERRIDE_ + { + reset(); + if (IsFloat) + { + if (Count > 0) ValueF[0] = (f32)color.getRed() / 255.0f; + if (Count > 1) ValueF[1] = (f32)color.getGreen() / 255.0f; + if (Count > 2) ValueF[2] = (f32)color.getBlue() / 255.0f; + if (Count > 3) ValueF[3] = (f32)color.getAlpha() / 255.0f; + } + else + { + if (Count > 0) ValueI[0] = color.getRed(); + if (Count > 1) ValueI[1] = color.getGreen(); + if (Count > 2) ValueI[2] = color.getBlue(); + if (Count > 3) ValueI[3] = color.getAlpha(); + } + } + + virtual void setRect(const core::rect& value) _IRR_OVERRIDE_ + { + reset(); + if (IsFloat) + { + if (Count > 0) ValueF[0] = (f32)value.UpperLeftCorner.X; + if (Count > 1) ValueF[1] = (f32)value.UpperLeftCorner.Y; + if (Count > 2) ValueF[2] = (f32)value.LowerRightCorner.X; + if (Count > 3) ValueF[3] = (f32)value.LowerRightCorner.Y; + } + else + { + if (Count > 0) ValueI[0] = value.UpperLeftCorner.X; + if (Count > 1) ValueI[1] = value.UpperLeftCorner.Y; + if (Count > 2) ValueI[2] = value.LowerRightCorner.X; + if (Count > 3) ValueI[3] = value.LowerRightCorner.Y; + } + } + + virtual void setMatrix(const core::matrix4& value) _IRR_OVERRIDE_ + { + reset(); + if (IsFloat) + { + for (u32 r=0; r<4; ++r) + for (u32 c=0; c<4; ++c) + 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) + ValueI[c+r*4] = (s32)value(r,c); + } + } + + virtual void setQuaternion(const core::quaternion& value) _IRR_OVERRIDE_ + { + reset(); + if (IsFloat) + { + if (Count > 0) ValueF[0] = value.X; + if (Count > 1) ValueF[1] = value.Y; + if (Count > 2) ValueF[2] = value.Z; + if (Count > 3) ValueF[3] = value.W; + } + else + { + if (Count > 0) ValueI[0] = (s32)value.X; + if (Count > 1) ValueI[1] = (s32)value.Y; + if (Count > 2) ValueI[2] = (s32)value.Z; + if (Count > 3) ValueI[3] = (s32)value.W; + } + } + + virtual void setBoundingBox(const core::aabbox3d& value) + { + reset(); + if (IsFloat) + { + if (Count > 0) ValueF[0] = value.MinEdge.X; + if (Count > 1) ValueF[1] = value.MinEdge.Y; + if (Count > 2) ValueF[2] = value.MinEdge.Z; + if (Count > 3) ValueF[3] = value.MaxEdge.X; + if (Count > 4) ValueF[4] = value.MaxEdge.Y; + if (Count > 5) ValueF[5] = value.MaxEdge.Z; + } + else + { + if (Count > 0) ValueI[0] = (s32)value.MinEdge.X; + if (Count > 1) ValueI[1] = (s32)value.MinEdge.Y; + if (Count > 2) ValueI[2] = (s32)value.MinEdge.Z; + if (Count > 3) ValueI[3] = (s32)value.MaxEdge.X; + if (Count > 4) ValueI[4] = (s32)value.MaxEdge.Y; + if (Count > 5) ValueI[5] = (s32)value.MaxEdge.Z; + } + } + + virtual void setPlane(const core::plane3df& value) _IRR_OVERRIDE_ + { + reset(); + if (IsFloat) + { + if (Count > 0) ValueF[0] = value.Normal.X; + if (Count > 1) ValueF[1] = value.Normal.Y; + if (Count > 2) ValueF[2] = value.Normal.Z; + if (Count > 3) ValueF[3] = value.D; + } + else + { + if (Count > 0) ValueI[0] = (s32)value.Normal.X; + if (Count > 1) ValueI[1] = (s32)value.Normal.Y; + if (Count > 2) ValueI[2] = (s32)value.Normal.Z; + if (Count > 3) ValueI[3] = (s32)value.D; + } + } + + virtual void setTriangle3d(const core::triangle3df& value) + { + reset(); + if (IsFloat) + { + if (Count > 0) ValueF[0] = value.pointA.X; + if (Count > 1) ValueF[1] = value.pointA.Y; + if (Count > 2) ValueF[2] = value.pointA.Z; + if (Count > 3) ValueF[3] = value.pointB.X; + if (Count > 4) ValueF[4] = value.pointB.Y; + if (Count > 5) ValueF[5] = value.pointB.Z; + if (Count > 6) ValueF[6] = value.pointC.X; + if (Count > 7) ValueF[7] = value.pointC.Y; + if (Count > 8) ValueF[8] = value.pointC.Z; + } + else + { + if (Count > 0) ValueI[0] = (s32)value.pointA.X; + if (Count > 1) ValueI[1] = (s32)value.pointA.Y; + if (Count > 2) ValueI[2] = (s32)value.pointA.Z; + if (Count > 3) ValueI[3] = (s32)value.pointB.X; + if (Count > 4) ValueI[4] = (s32)value.pointB.Y; + if (Count > 5) ValueI[5] = (s32)value.pointB.Z; + if (Count > 6) ValueI[6] = (s32)value.pointC.X; + if (Count > 7) ValueI[7] = (s32)value.pointC.Y; + if (Count > 8) ValueI[8] = (s32)value.pointC.Z; + } + } + + virtual void setVector2d(const core::vector2df& v) _IRR_OVERRIDE_ + { + reset(); + if (IsFloat) + { + if (Count > 0) ValueF[0] = v.X; + if (Count > 1) ValueF[1] = v.Y; + } + else + { + if (Count > 0) ValueI[0] = (s32)v.X; + if (Count > 1) ValueI[1] = (s32)v.Y; + } + } + + virtual void setVector2d(const core::vector2di& v) _IRR_OVERRIDE_ + { + reset(); + if (IsFloat) + { + if (Count > 0) ValueF[0] = (f32)v.X; + if (Count > 1) ValueF[1] = (f32)v.Y; + } + else + { + if (Count > 0) ValueI[0] = v.X; + if (Count > 1) ValueI[1] = v.Y; + } + } + + virtual void setLine2d(const core::line2di& v) _IRR_OVERRIDE_ + { + reset(); + if (IsFloat) + { + if (Count > 0) ValueF[0] = (f32)v.start.X; + if (Count > 1) ValueF[1] = (f32)v.start.Y; + if (Count > 2) ValueF[2] = (f32)v.end.X; + if (Count > 3) ValueF[3] = (f32)v.end.Y; + } + else + { + if (Count > 0) ValueI[0] = v.start.X; + if (Count > 1) ValueI[1] = v.start.Y; + if (Count > 2) ValueI[2] = v.end.X; + if (Count > 3) ValueI[3] = v.end.Y; + } + } + + virtual void setLine2d(const core::line2df& v) _IRR_OVERRIDE_ + { + reset(); + if (IsFloat) + { + if (Count > 0) ValueF[0] = v.start.X; + if (Count > 1) ValueF[1] = v.start.Y; + if (Count > 2) ValueF[2] = v.end.X; + if (Count > 3) ValueF[3] = v.end.Y; + } + else + { + if (Count > 0) ValueI[0] = (s32)v.start.X; + if (Count > 1) ValueI[1] = (s32)v.start.Y; + if (Count > 2) ValueI[2] = (s32)v.end.X; + if (Count > 3) ValueI[3] = (s32)v.end.Y; + } + } + + virtual void setDimension2d(const core::dimension2du& v) _IRR_OVERRIDE_ + { + reset(); + if (IsFloat) + { + if (Count > 0) ValueF[0] = (f32)v.Width; + if (Count > 1) ValueF[1] = (f32)v.Height; + } + else + { + if (Count > 0) ValueI[0] = (s32)v.Width; + if (Count > 1) ValueI[1] = (s32)v.Height; + } + } + + //! set float array + virtual void setFloatArray(core::array &vals) + { + reset(); + + for (u32 i=0; i &vals) + { + reset(); + + for (u32 i=0; i ValueI; + core::array ValueF; + u32 Count; + bool IsFloat; +}; + + +// Attribute implemented for floating point colors +class CColorfAttribute : public CNumbersAttribute +{ +public: + + CColorfAttribute(const char* name, video::SColorf value) : CNumbersAttribute(name, value) {} + + virtual s32 getInt() const _IRR_OVERRIDE_ + { + return getColor().color; + } + + virtual f32 getFloat() const _IRR_OVERRIDE_ + { + return (f32)getColor().color; + } + + virtual void setInt(s32 intValue) _IRR_OVERRIDE_ + { + video::SColorf c = video::SColor(intValue); + ValueF[0] = c.r; + ValueF[1] = c.g; + ValueF[2] = c.b; + ValueF[3] = c.a; + } + + virtual void setFloat(f32 floatValue) _IRR_OVERRIDE_ + { + setInt((s32)floatValue); + } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_COLORF; + } + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"colorf"; + } +}; + + + +// Attribute implemented for colors +class CColorAttribute : public CNumbersAttribute +{ +public: + + CColorAttribute(const char* name, const video::SColorf& value) : CNumbersAttribute(name, value) {} + + CColorAttribute(const char* name, const video::SColor& value) : CNumbersAttribute(name, value) {} + + virtual s32 getInt() const _IRR_OVERRIDE_ + { + return getColor().color; + } + + virtual f32 getFloat() const _IRR_OVERRIDE_ + { + return (f32)getColor().color; + } + + virtual void setInt(s32 intValue) _IRR_OVERRIDE_ + { + video::SColorf c = video::SColor(intValue); + ValueF[0] = c.r; + ValueF[1] = c.g; + ValueF[2] = c.b; + ValueF[3] = c.a; + } + + virtual void setFloat(f32 floatValue) _IRR_OVERRIDE_ + { + setInt((s32)floatValue); + } + + virtual core::stringc getString() const _IRR_OVERRIDE_ + { + char tmp[10]; + const video::SColor c = getColor(); + sprintf(tmp, "%02x%02x%02x%02x", c.getAlpha(), c.getRed(), c.getGreen(), c.getBlue()); + return core::stringc(tmp); + } + + virtual core::stringw getStringW() const _IRR_OVERRIDE_ + { + char tmp[10]; + const video::SColor c = getColor(); + sprintf(tmp, "%02x%02x%02x%02x", c.getAlpha(), c.getRed(), c.getGreen(), c.getBlue()); + return core::stringw(tmp); + } + + virtual void setString(const char* text) _IRR_OVERRIDE_ + { + u32 c; + int characters; + const int items = sscanf(text, "%08x%n", &c, &characters); + if (items != 1 || characters != 8 ) + { + CNumbersAttribute::setString(text); + } + else + setColor(c); + } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_COLOR; + } + + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"color"; + } + +}; + + +// Attribute implemented for 3d vectors +class CVector3DAttribute : public CNumbersAttribute +{ +public: + + CVector3DAttribute(const char* name, const core::vector3df& value) : CNumbersAttribute(name, value) {} + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_VECTOR3D; + } + + virtual core::matrix4 getMatrix() const _IRR_OVERRIDE_ + { + core::matrix4 ret; + ret.makeIdentity(); + ret.setTranslation( core::vector3df(ValueF[0],ValueF[1],ValueF[2]) ); + return ret; + } + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"vector3d"; + } +}; + +// Attribute implemented for 2d vectors +class CVector2DAttribute : public CNumbersAttribute +{ +public: + + CVector2DAttribute(const char* name, const core::vector2df& value) : CNumbersAttribute(name, value) {} + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_VECTOR2D; + } + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"vector2d"; + } +}; + +// Attribute implemented for 2d vectors +class CPosition2DAttribute : public CNumbersAttribute +{ +public: + + CPosition2DAttribute(const char* name, const core::position2di& value) : CNumbersAttribute(name, value) {} + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_POSITION2D; + } + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"position"; + } +}; + + + +// Attribute implemented for rectangles +class CRectAttribute : public CNumbersAttribute +{ +public: + + CRectAttribute(const char* name, const core::rect& value) : CNumbersAttribute(name, value) { } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_RECT; + } + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"rect"; + } +}; + + +// Attribute implemented for dimension +class CDimension2dAttribute : public CNumbersAttribute +{ +public: + + CDimension2dAttribute (const char* name, const core::dimension2d& value) : CNumbersAttribute(name, value) { } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_DIMENSION2D; + } + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"dimension2d"; + } +}; + +// Attribute implemented for matrices +class CMatrixAttribute : public CNumbersAttribute +{ +public: + + CMatrixAttribute(const char* name, const core::matrix4& value) : CNumbersAttribute(name, value) { } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_MATRIX; + } + + virtual core::quaternion getQuaternion() const _IRR_OVERRIDE_ + { + return core::quaternion(getMatrix()); + } + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"matrix"; + } +}; + +// Attribute implemented for quaternions +class CQuaternionAttribute : public CNumbersAttribute +{ +public: + + CQuaternionAttribute(const char* name, const core::quaternion& value) : CNumbersAttribute(name, value) { } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_QUATERNION; + } + + virtual core::matrix4 getMatrix() const _IRR_OVERRIDE_ + { + return getQuaternion().getMatrix(); + } + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"quaternion"; + } +}; + + +// Attribute implemented for bounding boxes +class CBBoxAttribute : public CNumbersAttribute +{ +public: + + CBBoxAttribute(const char* name, const core::aabbox3df& value) : CNumbersAttribute(name, value) { } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_BBOX; + } + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"box3d"; + } +}; + +// Attribute implemented for planes +class CPlaneAttribute : public CNumbersAttribute +{ +public: + + CPlaneAttribute(const char* name, const core::plane3df& value) : CNumbersAttribute(name, value) { } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_PLANE; + } + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"plane"; + } +}; + +// Attribute implemented for triangles +class CTriangleAttribute : public CNumbersAttribute +{ +public: + + CTriangleAttribute(const char* name, const core::triangle3df& value) : CNumbersAttribute(name, value) { } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_TRIANGLE3D; + } + + virtual core::plane3df getPlane() const _IRR_OVERRIDE_ + { + return getTriangle().getPlane(); + } + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"triangle"; + } +}; + + +// Attribute implemented for 2d lines +class CLine2dAttribute : public CNumbersAttribute +{ +public: + + CLine2dAttribute(const char* name, const core::line2df& value) : CNumbersAttribute(name, value) { } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_LINE2D; + } + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"line2d"; + } +}; + +// Attribute implemented for 3d lines +class CLine3dAttribute : public CNumbersAttribute +{ +public: + + CLine3dAttribute(const char* name, const core::line3df& value) : CNumbersAttribute(name, value) { } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_LINE3D; + } + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"line3d"; + } +}; + + +// vector2df +// dimension2du + +/* + Special attributes +*/ + +// Attribute implemented for enumeration literals +class CEnumAttribute : public IAttribute +{ +public: + + CEnumAttribute(const char* name, const char* value, const char* const* literals) + { + Name = name; + setEnum(value, literals); + } + + virtual void setEnum(const char* enumValue, const char* const* enumerationLiterals) _IRR_OVERRIDE_ + { + u32 literalCount = 0; + + if (enumerationLiterals) + { + s32 i; + for (i=0; enumerationLiterals[i]; ++i) + ++literalCount; + + EnumLiterals.reallocate(literalCount); + for (i=0; enumerationLiterals[i]; ++i) + EnumLiterals.push_back(enumerationLiterals[i]); + } + + setString(enumValue); + } + + virtual s32 getInt() const _IRR_OVERRIDE_ + { + for (u32 i=0; i < EnumLiterals.size(); ++i) + { + if (Value.equals_ignore_case(EnumLiterals[i])) + { + return (s32)i; + } + } + + return -1; + } + + virtual f32 getFloat() const _IRR_OVERRIDE_ + { + return (f32)getInt(); + } + + virtual bool getBool() const _IRR_OVERRIDE_ + { + return (getInt() != 0); // does not make a lot of sense, I know + } + + virtual core::stringc getString() const _IRR_OVERRIDE_ + { + return Value; + } + + virtual core::stringw getStringW() const _IRR_OVERRIDE_ + { + return core::stringw(Value.c_str()); + } + + virtual void setInt(s32 intValue) _IRR_OVERRIDE_ + { + if (intValue>=0 && intValue<(s32)EnumLiterals.size()) + Value = EnumLiterals[intValue]; + else + Value = ""; + } + + virtual void setFloat(f32 floatValue) _IRR_OVERRIDE_ + { + setInt((s32)floatValue); + }; + + virtual void setString(const char* text) _IRR_OVERRIDE_ + { + Value = text; + } + + virtual const char* getEnum() const _IRR_OVERRIDE_ + { + return Value.c_str(); + } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_ENUM; + } + + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"enum"; + } + + core::stringc Value; + core::array EnumLiterals; +}; + + + + + +// Attribute implemented for strings +class CStringAttribute : public IAttribute +{ +public: + + CStringAttribute(const char* name, const char* value) + { + IsStringW=false; + Name = name; + setString(value); + } + + CStringAttribute(const char* name, const wchar_t* value) + { + IsStringW = true; + Name = name; + setString(value); + } + + CStringAttribute(const char* name, void* binaryData, s32 lengthInBytes) + { + IsStringW=false; + Name = name; + setBinary(binaryData, lengthInBytes); + } + + virtual s32 getInt() const _IRR_OVERRIDE_ + { + if (IsStringW) + return atoi(core::stringc(ValueW.c_str()).c_str()); + else + return atoi(Value.c_str()); + } + + virtual f32 getFloat() const _IRR_OVERRIDE_ + { + if (IsStringW) + return core::fast_atof(core::stringc(ValueW.c_str()).c_str()); + else + return core::fast_atof(Value.c_str()); + } + + virtual bool getBool() const _IRR_OVERRIDE_ + { + if (IsStringW) + return ValueW.equals_ignore_case(L"true"); + else + return Value.equals_ignore_case("true"); + } + + virtual core::stringc getString() const _IRR_OVERRIDE_ + { + if (IsStringW) + return core::stringc(ValueW.c_str()); + else + return Value; + } + virtual core::stringw getStringW() const _IRR_OVERRIDE_ + { + if (IsStringW) + return ValueW; + else + return core::stringw(Value.c_str()); + } + + virtual void setInt(s32 intValue) _IRR_OVERRIDE_ + { + if (IsStringW) + ValueW = core::stringw(intValue); + else + Value = core::stringc(intValue); + } + + virtual void setFloat(f32 floatValue) _IRR_OVERRIDE_ + { + if (IsStringW) + { + ValueW = core::stringw((double)floatValue); + } + else + { + Value = core::stringc((double)floatValue); + } + }; + + virtual void setString(const char* text) _IRR_OVERRIDE_ + { + if (IsStringW) + ValueW = core::stringw(text); + else + Value = text; + } + + virtual void setString(const wchar_t* text) _IRR_OVERRIDE_ + { + if (IsStringW) + ValueW = text; + else + Value = core::stringc(text); + } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_STRING; + } + + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"string"; + } + + virtual void getBinary(void* outdata, s32 maxLength) const _IRR_OVERRIDE_ + { + const s32 dataSize = maxLength; + c8* datac8 = (c8*)(outdata); + s32 p = 0; + const c8* dataString = Value.c_str(); + + for (s32 i=0; i= '0' && h <='9') + return h-'0'; + + if (h >= 'a' && h <='f') + return h-'a' + 10; + + return 0; + } + + static inline void getHexStrFromByte(c8 byte, c8* out) + { + s32 b = (byte & 0xf0) >> 4; + + for (s32 i=0; i<2; ++i) + { + if (b >=0 && b <= 9) + out[i] = b+'0'; + if (b >=10 && b <= 15) + out[i] = (b-10)+'a'; + + b = byte & 0x0f; + } + } +}; + +// Attribute implemented for binary data +class CBinaryAttribute : public CStringAttribute +{ +public: + + CBinaryAttribute(const char* name, void* binaryData, s32 lengthInBytes) + : CStringAttribute(name, binaryData, lengthInBytes) + { + + } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_BINARY; + } + + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"binary"; + } +}; + + + +// Attribute implemented for texture references +class CTextureAttribute : public IAttribute +{ +public: + + CTextureAttribute(const char* name, video::ITexture* value, video::IVideoDriver* driver, const io::path& filename) + : Value(0), Driver(driver), OverrideName(filename) + { + if (Driver) + Driver->grab(); + + Name = name; + setTexture(value); + } + + virtual ~CTextureAttribute() + { + if (Driver) + Driver->drop(); + + if (Value) + Value->drop(); + } + + virtual video::ITexture* getTexture() const _IRR_OVERRIDE_ + { + return Value; + } + + virtual bool getBool() const _IRR_OVERRIDE_ + { + return (Value != 0); + } + + virtual core::stringw getStringW() const _IRR_OVERRIDE_ + { + // (note: don't try to put all this in some ?: operators, or c++ builder will choke) + if ( OverrideName.size() ) + return core::stringw(OverrideName); + + if ( Value ) + return core::stringw(Value->getName().getPath().c_str()); + + return core::stringw(); + } + + virtual core::stringc getString() const _IRR_OVERRIDE_ + { + // since texture names can be stringw we are careful with the types + if ( OverrideName.size() ) + return core::stringc(OverrideName); + + if ( Value ) + return core::stringc(Value->getName().getPath().c_str()); + + return core::stringc(); + } + + virtual void setString(const char* text) _IRR_OVERRIDE_ + { + if (Driver) + { + if (text && *text) + { + setTexture(Driver->getTexture(text)); + OverrideName=text; + } + else + setTexture(0); + } + } + + virtual void setTexture(video::ITexture* texture, const path& filename) _IRR_OVERRIDE_ + { + OverrideName = filename; + setTexture(texture); + }; + + void setTexture(video::ITexture* value) + { + if ( value == Value ) + return; + + if (Value) + Value->drop(); + + Value = value; + + if (Value) + Value->grab(); + } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_TEXTURE; + } + + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"texture"; + } + + video::ITexture* Value; + video::IVideoDriver* Driver; + io::path OverrideName; +}; + + + +// Attribute implemented for array of stringw +class CStringWArrayAttribute : public IAttribute +{ +public: + + CStringWArrayAttribute(const char* name, const core::array& value) + { + Name = name; + setArray(value); + } + + virtual core::array getArray() const _IRR_OVERRIDE_ + { + return Value; + } + + virtual void setArray(const core::array& value) _IRR_OVERRIDE_ + { + Value = value; + } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_STRINGWARRAY; + } + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"stringwarray"; + } + + core::array Value; +}; + + +// Attribute implemented for user pointers +class CUserPointerAttribute : public IAttribute +{ +public: + + CUserPointerAttribute(const char* name, void* value) + { + Name = name; + Value = value; + } + + virtual s32 getInt() const _IRR_OVERRIDE_ + { + return *static_cast(Value); + } + + virtual bool getBool() const _IRR_OVERRIDE_ + { + return (Value != 0); + } + + virtual core::stringw getStringW() const _IRR_OVERRIDE_ + { + wchar_t buf[32]; + swprintf_irr(buf, 32, L"%p", Value); + + return core::stringw(buf); + } + + virtual void setString(const char* text) _IRR_OVERRIDE_ + { + size_t val = 0; + switch ( sizeof(void*) ) + { + case 4: + { + unsigned int tmp; // not using an irrlicht type - sscanf with %x needs always unsigned int + sscanf(text, "%x", &tmp); + val = (size_t)tmp; + } + break; + case 8: + { +#ifdef _MSC_VER + const unsigned __int64 tmp = _strtoui64(text, NULL, 16); +#else + const unsigned long long tmp = strtoull(text, NULL, 16); +#endif + val = (size_t)tmp; + } + break; + } + Value = (void *)val; + } + + virtual E_ATTRIBUTE_TYPE getType() const _IRR_OVERRIDE_ + { + return EAT_USER_POINTER; + } + + virtual void setUserPointer(void* v) _IRR_OVERRIDE_ + { + Value = v; + } + + virtual void* getUserPointer() const _IRR_OVERRIDE_ + { + return Value; + } + + + virtual const wchar_t* getTypeString() const _IRR_OVERRIDE_ + { + return L"userPointer"; + } + + void* Value; +}; + + + +// todo: CGUIFontAttribute + +} // end namespace io +} // end namespace irr diff --git a/source/Irrlicht/CAttributes.cpp b/source/Irrlicht/CAttributes.cpp new file mode 100644 index 00000000..7b1f06ec --- /dev/null +++ b/source/Irrlicht/CAttributes.cpp @@ -0,0 +1,1658 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CAttributes.h" +#include "CAttributeImpl.h" +#include "ITexture.h" +#include "IXMLWriter.h" +#include "IVideoDriver.h" + +#ifndef _IRR_COMPILE_WITH_XML_ + #include "CXMLReader.h" // for noXML +#endif + +namespace irr +{ +namespace io +{ + +CAttributes::CAttributes(video::IVideoDriver* driver) +: Driver(driver) +{ + #ifdef _DEBUG + setDebugName("CAttributes"); + #endif + + if (Driver) + Driver->grab(); +} + +CAttributes::~CAttributes() +{ + clear(); + + if (Driver) + Driver->drop(); +} + + +//! Removes all attributes +void CAttributes::clear() +{ + for (u32 i=0; idrop(); + + Attributes.clear(); +} + + +//! Sets a string attribute. +//! \param attributeName: Name for the attribute +//! \param value: Value for the attribute. Set this to 0 to delete the attribute +void CAttributes::setAttribute(const c8* attributeName, const c8* value) +{ + for (u32 i=0; iName == attributeName) + { + if (!value) + { + Attributes[i]->drop(); + Attributes.erase(i); + } + else + Attributes[i]->setString(value); + + return; + } + + if (value) + { + Attributes.push_back(new CStringAttribute(attributeName, value)); + } +} + +//! Gets a string attribute. +//! \param attributeName: Name of the attribute to get. +//! \return Returns value of the attribute previously set by setStringAttribute() +//! or 0 if attribute is not set. +core::stringc CAttributes::getAttributeAsString(const c8* attributeName, const core::stringc& defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getString(); + else + return defaultNotFound; +} + +//! Gets a string attribute. +//! \param attributeName: Name of the attribute to get. +//! \param target: Buffer where the string is copied to. +void CAttributes::getAttributeAsString(const c8* attributeName, char* target) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + { + core::stringc str = att->getString(); + strcpy(target,str.c_str()); + } + else + target[0] = 0; +} + +//! Returns string attribute value by index. +//! \param index: Index value, must be between 0 and getAttributeCount()-1. +core::stringc CAttributes::getAttributeAsString(s32 index) const +{ + core::stringc str; + + if ((u32)index < Attributes.size()) + return Attributes[index]->getString(); + + return str; +} + + +//! Sets a string attribute. +//! \param attributeName: Name for the attribute +//! \param value: Value for the attribute. Set this to 0 to delete the attribute +void CAttributes::setAttribute(const c8* attributeName, const wchar_t* value) +{ + for (u32 i=0; iName == attributeName) + { + if (!value) + { + Attributes[i]->drop(); + Attributes.erase(i); + } + else + Attributes[i]->setString(value); + + return; + } + } + + if (value) + { + Attributes.push_back(new CStringAttribute(attributeName, value)); + } +} + +//! Gets a string attribute. +//! \param attributeName: Name of the attribute to get. +//! \return Returns value of the attribute previously set by setStringAttribute() +//! or 0 if attribute is not set. +core::stringw CAttributes::getAttributeAsStringW(const c8* attributeName, const core::stringw& defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getStringW(); + else + return defaultNotFound; +} + +//! Gets a string attribute. +//! \param attributeName: Name of the attribute to get. +//! \param target: Buffer where the string is copied to. +void CAttributes::getAttributeAsStringW(const c8* attributeName, wchar_t* target) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + { + core::stringw str = att->getStringW(); + wcscpy(target,str.c_str()); + } + else + target[0] = 0; +} + +//! Returns string attribute value by index. +//! \param index: Index value, must be between 0 and getAttributeCount()-1. +core::stringw CAttributes::getAttributeAsStringW(s32 index) const +{ + + if ((u32)index < Attributes.size()) + return Attributes[index]->getStringW(); + else + return core::stringw(); +} + + +//! Adds an attribute as an array of wide strings +void CAttributes::addArray(const c8* attributeName, const core::array& value) +{ + Attributes.push_back(new CStringWArrayAttribute(attributeName, value)); +} + +//! Sets an attribute value as an array of wide strings. +void CAttributes::setAttribute(const c8* attributeName, const core::array& value) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setArray(value); + else + { + Attributes.push_back(new CStringWArrayAttribute(attributeName, value)); + } +} + +//! Gets an attribute as an array of wide strings. +core::array CAttributes::getAttributeAsArray(const c8* attributeName, const core::array& defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getArray(); + else + return defaultNotFound; +} + +//! Returns attribute value as an array of wide strings by index. +core::array CAttributes::getAttributeAsArray(s32 index) const +{ + core::array ret; + + if (index >= 0 && index < (s32)Attributes.size()) + ret = Attributes[index]->getArray(); + + return ret; +} + +//! Sets an attribute as an array of wide strings +void CAttributes::setAttribute(s32 index, const core::array& value) +{ + if (index >= 0 && index < (s32)Attributes.size() ) + Attributes[index]->setArray(value); +} + + + + +//! Returns attribute index from name, -1 if not found +s32 CAttributes::findAttribute(const c8* attributeName) const +{ + for (u32 i=0; iName == attributeName) + return i; + + return -1; +} + + +IAttribute* CAttributes::getAttributeP(const c8* attributeName) const +{ + for (u32 i=0; iName == attributeName) + return Attributes[i]; + + return 0; +} + + +//! Sets a attribute as boolean value +void CAttributes::setAttribute(const c8* attributeName, bool value) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setBool(value); + else + { + Attributes.push_back(new CBoolAttribute(attributeName, value)); + } +} + +//! Gets a attribute as boolean value +//! \param attributeName: Name of the attribute to get. +//! \return Returns value of the attribute previously set by setAttribute() as bool +//! or 0 if attribute is not set. +bool CAttributes::getAttributeAsBool(const c8* attributeName, bool defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getBool(); + else + return defaultNotFound; +} + +//! Sets a attribute as integer value +void CAttributes::setAttribute(const c8* attributeName, s32 value) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setInt(value); + else + { + Attributes.push_back(new CIntAttribute(attributeName, value)); + } +} + +//! Gets a attribute as integer value +//! \param attributeName: Name of the attribute to get. +//! \return Returns value of the attribute previously set by setAttribute() as integer +//! or 0 if attribute is not set. +s32 CAttributes::getAttributeAsInt(const c8* attributeName, irr::s32 defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getInt(); + else + return defaultNotFound; +} + +//! Sets a attribute as float value +void CAttributes::setAttribute(const c8* attributeName, f32 value) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setFloat(value); + else + Attributes.push_back(new CFloatAttribute(attributeName, value)); +} + +//! Gets a attribute as integer value +//! \param attributeName: Name of the attribute to get. +//! \return Returns value of the attribute previously set by setAttribute() as float value +//! or 0 if attribute is not set. +f32 CAttributes::getAttributeAsFloat(const c8* attributeName, irr::f32 defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getFloat(); + + return defaultNotFound; +} + +//! Sets a attribute as color +void CAttributes::setAttribute(const c8* attributeName, video::SColor value) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setColor(value); + else + Attributes.push_back(new CColorAttribute(attributeName, value)); +} + +//! Gets an attribute as color +//! \param attributeName: Name of the attribute to get. +//! \return Returns value of the attribute previously set by setAttribute() +video::SColor CAttributes::getAttributeAsColor(const c8* attributeName, const video::SColor& defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getColor(); + else + return defaultNotFound; +} + +//! Sets a attribute as floating point color +void CAttributes::setAttribute(const c8* attributeName, video::SColorf value) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setColor(value); + else + Attributes.push_back(new CColorfAttribute(attributeName, value)); +} + +//! Gets an attribute as floating point color +//! \param attributeName: Name of the attribute to get. +//! \return Returns value of the attribute previously set by setAttribute() +video::SColorf CAttributes::getAttributeAsColorf(const c8* attributeName, const video::SColorf& defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getColorf(); + else + return defaultNotFound; +} + +//! Sets a attribute as 2d position +void CAttributes::setAttribute(const c8* attributeName, const core::position2di& value) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setPosition(value); + else + Attributes.push_back(new CPosition2DAttribute(attributeName, value)); +} + +//! Gets an attribute as 2d position +//! \param attributeName: Name of the attribute to get. +//! \return Returns value of the attribute previously set by setAttribute() +core::position2di CAttributes::getAttributeAsPosition2d(const c8* attributeName, const core::position2di& defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getPosition(); + else + return defaultNotFound; +} + +//! Sets a attribute as rectangle +void CAttributes::setAttribute(const c8* attributeName, const core::rect& value) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setRect(value); + else + Attributes.push_back(new CRectAttribute(attributeName, value)); +} + +//! Gets an attribute as rectangle +//! \param attributeName: Name of the attribute to get. +//! \return Returns value of the attribute previously set by setAttribute() +core::rect CAttributes::getAttributeAsRect(const c8* attributeName, const core::rect& defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getRect(); + else + return defaultNotFound; +} + +//! Sets a attribute as dimension2d +void CAttributes::setAttribute(const c8* attributeName, const core::dimension2d& value) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setDimension2d(value); + else + Attributes.push_back(new CDimension2dAttribute(attributeName, value)); +} + +//! Gets an attribute as dimension2d +//! \param attributeName: Name of the attribute to get. +//! \return Returns value of the attribute previously set by setAttribute() +core::dimension2d CAttributes::getAttributeAsDimension2d(const c8* attributeName, const core::dimension2d& defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getDimension2d(); + else + return defaultNotFound; +} + +//! Sets a attribute as vector +void CAttributes::setAttribute(const c8* attributeName, const core::vector3df& value) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setVector(value); + else + Attributes.push_back(new CVector3DAttribute(attributeName, value)); +} + +//! Sets a attribute as vector +void CAttributes::setAttribute(const c8* attributeName, const core::vector2df& value) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setVector2d(value); + else + Attributes.push_back(new CVector2DAttribute(attributeName, value)); +} + +//! Gets an attribute as vector +//! \param attributeName: Name of the attribute to get. +//! \return Returns value of the attribute previously set by setAttribute() +core::vector3df CAttributes::getAttributeAsVector3d(const c8* attributeName, const core::vector3df& defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getVector(); + else + return defaultNotFound; +} + +//! Gets an attribute as vector +core::vector2df CAttributes::getAttributeAsVector2d(const c8* attributeName, const core::vector2df& defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getVector2d(); + else + return defaultNotFound; +} + +//! Sets an attribute as binary data +void CAttributes::setAttribute(const c8* attributeName, void* data, s32 dataSizeInBytes ) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setBinary(data, dataSizeInBytes); + else + Attributes.push_back(new CBinaryAttribute(attributeName, data, dataSizeInBytes)); +} + +//! Gets an attribute as binary data +//! \param attributeName: Name of the attribute to get. +void CAttributes::getAttributeAsBinaryData(const c8* attributeName, void* outData, s32 maxSizeInBytes) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + att->getBinary(outData, maxSizeInBytes); +} + +//! Sets an attribute as enumeration +void CAttributes::setAttribute(const c8* attributeName, const char* enumValue, const char* const* enumerationLiterals) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setEnum(enumValue, enumerationLiterals); + else + Attributes.push_back(new CEnumAttribute(attributeName, enumValue, enumerationLiterals)); +} + +//! Gets an attribute as enumeration +//! \param attributeName: Name of the attribute to get. +//! \return Returns value of the attribute previously set by setAttribute() +const char* CAttributes::getAttributeAsEnumeration(const c8* attributeName, const c8* defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getEnum(); + else + return defaultNotFound; +} + +//! Gets an attribute as enumeration +s32 CAttributes::getAttributeAsEnumeration(const c8* attributeName, const char* const* enumerationLiteralsToUse, s32 defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + + if (enumerationLiteralsToUse && att) + { + const char* value = att->getEnum(); + if (value) + { + for (s32 i=0; enumerationLiteralsToUse[i]; ++i) + if (!strcmp(value, enumerationLiteralsToUse[i])) + return i; + } + } + + return defaultNotFound; +} + +//! Gets the list of enumeration literals of an enumeration attribute +//! \param attributeName: Name of the attribute to get. +void CAttributes::getAttributeEnumerationLiteralsOfEnumeration(const c8* attributeName, core::array& outLiterals) const +{ + const IAttribute* att = getAttributeP(attributeName); + + if (att && att->getType() == EAT_ENUM) + outLiterals = ((CEnumAttribute*)att)->EnumLiterals; +} + +//! Sets an attribute as texture reference +void CAttributes::setAttribute(const c8* attributeName, video::ITexture* value, const io::path& filename) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setTexture(value, filename); + else + Attributes.push_back(new CTextureAttribute(attributeName, value, Driver, filename)); +} + + +//! Gets an attribute as texture reference +//! \param attributeName: Name of the attribute to get. +video::ITexture* CAttributes::getAttributeAsTexture(const c8* attributeName, video::ITexture* defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getTexture(); + else + return defaultNotFound; +} + +//! Gets an attribute as texture reference +//! \param index: Index value, must be between 0 and getAttributeCount()-1. +video::ITexture* CAttributes::getAttributeAsTexture(s32 index) const +{ + if ((u32)index < Attributes.size()) + return Attributes[index]->getTexture(); + else + return 0; +} + + +//! Returns amount of string attributes set in this scene manager. +u32 CAttributes::getAttributeCount() const +{ + return Attributes.size(); +} + +//! Returns string attribute name by index. +//! \param index: Index value, must be between 0 and getStringAttributeCount()-1. +const c8* CAttributes::getAttributeName(s32 index) const +{ + if ((u32)index >= Attributes.size()) + return 0; + + return Attributes[index]->Name.c_str(); +} + +//! Returns the type of an attribute +E_ATTRIBUTE_TYPE CAttributes::getAttributeType(const c8* attributeName) const +{ + E_ATTRIBUTE_TYPE ret = EAT_UNKNOWN; + + const IAttribute* att = getAttributeP(attributeName); + if (att) + ret = att->getType(); + + return ret; +} + +//! Returns attribute type by index. +//! \param index: Index value, must be between 0 and getAttributeCount()-1. +E_ATTRIBUTE_TYPE CAttributes::getAttributeType(s32 index) const +{ + if ((u32)index >= Attributes.size()) + return EAT_UNKNOWN; + + return Attributes[index]->getType(); +} + +//! Returns the type of an attribute +const wchar_t* CAttributes::getAttributeTypeString(const c8* attributeName, const wchar_t* defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getTypeString(); + else + return defaultNotFound; +} + +//! Returns attribute type string by index. +//! \param index: Index value, must be between 0 and getAttributeCount()-1. +const wchar_t* CAttributes::getAttributeTypeString(s32 index, const wchar_t* defaultNotFound) const +{ + if ((u32)index >= Attributes.size()) + return defaultNotFound; + + return Attributes[index]->getTypeString(); +} + +//! Gets an attribute as boolean value +//! \param index: Index value, must be between 0 and getAttributeCount()-1. +bool CAttributes::getAttributeAsBool(s32 index) const +{ + bool ret = false; + + if ((u32)index < Attributes.size()) + ret = Attributes[index]->getBool(); + + return ret; +} + +//! Gets an attribute as integer value +//! \param index: Index value, must be between 0 and getAttributeCount()-1. +s32 CAttributes::getAttributeAsInt(s32 index) const +{ + if ((u32)index < Attributes.size()) + return Attributes[index]->getInt(); + else + return 0; +} + +//! Gets an attribute as float value +//! \param index: Index value, must be between 0 and getAttributeCount()-1. +f32 CAttributes::getAttributeAsFloat(s32 index) const +{ + if ((u32)index < Attributes.size()) + return Attributes[index]->getFloat(); + else + return 0.f; +} + +//! Gets an attribute as color +//! \param index: Index value, must be between 0 and getAttributeCount()-1. +video::SColor CAttributes::getAttributeAsColor(s32 index) const +{ + video::SColor ret(0); + + if ((u32)index < Attributes.size()) + ret = Attributes[index]->getColor(); + + return ret; +} + +//! Gets an attribute as floating point color +//! \param index: Index value, must be between 0 and getAttributeCount()-1. +video::SColorf CAttributes::getAttributeAsColorf(s32 index) const +{ + if ((u32)index < Attributes.size()) + return Attributes[index]->getColorf(); + + return video::SColorf(); +} + +//! Gets an attribute as 3d vector +//! \param index: Index value, must be between 0 and getAttributeCount()-1. +core::vector3df CAttributes::getAttributeAsVector3d(s32 index) const +{ + if ((u32)index < Attributes.size()) + return Attributes[index]->getVector(); + else + return core::vector3df(); +} + +//! Gets an attribute as 2d vector +core::vector2df CAttributes::getAttributeAsVector2d(s32 index) const +{ + if ((u32)index < Attributes.size()) + return Attributes[index]->getVector2d(); + else + return core::vector2df(); +} + +//! Gets an attribute as position2d +//! \param index: Index value, must be between 0 and getAttributeCount()-1. +core::position2di CAttributes::getAttributeAsPosition2d(s32 index) const +{ + if ((u32)index < Attributes.size()) + return Attributes[index]->getPosition(); + else + return core::position2di(); +} + +//! Gets an attribute as rectangle +//! \param index: Index value, must be between 0 and getAttributeCount()-1. +core::rect CAttributes::getAttributeAsRect(s32 index) const +{ + if ((u32)index < Attributes.size()) + return Attributes[index]->getRect(); + else + return core::rect(); +} + +//! Gets an attribute as dimension2d +//! \param index: Index value, must be between 0 and getAttributeCount()-1. +core::dimension2d CAttributes::getAttributeAsDimension2d(s32 index) const +{ + if ((u32)index < Attributes.size()) + return Attributes[index]->getDimension2d(); + else + return core::dimension2d(); +} + + +//! Gets an attribute as binary data +///! \param index: Index value, must be between 0 and getAttributeCount()-1. +void CAttributes::getAttributeAsBinaryData(s32 index, void* outData, s32 maxSizeInBytes) const +{ + if ((u32)index < Attributes.size()) + Attributes[index]->getBinary(outData, maxSizeInBytes); +} + + +//! Gets an attribute as enumeration +//! \param index: Index value, must be between 0 and getAttributeCount()-1. +const char* CAttributes::getAttributeAsEnumeration(s32 index) const +{ + if ((u32)index < Attributes.size()) + return Attributes[index]->getEnum(); + else + return 0; +} + + +//! Gets an attribute as enumeration +//! \param index: Index value, must be between 0 and getAttributeCount()-1. +s32 CAttributes::getAttributeAsEnumeration(s32 index, const char* const* enumerationLiteralsToUse, s32 defaultNotFound) const +{ + if ((u32)index < Attributes.size()) + { + const IAttribute* att = Attributes[index]; + + if (enumerationLiteralsToUse && att) + { + const char* value = att->getEnum(); + if (value) + { + for (s32 i=0; enumerationLiteralsToUse[i]; ++i) + if (!strcmp(value, enumerationLiteralsToUse[i])) + return i; + } + } + } + + return defaultNotFound; +} + +//! Gets the list of enumeration literals of an enumeration attribute +//! \param index: Index value, must be between 0 and getAttributeCount()-1. +void CAttributes::getAttributeEnumerationLiteralsOfEnumeration(s32 index, core::array& outLiterals) const +{ + if ((u32)index < Attributes.size() && + Attributes[index]->getType() == EAT_ENUM) + outLiterals = ((CEnumAttribute*)Attributes[index])->EnumLiterals; +} + + +//! Adds an attribute as integer +void CAttributes::addInt(const c8* attributeName, s32 value) +{ + Attributes.push_back(new CIntAttribute(attributeName, value)); +} + +//! Adds an attribute as float +void CAttributes::addFloat(const c8* attributeName, f32 value) +{ + Attributes.push_back(new CFloatAttribute(attributeName, value)); +} + +//! Adds an attribute as string +void CAttributes::addString(const c8* attributeName, const char* value) +{ + Attributes.push_back(new CStringAttribute(attributeName, value)); +} + +//! Adds an attribute as wchar string +void CAttributes::addString(const c8* attributeName, const wchar_t* value) +{ + Attributes.push_back(new CStringAttribute(attributeName, value)); +} + +//! Adds an attribute as bool +void CAttributes::addBool(const c8* attributeName, bool value) +{ + Attributes.push_back(new CBoolAttribute(attributeName, value)); +} + +//! Adds an attribute as enum +void CAttributes::addEnum(const c8* attributeName, const char* enumValue, const char* const* enumerationLiterals) +{ + Attributes.push_back(new CEnumAttribute(attributeName, enumValue, enumerationLiterals)); +} + +//! Adds an attribute as enum +void CAttributes::addEnum(const c8* attributeName, s32 enumValue, const char* const* enumerationLiterals) +{ + addEnum(attributeName, "", enumerationLiterals); + Attributes.getLast()->setInt(enumValue); +} + +//! Adds an attribute as color +void CAttributes::addColor(const c8* attributeName, video::SColor value) +{ + Attributes.push_back(new CColorAttribute(attributeName, value)); +} + +//! Adds an attribute as floating point color +void CAttributes::addColorf(const c8* attributeName, video::SColorf value) +{ + Attributes.push_back(new CColorfAttribute(attributeName, value)); +} + +//! Adds an attribute as 3d vector +void CAttributes::addVector3d(const c8* attributeName, const core::vector3df& value) +{ + Attributes.push_back(new CVector3DAttribute(attributeName, value)); +} + +//! Adds an attribute as 2d vector +void CAttributes::addVector2d(const c8* attributeName, const core::vector2df& value) +{ + Attributes.push_back(new CVector2DAttribute(attributeName, value)); +} + + +//! Adds an attribute as 2d position +void CAttributes::addPosition2d(const c8* attributeName, const core::position2di& value) +{ + Attributes.push_back(new CPosition2DAttribute(attributeName, value)); +} + +//! Adds an attribute as rectangle +void CAttributes::addRect(const c8* attributeName, const core::rect& value) +{ + Attributes.push_back(new CRectAttribute(attributeName, value)); +} + +//! Adds an attribute as dimension2d +void CAttributes::addDimension2d(const c8* attributeName, const core::dimension2d& value) +{ + Attributes.push_back(new CDimension2dAttribute(attributeName, value)); +} + +//! Adds an attribute as binary data +void CAttributes::addBinary(const c8* attributeName, void* data, s32 dataSizeInBytes) +{ + Attributes.push_back(new CBinaryAttribute(attributeName, data, dataSizeInBytes)); +} + +//! Adds an attribute as texture reference +void CAttributes::addTexture(const c8* attributeName, video::ITexture* texture, const io::path& filename) +{ + Attributes.push_back(new CTextureAttribute(attributeName, texture, Driver, filename)); +} + +//! Returns if an attribute with a name exists +bool CAttributes::existsAttribute(const c8* attributeName) const +{ + return getAttributeP(attributeName) != 0; +} + +//! Sets an attribute value as string. +//! \param attributeName: Name for the attribute +void CAttributes::setAttribute(s32 index, const c8* value) +{ + if ((u32)index < Attributes.size()) + Attributes[index]->setString(value); +} + +//! Sets an attribute value as string. +//! \param attributeName: Name for the attribute +void CAttributes::setAttribute(s32 index, const wchar_t* value) +{ + if ((u32)index < Attributes.size()) + Attributes[index]->setString(value); +} + +//! Sets an attribute as boolean value +void CAttributes::setAttribute(s32 index, bool value) +{ + if ((u32)index < Attributes.size()) + Attributes[index]->setBool(value); +} + +//! Sets an attribute as integer value +void CAttributes::setAttribute(s32 index, s32 value) +{ + if ((u32)index < Attributes.size()) + Attributes[index]->setInt(value); +} + +//! Sets a attribute as float value +void CAttributes::setAttribute(s32 index, f32 value) +{ + if ((u32)index < Attributes.size()) + Attributes[index]->setFloat(value); +} + +//! Sets a attribute as color +void CAttributes::setAttribute(s32 index, video::SColor color) +{ + if ((u32)index < Attributes.size()) + Attributes[index]->setColor(color); +} + +//! Sets a attribute as floating point color +void CAttributes::setAttribute(s32 index, video::SColorf color) +{ + if ((u32)index < Attributes.size()) + Attributes[index]->setColor(color); +} + +//! Sets a attribute as vector +void CAttributes::setAttribute(s32 index, const core::vector3df& v) +{ + if ((u32)index < Attributes.size()) + Attributes[index]->setVector(v); +} + +//! Sets a attribute as vector +void CAttributes::setAttribute(s32 index, const core::vector2df& v) +{ + if ((u32)index < Attributes.size()) + Attributes[index]->setVector2d(v); +} + +//! Sets a attribute as position +void CAttributes::setAttribute(s32 index, const core::position2di& v) +{ + if ((u32)index < Attributes.size()) + Attributes[index]->setPosition(v); +} + +//! Sets a attribute as rectangle +void CAttributes::setAttribute(s32 index, const core::rect& v) +{ + if ((u32)index < Attributes.size()) + Attributes[index]->setRect(v); +} + +//! Sets a attribute as dimension2d +void CAttributes::setAttribute(s32 index, const core::dimension2d& v) +{ + if ((u32)index < Attributes.size()) + Attributes[index]->setDimension2d(v); +} + +//! Sets an attribute as binary data +void CAttributes::setAttribute(s32 index, void* data, s32 dataSizeInBytes ) +{ + if ((u32)index < Attributes.size()) + Attributes[index]->setBinary(data, dataSizeInBytes); +} + + +//! Sets an attribute as enumeration +void CAttributes::setAttribute(s32 index, const char* enumValue, const char* const* enumerationLiterals) +{ + if ((u32)index < Attributes.size()) + Attributes[index]->setEnum(enumValue, enumerationLiterals); +} + + +//! Sets an attribute as texture reference +void CAttributes::setAttribute(s32 index, video::ITexture* texture, const io::path& filename) +{ + if ((u32)index < Attributes.size()) + Attributes[index]->setTexture(texture, filename); +} + + +//! Adds an attribute as matrix +void CAttributes::addMatrix(const c8* attributeName, const core::matrix4& v) +{ + Attributes.push_back(new CMatrixAttribute(attributeName, v)); +} + + +//! Sets an attribute as matrix +void CAttributes::setAttribute(const c8* attributeName, const core::matrix4& v) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setMatrix(v); + else + Attributes.push_back(new CMatrixAttribute(attributeName, v)); +} + +//! Gets an attribute as a matrix4 +core::matrix4 CAttributes::getAttributeAsMatrix(const c8* attributeName, const core::matrix4& defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getMatrix(); + else + return defaultNotFound; + +} + +//! Gets an attribute as matrix +core::matrix4 CAttributes::getAttributeAsMatrix(s32 index) const +{ + if ((u32)index < Attributes.size()) + return Attributes[index]->getMatrix(); + else + return core::matrix4(); +} + +//! Sets an attribute as matrix +void CAttributes::setAttribute(s32 index, const core::matrix4& v) +{ + if ((u32)index < Attributes.size()) + Attributes[index]->setMatrix(v); +} + + +//! Adds an attribute as quaternion +void CAttributes::addQuaternion(const c8* attributeName, const core::quaternion& v) +{ + Attributes.push_back(new CQuaternionAttribute(attributeName, v)); +} + + +//! Sets an attribute as quaternion +void CAttributes::setAttribute(const c8* attributeName, const core::quaternion& v) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setQuaternion(v); + else + { + Attributes.push_back(new CQuaternionAttribute(attributeName, v)); + } +} + +//! Gets an attribute as a quaternion +core::quaternion CAttributes::getAttributeAsQuaternion(const c8* attributeName, const core::quaternion& defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getQuaternion(); + else + return defaultNotFound; +} + +//! Gets an attribute as quaternion +core::quaternion CAttributes::getAttributeAsQuaternion(s32 index) const +{ + core::quaternion ret(0,1,0, 0); + + if (index >= 0 && index < (s32)Attributes.size()) + ret = Attributes[index]->getQuaternion(); + + return ret; +} + +//! Sets an attribute as quaternion +void CAttributes::setAttribute(s32 index, const core::quaternion& v) +{ +if (index >= 0 && index < (s32)Attributes.size() ) + Attributes[index]->setQuaternion(v); +} + +//! Adds an attribute as axis aligned bounding box +void CAttributes::addBox3d(const c8* attributeName, const core::aabbox3df& v) +{ + Attributes.push_back(new CBBoxAttribute(attributeName, v)); +} + +//! Sets an attribute as axis aligned bounding box +void CAttributes::setAttribute(const c8* attributeName, const core::aabbox3df& v) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setBBox(v); + else + { + Attributes.push_back(new CBBoxAttribute(attributeName, v)); + } +} + +//! Gets an attribute as a axis aligned bounding box +core::aabbox3df CAttributes::getAttributeAsBox3d(const c8* attributeName, const core::aabbox3df& defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getBBox(); + else + return defaultNotFound; +} + +//! Gets an attribute as axis aligned bounding box +core::aabbox3df CAttributes::getAttributeAsBox3d(s32 index) const +{ + core::aabbox3df ret(0,0,0, 0,0,0); + + if (index >= 0 && index < (s32)Attributes.size()) + ret = Attributes[index]->getBBox(); + + return ret; +} + +//! Sets an attribute as axis aligned bounding box +void CAttributes::setAttribute(s32 index, const core::aabbox3df& v) +{ +if (index >= 0 && index < (s32)Attributes.size() ) + Attributes[index]->setBBox(v); +} + +//! Adds an attribute as 3d plane +void CAttributes::addPlane3d(const c8* attributeName, const core::plane3df& v) +{ + Attributes.push_back(new CPlaneAttribute(attributeName, v)); +} + +//! Sets an attribute as 3d plane +void CAttributes::setAttribute(const c8* attributeName, const core::plane3df& v) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setPlane(v); + else + { + Attributes.push_back(new CPlaneAttribute(attributeName, v)); + } +} + +//! Gets an attribute as a 3d plane +core::plane3df CAttributes::getAttributeAsPlane3d(const c8* attributeName, const core::plane3df& defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getPlane(); + else + return defaultNotFound; +} + +//! Gets an attribute as 3d plane +core::plane3df CAttributes::getAttributeAsPlane3d(s32 index) const +{ + core::plane3df ret(0,0,0, 0,1,0); + + if (index >= 0 && index < (s32)Attributes.size()) + ret = Attributes[index]->getPlane(); + + return ret; +} + +//! Sets an attribute as 3d plane +void CAttributes::setAttribute(s32 index, const core::plane3df& v) +{ + if (index >= 0 && index < (s32)Attributes.size() ) + Attributes[index]->setPlane(v); +} + +//! Adds an attribute as 3d triangle +void CAttributes::addTriangle3d(const c8* attributeName, const core::triangle3df& v) +{ + Attributes.push_back(new CTriangleAttribute(attributeName, v)); +} + +//! Sets an attribute as 3d triangle +void CAttributes::setAttribute(const c8* attributeName, const core::triangle3df& v) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setTriangle(v); + else + { + Attributes.push_back(new CTriangleAttribute(attributeName, v)); + } +} + +//! Gets an attribute as a 3d triangle +core::triangle3df CAttributes::getAttributeAsTriangle3d(const c8* attributeName, const core::triangle3df& defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getTriangle(); + else + return defaultNotFound; +} + +//! Gets an attribute as 3d triangle +core::triangle3df CAttributes::getAttributeAsTriangle3d(s32 index) const +{ + core::triangle3df ret; + ret.pointA = ret.pointB = ret.pointC = core::vector3df(0,0,0); + + if (index >= 0 && index < (s32)Attributes.size()) + ret = Attributes[index]->getTriangle(); + + return ret; +} + +//! Sets an attribute as 3d triangle +void CAttributes::setAttribute(s32 index, const core::triangle3df& v) +{ + if (index >= 0 && index < (s32)Attributes.size() ) + Attributes[index]->setTriangle(v); +} + +//! Adds an attribute as a 2d line +void CAttributes::addLine2d(const c8* attributeName, const core::line2df& v) +{ + Attributes.push_back(new CLine2dAttribute(attributeName, v)); +} + +//! Sets an attribute as a 2d line +void CAttributes::setAttribute(const c8* attributeName, const core::line2df& v) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setLine2d(v); + else + { + Attributes.push_back(new CLine2dAttribute(attributeName, v)); + } +} + +//! Gets an attribute as a 2d line +core::line2df CAttributes::getAttributeAsLine2d(const c8* attributeName, const core::line2df& defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getLine2d(); + else + return defaultNotFound; +} + +//! Gets an attribute as a 2d line +core::line2df CAttributes::getAttributeAsLine2d(s32 index) const +{ + core::line2df ret(0,0, 0,0); + + if (index >= 0 && index < (s32)Attributes.size()) + ret = Attributes[index]->getLine2d(); + + return ret; +} + +//! Sets an attribute as a 2d line +void CAttributes::setAttribute(s32 index, const core::line2df& v) +{ + if (index >= 0 && index < (s32)Attributes.size() ) + Attributes[index]->setLine2d(v); +} + +//! Adds an attribute as a 3d line +void CAttributes::addLine3d(const c8* attributeName, const core::line3df& v) +{ + Attributes.push_back(new CLine3dAttribute(attributeName, v)); +} + +//! Sets an attribute as a 3d line +void CAttributes::setAttribute(const c8* attributeName, const core::line3df& v) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setLine3d(v); + else + { + Attributes.push_back(new CLine3dAttribute(attributeName, v)); + } +} + +//! Gets an attribute as a 3d line +core::line3df CAttributes::getAttributeAsLine3d(const c8* attributeName, const core::line3df& defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getLine3d(); + else + return defaultNotFound; +} + +//! Gets an attribute as a 3d line +core::line3df CAttributes::getAttributeAsLine3d(s32 index) const +{ + core::line3df ret(0,0,0, 0,0,0); + + if (index >= 0 && index < (s32)Attributes.size()) + ret = Attributes[index]->getLine3d(); + + return ret; +} + +//! Sets an attribute as a 3d line +void CAttributes::setAttribute(s32 index, const core::line3df& v) +{ + if (index >= 0 && index < (s32)Attributes.size() ) + Attributes[index]->setLine3d(v); + +} + + +//! Adds an attribute as user pointer +void CAttributes::addUserPointer(const c8* attributeName, void* userPointer) +{ + Attributes.push_back(new CUserPointerAttribute(attributeName, userPointer)); +} + +//! Sets an attribute as user pointer +void CAttributes::setAttribute(const c8* attributeName, void* userPointer) +{ + IAttribute* att = getAttributeP(attributeName); + if (att) + att->setUserPointer(userPointer); + else + { + Attributes.push_back(new CUserPointerAttribute(attributeName, userPointer)); + } +} + +//! Gets an attribute as user pointer +//! \param attributeName: Name of the attribute to get. +void* CAttributes::getAttributeAsUserPointer(const c8* attributeName, void* defaultNotFound) const +{ + const IAttribute* att = getAttributeP(attributeName); + if (att) + return att->getUserPointer(); + else + return defaultNotFound; +} + +//! Gets an attribute as user pointer +//! \param index: Index value, must be between 0 and getAttributeCount()-1. +void* CAttributes::getAttributeAsUserPointer(s32 index) const +{ + void* value = 0; + + if (index >= 0 && index < (s32)Attributes.size()) + value = Attributes[index]->getUserPointer(); + + return value; +} + +//! Sets an attribute as user pointer +void CAttributes::setAttribute(s32 index, void* userPointer) +{ + if (index >= 0 && index < (s32)Attributes.size() ) + Attributes[index]->setUserPointer(userPointer); +} + + +//! Reads attributes from a xml file. +//! \param readCurrentElementOnly: If set to true, reading only works if current element has the name 'attributes'. +//! IF set to false, the first appearing list attributes are read. +bool CAttributes::read(io::IXMLReader* reader, bool readCurrentElementOnly, + const wchar_t* nonDefaultElementName) +{ +#ifdef _IRR_COMPILE_WITH_XML_ + if (!reader) + return false; + + clear(); + + core::stringw elementName = L"attributes"; + if (nonDefaultElementName) + elementName = nonDefaultElementName; + + if (readCurrentElementOnly) + { + if (elementName != reader->getNodeName()) + return false; + } + + while(reader->read()) + { + switch(reader->getNodeType()) + { + case io::EXN_ELEMENT: + readAttributeFromXML(reader); + break; + case io::EXN_ELEMENT_END: + if (elementName == reader->getNodeName()) + return true; + break; + default: + break; + } + } + + return true; +#else + noXML(); + return false; +#endif +} + + +void CAttributes::readAttributeFromXML(const io::IXMLReader* reader) +{ +#ifdef _IRR_COMPILE_WITH_XML_ + core::stringw element = reader->getNodeName(); + core::stringc name = reader->getAttributeValue(L"name"); + + if (element == L"enum") + { + addEnum(name.c_str(), 0, 0); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"binary") + { + addBinary(name.c_str(), 0, 0); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"color") + { + addColor(name.c_str(), video::SColor()); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"colorf") + { + addColorf(name.c_str(), video::SColorf()); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"float") + { + addFloat(name.c_str(), 0); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"int") + { + addInt(name.c_str(), 0); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"bool") + { + addBool(name.c_str(), 0); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"string") + { + addString(name.c_str(), L""); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"texture") + { + addTexture(name.c_str(), 0); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"vector3d") + { + addVector3d(name.c_str(), core::vector3df()); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"vector2d") + { + addVector2d(name.c_str(), core::vector2df()); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"position") + { + addPosition2d(name.c_str(), core::position2di()); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"rect") + { + addRect(name.c_str(), core::rect()); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"matrix") + { + addMatrix(name.c_str(), core::matrix4()); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"quaternion") + { + addQuaternion(name.c_str(), core::quaternion()); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"box3d") + { + addBox3d(name.c_str(), core::aabbox3df()); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"plane") + { + addPlane3d(name.c_str(), core::plane3df()); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"triangle") + { + addTriangle3d(name.c_str(), core::triangle3df()); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"line2d") + { + addLine2d(name.c_str(), core::line2df()); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"line3d") + { + addLine3d(name.c_str(), core::line3df()); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } + else + if (element == L"stringwarray") + { + core::array tmpArray; + + const s32 count = reader->getAttributeValueAsInt(L"count"); + s32 n=0; + const core::stringw tmpName(L"value"); + for (; ngetAttributeValue((tmpName+core::stringw(n)).c_str())); + } + addArray(name.c_str(),tmpArray); + } + else + if (element == L"userPointer") + { + // It's debatable if a pointer should be set or not, but it's more likely that adding it now would wreck user-applications. + // Also it probably doesn't makes sense setting this to a value when it comes from file. + } + else + if (element == L"dimension2d") + { + addDimension2d(name.c_str(), core::dimension2d()); + Attributes.getLast()->setString(reader->getAttributeValue(L"value")); + } +#else + noXML(); +#endif +} + +//! Write these attributes into a xml file +bool CAttributes::write(io::IXMLWriter* writer, bool writeXMLHeader, + const wchar_t* nonDefaultElementName) +{ +#ifdef _IRR_COMPILE_WITH_XML_ + if (!writer) + return false; + + if (writeXMLHeader) + writer->writeXMLHeader(); + + core::stringw elementName = L"attributes"; + if (nonDefaultElementName) + elementName = nonDefaultElementName; + + writer->writeElement(elementName.c_str(), false); + writer->writeLineBreak(); + + s32 i=0; + for (; i<(s32)Attributes.size(); ++i) + { + if ( Attributes[i]->getType() == EAT_STRINGWARRAY ) + { + core::array arraynames, arrayvalues; + core::array arrayinput = Attributes[i]->getArray(); + + // build arrays + + // name + arraynames.push_back(core::stringw(L"name")); + arrayvalues.push_back(core::stringw(Attributes[i]->Name.c_str()) ); + + // count + arraynames.push_back(core::stringw(L"count")); + arrayvalues.push_back(core::stringw((s32)arrayinput.size())); + + // array... + u32 n=0; + const core::stringw tmpName(L"value"); + for (; n < arrayinput.size(); ++n) + { + arraynames.push_back((tmpName+core::stringw(n)).c_str()); + arrayvalues.push_back(arrayinput[n]); + } + + // write them + writer->writeElement( Attributes[i]->getTypeString(), true, arraynames, arrayvalues); + } + else + { + writer->writeElement( + Attributes[i]->getTypeString(), true, + L"name", core::stringw(Attributes[i]->Name.c_str()).c_str(), + L"value", Attributes[i]->getStringW().c_str() ); + } + + writer->writeLineBreak(); + } + + writer->writeClosingTag(elementName.c_str()); + writer->writeLineBreak(); + + return true; +#else + noXML(); + return false; +#endif +} + + +} // end namespace io +} // end namespace irr + diff --git a/source/Irrlicht/CAttributes.h b/source/Irrlicht/CAttributes.h new file mode 100644 index 00000000..466e9044 --- /dev/null +++ b/source/Irrlicht/CAttributes.h @@ -0,0 +1,738 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_ATTRIBUTES_H_INCLUDED__ +#define __C_ATTRIBUTES_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#include "IAttributes.h" +#include "IAttribute.h" + +namespace irr +{ +namespace video +{ + class ITexture; + class IVideoDriver; +} +namespace io +{ + + +//! Implementation of the IAttributes interface +class CAttributes : public IAttributes +{ +public: + + CAttributes(video::IVideoDriver* driver=0); + ~CAttributes(); + + //! Returns amount of attributes in this collection of attributes. + virtual u32 getAttributeCount() const _IRR_OVERRIDE_; + + //! Returns attribute name by index. + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual const c8* getAttributeName(s32 index) const _IRR_OVERRIDE_; + + //! Returns the type of an attribute + //! \param attributeName: Name for the attribute + virtual E_ATTRIBUTE_TYPE getAttributeType(const c8* attributeName) const _IRR_OVERRIDE_; + + //! Returns attribute type by index. + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual E_ATTRIBUTE_TYPE getAttributeType(s32 index) const _IRR_OVERRIDE_; + + //! Returns the type string of the attribute + //! \param attributeName: String for the attribute type + //! \param defaultNotFound Value returned when attributeName was not found + virtual const wchar_t* getAttributeTypeString(const c8* attributeName, const wchar_t* defaultNotFound = L"unknown") const _IRR_OVERRIDE_; + + //! 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, const wchar_t* defaultNotFound = L"unknown") const _IRR_OVERRIDE_; + + //! Returns if an attribute with a name exists + virtual bool existsAttribute(const c8* attributeName) const _IRR_OVERRIDE_; + + //! Returns attribute index from name, -1 if not found + virtual s32 findAttribute(const c8* attributeName) const _IRR_OVERRIDE_; + + //! Removes all attributes + virtual void clear() _IRR_OVERRIDE_; + + //! Reads attributes from a xml file. + //! \param readCurrentElementOnly: If set to true, reading only works if current element has the name 'attributes'. + //! IF set to false, the first appearing list attributes are read. + virtual bool read(io::IXMLReader* reader, bool readCurrentElementOnly=false, + const wchar_t* nonDefaultElementName = 0) _IRR_OVERRIDE_; + + //! Write these attributes into a xml file + virtual bool write(io::IXMLWriter* writer, bool writeXMLHeader=false, const wchar_t* nonDefaultElementName=0) _IRR_OVERRIDE_; + + + /* + + Integer Attribute + + */ + + //! Adds an attribute as integer + virtual void addInt(const c8* attributeName, s32 value) _IRR_OVERRIDE_; + + //! Sets an attribute as integer value + virtual void setAttribute(const c8* attributeName, s32 value) _IRR_OVERRIDE_; + + //! Gets an attribute as integer value + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual s32 getAttributeAsInt(const c8* attributeName, irr::s32 defaultNotFound=0) const _IRR_OVERRIDE_; + + //! Gets an attribute as integer value + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual s32 getAttributeAsInt(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute as integer value + virtual void setAttribute(s32 index, s32 value) _IRR_OVERRIDE_; + + /* + + Float Attribute + + */ + + //! Adds an attribute as float + virtual void addFloat(const c8* attributeName, f32 value) _IRR_OVERRIDE_; + + //! Sets a attribute as float value + virtual void setAttribute(const c8* attributeName, f32 value) _IRR_OVERRIDE_; + + //! Gets an attribute as float value + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual f32 getAttributeAsFloat(const c8* attributeName, irr::f32 defaultNotFound=0.f) const _IRR_OVERRIDE_; + + //! Gets an attribute as float value + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual f32 getAttributeAsFloat(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute as float value + virtual void setAttribute(s32 index, f32 value) _IRR_OVERRIDE_; + + /* + + String Attribute + + */ + + //! Adds an attribute as string + virtual void addString(const c8* attributeName, const c8* value) _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! Gets an attribute as string. + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + //! or defaultNotFound if attribute is not set. + virtual core::stringc getAttributeAsString(const c8* attributeName, const core::stringc& defaultNotFound=core::stringc()) const _IRR_OVERRIDE_; + + //! Gets an attribute as string. + //! \param attributeName: Name of the attribute to get. + //! \param target: Buffer where the string is copied to. + virtual void getAttributeAsString(const c8* attributeName, c8* target) const _IRR_OVERRIDE_; + + //! Returns attribute value as string by index. + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::stringc getAttributeAsString(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute value as string. + //! \param attributeName: Name for the attribute + virtual void setAttribute(s32 index, const c8* value) _IRR_OVERRIDE_; + + // wide strings + + //! Adds an attribute as string + virtual void addString(const c8* attributeName, const wchar_t* value) _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! Gets an attribute as string. + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + //! or defaultNotFound if attribute is not set. + virtual core::stringw getAttributeAsStringW(const c8* attributeName, const core::stringw& defaultNotFound = core::stringw()) const _IRR_OVERRIDE_; + + //! Gets an attribute as string. + //! \param attributeName: Name of the attribute to get. + //! \param target: Buffer where the string is copied to. + virtual void getAttributeAsStringW(const c8* attributeName, wchar_t* target) const _IRR_OVERRIDE_; + + //! Returns attribute value as string by index. + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::stringw getAttributeAsStringW(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute value as string. + //! \param attributeName: Name for the attribute + virtual void setAttribute(s32 index, const wchar_t* value) _IRR_OVERRIDE_; + + /* + + Binary Data Attribute + + */ + + //! Adds an attribute as binary data + virtual void addBinary(const c8* attributeName, void* data, s32 dataSizeInBytes) _IRR_OVERRIDE_; + + //! Sets an attribute as binary data + virtual void setAttribute(const c8* attributeName, void* data, s32 dataSizeInBytes) _IRR_OVERRIDE_; + + //! Gets an attribute as binary data + //! \param attributeName: Name of the attribute to get. + virtual void getAttributeAsBinaryData(const c8* attributeName, void* outData, s32 maxSizeInBytes) const _IRR_OVERRIDE_; + + //! Gets an attribute as binary data + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual void getAttributeAsBinaryData(s32 index, void* outData, s32 maxSizeInBytes) const _IRR_OVERRIDE_; + + //! Sets an attribute as binary data + virtual void setAttribute(s32 index, void* data, s32 dataSizeInBytes) _IRR_OVERRIDE_; + + + /* + + Array Attribute + + */ + + //! Adds an attribute as wide string array + virtual void addArray(const c8* attributeName, const core::array& value) _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! Gets an attribute as an array of wide strings. + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + //! or defaultNotFound if attribute is not set. + virtual core::array getAttributeAsArray(const c8* attributeName, const core::array& defaultNotFound = core::array()) const _IRR_OVERRIDE_; + + //! 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) const _IRR_OVERRIDE_; + + //! Sets an attribute as an array of wide strings + virtual void setAttribute(s32 index, const core::array& value) _IRR_OVERRIDE_; + + /* + + Bool Attribute + + */ + + //! Adds an attribute as bool + virtual void addBool(const c8* attributeName, bool value) _IRR_OVERRIDE_; + + //! Sets an attribute as boolean value + virtual void setAttribute(const c8* attributeName, bool value) _IRR_OVERRIDE_; + + //! Gets an attribute as boolean value + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual bool getAttributeAsBool(const c8* attributeName, bool defaultNotFound=false) const _IRR_OVERRIDE_; + + //! Gets an attribute as boolean value + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual bool getAttributeAsBool(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute as boolean value + virtual void setAttribute(s32 index, bool value) _IRR_OVERRIDE_; + + /* + + Enumeration Attribute + + */ + + //! Adds an attribute as enum + virtual void addEnum(const c8* attributeName, const c8* enumValue, const c8* const* enumerationLiterals) _IRR_OVERRIDE_; + + //! Adds an attribute as enum + virtual void addEnum(const c8* attributeName, s32 enumValue, const c8* const* enumerationLiterals) _IRR_OVERRIDE_; + + //! Sets an attribute as enumeration + virtual void setAttribute(const c8* attributeName, const c8* enumValue, const c8* const* enumerationLiterals) _IRR_OVERRIDE_; + + //! Gets an attribute as enumeration + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual const c8* getAttributeAsEnumeration(const c8* attributeName, const c8* defaultNotFound = 0) const _IRR_OVERRIDE_; + + //! Gets an attribute as enumeration + //! \param attributeName: Name of the attribute to get. + //! \param enumerationLiteralsToUse: Use these enumeration literals to get the index value instead of the set ones. + //! This is useful when the attribute list maybe was read from an xml file, and only contains the enumeration string, but + //! no information about its index. + //! \return Returns value of the attribute previously set by setAttribute() + virtual s32 getAttributeAsEnumeration(const c8* attributeName, const c8* const* enumerationLiteralsToUse, s32 defaultNotFound ) const _IRR_OVERRIDE_; + + //! Gets an attribute as enumeration + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual s32 getAttributeAsEnumeration(s32 index, const c8* const* enumerationLiteralsToUse, s32 defaultNotFound) const _IRR_OVERRIDE_; + + //! Gets an attribute as enumeration + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual const c8* getAttributeAsEnumeration(s32 index) const _IRR_OVERRIDE_; + + //! 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) const _IRR_OVERRIDE_; + + //! 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) const _IRR_OVERRIDE_; + + //! Sets an attribute as enumeration + virtual void setAttribute(s32 index, const c8* enumValue, const c8* const* enumerationLiterals) _IRR_OVERRIDE_; + + + /* + + SColor Attribute + + */ + + //! Adds an attribute as color + virtual void addColor(const c8* attributeName, video::SColor value) _IRR_OVERRIDE_; + + //! Sets a attribute as color + virtual void setAttribute(const c8* attributeName, video::SColor color) _IRR_OVERRIDE_; + + //! Gets an attribute as color + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual video::SColor getAttributeAsColor(const c8* attributeName, const video::SColor& defaultNotFound = video::SColor(0)) const _IRR_OVERRIDE_; + + //! Gets an attribute as color + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual video::SColor getAttributeAsColor(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute as color + virtual void setAttribute(s32 index, video::SColor color) _IRR_OVERRIDE_; + + /* + + SColorf Attribute + + */ + + //! Adds an attribute as floating point color + virtual void addColorf(const c8* attributeName, video::SColorf value) _IRR_OVERRIDE_; + + //! Sets a attribute as floating point color + virtual void setAttribute(const c8* attributeName, video::SColorf color) _IRR_OVERRIDE_; + + //! Gets an attribute as floating point color + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual video::SColorf getAttributeAsColorf(const c8* attributeName, const video::SColorf& defaultNotFound = video::SColorf(0)) const _IRR_OVERRIDE_; + + //! Gets an attribute as floating point color + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual video::SColorf getAttributeAsColorf(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute as floating point color + virtual void setAttribute(s32 index, video::SColorf color) _IRR_OVERRIDE_; + + + /* + + Vector3d Attribute + + */ + + //! Adds an attribute as 3d vector + virtual void addVector3d(const c8* attributeName, const core::vector3df& value) _IRR_OVERRIDE_; + + //! Sets a attribute as 3d vector + virtual void setAttribute(const c8* attributeName, const core::vector3df& v) _IRR_OVERRIDE_; + + //! Gets an attribute as 3d vector + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::vector3df getAttributeAsVector3d(const c8* attributeName, const core::vector3df& defaultNotFound=core::vector3df(0,0,0)) const _IRR_OVERRIDE_; + + //! Gets an attribute as 3d vector + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::vector3df getAttributeAsVector3d(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute as vector + virtual void setAttribute(s32 index, const core::vector3df& v) _IRR_OVERRIDE_; + + + /* + + Vector2d Attribute + + */ + + //! Adds an attribute as 2d vector + virtual void addVector2d(const c8* attributeName, const core::vector2df& value) _IRR_OVERRIDE_; + + //! Sets a attribute as 2d vector + virtual void setAttribute(const c8* attributeName, const core::vector2df& v) _IRR_OVERRIDE_; + + //! Gets an attribute as 2d vector + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::vector2df getAttributeAsVector2d(const c8* attributeName, const core::vector2df& defaultNotFound=core::vector2df(0,0)) const _IRR_OVERRIDE_; + + //! Gets an attribute as 3d vector + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::vector2df getAttributeAsVector2d(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute as vector + virtual void setAttribute(s32 index, const core::vector2df& v) _IRR_OVERRIDE_; + + + /* + + Position2d Attribute + + */ + + //! Adds an attribute as 2d position + virtual void addPosition2d(const c8* attributeName, const core::position2di& value) _IRR_OVERRIDE_; + + //! Sets a attribute as 2d position + virtual void setAttribute(const c8* attributeName, const core::position2di& v) _IRR_OVERRIDE_; + + //! Gets an attribute as position + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::position2di getAttributeAsPosition2d(const c8* attributeName, const core::position2di& defaultNotFound=core::position2di(0,0)) const _IRR_OVERRIDE_; + + //! Gets an attribute as position + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::position2di getAttributeAsPosition2d(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute as 2d position + virtual void setAttribute(s32 index, const core::position2di& v) _IRR_OVERRIDE_; + + /* + + Rectangle Attribute + + */ + + //! Adds an attribute as rectangle + virtual void addRect(const c8* attributeName, const core::rect& value) _IRR_OVERRIDE_; + + //! Sets an attribute as rectangle + virtual void setAttribute(const c8* attributeName, const core::rect& v) _IRR_OVERRIDE_; + + //! Gets an attribute as rectangle + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::rect getAttributeAsRect(const c8* attributeName, const core::rect& defaultNotFound = core::rect()) const _IRR_OVERRIDE_; + + //! Gets an attribute as rectangle + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::rect getAttributeAsRect(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute as rectangle + virtual void setAttribute(s32 index, const core::rect& v) _IRR_OVERRIDE_; + + + /* + + Dimension2d Attribute + + */ + + //! Adds an attribute as dimension2d + virtual void addDimension2d(const c8* attributeName, const core::dimension2d& value) _IRR_OVERRIDE_; + + //! Sets an attribute as dimension2d + virtual void setAttribute(const c8* attributeName, const core::dimension2d& v) _IRR_OVERRIDE_; + + //! Gets an attribute as dimension2d + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::dimension2d getAttributeAsDimension2d(const c8* attributeName, const core::dimension2d& defaultNotFound = core::dimension2d()) const _IRR_OVERRIDE_; + + //! Gets an attribute as dimension2d + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::dimension2d getAttributeAsDimension2d(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute as dimension2d + virtual void setAttribute(s32 index, const core::dimension2d& v) _IRR_OVERRIDE_; + + + /* + + matrix attribute + + */ + + //! Adds an attribute as matrix + virtual void addMatrix(const c8* attributeName, const core::matrix4& v) _IRR_OVERRIDE_; + + //! Sets an attribute as matrix + virtual void setAttribute(const c8* attributeName, const core::matrix4& v) _IRR_OVERRIDE_; + + //! Gets an attribute as a matrix4 + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::matrix4 getAttributeAsMatrix(const c8* attributeName, const core::matrix4& defaultNotFound=core::matrix4()) const _IRR_OVERRIDE_; + + //! Gets an attribute as matrix + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::matrix4 getAttributeAsMatrix(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute as matrix + virtual void setAttribute(s32 index, const core::matrix4& v) _IRR_OVERRIDE_; + + /* + quaternion attribute + + */ + + //! Adds an attribute as quaternion + virtual void addQuaternion(const c8* attributeName, const core::quaternion& v) _IRR_OVERRIDE_; + + //! Sets an attribute as quaternion + virtual void setAttribute(const c8* attributeName, const core::quaternion& v) _IRR_OVERRIDE_; + + //! Gets an attribute as a quaternion + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::quaternion getAttributeAsQuaternion(const c8* attributeName, const core::quaternion& defaultNotFound=core::quaternion(0,1,0, 0)) const _IRR_OVERRIDE_; + + //! Gets an attribute as quaternion + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::quaternion getAttributeAsQuaternion(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute as quaternion + virtual void setAttribute(s32 index, const core::quaternion& v) _IRR_OVERRIDE_; + + /* + + 3d bounding box + + */ + + //! Adds an attribute as axis aligned bounding box + virtual void addBox3d(const c8* attributeName, const core::aabbox3df& v) _IRR_OVERRIDE_; + + //! Sets an attribute as axis aligned bounding box + virtual void setAttribute(const c8* attributeName, const core::aabbox3df& v) _IRR_OVERRIDE_; + + //! Gets an attribute as a axis aligned bounding box + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::aabbox3df getAttributeAsBox3d(const c8* attributeName, const core::aabbox3df& defaultNotFound=core::aabbox3df(0,0,0, 0,0,0)) const _IRR_OVERRIDE_; + + //! Gets an attribute as axis aligned bounding box + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::aabbox3df getAttributeAsBox3d(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute as axis aligned bounding box + virtual void setAttribute(s32 index, const core::aabbox3df& v) _IRR_OVERRIDE_; + + /* + + plane + + */ + + //! Adds an attribute as 3d plane + virtual void addPlane3d(const c8* attributeName, const core::plane3df& v) _IRR_OVERRIDE_; + + //! Sets an attribute as 3d plane + virtual void setAttribute(const c8* attributeName, const core::plane3df& v) _IRR_OVERRIDE_; + + //! Gets an attribute as a 3d plane + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::plane3df getAttributeAsPlane3d(const c8* attributeName, const core::plane3df& defaultNotFound=core::plane3df(0,0,0, 0,1,0)) const _IRR_OVERRIDE_; + + //! Gets an attribute as 3d plane + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::plane3df getAttributeAsPlane3d(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute as 3d plane + virtual void setAttribute(s32 index, const core::plane3df& v) _IRR_OVERRIDE_; + + + /* + + 3d triangle + + */ + + //! Adds an attribute as 3d triangle + virtual void addTriangle3d(const c8* attributeName, const core::triangle3df& v) _IRR_OVERRIDE_; + + //! Sets an attribute as 3d triangle + virtual void setAttribute(const c8* attributeName, const core::triangle3df& v) _IRR_OVERRIDE_; + + //! Gets an attribute as a 3d triangle + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::triangle3df getAttributeAsTriangle3d(const c8* attributeName, const core::triangle3df& defaultNotFound = core::triangle3df(core::vector3df(0,0,0), core::vector3df(0,0,0), core::vector3df(0,0,0))) const _IRR_OVERRIDE_; + + //! Gets an attribute as 3d triangle + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::triangle3df getAttributeAsTriangle3d(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute as 3d triangle + virtual void setAttribute(s32 index, const core::triangle3df& v) _IRR_OVERRIDE_; + + + /* + + line 2d + + */ + + //! Adds an attribute as a 2d line + virtual void addLine2d(const c8* attributeName, const core::line2df& v) _IRR_OVERRIDE_; + + //! Sets an attribute as a 2d line + virtual void setAttribute(const c8* attributeName, const core::line2df& v) _IRR_OVERRIDE_; + + //! Gets an attribute as a 2d line + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::line2df getAttributeAsLine2d(const c8* attributeName, const core::line2df& defaultNotFound = core::line2df(0,0, 0,0)) const _IRR_OVERRIDE_; + + //! Gets an attribute as a 2d line + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::line2df getAttributeAsLine2d(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute as a 2d line + virtual void setAttribute(s32 index, const core::line2df& v) _IRR_OVERRIDE_; + + + /* + + line 3d + + */ + + //! Adds an attribute as a 3d line + virtual void addLine3d(const c8* attributeName, const core::line3df& v) _IRR_OVERRIDE_; + + //! Sets an attribute as a 3d line + virtual void setAttribute(const c8* attributeName, const core::line3df& v) _IRR_OVERRIDE_; + + //! Gets an attribute as a 3d line + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + //! \return Returns value of the attribute previously set by setAttribute() + virtual core::line3df getAttributeAsLine3d(const c8* attributeName, const core::line3df& defaultNotFound=core::line3df(0,0,0, 0,0,0)) const _IRR_OVERRIDE_; + + //! Gets an attribute as a 3d line + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual core::line3df getAttributeAsLine3d(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute as a 3d line + virtual void setAttribute(s32 index, const core::line3df& v) _IRR_OVERRIDE_; + + + /* + + Texture Attribute + + */ + + //! Adds an attribute as texture reference + virtual void addTexture(const c8* attributeName, video::ITexture* texture, const io::path& filename = "") _IRR_OVERRIDE_; + + //! Sets an attribute as texture reference + virtual void setAttribute(const c8* attributeName, video::ITexture* texture, const io::path& filename = "") _IRR_OVERRIDE_; + + //! Gets an attribute as texture reference + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + virtual video::ITexture* getAttributeAsTexture(const c8* attributeName, video::ITexture* defaultNotFound=0) const _IRR_OVERRIDE_; + + //! Gets an attribute as texture reference + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual video::ITexture* getAttributeAsTexture(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute as texture reference + virtual void setAttribute(s32 index, video::ITexture* texture, const io::path& filename = "") _IRR_OVERRIDE_; + + + + /* + + User Pointer Attribute + + */ + + //! Adds an attribute as user pointer + virtual void addUserPointer(const c8* attributeName, void* userPointer) _IRR_OVERRIDE_; + + //! Sets an attribute as user pointer + virtual void setAttribute(const c8* attributeName, void* userPointer) _IRR_OVERRIDE_; + + //! Gets an attribute as user pointer + //! \param attributeName: Name of the attribute to get. + //! \param defaultNotFound Value returned when attributeName was not found + virtual void* getAttributeAsUserPointer(const c8* attributeName, void* defaultNotFound = 0) const _IRR_OVERRIDE_; + + //! Gets an attribute as user pointer + //! \param index: Index value, must be between 0 and getAttributeCount()-1. + virtual void* getAttributeAsUserPointer(s32 index) const _IRR_OVERRIDE_; + + //! Sets an attribute as user pointer + virtual void setAttribute(s32 index, void* userPointer) _IRR_OVERRIDE_; + +protected: + + void readAttributeFromXML(const io::IXMLReader* reader); + + core::array Attributes; + + IAttribute* getAttributeP(const c8* attributeName) const; + + video::IVideoDriver* Driver; +}; + +} // end namespace io +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CB3DMeshFileLoader.cpp b/source/Irrlicht/CB3DMeshFileLoader.cpp new file mode 100644 index 00000000..c473d529 --- /dev/null +++ b/source/Irrlicht/CB3DMeshFileLoader.cpp @@ -0,0 +1,1106 @@ +// Copyright (C) 2006-2012 Luke Hoschke +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +// B3D Mesh loader +// File format designed by Mark Sibly for the Blitz3D engine and has been +// declared public domain + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_B3D_LOADER_ + +#include "CB3DMeshFileLoader.h" +#include "CMeshTextureLoader.h" + +#include "IVideoDriver.h" +#include "IFileSystem.h" +#include "os.h" + +#ifdef _DEBUG +#define _B3D_READER_DEBUG +#endif + +namespace irr +{ +namespace scene +{ + +//! Constructor +CB3DMeshFileLoader::CB3DMeshFileLoader(scene::ISceneManager* smgr) +: SceneManager(smgr), AnimatedMesh(0), B3DFile(0), NormalsInFile(false), + HasVertexColors(false), ShowWarning(true) +{ + #ifdef _DEBUG + setDebugName("CB3DMeshFileLoader"); + #endif + + TextureLoader = new CMeshTextureLoader( SceneManager->getFileSystem(), SceneManager->getVideoDriver() ); +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool CB3DMeshFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "b3d" ); +} + + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IReferenceCounted::drop() for more information. +IAnimatedMesh* CB3DMeshFileLoader::createMesh(io::IReadFile* file) +{ + if (!file) + return 0; + + if ( getMeshTextureLoader() ) + getMeshTextureLoader()->setMeshFile(file); + + B3DFile = file; + AnimatedMesh = new scene::CSkinnedMesh(); + ShowWarning = true; // If true a warning is issued if too many textures are used + VerticesStart=0; + + if ( load() ) + { + AnimatedMesh->finalize(); + } + else + { + AnimatedMesh->drop(); + AnimatedMesh = 0; + } + + return AnimatedMesh; +} + + +bool CB3DMeshFileLoader::load() +{ + B3dStack.clear(); + + NormalsInFile=false; + HasVertexColors=false; + + //------ Get header ------ + + SB3dChunkHeader header; + B3DFile->read(&header, sizeof(header)); +#ifdef __BIG_ENDIAN__ + header.size = os::Byteswap::byteswap(header.size); +#endif + + if ( strncmp( header.name, "BB3D", 4 ) != 0 ) + { + os::Printer::log("File is not a b3d file. Loading failed (No header found)", B3DFile->getFileName(), ELL_ERROR); + return false; + } + + // Add main chunk... + B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8)); + + // Get file version, but ignore it, as it's not important with b3d files... + s32 fileVersion; + B3DFile->read(&fileVersion, sizeof(fileVersion)); +#ifdef __BIG_ENDIAN__ + fileVersion = os::Byteswap::byteswap(fileVersion); +#endif + + //------ Read main chunk ------ + + while ( (B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos() ) + { + B3DFile->read(&header, sizeof(header)); +#ifdef __BIG_ENDIAN__ + header.size = os::Byteswap::byteswap(header.size); +#endif + B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8)); + + if ( strncmp( B3dStack.getLast().name, "TEXS", 4 ) == 0 ) + { + if (!readChunkTEXS()) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "BRUS", 4 ) == 0 ) + { + if (!readChunkBRUS()) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "NODE", 4 ) == 0 ) + { + if (!readChunkNODE((CSkinnedMesh::SJoint*)0) ) + return false; + } + else + { + os::Printer::log("Unknown chunk found in mesh base - skipping"); + B3DFile->seek(B3dStack.getLast().startposition + B3dStack.getLast().length); + B3dStack.erase(B3dStack.size()-1); + } + } + + B3dStack.clear(); + + BaseVertices.clear(); + AnimatedVertices_VertexID.clear(); + AnimatedVertices_BufferID.clear(); + + Materials.clear(); + Textures.clear(); + + return true; +} + + +bool CB3DMeshFileLoader::readChunkNODE(CSkinnedMesh::SJoint *inJoint) +{ + CSkinnedMesh::SJoint *joint = AnimatedMesh->addJoint(inJoint); + readString(joint->Name); + +#ifdef _B3D_READER_DEBUG + core::stringc logStr; + for ( u32 i=1; i < B3dStack.size(); ++i ) + logStr += "-"; + logStr += "read ChunkNODE"; + os::Printer::log(logStr.c_str(), joint->Name.c_str(), ELL_DEBUG); +#endif + + f32 position[3], scale[3], rotation[4]; + + readFloats(position, 3); + readFloats(scale, 3); + readFloats(rotation, 4); + + joint->Animatedposition = core::vector3df(position[0],position[1],position[2]) ; + joint->Animatedscale = core::vector3df(scale[0],scale[1],scale[2]); + joint->Animatedrotation = core::quaternion(rotation[1], rotation[2], rotation[3], rotation[0]); + + //Build LocalMatrix: + + core::matrix4 positionMatrix; + positionMatrix.setTranslation( joint->Animatedposition ); + core::matrix4 scaleMatrix; + scaleMatrix.setScale( joint->Animatedscale ); + core::matrix4 rotationMatrix; + joint->Animatedrotation.getMatrix_transposed(rotationMatrix); + + joint->LocalMatrix = positionMatrix * rotationMatrix * scaleMatrix; + + if (inJoint) + joint->GlobalMatrix = inJoint->GlobalMatrix * joint->LocalMatrix; + else + joint->GlobalMatrix = joint->LocalMatrix; + + while(B3dStack.getLast().startposition + B3dStack.getLast().length > B3DFile->getPos()) // this chunk repeats + { + SB3dChunkHeader header; + B3DFile->read(&header, sizeof(header)); +#ifdef __BIG_ENDIAN__ + header.size = os::Byteswap::byteswap(header.size); +#endif + + B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8)); + + if ( strncmp( B3dStack.getLast().name, "NODE", 4 ) == 0 ) + { + if (!readChunkNODE(joint)) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "MESH", 4 ) == 0 ) + { + VerticesStart=BaseVertices.size(); + if (!readChunkMESH(joint)) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "BONE", 4 ) == 0 ) + { + if (!readChunkBONE(joint)) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "KEYS", 4 ) == 0 ) + { + if(!readChunkKEYS(joint)) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "ANIM", 4 ) == 0 ) + { + if (!readChunkANIM()) + return false; + } + else + { + os::Printer::log("Unknown chunk found in node chunk - skipping"); + B3DFile->seek(B3dStack.getLast().startposition + B3dStack.getLast().length); + B3dStack.erase(B3dStack.size()-1); + } + } + + B3dStack.erase(B3dStack.size()-1); + + return true; +} + + +bool CB3DMeshFileLoader::readChunkMESH(CSkinnedMesh::SJoint *inJoint) +{ +#ifdef _B3D_READER_DEBUG + core::stringc logStr; + for ( u32 i=1; i < B3dStack.size(); ++i ) + logStr += "-"; + logStr += "read ChunkMESH"; + os::Printer::log(logStr.c_str(), ELL_DEBUG); +#endif + + s32 brushID; + B3DFile->read(&brushID, sizeof(brushID)); +#ifdef __BIG_ENDIAN__ + brushID = os::Byteswap::byteswap(brushID); +#endif + + NormalsInFile=false; + HasVertexColors=false; + + while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) //this chunk repeats + { + SB3dChunkHeader header; + B3DFile->read(&header, sizeof(header)); +#ifdef __BIG_ENDIAN__ + header.size = os::Byteswap::byteswap(header.size); +#endif + + B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8)); + + if ( strncmp( B3dStack.getLast().name, "VRTS", 4 ) == 0 ) + { + if (!readChunkVRTS(inJoint)) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "TRIS", 4 ) == 0 ) + { + scene::SSkinMeshBuffer *meshBuffer = AnimatedMesh->addMeshBuffer(); + + if (brushID!=-1) + { + loadTextures(Materials[brushID]); + meshBuffer->Material=Materials[brushID].Material; + } + + if(readChunkTRIS(meshBuffer,AnimatedMesh->getMeshBuffers().size()-1, VerticesStart)==false) + return false; + + if (!NormalsInFile) + { + s32 i; + + for ( i=0; i<(s32)meshBuffer->Indices.size(); i+=3) + { + core::plane3df p(meshBuffer->getVertex(meshBuffer->Indices[i+0])->Pos, + meshBuffer->getVertex(meshBuffer->Indices[i+1])->Pos, + meshBuffer->getVertex(meshBuffer->Indices[i+2])->Pos); + + meshBuffer->getVertex(meshBuffer->Indices[i+0])->Normal += p.Normal; + meshBuffer->getVertex(meshBuffer->Indices[i+1])->Normal += p.Normal; + meshBuffer->getVertex(meshBuffer->Indices[i+2])->Normal += p.Normal; + } + + for ( i = 0; i<(s32)meshBuffer->getVertexCount(); ++i ) + { + meshBuffer->getVertex(i)->Normal.normalize(); + BaseVertices[VerticesStart+i].Normal=meshBuffer->getVertex(i)->Normal; + } + } + } + else + { + os::Printer::log("Unknown chunk found in mesh - skipping"); + B3DFile->seek(B3dStack.getLast().startposition + B3dStack.getLast().length); + B3dStack.erase(B3dStack.size()-1); + } + } + + B3dStack.erase(B3dStack.size()-1); + + return true; +} + + +/* +VRTS: + int flags ;1=normal values present, 2=rgba values present + int tex_coord_sets ;texture coords per vertex (eg: 1 for simple U/V) max=8 + but we only support 3 + int tex_coord_set_size ;components per set (eg: 2 for simple U/V) max=4 + { + float x,y,z ;always present + float nx,ny,nz ;vertex normal: present if (flags&1) + float red,green,blue,alpha ;vertex color: present if (flags&2) + float tex_coords[tex_coord_sets][tex_coord_set_size] ;tex coords + } +*/ +bool CB3DMeshFileLoader::readChunkVRTS(CSkinnedMesh::SJoint *inJoint) +{ +#ifdef _B3D_READER_DEBUG + core::stringc logStr; + for ( u32 i=1; i < B3dStack.size(); ++i ) + logStr += "-"; + logStr += "ChunkVRTS"; + os::Printer::log(logStr.c_str(), ELL_DEBUG); +#endif + + const s32 max_tex_coords = 3; + s32 flags, tex_coord_sets, tex_coord_set_size; + + B3DFile->read(&flags, sizeof(flags)); + B3DFile->read(&tex_coord_sets, sizeof(tex_coord_sets)); + B3DFile->read(&tex_coord_set_size, sizeof(tex_coord_set_size)); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); + tex_coord_sets = os::Byteswap::byteswap(tex_coord_sets); + tex_coord_set_size = os::Byteswap::byteswap(tex_coord_set_size); +#endif + + if (tex_coord_sets >= max_tex_coords || tex_coord_set_size >= 4) // Something is wrong + { + os::Printer::log("tex_coord_sets or tex_coord_set_size too big", B3DFile->getFileName(), ELL_ERROR); + return false; + } + + //------ Allocate Memory, for speed -----------// + + s32 numberOfReads = 3; + + if (flags & 1) + { + NormalsInFile = true; + numberOfReads += 3; + } + if (flags & 2) + { + numberOfReads += 4; + HasVertexColors=true; + } + + numberOfReads += tex_coord_sets*tex_coord_set_size; + + const s32 memoryNeeded = (B3dStack.getLast().length / sizeof(f32)) / numberOfReads; + + BaseVertices.reallocate(memoryNeeded + BaseVertices.size() + 1); + AnimatedVertices_VertexID.reallocate(memoryNeeded + AnimatedVertices_VertexID.size() + 1); + + //--------------------------------------------// + + while( (B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) // this chunk repeats + { + f32 position[3]; + f32 normal[3]={0.f, 0.f, 0.f}; + f32 color[4]={1.0f, 1.0f, 1.0f, 1.0f}; + f32 tex_coords[max_tex_coords][4]; + + readFloats(position, 3); + + if (flags & 1) + readFloats(normal, 3); + if (flags & 2) + readFloats(color, 4); + + for (s32 i=0; i= 1 && tex_coord_set_size >= 2) + { + tu=tex_coords[0][0]; + tv=tex_coords[0][1]; + } + + f32 tu2=0.0f, tv2=0.0f; + if (tex_coord_sets>1 && tex_coord_set_size>1) + { + tu2=tex_coords[1][0]; + tv2=tex_coords[1][1]; + } + + // Create Vertex... + video::S3DVertex2TCoords Vertex(position[0], position[1], position[2], + normal[0], normal[1], normal[2], + video::SColorf(color[0], color[1], color[2], color[3]).toSColor(), + tu, tv, tu2, tv2); + + // Transform the Vertex position by nested node... + inJoint->GlobalMatrix.transformVect(Vertex.Pos); + inJoint->GlobalMatrix.rotateVect(Vertex.Normal); + + //Add it... + BaseVertices.push_back(Vertex); + + AnimatedVertices_VertexID.push_back(-1); + AnimatedVertices_BufferID.push_back(-1); + } + + B3dStack.erase(B3dStack.size()-1); + + return true; +} + + +bool CB3DMeshFileLoader::readChunkTRIS(scene::SSkinMeshBuffer *meshBuffer, u32 meshBufferID, s32 vertices_Start) +{ +#ifdef _B3D_READER_DEBUG + core::stringc logStr; + for ( u32 i=1; i < B3dStack.size(); ++i ) + logStr += "-"; + logStr += "ChunkTRIS"; + os::Printer::log(logStr.c_str(), ELL_DEBUG); +#endif + + bool showVertexWarning=false; + + s32 triangle_brush_id; // Note: Irrlicht can't have different brushes for each triangle (using a workaround) + B3DFile->read(&triangle_brush_id, sizeof(triangle_brush_id)); +#ifdef __BIG_ENDIAN__ + triangle_brush_id = os::Byteswap::byteswap(triangle_brush_id); +#endif + + SB3dMaterial *B3dMaterial; + + if (triangle_brush_id != -1) + { + loadTextures(Materials[triangle_brush_id]); + B3dMaterial = &Materials[triangle_brush_id]; + meshBuffer->Material = B3dMaterial->Material; + } + else + B3dMaterial = 0; + + const s32 memoryNeeded = B3dStack.getLast().length / sizeof(s32); + meshBuffer->Indices.reallocate(memoryNeeded + meshBuffer->Indices.size() + 1); + + while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) // this chunk repeats + { + s32 vertex_id[3]; + + B3DFile->read(vertex_id, 3*sizeof(s32)); +#ifdef __BIG_ENDIAN__ + vertex_id[0] = os::Byteswap::byteswap(vertex_id[0]); + vertex_id[1] = os::Byteswap::byteswap(vertex_id[1]); + vertex_id[2] = os::Byteswap::byteswap(vertex_id[2]); +#endif + + //Make Ids global: + vertex_id[0] += vertices_Start; + vertex_id[1] += vertices_Start; + vertex_id[2] += vertices_Start; + + for(s32 i=0; i<3; ++i) + { + if ((u32)vertex_id[i] >= AnimatedVertices_VertexID.size()) + { + os::Printer::log("Illegal vertex index found", B3DFile->getFileName(), ELL_ERROR); + return false; + } + + if (AnimatedVertices_VertexID[ vertex_id[i] ] != -1) + { + if ( AnimatedVertices_BufferID[ vertex_id[i] ] != (s32)meshBufferID ) //If this vertex is linked in a different meshbuffer + { + AnimatedVertices_VertexID[ vertex_id[i] ] = -1; + AnimatedVertices_BufferID[ vertex_id[i] ] = -1; + showVertexWarning=true; + } + } + if (AnimatedVertices_VertexID[ vertex_id[i] ] == -1) //If this vertex is not in the meshbuffer + { + //Check for lightmapping: + if (BaseVertices[ vertex_id[i] ].TCoords2 != core::vector2df(0.f,0.f)) + meshBuffer->convertTo2TCoords(); //Will only affect the meshbuffer the first time this is called + + //Add the vertex to the meshbuffer: + if (meshBuffer->VertexType == video::EVT_STANDARD) + meshBuffer->Vertices_Standard.push_back( BaseVertices[ vertex_id[i] ] ); + else + meshBuffer->Vertices_2TCoords.push_back(BaseVertices[ vertex_id[i] ] ); + + //create vertex id to meshbuffer index link: + AnimatedVertices_VertexID[ vertex_id[i] ] = meshBuffer->getVertexCount()-1; + AnimatedVertices_BufferID[ vertex_id[i] ] = meshBufferID; + + if (B3dMaterial) + { + // Apply Material/Color/etc... + video::S3DVertex *Vertex=meshBuffer->getVertex(meshBuffer->getVertexCount()-1); + + if (!HasVertexColors) + Vertex->Color=B3dMaterial->Material.DiffuseColor; + else if (Vertex->Color.getAlpha() == 255) + Vertex->Color.setAlpha( (s32)(B3dMaterial->alpha * 255.0f) ); + + // Use texture's scale + if (B3dMaterial->Textures[0]) + { + Vertex->TCoords.X *= B3dMaterial->Textures[0]->Xscale; + Vertex->TCoords.Y *= B3dMaterial->Textures[0]->Yscale; + } + /* + if (B3dMaterial->Textures[1]) + { + Vertex->TCoords2.X *=B3dMaterial->Textures[1]->Xscale; + Vertex->TCoords2.Y *=B3dMaterial->Textures[1]->Yscale; + } + */ + } + } + } + + meshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[0] ] ); + meshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[1] ] ); + meshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[2] ] ); + } + + B3dStack.erase(B3dStack.size()-1); + + if (showVertexWarning) + os::Printer::log("B3dMeshLoader: Warning, different meshbuffers linking to the same vertex, this will cause problems with animated meshes"); + + return true; +} + + +bool CB3DMeshFileLoader::readChunkBONE(CSkinnedMesh::SJoint *inJoint) +{ +#ifdef _B3D_READER_DEBUG + core::stringc logStr; + for ( u32 i=1; i < B3dStack.size(); ++i ) + logStr += "-"; + logStr += "read ChunkBONE"; + os::Printer::log(logStr.c_str(), ELL_DEBUG); +#endif + + if (B3dStack.getLast().length > 8) + { + while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) // this chunk repeats + { + u32 globalVertexID; + f32 strength; + B3DFile->read(&globalVertexID, sizeof(globalVertexID)); + B3DFile->read(&strength, sizeof(strength)); +#ifdef __BIG_ENDIAN__ + globalVertexID = os::Byteswap::byteswap(globalVertexID); + strength = os::Byteswap::byteswap(strength); +#endif + globalVertexID += VerticesStart; + + if (AnimatedVertices_VertexID[globalVertexID]==-1) + { + os::Printer::log("B3dMeshLoader: Weight has bad vertex id (no link to meshbuffer index found)"); + } + else if (strength >0) + { + CSkinnedMesh::SWeight *weight=AnimatedMesh->addWeight(inJoint); + weight->strength=strength; + //Find the meshbuffer and Vertex index from the Global Vertex ID: + weight->vertex_id = AnimatedVertices_VertexID[globalVertexID]; + weight->buffer_id = AnimatedVertices_BufferID[globalVertexID]; + } + } + } + + B3dStack.erase(B3dStack.size()-1); + return true; +} + + +bool CB3DMeshFileLoader::readChunkKEYS(CSkinnedMesh::SJoint *inJoint) +{ +#ifdef _B3D_READER_DEBUG + // Only print first, that's just too much output otherwise + if ( !inJoint || (inJoint->PositionKeys.empty() && inJoint->ScaleKeys.empty() && inJoint->RotationKeys.empty()) ) + { + core::stringc logStr; + for ( u32 i=1; i < B3dStack.size(); ++i ) + logStr += "-"; + logStr += "read ChunkKEYS"; + os::Printer::log(logStr.c_str(), ELL_DEBUG); + } +#endif + + s32 flags; + B3DFile->read(&flags, sizeof(flags)); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + + CSkinnedMesh::SPositionKey *oldPosKey=0; + core::vector3df oldPos[2]; + CSkinnedMesh::SScaleKey *oldScaleKey=0; + core::vector3df oldScale[2]; + CSkinnedMesh::SRotationKey *oldRotKey=0; + core::quaternion oldRot[2]; + bool isFirst[3]={true,true,true}; + while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) //this chunk repeats + { + s32 frame; + + B3DFile->read(&frame, sizeof(frame)); + #ifdef __BIG_ENDIAN__ + frame = os::Byteswap::byteswap(frame); + #endif + + // Add key frames, frames in Irrlicht are zero-based + f32 data[4]; + if (flags & 1) + { + readFloats(data, 3); + if ((oldPosKey!=0) && (oldPos[0]==oldPos[1])) + { + const core::vector3df pos(data[0], data[1], data[2]); + if (oldPos[1]==pos) + oldPosKey->frame = (f32)frame-1; + else + { + oldPos[0]=oldPos[1]; + oldPosKey=AnimatedMesh->addPositionKey(inJoint); + oldPosKey->frame = (f32)frame-1; + oldPos[1].set(oldPosKey->position.set(pos)); + } + } + else if (oldPosKey==0 && isFirst[0]) + { + oldPosKey=AnimatedMesh->addPositionKey(inJoint); + oldPosKey->frame = (f32)frame-1; + oldPos[0].set(oldPosKey->position.set(data[0], data[1], data[2])); + oldPosKey=0; + isFirst[0]=false; + } + else + { + if (oldPosKey!=0) + oldPos[0]=oldPos[1]; + oldPosKey=AnimatedMesh->addPositionKey(inJoint); + oldPosKey->frame = (f32)frame-1; + oldPos[1].set(oldPosKey->position.set(data[0], data[1], data[2])); + } + } + if (flags & 2) + { + readFloats(data, 3); + if ((oldScaleKey!=0) && (oldScale[0]==oldScale[1])) + { + const core::vector3df scale(data[0], data[1], data[2]); + if (oldScale[1]==scale) + oldScaleKey->frame = (f32)frame-1; + else + { + oldScale[0]=oldScale[1]; + oldScaleKey=AnimatedMesh->addScaleKey(inJoint); + oldScaleKey->frame = (f32)frame-1; + oldScale[1].set(oldScaleKey->scale.set(scale)); + } + } + else if (oldScaleKey==0 && isFirst[1]) + { + oldScaleKey=AnimatedMesh->addScaleKey(inJoint); + oldScaleKey->frame = (f32)frame-1; + oldScale[0].set(oldScaleKey->scale.set(data[0], data[1], data[2])); + oldScaleKey=0; + isFirst[1]=false; + } + else + { + if (oldScaleKey!=0) + oldScale[0]=oldScale[1]; + oldScaleKey=AnimatedMesh->addScaleKey(inJoint); + oldScaleKey->frame = (f32)frame-1; + oldScale[1].set(oldScaleKey->scale.set(data[0], data[1], data[2])); + } + } + if (flags & 4) + { + readFloats(data, 4); + if ((oldRotKey!=0) && (oldRot[0]==oldRot[1])) + { + // meant to be in this order since b3d stores W first + const core::quaternion rot(data[1], data[2], data[3], data[0]); + if (oldRot[1]==rot) + oldRotKey->frame = (f32)frame-1; + else + { + oldRot[0]=oldRot[1]; + oldRotKey=AnimatedMesh->addRotationKey(inJoint); + oldRotKey->frame = (f32)frame-1; + oldRot[1].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0])); + oldRot[1].normalize(); + } + } + else if (oldRotKey==0 && isFirst[2]) + { + oldRotKey=AnimatedMesh->addRotationKey(inJoint); + oldRotKey->frame = (f32)frame-1; + // meant to be in this order since b3d stores W first + oldRot[0].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0])); + oldRot[0].normalize(); + oldRotKey=0; + isFirst[2]=false; + } + else + { + if (oldRotKey!=0) + oldRot[0]=oldRot[1]; + oldRotKey=AnimatedMesh->addRotationKey(inJoint); + oldRotKey->frame = (f32)frame-1; + // meant to be in this order since b3d stores W first + oldRot[1].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0])); + oldRot[1].normalize(); + } + } + } + + B3dStack.erase(B3dStack.size()-1); + return true; +} + + +bool CB3DMeshFileLoader::readChunkANIM() +{ +#ifdef _B3D_READER_DEBUG + core::stringc logStr; + for ( u32 i=1; i < B3dStack.size(); ++i ) + logStr += "-"; + logStr += "read ChunkANIM"; + os::Printer::log(logStr.c_str(), ELL_DEBUG); +#endif + + s32 animFlags; //not stored\used + s32 animFrames;//not stored\used + f32 animFPS; //not stored\used + + B3DFile->read(&animFlags, sizeof(s32)); + B3DFile->read(&animFrames, sizeof(s32)); + readFloats(&animFPS, 1); + if (animFPS>0.f) + AnimatedMesh->setAnimationSpeed(animFPS); + os::Printer::log("FPS", io::path((double)animFPS), ELL_DEBUG); + + #ifdef __BIG_ENDIAN__ + animFlags = os::Byteswap::byteswap(animFlags); + animFrames = os::Byteswap::byteswap(animFrames); + #endif + + B3dStack.erase(B3dStack.size()-1); + return true; +} + + +bool CB3DMeshFileLoader::readChunkTEXS() +{ +#ifdef _B3D_READER_DEBUG + core::stringc logStr; + for ( u32 i=1; i < B3dStack.size(); ++i ) + logStr += "-"; + logStr += "read ChunkTEXS"; + os::Printer::log(logStr.c_str(), ELL_DEBUG); +#endif + + while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) //this chunk repeats + { + Textures.push_back(SB3dTexture()); + SB3dTexture& B3dTexture = Textures.getLast(); + + readString(B3dTexture.TextureName); + B3dTexture.TextureName.replace('\\','/'); +#ifdef _B3D_READER_DEBUG + os::Printer::log("read Texture", B3dTexture.TextureName.c_str(), ELL_DEBUG); +#endif + + B3DFile->read(&B3dTexture.Flags, sizeof(s32)); + B3DFile->read(&B3dTexture.Blend, sizeof(s32)); +#ifdef __BIG_ENDIAN__ + B3dTexture.Flags = os::Byteswap::byteswap(B3dTexture.Flags); + B3dTexture.Blend = os::Byteswap::byteswap(B3dTexture.Blend); +#endif +#ifdef _B3D_READER_DEBUG + os::Printer::log("Flags", core::stringc(B3dTexture.Flags).c_str(), ELL_DEBUG); + os::Printer::log("Blend", core::stringc(B3dTexture.Blend).c_str(), ELL_DEBUG); +#endif + readFloats(&B3dTexture.Xpos, 1); + readFloats(&B3dTexture.Ypos, 1); + readFloats(&B3dTexture.Xscale, 1); + readFloats(&B3dTexture.Yscale, 1); + readFloats(&B3dTexture.Angle, 1); + } + + B3dStack.erase(B3dStack.size()-1); + + return true; +} + + +bool CB3DMeshFileLoader::readChunkBRUS() +{ +#ifdef _B3D_READER_DEBUG + core::stringc logStr; + for ( u32 i=1; i < B3dStack.size(); ++i ) + logStr += "-"; + logStr += "read ChunkBRUS"; + os::Printer::log(logStr.c_str(), ELL_DEBUG); +#endif + + u32 n_texs; + B3DFile->read(&n_texs, sizeof(u32)); +#ifdef __BIG_ENDIAN__ + n_texs = os::Byteswap::byteswap(n_texs); +#endif + + // number of texture ids read for Irrlicht + const u32 num_textures = core::min_(n_texs, video::MATERIAL_MAX_TEXTURES); + // number of bytes to skip (for ignored texture ids) + const u32 n_texs_offset = (num_textures B3DFile->getPos()) //this chunk repeats + { + // This is what blitz basic calls a brush, like a Irrlicht Material + + core::stringc name; + readString(name); +#ifdef _B3D_READER_DEBUG + os::Printer::log("read Material", name, ELL_DEBUG); +#endif + Materials.push_back(SB3dMaterial()); + SB3dMaterial& B3dMaterial=Materials.getLast(); + + readFloats(&B3dMaterial.red, 1); + readFloats(&B3dMaterial.green, 1); + readFloats(&B3dMaterial.blue, 1); + readFloats(&B3dMaterial.alpha, 1); + readFloats(&B3dMaterial.shininess, 1); + + B3DFile->read(&B3dMaterial.blend, sizeof(B3dMaterial.blend)); + B3DFile->read(&B3dMaterial.fx, sizeof(B3dMaterial.fx)); +#ifdef __BIG_ENDIAN__ + B3dMaterial.blend = os::Byteswap::byteswap(B3dMaterial.blend); + B3dMaterial.fx = os::Byteswap::byteswap(B3dMaterial.fx); +#endif +#ifdef _B3D_READER_DEBUG + os::Printer::log("Blend", core::stringc(B3dMaterial.blend).c_str(), ELL_DEBUG); + os::Printer::log("FX", core::stringc(B3dMaterial.fx).c_str(), ELL_DEBUG); +#endif + + u32 i; + for (i=0; iread(&texture_id, sizeof(s32)); +#ifdef __BIG_ENDIAN__ + texture_id = os::Byteswap::byteswap(texture_id); +#endif + //--- Get pointers to the texture, based on the IDs --- + if ((u32)texture_id < Textures.size()) + { + B3dMaterial.Textures[i]=&Textures[texture_id]; +#ifdef _B3D_READER_DEBUG + os::Printer::log("Layer", core::stringc(i).c_str(), ELL_DEBUG); + os::Printer::log("using texture", Textures[texture_id].TextureName.c_str(), ELL_DEBUG); +#endif + } + else + B3dMaterial.Textures[i]=0; + } + // skip other texture ids + for (i=0; iread(&texture_id, sizeof(s32)); +#ifdef __BIG_ENDIAN__ + texture_id = os::Byteswap::byteswap(texture_id); +#endif + if (ShowWarning && (texture_id != -1) && (n_texs>video::MATERIAL_MAX_TEXTURES)) + { + os::Printer::log("Too many textures used in one material", B3DFile->getFileName(), ELL_WARNING); + ShowWarning = false; + } + } + + //Fixes problems when the lightmap is on the first texture: + if (B3dMaterial.Textures[0] != 0) + { + if (B3dMaterial.Textures[0]->Flags & 65536) // 65536 = secondary UV + { + SB3dTexture *TmpTexture; + TmpTexture = B3dMaterial.Textures[1]; + B3dMaterial.Textures[1] = B3dMaterial.Textures[0]; + B3dMaterial.Textures[0] = TmpTexture; + } + } + + //If a preceeding texture slot is empty move the others down: + for (i=num_textures; i>0; --i) + { + for (u32 j=i-1; jBlend == 5) //(Multiply 2) + B3dMaterial.Material.MaterialType = video::EMT_LIGHTMAP_M2; + else + B3dMaterial.Material.MaterialType = video::EMT_LIGHTMAP; + B3dMaterial.Material.Lighting = false; + } + else + { + B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + B3dMaterial.Material.ZWriteEnable = video::EZW_OFF; + } + } + else if (B3dMaterial.Textures[0]) //One texture: + { + // Flags & 0x1 is usual SOLID, 0x8 is mipmap (handled before) + if (B3dMaterial.Textures[0]->Flags & 0x2) //(Alpha mapped) + { + B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + B3dMaterial.Material.ZWriteEnable = video::EZW_OFF; + } + else if (B3dMaterial.Textures[0]->Flags & 0x4) //(Masked) + B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; // TODO: create color key texture + else if (B3dMaterial.Textures[0]->Flags & 0x40) + B3dMaterial.Material.MaterialType = video::EMT_SPHERE_MAP; + else if (B3dMaterial.Textures[0]->Flags & 0x80) + B3dMaterial.Material.MaterialType = video::EMT_SPHERE_MAP; // TODO: Should be cube map + else if (B3dMaterial.alpha == 1.f) + B3dMaterial.Material.MaterialType = video::EMT_SOLID; + else + { + B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + B3dMaterial.Material.ZWriteEnable = video::EZW_OFF; + } + } + else //No texture: + { + if (B3dMaterial.alpha == 1.f) + B3dMaterial.Material.MaterialType = video::EMT_SOLID; + else + { + B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + B3dMaterial.Material.ZWriteEnable = video::EZW_OFF; + } + } + + B3dMaterial.Material.DiffuseColor = video::SColorf(B3dMaterial.red, B3dMaterial.green, B3dMaterial.blue, B3dMaterial.alpha).toSColor(); + B3dMaterial.Material.ColorMaterial=video::ECM_NONE; + + //------ Material fx ------ + + if (B3dMaterial.fx & 1) //full-bright + { + B3dMaterial.Material.AmbientColor = video::SColor(255, 255, 255, 255); + B3dMaterial.Material.Lighting = false; + } + else + B3dMaterial.Material.AmbientColor = B3dMaterial.Material.DiffuseColor; + + if (B3dMaterial.fx & 2) //use vertex colors instead of brush color + B3dMaterial.Material.ColorMaterial=video::ECM_DIFFUSE_AND_AMBIENT; + + if (B3dMaterial.fx & 4) //flatshaded + B3dMaterial.Material.GouraudShading = false; + + if (B3dMaterial.fx & 16) //disable backface culling + B3dMaterial.Material.BackfaceCulling = false; + + if (B3dMaterial.fx & 32) //force vertex alpha-blending + { + B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + B3dMaterial.Material.ZWriteEnable = video::EZW_OFF; + } + + B3dMaterial.Material.Shininess = B3dMaterial.shininess; + } + + B3dStack.erase(B3dStack.size()-1); + + return true; +} + + +void CB3DMeshFileLoader::loadTextures(SB3dMaterial& material) const +{ + if ( getMeshTextureLoader() ) + { + if ( SceneManager->getParameters()->existsAttribute(B3D_TEXTURE_PATH) ) + getMeshTextureLoader()->setTexturePath( SceneManager->getParameters()->getAttributeAsString(B3D_TEXTURE_PATH) ); + } + + const bool previous32BitTextureFlag = SceneManager->getVideoDriver()->getTextureCreationFlag(video::ETCF_ALWAYS_32_BIT); + SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true); + + // read texture from disk + // note that mipmaps might be disabled by Flags & 0x8 + const bool doMipMaps = SceneManager->getVideoDriver()->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); + + for (u32 i=0; iTextureName.size() && !material.Material.getTexture(i)) + { + if (!SceneManager->getParameters()->getAttributeAsBool(B3D_LOADER_IGNORE_MIPMAP_FLAG)) + SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, (B3dTexture->Flags & 0x8) ? true:false); + { + video::ITexture* tex = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture(B3dTexture->TextureName) : NULL; + material.Material.setTexture(i, tex); + } + if (material.Textures[i]->Flags & 0x10) // Clamp U + material.Material.TextureLayer[i].TextureWrapU=video::ETC_CLAMP; + if (material.Textures[i]->Flags & 0x20) // Clamp V + material.Material.TextureLayer[i].TextureWrapV=video::ETC_CLAMP; + if (material.Textures[i]->Flags & 0x20) // Clamp R + material.Material.TextureLayer[i].TextureWrapW=video::ETC_CLAMP; + } + } + + SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, doMipMaps); + SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, previous32BitTextureFlag); +} + + +void CB3DMeshFileLoader::readString(core::stringc& newstring) +{ + newstring=""; + while (B3DFile->getPos() <= B3DFile->getSize()) + { + c8 character; + B3DFile->read(&character, sizeof(character)); + if (character==0) + return; + newstring.append(character); + } +} + + +void CB3DMeshFileLoader::readFloats(f32* vec, u32 count) +{ + B3DFile->read(vec, count*sizeof(f32)); + #ifdef __BIG_ENDIAN__ + for (u32 n=0; n B3dStack; + + core::array Materials; + core::array Textures; + + core::array AnimatedVertices_VertexID; + + core::array AnimatedVertices_BufferID; + + core::array BaseVertices; + + ISceneManager* SceneManager; + CSkinnedMesh* AnimatedMesh; + io::IReadFile* B3DFile; + + //B3Ds have Vertex ID's local within the mesh I don't want this + // Variable needs to be class member due to recursion in calls + u32 VerticesStart; + + bool NormalsInFile; + bool HasVertexColors; + bool ShowWarning; +}; + + +} // end namespace scene +} // end namespace irr + +#endif // __C_B3D_MESH_LOADER_H_INCLUDED__ + diff --git a/source/Irrlicht/CB3DMeshWriter.cpp b/source/Irrlicht/CB3DMeshWriter.cpp new file mode 100644 index 00000000..dd6031ad --- /dev/null +++ b/source/Irrlicht/CB3DMeshWriter.cpp @@ -0,0 +1,648 @@ +// Copyright (C) 2014 Lauri Kasanen +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +// TODO: replace printf's by logging messages + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_B3D_WRITER_ + +#include "CB3DMeshWriter.h" +#include "os.h" +#include "ISkinnedMesh.h" +#include "IMeshBuffer.h" +#include "IWriteFile.h" +#include "ITexture.h" +#include "irrMap.h" + + +namespace irr +{ +namespace scene +{ + +using namespace core; +using namespace video; + +CB3DMeshWriter::CB3DMeshWriter() +{ + #ifdef _DEBUG + setDebugName("CB3DMeshWriter"); + #endif +} + + +//! Returns the type of the mesh writer +EMESH_WRITER_TYPE CB3DMeshWriter::getType() const +{ + return EMWT_B3D; +} + + +//! writes a mesh +bool CB3DMeshWriter::writeMesh(io::IWriteFile* file, IMesh* const mesh, s32 flags) +{ + if (!file || !mesh) + return false; +#ifdef __BIG_ENDIAN__ + os::Printer::log("B3D export does not support big-endian systems.", ELL_ERROR); + return false; +#endif + + Size = 0; + file->write("BB3D", 4); + file->write(&Size, sizeof(u32)); // Updated later once known. + + int version = 1; + write(file, &version, sizeof(int)); + + // + + const u32 numBeshBuffers = mesh->getMeshBufferCount(); + array texs; + map tex2id; // TODO: texture pointer as key not sufficient as same texture can have several id's + u32 texsizes = 0; + for (u32 i = 0; i < numBeshBuffers; i++) + { + const IMeshBuffer * const mb = mesh->getMeshBuffer(i); + const SMaterial &mat = mb->getMaterial(); + + for (u32 j = 0; j < MATERIAL_MAX_TEXTURES; j++) + { + if (mat.getTexture(j)) + { + SB3dTexture t; + t.TextureName = core::stringc(mat.getTexture(j)->getName().getPath()); + + // TODO: need some description of Blitz3D texture-flags to figure this out. But Blend should likely depend on material-type. + t.Flags = j == 2 ? 65536 : 1; + t.Blend = 2; + + // TODO: evaluate texture matrix + t.Xpos = 0; + t.Ypos = 0; + t.Xscale = 1; + t.Yscale = 1; + t.Angle = 0; + + texs.push_back(t); + texsizes += 7*4 + t.TextureName.size() + 1; + tex2id[mat.getTexture(j)] = texs.size() - 1; + } + } + } + + write(file, "TEXS", 4); + write(file, &texsizes, 4); + + u32 numTexture = texs.size(); + for (u32 i = 0; i < numTexture; i++) + { + write(file, texs[i].TextureName.c_str(), texs[i].TextureName.size() + 1); + write(file, &texs[i].Flags, 7*4); + } + + // + + const u32 brushsize = (7 * 4 + 1) * numBeshBuffers + numBeshBuffers * 4 * MATERIAL_MAX_TEXTURES + 4; + write(file, "BRUS", 4); + write(file, &brushsize, 4); + u32 brushcheck = Size; + const u32 usedtex = MATERIAL_MAX_TEXTURES; + write(file, &usedtex, 4); + + for (u32 i = 0; i < numBeshBuffers; i++) + { + const IMeshBuffer * const mb = mesh->getMeshBuffer(i); + const SMaterial &mat = mb->getMaterial(); + + write(file, "", 1); + + float f = 1; + write(file, &f, 4); + write(file, &f, 4); + write(file, &f, 4); + write(file, &f, 4); + + f = 0; + write(file, &f, 4); + + u32 tmp = 1; + write(file, &tmp, 4); + tmp = 0; + write(file, &tmp, 4); + + for (u32 j = 0; j < MATERIAL_MAX_TEXTURES; j++) + { + if (mat.getTexture(j)) + { + const u32 id = tex2id[mat.getTexture(j)]; + write(file, &id, 4); + } + else + { + const int id = -1; + write(file, &id, 4); + } + } + } + + // Check brushsize + brushcheck = Size - brushcheck; + if (brushcheck != brushsize) + { + printf("Failed in brush size calculation, size %u advanced %u\n", + brushsize, brushcheck); + } + + write(file, "NODE", 4); + + // Calculate node size + u32 nodesize = 41 + 8 + 4 + 8; + u32 bonesSize = 0; + + if(ISkinnedMesh *skinnedMesh = getSkinned(mesh)) + { + if (!skinnedMesh->isStatic()) + { + bonesSize += 20; + } + + const core::array rootJoints = getRootJoints(skinnedMesh); + for (u32 i = 0; i < rootJoints.size(); i++) + { + bonesSize += getJointChunkSize(skinnedMesh, rootJoints[i]); + } + nodesize += bonesSize; + + // ------------------- + + } + + // VERT data + nodesize += 12; + + const u32 texcoords = getUVlayerCount(mesh); + for (u32 i = 0; i < numBeshBuffers; i++) + { + nodesize += 8 + 4; + const IMeshBuffer * const mb = mesh->getMeshBuffer(i); + + nodesize += mb->getVertexCount() * 10 * 4; + + nodesize += mb->getVertexCount() * texcoords * 2 * 4; + nodesize += mb->getIndexCount() * 4; + } + write(file, &nodesize, 4); + u32 nodecheck = Size; + + // Node + write(file, "", 1); + float f = 0; + write(file, &f, 4); + write(file, &f, 4); + write(file, &f, 4); + + f = 1; + write(file, &f, 4); + write(file, &f, 4); + write(file, &f, 4); + + write(file, &f, 4); + f = 0; + write(file, &f, 4); + write(file, &f, 4); + write(file, &f, 4); + + // Mesh + write(file, "MESH", 4); + const u32 meshsize = nodesize - 41 - 8 - bonesSize; + write(file, &meshsize, 4); + s32 brushID = -1; + write(file, &brushID, 4); + + + + // Verts + write(file, "VRTS", 4); + u32 vertsize = 12; + + for (u32 i = 0; i < numBeshBuffers; i++) + { + const IMeshBuffer * const mb = mesh->getMeshBuffer(i); + + vertsize += mb->getVertexCount() * 10 * 4 + + mb->getVertexCount() * texcoords * 2 * 4; + } + write(file, &vertsize, 4); + u32 vertcheck = Size; + + int flagsB3D = 3; + write(file, &flagsB3D, 4); + + write(file, &texcoords, 4); + flagsB3D = 2; + write(file, &flagsB3D, 4); + + for (u32 i = 0; i < numBeshBuffers; i++) + { + const IMeshBuffer * const mb = mesh->getMeshBuffer(i); + irr::u32 numVertices = mb->getVertexCount(); + for (u32 j = 0; j < numVertices; j++) + { + const vector3df &pos = mb->getPosition(j); + write(file, &pos.X, 4); + write(file, &pos.Y, 4); + write(file, &pos.Z, 4); + + const vector3df &n = mb->getNormal(j); + write(file, &n.X, 4); + write(file, &n.Y, 4); + write(file, &n.Z, 4); + + const u32 zero = 0; + switch (mb->getVertexType()) + { + case EVT_STANDARD: + { + S3DVertex *v = (S3DVertex *) mb->getVertices(); + const SColorf col(v[j].Color); + write(file, &col.r, 4); + write(file, &col.g, 4); + write(file, &col.b, 4); + write(file, &col.a, 4); + + write(file, &v[j].TCoords.X, 4); + write(file, &v[j].TCoords.Y, 4); + if (texcoords == 2) + { + write(file, &zero, 4); + write(file, &zero, 4); + } + } + break; + case EVT_2TCOORDS: + { + S3DVertex2TCoords *v = (S3DVertex2TCoords *) mb->getVertices(); + const SColorf col(v[j].Color); + write(file, &col.r, 4); + write(file, &col.g, 4); + write(file, &col.b, 4); + write(file, &col.a, 4); + + write(file, &v[j].TCoords.X, 4); + write(file, &v[j].TCoords.Y, 4); + write(file, &v[j].TCoords2.X, 4); + write(file, &v[j].TCoords2.Y, 4); + } + break; + case EVT_TANGENTS: + { + S3DVertexTangents *v = (S3DVertexTangents *) mb->getVertices(); + const SColorf col(v[j].Color); + write(file, &col.r, 4); + write(file, &col.g, 4); + write(file, &col.b, 4); + write(file, &col.a, 4); + + write(file, &v[j].TCoords.X, 4); + write(file, &v[j].TCoords.Y, 4); + if (texcoords == 2) + { + write(file, &zero, 4); + write(file, &zero, 4); + } + } + break; + } + } + } + // Check vertsize + vertcheck = Size - vertcheck; + if (vertcheck != vertsize) + { + printf("Failed in vertex size calculation, size %u advanced %u\n", + vertsize, vertcheck); + } + + u32 currentMeshBufferIndex = 0; + // Tris + for (u32 i = 0; i < numBeshBuffers; i++) + { + const IMeshBuffer * const mb = mesh->getMeshBuffer(i); + write(file, "TRIS", 4); + const u32 trisize = 4 + mb->getIndexCount() * 4; + write(file, &trisize, 4); + + u32 tricheck = Size; + + write(file, &i, 4); + + u32 numIndices = mb->getIndexCount(); + const u16 * const idx = (u16 *) mb->getIndices(); + for (u32 j = 0; j < numIndices; j += 3) + { + u32 tmp = idx[j] + currentMeshBufferIndex; + write(file, &tmp, sizeof(u32)); + + tmp = idx[j + 1] + currentMeshBufferIndex; + write(file, &tmp, sizeof(u32)); + + tmp = idx[j + 2] + currentMeshBufferIndex; + write(file, &tmp, sizeof(u32)); + } + + // Check that tris calculation was ok + tricheck = Size - tricheck; + if (tricheck != trisize) + { + printf("Failed in tris size calculation, size %u advanced %u\n", + trisize, tricheck); + } + + currentMeshBufferIndex += mb->getVertexCount(); + } + + if(ISkinnedMesh *skinnedMesh = getSkinned(mesh)) + { + // Write animation data + if (!skinnedMesh->isStatic()) + { + write(file, "ANIM", 4); + + const u32 animsize = 12; + write(file, &animsize, 4); + + const u32 flags = 0; + const u32 frames = skinnedMesh->getFrameCount(); + const f32 fps = skinnedMesh->getAnimationSpeed(); + + write(file, &flags, 4); + write(file, &frames, 4); + write(file, &fps, 4); + } + + // Write joints + core::array rootJoints = getRootJoints(skinnedMesh); + + for (u32 i = 0; i < rootJoints.size(); i++) + { + writeJointChunk(file, skinnedMesh, rootJoints[i]); + } + } + + // Check that node calculation was ok + nodecheck = Size - nodecheck; + if (nodecheck != nodesize) + { + printf("Failed in node size calculation, size %u advanced %u\n", + nodesize, nodecheck); + } + file->seek(4); + file->write(&Size, 4); + + return true; +} + + + +void CB3DMeshWriter::writeJointChunk(io::IWriteFile* file, ISkinnedMesh* mesh , ISkinnedMesh::SJoint* joint) +{ + // Node + write(file, "NODE", 4); + + // Calculate node size + u32 nodesize = getJointChunkSize(mesh, joint); + nodesize -= 8; // The declaration + size of THIS chunk shouldn't be added to the size + + write(file, &nodesize, 4); + + + core::stringc name = joint->Name; + write(file, name.c_str(), name.size()); + write(file, "", 1); + + core::vector3df pos = joint->Animatedposition; + // Position + write(file, &pos.X, 4); + write(file, &pos.Y, 4); + write(file, &pos.Z, 4); + + // Scale + core::vector3df scale = joint->Animatedscale; + if (scale == core::vector3df(0, 0, 0)) + scale = core::vector3df(1, 1, 1); + + write(file, &scale.X, 4); + write(file, &scale.Y, 4); + write(file, &scale.Z, 4); + + // Rotation + core::quaternion quat = joint->Animatedrotation; + write(file, &quat.W, 4); + write(file, &quat.X, 4); + write(file, &quat.Y, 4); + write(file, &quat.Z, 4); + + // Bone + write(file, "BONE", 4); + u32 bonesize = 8 * joint->Weights.size(); + write(file, &bonesize, 4); + + // Skinning ------------------ + for (u32 i = 0; i < joint->Weights.size(); i++) + { + const u32 vertexID = joint->Weights[i].vertex_id; + const u32 bufferID = joint->Weights[i].buffer_id; + const f32 weight = joint->Weights[i].strength; + + u32 b3dVertexID = vertexID; + for (u32 j = 0; j < bufferID; j++) + { + b3dVertexID += mesh->getMeshBuffer(j)->getVertexCount(); + } + + write(file, &b3dVertexID, 4); + write(file, &weight, 4); + } + // --------------------------- + + // Animation keys + if (joint->PositionKeys.size()) + { + write(file, "KEYS", 4); + u32 keysSize = 4 * joint->PositionKeys.size() * 4; // X, Y and Z pos + frame + keysSize += 4; // Flag to define the type of the key + write(file, &keysSize, 4); + + u32 flag = 1; // 1 = flag for position keys + write(file, &flag, 4); + + for (u32 i = 0; i < joint->PositionKeys.size(); i++) + { + const s32 frame = static_cast(joint->PositionKeys[i].frame); + const core::vector3df pos = joint->PositionKeys[i].position; + + write (file, &frame, 4); + + write (file, &pos.X, 4); + write (file, &pos.Y, 4); + write (file, &pos.Z, 4); + + } + } + if (joint->RotationKeys.size()) + { + write(file, "KEYS", 4); + u32 keysSize = 4 * joint->RotationKeys.size() * 5; // W, X, Y and Z rot + frame + keysSize += 4; // Flag + write(file, &keysSize, 4); + + u32 flag = 4; + write(file, &flag, 4); + + for (u32 i = 0; i < joint->RotationKeys.size(); i++) + { + const s32 frame = static_cast(joint->RotationKeys[i].frame); + const core::quaternion rot = joint->RotationKeys[i].rotation; + + write (file, &frame, 4); + + write (file, &rot.W, 4); + write (file, &rot.X, 4); + write (file, &rot.Y, 4); + write (file, &rot.Z, 4); + } + } + if (joint->ScaleKeys.size()) + { + write(file, "KEYS", 4); + u32 keysSize = 4 * joint->ScaleKeys.size() * 4; // X, Y and Z scale + frame + keysSize += 4; // Flag + write(file, &keysSize, 4); + + u32 flag = 2; + write(file, &flag, 4); + + for (u32 i = 0; i < joint->ScaleKeys.size(); i++) + { + const s32 frame = static_cast(joint->ScaleKeys[i].frame); + const core::vector3df scale = joint->ScaleKeys[i].scale; + + write (file, &frame, 4); + + write (file, &scale.X, 4); + write (file, &scale.Y, 4); + write (file, &scale.Z, 4); + } + } + + for (u32 i = 0; i < joint->Children.size(); i++) + { + writeJointChunk(file, mesh, joint->Children[i]); + } +} + + +ISkinnedMesh* CB3DMeshWriter::getSkinned (IMesh *mesh) +{ + if (mesh->getMeshType() == EAMT_SKINNED) + { + return static_cast(mesh); + } + return 0; +} + +u32 CB3DMeshWriter::getJointChunkSize(const ISkinnedMesh* mesh, ISkinnedMesh::SJoint* joint) +{ + u32 chunkSize = 8 + 40; // Chunk declaration + chunk data + chunkSize += joint->Name.size() + 1; // the NULL character at the end of the string + + u32 boneSize = joint->Weights.size() * 8; // vertex_id + weight = 8 bits per weight block + boneSize += 8; // declaration + size of he BONE chunk + + u32 keysSize = 0; + if (joint->PositionKeys.size() != 0) + { + keysSize += 8; // KEYS + chunk size + keysSize += 4; // flags + + keysSize += (joint->PositionKeys.size() * 16); + } + if (joint->RotationKeys.size() != 0) + { + keysSize += 8; // KEYS + chunk size + keysSize += 4; // flags + + keysSize += (joint->RotationKeys.size() * 20); + } + if (joint->ScaleKeys.size() != 0) + { + keysSize += 8; // KEYS + chunk size + keysSize += 4; // flags + + keysSize += (joint->ScaleKeys.size() * 16); + } + + chunkSize += boneSize; + chunkSize += keysSize; + + for (u32 i = 0; i < joint->Children.size(); ++i) + { + chunkSize += (getJointChunkSize(mesh, joint->Children[i])); + } + return chunkSize; +} + +core::array CB3DMeshWriter::getRootJoints(const ISkinnedMesh* mesh) +{ + core::array roots; + + core::array allJoints = mesh->getAllJoints(); + for (u32 i = 0; i < allJoints.size(); i++) + { + bool isRoot = true; + ISkinnedMesh::SJoint* testedJoint = allJoints[i]; + for (u32 j = 0; j < allJoints.size(); j++) + { + ISkinnedMesh::SJoint* testedJoint2 = allJoints[j]; + for (u32 k = 0; k < testedJoint2->Children.size(); k++) + { + if (testedJoint == testedJoint2->Children[k]) + isRoot = false; + } + } + if (isRoot) + roots.push_back(testedJoint); + } + + return roots; +} + +u32 CB3DMeshWriter::getUVlayerCount(IMesh* mesh) +{ + const u32 numBeshBuffers = mesh->getMeshBufferCount(); + for (u32 i = 0; i < numBeshBuffers; i++) + { + const IMeshBuffer * const mb = mesh->getMeshBuffer(i); + + if (mb->getVertexType() == EVT_2TCOORDS) + { + return 2; + } + } + return 1; +} + +void CB3DMeshWriter::write(io::IWriteFile* file, const void *ptr, const u32 bytes) +{ + file->write(ptr, bytes); + Size += bytes; +} + +} // end namespace +} // end namespace + +#endif // _IRR_COMPILE_WITH_B3D_WRITER_ + diff --git a/source/Irrlicht/CB3DMeshWriter.h b/source/Irrlicht/CB3DMeshWriter.h new file mode 100644 index 00000000..454b7a6e --- /dev/null +++ b/source/Irrlicht/CB3DMeshWriter.h @@ -0,0 +1,52 @@ +// Copyright (C) 2014 Lauri Kasanen +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +// Modified version with rigging/skinning support + +#ifndef __IRR_B3D_MESH_WRITER_H_INCLUDED__ +#define __IRR_B3D_MESH_WRITER_H_INCLUDED__ + +#include "IMeshWriter.h" +#include "IWriteFile.h" +#include "SB3DStructs.h" +#include "ISkinnedMesh.h" + + + +namespace irr +{ +namespace scene +{ + +//! class to write B3D mesh files +class CB3DMeshWriter : public IMeshWriter +{ +public: + + CB3DMeshWriter(); + + //! Returns the type of the mesh writer + virtual EMESH_WRITER_TYPE getType() const _IRR_OVERRIDE_; + + //! writes a mesh + virtual bool writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags=EMWF_NONE) _IRR_OVERRIDE_; + +private: + u32 Size; + + void writeJointChunk(io::IWriteFile* file, ISkinnedMesh* mesh , ISkinnedMesh::SJoint* joint); + u32 getJointChunkSize(const ISkinnedMesh* mesh, ISkinnedMesh::SJoint* joint); + core::array getRootJoints(const ISkinnedMesh* mesh); + + u32 getUVlayerCount(IMesh *mesh); + ISkinnedMesh* getSkinned (IMesh *mesh); + + void write(io::IWriteFile* file, const void *ptr, const u32 bytes); + +}; + +} // end namespace +} // end namespace + +#endif diff --git a/source/Irrlicht/CBSPMeshFileLoader.cpp b/source/Irrlicht/CBSPMeshFileLoader.cpp new file mode 100644 index 00000000..01ac04aa --- /dev/null +++ b/source/Irrlicht/CBSPMeshFileLoader.cpp @@ -0,0 +1,107 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_BSP_LOADER_ + +#include "CBSPMeshFileLoader.h" +#include "CQ3LevelMesh.h" + +namespace irr +{ +namespace scene +{ + +//! Constructor +CBSPMeshFileLoader::CBSPMeshFileLoader(scene::ISceneManager* smgr, + io::IFileSystem* fs) +: FileSystem(fs), SceneManager(smgr) +{ + + #ifdef _DEBUG + setDebugName("CBSPMeshFileLoader"); + #endif + + if (FileSystem) + FileSystem->grab(); +} + + +//! destructor +CBSPMeshFileLoader::~CBSPMeshFileLoader() +{ + if (FileSystem) + FileSystem->drop(); +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool CBSPMeshFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "bsp", "shader", "cfg" ); +} + + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IReferenceCounted::drop() for more information. +IAnimatedMesh* CBSPMeshFileLoader::createMesh(io::IReadFile* file) +{ + s32 type = core::isFileExtension ( file->getFileName(), "bsp", "shader", "cfg" ); + CQ3LevelMesh* q = 0; + + switch ( type ) + { + case 1: + q = new CQ3LevelMesh(FileSystem, SceneManager, LoadParam); + + // determine real shaders in LoadParam + if ( 0 == LoadParam.loadAllShaders ) + { + q->getShader("scripts/common.shader"); + q->getShader("scripts/sfx.shader"); + q->getShader("scripts/gfx.shader"); + q->getShader("scripts/liquid.shader"); + q->getShader("scripts/models.shader"); + q->getShader("scripts/walls.shader"); + //q->getShader("scripts/sky.shader"); + } + + if ( q->loadFile(file) ) + return q; + + q->drop(); + break; + + case 2: + q = new CQ3LevelMesh(FileSystem, SceneManager,LoadParam); + q->getShader( file ); + return q; + break; + + case 3: + // load quake 3 loading parameter + if ( file->getFileName() == "levelparameter.cfg" ) + { + file->read ( &LoadParam, sizeof ( LoadParam ) ); + } + else + { + q = new CQ3LevelMesh(FileSystem, SceneManager,LoadParam); + q->getConfiguration( file ); + return q; + } + break; + } + + return 0; +} + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BSP_LOADER_ + diff --git a/source/Irrlicht/CBSPMeshFileLoader.h b/source/Irrlicht/CBSPMeshFileLoader.h new file mode 100644 index 00000000..e636f989 --- /dev/null +++ b/source/Irrlicht/CBSPMeshFileLoader.h @@ -0,0 +1,52 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_BSP_MESH_FILE_LOADER_H_INCLUDED__ +#define __C_BSP_MESH_FILE_LOADER_H_INCLUDED__ + +#include "IMeshLoader.h" +#include "IFileSystem.h" +#include "IVideoDriver.h" +#include "ISceneManager.h" +#include "IQ3Shader.h" + +namespace irr +{ +namespace scene +{ + +//! Meshloader capable of loading Quake 3 BSP files and shaders +class CBSPMeshFileLoader : public IMeshLoader +{ +public: + + //! Constructor + CBSPMeshFileLoader(scene::ISceneManager* smgr, io::IFileSystem* fs); + + //! destructor + virtual ~CBSPMeshFileLoader(); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".bsp") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! creates/loads an animated mesh from the file. + //! \return Pointer to the created mesh. Returns 0 if loading failed. + //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). + //! See IReferenceCounted::drop() for more information. + virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_; + +private: + + io::IFileSystem* FileSystem; + scene::ISceneManager* SceneManager; + + quake3::Q3LevelLoadParameter LoadParam; +}; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CBillboardSceneNode.cpp b/source/Irrlicht/CBillboardSceneNode.cpp new file mode 100644 index 00000000..9eddb985 --- /dev/null +++ b/source/Irrlicht/CBillboardSceneNode.cpp @@ -0,0 +1,321 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_BILLBOARD_SCENENODE_ +#include "CBillboardSceneNode.h" +#include "IVideoDriver.h" +#include "ISceneManager.h" +#include "ICameraSceneNode.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CBillboardSceneNode::CBillboardSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position, const core::dimension2d& size, + video::SColor colorTop, video::SColor colorBottom) + : IBillboardSceneNode(parent, mgr, id, position) + , Buffer(new SMeshBuffer()) +{ + #ifdef _DEBUG + setDebugName("CBillboardSceneNode"); + #endif + + setSize(size); + + Buffer->Vertices.set_used(4); + Buffer->Indices.set_used(6); + + Buffer->Indices[0] = 0; + Buffer->Indices[1] = 2; + Buffer->Indices[2] = 1; + Buffer->Indices[3] = 0; + Buffer->Indices[4] = 3; + Buffer->Indices[5] = 2; + + Buffer->Vertices[0].TCoords.set(1.0f, 1.0f); + Buffer->Vertices[0].Color = colorBottom; + + Buffer->Vertices[1].TCoords.set(1.0f, 0.0f); + Buffer->Vertices[1].Color = colorTop; + + Buffer->Vertices[2].TCoords.set(0.0f, 0.0f); + Buffer->Vertices[2].Color = colorTop; + + Buffer->Vertices[3].TCoords.set(0.0f, 1.0f); + Buffer->Vertices[3].Color = colorBottom; +} + +CBillboardSceneNode::~CBillboardSceneNode() +{ + Buffer->drop(); +} + +//! pre render event +void CBillboardSceneNode::OnRegisterSceneNode() +{ + if (IsVisible) + SceneManager->registerNodeForRendering(this); + + ISceneNode::OnRegisterSceneNode(); +} + + +//! render +void CBillboardSceneNode::render() +{ + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + ICameraSceneNode* camera = SceneManager->getActiveCamera(); + + if (!camera || !driver) + return; + + // make billboard look to camera + updateMesh(camera); + + driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); + driver->setMaterial(Buffer->Material); + driver->drawMeshBuffer(Buffer); + + if (DebugDataVisible & scene::EDS_BBOX) + { + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + video::SMaterial m; + m.Lighting = false; + driver->setMaterial(m); + driver->draw3DBox(BBoxSafe, video::SColor(0,208,195,152)); + } +} + +void CBillboardSceneNode::updateMesh(const irr::scene::ICameraSceneNode* camera) +{ + // billboard looks toward camera + core::vector3df pos = getAbsolutePosition(); + + core::vector3df campos = camera->getAbsolutePosition(); + core::vector3df target = camera->getTarget(); + core::vector3df up = camera->getUpVector(); + core::vector3df view = target - campos; + view.normalize(); + + core::vector3df horizontal = up.crossProduct(view); + if ( horizontal.getLength() == 0 ) + { + horizontal.set(up.Y,up.X,up.Z); + } + horizontal.normalize(); + core::vector3df topHorizontal = horizontal * 0.5f * TopEdgeWidth; + horizontal *= 0.5f * Size.Width; + + // pointing down! + core::vector3df vertical = horizontal.crossProduct(view); + vertical.normalize(); + vertical *= 0.5f * Size.Height; + + view *= -1.0f; + + core::array& vertices = Buffer->Vertices; + + for (s32 i=0; i<4; ++i) + vertices[i].Normal = view; + + /* Vertices are: + 2--1 + |\ | + | \| + 3--0 + */ + vertices[0].Pos = pos + horizontal + vertical; + vertices[1].Pos = pos + topHorizontal - vertical; + vertices[2].Pos = pos - topHorizontal - vertical; + vertices[3].Pos = pos - horizontal + vertical; + + Buffer->setDirty(EBT_VERTEX); + Buffer->recalculateBoundingBox(); +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CBillboardSceneNode::getBoundingBox() const +{ + // Really wrong when scaled. + return BBoxSafe; +} + +const core::aabbox3d& CBillboardSceneNode::getTransformedBillboardBoundingBox(const irr::scene::ICameraSceneNode* camera) +{ + updateMesh(camera); + return Buffer->BoundingBox; +} + +void CBillboardSceneNode::setSize(const core::dimension2d& size) +{ + Size = size; + + if (core::equals(Size.Width, 0.0f)) + Size.Width = 1.0f; + TopEdgeWidth = Size.Width; + + if (core::equals(Size.Height, 0.0f)) + Size.Height = 1.0f; + + const f32 avg = (Size.Width + Size.Height)/6; + BBoxSafe.MinEdge.set(-avg,-avg,-avg); + BBoxSafe.MaxEdge.set(avg,avg,avg); +} + + +void CBillboardSceneNode::setSize(f32 height, f32 bottomEdgeWidth, f32 topEdgeWidth) +{ + Size.set(bottomEdgeWidth, height); + TopEdgeWidth = topEdgeWidth; + + if (core::equals(Size.Height, 0.0f)) + Size.Height = 1.0f; + + if (core::equals(Size.Width, 0.f) && core::equals(TopEdgeWidth, 0.f)) + { + Size.Width = 1.0f; + TopEdgeWidth = 1.0f; + } + + const f32 avg = (core::max_(Size.Width,TopEdgeWidth) + Size.Height)/6; + BBoxSafe.MinEdge.set(-avg,-avg,-avg); + BBoxSafe.MaxEdge.set(avg,avg,avg); +} + + +video::SMaterial& CBillboardSceneNode::getMaterial(u32 i) +{ + return Buffer->Material; +} + + +//! returns amount of materials used by this scene node. +u32 CBillboardSceneNode::getMaterialCount() const +{ + return 1; +} + + +//! gets the size of the billboard +const core::dimension2d& CBillboardSceneNode::getSize() const +{ + return Size; +} + + +//! Gets the widths of the top and bottom edges of the billboard. +void CBillboardSceneNode::getSize(f32& height, f32& bottomEdgeWidth, + f32& topEdgeWidth) const +{ + height = Size.Height; + bottomEdgeWidth = Size.Width; + topEdgeWidth = TopEdgeWidth; +} + + +//! Writes attributes of the scene node. +void CBillboardSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + IBillboardSceneNode::serializeAttributes(out, options); + + out->addFloat("Width", Size.Width); + out->addFloat("TopEdgeWidth", TopEdgeWidth); + out->addFloat("Height", Size.Height); + out->addColor("Shade_Top", Buffer->Vertices[1].Color); + out->addColor("Shade_Down", Buffer->Vertices[0].Color); +} + + +//! Reads attributes of the scene node. +void CBillboardSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + IBillboardSceneNode::deserializeAttributes(in, options); + + Size.Width = in->getAttributeAsFloat("Width"); + Size.Height = in->getAttributeAsFloat("Height"); + + if (in->existsAttribute("TopEdgeWidth")) + { + TopEdgeWidth = in->getAttributeAsFloat("TopEdgeWidth"); + if (Size.Width != TopEdgeWidth) + setSize(Size.Height, Size.Width, TopEdgeWidth); + } + else + setSize(Size); + Buffer->Vertices[1].Color = in->getAttributeAsColor("Shade_Top"); + Buffer->Vertices[0].Color = in->getAttributeAsColor("Shade_Down"); + Buffer->Vertices[2].Color = Buffer->Vertices[1].Color; + Buffer->Vertices[3].Color = Buffer->Vertices[0].Color; +} + + +//! Set the color of all vertices of the billboard +//! \param overallColor: the color to set +void CBillboardSceneNode::setColor(const video::SColor& overallColor) +{ + for(u32 vertex = 0; vertex < 4; ++vertex) + Buffer->Vertices[vertex].Color = overallColor; +} + + +//! Set the color of the top and bottom vertices of the billboard +//! \param topColor: the color to set the top vertices +//! \param bottomColor: the color to set the bottom vertices +void CBillboardSceneNode::setColor(const video::SColor& topColor, + const video::SColor& bottomColor) +{ + Buffer->Vertices[0].Color = bottomColor; + Buffer->Vertices[1].Color = topColor; + Buffer->Vertices[2].Color = topColor; + Buffer->Vertices[3].Color = bottomColor; +} + + +//! Gets the color of the top and bottom vertices of the billboard +//! \param[out] topColor: stores the color of the top vertices +//! \param[out] bottomColor: stores the color of the bottom vertices +void CBillboardSceneNode::getColor(video::SColor& topColor, + video::SColor& bottomColor) const +{ + bottomColor = Buffer->Vertices[0].Color; + topColor = Buffer->Vertices[1].Color; +} + + +//! Creates a clone of this scene node and its children. +ISceneNode* CBillboardSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager) +{ + if (!newParent) + newParent = Parent; + if (!newManager) + newManager = SceneManager; + + CBillboardSceneNode* nb = new CBillboardSceneNode(newParent, + newManager, ID, RelativeTranslation, Size); + + nb->cloneMembers(this, newManager); + nb->Buffer->Material = Buffer->Material; + nb->Size = Size; + nb->TopEdgeWidth = this->TopEdgeWidth; + + video::SColor topColor,bottomColor; + getColor(topColor,bottomColor); + nb->setColor(topColor,bottomColor); + + if ( newParent ) + nb->drop(); + return nb; +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BILLBOARD_SCENENODE_ diff --git a/source/Irrlicht/CBillboardSceneNode.h b/source/Irrlicht/CBillboardSceneNode.h new file mode 100644 index 00000000..73ae6d07 --- /dev/null +++ b/source/Irrlicht/CBillboardSceneNode.h @@ -0,0 +1,112 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_BILLBOARD_SCENE_NODE_H_INCLUDED__ +#define __C_BILLBOARD_SCENE_NODE_H_INCLUDED__ + +#include "IBillboardSceneNode.h" +#include "SMeshBuffer.h" + +namespace irr +{ +namespace scene +{ + +//! Scene node which is a billboard. A billboard is like a 3d sprite: A 2d element, +//! which always looks to the camera. +class CBillboardSceneNode : virtual public IBillboardSceneNode +{ +public: + + //! constructor + CBillboardSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position, const core::dimension2d& size, + video::SColor colorTop=video::SColor(0xFFFFFFFF), + video::SColor colorBottom=video::SColor(0xFFFFFFFF)); + + virtual ~CBillboardSceneNode(); + + //! pre render event + virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; + + //! render + virtual void render() _IRR_OVERRIDE_; + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + //! sets the size of the billboard + virtual void setSize(const core::dimension2d& size) _IRR_OVERRIDE_; + + //! Sets the widths of the top and bottom edges of the billboard independently. + virtual void setSize(f32 height, f32 bottomEdgeWidth, f32 topEdgeWidth) _IRR_OVERRIDE_; + + //! gets the size of the billboard + virtual const core::dimension2d& getSize() const _IRR_OVERRIDE_; + + //! Gets the widths of the top and bottom edges of the billboard. + virtual void getSize(f32& height, f32& bottomEdgeWidth, f32& topEdgeWidth) const _IRR_OVERRIDE_; + + virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_; + + //! returns amount of materials used by this scene node. + virtual u32 getMaterialCount() const _IRR_OVERRIDE_; + + //! Set the color of all vertices of the billboard + //! \param overallColor: the color to set + virtual void setColor(const video::SColor& overallColor) _IRR_OVERRIDE_; + + //! Set the color of the top and bottom vertices of the billboard + //! \param topColor: the color to set the top vertices + //! \param bottomColor: the color to set the bottom vertices + virtual void setColor(const video::SColor& topColor, + const video::SColor& bottomColor) _IRR_OVERRIDE_; + + //! Gets the color of the top and bottom vertices of the billboard + //! \param[out] topColor: stores the color of the top vertices + //! \param[out] bottomColor: stores the color of the bottom vertices + virtual void getColor(video::SColor& topColor, + video::SColor& bottomColor) const _IRR_OVERRIDE_; + + //! Get the real boundingbox used by the billboard (which depends on the active camera) + virtual const core::aabbox3d& getTransformedBillboardBoundingBox(const irr::scene::ICameraSceneNode* camera) _IRR_OVERRIDE_; + + //! Writes attributes of the scene node. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_BILLBOARD; } + + //! Creates a clone of this scene node and its children. + virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_; + +protected: + void updateMesh(const irr::scene::ICameraSceneNode* camera); + +private: + + //! Size.Width is the bottom edge width + core::dimension2d Size; + f32 TopEdgeWidth; + + //! BoundingBox which is large enough to contain the billboard independent of the camera + // TODO: BUG - still can be wrong with scaling < 1. Billboards should calculate relative coordinates for their mesh + // and then use the node-scaling. But needs some work... + /** Note that we can't use the real boundingbox for culling because at that point + the camera which is used to calculate the billboard is not yet updated. So we only + know the real boundingbox after rendering - which is too late for culling. */ + core::aabbox3d BBoxSafe; + + scene::SMeshBuffer* Buffer; +}; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CBlit.h b/source/Irrlicht/CBlit.h new file mode 100644 index 00000000..d67a76b0 --- /dev/null +++ b/source/Irrlicht/CBlit.h @@ -0,0 +1,1422 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef _C_BLIT_H_INCLUDED_ +#define _C_BLIT_H_INCLUDED_ + +#include "SoftwareDriver2_helper.h" + +namespace irr +{ + + struct SBlitJob + { + AbsRectangle Dest; + AbsRectangle Source; + + u32 argb; + + void * src; + void * dst; + + s32 width; + s32 height; + + u32 srcPitch; + u32 dstPitch; + + u32 srcPixelMul; + u32 dstPixelMul; + + bool stretch; + float x_stretch; + float y_stretch; + + SBlitJob() : stretch(false) {} + }; + + // Bitfields Cohen Sutherland + enum eClipCode + { + CLIPCODE_EMPTY = 0, + CLIPCODE_BOTTOM = 1, + CLIPCODE_TOP = 2, + CLIPCODE_LEFT = 4, + CLIPCODE_RIGHT = 8 + }; + +inline u32 GetClipCode( const AbsRectangle &r, const core::position2d &p ) +{ + u32 code = CLIPCODE_EMPTY; + + if ( p.X < r.x0 ) + code = CLIPCODE_LEFT; + else + if ( p.X > r.x1 ) + code = CLIPCODE_RIGHT; + + if ( p.Y < r.y0 ) + code |= CLIPCODE_TOP; + else + if ( p.Y > r.y1 ) + code |= CLIPCODE_BOTTOM; + + return code; +} + + +/*! + Cohen Sutherland clipping + @return: 1 if valid +*/ + +static int ClipLine(const AbsRectangle &clipping, + core::position2d &p0, + core::position2d &p1, + const core::position2d& p0_in, + const core::position2d& p1_in) +{ + u32 code0; + u32 code1; + u32 code; + + p0 = p0_in; + p1 = p1_in; + + code0 = GetClipCode( clipping, p0 ); + code1 = GetClipCode( clipping, p1 ); + + // trivial accepted + while ( code0 | code1 ) + { + s32 x=0; + s32 y=0; + + // trivial reject + if ( code0 & code1 ) + return 0; + + if ( code0 ) + { + // clip first point + code = code0; + } + else + { + // clip last point + code = code1; + } + + if ( (code & CLIPCODE_BOTTOM) == CLIPCODE_BOTTOM ) + { + // clip bottom viewport + y = clipping.y1; + x = p0.X + ( p1.X - p0.X ) * ( y - p0.Y ) / ( p1.Y - p0.Y ); + } + else + if ( (code & CLIPCODE_TOP) == CLIPCODE_TOP ) + { + // clip to viewport + y = clipping.y0; + x = p0.X + ( p1.X - p0.X ) * ( y - p0.Y ) / ( p1.Y - p0.Y ); + } + else + if ( (code & CLIPCODE_RIGHT) == CLIPCODE_RIGHT ) + { + // clip right viewport + x = clipping.x1; + y = p0.Y + ( p1.Y - p0.Y ) * ( x - p0.X ) / ( p1.X - p0.X ); + } + else + if ( (code & CLIPCODE_LEFT) == CLIPCODE_LEFT ) + { + // clip left viewport + x = clipping.x0; + y = p0.Y + ( p1.Y - p0.Y ) * ( x - p0.X ) / ( p1.X - p0.X ); + } + + if ( code == code0 ) + { + // modify first point + p0.X = x; + p0.Y = y; + code0 = GetClipCode( clipping, p0 ); + } + else + { + // modify second point + p1.X = x; + p1.Y = y; + code1 = GetClipCode( clipping, p1 ); + } + } + + return 1; +} + +/* +*/ +inline void GetClip(AbsRectangle &clipping, video::IImage * t) +{ + clipping.x0 = 0; + clipping.y0 = 0; + clipping.x1 = t->getDimension().Width - 1; + clipping.y1 = t->getDimension().Height - 1; +} + +/* + return alpha in [0;256] Granularity from 32-Bit ARGB + add highbit alpha ( alpha > 127 ? + 1 ) +*/ +static inline u32 extractAlpha(const u32 c) +{ + return ( c >> 24 ) + ( c >> 31 ); +} + +/* + return alpha in [0;255] Granularity and 32-Bit ARGB + add highbit alpha ( alpha > 127 ? + 1 ) +*/ +static inline u32 packAlpha(const u32 c) +{ + return (c > 127 ? c - 1 : c) << 24; +} + + +/*! + Scale Color by (1/value) + value 0 - 256 ( alpha ) +*/ +inline u32 PixelLerp32(const u32 source, const u32 value) +{ + u32 srcRB = source & 0x00FF00FF; + u32 srcXG = (source & 0xFF00FF00) >> 8; + + srcRB *= value; + srcXG *= value; + + srcRB >>= 8; + //srcXG >>= 8; + + srcXG &= 0xFF00FF00; + srcRB &= 0x00FF00FF; + + return srcRB | srcXG; +} + + +/* +*/ +static void RenderLine32_Decal(video::IImage *t, + const core::position2d &p0, + const core::position2d &p1, + u32 argb ) +{ + s32 dx = p1.X - p0.X; + s32 dy = p1.Y - p0.Y; + + s32 c; + s32 m; + s32 d = 0; + s32 run; + + s32 xInc = 4; + s32 yInc = (s32) t->getPitch(); + + if ( dx < 0 ) + { + xInc = -xInc; + dx = -dx; + } + + if ( dy < 0 ) + { + yInc = -yInc; + dy = -dy; + } + + u32 *dst; + dst = (u32*) ( (u8*) t->getData() + ( p0.Y * t->getPitch() ) + ( p0.X << 2 ) ); + + if ( dy > dx ) + { + s32 tmp; + tmp = dx; + dx = dy; + dy = tmp; + tmp = xInc; + xInc = yInc; + yInc = tmp; + } + + c = dx << 1; + m = dy << 1; + + run = dx; + do + { + *dst = argb; + + dst = (u32*) ( (u8*) dst + xInc ); // x += xInc + d += m; + if ( d > dx ) + { + dst = (u32*) ( (u8*) dst + yInc ); // y += yInc + d -= c; + } + run -= 1; + } while (run>=0); +} + + +/* +*/ +static void RenderLine32_Blend(video::IImage *t, + const core::position2d &p0, + const core::position2d &p1, + u32 argb, u32 alpha) +{ + s32 dx = p1.X - p0.X; + s32 dy = p1.Y - p0.Y; + + s32 c; + s32 m; + s32 d = 0; + s32 run; + + s32 xInc = 4; + s32 yInc = (s32) t->getPitch(); + + if ( dx < 0 ) + { + xInc = -xInc; + dx = -dx; + } + + if ( dy < 0 ) + { + yInc = -yInc; + dy = -dy; + } + + u32 *dst; + dst = (u32*) ( (u8*) t->getData() + ( p0.Y * t->getPitch() ) + ( p0.X << 2 ) ); + + if ( dy > dx ) + { + s32 tmp; + tmp = dx; + dx = dy; + dy = tmp; + tmp = xInc; + xInc = yInc; + yInc = tmp; + } + + c = dx << 1; + m = dy << 1; + + run = dx; + const u32 packA = packAlpha ( alpha ); + do + { + *dst = packA | PixelBlend32( *dst, argb, alpha ); + + dst = (u32*) ( (u8*) dst + xInc ); // x += xInc + d += m; + if ( d > dx ) + { + dst = (u32*) ( (u8*) dst + yInc ); // y += yInc + d -= c; + } + run -= 1; + } while (run>=0); +} + +/* +*/ +static void RenderLine16_Decal(video::IImage *t, + const core::position2d &p0, + const core::position2d &p1, + u32 argb ) +{ + s32 dx = p1.X - p0.X; + s32 dy = p1.Y - p0.Y; + + s32 c; + s32 m; + s32 d = 0; + s32 run; + + s32 xInc = 2; + s32 yInc = (s32) t->getPitch(); + + if ( dx < 0 ) + { + xInc = -xInc; + dx = -dx; + } + + if ( dy < 0 ) + { + yInc = -yInc; + dy = -dy; + } + + u16 *dst; + dst = (u16*) ( (u8*) t->getData() + ( p0.Y * t->getPitch() ) + ( p0.X << 1 ) ); + + if ( dy > dx ) + { + s32 tmp; + tmp = dx; + dx = dy; + dy = tmp; + tmp = xInc; + xInc = yInc; + yInc = tmp; + } + + c = dx << 1; + m = dy << 1; + + run = dx; + do + { + *dst = (u16)argb; + + dst = (u16*) ( (u8*) dst + xInc ); // x += xInc + d += m; + if ( d > dx ) + { + dst = (u16*) ( (u8*) dst + yInc ); // y += yInc + d -= c; + } + run -= 1; + } while (run>=0); +} + +/* +*/ +static void RenderLine16_Blend(video::IImage *t, + const core::position2d &p0, + const core::position2d &p1, + u16 argb, + u16 alpha) +{ + s32 dx = p1.X - p0.X; + s32 dy = p1.Y - p0.Y; + + s32 c; + s32 m; + s32 d = 0; + s32 run; + + s32 xInc = 2; + s32 yInc = (s32) t->getPitch(); + + if ( dx < 0 ) + { + xInc = -xInc; + dx = -dx; + } + + if ( dy < 0 ) + { + yInc = -yInc; + dy = -dy; + } + + u16 *dst; + dst = (u16*) ( (u8*) t->getData() + ( p0.Y * t->getPitch() ) + ( p0.X << 1 ) ); + + if ( dy > dx ) + { + s32 tmp; + tmp = dx; + dx = dy; + dy = tmp; + tmp = xInc; + xInc = yInc; + yInc = tmp; + } + + c = dx << 1; + m = dy << 1; + + run = dx; + const u16 packA = alpha ? 0x8000 : 0; + do + { + *dst = packA | PixelBlend16( *dst, argb, alpha ); + + dst = (u16*) ( (u8*) dst + xInc ); // x += xInc + d += m; + if ( d > dx ) + { + dst = (u16*) ( (u8*) dst + yInc ); // y += yInc + d -= c; + } + run -= 1; + } while (run>=0); +} + + +/*! +*/ +static void executeBlit_TextureCopy_x_to_x( const SBlitJob * job ) +{ + const u32 w = job->width; + const u32 h = job->height; + if (job->stretch) + { + const u32 *src = static_cast(job->src); + u32 *dst = static_cast(job->dst); + const float wscale = 1.f/job->x_stretch; + const float hscale = 1.f/job->y_stretch; + + for ( u32 dy = 0; dy < h; ++dy ) + { + const u32 src_y = (u32)(dy*hscale); + src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y ); + + for ( u32 dx = 0; dx < w; ++dx ) + { + const u32 src_x = (u32)(dx*wscale); + dst[dx] = src[src_x]; + } + dst = (u32*) ( (u8*) (dst) + job->dstPitch ); + } + } + else + { + const u32 widthPitch = job->width * job->dstPixelMul; + const void *src = (void*) job->src; + void *dst = (void*) job->dst; + + for ( u32 dy = 0; dy != h; ++dy ) + { + memcpy( dst, src, widthPitch ); + + src = (void*) ( (u8*) (src) + job->srcPitch ); + dst = (void*) ( (u8*) (dst) + job->dstPitch ); + } + } +} + +/*! +*/ +static void executeBlit_TextureCopy_32_to_16( const SBlitJob * job ) +{ + const u32 w = job->width; + const u32 h = job->height; + const u32 *src = static_cast(job->src); + u16 *dst = static_cast(job->dst); + + if (job->stretch) + { + const float wscale = 1.f/job->x_stretch; + const float hscale = 1.f/job->y_stretch; + + for ( u32 dy = 0; dy < h; ++dy ) + { + const u32 src_y = (u32)(dy*hscale); + src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y ); + + for ( u32 dx = 0; dx < w; ++dx ) + { + const u32 src_x = (u32)(dx*wscale); + //16 bit Blitter depends on pre-multiplied color + const u32 s = PixelLerp32( src[src_x] | 0xFF000000, extractAlpha( src[src_x] ) ); + dst[dx] = video::A8R8G8B8toA1R5G5B5( s ); + } + dst = (u16*) ( (u8*) (dst) + job->dstPitch ); + } + } + else + { + for ( u32 dy = 0; dy != h; ++dy ) + { + for ( u32 dx = 0; dx != w; ++dx ) + { + //16 bit Blitter depends on pre-multiplied color + const u32 s = PixelLerp32( src[dx] | 0xFF000000, extractAlpha( src[dx] ) ); + dst[dx] = video::A8R8G8B8toA1R5G5B5( s ); + } + + src = (u32*) ( (u8*) (src) + job->srcPitch ); + dst = (u16*) ( (u8*) (dst) + job->dstPitch ); + } + } +} + +/*! +*/ +static void executeBlit_TextureCopy_24_to_16( const SBlitJob * job ) +{ + const u32 w = job->width; + const u32 h = job->height; + const u8 *src = static_cast(job->src); + u16 *dst = static_cast(job->dst); + + if (job->stretch) + { + const float wscale = 3.f/job->x_stretch; + const float hscale = 1.f/job->y_stretch; + + for ( u32 dy = 0; dy < h; ++dy ) + { + const u32 src_y = (u32)(dy*hscale); + src = (u8*)(job->src) + job->srcPitch*src_y; + + for ( u32 dx = 0; dx < w; ++dx ) + { + const u8* src_x = src+(u32)(dx*wscale); + dst[dx] = video::RGBA16(src_x[0], src_x[1], src_x[2]); + } + dst = (u16*) ( (u8*) (dst) + job->dstPitch ); + } + } + else + { + for ( u32 dy = 0; dy != h; ++dy ) + { + const u8* s = src; + for ( u32 dx = 0; dx != w; ++dx ) + { + dst[dx] = video::RGBA16(s[0], s[1], s[2]); + s += 3; + } + + src = src+job->srcPitch; + dst = (u16*) ( (u8*) (dst) + job->dstPitch ); + } + } +} + + +/*! +*/ +static void executeBlit_TextureCopy_16_to_32( const SBlitJob * job ) +{ + const u32 w = job->width; + const u32 h = job->height; + const u16 *src = static_cast(job->src); + u32 *dst = static_cast(job->dst); + + if (job->stretch) + { + const float wscale = 1.f/job->x_stretch; + const float hscale = 1.f/job->y_stretch; + + for ( u32 dy = 0; dy < h; ++dy ) + { + const u32 src_y = (u32)(dy*hscale); + src = (u16*) ( (u8*) (job->src) + job->srcPitch*src_y ); + + for ( u32 dx = 0; dx < w; ++dx ) + { + const u32 src_x = (u32)(dx*wscale); + dst[dx] = video::A1R5G5B5toA8R8G8B8(src[src_x]); + } + dst = (u32*) ( (u8*) (dst) + job->dstPitch ); + } + } + else + { + for ( u32 dy = 0; dy != h; ++dy ) + { + for ( u32 dx = 0; dx != w; ++dx ) + { + dst[dx] = video::A1R5G5B5toA8R8G8B8( src[dx] ); + } + + src = (u16*) ( (u8*) (src) + job->srcPitch ); + dst = (u32*) ( (u8*) (dst) + job->dstPitch ); + } + } +} + +static void executeBlit_TextureCopy_16_to_24( const SBlitJob * job ) +{ + const u32 w = job->width; + const u32 h = job->height; + const u16 *src = static_cast(job->src); + u8 *dst = static_cast(job->dst); + + if (job->stretch) + { + const float wscale = 1.f/job->x_stretch; + const float hscale = 1.f/job->y_stretch; + + for ( u32 dy = 0; dy < h; ++dy ) + { + const u32 src_y = (u32)(dy*hscale); + src = (u16*) ( (u8*) (job->src) + job->srcPitch*src_y ); + + for ( u32 dx = 0; dx < w; ++dx ) + { + const u32 src_x = (u32)(dx*wscale); + u32 color = video::A1R5G5B5toA8R8G8B8(src[src_x]); + u8 * writeTo = &dst[dx * 3]; + *writeTo++ = (color >> 16)& 0xFF; + *writeTo++ = (color >> 8) & 0xFF; + *writeTo++ = color & 0xFF; + } + dst += job->dstPitch; + } + } + else + { + for ( u32 dy = 0; dy != h; ++dy ) + { + for ( u32 dx = 0; dx != w; ++dx ) + { + u32 color = video::A1R5G5B5toA8R8G8B8(src[dx]); + u8 * writeTo = &dst[dx * 3]; + *writeTo++ = (color >> 16)& 0xFF; + *writeTo++ = (color >> 8) & 0xFF; + *writeTo++ = color & 0xFF; + } + + src = (u16*) ( (u8*) (src) + job->srcPitch ); + dst += job->dstPitch; + } + } +} + +/*! +*/ +static void executeBlit_TextureCopy_24_to_32( const SBlitJob * job ) +{ + const u32 w = job->width; + const u32 h = job->height; + const u8 *src = static_cast(job->src); + u32 *dst = static_cast(job->dst); + + if (job->stretch) + { + const float wscale = 3.f/job->x_stretch; + const float hscale = 1.f/job->y_stretch; + + for ( u32 dy = 0; dy < h; ++dy ) + { + const u32 src_y = (u32)(dy*hscale); + src = (const u8*)job->src+(job->srcPitch*src_y); + + for ( u32 dx = 0; dx < w; ++dx ) + { + const u8* s = src+(u32)(dx*wscale); + dst[dx] = 0xFF000000 | s[0] << 16 | s[1] << 8 | s[2]; + } + dst = (u32*) ( (u8*) (dst) + job->dstPitch ); + } + } + else + { + for ( s32 dy = 0; dy != job->height; ++dy ) + { + const u8* s = src; + + for ( s32 dx = 0; dx != job->width; ++dx ) + { + dst[dx] = 0xFF000000 | s[0] << 16 | s[1] << 8 | s[2]; + s += 3; + } + + src = src + job->srcPitch; + dst = (u32*) ( (u8*) (dst) + job->dstPitch ); + } + } +} + +static void executeBlit_TextureCopy_32_to_24( const SBlitJob * job ) +{ + const u32 w = job->width; + const u32 h = job->height; + const u32 *src = static_cast(job->src); + u8 *dst = static_cast(job->dst); + + if (job->stretch) + { + const float wscale = 1.f/job->x_stretch; + const float hscale = 1.f/job->y_stretch; + + for ( u32 dy = 0; dy < h; ++dy ) + { + const u32 src_y = (u32)(dy*hscale); + src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y); + + for ( u32 dx = 0; dx < w; ++dx ) + { + const u32 src_x = src[(u32)(dx*wscale)]; + u8 * writeTo = &dst[dx * 3]; + *writeTo++ = (src_x >> 16)& 0xFF; + *writeTo++ = (src_x >> 8) & 0xFF; + *writeTo++ = src_x & 0xFF; + } + dst += job->dstPitch; + } + } + else + { + for ( u32 dy = 0; dy != h; ++dy ) + { + for ( u32 dx = 0; dx != w; ++dx ) + { + u8 * writeTo = &dst[dx * 3]; + *writeTo++ = (src[dx] >> 16)& 0xFF; + *writeTo++ = (src[dx] >> 8) & 0xFF; + *writeTo++ = src[dx] & 0xFF; + } + + src = (u32*) ( (u8*) (src) + job->srcPitch ); + dst += job->dstPitch; + } + } +} + +/*! +*/ +static void executeBlit_TextureBlend_16_to_16( const SBlitJob * job ) +{ + const u32 w = job->width; + const u32 h = job->height; + const u32 rdx = w>>1; + + const u32 *src = (u32*) job->src; + u32 *dst = (u32*) job->dst; + + if (job->stretch) + { + const float wscale = 1.f/job->x_stretch; + const float hscale = 1.f/job->y_stretch; + const u32 off = core::if_c_a_else_b(w&1, (u32)((w-1)*wscale), 0); + for ( u32 dy = 0; dy < h; ++dy ) + { + const u32 src_y = (u32)(dy*hscale); + src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y ); + + for ( u32 dx = 0; dx < rdx; ++dx ) + { + const u32 src_x = (u32)(dx*wscale); + dst[dx] = PixelBlend16_simd( dst[dx], src[src_x] ); + } + if ( off ) + { + ((u16*) dst)[off] = PixelBlend16( ((u16*) dst)[off], ((u16*) src)[off] ); + } + + dst = (u32*) ( (u8*) (dst) + job->dstPitch ); + } + } + else + { + const u32 off = core::if_c_a_else_b(w&1, w-1, 0); + for (u32 dy = 0; dy != h; ++dy ) + { + for (u32 dx = 0; dx != rdx; ++dx ) + { + dst[dx] = PixelBlend16_simd( dst[dx], src[dx] ); + } + + if ( off ) + { + ((u16*) dst)[off] = PixelBlend16( ((u16*) dst)[off], ((u16*) src)[off] ); + } + + src = (u32*) ( (u8*) (src) + job->srcPitch ); + dst = (u32*) ( (u8*) (dst) + job->dstPitch ); + } + } +} + +/*! +*/ +static void executeBlit_TextureBlend_32_to_32( const SBlitJob * job ) +{ + const u32 w = job->width; + const u32 h = job->height; + const u32 *src = (u32*) job->src; + u32 *dst = (u32*) job->dst; + + if (job->stretch) + { + const float wscale = 1.f/job->x_stretch; + const float hscale = 1.f/job->y_stretch; + for ( u32 dy = 0; dy < h; ++dy ) + { + const u32 src_y = (u32)(dy*hscale); + src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y ); + + for ( u32 dx = 0; dx < w; ++dx ) + { + const u32 src_x = (u32)(dx*wscale); + dst[dx] = PixelBlend32( dst[dx], src[src_x] ); + } + + dst = (u32*) ( (u8*) (dst) + job->dstPitch ); + } + } + else + { + for ( u32 dy = 0; dy != h; ++dy ) + { + for ( u32 dx = 0; dx != w; ++dx ) + { + dst[dx] = PixelBlend32( dst[dx], src[dx] ); + } + src = (u32*) ( (u8*) (src) + job->srcPitch ); + dst = (u32*) ( (u8*) (dst) + job->dstPitch ); + } + } +} + +/*! +*/ +static void executeBlit_TextureBlendColor_16_to_16( const SBlitJob * job ) +{ + u16 *src = (u16*) job->src; + u16 *dst = (u16*) job->dst; + + u16 blend = video::A8R8G8B8toA1R5G5B5 ( job->argb ); + for ( s32 dy = 0; dy != job->height; ++dy ) + { + for ( s32 dx = 0; dx != job->width; ++dx ) + { + if ( 0 == (src[dx] & 0x8000) ) + continue; + + dst[dx] = PixelMul16_2( src[dx], blend ); + } + src = (u16*) ( (u8*) (src) + job->srcPitch ); + dst = (u16*) ( (u8*) (dst) + job->dstPitch ); + } +} + + +/*! +*/ +static void executeBlit_TextureBlendColor_32_to_32( const SBlitJob * job ) +{ + u32 *src = (u32*) job->src; + u32 *dst = (u32*) job->dst; + + for ( s32 dy = 0; dy != job->height; ++dy ) + { + for ( s32 dx = 0; dx != job->width; ++dx ) + { + dst[dx] = PixelBlend32( dst[dx], PixelMul32_2( src[dx], job->argb ) ); + } + src = (u32*) ( (u8*) (src) + job->srcPitch ); + dst = (u32*) ( (u8*) (dst) + job->dstPitch ); + } +} + +/*! +*/ +static void executeBlit_Color_16_to_16( const SBlitJob * job ) +{ + const u16 c = video::A8R8G8B8toA1R5G5B5(job->argb); + u16 *dst = (u16*) job->dst; + + for ( s32 dy = 0; dy != job->height; ++dy ) + { + memset16(dst, c, job->srcPitch); + dst = (u16*) ( (u8*) (dst) + job->dstPitch ); + } +} + +/*! +*/ +static void executeBlit_Color_32_to_32( const SBlitJob * job ) +{ + u32 *dst = (u32*) job->dst; + + for ( s32 dy = 0; dy != job->height; ++dy ) + { + memset32( dst, job->argb, job->srcPitch ); + dst = (u32*) ( (u8*) (dst) + job->dstPitch ); + } +} + +/*! +*/ +static void executeBlit_ColorAlpha_16_to_16( const SBlitJob * job ) +{ + u16 *dst = (u16*) job->dst; + + const u16 alpha = extractAlpha( job->argb ) >> 3; + if ( 0 == alpha ) + return; + const u32 src = video::A8R8G8B8toA1R5G5B5( job->argb ); + + for ( s32 dy = 0; dy != job->height; ++dy ) + { + for ( s32 dx = 0; dx != job->width; ++dx ) + { + dst[dx] = 0x8000 | PixelBlend16( dst[dx], src, alpha ); + } + dst = (u16*) ( (u8*) (dst) + job->dstPitch ); + } +} + +/*! +*/ +static void executeBlit_ColorAlpha_32_to_32( const SBlitJob * job ) +{ + u32 *dst = (u32*) job->dst; + + const u32 alpha = extractAlpha( job->argb ); + const u32 src = job->argb; + + for ( s32 dy = 0; dy != job->height; ++dy ) + { + for ( s32 dx = 0; dx != job->width; ++dx ) + { + dst[dx] = (job->argb & 0xFF000000 ) | PixelBlend32( dst[dx], src, alpha ); + } + dst = (u32*) ( (u8*) (dst) + job->dstPitch ); + } +} + +/*! + Combine alpha channels (increases alpha / reduces transparency) +*/ +static void executeBlit_TextureCombineColor_16_to_16( const SBlitJob * job ) +{ + const u32 w = job->width * 2; + const u32 h = job->height * 2; + u16* src = (u16*) job->src; + u16* dst = (u16*) job->dst; + + const u16 jobColor = video::A8R8G8B8toA1R5G5B5( job->argb ); + + /* + Stretch not supported. + */ + for ( u32 dy = 0; dy != h; dy++ ) + { + for ( u32 dx = 0; dx != w; dx++ ) + { + const u16 src_x = src[dx]; + const u16 dst_x = dst[dx]; + dst[dx] = PixelCombine16( dst_x, PixelMul16_2( src_x, jobColor ) ); + } + src = (u16*) ( (u8*) (src) + job->srcPitch ); + dst = (u16*) ( (u8*) (dst) + job->dstPitch ); + } +} + +/*! + Combine alpha channels (increases alpha / reduces transparency) +*/ +static void executeBlit_TextureCombineColor_16_to_24( const SBlitJob * job ) +{ + const u32 w = job->width; + const u32 h = job->height; + const u16 *src = static_cast(job->src); + u8 *dst = static_cast(job->dst); + + const u16 jobColor = video::A8R8G8B8toA1R5G5B5( job->argb ); + + if (job->stretch) + { + const float wscale = 1.f/job->x_stretch; + const float hscale = 1.f/job->y_stretch; + + for ( u32 dy = 0; dy < h; ++dy ) + { + const u32 src_y = (u32)(dy*hscale); + src = (u16*) ( (u8*) (job->src) + job->srcPitch*src_y ); + + for ( u32 dx = 0; dx < w; ++dx ) + { + const u32 src_x = (u32)(dx*wscale); + u32 color = PixelMul16_2( video::A1R5G5B5toA8R8G8B8(src[src_x]), jobColor); + u8 * writeTo = &dst[dx * 3]; + if ( video::getAlpha(src[src_x]) > 0 ) // only overlay if source has visible alpha (alpha == 1) + { + *writeTo++ = (color >> 16)& 0xFF; + *writeTo++ = (color >> 8) & 0xFF; + *writeTo++ = color & 0xFF; + } + } + dst += job->dstPitch; + } + } + else + { + for ( u32 dy = 0; dy != h; ++dy ) + { + for ( u32 dx = 0; dx != w; ++dx ) + { + u32 color = PixelMul16_2( video::A1R5G5B5toA8R8G8B8(src[dx]), jobColor); + u8 * writeTo = &dst[dx * 3]; + if ( video::getAlpha(src[dx]) > 0 ) // only overlay if source has visible alpha (alpha == 1) + { + *writeTo++ = (color >> 16)& 0xFF; + *writeTo++ = (color >> 8) & 0xFF; + *writeTo++ = color & 0xFF; + } + } + + src = (u16*) ( (u8*) (src) + job->srcPitch ); + dst += job->dstPitch; + } + } +} + +/*! + Combine alpha channels (increases alpha / reduces transparency) + Destination alpha is treated as full 255 +*/ +static void executeBlit_TextureCombineColor_32_to_24( const SBlitJob * job ) +{ + const u32 w = job->width; + const u32 h = job->height; + const u32 *src = static_cast(job->src); + u8 *dst = static_cast(job->dst); + + if (job->stretch) + { + const float wscale = 1.f/job->x_stretch; + const float hscale = 1.f/job->y_stretch; + + for ( u32 dy = 0; dy < h; ++dy ) + { + const u32 src_y = (u32)(dy*hscale); + src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y); + + for ( u32 dx = 0; dx < w; ++dx ) + { + const u32 src_x = src[(u32)(dx*wscale)]; + u8* writeTo = &dst[dx * 3]; + const u32 dst_x = 0xFF000000 | writeTo[0] << 16 | writeTo[1] << 8 | writeTo[2]; + const u32 combo = PixelCombine32( dst_x, PixelMul32_2( src_x, job->argb ) ); + *writeTo++ = (combo >> 16) & 0xFF; + *writeTo++ = (combo >> 8) & 0xFF; + *writeTo++ = combo & 0xFF; + } + dst += job->dstPitch; + } + } + else + { + for ( u32 dy = 0; dy != h; ++dy ) + { + for ( u32 dx = 0; dx != w; ++dx ) + { + u8* writeTo = &dst[dx * 3]; + const u32 dst_x = 0xFF000000 | writeTo[0] << 16 | writeTo[1] << 8 | writeTo[2]; + const u32 combo = PixelCombine32( dst_x, PixelMul32_2( src[dx], job->argb ) ); + *writeTo++ = (combo >> 16) & 0xFF; + *writeTo++ = (combo >> 8) & 0xFF; + *writeTo++ = combo & 0xFF; + } + + src = (u32*) ( (u8*) (src) + job->srcPitch ); + dst += job->dstPitch; + } + } +} + +/*! + Combine alpha channels (increases alpha / reduces transparency) +*/ +static void executeBlit_TextureCombineColor_32_to_32( const SBlitJob * job ) +{ + u32 *src = (u32*) job->src; + u32 *dst = (u32*) job->dst; + + for ( s32 dy = 0; dy != job->height; ++dy ) + { + for ( s32 dx = 0; dx != job->width; ++dx ) + { + dst[dx] = PixelCombine32( dst[dx], PixelMul32_2( src[dx], job->argb ) ); + } + src = (u32*) ( (u8*) (src) + job->srcPitch ); + dst = (u32*) ( (u8*) (dst) + job->dstPitch ); + } +} + +// Blitter Operation +enum eBlitter +{ + BLITTER_INVALID = 0, + BLITTER_COLOR, + BLITTER_COLOR_ALPHA, + BLITTER_TEXTURE, + BLITTER_TEXTURE_ALPHA_BLEND, + BLITTER_TEXTURE_ALPHA_COLOR_BLEND, + BLITTER_TEXTURE_COMBINE_ALPHA, +}; + +typedef void (*tExecuteBlit) ( const SBlitJob * job ); + + +/*! +*/ +struct blitterTable +{ + eBlitter operation; + s32 destFormat; + s32 sourceFormat; + tExecuteBlit func; +}; + +static const blitterTable blitTable[] = +{ + { BLITTER_TEXTURE, -2, -2, executeBlit_TextureCopy_x_to_x }, + { BLITTER_TEXTURE, video::ECF_A1R5G5B5, video::ECF_A8R8G8B8, executeBlit_TextureCopy_32_to_16 }, + { BLITTER_TEXTURE, video::ECF_A1R5G5B5, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_16 }, + { BLITTER_TEXTURE, video::ECF_A8R8G8B8, video::ECF_A1R5G5B5, executeBlit_TextureCopy_16_to_32 }, + { BLITTER_TEXTURE, video::ECF_A8R8G8B8, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_32 }, + { BLITTER_TEXTURE, video::ECF_R8G8B8, video::ECF_A1R5G5B5, executeBlit_TextureCopy_16_to_24 }, + { BLITTER_TEXTURE, video::ECF_R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureCopy_32_to_24 }, + { BLITTER_TEXTURE_ALPHA_BLEND, video::ECF_A1R5G5B5, video::ECF_A1R5G5B5, executeBlit_TextureBlend_16_to_16 }, + { BLITTER_TEXTURE_ALPHA_BLEND, video::ECF_A8R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureBlend_32_to_32 }, + { BLITTER_TEXTURE_ALPHA_COLOR_BLEND, video::ECF_A1R5G5B5, video::ECF_A1R5G5B5, executeBlit_TextureBlendColor_16_to_16 }, + { BLITTER_TEXTURE_ALPHA_COLOR_BLEND, video::ECF_A8R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureBlendColor_32_to_32 }, + { BLITTER_COLOR, video::ECF_A1R5G5B5, -1, executeBlit_Color_16_to_16 }, + { BLITTER_COLOR, video::ECF_A8R8G8B8, -1, executeBlit_Color_32_to_32 }, + { BLITTER_COLOR_ALPHA, video::ECF_A1R5G5B5, -1, executeBlit_ColorAlpha_16_to_16 }, + { BLITTER_COLOR_ALPHA, video::ECF_A8R8G8B8, -1, executeBlit_ColorAlpha_32_to_32 }, + { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A8R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureCombineColor_32_to_32 }, + { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A8R8G8B8, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_32 }, + { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureCombineColor_32_to_24 }, + { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_R8G8B8, video::ECF_R8G8B8, executeBlit_TextureCopy_x_to_x }, + { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A1R5G5B5, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_16 }, + { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A1R5G5B5, video::ECF_A1R5G5B5, executeBlit_TextureCombineColor_16_to_16 }, + { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A1R5G5B5, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_16 }, + { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_R8G8B8, video::ECF_A1R5G5B5, executeBlit_TextureCombineColor_16_to_24 }, + { BLITTER_INVALID, -1, -1, 0 } +}; + + +static inline tExecuteBlit getBlitter2( eBlitter operation,const video::IImage * dest,const video::IImage * source ) +{ + video::ECOLOR_FORMAT sourceFormat = (video::ECOLOR_FORMAT) ( source ? source->getColorFormat() : -1 ); + video::ECOLOR_FORMAT destFormat = (video::ECOLOR_FORMAT) ( dest ? dest->getColorFormat() : -1 ); + + const blitterTable * b = blitTable; + + while ( b->operation != BLITTER_INVALID ) + { + if ( b->operation == operation ) + { + if (( b->destFormat == -1 || b->destFormat == destFormat ) && + ( b->sourceFormat == -1 || b->sourceFormat == sourceFormat ) ) + return b->func; + else + if ( b->destFormat == -2 && ( sourceFormat == destFormat ) ) + return b->func; + } + b += 1; + } + return 0; +} + + +// bounce clipping to texture +inline void setClip ( AbsRectangle &out, const core::rect *clip, + const video::IImage * tex, s32 passnative ) +{ + if ( clip && 0 == tex && passnative ) + { + out.x0 = clip->UpperLeftCorner.X; + out.x1 = clip->LowerRightCorner.X; + out.y0 = clip->UpperLeftCorner.Y; + out.y1 = clip->LowerRightCorner.Y; + return; + } + + const s32 w = tex ? tex->getDimension().Width : 0; + const s32 h = tex ? tex->getDimension().Height : 0; + if ( clip ) + { + out.x0 = core::s32_clamp ( clip->UpperLeftCorner.X, 0, w ); + out.x1 = core::s32_clamp ( clip->LowerRightCorner.X, out.x0, w ); + out.y0 = core::s32_clamp ( clip->UpperLeftCorner.Y, 0, h ); + out.y1 = core::s32_clamp ( clip->LowerRightCorner.Y, out.y0, h ); + } + else + { + out.x0 = 0; + out.y0 = 0; + out.x1 = w; + out.y1 = h; + } + +} + +/*! + a generic 2D Blitter +*/ +static s32 Blit(eBlitter operation, + video::IImage * dest, + const core::rect *destClipping, + const core::position2d *destPos, + video::IImage * const source, + const core::rect *sourceClipping, + u32 argb) +{ + tExecuteBlit blitter = getBlitter2( operation, dest, source ); + if ( 0 == blitter ) + { + return 0; + } + + // Clipping + AbsRectangle sourceClip; + AbsRectangle destClip; + AbsRectangle v; + + SBlitJob job; + + setClip ( sourceClip, sourceClipping, source, 1 ); + setClip ( destClip, destClipping, dest, 0 ); + + v.x0 = destPos ? destPos->X : 0; + v.y0 = destPos ? destPos->Y : 0; + v.x1 = v.x0 + ( sourceClip.x1 - sourceClip.x0 ); + v.y1 = v.y0 + ( sourceClip.y1 - sourceClip.y0 ); + + if ( !intersect( job.Dest, destClip, v ) ) + return 0; + + job.width = job.Dest.x1 - job.Dest.x0; + job.height = job.Dest.y1 - job.Dest.y0; + + job.Source.x0 = sourceClip.x0 + ( job.Dest.x0 - v.x0 ); + job.Source.x1 = job.Source.x0 + job.width; + job.Source.y0 = sourceClip.y0 + ( job.Dest.y0 - v.y0 ); + job.Source.y1 = job.Source.y0 + job.height; + + job.argb = argb; + + if ( source ) + { + job.srcPitch = source->getPitch(); + job.srcPixelMul = source->getBytesPerPixel(); + job.src = (void*) ( (u8*) source->getData() + ( job.Source.y0 * job.srcPitch ) + ( job.Source.x0 * job.srcPixelMul ) ); + } + else + { + // use srcPitch for color operation on dest + job.srcPitch = job.width * dest->getBytesPerPixel(); + } + + job.dstPitch = dest->getPitch(); + job.dstPixelMul = dest->getBytesPerPixel(); + job.dst = (void*) ( (u8*) dest->getData() + ( job.Dest.y0 * job.dstPitch ) + ( job.Dest.x0 * job.dstPixelMul ) ); + + blitter( &job ); + + return 1; +} + +static s32 StretchBlit(eBlitter operation, + video::IImage* dest, const core::rect *destRect, + const core::rect *srcRect, video::IImage* const source, + u32 argb) +{ + tExecuteBlit blitter = getBlitter2( operation, dest, source ); + if ( 0 == blitter ) + { + return 0; + } + + SBlitJob job; + + // Clipping + setClip ( job.Source, srcRect, source, 1 ); + setClip ( job.Dest, destRect, dest, 0 ); + + job.width = job.Dest.x1-job.Dest.x0; + job.height = job.Dest.y1-job.Dest.y0; + + job.argb = argb; + + // use original dest size, despite any clipping + job.x_stretch = (float)destRect->getWidth() / (float)(job.Source.x1-job.Source.x0); + job.y_stretch = (float)destRect->getHeight() / (float)(job.Source.y1-job.Source.y0); + job.stretch = (job.x_stretch != 1.f) || (job.y_stretch != 1.f); + + if ( source ) + { + job.srcPitch = source->getPitch(); + job.srcPixelMul = source->getBytesPerPixel(); + job.src = (void*) ( (u8*) source->getData() + ( job.Source.y0 * job.srcPitch ) + ( job.Source.x0 * job.srcPixelMul ) ); + } + else + { + // use srcPitch for color operation on dest + job.srcPitch = job.width * dest->getBytesPerPixel(); + } + + job.dstPitch = dest->getPitch(); + job.dstPixelMul = dest->getBytesPerPixel(); + job.dst = (void*) ( (u8*) dest->getData() + ( job.Dest.y0 * job.dstPitch ) + ( job.Dest.x0 * job.dstPixelMul ) ); + + blitter( &job ); + + return 1; +} + + +// Methods for Software drivers +//! draws a rectangle +static void drawRectangle(video::IImage* img, const core::rect& rect, const video::SColor &color) +{ + Blit(color.getAlpha() == 0xFF ? BLITTER_COLOR : BLITTER_COLOR_ALPHA, + img, 0, &rect.UpperLeftCorner, 0, &rect, color.color); +} + + +//! draws a line from to with color +static void drawLine(video::IImage* img, const core::position2d& from, + const core::position2d& to, const video::SColor &color) +{ + AbsRectangle clip; + GetClip(clip, img); + + core::position2d p[2]; + if (ClipLine( clip, p[0], p[1], from, to)) + { + u32 alpha = extractAlpha(color.color); + + switch(img->getColorFormat()) + { + case video::ECF_A1R5G5B5: + if (alpha == 256) + { + RenderLine16_Decal(img, p[0], p[1], video::A8R8G8B8toA1R5G5B5(color.color)); + } + else + { + RenderLine16_Blend(img, p[0], p[1], video::A8R8G8B8toA1R5G5B5(color.color), alpha >> 3); + } + break; + case video::ECF_A8R8G8B8: + if (alpha == 256) + { + RenderLine32_Decal(img, p[0], p[1], color.color); + } + else + { + RenderLine32_Blend(img, p[0], p[1], color.color, alpha); + } + break; + default: + break; + } + } +} + + +} + +#endif + diff --git a/source/Irrlicht/CBoneSceneNode.cpp b/source/Irrlicht/CBoneSceneNode.cpp new file mode 100644 index 00000000..af540110 --- /dev/null +++ b/source/Irrlicht/CBoneSceneNode.cpp @@ -0,0 +1,129 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ + +#include "CBoneSceneNode.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CBoneSceneNode::CBoneSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + u32 boneIndex, const c8* boneName) +: IBoneSceneNode(parent, mgr, id), BoneIndex(boneIndex), + AnimationMode(EBAM_AUTOMATIC), SkinningSpace(EBSS_LOCAL) +{ + #ifdef _DEBUG + setDebugName("CBoneSceneNode"); + #endif + setName(boneName); +} + + +//! Returns the index of the bone +u32 CBoneSceneNode::getBoneIndex() const +{ + return BoneIndex; +} + + +//! Sets the animation mode of the bone. Returns true if successful. +bool CBoneSceneNode::setAnimationMode(E_BONE_ANIMATION_MODE mode) +{ + AnimationMode = mode; + return true; +} + + +//! Gets the current animation mode of the bone +E_BONE_ANIMATION_MODE CBoneSceneNode::getAnimationMode() const +{ + return AnimationMode; +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CBoneSceneNode::getBoundingBox() const +{ + return Box; +} + + +/* +//! Returns the relative transformation of the scene node. +core::matrix4 CBoneSceneNode::getRelativeTransformation() const +{ + return core::matrix4(); // RelativeTransformation; +} +*/ + + +void CBoneSceneNode::OnAnimate(u32 timeMs) +{ + if (IsVisible) + { + // animate this node with all animators + + ISceneNodeAnimatorList::Iterator ait = Animators.begin(); + for (; ait != Animators.end(); ++ait) + (*ait)->animateNode(this, timeMs); + + // update absolute position + //updateAbsolutePosition(); + + // perform the post render process on all children + ISceneNodeList::Iterator it = Children.begin(); + for (; it != Children.end(); ++it) + (*it)->OnAnimate(timeMs); + } +} + + +void CBoneSceneNode::helper_updateAbsolutePositionOfAllChildren(ISceneNode *Node) +{ + Node->updateAbsolutePosition(); + + ISceneNodeList::ConstIterator it = Node->getChildren().begin(); + for (; it != Node->getChildren().end(); ++it) + { + helper_updateAbsolutePositionOfAllChildren( (*it) ); + } +} + + +void CBoneSceneNode::updateAbsolutePositionOfAllChildren() +{ + helper_updateAbsolutePositionOfAllChildren( this ); +} + + +void CBoneSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + IBoneSceneNode::serializeAttributes(out, options); + out->addInt("BoneIndex", BoneIndex); + out->addEnum("AnimationMode", AnimationMode, BoneAnimationModeNames); +} + + +void CBoneSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + BoneIndex = in->getAttributeAsInt("BoneIndex"); + AnimationMode = (E_BONE_ANIMATION_MODE)in->getAttributeAsEnumeration("AnimationMode", BoneAnimationModeNames); + // for legacy files (before 1.5) + const core::stringc boneName = in->getAttributeAsString("BoneName"); + setName(boneName); + IBoneSceneNode::deserializeAttributes(in, options); + // TODO: add/replace bone in parent with bone from mesh +} + + +} // namespace scene +} // namespace irr + +#endif + diff --git a/source/Irrlicht/CBoneSceneNode.h b/source/Irrlicht/CBoneSceneNode.h new file mode 100644 index 00000000..711849ba --- /dev/null +++ b/source/Irrlicht/CBoneSceneNode.h @@ -0,0 +1,79 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_BONE_SCENE_NODE_H_INCLUDED__ +#define __C_BONE_SCENE_NODE_H_INCLUDED__ + +// Used with SkinnedMesh and IAnimatedMeshSceneNode, for boned meshes + +#include "IBoneSceneNode.h" + +namespace irr +{ +namespace scene +{ + + class CBoneSceneNode : public IBoneSceneNode + { + public: + + //! constructor + CBoneSceneNode(ISceneNode* parent, ISceneManager* mgr, + s32 id=-1, u32 boneIndex=0, const c8* boneName=0); + + //! Returns the index of the bone + virtual u32 getBoneIndex() const _IRR_OVERRIDE_; + + //! Sets the animation mode of the bone. Returns true if successful. + virtual bool setAnimationMode(E_BONE_ANIMATION_MODE mode) _IRR_OVERRIDE_; + + //! Gets the current animation mode of the bone + virtual E_BONE_ANIMATION_MODE getAnimationMode() const _IRR_OVERRIDE_; + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + /* + //! Returns the relative transformation of the scene node. + //virtual core::matrix4 getRelativeTransformation() const _IRR_OVERRIDE_; + */ + + virtual void OnAnimate(u32 timeMs) _IRR_OVERRIDE_; + + virtual void updateAbsolutePositionOfAllChildren() _IRR_OVERRIDE_; + + //! Writes attributes of the scene node. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! How the relative transformation of the bone is used + virtual void setSkinningSpace(E_BONE_SKINNING_SPACE space) _IRR_OVERRIDE_ + { + SkinningSpace=space; + } + + virtual E_BONE_SKINNING_SPACE getSkinningSpace() const _IRR_OVERRIDE_ + { + return SkinningSpace; + } + + private: + void helper_updateAbsolutePositionOfAllChildren(ISceneNode *Node); + + u32 BoneIndex; + + core::aabbox3d Box; + + E_BONE_ANIMATION_MODE AnimationMode; + E_BONE_SKINNING_SPACE SkinningSpace; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CBurningShader_Raster_Reference.cpp b/source/Irrlicht/CBurningShader_Raster_Reference.cpp new file mode 100644 index 00000000..c04db94b --- /dev/null +++ b/source/Irrlicht/CBurningShader_Raster_Reference.cpp @@ -0,0 +1,1141 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + + +namespace irr +{ + +namespace video +{ + + /*! Render states define set-up states for all kinds of vertex and pixel processing. + Some render states set up vertex processing, and some set up pixel processing (see Render States). + Render states can be saved and restored using stateblocks (see State Blocks Save and Restore State). + */ + enum BD3DRENDERSTATETYPE + { + /*! BD3DRS_ZENABLE + Depth-buffering state as one member of the BD3DZBUFFERTYPE enumerated type. + Set this state to D3DZB_TRUE to enable z-buffering, + D3DZB_USEW to enable w-buffering, or D3DZB_FALSE to disable depth buffering. + The default value for this render state is D3DZB_TRUE if a depth stencil was created + along with the swap chain by setting the EnableAutoDepthStencil member of the + D3DPRESENT_PARAMETERS structure to TRUE, and D3DZB_FALSE otherwise. + */ + BD3DRS_ZENABLE, + + /*! BD3DRS_FILLMODE + One or more members of the D3DFILLMODE enumerated type. The default value is D3DFILL_SOLID. + */ + BD3DRS_FILLMODE, + + /*! BD3DRS_SHADEMODE + One or more members of the D3DSHADEMODE enumerated type. The default value is D3DSHADE_GOURAUD. + */ + BD3DRS_SHADEMODE, + + /*! BD3DRS_ZWRITEENABLE + TRUE to enable the application to write to the depth buffer. The default value is TRUE. + This member enables an application to prevent the system from updating the depth buffer with + new depth values. If FALSE, depth comparisons are still made according to the render state + D3DRS_ZFUNC, assuming that depth buffering is taking place, but depth values are not written + to the buffer. + */ + BD3DRS_ZWRITEENABLE, + + /*! BD3DRS_ALPHATESTENABLE + TRUE to enable per pixel alpha testing. If the test passes, the pixel is processed by the frame + buffer. Otherwise, all frame-buffer processing is skipped for the pixel. The test is done by + comparing the incoming alpha value with the reference alpha value, using the comparison function + provided by the D3DRS_ALPHAFUNC render state. The reference alpha value is determined by the value + set for D3DRS_ALPHAREF. For more information, see Alpha Testing State. + The default value of this parameter is FALSE. + */ + BD3DRS_ALPHATESTENABLE, + + /*! BD3DRS_SRCBLEND + One member of the BD3DBLEND enumerated type. The default value is BD3DBLEND_ONE. + */ + BD3DRS_SRCBLEND, + + /*! BD3DRS_DESTBLEND + One member of the BD3DBLEND enumerated type. The default value is BD3DBLEND_ZERO. + */ + BD3DRS_DESTBLEND, + + /*! BD3DRS_CULLMODE + Specifies how back-facing triangles are culled, if at all. This can be set to one + member of the BD3DCULL enumerated type. The default value is BD3DCULL_CCW. + */ + BD3DRS_CULLMODE, + + /*! BD3DRS_ZFUNC + One member of the BD3DCMPFUNC enumerated type. The default value is BD3DCMP_LESSEQUAL. + This member enables an application to accept or reject a pixel, based on its distance from + the camera. The depth value of the pixel is compared with the depth-buffer value. If the depth + value of the pixel passes the comparison function, the pixel is written. + + The depth value is written to the depth buffer only if the render state is TRUE. + Software rasterizers and many hardware accelerators work faster if the depth test fails, + because there is no need to filter and modulate the texture if the pixel is not going to be + rendered. + */ + BD3DRS_ZFUNC, + + /*! BD3DRS_ALPHAREF + Value that specifies a reference alpha value against which pixels are tested when alpha testing + is enabled. This is an 8-bit value placed in the low 8 bits of the DWORD render-state value. + Values can range from 0x00000000 through 0x000000FF. The default value is 0. + */ + BD3DRS_ALPHAREF, + + /*! BD3DRS_ALPHAFUNC + One member of the BD3DCMPFUNC enumerated type. The default value is BD3DCMP_ALWAYS. + This member enables an application to accept or reject a pixel, based on its alpha value. + */ + BD3DRS_ALPHAFUNC, + + /*! BD3DRS_DITHERENABLE + TRUE to enable dithering. The default value is FALSE. + */ + BD3DRS_DITHERENABLE, + + /*! BD3DRS_ALPHABLENDENABLE + TRUE to enable alpha-blended transparency. The default value is FALSE. + The type of alpha blending is determined by the BD3DRS_SRCBLEND and BD3DRS_DESTBLEND render states. + */ + BD3DRS_ALPHABLENDENABLE, + + /*! BD3DRS_FOGENABLE + TRUE to enable fog blending. The default value is FALSE. For more information about using fog + blending, see Fog. + */ + BD3DRS_FOGENABLE, + + /*! BD3DRS_SPECULARENABLE + TRUE to enable specular highlights. The default value is FALSE. + Specular highlights are calculated as though every vertex in the object being lit is at the + object's origin. This gives the expected results as long as the object is modeled around the + origin and the distance from the light to the object is relatively large. In other cases, the + results as undefined. + When this member is set to TRUE, the specular color is added to the base color after the + texture cascade but before alpha blending. + */ + BD3DRS_SPECULARENABLE, + + /*! BD3DRS_FOGCOLOR + Value whose type is D3DCOLOR. The default value is 0. For more information about fog color, + see Fog Color. + */ + BD3DRS_FOGCOLOR, + + /*! BD3DRS_FOGTABLEMODE + The fog formula to be used for pixel fog. Set to one of the members of the D3DFOGMODE + enumerated type. The default value is D3DFOG_NONE. For more information about pixel fog, + see Pixel Fog. + */ + BD3DRS_FOGTABLEMODE, + + /*! BD3DRS_FOGSTART + Depth at which pixel or vertex fog effects begin for linear fog mode. The default value is 0.0f. + Depth is specified in world space for vertex fog and either device space [0.0, 1.0] or world + space for pixel fog. For pixel fog, these values are in device space when the system uses z for + fog calculations and world-world space when the system is using eye-relative fog (w-fog). For + more information, see Fog Parameters and Eye-Relative vs. Z-based Depth. + Values for the this render state are floating-point values. + Because the IDirect3DDevice9::SetRenderState method accepts DWORD values, your + application must cast a variable that contains the value, as shown in the following code example. + pDevice9->SetRenderState( BD3DRS_FOGSTART, *((DWORD*) (&fFogStart))); + */ + BD3DRS_FOGSTART, + + /*! BD3DRS_FOGEND + Depth at which pixel or vertex fog effects end for linear fog mode. The default value is 1.0f. + Depth is specified in world space for vertex fog and either device space [0.0, 1.0] or world space + for pixel fog. For pixel fog, these values are in device space when the system uses z for fog + calculations and in world space when the system is using eye-relative fog (w-fog). For more + information, see Fog Parameters and Eye-Relative vs. Z-based Depth. + Values for this render state are floating-point values. + */ + BD3DRS_FOGEND, + + /*! BD3DRS_FOGDENSITY + Fog density for pixel or vertex fog used in the exponential fog modes (D3DFOG_EXP and D3DFOG_EXP2). + Valid density values range from 0.0 through 1.0. The default value is 1.0. For more information, + see Fog Parameters. + Values for this render state are floating-point values. + */ + BD3DRS_FOGDENSITY, + + + /*! BD3DRS_RANGEFOGENABLE + TRUE to enable range-based vertex fog. The default value is FALSE, in which case the system + uses depth-based fog. In range-based fog, the distance of an object from the viewer is used + to compute fog effects, not the depth of the object (that is, the z-coordinate) in the scene. + In range-based fog, all fog methods work as usual, except that they use range instead of depth + in the computations. + Range is the correct factor to use for fog computations, but depth is commonly used instead + because range is time-consuming to compute and depth is generally already available. Using depth + to calculate fog has the undesirable effect of having the fogginess of peripheral objects change + as the viewer's eye moves - in this case, the depth changes and the range remains constant. + + Because no hardware currently supports per-pixel range-based fog, range correction is offered + only for vertex fog. + For more information, see Vertex Fog. + */ + BD3DRS_RANGEFOGENABLE = 48, + + /*! BD3DRS_STENCILENABLE + TRUE to enable stenciling, or FALSE to disable stenciling. The default value is FALSE. + For more information, see Stencil Buffer Techniques. + */ + BD3DRS_STENCILENABLE = 52, + + /*! BD3DRS_STENCILFAIL + Stencil operation to perform if the stencil test fails. Values are from the D3DSTENCILOP + enumerated type. The default value is D3DSTENCILOP_KEEP. + */ + BD3DRS_STENCILFAIL = 53, + + /*! BD3DRS_STENCILZFAIL + Stencil operation to perform if the stencil test passes and the depth test (z-test) fails. + Values are from the D3DSTENCILOP enumerated type. The default value is D3DSTENCILOP_KEEP. + */ + BD3DRS_STENCILZFAIL = 54, + + /*! BD3DRS_STENCILPASS + Stencil operation to perform if both the stencil and the depth (z) tests pass. Values are + from the D3DSTENCILOP enumerated type. The default value is D3DSTENCILOP_KEEP. + */ + BD3DRS_STENCILPASS = 55, + + /*! BD3DRS_STENCILFUNC + Comparison function for the stencil test. Values are from the D3DCMPFUNC enumerated type. + The default value is D3DCMP_ALWAYS. + The comparison function is used to compare the reference value to a stencil buffer entry. + This comparison applies only to the bits in the reference value and stencil buffer entry that + are set in the stencil mask (set by the D3DRS_STENCILMASK render state). If TRUE, the stencil + test passes. + */ + BD3DRS_STENCILFUNC = 56, + + /*! BD3DRS_STENCILREF + An int reference value for the stencil test. The default value is 0. + */ + BD3DRS_STENCILREF = 57, + + /*! BD3DRS_STENCILMASK + Mask applied to the reference value and each stencil buffer entry to determine the significant + bits for the stencil test. The default mask is 0xFFFFFFFF. + */ + BD3DRS_STENCILMASK = 58, + + /*! BD3DRS_STENCILWRITEMASK + Write mask applied to values written into the stencil buffer. The default mask is 0xFFFFFFFF. + */ + BD3DRS_STENCILWRITEMASK = 59, + + /*! BD3DRS_TEXTUREFACTOR + Color used for multiple-texture blending with the D3DTA_TFACTOR texture-blending argument or the + D3DTOP_BLENDFACTORALPHA texture-blending operation. The associated value is a D3DCOLOR variable. + The default value is opaque white (0xFFFFFFFF). + */ + BD3DRS_TEXTUREFACTOR = 60, + + /*! BD3DRS_WRAP0 + Texture-wrapping behavior for multiple sets of texture coordinates. Valid values for this + render state can be any combination of the D3DWRAPCOORD_0 (or D3DWRAP_U), D3DWRAPCOORD_1 + (or D3DWRAP_V), D3DWRAPCOORD_2 (or D3DWRAP_W), and D3DWRAPCOORD_3 flags. These cause the system + to wrap in the direction of the first, second, third, and fourth dimensions, sometimes referred + to as the s, t, r, and q directions, for a given texture. The default value for this render state + is 0 (wrapping disabled in all directions). + */ + BD3DRS_WRAP0 = 128, + BD3DRS_WRAP1 = 129, + BD3DRS_WRAP2 = 130, + BD3DRS_WRAP3 = 131, + BD3DRS_WRAP4 = 132, + BD3DRS_WRAP5 = 133, + BD3DRS_WRAP6 = 134, + BD3DRS_WRAP7 = 135, + + /*! BD3DRS_CLIPPING + TRUE to enable primitive clipping by Direct3D, or FALSE to disable it. The default value is TRUE. + */ + BD3DRS_CLIPPING = 136, + + /*! BD3DRS_LIGHTING + TRUE to enable Direct3D lighting, or FALSE to disable it. The default value is TRUE. Only + vertices that include a vertex normal are properly lit; vertices that do not contain a normal + employ a dot product of 0 in all lighting calculations. + */ + BD3DRS_LIGHTING = 137, + + /*! D3DRS_AMBIENT + Ambient light color. This value is of type D3DCOLOR. The default value is 0. + */ + BD3DRS_AMBIENT = 139, + + /*! BD3DRS_FOGVERTEXMODE + Fog formula to be used for vertex fog. Set to one member of the BD3DFOGMODE enumerated type. + The default value is D3DFOG_NONE. + */ + BD3DRS_FOGVERTEXMODE = 140, + + /*! BD3DRS_COLORVERTEX + TRUE to enable per-vertex color or FALSE to disable it. The default value is TRUE. Enabling + per-vertex color allows the system to include the color defined for individual vertices in its + lighting calculations. + For more information, see the following render states: + BD3DRS_DIFFUSEMATERIALSOURCE + BD3DRS_SPECULARMATERIALSOURCE + BD3DRS_AMBIENTMATERIALSOURCE + BD3DRS_EMISSIVEMATERIALSOURCE + */ + BD3DRS_COLORVERTEX = 141, + + /*! BD3DRS_LOCALVIEWER + TRUE to enable camera-relative specular highlights, or FALSE to use orthogonal specular + highlights. The default value is TRUE. Applications that use orthogonal projection should + specify false. + */ + BD3DRS_LOCALVIEWER = 142, + + /*! BD3DRS_NORMALIZENORMALS + TRUE to enable automatic normalization of vertex normals, or FALSE to disable it. The default + value is FALSE. Enabling this feature causes the system to normalize the vertex normals for + vertices after transforming them to camera space, which can be computationally time-consuming. + */ + BD3DRS_NORMALIZENORMALS = 143, + + /*! BD3DRS_DIFFUSEMATERIALSOURCE + Diffuse color source for lighting calculations. Valid values are members of the + D3DMATERIALCOLORSOURCE enumerated type. The default value is D3DMCS_COLOR1. The value for this + render state is used only if the D3DRS_COLORVERTEX render state is set to TRUE. + */ + BD3DRS_DIFFUSEMATERIALSOURCE = 145, + + /*! BD3DRS_SPECULARMATERIALSOURCE + Specular color source for lighting calculations. Valid values are members of the + D3DMATERIALCOLORSOURCE enumerated type. The default value is D3DMCS_COLOR2. + */ + BD3DRS_SPECULARMATERIALSOURCE = 146, + + /*! D3DRS_AMBIENTMATERIALSOURCE + Ambient color source for lighting calculations. Valid values are members of the + D3DMATERIALCOLORSOURCE enumerated type. The default value is D3DMCS_MATERIAL. + */ + BD3DRS_AMBIENTMATERIALSOURCE = 147, + + /*! D3DRS_EMISSIVEMATERIALSOURCE + Emissive color source for lighting calculations. Valid values are members of the + D3DMATERIALCOLORSOURCE enumerated type. The default value is D3DMCS_MATERIAL. + */ + BD3DRS_EMISSIVEMATERIALSOURCE = 148, + + /*! D3DRS_VERTEXBLEND + Number of matrices to use to perform geometry blending, if any. Valid values are members + of the D3DVERTEXBLENDFLAGS enumerated type. The default value is D3DVBF_DISABLE. + */ + BD3DRS_VERTEXBLEND = 151, + + /* D3DRS_CLIPPLANEENABLE + Enables or disables user-defined clipping planes. Valid values are any DWORD in which the + status of each bit (set or not set) toggles the activation state of a corresponding user-defined + clipping plane. The least significant bit (bit 0) controls the first clipping plane at index 0, + and subsequent bits control the activation of clipping planes at higher indexes. If a bit is set, + the system applies the appropriate clipping plane during scene rendering. The default value is 0. + The D3DCLIPPLANEn macros are defined to provide a convenient way to enable clipping planes. + */ + BD3DRS_CLIPPLANEENABLE = 152, + BD3DRS_POINTSIZE = 154, + BD3DRS_POINTSIZE_MIN = 155, + BD3DRS_POINTSPRITEENABLE = 156, + BD3DRS_POINTSCALEENABLE = 157, + BD3DRS_POINTSCALE_A = 158, + BD3DRS_POINTSCALE_B = 159, + BD3DRS_POINTSCALE_C = 160, + BD3DRS_MULTISAMPLEANTIALIAS = 161, + BD3DRS_MULTISAMPLEMASK = 162, + BD3DRS_PATCHEDGESTYLE = 163, + BD3DRS_DEBUGMONITORTOKEN = 165, + BD3DRS_POINTSIZE_MAX = 166, + BD3DRS_INDEXEDVERTEXBLENDENABLE = 167, + BD3DRS_COLORWRITEENABLE = 168, + BD3DRS_TWEENFACTOR = 170, + BD3DRS_BLENDOP = 171, + BD3DRS_POSITIONDEGREE = 172, + BD3DRS_NORMALDEGREE = 173, + BD3DRS_SCISSORTESTENABLE = 174, + BD3DRS_SLOPESCALEDEPTHBIAS = 175, + BD3DRS_ANTIALIASEDLINEENABLE = 176, + BD3DRS_MINTESSELLATIONLEVEL = 178, + BD3DRS_MAXTESSELLATIONLEVEL = 179, + BD3DRS_ADAPTIVETESS_X = 180, + BD3DRS_ADAPTIVETESS_Y = 181, + BD3DRS_ADAPTIVETESS_Z = 182, + BD3DRS_ADAPTIVETESS_W = 183, + BD3DRS_ENABLEADAPTIVETESSELLATION = 184, + BD3DRS_TWOSIDEDSTENCILMODE = 185, + BD3DRS_CCW_STENCILFAIL = 186, + BD3DRS_CCW_STENCILZFAIL = 187, + BD3DRS_CCW_STENCILPASS = 188, + BD3DRS_CCW_STENCILFUNC = 189, + BD3DRS_COLORWRITEENABLE1 = 190, + BD3DRS_COLORWRITEENABLE2 = 191, + BD3DRS_COLORWRITEENABLE3 = 192, + BD3DRS_BLENDFACTOR = 193, + BD3DRS_SRGBWRITEENABLE = 194, + BD3DRS_DEPTHBIAS = 195, + BD3DRS_WRAP8 = 198, + BD3DRS_WRAP9 = 199, + BD3DRS_WRAP10 = 200, + BD3DRS_WRAP11 = 201, + BD3DRS_WRAP12 = 202, + BD3DRS_WRAP13 = 203, + BD3DRS_WRAP14 = 204, + BD3DRS_WRAP15 = 205, + BD3DRS_SEPARATEALPHABLENDENABLE = 206, + BD3DRS_SRCBLENDALPHA = 207, + BD3DRS_DESTBLENDALPHA = 208, + BD3DRS_BLENDOPALPHA = 209, + + BD3DRS_MAX_TYPE + }; + + + + /*! Defines constants that describe depth-buffer formats + Members of this enumerated type are used with the D3DRS_ZENABLE render state. + */ + enum BD3DZBUFFERTYPE + { + BD3DZB_FALSE = 0, // Disable depth buffering + BD3DZB_TRUE = 1, // Enable z-buffering + BD3DZB_USEW = 2 //Enable w-buffering. + }; + + //! Defines the supported compare functions. + enum BD3DCMPFUNC + { + BD3DCMP_NEVER = 1,// Always fail the test. + BD3DCMP_LESS, // Accept the new pixel if its value is less than the value of the current pixel. + BD3DCMP_EQUAL, // Accept the new pixel if its value equals the value of the current pixel. + BD3DCMP_LESSEQUAL, // Accept the new pixel if its value is less than or equal to the value of the current pixel. + BD3DCMP_GREATER, // Accept the new pixel if its value is greater than the value of the current pixel. + BD3DCMP_NOTEQUAL, // Accept the new pixel if its value does not equal the value of the current pixel. + BD3DCMP_GREATEREQUAL,// Accept the new pixel if its value is greater than or equal to the value of the current pixel. + BD3DCMP_ALWAYS // Always pass the test. + }; + + enum BD3DMATERIALCOLORSOURCE + { + BD3DMCS_MATERIAL = 0, // Use the color from the current material. + BD3DMCS_COLOR1 = 1, // Use the diffuse vertex color. + BD3DMCS_COLOR2 = 2 // Use the specular vertex color. + }; + + + //! Defines constants that describe the supported shading modes. + enum BD3DSHADEMODE + { + /*! BD3DSHADE_FLAT + Flat shading mode. The color and specular component of the first vertex in the triangle + are used to determine the color and specular component of the face. These colors remain + constant across the triangle; that is, they are not interpolated. The specular alpha is + interpolated. + */ + BD3DSHADE_FLAT = 1, + + /*! BD3DSHADE_GOURAUD + Gouraud shading mode. The color and specular components of the face are determined by a + linear interpolation between all three of the triangle's vertices. + */ + BD3DSHADE_GOURAUD = 2, + + /*! BD3DSHADE_PHONG + Not supported. + */ + BD3DSHADE_PHONG = 3 + }; + + /*! Defines constants describing the fill mode + The values in this enumerated type are used by the BD3DRS_FILLMODE render state + */ + enum BD3DFILLMODE + { + BD3DFILL_POINT = 1, // Fill points. + BD3DFILL_WIREFRAME = 2, // Fill wireframes. + BD3DFILL_SOLID = 3 // Fill solids. + }; + + + + /*! Defines the supported culling modes. + The values in this enumerated type are used by the B3DRS_CULLMODE render state. + The culling modes define how back faces are culled when rendering a geometry. + */ + enum BD3DCULL + { + BD3DCULL_NONE = 1, // Do not cull back faces. + BD3DCULL_CW = 2, // Cull back faces with clockwise vertices. + BD3DCULL_CCW = 3 // Cull back faces with counterclockwise vertices. + }; + + struct SShaderParam + { + u32 ColorUnits; + u32 TextureUnits; + + u32 RenderState [ BD3DRS_MAX_TYPE ]; + void SetRenderState ( BD3DRENDERSTATETYPE state, u32 value ); + }; + + void SShaderParam::SetRenderState ( BD3DRENDERSTATETYPE state, u32 value ) + { + RenderState [ state ] = value; + } + + + +class CBurningShader_Raster_Reference : public IBurningShader +{ +public: + + //! constructor + CBurningShader_Raster_Reference(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + + virtual void setMaterial ( const SBurningShaderMaterial &material ) _IRR_OVERRIDE_; + + +private: + void scanline (); + void scanline2 (); + + sScanLineData line; + sPixelShaderData pShader; + + void pShader_1 (); + void pShader_EMT_LIGHTMAP_M4 (); + + SShaderParam ShaderParam; + + REALINLINE u32 depthFunc (); + REALINLINE void depthWrite (); + + +}; + +//! constructor +CBurningShader_Raster_Reference::CBurningShader_Raster_Reference(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CBurningShader_Raster_Reference"); + #endif +} + + +/*! +*/ +void CBurningShader_Raster_Reference::pShader_EMT_LIGHTMAP_M4 () +{ + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; + + f32 inversew = fix_inverse32 ( line.w[0] ); + + getSample_texture ( r0, g0, b0, &IT[0], tofix ( line.t[0][0].x,inversew), tofix ( line.t[0][0].y,inversew) ); + getSample_texture ( r1, g1, b1, &IT[1], tofix ( line.t[1][0].x,inversew), tofix ( line.t[1][0].y,inversew) ); + + + pShader.dst[pShader.i] = fix_to_color ( clampfix_maxcolor ( imulFix_tex2 ( r0, r1 ) ), + clampfix_maxcolor ( imulFix_tex2 ( g0, g1 ) ), + clampfix_maxcolor ( imulFix_tex2 ( b0, b1 ) ) + ); + +} + +/*! +*/ +void CBurningShader_Raster_Reference::pShader_1 () +{ + tFixPoint r0, g0, b0; + tFixPoint tx0, ty0; + + const f32 inversew = fix_inverse32 ( line.w[0] ); + + tx0 = tofix ( line.t[0][0].x, inversew ); + ty0 = tofix ( line.t[0][0].y, inversew ); + + getSample_texture ( r0, g0, b0, &IT[0], tx0, ty0 ); + pShader.dst[pShader.i] = fix_to_color ( r0, g0, b0 ); + +} + + +/*! +*/ +void CBurningShader_Raster_Reference::setMaterial ( const SBurningShaderMaterial &material ) +{ + const video::SMaterial &m = material.org; + + u32 i; + u32 enable; + + ShaderParam.ColorUnits = 0; + ShaderParam.TextureUnits = 0; + for ( i = 0; i != BURNING_MATERIAL_MAX_TEXTURES; ++i ) + { + if ( m.getTexture( i ) ) + ShaderParam.TextureUnits = i; + } + + // shademode + ShaderParam.SetRenderState( BD3DRS_SHADEMODE, + m.GouraudShading ? BD3DSHADE_GOURAUD : BD3DSHADE_FLAT + ); + + // fillmode + ShaderParam.SetRenderState( BD3DRS_FILLMODE, + m.Wireframe ? BD3DFILL_WIREFRAME : m.PointCloud ? BD3DFILL_POINT : BD3DFILL_SOLID + ); + + // back face culling + ShaderParam.SetRenderState( BD3DRS_CULLMODE, + m.BackfaceCulling ? BD3DCULL_CCW : BD3DCULL_NONE + ); + + // lighting + ShaderParam.SetRenderState( BD3DRS_LIGHTING, m.Lighting ); + + // specular highlights + enable = F32_LOWER_EQUAL_0 ( m.Shininess ); + ShaderParam.SetRenderState( BD3DRS_SPECULARENABLE, enable); + ShaderParam.SetRenderState( BD3DRS_NORMALIZENORMALS, enable); + ShaderParam.SetRenderState( BD3DRS_SPECULARMATERIALSOURCE, (m.ColorMaterial==ECM_SPECULAR)?BD3DMCS_COLOR1:BD3DMCS_MATERIAL); + + // depth buffer enable and compare + ShaderParam.SetRenderState( BD3DRS_ZENABLE, (material.org.ZBuffer==video::ECFN_DISABLED) ? 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 != video::EZW_OFF ); +} + +/*! +*/ +REALINLINE u32 CBurningShader_Raster_Reference::depthFunc () +{ + if ( ShaderParam.RenderState [ BD3DRS_ZENABLE ] ) + { + switch ( ShaderParam.RenderState [ BD3DRS_ZFUNC ] ) + { + case BD3DCMP_LESSEQUAL: + return line.w[0] >= pShader.z[ pShader.i]; + case BD3DCMP_EQUAL: + return line.w[0] == pShader.z[ pShader.i]; + } + } + return 1; +} + +/*! +*/ +REALINLINE void CBurningShader_Raster_Reference::depthWrite () +{ + if ( ShaderParam.RenderState [ BD3DRS_ZWRITEENABLE ] ) + { + pShader.z[pShader.i] = line.w[0]; + } +} + +/*! +*/ +REALINLINE void CBurningShader_Raster_Reference::scanline2() +{ + // apply top-left fill-convention, left + pShader.xStart = core::ceil32_fast( line.x[0] ); + pShader.xEnd = core::ceil32_fast( line.x[1] ) - 1; + + pShader.dx = pShader.xEnd - pShader.xStart; + if ( pShader.dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal ( line.x[1] - line.x[0] ); + const f32 subPixel = ( (f32) pShader.xStart ) - line.x[0]; + + // store slopes in endpoint, and correct first pixel + + line.w[0] += (line.w[1] = (line.w[1] - line.w[0]) * invDeltaX) * subPixel; + + u32 i; + +#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + for ( i = 0; i != ShaderParam.ColorUnits; ++i ) + { + line.c[i][1] = (line.c[i][1] - line.c[i][0]) * invDeltaX; + line.c[i][0] += line.c[i][1] * subPixel; + } +#endif + + for ( i = 0; i != ShaderParam.TextureUnits; ++i ) + { + line.t[i][1] = (line.t[i][1] - line.t[i][0]) * invDeltaX; + line.t[i][0] += line.t[i][1] * subPixel; + } + + pShader.dst = (tVideoSample*) ( (u8*) RenderTarget->getData() + ( line.y * RenderTarget->getPitch() ) + ( pShader.xStart << VIDEO_SAMPLE_GRANULARITY ) ); + pShader.z = (fp24*) ( (u8*) DepthBuffer->lock() + ( line.y * DepthBuffer->getPitch() ) + ( pShader.xStart << VIDEO_SAMPLE_GRANULARITY ) ); + + for ( pShader.i = 0; pShader.i <= pShader.dx; ++pShader.i ) + { + if ( depthFunc() ) + { + depthWrite (); + } + + // advance next pixel + line.w[0] += line.w[1]; + +#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + for ( i = 0; i != ShaderParam.ColorUnits; ++i ) + { + line.c[i][0] += line.c[i][1]; + } +#endif + for ( i = 0; i != ShaderParam.TextureUnits; ++i ) + { + line.t[i][0] += line.t[i][1]; + } + } +} + + +/*! +*/ +REALINLINE void CBurningShader_Raster_Reference::scanline () +{ + u32 i; + + // apply top-left fill-convention, left + pShader.xStart = core::ceil32_fast( line.x[0] ); + pShader.xEnd = core::ceil32_fast( line.x[1] ) - 1; + + pShader.dx = pShader.xEnd - pShader.xStart; + if ( pShader.dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal ( line.x[1] - line.x[0] ); + + // search z-buffer for first not occulled pixel + pShader.z = (fp24*) ( (u8*) DepthBuffer->lock() + ( line.y * DepthBuffer->getPitch() ) + ( pShader.xStart << VIDEO_SAMPLE_GRANULARITY ) ); + + // subTexel + const f32 subPixel = ( (f32) pShader.xStart ) - line.x[0]; + + const f32 b = (line.w[1] - line.w[0]) * invDeltaX; + f32 a = line.w[0] + ( b * subPixel ); + + pShader.i = 0; + + if ( ShaderParam.RenderState [ BD3DRS_ZENABLE ] ) + { + u32 condition; + switch ( ShaderParam.RenderState [ BD3DRS_ZFUNC ] ) + { + case BD3DCMP_LESSEQUAL: + condition = a < pShader.z[pShader.i]; + break; + case BD3DCMP_EQUAL: + condition = a != pShader.z[pShader.i]; + break; + } + while ( a < pShader.z[pShader.i] ) + { + a += b; + + pShader.i += 1; + if ( pShader.i > pShader.dx ) + return; + } + } + + // lazy setup rest of scanline + + line.w[0] = a; + line.w[1] = b; + + pShader.dst = (tVideoSample*) ( (u8*) RenderTarget->getData() + ( line.y * RenderTarget->getPitch() ) + ( pShader.xStart << VIDEO_SAMPLE_GRANULARITY ) ); + + a = (f32) pShader.i + subPixel; + +#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + for ( i = 0; i != ShaderParam.ColorUnits; ++i ) + { + line.c[i][1] = (line.c[i][1] - line.c[i][0]) * invDeltaX; + line.c[i][0] += line.c[i][1] * a; + } +#endif + + for ( i = 0; i != ShaderParam.TextureUnits; ++i ) + { + line.t[i][1] = (line.t[i][1] - line.t[i][0]) * invDeltaX; + line.t[i][0] += line.t[i][1] * a; + } + + for ( ; pShader.i <= pShader.dx; ++pShader.i ) + { + if ( line.w[0] >= pShader.z[pShader.i] ) + { + pShader.z[pShader.i] = line.w[0]; + + pShader_EMT_LIGHTMAP_M4 (); + } + + line.w[0] += line.w[1]; + +#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + for ( i = 0; i != ShaderParam.ColorUnits; ++i ) + { + line.c[i][0] += line.c[i][1]; + } +#endif + for ( i = 0; i != ShaderParam.TextureUnits; ++i ) + { + line.t[i][0] += line.t[i][1]; + } + } + +} + + +void CBurningShader_Raster_Reference::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + sScanConvertData scan; + u32 i; + + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal ( c->Pos.y - a->Pos.y ); + scan.invDeltaY[1] = core::reciprocal ( b->Pos.y - a->Pos.y ); + scan.invDeltaY[2] = core::reciprocal ( c->Pos.y - b->Pos.y ); + + if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) ) + return; + + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = a->Pos.y - c->Pos.y; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = b->Pos.y - a->Pos.y; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > (f32) 0.0 ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; + +#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + for ( i = 0; i != ShaderParam.ColorUnits; ++i ) + { + scan.c[i][0] = a->Color[i]; + scan.slopeC[i][0] = (c->Color[i] - a->Color[i]) * scan.invDeltaY[0]; + } +#endif + + for ( i = 0; i != ShaderParam.TextureUnits; ++i ) + { + scan.t[i][0] = a->Tex[i]; + scan.slopeT[i][0] = (c->Tex[i] - a->Tex[i]) * scan.invDeltaY[0]; + } + + // top left fill convention y run + s32 yStart; + s32 yEnd; + + f32 subPixel; + + // rasterize upper sub-triangle + if ( F32_GREATER_0 ( scan.invDeltaY[1] ) ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; + +#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + for ( i = 0; i != ShaderParam.ColorUnits; ++i ) + { + scan.c[i][1] = a->Color[i]; + scan.slopeC[i][1] = (b->Color[i] - a->Color[i]) * scan.invDeltaY[1]; + } +#endif + for ( i = 0; i != ShaderParam.TextureUnits; ++i ) + { + scan.t[i][1] = a->Tex[i]; + scan.slopeT[i][1] = (b->Tex[i] - a->Tex[i]) * scan.invDeltaY[1]; + } + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; + + for ( i = 0; i != ShaderParam.ColorUnits; ++i ) + { + scan.c[i][0] += scan.slopeC[i][0] * subPixel; + scan.c[i][1] += scan.slopeC[i][1] * subPixel; + } + + for ( i = 0; i != ShaderParam.TextureUnits; ++i ) + { + scan.t[i][0] += scan.slopeT[i][0] * subPixel; + scan.t[i][1] += scan.slopeT[i][1] * subPixel; + } + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.w[scan.left] = scan.w[0]; + + line.x[scan.right] = scan.x[1]; + line.w[scan.right] = scan.w[1]; + +#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + for ( i = 0; i != ShaderParam.ColorUnits; ++i ) + { + line.c[i][scan.left] = scan.c[i][0]; + line.c[i][scan.right] = scan.c[i][1]; + } +#endif + for ( i = 0; i != ShaderParam.TextureUnits; ++i ) + { + line.t[i][scan.left] = scan.t[i][0]; + line.t[i][scan.right] = scan.t[i][1]; + } + + // render a scanline + scanline (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; + + for ( i = 0; i != ShaderParam.ColorUnits; ++i ) + { + scan.c[i][0] += scan.slopeC[i][0]; + scan.c[i][1] += scan.slopeC[i][1]; + } + + for ( i = 0; i != ShaderParam.TextureUnits; ++i ) + { + scan.t[i][0] += scan.slopeT[i][0]; + scan.t[i][1] += scan.slopeT[i][1]; + } + + } + } + + // rasterize lower sub-triangle + if ( F32_GREATER_0 ( scan.invDeltaY[2] ) ) + { + // advance to middle point + if ( F32_GREATER_0 ( scan.invDeltaY[1] ) ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; + +#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + for ( i = 0; i != ShaderParam.ColorUnits; ++i ) + { + scan.c[i][0] = a->Color[i] + scan.slopeC[i][0] * temp[0]; + } +#endif + for ( i = 0; i != ShaderParam.TextureUnits; ++i ) + { + scan.t[i][0] = a->Tex[i] + scan.slopeT[i][0] * temp[0]; + } + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; + +#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + for ( i = 0; i != ShaderParam.ColorUnits; ++i ) + { + scan.c[i][1] = b->Color[i]; + scan.slopeC[i][1] = (c->Color[i] - b->Color[i]) * scan.invDeltaY[2]; + } +#endif + for ( i = 0; i != ShaderParam.TextureUnits; ++i ) + { + scan.t[i][1] = b->Tex[i]; + scan.slopeT[i][1] = (c->Tex[i] - b->Tex[i]) * scan.invDeltaY[2]; + } + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; + + for ( i = 0; i != ShaderParam.ColorUnits; ++i ) + { + scan.c[i][0] += scan.slopeC[i][0] * subPixel; + scan.c[i][1] += scan.slopeC[i][1] * subPixel; + } + + for ( i = 0; i != ShaderParam.TextureUnits; ++i ) + { + scan.t[i][0] += scan.slopeT[i][0] * subPixel; + scan.t[i][1] += scan.slopeT[i][1] * subPixel; + } + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.w[scan.left] = scan.w[0]; + + line.x[scan.right] = scan.x[1]; + line.w[scan.right] = scan.w[1]; + +#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + for ( i = 0; i != ShaderParam.ColorUnits; ++i ) + { + line.c[i][scan.left] = scan.c[i][0]; + line.c[i][scan.right] = scan.c[i][1]; + } +#endif + for ( i = 0; i != ShaderParam.TextureUnits; ++i ) + { + line.t[i][scan.left] = scan.t[i][0]; + line.t[i][scan.right] = scan.t[i][1]; + } + + // render a scanline + scanline (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; + + for ( i = 0; i != ShaderParam.TextureUnits; ++i ) + { + scan.c[i][0] += scan.slopeC[i][0]; + scan.c[i][1] += scan.slopeC[i][1]; + } + + for ( i = 0; i != ShaderParam.TextureUnits; ++i ) + { + scan.t[i][0] += scan.slopeT[i][0]; + scan.t[i][1] += scan.slopeT[i][1]; + } + } + } +} + + +} // end namespace video +} // end namespace irr + + +namespace irr +{ +namespace video +{ + + + +//! creates a flat triangle renderer +IBurningShader* createTriangleRendererReference(CBurningVideoDriver* driver) +{ + return new CBurningShader_Raster_Reference(driver); +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + + diff --git a/source/Irrlicht/CCSMLoader.cpp b/source/Irrlicht/CCSMLoader.cpp new file mode 100644 index 00000000..d560311c --- /dev/null +++ b/source/Irrlicht/CCSMLoader.cpp @@ -0,0 +1,859 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_CSM_LOADER_ + +#include "CCSMLoader.h" +#include "CMeshTextureLoader.h" +#include "os.h" +#include "IFileSystem.h" +#include "IReadFile.h" +#include "ISceneManager.h" +#include "IAttributes.h" +#include "SMesh.h" +#include "IVideoDriver.h" +#include "SAnimatedMesh.h" +#include "SMeshBufferLightMap.h" + +#ifdef _DEBUG +#define _IRR_DEBUG_CSM_LOADER_ +#endif + +namespace irr +{ +namespace scene +{ + // + // the CSM data types + // + struct color_rgb_t + { + s32 red; + s32 green; + s32 blue; + + color_rgb_t() : red(0), green(0), blue(0) {} + void clear() { red=0; green=0; blue=0; } + video::SColor toSColor() const { return video::SColor(255, red, green, blue); } + }; + + + // + // A Binary File Reader + // + struct BinaryFileReader + { + BinaryFileReader(io::IReadFile* pFile) : file(pFile) { } + + size_t readBuffer(void* buffer, s32 len) + { + return file->read(buffer,len); + } + + s32 readLong(); + f32 readFloat(); + + void readString(core::stringc &str); + void readVec3f(core::vector3df* v); + void readVec2f(core::vector2df* v); + void readColorRGB(color_rgb_t* color); + + io::IReadFile *file; + }; + + // + // The file header + // + class Header + { + public: + + enum E_CSM_VERSION + { + VERSION_4 = 4, + VERSION_4_1 = 5 + }; + + Header(){ clear(); } + + s32 getVersion() const { return version; } + void clear(){ version = 0; } + void load(BinaryFileReader* pReader) + { + version = pReader->readLong(); + } + + private: + + s32 version; + }; + + + // + // The groups + // + class Group + { + public: + + Group(){ clear(); } + ~Group(){ clear(); } + + void clear(); + void load(BinaryFileReader* pReader); + + s32 getFlags() const { return flags; } + s32 getParentGroupID() const { return parentGroup; } + const core::stringc& getProperties() const { return props; } + video::SColor getColor() const { return color.toSColor(); } + + private: + + s32 flags; + s32 parentGroup; + core::stringc props; + color_rgb_t color; + }; + + + // + // The visgroups + // + class VisGroup + { + public: + + VisGroup(){ clear(); } + ~VisGroup(){ clear(); } + void clear(); + void load(BinaryFileReader* pReader); + + s32 getFlags() const{ return flags; } + const core::stringc& getName() const{ return name; } + video::SColor getColor() const{ return color.toSColor(); } + + private: + + core::stringc name; + s32 flags; + color_rgb_t color; + }; + + + // + // Lightmaps + // + class LightMap + { + public: + + LightMap() : pixelData(0){ clear(); } + ~LightMap(){ clear(); } + void clear(); + void load(BinaryFileReader* pReader); + s32 getWidth() const{ return width; } + s32 getHeight() const{ return height; } + s32* getPixelData() const{ return pixelData; } + + private: + + s32 width; + s32 height; + s32* pixelData; + }; + + struct Triangle + { + s32 a,b,c; + }; + + + struct Line + { + s32 a,b; + }; + + + class Vertex + { + public: + + Vertex(){ clear(); } + ~Vertex(){ clear(); } + void clear(); + void load(BinaryFileReader* pReader); + + const core::vector3df& getPosition() const { return position; } + const core::vector3df& getNormal() const { return normal; } + video::SColor getColor() const { return color.toSColor(); } + const core::vector3df& getTextureCoordinates() const { return texCoords; } + const core::vector3df& getLightMapCoordinates() const { return lmapCoords; } + + private: + + core::vector3df position; + core::vector3df normal; + color_rgb_t color; + core::vector3df texCoords; + core::vector3df lmapCoords; + }; + + + class Surface + { + public: + + Surface() { clear(); } + ~Surface(){ clear(); } + + void clear(); + void load(BinaryFileReader *pReader); + + s32 getFlags() const{ return flags; } + const core::stringc& getTextureName() const{ return textureName; } + s32 getLightMapId() const{ return lightMapId; } + const core::vector2df* getUVOffset() const{ return &uvOffset; } + const core::vector2df* getUVScale() const{ return &uvScale; } + f32 getUVRotation() const{ return uvRotation; } + + u32 getVertexCount() const{ return vertices.size(); } + const Vertex& getVertexAt(const s32 index) const{ return vertices[index]; } + + u32 getTriangleCount() const{ return triangles.size(); } + const Triangle& getTriangleAt(const s32 index) const{ return triangles[index]; } + + private: + + s32 flags; + core::stringc textureName; + s32 lightMapId; + core::vector2df uvOffset; + core::vector2df uvScale; + f32 uvRotation; + core::array vertices; + core::array triangles; + core::array lines; + }; + + class Mesh + { + public: + + Mesh(){ clear(); } + ~Mesh(){ clear(); } + + void clear(); + void load(BinaryFileReader* pReader, bool bReadVisGroups); + + s32 getFlags() const { return flags; } + s32 getGroupID() const { return groupId; } + const core::stringc& getProperties() const { return props; } + video::SColor getColor() const { return color.toSColor(); } + const core::vector3df* getPosition() const { return &position; } + s32 getVisgroupID() const { return visgroupId; } + s32 getSurfaceCount() const { return surfaces.size(); } + const Surface* getSurfaceAt(const s32 index) const { return surfaces[index]; } + + private: + + s32 flags; + s32 groupId; + core::stringc props; + color_rgb_t color; + core::vector3df position; + s32 visgroupId; + + core::array surfaces; + }; + + class Entity + { + public: + + Entity() { clear(); } + ~Entity() { clear(); } + + void clear(); + void load(BinaryFileReader* pReader); + s32 getVisgroupID() const { return visgroupId; } + s32 getGroupID() const { return groupId; } + const core::stringc& getProperties() const { return props; } + const core::vector3df* getPosition() const { return &position; } + + private: + + s32 visgroupId; + s32 groupId; + core::stringc props; + core::vector3df position; + }; + + + class CameraData + { + public: + + CameraData(){ clear(); } + ~CameraData(){ clear(); } + + void clear(); + void load(BinaryFileReader* pReader); + + const core::vector3df* getPosition(){ return &position; } + f32 getPitch(){ return pitch; } + f32 getYaw(){ return yaw; } + + private: + + core::vector3df position; + f32 pitch; + f32 yaw; + }; + + // + // A CSM File + // + class CSMFile + { + public: + + CSMFile(){ clear(); } + ~CSMFile(){ clear(); } + void clear(); + void load(BinaryFileReader* pReader); + + const Header* getHeader() const{ return &header; } + + u32 getGroupCount() const{ return groups.size(); } + const Group* getGroupAt(const s32 index) const{ return groups[index]; } + + u32 getVisGroupCount() const{ return visgroups.size(); } + const VisGroup* getVisGroupAt(const s32 index) const{ return visgroups[index]; } + + u32 getLightMapCount() const{ return lightmaps.size(); } + const LightMap* getLightMapAt(const s32 index) const { return lightmaps[index]; } + + u32 getMeshCount() const{ return meshes.size(); } + const Mesh* getMeshAt(const s32 index) const{ return meshes[index]; } + + u32 getEntityCount() const{ return entities.size(); } + const Entity* getEntityAt(const s32 index) const{ return entities[index]; } + + const CameraData* getCameraData() const{ return &cameraData; } + + private: + + Header header; + core::array groups; + core::array visgroups; + core::array lightmaps; + core::array meshes; + core::array entities; + CameraData cameraData; + }; + + CCSMLoader::CCSMLoader(scene::ISceneManager* manager, io::IFileSystem* fs) + : FileSystem(fs), SceneManager(manager) + { + #ifdef _DEBUG + setDebugName("CCSMLoader"); + #endif + + TextureLoader = new CMeshTextureLoader( FileSystem, SceneManager->getVideoDriver() ); + } + + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".bsp") + bool CCSMLoader::isALoadableFileExtension(const io::path& filename) const + { + return core::hasFileExtension ( filename, "csm" ); + } + + + //! creates/loads an animated mesh from the file. + IAnimatedMesh* CCSMLoader::createMesh(io::IReadFile* file) + { + if ( getMeshTextureLoader() ) + getMeshTextureLoader()->setMeshFile(file); + + scene::IMesh* m = createCSMMesh(file); + + if (!m) + return 0; + + SAnimatedMesh* am = new SAnimatedMesh(); + am->Type = EAMT_CSM; + am->addMesh(m); + m->drop(); + + am->recalculateBoundingBox(); + return am; + } + + scene::IMesh* CCSMLoader::createCSMMesh(io::IReadFile* file) + { + if (!file) + return 0; + + BinaryFileReader reader(file); + CSMFile csmFile; + csmFile.load(&reader); + + return createIrrlichtMesh(&csmFile, file->getFileName()); + } + + + scene::IMesh* CCSMLoader::createIrrlichtMesh(const CSMFile* csmFile, const io::path& lmprefix) + { + if ( getMeshTextureLoader() ) + { + if ( SceneManager->getParameters()->existsAttribute(CSM_TEXTURE_PATH) ) + getMeshTextureLoader()->setTexturePath( SceneManager->getParameters()->getAttributeAsString(CSM_TEXTURE_PATH) ); + } + + scene::SMesh *pMesh = new scene::SMesh(); + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + + for(u32 l = 0; lgetLightMapCount(); l++) + { + const LightMap* lmap = csmFile->getLightMapAt(l); + + io::path lmapName = lmprefix; + lmapName += "LMAP_"; + lmapName += io::path(l+1); + os::Printer::log("CCSMLoader loading light map", lmapName.c_str()); + + video::IImage* lmapImg = driver->createImageFromData( + video::ECF_A8R8G8B8, + core::dimension2d(lmap->getWidth(),lmap->getHeight()), + lmap->getPixelData()); + + driver->addTexture(lmapName.c_str(), lmapImg); + lmapImg->drop(); + } + + for(u32 m = 0; mgetMeshCount(); m++) + { + const Mesh* mshPtr = csmFile->getMeshAt(m); + + for(s32 s = 0; s < mshPtr->getSurfaceCount(); s++) + { + const Surface* surface = mshPtr->getSurfaceAt(s); + + video::ITexture* texture = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture(surface->getTextureName()) : NULL; + + // same lightmap name as above where they are created + io::path lmapName = lmprefix; + lmapName += "LMAP_"; + lmapName += io::path(surface->getLightMapId()); + + scene::SMeshBufferLightMap *buffer = new scene::SMeshBufferLightMap(); + buffer->Material.setTexture(0, texture); + if (surface->getLightMapId()) + { + buffer->Material.setTexture(1, driver->getTexture(lmapName)); + buffer->Material.Lighting = false; + buffer->Material.MaterialType = video::EMT_LIGHTMAP_ADD; + } + + buffer->Vertices.reallocate(surface->getVertexCount()); + for(u32 v = 0; v < surface->getVertexCount(); ++v) + { + const Vertex& vtxPtr = surface->getVertexAt(v); + video::S3DVertex2TCoords vtx; + vtx.Pos = vtxPtr.getPosition(); + vtx.Normal = vtxPtr.getPosition(); + vtx.Color=vtxPtr.getColor(); + vtx.TCoords.set(vtxPtr.getTextureCoordinates().X, 1.f-vtxPtr.getTextureCoordinates().Y); + vtx.TCoords2.set(vtxPtr.getLightMapCoordinates().X, 1.f-vtxPtr.getLightMapCoordinates().Y); + + buffer->Vertices.push_back(vtx); + } + + buffer->Indices.reallocate(surface->getTriangleCount()*3); + for(u32 t = 0; t < surface->getTriangleCount(); ++t) + { + const Triangle& tri = surface->getTriangleAt(t); + buffer->Indices.push_back(tri.c); + buffer->Indices.push_back(tri.b); + buffer->Indices.push_back(tri.a); + } + + buffer->recalculateBoundingBox(); + pMesh->addMeshBuffer(buffer); + buffer->drop(); + } + } + + pMesh->recalculateBoundingBox(); + return pMesh; + } + + void Group::clear() + { + color.clear(); + flags = 0; + parentGroup = 0; + props = ""; + } + + void Group::load(BinaryFileReader* pReader) + { + flags = pReader->readLong(); + parentGroup = pReader->readLong(); + pReader->readString(props); + pReader->readColorRGB(&color); + } + + void VisGroup::clear() + { + color.clear(); + flags = 0; + name = ""; + } + + void VisGroup::load(BinaryFileReader* pReader) + { + pReader->readString(name); + flags = pReader->readLong(); + pReader->readColorRGB(&color); + } + + void LightMap::clear() + { + delete[] pixelData; + pixelData = 0; + width = height = 0; + } + + void LightMap::load(BinaryFileReader* pReader) + { + width = pReader->readLong(); + height = pReader->readLong(); + pixelData = new s32[width * height]; + pReader->readBuffer(pixelData, width * height * sizeof(s32)); + } + + void Mesh::clear() + { + flags = 0; + groupId = 0; + visgroupId = 0; + props = ""; + color.clear(); + position.set(0,0,0); + + for(u32 s = 0; s < surfaces.size(); s++) + { + delete surfaces[s]; + } + surfaces.clear(); + } + + void Mesh::load(BinaryFileReader* pReader, bool bReadVisGroups) + { + flags = pReader->readLong(); + groupId = pReader->readLong(); + pReader->readString(props); + pReader->readColorRGB(&color); + pReader->readVec3f(&position); + if(bReadVisGroups) + visgroupId = pReader->readLong(); + else + visgroupId = 0; + + s32 count = pReader->readLong(); + + for(s32 i = 0; i < count; i++) + { + Surface* surf = new Surface(); + surf->load(pReader); + surfaces.push_back(surf); + } + } + + void Surface::clear() + { + flags = 0; + lightMapId = 0; + textureName = ""; + uvOffset.set(0.0f,0.0f); + uvScale.set(0.0f,0.0f); + uvRotation = 0.0f; + triangles.clear(); + lines.clear(); + vertices.clear(); + } + + void Surface::load(BinaryFileReader* pReader) + { + flags = pReader->readLong(); + pReader->readString(textureName); + textureName.replace('\\', '/'); + + lightMapId = pReader->readLong(); + pReader->readVec2f(&uvOffset); + pReader->readVec2f(&uvScale); + uvRotation = pReader->readFloat(); + s32 vtxCount = pReader->readLong(); + s32 triCount = pReader->readLong(); + s32 lineCount = pReader->readLong(); + + for(s32 v = 0; v < vtxCount; v++) + { + vertices.push_back(Vertex()); + vertices.getLast().load(pReader); + } + + for(s32 t = 0; t < triCount; t++) + { + Triangle tri; + pReader->readBuffer(&tri, sizeof(tri)); + triangles.push_back(tri); + } + + for(s32 l = 0; l < lineCount; l++) + { + Line line; + pReader->readBuffer(&line,sizeof(line)); + lines.push_back(line); + + } + + } + + void Vertex::clear() + { + position.set(0,0,0); + normal.set(0,0,0); + color.clear(); + texCoords.set(0,0,0); + lmapCoords.set(0,0,0); + } + + void Vertex::load(BinaryFileReader* pReader) + { + pReader->readVec3f(&position); + pReader->readVec3f(&normal); + pReader->readColorRGB(&color); + pReader->readVec3f(&texCoords); + pReader->readVec3f(&lmapCoords); + } + + void Entity::clear() + { + visgroupId = groupId = 0; + props = ""; + position.set(0,0,0); + } + + void Entity::load(BinaryFileReader* pReader) + { + visgroupId = pReader->readLong(); + groupId = pReader->readLong(); + pReader->readString(props); + pReader->readVec3f(&position); + } + + void CameraData::clear() + { + position.set(0,0,0); + pitch = 0; + yaw = 0; + } + + void CameraData::load(BinaryFileReader* pReader) + { + pReader->readVec3f(&position); + pitch = pReader->readFloat(); + yaw = pReader->readFloat(); + } + + void CSMFile::clear() + { + header.clear(); + cameraData.clear(); + + u32 x =0; + for( x= 0; x < groups.size(); x++) + delete groups[x]; + + groups.clear(); + + for(x= 0; x < visgroups.size(); x++) + delete visgroups[x]; + + visgroups.clear(); + + for(x= 0; x < lightmaps.size(); x++) + delete lightmaps[x]; + + lightmaps.clear(); + + for(x= 0; x < meshes.size(); x++) + delete meshes[x]; + + meshes.clear(); + + for(x= 0; x < entities.size(); x++) + delete entities[x]; + + entities.clear(); + } + + void CSMFile::load(BinaryFileReader* pReader) + { + clear(); + + header.load(pReader); + + //groups + { + const s32 count = pReader->readLong(); +#ifdef _IRR_DEBUG_CSM_LOADER_ + os::Printer::log("CSM Version", core::stringc(header.getVersion()).c_str()); + os::Printer::log("Loading groups. Count", core::stringc(count)); +#endif + + groups.reallocate(count); + for (s32 i = 0; i < count; i++) + { + Group* grp = new Group(); + grp->load(pReader); + groups.push_back(grp); + } + } + const bool bHasVGroups = (header.getVersion() == Header::VERSION_4_1); + + if (bHasVGroups) + { + //visgroups + const s32 count = pReader->readLong(); +#ifdef _IRR_DEBUG_CSM_LOADER_ + os::Printer::log("Loading visgroups. Count", core::stringc(count)); +#endif + + visgroups.reallocate(count); + for (s32 i = 0; i < count; i++) + { + VisGroup* grp = new VisGroup(); + grp->load(pReader); + visgroups.push_back(grp); + } + } + + //lightmaps + { + const s32 count = pReader->readLong(); +#ifdef _IRR_DEBUG_CSM_LOADER_ + os::Printer::log("Loading lightmaps. Count", core::stringc(count)); +#endif + + lightmaps.reallocate(count); + for(s32 i = 0; i < count; i++) + { + LightMap* lm = new LightMap(); + lm->load(pReader); + lightmaps.push_back(lm); + } + } + + //meshes + { + const s32 count = pReader->readLong(); +#ifdef _IRR_DEBUG_CSM_LOADER_ + os::Printer::log("Loading meshes. Count", core::stringc(count)); +#endif + + meshes.reallocate(count); + for(s32 i = 0; i < count; i++) + { + Mesh* mesh = new Mesh(); + mesh->load(pReader,bHasVGroups); + meshes.push_back(mesh); + } + } + + //entities + { + const s32 count = pReader->readLong(); +#ifdef _IRR_DEBUG_CSM_LOADER_ + os::Printer::log("Loading entitites. Count", core::stringc(count)); +#endif + + entities.reallocate(count); + for(s32 i = 0; i < count; i++) + { + Entity* ent = new Entity(); + ent->load(pReader); + entities.push_back(ent); + } + } + + //camera data +#ifdef _IRR_DEBUG_CSM_LOADER_ + os::Printer::log("Loading camera data."); +#endif + cameraData.load(pReader); + } + + s32 BinaryFileReader::readLong() + { + int ret = 0; + readBuffer(&ret,sizeof(int)); +#ifdef __BIG_ENDIAN__ + ret = os::Byteswap::byteswap(ret); +#endif + return ret; + } + + f32 BinaryFileReader::readFloat() + { + float ret = 0; + readBuffer(&ret,sizeof(float)); +#ifdef __BIG_ENDIAN__ + ret = os::Byteswap::byteswap(ret); +#endif + return ret; + } + + void BinaryFileReader::readString(core::stringc &str) + { + str = ""; + c8 c; + readBuffer(&c,sizeof(char)); + while(c != 0) + { + str += c; + readBuffer(&c,sizeof(char)); + } + } + + void BinaryFileReader::readVec3f(core::vector3df* v) + { + v->X = readFloat(); + v->Y = readFloat(); + v->Z = readFloat(); + } + + void BinaryFileReader::readVec2f(core::vector2df* v) + { + v->X = readFloat(); + v->Y = readFloat(); + } + + void BinaryFileReader::readColorRGB(color_rgb_t* color) + { + readBuffer(color,sizeof(color_rgb_t)); + } + +} // end namespace +} // end namespace + +#endif // _IRR_COMPILE_WITH_CSM_LOADER_ diff --git a/source/Irrlicht/CCSMLoader.h b/source/Irrlicht/CCSMLoader.h new file mode 100644 index 00000000..ed5fbda2 --- /dev/null +++ b/source/Irrlicht/CCSMLoader.h @@ -0,0 +1,81 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +// +// This Loader has been originally written by Saurav Mohapatra. I (Nikolaus Gebhardt) +// modified some minor things and integrated it into Irrlicht 0.9. Thanks a lot +// to Saurav Mohapatra for his work on this and that he gave me his permission to +// add it into Irrlicht. +// I did some changes to Saurav Mohapatra's loader, so I'm writing this down here: +// - Replaced all dependencies to STL and stdio with irr:: methods/constructs. +// - Moved everything into namespace irr::scene +// - Replaced logging with Irrlicht's internal logger. +// - Removed dependency to IrrlichtDevice +// - Moved all internal structures into CCSMLoader.cpp +// - Made the texture root parameter dependent on a ISceneManager string parameter +// - removed exceptions +// - Implemented CCCSMLoader as IMeshLoader +// - Fixed some problems with memory leaks +// - Fixed bounding box calculation +// +// The original readme of this file looks like this: +// +// This component provides a loader for the Cartography shop 4.x .csm maps for Irrlicht Engine. +// This is a part of the M_TRIX Project. +// This is licensed under the ZLib/LibPNG license +// The IrrCSM library is written by Saurav Mohapatra. +// +// Features +// +// The IrrCSM library features the following capabilities +// +// * Loads the .csm 4.0 and 4.1 files transparently +// * Presents the loaded file as irr::scene::IAnimatedMesh for easy creation of IOctreeSceneNode +// * Loads the textures given the correct texture root. hence map and textures can be in separate directories +// +// For more information go to http://www.geocities.com/standard_template/irrcsm/downloads.html + +#ifndef __CSM_LOADER_H_INCLUDED__ +#define __CSM_LOADER_H_INCLUDED__ + +#include "irrArray.h" +#include "IMesh.h" +#include "irrString.h" +#include "IFileSystem.h" +#include "IMeshLoader.h" + +namespace irr +{ +namespace scene +{ + class CSMFile; + class ISceneManager; + + class CCSMLoader : public scene::IMeshLoader + { + public: + + CCSMLoader(ISceneManager* manager, io::IFileSystem* fs); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".bsp") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! creates/loads an animated mesh from the file. + virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_; + + private: + + scene::IMesh* createCSMMesh(io::IReadFile* file); + + scene::IMesh* createIrrlichtMesh(const CSMFile* csmFile, const io::path& lmprefix); + + io::IFileSystem* FileSystem; + scene::ISceneManager* SceneManager; + }; + +} // end namespace +} // end namespace + +#endif + diff --git a/source/Irrlicht/CCameraSceneNode.cpp b/source/Irrlicht/CCameraSceneNode.cpp new file mode 100644 index 00000000..e0b68fc7 --- /dev/null +++ b/source/Irrlicht/CCameraSceneNode.cpp @@ -0,0 +1,401 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CCameraSceneNode.h" +#include "ISceneManager.h" +#include "IVideoDriver.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + + +//! constructor +CCameraSceneNode::CCameraSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position, const core::vector3df& lookat) + : ICameraSceneNode(parent, mgr, id, position), + BoundingBox(core::vector3df(0, 0, 0)), // Camera has no size. Still not sure if FLT_MAX might be the better variant + Target(lookat), UpVector(0.0f, 1.0f, 0.0f), ZNear(1.0f), ZFar(3000.0f), + InputReceiverEnabled(true), TargetAndRotationAreBound(false), + HasD3DStyleProjectionMatrix(true) +{ + #ifdef _DEBUG + setDebugName("CCameraSceneNode"); + #endif + + // set default projection + Fovy = core::PI / 2.5f; // Field of view, in radians. + + const video::IVideoDriver* const d = mgr?mgr->getVideoDriver():0; + if (d) + { + Aspect = (f32)d->getCurrentRenderTargetSize().Width / + (f32)d->getCurrentRenderTargetSize().Height; + HasD3DStyleProjectionMatrix = d->getDriverType() != video::EDT_OPENGL; + } + else + Aspect = 4.0f / 3.0f; // Aspect ratio. + + ViewArea.setFarNearDistance(ZFar - ZNear); + recalculateProjectionMatrix(); + recalculateViewArea(); +} + + +//! Disables or enables the camera to get key or mouse inputs. +void CCameraSceneNode::setInputReceiverEnabled(bool enabled) +{ + InputReceiverEnabled = enabled; +} + + +//! Returns if the input receiver of the camera is currently enabled. +bool CCameraSceneNode::isInputReceiverEnabled() const +{ + return InputReceiverEnabled; +} + + +//! Sets the projection matrix of the camera. +/** The core::matrix4 class has some methods +to build a projection matrix. e.g: core::matrix4::buildProjectionMatrixPerspectiveFovLH +\param projection: The new projection matrix of the camera. */ +void CCameraSceneNode::setProjectionMatrix(const core::matrix4& projection, bool isOrthogonal) +{ + IsOrthogonal = isOrthogonal; + ViewArea.getTransform ( video::ETS_PROJECTION ) = projection; +} + + +//! Gets the current projection matrix of the camera +//! \return Returns the current projection matrix of the camera. +const core::matrix4& CCameraSceneNode::getProjectionMatrix() const +{ + return ViewArea.getTransform ( video::ETS_PROJECTION ); +} + + +//! Gets the current view matrix of the camera +//! \return Returns the current view matrix of the camera. +const core::matrix4& CCameraSceneNode::getViewMatrix() const +{ + return ViewArea.getTransform ( video::ETS_VIEW ); +} + + +//! Sets a custom view matrix affector. The matrix passed here, will be +//! multiplied with the view matrix when it gets updated. +//! This allows for custom camera setups like, for example, a reflection camera. +/** \param affector: The affector matrix. */ +void CCameraSceneNode::setViewMatrixAffector(const core::matrix4& affector) +{ + Affector = affector; +} + + +//! Gets the custom view matrix affector. +const core::matrix4& CCameraSceneNode::getViewMatrixAffector() const +{ + return Affector; +} + + +//! It is possible to send mouse and key events to the camera. Most cameras +//! may ignore this input, but camera scene nodes which are created for +//! example with scene::ISceneManager::addMayaCameraSceneNode or +//! scene::ISceneManager::addFPSCameraSceneNode, may want to get this input +//! for changing their position, look at target or whatever. +bool CCameraSceneNode::OnEvent(const SEvent& event) +{ + if (!InputReceiverEnabled) + return false; + + // send events to event receiving animators + + ISceneNodeAnimatorList::Iterator ait = Animators.begin(); + + for (; ait != Animators.end(); ++ait) + if ((*ait)->isEventReceiverEnabled() && (*ait)->OnEvent(event)) + return true; + + // if nobody processed the event, return false + return false; +} + + +//! sets the look at target of the camera +//! \param pos: Look at target of the camera. +void CCameraSceneNode::setTarget(const core::vector3df& pos) +{ + Target = pos; + + if(TargetAndRotationAreBound) + { + const core::vector3df toTarget = Target - getAbsolutePosition(); + ISceneNode::setRotation(toTarget.getHorizontalAngle()); + } +} + + +//! Sets the rotation of the node. +/** This only modifies the relative rotation of the node. +If the camera's target and rotation are bound ( @see bindTargetAndRotation() ) +then calling this will also change the camera's target to match the rotation. +\param rotation New rotation of the node in degrees. */ +void CCameraSceneNode::setRotation(const core::vector3df& rotation) +{ + if(TargetAndRotationAreBound) + Target = getAbsolutePosition() + rotation.rotationToDirection(); + + ISceneNode::setRotation(rotation); +} + + +//! Gets the current look at target of the camera +//! \return Returns the current look at target of the camera +const core::vector3df& CCameraSceneNode::getTarget() const +{ + return Target; +} + + +//! sets the up vector of the camera +//! \param pos: New upvector of the camera. +void CCameraSceneNode::setUpVector(const core::vector3df& pos) +{ + UpVector = pos; +} + + +//! Gets the up vector of the camera. +//! \return Returns the up vector of the camera. +const core::vector3df& CCameraSceneNode::getUpVector() const +{ + return UpVector; +} + + +f32 CCameraSceneNode::getNearValue() const +{ + return ZNear; +} + + +f32 CCameraSceneNode::getFarValue() const +{ + return ZFar; +} + + +f32 CCameraSceneNode::getAspectRatio() const +{ + return Aspect; +} + + +f32 CCameraSceneNode::getFOV() const +{ + return Fovy; +} + + +void CCameraSceneNode::setNearValue(f32 f) +{ + ZNear = f; + recalculateProjectionMatrix(); + ViewArea.setFarNearDistance(ZFar - ZNear); +} + + +void CCameraSceneNode::setFarValue(f32 f) +{ + ZFar = f; + recalculateProjectionMatrix(); + ViewArea.setFarNearDistance(ZFar - ZNear); +} + + +void CCameraSceneNode::setAspectRatio(f32 f) +{ + Aspect = f; + recalculateProjectionMatrix(); +} + + +void CCameraSceneNode::setFOV(f32 f) +{ + Fovy = f; + recalculateProjectionMatrix(); +} + + +void CCameraSceneNode::recalculateProjectionMatrix() +{ + ViewArea.getTransform ( video::ETS_PROJECTION ).buildProjectionMatrixPerspectiveFovLH(Fovy, Aspect, ZNear, ZFar, HasD3DStyleProjectionMatrix); + IsOrthogonal = false; +} + + +//! prerender +void CCameraSceneNode::OnRegisterSceneNode() +{ + if ( SceneManager->getActiveCamera () == this ) + SceneManager->registerNodeForRendering(this, ESNRP_CAMERA); + + ISceneNode::OnRegisterSceneNode(); +} + + +//! render +void CCameraSceneNode::render() +{ + updateMatrices(); + + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + if ( driver) + { + driver->setTransform(video::ETS_PROJECTION, ViewArea.getTransform ( video::ETS_PROJECTION) ); + driver->setTransform(video::ETS_VIEW, ViewArea.getTransform ( video::ETS_VIEW) ); + } +} + +//! update +void CCameraSceneNode::updateMatrices() +{ + core::vector3df pos = getAbsolutePosition(); + core::vector3df tgtv = Target - pos; + tgtv.normalize(); + + // if upvector and vector to the target are the same, we have a + // problem. so solve this problem: + core::vector3df up = UpVector; + up.normalize(); + + f32 dp = tgtv.dotProduct(up); + + if ( core::equals(core::abs_(dp), 1.f) ) + { + up.X += 0.5f; + } + + ViewArea.getTransform(video::ETS_VIEW).buildCameraLookAtMatrixLH(pos, Target, up); + ViewArea.getTransform(video::ETS_VIEW) *= Affector; + recalculateViewArea(); +} + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CCameraSceneNode::getBoundingBox() const +{ + // NOTE: We deliberately don't return the boundingbox of the ViewArea. People can access that already. + // We want to prevent cameras from having their bounding box colliding in the SceneCollisionManager. + // If another boundingbox is ever necessary then please move BoundingBox to ICameraSceneNode and make it accessible (via a setter or an enum with options). + return BoundingBox; +} + + +//! returns the view frustum. +const SViewFrustum* CCameraSceneNode::getViewFrustum() const +{ + return &ViewArea; +} + + +void CCameraSceneNode::recalculateViewArea() +{ + ViewArea.cameraPosition = getAbsolutePosition(); + + core::matrix4 m(core::matrix4::EM4CONST_NOTHING); + m.setbyproduct_nocheck(ViewArea.getTransform(video::ETS_PROJECTION), + ViewArea.getTransform(video::ETS_VIEW)); + ViewArea.setFrom(m, HasD3DStyleProjectionMatrix); +} + + +//! Writes attributes of the scene node. +void CCameraSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + ICameraSceneNode::serializeAttributes(out, options); + + out->addVector3d("Target", Target); + out->addVector3d("UpVector", UpVector); + out->addFloat("Fovy", Fovy); + out->addFloat("Aspect", Aspect); + out->addFloat("ZNear", ZNear); + out->addFloat("ZFar", ZFar); + out->addBool("Binding", TargetAndRotationAreBound); + out->addBool("ReceiveInput", InputReceiverEnabled); +} + +//! Reads attributes of the scene node. +void CCameraSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + ICameraSceneNode::deserializeAttributes(in, options); + + Target = in->getAttributeAsVector3d("Target"); + UpVector = in->getAttributeAsVector3d("UpVector"); + Fovy = in->getAttributeAsFloat("Fovy"); + Aspect = in->getAttributeAsFloat("Aspect"); + ZNear = in->getAttributeAsFloat("ZNear"); + ZFar = in->getAttributeAsFloat("ZFar"); + TargetAndRotationAreBound = in->getAttributeAsBool("Binding"); + if ( in->findAttribute("ReceiveInput") ) + InputReceiverEnabled = in->getAttributeAsBool("ReceiveInput"); + + recalculateProjectionMatrix(); + recalculateViewArea(); +} + + +//! Set the binding between the camera's rotation adn target. +void CCameraSceneNode::bindTargetAndRotation(bool bound) +{ + TargetAndRotationAreBound = bound; +} + + +//! Gets the binding between the camera's rotation and target. +bool CCameraSceneNode::getTargetAndRotationBinding(void) const +{ + return TargetAndRotationAreBound; +} + + +//! Creates a clone of this scene node and its children. +ISceneNode* CCameraSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager) +{ + ICameraSceneNode::clone(newParent, newManager); + + if (!newParent) + newParent = Parent; + if (!newManager) + newManager = SceneManager; + + CCameraSceneNode* nb = new CCameraSceneNode(newParent, + newManager, ID, RelativeTranslation, Target); + + nb->ISceneNode::cloneMembers(this, newManager); + nb->ICameraSceneNode::cloneMembers(this); + + nb->Target = Target; + nb->UpVector = UpVector; + nb->Fovy = Fovy; + nb->Aspect = Aspect; + nb->ZNear = ZNear; + nb->ZFar = ZFar; + nb->ViewArea = ViewArea; + nb->Affector = Affector; + nb->InputReceiverEnabled = InputReceiverEnabled; + nb->TargetAndRotationAreBound = TargetAndRotationAreBound; + + if ( newParent ) + nb->drop(); + return nb; +} + + +} // end namespace +} // end namespace + diff --git a/source/Irrlicht/CCameraSceneNode.h b/source/Irrlicht/CCameraSceneNode.h new file mode 100644 index 00000000..4916a472 --- /dev/null +++ b/source/Irrlicht/CCameraSceneNode.h @@ -0,0 +1,179 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_CAMERA_SCENE_NODE_H_INCLUDED__ +#define __C_CAMERA_SCENE_NODE_H_INCLUDED__ + +#include "ICameraSceneNode.h" +#include "SViewFrustum.h" + +namespace irr +{ +namespace scene +{ + + class CCameraSceneNode : public ICameraSceneNode + { + public: + + //! constructor + CCameraSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& lookat = core::vector3df(0,0,100)); + + //! Sets the projection matrix of the camera. + /** The core::matrix4 class has some methods + to build a projection matrix. e.g: core::matrix4::buildProjectionMatrixPerspectiveFovLH. + Note that the matrix will only stay as set by this method until one of + the following Methods are called: setNearValue, setFarValue, setAspectRatio, setFOV. + \param projection The new projection matrix of the camera. + \param isOrthogonal Set this to true if the matrix is an orthogonal one (e.g. + from matrix4::buildProjectionMatrixOrthoLH(). */ + virtual void setProjectionMatrix(const core::matrix4& projection, bool isOrthogonal = false) _IRR_OVERRIDE_; + + //! Gets the current projection matrix of the camera + //! \return Returns the current projection matrix of the camera. + virtual const core::matrix4& getProjectionMatrix() const _IRR_OVERRIDE_; + + //! Gets the current view matrix of the camera + //! \return Returns the current view matrix of the camera. + virtual const core::matrix4& getViewMatrix() const _IRR_OVERRIDE_; + + //! Sets a custom view matrix affector. + /** \param affector: The affector matrix. */ + virtual void setViewMatrixAffector(const core::matrix4& affector) _IRR_OVERRIDE_; + + //! Gets the custom view matrix affector. + virtual const core::matrix4& getViewMatrixAffector() const _IRR_OVERRIDE_; + + //! It is possible to send mouse and key events to the camera. Most cameras + //! may ignore this input, but camera scene nodes which are created for + //! example with scene::ISceneManager::addMayaCameraSceneNode or + //! scene::ISceneManager::addMeshViewerCameraSceneNode, may want to get this input + //! for changing their position, look at target or whatever. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! Sets the look at target of the camera + /** If the camera's target and rotation are bound ( @see bindTargetAndRotation() ) + then calling this will also change the camera's scene node rotation to match the target. + \param pos: Look at target of the camera. */ + virtual void setTarget(const core::vector3df& pos) _IRR_OVERRIDE_; + + //! Sets the rotation of the node. + /** This only modifies the relative rotation of the node. + If the camera's target and rotation are bound ( @see bindTargetAndRotation() ) + then calling this will also change the camera's target to match the rotation. + \param rotation New rotation of the node in degrees. */ + virtual void setRotation(const core::vector3df& rotation) _IRR_OVERRIDE_; + + //! Gets the current look at target of the camera + /** \return The current look at target of the camera */ + virtual const core::vector3df& getTarget() const _IRR_OVERRIDE_; + + //! Sets the up vector of the camera. + //! \param pos: New upvector of the camera. + virtual void setUpVector(const core::vector3df& pos) _IRR_OVERRIDE_; + + //! Gets the up vector of the camera. + //! \return Returns the up vector of the camera. + virtual const core::vector3df& getUpVector() const _IRR_OVERRIDE_; + + //! Gets distance from the camera to the near plane. + //! \return Value of the near plane of the camera. + virtual f32 getNearValue() const _IRR_OVERRIDE_; + + //! Gets the distance from the camera to the far plane. + //! \return Value of the far plane of the camera. + virtual f32 getFarValue() const _IRR_OVERRIDE_; + + //! Get the aspect ratio of the camera. + //! \return The aspect ratio of the camera. + virtual f32 getAspectRatio() const _IRR_OVERRIDE_; + + //! Gets the field of view of the camera. + //! \return Field of view of the camera + virtual f32 getFOV() const _IRR_OVERRIDE_; + + //! Sets the value of the near clipping plane. (default: 1.0f) + virtual void setNearValue(f32 zn) _IRR_OVERRIDE_; + + //! Sets the value of the far clipping plane (default: 2000.0f) + virtual void setFarValue(f32 zf) _IRR_OVERRIDE_; + + //! Sets the aspect ratio (default: 4.0f / 3.0f) + virtual void setAspectRatio(f32 aspect) _IRR_OVERRIDE_; + + //! Sets the field of view (Default: PI / 3.5f) + virtual void setFOV(f32 fovy) _IRR_OVERRIDE_; + + //! PreRender event + virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; + + //! Render + virtual void render() _IRR_OVERRIDE_; + + //! Update + virtual void updateMatrices() _IRR_OVERRIDE_; + + //! Returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + //! Returns the view area. + virtual const SViewFrustum* getViewFrustum() const _IRR_OVERRIDE_; + + //! Disables or enables the camera to get key or mouse inputs. + //! If this is set to true, the camera will respond to key inputs + //! otherwise not. + virtual void setInputReceiverEnabled(bool enabled) _IRR_OVERRIDE_; + + //! Returns if the input receiver of the camera is currently enabled. + virtual bool isInputReceiverEnabled() const _IRR_OVERRIDE_; + + //! Writes attributes of the scene node. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_CAMERA; } + + //! Binds the camera scene node's rotation to its target position and vice versa, or unbinds them. + virtual void bindTargetAndRotation(bool bound) _IRR_OVERRIDE_; + + //! Queries if the camera scene node's rotation and its target position are bound together. + virtual bool getTargetAndRotationBinding(void) const _IRR_OVERRIDE_; + + //! Creates a clone of this scene node and its children. + virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + protected: + + void recalculateProjectionMatrix(); + void recalculateViewArea(); + + core::aabbox3d BoundingBox; + + core::vector3df Target; + core::vector3df UpVector; + + f32 Fovy; // Field of view, in radians. + f32 Aspect; // Aspect ratio. + f32 ZNear; // value of the near view-plane. + f32 ZFar; // Z-value of the far view-plane. + + SViewFrustum ViewArea; + core::matrix4 Affector; + + bool InputReceiverEnabled; + bool TargetAndRotationAreBound; + + bool HasD3DStyleProjectionMatrix; // true: projection from 0 to w; false: -w to w + }; + +} // end namespace +} // end namespace + +#endif + diff --git a/source/Irrlicht/CColladaFileLoader.cpp b/source/Irrlicht/CColladaFileLoader.cpp new file mode 100644 index 00000000..7645254d --- /dev/null +++ b/source/Irrlicht/CColladaFileLoader.cpp @@ -0,0 +1,3008 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_COLLADA_LOADER_ + +#include "CColladaFileLoader.h" +#include "CMeshTextureLoader.h" +#include "os.h" +#include "IXMLReader.h" +#include "IDummyTransformationSceneNode.h" +#include "SAnimatedMesh.h" +#include "fast_atof.h" +#include "quaternion.h" +#include "ILightSceneNode.h" +#include "ICameraSceneNode.h" +#include "IMeshManipulator.h" +#include "IReadFile.h" +#include "IAttributes.h" +#include "IMeshCache.h" +#include "IMeshSceneNode.h" +#include "SMeshBufferLightMap.h" +#include "irrMap.h" + +#ifdef _DEBUG +#define COLLADA_READER_DEBUG +#endif +namespace irr +{ +namespace scene +{ +namespace +{ + // currently supported COLLADA tag names + const core::stringc colladaSectionName = "COLLADA"; + const core::stringc librarySectionName = "library"; + const core::stringc libraryNodesSectionName = "library_nodes"; + const core::stringc libraryGeometriesSectionName = "library_geometries"; + const core::stringc libraryMaterialsSectionName = "library_materials"; + const core::stringc libraryImagesSectionName = "library_images"; + const core::stringc libraryVisualScenesSectionName = "library_visual_scenes"; + const core::stringc libraryCamerasSectionName = "library_cameras"; + const core::stringc libraryLightsSectionName = "library_lights"; + const core::stringc libraryEffectsSectionName = "library_effects"; + const core::stringc assetSectionName = "asset"; + const core::stringc sceneSectionName = "scene"; + const core::stringc visualSceneSectionName = "visual_scene"; + + const core::stringc lightPrefabName = "light"; + const core::stringc cameraPrefabName = "camera"; + const core::stringc materialSectionName = "material"; + const core::stringc geometrySectionName = "geometry"; + const core::stringc imageSectionName = "image"; + const core::stringc textureSectionName = "texture"; + const core::stringc effectSectionName = "effect"; + + const core::stringc pointSectionName = "point"; + const core::stringc directionalSectionName ="directional"; + const core::stringc spotSectionName = "spot"; + const core::stringc ambientSectionName = "ambient"; + const core::stringc meshSectionName = "mesh"; + const core::stringc sourceSectionName = "source"; + const core::stringc arraySectionName = "array"; + const core::stringc floatArraySectionName ="float_array"; + const core::stringc intArraySectionName = "int_array"; + const core::stringc techniqueCommonSectionName = "technique_common"; + const core::stringc accessorSectionName = "accessor"; + const core::stringc verticesSectionName = "vertices"; + const core::stringc inputTagName = "input"; + const core::stringc polylistSectionName = "polylist"; + const core::stringc trianglesSectionName = "triangles"; + const core::stringc polygonsSectionName = "polygons"; + const core::stringc primitivesName = "p"; + const core::stringc vcountName = "vcount"; + + const core::stringc upAxisNodeName = "up_axis"; + const core::stringc nodeSectionName = "node"; + const core::stringc lookatNodeName = "lookat"; + const core::stringc matrixNodeName = "matrix"; + const core::stringc perspectiveNodeName = "perspective"; + const core::stringc rotateNodeName = "rotate"; + const core::stringc scaleNodeName = "scale"; + const core::stringc translateNodeName = "translate"; + const core::stringc skewNodeName = "skew"; + const core::stringc minNodeName = "min"; + const core::stringc maxNodeName = "max"; + const core::stringc instanceName = "instance"; + const core::stringc instanceGeometryName = "instance_geometry"; + const core::stringc instanceSceneName = "instance_visual_scene"; + const core::stringc instanceEffectName = "instance_effect"; + const core::stringc instanceMaterialName = "instance_material"; + const core::stringc instanceLightName = "instance_light"; + const core::stringc instanceNodeName = "instance_node"; + const core::stringc instanceCameraName = "instance_camera"; + const core::stringc bindMaterialName = "bind_material"; + const core::stringc extraNodeName = "extra"; + const core::stringc techniqueNodeName = "technique"; + const core::stringc colorNodeName = "color"; + const core::stringc floatNodeName = "float"; + const core::stringc float2NodeName = "float2"; + const core::stringc float3NodeName = "float3"; + + const core::stringc newParamName = "newparam"; + const core::stringc paramTagName = "param"; + const core::stringc initFromName = "init_from"; + const core::stringc dataName = "data"; + const core::stringc wrapsName = "wrap_s"; + const core::stringc wraptName = "wrap_t"; + const core::stringc wraprName = "wrap_r"; // for downward compatibility to bug in old Irrlicht collada writer. Not standard but we wrote that accidentally up to Irrlicht 1.8, so we should still be able to load those files + const core::stringc wrappName = "wrap_p"; + const core::stringc minfilterName = "minfilter"; + const core::stringc magfilterName = "magfilter"; + const core::stringc mipfilterName = "mipfilter"; + + const core::stringc textureNodeName = "texture"; + const core::stringc doubleSidedNodeName = "double_sided"; + const core::stringc constantAttenuationNodeName = "constant_attenuation"; + const core::stringc linearAttenuationNodeName = "linear_attenuation"; + const core::stringc quadraticAttenuationNodeName = "quadratic_attenuation"; + const core::stringc falloffAngleNodeName = "falloff_angle"; + const core::stringc falloffExponentNodeName = "falloff_exponent"; + + const core::stringc profileCOMMONSectionName = "profile_COMMON"; + const core::stringc profileCOMMONAttributeName = "COMMON"; + + const char* const inputSemanticNames[] = {"POSITION", "VERTEX", "NORMAL", "TEXCOORD", + "UV", "TANGENT", "IMAGE", "TEXTURE", "COLOR", 0}; + + // We have to read ambient lights like other light types here, so we need a type for it + const video::E_LIGHT_TYPE ELT_AMBIENT = video::E_LIGHT_TYPE(video::ELT_COUNT+1); +} + + //! following class is for holding and creating instances of library + //! objects, named prefabs in this loader. + class CPrefab : public IColladaPrefab + { + public: + + CPrefab(const core::stringc& id) : Id(id) + { + } + + //! creates an instance of this prefab + virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent, + scene::ISceneManager* mgr) _IRR_OVERRIDE_ + { + // empty implementation + return 0; + } + + //! returns id of this prefab + virtual const core::stringc& getId() _IRR_OVERRIDE_ + { + return Id; + } + + protected: + + core::stringc Id; + }; + + + //! prefab for a light scene node + class CLightPrefab : public CPrefab + { + public: + + CLightPrefab(const core::stringc& id) : CPrefab(id) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA: loaded light prefab", Id.c_str(), ELL_DEBUG); + #endif + } + + video::SLight LightData; // publically accessible + + //! creates an instance of this prefab + virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent, + scene::ISceneManager* mgr) _IRR_OVERRIDE_ + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA: Constructing light instance", Id.c_str(), ELL_DEBUG); + #endif + + if ( LightData.Type == ELT_AMBIENT ) + { + mgr->setAmbientLight( LightData.DiffuseColor ); + return 0; + } + + scene::ILightSceneNode* l = mgr->addLightSceneNode(parent); + if (l) + { + l->setLightData ( LightData ); + l->setName(getId()); + } + return l; + } + }; + + + //! prefab for a mesh scene node + class CGeometryPrefab : public CPrefab + { + public: + + CGeometryPrefab(const core::stringc& id) : CPrefab(id) + { + } + + scene::IMesh* Mesh; + + //! creates an instance of this prefab + virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent, + scene::ISceneManager* mgr) _IRR_OVERRIDE_ + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA: Constructing mesh instance", Id.c_str(), ELL_DEBUG); + #endif + + scene::ISceneNode* m = mgr->addMeshSceneNode(Mesh, parent); + if (m) + { + m->setName(getId()); +// m->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false); +// m->setDebugDataVisible(scene::EDS_FULL); + } + return m; + } + }; + + + //! prefab for a camera scene node + class CCameraPrefab : public CPrefab + { + public: + + CCameraPrefab(const core::stringc& id) + : CPrefab(id), YFov(core::PI / 2.5f), ZNear(1.0f), ZFar(3000.0f) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA: loaded camera prefab", Id.c_str(), ELL_DEBUG); + #endif + } + + // publicly accessible data + f32 YFov; + f32 ZNear; + f32 ZFar; + + //! creates an instance of this prefab + virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent, + scene::ISceneManager* mgr) _IRR_OVERRIDE_ + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA: Constructing camera instance", Id.c_str(), ELL_DEBUG); + #endif + + scene::ICameraSceneNode* c = mgr->addCameraSceneNode(parent, core::vector3df(0,0,0), core::vector3df(0,0,100), -1, false); + if (c) + { + c->setFOV(YFov); + c->setNearValue(ZNear); + c->setFarValue(ZFar); + c->setName(getId()); + } + return c; + } + }; + + + //! prefab for a container scene node + //! Collects other prefabs and instantiates them upon instantiation + //! Uses a dummy scene node to return the children as one scene node + class CScenePrefab : public CPrefab + { + public: + CScenePrefab(const core::stringc& id) : CPrefab(id) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA: loaded scene prefab", Id.c_str(), ELL_DEBUG); + #endif + } + + //! creates an instance of this prefab + virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent, + scene::ISceneManager* mgr) _IRR_OVERRIDE_ + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA: Constructing scene instance", Id.c_str(), ELL_DEBUG); + #endif + + if (Children.size()==0) + return 0; + + scene::IDummyTransformationSceneNode* s = mgr->addDummyTransformationSceneNode(parent); + if (s) + { + s->setName(getId()); + s->getRelativeTransformationMatrix() = Transformation; + s->updateAbsolutePosition(); + core::stringc t; + for (u32 i=0; i<16; ++i) + { + t+=core::stringc((double)Transformation[i]); + t+=" "; + } + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA: Transformation", t.c_str(), ELL_DEBUG); + #endif + + for (u32 i=0; iaddInstance(s, mgr); + } + + return s; + } + + core::array Children; + core::matrix4 Transformation; + }; + + +//! Constructor +CColladaFileLoader::CColladaFileLoader(scene::ISceneManager* smgr, + io::IFileSystem* fs) +: SceneManager(smgr), FileSystem(fs), DummyMesh(0), + FirstLoadedMesh(0), LoadedMeshCount(0), CreateInstances(false) +{ + #ifdef _DEBUG + setDebugName("CColladaFileLoader"); + #endif + + // Escape characters, see https://www.w3schools.com/tags/ref_urlencode.asp + // TODO: There should be more, but usually people just escape the space character anyway. + // And I'm not sure if our xml files are utf-8 or windows-1252, so let's avoid the ambiguous ones. + EscapeCharsAnyURI.push_back(EscapeCharacterURL(' ', "%20")); + EscapeCharsAnyURI.push_back(EscapeCharacterURL('"', "%22")); + EscapeCharsAnyURI.push_back(EscapeCharacterURL('#', "%23")); + EscapeCharsAnyURI.push_back(EscapeCharacterURL('$', "%24")); + EscapeCharsAnyURI.push_back(EscapeCharacterURL('%', "%25")); + EscapeCharsAnyURI.push_back(EscapeCharacterURL('&', "%26")); + EscapeCharsAnyURI.push_back(EscapeCharacterURL('\'', "%27")); + EscapeCharsAnyURI.push_back(EscapeCharacterURL('(', "%28")); + EscapeCharsAnyURI.push_back(EscapeCharacterURL(')', "%29")); + EscapeCharsAnyURI.push_back(EscapeCharacterURL('/', "%2F")); + EscapeCharsAnyURI.push_back(EscapeCharacterURL('\\', "%5C")); + + + TextureLoader = new CMeshTextureLoader( FileSystem, SceneManager->getVideoDriver() ); +} + + +//! destructor +CColladaFileLoader::~CColladaFileLoader() +{ + if (DummyMesh) + DummyMesh->drop(); + + if (FirstLoadedMesh) + FirstLoadedMesh->drop(); +} + + +//! Returns true if the file maybe is able to be loaded by this class. +/** This decision should be based only on the file extension (e.g. ".cob") */ +bool CColladaFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "xml", "dae" ); +} + + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IReferenceCounted::drop() for more information. +IAnimatedMesh* CColladaFileLoader::createMesh(io::IReadFile* file) +{ + io::IXMLReaderUTF8* reader = FileSystem->createXMLReaderUTF8(file); + if (!reader) + return 0; + + if ( getMeshTextureLoader() ) + getMeshTextureLoader()->setMeshFile(file); + + CurrentlyLoadingMesh = file->getFileName(); + CreateInstances = SceneManager->getParameters()->getAttributeAsBool( + scene::COLLADA_CREATE_SCENE_INSTANCES); + Version = 0; + FlipAxis = false; + + // read until COLLADA section, skip other parts + + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (colladaSectionName == reader->getNodeName()) + readColladaSection(reader); + else + skipSection(reader, true); // unknown section + } + } + + reader->drop(); + if (!Version) + return 0; + + // because this loader loads and creates a complete scene instead of + // a single mesh, return an empty dummy mesh to make the scene manager + // know that everything went well. + if (!DummyMesh) + DummyMesh = new SAnimatedMesh(); + scene::IAnimatedMesh* returnMesh = DummyMesh; + + if (Version < 10400) + instantiateNode(SceneManager->getRootSceneNode()); + + // add the first loaded mesh into the mesh cache too, if more than one + // meshes have been loaded from the file + if (LoadedMeshCount>1 && FirstLoadedMesh) + { + os::Printer::log("Added COLLADA mesh", FirstLoadedMeshName.c_str()); + SceneManager->getMeshCache()->addMesh(FirstLoadedMeshName.c_str(), FirstLoadedMesh); + } + + // clean up temporary loaded data + clearData(); + + returnMesh->grab(); // store until this loader is destroyed + + DummyMesh->drop(); + DummyMesh = 0; + + if (FirstLoadedMesh) + FirstLoadedMesh->drop(); + FirstLoadedMesh = 0; + LoadedMeshCount = 0; + + return returnMesh; +} + + +//! skips an (unknown) section in the collada document +void CColladaFileLoader::skipSection(io::IXMLReaderUTF8* reader, bool reportSkipping) +{ + #ifndef COLLADA_READER_DEBUG + if (reportSkipping) // always report in COLLADA_READER_DEBUG mode + #endif + os::Printer::log("COLLADA skipping section", core::stringc(reader->getNodeName()).c_str(), ELL_DEBUG); + + // skip if this element is empty anyway. + if (reader->isEmptyElement()) + return; + + // read until we've reached the last element in this section + u32 tagCounter = 1; + + while(tagCounter && reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT && + !reader->isEmptyElement()) + { + #ifdef COLLADA_READER_DEBUG + if (reportSkipping) + os::Printer::log("Skipping COLLADA unknown element", core::stringc(reader->getNodeName()).c_str(), ELL_DEBUG); + #endif + + ++tagCounter; + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + --tagCounter; + } +} + + +//! reads the section and its content +void CColladaFileLoader::readColladaSection(io::IXMLReaderUTF8* reader) +{ + if (reader->isEmptyElement()) + return; + + // todo: patch level needs to be handled + const f32 version = core::fast_atof(core::stringc(reader->getAttributeValue("version")).c_str()); + Version = core::floor32(version)*10000+core::round32(core::fract(version)*1000.0f); + // Version 1.4 can be checked for by if (Version >= 10400) + + while(reader->read()) + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (assetSectionName == reader->getNodeName()) + readAssetSection(reader); + else + if (librarySectionName == reader->getNodeName()) + readLibrarySection(reader); + else + if (libraryNodesSectionName == reader->getNodeName()) + readLibrarySection(reader); + else + if (libraryGeometriesSectionName == reader->getNodeName()) + readLibrarySection(reader); + else + if (libraryMaterialsSectionName == reader->getNodeName()) + readLibrarySection(reader); + else + if (libraryEffectsSectionName == reader->getNodeName()) + readLibrarySection(reader); + else + if (libraryImagesSectionName == reader->getNodeName()) + readLibrarySection(reader); + else + if (libraryCamerasSectionName == reader->getNodeName()) + readLibrarySection(reader); + else + if (libraryLightsSectionName == reader->getNodeName()) + readLibrarySection(reader); + else + if (libraryVisualScenesSectionName == reader->getNodeName()) + readVisualScene(reader); + else + if (assetSectionName == reader->getNodeName()) + readAssetSection(reader); + else + if (sceneSectionName == reader->getNodeName()) + readSceneSection(reader); + else + { + os::Printer::log("COLLADA loader warning: Wrong tag usage found", reader->getNodeName(), ELL_WARNING); + skipSection(reader, true); // unknown section + } + } +} + + +//! reads a section and its content +void CColladaFileLoader::readLibrarySection(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading library", ELL_DEBUG); + #endif + + if (reader->isEmptyElement()) + return; + + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + // animation section tbd + if (cameraPrefabName == reader->getNodeName()) + readCameraPrefab(reader); + else + // code section tbd + // controller section tbd + if (geometrySectionName == reader->getNodeName()) + readGeometry(reader); + else + if (imageSectionName == reader->getNodeName()) + readImage(reader); + else + if (lightPrefabName == reader->getNodeName()) + readLightPrefab(reader); + else + if (materialSectionName == reader->getNodeName()) + readMaterial(reader); + else + if (nodeSectionName == reader->getNodeName()) + { + CScenePrefab p(""); + + readNodeSection(reader, SceneManager->getRootSceneNode(), &p); + } + else + if (effectSectionName == reader->getNodeName()) + readEffect(reader); + else + // program section tbd + if (textureSectionName == reader->getNodeName()) + readTexture(reader); + else + skipSection(reader, true); // unknown section, not all allowed supported yet + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + { + if (librarySectionName == reader->getNodeName()) + break; // end reading. + if (libraryNodesSectionName == reader->getNodeName()) + break; // end reading. + if (libraryGeometriesSectionName == reader->getNodeName()) + break; // end reading. + if (libraryMaterialsSectionName == reader->getNodeName()) + break; // end reading. + if (libraryEffectsSectionName == reader->getNodeName()) + break; // end reading. + if (libraryImagesSectionName == reader->getNodeName()) + break; // end reading. + if (libraryLightsSectionName == reader->getNodeName()) + break; // end reading. + if (libraryCamerasSectionName == reader->getNodeName()) + break; // end reading. + } + } +} + + +//! reads a element and stores it as a prefab +void CColladaFileLoader::readVisualScene(io::IXMLReaderUTF8* reader) +{ + CScenePrefab* p = 0; + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (visualSceneSectionName == reader->getNodeName()) + p = new CScenePrefab(readId(reader)); + else + if (p && nodeSectionName == reader->getNodeName()) // as a child of visual_scene + readNodeSection(reader, SceneManager->getRootSceneNode(), p); + else + if (assetSectionName == reader->getNodeName()) + readAssetSection(reader); + else + if (extraNodeName == reader->getNodeName()) + skipSection(reader, false); // ignore all other sections + else + { + os::Printer::log("COLLADA loader warning: Wrong tag usage found", reader->getNodeName(), ELL_WARNING); + skipSection(reader, true); // ignore all other sections + } + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + { + if (libraryVisualScenesSectionName == reader->getNodeName()) + return; + else + if ((visualSceneSectionName == reader->getNodeName()) && p) + { + Prefabs.push_back(p); + p = 0; + } + } + } +} + + +//! reads a section and its content +void CColladaFileLoader::readSceneSection(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading scene", ELL_DEBUG); + #endif + + if (reader->isEmptyElement()) + return; + + // read the scene + + core::matrix4 transform; // transformation of this node + scene::IDummyTransformationSceneNode* node = 0; + + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (lookatNodeName == reader->getNodeName()) + transform *= readLookAtNode(reader); + else + if (matrixNodeName == reader->getNodeName()) + transform *= readMatrixNode(reader); + else + if (perspectiveNodeName == reader->getNodeName()) + transform *= readPerspectiveNode(reader); + else + if (rotateNodeName == reader->getNodeName()) + transform *= readRotateNode(reader); + else + if (scaleNodeName == reader->getNodeName()) + transform *= readScaleNode(reader); + else + if (skewNodeName == reader->getNodeName()) + transform *= readSkewNode(reader); + else + if (translateNodeName == reader->getNodeName()) + transform *= readTranslateNode(reader); + else + if (nodeSectionName == reader->getNodeName()) + { + // create dummy node if there is none yet. + if (!node) + node = SceneManager->addDummyTransformationSceneNode(SceneManager->getRootSceneNode()); + + readNodeSection(reader, node); + } + else + if ((instanceSceneName == reader->getNodeName())) + readInstanceNode(reader, SceneManager->getRootSceneNode(), 0, 0,instanceSceneName); + else + if (extraNodeName == reader->getNodeName()) + skipSection(reader, false); + else + { + os::Printer::log("COLLADA loader warning: Wrong tag usage found", reader->getNodeName(), ELL_WARNING); + skipSection(reader, true); // ignore all other sections + } + } + else + if ((reader->getNodeType() == io::EXN_ELEMENT_END) && + (sceneSectionName == reader->getNodeName())) + return; + } + if (node) + node->getRelativeTransformationMatrix() = transform; +} + + +//! reads a section and its content +void CColladaFileLoader::readAssetSection(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading asset", ELL_DEBUG); + #endif + + if (reader->isEmptyElement()) + return; + + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (upAxisNodeName == reader->getNodeName()) + { + reader->read(); + FlipAxis = (core::stringc("Z_UP") == reader->getNodeData()); + } + } + else + if ((reader->getNodeType() == io::EXN_ELEMENT_END) && + (assetSectionName == reader->getNodeName())) + return; + } +} + + +//! reads a section and its content +void CColladaFileLoader::readNodeSection(io::IXMLReaderUTF8* reader, scene::ISceneNode* parent, CScenePrefab* p) +{ + if (reader->isEmptyElement()) + { + return; + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading empty node", ELL_DEBUG); + #endif + } + + core::stringc name = readId(reader); + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading node", name, ELL_DEBUG); + #endif + + core::matrix4 transform; // transformation of this node + scene::ISceneNode* node = 0; // instance + CScenePrefab* nodeprefab = 0; // prefab for library_nodes usage + + if (p) + { + nodeprefab = new CScenePrefab(readId(reader)); + p->Children.push_back(nodeprefab); + Prefabs.push_back(nodeprefab); // in order to delete them later on + } + + // read the node + + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (assetSectionName == reader->getNodeName()) + readAssetSection(reader); + else + if (lookatNodeName == reader->getNodeName()) + transform *= readLookAtNode(reader); + else + if (matrixNodeName == reader->getNodeName()) + transform *= readMatrixNode(reader); + else + if (perspectiveNodeName == reader->getNodeName()) + transform *= readPerspectiveNode(reader); + else + if (rotateNodeName == reader->getNodeName()) + transform *= readRotateNode(reader); + else + if (scaleNodeName == reader->getNodeName()) + transform *= readScaleNode(reader); + else + if (skewNodeName == reader->getNodeName()) + transform *= readSkewNode(reader); + else + if (translateNodeName == reader->getNodeName()) + transform *= readTranslateNode(reader); + else + if ((instanceName == reader->getNodeName()) || + (instanceNodeName == reader->getNodeName()) || + (instanceGeometryName == reader->getNodeName()) || + (instanceLightName == reader->getNodeName()) || + (instanceCameraName == reader->getNodeName()) + ) + { + scene::ISceneNode* newnode = 0; + readInstanceNode(reader, parent, &newnode, nodeprefab, reader->getNodeName()); + + if (node && newnode) + { + // move children from dummy to new node + ISceneNodeList::ConstIterator it = node->getChildren().begin(); + for (; it != node->getChildren().end(); it = node->getChildren().begin()) + (*it)->setParent(newnode); + + // remove previous dummy node + node->remove(); + node = newnode; + } + } + else + if (nodeSectionName == reader->getNodeName()) + { + // create dummy node if there is none yet. + if (CreateInstances && !node) + { + scene::IDummyTransformationSceneNode* dummy = + SceneManager->addDummyTransformationSceneNode(parent); + dummy->getRelativeTransformationMatrix() = transform; + node = dummy; + } + else + node = parent; + + // read and add child + readNodeSection(reader, node, nodeprefab); + } + else + if (extraNodeName == reader->getNodeName()) + skipSection(reader, false); + else + skipSection(reader, true); // ignore all other sections + + } // end if node + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + { + if (nodeSectionName == reader->getNodeName()) + break; + } + } + + if (nodeprefab) + nodeprefab->Transformation = transform; + else + if (node) + { + // set transformation correctly into node. + node->setPosition(transform.getTranslation()); + node->setRotation(transform.getRotationDegrees()); + node->setScale(transform.getScale()); + node->updateAbsolutePosition(); + + node->setName(name); + } +} + + +//! reads a element and its content and creates a matrix from it +core::matrix4 CColladaFileLoader::readLookAtNode(io::IXMLReaderUTF8* reader) +{ + core::matrix4 mat; + if (reader->isEmptyElement()) + return mat; + + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading look at node", ELL_DEBUG); + #endif + + f32 floats[9]; + readFloatsInsideElement(reader, floats, 9); + + if (FlipAxis) + { + mat.buildCameraLookAtMatrixLH( + core::vector3df(floats[0], floats[2], floats[1]), + core::vector3df(floats[3], floats[5], floats[4]), + core::vector3df(floats[6], floats[8], floats[7])); + } + else + { + mat.buildCameraLookAtMatrixLH( + core::vector3df(floats[0], floats[1], floats[2]*-1.f), + core::vector3df(floats[3], floats[4], floats[5]*-1.f), + core::vector3df(floats[6], floats[7], floats[8]*-1.f)); + } + + return mat; +} + + +//! reads a element and its content and creates a matrix from it +core::matrix4 CColladaFileLoader::readSkewNode(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading skew node", ELL_DEBUG); + #endif + + core::matrix4 mat; + if (reader->isEmptyElement()) + return mat; + + f32 floats[7]; // angle rotation-axis translation-axis + readFloatsInsideElement(reader, floats, 7); + + // build skew matrix from these 7 floats + // TODO: missing example, not sure if rotation is in correct direction. + // TODO: shouldn't FlipAxis also be regarded here? + core::quaternion q; + q.fromAngleAxis(floats[0]*core::DEGTORAD, core::vector3df(floats[1], floats[2], floats[3])); + mat = q.getMatrix(); + + if (floats[4]==1.f) // along x-axis + { + mat[4]=0.f; + mat[6]=0.f; + mat[8]=0.f; + mat[9]=0.f; + } + else + if (floats[5]==1.f) // along y-axis + { + mat[1]=0.f; + mat[2]=0.f; + mat[8]=0.f; + mat[9]=0.f; + } + else + if (floats[6]==1.f) // along z-axis + { + mat[1]=0.f; + mat[2]=0.f; + mat[4]=0.f; + mat[6]=0.f; + } + + if ( FlipAxis ) + return mat; + else + return flipZAxis(mat); +} + +//! reads a element and its content and creates a matrix from it +core::matrix4 CColladaFileLoader::readMatrixNode(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading matrix node", ELL_DEBUG); + #endif + + core::matrix4 mat; + if (reader->isEmptyElement()) + return mat; + + readFloatsInsideElement(reader, mat.pointer(), 16); + + // put translation into the correct place + if (FlipAxis) + { + core::matrix4 mat2(mat, core::matrix4::EM4CONST_TRANSPOSED); + mat2[1]=mat[8]; + mat2[2]=mat[4]; + mat2[4]=mat[2]; + mat2[5]=mat[10]; + mat2[6]=mat[6]; + mat2[8]=mat[1]; + mat2[9]=mat[9]; + mat2[10]=mat[5]; + mat2[12]=mat[3]; + mat2[13]=mat[11]; + mat2[14]=mat[7]; + return mat2; + } + else + return flipZAxis(core::matrix4(mat, core::matrix4::EM4CONST_TRANSPOSED)); +} + + +//! reads a element and its content and creates a matrix from it +core::matrix4 CColladaFileLoader::readPerspectiveNode(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading perspective node", ELL_DEBUG); + #endif + + core::matrix4 mat; + if (reader->isEmptyElement()) + return mat; + + f32 floats[1]; + readFloatsInsideElement(reader, floats, 1); + + // TODO: build perspective matrix from this float + + os::Printer::log("COLLADA loader warning: not implemented yet.", ELL_WARNING); + + return mat; +} + + +//! reads a element and its content and creates a matrix from it +core::matrix4 CColladaFileLoader::readRotateNode(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading rotate node", ELL_DEBUG); + #endif + + core::matrix4 mat; + if (reader->isEmptyElement()) + return mat; + + f32 floats[4]; + readFloatsInsideElement(reader, floats, 4); + floats[3] *= -1.f; // to left handed rotation + + if (!core::iszero(floats[3])) + { + core::quaternion q; + if (FlipAxis) + q.fromAngleAxis(floats[3]*core::DEGTORAD, core::vector3df(floats[0], floats[2], floats[1])); + else + q.fromAngleAxis(floats[3]*core::DEGTORAD, core::vector3df(floats[0], floats[1], floats[2]*-1.f)); + return q.getMatrix(); + } + else + return core::IdentityMatrix; +} + + +//! reads a element and its content and creates a matrix from it +core::matrix4 CColladaFileLoader::readScaleNode(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading scale node", ELL_DEBUG); + #endif + + core::matrix4 mat; + if (reader->isEmptyElement()) + return mat; + + f32 floats[3]; + readFloatsInsideElement(reader, floats, 3); + + if (FlipAxis) + mat.setScale(core::vector3df(floats[0], floats[2], floats[1])); + else + mat.setScale(core::vector3df(floats[0], floats[1], floats[2])); + + return mat; +} + + +//! reads a element and its content and creates a matrix from it +core::matrix4 CColladaFileLoader::readTranslateNode(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading translate node", ELL_DEBUG); + #endif + + core::matrix4 mat; + if (reader->isEmptyElement()) + return mat; + + f32 floats[3]; + readFloatsInsideElement(reader, floats, 3); + + if (FlipAxis) + mat.setTranslation(core::vector3df(floats[0], floats[2], floats[1])); + else + mat.setTranslation(core::vector3df(floats[0], floats[1], floats[2]*-1.f)); + + return mat; +} + + +//! reads any kind of node +void CColladaFileLoader::readInstanceNode(io::IXMLReaderUTF8* reader, + scene::ISceneNode* parent, scene::ISceneNode** outNode, + CScenePrefab* p, const core::stringc& type) +{ + // find prefab of the specified id + core::stringc url = reader->getAttributeValue("url"); + uriToId(url); + + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading instance", url, ELL_DEBUG); + #endif + + if (!reader->isEmptyElement()) + { + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (bindMaterialName == reader->getNodeName()) + readBindMaterialSection(reader,url); + else + if (extraNodeName == reader->getNodeName()) + skipSection(reader, false); + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + break; + } + } + instantiateNode(parent, outNode, p, url, type); +} + + +void CColladaFileLoader::instantiateNode(scene::ISceneNode* parent, + scene::ISceneNode** outNode, CScenePrefab* p, const core::stringc& url, + const core::stringc& type) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA instantiate node", ELL_DEBUG); + #endif + + for (u32 i=0; igetId()) + { + if (p) + p->Children.push_back(Prefabs[i]); + else + if (CreateInstances) + { + scene::ISceneNode * newNode + = Prefabs[i]->addInstance(parent, SceneManager); + if (outNode) + { + *outNode = newNode; + if (*outNode) + (*outNode)->setName(url); + } + } + return; + } + } + if (p) + { + if (instanceGeometryName==type) + { + Prefabs.push_back(new CGeometryPrefab(url)); + p->Children.push_back(Prefabs.getLast()); + } + } +} + + +//! reads a element and stores it as prefab +void CColladaFileLoader::readCameraPrefab(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading camera prefab", ELL_DEBUG); + #endif + + CCameraPrefab* prefab = new CCameraPrefab(readId(reader)); + + if (!reader->isEmptyElement()) + { + // read techniques optics and imager (the latter is completely ignored, though) + readColladaParameters(reader, cameraPrefabName); + + SColladaParam* p; + + // XFOV not yet supported + p = getColladaParameter(ECPN_YFOV); + if (p && p->Type == ECPT_FLOAT) + prefab->YFov = p->Floats[0]; + + p = getColladaParameter(ECPN_ZNEAR); + if (p && p->Type == ECPT_FLOAT) + prefab->ZNear = p->Floats[0]; + + p = getColladaParameter(ECPN_ZFAR); + if (p && p->Type == ECPT_FLOAT) + prefab->ZFar = p->Floats[0]; + // orthographic camera uses LEFT, RIGHT, TOP, and BOTTOM + } + + Prefabs.push_back(prefab); +} + + +//! reads a element and stores it in the image section +void CColladaFileLoader::readImage(io::IXMLReaderUTF8* reader) +{ + // add image to list of loaded images. + Images.push_back(SColladaImage()); + SColladaImage& image=Images.getLast(); + + image.Id = readId(reader); + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading image", core::stringc(image.Id), ELL_DEBUG); + #endif + image.Dimension.Height = (u32)reader->getAttributeValueAsInt("height"); + image.Dimension.Width = (u32)reader->getAttributeValueAsInt("width"); + + if (Version >= 10400) // start with 1.4 + { + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (assetSectionName == reader->getNodeName()) + skipSection(reader, false); + else + if (initFromName == reader->getNodeName()) + { + reader->read(); + image.Source = reader->getNodeData(); + image.Source.trim(); + unescape(image.Source); + image.SourceIsFilename=true; + } + else + if (dataName == reader->getNodeName()) + { + reader->read(); + image.Source = reader->getNodeData(); + image.Source.trim(); + image.SourceIsFilename=false; + } + else + if (extraNodeName == reader->getNodeName()) + skipSection(reader, false); + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + { + if (initFromName == reader->getNodeName()) + return; + } + } + } + else + { + image.Source = reader->getAttributeValue("source"); + image.Source.trim(); + image.SourceIsFilename=false; + } +} + + +//! reads a element and stores it in the texture section +void CColladaFileLoader::readTexture(io::IXMLReaderUTF8* reader) +{ + // add texture to list of loaded textures. + Textures.push_back(SColladaTexture()); + SColladaTexture& texture=Textures.getLast(); + + texture.Id = readId(reader); + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading texture", core::stringc(texture.Id), ELL_DEBUG); + #endif + + if (!reader->isEmptyElement()) + { + readColladaInputs(reader, textureSectionName); + SColladaInput* input = getColladaInput(ECIS_IMAGE); + if (input) + { + const core::stringc imageName = input->Source; + texture.Texture = getTextureFromImage(imageName, NULL); + } + } +} + + +//! reads a element and stores it in the material section +void CColladaFileLoader::readMaterial(io::IXMLReaderUTF8* reader) +{ + // add material to list of loaded materials. + Materials.push_back(SColladaMaterial()); + + SColladaMaterial& material = Materials.getLast(); + material.Id = readId(reader); + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading material", core::stringc(material.Id), ELL_DEBUG); + #endif + + if (Version >= 10400) + { + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT && + instanceEffectName == reader->getNodeName()) + { + material.InstanceEffectId = reader->getAttributeValue("url"); + uriToId(material.InstanceEffectId); + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END && + materialSectionName == reader->getNodeName()) + { + break; + } + } // end while reader->read(); + } + else + { + if (!reader->isEmptyElement()) + { + readColladaInputs(reader, materialSectionName); + SColladaInput* input = getColladaInput(ECIS_TEXTURE); + if (input) + { + core::stringc textureName = input->Source; + uriToId(textureName); + for (u32 i=0; iType == ECPT_FLOAT3) + material.Mat.AmbientColor = video::SColorf(p->Floats[0],p->Floats[1],p->Floats[2]).toSColor(); + p = getColladaParameter(ECPN_DIFFUSE); + if (p && p->Type == ECPT_FLOAT3) + material.Mat.DiffuseColor = video::SColorf(p->Floats[0],p->Floats[1],p->Floats[2]).toSColor(); + p = getColladaParameter(ECPN_SPECULAR); + if (p && p->Type == ECPT_FLOAT3) + material.Mat.DiffuseColor = video::SColorf(p->Floats[0],p->Floats[1],p->Floats[2]).toSColor(); + p = getColladaParameter(ECPN_SHININESS); + if (p && p->Type == ECPT_FLOAT) + material.Mat.Shininess = p->Floats[0]; +#endif + } + } +} + +void CColladaFileLoader::readEffect(io::IXMLReaderUTF8* reader, SColladaEffect * effect) +{ + static const core::stringc constantNode("constant"); + static const core::stringc lambertNode("lambert"); + static const core::stringc phongNode("phong"); + static const core::stringc blinnNode("blinn"); + static const core::stringc emissionNode("emission"); + static const core::stringc ambientNode("ambient"); + static const core::stringc diffuseNode("diffuse"); + static const core::stringc specularNode("specular"); + static const core::stringc shininessNode("shininess"); + static const core::stringc reflectiveNode("reflective"); + static const core::stringc reflectivityNode("reflectivity"); + static const core::stringc transparentNode("transparent"); + static const core::stringc transparencyNode("transparency"); + static const core::stringc indexOfRefractionNode("index_of_refraction"); + + if (!effect) + { + Effects.push_back(SColladaEffect()); + effect = &Effects.getLast(); + effect->Parameters = new io::CAttributes(); + effect->Id = readId(reader); + effect->Transparency = 1.f; + effect->Mat.Lighting=true; + effect->Mat.NormalizeNormals=true; + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading effect", core::stringc(effect->Id), ELL_DEBUG); + #endif + } + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + // first come the tags we descend, but ignore the top-levels + if (!reader->isEmptyElement() && ((profileCOMMONSectionName == reader->getNodeName()) || + (techniqueNodeName == reader->getNodeName()))) + readEffect(reader,effect); + else + if (newParamName == reader->getNodeName()) + readParameter(reader, effect->Parameters); + else + // these are the actual materials inside technique + if (constantNode == reader->getNodeName() || + lambertNode == reader->getNodeName() || + phongNode == reader->getNodeName() || + blinnNode == reader->getNodeName()) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading effect part", reader->getNodeName(), ELL_DEBUG); + #endif + effect->Mat.setFlag(irr::video::EMF_GOURAUD_SHADING, + phongNode == reader->getNodeName() || + blinnNode == reader->getNodeName()); + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + const core::stringc node = reader->getNodeName(); + if (emissionNode == node || ambientNode == node || + diffuseNode == node || specularNode == node || + reflectiveNode == node || transparentNode == node ) + { + // color or texture types + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT && + colorNodeName == reader->getNodeName()) + { + const video::SColorf colorf = readColorNode(reader); + const video::SColor color = colorf.toSColor(); + if (emissionNode == node) + effect->Mat.EmissiveColor = color; + else + if (ambientNode == node) + effect->Mat.AmbientColor = color; + else + if (diffuseNode == node) + effect->Mat.DiffuseColor = color; + else + if (specularNode == node) + effect->Mat.SpecularColor = color; + else + if (transparentNode == node) + effect->Transparency = colorf.getAlpha(); + } + else + if (reader->getNodeType() == io::EXN_ELEMENT && + textureNodeName == reader->getNodeName()) + { + effect->Textures.push_back(reader->getAttributeValue("texture")); + break; + } + else + if (reader->getNodeType() == io::EXN_ELEMENT) + skipSection(reader, false); + else + if (reader->getNodeType() == io::EXN_ELEMENT_END && + node == reader->getNodeName()) + break; + } + } + else + if (shininessNode == node || reflectivityNode == node || + transparencyNode == node || indexOfRefractionNode == node ) + { + // float or param types + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT && + floatNodeName == reader->getNodeName()) + { + f32 f = readFloatNode(reader); + if (shininessNode == node) + effect->Mat.Shininess = f; + else + if (transparencyNode == node) + effect->Transparency *= f; + } + else + if (reader->getNodeType() == io::EXN_ELEMENT) + skipSection(reader, false); + else + if (reader->getNodeType() == io::EXN_ELEMENT_END && + node == reader->getNodeName()) + break; + } + } + else + skipSection(reader, true); // ignore all other nodes + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END && ( + constantNode == reader->getNodeName() || + lambertNode == reader->getNodeName() || + phongNode == reader->getNodeName() || + blinnNode == reader->getNodeName() + )) + break; + } + } + else + if (!reader->isEmptyElement() && (extraNodeName == reader->getNodeName())) + readEffect(reader,effect); + else + if (doubleSidedNodeName == reader->getNodeName()) + { + // read the GoogleEarth extra flag for double sided polys + s32 doubleSided = 0; + readIntsInsideElement(reader,&doubleSided,1); + if (doubleSided) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("Setting double sided flag for effect.", ELL_DEBUG); + #endif + + effect->Mat.setFlag(irr::video::EMF_BACK_FACE_CULLING,false); + } + } + else + skipSection(reader, true); // ignore all other sections + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + { + if (effectSectionName == reader->getNodeName()) + break; + else + if (profileCOMMONSectionName == reader->getNodeName()) + break; + else + if (techniqueNodeName == reader->getNodeName()) + break; + else + if (extraNodeName == reader->getNodeName()) + break; + } + } + + if (effect->Mat.AmbientColor == video::SColor(0) && + effect->Mat.DiffuseColor != video::SColor(0)) + effect->Mat.AmbientColor = effect->Mat.DiffuseColor; + if (effect->Mat.DiffuseColor == video::SColor(0) && + effect->Mat.AmbientColor != video::SColor(0)) + effect->Mat.DiffuseColor = effect->Mat.AmbientColor; + if ((effect->Transparency != 0.0f) && (effect->Transparency != 1.0f)) + { + effect->Mat.MaterialType = irr::video::EMT_TRANSPARENT_VERTEX_ALPHA; + effect->Mat.ZWriteEnable = video::EZW_OFF; + } + + video::E_TEXTURE_CLAMP twu = video::ETC_REPEAT; + s32 idx = effect->Parameters->findAttribute(wrapsName.c_str()); + if ( idx >= 0 ) + twu = (video::E_TEXTURE_CLAMP)(effect->Parameters->getAttributeAsInt(idx)); + video::E_TEXTURE_CLAMP twv = video::ETC_REPEAT; + idx = effect->Parameters->findAttribute(wraptName.c_str()); + if ( idx >= 0 ) + twv = (video::E_TEXTURE_CLAMP)(effect->Parameters->getAttributeAsInt(idx)); + video::E_TEXTURE_CLAMP twr = video::ETC_REPEAT; + idx = effect->Parameters->findAttribute(wrappName.c_str()); + if ( idx >= 0 ) + twr = (video::E_TEXTURE_CLAMP)(effect->Parameters->getAttributeAsInt(idx)); + else + { + // for downward compatibility with older Irrlicht collada writer + idx = effect->Parameters->findAttribute(wraprName.c_str()); + if ( idx >= 0 ) + twr = (video::E_TEXTURE_CLAMP)(effect->Parameters->getAttributeAsInt(idx)); + } + + for (u32 i=0; iMat.TextureLayer[i].TextureWrapU = twu; + effect->Mat.TextureLayer[i].TextureWrapV = twv; + effect->Mat.TextureLayer[i].TextureWrapW = twr; + } + + effect->Mat.setFlag(video::EMF_BILINEAR_FILTER, effect->Parameters->getAttributeAsBool("bilinear")); + effect->Mat.setFlag(video::EMF_TRILINEAR_FILTER, effect->Parameters->getAttributeAsBool("trilinear")); + effect->Mat.setFlag(video::EMF_ANISOTROPIC_FILTER, effect->Parameters->getAttributeAsBool("anisotropic")); +} + + +const SColladaMaterial* CColladaFileLoader::findMaterial(const core::stringc& materialName) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA find material", materialName, ELL_DEBUG); + #endif + + // do a quick lookup in the materials + SColladaMaterial matToFind; + matToFind.Id = materialName; + s32 mat = Materials.binary_search(matToFind); + if (mat == -1) + return 0; + // instantiate the material effect if needed + if (Materials[mat].InstanceEffectId.size() != 0) + { + // do a quick lookup in the effects + SColladaEffect effectToFind; + effectToFind.Id = Materials[mat].InstanceEffectId; + s32 effect = Effects.binary_search(effectToFind); + if (effect != -1) + { + // found the effect, instantiate by copying into the material + Materials[mat].Mat = Effects[effect].Mat; + if (Effects[effect].Textures.size()) + Materials[mat].Mat.setTexture(0, getTextureFromImage(Effects[effect].Textures[0], &(Effects[effect]))); + Materials[mat].Transparency = Effects[effect].Transparency; + // and indicate the material is instantiated by removing the effect ref + Materials[mat].InstanceEffectId = ""; + } + else + return 0; + } + return &Materials[mat]; +} + + +void CColladaFileLoader::readBindMaterialSection(io::IXMLReaderUTF8* reader, const core::stringc & id) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading bind material", ELL_DEBUG); + #endif + + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (instanceMaterialName == reader->getNodeName()) + { + // the symbol to retarget, and the target material + core::stringc meshbufferReference = reader->getAttributeValue("symbol"); + if (meshbufferReference.size()==0) + continue; + core::stringc target = reader->getAttributeValue("target"); + uriToId(target); + if (target.size()==0) + continue; + const SColladaMaterial * material = findMaterial(target); + if (!material) + continue; + // bind any pending materials for this node + meshbufferReference = id+"/"+meshbufferReference; +#ifdef COLLADA_READER_DEBUG + os::Printer::log((core::stringc("Material binding: ")+meshbufferReference+" "+target).c_str(), ELL_DEBUG); +#endif + if (MaterialsToBind.find(meshbufferReference)) + { + core::array & toBind + = MeshesToBind[MaterialsToBind[meshbufferReference]]; +#ifdef COLLADA_READER_DEBUG + os::Printer::log("Material binding now ",material->Id.c_str(), ELL_DEBUG); + os::Printer::log("#meshbuffers",core::stringc(toBind.size()).c_str(), ELL_DEBUG); +#endif + SMesh tmpmesh; + for (u32 i = 0; i < toBind.size(); ++i) + { + toBind[i]->getMaterial() = material->Mat; + tmpmesh.addMeshBuffer(toBind[i]); + + if ((material->Transparency!=0.0f) && (material->Transparency!=1.0f)) + { + toBind[i]->getMaterial().MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + toBind[i]->getMaterial().ZWriteEnable = video::EZW_OFF; + } + } + SceneManager->getMeshManipulator()->setVertexColors(&tmpmesh,material->Mat.DiffuseColor); + if ((material->Transparency!=0.0f) && (material->Transparency!=1.0f)) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA found transparency material", core::stringc(material->Transparency).c_str(), ELL_DEBUG); + #endif + SceneManager->getMeshManipulator()->setVertexColorAlpha(&tmpmesh, core::floor32(material->Transparency*255.0f)); + } + } + } + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END && + bindMaterialName == reader->getNodeName()) + break; + } +} + + +//! reads a element and stores it as mesh if possible +void CColladaFileLoader::readGeometry(io::IXMLReaderUTF8* reader) +{ + core::stringc id = readId(reader); + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading geometry", id, ELL_DEBUG); + #endif + + SAnimatedMesh* amesh = new SAnimatedMesh(); + scene::SMesh* mesh = new SMesh(); + amesh->addMesh(mesh); + core::array sources; + bool okToReadArray = false; + + // handles geometry node and the mesh children in this loop + // read sources with arrays and accessor for each mesh + if (!reader->isEmptyElement()) + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + const char* nodeName = reader->getNodeName(); + if (meshSectionName == nodeName) + { + // inside a mesh section. Don't have to do anything here. + } + else + if (sourceSectionName == nodeName) + { + // create a new source + sources.push_back(SSource()); + sources.getLast().Id = readId(reader); + + #ifdef COLLADA_READER_DEBUG + os::Printer::log("Reading source", sources.getLast().Id.c_str(), ELL_DEBUG); + #endif + } + else + if (arraySectionName == nodeName || floatArraySectionName == nodeName || intArraySectionName == nodeName) + { + // create a new array and read it. + if (!sources.empty()) + { + sources.getLast().Array.Name = readId(reader); + + int count = reader->getAttributeValueAsInt("count"); + sources.getLast().Array.Data.set_used(count); // pre allocate + + // check if type of array is ok + const char* type = reader->getAttributeValue("type"); + okToReadArray = (type && (!strcmp("float", type) || !strcmp("int", type))) || floatArraySectionName == nodeName || intArraySectionName == nodeName; + + #ifdef COLLADA_READER_DEBUG + os::Printer::log("Read array", sources.getLast().Array.Name.c_str(), ELL_DEBUG); + #endif + } + #ifdef COLLADA_READER_DEBUG + else + os::Printer::log("Warning, array outside source found", + readId(reader).c_str(), ELL_DEBUG); + #endif + + } + else + if (accessorSectionName == nodeName) // child of source (below a technique tag) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("Reading accessor", ELL_DEBUG); + #endif + SAccessor accessor; + accessor.Count = reader->getAttributeValueAsInt("count"); + accessor.Offset = reader->getAttributeValueAsInt("offset"); + accessor.Stride = reader->getAttributeValueAsInt("stride"); + if (accessor.Stride == 0) + accessor.Stride = 1; + + // the accessor contains some information on how to access (boi!) the array, + // the info is stored in collada style parameters, so just read them. + readColladaParameters(reader, accessorSectionName); + if (!sources.empty()) + { + sources.getLast().Accessors.push_back(accessor); + sources.getLast().Accessors.getLast().Parameters = ColladaParameters; + } + } + else + if (verticesSectionName == nodeName) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("Reading vertices", ELL_DEBUG); + #endif + // read vertex input position source + readColladaInputs(reader, verticesSectionName); + } + else + // lines and linestrips missing + if (polygonsSectionName == nodeName || + polylistSectionName == nodeName || + trianglesSectionName == nodeName) + { + // read polygons section + readPolygonSection(reader, sources, mesh, id); + } + else + // trifans, and tristrips missing + if (doubleSidedNodeName == reader->getNodeName()) + { + // read the extra flag for double sided polys + s32 doubleSided = 0; + readIntsInsideElement(reader,&doubleSided,1); + if (doubleSided) + { + #ifdef COLLADA_READER_DEBUG + os::Printer::log("Setting double sided flag for mesh.", ELL_DEBUG); + #endif + amesh->setMaterialFlag(irr::video::EMF_BACK_FACE_CULLING,false); + } + } + else + // techniqueCommon or 'technique profile=common' must not be skipped + if ((techniqueCommonSectionName != nodeName) // Collada 1.2/1.3 + && (techniqueNodeName != nodeName) // Collada 1.4+ + && (extraNodeName != nodeName)) + { + os::Printer::log("COLLADA loader warning: Wrong tag usage found in geometry", reader->getNodeName(), ELL_WARNING); + skipSection(reader, true); // ignore all other sections + } + } // end if node type is element + else + if (reader->getNodeType() == io::EXN_TEXT) + { + // read array data + if (okToReadArray && !sources.empty()) + { + core::array& a = sources.getLast().Array.Data; + core::stringc data = reader->getNodeData(); + data.trim(); + const c8* p = &data[0]; + + for (u32 i=0; igetNodeType() == io::EXN_ELEMENT_END) + { + if (geometrySectionName == reader->getNodeName()) + { + // end of geometry section reached, cancel out + break; + } + } + } // end while reader->read(); + + // add mesh as geometry + + mesh->recalculateBoundingBox(); + amesh->recalculateBoundingBox(); + + // create virtual file name + io::path filename = CurrentlyLoadingMesh; + filename += '#'; + filename += id; + + // add to scene manager + if (LoadedMeshCount) + { + SceneManager->getMeshCache()->addMesh(filename.c_str(), amesh); + os::Printer::log("Added COLLADA mesh", filename.c_str(), ELL_DEBUG); + } + else + { + FirstLoadedMeshName = filename; + FirstLoadedMesh = amesh; + FirstLoadedMesh->grab(); + } + + ++LoadedMeshCount; + mesh->drop(); + amesh->drop(); + + // create geometry prefab + u32 i; + for (i=0; igetId()==id) + { + ((CGeometryPrefab*)Prefabs[i])->Mesh=mesh; + break; + } + } + if (i==Prefabs.size()) + { + CGeometryPrefab* prefab = new CGeometryPrefab(id); + prefab->Mesh = mesh; + Prefabs.push_back(prefab); + } + + // store as dummy mesh if no instances will be created + if (!CreateInstances && !DummyMesh) + { + DummyMesh = amesh; + DummyMesh->grab(); + } +} + + +struct SPolygon +{ + core::array Indices; +}; + +//! reads a polygons section and creates a mesh from it +void CColladaFileLoader::readPolygonSection(io::IXMLReaderUTF8* reader, + core::array& sources, scene::SMesh* mesh, + const core::stringc& geometryId) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading polygon section", ELL_DEBUG); + #endif + + core::stringc materialName = reader->getAttributeValue("material"); + + core::stringc polygonType = reader->getNodeName(); + const int polygonCount = reader->getAttributeValueAsInt("count"); // Not useful because it only determines the number of primitives, which have arbitrary vertices in case of polygon + core::array polygons; + if (polygonType == polygonsSectionName) + polygons.reallocate(polygonCount); + core::array vCounts; + bool parsePolygonOK = false; + bool parseVcountOK = false; + u32 inputSemanticCount = 0; + u32 maxOffset = 0; + core::array localInputs; + + // read all and primitives + if (!reader->isEmptyElement()) + while(reader->read()) + { + const char* nodeName = reader->getNodeName(); + + if (reader->getNodeType() == io::EXN_ELEMENT) + { + // polygon node may contain params + if (inputTagName == nodeName) + { + // read input tag + readColladaInput(reader, localInputs); + + // resolve input source + SColladaInput& inp = localInputs.getLast(); + + // get input source array id, if it is a vertex input, take + // the -source attribute. + if (inp.Semantic == ECIS_VERTEX) + { + inp.Source = Inputs[0].Source; + for (u32 i=1; igetNodeType() == io::EXN_ELEMENT_END) + { + if (primitivesName == nodeName) + parsePolygonOK = false; // end parsing a polygon + else + if (vcountName == nodeName) + parseVcountOK = false; // end parsing vcounts + else + if (polygonType == nodeName) + break; // cancel out and create mesh + + } // end is element end + else + if (reader->getNodeType() == io::EXN_TEXT) + { + if (parseVcountOK) + { + core::stringc data = reader->getNodeData(); + data.trim(); + const c8* p = &data[0]; + while(*p) + { + findNextNoneWhiteSpace(&p); + if (*p) + vCounts.push_back(readInt(&p)); + } + parseVcountOK = false; + } + else + if (parsePolygonOK && polygons.size()) + { + core::stringc data = reader->getNodeData(); + data.trim(); + const c8* p = &data[0]; + SPolygon& poly = polygons.getLast(); + if (polygonType == polygonsSectionName) + poly.Indices.reallocate((maxOffset+1)*3); + else + poly.Indices.reallocate(polygonCount*(maxOffset+1)*3); + + if (vCounts.empty()) + { + while(*p) + { + findNextNoneWhiteSpace(&p); + poly.Indices.push_back(readInt(&p)); + } + } + else + { + for (u32 i = 0; i < vCounts.size(); i++) + { + const int polyVCount = vCounts[i]; + core::array polyCorners; + + for (u32 j = 0; j < polyVCount * inputSemanticCount; j++) + { + if (!*p) + break; + findNextNoneWhiteSpace(&p); + polyCorners.push_back(readInt(&p)); + } + + while (polyCorners.size() >= 3 * inputSemanticCount) + { + // add one triangle's worth of indices + for (u32 k = 0; k < inputSemanticCount * 3; ++k) + { + poly.Indices.push_back(polyCorners[k]); + } + + // remove one corner from our poly + polyCorners.erase(inputSemanticCount,inputSemanticCount); + } + polyCorners.clear(); + } + vCounts.clear(); + } + parsePolygonOK = false; + } + } + } // end while reader->read() + + // find source array (we'll ignore accessors for this implementation) + for (u32 i=0; i vertMap; + + for (u32 i=0; i indices; + const u32 vertexCount = polygons[i].Indices.size() / maxOffset; + mbuffer->Vertices.reallocate(mbuffer->Vertices.size()+vertexCount); + + // for all index/semantic groups + for (u32 v=0; v::Node* n = vertMap.find(vtx); + if (n) + { + indices.push_back(n->getValue()); + } + else + { + indices.push_back(mbuffer->getVertexCount()); + mbuffer->Vertices.push_back(vtx); + vertMap.insert(vtx, mbuffer->getVertexCount()-1); + } + } // end for all vertices + + if (polygonsSectionName == polygonType && + indices.size() > 3) + { + // need to tessellate for polygons of 4 or more vertices + // for now we naively turn interpret it as a triangle fan + // as full tessellation is problematic + for (u32 ind = 0; ind+2 < indices.size(); ++ind) + { + mbuffer->Indices.push_back(indices[0]); + mbuffer->Indices.push_back(indices[ind+2]); + mbuffer->Indices.push_back(indices[ind+1]); + } + } + else + { + // it's just triangles + for (u32 ind = 0; ind < indices.size(); ind+=3) + { + mbuffer->Indices.push_back(indices[ind+2]); + mbuffer->Indices.push_back(indices[ind+1]); + mbuffer->Indices.push_back(indices[ind+0]); + } + } + + } // end for all polygons + } + else + { + // lightmap mesh buffer + + scene::SMeshBufferLightMap* mbuffer = new SMeshBufferLightMap(); + buffer = mbuffer; + + for (u32 i=0; iVertices.reallocate(mbuffer->Vertices.size()+vertexCount); + // for all vertices in array + for (u32 v=0; vVertices.push_back(vtx); + + } // end for all vertices + + // add vertex indices + const u32 oldVertexCount = mbuffer->Vertices.size() - vertexCount; + for (u32 face=0; faceIndices.push_back(oldVertexCount + 0); + mbuffer->Indices.push_back(oldVertexCount + 1 + face); + mbuffer->Indices.push_back(oldVertexCount + 2 + face); + } + + } // end for all polygons + } + + const SColladaMaterial* m = findMaterial(materialName); + if (m) + { + buffer->getMaterial() = m->Mat; + SMesh tmpmesh; + tmpmesh.addMeshBuffer(buffer); + SceneManager->getMeshManipulator()->setVertexColors(&tmpmesh,m->Mat.DiffuseColor); + if (m->Transparency != 1.0f) + SceneManager->getMeshManipulator()->setVertexColorAlpha(&tmpmesh,core::floor32(m->Transparency*255.0f)); + } + // add future bind reference for the material + core::stringc meshbufferReference = geometryId+"/"+materialName; + if (!MaterialsToBind.find(meshbufferReference)) + { + MaterialsToBind[meshbufferReference] = MeshesToBind.size(); + MeshesToBind.push_back(core::array()); + } + MeshesToBind[MaterialsToBind[meshbufferReference]].push_back(buffer); + + // calculate normals if there is no slot for it + + if (!normalSlotCount) + SceneManager->getMeshManipulator()->recalculateNormals(buffer, true); + + // recalculate bounding box + buffer->recalculateBoundingBox(); + + // add mesh buffer + mesh->addMeshBuffer(buffer); + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA added meshbuffer", core::stringc(buffer->getVertexCount())+" vertices, "+core::stringc(buffer->getIndexCount())+" indices.", ELL_DEBUG); + #endif + + buffer->drop(); +} + + +//! reads a element and stores it as prefab +void CColladaFileLoader::readLightPrefab(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading light prefab", ELL_DEBUG); + #endif + + CLightPrefab* prefab = new CLightPrefab(readId(reader)); + + if (!reader->isEmptyElement()) + { + if (Version >= 10400) // start with 1.4 + { + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (pointSectionName == reader->getNodeName()) + prefab->LightData.Type=video::ELT_POINT; + else + if (directionalSectionName == reader->getNodeName()) + prefab->LightData.Type=video::ELT_DIRECTIONAL; + else + if (spotSectionName == reader->getNodeName()) + prefab->LightData.Type=video::ELT_SPOT; + else + if (ambientSectionName == reader->getNodeName()) + prefab->LightData.Type=ELT_AMBIENT; + else + if (colorNodeName == reader->getNodeName()) + prefab->LightData.DiffuseColor=readColorNode(reader); + else + if (constantAttenuationNodeName == reader->getNodeName()) + readFloatsInsideElement(reader,&prefab->LightData.Attenuation.X,1); + else + if (linearAttenuationNodeName == reader->getNodeName()) + readFloatsInsideElement(reader,&prefab->LightData.Attenuation.Y,1); + else + if (quadraticAttenuationNodeName == reader->getNodeName()) + readFloatsInsideElement(reader,&prefab->LightData.Attenuation.Z,1); + else + if (falloffAngleNodeName == reader->getNodeName()) + { + readFloatsInsideElement(reader,&prefab->LightData.OuterCone,1); + prefab->LightData.OuterCone *= core::DEGTORAD; + } + else + if (falloffExponentNodeName == reader->getNodeName()) + readFloatsInsideElement(reader,&prefab->LightData.Falloff,1); + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + { + if ((pointSectionName == reader->getNodeName()) || + (directionalSectionName == reader->getNodeName()) || + (spotSectionName == reader->getNodeName()) || + (ambientSectionName == reader->getNodeName())) + break; + } + } + } + else + { + readColladaParameters(reader, lightPrefabName); + + SColladaParam* p = getColladaParameter(ECPN_COLOR); + if (p && p->Type == ECPT_FLOAT3) + prefab->LightData.DiffuseColor.set(p->Floats[0], p->Floats[1], p->Floats[2]); + } + } + + Prefabs.push_back(prefab); +} + + +//! returns a collada parameter or none if not found +SColladaParam* CColladaFileLoader::getColladaParameter(ECOLLADA_PARAM_NAME name) +{ + for (u32 i=0; i& inputs) +{ + // parse param + SColladaInput p; + + // get type + core::stringc semanticName = reader->getAttributeValue("semantic"); + for (u32 i=0; inputSemanticNames[i]; ++i) + { + if (semanticName == inputSemanticNames[i]) + { + p.Semantic = (ECOLLADA_INPUT_SEMANTIC)i; + break; + } + } + + // get source + p.Source = reader->getAttributeValue("source"); + if (reader->getAttributeValue("offset")) // Collada 1.4+ + p.Offset = (u32)reader->getAttributeValueAsInt("offset"); + else // Collada 1.2/1.3 + p.Offset = (u32)reader->getAttributeValueAsInt("idx"); + p.Set = (u32)reader->getAttributeValueAsInt("set"); + + // add input + inputs.push_back(p); +} + +//! parses all collada inputs inside an element and stores them in Inputs +void CColladaFileLoader::readColladaInputs(io::IXMLReaderUTF8* reader, const core::stringc& parentName) +{ + Inputs.clear(); + + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT && + inputTagName == reader->getNodeName()) + { + readColladaInput(reader, Inputs); + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + { + if (parentName == reader->getNodeName()) + return; // end of parent reached + } + + } // end while reader->read(); +} + +//! parses all collada parameters inside an element and stores them in ColladaParameters +void CColladaFileLoader::readColladaParameters(io::IXMLReaderUTF8* reader, + const core::stringc& parentName) +{ + ColladaParameters.clear(); + + const char* const paramNames[] = {"COLOR", "AMBIENT", "DIFFUSE", + "SPECULAR", "SHININESS", "YFOV", "ZNEAR", "ZFAR", 0}; + + const char* const typeNames[] = {"float", "float2", "float3", 0}; + + while(reader->read()) + { + const char* nodeName = reader->getNodeName(); + if (reader->getNodeType() == io::EXN_ELEMENT && + paramTagName == nodeName) + { + // parse param + SColladaParam p; + + // get type + u32 i; + core::stringc typeName = reader->getAttributeValue("type"); + for (i=0; typeNames[i]; ++i) + if (typeName == typeNames[i]) + { + p.Type = (ECOLLADA_PARAM_TYPE)i; + break; + } + + // get name + core::stringc nameName = reader->getAttributeValue("name"); + for (i=0; typeNames[i]; ++i) + if (nameName == paramNames[i]) + { + p.Name = (ECOLLADA_PARAM_NAME)i; + break; + } + + // read parameter data inside parameter tags + switch(p.Type) + { + case ECPT_FLOAT: + case ECPT_FLOAT2: + case ECPT_FLOAT3: + case ECPT_FLOAT4: + readFloatsInsideElement(reader, p.Floats, p.Type - ECPT_FLOAT + 1); + break; + + // TODO: other types of data (ints, bools or whatever) + default: + break; + } + + // add param + ColladaParameters.push_back(p); + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + { + if (parentName == reader->getNodeName()) + return; // end of parent reached + } + + } // end while reader->read(); +} + + +//! parses a float from a char pointer and moves the pointer +//! to the end of the parsed float +inline f32 CColladaFileLoader::readFloat(const c8** p) +{ + f32 ftmp; + *p = core::fast_atof_move(*p, ftmp); + return ftmp; +} + + +//! parses an int from a char pointer and moves the pointer to +//! the end of the parsed float +inline s32 CColladaFileLoader::readInt(const c8** p) +{ + return (s32)readFloat(p); +} + + +//! places pointer to next begin of a token +void CColladaFileLoader::findNextNoneWhiteSpace(const c8** start) +{ + const c8* p = *start; + + while(*p && (*p==' ' || *p=='\n' || *p=='\r' || *p=='\t')) + ++p; + + // TODO: skip comments + + *start = p; +} + + +//! reads floats from inside of xml element until end of xml element +void CColladaFileLoader::readFloatsInsideElement(io::IXMLReaderUTF8* reader, f32* floats, u32 count) +{ + if (reader->isEmptyElement()) + return; + + while(reader->read()) + { + // TODO: check for comments inside the element + // and ignore them. + + if (reader->getNodeType() == io::EXN_TEXT) + { + // parse float data + core::stringc data = reader->getNodeData(); + data.trim(); + const c8* p = &data[0]; + + for (u32 i=0; igetNodeType() == io::EXN_ELEMENT_END) + break; // end parsing text + } +} + + +//! reads ints from inside of xml element until end of xml element +void CColladaFileLoader::readIntsInsideElement(io::IXMLReaderUTF8* reader, s32* ints, u32 count) +{ + if (reader->isEmptyElement()) + return; + + while(reader->read()) + { + // TODO: check for comments inside the element + // and ignore them. + + if (reader->getNodeType() == io::EXN_TEXT) + { + // parse float data + core::stringc data = reader->getNodeData(); + data.trim(); + const c8* p = &data[0]; + + for (u32 i=0; igetNodeType() == io::EXN_ELEMENT_END) + break; // end parsing text + } +} + + +video::SColorf CColladaFileLoader::readColorNode(io::IXMLReaderUTF8* reader) +{ + if (reader->getNodeType() == io::EXN_ELEMENT && + colorNodeName == reader->getNodeName()) + { + f32 color[4]; + readFloatsInsideElement(reader,color,4); + return video::SColorf(color[0], color[1], color[2], color[3]); + } + + return video::SColorf(); +} + + +f32 CColladaFileLoader::readFloatNode(io::IXMLReaderUTF8* reader) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading ", ELL_DEBUG); + #endif + + f32 result = 0.0f; + if (reader->getNodeType() == io::EXN_ELEMENT && + floatNodeName == reader->getNodeName()) + { + readFloatsInsideElement(reader,&result,1); + } + + return result; +} + + +//! clears all loaded data +void CColladaFileLoader::clearData() +{ + // delete all prefabs + + for (u32 i=0; idrop(); + + Prefabs.clear(); + + // clear all parameters + ColladaParameters.clear(); + + // clear all materials + Images.clear(); + + // clear all materials + Textures.clear(); + + // clear all materials + Materials.clear(); + + // clear all inputs + Inputs.clear(); + + // clear all effects + for ( u32 i=0; idrop(); + Effects.clear(); + + // clear all the materials to bind + MaterialsToBind.clear(); + MeshesToBind.clear(); +} + + +//! changes the XML URI into an internal id +void CColladaFileLoader::uriToId(core::stringc& str) +{ + // Currently, we only remove the # from the beginning + // as we don't support referencing other files. + if (!str.size()) + return; + + if (str[0] == '#') + str.erase(0); +} + + +//! read Collada Id, uses id or name if id is missing +core::stringc CColladaFileLoader::readId(io::IXMLReaderUTF8* reader) +{ + core::stringc id = reader->getAttributeValue("id"); + if (id.size()==0) + id = reader->getAttributeValue("name"); + return id; +} + + +//! create an Irrlicht texture from the reference +video::ITexture* CColladaFileLoader::getTextureFromImage(core::stringc uri, SColladaEffect * effect) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA searching texture", uri, ELL_DEBUG); + #endif + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + for (;;) + { + uriToId(uri); + for (u32 i=0; igetTexture( Images[i].Source ) : NULL; + } + else + if (Images[i].Source.size()) + { + //const u32 size = Images[i].Dimension.getArea(); + const u32 size = Images[i].Dimension.Width * Images[i].Dimension.Height;; + u32* data = new u32[size]; // we assume RGBA + u32* ptrdest = data; + const c8* ptrsrc = Images[i].Source.c_str(); + for (u32 j=0; jcreateImageFromData(video::ECF_A8R8G8B8, Images[i].Dimension, data, true, true); + video::ITexture* tex = driver->addTexture((CurrentlyLoadingMesh+"#"+Images[i].Id).c_str(), img); + img->drop(); + return tex; + } + break; + } + } + if (effect && effect->Parameters->getAttributeType(uri.c_str())==io::EAT_STRING) + { + uri = effect->Parameters->getAttributeAsString(uri.c_str()); +#ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA now searching texture", uri.c_str(), ELL_DEBUG); +#endif + } + else + break; + } + return 0; +} + + +//! read a parameter and value +void CColladaFileLoader::readParameter(io::IXMLReaderUTF8* reader, io::IAttributes* parameters) +{ + #ifdef COLLADA_READER_DEBUG + os::Printer::log("COLLADA reading parameter", ELL_DEBUG); + #endif + + if ( !parameters ) + return; + + const core::stringc name = reader->getAttributeValue("sid"); + if (!reader->isEmptyElement()) + { + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (floatNodeName == reader->getNodeName()) + { + const f32 f = readFloatNode(reader); + parameters->addFloat(name.c_str(), f); + } + else + if (float2NodeName == reader->getNodeName()) + { + f32 f[2]; + readFloatsInsideElement(reader, f, 2); +// Parameters.addVector2d(name.c_str(), core::vector2df(f[0],f[1])); + } + else + if (float3NodeName == reader->getNodeName()) + { + f32 f[3]; + readFloatsInsideElement(reader, f, 3); + parameters->addVector3d(name.c_str(), core::vector3df(f[0],f[1],f[2])); + } + else + if ((initFromName == reader->getNodeName()) || + (sourceSectionName == reader->getNodeName())) + { + reader->read(); + parameters->addString(name.c_str(), reader->getNodeData()); + } + else + if (wrapsName == reader->getNodeName()) + { + reader->read(); + const core::stringc val = reader->getNodeData(); + if (val == "WRAP") + parameters->addInt(wrapsName.c_str(), (int)video::ETC_REPEAT); + else if ( val== "MIRROR") + parameters->addInt(wrapsName.c_str(), (int)video::ETC_MIRROR); + else if ( val== "CLAMP") + parameters->addInt(wrapsName.c_str(), (int)video::ETC_CLAMP_TO_EDGE); + else if ( val== "BORDER") + parameters->addInt(wrapsName.c_str(), (int)video::ETC_CLAMP_TO_BORDER); + else if ( val== "NONE") + parameters->addInt(wrapsName.c_str(), (int)video::ETC_CLAMP_TO_BORDER); + } + else + if (wraptName == reader->getNodeName()) + { + reader->read(); + const core::stringc val = reader->getNodeData(); + if (val == "WRAP") + parameters->addInt(wraptName.c_str(), (int)video::ETC_REPEAT); + else if ( val== "MIRROR") + parameters->addInt(wraptName.c_str(), (int)video::ETC_MIRROR); + else if ( val== "CLAMP") + parameters->addInt(wraptName.c_str(), (int)video::ETC_CLAMP_TO_EDGE); + else if ( val== "BORDER") + parameters->addInt(wraptName.c_str(), (int)video::ETC_CLAMP_TO_BORDER); + else if ( val== "NONE") + parameters->addInt(wraptName.c_str(), (int)video::ETC_CLAMP_TO_BORDER); + } + else + if (minfilterName == reader->getNodeName()) + { + reader->read(); + const core::stringc val = reader->getNodeData(); + if (val == "LINEAR_MIPMAP_LINEAR") + parameters->addBool("trilinear", true); + else + if (val == "LINEAR_MIPMAP_NEAREST") + parameters->addBool("bilinear", true); + } + else + if (magfilterName == reader->getNodeName()) + { + reader->read(); + const core::stringc val = reader->getNodeData(); + if (val != "LINEAR") + { + parameters->addBool("bilinear", false); + parameters->addBool("trilinear", false); + } + } + else + if (mipfilterName == reader->getNodeName()) + { + parameters->addBool("anisotropic", true); + } + } + else + if(reader->getNodeType() == io::EXN_ELEMENT_END) + { + if (newParamName == reader->getNodeName()) + break; + } + } + } +} + +core::matrix4 CColladaFileLoader::flipZAxis(const core::matrix4& m) +{ + core::matrix4 matrix(m); + matrix[2] *= -1.f; + matrix[6] *= -1.f; + matrix[8] *= -1.f; + matrix[9] *= -1.f; + matrix[11] *= -1.f; + matrix[14] *= -1.f; + + return matrix; +} + +void CColladaFileLoader::unescape(irr::core::stringc& uri) +{ + u32 len = uri.size(); + for (u32 i=0; i Textures; + video::SMaterial Mat; + // TODO: Parameters looks somewhat lazy workaround, I think we should really read all parameters correct. + io::IAttributes * Parameters; + + inline bool operator< (const SColladaEffect & other) const + { + return Id < other.Id; + } +}; + + +struct SNumberArray // for storing float and int arrays +{ + core::stringc Name; + core::array Data; +}; + +struct SAccessor +{ + SAccessor() + : Count(0), Offset(0), Stride(1) {} + // I don't store the source of the accessor here because I assume + // it to use the array of the source this accessor is located in. + + int Count; + int Offset; + int Stride; + + core::array Parameters; // parameters defining the accessor +}; + +struct SSource +{ + core::stringc Id; + SNumberArray Array; + core::array Accessors; +}; + +class CScenePrefab; + +//! Meshloader capable of loading COLLADA meshes and scene descriptions into Irrlicht. +class CColladaFileLoader : public IMeshLoader +{ +public: + + //! Constructor + CColladaFileLoader(scene::ISceneManager* smgr, io::IFileSystem* fs); + + //! destructor + virtual ~CColladaFileLoader(); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".cob") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! creates/loads an animated mesh from the file. + //! \return Pointer to the created mesh. Returns 0 if loading failed. + //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). + //! See IReferenceCounted::drop() for more information. + virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_; + +private: + + //! skips an (unknown) section in the collada document + void skipSection(io::IXMLReaderUTF8* reader, bool reportSkipping); + + //! reads the section and its content + void readColladaSection(io::IXMLReaderUTF8* reader); + + //! reads a section and its content + void readLibrarySection(io::IXMLReaderUTF8* reader); + + //! reads a element and stores it as a prefab + void readVisualScene(io::IXMLReaderUTF8* reader); + + //! reads a section and its content + void readSceneSection(io::IXMLReaderUTF8* reader); + + //! reads a section and its content + void readAssetSection(io::IXMLReaderUTF8* reader); + + //! reads a section and its content + //! if a prefab pointer is passed the nodes are created as scene prefabs children of that prefab + void readNodeSection(io::IXMLReaderUTF8* reader, scene::ISceneNode* parent, CScenePrefab* p=0); + + //! reads a element and its content and creates a matrix from it + core::matrix4 readLookAtNode(io::IXMLReaderUTF8* reader); + + //! reads a element and its content and creates a matrix from it + core::matrix4 readMatrixNode(io::IXMLReaderUTF8* reader); + + //! reads a element and its content and creates a matrix from it + core::matrix4 readPerspectiveNode(io::IXMLReaderUTF8* reader); + + //! reads a element and its content and creates a matrix from it + core::matrix4 readRotateNode(io::IXMLReaderUTF8* reader); + + //! reads a element and its content and creates a matrix from it + core::matrix4 readSkewNode(io::IXMLReaderUTF8* reader); + + //! reads a element and its content and stores it in bbox + void readBboxNode(io::IXMLReaderUTF8* reader, core::aabbox3df& bbox); + + //! reads a element and its content and creates a matrix from it + core::matrix4 readScaleNode(io::IXMLReaderUTF8* reader); + + //! reads a element and its content and creates a matrix from it + core::matrix4 readTranslateNode(io::IXMLReaderUTF8* reader); + + //! reads a element + video::SColorf readColorNode(io::IXMLReaderUTF8* reader); + + //! reads a element + f32 readFloatNode(io::IXMLReaderUTF8* reader); + + //! reads a node + void readInstanceNode(io::IXMLReaderUTF8* reader, + scene::ISceneNode* parent, scene::ISceneNode** outNode, + CScenePrefab* p=0, const core::stringc& type=core::stringc()); + + //! creates a scene node from Prefabs (with name given in 'url') + void instantiateNode(scene::ISceneNode* parent, scene::ISceneNode** outNode=0, + CScenePrefab* p=0, const core::stringc& url="", + const core::stringc& type=core::stringc()); + + //! reads a element and stores it as prefab + void readLightPrefab(io::IXMLReaderUTF8* reader); + + //! reads a element and stores it as prefab + void readCameraPrefab(io::IXMLReaderUTF8* reader); + + //! reads a element and stores it in the image section + void readImage(io::IXMLReaderUTF8* reader); + + //! reads a element and stores it in the texture section + void readTexture(io::IXMLReaderUTF8* reader); + + //! reads a element and stores it in the material section + void readMaterial(io::IXMLReaderUTF8* reader); + + //! reads a element and stores it in the effects section + void readEffect(io::IXMLReaderUTF8* reader, SColladaEffect * effect = 0); + + //! reads a element and stores it as mesh if possible + void readGeometry(io::IXMLReaderUTF8* reader); + + //! parses a float from a char pointer and moves the pointer to + //! the end of the parsed float + inline f32 readFloat(const c8** p); + + //! parses an int from a char pointer and moves the pointer to + //! the end of the parsed float + inline s32 readInt(const c8** p); + + //! places pointer to next begin of a token + void findNextNoneWhiteSpace(const c8** p); + + //! reads floats from inside of xml element until end of xml element + void readFloatsInsideElement(io::IXMLReaderUTF8* reader, f32* floats, u32 count); + + //! reads ints from inside of xml element until end of xml element + void readIntsInsideElement(io::IXMLReaderUTF8* reader, s32* ints, u32 count); + + //! clears all loaded data + void clearData(); + + //! parses all collada parameters inside an element and stores them in ColladaParameters + void readColladaParameters(io::IXMLReaderUTF8* reader, const core::stringc& parentName); + + //! returns a collada parameter or none if not found + SColladaParam* getColladaParameter(ECOLLADA_PARAM_NAME name); + + //! parses all collada inputs inside an element and stores them in Inputs. Reads + //! until first tag which is not an input tag or the end of the parent is reached + void readColladaInputs(io::IXMLReaderUTF8* reader, const core::stringc& parentName); + + //! reads a collada input tag and adds it to the input parameter + void readColladaInput(io::IXMLReaderUTF8* reader, core::array& inputs); + + //! returns a collada input or none if not found + SColladaInput* getColladaInput(ECOLLADA_INPUT_SEMANTIC input); + + //! read Collada Id, uses id or name if id is missing + core::stringc readId(io::IXMLReaderUTF8* reader); + + //! changes the XML URI into an internal id + void uriToId(core::stringc& str); + + //! reads a polygons section and creates a mesh from it + void readPolygonSection(io::IXMLReaderUTF8* reader, + 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); + + //! create an Irrlicht texture from the SColladaImage + video::ITexture* getTextureFromImage(core::stringc uri, SColladaEffect * effect); + + //! read a parameter and value + void readParameter(io::IXMLReaderUTF8* reader, io::IAttributes* parameters); + + //! Flip z axis in matrix around to convert between right-handed and left-handed coordinate system. + //! Note that function is symmetric (no difference if called before or after a transpose). + core::matrix4 flipZAxis(const core::matrix4& m); + + //! replace escape characters with the unescaped ones + void unescape(irr::core::stringc& uri); + + scene::ISceneManager* SceneManager; + io::IFileSystem* FileSystem; + + scene::IAnimatedMesh* DummyMesh; + core::stringc CurrentlyLoadingMesh; + + scene::IAnimatedMesh* FirstLoadedMesh; + io::path FirstLoadedMeshName; + s32 LoadedMeshCount; + u32 Version; + bool FlipAxis; + + core::array Prefabs; + core::array ColladaParameters; + core::array Images; + core::array Textures; + core::array Materials; + core::array Inputs; + core::array Effects; + //! meshbuffer reference ("geomid/matname") -> index into MeshesToBind + core::map MaterialsToBind; + //! Array of buffers for each material binding + core::array< core::array > MeshesToBind; + + bool CreateInstances; + + struct EscapeCharacterURL + { + EscapeCharacterURL(irr::c8 c, const irr::c8* e) + : Character(c) + { + Escape = e; + } + + irr::c8 Character; // unescaped (like ' ') + irr::core::stringc Escape; // escaped (like '%20') + }; + irr::core::array EscapeCharsAnyURI; +}; + + + +//! following class is for holding and createing instances of library objects, +//! named prefabs in this loader. +class IColladaPrefab : public virtual IReferenceCounted +{ +public: + //! creates an instance of this prefab + virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent, + scene::ISceneManager* mgr) = 0; + + //! returns id of this prefab + virtual const core::stringc& getId() = 0; +}; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CColladaMeshWriter.cpp b/source/Irrlicht/CColladaMeshWriter.cpp new file mode 100644 index 00000000..52653a04 --- /dev/null +++ b/source/Irrlicht/CColladaMeshWriter.cpp @@ -0,0 +1,2309 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +// TODO: second UV-coordinates currently ignored in textures + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_COLLADA_WRITER_ + +#include "CColladaMeshWriter.h" +#include "os.h" +#include "IFileSystem.h" +#include "IWriteFile.h" +#include "IXMLWriter.h" +#include "IMesh.h" +#include "IAttributes.h" +#include "IAnimatedMeshSceneNode.h" +#include "IMeshSceneNode.h" +#include "ITerrainSceneNode.h" +#include "ILightSceneNode.h" +#include "ICameraSceneNode.h" +#include "ISceneManager.h" + +namespace irr +{ +namespace scene +{ + +//! Which lighting model should be used in the technique (FX) section when exporting effects (materials) +E_COLLADA_TECHNIQUE_FX CColladaMeshWriterProperties::getTechniqueFx(const video::SMaterial& material) const +{ + return ECTF_BLINN; +} + +//! Which texture index should be used when writing the texture of the given sampler color. +s32 CColladaMeshWriterProperties::getTextureIdx(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs) const +{ + // So far we just export in a way which is similar to how we import colladas. + // There might be better ways to do this, but I suppose it depends a lot for which target + // application we export, so in most cases it will have to be done in user-code anyway. + switch ( cs ) + { + case ECCS_DIFFUSE: + return 2; + case ECCS_AMBIENT: + return 1; + case ECCS_EMISSIVE: + return 0; + case ECCS_SPECULAR: + return 3; + case ECCS_TRANSPARENT: + return -1; + case ECCS_REFLECTIVE: + return -1; + }; + return -1; +} + +E_COLLADA_IRR_COLOR CColladaMeshWriterProperties::getColorMapping(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs) const +{ + switch ( cs ) + { + case ECCS_DIFFUSE: + return ECIC_DIFFUSE; + case ECCS_AMBIENT: + return ECIC_AMBIENT; + case ECCS_EMISSIVE: + return ECIC_EMISSIVE; + case ECCS_SPECULAR: + return ECIC_SPECULAR; + case ECCS_TRANSPARENT: + return ECIC_NONE; + case ECCS_REFLECTIVE: + return ECIC_CUSTOM; + }; + + return ECIC_NONE; +} + +//! Return custom colors for certain color types requested by collada. +video::SColor CColladaMeshWriterProperties::getCustomColor(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs) const +{ + return video::SColor(255, 0, 0, 0); +} + + +//! Return the settings for transparence +E_COLLADA_TRANSPARENT_FX CColladaMeshWriterProperties::getTransparentFx(const video::SMaterial& material) const +{ + // TODO: figure out best default mapping + return ECOF_A_ONE; +} + +//! Transparency value for the material. +f32 CColladaMeshWriterProperties::getTransparency(const video::SMaterial& material) const +{ + // TODO: figure out best default mapping + return -1.f; +} + +//! Reflectivity value for that material +f32 CColladaMeshWriterProperties::getReflectivity(const video::SMaterial& material) const +{ + // TODO: figure out best default mapping + return 0.f; +} + +//! Return index of refraction for that material +f32 CColladaMeshWriterProperties::getIndexOfRefraction(const video::SMaterial& material) const +{ + return -1.f; +} + +bool CColladaMeshWriterProperties::isExportable(const irr::scene::ISceneNode * node) const +{ + return node && node->isVisible(); +} + +IMesh* CColladaMeshWriterProperties::getMesh(irr::scene::ISceneNode * node) +{ + if ( !node ) + return 0; + if ( node->getType() == ESNT_ANIMATED_MESH ) + return static_cast(node)->getMesh()->getMesh(0); + // TODO: we need some ISceneNode::hasType() function to get rid of those checks + if ( node->getType() == ESNT_MESH + || node->getType() == ESNT_CUBE + || node->getType() == ESNT_SPHERE + || node->getType() == ESNT_WATER_SURFACE + || node->getType() == ESNT_Q3SHADER_SCENE_NODE + ) + return static_cast(node)->getMesh(); + if ( node->getType() == ESNT_TERRAIN ) + return static_cast(node)->getMesh(); + return 0; +} + +// Check if the node has it's own material overwriting the mesh-materials +bool CColladaMeshWriterProperties::useNodeMaterial(const scene::ISceneNode* node) const +{ + if ( !node ) + return false; + + // TODO: we need some ISceneNode::hasType() function to get rid of those checks + bool useMeshMaterial = ( (node->getType() == ESNT_MESH || + node->getType() == ESNT_CUBE || + node->getType() == ESNT_SPHERE || + node->getType() == ESNT_WATER_SURFACE || + node->getType() == ESNT_Q3SHADER_SCENE_NODE) + && static_cast(node)->isReadOnlyMaterials()) + + || (node->getType() == ESNT_ANIMATED_MESH + && static_cast(node)->isReadOnlyMaterials() ); + + return !useMeshMaterial; +} + + + +CColladaMeshWriterNames::CColladaMeshWriterNames(IColladaMeshWriter * writer) + : ColladaMeshWriter(writer) +{ +} + +irr::core::stringc CColladaMeshWriterNames::nameForMesh(const scene::IMesh* mesh, int instance) +{ + irr::core::stringc name("mesh"); + name += nameForPtr(mesh); + if ( instance > 0 ) + { + name += "i"; + name += irr::core::stringc(instance); + } + return ColladaMeshWriter->toNCName(name); +} + +irr::core::stringc CColladaMeshWriterNames::nameForNode(const scene::ISceneNode* node) +{ + irr::core::stringc name; + // Prefix, because xs:ID can't start with a number, also nicer name + if ( node && node->getType() == ESNT_LIGHT ) + name = "light"; + else + name = "node"; + name += nameForPtr(node); + if ( node ) + { + name += irr::core::stringc(node->getName()); + } + return ColladaMeshWriter->toNCName(name); +} + +irr::core::stringc CColladaMeshWriterNames::nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node) +{ + core::stringc strMat("mat"); + + bool nodeMaterial = ColladaMeshWriter->getProperties()->useNodeMaterial(node); + if ( nodeMaterial ) + { + strMat += "node"; + strMat += nameForPtr(node); + strMat += irr::core::stringc(node->getName()); + } + strMat += "mesh"; + strMat += nameForPtr(mesh); + strMat += materialId; + return ColladaMeshWriter->toNCName(strMat); +} + +irr::core::stringc CColladaMeshWriterNames::nameForPtr(const void* ptr) const +{ + c8 buf[32]; + snprintf_irr(buf, 32, "%p", ptr); + return irr::core::stringc(buf); +} + + + +CColladaMeshWriter::CColladaMeshWriter( ISceneManager * smgr, video::IVideoDriver* driver, + io::IFileSystem* fs) + : FileSystem(fs), VideoDriver(driver), Writer(0) +{ + + #ifdef _DEBUG + setDebugName("CColladaMeshWriter"); + #endif + + if (VideoDriver) + VideoDriver->grab(); + + if (FileSystem) + FileSystem->grab(); + + if ( smgr ) + setAmbientLight( smgr->getAmbientLight() ); + + // Escape some characters + // Slightly fuzzy definition for xs:anyURI. + // In theory not even spaces would need to be escaped, + // but it's strongly encouraged to do so and many Apps rely on it. + // If there are any apps out there which need more escapes we can add them. + // See https://www.w3schools.com/tags/ref_urlencode.asp for a list. + // NOTE: Never replace by empty characters (so not the place to delete chars!) + EscapeCharsAnyURI.push_back(EscapeCharacterURL(' ', "%20")); + EscapeCharsAnyURI.push_back(EscapeCharacterURL('#', "%23")); + EscapeCharsAnyURI.push_back(EscapeCharacterURL('%', "%25")); + + CColladaMeshWriterProperties * p = new CColladaMeshWriterProperties(); + setDefaultProperties(p); + setProperties(p); + p->drop(); + + CColladaMeshWriterNames * nameGenerator = new CColladaMeshWriterNames(this); + setDefaultNameGenerator(nameGenerator); + setNameGenerator(nameGenerator); + nameGenerator->drop(); +} + + +CColladaMeshWriter::~CColladaMeshWriter() +{ + if (VideoDriver) + VideoDriver->drop(); + + if (FileSystem) + FileSystem->drop(); +} + + +void CColladaMeshWriter::reset() +{ + LibraryImages.clear(); + Meshes.clear(); + LightNodes.clear(); + CameraNodes.clear(); + MaterialsWritten.clear(); + EffectsWritten.clear(); + MaterialNameCache.clear(); +} + +//! Returns the type of the mesh writer +EMESH_WRITER_TYPE CColladaMeshWriter::getType() const +{ + return EMWT_COLLADA; +} + +//! writes a scene starting with the given node +bool CColladaMeshWriter::writeScene(io::IWriteFile* file, scene::ISceneNode* root, int writeRoot) +{ + if (!file || !root) + return false; + + reset(); + + Writer = FileSystem->createXMLWriterUTF8(file); + + if (!Writer) + { + os::Printer::log("Could not write file", file->getFileName()); + return false; + } + + Directory = FileSystem->getFileDir(FileSystem->getAbsolutePath( file->getFileName() )); + + // make names for all nodes with exportable meshes + makeMeshNames(root); + + os::Printer::log("Writing scene", file->getFileName()); + + // write COLLADA header + + Writer->writeXMLHeader(); + + Writer->writeElement("COLLADA", false, + "xmlns", "http://www.collada.org/2005/11/COLLADASchema", + "version", "1.4.1"); + Writer->writeLineBreak(); + + // write asset data + writeAsset(); + + // write all materials + Writer->writeElement("library_materials", false); + Writer->writeLineBreak(); + writeNodeMaterials(root); + Writer->writeClosingTag("library_materials"); + Writer->writeLineBreak(); + + Writer->writeElement("library_effects", false); + Writer->writeLineBreak(); + writeNodeEffects(root); + Writer->writeClosingTag("library_effects"); + Writer->writeLineBreak(); + + + // images + writeLibraryImages(); + + // lights + Writer->writeElement("library_lights", false); + Writer->writeLineBreak(); + + writeAmbientLightElement( getAmbientLight() ); + writeNodeLights(root); + + Writer->writeClosingTag("library_lights"); + Writer->writeLineBreak(); + + // cameras + Writer->writeElement("library_cameras", false); + Writer->writeLineBreak(); + writeNodeCameras(root); + Writer->writeClosingTag("library_cameras"); + Writer->writeLineBreak(); + + // write meshes + Writer->writeElement("library_geometries", false); + Writer->writeLineBreak(); + writeAllMeshGeometries(); + Writer->writeClosingTag("library_geometries"); + Writer->writeLineBreak(); + + // write scene + Writer->writeElement("library_visual_scenes", false); + Writer->writeLineBreak(); + Writer->writeElement("visual_scene", false, "id", "default_scene"); + Writer->writeLineBreak(); + + // ambient light (instance_light also needs a node as parent so we have to create one) + Writer->writeElement("node", false); + Writer->writeLineBreak(); + Writer->writeElement("instance_light", true, "url", "#ambientlight"); + Writer->writeLineBreak(); + Writer->writeClosingTag("node"); + Writer->writeLineBreak(); + + // Write the scenegraph. + if ( writeRoot == 2 || (writeRoot == 1 && root->getType() != ESNT_SCENE_MANAGER) ) + { + // TODO: Not certain if we should really write the root or if we should just always only write the children. + // For now writing root to keep backward compatibility for this case, but if anyone needs to _not_ write + // that root-node we can add a parameter for this later on in writeScene. + writeSceneNode(root); + } + else + { + // The visual_scene element is identical to our scenemanager and acts as root, + // so we do not write the root itself if it points to the scenemanager. + const core::list& rootChildren = root->getChildren(); + for ( core::list::ConstIterator it = rootChildren.begin(); + it != rootChildren.end(); + ++ it ) + { + writeSceneNode(*it); + } + } + + + Writer->writeClosingTag("visual_scene"); + Writer->writeLineBreak(); + Writer->writeClosingTag("library_visual_scenes"); + Writer->writeLineBreak(); + + + // instance scene + Writer->writeElement("scene", false); + Writer->writeLineBreak(); + + Writer->writeElement("instance_visual_scene", true, "url", "#default_scene"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("scene"); + Writer->writeLineBreak(); + + + // close everything + + Writer->writeClosingTag("COLLADA"); + Writer->drop(); + + return true; +} + +void CColladaMeshWriter::makeMeshNames(irr::scene::ISceneNode * node) +{ + if ( !node || !getProperties() || !getProperties()->isExportable(node) || !getNameGenerator()) + return; + + IMesh* mesh = getProperties()->getMesh(node); + if ( mesh ) + { + if ( !Meshes.find(mesh) ) + { + SColladaMesh cm; + cm.Name = nameForMesh(mesh, 0); + Meshes.insert(mesh, cm); + } + } + + const core::list& children = node->getChildren(); + for ( core::list::ConstIterator it = children.begin(); it != children.end(); ++it ) + { + makeMeshNames(*it); + } +} + +void CColladaMeshWriter::writeNodeMaterials(irr::scene::ISceneNode * node) +{ + if ( !node || !getProperties() || !getProperties()->isExportable(node) ) + return; + + core::array materialNames; + + IMesh* mesh = getProperties()->getMesh(node); + if ( mesh ) + { + MeshNode * n = Meshes.find(mesh); + if ( !getProperties()->useNodeMaterial(node) ) + { + // no material overrides - write mesh materials + if ( n && !n->getValue().MaterialsWritten ) + { + writeMeshMaterials(mesh, getGeometryWriting() == ECGI_PER_MESH_AND_MATERIAL ? &materialNames : NULL); + n->getValue().MaterialsWritten = true; + } + } + else + { + // write node materials + for (u32 i=0; igetMaterialCount(); ++i) + { + video::SMaterial & material = node->getMaterial(i); + core::stringc strMat(nameForMaterial(material, i, mesh, node)); + writeMaterial(strMat); + if ( getGeometryWriting() == ECGI_PER_MESH_AND_MATERIAL ) + materialNames.push_back(strMat); + } + } + + // When we write another mesh-geometry for each new material-list we have + // to figure out here if we need another geometry copy and create a new name here. + if ( n && getGeometryWriting() == ECGI_PER_MESH_AND_MATERIAL ) + { + SGeometryMeshMaterials * geomMat = n->getValue().findGeometryMeshMaterials(materialNames); + if ( geomMat ) + geomMat->MaterialOwners.push_back(node); + else + { + SGeometryMeshMaterials gmm; + if ( n->getValue().GeometryMeshMaterials.empty() ) + gmm.GeometryName = n->getValue().Name; // first one can use the original name + else + gmm.GeometryName = nameForMesh(mesh, n->getValue().GeometryMeshMaterials.size()); + gmm.MaterialNames = materialNames; + gmm.MaterialOwners.push_back(node); + n->getValue().GeometryMeshMaterials.push_back(gmm); + } + } + } + + const core::list& children = node->getChildren(); + for ( core::list::ConstIterator it = children.begin(); it != children.end(); ++it ) + { + writeNodeMaterials( *it ); + } +} + +void CColladaMeshWriter::writeMaterial(const irr::core::stringc& materialname) +{ + if ( MaterialsWritten.find(materialname) ) + return; + MaterialsWritten.insert(materialname, true); + + Writer->writeElement("material", false, + "id", materialname.c_str(), + "name", materialname.c_str()); + Writer->writeLineBreak(); + + // We don't make a difference between material and effect on export. + // Every material is just using an instance of an effect. + core::stringc strFx(materialname); + strFx += "-fx"; + Writer->writeElement("instance_effect", true, + "url", (core::stringc("#") + strFx).c_str()); + Writer->writeLineBreak(); + + Writer->writeClosingTag("material"); + Writer->writeLineBreak(); +} + +void CColladaMeshWriter::writeNodeEffects(irr::scene::ISceneNode * node) +{ + if ( !node || !getProperties() || !getProperties()->isExportable(node) || !getNameGenerator() ) + return; + + IMesh* mesh = getProperties()->getMesh(node); + if ( mesh ) + { + if ( !getProperties()->useNodeMaterial(node) ) + { + // no material overrides - write mesh materials + MeshNode * n = Meshes.find(mesh); + if ( n && !n->getValue().EffectsWritten ) + { + writeMeshEffects(mesh); + n->getValue().EffectsWritten = true; + } + } + else + { + // write node materials + for (u32 i=0; igetMaterialCount(); ++i) + { + video::SMaterial & material = node->getMaterial(i); + irr::core::stringc materialfxname(nameForMaterial(material, i, mesh, node)); + materialfxname += "-fx"; + writeMaterialEffect(materialfxname, material); + } + } + } + + const core::list& children = node->getChildren(); + for ( core::list::ConstIterator it = children.begin(); it != children.end(); ++it ) + { + writeNodeEffects( *it ); + } +} + +void CColladaMeshWriter::writeNodeLights(irr::scene::ISceneNode * node) +{ + if ( !node || !getProperties() || !getProperties()->isExportable(node)) + return; + + if ( node->getType() == ESNT_LIGHT ) + { + ILightSceneNode * lightNode = static_cast(node); + const video::SLight& lightData = lightNode->getLightData(); + + SColladaLight cLight; + cLight.Name = nameForNode(node); + LightNodes.insert(node, cLight); + + Writer->writeElement("light", false, "id", cLight.Name.c_str()); + Writer->writeLineBreak(); + + Writer->writeElement("technique_common", false); + Writer->writeLineBreak(); + + switch ( lightNode->getLightType() ) + { + case video::ELT_POINT: + Writer->writeElement("point", false); + Writer->writeLineBreak(); + + writeColorElement(lightData.DiffuseColor, false); + writeNode("constant_attenuation ", core::stringc(lightData.Attenuation.X).c_str()); + writeNode("linear_attenuation ", core::stringc(lightData.Attenuation.Y).c_str()); + writeNode("quadratic_attenuation", core::stringc(lightData.Attenuation.Z).c_str()); + + Writer->writeClosingTag("point"); + Writer->writeLineBreak(); + break; + + case video::ELT_SPOT: + Writer->writeElement("spot", false); + Writer->writeLineBreak(); + + writeColorElement(lightData.DiffuseColor, false); + + writeNode("constant_attenuation ", core::stringc(lightData.Attenuation.X).c_str()); + writeNode("linear_attenuation ", core::stringc(lightData.Attenuation.Y).c_str()); + writeNode("quadratic_attenuation", core::stringc(lightData.Attenuation.Z).c_str()); + + writeNode("falloff_angle", core::stringc(lightData.OuterCone * core::RADTODEG).c_str()); + writeNode("falloff_exponent", core::stringc(lightData.Falloff).c_str()); + + Writer->writeClosingTag("spot"); + Writer->writeLineBreak(); + break; + + case video::ELT_DIRECTIONAL: + Writer->writeElement("directional", false); + Writer->writeLineBreak(); + + writeColorElement(lightData.DiffuseColor, false); + + Writer->writeClosingTag("directional"); + Writer->writeLineBreak(); + break; + default: + break; + } + + Writer->writeClosingTag("technique_common"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("light"); + Writer->writeLineBreak(); + + } + + const core::list& children = node->getChildren(); + for ( core::list::ConstIterator it = children.begin(); it != children.end(); ++it ) + { + writeNodeLights( *it ); + } +} + +void CColladaMeshWriter::writeNodeCameras(irr::scene::ISceneNode * node) +{ + if ( !node || !getProperties() || !getProperties()->isExportable(node) ) + return; + + if ( isCamera(node) ) + { + ICameraSceneNode * cameraNode = static_cast(node); + irr::core::stringc name = nameForNode(node); + CameraNodes.insert(cameraNode, name); + + Writer->writeElement("camera", false, "id", name.c_str()); + Writer->writeLineBreak(); + + Writer->writeElement("optics", false); + Writer->writeLineBreak(); + + Writer->writeElement("technique_common", false); + Writer->writeLineBreak(); + + if ( cameraNode->isOrthogonal() ) + { + Writer->writeElement("orthographic", false); + Writer->writeLineBreak(); + + irr::core::matrix4 projMat( cameraNode->getProjectionMatrix() ); + irr::f32 xmag = 2.f/projMat[0]; + irr::f32 ymag = 2.f/projMat[5]; + + // Note that Irrlicht camera does not update near/far when setting the projection matrix, + // so we have to calculate that here (at least currently - maybe camera code will be updated at some time). + irr::f32 nearMinusFar = -1.f/projMat[10]; + irr::f32 zNear = projMat[14]*nearMinusFar; + irr::f32 zFar = 1.f/projMat[10] + zNear; + + writeNode("xmag", core::stringc(xmag).c_str()); + writeNode("ymag", core::stringc(ymag).c_str()); + writeNode("znear", core::stringc(zNear).c_str()); + writeNode("zfar", core::stringc(zFar).c_str()); + + Writer->writeClosingTag("orthographic"); + Writer->writeLineBreak(); + } + else + { + Writer->writeElement("perspective", false); + Writer->writeLineBreak(); + + writeNode("yfov", core::stringc(cameraNode->getFOV()*core::RADTODEG).c_str()); + writeNode("aspect_ratio", core::stringc(cameraNode->getAspectRatio()).c_str()); + writeNode("znear", core::stringc(cameraNode->getNearValue()).c_str()); + writeNode("zfar", core::stringc(cameraNode->getFarValue()).c_str()); + + Writer->writeClosingTag("perspective"); + Writer->writeLineBreak(); + } + + Writer->writeClosingTag("technique_common"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("optics"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("camera"); + Writer->writeLineBreak(); + } + + const core::list& children = node->getChildren(); + for ( core::list::ConstIterator it = children.begin(); it != children.end(); ++it ) + { + writeNodeCameras( *it ); + } +} + +void CColladaMeshWriter::writeAllMeshGeometries() +{ + core::map::ConstIterator it = Meshes.getConstIterator(); + for(; !it.atEnd(); it++ ) + { + IMesh* mesh = it->getKey(); + const SColladaMesh& colladaMesh = it->getValue(); + + if ( getGeometryWriting() == ECGI_PER_MESH_AND_MATERIAL && colladaMesh.GeometryMeshMaterials.size() > 1 ) + { + for ( u32 i=0; iisExportable(node) ) + return; + + // Collada doesn't require to set the id, but some other tools have problems if none exists, so we just add it. + irr::core::stringc nameId(nameForNode(node)); + Writer->writeElement("node", false, "id", nameId.c_str()); + Writer->writeLineBreak(); + + // DummyTransformationSceneNode don't have rotation, position, scale information + // But also don't always export the transformation matrix as that forces us creating + // new DummyTransformationSceneNode's on import. + if ( node->getType() == ESNT_DUMMY_TRANSFORMATION ) + { + writeMatrixElement(node->getRelativeTransformation()); + } + else if ( isCamera(node) ) + { + // TODO: We do not handle the case when ICameraSceneNode::getTargetAndRotationBinding() is false. Probably we would have to create a second + // node to do that. + + // Note: We can't use rotations for the camera as Irrlicht does not regard the up-vector in rotations so far. + // We could maybe use projection matrices, but avoiding them might allow us to get rid of some DummyTransformationSceneNodes on + // import in the future. So that's why we use the lookat element instead. + + ICameraSceneNode * camNode = static_cast(node); + writeLookAtElement(camNode->getPosition(), camNode->getTarget(), camNode->getUpVector()); + } + else + { + writeTranslateElement( node->getPosition() ); + + irr::core::vector3df rot(node->getRotation()); + core::quaternion quat(rot*core::DEGTORAD); + f32 angle; + core::vector3df axis; + quat.toAngleAxis(angle, axis); + writeRotateElement( axis, angle*core::RADTODEG ); + + writeScaleElement( node->getScale() ); + } + + // instance geometry + IMesh* mesh = getProperties()->getMesh(node); + if ( mesh ) + { + MeshNode * n = Meshes.find(mesh); + if ( n ) + { + const SColladaMesh& colladaMesh = n->getValue(); + writeMeshInstanceGeometry(colladaMesh.findGeometryNameForNode(node), mesh, node); + } + } + + // instance light + if ( node->getType() == ESNT_LIGHT ) + { + LightNode * n = LightNodes.find(node); + if ( n ) + writeLightInstance(n->getValue().Name); + } + + // instance camera + if ( isCamera(node) ) + { + CameraNode * camNode = CameraNodes.find(node); + if ( camNode ) + writeCameraInstance(camNode->getValue()); + } + + const core::list& children = node->getChildren(); + for ( core::list::ConstIterator it = children.begin(); it != children.end(); ++it ) + { + writeSceneNode( *it ); + } + + Writer->writeClosingTag("node"); + Writer->writeLineBreak(); +} + +//! writes a mesh +bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags) +{ + if (!file) + return false; + + reset(); + + Writer = FileSystem->createXMLWriterUTF8(file); + + if (!Writer) + { + os::Printer::log("Could not write file", file->getFileName()); + return false; + } + + Directory = FileSystem->getFileDir(FileSystem->getAbsolutePath( file->getFileName() )); + + os::Printer::log("Writing mesh", file->getFileName()); + + // write COLLADA header + + Writer->writeXMLHeader(); + + Writer->writeElement("COLLADA", false, + "xmlns", "http://www.collada.org/2005/11/COLLADASchema", + "version", "1.4.1"); + Writer->writeLineBreak(); + + // write asset data + writeAsset(); + + // write all materials + + Writer->writeElement("library_materials", false); + Writer->writeLineBreak(); + + writeMeshMaterials(mesh); + + Writer->writeClosingTag("library_materials"); + Writer->writeLineBreak(); + + Writer->writeElement("library_effects", false); + Writer->writeLineBreak(); + + writeMeshEffects(mesh); + + Writer->writeClosingTag("library_effects"); + Writer->writeLineBreak(); + + // images + writeLibraryImages(); + + // write mesh + + Writer->writeElement("library_geometries", false); + Writer->writeLineBreak(); + + irr::core::stringc meshname(nameForMesh(mesh, 0)); + writeMeshGeometry(meshname, mesh); + + Writer->writeClosingTag("library_geometries"); + Writer->writeLineBreak(); + + // write scene_library + if ( getWriteDefaultScene() ) + { + Writer->writeElement("library_visual_scenes", false); + Writer->writeLineBreak(); + + Writer->writeElement("visual_scene", false, "id", "default_scene"); + Writer->writeLineBreak(); + + Writer->writeElement("node", false); + Writer->writeLineBreak(); + + writeMeshInstanceGeometry(meshname, mesh); + + Writer->writeClosingTag("node"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("visual_scene"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("library_visual_scenes"); + Writer->writeLineBreak(); + + + // write scene + Writer->writeElement("scene", false); + Writer->writeLineBreak(); + + Writer->writeElement("instance_visual_scene", true, "url", "#default_scene"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("scene"); + Writer->writeLineBreak(); + } + + + // close everything + + Writer->writeClosingTag("COLLADA"); + Writer->drop(); + + return true; +} + +void CColladaMeshWriter::writeMeshInstanceGeometry(const irr::core::stringc& meshname, scene::IMesh* mesh, scene::ISceneNode* node) +{ + // + Writer->writeElement("instance_geometry", false, "url", toRef(meshname).c_str()); + Writer->writeLineBreak(); + + Writer->writeElement("bind_material", false); + Writer->writeLineBreak(); + + Writer->writeElement("technique_common", false); + Writer->writeLineBreak(); + + // instance materials + // + bool useNodeMaterials = node && node->getMaterialCount() == mesh->getMeshBufferCount(); + for (u32 i=0; igetMeshBufferCount(); ++i) + { + irr::core::stringc strMatSymbol(nameForMaterialSymbol(mesh, i)); + core::stringc strMatTarget = "#"; + video::SMaterial & material = useNodeMaterials ? node->getMaterial(i) : mesh->getMeshBuffer(i)->getMaterial(); + strMatTarget += nameForMaterial(material, i, mesh, node); + Writer->writeElement("instance_material", false, "symbol", strMatSymbol.c_str(), "target", strMatTarget.c_str()); + Writer->writeLineBreak(); + + // TODO: need to handle second UV-set + // + Writer->writeElement("bind_vertex_input", true, "semantic", "uv", "input_semantic", "TEXCOORD", "input_set", "0" ); + Writer->writeLineBreak(); + + Writer->writeClosingTag("instance_material"); + Writer->writeLineBreak(); + } + + Writer->writeClosingTag("technique_common"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("bind_material"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("instance_geometry"); + Writer->writeLineBreak(); +} + +void CColladaMeshWriter::writeLightInstance(const irr::core::stringc& lightName) +{ + Writer->writeElement("instance_light", true, "url", toRef(lightName).c_str()); + Writer->writeLineBreak(); +} + +void CColladaMeshWriter::writeCameraInstance(const irr::core::stringc& cameraName) +{ + Writer->writeElement("instance_camera", true, "url", toRef(cameraName).c_str()); + Writer->writeLineBreak(); +} + +bool CColladaMeshWriter::hasSecondTextureCoordinates(video::E_VERTEX_TYPE type) const +{ + return type == video::EVT_2TCOORDS; +} + +void CColladaMeshWriter::writeVector(const irr::core::vector3df& vec) +{ + c8 tmpbuf[255]; + + snprintf_irr(tmpbuf, 255, "%f", vec.X); + WriteBuffer = tmpbuf; + WriteBuffer.eraseTrailingFloatZeros(); + + snprintf_irr(tmpbuf, 255, " %f", vec.Y); + WriteBuffer.append(tmpbuf); + WriteBuffer.eraseTrailingFloatZeros(); + + snprintf_irr(tmpbuf, 255, " %f", vec.Z*-1.f); // change handedness + WriteBuffer.append(tmpbuf); + WriteBuffer.eraseTrailingFloatZeros(); + + Writer->writeText(WriteBuffer.c_str()); +} + +void CColladaMeshWriter::writeUv(const irr::core::vector2df& vec) +{ + c8 tmpbuf[255]; + + snprintf_irr(tmpbuf, 255, "%f", vec.X); + WriteBuffer = tmpbuf; + WriteBuffer.eraseTrailingFloatZeros(); + + snprintf_irr(tmpbuf, 255, " %f", 1.f-vec.Y); // change handedness + WriteBuffer.append(tmpbuf); + WriteBuffer.eraseTrailingFloatZeros(); + + Writer->writeText(WriteBuffer.c_str()); +} + +void CColladaMeshWriter::writeColor(const irr::video::SColorf& colorf, bool writeAlpha) +{ + c8 tmpbuf[255]; + + snprintf_irr(tmpbuf, 255, "%f", colorf.getRed()); + WriteBuffer = tmpbuf; + WriteBuffer.eraseTrailingFloatZeros(); + + snprintf_irr(tmpbuf, 255, " %f", colorf.getGreen()); + WriteBuffer.append(tmpbuf); + WriteBuffer.eraseTrailingFloatZeros(); + + snprintf_irr(tmpbuf, 255, " %f", colorf.getBlue()); + WriteBuffer.append(tmpbuf); + WriteBuffer.eraseTrailingFloatZeros(); + + if ( writeAlpha ) + { + snprintf_irr(tmpbuf, 255, " %f", colorf.getAlpha()); + WriteBuffer.append(tmpbuf); + WriteBuffer.eraseTrailingFloatZeros(); + } + + Writer->writeText(WriteBuffer.c_str()); +} + +irr::core::stringc CColladaMeshWriter::toString(const irr::video::ECOLOR_FORMAT format) const +{ + switch ( format ) + { + case video::ECF_A1R5G5B5: return irr::core::stringc("A1R5G5B5"); + case video::ECF_R5G6B5: return irr::core::stringc("R5G6B5"); + case video::ECF_R8G8B8: return irr::core::stringc("R8G8B8"); + case video::ECF_A8R8G8B8: return irr::core::stringc("A8R8G8B8"); + default: return irr::core::stringc(""); + } +} + +irr::core::stringc CColladaMeshWriter::toString(const irr::video::E_TEXTURE_CLAMP clamp) const +{ + switch ( clamp ) + { + case video::ETC_REPEAT: + return core::stringc("WRAP"); + case video::ETC_CLAMP: + case video::ETC_CLAMP_TO_EDGE: + return core::stringc("CLAMP"); + case video::ETC_CLAMP_TO_BORDER: + return core::stringc("BORDER"); + case video::ETC_MIRROR: + case video::ETC_MIRROR_CLAMP: + case video::ETC_MIRROR_CLAMP_TO_EDGE: + case video::ETC_MIRROR_CLAMP_TO_BORDER: + return core::stringc("MIRROR"); + } + return core::stringc("NONE"); +} + +irr::core::stringc CColladaMeshWriter::toString(const irr::scene::E_COLLADA_TRANSPARENT_FX transparent) const +{ + if ( transparent & ECOF_RGB_ZERO ) + return core::stringc("RGB_ZERO"); + else + return core::stringc("A_ONE"); +} + +irr::core::stringc CColladaMeshWriter::toRef(const irr::core::stringc& source) const +{ + irr::core::stringc ref("#"); + ref += source; + return ref; +} + +bool CColladaMeshWriter::isCamera(const scene::ISceneNode* node) const +{ + // TODO: we need some ISceneNode::hasType() function to get rid of those checks + if ( node->getType() == ESNT_CAMERA + || node->getType() == ESNT_CAMERA_MAYA + || node->getType() == ESNT_CAMERA_FPS ) + return true; + return false; +} + +irr::core::stringc CColladaMeshWriter::nameForMesh(const scene::IMesh* mesh, int instance) const +{ + IColladaMeshWriterNames * nameGenerator = getNameGenerator(); + if ( nameGenerator ) + { + return nameGenerator->nameForMesh(mesh, instance); + } + return irr::core::stringc("missing_name_generator"); +} + +irr::core::stringc CColladaMeshWriter::nameForNode(const scene::ISceneNode* node) const +{ + IColladaMeshWriterNames * nameGenerator = getNameGenerator(); + if ( nameGenerator ) + { + return nameGenerator->nameForNode(node); + } + return irr::core::stringc("missing_name_generator"); +} + +irr::core::stringc CColladaMeshWriter::nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node) +{ + irr::core::stringc matName; + if ( getExportSMaterialsOnlyOnce() ) + { + matName = findCachedMaterialName(material); + if ( !matName.empty() ) + return matName; + } + + IColladaMeshWriterNames * nameGenerator = getNameGenerator(); + if ( nameGenerator ) + { + matName = nameGenerator->nameForMaterial(material, materialId, mesh, node); + } + else + matName = irr::core::stringc("missing_name_generator"); + + if ( getExportSMaterialsOnlyOnce() ) + MaterialNameCache.push_back (MaterialName(material, matName)); + return matName; +} + +// Each mesh-material has one symbol which is replaced on instantiation +irr::core::stringc CColladaMeshWriter::nameForMaterialSymbol(const scene::IMesh* mesh, int materialId) const +{ + c8 buf[100]; + snprintf_irr(buf, 100, "mat_symb_%p_%d", mesh, materialId); + return irr::core::stringc(buf); +} + +irr::core::stringc CColladaMeshWriter::findCachedMaterialName(const irr::video::SMaterial& material) const +{ + for ( u32 i=0; i= 'A' && c <= 'Z') + || c == '_' + || (c >= 'a' && c <= 'z'); + /* Following would also be legal, but only when using real unicode. + We do only check ansi codes as they are sufficient for us. + || (c >= 0xC0 && c <= 0xD6) + || (c >= 0xD8 && c <= 0xF6) + || (c >= 0xF8 && c <= 0x2FF) + || (c >= 0x370 && c <= 0x37D) + || (c >= 0x37F && c <= 0x1FFF) + || (c >= 0x200C && c <= 0x200D) + || (c >= 0x2070 && c <= 0x218F) + || (c >= 0x2C00 && c <= 0x2FEF) + || (c >= 0x3001 && c <= 0xD7FF) + || (c >= 0xF900 && c <= 0xFDCF) + || (c >= 0xFDF0 && c <= 0xFFFD) + || (c >= 0x10000 && c <=0xEFFFF) +*/ + ; +} + +bool CColladaMeshWriter::isXmlNameChar(c8 c) const +{ + return isXmlNameStartChar(c) + || c == '-' + || c == '.' + || (c >= '0' && c <= '9'); + /* Following would also be legal, but only when using real unicode. + We do only check ansi codes for now as they are sufficient for us. + || c == 0xB7 + || (c >= 9x0300 && c <= 0x036F) + || (c >= 0x203F && c <= 0x2040) + */ +} + +// Restrict the characters to a set of allowed characters in xs:NCName. +irr::core::stringc CColladaMeshWriter::toNCName(const irr::core::stringc& oldString, const irr::core::stringc& prefix) const +{ + irr::core::stringc result(prefix); // help to ensure id starts with a valid char and reduce chance of name-conflicts + if ( oldString.empty() ) + return result; + + result.append( oldString ); + + // We replace all characters not allowed by a replacement char + const c8 REPLACMENT = '-'; + for ( irr::u32 i=1; i < result.size(); ++i ) + { + if ( result[i] == ':' || !isXmlNameChar(result[i]) ) + { + result[i] = REPLACMENT; + } + } + return result; +} + +const irr::core::stringc* CColladaMeshWriter::findGeometryNameForNode(ISceneNode* node) +{ + IMesh* mesh = getProperties()->getMesh(node); + if ( !mesh ) + return NULL; + + MeshNode * n = Meshes.find(mesh); + if ( !n ) + return NULL; + + const SColladaMesh& colladaMesh = n->getValue(); + return &colladaMesh.findGeometryNameForNode(node); +} + +// Restrict the characters to a set of allowed characters in xs:anyURI +irr::core::stringc CColladaMeshWriter::pathToURI(const irr::io::path& path) const +{ + irr::core::stringc result; + + // is this a relative path? + if ( path.size() > 1 + && path[0] != _IRR_TEXT('/') + && path[0] != _IRR_TEXT('\\') + && path[1] != _IRR_TEXT(':') ) + { + // not already starting with "./" ? + if ( path[0] != _IRR_TEXT('.') + || path[1] != _IRR_TEXT('/') ) + { + result.append("./"); + } + } + result.append(path); + + // Make correct URI (without whitespace) + u32 len = result.size(); + for (u32 i=0; iwriteElement("asset", false); + Writer->writeLineBreak(); + + Writer->writeElement("contributor", false); + Writer->writeLineBreak(); + Writer->writeElement("authoring_tool", false); + Writer->writeText("Irrlicht Engine"); + Writer->writeClosingTag("authoring_tool"); + Writer->writeLineBreak(); + Writer->writeClosingTag("contributor"); + Writer->writeLineBreak(); + + // The next two are required + Writer->writeElement("created", false); + Writer->writeText("2008-01-31T00:00:00Z"); + Writer->writeClosingTag("created"); + Writer->writeLineBreak(); + + Writer->writeElement("modified", false); + Writer->writeText("2008-01-31T00:00:00Z"); + Writer->writeClosingTag("modified"); + Writer->writeLineBreak(); + + // Revision 2.0 changes (since 1.0): + // - All coordinates are now written with right-handed coordinate system. + // Before only texture V of first textures was swapped and all other + // parameters where exported left-handed. + // For specific changes change svn revision 5708. + // - authoring_tool no longer mentions IrrEdit (this code has originated + // from irrEdit 0.7) to avoid conflicts as the software is now + // independent of each other and we're not aware of irrEdit revision numbers. + Writer->writeElement("revision", false); + Writer->writeText("2.0"); + Writer->writeClosingTag("revision"); + Writer->writeLineBreak(); + + Writer->writeElement("unit", true, "meter", core::stringc(getUnitMeter()).eraseTrailingFloatZeros().c_str(), "name", getUnitName().c_str()); + Writer->writeLineBreak(); + + Writer->writeClosingTag("asset"); + Writer->writeLineBreak(); +} + +void CColladaMeshWriter::writeMeshMaterials(scene::IMesh* mesh, irr::core::array * materialNamesOut) +{ + u32 i; + for (i=0; igetMeshBufferCount(); ++i) + { + video::SMaterial & material = mesh->getMeshBuffer(i)->getMaterial(); + core::stringc strMat(nameForMaterial(material, i, mesh, NULL)); + writeMaterial(strMat); + if ( materialNamesOut ) + materialNamesOut->push_back(strMat); + } +} + +void CColladaMeshWriter::writeMaterialEffect(const irr::core::stringc& materialfxname, const video::SMaterial & material) +{ + if ( EffectsWritten.find(materialfxname) ) + return; + EffectsWritten.insert(materialfxname, true); + + Writer->writeElement("effect", false, + "id", materialfxname.c_str(), + "name", materialfxname.c_str()); + Writer->writeLineBreak(); + Writer->writeElement("profile_COMMON", false); + Writer->writeLineBreak(); + + int numTextures = 0; + if ( getWriteTextures() ) + { + // write texture surfaces and samplers and buffer all used imagess + for ( int t=0; t<4; ++t ) + { + const video::SMaterialLayer& layer = material.TextureLayer[t]; + if ( !layer.Texture ) + break; + ++numTextures; + + if ( LibraryImages.linear_search(layer.Texture) < 0 ) + LibraryImages.push_back( layer.Texture ); + + irr::core::stringc texName("tex"); + texName += irr::core::stringc(t); + + // write texture surface + // + irr::core::stringc texSurface(texName); + texSurface += "-surface"; + Writer->writeElement("newparam", false, "sid", texSurface.c_str()); + Writer->writeLineBreak(); + // + Writer->writeElement("surface", false, "type", "2D"); + Writer->writeLineBreak(); + + // internal_texturename + Writer->writeElement("init_from", false); + irr::io::path p(FileSystem->getRelativeFilename(layer.Texture->getName().getPath(), Directory)); + Writer->writeText(toNCName(irr::core::stringc(p)).c_str()); // same ID for internal name as in writeLibraryImages + Writer->writeClosingTag("init_from"); + Writer->writeLineBreak(); + + // A8R8G8B8 + Writer->writeElement("format", false); + video::ECOLOR_FORMAT format = layer.Texture->getColorFormat(); + Writer->writeText(toString(format).c_str()); + Writer->writeClosingTag("format"); + Writer->writeLineBreak(); + // + Writer->writeClosingTag("surface"); + Writer->writeLineBreak(); + // + Writer->writeClosingTag("newparam"); + Writer->writeLineBreak(); + + // write texture sampler + // + irr::core::stringc texSampler(texName); + texSampler += "-sampler"; + Writer->writeElement("newparam", false, "sid", texSampler.c_str()); + Writer->writeLineBreak(); + // + Writer->writeElement("sampler2D", false); + Writer->writeLineBreak(); + + // tex0-surface + Writer->writeElement("source", false); + Writer->writeText(texSurface.c_str()); + Writer->writeClosingTag("source"); + Writer->writeLineBreak(); + + // WRAP + Writer->writeElement("wrap_s", false); + Writer->writeText(toString((video::E_TEXTURE_CLAMP)layer.TextureWrapU).c_str()); + Writer->writeClosingTag("wrap_s"); + Writer->writeLineBreak(); + + // WRAP + Writer->writeElement("wrap_t", false); + Writer->writeText(toString((video::E_TEXTURE_CLAMP)layer.TextureWrapV).c_str()); + Writer->writeClosingTag("wrap_t"); + Writer->writeLineBreak(); + + // WRAP // TODO: Should only be written in Collada 1.5 + Writer->writeElement("wrap_p", false); + Writer->writeText(toString((video::E_TEXTURE_CLAMP)layer.TextureWrapW).c_str()); + Writer->writeClosingTag("wrap_p"); + Writer->writeLineBreak(); + + // LINEAR_MIPMAP_LINEAR + Writer->writeElement("minfilter", false); + Writer->writeText(minTexfilterToString(layer.BilinearFilter, layer.TrilinearFilter).c_str()); + Writer->writeClosingTag("minfilter"); + Writer->writeLineBreak(); + + // LINEAR + Writer->writeElement("magfilter", false); + Writer->writeText(magTexfilterToString(layer.BilinearFilter, layer.TrilinearFilter).c_str()); + Writer->writeClosingTag("magfilter"); + Writer->writeLineBreak(); + + // TBD - actually not sure how anisotropic should be written, so for now it writes in a way + // that works with the way the loader reads it again. + if ( layer.AnisotropicFilter ) + { + // LINEAR_MIPMAP_LINEAR + Writer->writeElement("mipfilter", false); + Writer->writeText("LINEAR_MIPMAP_LINEAR"); + Writer->writeClosingTag("mipfilter"); + Writer->writeLineBreak(); + } + + // + Writer->writeClosingTag("sampler2D"); + Writer->writeLineBreak(); + // + Writer->writeClosingTag("newparam"); + Writer->writeLineBreak(); + } + } + + Writer->writeElement("technique", false, "sid", "common"); + Writer->writeLineBreak(); + + E_COLLADA_TECHNIQUE_FX techFx = getProperties() ? getProperties()->getTechniqueFx(material) : ECTF_BLINN; + writeFxElement(material, techFx); + + Writer->writeClosingTag("technique"); + Writer->writeLineBreak(); + Writer->writeClosingTag("profile_COMMON"); + Writer->writeLineBreak(); + Writer->writeClosingTag("effect"); + Writer->writeLineBreak(); +} + +void CColladaMeshWriter::writeMeshEffects(scene::IMesh* mesh) +{ + for (u32 i=0; igetMeshBufferCount(); ++i) + { + video::SMaterial & material = mesh->getMeshBuffer(i)->getMaterial(); + irr::core::stringc materialfxname(nameForMaterial(material, i, mesh, NULL)); + materialfxname += "-fx"; + writeMaterialEffect(materialfxname, material); + } +} + +void CColladaMeshWriter::writeMeshGeometry(const irr::core::stringc& meshname, scene::IMesh* mesh) +{ + core::stringc meshId(meshname); + + Writer->writeElement("geometry", false, "id", meshId.c_str(), "name", meshId.c_str()); + Writer->writeLineBreak(); + Writer->writeElement("mesh"); + Writer->writeLineBreak(); + + // do some statistics for the mesh to know which stuff needs to be saved into + // the file: + // - count vertices + // - check for the need of a second texture coordinate + // - count amount of second texture coordinates + // - check for the need of tangents (TODO) + + u32 totalVertexCount = 0; + u32 totalTCoords2Count = 0; + bool needsTangents = false; // TODO: tangents not supported here yet + u32 i=0; + for (i=0; igetMeshBufferCount(); ++i) + { + totalVertexCount += mesh->getMeshBuffer(i)->getVertexCount(); + + if (hasSecondTextureCoordinates(mesh->getMeshBuffer(i)->getVertexType())) + totalTCoords2Count += mesh->getMeshBuffer(i)->getVertexCount(); + + if (!needsTangents) + needsTangents = mesh->getMeshBuffer(i)->getVertexType() == video::EVT_TANGENTS; + } + + const irr::u32 mbCount = mesh->getMeshBufferCount(); + SComponentGlobalStartPos* globalIndices = new SComponentGlobalStartPos[mbCount]; + + // write positions + core::stringc meshPosId(meshId); + meshPosId += "-Pos"; + Writer->writeElement("source", false, "id", meshPosId.c_str()); + Writer->writeLineBreak(); + + core::stringc vertexCountStr(totalVertexCount*3); + core::stringc meshPosArrayId(meshPosId); + meshPosArrayId += "-array"; + Writer->writeElement("float_array", false, "id", meshPosArrayId.c_str(), + "count", vertexCountStr.c_str()); + Writer->writeLineBreak(); + + for (i=0; igetMeshBuffer(i); + u32 vertexCount = buffer->getVertexCount(); + + if ( i == 0 ) + globalIndices[i].PosStartIndex = 0; + + if (i+1 < mbCount) + globalIndices[i+1].PosStartIndex = globalIndices[i].PosStartIndex + vertexCount; + + u8* vertices = static_cast(buffer->getVertices()); + u32 vertexPitch = getVertexPitchFromType(buffer->getVertexType()); + for (u32 j=0; j(&vertices[j*vertexPitch])).Pos ); + Writer->writeLineBreak(); + } + } + + Writer->writeClosingTag("float_array"); + Writer->writeLineBreak(); + + Writer->writeElement("technique_common", false); + Writer->writeLineBreak(); + + vertexCountStr = core::stringc(totalVertexCount); + + Writer->writeElement("accessor", false, "source", toRef(meshPosArrayId).c_str(), + "count", vertexCountStr.c_str(), "stride", "3"); + Writer->writeLineBreak(); + + Writer->writeElement("param", true, "name", "X", "type", "float"); + Writer->writeLineBreak(); + Writer->writeElement("param", true, "name", "Y", "type", "float"); + Writer->writeLineBreak(); + Writer->writeElement("param", true, "name", "Z", "type", "float"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("accessor"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("technique_common"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("source"); + Writer->writeLineBreak(); + + // write texture coordinates + + core::stringc meshTexCoord0Id(meshId); + meshTexCoord0Id += "-TexCoord0"; + Writer->writeElement("source", false, "id", meshTexCoord0Id.c_str()); + Writer->writeLineBreak(); + + vertexCountStr = core::stringc(totalVertexCount*2); + core::stringc meshTexCoordArrayId(meshTexCoord0Id); + meshTexCoordArrayId += "-array"; + Writer->writeElement("float_array", false, "id", meshTexCoordArrayId.c_str(), + "count", vertexCountStr.c_str()); + Writer->writeLineBreak(); + + for (i=0; igetMeshBuffer(i); + u32 vertexCount = buffer->getVertexCount(); + + if (i==0) + globalIndices[i].TCoord0StartIndex = 0; + + if (i+1 < mbCount) + globalIndices[i+1].TCoord0StartIndex = globalIndices[i].TCoord0StartIndex + vertexCount; + + u8* vertices = static_cast(buffer->getVertices()); + u32 vertexPitch = getVertexPitchFromType(buffer->getVertexType()); + for (u32 j=0; j(&vertices[j*vertexPitch])).TCoords ); + Writer->writeLineBreak(); + } + } + + Writer->writeClosingTag("float_array"); + Writer->writeLineBreak(); + + Writer->writeElement("technique_common", false); + Writer->writeLineBreak(); + + vertexCountStr = core::stringc(totalVertexCount); + + Writer->writeElement("accessor", false, "source", toRef(meshTexCoordArrayId).c_str(), + "count", vertexCountStr.c_str(), "stride", "2"); + Writer->writeLineBreak(); + + Writer->writeElement("param", true, "name", ParamNamesUV[0].c_str(), "type", "float"); + Writer->writeLineBreak(); + Writer->writeElement("param", true, "name", ParamNamesUV[1].c_str(), "type", "float"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("accessor"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("technique_common"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("source"); + Writer->writeLineBreak(); + + // write normals + core::stringc meshNormalId(meshId); + meshNormalId += "-Normal"; + Writer->writeElement("source", false, "id", meshNormalId.c_str()); + Writer->writeLineBreak(); + + vertexCountStr = core::stringc(totalVertexCount*3); + core::stringc meshNormalArrayId(meshNormalId); + meshNormalArrayId += "-array"; + Writer->writeElement("float_array", false, "id", meshNormalArrayId.c_str(), + "count", vertexCountStr.c_str()); + Writer->writeLineBreak(); + + for (i=0; igetMeshBuffer(i); + u32 vertexCount = buffer->getVertexCount(); + + if ( i==0 ) + globalIndices[i].NormalStartIndex = 0; + + if (i+1 < mbCount) + globalIndices[i+1].NormalStartIndex = globalIndices[i].NormalStartIndex + vertexCount; + + u8* vertices = static_cast(buffer->getVertices()); + u32 vertexPitch = getVertexPitchFromType(buffer->getVertexType()); + for (u32 j=0; j(&vertices[j*vertexPitch])).Normal ); + Writer->writeLineBreak(); + } + } + + Writer->writeClosingTag("float_array"); + Writer->writeLineBreak(); + + Writer->writeElement("technique_common", false); + Writer->writeLineBreak(); + + vertexCountStr = core::stringc(totalVertexCount); + + Writer->writeElement("accessor", false, "source", toRef(meshNormalArrayId).c_str(), + "count", vertexCountStr.c_str(), "stride", "3"); + Writer->writeLineBreak(); + + Writer->writeElement("param", true, "name", "X", "type", "float"); + Writer->writeLineBreak(); + Writer->writeElement("param", true, "name", "Y", "type", "float"); + Writer->writeLineBreak(); + Writer->writeElement("param", true, "name", "Z", "type", "float"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("accessor"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("technique_common"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("source"); + Writer->writeLineBreak(); + + // write second set of texture coordinates + core::stringc meshTexCoord1Id(meshId); + meshTexCoord1Id += "-TexCoord1"; + if (totalTCoords2Count) + { + Writer->writeElement("source", false, "id", meshTexCoord1Id.c_str()); + Writer->writeLineBreak(); + + vertexCountStr = core::stringc(totalTCoords2Count*2); + core::stringc meshTexCoord1ArrayId(meshTexCoord1Id); + meshTexCoord1ArrayId += "-array"; + Writer->writeElement("float_array", false, "id", meshTexCoord1ArrayId.c_str(), + "count", vertexCountStr.c_str()); + Writer->writeLineBreak(); + + for (i=0; igetMeshBuffer(i); + video::E_VERTEX_TYPE vtxType = buffer->getVertexType(); + u32 vertexCount = 0; + + if (hasSecondTextureCoordinates(vtxType)) + { + vertexCount = buffer->getVertexCount(); + switch(vtxType) + { + case video::EVT_2TCOORDS: + { + video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices(); + for (u32 j=0; jwriteLineBreak(); + } + } + break; + default: + break; + } + } // end this buffer has 2 texture coordinates + + if ( i == 0 ) + globalIndices[i].TCoord1StartIndex = 0; + + if (i+1 < mbCount) + globalIndices[i+1].TCoord1StartIndex = globalIndices[i].TCoord1StartIndex + vertexCount; + } + + Writer->writeClosingTag("float_array"); + Writer->writeLineBreak(); + + Writer->writeElement("technique_common", false); + Writer->writeLineBreak(); + + vertexCountStr = core::stringc(totalTCoords2Count); + + Writer->writeElement("accessor", false, "source", toRef(meshTexCoord1ArrayId).c_str(), + "count", vertexCountStr.c_str(), "stride", "2"); + Writer->writeLineBreak(); + + Writer->writeElement("param", true, "name", ParamNamesUV[0].c_str(), "type", "float"); + Writer->writeLineBreak(); + Writer->writeElement("param", true, "name", ParamNamesUV[1].c_str(), "type", "float"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("accessor"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("technique_common"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("source"); + Writer->writeLineBreak(); + } + + // write tangents + + // TODO + + // write vertices + core::stringc meshVtxId(meshId); + meshVtxId += "-Vtx"; + Writer->writeElement("vertices", false, "id", meshVtxId.c_str()); + Writer->writeLineBreak(); + + Writer->writeElement("input", true, "semantic", "POSITION", "source", toRef(meshPosId).c_str()); + Writer->writeLineBreak(); + + Writer->writeClosingTag("vertices"); + Writer->writeLineBreak(); + + // write polygons + + for (i=0; igetMeshBuffer(i); + + if ( buffer->getPrimitiveType() != EPT_TRIANGLES ) + { + os::Printer::log("Collada writer does not support non-triangle meshbuffers. Mesh: ", meshname.c_str(), ELL_WARNING); + continue; + } + + const u32 polyCount = buffer->getPrimitiveCount(); + core::stringc strPolyCount(polyCount); + irr::core::stringc strMat(nameForMaterialSymbol(mesh, i)); + + Writer->writeElement("triangles", false, "count", strPolyCount.c_str(), + "material", strMat.c_str()); + Writer->writeLineBreak(); + + Writer->writeElement("input", true, "semantic", "VERTEX", "source", toRef(meshVtxId).c_str(), "offset", "0"); + Writer->writeLineBreak(); + Writer->writeElement("input", true, "semantic", "TEXCOORD", "source", toRef(meshTexCoord0Id).c_str(), "offset", "1", "set", "0"); + Writer->writeLineBreak(); + Writer->writeElement("input", true, "semantic", "NORMAL", "source", toRef(meshNormalId).c_str(), "offset", "2"); + Writer->writeLineBreak(); + + bool has2ndTexCoords = hasSecondTextureCoordinates(buffer->getVertexType()); + if (has2ndTexCoords) + { + // TODO: when working on second uv-set - my suspicion is that this one should be called "TEXCOORD2" + // to allow bind_vertex_input to differentiate the uv-sets. + Writer->writeElement("input", true, "semantic", "TEXCOORD", "source", toRef(meshTexCoord1Id).c_str(), "idx", "3"); + Writer->writeLineBreak(); + } + + // write indices now + + // In Collada we us a single global buffer for all vertices, so indices have this offset compared to Irrlicht + u32 posIdx = globalIndices[i].PosStartIndex; + u32 tCoordIdx = globalIndices[i].TCoord0StartIndex; + u32 normalIdx = globalIndices[i].NormalStartIndex; + u32 tCoord2Idx = globalIndices[i].TCoord1StartIndex; + + Writer->writeElement("p", false); + + core::stringc strP; + strP.reserve(100); + for (u32 p=0; pgetIndices()[(p*3) + 2]; + strP = ""; + strP += irrIdx + posIdx; + strP += " "; + strP += irrIdx + tCoordIdx; + strP += " "; + strP += irrIdx + normalIdx; + strP += " "; + if (has2ndTexCoords) + { + strP += irrIdx + tCoord2Idx; + strP += " "; + } + + irrIdx = buffer->getIndices()[(p*3) + 1]; + strP += irrIdx + posIdx; + strP += " "; + strP += irrIdx + tCoordIdx; + strP += " "; + strP += irrIdx + normalIdx; + strP += " "; + if (has2ndTexCoords) + { + strP += irrIdx + tCoord2Idx; + strP += " "; + } + + irrIdx = buffer->getIndices()[(p*3) + 0]; + strP += irrIdx + posIdx; + strP += " "; + strP += irrIdx + tCoordIdx; + strP += " "; + strP += irrIdx + normalIdx; + if (has2ndTexCoords) + { + strP += " "; + strP += irrIdx + tCoord2Idx; + } + strP += " "; + + Writer->writeText(strP.c_str()); + } + + Writer->writeClosingTag("p"); + Writer->writeLineBreak(); + + // close index buffer section + + Writer->writeClosingTag("triangles"); + Writer->writeLineBreak(); + } + + // close mesh and geometry + delete [] globalIndices; + Writer->writeClosingTag("mesh"); + Writer->writeLineBreak(); + Writer->writeClosingTag("geometry"); + Writer->writeLineBreak(); +} + +void CColladaMeshWriter::writeLibraryImages() +{ + if ( getWriteTextures() && !LibraryImages.empty() ) + { + Writer->writeElement("library_images", false); + Writer->writeLineBreak(); + + for ( irr::u32 i=0; igetRelativeFilename(LibraryImages[i]->getName().getPath(), Directory)); + // + irr::core::stringc ncname( toNCName(irr::core::stringc(p)) ); + Writer->writeElement("image", false, "id", ncname.c_str(), "name", ncname.c_str()); + Writer->writeLineBreak(); + // ../flowers/rose01.jpg + Writer->writeElement("init_from", false); + Writer->writeText(pathToURI(p).c_str()); + Writer->writeClosingTag("init_from"); + Writer->writeLineBreak(); + // + Writer->writeClosingTag("image"); + Writer->writeLineBreak(); + } + + Writer->writeClosingTag("library_images"); + Writer->writeLineBreak(); + } +} + +void CColladaMeshWriter::writeColorElement(const video::SColorf & col, bool writeAlpha) +{ + Writer->writeElement("color", false); + + writeColor(col, writeAlpha); + + Writer->writeClosingTag("color"); + Writer->writeLineBreak(); +} + +void CColladaMeshWriter::writeColorElement(const video::SColor & col, bool writeAlpha) +{ + writeColorElement( video::SColorf(col), writeAlpha ); +} + +void CColladaMeshWriter::writeAmbientLightElement(const video::SColorf & col) +{ + Writer->writeElement("light", false, "id", "ambientlight"); + Writer->writeLineBreak(); + + Writer->writeElement("technique_common", false); + Writer->writeLineBreak(); + + Writer->writeElement("ambient", false); + Writer->writeLineBreak(); + + writeColorElement(col, false); + + Writer->writeClosingTag("ambient"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("technique_common"); + Writer->writeLineBreak(); + + Writer->writeClosingTag("light"); + Writer->writeLineBreak(); +} + +s32 CColladaMeshWriter::getCheckedTextureIdx(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs) +{ + if ( !getWriteTextures() + || !getProperties() ) + return -1; + + s32 idx = getProperties()->getTextureIdx(material, cs); + if ( idx >= 0 && !material.TextureLayer[idx].Texture ) + return -1; + + return idx; +} + +video::SColor CColladaMeshWriter::getColorMapping(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs, E_COLLADA_IRR_COLOR colType) +{ + switch ( colType ) + { + case ECIC_NONE: + return video::SColor(255, 0, 0, 0); + + case ECIC_CUSTOM: + return getProperties()->getCustomColor(material, cs); + + case ECIC_DIFFUSE: + return material.DiffuseColor; + + case ECIC_AMBIENT: + return material.AmbientColor; + + case ECIC_EMISSIVE: + return material.EmissiveColor; + + case ECIC_SPECULAR: + return material.SpecularColor; + } + return video::SColor(255, 0, 0, 0); +} + +void CColladaMeshWriter::writeTextureSampler(s32 textureIdx) +{ + irr::core::stringc sampler("tex"); + sampler += irr::core::stringc(textureIdx); + sampler += "-sampler"; + + // + Writer->writeElement("texture", true, "texture", sampler.c_str(), "texcoord", "uv" ); + Writer->writeLineBreak(); +} + +void CColladaMeshWriter::writeFxElement(const video::SMaterial & material, E_COLLADA_TECHNIQUE_FX techFx) +{ + core::stringc fxLabel; + bool writeEmission = true; + bool writeAmbient = true; + bool writeDiffuse = true; + bool writeSpecular = true; + bool writeShininess = true; + bool writeReflective = true; + bool writeReflectivity = true; + bool writeTransparent = true; + bool writeTransparency = true; + bool writeIndexOfRefraction = true; + switch ( techFx ) + { + case ECTF_BLINN: + fxLabel = "blinn"; + break; + case ECTF_PHONG: + fxLabel = "phong"; + break; + case ECTF_LAMBERT: + fxLabel = "lambert"; + writeSpecular = false; + writeShininess = false; + break; + case ECTF_CONSTANT: + fxLabel = "constant"; + writeAmbient = false; + writeDiffuse = false; + writeSpecular = false; + writeShininess = false; + break; + } + + Writer->writeElement(fxLabel.c_str(), false); + Writer->writeLineBreak(); + + // write all interesting material parameters + // attributes must be written in fixed order + if ( getProperties() ) + { + if ( writeEmission ) + { + writeColorFx(material, "emission", ECCS_EMISSIVE); + } + + if ( writeAmbient ) + { + writeColorFx(material, "ambient", ECCS_AMBIENT); + } + + if ( writeDiffuse ) + { + writeColorFx(material, "diffuse", ECCS_DIFFUSE); + } + + if ( writeSpecular ) + { + writeColorFx(material, "specular", ECCS_SPECULAR); + } + + if ( writeShininess ) + { + Writer->writeElement("shininess", false); + Writer->writeLineBreak(); + writeFloatElement(material.Shininess); + Writer->writeClosingTag("shininess"); + Writer->writeLineBreak(); + } + + if ( writeReflective ) + { + writeColorFx(material, "reflective", ECCS_REFLECTIVE); + } + + if ( writeReflectivity ) + { + f32 t = getProperties()->getReflectivity(material); + if ( t >= 0.f ) + { + // 1.000000 + Writer->writeElement("reflectivity", false); + Writer->writeLineBreak(); + writeFloatElement(t); + Writer->writeClosingTag("reflectivity"); + Writer->writeLineBreak(); + } + } + + if ( writeTransparent ) + { + E_COLLADA_TRANSPARENT_FX transparentFx = getProperties()->getTransparentFx(material); + writeColorFx(material, "transparent", ECCS_TRANSPARENT, "opaque", toString(transparentFx).c_str()); + } + + if ( writeTransparency ) + { + f32 t = getProperties()->getTransparency(material); + if ( t >= 0.f ) + { + // 1.000000 + Writer->writeElement("transparency", false); + Writer->writeLineBreak(); + writeFloatElement(t); + Writer->writeClosingTag("transparency"); + Writer->writeLineBreak(); + } + } + + if ( writeIndexOfRefraction ) + { + f32 t = getProperties()->getIndexOfRefraction(material); + if ( t >= 0.f ) + { + Writer->writeElement("index_of_refraction", false); + Writer->writeLineBreak(); + writeFloatElement(t); + Writer->writeClosingTag("index_of_refraction"); + Writer->writeLineBreak(); + } + } + } + + + Writer->writeClosingTag(fxLabel.c_str()); + Writer->writeLineBreak(); +} + +void CColladaMeshWriter::writeColorFx(const video::SMaterial & material, const c8 * colorname, E_COLLADA_COLOR_SAMPLER cs, const c8* attr1Name, const c8* attr1Value) +{ + irr::s32 idx = getCheckedTextureIdx(material, cs); + E_COLLADA_IRR_COLOR colType = idx < 0 ? getProperties()->getColorMapping(material, cs) : ECIC_NONE; + if ( idx >= 0 || colType != ECIC_NONE ) + { + Writer->writeElement(colorname, false, attr1Name, attr1Value); + Writer->writeLineBreak(); + if ( idx >= 0 ) + writeTextureSampler(idx); + else + writeColorElement(getColorMapping(material, cs, colType)); + Writer->writeClosingTag(colorname); + Writer->writeLineBreak(); + } +} + +void CColladaMeshWriter::writeNode(const c8 * nodeName, const c8 * content) +{ + Writer->writeElement(nodeName, false); + Writer->writeText(content); + Writer->writeClosingTag(nodeName); + Writer->writeLineBreak(); +} + +void CColladaMeshWriter::writeFloatElement(irr::f32 value) +{ + Writer->writeElement("float", false); + Writer->writeText(core::stringc((double)value).eraseTrailingFloatZeros().c_str()); + Writer->writeClosingTag("float"); + Writer->writeLineBreak(); +} + +void CColladaMeshWriter::writeRotateElement(const irr::core::vector3df& axis, irr::f32 angle) +{ + Writer->writeElement("rotate", false); + irr::core::stringc txt(axis.X); + txt.eraseTrailingFloatZeros(); + txt += " "; + txt += irr::core::stringc(axis.Y); + txt.eraseTrailingFloatZeros(); + txt += " "; + txt += irr::core::stringc(axis.Z * -1.f); + txt.eraseTrailingFloatZeros(); + txt += " "; + txt += irr::core::stringc((double)angle * -1.f); + txt.eraseTrailingFloatZeros(); + Writer->writeText(txt.c_str()); + Writer->writeClosingTag("rotate"); + Writer->writeLineBreak(); +} + +void CColladaMeshWriter::writeScaleElement(const irr::core::vector3df& scale) +{ + Writer->writeElement("scale", false); + irr::core::stringc txt(scale.X); + txt.eraseTrailingFloatZeros(); + txt += " "; + txt += irr::core::stringc(scale.Y); + txt.eraseTrailingFloatZeros(); + txt += " "; + txt += irr::core::stringc(scale.Z); + txt.eraseTrailingFloatZeros(); + Writer->writeText(txt.c_str()); + Writer->writeClosingTag("scale"); + Writer->writeLineBreak(); +} + +void CColladaMeshWriter::writeTranslateElement(const irr::core::vector3df& translate) +{ + Writer->writeElement("translate", false); + irr::core::stringc txt(translate.X); + txt.eraseTrailingFloatZeros(); + txt += " "; + txt += irr::core::stringc(translate.Y); + txt.eraseTrailingFloatZeros(); + txt += " "; + txt += irr::core::stringc(translate.Z*-1.f); + txt.eraseTrailingFloatZeros(); + Writer->writeText(txt.c_str()); + Writer->writeClosingTag("translate"); + Writer->writeLineBreak(); +} + +void CColladaMeshWriter::writeLookAtElement(const irr::core::vector3df& eyePos, const irr::core::vector3df& targetPos, const irr::core::vector3df& upVector) +{ + Writer->writeElement("lookat", false); + + c8 tmpbuf[255]; + snprintf_irr(tmpbuf, 255, "%f %f %f %f %f %f %f %f %f", eyePos.X, eyePos.Y, eyePos.Z*-1.f, targetPos.X, targetPos.Y, targetPos.Z*-1.f, upVector.X, upVector.Y, upVector.Z*-1.f); + Writer->writeText(tmpbuf); + + Writer->writeClosingTag("lookat"); + Writer->writeLineBreak(); +} + +void CColladaMeshWriter::writeMatrixElement(const irr::core::matrix4& matrixIrr) +{ + irr::core::matrix4 matrix(matrixIrr.getTransposed()); // transposed because row/lines are written other way round in Collada + // Convert to right-handed + matrix[2] *= -1.f; + matrix[6] *= -1.f; + matrix[8] *= -1.f; + matrix[9] *= -1.f; + matrix[11] *= -1.f; + matrix[14] *= -1.f; + + Writer->writeElement("matrix", false); + Writer->writeLineBreak(); + + for ( int a=0; a<4; ++a ) + { + irr::core::stringc txt; + for ( int b=0; b<4; ++b ) + { + if ( b > 0 ) + txt += " "; + txt += irr::core::stringc(matrix[a*4+b]).eraseTrailingFloatZeros(); + } + Writer->writeText(txt.c_str()); + Writer->writeLineBreak(); + } + + Writer->writeClosingTag("matrix"); + Writer->writeLineBreak(); +} + +} // end namespace +} // end namespace + +#endif + diff --git a/source/Irrlicht/CColladaMeshWriter.h b/source/Irrlicht/CColladaMeshWriter.h new file mode 100644 index 00000000..6c07d49c --- /dev/null +++ b/source/Irrlicht/CColladaMeshWriter.h @@ -0,0 +1,282 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_C_COLLADA_MESH_WRITER_H_INCLUDED__ +#define __IRR_C_COLLADA_MESH_WRITER_H_INCLUDED__ + +#include "IColladaMeshWriter.h" +#include "S3DVertex.h" +#include "irrMap.h" +#include "IVideoDriver.h" +#include "IXMLWriter.h" + +namespace irr +{ +namespace io +{ + class IFileSystem; +} + +namespace scene +{ + //! Callback interface for properties which can be used to influence collada writing + // (Implementer note: keep namespace labels here to make it easier for users copying this one) + class CColladaMeshWriterProperties : public virtual IColladaMeshWriterProperties + { + public: + //! Which lighting model should be used in the technique (FX) section when exporting effects (materials) + virtual irr::scene::E_COLLADA_TECHNIQUE_FX getTechniqueFx(const irr::video::SMaterial& material) const _IRR_OVERRIDE_; + + //! Which texture index should be used when writing the texture of the given sampler color. + virtual irr::s32 getTextureIdx(const irr::video::SMaterial & material, irr::scene::E_COLLADA_COLOR_SAMPLER cs) const _IRR_OVERRIDE_; + + //! Return which color from Irrlicht should be used for the color requested by collada + virtual irr::scene::E_COLLADA_IRR_COLOR getColorMapping(const irr::video::SMaterial & material, irr::scene::E_COLLADA_COLOR_SAMPLER cs) const _IRR_OVERRIDE_; + + //! Return custom colors for certain color types requested by collada. + virtual irr::video::SColor getCustomColor(const irr::video::SMaterial & material, irr::scene::E_COLLADA_COLOR_SAMPLER cs) const _IRR_OVERRIDE_; + + //! Return the settings for transparence + virtual irr::scene::E_COLLADA_TRANSPARENT_FX getTransparentFx(const irr::video::SMaterial& material) const _IRR_OVERRIDE_; + + //! Transparency value for that material. + virtual irr::f32 getTransparency(const irr::video::SMaterial& material) const _IRR_OVERRIDE_; + + //! Reflectivity value for that material + virtual irr::f32 getReflectivity(const irr::video::SMaterial& material) const _IRR_OVERRIDE_; + + //! Return index of refraction for that material + virtual irr::f32 getIndexOfRefraction(const irr::video::SMaterial& material) const _IRR_OVERRIDE_; + + //! Should node be used in scene export? By default all visible nodes are exported. + virtual bool isExportable(const irr::scene::ISceneNode * node) const _IRR_OVERRIDE_; + + //! Return the mesh for the given nod. If it has no mesh or shouldn't export it's mesh return 0. + virtual irr::scene::IMesh* getMesh(irr::scene::ISceneNode * node) _IRR_OVERRIDE_; + + //! Return if the node has it's own material overwriting the mesh-materials + virtual bool useNodeMaterial(const scene::ISceneNode* node) const _IRR_OVERRIDE_; + }; + + class CColladaMeshWriterNames : public virtual IColladaMeshWriterNames + { + public: + CColladaMeshWriterNames(IColladaMeshWriter * writer); + virtual irr::core::stringc nameForMesh(const scene::IMesh* mesh, int instance) _IRR_OVERRIDE_; + virtual irr::core::stringc nameForNode(const scene::ISceneNode* node) _IRR_OVERRIDE_; + virtual irr::core::stringc nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node) _IRR_OVERRIDE_; + protected: + irr::core::stringc nameForPtr(const void* ptr) const; + private: + IColladaMeshWriter * ColladaMeshWriter; + }; + + + +//! class to write meshes, implementing a COLLADA (.dae, .xml) writer +/** This writer implementation has been originally developed for irrEdit and then +merged out to the Irrlicht Engine */ +class CColladaMeshWriter : public IColladaMeshWriter +{ +public: + + CColladaMeshWriter(ISceneManager * smgr, video::IVideoDriver* driver, io::IFileSystem* fs); + virtual ~CColladaMeshWriter(); + + //! Returns the type of the mesh writer + virtual EMESH_WRITER_TYPE getType() const _IRR_OVERRIDE_; + + //! writes a scene starting with the given node + virtual bool writeScene(io::IWriteFile* file, scene::ISceneNode* root, int writeRoot) _IRR_OVERRIDE_; + + //! writes a mesh + virtual bool writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags=EMWF_NONE) _IRR_OVERRIDE_; + + // Restrict the characters of oldString a set of allowed characters in xs:NCName and add the prefix. + virtual irr::core::stringc toNCName(const irr::core::stringc& oldString, const irr::core::stringc& prefix=irr::core::stringc("_NC_")) const _IRR_OVERRIDE_; + + //! After export you can find out which name had been used for writing the geometry for this node. + virtual const irr::core::stringc* findGeometryNameForNode(ISceneNode* node) _IRR_OVERRIDE_; + +protected: + + void reset(); + bool hasSecondTextureCoordinates(video::E_VERTEX_TYPE type) const; + void writeUv(const irr::core::vector2df& vec); + void writeVector(const irr::core::vector3df& vec); + void writeColor(const irr::video::SColorf& colorf, bool writeAlpha=true); + inline irr::core::stringc toString(const irr::video::ECOLOR_FORMAT format) const; + inline irr::core::stringc toString(const irr::video::E_TEXTURE_CLAMP clamp) const; + inline irr::core::stringc toString(const irr::scene::E_COLLADA_TRANSPARENT_FX opaque) const; + inline irr::core::stringc toRef(const irr::core::stringc& source) const; + bool isCamera(const scene::ISceneNode* node) const; + irr::core::stringc nameForMesh(const scene::IMesh* mesh, int instance) const; + irr::core::stringc nameForNode(const scene::ISceneNode* node) const; + irr::core::stringc nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node); + irr::core::stringc nameForMaterialSymbol(const scene::IMesh* mesh, int materialId) const; + irr::core::stringc findCachedMaterialName(const irr::video::SMaterial& material) const; + irr::core::stringc minTexfilterToString(bool bilinear, bool trilinear) const; + irr::core::stringc magTexfilterToString(bool bilinear, bool trilinear) const; + irr::core::stringc pathToURI(const irr::io::path& path) const; + inline bool isXmlNameStartChar(c8 c) const; + inline bool isXmlNameChar(c8 c) const; + s32 getCheckedTextureIdx(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs); + video::SColor getColorMapping(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs, E_COLLADA_IRR_COLOR colType); + void writeAsset(); + void makeMeshNames(irr::scene::ISceneNode * node); + void writeNodeMaterials(irr::scene::ISceneNode * node); + void writeNodeEffects(irr::scene::ISceneNode * node); + void writeNodeLights(irr::scene::ISceneNode * node); + void writeNodeCameras(irr::scene::ISceneNode * node); + void writeAllMeshGeometries(); + void writeSceneNode(irr::scene::ISceneNode * node); + void writeMeshMaterials(scene::IMesh* mesh, irr::core::array * materialNamesOut=0); + void writeMeshEffects(scene::IMesh* mesh); + void writeMaterialEffect(const irr::core::stringc& materialname, const video::SMaterial & material); + void writeMeshGeometry(const irr::core::stringc& meshname, scene::IMesh* mesh); + void writeMeshInstanceGeometry(const irr::core::stringc& meshname, scene::IMesh* mesh, scene::ISceneNode* node=0); + void writeMaterial(const irr::core::stringc& materialname); + void writeLightInstance(const irr::core::stringc& lightName); + void writeCameraInstance(const irr::core::stringc& cameraName); + void writeLibraryImages(); + void writeColorFx(const video::SMaterial & material, const c8 * colorname, E_COLLADA_COLOR_SAMPLER cs, const c8* attr1Name=0, const c8* attr1Value=0); + void writeAmbientLightElement(const video::SColorf & col); + void writeColorElement(const video::SColor & col, bool writeAlpha=true); + void writeColorElement(const video::SColorf & col, bool writeAlpha=true); + void writeTextureSampler(s32 textureIdx); + void writeFxElement(const video::SMaterial & material, E_COLLADA_TECHNIQUE_FX techFx); + void writeNode(const c8 * nodeName, const c8 * content); + void writeFloatElement(irr::f32 value); + void writeRotateElement(const irr::core::vector3df& axis, irr::f32 angle); + void writeScaleElement(const irr::core::vector3df& scale); + void writeTranslateElement(const irr::core::vector3df& translate); + void writeLookAtElement(const irr::core::vector3df& eyePos, const irr::core::vector3df& targetPos, const irr::core::vector3df& upVector); + void writeMatrixElement(const irr::core::matrix4& matrix); + + struct SComponentGlobalStartPos + { + SComponentGlobalStartPos() : PosStartIndex(0), + NormalStartIndex(0), + TCoord0StartIndex(0), + TCoord1StartIndex(0) + { } + + u32 PosStartIndex; + u32 NormalStartIndex; + u32 TCoord0StartIndex; + u32 TCoord1StartIndex; + }; + + io::IFileSystem* FileSystem; + video::IVideoDriver* VideoDriver; + io::IXMLWriterUTF8* Writer; + core::array LibraryImages; + io::path Directory; + + // Helper struct for creating geometry copies for the ECGI_PER_MESH_AND_MATERIAL settings. + struct SGeometryMeshMaterials + { + bool equals(const core::array& names) const + { + if ( names.size() != MaterialNames.size() ) + return false; + for ( irr::u32 i=0; i MaterialNames; // Material names exported for this instance + core::array MaterialOwners; // Nodes using this specific mesh-material combination + }; + + // Check per mesh-ptr if stuff has been written for this mesh already + struct SColladaMesh + { + SColladaMesh() : MaterialsWritten(false), EffectsWritten(false) + { + } + + SGeometryMeshMaterials * findGeometryMeshMaterials(const irr::core::array materialNames) + { + for ( irr::u32 i=0; i= 0 ) + return GeometryMeshMaterials[i].GeometryName; + } + return Name; // (shouldn't get here usually) + } + + irr::core::stringc Name; + bool MaterialsWritten; // just an optimization doing that here in addition to the MaterialsWritten map + bool EffectsWritten; // just an optimization doing that here in addition to the EffectsWritten map + + core::array GeometryMeshMaterials; + }; + typedef core::map::Node MeshNode; + core::map Meshes; + + // structure for the lights library + struct SColladaLight + { + SColladaLight() {} + irr::core::stringc Name; + }; + typedef core::map::Node LightNode; + core::map LightNodes; + + // structure for the camera library + typedef core::map::Node CameraNode; + core::map CameraNodes; + + // Check per name if stuff has been written already + // TODO: second parameter not needed, we just don't have a core::set class yet in Irrlicht + core::map MaterialsWritten; + core::map EffectsWritten; + + // Cache material names + struct MaterialName + { + MaterialName(const irr::video::SMaterial & material, const irr::core::stringc& name) + : Material(material), Name(name) + {} + irr::video::SMaterial Material; + irr::core::stringc Name; + }; + irr::core::array< MaterialName > MaterialNameCache; + + irr::core::stringc WriteBuffer; // use for writing short strings to avoid regular memory allocations + + struct EscapeCharacterURL + { + EscapeCharacterURL(irr::c8 c, const irr::c8* e) + : Character(c) + { + Escape = e; + } + + irr::c8 Character; // unescaped (like ' ') + irr::core::stringc Escape; // escaped (like '%20') + }; + irr::core::array EscapeCharsAnyURI; +}; + + +} // end namespace +} // end namespace + +#endif diff --git a/source/Irrlicht/CColorConverter.cpp b/source/Irrlicht/CColorConverter.cpp new file mode 100644 index 00000000..76e606fb --- /dev/null +++ b/source/Irrlicht/CColorConverter.cpp @@ -0,0 +1,830 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CColorConverter.h" +#include "SColor.h" +#include "os.h" +#include "irrString.h" + +namespace irr +{ +namespace video +{ + +//! converts a monochrome bitmap to A1R5G5B5 data +void CColorConverter::convert1BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, s32 linepad, bool flip) +{ + if (!in || !out) + return; + + if (flip) + out += width * height; + + for (s32 y=0; y>shift & 0x01 ? (s16)0xffff : (s16)0x8000; + + if ((--shift)<0) // 8 pixel done + { + shift=7; + ++in; + } + } + + if (shift != 7) // width did not fill last byte + ++in; + + if (!flip) + out += width; + in += linepad; + } +} + + + +//! converts a 4 bit palettized image to A1R5G5B5 +void CColorConverter::convert4BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, const s32* palette, s32 linepad, bool flip) +{ + if (!in || !out || !palette) + return; + + if (flip) + out += width*height; + + for (s32 y=0; y> shift) & 0xf)]); + + if (shift==0) + { + shift = 4; + ++in; + } + else + shift = 0; + } + + if (shift == 0) // odd width + ++in; + + if (!flip) + out += width; + in += linepad; + } +} + + + +//! converts a 8 bit palettized image into A1R5G5B5 +void CColorConverter::convert8BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, const s32* palette, s32 linepad, bool flip) +{ + if (!in || !out || !palette) + return; + + if (flip) + out += width * height; + + for (s32 y=0; y> 15)&0x1)<<31) | (((t >> 10)&0x1F)<<19) | + (((t >> 5)&0x1F)<<11) | (t&0x1F)<<3; + out[(s32)(y*newWidth + x)] = t; + + sy+=sourceYStep; + } + } +} + + + +//! copies X8R8G8B8 32 bit data +void CColorConverter::convert32BitTo32Bit(const s32* in, s32* out, s32 width, s32 height, s32 linepad, bool flip) +{ + if (!in || !out) + return; + + if (flip) + out += width * height; + + for (s32 y=0; y> 7; + dB[1] = (*sB & 0x03e0) >> 2; + dB[0] = (*sB & 0x1f) << 3; + + sB += 1; + dB += 3; + } +} + +void CColorConverter::convert_A1R5G5B5toB8G8R8(const void* sP, s32 sN, void* dP) +{ + u16* sB = (u16*)sP; + u8 * dB = (u8 *)dP; + + for (s32 x = 0; x < sN; ++x) + { + dB[0] = (*sB & 0x7c00) >> 7; + dB[1] = (*sB & 0x03e0) >> 2; + dB[2] = (*sB & 0x1f) << 3; + + sB += 1; + dB += 3; + } +} + +void CColorConverter::convert_A1R5G5B5toR5G5B5A1(const void* sP, s32 sN, void* dP) +{ + const u16* sB = (const u16*)sP; + u16* dB = (u16*)dP; + + for (s32 x = 0; x < sN; ++x) + { + *dB = (*sB<<1)|(*sB>>15); + ++sB; ++dB; + } +} + +void CColorConverter::convert_A1R5G5B5toA8R8G8B8(const void* sP, s32 sN, void* dP) +{ + u16* sB = (u16*)sP; + u32* dB = (u32*)dP; + + for (s32 x = 0; x < sN; ++x) + *dB++ = A1R5G5B5toA8R8G8B8(*sB++); +} + +void CColorConverter::convert_A1R5G5B5toA1R5G5B5(const void* sP, s32 sN, void* dP) +{ + memcpy(dP, sP, sN * 2); +} + +void CColorConverter::convert_A1R5G5B5toR5G6B5(const void* sP, s32 sN, void* dP) +{ + u16* sB = (u16*)sP; + u16* dB = (u16*)dP; + + for (s32 x = 0; x < sN; ++x) + *dB++ = A1R5G5B5toR5G6B5(*sB++); +} + +void CColorConverter::convert_A8R8G8B8toR8G8B8(const void* sP, s32 sN, void* dP) +{ + u8* sB = (u8*)sP; + u8* dB = (u8*)dP; + + for (s32 x = 0; x < sN; ++x) + { + // sB[3] is alpha + dB[0] = sB[2]; + dB[1] = sB[1]; + dB[2] = sB[0]; + + sB += 4; + dB += 3; + } +} + +void CColorConverter::convert_A8R8G8B8toB8G8R8(const void* sP, s32 sN, void* dP) +{ + u8* sB = (u8*)sP; + u8* dB = (u8*)dP; + + for (s32 x = 0; x < sN; ++x) + { + // sB[3] is alpha + dB[0] = sB[0]; + dB[1] = sB[1]; + dB[2] = sB[2]; + + sB += 4; + dB += 3; + } +} + +void CColorConverter::convert_A8R8G8B8toA8R8G8B8(const void* sP, s32 sN, void* dP) +{ + memcpy(dP, sP, sN * 4); +} + +void CColorConverter::convert_A8R8G8B8toA1R5G5B5(const void* sP, s32 sN, void* dP) +{ + u32* sB = (u32*)sP; + u16* dB = (u16*)dP; + + for (s32 x = 0; x < sN; ++x) + *dB++ = A8R8G8B8toA1R5G5B5(*sB++); +} + +void CColorConverter::convert_A8R8G8B8toA1B5G5R5(const void* sP, s32 sN, void* dP) +{ + u8 * sB = (u8 *)sP; + u16* dB = (u16*)dP; + + for (s32 x = 0; x < sN; ++x) + { + s32 r = sB[0] >> 3; + s32 g = sB[1] >> 3; + s32 b = sB[2] >> 3; + s32 a = sB[3] >> 3; + + dB[0] = (a << 15) | (r << 10) | (g << 5) | (b); + + sB += 4; + dB += 1; + } +} + +void CColorConverter::convert_A8R8G8B8toR5G6B5(const void* sP, s32 sN, void* dP) +{ + u8 * sB = (u8 *)sP; + u16* dB = (u16*)dP; + + for (s32 x = 0; x < sN; ++x) + { + s32 r = sB[2] >> 3; + s32 g = sB[1] >> 2; + s32 b = sB[0] >> 3; + + dB[0] = (r << 11) | (g << 5) | (b); + + sB += 4; + dB += 1; + } +} + +void CColorConverter::convert_A8R8G8B8toR3G3B2(const void* sP, s32 sN, void* dP) +{ + u8* sB = (u8*)sP; + u8* dB = (u8*)dP; + + for (s32 x = 0; x < sN; ++x) + { + u8 r = sB[2] & 0xe0; + u8 g = (sB[1] & 0xe0) >> 3; + u8 b = (sB[0] & 0xc0) >> 6; + + dB[0] = (r | g | b); + + sB += 4; + dB += 1; + } +} + +void CColorConverter::convert_R8G8B8toR8G8B8(const void* sP, s32 sN, void* dP) +{ + memcpy(dP, sP, sN * 3); +} + +void CColorConverter::convert_R8G8B8toA8R8G8B8(const void* sP, s32 sN, void* dP) +{ + u8* sB = (u8* )sP; + u32* dB = (u32*)dP; + + for (s32 x = 0; x < sN; ++x) + { + *dB = 0xff000000 | (sB[0]<<16) | (sB[1]<<8) | sB[2]; + + sB += 3; + ++dB; + } +} + +void CColorConverter::convert_R8G8B8toA1R5G5B5(const void* sP, s32 sN, void* dP) +{ + u8 * sB = (u8 *)sP; + u16* dB = (u16*)dP; + + for (s32 x = 0; x < sN; ++x) + { + s32 r = sB[0] >> 3; + s32 g = sB[1] >> 3; + s32 b = sB[2] >> 3; + + dB[0] = (0x8000) | (r << 10) | (g << 5) | (b); + + sB += 3; + dB += 1; + } +} + +void CColorConverter::convert_B8G8R8toA8R8G8B8(const void* sP, s32 sN, void* dP) +{ + u8* sB = (u8* )sP; + u32* dB = (u32*)dP; + + for (s32 x = 0; x < sN; ++x) + { + *dB = 0xff000000 | (sB[2]<<16) | (sB[1]<<8) | sB[0]; + + sB += 3; + ++dB; + } +} + +void CColorConverter::convert_A8R8G8B8toR8G8B8A8(const void* sP, s32 sN, void* dP) +{ + const u32* sB = (const u32*)sP; + u32* dB = (u32*)dP; + + for (s32 x = 0; x < sN; ++x) + { + *dB++ = (*sB<<8) | (*sB>>24); + ++sB; + } +} + +void CColorConverter::convert_A8R8G8B8toA8B8G8R8(const void* sP, s32 sN, void* dP) +{ + const u32* sB = (const u32*)sP; + u32* dB = (u32*)dP; + + for (s32 x = 0; x < sN; ++x) + { + *dB++ = (*sB&0xff00ff00)|((*sB&0x00ff0000)>>16)|((*sB&0x000000ff)<<16); + ++sB; + } +} + +void CColorConverter::convert_B8G8R8A8toA8R8G8B8(const void* sP, s32 sN, void* dP) +{ + u8* sB = (u8*)sP; + u8* dB = (u8*)dP; + + for (s32 x = 0; x < sN; ++x) + { + dB[0] = sB[3]; + dB[1] = sB[2]; + dB[2] = sB[1]; + dB[3] = sB[0]; + + sB += 4; + dB += 4; + } + +} + +void CColorConverter::convert_R8G8B8toB8G8R8(const void* sP, s32 sN, void* dP) +{ + u8* sB = (u8*)sP; + u8* dB = (u8*)dP; + + for (s32 x = 0; x < sN; ++x) + { + dB[2] = sB[0]; + dB[1] = sB[1]; + dB[0] = sB[2]; + + sB += 3; + dB += 3; + } +} + +void CColorConverter::convert_R8G8B8toR5G6B5(const void* sP, s32 sN, void* dP) +{ + u8 * sB = (u8 *)sP; + u16* dB = (u16*)dP; + + for (s32 x = 0; x < sN; ++x) + { + s32 r = sB[0] >> 3; + s32 g = sB[1] >> 2; + s32 b = sB[2] >> 3; + + dB[0] = (r << 11) | (g << 5) | (b); + + sB += 3; + dB += 1; + } +} + +void CColorConverter::convert_R5G6B5toR5G6B5(const void* sP, s32 sN, void* dP) +{ + memcpy(dP, sP, sN * 2); +} + +void CColorConverter::convert_R5G6B5toR8G8B8(const void* sP, s32 sN, void* dP) +{ + u16* sB = (u16*)sP; + u8 * dB = (u8 *)dP; + + for (s32 x = 0; x < sN; ++x) + { + dB[0] = (*sB & 0xf800) >> 8; + dB[1] = (*sB & 0x07e0) >> 3; + dB[2] = (*sB & 0x001f) << 3; + + sB += 1; + dB += 3; + } +} + +void CColorConverter::convert_R5G6B5toB8G8R8(const void* sP, s32 sN, void* dP) +{ + u16* sB = (u16*)sP; + u8 * dB = (u8 *)dP; + + for (s32 x = 0; x < sN; ++x) + { + dB[2] = (*sB & 0xf800) >> 8; + dB[1] = (*sB & 0x07e0) >> 3; + dB[0] = (*sB & 0x001f) << 3; + + sB += 1; + dB += 3; + } +} + +void CColorConverter::convert_R5G6B5toA8R8G8B8(const void* sP, s32 sN, void* dP) +{ + u16* sB = (u16*)sP; + u32* dB = (u32*)dP; + + for (s32 x = 0; x < sN; ++x) + *dB++ = R5G6B5toA8R8G8B8(*sB++); +} + +void CColorConverter::convert_R5G6B5toA1R5G5B5(const void* sP, s32 sN, void* dP) +{ + u16* sB = (u16*)sP; + u16* dB = (u16*)dP; + + for (s32 x = 0; x < sN; ++x) + *dB++ = R5G6B5toA1R5G5B5(*sB++); +} + +bool CColorConverter::canConvertFormat(ECOLOR_FORMAT sourceFormat, ECOLOR_FORMAT destFormat) +{ + switch (sourceFormat) + { + case ECF_A1R5G5B5: + switch (destFormat) + { + case ECF_A1R5G5B5: + case ECF_R5G6B5: + case ECF_A8R8G8B8: + case ECF_R8G8B8: + return true; + default: + break; + } + break; + case ECF_R5G6B5: + switch (destFormat) + { + case ECF_A1R5G5B5: + case ECF_R5G6B5: + case ECF_A8R8G8B8: + case ECF_R8G8B8: + return true; + default: + break; + } + break; + case ECF_A8R8G8B8: + switch (destFormat) + { + case ECF_A1R5G5B5: + case ECF_R5G6B5: + case ECF_A8R8G8B8: + case ECF_R8G8B8: + return true; + default: + break; + } + break; + case ECF_R8G8B8: + switch (destFormat) + { + case ECF_A1R5G5B5: + case ECF_R5G6B5: + case ECF_A8R8G8B8: + case ECF_R8G8B8: + return true; + default: + break; + } + break; + default: + break; + } + return false; +} + +void CColorConverter::convert_viaFormat(const void* sP, ECOLOR_FORMAT sF, s32 sN, + void* dP, ECOLOR_FORMAT dF) +{ + // please also update can_convert_viaFormat when adding new conversions + switch (sF) + { + case ECF_A1R5G5B5: + switch (dF) + { + case ECF_A1R5G5B5: + convert_A1R5G5B5toA1R5G5B5(sP, sN, dP); + break; + case ECF_R5G6B5: + convert_A1R5G5B5toR5G6B5(sP, sN, dP); + break; + case ECF_A8R8G8B8: + convert_A1R5G5B5toA8R8G8B8(sP, sN, dP); + break; + case ECF_R8G8B8: + convert_A1R5G5B5toR8G8B8(sP, sN, dP); + break; + default: + break; + } + break; + case ECF_R5G6B5: + switch (dF) + { + case ECF_A1R5G5B5: + convert_R5G6B5toA1R5G5B5(sP, sN, dP); + break; + case ECF_R5G6B5: + convert_R5G6B5toR5G6B5(sP, sN, dP); + break; + case ECF_A8R8G8B8: + convert_R5G6B5toA8R8G8B8(sP, sN, dP); + break; + case ECF_R8G8B8: + convert_R5G6B5toR8G8B8(sP, sN, dP); + break; + default: + break; + } + break; + case ECF_A8R8G8B8: + switch (dF) + { + case ECF_A1R5G5B5: + convert_A8R8G8B8toA1R5G5B5(sP, sN, dP); + break; + case ECF_R5G6B5: + convert_A8R8G8B8toR5G6B5(sP, sN, dP); + break; + case ECF_A8R8G8B8: + convert_A8R8G8B8toA8R8G8B8(sP, sN, dP); + break; + case ECF_R8G8B8: + convert_A8R8G8B8toR8G8B8(sP, sN, dP); + break; + default: + break; + } + break; + case ECF_R8G8B8: + switch (dF) + { + case ECF_A1R5G5B5: + convert_R8G8B8toA1R5G5B5(sP, sN, dP); + break; + case ECF_R5G6B5: + convert_R8G8B8toR5G6B5(sP, sN, dP); + break; + case ECF_A8R8G8B8: + convert_R8G8B8toA8R8G8B8(sP, sN, dP); + break; + case ECF_R8G8B8: + convert_R8G8B8toR8G8B8(sP, sN, dP); + break; + default: + break; + } + break; +#ifndef _DEBUG + default: + break; +#endif + } +} + + +} // end namespace video +} // end namespace irr diff --git a/source/Irrlicht/CColorConverter.h b/source/Irrlicht/CColorConverter.h new file mode 100644 index 00000000..7a8f4a38 --- /dev/null +++ b/source/Irrlicht/CColorConverter.h @@ -0,0 +1,101 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_COLOR_CONVERTER_H_INCLUDED__ +#define __C_COLOR_CONVERTER_H_INCLUDED__ + +#include "irrTypes.h" +#include "IImage.h" + +namespace irr +{ +namespace video +{ + +class CColorConverter +{ +public: + + //! converts a monochrome bitmap to A1R5G5B5 + static void convert1BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, s32 linepad=0, bool flip=false); + + //! converts a 4 bit palettized image to A1R5G5B5 + static void convert4BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, const s32* palette, s32 linepad=0, bool flip=false); + + //! converts a 8 bit palettized image to A1R5G5B5 + static void convert8BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, const s32* palette, s32 linepad=0, bool flip=false); + + //! converts a 8 bit palettized or non palettized image (A8) into R8G8B8 + static void convert8BitTo24Bit(const u8* in, u8* out, s32 width, s32 height, const u8* palette, s32 linepad = 0, bool flip=false); + + //! converts a 8 bit palettized or non palettized image (A8) into A8R8G8B8 + static void convert8BitTo32Bit(const u8* in, u8* out, s32 width, s32 height, const u8* palette, s32 linepad = 0, bool flip=false); + + //! converts R8G8B8 16 bit data to A1R5G5B5 data + static void convert16BitTo16Bit(const s16* in, s16* out, s32 width, s32 height, s32 linepad=0, bool flip=false); + + //! copies R8G8B8 24 bit data to 24 data, and flips and + //! mirrors the image during the process. + static void convert24BitTo24Bit(const u8* in, u8* out, s32 width, s32 height, s32 linepad=0, bool flip=false, bool bgr=false); + + //! Resizes the surface to a new size and converts it at the same time + //! to an A8R8G8B8 format, returning the pointer to the new buffer. + static void convert16bitToA8R8G8B8andResize(const s16* in, s32* out, s32 newWidth, s32 newHeight, s32 currentWidth, s32 currentHeight); + + //! copies X8R8G8B8 32 bit data, and flips and + //! mirrors the image during the process. + static void convert32BitTo32Bit(const s32* in, s32* out, s32 width, s32 height, s32 linepad, bool flip=false); + + + //! Functions for converting one image format to another efficiently + //! and hopefully correctly. + //! Note that the format descriptions refer to the ECOLOR_FORMAT's and not to memory layout. + //! Reasons for that go back to DX9 naming which tended to flip 32-bit and 16-bit byte orders so ARGB usually means BGRA. + //! + //! \param sP pointer to source pixel data + //! \param sN number of source pixels to copy + //! \param dP pointer to destination data buffer. must be big enough + //! to hold sN pixels in the output format. + static void convert_A1R5G5B5toR8G8B8(const void* sP, s32 sN, void* dP); + static void convert_A1R5G5B5toB8G8R8(const void* sP, s32 sN, void* dP); + static void convert_A1R5G5B5toA8R8G8B8(const void* sP, s32 sN, void* dP); + static void convert_A1R5G5B5toA1R5G5B5(const void* sP, s32 sN, void* dP); + static void convert_A1R5G5B5toR5G5B5A1(const void* sP, s32 sN, void* dP); + static void convert_A1R5G5B5toR5G6B5(const void* sP, s32 sN, void* dP); + + static void convert_A8R8G8B8toR8G8B8(const void* sP, s32 sN, void* dP); + static void convert_A8R8G8B8toB8G8R8(const void* sP, s32 sN, void* dP); + static void convert_A8R8G8B8toA8R8G8B8(const void* sP, s32 sN, void* dP); + static void convert_A8R8G8B8toA1R5G5B5(const void* sP, s32 sN, void* dP); + static void convert_A8R8G8B8toA1B5G5R5(const void* sP, s32 sN, void* dP); + static void convert_A8R8G8B8toR5G6B5(const void* sP, s32 sN, void* dP); + + static void convert_A8R8G8B8toR3G3B2(const void* sP, s32 sN, void* dP); + static void convert_R8G8B8toR8G8B8(const void* sP, s32 sN, void* dP); + static void convert_R8G8B8toA8R8G8B8(const void* sP, s32 sN, void* dP); + static void convert_R8G8B8toA1R5G5B5(const void* sP, s32 sN, void* dP); + static void convert_R8G8B8toB8G8R8(const void* sP, s32 sN, void* dP); + static void convert_R8G8B8toR5G6B5(const void* sP, s32 sN, void* dP); + static void convert_B8G8R8toA8R8G8B8(const void* sP, s32 sN, void* dP); + static void convert_B8G8R8A8toA8R8G8B8(const void* sP, s32 sN, void* dP); + static void convert_A8R8G8B8toR8G8B8A8(const void* sP, s32 sN, void* dP); + static void convert_A8R8G8B8toA8B8G8R8(const void* sP, s32 sN, void* dP); + + static void convert_R5G6B5toR5G6B5(const void* sP, s32 sN, void* dP); + static void convert_R5G6B5toR8G8B8(const void* sP, s32 sN, void* dP); + static void convert_R5G6B5toB8G8R8(const void* sP, s32 sN, void* dP); + static void convert_R5G6B5toA8R8G8B8(const void* sP, s32 sN, void* dP); + static void convert_R5G6B5toA1R5G5B5(const void* sP, s32 sN, void* dP); + static void convert_viaFormat(const void* sP, ECOLOR_FORMAT sF, s32 sN, + void* dP, ECOLOR_FORMAT dF); + // Check if convert_viaFormat is usable + static bool canConvertFormat(ECOLOR_FORMAT sourceFormat, ECOLOR_FORMAT destFormat); +}; + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CCubeSceneNode.cpp b/source/Irrlicht/CCubeSceneNode.cpp new file mode 100644 index 00000000..0400c116 --- /dev/null +++ b/source/Irrlicht/CCubeSceneNode.cpp @@ -0,0 +1,246 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_CUBE_SCENENODE_ +#include "CCubeSceneNode.h" +#include "IVideoDriver.h" +#include "ISceneManager.h" +#include "S3DVertex.h" +#include "SMeshBuffer.h" +#include "os.h" +#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ +#include "CShadowVolumeSceneNode.h" +#else +#include "IShadowVolumeSceneNode.h" +#endif // _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ + +namespace irr +{ +namespace scene +{ + + /* + 011 111 + /6,8------/5 y + / | / | ^ z + / | / | | / + 010 3,9-------2 | |/ + | 7- - -10,4 101 *---->x + | / | / + |/ | / + 0------11,1/ + 000 100 + */ + +//! constructor +CCubeSceneNode::CCubeSceneNode(f32 size, ISceneNode* parent, ISceneManager* mgr, + s32 id, const core::vector3df& position, + const core::vector3df& rotation, const core::vector3df& scale) + : IMeshSceneNode(parent, mgr, id, position, rotation, scale), + Mesh(0), Shadow(0), Size(size) +{ + #ifdef _DEBUG + setDebugName("CCubeSceneNode"); + #endif + + setSize(); +} + + +CCubeSceneNode::~CCubeSceneNode() +{ + if (Shadow) + Shadow->drop(); + if (Mesh) + Mesh->drop(); +} + + +void CCubeSceneNode::setSize() +{ + if (Mesh) + Mesh->drop(); + Mesh = SceneManager->getGeometryCreator()->createCubeMesh(core::vector3df(Size)); +} + + +//! renders the node. +void CCubeSceneNode::render() +{ + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + + if (Shadow) + Shadow->updateShadowVolumes(); + + // for debug purposes only: + video::SMaterial mat = Mesh->getMeshBuffer(0)->getMaterial(); + + // overwrite half transparency + if (DebugDataVisible & scene::EDS_HALF_TRANSPARENCY) + mat.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR; + driver->setMaterial(mat); + driver->drawMeshBuffer(Mesh->getMeshBuffer(0)); + + // for debug purposes only: + if (DebugDataVisible) + { + video::SMaterial m; + m.Lighting = false; + m.AntiAliasing=0; + driver->setMaterial(m); + + if (DebugDataVisible & scene::EDS_BBOX) + { + driver->draw3DBox(Mesh->getMeshBuffer(0)->getBoundingBox(), video::SColor(255,255,255,255)); + } + if (DebugDataVisible & scene::EDS_BBOX_BUFFERS) + { + driver->draw3DBox(Mesh->getMeshBuffer(0)->getBoundingBox(), + video::SColor(255,190,128,128)); + } + if (DebugDataVisible & scene::EDS_NORMALS) + { + // draw normals + const f32 debugNormalLength = SceneManager->getParameters()->getAttributeAsFloat(DEBUG_NORMAL_LENGTH); + const video::SColor debugNormalColor = SceneManager->getParameters()->getAttributeAsColor(DEBUG_NORMAL_COLOR); + const u32 count = Mesh->getMeshBufferCount(); + + for (u32 i=0; i != count; ++i) + { + driver->drawMeshBufferNormals(Mesh->getMeshBuffer(i), debugNormalLength, debugNormalColor); + } + } + + // show mesh + if (DebugDataVisible & scene::EDS_MESH_WIRE_OVERLAY) + { + m.Wireframe = true; + driver->setMaterial(m); + + driver->drawMeshBuffer(Mesh->getMeshBuffer(0)); + } + } +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CCubeSceneNode::getBoundingBox() const +{ + return Mesh->getMeshBuffer(0)->getBoundingBox(); +} + + +//! Removes a child from this scene node. +//! Implemented here, to be able to remove the shadow properly, if there is one, +//! or to remove attached childs. +bool CCubeSceneNode::removeChild(ISceneNode* child) +{ + if (child && Shadow == child) + { + Shadow->drop(); + Shadow = 0; + } + + return ISceneNode::removeChild(child); +} + + +//! Creates shadow volume scene node as child of this node +//! and returns a pointer to it. +IShadowVolumeSceneNode* CCubeSceneNode::addShadowVolumeSceneNode( + const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity) +{ +#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ + if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER)) + return 0; + + if (!shadowMesh) + shadowMesh = Mesh; // if null is given, use the mesh of node + + if (Shadow) + Shadow->drop(); + + Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity); + return Shadow; +#else + return 0; +#endif +} + + +void CCubeSceneNode::OnRegisterSceneNode() +{ + if (IsVisible) + SceneManager->registerNodeForRendering(this); + ISceneNode::OnRegisterSceneNode(); +} + + +//! returns the material based on the zero based index i. +video::SMaterial& CCubeSceneNode::getMaterial(u32 i) +{ + return Mesh->getMeshBuffer(0)->getMaterial(); +} + + +//! returns amount of materials used by this scene node. +u32 CCubeSceneNode::getMaterialCount() const +{ + return 1; +} + + +//! Writes attributes of the scene node. +void CCubeSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + ISceneNode::serializeAttributes(out, options); + + out->addFloat("Size", Size); +} + + +//! Reads attributes of the scene node. +void CCubeSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + f32 newSize = in->getAttributeAsFloat("Size"); + newSize = core::max_(newSize, 0.0001f); + if (newSize != Size) + { + Size = newSize; + setSize(); + } + + ISceneNode::deserializeAttributes(in, options); +} + + +//! Creates a clone of this scene node and its children. +ISceneNode* CCubeSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager) +{ + if (!newParent) + newParent = Parent; + if (!newManager) + newManager = SceneManager; + + CCubeSceneNode* nb = new CCubeSceneNode(Size, newParent, + newManager, ID, RelativeTranslation); + + nb->cloneMembers(this, newManager); + nb->getMaterial(0) = getMaterial(0); + nb->Shadow = Shadow; + if ( nb->Shadow ) + nb->Shadow->grab(); + + if ( newParent ) + nb->drop(); + return nb; +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_CUBE_SCENENODE_ diff --git a/source/Irrlicht/CCubeSceneNode.h b/source/Irrlicht/CCubeSceneNode.h new file mode 100644 index 00000000..f8ad068f --- /dev/null +++ b/source/Irrlicht/CCubeSceneNode.h @@ -0,0 +1,93 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_CUBE_SCENE_NODE_H_INCLUDED__ +#define __C_CUBE_SCENE_NODE_H_INCLUDED__ + +#include "IMeshSceneNode.h" +#include "SMesh.h" + +namespace irr +{ +namespace scene +{ + class CCubeSceneNode : public IMeshSceneNode + { + public: + + //! constructor + CCubeSceneNode(f32 size, ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)); + + virtual ~CCubeSceneNode(); + + virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; + + //! renders the node. + virtual void render() _IRR_OVERRIDE_; + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + //! returns the material based on the zero based index i. To get the amount + //! of materials used by this scene node, use getMaterialCount(). + //! This function is needed for inserting the node into the scene hierarchy on a + //! optimal position for minimizing renderstate changes, but can also be used + //! to directly modify the material of a scene node. + virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_; + + //! returns amount of materials used by this scene node. + virtual u32 getMaterialCount() const _IRR_OVERRIDE_; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_CUBE; } + + //! Creates shadow volume scene node as child of this node + //! and returns a pointer to it. + virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh, + s32 id, bool zfailmethod=true, f32 infinity=10000.0f) _IRR_OVERRIDE_; + + //! Writes attributes of the scene node. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! Creates a clone of this scene node and its children. + virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + //! Sets a new mesh to display + virtual void setMesh(IMesh* mesh) _IRR_OVERRIDE_ {} + + //! Returns the current mesh + virtual IMesh* getMesh(void) _IRR_OVERRIDE_ { return Mesh; } + + //! Sets if the scene node should not copy the materials of the mesh but use them in a read only style. + /* In this way it is possible to change the materials a mesh causing all mesh scene nodes + referencing this mesh to change too. */ + virtual void setReadOnlyMaterials(bool readonly) _IRR_OVERRIDE_ {} + + //! Returns if the scene node should not copy the materials of the mesh but use them in a read only style + virtual bool isReadOnlyMaterials() const _IRR_OVERRIDE_ { return false; } + + //! Removes a child from this scene node. + //! Implemented here, to be able to remove the shadow properly, if there is one, + //! or to remove attached child. + virtual bool removeChild(ISceneNode* child) _IRR_OVERRIDE_; + + private: + void setSize(); + + IMesh* Mesh; + IShadowVolumeSceneNode* Shadow; + f32 Size; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CD3D9Driver.cpp b/source/Irrlicht/CD3D9Driver.cpp new file mode 100644 index 00000000..7073b26d --- /dev/null +++ b/source/Irrlicht/CD3D9Driver.cpp @@ -0,0 +1,3793 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#define _IRR_DONT_DO_MEMORY_DEBUGGING_HERE +#include "CD3D9Driver.h" + +#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ + +#include "os.h" +#include "S3DVertex.h" +#include "CD3D9Texture.h" +#include "CD3D9RenderTarget.h" +#include "CD3D9MaterialRenderer.h" +#include "CD3D9ShaderMaterialRenderer.h" +#include "CD3D9NormalMapRenderer.h" +#include "CD3D9ParallaxMapRenderer.h" +#include "CD3D9HLSLMaterialRenderer.h" +#include "SIrrCreationParameters.h" + +namespace irr +{ +namespace video +{ + +namespace +{ + inline DWORD F2DW( FLOAT f ) { return *((DWORD*)&f); } +} + +//! constructor +CD3D9Driver::CD3D9Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io) + : CNullDriver(io, params.WindowSize), BridgeCalls(0), CurrentRenderMode(ERM_NONE), + ResetRenderStates(true), Transformation3DChanged(false), + D3DLibrary(0), pID3D(0), pID3DDevice(0), BackBufferSurface(0), + DepthStencilSurface(0), WindowId(0), SceneSourceRect(0), + LastVertexType((video::E_VERTEX_TYPE)-1), VendorID(0), + MaxTextureUnits(0), MaxFixedPipelineTextureUnits(0), MaxUserClipPlanes(0), + MaxLightDistance(0.f), LastSetLight(-1), + ColorFormat(ECF_A8R8G8B8), DeviceLost(false), + DriverWasReset(true), OcclusionQuerySupport(false), + AlphaToCoverageSupport(false), Params(params) +{ + #ifdef _DEBUG + setDebugName("CD3D9Driver"); + #endif + + printVersion(); + + for (u32 i=0; iRelease(); + + delete BridgeCalls; + + // drop d3d9 + + if (pID3DDevice) + pID3DDevice->Release(); + + if (pID3D) + pID3D->Release(); +} + + +void CD3D9Driver::createMaterialRenderers() +{ + // create D3D9 material renderers + + addAndDropMaterialRenderer(new CD3D9MaterialRenderer_SOLID(pID3DDevice, this)); + addAndDropMaterialRenderer(new CD3D9MaterialRenderer_SOLID_2_LAYER(pID3DDevice, this)); + + // add the same renderer for all lightmap types + + CD3D9MaterialRenderer_LIGHTMAP* lmr = new CD3D9MaterialRenderer_LIGHTMAP(pID3DDevice, this); + addMaterialRenderer(lmr); // for EMT_LIGHTMAP: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_ADD: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M2: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M4: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M2: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M4: + lmr->drop(); + + // add remaining fixed function pipeline material renderers + + addAndDropMaterialRenderer(new CD3D9MaterialRenderer_DETAIL_MAP(pID3DDevice, this)); + addAndDropMaterialRenderer(new CD3D9MaterialRenderer_SPHERE_MAP(pID3DDevice, this)); + addAndDropMaterialRenderer(new CD3D9MaterialRenderer_REFLECTION_2_LAYER(pID3DDevice, this)); + addAndDropMaterialRenderer(new CD3D9MaterialRenderer_TRANSPARENT_ADD_COLOR(pID3DDevice, this)); + addAndDropMaterialRenderer(new CD3D9MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL(pID3DDevice, this)); + addAndDropMaterialRenderer(new CD3D9MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF(pID3DDevice, this)); + addAndDropMaterialRenderer(new CD3D9MaterialRenderer_TRANSPARENT_VERTEX_ALPHA(pID3DDevice, this)); + addAndDropMaterialRenderer(new CD3D9MaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER(pID3DDevice, this)); + + // add normal map renderers + + s32 tmp = 0; + video::IMaterialRenderer* renderer = 0; + + renderer = new CD3D9NormalMapRenderer(pID3DDevice, this, tmp, + MaterialRenderers[EMT_SOLID].Renderer); + renderer->drop(); + + renderer = new CD3D9NormalMapRenderer(pID3DDevice, this, tmp, + MaterialRenderers[EMT_TRANSPARENT_ADD_COLOR].Renderer); + renderer->drop(); + + renderer = new CD3D9NormalMapRenderer(pID3DDevice, this, tmp, + MaterialRenderers[EMT_TRANSPARENT_VERTEX_ALPHA].Renderer); + renderer->drop(); + + // add parallax map renderers + + renderer = new CD3D9ParallaxMapRenderer(pID3DDevice, this, tmp, + MaterialRenderers[EMT_SOLID].Renderer); + renderer->drop(); + + renderer = new CD3D9ParallaxMapRenderer(pID3DDevice, this, tmp, + MaterialRenderers[EMT_TRANSPARENT_ADD_COLOR].Renderer); + renderer->drop(); + + renderer = new CD3D9ParallaxMapRenderer(pID3DDevice, this, tmp, + 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(HWND hwnd, bool pureSoftware) +{ + if (!pID3D) + { + D3DLibrary = LoadLibrary( __TEXT("d3d9.dll") ); + + if (!D3DLibrary) + { + os::Printer::log("Error, could not load d3d9.dll.", ELL_ERROR); + return false; + } + + typedef IDirect3D9 * (__stdcall *D3DCREATETYPE)(UINT); + D3DCREATETYPE d3dCreate = (D3DCREATETYPE) GetProcAddress(D3DLibrary, "Direct3DCreate9"); + + if (!d3dCreate) + { + os::Printer::log("Error, could not get proc adress of Direct3DCreate9.", ELL_ERROR); + return false; + } + + //just like pID3D = Direct3DCreate9(D3D_SDK_VERSION); + pID3D = (*d3dCreate)(D3D_SDK_VERSION); + + if (!pID3D) + { + os::Printer::log("Error initializing D3D.", ELL_ERROR); + return false; + } + } + + // print device information + D3DADAPTER_IDENTIFIER9 dai; + if (!FAILED(pID3D->GetAdapterIdentifier(Params.DisplayAdapter, 0, &dai))) + { + char tmp[512]; + + s32 Product = HIWORD(dai.DriverVersion.HighPart); + s32 Version = LOWORD(dai.DriverVersion.HighPart); + s32 SubVersion = HIWORD(dai.DriverVersion.LowPart); + s32 Build = LOWORD(dai.DriverVersion.LowPart); + + sprintf(tmp, "%s %s %d.%d.%d.%d", dai.Description, dai.Driver, Product, Version, + SubVersion, Build); + 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; + } + } + + D3DDISPLAYMODE d3ddm; + if (FAILED(pID3D->GetAdapterDisplayMode(Params.DisplayAdapter, &d3ddm))) + { + os::Printer::log("Error: Could not get Adapter Display mode.", ELL_ERROR); + return false; + } + + ZeroMemory(&present, sizeof(present)); + + present.BackBufferCount = 1; + present.EnableAutoDepthStencil = TRUE; + if (Params.Vsync) + present.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + else + present.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + + if (Params.Fullscreen) + { + present.BackBufferWidth = Params.WindowSize.Width; + present.BackBufferHeight = Params.WindowSize.Height; + // request 32bit mode if user specified 32 bit, added by Thomas Stuefe + if (Params.Bits == 32) + present.BackBufferFormat = D3DFMT_X8R8G8B8; + else + present.BackBufferFormat = D3DFMT_R5G6B5; + present.SwapEffect = D3DSWAPEFFECT_FLIP; + present.Windowed = FALSE; + present.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; + } + else + { + present.BackBufferFormat = d3ddm.Format; + present.SwapEffect = D3DSWAPEFFECT_DISCARD; + present.Windowed = TRUE; + } + + UINT adapter = Params.DisplayAdapter; + D3DDEVTYPE devtype = D3DDEVTYPE_HAL; + #ifndef _IRR_D3D_NO_SHADER_DEBUGGING + devtype = D3DDEVTYPE_REF; + #elif defined(_IRR_USE_NVIDIA_PERFHUD_) + for (UINT adapter_i = 0; adapter_i < pID3D->GetAdapterCount(); ++adapter_i) + { + D3DADAPTER_IDENTIFIER9 identifier; + pID3D->GetAdapterIdentifier(adapter_i,0,&identifier); + if (strstr(identifier.Description,"PerfHUD") != 0) + { + adapter = adapter_i; + devtype = D3DDEVTYPE_REF; + break; + } + } + #endif + + // enable anti alias if possible and desired + if (Params.AntiAlias > 0) + { + if (Params.AntiAlias > 32) + Params.AntiAlias = 32; + + DWORD qualityLevels = 0; + + while(Params.AntiAlias > 0) + { + if(SUCCEEDED(pID3D->CheckDeviceMultiSampleType(adapter, + devtype, present.BackBufferFormat, !Params.Fullscreen, + (D3DMULTISAMPLE_TYPE)Params.AntiAlias, &qualityLevels))) + { + present.MultiSampleType = (D3DMULTISAMPLE_TYPE)Params.AntiAlias; + present.MultiSampleQuality = qualityLevels-1; + present.SwapEffect = D3DSWAPEFFECT_DISCARD; + break; + } + --Params.AntiAlias; + } + + if (Params.AntiAlias==0) + { + os::Printer::log("Anti aliasing disabled because hardware/driver lacks necessary caps.", ELL_WARNING); + } + } + + // check stencil buffer compatibility + if (Params.Stencilbuffer) + { + present.AutoDepthStencilFormat = D3DFMT_D24S8; + if(FAILED(pID3D->CheckDeviceFormat(adapter, devtype, + present.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL, + D3DRTYPE_SURFACE, present.AutoDepthStencilFormat))) + { + present.AutoDepthStencilFormat = D3DFMT_D24X4S4; + if(FAILED(pID3D->CheckDeviceFormat(adapter, devtype, + present.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL, + D3DRTYPE_SURFACE, present.AutoDepthStencilFormat))) + { + present.AutoDepthStencilFormat = D3DFMT_D15S1; + if(FAILED(pID3D->CheckDeviceFormat(adapter, devtype, + present.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL, + D3DRTYPE_SURFACE, present.AutoDepthStencilFormat))) + { + os::Printer::log("Device does not support stencilbuffer, disabling stencil buffer.", ELL_WARNING); + Params.Stencilbuffer = false; + } + } + } + else + if(FAILED(pID3D->CheckDepthStencilMatch(adapter, devtype, + present.BackBufferFormat, present.BackBufferFormat, present.AutoDepthStencilFormat))) + { + os::Printer::log("Depth-stencil format is not compatible with display format, disabling stencil buffer.", ELL_WARNING); + Params.Stencilbuffer = false; + } + } + // do not use else here to cope with flag change in previous block + if (!Params.Stencilbuffer) + { + present.AutoDepthStencilFormat = D3DFMT_D32; + if(FAILED(pID3D->CheckDeviceFormat(adapter, devtype, + present.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL, + D3DRTYPE_SURFACE, present.AutoDepthStencilFormat))) + { + present.AutoDepthStencilFormat = D3DFMT_D24X8; + if(FAILED(pID3D->CheckDeviceFormat(adapter, devtype, + present.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL, + D3DRTYPE_SURFACE, present.AutoDepthStencilFormat))) + { + present.AutoDepthStencilFormat = D3DFMT_D16; + if(FAILED(pID3D->CheckDeviceFormat(adapter, devtype, + present.BackBufferFormat, D3DUSAGE_DEPTHSTENCIL, + D3DRTYPE_SURFACE, present.AutoDepthStencilFormat))) + { + os::Printer::log("Device does not support required depth buffer.", ELL_WARNING); + return false; + } + } + } + } + + // create device + + DWORD fpuPrecision = Params.HighPrecisionFPU ? D3DCREATE_FPU_PRESERVE : 0; + DWORD multithreaded = Params.DriverMultithreaded ? D3DCREATE_MULTITHREADED : 0; + if (pureSoftware) + { + if (FAILED(pID3D->CreateDevice(Params.DisplayAdapter, D3DDEVTYPE_REF, hwnd, + fpuPrecision | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present, &pID3DDevice))) + os::Printer::log("Was not able to create Direct3D9 software device.", ELL_ERROR); + } + else + { + HRESULT hr = pID3D->CreateDevice(adapter, devtype, hwnd, + fpuPrecision | multithreaded | D3DCREATE_HARDWARE_VERTEXPROCESSING, &present, &pID3DDevice); + + if(FAILED(hr)) + hr = pID3D->CreateDevice(adapter, devtype, hwnd, + fpuPrecision | multithreaded | D3DCREATE_MIXED_VERTEXPROCESSING , &present, &pID3DDevice); + + if(FAILED(hr)) + hr = pID3D->CreateDevice(adapter, devtype, hwnd, + fpuPrecision | multithreaded | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present, &pID3DDevice); + + if (FAILED(hr)) + os::Printer::log("Was not able to create Direct3D9 device.", ELL_ERROR); + } + + if (!pID3DDevice) + { + os::Printer::log("Was not able to create DIRECT3D9 device.", ELL_ERROR); + return false; + } + + // get caps + pID3DDevice->GetDeviceCaps(&Caps); + + os::Printer::log("Currently available Video Memory (kB)", core::stringc(pID3DDevice->GetAvailableTextureMem()/1024).c_str()); + + // disable stencilbuffer if necessary + if (Params.Stencilbuffer && + (!(Caps.StencilCaps & D3DSTENCILCAPS_DECRSAT) || + !(Caps.StencilCaps & D3DSTENCILCAPS_INCRSAT) || + !(Caps.StencilCaps & D3DSTENCILCAPS_KEEP))) + { + os::Printer::log("Device not able to use stencil buffer, disabling stencil buffer.", ELL_WARNING); + Params.Stencilbuffer = false; + } + + if (!BridgeCalls) + BridgeCalls = new CD3D9CallBridge(pID3DDevice, this); + + // set default vertex shader + setVertexShader(EVT_STANDARD); + + // set fog mode + setFog(FogColor, FogType, FogStart, FogEnd, FogDensity, PixelFog, RangeFog); + + // set exposed data + ExposedData.D3D9.D3D9 = pID3D; + ExposedData.D3D9.D3DDev9 = pID3DDevice; + ExposedData.D3D9.HWnd = hwnd; + + ResetRenderStates = true; + + // create materials + createMaterialRenderers(); + + MaxFixedPipelineTextureUnits = (u32)Caps.MaxSimultaneousTextures; + DriverAttributes->setAttribute("MaxSupportedTextures", (s32)MaxFixedPipelineTextureUnits); + + u32 maxTextureSamplers = (Caps.PixelShaderVersion >= D3DPS_VERSION(2, 0)) ? 16 : (Caps.PixelShaderVersion >= D3DPS_VERSION(1, 4)) ? + 6 : (Caps.PixelShaderVersion >= D3DPS_VERSION(1, 0)) ? 4 : 0; + + MaxTextureUnits = core::max_(MaxFixedPipelineTextureUnits, maxTextureSamplers); + MaxTextureUnits = core::min_(MaxTextureUnits, MATERIAL_MAX_TEXTURES); + MaxTextureUnits = core::min_(MaxTextureUnits, MATERIAL_MAX_TEXTURES_USED); + + MaxUserClipPlanes = (u32)Caps.MaxUserClipPlanes; + OcclusionQuerySupport=(pID3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, NULL) == S_OK); + + if (VendorID==0x10DE)//NVidia + AlphaToCoverageSupport = (pID3D->CheckDeviceFormat(adapter, 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(adapter, D3DDEVTYPE_HAL, + D3DFMT_X8R8G8B8, 0,D3DRTYPE_SURFACE, + (D3DFORMAT)MAKEFOURCC('A','2','M','1')) == S_OK); +#endif + + DriverAttributes->setAttribute("MaxTextures", (s32)MaxTextureUnits); + DriverAttributes->setAttribute("MaxLights", (s32)Caps.MaxActiveLights); + DriverAttributes->setAttribute("MaxAnisotropy", (s32)Caps.MaxAnisotropy); + DriverAttributes->setAttribute("MaxUserClipPlanes", (s32)Caps.MaxUserClipPlanes); + DriverAttributes->setAttribute("MaxMultipleRenderTargets", (s32)Caps.NumSimultaneousRTs); + DriverAttributes->setAttribute("MaxIndices", (s32)Caps.MaxVertexIndex); + DriverAttributes->setAttribute("MaxTextureSize", (s32)core::min_(Caps.MaxTextureHeight,Caps.MaxTextureWidth)); + DriverAttributes->setAttribute("MaxTextureLODBias", 16); + DriverAttributes->setAttribute("Version", 901); + DriverAttributes->setAttribute("ShaderLanguageVersion", (s32)(((0x00ff00 & Caps.VertexShaderVersion)>>8)*100 + (Caps.VertexShaderVersion&0xff))); + DriverAttributes->setAttribute("AntiAlias", Params.AntiAlias); + + // set the renderstates + setRenderStates3DMode(); + + // store the screen's depth buffer descriptor + if (!SUCCEEDED(pID3DDevice->GetDepthStencilSurface(&DepthStencilSurface))) + { + os::Printer::log("Was not able to get main depth buffer.", ELL_ERROR); + return false; + } + + D3DColorFormat = D3DFMT_A8R8G8B8; + IDirect3DSurface9* bb = 0; + if (SUCCEEDED(pID3DDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &bb))) + { + D3DSURFACE_DESC desc; + bb->GetDesc(&desc); + D3DColorFormat = desc.Format; + + if (D3DColorFormat == D3DFMT_X8R8G8B8) + D3DColorFormat = D3DFMT_A8R8G8B8; + + bb->Release(); + } + ColorFormat = getColorFormatFromD3DFormat(D3DColorFormat); + + ActiveRenderTarget.set_used((u32)Caps.NumSimultaneousRTs); + + for (u32 i = 0; i < ActiveRenderTarget.size(); ++i) + ActiveRenderTarget[i] = false; + + // so far so good. + return true; +} + +bool CD3D9Driver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil, const SExposedVideoData& videoData, core::rect* sourceRect) +{ + CNullDriver::beginScene(clearFlag, clearColor, clearDepth, clearStencil, videoData, sourceRect); + WindowId = (HWND)videoData.D3D9.HWnd; + SceneSourceRect = sourceRect; + + if (!pID3DDevice) + return false; + + HRESULT hr; + if (DeviceLost) + { + if ( !retrieveDevice(1) ) + return false; + } + + clearBuffers(clearFlag, clearColor, clearDepth, clearStencil); + + hr = pID3DDevice->BeginScene(); + if (FAILED(hr)) + { + os::Printer::log("DIRECT3D9 begin scene failed.", ELL_WARNING); + return false; + } + + return true; +} + +bool CD3D9Driver::endScene() +{ + CNullDriver::endScene(); + DriverWasReset=false; + + HRESULT hr = pID3DDevice->EndScene(); + if (FAILED(hr)) + { + os::Printer::log("DIRECT3D9 end scene failed.", ELL_WARNING); + return false; + } + + RECT* srcRct = 0; + RECT sourceRectData; + if ( SceneSourceRect ) + { + srcRct = &sourceRectData; + sourceRectData.left = SceneSourceRect->UpperLeftCorner.X; + sourceRectData.top = SceneSourceRect->UpperLeftCorner.Y; + sourceRectData.right = SceneSourceRect->LowerRightCorner.X; + sourceRectData.bottom = SceneSourceRect->LowerRightCorner.Y; + } + + IDirect3DSwapChain9* swChain; + hr = pID3DDevice->GetSwapChain(0, &swChain); + DWORD flags = (Params.HandleSRGB && (Caps.Caps3&D3DCAPS3_LINEAR_TO_SRGB_PRESENTATION))?D3DPRESENT_LINEAR_CONTENT:0; + hr = swChain->Present(srcRct, NULL, WindowId, NULL, flags); + swChain->Release(); + + if (SUCCEEDED(hr)) + return true; + + if (hr == D3DERR_DEVICELOST) + { + DeviceLost = true; + os::Printer::log("Present failed", "DIRECT3D9 device lost.", ELL_WARNING); + } +#ifdef D3DERR_DEVICEREMOVED + else if (hr == D3DERR_DEVICEREMOVED) + { + os::Printer::log("Present failed", "Device removed.", ELL_WARNING); + } +#endif + else if (hr == D3DERR_INVALIDCALL) + { + os::Printer::log("Present failed", "Invalid Call", ELL_WARNING); + } + else + os::Printer::log("DIRECT3D9 present failed.", ELL_WARNING); + return false; +} + + +//! queries the features of the driver, returns true if feature is available +bool CD3D9Driver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const +{ + if (!FeatureEnabled[feature]) + return false; + + switch (feature) + { + case EVDF_MULTITEXTURE: + case EVDF_BILINEAR_FILTER: + return true; + case EVDF_RENDER_TO_TARGET: + return Caps.NumSimultaneousRTs > 0; + case EVDF_HARDWARE_TL: + return (Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0; + case EVDF_MIP_MAP: + return (Caps.TextureCaps & D3DPTEXTURECAPS_MIPMAP) != 0; + case EVDF_MIP_MAP_AUTO_UPDATE: + return (Caps.Caps2 & D3DCAPS2_CANAUTOGENMIPMAP) != 0; + case EVDF_STENCIL_BUFFER: + return Params.Stencilbuffer && Caps.StencilCaps; + case EVDF_VERTEX_SHADER_1_1: + return Caps.VertexShaderVersion >= D3DVS_VERSION(1,1); + case EVDF_VERTEX_SHADER_2_0: + return Caps.VertexShaderVersion >= D3DVS_VERSION(2,0); + case EVDF_VERTEX_SHADER_3_0: + return Caps.VertexShaderVersion >= D3DVS_VERSION(3,0); + case EVDF_PIXEL_SHADER_1_1: + return Caps.PixelShaderVersion >= D3DPS_VERSION(1,1); + case EVDF_PIXEL_SHADER_1_2: + return Caps.PixelShaderVersion >= D3DPS_VERSION(1,2); + case EVDF_PIXEL_SHADER_1_3: + return Caps.PixelShaderVersion >= D3DPS_VERSION(1,3); + case EVDF_PIXEL_SHADER_1_4: + return Caps.PixelShaderVersion >= D3DPS_VERSION(1,4); + case EVDF_PIXEL_SHADER_2_0: + return Caps.PixelShaderVersion >= D3DPS_VERSION(2,0); + case EVDF_PIXEL_SHADER_3_0: + return Caps.PixelShaderVersion >= D3DPS_VERSION(3,0); + case EVDF_HLSL: + return Caps.VertexShaderVersion >= D3DVS_VERSION(1,1); + case EVDF_TEXTURE_NSQUARE: + 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; + case EVDF_MULTIPLE_RENDER_TARGETS: + return Caps.NumSimultaneousRTs > 1; + case EVDF_MRT_COLOR_MASK: + return (Caps.PrimitiveMiscCaps & D3DPMISCCAPS_INDEPENDENTWRITEMASKS) != 0; + case EVDF_MRT_BLEND: + return (Caps.PrimitiveMiscCaps & D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING) != 0; + case EVDF_OCCLUSION_QUERY: + return OcclusionQuerySupport; + case EVDF_POLYGON_OFFSET: + return (Caps.RasterCaps & (D3DPRASTERCAPS_DEPTHBIAS|D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS)) != 0; + case EVDF_BLEND_OPERATIONS: + return true; + case EVDF_BLEND_SEPARATE: + return (Caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) != 0; + case EVDF_TEXTURE_MATRIX: + return true; + case EVDF_TEXTURE_COMPRESSED_DXT: + return true; + case EVDF_TEXTURE_CUBEMAP: + return true; + default: + return false; + }; +} + + +//! sets transformation +void CD3D9Driver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) +{ + Transformation3DChanged = true; + + switch(state) + { + case ETS_VIEW: + pID3DDevice->SetTransform(D3DTS_VIEW, (D3DMATRIX*)((void*)mat.pointer())); + break; + case ETS_WORLD: + pID3DDevice->SetTransform(D3DTS_WORLD, (D3DMATRIX*)((void*)mat.pointer())); + break; + case ETS_PROJECTION: + pID3DDevice->SetTransform( D3DTS_PROJECTION, (D3DMATRIX*)((void*)mat.pointer())); + break; + case ETS_COUNT: + return; + default: + { + const s32 stage = state - ETS_TEXTURE_0; + + if ( stage < static_cast(MaxTextureUnits) + && stage < static_cast(MaxFixedPipelineTextureUnits)) // texture transforms for shader pipeline have to be passed by user + { + if (mat.isIdentity()) + pID3DDevice->SetTextureStageState(stage, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); + else + { + pID3DDevice->SetTextureStageState(stage, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2); + pID3DDevice->SetTransform((D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + stage), (D3DMATRIX*)((void*)mat.pointer())); + } + } + } + break; + } + + Matrices[state] = mat; +} + + +//! sets the current Texture +bool CD3D9Driver::setActiveTexture(u32 stage, const video::ITexture* texture) +{ + if (CurrentTexture[stage] == texture) + return true; + + if (texture && texture->getDriverType() != EDT_DIRECT3D9) + { + os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR); + return false; + } + + CurrentTexture[stage] = texture; + + if (!texture) + { + pID3DDevice->SetTexture(stage, 0); + pID3DDevice->SetTextureStageState( stage, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE ); + } + else + { + pID3DDevice->SetTexture(stage, ((const CD3D9Texture*)texture)->getDX9BaseTexture()); + + if (stage <= 4) + pID3DDevice->SetTexture(D3DVERTEXTEXTURESAMPLER0 + stage, ((const CD3D9Texture*)texture)->getDX9BaseTexture()); + } + return true; +} + + +//! sets a material +void CD3D9Driver::setMaterial(const SMaterial& material) +{ + Material = material; + OverrideMaterial.apply(Material); + + for (u32 i=0; i imageArray(1); + imageArray.push_back(image); + + CD3D9Texture* texture = new CD3D9Texture(name, imageArray, ETT_2D, this); + if ( !texture->getDX9Texture() ) + { + texture->drop(); + return 0; + } + + return texture; +} + +ITexture* CD3D9Driver::createDeviceDependentTextureCubemap(const io::path& name, const core::array& image) +{ + CD3D9Texture* texture = new CD3D9Texture(name, image, ETT_CUBEMAP, this); + + if ( !texture->getDX9CubeTexture() ) + { + texture->drop(); + return 0; + } + + return texture; +} + +bool CD3D9Driver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil) +{ + if (target && target->getDriverType() != EDT_DIRECT3D9) + { + os::Printer::log("Fatal Error: Tried to set a render target not owned by this driver.", ELL_ERROR); + return false; + } + + if (target) + { + // Store main render target. + + if (!BackBufferSurface) + { + if (FAILED(pID3DDevice->GetRenderTarget(0, &BackBufferSurface))) + { + os::Printer::log("Could not get main render target.", ELL_ERROR); + return false; + } + } + + // Set new color textures. + + CD3D9RenderTarget* renderTarget = static_cast(target); + + const u32 surfaceSize = core::min_(renderTarget->getSurfaceCount(), ActiveRenderTarget.size()); + + for (u32 i = 0; i < surfaceSize; ++i) + { + ActiveRenderTarget[i] = true; + + if (FAILED(pID3DDevice->SetRenderTarget(i, renderTarget->getSurface(i)))) + { + ActiveRenderTarget[i] = false; + + os::Printer::log("Error: Could not set render target.", ELL_ERROR); + } + } + + // Reset other render target channels. + + for (u32 i = surfaceSize; i < ActiveRenderTarget.size(); ++i) + { + if (ActiveRenderTarget[i]) + { + pID3DDevice->SetRenderTarget(i, 0); + ActiveRenderTarget[i] = false; + } + } + + // Set depth stencil buffer. + + IDirect3DSurface9* depthStencilSurface = renderTarget->getDepthStencilSurface(); + + if (depthStencilSurface && FAILED(pID3DDevice->SetDepthStencilSurface(depthStencilSurface))) + { + os::Printer::log("Error: Could not set depth-stencil buffer.", ELL_ERROR); + } + + // Set other settings. + + CurrentRenderTargetSize = renderTarget->getSize(); + Transformation3DChanged = true; + } + else if (CurrentRenderTarget != target) + { + // Set main render target. + + if (BackBufferSurface) + { + ActiveRenderTarget[0] = true; + + if (FAILED(pID3DDevice->SetRenderTarget(0, BackBufferSurface))) + { + os::Printer::log("Error: Could not set main render target.", ELL_ERROR); + ActiveRenderTarget[0] = false; + + return false; + } + + BackBufferSurface->Release(); + BackBufferSurface = 0; + } + + // Reset other render target channels. + + for (u32 i = 1; i < ActiveRenderTarget.size(); ++i) + { + if (ActiveRenderTarget[i]) + { + pID3DDevice->SetRenderTarget(i, 0); + ActiveRenderTarget[i] = false; + } + } + + // Set main depth-stencil stencil buffer. + + if (FAILED(pID3DDevice->SetDepthStencilSurface(DepthStencilSurface))) + { + os::Printer::log("Error: Could not set main depth-stencil buffer.", ELL_ERROR); + } + + // Set other settings. + + CurrentRenderTargetSize = core::dimension2d(0, 0); + Transformation3DChanged = true; + } + + CurrentRenderTarget = target; + + clearBuffers(clearFlag, clearColor, clearDepth, clearStencil); + + return true; +} + + +//! sets a viewport +void CD3D9Driver::setViewPort(const core::rect& area) +{ + core::rect vp = area; + core::rect rendert(0,0, getCurrentRenderTargetSize().Width, getCurrentRenderTargetSize().Height); + vp.clipAgainst(rendert); + if (vp.getHeight()>0 && vp.getWidth()>0) + { + D3DVIEWPORT9 viewPort; + viewPort.X = vp.UpperLeftCorner.X; + viewPort.Y = vp.UpperLeftCorner.Y; + viewPort.Width = vp.getWidth(); + viewPort.Height = vp.getHeight(); + viewPort.MinZ = 0.0f; + viewPort.MaxZ = 1.0f; + + HRESULT hr = pID3DDevice->SetViewport(&viewPort); + if (FAILED(hr)) + os::Printer::log("Failed setting the viewport.", ELL_WARNING); + else + ViewPort = vp; + } +} + + +//! gets the area of the current viewport +const core::rect& CD3D9Driver::getViewPort() const +{ + return ViewPort; +} + + +bool CD3D9Driver::updateVertexHardwareBuffer(SHWBufferLink_d3d9 *hwBuffer) +{ + if (!hwBuffer) + return false; + + const scene::IMeshBuffer* mb = hwBuffer->MeshBuffer; + const void* vertices=mb->getVertices(); + const u32 vertexCount=mb->getVertexCount(); + const E_VERTEX_TYPE vType=mb->getVertexType(); + const u32 vertexSize = getVertexPitchFromType(vType); + const u32 bufSize = vertexSize * vertexCount; + + if (!hwBuffer->vertexBuffer || (bufSize > hwBuffer->vertexBufferSize)) + { + if (hwBuffer->vertexBuffer) + { + hwBuffer->vertexBuffer->Release(); + hwBuffer->vertexBuffer=0; + } + + DWORD FVF; + // Get the vertex sizes and cvf + switch (vType) + { + case EVT_STANDARD: + FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1; + break; + case EVT_2TCOORDS: + FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX2; + break; + case EVT_TANGENTS: + FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX3; + break; + default: + return false; + } + + DWORD flags = D3DUSAGE_WRITEONLY; // SIO2: Default to D3DUSAGE_WRITEONLY + if (hwBuffer->Mapped_Vertex != scene::EHM_STATIC) + flags |= D3DUSAGE_DYNAMIC; + + if (FAILED(pID3DDevice->CreateVertexBuffer(bufSize, flags, FVF, D3DPOOL_DEFAULT, &hwBuffer->vertexBuffer, NULL))) + return false; + hwBuffer->vertexBufferSize = bufSize; + + flags = 0; // SIO2: Reset flags before Lock + if (hwBuffer->Mapped_Vertex != scene::EHM_STATIC) + flags = D3DLOCK_DISCARD; + + void* lockedBuffer = 0; + hwBuffer->vertexBuffer->Lock(0, bufSize, (void**)&lockedBuffer, flags); + memcpy(lockedBuffer, vertices, bufSize); + hwBuffer->vertexBuffer->Unlock(); + } + else + { + void* lockedBuffer = 0; + hwBuffer->vertexBuffer->Lock(0, bufSize, (void**)&lockedBuffer, D3DLOCK_DISCARD); + memcpy(lockedBuffer, vertices, bufSize); + hwBuffer->vertexBuffer->Unlock(); + } + + return true; +} + + +bool CD3D9Driver::updateIndexHardwareBuffer(SHWBufferLink_d3d9 *hwBuffer) +{ + if (!hwBuffer) + return false; + + const scene::IMeshBuffer* mb = hwBuffer->MeshBuffer; + const u16* indices=mb->getIndices(); + const u32 indexCount=mb->getIndexCount(); + u32 indexSize = 2; + D3DFORMAT indexType=D3DFMT_UNKNOWN; + switch (mb->getIndexType()) + { + case EIT_16BIT: + { + indexType=D3DFMT_INDEX16; + indexSize = 2; + break; + } + case EIT_32BIT: + { + indexType=D3DFMT_INDEX32; + indexSize = 4; + break; + } + } + + const u32 bufSize = indexSize * indexCount; + if (!hwBuffer->indexBuffer || (bufSize > hwBuffer->indexBufferSize)) + { + if (hwBuffer->indexBuffer) + { + hwBuffer->indexBuffer->Release(); + hwBuffer->indexBuffer=0; + } + + DWORD flags = D3DUSAGE_WRITEONLY; // SIO2: Default to D3DUSAGE_WRITEONLY + if (hwBuffer->Mapped_Index != scene::EHM_STATIC) + flags |= D3DUSAGE_DYNAMIC; // SIO2: Add DYNAMIC flag for dynamic buffer data + + if (FAILED(pID3DDevice->CreateIndexBuffer(bufSize, flags, indexType, D3DPOOL_DEFAULT, &hwBuffer->indexBuffer, NULL))) + return false; + + flags = 0; // SIO2: Reset flags before Lock + if (hwBuffer->Mapped_Index != scene::EHM_STATIC) + flags = D3DLOCK_DISCARD; + + void* lockedBuffer = 0; + if (FAILED(hwBuffer->indexBuffer->Lock( 0, 0, (void**)&lockedBuffer, flags))) + return false; + + memcpy(lockedBuffer, indices, bufSize); + hwBuffer->indexBuffer->Unlock(); + + hwBuffer->indexBufferSize = bufSize; + } + else + { + void* lockedBuffer = 0; + if( SUCCEEDED(hwBuffer->indexBuffer->Lock( 0, 0, (void**)&lockedBuffer, D3DLOCK_DISCARD))) + { + memcpy(lockedBuffer, indices, bufSize); + hwBuffer->indexBuffer->Unlock(); + } + } + + return true; +} + + +//! updates hardware buffer if needed +bool CD3D9Driver::updateHardwareBuffer(SHWBufferLink *hwBuffer) +{ + if (!hwBuffer) + return false; + + if (hwBuffer->Mapped_Vertex!=scene::EHM_NEVER) + { + if (hwBuffer->ChangedID_Vertex != hwBuffer->MeshBuffer->getChangedID_Vertex() + || !((SHWBufferLink_d3d9*)hwBuffer)->vertexBuffer) + { + hwBuffer->ChangedID_Vertex = hwBuffer->MeshBuffer->getChangedID_Vertex(); + + if (!updateVertexHardwareBuffer((SHWBufferLink_d3d9*)hwBuffer)) + return false; + } + } + + if (hwBuffer->Mapped_Index!=scene::EHM_NEVER) + { + if (hwBuffer->ChangedID_Index != hwBuffer->MeshBuffer->getChangedID_Index() + || !((SHWBufferLink_d3d9*)hwBuffer)->indexBuffer) + { + hwBuffer->ChangedID_Index = hwBuffer->MeshBuffer->getChangedID_Index(); + + if (!updateIndexHardwareBuffer((SHWBufferLink_d3d9*)hwBuffer)) + return false; + } + } + + return true; +} + + +//! Create hardware buffer from meshbuffer +CD3D9Driver::SHWBufferLink *CD3D9Driver::createHardwareBuffer(const scene::IMeshBuffer* mb) +{ + // Looks like d3d does not support only partial buffering, so refuse + // in any case of NEVER + if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER || mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER)) + return 0; + + SHWBufferLink_d3d9 *hwBuffer=new SHWBufferLink_d3d9(mb); + + //add to map + HWBufferMap.insert(hwBuffer->MeshBuffer, hwBuffer); + + hwBuffer->ChangedID_Vertex=hwBuffer->MeshBuffer->getChangedID_Vertex(); + hwBuffer->ChangedID_Index=hwBuffer->MeshBuffer->getChangedID_Index(); + hwBuffer->Mapped_Vertex=mb->getHardwareMappingHint_Vertex(); + hwBuffer->Mapped_Index=mb->getHardwareMappingHint_Index(); + hwBuffer->LastUsed=0; + hwBuffer->vertexBuffer=0; + hwBuffer->indexBuffer=0; + hwBuffer->vertexBufferSize=0; + hwBuffer->indexBufferSize=0; + + if (!updateHardwareBuffer(hwBuffer)) + { + deleteHardwareBuffer(hwBuffer); + return 0; + } + + return hwBuffer; +} + + +void CD3D9Driver::deleteHardwareBuffer(SHWBufferLink *_HWBuffer) +{ + if (!_HWBuffer) + return; + + SHWBufferLink_d3d9 *HWBuffer=(SHWBufferLink_d3d9*)_HWBuffer; + if (HWBuffer->indexBuffer) + { + HWBuffer->indexBuffer->Release(); + HWBuffer->indexBuffer = 0; + } + + if (HWBuffer->vertexBuffer) + { + HWBuffer->vertexBuffer->Release(); + HWBuffer->vertexBuffer = 0; + } + + CNullDriver::deleteHardwareBuffer(_HWBuffer); +} + + +//! Draw hardware buffer +void CD3D9Driver::drawHardwareBuffer(SHWBufferLink *_HWBuffer) +{ + if (!_HWBuffer) + return; + + SHWBufferLink_d3d9 *HWBuffer=(SHWBufferLink_d3d9*)_HWBuffer; + + updateHardwareBuffer(HWBuffer); //check if update is needed + + HWBuffer->LastUsed=0;//reset count + + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + const E_VERTEX_TYPE vType = mb->getVertexType(); + const u32 stride = getVertexPitchFromType(vType); + const void* vPtr = mb->getVertices(); + const void* iPtr = mb->getIndices(); + if (HWBuffer->vertexBuffer) + { + pID3DDevice->SetStreamSource(0, HWBuffer->vertexBuffer, 0, stride); + vPtr=0; + } + if (HWBuffer->indexBuffer) + { + pID3DDevice->SetIndices(HWBuffer->indexBuffer); + iPtr=0; + } + + drawVertexPrimitiveList(vPtr, mb->getVertexCount(), iPtr, mb->getPrimitiveCount(), mb->getVertexType(), mb->getPrimitiveType(), mb->getIndexType()); + + if (HWBuffer->vertexBuffer) + pID3DDevice->SetStreamSource(0, 0, 0, 0); + if (HWBuffer->indexBuffer) + pID3DDevice->SetIndices(0); +} + + +//! Create occlusion query. +/** Use node for identification and mesh for occlusion test. */ +void CD3D9Driver::addOcclusionQuery(scene::ISceneNode* node, + const scene::IMesh* mesh) +{ + if (!queryFeature(EVDF_OCCLUSION_QUERY)) + return; + CNullDriver::addOcclusionQuery(node, mesh); + const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); + if ((index != -1) && (OcclusionQueries[index].PID == 0)) + pID3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, reinterpret_cast(&OcclusionQueries[index].PID)); +} + + +//! Remove occlusion query. +void CD3D9Driver::removeOcclusionQuery(scene::ISceneNode* node) +{ + const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); + if (index != -1) + { + if (OcclusionQueries[index].PID != 0) + reinterpret_cast(OcclusionQueries[index].PID)->Release(); + CNullDriver::removeOcclusionQuery(node); + } +} + + +//! Run occlusion query. Draws mesh stored in query. +/** If the mesh shall not be rendered visible, use +overrideMaterial to disable the color and depth buffer. */ +void CD3D9Driver::runOcclusionQuery(scene::ISceneNode* node, bool visible) +{ + if (!node) + return; + + const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); + if (index != -1) + { + if (OcclusionQueries[index].PID) + reinterpret_cast(OcclusionQueries[index].PID)->Issue(D3DISSUE_BEGIN); + CNullDriver::runOcclusionQuery(node,visible); + if (OcclusionQueries[index].PID) + reinterpret_cast(OcclusionQueries[index].PID)->Issue(D3DISSUE_END); + } +} + + +//! Update occlusion query. Retrieves results from GPU. +/** If the query shall not block, set the flag to false. +Update might not occur in this case, though */ +void CD3D9Driver::updateOcclusionQuery(scene::ISceneNode* node, bool block) +{ + const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); + if (index != -1) + { + // not yet started + if (OcclusionQueries[index].Run==u32(~0)) + return; + bool available = block?true:false; + int tmp=0; + if (!block) + available=(reinterpret_cast(OcclusionQueries[index].PID)->GetData(&tmp, sizeof(DWORD), 0)==S_OK); + else + { + do + { + HRESULT hr = reinterpret_cast(OcclusionQueries[index].PID)->GetData(&tmp, sizeof(DWORD), D3DGETDATA_FLUSH); + available = (hr == S_OK); + if (hr!=S_FALSE) + break; + } while (!available); + } + if (available) + OcclusionQueries[index].Result = tmp; + } +} + + +//! Return query result. +/** Return value is the number of visible pixels/fragments. +The value is a safe approximation, i.e. can be larger than the +actual value of pixels. */ +u32 CD3D9Driver::getOcclusionQueryResult(scene::ISceneNode* node) const +{ + const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); + if (index != -1) + return OcclusionQueries[index].Result; + else + return ~0; +} + + +//! Create render target. +IRenderTarget* CD3D9Driver::addRenderTarget() +{ + CD3D9RenderTarget* renderTarget = new CD3D9RenderTarget(this); + RenderTargets.push_back(renderTarget); + + return renderTarget; +} + + +//! draws a vertex primitive list +void CD3D9Driver::drawVertexPrimitiveList(const void* vertices, + u32 vertexCount, const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, + E_INDEX_TYPE iType) +{ + if (!checkPrimitiveCount(primitiveCount)) + return; + + CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType,iType); + + if (!vertexCount || !primitiveCount) + return; + + draw2D3DVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, + vType, pType, iType, true); +} + + +//! draws a vertex primitive list +void CD3D9Driver::draw2DVertexPrimitiveList(const void* vertices, + u32 vertexCount, const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, + E_INDEX_TYPE iType) +{ + if (!checkPrimitiveCount(primitiveCount)) + return; + + CNullDriver::draw2DVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType,iType); + + if (!vertexCount || !primitiveCount) + return; + + draw2D3DVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, + vType, pType, iType, false); +} + + +void CD3D9Driver::draw2D3DVertexPrimitiveList(const void* vertices, + u32 vertexCount, const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, + E_INDEX_TYPE iType, bool is3D) +{ + setVertexShader(vType); + + const u32 stride = getVertexPitchFromType(vType); + + D3DFORMAT indexType=D3DFMT_UNKNOWN; + switch (iType) + { + case (EIT_16BIT): + { + indexType=D3DFMT_INDEX16; + break; + } + case (EIT_32BIT): + { + indexType=D3DFMT_INDEX32; + break; + } + } + + if (is3D) + { + if (!setRenderStates3DMode()) + return; + } + else + { + if (Material.MaterialType==EMT_ONETEXTURE_BLEND) + { + E_BLEND_FACTOR srcFact; + E_BLEND_FACTOR dstFact; + E_MODULATE_FUNC modulo; + u32 alphaSource; + unpack_textureBlendFunc ( srcFact, dstFact, modulo, alphaSource, Material.MaterialTypeParam); + setRenderStates2DMode(alphaSource&video::EAS_VERTEX_COLOR, (Material.getTexture(0) != 0), (alphaSource&video::EAS_TEXTURE) != 0); + } + else + setRenderStates2DMode(Material.MaterialType==EMT_TRANSPARENT_VERTEX_ALPHA, (Material.getTexture(0) != 0), Material.MaterialType==EMT_TRANSPARENT_ALPHA_CHANNEL); + } + + switch (pType) + { + case scene::EPT_POINT_SPRITES: + case scene::EPT_POINTS: + { + f32 tmp=Material.Thickness/getScreenSize().Height; + if (pType==scene::EPT_POINT_SPRITES) + pID3DDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_POINTSCALEENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_POINTSIZE, F2DW(tmp)); + tmp=1.0f; + pID3DDevice->SetRenderState(D3DRS_POINTSCALE_A, F2DW(tmp)); + pID3DDevice->SetRenderState(D3DRS_POINTSCALE_B, F2DW(tmp)); + pID3DDevice->SetRenderState(D3DRS_POINTSIZE_MIN, F2DW(tmp)); + tmp=0.0f; + pID3DDevice->SetRenderState(D3DRS_POINTSCALE_C, F2DW(tmp)); + + if (!vertices) + { + pID3DDevice->DrawIndexedPrimitive(D3DPT_POINTLIST, 0, 0, vertexCount, 0, primitiveCount); + } + else + { + pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_POINTLIST, 0, vertexCount, + primitiveCount, indexList, indexType, vertices, stride); + } + + pID3DDevice->SetRenderState(D3DRS_POINTSCALEENABLE, FALSE); + if (pType==scene::EPT_POINT_SPRITES) + pID3DDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, FALSE); + } + break; + case scene::EPT_LINE_STRIP: + if(!vertices) + pID3DDevice->DrawIndexedPrimitive(D3DPT_LINESTRIP, 0, 0, vertexCount, 0, primitiveCount); + else + pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_LINESTRIP, 0, vertexCount, + primitiveCount, indexList, indexType, vertices, stride); + break; + case scene::EPT_LINE_LOOP: + if(!vertices) + { + // TODO: Implement proper hardware support for this primitive type. + // (No looping occurs currently because this would require a way to + // draw the hardware buffer with a custom set of indices. We may even + // need to create a new mini index buffer specifically for this + // primitive type.) + pID3DDevice->DrawIndexedPrimitive(D3DPT_LINELIST, 0, 0, vertexCount, 0, primitiveCount); + } + else + { + pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_LINESTRIP, 0, vertexCount, + primitiveCount - 1, indexList, indexType, vertices, stride); + + u16 tmpIndices[] = {static_cast(primitiveCount - 1), 0}; + + pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_LINELIST, 0, vertexCount, + 1, tmpIndices, indexType, vertices, stride); + } + break; + case scene::EPT_LINES: + if(!vertices) + pID3DDevice->DrawIndexedPrimitive(D3DPT_LINELIST, 0, 0, vertexCount, 0, primitiveCount); + else + pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_LINELIST, 0, vertexCount, + primitiveCount, indexList, indexType, vertices, stride); + break; + case scene::EPT_TRIANGLE_STRIP: + if(!vertices) + pID3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 0, 0, vertexCount, 0, primitiveCount); + else + pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLESTRIP, 0, vertexCount, primitiveCount, + indexList, indexType, vertices, stride); + break; + case scene::EPT_TRIANGLE_FAN: + if(!vertices) + pID3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLEFAN, 0, 0, vertexCount, 0, primitiveCount); + else + pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLEFAN, 0, vertexCount, primitiveCount, + indexList, indexType, vertices, stride); + break; + case scene::EPT_TRIANGLES: + if(!vertices) + { + pID3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, vertexCount, 0, primitiveCount); + } + else + { + pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, vertexCount, + primitiveCount, indexList, indexType, vertices, stride); + } + break; + } +} + + +void CD3D9Driver::draw2DImage(const video::ITexture* texture, + const core::rect& destRect, + const core::rect& sourceRect, + const core::rect* clipRect, + const video::SColor* const colors, + bool useAlphaChannelOfTexture) +{ + if(!texture) + return; + + 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 video::SColor temp[4] = + { + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF + }; + + const video::SColor* const useColor = colors ? colors : temp; + + S3DVertex vtx[4]; // clock wise + vtx[0] = S3DVertex((f32)destRect.UpperLeftCorner.X, (f32)destRect.UpperLeftCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, useColor[0], + tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + vtx[1] = S3DVertex((f32)destRect.LowerRightCorner.X, (f32)destRect.UpperLeftCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, useColor[3], + tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + vtx[2] = S3DVertex((f32)destRect.LowerRightCorner.X, (f32)destRect.LowerRightCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, useColor[2], + tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + vtx[3] = S3DVertex((f32)destRect.UpperLeftCorner.X, (f32)destRect.LowerRightCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, useColor[1], + tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + + s16 indices[6] = {0,1,2,0,2,3}; + + setActiveTexture(0, texture); + + setRenderStates2DMode(useColor[0].getAlpha()<255 || useColor[1].getAlpha()<255 || + useColor[2].getAlpha()<255 || useColor[3].getAlpha()<255, + true, useAlphaChannelOfTexture); + + setVertexShader(EVT_STANDARD); + + if (clipRect) + { + pID3DDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); + RECT scissor; + scissor.left = clipRect->UpperLeftCorner.X; + scissor.top = clipRect->UpperLeftCorner.Y; + scissor.right = clipRect->LowerRightCorner.X; + scissor.bottom = clipRect->LowerRightCorner.Y; + pID3DDevice->SetScissorRect(&scissor); + } + + pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0], + D3DFMT_INDEX16,&vtx[0], sizeof(S3DVertex)); + + if (clipRect) + pID3DDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); +} + + +void CD3D9Driver::draw2DImageBatch(const video::ITexture* texture, + const core::array >& positions, + const core::array >& sourceRects, + const core::rect* clipRect, + SColor color, + bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + if (!setActiveTexture(0, texture)) + return; + + setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); + + const irr::u32 drawCount = core::min_(positions.size(), sourceRects.size()); + + core::array vtx(drawCount * 4); + core::array indices(drawCount * 6); + + for(u32 i = 0;i < drawCount;i++) + { + core::position2d targetPos = positions[i]; + core::position2d sourcePos = sourceRects[i].UpperLeftCorner; + // This needs to be signed as it may go negative. + core::dimension2d sourceSize(sourceRects[i].getSize()); + + if (clipRect) + { + if (targetPos.X < clipRect->UpperLeftCorner.X) + { + sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X; + if (sourceSize.Width <= 0) + continue; + + sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X; + targetPos.X = clipRect->UpperLeftCorner.X; + } + + if (targetPos.X + (s32)sourceSize.Width > clipRect->LowerRightCorner.X) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X; + if (sourceSize.Width <= 0) + continue; + } + + if (targetPos.Y < clipRect->UpperLeftCorner.Y) + { + sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y; + if (sourceSize.Height <= 0) + continue; + + sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y; + targetPos.Y = clipRect->UpperLeftCorner.Y; + } + + if (targetPos.Y + (s32)sourceSize.Height > clipRect->LowerRightCorner.Y) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y; + if (sourceSize.Height <= 0) + continue; + } + } + + // clip these coordinates + + if (targetPos.X<0) + { + sourceSize.Width += targetPos.X; + if (sourceSize.Width <= 0) + continue; + + sourcePos.X -= targetPos.X; + targetPos.X = 0; + } + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width; + if (sourceSize.Width <= 0) + continue; + } + + if (targetPos.Y<0) + { + sourceSize.Height += targetPos.Y; + if (sourceSize.Height <= 0) + continue; + + sourcePos.Y -= targetPos.Y; + targetPos.Y = 0; + } + + if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height; + if (sourceSize.Height <= 0) + continue; + } + + // ok, we've clipped everything. + // now draw it. + + core::rect tcoords; + tcoords.UpperLeftCorner.X = (((f32)sourcePos.X)) / texture->getOriginalSize().Width ; + tcoords.UpperLeftCorner.Y = (((f32)sourcePos.Y)) / texture->getOriginalSize().Height; + tcoords.LowerRightCorner.X = tcoords.UpperLeftCorner.X + ((f32)(sourceSize.Width) / texture->getOriginalSize().Width); + tcoords.LowerRightCorner.Y = tcoords.UpperLeftCorner.Y + ((f32)(sourceSize.Height) / texture->getOriginalSize().Height); + + const core::rect poss(targetPos, sourceSize); + + vtx.push_back(S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, color, + tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y)); + vtx.push_back(S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, color, + tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y)); + vtx.push_back(S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, color, + tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y)); + vtx.push_back(S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, color, + tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y)); + + const u32 curPos = vtx.size()-4; + indices.push_back(0+curPos); + indices.push_back(1+curPos); + indices.push_back(2+curPos); + + indices.push_back(0+curPos); + indices.push_back(2+curPos); + indices.push_back(3+curPos); + } + + if (vtx.size()) + { + setVertexShader(EVT_STANDARD); + + pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, vtx.size(), indices.size() / 3, indices.pointer(), + D3DFMT_INDEX16,vtx.pointer(), sizeof(S3DVertex)); + } +} + + +//! draws a 2d image, using a color and the alpha channel of the texture if +//! desired. The image is drawn at pos and clipped against clipRect (if != 0). +void CD3D9Driver::draw2DImage(const video::ITexture* texture, + const core::position2d& pos, + const core::rect& sourceRect, + const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + if (!sourceRect.isValid()) + return; + + if (!setActiveTexture(0, texture)) + return; + + 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) + { + if (targetPos.X < clipRect->UpperLeftCorner.X) + { + sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X; + if (sourceSize.Width <= 0) + return; + + sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X; + targetPos.X = clipRect->UpperLeftCorner.X; + } + + if (targetPos.X + (s32)sourceSize.Width > clipRect->LowerRightCorner.X) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X; + if (sourceSize.Width <= 0) + return; + } + + if (targetPos.Y < clipRect->UpperLeftCorner.Y) + { + sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y; + if (sourceSize.Height <= 0) + return; + + sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y; + targetPos.Y = clipRect->UpperLeftCorner.Y; + } + + if (targetPos.Y + (s32)sourceSize.Height > clipRect->LowerRightCorner.Y) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y; + if (sourceSize.Height <= 0) + return; + } + } + + // clip these coordinates + + if (targetPos.X<0) + { + sourceSize.Width += targetPos.X; + if (sourceSize.Width <= 0) + return; + + sourcePos.X -= targetPos.X; + targetPos.X = 0; + } + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width; + if (sourceSize.Width <= 0) + return; + } + + if (targetPos.Y<0) + { + sourceSize.Height += targetPos.Y; + if (sourceSize.Height <= 0) + return; + + sourcePos.Y -= targetPos.Y; + targetPos.Y = 0; + } + + if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height; + if (sourceSize.Height <= 0) + return; + } + + // ok, we've clipped everything. + // now draw it. + + core::rect tcoords; + tcoords.UpperLeftCorner.X = (((f32)sourcePos.X)) / texture->getOriginalSize().Width ; + tcoords.UpperLeftCorner.Y = (((f32)sourcePos.Y)) / texture->getOriginalSize().Height; + tcoords.LowerRightCorner.X = tcoords.UpperLeftCorner.X + ((f32)(sourceSize.Width) / texture->getOriginalSize().Width); + tcoords.LowerRightCorner.Y = tcoords.UpperLeftCorner.Y + ((f32)(sourceSize.Height) / texture->getOriginalSize().Height); + + const core::rect poss(targetPos, sourceSize); + + setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); + + S3DVertex vtx[4]; + vtx[0] = S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, color, + tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + vtx[1] = S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, color, + tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + vtx[2] = S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, color, + tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + vtx[3] = S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, color, + tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + + s16 indices[6] = {0,1,2,0,2,3}; + + setVertexShader(EVT_STANDARD); + + pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0], + D3DFMT_INDEX16,&vtx[0], sizeof(S3DVertex)); +} + + +//!Draws a 2d rectangle with a gradient. +void CD3D9Driver::draw2DRectangle(const core::rect& position, + SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, + const core::rect* clip) +{ + core::rect pos(position); + + if (clip) + pos.clipAgainst(*clip); + + if (!pos.isValid()) + return; + + S3DVertex vtx[4]; + vtx[0] = S3DVertex((f32)pos.UpperLeftCorner.X, (f32)pos.UpperLeftCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, colorLeftUp, 0.0f, 0.0f); + vtx[1] = S3DVertex((f32)pos.LowerRightCorner.X, (f32)pos.UpperLeftCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, colorRightUp, 0.0f, 1.0f); + vtx[2] = S3DVertex((f32)pos.LowerRightCorner.X, (f32)pos.LowerRightCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, colorRightDown, 1.0f, 0.0f); + vtx[3] = S3DVertex((f32)pos.UpperLeftCorner.X, (f32)pos.LowerRightCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, colorLeftDown, 1.0f, 1.0f); + + s16 indices[6] = {0,1,2,0,2,3}; + + setRenderStates2DMode( + colorLeftUp.getAlpha() < 255 || + colorRightUp.getAlpha() < 255 || + colorLeftDown.getAlpha() < 255 || + colorRightDown.getAlpha() < 255, false, false); + + setActiveTexture(0,0); + + setVertexShader(EVT_STANDARD); + + pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0], + D3DFMT_INDEX16, &vtx[0], sizeof(S3DVertex)); +} + + +//! Draws a 2d line. +void CD3D9Driver::draw2DLine(const core::position2d& start, + const core::position2d& end, + SColor color) +{ + if (start==end) + drawPixel(start.X, start.Y, color); + else + { + // thanks to Vash TheStampede who sent in his implementation + S3DVertex vtx[2]; + vtx[0] = S3DVertex((f32)start.X+0.375f, (f32)start.Y+0.375f, 0.0f, + 0.0f, 0.0f, 0.0f, // normal + color, 0.0f, 0.0f); // texture + + vtx[1] = S3DVertex((f32)end.X+0.375f, (f32)end.Y+0.375f, 0.0f, + 0.0f, 0.0f, 0.0f, + color, 0.0f, 0.0f); + + setRenderStates2DMode(color.getAlpha() < 255, false, false); + setActiveTexture(0,0); + + setVertexShader(EVT_STANDARD); + + pID3DDevice->DrawPrimitiveUP(D3DPT_LINELIST, 1, + &vtx[0], sizeof(S3DVertex) ); + } +} + + +//! Draws a pixel +void CD3D9Driver::drawPixel(u32 x, u32 y, const SColor & color) +{ + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + if(x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height) + return; + + setRenderStates2DMode(color.getAlpha() < 255, false, false); + setActiveTexture(0,0); + + setVertexShader(EVT_STANDARD); + + S3DVertex vertex((f32)x+0.375f, (f32)y+0.375f, 0.f, 0.f, 0.f, 0.f, color, 0.f, 0.f); + + pID3DDevice->DrawPrimitiveUP(D3DPT_POINTLIST, 1, &vertex, sizeof(vertex)); +} + + +//! sets right vertex shader +void CD3D9Driver::setVertexShader(E_VERTEX_TYPE newType) +{ + if (newType != LastVertexType) + { + LastVertexType = newType; + HRESULT hr = 0; + + switch(newType) + { + case EVT_STANDARD: + hr = pID3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1); + break; + case EVT_2TCOORDS: + hr = pID3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX2); + break; + case EVT_TANGENTS: + hr = pID3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX3 | + D3DFVF_TEXCOORDSIZE2(0) | // real texture coord + D3DFVF_TEXCOORDSIZE3(1) | // misuse texture coord 2 for tangent + D3DFVF_TEXCOORDSIZE3(2) // misuse texture coord 3 for binormal + ); + break; + } + + if (FAILED(hr)) + { + os::Printer::log("Could not set vertex Shader.", ELL_ERROR); + return; + } + } +} + + +//! sets the needed renderstates +bool CD3D9Driver::setRenderStates3DMode() +{ + if (!pID3DDevice) + return false; + + if (CurrentRenderMode != ERM_3D) + { + // switch back the matrices + pID3DDevice->SetTransform(D3DTS_VIEW, (D3DMATRIX*)((void*)&Matrices[ETS_VIEW])); + pID3DDevice->SetTransform(D3DTS_WORLD, (D3DMATRIX*)((void*)&Matrices[ETS_WORLD])); + pID3DDevice->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)((void*)&Matrices[ETS_PROJECTION])); + + pID3DDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + pID3DDevice->SetRenderState(D3DRS_CLIPPING, TRUE); + + ResetRenderStates = true; + } + + if (ResetRenderStates || LastMaterial != Material) + { + // unset old material + + if (CurrentRenderMode == ERM_3D && + LastMaterial.MaterialType != Material.MaterialType && + LastMaterial.MaterialType >= 0 && LastMaterial.MaterialType < (s32)MaterialRenderers.size()) + MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); + + // set new material. + + if (Material.MaterialType >= 0 && Material.MaterialType < (s32)MaterialRenderers.size()) + MaterialRenderers[Material.MaterialType].Renderer->OnSetMaterial( + Material, LastMaterial, ResetRenderStates, this); + } + + bool shaderOK = true; + if (Material.MaterialType >= 0 && Material.MaterialType < (s32)MaterialRenderers.size()) + shaderOK = MaterialRenderers[Material.MaterialType].Renderer->OnRender(this, LastVertexType); + + LastMaterial = Material; + + ResetRenderStates = false; + + CurrentRenderMode = ERM_3D; + + return shaderOK; +} + + +//! Map Irrlicht texture wrap mode to native values +D3DTEXTUREADDRESS CD3D9Driver::getTextureWrapMode(const u8 clamp) +{ + switch (clamp) + { + case ETC_REPEAT: + if (Caps.TextureAddressCaps & D3DPTADDRESSCAPS_WRAP) + return D3DTADDRESS_WRAP; + case ETC_CLAMP: + case ETC_CLAMP_TO_EDGE: + if (Caps.TextureAddressCaps & D3DPTADDRESSCAPS_CLAMP) + return D3DTADDRESS_CLAMP; + case ETC_MIRROR: + if (Caps.TextureAddressCaps & D3DPTADDRESSCAPS_MIRROR) + return D3DTADDRESS_MIRROR; + case ETC_CLAMP_TO_BORDER: + if (Caps.TextureAddressCaps & D3DPTADDRESSCAPS_BORDER) + return D3DTADDRESS_BORDER; + else + return D3DTADDRESS_CLAMP; + case ETC_MIRROR_CLAMP: + case ETC_MIRROR_CLAMP_TO_EDGE: + case ETC_MIRROR_CLAMP_TO_BORDER: + if (Caps.TextureAddressCaps & D3DPTADDRESSCAPS_MIRRORONCE) + return D3DTADDRESS_MIRRORONCE; + else + return D3DTADDRESS_CLAMP; + default: + return D3DTADDRESS_WRAP; + } +} + + +//! Can be called by an IMaterialRenderer to make its work easier. +void CD3D9Driver::setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial, + bool resetAllRenderstates) +{ + // This needs only to be updated onresets + if (Params.HandleSRGB && resetAllRenderstates) + pID3DDevice->SetRenderState(D3DRS_SRGBWRITEENABLE, TRUE); + + if (resetAllRenderstates || + lastmaterial.AmbientColor != material.AmbientColor || + lastmaterial.DiffuseColor != material.DiffuseColor || + lastmaterial.SpecularColor != material.SpecularColor || + lastmaterial.EmissiveColor != material.EmissiveColor || + lastmaterial.Shininess != material.Shininess) + { + D3DMATERIAL9 mat; + mat.Diffuse = colorToD3D(material.DiffuseColor); + mat.Ambient = colorToD3D(material.AmbientColor); + mat.Specular = colorToD3D(material.SpecularColor); + mat.Emissive = colorToD3D(material.EmissiveColor); + mat.Power = material.Shininess; + pID3DDevice->SetMaterial(&mat); + } + + if (lastmaterial.ColorMaterial != material.ColorMaterial) + { + pID3DDevice->SetRenderState(D3DRS_COLORVERTEX, (material.ColorMaterial != ECM_NONE)); + pID3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, + ((material.ColorMaterial == ECM_DIFFUSE)|| + (material.ColorMaterial == ECM_DIFFUSE_AND_AMBIENT))?D3DMCS_COLOR1:D3DMCS_MATERIAL); + pID3DDevice->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, + ((material.ColorMaterial == ECM_AMBIENT)|| + (material.ColorMaterial == ECM_DIFFUSE_AND_AMBIENT))?D3DMCS_COLOR1:D3DMCS_MATERIAL); + pID3DDevice->SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, + (material.ColorMaterial == ECM_EMISSIVE)?D3DMCS_COLOR1:D3DMCS_MATERIAL); + pID3DDevice->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, + (material.ColorMaterial == ECM_SPECULAR)?D3DMCS_COLOR1:D3DMCS_MATERIAL); + } + + // fillmode + if (resetAllRenderstates || lastmaterial.Wireframe != material.Wireframe || lastmaterial.PointCloud != material.PointCloud) + { + if (material.Wireframe) + pID3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + else + if (material.PointCloud) + pID3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_POINT); + else + pID3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + } + + // shademode + + if (resetAllRenderstates || lastmaterial.GouraudShading != material.GouraudShading) + { + if (material.GouraudShading) + pID3DDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); + else + pID3DDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT); + } + + // lighting + + if (resetAllRenderstates || lastmaterial.Lighting != material.Lighting) + { + if (material.Lighting) + pID3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE); + else + pID3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE); + } + + // zbuffer + + if (resetAllRenderstates || lastmaterial.ZBuffer != material.ZBuffer) + { + switch (material.ZBuffer) + { + case ECFN_DISABLED: + 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; + case ECFN_NEVER: + pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_NEVER); + } + } + + // zwrite + if (getWriteZBuffer(material)) + { + pID3DDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE); + } + else + { + pID3DDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + } + + // back face culling + + if (resetAllRenderstates || (lastmaterial.FrontfaceCulling != material.FrontfaceCulling) || (lastmaterial.BackfaceCulling != material.BackfaceCulling)) + { +// if (material.FrontfaceCulling && material.BackfaceCulling) +// pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW|D3DCULL_CCW); +// else + if (material.FrontfaceCulling) + pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW); + else + if (material.BackfaceCulling) + pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); + else + pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + } + + // fog + if (resetAllRenderstates || lastmaterial.FogEnable != material.FogEnable) + { + pID3DDevice->SetRenderState(D3DRS_FOGENABLE, material.FogEnable); + } + + // specular highlights + if (resetAllRenderstates || !core::equals(lastmaterial.Shininess,material.Shininess)) + { + const bool enable = (material.Shininess!=0.0f); + pID3DDevice->SetRenderState(D3DRS_SPECULARENABLE, enable); + pID3DDevice->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL); + } + + // normalization + if (resetAllRenderstates || lastmaterial.NormalizeNormals != material.NormalizeNormals) + { + 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); + } + + // Blend Operation + if (material.BlendOperation == EBO_NONE) + BridgeCalls->setBlend(false); + else + { + BridgeCalls->setBlend(true); + + if (queryFeature(EVDF_BLEND_OPERATIONS)) + { + switch (material.BlendOperation) + { + case EBO_MAX: + case EBO_MAX_FACTOR: + case EBO_MAX_ALPHA: + BridgeCalls->setBlendOperation(D3DBLENDOP_MAX); + break; + case EBO_MIN: + case EBO_MIN_FACTOR: + case EBO_MIN_ALPHA: + BridgeCalls->setBlendOperation(D3DBLENDOP_MIN); + break; + case EBO_SUBTRACT: + BridgeCalls->setBlendOperation(D3DBLENDOP_SUBTRACT); + break; + case EBO_REVSUBTRACT: + BridgeCalls->setBlendOperation(D3DBLENDOP_REVSUBTRACT); + break; + default: + BridgeCalls->setBlendOperation(D3DBLENDOP_ADD); + break; + } + } + } + + // Blend Factor + if (IR(material.BlendFactor) & 0xFFFFFFFF // TODO: why the & 0xFFFFFFFF? + && material.MaterialType != EMT_ONETEXTURE_BLEND + ) + { + E_BLEND_FACTOR srcRGBFact = EBF_ZERO; + E_BLEND_FACTOR dstRGBFact = EBF_ZERO; + E_BLEND_FACTOR srcAlphaFact = EBF_ZERO; + E_BLEND_FACTOR dstAlphaFact = EBF_ZERO; + E_MODULATE_FUNC modulo = EMFN_MODULATE_1X; + u32 alphaSource = 0; + + unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulo, alphaSource, material.BlendFactor); + + BridgeCalls->setBlendFuncSeparate(getD3DBlend(srcRGBFact), getD3DBlend(dstRGBFact), + getD3DBlend(srcAlphaFact), getD3DBlend(dstAlphaFact)); + } + + // Polygon offset + if (queryFeature(EVDF_POLYGON_OFFSET) && (resetAllRenderstates || + lastmaterial.PolygonOffsetDirection != material.PolygonOffsetDirection || + lastmaterial.PolygonOffsetFactor != material.PolygonOffsetFactor || + lastmaterial.PolygonOffsetSlopeScale != material.PolygonOffsetSlopeScale || + lastmaterial.PolygonOffsetDepthBias != material.PolygonOffsetDepthBias )) + { + if ( material.PolygonOffsetSlopeScale || material.PolygonOffsetDepthBias ) + { + pID3DDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, F2DW(material.PolygonOffsetSlopeScale)); + pID3DDevice->SetRenderState(D3DRS_DEPTHBIAS, F2DW(material.PolygonOffsetDepthBias)); + } + else if (material.PolygonOffsetFactor) + { + if (material.PolygonOffsetDirection==EPO_BACK) + { + pID3DDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, F2DW(1.f)); + pID3DDevice->SetRenderState(D3DRS_DEPTHBIAS, F2DW((FLOAT)material.PolygonOffsetFactor)); + } + else + { + pID3DDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, F2DW(-1.f)); + pID3DDevice->SetRenderState(D3DRS_DEPTHBIAS, F2DW((FLOAT)-material.PolygonOffsetFactor)); + } + } + else + { + pID3DDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0); + pID3DDevice->SetRenderState(D3DRS_DEPTHBIAS, 0); + } + } + + // 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 (Params.AntiAlias) + { + 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) + { + pID3DDevice->SetRenderState(D3DRS_POINTSIZE, F2DW(material.Thickness)); + } + + // texture address mode + for (u32 st=0; stSetSamplerState(st, D3DSAMP_SRGBTEXTURE, TRUE); + + if (resetAllRenderstates || lastmaterial.TextureLayer[st].LODBias != material.TextureLayer[st].LODBias) + { + const float tmp = material.TextureLayer[st].LODBias * 0.125f; + pID3DDevice->SetSamplerState(st, D3DSAMP_MIPMAPLODBIAS, F2DW(tmp)); + } + + if (resetAllRenderstates || lastmaterial.TextureLayer[st].TextureWrapU != material.TextureLayer[st].TextureWrapU) + pID3DDevice->SetSamplerState(st, D3DSAMP_ADDRESSU, getTextureWrapMode(material.TextureLayer[st].TextureWrapU)); + // If separate UV not supported reuse U for V + if (!(Caps.TextureAddressCaps & D3DPTADDRESSCAPS_INDEPENDENTUV)) + { + pID3DDevice->SetSamplerState(st, D3DSAMP_ADDRESSV, getTextureWrapMode(material.TextureLayer[st].TextureWrapU)); + pID3DDevice->SetSamplerState(st, D3DSAMP_ADDRESSW, getTextureWrapMode(material.TextureLayer[st].TextureWrapU)); + } + else + { + if (resetAllRenderstates || lastmaterial.TextureLayer[st].TextureWrapV != material.TextureLayer[st].TextureWrapV) + pID3DDevice->SetSamplerState(st, D3DSAMP_ADDRESSV, getTextureWrapMode(material.TextureLayer[st].TextureWrapV)); + + if (resetAllRenderstates || lastmaterial.TextureLayer[st].TextureWrapW != material.TextureLayer[st].TextureWrapW) + pID3DDevice->SetSamplerState(st, D3DSAMP_ADDRESSW, getTextureWrapMode(material.TextureLayer[st].TextureWrapW)); + } + + // Bilinear, trilinear, and anisotropic filter + if (resetAllRenderstates || + lastmaterial.TextureLayer[st].BilinearFilter != material.TextureLayer[st].BilinearFilter || + lastmaterial.TextureLayer[st].TrilinearFilter != material.TextureLayer[st].TrilinearFilter || + lastmaterial.TextureLayer[st].AnisotropicFilter != material.TextureLayer[st].AnisotropicFilter || + lastmaterial.UseMipMaps != material.UseMipMaps) + { + if (material.TextureLayer[st].BilinearFilter || material.TextureLayer[st].TrilinearFilter || material.TextureLayer[st].AnisotropicFilter) + { + D3DTEXTUREFILTERTYPE tftMag = ((Caps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC) && + material.TextureLayer[st].AnisotropicFilter) ? D3DTEXF_ANISOTROPIC : D3DTEXF_LINEAR; + D3DTEXTUREFILTERTYPE tftMin = ((Caps.TextureFilterCaps & D3DPTFILTERCAPS_MINFANISOTROPIC) && + material.TextureLayer[st].AnisotropicFilter) ? D3DTEXF_ANISOTROPIC : D3DTEXF_LINEAR; + D3DTEXTUREFILTERTYPE tftMip = material.UseMipMaps? (material.TextureLayer[st].TrilinearFilter ? D3DTEXF_LINEAR : D3DTEXF_POINT) : D3DTEXF_NONE; + + 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); + } + else + { + pID3DDevice->SetSamplerState(st, D3DSAMP_MINFILTER, D3DTEXF_POINT); + pID3DDevice->SetSamplerState(st, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + pID3DDevice->SetSamplerState(st, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + } + } + } +} + + +//! sets the needed renderstates +void CD3D9Driver::setRenderStatesStencilShadowMode(bool zfail, u32 debugDataVisible) +{ + if ((CurrentRenderMode != ERM_SHADOW_VOLUME_ZFAIL && + CurrentRenderMode != ERM_SHADOW_VOLUME_ZPASS) || + Transformation3DChanged) + { + // unset last 3d material + if (CurrentRenderMode == ERM_3D && + static_cast(Material.MaterialType) < MaterialRenderers.size()) + { + MaterialRenderers[Material.MaterialType].Renderer->OnUnsetMaterial(); + ResetRenderStates = true; + } + // switch back the matrices + pID3DDevice->SetTransform(D3DTS_VIEW, (D3DMATRIX*)((void*)&Matrices[ETS_VIEW])); + pID3DDevice->SetTransform(D3DTS_WORLD, (D3DMATRIX*)((void*)&Matrices[ETS_WORLD])); + pID3DDevice->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)((void*)&Matrices[ETS_PROJECTION])); + + Transformation3DChanged = false; + + setActiveTexture(0,0); + setActiveTexture(1,0); + setActiveTexture(2,0); + setActiveTexture(3,0); + + pID3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE); + + pID3DDevice->SetFVF(D3DFVF_XYZ); + LastVertexType = (video::E_VERTEX_TYPE)(-1); + + pID3DDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + pID3DDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT); + //pID3DDevice->SetRenderState(D3DRS_FOGENABLE, FALSE); + //pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + + pID3DDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + pID3DDevice->SetRenderState(D3DRS_STENCILREF, 0x0); + pID3DDevice->SetRenderState(D3DRS_STENCILMASK, 0xffffffff); + pID3DDevice->SetRenderState(D3DRS_STENCILWRITEMASK, 0xffffffff); + + BridgeCalls->setBlend(true); + BridgeCalls->setBlendFunc(D3DBLEND_ZERO, D3DBLEND_ONE); + + pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS); + + //if (!(debugDataVisible & (scene::EDS_SKELETON|scene::EDS_MESH_WIRE_OVERLAY))) + // pID3DDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); + if ((debugDataVisible & scene::EDS_MESH_WIRE_OVERLAY)) + pID3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); + } + + if (CurrentRenderMode != ERM_SHADOW_VOLUME_ZPASS && !zfail) + { + // USE THE ZPASS METHOD + pID3DDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); + pID3DDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP); + //pID3DDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCR); // does not matter, will be set later + } + else + if (CurrentRenderMode != ERM_SHADOW_VOLUME_ZFAIL && zfail) + { + // USE THE ZFAIL METHOD + pID3DDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); + //pID3DDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_INCR); // does not matter, will be set later + pID3DDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); + } + + CurrentRenderMode = zfail ? ERM_SHADOW_VOLUME_ZFAIL : ERM_SHADOW_VOLUME_ZPASS; +} + + +//! sets the needed renderstates +void CD3D9Driver::setRenderStatesStencilFillMode(bool alpha) +{ + if (CurrentRenderMode != ERM_STENCIL_FILL || Transformation3DChanged) + { + core::matrix4 mat; + pID3DDevice->SetTransform(D3DTS_VIEW, &UnitMatrixD3D9); + pID3DDevice->SetTransform(D3DTS_WORLD, &UnitMatrixD3D9); + pID3DDevice->SetTransform(D3DTS_PROJECTION, &UnitMatrixD3D9); + + pID3DDevice->SetRenderState(D3DRS_ZENABLE, FALSE); + pID3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE); + pID3DDevice->SetRenderState(D3DRS_FOGENABLE, FALSE); + + pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + + pID3DDevice->SetRenderState(D3DRS_STENCILREF, 0x1); + pID3DDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_LESSEQUAL); + //pID3DDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_GREATEREQUAL); + pID3DDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); + pID3DDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP); + pID3DDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); + pID3DDevice->SetRenderState(D3DRS_STENCILMASK, 0xffffffff); + pID3DDevice->SetRenderState(D3DRS_STENCILWRITEMASK, 0xffffffff); + + pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); + + Transformation3DChanged = false; + + pID3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + pID3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + pID3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); + if (alpha) + { + BridgeCalls->setBlend(true); + BridgeCalls->setBlendFunc(D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + } + else + { + BridgeCalls->setBlend(false); + } + } + + CurrentRenderMode = ERM_STENCIL_FILL; +} + + +//! Enable the 2d override material +void CD3D9Driver::enableMaterial2D(bool enable) +{ + if (!enable) + CurrentRenderMode = ERM_NONE; + CNullDriver::enableMaterial2D(enable); +} + + +//! sets the needed renderstates +void CD3D9Driver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel) +{ + if (!pID3DDevice) + return; + + if (CurrentRenderMode != ERM_2D || Transformation3DChanged) + { + // unset last 3d material + if (CurrentRenderMode == ERM_3D) + { + if (static_cast(LastMaterial.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); + } + if (!OverrideMaterial2DEnabled) + { + setBasicRenderStates(InitMaterial2D, LastMaterial, true); + LastMaterial=InitMaterial2D; + + // fix everything that is wrongly set by InitMaterial2D default + pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + + pID3DDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + } + core::matrix4 m; +// this fixes some problems with pixel exact rendering, but also breaks nice texturing +// moreover, it would have to be tested in each call, as the texture flag can change each time +// if (!texture) +// m.setTranslation(core::vector3df(0.5f,0.5f,0)); + pID3DDevice->SetTransform(D3DTS_WORLD, (D3DMATRIX*)((void*)m.pointer())); + + // adjust the view such that pixel center aligns with texels + // Otherwise, subpixel artifacts will occur + m.setTranslation(core::vector3df(-0.5f,-0.5f,0)); + pID3DDevice->SetTransform(D3DTS_VIEW, (D3DMATRIX*)((void*)m.pointer())); + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + m.buildProjectionMatrixOrthoLH(f32(renderTargetSize.Width), f32(-(s32)(renderTargetSize.Height)), -1.0, 1.0); + m.setTranslation(core::vector3df(-1,1,0)); + pID3DDevice->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)((void*)m.pointer())); + + // 2d elements are clipped in software + pID3DDevice->SetRenderState(D3DRS_CLIPPING, FALSE); + + Transformation3DChanged = false; + } + if (OverrideMaterial2DEnabled) + { + OverrideMaterial2D.Lighting=false; + setBasicRenderStates(OverrideMaterial2D, LastMaterial, false); + LastMaterial = OverrideMaterial2D; + } + + // no alphaChannel without texture + alphaChannel &= texture; + + if (alpha || alphaChannel) + { + BridgeCalls->setBlend(true); + BridgeCalls->setBlendFunc(D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + } + else + BridgeCalls->setBlend(false); + pID3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + pID3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + pID3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + if (texture) + { + setTransform(ETS_TEXTURE_0, core::IdentityMatrix); + // Due to the transformation change, the previous line would call a reset each frame + // but we can safely reset the variable as it was false before + Transformation3DChanged=false; + } + if (alphaChannel) + { + pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + + if (alpha) + { + pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + } + else + { + pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + } + } + else + { + pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + if (alpha) + { + pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2); + } + else + { + pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + pID3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + } + } + + CurrentRenderMode = ERM_2D; +} + + +//! deletes all dynamic lights there are +void CD3D9Driver::deleteAllDynamicLights() +{ + for (s32 i=0; iLightEnable(i, false); + + LastSetLight = -1; + + CNullDriver::deleteAllDynamicLights(); +} + + +//! adds a dynamic light +s32 CD3D9Driver::addDynamicLight(const SLight& dl) +{ + CNullDriver::addDynamicLight(dl); + + D3DLIGHT9 light; + + switch (dl.Type) + { + case ELT_POINT: + light.Type = D3DLIGHT_POINT; + break; + case ELT_SPOT: + light.Type = D3DLIGHT_SPOT; + break; + case ELT_DIRECTIONAL: + light.Type = D3DLIGHT_DIRECTIONAL; + break; + } + + light.Position = *(D3DVECTOR*)((void*)(&dl.Position)); + light.Direction = *(D3DVECTOR*)((void*)(&dl.Direction)); + + light.Range = core::min_(dl.Radius, MaxLightDistance); + light.Falloff = dl.Falloff; + + light.Diffuse = *(D3DCOLORVALUE*)((void*)(&dl.DiffuseColor)); + light.Specular = *(D3DCOLORVALUE*)((void*)(&dl.SpecularColor)); + light.Ambient = *(D3DCOLORVALUE*)((void*)(&dl.AmbientColor)); + + light.Attenuation0 = dl.Attenuation.X; + light.Attenuation1 = dl.Attenuation.Y; + light.Attenuation2 = dl.Attenuation.Z; + + light.Theta = dl.InnerCone * 2.0f * core::DEGTORAD; + light.Phi = dl.OuterCone * 2.0f * core::DEGTORAD; + + ++LastSetLight; + + 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); +} + + +//! returns the maximal amount of dynamic lights the device can handle +u32 CD3D9Driver::getMaximalDynamicLightAmount() const +{ + return Caps.MaxActiveLights; +} + + +//! 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. +void CD3D9Driver::setAmbientLight(const SColorf& color) +{ + CNullDriver::setAmbientLight(color); + + if (!pID3DDevice) + return; + + D3DCOLOR col = color.toSColor().color; + pID3DDevice->SetRenderState(D3DRS_AMBIENT, col); +} + + +//! \return Returns the name of the video driver. Example: In case of the DIRECT3D9 +//! driver, it would return "Direct3D9.0". +const wchar_t* CD3D9Driver::getName() const +{ + return L"Direct3D 9.0"; +} + + +//! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do +//! this: First, draw all geometry. Then use this method, to draw the shadow +//! volume. Then, use IVideoDriver::drawStencilShadow() to visualize the shadow. +void CD3D9Driver::drawStencilShadowVolume(const core::array& triangles, bool zfail, u32 debugDataVisible) +{ + if (!Params.Stencilbuffer) + return; + + setRenderStatesStencilShadowMode(zfail, debugDataVisible); + + const u32 count = triangles.size(); + if (!count) + return; + + if (!zfail) + { + // ZPASS Method + + // Draw front-side of shadow volume in stencil only + pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); + pID3DDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCR); + pID3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, count / 3, triangles.const_pointer(), sizeof(core::vector3df)); + + // Now reverse cull order so front sides of shadow volume are written. + pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW); + pID3DDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_DECR); + pID3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, count / 3, triangles.const_pointer(), sizeof(core::vector3df)); + } + else + { + // ZFAIL Method + + // Draw front-side of shadow volume in stencil only + pID3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW); + pID3DDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_INCR); + pID3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, count / 3, triangles.const_pointer(), sizeof(core::vector3df)); + + // Now reverse cull order so front sides of shadow volume are written. + pID3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW); + pID3DDevice->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_DECR); + pID3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, count / 3, triangles.const_pointer(), sizeof(core::vector3df)); + } +} + + +//! 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. +void CD3D9Driver::drawStencilShadow(bool clearStencilBuffer, video::SColor leftUpEdge, + video::SColor rightUpEdge, video::SColor leftDownEdge, video::SColor rightDownEdge) +{ + if (!Params.Stencilbuffer) + return; + + S3DVertex vtx[4]; + vtx[0] = S3DVertex(1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, leftUpEdge, 0.0f, 0.0f); + vtx[1] = S3DVertex(1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, rightUpEdge, 0.0f, 1.0f); + vtx[2] = S3DVertex(-1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, leftDownEdge, 1.0f, 0.0f); + vtx[3] = S3DVertex(-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, rightDownEdge, 1.0f, 1.0f); + + s16 indices[6] = {0,1,2,1,3,2}; + + setRenderStatesStencilFillMode( + leftUpEdge.getAlpha() < 255 || + rightUpEdge.getAlpha() < 255 || + leftDownEdge.getAlpha() < 255 || + rightDownEdge.getAlpha() < 255); + + setActiveTexture(0,0); + + setVertexShader(EVT_STANDARD); + + pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0], + D3DFMT_INDEX16, &vtx[0], sizeof(S3DVertex)); + + if (clearStencilBuffer) + pID3DDevice->Clear( 0, NULL, D3DCLEAR_STENCIL,0, 1.0, 0); +} + + +//! Returns the maximum amount of primitives (mostly vertices) which +//! the device is able to render with one drawIndexedTriangleList +//! call. +u32 CD3D9Driver::getMaximalPrimitiveCount() const +{ + return Caps.MaxPrimitiveCount; +} + + +//! Sets the fog mode. +void CD3D9Driver::setFog(SColor color, E_FOG_TYPE fogType, f32 start, + f32 end, f32 density, bool pixelFog, bool rangeFog) +{ + CNullDriver::setFog(color, fogType, start, end, density, pixelFog, rangeFog); + + if (!pID3DDevice) + return; + + pID3DDevice->SetRenderState(D3DRS_FOGCOLOR, color.color); + + pID3DDevice->SetRenderState( + pixelFog ? D3DRS_FOGTABLEMODE : D3DRS_FOGVERTEXMODE, + (fogType==EFT_FOG_LINEAR)? D3DFOG_LINEAR : (fogType==EFT_FOG_EXP)?D3DFOG_EXP:D3DFOG_EXP2); + + if (fogType==EFT_FOG_LINEAR) + { + pID3DDevice->SetRenderState(D3DRS_FOGSTART, F2DW(start)); + pID3DDevice->SetRenderState(D3DRS_FOGEND, F2DW(end)); + } + else + pID3DDevice->SetRenderState(D3DRS_FOGDENSITY, F2DW(density)); + + if(!pixelFog) + pID3DDevice->SetRenderState(D3DRS_RANGEFOGENABLE, rangeFog); +} + + +//! Draws a 3d line. +void CD3D9Driver::draw3DLine(const core::vector3df& start, + const core::vector3df& end, SColor color) +{ + setVertexShader(EVT_STANDARD); + setRenderStates3DMode(); + video::S3DVertex v[2]; + v[0].Color = color; + v[1].Color = color; + v[0].Pos = start; + v[1].Pos = end; + + pID3DDevice->DrawPrimitiveUP(D3DPT_LINELIST, 1, v, sizeof(S3DVertex)); +} + +void CD3D9Driver::draw3DBox( const core::aabbox3d& box, SColor color) +{ + core::vector3df edges[8]; + box.getEdges(edges); + + setVertexShader(EVT_STANDARD); + setRenderStates3DMode(); + + video::S3DVertex v[24]; + + for(u32 i = 0; i < 24; i++) + v[i].Color = color; + + v[0].Pos = edges[5]; + v[1].Pos = edges[1]; + v[2].Pos = edges[1]; + v[3].Pos = edges[3]; + v[4].Pos = edges[3]; + v[5].Pos = edges[7]; + v[6].Pos = edges[7]; + v[7].Pos = edges[5]; + v[8].Pos = edges[0]; + v[9].Pos = edges[2]; + v[10].Pos = edges[2]; + v[11].Pos = edges[6]; + v[12].Pos = edges[6]; + v[13].Pos = edges[4]; + v[14].Pos = edges[4]; + v[15].Pos = edges[0]; + v[16].Pos = edges[1]; + v[17].Pos = edges[0]; + v[18].Pos = edges[3]; + v[19].Pos = edges[2]; + v[20].Pos = edges[7]; + v[21].Pos = edges[6]; + v[22].Pos = edges[5]; + v[23].Pos = edges[4]; + + pID3DDevice->DrawPrimitiveUP(D3DPT_LINELIST, 12, v, sizeof(S3DVertex)); +} + +bool CD3D9Driver::retrieveDevice(int numTries, int msSleepBetweenTries) +{ + while ( numTries > 0) + { + HRESULT hr; + if ( FAILED(hr = pID3DDevice->TestCooperativeLevel()) ) + { + // hr can be: D3DERR_DEVICELOST, D3DERR_DEVICENOTRESET or D3DERR_DRIVERINTERNALERROR + switch ( hr ) + { + case D3DERR_DEVICENOTRESET: + if ( reset() ) + return true; + // when reset fails, just try again, maybe device got lost in between TestCooperativeLevel and reset calls? + break; + case D3DERR_DEVICELOST: + break; + case D3DERR_DRIVERINTERNALERROR: + return false; + } + + Sleep(msSleepBetweenTries); + --numTries; + } + else + return true; + } + return false; +} + +//! resets the device +bool CD3D9Driver::reset() +{ + os::Printer::log("Resetting D3D9 device.", ELL_INFORMATION); + + for (u32 i = 0; igetDriverType() == EDT_DIRECT3D9) + { + static_cast(RenderTargets[i])->releaseSurfaces(); + + const core::array texArray = RenderTargets[i]->getTexture(); + + for (u32 j = 0; j < texArray.size(); ++j) + { + CD3D9Texture* tex = static_cast(texArray[j]); + + if (tex) + tex->releaseTexture(); + } + + CD3D9Texture* tex = static_cast(RenderTargets[i]->getDepthStencil()); + + if (tex) + tex->releaseTexture(); + } + } + for (u32 i=0; iisRenderTarget()) + { + CD3D9Texture* tex = static_cast(Textures[i].Surface); + + if (tex) + tex->releaseTexture(); + } + } + for (u32 i=0; i(OcclusionQueries[i].PID)->Release(); + OcclusionQueries[i].PID=0; + } + } + // this does not require a restore in the reset method, it's updated + // automatically in the next render cycle. + removeAllHardwareBuffers(); + + // reset render target usage information. + for (u32 i = 0; i < ActiveRenderTarget.size(); ++i) + ActiveRenderTarget[i] = false; + + if (DepthStencilSurface) + { + DepthStencilSurface->Release(); + DepthStencilSurface = 0; + } + + if (BackBufferSurface) + { + BackBufferSurface->Release(); + BackBufferSurface = 0; + } + + DriverWasReset=true; + + HRESULT hr = pID3DDevice->Reset(&present); + if (FAILED(hr)) + { + if (hr == D3DERR_DEVICELOST) + { + DeviceLost = true; + os::Printer::log("Resetting failed due to device lost.", ELL_WARNING); + } +#ifdef D3DERR_DEVICEREMOVED + else if (hr == D3DERR_DEVICEREMOVED) + { + os::Printer::log("Resetting failed due to device removed.", ELL_WARNING); + } +#endif + else if (hr == D3DERR_DRIVERINTERNALERROR) + { + os::Printer::log("Resetting failed due to internal error.", ELL_WARNING); + } + else if (hr == D3DERR_OUTOFVIDEOMEMORY) + { + os::Printer::log("Resetting failed due to out of memory.", ELL_WARNING); + } + else if (hr == D3DERR_DEVICENOTRESET) + { + os::Printer::log("Resetting failed due to not reset.", ELL_WARNING); + } + else if (hr == D3DERR_INVALIDCALL) + { + os::Printer::log("Resetting failed due to invalid call", "You need to release some more surfaces.", ELL_WARNING); + } + else + { + os::Printer::log("Resetting failed due to unknown reason.", core::stringc((int)hr).c_str(), ELL_WARNING); + } + return false; + } + DeviceLost = false; + + // reset bridge calls. + if (BridgeCalls) + BridgeCalls->reset(); + + // restore screen depthbuffer descriptor + if (!SUCCEEDED(pID3DDevice->GetDepthStencilSurface(&DepthStencilSurface))) + { + os::Printer::log("Was not able to get main depth buffer.", ELL_ERROR); + return false; + } + + // restore RTTs + for (u32 i=0; iisRenderTarget()) + ((CD3D9Texture*)(Textures[i].Surface))->generateRenderTarget(); + } + for (u32 i = 0; igetDriverType() == EDT_DIRECT3D9) + { + const core::array texArray = RenderTargets[i]->getTexture(); + + for (u32 j = 0; j < texArray.size(); ++j) + { + CD3D9Texture* tex = static_cast(texArray[j]); + + if (tex) + tex->generateRenderTarget(); + } + + CD3D9Texture* tex = static_cast(RenderTargets[i]->getDepthStencil()); + + if (tex) + tex->generateRenderTarget(); + + static_cast(RenderTargets[i])->generateSurfaces(); + } + } + + // restore occlusion queries + for (u32 i=0; iCreateQuery(D3DQUERYTYPE_OCCLUSION, reinterpret_cast(&OcclusionQueries[i].PID)); + } + + ResetRenderStates = true; + LastVertexType = (E_VERTEX_TYPE)-1; + + for (u32 i=0; i& size) +{ + if (!pID3DDevice) + return; + + CNullDriver::OnResize(size); + present.BackBufferWidth = size.Width; + present.BackBufferHeight = size.Height; + + if ( !reset() ) + { + if ( !retrieveDevice(20, 200) ) // retrying for 3 seconds, I hope that's long enough? + { + os::Printer::log("Failed to retrieve device in OnResize.", ELL_ERROR); + } + } +} + + +//! Returns type of video driver +E_DRIVER_TYPE CD3D9Driver::getDriverType() const +{ + return EDT_DIRECT3D9; +} + + +//! Returns the transformation set by setTransform +const core::matrix4& CD3D9Driver::getTransform(E_TRANSFORMATION_STATE state) const +{ + return Matrices[state]; +} + + +//! Get a vertex shader constant index. +s32 CD3D9Driver::getVertexShaderConstantID(const c8* name) +{ + if (Material.MaterialType >= 0 && Material.MaterialType < (s32)MaterialRenderers.size()) + { + CD3D9MaterialRenderer* r = (CD3D9MaterialRenderer*)MaterialRenderers[Material.MaterialType].Renderer; + return r->getVariableID(true, name); + } + + return -1; +} + +//! Get a pixel shader constant index. +s32 CD3D9Driver::getPixelShaderConstantID(const c8* name) +{ + if (Material.MaterialType >= 0 && Material.MaterialType < (s32)MaterialRenderers.size()) + { + CD3D9MaterialRenderer* r = (CD3D9MaterialRenderer*)MaterialRenderers[Material.MaterialType].Renderer; + return r->getVariableID(false, name); + } + + return -1; +} + + +//! Sets a vertex shader constant. +void CD3D9Driver::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount) +{ + if (data) + pID3DDevice->SetVertexShaderConstantF(startRegister, data, constantAmount); +} + + +//! Sets a pixel shader constant. +void CD3D9Driver::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount) +{ + if (data) + pID3DDevice->SetPixelShaderConstantF(startRegister, data, constantAmount); +} + + +//! Sets a constant for the vertex shader based on an index. +bool CD3D9Driver::setVertexShaderConstant(s32 index, const f32* floats, int count) +{ + if (Material.MaterialType >= 0 && Material.MaterialType < (s32)MaterialRenderers.size()) + { + CD3D9MaterialRenderer* r = (CD3D9MaterialRenderer*)MaterialRenderers[Material.MaterialType].Renderer; + return r->setVariable(true, index, floats, count); + } + + return false; +} + + +//! Int interface for the above. +bool CD3D9Driver::setVertexShaderConstant(s32 index, const s32* ints, int count) +{ + if (Material.MaterialType >= 0 && Material.MaterialType < (s32)MaterialRenderers.size()) + { + CD3D9MaterialRenderer* r = (CD3D9MaterialRenderer*)MaterialRenderers[Material.MaterialType].Renderer; + return r->setVariable(true, index, ints, count); + } + + return false; +} + + +//! Sets a constant for the pixel shader based on an index. +bool CD3D9Driver::setPixelShaderConstant(s32 index, const f32* floats, int count) +{ + if (Material.MaterialType >= 0 && Material.MaterialType < (s32)MaterialRenderers.size()) + { + CD3D9MaterialRenderer* r = (CD3D9MaterialRenderer*)MaterialRenderers[Material.MaterialType].Renderer; + return r->setVariable(false, index, floats, count); + } + + return false; +} + + +//! Int interface for the above. +bool CD3D9Driver::setPixelShaderConstant(s32 index, const s32* ints, int count) +{ + if (Material.MaterialType >= 0 && Material.MaterialType < (s32)MaterialRenderers.size()) + { + CD3D9MaterialRenderer* r = (CD3D9MaterialRenderer*)MaterialRenderers[Material.MaterialType].Renderer; + return r->setVariable(false, index, ints, count); + } + + return false; +} + + +//! Adds a new material renderer to the VideoDriver, using pixel and/or +//! vertex shaders to render geometry. +s32 CD3D9Driver::addShaderMaterial(const c8* vertexShaderProgram, + const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, s32 userData) +{ + s32 nr = -1; + CD3D9ShaderMaterialRenderer* r = new CD3D9ShaderMaterialRenderer( + pID3DDevice, this, nr, vertexShaderProgram, pixelShaderProgram, + callback, getMaterialRenderer(baseMaterial), userData); + + r->drop(); + return nr; +} + + +//! Adds a new material renderer to the VideoDriver, based on a high level shading +//! language. +s32 CD3D9Driver::addHighLevelShaderMaterial( + const c8* vertexShaderProgram, + const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, + const c8* pixelShaderProgram, + const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, + const c8* geometryShaderProgram, + const c8* geometryShaderEntryPointName, + E_GEOMETRY_SHADER_TYPE gsCompileTarget, + scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType, + u32 verticesOut, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, s32 userData) +{ + s32 nr = -1; + + CD3D9HLSLMaterialRenderer* r = new CD3D9HLSLMaterialRenderer( + pID3DDevice, this, nr, + vertexShaderProgram, + vertexShaderEntryPointName, + vsCompileTarget, + pixelShaderProgram, + pixelShaderEntryPointName, + psCompileTarget, + callback, + getMaterialRenderer(baseMaterial), + userData); + + r->drop(); + + return nr; +} + + +//! Returns a pointer to the IVideoDriver interface. (Implementation for +//! IMaterialRendererServices) +IVideoDriver* CD3D9Driver::getVideoDriver() +{ + return this; +} + + +//! Creates a render target texture. +ITexture* CD3D9Driver::addRenderTargetTexture(const core::dimension2d& size, + const io::path& name, + const ECOLOR_FORMAT format) +{ + CD3D9Texture* tex = new CD3D9Texture(this, size, name, ETT_2D, format); + if (tex) + { + if (!tex->Texture) + { + tex->drop(); + return 0; + } + + addTexture(tex); + tex->drop(); + } + return tex; +} + +ITexture* CD3D9Driver::addRenderTargetTextureCubemap(const irr::u32 sideLen, + const io::path& name, const ECOLOR_FORMAT format) +{ + CD3D9Texture* tex = new CD3D9Texture(this, core::dimension2d(sideLen, sideLen), name, ETT_CUBEMAP, format); + if (tex) + { + if (!tex->CubeTexture) + { + tex->drop(); + return 0; + } + + addTexture(tex); + tex->drop(); + } + return tex; +} + +void CD3D9Driver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil) +{ + DWORD internalFlag = 0; + + if (flag & ECBF_COLOR) + internalFlag |= D3DCLEAR_TARGET; + + if (flag & ECBF_DEPTH) + internalFlag |= D3DCLEAR_ZBUFFER; + + if (flag & ECBF_STENCIL) + internalFlag |= D3DCLEAR_STENCIL; + + if (internalFlag) + { + HRESULT hr = pID3DDevice->Clear(0, NULL, internalFlag, color.color, depth, stencil); + + if (FAILED(hr)) + os::Printer::log("DIRECT3D9 clear failed.", ELL_WARNING); + } +} + + +//! Returns an image created from the last rendered frame. +IImage* CD3D9Driver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target) +{ + if (target != video::ERT_FRAME_BUFFER) + return 0; + + if (format==video::ECF_UNKNOWN) + format=getColorFormat(); + + // TODO: Maybe we could support more formats (floating point and some of those beyond ECF_R8), didn't really try yet + if (IImage::isCompressedFormat(format) || IImage::isDepthFormat(format) || IImage::isFloatingPointFormat(format) || format >= ECF_R8) + return 0; + + // query the screen dimensions of the current adapter + D3DDISPLAYMODE displayMode; + pID3DDevice->GetDisplayMode(0, &displayMode); + + // create the image surface to store the front buffer image [always A8R8G8B8] + HRESULT hr; + LPDIRECT3DSURFACE9 lpSurface; + if (FAILED(hr = pID3DDevice->CreateOffscreenPlainSurface(displayMode.Width, displayMode.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &lpSurface, 0))) + return 0; + + // read the front buffer into the image surface + if (FAILED(hr = pID3DDevice->GetFrontBufferData(0, lpSurface))) + { + lpSurface->Release(); + return 0; + } + + RECT clientRect; + { + POINT clientPoint; + clientPoint.x = 0; + clientPoint.y = 0; + + ClientToScreen((HWND)getExposedVideoData().D3D9.HWnd, &clientPoint); + + clientRect.left = clientPoint.x; + clientRect.top = clientPoint.y; + clientRect.right = clientRect.left + ScreenSize.Width; + clientRect.bottom = clientRect.top + ScreenSize.Height; + + // window can be off-screen partly, we can't take screenshots from that + clientRect.left = core::max_(clientRect.left, 0l); + clientRect.top = core::max_(clientRect.top, 0l); + clientRect.right = core::min_(clientRect.right, (long)displayMode.Width); + clientRect.bottom = core::min_(clientRect.bottom, (long)displayMode.Height ); + } + + // lock our area of the surface + D3DLOCKED_RECT lockedRect; + if (FAILED(lpSurface->LockRect(&lockedRect, &clientRect, D3DLOCK_READONLY))) + { + lpSurface->Release(); + return 0; + } + + irr::core::dimension2d shotSize; + shotSize.Width = core::min_( ScreenSize.Width, (u32)(clientRect.right-clientRect.left) ); + shotSize.Height = core::min_( ScreenSize.Height, (u32)(clientRect.bottom-clientRect.top) ); + + // this could throw, but we aren't going to worry about that case very much + IImage* newImage = createImage(format, shotSize); + + if (newImage) + { + // d3d pads the image, so we need to copy the correct number of bytes + u32* dP = (u32*)newImage->lock(); + 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 + // set each pixel alpha value to 255. + if (D3DFMT_X8R8G8B8 == displayMode.Format && (0xFF000000 != (*dP & 0xFF000000))) + { + for (u32 y = 0; y < shotSize.Height; ++y) + { + for (u32 x = 0; x < shotSize.Width; ++x) + { + newImage->setPixel(x,y,*((u32*)sP) | 0xFF000000); + sP += 4; + } + + sP += lockedRect.Pitch - (4 * shotSize.Width); + } + } + else + { + for (u32 y = 0; y < shotSize.Height; ++y) + { + convertColor(sP, video::ECF_A8R8G8B8, shotSize.Width, dP, format); + sP += lockedRect.Pitch; + dP += shotSize.Width; + } + } + + newImage->unlock(); + } + + // we can unlock and release the surface + lpSurface->UnlockRect(); + + // release the image surface + lpSurface->Release(); + + // return status of save operation to caller + return newImage; +} + + +//! returns color format +ECOLOR_FORMAT CD3D9Driver::getColorFormat() const +{ + return ColorFormat; +} + + +//! returns color format +D3DFORMAT CD3D9Driver::getD3DColorFormat() const +{ + return D3DColorFormat; +} + + +// Set/unset a clipping plane. +bool CD3D9Driver::setClipPlane(u32 index, const core::plane3df& plane, bool enable) +{ + if (index >= MaxUserClipPlanes) + return false; + + HRESULT ok = pID3DDevice->SetClipPlane(index, (const float*)&(plane.Normal.X)); + if (D3D_OK == ok) + enableClipPlane(index, enable); + return true; +} + + +// Enable/disable a clipping plane. +void CD3D9Driver::enableClipPlane(u32 index, bool enable) +{ + if (index >= MaxUserClipPlanes) + return; + DWORD renderstate; + HRESULT ok = pID3DDevice->GetRenderState(D3DRS_CLIPPLANEENABLE, &renderstate); + if (S_OK == ok) + { + if (enable) + renderstate |= (1 << index); + else + renderstate &= ~(1 << index); + ok = pID3DDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, renderstate); + } +} + + +D3DFORMAT CD3D9Driver::getD3DFormatFromColorFormat(ECOLOR_FORMAT format) const +{ + switch(format) + { + case ECF_A1R5G5B5: + return D3DFMT_A1R5G5B5; + case ECF_R5G6B5: + return D3DFMT_R5G6B5; + case ECF_R8G8B8: + return D3DFMT_R8G8B8; + case ECF_A8R8G8B8: + return D3DFMT_A8R8G8B8; + + case ECF_DXT1: + return D3DFMT_DXT1; + case ECF_DXT2: + return D3DFMT_DXT2; + case ECF_DXT3: + return D3DFMT_DXT3; + case ECF_DXT4: + return D3DFMT_DXT4; + case ECF_DXT5: + return D3DFMT_DXT5; + case ECF_R16F: + return D3DFMT_R16F; + case ECF_G16R16F: + return D3DFMT_G16R16F; + case ECF_A16B16G16R16F: + return D3DFMT_A16B16G16R16F; + case ECF_R32F: + return D3DFMT_R32F; + case ECF_G32R32F: + return D3DFMT_G32R32F; + case ECF_A32B32G32R32F: + return D3DFMT_A32B32G32R32F; + + case ECF_R8: + return D3DFMT_A8; // not correct, but somewhat similar + case ECF_R8G8: + return D3DFMT_A8L8; // not correct, but somewhat similar + case ECF_R16: + return D3DFMT_L16; // not correct, but somewhat similar + case ECF_R16G16: + return D3DFMT_G16R16; // flipped :-( + + case ECF_D16: + return D3DFMT_D16; + case ECF_D24S8: + return D3DFMT_D24S8; + case ECF_D32: + return D3DFMT_D32; + } + return D3DFMT_UNKNOWN; +} + + +ECOLOR_FORMAT CD3D9Driver::getColorFormatFromD3DFormat(D3DFORMAT format) const +{ + switch(format) + { + case D3DFMT_X1R5G5B5: + case D3DFMT_A1R5G5B5: + return ECF_A1R5G5B5; + case D3DFMT_A8B8G8R8: + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + return ECF_A8R8G8B8; + case D3DFMT_R5G6B5: + return ECF_R5G6B5; + case D3DFMT_R8G8B8: + return ECF_R8G8B8; + + // Floating Point formats. Thanks to Patryk "Nadro" Nadrowski. + case D3DFMT_R16F: + return ECF_R16F; + case D3DFMT_G16R16F: + return ECF_G16R16F; + case D3DFMT_A16B16G16R16F: + return ECF_A16B16G16R16F; + case D3DFMT_R32F: + return ECF_R32F; + case D3DFMT_G32R32F: + return ECF_G32R32F; + case D3DFMT_A32B32G32R32F: + return ECF_A32B32G32R32F; + default: + return (ECOLOR_FORMAT)0; + }; +} + + +core::dimension2du CD3D9Driver::getMaxTextureSize() const +{ + return core::dimension2du(Caps.MaxTextureWidth, Caps.MaxTextureHeight); +} + +bool CD3D9Driver::queryTextureFormat(ECOLOR_FORMAT format) const +{ + return getD3DFormatFromColorFormat(format) != D3DFMT_UNKNOWN; +} + +bool CD3D9Driver::needsTransparentRenderPass(const irr::video::SMaterial& material) const +{ + return CNullDriver::needsTransparentRenderPass(material) || material.isAlphaBlendOperation(); +} + +u32 CD3D9Driver::getD3DBlend(E_BLEND_FACTOR factor) const +{ + u32 r = 0; + switch (factor) + { + case EBF_ZERO: r = D3DBLEND_ZERO; break; + case EBF_ONE: r = D3DBLEND_ONE; break; + case EBF_DST_COLOR: r = D3DBLEND_DESTCOLOR; break; + case EBF_ONE_MINUS_DST_COLOR: r = D3DBLEND_INVDESTCOLOR; break; + case EBF_SRC_COLOR: r = D3DBLEND_SRCCOLOR; break; + case EBF_ONE_MINUS_SRC_COLOR: r = D3DBLEND_INVSRCCOLOR; break; + case EBF_SRC_ALPHA: r = D3DBLEND_SRCALPHA; break; + case EBF_ONE_MINUS_SRC_ALPHA: r = D3DBLEND_INVSRCALPHA; break; + case EBF_DST_ALPHA: r = D3DBLEND_DESTALPHA; break; + case EBF_ONE_MINUS_DST_ALPHA: r = D3DBLEND_INVDESTALPHA; break; + case EBF_SRC_ALPHA_SATURATE: r = D3DBLEND_SRCALPHASAT; break; + } + return r; +} + + +u32 CD3D9Driver::getD3DModulate(E_MODULATE_FUNC func) const +{ + u32 r = D3DTOP_MODULATE; + switch (func) + { + case EMFN_MODULATE_1X: r = D3DTOP_MODULATE; break; + case EMFN_MODULATE_2X: r = D3DTOP_MODULATE2X; break; + case EMFN_MODULATE_4X: r = D3DTOP_MODULATE4X; break; + } + return r; +} + + +CD3D9CallBridge* CD3D9Driver::getBridgeCalls() const +{ + return BridgeCalls; +} + +CD3D9CallBridge::CD3D9CallBridge(IDirect3DDevice9* p, CD3D9Driver* driver) : pID3DDevice(p), + BlendOperation(D3DBLENDOP_ADD), BlendSourceRGB(D3DBLEND_ONE), BlendDestinationRGB(D3DBLEND_ZERO), + BlendSourceAlpha(D3DBLEND_ONE), BlendDestinationAlpha(D3DBLEND_ZERO), Blend(false), BlendSeparate(false), + FeatureBlendSeparate(false) +{ + FeatureBlendSeparate = driver->queryFeature(EVDF_BLEND_SEPARATE); + + reset(); +} + +void CD3D9CallBridge::reset() +{ + BlendOperation = D3DBLENDOP_ADD; + + BlendSourceRGB = D3DBLEND_ONE; + BlendDestinationRGB = D3DBLEND_ZERO; + BlendSourceAlpha = D3DBLEND_ONE; + BlendDestinationAlpha = D3DBLEND_ZERO; + + Blend = false; + BlendSeparate = false; + + pID3DDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + pID3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); + pID3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO); + pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + + if (FeatureBlendSeparate) + { + pID3DDevice->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); + pID3DDevice->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO); + pID3DDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE); + } +} + +void CD3D9CallBridge::setBlendOperation(DWORD mode) +{ + if (BlendOperation != mode) + { + pID3DDevice->SetRenderState(D3DRS_BLENDOP, mode); + + BlendOperation = mode; + } +} + +void CD3D9CallBridge::setBlendFunc(DWORD source, DWORD destination) +{ + if (BlendSourceRGB != source) + { + pID3DDevice->SetRenderState(D3DRS_SRCBLEND, source); + + BlendSourceRGB = source; + } + + if (BlendDestinationRGB != destination) + { + pID3DDevice->SetRenderState(D3DRS_DESTBLEND, destination); + + BlendDestinationRGB = destination; + } + + if (FeatureBlendSeparate && BlendSeparate) + { + pID3DDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE); + + BlendSeparate = false; + } +} + +void CD3D9CallBridge::setBlendFuncSeparate(DWORD sourceRGB, DWORD destinationRGB, DWORD sourceAlpha, DWORD destinationAlpha) +{ + if (BlendSourceRGB != sourceRGB) + { + pID3DDevice->SetRenderState(D3DRS_SRCBLEND, sourceRGB); + + BlendSourceRGB = sourceRGB; + } + + if (BlendDestinationRGB != destinationRGB) + { + pID3DDevice->SetRenderState(D3DRS_DESTBLEND, destinationRGB); + + BlendDestinationRGB = destinationRGB; + } + + if (FeatureBlendSeparate) + { + if (sourceRGB != sourceAlpha || destinationRGB != destinationAlpha) + { + if (BlendSourceAlpha != sourceAlpha) + { + pID3DDevice->SetRenderState(D3DRS_SRCBLENDALPHA, sourceAlpha); + + BlendSourceAlpha = sourceAlpha; + } + + if (BlendDestinationAlpha != destinationAlpha) + { + pID3DDevice->SetRenderState(D3DRS_DESTBLENDALPHA, destinationAlpha); + + BlendDestinationAlpha = destinationAlpha; + } + + if (!BlendSeparate) + { + pID3DDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + + BlendSeparate = true; + } + } + else if (BlendSeparate) + { + pID3DDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE); + + BlendSeparate = false; + } + } +} + +void CD3D9CallBridge::setBlend(bool enable) +{ + if (Blend != enable) + { + if (enable) + pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + else + pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + + Blend = enable; + } +} + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_DIRECT3D_9_ + + + +namespace irr +{ +namespace video +{ + +#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ +//! creates a video driver +IVideoDriver* createDirectX9Driver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io, HWND window) +{ + const bool pureSoftware = false; + CD3D9Driver* dx9 = new CD3D9Driver(params, io); + if (!dx9->initDriver(window, pureSoftware)) + { + dx9->drop(); + dx9 = 0; + } + + return dx9; +} +#endif // _IRR_COMPILE_WITH_DIRECT3D_9_ + +} // end namespace video +} // end namespace irr + diff --git a/source/Irrlicht/CD3D9Driver.h b/source/Irrlicht/CD3D9Driver.h new file mode 100644 index 00000000..e4d7925d --- /dev/null +++ b/source/Irrlicht/CD3D9Driver.h @@ -0,0 +1,507 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_VIDEO_DIRECTX_9_H_INCLUDED__ +#define __C_VIDEO_DIRECTX_9_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ + +#ifdef _IRR_WINDOWS_ +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include "CNullDriver.h" +#include "SIrrCreationParameters.h" +#include "IMaterialRendererServices.h" +#if defined(__BORLANDC__) || defined (__BCPLUSPLUS__) +#include "irrMath.h" // needed by borland for sqrtf define +#endif +#include + +namespace irr +{ +namespace video +{ + class CD3D9CallBridge; + class CD3D9RenderTarget; + class CD3D9Texture; + + class CD3D9Driver : public CNullDriver, IMaterialRendererServices + { + public: + + friend class CD3D9CallBridge; + friend class CD3D9RenderTarget; + friend class CD3D9Texture; + + //! constructor + CD3D9Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io); + + //! destructor + virtual ~CD3D9Driver(); + + virtual bool beginScene(u16 clearFlag, SColor clearColor = SColor(255,0,0,0), f32 clearDepth = 1.f, u8 clearStencil = 0, + const SExposedVideoData& videoData = SExposedVideoData(), core::rect* sourceRect = 0) _IRR_OVERRIDE_; + + virtual bool endScene() _IRR_OVERRIDE_; + + //! queries the features of the driver, returns true if feature is available + virtual bool queryFeature(E_VIDEO_DRIVER_FEATURE feature) const _IRR_OVERRIDE_; + + //! sets transformation + virtual void setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) _IRR_OVERRIDE_; + + //! sets a material + virtual void setMaterial(const SMaterial& material) _IRR_OVERRIDE_; + + virtual bool setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor = SColor(255,0,0,0), + f32 clearDepth = 1.f, u8 clearStencil = 0) _IRR_OVERRIDE_; + + //! sets a viewport + virtual void setViewPort(const core::rect& area) _IRR_OVERRIDE_; + + //! gets the area of the current viewport + virtual const core::rect& getViewPort() const _IRR_OVERRIDE_; + + struct SHWBufferLink_d3d9 : public SHWBufferLink + { + SHWBufferLink_d3d9(const scene::IMeshBuffer *_MeshBuffer): + SHWBufferLink(_MeshBuffer), + vertexBuffer(0), indexBuffer(0), + vertexBufferSize(0), indexBufferSize(0) {} + + IDirect3DVertexBuffer9* vertexBuffer; + IDirect3DIndexBuffer9* indexBuffer; + + u32 vertexBufferSize; + u32 indexBufferSize; + }; + + bool updateVertexHardwareBuffer(SHWBufferLink_d3d9 *HWBuffer); + bool updateIndexHardwareBuffer(SHWBufferLink_d3d9 *HWBuffer); + + //! updates hardware buffer if needed + virtual bool updateHardwareBuffer(SHWBufferLink *HWBuffer) _IRR_OVERRIDE_; + + //! Create hardware buffer from mesh + virtual SHWBufferLink *createHardwareBuffer(const scene::IMeshBuffer* mb) _IRR_OVERRIDE_; + + //! Delete hardware buffer (only some drivers can) + virtual void deleteHardwareBuffer(SHWBufferLink *HWBuffer) _IRR_OVERRIDE_; + + //! Draw hardware buffer + virtual void drawHardwareBuffer(SHWBufferLink *HWBuffer) _IRR_OVERRIDE_; + + //! Create occlusion query. + /** Use node for identification and mesh for occlusion test. */ + virtual void addOcclusionQuery(scene::ISceneNode* node, + const scene::IMesh* mesh=0) _IRR_OVERRIDE_; + + //! Remove occlusion query. + virtual void removeOcclusionQuery(scene::ISceneNode* node) _IRR_OVERRIDE_; + + //! Run occlusion query. Draws mesh stored in query. + /** If the mesh shall not be rendered visible, use + overrideMaterial to disable the color and depth buffer. */ + virtual void runOcclusionQuery(scene::ISceneNode* node, bool visible=false) _IRR_OVERRIDE_; + + //! Update occlusion query. Retrieves results from GPU. + /** If the query shall not block, set the flag to false. + Update might not occur in this case, though */ + virtual void updateOcclusionQuery(scene::ISceneNode* node, bool block=true) _IRR_OVERRIDE_; + + //! Return query result. + /** Return value is the number of visible pixels/fragments. + The value is a safe approximation, i.e. can be larger then the + actual value of pixels. */ + virtual u32 getOcclusionQueryResult(scene::ISceneNode* node) const _IRR_OVERRIDE_; + + //! Create render target. + virtual IRenderTarget* addRenderTarget() _IRR_OVERRIDE_; + + //! draws a vertex primitive list + virtual void drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, + E_INDEX_TYPE iType) _IRR_OVERRIDE_; + + //! draws a vertex primitive list in 2d + virtual void draw2DVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, + E_INDEX_TYPE iType) _IRR_OVERRIDE_; + + //! 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. + 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) _IRR_OVERRIDE_; + + //! Draws a part of the texture into the rectangle. + 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) _IRR_OVERRIDE_; + + //! Draws a set of 2d images, using a color and the alpha channel of the texture. + virtual void draw2DImageBatch(const video::ITexture* texture, + const core::array >& positions, + const core::array >& sourceRects, + const core::rect* clipRect=0, + SColor color=SColor(255,255,255,255), + bool useAlphaChannelOfTexture=false) _IRR_OVERRIDE_; + + //!Draws an 2d rectangle with a gradient. + virtual void draw2DRectangle(const core::rect& pos, + SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, + const core::rect* clip) _IRR_OVERRIDE_; + + //! Draws a 2d line. + virtual void draw2DLine(const core::position2d& start, + const core::position2d& end, + SColor color=SColor(255,255,255,255)) _IRR_OVERRIDE_; + + //! Draws a pixel. + virtual void drawPixel(u32 x, u32 y, const SColor & color) _IRR_OVERRIDE_; + + //! Draws a 3d line. + virtual void draw3DLine(const core::vector3df& start, + const core::vector3df& end, SColor color = SColor(255,255,255,255)) _IRR_OVERRIDE_; + + //! Draws a 3d box. + virtual void draw3DBox( const core::aabbox3d& box, SColor color = SColor(255,255,255,255 ) ) _IRR_OVERRIDE_; + + //! initialises the Direct3D API + bool initDriver(HWND hwnd, bool pureSoftware); + + //! \return Returns the name of the video driver. Example: In case of the DIRECT3D8 + //! driver, it would return "Direct3D8.1". + virtual const wchar_t* getName() const _IRR_OVERRIDE_; + + //! deletes all dynamic lights there are + virtual void deleteAllDynamicLights() _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! returns the maximal amount of dynamic lights the device can handle + virtual u32 getMaximalDynamicLightAmount() const _IRR_OVERRIDE_; + + //! 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. + virtual void setAmbientLight(const SColorf& color) _IRR_OVERRIDE_; + + //! Draws a shadow volume into the stencil buffer. + virtual void drawStencilShadowVolume(const core::array& triangles, bool zfail=true, u32 debugDataVisible=0) _IRR_OVERRIDE_; + + //! Fills the stencil shadow with color. + virtual void drawStencilShadow(bool clearStencilBuffer=false, + video::SColor leftUpEdge = video::SColor(0,0,0,0), + video::SColor rightUpEdge = video::SColor(0,0,0,0), + video::SColor leftDownEdge = video::SColor(0,0,0,0), + video::SColor rightDownEdge = video::SColor(0,0,0,0)) _IRR_OVERRIDE_; + + //! Returns the maximum amount of primitives (mostly vertices) which + //! the device is able to render with one drawIndexedTriangleList + //! call. + virtual u32 getMaximalPrimitiveCount() const _IRR_OVERRIDE_; + + //! Sets the fog mode. + virtual void setFog(SColor color, E_FOG_TYPE fogType, f32 start, + f32 end, f32 density, bool pixelFog, bool rangeFog) _IRR_OVERRIDE_; + + //! Only used by the internal engine. Used to notify the driver that + //! the window was resized. + virtual void OnResize(const core::dimension2d& size) _IRR_OVERRIDE_; + + //! Can be called by an IMaterialRenderer to make its work easier. + virtual void setBasicRenderStates(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates) _IRR_OVERRIDE_; + + //! Returns type of video driver + virtual E_DRIVER_TYPE getDriverType() const _IRR_OVERRIDE_; + + //! Returns the transformation set by setTransform + virtual const core::matrix4& getTransform(E_TRANSFORMATION_STATE state) const _IRR_OVERRIDE_; + + //! Get a vertex shader constant index. + virtual s32 getVertexShaderConstantID(const c8* name) _IRR_OVERRIDE_; + + //! Get a pixel shader constant index. + virtual s32 getPixelShaderConstantID(const c8* name) _IRR_OVERRIDE_; + + //! Sets a vertex shader constant. + virtual void setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1) _IRR_OVERRIDE_; + + //! Sets a pixel shader constant. + virtual void setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1) _IRR_OVERRIDE_; + + //! Sets a constant for the vertex shader based on an index. + virtual bool setVertexShaderConstant(s32 index, const f32* floats, int count) _IRR_OVERRIDE_; + + //! Int interface for the above. + virtual bool setVertexShaderConstant(s32 index, const s32* ints, int count) _IRR_OVERRIDE_; + + //! Sets a constant for the pixel shader based on an index. + virtual bool setPixelShaderConstant(s32 index, const f32* floats, int count) _IRR_OVERRIDE_; + + //! Int interface for the above. + virtual bool setPixelShaderConstant(s32 index, const s32* ints, int count) _IRR_OVERRIDE_; + + //! Returns a pointer to the IVideoDriver interface. (Implementation for + //! IMaterialRendererServices) + virtual IVideoDriver* getVideoDriver() _IRR_OVERRIDE_; + + //! Creates a render target texture. + virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, + const io::path& name, const ECOLOR_FORMAT format = ECF_UNKNOWN) _IRR_OVERRIDE_; + + //! Creates a render target texture for a cubemap + ITexture* addRenderTargetTextureCubemap(const irr::u32 sideLen, + const io::path& name, const ECOLOR_FORMAT format) _IRR_OVERRIDE_; + + virtual void clearBuffers(u16 flag, SColor color = SColor(255,0,0,0), f32 depth = 1.f, u8 stencil = 0) _IRR_OVERRIDE_; + + //! Returns an image created from the last rendered frame. + virtual IImage* createScreenShot(video::ECOLOR_FORMAT format=video::ECF_UNKNOWN, video::E_RENDER_TARGET target=video::ERT_FRAME_BUFFER) _IRR_OVERRIDE_; + + //! Set/unset a clipping plane. + virtual bool setClipPlane(u32 index, const core::plane3df& plane, bool enable=false) _IRR_OVERRIDE_; + + //! Enable/disable a clipping plane. + virtual void enableClipPlane(u32 index, bool enable) _IRR_OVERRIDE_; + + //! Returns the graphics card vendor name. + virtual core::stringc getVendorInfo() _IRR_OVERRIDE_ {return VendorName;} + + //! Enable the 2d override material + virtual void enableMaterial2D(bool enable=true) _IRR_OVERRIDE_; + + //! Check if the driver was recently reset. + virtual bool checkDriverReset() _IRR_OVERRIDE_ {return DriverWasReset;} + + //! Get the current color format of the color buffer + /** \return Color format of the color buffer. */ + virtual ECOLOR_FORMAT getColorFormat() const _IRR_OVERRIDE_; + + //! Returns the maximum texture size supported. + virtual core::dimension2du getMaxTextureSize() const _IRR_OVERRIDE_; + + //! Check if the driver supports creating textures with the given color format + virtual bool queryTextureFormat(ECOLOR_FORMAT format) const _IRR_OVERRIDE_; + + //! Used by some SceneNodes to check if a material should be rendered in the transparent render pass + virtual bool needsTransparentRenderPass(const irr::video::SMaterial& material) const _IRR_OVERRIDE_; + + //! Get the current color format of the color buffer + /** \return Color format of the color buffer as D3D color value. */ + D3DFORMAT getD3DColorFormat() const; + + //! Get D3D color format from Irrlicht color format. + D3DFORMAT getD3DFormatFromColorFormat(ECOLOR_FORMAT format) const; + + //! Get Irrlicht color format from D3D color format. + ECOLOR_FORMAT getColorFormatFromD3DFormat(D3DFORMAT format) const; + + //! Get D3D blending factor. + u32 getD3DBlend(E_BLEND_FACTOR factor) const; + + //! Get D3D modulate. + u32 getD3DModulate(E_MODULATE_FUNC func) const; + + //! Get bridge calls. + CD3D9CallBridge* getBridgeCalls() const; + + private: + + //! enumeration for rendering modes such as 2d and 3d for minimizing the switching of renderStates. + enum E_RENDER_MODE + { + ERM_NONE = 0, // no render state has been set yet. + ERM_2D, // 2d drawing rendermode + ERM_3D, // 3d rendering mode + ERM_STENCIL_FILL, // stencil fill mode + ERM_SHADOW_VOLUME_ZFAIL, // stencil volume draw mode + ERM_SHADOW_VOLUME_ZPASS // stencil volume draw mode + }; + + //! sets right vertex shader + void setVertexShader(video::E_VERTEX_TYPE newType); + + //! sets the needed renderstates + bool setRenderStates3DMode(); + + //! sets the needed renderstates + void setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel); + + //! sets the needed renderstates + void setRenderStatesStencilFillMode(bool alpha); + + //! sets the needed renderstates + void setRenderStatesStencilShadowMode(bool zfail, u32 debugDataVisible); + + //! sets the current Texture + bool setActiveTexture(u32 stage, const video::ITexture* texture); + + //! resets the device + bool reset(); + + //! Try to get back a lost device + bool retrieveDevice(int numTries, int msSleepBetweenTries=100); + + virtual ITexture* createDeviceDependentTexture(const io::path& name, IImage* image) _IRR_OVERRIDE_; + + virtual ITexture* createDeviceDependentTextureCubemap(const io::path& name, const core::array& image) _IRR_OVERRIDE_; + + //! 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, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, s32 userData) _IRR_OVERRIDE_; + + //! Adds a new material renderer to the VideoDriver, based on a high level shading + //! language. + virtual s32 addHighLevelShaderMaterial( + const c8* vertexShaderProgram, + const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, + const c8* pixelShaderProgram, + const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, + const c8* geometryShaderProgram, + const c8* geometryShaderEntryPointName = "main", + E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0, + scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES, + scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP, + u32 verticesOut = 0, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData = 0) _IRR_OVERRIDE_; + + void createMaterialRenderers(); + + void draw2D3DVertexPrimitiveList(const void* vertices, + u32 vertexCount, const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, + E_INDEX_TYPE iType, bool is3D); + + D3DTEXTUREADDRESS getTextureWrapMode(const u8 clamp); + + inline D3DCOLORVALUE colorToD3D(const SColor& col) + { + const f32 f = 1.0f / 255.0f; + D3DCOLORVALUE v; + v.r = col.getRed() * f; + v.g = col.getGreen() * f; + v.b = col.getBlue() * f; + v.a = col.getAlpha() * f; + return v; + } + + CD3D9CallBridge* BridgeCalls; + + E_RENDER_MODE CurrentRenderMode; + D3DPRESENT_PARAMETERS present; + + SMaterial Material, LastMaterial; + bool ResetRenderStates; // bool to make all renderstates be reseted if set. + bool Transformation3DChanged; + const ITexture* CurrentTexture[MATERIAL_MAX_TEXTURES]; + bool LastTextureMipMapsAvailable[MATERIAL_MAX_TEXTURES]; + core::matrix4 Matrices[ETS_COUNT]; // matrices of the 3d mode we need to restore when we switch back from the 2d mode. + + HINSTANCE D3DLibrary; + IDirect3D9* pID3D; + IDirect3DDevice9* pID3DDevice; + + IDirect3DSurface9* BackBufferSurface; + IDirect3DSurface9* DepthStencilSurface; + + core::array ActiveRenderTarget; + + HWND WindowId; + core::rect* SceneSourceRect; + + D3DCAPS9 Caps; + + SIrrlichtCreationParameters Params; + + E_VERTEX_TYPE LastVertexType; + + core::stringc VendorName; + u16 VendorID; + + u32 MaxTextureUnits; + u32 MaxFixedPipelineTextureUnits; + u32 MaxUserClipPlanes; + f32 MaxLightDistance; + s32 LastSetLight; + + enum E_CACHE_2D_ATTRIBUTES + { + EC2D_ALPHA = 0x1, + EC2D_TEXTURE = 0x2, + EC2D_ALPHA_CHANNEL = 0x4 + }; + + ECOLOR_FORMAT ColorFormat; + D3DFORMAT D3DColorFormat; + bool DeviceLost; + bool DriverWasReset; + bool OcclusionQuerySupport; + bool AlphaToCoverageSupport; + }; + + //! This bridge between Irrlicht pseudo D3D9 calls + //! and true D3D9 calls. + + class CD3D9CallBridge + { + public: + CD3D9CallBridge(IDirect3DDevice9* p, CD3D9Driver* driver); + + // Reset to default state. + + void reset(); + + // Blending calls. + + void setBlendOperation(DWORD mode); + + void setBlendFunc(DWORD source, DWORD destination); + + void setBlendFuncSeparate(DWORD sourceRGB, DWORD destinationRGB, DWORD sourceAlpha, DWORD destinationAlpha); + + void setBlend(bool enable); + + private: + IDirect3DDevice9* pID3DDevice; + + DWORD BlendOperation; + DWORD BlendSourceRGB; + DWORD BlendDestinationRGB; + DWORD BlendSourceAlpha; + DWORD BlendDestinationAlpha; + bool Blend; + bool BlendSeparate; + + bool FeatureBlendSeparate; + }; + +} // end namespace video +} // end namespace irr + + +#endif // _IRR_COMPILE_WITH_DIRECT3D_9_ +#endif // __C_VIDEO_DIRECTX_9_H_INCLUDED__ + diff --git a/source/Irrlicht/CD3D9HLSLMaterialRenderer.cpp b/source/Irrlicht/CD3D9HLSLMaterialRenderer.cpp new file mode 100644 index 00000000..3600333a --- /dev/null +++ b/source/Irrlicht/CD3D9HLSLMaterialRenderer.cpp @@ -0,0 +1,416 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ + +#include "CD3D9HLSLMaterialRenderer.h" +#include "IShaderConstantSetCallBack.h" +#include "IVideoDriver.h" +#include "os.h" +#include "irrString.h" + +#ifndef _IRR_D3D_NO_SHADER_DEBUGGING +#include +#endif + + +namespace irr +{ +namespace video +{ + + +//! Public constructor +CD3D9HLSLMaterialRenderer::CD3D9HLSLMaterialRenderer(IDirect3DDevice9* d3ddev, + video::IVideoDriver* driver, s32& outMaterialTypeNr, + const c8* vertexShaderProgram, + const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, + const c8* pixelShaderProgram, + const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, + IShaderConstantSetCallBack* callback, + IMaterialRenderer* baseMaterial, + s32 userData) + : CD3D9ShaderMaterialRenderer(d3ddev, driver, callback, baseMaterial, userData), + VSConstantsTable(0), PSConstantsTable(0) +{ + + #ifdef _DEBUG + setDebugName("CD3D9HLSLMaterialRenderer"); + #endif + + outMaterialTypeNr = -1; + + // now create shaders + + if (vsCompileTarget < 0 || vsCompileTarget > EVST_COUNT) + { + os::Printer::log("Invalid HLSL vertex shader compilation target", ELL_ERROR); + return; + } + + if (!createHLSLVertexShader(vertexShaderProgram, + vertexShaderEntryPointName, VERTEX_SHADER_TYPE_NAMES[vsCompileTarget])) + return; + + if (!createHLSLPixelShader(pixelShaderProgram, + pixelShaderEntryPointName, PIXEL_SHADER_TYPE_NAMES[psCompileTarget])) + return; + + // register myself as new material + outMaterialTypeNr = Driver->addMaterialRenderer(this); +} + + +//! Destructor +CD3D9HLSLMaterialRenderer::~CD3D9HLSLMaterialRenderer() +{ + if (VSConstantsTable) + VSConstantsTable->Release(); + + if (PSConstantsTable) + PSConstantsTable->Release(); +} + + +bool CD3D9HLSLMaterialRenderer::createHLSLVertexShader(const char* vertexShaderProgram, + const char* shaderEntryPointName, + const char* shaderTargetName) +{ + if (!vertexShaderProgram) + return true; + + LPD3DXBUFFER buffer = 0; + LPD3DXBUFFER errors = 0; + +#ifdef _IRR_D3D_NO_SHADER_DEBUGGING + + size_t dataLen_t = strlen(vertexShaderProgram); + UINT dataLen = (UINT)dataLen_t; + if ( dataLen != dataLen_t ) + return false; + + // compile without debug info + HRESULT h = stubD3DXCompileShader( + vertexShaderProgram, + dataLen, + 0, // macros + 0, // no includes + shaderEntryPointName, + shaderTargetName, + 0, // no flags + &buffer, + &errors, + &VSConstantsTable); + +#else + + // compile shader and emit some debug information 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); + + 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); + +#endif + + if (FAILED(h)) + { + os::Printer::log("HLSL vertex shader compilation failed:", ELL_ERROR); + if (errors) + { + os::Printer::log((c8*)errors->GetBufferPointer(), ELL_ERROR); + errors->Release(); + if (buffer) + buffer->Release(); + } + return false; + } + + if (errors) + errors->Release(); + + if (buffer) + { + if (FAILED(pID3DDevice->CreateVertexShader((DWORD*)buffer->GetBufferPointer(), + &VertexShader))) + { + os::Printer::log("Could not create hlsl vertex shader.", ELL_ERROR); + buffer->Release(); + return false; + } + + buffer->Release(); + return true; + } + + return false; +} + + +bool CD3D9HLSLMaterialRenderer::createHLSLPixelShader(const char* pixelShaderProgram, + const char* shaderEntryPointName, + const char* shaderTargetName) +{ + if (!pixelShaderProgram) + return true; + + LPD3DXBUFFER buffer = 0; + LPD3DXBUFFER errors = 0; + + DWORD flags = 0; + +#ifdef D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY + if (Driver->queryFeature(video::EVDF_VERTEX_SHADER_2_0) || Driver->queryFeature(video::EVDF_VERTEX_SHADER_3_0)) + // this one's for newer DX SDKs which don't support ps_1_x anymore + // instead they'll silently compile 1_x as 2_x when using this flag + flags |= D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY; +#endif +#if defined(_IRR_D3D_USE_LEGACY_HLSL_COMPILER) && defined(D3DXSHADER_USE_LEGACY_D3DX9_31_DLL) +#ifdef D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY + else +#endif + flags |= D3DXSHADER_USE_LEGACY_D3DX9_31_DLL; +#endif + +#ifdef _IRR_D3D_NO_SHADER_DEBUGGING + + size_t dataLen_t = strlen(pixelShaderProgram); + UINT dataLen = (UINT)dataLen_t; + if ( dataLen != dataLen_t ) + return false; + + // compile without debug info + HRESULT h = stubD3DXCompileShader( + pixelShaderProgram, + dataLen, + 0, // macros + 0, // no includes + shaderEntryPointName, + shaderTargetName, + flags, + &buffer, + &errors, + &PSConstantsTable); + +#else + + // compile shader and emit some debug information 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, + flags | D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION, + &buffer, + &errors, + &PSConstantsTable); + +#endif + + if (FAILED(h)) + { + os::Printer::log("HLSL pixel shader compilation failed:", ELL_ERROR); + if (errors) + { + os::Printer::log((c8*)errors->GetBufferPointer(), ELL_ERROR); + errors->Release(); + if (buffer) + buffer->Release(); + } + return false; + } + + if (errors) + errors->Release(); + + if (buffer) + { + if (FAILED(pID3DDevice->CreatePixelShader((DWORD*)buffer->GetBufferPointer(), + &PixelShader))) + { + os::Printer::log("Could not create hlsl pixel shader.", ELL_ERROR); + buffer->Release(); + return false; + } + + buffer->Release(); + return true; + } + + return false; +} + + +s32 CD3D9HLSLMaterialRenderer::getVariableID(bool vertexShader, const c8* name) +{ + LPD3DXCONSTANTTABLE tbl = vertexShader ? VSConstantsTable : PSConstantsTable; + if (!tbl) + return -1; + + D3DXCONSTANTTABLE_DESC tblDesc; + if (!FAILED(tbl->GetDesc(&tblDesc))) + { + for (u32 i = 0; i < tblDesc.Constants; ++i) + { + D3DXHANDLE curConst = tbl->GetConstant(NULL, i); + D3DXCONSTANT_DESC constDesc; + UINT ucount = 1; + + if (!FAILED(tbl->GetConstantDesc(curConst, &constDesc, &ucount))) + if(strcmp(name, constDesc.Name) == 0) + return i; + } + } + + core::stringc s = "HLSL Variable to get ID not found: '"; + s += name; + s += "'. Available variables are:"; + os::Printer::log(s.c_str(), ELL_WARNING); + printHLSLVariables(tbl); + + return -1; +} + + +bool CD3D9HLSLMaterialRenderer::setVariable(bool vertexShader, s32 index, + const f32* floats, int count) +{ + LPD3DXCONSTANTTABLE tbl = vertexShader ? VSConstantsTable : PSConstantsTable; + if (index < 0 || !tbl) + return false; + + // currently we only support top level parameters. + // Should be enough for the beginning. (TODO) + + D3DXHANDLE hndl = tbl->GetConstant(NULL, index); + if (!hndl) + return false; + + D3DXCONSTANT_DESC Description; + UINT ucount = 1; + tbl->GetConstantDesc(hndl, &Description, &ucount); + + if(Description.RegisterSet != D3DXRS_SAMPLER) + { + HRESULT hr = tbl->SetFloatArray(pID3DDevice, hndl, floats, count); + if (FAILED(hr)) + { + os::Printer::log("Error setting float array for HLSL variable", ELL_WARNING); + return false; + } + } + + return true; +} + + +bool CD3D9HLSLMaterialRenderer::setVariable(bool vertexShader, s32 index, + const s32* ints, int count) +{ + LPD3DXCONSTANTTABLE tbl = vertexShader ? VSConstantsTable : PSConstantsTable; + if (index < 0 || !tbl) + return false; + + // currently we only support top level parameters. + // Should be enough for the beginning. (TODO) + + D3DXHANDLE hndl = tbl->GetConstant(NULL, index); + if (!hndl) + return false; + + D3DXCONSTANT_DESC Description; + UINT ucount = 1; + tbl->GetConstantDesc(hndl, &Description, &ucount); + + if(Description.RegisterSet != D3DXRS_SAMPLER) + { + HRESULT hr = tbl->SetIntArray(pID3DDevice, hndl, ints, count); + if (FAILED(hr)) + { + os::Printer::log("Error setting int array for HLSL variable", ELL_WARNING); + return false; + } + } + + return true; +} + + +bool CD3D9HLSLMaterialRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) +{ + if (VSConstantsTable) + VSConstantsTable->SetDefaults(pID3DDevice); + + return CD3D9ShaderMaterialRenderer::OnRender(service, vtxtype); +} + + +void CD3D9HLSLMaterialRenderer::printHLSLVariables(LPD3DXCONSTANTTABLE table) +{ + // currently we only support top level parameters. + // Should be enough for the beginning. (TODO) + + // print out constant names + D3DXCONSTANTTABLE_DESC tblDesc; + HRESULT hr = table->GetDesc(&tblDesc); + if (!FAILED(hr)) + { + for (int i=0; i<(int)tblDesc.Constants; ++i) + { + D3DXCONSTANT_DESC d; + UINT n = 1; + D3DXHANDLE cHndl = table->GetConstant(NULL, i); + if (!FAILED(table->GetConstantDesc(cHndl, &d, &n))) + { + core::stringc s = " '"; + s += d.Name; + s += "' Registers:[begin:"; + s += (int)d.RegisterIndex; + s += ", count:"; + s += (int)d.RegisterCount; + s += "]"; + os::Printer::log(s.c_str()); + } + } + } +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_DIRECT3D_9_ diff --git a/source/Irrlicht/CD3D9HLSLMaterialRenderer.h b/source/Irrlicht/CD3D9HLSLMaterialRenderer.h new file mode 100644 index 00000000..c485ee6f --- /dev/null +++ b/source/Irrlicht/CD3D9HLSLMaterialRenderer.h @@ -0,0 +1,84 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_D3D9_HLSL_MATERIAL_RENDERER_H_INCLUDED__ +#define __C_D3D9_HLSL_MATERIAL_RENDERER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_WINDOWS_ + +#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ + +#include "CD3D9ShaderMaterialRenderer.h" +#include "IGPUProgrammingServices.h" + +namespace irr +{ +namespace video +{ + +class IVideoDriver; +class IShaderConstantSetCallBack; +class IMaterialRenderer; + +//! Class for using vertex and pixel shaders via HLSL with D3D9 +class CD3D9HLSLMaterialRenderer : public CD3D9ShaderMaterialRenderer +{ +public: + + //! Public constructor + CD3D9HLSLMaterialRenderer(IDirect3DDevice9* d3ddev, video::IVideoDriver* driver, + s32& outMaterialTypeNr, + const c8* vertexShaderProgram, + const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, + const c8* pixelShaderProgram, + const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, + IShaderConstantSetCallBack* callback, + IMaterialRenderer* baseMaterial, + s32 userData); + + //! Destructor + ~CD3D9HLSLMaterialRenderer(); + + virtual s32 getVariableID(bool vertexShader, const c8* name); + + //! sets a variable in the shader. + //! \param vertexShader: True if this should be set in the vertex shader, false if + //! in the pixel shader. + //! \param index: Index of the variable + //! \param floats: Pointer to array of floats + //! \param count: Amount of floats in array. + virtual bool setVariable(bool vertexShader, s32 index, const f32* floats, int count); + + //! Int interface for the above. + virtual bool setVariable(bool vertexShader, s32 index, const s32* ints, int count); + + bool OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) _IRR_OVERRIDE_; + +protected: + + bool createHLSLVertexShader(const char* vertexShaderProgram, + const char* shaderEntryPointName, + const char* shaderTargetName); + + bool createHLSLPixelShader(const char* pixelShaderProgram, + const char* shaderEntryPointName, + const char* shaderTargetName); + + void printHLSLVariables(LPD3DXCONSTANTTABLE table); + + LPD3DXCONSTANTTABLE VSConstantsTable; + LPD3DXCONSTANTTABLE PSConstantsTable; +}; + + +} // end namespace video +} // end namespace irr + +#endif +#endif +#endif + diff --git a/source/Irrlicht/CD3D9MaterialRenderer.h b/source/Irrlicht/CD3D9MaterialRenderer.h new file mode 100644 index 00000000..fb81391d --- /dev/null +++ b/source/Irrlicht/CD3D9MaterialRenderer.h @@ -0,0 +1,577 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_D3D9_MATERIAL_RENDERER_H_INCLUDED__ +#define __C_D3D9_MATERIAL_RENDERER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_WINDOWS_ + +#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ +#if defined(__BORLANDC__) || defined (__BCPLUSPLUS__) +#include "irrMath.h" // needed by borland for sqrtf define +#endif +#include + +#include "IMaterialRenderer.h" +#include "CD3D9Driver.h" + +namespace irr +{ +namespace video +{ + +namespace +{ +D3DMATRIX UnitMatrixD3D9; +D3DMATRIX SphereMapMatrixD3D9; +inline void setTextureColorStage(IDirect3DDevice9* dev, DWORD i, + DWORD arg1, DWORD op, DWORD arg2) +{ + dev->SetTextureStageState(i, D3DTSS_COLOROP, op); + dev->SetTextureStageState(i, D3DTSS_COLORARG1, arg1); + dev->SetTextureStageState(i, D3DTSS_COLORARG2, arg2); +} +inline void setTextureColorStage(IDirect3DDevice9* dev, DWORD i, DWORD arg1) +{ + dev->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + dev->SetTextureStageState(i, D3DTSS_COLORARG1, arg1); +} + +inline void setTextureAlphaStage(IDirect3DDevice9* dev, DWORD i, + DWORD arg1, DWORD op, DWORD arg2) +{ + dev->SetTextureStageState(i, D3DTSS_ALPHAOP, op); + dev->SetTextureStageState(i, D3DTSS_ALPHAARG1, arg1); + dev->SetTextureStageState(i, D3DTSS_ALPHAARG2, arg2); +} +inline void setTextureAlphaStage(IDirect3DDevice9* dev, DWORD i, DWORD arg1) +{ + dev->SetTextureStageState(i, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + dev->SetTextureStageState(i, D3DTSS_ALPHAARG1, arg1); +} +} // anonymous namespace + +//! Base class for all internal D3D9 material renderers +class CD3D9MaterialRenderer : public IMaterialRenderer +{ +public: + + //! Constructor + CD3D9MaterialRenderer(IDirect3DDevice9* d3ddev, CD3D9Driver* driver) + : pID3DDevice(d3ddev), Driver(driver) + { + } + + virtual s32 getVariableID(bool vertexShader, const c8* name) + { + os::Printer::log("Invalid material to set variable in."); + return -1; + } + + //! sets a variable in the shader. + //! \param vertexShader: True if this should be set in the vertex shader, false if + //! in the pixel shader. + //! \param index: Index of the variable + //! \param floats: Pointer to array of floats + //! \param count: Amount of floats in array. + virtual bool setVariable(bool vertexShader, s32 index, const f32* floats, int count) + { + os::Printer::log("Invalid material to set variable in."); + return false; + } + + //! Int interface for the above. + virtual bool setVariable(bool vertexShader, s32 index, const s32* ints, int count) + { + os::Printer::log("Invalid material to set variable in."); + return false; + } + +protected: + + IDirect3DDevice9* pID3DDevice; + CD3D9Driver* Driver; +}; + + +//! Solid material renderer +class CD3D9MaterialRenderer_SOLID : public CD3D9MaterialRenderer +{ +public: + + CD3D9MaterialRenderer_SOLID(IDirect3DDevice9* p, CD3D9Driver* d) + : CD3D9MaterialRenderer(p, d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + setTextureColorStage(pID3DDevice, 0, + D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE); + } + + pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + } +}; + +//! Generic Texture Blend +class CD3D9MaterialRenderer_ONETEXTURE_BLEND : public CD3D9MaterialRenderer +{ +public: + + CD3D9MaterialRenderer_ONETEXTURE_BLEND(IDirect3DDevice9* p, CD3D9Driver* d) + : CD3D9MaterialRenderer(p, d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + +// if (material.MaterialType != lastMaterial.MaterialType || +// material.MaterialTypeParam != lastMaterial.MaterialTypeParam || +// resetAllRenderstates) + { + E_BLEND_FACTOR srcRGBFact,dstRGBFact,srcAlphaFact,dstAlphaFact; + E_MODULATE_FUNC modulate; + u32 alphaSource; + unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulate, alphaSource, material.MaterialTypeParam); + + Driver->getBridgeCalls()->setBlend(true); + Driver->getBridgeCalls()->setBlendFuncSeparate(Driver->getD3DBlend(srcRGBFact), Driver->getD3DBlend(dstRGBFact), + Driver->getD3DBlend(srcAlphaFact), Driver->getD3DBlend(dstAlphaFact)); + + setTextureColorStage(pID3DDevice, 0, + D3DTA_TEXTURE, Driver->getD3DModulate(modulate), D3DTA_DIFFUSE); + + if (textureBlendFunc_hasAlpha(srcRGBFact) || textureBlendFunc_hasAlpha(dstRGBFact) || + textureBlendFunc_hasAlpha(srcAlphaFact) || textureBlendFunc_hasAlpha(dstAlphaFact)) + { + if (alphaSource==EAS_VERTEX_COLOR) + { + setTextureAlphaStage(pID3DDevice, 0, D3DTA_DIFFUSE); + } + else if (alphaSource==EAS_TEXTURE) + { + setTextureAlphaStage(pID3DDevice, 0, D3DTA_TEXTURE); + } + else + { + setTextureAlphaStage(pID3DDevice, 0, + D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE); + } + } + + pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + + } + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + Driver->getBridgeCalls()->setBlend(false); + } + + //! Returns if the material is transparent. + /** The scene management needs to know this for being able to sort the + materials by opaque and transparent. + The return value could be optimized, but we'd need to know the + MaterialTypeParam for it. */ + virtual bool isTransparent() const _IRR_OVERRIDE_ + { + return true; + } +}; + + + +//! Solid 2 layer material renderer +class CD3D9MaterialRenderer_SOLID_2_LAYER : public CD3D9MaterialRenderer +{ +public: + + CD3D9MaterialRenderer_SOLID_2_LAYER(IDirect3DDevice9* p, CD3D9Driver* d) + : CD3D9MaterialRenderer(p, d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + setTextureColorStage(pID3DDevice, 0, D3DTA_TEXTURE); + + pID3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 0); + pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_BLENDDIFFUSEALPHA); + } + } +}; + + +//! Transparent add color material renderer +class CD3D9MaterialRenderer_TRANSPARENT_ADD_COLOR : public CD3D9MaterialRenderer +{ +public: + + CD3D9MaterialRenderer_TRANSPARENT_ADD_COLOR(IDirect3DDevice9* p, CD3D9Driver* d) + : CD3D9MaterialRenderer(p, d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + Driver->getBridgeCalls()->setBlend(true); + Driver->getBridgeCalls()->setBlendFunc(D3DBLEND_ONE, D3DBLEND_INVSRCCOLOR); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + setTextureColorStage(pID3DDevice, 0, + D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE); + + pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + } + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + Driver->getBridgeCalls()->setBlend(false); + } + + //! Returns if the material is transparent. The scene management needs to know this + //! for being able to sort the materials by opaque and transparent. + virtual bool isTransparent() const _IRR_OVERRIDE_ + { + return true; + } +}; + + +//! Transparent vertex alpha material renderer +class CD3D9MaterialRenderer_TRANSPARENT_VERTEX_ALPHA : public CD3D9MaterialRenderer +{ +public: + + CD3D9MaterialRenderer_TRANSPARENT_VERTEX_ALPHA(IDirect3DDevice9* p, CD3D9Driver* d) + : CD3D9MaterialRenderer(p, d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + Driver->getBridgeCalls()->setBlend(true); + Driver->getBridgeCalls()->setBlendFunc(D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + setTextureColorStage(pID3DDevice, 0, + D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE); + setTextureAlphaStage(pID3DDevice, 0, D3DTA_DIFFUSE); + + pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + } + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + Driver->getBridgeCalls()->setBlend(false); + } + + //! Returns if the material is transparent. The scene management needs to know this + //! for being able to sort the materials by opaque and transparent. + virtual bool isTransparent() const _IRR_OVERRIDE_ + { + return true; + } +}; + + +//! Transparent alpha channel material renderer +class CD3D9MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL : public CD3D9MaterialRenderer +{ +public: + + CD3D9MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL(IDirect3DDevice9* p, CD3D9Driver* d) + : CD3D9MaterialRenderer(p, d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + Driver->getBridgeCalls()->setBlend(true); + Driver->getBridgeCalls()->setBlendFunc(D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates + || material.MaterialTypeParam != lastMaterial.MaterialTypeParam ) + { + setTextureColorStage(pID3DDevice, 0, + D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT); + setTextureAlphaStage(pID3DDevice, 0, D3DTA_TEXTURE); + + pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + + pID3DDevice->SetRenderState(D3DRS_ALPHAREF, core::floor32(material.MaterialTypeParam * 255.f)); + pID3DDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); + pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); + } + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + Driver->getBridgeCalls()->setBlend(false); + } + + //! Returns if the material is transparent. The scene management needs to know this + //! for being able to sort the materials by opaque and transparent. + virtual bool isTransparent() const _IRR_OVERRIDE_ + { + return true; + } +}; + + + +//! Transparent alpha channel material renderer +class CD3D9MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF : public CD3D9MaterialRenderer +{ +public: + + CD3D9MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF(IDirect3DDevice9* p, CD3D9Driver* d) + : CD3D9MaterialRenderer(p, d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + setTextureColorStage(pID3DDevice, 0, + D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT); + setTextureAlphaStage(pID3DDevice, 0, D3DTA_TEXTURE); + + pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + + // 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); + } + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + } + + //! Returns if the material is transparent. The scene management needs to know this + //! for being able to sort the materials by opaque and transparent. + virtual bool isTransparent() const _IRR_OVERRIDE_ + { + return false; // this material is not really transparent because it does no blending. + } +}; + + +//! material renderer for all kinds of lightmaps +class CD3D9MaterialRenderer_LIGHTMAP : public CD3D9MaterialRenderer +{ +public: + + CD3D9MaterialRenderer_LIGHTMAP(IDirect3DDevice9* p, CD3D9Driver* d) + : CD3D9MaterialRenderer(p, d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + if (material.MaterialType >= EMT_LIGHTMAP_LIGHTING) + { + // with lighting + setTextureColorStage(pID3DDevice, 0, + D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE); + } + else + { + setTextureColorStage(pID3DDevice, 0, D3DTA_TEXTURE); + } + + pID3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1); + + setTextureColorStage(pID3DDevice, 1, + D3DTA_TEXTURE, + (material.MaterialType == EMT_LIGHTMAP_ADD)? + D3DTOP_ADD: + (material.MaterialType == EMT_LIGHTMAP_M4 || material.MaterialType == EMT_LIGHTMAP_LIGHTING_M4)? + D3DTOP_MODULATE4X: + (material.MaterialType == EMT_LIGHTMAP_M2 || material.MaterialType == EMT_LIGHTMAP_LIGHTING_M2)? + D3DTOP_MODULATE2X: + D3DTOP_MODULATE, + D3DTA_CURRENT); + } + } +}; + + + +//! material renderer for detail maps +class CD3D9MaterialRenderer_DETAIL_MAP : public CD3D9MaterialRenderer +{ +public: + + CD3D9MaterialRenderer_DETAIL_MAP(IDirect3DDevice9* p, CD3D9Driver* d) + : CD3D9MaterialRenderer(p, d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + setTextureColorStage(pID3DDevice, 0, + D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE); + setTextureColorStage(pID3DDevice, 1, + D3DTA_TEXTURE, D3DTOP_ADDSIGNED, D3DTA_CURRENT); + pID3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1); + } + } +}; + + +//! sphere map material renderer +class CD3D9MaterialRenderer_SPHERE_MAP : public CD3D9MaterialRenderer +{ +public: + + CD3D9MaterialRenderer_SPHERE_MAP(IDirect3DDevice9* p, CD3D9Driver* d) + : CD3D9MaterialRenderer(p, d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + setTextureColorStage(pID3DDevice, 0, + D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE); + + pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + + pID3DDevice->SetTransform( D3DTS_TEXTURE0, &SphereMapMatrixD3D9 ); + pID3DDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 ); + pID3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACENORMAL ); + } + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + pID3DDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE ); + pID3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0); + pID3DDevice->SetTransform( D3DTS_TEXTURE0, &UnitMatrixD3D9 ); + } +}; + + +//! reflection 2 layer material renderer +class CD3D9MaterialRenderer_REFLECTION_2_LAYER : public CD3D9MaterialRenderer +{ +public: + + CD3D9MaterialRenderer_REFLECTION_2_LAYER(IDirect3DDevice9* p, CD3D9Driver* d) + : CD3D9MaterialRenderer(p, d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + setTextureColorStage(pID3DDevice, 0, + D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE); + + setTextureColorStage(pID3DDevice, 1, + D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT); + + pID3DDevice->SetTransform( D3DTS_TEXTURE1, &SphereMapMatrixD3D9 ); + pID3DDevice->SetTextureStageState( 1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 ); + pID3DDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR); + } + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + pID3DDevice->SetTextureStageState( 1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE ); + pID3DDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 1); + pID3DDevice->SetTransform( D3DTS_TEXTURE1, &UnitMatrixD3D9 ); + } +}; + + +//! reflection 2 layer material renderer +class CD3D9MaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER : public CD3D9MaterialRenderer +{ +public: + + CD3D9MaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER(IDirect3DDevice9* p, CD3D9Driver* d) + : CD3D9MaterialRenderer(p, d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + Driver->getBridgeCalls()->setBlend(true); + Driver->getBridgeCalls()->setBlendFunc(D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + setTextureColorStage(pID3DDevice, 0, + D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE); + setTextureAlphaStage(pID3DDevice, 0, D3DTA_DIFFUSE); + setTextureColorStage(pID3DDevice, 1, + D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT); + setTextureAlphaStage(pID3DDevice, 1, D3DTA_CURRENT); + + pID3DDevice->SetTransform(D3DTS_TEXTURE1, &SphereMapMatrixD3D9 ); + pID3DDevice->SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 ); + pID3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR); + } + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + pID3DDevice->SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); + pID3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1); + pID3DDevice->SetTransform(D3DTS_TEXTURE1, &UnitMatrixD3D9); + Driver->getBridgeCalls()->setBlend(false); + } + + //! Returns if the material is transparent. The scene management needs to know this + //! for being able to sort the materials by opaque and transparent. + virtual bool isTransparent() const _IRR_OVERRIDE_ + { + return true; + } +}; + +} // end namespace video +} // end namespace irr + +#endif +#endif +#endif + diff --git a/source/Irrlicht/CD3D9NormalMapRenderer.cpp b/source/Irrlicht/CD3D9NormalMapRenderer.cpp new file mode 100644 index 00000000..13c6d361 --- /dev/null +++ b/source/Irrlicht/CD3D9NormalMapRenderer.cpp @@ -0,0 +1,306 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ + +#include "CD3D9NormalMapRenderer.h" +#include "IVideoDriver.h" +#include "IMaterialRendererServices.h" +#include "os.h" +#include "SLight.h" + +namespace irr +{ +namespace video +{ + + // 1.1 Shaders with two lights and vertex based attenuation + + // Irrlicht Engine D3D9 render path normal map vertex shader + const char D3D9_NORMAL_MAP_VSH[] = + ";Irrlicht Engine 0.8 D3D9 render path normal map vertex shader\n"\ + "; c0-3: Transposed world matrix \n"\ + "; c8-11: Transposed worldViewProj matrix (Projection * View * World) \n"\ + "; c12: Light01 position \n"\ + "; c13: x,y,z: Light01 color; .w: 1/LightRadius \n"\ + "; c14: Light02 position \n"\ + "; c15: x,y,z: Light02 color; .w: 1/LightRadius \n"\ + "vs.1.1\n"\ + "dcl_position v0 ; position \n"\ + "dcl_normal v1 ; normal \n"\ + "dcl_color v2 ; color \n"\ + "dcl_texcoord0 v3 ; texture coord \n"\ + "dcl_texcoord1 v4 ; tangent \n"\ + "dcl_texcoord2 v5 ; binormal \n"\ + "\n"\ + "def c95, 0.5, 0.5, 0.5, 0.5 ; used for moving light vector to ps \n"\ + "\n"\ + "m4x4 oPos, v0, c8 ; transform position to clip space with worldViewProj matrix\n"\ + "\n"\ + "m3x3 r5, v4, c0 ; transform tangent U\n"\ + "m3x3 r7, v1, c0 ; transform normal W\n"\ + "m3x3 r6, v5, c0 ; transform binormal V\n"\ + "\n"\ + "m4x4 r4, v0, c0 ; vertex into world position\n"\ + "add r2, c12, -r4 ; vtxpos - lightpos1\n"\ + "add r3, c14, -r4 ; vtxpos - lightpos2\n"\ + "\n"\ + "dp3 r8.x, r5, r2 ; transform the light vector 1 with U, V, W\n"\ + "dp3 r8.y, r6, r2 \n"\ + "dp3 r8.z, r7, r2 \n"\ + "dp3 r9.x, r5, r3 ; transform the light vector 2 with U, V, W\n"\ + "dp3 r9.y, r6, r3 \n"\ + "dp3 r9.z, r7, r3 \n"\ + "\n"\ + "dp3 r8.w, r8, r8 ; normalize light vector 1 (r8)\n"\ + "rsq r8.w, r8.w \n"\ + "mul r8, r8, r8.w \n"\ + "dp3 r9.w, r9, r9 ; normalize light vector 2 (r9)\n"\ + "rsq r9.w, r9.w \n"\ + "mul r9, r9, r9.w \n"\ + "\n"\ + "mad oT2.xyz, r8.xyz, c95, c95 ; move light vector 1 from -1..1 into 0..1 \n"\ + "mad oT3.xyz, r9.xyz, c95, c95 ; move light vector 2 from -1..1 into 0..1 \n"\ + "\n"\ + " ; calculate attenuation of light 1 \n"\ + "dp3 r2.x, r2.xyz, r2.xyz ; r2.x = r2.x + r2.y + r2.z \n"\ + "mul r2.x, r2.x, c13.w ; r2.x * attenutation \n"\ + "rsq r2, r2.x ; r2.xyzw = 1/sqrt(r2.x * attenutation)\n"\ + "mul oD0, r2, c13 ; resulting light color = lightcolor * attenuation \n"\ + "\n"\ + " ; calculate attenuation of light 2 \n"\ + "dp3 r3.x, r3.xyz, r3.xyz ; r3.x = r3.x + r3.y + r3.z \n"\ + "mul r3.x, r3.x, c15.w ; r2.x * attenutation \n"\ + "rsq r3, r3.x ; r2.xyzw = 1/sqrt(r2.x * attenutation)\n"\ + "mul oD1, r3, c15 ; resulting light color = lightcolor * attenuation \n"\ + "\n"\ + "mov oT0.xy, v3.xy ; move out texture coordinates 1\n"\ + "mov oT1.xy, v3.xy ; move out texture coordinates 2\n"\ + "mov oD0.a, v2.a ; move out original alpha value \n"\ + "\n"; + + // Irrlicht Engine D3D9 render path normal map pixel shader + const char D3D9_NORMAL_MAP_PSH_1_1[] = + ";Irrlicht Engine 0.8 D3D9 render path normal map pixel shader\n"\ + ";Input: \n"\ + ";t0: color map texture coord \n"\ + ";t1: normal map texture coords \n"\ + ";t2: light 1 vector in tangent space \n"\ + ";v0: light 1 color \n"\ + ";t3: light 2 vector in tangent space \n"\ + ";v1: light 2 color \n"\ + ";v0.a: vertex alpha value \n"\ + "ps.1.1 \n"\ + "tex t0 ; sample color map \n"\ + "tex t1 ; sample normal map\n"\ + "texcoord t2 ; fetch light vector 1\n"\ + "texcoord t3 ; fetch light vector 2\n"\ + "\n"\ + "dp3_sat r0, t1_bx2, t2_bx2 ; normal dot light 1 (_bx2 because moved into 0..1)\n"\ + "mul r0, r0, v0 ; luminance1 * light color 1 \n"\ + "\n"\ + "dp3_sat r1, t1_bx2, t3_bx2 ; normal dot light 2 (_bx2 because moved into 0..1)\n"\ + "mad r0, r1, v1, r0 ; (luminance2 * light color 2) + luminance 1 \n"\ + "\n"\ + "mul r0.xyz, t0, r0 ; total luminance * base color\n"\ + "+mov r0.a, v0.a ; write interpolated vertex alpha value \n"\ + "\n"\ + ""; + + // Higher-quality normal map pixel shader (requires PS 2.0) + // uses per-pixel normalization for improved accuracy + const char D3D9_NORMAL_MAP_PSH_2_0[] = + ";Irrlicht Engine 0.8 D3D9 render path normal map pixel shader\n"\ + ";Input: \n"\ + ";t0: color map texture coord \n"\ + ";t1: normal map texture coords \n"\ + ";t2: light 1 vector in tangent space \n"\ + ";v0: light 1 color \n"\ + ";t3: light 2 vector in tangent space \n"\ + ";v1: light 2 color \n"\ + ";v0.a: vertex alpha value \n"\ + + "ps_2_0 \n"\ + "def c0, 0, 0, 0, 0\n"\ + "def c1, 1.0, 1.0, 1.0, 1.0\n"\ + "def c2, 2.0, 2.0, 2.0, 2.0\n"\ + "def c3, -.5, -.5, -.5, -.5\n"\ + "dcl t0\n"\ + "dcl t1\n"\ + "dcl t2\n"\ + "dcl t3\n"\ + "dcl v1\n"\ + "dcl v0\n"\ + "dcl_2d s0\n"\ + "dcl_2d s1\n"\ + + "texld r0, t0, s0 ; sample color map into r0 \n"\ + "texld r4, t0, s1 ; sample normal map into r4\n"\ + "add r4, r4, c3 ; bias the normal vector\n"\ + "add r5, t2, c3 ; bias the light 1 vector into r5\n"\ + "add r6, t3, c3 ; bias the light 2 vector into r6\n"\ + + "nrm r1, r4 ; normalize the normal vector into r1\n"\ + "nrm r2, r5 ; normalize the light1 vector into r2\n"\ + "nrm r3, r6 ; normalize the light2 vector into r3\n"\ + + "dp3 r2, r2, r1 ; let r2 = normal DOT light 1 vector\n"\ + "max r2, r2, c0 ; clamp result to positive numbers\n"\ + "mul r2, r2, v0 ; let r2 = luminance1 * light color 1 \n"\ + + "dp3 r3, r3, r1 ; let r3 = normal DOT light 2 vector\n"\ + "max r3, r3, c0 ; clamp result to positive numbers\n"\ + + "mad r2, r3, v1, r2 ; let r2 = (luminance2 * light color 2) + (luminance2 * light color 1) \n"\ + + "mul r2, r2, r0 ; let r2 = total luminance * base color\n"\ + "mov r2.w, v0.w ; write interpolated vertex alpha value \n"\ + + "mov oC0, r2 ; copy r2 to the output register \n"\ + + "\n"\ + ""; + + CD3D9NormalMapRenderer::CD3D9NormalMapRenderer( + IDirect3DDevice9* d3ddev, video::IVideoDriver* driver, + s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial) + : CD3D9ShaderMaterialRenderer(d3ddev, driver, 0, baseMaterial) + { + #ifdef _DEBUG + setDebugName("CD3D9NormalMapRenderer"); + #endif + + // set this as callback. We could have done this in + // the initialization list, but some compilers don't like it. + + CallBack = this; + + // basically, this thing simply compiles the hardcoded shaders + // if the hardware is able to do them, otherwise it maps to the + // base material + + if (!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) || + !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1)) + { + // this hardware is not able to do shaders. Fall back to + // base material. + outMaterialTypeNr = driver->addMaterialRenderer(this); + return; + } + + // check if already compiled normal map shaders are there. + + video::IMaterialRenderer* renderer = driver->getMaterialRenderer(EMT_NORMAL_MAP_SOLID); + if (renderer) + { + // use the already compiled shaders + video::CD3D9NormalMapRenderer* nmr = (video::CD3D9NormalMapRenderer*)renderer; + VertexShader = nmr->VertexShader; + if (VertexShader) + VertexShader->AddRef(); + + PixelShader = nmr->PixelShader; + if (PixelShader) + PixelShader->AddRef(); + + outMaterialTypeNr = driver->addMaterialRenderer(this); + } + else + { + // compile shaders on our own + if (driver->queryFeature(video::EVDF_PIXEL_SHADER_2_0)) + { + init(outMaterialTypeNr, D3D9_NORMAL_MAP_VSH, D3D9_NORMAL_MAP_PSH_2_0); + } + else + { + init(outMaterialTypeNr, D3D9_NORMAL_MAP_VSH, D3D9_NORMAL_MAP_PSH_1_1); + } + } + // something failed, use base material + if (-1==outMaterialTypeNr) + driver->addMaterialRenderer(this); + } + + + CD3D9NormalMapRenderer::~CD3D9NormalMapRenderer() + { + if (CallBack == this) + CallBack = 0; + } + + + bool CD3D9NormalMapRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) + { + if (vtxtype != video::EVT_TANGENTS) + { + os::Printer::log("Error: Normal map renderer only supports vertices of type EVT_TANGENTS", ELL_ERROR); + return false; + } + + return CD3D9ShaderMaterialRenderer::OnRender(service, vtxtype); + } + + + //! Returns the render capability of the material. + s32 CD3D9NormalMapRenderer::getRenderCapability() const + { + if (Driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) && + Driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1)) + return 0; + + return 1; + } + + + //! Called by the engine when the vertex and/or pixel shader constants + //! for an material renderer should be set. + void CD3D9NormalMapRenderer::OnSetConstants(IMaterialRendererServices* services, s32 userData) + { + video::IVideoDriver* driver = services->getVideoDriver(); + + // set transposed world matrix + services->setVertexShaderConstant(driver->getTransform(video::ETS_WORLD).getTransposed().pointer(), 0, 4); + + // set transposed worldViewProj matrix + core::matrix4 worldViewProj(driver->getTransform(video::ETS_PROJECTION)); + worldViewProj *= driver->getTransform(video::ETS_VIEW); + worldViewProj *= driver->getTransform(video::ETS_WORLD); + services->setVertexShaderConstant(worldViewProj.getTransposed().pointer(), 8, 4); + + // here we've got to fetch the fixed function lights from the + // driver and set them as constants + + u32 cnt = driver->getDynamicLightCount(); + + for (u32 i=0; i<2; ++i) + { + SLight light; + + if (igetDynamicLight(i); + else + { + light.DiffuseColor.set(0,0,0); // make light dark + light.Radius = 1.0f; + } + + light.DiffuseColor.a = 1.0f/(light.Radius*light.Radius); // set attenuation + + services->setVertexShaderConstant(reinterpret_cast(&light.Position), 12+(i*2), 1); + services->setVertexShaderConstant(reinterpret_cast(&light.DiffuseColor), 13+(i*2), 1); + } + + // this is not really necessary in d3d9 (used a def instruction), but to be sure: + f32 c95[] = {0.5f, 0.5f, 0.5f, 0.5f}; + services->setVertexShaderConstant(c95, 95, 1); + } + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_DIRECT3D_9_ + diff --git a/source/Irrlicht/CD3D9NormalMapRenderer.h b/source/Irrlicht/CD3D9NormalMapRenderer.h new file mode 100644 index 00000000..56cbde92 --- /dev/null +++ b/source/Irrlicht/CD3D9NormalMapRenderer.h @@ -0,0 +1,56 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_D3D9_NORMAL_MAPMATERIAL_RENDERER_H_INCLUDED__ +#define __C_D3D9_NORMAL_MAPMATERIAL_RENDERER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_WINDOWS_ + +#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ +#if defined(__BORLANDC__) || defined (__BCPLUSPLUS__) +#include "irrMath.h" // needed by borland for sqrtf define +#endif +#include + +#include "CD3D9ShaderMaterialRenderer.h" +#include "IShaderConstantSetCallBack.h" + +namespace irr +{ +namespace video +{ + +//! Renderer for normal maps +class CD3D9NormalMapRenderer : + public CD3D9ShaderMaterialRenderer, IShaderConstantSetCallBack +{ +public: + + CD3D9NormalMapRenderer( + IDirect3DDevice9* d3ddev, video::IVideoDriver* driver, + s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial); + + ~CD3D9NormalMapRenderer(); + + //! Called by the engine when the vertex and/or pixel shader constants for an + //! material renderer should be set. + virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData) _IRR_OVERRIDE_; + + virtual bool OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) _IRR_OVERRIDE_; + + //! Returns the render capability of the material. + virtual s32 getRenderCapability() const _IRR_OVERRIDE_; + +private: + +}; + +} // end namespace video +} // end namespace irr + +#endif +#endif +#endif + diff --git a/source/Irrlicht/CD3D9ParallaxMapRenderer.cpp b/source/Irrlicht/CD3D9ParallaxMapRenderer.cpp new file mode 100644 index 00000000..f036fb72 --- /dev/null +++ b/source/Irrlicht/CD3D9ParallaxMapRenderer.cpp @@ -0,0 +1,409 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ + +#include "CD3D9ParallaxMapRenderer.h" +#include "IMaterialRendererServices.h" +#include "IVideoDriver.h" +#include "os.h" +#include "SLight.h" + +//#define SHADER_EXTERNAL_DEBUG + +#ifdef SHADER_EXTERNAL_DEBUG +#include "CReadFile.h" +#endif + +namespace irr +{ +namespace video +{ + // 1.1/1.4 Shaders with two lights and vertex based attenuation + + // Irrlicht Engine D3D9 render path normal map vertex shader + const char D3D9_PARALLAX_MAP_VSH[] = + ";Irrlicht Engine 0.10 D3D9 render path parallax mapping vertex shader\n"\ + "; c0-3: Transposed world matrix \n"\ + "; c4: Eye position \n"\ + "; c8-11: Transposed worldViewProj matrix (Projection * View * World) \n"\ + "; c12: Light01 position \n"\ + "; c13: x,y,z: Light01 color; .w: 1/LightRadius \n"\ + "; c14: Light02 position \n"\ + "; c15: x,y,z: Light02 color; .w: 1/LightRadius \n"\ + "vs.1.1\n"\ + "dcl_position v0 ; position \n"\ + "dcl_normal v1 ; normal \n"\ + "dcl_color v2 ; color \n"\ + "dcl_texcoord0 v3 ; texture coord \n"\ + "dcl_texcoord1 v4 ; tangent \n"\ + "dcl_texcoord2 v5 ; binormal \n"\ + "\n"\ + "def c95, 0.5, 0.5, 0.5, 0.5 ; used for moving light vector to ps \n"\ + "def c96, -1, 1, 1, 1 ; somewhere I've got a bug. flipping the vectors with this fixes it. \n"\ + "\n"\ + "m4x4 oPos, v0, c8 ; transform position to clip space with worldViewProj matrix\n"\ + "\n"\ + "m3x3 r5, v4, c0 ; transform tangent U\n"\ + "m3x3 r7, v1, c0 ; transform normal W\n"\ + "m3x3 r6, v5, c0 ; transform binormal V\n"\ + "\n"\ + "m4x4 r4, v0, c0 ; vertex into world position\n"\ + "add r2, c12, -r4 ; vtxpos - light1 pos\n"\ + "add r3, c14, -r4 ; vtxpos - light2 pos\n"\ + "add r1, -c4, r4 ; eye - vtxpos \n"\ + "\n"\ + "dp3 r8.x, r5, r2 ; transform the light1 vector with U, V, W\n"\ + "dp3 r8.y, r6, r2 \n"\ + "dp3 r8.z, r7, r2 \n"\ + "dp3 r9.x, r5, r3 ; transform the light2 vector with U, V, W\n"\ + "dp3 r9.y, r6, r3 \n"\ + "dp3 r9.z, r7, r3 \n"\ + "dp3 r10.x, r5, r1 ; transform the eye vector with U, V, W\n"\ + "dp3 r10.y, r6, r1 \n"\ + "dp3 r10.z, r7, r1 \n"\ + "\n"\ + "dp3 r8.w, r8, r8 ; normalize light vector 1 (r8)\n"\ + "rsq r8.w, r8.w \n"\ + "mul r8, r8, r8.w \n"\ + ";mul r8, r8, c96 \n"\ + "dp3 r9.w, r9, r9 ; normalize light vector 2 (r9)\n"\ + "rsq r9.w, r9.w \n"\ + "mul r9, r9, r9.w \n"\ + ";mul r9, r9, c96 \n"\ + "dp3 r10.w, r10, r10 ; normalize eye vector (r10)\n"\ + "rsq r10.w, r10.w \n"\ + "mul r10, r10, r10.w \n"\ + "mul r10, r10, c96 \n"\ + "\n"\ + "\n"\ + "mad oT2.xyz, r8.xyz, c95, c95 ; move light vector 1 from -1..1 into 0..1 \n"\ + "mad oT3.xyz, r9.xyz, c95, c95 ; move light vector 2 from -1..1 into 0..1 \n"\ + "mad oT4.xyz, r10.xyz, c95, c95 ; move eye vector from -1..1 into 0..1 \n"\ + "\n"\ + " ; calculate attenuation of light 1 \n"\ + "dp3 r2.x, r2.xyz, r2.xyz ; r2.x = r2.x + r2.y + r2.z \n"\ + "mul r2.x, r2.x, c13.w ; r2.x * attenutation \n"\ + "rsq r2, r2.x ; r2.xyzw = 1/sqrt(r2.x * attenutation)\n"\ + "mul oD0, r2, c13 ; resulting light color = lightcolor * attenuation \n"\ + "\n"\ + " ; calculate attenuation of light 2 \n"\ + "dp3 r3.x, r3.xyz, r3.xyz ; r3.x = r3.x + r3.y + r3.z \n"\ + "mul r3.x, r3.x, c15.w ; r2.x * attenutation \n"\ + "rsq r3, r3.x ; r2.xyzw = 1/sqrt(r2.x * attenutation)\n"\ + "mul oD1, r3, c15 ; resulting light color = lightcolor * attenuation \n"\ + "\n"\ + "mov oT0.xy, v3.xy ; move out texture coordinates 1\n"\ + "mov oT1.xy, v3.xy ; move out texture coordinates 2\n"\ + "mov oD0.a, v2.a ; move out original alpha value \n"\ + "\n"; + + + // Irrlicht Engine D3D9 render path normal map pixel shader version 1.4 + const char D3D9_PARALLAX_MAP_PSH[] = + ";Irrlicht Engine 0.10 D3D9 render path parallax mapping pixel shader \n"\ + ";Input: \n"\ + ";t0: color map texture coord \n"\ + ";t1: normal map texture coords \n"\ + ";t2: light 1 vector in tangent space \n"\ + ";t4: eye vector in tangent space \n"\ + ";v0: light 1 color \n"\ + ";t3: light 2 vector in tangent space \n"\ + ";v1: light 2 color \n"\ + ";v0.a: vertex alpha value \n"\ + " \n"\ + "ps.1.4 \n"\ + " \n"\ + ";def c6, 0.02f, 0.02f, 0.02f, 0.0f ; scale factor, now set in callback \n"\ + "def c5, 0.5f, 0.5f, 0.5f, 0.0f ; for specular division \n"\ + " \n"\ + "texld r1, t1 ; sample (normal.x, normal.y, normal.z, height) \n"\ + "texcrd r4.xyz, t4 ; fetch eye vector \n"\ + "texcrd r0.xyz, t0 ; color map \n"\ + " \n"\ + "; original parallax mapping: \n"\ + ";mul r3, r1_bx2.wwww, c6; ; r3 = (height, height, height) * scale \n"\ + ";mad r2.xyz, r3, r4_bx2, r0 ; newTexCoord = height * eye + oldTexCoord \n"\ + " \n"\ + "; modified parallax mapping to reduce swimming effect: \n"\ + "mul r3, r1_bx2.wwww, r1_bx2.zzzz ; (nh,nh,nh,nh) = (h,h,h,h) * (n.z,n.z,n.z,n.z,) \n"\ + "mul r3, r3, c6; ; r3 = (nh, nh, nh) * scale \n"\ + "mad r2.xyz, r3, r4_bx2, r0 ; newTexCoord = height * eye + oldTexCoord \n"\ + " \n"\ + "phase \n"\ + " \n"\ + "texld r0, r2 ; load diffuse texture with new tex coord \n"\ + "texld r1, r2 ; sample normal map \n"\ + "texcrd r2.xyz, t2 ; fetch light vector 1 \n"\ + "texcrd r3.xyz, t3 ; fetch light vector 2 \n"\ + " \n"\ + "dp3_sat r5, r1_bx2, r2_bx2 ; normal dot light 1 (_bx2 because moved into 0..1) \n"\ + "mul r5, r5, v0 ; luminance1 * light color 1 \n"\ + " \n"\ + "dp3_sat r3, r1_bx2, r3_bx2 ; normal dot light 2 (_bx2 because moved into 0..1) \n"\ + "mad r3, r3, v1, r5 ; (luminance2 * light color 2) + luminance1 \n"\ + " \n"\ + "mul r0.xyz, r0, r3 ; total luminance * base color \n"\ + "+mov r0.a, v0.a ; write original alpha value \n"\ + "\n"; + + // Irrlicht Engine D3D9 render path normal map pixel shader version 2.0 + const char D3D9_PARALLAX_MAP_PSH_20[] = + ";Irrlicht Engine D3D9 render path parallax mapping pixel shader \n"\ + ";Input: \n"\ + " \n"\ + ";t0: color map texture coord \n"\ + ";t1: normal map texture coords \n"\ + ";t2: light 1 vector in tangent space \n"\ + ";t4: eye vector in tangent space \n"\ + ";v0: light 1 color \n"\ + ";t3: light 2 vector in tangent space \n"\ + ";v1: light 2 color \n"\ + ";v0.a: vertex alpha value \n"\ + " \n"\ + "ps.2.0 \n"\ + " \n"\ + "dcl_2d s0 ; Declare the s0 register to be the sampler for stage 0 \n"\ + "dcl t0.xy ; Declare t0 to have 2D texture coordinates from stage 0 \n"\ + "dcl t1.xy ; Declare t0 to have 2D texture coordinates from stage 0 \n"\ + "dcl_2d s1 ; Declare the s1 register to be the sampler for stage 1 \n"\ + " \n"\ + "dcl t2.xyz ; \n"\ + "dcl t3.xyz ; \n"\ + "dcl t4.xyz ; \n"\ + "dcl v0.xyzw; \n"\ + "dcl v1.xyzw; \n"\ + " \n"\ + "def c0, -1.0f, -1.0f, -1.0f, -1.0f ; for _bx2 emulation \n"\ + "def c1, 2.0f, 2.0f, 2.0f, 2.0f ; for _bx2 emulation \n"\ + "mov r11, c1; \n"\ + " \n"\ + "texld r1, t1, s1 ; sample (normal.x, normal.y, normal.z, height) \n"\ + "mov r4.xyz, t4 ; fetch eye vector \n"\ + "mov r0.xy, t0 ; color map \n"\ + " \n"\ + "; original parallax mapping: \n"\ + "; emulate ps1x _bx2, so substract 0.5f and multiply by 2 \n"\ + "mad r1.xyz, r1, r11, c0; \n"\ + " \n"\ + "mul r3, r1.wwww, c6; ; r3 = (height, height, height) * scale \n"\ + " \n"\ + "; emulate ps1x _bx2, so substract 0.5f and multiply by 2 \n"\ + "mad r4.xyz, r4, r11, c0; \n"\ + " \n"\ + "mad r2.xy, r3, r4, r0 ; newTexCoord = height * eye + oldTexCoord \n"\ + " \n"\ + "; modified parallax mapping to avoid swimming: \n"\ + ";mul r3, r1_bx2.wwww, r1_bx2.zzzz ; r3 = (h,h,h,h) * (n.z, n.z, n.z, n.z,) \n"\ + ";mul r3, r3, c6; ; r3 = (nh, nh, nh) * scale \n"\ + ";mad r2.xyz, r3, r4_bx2, r0 ; newTexCoord = height * eye + oldTexCoord \n"\ + " \n"\ + "texld r0, r2, s0 ; load diffuse texture with new tex coord \n"\ + "texld r1, r2, s1 ; sample normal map \n"\ + "mov r2.xyz, t2 ; fetch light vector 1 \n"\ + "mov r3.xyz, t3 ; fetch light vector 2 \n"\ + " \n"\ + "; emulate ps1x _bx2, so substract 0.5f and multiply by 2 \n"\ + "mad r1.xyz, r1, r11, c0; \n"\ + "mad r2.xyz, r2, r11, c0; \n"\ + "mad r3.xyz, r3, r11, c0; \n"\ + " \n"\ + "dp3_sat r2, r1, r2 ; normal dot light 1 (_bx2 because moved into 0..1) \n"\ + "mul r2, r2, v0 ; luminance1 * light color 1 \n"\ + " \n"\ + "dp3_sat r3, r1, r3 ; normal dot light 2 (_bx2 because moved into 0..1) \n"\ + "mad r3, r3, v1, r2 ; (luminance2 * light color 2) + luminance1 \n"\ + " \n"\ + "mul r0.xyz, r0, r3 ; total luminance * base color \n"\ + "mov r0.a, v0.a ; write original alpha value \n"\ + "mov oC0, r0; \n"\ + "\n"; + + CD3D9ParallaxMapRenderer::CD3D9ParallaxMapRenderer( + IDirect3DDevice9* d3ddev, video::IVideoDriver* driver, + s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial) + : CD3D9ShaderMaterialRenderer(d3ddev, driver, 0, baseMaterial), + CurrentScale(0.0f) + { + #ifdef _DEBUG + setDebugName("CD3D9ParallaxMapRenderer"); + #endif + + // set this as callback. We could have done this in + // the initialization list, but some compilers don't like it. + + CallBack = this; + + // basically, this thing simply compiles these hardcoded shaders if the + // hardware is able to do them, otherwise it maps to the base material + + if (!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_4) || + !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1)) + { + // this hardware is not able to do shaders. Fall back to + // base material. + outMaterialTypeNr = driver->addMaterialRenderer(this); + return; + } + + // check if already compiled parallax map shaders are there. + + video::IMaterialRenderer* renderer = driver->getMaterialRenderer(EMT_PARALLAX_MAP_SOLID); + if (renderer) + { + // use the already compiled shaders + video::CD3D9ParallaxMapRenderer* nmr = (video::CD3D9ParallaxMapRenderer*)renderer; + VertexShader = nmr->VertexShader; + if (VertexShader) + VertexShader->AddRef(); + + PixelShader = nmr->PixelShader; + if (PixelShader) + PixelShader->AddRef(); + + outMaterialTypeNr = driver->addMaterialRenderer(this); + } + else + { + #ifdef SHADER_EXTERNAL_DEBUG + + // quickly load shader from external file + io::CReadFile* file = new io::CReadFile("parallax.psh"); + s32 sz = file->getSize(); + char* s = new char[sz+1]; + file->read(s, sz); + s[sz] = 0; + + init(outMaterialTypeNr, D3D9_PARALLAX_MAP_VSH, s); + + delete [] s; + file->drop(); + + #else + + // compile shaders on our own + init(outMaterialTypeNr, D3D9_PARALLAX_MAP_VSH, D3D9_PARALLAX_MAP_PSH); + + #endif // SHADER_EXTERNAL_DEBUG + } + // something failed, use base material + if (-1==outMaterialTypeNr) + driver->addMaterialRenderer(this); + } + + + CD3D9ParallaxMapRenderer::~CD3D9ParallaxMapRenderer() + { + if (CallBack == this) + CallBack = 0; + } + + bool CD3D9ParallaxMapRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) + { + if (vtxtype != video::EVT_TANGENTS) + { + os::Printer::log("Error: Parallax map renderer only supports vertices of type EVT_TANGENTS", ELL_ERROR); + return false; + } + + return CD3D9ShaderMaterialRenderer::OnRender(service, vtxtype); + } + + + void CD3D9ParallaxMapRenderer::OnSetMaterial(const video::SMaterial& material, + const video::SMaterial& lastMaterial, + bool resetAllRenderstates, video::IMaterialRendererServices* services) + { + CD3D9ShaderMaterialRenderer::OnSetMaterial(material, lastMaterial, + resetAllRenderstates, services); + + CurrentScale = material.MaterialTypeParam; + } + + + //! Returns the render capability of the material. + s32 CD3D9ParallaxMapRenderer::getRenderCapability() const + { + if (Driver->queryFeature(video::EVDF_PIXEL_SHADER_1_4) && + Driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1)) + return 0; + + return 1; + } + + + //! Called by the engine when the vertex and/or pixel shader constants + //! for an material renderer should be set. + void CD3D9ParallaxMapRenderer::OnSetConstants(IMaterialRendererServices* services, s32 userData) + { + video::IVideoDriver* driver = services->getVideoDriver(); + + // set transposed world matrix + services->setVertexShaderConstant(driver->getTransform(video::ETS_WORLD).getTransposed().pointer(), 0, 4); + + // set eye position + + // The viewpoint is at (0., 0., 0.) in eye space. + // Turning this into a vector [0 0 0 1] and multiply it by + // the inverse of the view matrix, the resulting vector is the + // object space location of the camera. + + f32 floats[4] = {0,0,0,1}; + core::matrix4 minv = driver->getTransform(video::ETS_VIEW); + minv.makeInverse(); + minv.multiplyWith1x4Matrix(floats); + services->setVertexShaderConstant(floats, 4, 1); + + // set transposed worldViewProj matrix + core::matrix4 worldViewProj; + worldViewProj = driver->getTransform(video::ETS_PROJECTION); + worldViewProj *= driver->getTransform(video::ETS_VIEW); + worldViewProj *= driver->getTransform(video::ETS_WORLD); + services->setVertexShaderConstant(worldViewProj.getTransposed().pointer(), 8, 4); + + // here we've got to fetch the fixed function lights from the + // driver and set them as constants + + const u32 cnt = driver->getDynamicLightCount(); + + for (u32 i=0; i<2; ++i) + { + SLight light; + + if (igetDynamicLight(i); + else + { + light.DiffuseColor.set(0,0,0); // make light dark + light.Radius = 1.0f; + } + + light.DiffuseColor.a = 1.0f/(light.Radius*light.Radius); // set attenuation + + services->setVertexShaderConstant(reinterpret_cast(&light.Position), 12+(i*2), 1); + services->setVertexShaderConstant(reinterpret_cast(&light.DiffuseColor), 13+(i*2), 1); + } + + // this is not really necessary in d3d9 (used a def instruction), but to be sure: + f32 c95[] = {0.5f, 0.5f, 0.5f, 0.5f}; + services->setVertexShaderConstant(c95, 95, 1); + f32 c96[] = {-1, 1, 1, 1}; + services->setVertexShaderConstant(c96, 96, 1); + + // set scale factor + f32 factor = 0.02f; // default value + if (CurrentScale != 0) + factor = CurrentScale; + + f32 c6[] = {factor, factor, factor, 0}; + services->setPixelShaderConstant(c6, 6, 1); + } + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_DIRECT3D_9_ + diff --git a/source/Irrlicht/CD3D9ParallaxMapRenderer.h b/source/Irrlicht/CD3D9ParallaxMapRenderer.h new file mode 100644 index 00000000..187b6f9d --- /dev/null +++ b/source/Irrlicht/CD3D9ParallaxMapRenderer.h @@ -0,0 +1,63 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_D3D9_PARALLAX_MAPMATERIAL_RENDERER_H_INCLUDED__ +#define __C_D3D9_PARALLAX_MAPMATERIAL_RENDERER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_WINDOWS_ + +#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ +#if defined(__BORLANDC__) || defined (__BCPLUSPLUS__) +#include "irrMath.h" // needed by borland for sqrtf define +#endif +#include + +#include "CD3D9ShaderMaterialRenderer.h" +#include "IShaderConstantSetCallBack.h" + +namespace irr +{ +namespace video +{ + +//! Renderer for normal maps using parallax mapping +class CD3D9ParallaxMapRenderer : + public CD3D9ShaderMaterialRenderer, IShaderConstantSetCallBack +{ +public: + + CD3D9ParallaxMapRenderer( + IDirect3DDevice9* d3ddev, video::IVideoDriver* driver, + s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial); + + ~CD3D9ParallaxMapRenderer(); + + //! Called by the engine when the vertex and/or pixel shader constants for an + //! material renderer should be set. + virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData) _IRR_OVERRIDE_; + + virtual bool OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) _IRR_OVERRIDE_; + + //! Returns the render capability of the material. + virtual s32 getRenderCapability() const _IRR_OVERRIDE_; + + virtual void OnSetMaterial(const SMaterial& material) _IRR_OVERRIDE_ { } + virtual void OnSetMaterial(const video::SMaterial& material, + const video::SMaterial& lastMaterial, + bool resetAllRenderstates, video::IMaterialRendererServices* services) _IRR_OVERRIDE_; + +private: + + f32 CurrentScale; + +}; + +} // end namespace video +} // end namespace irr + +#endif +#endif +#endif + diff --git a/source/Irrlicht/CD3D9RenderTarget.cpp b/source/Irrlicht/CD3D9RenderTarget.cpp new file mode 100644 index 00000000..630c428d --- /dev/null +++ b/source/Irrlicht/CD3D9RenderTarget.cpp @@ -0,0 +1,281 @@ +// Copyright (C) 2015 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CD3D9RenderTarget.h" + +#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ + +#include "IImage.h" +#include "irrMath.h" +#include "irrString.h" + +#include "CD3D9Driver.h" +#include "CD3D9Texture.h" + +namespace irr +{ + namespace video + { + + CD3D9RenderTarget::CD3D9RenderTarget(CD3D9Driver* driver) : DepthStencilSurface(0), Driver(driver) + { +#ifdef _DEBUG + setDebugName("CD3D9RenderTarget"); +#endif + + DriverType = EDT_DIRECT3D9; + Size = Driver->getScreenSize(); + } + + CD3D9RenderTarget::~CD3D9RenderTarget() + { + for (u32 i = 0; i < Surface.size(); ++i) + { + if (Surface[i]) + Surface[i]->Release(); + } + + if (DepthStencilSurface) + DepthStencilSurface->Release(); + + for (u32 i = 0; i < Texture.size(); ++i) + { + if (Texture[i]) + Texture[i]->drop(); + } + + if (DepthStencil) + DepthStencil->drop(); + } + + void CD3D9RenderTarget::setTexture(const core::array& texture, ITexture* depthStencil, const core::array& cubeSurfaces) + { + bool needSizeUpdate = false; + + // Set color attachments. + if ((Texture != texture) || (CubeSurfaces != cubeSurfaces)) + { + needSizeUpdate = true; + CubeSurfaces = cubeSurfaces; // TODO: we can probably avoid some memory allocating/de-allocating if _only_ CubeSurfaces change. + + if (texture.size() > Driver->ActiveRenderTarget.size()) + { + core::stringc message = "This GPU supports up to "; + message += Driver->ActiveRenderTarget.size(); + message += " textures per render target."; + + os::Printer::log(message.c_str(), ELL_WARNING); + } + + const u32 size = core::min_(texture.size(), static_cast(Driver->ActiveRenderTarget.size())); + + for (u32 i = 0; i < Surface.size(); ++i) + { + if (Surface[i]) + Surface[i]->Release(); + } + + Surface.set_used(size); + + core::array prevTextures(Texture); + + Texture.set_used(size); + + for (u32 i = 0; i < size; ++i) + { + CD3D9Texture* currentTexture = (texture[i] && texture[i]->getDriverType() == DriverType) ? static_cast(texture[i]) : 0; + + IDirect3DTexture9* textureID = 0; + IDirect3DCubeTexture9* cubeTextureId = 0; + UINT level = 0; // no support for rendering to to other mip-levels so far + + if (currentTexture) + { + if (currentTexture->getType() == ETT_2D) + textureID = currentTexture->getDX9Texture(); + else if ( currentTexture->getType() == ETT_CUBEMAP ) + cubeTextureId = currentTexture->getDX9CubeTexture(); + } + + if (textureID) + { + Texture[i] = texture[i]; + Texture[i]->grab(); + + IDirect3DSurface9* currentSurface = 0; + textureID->GetSurfaceLevel(level, ¤tSurface); + + Surface[i] = currentSurface; + } + else if ( cubeTextureId ) + { + Texture[i] = texture[i]; + Texture[i]->grab(); + + IDirect3DSurface9* currentSurface = 0; + D3DCUBEMAP_FACES face = (D3DCUBEMAP_FACES)CubeSurfaces[i]; // we use same numbering + cubeTextureId->GetCubeMapSurface(face, level, ¤tSurface); + + Surface[i] = currentSurface; + } + else + { + Surface[i] = 0; + Texture[i] = 0; + } + } + + for (u32 i = 0; i < prevTextures.size(); ++i) + { + if (prevTextures[i]) + prevTextures[i]->drop(); + } + } + + // Set depth and stencil attachments. + + if (DepthStencil != depthStencil) + { + if (DepthStencilSurface) + { + DepthStencilSurface->Release(); + DepthStencilSurface = 0; + } + + if (DepthStencil) + { + DepthStencil->drop(); + DepthStencil = 0; + + DepthStencilSurface = 0; + } + + needSizeUpdate = true; + CD3D9Texture* currentTexture = (depthStencil && depthStencil->getDriverType() == DriverType) ? static_cast(depthStencil) : 0; + + if (currentTexture) + { + if (currentTexture->getType() == ETT_2D) + { + IDirect3DTexture9* textureID = currentTexture->getDX9Texture(); + if (textureID) + { + const ECOLOR_FORMAT textureFormat = depthStencil->getColorFormat(); + if (IImage::isDepthFormat(textureFormat)) + { + DepthStencil = depthStencil; + DepthStencil->grab(); + + IDirect3DSurface9* currentSurface = 0; + textureID->GetSurfaceLevel(0, ¤tSurface); + + DepthStencilSurface = currentSurface; + } + else + { + os::Printer::log("Ignoring depth/stencil texture without depth color format.", ELL_WARNING); + } + } + } + else + os::Printer::log("This driver doesn't support depth/stencil to cubemaps.", ELL_WARNING); + } + } + + if (needSizeUpdate) + { + // Set size required for a viewport. + + bool sizeDetected = false; + + for (u32 i = 0; i < Texture.size(); ++i) + { + if (Texture[i]) + { + Size = Texture[i]->getSize(); + sizeDetected = true; + + break; + } + } + + if (!sizeDetected) + { + if (DepthStencil) + Size = DepthStencil->getSize(); + else + Size = Driver->getScreenSize(); + } + } + } + + const core::dimension2d& CD3D9RenderTarget::getSize() const + { + return Size; + } + + IDirect3DSurface9* CD3D9RenderTarget::getSurface(u32 id) const + { + return (id < Surface.size()) ? Surface[id] : 0; + } + + u32 CD3D9RenderTarget::getSurfaceCount() const + { + return Surface.size(); + } + + IDirect3DSurface9* CD3D9RenderTarget::getDepthStencilSurface() const + { + return DepthStencilSurface; + } + + void CD3D9RenderTarget::releaseSurfaces() + { + for (u32 i = 0; i < Surface.size(); ++i) + { + if (Surface[i]) + { + Surface[i]->Release(); + Surface[i] = 0; + } + } + + if (DepthStencilSurface) + { + DepthStencilSurface->Release(); + DepthStencilSurface = 0; + } + } + + void CD3D9RenderTarget::generateSurfaces() + { + for (u32 i = 0; i < Surface.size(); ++i) + { + if (!Surface[i] && Texture[i]) + { + IDirect3DTexture9* currentTexture = static_cast(Texture[i])->getDX9Texture(); + if ( currentTexture ) + { + IDirect3DSurface9* currentSurface = 0; + currentTexture->GetSurfaceLevel(0, ¤tSurface); + Surface[i] = currentSurface; + } + } + } + + if (!DepthStencilSurface && DepthStencil) + { + IDirect3DTexture9* currentTexture = static_cast(DepthStencil)->getDX9Texture(); + if ( currentTexture ) + { + IDirect3DSurface9* currentSurface = 0; + currentTexture->GetSurfaceLevel(0, ¤tSurface); + DepthStencilSurface = currentSurface; + } + } + } + } +} + +#endif diff --git a/source/Irrlicht/CD3D9RenderTarget.h b/source/Irrlicht/CD3D9RenderTarget.h new file mode 100644 index 00000000..1f643f09 --- /dev/null +++ b/source/Irrlicht/CD3D9RenderTarget.h @@ -0,0 +1,60 @@ +// Copyright (C) 2015 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OPEN_GL_RENDER_TARGET_H_INCLUDED__ +#define __C_OPEN_GL_RENDER_TARGET_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ + +#include "IRenderTarget.h" + +#include "dimension2d.h" +#include "os.h" + +#include + +namespace irr +{ + namespace video + { + + class CD3D9Driver; + + class CD3D9RenderTarget : public IRenderTarget + { + public: + CD3D9RenderTarget(CD3D9Driver* driver); + virtual ~CD3D9RenderTarget(); + + virtual void setTexture(const core::array& texture, ITexture* depthStencil, const core::array& cubeSurfaces) _IRR_OVERRIDE_; + + const core::dimension2d& getSize() const; + + IDirect3DSurface9* getSurface(u32 id) const; + + u32 getSurfaceCount() const; + + IDirect3DSurface9* getDepthStencilSurface() const; + + void releaseSurfaces(); + + void generateSurfaces(); + + protected: + core::dimension2d Size; + + core::array Surface; + + IDirect3DSurface9* DepthStencilSurface; + + CD3D9Driver* Driver; + }; + + } +} + +#endif +#endif diff --git a/source/Irrlicht/CD3D9ShaderMaterialRenderer.cpp b/source/Irrlicht/CD3D9ShaderMaterialRenderer.cpp new file mode 100644 index 00000000..fecc85fa --- /dev/null +++ b/source/Irrlicht/CD3D9ShaderMaterialRenderer.cpp @@ -0,0 +1,539 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ + +#include "CD3D9ShaderMaterialRenderer.h" +#include "IShaderConstantSetCallBack.h" +#include "IMaterialRendererServices.h" +#include "IVideoDriver.h" +#include "os.h" +#include "irrString.h" + +#ifndef _IRR_D3D_NO_SHADER_DEBUGGING +#include +#endif + + +namespace irr +{ +namespace video +{ + +//! Public constructor +CD3D9ShaderMaterialRenderer::CD3D9ShaderMaterialRenderer(IDirect3DDevice9* d3ddev, video::IVideoDriver* driver, + s32& outMaterialTypeNr, const c8* vertexShaderProgram, const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, IMaterialRenderer* baseMaterial, s32 userData) +: pID3DDevice(d3ddev), Driver(driver), CallBack(callback), BaseMaterial(baseMaterial), + VertexShader(0), OldVertexShader(0), PixelShader(0), UserData(userData) +{ + #ifdef _DEBUG + setDebugName("CD3D9ShaderMaterialRenderer"); + #endif + + if (BaseMaterial) + BaseMaterial->grab(); + + if (CallBack) + CallBack->grab(); + + init(outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram); +} + + +//! constructor only for use by derived classes who want to +//! create a fall back material for example. +CD3D9ShaderMaterialRenderer::CD3D9ShaderMaterialRenderer(IDirect3DDevice9* d3ddev, + video::IVideoDriver* driver, + IShaderConstantSetCallBack* callback, + IMaterialRenderer* baseMaterial, s32 userData) +: pID3DDevice(d3ddev), Driver(driver), CallBack(callback), BaseMaterial(baseMaterial), + VertexShader(0), OldVertexShader(0), PixelShader(0), UserData(userData) +{ + #ifdef _DEBUG + setDebugName("CD3D9ShaderMaterialRenderer"); + #endif + + if (BaseMaterial) + BaseMaterial->grab(); + + if (CallBack) + CallBack->grab(); +} + + +void CD3D9ShaderMaterialRenderer::init(s32& outMaterialTypeNr, + const c8* vertexShaderProgram, const c8* pixelShaderProgram) +{ + outMaterialTypeNr = -1; + + // create vertex shader + if (!createVertexShader(vertexShaderProgram)) + return; + + // create pixel shader + if (!createPixelShader(pixelShaderProgram)) + return; + + // register myself as new material + outMaterialTypeNr = Driver->addMaterialRenderer(this); +} + + +//! Destructor +CD3D9ShaderMaterialRenderer::~CD3D9ShaderMaterialRenderer() +{ + if (CallBack) + CallBack->drop(); + + if (VertexShader) + VertexShader->Release(); + + if (PixelShader) + PixelShader->Release(); + + if (BaseMaterial) + BaseMaterial->drop(); +} + + +bool CD3D9ShaderMaterialRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) +{ + // call callback to set shader constants + if (CallBack && (VertexShader || PixelShader)) + CallBack->OnSetConstants(service, UserData); + + return true; +} + + +void CD3D9ShaderMaterialRenderer::OnSetMaterial(const video::SMaterial& material, const video::SMaterial& lastMaterial, + bool resetAllRenderstates, video::IMaterialRendererServices* services) +{ + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + if (VertexShader) + { + // save old vertex shader + pID3DDevice->GetVertexShader(&OldVertexShader); + + // set new vertex shader + if (FAILED(pID3DDevice->SetVertexShader(VertexShader))) + os::Printer::log("Could not set vertex shader.", ELL_WARNING); + } + + // set new pixel shader + if (PixelShader) + { + if (FAILED(pID3DDevice->SetPixelShader(PixelShader))) + os::Printer::log("Could not set pixel shader.", ELL_WARNING); + } + } + + services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (BaseMaterial) + BaseMaterial->OnSetMaterial(material, lastMaterial, resetAllRenderstates, services); + + if (CallBack) + CallBack->OnSetMaterial(material); +} + + +void CD3D9ShaderMaterialRenderer::OnUnsetMaterial() +{ + if (VertexShader) + pID3DDevice->SetVertexShader(OldVertexShader); + + if (PixelShader) + pID3DDevice->SetPixelShader(0); + + if (BaseMaterial) + BaseMaterial->OnUnsetMaterial(); +} + + +//! Returns if the material is transparent. The scene management needs to know this +//! for being able to sort the materials by opaque and transparent. +bool CD3D9ShaderMaterialRenderer::isTransparent() const +{ + return BaseMaterial ? BaseMaterial->isTransparent() : false; +} + + +bool CD3D9ShaderMaterialRenderer::createPixelShader(const c8* pxsh) +{ + if (!pxsh) + return true; + + // compile shader + + LPD3DXBUFFER code = 0; + LPD3DXBUFFER errors = 0; + + #ifdef _IRR_D3D_NO_SHADER_DEBUGGING + + // compile shader without debug info + stubD3DXAssembleShader(pxsh, (UINT)strlen(pxsh), 0, 0, 0, &code, &errors); + #else + + // compile shader and emit some debug information to + // make it possible to debug the shader in visual studio + + static int irr_dbg_file_nr = 0; + ++irr_dbg_file_nr; + char tmp[32]; + sprintf(tmp, "irr_d3d9_dbg_shader_%d.psh", irr_dbg_file_nr); + + FILE* f = fopen(tmp, "wb"); + fwrite(pxsh, strlen(pxsh), 1, f); + fflush(f); + fclose(f); + + stubD3DXAssembleShaderFromFile(tmp, 0, 0, D3DXSHADER_DEBUG, &code, &errors); + + #endif + + + if (errors) + { + // print out compilation errors. + os::Printer::log("Pixel shader compilation failed:", ELL_ERROR); + os::Printer::log((c8*)errors->GetBufferPointer(), ELL_ERROR); + + if (code) + code->Release(); + + errors->Release(); + return false; + } + + if (FAILED(pID3DDevice->CreatePixelShader((DWORD*)code->GetBufferPointer(), &PixelShader))) + { + os::Printer::log("Could not create pixel shader.", ELL_ERROR); + code->Release(); + return false; + } + + code->Release(); + return true; +} + + +bool CD3D9ShaderMaterialRenderer::createVertexShader(const char* vtxsh) +{ + if (!vtxsh) + return true; + + // compile shader + + LPD3DXBUFFER code = 0; + LPD3DXBUFFER errors = 0; + + #ifdef _IRR_D3D_NO_SHADER_DEBUGGING + + // compile shader without debug info + stubD3DXAssembleShader(vtxsh, (UINT)strlen(vtxsh), 0, 0, 0, &code, &errors); + + #else + + // compile shader and emit some debug information to + // make it possible to debug the shader in visual studio + + static int irr_dbg_file_nr = 0; + ++irr_dbg_file_nr; + char tmp[32]; + sprintf(tmp, "irr_d3d9_dbg_shader_%d.vsh", irr_dbg_file_nr); + + FILE* f = fopen(tmp, "wb"); + fwrite(vtxsh, strlen(vtxsh), 1, f); + fflush(f); + fclose(f); + + stubD3DXAssembleShaderFromFile(tmp, 0, 0, D3DXSHADER_DEBUG, &code, &errors); + + #endif + + if (errors) + { + // print out compilation errors. + os::Printer::log("Vertex shader compilation failed:", ELL_ERROR); + os::Printer::log((c8*)errors->GetBufferPointer(), ELL_ERROR); + + if (code) + code->Release(); + + errors->Release(); + return false; + } + + if (!code || FAILED(pID3DDevice->CreateVertexShader((DWORD*)code->GetBufferPointer(), &VertexShader))) + { + os::Printer::log("Could not create vertex shader.", ELL_ERROR); + if (code) + code->Release(); + return false; + } + + code->Release(); + return true; +} + + +HRESULT CD3D9ShaderMaterialRenderer::stubD3DXAssembleShader(LPCSTR pSrcData, + UINT SrcDataLen, CONST D3DXMACRO* pDefines, + LPD3DXINCLUDE pInclude, DWORD Flags, LPD3DXBUFFER* ppShader, + LPD3DXBUFFER* ppErrorMsgs) +{ + // Because Irrlicht needs to be able to start up even without installed d3d dlls, it + // needs to load external d3d dlls manually. examples for the dlls are: + // SDK dll name D3DX_SDK_VERSION + // Summer 2004: no dll 22 + // February 2005: d3dx9_24.dll 24 + // April 2005: d3dx9_25.dll 25 + // June 2005: d3dx9_26.dll 26 + // August 2005: d3dx9_27.dll 27 + // October 2005, + // December 2005: d3dx9_28.dll 28 + + #if ( D3DX_SDK_VERSION < 24 ) + // directly link functions, old d3d sdks didn't try to load external dlls + // when linking to the d3dx9.lib + #ifdef _MSC_VER + #pragma comment (lib, "d3dx9.lib") + #endif + + // invoke static linked function + return D3DXAssembleShader(pSrcData, SrcDataLen, pDefines, pInclude, + Flags, ppShader, ppErrorMsgs); + #else + { + // try to load shader functions from the dll and print error if failed. + + // D3DXAssembleShader signature + typedef HRESULT (WINAPI *AssembleShaderFunction)(LPCSTR pSrcData, UINT SrcDataLen, + CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude, + DWORD Flags, LPD3DXBUFFER* ppShader, + LPD3DXBUFFER* ppErrorMsgs); + + static bool LoadFailed = false; + static AssembleShaderFunction pFn = 0; + + if (!pFn && !LoadFailed) + { + // try to load dll + io::path strDllName = "d3dx9_"; + strDllName += (int)D3DX_SDK_VERSION; + strDllName += ".dll"; + + HMODULE hMod = LoadLibrary(strDllName.c_str()); + if (hMod) + pFn = (AssembleShaderFunction)GetProcAddress(hMod, "D3DXAssembleShader"); + + if (!pFn) + { + LoadFailed = true; + os::Printer::log("Could not load shader function D3DXAssembleShader from dll, shaders disabled", + strDllName.c_str(), ELL_ERROR); + } + } + + if (pFn) + { + // call already loaded function + return (*pFn)(pSrcData, SrcDataLen, pDefines, pInclude, Flags, ppShader, ppErrorMsgs); + } + } + #endif // D3DX_SDK_VERSION < 24 + + return 0; +} + + +HRESULT CD3D9ShaderMaterialRenderer::stubD3DXAssembleShaderFromFile(LPCSTR pSrcFile, + CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude, DWORD Flags, + LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs) +{ + // wondering what I'm doing here? + // see comment in CD3D9ShaderMaterialRenderer::stubD3DXAssembleShader() + + #if ( D3DX_SDK_VERSION < 24 ) + // directly link functions, old d3d sdks didn't try to load external dlls + // when linking to the d3dx9.lib + #ifdef _MSC_VER + #pragma comment (lib, "d3dx9.lib") + #endif + + // invoke static linked function + return D3DXAssembleShaderFromFileA(pSrcFile, pDefines, pInclude, Flags, + ppShader, ppErrorMsgs); + #else + { + // try to load shader functions from the dll and print error if failed. + + // D3DXAssembleShaderFromFileA signature + typedef HRESULT (WINAPI *AssembleShaderFromFileFunction)(LPCSTR pSrcFile, + CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude, DWORD Flags, + LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs); + + static bool LoadFailed = false; + static AssembleShaderFromFileFunction pFn = 0; + + if (!pFn && !LoadFailed) + { + // try to load dll + io::path strDllName = "d3dx9_"; + strDllName += (int)D3DX_SDK_VERSION; + strDllName += ".dll"; + + HMODULE hMod = LoadLibrary(strDllName.c_str()); + if (hMod) + pFn = (AssembleShaderFromFileFunction)GetProcAddress(hMod, "D3DXAssembleShaderFromFileA"); + + if (!pFn) + { + LoadFailed = true; + os::Printer::log("Could not load shader function D3DXAssembleShaderFromFileA from dll, shaders disabled", + strDllName.c_str(), ELL_ERROR); + } + } + + if (pFn) + { + // call already loaded function + return (*pFn)(pSrcFile, pDefines, pInclude, Flags, ppShader, ppErrorMsgs); + } + } + #endif // D3DX_SDK_VERSION < 24 + + return 0; +} + + +HRESULT CD3D9ShaderMaterialRenderer::stubD3DXCompileShader(LPCSTR pSrcData, UINT SrcDataLen, CONST D3DXMACRO* pDefines, + LPD3DXINCLUDE pInclude, LPCSTR pFunctionName, + LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader, + LPD3DXBUFFER* ppErrorMsgs, LPD3DXCONSTANTTABLE* ppConstantTable) +{ + // wondering what I'm doing here? + // see comment in CD3D9ShaderMaterialRenderer::stubD3DXAssembleShader() + + #if ( D3DX_SDK_VERSION < 24 ) + // directly link functions, old d3d sdks didn't try to load external dlls + // when linking to the d3dx9.lib + #ifdef _MSC_VER + #pragma comment (lib, "d3dx9.lib") + #endif + + // invoke static linked function + return D3DXCompileShader(pSrcData, SrcDataLen, pDefines, pInclude, pFunctionName, pProfile, Flags, ppShader, ppErrorMsgs, ppConstantTable); + #else + { + // try to load shader functions from the dll and print error if failed. + + // D3DXCompileShader + typedef HRESULT (WINAPI *D3DXCompileShaderFunction)(LPCSTR pSrcData, UINT SrcDataLen, CONST D3DXMACRO* pDefines, + LPD3DXINCLUDE pInclude, LPCSTR pFunctionName, + LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader, + LPD3DXBUFFER* ppErrorMsgs, LPD3DXCONSTANTTABLE* ppConstantTable); + + static bool LoadFailed = false; + static D3DXCompileShaderFunction pFn = 0; + + if (!pFn && !LoadFailed) + { + // try to load dll + io::path strDllName = "d3dx9_"; + strDllName += (int)D3DX_SDK_VERSION; + strDllName += ".dll"; + + HMODULE hMod = LoadLibrary(strDllName.c_str()); + if (hMod) + pFn = (D3DXCompileShaderFunction)GetProcAddress(hMod, "D3DXCompileShader"); + + if (!pFn) + { + LoadFailed = true; + os::Printer::log("Could not load shader function D3DXCompileShader from dll, shaders disabled", + strDllName.c_str(), ELL_ERROR); + } + } + + if (pFn) + { + // call already loaded function + return (*pFn)(pSrcData, SrcDataLen, pDefines, pInclude, pFunctionName, pProfile, Flags, ppShader, ppErrorMsgs, ppConstantTable); + } + } + #endif // D3DX_SDK_VERSION < 24 + + return 0; +} + +HRESULT CD3D9ShaderMaterialRenderer::stubD3DXCompileShaderFromFile(LPCSTR pSrcFile, CONST D3DXMACRO* pDefines, + LPD3DXINCLUDE pInclude, LPCSTR pFunctionName, + LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs, + LPD3DXCONSTANTTABLE* ppConstantTable) +{ + // wondering what I'm doing here? + // see comment in CD3D9ShaderMaterialRenderer::stubD3DXAssembleShader() + + #if ( D3DX_SDK_VERSION < 24 ) + // directly link functions, old d3d sdks didn't try to load external dlls + // when linking to the d3dx9.lib + #ifdef _MSC_VER + #pragma comment (lib, "d3dx9.lib") + #endif + + // invoke static linked function + return D3DXCompileShaderFromFileA(pSrcFile, pDefines, pInclude, pFunctionName, pProfile, Flags, ppShader, ppErrorMsgs, ppConstantTable); + #else + { + // try to load shader functions from the dll and print error if failed. + + // D3DXCompileShaderFromFileA + typedef HRESULT (WINAPI *D3DXCompileShaderFromFileFunction)(LPCSTR pSrcFile, + CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude, LPCSTR pFunctionName, + LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs, + LPD3DXCONSTANTTABLE* ppConstantTable); + + static bool LoadFailed = false; + static D3DXCompileShaderFromFileFunction pFn = 0; + + if (!pFn && !LoadFailed) + { + // try to load dll + io::path strDllName = "d3dx9_"; + strDllName += (int)D3DX_SDK_VERSION; + strDllName += ".dll"; + + HMODULE hMod = LoadLibrary(strDllName.c_str()); + if (hMod) + pFn = (D3DXCompileShaderFromFileFunction)GetProcAddress(hMod, "D3DXCompileShaderFromFileA"); + + if (!pFn) + { + LoadFailed = true; + os::Printer::log("Could not load shader function D3DXCompileShaderFromFileA from dll, shaders disabled", + strDllName.c_str(), ELL_ERROR); + } + } + + if (pFn) + { + // call already loaded function + return (*pFn)(pSrcFile, pDefines, pInclude, pFunctionName, pProfile, Flags, ppShader, ppErrorMsgs, ppConstantTable); + } + } + #endif // D3DX_SDK_VERSION < 24 + + return 0; +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_DIRECT3D_9_ diff --git a/source/Irrlicht/CD3D9ShaderMaterialRenderer.h b/source/Irrlicht/CD3D9ShaderMaterialRenderer.h new file mode 100644 index 00000000..e7517906 --- /dev/null +++ b/source/Irrlicht/CD3D9ShaderMaterialRenderer.h @@ -0,0 +1,108 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_D3D9_SHADER_MATERIAL_RENDERER_H_INCLUDED__ +#define __C_D3D9_SHADER_MATERIAL_RENDERER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_WINDOWS_ + +#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ +#if defined(__BORLANDC__) || defined (__BCPLUSPLUS__) +#include "irrMath.h" // needed by borland for sqrtf define +#endif +#include + +#include "IMaterialRenderer.h" + +namespace irr +{ +namespace video +{ + +class IVideoDriver; +class IShaderConstantSetCallBack; +class IMaterialRenderer; + +//! Class for using vertex and pixel shaders with D3D9 +class CD3D9ShaderMaterialRenderer : public IMaterialRenderer +{ +public: + + //! Public constructor + CD3D9ShaderMaterialRenderer(IDirect3DDevice9* d3ddev, video::IVideoDriver* driver, + s32& outMaterialTypeNr, const c8* vertexShaderProgram, const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, IMaterialRenderer* baseMaterial, s32 userData); + + //! Destructor + ~CD3D9ShaderMaterialRenderer(); + + virtual void OnSetMaterial(const video::SMaterial& material, const video::SMaterial& lastMaterial, + bool resetAllRenderstates, video::IMaterialRendererServices* services) _IRR_OVERRIDE_; + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_; + + virtual bool OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) _IRR_OVERRIDE_; + + //! Returns if the material is transparent. + virtual bool isTransparent() const _IRR_OVERRIDE_; + + //! Access the callback provided by the users when creating shader materials + virtual IShaderConstantSetCallBack* getShaderConstantSetCallBack() const _IRR_OVERRIDE_ + { + return CallBack; + } + +protected: + + //! constructor only for use by derived classes who want to + //! create a fall back material for example. + CD3D9ShaderMaterialRenderer(IDirect3DDevice9* d3ddev, + video::IVideoDriver* driver, + IShaderConstantSetCallBack* callback, + IMaterialRenderer* baseMaterial, + s32 userData=0); + + void init(s32& outMaterialTypeNr, const c8* vertexShaderProgram, const c8* pixelShaderProgram); + bool createPixelShader(const c8* pxsh); + bool createVertexShader(const char* vtxsh); + + HRESULT stubD3DXAssembleShader(LPCSTR pSrcData, UINT SrcDataLen, + CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude, + DWORD Flags, LPD3DXBUFFER* ppShader, + LPD3DXBUFFER* ppErrorMsgs); + + HRESULT stubD3DXAssembleShaderFromFile(LPCSTR pSrcFile, + CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude, DWORD Flags, + LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs); + + HRESULT stubD3DXCompileShader(LPCSTR pSrcData, UINT SrcDataLen, CONST D3DXMACRO* pDefines, + LPD3DXINCLUDE pInclude, LPCSTR pFunctionName, + LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader, + LPD3DXBUFFER* ppErrorMsgs, LPD3DXCONSTANTTABLE* ppConstantTable); + + HRESULT stubD3DXCompileShaderFromFile(LPCSTR pSrcFile, CONST D3DXMACRO* pDefines, + LPD3DXINCLUDE pInclude, LPCSTR pFunctionName, + LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs, + LPD3DXCONSTANTTABLE* ppConstantTable); + + IDirect3DDevice9* pID3DDevice; + video::IVideoDriver* Driver; + IShaderConstantSetCallBack* CallBack; + IMaterialRenderer* BaseMaterial; + + IDirect3DVertexShader9* VertexShader; + IDirect3DVertexShader9* OldVertexShader; + IDirect3DPixelShader9* PixelShader; + s32 UserData; +}; + + +} // end namespace video +} // end namespace irr + +#endif +#endif +#endif + diff --git a/source/Irrlicht/CD3D9Texture.cpp b/source/Irrlicht/CD3D9Texture.cpp new file mode 100644 index 00000000..42a8df55 --- /dev/null +++ b/source/Irrlicht/CD3D9Texture.cpp @@ -0,0 +1,758 @@ +// Copyright (C) 2002-2012 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" + +#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ + +#include "CD3D9Texture.h" +#include "CD3D9Driver.h" +#include "os.h" + +namespace irr +{ +namespace video +{ + +CD3D9Texture::CD3D9Texture(const io::path& name, const core::array& image, E_TEXTURE_TYPE type, CD3D9Driver* driver) + : ITexture(name, type), Driver(driver), InternalFormat(D3DFMT_UNKNOWN), LockReadOnly(false), LockData(0), LockLayer(0), + MipLevelLocked(0), HardwareMipMaps(false), Device(0), Texture(0), CubeTexture(0), RTTSurface(0) +{ +#ifdef _DEBUG + setDebugName("CD3D9Texture"); +#endif + + _IRR_DEBUG_BREAK_IF(image.size() == 0) + + Device=driver->getExposedVideoData().D3D9.D3DDev9; + + if (Device) + Device->AddRef(); + + DriverType = Driver->getDriverType(); + HasMipMaps = Driver->getTextureCreationFlag(ETCF_CREATE_MIP_MAPS); + HardwareMipMaps = Driver->getTextureCreationFlag(ETCF_AUTO_GENERATE_MIP_MAPS) && Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE); + + getImageValues(image[0]); + + DWORD flags = 0; + + if (HasMipMaps && HardwareMipMaps) + { + LPDIRECT3D9 intf = Driver->getExposedVideoData().D3D9.D3D9; + D3DDISPLAYMODE d3ddm; + intf->GetAdapterDisplayMode(Driver->Params.DisplayAdapter, &d3ddm); + + if (D3D_OK == intf->CheckDeviceFormat(Driver->Params.DisplayAdapter, D3DDEVTYPE_HAL, d3ddm.Format, D3DUSAGE_AUTOGENMIPMAP, D3DRTYPE_TEXTURE, InternalFormat)) + flags = D3DUSAGE_AUTOGENMIPMAP; + else + HardwareMipMaps = false; + } + + HRESULT hr = 0; + + switch (Type) + { + case ETT_2D: + hr = Device->CreateTexture(Size.Width, Size.Height, HasMipMaps ? 0 : 1, flags, InternalFormat, D3DPOOL_MANAGED, &Texture, NULL); + break; + case ETT_CUBEMAP: + hr = Device->CreateCubeTexture(Size.Width, HasMipMaps ? 0 : 1, flags, InternalFormat, D3DPOOL_MANAGED, &CubeTexture, NULL); + break; + default: + _IRR_DEBUG_BREAK_IF(true) + break; + } + + if (FAILED(hr)) + { + // Try again with 16-bit format + if (InternalFormat == D3DFMT_A8R8G8B8) + { + InternalFormat = D3DFMT_A1R5G5B5; + ColorFormat = ECF_A1R5G5B5; + } + else if (InternalFormat == D3DFMT_R8G8B8) // (24 bit is usually failing in d3d9, not sure if it's ever supported) + { + InternalFormat = D3DFMT_R5G6B5; + ColorFormat = ECF_R5G6B5; + } + switch (Type) + { + case ETT_2D: + hr = Device->CreateTexture(Size.Width, Size.Height, HasMipMaps ? 0 : 1, flags, InternalFormat, D3DPOOL_MANAGED, &Texture, NULL); + break; + case ETT_CUBEMAP: + hr = Device->CreateCubeTexture(Size.Width, HasMipMaps ? 0 : 1, flags, InternalFormat, D3DPOOL_MANAGED, &CubeTexture, NULL); + break; + } + } + + core::array tmpImage = image; + bool releaseImageData = false; + + if (SUCCEEDED(hr)) + { + if (OriginalSize != Size || OriginalColorFormat != ColorFormat) + { + releaseImageData = true; + + for (u32 i = 0; i < image.size(); ++i) + { + tmpImage[i] = Driver->createImage(ColorFormat, Size); + + if (image[i]->getDimension() == Size) + image[i]->copyTo(tmpImage[i]); + else + image[i]->copyToScaling(tmpImage[i]); + } + } + + for (u32 i = 0; i < tmpImage.size(); ++i) + uploadTexture(tmpImage[i]->getData(), 0, i); + + bool autoGenerateRequired = true; + + for (u32 i = 0; i < tmpImage.size(); ++i) + { + void* mipmapsData = tmpImage[i]->getMipMapsData(); + + if (autoGenerateRequired || mipmapsData) + regenerateMipMapLevels(mipmapsData, i); + + if (!mipmapsData) + autoGenerateRequired = false; + } + } + else + { + switch (hr ) + { + case D3DERR_INVALIDCALL: + os::Printer::log("Could not create DIRECT3D9 Texture. D3DERR_INVALIDCALL", ELL_WARNING); + break; + case D3DERR_OUTOFVIDEOMEMORY: + os::Printer::log("Could not create DIRECT3D9 Texture. D3DERR_OUTOFVIDEOMEMORY", ELL_WARNING); + break; + case E_OUTOFMEMORY: + os::Printer::log("Could not create DIRECT3D9 Texture. E_OUTOFMEMORY", ELL_WARNING); + break; + default: + os::Printer::log("Could not create DIRECT3D9 Texture.", ELL_WARNING); + } + } + + if (releaseImageData) + { + for (u32 i = 0; i < tmpImage.size(); ++i) + tmpImage[i]->drop(); + } +} + +CD3D9Texture::CD3D9Texture(CD3D9Driver* driver, const core::dimension2d& size, const io::path& name, E_TEXTURE_TYPE type, const ECOLOR_FORMAT format) + : ITexture(name, type), Driver(driver), InternalFormat(D3DFMT_UNKNOWN), LockReadOnly(false), LockData(0), LockLayer(0), + MipLevelLocked(0), HardwareMipMaps(false), Device(0), Texture(0), CubeTexture(0), RTTSurface(0) +{ +#ifdef _DEBUG + setDebugName("CD3D9Texture"); +#endif + + Device = driver->getExposedVideoData().D3D9.D3DDev9; + + if (Device) + Device->AddRef(); + + DriverType = Driver->getDriverType(); + HasMipMaps = false; + IsRenderTarget = true; + + OriginalColorFormat = format; + + if (ECF_UNKNOWN == OriginalColorFormat) + ColorFormat = getBestColorFormat(Driver->getColorFormat()); + else + ColorFormat = OriginalColorFormat; + + OriginalSize = size; + Size = OriginalSize; + + if (!Driver->queryFeature(EVDF_TEXTURE_NPOT)) + { + Size = Size.getOptimalSize(true, !Driver->queryFeature(EVDF_TEXTURE_NSQUARE), true, Driver->Caps.MaxTextureWidth); + + if (Size != OriginalSize) + os::Printer::log("RenderTarget size has to be a power of two", ELL_INFORMATION); + } + + Pitch = Size.Width * IImage::getBitsPerPixelFromFormat(ColorFormat) / 8; + + InternalFormat = Driver->getD3DFormatFromColorFormat(ColorFormat); + + generateRenderTarget(); +} + +CD3D9Texture::~CD3D9Texture() +{ + releaseTexture(); + + if (Device) + Device->Release(); +} + +void* CD3D9Texture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel, u32 layer, E_TEXTURE_LOCK_FLAGS lockFlags) +{ + if (LockData) + return LockData; + + if (IImage::isCompressedFormat(ColorFormat)) + return 0; + + MipLevelLocked = mipmapLevel; + LockReadOnly = (mode == ETLM_READ_ONLY); + LockLayer = layer; + + HRESULT hr; + D3DLOCKED_RECT rect; + + if (!IsRenderTarget) + { + if (Texture) + { + hr = Texture->LockRect(MipLevelLocked, &rect, 0, LockReadOnly ? D3DLOCK_READONLY : 0); + } + else if (CubeTexture) + { + _IRR_DEBUG_BREAK_IF(layer > 5) + + hr = CubeTexture->LockRect(static_cast<_D3DCUBEMAP_FACES>(layer), MipLevelLocked, &rect, 0, LockReadOnly ? D3DLOCK_READONLY : 0); + } + else + { + os::Printer::log("Could not lock DIRECT3D9 Texture. Missing internal D3D texture.", ELL_ERROR); + return 0; + } + + if (FAILED(hr)) + { + os::Printer::log("Could not lock DIRECT3D9 Texture.", ELL_ERROR); + return 0; + } + } + else + { + if (!RTTSurface) + { + // Make RTT surface large enough for all miplevels (including 0) + D3DSURFACE_DESC desc; + if (Texture) + Texture->GetLevelDesc(0, &desc); + else if (CubeTexture) + CubeTexture->GetLevelDesc(0, &desc); + hr = Device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &RTTSurface, 0); + if (FAILED(hr)) + { + os::Printer::log("Could not lock DIRECT3D9 Texture", "Offscreen surface creation failed.", ELL_ERROR); + return 0; + } + } + + IDirect3DSurface9 *surface = 0; + if (Texture) + hr = Texture->GetSurfaceLevel(MipLevelLocked, &surface); + else if (CubeTexture) + hr = CubeTexture->GetCubeMapSurface(static_cast<_D3DCUBEMAP_FACES>(layer), MipLevelLocked, &surface); + if (FAILED(hr)) + { + os::Printer::log("Could not lock DIRECT3D9 Texture", "Could not get surface.", ELL_ERROR); + return 0; + } + hr = Device->GetRenderTargetData(surface, RTTSurface); + surface->Release(); + if(FAILED(hr)) + { + os::Printer::log("Could not lock DIRECT3D9 Texture", "Data copy failed.", ELL_ERROR); + return 0; + } + hr = RTTSurface->LockRect(&rect, 0, LockReadOnly ? D3DLOCK_READONLY : 0); + if(FAILED(hr)) + { + os::Printer::log("Could not lock DIRECT3D9 Texture", "LockRect failed.", ELL_ERROR); + return 0; + } + } + + LockData = rect.pBits; + + return LockData; +} + +void CD3D9Texture::unlock() +{ + if (!LockData) + return; + + if (!IsRenderTarget) + { + if (Texture) + { + Texture->UnlockRect(MipLevelLocked); + } + else if (CubeTexture) + { + CubeTexture->UnlockRect(static_cast<_D3DCUBEMAP_FACES>(LockLayer), MipLevelLocked); + } + } + else if (RTTSurface) + { + RTTSurface->UnlockRect(); + } + + LockReadOnly = false; + LockData = 0; + LockLayer = 0; +} + +void CD3D9Texture::regenerateMipMapLevels(void* data, u32 layer) +{ + if (!HasMipMaps || (Size.Width <= 1 && Size.Height <= 1)) + return; + + if ( HardwareMipMaps ) + { + // Can't update with custom data with those unfortunately + // Also MSDN docs don't mention it, but GenerateMipSubLevels only works when AUTOGENMIPMAP is set. + // So we can't call this to get hardware mipmaps when not setting AUTOGENMIPMAP. + if (Texture) + Texture->GenerateMipSubLevels(); + else if (CubeTexture) + CubeTexture->GenerateMipSubLevels(); + } + else if (data) + { + u32 width = Size.Width; + u32 height = Size.Height; + u8* tmpData = static_cast(data); + u32 dataSize = 0; + u32 level = 0; + + do + { + if (width > 1) + width >>= 1; + + if (height > 1) + height >>= 1; + + dataSize = IImage::getDataSizeFromFormat(ColorFormat, width, height); + ++level; + + uploadTexture(tmpData, level, layer); + + tmpData += dataSize; + } while (width != 1 || height != 1); + } + else + { + createManualMipMaps(1); + } +} + +void CD3D9Texture::copy16BitMipMap(char* src, char* tgt, + s32 width, s32 height, + s32 pitchsrc, s32 pitchtgt) const +{ + for (s32 y=0; yGetSurfaceLevel(level-1, &upperSurface); + if (FAILED(hr) || !upperSurface) + { + os::Printer::log("Could not get upper surface level for mip map generation", ELL_WARNING); + return false; + } + + // get lower level + hr = Texture->GetSurfaceLevel(level, &lowerSurface); + if (FAILED(hr) || !lowerSurface) + { + os::Printer::log("Could not get lower surface level for mip map generation", ELL_WARNING); + upperSurface->Release(); + return false; + } + + D3DSURFACE_DESC upperDesc, lowerDesc; + upperSurface->GetDesc(&upperDesc); + lowerSurface->GetDesc(&lowerDesc); + + D3DLOCKED_RECT upperlr; + D3DLOCKED_RECT lowerlr; + + // lock upper surface + if (FAILED(upperSurface->LockRect(&upperlr, NULL, 0))) + { + upperSurface->Release(); + lowerSurface->Release(); + os::Printer::log("Could not lock upper texture for mip map generation", ELL_WARNING); + return false; + } + + // lock lower surface + if (FAILED(lowerSurface->LockRect(&lowerlr, NULL, 0))) + { + upperSurface->UnlockRect(); + upperSurface->Release(); + lowerSurface->Release(); + os::Printer::log("Could not lock lower texture for mip map generation", ELL_WARNING); + return false; + } + + if (upperDesc.Format != lowerDesc.Format) + { + os::Printer::log("Cannot copy mip maps with different formats.", ELL_WARNING); + } + else + { + if ((upperDesc.Format == D3DFMT_A1R5G5B5) || (upperDesc.Format == D3DFMT_R5G6B5)) + copy16BitMipMap((char*)upperlr.pBits, (char*)lowerlr.pBits, + lowerDesc.Width, lowerDesc.Height, + upperlr.Pitch, lowerlr.Pitch); + else + if (upperDesc.Format == D3DFMT_A8R8G8B8) + copy32BitMipMap((char*)upperlr.pBits, (char*)lowerlr.pBits, + lowerDesc.Width, lowerDesc.Height, + upperlr.Pitch, lowerlr.Pitch); + else + os::Printer::log("Unsupported mipmap format, cannot copy.", ELL_WARNING); + } + + bool result=true; + // unlock + if (FAILED(upperSurface->UnlockRect())) + result=false; + if (FAILED(lowerSurface->UnlockRect())) + result=false; + + // release + upperSurface->Release(); + lowerSurface->Release(); + + if (!result || (upperDesc.Width <= 3 && upperDesc.Height <= 3)) + return result; // stop generating levels + + // generate next level + return createManualMipMaps(level+1); +} + + +IDirect3DBaseTexture9* CD3D9Texture::getDX9BaseTexture() const +{ + return (Texture) ? static_cast(Texture) : static_cast(CubeTexture); +} + +IDirect3DTexture9* CD3D9Texture::getDX9Texture() const +{ + return Texture; +} + +IDirect3DCubeTexture9* CD3D9Texture::getDX9CubeTexture() const +{ + return CubeTexture; +} + +void CD3D9Texture::releaseTexture() +{ + if (RTTSurface) + { + if (RTTSurface->Release() == 0) + RTTSurface = 0; + } + + if (Texture) + { + if (Texture->Release() == 0) + Texture = 0; + } + + if (CubeTexture) + { + if (CubeTexture->Release() == 0) + CubeTexture = 0; + } +} + +void CD3D9Texture::generateRenderTarget() +{ + DWORD flags = (IImage::isDepthFormat(ColorFormat)) ? D3DUSAGE_DEPTHSTENCIL : D3DUSAGE_RENDERTARGET; + + HRESULT hr = 0; + + switch (Type) + { + case ETT_2D: + if (!Texture ) + hr = Device->CreateTexture(Size.Width, Size.Height, 1, flags, InternalFormat, D3DPOOL_DEFAULT, &Texture, NULL); + break; + case ETT_CUBEMAP: + if (!CubeTexture) + hr = Device->CreateCubeTexture(Size.Width, 1, flags, InternalFormat, D3DPOOL_DEFAULT, &CubeTexture, NULL); + break; + default: + _IRR_DEBUG_BREAK_IF(true) + break; + } + + if (FAILED(hr)) + { + if (D3DERR_INVALIDCALL == hr) + os::Printer::log("Could not create render target texture", "Invalid Call", irr::ELL_ERROR); + else if (D3DERR_OUTOFVIDEOMEMORY == hr) + os::Printer::log("Could not create render target texture", "Out of Video Memory", irr::ELL_ERROR); + else if (E_OUTOFMEMORY == hr) + os::Printer::log("Could not create render target texture", "Out of Memory", irr::ELL_ERROR); + else + os::Printer::log("Could not create render target texture", irr::ELL_ERROR); + core::stringc params("Width:"); + params += (unsigned int)Size.Width; + params += " Height: "; + params += (unsigned int)Size.Height; + params += " flag: "; + params += (unsigned int)flags; + params += " format"; + params += (unsigned int)InternalFormat; + params += " Type: "; + params += (unsigned int)Type; + os::Printer::log(params.c_str(), irr::ELL_ERROR); + } +} + +ECOLOR_FORMAT CD3D9Texture::getBestColorFormat(ECOLOR_FORMAT format) +{ + // We only try for to adapt "simple" formats + ECOLOR_FORMAT destFormat = (format <= ECF_A8R8G8B8) ? ECF_A8R8G8B8 : format; + + switch (format) + { + case ECF_A1R5G5B5: + if (!Driver->getTextureCreationFlag(ETCF_ALWAYS_32_BIT)) + destFormat = ECF_A1R5G5B5; + break; + case ECF_R5G6B5: + if (!Driver->getTextureCreationFlag(ETCF_ALWAYS_32_BIT)) + destFormat = ECF_R5G6B5; + break; + case ECF_A8R8G8B8: + if (Driver->getTextureCreationFlag(ETCF_ALWAYS_16_BIT) || + Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED)) + destFormat = ECF_A1R5G5B5; + break; + case ECF_R8G8B8: + // Note: Using ECF_A8R8G8B8 even when ETCF_ALWAYS_32_BIT is not set as 24 bit textures fail with too many cards + if (Driver->getTextureCreationFlag(ETCF_ALWAYS_16_BIT) || Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED)) + destFormat = ECF_A1R5G5B5; + default: + break; + } + + if (Driver->getTextureCreationFlag(ETCF_NO_ALPHA_CHANNEL)) + { + switch (destFormat) + { + case ECF_A1R5G5B5: + destFormat = ECF_R5G6B5; + break; + case ECF_A8R8G8B8: + destFormat = ECF_R8G8B8; + break; + default: + break; + } + } + + return destFormat; +} + +void CD3D9Texture::getImageValues(const IImage* image) +{ + OriginalColorFormat = image->getColorFormat(); + ColorFormat = getBestColorFormat(OriginalColorFormat); + + InternalFormat = Driver->getD3DFormatFromColorFormat(ColorFormat); + + if (IImage::isCompressedFormat(image->getColorFormat())) + { + HardwareMipMaps = false; + } + + OriginalSize = image->getDimension(); + Size = OriginalSize; + + if (Size.Width == 0 || Size.Height == 0) + { + os::Printer::log("Invalid size of image for texture.", ELL_ERROR); + return; + } + + const f32 ratio = (f32)Size.Width / (f32)Size.Height; + + if ((Size.Width > Driver->Caps.MaxTextureWidth) && (ratio >= 1.f)) + { + Size.Width = Driver->Caps.MaxTextureWidth; + Size.Height = (u32)(Driver->Caps.MaxTextureWidth / ratio); + } + else if (Size.Height > Driver->Caps.MaxTextureHeight) + { + Size.Height = Driver->Caps.MaxTextureHeight; + Size.Width = (u32)(Driver->Caps.MaxTextureHeight * ratio); + } + + bool needSquare = (!Driver->queryFeature(EVDF_TEXTURE_NSQUARE) || Type == ETT_CUBEMAP); + + Size = Size.getOptimalSize(!Driver->queryFeature(EVDF_TEXTURE_NPOT), needSquare, true, Driver->Caps.MaxTextureWidth); + + Pitch = Size.Width * IImage::getBitsPerPixelFromFormat(ColorFormat) / 8; +} + +void CD3D9Texture::uploadTexture(void* data, u32 mipmapLevel, u32 layer) +{ + if (!data) + return; + + u32 width = Size.Width >> mipmapLevel; + u32 height = Size.Height >> mipmapLevel; + + u32 dataSize = IImage::getDataSizeFromFormat(ColorFormat, width, height); + + HRESULT hr = 0; + + D3DLOCKED_RECT lockRectangle; + + if (Texture) + { + hr = Texture->LockRect(mipmapLevel, &lockRectangle, 0, 0); + } + else if (CubeTexture) + { + _IRR_DEBUG_BREAK_IF(layer > 5) + + hr = CubeTexture->LockRect(static_cast<_D3DCUBEMAP_FACES>(layer), mipmapLevel, &lockRectangle, 0, 0); + } + + if (FAILED(hr)) + { + os::Printer::log("Texture data not copied", "Could not LockRect D3D9 Texture.", ELL_ERROR); + return; + } + + memcpy(lockRectangle.pBits, data, dataSize); + + if (Texture) + { + hr = Texture->UnlockRect(mipmapLevel); + } + else if (CubeTexture) + { + hr = CubeTexture->UnlockRect(static_cast<_D3DCUBEMAP_FACES>(layer), mipmapLevel); + } + + if (FAILED(hr)) + { + os::Printer::log("Texture data not copied", "Could not UnlockRect D3D9 Texture.", ELL_ERROR); + } +} + +} +} + +#endif diff --git a/source/Irrlicht/CD3D9Texture.h b/source/Irrlicht/CD3D9Texture.h new file mode 100644 index 00000000..879f1437 --- /dev/null +++ b/source/Irrlicht/CD3D9Texture.h @@ -0,0 +1,91 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_DIRECTX9_TEXTURE_H_INCLUDED__ +#define __C_DIRECTX9_TEXTURE_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ + +#include "irrArray.h" +#include "ITexture.h" +#include "IImage.h" +#if defined(__BORLANDC__) || defined (__BCPLUSPLUS__) +#include "irrMath.h" // needed by borland for sqrtf define +#endif +#include + +namespace irr +{ +namespace video +{ + +class CD3D9Driver; + +class CD3D9Texture : public ITexture +{ +public: + CD3D9Texture(const io::path& name, const core::array& image, E_TEXTURE_TYPE type, CD3D9Driver* driver); + + CD3D9Texture(CD3D9Driver* driver, const core::dimension2d& size, const io::path& name, E_TEXTURE_TYPE type, const ECOLOR_FORMAT format = ECF_UNKNOWN); + + virtual ~CD3D9Texture(); + + virtual void* lock(E_TEXTURE_LOCK_MODE mode = ETLM_READ_WRITE, u32 mipmapLevel=0, u32 layer = 0, E_TEXTURE_LOCK_FLAGS lockFlags = ETLF_FLIP_Y_UP_RTT) _IRR_OVERRIDE_; + + virtual void unlock() _IRR_OVERRIDE_; + + virtual void regenerateMipMapLevels(void* data = 0, u32 layer = 0) _IRR_OVERRIDE_; + + IDirect3DBaseTexture9* getDX9BaseTexture() const; + IDirect3DTexture9* getDX9Texture() const; + IDirect3DCubeTexture9* getDX9CubeTexture() const; + +private: + friend class CD3D9Driver; + + void releaseTexture(); + + void generateRenderTarget(); + + ECOLOR_FORMAT getBestColorFormat(ECOLOR_FORMAT format); + + void getImageValues(const IImage* image); + + void uploadTexture(void* data, u32 mipmapLevel, u32 layer); + + //! Helper function for mipmap generation. + bool createManualMipMaps(u32 level); + + //! Helper function for mipmap generation. + void copy16BitMipMap(char* src, char* tgt, + s32 width, s32 height, s32 pitchsrc, s32 pitchtgt) const; + + //! Helper function for mipmap generation. + void copy32BitMipMap(char* src, char* tgt, + s32 width, s32 height, s32 pitchsrc, s32 pitchtgt) const; + + + CD3D9Driver* Driver; + + D3DFORMAT InternalFormat; + + bool LockReadOnly; + void* LockData; + u32 LockLayer; + u32 MipLevelLocked; + + bool HardwareMipMaps; + + IDirect3DDevice9* Device; + IDirect3DTexture9* Texture; + IDirect3DCubeTexture9* CubeTexture; + IDirect3DSurface9* RTTSurface; +}; + +} +} + +#endif +#endif diff --git a/source/Irrlicht/CDMFLoader.cpp b/source/Irrlicht/CDMFLoader.cpp new file mode 100644 index 00000000..0e42363a --- /dev/null +++ b/source/Irrlicht/CDMFLoader.cpp @@ -0,0 +1,431 @@ +// Copyright (C) 2002-2012 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 originally written by Salvatore Russo. +// I (Nikolaus Gebhardt) did some minor modifications and changes to it and +// integrated it into Irrlicht. +// Thanks a lot to Salvatore for his work on this and that he gave me +// his permission to add it into Irrlicht using the zlib license. +/* + CDMFLoader by Salvatore Russo (September 2005) + + See the header file for additional information including use and distribution rights. +*/ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_DMF_LOADER_ + +#ifdef _DEBUG +#define _IRR_DMF_DEBUG_ +#include "os.h" +#endif + +#include "CDMFLoader.h" +#include "CMeshTextureLoader.h" +#include "ISceneManager.h" +#include "IAttributes.h" +#include "SAnimatedMesh.h" +#include "SSkinMeshBuffer.h" +#include "irrString.h" +#include "irrMath.h" +#include "dmfsupport.h" + +namespace irr +{ +namespace scene +{ + +/** Constructor*/ +CDMFLoader::CDMFLoader(ISceneManager* smgr, io::IFileSystem* filesys) +: SceneMgr(smgr), FileSystem(filesys) +{ + #ifdef _DEBUG + IReferenceCounted::setDebugName("CDMFLoader"); + #endif + + TextureLoader = new CMeshTextureLoader( FileSystem, SceneMgr->getVideoDriver() ); +} + +void CDMFLoader::addMaterialPath(core::stringc& filename, const core::stringc& matPath) +{ + c8 last = matPath.lastChar(); + if ( last == '/' || last == '\\' ) + filename = matPath+filename; + else + { + core::stringc matPathSlash(matPath); + matPathSlash.append('/'); + filename = matPathSlash+filename; + } +} + + +/**Creates/loads an animated mesh from the file. + \return Pointer to the created mesh. Returns 0 if loading failed. + If you no longer need the mesh, you should call IAnimatedMesh::drop(). + See IReferenceCounted::drop() for more information.*/ +IAnimatedMesh* CDMFLoader::createMesh(io::IReadFile* file) +{ + if (!file) + return 0; + + if ( getMeshTextureLoader() ) + { + getMeshTextureLoader()->setMeshFile(file); + + if ( SceneMgr->getParameters()->existsAttribute(DMF_TEXTURE_PATH) ) + getMeshTextureLoader()->setTexturePath( SceneMgr->getParameters()->getAttributeAsString(DMF_TEXTURE_PATH) ); + } + + video::IVideoDriver* driver = SceneMgr->getVideoDriver(); + + //Load stringlist + StringList dmfRawFile; + LoadFromFile(file, dmfRawFile); + + if (dmfRawFile.size()==0) + return 0; + + SMesh * mesh = new SMesh(); + + u32 i; + + dmfHeader header; + + //load header + core::array materiali; + if (GetDMFHeader(dmfRawFile, header)) + { + //let's set ambient light + SceneMgr->setAmbientLight(header.dmfAmbient); + + //let's create the correct number of materials, vertices and faces + dmfVert *verts=new dmfVert[header.numVertices]; + dmfFace *faces=new dmfFace[header.numFaces]; + + //let's get the materials +#ifdef _IRR_DMF_DEBUG_ + os::Printer::log("Loading materials", core::stringc(header.numMaterials).c_str()); +#endif + GetDMFMaterials(dmfRawFile, materiali, header.numMaterials); + + //let's get vertices and faces +#ifdef _IRR_DMF_DEBUG_ + os::Printer::log("Loading geometry"); +#endif + GetDMFVerticesFaces(dmfRawFile, verts, faces); + + //create a meshbuffer for each material, then we'll remove empty ones +#ifdef _IRR_DMF_DEBUG_ + os::Printer::log("Creating meshbuffers."); +#endif + for (i=0; iMaterial.MaterialType = video::EMT_LIGHTMAP_LIGHTING; + buffer->Material.Wireframe = false; + buffer->Material.Lighting = true; + mesh->addMeshBuffer(buffer); + buffer->drop(); + } + + // Build the mesh buffers +#ifdef _IRR_DMF_DEBUG_ + os::Printer::log("Adding geometry to mesh."); +#endif + for (i = 0; i < header.numFaces; i++) + { +#ifdef _IRR_DMF_DEBUG_ + os::Printer::log("Polygon with #vertices", core::stringc(faces[i].numVerts).c_str()); +#endif + if (faces[i].numVerts < 3) + continue; + + const core::vector3df normal = + core::triangle3df(verts[faces[i].firstVert].pos, + verts[faces[i].firstVert+1].pos, + verts[faces[i].firstVert+2].pos).getNormal().normalize(); + + SSkinMeshBuffer* meshBuffer = (SSkinMeshBuffer*)mesh->getMeshBuffer( + faces[i].materialID); + + const bool use2TCoords = meshBuffer->Vertices_2TCoords.size() || + materiali[faces[i].materialID].lightmapName.size(); + if (use2TCoords && meshBuffer->Vertices_Standard.size()) + meshBuffer->convertTo2TCoords(); + const u32 base = meshBuffer->Vertices_2TCoords.size()?meshBuffer->Vertices_2TCoords.size():meshBuffer->Vertices_Standard.size(); + + // Add this face's verts + if (use2TCoords) + { + // make sure we have the proper type set + meshBuffer->VertexType=video::EVT_2TCOORDS; + for (u32 v = 0; v < faces[i].numVerts; v++) + { + const dmfVert& vv = verts[faces[i].firstVert + v]; + video::S3DVertex2TCoords vert(vv.pos, + normal, video::SColor(255,255,255,255), vv.tc, vv.lc); + if (materiali[faces[i].materialID].textureBlend==4 && + SceneMgr->getParameters()->getAttributeAsBool(DMF_FLIP_ALPHA_TEXTURES)) + { + vert.TCoords.set(vv.tc.X,-vv.tc.Y); + } + meshBuffer->Vertices_2TCoords.push_back(vert); + } + } + else + { + for (u32 v = 0; v < faces[i].numVerts; v++) + { + const dmfVert& vv = verts[faces[i].firstVert + v]; + video::S3DVertex vert(vv.pos, + normal, video::SColor(255,255,255,255), vv.tc); + if (materiali[faces[i].materialID].textureBlend==4 && + SceneMgr->getParameters()->getAttributeAsBool(DMF_FLIP_ALPHA_TEXTURES)) + { + vert.TCoords.set(vv.tc.X,-vv.tc.Y); + } + meshBuffer->Vertices_Standard.push_back(vert); + } + } + + // Now add the indices + // This weird loop turns convex polygons into triangle strips. + // I do it this way instead of a simple fan because it usually + // looks a lot better in wireframe, for example. + u32 h = faces[i].numVerts - 1, l = 0, c; // High, Low, Center + for (u32 v = 0; v < faces[i].numVerts - 2; v++) + { + if (v & 1) // odd + c = h - 1; + else // even + c = l + 1; + + meshBuffer->Indices.push_back(base + h); + meshBuffer->Indices.push_back(base + l); + meshBuffer->Indices.push_back(base + c); + + if (v & 1) // odd + h--; + else // even + l++; + } + } + + delete [] verts; + delete [] faces; + } + + // delete all buffers without geometry in it. +#ifdef _IRR_DMF_DEBUG_ + os::Printer::log("Cleaning meshbuffers."); +#endif + i = 0; + while(i < mesh->MeshBuffers.size()) + { + if (mesh->MeshBuffers[i]->getVertexCount() == 0 || + mesh->MeshBuffers[i]->getIndexCount() == 0) + { + // Meshbuffer is empty -- drop it + mesh->MeshBuffers[i]->drop(); + mesh->MeshBuffers.erase(i); + materiali.erase(i); + } + else + { + i++; + } + } + + + { + //load textures and lightmaps in materials. + //don't worry if you receive a could not load texture, cause if you don't need + //a particular material in your scene it will be loaded and then destroyed. +#ifdef _IRR_DMF_DEBUG_ + os::Printer::log("Loading textures."); +#endif + const bool use_mat_dirs=!SceneMgr->getParameters()->getAttributeAsBool(DMF_IGNORE_MATERIALS_DIRS); + + for (i=0; igetMeshBufferCount(); i++) + { + //texture and lightmap + video::ITexture *tex = 0; + video::ITexture *lig = 0; + + //current buffer to apply material + video::SMaterial& mat = mesh->getMeshBuffer(i)->getMaterial(); + + //Primary texture is normal + if (materiali[i].textureFlag==0) + { + if (materiali[i].textureBlend==4) + driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT,true); + + if ( use_mat_dirs ) + addMaterialPath(materiali[i].textureName, materiali[i].pathName); + tex = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture( materiali[i].textureName ) : NULL; + } + //Primary texture is just a color + else if(materiali[i].textureFlag==1) + { + video::SColor color(axtoi(materiali[i].textureName.c_str())); + + //just for compatibility with older Irrlicht versions + //to support transparent materials + if (color.getAlpha()!=255 && materiali[i].textureBlend==4) + driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT,true); + + video::IImage *immagine= driver->createImage(video::ECF_A8R8G8B8, + core::dimension2d(8,8)); + immagine->fill(color); + tex = driver->addTexture("", immagine); + immagine->drop(); + + //to support transparent materials + if (color.getAlpha()!=255 && materiali[i].textureBlend==4) + { + mat.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + mat.MaterialTypeParam =(((f32) (color.getAlpha()-1))/255.0f); + } + } + + //Lightmap is present + if (materiali[i].lightmapFlag == 0) + { + if ( use_mat_dirs ) + addMaterialPath(materiali[i].lightmapName, materiali[i].pathName); + lig = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture(materiali[i].lightmapName) : NULL; + } + else //no lightmap + { + mat.MaterialType = video::EMT_SOLID; + const f32 mult = 100.0f - header.dmfShadow; + mat.AmbientColor=header.dmfAmbient.getInterpolated(video::SColor(255,0,0,0),mult/100.f); + } + + if (materiali[i].textureBlend==4) + { + mat.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + mat.MaterialTypeParam = + SceneMgr->getParameters()->getAttributeAsFloat(DMF_ALPHA_CHANNEL_REF); + } + + //if texture is present mirror vertically owing to DeleD representation + if (tex && header.dmfVersion<1.1) + { + const core::dimension2d texsize = tex->getSize(); + void* pp = tex->lock(); + if (pp) + { + const video::ECOLOR_FORMAT format = tex->getColorFormat(); + if (format == video::ECF_A1R5G5B5) + { + s16* p = (s16*)pp; + s16 tmp=0; + for (u32 x=0; xunlock(); + tex->regenerateMipMapLevels(); + } + + //if lightmap is present mirror vertically owing to DeleD rapresentation + if (lig && header.dmfVersion<1.1) + { + const core::dimension2d ligsize=lig->getSize(); + void* pp = lig->lock(); + if (pp) + { + video::ECOLOR_FORMAT format = lig->getColorFormat(); + if (format == video::ECF_A1R5G5B5) + { + s16* p = (s16*)pp; + s16 tmp=0; + for (u32 x=0; xunlock(); + lig->regenerateMipMapLevels(); + } + + mat.setTexture(0, tex); + mat.setTexture(1, lig); + } + } + + // create bounding box + for (i = 0; i < mesh->MeshBuffers.size(); ++i) + { + mesh->MeshBuffers[i]->recalculateBoundingBox(); + } + mesh->recalculateBoundingBox(); + + // Set up an animated mesh to hold the mesh + SAnimatedMesh* AMesh = new SAnimatedMesh(); + AMesh->Type = EAMT_UNKNOWN; + AMesh->addMesh(mesh); + AMesh->recalculateBoundingBox(); + mesh->drop(); + + return AMesh; +} + + +/** \brief Tell us if this file is able to be loaded by this class + based on the file extension (e.g. ".bsp") + \return true if file is loadable.*/ +bool CDMFLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "dmf" ); +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_DMF_LOADER_ + diff --git a/source/Irrlicht/CDMFLoader.h b/source/Irrlicht/CDMFLoader.h new file mode 100644 index 00000000..c2d70911 --- /dev/null +++ b/source/Irrlicht/CDMFLoader.h @@ -0,0 +1,91 @@ +// Copyright (C) 2002-2012 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 originally written by Salvatore Russo. +// I (Nikolaus Gebhardt) did some minor modifications changes to it and integrated +// it into Irrlicht: +// - removed STL dependency +// - removed log file and replaced it with irrlicht logging +// - adapted code formatting a bit to Irrlicht style +// - removed memory leaks +// Thanks a lot to Salvatore for his work on this and that he gave me +// his permission to add it into Irrlicht. + +/* + CDMFLoader by Salvatore Russo + Version 1.3 + + This loader is used to load DMF files in Irrlicht. + Look at the documentation for a sample application. + + Parts of this code are from Murphy McCauley COCTLoader just like + GetFaceNormal() or indexes creation routines and a routine to add faces. So + please refer to COCTLoader.h to know more about rights granted. + + You can use this software as you wish but you must not remove these notes about license nor + credits to others for parts of this code. +*/ + +#ifndef __C_DMF_LOADER_H_INCLUDED__ +#define __C_DMF_LOADER_H_INCLUDED__ + +#include "IMeshLoader.h" +#include "IReadFile.h" +#include "IFileSystem.h" +#include "SMesh.h" +#include "IVideoDriver.h" +#include "ISceneManager.h" +#include "SAnimatedMesh.h" + +namespace irr +{ +namespace scene +{ + /** A class to load DeleD mesh files.*/ + class CDMFLoader : public IMeshLoader + { + public: + + /** constructor*/ + CDMFLoader(ISceneManager* smgr, io::IFileSystem* filesys); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".cob") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + /** creates/loads an animated mesh from the file. + \return Pointer to the created mesh. Returns 0 if loading failed. + If you no longer need the mesh, you should call IAnimatedMesh::drop(). + See IReferenceCounted::drop() for more information.*/ + virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_; + + /** loads dynamic lights present in this scene. + Note that loaded lights from DeleD must have the suffix \b dynamic_ and must be \b pointlight. + Irrlicht correctly loads specular color, diffuse color , position and distance of object affected by light. + \return number of lights loaded or 0 if loading failed.*/ + int loadLights(const c8 * filename, ISceneManager* smgr, + ISceneNode* parent = 0, s32 base_id = 1000); + + /** loads water plains present in this scene. + Note that loaded water plains from DeleD must have the suffix \b water_ and must be \b rectangle (with just 1 rectangular face). + Irrlicht correctly loads position and rotation of water plain as well as texture layers. + \return number of water plains loaded or 0 if loading failed.*/ + int loadWaterPlains(const c8 *filename, + ISceneManager* smgr, + ISceneNode * parent = 0, + s32 base_id = 2000, + bool mode = true); + + private: + void addMaterialPath(core::stringc& filename, const core::stringc& matPath); + + ISceneManager* SceneMgr; + io::IFileSystem* FileSystem; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CDefaultGUIElementFactory.cpp b/source/Irrlicht/CDefaultGUIElementFactory.cpp new file mode 100644 index 00000000..d21fbd68 --- /dev/null +++ b/source/Irrlicht/CDefaultGUIElementFactory.cpp @@ -0,0 +1,167 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CDefaultGUIElementFactory.h" + +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIEnvironment.h" + +#include "IGUIButton.h" +#include "IGUICheckBox.h" +#include "IGUIColorSelectDialog.h" +#include "IGUIComboBox.h" +#include "IGUIContextMenu.h" +#include "IGUIEditBox.h" +#include "IGUIFileOpenDialog.h" +#include "IGUIInOutFader.h" +#include "IGUIImage.h" +#include "IGUIListBox.h" +#include "IGUIMeshViewer.h" +#include "IGUIScrollBar.h" +#include "IGUISpinBox.h" +#include "IGUIStaticText.h" +#include "IGUITabControl.h" +#include "IGUITable.h" +#include "IGUIToolbar.h" +#include "IGUIWindow.h" +#include "IGUITreeView.h" +#include "IGUIProfiler.h" + +namespace irr +{ +namespace gui +{ + +CDefaultGUIElementFactory::CDefaultGUIElementFactory(IGUIEnvironment* env) +: Environment(env) +{ + + #ifdef _DEBUG + setDebugName("CDefaultGUIElementFactory"); + #endif + + // don't grab the gui environment here to prevent cyclic references +} + + +//! adds an element to the env based on its type id +IGUIElement* CDefaultGUIElementFactory::addGUIElement(EGUI_ELEMENT_TYPE type, IGUIElement* parent) +{ + switch(type) + { + case EGUIET_BUTTON: + return Environment->addButton(core::rect(0,0,100,100),parent); + case EGUIET_CHECK_BOX: + return Environment->addCheckBox(false, core::rect(0,0,100,100), parent); + case EGUIET_COLOR_SELECT_DIALOG: + return Environment->addColorSelectDialog(0,true,parent); + case EGUIET_COMBO_BOX: + return Environment->addComboBox(core::rect(0,0,100,100),parent); + case EGUIET_CONTEXT_MENU: + return Environment->addContextMenu(core::rect(0,0,100,100),parent); + case EGUIET_MENU: + return Environment->addMenu(parent); + case EGUIET_EDIT_BOX: + return Environment->addEditBox(0,core::rect(0,0,100,100),true, parent); + case EGUIET_FILE_OPEN_DIALOG: + return Environment->addFileOpenDialog(0,true,parent); + case EGUIET_IMAGE: + return Environment->addImage(0,core::position2di(0,0), true, parent); + case EGUIET_IN_OUT_FADER: + return Environment->addInOutFader(0,parent); + case EGUIET_LIST_BOX: + return Environment->addListBox(core::rect(0,0,100,100),parent); + case EGUIET_MESH_VIEWER: + return Environment->addMeshViewer(core::rect(0,0,100,100),parent); + case EGUIET_MODAL_SCREEN: + return Environment->addModalScreen(parent); + case EGUIET_MESSAGE_BOX: + return Environment->addMessageBox(0,0,false,0,parent); + case EGUIET_SCROLL_BAR: + return Environment->addScrollBar(false,core::rect(0,0,100,100),parent); + case EGUIET_STATIC_TEXT: + return Environment->addStaticText(0,core::rect(0,0,100,100),false,true,parent); + case EGUIET_TAB: + return Environment->addTab(core::rect(0,0,100,100),parent); + case EGUIET_TAB_CONTROL: + return Environment->addTabControl(core::rect(0,0,100,100),parent); + case EGUIET_TABLE: + return Environment->addTable(core::rect(0,0,100,100), parent); + case EGUIET_TOOL_BAR: + return Environment->addToolBar(parent); + case EGUIET_WINDOW: + return Environment->addWindow(core::rect(0,0,100,100),false,0,parent); + case EGUIET_SPIN_BOX: + return Environment->addSpinBox(L"0.0", core::rect(0,0,100,100), true, parent); + case EGUIET_TREE_VIEW: + return Environment->addTreeView(core::rect(0,0,100,100),parent); + case EGUIET_PROFILER: + return Environment->addProfilerDisplay(core::rect(0,0,100,100), parent); + default: + return 0; + } +} + + +//! adds an element to the environment based on its type name +IGUIElement* CDefaultGUIElementFactory::addGUIElement(const c8* typeName, IGUIElement* parent) +{ + return addGUIElement( getTypeFromName(typeName), parent ); +} + + +//! Returns the amount of element types this factory is able to create. +s32 CDefaultGUIElementFactory::getCreatableGUIElementTypeCount() const +{ + return EGUIET_COUNT; +} + + +//! Returns the type of a creatable element type. +EGUI_ELEMENT_TYPE CDefaultGUIElementFactory::getCreateableGUIElementType(s32 idx) const +{ + if (idx>=0 && idx=0 && idx=0 && typegrab(); +} + + +CDefaultSceneNodeAnimatorFactory::~CDefaultSceneNodeAnimatorFactory() +{ + if (CursorControl) + CursorControl->drop(); +} + + +//! creates a scene node animator based on its type id +ISceneNodeAnimator* CDefaultSceneNodeAnimatorFactory::createSceneNodeAnimator(ESCENE_NODE_ANIMATOR_TYPE type, ISceneNode* target) +{ + scene::ISceneNodeAnimator* anim = 0; + + switch(type) + { + case ESNAT_FLY_CIRCLE: + anim = Manager->createFlyCircleAnimator(core::vector3df(0,0,0), 10); + break; + case ESNAT_FLY_STRAIGHT: + anim = Manager->createFlyStraightAnimator(core::vector3df(0,0,0), core::vector3df(100,100,100), 10000, true ); + break; + case ESNAT_FOLLOW_SPLINE: + { + core::array points; + points.push_back(core::vector3df(0,0,0)); + points.push_back(core::vector3df(10,5,10)); + anim = Manager->createFollowSplineAnimator(0, points); + } + break; + case ESNAT_ROTATION: + anim = Manager->createRotationAnimator(core::vector3df(0.3f,0,0)); + break; + case ESNAT_TEXTURE: + { + core::array textures; + anim = Manager->createTextureAnimator(textures, 250); + } + break; + case ESNAT_DELETION: + anim = Manager->createDeleteAnimator(5000); + break; + case ESNAT_COLLISION_RESPONSE: + anim = Manager->createCollisionResponseAnimator(0, target); + break; + case ESNAT_CAMERA_FPS: + anim = new CSceneNodeAnimatorCameraFPS(CursorControl); + break; + case ESNAT_CAMERA_MAYA: + anim = new CSceneNodeAnimatorCameraMaya(CursorControl); + break; + default: + break; + } + + if (anim && target) + target->addAnimator(anim); + + return anim; +} + + +//! creates a scene node animator based on its type name +ISceneNodeAnimator* CDefaultSceneNodeAnimatorFactory::createSceneNodeAnimator(const c8* typeName, ISceneNode* target) +{ + return createSceneNodeAnimator( getTypeFromName(typeName), target ); +} + + +//! returns amount of scene node animator types this factory is able to create +u32 CDefaultSceneNodeAnimatorFactory::getCreatableSceneNodeAnimatorTypeCount() const +{ + return ESNAT_COUNT; +} + + +//! returns type of a creatable scene node animator type +ESCENE_NODE_ANIMATOR_TYPE CDefaultSceneNodeAnimatorFactory::getCreateableSceneNodeAnimatorType(u32 idx) const +{ + if (idxaddCubeSceneNode(10, parent); + case ESNT_SPHERE: + return Manager->addSphereSceneNode(5, 16, parent); + case ESNT_TEXT: + return Manager->addTextSceneNode(0, L"example"); + case ESNT_BILLBOARD_TEXT: + return Manager->addBillboardTextSceneNode(0, L"example"); + case ESNT_WATER_SURFACE: + return Manager->addWaterSurfaceSceneNode(0, 2.0f, 300.0f, 10.0f, parent); + case ESNT_TERRAIN: + return Manager->addTerrainSceneNode("", parent, -1, + core::vector3df(0.0f,0.0f,0.0f), + core::vector3df(0.0f,0.0f,0.0f), + core::vector3df(1.0f,1.0f,1.0f), + video::SColor(255,255,255,255), + 4, ETPS_17, 0, true); + case ESNT_SKY_BOX: + return Manager->addSkyBoxSceneNode(0,0,0,0,0,0, parent); + case ESNT_SKY_DOME: + return Manager->addSkyDomeSceneNode(0, 16, 8, 0.9f, 2.0f, 1000.0f, parent); + case ESNT_SHADOW_VOLUME: + return 0; + case ESNT_OCTREE: + return Manager->addOctreeSceneNode((IMesh*)0, parent, -1, 128, true); + case ESNT_MESH: + return Manager->addMeshSceneNode(0, parent, -1, core::vector3df(), + core::vector3df(), core::vector3df(1,1,1), true); + case ESNT_LIGHT: + return Manager->addLightSceneNode(parent); + case ESNT_EMPTY: + return Manager->addEmptySceneNode(parent); + case ESNT_DUMMY_TRANSFORMATION: + return Manager->addDummyTransformationSceneNode(parent); + case ESNT_CAMERA: + return Manager->addCameraSceneNode(parent); + case ESNT_CAMERA_MAYA: + return Manager->addCameraSceneNodeMaya(parent); + case ESNT_CAMERA_FPS: + return Manager->addCameraSceneNodeFPS(parent); + case ESNT_BILLBOARD: + return Manager->addBillboardSceneNode(parent); + case ESNT_ANIMATED_MESH: + return Manager->addAnimatedMeshSceneNode(0, parent, -1, core::vector3df(), + core::vector3df(), core::vector3df(1,1,1), true); + case ESNT_PARTICLE_SYSTEM: + return Manager->addParticleSystemSceneNode(true, parent); + case ESNT_VOLUME_LIGHT: + return (ISceneNode*)Manager->addVolumeLightSceneNode(parent); + default: + break; + } + + return 0; +} + + +//! adds a scene node to the scene graph based on its type name +ISceneNode* CDefaultSceneNodeFactory::addSceneNode(const c8* typeName, ISceneNode* parent) +{ + return addSceneNode( getTypeFromName(typeName), parent ); +} + + +//! returns amount of scene node types this factory is able to create +u32 CDefaultSceneNodeFactory::getCreatableSceneNodeTypeCount() const +{ + return SupportedSceneNodeTypes.size(); +} + + +//! returns type of a creatable scene node type +ESCENE_NODE_TYPE CDefaultSceneNodeFactory::getCreateableSceneNodeType(u32 idx) const +{ + if (idx SupportedSceneNodeTypes; + + ISceneManager* Manager; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CDepthBuffer.cpp b/source/Irrlicht/CDepthBuffer.cpp new file mode 100644 index 00000000..e9126bda --- /dev/null +++ b/source/Irrlicht/CDepthBuffer.cpp @@ -0,0 +1,172 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "SoftwareDriver2_compile_config.h" +#include "CDepthBuffer.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + + +//! constructor +CDepthBuffer::CDepthBuffer(const core::dimension2d& size) +: Buffer(0), Size(0,0) +{ + #ifdef _DEBUG + setDebugName("CDepthBuffer"); + #endif + + setSize(size); +} + + + +//! destructor +CDepthBuffer::~CDepthBuffer() +{ + delete [] Buffer; +} + + + +//! clears the zbuffer +void CDepthBuffer::clear() +{ + +#ifdef SOFTWARE_DRIVER_2_USE_WBUFFER + f32 zMax = 0.f; +#else + f32 zMax = 1.f; +#endif + + u32 zMaxValue; + zMaxValue = IR(zMax); + + memset32 ( Buffer, zMaxValue, TotalSize ); +} + + + +//! sets the new size of the zbuffer +void CDepthBuffer::setSize(const core::dimension2d& size) +{ + if (size == Size) + return; + + Size = size; + + delete [] Buffer; + + Pitch = size.Width * sizeof ( fp24 ); + TotalSize = Pitch * size.Height; + Buffer = new u8[TotalSize]; + clear (); +} + + + +//! returns the size of the zbuffer +const core::dimension2d& CDepthBuffer::getSize() const +{ + return Size; +} + +// ----------------------------------------------------------------- + +//! constructor +CStencilBuffer::CStencilBuffer(const core::dimension2d& size) +: Buffer(0), Size(0,0) +{ + #ifdef _DEBUG + setDebugName("CDepthBuffer"); + #endif + + setSize(size); +} + + + +//! destructor +CStencilBuffer::~CStencilBuffer() +{ + delete [] Buffer; +} + + + +//! clears the zbuffer +void CStencilBuffer::clear() +{ + memset32 ( Buffer, 0, TotalSize ); +} + + + +//! sets the new size of the zbuffer +void CStencilBuffer::setSize(const core::dimension2d& size) +{ + if (size == Size) + return; + + Size = size; + + delete [] Buffer; + + Pitch = size.Width * sizeof ( u32 ); + TotalSize = Pitch * size.Height; + Buffer = new u8[TotalSize]; + clear (); +} + + + +//! returns the size of the zbuffer +const core::dimension2d& CStencilBuffer::getSize() const +{ + return Size; +} + + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + +//! creates a ZBuffer +IDepthBuffer* createDepthBuffer(const core::dimension2d& size) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CDepthBuffer(size); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +//! creates a ZBuffer +IStencilBuffer* createStencilBuffer(const core::dimension2d& size) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CStencilBuffer(size); + #else + 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 new file mode 100644 index 00000000..7964efa6 --- /dev/null +++ b/source/Irrlicht/CDepthBuffer.h @@ -0,0 +1,94 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_Z_BUFFER_H_INCLUDED__ +#define __C_Z_BUFFER_H_INCLUDED__ + +#include "IDepthBuffer.h" + +namespace irr +{ +namespace video +{ + + class CDepthBuffer : public IDepthBuffer + { + public: + + //! constructor + CDepthBuffer(const core::dimension2d& size); + + //! destructor + virtual ~CDepthBuffer(); + + //! clears the zbuffer + virtual void clear() _IRR_OVERRIDE_; + + //! sets the new size of the zbuffer + virtual void setSize(const core::dimension2d& size) _IRR_OVERRIDE_; + + //! returns the size of the zbuffer + virtual const core::dimension2d& getSize() const _IRR_OVERRIDE_; + + //! locks the zbuffer + virtual void* lock() _IRR_OVERRIDE_ { return (void*) Buffer; } + + //! unlocks the zbuffer + virtual void unlock() _IRR_OVERRIDE_ {} + + //! returns pitch of depthbuffer (in bytes) + virtual u32 getPitch() const _IRR_OVERRIDE_ { return Pitch; } + + + private: + + u8* Buffer; + core::dimension2d Size; + u32 TotalSize; + u32 Pitch; + }; + + + class CStencilBuffer : public IStencilBuffer + { + public: + + //! constructor + CStencilBuffer(const core::dimension2d& size); + + //! destructor + virtual ~CStencilBuffer(); + + //! clears the zbuffer + virtual void clear() _IRR_OVERRIDE_; + + //! sets the new size of the zbuffer + virtual void setSize(const core::dimension2d& size) _IRR_OVERRIDE_; + + //! returns the size of the zbuffer + virtual const core::dimension2d& getSize() const _IRR_OVERRIDE_; + + //! locks the zbuffer + virtual void* lock() _IRR_OVERRIDE_ { return (void*) Buffer; } + + //! unlocks the zbuffer + virtual void unlock() _IRR_OVERRIDE_ {} + + //! returns pitch of depthbuffer (in bytes) + virtual u32 getPitch() const _IRR_OVERRIDE_ { return Pitch; } + + + private: + + u8* Buffer; + core::dimension2d Size; + u32 TotalSize; + u32 Pitch; + }; + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CDummyTransformationSceneNode.cpp b/source/Irrlicht/CDummyTransformationSceneNode.cpp new file mode 100644 index 00000000..812145aa --- /dev/null +++ b/source/Irrlicht/CDummyTransformationSceneNode.cpp @@ -0,0 +1,105 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CDummyTransformationSceneNode.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CDummyTransformationSceneNode::CDummyTransformationSceneNode( + ISceneNode* parent, ISceneManager* mgr, s32 id) + : IDummyTransformationSceneNode(parent, mgr, id) +{ + #ifdef _DEBUG + setDebugName("CDummyTransformationSceneNode"); + #endif + + setAutomaticCulling(scene::EAC_OFF); +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CDummyTransformationSceneNode::getBoundingBox() const +{ + return Box; +} + + +//! Returns a reference to the current relative transformation matrix. +//! This is the matrix, this scene node uses instead of scale, translation +//! and rotation. +core::matrix4& CDummyTransformationSceneNode::getRelativeTransformationMatrix() +{ + return RelativeTransformationMatrix; +} + + +//! Returns the relative transformation of the scene node. +core::matrix4 CDummyTransformationSceneNode::getRelativeTransformation() const +{ + return RelativeTransformationMatrix; +} + +//! Creates a clone of this scene node and its children. +ISceneNode* CDummyTransformationSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager) +{ + if (!newParent) + newParent = Parent; + if (!newManager) + newManager = SceneManager; + + CDummyTransformationSceneNode* nb = new CDummyTransformationSceneNode(newParent, + newManager, ID); + + nb->cloneMembers(this, newManager); + nb->RelativeTransformationMatrix = RelativeTransformationMatrix; + nb->Box = Box; + + if ( newParent ) + nb->drop(); + return nb; +} + +const core::vector3df& CDummyTransformationSceneNode::getScale() const +{ + os::Printer::log("CDummyTransformationSceneNode::getScale() does not contain the relative transformation.", ELL_DEBUG); + return RelativeScale; +} + +void CDummyTransformationSceneNode::setScale(const core::vector3df& scale) +{ + os::Printer::log("CDummyTransformationSceneNode::setScale() does not affect the relative transformation.", ELL_DEBUG); + RelativeScale = scale; +} + +const core::vector3df& CDummyTransformationSceneNode::getRotation() const +{ + os::Printer::log("CDummyTransformationSceneNode::getRotation() does not contain the relative transformation.", ELL_DEBUG); + return RelativeRotation; +} + +void CDummyTransformationSceneNode::setRotation(const core::vector3df& rotation) +{ + os::Printer::log("CDummyTransformationSceneNode::setRotation() does not affect the relative transformation.", ELL_DEBUG); + RelativeRotation = rotation; +} + +const core::vector3df& CDummyTransformationSceneNode::getPosition() const +{ + os::Printer::log("CDummyTransformationSceneNode::getPosition() does not contain the relative transformation.", ELL_DEBUG); + return RelativeTranslation; +} + +void CDummyTransformationSceneNode::setPosition(const core::vector3df& newpos) +{ + os::Printer::log("CDummyTransformationSceneNode::setPosition() does not affect the relative transformation.", ELL_DEBUG); + RelativeTranslation = newpos; +} + +} // end namespace scene +} // end namespace irr diff --git a/source/Irrlicht/CDummyTransformationSceneNode.h b/source/Irrlicht/CDummyTransformationSceneNode.h new file mode 100644 index 00000000..ac95b148 --- /dev/null +++ b/source/Irrlicht/CDummyTransformationSceneNode.h @@ -0,0 +1,62 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_DUMMY_TRANSFORMATION_SCENE_NODE_H_INCLUDED__ +#define __C_DUMMY_TRANSFORMATION_SCENE_NODE_H_INCLUDED__ + +#include "IDummyTransformationSceneNode.h" + +namespace irr +{ +namespace scene +{ + + class CDummyTransformationSceneNode : public IDummyTransformationSceneNode + { + public: + + //! constructor + CDummyTransformationSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id); + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + //! Returns a reference to the current relative transformation matrix. + //! This is the matrix, this scene node uses instead of scale, translation + //! and rotation. + virtual core::matrix4& getRelativeTransformationMatrix() _IRR_OVERRIDE_; + + //! Returns the relative transformation of the scene node. + virtual core::matrix4 getRelativeTransformation() const _IRR_OVERRIDE_; + + //! does nothing. + virtual void render() _IRR_OVERRIDE_ {} + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_DUMMY_TRANSFORMATION; } + + //! Creates a clone of this scene node and its children. + virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + + private: + + // TODO: We can add least add some warnings to find troubles faster until we have + // fixed bug id 2318691. + virtual const core::vector3df& getScale() const _IRR_OVERRIDE_; + virtual void setScale(const core::vector3df& scale) _IRR_OVERRIDE_; + virtual const core::vector3df& getRotation() const _IRR_OVERRIDE_; + virtual void setRotation(const core::vector3df& rotation) _IRR_OVERRIDE_; + virtual const core::vector3df& getPosition() const _IRR_OVERRIDE_; + virtual void setPosition(const core::vector3df& newpos) _IRR_OVERRIDE_; + + core::matrix4 RelativeTransformationMatrix; + core::aabbox3d Box; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CEAGLManager.h b/source/Irrlicht/CEAGLManager.h new file mode 100644 index 00000000..7b670e16 --- /dev/null +++ b/source/Irrlicht/CEAGLManager.h @@ -0,0 +1,87 @@ +// Copyright (C) 2015 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __C_EAGL_MANAGER_H_INCLUDED__ +#define __C_EAGL_MANAGER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_EAGL_MANAGER_ + +#include "SIrrCreationParameters.h" +#include "SExposedVideoData.h" +#include "IContextManager.h" + +namespace irr +{ +namespace video +{ + // EAGL manager. + class CEAGLManager : public IContextManager + { + public: + //! Constructor. + CEAGLManager(); + + //! Destructor. + virtual ~CEAGLManager(); + + // Initialize EAGL. + /* This method checks if a view has CAEAGLLayer and grabs it if it does, anyway surface and context + aren't create. */ + bool initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& data); + + // Terminate EAGL. + /* Terminate EAGL context. This method break both existed surface and context. */ + void terminate(); + + // Create EAGL surface. + /* This method configure CAEAGLLayer. */ + bool generateSurface(); + + // Destroy EAGL surface. + /* This method reset CAEAGLLayer states. */ + void destroySurface(); + + // Create EAGL context. + /* This method create and activate EAGL context. */ + bool generateContext(); + + // Destroy EAGL context. + /* This method destroy EAGL context. */ + void destroyContext(); + + const SExposedVideoData& getContext() const; + + bool activateContext(const SExposedVideoData& videoData); + + // Swap buffers. + bool swapBuffers(); + + private: + SIrrlichtCreationParameters Params; + SExposedVideoData Data; + + bool Configured; + + void* DataStorage; + + struct SFrameBuffer + { + SFrameBuffer() : BufferID(0), ColorBuffer(0), DepthBuffer(0) + { + } + + u32 BufferID; + u32 ColorBuffer; + u32 DepthBuffer; + }; + + SFrameBuffer FrameBuffer; + }; +} +} + +#endif +#endif diff --git a/source/Irrlicht/CEAGLManager.mm b/source/Irrlicht/CEAGLManager.mm new file mode 100644 index 00000000..f9d53e50 --- /dev/null +++ b/source/Irrlicht/CEAGLManager.mm @@ -0,0 +1,273 @@ +// Copyright (C) 2015 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#include "CEAGLManager.h" + +#ifdef _IRR_COMPILE_WITH_EAGL_MANAGER_ + +#include "irrString.h" +#include "os.h" + +#import +#import + +#if defined(_IRR_COMPILE_WITH_OGLES1_) +#include +#include +#elif defined(_IRR_COMPILE_WITH_OGLES2_) +#include +#include +#endif + +namespace irr +{ +namespace video +{ + +struct SEAGLManagerDataStorage +{ + SEAGLManagerDataStorage() : Layer(0), Context(0) + { + } + + CAEAGLLayer* Layer; + EAGLContext* Context; +}; + +CEAGLManager::CEAGLManager() : IContextManager(), Configured(false), DataStorage(0) +{ +#ifdef _DEBUG + setDebugName("CEAGLManager"); +#endif + + DataStorage = new SEAGLManagerDataStorage(); +} + +CEAGLManager::~CEAGLManager() +{ + destroyContext(); + destroySurface(); + terminate(); + + delete static_cast(DataStorage); +} + +bool CEAGLManager::initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& data) +{ + SEAGLManagerDataStorage* dataStorage = static_cast(DataStorage); + + if (dataStorage->Layer != nil) + return true; + + Params = params; + Data = data; + + UIView* view = (__bridge UIView*)data.OpenGLiOS.View; + + if (view == nil || ![[view layer] isKindOfClass:[CAEAGLLayer class]]) + { + os::Printer::log("Could not get EAGL display."); + return false; + } + + dataStorage->Layer = (CAEAGLLayer*)[view layer]; + + return true; +} + +void CEAGLManager::terminate() +{ + SEAGLManagerDataStorage* dataStorage = static_cast(DataStorage); + + [EAGLContext setCurrentContext:0]; + + destroySurface(); + + if (dataStorage->Layer != nil) + dataStorage->Layer = 0; +} + +bool CEAGLManager::generateSurface() +{ + SEAGLManagerDataStorage* dataStorage = static_cast(DataStorage); + CAEAGLLayer* layer = dataStorage->Layer; + + if (layer == nil) + return false; + + if (Configured) + return true; + + NSDictionary* attribs = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:NO], + kEAGLDrawablePropertyRetainedBacking, + (Params.Bits > 16) ? kEAGLColorFormatRGBA8 : kEAGLColorFormatRGB565, + kEAGLDrawablePropertyColorFormat, + nil]; + + [layer setOpaque:(Params.WithAlphaChannel) ? YES : NO]; + [layer setDrawableProperties:attribs]; + + Configured = true; + + return true; +} + +void CEAGLManager::destroySurface() +{ + SEAGLManagerDataStorage* dataStorage = static_cast(DataStorage); + CAEAGLLayer* layer = dataStorage->Layer; + + if (layer == nil) + return; + + [layer setOpaque:NO]; + [layer setDrawableProperties:nil]; + + Configured = false; +} + +bool CEAGLManager::generateContext() +{ + SEAGLManagerDataStorage* dataStorage = static_cast(DataStorage); + + if (dataStorage->Context != nil || !Configured) + return false; + + EAGLRenderingAPI OpenGLESVersion = kEAGLRenderingAPIOpenGLES2; + + switch (Params.DriverType) + { + case EDT_OGLES1: + OpenGLESVersion = kEAGLRenderingAPIOpenGLES1; + break; + case EDT_OGLES2: + OpenGLESVersion = kEAGLRenderingAPIOpenGLES2; + break; + default: + break; + } + + dataStorage->Context = [[EAGLContext alloc] initWithAPI:OpenGLESVersion]; + + if (dataStorage->Context == nil) + { + os::Printer::log("Could not create EAGL context.", ELL_ERROR); + return false; + } + + Data.OpenGLiOS.Context = (__bridge void*)dataStorage->Context; + + os::Printer::log("EAGL context created with OpenGLESVersion: ", core::stringc(static_cast(OpenGLESVersion)), ELL_DEBUG); + + return true; +} + +void CEAGLManager::destroyContext() +{ + SEAGLManagerDataStorage* dataStorage = static_cast(DataStorage); + + [dataStorage->Context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:nil]; + + if (FrameBuffer.BufferID != 0) + { + glDeleteFramebuffersOES(1, &FrameBuffer.BufferID); + FrameBuffer.BufferID = 0; + } + + if (FrameBuffer.ColorBuffer != 0) + { + glDeleteRenderbuffersOES(1, &FrameBuffer.ColorBuffer); + FrameBuffer.ColorBuffer = 0; + } + + if (FrameBuffer.DepthBuffer != 0) + { + glDeleteRenderbuffersOES(1, &FrameBuffer.DepthBuffer); + FrameBuffer.DepthBuffer = 0; + } + + [EAGLContext setCurrentContext:0]; + + if (dataStorage->Context != nil) + dataStorage->Context = 0; + + Data.OpenGLiOS.Context = 0; +} + +bool CEAGLManager::activateContext(const SExposedVideoData& videoData) +{ + SEAGLManagerDataStorage* dataStorage = static_cast(DataStorage); + EAGLContext* context = dataStorage->Context; + + bool status = false; + + if (context != nil) + { + status = ([EAGLContext currentContext] == context || [EAGLContext setCurrentContext:context]); + } + + if (status) + { + if (FrameBuffer.ColorBuffer == 0) + { + glGenRenderbuffersOES(1, &FrameBuffer.ColorBuffer); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, FrameBuffer.ColorBuffer); + [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:dataStorage->Layer]; + } + + if (FrameBuffer.DepthBuffer == 0) + { + GLenum depth = (Params.ZBufferBits >= 24) ? GL_DEPTH_COMPONENT24_OES : GL_DEPTH_COMPONENT16_OES; + + glGenRenderbuffersOES(1, &FrameBuffer.DepthBuffer); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, FrameBuffer.DepthBuffer); + glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depth, Params.WindowSize.Width, Params.WindowSize.Height); + } + + if (FrameBuffer.BufferID == 0) + { + glGenFramebuffersOES(1, &FrameBuffer.BufferID); + glBindFramebufferOES(GL_FRAMEBUFFER_OES, FrameBuffer.BufferID); + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, FrameBuffer.ColorBuffer); + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, FrameBuffer.DepthBuffer); + } + + glBindFramebufferOES(GL_FRAMEBUFFER_OES, FrameBuffer.BufferID); + } + else + { + os::Printer::log("Could not make EGL context current."); + } + + return status; +} + +const SExposedVideoData& CEAGLManager::getContext() const +{ + return Data; +} + +bool CEAGLManager::swapBuffers() +{ + SEAGLManagerDataStorage* dataStorage = static_cast(DataStorage); + EAGLContext* context = dataStorage->Context; + + bool status = false; + + if (context != nil && context == [EAGLContext currentContext]) + { + glBindRenderbufferOES(GL_RENDERBUFFER_OES, FrameBuffer.ColorBuffer); + [context presentRenderbuffer:GL_RENDERBUFFER_OES]; + + status = true; + } + + return status; +} + +} +} + +#endif diff --git a/source/Irrlicht/CEGLManager.cpp b/source/Irrlicht/CEGLManager.cpp new file mode 100755 index 00000000..49b72901 --- /dev/null +++ b/source/Irrlicht/CEGLManager.cpp @@ -0,0 +1,662 @@ +// Copyright (C) 2013 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#include "CEGLManager.h" + +#ifdef _IRR_COMPILE_WITH_EGL_MANAGER_ + +#include "irrString.h" +#include "irrArray.h" +#include "os.h" + +#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_) +#include +#endif + +namespace irr +{ +namespace video +{ + +CEGLManager::CEGLManager() : IContextManager(), EglWindow(0), EglDisplay(EGL_NO_DISPLAY), + EglSurface(EGL_NO_SURFACE), EglContext(EGL_NO_CONTEXT), EglConfig(0), MajorVersion(0), MinorVersion(0) +{ + #ifdef _DEBUG + setDebugName("CEGLManager"); + #endif +} + +CEGLManager::~CEGLManager() +{ + destroyContext(); + destroySurface(); + terminate(); +} + +bool CEGLManager::initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& data) +{ + // store new data + Params=params; + Data=data; + + if (EglWindow != 0 && EglDisplay != EGL_NO_DISPLAY) + return true; + + // Window is depend on platform. +#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) + EglWindow = (NativeWindowType)Data.OpenGLWin32.HWnd; + Data.OpenGLWin32.HDc = GetDC((HWND)EglWindow); + EglDisplay = eglGetDisplay((NativeDisplayType)Data.OpenGLWin32.HDc); +#elif defined(_IRR_EMSCRIPTEN_PLATFORM_) + EglWindow = 0; + EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); +#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_) + EglWindow = (NativeWindowType)Data.OpenGLLinux.X11Window; + EglDisplay = eglGetDisplay((NativeDisplayType)Data.OpenGLLinux.X11Display); +#elif defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_) + EglWindow = (ANativeWindow*)Data.OGLESAndroid.Window; + EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); +#elif defined(_IRR_COMPILE_WITH_FB_DEVICE_) + EglWindow = (NativeWindowType)Data.OpenGLFB.Window; + EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); +#endif + + // We must check if EGL display is valid. + if (EglDisplay == EGL_NO_DISPLAY) + { + os::Printer::log("Could not get EGL display."); + terminate(); + return false; + } + + // Initialize EGL here. + if (!eglInitialize(EglDisplay, &MajorVersion, &MinorVersion)) + { + os::Printer::log("Could not initialize EGL display."); + + EglDisplay = EGL_NO_DISPLAY; + terminate(); + return false; + } + else + os::Printer::log("EGL version", core::stringc(MajorVersion+(MinorVersion*0.1f)).c_str()); + + return true; +} + +void CEGLManager::terminate() +{ + if (EglWindow == 0 && EglDisplay == EGL_NO_DISPLAY) + return; + + if (EglDisplay != EGL_NO_DISPLAY) + { + // We should unbind current EGL context before terminate EGL. + eglMakeCurrent(EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + eglTerminate(EglDisplay); + EglDisplay = EGL_NO_DISPLAY; + } + +#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) + if (Data.OpenGLWin32.HDc) + { + ReleaseDC((HWND)EglWindow, (HDC)Data.OpenGLWin32.HDc); + Data.OpenGLWin32.HDc = 0; + } +#endif + + MajorVersion = 0; + MinorVersion = 0; +} + +bool CEGLManager::generateSurface() +{ + if (EglDisplay == EGL_NO_DISPLAY) + return false; + + if (EglSurface != EGL_NO_SURFACE) + return true; + + // We should assign new WindowID on platforms, where WindowID may change at runtime, + // at this time only Android support this feature. + // this needs an update method instead! + +#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_) + EglWindow = (ANativeWindow*)Data.OGLESAndroid.Window; +#endif + +#if defined(_IRR_EMSCRIPTEN_PLATFORM_) + // eglChooseConfig is currently only implemented as stub in emscripten (version 1.37.22 at point of writing) + // But the other solution would also be fine as it also only generates a single context so there is not much to choose from. + EglConfig = chooseConfig(ECS_IRR_CHOOSE); +#else + EglConfig = chooseConfig(ECS_EGL_CHOOSE_FIRST_LOWER_EXPECTATIONS); +#endif + + if ( EglConfig == 0 ) + { + os::Printer::log("Could not get config for EGL display."); + return false; + } + + +#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_) + EGLint Format = 0; + eglGetConfigAttrib(EglDisplay, EglConfig, EGL_NATIVE_VISUAL_ID, &Format); + + ANativeWindow_setBuffersGeometry(EglWindow, 0, 0, Format); +#endif + + // Now we are able to create EGL surface. + EglSurface = eglCreateWindowSurface(EglDisplay, EglConfig, EglWindow, 0); + + if (EGL_NO_SURFACE == EglSurface) + EglSurface = eglCreateWindowSurface(EglDisplay, EglConfig, 0, 0); + + if (EGL_NO_SURFACE == EglSurface) + os::Printer::log("Could not create EGL surface."); + +#ifdef EGL_VERSION_1_2 + if (MinorVersion > 1) + eglBindAPI(EGL_OPENGL_ES_API); +#endif + + if (Params.Vsync) + eglSwapInterval(EglDisplay, 1); + + return true; +} + +EGLConfig CEGLManager::chooseConfig(EConfigStyle confStyle) +{ + EGLConfig configResult = 0; + + // Find proper OpenGL BIT. + EGLint eglOpenGLBIT = 0; + switch (Params.DriverType) + { + case EDT_OGLES1: + eglOpenGLBIT = EGL_OPENGL_ES_BIT; + break; + case EDT_OGLES2: + case EDT_WEBGL1: + eglOpenGLBIT = EGL_OPENGL_ES2_BIT; + break; + default: + break; + } + + if ( confStyle == ECS_EGL_CHOOSE_FIRST_LOWER_EXPECTATIONS ) + { + EGLint Attribs[] = + { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, Params.WithAlphaChannel ? 1:0, + EGL_BUFFER_SIZE, Params.Bits, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_DEPTH_SIZE, Params.ZBufferBits, + EGL_STENCIL_SIZE, Params.Stencilbuffer, + EGL_SAMPLE_BUFFERS, Params.AntiAlias ? 1:0, + EGL_SAMPLES, Params.AntiAlias, + #ifdef EGL_VERSION_1_3 + EGL_RENDERABLE_TYPE, eglOpenGLBIT, + #endif + EGL_NONE, 0 + }; + + EGLint numConfigs = 0; + u32 steps = 5; + + // Choose the best EGL config. + // TODO: We should also have a confStyle ECS_EGL_CHOOSE_CLOSEST + // which doesn't take first result of eglChooseConfigs, + // but the closest to requested parameters. eglChooseConfigs + // can return more than 1 result and first one might have + // "better" values than requested (more bits per pixel etc). + // So this returns the config which can do most, not the + // config which is closest to the requested parameters. + // + while (!eglChooseConfig(EglDisplay, Attribs, &configResult, 1, &numConfigs) || !numConfigs) + { + switch (steps) + { + case 5: // samples + if (Attribs[19] > 2) // Params.AntiAlias + --Attribs[19]; + else + { + Attribs[17] = 0; // Params.Stencilbuffer + Attribs[19] = 0; // Params.AntiAlias + --steps; + } + break; + case 4: // alpha + if (Attribs[7]) // Params.WithAlphaChannel + { + Attribs[7] = 0; + + if (Params.AntiAlias) + { + Attribs[17] = 1; + Attribs[19] = Params.AntiAlias; + steps = 5; + } + } + else + --steps; + break; + case 3: // stencil + if (Attribs[15]) // Params.Stencilbuffer + { + Attribs[15] = 0; + + if (Params.AntiAlias) + { + Attribs[17] = 1; + Attribs[19] = Params.AntiAlias; + steps = 5; + } + } + else + --steps; + break; + case 2: // depth size + if (Attribs[13] > 16) // Params.ZBufferBits + { + Attribs[13] -= 8; + } + else + --steps; + break; + case 1: // buffer size + if (Attribs[9] > 16) // Params.Bits + { + Attribs[9] -= 8; + } + else + --steps; + break; + default: + return 0; + } + } + + if (Params.AntiAlias && !Attribs[17]) + os::Printer::log("No multisampling."); + + if (Params.WithAlphaChannel && !Attribs[7]) + os::Printer::log("No alpha."); + + if (Params.Stencilbuffer && !Attribs[15]) + os::Printer::log("No stencil buffer."); + + if (Params.ZBufferBits > Attribs[13]) + os::Printer::log("No full depth buffer."); + + if (Params.Bits > Attribs[9]) + os::Printer::log("No full color buffer."); + } + else if ( confStyle == ECS_IRR_CHOOSE ) + { + // find number of available configs + EGLint numConfigs; + if ( eglGetConfigs( EglDisplay, NULL, 0, &numConfigs) == EGL_FALSE ) + { + testEGLError(); + return 0; + } + + if ( numConfigs <= 0 ) + return 0; + + // Get all available configs. + EGLConfig * configs = new EGLConfig[numConfigs]; + if ( eglGetConfigs( EglDisplay, configs, numConfigs, &numConfigs) == EGL_FALSE ) + { + testEGLError(); + return 0; + } + + // Find the best one. + core::array ratings((u32)numConfigs); + for ( u32 i=0; i < (u32)numConfigs; ++i ) + { + SConfigRating r; + r.config = configs[i]; + r.rating = rateConfig(r.config, eglOpenGLBIT); + + if ( r.rating >= 0 ) + ratings.push_back(r); + } + + if ( ratings.size() > 0 ) + { + ratings.sort(); + configResult = ratings[0].config; + + if ( ratings[0].rating != 0 ) + { + // This is just to print some log info (it also rates again while doing that, but rating is cheap enough, so that doesn't matter here). + rateConfig(ratings[0].config, eglOpenGLBIT, true); + } + } + + delete[] configs; + } + + return configResult; +} + +irr::s32 CEGLManager::rateConfig(EGLConfig config, EGLint eglOpenGLBIT, bool log) +{ + // some values must be there or we ignore the config +#ifdef EGL_VERSION_1_3 + EGLint attribRenderableType = 0; + eglGetConfigAttrib( EglDisplay, config, EGL_RENDERABLE_TYPE, &attribRenderableType); + if ( attribRenderableType != eglOpenGLBIT ) + { + if ( log ) + os::Printer::log("EGL_RENDERABLE_TYPE != eglOpenGLBIT"); + return -1; + } +#endif + EGLint attribSurfaceType = 0; + eglGetConfigAttrib( EglDisplay, config, EGL_SURFACE_TYPE, &attribSurfaceType); + if ( attribSurfaceType != EGL_WINDOW_BIT ) + { + if ( log ) + os::Printer::log("EGL_SURFACE_TYPE!= EGL_WINDOW_BIT"); + return -1; + } + + // Generally we give a really bad rating if attributes are worse than requested + // We give a slight worse rating if attributes are not exact as requested + // And we use some priorities which might make sense (but not really fine-tuned, + // so if you think other priorities would be better don't worry about changing the values. + int rating = 0; + + EGLint attribBufferSize = 0; + eglGetConfigAttrib( EglDisplay, config, EGL_BUFFER_SIZE, &attribBufferSize); + if ( attribBufferSize < Params.Bits ) + { + if ( log ) + os::Printer::log("No full color buffer."); + rating += 100; + } + if ( attribBufferSize > Params.Bits ) + { + if ( log ) + os::Printer::log("Larger color buffer.", ELL_DEBUG); + ++rating; + } + + EGLint attribRedSize = 0; + eglGetConfigAttrib( EglDisplay, config, EGL_RED_SIZE, &attribRedSize); + if ( attribRedSize < 5 && Params.Bits >= 4 ) + rating += 100; + else if ( attribRedSize < 8 && Params.Bits >= 24) + rating += 10; + else if ( attribRedSize >= 8 && Params.Bits < 24 ) + rating ++; + EGLint attribGreenSize = 0; + eglGetConfigAttrib( EglDisplay, config, EGL_GREEN_SIZE, &attribGreenSize); + if ( attribGreenSize < 5 && Params.Bits >= 4 ) + rating += 100; + else if ( attribGreenSize < 8 && Params.Bits >= 24) + rating += 10; + else if ( attribGreenSize >= 8 && Params.Bits < 24 ) + rating ++; + EGLint attribBlueSize = 0; + eglGetConfigAttrib( EglDisplay, config, EGL_BLUE_SIZE, &attribBlueSize); + if ( attribBlueSize < 5 && Params.Bits >= 4 ) + rating += 100; + else if ( attribBlueSize < 8 && Params.Bits >= 24) + rating += 10; + else if ( attribBlueSize >= 8 && Params.Bits < 24 ) + rating ++; + + EGLint attribAlphaSize = 0; + eglGetConfigAttrib( EglDisplay, config, EGL_ALPHA_SIZE, &attribAlphaSize); + if ( Params.WithAlphaChannel && attribAlphaSize == 0 ) + { + if ( log ) + os::Printer::log("No alpha."); + rating += 10; + } + else if ( !Params.WithAlphaChannel && attribAlphaSize > 0 ) + { + if ( log ) + os::Printer::log("Got alpha (unrequested).", ELL_DEBUG); + rating ++; + } + + EGLint attribStencilSize = 0; + eglGetConfigAttrib( EglDisplay, config, EGL_STENCIL_SIZE, &attribStencilSize); + if ( Params.Stencilbuffer && attribStencilSize == 0 ) + { + if ( log ) + os::Printer::log("No stencil buffer."); + rating += 10; + } + else if ( !Params.Stencilbuffer && attribStencilSize > 0 ) + { + if ( log ) + os::Printer::log("Got a stencil buffer (unrequested).", ELL_DEBUG); + rating ++; + } + + EGLint attribDepthSize = 0; + eglGetConfigAttrib( EglDisplay, config, EGL_DEPTH_SIZE, &attribDepthSize); + if ( attribDepthSize < Params.ZBufferBits ) + { + if ( log ) + { + if (attribDepthSize > 0) + os::Printer::log("No full depth buffer."); + else + os::Printer::log("No depth buffer."); + } + rating += 50; + } + else if ( attribDepthSize != Params.ZBufferBits ) + { + if ( log ) + { + if ( Params.ZBufferBits == 0 ) + os::Printer::log("Got a depth buffer (unrequested).", ELL_DEBUG); + else + os::Printer::log("Got a larger depth buffer.", ELL_DEBUG); + } + rating ++; + } + + EGLint attribSampleBuffers=0, attribSamples = 0; + eglGetConfigAttrib( EglDisplay, config, EGL_SAMPLE_BUFFERS, &attribSampleBuffers); + eglGetConfigAttrib( EglDisplay, config, EGL_SAMPLES, &attribSamples); + if ( Params.AntiAlias && attribSampleBuffers == 0 ) + { + if ( log ) + os::Printer::log("No multisampling."); + rating += 20; + } + else if ( Params.AntiAlias && attribSampleBuffers && attribSamples < Params.AntiAlias ) + { + if ( log ) + os::Printer::log("Multisampling with less samples than requested.", ELL_DEBUG); + rating += 10; + } + else if ( Params.AntiAlias && attribSampleBuffers && attribSamples > Params.AntiAlias ) + { + if ( log ) + os::Printer::log("Multisampling with more samples than requested.", ELL_DEBUG); + rating += 5; + } + else if ( !Params.AntiAlias && attribSampleBuffers > 0 ) + { + if ( log ) + os::Printer::log("Got multisampling (unrequested).", ELL_DEBUG); + rating += 3; + } + + return rating; +} + +void CEGLManager::destroySurface() +{ + if (EglSurface == EGL_NO_SURFACE) + return; + + // We should unbind current EGL context before destroy EGL surface. + eglMakeCurrent(EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + eglDestroySurface(EglDisplay, EglSurface); + EglSurface = EGL_NO_SURFACE; +} + +bool CEGLManager::generateContext() +{ + if (EglDisplay == EGL_NO_DISPLAY || EglSurface == EGL_NO_SURFACE) + return false; + + if (EglContext != EGL_NO_CONTEXT) + return true; + + EGLint OpenGLESVersion = 0; + + switch (Params.DriverType) + { + case EDT_OGLES1: + OpenGLESVersion = 1; + break; + case EDT_OGLES2: + case EDT_WEBGL1: + OpenGLESVersion = 2; + break; + default: + break; + } + + EGLint ContextAttrib[] = + { +#ifdef EGL_VERSION_1_3 + EGL_CONTEXT_CLIENT_VERSION, OpenGLESVersion, +#endif + EGL_NONE, 0 + }; + + EglContext = eglCreateContext(EglDisplay, EglConfig, EGL_NO_CONTEXT, ContextAttrib); + + if (testEGLError()) + { + os::Printer::log("Could not create EGL context.", ELL_ERROR); + return false; + } + + os::Printer::log("EGL context created with OpenGLESVersion: ", core::stringc((int)OpenGLESVersion), ELL_DEBUG); + + return true; +} + +void CEGLManager::destroyContext() +{ + if (EglContext == EGL_NO_CONTEXT) + return; + + // We must unbind current EGL context before destroy it. + eglMakeCurrent(EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroyContext(EglDisplay, EglContext); + + EglContext = EGL_NO_CONTEXT; +} + +bool CEGLManager::activateContext(const SExposedVideoData& videoData, bool restorePrimaryOnZero) +{ + eglMakeCurrent(EglDisplay, EglSurface, EglSurface, EglContext); + + if (testEGLError()) + { + os::Printer::log("Could not make EGL context current."); + return false; + } + return true; +} + +const SExposedVideoData& CEGLManager::getContext() const +{ + return Data; +} + +bool CEGLManager::swapBuffers() +{ + return (eglSwapBuffers(EglDisplay, EglSurface)==EGL_TRUE); +} + +bool CEGLManager::testEGLError() +{ +#if defined(EGL_VERSION_1_0) && defined(_DEBUG) + EGLint status = eglGetError(); + + switch (status) + { + case EGL_SUCCESS: + return false; + case EGL_NOT_INITIALIZED : + os::Printer::log("Not Initialized", ELL_ERROR); + break; + case EGL_BAD_ACCESS: + os::Printer::log("Bad Access", ELL_ERROR); + break; + case EGL_BAD_ALLOC: + os::Printer::log("Bad Alloc", ELL_ERROR); + break; + case EGL_BAD_ATTRIBUTE: + os::Printer::log("Bad Attribute", ELL_ERROR); + break; + case EGL_BAD_CONTEXT: + os::Printer::log("Bad Context", ELL_ERROR); + break; + case EGL_BAD_CONFIG: + os::Printer::log("Bad Config", ELL_ERROR); + break; + case EGL_BAD_CURRENT_SURFACE: + os::Printer::log("Bad Current Surface", ELL_ERROR); + break; + case EGL_BAD_DISPLAY: + os::Printer::log("Bad Display", ELL_ERROR); + break; + case EGL_BAD_SURFACE: + os::Printer::log("Bad Surface", ELL_ERROR); + break; + case EGL_BAD_MATCH: + os::Printer::log("Bad Match", ELL_ERROR); + break; + case EGL_BAD_PARAMETER: + os::Printer::log("Bad Parameter", ELL_ERROR); + break; + case EGL_BAD_NATIVE_PIXMAP: + os::Printer::log("Bad Native Pixmap", ELL_ERROR); + break; + case EGL_BAD_NATIVE_WINDOW: + os::Printer::log("Bad Native Window", ELL_ERROR); + break; + case EGL_CONTEXT_LOST: + os::Printer::log("Context Lost", ELL_ERROR); + break; + default: + break; + }; + + return true; +#else + return false; +#endif +} + +} +} + +#endif diff --git a/source/Irrlicht/CEGLManager.h b/source/Irrlicht/CEGLManager.h new file mode 100755 index 00000000..c82d48c6 --- /dev/null +++ b/source/Irrlicht/CEGLManager.h @@ -0,0 +1,119 @@ +// Copyright (C) 2013 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __C_EGL_MANAGER_H_INCLUDED__ +#define __C_EGL_MANAGER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_EGL_MANAGER_ + +#include + +#include "SIrrCreationParameters.h" +#include "SExposedVideoData.h" +#include "IContextManager.h" + +#ifdef _MSC_VER +#pragma comment(lib, "libEGL.lib") +#endif + +namespace irr +{ +namespace video +{ + // EGL manager. + class CEGLManager : public IContextManager + { + public: + //! Constructor. + CEGLManager(); + + //! Destructor. + virtual ~CEGLManager(); + + // Initialize EGL. + /* This method initialize EGLand create EGL display, anyway surface and context + aren't create. */ + virtual bool initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& data) _IRR_OVERRIDE_; + + // Terminate EGL. + /* Terminate EGL context. This method break both existed surface and context. */ + virtual void terminate() _IRR_OVERRIDE_; + + // Create EGL surface. + /* This method create EGL surface. On some platforms eg. Android, we must + recreate surface on each resume, because WindowID may change, so existed + surface may not be valid. If EGL context already exist, this method + automatically activates it. */ + virtual bool generateSurface() _IRR_OVERRIDE_; + + // Destroy EGL surface. + /* This method destroy EGL. On some platforms eg. Android, we should call + this method on each pause, because after resume this surface may not be valid. + Hovewer this method doesn'r break EGL context. */ + virtual void destroySurface() _IRR_OVERRIDE_; + + // Create EGL context. + /* This method create and activate EGL context. */ + virtual bool generateContext() _IRR_OVERRIDE_; + + // Destroy EGL context. + /* This method destroy EGL context. */ + virtual void destroyContext() _IRR_OVERRIDE_; + + virtual const SExposedVideoData& getContext() const _IRR_OVERRIDE_; + + virtual bool activateContext(const SExposedVideoData& videoData, bool restorePrimaryOnZero) _IRR_OVERRIDE_; + + // Swap buffers. + virtual bool swapBuffers() _IRR_OVERRIDE_; + + protected: + enum EConfigStyle + { + //! Get first result of eglChooseConfigs and if that fails try again by requesting simpler attributes + ECS_EGL_CHOOSE_FIRST_LOWER_EXPECTATIONS, + + //! We select our own best fit and avoid using eglChooseConfigs + ECS_IRR_CHOOSE, + }; + + EGLConfig chooseConfig(EConfigStyle confStyle); + + //! Check how close this config is to the parameters we requested + //! returns 0 is perfect, larger values are worse and < 0 is unusable. + irr::s32 rateConfig(EGLConfig config, EGLint eglOpenGLBIT, bool log=false); + + // Helper to sort EGLConfig's. (because we got no std::pair....) + struct SConfigRating + { + EGLConfig config; + irr::s32 rating; + bool operator<(const SConfigRating& other) const + { + return rating < other.rating; + } + }; + + private: + bool testEGLError(); + + NativeWindowType EglWindow; + EGLDisplay EglDisplay; + EGLSurface EglSurface; + EGLContext EglContext; + + EGLConfig EglConfig; + + SIrrlichtCreationParameters Params; + SExposedVideoData Data; + + EGLint MajorVersion; + EGLint MinorVersion; + }; +} +} +#endif +#endif diff --git a/source/Irrlicht/CEmptySceneNode.cpp b/source/Irrlicht/CEmptySceneNode.cpp new file mode 100644 index 00000000..fc1b9310 --- /dev/null +++ b/source/Irrlicht/CEmptySceneNode.cpp @@ -0,0 +1,70 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CEmptySceneNode.h" +#include "ISceneManager.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CEmptySceneNode::CEmptySceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id) +: ISceneNode(parent, mgr, id) +{ + #ifdef _DEBUG + setDebugName("CEmptySceneNode"); + #endif + + setAutomaticCulling(scene::EAC_OFF); +} + + +//! pre render event +void CEmptySceneNode::OnRegisterSceneNode() +{ + if (IsVisible) + SceneManager->registerNodeForRendering(this); + + ISceneNode::OnRegisterSceneNode(); +} + + +//! render +void CEmptySceneNode::render() +{ + // do nothing +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CEmptySceneNode::getBoundingBox() const +{ + return Box; +} + + +//! Creates a clone of this scene node and its children. +ISceneNode* CEmptySceneNode::clone(ISceneNode* newParent, ISceneManager* newManager) +{ + if (!newParent) + newParent = Parent; + if (!newManager) + newManager = SceneManager; + + CEmptySceneNode* nb = new CEmptySceneNode(newParent, + newManager, ID); + + nb->cloneMembers(this, newManager); + nb->Box = Box; + + if ( newParent ) + nb->drop(); + return nb; +} + + +} // end namespace scene +} // end namespace irr diff --git a/source/Irrlicht/CEmptySceneNode.h b/source/Irrlicht/CEmptySceneNode.h new file mode 100644 index 00000000..2832595c --- /dev/null +++ b/source/Irrlicht/CEmptySceneNode.h @@ -0,0 +1,46 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_EMPTY_SCENE_NODE_H_INCLUDED__ +#define __C_EMPTY_SCENE_NODE_H_INCLUDED__ + +#include "ISceneNode.h" + +namespace irr +{ +namespace scene +{ + + class CEmptySceneNode : public ISceneNode + { + public: + + //! constructor + CEmptySceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id); + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + //! This method is called just before the rendering process of the whole scene. + virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; + + //! does nothing. + virtual void render() _IRR_OVERRIDE_; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_EMPTY; } + + //! Creates a clone of this scene node and its children. + virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + private: + + core::aabbox3d Box; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CFPSCounter.cpp b/source/Irrlicht/CFPSCounter.cpp new file mode 100644 index 00000000..48a76a46 --- /dev/null +++ b/source/Irrlicht/CFPSCounter.cpp @@ -0,0 +1,76 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CFPSCounter.h" +#include "irrMath.h" + +namespace irr +{ +namespace video +{ + + +CFPSCounter::CFPSCounter() +: FPS(60), Primitive(0), StartTime(0), FramesCounted(0), + PrimitivesCounted(0), PrimitiveAverage(0), PrimitiveTotal(0) +{ + +} + + +//! returns current fps +s32 CFPSCounter::getFPS() const +{ + return FPS; +} + + +//! returns current primitive count +u32 CFPSCounter::getPrimitive() const +{ + return Primitive; +} + + +//! returns average primitive count of last period +u32 CFPSCounter::getPrimitiveAverage() const +{ + return PrimitiveAverage; +} + + +//! returns accumulated primitive count since start +u32 CFPSCounter::getPrimitiveTotal() const +{ + return PrimitiveTotal; +} + + +//! to be called every frame +void CFPSCounter::registerFrame(u32 now, u32 primitivesDrawn) +{ + ++FramesCounted; + PrimitiveTotal += primitivesDrawn; + PrimitivesCounted += primitivesDrawn; + Primitive = primitivesDrawn; + + const u32 milliseconds = now - StartTime; + + if (milliseconds >= 1500 ) + { + const f32 invMilli = core::reciprocal ( (f32) milliseconds ); + + FPS = core::ceil32 ( ( 1000 * FramesCounted ) * invMilli ); + PrimitiveAverage = core::ceil32 ( ( 1000 * PrimitivesCounted ) * invMilli ); + + FramesCounted = 0; + PrimitivesCounted = 0; + StartTime = now; + } +} + + +} // end namespace video +} // end namespace irr + diff --git a/source/Irrlicht/CFPSCounter.h b/source/Irrlicht/CFPSCounter.h new file mode 100644 index 00000000..12e0d4e8 --- /dev/null +++ b/source/Irrlicht/CFPSCounter.h @@ -0,0 +1,54 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_FPSCOUNTER_H_INCLUDED__ +#define __C_FPSCOUNTER_H_INCLUDED__ + +#include "irrTypes.h" + +namespace irr +{ +namespace video +{ + + +class CFPSCounter +{ +public: + CFPSCounter(); + + //! returns current fps + s32 getFPS() const; + + //! returns primitive count + u32 getPrimitive() const; + + //! returns average primitive count of last period + u32 getPrimitiveAverage() const; + + //! returns accumulated primitive count since start + u32 getPrimitiveTotal() const; + + //! to be called every frame + void registerFrame(u32 now, u32 primitive); + +private: + + s32 FPS; + u32 Primitive; + u32 StartTime; + + u32 FramesCounted; + u32 PrimitivesCounted; + u32 PrimitiveAverage; + u32 PrimitiveTotal; +}; + + +} // end namespace video +} // end namespace irr + + +#endif + diff --git a/source/Irrlicht/CFileList.cpp b/source/Irrlicht/CFileList.cpp new file mode 100644 index 00000000..15d5410e --- /dev/null +++ b/source/Irrlicht/CFileList.cpp @@ -0,0 +1,163 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CFileList.h" +#include "IrrCompileConfig.h" +#include "irrArray.h" +#include "coreutil.h" + +#include "os.h" + +namespace irr +{ +namespace io +{ + +static const io::path emptyFileListEntry; + +CFileList::CFileList(const io::path& path, bool ignoreCase, bool ignorePaths) + : IgnorePaths(ignorePaths), IgnoreCase(ignoreCase), Path(path) +{ + #ifdef _DEBUG + setDebugName("CFileList"); + #endif + + Path.replace('\\', '/'); +} + +CFileList::~CFileList() +{ + Files.clear(); +} + +u32 CFileList::getFileCount() const +{ + return Files.size(); +} + +void CFileList::sort() +{ + Files.sort(); +} + +const io::path& CFileList::getFileName(u32 index) const +{ + if (index >= Files.size()) + return emptyFileListEntry; + + return Files[index].Name; +} + + +//! Gets the full name of a file in the list, path included, based on an index. +const io::path& CFileList::getFullFileName(u32 index) const +{ + if (index >= Files.size()) + return emptyFileListEntry; + + return Files[index].FullName; +} + +//! adds a file or folder +u32 CFileList::addItem(const io::path& fullPath, u32 offset, u32 size, bool isDirectory, u32 id) +{ + SFileListEntry entry; + entry.ID = id ? id : Files.size(); + entry.Offset = offset; + entry.Size = size; + entry.Name = fullPath; + entry.Name.replace('\\', '/'); + entry.IsDirectory = isDirectory; + + // remove trailing slash + if (entry.Name.lastChar() == '/') + { + entry.IsDirectory = true; + entry.Name[entry.Name.size()-1] = 0; + entry.Name.validate(); + } + + if (IgnoreCase) + entry.Name.make_lower(); + + entry.FullName = entry.Name; + + core::deletePathFromFilename(entry.Name); + + if (IgnorePaths) + entry.FullName = entry.Name; + + //os::Printer::log(Path.c_str(), entry.FullName); + + Files.push_back(entry); + + return Files.size() - 1; +} + +//! Returns the ID of a file in the file list, based on an index. +u32 CFileList::getID(u32 index) const +{ + return index < Files.size() ? Files[index].ID : 0; +} + +bool CFileList::isDirectory(u32 index) const +{ + bool ret = false; + if (index < Files.size()) + ret = Files[index].IsDirectory; + + return ret; +} + +//! Returns the size of a file +u32 CFileList::getFileSize(u32 index) const +{ + return index < Files.size() ? Files[index].Size : 0; +} + +u32 CFileList::getFileOffset(u32 index) const +{ + return index < Files.size() ? Files[index].Offset : 0; +} + + +//! Searches for a file or folder within the list, returns the index +s32 CFileList::findFile(const io::path& filename, bool isDirectory = false) const +{ + SFileListEntry entry; + // we only need FullName to be set for the search + entry.FullName = filename; + entry.IsDirectory = isDirectory; + + // exchange + entry.FullName.replace('\\', '/'); + + // remove trailing slash + if (entry.FullName.lastChar() == '/') + { + entry.IsDirectory = true; + entry.FullName[entry.FullName.size()-1] = 0; + entry.FullName.validate(); + } + + if (IgnoreCase) + entry.FullName.make_lower(); + + if (IgnorePaths) + core::deletePathFromFilename(entry.FullName); + + return Files.binary_search(entry); +} + + +//! Returns the base path of the file list +const io::path& CFileList::getPath() const +{ + return Path; +} + + +} // end namespace irr +} // end namespace io + diff --git a/source/Irrlicht/CFileList.h b/source/Irrlicht/CFileList.h new file mode 100644 index 00000000..228f231b --- /dev/null +++ b/source/Irrlicht/CFileList.h @@ -0,0 +1,138 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_FILE_LIST_H_INCLUDED__ +#define __C_FILE_LIST_H_INCLUDED__ + +#include "IFileList.h" +#include "irrString.h" +#include "irrArray.h" + + +namespace irr +{ +namespace io +{ + +//! An entry in a list of files, can be a folder or a file. +struct SFileListEntry +{ + //! The name of the file + /** If this is a file or folder in the virtual filesystem and the archive + was created with the ignoreCase flag then the file name will be lower case. */ + io::path Name; + + //! The name of the file including the path + /** If this is a file or folder in the virtual filesystem and the archive was + created with the ignoreDirs flag then it will be the same as Name. */ + io::path FullName; + + //! The size of the file in bytes + u32 Size; + + //! The ID of the file in an archive + /** This is used to link the FileList entry to extra info held about this + file in an archive, which can hold things like data offset and CRC. */ + u32 ID; + + //! FileOffset inside an archive + u32 Offset; + + //! True if this is a folder, false if not. + bool IsDirectory; + + //! The == operator is provided so that CFileList can slowly search the list! + bool operator ==(const struct SFileListEntry& other) const + { + if (IsDirectory != other.IsDirectory) + return false; + + return FullName.equals_ignore_case(other.FullName); + } + + //! The < operator is provided so that CFileList can sort and quickly search the list. + bool operator <(const struct SFileListEntry& other) const + { + if (IsDirectory != other.IsDirectory) + return IsDirectory; + + return FullName.lower_ignore_case(other.FullName); + } +}; + + +//! Implementation of a file list +class CFileList : public IFileList +{ +public: + + // CFileList methods + + //! Constructor + /** \param path The path of this file archive */ + CFileList(const io::path& path, bool ignoreCase, bool ignorePaths); + + //! Destructor + virtual ~CFileList(); + + //! Add as a file or folder to the list + /** \param fullPath The file name including path, up to the root of the file list. + \param isDirectory True if this is a directory rather than a file. + \param offset The offset where the file is stored in an archive + \param size The size of the file in bytes. + \param id The ID of the file in the archive which owns it */ + virtual u32 addItem(const io::path& fullPath, u32 offset, u32 size, bool isDirectory, u32 id=0) _IRR_OVERRIDE_; + + //! Sorts the file list. You should call this after adding any items to the file list + virtual void sort() _IRR_OVERRIDE_; + + //! Returns the amount of files in the filelist. + virtual u32 getFileCount() const _IRR_OVERRIDE_; + + //! Gets the name of a file in the list, based on an index. + virtual const io::path& getFileName(u32 index) const _IRR_OVERRIDE_; + + //! Gets the full name of a file in the list, path included, based on an index. + virtual const io::path& getFullFileName(u32 index) const _IRR_OVERRIDE_; + + //! Returns the ID of a file in the file list, based on an index. + virtual u32 getID(u32 index) const _IRR_OVERRIDE_; + + //! Returns true if the file is a directory + virtual bool isDirectory(u32 index) const _IRR_OVERRIDE_; + + //! Returns the size of a file + virtual u32 getFileSize(u32 index) const _IRR_OVERRIDE_; + + //! Returns the offset of a file + virtual u32 getFileOffset(u32 index) const _IRR_OVERRIDE_; + + //! Searches for a file or folder within the list, returns the index + virtual s32 findFile(const io::path& filename, bool isFolder) const _IRR_OVERRIDE_; + + //! Returns the base path of the file list + virtual const io::path& getPath() const _IRR_OVERRIDE_; + +protected: + + //! Ignore paths when adding or searching for files + bool IgnorePaths; + + //! Ignore case when adding or searching for files + bool IgnoreCase; + + //! Path to the file list + io::path Path; + + //! List of files + core::array Files; +}; + + +} // end namespace irr +} // end namespace io + + +#endif + diff --git a/source/Irrlicht/CFileSystem.cpp b/source/Irrlicht/CFileSystem.cpp new file mode 100644 index 00000000..6e336b91 --- /dev/null +++ b/source/Irrlicht/CFileSystem.cpp @@ -0,0 +1,1127 @@ +// Copyright (C) 2002-2012 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" + +#include "CFileSystem.h" +#include "IReadFile.h" +#include "IWriteFile.h" +#include "CZipReader.h" +#include "CMountPointReader.h" +#include "CPakReader.h" +#include "CNPKReader.h" +#include "CTarReader.h" +#include "CWADReader.h" +#include "CFileList.h" +#include "CXMLReader.h" +#include "CXMLWriter.h" +#include "stdio.h" +#include "os.h" +#include "CAttributes.h" +#include "CReadFile.h" +#include "CMemoryFile.h" +#include "CLimitReadFile.h" +#include "CWriteFile.h" +#include "irrList.h" + +#if defined (__STRICT_ANSI__) + #error Compiling with __STRICT_ANSI__ not supported. g++ does set this when compiling with -std=c++11 or -std=c++0x. Use instead -std=gnu++11 or -std=gnu++0x. Or use -U__STRICT_ANSI__ to disable strict ansi. +#endif + +#if defined (_IRR_WINDOWS_API_) + #if !defined ( _WIN32_WCE ) + #include // for _chdir + #include // for _access + #include + #endif +#elif (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_) || defined(_IRR_IOS_PLATFORM_) || defined(_IRR_ANDROID_PLATFORM_)) + #include + #include + #include + #include + #include + #include + #include + #include +#elif defined(_IRR_EMSCRIPTEN_PLATFORM_) + #include +#endif + +namespace irr +{ +namespace io +{ + +//! constructor +CFileSystem::CFileSystem() +{ + #ifdef _DEBUG + setDebugName("CFileSystem"); + #endif + + setFileListSystem(FILESYSTEM_NATIVE); + //! reset current working directory + getWorkingDirectory(); + +#ifdef __IRR_COMPILE_WITH_PAK_ARCHIVE_LOADER_ + ArchiveLoader.push_back(new CArchiveLoaderPAK(this)); +#endif + +#ifdef __IRR_COMPILE_WITH_NPK_ARCHIVE_LOADER_ + ArchiveLoader.push_back(new CArchiveLoaderNPK(this)); +#endif + +#ifdef __IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_ + ArchiveLoader.push_back(new CArchiveLoaderTAR(this)); +#endif + +#ifdef __IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_ + ArchiveLoader.push_back(new CArchiveLoaderWAD(this)); +#endif + +#ifdef __IRR_COMPILE_WITH_MOUNT_ARCHIVE_LOADER_ + ArchiveLoader.push_back(new CArchiveLoaderMount(this)); +#endif + +#ifdef __IRR_COMPILE_WITH_ZIP_ARCHIVE_LOADER_ + ArchiveLoader.push_back(new CArchiveLoaderZIP(this)); +#endif + +} + + +//! destructor +CFileSystem::~CFileSystem() +{ + u32 i; + + for ( i=0; i < FileArchives.size(); ++i) + { + FileArchives[i]->drop(); + } + + for ( i=0; i < ArchiveLoader.size(); ++i) + { + ArchiveLoader[i]->drop(); + } +} + + +//! opens a file for read access +IReadFile* CFileSystem::createAndOpenFile(const io::path& filename) +{ + if ( filename.empty() ) + return 0; + + IReadFile* file = 0; + u32 i; + + for (i=0; i< FileArchives.size(); ++i) + { + file = FileArchives[i]->createAndOpenFile(filename); + if (file) + return file; + } + + // Create the file using an absolute path so that it matches + // the scheme used by CNullDriver::getTexture(). + return CReadFile::createReadFile(getAbsolutePath(filename)); +} + + +//! Creates an IReadFile interface for treating memory like a file. +IReadFile* CFileSystem::createMemoryReadFile(const void* memory, s32 len, + const io::path& fileName, bool deleteMemoryWhenDropped) +{ + if (!memory) + return 0; + else + return new CMemoryReadFile(memory, len, fileName, deleteMemoryWhenDropped); +} + + +//! Creates an IReadFile interface for reading files inside files +IReadFile* CFileSystem::createLimitReadFile(const io::path& fileName, + IReadFile* alreadyOpenedFile, long pos, long areaSize) +{ + if (!alreadyOpenedFile) + return 0; + else + return new CLimitReadFile(alreadyOpenedFile, pos, areaSize, fileName); +} + + +//! Creates an IReadFile interface for treating memory like a file. +IWriteFile* CFileSystem::createMemoryWriteFile(void* memory, s32 len, + const io::path& fileName, bool deleteMemoryWhenDropped) +{ + if (!memory) + return 0; + else + return new CMemoryWriteFile(memory, len, fileName, deleteMemoryWhenDropped); +} + + +//! Opens a file for write access. +IWriteFile* CFileSystem::createAndWriteFile(const io::path& filename, bool append) +{ + return CWriteFile::createWriteFile(filename, append); +} + + +//! Adds an external archive loader to the engine. +void CFileSystem::addArchiveLoader(IArchiveLoader* loader) +{ + if (!loader) + return; + + loader->grab(); + ArchiveLoader.push_back(loader); +} + +//! Returns the total number of archive loaders added. +u32 CFileSystem::getArchiveLoaderCount() const +{ + return ArchiveLoader.size(); +} + +//! Gets the archive loader by index. +IArchiveLoader* CFileSystem::getArchiveLoader(u32 index) const +{ + if (index < ArchiveLoader.size()) + return ArchiveLoader[index]; + else + return 0; +} + +//! move the hirarchy of the filesystem. moves sourceIndex relative up or down +bool CFileSystem::moveFileArchive(u32 sourceIndex, s32 relative) +{ + bool r = false; + const s32 dest = (s32) sourceIndex + relative; + const s32 dir = relative < 0 ? -1 : 1; + const s32 sourceEnd = ((s32) FileArchives.size() ) - 1; + IFileArchive *t; + + for (s32 s = (s32) sourceIndex;s != dest; s += dir) + { + if (s < 0 || s > sourceEnd || s + dir < 0 || s + dir > sourceEnd) + continue; + + t = FileArchives[s + dir]; + FileArchives[s + dir] = FileArchives[s]; + FileArchives[s] = t; + r = true; + } + return r; +} + + +//! Adds an archive to the file system. +bool CFileSystem::addFileArchive(const io::path& filename, bool ignoreCase, + bool ignorePaths, E_FILE_ARCHIVE_TYPE archiveType, + const core::stringc& password, + IFileArchive** retArchive) +{ + IFileArchive* archive = 0; + bool ret = false; + + // see if archive is already added + if (changeArchivePassword(filename, password, retArchive)) + return true; + + s32 i; + + // do we know what type it should be? + if (archiveType == EFAT_UNKNOWN || archiveType == EFAT_FOLDER) + { + // try to load archive based on file name + for (i = ArchiveLoader.size()-1; i >=0 ; --i) + { + if (ArchiveLoader[i]->isALoadableFileFormat(filename)) + { + archive = ArchiveLoader[i]->createArchive(filename, ignoreCase, ignorePaths); + if (archive) + break; + } + } + + // try to load archive based on content + if (!archive) + { + io::IReadFile* file = createAndOpenFile(filename); + if (file) + { + for (i = ArchiveLoader.size()-1; i >= 0; --i) + { + file->seek(0); + if (ArchiveLoader[i]->isALoadableFileFormat(file)) + { + file->seek(0); + archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths); + if (archive) + break; + } + } + file->drop(); + } + } + } + else + { + // try to open archive based on archive loader type + + io::IReadFile* file = 0; + + for (i = ArchiveLoader.size()-1; i >= 0; --i) + { + if (ArchiveLoader[i]->isALoadableFileFormat(archiveType)) + { + // attempt to open file + if (!file) + file = createAndOpenFile(filename); + + // is the file open? + if (file) + { + // attempt to open archive + file->seek(0); + if (ArchiveLoader[i]->isALoadableFileFormat(file)) + { + file->seek(0); + archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths); + if (archive) + break; + } + } + else + { + // couldn't open file + break; + } + } + } + + // if open, close the file + if (file) + file->drop(); + } + + if (archive) + { + FileArchives.push_back(archive); + if (password.size()) + archive->Password=password; + if (retArchive) + *retArchive = archive; + ret = true; + } + else + { + os::Printer::log("Could not create archive for", filename, ELL_ERROR); + } + + return ret; +} + +// don't expose! +bool CFileSystem::changeArchivePassword(const path& filename, + const core::stringc& password, + IFileArchive** archive) +{ + for (s32 idx = 0; idx < (s32)FileArchives.size(); ++idx) + { + // TODO: This should go into a path normalization method + // We need to check for directory names with trailing slash and without + const path absPath = getAbsolutePath(filename); + const path arcPath = FileArchives[idx]->getFileList()->getPath(); + if ((absPath == arcPath) || ((absPath+_IRR_TEXT("/")) == arcPath)) + { + if (password.size()) + FileArchives[idx]->Password=password; + if (archive) + *archive = FileArchives[idx]; + return true; + } + } + + return false; +} + +bool CFileSystem::addFileArchive(IReadFile* file, bool ignoreCase, + bool ignorePaths, E_FILE_ARCHIVE_TYPE archiveType, + const core::stringc& password, IFileArchive** retArchive) +{ + if (!file || archiveType == EFAT_FOLDER) + return false; + + if (file) + { + if (changeArchivePassword(file->getFileName(), password, retArchive)) + return true; + + IFileArchive* archive = 0; + s32 i; + + if (archiveType == EFAT_UNKNOWN) + { + // try to load archive based on file name + for (i = ArchiveLoader.size()-1; i >=0 ; --i) + { + if (ArchiveLoader[i]->isALoadableFileFormat(file->getFileName())) + { + archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths); + if (archive) + break; + } + } + + // try to load archive based on content + if (!archive) + { + for (i = ArchiveLoader.size()-1; i >= 0; --i) + { + file->seek(0); + if (ArchiveLoader[i]->isALoadableFileFormat(file)) + { + file->seek(0); + archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths); + if (archive) + break; + } + } + } + } + else + { + // try to open archive based on archive loader type + for (i = ArchiveLoader.size()-1; i >= 0; --i) + { + if (ArchiveLoader[i]->isALoadableFileFormat(archiveType)) + { + // attempt to open archive + file->seek(0); + if (ArchiveLoader[i]->isALoadableFileFormat(file)) + { + file->seek(0); + archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths); + if (archive) + break; + } + } + } + } + + if (archive) + { + FileArchives.push_back(archive); + if (password.size()) + archive->Password=password; + if (retArchive) + *retArchive = archive; + return true; + } + else + { + os::Printer::log("Could not create archive for", file->getFileName(), ELL_ERROR); + } + } + + return false; +} + + +//! Adds an archive to the file system. +bool CFileSystem::addFileArchive(IFileArchive* archive) +{ + if ( archive ) + { + for (u32 i=0; i < FileArchives.size(); ++i) + { + if (archive == FileArchives[i]) + { + return false; + } + } + FileArchives.push_back(archive); + archive->grab(); + + return true; + } + + return false; +} + + +//! removes an archive from the file system. +bool CFileSystem::removeFileArchive(u32 index) +{ + bool ret = false; + if (index < FileArchives.size()) + { + FileArchives[index]->drop(); + FileArchives.erase(index); + ret = true; + } + return ret; +} + + +//! removes an archive from the file system. +bool CFileSystem::removeFileArchive(const io::path& filename) +{ + const path absPath = getAbsolutePath(filename); + for (u32 i=0; i < FileArchives.size(); ++i) + { + if (absPath == FileArchives[i]->getFileList()->getPath()) + return removeFileArchive(i); + } + return false; +} + + +//! Removes an archive from the file system. +bool CFileSystem::removeFileArchive(const IFileArchive* archive) +{ + for (u32 i=0; i < FileArchives.size(); ++i) + { + if (archive == FileArchives[i]) + { + return removeFileArchive(i); + } + } + return false; +} + + +//! gets an archive +u32 CFileSystem::getFileArchiveCount() const +{ + return FileArchives.size(); +} + + +IFileArchive* CFileSystem::getFileArchive(u32 index) +{ + return index < getFileArchiveCount() ? FileArchives[index] : 0; +} + + +//! Returns the string of the current working directory +const io::path& CFileSystem::getWorkingDirectory() +{ + EFileSystemType type = FileSystemType; + + if (type != FILESYSTEM_NATIVE) + { + type = FILESYSTEM_VIRTUAL; + } + else + { + #if defined(_IRR_WINDOWS_API_) + fschar_t tmp[_MAX_PATH]; + #if defined(_IRR_WCHAR_FILESYSTEM ) + _wgetcwd(tmp, _MAX_PATH); + WorkingDirectory[FILESYSTEM_NATIVE] = tmp; + WorkingDirectory[FILESYSTEM_NATIVE].replace(L'\\', L'/'); + #else + _getcwd(tmp, _MAX_PATH); + WorkingDirectory[FILESYSTEM_NATIVE] = tmp; + WorkingDirectory[FILESYSTEM_NATIVE].replace('\\', '/'); + #endif + #endif + + #if (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_)) + + // getting the CWD is rather complex as we do not know the size + // so try it until the call was successful + // Note that neither the first nor the second parameter may be 0 according to POSIX + + #if defined(_IRR_WCHAR_FILESYSTEM ) + u32 pathSize=256; + wchar_t *tmpPath = new wchar_t[pathSize]; + while ((pathSize < (1<<16)) && !(wgetcwd(tmpPath,pathSize))) + { + delete [] tmpPath; + pathSize *= 2; + tmpPath = new char[pathSize]; + } + if (tmpPath) + { + WorkingDirectory[FILESYSTEM_NATIVE] = tmpPath; + delete [] tmpPath; + } + #else + u32 pathSize=256; + char *tmpPath = new char[pathSize]; + while ((pathSize < (1<<16)) && !(getcwd(tmpPath,pathSize))) + { + delete [] tmpPath; + pathSize *= 2; + tmpPath = new char[pathSize]; + } + if (tmpPath) + { + WorkingDirectory[FILESYSTEM_NATIVE] = tmpPath; + delete [] tmpPath; + } + #endif + #endif + + WorkingDirectory[type].validate(); + } + + return WorkingDirectory[type]; +} + + +//! Changes the current Working Directory to the given string. +bool CFileSystem::changeWorkingDirectoryTo(const io::path& newDirectory) +{ + bool success=false; + + if (FileSystemType != FILESYSTEM_NATIVE) + { + WorkingDirectory[FILESYSTEM_VIRTUAL] = newDirectory; + // is this empty string constant really intended? + flattenFilename(WorkingDirectory[FILESYSTEM_VIRTUAL], _IRR_TEXT("")); + success = true; + } + else + { + WorkingDirectory[FILESYSTEM_NATIVE] = newDirectory; + +#if defined(_MSC_VER) + #if defined(_IRR_WCHAR_FILESYSTEM) + success = (_wchdir(newDirectory.c_str()) == 0); + #else + success = (_chdir(newDirectory.c_str()) == 0); + #endif +#else + #if defined(_IRR_WCHAR_FILESYSTEM) + success = (_wchdir(newDirectory.c_str()) == 0); + #else + success = (chdir(newDirectory.c_str()) == 0); + #endif +#endif + } + + return success; +} + + +io::path CFileSystem::getAbsolutePath(const io::path& filename) const +{ + if ( filename.empty() ) + return filename; +#if defined(_IRR_WINDOWS_API_) + fschar_t *p=0; + fschar_t fpath[_MAX_PATH]; + #if defined(_IRR_WCHAR_FILESYSTEM ) + p = _wfullpath(fpath, filename.c_str(), _MAX_PATH); + core::stringw tmp(p); + tmp.replace(L'\\', L'/'); + #else + p = _fullpath(fpath, filename.c_str(), _MAX_PATH); + core::stringc tmp(p); + tmp.replace('\\', '/'); + #endif + return tmp; +#elif (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_)) + c8* p=0; + c8 fpath[4096]; + fpath[0]=0; + p = realpath(filename.c_str(), fpath); + if (!p) + { + // content in fpath is unclear at this point + if (!fpath[0]) // seems like fpath wasn't altered, use our best guess + { + io::path tmp(filename); + return flattenFilename(tmp); + } + else + return io::path(fpath); + } + if (filename[filename.size()-1]=='/') + return io::path(p)+_IRR_TEXT("/"); + else + return io::path(p); +#else + return io::path(filename); +#endif +} + + +//! returns the directory part of a filename, i.e. all until the first +//! slash or backslash, excluding it. If no directory path is prefixed, a '.' +//! is returned. +io::path CFileSystem::getFileDir(const io::path& filename) const +{ + // find last forward or backslash + s32 lastSlash = filename.findLast('/'); + const s32 lastBackSlash = filename.findLast('\\'); + lastSlash = lastSlash > lastBackSlash ? lastSlash : lastBackSlash; + + if ((u32)lastSlash < filename.size()) + return filename.subString(0, lastSlash); + else + return _IRR_TEXT("."); +} + + +//! returns the base part of a filename, i.e. all except for the directory +//! part. If no directory path is prefixed, the full name is returned. +io::path CFileSystem::getFileBasename(const io::path& filename, bool keepExtension) const +{ + // find last forward or backslash + s32 lastSlash = filename.findLast('/'); + const s32 lastBackSlash = filename.findLast('\\'); + lastSlash = core::max_(lastSlash, lastBackSlash); + + // get number of chars after last dot + s32 end = 0; + if (!keepExtension) + { + // take care to search only after last slash to check only for + // dots in the filename + end = filename.findLast('.'); + if (end == -1 || end < lastSlash) + end=0; + else + end = filename.size()-end; + } + + if ((u32)lastSlash < filename.size()) + return filename.subString(lastSlash+1, filename.size()-lastSlash-1-end); + else if (end != 0) + return filename.subString(0, filename.size()-end); + else + return filename; +} + + +//! flatten a path and file name for example: "/you/me/../." becomes "/you" +io::path& CFileSystem::flattenFilename(io::path& directory, const io::path& root) const +{ + directory.replace('\\', '/'); + if (directory.lastChar() != '/') + directory.append('/'); + + io::path dir; + io::path subdir; + + s32 lastpos = 0; + s32 pos = 0; + bool lastWasRealDir=false; + + while ((pos = directory.findNext('/', lastpos)) >= 0) + { + subdir = directory.subString(lastpos, pos - lastpos + 1); + + if (subdir == _IRR_TEXT("../")) + { + if (lastWasRealDir) + { + deletePathFromPath(dir, 2); + lastWasRealDir=(dir.size()!=0); + } + else + { + dir.append(subdir); + lastWasRealDir=false; + } + } + else if (subdir == _IRR_TEXT("/")) + { + dir = root; + } + else if (subdir != _IRR_TEXT("./")) + { + dir.append(subdir); + lastWasRealDir=true; + } + + lastpos = pos + 1; + } + directory = dir; + return directory; +} + + +//! Get the relative filename, relative to the given directory +path CFileSystem::getRelativeFilename(const path& filename, const path& directory) const +{ + if ( filename.empty() || directory.empty() ) + return filename; + + io::path path1, file, ext; + core::splitFilename(getAbsolutePath(filename), &path1, &file, &ext); + io::path path2(getAbsolutePath(directory)); + core::list list1, list2; + path1.split(list1, _IRR_TEXT("/\\"), 2); + path2.split(list2, _IRR_TEXT("/\\"), 2); + u32 i=0; + core::list::ConstIterator it1,it2; + it1=list1.begin(); + it2=list2.begin(); + + #if defined (_IRR_WINDOWS_API_) + fschar_t partition1 = 0, partition2 = 0; + io::path prefix1, prefix2; + if ( it1 != list1.end() ) + prefix1 = *it1; + if ( it2 != list2.end() ) + prefix2 = *it2; + if ( prefix1.size() > 1 && prefix1[1] == _IRR_TEXT(':') ) + partition1 = core::locale_lower(prefix1[0]); + if ( prefix2.size() > 1 && prefix2[1] == _IRR_TEXT(':') ) + partition2 = core::locale_lower(prefix2[0]); + + // must have the same prefix or we can't resolve it to a relative filename + if ( partition1 != partition2 ) + { + return filename; + } + #endif + + + for (; iaddItem(Path + c_file.name, 0, c_file.size, (_A_SUBDIR & c_file.attrib) != 0, 0); + } + while( _tfindnext( hFile, &c_file ) == 0 ); + + _findclose( hFile ); + } + #endif + + //TODO add drives + //entry.Name = "E:\\"; + //entry.isDirectory = true; + //Files.push_back(entry); + #endif + + // -------------------------------------------- + //! Linux version + #if (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_)) + + + r = new CFileList(Path, false, false); + + r->addItem(Path + _IRR_TEXT(".."), 0, 0, true, 0); + + //! We use the POSIX compliant methods instead of scandir + DIR* dirHandle=opendir(Path.c_str()); + if (dirHandle) + { + struct dirent *dirEntry; + while ((dirEntry=readdir(dirHandle))) + { + u32 size = 0; + bool isDirectory = false; + + if((strcmp(dirEntry->d_name, ".")==0) || + (strcmp(dirEntry->d_name, "..")==0)) + { + continue; + } + struct stat buf; + if (stat(dirEntry->d_name, &buf)==0) + { + size = buf.st_size; + isDirectory = S_ISDIR(buf.st_mode); + } + #if !defined(_IRR_SOLARIS_PLATFORM_) && !defined(__CYGWIN__) + // only available on some systems + else + { + isDirectory = dirEntry->d_type == DT_DIR; + } + #endif + + r->addItem(Path + dirEntry->d_name, 0, size, isDirectory, 0); + } + closedir(dirHandle); + } + #endif + } + else + { + //! create file list for the virtual filesystem + r = new CFileList(Path, false, false); + + //! add relative navigation + SFileListEntry e2; + SFileListEntry e3; + + //! PWD + r->addItem(Path + _IRR_TEXT("."), 0, 0, true, 0); + + //! parent + r->addItem(Path + _IRR_TEXT(".."), 0, 0, true, 0); + + //! merge archives + for (u32 i=0; i < FileArchives.size(); ++i) + { + const IFileList *merge = FileArchives[i]->getFileList(); + + for (u32 j=0; j < merge->getFileCount(); ++j) + { + if (core::isInSameDirectory(Path, merge->getFullFileName(j)) == 0) + { + r->addItem(merge->getFullFileName(j), merge->getFileOffset(j), merge->getFileSize(j), merge->isDirectory(j), 0); + } + } + } + } + + if (r) + r->sort(); + return r; +} + +//! Creates an empty filelist +IFileList* CFileSystem::createEmptyFileList(const io::path& path, bool ignoreCase, bool ignorePaths) +{ + return new CFileList(path, ignoreCase, ignorePaths); +} + + +//! determines if a file exists and would be able to be opened. +bool CFileSystem::existFile(const io::path& filename) const +{ + for (u32 i=0; i < FileArchives.size(); ++i) + if (FileArchives[i]->getFileList()->findFile(filename)!=-1) + return true; + +#if defined(_MSC_VER) + #if defined(_IRR_WCHAR_FILESYSTEM) + return (_waccess(filename.c_str(), 0) != -1); + #else + return (_access(filename.c_str(), 0) != -1); + #endif +#elif defined(F_OK) + #if defined(_IRR_WCHAR_FILESYSTEM) + return (_waccess(filename.c_str(), F_OK) != -1); + #else + return (access(filename.c_str(), F_OK) != -1); + #endif +#else + return (access(filename.c_str(), 0) != -1); +#endif +} + + +//! Creates a XML Reader from a file. +IXMLReader* CFileSystem::createXMLReader(const io::path& filename) +{ +#ifdef _IRR_COMPILE_WITH_XML_ + IReadFile* file = createAndOpenFile(filename); + if (!file) + return 0; + + IXMLReader* reader = createXMLReader(file); + file->drop(); + return reader; +#else + noXML(); + return 0; +#endif +} + + +//! Creates a XML Reader from a file. +IXMLReader* CFileSystem::createXMLReader(IReadFile* file) +{ +#ifdef _IRR_COMPILE_WITH_XML_ + if (!file) + return 0; + + return createIXMLReader(file); +#else + noXML(); + return 0; +#endif +} + + +//! Creates a XML Reader from a file. +IXMLReaderUTF8* CFileSystem::createXMLReaderUTF8(const io::path& filename) +{ +#ifdef _IRR_COMPILE_WITH_XML_ + IReadFile* file = createAndOpenFile(filename); + if (!file) + return 0; + + IXMLReaderUTF8* reader = createIXMLReaderUTF8(file); + file->drop(); + return reader; +#else + noXML(); + return 0; +#endif +} + + +//! Creates a XML Reader from a file. +IXMLReaderUTF8* CFileSystem::createXMLReaderUTF8(IReadFile* file) +{ +#ifdef _IRR_COMPILE_WITH_XML_ + if (!file) + return 0; + + return createIXMLReaderUTF8(file); +#else + noXML(); + return 0; +#endif +} + + +//! Creates a XML Writer from a file. +IXMLWriter* CFileSystem::createXMLWriter(const io::path& filename) +{ +#ifdef _IRR_COMPILE_WITH_XML_ + IWriteFile* file = createAndWriteFile(filename); + IXMLWriter* writer = 0; + if (file) + { + writer = createXMLWriter(file); + file->drop(); + } + return writer; +#else + noXML(); + return 0; +#endif +} + + +//! Creates a XML Writer from a file. +IXMLWriter* CFileSystem::createXMLWriter(IWriteFile* file) +{ +#ifdef _IRR_COMPILE_WITH_XML_ + return createIXMLWriter(file); +#else + noXML(); + return 0; +#endif +} + +//! Creates a XML Writer from a file. +IXMLWriterUTF8* CFileSystem::createXMLWriterUTF8(const io::path& filename) +{ +#ifdef _IRR_COMPILE_WITH_XML_ + IWriteFile* file = createAndWriteFile(filename); + IXMLWriterUTF8* writer = 0; + if (file) + { + writer = createXMLWriterUTF8(file); + file->drop(); + } + return writer; +#else + noXML(); + return 0; +#endif +} + + +//! Creates a XML Writer from a file. +IXMLWriterUTF8* CFileSystem::createXMLWriterUTF8(IWriteFile* file) +{ +#ifdef _IRR_COMPILE_WITH_XML_ + return createIXMLWriterUTF8(file); +#else + noXML(); + return 0; +#endif +} + + +//! creates a filesystem which is able to open files from the ordinary file system, +//! and out of zipfiles, which are able to be added to the filesystem. +IFileSystem* createFileSystem() +{ + return new CFileSystem(); +} + + +//! Creates a new empty collection of attributes, usable for serialization and more. +IAttributes* CFileSystem::createEmptyAttributes(video::IVideoDriver* driver) +{ + return new CAttributes(driver); +} + + +} // end namespace irr +} // end namespace io diff --git a/source/Irrlicht/CFileSystem.h b/source/Irrlicht/CFileSystem.h new file mode 100644 index 00000000..87c51340 --- /dev/null +++ b/source/Irrlicht/CFileSystem.h @@ -0,0 +1,179 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_FILE_SYSTEM_H_INCLUDED__ +#define __C_FILE_SYSTEM_H_INCLUDED__ + +#include "IFileSystem.h" +#include "irrArray.h" + +namespace irr +{ +namespace io +{ + + class CZipReader; + class CPakReader; + class CMountPointReader; + +/*! + FileSystem which uses normal files and one zipfile +*/ +class CFileSystem : public IFileSystem +{ +public: + + //! constructor + CFileSystem(); + + //! destructor + virtual ~CFileSystem(); + + //! opens a file for read access + virtual IReadFile* createAndOpenFile(const io::path& filename) _IRR_OVERRIDE_; + + //! Creates an IReadFile interface for accessing memory like a file. + virtual IReadFile* createMemoryReadFile(const void* memory, s32 len, const io::path& fileName, bool deleteMemoryWhenDropped = false) _IRR_OVERRIDE_; + + //! Creates an IReadFile interface for accessing files inside files + virtual IReadFile* createLimitReadFile(const io::path& fileName, IReadFile* alreadyOpenedFile, long pos, long areaSize) _IRR_OVERRIDE_; + + //! Creates an IWriteFile interface for accessing memory like a file. + virtual IWriteFile* createMemoryWriteFile(void* memory, s32 len, const io::path& fileName, bool deleteMemoryWhenDropped=false) _IRR_OVERRIDE_; + + //! Opens a file for write access. + virtual IWriteFile* createAndWriteFile(const io::path& filename, bool append=false) _IRR_OVERRIDE_; + + //! Adds an archive to the file system. + virtual bool addFileArchive(const io::path& filename, + bool ignoreCase = true, bool ignorePaths = true, + E_FILE_ARCHIVE_TYPE archiveType = EFAT_UNKNOWN, + const core::stringc& password="", + IFileArchive** retArchive = 0) _IRR_OVERRIDE_; + + //! Adds an archive to the file system. + virtual bool addFileArchive(IReadFile* file, bool ignoreCase=true, + bool ignorePaths=true, + E_FILE_ARCHIVE_TYPE archiveType=EFAT_UNKNOWN, + const core::stringc& password="", + IFileArchive** retArchive = 0) _IRR_OVERRIDE_; + + //! Adds an archive to the file system. + virtual bool addFileArchive(IFileArchive* archive) _IRR_OVERRIDE_; + + //! move the hirarchy of the filesystem. moves sourceIndex relative up or down + virtual bool moveFileArchive(u32 sourceIndex, s32 relative) _IRR_OVERRIDE_; + + //! Adds an external archive loader to the engine. + virtual void addArchiveLoader(IArchiveLoader* loader) _IRR_OVERRIDE_; + + //! Returns the total number of archive loaders added. + virtual u32 getArchiveLoaderCount() const _IRR_OVERRIDE_; + + //! Gets the archive loader by index. + virtual IArchiveLoader* getArchiveLoader(u32 index) const _IRR_OVERRIDE_; + + //! gets the file archive count + virtual u32 getFileArchiveCount() const _IRR_OVERRIDE_; + + //! gets an archive + virtual IFileArchive* getFileArchive(u32 index) _IRR_OVERRIDE_; + + //! removes an archive from the file system. + virtual bool removeFileArchive(u32 index) _IRR_OVERRIDE_; + + //! removes an archive from the file system. + virtual bool removeFileArchive(const io::path& filename) _IRR_OVERRIDE_; + + //! Removes an archive from the file system. + virtual bool removeFileArchive(const IFileArchive* archive) _IRR_OVERRIDE_; + + //! Returns the string of the current working directory + virtual const io::path& getWorkingDirectory() _IRR_OVERRIDE_; + + //! Changes the current Working Directory to the string given. + //! The string is operating system dependent. Under Windows it will look + //! like this: "drive:\directory\sudirectory\" + virtual bool changeWorkingDirectoryTo(const io::path& newDirectory) _IRR_OVERRIDE_; + + //! Converts a relative path to an absolute (unique) path, resolving symbolic links + virtual io::path getAbsolutePath(const io::path& filename) const _IRR_OVERRIDE_; + + //! Returns the directory a file is located in. + /** \param filename: The file to get the directory from */ + virtual io::path getFileDir(const io::path& filename) const _IRR_OVERRIDE_; + + //! 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 */ + virtual io::path getFileBasename(const io::path& filename, bool keepExtension=true) const _IRR_OVERRIDE_; + + //! flatten a path and file name for example: "/you/me/../." becomes "/you" + virtual io::path& flattenFilename( io::path& directory, const io::path& root = "/" ) const _IRR_OVERRIDE_; + + //! Get the relative filename, relative to the given directory + virtual path getRelativeFilename(const path& filename, const path& directory) const _IRR_OVERRIDE_; + + virtual EFileSystemType setFileListSystem(EFileSystemType listType) _IRR_OVERRIDE_; + + //! Creates a list of files and directories in the current working directory + //! and returns it. + virtual IFileList* createFileList() _IRR_OVERRIDE_; + + //! Creates an empty filelist + virtual IFileList* createEmptyFileList(const io::path& path, bool ignoreCase, bool ignorePaths) _IRR_OVERRIDE_; + + //! determines if a file exists and would be able to be opened. + virtual bool existFile(const io::path& filename) const _IRR_OVERRIDE_; + + //! Creates a XML Reader from a file. + virtual IXMLReader* createXMLReader(const io::path& filename) _IRR_OVERRIDE_; + + //! Creates a XML Reader from a file. + virtual IXMLReader* createXMLReader(IReadFile* file) _IRR_OVERRIDE_; + + //! Creates a XML Reader from a file. + virtual IXMLReaderUTF8* createXMLReaderUTF8(const io::path& filename) _IRR_OVERRIDE_; + + //! Creates a XML Reader from a file. + virtual IXMLReaderUTF8* createXMLReaderUTF8(IReadFile* file) _IRR_OVERRIDE_; + + //! Creates a XML Writer from a file. + virtual IXMLWriter* createXMLWriter(const io::path& filename) _IRR_OVERRIDE_; + + //! Creates a XML Writer from a file. + virtual IXMLWriter* createXMLWriter(IWriteFile* file) _IRR_OVERRIDE_; + + //! Creates a XML Writer from a file which will write ASCII/UTF-8 characters (char*). + virtual IXMLWriterUTF8* createXMLWriterUTF8(const path& filename) _IRR_OVERRIDE_; + + //! Creates a XML Writer from a file which will write ASCII/UTF-8 characters (char*). + virtual IXMLWriterUTF8* createXMLWriterUTF8(IWriteFile* file) _IRR_OVERRIDE_; + + //! Creates a new empty collection of attributes, usable for serialization and more. + virtual IAttributes* createEmptyAttributes(video::IVideoDriver* driver) _IRR_OVERRIDE_; + +private: + + // don't expose, needs refactoring + bool changeArchivePassword(const path& filename, + const core::stringc& password, + IFileArchive** archive = 0); + + //! Currently used FileSystemType + EFileSystemType FileSystemType; + //! WorkingDirectory for Native and Virtual filesystems + io::path WorkingDirectory [2]; + //! currently attached ArchiveLoaders + core::array ArchiveLoader; + //! currently attached Archives + core::array FileArchives; +}; + + +} // end namespace irr +} // end namespace io + +#endif + diff --git a/source/Irrlicht/CGLXManager.cpp b/source/Irrlicht/CGLXManager.cpp new file mode 100644 index 00000000..467b69c2 --- /dev/null +++ b/source/Irrlicht/CGLXManager.cpp @@ -0,0 +1,436 @@ +// Copyright (C) 2013 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#include "CGLXManager.h" + +#ifdef _IRR_COMPILE_WITH_GLX_MANAGER_ + +#include "os.h" + +#if defined(_IRR_OPENGL_USE_EXTPOINTER_) + #define GL_GLEXT_LEGACY 1 + #define GLX_GLXEXT_LEGACY 1 +#else + #define GL_GLEXT_PROTOTYPES 1 + #define GLX_GLXEXT_PROTOTYPES 1 +#endif +#include +#include +#if defined(_IRR_OPENGL_USE_EXTPOINTER_) +#include "glext.h" +#undef GLX_ARB_get_proc_address // avoid problems with local glxext.h +#include "glxext.h" +#endif + +namespace irr +{ +namespace video +{ + +CGLXManager::CGLXManager(const SIrrlichtCreationParameters& params, const SExposedVideoData& videodata, int screennr) + : Params(params), PrimaryContext(videodata), VisualInfo(0), glxFBConfig(0), GlxWin(0) +{ + #ifdef _DEBUG + setDebugName("CGLXManager"); + #endif + + CurrentContext.OpenGLLinux.X11Display=PrimaryContext.OpenGLLinux.X11Display; + + int major, minor; + Display* display = (Display*)PrimaryContext.OpenGLLinux.X11Display; + const bool isAvailableGLX=glXQueryExtension(display,&major,&minor); + + if (isAvailableGLX && glXQueryVersion(display, &major, &minor)) + { +#if defined(GLX_VERSION_1_3) + typedef GLXFBConfig * ( * PFNGLXCHOOSEFBCONFIGPROC) (Display *dpy, int screen, const int *attrib_list, int *nelements); + +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + PFNGLXCHOOSEFBCONFIGPROC glxChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)glXGetProcAddress(reinterpret_cast("glXChooseFBConfig")); +#else + PFNGLXCHOOSEFBCONFIGPROC glxChooseFBConfig=glXChooseFBConfig; +#endif + if (major==1 && minor>2 && glxChooseFBConfig) + { +os::Printer::log("GLX >= 1.3", ELL_DEBUG); + // attribute array for the draw buffer + int visualAttrBuffer[] = + { + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_RED_SIZE, 4, + GLX_GREEN_SIZE, 4, + GLX_BLUE_SIZE, 4, + GLX_ALPHA_SIZE, Params.WithAlphaChannel?1:0, + GLX_DEPTH_SIZE, Params.ZBufferBits, //10,11 + GLX_DOUBLEBUFFER, Params.Doublebuffer?True:False, + GLX_STENCIL_SIZE, Params.Stencilbuffer?1:0, +#if defined(GLX_VERSION_1_4) && defined(GLX_SAMPLE_BUFFERS) // we need to check the extension string! + GLX_SAMPLE_BUFFERS, 1, + GLX_SAMPLES, Params.AntiAlias, // 18,19 +#elif defined(GLX_ARB_multisample) + GLX_SAMPLE_BUFFERS_ARB, 1, + GLX_SAMPLES_ARB, Params.AntiAlias, // 18,19 +#elif defined(GLX_SGIS_multisample) + GLX_SAMPLE_BUFFERS_SGIS, 1, + GLX_SAMPLES_SGIS, Params.AntiAlias, // 18,19 +#endif +//#ifdef GL_ARB_framebuffer_sRGB +// GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, Params.HandleSRGB, +//#elif defined(GL_EXT_framebuffer_sRGB) +// GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, Params.HandleSRGB, +//#endif + GLX_STEREO, Params.Stereobuffer?True:False, + None + }; + + GLXFBConfig *configList=0; + int nitems=0; + if (Params.AntiAlias<2) + { + visualAttrBuffer[17] = 0; + visualAttrBuffer[19] = 0; + } + // first round with unchanged values + { + configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems); + if (!configList && Params.AntiAlias) + { + while (!configList && (visualAttrBuffer[19]>1)) + { + visualAttrBuffer[19] -= 1; + configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems); + } + if (!configList) + { + visualAttrBuffer[17] = 0; + visualAttrBuffer[19] = 0; + configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems); + if (configList) + { + os::Printer::log("No FSAA available.", ELL_WARNING); + Params.AntiAlias=0; + } + else + { + //reenable multisampling + visualAttrBuffer[17] = 1; + visualAttrBuffer[19] = Params.AntiAlias; + } + } + } + } + // 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 (Params.Stencilbuffer) + os::Printer::log("No stencilbuffer available, disabling stencil shadows.", ELL_WARNING); + Params.Stencilbuffer = !Params.Stencilbuffer; + visualAttrBuffer[15]=Params.Stencilbuffer?1:0; + + configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems); + if (!configList && Params.AntiAlias) + { + while (!configList && (visualAttrBuffer[19]>1)) + { + visualAttrBuffer[19] -= 1; + configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems); + } + if (!configList) + { + visualAttrBuffer[17] = 0; + visualAttrBuffer[19] = 0; + configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems); + if (configList) + { + os::Printer::log("No FSAA available.", ELL_WARNING); + Params.AntiAlias=0; + } + else + { + //reenable multisampling + visualAttrBuffer[17] = 1; + visualAttrBuffer[19] = Params.AntiAlias; + } + } + } + } + // Next try without double buffer + if (!configList && Params.Doublebuffer) + { + os::Printer::log("No doublebuffering available.", ELL_WARNING); + Params.Doublebuffer=false; + visualAttrBuffer[13] = GLX_DONT_CARE; + Params.Stencilbuffer = false; + visualAttrBuffer[15]=0; + configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems); + if (!configList && Params.AntiAlias) + { + while (!configList && (visualAttrBuffer[19]>1)) + { + visualAttrBuffer[19] -= 1; + configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems); + } + if (!configList) + { + visualAttrBuffer[17] = 0; + visualAttrBuffer[19] = 0; + configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems); + if (configList) + { + os::Printer::log("No FSAA available.", ELL_WARNING); + Params.AntiAlias=0; + } + else + { + //reenable multisampling + visualAttrBuffer[17] = 1; + visualAttrBuffer[19] = Params.AntiAlias; + } + } + } + } + if (configList) + { + glxFBConfig=configList[0]; + XFree(configList); +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + typedef XVisualInfo * ( * PFNGLXGETVISUALFROMFBCONFIGPROC) (Display *dpy, GLXFBConfig config); + PFNGLXGETVISUALFROMFBCONFIGPROC glxGetVisualFromFBConfig= (PFNGLXGETVISUALFROMFBCONFIGPROC)glXGetProcAddress(reinterpret_cast("glXGetVisualFromFBConfig")); + if (glxGetVisualFromFBConfig) + VisualInfo = glxGetVisualFromFBConfig(display,(GLXFBConfig)glxFBConfig); +#else + VisualInfo = glXGetVisualFromFBConfig(display,(GLXFBConfig)glxFBConfig); +#endif + } + } + else +#endif + { + // attribute array for the draw buffer + int visualAttrBuffer[] = + { + GLX_RGBA, GLX_USE_GL, + GLX_RED_SIZE, 4, + GLX_GREEN_SIZE, 4, + GLX_BLUE_SIZE, 4, + GLX_ALPHA_SIZE, Params.WithAlphaChannel?1:0, + GLX_DEPTH_SIZE, Params.ZBufferBits, + GLX_STENCIL_SIZE, Params.Stencilbuffer?1:0, // 12,13 + // The following attributes have no flags, but are + // either present or not. As a no-op we use + // GLX_USE_GL, which is silently ignored by glXChooseVisual + Params.Doublebuffer?GLX_DOUBLEBUFFER:GLX_USE_GL, // 14 + Params.Stereobuffer?GLX_STEREO:GLX_USE_GL, // 15 +//#ifdef GL_ARB_framebuffer_sRGB +// Params.HandleSRGB?GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB:GLX_USE_GL, +//#elif defined(GL_EXT_framebuffer_sRGB) +// Params.HandleSRGB?GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT:GLX_USE_GL, +//#endif + None + }; + + VisualInfo=glXChooseVisual(display, screennr, visualAttrBuffer); + if (!VisualInfo) + { + if (Params.Stencilbuffer) + os::Printer::log("No stencilbuffer available, disabling.", ELL_WARNING); + Params.Stencilbuffer = !Params.Stencilbuffer; + visualAttrBuffer[13]=Params.Stencilbuffer?1:0; + + VisualInfo=glXChooseVisual(display, screennr, visualAttrBuffer); + if (!VisualInfo && Params.Doublebuffer) + { + os::Printer::log("No doublebuffering available.", ELL_WARNING); + Params.Doublebuffer=false; + visualAttrBuffer[14] = GLX_USE_GL; + VisualInfo=glXChooseVisual(display, screennr, visualAttrBuffer); + } + } + } + } + else + os::Printer::log("No GLX support available. OpenGL driver will not work.", ELL_WARNING); +} + +CGLXManager::~CGLXManager() +{ +} + +bool CGLXManager::initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& videodata) +{ + // store params + Params=params; + + // set display + CurrentContext.OpenGLLinux.X11Display=videodata.OpenGLLinux.X11Display; + + // now get new window + CurrentContext.OpenGLLinux.X11Window=videodata.OpenGLLinux.X11Window; + if (!PrimaryContext.OpenGLLinux.X11Window) + { + PrimaryContext.OpenGLLinux.X11Window=CurrentContext.OpenGLLinux.X11Window; + } + + return true; +} + +void CGLXManager::terminate() +{ + memset(&CurrentContext, 0, sizeof(CurrentContext)); +} + +bool CGLXManager::generateSurface() +{ + if (glxFBConfig) + { + GlxWin=glXCreateWindow((Display*)CurrentContext.OpenGLLinux.X11Display,(GLXFBConfig)glxFBConfig,CurrentContext.OpenGLLinux.X11Window,NULL); + if (!GlxWin) + { + os::Printer::log("Could not create GLX window.", ELL_WARNING); + return false; + } + + CurrentContext.OpenGLLinux.X11Window=GlxWin; + } + return true; +} + +void CGLXManager::destroySurface() +{ + if (GlxWin) + glXDestroyWindow((Display*)CurrentContext.OpenGLLinux.X11Display, GlxWin); +} + +bool CGLXManager::generateContext() +{ + GLXContext context; + + if (glxFBConfig) + { + if (GlxWin) + { + // create glx context + context = glXCreateNewContext((Display*)CurrentContext.OpenGLLinux.X11Display, (GLXFBConfig)glxFBConfig, GLX_RGBA_TYPE, NULL, True); + if (!context) + { + os::Printer::log("Could not create GLX rendering context.", ELL_WARNING); + return false; + } + } + else + { + os::Printer::log("GLX window was not properly created.", ELL_WARNING); + return false; + } + } + else + { + context = glXCreateContext((Display*)CurrentContext.OpenGLLinux.X11Display, VisualInfo, NULL, True); + if (!context) + { + os::Printer::log("Could not create GLX rendering context.", ELL_WARNING); + return false; + } + } + CurrentContext.OpenGLLinux.X11Context=context; + return true; +} + +const SExposedVideoData& CGLXManager::getContext() const +{ + return CurrentContext; +} + +bool CGLXManager::activateContext(const SExposedVideoData& videoData, bool restorePrimaryOnZero) +{ + //TODO: handle restorePrimaryOnZero + + if (videoData.OpenGLLinux.X11Window) + { + if (videoData.OpenGLLinux.X11Display && videoData.OpenGLLinux.X11Context) + { + if (!glXMakeCurrent((Display*)videoData.OpenGLLinux.X11Display, videoData.OpenGLLinux.X11Window, (GLXContext)videoData.OpenGLLinux.X11Context)) + { + os::Printer::log("Context activation failed."); + return false; + } + else + { + CurrentContext.OpenGLLinux.X11Window = videoData.OpenGLLinux.X11Window; + CurrentContext.OpenGLLinux.X11Display = videoData.OpenGLLinux.X11Display; + } + } + else + { + // in case we only got a window ID, try with the existing values for display and context + if (!glXMakeCurrent((Display*)PrimaryContext.OpenGLLinux.X11Display, videoData.OpenGLLinux.X11Window, (GLXContext)PrimaryContext.OpenGLLinux.X11Context)) + { + os::Printer::log("Context activation failed."); + return false; + } + else + { + CurrentContext.OpenGLLinux.X11Window = videoData.OpenGLLinux.X11Window; + CurrentContext.OpenGLLinux.X11Display = PrimaryContext.OpenGLLinux.X11Display; + } + } + } + else if (!restorePrimaryOnZero && !videoData.OpenGLLinux.X11Window && !videoData.OpenGLLinux.X11Display) + { + if (!glXMakeCurrent((Display*)PrimaryContext.OpenGLLinux.X11Display, None, NULL)) + { + os::Printer::log("Render Context reset failed."); + return false; + } + CurrentContext.OpenGLLinux.X11Window = 0; + CurrentContext.OpenGLLinux.X11Display = 0; + } + // set back to main context + else if (CurrentContext.OpenGLLinux.X11Display != PrimaryContext.OpenGLLinux.X11Display) + { + if (!glXMakeCurrent((Display*)PrimaryContext.OpenGLLinux.X11Display, PrimaryContext.OpenGLLinux.X11Window, (GLXContext)PrimaryContext.OpenGLLinux.X11Context)) + { + os::Printer::log("Context activation failed."); + return false; + } + else + { + CurrentContext = PrimaryContext; + } + } + return true; +} + +void CGLXManager::destroyContext() +{ + if (CurrentContext.OpenGLLinux.X11Context) + { + if (GlxWin) + { + if (!glXMakeContextCurrent((Display*)CurrentContext.OpenGLLinux.X11Display, None, None, NULL)) + os::Printer::log("Could not release glx context.", ELL_WARNING); + } + else + { + if (!glXMakeCurrent((Display*)CurrentContext.OpenGLLinux.X11Display, None, NULL)) + os::Printer::log("Could not release glx context.", ELL_WARNING); + } + glXDestroyContext((Display*)CurrentContext.OpenGLLinux.X11Display, (GLXContext)CurrentContext.OpenGLLinux.X11Context); + } +} + +bool CGLXManager::swapBuffers() +{ + glXSwapBuffers((Display*)CurrentContext.OpenGLLinux.X11Display, CurrentContext.OpenGLLinux.X11Window); + return true; +} + +} +} + +#endif + diff --git a/source/Irrlicht/CGLXManager.h b/source/Irrlicht/CGLXManager.h new file mode 100644 index 00000000..ef2566ee --- /dev/null +++ b/source/Irrlicht/CGLXManager.h @@ -0,0 +1,79 @@ +// Copyright (C) 2013 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __C_GLX_MANAGER_H_INCLUDED__ +#define __C_GLX_MANAGER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_GLX_MANAGER_ + +#include "SIrrCreationParameters.h" +#include "SExposedVideoData.h" +#include "IContextManager.h" +#include "SColor.h" +#include +#include + +// we can't include glx.h here, because gl.h has incompatible types with ogl es headers and it +// cause redefinition errors, thats why we use ugly trick with void* types and casts. + +namespace irr +{ +namespace video +{ + // GLX manager. + class CGLXManager : public IContextManager + { + public: + //! Constructor. + CGLXManager(const SIrrlichtCreationParameters& params, const SExposedVideoData& videodata, int screennr); + + //! Destructor + ~CGLXManager(); + + // Initialize + virtual bool initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& data) _IRR_OVERRIDE_; + + // Terminate + virtual void terminate() _IRR_OVERRIDE_; + + // Create surface. + virtual bool generateSurface() _IRR_OVERRIDE_; + + // Destroy surface. + virtual void destroySurface() _IRR_OVERRIDE_; + + // Create context. + virtual bool generateContext() _IRR_OVERRIDE_; + + // Destroy context. + virtual void destroyContext() _IRR_OVERRIDE_; + + //! Get current context + virtual const SExposedVideoData& getContext() const _IRR_OVERRIDE_; + + //! Change render context, disable old and activate new defined by videoData + virtual bool activateContext(const SExposedVideoData& videoData, bool restorePrimaryOnZero) _IRR_OVERRIDE_; + + // Swap buffers. + virtual bool swapBuffers() _IRR_OVERRIDE_; + + XVisualInfo* getVisual() const {return VisualInfo;} // return XVisualInfo + + private: + SIrrlichtCreationParameters Params; + SExposedVideoData PrimaryContext; + SExposedVideoData CurrentContext; + XVisualInfo* VisualInfo; + void* glxFBConfig; // GLXFBConfig + XID GlxWin; // GLXWindow + }; +} +} + +#endif + +#endif + diff --git a/source/Irrlicht/CGUIButton.cpp b/source/Irrlicht/CGUIButton.cpp new file mode 100644 index 00000000..895e31a2 --- /dev/null +++ b/source/Irrlicht/CGUIButton.cpp @@ -0,0 +1,650 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUIButton.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" +#include "IGUIFont.h" +#include "os.h" + +namespace irr +{ +namespace gui +{ + +//! constructor +CGUIButton::CGUIButton(IGUIEnvironment* environment, IGUIElement* parent, + s32 id, core::rect rectangle, bool noclip) +: IGUIButton(environment, parent, id, rectangle), + SpriteBank(0), OverrideFont(0), + OverrideColorEnabled(false), OverrideColor(video::SColor(101,255,255,255)), + ClickTime(0), HoverTime(0), FocusTime(0), + ClickShiftState(false), ClickControlState(false), + IsPushButton(false), Pressed(false), + UseAlphaChannel(false), DrawBorder(true), ScaleImage(false) +{ + #ifdef _DEBUG + setDebugName("CGUIButton"); + #endif + setNotClipped(noclip); + + // This element can be tabbed. + setTabStop(true); + setTabOrder(-1); +} + + +//! destructor +CGUIButton::~CGUIButton() +{ + if (OverrideFont) + OverrideFont->drop(); + + if (SpriteBank) + SpriteBank->drop(); +} + + +//! Sets if the images should be scaled to fit the button +void CGUIButton::setScaleImage(bool scaleImage) +{ + ScaleImage = scaleImage; +} + + +//! Returns whether the button scale the used images +bool CGUIButton::isScalingImage() const +{ + return ScaleImage; +} + + +//! Sets if the button should use the skin to draw its border +void CGUIButton::setDrawBorder(bool border) +{ + DrawBorder = border; +} + + +void CGUIButton::setSpriteBank(IGUISpriteBank* sprites) +{ + if (sprites) + sprites->grab(); + + if (SpriteBank) + SpriteBank->drop(); + + SpriteBank = sprites; +} + + +void CGUIButton::setSprite(EGUI_BUTTON_STATE state, s32 index, video::SColor color, bool loop, bool scale) +{ + ButtonSprites[(u32)state].Index = index; + ButtonSprites[(u32)state].Color = color; + ButtonSprites[(u32)state].Loop = loop; + ButtonSprites[(u32)state].Scale = scale; +} + +//! Get the sprite-index for the given state or -1 when no sprite is set +s32 CGUIButton::getSpriteIndex(EGUI_BUTTON_STATE state) const +{ + return ButtonSprites[(u32)state].Index; +} + +//! Get the sprite color for the given state. Color is only used when a sprite is set. +video::SColor CGUIButton::getSpriteColor(EGUI_BUTTON_STATE state) const +{ + return ButtonSprites[(u32)state].Color; +} + +//! Returns if the sprite in the given state does loop +bool CGUIButton::getSpriteLoop(EGUI_BUTTON_STATE state) const +{ + return ButtonSprites[(u32)state].Loop; +} + +//! Returns if the sprite in the given state is scaled +bool CGUIButton::getSpriteScale(EGUI_BUTTON_STATE state) const +{ + return ButtonSprites[(u32)state].Scale; +} + +//! called if an event happened. +bool CGUIButton::OnEvent(const SEvent& event) +{ + if (!isEnabled()) + return IGUIElement::OnEvent(event); + + switch(event.EventType) + { + case EET_KEY_INPUT_EVENT: + if (event.KeyInput.PressedDown && + (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE)) + { + if (!IsPushButton) + setPressed(true); + else + setPressed(!Pressed); + + return true; + } + if (Pressed && !IsPushButton && event.KeyInput.PressedDown && event.KeyInput.Key == KEY_ESCAPE) + { + setPressed(false); + return true; + } + else + if (!event.KeyInput.PressedDown && Pressed && + (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE)) + { + + if (!IsPushButton) + setPressed(false); + + if (Parent) + { + ClickShiftState = event.KeyInput.Shift; + ClickControlState = event.KeyInput.Control; + + SEvent newEvent; + newEvent.EventType = EET_GUI_EVENT; + newEvent.GUIEvent.Caller = this; + newEvent.GUIEvent.Element = 0; + newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED; + Parent->OnEvent(newEvent); + } + return true; + } + break; + case EET_GUI_EVENT: + if (event.GUIEvent.Caller == this) + { + if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST) + { + if (!IsPushButton) + setPressed(false); + FocusTime = os::Timer::getTime(); + } + else if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED) + { + FocusTime = os::Timer::getTime(); + } + else if (event.GUIEvent.EventType == EGET_ELEMENT_HOVERED || event.GUIEvent.EventType == EGET_ELEMENT_LEFT) + { + HoverTime = os::Timer::getTime(); + } + } + break; + case EET_MOUSE_INPUT_EVENT: + if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) + { + if (!IsPushButton) + setPressed(true); + + return true; + } + else + if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) + { + bool wasPressed = Pressed; + + if ( !AbsoluteClippingRect.isPointInside( core::position2d(event.MouseInput.X, event.MouseInput.Y ) ) ) + { + if (!IsPushButton) + setPressed(false); + return true; + } + + if (!IsPushButton) + setPressed(false); + else + { + setPressed(!Pressed); + } + + if ((!IsPushButton && wasPressed && Parent) || + (IsPushButton && wasPressed != Pressed)) + { + ClickShiftState = event.MouseInput.Shift; + ClickControlState = event.MouseInput.Control; + + SEvent newEvent; + newEvent.EventType = EET_GUI_EVENT; + newEvent.GUIEvent.Caller = this; + newEvent.GUIEvent.Element = 0; + newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED; + Parent->OnEvent(newEvent); + } + + return true; + } + break; + default: + break; + } + + return Parent ? Parent->OnEvent(event) : false; +} + + +//! draws the element and its children +void CGUIButton::draw() +{ + if (!IsVisible) + return; + + IGUISkin* skin = Environment->getSkin(); + video::IVideoDriver* driver = Environment->getVideoDriver(); + + if (DrawBorder) + { + if (!Pressed) + { + skin->draw3DButtonPaneStandard(this, AbsoluteRect, &AbsoluteClippingRect); + } + else + { + skin->draw3DButtonPanePressed(this, AbsoluteRect, &AbsoluteClippingRect); + } + } + + + const core::position2di buttonCenter(AbsoluteRect.getCenter()); + + EGUI_BUTTON_IMAGE_STATE imageState = getImageState(Pressed); + if ( ButtonImages[(u32)imageState].Texture ) + { + core::position2d pos(buttonCenter); + core::rect sourceRect(ButtonImages[(u32)imageState].SourceRect); + if ( sourceRect.getWidth() == 0 && sourceRect.getHeight() == 0 ) + sourceRect = core::rect(core::position2di(0,0), ButtonImages[(u32)imageState].Texture->getOriginalSize()); + + pos.X -= sourceRect.getWidth() / 2; + pos.Y -= sourceRect.getHeight() / 2; + + if ( Pressed ) + { + // Create a pressed-down effect by moving the image when it looks identical to the unpressed state image + EGUI_BUTTON_IMAGE_STATE unpressedState = getImageState(false); + if ( unpressedState == imageState || ButtonImages[(u32)imageState] == ButtonImages[(u32)unpressedState] ) + { + pos.X += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X); + pos.Y += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y); + } + } + + driver->draw2DImage(ButtonImages[(u32)imageState].Texture, + ScaleImage? AbsoluteRect : core::rect(pos, sourceRect.getSize()), + sourceRect, &AbsoluteClippingRect, + 0, UseAlphaChannel); + } + + if (SpriteBank) + { + core::position2di pos(buttonCenter); + if ( Pressed ) + { + pos.X += skin->getSize(EGDS_BUTTON_PRESSED_SPRITE_OFFSET_X); + pos.Y += skin->getSize(EGDS_BUTTON_PRESSED_SPRITE_OFFSET_Y); + } + + if (isEnabled()) + { + // pressed / unpressed animation + EGUI_BUTTON_STATE state = Pressed ? EGBS_BUTTON_DOWN : EGBS_BUTTON_UP; + drawSprite(state, ClickTime, pos); + + // focused / unfocused animation + state = Environment->hasFocus(this) ? EGBS_BUTTON_FOCUSED : EGBS_BUTTON_NOT_FOCUSED; + drawSprite(state, FocusTime, pos); + + // mouse over / off animation + state = Environment->getHovered() == this ? EGBS_BUTTON_MOUSE_OVER : EGBS_BUTTON_MOUSE_OFF; + drawSprite(state, HoverTime, pos); + } + else + { + // draw disabled + drawSprite(EGBS_BUTTON_DISABLED, 0, pos); + } + } + + if (Text.size()) + { + IGUIFont* font = getActiveFont(); + + core::rect rect = AbsoluteRect; + if (Pressed) + { + rect.UpperLeftCorner.X += skin->getSize(EGDS_BUTTON_PRESSED_TEXT_OFFSET_X); + rect.UpperLeftCorner.Y += skin->getSize(EGDS_BUTTON_PRESSED_TEXT_OFFSET_Y); + } + + if (font) + font->draw(Text.c_str(), rect, + OverrideColorEnabled ? OverrideColor : skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT), + true, true, &AbsoluteClippingRect); + } + + IGUIElement::draw(); +} + +void CGUIButton::drawSprite(EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center) +{ + u32 stateIdx = (u32)state; + + if (ButtonSprites[stateIdx].Index != -1) + { + if ( ButtonSprites[stateIdx].Scale ) + { + const video::SColor colors[] = {ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color}; + SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, AbsoluteRect, + &AbsoluteClippingRect, colors, + os::Timer::getTime()-startTime, ButtonSprites[stateIdx].Loop); + } + else + { + SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, center, + &AbsoluteClippingRect, ButtonSprites[stateIdx].Color, startTime, os::Timer::getTime(), + ButtonSprites[stateIdx].Loop, true); + } + } +} + +EGUI_BUTTON_IMAGE_STATE CGUIButton::getImageState(bool pressed) const +{ + // figure state we should have + EGUI_BUTTON_IMAGE_STATE state = EGBIS_IMAGE_DISABLED; + bool focused = Environment->hasFocus(this); + bool mouseOver = static_cast(Environment->getHovered()) == this; // (static cast for Borland) + if (isEnabled()) + { + if ( pressed ) + { + if ( focused && mouseOver ) + state = EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER; + else if ( focused ) + state = EGBIS_IMAGE_DOWN_FOCUSED; + else if ( mouseOver ) + state = EGBIS_IMAGE_DOWN_MOUSEOVER; + else + state = EGBIS_IMAGE_DOWN; + } + else // !pressed + { + if ( focused && mouseOver ) + state = EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER; + else if ( focused ) + state = EGBIS_IMAGE_UP_FOCUSED; + else if ( mouseOver ) + state = EGBIS_IMAGE_UP_MOUSEOVER; + else + state = EGBIS_IMAGE_UP; + } + } + + // find a compatible state that has images + while ( state != EGBIS_IMAGE_UP && !ButtonImages[(u32)state].Texture ) + { + switch ( state ) + { + case EGBIS_IMAGE_UP_FOCUSED: + state = EGBIS_IMAGE_UP_MOUSEOVER; + break; + case EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER: + state = EGBIS_IMAGE_UP_FOCUSED; + break; + case EGBIS_IMAGE_DOWN_MOUSEOVER: + state = EGBIS_IMAGE_DOWN; + break; + case EGBIS_IMAGE_DOWN_FOCUSED: + state = EGBIS_IMAGE_DOWN_MOUSEOVER; + break; + case EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER: + state = EGBIS_IMAGE_DOWN_FOCUSED; + break; + case EGBIS_IMAGE_DISABLED: + if ( pressed ) + state = EGBIS_IMAGE_DOWN; + else + state = EGBIS_IMAGE_UP; + break; + default: + state = EGBIS_IMAGE_UP; + } + } + + return state; +} + +//! 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(); + + OverrideFont = font; + + if (OverrideFont) + OverrideFont->grab(); +} + +//! Gets the override font (if any) +IGUIFont * CGUIButton::getOverrideFont() const +{ + return OverrideFont; +} + +//! Get the font which is used right now for drawing +IGUIFont* CGUIButton::getActiveFont() const +{ + if ( OverrideFont ) + return OverrideFont; + IGUISkin* skin = Environment->getSkin(); + if (skin) + return skin->getFont(EGDF_BUTTON); + return 0; +} + +//! Sets another color for the text. +void CGUIButton::setOverrideColor(video::SColor color) +{ + OverrideColor = color; + OverrideColorEnabled = true; +} + +video::SColor CGUIButton::getOverrideColor() const +{ + return OverrideColor; +} + +void CGUIButton::enableOverrideColor(bool enable) +{ + OverrideColorEnabled = enable; +} + +bool CGUIButton::isOverrideColorEnabled() const +{ + return OverrideColorEnabled; +} + +void CGUIButton::setImage(EGUI_BUTTON_IMAGE_STATE state, video::ITexture* image, const core::rect& sourceRect) +{ + if ( state >= EGBIS_COUNT ) + return; + + if ( image ) + image->grab(); + + u32 stateIdx = (u32)state; + if ( ButtonImages[stateIdx].Texture ) + ButtonImages[stateIdx].Texture->drop(); + + ButtonImages[stateIdx].Texture = image; + ButtonImages[stateIdx].SourceRect = sourceRect; +} + +//! Sets if the button should behave like a push button. Which means it +//! can be in two states: Normal or Pressed. With a click on the button, +//! the user can change the state of the button. +void CGUIButton::setIsPushButton(bool isPushButton) +{ + IsPushButton = isPushButton; +} + + +//! Returns if the button is currently pressed +bool CGUIButton::isPressed() const +{ + return Pressed; +} + + +//! Sets the pressed state of the button if this is a pushbutton +void CGUIButton::setPressed(bool pressed) +{ + if (Pressed != pressed) + { + ClickTime = os::Timer::getTime(); + Pressed = pressed; + } +} + + +//! Returns whether the button is a push button +bool CGUIButton::isPushButton() const +{ + return IsPushButton; +} + + +//! Sets if the alpha channel should be used for drawing images on the button (default is false) +void CGUIButton::setUseAlphaChannel(bool useAlphaChannel) +{ + UseAlphaChannel = useAlphaChannel; +} + + +//! Returns if the alpha channel should be used for drawing images on the button +bool CGUIButton::isAlphaChannelUsed() const +{ + return UseAlphaChannel; +} + + +bool CGUIButton::isDrawingBorder() const +{ + return DrawBorder; +} + + +//! Writes attributes of the element. +void CGUIButton::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const +{ + IGUIButton::serializeAttributes(out,options); + + out->addBool ("PushButton", IsPushButton ); + if (IsPushButton) + out->addBool("Pressed", Pressed); + + for ( u32 i=0; i<(u32)EGBIS_COUNT; ++i ) + { + if ( ButtonImages[i].Texture ) + { + core::stringc name( GUIButtonImageStateNames[i] ); + out->addTexture(name.c_str(), ButtonImages[i].Texture); + name += "Rect"; + out->addRect(name.c_str(), ButtonImages[i].SourceRect); + } + } + + out->addBool ("UseAlphaChannel", UseAlphaChannel); + out->addBool ("Border", DrawBorder); + out->addBool ("ScaleImage", ScaleImage); + + for ( u32 i=0; i<(u32)EGBS_COUNT; ++i ) + { + if ( ButtonSprites[i].Index >= 0 ) + { + core::stringc nameIndex( GUIButtonStateNames[i] ); + nameIndex += "Index"; + out->addInt(nameIndex.c_str(), ButtonSprites[i].Index ); + + core::stringc nameColor( GUIButtonStateNames[i] ); + nameColor += "Color"; + out->addColor(nameColor.c_str(), ButtonSprites[i].Color ); + + core::stringc nameLoop( GUIButtonStateNames[i] ); + nameLoop += "Loop"; + out->addBool(nameLoop.c_str(), ButtonSprites[i].Loop ); + + core::stringc nameScale( GUIButtonStateNames[i] ); + nameScale += "Scale"; + out->addBool(nameScale.c_str(), ButtonSprites[i].Scale ); + } + } + + // out->addString ("OverrideFont", OverrideFont); +} + + +//! Reads attributes of the element +void CGUIButton::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) +{ + IGUIButton::deserializeAttributes(in,options); + + IsPushButton = in->getAttributeAsBool("PushButton", IsPushButton); + Pressed = IsPushButton ? in->getAttributeAsBool("Pressed", Pressed) : false; + + for ( u32 i=0; i<(u32)EGBIS_COUNT; ++i ) + { + core::stringc nameRect( GUIButtonImageStateNames[i] ); + nameRect += "Rect"; + + setImage((EGUI_BUTTON_IMAGE_STATE)i, + in->getAttributeAsTexture(GUIButtonImageStateNames[i], ButtonImages[i].Texture), + in->getAttributeAsRect(nameRect.c_str(), ButtonImages[i].SourceRect) ); + } + + setDrawBorder(in->getAttributeAsBool("Border", DrawBorder)); + setUseAlphaChannel(in->getAttributeAsBool("UseAlphaChannel", UseAlphaChannel)); + setScaleImage(in->getAttributeAsBool("ScaleImage", ScaleImage)); + + for ( u32 i=0; i<(u32)EGBS_COUNT; ++i ) + { + core::stringc nameIndex( GUIButtonStateNames[i] ); + nameIndex += "Index"; + ButtonSprites[i].Index = in->getAttributeAsInt(nameIndex.c_str(), ButtonSprites[i].Index ); + + core::stringc nameColor( GUIButtonStateNames[i] ); + nameColor += "Color"; + ButtonSprites[i].Color = in->getAttributeAsColor(nameColor.c_str(), ButtonSprites[i].Color ); + + core::stringc nameLoop( GUIButtonStateNames[i] ); + nameLoop += "Loop"; + ButtonSprites[i].Loop = in->getAttributeAsBool(nameLoop.c_str(), ButtonSprites[i].Loop ); + + core::stringc nameScale( GUIButtonStateNames[i] ); + nameScale += "Scale"; + ButtonSprites[i].Scale = in->getAttributeAsBool(nameScale.c_str(), ButtonSprites[i].Scale ); + } + + // setOverrideFont(in->getAttributeAsString("OverrideFont")); + + updateAbsolutePosition(); +} + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIButton.h b/source/Irrlicht/CGUIButton.h new file mode 100644 index 00000000..ab383db7 --- /dev/null +++ b/source/Irrlicht/CGUIButton.h @@ -0,0 +1,253 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_BUTTON_H_INCLUDED__ +#define __C_GUI_BUTTON_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIButton.h" +#include "IGUISpriteBank.h" +#include "ITexture.h" +#include "SColor.h" + +namespace irr +{ +namespace gui +{ + + class CGUIButton : public IGUIButton + { + public: + + //! constructor + CGUIButton(IGUIEnvironment* environment, IGUIElement* parent, + s32 id, core::rect rectangle, bool noclip=false); + + //! destructor + virtual ~CGUIButton(); + + //! called if an event happened. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! Gets the override font (if any) + virtual IGUIFont* getOverrideFont() const _IRR_OVERRIDE_; + + //! Get the font which is used right now for drawing + virtual IGUIFont* getActiveFont() const _IRR_OVERRIDE_; + + //! Sets another color for the button text. + virtual void setOverrideColor(video::SColor color) _IRR_OVERRIDE_; + + //! Gets the override color + virtual video::SColor getOverrideColor(void) const _IRR_OVERRIDE_; + + //! Sets if the button text should use the override color or the color in the gui skin. + virtual void enableOverrideColor(bool enable) _IRR_OVERRIDE_; + + //! Checks if an override color is enabled + virtual bool isOverrideColorEnabled(void) const _IRR_OVERRIDE_; + + //! Sets an image which should be displayed on the button when it is in the given state. + virtual void setImage(EGUI_BUTTON_IMAGE_STATE state, video::ITexture* image=0, const core::rect& sourceRect=core::rect(0,0,0,0)) _IRR_OVERRIDE_; + + //! Sets an image which should be displayed on the button when it is in normal state. + virtual void setImage(video::ITexture* image=0) _IRR_OVERRIDE_ + { + setImage(EGBIS_IMAGE_UP, image); + } + + //! 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) _IRR_OVERRIDE_ + { + setImage(EGBIS_IMAGE_UP, image, pos); + } + + //! Sets an image which should be displayed on the button when it is in pressed state. + virtual void setPressedImage(video::ITexture* image=0) _IRR_OVERRIDE_ + { + setImage(EGBIS_IMAGE_DOWN, image); + } + + //! 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) _IRR_OVERRIDE_ + { + setImage(EGBIS_IMAGE_DOWN, image, pos); + } + + //! Sets the sprite bank used by the button + virtual void setSpriteBank(IGUISpriteBank* bank=0) _IRR_OVERRIDE_; + + //! Sets the animated sprite for a specific button state + /** \param index: Number of the sprite within the sprite bank, use -1 for no sprite + \param state: State of the button to set the sprite for + \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, + video::SColor color=video::SColor(255,255,255,255), + bool loop=false, bool scale=false) _IRR_OVERRIDE_; + + //! Get the sprite-index for the given state or -1 when no sprite is set + virtual s32 getSpriteIndex(EGUI_BUTTON_STATE state) const _IRR_OVERRIDE_; + + //! Get the sprite color for the given state. Color is only used when a sprite is set. + virtual video::SColor getSpriteColor(EGUI_BUTTON_STATE state) const _IRR_OVERRIDE_; + + //! Returns if the sprite in the given state does loop + virtual bool getSpriteLoop(EGUI_BUTTON_STATE state) const _IRR_OVERRIDE_; + + //! Returns if the sprite in the given state is scaled + virtual bool getSpriteScale(EGUI_BUTTON_STATE state) const _IRR_OVERRIDE_; + + //! Sets if the button should behave like a push button. Which means it + //! can be in two states: Normal or Pressed. With a click on the button, + //! the user can change the state of the button. + virtual void setIsPushButton(bool isPushButton=true) _IRR_OVERRIDE_; + + //! Checks whether the button is a push button + virtual bool isPushButton() const _IRR_OVERRIDE_; + + //! Sets the pressed state of the button if this is a pushbutton + virtual void setPressed(bool pressed=true) _IRR_OVERRIDE_; + + //! Returns if the button is currently pressed + virtual bool isPressed() const _IRR_OVERRIDE_; + + //! Sets if the button should use the skin to draw its border + virtual void setDrawBorder(bool border=true) _IRR_OVERRIDE_; + + //! Checks if the button face and border are being drawn + virtual bool isDrawingBorder() const _IRR_OVERRIDE_; + + //! Sets if the alpha channel should be used for drawing images on the button (default is false) + virtual void setUseAlphaChannel(bool useAlphaChannel=true) _IRR_OVERRIDE_; + + //! Checks if the alpha channel should be used for drawing images on the button + virtual bool isAlphaChannelUsed() const _IRR_OVERRIDE_; + + //! Sets if the button should scale the button images to fit + virtual void setScaleImage(bool scaleImage=true) _IRR_OVERRIDE_; + + //! Checks whether the button scales the used images + virtual bool isScalingImage() const _IRR_OVERRIDE_; + + //! Get if the shift key was pressed in last EGET_BUTTON_CLICKED event + virtual bool getClickShiftState() const _IRR_OVERRIDE_ + { + return ClickShiftState; + } + + //! Get if the control key was pressed in last EGET_BUTTON_CLICKED event + virtual bool getClickControlState() const _IRR_OVERRIDE_ + { + return ClickControlState; + } + + //! Writes attributes of the element. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the element + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + + protected: + void drawSprite(EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center); + EGUI_BUTTON_IMAGE_STATE getImageState(bool pressed) const; + + private: + + struct ButtonSprite + { + ButtonSprite() : Index(-1), Loop(false), Scale(false) + { + } + + bool operator==(const ButtonSprite& other) const + { + return Index == other.Index && Color == other.Color && Loop == other.Loop && Scale == other.Scale; + } + + s32 Index; + video::SColor Color; + bool Loop; + bool Scale; + }; + + ButtonSprite ButtonSprites[EGBS_COUNT]; + IGUISpriteBank* SpriteBank; + + struct ButtonImage + { + ButtonImage() : Texture(0), SourceRect(core::rect(0,0,0,0)) + { + } + + ButtonImage(const ButtonImage& other) : Texture(0), SourceRect(core::rect(0,0,0,0)) + { + *this = other; + } + + ~ButtonImage() + { + if ( Texture ) + Texture->drop(); + } + + ButtonImage& operator=(const ButtonImage& other) + { + if ( this == &other ) + return *this; + + if (other.Texture) + other.Texture->grab(); + if ( Texture ) + Texture->drop(); + Texture = other.Texture; + SourceRect = other.SourceRect; + return *this; + } + + bool operator==(const ButtonImage& other) const + { + return Texture == other.Texture && SourceRect == other.SourceRect; + } + + + video::ITexture* Texture; + core::rect SourceRect; + }; + + ButtonImage ButtonImages[EGBIS_COUNT]; + + IGUIFont* OverrideFont; + + bool OverrideColorEnabled; + video::SColor OverrideColor; + + u32 ClickTime, HoverTime, FocusTime; + + bool ClickShiftState; + bool ClickControlState; + + bool IsPushButton; + bool Pressed; + bool UseAlphaChannel; + bool DrawBorder; + bool ScaleImage; + }; + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif // __C_GUI_BUTTON_H_INCLUDED__ + diff --git a/source/Irrlicht/CGUICheckBox.cpp b/source/Irrlicht/CGUICheckBox.cpp new file mode 100644 index 00000000..9fc6dc79 --- /dev/null +++ b/source/Irrlicht/CGUICheckBox.cpp @@ -0,0 +1,254 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUICheckBox.h" + +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" +#include "IGUIFont.h" +#include "os.h" + +namespace irr +{ +namespace gui +{ + +//! constructor +CGUICheckBox::CGUICheckBox(bool checked, IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) +: IGUICheckBox(environment, parent, id, rectangle), CheckTime(0), Pressed(false), Checked(checked) +, Border(false), Background(false) +{ + #ifdef _DEBUG + setDebugName("CGUICheckBox"); + #endif + + // this element can be tabbed into + setTabStop(true); + setTabOrder(-1); +} + + +//! called if an event happened. +bool CGUICheckBox::OnEvent(const SEvent& event) +{ + if (isEnabled()) + { + switch(event.EventType) + { + case EET_KEY_INPUT_EVENT: + if (event.KeyInput.PressedDown && + (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE)) + { + Pressed = true; + return true; + } + else + if (Pressed && event.KeyInput.PressedDown && event.KeyInput.Key == KEY_ESCAPE) + { + Pressed = false; + return true; + } + else + if (!event.KeyInput.PressedDown && Pressed && + (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE)) + { + Pressed = false; + if (Parent) + { + SEvent newEvent; + newEvent.EventType = EET_GUI_EVENT; + newEvent.GUIEvent.Caller = this; + newEvent.GUIEvent.Element = 0; + Checked = !Checked; + newEvent.GUIEvent.EventType = EGET_CHECKBOX_CHANGED; + Parent->OnEvent(newEvent); + } + return true; + } + break; + case EET_GUI_EVENT: + if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST) + { + if (event.GUIEvent.Caller == this) + Pressed = false; + } + break; + case EET_MOUSE_INPUT_EVENT: + if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) + { + Pressed = true; + CheckTime = os::Timer::getTime(); + return true; + } + else + if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) + { + bool wasPressed = Pressed; + Pressed = false; + + if (wasPressed && Parent) + { + if ( !AbsoluteClippingRect.isPointInside( core::position2d(event.MouseInput.X, event.MouseInput.Y) ) ) + { + Pressed = false; + return true; + } + + SEvent newEvent; + newEvent.EventType = EET_GUI_EVENT; + newEvent.GUIEvent.Caller = this; + newEvent.GUIEvent.Element = 0; + Checked = !Checked; + newEvent.GUIEvent.EventType = EGET_CHECKBOX_CHANGED; + Parent->OnEvent(newEvent); + } + + return true; + } + break; + default: + break; + } + } + + return IGUIElement::OnEvent(event); +} + + +//! draws the element and its children +void CGUICheckBox::draw() +{ + if (!IsVisible) + return; + + IGUISkin* skin = Environment->getSkin(); + if (skin) + { + video::IVideoDriver* driver = Environment->getVideoDriver(); + core::rect frameRect(AbsoluteRect); + + // draw background + if (Background) + { + video::SColor bgColor = skin->getColor(gui::EGDC_3D_FACE); + driver->draw2DRectangle(bgColor, frameRect, &AbsoluteClippingRect); + } + + // draw the border + if (Border) + { + skin->draw3DSunkenPane(this, 0, true, false, frameRect, &AbsoluteClippingRect); + frameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X); + frameRect.LowerRightCorner.X -= skin->getSize(EGDS_TEXT_DISTANCE_X); + } + + const s32 height = skin->getSize(EGDS_CHECK_BOX_WIDTH); + + // the rectangle around the "checked" area. + core::rect checkRect(frameRect.UpperLeftCorner.X, + ((frameRect.getHeight() - height) / 2) + frameRect.UpperLeftCorner.Y, + 0, 0); + + checkRect.LowerRightCorner.X = checkRect.UpperLeftCorner.X + height; + checkRect.LowerRightCorner.Y = checkRect.UpperLeftCorner.Y + height; + + EGUI_DEFAULT_COLOR col = EGDC_GRAY_EDITABLE; + if ( isEnabled() ) + col = Pressed ? EGDC_FOCUSED_EDITABLE : EGDC_EDITABLE; + skin->draw3DSunkenPane(this, skin->getColor(col), + false, true, checkRect, &AbsoluteClippingRect); + + // the checked icon + if (Checked) + { + skin->drawIcon(this, EGDI_CHECK_BOX_CHECKED, checkRect.getCenter(), + CheckTime, os::Timer::getTime(), false, &AbsoluteClippingRect); + } + + // associated text + if (Text.size()) + { + checkRect = frameRect; + checkRect.UpperLeftCorner.X += height + 5; + + IGUIFont* font = skin->getFont(); + if (font) + { + font->draw(Text.c_str(), checkRect, + skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT), false, true, &AbsoluteClippingRect); + } + } + } + IGUIElement::draw(); +} + + +//! set if box is checked +void CGUICheckBox::setChecked(bool checked) +{ + Checked = checked; +} + + +//! returns if box is checked +bool CGUICheckBox::isChecked() const +{ + return Checked; +} + +//! Sets whether to draw the background +void CGUICheckBox::setDrawBackground(bool draw) +{ + Background = draw; +} + +//! Checks if background drawing is enabled +bool CGUICheckBox::isDrawBackgroundEnabled() const +{ + return Background; +} + +//! Sets whether to draw the border +void CGUICheckBox::setDrawBorder(bool draw) +{ + Border = draw; +} + +//! Checks if border drawing is enabled +bool CGUICheckBox::isDrawBorderEnabled() const +{ + return Border; +} + + +//! 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("Border", Border); + out->addBool("Background", Background); +} + + +//! Reads attributes of the element +void CGUICheckBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) +{ + Checked = in->getAttributeAsBool ("Checked"); + Border = in->getAttributeAsBool ("Border", Border); + Background = in->getAttributeAsBool ("Background", Background); + + IGUICheckBox::deserializeAttributes(in,options); +} + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUICheckBox.h b/source/Irrlicht/CGUICheckBox.h new file mode 100644 index 00000000..47260a92 --- /dev/null +++ b/source/Irrlicht/CGUICheckBox.h @@ -0,0 +1,71 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_CHECKBOX_H_INCLUDED__ +#define __C_GUI_CHECKBOX_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUICheckBox.h" + +namespace irr +{ +namespace gui +{ + + class CGUICheckBox : public IGUICheckBox + { + public: + + //! constructor + CGUICheckBox(bool checked, IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle); + + //! set if box is checked + virtual void setChecked(bool checked) _IRR_OVERRIDE_; + + //! returns if box is checked + virtual bool isChecked() const _IRR_OVERRIDE_; + + //! Sets whether to draw the background + virtual void setDrawBackground(bool draw) _IRR_OVERRIDE_; + + //! Checks if background drawing is enabled + /** \return true if background drawing is enabled, false otherwise */ + virtual bool isDrawBackgroundEnabled() const _IRR_OVERRIDE_; + + //! Sets whether to draw the border + virtual void setDrawBorder(bool draw) _IRR_OVERRIDE_; + + //! Checks if border drawing is enabled + /** \return true if border drawing is enabled, false otherwise */ + virtual bool isDrawBorderEnabled() const _IRR_OVERRIDE_; + + //! called if an event happened. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + //! Writes attributes of the element. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the element + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + + private: + + u32 CheckTime; + bool Pressed; + bool Checked; + bool Border; + bool Background; + }; + +} // end namespace gui +} // end namespace irr + +#endif // __C_GUI_CHECKBOX_H_INCLUDED__ + +#endif // _IRR_COMPILE_WITH_GUI_ diff --git a/source/Irrlicht/CGUIColorSelectDialog.cpp b/source/Irrlicht/CGUIColorSelectDialog.cpp new file mode 100644 index 00000000..29c5482d --- /dev/null +++ b/source/Irrlicht/CGUIColorSelectDialog.cpp @@ -0,0 +1,479 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUIColorSelectDialog.h" + +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" +#include "IGUIButton.h" +#include "IGUIStaticText.h" +#include "IGUIFont.h" +#include "IGUISpriteBank.h" +#include "IFileList.h" +#include "os.h" +#include "fast_atof.h" + +namespace irr +{ +namespace gui +{ + +const s32 CSD_WIDTH = 350; +const s32 CSD_HEIGHT = 300; + +namespace +{ + +struct subElementPredefines +{ + const wchar_t *pre; + const wchar_t *init; + const wchar_t *post; + int x, y; + int range_down ,range_up; +}; + +static const subElementPredefines Template [] = +{ + { L"A:", L"0", 0,50,165, 0, 255 }, + { L"R:", L"0", 0,20,205, 0, 255 }, + { L"G:", L"0", 0,20,230, 0, 255 }, + { L"B:", L"0", 0,20,255, 0, 255 }, + { L"H:", L"0", L"°",80,205, 0, 360 }, + { L"S:", L"0", L"%",80,230, 0, 100 }, + { L"L:", L"0", L"%",80,255, 0, 100 }, +}; + +} + +//! constructor +CGUIColorSelectDialog::CGUIColorSelectDialog(const wchar_t* title, IGUIEnvironment* environment, IGUIElement* parent, s32 id) + : IGUIColorSelectDialog(environment, parent, id, + core::rect((parent->getAbsolutePosition().getWidth()-CSD_WIDTH)/2, + (parent->getAbsolutePosition().getHeight()-CSD_HEIGHT)/2, + (parent->getAbsolutePosition().getWidth()-CSD_WIDTH)/2+CSD_WIDTH, + (parent->getAbsolutePosition().getHeight()-CSD_HEIGHT)/2+CSD_HEIGHT)), + Dragging(false) +{ + #ifdef _DEBUG + IGUIElement::setDebugName("CGUIColorSelectDialog"); + #endif + + Text = title; + + IGUISkin* skin = Environment->getSkin(); + + 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"); + if (skin && skin->getSpriteBank()) + { + CloseButton->setSpriteBank(skin->getSpriteBank()); + CloseButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_CLOSE), skin->getColor(EGDC_WINDOW_SYMBOL)); + CloseButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_CLOSE), skin->getColor(EGDC_WINDOW_SYMBOL)); + } + CloseButton->setSubElement(true); + CloseButton->setTabStop(false); + CloseButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + CloseButton->grab(); + + OKButton = Environment->addButton( + core::rect(RelativeRect.getWidth()-80, 30, RelativeRect.getWidth()-10, 50), + this, -1, skin ? skin->getDefaultText(EGDT_MSG_BOX_OK) : L"OK"); + OKButton->setSubElement(true); + OKButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + OKButton->grab(); + + CancelButton = Environment->addButton( + core::rect(RelativeRect.getWidth()-80, 55, RelativeRect.getWidth()-10, 75), + this, -1, skin ? skin->getDefaultText(EGDT_MSG_BOX_CANCEL) : L"Cancel"); + CancelButton->setSubElement(true); + CancelButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + CancelButton->grab(); + + video::IVideoDriver* driver = Environment->getVideoDriver(); + ColorRing.Texture = driver->getTexture ( "#colorring" ); + if ( 0 == ColorRing.Texture ) + { + buildColorRing(core::dimension2d(128, 128), 1, + Environment->getSkin()->getColor(EGDC_3D_SHADOW)); + } + + core::rect r(20,20, 0,0); + + ColorRing.Control = Environment->addImage(ColorRing.Texture, r.UpperLeftCorner, true, this); + ColorRing.Control->setSubElement(true); + ColorRing.Control->grab(); + + for ( u32 i = 0; i != sizeof (Template) / sizeof ( subElementPredefines ); ++i ) + { + if ( Template[i].pre ) + { + r.UpperLeftCorner.X = Template[i].x; + r.UpperLeftCorner.Y = Template[i].y; + r.LowerRightCorner.X = r.UpperLeftCorner.X + 15; + r.LowerRightCorner.Y = r.UpperLeftCorner.Y + 20; + IGUIElement *t = Environment->addStaticText(Template[i].pre, r, false, false, this); + t->setSubElement(true); + } + + if ( Template[i].post ) + { + r.UpperLeftCorner.X = Template[i].x + 56; + r.UpperLeftCorner.Y = Template[i].y; + r.LowerRightCorner.X = r.UpperLeftCorner.X + 15; + r.LowerRightCorner.Y = r.UpperLeftCorner.Y + 20; + IGUIElement *t = Environment->addStaticText( Template[i].post, r, false, false, this); + t->setSubElement(true); + } + + r.UpperLeftCorner.X = Template[i].x + 15; + r.UpperLeftCorner.Y = Template[i].y-2; + r.LowerRightCorner.X = r.UpperLeftCorner.X + 40; + r.LowerRightCorner.Y = r.UpperLeftCorner.Y + 20; + + gui::IGUISpinBox* spin = Environment->addSpinBox( Template[i].init, r, true, this); + spin->setSubElement(true); + spin->setDecimalPlaces(0); + spin->setRange((f32)Template[i].range_down, (f32)Template[i].range_up); + spin->grab(); + + Battery.push_back(spin); + } + + bringToFront(CancelButton); + bringToFront(OKButton); +} + + +//! destructor +CGUIColorSelectDialog::~CGUIColorSelectDialog() +{ + if (CloseButton) + CloseButton->drop(); + + if (OKButton) + OKButton->drop(); + + if (CancelButton) + CancelButton->drop(); + + for (u32 i = 0; i != Battery.size(); ++i) + Battery[i]->drop(); + + if (ColorRing.Control) + ColorRing.Control->drop(); +} + + +//! renders a antialiased, colored ring +void CGUIColorSelectDialog::buildColorRing( const core::dimension2d & dim, s32 supersample, const video::SColor& borderColor ) +{ + const core::dimension2d d(dim.Width * supersample, dim.Height * supersample); + video::IVideoDriver* driver = Environment->getVideoDriver(); + + video::IImage *RawTexture = driver->createImage(video::ECF_A8R8G8B8, d); + + RawTexture->fill ( 0x00808080 ); + + const s32 radiusOut = ( d.Width / 2 ) - 4; + const s32 fullR2 = radiusOut * radiusOut; + + video::SColorf rgb(0,0,0); + video::SColorHSL hsl; + hsl.Luminance = 50; + hsl.Saturation = 100; + + core::position2d p; + for ( p.Y = -radiusOut; p.Y <= radiusOut; p.Y += 1 ) + { + s32 y2 = p.Y * p.Y; + + for (p.X = -radiusOut; p.X <= radiusOut; p.X += 1) + { + s32 r2 = y2 + ( p.X * p.X ); + + // test point in circle + s32 testa = r2 - fullR2; + + if ( testa < 0 ) + { + // dotproduct u ( x,y ) * v ( 1, 0 ) = cosinus(a) + + const f32 r = sqrtf((f32) r2); + + // normalize, dotproduct = xnorm + const f32 xn = r == 0.f ? 0.f : -p.X * core::reciprocal(r); + + hsl.Hue = acosf(xn)*core::RADTODEG; + if ( p.Y > 0 ) + hsl.Hue = 360 - hsl.Hue; + hsl.Hue -= 90; + + const f32 rTest = r / radiusOut; +#if 0 + if (rTest < 0.33f) + { + // luminance from 0 to 50 + hsl.Luminance = 50*(rTest/0.33); + hsl.Saturation = 0.f; + hsl.toRGB(rgb); + } + else + if ( rTest < 0.66f ) + { + // saturation from 0 to 100 + hsl.Saturation = 100*(( rTest - 0.33f ) / 0.33f); + hsl.Luminance = 50; + hsl.toRGB(rgb); + } + else + { + // luminance from 50 to 100 + hsl.Luminance = 100*(0.5f + ( ( rTest - 0.66f ) / .66f )); + hsl.Saturation = 100; + hsl.toRGB(rgb); + } + // borders should be slightly transparent + if ( rTest >= 0.95f ) + rgb.a = (1.f-rTest)*20; + else + rgb.a=1.f; +#else + if ( rTest > 0.5f ) + { + hsl.Saturation = 100; + hsl.Luminance = 50; + hsl.toRGB(rgb); + } + // borders should be slightly transparent + if ( rTest < 0.5f ) + rgb.a = 0; + else if ( rTest >= 0.95f ) + rgb.a = (1.f-rTest)*20; + else if ( rTest <= 0.55f ) + rgb.a = (rTest-0.5f)*20; + else + rgb.a=1.f; +#endif + RawTexture->setPixel(4+p.X+radiusOut, 4+p.Y+radiusOut, rgb.toSColor()); + } + } + } + + if ( supersample > 1 ) + { + video::IImage * filter = driver->createImage(video::ECF_A8R8G8B8, dim ); + RawTexture->copyToScalingBoxFilter(filter); + RawTexture->drop(); + RawTexture = filter; + } + + bool generateMipLevels = driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); + driver->setTextureCreationFlag( video::ETCF_CREATE_MIP_MAPS, false); + + ColorRing.Texture = driver->addTexture ( "#colorring", RawTexture); + RawTexture->drop(); + + driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, generateMipLevels); +} + + +//! called if an event happened. +bool CGUIColorSelectDialog::OnEvent(const SEvent& event) +{ + if (isEnabled()) + { + switch(event.EventType) + { + case EET_GUI_EVENT: + switch(event.GUIEvent.EventType) + { + case EGET_SPINBOX_CHANGED: + { + for ( u32 i = 0; i!= Battery.size (); ++i ) + { + if ( event.GUIEvent.Caller == Battery[i] ) + { + if (i<4) + { + video::SColor rgb((u32)Battery[0]->getValue(), (u32)Battery[1]->getValue(), + (u32)Battery[2]->getValue(), (u32)Battery[3]->getValue()); + video::SColorHSL hsl; + video::SColorf rgb2(rgb); + hsl.fromRGB(rgb2); + Battery[4]->setValue(hsl.Hue); + Battery[5]->setValue(hsl.Saturation); + Battery[6]->setValue(hsl.Luminance); + } + else + { + video::SColorHSL hsl(Battery[4]->getValue(), Battery[5]->getValue(), + Battery[6]->getValue()); + video::SColorf rgb2; + hsl.toRGB(rgb2); + video::SColor rgb = rgb2.toSColor(); + Battery[1]->setValue((f32)rgb.getRed()); + Battery[2]->setValue((f32)rgb.getGreen()); + Battery[3]->setValue((f32)rgb.getBlue()); + } + } + } + return true; + } + + case EGET_ELEMENT_FOCUS_LOST: + Dragging = false; + break; + case EGET_BUTTON_CLICKED: + if (event.GUIEvent.Caller == CloseButton || + event.GUIEvent.Caller == CancelButton) + { + sendCancelEvent(); + remove(); + return true; + } + else + if (event.GUIEvent.Caller == OKButton) + { + sendSelectedEvent(); + remove(); + return true; + } + break; + + case EGET_LISTBOX_CHANGED: + case EGET_LISTBOX_SELECTED_AGAIN: + default: + break; + } + break; + case EET_MOUSE_INPUT_EVENT: + switch(event.MouseInput.Event) + { + case EMIE_LMOUSE_PRESSED_DOWN: + DragStart.X = event.MouseInput.X; + DragStart.Y = event.MouseInput.Y; + Dragging = true; + return true; + case EMIE_LMOUSE_LEFT_UP: + Dragging = false; + return true; + case EMIE_MOUSE_MOVED: + if (Dragging) + { + // gui window should not be dragged outside its parent + if (Parent) + if (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; + + move(core::position2d(event.MouseInput.X - DragStart.X, event.MouseInput.Y - DragStart.Y)); + DragStart.X = event.MouseInput.X; + DragStart.Y = event.MouseInput.Y; + return true; + } + default: + break; + } + default: + break; + } + } + + return IGUIElement::OnEvent(event); +} + + +//! draws the element and its children +void CGUIColorSelectDialog::draw() +{ + if (!IsVisible) + return; + + IGUISkin* skin = Environment->getSkin(); + core::rect rect = skin->draw3DWindowBackground(this, true, skin->getColor(EGDC_ACTIVE_BORDER), + AbsoluteRect, &AbsoluteClippingRect); + + if (Text.size()) + { + rect.UpperLeftCorner.X += 2; + rect.LowerRightCorner.X -= skin->getSize(EGDS_WINDOW_BUTTON_WIDTH) + 5; + + IGUIFont* font = skin->getFont(EGDF_WINDOW); + if (font) + font->draw(Text.c_str(), rect, skin->getColor(EGDC_ACTIVE_CAPTION), false, true, + &AbsoluteClippingRect); + } + + IGUIElement::draw(); + + // draw color selector after the window elements + core::vector2di pos(ColorRing.Control->getAbsolutePosition().UpperLeftCorner); + pos.X += ColorRing.Texture->getOriginalSize().Width/2; + pos.Y += ColorRing.Texture->getOriginalSize().Height/2; +#if 0 + const f32 h = Battery[4]->getValue(); + const f32 s = Battery[5]->getValue(); + const f32 l = Battery[6]->getValue(); + const f32 factor = 58.f*(((s==0)&&(l<50))?(l*0.33f/50):( + (s<100)?((.33f+(s*0.33f/100))):((0.66f+(l-50)*0.33f/50)))); + +#else + const f32 factor = 44; +#endif + pos.X += core::round32(sinf(Battery[4]->getValue()*core::DEGTORAD)*factor); + pos.Y -= core::round32(cosf(Battery[4]->getValue()*core::DEGTORAD)*factor); + Environment->getVideoDriver()->draw2DPolygon(pos, 4, 0xffffffff, 4); +} + + +video::SColor CGUIColorSelectDialog::getColor() +{ + return video::SColor((u32)Battery[0]->getValue(), (u32)Battery[1]->getValue(), + (u32)Battery[2]->getValue(), (u32)Battery[3]->getValue()); +} + +video::SColorHSL CGUIColorSelectDialog::getColorHSL() +{ + return video::SColorHSL(Battery[4]->getValue(), Battery[5]->getValue(), + Battery[6]->getValue()); +} + +//! sends the event that the file has been selected. +void CGUIColorSelectDialog::sendSelectedEvent() +{ + SEvent event; + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.Element = 0; + event.GUIEvent.EventType = EGET_FILE_SELECTED; + Parent->OnEvent(event); +} + + +//! sends the event that the file choose process has been canceld +void CGUIColorSelectDialog::sendCancelEvent() +{ + SEvent event; + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.Element = 0; + event.GUIEvent.EventType = EGET_FILE_CHOOSE_DIALOG_CANCELLED; + Parent->OnEvent(event); +} + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ diff --git a/source/Irrlicht/CGUIColorSelectDialog.h b/source/Irrlicht/CGUIColorSelectDialog.h new file mode 100644 index 00000000..8dbad50e --- /dev/null +++ b/source/Irrlicht/CGUIColorSelectDialog.h @@ -0,0 +1,74 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_COLOR_SELECT_DIALOG_H_INCLUDED__ +#define __C_GUI_COLOR_SELECT_DIALOG_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIColorSelectDialog.h" +#include "IGUIButton.h" +#include "IGUISpinBox.h" +#include "IGUIImage.h" +#include "irrArray.h" + + +namespace irr +{ +namespace gui +{ + + class CGUIColorSelectDialog : public IGUIColorSelectDialog + { + public: + + //! constructor + CGUIColorSelectDialog(const wchar_t* title, IGUIEnvironment* environment, IGUIElement* parent, s32 id); + + //! destructor + virtual ~CGUIColorSelectDialog(); + + //! called if an event happened. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + virtual video::SColor getColor() _IRR_OVERRIDE_; + virtual video::SColorHSL getColorHSL() _IRR_OVERRIDE_; + + private: + + //! sends the event that the file has been selected. + void sendSelectedEvent(); + + //! sends the event that the file choose process has been canceld + void sendCancelEvent(); + + core::position2d DragStart; + bool Dragging; + IGUIButton* CloseButton; + IGUIButton* OKButton; + IGUIButton* CancelButton; + + core::array Battery; + + struct SColorCircle + { + IGUIImage * Control; + video::ITexture * Texture; + }; + SColorCircle ColorRing; + + void buildColorRing( const core::dimension2d & dim, s32 supersample, const video::SColor& borderColor ); + }; + + +} // end namespace gui +} // end namespace irr + +#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 new file mode 100644 index 00000000..1efd345b --- /dev/null +++ b/source/Irrlicht/CGUIComboBox.cpp @@ -0,0 +1,540 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUIComboBox.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IGUIFont.h" +#include "IGUIButton.h" +#include "CGUIListBox.h" +#include "os.h" + +namespace irr +{ +namespace gui +{ + +//! constructor +CGUIComboBox::CGUIComboBox(IGUIEnvironment* environment, IGUIElement* parent, + s32 id, core::rect rectangle) + : IGUIComboBox(environment, parent, id, rectangle), + ListButton(0), SelectedText(0), ListBox(0), LastFocus(0), + Selected(-1), HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_CENTER), MaxSelectionRows(5), HasFocus(false), + ActiveFont(0) +{ + #ifdef _DEBUG + setDebugName("CGUIComboBox"); + #endif + + IGUISkin* skin = Environment->getSkin(); + + ListButton = Environment->addButton(core::recti(0,0,1,1), this, -1, L""); + if (skin && skin->getSpriteBank()) + { + ListButton->setSpriteBank(skin->getSpriteBank()); + ListButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_DOWN), skin->getColor(EGDC_WINDOW_SYMBOL)); + ListButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_DOWN), skin->getColor(EGDC_WINDOW_SYMBOL)); + } + ListButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + ListButton->setSubElement(true); + ListButton->setTabStop(false); + + SelectedText = Environment->addStaticText(L"", core::recti(0,0,1,1), false, false, this, -1, false); + SelectedText->setSubElement(true); + SelectedText->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + SelectedText->setTextAlignment(EGUIA_UPPERLEFT, EGUIA_CENTER); + if (skin) + SelectedText->setOverrideColor(skin->getColor(EGDC_BUTTON_TEXT)); + SelectedText->enableOverrideColor(true); + + updateListButtonWidth(skin ? skin->getSize(EGDS_SCROLLBAR_SIZE) : 15); + + // this element can be tabbed to + setTabStop(true); + setTabOrder(-1); +} + + +void CGUIComboBox::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical) +{ + HAlign = horizontal; + VAlign = vertical; + SelectedText->setTextAlignment(horizontal, vertical); +} + + +//! Set the maximal number of rows for the selection listbox +void CGUIComboBox::setMaxSelectionRows(u32 max) +{ + MaxSelectionRows = max; + + // force recalculation of open listbox + if (ListBox) + { + openCloseMenu(); + openCloseMenu(); + } +} + +//! Get the maximal number of rows for the selection listbox +u32 CGUIComboBox::getMaxSelectionRows() const +{ + return MaxSelectionRows; +} + + +//! Returns amount of items in box +u32 CGUIComboBox::getItemCount() const +{ + return Items.size(); +} + + +//! returns string of an item. the idx may be a value from 0 to itemCount-1 +const wchar_t* CGUIComboBox::getItem(u32 idx) const +{ + if (idx >= Items.size()) + return 0; + + return Items[idx].Name.c_str(); +} + +//! returns string of an item. the idx may be a value from 0 to itemCount-1 +u32 CGUIComboBox::getItemData(u32 idx) const +{ + if (idx >= Items.size()) + return 0; + + return Items[idx].Data; +} + +//! Returns index based on item data +s32 CGUIComboBox::getIndexForItemData(u32 data ) const +{ + for ( u32 i = 0; i < Items.size (); ++i ) + { + if ( Items[i].Data == data ) + return i; + } + return -1; +} + + +//! Removes an item from the combo box. +void CGUIComboBox::removeItem(u32 idx) +{ + if (idx >= Items.size()) + return; + + if (Selected == (s32)idx) + setSelected(-1); + + Items.erase(idx); +} + + +//! Returns caption of this element. +const wchar_t* CGUIComboBox::getText() const +{ + return getItem(Selected); +} + + +//! adds an item and returns the index of it +u32 CGUIComboBox::addItem(const wchar_t* text, u32 data) +{ + Items.push_back( SComboData ( text, data ) ); + + if (Selected == -1) + setSelected(0); + + return Items.size() - 1; +} + + +//! deletes all items in the combo box +void CGUIComboBox::clear() +{ + Items.clear(); + setSelected(-1); +} + + +//! returns id of selected item. returns -1 if no item is selected. +s32 CGUIComboBox::getSelected() const +{ + return Selected; +} + + +//! sets the selected item. Set this to -1 if no item should be selected +void CGUIComboBox::setSelected(s32 idx) +{ + if (idx < -1 || idx >= (s32)Items.size()) + return; + + Selected = idx; + if (Selected == -1) + SelectedText->setText(L""); + else + SelectedText->setText(Items[Selected].Name.c_str()); +} + + +//! called if an event happened. +bool CGUIComboBox::OnEvent(const SEvent& event) +{ + if (isEnabled()) + { + switch(event.EventType) + { + + case EET_KEY_INPUT_EVENT: + if (ListBox && event.KeyInput.PressedDown && event.KeyInput.Key == KEY_ESCAPE) + { + // hide list box + openCloseMenu(); + return true; + } + else + if (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE) + { + if (!event.KeyInput.PressedDown) + { + openCloseMenu(); + } + + ListButton->setPressed(ListBox == 0); + + return true; + } + else + if (event.KeyInput.PressedDown) + { + s32 oldSelected = Selected; + bool absorb = true; + switch (event.KeyInput.Key) + { + case KEY_DOWN: + setSelected(Selected+1); + break; + case KEY_UP: + setSelected(Selected-1); + break; + case KEY_HOME: + case KEY_PRIOR: + setSelected(0); + break; + case KEY_END: + case KEY_NEXT: + setSelected((s32)Items.size()-1); + break; + default: + absorb = false; + } + + if (Selected <0) + setSelected(0); + + if (Selected >= (s32)Items.size()) + setSelected((s32)Items.size() -1); + + if (Selected != oldSelected) + { + sendSelectionChangedEvent(); + return true; + } + + if (absorb) + return true; + } + break; + + case EET_GUI_EVENT: + + switch(event.GUIEvent.EventType) + { + case EGET_ELEMENT_FOCUS_LOST: + if (ListBox && + (Environment->hasFocus(ListBox) || ListBox->isMyChild(event.GUIEvent.Caller) ) && + event.GUIEvent.Element != this && + !isMyChild(event.GUIEvent.Element) && + !ListBox->isMyChild(event.GUIEvent.Element)) + { + openCloseMenu(); + } + break; + case EGET_BUTTON_CLICKED: + if (event.GUIEvent.Caller == ListButton) + { + openCloseMenu(); + return true; + } + break; + case EGET_LISTBOX_SELECTED_AGAIN: + case EGET_LISTBOX_CHANGED: + if (event.GUIEvent.Caller == ListBox) + { + setSelected(ListBox->getSelected()); + if (Selected <0 || Selected >= (s32)Items.size()) + setSelected(-1); + openCloseMenu(); + + sendSelectionChangedEvent(); + } + return true; + default: + break; + } + break; + case EET_MOUSE_INPUT_EVENT: + + switch(event.MouseInput.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; + + return true; + } + case EMIE_LMOUSE_LEFT_UP: + { + core::position2d p(event.MouseInput.X, event.MouseInput.Y); + + // send to list box + if (!(ListBox && + ListBox->getAbsolutePosition().isPointInside(p) && + ListBox->OnEvent(event))) + { + openCloseMenu(); + } + return true; + } + case EMIE_MOUSE_WHEEL: + { + s32 oldSelected = Selected; + setSelected( Selected + ((event.MouseInput.Wheel < 0) ? 1 : -1)); + + if (Selected <0) + setSelected(0); + + if (Selected >= (s32)Items.size()) + setSelected((s32)Items.size() -1); + + if (Selected != oldSelected) + { + sendSelectionChangedEvent(); + return true; + } + } + default: + break; + } + break; + default: + break; + } + } + + return IGUIElement::OnEvent(event); +} + + +void CGUIComboBox::sendSelectionChangedEvent() +{ + if (Parent) + { + SEvent event; + + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.Element = 0; + event.GUIEvent.EventType = EGET_COMBO_BOX_CHANGED; + Parent->OnEvent(event); + } +} + +void CGUIComboBox::updateListButtonWidth(s32 width) +{ + if (ListButton->getRelativePosition().getWidth() != width) + { + core::rect r; + r.UpperLeftCorner.X = RelativeRect.getWidth() - width - 2; + r.LowerRightCorner.X = RelativeRect.getWidth() - 2; + r.UpperLeftCorner.Y = 2; + r.LowerRightCorner.Y = RelativeRect.getHeight() - 2; + ListButton->setRelativePosition(r); + + r.UpperLeftCorner.X = 2; + r.UpperLeftCorner.Y = 2; + r.LowerRightCorner.X = RelativeRect.getWidth() - (width + 2); + r.LowerRightCorner.Y = RelativeRect.getHeight() - 2; + SelectedText->setRelativePosition(r); + } +} + +//! draws the element and its children +void CGUIComboBox::draw() +{ + if (!IsVisible) + return; + + IGUISkin* skin = Environment->getSkin(); + + updateListButtonWidth(skin->getSize(EGDS_SCROLLBAR_SIZE)); + + // font changed while the listbox is open? + if ( ActiveFont != skin->getFont() && ListBox ) + { + // close and re-open to use new font-size + openCloseMenu(); + openCloseMenu(); + } + + + IGUIElement *currentFocus = Environment->getFocus(); + if (currentFocus != LastFocus) + { + HasFocus = currentFocus == this || isMyChild(currentFocus); + LastFocus = currentFocus; + } + + // set colors each time as skin-colors can be changed + SelectedText->setBackgroundColor(skin->getColor(EGDC_HIGH_LIGHT)); + 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)); + } + ListButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_DOWN), skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL)); + ListButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_DOWN), skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL)); + + + core::rect frameRect(AbsoluteRect); + + // draw the border + + skin->draw3DSunkenPane(this, skin->getColor(EGDC_3D_HIGH_LIGHT), + true, true, frameRect, &AbsoluteClippingRect); + + // draw children + IGUIElement::draw(); +} + + +void CGUIComboBox::openCloseMenu() +{ + if (ListBox) + { + // close list box + Environment->setFocus(this); + ListBox->remove(); + ListBox = 0; + } + else + { + if (Parent) + Parent->bringToFront(this); + + IGUISkin* skin = Environment->getSkin(); + u32 h = Items.size(); + + if (h > getMaxSelectionRows()) + h = getMaxSelectionRows(); + if (h == 0) + h = 1; + + ActiveFont = skin->getFont(); + if (ActiveFont) + h *= (ActiveFont->getDimension(L"A").Height + 4); + + // open list box + core::rect r(0, AbsoluteRect.getHeight(), + AbsoluteRect.getWidth(), AbsoluteRect.getHeight() + h); + + ListBox = new CGUIListBox(Environment, this, -1, r, false, true, true); + ListBox->setSubElement(true); + ListBox->setNotClipped(true); + ListBox->drop(); + + // ensure that list box is always completely visible + if (ListBox->getAbsolutePosition().LowerRightCorner.Y > Environment->getRootGUIElement()->getAbsolutePosition().getHeight()) + ListBox->setRelativePosition( core::rect(0, -ListBox->getAbsolutePosition().getHeight(), AbsoluteRect.getWidth(), 0) ); + + for (s32 i=0; i<(s32)Items.size(); ++i) + ListBox->addItem(Items[i].Name.c_str()); + + ListBox->setSelected(Selected); + + // set focus + Environment->setFocus(ListBox); + } +} + + +//! Writes attributes of the element. +void CGUIComboBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const +{ + IGUIComboBox::serializeAttributes(out,options); + + out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames); + out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames); + out->addInt("MaxSelectionRows", (s32)MaxSelectionRows ); + + out->addInt ("Selected", Selected ); + out->addInt ("ItemCount", Items.size()); + for (u32 i=0; i < Items.size(); ++i) + { + core::stringc s = "Item"; + s += i; + s += "Text"; + out->addString(s.c_str(), Items[i].Name.c_str()); + } +} + + +//! Reads attributes of the element +void CGUIComboBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) +{ + IGUIComboBox::deserializeAttributes(in,options); + + setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames), + (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames)); + setMaxSelectionRows( (u32)(in->getAttributeAsInt("MaxSelectionRows")) ); + + // clear the list + clear(); + // get item count + u32 c = in->getAttributeAsInt("ItemCount"); + // add items + for (u32 i=0; i < c; ++i) + { + core::stringc s = "Item"; + s += i; + s += "Text"; + addItem(in->getAttributeAsStringW(s.c_str()).c_str(), 0); + } + + setSelected(in->getAttributeAsInt("Selected")); +} + +} // end namespace gui +} // end namespace irr + + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIComboBox.h b/source/Irrlicht/CGUIComboBox.h new file mode 100644 index 00000000..5aa5de6d --- /dev/null +++ b/source/Irrlicht/CGUIComboBox.h @@ -0,0 +1,119 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_COMBO_BOX_H_INCLUDED__ +#define __C_GUI_COMBO_BOX_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIComboBox.h" +#include "IGUIStaticText.h" +#include "irrString.h" +#include "irrArray.h" + +namespace irr +{ +namespace gui +{ + class IGUIButton; + class IGUIListBox; + + //! Single line edit box for editing simple text. + class CGUIComboBox : public IGUIComboBox + { + public: + + //! constructor + CGUIComboBox(IGUIEnvironment* environment, IGUIElement* parent, + s32 id, core::rect rectangle); + + //! Returns amount of items in box + virtual u32 getItemCount() const _IRR_OVERRIDE_; + + //! returns string of an item. the idx may be a value from 0 to itemCount-1 + virtual const wchar_t* getItem(u32 idx) const _IRR_OVERRIDE_; + + //! Returns item data of an item. the idx may be a value from 0 to itemCount-1 + virtual u32 getItemData(u32 idx) const _IRR_OVERRIDE_; + + //! Returns index based on item data + virtual s32 getIndexForItemData( u32 data ) const _IRR_OVERRIDE_; + + //! adds an item and returns the index of it + virtual u32 addItem(const wchar_t* text, u32 data) _IRR_OVERRIDE_; + + //! Removes an item from the combo box. + virtual void removeItem(u32 id) _IRR_OVERRIDE_; + + //! deletes all items in the combo box + virtual void clear() _IRR_OVERRIDE_; + + //! returns the text of the currently selected item + virtual const wchar_t* getText() const _IRR_OVERRIDE_; + + //! returns id of selected item. returns -1 if no item is selected. + virtual s32 getSelected() const _IRR_OVERRIDE_; + + //! sets the selected item. Set this to -1 if no item should be selected + virtual void setSelected(s32 idx) _IRR_OVERRIDE_; + + //! sets the text alignment of the text part + virtual void setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical) _IRR_OVERRIDE_; + + //! Set the maximal number of rows for the selection listbox + virtual void setMaxSelectionRows(u32 max) _IRR_OVERRIDE_; + + //! Get the maximal number of rows for the selection listbox + virtual u32 getMaxSelectionRows() const _IRR_OVERRIDE_; + + //! called if an event happened. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + //! Writes attributes of the element. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the element + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + + private: + + void openCloseMenu(); + void sendSelectionChangedEvent(); + void updateListButtonWidth(s32 width); + + IGUIButton* ListButton; + IGUIStaticText* SelectedText; + IGUIListBox* ListBox; + IGUIElement *LastFocus; + + + struct SComboData + { + SComboData ( const wchar_t * text, u32 data ) + : Name (text), Data ( data ) {} + + core::stringw Name; + u32 Data; + }; + core::array< SComboData > Items; + + s32 Selected; + EGUI_ALIGNMENT HAlign, VAlign; + u32 MaxSelectionRows; + bool HasFocus; + IGUIFont* ActiveFont; + }; + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif // __C_GUI_COMBO_BOX_H_INCLUDED__ + diff --git a/source/Irrlicht/CGUIContextMenu.cpp b/source/Irrlicht/CGUIContextMenu.cpp new file mode 100644 index 00000000..c28d30ab --- /dev/null +++ b/source/Irrlicht/CGUIContextMenu.cpp @@ -0,0 +1,879 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUIContextMenu.h" + +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" +#include "IGUIFont.h" +#include "IGUISpriteBank.h" +#include "os.h" + +namespace irr +{ +namespace gui +{ + + +//! constructor +CGUIContextMenu::CGUIContextMenu(IGUIEnvironment* environment, + IGUIElement* parent, s32 id, + core::rect rectangle, bool getFocus, bool allowFocus) + : IGUIContextMenu(environment, parent, id, rectangle), EventParent(0), LastFont(0), + CloseHandling(ECMC_REMOVE), HighLighted(-1), ChangeTime(0), AllowFocus(allowFocus) +{ + #ifdef _DEBUG + setDebugName("CGUIContextMenu"); + #endif + + Pos = rectangle.UpperLeftCorner; + recalculateSize(); + + if (getFocus) + Environment->setFocus(this); + + setNotClipped(true); +} + + +//! destructor +CGUIContextMenu::~CGUIContextMenu() +{ + for (u32 i=0; idrop(); + + if (LastFont) + LastFont->drop(); +} + +//! set behavior when menus are closed +void CGUIContextMenu::setCloseHandling(ECONTEXT_MENU_CLOSE onClose) +{ + CloseHandling = onClose; +} + +//! get current behavior when the menue will be closed +ECONTEXT_MENU_CLOSE CGUIContextMenu::getCloseHandling() const +{ + return CloseHandling; +} + +//! Returns amount of menu items +u32 CGUIContextMenu::getItemCount() const +{ + return Items.size(); +} + + +//! Adds a menu item. +u32 CGUIContextMenu::addItem(const wchar_t* text, s32 commandId, bool enabled, bool hasSubMenu, bool checked, bool autoChecking) +{ + return insertItem(Items.size(), text, commandId, enabled, hasSubMenu, checked, autoChecking); +} + +//! Insert a menu item at specified position. +u32 CGUIContextMenu::insertItem(u32 idx, const wchar_t* text, s32 commandId, bool enabled, + bool hasSubMenu, bool checked, bool autoChecking) +{ + SItem s; + s.Enabled = enabled; + s.Checked = checked; + s.AutoChecking = autoChecking; + s.Text = text; + s.IsSeparator = (text == 0); + s.SubMenu = 0; + s.CommandId = commandId; + + if (hasSubMenu) + { + s.SubMenu = new CGUIContextMenu(Environment, this, commandId, + core::rect(0,0,100,100), false, false); + s.SubMenu->setVisible(false); + } + + u32 result = idx; + if ( idx < Items.size() ) + { + Items.insert(s, idx); + } + else + { + Items.push_back(s); + result = Items.size() - 1; + } + + recalculateSize(); + return result; +} + +s32 CGUIContextMenu::findItemWithCommandId(s32 commandId, u32 idxStartSearch) const +{ + for ( u32 i=idxStartSearch; i= Items.size()) + return; + + if (menu) + menu->grab(); + if (Items[index].SubMenu) + Items[index].SubMenu->drop(); + + Items[index].SubMenu = menu; + menu->setVisible(false); + + if (Items[index].SubMenu) + { + menu->AllowFocus = false; + if ( Environment->getFocus() == menu ) + { + Environment->setFocus( this ); + } + } + + recalculateSize(); +} + + +//! Adds a separator item to the menu +void CGUIContextMenu::addSeparator() +{ + addItem(0, -1, true, false, false, false); +} + + +//! Returns text of the menu item. +const wchar_t* CGUIContextMenu::getItemText(u32 idx) const +{ + if (idx >= Items.size()) + return 0; + + return Items[idx].Text.c_str(); +} + + +//! Sets text of the menu item. +void CGUIContextMenu::setItemText(u32 idx, const wchar_t* text) +{ + if (idx >= Items.size()) + return; + + Items[idx].Text = text; + recalculateSize(); +} + +//! should the element change the checked status on clicking +void CGUIContextMenu::setItemAutoChecking(u32 idx, bool autoChecking) +{ + if ( idx >= Items.size()) + return; + + Items[idx].AutoChecking = autoChecking; +} + +//! does the element change the checked status on clicking +bool CGUIContextMenu::getItemAutoChecking(u32 idx) const +{ + if (idx >= Items.size()) + return false; + + return Items[idx].AutoChecking; +} + + +//! Returns if a menu item is enabled +bool CGUIContextMenu::isItemEnabled(u32 idx) const +{ + if (idx >= Items.size()) + { + return false; + } + + return Items[idx].Enabled; +} + + +//! Returns if a menu item is checked +bool CGUIContextMenu::isItemChecked(u32 idx) const +{ + if (idx >= Items.size()) + { + return false; + } + + return Items[idx].Checked; +} + + +//! Sets if the menu item should be enabled. +void CGUIContextMenu::setItemEnabled(u32 idx, bool enabled) +{ + if (idx >= Items.size()) + return; + + Items[idx].Enabled = enabled; +} + + +//! Sets if the menu item should be checked. +void CGUIContextMenu::setItemChecked(u32 idx, bool checked ) +{ + if (idx >= Items.size()) + return; + + Items[idx].Checked = checked; +} + + +//! Removes a menu item +void CGUIContextMenu::removeItem(u32 idx) +{ + if (idx >= Items.size()) + return; + + if (Items[idx].SubMenu) + { + Items[idx].SubMenu->drop(); + Items[idx].SubMenu = 0; + } + + Items.erase(idx); + recalculateSize(); +} + + +//! Removes all menu items +void CGUIContextMenu::removeAllItems() +{ + for (u32 i=0; idrop(); + + Items.clear(); + recalculateSize(); +} + + +//! called if an event happened. +bool CGUIContextMenu::OnEvent(const SEvent& event) +{ + if (isEnabled()) + { + + switch(event.EventType) + { + case EET_GUI_EVENT: + switch(event.GUIEvent.EventType) + { + case EGET_ELEMENT_FOCUS_LOST: + if (event.GUIEvent.Caller == this && !isMyChild(event.GUIEvent.Element) && AllowFocus) + { + // set event parent of submenus + IGUIElement * p = EventParent ? EventParent : Parent; + if ( p ) // can be 0 when element got removed already + { + setEventParent(p); + + SEvent eventClose; + eventClose.EventType = EET_GUI_EVENT; + eventClose.GUIEvent.Caller = this; + eventClose.GUIEvent.Element = 0; + eventClose.GUIEvent.EventType = EGET_ELEMENT_CLOSED; + if ( !p->OnEvent(eventClose) ) + { + if ( CloseHandling & ECMC_HIDE ) + { + setVisible(false); + } + if ( CloseHandling & ECMC_REMOVE ) + { + remove(); + } + } + } + + return false; + } + break; + case EGET_ELEMENT_FOCUSED: + if (event.GUIEvent.Caller == this && !AllowFocus) + { + return true; + } + break; + default: + break; + } + break; + case EET_MOUSE_INPUT_EVENT: + switch(event.MouseInput.Event) + { + case EMIE_LMOUSE_LEFT_UP: + { + // menu might be removed if it loses focus in sendClick, so grab a reference + grab(); + const u32 t = sendClick(core::position2d(event.MouseInput.X, event.MouseInput.Y)); + if ((t==0 || t==1) && Environment->hasFocus(this)) + Environment->removeFocus(this); + drop(); + } + return true; + case EMIE_LMOUSE_PRESSED_DOWN: + return true; + case EMIE_MOUSE_MOVED: + if (Environment->hasFocus(this)) + highlight(core::position2d(event.MouseInput.X, event.MouseInput.Y), true); + return true; + default: + break; + } + break; + default: + break; + } + } + + return IGUIElement::OnEvent(event); +} + + +//! Sets the visible state of this element. +void CGUIContextMenu::setVisible(bool visible) +{ + HighLighted = -1; + ChangeTime = os::Timer::getTime(); + for (u32 j=0; jsetVisible(false); + + IGUIElement::setVisible(visible); +} + + +//! sends a click Returns: +//! 0 if click went outside of the element, +//! 1 if a valid button was clicked, +//! 2 if a nonclickable element was clicked +u32 CGUIContextMenu::sendClick(const core::position2d& p) +{ + u32 t = 0; + + // get number of open submenu + s32 openmenu = -1; + s32 j; + for (j=0; j<(s32)Items.size(); ++j) + if (Items[j].SubMenu && Items[j].SubMenu->isVisible()) + { + openmenu = j; + break; + } + + // delegate click operation to submenu + if (openmenu != -1) + { + t = Items[j].SubMenu->sendClick(p); + if (t != 0) + return t; // clicked something + } + + // check click on myself + if (isPointInside(p) && + (u32)HighLighted < Items.size()) + { + if (!Items[HighLighted].Enabled || + Items[HighLighted].IsSeparator || + Items[HighLighted].SubMenu) + return 2; + + if ( Items[HighLighted].AutoChecking ) + { + Items[HighLighted].Checked = Items[HighLighted].Checked ? false : true; + } + + SEvent event; + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.Element = 0; + event.GUIEvent.EventType = EGET_MENU_ITEM_SELECTED; + if (EventParent) + EventParent->OnEvent(event); + else if (Parent) + Parent->OnEvent(event); + + return 1; + } + + return 0; +} + + +//! returns true, if an element was highligted +bool CGUIContextMenu::highlight(const core::position2d& p, bool canOpenSubMenu) +{ + if (!isEnabled()) + { + return false; + } + + // get number of open submenu + s32 openmenu = -1; + s32 i; + for (i=0; i<(s32)Items.size(); ++i) + if (Items[i].Enabled && Items[i].SubMenu && Items[i].SubMenu->isVisible()) + { + openmenu = i; + break; + } + + // delegate highlight operation to submenu + if (openmenu != -1) + { + if (Items[openmenu].Enabled && Items[openmenu].SubMenu->highlight(p, canOpenSubMenu)) + { + HighLighted = openmenu; + ChangeTime = os::Timer::getTime(); + return true; + } + } + + // highlight myself + for (i=0; i<(s32)Items.size(); ++i) + { + if (Items[i].Enabled && getHRect(Items[i], AbsoluteRect).isPointInside(p)) + { + HighLighted = i; + ChangeTime = os::Timer::getTime(); + + // make submenus visible/invisible + for (s32 j=0; j<(s32)Items.size(); ++j) + if (Items[j].SubMenu) + { + if ( j == i && canOpenSubMenu && Items[j].Enabled ) + Items[j].SubMenu->setVisible(true); + else if ( j != i ) + Items[j].SubMenu->setVisible(false); + } + return true; + } + } + + HighLighted = openmenu; + return false; +} + + +//! returns the item highlight-area +core::rect CGUIContextMenu::getHRect(const SItem& i, const core::rect& absolute) const +{ + core::rect r = absolute; + r.UpperLeftCorner.Y += i.PosY; + r.LowerRightCorner.Y = r.UpperLeftCorner.Y + i.Dim.Height; + return r; +} + + +//! Gets drawing rect of Item +core::rect CGUIContextMenu::getRect(const SItem& i, const core::rect& absolute) const +{ + core::rect r = absolute; + r.UpperLeftCorner.Y += i.PosY; + r.LowerRightCorner.Y = r.UpperLeftCorner.Y + i.Dim.Height; + r.UpperLeftCorner.X += 20; + return r; +} + + +//! draws the element and its children +void CGUIContextMenu::draw() +{ + if (!IsVisible) + return; + + IGUISkin* skin = Environment->getSkin(); + + if (!skin) + return; + + IGUIFont* font = skin->getFont(EGDF_MENU); + if (font != LastFont) + { + if (LastFont) + LastFont->drop(); + LastFont = font; + if (LastFont) + LastFont->grab(); + + recalculateSize(); + } + + IGUISpriteBank* sprites = skin->getSpriteBank(); + + core::rect rect = AbsoluteRect; + core::rect* clip = 0; + + // draw frame + skin->draw3DMenuPane(this, AbsoluteRect, clip); + + // loop through all menu items + + rect = AbsoluteRect; + s32 y = AbsoluteRect.UpperLeftCorner.Y; + + for (s32 i=0; i<(s32)Items.size(); ++i) + { + if (Items[i].IsSeparator) + { + // draw separator + rect = AbsoluteRect; + rect.UpperLeftCorner.Y += Items[i].PosY + 3; + rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1; + rect.UpperLeftCorner.X += 5; + rect.LowerRightCorner.X -= 5; + skin->draw2DRectangle(this, skin->getColor(EGDC_3D_SHADOW), rect, clip); + + rect.LowerRightCorner.Y += 1; + rect.UpperLeftCorner.Y += 1; + skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), rect, clip); + + y += 10; + } + else + { + rect = getRect(Items[i], AbsoluteRect); + + // draw highlighted + + if (i == HighLighted && Items[i].Enabled) + { + core::rect r = AbsoluteRect; + r.LowerRightCorner.Y = rect.LowerRightCorner.Y; + r.UpperLeftCorner.Y = rect.UpperLeftCorner.Y; + r.LowerRightCorner.X -= 5; + r.UpperLeftCorner.X += 5; + skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), r, clip); + } + + // draw text + + EGUI_DEFAULT_COLOR c = EGDC_BUTTON_TEXT; + + if (i == HighLighted) + c = EGDC_HIGH_LIGHT_TEXT; + + if (!Items[i].Enabled) + c = EGDC_GRAY_TEXT; + + if (font) + font->draw(Items[i].Text.c_str(), rect, + skin->getColor(c), false, true, clip); + + // draw submenu symbol + if (Items[i].SubMenu && sprites) + { + core::rect r = rect; + r.UpperLeftCorner.X = r.LowerRightCorner.X - 15; + + sprites->draw2DSprite(skin->getIcon(EGDI_CURSOR_RIGHT), + r.getCenter(), clip, skin->getColor(c), + (i == HighLighted) ? ChangeTime : 0, + (i == HighLighted) ? os::Timer::getTime() : 0, + (i == HighLighted), true); + } + + // draw checked symbol + if (Items[i].Checked && sprites) + { + core::rect r = rect; + r.LowerRightCorner.X = r.UpperLeftCorner.X - 15; + r.UpperLeftCorner.X = r.LowerRightCorner.X + 15; + sprites->draw2DSprite(skin->getIcon(EGDI_CHECK_BOX_CHECKED), + r.getCenter(), clip, skin->getColor(c), + (i == HighLighted) ? ChangeTime : 0, + (i == HighLighted) ? os::Timer::getTime() : 0, + (i == HighLighted), true); + } + } + } + + IGUIElement::draw(); +} + + +void CGUIContextMenu::recalculateSize() +{ + IGUIFont* font = Environment->getSkin()->getFont(EGDF_MENU); + + if (!font) + return; + + core::rect rect; + rect.UpperLeftCorner = RelativeRect.UpperLeftCorner; + u32 width = 100; + u32 height = 3; + + u32 i; + for (i=0; igetDimension(Items[i].Text.c_str()); + Items[i].Dim.Width += 40; + + if (Items[i].Dim.Width > width) + width = Items[i].Dim.Width; + } + + Items[i].PosY = height; + height += Items[i].Dim.Height; + } + + height += 5; + + if (height < 10) + height = 10; + + rect.LowerRightCorner.X = RelativeRect.UpperLeftCorner.X + width; + rect.LowerRightCorner.Y = RelativeRect.UpperLeftCorner.Y + height; + + setRelativePosition(rect); + + // recalculate submenus + for (i=0; igetAbsolutePosition().getWidth(); + const s32 h = Items[i].SubMenu->getAbsolutePosition().getHeight(); + + core::rect subRect(width-5, Items[i].PosY, width+w-5, Items[i].PosY+h); + + gui::IGUIElement * root = Environment->getRootGUIElement(); + if ( root ) + { + core::rect rectRoot( root->getAbsolutePosition() ); + + // if it would be drawn beyond the right border, then add it to the left side + if ( getAbsolutePosition().UpperLeftCorner.X+subRect.LowerRightCorner.X > rectRoot.LowerRightCorner.X ) + { + subRect.UpperLeftCorner.X = -w; + subRect.LowerRightCorner.X = 0; + } + + // if it would be drawn below bottom border, move it up, but not further than to top. + irr::s32 belowBottom = getAbsolutePosition().UpperLeftCorner.Y+subRect.LowerRightCorner.Y - rectRoot.LowerRightCorner.Y; + if ( belowBottom > 0 ) + { + irr::s32 belowTop = getAbsolutePosition().UpperLeftCorner.Y+subRect.UpperLeftCorner.Y; + irr::s32 moveUp = belowBottom < belowTop ? belowBottom : belowTop; + subRect.UpperLeftCorner.Y -= moveUp; + subRect.LowerRightCorner.Y -= moveUp; + } + } + + Items[i].SubMenu->setRelativePosition(subRect); + } + } +} + + +//! Returns the selected item in the menu +s32 CGUIContextMenu::getSelectedItem() const +{ + return HighLighted; +} + + +//! \return Returns a pointer to the submenu of an item. +IGUIContextMenu* CGUIContextMenu::getSubMenu(u32 idx) const +{ + if (idx >= Items.size()) + return 0; + + return Items[idx].SubMenu; +} + + +//! Returns command id of a menu item +s32 CGUIContextMenu::getItemCommandId(u32 idx) const +{ + if (idx >= Items.size()) + return -1; + + return Items[idx].CommandId; +} + + +//! Sets the command id of a menu item +void CGUIContextMenu::setItemCommandId(u32 idx, s32 id) +{ + if (idx >= Items.size()) + return; + + Items[idx].CommandId = id; +} + + +//! Writes attributes of the element. +void CGUIContextMenu::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const +{ + IGUIElement::serializeAttributes(out,options); + out->addPosition2d("Position", Pos); + + if (Parent->getType() == EGUIET_CONTEXT_MENU || Parent->getType() == EGUIET_MENU ) + { + const IGUIContextMenu* const ptr = (const IGUIContextMenu*)Parent; + // find the position of this item in its parent's list + u32 i; + // VC6 needs the cast for this + for (i=0; (igetItemCount()) && (ptr->getSubMenu(i) != (const IGUIContextMenu*)this); ++i) + ; // do nothing + + out->addInt("ParentItem", i); + } + + out->addInt("CloseHandling", (s32)CloseHandling); + + // write out the item list + out->addInt("ItemCount", Items.size()); + + core::stringc tmp; + + for (u32 i=0; i < Items.size(); ++i) + { + tmp = "IsSeparator"; tmp += i; + out->addBool(tmp.c_str(), Items[i].IsSeparator); + + if (!Items[i].IsSeparator) + { + tmp = "Text"; tmp += i; + out->addString(tmp.c_str(), Items[i].Text.c_str()); + tmp = "CommandID"; tmp += i; + out->addInt(tmp.c_str(), Items[i].CommandId); + tmp = "Enabled"; tmp += i; + out->addBool(tmp.c_str(), Items[i].Enabled); + tmp = "Checked"; tmp += i; + out->addBool(tmp.c_str(), Items[i].Checked); + tmp = "AutoChecking"; tmp += i; + out->addBool(tmp.c_str(), Items[i].AutoChecking); + } + } +} + + +//! Reads attributes of the element +void CGUIContextMenu::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) +{ + IGUIElement::deserializeAttributes(in,options); + + Pos = in->getAttributeAsPosition2d("Position"); + + // link to this item's parent + if (Parent && ( Parent->getType() == EGUIET_CONTEXT_MENU || Parent->getType() == EGUIET_MENU ) ) + ((CGUIContextMenu*)Parent)->setSubMenu(in->getAttributeAsInt("ParentItem"),this); + + CloseHandling = (ECONTEXT_MENU_CLOSE)in->getAttributeAsInt("CloseHandling"); + + removeAllItems(); + + // read the item list + const s32 count = in->getAttributeAsInt("ItemCount"); + + for (s32 i=0; iexistsAttribute(tmp.c_str()) && in->getAttributeAsBool(tmp.c_str()) ) + addSeparator(); + else + { + tmp = "Text"; tmp += i; + if ( in->existsAttribute(tmp.c_str()) ) + txt = in->getAttributeAsStringW(tmp.c_str()); + + tmp = "CommandID"; tmp += i; + if ( in->existsAttribute(tmp.c_str()) ) + commandid = in->getAttributeAsInt(tmp.c_str()); + + tmp = "Enabled"; tmp += i; + if ( in->existsAttribute(tmp.c_str()) ) + enabled = in->getAttributeAsBool(tmp.c_str()); + + tmp = "Checked"; tmp += i; + if ( in->existsAttribute(tmp.c_str()) ) + checked = in->getAttributeAsBool(tmp.c_str()); + + tmp = "AutoChecking"; tmp += i; + if ( in->existsAttribute(tmp.c_str()) ) + autochecking = in->getAttributeAsBool(tmp.c_str()); + + addItem(core::stringw(txt.c_str()).c_str(), commandid, enabled, false, checked, autochecking); + } + } + + recalculateSize(); +} + + +// because sometimes the element has no parent at click time +void CGUIContextMenu::setEventParent(IGUIElement *parent) +{ + EventParent = parent; + + for (u32 i=0; isetEventParent(parent); +} + + +bool CGUIContextMenu::hasOpenSubMenu() const +{ + for (u32 i=0; iisVisible()) + return true; + + return false; +} + + +void CGUIContextMenu::closeAllSubMenus() +{ + for (u32 i=0; isetVisible(false); + + //HighLighted = -1; +} + + +} // end namespace +} // end namespace + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIContextMenu.h b/source/Irrlicht/CGUIContextMenu.h new file mode 100644 index 00000000..80ddf325 --- /dev/null +++ b/source/Irrlicht/CGUIContextMenu.h @@ -0,0 +1,174 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_CONTEXT_MENU_H_INCLUDED__ +#define __C_GUI_CONTEXT_MENU_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIContextMenu.h" +#include "irrString.h" +#include "irrArray.h" +#include "IGUIFont.h" + +namespace irr +{ +namespace gui +{ + + //! GUI Context menu interface. + class CGUIContextMenu : public IGUIContextMenu + { + public: + + //! constructor + CGUIContextMenu(IGUIEnvironment* environment, + IGUIElement* parent, s32 id, core::rect rectangle, + bool getFocus = true, bool allowFocus = true); + + //! destructor + virtual ~CGUIContextMenu(); + + //! set behavior when menus are closed + virtual void setCloseHandling(ECONTEXT_MENU_CLOSE onClose) _IRR_OVERRIDE_; + + //! get current behavior when the menue will be closed + virtual ECONTEXT_MENU_CLOSE getCloseHandling() const _IRR_OVERRIDE_; + + //! Returns amount of menu items + virtual u32 getItemCount() const _IRR_OVERRIDE_; + + //! Adds a menu item. + virtual u32 addItem(const wchar_t* text, s32 commandid, + bool enabled, bool hasSubMenu, bool checked, bool autoChecking) _IRR_OVERRIDE_; + + //! Insert a menu item at specified position. + virtual u32 insertItem(u32 idx, const wchar_t* text, s32 commandId, bool enabled, + bool hasSubMenu, bool checked, bool autoChecking) _IRR_OVERRIDE_; + + //! Find a item which has the given CommandId starting from given index + virtual s32 findItemWithCommandId(s32 commandId, u32 idxStartSearch) const _IRR_OVERRIDE_; + + //! Adds a separator item to the menu + virtual void addSeparator() _IRR_OVERRIDE_; + + //! Returns text of the menu item. + virtual const wchar_t* getItemText(u32 idx) const _IRR_OVERRIDE_; + + //! Sets text of the menu item. + virtual void setItemText(u32 idx, const wchar_t* text) _IRR_OVERRIDE_; + + //! Returns if a menu item is enabled + virtual bool isItemEnabled(u32 idx) const _IRR_OVERRIDE_; + + //! Sets if the menu item should be enabled. + virtual void setItemEnabled(u32 idx, bool enabled) _IRR_OVERRIDE_; + + //! Returns if a menu item is checked + virtual bool isItemChecked(u32 idx) const _IRR_OVERRIDE_; + + //! Sets if the menu item should be checked. + virtual void setItemChecked(u32 idx, bool enabled) _IRR_OVERRIDE_; + + //! Removes a menu item + virtual void removeItem(u32 idx) _IRR_OVERRIDE_; + + //! Removes all menu items + virtual void removeAllItems() _IRR_OVERRIDE_; + + //! called if an event happened. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + //! Returns the selected item in the menu + virtual s32 getSelectedItem() const _IRR_OVERRIDE_; + + //! Returns a pointer to the submenu of an item. + //! \return Pointer to the submenu of an item. + virtual IGUIContextMenu* getSubMenu(u32 idx) const _IRR_OVERRIDE_; + + //! Sets the visible state of this element. + virtual void setVisible(bool visible) _IRR_OVERRIDE_; + + //! should the element change the checked status on clicking + virtual void setItemAutoChecking(u32 idx, bool autoChecking) _IRR_OVERRIDE_; + + //! does the element change the checked status on clicking + virtual bool getItemAutoChecking(u32 idx) const _IRR_OVERRIDE_; + + //! Returns command id of a menu item + virtual s32 getItemCommandId(u32 idx) const _IRR_OVERRIDE_; + + //! Sets the command id of a menu item + virtual void setItemCommandId(u32 idx, s32 id) _IRR_OVERRIDE_; + + //! Adds a sub menu from an element that already exists. + virtual void setSubMenu(u32 index, CGUIContextMenu* menu); + + //! When an eventparent is set it receives events instead of the usual parent element + virtual void setEventParent(IGUIElement *parent) _IRR_OVERRIDE_; + + //! Writes attributes of the element. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the element + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + + protected: + + void closeAllSubMenus(); + bool hasOpenSubMenu() const; + + struct SItem + { + core::stringw Text; + bool IsSeparator; + bool Enabled; + bool Checked; + bool AutoChecking; + core::dimension2d Dim; + s32 PosY; + CGUIContextMenu* SubMenu; + s32 CommandId; + }; + + virtual void recalculateSize(); + + //! returns true, if an element was highlighted + virtual bool highlight(const core::position2d& p, bool canOpenSubMenu); + + //! sends a click Returns: + //! 0 if click went outside of the element, + //! 1 if a valid button was clicked, + //! 2 if a nonclickable element was clicked + virtual u32 sendClick(const core::position2d& p); + + //! returns the item highlight-area + virtual core::rect getHRect(const SItem& i, const core::rect& absolute) const; + + //! Gets drawing rect of Item + virtual core::rect getRect(const SItem& i, const core::rect& absolute) const; + + + core::array Items; + core::position2d Pos; + IGUIElement* EventParent; + IGUIFont *LastFont; + ECONTEXT_MENU_CLOSE CloseHandling; + s32 HighLighted; + u32 ChangeTime; + bool AllowFocus; + }; + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif // __C_GUI_CONTEXT_MENU_H_INCLUDED__ + diff --git a/source/Irrlicht/CGUIEditBox.cpp b/source/Irrlicht/CGUIEditBox.cpp new file mode 100644 index 00000000..a55664e1 --- /dev/null +++ b/source/Irrlicht/CGUIEditBox.cpp @@ -0,0 +1,1686 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUIEditBox.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IGUIFont.h" +#include "IVideoDriver.h" +#include "rect.h" +#include "os.h" +#include "Keycodes.h" + +/* + todo: + optional scrollbars + ctrl+left/right to select word + double click/ctrl click: word select + drag to select whole words, triple click to select line + optional? dragging selected text + numerical +*/ + +namespace irr +{ +namespace gui +{ + +//! constructor +CGUIEditBox::CGUIEditBox(const wchar_t* text, bool border, + IGUIEnvironment* environment, IGUIElement* parent, s32 id, + const core::rect& rectangle) + : IGUIEditBox(environment, parent, id, rectangle), OverwriteMode(false), MouseMarking(false), + Border(border), Background(true), OverrideColorEnabled(false), MarkBegin(0), MarkEnd(0), + OverrideColor(video::SColor(101,255,255,255)), OverrideFont(0), LastBreakFont(0), + Operator(0), BlinkStartTime(0), CursorBlinkTime(350), CursorChar(L"_"), CursorPos(0), HScrollPos(0), VScrollPos(0), Max(0), + WordWrap(false), MultiLine(false), AutoScroll(true), PasswordBox(false), + PasswordChar(L'*'), HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_CENTER), + CurrentTextRect(0,0,1,1), FrameRect(rectangle) +{ + #ifdef _DEBUG + setDebugName("CGUIEditBox"); + #endif + + Text = text; + + if (Environment) + Operator = Environment->getOSOperator(); + + if (Operator) + Operator->grab(); + + // this element can be tabbed to + setTabStop(true); + setTabOrder(-1); + + calculateFrameRect(); + breakText(); + + calculateScrollPos(); +} + + +//! destructor +CGUIEditBox::~CGUIEditBox() +{ + if (OverrideFont) + OverrideFont->drop(); + + if (Operator) + Operator->drop(); +} + + +//! Sets another skin independent font. +void CGUIEditBox::setOverrideFont(IGUIFont* font) +{ + if (OverrideFont == font) + return; + + if (OverrideFont) + OverrideFont->drop(); + + OverrideFont = font; + + if (OverrideFont) + OverrideFont->grab(); + + breakText(); +} + +//! Gets the override font (if any) +IGUIFont * CGUIEditBox::getOverrideFont() const +{ + return OverrideFont; +} + +//! Get the font which is used right now for drawing +IGUIFont* CGUIEditBox::getActiveFont() const +{ + if ( OverrideFont ) + return OverrideFont; + IGUISkin* skin = Environment->getSkin(); + if (skin) + return skin->getFont(); + return 0; +} + +//! Sets another color for the text. +void CGUIEditBox::setOverrideColor(video::SColor color) +{ + OverrideColor = color; + OverrideColorEnabled = true; +} + + +video::SColor CGUIEditBox::getOverrideColor() const +{ + return OverrideColor; +} + + +//! Turns the border on or off +void CGUIEditBox::setDrawBorder(bool border) +{ + Border = border; +} + +//! Checks if border drawing is enabled +bool CGUIEditBox::isDrawBorderEnabled() const +{ + return Border; +} + +//! Sets whether to draw the background +void CGUIEditBox::setDrawBackground(bool draw) +{ + Background = draw; +} + +//! Checks if background drawing is enabled +bool CGUIEditBox::isDrawBackgroundEnabled() const +{ + return Background; +} + +//! Sets if the text should use the override color or the color in the gui skin. +void CGUIEditBox::enableOverrideColor(bool enable) +{ + OverrideColorEnabled = enable; +} + +bool CGUIEditBox::isOverrideColorEnabled() const +{ + return OverrideColorEnabled; +} + +//! Enables or disables word wrap +void CGUIEditBox::setWordWrap(bool enable) +{ + WordWrap = enable; + breakText(); +} + + +void CGUIEditBox::updateAbsolutePosition() +{ + core::rect oldAbsoluteRect(AbsoluteRect); + IGUIElement::updateAbsolutePosition(); + if ( oldAbsoluteRect != AbsoluteRect ) + { + calculateFrameRect(); + breakText(); + calculateScrollPos(); + } +} + + +//! Checks if word wrap is enabled +bool CGUIEditBox::isWordWrapEnabled() const +{ + return WordWrap; +} + + +//! Enables or disables newlines. +void CGUIEditBox::setMultiLine(bool enable) +{ + MultiLine = enable; + breakText(); +} + + +//! Checks if multi line editing is enabled +bool CGUIEditBox::isMultiLineEnabled() const +{ + return MultiLine; +} + + +void CGUIEditBox::setPasswordBox(bool passwordBox, wchar_t passwordChar) +{ + PasswordBox = passwordBox; + if (PasswordBox) + { + PasswordChar = passwordChar; + setMultiLine(false); + setWordWrap(false); + BrokenText.clear(); + } +} + + +bool CGUIEditBox::isPasswordBox() const +{ + return PasswordBox; +} + + +//! Sets text justification +void CGUIEditBox::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical) +{ + HAlign = horizontal; + VAlign = vertical; +} + + +//! called if an event happened. +bool CGUIEditBox::OnEvent(const SEvent& event) +{ + if (isEnabled()) + { + + switch(event.EventType) + { + case EET_GUI_EVENT: + if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST) + { + if (event.GUIEvent.Caller == this) + { + MouseMarking = false; + setTextMarkers(0,0); + } + } + break; + case EET_KEY_INPUT_EVENT: + if (processKey(event)) + return true; + break; + case EET_MOUSE_INPUT_EVENT: + if (processMouse(event)) + return true; + break; + default: + break; + } + } + + return IGUIElement::OnEvent(event); +} + + +bool CGUIEditBox::processKey(const SEvent& event) +{ + if (!event.KeyInput.PressedDown) + return false; + + bool textChanged = false; + s32 newMarkBegin = MarkBegin; + s32 newMarkEnd = MarkEnd; + + // control shortcut handling + + if (event.KeyInput.Control) + { + // german backlash '\' entered with control + '?' + if ( event.KeyInput.Char == '\\' ) + { + inputChar(event.KeyInput.Char); + return true; + } + + switch(event.KeyInput.Key) + { + case KEY_KEY_A: + // select all + newMarkBegin = 0; + newMarkEnd = Text.size(); + break; + case KEY_KEY_C: + // copy to clipboard + if (!PasswordBox && Operator && MarkBegin != MarkEnd) + { + const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; + const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; + + core::stringc s; + s = Text.subString(realmbgn, realmend - realmbgn).c_str(); + Operator->copyToClipboard(s.c_str()); + } + break; + case KEY_KEY_X: + // cut to the clipboard + if (!PasswordBox && Operator && MarkBegin != MarkEnd) + { + const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; + const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; + + // copy + core::stringc sc; + sc = Text.subString(realmbgn, realmend - realmbgn).c_str(); + Operator->copyToClipboard(sc.c_str()); + + if (isEnabled()) + { + // delete + core::stringw s; + s = Text.subString(0, realmbgn); + s.append( Text.subString(realmend, Text.size()-realmend) ); + Text = s; + + CursorPos = realmbgn; + newMarkBegin = 0; + newMarkEnd = 0; + textChanged = true; + } + } + break; + case KEY_KEY_V: + if ( !isEnabled() ) + break; + + // paste from the clipboard + if (Operator) + { + const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; + const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; + + // add new character + const c8* p = Operator->getTextFromClipboard(); + if (p) + { + irr::core::stringw widep; + core::multibyteToWString(widep, p); + + if (MarkBegin == MarkEnd) + { + // insert text + core::stringw s = Text.subString(0, CursorPos); + s.append(widep); + s.append( Text.subString(CursorPos, Text.size()-CursorPos) ); + + if (!Max || s.size()<=Max) // thx to Fish FH for fix + { + Text = s; + s = widep; + CursorPos += s.size(); + } + } + else + { + // replace text + + core::stringw s = Text.subString(0, realmbgn); + s.append(widep); + s.append( Text.subString(realmend, Text.size()-realmend) ); + + if (!Max || s.size()<=Max) // thx to Fish FH for fix + { + Text = s; + s = widep; + CursorPos = realmbgn + s.size(); + } + } + } + + newMarkBegin = 0; + newMarkEnd = 0; + textChanged = true; + } + break; + case KEY_HOME: + // move/highlight to start of text + if (event.KeyInput.Shift) + { + newMarkEnd = CursorPos; + newMarkBegin = 0; + CursorPos = 0; + } + else + { + CursorPos = 0; + newMarkBegin = 0; + newMarkEnd = 0; + } + break; + case KEY_END: + // move/highlight to end of text + if (event.KeyInput.Shift) + { + newMarkBegin = CursorPos; + newMarkEnd = Text.size(); + CursorPos = 0; + } + else + { + CursorPos = Text.size(); + newMarkBegin = 0; + newMarkEnd = 0; + } + break; + default: + return false; + } + } + // Some special keys - but only handle them if KeyInput.Char is null as on some systems (X11) they might have same key-code as ansi-keys otherwise + else if (event.KeyInput.Char == 0) + { + switch(event.KeyInput.Key) + { + case KEY_END: + { + s32 p = Text.size(); + if (WordWrap || MultiLine) + { + p = getLineFromPos(CursorPos); + p = BrokenTextPositions[p] + (s32)BrokenText[p].size(); + if (p > 0 && (Text[p-1] == L'\r' || Text[p-1] == L'\n' )) + p-=1; + } + + if (event.KeyInput.Shift) + { + if (MarkBegin == MarkEnd) + newMarkBegin = CursorPos; + + newMarkEnd = p; + } + else + { + newMarkBegin = 0; + newMarkEnd = 0; + } + CursorPos = p; + BlinkStartTime = os::Timer::getTime(); + } + break; + case KEY_HOME: + { + + s32 p = 0; + if (WordWrap || MultiLine) + { + p = getLineFromPos(CursorPos); + p = BrokenTextPositions[p]; + } + + if (event.KeyInput.Shift) + { + if (MarkBegin == MarkEnd) + newMarkBegin = CursorPos; + newMarkEnd = p; + } + else + { + newMarkBegin = 0; + newMarkEnd = 0; + } + CursorPos = p; + BlinkStartTime = os::Timer::getTime(); + } + break; + case KEY_LEFT: + + if (event.KeyInput.Shift) + { + if (CursorPos > 0) + { + if (MarkBegin == MarkEnd) + newMarkBegin = CursorPos; + + newMarkEnd = CursorPos-1; + } + } + else + { + newMarkBegin = 0; + newMarkEnd = 0; + } + + if (CursorPos > 0) CursorPos--; + BlinkStartTime = os::Timer::getTime(); + break; + + case KEY_RIGHT: + if (event.KeyInput.Shift) + { + if (Text.size() > (u32)CursorPos) + { + if (MarkBegin == MarkEnd) + newMarkBegin = CursorPos; + + newMarkEnd = CursorPos+1; + } + } + else + { + newMarkBegin = 0; + newMarkEnd = 0; + } + + if (Text.size() > (u32)CursorPos) CursorPos++; + BlinkStartTime = os::Timer::getTime(); + break; + case KEY_UP: + if (MultiLine || (WordWrap && BrokenText.size() > 1) ) + { + s32 lineNo = getLineFromPos(CursorPos); + s32 mb = (MarkBegin == MarkEnd) ? CursorPos : (MarkBegin > MarkEnd ? MarkBegin : MarkEnd); + if (lineNo > 0) + { + s32 cp = CursorPos - BrokenTextPositions[lineNo]; + if ((s32)BrokenText[lineNo-1].size() < cp) + CursorPos = BrokenTextPositions[lineNo-1] + core::max_((u32)1, BrokenText[lineNo-1].size())-1; + else + CursorPos = BrokenTextPositions[lineNo-1] + cp; + } + + if (event.KeyInput.Shift) + { + newMarkBegin = mb; + newMarkEnd = CursorPos; + } + else + { + newMarkBegin = 0; + newMarkEnd = 0; + } + + } + else + { + return false; + } + break; + case KEY_DOWN: + if (MultiLine || (WordWrap && BrokenText.size() > 1) ) + { + s32 lineNo = getLineFromPos(CursorPos); + s32 mb = (MarkBegin == MarkEnd) ? CursorPos : (MarkBegin < MarkEnd ? MarkBegin : MarkEnd); + if (lineNo < (s32)BrokenText.size()-1) + { + s32 cp = CursorPos - BrokenTextPositions[lineNo]; + if ((s32)BrokenText[lineNo+1].size() < cp) + CursorPos = BrokenTextPositions[lineNo+1] + core::max_((u32)1, BrokenText[lineNo+1].size())-1; + else + CursorPos = BrokenTextPositions[lineNo+1] + cp; + } + + if (event.KeyInput.Shift) + { + newMarkBegin = mb; + newMarkEnd = CursorPos; + } + else + { + newMarkBegin = 0; + newMarkEnd = 0; + } + + } + else + { + return false; + } + break; + case KEY_INSERT: + if ( !isEnabled() ) + break; + + OverwriteMode = !OverwriteMode; + break; + case KEY_DELETE: + if ( !isEnabled() ) + break; + + if (keyDelete()) + { + BlinkStartTime = os::Timer::getTime(); + newMarkBegin = 0; + newMarkEnd = 0; + textChanged = true; + } + break; + default: + return false; + } + } + else + { + // default keyboard handling + switch(event.KeyInput.Key) + { + case KEY_RETURN: + if (MultiLine) + { + inputChar(L'\n'); + } + else + { + calculateScrollPos(); + sendGuiEvent( EGET_EDITBOX_ENTER ); + } + return true; + + case KEY_BACK: + if ( !isEnabled() ) + break; + + if (Text.size()) + { + core::stringw s; + + if (MarkBegin != MarkEnd) + { + // delete marked text + const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; + const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; + + s = Text.subString(0, realmbgn); + s.append( Text.subString(realmend, Text.size()-realmend) ); + Text = s; + + CursorPos = realmbgn; + } + else + { + // delete text behind cursor + if (CursorPos>0) + s = Text.subString(0, CursorPos-1); + else + s = L""; + s.append( Text.subString(CursorPos, Text.size()-CursorPos) ); + Text = s; + --CursorPos; + } + + if (CursorPos < 0) + CursorPos = 0; + BlinkStartTime = os::Timer::getTime(); + newMarkBegin = 0; + newMarkEnd = 0; + textChanged = true; + } + break; + + case KEY_DELETE: + + // At least on X11 we get a char with 127 when the delete key is pressed. + // We get no char when the delete key on numkeys is pressed with numlock off (handled in the other case calling keyDelete as Char is then 0). + // We get a keykode != 127 when delete key on numlock is pressed with numlock on. + if (event.KeyInput.Char == 127) + { + if ( !isEnabled() ) + break; + + if (keyDelete()) + { + BlinkStartTime = os::Timer::getTime(); + newMarkBegin = 0; + newMarkEnd = 0; + textChanged = true; + } + break; + } + else + { + inputChar(event.KeyInput.Char); + return true; + } + + case KEY_ESCAPE: + case KEY_TAB: + case KEY_SHIFT: + case KEY_F1: + case KEY_F2: + case KEY_F3: + case KEY_F4: + case KEY_F5: + case KEY_F6: + case KEY_F7: + case KEY_F8: + case KEY_F9: + case KEY_F10: + case KEY_F11: + case KEY_F12: + case KEY_F13: + case KEY_F14: + case KEY_F15: + case KEY_F16: + case KEY_F17: + case KEY_F18: + case KEY_F19: + case KEY_F20: + case KEY_F21: + case KEY_F22: + case KEY_F23: + case KEY_F24: + // ignore these keys + return false; + + default: + inputChar(event.KeyInput.Char); + return true; + } + } + + // Set new text markers + setTextMarkers( newMarkBegin, newMarkEnd ); + + // break the text if it has changed + if (textChanged) + { + breakText(); + calculateScrollPos(); + sendGuiEvent(EGET_EDITBOX_CHANGED); + } + else + { + calculateScrollPos(); + } + + return true; +} + +bool CGUIEditBox::keyDelete() +{ + if (Text.size() != 0) + { + core::stringw s; + + if (MarkBegin != MarkEnd) + { + // delete marked text + const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; + const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; + + s = Text.subString(0, realmbgn); + s.append( Text.subString(realmend, Text.size()-realmend) ); + Text = s; + + CursorPos = realmbgn; + } + else + { + // delete text before cursor + s = Text.subString(0, CursorPos); + s.append( Text.subString(CursorPos+1, Text.size()-CursorPos-1) ); + Text = s; + } + + if (CursorPos > (s32)Text.size()) + CursorPos = (s32)Text.size(); + + return true; + } + + return false; +} + +//! draws the element and its children +void CGUIEditBox::draw() +{ + if (!IsVisible) + return; + + const bool focus = Environment->hasFocus(this); + + IGUISkin* skin = Environment->getSkin(); + if (!skin) + return; + + EGUI_DEFAULT_COLOR bgCol = EGDC_GRAY_EDITABLE; + if ( isEnabled() ) + bgCol = focus ? EGDC_FOCUSED_EDITABLE : EGDC_EDITABLE; + + if (!Border && Background) + { + skin->draw2DRectangle(this, skin->getColor(bgCol), AbsoluteRect, &AbsoluteClippingRect); + } + + if (Border) + { + // draw the border + skin->draw3DSunkenPane(this, skin->getColor(bgCol), false, Background, AbsoluteRect, &AbsoluteClippingRect); + + calculateFrameRect(); + } + + core::rect localClipRect = FrameRect; + localClipRect.clipAgainst(AbsoluteClippingRect); + + // draw the text + + IGUIFont* font = getActiveFont(); + + s32 cursorLine = 0; + s32 charcursorpos = 0; + + if (font) + { + if (LastBreakFont != font) + { + breakText(); + } + + // calculate cursor pos + + core::stringw *txtLine = &Text; + s32 startPos = 0; + + core::stringw s, s2; + + // get mark position + const bool ml = (!PasswordBox && (WordWrap || MultiLine)); + const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; + const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; + const s32 hlineStart = ml ? getLineFromPos(realmbgn) : 0; + const s32 hlineCount = ml ? getLineFromPos(realmend) - hlineStart + 1 : 1; + const s32 lineCount = ml ? BrokenText.size() : 1; + + // Save the override color information. + // Then, alter it if the edit box is disabled. + const bool prevOver = OverrideColorEnabled; + const video::SColor prevColor = OverrideColor; + + if (Text.size()) + { + if (!isEnabled() && !OverrideColorEnabled) + { + OverrideColorEnabled = true; + OverrideColor = skin->getColor(EGDC_GRAY_TEXT); + } + + for (s32 i=0; i < lineCount; ++i) + { + setTextRect(i); + + // clipping test - don't draw anything outside the visible area + core::rect c = localClipRect; + c.clipAgainst(CurrentTextRect); + if (!c.isValid()) + continue; + + // get current line + if (PasswordBox) + { + if (BrokenText.size() != 1) + { + BrokenText.clear(); + BrokenText.push_back(core::stringw()); + } + if (BrokenText[0].size() != Text.size()) + { + BrokenText[0] = Text; + for (u32 q = 0; q < Text.size(); ++q) + { + BrokenText[0] [q] = PasswordChar; + } + } + txtLine = &BrokenText[0]; + startPos = 0; + } + else + { + txtLine = ml ? &BrokenText[i] : &Text; + startPos = ml ? BrokenTextPositions[i] : 0; + } + + + // draw normal text + font->draw(txtLine->c_str(), CurrentTextRect, + OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_BUTTON_TEXT), + false, true, &localClipRect); + + // draw mark and marked text + if (focus && MarkBegin != MarkEnd && i >= hlineStart && i < hlineStart + hlineCount) + { + + s32 mbegin = 0, mend = 0; + s32 lineStartPos = 0, lineEndPos = txtLine->size(); + + if (i == hlineStart) + { + // highlight start is on this line + s = txtLine->subString(0, realmbgn - startPos); + mbegin = font->getDimension(s.c_str()).Width; + + // deal with kerning + mbegin += font->getKerningWidth( + &((*txtLine)[realmbgn - startPos]), + realmbgn - startPos > 0 ? &((*txtLine)[realmbgn - startPos - 1]) : 0); + + lineStartPos = realmbgn - startPos; + } + if (i == hlineStart + hlineCount - 1) + { + // highlight end is on this line + s2 = txtLine->subString(0, realmend - startPos); + mend = font->getDimension(s2.c_str()).Width; + lineEndPos = (s32)s2.size(); + } + else + mend = font->getDimension(txtLine->c_str()).Width; + + CurrentTextRect.UpperLeftCorner.X += mbegin; + CurrentTextRect.LowerRightCorner.X = CurrentTextRect.UpperLeftCorner.X + mend - mbegin; + + // draw mark + skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), CurrentTextRect, &localClipRect); + + // draw marked text + s = txtLine->subString(lineStartPos, lineEndPos - lineStartPos); + + if (s.size()) + font->draw(s.c_str(), CurrentTextRect, + OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_HIGH_LIGHT_TEXT), + false, true, &localClipRect); + + } + } + + // Return the override color information to its previous settings. + OverrideColorEnabled = prevOver; + OverrideColor = prevColor; + } + + // draw cursor + if ( isEnabled() ) + { + if (WordWrap || MultiLine) + { + cursorLine = getLineFromPos(CursorPos); + txtLine = &BrokenText[cursorLine]; + startPos = BrokenTextPositions[cursorLine]; + } + s = txtLine->subString(0,CursorPos-startPos); + charcursorpos = font->getDimension(s.c_str()).Width + + font->getKerningWidth(CursorChar.c_str(), CursorPos-startPos > 0 ? &((*txtLine)[CursorPos-startPos-1]) : 0); + + if (focus && (CursorBlinkTime == 0 || (os::Timer::getTime() - BlinkStartTime) % (2*CursorBlinkTime) < CursorBlinkTime)) + { + setTextRect(cursorLine); + CurrentTextRect.UpperLeftCorner.X += charcursorpos; + + if ( OverwriteMode ) + { + core::stringw character = Text.subString(CursorPos,1); + s32 mend = font->getDimension(character.c_str()).Width; + //Make sure the cursor box has at least some width to it + if ( mend <= 0 ) + mend = font->getDimension(CursorChar.c_str()).Width; + CurrentTextRect.LowerRightCorner.X = CurrentTextRect.UpperLeftCorner.X + mend; + skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), CurrentTextRect, &localClipRect); + font->draw(character.c_str(), CurrentTextRect, + OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_HIGH_LIGHT_TEXT), + false, true, &localClipRect); + } + else + { + font->draw(CursorChar, CurrentTextRect, + OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_BUTTON_TEXT), + false, true, &localClipRect); + } + } + } + } + + // draw children + IGUIElement::draw(); +} + + +//! Sets the new caption of this element. +void CGUIEditBox::setText(const wchar_t* text) +{ + Text = text; + if (u32(CursorPos) > Text.size()) + CursorPos = Text.size(); + HScrollPos = 0; + breakText(); +} + + +//! Enables or disables automatic scrolling with cursor position +//! \param enable: If set to true, the text will move around with the cursor position +void CGUIEditBox::setAutoScroll(bool enable) +{ + AutoScroll = enable; +} + + +//! Checks to see if automatic scrolling is enabled +//! \return true if automatic scrolling is enabled, false if not +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::dimension2du CGUIEditBox::getTextDimension() +{ + core::rect ret; + + setTextRect(0); + ret = CurrentTextRect; + + for (u32 i=1; i < BrokenText.size(); ++i) + { + setTextRect(i); + ret.addInternalPoint(CurrentTextRect.UpperLeftCorner); + ret.addInternalPoint(CurrentTextRect.LowerRightCorner); + } + + return core::dimension2du(ret.getSize()); +} + + +//! 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 +//! infinity. +void CGUIEditBox::setMax(u32 max) +{ + Max = max; + + if (Text.size() > Max && Max != 0) + Text = Text.subString(0, Max); +} + + +//! Returns maximum amount of characters, previously set by setMax(); +u32 CGUIEditBox::getMax() const +{ + return Max; +} + +//! Set the character used for the cursor. +/** By default it's "_" */ +void CGUIEditBox::setCursorChar(const wchar_t cursorChar) +{ + CursorChar[0] = cursorChar; +} + +//! Get the character used for the cursor. +wchar_t CGUIEditBox::getCursorChar() const +{ + return CursorChar[0]; +} + +//! Set the blinktime for the cursor. 2x blinktime is one full cycle. +void CGUIEditBox::setCursorBlinkTime(irr::u32 timeMs) +{ + CursorBlinkTime = timeMs; +} + +//! Get the cursor blinktime +irr::u32 CGUIEditBox::getCursorBlinkTime() const +{ + return CursorBlinkTime; +} + +bool CGUIEditBox::processMouse(const SEvent& event) +{ + switch(event.MouseInput.Event) + { + case irr::EMIE_LMOUSE_LEFT_UP: + if (Environment->hasFocus(this)) + { + CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y); + if (MouseMarking) + { + setTextMarkers( MarkBegin, CursorPos ); + } + MouseMarking = false; + calculateScrollPos(); + return true; + } + break; + case irr::EMIE_MOUSE_MOVED: + { + if (MouseMarking) + { + CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y); + setTextMarkers( MarkBegin, CursorPos ); + calculateScrollPos(); + return true; + } + } + break; + case EMIE_LMOUSE_PRESSED_DOWN: + if (!Environment->hasFocus(this)) // can happen when events are manually send to the element + { + BlinkStartTime = os::Timer::getTime(); + MouseMarking = true; + CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y); + setTextMarkers(CursorPos, CursorPos ); + calculateScrollPos(); + return true; + } + else + { + if (!AbsoluteClippingRect.isPointInside( + core::position2d(event.MouseInput.X, event.MouseInput.Y))) + { + return false; + } + else + { + // move cursor + CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y); + + s32 newMarkBegin = MarkBegin; + if (!MouseMarking) + newMarkBegin = CursorPos; + + MouseMarking = true; + setTextMarkers( newMarkBegin, CursorPos); + calculateScrollPos(); + return true; + } + } + default: + break; + } + + return false; +} + + +s32 CGUIEditBox::getCursorPos(s32 x, s32 y) +{ + IGUIFont* font = getActiveFont(); + + const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1; + + core::stringw *txtLine=0; + s32 startPos=0; + x+=3; + + for (u32 i=0; i < lineCount; ++i) + { + setTextRect(i); + if (i == 0 && y < CurrentTextRect.UpperLeftCorner.Y) + y = CurrentTextRect.UpperLeftCorner.Y; + if (i == lineCount - 1 && y > CurrentTextRect.LowerRightCorner.Y ) + y = CurrentTextRect.LowerRightCorner.Y; + + // is it inside this region? + if (y >= CurrentTextRect.UpperLeftCorner.Y && y <= CurrentTextRect.LowerRightCorner.Y) + { + // we've found the clicked line + txtLine = (WordWrap || MultiLine) ? &BrokenText[i] : &Text; + startPos = (WordWrap || MultiLine) ? BrokenTextPositions[i] : 0; + break; + } + } + + if (x < CurrentTextRect.UpperLeftCorner.X) + x = CurrentTextRect.UpperLeftCorner.X; + + if ( !txtLine ) + return 0; + + s32 idx = font->getCharacterFromPos(txtLine->c_str(), x - CurrentTextRect.UpperLeftCorner.X); + + // click was on or left of the line + if (idx != -1) + return idx + startPos; + + // click was off the right edge of the line, go to end. + return txtLine->size() + startPos; +} + + +//! Breaks the single text line. +void CGUIEditBox::breakText() +{ + if ((!WordWrap && !MultiLine)) + return; + + BrokenText.clear(); // need to reallocate :/ + BrokenTextPositions.set_used(0); + + IGUIFont* font = getActiveFont(); + if (!font) + return; + + LastBreakFont = font; + + core::stringw line; + core::stringw word; + core::stringw whitespace; + s32 lastLineStart = 0; + s32 size = Text.size(); + s32 length = 0; + s32 elWidth = RelativeRect.getWidth() - 6; + wchar_t c; + + for (s32 i=0; i i ) + --CursorPos; + } + } + else if (c == L'\n') // Unix breaks + { + lineBreak = true; + c = 0; + } + + // don't break if we're not a multi-line edit box + if (!MultiLine) + lineBreak = false; + + if (c == L' ' || c == 0 || i == (size-1)) + { + // here comes the next whitespace, look if + // we can break the last word to the next line + // We also break whitespace, otherwise cursor would vanish beside the right border. + s32 whitelgth = font->getDimension(whitespace.c_str()).Width; + s32 worldlgth = font->getDimension(word.c_str()).Width; + + if (WordWrap && length + worldlgth + whitelgth > elWidth && line.size() > 0) + { + // break to next line + length = worldlgth; + BrokenText.push_back(line); + BrokenTextPositions.push_back(lastLineStart); + lastLineStart = i - (s32)word.size(); + line = word; + } + else + { + // add word to line + line += whitespace; + line += word; + length += whitelgth + worldlgth; + } + + word = L""; + whitespace = L""; + + + if ( c ) + whitespace += c; + + // compute line break + if (lineBreak) + { + line += whitespace; + line += word; + BrokenText.push_back(line); + BrokenTextPositions.push_back(lastLineStart); + lastLineStart = i+1; + line = L""; + word = L""; + whitespace = L""; + length = 0; + } + } + else + { + // yippee this is a word.. + word += c; + } + } + + line += whitespace; + line += word; + BrokenText.push_back(line); + BrokenTextPositions.push_back(lastLineStart); +} + +// TODO: that function does interpret VAlign according to line-index (indexed line is placed on top-center-bottom) +// but HAlign according to line-width (pixels) and not by row. +// Intuitively I suppose HAlign handling is better as VScrollPos should handle the line-scrolling. +// But please no one change this without also rewriting (and this time fucking testing!!!) autoscrolling (I noticed this when fixing the old autoscrolling). +void CGUIEditBox::setTextRect(s32 line) +{ + if ( line < 0 ) + return; + + IGUIFont* font = getActiveFont(); + if (!font) + return; + + core::dimension2du d; + + // get text dimension + const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1; + if (WordWrap || MultiLine) + { + d = font->getDimension(BrokenText[line].c_str()); + } + else + { + d = font->getDimension(Text.c_str()); + d.Height = AbsoluteRect.getHeight(); + } + d.Height += font->getKerningHeight(); + + // justification + switch (HAlign) + { + case EGUIA_CENTER: + // align to h centre + CurrentTextRect.UpperLeftCorner.X = (FrameRect.getWidth()/2) - (d.Width/2); + CurrentTextRect.LowerRightCorner.X = (FrameRect.getWidth()/2) + (d.Width/2); + break; + case EGUIA_LOWERRIGHT: + // align to right edge + CurrentTextRect.UpperLeftCorner.X = FrameRect.getWidth() - d.Width; + CurrentTextRect.LowerRightCorner.X = FrameRect.getWidth(); + break; + default: + // align to left edge + CurrentTextRect.UpperLeftCorner.X = 0; + CurrentTextRect.LowerRightCorner.X = d.Width; + + } + + switch (VAlign) + { + case EGUIA_CENTER: + // align to v centre + CurrentTextRect.UpperLeftCorner.Y = + (FrameRect.getHeight()/2) - (lineCount*d.Height)/2 + d.Height*line; + break; + case EGUIA_LOWERRIGHT: + // align to bottom edge + CurrentTextRect.UpperLeftCorner.Y = + FrameRect.getHeight() - lineCount*d.Height + d.Height*line; + break; + default: + // align to top edge + CurrentTextRect.UpperLeftCorner.Y = d.Height*line; + break; + } + + CurrentTextRect.UpperLeftCorner.X -= HScrollPos; + CurrentTextRect.LowerRightCorner.X -= HScrollPos; + CurrentTextRect.UpperLeftCorner.Y -= VScrollPos; + CurrentTextRect.LowerRightCorner.Y = CurrentTextRect.UpperLeftCorner.Y + d.Height; + + CurrentTextRect += FrameRect.UpperLeftCorner; + +} + + +s32 CGUIEditBox::getLineFromPos(s32 pos) +{ + if (!WordWrap && !MultiLine) + return 0; + + s32 i=0; + while (i < (s32)BrokenTextPositions.size()) + { + if (BrokenTextPositions[i] > pos) + return i-1; + ++i; + } + return (s32)BrokenTextPositions.size() - 1; +} + + +void CGUIEditBox::inputChar(wchar_t c) +{ + if (!isEnabled()) + return; + + if (c != 0) + { + { + core::stringw s; + + if (MarkBegin != MarkEnd) + { + // replace marked text + const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd; + const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; + + s = Text.subString(0, realmbgn); + s.append(c); + s.append( Text.subString(realmend, Text.size()-realmend) ); + Text = s; + CursorPos = realmbgn+1; + } + else if ( OverwriteMode ) + { + //check to see if we are at the end of the text + if ( (u32)CursorPos != Text.size()) + { + bool isEOL = (Text[CursorPos] == L'\n' ||Text[CursorPos] == L'\r' ); + if (!isEOL || Text.size() < Max || Max == 0) + { + s = Text.subString(0, CursorPos); + s.append(c); + if ( isEOL ) + { + //just keep appending to the current line + //This follows the behavior of other gui libraries behaviors + s.append( Text.subString(CursorPos, Text.size()-CursorPos) ); + } + else + { + //replace the next character + s.append( Text.subString(CursorPos + 1,Text.size() - CursorPos + 1)); + } + Text = s; + ++CursorPos; + } + } + else if (Text.size() < Max || Max == 0) + { + // add new character because we are at the end of the string + s = Text.subString(0, CursorPos); + s.append(c); + s.append( Text.subString(CursorPos, Text.size()-CursorPos) ); + Text = s; + ++CursorPos; + } + } + else if (Text.size() < Max || Max == 0) + { + // add new character + s = Text.subString(0, CursorPos); + s.append(c); + s.append( Text.subString(CursorPos, Text.size()-CursorPos) ); + Text = s; + ++CursorPos; + } + + BlinkStartTime = os::Timer::getTime(); + setTextMarkers(0, 0); + } + } + breakText(); + calculateScrollPos(); + sendGuiEvent(EGET_EDITBOX_CHANGED); +} + +// calculate autoscroll +void CGUIEditBox::calculateScrollPos() +{ + if (!AutoScroll) + return; + + IGUIFont* font = getActiveFont(); + if (!font) + return; + + s32 cursLine = getLineFromPos(CursorPos); + if ( cursLine < 0 ) + return; + setTextRect(cursLine); + const bool hasBrokenText = MultiLine || WordWrap; + + // Check horizonal scrolling + // NOTE: Calculations different to vertical scrolling because setTextRect interprets VAlign relative to line but HAlign not relative to row + { + // get cursor position + // get cursor area + irr::u32 cursorWidth = font->getDimension(CursorChar.c_str()).Width; + core::stringw *txtLine = hasBrokenText ? &BrokenText[cursLine] : &Text; + s32 cPos = hasBrokenText ? CursorPos - BrokenTextPositions[cursLine] : CursorPos; // column + s32 cStart = font->getDimension(txtLine->subString(0, cPos).c_str()).Width; // pixels from text-start + s32 cEnd = cStart + cursorWidth; + s32 txtWidth = font->getDimension(txtLine->c_str()).Width; + + if ( txtWidth < FrameRect.getWidth() ) + { + // TODO: Needs a clean left and right gap removal depending on HAlign, similar to vertical scrolling tests for top/bottom. + // This check just fixes the case where it was most noticable (text smaller than clipping area). + + HScrollPos = 0; + setTextRect(cursLine); + } + + if ( CurrentTextRect.UpperLeftCorner.X+cStart < FrameRect.UpperLeftCorner.X ) + { + // cursor to the left of the clipping area + HScrollPos -= FrameRect.UpperLeftCorner.X-(CurrentTextRect.UpperLeftCorner.X+cStart); + setTextRect(cursLine); + + // TODO: should show more characters to the left when we're scrolling left + // and the cursor reaches the border. + } + else if ( CurrentTextRect.UpperLeftCorner.X+cEnd > FrameRect.LowerRightCorner.X) + { + // cursor to the right of the clipping area + HScrollPos += (CurrentTextRect.UpperLeftCorner.X+cEnd)-FrameRect.LowerRightCorner.X; + setTextRect(cursLine); + } + } + + // calculate vertical scrolling + if (hasBrokenText) + { + irr::u32 lineHeight = font->getDimension(L"A").Height + font->getKerningHeight(); + // only up to 1 line fits? + if ( lineHeight >= (irr::u32)FrameRect.getHeight() ) + { + VScrollPos = 0; + setTextRect(cursLine); + s32 unscrolledPos = CurrentTextRect.UpperLeftCorner.Y; + s32 pivot = FrameRect.UpperLeftCorner.Y; + switch (VAlign) + { + case EGUIA_CENTER: + pivot += FrameRect.getHeight()/2; + unscrolledPos += lineHeight/2; + break; + case EGUIA_LOWERRIGHT: + pivot += FrameRect.getHeight(); + unscrolledPos += lineHeight; + break; + default: + break; + } + VScrollPos = unscrolledPos-pivot; + setTextRect(cursLine); + } + else + { + // First 2 checks are necessary when people delete lines + setTextRect(0); + if ( CurrentTextRect.UpperLeftCorner.Y > FrameRect.UpperLeftCorner.Y && VAlign != EGUIA_LOWERRIGHT) + { + // first line is leaving a gap on top + VScrollPos = 0; + } + else if (VAlign != EGUIA_UPPERLEFT) + { + u32 lastLine = BrokenTextPositions.empty() ? 0 : BrokenTextPositions.size()-1; + setTextRect(lastLine); + if ( CurrentTextRect.LowerRightCorner.Y < FrameRect.LowerRightCorner.Y) + { + // last line is leaving a gap on bottom + VScrollPos -= FrameRect.LowerRightCorner.Y-CurrentTextRect.LowerRightCorner.Y; + } + } + + setTextRect(cursLine); + if ( CurrentTextRect.UpperLeftCorner.Y < FrameRect.UpperLeftCorner.Y ) + { + // text above valid area + VScrollPos -= FrameRect.UpperLeftCorner.Y-CurrentTextRect.UpperLeftCorner.Y; + setTextRect(cursLine); + } + else if ( CurrentTextRect.LowerRightCorner.Y > FrameRect.LowerRightCorner.Y) + { + // text below valid area + VScrollPos += CurrentTextRect.LowerRightCorner.Y-FrameRect.LowerRightCorner.Y; + setTextRect(cursLine); + } + } + } +} + +void CGUIEditBox::calculateFrameRect() +{ + FrameRect = AbsoluteRect; + IGUISkin *skin = 0; + if (Environment) + skin = Environment->getSkin(); + if (Border && skin) + { + FrameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X)+1; + FrameRect.UpperLeftCorner.Y += skin->getSize(EGDS_TEXT_DISTANCE_Y)+1; + FrameRect.LowerRightCorner.X -= skin->getSize(EGDS_TEXT_DISTANCE_X)+1; + FrameRect.LowerRightCorner.Y -= skin->getSize(EGDS_TEXT_DISTANCE_Y)+1; + } +} + +//! set text markers +void CGUIEditBox::setTextMarkers(s32 begin, s32 end) +{ + if ( begin != MarkBegin || end != MarkEnd ) + { + MarkBegin = begin; + MarkEnd = end; + sendGuiEvent(EGET_EDITBOX_MARKING_CHANGED); + } +} + +//! send some gui event to parent +void CGUIEditBox::sendGuiEvent(EGUI_EVENT_TYPE type) +{ + if ( Parent ) + { + SEvent e; + e.EventType = EET_GUI_EVENT; + e.GUIEvent.Caller = this; + e.GUIEvent.Element = 0; + e.GUIEvent.EventType = type; + + Parent->OnEvent(e); + } +} + +//! Writes attributes of the element. +void CGUIEditBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const +{ + // IGUIEditBox::serializeAttributes(out,options); + + out->addBool ("Border", Border); + out->addBool ("Background", Background); + out->addBool ("OverrideColorEnabled", OverrideColorEnabled ); + out->addColor ("OverrideColor", OverrideColor); + // out->addFont("OverrideFont", OverrideFont); + out->addInt ("MaxChars", Max); + out->addBool ("WordWrap", WordWrap); + out->addBool ("MultiLine", MultiLine); + out->addBool ("AutoScroll", AutoScroll); + out->addBool ("PasswordBox", PasswordBox); + core::stringw ch = L" "; + ch[0] = PasswordChar; + out->addString("PasswordChar", ch.c_str()); + out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames); + out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames); + + IGUIEditBox::serializeAttributes(out,options); +} + + +//! Reads attributes of the element +void CGUIEditBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) +{ + IGUIEditBox::deserializeAttributes(in,options); + + setDrawBorder( in->getAttributeAsBool("Border", Border) ); + setDrawBackground( in->getAttributeAsBool("Background", Background) ); + setOverrideColor(in->getAttributeAsColor("OverrideColor", OverrideColor)); + enableOverrideColor(in->getAttributeAsBool("OverrideColorEnabled", OverrideColorEnabled)); + setMax(in->getAttributeAsInt("MaxChars", Max)); + setWordWrap(in->getAttributeAsBool("WordWrap", WordWrap)); + setMultiLine(in->getAttributeAsBool("MultiLine", MultiLine)); + setAutoScroll(in->getAttributeAsBool("AutoScroll", AutoScroll)); + core::stringw ch = L" "; + ch[0] = PasswordChar; + ch = in->getAttributeAsStringW("PasswordChar", ch); + + if (!ch.size()) + setPasswordBox(in->getAttributeAsBool("PasswordBox", PasswordBox)); + else + setPasswordBox(in->getAttributeAsBool("PasswordBox", PasswordBox), ch[0]); + + setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames, (s32)HAlign), + (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames, (s32)VAlign)); + + // setOverrideFont(in->getAttributeAsFont("OverrideFont")); +} + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIEditBox.h b/source/Irrlicht/CGUIEditBox.h new file mode 100644 index 00000000..f251e5ec --- /dev/null +++ b/source/Irrlicht/CGUIEditBox.h @@ -0,0 +1,207 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_EDIT_BOX_H_INCLUDED__ +#define __C_GUI_EDIT_BOX_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIEditBox.h" +#include "irrArray.h" +#include "IOSOperator.h" + +namespace irr +{ +namespace gui +{ + class CGUIEditBox : public IGUIEditBox + { + public: + + //! constructor + CGUIEditBox(const wchar_t* text, bool border, IGUIEnvironment* environment, + IGUIElement* parent, s32 id, const core::rect& rectangle); + + //! destructor + virtual ~CGUIEditBox(); + + //! Sets another skin independent font. + virtual void setOverrideFont(IGUIFont* font=0) _IRR_OVERRIDE_; + + //! Gets the override font (if any) + /** \return The override font (may be 0) */ + virtual IGUIFont* getOverrideFont() const _IRR_OVERRIDE_; + + //! Get the font which is used right now for drawing + /** Currently this is the override font when one is set and the + font of the active skin otherwise */ + virtual IGUIFont* getActiveFont() const _IRR_OVERRIDE_; + + //! Sets another color for the text. + virtual void setOverrideColor(video::SColor color) _IRR_OVERRIDE_; + + //! Gets the override color + virtual video::SColor getOverrideColor() const _IRR_OVERRIDE_; + + //! Sets if the text should use the override color or the + //! color in the gui skin. + virtual void enableOverrideColor(bool enable) _IRR_OVERRIDE_; + + //! Checks if an override color is enabled + /** \return true if the override color is enabled, false otherwise */ + virtual bool isOverrideColorEnabled(void) const _IRR_OVERRIDE_; + + //! Sets whether to draw the background + virtual void setDrawBackground(bool draw) _IRR_OVERRIDE_; + + //! Checks if background drawing is enabled + virtual bool isDrawBackgroundEnabled() const _IRR_OVERRIDE_; + + //! Turns the border on or off + virtual void setDrawBorder(bool border) _IRR_OVERRIDE_; + + //! Checks if border drawing is enabled + virtual bool isDrawBorderEnabled() const _IRR_OVERRIDE_; + + //! Enables or disables word wrap for using the edit box as multiline text editor. + virtual void setWordWrap(bool enable) _IRR_OVERRIDE_; + + //! Checks if word wrap is enabled + //! \return true if word wrap is enabled, false otherwise + virtual bool isWordWrapEnabled() const _IRR_OVERRIDE_; + + //! Enables or disables newlines. + /** \param enable: If set to true, the EGET_EDITBOX_ENTER event will not be fired, + instead a newline character will be inserted. */ + virtual void setMultiLine(bool enable) _IRR_OVERRIDE_; + + //! Checks if multi line editing is enabled + //! \return true if mult-line is enabled, false otherwise + virtual bool isMultiLineEnabled() const _IRR_OVERRIDE_; + + //! Enables or disables automatic scrolling with cursor position + //! \param enable: If set to true, the text will move around with the cursor position + virtual void setAutoScroll(bool enable) _IRR_OVERRIDE_; + + //! Checks to see if automatic scrolling is enabled + //! \return true if automatic scrolling is enabled, false if not + virtual bool isAutoScrollEnabled() const _IRR_OVERRIDE_; + + //! Gets the size area of the text in the edit box + //! \return Returns the size in pixels of the text + virtual core::dimension2du getTextDimension() _IRR_OVERRIDE_; + + //! Sets text justification + virtual void setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical) _IRR_OVERRIDE_; + + //! called if an event happened. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + //! Sets the new caption of this element. + virtual void setText(const wchar_t* text) _IRR_OVERRIDE_; + + //! 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 + //! infinity. + virtual void setMax(u32 max) _IRR_OVERRIDE_; + + //! Returns maximum amount of characters, previously set by setMax(); + virtual u32 getMax() const _IRR_OVERRIDE_; + + //! Set the character used for the cursor. + /** By default it's "_" */ + virtual void setCursorChar(const wchar_t cursorChar) _IRR_OVERRIDE_; + + //! Get the character used for the cursor. + virtual wchar_t getCursorChar() const _IRR_OVERRIDE_; + + //! Set the blinktime for the cursor. 2x blinktime is one full cycle. + //** \param timeMs Blinktime in milliseconds. When set to 0 the cursor is constantly on without blinking */ + virtual void setCursorBlinkTime(irr::u32 timeMs) _IRR_OVERRIDE_; + + //! Get the cursor blinktime + virtual irr::u32 getCursorBlinkTime() const _IRR_OVERRIDE_; + + //! 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 */ + virtual void setPasswordBox(bool passwordBox, wchar_t passwordChar = L'*') _IRR_OVERRIDE_; + + //! Returns true if the edit box is currently a password box. + virtual bool isPasswordBox() const _IRR_OVERRIDE_; + + //! Updates the absolute position, splits text if required + virtual void updateAbsolutePosition() _IRR_OVERRIDE_; + + //! Writes attributes of the element. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the element + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + + protected: + //! Breaks the single text line. + void breakText(); + //! sets the area of the given line + void setTextRect(s32 line); + //! returns the line number that the cursor is on + s32 getLineFromPos(s32 pos); + //! adds a letter to the edit box + void inputChar(wchar_t c); + //! calculates the current scroll position + void calculateScrollPos(); + //! calculated the FrameRect + void calculateFrameRect(); + //! send some gui event to parent + void sendGuiEvent(EGUI_EVENT_TYPE type); + //! set text markers + void setTextMarkers(s32 begin, s32 end); + //! delete current selection or next char + bool keyDelete(); + + bool processKey(const SEvent& event); + bool processMouse(const SEvent& event); + s32 getCursorPos(s32 x, s32 y); + + bool OverwriteMode; + bool MouseMarking; + bool Border; + bool Background; + bool OverrideColorEnabled; + s32 MarkBegin; + s32 MarkEnd; + + video::SColor OverrideColor; + gui::IGUIFont *OverrideFont, *LastBreakFont; + IOSOperator* Operator; + + u32 BlinkStartTime; + irr::u32 CursorBlinkTime; + core::stringw CursorChar; // IGUIFont::draw needs stringw instead of wchar_t + s32 CursorPos; + s32 HScrollPos, VScrollPos; // scroll position in characters + u32 Max; + + bool WordWrap, MultiLine, AutoScroll, PasswordBox; + wchar_t PasswordChar; + EGUI_ALIGNMENT HAlign, VAlign; + + core::array< core::stringw > BrokenText; + core::array< s32 > BrokenTextPositions; + + core::rect CurrentTextRect, FrameRect; // temporary values + }; + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ +#endif // __C_GUI_EDIT_BOX_H_INCLUDED__ + diff --git a/source/Irrlicht/CGUIEnvironment.cpp b/source/Irrlicht/CGUIEnvironment.cpp new file mode 100644 index 00000000..e29195b2 --- /dev/null +++ b/source/Irrlicht/CGUIEnvironment.cpp @@ -0,0 +1,1693 @@ + +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUIEnvironment.h" + +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IVideoDriver.h" + +#include "CGUISkin.h" +#include "CGUIButton.h" +#include "CGUIWindow.h" +#include "CGUIScrollBar.h" +#include "CGUIFont.h" +#include "CGUISpriteBank.h" +#include "CGUIImage.h" +#include "CGUIMeshViewer.h" +#include "CGUICheckBox.h" +#include "CGUIListBox.h" +#include "CGUITreeView.h" +#include "CGUIImageList.h" +#include "CGUIFileOpenDialog.h" +#include "CGUIColorSelectDialog.h" +#include "CGUIStaticText.h" +#include "CGUIEditBox.h" +#include "CGUISpinBox.h" +#include "CGUIInOutFader.h" +#include "CGUIMessageBox.h" +#include "CGUIModalScreen.h" +#include "CGUITabControl.h" +#include "CGUIContextMenu.h" +#include "CGUIComboBox.h" +#include "CGUIMenu.h" +#include "CGUIToolBar.h" +#include "CGUITable.h" +#include "CGUIProfiler.h" + +#include "CDefaultGUIElementFactory.h" +#include "IWriteFile.h" +#include "IXMLWriter.h" + +#include "BuiltInFont.h" +#include "os.h" + +namespace irr +{ +namespace gui +{ + +const wchar_t IRR_XML_FORMAT_GUI_ENV[] = L"irr_gui"; +const wchar_t IRR_XML_FORMAT_GUI_ELEMENT[] = L"element"; +const wchar_t IRR_XML_FORMAT_GUI_ELEMENT_ATTR_TYPE[] = L"type"; + +const io::path CGUIEnvironment::DefaultFontName = "#DefaultFont"; + +//! constructor +CGUIEnvironment::CGUIEnvironment(io::IFileSystem* fs, video::IVideoDriver* driver, IOSOperator* op) +: IGUIElement(EGUIET_ROOT, 0, 0, 0, core::rect(driver ? core::dimension2d(driver->getScreenSize()) : core::dimension2d(0,0))), + Driver(driver), Hovered(0), HoveredNoSubelement(0), Focus(0), LastHoveredMousePos(0,0), CurrentSkin(0), + FileSystem(fs), UserReceiver(0), Operator(op), FocusFlags(EFF_SET_ON_LMOUSE_DOWN|EFF_SET_ON_TAB) +{ + if (Driver) + Driver->grab(); + + if (FileSystem) + FileSystem->grab(); + + if (Operator) + Operator->grab(); + + #ifdef _DEBUG + IGUIEnvironment::setDebugName("CGUIEnvironment"); + #endif + + // gui factory + IGUIElementFactory* factory = new CDefaultGUIElementFactory(this); + registerGUIElementFactory(factory); + factory->drop(); + + loadBuiltInFont(); + + IGUISkin* skin = createSkin( gui::EGST_WINDOWS_METALLIC ); + setSkin(skin); + skin->drop(); + + //set tooltip default + ToolTip.LastTime = 0; + ToolTip.EnterTime = 0; + ToolTip.LaunchTime = 1000; + ToolTip.RelaunchTime = 500; + ToolTip.Element = 0; + + // environment is root tab group + Environment = this; + setTabGroup(true); +} + + +//! destructor +CGUIEnvironment::~CGUIEnvironment() +{ + if ( HoveredNoSubelement && HoveredNoSubelement != this ) + { + HoveredNoSubelement->drop(); + HoveredNoSubelement = 0; + } + + if (Hovered && Hovered != this) + { + Hovered->drop(); + Hovered = 0; + } + + if (Focus) + { + Focus->drop(); + Focus = 0; + } + + if (ToolTip.Element) + { + ToolTip.Element->drop(); + ToolTip.Element = 0; + } + + // drop skin + if (CurrentSkin) + { + CurrentSkin->drop(); + CurrentSkin = 0; + } + + u32 i; + + // delete all sprite banks + for (i=0; idrop(); + + // delete all fonts + for (i=0; idrop(); + + // remove all factories + for (i=0; idrop(); + + if (Operator) + { + Operator->drop(); + Operator = 0; + } + + if (FileSystem) + { + FileSystem->drop(); + FileSystem = 0; + } + + if (Driver) + { + Driver->drop(); + Driver = 0; + } +} + + +void CGUIEnvironment::loadBuiltInFont() +{ + io::IReadFile* file = FileSystem->createMemoryReadFile(BuiltInFontData, + BuiltInFontDataSize, DefaultFontName, false); + + CGUIFont* font = new CGUIFont(this, DefaultFontName ); + if (!font->load(file)) + { + os::Printer::log("Error: Could not load built-in Font. Did you compile without the BMP loader?", ELL_ERROR); + font->drop(); + file->drop(); + return; + } + + SFont f; + f.NamedPath.setPath(DefaultFontName); + f.Font = font; + Fonts.push_back(f); + + file->drop(); +} + + +//! draws all gui elements +void CGUIEnvironment::drawAll() +{ + if (Driver) + { + core::dimension2d dim(Driver->getScreenSize()); + if (AbsoluteRect.LowerRightCorner.X != dim.Width || + AbsoluteRect.LowerRightCorner.Y != dim.Height) + { + // resize gui environment + DesiredRect.LowerRightCorner = dim; + AbsoluteClippingRect = DesiredRect; + AbsoluteRect = DesiredRect; + updateAbsolutePosition(); + } + } + + // make sure tooltip is always on top + if (ToolTip.Element) + bringToFront(ToolTip.Element); + + draw(); + OnPostRender ( os::Timer::getTime () ); +} + + +//! sets the focus to an element +bool CGUIEnvironment::setFocus(IGUIElement* element) +{ + if (Focus == element) + { + return false; + } + + // GUI Environment should just reset the focus to 0 + if (element == this) + element = 0; + + // stop element from being deleted + if (element) + element->grab(); + + // focus may change or be removed in this call + IGUIElement *currentFocus = 0; + if (Focus) + { + currentFocus = Focus; + currentFocus->grab(); + SEvent e; + e.EventType = EET_GUI_EVENT; + e.GUIEvent.Caller = Focus; + e.GUIEvent.Element = element; + e.GUIEvent.EventType = EGET_ELEMENT_FOCUS_LOST; + if (Focus->OnEvent(e)) + { + if (element) + element->drop(); + currentFocus->drop(); + return false; + } + currentFocus->drop(); + currentFocus = 0; + } + + if (element) + { + currentFocus = Focus; + if (currentFocus) + currentFocus->grab(); + + // send focused event + SEvent e; + e.EventType = EET_GUI_EVENT; + e.GUIEvent.Caller = element; + e.GUIEvent.Element = Focus; + e.GUIEvent.EventType = EGET_ELEMENT_FOCUSED; + if (element->OnEvent(e)) + { + if (element) + element->drop(); + if (currentFocus) + currentFocus->drop(); + return false; + } + } + + if (currentFocus) + currentFocus->drop(); + + if (Focus) + Focus->drop(); + + // element is the new focus so it doesn't have to be dropped + Focus = element; + + return true; +} + + +//! returns the element with the focus +IGUIElement* CGUIEnvironment::getFocus() const +{ + return Focus; +} + +//! returns the element last known to be under the mouse cursor +IGUIElement* CGUIEnvironment::getHovered() const +{ + return Hovered; +} + + +//! removes the focus from an element +bool CGUIEnvironment::removeFocus(IGUIElement* element) +{ + if (Focus && Focus==element) + { + SEvent e; + e.EventType = EET_GUI_EVENT; + e.GUIEvent.Caller = Focus; + e.GUIEvent.Element = 0; + e.GUIEvent.EventType = EGET_ELEMENT_FOCUS_LOST; + if (Focus->OnEvent(e)) + { + return false; + } + } + if (Focus) + { + Focus->drop(); + Focus = 0; + } + + return true; +} + + +//! Returns whether the element has focus +bool CGUIEnvironment::hasFocus(const IGUIElement* element, bool checkSubElements) const +{ + if (element == Focus) + return true; + + if ( !checkSubElements || !element ) + return false; + + IGUIElement* f = Focus; + while ( f && f->isSubElement() ) + { + f = f->getParent(); + if ( f == element ) + return true; + } + return false; +} + + +//! returns the current video driver +video::IVideoDriver* CGUIEnvironment::getVideoDriver() const +{ + return Driver; +} + + +//! returns the current file system +io::IFileSystem* CGUIEnvironment::getFileSystem() const +{ + return FileSystem; +} + + +//! returns a pointer to the OS operator +IOSOperator* CGUIEnvironment::getOSOperator() const +{ + return Operator; +} + + +//! clear all GUI elements +void CGUIEnvironment::clear() +{ + // Remove the focus + if (Focus) + { + Focus->drop(); + Focus = 0; + } + + if (Hovered && Hovered != this) + { + Hovered->drop(); + Hovered = 0; + } + if ( HoveredNoSubelement && HoveredNoSubelement != this) + { + HoveredNoSubelement->drop(); + HoveredNoSubelement = 0; + } + + // get the root's children in case the root changes in future + const core::list& children = getRootGUIElement()->getChildren(); + + while (!children.empty()) + (*children.getLast())->remove(); +} + + +//! called by ui if an event happened. +bool CGUIEnvironment::OnEvent(const SEvent& event) +{ + + bool ret = false; + if (UserReceiver + && (event.EventType != EET_MOUSE_INPUT_EVENT) + && (event.EventType != EET_KEY_INPUT_EVENT) + && (event.EventType != EET_GUI_EVENT || event.GUIEvent.Caller != this)) + { + ret = UserReceiver->OnEvent(event); + } + + return ret; +} + +// +void CGUIEnvironment::OnPostRender( u32 time ) +{ + // launch tooltip + if ( ToolTip.Element == 0 && + HoveredNoSubelement && HoveredNoSubelement != this && + (time - ToolTip.EnterTime >= ToolTip.LaunchTime + || (time - ToolTip.LastTime >= ToolTip.RelaunchTime && time - ToolTip.LastTime < ToolTip.LaunchTime)) && + HoveredNoSubelement->getToolTipText().size() && + getSkin() && + getSkin()->getFont(EGDF_TOOLTIP) + ) + { + core::rect pos; + + pos.UpperLeftCorner = LastHoveredMousePos; + core::dimension2du dim = getSkin()->getFont(EGDF_TOOLTIP)->getDimension(HoveredNoSubelement->getToolTipText().c_str()); + dim.Width += getSkin()->getSize(EGDS_TEXT_DISTANCE_X)*2; + dim.Height += getSkin()->getSize(EGDS_TEXT_DISTANCE_Y)*2; + + pos.UpperLeftCorner.Y -= dim.Height+1; + pos.LowerRightCorner.Y = pos.UpperLeftCorner.Y + dim.Height-1; + pos.LowerRightCorner.X = pos.UpperLeftCorner.X + dim.Width; + + pos.constrainTo(getAbsolutePosition()); + + ToolTip.Element = addStaticText(HoveredNoSubelement->getToolTipText().c_str(), pos, true, true, this, -1, true); + ToolTip.Element->setOverrideColor(getSkin()->getColor(EGDC_TOOLTIP)); + ToolTip.Element->setBackgroundColor(getSkin()->getColor(EGDC_TOOLTIP_BACKGROUND)); + ToolTip.Element->setOverrideFont(getSkin()->getFont(EGDF_TOOLTIP)); + ToolTip.Element->setSubElement(true); + ToolTip.Element->grab(); + + s32 textHeight = ToolTip.Element->getTextHeight(); + pos = ToolTip.Element->getRelativePosition(); + pos.LowerRightCorner.Y = pos.UpperLeftCorner.Y + textHeight; + ToolTip.Element->setRelativePosition(pos); + } + + if (ToolTip.Element && ToolTip.Element->isVisible() ) // (isVisible() check only because we might use visibility for ToolTip one day) + { + ToolTip.LastTime = time; + + // got invisible or removed in the meantime? + if ( !HoveredNoSubelement || + !HoveredNoSubelement->isVisible() || + !HoveredNoSubelement->getParent() + ) // got invisible or removed in the meantime? + { + ToolTip.Element->remove(); + ToolTip.Element->drop(); + ToolTip.Element = 0; + } + } + + IGUIElement::OnPostRender ( time ); +} + + +// +void CGUIEnvironment::updateHoveredElement(core::position2d mousePos) +{ + IGUIElement* lastHovered = Hovered; + IGUIElement* lastHoveredNoSubelement = HoveredNoSubelement; + LastHoveredMousePos = mousePos; + + Hovered = getElementFromPoint(mousePos); + + if ( ToolTip.Element && Hovered == ToolTip.Element ) + { + // When the mouse is over the ToolTip we remove that so it will be re-created at a new position. + // Note that ToolTip.EnterTime does not get changed here, so it will be re-created at once. + ToolTip.Element->remove(); + ToolTip.Element->drop(); + ToolTip.Element = 0; + + // Get the real Hovered + Hovered = getElementFromPoint(mousePos); + } + + // for tooltips we want the element itself and not some of it's subelements + HoveredNoSubelement = Hovered; + while ( HoveredNoSubelement && HoveredNoSubelement->isSubElement() ) + { + HoveredNoSubelement = HoveredNoSubelement->getParent(); + } + + if (Hovered && Hovered != this) + Hovered->grab(); + if ( HoveredNoSubelement && HoveredNoSubelement != this) + HoveredNoSubelement->grab(); + + if (Hovered != lastHovered) + { + SEvent event; + event.EventType = EET_GUI_EVENT; + + if (lastHovered) + { + event.GUIEvent.Caller = lastHovered; + event.GUIEvent.Element = 0; + event.GUIEvent.EventType = EGET_ELEMENT_LEFT; + lastHovered->OnEvent(event); + } + + if ( Hovered ) + { + event.GUIEvent.Caller = Hovered; + event.GUIEvent.Element = Hovered; + event.GUIEvent.EventType = EGET_ELEMENT_HOVERED; + Hovered->OnEvent(event); + } + } + + if ( lastHoveredNoSubelement != HoveredNoSubelement ) + { + if (ToolTip.Element) + { + ToolTip.Element->remove(); + ToolTip.Element->drop(); + ToolTip.Element = 0; + } + + if ( HoveredNoSubelement ) + { + u32 now = os::Timer::getTime(); + ToolTip.EnterTime = now; + } + } + + if (lastHovered && lastHovered != this) + lastHovered->drop(); + if (lastHoveredNoSubelement && lastHoveredNoSubelement != this) + lastHoveredNoSubelement->drop(); +} + + +//! This sets a new event receiver for gui events. Usually you do not have to +//! use this method, it is used by the internal engine. +void CGUIEnvironment::setUserEventReceiver(IEventReceiver* evr) +{ + UserReceiver = evr; +} + + +//! posts an input event to the environment +bool CGUIEnvironment::postEventFromUser(const SEvent& event) +{ + switch(event.EventType) + { + case EET_GUI_EVENT: + { + // hey, why is the user sending gui events..? + } + + break; + case EET_MOUSE_INPUT_EVENT: + + updateHoveredElement(core::position2d(event.MouseInput.X, event.MouseInput.Y)); + + if ( Hovered != Focus ) + { + IGUIElement * focusCandidate = Hovered; + + // Only allow enabled elements to be focused (unless EFF_CAN_FOCUS_DISABLED is set) + if ( Hovered && !Hovered->isEnabled() && !(FocusFlags & EFF_CAN_FOCUS_DISABLED)) + focusCandidate = NULL; // we still remove focus from the active element + + // Please don't merge this into a single if clause, it's easier to debug the way it is + if (FocusFlags & EFF_SET_ON_LMOUSE_DOWN && + event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN ) + { + setFocus(focusCandidate); + } + else if ( FocusFlags & EFF_SET_ON_RMOUSE_DOWN && + event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN ) + { + setFocus(focusCandidate); + } + else if ( FocusFlags & EFF_SET_ON_MOUSE_OVER && + event.MouseInput.Event == EMIE_MOUSE_MOVED ) + { + setFocus(focusCandidate); + } + } + + // sending input to focus + if (Focus && Focus->OnEvent(event)) + return true; + + // focus could have died in last call + if (!Focus && Hovered) + { + return Hovered->OnEvent(event); + } + + break; + case EET_KEY_INPUT_EVENT: + { + if (Focus && Focus->OnEvent(event)) + return true; + + // For keys we handle the event before changing focus to give elements the chance for catching the TAB + // Send focus changing event + if (FocusFlags & EFF_SET_ON_TAB && + event.EventType == EET_KEY_INPUT_EVENT && + event.KeyInput.PressedDown && + event.KeyInput.Key == KEY_TAB) + { + IGUIElement *next = getNextElement(event.KeyInput.Shift, event.KeyInput.Control); + if (next && next != Focus) + { + if (setFocus(next)) + return true; + } + } + } + break; + default: + break; + } // end switch + + return false; +} + + +//! returns the current gui skin +IGUISkin* CGUIEnvironment::getSkin() const +{ + return CurrentSkin; +} + + +//! Sets a new GUI Skin +void CGUIEnvironment::setSkin(IGUISkin* skin) +{ + if (CurrentSkin==skin) + return; + + if (CurrentSkin) + CurrentSkin->drop(); + + CurrentSkin = skin; + + if (CurrentSkin) + CurrentSkin->grab(); +} + + +//! Creates a new GUI Skin based on a template. +/** \return Returns a pointer to the created skin. +If you no longer need the skin, you should call IGUISkin::drop(). +See IReferenceCounted::drop() for more information. */ +IGUISkin* CGUIEnvironment::createSkin(EGUI_SKIN_TYPE type) +{ + IGUISkin* skin = new CGUISkin(type, Driver); + + IGUIFont* builtinfont = getBuiltInFont(); + IGUIFontBitmap* bitfont = 0; + if (builtinfont && builtinfont->getType() == EGFT_BITMAP) + bitfont = (IGUIFontBitmap*)builtinfont; + + IGUISpriteBank* bank = 0; + skin->setFont(builtinfont); + + if (bitfont) + bank = bitfont->getSpriteBank(); + + skin->setSpriteBank(bank); + + return skin; +} + + +//! Returns the default element factory which can create all built in elements +IGUIElementFactory* CGUIEnvironment::getDefaultGUIElementFactory() const +{ + return getGUIElementFactory(0); +} + + +//! Adds an element factory to the gui environment. +/** Use this to extend the gui environment with new element types which it should be +able to create automatically, for example when loading data from xml files. */ +void CGUIEnvironment::registerGUIElementFactory(IGUIElementFactory* factoryToAdd) +{ + if (factoryToAdd) + { + factoryToAdd->grab(); + GUIElementFactoryList.push_back(factoryToAdd); + } +} + + +//! Returns amount of registered scene node factories. +u32 CGUIEnvironment::getRegisteredGUIElementFactoryCount() const +{ + return GUIElementFactoryList.size(); +} + + +//! Returns a scene node factory by index +IGUIElementFactory* CGUIEnvironment::getGUIElementFactory(u32 index) const +{ + if (index < GUIElementFactoryList.size()) + return GUIElementFactoryList[index]; + else + return 0; +} + + +//! adds a GUI Element using its name +IGUIElement* CGUIEnvironment::addGUIElement(const c8* elementName, IGUIElement* parent) +{ + IGUIElement* node=0; + + if (!parent) + parent = this; + + for (s32 i=GUIElementFactoryList.size()-1; i>=0 && !node; --i) + node = GUIElementFactoryList[i]->addGUIElement(elementName, parent); + + + return node; +} + + +//! Saves the current gui into a file. +//! \param filename: Name of the file . +bool CGUIEnvironment::saveGUI(const io::path& filename, IGUIElement* start) +{ + io::IWriteFile* file = FileSystem->createAndWriteFile(filename); + if (!file) + { + return false; + } + + bool ret = saveGUI(file, start); + file->drop(); + return ret; +} + + +//! Saves the current gui into a file. +bool CGUIEnvironment::saveGUI(io::IWriteFile* file, IGUIElement* start) +{ + if (!file) + { + return false; + } + + io::IXMLWriter* writer = FileSystem->createXMLWriter(file); + if (!writer) + { + return false; + } + + writer->writeXMLHeader(); + writeGUIElement(writer, start ? start : this); + writer->drop(); + + return true; +} + + +//! Loads the gui. Note that the current gui is not cleared before. +//! \param filename: Name of the file. +bool CGUIEnvironment::loadGUI(const io::path& filename, IGUIElement* parent) +{ + io::IReadFile* read = FileSystem->createAndOpenFile(filename); + if (!read) + { + os::Printer::log("Unable to open gui file", filename, ELL_ERROR); + return false; + } + + bool ret = loadGUI(read, parent); + read->drop(); + + return ret; +} + + +//! Loads the gui. Note that the current gui is not cleared before. +bool CGUIEnvironment::loadGUI(io::IReadFile* file, IGUIElement* parent) +{ + if (!file) + { + os::Printer::log("Unable to open GUI file", ELL_ERROR); + return false; + } + + io::IXMLReader* reader = FileSystem->createXMLReader(file); + if (!reader) + { + os::Printer::log("GUI is not a valid XML file", file->getFileName(), ELL_ERROR); + return false; + } + + // read file + while(reader->read()) + { + readGUIElement(reader, parent); + } + + // finish up + + reader->drop(); + return true; +} + + +//! reads an element +void CGUIEnvironment::readGUIElement(io::IXMLReader* reader, IGUIElement* node) +{ + if (!reader) + return; + + io::EXML_NODE nodeType = reader->getNodeType(); + + if (nodeType == io::EXN_NONE || nodeType == io::EXN_UNKNOWN || nodeType == io::EXN_ELEMENT_END) + return; + + IGUIElement* deferedNode = 0; + if (!wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName())) + { + // GuiEnvironment always must be this as it would serialize into a wrong element otherwise. + // So we use the given node next time + if ( node && node != this ) + deferedNode = node; + node = this; // root + } + else if (!wcscmp(IRR_XML_FORMAT_GUI_ELEMENT, reader->getNodeName())) + { + // find node type and create it + const core::stringc attrName = reader->getAttributeValue(IRR_XML_FORMAT_GUI_ELEMENT_ATTR_TYPE); + + node = addGUIElement(attrName.c_str(), node); + + if (!node) + os::Printer::log("Could not create GUI element of unknown type", attrName.c_str()); + } + + // read attributes + + while(reader->read()) + { + bool endreached = false; + + switch (reader->getNodeType()) + { + case io::EXN_ELEMENT_END: + if (!wcscmp(IRR_XML_FORMAT_GUI_ELEMENT, reader->getNodeName()) || + !wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName())) + { + endreached = true; + } + break; + case io::EXN_ELEMENT: + if (!wcscmp(L"attributes", reader->getNodeName())) + { + // read attributes + io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver); + attr->read(reader, true); + + if (node) + node->deserializeAttributes(attr); + + attr->drop(); + } + else + if (!wcscmp(IRR_XML_FORMAT_GUI_ELEMENT, reader->getNodeName()) || + !wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName())) + { + if ( deferedNode ) + readGUIElement(reader, deferedNode); + else + readGUIElement(reader, node); + } + else + { + os::Printer::log("Found unknown element in irrlicht GUI file", + core::stringc(reader->getNodeName()).c_str()); + } + + break; + default: + break; + } + + if (endreached) + break; + } +} + + +//! writes an element +void CGUIEnvironment::writeGUIElement(io::IXMLWriter* writer, IGUIElement* node) +{ + if (!writer || !node ) + return; + + const wchar_t* name = 0; + + // write properties + + io::IAttributes* attr = FileSystem->createEmptyAttributes(); + node->serializeAttributes(attr); + + // all gui elements must have at least one attribute + // if they have nothing then we ignore them. + if (attr->getAttributeCount() != 0) + { + if (node == this) + { + name = IRR_XML_FORMAT_GUI_ENV; + writer->writeElement(name, false); + } + else + { + name = IRR_XML_FORMAT_GUI_ELEMENT; + writer->writeElement(name, false, IRR_XML_FORMAT_GUI_ELEMENT_ATTR_TYPE, + core::stringw(node->getTypeName()).c_str()); + } + + writer->writeLineBreak(); + + attr->write(writer); + } + + // write children + + core::list::ConstIterator it = node->getChildren().begin(); + for (; it != node->getChildren().end(); ++it) + { + if (!(*it)->isSubElement()) + { + writer->writeLineBreak(); + writeGUIElement(writer, (*it)); + } + } + + // write closing brace if required + if (attr->getAttributeCount() != 0) + { + writer->writeClosingTag(name); + writer->writeLineBreak(); + } + + attr->drop(); +} + + +//! Writes attributes of the environment +void CGUIEnvironment::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + IGUISkin* skin = getSkin(); + + if (skin) + { + out->addEnum("Skin", getSkin()->getType(), GUISkinTypeNames); + skin->serializeAttributes(out, options); + } +} + + +//! Reads attributes of the environment +void CGUIEnvironment::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + if (in->existsAttribute("Skin")) + { + IGUISkin *skin = getSkin(); + + EGUI_SKIN_TYPE t = (EGUI_SKIN_TYPE) in->getAttributeAsEnumeration("Skin",GUISkinTypeNames); + if ( !skin || t != skin->getType()) + { + skin = createSkin(t); + setSkin(skin); + skin->drop(); + } + + skin = getSkin(); + + if (skin) + { + skin->deserializeAttributes(in, options); + } + + } + + RelativeRect = AbsoluteRect = + core::rect(Driver ? core::dimension2di(Driver->getScreenSize()) : core::dimension2d(0,0)); +} + + +//! adds a button. The returned pointer must not be dropped. +IGUIButton* CGUIEnvironment::addButton(const core::rect& rectangle, IGUIElement* parent, s32 id, const wchar_t* text, const wchar_t *tooltiptext) +{ + IGUIButton* button = new CGUIButton(this, parent ? parent : this, id, rectangle); + if (text) + button->setText(text); + + if ( tooltiptext ) + button->setToolTipText ( tooltiptext ); + + button->drop(); + return button; +} + + +//! adds a window. The returned pointer must not be dropped. +IGUIWindow* CGUIEnvironment::addWindow(const core::rect& rectangle, bool modal, + const wchar_t* text, IGUIElement* parent, s32 id) +{ + parent = parent ? parent : this; + + IGUIWindow* win = new CGUIWindow(this, parent, id, rectangle); + if (text) + win->setText(text); + win->drop(); + + if (modal) + { + // Careful, don't just set the modal as parent above. That will mess up the focus (and is hard to change because we have to be very + // careful not to get virtual function call, like OnEvent, in the window. + CGUIModalScreen * modalScreen = new CGUIModalScreen(this, parent, -1); + modalScreen->drop(); + modalScreen->addChild(win); + } + + return win; +} + + +//! adds a modal screen. The returned pointer must not be dropped. +IGUIElement* CGUIEnvironment::addModalScreen(IGUIElement* parent) +{ + parent = parent ? parent : this; + + IGUIElement *win = new CGUIModalScreen(this, parent, -1); + win->drop(); + + return win; +} + + +//! Adds a message box. +IGUIWindow* CGUIEnvironment::addMessageBox(const wchar_t* caption, const wchar_t* text, + bool modal, s32 flag, IGUIElement* parent, s32 id, video::ITexture* image) +{ + if (!CurrentSkin) + return 0; + + parent = parent ? parent : this; + + core::rect rect; + core::dimension2d screenDim, msgBoxDim; + + screenDim.Width = parent->getAbsolutePosition().getWidth(); + screenDim.Height = parent->getAbsolutePosition().getHeight(); + msgBoxDim.Width = 2; + msgBoxDim.Height = 2; + + rect.UpperLeftCorner.X = (screenDim.Width - msgBoxDim.Width) / 2; + rect.UpperLeftCorner.Y = (screenDim.Height - msgBoxDim.Height) / 2; + rect.LowerRightCorner.X = rect.UpperLeftCorner.X + msgBoxDim.Width; + rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + msgBoxDim.Height; + + IGUIWindow* win = new CGUIMessageBox(this, caption, text, flag, + parent, id, rect, image); + win->drop(); + + if (modal) + { + // Careful, don't just set the modal as parent above. That will mess up the focus (and is hard to change because we have to be very + // careful not to get virtual function call, like OnEvent, in the CGUIMessageBox. + CGUIModalScreen * modalScreen = new CGUIModalScreen(this, parent, -1); + modalScreen->drop(); + modalScreen->addChild( win ); + } + + + return win; +} + + +//! adds a scrollbar. The returned pointer must not be dropped. +IGUIScrollBar* CGUIEnvironment::addScrollBar(bool horizontal, const core::rect& rectangle, IGUIElement* parent, s32 id) +{ + IGUIScrollBar* bar = new CGUIScrollBar(horizontal, this, parent ? parent : this, id, rectangle); + bar->drop(); + return bar; +} + +//! Adds a table to the environment +IGUITable* CGUIEnvironment::addTable(const core::rect& rectangle, IGUIElement* parent, s32 id, bool drawBackground) +{ + CGUITable* b = new CGUITable(this, parent ? parent : this, id, rectangle, true, drawBackground, false); + b->drop(); + return b; +} + + //! Adds an element to display the information from the Irrlicht profiler +IGUIProfiler* CGUIEnvironment::addProfilerDisplay(const core::rect& rectangle, IGUIElement* parent, s32 id) +{ + CGUIProfiler* p = new CGUIProfiler(this, parent ? parent : this, id, rectangle, NULL); + p->drop(); + return p; +} + +//! 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 = core::dimension2d(image->getOriginalSize()); + + IGUIImage* img = new CGUIImage(this, parent ? parent : this, + id, core::rect(pos, sz)); + + if (text) + img->setText(text); + + if (useAlphaChannel) + img->setUseAlphaChannel(true); + + if (image) + img->setImage(image); + + img->drop(); + return img; +} + + +//! adds an image. The returned pointer must not be dropped. +IGUIImage* CGUIEnvironment::addImage(const core::rect& rectangle, IGUIElement* parent, s32 id, const wchar_t* text, bool useAlphaChannel) +{ + IGUIImage* img = new CGUIImage(this, parent ? parent : this, + id, rectangle); + + if (text) + img->setText(text); + + if ( useAlphaChannel ) + img->setUseAlphaChannel(true); + + img->drop(); + return img; +} + + +//! adds an mesh viewer. The returned pointer must not be dropped. +IGUIMeshViewer* CGUIEnvironment::addMeshViewer(const core::rect& rectangle, IGUIElement* parent, s32 id, const wchar_t* text) +{ + IGUIMeshViewer* v = new CGUIMeshViewer(this, parent ? parent : this, + id, rectangle); + + if (text) + v->setText(text); + + v->drop(); + return v; +} + + +//! 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, + parent ? parent : this , id , rectangle); + + if (text) + b->setText(text); + + b->drop(); + return b; +} + + +//! adds a list box +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); + + if (CurrentSkin && CurrentSkin->getSpriteBank()) + { + b->setSpriteBank(CurrentSkin->getSpriteBank()); + } + else if (getBuiltInFont() && getBuiltInFont()->getType() == EGFT_BITMAP) + { + b->setSpriteBank( ((IGUIFontBitmap*)getBuiltInFont())->getSpriteBank()); + } + + b->drop(); + return b; +} + +//! adds a tree view +IGUITreeView* CGUIEnvironment::addTreeView(const core::rect& rectangle, + IGUIElement* parent, s32 id, + bool drawBackground, + bool scrollBarVertical, bool scrollBarHorizontal) +{ + IGUITreeView* b = new CGUITreeView(this, parent ? parent : this, id, rectangle, + true, drawBackground, scrollBarVertical, scrollBarHorizontal); + + b->setIconFont ( getBuiltInFont () ); + b->drop(); + return b; +} + +//! 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, + bool restoreCWD, io::path::char_type* startDir) +{ + parent = parent ? parent : this; + + IGUIFileOpenDialog* d = new CGUIFileOpenDialog(title, this, parent, id, + restoreCWD, startDir); + d->drop(); + + if (modal) + { + // Careful, don't just set the modal as parent above. That will mess up the focus (and is hard to change because we have to be very + // careful not to get virtual function call, like OnEvent, in the window. + CGUIModalScreen * modalScreen = new CGUIModalScreen(this, parent, -1); + modalScreen->drop(); + modalScreen->addChild(d); + } + + return d; +} + + +//! 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) +{ + parent = parent ? parent : this; + + IGUIColorSelectDialog* d = new CGUIColorSelectDialog( title, + this, parent, id); + d->drop(); + + if (modal) + { + // Careful, don't just set the modal as parent above. That will mess up the focus (and is hard to change because we have to be very + // careful not to get virtual function call, like OnEvent, in the window. + CGUIModalScreen * modalScreen = new CGUIModalScreen(this, parent, -1); + modalScreen->drop(); + modalScreen->addChild(d); + } + + return d; +} + + +//! 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* d = new CGUIStaticText(text, border, this, + parent ? parent : this, id, rectangle, background); + + d->setWordWrap(wordWrap); + d->drop(); + + return d; +} + + +//! 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* d = new CGUIEditBox(text, border, this, + parent ? parent : this, id, rectangle); + + d->drop(); + return d; +} + + +//! Adds a spin box to the environment +IGUISpinBox* CGUIEnvironment::addSpinBox(const wchar_t* text, + const core::rect &rectangle, + bool border,IGUIElement* parent, s32 id) +{ + IGUISpinBox* d = new CGUISpinBox(text, border,this, + parent ? parent : this, id, rectangle); + + d->drop(); + return d; +} + + +//! Adds a tab control to the environment. +IGUITabControl* CGUIEnvironment::addTabControl(const core::rect& rectangle, + IGUIElement* parent, bool fillbackground, bool border, s32 id) +{ + IGUITabControl* t = new CGUITabControl(this, parent ? parent : this, + rectangle, fillbackground, border, id); + t->drop(); + return t; +} + + +//! Adds tab to the environment. +IGUITab* CGUIEnvironment::addTab(const core::rect& rectangle, + IGUIElement* parent, s32 id) +{ + IGUITab* t = new CGUITab(this, parent ? parent : this, + rectangle, id); + t->drop(); + return t; +} + + +//! Adds a context menu to the environment. +IGUIContextMenu* CGUIEnvironment::addContextMenu(const core::rect& rectangle, + IGUIElement* parent, s32 id) +{ + IGUIContextMenu* c = new CGUIContextMenu(this, + parent ? parent : this, id, rectangle, true); + c->drop(); + return c; +} + + +//! Adds a menu to the environment. +IGUIContextMenu* CGUIEnvironment::addMenu(IGUIElement* parent, s32 id) +{ + if (!parent) + parent = this; + + IGUIContextMenu* c = new CGUIMenu(this, + parent, id, core::rect(0,0, + parent->getAbsolutePosition().getWidth(), + parent->getAbsolutePosition().getHeight())); + + c->drop(); + return c; +} + + +//! Adds a toolbar to the environment. It is like a menu is always placed on top +//! in its parent, and contains buttons. +IGUIToolBar* CGUIEnvironment::addToolBar(IGUIElement* parent, s32 id) +{ + if (!parent) + parent = this; + + IGUIToolBar* b = new CGUIToolBar(this, parent, id, core::rect(0,0,10,10)); + b->drop(); + return b; +} + + +//! Adds an element for fading in or out. +IGUIInOutFader* CGUIEnvironment::addInOutFader(const core::rect* rectangle, IGUIElement* parent, s32 id) +{ + core::rect rect; + + if (rectangle) + rect = *rectangle; + else if (Driver) + rect = core::rect(core::dimension2di(Driver->getScreenSize())); + + if (!parent) + parent = this; + + IGUIInOutFader* fader = new CGUIInOutFader(this, parent, id, rect); + fader->drop(); + return fader; +} + + +//! Adds a combo box to the environment. +IGUIComboBox* CGUIEnvironment::addComboBox(const core::rect& rectangle, + IGUIElement* parent, s32 id) +{ + IGUIComboBox* t = new CGUIComboBox(this, parent ? parent : this, + id, rectangle); + t->drop(); + return t; +} + + +//! returns the font +IGUIFont* CGUIEnvironment::getFont(const io::path& filename) +{ + // search existing font + + SFont f; + f.NamedPath.setPath(filename); + + s32 index = Fonts.binary_search(f); + if (index != -1) + return Fonts[index].Font; + + // font doesn't exist, attempt to load it + + // does the file exist? + + if (!FileSystem->existFile(filename)) + { + os::Printer::log("Could not load font because the file does not exist", f.NamedPath.getPath(), ELL_ERROR); + return 0; + } + + IGUIFont* ifont=0; + io::IXMLReader *xml = FileSystem->createXMLReader(filename ); + if (xml) + { + // this is an XML font, but we need to know what type + EGUI_FONT_TYPE t = EGFT_CUSTOM; + + bool found=false; + while(!found && xml->read()) + { + if (xml->getNodeType() == io::EXN_ELEMENT) + { + if (core::stringw(L"font") == xml->getNodeName()) + { + if (core::stringw(L"vector") == xml->getAttributeValue(L"type")) + { + t = EGFT_VECTOR; + found=true; + } + else if (core::stringw(L"bitmap") == xml->getAttributeValue(L"type")) + { + t = EGFT_BITMAP; + found=true; + } + else found=true; + } + } + } + + if (t==EGFT_BITMAP) + { + CGUIFont* font = new CGUIFont(this, filename); + ifont = (IGUIFont*)font; + + // load the font + io::path directory; + core::splitFilename(filename, &directory); + if (!font->load(xml, directory)) + { + font->drop(); + font = 0; + ifont = 0; + } + } + else if (t==EGFT_VECTOR) + { + // todo: vector fonts + os::Printer::log("Unable to load font, XML vector fonts are not supported yet", f.NamedPath, ELL_ERROR); + + //CGUIFontVector* font = new CGUIFontVector(Driver); + //ifont = (IGUIFont*)font; + //if (!font->load(xml)) + } + xml->drop(); + } + + + if (!ifont) + { + + CGUIFont* font = new CGUIFont(this, f.NamedPath.getPath() ); + ifont = (IGUIFont*)font; + if (!font->load(f.NamedPath.getPath())) + { + font->drop(); + return 0; + } + } + + // add to fonts. + + f.Font = ifont; + Fonts.push_back(f); + + return ifont; +} + + +//! add an externally loaded font +IGUIFont* CGUIEnvironment::addFont(const io::path& name, IGUIFont* font) +{ + if (font) + { + SFont f; + f.NamedPath.setPath(name); + s32 index = Fonts.binary_search(f); + if (index != -1) + return Fonts[index].Font; + f.Font = font; + Fonts.push_back(f); + font->grab(); + } + return font; +} + +//! remove loaded font +void CGUIEnvironment::removeFont(IGUIFont* font) +{ + if ( !font ) + return; + for ( u32 i=0; idrop(); + Fonts.erase(i); + return; + } + } +} + +//! returns default font +IGUIFont* CGUIEnvironment::getBuiltInFont() const +{ + if (Fonts.empty()) + return 0; + + return Fonts[0].Font; +} + + +IGUISpriteBank* CGUIEnvironment::getSpriteBank(const io::path& filename) +{ + // search for the file name + + SSpriteBank b; + b.NamedPath.setPath(filename); + + s32 index = Banks.binary_search(b); + if (index != -1) + return Banks[index].Bank; + + // we don't have this sprite bank, we should load it + if (!FileSystem->existFile(b.NamedPath.getPath())) + { + if ( filename != DefaultFontName ) + { + os::Printer::log("Could not load sprite bank because the file does not exist", b.NamedPath.getPath(), ELL_DEBUG); + } + return 0; + } + + // todo: load it! + + return 0; +} + + +IGUISpriteBank* CGUIEnvironment::addEmptySpriteBank(const io::path& name) +{ + // no duplicate names allowed + + SSpriteBank b; + b.NamedPath.setPath(name); + + const s32 index = Banks.binary_search(b); + if (index != -1) + return 0; + + // create a new sprite bank + + b.Bank = new CGUISpriteBank(this); + Banks.push_back(b); + + return b.Bank; +} + + +//! Creates the image list from the given texture. +IGUIImageList* CGUIEnvironment::createImageList( video::ITexture* texture, + core::dimension2d imageSize, bool useAlphaChannel ) +{ + CGUIImageList* imageList = new CGUIImageList( Driver ); + if( !imageList->createImageList( texture, imageSize, useAlphaChannel ) ) + { + imageList->drop(); + return 0; + } + + return imageList; +} + +//! Returns the root gui element. +IGUIElement* CGUIEnvironment::getRootGUIElement() +{ + return this; +} + + +//! Returns the next element in the tab group starting at the focused element +IGUIElement* CGUIEnvironment::getNextElement(bool reverse, bool group) +{ + // start the search at the root of the current tab group + IGUIElement *startPos = Focus ? Focus->getTabGroup() : 0; + s32 startOrder = -1; + + // if we're searching for a group + if (group && startPos) + { + startOrder = startPos->getTabOrder(); + } + else + if (!group && Focus && !Focus->isTabGroup()) + { + startOrder = Focus->getTabOrder(); + if (startOrder == -1) + { + // this element is not part of the tab cycle, + // but its parent might be... + IGUIElement *el = Focus; + while (el && el->getParent() && startOrder == -1) + { + el = el->getParent(); + startOrder = el->getTabOrder(); + } + + } + } + + if (group || !startPos) + startPos = this; // start at the root + + // find the element + IGUIElement *closest = 0; + IGUIElement *first = 0; + startPos->getNextElement(startOrder, reverse, group, first, closest, false, (FocusFlags & EFF_CAN_FOCUS_DISABLED) != 0); + + if (closest) + return closest; // we found an element + else if (first) + return first; // go to the end or the start + else if (group) + return this; // no group found? root group + else + return 0; +} + +void CGUIEnvironment::setFocusBehavior(u32 flags) +{ + FocusFlags = flags; +} + +u32 CGUIEnvironment::getFocusBehavior() const +{ + return FocusFlags; +} + +//! creates an GUI Environment +IGUIEnvironment* createGUIEnvironment(io::IFileSystem* fs, + video::IVideoDriver* Driver, + IOSOperator* op) +{ + return new CGUIEnvironment(fs, Driver, op); +} + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIEnvironment.h b/source/Irrlicht/CGUIEnvironment.h new file mode 100644 index 00000000..58b7f545 --- /dev/null +++ b/source/Irrlicht/CGUIEnvironment.h @@ -0,0 +1,335 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_ENVIRONMENT_H_INCLUDED__ +#define __C_GUI_ENVIRONMENT_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIEnvironment.h" +#include "IGUIElement.h" +#include "irrArray.h" +#include "IFileSystem.h" +#include "IOSOperator.h" + +namespace irr +{ + +namespace gui +{ + +class CGUIEnvironment : public IGUIEnvironment, public IGUIElement +{ +public: + + //! constructor + CGUIEnvironment(io::IFileSystem* fs, video::IVideoDriver* driver, IOSOperator* op); + + //! destructor + virtual ~CGUIEnvironment(); + + //! draws all gui elements + virtual void drawAll() _IRR_OVERRIDE_; + + //! returns the current video driver + virtual video::IVideoDriver* getVideoDriver() const _IRR_OVERRIDE_; + + //! returns pointer to the filesystem + virtual io::IFileSystem* getFileSystem() const _IRR_OVERRIDE_; + + //! returns a pointer to the OS operator + virtual IOSOperator* getOSOperator() const _IRR_OVERRIDE_; + + //! posts an input event to the environment + virtual bool postEventFromUser(const SEvent& event) _IRR_OVERRIDE_; + + //! This sets a new event receiver for gui events. Usually you do not have to + //! use this method, it is used by the internal engine. + virtual void setUserEventReceiver(IEventReceiver* evr) _IRR_OVERRIDE_; + + //! removes all elements from the environment + virtual void clear() _IRR_OVERRIDE_; + + //! called if an event happened. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! returns the current gui skin + virtual IGUISkin* getSkin() const _IRR_OVERRIDE_; + + //! Sets a new GUI Skin + virtual void setSkin(IGUISkin* skin) _IRR_OVERRIDE_; + + //! Creates a new GUI Skin based on a template. + /** \return Returns a pointer to the created skin. + If you no longer need the skin, you should call IGUISkin::drop(). + See IReferenceCounted::drop() for more information. */ + virtual IGUISkin* createSkin(EGUI_SKIN_TYPE type) _IRR_OVERRIDE_; + + //! Creates the image list from the given texture. + virtual IGUIImageList* createImageList(video::ITexture* texture, + core::dimension2d imageSize, bool useAlphaChannel) _IRR_OVERRIDE_; + + //! returns the font + virtual IGUIFont* getFont(const io::path& filename) _IRR_OVERRIDE_; + + //! add an externally loaded font + virtual IGUIFont* addFont(const io::path& name, IGUIFont* font) _IRR_OVERRIDE_; + + //! remove loaded font + virtual void removeFont(IGUIFont* font) _IRR_OVERRIDE_; + + //! returns default font + virtual IGUIFont* getBuiltInFont() const _IRR_OVERRIDE_; + + //! returns the sprite bank + virtual IGUISpriteBank* getSpriteBank(const io::path& filename) _IRR_OVERRIDE_; + + //! returns the sprite bank + virtual IGUISpriteBank* addEmptySpriteBank(const io::path& name) _IRR_OVERRIDE_; + + //! adds an button. The returned pointer must not be dropped. + virtual IGUIButton* addButton(const core::rect& rectangle, IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0,const wchar_t* tooltiptext = 0) _IRR_OVERRIDE_; + + //! adds a window. The returned pointer must not be dropped. + virtual IGUIWindow* addWindow(const core::rect& rectangle, bool modal = false, + const wchar_t* text=0, IGUIElement* parent=0, s32 id=-1) _IRR_OVERRIDE_; + + //! adds a modal screen. The returned pointer must not be dropped. + virtual IGUIElement* addModalScreen(IGUIElement* parent) _IRR_OVERRIDE_; + + //! Adds a message box. + virtual IGUIWindow* addMessageBox(const wchar_t* caption, const wchar_t* text=0, + bool modal = true, s32 flag = EMBF_OK, IGUIElement* parent=0, s32 id=-1, video::ITexture* image=0) _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! adds an image. The returned pointer must not be dropped. + virtual IGUIImage* addImage(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0, bool useAlphaChannel=true) _IRR_OVERRIDE_; + + //! adds a checkbox + virtual IGUICheckBox* addCheckBox(bool checked, const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0) _IRR_OVERRIDE_; + + //! adds a list box + virtual IGUIListBox* addListBox(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1, bool drawBackground=false) _IRR_OVERRIDE_; + + //! adds a tree view + virtual IGUITreeView* addTreeView(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1, bool drawBackground=false, + bool scrollBarVertical = true, bool scrollBarHorizontal = false) _IRR_OVERRIDE_; + + //! adds an mesh viewer. The returned pointer must not be dropped. + virtual IGUIMeshViewer* addMeshViewer(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0) _IRR_OVERRIDE_; + + //! Adds a file open dialog. + virtual IGUIFileOpenDialog* addFileOpenDialog(const wchar_t* title = 0, + bool modal=true, IGUIElement* parent=0, s32 id=-1, + bool restoreCWD=false, io::path::char_type* startDir=0) _IRR_OVERRIDE_; + + //! Adds a color select dialog. + virtual IGUIColorSelectDialog* addColorSelectDialog(const wchar_t* title = 0, + bool modal=true, IGUIElement* parent=0, s32 id=-1) _IRR_OVERRIDE_; + + //! adds a static text. The returned pointer must not be dropped. + virtual IGUIStaticText* addStaticText(const wchar_t* text, const core::rect& rectangle, + bool border=false, bool wordWrap=true, IGUIElement* parent=0, s32 id=-1, bool drawBackground = false) _IRR_OVERRIDE_; + + //! Adds an edit box. The returned pointer must not be dropped. + virtual IGUIEditBox* addEditBox(const wchar_t* text, const core::rect& rectangle, + bool border=false, IGUIElement* parent=0, s32 id=-1) _IRR_OVERRIDE_; + + //! Adds a spin box to the environment + virtual IGUISpinBox* addSpinBox(const wchar_t* text, const core::rect& rectangle, + bool border=false,IGUIElement* parent=0, s32 id=-1) _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! Adds tab to the environment. + virtual IGUITab* addTab(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1) _IRR_OVERRIDE_; + + //! Adds a context menu to the environment. + virtual IGUIContextMenu* addContextMenu(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1) _IRR_OVERRIDE_; + + //! Adds a menu to the environment. + virtual IGUIContextMenu* addMenu(IGUIElement* parent=0, s32 id=-1) _IRR_OVERRIDE_; + + //! Adds a toolbar to the environment. It is like a menu is always placed on top + //! in its parent, and contains buttons. + virtual IGUIToolBar* addToolBar(IGUIElement* parent=0, s32 id=-1) _IRR_OVERRIDE_; + + //! Adds a combo box to the environment. + virtual IGUIComboBox* addComboBox(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1) _IRR_OVERRIDE_; + + //! Adds a table element. + virtual IGUITable* addTable(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1, bool drawBackground=false) _IRR_OVERRIDE_; + + //! Adds an element to display the information from the Irrlicht profiler + virtual IGUIProfiler* addProfilerDisplay(const core::rect& rectangle, + IGUIElement* parent=0, s32 id=-1) _IRR_OVERRIDE_; + + //! sets the focus to an element + virtual bool setFocus(IGUIElement* element) _IRR_OVERRIDE_; + + //! removes the focus from an element + virtual bool removeFocus(IGUIElement* element) _IRR_OVERRIDE_; + + //! Returns if the element has focus + virtual bool hasFocus(const IGUIElement* element, bool checkSubElements=false) const _IRR_OVERRIDE_; + + //! Returns the element with the focus + virtual IGUIElement* getFocus() const _IRR_OVERRIDE_; + + //! Returns the element last known to be under the mouse + virtual IGUIElement* getHovered() const _IRR_OVERRIDE_; + + //! Adds an element for fading in or out. + virtual IGUIInOutFader* addInOutFader(const core::rect* rectangle=0, IGUIElement* parent=0, s32 id=-1) _IRR_OVERRIDE_; + + //! Returns the root gui element. + virtual IGUIElement* getRootGUIElement() _IRR_OVERRIDE_; + + virtual void OnPostRender( u32 time ) _IRR_OVERRIDE_; + + //! Returns the default element factory which can create all built in elements + virtual IGUIElementFactory* getDefaultGUIElementFactory() const _IRR_OVERRIDE_; + + //! Adds an element factory to the gui environment. + /** Use this to extend the gui environment with new element types which it should be + able to create automatically, for example when loading data from xml files. */ + virtual void registerGUIElementFactory(IGUIElementFactory* factoryToAdd) _IRR_OVERRIDE_; + + //! Returns amount of registered scene node factories. + virtual u32 getRegisteredGUIElementFactoryCount() const _IRR_OVERRIDE_; + + //! Returns a scene node factory by index + virtual IGUIElementFactory* getGUIElementFactory(u32 index) const _IRR_OVERRIDE_; + + //! Adds a GUI Element by its name + virtual IGUIElement* addGUIElement(const c8* elementName, IGUIElement* parent=0) _IRR_OVERRIDE_; + + //! 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 */ + virtual bool saveGUI( const io::path& filename, IGUIElement* start=0) _IRR_OVERRIDE_; + + //! Saves the current gui into a file. + /** \param file: The file to save the GUI to. + \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) _IRR_OVERRIDE_; + + //! 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, + if not specified, the root element will be used */ + virtual bool loadGUI(const io::path& filename, IGUIElement* parent=0) _IRR_OVERRIDE_; + + //! 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, + if not specified, the root element will be used */ + virtual bool loadGUI(io::IReadFile* file, IGUIElement* parent=0) _IRR_OVERRIDE_; + + //! Writes attributes of the environment + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the environment. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! writes an element + virtual void writeGUIElement(io::IXMLWriter* writer, IGUIElement* node) _IRR_OVERRIDE_; + + //! reads an element + virtual void readGUIElement(io::IXMLReader* reader, IGUIElement* node) _IRR_OVERRIDE_; + + //! Find the next element which would be selected when pressing the tab-key + virtual IGUIElement* getNextElement(bool reverse=false, bool group=false) _IRR_OVERRIDE_; + + //! Set the way the gui will handle focus changes + virtual void setFocusBehavior(u32 flags) _IRR_OVERRIDE_; + + //! Get the way the gui does handle focus changes + virtual u32 getFocusBehavior() const _IRR_OVERRIDE_; + +private: + + void updateHoveredElement(core::position2d mousePos); + + void loadBuiltInFont(); + + struct SFont + { + io::SNamedPath NamedPath; + IGUIFont* Font; + + bool operator < (const SFont& other) const + { + return (NamedPath < other.NamedPath); + } + }; + + struct SSpriteBank + { + io::SNamedPath NamedPath; + IGUISpriteBank* Bank; + + bool operator < (const SSpriteBank& other) const + { + return (NamedPath < other.NamedPath); + } + }; + + struct SToolTip + { + IGUIStaticText* Element; + u32 LastTime; + u32 EnterTime; + u32 LaunchTime; + u32 RelaunchTime; + }; + + SToolTip ToolTip; + + core::array GUIElementFactoryList; + + core::array Fonts; + core::array Banks; + video::IVideoDriver* Driver; + IGUIElement* Hovered; + IGUIElement* HoveredNoSubelement; // subelements replaced by their parent, so you only have 'real' elements here + IGUIElement* Focus; + core::position2d LastHoveredMousePos; + IGUISkin* CurrentSkin; + io::IFileSystem* FileSystem; + IEventReceiver* UserReceiver; + IOSOperator* Operator; + u32 FocusFlags; + static const io::path DefaultFontName; +}; + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif // __C_GUI_ENVIRONMENT_H_INCLUDED__ + + diff --git a/source/Irrlicht/CGUIFileOpenDialog.cpp b/source/Irrlicht/CGUIFileOpenDialog.cpp new file mode 100644 index 00000000..25da8976 --- /dev/null +++ b/source/Irrlicht/CGUIFileOpenDialog.cpp @@ -0,0 +1,454 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUIFileOpenDialog.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include + +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" +#include "IGUIButton.h" +#include "IGUIStaticText.h" +#include "IGUIFont.h" +#include "IGUIFontBitmap.h" +#include "IFileList.h" +#include "os.h" + +namespace irr +{ +namespace gui +{ + +const s32 FOD_WIDTH = 350; +const s32 FOD_HEIGHT = 250; + + +//! constructor +CGUIFileOpenDialog::CGUIFileOpenDialog(const wchar_t* title, + IGUIEnvironment* environment, IGUIElement* parent, s32 id, + bool restoreCWD, io::path::char_type* startDir) +: IGUIFileOpenDialog(environment, parent, id, + core::rect((parent->getAbsolutePosition().getWidth()-FOD_WIDTH)/2, + (parent->getAbsolutePosition().getHeight()-FOD_HEIGHT)/2, + (parent->getAbsolutePosition().getWidth()-FOD_WIDTH)/2+FOD_WIDTH, + (parent->getAbsolutePosition().getHeight()-FOD_HEIGHT)/2+FOD_HEIGHT)), + FileNameText(0), FileList(0), Dragging(false) +{ + #ifdef _DEBUG + IGUIElement::setDebugName("CGUIFileOpenDialog"); + #endif + + Text = title; + + FileSystem = Environment?Environment->getFileSystem():0; + + if (FileSystem) + { + FileSystem->grab(); + + if (restoreCWD) + RestoreDirectory = FileSystem->getWorkingDirectory(); + if (startDir) + { + StartDirectory = startDir; + FileSystem->changeWorkingDirectoryTo(startDir); + } + } + else + return; + + IGUISpriteBank* sprites = 0; + video::SColor color(255,255,255,255); + IGUISkin* skin = Environment->getSkin(); + if (skin) + { + sprites = skin->getSpriteBank(); + color = skin->getColor(EGDC_WINDOW_SYMBOL); + } + + const s32 buttonw = skin ? skin->getSize(EGDS_WINDOW_BUTTON_WIDTH) : 2; + 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"); + CloseButton->setSubElement(true); + CloseButton->setTabStop(false); + if (sprites) + { + CloseButton->setSpriteBank(sprites); + CloseButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_CLOSE), color); + CloseButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_CLOSE), color); + } + CloseButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + CloseButton->grab(); + + OKButton = Environment->addButton( + core::rect(RelativeRect.getWidth()-80, 30, RelativeRect.getWidth()-10, 50), + this, -1, skin ? skin->getDefaultText(EGDT_MSG_BOX_OK) : L"OK"); + OKButton->setSubElement(true); + OKButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + OKButton->grab(); + + CancelButton = Environment->addButton( + core::rect(RelativeRect.getWidth()-80, 55, RelativeRect.getWidth()-10, 75), + this, -1, skin ? skin->getDefaultText(EGDT_MSG_BOX_CANCEL) : L"Cancel"); + CancelButton->setSubElement(true); + CancelButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + CancelButton->grab(); + + FileBox = Environment->addListBox(core::rect(10, 55, RelativeRect.getWidth()-90, 230), this, -1, true); + FileBox->setSubElement(true); + FileBox->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + FileBox->grab(); + + FileNameText = Environment->addEditBox(0, core::rect(10, 30, RelativeRect.getWidth()-90, 50), true, this); + FileNameText->setSubElement(true); + FileNameText->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + FileNameText->grab(); + + setTabGroup(true); + + fillListBox(); +} + + +//! destructor +CGUIFileOpenDialog::~CGUIFileOpenDialog() +{ + if (CloseButton) + CloseButton->drop(); + + if (OKButton) + OKButton->drop(); + + if (CancelButton) + CancelButton->drop(); + + if (FileBox) + FileBox->drop(); + + if (FileNameText) + FileNameText->drop(); + + if (FileSystem) + { + // revert to original CWD if path was set in constructor + if (RestoreDirectory.size()) + FileSystem->changeWorkingDirectoryTo(RestoreDirectory); + FileSystem->drop(); + } + + if (FileList) + FileList->drop(); +} + + +//! returns the filename of the selected file. Returns NULL, if no file was selected. +const wchar_t* CGUIFileOpenDialog::getFileName() const +{ + return FileNameW.c_str(); +} + +const io::path& CGUIFileOpenDialog::getFileNameP() const +{ + return FileName; +} + +//! Returns the directory of the selected file. Returns NULL, if no directory was selected. +const io::path& CGUIFileOpenDialog::getDirectoryName() const +{ + return FileDirectoryFlat; +} + +const wchar_t* CGUIFileOpenDialog::getDirectoryNameW() const +{ + return FileDirectoryFlatW.c_str(); +} + +void CGUIFileOpenDialog::setFileName(const irr::io::path& name) +{ + FileName = name; + pathToStringW(FileNameW, FileName); +} + +void CGUIFileOpenDialog::setDirectoryName(const irr::io::path& name) +{ + FileDirectory = name; + FileDirectoryFlat = name; + FileSystem->flattenFilename (FileDirectoryFlat ); + pathToStringW(FileDirectoryFlatW, FileDirectoryFlat); +} + +//! called if an event happened. +bool CGUIFileOpenDialog::OnEvent(const SEvent& event) +{ + if (isEnabled()) + { + switch(event.EventType) + { + case EET_GUI_EVENT: + switch(event.GUIEvent.EventType) + { + case EGET_ELEMENT_FOCUS_LOST: + Dragging = false; + break; + case EGET_BUTTON_CLICKED: + if (event.GUIEvent.Caller == CloseButton || + event.GUIEvent.Caller == CancelButton) + { + sendCancelEvent(); + remove(); + return true; + } + else + if (event.GUIEvent.Caller == OKButton ) + { + if ( FileDirectory != L"" ) + { + sendSelectedEvent( EGET_DIRECTORY_SELECTED ); + } + if ( FileName != L"" ) + { + sendSelectedEvent( EGET_FILE_SELECTED ); + remove(); + return true; + } + } + break; + + case EGET_LISTBOX_CHANGED: + { + s32 selected = FileBox->getSelected(); + if (FileList && FileSystem) + { + if (FileList->isDirectory(selected)) + { + setFileName(""); + setDirectoryName(FileList->getFullFileName(selected)); + } + else + { + setDirectoryName(""); + setFileName(FileList->getFullFileName(selected)); + } + return true; + } + } + break; + + case EGET_LISTBOX_SELECTED_AGAIN: + { + const s32 selected = FileBox->getSelected(); + if (FileList && FileSystem) + { + if (FileList->isDirectory(selected)) + { + setDirectoryName(FileList->getFullFileName(selected)); + FileSystem->changeWorkingDirectoryTo(FileDirectory ); + fillListBox(); + setFileName(""); + } + else + { + setFileName(FileList->getFullFileName(selected)); + } + return true; + } + } + break; + case EGET_EDITBOX_ENTER: + if (event.GUIEvent.Caller == FileNameText) + { + io::path dir( FileNameText->getText () ); + if ( FileSystem->changeWorkingDirectoryTo( dir ) ) + { + fillListBox(); + setFileName(""); + } + return true; + } + break; + default: + break; + } + break; + case EET_MOUSE_INPUT_EVENT: + switch(event.MouseInput.Event) + { + case EMIE_MOUSE_WHEEL: + return FileBox->OnEvent(event); + case EMIE_LMOUSE_PRESSED_DOWN: + DragStart.X = event.MouseInput.X; + DragStart.Y = event.MouseInput.Y; + Dragging = true; + return true; + case EMIE_LMOUSE_LEFT_UP: + Dragging = false; + return true; + case EMIE_MOUSE_MOVED: + + if ( !event.MouseInput.isLeftPressed () ) + Dragging = false; + + if (Dragging) + { + // gui window should not be dragged outside its parent + if (Parent) + if (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; + + move(core::position2d(event.MouseInput.X - DragStart.X, event.MouseInput.Y - DragStart.Y)); + DragStart.X = event.MouseInput.X; + DragStart.Y = event.MouseInput.Y; + return true; + } + break; + default: + break; + } + default: + break; + } + } + + return IGUIElement::OnEvent(event); +} + + +//! draws the element and its children +void CGUIFileOpenDialog::draw() +{ + if (!IsVisible) + return; + + IGUISkin* skin = Environment->getSkin(); + + core::rect rect = AbsoluteRect; + + rect = skin->draw3DWindowBackground(this, true, skin->getColor(EGDC_ACTIVE_BORDER), + rect, &AbsoluteClippingRect); + + if (Text.size()) + { + rect.UpperLeftCorner.X += 2; + rect.LowerRightCorner.X -= skin->getSize(EGDS_WINDOW_BUTTON_WIDTH) + 5; + + IGUIFont* font = skin->getFont(EGDF_WINDOW); + if (font) + font->draw(Text.c_str(), rect, + skin->getColor(EGDC_ACTIVE_CAPTION), + false, true, &AbsoluteClippingRect); + } + + IGUIElement::draw(); +} + + +//! Writes attributes of the element. +/* Not sure if this will really work out properly. Saving paths can be +rather problematic. */ +void CGUIFileOpenDialog::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + IGUIFileOpenDialog::serializeAttributes(out,options); + + out->addString("StartDirectory", StartDirectory.c_str()); + out->addBool("RestoreDirectory", (RestoreDirectory.size()!=0)); +} + + +//! Reads attributes of the element +/* Note that these paths changes will happen at arbitrary places upon +load of the gui description. This may be undesired. */ +void CGUIFileOpenDialog::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + StartDirectory = in->getAttributeAsString("StartDirectory"); + const bool restore = in->getAttributeAsBool("RestoreDirectory"); + if (restore) + RestoreDirectory = FileSystem->getWorkingDirectory(); + else + RestoreDirectory = ""; + if (StartDirectory.size()) + FileSystem->changeWorkingDirectoryTo(StartDirectory); + + IGUIFileOpenDialog::deserializeAttributes(in,options); +} + +void CGUIFileOpenDialog::pathToStringW(irr::core::stringw& result, const irr::io::path& p) +{ +#ifndef _IRR_WCHAR_FILESYSTEM + char* oldLocale = setlocale(LC_CTYPE, NULL); + setlocale(LC_CTYPE,""); // multibyteToWString is affected by LC_CTYPE. Filenames seem to need the system-locale. + core::multibyteToWString(result, p); + setlocale(LC_CTYPE, oldLocale); +#else + result = p.c_str(); +#endif +} + +//! fills the listbox with files. +void CGUIFileOpenDialog::fillListBox() +{ + IGUISkin *skin = Environment->getSkin(); + + if (!FileSystem || !FileBox || !skin) + return; + + if (FileList) + FileList->drop(); + + FileBox->clear(); + + FileList = FileSystem->createFileList(); + core::stringw s; + + if (FileList) + { + for (u32 i=0; i < FileList->getFileCount(); ++i) + { + pathToStringW(s, FileList->getFileName(i)); + FileBox->addItem(s.c_str(), skin->getIcon(FileList->isDirectory(i) ? EGDI_DIRECTORY : EGDI_FILE)); + } + } + + if (FileNameText) + { + setDirectoryName(FileSystem->getWorkingDirectory()); + pathToStringW(s, FileDirectory); + FileNameText->setText(s.c_str()); + } +} + +//! sends the event that the file has been selected. +void CGUIFileOpenDialog::sendSelectedEvent( EGUI_EVENT_TYPE type) +{ + SEvent event; + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.Element = 0; + event.GUIEvent.EventType = type; + Parent->OnEvent(event); +} + + +//! sends the event that the file choose process has been cancelled +void CGUIFileOpenDialog::sendCancelEvent() +{ + SEvent event; + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.Element = 0; + event.GUIEvent.EventType = EGET_FILE_CHOOSE_DIALOG_CANCELLED; + Parent->OnEvent(event); +} + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ diff --git a/source/Irrlicht/CGUIFileOpenDialog.h b/source/Irrlicht/CGUIFileOpenDialog.h new file mode 100644 index 00000000..aec04898 --- /dev/null +++ b/source/Irrlicht/CGUIFileOpenDialog.h @@ -0,0 +1,99 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_FILE_OPEN_DIALOG_H_INCLUDED__ +#define __C_GUI_FILE_OPEN_DIALOG_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIFileOpenDialog.h" +#include "IGUIButton.h" +#include "IGUIListBox.h" +#include "IGUIEditBox.h" +#include "IFileSystem.h" + +namespace irr +{ +namespace gui +{ + + class CGUIFileOpenDialog : public IGUIFileOpenDialog + { + public: + + //! constructor + CGUIFileOpenDialog(const wchar_t* title, IGUIEnvironment* environment, + IGUIElement* parent, s32 id, bool restoreCWD=false, + io::path::char_type* startDir=0); + + //! destructor + virtual ~CGUIFileOpenDialog(); + + //! returns the filename of the selected file. Returns NULL, if no file was selected. + virtual const wchar_t* getFileName() const _IRR_OVERRIDE_; + + //! Returns the filename of the selected file. Is empty if no file was selected. + virtual const io::path& getFileNameP() const _IRR_OVERRIDE_; + + //! Returns the directory of the selected file. Returns NULL, if no directory was selected. + virtual const io::path& getDirectoryName() const _IRR_OVERRIDE_; + + //! Returns the directory of the selected file converted to wide characters. Returns NULL if no directory was selected. + virtual const wchar_t* getDirectoryNameW() const _IRR_OVERRIDE_; + + //! called if an event happened. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + protected: + + void setFileName(const irr::io::path& name); + void setDirectoryName(const irr::io::path& name); + + //! Ensure filenames are converted correct depending on wide-char settings + void pathToStringW(irr::core::stringw& result, const irr::io::path& p); + + //! fills the listbox with files. + void fillListBox(); + + //! sends the event that the file has been selected. + void sendSelectedEvent( EGUI_EVENT_TYPE type ); + + //! sends the event that the file choose process has been canceld + void sendCancelEvent(); + + core::position2d DragStart; + io::path FileName; + core::stringw FileNameW; + io::path FileDirectory; + io::path FileDirectoryFlat; + core::stringw FileDirectoryFlatW; + io::path RestoreDirectory; + io::path StartDirectory; + + IGUIButton* CloseButton; + IGUIButton* OKButton; + IGUIButton* CancelButton; + IGUIListBox* FileBox; + IGUIEditBox* FileNameText; + IGUIElement* EventParent; + io::IFileSystem* FileSystem; + io::IFileList* FileList; + bool Dragging; + }; + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif // __C_GUI_FILE_OPEN_DIALOG_H_INCLUDED__ + diff --git a/source/Irrlicht/CGUIFont.cpp b/source/Irrlicht/CGUIFont.cpp new file mode 100644 index 00000000..08579244 --- /dev/null +++ b/source/Irrlicht/CGUIFont.cpp @@ -0,0 +1,600 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUIFont.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "os.h" +#include "coreutil.h" +#include "IGUIEnvironment.h" +#include "IXMLReader.h" +#include "IReadFile.h" +#include "IVideoDriver.h" +#include "IGUISpriteBank.h" + +namespace irr +{ +namespace gui +{ + +//! constructor +CGUIFont::CGUIFont(IGUIEnvironment *env, const io::path& filename) +: Driver(0), SpriteBank(0), Environment(env), WrongCharacter(0), + MaxHeight(0), GlobalKerningWidth(0), GlobalKerningHeight(0) +{ + #ifdef _DEBUG + setDebugName("CGUIFont"); + #endif + + if (Environment) + { + // don't grab environment, to avoid circular references + Driver = Environment->getVideoDriver(); + + SpriteBank = Environment->getSpriteBank(filename); + if (!SpriteBank) // could be default-font which has no file + SpriteBank = Environment->addEmptySpriteBank(filename); + if (SpriteBank) + SpriteBank->grab(); + } + + if (Driver) + Driver->grab(); + + setInvisibleCharacters ( L" " ); +} + + +//! destructor +CGUIFont::~CGUIFont() +{ + if (Driver) + Driver->drop(); + + if (SpriteBank) + { + SpriteBank->drop(); + // TODO: spritebank still exists in gui-environment and should be removed here when it's + // reference-count is 1. Just can't do that from here at the moment. + // But spritebank would not be able to drop textures anyway because those are in texture-cache + // where they can't be removed unless materials start reference-couting 'em. + } +} + + +//! loads a font file from xml +bool CGUIFont::load(io::IXMLReader* xml, const io::path& directory) +{ + if (!SpriteBank) + return false; + + SpriteBank->clear(); + + while (xml->read()) + { + if (io::EXN_ELEMENT == xml->getNodeType()) + { + if (core::stringw(L"Texture") == xml->getNodeName()) + { + // add a texture + core::stringc fn = xml->getAttributeValue(L"filename"); + u32 i = (u32)xml->getAttributeValueAsInt(L"index"); + core::stringw alpha = xml->getAttributeValue(L"hasAlpha"); + + while (i+1 > SpriteBank->getTextureCount()) + SpriteBank->addTexture(0); + + bool flags[3]; + pushTextureCreationFlags(flags); + + // load texture + io::path textureFullName = core::mergeFilename(directory, fn); + SpriteBank->setTexture(i, Driver->getTexture(textureFullName)); + + popTextureCreationFlags(flags); + + // couldn't load texture, abort. + if (!SpriteBank->getTexture(i)) + { + os::Printer::log("Unable to load all textures in the font, aborting", ELL_ERROR); + return false; + } + else + { + // colorkey texture rather than alpha channel? + 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 + SFontArea a; + SGUISpriteFrame f; + SGUISprite s; + core::rect rectangle; + + a.underhang = xml->getAttributeValueAsInt(L"u"); + a.overhang = xml->getAttributeValueAsInt(L"o"); + a.spriteno = SpriteBank->getSprites().size(); + s32 texno = xml->getAttributeValueAsInt(L"i"); + + // parse rectangle + core::stringc rectstr = xml->getAttributeValue(L"r"); + 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'; + c++; + } + rectangle.UpperLeftCorner.X = val; + while (*c == L' ' || *c == L',') c++; + + val = 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'; + c++; + } + rectangle.LowerRightCorner.X = val; + while (*c == L' ' || *c == L',') c++; + + val = 0; + while (*c >= '0' && *c <= '9') + { + val *= 10; + val += *c - '0'; + c++; + } + rectangle.LowerRightCorner.Y = val; + + CharacterMap.insert(ch,Areas.size()); + + // make frame + f.rectNumber = SpriteBank->getPositions().size(); + f.textureNumber = texno; + + // add frame to sprite + s.Frames.push_back(f); + s.frameTime = 0; + + // add rectangle to sprite bank + SpriteBank->getPositions().push_back(rectangle); + a.width = rectangle.getWidth(); + + // add sprite to sprite bank + SpriteBank->getSprites().push_back(s); + + // add character to font + Areas.push_back(a); + } + } + } + + // set bad character + WrongCharacter = getAreaFromCharacter(L' '); + + setMaxHeight(); + + return true; +} + + +void CGUIFont::setMaxHeight() +{ + if ( !SpriteBank ) + return; + + MaxHeight = 0; + s32 t; + + core::array< core::rect >& p = SpriteBank->getPositions(); + + for (u32 i=0; iMaxHeight) + MaxHeight = t; + } + +} + +void CGUIFont::pushTextureCreationFlags(bool(&flags)[3]) +{ + flags[0] = Driver->getTextureCreationFlag(video::ETCF_ALLOW_NON_POWER_2); + flags[1] = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); + flags[2] = Driver->getTextureCreationFlag(video::ETCF_ALLOW_MEMORY_COPY); + + Driver->setTextureCreationFlag(video::ETCF_ALLOW_NON_POWER_2, true); + Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); + Driver->setTextureCreationFlag(video::ETCF_ALLOW_MEMORY_COPY, true); +} + +void CGUIFont::popTextureCreationFlags(const bool(&flags)[3]) +{ + Driver->setTextureCreationFlag(video::ETCF_ALLOW_NON_POWER_2, flags[0]); + Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, flags[1]); + Driver->setTextureCreationFlag(video::ETCF_ALLOW_MEMORY_COPY, flags[2]); +} + +//! loads a font file, native file needed, for texture parsing +bool CGUIFont::load(io::IReadFile* file) +{ + if (!Driver) + return false; + + return loadTexture(Driver->createImageFromFile(file), + file->getFileName()); +} + + +//! loads a font file, native file needed, for texture parsing +bool CGUIFont::load(const io::path& filename) +{ + if (!Driver) + return false; + + return loadTexture(Driver->createImageFromFile( filename ), + filename); +} + + +//! load & prepare font from ITexture +bool CGUIFont::loadTexture(video::IImage* image, const io::path& name) +{ + if (!image || !SpriteBank) + return false; + + s32 lowerRightPositions = 0; + + video::IImage* tmpImage=image; + bool deleteTmpImage=false; + switch(image->getColorFormat()) + { + case video::ECF_R5G6B5: + tmpImage = Driver->createImage(video::ECF_A1R5G5B5,image->getDimension()); + image->copyTo(tmpImage); + deleteTmpImage=true; + break; + case video::ECF_A1R5G5B5: + case video::ECF_A8R8G8B8: + break; + case video::ECF_R8G8B8: + tmpImage = Driver->createImage(video::ECF_A8R8G8B8,image->getDimension()); + image->copyTo(tmpImage); + deleteTmpImage=true; + break; + default: + os::Printer::log("Unknown texture format provided for CGUIFont::loadTexture", ELL_ERROR); + return false; + } + readPositions(tmpImage, lowerRightPositions); + + WrongCharacter = getAreaFromCharacter(L' '); + + // output warnings + if (!lowerRightPositions || !SpriteBank->getSprites().size()) + os::Printer::log("Either no upper or lower corner pixels in the font file. If this font was made using the new font tool, please load the XML file instead. If not, the font may be corrupted.", ELL_ERROR); + else + if (lowerRightPositions != (s32)SpriteBank->getPositions().size()) + os::Printer::log("The amount of upper corner pixels and the lower corner pixels is not equal, font file may be corrupted.", ELL_ERROR); + + bool ret = ( !SpriteBank->getSprites().empty() && lowerRightPositions ); + + if ( ret ) + { + bool flags[3]; + pushTextureCreationFlags(flags); + + SpriteBank->addTexture(Driver->addTexture(name, tmpImage)); + + popTextureCreationFlags(flags); + } + if (deleteTmpImage) + tmpImage->drop(); + image->drop(); + + setMaxHeight(); + + return ret; +} + + +void CGUIFont::readPositions(video::IImage* image, s32& lowerRightPositions) +{ + if (!SpriteBank ) + return; + + const core::dimension2d size = image->getDimension(); + + video::SColor colorTopLeft = image->getPixel(0,0); + colorTopLeft.setAlpha(255); + image->setPixel(0,0,colorTopLeft); + video::SColor colorLowerRight = image->getPixel(1,0); + video::SColor colorBackGround = image->getPixel(2,0); + video::SColor colorBackGroundTransparent = 0; + + image->setPixel(1,0,colorBackGround); + + // start parsing + + core::position2d pos(0,0); + for (pos.Y=0; pos.Y<(s32)size.Height; ++pos.Y) + { + for (pos.X=0; pos.X<(s32)size.Width; ++pos.X) + { + const video::SColor c = image->getPixel(pos.X, pos.Y); + if (c == colorTopLeft) + { + image->setPixel(pos.X, pos.Y, colorBackGroundTransparent); + SpriteBank->getPositions().push_back(core::rect(pos, pos)); + } + else + if (c == colorLowerRight) + { + // too many lower right points + if (SpriteBank->getPositions().size()<=(u32)lowerRightPositions) + { + lowerRightPositions = 0; + return; + } + + image->setPixel(pos.X, pos.Y, colorBackGroundTransparent); + SpriteBank->getPositions()[lowerRightPositions].LowerRightCorner = pos; + // add frame to sprite bank + SGUISpriteFrame f; + f.rectNumber = lowerRightPositions; + f.textureNumber = 0; + SGUISprite s; + s.Frames.push_back(f); + s.frameTime = 0; + SpriteBank->getSprites().push_back(s); + // add character to font + SFontArea a; + a.overhang = 0; + a.underhang = 0; + a.spriteno = lowerRightPositions; + a.width = SpriteBank->getPositions()[lowerRightPositions].getWidth(); + Areas.push_back(a); + // map letter to character + wchar_t ch = (wchar_t)(lowerRightPositions + 32); + CharacterMap.set(ch, lowerRightPositions); + + ++lowerRightPositions; + } + else + if (c == colorBackGround) + image->setPixel(pos.X, pos.Y, colorBackGroundTransparent); + } + } +} + + +//! set an Pixel Offset on Drawing ( scale position on width ) +void CGUIFont::setKerningWidth(s32 kerning) +{ + GlobalKerningWidth = kerning; +} + + +//! set an Pixel Offset on Drawing ( scale position on width ) +s32 CGUIFont::getKerningWidth(const wchar_t* thisLetter, const wchar_t* previousLetter) const +{ + s32 ret = GlobalKerningWidth; + + if (thisLetter) + { + ret += Areas[getAreaFromCharacter(*thisLetter)].overhang; + + if (previousLetter) + { + ret += Areas[getAreaFromCharacter(*previousLetter)].underhang; + } + } + + return ret; +} + + +//! set an Pixel Offset on Drawing ( scale position on height ) +void CGUIFont::setKerningHeight(s32 kerning) +{ + GlobalKerningHeight = kerning; +} + + +//! set an Pixel Offset on Drawing ( scale position on height ) +s32 CGUIFont::getKerningHeight () const +{ + return GlobalKerningHeight; +} + + +//! returns the sprite number from a given character +u32 CGUIFont::getSpriteNoFromChar(const wchar_t *c) const +{ + return Areas[getAreaFromCharacter(*c)].spriteno; +} + + +s32 CGUIFont::getAreaFromCharacter(const wchar_t c) const +{ + core::map::Node* n = CharacterMap.find(c); + if (n) + return n->getValue(); + else + return WrongCharacter; +} + +void CGUIFont::setInvisibleCharacters( const wchar_t *s ) +{ + Invisible = s; +} + + +//! returns the dimension of text +core::dimension2d CGUIFont::getDimension(const wchar_t* text) const +{ + core::dimension2d dim(0, 0); + core::dimension2d thisLine(0, MaxHeight); + + for (const wchar_t* p = text; *p; ++p) + { + bool lineBreak=false; + if (*p == L'\r') // Mac or Windows breaks + { + lineBreak = true; + if (p[1] == L'\n') // Windows breaks + ++p; + } + else if (*p == L'\n') // Unix breaks + { + lineBreak = true; + } + if (lineBreak) + { + dim.Height += thisLine.Height; + if (dim.Width < thisLine.Width) + dim.Width = thisLine.Width; + thisLine.Width = 0; + continue; + } + + const SFontArea &area = Areas[getAreaFromCharacter(*p)]; + + thisLine.Width += area.underhang; + thisLine.Width += area.width + area.overhang + GlobalKerningWidth; + } + + dim.Height += thisLine.Height; + if (dim.Width < thisLine.Width) + dim.Width = thisLine.Width; + + return dim; +} + +//! draws some text and clips it to the specified rectangle if wanted +void CGUIFont::draw(const core::stringw& text, const core::rect& position, + video::SColor color, + bool hcenter, bool vcenter, const core::rect* clip + ) +{ + if (!Driver || !SpriteBank) + return; + + core::dimension2d textDimension; // NOTE: don't make this u32 or the >> later on can fail when the dimension width is < position width + core::position2d offset = position.UpperLeftCorner; + + if (hcenter || vcenter || clip) + textDimension = getDimension(text.c_str()); + + if (hcenter) + offset.X += (position.getWidth() - textDimension.Width) >> 1; + + if (vcenter) + offset.Y += (position.getHeight() - textDimension.Height) >> 1; + + if (clip) + { + core::rect clippedRect(offset, textDimension); + clippedRect.clipAgainst(*clip); + if (!clippedRect.isValid()) + return; + } + + core::array indices(text.size()); + core::array offsets(text.size()); + + for(u32 i = 0;i < text.size();i++) + { + wchar_t c = text[i]; + + bool lineBreak=false; + if ( c == L'\r') // Mac or Windows breaks + { + lineBreak = true; + if ( text[i + 1] == L'\n') // Windows breaks + c = text[++i]; + } + else if ( c == L'\n') // Unix breaks + { + lineBreak = true; + } + + if (lineBreak) + { + offset.Y += MaxHeight; + offset.X = position.UpperLeftCorner.X; + + if ( hcenter ) + { + offset.X += (position.getWidth() - textDimension.Width) >> 1; + } + continue; + } + + SFontArea& area = Areas[getAreaFromCharacter(c)]; + + offset.X += area.underhang; + if ( Invisible.findFirst ( c ) < 0 ) + { + indices.push_back(area.spriteno); + offsets.push_back(offset); + } + + offset.X += area.width + area.overhang + GlobalKerningWidth; + } + + SpriteBank->draw2DSpriteBatch(indices, offsets, clip, color); +} + + +//! Calculates the index of the character in the text which is on a specific position. +s32 CGUIFont::getCharacterFromPos(const wchar_t* text, s32 pixel_x) const +{ + s32 x = 0; + s32 idx = 0; + + while (text[idx]) + { + const SFontArea& a = Areas[getAreaFromCharacter(text[idx])]; + + x += a.width + a.overhang + a.underhang + GlobalKerningWidth; + + if (x >= pixel_x) + return idx; + + ++idx; + } + + return -1; +} + + +IGUISpriteBank* CGUIFont::getSpriteBank() const +{ + return SpriteBank; +} + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIFont.h b/source/Irrlicht/CGUIFont.h new file mode 100644 index 00000000..c88441e3 --- /dev/null +++ b/source/Irrlicht/CGUIFont.h @@ -0,0 +1,122 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_FONT_H_INCLUDED__ +#define __C_GUI_FONT_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIFontBitmap.h" +#include "irrString.h" +#include "irrMap.h" +#include "IXMLReader.h" +#include "IReadFile.h" +#include "irrArray.h" + +namespace irr +{ + +namespace video +{ + class IVideoDriver; + class IImage; +} + +namespace gui +{ + + class IGUIEnvironment; + +class CGUIFont : public IGUIFontBitmap +{ +public: + + //! constructor + CGUIFont(IGUIEnvironment* env, const io::path& filename); + + //! destructor + virtual ~CGUIFont(); + + //! loads a font from a texture file + bool load(const io::path& filename); + + //! loads a font from a texture file + bool load(io::IReadFile* file); + + //! loads a font from an XML file + //\param directory Directory in which the bitmaps can be found + bool load(io::IXMLReader* xml, const io::path& directory); + + //! draws an text and clips it to the specified rectangle if wanted + virtual void draw(const core::stringw& text, const core::rect& position, + video::SColor color, bool hcenter=false, + bool vcenter=false, const core::rect* clip=0) _IRR_OVERRIDE_; + + //! returns the dimension of a text + virtual core::dimension2d getDimension(const wchar_t* text) const _IRR_OVERRIDE_; + + //! 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 _IRR_OVERRIDE_; + + //! Returns the type of this font + virtual EGUI_FONT_TYPE getType() const _IRR_OVERRIDE_ { return EGFT_BITMAP; } + + //! set an Pixel Offset on Drawing ( scale position on width ) + virtual void setKerningWidth (s32 kerning) _IRR_OVERRIDE_; + virtual void setKerningHeight (s32 kerning) _IRR_OVERRIDE_; + + //! set an Pixel Offset on Drawing ( scale position on width ) + virtual s32 getKerningWidth(const wchar_t* thisLetter=0, const wchar_t* previousLetter=0) const _IRR_OVERRIDE_; + virtual s32 getKerningHeight() const _IRR_OVERRIDE_; + + //! gets the sprite bank + virtual IGUISpriteBank* getSpriteBank() const _IRR_OVERRIDE_; + + //! returns the sprite number from a given character + virtual u32 getSpriteNoFromChar(const wchar_t *c) const _IRR_OVERRIDE_; + + virtual void setInvisibleCharacters( const wchar_t *s ) _IRR_OVERRIDE_; + +private: + + struct SFontArea + { + SFontArea() : underhang(0), overhang(0), width(0), spriteno(0) {} + s32 underhang; + s32 overhang; + s32 width; + u32 spriteno; + }; + + //! load & prepare font from ITexture + bool loadTexture(video::IImage * image, const io::path& name); + + void readPositions(video::IImage* texture, s32& lowerRightPositions); + + s32 getAreaFromCharacter (const wchar_t c) const; + void setMaxHeight(); + + void pushTextureCreationFlags(bool(&flags)[3]); + void popTextureCreationFlags(const bool(&flags)[3]); + + core::array Areas; + core::map CharacterMap; + video::IVideoDriver* Driver; + IGUISpriteBank* SpriteBank; + IGUIEnvironment* Environment; + u32 WrongCharacter; + s32 MaxHeight; + s32 GlobalKerningWidth, GlobalKerningHeight; + + core::stringw Invisible; +}; + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif // __C_GUI_FONT_H_INCLUDED__ + diff --git a/source/Irrlicht/CGUIImage.cpp b/source/Irrlicht/CGUIImage.cpp new file mode 100644 index 00000000..87e5818d --- /dev/null +++ b/source/Irrlicht/CGUIImage.cpp @@ -0,0 +1,221 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUIImage.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" + +namespace irr +{ +namespace gui +{ + + +//! constructor +CGUIImage::CGUIImage(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) +: IGUIImage(environment, parent, id, rectangle), Texture(0), Color(255,255,255,255), + UseAlphaChannel(false), ScaleImage(false), DrawBounds(0.f, 0.f, 1.f, 1.f), DrawBackground(true) +{ + #ifdef _DEBUG + setDebugName("CGUIImage"); + #endif +} + + +//! destructor +CGUIImage::~CGUIImage() +{ + if (Texture) + Texture->drop(); +} + + +//! sets an image +void CGUIImage::setImage(video::ITexture* image) +{ + if (image == Texture) + return; + + if (Texture) + Texture->drop(); + + Texture = image; + + if (Texture) + Texture->grab(); +} + +//! Gets the image texture +video::ITexture* CGUIImage::getImage() const +{ + return Texture; +} + +//! sets the color of the image +void CGUIImage::setColor(video::SColor color) +{ + Color = color; +} + +//! Gets the color of the image +video::SColor CGUIImage::getColor() const +{ + return Color; +} + +//! draws the element and its children +void CGUIImage::draw() +{ + if (!IsVisible) + return; + + IGUISkin* skin = Environment->getSkin(); + video::IVideoDriver* driver = Environment->getVideoDriver(); + + if (Texture) + { + core::rect sourceRect(SourceRect); + if (sourceRect.getWidth() == 0 || sourceRect.getHeight() == 0) + { + sourceRect = core::rect(core::dimension2di(Texture->getOriginalSize())); + } + + if (ScaleImage) + { + const video::SColor Colors[] = {Color,Color,Color,Color}; + + core::rect clippingRect(AbsoluteClippingRect); + checkBounds(clippingRect); + + driver->draw2DImage(Texture, AbsoluteRect, sourceRect, + &clippingRect, Colors, UseAlphaChannel); + } + else + { + core::rect clippingRect(AbsoluteRect.UpperLeftCorner, sourceRect.getSize()); + checkBounds(clippingRect); + clippingRect.clipAgainst(AbsoluteClippingRect); + + driver->draw2DImage(Texture, AbsoluteRect.UpperLeftCorner, sourceRect, + &clippingRect, Color, UseAlphaChannel); + } + } + else if ( DrawBackground ) + { + core::rect clippingRect(AbsoluteClippingRect); + checkBounds(clippingRect); + + skin->draw2DRectangle(this, skin->getColor(EGDC_3D_DARK_SHADOW), AbsoluteRect, &clippingRect); + } + + IGUIElement::draw(); +} + + +//! sets if the image should use its alpha channel to draw itself +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 +{ + return ScaleImage; +} + +//! Returns true if the image is using the alpha channel, false if not +bool CGUIImage::isAlphaChannelUsed() const +{ + return UseAlphaChannel; +} + +//! Sets the source rectangle of the image. By default the full image is used. +void CGUIImage::setSourceRect(const core::rect& sourceRect) +{ + SourceRect = sourceRect; +} + +//! Returns the customized source rectangle of the image to be used. +core::rect CGUIImage::getSourceRect() const +{ + return SourceRect; +} + +//! Restrict target drawing-area. +void CGUIImage::setDrawBounds(const core::rect& drawBoundUVs) +{ + DrawBounds = drawBoundUVs; + DrawBounds.UpperLeftCorner.X = core::clamp(DrawBounds.UpperLeftCorner.X, 0.f, 1.f); + DrawBounds.UpperLeftCorner.Y = core::clamp(DrawBounds.UpperLeftCorner.Y, 0.f, 1.f); + DrawBounds.LowerRightCorner.X = core::clamp(DrawBounds.LowerRightCorner.X, 0.f, 1.f); + DrawBounds.LowerRightCorner.X = core::clamp(DrawBounds.LowerRightCorner.X, 0.f, 1.f); + if ( DrawBounds.UpperLeftCorner.X > DrawBounds.LowerRightCorner.X ) + DrawBounds.UpperLeftCorner.X = DrawBounds.LowerRightCorner.X; + if ( DrawBounds.UpperLeftCorner.Y > DrawBounds.LowerRightCorner.Y ) + DrawBounds.UpperLeftCorner.Y = DrawBounds.LowerRightCorner.Y; +} + +//! Get target drawing-area restrictions. +core::rect CGUIImage::getDrawBounds() const +{ + return DrawBounds; +} + +//! Writes attributes of the element. +void CGUIImage::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const +{ + IGUIImage::serializeAttributes(out,options); + + out->addTexture ("Texture", Texture); + out->addBool ("UseAlphaChannel", UseAlphaChannel); + out->addColor ("Color", Color); + out->addBool ("ScaleImage", ScaleImage); + out->addRect ("SourceRect", SourceRect); + out->addFloat ("DrawBoundsX1", DrawBounds.UpperLeftCorner.X); + out->addFloat ("DrawBoundsY1", DrawBounds.UpperLeftCorner.Y); + out->addFloat ("DrawBoundsX2", DrawBounds.LowerRightCorner.X); + out->addFloat ("DrawBoundsY2", DrawBounds.LowerRightCorner.Y); + out->addBool ("DrawBackground", DrawBackground); +} + + +//! Reads attributes of the element +void CGUIImage::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) +{ + IGUIImage::deserializeAttributes(in,options); + + setImage(in->getAttributeAsTexture("Texture", Texture)); + setUseAlphaChannel(in->getAttributeAsBool("UseAlphaChannel", UseAlphaChannel)); + setColor(in->getAttributeAsColor("Color", Color)); + setScaleImage(in->getAttributeAsBool("ScaleImage", ScaleImage)); + setSourceRect(in->getAttributeAsRect("SourceRect", SourceRect)); + + DrawBounds.UpperLeftCorner.X = in->getAttributeAsFloat("DrawBoundsX1", DrawBounds.UpperLeftCorner.X); + DrawBounds.UpperLeftCorner.Y = in->getAttributeAsFloat("DrawBoundsY1", DrawBounds.UpperLeftCorner.Y); + DrawBounds.LowerRightCorner.X = in->getAttributeAsFloat("DrawBoundsX2", DrawBounds.LowerRightCorner.X); + DrawBounds.LowerRightCorner.Y = in->getAttributeAsFloat("DrawBoundsY2", DrawBounds.LowerRightCorner.Y); + setDrawBounds(DrawBounds); + + setDrawBackground(in->getAttributeAsBool("DrawBackground", DrawBackground)); +} + + +} // end namespace gui +} // end namespace irr + + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIImage.h b/source/Irrlicht/CGUIImage.h new file mode 100644 index 00000000..034a8903 --- /dev/null +++ b/source/Irrlicht/CGUIImage.h @@ -0,0 +1,113 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_IMAGE_H_INCLUDED__ +#define __C_GUI_IMAGE_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIImage.h" + +namespace irr +{ +namespace gui +{ + + class CGUIImage : public IGUIImage + { + public: + + //! constructor + CGUIImage(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle); + + //! destructor + virtual ~CGUIImage(); + + //! sets an image + virtual void setImage(video::ITexture* image) _IRR_OVERRIDE_; + + //! Gets the image texture + virtual video::ITexture* getImage() const _IRR_OVERRIDE_; + + //! sets the color of the image + virtual void setColor(video::SColor color) _IRR_OVERRIDE_; + + //! sets if the image should scale to fit the element + virtual void setScaleImage(bool scale) _IRR_OVERRIDE_; + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + //! sets if the image should use its alpha channel to draw itself + virtual void setUseAlphaChannel(bool use) _IRR_OVERRIDE_; + + //! Gets the color of the image + virtual video::SColor getColor() const _IRR_OVERRIDE_; + + //! Returns true if the image is scaled to fit, false if not + virtual bool isImageScaled() const _IRR_OVERRIDE_; + + //! Returns true if the image is using the alpha channel, false if not + virtual bool isAlphaChannelUsed() const _IRR_OVERRIDE_; + + //! Sets the source rectangle of the image. By default the full image is used. + virtual void setSourceRect(const core::rect& sourceRect) _IRR_OVERRIDE_; + + //! Returns the customized source rectangle of the image to be used. + virtual core::rect getSourceRect() const _IRR_OVERRIDE_; + + //! Restrict drawing-area. + virtual void setDrawBounds(const core::rect& drawBoundUVs) _IRR_OVERRIDE_; + + //! Get drawing-area restrictions. + virtual core::rect getDrawBounds() const _IRR_OVERRIDE_; + + //! Sets whether to draw a background color (EGDC_3D_DARK_SHADOW) when no texture is set + virtual void setDrawBackground(bool draw) _IRR_OVERRIDE_ + { + DrawBackground = draw; + } + + //! Checks if a background is drawn when no texture is set + virtual bool isDrawBackgroundEnabled() const _IRR_OVERRIDE_ + { + return DrawBackground; + } + + //! Writes attributes of the element. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the element + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + + protected: + void checkBounds(core::rect& rect) + { + f32 clipWidth = (f32)rect.getWidth(); + f32 clipHeight = (f32)rect.getHeight(); + + rect.UpperLeftCorner.X += core::round32(DrawBounds.UpperLeftCorner.X*clipWidth); + rect.UpperLeftCorner.Y += core::round32(DrawBounds.UpperLeftCorner.Y*clipHeight); + rect.LowerRightCorner.X -= core::round32((1.f-DrawBounds.LowerRightCorner.X)*clipWidth); + rect.LowerRightCorner.Y -= core::round32((1.f-DrawBounds.LowerRightCorner.Y)*clipHeight); + } + + private: + video::ITexture* Texture; + video::SColor Color; + bool UseAlphaChannel; + bool ScaleImage; + core::rect SourceRect; + core::rect DrawBounds; + bool DrawBackground; + }; + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif // __C_GUI_IMAGE_H_INCLUDED__ diff --git a/source/Irrlicht/CGUIImageList.cpp b/source/Irrlicht/CGUIImageList.cpp new file mode 100644 index 00000000..2896712a --- /dev/null +++ b/source/Irrlicht/CGUIImageList.cpp @@ -0,0 +1,93 @@ +// This file is part of the "Irrlicht Engine". +// written by Reinhard Ostermeier, reinhard@nospam.r-ostermeier.de +// modified by Thomas Alten + +#include "CGUIImageList.h" + + +namespace irr +{ +namespace gui +{ + +//! constructor +CGUIImageList::CGUIImageList( video::IVideoDriver* driver ) + : Driver( driver ), + Texture( 0 ), + ImageCount( 0 ), + ImageSize( 0, 0 ), + ImagesPerRow( 0 ), + UseAlphaChannel( false ) +{ + #ifdef _DEBUG + setDebugName( "CGUIImageList" ); + #endif + + if( Driver ) + { + Driver->grab(); + } +} + + + +//! destructor +CGUIImageList::~CGUIImageList() +{ + if( Driver ) + { + Driver->drop(); + } + + if( Texture ) + { + Texture->drop(); + } +} + + +//! Creates the image list from texture. +bool CGUIImageList::createImageList(video::ITexture* texture, + core::dimension2d imageSize, + bool useAlphaChannel) +{ + if( !texture ) + { + return false; + } + + Texture = texture; + Texture->grab(); + + ImageSize = imageSize; + + ImagesPerRow = Texture->getSize().Width / ImageSize.Width; + ImageCount = ImagesPerRow * Texture->getSize().Height / ImageSize.Height; + + UseAlphaChannel = useAlphaChannel; + + return true; +} + +//! Draws an image and clips it to the specified rectangle if wanted +void CGUIImageList::draw( s32 index, const core::position2d& destPos, + const core::rect* clip /*= 0*/ ) +{ + core::rect sourceRect; + + if( !Driver || index < 0 || index >= ImageCount ) + { + return; + } + + sourceRect.UpperLeftCorner.X = ( index % ImagesPerRow ) * ImageSize.Width; + sourceRect.UpperLeftCorner.Y = ( index / ImagesPerRow ) * ImageSize.Height; + sourceRect.LowerRightCorner.X = sourceRect.UpperLeftCorner.X + ImageSize.Width; + sourceRect.LowerRightCorner.Y = sourceRect.UpperLeftCorner.Y + ImageSize.Height; + + Driver->draw2DImage( Texture, destPos, sourceRect, clip, + video::SColor( 255, 255, 255, 255 ), UseAlphaChannel ); +} + +} // end namespace gui +} // end namespace irr diff --git a/source/Irrlicht/CGUIImageList.h b/source/Irrlicht/CGUIImageList.h new file mode 100644 index 00000000..5ca4c992 --- /dev/null +++ b/source/Irrlicht/CGUIImageList.h @@ -0,0 +1,67 @@ +// This file is part of the "Irrlicht Engine". +// written by Reinhard Ostermeier, reinhard@nospam.r-ostermeier.de + +#ifndef __C_GUI_IMAGE_LIST_H_INCLUDED__ +#define __C_GUI_IMAGE_LIST_H_INCLUDED__ + +#include "IGUIImageList.h" +#include "IVideoDriver.h" + +namespace irr +{ +namespace gui +{ + +class CGUIImageList : public IGUIImageList +{ +public: + + //! constructor + CGUIImageList( video::IVideoDriver* Driver ); + + //! destructor + virtual ~CGUIImageList(); + + //! Creates the image list from texture. + //! \param texture: The texture to use + //! \param imageSize: Size of a single image + //! \param useAlphaChannel: true if the alpha channel from the texture should be used + //! \return + //! true if the image list was created + bool createImageList(video::ITexture* texture, + core::dimension2d imageSize, + bool useAlphaChannel); + + //! Draws an image and clips it to the specified rectangle if wanted + //! \param index: Index of the image + //! \param destPos: Position of the image to draw + //! \param clip: Optional pointer to a rectangle against which the text will be clipped. + //! If the pointer is null, no clipping will be done. + virtual void draw( s32 index, const core::position2d& destPos, + const core::rect* clip = 0 ) _IRR_OVERRIDE_; + + //! Returns the count of Images in the list. + //! \return Returns the count of Images in the list. + virtual s32 getImageCount() const _IRR_OVERRIDE_ + { return ImageCount; } + + //! Returns the size of the images in the list. + //! \return Returns the size of the images in the list. + virtual core::dimension2d getImageSize() const _IRR_OVERRIDE_ + { return ImageSize; } + +private: + + video::IVideoDriver* Driver; + video::ITexture* Texture; + s32 ImageCount; + core::dimension2d ImageSize; + s32 ImagesPerRow; + bool UseAlphaChannel; +}; + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CGUIInOutFader.cpp b/source/Irrlicht/CGUIInOutFader.cpp new file mode 100644 index 00000000..0239db1c --- /dev/null +++ b/source/Irrlicht/CGUIInOutFader.cpp @@ -0,0 +1,178 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUIInOutFader.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" +#include "os.h" + +namespace irr +{ +namespace gui +{ + + +//! constructor +CGUIInOutFader::CGUIInOutFader(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) +: IGUIInOutFader(environment, parent, id, rectangle) +{ + #ifdef _DEBUG + setDebugName("CGUIInOutFader"); + #endif + + Action = EFA_NOTHING; + StartTime = 0; + EndTime = 0; + + setColor(video::SColor(0,0,0,0)); +} + + +//! draws the element and its children +void CGUIInOutFader::draw() +{ + if (!IsVisible || !Action) + return; + + u32 now = os::Timer::getTime(); + if (now > EndTime && Action == EFA_FADE_IN) + { + Action = EFA_NOTHING; + return; + } + + video::IVideoDriver* driver = Environment->getVideoDriver(); + + if (driver) + { + f32 d; + + if (now > EndTime) + d = 0.0f; + else + d = (EndTime - now) / (f32)(EndTime - StartTime); + + video::SColor newCol = FullColor.getInterpolated(TransColor, d); + driver->draw2DRectangle(newCol, AbsoluteRect, &AbsoluteClippingRect); + } + + IGUIElement::draw(); +} + + +//! Gets the color to fade out to or to fade in from. +video::SColor CGUIInOutFader::getColor() const +{ + return Color[1]; +} + + +//! Sets the color to fade out to or to fade in from. +void CGUIInOutFader::setColor(video::SColor color) +{ + video::SColor s = color; + video::SColor d = color; + + s.setAlpha ( 255 ); + d.setAlpha ( 0 ); + setColor ( s,d ); + +/* + Color[0] = color; + + FullColor = Color[0]; + TransColor = Color[0]; + + if (Action == EFA_FADE_OUT) + { + FullColor.setAlpha(0); + TransColor.setAlpha(255); + } + else + if (Action == EFA_FADE_IN) + { + FullColor.setAlpha(255); + TransColor.setAlpha(0); + } +*/ +} + + +void CGUIInOutFader::setColor(video::SColor source, video::SColor dest) +{ + Color[0] = source; + Color[1] = dest; + + if (Action == EFA_FADE_OUT) + { + FullColor = Color[1]; + TransColor = Color[0]; + } + else + if (Action == EFA_FADE_IN) + { + FullColor = Color[0]; + TransColor = Color[1]; + } + +} + + +//! Returns if the fade in or out process is done. +bool CGUIInOutFader::isReady() const +{ + u32 now = os::Timer::getTime(); + bool ret = (now > EndTime); + return ret; +} + + +//! Starts the fade in process. +void CGUIInOutFader::fadeIn(u32 time) +{ + StartTime = os::Timer::getTime(); + EndTime = StartTime + time; + Action = EFA_FADE_IN; + setColor(Color[0],Color[1]); +} + + +//! Starts the fade out process. +void CGUIInOutFader::fadeOut(u32 time) +{ + StartTime = os::Timer::getTime(); + EndTime = StartTime + time; + Action = EFA_FADE_OUT; + setColor(Color[0],Color[1]); +} + + +//! Writes attributes of the element. +void CGUIInOutFader::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const +{ + IGUIInOutFader::serializeAttributes(out,options); + + out->addColor ("FullColor", FullColor); + out->addColor ("TransColor", TransColor); + +} + + +//! Reads attributes of the element +void CGUIInOutFader::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) +{ + IGUIInOutFader::deserializeAttributes(in,options); + + FullColor = in->getAttributeAsColor("FullColor"); + TransColor = in->getAttributeAsColor("TransColor"); +} + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIInOutFader.h b/source/Irrlicht/CGUIInOutFader.h new file mode 100644 index 00000000..1fdb6bb3 --- /dev/null +++ b/source/Irrlicht/CGUIInOutFader.h @@ -0,0 +1,75 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_IN_OUT_FADER_H_INCLUDED__ +#define __C_GUI_IN_OUT_FADER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIInOutFader.h" + +namespace irr +{ +namespace gui +{ + + class CGUIInOutFader : public IGUIInOutFader + { + public: + + //! constructor + CGUIInOutFader(IGUIEnvironment* environment, IGUIElement* parent, + s32 id, core::rect rectangle); + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + //! Gets the color to fade out to or to fade in from. + virtual video::SColor getColor() const _IRR_OVERRIDE_; + + //! Sets the color to fade out to or to fade in from. + virtual void setColor(video::SColor color ) _IRR_OVERRIDE_; + virtual void setColor(video::SColor source, video::SColor dest) _IRR_OVERRIDE_; + + //! Starts the fade in process. + virtual void fadeIn(u32 time) _IRR_OVERRIDE_; + + //! Starts the fade out process. + virtual void fadeOut(u32 time) _IRR_OVERRIDE_; + + //! Returns if the fade in or out process is done. + virtual bool isReady() const _IRR_OVERRIDE_; + + //! Writes attributes of the element. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the element + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + + private: + + enum EFadeAction + { + EFA_NOTHING = 0, + EFA_FADE_IN, + EFA_FADE_OUT + }; + + u32 StartTime; + u32 EndTime; + EFadeAction Action; + + video::SColor Color[2]; + video::SColor FullColor; + video::SColor TransColor; + }; + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif // __C_GUI_IN_OUT_FADER_H_INCLUDED__ + diff --git a/source/Irrlicht/CGUIListBox.cpp b/source/Irrlicht/CGUIListBox.cpp new file mode 100644 index 00000000..39e35916 --- /dev/null +++ b/source/Irrlicht/CGUIListBox.cpp @@ -0,0 +1,923 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUIListBox.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "CGUIListBox.h" +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" +#include "IGUIFont.h" +#include "IGUISpriteBank.h" +#include "CGUIScrollBar.h" +#include "os.h" + +namespace irr +{ +namespace gui +{ + +//! constructor +CGUIListBox::CGUIListBox(IGUIEnvironment* environment, IGUIElement* parent, + s32 id, core::rect rectangle, bool clip, + bool drawBack, bool moveOverSelect) +: IGUIListBox(environment, parent, id, rectangle), Selected(-1), + ItemHeight(0),ItemHeightOverride(0), + TotalItemHeight(0), ItemsIconWidth(0), Font(0), IconBank(0), + ScrollBar(0), selectTime(0), LastKeyTime(0), Selecting(false), DrawBack(drawBack), + MoveOverSelect(moveOverSelect), AutoScroll(true), HighlightWhenNotFocused(true) +{ + #ifdef _DEBUG + setDebugName("CGUIListBox"); + #endif + + IGUISkin* skin = Environment->getSkin(); + + ScrollBar = new CGUIScrollBar(false, Environment, this, -1, + core::recti(0, 0, 1, 1), + !clip); + ScrollBar->setSubElement(true); + ScrollBar->setTabStop(false); + ScrollBar->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + ScrollBar->setVisible(false); + ScrollBar->setPos(0); + + updateScrollBarSize(skin->getSize(EGDS_SCROLLBAR_SIZE)); + + setNotClipped(!clip); + + // this element can be tabbed to + setTabStop(true); + setTabOrder(-1); + + updateAbsolutePosition(); +} + + +//! destructor +CGUIListBox::~CGUIListBox() +{ + if (ScrollBar) + ScrollBar->drop(); + + if (Font) + Font->drop(); + + if (IconBank) + IconBank->drop(); +} + + +//! returns amount of list items +u32 CGUIListBox::getItemCount() const +{ + return Items.size(); +} + + +//! returns string of a list item. the may be a value from 0 to itemCount-1 +const wchar_t* CGUIListBox::getListItem(u32 id) const +{ + if (id>=Items.size()) + return 0; + + return Items[id].Text.c_str(); +} + + +//! Returns the icon of an item +s32 CGUIListBox::getIcon(u32 id) const +{ + if (id>=Items.size()) + return -1; + + return Items[id].Icon; +} + + +//! adds a list item, returns id of item +u32 CGUIListBox::addItem(const wchar_t* text) +{ + return addItem(text, -1); +} + + +//! adds a list item, returns id of item +void CGUIListBox::removeItem(u32 id) +{ + if (id >= Items.size()) + return; + + if ((u32)Selected==id) + { + Selected = -1; + } + else if ((u32)Selected > id) + { + Selected -= 1; + selectTime = os::Timer::getTime(); + } + + Items.erase(id); + + recalculateItemHeight(); +} + + +s32 CGUIListBox::getItemAt(s32 xpos, s32 ypos) const +{ + if ( xpos < AbsoluteRect.UpperLeftCorner.X || xpos >= AbsoluteRect.LowerRightCorner.X + || ypos < AbsoluteRect.UpperLeftCorner.Y || ypos >= AbsoluteRect.LowerRightCorner.Y + ) + return -1; + + if ( ItemHeight == 0 ) + return -1; + + s32 item = ((ypos - AbsoluteRect.UpperLeftCorner.Y - 1) + ScrollBar->getPos()) / ItemHeight; + if ( item < 0 || item >= (s32)Items.size()) + return -1; + + return item; +} + +//! clears the list +void CGUIListBox::clear() +{ + Items.clear(); + ItemsIconWidth = 0; + Selected = -1; + + ScrollBar->setPos(0); + + recalculateItemHeight(); +} + + +void CGUIListBox::recalculateItemHeight() +{ + IGUISkin* skin = Environment->getSkin(); + + if (Font != skin->getFont()) + { + if (Font) + Font->drop(); + + Font = skin->getFont(); + if ( 0 == ItemHeightOverride ) + ItemHeight = 0; + + if (Font) + { + if ( 0 == ItemHeightOverride ) + ItemHeight = Font->getDimension(L"A").Height + 4; + + Font->grab(); + } + } + + TotalItemHeight = ItemHeight * Items.size(); + ScrollBar->setMax( core::max_(0, TotalItemHeight - AbsoluteRect.getHeight()) ); + s32 minItemHeight = ItemHeight > 0 ? ItemHeight : 1; + ScrollBar->setSmallStep ( minItemHeight ); + ScrollBar->setLargeStep ( 2*minItemHeight ); + + if ( TotalItemHeight <= AbsoluteRect.getHeight() ) + ScrollBar->setVisible(false); + else + ScrollBar->setVisible(true); +} + +//! returns id of selected item. returns -1 if no item is selected. +s32 CGUIListBox::getSelected() const +{ + return Selected; +} + + +//! sets the selected item. Set this to -1 if no item should be selected +void CGUIListBox::setSelected(s32 id) +{ + if ((u32)id>=Items.size()) + Selected = -1; + else + Selected = id; + + selectTime = os::Timer::getTime(); + + recalculateScrollPos(); +} + +//! sets the selected item. Set this to -1 if no item should be selected +void CGUIListBox::setSelected(const wchar_t *item) +{ + s32 index = -1; + + if ( item ) + { + for ( index = 0; index < (s32) Items.size(); ++index ) + { + if ( Items[index].Text == item ) + break; + } + } + setSelected ( index ); +} + +//! called if an event happened. +bool CGUIListBox::OnEvent(const SEvent& event) +{ + if (isEnabled()) + { + switch(event.EventType) + { + case EET_KEY_INPUT_EVENT: + if (event.KeyInput.PressedDown && + (event.KeyInput.Key == KEY_DOWN || + event.KeyInput.Key == KEY_UP || + event.KeyInput.Key == KEY_HOME || + event.KeyInput.Key == KEY_END || + event.KeyInput.Key == KEY_NEXT || + event.KeyInput.Key == KEY_PRIOR ) ) + { + s32 oldSelected = Selected; + switch (event.KeyInput.Key) + { + case KEY_DOWN: + Selected += 1; + break; + case KEY_UP: + Selected -= 1; + break; + case KEY_HOME: + Selected = 0; + break; + case KEY_END: + Selected = (s32)Items.size()-1; + break; + case KEY_NEXT: + Selected += AbsoluteRect.getHeight() / ItemHeight; + break; + case KEY_PRIOR: + Selected -= AbsoluteRect.getHeight() / ItemHeight; + break; + default: + break; + } + if (Selected<0) + Selected = 0; + if (Selected >= (s32)Items.size()) + Selected = Items.size() - 1; // will set Selected to -1 for empty listboxes which is correct + + + recalculateScrollPos(); + + // post the news + + if (oldSelected != Selected && Parent && !Selecting && !MoveOverSelect) + { + SEvent e; + e.EventType = EET_GUI_EVENT; + e.GUIEvent.Caller = this; + e.GUIEvent.Element = 0; + e.GUIEvent.EventType = EGET_LISTBOX_CHANGED; + Parent->OnEvent(e); + } + + return true; + } + else + if (!event.KeyInput.PressedDown && ( event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE ) ) + { + if (Parent) + { + SEvent e; + e.EventType = EET_GUI_EVENT; + e.GUIEvent.Caller = this; + e.GUIEvent.Element = 0; + e.GUIEvent.EventType = EGET_LISTBOX_SELECTED_AGAIN; + Parent->OnEvent(e); + } + return true; + } + else if (event.KeyInput.Key == KEY_TAB ) + { + return false; + } + else if (event.KeyInput.PressedDown && event.KeyInput.Char) + { + // change selection based on text as it is typed. + u32 now = os::Timer::getTime(); + + if (now - LastKeyTime < 500) + { + // add to key buffer if it isn't a key repeat + if (!(KeyBuffer.size() == 1 && KeyBuffer[0] == event.KeyInput.Char)) + { + KeyBuffer += L" "; + KeyBuffer[KeyBuffer.size()-1] = event.KeyInput.Char; + } + } + else + { + KeyBuffer = L" "; + KeyBuffer[0] = event.KeyInput.Char; + } + LastKeyTime = now; + + // find the selected item, starting at the current selection + s32 start = Selected; + // dont change selection if the key buffer matches the current item + if (Selected > -1 && KeyBuffer.size() > 1) + { + if (Items[Selected].Text.size() >= KeyBuffer.size() && + KeyBuffer.equals_ignore_case(Items[Selected].Text.subString(0,KeyBuffer.size()))) + return true; + } + + s32 current; + for (current = start+1; current < (s32)Items.size(); ++current) + { + if (Items[current].Text.size() >= KeyBuffer.size()) + { + if (KeyBuffer.equals_ignore_case(Items[current].Text.subString(0,KeyBuffer.size()))) + { + if (Parent && Selected != current && !Selecting && !MoveOverSelect) + { + SEvent e; + e.EventType = EET_GUI_EVENT; + e.GUIEvent.Caller = this; + e.GUIEvent.Element = 0; + e.GUIEvent.EventType = EGET_LISTBOX_CHANGED; + Parent->OnEvent(e); + } + setSelected(current); + return true; + } + } + } + for (current = 0; current <= start; ++current) + { + if (Items[current].Text.size() >= KeyBuffer.size()) + { + if (KeyBuffer.equals_ignore_case(Items[current].Text.subString(0,KeyBuffer.size()))) + { + if (Parent && Selected != current && !Selecting && !MoveOverSelect) + { + Selected = current; + SEvent e; + e.EventType = EET_GUI_EVENT; + e.GUIEvent.Caller = this; + e.GUIEvent.Element = 0; + e.GUIEvent.EventType = EGET_LISTBOX_CHANGED; + Parent->OnEvent(e); + } + setSelected(current); + return true; + } + } + } + + return true; + } + break; + + case EET_GUI_EVENT: + switch(event.GUIEvent.EventType) + { + case gui::EGET_SCROLL_BAR_CHANGED: + if (event.GUIEvent.Caller == ScrollBar) + return true; + break; + case gui::EGET_ELEMENT_FOCUS_LOST: + { + if (event.GUIEvent.Caller == this) + Selecting = false; + } + default: + break; + } + break; + + case EET_MOUSE_INPUT_EVENT: + { + core::position2d p(event.MouseInput.X, event.MouseInput.Y); + + switch(event.MouseInput.Event) + { + case EMIE_MOUSE_WHEEL: + ScrollBar->setPos(ScrollBar->getPos() + (event.MouseInput.Wheel < 0 ? -1 : 1)*-ItemHeight/2); + return true; + + case EMIE_LMOUSE_PRESSED_DOWN: + { + Selecting = true; + return true; + } + + case EMIE_LMOUSE_LEFT_UP: + { + Selecting = false; + + if (isPointInside(p)) + selectNew(event.MouseInput.Y); + + return true; + } + + case EMIE_MOUSE_MOVED: + if (Selecting || MoveOverSelect) + { + if (isPointInside(p)) + { + selectNew(event.MouseInput.Y, true); + return true; + } + } + default: + break; + } + } + break; + default: + break; + } + } + + return IGUIElement::OnEvent(event); +} + + +void CGUIListBox::selectNew(s32 ypos, bool onlyHover) +{ + u32 now = os::Timer::getTime(); + s32 oldSelected = Selected; + + Selected = getItemAt(AbsoluteRect.UpperLeftCorner.X, ypos); + if (Selected<0 && !Items.empty()) + Selected = 0; + + recalculateScrollPos(); + + gui::EGUI_EVENT_TYPE eventType = (Selected == oldSelected && now < selectTime + 500) ? EGET_LISTBOX_SELECTED_AGAIN : EGET_LISTBOX_CHANGED; + selectTime = now; + // post the news + if (Parent && !onlyHover) + { + SEvent event; + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.Element = 0; + event.GUIEvent.EventType = eventType; + Parent->OnEvent(event); + } +} + + +//! Update the position and size of the listbox, and update the scrollbar +void CGUIListBox::updateAbsolutePosition() +{ + IGUIElement::updateAbsolutePosition(); + + recalculateItemHeight(); +} + + +//! draws the element and its children +void CGUIListBox::draw() +{ + if (!IsVisible) + return; + + recalculateItemHeight(); // if the font changed + + IGUISkin* skin = Environment->getSkin(); + updateScrollBarSize(skin->getSize(EGDS_SCROLLBAR_SIZE)); + + core::rect* clipRect = 0; + + // draw background + core::rect frameRect(AbsoluteRect); + + // draw items + + core::rect clientClip(AbsoluteRect); + clientClip.UpperLeftCorner.Y += 1; + clientClip.UpperLeftCorner.X += 1; + if (ScrollBar->isVisible()) + clientClip.LowerRightCorner.X -= ScrollBar->getRelativePosition().getWidth(); + clientClip.LowerRightCorner.Y -= 1; + clientClip.clipAgainst(AbsoluteClippingRect); + + skin->draw3DSunkenPane(this, skin->getColor(EGDC_3D_HIGH_LIGHT), true, + DrawBack, frameRect, &AbsoluteClippingRect); + + if (clipRect) + clientClip.clipAgainst(*clipRect); + + frameRect = AbsoluteRect; + frameRect.UpperLeftCorner.X += 1; + if (ScrollBar->isVisible()) + frameRect.LowerRightCorner.X -= ScrollBar->getRelativePosition().getWidth(); + + frameRect.LowerRightCorner.Y = AbsoluteRect.UpperLeftCorner.Y + ItemHeight; + + frameRect.UpperLeftCorner.Y -= ScrollBar->getPos(); + frameRect.LowerRightCorner.Y -= ScrollBar->getPos(); + + bool hl = (HighlightWhenNotFocused || Environment->hasFocus(this) || Environment->hasFocus(ScrollBar)); + + for (s32 i=0; i<(s32)Items.size(); ++i) + { + if (frameRect.LowerRightCorner.Y >= AbsoluteRect.UpperLeftCorner.Y && + frameRect.UpperLeftCorner.Y <= AbsoluteRect.LowerRightCorner.Y) + { + if (i == Selected && hl) + skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), frameRect, &clientClip); + + core::rect textRect = frameRect; + textRect.UpperLeftCorner.X += 3; + + if (Font) + { + if (IconBank && (Items[i].Icon > -1)) + { + core::position2di iconPos = textRect.UpperLeftCorner; + iconPos.Y += textRect.getHeight() / 2; + iconPos.X += ItemsIconWidth/2; + + if ( i==Selected && hl ) + { + IconBank->draw2DSprite( (u32)Items[i].Icon, iconPos, &clientClip, + hasItemOverrideColor(i, EGUI_LBC_ICON_HIGHLIGHT) ? + getItemOverrideColor(i, EGUI_LBC_ICON_HIGHLIGHT) : getItemDefaultColor(EGUI_LBC_ICON_HIGHLIGHT), + selectTime, os::Timer::getTime(), false, true); + } + else + { + IconBank->draw2DSprite( (u32)Items[i].Icon, iconPos, &clientClip, + hasItemOverrideColor(i, EGUI_LBC_ICON) ? getItemOverrideColor(i, EGUI_LBC_ICON) : getItemDefaultColor(EGUI_LBC_ICON), + 0 , (i==Selected) ? os::Timer::getTime() : 0, false, true); + } + } + + textRect.UpperLeftCorner.X += ItemsIconWidth+3; + + if ( i==Selected && hl ) + { + Font->draw(Items[i].Text.c_str(), textRect, + hasItemOverrideColor(i, EGUI_LBC_TEXT_HIGHLIGHT) ? + getItemOverrideColor(i, EGUI_LBC_TEXT_HIGHLIGHT) : getItemDefaultColor(EGUI_LBC_TEXT_HIGHLIGHT), + false, true, &clientClip); + } + else + { + Font->draw(Items[i].Text.c_str(), textRect, + hasItemOverrideColor(i, EGUI_LBC_TEXT) ? getItemOverrideColor(i, EGUI_LBC_TEXT) : getItemDefaultColor(EGUI_LBC_TEXT), + false, true, &clientClip); + } + + textRect.UpperLeftCorner.X -= ItemsIconWidth+3; + } + } + + frameRect.UpperLeftCorner.Y += ItemHeight; + frameRect.LowerRightCorner.Y += ItemHeight; + } + + IGUIElement::draw(); +} + + +//! adds an list item with an icon +u32 CGUIListBox::addItem(const wchar_t* text, s32 icon) +{ + ListItem i; + i.Text = text; + i.Icon = icon; + + Items.push_back(i); + recalculateItemHeight(); + recalculateItemWidth(icon); + + return Items.size() - 1; +} + + +void CGUIListBox::setSpriteBank(IGUISpriteBank* bank) +{ + if ( bank == IconBank ) + return; + if (IconBank) + IconBank->drop(); + + IconBank = bank; + if (IconBank) + IconBank->grab(); +} + + +void CGUIListBox::recalculateScrollPos() +{ + if (!AutoScroll) + return; + + const s32 selPos = (Selected == -1 ? TotalItemHeight : Selected * ItemHeight) - ScrollBar->getPos(); + + if (selPos < 0) + { + ScrollBar->setPos(ScrollBar->getPos() + selPos); + } + else + if (selPos > AbsoluteRect.getHeight() - ItemHeight) + { + ScrollBar->setPos(ScrollBar->getPos() + selPos - AbsoluteRect.getHeight() + ItemHeight); + } +} + +void CGUIListBox::updateScrollBarSize(s32 size) +{ + if ( size != ScrollBar->getRelativePosition().getWidth() ) + { + core::recti r(RelativeRect.getWidth() - size, 0, RelativeRect.getWidth(), RelativeRect.getHeight()); + ScrollBar->setRelativePosition(r); + } +} + +void CGUIListBox::setAutoScrollEnabled(bool scroll) +{ + AutoScroll = scroll; +} + + +bool CGUIListBox::isAutoScrollEnabled() const +{ + return AutoScroll; +} + + +bool CGUIListBox::getSerializationLabels(EGUI_LISTBOX_COLOR colorType, core::stringc & useColorLabel, core::stringc & colorLabel) const +{ + switch ( colorType ) + { + case EGUI_LBC_TEXT: + useColorLabel = "UseColText"; + colorLabel = "ColText"; + break; + case EGUI_LBC_TEXT_HIGHLIGHT: + useColorLabel = "UseColTextHl"; + colorLabel = "ColTextHl"; + break; + case EGUI_LBC_ICON: + useColorLabel = "UseColIcon"; + colorLabel = "ColIcon"; + break; + case EGUI_LBC_ICON_HIGHLIGHT: + useColorLabel = "UseColIconHl"; + colorLabel = "ColIconHl"; + break; + default: + return false; + } + return true; +} + + +//! Writes attributes of the element. +void CGUIListBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const +{ + IGUIListBox::serializeAttributes(out,options); + + // todo: out->addString ("IconBank", IconBank->getName?); + out->addBool ("DrawBack", DrawBack); + out->addBool ("MoveOverSelect", MoveOverSelect); + out->addBool ("AutoScroll", AutoScroll); + + out->addInt("ItemCount", Items.size()); + for (u32 i=0;iaddString(label.c_str(), Items[i].Text.c_str() ); + + for ( s32 c=0; c < (s32)EGUI_LBC_COUNT; ++c ) + { + core::stringc useColorLabel, colorLabel; + if ( !getSerializationLabels((EGUI_LISTBOX_COLOR)c, useColorLabel, colorLabel) ) + return; + label = useColorLabel; label += i; + if ( Items[i].OverrideColors[c].Use ) + { + out->addBool(label.c_str(), true ); + label = colorLabel; label += i; + out->addColor(label.c_str(), Items[i].OverrideColors[c].Color); + } + else + { + out->addBool(label.c_str(), false ); + } + } + } +} + + +//! Reads attributes of the element +void CGUIListBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) +{ + clear(); + + DrawBack = in->getAttributeAsBool("DrawBack", DrawBack); + MoveOverSelect = in->getAttributeAsBool("MoveOverSelect", MoveOverSelect); + AutoScroll = in->getAttributeAsBool("AutoScroll", AutoScroll); + + IGUIListBox::deserializeAttributes(in,options); + + const s32 count = in->getAttributeAsInt("ItemCount"); + for (s32 i=0; igetAttributeAsStringW(label.c_str()); + + addItem(item.Text.c_str(), item.Icon); + + for ( u32 c=0; c < EGUI_LBC_COUNT; ++c ) + { + core::stringc useColorLabel, colorLabel; + if ( !getSerializationLabels((EGUI_LISTBOX_COLOR)c, useColorLabel, colorLabel) ) + return; + label = useColorLabel; label += i; + Items[i].OverrideColors[c].Use = in->getAttributeAsBool(label.c_str()); + if ( Items[i].OverrideColors[c].Use ) + { + label = colorLabel; label += i; + Items[i].OverrideColors[c].Color = in->getAttributeAsColor(label.c_str()); + } + } + } +} + + +void CGUIListBox::recalculateItemWidth(s32 icon) +{ + if (IconBank && icon > -1 && + IconBank->getSprites().size() > (u32)icon && + IconBank->getSprites()[(u32)icon].Frames.size()) + { + u32 rno = IconBank->getSprites()[(u32)icon].Frames[0].rectNumber; + if (IconBank->getPositions().size() > rno) + { + const s32 w = IconBank->getPositions()[rno].getWidth(); + if (w > ItemsIconWidth) + ItemsIconWidth = w; + } + } +} + + +void CGUIListBox::setItem(u32 index, const wchar_t* text, s32 icon) +{ + if ( index >= Items.size() ) + return; + + Items[index].Text = text; + Items[index].Icon = icon; + + recalculateItemHeight(); + recalculateItemWidth(icon); +} + + +//! Insert the item at the given index +//! Return the index on success or -1 on failure. +s32 CGUIListBox::insertItem(u32 index, const wchar_t* text, s32 icon) +{ + ListItem i; + i.Text = text; + i.Icon = icon; + + Items.insert(i, index); + recalculateItemHeight(); + recalculateItemWidth(icon); + + return index; +} + + +void CGUIListBox::swapItems(u32 index1, u32 index2) +{ + if ( index1 >= Items.size() || index2 >= Items.size() ) + return; + + ListItem dummmy = Items[index1]; + Items[index1] = Items[index2]; + Items[index2] = dummmy; +} + + +void CGUIListBox::setItemOverrideColor(u32 index, video::SColor color) +{ + for ( u32 c=0; c < EGUI_LBC_COUNT; ++c ) + { + Items[index].OverrideColors[c].Use = true; + Items[index].OverrideColors[c].Color = color; + } +} + + +void CGUIListBox::setItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType, video::SColor color) +{ + if ( index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT ) + return; + + Items[index].OverrideColors[colorType].Use = true; + Items[index].OverrideColors[colorType].Color = color; +} + + +void CGUIListBox::clearItemOverrideColor(u32 index) +{ + for (u32 c=0; c < (u32)EGUI_LBC_COUNT; ++c ) + { + Items[index].OverrideColors[c].Use = false; + } +} + + +void CGUIListBox::clearItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) +{ + if ( index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT ) + return; + + Items[index].OverrideColors[colorType].Use = false; +} + + +bool CGUIListBox::hasItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const +{ + if ( index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT ) + return false; + + return Items[index].OverrideColors[colorType].Use; +} + + +video::SColor CGUIListBox::getItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const +{ + if ( (u32)index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT ) + return video::SColor(); + + return Items[index].OverrideColors[colorType].Color; +} + + +video::SColor CGUIListBox::getItemDefaultColor(EGUI_LISTBOX_COLOR colorType) const +{ + IGUISkin* skin = Environment->getSkin(); + if ( !skin ) + return video::SColor(); + + switch ( colorType ) + { + case EGUI_LBC_TEXT: + return skin->getColor(EGDC_BUTTON_TEXT); + case EGUI_LBC_TEXT_HIGHLIGHT: + return skin->getColor(EGDC_HIGH_LIGHT_TEXT); + case EGUI_LBC_ICON: + return skin->getColor(EGDC_ICON); + case EGUI_LBC_ICON_HIGHLIGHT: + return skin->getColor(EGDC_ICON_HIGH_LIGHT); + default: + return video::SColor(); + } +} + +//! set global itemHeight +void CGUIListBox::setItemHeight( s32 height ) +{ + ItemHeight = height; + ItemHeightOverride = 1; +} + + +//! Sets whether to draw the background +void CGUIListBox::setDrawBackground(bool draw) +{ + DrawBack = draw; +} + +//! Access the vertical scrollbar +IGUIScrollBar* CGUIListBox::getVerticalScrollBar() const +{ + return ScrollBar; +} + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIListBox.h b/source/Irrlicht/CGUIListBox.h new file mode 100644 index 00000000..4fc61220 --- /dev/null +++ b/source/Irrlicht/CGUIListBox.h @@ -0,0 +1,193 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_LIST_BOX_H_INCLUDED__ +#define __C_GUI_LIST_BOX_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIListBox.h" +#include "irrArray.h" + +namespace irr +{ +namespace gui +{ + + class IGUIFont; + class IGUIScrollBar; + + class CGUIListBox : public IGUIListBox + { + public: + //! constructor + CGUIListBox(IGUIEnvironment* environment, IGUIElement* parent, + s32 id, core::rect rectangle, bool clip=true, + bool drawBack=false, bool moveOverSelect=false); + + //! destructor + virtual ~CGUIListBox(); + + //! returns amount of list items + virtual u32 getItemCount() const _IRR_OVERRIDE_; + + //! returns string of a list item. the id may be a value from 0 to itemCount-1 + virtual const wchar_t* getListItem(u32 id) const _IRR_OVERRIDE_; + + //! adds an list item, returns id of item + virtual u32 addItem(const wchar_t* text) _IRR_OVERRIDE_; + + //! clears the list + virtual void clear() _IRR_OVERRIDE_; + + //! returns id of selected item. returns -1 if no item is selected. + virtual s32 getSelected() const _IRR_OVERRIDE_; + + //! sets the selected item. Set this to -1 if no item should be selected + virtual void setSelected(s32 id) _IRR_OVERRIDE_; + + //! sets the selected item. Set this to -1 if no item should be selected + virtual void setSelected(const wchar_t *item) _IRR_OVERRIDE_; + + //! called if an event happened. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + //! 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 + virtual u32 addItem(const wchar_t* text, s32 icon) _IRR_OVERRIDE_; + + //! Returns the icon of an item + virtual s32 getIcon(u32 id) const _IRR_OVERRIDE_; + + //! removes an item from the list + virtual void removeItem(u32 id) _IRR_OVERRIDE_; + + //! get the the id of the item at the given absolute coordinates + virtual s32 getItemAt(s32 xpos, s32 ypos) const _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! set whether the listbox should scroll to newly selected items + virtual void setAutoScrollEnabled(bool scroll) _IRR_OVERRIDE_; + + //! returns true if automatic scrolling is enabled, false if not. + virtual bool isAutoScrollEnabled() const _IRR_OVERRIDE_; + + //! Update the position and size of the listbox, and update the scrollbar + virtual void updateAbsolutePosition() _IRR_OVERRIDE_; + + //! Writes attributes of the element. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the element + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + + //! set all item colors at given index to color + virtual void setItemOverrideColor(u32 index, video::SColor color) _IRR_OVERRIDE_; + + //! set all item colors of specified type at given index to color + virtual void setItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType, video::SColor color) _IRR_OVERRIDE_; + + //! clear all item colors at index + virtual void clearItemOverrideColor(u32 index) _IRR_OVERRIDE_; + + //! clear item color at index for given colortype + virtual void clearItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) _IRR_OVERRIDE_; + + //! has the item at index its color overwritten? + virtual bool hasItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const _IRR_OVERRIDE_; + + //! return the overwrite color at given item index. + virtual video::SColor getItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const _IRR_OVERRIDE_; + + //! return the default color which is used for the given colorType + virtual video::SColor getItemDefaultColor(EGUI_LISTBOX_COLOR colorType) const _IRR_OVERRIDE_; + + //! set the item at the given index + virtual void setItem(u32 index, const wchar_t* text, s32 icon) _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! Swap the items at the given indices + virtual void swapItems(u32 index1, u32 index2) _IRR_OVERRIDE_; + + //! set global itemHeight + virtual void setItemHeight( s32 height ) _IRR_OVERRIDE_; + + //! Sets whether to draw the background + virtual void setDrawBackground(bool draw) _IRR_OVERRIDE_; + + //! Access the vertical scrollbar + virtual IGUIScrollBar* getVerticalScrollBar() const _IRR_OVERRIDE_; + + private: + + struct ListItem + { + ListItem() : Icon(-1) + {} + + core::stringw Text; + s32 Icon; + + // A multicolor extension + struct ListItemOverrideColor + { + ListItemOverrideColor() : Use(false) {} + bool Use; + video::SColor Color; + }; + ListItemOverrideColor OverrideColors[EGUI_LBC_COUNT]; + }; + + void recalculateItemHeight(); + void selectNew(s32 ypos, bool onlyHover=false); + void recalculateScrollPos(); + void updateScrollBarSize(s32 size); + + // extracted that function to avoid copy&paste code + void recalculateItemWidth(s32 icon); + + // get labels used for serialization + bool getSerializationLabels(EGUI_LISTBOX_COLOR colorType, core::stringc & useColorLabel, core::stringc & colorLabel) const; + + core::array< ListItem > Items; + s32 Selected; + s32 ItemHeight; + s32 ItemHeightOverride; + s32 TotalItemHeight; + s32 ItemsIconWidth; + gui::IGUIFont* Font; + gui::IGUISpriteBank* IconBank; + gui::IGUIScrollBar* ScrollBar; + u32 selectTime; + u32 LastKeyTime; + core::stringw KeyBuffer; + bool Selecting; + bool DrawBack; + bool MoveOverSelect; + bool AutoScroll; + bool HighlightWhenNotFocused; + }; + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif diff --git a/source/Irrlicht/CGUIMenu.cpp b/source/Irrlicht/CGUIMenu.cpp new file mode 100644 index 00000000..37e9ec31 --- /dev/null +++ b/source/Irrlicht/CGUIMenu.cpp @@ -0,0 +1,289 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUIMenu.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" +#include "IGUIFont.h" +#include "IGUIWindow.h" + +#include "os.h" + +namespace irr +{ +namespace gui +{ + +//! constructor +CGUIMenu::CGUIMenu(IGUIEnvironment* environment, IGUIElement* parent, + s32 id, core::rect rectangle) + : CGUIContextMenu(environment, parent, id, rectangle, false, true) +{ + #ifdef _DEBUG + setDebugName("CGUIMenu"); + #endif + + Type = EGUIET_MENU; + + setNotClipped(false); + + recalculateSize(); +} + + +//! draws the element and its children +void CGUIMenu::draw() +{ + if (!IsVisible) + return; + + IGUISkin* skin = Environment->getSkin(); + IGUIFont* font = skin->getFont(EGDF_MENU); + + if (font != LastFont) + { + if (LastFont) + LastFont->drop(); + LastFont = font; + if (LastFont) + LastFont->grab(); + + recalculateSize(); + } + + core::rect rect = AbsoluteRect; + + // draw frame + + skin->draw3DToolBar(this, rect, &AbsoluteClippingRect); + + // loop through all menu items + + rect = AbsoluteRect; + + for (s32 i=0; i<(s32)Items.size(); ++i) + { + if (!Items[i].IsSeparator) + { + rect = getRect(Items[i], AbsoluteRect); + + // draw highlighted + if (i == HighLighted && Items[i].Enabled) + { + skin->draw3DSunkenPane(this, skin->getColor(EGDC_3D_DARK_SHADOW), + true, true, rect, &AbsoluteClippingRect); + } + // draw text + + EGUI_DEFAULT_COLOR c = EGDC_BUTTON_TEXT; + + if (i == HighLighted) + c = EGDC_HIGH_LIGHT_TEXT; + + if (!Items[i].Enabled) + c = EGDC_GRAY_TEXT; + + if (font) + font->draw(Items[i].Text.c_str(), rect, + skin->getColor(c), true, true, &AbsoluteClippingRect); + } + } + + IGUIElement::draw(); +} + + +//! called if an event happened. +bool CGUIMenu::OnEvent(const SEvent& event) +{ + if (isEnabled()) + { + + switch(event.EventType) + { + case EET_GUI_EVENT: + switch(event.GUIEvent.EventType) + { + case gui::EGET_ELEMENT_FOCUS_LOST: + if (event.GUIEvent.Caller == this && !isMyChild(event.GUIEvent.Element)) + { + closeAllSubMenus(); + HighLighted = -1; + } + break; + case gui::EGET_ELEMENT_FOCUSED: + if (event.GUIEvent.Caller == this && Parent) + { + Parent->bringToFront(this); + } + break; + default: + break; + } + break; + case EET_MOUSE_INPUT_EVENT: + switch(event.MouseInput.Event) + { + case EMIE_LMOUSE_PRESSED_DOWN: + { + if (Parent) + Parent->bringToFront(this); + + core::position2d p(event.MouseInput.X, event.MouseInput.Y); + bool shouldCloseSubMenu = hasOpenSubMenu(); + if (!AbsoluteClippingRect.isPointInside(p)) + { + shouldCloseSubMenu = false; + } + highlight(core::position2d(event.MouseInput.X, event.MouseInput.Y), true); + if ( shouldCloseSubMenu ) + { + Environment->removeFocus(this); + } + + return true; + } + case EMIE_LMOUSE_LEFT_UP: + { + core::position2d p(event.MouseInput.X, event.MouseInput.Y); + if (!AbsoluteClippingRect.isPointInside(p)) + { + s32 t = sendClick(p); + if ((t==0 || t==1) && Environment->hasFocus(this)) + Environment->removeFocus(this); + } + + return true; + } + case EMIE_MOUSE_MOVED: + if (Environment->hasFocus(this) && HighLighted >= 0) + { + s32 oldHighLighted = HighLighted; + highlight(core::position2d(event.MouseInput.X, event.MouseInput.Y), true); + if ( HighLighted < 0 ) + HighLighted = oldHighLighted; // keep last hightlight active when moving outside the area + } + return true; + default: + break; + } + break; + default: + break; + } + } + + return IGUIElement::OnEvent(event); +} + +void CGUIMenu::recalculateSize() +{ + core::rect clientRect; // client rect of parent + if ( Parent && Parent->hasType(EGUIET_WINDOW) ) + { + clientRect = static_cast(Parent)->getClientRect(); + } + else if ( Parent ) + { + clientRect = core::rect(0,0, Parent->getAbsolutePosition().getWidth(), + Parent->getAbsolutePosition().getHeight()); + } + else + { + clientRect = RelativeRect; + } + + + IGUISkin* skin = Environment->getSkin(); + IGUIFont* font = skin->getFont(EGDF_MENU); + + if (!font) + { + if (Parent && skin) + RelativeRect = core::rect(clientRect.UpperLeftCorner.X, clientRect.UpperLeftCorner.Y, + clientRect.LowerRightCorner.X, clientRect.UpperLeftCorner.Y+skin->getSize(EGDS_MENU_HEIGHT)); + return; + } + + core::rect rect; + rect.UpperLeftCorner = clientRect.UpperLeftCorner; + s32 height = font->getDimension(L"A").Height + 5; + //if (skin && height < skin->getSize ( EGDS_MENU_HEIGHT )) + // height = skin->getSize(EGDS_MENU_HEIGHT); + s32 width = rect.UpperLeftCorner.X; + s32 i; + + for (i=0; i<(s32)Items.size(); ++i) + { + if (Items[i].IsSeparator) + { + Items[i].Dim.Width = 0; + Items[i].Dim.Height = height; + } + else + { + Items[i].Dim = font->getDimension(Items[i].Text.c_str()); + Items[i].Dim.Width += 20; + } + + Items[i].PosY = width; + width += Items[i].Dim.Width; + } + + width = clientRect.getWidth(); + + rect.LowerRightCorner.X = rect.UpperLeftCorner.X + width; + rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + height; + + setRelativePosition(rect); + + // recalculate submenus + for (i=0; i<(s32)Items.size(); ++i) + if (Items[i].SubMenu) + { + // move submenu + s32 w = Items[i].SubMenu->getAbsolutePosition().getWidth(); + s32 h = Items[i].SubMenu->getAbsolutePosition().getHeight(); + + Items[i].SubMenu->setRelativePosition( + core::rect(Items[i].PosY, height , + Items[i].PosY+w-5, height+h)); + } +} + + +//! returns the item highlight-area +core::rect CGUIMenu::getHRect(const SItem& i, const core::rect& absolute) const +{ + core::rect r = absolute; + r.UpperLeftCorner.X += i.PosY; + r.LowerRightCorner.X = r.UpperLeftCorner.X + i.Dim.Width; + 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) + DesiredRect.LowerRightCorner.X = Parent->getAbsolutePosition().getWidth(); + + IGUIElement::updateAbsolutePosition(); +} + + +} // end namespace +} // end namespace + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIMenu.h b/source/Irrlicht/CGUIMenu.h new file mode 100644 index 00000000..7e5f9fcd --- /dev/null +++ b/source/Irrlicht/CGUIMenu.h @@ -0,0 +1,52 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_MENU_H_INCLUDED__ +#define __C_GUI_MENU_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "CGUIContextMenu.h" + +namespace irr +{ +namespace gui +{ + + //! GUI menu interface. + class CGUIMenu : public CGUIContextMenu + { + public: + + //! constructor + CGUIMenu(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle); + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + //! called if an event happened. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! Updates the absolute position. + virtual void updateAbsolutePosition() _IRR_OVERRIDE_; + + protected: + + virtual void recalculateSize() _IRR_OVERRIDE_; + + //! returns the item highlight-area + virtual core::rect getHRect(const SItem& i, const core::rect& absolute) const _IRR_OVERRIDE_; + + //! Gets drawing rect of Item + virtual core::rect getRect(const SItem& i, const core::rect& absolute) const _IRR_OVERRIDE_; + }; + +} // end namespace gui +} // end namespace irr + + +#endif // __C_GUI_MENU_H_INCLUDED__ +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIMeshViewer.cpp b/source/Irrlicht/CGUIMeshViewer.cpp new file mode 100644 index 00000000..fa310f84 --- /dev/null +++ b/source/Irrlicht/CGUIMeshViewer.cpp @@ -0,0 +1,171 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUIMeshViewer.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" +#include "IAnimatedMesh.h" +#include "IMesh.h" +#include "os.h" +#include "IGUISkin.h" + +namespace irr +{ + +namespace gui +{ + + +//! constructor +CGUIMeshViewer::CGUIMeshViewer(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) +: IGUIMeshViewer(environment, parent, id, rectangle), Mesh(0) +{ + #ifdef _DEBUG + setDebugName("CGUIMeshViewer"); + #endif +} + + +//! destructor +CGUIMeshViewer::~CGUIMeshViewer() +{ + if (Mesh) + Mesh->drop(); +} + + +//! sets the mesh to be shown +void CGUIMeshViewer::setMesh(scene::IAnimatedMesh* mesh) +{ + if (mesh) + mesh->grab(); + if (Mesh) + Mesh->drop(); + + Mesh = mesh; + + /* This might be used for proper transformation etc. + core::vector3df center(0.0f,0.0f,0.0f); + core::aabbox3d box; + + box = Mesh->getMesh(0)->getBoundingBox(); + center = (box.MaxEdge + box.MinEdge) / 2; + */ +} + + +//! Gets the displayed mesh +scene::IAnimatedMesh* CGUIMeshViewer::getMesh() const +{ + return Mesh; +} + + +//! sets the material +void CGUIMeshViewer::setMaterial(const video::SMaterial& material) +{ + Material = material; +} + + +//! gets the material +const video::SMaterial& CGUIMeshViewer::getMaterial() const +{ + return Material; +} + + +//! called if an event happened. +bool CGUIMeshViewer::OnEvent(const SEvent& event) +{ + return IGUIElement::OnEvent(event); +} + + +//! draws the element and its children +void CGUIMeshViewer::draw() +{ + if (!IsVisible) + return; + + IGUISkin* skin = Environment->getSkin(); + video::IVideoDriver* driver = Environment->getVideoDriver(); + core::rect viewPort = AbsoluteRect; + viewPort.LowerRightCorner.X -= 1; + viewPort.LowerRightCorner.Y -= 1; + viewPort.UpperLeftCorner.X += 1; + viewPort.UpperLeftCorner.Y += 1; + + viewPort.clipAgainst(AbsoluteClippingRect); + + // draw the frame + + core::rect frameRect(AbsoluteRect); + frameRect.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y + 1; + skin->draw2DRectangle(this, skin->getColor(EGDC_3D_SHADOW), frameRect, &AbsoluteClippingRect); + + frameRect.LowerRightCorner.Y = AbsoluteRect.LowerRightCorner.Y; + frameRect.LowerRightCorner.X = frameRect.UpperLeftCorner.X + 1; + skin->draw2DRectangle(this, skin->getColor(EGDC_3D_SHADOW), frameRect, &AbsoluteClippingRect); + + frameRect = AbsoluteRect; + frameRect.UpperLeftCorner.X = frameRect.LowerRightCorner.X - 1; + skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), frameRect, &AbsoluteClippingRect); + + frameRect = AbsoluteRect; + frameRect.UpperLeftCorner.Y = AbsoluteRect.LowerRightCorner.Y - 1; + skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), frameRect, &AbsoluteClippingRect); + + // draw the mesh + + if (Mesh) + { + //TODO: if outside of screen, dont draw. + // - why is the absolute clipping rect not already the screen? + + core::rect oldViewPort = driver->getViewPort(); + + driver->setViewPort(viewPort); + + core::matrix4 mat; + + //CameraControl->calculateProjectionMatrix(mat); + //driver->setTransform(video::TS_PROJECTION, mat); + + mat.makeIdentity(); + mat.setTranslation(core::vector3df(0,0,0)); + driver->setTransform(video::ETS_WORLD, mat); + + //CameraControl->calculateViewMatrix(mat); + //driver->setTransform(video::TS_VIEW, mat); + + driver->setMaterial(Material); + + u32 frame = 0; + if(Mesh->getFrameCount()) + frame = (os::Timer::getTime()/20)%Mesh->getFrameCount(); + const scene::IMesh* const m = Mesh->getMesh(frame); + for (u32 i=0; igetMeshBufferCount(); ++i) + { + scene::IMeshBuffer* mb = m->getMeshBuffer(i); + driver->drawVertexPrimitiveList(mb->getVertices(), + mb->getVertexCount(), mb->getIndices(), + mb->getPrimitiveCount(), mb->getVertexType(), + mb->getPrimitiveType(), mb->getIndexType()); + } + + driver->setViewPort(oldViewPort); + } + + IGUIElement::draw(); +} + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIMeshViewer.h b/source/Irrlicht/CGUIMeshViewer.h new file mode 100644 index 00000000..431a9dc9 --- /dev/null +++ b/source/Irrlicht/CGUIMeshViewer.h @@ -0,0 +1,61 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_MESH_VIEWER_H_INCLUDED__ +#define __C_GUI_MESH_VIEWER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIMeshViewer.h" +#include "SMaterial.h" + +namespace irr +{ + +namespace gui +{ + + class CGUIMeshViewer : public IGUIMeshViewer + { + public: + + //! constructor + CGUIMeshViewer(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle); + + //! destructor + virtual ~CGUIMeshViewer(); + + //! sets the mesh to be shown + virtual void setMesh(scene::IAnimatedMesh* mesh) _IRR_OVERRIDE_; + + //! Gets the displayed mesh + virtual scene::IAnimatedMesh* getMesh() const _IRR_OVERRIDE_; + + //! sets the material + virtual void setMaterial(const video::SMaterial& material) _IRR_OVERRIDE_; + + //! gets the material + virtual const video::SMaterial& getMaterial() const _IRR_OVERRIDE_; + + //! called if an event happened. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + private: + + video::SMaterial Material; + scene::IAnimatedMesh* Mesh; + }; + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif // __C_GUI_MESH_VIEWER_H_INCLUDED__ + diff --git a/source/Irrlicht/CGUIMessageBox.cpp b/source/Irrlicht/CGUIMessageBox.cpp new file mode 100644 index 00000000..57b383db --- /dev/null +++ b/source/Irrlicht/CGUIMessageBox.cpp @@ -0,0 +1,463 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUIMessageBox.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IGUIButton.h" +#include "IGUIFont.h" +#include "ITexture.h" + +namespace irr +{ +namespace gui +{ + +//! constructor +CGUIMessageBox::CGUIMessageBox(IGUIEnvironment* environment, const wchar_t* caption, + const wchar_t* text, s32 flags, + IGUIElement* parent, s32 id, core::rect rectangle, video::ITexture* image) +: CGUIWindow(environment, parent, id, rectangle), + OkButton(0), CancelButton(0), YesButton(0), NoButton(0), StaticText(0), + Icon(0), IconTexture(image), + Flags(flags), MessageText(text), Pressed(false) +{ + #ifdef _DEBUG + setDebugName("CGUIMessageBox"); + #endif + + // set element type + Type = EGUIET_MESSAGE_BOX; + + // remove focus + Environment->setFocus(0); + + // remove buttons + + getMaximizeButton()->remove(); + getMinimizeButton()->remove(); + + if (caption) + setText(caption); + + Environment->setFocus(this); + + if ( IconTexture ) + IconTexture->grab(); + + refreshControls(); +} + + +//! destructor +CGUIMessageBox::~CGUIMessageBox() +{ + if (StaticText) + StaticText->drop(); + + if (OkButton) + OkButton->drop(); + + if (CancelButton) + CancelButton->drop(); + + if (YesButton) + YesButton->drop(); + + if (NoButton) + NoButton->drop(); + + if (Icon) + Icon->drop(); + + if ( IconTexture ) + IconTexture->drop(); +} + +void CGUIMessageBox::setButton(IGUIButton*& button, bool isAvailable, const core::rect & btnRect, const wchar_t * text, IGUIElement*& focusMe) +{ + // add/remove ok button + if (isAvailable) + { + if (!button) + { + button = Environment->addButton(btnRect, this); + button->setSubElement(true); + button->grab(); + } + else + button->setRelativePosition(btnRect); + + button->setText(text); + + focusMe = button; + } + else if (button) + { + button->drop(); + button->remove(); + button =0; + } +} + +void CGUIMessageBox::refreshControls() +{ + // Layout can be seen as 4 boxes (a layoutmanager would be nice) + // One box at top over the whole width for title + // Two boxes with same height at the middle beside each other for icon and for text + // One box at the bottom for the buttons + + const IGUISkin* skin = Environment->getSkin(); + + const s32 buttonHeight = skin->getSize(EGDS_BUTTON_HEIGHT); + const s32 buttonWidth = skin->getSize(EGDS_BUTTON_WIDTH); + const s32 titleHeight = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH)+2; // titlebar has no own constant + const s32 buttonDistance = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH); + const s32 borderWidth = skin->getSize(EGDS_MESSAGE_BOX_GAP_SPACE); + + // add the static text for the message + core::rect staticRect; + staticRect.UpperLeftCorner.X = borderWidth; + staticRect.UpperLeftCorner.Y = titleHeight + borderWidth; + staticRect.LowerRightCorner.X = staticRect.UpperLeftCorner.X + skin->getSize(EGDS_MESSAGE_BOX_MAX_TEXT_WIDTH); + staticRect.LowerRightCorner.Y = staticRect.UpperLeftCorner.Y + skin->getSize(EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT); + if (!StaticText) + { + StaticText = Environment->addStaticText(MessageText.c_str(), staticRect, false, false, this); + + StaticText->setWordWrap(true); + StaticText->setSubElement(true); + StaticText->grab(); + } + else + { + StaticText->setRelativePosition(staticRect); + StaticText->setText(MessageText.c_str()); + } + + s32 textHeight = StaticText->getTextHeight(); + s32 textWidth = StaticText->getTextWidth() + 6; // +6 because the static itself needs that + const s32 iconHeight = IconTexture ? IconTexture->getOriginalSize().Height : 0; + + if ( textWidth < skin->getSize(EGDS_MESSAGE_BOX_MIN_TEXT_WIDTH) ) + textWidth = skin->getSize(EGDS_MESSAGE_BOX_MIN_TEXT_WIDTH) + 6; + // no neeed to check for max because it couldn't get larger due to statictextbox. + if ( textHeight < skin->getSize(EGDS_MESSAGE_BOX_MIN_TEXT_HEIGHT) ) + textHeight = skin->getSize(EGDS_MESSAGE_BOX_MIN_TEXT_HEIGHT); + if ( textHeight > skin->getSize(EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT) ) + textHeight = skin->getSize(EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT); + + // content is text + icons + borders (but not titlebar) + s32 contentHeight = textHeight > iconHeight ? textHeight : iconHeight; + contentHeight += borderWidth; + s32 contentWidth = 0; + + // add icon + if ( IconTexture ) + { + core::position2d iconPos; + iconPos.Y = titleHeight + borderWidth; + if ( iconHeight < textHeight ) + iconPos.Y += (textHeight-iconHeight) / 2; + iconPos.X = borderWidth; + + if (!Icon) + { + Icon = Environment->addImage(IconTexture, iconPos, true, this); + Icon->setSubElement(true); + Icon->grab(); + } + else + { + core::rect iconRect( iconPos.X, iconPos.Y, iconPos.X + IconTexture->getOriginalSize().Width, iconPos.Y + IconTexture->getOriginalSize().Height ); + Icon->setRelativePosition(iconRect); + } + + contentWidth += borderWidth + IconTexture->getOriginalSize().Width; + } + else if ( Icon ) + { + Icon->drop(); + Icon->remove(); + Icon = 0; + } + + // position text + core::rect textRect; + textRect.UpperLeftCorner.X = contentWidth + borderWidth; + textRect.UpperLeftCorner.Y = titleHeight + borderWidth; + if ( textHeight < iconHeight ) + textRect.UpperLeftCorner.Y += (iconHeight-textHeight) / 2; + textRect.LowerRightCorner.X = textRect.UpperLeftCorner.X + textWidth; + textRect.LowerRightCorner.Y = textRect.UpperLeftCorner.Y + textHeight; + contentWidth += 2*borderWidth + textWidth; + StaticText->setRelativePosition( textRect ); + + // find out button size needs + s32 countButtons = 0; + if (Flags & EMBF_OK) + ++countButtons; + if (Flags & EMBF_CANCEL) + ++countButtons; + if (Flags & EMBF_YES) + ++countButtons; + if (Flags & EMBF_NO) + ++countButtons; + + s32 buttonBoxWidth = countButtons * buttonWidth + 2 * borderWidth; + if ( countButtons > 1 ) + buttonBoxWidth += (countButtons-1) * buttonDistance; + s32 buttonBoxHeight = buttonHeight + 2 * borderWidth; + + // calc new message box sizes + core::rect tmp = getRelativePosition(); + s32 msgBoxHeight = titleHeight + contentHeight + buttonBoxHeight; + s32 msgBoxWidth = contentWidth > buttonBoxWidth ? contentWidth : buttonBoxWidth; + + // adjust message box position + tmp.UpperLeftCorner.Y = (Parent->getAbsolutePosition().getHeight() - msgBoxHeight) / 2; + tmp.LowerRightCorner.Y = tmp.UpperLeftCorner.Y + msgBoxHeight; + tmp.UpperLeftCorner.X = (Parent->getAbsolutePosition().getWidth() - msgBoxWidth) / 2; + tmp.LowerRightCorner.X = tmp.UpperLeftCorner.X + msgBoxWidth; + setRelativePosition(tmp); + + // add buttons + + core::rect btnRect; + btnRect.UpperLeftCorner.Y = titleHeight + contentHeight + borderWidth; + btnRect.LowerRightCorner.Y = btnRect.UpperLeftCorner.Y + buttonHeight; + btnRect.UpperLeftCorner.X = borderWidth; + if ( contentWidth > buttonBoxWidth ) + btnRect.UpperLeftCorner.X += (contentWidth - buttonBoxWidth) / 2; // center buttons + btnRect.LowerRightCorner.X = btnRect.UpperLeftCorner.X + buttonWidth; + + IGUIElement* focusMe = 0; + setButton(OkButton, (Flags & EMBF_OK) != 0, btnRect, skin->getDefaultText(EGDT_MSG_BOX_OK), focusMe); + if ( Flags & EMBF_OK ) + btnRect += core::position2d(buttonWidth + buttonDistance, 0); + setButton(CancelButton, (Flags & EMBF_CANCEL) != 0, btnRect, skin->getDefaultText(EGDT_MSG_BOX_CANCEL), focusMe); + if ( Flags & EMBF_CANCEL ) + btnRect += core::position2d(buttonWidth + buttonDistance, 0); + setButton(YesButton, (Flags & EMBF_YES) != 0, btnRect, skin->getDefaultText(EGDT_MSG_BOX_YES), focusMe); + if ( Flags & EMBF_YES ) + btnRect += core::position2d(buttonWidth + buttonDistance, 0); + setButton(NoButton, (Flags & EMBF_NO) != 0, btnRect, skin->getDefaultText(EGDT_MSG_BOX_NO), focusMe); + + if (Environment->hasFocus(this) && focusMe) + Environment->setFocus(focusMe); +} + + +//! called if an event happened. +bool CGUIMessageBox::OnEvent(const SEvent& event) +{ + if (isEnabled()) + { + SEvent outevent; + outevent.EventType = EET_GUI_EVENT; + outevent.GUIEvent.Caller = this; + outevent.GUIEvent.Element = 0; + + switch(event.EventType) + { + case EET_KEY_INPUT_EVENT: + + if (event.KeyInput.PressedDown) + { + switch (event.KeyInput.Key) + { + case KEY_RETURN: + if (OkButton) + { + OkButton->setPressed(true); + Pressed = true; + } + break; + case KEY_KEY_Y: + if (YesButton) + { + YesButton->setPressed(true); + Pressed = true; + } + break; + case KEY_KEY_N: + if (NoButton) + { + NoButton->setPressed(true); + Pressed = true; + } + break; + case KEY_ESCAPE: + if (Pressed) + { + // cancel press + if (OkButton) OkButton->setPressed(false); + if (YesButton) YesButton->setPressed(false); + if (NoButton) NoButton->setPressed(false); + Pressed = false; + } + else + if (CancelButton) + { + CancelButton->setPressed(true); + Pressed = true; + } + else + if (CloseButton && CloseButton->isVisible()) + { + CloseButton->setPressed(true); + Pressed = true; + } + break; + default: // no other key is handled here + break; + } + } + else + if (Pressed) + { + if (OkButton && event.KeyInput.Key == KEY_RETURN) + { + setVisible(false); // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC + Environment->setFocus(0); + outevent.GUIEvent.EventType = EGET_MESSAGEBOX_OK; + Parent->OnEvent(outevent); + remove(); + return true; + } + else + if ((CancelButton || CloseButton) && event.KeyInput.Key == KEY_ESCAPE) + { + setVisible(false); // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC + Environment->setFocus(0); + outevent.GUIEvent.EventType = EGET_MESSAGEBOX_CANCEL; + Parent->OnEvent(outevent); + remove(); + return true; + } + else + if (YesButton && event.KeyInput.Key == KEY_KEY_Y) + { + setVisible(false); // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC + Environment->setFocus(0); + outevent.GUIEvent.EventType = EGET_MESSAGEBOX_YES; + Parent->OnEvent(outevent); + remove(); + return true; + } + else + if (NoButton && event.KeyInput.Key == KEY_KEY_N) + { + setVisible(false); // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC + Environment->setFocus(0); + outevent.GUIEvent.EventType = EGET_MESSAGEBOX_NO; + Parent->OnEvent(outevent); + remove(); + return true; + } + } + break; + case EET_GUI_EVENT: + if (event.GUIEvent.EventType == EGET_BUTTON_CLICKED) + { + if (event.GUIEvent.Caller == OkButton) + { + setVisible(false); // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC + Environment->setFocus(0); + outevent.GUIEvent.EventType = EGET_MESSAGEBOX_OK; + Parent->OnEvent(outevent); + remove(); + return true; + } + else + if (event.GUIEvent.Caller == CancelButton || + event.GUIEvent.Caller == CloseButton) + { + setVisible(false); // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC + Environment->setFocus(0); + outevent.GUIEvent.EventType = EGET_MESSAGEBOX_CANCEL; + Parent->OnEvent(outevent); + remove(); + return true; + } + else + if (event.GUIEvent.Caller == YesButton) + { + setVisible(false); // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC + Environment->setFocus(0); + outevent.GUIEvent.EventType = EGET_MESSAGEBOX_YES; + Parent->OnEvent(outevent); + remove(); + return true; + } + else + if (event.GUIEvent.Caller == NoButton) + { + setVisible(false); // this is a workaround to make sure it's no longer the hovered element, crashes on pressing 1-2 times ESC + Environment->setFocus(0); + outevent.GUIEvent.EventType = EGET_MESSAGEBOX_NO; + Parent->OnEvent(outevent); + remove(); + return true; + } + } + break; + default: + break; + } + } + + return CGUIWindow::OnEvent(event); +} + + +//! Writes attributes of the element. +void CGUIMessageBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const +{ + CGUIWindow::serializeAttributes(out,options); + + out->addBool ("OkayButton", (Flags & EMBF_OK) != 0 ); + out->addBool ("CancelButton", (Flags & EMBF_CANCEL) != 0 ); + out->addBool ("YesButton", (Flags & EMBF_YES) != 0 ); + out->addBool ("NoButton", (Flags & EMBF_NO) != 0 ); + out->addTexture ("Texture", IconTexture); + + out->addString ("MessageText", MessageText.c_str()); +} + + +//! Reads attributes of the element +void CGUIMessageBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) +{ + Flags = 0; + + Flags = in->getAttributeAsBool("OkayButton") ? EMBF_OK : 0; + Flags |= in->getAttributeAsBool("CancelButton")? EMBF_CANCEL : 0; + Flags |= in->getAttributeAsBool("YesButton") ? EMBF_YES : 0; + Flags |= in->getAttributeAsBool("NoButton") ? EMBF_NO : 0; + + if ( IconTexture ) + { + IconTexture->drop(); + IconTexture = NULL; + } + IconTexture = in->getAttributeAsTexture("Texture"); + if ( IconTexture ) + IconTexture->grab(); + + MessageText = in->getAttributeAsStringW("MessageText").c_str(); + + CGUIWindow::deserializeAttributes(in,options); + + refreshControls(); +} + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIMessageBox.h b/source/Irrlicht/CGUIMessageBox.h new file mode 100644 index 00000000..91d98860 --- /dev/null +++ b/source/Irrlicht/CGUIMessageBox.h @@ -0,0 +1,64 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_MESSAGE_BOX_H_INCLUDED__ +#define __C_GUI_MESSAGE_BOX_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "CGUIWindow.h" +#include "IGUIStaticText.h" +#include "IGUIImage.h" +#include "irrArray.h" + +namespace irr +{ +namespace gui +{ + class CGUIMessageBox : public CGUIWindow + { + public: + + //! constructor + CGUIMessageBox(IGUIEnvironment* environment, const wchar_t* caption, + const wchar_t* text, s32 flag, + IGUIElement* parent, s32 id, core::rect rectangle, video::ITexture* image=0); + + //! destructor + virtual ~CGUIMessageBox(); + + //! called if an event happened. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! Writes attributes of the element. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the element + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + + private: + + void refreshControls(); + void setButton(IGUIButton*& button, bool isAvailable, const core::rect & btnRect, const wchar_t * text, IGUIElement*& focusMe); + + IGUIButton* OkButton; + IGUIButton* CancelButton; + IGUIButton* YesButton; + IGUIButton* NoButton; + IGUIStaticText* StaticText; + IGUIImage * Icon; + video::ITexture * IconTexture; + + s32 Flags; + core::stringw MessageText; + bool Pressed; + }; + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif diff --git a/source/Irrlicht/CGUIModalScreen.cpp b/source/Irrlicht/CGUIModalScreen.cpp new file mode 100644 index 00000000..047fc716 --- /dev/null +++ b/source/Irrlicht/CGUIModalScreen.cpp @@ -0,0 +1,235 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUIModalScreen.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIEnvironment.h" +#include "os.h" +#include "IVideoDriver.h" +#include "IGUISkin.h" + +namespace irr +{ +namespace gui +{ + +//! constructor +CGUIModalScreen::CGUIModalScreen(IGUIEnvironment* environment, IGUIElement* parent, s32 id) +: IGUIElement(EGUIET_MODAL_SCREEN, environment, parent, id, core::recti(0, 0, parent->getAbsolutePosition().getWidth(), parent->getAbsolutePosition().getHeight()) ), + MouseDownTime(0) +{ + #ifdef _DEBUG + setDebugName("CGUIModalScreen"); + #endif + setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + + // this element is a tab group + setTabGroup(true); +} + +bool CGUIModalScreen::canTakeFocus(IGUIElement* target) const +{ + return (target && ((const IGUIElement*)target == this // this element can take it + || isMyChild(target) // own children also + || (target->getType() == EGUIET_MODAL_SCREEN ) // other modals also fine (is now on top or explicitely requested) + || (target->getParent() && target->getParent()->getType() == EGUIET_MODAL_SCREEN ))) // children of other modals will do + ; +} + +bool CGUIModalScreen::isVisible() const +{ + // any parent invisible? + IGUIElement * parentElement = getParent(); + while ( parentElement ) + { + if ( !parentElement->isVisible() ) + return false; + parentElement = parentElement->getParent(); + } + + // if we have no children then the modal is probably abused as a way to block input + if ( Children.empty() ) + { + return IGUIElement::isVisible(); + } + + // any child visible? + bool visible = false; + core::list::ConstIterator it = Children.begin(); + for (; it != Children.end(); ++it) + { + if ( (*it)->isVisible() ) + { + visible = true; + break; + } + } + return visible; +} + +bool CGUIModalScreen::isPointInside(const core::position2d& point) const +{ + return true; +} + +//! called if an event happened. +bool CGUIModalScreen::OnEvent(const SEvent& event) +{ + if (!isEnabled() || !isVisible() ) + return IGUIElement::OnEvent(event); + + switch(event.EventType) + { + case EET_GUI_EVENT: + switch(event.GUIEvent.EventType) + { + case EGET_ELEMENT_FOCUSED: + if ( event.GUIEvent.Caller == this && isMyChild(event.GUIEvent.Element) ) + { + Environment->removeFocus(0); // can't setFocus otherwise at it still has focus here + Environment->setFocus(event.GUIEvent.Element); + MouseDownTime = os::Timer::getTime(); + return true; + } + if ( !canTakeFocus(event.GUIEvent.Caller)) + { + if ( !Children.empty() ) + Environment->setFocus(*(Children.begin())); + else + Environment->setFocus(this); + } + IGUIElement::OnEvent(event); + return false; + case EGET_ELEMENT_FOCUS_LOST: + if ( !canTakeFocus(event.GUIEvent.Element)) + { + if ( isMyChild(event.GUIEvent.Caller) ) + { + if ( !Children.empty() ) + Environment->setFocus(*(Children.begin())); + else + Environment->setFocus(this); + } + else + { + MouseDownTime = os::Timer::getTime(); + } + return true; + } + else + { + return IGUIElement::OnEvent(event); + } + case EGET_ELEMENT_CLOSED: + // do not interfere with children being removed + return IGUIElement::OnEvent(event); + default: + break; + } + break; + case EET_MOUSE_INPUT_EVENT: + if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) + { + MouseDownTime = os::Timer::getTime(); + } + default: + break; + } + + IGUIElement::OnEvent(event); // anyone knows why events are passed on here? Causes p.e. problems when this is child of a CGUIWindow. + + return true; // absorb everything else +} + + +//! draws the element and its children +void CGUIModalScreen::draw() +{ + IGUISkin *skin = Environment->getSkin(); + + if (!skin) + return; + + u32 now = os::Timer::getTime(); + if (now - MouseDownTime < 300 && (now / 70)%2) + { + core::list::Iterator it = Children.begin(); + core::rect r; + video::SColor c = Environment->getSkin()->getColor(gui::EGDC_3D_HIGH_LIGHT); + + for (; it != Children.end(); ++it) + { + if ((*it)->isVisible()) + { + r = (*it)->getAbsolutePosition(); + r.LowerRightCorner.X += 1; + r.LowerRightCorner.Y += 1; + r.UpperLeftCorner.X -= 1; + r.UpperLeftCorner.Y -= 1; + + skin->draw2DRectangle(this, c, r, &AbsoluteClippingRect); + } + } + } + + IGUIElement::draw(); +} + + +//! Removes a child. +void CGUIModalScreen::removeChild(IGUIElement* child) +{ + IGUIElement::removeChild(child); + + if (Children.empty()) + { + remove(); + } +} + + +//! adds a child +void CGUIModalScreen::addChild(IGUIElement* child) +{ + IGUIElement::addChild(child); + Environment->setFocus(child); +} + + +void CGUIModalScreen::updateAbsolutePosition() +{ + core::rect parentRect(0,0,0,0); + + if (Parent) + { + parentRect = Parent->getAbsolutePosition(); + RelativeRect.UpperLeftCorner.X = 0; + RelativeRect.UpperLeftCorner.Y = 0; + RelativeRect.LowerRightCorner.X = parentRect.getWidth(); + RelativeRect.LowerRightCorner.Y = parentRect.getHeight(); + } + + IGUIElement::updateAbsolutePosition(); +} + + +//! Writes attributes of the element. +void CGUIModalScreen::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const +{ + IGUIElement::serializeAttributes(out,options); +} + +//! Reads attributes of the element +void CGUIModalScreen::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) +{ + IGUIElement::deserializeAttributes(in, options); +} + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIModalScreen.h b/source/Irrlicht/CGUIModalScreen.h new file mode 100644 index 00000000..0fe761a2 --- /dev/null +++ b/source/Irrlicht/CGUIModalScreen.h @@ -0,0 +1,70 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_MODAL_SCREEN_H_INCLUDED__ +#define __C_GUI_MODAL_SCREEN_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIElement.h" + +namespace irr +{ +namespace gui +{ + + class CGUIModalScreen : public IGUIElement + { + public: + + //! constructor + CGUIModalScreen(IGUIEnvironment* environment, IGUIElement* parent, s32 id); + + //! called if an event happened. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! Removes a child. + virtual void removeChild(IGUIElement* child) _IRR_OVERRIDE_; + + //! Adds a child + virtual void addChild(IGUIElement* child) _IRR_OVERRIDE_; + + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + //! Updates the absolute position. + virtual void updateAbsolutePosition() _IRR_OVERRIDE_; + + //! Modalscreen is not a typical element, but rather acts like a state for it's children. + //! isVisible is overriden to give this a useful behavior, so that a modal will no longer + //! be active when its parent is invisible or all its children are invisible. + virtual bool isVisible() const _IRR_OVERRIDE_; + + //! Modals are infinite so every point is inside + virtual bool isPointInside(const core::position2d& point) const _IRR_OVERRIDE_; + + //! Writes attributes of the element. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the element + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + + protected: + virtual bool canTakeFocus(IGUIElement* target) const; + + private: + + u32 MouseDownTime; + }; + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif + diff --git a/source/Irrlicht/CGUIProfiler.cpp b/source/Irrlicht/CGUIProfiler.cpp new file mode 100644 index 00000000..693fc88c --- /dev/null +++ b/source/Irrlicht/CGUIProfiler.cpp @@ -0,0 +1,331 @@ +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +// Written by Michael Zeilfelder + +#include "CGUIProfiler.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUITable.h" +#include "IGUIScrollBar.h" +#include "IGUIEnvironment.h" +#include "CProfiler.h" + +namespace irr +{ +namespace gui +{ + +//! constructor +CGUIProfiler::CGUIProfiler(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle, IProfiler* profiler) + : IGUIProfiler(environment, parent, id, rectangle, profiler) + , Profiler(profiler) + , DisplayTable(0), CurrentGroupIdx(0), CurrentGroupPage(0), NumGroupPages(1) + , DrawBackground(false), Frozen(false), UnfreezeOnce(false), ShowGroupsTogether(false) + , MinCalls(0), MinTimeSum(0), MinTimeAverage(0.f), MinTimeMax(0) +{ + if ( !Profiler ) + Profiler = &getProfiler(); + + core::recti r(0, 0, rectangle.getWidth(), rectangle.getHeight()); + + // Really just too lazy to code a complete new element for this. + // If anyone can do this nicer he's welcome. + DisplayTable = Environment->addTable(r, this, -1, DrawBackground); + DisplayTable->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + DisplayTable->setSubElement(true); + rebuildColumns(); +} + +void CGUIProfiler::fillRow(u32 rowIndex, const SProfileData& data, bool overviewTitle, bool groupTitle) +{ + DisplayTable->setCellText(rowIndex, 0, data.getName()); + + if ( !overviewTitle ) + DisplayTable->setCellText(rowIndex, 1, core::stringw(data.getCallsCounter())); + if ( data.getCallsCounter() > 0 ) + { + DisplayTable->setCellText(rowIndex, 2, core::stringw(data.getTimeSum())); + DisplayTable->setCellText(rowIndex, 3, core::stringw((u32)((f32)data.getTimeSum()/(f32)data.getCallsCounter()))); + DisplayTable->setCellText(rowIndex, 4, core::stringw(data.getLongestTime())); + } + + if ( overviewTitle || groupTitle ) + { + const video::SColor titleColor(255, 0, 0, 255); + DisplayTable->setCellColor(rowIndex, 0, titleColor); + } +} + +void CGUIProfiler::rebuildColumns() +{ + if ( DisplayTable ) + { + DisplayTable->clear(); + DisplayTable->addColumn(L"name "); + DisplayTable->addColumn(L"count calls"); + DisplayTable->addColumn(L"time(sum)"); + DisplayTable->addColumn(L"time(avg)"); + DisplayTable->addColumn(L"time(max) "); + DisplayTable->setActiveColumn(-1); + } +} + +u32 CGUIProfiler::addDataToTable(u32 rowIndex, u32 dataIndex, u32 groupIndex) +{ + const SProfileData& data = Profiler->getProfileDataByIndex(dataIndex); + if ( data.getGroupIndex() == groupIndex + && data.getCallsCounter() >= MinCalls + && ( data.getCallsCounter() == 0 || + (data.getTimeSum() >= MinTimeSum && + (f32)data.getTimeSum()/(f32)data.getCallsCounter() >= MinTimeAverage && + data.getLongestTime() >= MinTimeMax)) + ) + { + rowIndex = DisplayTable->addRow(rowIndex); + fillRow(rowIndex, data, false, false); + ++rowIndex; + } + return rowIndex; +} + +void CGUIProfiler::updateDisplay() +{ + if ( DisplayTable ) + { + DisplayTable->clearRows(); + + if ( CurrentGroupIdx < Profiler->getGroupCount() ) + { + bool overview = CurrentGroupIdx == 0; + u32 rowIndex = 0; + + // show description row (overview or name of the following group) + const SProfileData& groupData = Profiler->getGroupData(CurrentGroupIdx); + if ( !ShowGroupsTogether && (overview || groupData.getCallsCounter() >= MinCalls) ) + { + rowIndex = DisplayTable->addRow(rowIndex); + fillRow(rowIndex, groupData, overview, true); + ++rowIndex; + } + + // show overview over all groups? + if ( overview ) + { + for ( u32 i=1; igetGroupCount(); ++i ) + { + const SProfileData& groupDataOv = Profiler->getGroupData(i); + if (groupDataOv.getCallsCounter() >= MinCalls ) + { + rowIndex = DisplayTable->addRow(rowIndex); + fillRow(rowIndex, groupDataOv, false, false); + ++rowIndex; + } + } + } + // show data for all elements in current group + else + { + for ( u32 i=0; i < Profiler->getProfileDataCount(); ++i ) + { + rowIndex = addDataToTable(rowIndex, i, CurrentGroupIdx); + } + } + // Show the rest of the groups + if (ShowGroupsTogether) + { + for ( u32 groupIdx = CurrentGroupIdx+1; groupIdx < Profiler->getGroupCount(); ++groupIdx) + { + for ( u32 i=0; i < Profiler->getProfileDataCount(); ++i ) + { + rowIndex = addDataToTable(rowIndex, i, groupIdx); + } + } + } + } + + // IGUITable has no page-wise scrolling yet. The following code can be replaced when we add that. + // For now we use some CGUITable implementation info to figure this out. + // (If you wonder why I didn't code page-scrolling directly in CGUITable ... because then it needs to be a + // public interface and I don't have enough time currently to design & implement that well) + s32 itemsTotalHeight = DisplayTable->getRowCount() * DisplayTable->getItemHeight(); + s32 tableHeight = DisplayTable->getAbsolutePosition().getHeight(); + s32 heightTitleRow = DisplayTable->getItemHeight()+1; + if ( itemsTotalHeight+heightTitleRow < tableHeight ) + { + NumGroupPages = 1; + } + else + { + s32 heightHScrollBar = DisplayTable->getHorizontalScrollBar() ? DisplayTable->getHorizontalScrollBar()->getAbsolutePosition().getHeight() : 0; + s32 pageHeight = tableHeight - (heightTitleRow+heightHScrollBar); + if ( pageHeight > 0 ) + { + NumGroupPages = (itemsTotalHeight/pageHeight); + if ( itemsTotalHeight % pageHeight ) + ++NumGroupPages; + } + else // won't see anything, but that's up to the user + { + NumGroupPages = DisplayTable->getRowCount(); + } + if ( NumGroupPages < 1 ) + NumGroupPages = 1; + } + if ( CurrentGroupPage < 0 ) + CurrentGroupPage = (s32)NumGroupPages-1; + + IGUIScrollBar* vScrollBar = DisplayTable->getVerticalScrollBar(); + if ( vScrollBar ) + { + if ( NumGroupPages < 2 ) + vScrollBar->setPos(0); + else + { + f32 factor = (f32)CurrentGroupPage/(f32)(NumGroupPages-1); + vScrollBar->setPos( s32(factor * (f32)vScrollBar->getMax()) ); + } + } + } +} + +void CGUIProfiler::draw() +{ + if ( isVisible() ) + { + if (!Frozen || UnfreezeOnce) + { + UnfreezeOnce = false; + updateDisplay(); + } + } + + IGUIElement::draw(); +} + +void CGUIProfiler::nextPage(bool includeOverview) +{ + UnfreezeOnce = true; + if ( CurrentGroupPage < NumGroupPages-1 ) + ++CurrentGroupPage; + else + { + CurrentGroupPage = 0; + if ( ++CurrentGroupIdx >= Profiler->getGroupCount() ) + { + if ( includeOverview ) + CurrentGroupIdx = 0; + else + CurrentGroupIdx = 1; // can be invalid + } + } +} + +void CGUIProfiler::previousPage(bool includeOverview) +{ + UnfreezeOnce = true; + if ( CurrentGroupPage > 0 ) + { + --CurrentGroupPage; + } + else + { + CurrentGroupPage = -1; // unknown because NumGroupPages has to be re-calculated first + if ( CurrentGroupIdx > 0 ) + --CurrentGroupIdx; + else + CurrentGroupIdx = Profiler->getGroupCount()-1; + if ( CurrentGroupIdx == 0 && !includeOverview ) + { + if ( Profiler->getGroupCount() ) + CurrentGroupIdx = Profiler->getGroupCount()-1; + if ( CurrentGroupIdx == 0 ) + CurrentGroupIdx = 1; // invalid to avoid showing the overview + } + } +} + +void CGUIProfiler::setShowGroupsTogether(bool groupsTogether) +{ + ShowGroupsTogether = groupsTogether; +} + +bool CGUIProfiler::getShowGroupsTogether() const +{ + return ShowGroupsTogether; +} + +void CGUIProfiler::firstPage(bool includeOverview) +{ + UnfreezeOnce = true; + if ( includeOverview ) + CurrentGroupIdx = 0; + else + CurrentGroupIdx = 1; // can be invalid + CurrentGroupPage = 0; +} + +//! Sets another skin independent font. +void CGUIProfiler::setOverrideFont(IGUIFont* font) +{ + if ( DisplayTable ) + { + DisplayTable->setOverrideFont(font); + rebuildColumns(); + } +} + +//! Gets the override font (if any) +IGUIFont * CGUIProfiler::getOverrideFont() const +{ + if ( DisplayTable ) + return DisplayTable->getOverrideFont(); + return 0; +} + +//! Get the font which is used right now for drawing +IGUIFont* CGUIProfiler::getActiveFont() const +{ + if ( DisplayTable ) + return DisplayTable->getActiveFont(); + return 0; +} + +//! Sets whether to draw the background. By default disabled, +void CGUIProfiler::setDrawBackground(bool draw) +{ + DrawBackground = draw; + if ( DisplayTable ) + DisplayTable->setDrawBackground(draw); +} + +//! Checks if background drawing is enabled +bool CGUIProfiler::isDrawBackgroundEnabled() const +{ + return DrawBackground; +} + +//! Allows to freeze updates which makes it easier to read the numbers +void CGUIProfiler::setFrozen(bool freeze) +{ + Frozen = freeze; +} + +//! Are updates currently frozen +bool CGUIProfiler::getFrozen() const +{ + return Frozen; +} + +void CGUIProfiler::setFilters(irr::u32 minCalls, irr::u32 minTimeSum, irr::f32 minTimeAverage, irr::u32 minTimeMax) +{ + MinCalls = minCalls; + MinTimeSum = minTimeSum; + MinTimeAverage = minTimeAverage; + MinTimeMax = minTimeMax; +} + +} // end namespace gui +} // end namespace irr + + +#endif // _IRR_COMPILE_WITH_GUI_ diff --git a/source/Irrlicht/CGUIProfiler.h b/source/Irrlicht/CGUIProfiler.h new file mode 100644 index 00000000..a3c5399a --- /dev/null +++ b/source/Irrlicht/CGUIProfiler.h @@ -0,0 +1,106 @@ +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +// Written by Michael Zeilfelder + +#ifndef C_GUI_PROFILER_H_INCLUDED__ +#define C_GUI_PROFILER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIProfiler.h" + +namespace irr +{ + +class IProfiler; +struct SProfileData; + +namespace gui +{ + class IGUITable; + + //! Element to display profiler information + class CGUIProfiler : public IGUIProfiler + { + public: + //! constructor + CGUIProfiler(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle, IProfiler* profiler); + + //! Show first page of profile data + virtual void firstPage(bool includeOverview) _IRR_OVERRIDE_; + + //! Show next page of profile data + virtual void nextPage(bool includeOverview) _IRR_OVERRIDE_; + + //! Show previous page of profile data + virtual void previousPage(bool includeOverview) _IRR_OVERRIDE_; + + //! Try to show as many group-pages together as possible instead of showing at most one group per page. + /** \param groupsTogether When true show several groups on one page, when false show max. one group per page. Default is false. */ + virtual void setShowGroupsTogether(bool groupsTogether) _IRR_OVERRIDE_; + + //! Can several groups be displayed per page? + virtual bool getShowGroupsTogether() const _IRR_OVERRIDE_; + + //! Sets another skin independent font. + virtual void setOverrideFont(IGUIFont* font) _IRR_OVERRIDE_; + + //! Gets the override font (if any) + virtual IGUIFont* getOverrideFont() const _IRR_OVERRIDE_; + + //! Get the font which is used right now for drawing + virtual IGUIFont* getActiveFont() const _IRR_OVERRIDE_; + + //! Sets whether to draw the background. By default disabled, + virtual void setDrawBackground(bool draw) _IRR_OVERRIDE_; + + //! Checks if background drawing is enabled + /** \return true if background drawing is enabled, false otherwise */ + virtual bool isDrawBackgroundEnabled() const _IRR_OVERRIDE_; + + //! Allows to freeze updates which makes it easier to read the numbers + virtual void setFrozen(bool freeze) _IRR_OVERRIDE_; + + //! Are updates currently frozen + virtual bool getFrozen() const _IRR_OVERRIDE_; + + //! Filters prevents data that doesn't achieve the conditions from being displayed + virtual void setFilters(irr::u32 minCalls, irr::u32 minTimeSum, irr::f32 minTimeAverage, irr::u32 minTimeMax) _IRR_OVERRIDE_; + + virtual IGUIElement* getElementFromPoint(const core::position2d& point) _IRR_OVERRIDE_ + { + // This element should never get focus from mouse-clicks + return 0; + } + + virtual void draw() _IRR_OVERRIDE_; + + protected: + + void updateDisplay(); + void fillRow(u32 rowIndex, const SProfileData& data, bool overviewTitle, bool groupTitle); + u32 addDataToTable(u32 rowIndex, u32 dataIndex, u32 groupIndex); + void rebuildColumns(); + + IProfiler * Profiler; + irr::gui::IGUITable* DisplayTable; + irr::u32 CurrentGroupIdx; + irr::s32 CurrentGroupPage; + irr::s32 NumGroupPages; + bool DrawBackground; + bool Frozen; + bool UnfreezeOnce; + bool ShowGroupsTogether; + irr::u32 MinCalls; + irr::u32 MinTimeSum; + irr::f32 MinTimeAverage; + irr::u32 MinTimeMax; + }; + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif // __C_GUI_IMAGE_H_INCLUDED__ diff --git a/source/Irrlicht/CGUIScrollBar.cpp b/source/Irrlicht/CGUIScrollBar.cpp new file mode 100644 index 00000000..a1779bde --- /dev/null +++ b/source/Irrlicht/CGUIScrollBar.cpp @@ -0,0 +1,572 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUIScrollBar.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" +#include "CGUIButton.h" +#include "IGUIFont.h" +#include "IGUIFontBitmap.h" +#include "os.h" + +namespace irr +{ +namespace gui +{ + + +//! constructor +CGUIScrollBar::CGUIScrollBar(bool horizontal, IGUIEnvironment* environment, + IGUIElement* parent, s32 id, + core::rect rectangle, bool noclip) + : IGUIScrollBar(environment, parent, id, rectangle), UpButton(0), + DownButton(0), Dragging(false), Horizontal(horizontal), + DraggedBySlider(false), TrayClick(false), Pos(0), DrawPos(0), + DrawHeight(0), Min(0), Max(100), SmallStep(10), LargeStep(50), DesiredPos(0), + LastChange(0) +{ + #ifdef _DEBUG + setDebugName("CGUIScrollBar"); + #endif + + refreshControls(); + + setNotClipped(noclip); + + // this element can be tabbed to + setTabStop(true); + setTabOrder(-1); + + setPos(0); +} + + +//! destructor +CGUIScrollBar::~CGUIScrollBar() +{ + if (UpButton) + UpButton->drop(); + + if (DownButton) + DownButton->drop(); +} + + +//! called if an event happened. +bool CGUIScrollBar::OnEvent(const SEvent& event) +{ + if (isEnabled()) + { + + switch(event.EventType) + { + case EET_KEY_INPUT_EVENT: + if (event.KeyInput.PressedDown) + { + const s32 oldPos = Pos; + bool absorb = true; + switch (event.KeyInput.Key) + { + case KEY_LEFT: + case KEY_UP: + setPos(Pos-SmallStep); + break; + case KEY_RIGHT: + case KEY_DOWN: + setPos(Pos+SmallStep); + break; + case KEY_HOME: + setPos(Min); + break; + case KEY_PRIOR: + setPos(Pos-LargeStep); + break; + case KEY_END: + setPos(Max); + break; + case KEY_NEXT: + setPos(Pos+LargeStep); + break; + default: + absorb = false; + } + + if (Pos != oldPos) + { + SEvent newEvent; + newEvent.EventType = EET_GUI_EVENT; + newEvent.GUIEvent.Caller = this; + newEvent.GUIEvent.Element = 0; + newEvent.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED; + Parent->OnEvent(newEvent); + } + if (absorb) + return true; + } + break; + case EET_GUI_EVENT: + if (event.GUIEvent.EventType == EGET_BUTTON_CLICKED) + { + if (event.GUIEvent.Caller == UpButton) + setPos(Pos-SmallStep); + else + if (event.GUIEvent.Caller == DownButton) + setPos(Pos+SmallStep); + + SEvent newEvent; + newEvent.EventType = EET_GUI_EVENT; + newEvent.GUIEvent.Caller = this; + newEvent.GUIEvent.Element = 0; + newEvent.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED; + Parent->OnEvent(newEvent); + + return true; + } + else + if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST) + { + if (event.GUIEvent.Caller == this) + Dragging = false; + } + break; + case EET_MOUSE_INPUT_EVENT: + { + const core::position2di p(event.MouseInput.X, event.MouseInput.Y); + bool isInside = isPointInside ( p ); + switch(event.MouseInput.Event) + { + case EMIE_MOUSE_WHEEL: + if (Environment->hasFocus(this)) + { + // thanks to a bug report by REAPER + // thanks to tommi by tommi for another bugfix + // everybody needs a little thanking. hallo niko!;-) + setPos( getPos() + + ( (event.MouseInput.Wheel < 0 ? -1 : 1) * SmallStep * (Horizontal ? 1 : -1 ) ) + ); + + SEvent newEvent; + newEvent.EventType = EET_GUI_EVENT; + newEvent.GUIEvent.Caller = this; + newEvent.GUIEvent.Element = 0; + newEvent.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED; + Parent->OnEvent(newEvent); + return true; + } + break; + case EMIE_LMOUSE_PRESSED_DOWN: + { + if (isInside) + { + Dragging = true; + DraggedBySlider = SliderRect.isPointInside(p); + TrayClick = !DraggedBySlider; + DesiredPos = getPosFromMousePos(p); + return true; + } + break; + } + case EMIE_LMOUSE_LEFT_UP: + case EMIE_MOUSE_MOVED: + { + if ( !event.MouseInput.isLeftPressed () ) + Dragging = false; + + if ( !Dragging ) + { + if ( event.MouseInput.Event == EMIE_MOUSE_MOVED ) + break; + return isInside; + } + + if ( event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP ) + Dragging = false; + + const s32 newPos = getPosFromMousePos(p); + const s32 oldPos = Pos; + + if (!DraggedBySlider) + { + if ( isInside ) + { + DraggedBySlider = SliderRect.isPointInside(p); + TrayClick = !DraggedBySlider; + } + + if (DraggedBySlider) + { + setPos(newPos); + } + else + { + TrayClick = false; + if (event.MouseInput.Event == EMIE_MOUSE_MOVED) + return isInside; + } + } + + if (DraggedBySlider) + { + setPos(newPos); + } + else + { + DesiredPos = newPos; + } + + if (Pos != oldPos && Parent) + { + SEvent newEvent; + newEvent.EventType = EET_GUI_EVENT; + newEvent.GUIEvent.Caller = this; + newEvent.GUIEvent.Element = 0; + newEvent.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED; + Parent->OnEvent(newEvent); + } + return isInside; + } break; + + default: + break; + } + } break; + default: + break; + } + } + + return IGUIElement::OnEvent(event); +} + +void CGUIScrollBar::OnPostRender(u32 timeMs) +{ + if (Dragging && !DraggedBySlider && TrayClick && timeMs > LastChange + 200) + { + LastChange = timeMs; + + const s32 oldPos = Pos; + + if (DesiredPos >= Pos + LargeStep) + setPos(Pos + LargeStep); + else + if (DesiredPos <= Pos - LargeStep) + setPos(Pos - LargeStep); + else + if (DesiredPos >= Pos - LargeStep && DesiredPos <= Pos + LargeStep) + setPos(DesiredPos); + + if (Pos != oldPos && Parent) + { + SEvent newEvent; + newEvent.EventType = EET_GUI_EVENT; + newEvent.GUIEvent.Caller = this; + newEvent.GUIEvent.Element = 0; + newEvent.GUIEvent.EventType = EGET_SCROLL_BAR_CHANGED; + Parent->OnEvent(newEvent); + } + } + +} + +//! draws the element and its children +void CGUIScrollBar::draw() +{ + if (!IsVisible) + return; + + IGUISkin* skin = Environment->getSkin(); + if (!skin) + return; + + + video::SColor iconColor = skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL); + if ( iconColor != CurrentIconColor ) + { + refreshControls(); + } + + + SliderRect = AbsoluteRect; + + // draws the background + skin->draw2DRectangle(this, skin->getColor(EGDC_SCROLLBAR), SliderRect, &AbsoluteClippingRect); + + if ( core::isnotzero ( range() ) ) + { + // recalculate slider rectangle + if (Horizontal) + { + SliderRect.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X + DrawPos + RelativeRect.getHeight() - DrawHeight/2; + SliderRect.LowerRightCorner.X = SliderRect.UpperLeftCorner.X + DrawHeight; + } + else + { + SliderRect.UpperLeftCorner.Y = AbsoluteRect.UpperLeftCorner.Y + DrawPos + RelativeRect.getWidth() - DrawHeight/2; + SliderRect.LowerRightCorner.Y = SliderRect.UpperLeftCorner.Y + DrawHeight; + } + + skin->draw3DButtonPaneStandard(this, SliderRect, &AbsoluteClippingRect); + } + + // draw buttons + IGUIElement::draw(); +} + + +void CGUIScrollBar::updateAbsolutePosition() +{ + IGUIElement::updateAbsolutePosition(); + // todo: properly resize + refreshControls(); + setPos ( Pos ); +} + +//! +s32 CGUIScrollBar::getPosFromMousePos(const core::position2di &pos) const +{ + f32 w, p; + if (Horizontal) + { + w = RelativeRect.getWidth() - f32(RelativeRect.getHeight())*3.0f; + p = pos.X - AbsoluteRect.UpperLeftCorner.X - RelativeRect.getHeight()*1.5f; + } + else + { + w = RelativeRect.getHeight() - f32(RelativeRect.getWidth())*3.0f; + p = pos.Y - AbsoluteRect.UpperLeftCorner.Y - RelativeRect.getWidth()*1.5f; + } + return (s32) ( p/w * range() ) + Min; +} + + +//! sets the position of the scrollbar +void CGUIScrollBar::setPos(s32 pos) +{ + Pos = core::s32_clamp ( pos, Min, Max ); + + if ( core::isnotzero ( range() ) ) + { + if (Horizontal) + { + f32 f = (RelativeRect.getWidth() - ((f32)RelativeRect.getHeight()*3.0f)) / range(); + DrawPos = (s32)( ( ( Pos - Min ) * f) + ((f32)RelativeRect.getHeight() * 0.5f)); + DrawHeight = RelativeRect.getHeight(); + } + else + { + f32 f = (RelativeRect.getHeight() - ((f32)RelativeRect.getWidth()*3.0f)) / range(); + + DrawPos = (s32)( ( ( Pos - Min ) * f) + ((f32)RelativeRect.getWidth() * 0.5f)); + DrawHeight = RelativeRect.getWidth(); + } + } +} + + +//! gets the small step value +s32 CGUIScrollBar::getSmallStep() const +{ + return SmallStep; +} + + +//! sets the small step value +void CGUIScrollBar::setSmallStep(s32 step) +{ + if (step > 0) + SmallStep = step; + else + SmallStep = 10; +} + + +//! gets the small step value +s32 CGUIScrollBar::getLargeStep() const +{ + return LargeStep; +} + + +//! sets the small step value +void CGUIScrollBar::setLargeStep(s32 step) +{ + if (step > 0) + LargeStep = step; + else + LargeStep = 50; +} + + +//! gets the maximum value of the scrollbar. +s32 CGUIScrollBar::getMax() const +{ + return Max; +} + + +//! sets the maximum value of the scrollbar. +void CGUIScrollBar::setMax(s32 max) +{ + Max = max; + if ( Min > Max ) + Min = Max; + + bool enable = core::isnotzero ( range() ); + UpButton->setEnabled(enable); + DownButton->setEnabled(enable); + setPos(Pos); +} + +//! gets the minimum value of the scrollbar. +s32 CGUIScrollBar::getMin() const +{ + return Min; +} + + +//! sets the minimum value of the scrollbar. +void CGUIScrollBar::setMin(s32 min) +{ + Min = min; + if ( Max < Min ) + Max = Min; + + + bool enable = core::isnotzero ( range() ); + UpButton->setEnabled(enable); + DownButton->setEnabled(enable); + setPos(Pos); +} + + +//! gets the current position of the scrollbar +s32 CGUIScrollBar::getPos() const +{ + return Pos; +} + + +//! refreshes the position and text on child buttons +void CGUIScrollBar::refreshControls() +{ + CurrentIconColor = video::SColor(255,255,255,255); + + IGUISkin* skin = Environment->getSkin(); + IGUISpriteBank* sprites = 0; + + if (skin) + { + sprites = skin->getSpriteBank(); + CurrentIconColor = skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL); + } + + if (Horizontal) + { + const s32 h = RelativeRect.getHeight(); + const s32 w = (h < RelativeRect.getWidth() / 2) ? h : RelativeRect.getWidth() / 2; + if (!UpButton) + { + UpButton = new CGUIButton(Environment, this, -1, core::rect(0,0, w, h), NoClip); + UpButton->setSubElement(true); + UpButton->setTabStop(false); + } + if (sprites) + { + UpButton->setSpriteBank(sprites); + UpButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_LEFT), CurrentIconColor); + UpButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_LEFT), CurrentIconColor); + } + UpButton->setRelativePosition(core::rect(0,0, w, h)); + UpButton->setAlignment(EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + if (!DownButton) + { + DownButton = new CGUIButton(Environment, this, -1, core::rect(RelativeRect.getWidth()-w, 0, RelativeRect.getWidth(), h), NoClip); + DownButton->setSubElement(true); + DownButton->setTabStop(false); + } + if (sprites) + { + DownButton->setSpriteBank(sprites); + DownButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_RIGHT), CurrentIconColor); + DownButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_RIGHT), CurrentIconColor); + } + DownButton->setRelativePosition(core::rect(RelativeRect.getWidth()-w, 0, RelativeRect.getWidth(), h)); + DownButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + } + else + { + const s32 w = RelativeRect.getWidth(); + const s32 h = (w < RelativeRect.getHeight() / 2) ? w : RelativeRect.getHeight() / 2; + if (!UpButton) + { + UpButton = new CGUIButton(Environment, this, -1, core::rect(0,0, w, h), NoClip); + UpButton->setSubElement(true); + UpButton->setTabStop(false); + } + if (sprites) + { + UpButton->setSpriteBank(sprites); + UpButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_UP), CurrentIconColor); + UpButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_UP), CurrentIconColor); + } + UpButton->setRelativePosition(core::rect(0,0, w, h)); + UpButton->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + if (!DownButton) + { + DownButton = new CGUIButton(Environment, this, -1, core::rect(0,RelativeRect.getHeight()-h, w, RelativeRect.getHeight()), NoClip); + DownButton->setSubElement(true); + DownButton->setTabStop(false); + } + if (sprites) + { + DownButton->setSpriteBank(sprites); + DownButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_DOWN), CurrentIconColor); + DownButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_DOWN), CurrentIconColor); + } + DownButton->setRelativePosition(core::rect(0,RelativeRect.getHeight()-h, w, RelativeRect.getHeight())); + DownButton->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT); + } +} + + +//! Writes attributes of the element. +void CGUIScrollBar::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const +{ + IGUIScrollBar::serializeAttributes(out,options); + + out->addBool("Horizontal", Horizontal); + out->addInt ("Value", Pos); + out->addInt ("Min", Min); + out->addInt ("Max", Max); + out->addInt ("SmallStep", SmallStep); + out->addInt ("LargeStep", LargeStep); + // CurrentIconColor - not serialized as continuously updated +} + + +//! Reads attributes of the element +void CGUIScrollBar::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) +{ + IGUIScrollBar::deserializeAttributes(in,options); + + Horizontal = in->getAttributeAsBool("Horizontal", Horizontal); + setMin(in->getAttributeAsInt("Min", Min)); + setMax(in->getAttributeAsInt("Max", Max)); + setPos(in->getAttributeAsInt("Value", Pos)); + setSmallStep(in->getAttributeAsInt("SmallStep", SmallStep)); + setLargeStep(in->getAttributeAsInt("LargeStep", LargeStep)); + // CurrentIconColor - not serialized as continuously updated + + refreshControls(); +} + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIScrollBar.h b/source/Irrlicht/CGUIScrollBar.h new file mode 100644 index 00000000..2bbe50ac --- /dev/null +++ b/source/Irrlicht/CGUIScrollBar.h @@ -0,0 +1,113 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_SCROLL_BAR_H_INCLUDED__ +#define __C_GUI_SCROLL_BAR_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIScrollBar.h" +#include "IGUIButton.h" + +namespace irr +{ +namespace gui +{ + + class CGUIScrollBar : public IGUIScrollBar + { + public: + + //! constructor + CGUIScrollBar(bool horizontal, IGUIEnvironment* environment, + IGUIElement* parent, s32 id, core::rect rectangle, + bool noclip=false); + + //! destructor + virtual ~CGUIScrollBar(); + + //! called if an event happened. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + virtual void OnPostRender(u32 timeMs) _IRR_OVERRIDE_; + + + //! gets the maximum value of the scrollbar. + virtual s32 getMax() const _IRR_OVERRIDE_; + + //! sets the maximum value of the scrollbar. + virtual void setMax(s32 max) _IRR_OVERRIDE_; + + //! gets the minimum value of the scrollbar. + virtual s32 getMin() const _IRR_OVERRIDE_; + + //! sets the minimum value of the scrollbar. + virtual void setMin(s32 min) _IRR_OVERRIDE_; + + //! gets the small step value + virtual s32 getSmallStep() const _IRR_OVERRIDE_; + + //! sets the small step value + virtual void setSmallStep(s32 step) _IRR_OVERRIDE_; + + //! gets the large step value + virtual s32 getLargeStep() const _IRR_OVERRIDE_; + + //! sets the large step value + virtual void setLargeStep(s32 step) _IRR_OVERRIDE_; + + //! gets the current position of the scrollbar + virtual s32 getPos() const _IRR_OVERRIDE_; + + //! sets the position of the scrollbar + virtual void setPos(s32 pos) _IRR_OVERRIDE_; + + //! updates the rectangle + virtual void updateAbsolutePosition() _IRR_OVERRIDE_; + + //! Writes attributes of the element. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the element + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + + private: + + void refreshControls(); + s32 getPosFromMousePos(const core::position2di &p) const; + + IGUIButton* UpButton; + IGUIButton* DownButton; + + core::rect SliderRect; + + bool Dragging; + bool Horizontal; + bool DraggedBySlider; + bool TrayClick; + s32 Pos; + s32 DrawPos; + s32 DrawHeight; + s32 Min; + s32 Max; + s32 SmallStep; + s32 LargeStep; + s32 DesiredPos; + u32 LastChange; + video::SColor CurrentIconColor; + + f32 range () const { return (f32) ( Max - Min ); } + }; + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif + diff --git a/source/Irrlicht/CGUISkin.cpp b/source/Irrlicht/CGUISkin.cpp new file mode 100644 index 00000000..30573b93 --- /dev/null +++ b/source/Irrlicht/CGUISkin.cpp @@ -0,0 +1,1015 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUISkin.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIFont.h" +#include "IGUISpriteBank.h" +#include "IGUIElement.h" +#include "IVideoDriver.h" +#include "IAttributes.h" + +namespace irr +{ +namespace gui +{ + +CGUISkin::CGUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver) +: SpriteBank(0), Driver(driver), Type(type) +{ + #ifdef _DEBUG + setDebugName("CGUISkin"); + #endif + + 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); + Colors[EGDC_3D_FACE] = video::SColor(101,210,210,210); + Colors[EGDC_3D_HIGH_LIGHT] = video::SColor(101,255,255,255); + Colors[EGDC_3D_LIGHT] = video::SColor(101,210,210,210); + Colors[EGDC_ACTIVE_BORDER] = video::SColor(101,16,14,115); + Colors[EGDC_ACTIVE_CAPTION] = video::SColor(255,255,255,255); + Colors[EGDC_APP_WORKSPACE] = video::SColor(101,100,100,100); + Colors[EGDC_BUTTON_TEXT] = video::SColor(240,10,10,10); + Colors[EGDC_GRAY_TEXT] = video::SColor(240,130,130,130); + Colors[EGDC_HIGH_LIGHT] = video::SColor(101,8,36,107); + Colors[EGDC_HIGH_LIGHT_TEXT] = video::SColor(240,255,255,255); + Colors[EGDC_INACTIVE_BORDER] = video::SColor(101,165,165,165); + Colors[EGDC_INACTIVE_CAPTION] = video::SColor(255,30,30,30); + Colors[EGDC_TOOLTIP] = video::SColor(200,0,0,0); + Colors[EGDC_TOOLTIP_BACKGROUND] = video::SColor(200,255,255,225); + Colors[EGDC_SCROLLBAR] = video::SColor(101,230,230,230); + Colors[EGDC_WINDOW] = video::SColor(101,255,255,255); + Colors[EGDC_WINDOW_SYMBOL] = video::SColor(200,10,10,10); + Colors[EGDC_ICON] = video::SColor(200,255,255,255); + Colors[EGDC_ICON_HIGH_LIGHT] = video::SColor(200,8,36,107); + Colors[EGDC_GRAY_WINDOW_SYMBOL] = video::SColor(240,100,100,100); + Colors[EGDC_EDITABLE] = video::SColor(255,255,255,255); + Colors[EGDC_GRAY_EDITABLE] = video::SColor(255,120,120,120); + Colors[EGDC_FOCUSED_EDITABLE] = video::SColor(255,240,240,255); + + + Sizes[EGDS_SCROLLBAR_SIZE] = 14; + Sizes[EGDS_MENU_HEIGHT] = 30; + Sizes[EGDS_WINDOW_BUTTON_WIDTH] = 15; + Sizes[EGDS_CHECK_BOX_WIDTH] = 18; + Sizes[EGDS_MESSAGE_BOX_WIDTH] = 500; + 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; + + Sizes[EGDS_TITLEBARTEXT_DISTANCE_X] = 2; + Sizes[EGDS_TITLEBARTEXT_DISTANCE_Y] = 0; + } + else + { + //0x80a6a8af + Colors[EGDC_3D_DARK_SHADOW] = 0x60767982; + //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_LIGHT] = 0x802e313a; + Colors[EGDC_ACTIVE_BORDER] = 0x80404040; // window title + Colors[EGDC_ACTIVE_CAPTION] = 0xffd0d0d0; + Colors[EGDC_APP_WORKSPACE] = 0xc0646464; // unused + Colors[EGDC_BUTTON_TEXT] = 0xd0161616; + Colors[EGDC_GRAY_TEXT] = 0x3c141414; + Colors[EGDC_HIGH_LIGHT] = 0x6c606060; + Colors[EGDC_HIGH_LIGHT_TEXT] = 0xd0e0e0e0; + Colors[EGDC_INACTIVE_BORDER] = 0xf0a5a5a5; + Colors[EGDC_INACTIVE_CAPTION] = 0xffd2d2d2; + Colors[EGDC_TOOLTIP] = 0xf00f2033; + Colors[EGDC_TOOLTIP_BACKGROUND] = 0xc0cbd2d9; + Colors[EGDC_SCROLLBAR] = 0xf0e0e0e0; + Colors[EGDC_WINDOW] = 0xf0f0f0f0; + Colors[EGDC_WINDOW_SYMBOL] = 0xd0161616; + Colors[EGDC_ICON] = 0xd0161616; + Colors[EGDC_ICON_HIGH_LIGHT] = 0xd0606060; + Colors[EGDC_GRAY_WINDOW_SYMBOL] = 0x3c101010; + Colors[EGDC_EDITABLE] = 0xf0ffffff; + Colors[EGDC_GRAY_EDITABLE] = 0xf0cccccc; + Colors[EGDC_FOCUSED_EDITABLE] = 0xf0fffff0; + + Sizes[EGDS_SCROLLBAR_SIZE] = 14; + Sizes[EGDS_MENU_HEIGHT] = 48; + Sizes[EGDS_WINDOW_BUTTON_WIDTH] = 15; + Sizes[EGDS_CHECK_BOX_WIDTH] = 18; + Sizes[EGDS_MESSAGE_BOX_WIDTH] = 500; + Sizes[EGDS_MESSAGE_BOX_HEIGHT] = 200; + Sizes[EGDS_BUTTON_WIDTH] = 80; + Sizes[EGDS_BUTTON_HEIGHT] = 30; + + Sizes[EGDS_TEXT_DISTANCE_X] = 3; + Sizes[EGDS_TEXT_DISTANCE_Y] = 2; + + Sizes[EGDS_TITLEBARTEXT_DISTANCE_X] = 3; + Sizes[EGDS_TITLEBARTEXT_DISTANCE_Y] = 2; + } + + Sizes[EGDS_MESSAGE_BOX_GAP_SPACE] = 15; + Sizes[EGDS_MESSAGE_BOX_MIN_TEXT_WIDTH] = 0; + Sizes[EGDS_MESSAGE_BOX_MAX_TEXT_WIDTH] = 500; + Sizes[EGDS_MESSAGE_BOX_MIN_TEXT_HEIGHT] = 0; + Sizes[EGDS_MESSAGE_BOX_MAX_TEXT_HEIGHT] = 99999; + + Sizes[EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X] = 1; + Sizes[EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y] = 1; + Sizes[EGDS_BUTTON_PRESSED_TEXT_OFFSET_X] = 0; + Sizes[EGDS_BUTTON_PRESSED_TEXT_OFFSET_Y] = 2; + Sizes[EGDS_BUTTON_PRESSED_SPRITE_OFFSET_X] = 0; + Sizes[EGDS_BUTTON_PRESSED_SPRITE_OFFSET_Y] = 0; + + Texts[EGDT_MSG_BOX_OK] = L"OK"; + Texts[EGDT_MSG_BOX_CANCEL] = L"Cancel"; + Texts[EGDT_MSG_BOX_YES] = L"Yes"; + Texts[EGDT_MSG_BOX_NO] = L"No"; + Texts[EGDT_WINDOW_CLOSE] = L"Close"; + Texts[EGDT_WINDOW_RESTORE] = L"Restore"; + Texts[EGDT_WINDOW_MINIMIZE] = L"Minimize"; + Texts[EGDT_WINDOW_MAXIMIZE] = L"Maximize"; + + Icons[EGDI_WINDOW_MAXIMIZE] = 225; + Icons[EGDI_WINDOW_RESTORE] = 226; + Icons[EGDI_WINDOW_CLOSE] = 227; + Icons[EGDI_WINDOW_MINIMIZE] = 228; + Icons[EGDI_CURSOR_UP] = 229; + Icons[EGDI_CURSOR_DOWN] = 230; + Icons[EGDI_CURSOR_LEFT] = 231; + Icons[EGDI_CURSOR_RIGHT] = 232; + Icons[EGDI_MENU_MORE] = 232; + Icons[EGDI_CHECK_BOX_CHECKED] = 233; + Icons[EGDI_DROP_DOWN] = 234; + Icons[EGDI_SMALL_CURSOR_UP] = 235; + Icons[EGDI_SMALL_CURSOR_DOWN] = 236; + Icons[EGDI_RADIO_BUTTON_CHECKED] = 237; + Icons[EGDI_MORE_LEFT] = 238; + Icons[EGDI_MORE_RIGHT] = 239; + Icons[EGDI_MORE_UP] = 240; + Icons[EGDI_MORE_DOWN] = 241; + Icons[EGDI_WINDOW_RESIZE] = 242; + Icons[EGDI_EXPAND] = 243; + Icons[EGDI_COLLAPSE] = 244; + + Icons[EGDI_FILE] = 245; + Icons[EGDI_DIRECTORY] = 246; + + for (u32 i=0; idrop(); + } + + if (SpriteBank) + SpriteBank->drop(); +} + + +//! returns default color +video::SColor CGUISkin::getColor(EGUI_DEFAULT_COLOR color) const +{ + if ((u32)color < EGDC_COUNT) + return Colors[color]; + else + return video::SColor(); +} + + +//! sets a default color +void CGUISkin::setColor(EGUI_DEFAULT_COLOR which, video::SColor newColor) +{ + if ((u32)which < EGDC_COUNT) + Colors[which] = newColor; +} + + +//! returns size for the given size type +s32 CGUISkin::getSize(EGUI_DEFAULT_SIZE size) const +{ + if ((u32)size < EGDS_COUNT) + return Sizes[size]; + else + return 0; +} + + +//! sets a default size +void CGUISkin::setSize(EGUI_DEFAULT_SIZE which, s32 size) +{ + if ((u32)which < EGDS_COUNT) + Sizes[which] = size; +} + + +//! returns the default font +IGUIFont* CGUISkin::getFont(EGUI_DEFAULT_FONT which) const +{ + if (((u32)which < EGDF_COUNT) && Fonts[which]) + return Fonts[which]; + else + return Fonts[EGDF_DEFAULT]; +} + + +//! sets a default font +void CGUISkin::setFont(IGUIFont* font, EGUI_DEFAULT_FONT which) +{ + if ((u32)which >= EGDF_COUNT) + return; + + if (font) + { + font->grab(); + if (Fonts[which]) + Fonts[which]->drop(); + + Fonts[which] = font; + } +} + + +//! gets the sprite bank stored +IGUISpriteBank* CGUISkin::getSpriteBank() const +{ + return SpriteBank; +} + + +//! set a new sprite bank or remove one by passing 0 +void CGUISkin::setSpriteBank(IGUISpriteBank* bank) +{ + if (bank) + bank->grab(); + + if (SpriteBank) + SpriteBank->drop(); + + SpriteBank = bank; +} + + +//! Returns a default icon +u32 CGUISkin::getIcon(EGUI_DEFAULT_ICON icon) const +{ + if ((u32)icon < EGDI_COUNT) + return Icons[icon]; + else + return 0; +} + + +//! Sets a default icon +void CGUISkin::setIcon(EGUI_DEFAULT_ICON icon, u32 index) +{ + if ((u32)icon < EGDI_COUNT) + Icons[icon] = index; +} + + +//! Returns a default text. For example for Message box button captions: +//! "OK", "Cancel", "Yes", "No" and so on. +const wchar_t* CGUISkin::getDefaultText(EGUI_DEFAULT_TEXT text) const +{ + if ((u32)text < EGDT_COUNT) + return Texts[text].c_str(); + else + return Texts[0].c_str(); +} + + +//! Sets a default text. For example for Message box button captions: +//! "OK", "Cancel", "Yes", "No" and so on. +void CGUISkin::setDefaultText(EGUI_DEFAULT_TEXT which, const wchar_t* newText) +{ + if ((u32)which < EGDT_COUNT) + Texts[which] = newText; +} + + +//! draws a standard 3d button pane +/** 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. +\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 +implementations to find out how to draw the part exactly. */ +void CGUISkin::draw3DButtonPaneStandard(IGUIElement* element, + const core::rect& r, + const core::rect* clip) +{ + if (!Driver) + return; + + core::rect rect = r; + + if ( Type == EGST_BURNING_SKIN ) + { + rect.UpperLeftCorner.X -= 1; + rect.UpperLeftCorner.Y -= 1; + rect.LowerRightCorner.X += 1; + rect.LowerRightCorner.Y += 1; + draw3DSunkenPane(element, + getColor( EGDC_WINDOW ).getInterpolated( 0xFFFFFFFF, 0.9f ) + ,false, true, rect, clip); + return; + } + + Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, clip); + + rect.LowerRightCorner.X -= 1; + rect.LowerRightCorner.Y -= 1; + Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); + + rect.UpperLeftCorner.X += 1; + rect.UpperLeftCorner.Y += 1; + Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); + + rect.LowerRightCorner.X -= 1; + rect.LowerRightCorner.Y -= 1; + + if (!UseGradient) + { + Driver->draw2DRectangle(getColor(EGDC_3D_FACE), rect, clip); + } + else + { + const video::SColor c1 = getColor(EGDC_3D_FACE); + const video::SColor c2 = c1.getInterpolated(getColor(EGDC_3D_DARK_SHADOW), 0.4f); + Driver->draw2DRectangle(rect, c1, c1, c2, c2, clip); + } +} + + +//! draws a pressed 3d button pane +/** 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. +\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 +implementations to find out how to draw the part exactly. */ +void CGUISkin::draw3DButtonPanePressed(IGUIElement* element, + const core::rect& r, + const core::rect* clip) +{ + if (!Driver) + return; + + core::rect rect = r; + Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); + + rect.LowerRightCorner.X -= 1; + rect.LowerRightCorner.Y -= 1; + Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, clip); + + rect.UpperLeftCorner.X += 1; + rect.UpperLeftCorner.Y += 1; + Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); + + rect.UpperLeftCorner.X += 1; + rect.UpperLeftCorner.Y += 1; + + if (!UseGradient) + { + Driver->draw2DRectangle(getColor(EGDC_3D_FACE), rect, clip); + } + else + { + const video::SColor c1 = getColor(EGDC_3D_FACE); + const video::SColor c2 = c1.getInterpolated(getColor(EGDC_3D_DARK_SHADOW), 0.4f); + Driver->draw2DRectangle(rect, c1, c1, c2, c2, clip); + } +} + + +//! 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. +\param bgcolor: Background color. +\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. */ +void CGUISkin::draw3DSunkenPane(IGUIElement* element, video::SColor bgcolor, + bool flat, bool fillBackGround, + const core::rect& r, + const core::rect* clip) +{ + if (!Driver) + return; + + core::rect rect = r; + + if (fillBackGround) + Driver->draw2DRectangle(bgcolor, rect, clip); + + if (flat) + { + // draw flat sunken pane + + rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1; + Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); // top + + ++rect.UpperLeftCorner.Y; + rect.LowerRightCorner.Y = r.LowerRightCorner.Y; + rect.LowerRightCorner.X = rect.UpperLeftCorner.X + 1; + Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); // left + + rect = r; + ++rect.UpperLeftCorner.Y; + rect.UpperLeftCorner.X = rect.LowerRightCorner.X - 1; + Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); // right + + rect = r; + ++rect.UpperLeftCorner.X; + rect.UpperLeftCorner.Y = r.LowerRightCorner.Y - 1; + --rect.LowerRightCorner.X; + Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); // bottom + } + else + { + // draw deep sunken pane + rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1; + Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); // top + ++rect.UpperLeftCorner.X; + ++rect.UpperLeftCorner.Y; + --rect.LowerRightCorner.X; + ++rect.LowerRightCorner.Y; + Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, clip); + + rect.UpperLeftCorner.X = r.UpperLeftCorner.X; + rect.UpperLeftCorner.Y = r.UpperLeftCorner.Y+1; + rect.LowerRightCorner.X = rect.UpperLeftCorner.X + 1; + rect.LowerRightCorner.Y = r.LowerRightCorner.Y; + Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); // left + ++rect.UpperLeftCorner.X; + ++rect.UpperLeftCorner.Y; + ++rect.LowerRightCorner.X; + --rect.LowerRightCorner.Y; + Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, clip); + + rect = r; + rect.UpperLeftCorner.X = rect.LowerRightCorner.X - 1; + ++rect.UpperLeftCorner.Y; + Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); // right + --rect.UpperLeftCorner.X; + ++rect.UpperLeftCorner.Y; + --rect.LowerRightCorner.X; + --rect.LowerRightCorner.Y; + Driver->draw2DRectangle(getColor(EGDC_3D_LIGHT), rect, clip); + + rect = r; + ++rect.UpperLeftCorner.X; + rect.UpperLeftCorner.Y = r.LowerRightCorner.Y - 1; + --rect.LowerRightCorner.X; + Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); // bottom + ++rect.UpperLeftCorner.X; + --rect.UpperLeftCorner.Y; + --rect.LowerRightCorner.X; + --rect.LowerRightCorner.Y; + Driver->draw2DRectangle(getColor(EGDC_3D_LIGHT), rect, clip); + } +} + + +//! draws a window background +// return where to draw title bar text. +core::rect CGUISkin::draw3DWindowBackground(IGUIElement* element, + bool drawTitleBar, video::SColor titleBarColor, + const core::rect& r, + const core::rect* clip, + core::rect* checkClientArea) +{ + if (!Driver) + { + if ( checkClientArea ) + { + *checkClientArea = r; + } + return r; + } + + core::rect rect = r; + + // top border + rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1; + if ( !checkClientArea ) + { + Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); + } + + // left border + rect.LowerRightCorner.Y = r.LowerRightCorner.Y; + rect.LowerRightCorner.X = rect.UpperLeftCorner.X + 1; + if ( !checkClientArea ) + { + Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); + } + + // right border dark outer line + rect.UpperLeftCorner.X = r.LowerRightCorner.X - 1; + rect.LowerRightCorner.X = r.LowerRightCorner.X; + rect.UpperLeftCorner.Y = r.UpperLeftCorner.Y; + rect.LowerRightCorner.Y = r.LowerRightCorner.Y; + if ( !checkClientArea ) + { + Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, clip); + } + + // right border bright innner line + rect.UpperLeftCorner.X -= 1; + rect.LowerRightCorner.X -= 1; + rect.UpperLeftCorner.Y += 1; + rect.LowerRightCorner.Y -= 1; + if ( !checkClientArea ) + { + Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); + } + + // bottom border dark outer line + rect.UpperLeftCorner.X = r.UpperLeftCorner.X; + rect.UpperLeftCorner.Y = r.LowerRightCorner.Y - 1; + rect.LowerRightCorner.Y = r.LowerRightCorner.Y; + rect.LowerRightCorner.X = r.LowerRightCorner.X; + if ( !checkClientArea ) + { + Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, clip); + } + + // bottom border bright inner line + rect.UpperLeftCorner.X += 1; + rect.LowerRightCorner.X -= 1; + rect.UpperLeftCorner.Y -= 1; + rect.LowerRightCorner.Y -= 1; + if ( !checkClientArea ) + { + Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); + } + + // client area for background + rect = r; + rect.UpperLeftCorner.X +=1; + rect.UpperLeftCorner.Y +=1; + rect.LowerRightCorner.X -= 2; + rect.LowerRightCorner.Y -= 2; + if (checkClientArea) + { + *checkClientArea = rect; + } + + if ( !checkClientArea ) + { + if (!UseGradient) + { + Driver->draw2DRectangle(getColor(EGDC_3D_FACE), rect, clip); + } + else if ( Type == EGST_BURNING_SKIN ) + { + const video::SColor c1 = getColor(EGDC_WINDOW).getInterpolated ( 0xFFFFFFFF, 0.9f ); + const video::SColor c2 = getColor(EGDC_WINDOW).getInterpolated ( 0xFFFFFFFF, 0.8f ); + + Driver->draw2DRectangle(rect, c1, c1, c2, c2, clip); + } + else + { + const video::SColor c2 = getColor(EGDC_3D_SHADOW); + const video::SColor c1 = getColor(EGDC_3D_FACE); + Driver->draw2DRectangle(rect, c1, c1, c1, c2, clip); + } + } + + // title bar + rect = r; + rect.UpperLeftCorner.X += 2; + rect.UpperLeftCorner.Y += 2; + rect.LowerRightCorner.X -= 2; + rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + getSize(EGDS_WINDOW_BUTTON_WIDTH) + 2; + + if (drawTitleBar ) + { + if (checkClientArea) + { + (*checkClientArea).UpperLeftCorner.Y = rect.LowerRightCorner.Y; + } + else + { + // draw title bar + //if (!UseGradient) + // Driver->draw2DRectangle(titleBarColor, rect, clip); + //else + if ( Type == EGST_BURNING_SKIN ) + { + const video::SColor c = titleBarColor.getInterpolated( video::SColor(titleBarColor.getAlpha(),255,255,255), 0.8f); + Driver->draw2DRectangle(rect, titleBarColor, titleBarColor, c, c, clip); + } + else + { + const video::SColor c = titleBarColor.getInterpolated(video::SColor(titleBarColor.getAlpha(),0,0,0), 0.2f); + Driver->draw2DRectangle(rect, titleBarColor, c, titleBarColor, c, clip); + } + } + } + + return rect; +} + + +//! draws a standard 3d menu pane +/** 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. +\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 rect: Defining area where to draw. +\param clip: Clip area. */ +void CGUISkin::draw3DMenuPane(IGUIElement* element, + const core::rect& r, const core::rect* clip) +{ + if (!Driver) + return; + + core::rect rect = r; + + if ( Type == EGST_BURNING_SKIN ) + { + rect.UpperLeftCorner.Y -= 3; + draw3DButtonPaneStandard(element, rect, clip); + return; + } + + // in this skin, this is exactly what non pressed buttons look like, + // so we could simply call + // draw3DButtonPaneStandard(element, rect, clip); + // here. + // but if the skin is transparent, this doesn't look that nice. So + // We draw it a little bit better, with some more draw2DRectangle calls, + // but there aren't that much menus visible anyway. + + rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1; + Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); + + rect.LowerRightCorner.Y = r.LowerRightCorner.Y; + rect.LowerRightCorner.X = rect.UpperLeftCorner.X + 1; + Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), rect, clip); + + rect.UpperLeftCorner.X = r.LowerRightCorner.X - 1; + rect.LowerRightCorner.X = r.LowerRightCorner.X; + rect.UpperLeftCorner.Y = r.UpperLeftCorner.Y; + rect.LowerRightCorner.Y = r.LowerRightCorner.Y; + Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, clip); + + rect.UpperLeftCorner.X -= 1; + rect.LowerRightCorner.X -= 1; + rect.UpperLeftCorner.Y += 1; + rect.LowerRightCorner.Y -= 1; + Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); + + rect.UpperLeftCorner.X = r.UpperLeftCorner.X; + rect.UpperLeftCorner.Y = r.LowerRightCorner.Y - 1; + rect.LowerRightCorner.Y = r.LowerRightCorner.Y; + rect.LowerRightCorner.X = r.LowerRightCorner.X; + Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), rect, clip); + + rect.UpperLeftCorner.X += 1; + rect.LowerRightCorner.X -= 1; + rect.UpperLeftCorner.Y -= 1; + rect.LowerRightCorner.Y -= 1; + Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); + + rect = r; + rect.UpperLeftCorner.X +=1; + rect.UpperLeftCorner.Y +=1; + rect.LowerRightCorner.X -= 2; + rect.LowerRightCorner.Y -= 2; + + if (!UseGradient) + Driver->draw2DRectangle(getColor(EGDC_3D_FACE), rect, clip); + else + { + const video::SColor c1 = getColor(EGDC_3D_FACE); + const video::SColor c2 = getColor(EGDC_3D_SHADOW); + Driver->draw2DRectangle(rect, c1, c1, c2, c2, clip); + } +} + + +//! draws a standard 3d tool bar +/** 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. +\param rect: Defining area where to draw. +\param clip: Clip area. */ +void CGUISkin::draw3DToolBar(IGUIElement* element, + const core::rect& r, + const core::rect* clip) +{ + if (!Driver) + return; + + core::rect rect = r; + + rect.UpperLeftCorner.X = r.UpperLeftCorner.X; + rect.UpperLeftCorner.Y = r.LowerRightCorner.Y - 1; + rect.LowerRightCorner.Y = r.LowerRightCorner.Y; + rect.LowerRightCorner.X = r.LowerRightCorner.X; + Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), rect, clip); + + rect = r; + rect.LowerRightCorner.Y -= 1; + + if (!UseGradient) + { + Driver->draw2DRectangle(getColor(EGDC_3D_FACE), rect, clip); + } + else + if ( Type == EGST_BURNING_SKIN ) + { + const video::SColor c1 = 0xF0000000 | getColor(EGDC_3D_FACE).color; + const video::SColor c2 = 0xF0000000 | getColor(EGDC_3D_SHADOW).color; + + rect.LowerRightCorner.Y += 1; + Driver->draw2DRectangle(rect, c1, c2, c1, c2, clip); + } + else + { + const video::SColor c1 = getColor(EGDC_3D_FACE); + const video::SColor c2 = getColor(EGDC_3D_SHADOW); + Driver->draw2DRectangle(rect, c1, c1, c2, c2, clip); + } +} + + +//! draws a tab button +/** 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. +\param active: Specifies if the tab is currently active. +\param rect: Defining area where to draw. +\param clip: Clip area. */ +void CGUISkin::draw3DTabButton(IGUIElement* element, bool active, + const core::rect& frameRect, const core::rect* clip, EGUI_ALIGNMENT alignment) +{ + if (!Driver) + return; + + core::rect tr = frameRect; + + if ( alignment == EGUIA_UPPERLEFT ) + { + tr.LowerRightCorner.X -= 2; + 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; + tr.UpperLeftCorner.Y += 1; + Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), tr, clip); + + // draw grey background + tr = frameRect; + tr.UpperLeftCorner.X += 1; + tr.UpperLeftCorner.Y += 1; + 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); + } + else + { + tr.LowerRightCorner.X -= 2; + 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; + tr.LowerRightCorner.Y -= 1; + Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), tr, clip); + + // draw grey background + tr = frameRect; + tr.UpperLeftCorner.X += 1; + tr.UpperLeftCorner.Y -= 1; + 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); + } +} + + +//! 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 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. */ +void CGUISkin::draw3DTabBody(IGUIElement* element, bool border, bool background, + const core::rect& rect, const core::rect* clip, s32 tabHeight, EGUI_ALIGNMENT alignment) +{ + if (!Driver) + return; + + core::rect tr = rect; + + if ( tabHeight == -1 ) + tabHeight = getSize(gui::EGDS_BUTTON_HEIGHT); + + // draw border. + if (border) + { + if ( alignment == EGUIA_UPPERLEFT ) + { + // draw left hightlight + tr.UpperLeftCorner.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.UpperLeftCorner.Y = tr.LowerRightCorner.Y - 1; + Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), tr, clip); + } + else + { + // draw left hightlight + 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; + tr.UpperLeftCorner.Y += tabHeight + 2; + tr.LowerRightCorner.X -= 1; + tr.UpperLeftCorner.X += 1; + tr.LowerRightCorner.Y -= 1; + } + else + { + tr = rect; + tr.UpperLeftCorner.X += 1; + tr.UpperLeftCorner.Y -= 1; + tr.LowerRightCorner.X -= 1; + tr.LowerRightCorner.Y -= tabHeight + 2; + //tr.UpperLeftCorner.X += 1; + } + + if (!UseGradient) + Driver->draw2DRectangle(getColor(EGDC_3D_FACE), tr, clip); + else + { + video::SColor c1 = getColor(EGDC_3D_FACE); + video::SColor c2 = getColor(EGDC_3D_SHADOW); + Driver->draw2DRectangle(tr, c1, c1, c2, c2, clip); + } + } +} + + +//! 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 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 +\param currenttime: The present time, used to calculate the frame number +\param loop: Whether the animation should loop or not +\param clip: Clip area. */ +void CGUISkin::drawIcon(IGUIElement* element, EGUI_DEFAULT_ICON icon, + const core::position2di position, + u32 starttime, u32 currenttime, + bool loop, const core::rect* clip) +{ + if (!SpriteBank) + return; + + bool gray = element && !element->isEnabled(); + SpriteBank->draw2DSprite(Icons[icon], position, clip, + Colors[gray? EGDC_GRAY_WINDOW_SYMBOL : EGDC_WINDOW_SYMBOL], starttime, currenttime, loop, true); +} + + +EGUI_SKIN_TYPE CGUISkin::getType() const +{ + return Type; +} + + +//! draws a 2d rectangle. +void CGUISkin::draw2DRectangle(IGUIElement* element, + const video::SColor &color, const core::rect& pos, + const core::rect* clip) +{ + Driver->draw2DRectangle(color, pos, clip); +} + + +//! Writes attributes of the skin +void CGUISkin::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + u32 i; + for (i=0; iaddColor(GUISkinColorNames[i], Colors[i]); + + for (i=0; iaddInt(GUISkinSizeNames[i], Sizes[i]); + + for (i=0; iaddString(GUISkinTextNames[i], Texts[i].c_str()); + + for (i=0; iaddInt(GUISkinIconNames[i], Icons[i]); +} + + +//! Reads attributes of the skikn +void CGUISkin::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + u32 i; + for (i=0; igetAttributeAsColor(GUISkinColorNames[i], Colors[i]); + + for (i=0; igetAttributeAsInt(GUISkinSizeNames[i], Sizes[i]); + + for (i=0; igetAttributeAsStringW(GUISkinTextNames[i], Texts[i]); + + for (i=0; igetAttributeAsInt(GUISkinIconNames[i], Icons[i]); +} + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUISkin.h b/source/Irrlicht/CGUISkin.h new file mode 100644 index 00000000..eb58e6be --- /dev/null +++ b/source/Irrlicht/CGUISkin.h @@ -0,0 +1,247 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_SKIN_H_INCLUDED__ +#define __C_GUI_SKIN_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUISkin.h" +#include "irrString.h" + +namespace irr +{ +namespace video +{ + class IVideoDriver; +} +namespace gui +{ + + class CGUISkin : public IGUISkin + { + public: + + CGUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver); + + //! destructor + virtual ~CGUISkin(); + + //! returns default color + virtual video::SColor getColor(EGUI_DEFAULT_COLOR color) const _IRR_OVERRIDE_; + + //! sets a default color + virtual void setColor(EGUI_DEFAULT_COLOR which, video::SColor newColor) _IRR_OVERRIDE_; + + //! returns size for the given size type + virtual s32 getSize(EGUI_DEFAULT_SIZE size) const _IRR_OVERRIDE_; + + //! sets a default size + virtual void setSize(EGUI_DEFAULT_SIZE which, s32 size) _IRR_OVERRIDE_; + + //! returns the default font + virtual IGUIFont* getFont(EGUI_DEFAULT_FONT which=EGDF_DEFAULT) const _IRR_OVERRIDE_; + + //! sets a default font + virtual void setFont(IGUIFont* font, EGUI_DEFAULT_FONT which=EGDF_DEFAULT) _IRR_OVERRIDE_; + + //! sets the sprite bank used for drawing icons + virtual void setSpriteBank(IGUISpriteBank* bank) _IRR_OVERRIDE_; + + //! gets the sprite bank used for drawing icons + virtual IGUISpriteBank* getSpriteBank() const _IRR_OVERRIDE_; + + //! Returns a default icon + /** Returns the sprite index within the sprite bank */ + virtual u32 getIcon(EGUI_DEFAULT_ICON icon) const _IRR_OVERRIDE_; + + //! Sets a default icon + /** 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) _IRR_OVERRIDE_; + + //! Returns a default text. + /** For example for Message box button captions: + "OK", "Cancel", "Yes", "No" and so on. */ + virtual const wchar_t* getDefaultText(EGUI_DEFAULT_TEXT text) const _IRR_OVERRIDE_; + + //! Sets a default text. + /** For example for Message box button captions: + "OK", "Cancel", "Yes", "No" and so on. */ + virtual void setDefaultText(EGUI_DEFAULT_TEXT which, const wchar_t* newText) _IRR_OVERRIDE_; + + //! draws a standard 3d button pane + /** 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. + \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 + implementations to find out how to draw the part exactly. */ + virtual void draw3DButtonPaneStandard(IGUIElement* element, + const core::rect& rect, + const core::rect* clip=0) _IRR_OVERRIDE_; + + //! draws a pressed 3d button pane + /** 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. + \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 + implementations to find out how to draw the part exactly. */ + virtual void draw3DButtonPanePressed(IGUIElement* element, + const core::rect& rect, + const core::rect* clip=0) _IRR_OVERRIDE_; + + //! 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. + \param bgcolor: Background color. + \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, + video::SColor bgcolor, bool flat, + bool fillBackGround, + const core::rect& rect, + const core::rect* clip=0) _IRR_OVERRIDE_; + + //! 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. + \param titleBarColor: Title color. + \param drawTitleBar: True to enable title drawing. + \param rect: Defining area where to draw. + \param clip: Clip area. + \param checkClientArea: When set to non-null the function will not draw anything, + but will instead return the clientArea which can be used for drawing by the calling window. + That is the area without borders and without titlebar. + \return Returns rect where it would be good to draw title bar text. This will + work even when checkClientArea is set to a non-null value.*/ + virtual core::rect draw3DWindowBackground(IGUIElement* element, + bool drawTitleBar, video::SColor titleBarColor, + const core::rect& rect, + const core::rect* clip, + core::rect* checkClientArea) _IRR_OVERRIDE_; + + //! draws a standard 3d menu pane + /** 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. + \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 rect: Defining area where to draw. + \param clip: Clip area. */ + virtual void draw3DMenuPane(IGUIElement* element, + const core::rect& rect, + const core::rect* clip=0) _IRR_OVERRIDE_; + + //! draws a standard 3d tool bar + /** 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. + \param rect: Defining area where to draw. + \param clip: Clip area. */ + virtual void draw3DToolBar(IGUIElement* element, + const core::rect& rect, + const core::rect* clip=0) _IRR_OVERRIDE_; + + //! draws a tab button + /** 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. + \param active: Specifies if the tab is currently active. + \param rect: Defining area where to draw. + \param clip: Clip area. */ + virtual void draw3DTabButton(IGUIElement* element, bool active, + const core::rect& rect, const core::rect* clip=0, + EGUI_ALIGNMENT alignment=EGUIA_UPPERLEFT) _IRR_OVERRIDE_; + + //! 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 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. */ + virtual void draw3DTabBody(IGUIElement* element, bool border, bool background, + const core::rect& rect, const core::rect* clip=0, s32 tabHeight=-1, + EGUI_ALIGNMENT alignment=EGUIA_UPPERLEFT) _IRR_OVERRIDE_; + + //! 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 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 + \param currenttime: The present time, used to calculate the frame number + \param loop: Whether the animation should loop or not + \param clip: Clip area. */ + virtual void drawIcon(IGUIElement* element, EGUI_DEFAULT_ICON icon, + const core::position2di position, + u32 starttime=0, u32 currenttime=0, + bool loop=false, const core::rect* clip=0) _IRR_OVERRIDE_; + + + //! 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 + 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, + const core::rect& pos, const core::rect* clip = 0) _IRR_OVERRIDE_; + + + //! get the type of this skin + virtual EGUI_SKIN_TYPE getType() const _IRR_OVERRIDE_; + + //! Writes attributes of the skin + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the skin + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + private: + + video::SColor Colors[EGDC_COUNT]; + s32 Sizes[EGDS_COUNT]; + u32 Icons[EGDI_COUNT]; + IGUIFont* Fonts[EGDF_COUNT]; + IGUISpriteBank* SpriteBank; + core::stringw Texts[EGDT_COUNT]; + video::IVideoDriver* Driver; + bool UseGradient; + + EGUI_SKIN_TYPE Type; + }; + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif + + diff --git a/source/Irrlicht/CGUISpinBox.cpp b/source/Irrlicht/CGUISpinBox.cpp new file mode 100644 index 00000000..16e81656 --- /dev/null +++ b/source/Irrlicht/CGUISpinBox.cpp @@ -0,0 +1,346 @@ +// Copyright (C) 2006-2012 Michael Zeilfelder +// This file uses the licence of the Irrlicht Engine. + +#include "CGUISpinBox.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "CGUIEditBox.h" +#include "CGUIButton.h" +#include "IGUIEnvironment.h" +#include "IEventReceiver.h" +#include "fast_atof.h" +#include + + +namespace irr +{ +namespace gui +{ + +//! constructor +CGUISpinBox::CGUISpinBox(const wchar_t* text, bool border,IGUIEnvironment* environment, + IGUIElement* parent, s32 id, const core::rect& rectangle) +: IGUISpinBox(environment, parent, id, rectangle), + EditBox(0), ButtonSpinUp(0), ButtonSpinDown(0), StepSize(1.f), + RangeMin(-FLT_MAX), RangeMax(FLT_MAX), FormatString(L"%f"), + DecimalPlaces(-1), ValidateOn(EGUI_SBV_ENTER|EGUI_SBV_LOSE_FOCUS) +{ + #ifdef _DEBUG + setDebugName("CGUISpinBox"); + #endif + + CurrentIconColor = video::SColor(255,255,255,255); + s32 ButtonWidth = 16; + + ButtonSpinDown = Environment->addButton( + core::rect(rectangle.getWidth() - ButtonWidth, rectangle.getHeight()/2 +1, + rectangle.getWidth(), rectangle.getHeight()), this); + ButtonSpinDown->grab(); + ButtonSpinDown->setSubElement(true); + ButtonSpinDown->setTabStop(false); + ButtonSpinDown->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_CENTER, EGUIA_LOWERRIGHT); + + ButtonSpinUp = Environment->addButton( + core::rect(rectangle.getWidth() - ButtonWidth, 0, + rectangle.getWidth(), rectangle.getHeight()/2), this); + ButtonSpinUp->grab(); + ButtonSpinUp->setSubElement(true); + ButtonSpinUp->setTabStop(false); + ButtonSpinUp->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_CENTER); + + const core::rect rectEdit(0, 0, rectangle.getWidth() - ButtonWidth - 1, rectangle.getHeight()); + EditBox = Environment->addEditBox(text, rectEdit, border, this, -1); + EditBox->grab(); + EditBox->setSubElement(true); + EditBox->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + + refreshSprites(); +} + + +//! destructor +CGUISpinBox::~CGUISpinBox() +{ + if (ButtonSpinUp) + ButtonSpinUp->drop(); + if (ButtonSpinDown) + ButtonSpinDown->drop(); + if (EditBox) + EditBox->drop(); +} + +void CGUISpinBox::refreshSprites() +{ + IGUISpriteBank *sb = 0; + if (Environment && Environment->getSkin()) + { + sb = Environment->getSkin()->getSpriteBank(); + } + + if (sb) + { + IGUISkin * skin = Environment->getSkin(); + CurrentIconColor = skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL); + ButtonSpinDown->setSpriteBank(sb); + ButtonSpinDown->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_SMALL_CURSOR_DOWN), CurrentIconColor); + ButtonSpinDown->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_SMALL_CURSOR_DOWN), CurrentIconColor); + ButtonSpinUp->setSpriteBank(sb); + ButtonSpinUp->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_SMALL_CURSOR_UP), CurrentIconColor); + ButtonSpinUp->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_SMALL_CURSOR_UP), CurrentIconColor); + } + else + { + ButtonSpinDown->setText(L"-"); + ButtonSpinUp->setText(L"+"); + } +} + +IGUIEditBox* CGUISpinBox::getEditBox() const +{ + return EditBox; +} + + +void CGUISpinBox::setValue(f32 val) +{ + wchar_t str[100]; + + swprintf_irr(str, 99, FormatString.c_str(), val); + EditBox->setText(str); + verifyValueRange(); +} + + +f32 CGUISpinBox::getValue() const +{ + const wchar_t* val = EditBox->getText(); + if ( !val ) + return 0.f; + core::stringc tmp(val); + return core::fast_atof(tmp.c_str()); +} + + +void CGUISpinBox::setRange(f32 min, f32 max) +{ + if (maxOnEvent(e); + if ( eatEvent ) + return true; + } + } + + return IGUIElement::OnEvent(event); +} + + +void CGUISpinBox::draw() +{ + if ( !isVisible() ) + return; + + IGUISkin* skin = Environment->getSkin(); + if (!skin) + return; + + video::SColor iconColor = skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL); + if ( iconColor != CurrentIconColor ) + { + refreshSprites(); + } + + IGUISpinBox::draw(); +} + +void CGUISpinBox::verifyValueRange() +{ + f32 val = getValue(); + if ( val+core::ROUNDING_ERROR_f32 < RangeMin ) + val = RangeMin; + else if ( val-core::ROUNDING_ERROR_f32 > RangeMax ) + val = RangeMax; + else + return; + + setValue(val); +} + + +//! Sets the new caption of the element +void CGUISpinBox::setText(const wchar_t* text) +{ + EditBox->setText(text); + setValue(getValue()); + verifyValueRange(); +} + + +//! Returns caption of this element. +const wchar_t* CGUISpinBox::getText() const +{ + return EditBox->getText(); +} + + +//! Writes attributes of the element. +void CGUISpinBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + IGUIElement::serializeAttributes(out, options); + out->addFloat("Min", getMin()); + out->addFloat("Max", getMax()); + out->addFloat("Step", getStepSize()); + out->addInt("DecimalPlaces", DecimalPlaces); + out->addInt("ValidateOn", (s32)ValidateOn); +} + + +//! Reads attributes of the element +void CGUISpinBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + IGUIElement::deserializeAttributes(in, options); + setRange(in->getAttributeAsFloat("Min", RangeMin), in->getAttributeAsFloat("Max", RangeMax)); + setStepSize(in->getAttributeAsFloat("Step", StepSize)); + setDecimalPlaces(in->getAttributeAsInt("DecimalPlaces", DecimalPlaces)); + setValidateOn((u32)in->getAttributeAsInt("ValidateOn", (s32)ValidateOn) ); +} + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUISpinBox.h b/source/Irrlicht/CGUISpinBox.h new file mode 100644 index 00000000..1a84359a --- /dev/null +++ b/source/Irrlicht/CGUISpinBox.h @@ -0,0 +1,116 @@ +// Copyright (C) 2006-2012 Michael Zeilfelder +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_SPIN_BOX_H_INCLUDED__ +#define __C_GUI_SPIN_BOX_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUISpinBox.h" + +namespace irr +{ +namespace gui +{ + class IGUIEditBox; + class IGUIButton; + + class CGUISpinBox : public IGUISpinBox + { + public: + + //! constructor + CGUISpinBox(const wchar_t* text, bool border, IGUIEnvironment* environment, + IGUIElement* parent, s32 id, const core::rect& rectangle); + + //! destructor + virtual ~CGUISpinBox(); + + //! Access the edit box used in the spin control + /** \param enable: If set to true, the override color, which can be set + with IGUIEditBox::setOverrideColor is used, otherwise the + EGDC_BUTTON_TEXT color of the skin. */ + virtual IGUIEditBox* getEditBox() const _IRR_OVERRIDE_; + + //! set the current value of the spinbox + /** \param val: value to be set in the spinbox */ + virtual void setValue(f32 val) _IRR_OVERRIDE_; + + //! Get the current value of the spinbox + virtual f32 getValue() const _IRR_OVERRIDE_; + + //! set the range of values which can be used in the spinbox + /** \param min: minimum value + \param max: maximum value */ + virtual void setRange(f32 min, f32 max) _IRR_OVERRIDE_; + + //! get the minimum value which can be used in the spinbox + virtual f32 getMin() const _IRR_OVERRIDE_; + + //! get the maximum value which can be used in the spinbox + virtual f32 getMax() const _IRR_OVERRIDE_; + + //! step size by which values are changed when pressing the spin buttons + /** \param step: stepsize used for value changes when pressing spin buttons */ + virtual void setStepSize(f32 step=1.f) _IRR_OVERRIDE_; + + //! returns the step size + virtual f32 getStepSize() const _IRR_OVERRIDE_; + + //! called if an event happened. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! Draws the element and its children. + virtual void draw() _IRR_OVERRIDE_; + + //! Sets the new caption of the element + virtual void setText(const wchar_t* text) _IRR_OVERRIDE_; + + //! Returns caption of this element. + virtual const wchar_t* getText() const _IRR_OVERRIDE_; + + //! Sets the number of decimal places to display. + //! Note that this also rounds the range to the same number of decimal places. + /** \param places: The number of decimal places to display, use -1 to reset */ + virtual void setDecimalPlaces(s32 places) _IRR_OVERRIDE_; + + //! Sets when the spinbox has to validate entered text. + /** \param validateOn Can be any combination of EGUI_SPINBOX_VALIDATION bit flags */ + virtual void setValidateOn(u32 validateOn) _IRR_OVERRIDE_; + + //! Gets when the spinbox has to validate entered text. + virtual u32 getValidateOn() const _IRR_OVERRIDE_; + + //! Writes attributes of the element. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the element + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + + protected: + virtual void verifyValueRange(); + void refreshSprites(); + + IGUIEditBox * EditBox; + IGUIButton * ButtonSpinUp; + IGUIButton * ButtonSpinDown; + video::SColor CurrentIconColor; + f32 StepSize; + f32 RangeMin; + f32 RangeMax; + + core::stringw FormatString; + s32 DecimalPlaces; + u32 ValidateOn; // combination of EGUI_SPINBOX_VALIDATION bit-flags + }; + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif // __C_GUI_SPIN_BOX_H_INCLUDED__ + diff --git a/source/Irrlicht/CGUISpriteBank.cpp b/source/Irrlicht/CGUISpriteBank.cpp new file mode 100644 index 00000000..c89bb26e --- /dev/null +++ b/source/Irrlicht/CGUISpriteBank.cpp @@ -0,0 +1,253 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUISpriteBank.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" +#include "ITexture.h" + +namespace irr +{ +namespace gui +{ + +CGUISpriteBank::CGUISpriteBank(IGUIEnvironment* env) : + Environment(env), Driver(0) +{ + #ifdef _DEBUG + setDebugName("CGUISpriteBank"); + #endif + + if (Environment) + { + Driver = Environment->getVideoDriver(); + if (Driver) + Driver->grab(); + } +} + + +CGUISpriteBank::~CGUISpriteBank() +{ + // drop textures + for (u32 i=0; idrop(); + + // drop video driver + if (Driver) + Driver->drop(); +} + + +core::array< core::rect >& CGUISpriteBank::getPositions() +{ + return Rectangles; +} + + +core::array< SGUISprite >& CGUISpriteBank::getSprites() +{ + return Sprites; +} + + +u32 CGUISpriteBank::getTextureCount() const +{ + return Textures.size(); +} + + +video::ITexture* CGUISpriteBank::getTexture(u32 index) const +{ + if (index < Textures.size()) + return Textures[index]; + else + return 0; +} + + +void CGUISpriteBank::addTexture(video::ITexture* texture) +{ + if (texture) + texture->grab(); + + Textures.push_back(texture); +} + + +void CGUISpriteBank::setTexture(u32 index, video::ITexture* texture) +{ + while (index >= Textures.size()) + Textures.push_back(0); + + if (texture) + texture->grab(); + + if (Textures[index]) + Textures[index]->drop(); + + Textures[index] = texture; +} + + +//! clear everything +void CGUISpriteBank::clear() +{ + // drop textures + for (u32 i=0; idrop(); + } + Textures.clear(); + Sprites.clear(); + Rectangles.clear(); +} + +//! Add the texture and use it for a single non-animated sprite. +s32 CGUISpriteBank::addTextureAsSprite(video::ITexture* texture) +{ + if ( !texture ) + return -1; + + addTexture(texture); + u32 textureIndex = getTextureCount() - 1; + + u32 rectangleIndex = Rectangles.size(); + Rectangles.push_back( core::rect(0,0, texture->getOriginalSize().Width, texture->getOriginalSize().Height) ); + + SGUISprite sprite; + sprite.frameTime = 0; + + SGUISpriteFrame frame; + frame.textureNumber = textureIndex; + frame.rectNumber = rectangleIndex; + sprite.Frames.push_back( frame ); + + Sprites.push_back( sprite ); + + return Sprites.size() - 1; +} + +//! draws a sprite in 2d with scale and color +void CGUISpriteBank::draw2DSprite(u32 index, const core::position2di& pos, + const core::rect* clip, const video::SColor& color, + u32 starttime, u32 currenttime, bool loop, bool center) +{ + if (index >= Sprites.size() || Sprites[index].Frames.empty() ) + return; + + u32 frame = getFrameNr(index, currenttime - starttime, loop); + const video::ITexture* tex = getTexture(Sprites[index].Frames[frame].textureNumber); + if (!tex) + return; + + const u32 rn = Sprites[index].Frames[frame].rectNumber; + if (rn >= Rectangles.size()) + return; + + const core::rect& r = Rectangles[rn]; + core::position2di p(pos); + if (center) + { + p -= r.getSize() / 2; + } + Driver->draw2DImage(tex, p, r, clip, color, true); +} + +void CGUISpriteBank::draw2DSprite(u32 index, const core::rect& destRect, + const core::rect* clip, const video::SColor * const colors, + u32 timeTicks, bool loop) +{ + if (index >= Sprites.size() || Sprites[index].Frames.empty() ) + return; + + u32 frame = getFrameNr(index, timeTicks, loop); + const video::ITexture* tex = getTexture(Sprites[index].Frames[frame].textureNumber); + if (!tex) + return; + + const u32 rn = Sprites[index].Frames[frame].rectNumber; + if (rn >= Rectangles.size()) + return; + + Driver->draw2DImage(tex, destRect, Rectangles[rn], clip, colors, true); +} + +void CGUISpriteBank::draw2DSpriteBatch( const core::array& indices, + const core::array& pos, + const core::rect* clip, + const video::SColor& color, + u32 starttime, u32 currenttime, + bool loop, bool center) +{ + const irr::u32 drawCount = core::min_(indices.size(), pos.size()); + + if (!getTextureCount()) + return; + core::array drawBatches(getTextureCount()); + for (u32 i=0; i < Textures.size(); ++i) + { + drawBatches.push_back(SDrawBatch()); + drawBatches[i].positions.reallocate(drawCount); + drawBatches[i].sourceRects.reallocate(drawCount); + } + + for (u32 i = 0; i < drawCount; ++i) + { + const u32 index = indices[i]; + + if (index >= Sprites.size() || Sprites[index].Frames.empty() ) + continue; + + // work out frame number + u32 frame = 0; + if (Sprites[index].frameTime) + { + u32 f = ((currenttime - starttime) / Sprites[index].frameTime); + if (loop) + frame = f % Sprites[index].Frames.size(); + else + frame = (f >= Sprites[index].Frames.size()) ? Sprites[index].Frames.size()-1 : f; + } + + const u32 texNum = Sprites[index].Frames[frame].textureNumber; + SDrawBatch& currentBatch = drawBatches[texNum]; + + const u32 rn = Sprites[index].Frames[frame].rectNumber; + if (rn >= Rectangles.size()) + return; + + const core::rect& r = Rectangles[rn]; + + if (center) + { + core::position2di p = pos[i]; + p -= r.getSize() / 2; + + currentBatch.positions.push_back(p); + currentBatch.sourceRects.push_back(r); + } + else + { + currentBatch.positions.push_back(pos[i]); + currentBatch.sourceRects.push_back(r); + } + } + + for(u32 i = 0;i < drawBatches.size();i++) + { + if(!drawBatches[i].positions.empty() && !drawBatches[i].sourceRects.empty()) + Driver->draw2DImageBatch(getTexture(i), drawBatches[i].positions, + drawBatches[i].sourceRects, clip, color, true); + } +} + +} // namespace gui +} // namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ diff --git a/source/Irrlicht/CGUISpriteBank.h b/source/Irrlicht/CGUISpriteBank.h new file mode 100644 index 00000000..06c154d6 --- /dev/null +++ b/source/Irrlicht/CGUISpriteBank.h @@ -0,0 +1,105 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_SPRITE_BANK_H_INCLUDED__ +#define __C_GUI_SPRITE_BANK_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUISpriteBank.h" + +namespace irr +{ + +namespace video +{ + class IVideoDriver; + class ITexture; +} + +namespace gui +{ + + class IGUIEnvironment; + +//! Sprite bank interface. +class CGUISpriteBank : public IGUISpriteBank +{ +public: + + CGUISpriteBank(IGUIEnvironment* env); + virtual ~CGUISpriteBank(); + + virtual core::array< core::rect >& getPositions() _IRR_OVERRIDE_; + virtual core::array< SGUISprite >& getSprites() _IRR_OVERRIDE_; + + virtual u32 getTextureCount() const _IRR_OVERRIDE_; + virtual video::ITexture* getTexture(u32 index) const _IRR_OVERRIDE_; + virtual void addTexture(video::ITexture* texture) _IRR_OVERRIDE_; + virtual void setTexture(u32 index, video::ITexture* texture) _IRR_OVERRIDE_; + + //! Add the texture and use it for a single non-animated sprite. + virtual s32 addTextureAsSprite(video::ITexture* texture) _IRR_OVERRIDE_; + + //! clears sprites, rectangles and textures + virtual void clear() _IRR_OVERRIDE_; + + //! Draws a sprite in 2d with position and color + virtual void draw2DSprite(u32 index, const core::position2di& pos, const core::rect* clip=0, + const video::SColor& color= video::SColor(255,255,255,255), + u32 starttime=0, u32 currenttime=0, bool loop=true, bool center=false) _IRR_OVERRIDE_; + + //! Draws a sprite in 2d with destination rectangle and colors + virtual void draw2DSprite(u32 index, const core::rect& destRect, + const core::rect* clip=0, + const video::SColor * const colors=0, + u32 timeTicks = 0, + bool loop=true) _IRR_OVERRIDE_; + + //! Draws a sprite batch in 2d using an array of positions and a color + virtual void draw2DSpriteBatch(const core::array& indices, const core::array& pos, + const core::rect* clip=0, + const video::SColor& color= video::SColor(255,255,255,255), + u32 starttime=0, u32 currenttime=0, + bool loop=true, bool center=false) _IRR_OVERRIDE_; + +protected: + + inline u32 getFrameNr(u32 index, u32 time, bool loop) const + { + u32 frame = 0; + if (Sprites[index].frameTime && Sprites[index].Frames.size() ) + { + u32 f = (time / Sprites[index].frameTime); + if (loop) + frame = f % Sprites[index].Frames.size(); + else + frame = (f >= Sprites[index].Frames.size()) ? Sprites[index].Frames.size()-1 : f; + } + return frame; + } + + struct SDrawBatch + { + core::array positions; + core::array sourceRects; + u32 textureNumber; + }; + + core::array Sprites; + core::array< core::rect > Rectangles; + core::array Textures; + IGUIEnvironment* Environment; + video::IVideoDriver* Driver; + +}; + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif // __C_GUI_SPRITE_BANK_H_INCLUDED__ + diff --git a/source/Irrlicht/CGUIStaticText.cpp b/source/Irrlicht/CGUIStaticText.cpp new file mode 100644 index 00000000..fc26a1a9 --- /dev/null +++ b/source/Irrlicht/CGUIStaticText.cpp @@ -0,0 +1,632 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUIStaticText.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IGUIFont.h" +#include "IVideoDriver.h" +#include "rect.h" + +namespace irr +{ +namespace gui +{ + +//! constructor +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), + HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_UPPERLEFT), + Border(border), OverrideColorEnabled(false), OverrideBGColorEnabled(false), WordWrap(false), Background(background), + RestrainTextInside(true), RightToLeft(false), + OverrideColor(video::SColor(101,255,255,255)), BGColor(video::SColor(101,210,210,210)), + OverrideFont(0), LastBreakFont(0) +{ + #ifdef _DEBUG + setDebugName("CGUIStaticText"); + #endif + + Text = text; + if (environment && environment->getSkin()) + { + BGColor = environment->getSkin()->getColor(gui::EGDC_3D_FACE); + } +} + + +//! destructor +CGUIStaticText::~CGUIStaticText() +{ + if (OverrideFont) + OverrideFont->drop(); +} + + +//! draws the element and its children +void CGUIStaticText::draw() +{ + if (!IsVisible) + return; + + IGUISkin* skin = Environment->getSkin(); + if (!skin) + return; + video::IVideoDriver* driver = Environment->getVideoDriver(); + + core::rect frameRect(AbsoluteRect); + + // draw background + + if (Background) + { + if ( !OverrideBGColorEnabled ) // skin-colors can change + BGColor = skin->getColor(gui::EGDC_3D_FACE); + + driver->draw2DRectangle(BGColor, frameRect, &AbsoluteClippingRect); + } + + // draw the border + + if (Border) + { + skin->draw3DSunkenPane(this, 0, true, false, frameRect, &AbsoluteClippingRect); + frameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X); + } + + // draw the text + if (Text.size()) + { + IGUIFont* font = getActiveFont(); + + if (font) + { + if (!WordWrap) + { + if (VAlign == EGUIA_LOWERRIGHT) + { + frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y - + font->getDimension(L"A").Height - font->getKerningHeight(); + } + if (HAlign == EGUIA_LOWERRIGHT) + { + frameRect.UpperLeftCorner.X = frameRect.LowerRightCorner.X - + font->getDimension(Text.c_str()).Width; + } + + font->draw(Text.c_str(), frameRect, + OverrideColorEnabled ? OverrideColor : skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT), + HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER, (RestrainTextInside ? &AbsoluteClippingRect : NULL)); + } + else + { + if (font != LastBreakFont) + breakText(); + + core::rect r = frameRect; + s32 height = font->getDimension(L"A").Height + font->getKerningHeight(); + s32 totalHeight = height * BrokenText.size(); + if (VAlign == EGUIA_CENTER) + { + r.UpperLeftCorner.Y = r.getCenter().Y - (totalHeight / 2); + } + else if (VAlign == EGUIA_LOWERRIGHT) + { + r.UpperLeftCorner.Y = r.LowerRightCorner.Y - totalHeight; + } + + for (u32 i=0; igetDimension(BrokenText[i].c_str()).Width; + } + + font->draw(BrokenText[i].c_str(), r, + OverrideColorEnabled ? OverrideColor : skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT), + HAlign == EGUIA_CENTER, false, (RestrainTextInside ? &AbsoluteClippingRect : NULL)); + + r.LowerRightCorner.Y += height; + r.UpperLeftCorner.Y += height; + } + } + } + } + + IGUIElement::draw(); +} + + +//! Sets another skin independent font. +void CGUIStaticText::setOverrideFont(IGUIFont* font) +{ + if (OverrideFont == font) + return; + + if (OverrideFont) + OverrideFont->drop(); + + OverrideFont = font; + + if (OverrideFont) + OverrideFont->grab(); + + breakText(); +} + +//! Gets the override font (if any) +IGUIFont * CGUIStaticText::getOverrideFont() const +{ + return OverrideFont; +} + +//! Get the font which is used right now for drawing +IGUIFont* CGUIStaticText::getActiveFont() const +{ + if ( OverrideFont ) + return OverrideFont; + IGUISkin* skin = Environment->getSkin(); + if (skin) + return skin->getFont(); + return 0; +} + +//! Sets another color for the text. +void CGUIStaticText::setOverrideColor(video::SColor color) +{ + OverrideColor = color; + OverrideColorEnabled = true; +} + + +//! Sets another color for the text. +void CGUIStaticText::setBackgroundColor(video::SColor color) +{ + BGColor = color; + OverrideBGColorEnabled = true; + Background = true; +} + + +//! Sets whether to draw the background +void CGUIStaticText::setDrawBackground(bool draw) +{ + Background = draw; +} + + +//! Gets the background color +video::SColor CGUIStaticText::getBackgroundColor() const +{ + return BGColor; +} + + +//! Checks if background drawing is enabled +bool CGUIStaticText::isDrawBackgroundEnabled() const +{ + return Background; +} + + +//! Sets whether to draw the border +void CGUIStaticText::setDrawBorder(bool draw) +{ + Border = draw; +} + + +//! Checks if border drawing is enabled +bool CGUIStaticText::isDrawBorderEnabled() const +{ + return Border; +} + + +void CGUIStaticText::setTextRestrainedInside(bool restrainTextInside) +{ + RestrainTextInside = restrainTextInside; +} + + +bool CGUIStaticText::isTextRestrainedInside() const +{ + return RestrainTextInside; +} + + +void CGUIStaticText::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical) +{ + HAlign = horizontal; + VAlign = vertical; +} + + +video::SColor CGUIStaticText::getOverrideColor() const +{ + return OverrideColor; +} + + +//! Sets if the static text should use the override color or the +//! color in the gui skin. +void CGUIStaticText::enableOverrideColor(bool enable) +{ + OverrideColorEnabled = enable; +} + + +bool CGUIStaticText::isOverrideColorEnabled() const +{ + return OverrideColorEnabled; +} + + +//! Enables or disables word wrap for using the static text as +//! multiline text control. +void CGUIStaticText::setWordWrap(bool enable) +{ + WordWrap = enable; + breakText(); +} + + +bool CGUIStaticText::isWordWrapEnabled() const +{ + return WordWrap; +} + + +void CGUIStaticText::setRightToLeft(bool rtl) +{ + if (RightToLeft != rtl) + { + RightToLeft = rtl; + breakText(); + } +} + + +bool CGUIStaticText::isRightToLeft() const +{ + return RightToLeft; +} + + +//! Breaks the single text line. +void CGUIStaticText::breakText() +{ + if (!WordWrap) + return; + + BrokenText.clear(); + + IGUISkin* skin = Environment->getSkin(); + IGUIFont* font = getActiveFont(); + if (!font) + return; + + LastBreakFont = font; + + core::stringw line; + core::stringw word; + core::stringw whitespace; + s32 size = Text.size(); + s32 length = 0; + s32 elWidth = RelativeRect.getWidth(); + if (Border) + elWidth -= 2*skin->getSize(EGDS_TEXT_DISTANCE_X); + wchar_t c; + + // We have to deal with right-to-left and left-to-right differently + // However, most parts of the following code is the same, it's just + // some order and boundaries which change. + if (!RightToLeft) + { + // regular (left-to-right) + for (s32 i=0; igetDimension(whitespace.c_str()).Width; + const s32 wordlgth = font->getDimension(word.c_str()).Width; + + if (wordlgth > elWidth) + { + // This word is too long to fit in the available space, look for + // the Unicode Soft HYphen (SHY / 00AD) character for a place to + // break the word at + int where = word.findFirst( wchar_t(0x00AD) ); + if (where != -1) + { + core::stringw first = word.subString(0, where); + core::stringw second = word.subString(where, word.size() - where); + BrokenText.push_back(line + first + L"-"); + const s32 secondLength = font->getDimension(second.c_str()).Width; + + length = secondLength; + line = second; + } + else + { + // No soft hyphen found, so there's nothing more we can do + // break to next line + if (length) + BrokenText.push_back(line); + length = wordlgth; + line = word; + } + } + else if (length && (length + wordlgth + whitelgth > elWidth)) + { + // break to next line + BrokenText.push_back(line); + length = wordlgth; + line = word; + } + else + { + // add word to line + line += whitespace; + line += word; + length += whitelgth + wordlgth; + } + + word = L""; + whitespace = L""; + } + + if ( isWhitespace ) + { + whitespace += c; + } + + // compute line break + if (lineBreak) + { + line += whitespace; + line += word; + BrokenText.push_back(line); + line = L""; + word = L""; + whitespace = L""; + length = 0; + } + } + } + + line += whitespace; + line += word; + BrokenText.push_back(line); + } + else + { + // right-to-left + for (s32 i=size; i>=0; --i) + { + c = Text[i]; + bool lineBreak = false; + + if (c == L'\r') // Mac or Windows breaks + { + lineBreak = true; + if ((i>0) && Text[i-1] == L'\n') // Windows breaks + { + Text.erase(i-1); + --size; + } + c = '\0'; + } + else if (c == L'\n') // Unix breaks + { + lineBreak = true; + c = '\0'; + } + + if (c==L' ' || c==0 || i==0) + { + if (word.size()) + { + // here comes the next whitespace, look if + // we must break the last word to the next line. + const s32 whitelgth = font->getDimension(whitespace.c_str()).Width; + const s32 wordlgth = font->getDimension(word.c_str()).Width; + + if (length && (length + wordlgth + whitelgth > elWidth)) + { + // break to next line + BrokenText.push_back(line); + length = wordlgth; + line = word; + } + else + { + // add word to line + line = whitespace + line; + line = word + line; + length += whitelgth + wordlgth; + } + + word = L""; + whitespace = L""; + } + + if (c != 0) + whitespace = core::stringw(&c, 1) + whitespace; + + // compute line break + if (lineBreak) + { + line = whitespace + line; + line = word + line; + BrokenText.push_back(line); + line = L""; + word = L""; + whitespace = L""; + length = 0; + } + } + else + { + // yippee this is a word.. + word = core::stringw(&c, 1) + word; + } + } + + line = whitespace + line; + line = word + line; + BrokenText.push_back(line); + } +} + + +//! Sets the new caption of this element. +void CGUIStaticText::setText(const wchar_t* text) +{ + IGUIElement::setText(text); + breakText(); +} + + +void CGUIStaticText::updateAbsolutePosition() +{ + IGUIElement::updateAbsolutePosition(); + breakText(); +} + + +//! Returns the height of the text in pixels when it is drawn. +s32 CGUIStaticText::getTextHeight() const +{ + IGUIFont* font = getActiveFont(); + if (!font) + return 0; + + if (WordWrap) + { + s32 height = font->getDimension(L"A").Height + font->getKerningHeight(); + return height* BrokenText.size(); + } + else + { + // TODO: Text can have multiple lines which are not in BrokenText + // This is likely not correct. But as I have no time for further + // investigation I just fix it for now by return the true height here. + return font->getDimension(Text.c_str()).Height; + } +} + + +s32 CGUIStaticText::getTextWidth() const +{ + IGUIFont * font = getActiveFont(); + if(!font) + return 0; + + if(WordWrap) + { + s32 widest = 0; + + for(u32 line = 0; line < BrokenText.size(); ++line) + { + s32 width = font->getDimension(BrokenText[line].c_str()).Width; + + if(width > widest) + widest = width; + } + + return widest; + } + else + { + return font->getDimension(Text.c_str()).Width; + } +} + + +//! Writes attributes of the element. +//! Implement this to expose the attributes of your element for +//! scripting languages, editors, debuggers or xml serialization purposes. +void CGUIStaticText::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const +{ + IGUIStaticText::serializeAttributes(out,options); + + out->addBool ("Border", Border); + out->addBool ("OverrideColorEnabled",OverrideColorEnabled); + out->addBool ("OverrideBGColorEnabled",OverrideBGColorEnabled); + out->addBool ("WordWrap", WordWrap); + out->addBool ("Background", Background); + out->addBool ("RightToLeft", RightToLeft); + out->addBool ("RestrainTextInside", RestrainTextInside); + out->addColor ("OverrideColor", OverrideColor); + out->addColor ("BGColor", BGColor); + out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames); + out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames); + + // out->addFont ("OverrideFont", OverrideFont); +} + + +//! Reads attributes of the element +void CGUIStaticText::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) +{ + IGUIStaticText::deserializeAttributes(in,options); + + Border = in->getAttributeAsBool("Border", Border); + enableOverrideColor(in->getAttributeAsBool("OverrideColorEnabled", OverrideColorEnabled)); + OverrideBGColorEnabled = in->getAttributeAsBool("OverrideBGColorEnabled", OverrideBGColorEnabled); + setWordWrap(in->getAttributeAsBool("WordWrap", WordWrap)); + Background = in->getAttributeAsBool("Background", Background); + RightToLeft = in->getAttributeAsBool("RightToLeft", RightToLeft); + RestrainTextInside = in->getAttributeAsBool("RestrainTextInside", RestrainTextInside); + OverrideColor = in->getAttributeAsColor("OverrideColor", OverrideColor); + BGColor = in->getAttributeAsColor("BGColor", BGColor); + + setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames, (s32)HAlign), + (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames, (s32)VAlign)); + + // OverrideFont = in->getAttributeAsFont("OverrideFont"); +} + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIStaticText.h b/source/Irrlicht/CGUIStaticText.h new file mode 100644 index 00000000..7ca74019 --- /dev/null +++ b/source/Irrlicht/CGUIStaticText.h @@ -0,0 +1,145 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_STATIC_TEXT_H_INCLUDED__ +#define __C_GUI_STATIC_TEXT_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIStaticText.h" +#include "irrArray.h" + +namespace irr +{ +namespace gui +{ + class CGUIStaticText : public IGUIStaticText + { + public: + + //! constructor + CGUIStaticText(const wchar_t* text, bool border, IGUIEnvironment* environment, + IGUIElement* parent, s32 id, const core::rect& rectangle, + bool background = false); + + //! destructor + virtual ~CGUIStaticText(); + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + //! Sets another skin independent font. + virtual void setOverrideFont(IGUIFont* font=0) _IRR_OVERRIDE_; + + //! Gets the override font (if any) + virtual IGUIFont* getOverrideFont() const _IRR_OVERRIDE_; + + //! Get the font which is used right now for drawing + virtual IGUIFont* getActiveFont() const _IRR_OVERRIDE_; + + //! Sets another color for the text. + virtual void setOverrideColor(video::SColor color) _IRR_OVERRIDE_; + + //! Sets another color for the background. + virtual void setBackgroundColor(video::SColor color) _IRR_OVERRIDE_; + + //! Sets whether to draw the background + virtual void setDrawBackground(bool draw) _IRR_OVERRIDE_; + + //! Gets the background color + virtual video::SColor getBackgroundColor() const _IRR_OVERRIDE_; + + //! Checks if background drawing is enabled + virtual bool isDrawBackgroundEnabled() const _IRR_OVERRIDE_; + + //! Sets whether to draw the border + virtual void setDrawBorder(bool draw) _IRR_OVERRIDE_; + + //! Checks if border drawing is enabled + virtual bool isDrawBorderEnabled() const _IRR_OVERRIDE_; + + //! Sets alignment mode for text + virtual void setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical) _IRR_OVERRIDE_; + + //! Gets the override color + virtual video::SColor getOverrideColor() const _IRR_OVERRIDE_; + + //! Sets if the static text should use the override color or the + //! color in the gui skin. + virtual void enableOverrideColor(bool enable) _IRR_OVERRIDE_; + + //! Checks if an override color is enabled + virtual bool isOverrideColorEnabled() const _IRR_OVERRIDE_; + + //! Set whether the text in this label should be clipped if it goes outside bounds + virtual void setTextRestrainedInside(bool restrainedInside) _IRR_OVERRIDE_; + + //! Checks if the text in this label should be clipped if it goes outside bounds + virtual bool isTextRestrainedInside() const _IRR_OVERRIDE_; + + //! Enables or disables word wrap for using the static text as + //! multiline text control. + virtual void setWordWrap(bool enable) _IRR_OVERRIDE_; + + //! Checks if word wrap is enabled + virtual bool isWordWrapEnabled() const _IRR_OVERRIDE_; + + //! Sets the new caption of this element. + virtual void setText(const wchar_t* text) _IRR_OVERRIDE_; + + //! Returns the height of the text in pixels when it is drawn. + virtual s32 getTextHeight() const _IRR_OVERRIDE_; + + //! Returns the width of the current text, in the current font + virtual s32 getTextWidth() const _IRR_OVERRIDE_; + + //! Updates the absolute position, splits text if word wrap is enabled + virtual void updateAbsolutePosition() _IRR_OVERRIDE_; + + //! Set whether the string should be interpreted as right-to-left (RTL) text + /** \note This component does not implement the Unicode bidi standard, the + text of the component should be already RTL if you call this. The + main difference when RTL is enabled is that the linebreaks for multiline + elements are performed starting from the end. + */ + virtual void setRightToLeft(bool rtl) _IRR_OVERRIDE_; + + //! Checks if the text should be interpreted as right-to-left text + virtual bool isRightToLeft() const _IRR_OVERRIDE_; + + //! Writes attributes of the element. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the element + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + + private: + + //! Breaks the single text line. + void breakText(); + + EGUI_ALIGNMENT HAlign, VAlign; + bool Border; + bool OverrideColorEnabled; + bool OverrideBGColorEnabled; + bool WordWrap; + bool Background; + bool RestrainTextInside; + bool RightToLeft; + + video::SColor OverrideColor, BGColor; + gui::IGUIFont* OverrideFont; + gui::IGUIFont* LastBreakFont; // stored because: if skin changes, line break must be recalculated. + + core::array< core::stringw > BrokenText; + }; + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif + diff --git a/source/Irrlicht/CGUITabControl.cpp b/source/Irrlicht/CGUITabControl.cpp new file mode 100644 index 00000000..998856b1 --- /dev/null +++ b/source/Irrlicht/CGUITabControl.cpp @@ -0,0 +1,1059 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUITabControl.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "CGUIButton.h" +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IGUIFont.h" +#include "IVideoDriver.h" +#include "rect.h" +#include "os.h" + +namespace irr +{ +namespace gui +{ + +// ------------------------------------------------------------------ +// Tab +// ------------------------------------------------------------------ + +//! constructor +CGUITab::CGUITab(IGUIEnvironment* environment, + IGUIElement* parent, const core::rect& rectangle, + s32 id) + : IGUITab(environment, parent, id, rectangle), + BackColor(0,0,0,0), OverrideTextColorEnabled(false), TextColor(255,0,0,0), + DrawBackground(false) +{ + #ifdef _DEBUG + setDebugName("CGUITab"); + #endif + + const IGUISkin* const skin = environment->getSkin(); + if (skin) + TextColor = skin->getColor(EGDC_BUTTON_TEXT); +} + +//! draws the element and its children +void CGUITab::draw() +{ + if (!IsVisible) + return; + + IGUISkin *skin = Environment->getSkin(); + + if (skin && DrawBackground) + skin->draw2DRectangle(this, BackColor, AbsoluteRect, &AbsoluteClippingRect); + + IGUIElement::draw(); +} + + +//! sets if the tab should draw its background +void CGUITab::setDrawBackground(bool draw) +{ + DrawBackground = draw; +} + + +//! sets the color of the background, if it should be drawn. +void CGUITab::setBackgroundColor(video::SColor c) +{ + BackColor = c; +} + + +//! sets the color of the text +void CGUITab::setTextColor(video::SColor c) +{ + OverrideTextColorEnabled = true; + TextColor = c; +} + + +video::SColor CGUITab::getTextColor() const +{ + if ( OverrideTextColorEnabled ) + return TextColor; + else + return Environment->getSkin()->getColor(EGDC_BUTTON_TEXT); +} + +//! returns true if the tab is drawing its background, false if not +bool CGUITab::isDrawingBackground() const +{ + return DrawBackground; +} + + +//! returns the color of the background +video::SColor CGUITab::getBackgroundColor() const +{ + return BackColor; +} + + +//! Writes attributes of the element. +void CGUITab::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const +{ + IGUITab::serializeAttributes(out,options); + + IGUITabControl* parentTabControl = Parent && Parent->getType() == EGUIET_TAB_CONTROL ? static_cast(Parent) : 0; + if ( parentTabControl ) + out->addInt ("TabNumber", parentTabControl->getTabIndex(this)); // order of children and tabs can be different, so we save tab-number + out->addBool ("DrawBackground", DrawBackground); + out->addColor ("BackColor", BackColor); + out->addBool ("OverrideTextColorEnabled", OverrideTextColorEnabled); + out->addColor ("TextColor", TextColor); + +} + + +//! Reads attributes of the element +void CGUITab::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) +{ + IGUITab::deserializeAttributes(in,options); + + setDrawBackground(in->getAttributeAsBool("DrawBackground", DrawBackground)); + setBackgroundColor(in->getAttributeAsColor("BackColor", BackColor)); + bool overrideColor = in->getAttributeAsBool("OverrideTextColorEnabled", OverrideTextColorEnabled); + setTextColor(in->getAttributeAsColor("TextColor", TextColor)); + OverrideTextColorEnabled = overrideColor; // because setTextColor does set OverrideTextColorEnabled always to true + + IGUITabControl* parentTabControl = Parent && Parent->getType() == EGUIET_TAB_CONTROL ? static_cast(Parent) : 0; + if (parentTabControl) + { + s32 idx = in->getAttributeAsInt("TabNumber", -1); + if ( idx >= 0 ) + parentTabControl->insertTab(idx, this, true); + else + parentTabControl->addTab(this); + } +} + + +// ------------------------------------------------------------------ +// Tabcontrol +// ------------------------------------------------------------------ + +//! constructor +CGUITabControl::CGUITabControl(IGUIEnvironment* environment, + IGUIElement* parent, const core::rect& rectangle, + bool fillbackground, bool border, s32 id) + : IGUITabControl(environment, parent, id, rectangle), ActiveTabIndex(-1), + Border(border), FillBackground(fillbackground), ScrollControl(false), TabHeight(0), VerticalAlignment(EGUIA_UPPERLEFT), + UpButton(0), DownButton(0), TabMaxWidth(0), CurrentScrollTabIndex(0), TabExtraWidth(20) +{ + #ifdef _DEBUG + setDebugName("CGUITabControl"); + #endif + + IGUISkin* skin = Environment->getSkin(); + IGUISpriteBank* sprites = 0; + + TabHeight = 32; + + if (skin) + { + sprites = skin->getSpriteBank(); + TabHeight = skin->getSize(gui::EGDS_BUTTON_HEIGHT) + 2; + } + + UpButton = Environment->addButton(core::rect(0,0,10,10), this); + + if (UpButton) + { + UpButton->setSpriteBank(sprites); + UpButton->setVisible(false); + UpButton->setSubElement(true); + UpButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + UpButton->setOverrideFont(Environment->getBuiltInFont()); + UpButton->grab(); + } + + DownButton = Environment->addButton(core::rect(0,0,10,10), this); + + if (DownButton) + { + DownButton->setSpriteBank(sprites); + DownButton->setVisible(false); + DownButton->setSubElement(true); + DownButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + DownButton->setOverrideFont(Environment->getBuiltInFont()); + DownButton->grab(); + } + + setTabVerticalAlignment(EGUIA_UPPERLEFT); + refreshSprites(); +} + +//! destructor +CGUITabControl::~CGUITabControl() +{ + for (u32 i=0; idrop(); + } + + if (UpButton) + UpButton->drop(); + + if (DownButton) + DownButton->drop(); +} + +void CGUITabControl::refreshSprites() +{ + video::SColor color(255,255,255,255); + IGUISkin* skin = Environment->getSkin(); + if (skin) + { + color = skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL); + + if (UpButton) + { + UpButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_LEFT), color); + UpButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_LEFT), color); + } + + if (DownButton) + { + DownButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_RIGHT), color); + DownButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_RIGHT), color); + } + } +} + +//! Adds a tab +IGUITab* CGUITabControl::addTab(const wchar_t* caption, s32 id) +{ + CGUITab* tab = new CGUITab(Environment, this, calcTabPos(), id); + + tab->setText(caption); + tab->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + tab->setVisible(false); + Tabs.push_back(tab); // no grab as new already creates a reference + + if (ActiveTabIndex == -1) + { + ActiveTabIndex = Tabs.size()-1; + tab->setVisible(true); + } + + recalculateScrollBar(); + + return tab; +} + + +//! adds a tab which has been created elsewhere +s32 CGUITabControl::addTab(IGUITab* tab) +{ + return insertTab( Tabs.size(), tab, false); +} + +//! Insert the tab at the given index +IGUITab* CGUITabControl::insertTab(s32 idx, const wchar_t* caption, s32 id) +{ + if ( idx < 0 || idx > (s32)Tabs.size() ) // idx == Tabs.size() is indeed OK here as core::array can handle that + return NULL; + + CGUITab* tab = new CGUITab(Environment, this, calcTabPos(), id); + + tab->setText(caption); + tab->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + tab->setVisible(false); + Tabs.insert(tab, (u32)idx); + + if (ActiveTabIndex == -1) + { + ActiveTabIndex = (u32)idx; + tab->setVisible(true); + } + else if ( idx <= ActiveTabIndex ) + { + ++ActiveTabIndex; + setVisibleTab(ActiveTabIndex); + } + + recalculateScrollBar(); + + return tab; +} + +s32 CGUITabControl::insertTab(s32 idx, IGUITab* tab, bool serializationMode) +{ + if (!tab) + return -1; + if ( idx > (s32)Tabs.size() && !serializationMode ) // idx == Tabs.size() is indeed OK here as core::array can handle that + return -1; + // Not allowing to add same tab twice as it would make things complicated (serialization or setting active visible) + if ( getTabIndex(tab) >= 0 ) + return -1; + + if ( idx < 0 ) + idx = (s32)Tabs.size(); + + if ( tab->getParent() != this ) + this->addChildToEnd(tab); + + tab->setVisible(false); + + tab->grab(); + + if ( serializationMode) + { + while ( idx >= (s32)Tabs.size() ) + { + Tabs.push_back(0); + } + Tabs[idx] = tab; + + if ( idx == ActiveTabIndex) // in serialization that can happen for any index + { + setVisibleTab(ActiveTabIndex); + tab->setVisible(true); + } + } + else + { + Tabs.insert(tab, (u32)idx); + + if (ActiveTabIndex == -1) + { + ActiveTabIndex = idx; + setVisibleTab(ActiveTabIndex); + } + else if ( idx <= ActiveTabIndex) + { + ++ActiveTabIndex; + setVisibleTab(ActiveTabIndex); + } + } + + recalculateScrollBar(); + + return idx; +} + +//! Removes a child. +void CGUITabControl::removeChild(IGUIElement* child) +{ + s32 idx = getTabIndex(child); + if ( idx >= 0 ) + removeTabButNotChild(idx); + + // remove real element + IGUIElement::removeChild(child); + + recalculateScrollBar(); +} + + +//! Removes a tab from the tabcontrol +void CGUITabControl::removeTab(s32 idx) +{ + if ( idx < 0 || idx >= (s32)Tabs.size() ) + return; + + removeChild(Tabs[(u32)idx]); +} + +void CGUITabControl::removeTabButNotChild(s32 idx) +{ + if ( idx < 0 || idx >= (s32)Tabs.size() ) + return; + + Tabs[(u32)idx]->drop(); + Tabs.erase((u32)idx); + + if ( idx < ActiveTabIndex ) + { + --ActiveTabIndex; + setVisibleTab(ActiveTabIndex); + } + else if ( idx == ActiveTabIndex ) + { + if ( (u32)idx == Tabs.size() ) + --ActiveTabIndex; + setVisibleTab(ActiveTabIndex); + } +} + +//! Clears the tabcontrol removing all tabs +void CGUITabControl::clear() +{ + for (u32 i=0; idrop(); + } + } + Tabs.clear(); + + recalculateScrollBar(); +} + +//! Returns amount of tabs in the tabcontrol +s32 CGUITabControl::getTabCount() const +{ + return Tabs.size(); +} + + +//! Returns a tab based on zero based index +IGUITab* CGUITabControl::getTab(s32 idx) const +{ + if (idx < 0 || (u32)idx >= Tabs.size()) + return 0; + + return Tabs[idx]; +} + + +//! called if an event happened. +bool CGUITabControl::OnEvent(const SEvent& event) +{ + if (isEnabled()) + { + switch(event.EventType) + { + case EET_GUI_EVENT: + switch(event.GUIEvent.EventType) + { + case EGET_BUTTON_CLICKED: + if (event.GUIEvent.Caller == UpButton) + { + scrollLeft(); + return true; + } + else if (event.GUIEvent.Caller == DownButton) + { + scrollRight(); + return true; + } + + break; + default: + break; + } + break; + case EET_MOUSE_INPUT_EVENT: + switch(event.MouseInput.Event) + { + //case EMIE_LMOUSE_PRESSED_DOWN: + // // todo: dragging tabs around + // return true; + case EMIE_LMOUSE_LEFT_UP: + { + s32 idx = getTabAt(event.MouseInput.X, event.MouseInput.Y); + if ( idx >= 0 ) + { + setActiveTab(idx); + return true; + } + break; + } + default: + break; + } + break; + default: + break; + } + } + + return IGUIElement::OnEvent(event); +} + + +void CGUITabControl::scrollLeft() +{ + if ( CurrentScrollTabIndex > 0 ) + --CurrentScrollTabIndex; + recalculateScrollBar(); +} + + +void CGUITabControl::scrollRight() +{ + if ( CurrentScrollTabIndex < (s32)(Tabs.size()) - 1 ) + { + if ( needScrollControl(CurrentScrollTabIndex, true) ) + ++CurrentScrollTabIndex; + } + recalculateScrollBar(); +} + +s32 CGUITabControl::calcTabWidth(s32 pos, IGUIFont* font, const wchar_t* text, bool withScrollControl) const +{ + if ( !font ) + return 0; + + s32 len = font->getDimension(text).Width + TabExtraWidth; + if ( TabMaxWidth > 0 && len > TabMaxWidth ) + len = TabMaxWidth; + + // check if we miss the place to draw the tab-button + if ( withScrollControl && ScrollControl && pos+len > UpButton->getAbsolutePosition().UpperLeftCorner.X - 2 ) + { + s32 tabMinWidth = font->getDimension(L"A").Width; + if ( TabExtraWidth > 0 && TabExtraWidth > tabMinWidth ) + tabMinWidth = TabExtraWidth; + + if ( ScrollControl && pos+tabMinWidth <= UpButton->getAbsolutePosition().UpperLeftCorner.X - 2 ) + { + len = UpButton->getAbsolutePosition().UpperLeftCorner.X - 2 - pos; + } + } + return len; +} + +bool CGUITabControl::needScrollControl(s32 startIndex, bool withScrollControl) +{ + if ( startIndex >= (s32)Tabs.size() ) + startIndex -= 1; + + if ( startIndex < 0 ) + startIndex = 0; + + IGUISkin* skin = Environment->getSkin(); + if (!skin) + return false; + + IGUIFont* font = skin->getFont(); + + core::rect frameRect(AbsoluteRect); + + if (Tabs.empty()) + return false; + + if (!font) + return false; + + s32 pos = frameRect.UpperLeftCorner.X + 2; + + for (s32 i=startIndex; i<(s32)Tabs.size(); ++i) + { + // get Text + const wchar_t* text = 0; + if (Tabs[i]) + { + text = Tabs[i]->getText(); + + // get text length + s32 len = calcTabWidth(pos, font, text, false); // always without withScrollControl here or len would be shortened + + frameRect.LowerRightCorner.X += len; + + frameRect.UpperLeftCorner.X = pos; + frameRect.LowerRightCorner.X = frameRect.UpperLeftCorner.X + len; + pos += len; + } + + if ( withScrollControl && pos > UpButton->getAbsolutePosition().UpperLeftCorner.X - 2) + return true; + + if ( !withScrollControl && pos > AbsoluteRect.LowerRightCorner.X ) + return true; + } + + return false; +} + + +core::rect CGUITabControl::calcTabPos() +{ + core::rect r; + r.UpperLeftCorner.X = 0; + r.LowerRightCorner.X = AbsoluteRect.getWidth(); + if ( Border ) + { + ++r.UpperLeftCorner.X; + --r.LowerRightCorner.X; + } + + if ( VerticalAlignment == EGUIA_UPPERLEFT ) + { + r.UpperLeftCorner.Y = TabHeight+2; + r.LowerRightCorner.Y = AbsoluteRect.getHeight()-1; + if ( Border ) + { + --r.LowerRightCorner.Y; + } + } + else + { + r.UpperLeftCorner.Y = 0; + r.LowerRightCorner.Y = AbsoluteRect.getHeight()-(TabHeight+2); + if ( Border ) + { + ++r.UpperLeftCorner.Y; + } + } + + return r; +} + + +//! draws the element and its children +void CGUITabControl::draw() +{ + if (!IsVisible) + return; + + IGUISkin* skin = Environment->getSkin(); + if (!skin) + return; + + IGUIFont* font = skin->getFont(); + video::IVideoDriver* driver = Environment->getVideoDriver(); + + core::rect frameRect(AbsoluteRect); + + // some empty background as placeholder when there are no tabs + if (Tabs.empty()) + driver->draw2DRectangle(skin->getColor(EGDC_3D_HIGH_LIGHT), frameRect, &AbsoluteClippingRect); + + if (!font) + return; + + // tab button bar can be above or below the tabs + if ( VerticalAlignment == EGUIA_UPPERLEFT ) + { + frameRect.UpperLeftCorner.Y += 2; + frameRect.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y + TabHeight; + } + else + { + frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y - TabHeight - 1; + frameRect.LowerRightCorner.Y -= 2; + } + + core::rect tr; + s32 pos = frameRect.UpperLeftCorner.X + 2; + + bool needLeftScroll = CurrentScrollTabIndex > 0; + bool needRightScroll = false; + + // left and right pos of the active tab + s32 left = 0; + s32 right = 0; + + //const wchar_t* activetext = 0; + IGUITab *activeTab = 0; + + // Draw all tab-buttons except the active one + for (u32 i=CurrentScrollTabIndex; igetText(); + + // get text length + s32 len = calcTabWidth(pos, font, text, true); + if ( ScrollControl && pos+len > UpButton->getAbsolutePosition().UpperLeftCorner.X - 2 ) + { + needRightScroll = true; + break; + } + + frameRect.LowerRightCorner.X += len; + frameRect.UpperLeftCorner.X = pos; + frameRect.LowerRightCorner.X = frameRect.UpperLeftCorner.X + len; + + pos += len; + + if ((s32)i == ActiveTabIndex) + { + // for active button just remember values + left = frameRect.UpperLeftCorner.X; + right = frameRect.LowerRightCorner.X; + //activetext = text; + activeTab = Tabs[i]; + } + else + { + skin->draw3DTabButton(this, false, frameRect, &AbsoluteClippingRect, VerticalAlignment); + + // draw text + core::rect textClipRect(frameRect); // TODO: exact size depends on borders in draw3DTabButton which we don't get with current interface + textClipRect.clipAgainst(AbsoluteClippingRect); + font->draw(text, frameRect, Tabs[i]->getTextColor(), + true, true, &textClipRect); + } + } + + // Draw active tab button + // Drawn later than other buttons because it draw over the buttons before/after it. + if (left != 0 && right != 0 && activeTab != 0) + { + // draw upper highlight frame + if ( VerticalAlignment == EGUIA_UPPERLEFT ) + { + frameRect.UpperLeftCorner.X = left-2; + frameRect.LowerRightCorner.X = right+2; + frameRect.UpperLeftCorner.Y -= 2; + + skin->draw3DTabButton(this, true, frameRect, &AbsoluteClippingRect, VerticalAlignment); + + // draw text + core::rect textClipRect(frameRect); // TODO: exact size depends on borders in draw3DTabButton which we don't get with current interface + textClipRect.clipAgainst(AbsoluteClippingRect); + font->draw(activeTab->getText(), frameRect, activeTab->getTextColor(), + true, true, &textClipRect); + + tr.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X; + tr.LowerRightCorner.X = left - 1; + tr.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y - 1; + tr.LowerRightCorner.Y = frameRect.LowerRightCorner.Y; + driver->draw2DRectangle(skin->getColor(EGDC_3D_HIGH_LIGHT), tr, &AbsoluteClippingRect); + + tr.UpperLeftCorner.X = right; + tr.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X; + driver->draw2DRectangle(skin->getColor(EGDC_3D_HIGH_LIGHT), tr, &AbsoluteClippingRect); + } + else + { + frameRect.UpperLeftCorner.X = left-2; + frameRect.LowerRightCorner.X = right+2; + frameRect.LowerRightCorner.Y += 2; + + skin->draw3DTabButton(this, true, frameRect, &AbsoluteClippingRect, VerticalAlignment); + + // draw text + font->draw(activeTab->getText(), frameRect, activeTab->getTextColor(), + true, true, &frameRect); + + tr.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X; + tr.LowerRightCorner.X = left - 1; + tr.UpperLeftCorner.Y = frameRect.UpperLeftCorner.Y - 1; + tr.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y; + driver->draw2DRectangle(skin->getColor(EGDC_3D_DARK_SHADOW), tr, &AbsoluteClippingRect); + + tr.UpperLeftCorner.X = right; + tr.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X; + driver->draw2DRectangle(skin->getColor(EGDC_3D_DARK_SHADOW), tr, &AbsoluteClippingRect); + } + } + else + { + // No active tab + // Draw a line separating button bar from tab area + tr.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X; + tr.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X; + tr.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y - 1; + tr.LowerRightCorner.Y = frameRect.LowerRightCorner.Y; + + if ( VerticalAlignment == EGUIA_UPPERLEFT ) + { + driver->draw2DRectangle(skin->getColor(EGDC_3D_HIGH_LIGHT), tr, &AbsoluteClippingRect); + } + else + { + tr.UpperLeftCorner.Y = frameRect.UpperLeftCorner.Y - 1; + tr.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y; + driver->draw2DRectangle(skin->getColor(EGDC_3D_DARK_SHADOW), tr, &AbsoluteClippingRect); + } + } + + // drawing some border and background for the tab-area. + skin->draw3DTabBody(this, Border, FillBackground, AbsoluteRect, &AbsoluteClippingRect, TabHeight, VerticalAlignment); + + // enable scrollcontrols on need + if ( UpButton ) + UpButton->setEnabled(needLeftScroll); + if ( DownButton ) + DownButton->setEnabled(needRightScroll); + refreshSprites(); + + IGUIElement::draw(); +} + + +//! Set the height of the tabs +void CGUITabControl::setTabHeight( s32 height ) +{ + if ( height < 0 ) + height = 0; + + TabHeight = height; + + recalculateScrollButtonPlacement(); + recalculateScrollBar(); +} + + +//! Get the height of the tabs +s32 CGUITabControl::getTabHeight() const +{ + return TabHeight; +} + +//! set the maximal width of a tab. Per default width is 0 which means "no width restriction". +void CGUITabControl::setTabMaxWidth(s32 width ) +{ + TabMaxWidth = width; +} + +//! get the maximal width of a tab +s32 CGUITabControl::getTabMaxWidth() const +{ + return TabMaxWidth; +} + + +//! Set the extra width added to tabs on each side of the text +void CGUITabControl::setTabExtraWidth( s32 extraWidth ) +{ + if ( extraWidth < 0 ) + extraWidth = 0; + + TabExtraWidth = extraWidth; + + recalculateScrollBar(); +} + + +//! Get the extra width added to tabs on each side of the text +s32 CGUITabControl::getTabExtraWidth() const +{ + return TabExtraWidth; +} + + +void CGUITabControl::recalculateScrollBar() +{ + if (!UpButton || !DownButton) + return; + + ScrollControl = needScrollControl() || CurrentScrollTabIndex > 0; + + if (ScrollControl) + { + UpButton->setVisible( true ); + DownButton->setVisible( true ); + } + else + { + UpButton->setVisible( false ); + DownButton->setVisible( false ); + } + + bringToFront( UpButton ); + bringToFront( DownButton ); +} + +//! Set the alignment of the tabs +void CGUITabControl::setTabVerticalAlignment( EGUI_ALIGNMENT alignment ) +{ + VerticalAlignment = alignment; + + recalculateScrollButtonPlacement(); + recalculateScrollBar(); + + core::rect r(calcTabPos()); + for ( u32 i=0; isetRelativePosition(r); + } +} + +void CGUITabControl::recalculateScrollButtonPlacement() +{ + IGUISkin* skin = Environment->getSkin(); + s32 ButtonSize = 16; + s32 ButtonHeight = TabHeight - 2; + if ( ButtonHeight < 0 ) + ButtonHeight = TabHeight; + if (skin) + { + ButtonSize = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH); + if (ButtonSize > TabHeight) + ButtonSize = TabHeight; + } + + s32 ButtonX = RelativeRect.getWidth() - (s32)(2.5f*(f32)ButtonSize) - 1; + s32 ButtonY = 0; + + if (VerticalAlignment == EGUIA_UPPERLEFT) + { + ButtonY = 2 + (TabHeight / 2) - (ButtonHeight / 2); + UpButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + DownButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + } + else + { + ButtonY = RelativeRect.getHeight() - (TabHeight / 2) - (ButtonHeight / 2) - 2; + 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+ButtonHeight)); + ButtonX += ButtonSize + 1; + DownButton->setRelativePosition(core::rect(ButtonX, ButtonY, ButtonX+ButtonSize, ButtonY+ButtonHeight)); +} + +//! Get the alignment of the tabs +EGUI_ALIGNMENT CGUITabControl::getTabVerticalAlignment() const +{ + return VerticalAlignment; +} + + +s32 CGUITabControl::getTabAt(s32 xpos, s32 ypos) const +{ + core::position2di p(xpos, ypos); + IGUISkin* skin = Environment->getSkin(); + IGUIFont* font = skin->getFont(); + + core::rect frameRect(AbsoluteRect); + + if ( VerticalAlignment == EGUIA_UPPERLEFT ) + { + frameRect.UpperLeftCorner.Y += 2; + frameRect.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y + TabHeight; + } + else + { + frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y - TabHeight; + } + + s32 pos = frameRect.UpperLeftCorner.X + 2; + + if (!frameRect.isPointInside(p)) + return -1; + + for (s32 i=CurrentScrollTabIndex; i<(s32)Tabs.size(); ++i) + { + // get Text + const wchar_t* text = 0; + if (Tabs[i]) + text = Tabs[i]->getText(); + + // get text length + s32 len = calcTabWidth(pos, font, text, true); + if ( ScrollControl && pos+len > UpButton->getAbsolutePosition().UpperLeftCorner.X - 2 ) + return -1; + + frameRect.UpperLeftCorner.X = pos; + frameRect.LowerRightCorner.X = frameRect.UpperLeftCorner.X + len; + + pos += len; + + if (frameRect.isPointInside(p)) + { + return i; + } + } + return -1; +} + +//! Returns which tab is currently active +s32 CGUITabControl::getActiveTab() const +{ + return ActiveTabIndex; +} + + +//! Brings a tab to front. +bool CGUITabControl::setActiveTab(s32 idx) +{ + if ((u32)idx >= Tabs.size()) + return false; + + bool changed = (ActiveTabIndex != idx); + + ActiveTabIndex = idx; + + setVisibleTab(ActiveTabIndex); + + if (changed && Parent) + { + SEvent event; + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.Element = 0; + event.GUIEvent.EventType = EGET_TAB_CHANGED; + Parent->OnEvent(event); + } + + return true; +} + +void CGUITabControl::setVisibleTab(s32 idx) +{ + for (u32 i=0; isetVisible( (s32)i == idx ); +} + + +bool CGUITabControl::setActiveTab(IGUITab *tab) +{ + return setActiveTab(getTabIndex(tab)); +} + +s32 CGUITabControl::getTabIndex(const IGUIElement *tab) const +{ + for (u32 i=0; iaddInt ("ActiveTab", ActiveTabIndex); + out->addBool("Border", Border); + out->addBool("FillBackground", FillBackground); + out->addInt ("TabHeight", TabHeight); + out->addInt ("TabMaxWidth", TabMaxWidth); + out->addEnum("TabVerticalAlignment", s32(VerticalAlignment), GUIAlignmentNames); +} + + +//! Reads attributes of the element +void CGUITabControl::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) +{ + Border = in->getAttributeAsBool("Border"); + FillBackground = in->getAttributeAsBool("FillBackground"); + + ActiveTabIndex = -1; + + setTabHeight(in->getAttributeAsInt("TabHeight")); + TabMaxWidth = in->getAttributeAsInt("TabMaxWidth"); + + IGUITabControl::deserializeAttributes(in,options); + + ActiveTabIndex = in->getAttributeAsInt("ActiveTab", -1); // not setActiveTab as tabs are loaded later + setTabVerticalAlignment( static_cast(in->getAttributeAsEnumeration("TabVerticalAlignment" , GUIAlignmentNames)) ); +} + + +} // end namespace irr +} // end namespace gui + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUITabControl.h b/source/Irrlicht/CGUITabControl.h new file mode 100644 index 00000000..3752a10f --- /dev/null +++ b/source/Irrlicht/CGUITabControl.h @@ -0,0 +1,198 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_TAB_CONTROL_H_INCLUDED__ +#define __C_GUI_TAB_CONTROL_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUITabControl.h" +#include "irrArray.h" +#include "IGUISkin.h" + +namespace irr +{ +namespace gui +{ + class CGUITabControl; + class IGUIButton; + + // A tab, onto which other gui elements could be added. + class CGUITab : public IGUITab + { + public: + + //! constructor + CGUITab(IGUIEnvironment* environment, + IGUIElement* parent, const core::rect& rectangle, + s32 id); + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + //! sets if the tab should draw its background + virtual void setDrawBackground(bool draw=true) _IRR_OVERRIDE_; + + //! sets the color of the background, if it should be drawn. + virtual void setBackgroundColor(video::SColor c) _IRR_OVERRIDE_; + + //! sets the color of the text + virtual void setTextColor(video::SColor c) _IRR_OVERRIDE_; + + //! returns true if the tab is drawing its background, false if not + virtual bool isDrawingBackground() const _IRR_OVERRIDE_; + + //! returns the color of the background + virtual video::SColor getBackgroundColor() const _IRR_OVERRIDE_; + + virtual video::SColor getTextColor() const _IRR_OVERRIDE_; + + //! Writes attributes of the element. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the element + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + + private: + + video::SColor BackColor; + bool OverrideTextColorEnabled; + video::SColor TextColor; + bool DrawBackground; + }; + + + //! A standard tab control + class CGUITabControl : public IGUITabControl + { + public: + + //! destructor + CGUITabControl(IGUIEnvironment* environment, + IGUIElement* parent, const core::rect& rectangle, + bool fillbackground=true, bool border=true, s32 id=-1); + + //! destructor + virtual ~CGUITabControl(); + + //! Adds a tab + virtual IGUITab* addTab(const wchar_t* caption, s32 id=-1) _IRR_OVERRIDE_; + + //! Adds an existing tab + virtual s32 addTab(IGUITab* tab) _IRR_OVERRIDE_; + + //! Insert the tab at the given index + virtual IGUITab* insertTab(s32 idx, const wchar_t* caption, s32 id=-1) _IRR_OVERRIDE_; + + //! Insert an existing tab + /** Note that it will also add the tab as a child of this TabControl. + \return Index of added tab (should be same as the one passed) or -1 for failure*/ + virtual s32 insertTab(s32 idx, IGUITab* tab, bool serializationMode) _IRR_OVERRIDE_; + + //! Removes a tab from the tabcontrol + virtual void removeTab(s32 idx) _IRR_OVERRIDE_; + + //! Clears the tabcontrol removing all tabs + virtual void clear() _IRR_OVERRIDE_; + + //! Returns amount of tabs in the tabcontrol + virtual s32 getTabCount() const _IRR_OVERRIDE_; + + //! Returns a tab based on zero based index + virtual IGUITab* getTab(s32 idx) const _IRR_OVERRIDE_; + + //! Brings a tab to front. + virtual bool setActiveTab(s32 idx) _IRR_OVERRIDE_; + + //! Brings a tab to front. + virtual bool setActiveTab(IGUITab *tab) _IRR_OVERRIDE_; + + //! For given given tab find it's zero-based index (or -1 for not found) + virtual s32 getTabIndex(const IGUIElement *tab) const _IRR_OVERRIDE_; + + //! Returns which tab is currently active + virtual s32 getActiveTab() const _IRR_OVERRIDE_; + + //! get the the id of the tab at the given absolute coordinates + virtual s32 getTabAt(s32 xpos, s32 ypos) const _IRR_OVERRIDE_; + + //! called if an event happened. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + //! Removes a child. + virtual void removeChild(IGUIElement* child) _IRR_OVERRIDE_; + + //! Writes attributes of the element. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + //! Set the height of the tabs + virtual void setTabHeight( s32 height ) _IRR_OVERRIDE_; + + //! Reads attributes of the element + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + + //! Get the height of the tabs + virtual s32 getTabHeight() const _IRR_OVERRIDE_; + + //! set the maximal width of a tab. Per default width is 0 which means "no width restriction". + virtual void setTabMaxWidth(s32 width ) _IRR_OVERRIDE_; + + //! get the maximal width of a tab + virtual s32 getTabMaxWidth() const _IRR_OVERRIDE_; + + //! Set the alignment of the tabs + //! note: EGUIA_CENTER is not an option + virtual void setTabVerticalAlignment( gui::EGUI_ALIGNMENT alignment ) _IRR_OVERRIDE_; + + //! Get the alignment of the tabs + virtual gui::EGUI_ALIGNMENT getTabVerticalAlignment() const _IRR_OVERRIDE_; + + //! Set the extra width added to tabs on each side of the text + virtual void setTabExtraWidth( s32 extraWidth ) _IRR_OVERRIDE_; + + //! Get the extra width added to tabs on each side of the text + virtual s32 getTabExtraWidth() const _IRR_OVERRIDE_; + + //! Update the position of the element, decides scroll button status + virtual void updateAbsolutePosition() _IRR_OVERRIDE_; + + private: + + void scrollLeft(); + void scrollRight(); + bool needScrollControl( s32 startIndex=0, bool withScrollControl=false ); + s32 calcTabWidth(s32 pos, IGUIFont* font, const wchar_t* text, bool withScrollControl ) const; + core::rect calcTabPos(); + void setVisibleTab(s32 idx); + void removeTabButNotChild(s32 idx); + + void recalculateScrollButtonPlacement(); + void recalculateScrollBar(); + void refreshSprites(); + + core::array Tabs; + s32 ActiveTabIndex; + bool Border; + bool FillBackground; + bool ScrollControl; + s32 TabHeight; + gui::EGUI_ALIGNMENT VerticalAlignment; + IGUIButton* UpButton; + IGUIButton* DownButton; + s32 TabMaxWidth; + s32 CurrentScrollTabIndex; + s32 TabExtraWidth; + }; + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif + diff --git a/source/Irrlicht/CGUITable.cpp b/source/Irrlicht/CGUITable.cpp new file mode 100644 index 00000000..206f7ff5 --- /dev/null +++ b/source/Irrlicht/CGUITable.cpp @@ -0,0 +1,1296 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +// 07.10.2005 - Multicolor-Listbox added by A. Buschhueter (Acki) +// A_Buschhueter@gmx.de + +#include "CGUITable.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" +#include "IGUIFont.h" +#include "CGUIScrollBar.h" +#include "os.h" + +#define ARROW_PAD 15 + +namespace irr +{ +namespace gui +{ + +//! constructor +CGUITable::CGUITable(IGUIEnvironment* environment, IGUIElement* parent, + s32 id, const core::rect& rectangle, bool clip, + bool drawBack, bool moveOverSelect) +: IGUITable(environment, parent, id, rectangle), + VerticalScrollBar(0), HorizontalScrollBar(0), + Clip(clip), DrawBack(drawBack), MoveOverSelect(moveOverSelect), + Selecting(false), CurrentResizedColumn(-1), ResizeStart(0), ResizableColumns(true), + ItemHeight(0), TotalItemHeight(0), TotalItemWidth(0), Selected(-1), + CellHeightPadding(2), CellWidthPadding(5), ActiveTab(-1), + CurrentOrdering(EGOM_NONE), DrawFlags(EGTDF_ROWS | EGTDF_COLUMNS | EGTDF_ACTIVE_ROW ), + ScrollBarSize(0), + OverrideFont(0) +{ + #ifdef _DEBUG + setDebugName("CGUITable"); + #endif + + VerticalScrollBar = Environment->addScrollBar(false, core::rect(0, 0, 100, 100), this, -1); + if (VerticalScrollBar) + { + VerticalScrollBar->grab(); + VerticalScrollBar->setNotClipped(false); + VerticalScrollBar->setSubElement(true); + } + + HorizontalScrollBar = Environment->addScrollBar(true, core::rect(0, 0, 100, 100), this, -1); + if ( HorizontalScrollBar ) + { + HorizontalScrollBar->grab(); + HorizontalScrollBar->setNotClipped(false); + HorizontalScrollBar->setSubElement(true); + } + + refreshControls(); +} + + +//! destructor +CGUITable::~CGUITable() +{ + if (VerticalScrollBar) + VerticalScrollBar->drop(); + if ( HorizontalScrollBar ) + HorizontalScrollBar->drop(); + + if (OverrideFont) + OverrideFont->drop(); +} + + +void CGUITable::addColumn(const wchar_t* caption, s32 columnIndex) +{ + Column tabHeader; + tabHeader.Name = caption; + tabHeader.Width = getActiveFont()->getDimension(caption).Width + (CellWidthPadding * 2) + ARROW_PAD; + tabHeader.OrderingMode = EGCO_NONE; + + if ( columnIndex < 0 || columnIndex >= (s32)Columns.size() ) + { + Columns.push_back(tabHeader); + for ( u32 i=0; i < Rows.size(); ++i ) + { + Cell cell; + Rows[i].Items.push_back(cell); + } + } + else + { + Columns.insert(tabHeader, columnIndex); + for ( u32 i=0; i < Rows.size(); ++i ) + { + Cell cell; + Rows[i].Items.insert(cell, columnIndex); + } + } + + if (ActiveTab == -1 && Columns.size() == 1) // first column added - make it active automatically + ActiveTab = 0; + + recalculateWidths(); +} + + +//! remove a column from the table +void CGUITable::removeColumn(u32 columnIndex) +{ + if ( columnIndex < Columns.size() ) + { + Columns.erase(columnIndex); + for ( u32 i=0; i < Rows.size(); ++i ) + { + Rows[i].Items.erase(columnIndex); + } + } + if ( (s32)columnIndex <= ActiveTab ) + ActiveTab = Columns.size() ? 0 : -1; + + recalculateWidths(); +} + + +s32 CGUITable::getColumnCount() const +{ + return Columns.size(); +} + + +s32 CGUITable::getRowCount() const +{ + return Rows.size(); +} + + +bool CGUITable::setActiveColumn(s32 idx, bool doOrder ) +{ + if ( idx >= (s32)Columns.size() ) + idx = -1; + + bool changed = (ActiveTab != idx); + ActiveTab = idx; + if ( ActiveTab < 0 ) + return false; + + if ( doOrder ) + { + switch ( Columns[idx].OrderingMode ) + { + case EGCO_NONE: + CurrentOrdering = EGOM_NONE; + break; + + case EGCO_CUSTOM: + CurrentOrdering = EGOM_NONE; + if (Parent) + { + SEvent event; + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.Element = 0; + event.GUIEvent.EventType = EGET_TABLE_HEADER_CHANGED; + Parent->OnEvent(event); + } + + break; + + case EGCO_ASCENDING: + CurrentOrdering = EGOM_ASCENDING; + break; + + case EGCO_DESCENDING: + CurrentOrdering = EGOM_DESCENDING; + break; + + case EGCO_FLIP_ASCENDING_DESCENDING: + CurrentOrdering = EGOM_ASCENDING == CurrentOrdering ? EGOM_DESCENDING : EGOM_ASCENDING; + break; + default: + CurrentOrdering = EGOM_NONE; + } + + orderRows(getActiveColumn(), CurrentOrdering); + } + + if (changed) + { + SEvent event; + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.Element = 0; + event.GUIEvent.EventType = EGET_TABLE_HEADER_CHANGED; + Parent->OnEvent(event); + } + + 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() ) + { + const u32 MIN_WIDTH = getActiveFont()->getDimension(Columns[columnIndex].Name.c_str() ).Width + (CellWidthPadding * 2); + if ( width < MIN_WIDTH ) + width = MIN_WIDTH; + + Columns[columnIndex].Width = width; + + for ( u32 i=0; i < Rows.size(); ++i ) + { + breakText( Rows[i].Items[columnIndex].Text, Rows[i].Items[columnIndex].BrokenText, Columns[columnIndex].Width ); + } + } + recalculateWidths(); +} + +//! Get the width of a column +u32 CGUITable::getColumnWidth(u32 columnIndex) const +{ + if ( columnIndex >= Columns.size() ) + return 0; + + return Columns[columnIndex].Width; +} + +void CGUITable::setResizableColumns(bool resizable) +{ + ResizableColumns = resizable; +} + + +bool CGUITable::hasResizableColumns() const +{ + return ResizableColumns; +} + + +u32 CGUITable::addRow(u32 rowIndex) +{ + if ( rowIndex > Rows.size() ) + { + rowIndex = Rows.size(); + } + + Row row; + + if ( rowIndex == Rows.size() ) + Rows.push_back(row); + else + Rows.insert(row, rowIndex); + + Rows[rowIndex].Items.reallocate(Columns.size()); + for ( u32 i = 0 ; i < Columns.size() ; ++i ) + { + Rows[rowIndex].Items.push_back(Cell()); + } + + recalculateHeights(); + return rowIndex; +} + + +void CGUITable::removeRow(u32 rowIndex) +{ + if ( rowIndex > Rows.size() ) + return; + + Rows.erase( rowIndex ); + + if ( !(Selected < s32(Rows.size())) ) + Selected = Rows.size() - 1; + + recalculateHeights(); +} + + +//! adds an list item, returns id of item +void CGUITable::setCellText(u32 rowIndex, u32 columnIndex, const core::stringw& text) +{ + if ( rowIndex < Rows.size() && columnIndex < Columns.size() ) + { + Rows[rowIndex].Items[columnIndex].Text = text; + breakText( Rows[rowIndex].Items[columnIndex].Text, Rows[rowIndex].Items[columnIndex].BrokenText, Columns[columnIndex].Width ); + + IGUISkin* skin = Environment->getSkin(); + if ( skin ) + Rows[rowIndex].Items[columnIndex].Color = skin->getColor(EGDC_BUTTON_TEXT); + } +} + +void CGUITable::setCellText(u32 rowIndex, u32 columnIndex, const core::stringw& text, video::SColor color) +{ + if ( rowIndex < Rows.size() && columnIndex < Columns.size() ) + { + Rows[rowIndex].Items[columnIndex].Text = text; + breakText( Rows[rowIndex].Items[columnIndex].Text, Rows[rowIndex].Items[columnIndex].BrokenText, Columns[columnIndex].Width ); + Rows[rowIndex].Items[columnIndex].Color = color; + Rows[rowIndex].Items[columnIndex].IsOverrideColor = true; + } +} + + +void CGUITable::setCellColor(u32 rowIndex, u32 columnIndex, video::SColor color) +{ + if ( rowIndex < Rows.size() && columnIndex < Columns.size() ) + { + Rows[rowIndex].Items[columnIndex].Color = color; + Rows[rowIndex].Items[columnIndex].IsOverrideColor = true; + } +} + + +void CGUITable::setCellData(u32 rowIndex, u32 columnIndex, void *data) +{ + if ( rowIndex < Rows.size() && columnIndex < Columns.size() ) + { + Rows[rowIndex].Items[columnIndex].Data = data; + } +} + + +const wchar_t* CGUITable::getCellText(u32 rowIndex, u32 columnIndex ) const +{ + if ( rowIndex < Rows.size() && columnIndex < Columns.size() ) + { + return Rows[rowIndex].Items[columnIndex].Text.c_str(); + } + + return 0; +} + + +void* CGUITable::getCellData(u32 rowIndex, u32 columnIndex ) const +{ + if ( rowIndex < Rows.size() && columnIndex < Columns.size() ) + { + return Rows[rowIndex].Items[columnIndex].Data; + } + + return 0; +} + + +//! clears the list +void CGUITable::clear() +{ + Selected = -1; + Rows.clear(); + Columns.clear(); + + if (VerticalScrollBar) + VerticalScrollBar->setPos(0); + if ( HorizontalScrollBar ) + HorizontalScrollBar->setPos(0); + + recalculateHeights(); + recalculateWidths(); +} + + +void CGUITable::clearRows() +{ + Selected = -1; + Rows.clear(); + + if (VerticalScrollBar) + VerticalScrollBar->setPos(0); + + recalculateHeights(); +} + + +/*! +*/ +s32 CGUITable::getSelected() const +{ + return Selected; +} + +//! set which row is currently selected +void CGUITable::setSelected( s32 index ) +{ + Selected = -1; + if ( index >= 0 && index < (s32) Rows.size() ) + Selected = index; +} + + +void CGUITable::recalculateWidths() +{ + TotalItemWidth=0; + for ( u32 i=0; i < Columns.size(); ++i ) + { + TotalItemWidth += Columns[i].Width; + } + checkScrollbars(); +} + + +void CGUITable::recalculateHeights() +{ + IGUIFont* activeFont = getActiveFont(); + if(activeFont) + { + ItemHeight = activeFont->getDimension(L"A").Height + (CellHeightPadding * 2); + TotalItemHeight = ItemHeight * Rows.size(); // header is not counted, because we only want items + } + else + { + ItemHeight = 0; + TotalItemHeight = 0; + } + checkScrollbars(); +} + + +// automatic enabled/disabling and resizing of scrollbars +void CGUITable::checkScrollbars() +{ + IGUISkin* skin = Environment->getSkin(); + if ( !HorizontalScrollBar || !VerticalScrollBar || !skin) + return; + + ScrollBarSize = skin->getSize(EGDS_SCROLLBAR_SIZE); + + bool wasHorizontalScrollBarVisible = HorizontalScrollBar->isVisible(); + bool wasVerticalScrollBarVisible = VerticalScrollBar->isVisible(); + HorizontalScrollBar->setVisible(false); + VerticalScrollBar->setVisible(false); + + // CAREFUL: near identical calculations for tableRect and clientClip are also done in draw + // area of table used for drawing without scrollbars + core::rect tableRect(AbsoluteRect); + tableRect.UpperLeftCorner.X += 1; + tableRect.UpperLeftCorner.Y += 1; + s32 headerBottom = tableRect.UpperLeftCorner.Y + ItemHeight; + + // area of for the items (without header and without scrollbars) + core::rect clientClip(tableRect); + clientClip.UpperLeftCorner.Y = headerBottom + 1; + + // needs horizontal scroll be visible? + if( TotalItemWidth > clientClip.getWidth() ) + { + clientClip.LowerRightCorner.Y -= ScrollBarSize; + HorizontalScrollBar->setVisible(true); + HorizontalScrollBar->setMax(core::max_(0,TotalItemWidth - clientClip.getWidth())); + } + + // needs vertical scroll be visible? + if( TotalItemHeight > clientClip.getHeight() ) + { + clientClip.LowerRightCorner.X -= ScrollBarSize; + VerticalScrollBar->setVisible(true); + VerticalScrollBar->setMax(core::max_(0,TotalItemHeight - clientClip.getHeight())); + + // check horizontal again because we have now smaller clientClip + if ( !HorizontalScrollBar->isVisible() ) + { + if( TotalItemWidth > clientClip.getWidth() ) + { + clientClip.LowerRightCorner.Y -= ScrollBarSize; + HorizontalScrollBar->setVisible(true); + HorizontalScrollBar->setMax(core::max_(0,TotalItemWidth - clientClip.getWidth())); + } + } + } + + // find the correct size for the vertical scrollbar + if ( VerticalScrollBar->isVisible() ) + { + if (!wasVerticalScrollBarVisible ) + VerticalScrollBar->setPos(0); + + if ( HorizontalScrollBar->isVisible() ) + { + VerticalScrollBar->setRelativePosition( + core::rect(RelativeRect.getWidth() - ScrollBarSize, 1, + RelativeRect.getWidth()-1, RelativeRect.getHeight()-(1+ScrollBarSize) ) ); + } + else + { + VerticalScrollBar->setRelativePosition( + core::rect(RelativeRect.getWidth() - ScrollBarSize, 1, + RelativeRect.getWidth()-1, RelativeRect.getHeight()-1) ); + } + } + + // find the correct size for the horizontal scrollbar + if ( HorizontalScrollBar->isVisible() ) + { + if ( !wasHorizontalScrollBarVisible ) + HorizontalScrollBar->setPos(0); + + if ( VerticalScrollBar->isVisible() ) + { + HorizontalScrollBar->setRelativePosition( core::rect(1, RelativeRect.getHeight() - ScrollBarSize, RelativeRect.getWidth()-(1+ScrollBarSize), RelativeRect.getHeight()-1) ); + } + else + { + HorizontalScrollBar->setRelativePosition( core::rect(1, RelativeRect.getHeight() - ScrollBarSize, RelativeRect.getWidth()-1, RelativeRect.getHeight()-1) ); + } + } +} + + +void CGUITable::refreshControls() +{ + updateAbsolutePosition(); + + if ( VerticalScrollBar ) + VerticalScrollBar->setVisible(false); + + if ( HorizontalScrollBar ) + HorizontalScrollBar->setVisible(false); + + recalculateHeights(); + recalculateWidths(); +} + + +//! called if an event happened. +bool CGUITable::OnEvent(const SEvent &event) +{ + if (isEnabled()) + { + + switch(event.EventType) + { + case EET_GUI_EVENT: + switch(event.GUIEvent.EventType) + { + case gui::EGET_SCROLL_BAR_CHANGED: + if (event.GUIEvent.Caller == VerticalScrollBar) + { + // current position will get read out in draw + return true; + } + if (event.GUIEvent.Caller == HorizontalScrollBar) + { + // current position will get read out in draw + return true; + } + break; + case gui::EGET_ELEMENT_FOCUS_LOST: + { + CurrentResizedColumn = -1; + Selecting = false; + } + break; + default: + break; + } + break; + case EET_MOUSE_INPUT_EVENT: + { + if ( !isEnabled() ) + return false; + + core::position2d p(event.MouseInput.X, event.MouseInput.Y); + + switch(event.MouseInput.Event) + { + case EMIE_MOUSE_WHEEL: + VerticalScrollBar->setPos(VerticalScrollBar->getPos() + (event.MouseInput.Wheel < 0 ? -1 : 1)*-10); + return true; + + case EMIE_LMOUSE_PRESSED_DOWN: + + if (VerticalScrollBar->isVisible() && + VerticalScrollBar->getAbsolutePosition().isPointInside(p) && + VerticalScrollBar->OnEvent(event)) + return true; + + if (HorizontalScrollBar->isVisible() && + HorizontalScrollBar->getAbsolutePosition().isPointInside(p) && + HorizontalScrollBar->OnEvent(event)) + return true; + + if ( dragColumnStart( event.MouseInput.X, event.MouseInput.Y ) ) + { + return true; + } + + if ( selectColumnHeader( event.MouseInput.X, event.MouseInput.Y ) ) + return true; + + Selecting = true; + return true; + + case EMIE_LMOUSE_LEFT_UP: + + CurrentResizedColumn = -1; + Selecting = false; + + if (VerticalScrollBar->isVisible() && + VerticalScrollBar->getAbsolutePosition().isPointInside(p) && + VerticalScrollBar->OnEvent(event)) + { + return true; + } + + if (HorizontalScrollBar->isVisible() && + HorizontalScrollBar->getAbsolutePosition().isPointInside(p) && + HorizontalScrollBar->OnEvent(event)) + { + return true; + } + + selectNew(event.MouseInput.Y); + return true; + + case EMIE_MOUSE_MOVED: + if ( CurrentResizedColumn >= 0 ) + { + if ( dragColumnUpdate(event.MouseInput.X) ) + { + return true; + } + } + if (Selecting || MoveOverSelect) + { + if (getAbsolutePosition().isPointInside(p)) + { + selectNew(event.MouseInput.Y); + return true; + } + } + break; + default: + break; + } + } + break; + default: + break; + } + } + + return IGUIElement::OnEvent(event); +} + + +void CGUITable::setColumnOrdering(u32 columnIndex, EGUI_COLUMN_ORDERING mode) +{ + if ( columnIndex < Columns.size() ) + Columns[columnIndex].OrderingMode = mode; +} + + +void CGUITable::swapRows(u32 rowIndexA, u32 rowIndexB) +{ + if ( rowIndexA >= Rows.size() ) + return; + + if ( rowIndexB >= Rows.size() ) + return; + + Row swap = Rows[rowIndexA]; + Rows[rowIndexA] = Rows[rowIndexB]; + Rows[rowIndexB] = swap; + + if ( Selected == s32(rowIndexA) ) + Selected = rowIndexB; + else if( Selected == s32(rowIndexB) ) + Selected = rowIndexA; + +} + + +bool CGUITable::dragColumnStart(s32 xpos, s32 ypos) +{ + if ( !ResizableColumns ) + return false; + + if ( ypos > ( AbsoluteRect.UpperLeftCorner.Y + ItemHeight ) ) + return false; + + const s32 CLICK_AREA = 12; // to left and right of line which can be dragged + s32 pos = AbsoluteRect.UpperLeftCorner.X+1; + + if ( HorizontalScrollBar && HorizontalScrollBar->isVisible() ) + pos -= HorizontalScrollBar->getPos(); + + pos += TotalItemWidth; + + // have to search from the right as otherwise lines could no longer be resized when a column width is 0 + for ( s32 i = (s32)Columns.size()-1; i >= 0 ; --i ) + { + u32 colWidth = Columns[i].Width; + + if ( xpos >= (pos - CLICK_AREA) && xpos < ( pos + CLICK_AREA ) ) + { + CurrentResizedColumn = i; + ResizeStart = xpos; + return true; + } + + pos -= colWidth; + } + + return false; +} + + +bool CGUITable::dragColumnUpdate(s32 xpos) +{ + if ( !ResizableColumns || CurrentResizedColumn < 0 || CurrentResizedColumn >= s32(Columns.size()) ) + { + CurrentResizedColumn = -1; + return false; + } + + s32 width = s32(Columns[CurrentResizedColumn].Width) + (xpos-ResizeStart); + if ( width < 0 ) + width = 0; + setColumnWidth(CurrentResizedColumn, u32(width)); + ResizeStart = xpos; + + return false; +} + + +bool CGUITable::selectColumnHeader(s32 xpos, s32 ypos) +{ + if ( ypos > ( AbsoluteRect.UpperLeftCorner.Y + ItemHeight ) ) + return false; + + s32 pos = AbsoluteRect.UpperLeftCorner.X+1; + + if ( HorizontalScrollBar && HorizontalScrollBar->isVisible() ) + pos -= HorizontalScrollBar->getPos(); + + for ( u32 i = 0 ; i < Columns.size() ; ++i ) + { + u32 colWidth = Columns[i].Width; + + if ( xpos >= pos && xpos < ( pos + s32(colWidth) ) ) + { + setActiveColumn( i, true ); + + return true; + } + + pos += colWidth; + } + + return false; +} + + +void CGUITable::orderRows(s32 columnIndex, EGUI_ORDERING_MODE mode) +{ + Row swap; + + if ( columnIndex == -1 ) + columnIndex = getActiveColumn(); + if ( columnIndex < 0 ) + return; + + if ( mode == EGOM_ASCENDING ) + { + for ( s32 i = 0 ; i < s32(Rows.size()) - 1 ; ++i ) + { + for ( s32 j = 0 ; j < s32(Rows.size()) - i - 1 ; ++j ) + { + if ( Rows[j+1].Items[columnIndex].Text < Rows[j].Items[columnIndex].Text ) + { + swap = Rows[j]; + Rows[j] = Rows[j+1]; + Rows[j+1] = swap; + + if ( Selected == j ) + Selected = j+1; + else if( Selected == j+1 ) + Selected = j; + } + } + } + } + else if ( mode == EGOM_DESCENDING ) + { + for ( s32 i = 0 ; i < s32(Rows.size()) - 1 ; ++i ) + { + for ( s32 j = 0 ; j < s32(Rows.size()) - i - 1 ; ++j ) + { + if ( Rows[j].Items[columnIndex].Text < Rows[j+1].Items[columnIndex].Text) + { + swap = Rows[j]; + Rows[j] = Rows[j+1]; + Rows[j+1] = swap; + + if ( Selected == j ) + Selected = j+1; + else if( Selected == j+1 ) + Selected = j; + } + } + } + } +} + + +void CGUITable::selectNew(s32 ypos, bool onlyHover) +{ + IGUISkin* skin = Environment->getSkin(); + if (!skin) + return; + + s32 oldSelected = Selected; + + if ( ypos < ( AbsoluteRect.UpperLeftCorner.Y + ItemHeight ) ) + return; + + // find new selected item. + if (ItemHeight!=0) + Selected = ((ypos - AbsoluteRect.UpperLeftCorner.Y - ItemHeight - 1) + VerticalScrollBar->getPos()) / ItemHeight; + + if (Selected >= (s32)Rows.size()) + Selected = Rows.size() - 1; + else if (Selected<0) + Selected = 0; + + // post the news + if (Parent && !onlyHover) + { + SEvent event; + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.Element = 0; + event.GUIEvent.EventType = (Selected != oldSelected) ? EGET_TABLE_CHANGED : EGET_TABLE_SELECTED_AGAIN; + Parent->OnEvent(event); + } +} + + +//! draws the element and its children +void CGUITable::draw() +{ + if (!IsVisible) + return; + + irr::video::IVideoDriver* driver = Environment->getVideoDriver(); + + IGUISkin* skin = Environment->getSkin(); + if (!skin) + return; + + IGUIFont* font = getActiveFont(); + if (!font) + return; + + if ( ScrollBarSize != skin->getSize(EGDS_SCROLLBAR_SIZE) ) + checkScrollbars(); + + // CAREFUL: near identical calculations for tableRect and clientClip are also done in checkScrollbars and selectColumnHeader + // Area of table used for drawing without scrollbars + core::rect tableRect(AbsoluteRect); + tableRect.UpperLeftCorner.X += 1; + tableRect.UpperLeftCorner.Y += 1; + if ( VerticalScrollBar && VerticalScrollBar->isVisible() ) + tableRect.LowerRightCorner.X -= ScrollBarSize; + if ( HorizontalScrollBar && HorizontalScrollBar->isVisible() ) + tableRect.LowerRightCorner.Y -= ScrollBarSize; + + s32 headerBottom = tableRect.UpperLeftCorner.Y + ItemHeight; + + // area of for the items (without header and without scrollbars) + core::rect clientClip(tableRect); + clientClip.UpperLeftCorner.Y = headerBottom + 1; + clientClip.clipAgainst(AbsoluteClippingRect); + + // draw background for whole element + skin->draw3DSunkenPane(this, skin->getColor(EGDC_3D_HIGH_LIGHT), true, DrawBack, AbsoluteRect, &AbsoluteClippingRect); + + // scrolledTableClient is the area where the table items would be if it could be drawn completely + core::rect scrolledTableClient(tableRect); + scrolledTableClient.UpperLeftCorner.Y = headerBottom + 1; + scrolledTableClient.LowerRightCorner.Y = scrolledTableClient.UpperLeftCorner.Y + TotalItemHeight; + scrolledTableClient.LowerRightCorner.X = scrolledTableClient.UpperLeftCorner.X + TotalItemWidth; + if ( VerticalScrollBar && VerticalScrollBar->isVisible() ) + { + scrolledTableClient.UpperLeftCorner.Y -= VerticalScrollBar->getPos(); + scrolledTableClient.LowerRightCorner.Y -= VerticalScrollBar->getPos(); + } + if ( HorizontalScrollBar && HorizontalScrollBar->isVisible() ) + { + scrolledTableClient.UpperLeftCorner.X -= HorizontalScrollBar->getPos(); + scrolledTableClient.LowerRightCorner.X -= HorizontalScrollBar->getPos(); + } + + // rowRect is around the scrolled row + core::rect rowRect(scrolledTableClient); + rowRect.LowerRightCorner.Y = rowRect.UpperLeftCorner.Y + ItemHeight; + + u32 pos; + for ( u32 i = 0 ; i < Rows.size() ; ++i ) + { + if (rowRect.LowerRightCorner.Y >= AbsoluteRect.UpperLeftCorner.Y && + rowRect.UpperLeftCorner.Y <= AbsoluteRect.LowerRightCorner.Y) + { + // draw row separator + if ( DrawFlags & EGTDF_ROWS ) + { + core::rect lineRect(rowRect); + lineRect.UpperLeftCorner.Y = lineRect.LowerRightCorner.Y - 1; + driver->draw2DRectangle(skin->getColor(EGDC_3D_SHADOW), lineRect, &clientClip); + } + + core::rect textRect(rowRect); + pos = rowRect.UpperLeftCorner.X; + + // draw selected row background highlighted + if ((s32)i == Selected && DrawFlags & EGTDF_ACTIVE_ROW ) + driver->draw2DRectangle(skin->getColor(EGDC_HIGH_LIGHT), rowRect, &clientClip); + + for ( u32 j = 0 ; j < Columns.size() ; ++j ) + { + textRect.UpperLeftCorner.X = pos + CellWidthPadding; + textRect.LowerRightCorner.X = pos + Columns[j].Width - CellWidthPadding; + + // draw item text + if ((s32)i == Selected) + { + font->draw(Rows[i].Items[j].BrokenText.c_str(), textRect, skin->getColor(isEnabled() ? EGDC_HIGH_LIGHT_TEXT : EGDC_GRAY_TEXT), false, true, &clientClip); + } + else + { + if ( !Rows[i].Items[j].IsOverrideColor ) // skin-colors can change + Rows[i].Items[j].Color = skin->getColor(EGDC_BUTTON_TEXT); + font->draw(Rows[i].Items[j].BrokenText.c_str(), textRect, isEnabled() ? Rows[i].Items[j].Color : skin->getColor(EGDC_GRAY_TEXT), false, true, &clientClip); + } + + pos += Columns[j].Width; + } + } + + rowRect.UpperLeftCorner.Y += ItemHeight; + rowRect.LowerRightCorner.Y += ItemHeight; + } + + core::rect columnSeparator(clientClip); + pos = scrolledTableClient.UpperLeftCorner.X; + + core::rect tableClip(tableRect); + tableClip.clipAgainst(AbsoluteClippingRect); + + for (u32 i = 0 ; i < Columns.size() ; ++i ) + { + const wchar_t* text = Columns[i].Name.c_str(); + u32 colWidth = Columns[i].Width; + + core::rect columnrect(pos, tableRect.UpperLeftCorner.Y, pos + colWidth, headerBottom); + + // draw column background + skin->draw3DButtonPaneStandard(this, columnrect, &tableClip); + + // draw column separator + if ( DrawFlags & EGTDF_COLUMNS ) + { + columnSeparator.UpperLeftCorner.X = pos; + columnSeparator.LowerRightCorner.X = pos + 1; + driver->draw2DRectangle(skin->getColor(EGDC_3D_SHADOW), columnSeparator, &tableClip); + } + + // draw header column text + columnrect.UpperLeftCorner.X += CellWidthPadding; + font->draw(text, columnrect, skin->getColor( isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT), false, true, &tableClip); + + // draw icon for active column tab + if ( (s32)i == ActiveTab ) + { + if ( CurrentOrdering == EGOM_ASCENDING ) + { + columnrect.UpperLeftCorner.X = columnrect.LowerRightCorner.X - CellWidthPadding - ARROW_PAD / 2 + 2; + columnrect.UpperLeftCorner.Y += 7; + skin->drawIcon(this,EGDI_CURSOR_UP,columnrect.UpperLeftCorner,0,0,false,&tableClip); + } + else + { + columnrect.UpperLeftCorner.X = columnrect.LowerRightCorner.X - CellWidthPadding - ARROW_PAD / 2 + 2; + columnrect.UpperLeftCorner.Y += 7; + skin->drawIcon(this,EGDI_CURSOR_DOWN,columnrect.UpperLeftCorner,0,0,false,&tableClip); + } + } + + pos += colWidth; + } + + // fill up header background up to the right side + core::rect columnrect(pos, tableRect.UpperLeftCorner.Y, tableRect.LowerRightCorner.X , headerBottom); + skin->draw3DButtonPaneStandard(this, columnrect, &tableClip); + + IGUIElement::draw(); +} + + +void CGUITable::breakText(const core::stringw& text, core::stringw& brokenText, u32 cellWidth) +{ + IGUISkin* skin = Environment->getSkin(); + + if (!skin) + return; + + IGUIFont* font = getActiveFont(); + if (!font) + return; + + core::stringw line, lineDots; + wchar_t c[2]; + c[1] = L'\0'; + + const u32 maxLength = cellWidth - (CellWidthPadding * 2); + const u32 maxLengthDots = cellWidth - (CellWidthPadding * 2) - font->getDimension(L"...").Width; + const u32 size = text.size(); + u32 pos = 0; + + u32 i; + + for (i=0; igetDimension(c).Width; + if ( pos > maxLength ) + break; + + if ( font->getDimension( (line + c).c_str() ).Width > maxLengthDots ) + lineDots = line; + + line += c[0]; + } + + if ( i < size ) + brokenText = lineDots + L"..."; + else + brokenText = line; +} + + +//! Set some flags influencing the layout of the table +void CGUITable::setDrawFlags(s32 flags) +{ + DrawFlags = flags; +} + + +//! Get the flags which influence the layout of the table +s32 CGUITable::getDrawFlags() const +{ + return DrawFlags; +} + +//! Sets another skin independent font. +void CGUITable::setOverrideFont(IGUIFont* font) +{ + if (OverrideFont == font) + return; + + if (OverrideFont) + OverrideFont->drop(); + + OverrideFont = font; + + if (OverrideFont) + OverrideFont->grab(); + + refreshControls(); +} + +//! Gets the override font (if any) +IGUIFont * CGUITable::getOverrideFont() const +{ + return OverrideFont; +} + +//! Get the font which is used right now for drawing +IGUIFont* CGUITable::getActiveFont() const +{ + if ( OverrideFont ) + return OverrideFont; + IGUISkin* skin = Environment->getSkin(); + if (skin) + return skin->getFont(); + return 0; +} + +//! Get the height of items/rows +s32 CGUITable::getItemHeight() const +{ + return ItemHeight; +} + +//! Access the vertical scrollbar +IGUIScrollBar* CGUITable::getVerticalScrollBar() const +{ + return VerticalScrollBar; +} + +//! Access the horizontal scrollbar +IGUIScrollBar* CGUITable::getHorizontalScrollBar() const +{ + return HorizontalScrollBar; +} + +//! Sets whether to draw the background. +void CGUITable::setDrawBackground(bool draw) +{ + DrawBack = draw; +} + +//! Checks if background drawing is enabled +/** \return true if background drawing is enabled, false otherwise */ +bool CGUITable::isDrawBackgroundEnabled() const +{ + return DrawBack; +} + +//! Writes attributes of the element. +void CGUITable::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + IGUITable::serializeAttributes(out, options); + + out->addInt("ColumnCount", Columns.size()); + u32 i; + for (i=0;iaddString(label.c_str(), Columns[i].Name.c_str() ); + label = "Column"; label += i; label += "width"; + out->addInt(label.c_str(), Columns[i].Width ); + label = "Column"; label += i; label += "OrderingMode"; + out->addEnum(label.c_str(), Columns[i].OrderingMode, GUIColumnOrderingNames); + } + + out->addInt("RowCount", Rows.size()); + for (i=0;iaddInt(label.c_str(), Rows[i].Height ); + + //label = "Row"; label += i; label += "ItemCount"; + //out->addInt(label.c_str(), Rows[i].Items.size()); + u32 c; + for ( c=0; c < Rows[i].Items.size(); ++c ) + { + label = "Row"; label += i; label += "cell"; label += c; label += "text"; + out->addString(label.c_str(), Rows[i].Items[c].Text.c_str() ); + // core::stringw BrokenText; // can be recalculated + label = "Row"; label += i; label += "cell"; label += c; label += "color"; + out->addColor(label.c_str(), Rows[i].Items[c].Color ); + label = "Row"; label += i; label += "cell"; label += c; label += "IsOverrideColor"; + out->addColor(label.c_str(), Rows[i].Items[c].IsOverrideColor ); + // void *data; // can't be serialized + } + } + + // s32 ItemHeight; // can be calculated + // TotalItemHeight // calculated + // TotalItemWidth // calculated + // gui::IGUIFont* ActiveFont; // TODO: we don't have a sane font-serialization so far + // gui::IGUIScrollBar* VerticalScrollBar; // not serialized + // gui::IGUIScrollBar* HorizontalScrollBar; // not serialized + + out->addBool ("Clip", Clip); + out->addBool ("DrawBack", DrawBack); + out->addBool ("MoveOverSelect", MoveOverSelect); + + // s32 CurrentResizedColumn; // runtime info - depends on user action + out->addBool ("ResizableColumns", ResizableColumns); + + // s32 Selected; // runtime info - depends on user action + out->addInt("CellWidthPadding", CellWidthPadding ); + out->addInt("CellHeightPadding", CellHeightPadding ); + // s32 ActiveTab; // runtime info - depends on user action + // bool Selecting; // runtime info - depends on user action + out->addEnum("CurrentOrdering", CurrentOrdering, GUIOrderingModeNames); + out->addInt("DrawFlags", DrawFlags); +} + + +//! Reads attributes of the element +void CGUITable::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + IGUITable::deserializeAttributes(in, options); + + Columns.clear(); + u32 columnCount = in->getAttributeAsInt("ColumnCount"); + u32 i; + for (i=0;igetAttributeAsString(label.c_str()).c_str()); + label = "Column"; label += i; label += "width"; + column.Width = in->getAttributeAsInt(label.c_str()); + label = "Column"; label += i; label += "OrderingMode"; + + column.OrderingMode = EGCO_NONE; + s32 co = in->getAttributeAsEnumeration(label.c_str(), GUIColumnOrderingNames); + if (co > 0) + column.OrderingMode = EGUI_COLUMN_ORDERING(co); + + Columns.push_back(column); + } + + Rows.clear(); + u32 rowCount = in->getAttributeAsInt("RowCount"); + for (i=0; igetAttributeAsInt(label.c_str() ); + + Rows.push_back(row); + + //label = "Row"; label += i; label += "ItemCount"; + //u32 itemCount = in->getAttributeAsInt(label.c_str()); + u32 c; + for ( c=0; c < columnCount; ++c ) + { + Cell cell; + + label = "Row"; label += i; label += "cell"; label += c; label += "text"; + cell.Text = core::stringw(in->getAttributeAsString(label.c_str()).c_str()); + breakText( cell.Text, cell.BrokenText, Columns[c].Width ); + label = "Row"; label += i; label += "cell"; label += c; label += "color"; + cell.Color = in->getAttributeAsColor(label.c_str()); + label = "Row"; label += i; label += "cell"; label += c; label += "IsOverrideColor"; + cell.IsOverrideColor = in->getAttributeAsBool(label.c_str()); + + cell.Data = NULL; + + Rows[Rows.size()-1].Items.push_back(cell); + } + } + + ItemHeight = 0; // calculated + TotalItemHeight = 0; // calculated + TotalItemWidth = 0; // calculated + + Clip = in->getAttributeAsBool("Clip", Clip); + DrawBack = in->getAttributeAsBool("DrawBack", DrawBack); + MoveOverSelect = in->getAttributeAsBool("MoveOverSelect", MoveOverSelect); + + CurrentResizedColumn = -1; + ResizeStart = 0; + ResizableColumns = in->getAttributeAsBool("ResizableColumns", ResizableColumns); + + Selected = -1; + CellWidthPadding = in->getAttributeAsInt("CellWidthPadding", CellWidthPadding); + CellHeightPadding = in->getAttributeAsInt("CellHeightPadding", CellHeightPadding); + ActiveTab = -1; + Selecting = false; + + CurrentOrdering = (EGUI_ORDERING_MODE) in->getAttributeAsEnumeration("CurrentOrdering", GUIOrderingModeNames, (s32)CurrentOrdering); + DrawFlags = in->getAttributeAsInt("DrawFlags", DrawFlags); + + refreshControls(); +} + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CGUITable.h b/source/Irrlicht/CGUITable.h new file mode 100644 index 00000000..f325f49f --- /dev/null +++ b/source/Irrlicht/CGUITable.h @@ -0,0 +1,254 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +// 07.10.2005 - Multicolor-Listbox addet by A. Buschhueter (Acki) +// A_Buschhueter@gmx.de + +#ifndef __C_GUI_TABLE_BAR_H_INCLUDED__ +#define __C_GUI_TABLE_BAR_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUITable.h" +#include "irrArray.h" + +namespace irr +{ +namespace gui +{ + + class IGUIFont; + class IGUIScrollBar; + + class CGUITable : public IGUITable + { + public: + //! constructor + CGUITable(IGUIEnvironment* environment, IGUIElement* parent, + s32 id, const core::rect& rectangle, bool clip=true, + bool drawBack=false, bool moveOverSelect=true); + + //! destructor + ~CGUITable(); + + //! Adds a column + //! If columnIndex is outside the current range, do push new column at the end + virtual void addColumn(const wchar_t* caption, s32 columnIndex=-1) _IRR_OVERRIDE_; + + //! remove a column from the table + virtual void removeColumn(u32 columnIndex) _IRR_OVERRIDE_; + + //! Returns the number of columns in the table control + virtual s32 getColumnCount() const _IRR_OVERRIDE_; + + //! Makes a column active. This will trigger an ordering process. + /** \param idx: The id of the column to make active. + \return True if successful. */ + virtual bool setActiveColumn(s32 columnIndex, bool doOrder=false) _IRR_OVERRIDE_; + + //! Returns which header is currently active + virtual s32 getActiveColumn() const _IRR_OVERRIDE_; + + //! Returns the ordering used by the currently active column + virtual EGUI_ORDERING_MODE getActiveColumnOrdering() const _IRR_OVERRIDE_; + + //! set a column width + virtual void setColumnWidth(u32 columnIndex, u32 width) _IRR_OVERRIDE_; + + //! Get the width of a column + virtual u32 getColumnWidth(u32 columnIndex) const _IRR_OVERRIDE_; + + //! columns can be resized by drag 'n drop + virtual void setResizableColumns(bool resizable) _IRR_OVERRIDE_; + + //! can columns be resized by drag 'n drop? + virtual bool hasResizableColumns() const _IRR_OVERRIDE_; + + //! 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 + virtual void setColumnOrdering(u32 columnIndex, EGUI_COLUMN_ORDERING mode) _IRR_OVERRIDE_; + + //! Returns which row is currently selected + virtual s32 getSelected() const _IRR_OVERRIDE_; + + //! set currently selected row + virtual void setSelected( s32 index ) _IRR_OVERRIDE_; + + //! Returns amount of rows in the tab control + virtual s32 getRowCount() const _IRR_OVERRIDE_; + + //! 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 exists + there, it will be placed after it. If the row is larger + than the actual number of rows by more than one, it + won't be created. Note that if you create a row that is + not at the end, there might be performance issues*/ + virtual u32 addRow(u32 rowIndex) _IRR_OVERRIDE_; + + //! Remove a row from the table + virtual void removeRow(u32 rowIndex) _IRR_OVERRIDE_; + + //! clear the table rows, but keep the columns intact + virtual void clearRows() _IRR_OVERRIDE_; + + //! Swap two row positions. This is useful for a custom ordering algo. + virtual void swapRows(u32 rowIndexA, u32 rowIndexB) _IRR_OVERRIDE_; + + //! This tells the table to start ordering all the rows. You + //! need to explicitly tell the table to reorder 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. + virtual void orderRows(s32 columnIndex=-1, EGUI_ORDERING_MODE mode=EGOM_NONE) _IRR_OVERRIDE_; + + + //! Set the text of a cell + virtual void setCellText(u32 rowIndex, u32 columnIndex, const core::stringw& text) _IRR_OVERRIDE_; + + //! Set the text of a cell, and set a color of this cell. + virtual void setCellText(u32 rowIndex, u32 columnIndex, const core::stringw& text, video::SColor color) _IRR_OVERRIDE_; + + //! Set the data of a cell + //! data will not be serialized. + virtual void setCellData(u32 rowIndex, u32 columnIndex, void *data) _IRR_OVERRIDE_; + + //! Set the color of a cell text + virtual void setCellColor(u32 rowIndex, u32 columnIndex, video::SColor color) _IRR_OVERRIDE_; + + //! Get the text of a cell + virtual const wchar_t* getCellText(u32 rowIndex, u32 columnIndex ) const _IRR_OVERRIDE_; + + //! Get the data of a cell + virtual void* getCellData(u32 rowIndex, u32 columnIndex ) const _IRR_OVERRIDE_; + + //! clears the table, deletes all items in the table + virtual void clear() _IRR_OVERRIDE_; + + //! called if an event happened. + virtual bool OnEvent(const SEvent &event) _IRR_OVERRIDE_; + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + //! Set flags, as defined in EGUI_TABLE_DRAW_FLAGS, which influence the layout + virtual void setDrawFlags(s32 flags) _IRR_OVERRIDE_; + + //! Get the flags, as defined in EGUI_TABLE_DRAW_FLAGS, which influence the layout + virtual s32 getDrawFlags() const _IRR_OVERRIDE_; + + //! Sets another skin independent font. + virtual void setOverrideFont(IGUIFont* font=0) _IRR_OVERRIDE_; + + //! Gets the override font (if any) + virtual IGUIFont* getOverrideFont() const _IRR_OVERRIDE_; + + //! Get the font which is used right now for drawing + virtual IGUIFont* getActiveFont() const _IRR_OVERRIDE_; + + //! Get the height of items/rows + virtual s32 getItemHeight() const _IRR_OVERRIDE_; + + //! Access the vertical scrollbar + virtual IGUIScrollBar* getVerticalScrollBar() const _IRR_OVERRIDE_; + + //! Access the horizontal scrollbar + virtual IGUIScrollBar* getHorizontalScrollBar() const _IRR_OVERRIDE_; + + //! Sets whether to draw the background. + virtual void setDrawBackground(bool draw) _IRR_OVERRIDE_; + + //! Checks if background drawing is enabled + /** \return true if background drawing is enabled, false otherwise */ + virtual bool isDrawBackgroundEnabled() const _IRR_OVERRIDE_; + + //! Writes attributes of the object. + //! 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 _IRR_OVERRIDE_; + + //! Reads attributes of the object. + //! 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) _IRR_OVERRIDE_; + + protected: + void refreshControls(); + void checkScrollbars(); + + private: + + struct Cell + { + Cell() : IsOverrideColor(false), Data(0) {} + + core::stringw Text; + core::stringw BrokenText; + bool IsOverrideColor; + video::SColor Color; + void *Data; + }; + + struct Row + { + Row() {} + + core::array Items; + }; + + struct Column + { + Column() : Width(0), OrderingMode(EGCO_NONE) {} + + core::stringw Name; + u32 Width; + EGUI_COLUMN_ORDERING OrderingMode; + }; + + void breakText(const core::stringw &text, core::stringw & brokenText, u32 cellWidth); + void selectNew(s32 ypos, bool onlyHover=false); + bool selectColumnHeader(s32 xpos, s32 ypos); + bool dragColumnStart(s32 xpos, s32 ypos); + bool dragColumnUpdate(s32 xpos); + void recalculateHeights(); + void recalculateWidths(); + + core::array< Column > Columns; + core::array< Row > Rows; + gui::IGUIScrollBar* VerticalScrollBar; + gui::IGUIScrollBar* HorizontalScrollBar; + bool Clip; + bool DrawBack; + bool MoveOverSelect; + bool Selecting; + s32 CurrentResizedColumn; + s32 ResizeStart; + bool ResizableColumns; + + s32 ItemHeight; + s32 TotalItemHeight; + s32 TotalItemWidth; + s32 Selected; + s32 CellHeightPadding; + s32 CellWidthPadding; + s32 ActiveTab; + EGUI_ORDERING_MODE CurrentOrdering; + s32 DrawFlags; + s32 ScrollBarSize; + + gui::IGUIFont* OverrideFont; + }; + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif + diff --git a/source/Irrlicht/CGUIToolBar.cpp b/source/Irrlicht/CGUIToolBar.cpp new file mode 100644 index 00000000..2f4bf4ec --- /dev/null +++ b/source/Irrlicht/CGUIToolBar.cpp @@ -0,0 +1,188 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUIToolBar.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" +#include "IGUIButton.h" +#include "IGUIFont.h" +#include "CGUIButton.h" + +namespace irr +{ +namespace gui +{ + +//! constructor +CGUIToolBar::CGUIToolBar(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) +:IGUIToolBar(environment, parent, id, rectangle), ButtonX(5) +{ + #ifdef _DEBUG + setDebugName("CGUIToolBar"); + #endif + + // calculate position and find other menubars + s32 y = 0; + s32 parentwidth = 100; + + if (parent) + { + parentwidth = Parent->getAbsolutePosition().getWidth(); + s32 parentheight = Parent->getAbsolutePosition().getHeight(); + + const core::list& children = parent->getChildren(); + core::list::ConstIterator it = children.begin(); + for (; it != children.end(); ++it) + { + const IGUIElement* e = *it; + if ( e->hasType(EGUIET_CONTEXT_MENU) + || e->hasType(EGUIET_MENU) + || e->hasType(EGUIET_TOOL_BAR) ) + { + core::rect r = e->getAbsolutePosition(); + if (r.UpperLeftCorner.X == 0 && r.UpperLeftCorner.Y <= y && + r.LowerRightCorner.X == parentwidth + && parentheight > r.LowerRightCorner.Y ) + y = r.LowerRightCorner.Y; + } + else + { + e->getType(); + } + } + } + + core::rect rr; + rr.UpperLeftCorner.X = 0; + rr.UpperLeftCorner.Y = y; + s32 height = Environment->getSkin()->getSize ( EGDS_MENU_HEIGHT ); + + /*IGUISkin* skin = Environment->getSkin(); + IGUIFont* font = skin->getFont(); + if (font) + { + s32 t = font->getDimension(L"A").Height + 5; + if (t > height) + height = t; + }*/ + + rr.LowerRightCorner.X = parentwidth; + rr.LowerRightCorner.Y = rr.UpperLeftCorner.Y + height; + setRelativePosition(rr); +} + + +//! called if an event happened. +bool CGUIToolBar::OnEvent(const SEvent& event) +{ + if (isEnabled()) + { + 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))) + return true; + } + } + + return IGUIElement::OnEvent(event); +} + + +//! draws the element and its children +void CGUIToolBar::draw() +{ + if (!IsVisible) + return; + + IGUISkin* skin = Environment->getSkin(); + if (!skin) + return; + + core::rect rect = AbsoluteRect; + core::rect* clip = &AbsoluteClippingRect; + + // draw frame + skin->draw3DToolBar(this, rect, clip); + + IGUIElement::draw(); +} + + +//! Updates the absolute position. +void CGUIToolBar::updateAbsolutePosition() +{ + if (Parent) + { + DesiredRect.UpperLeftCorner.X = 0; + DesiredRect.LowerRightCorner.X = Parent->getAbsolutePosition().getWidth(); + } + + IGUIElement::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, + bool useAlphaChannel) +{ + ButtonX += 3; + + core::rect rectangle(ButtonX,2,ButtonX+1,3); + if ( img ) + { + const core::dimension2du &size = img->getOriginalSize(); + rectangle.LowerRightCorner.X = rectangle.UpperLeftCorner.X + size.Width + 8; + rectangle.LowerRightCorner.Y = rectangle.UpperLeftCorner.Y + size.Height + 6; + } + + if ( text ) + { + IGUISkin* skin = Environment->getSkin(); + IGUIFont * font = skin->getFont(EGDF_BUTTON); + if ( font ) + { + core::dimension2d dim = font->getDimension(text); + if ( (s32)dim.Width > rectangle.getWidth() ) + rectangle.LowerRightCorner.X = rectangle.UpperLeftCorner.X + dim.Width + 8; + if ( (s32)dim.Height > rectangle.getHeight() ) + rectangle.LowerRightCorner.Y = rectangle.UpperLeftCorner.Y + dim.Height + 6; + } + } + + ButtonX += rectangle.getWidth(); + + IGUIButton* button = new CGUIButton(Environment, this, id, rectangle); + button->drop(); + + if (text) + button->setText(text); + + if (tooltiptext) + button->setToolTipText(tooltiptext); + + if (img) + button->setImage(img); + + if (pressed) + button->setPressedImage(pressed); + + if (isPushButton) + button->setIsPushButton(isPushButton); + + if (useAlphaChannel) + button->setUseAlphaChannel(useAlphaChannel); + + return button; +} + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIToolBar.h b/source/Irrlicht/CGUIToolBar.h new file mode 100644 index 00000000..316a926b --- /dev/null +++ b/source/Irrlicht/CGUIToolBar.h @@ -0,0 +1,52 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_TOOL_BAR_H_INCLUDED__ +#define __C_GUI_TOOL_BAR_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIToolbar.h" + +namespace irr +{ +namespace gui +{ + + //! Stays at the top of its parent like the menu bar and contains tool buttons + class CGUIToolBar : public IGUIToolBar + { + public: + + //! constructor + CGUIToolBar(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle); + + //! called if an event happened. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + //! Updates the absolute position. + virtual void updateAbsolutePosition() _IRR_OVERRIDE_; + + //! Adds a button to the tool bar + virtual IGUIButton* addButton(s32 id=-1, const wchar_t* text=0,const wchar_t* tooltiptext=0, + video::ITexture* img=0, video::ITexture* pressed=0, + bool isPushButton=false, bool useAlphaChannel=false) _IRR_OVERRIDE_; + + private: + + s32 ButtonX; + }; + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif + diff --git a/source/Irrlicht/CGUITreeView.cpp b/source/Irrlicht/CGUITreeView.cpp new file mode 100644 index 00000000..f6d7743a --- /dev/null +++ b/source/Irrlicht/CGUITreeView.cpp @@ -0,0 +1,1166 @@ +// This file is part of the "Irrlicht Engine". +// Written by Reinhard Ostermeier, reinhard@nospam.r-ostermeier.de +// Expanded by burningwater +// Bugfixes by Michael Zeilfelder +// Bugfixes by Andreas Reichl + +#include "CGUITreeView.h" + +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" +#include "IGUIFont.h" +#include "CGUIScrollBar.h" +#include "os.h" + +namespace irr +{ +namespace gui +{ + +CGUITreeViewNode::CGUITreeViewNode( CGUITreeView* owner, CGUITreeViewNode* parent ) + : Owner(owner), Parent(parent), ImageIndex(-1), SelectedImageIndex(-1), + Data(0), Data2(0), Expanded(false) +{ +#ifdef _DEBUG + setDebugName( "CGUITreeView" ); +#endif +} + +CGUITreeViewNode::~CGUITreeViewNode() +{ + if( Owner && this == Owner->getSelected() ) + { + setSelected( false ); + } + + clearChildren(); + + if( Data2 ) + { + Data2->drop(); + } +} + +IGUITreeView* CGUITreeViewNode::getOwner() const +{ + return Owner; +} + +IGUITreeViewNode* CGUITreeViewNode::getParent() const +{ + return Parent; +} + +void CGUITreeViewNode::setText( const wchar_t* text ) +{ + Text = text; +} + +void CGUITreeViewNode::setIcon( const wchar_t* icon ) +{ + Icon = icon; +} + +void CGUITreeViewNode::clearChildren() +{ + core::list::Iterator it; + + for( it = Children.begin(); it != Children.end(); it++ ) + { + ( *it )->drop(); + } + Children.clear(); +} + +IGUITreeViewNode* CGUITreeViewNode::addChildBack( + const wchar_t* text, + const wchar_t* icon /*= 0*/, + s32 imageIndex /*= -1*/, + s32 selectedImageIndex /*= -1*/, + void* data /*= 0*/, + IReferenceCounted* data2 /*= 0*/ ) +{ + CGUITreeViewNode* newChild = new CGUITreeViewNode( Owner, this ); + + Children.push_back( newChild ); + newChild->Text = text; + newChild->Icon = icon; + newChild->ImageIndex = imageIndex; + newChild->SelectedImageIndex = selectedImageIndex; + newChild->Data = data; + newChild->Data2 = data2; + if( data2 ) + { + data2->grab(); + } + return newChild; +} + +IGUITreeViewNode* CGUITreeViewNode::addChildFront( + const wchar_t* text, + const wchar_t* icon /*= 0*/, + s32 imageIndex /*= -1*/, + s32 selectedImageIndex /*= -1*/, + void* data /*= 0*/, + IReferenceCounted* data2 /*= 0*/ ) +{ + CGUITreeViewNode* newChild = new CGUITreeViewNode( Owner, this ); + + Children.push_front( newChild ); + newChild->Text = text; + newChild->Icon = icon; + newChild->ImageIndex = imageIndex; + newChild->SelectedImageIndex = selectedImageIndex; + newChild->Data = data; + newChild->Data2 = data2; + if( data2 ) + { + data2->grab(); + } + return newChild; +} + +IGUITreeViewNode* CGUITreeViewNode::insertChildAfter( + IGUITreeViewNode* other, + const wchar_t* text, + const wchar_t* icon /*= 0*/, + s32 imageIndex /*= -1*/, + s32 selectedImageIndex /*= -1*/, + void* data /*= 0*/, + IReferenceCounted* data2/* = 0*/ ) +{ + core::list::Iterator itOther; + CGUITreeViewNode* newChild = 0; + + for( itOther = Children.begin(); itOther != Children.end(); itOther++ ) + { + if( other == *itOther ) + { + newChild = new CGUITreeViewNode( Owner, this ); + newChild->Text = text; + newChild->Icon = icon; + newChild->ImageIndex = imageIndex; + newChild->SelectedImageIndex = selectedImageIndex; + newChild->Data = data; + newChild->Data2 = data2; + if( data2 ) + { + data2->grab(); + } + Children.insert_after( itOther, newChild ); + break; + } + } + return newChild; +} + +IGUITreeViewNode* CGUITreeViewNode::insertChildBefore( + IGUITreeViewNode* other, + const wchar_t* text, + const wchar_t* icon /*= 0*/, + s32 imageIndex /*= -1*/, + s32 selectedImageIndex /*= -1*/, + void* data /*= 0*/, + IReferenceCounted* data2/* = 0*/ ) +{ + core::list::Iterator itOther; + CGUITreeViewNode* newChild = 0; + + for( itOther = Children.begin(); itOther != Children.end(); itOther++ ) + { + if( other == *itOther ) + { + newChild = new CGUITreeViewNode( Owner, this ); + newChild->Text = text; + newChild->Icon = icon; + newChild->ImageIndex = imageIndex; + newChild->SelectedImageIndex = selectedImageIndex; + newChild->Data = data; + newChild->Data2 = data2; + if( data2 ) + { + data2->grab(); + } + Children.insert_before( itOther, newChild ); + break; + } + } + return newChild; +} + +IGUITreeViewNode* CGUITreeViewNode::getFirstChild() const +{ + if( Children.empty() ) + { + return 0; + } + else + { + return *( Children.begin() ); + } +} + +IGUITreeViewNode* CGUITreeViewNode::getLastChild() const +{ + if( Children.empty() ) + { + return 0; + } + else + { + return *( Children.getLast() ); + } +} + +IGUITreeViewNode* CGUITreeViewNode::getPrevSibling() const +{ + core::list::Iterator itThis; + core::list::Iterator itOther; + CGUITreeViewNode* other = 0; + + if( Parent ) + { + for( itThis = Parent->Children.begin(); itThis != Parent->Children.end(); itThis++ ) + { + if( this == *itThis ) + { + if( itThis != Parent->Children.begin() ) + { + other = *itOther; + } + break; + } + itOther = itThis; + } + } + return other; +} + +IGUITreeViewNode* CGUITreeViewNode::getNextSibling() const +{ + core::list::Iterator itThis; + CGUITreeViewNode* other = 0; + + if( Parent ) + { + for( itThis = Parent->Children.begin(); itThis != Parent->Children.end(); itThis++ ) + { + if( this == *itThis ) + { + if( itThis != Parent->Children.getLast() ) + { + other = *( ++itThis ); + } + break; + } + } + } + return other; +} + +IGUITreeViewNode* CGUITreeViewNode::getNextVisible() const +{ + IGUITreeViewNode* next = 0; + IGUITreeViewNode* node = 0; + + node = const_cast( this ); + + if( node->getExpanded() && node->hasChildren() ) + { + next = node->getFirstChild(); + } + else + { + next = node->getNextSibling(); + } + while( !next && node->getParent() ) + { + next = node->getParent()->getNextSibling(); + if( !next ) + { + node = node->getParent(); + } + } + + return next; +} + +bool CGUITreeViewNode::deleteChild( IGUITreeViewNode* child ) +{ + core::list::Iterator itChild; + bool deleted = false; + + for( itChild = Children.begin(); itChild != Children.end(); itChild++ ) + { + if( child == *itChild ) + { + child->drop(); + Children.erase( itChild ); + deleted = true; + break; + } + } + return deleted; +} + +bool CGUITreeViewNode::moveChildUp( IGUITreeViewNode* child ) +{ + core::list::Iterator itChild; + core::list::Iterator itOther; + CGUITreeViewNode* nodeTmp; + bool moved = false; + + for( itChild = Children.begin(); itChild != Children.end(); itChild++ ) + { + if( child == *itChild ) + { + if( itChild != Children.begin() ) + { + nodeTmp = *itChild; + *itChild = *itOther; + *itOther = nodeTmp; + moved = true; + } + break; + } + itOther = itChild; + } + return moved; +} + +bool CGUITreeViewNode::moveChildDown( IGUITreeViewNode* child ) +{ + core::list::Iterator itChild; + core::list::Iterator itOther; + CGUITreeViewNode* nodeTmp; + bool moved = false; + + for( itChild = Children.begin(); itChild != Children.end(); itChild++ ) + { + if( child == *itChild ) + { + if( itChild != Children.getLast() ) + { + itOther = itChild; + ++itOther; + nodeTmp = *itChild; + *itChild = *itOther; + *itOther = nodeTmp; + moved = true; + } + break; + } + } + return moved; +} + +void CGUITreeViewNode::setExpanded( bool expanded ) +{ + Expanded = expanded; +} + +void CGUITreeViewNode::setSelected( bool selected ) +{ + if( Owner ) + { + if( selected ) + { + Owner->Selected = this; + } + else + { + if( Owner->Selected == this ) + { + Owner->Selected = 0; + } + } + } +} + +bool CGUITreeViewNode::getSelected() const +{ + if( Owner ) + { + return Owner->Selected == (IGUITreeViewNode*)this; + } + else + { + return false; + } +} + +bool CGUITreeViewNode::isRoot() const +{ + return ( Owner && ( this == Owner->Root ) ); +} + +s32 CGUITreeViewNode::getLevel() const +{ + if( Parent ) + { + return Parent->getLevel() + 1; + } + else + { + return 0; + } +} + +bool CGUITreeViewNode::isVisible() const +{ + if( Parent ) + { + return Parent->getExpanded() && Parent->isVisible(); + } + else + { + return true; + } +} + + +//! constructor +CGUITreeView::CGUITreeView(IGUIEnvironment* environment, IGUIElement* parent, + s32 id, core::rect rectangle, bool clip, + bool drawBack,bool scrollBarVertical, bool scrollBarHorizontal) + : IGUITreeView( environment, parent, id, rectangle ), + Root(0), Selected(0), + ItemHeight( 0 ), + IndentWidth( 0 ), + TotalItemHeight( 0 ), + TotalItemWidth ( 0 ), + ScrollBarSize( 0 ), + Font( 0 ), + OverrideFont( 0 ), + IconFont( 0 ), + ScrollBarH( 0 ), + ScrollBarV( 0 ), + ImageList( 0 ), + LastEventNode( 0 ), + LinesVisible( true ), + Selecting( false ), + Clip( clip ), + DrawBack( drawBack ), + ImageLeftOfIcon( true ) +{ +#ifdef _DEBUG + setDebugName( "CGUITreeView" ); +#endif + + IGUISkin* skin = Environment->getSkin(); + ScrollBarSize = skin->getSize( EGDS_SCROLLBAR_SIZE ); + + if ( scrollBarVertical ) + { + ScrollBarV = new CGUIScrollBar( false, Environment, this, -1, + core::rect( RelativeRect.getWidth() - ScrollBarSize, + 0, + RelativeRect.getWidth(), + RelativeRect.getHeight() - ScrollBarSize + ), !clip ); + ScrollBarV->drop(); + + ScrollBarV->setSubElement(true); + ScrollBarV->setPos( 0 ); + ScrollBarV->grab(); + } + + if ( scrollBarHorizontal ) + { + ScrollBarH = new CGUIScrollBar( true, Environment, this, -1, + core::rect( 0, + RelativeRect.getHeight() - ScrollBarSize, + RelativeRect.getWidth() - ScrollBarSize, + RelativeRect.getHeight() + ), !clip ); + ScrollBarH->drop(); + + ScrollBarH->setSubElement(true); + ScrollBarH->setPos( 0 ); + ScrollBarH->grab(); + } + + Root = new CGUITreeViewNode( this, 0 ); + Root->Expanded = true; + + recalculateItemHeight(); +} + + +//! destructor +CGUITreeView::~CGUITreeView() +{ + if( ScrollBarV ) + { + ScrollBarV->drop(); + } + + if( ScrollBarH ) + { + ScrollBarH->drop(); + } + + if( Font ) + { + Font->drop(); + } + + if( IconFont ) + { + IconFont->drop(); + } + + if( ImageList ) + { + ImageList->drop(); + } + + if( Root ) + { + Root->drop(); + } +} + +//! Sets another skin independent font. +void CGUITreeView::setOverrideFont(IGUIFont* font) +{ + if (OverrideFont == font) + return; + + if (OverrideFont) + OverrideFont->drop(); + + OverrideFont = font; + + if (OverrideFont) + OverrideFont->grab(); + + recalculateItemHeight(); +} + +//! Gets the override font (if any) +IGUIFont * CGUITreeView::getOverrideFont() const +{ + return OverrideFont; +} + +//! Get the font which is used right now for drawing +IGUIFont* CGUITreeView::getActiveFont() const +{ + if ( OverrideFont ) + return OverrideFont; + IGUISkin* skin = Environment->getSkin(); + if (skin) + return skin->getFont(); + return 0; +} + +void CGUITreeView::recalculateItemHeight() +{ + if( Font != getActiveFont() ) + { + if( Font ) + { + Font->drop(); + } + + Font = getActiveFont(); + ItemHeight = 0; + + if( Font ) + { + ItemHeight = Font->getDimension( L"A" ).Height + 4; + Font->grab(); + } + + if( IconFont ) + { + s32 height = IconFont->getDimension( L" " ).Height; + if( height > ItemHeight ) + { + ItemHeight = height; + } + } + if( ImageList ) + { + if( ImageList->getImageSize().Height + 1 > ItemHeight ) + { + ItemHeight = ImageList->getImageSize().Height + 1; + } + } + } + + IndentWidth = ItemHeight; + if( IndentWidth < 9 ) + { + IndentWidth = 9; + } + else if( IndentWidth > 15 ) + { + IndentWidth = 15; + } + else + { + if( ( ( IndentWidth >> 1 ) << 1 ) - IndentWidth == 0 ) + { + --IndentWidth; + } + } + + TotalItemHeight = 0; + TotalItemWidth = AbsoluteRect.getWidth() * 2; + IGUITreeViewNode* node = Root->getFirstChild(); + while( node ) + { + TotalItemHeight += ItemHeight; + node = node->getNextVisible(); + } + + if ( ScrollBarV ) + { + s32 diffHor = TotalItemHeight - AbsoluteRect.getHeight(); + if ( ScrollBarH ) + { + diffHor += ScrollBarH->getAbsolutePosition().getHeight(); + } + ScrollBarV->setMax( core::max_( 0, diffHor) ); + } + + if ( ScrollBarH ) + { + s32 diffVert = TotalItemWidth - AbsoluteRect.getWidth(); + if ( ScrollBarV ) + { + // TODO: not sure yet if it needs handling + } + ScrollBarH->setMax( core::max_( 0, diffVert ) ); + } + +} + +void CGUITreeView::updateScrollBarSize(s32 size) +{ + if ( size != ScrollBarSize ) + { + ScrollBarSize = size; + + if ( ScrollBarV ) + { + core::recti r(RelativeRect.getWidth() - ScrollBarSize, 0, + RelativeRect.getWidth(), RelativeRect.getHeight() - ScrollBarSize); + ScrollBarV->setRelativePosition(r); + } + + if ( ScrollBarH ) + { + core::recti r(0, RelativeRect.getHeight() - ScrollBarSize, + RelativeRect.getWidth() - ScrollBarSize, RelativeRect.getHeight()); + ScrollBarH->setRelativePosition(r); + } + } +} + +//! called if an event happened. +bool CGUITreeView::OnEvent( const SEvent &event ) +{ + if ( isEnabled() ) + { + switch( event.EventType ) + { + case EET_GUI_EVENT: + switch( event.GUIEvent.EventType ) + { + case gui::EGET_SCROLL_BAR_CHANGED: + if( event.GUIEvent.Caller == ScrollBarV || event.GUIEvent.Caller == ScrollBarH ) + { + //s32 pos = ( ( gui::IGUIScrollBar* )event.GUIEvent.Caller )->getPos(); + return true; + } + break; + case gui::EGET_ELEMENT_FOCUS_LOST: + { + Selecting = false; + return false; + } + break; + default: + break; + } + break; + case EET_MOUSE_INPUT_EVENT: + { + core::position2d p( event.MouseInput.X, event.MouseInput.Y ); + + switch( event.MouseInput.Event ) + { + case EMIE_MOUSE_WHEEL: + if ( ScrollBarV ) + ScrollBarV->setPos( ScrollBarV->getPos() + (event.MouseInput.Wheel < 0 ? -1 : 1) * -10 ); + return true; + break; + + case EMIE_LMOUSE_PRESSED_DOWN: + if( ( ScrollBarV && ScrollBarV->getAbsolutePosition().isPointInside( p ) && ScrollBarV->OnEvent( event ) ) || + ( ScrollBarH && ScrollBarH->getAbsolutePosition().isPointInside( p ) && ScrollBarH->OnEvent( event ) ) + ) + { + return true; + } + + Selecting = true; + return true; + break; + + case EMIE_LMOUSE_LEFT_UP: + if( ( ScrollBarV && ScrollBarV->getAbsolutePosition().isPointInside( p ) && ScrollBarV->OnEvent( event ) ) || + ( ScrollBarH && ScrollBarH->getAbsolutePosition().isPointInside( p ) && ScrollBarH->OnEvent( event ) ) + ) + { + return true; + } + + Selecting = false; + mouseAction( event.MouseInput.X, event.MouseInput.Y ); + return true; + break; + + case EMIE_MOUSE_MOVED: + if( Selecting ) + { + if( getAbsolutePosition().isPointInside( p ) ) + { + mouseAction( event.MouseInput.X, event.MouseInput.Y, true ); + return true; + } + } + break; + + default: + break; + } + } + break; + default: + break; + } + } + + return Parent ? Parent->OnEvent( event ) : false; +} + +/*! +*/ +void CGUITreeView::mouseAction( s32 xpos, s32 ypos, bool onlyHover /*= false*/ ) +{ + IGUITreeViewNode* oldSelected = Selected; + IGUITreeViewNode* hitNode = 0; + s32 selIdx=-1; + s32 n; + IGUITreeViewNode* node; + SEvent event; + + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.Element = 0; + + xpos -= AbsoluteRect.UpperLeftCorner.X; + ypos -= AbsoluteRect.UpperLeftCorner.Y; + + // find new selected item. + s32 scrollBarVPos = ScrollBarV ? ScrollBarV->getPos() : 0; + if( ItemHeight != 0 ) + { + selIdx = ( ( ypos - 1 ) + scrollBarVPos ) / ItemHeight; + } + + hitNode = 0; + node = Root->getFirstChild(); + n = 0; + while( node ) + { + if( selIdx == n ) + { + hitNode = node; + break; + } + node = node->getNextVisible(); + ++n; + } + + s32 scrollBarHPos = ScrollBarH ? ScrollBarH->getPos() : 0; + xpos += scrollBarHPos; // correction for shift + if( hitNode && xpos > hitNode->getLevel() * IndentWidth ) + { + Selected = hitNode; + } + + if( hitNode && !onlyHover + && xpos < hitNode->getLevel() * IndentWidth + && xpos > ( hitNode->getLevel() - 1 ) * IndentWidth + && hitNode->hasChildren() ) + { + hitNode->setExpanded( !hitNode->getExpanded() ); + + // post expand/collaps news + if( hitNode->getExpanded() ) + { + event.GUIEvent.EventType = EGET_TREEVIEW_NODE_EXPAND; + } + else + { + event.GUIEvent.EventType = EGET_TREEVIEW_NODE_COLLAPS; + } + LastEventNode = hitNode; + Parent->OnEvent( event ); + LastEventNode = 0; + } + + if( Selected && !Selected->isVisible() ) + { + Selected = 0; + } + + // post selection news + + if( Parent && !onlyHover && Selected != oldSelected ) + { + if( oldSelected ) + { + event.GUIEvent.EventType = EGET_TREEVIEW_NODE_DESELECT; + LastEventNode = oldSelected; + Parent->OnEvent( event ); + LastEventNode = 0; + } + if( Selected ) + { + event.GUIEvent.EventType = EGET_TREEVIEW_NODE_SELECT; + LastEventNode = Selected; + Parent->OnEvent( event ); + LastEventNode = 0; + } + } +} + +//! draws the element and its children +void CGUITreeView::draw() +{ + if( !IsVisible ) + { + return; + } + + IGUISkin* skin = Environment->getSkin(); + + updateScrollBarSize(skin->getSize(EGDS_SCROLLBAR_SIZE)); + recalculateItemHeight(); // if the font changed + + irr::video::IVideoDriver* driver = Environment->getVideoDriver(); + + core::rect* clipRect = 0; + if( Clip ) + { + clipRect = &AbsoluteClippingRect; + } + + // draw background + + core::rect frameRect( AbsoluteRect ); + + if( DrawBack ) + { + driver->draw2DRectangle( skin->getColor( EGDC_3D_HIGH_LIGHT ), frameRect, clipRect ); + } + + // draw the border + + frameRect.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y + 1; + driver->draw2DRectangle( skin->getColor( EGDC_3D_SHADOW ), frameRect, clipRect ); + + frameRect.LowerRightCorner.Y = AbsoluteRect.LowerRightCorner.Y; + frameRect.LowerRightCorner.X = frameRect.UpperLeftCorner.X + 1; + driver->draw2DRectangle( skin->getColor( EGDC_3D_SHADOW ), frameRect, clipRect ); + + frameRect = AbsoluteRect; + frameRect.UpperLeftCorner.X = frameRect.LowerRightCorner.X - 1; + driver->draw2DRectangle( skin->getColor( EGDC_3D_HIGH_LIGHT ), frameRect, clipRect ); + + frameRect = AbsoluteRect; + frameRect.UpperLeftCorner.Y = AbsoluteRect.LowerRightCorner.Y - 1; + frameRect.LowerRightCorner.Y = AbsoluteRect.LowerRightCorner.Y; + driver->draw2DRectangle( skin->getColor( EGDC_3D_HIGH_LIGHT ), frameRect, clipRect ); + + // draw items + + core::rect clientClip( AbsoluteRect ); + clientClip.UpperLeftCorner.X += 1; + clientClip.UpperLeftCorner.Y += 1; + clientClip.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X; + clientClip.LowerRightCorner.Y -= 1; + + if ( ScrollBarV ) + clientClip.LowerRightCorner.X -= ScrollBarSize; + if ( ScrollBarH ) + clientClip.LowerRightCorner.Y -= ScrollBarSize; + + if( clipRect ) + { + clientClip.clipAgainst( *clipRect ); + } + + frameRect = AbsoluteRect; + frameRect.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - ScrollBarSize; + frameRect.LowerRightCorner.Y = AbsoluteRect.UpperLeftCorner.Y + ItemHeight; + + if ( ScrollBarV ) + { + frameRect.UpperLeftCorner.Y -= ScrollBarV->getPos(); + frameRect.LowerRightCorner.Y -= ScrollBarV->getPos(); + } + + IGUITreeViewNode* node = Root->getFirstChild(); + while( node ) + { + frameRect.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X + 1 + node->getLevel() * IndentWidth; + if ( ScrollBarH ) + { + frameRect.UpperLeftCorner.X -= ScrollBarH->getPos(); + } + + if( frameRect.LowerRightCorner.Y >= AbsoluteRect.UpperLeftCorner.Y + && frameRect.UpperLeftCorner.Y <= AbsoluteRect.LowerRightCorner.Y ) + { + if( node == Selected ) + { + // selection box beginning from far left + core::rect copyFrameRect( frameRect ); // local copy to keep original untouched + copyFrameRect.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X + 1; + driver->draw2DRectangle( skin->getColor( EGDC_HIGH_LIGHT ), copyFrameRect, &clientClip ); + } + + if( node->hasChildren() ) + { + core::rect rc; + core::rect expanderRect; + + expanderRect.UpperLeftCorner.X = frameRect.UpperLeftCorner.X - IndentWidth + 2; + expanderRect.UpperLeftCorner.Y = frameRect.UpperLeftCorner.Y + ( ( frameRect.getHeight() - ( IndentWidth - 4 ) ) >> 1 ); + expanderRect.LowerRightCorner.X = expanderRect.UpperLeftCorner.X + IndentWidth - 4; + expanderRect.LowerRightCorner.Y = expanderRect.UpperLeftCorner.Y + IndentWidth - 4; + + // box upper line + rc.UpperLeftCorner.X = expanderRect.UpperLeftCorner.X; + rc.UpperLeftCorner.Y = expanderRect.UpperLeftCorner.Y; + rc.LowerRightCorner.X = expanderRect.LowerRightCorner.X; + rc.LowerRightCorner.Y = rc.UpperLeftCorner.Y + 1; + driver->draw2DRectangle( skin->getColor( EGDC_3D_DARK_SHADOW ), rc, clipRect ); + + // box left line + rc.UpperLeftCorner.X = expanderRect.UpperLeftCorner.X; + rc.UpperLeftCorner.Y = expanderRect.UpperLeftCorner.Y; + rc.LowerRightCorner.X = rc.UpperLeftCorner.X + 1; + rc.LowerRightCorner.Y = expanderRect.LowerRightCorner.Y; + driver->draw2DRectangle( skin->getColor( EGDC_3D_DARK_SHADOW ), rc, clipRect ); + + // box right line + rc.UpperLeftCorner.X = expanderRect.LowerRightCorner.X - 1; + rc.UpperLeftCorner.Y = expanderRect.UpperLeftCorner.Y; + rc.LowerRightCorner.X = rc.UpperLeftCorner.X + 1; + rc.LowerRightCorner.Y = expanderRect.LowerRightCorner.Y; + driver->draw2DRectangle( skin->getColor( EGDC_3D_DARK_SHADOW ), rc, clipRect ); + + // box bottom line + rc.UpperLeftCorner.X = expanderRect.UpperLeftCorner.X; + rc.UpperLeftCorner.Y = expanderRect.LowerRightCorner.Y - 1; + rc.LowerRightCorner.X = expanderRect.LowerRightCorner.X; + rc.LowerRightCorner.Y = rc.UpperLeftCorner.Y + 1; + driver->draw2DRectangle( skin->getColor( EGDC_3D_DARK_SHADOW ), rc, clipRect ); + + // horizontal '-' line + rc.UpperLeftCorner.X = expanderRect.UpperLeftCorner.X + 2; + rc.UpperLeftCorner.Y = expanderRect.UpperLeftCorner.Y + ( expanderRect.getHeight() >> 1 ); + rc.LowerRightCorner.X = rc.UpperLeftCorner.X + expanderRect.getWidth() - 4; + rc.LowerRightCorner.Y = rc.UpperLeftCorner.Y + 1; + driver->draw2DRectangle( skin->getColor( EGDC_BUTTON_TEXT ), rc, clipRect ); + + if( !node->getExpanded() ) + { + // vertical '+' line + rc.UpperLeftCorner.X = expanderRect.UpperLeftCorner.X + ( expanderRect.getWidth() >> 1 ); + rc.UpperLeftCorner.Y = expanderRect.UpperLeftCorner.Y + 2; + rc.LowerRightCorner.X = rc.UpperLeftCorner.X + 1; + rc.LowerRightCorner.Y = rc.UpperLeftCorner.Y + expanderRect.getHeight() - 4; + driver->draw2DRectangle( skin->getColor( EGDC_BUTTON_TEXT ), rc, clipRect ); + } + } + + core::rect textRect = frameRect; + + if( Font ) + { + EGUI_DEFAULT_COLOR textCol = EGDC_GRAY_TEXT; + if ( isEnabled() ) + textCol = ( node == Selected ) ? EGDC_HIGH_LIGHT_TEXT : EGDC_BUTTON_TEXT; + + s32 iconWidth = 0; + for( s32 n = 0; n < 2; ++n ) + { + s32 index = node->getImageIndex(); + if( ( ImageList && index >= 0 ) + && ( ( ImageLeftOfIcon && n == 0 ) + || ( !ImageLeftOfIcon && n == 1 ) ) ) + { + index = node->getSelectedImageIndex(); + if( node != Selected || index < 0 ) + { + index = node->getImageIndex(); + } + ImageList->draw( + index, + core::position2d( + textRect.UpperLeftCorner.X, + textRect.UpperLeftCorner.Y + ( ( textRect.getHeight() - ImageList->getImageSize().Height ) >> 1 ) ), + &clientClip ); + iconWidth += ImageList->getImageSize().Width + 3; + textRect.UpperLeftCorner.X += ImageList->getImageSize().Width + 3; + } + else if( ( IconFont && reinterpret_cast( node )->Icon.size() ) + && ( ( ImageLeftOfIcon && n == 1 ) + || ( !ImageLeftOfIcon && n == 0 ) ) ) + { + IconFont->draw( node->getIcon(), textRect, skin->getColor(textCol), false, true, &clientClip ); + iconWidth += IconFont->getDimension( node->getIcon() ).Width + 3; + textRect.UpperLeftCorner.X += IconFont->getDimension( node->getIcon() ).Width + 3; + } + } + + Font->draw( node->getText(), textRect, skin->getColor(textCol), false, true, &clientClip ); + + textRect.UpperLeftCorner.X -= iconWidth; + } + + // draw the lines if neccessary + if( LinesVisible ) + { + core::rect rc; + + // horizontal line + rc.UpperLeftCorner.X = frameRect.UpperLeftCorner.X - IndentWidth - ( IndentWidth >> 1 ) - 1; + rc.UpperLeftCorner.Y = frameRect.UpperLeftCorner.Y + ( ( frameRect.getHeight() ) >> 1 ); + if( node->hasChildren() ) + { + rc.LowerRightCorner.X = frameRect.UpperLeftCorner.X - IndentWidth; + } + else + { + rc.LowerRightCorner.X = frameRect.UpperLeftCorner.X - 2; + } + rc.LowerRightCorner.Y = rc.UpperLeftCorner.Y + 1; + driver->draw2DRectangle( skin->getColor( EGDC_3D_SHADOW ), rc, clipRect ); + + if( node->getParent() != Root ) + { + // vertical line + if( node == node->getParent()->getFirstChild() ) + { + rc.UpperLeftCorner.Y = frameRect.UpperLeftCorner.Y - ( ( frameRect.getHeight() - IndentWidth ) >> 1 ); + } + else + { + rc.UpperLeftCorner.Y = frameRect.UpperLeftCorner.Y - ( frameRect.getHeight() >> 1 ); + } + rc.LowerRightCorner.X = rc.UpperLeftCorner.X + 1; + driver->draw2DRectangle( skin->getColor( EGDC_3D_SHADOW ), rc, clipRect ); + + // the vertical lines of all parents + IGUITreeViewNode* nodeTmp = node->getParent(); + rc.UpperLeftCorner.Y = frameRect.UpperLeftCorner.Y - ( frameRect.getHeight() >> 1 ); + for( s32 n = 0; n < node->getLevel() - 2; ++n ) + { + rc.UpperLeftCorner.X -= IndentWidth; + rc.LowerRightCorner.X -= IndentWidth; + if( nodeTmp != nodeTmp->getParent()->getLastChild() ) + { + driver->draw2DRectangle( skin->getColor( EGDC_3D_SHADOW ), rc, clipRect ); + } + nodeTmp = nodeTmp->getParent(); + } + } + } + } + + frameRect.UpperLeftCorner.Y += ItemHeight; + frameRect.LowerRightCorner.Y += ItemHeight; + + node = node->getNextVisible(); + } + + IGUIElement::draw(); +} + +//! Sets the font which should be used as icon font. This font is set to the Irrlicht engine +//! built-in-font by default. Icons can be displayed in front of every list item. +//! An icon is a string, displayed with the icon font. When using the build-in-font of the +//! Irrlicht engine as icon font, the icon strings defined in GUIIcons.h can be used. +void CGUITreeView::setIconFont( IGUIFont* font ) +{ + s32 height; + + if ( font ) + font->grab(); + if ( IconFont ) + { + IconFont->drop(); + } + + IconFont = font; + if( IconFont ) + { + height = IconFont->getDimension( L" " ).Height; + if( height > ItemHeight ) + { + ItemHeight = height; + } + } +} + +//! Sets the image list which should be used for the image and selected image of every node. +//! The default is 0 (no images). +void CGUITreeView::setImageList( IGUIImageList* imageList ) +{ + if (imageList ) + imageList->grab(); + if( ImageList ) + { + ImageList->drop(); + } + + ImageList = imageList; + if( ImageList ) + { + if( ImageList->getImageSize().Height + 1 > ItemHeight ) + { + ItemHeight = ImageList->getImageSize().Height + 1; + } + } +} + +//! Access the vertical scrollbar +IGUIScrollBar* CGUITreeView::getVerticalScrollBar() const +{ + return ScrollBarV; +} + +//! Access the horizontal scrollbar +IGUIScrollBar* CGUITreeView::getHorizontalScrollBar() const +{ + return ScrollBarH; +} + +} // end namespace gui +} // end namespace irr + + +#endif // _IRR_COMPILE_WITH_GUI_ diff --git a/source/Irrlicht/CGUITreeView.h b/source/Irrlicht/CGUITreeView.h new file mode 100644 index 00000000..bdcf035e --- /dev/null +++ b/source/Irrlicht/CGUITreeView.h @@ -0,0 +1,355 @@ +// This file is part of the "Irrlicht Engine". +// written by Reinhard Ostermeier, reinhard@nospam.r-ostermeier.de + +#ifndef __C_GUI_TREE_VIEW_H_INCLUDED__ +#define __C_GUI_TREE_VIEW_H_INCLUDED__ + +#include "IGUITreeView.h" +#include "irrList.h" + + +namespace irr +{ +namespace gui +{ + // forward declarations + class IGUIFont; + class IGUIScrollBar; + class CGUITreeView; + + //! Node for gui tree view + class CGUITreeViewNode : public IGUITreeViewNode + { + friend class CGUITreeView; + + public: + //! constructor + CGUITreeViewNode( CGUITreeView* owner, CGUITreeViewNode* parent ); + + //! destructor + ~CGUITreeViewNode(); + + //! returns the owner (tree view) of this node + virtual IGUITreeView* getOwner() const _IRR_OVERRIDE_; + + //! Returns the parent node of this node. + virtual IGUITreeViewNode* getParent() const _IRR_OVERRIDE_; + + //! returns the text of the node + virtual const wchar_t* getText() const _IRR_OVERRIDE_ + { return Text.c_str(); } + + //! sets the text of the node + virtual void setText( const wchar_t* text ) _IRR_OVERRIDE_; + + //! returns the icon text of the node + virtual const wchar_t* getIcon() const _IRR_OVERRIDE_ + { return Icon.c_str(); } + + //! sets the icon text of the node + virtual void setIcon( const wchar_t* icon ) _IRR_OVERRIDE_; + + //! returns the image index of the node + virtual u32 getImageIndex() const _IRR_OVERRIDE_ + { return ImageIndex; } + + //! sets the image index of the node + virtual void setImageIndex( u32 imageIndex ) _IRR_OVERRIDE_ + { ImageIndex = imageIndex; } + + //! returns the image index of the node + virtual u32 getSelectedImageIndex() const _IRR_OVERRIDE_ + { return SelectedImageIndex; } + + //! sets the image index of the node + virtual void setSelectedImageIndex( u32 imageIndex ) _IRR_OVERRIDE_ + { SelectedImageIndex = imageIndex; } + + //! returns the user data (void*) of this node + virtual void* getData() const _IRR_OVERRIDE_ + { return Data; } + + //! sets the user data (void*) of this node + virtual void setData( void* data ) _IRR_OVERRIDE_ + { Data = data; } + + //! returns the user data2 (IReferenceCounted) of this node + virtual IReferenceCounted* getData2() const _IRR_OVERRIDE_ + { return Data2; } + + //! sets the user data2 (IReferenceCounted) of this node + virtual void setData2( IReferenceCounted* data ) _IRR_OVERRIDE_ + { + if( Data2 ) + { + Data2->drop(); + } + Data2 = data; + if( Data2 ) + { + Data2->grab(); + } + } + + //! returns the child item count + virtual u32 getChildCount() const _IRR_OVERRIDE_ + { return Children.getSize(); } + + //! removes all children (recursive) from this node + virtual void clearChildren() _IRR_OVERRIDE_; + + //! returns true if this node has child nodes + virtual bool hasChildren() const _IRR_OVERRIDE_ + { return !Children.empty(); } + + //! Adds a new node behind the last child node. + //! \param text text of the new node + //! \param icon icon text of the new node + //! \param imageIndex index of the image for the new node (-1 = none) + //! \param selectedImageIndex index of the selected image for the new node (-1 = same as imageIndex) + //! \param data user data (void*) of the new node + //! \param data2 user data2 (IReferenceCounted*) of the new node + //! \return + //! returns the new node + virtual IGUITreeViewNode* addChildBack( + const wchar_t* text, + const wchar_t* icon = 0, + s32 imageIndex = -1, + s32 selectedImageIndex = -1, + void* data = 0, + IReferenceCounted* data2 = 0) _IRR_OVERRIDE_; + + //! Adds a new node before the first child node. + //! \param text text of the new node + //! \param icon icon text of the new node + //! \param imageIndex index of the image for the new node (-1 = none) + //! \param selectedImageIndex index of the selected image for the new node (-1 = same as imageIndex) + //! \param data user data (void*) of the new node + //! \param data2 user data2 (IReferenceCounted*) of the new node + //! \return + //! returns the new node + virtual IGUITreeViewNode* addChildFront( + const wchar_t* text, + const wchar_t* icon = 0, + s32 imageIndex = -1, + s32 selectedImageIndex = -1, + void* data = 0, + IReferenceCounted* data2 = 0 ) _IRR_OVERRIDE_; + + //! Adds a new node behind the other node. + //! The other node has also te be a child node from this node. + //! \param text text of the new node + //! \param icon icon text of the new node + //! \param imageIndex index of the image for the new node (-1 = none) + //! \param selectedImageIndex index of the selected image for the new node (-1 = same as imageIndex) + //! \param data user data (void*) of the new node + //! \param data2 user data2 (IReferenceCounted*) of the new node + //! \return + //! returns the new node or 0 if other is no child node from this + virtual IGUITreeViewNode* insertChildAfter( + IGUITreeViewNode* other, + const wchar_t* text, + const wchar_t* icon = 0, + s32 imageIndex = -1, + s32 selectedImageIndex = -1, + void* data = 0, + IReferenceCounted* data2 = 0 ) _IRR_OVERRIDE_; + + //! Adds a new node before the other node. + //! The other node has also te be a child node from this node. + //! \param text text of the new node + //! \param icon icon text of the new node + //! \param imageIndex index of the image for the new node (-1 = none) + //! \param selectedImageIndex index of the selected image for the new node (-1 = same as imageIndex) + //! \param data user data (void*) of the new node + //! \param data2 user data2 (IReferenceCounted*) of the new node + //! \return + //! returns the new node or 0 if other is no child node from this + virtual IGUITreeViewNode* insertChildBefore( + IGUITreeViewNode* other, + const wchar_t* text, + const wchar_t* icon = 0, + s32 imageIndex = -1, + s32 selectedImageIndex = -1, + void* data = 0, + IReferenceCounted* data2 = 0 ) _IRR_OVERRIDE_; + + //! Return the first child note from this node. + virtual IGUITreeViewNode* getFirstChild() const _IRR_OVERRIDE_; + + //! Return the last child note from this node. + virtual IGUITreeViewNode* getLastChild() const _IRR_OVERRIDE_; + + //! Returns the preverse sibling node from this node. + virtual IGUITreeViewNode* getPrevSibling() const _IRR_OVERRIDE_; + + //! Returns the next sibling node from this node. + virtual IGUITreeViewNode* getNextSibling() const _IRR_OVERRIDE_; + + //! Returns the next visible (expanded, may be out of scrolling) node from this node. + virtual IGUITreeViewNode* getNextVisible() const _IRR_OVERRIDE_; + + //! Deletes a child node. + virtual bool deleteChild( IGUITreeViewNode* child ) _IRR_OVERRIDE_; + + //! Moves a child node one position up. + virtual bool moveChildUp( IGUITreeViewNode* child ) _IRR_OVERRIDE_; + + //! Moves a child node one position down. + virtual bool moveChildDown( IGUITreeViewNode* child ) _IRR_OVERRIDE_; + + //! Returns true if the node is expanded (children are visible). + virtual bool getExpanded() const _IRR_OVERRIDE_ + { return Expanded; } + + //! Sets if the node is expanded. + virtual void setExpanded( bool expanded ) _IRR_OVERRIDE_; + + //! Returns true if the node is currently selected. + virtual bool getSelected() const _IRR_OVERRIDE_; + + //! Sets this node as selected. + virtual void setSelected( bool selected ) _IRR_OVERRIDE_; + + //! Returns true if this node is the root node. + virtual bool isRoot() const _IRR_OVERRIDE_; + + //! Returns the level of this node. + virtual s32 getLevel() const _IRR_OVERRIDE_; + + //! Returns true if this node is visible (all parents are expanded). + virtual bool isVisible() const _IRR_OVERRIDE_; + + private: + + CGUITreeView* Owner; + CGUITreeViewNode* Parent; + core::stringw Text; + core::stringw Icon; + s32 ImageIndex; + s32 SelectedImageIndex; + void* Data; + IReferenceCounted* Data2; + bool Expanded; + core::list Children; + }; + + + //! Default tree view GUI element. + class CGUITreeView : public IGUITreeView + { + friend class CGUITreeViewNode; + + public: + //! constructor + CGUITreeView( IGUIEnvironment* environment, IGUIElement* parent, + s32 id, core::rect rectangle, bool clip = true, + bool drawBack = false, bool scrollBarVertical = true, bool scrollBarHorizontal = true ); + + //! destructor + virtual ~CGUITreeView(); + + //! returns the root node (not visible) from the tree. + virtual IGUITreeViewNode* getRoot() const _IRR_OVERRIDE_ + { return Root; } + + //! returns the selected node of the tree or 0 if none is selected + virtual IGUITreeViewNode* getSelected() const _IRR_OVERRIDE_ + { return Selected; } + + //! returns true if the tree lines are visible + virtual bool getLinesVisible() const _IRR_OVERRIDE_ + { return LinesVisible; } + + //! sets if the tree lines are visible + virtual void setLinesVisible( bool visible ) _IRR_OVERRIDE_ + { LinesVisible = visible; } + + //! called if an event happened. + virtual bool OnEvent( const SEvent &event ) _IRR_OVERRIDE_; + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + //! Sets the font which should be used as icon font. This font is set to the Irrlicht engine + //! built-in-font by default. Icons can be displayed in front of every list item. + //! An icon is a string, displayed with the icon font. When using the build-in-font of the + //! Irrlicht engine as icon font, the icon strings defined in GUIIcons.h can be used. + virtual void setIconFont( IGUIFont* font ) _IRR_OVERRIDE_; + + //! Sets a skin independent font. + /** \param font: New font to set or 0 to use the skin-font. */ + virtual void setOverrideFont(IGUIFont* font=0) _IRR_OVERRIDE_; + + //! Gets the override font (if any) + /** \return The override font (may be 0) */ + virtual IGUIFont* getOverrideFont(void) const _IRR_OVERRIDE_; + + //! Get the font which is used for drawing + /** This is the override font when one is set and the + font of the skin otherwise. */ + virtual IGUIFont* getActiveFont() const _IRR_OVERRIDE_; + + //! Sets the image list which should be used for the image and selected image of every node. + //! The default is 0 (no images). + virtual void setImageList( IGUIImageList* imageList ) _IRR_OVERRIDE_; + + //! Returns the image list which is used for the nodes. + virtual IGUIImageList* getImageList() const _IRR_OVERRIDE_ + { return ImageList; } + + //! Sets if the image is left of the icon. Default is true. + virtual void setImageLeftOfIcon( bool bLeftOf ) _IRR_OVERRIDE_ + { ImageLeftOfIcon = bLeftOf; } + + //! Returns if the Image is left of the icon. Default is true. + virtual bool getImageLeftOfIcon() const _IRR_OVERRIDE_ + { return ImageLeftOfIcon; } + + //! Returns the node which is associated to the last event. + virtual IGUITreeViewNode* getLastEventNode() const _IRR_OVERRIDE_ + { return LastEventNode; } + + //! Access the vertical scrollbar + virtual IGUIScrollBar* getVerticalScrollBar() const _IRR_OVERRIDE_; + + //! Access the horizontal scrollbar + virtual IGUIScrollBar* getHorizontalScrollBar() const _IRR_OVERRIDE_; + + private: + //! calculates the heigth of an node and of all visible nodes. + void recalculateItemHeight(); + + //! Resize scrollbars when their size in the skin has changed + void updateScrollBarSize(s32 size); + + //! executes an mouse action (like selectNew of CGUIListBox) + void mouseAction( s32 xpos, s32 ypos, bool onlyHover = false ); + + CGUITreeViewNode* Root; + IGUITreeViewNode* Selected; + s32 ItemHeight; + s32 IndentWidth; + s32 TotalItemHeight; + s32 TotalItemWidth; + s32 ScrollBarSize; + IGUIFont* Font; + gui::IGUIFont* OverrideFont; + IGUIFont* IconFont; + IGUIScrollBar* ScrollBarH; + IGUIScrollBar* ScrollBarV; + IGUIImageList* ImageList; + IGUITreeViewNode* LastEventNode; + bool LinesVisible; + bool Selecting; + bool Clip; + bool DrawBack; + bool ImageLeftOfIcon; + }; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CGUIWindow.cpp b/source/Irrlicht/CGUIWindow.cpp new file mode 100644 index 00000000..97697506 --- /dev/null +++ b/source/Irrlicht/CGUIWindow.cpp @@ -0,0 +1,404 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUIWindow.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUISkin.h" +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" +#include "IGUIButton.h" +#include "IGUIFont.h" +#include "IGUIFontBitmap.h" + +namespace irr +{ +namespace gui +{ + +//! constructor +CGUIWindow::CGUIWindow(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) +: IGUIWindow(environment, parent, id, rectangle), Dragging(false), IsDraggable(true), DrawBackground(true), DrawTitlebar(true), IsActive(false) +{ + #ifdef _DEBUG + setDebugName("CGUIWindow"); + #endif + + IGUISkin* skin = 0; + if (environment) + skin = environment->getSkin(); + + CurrentIconColor = video::SColor(255,255,255,255); + + s32 buttonw = 15; + if (skin) + { + buttonw = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH); + } + 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" ); + CloseButton->setSubElement(true); + CloseButton->setTabStop(false); + CloseButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + posx -= buttonw + 2; + + 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); + RestoreButton->setTabStop(false); + RestoreButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + posx -= buttonw + 2; + + 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); + MinButton->setTabStop(false); + MinButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + + MinButton->grab(); + RestoreButton->grab(); + CloseButton->grab(); + + // this element is a tab group + setTabGroup(true); + setTabStop(true); + setTabOrder(-1); + + refreshSprites(); + updateClientRect(); +} + + +//! destructor +CGUIWindow::~CGUIWindow() +{ + if (MinButton) + MinButton->drop(); + + if (RestoreButton) + RestoreButton->drop(); + + if (CloseButton) + CloseButton->drop(); +} + +void CGUIWindow::refreshSprites() +{ + if (!Environment) + return; + IGUISkin* skin = Environment->getSkin(); + if ( !skin ) + return; + + IGUISpriteBank* sprites = skin->getSpriteBank(); + if ( !sprites ) + return; + + CurrentIconColor = skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL); + + if (sprites) + { + CloseButton->setSpriteBank(sprites); + CloseButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_CLOSE), CurrentIconColor); + CloseButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_CLOSE), CurrentIconColor); + + RestoreButton->setSpriteBank(sprites); + RestoreButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_RESTORE), CurrentIconColor); + RestoreButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_RESTORE), CurrentIconColor); + + MinButton->setSpriteBank(sprites); + MinButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_MINIMIZE), CurrentIconColor); + MinButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_MINIMIZE), CurrentIconColor); + } +} + +//! called if an event happened. +bool CGUIWindow::OnEvent(const SEvent& event) +{ + if (isEnabled()) + { + + switch(event.EventType) + { + case EET_GUI_EVENT: + if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST) + { + Dragging = false; + IsActive = false; + } + else + if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED) + { + if (Parent && ((event.GUIEvent.Caller == this) || isMyChild(event.GUIEvent.Caller))) + { + Parent->bringToFront(this); + IsActive = true; + } + else + { + IsActive = false; + } + } + else + if (event.GUIEvent.EventType == EGET_BUTTON_CLICKED) + { + if (event.GUIEvent.Caller == CloseButton) + { + if (Parent) + { + // send close event to parent + SEvent e; + e.EventType = EET_GUI_EVENT; + e.GUIEvent.Caller = this; + e.GUIEvent.Element = 0; + e.GUIEvent.EventType = EGET_ELEMENT_CLOSED; + + // if the event was not absorbed + if (!Parent->OnEvent(e)) + remove(); + + return true; + + } + else + { + remove(); + return true; + } + } + } + break; + case EET_MOUSE_INPUT_EVENT: + switch(event.MouseInput.Event) + { + case EMIE_LMOUSE_PRESSED_DOWN: + DragStart.X = event.MouseInput.X; + DragStart.Y = event.MouseInput.Y; + Dragging = IsDraggable; + if (Parent) + Parent->bringToFront(this); + return true; + case EMIE_LMOUSE_LEFT_UP: + Dragging = false; + return true; + case EMIE_MOUSE_MOVED: + if (!event.MouseInput.isLeftPressed()) + Dragging = false; + + if (Dragging) + { + // gui window should not be dragged outside its parent + 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; + + move(core::position2d(event.MouseInput.X - DragStart.X, event.MouseInput.Y - DragStart.Y)); + DragStart.X = event.MouseInput.X; + DragStart.Y = event.MouseInput.Y; + return true; + } + break; + default: + break; + } + default: + break; + } + } + + return IGUIElement::OnEvent(event); +} + + +//! Updates the absolute position. +void CGUIWindow::updateAbsolutePosition() +{ + IGUIElement::updateAbsolutePosition(); +} + + +//! draws the element and its children +void CGUIWindow::draw() +{ + if (IsVisible) + { + IGUISkin* skin = Environment->getSkin(); + + + // update each time because the skin is allowed to change this always. + updateClientRect(); + + if ( CurrentIconColor != skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL) ) + refreshSprites(); + + core::rect rect = AbsoluteRect; + + // draw body fast + if (DrawBackground) + { + rect = skin->draw3DWindowBackground(this, DrawTitlebar, + skin->getColor(IsActive ? EGDC_ACTIVE_BORDER : EGDC_INACTIVE_BORDER), + AbsoluteRect, &AbsoluteClippingRect); + + if (DrawTitlebar && Text.size()) + { + rect.UpperLeftCorner.X += skin->getSize(EGDS_TITLEBARTEXT_DISTANCE_X); + rect.UpperLeftCorner.Y += skin->getSize(EGDS_TITLEBARTEXT_DISTANCE_Y); + rect.LowerRightCorner.X -= skin->getSize(EGDS_WINDOW_BUTTON_WIDTH) + 5; + + IGUIFont* font = skin->getFont(EGDF_WINDOW); + if (font) + { + font->draw(Text.c_str(), rect, + skin->getColor(IsActive ? EGDC_ACTIVE_CAPTION:EGDC_INACTIVE_CAPTION), + false, true, &AbsoluteClippingRect); + } + } + } + } + + IGUIElement::draw(); +} + + +//! Returns pointer to the close button +IGUIButton* CGUIWindow::getCloseButton() const +{ + return CloseButton; +} + + +//! Returns pointer to the minimize button +IGUIButton* CGUIWindow::getMinimizeButton() const +{ + return MinButton; +} + + +//! Returns pointer to the maximize button +IGUIButton* CGUIWindow::getMaximizeButton() const +{ + return RestoreButton; +} + + +//! Returns true if the window is draggable, false if not +bool CGUIWindow::isDraggable() const +{ + return IsDraggable; +} + + +//! Sets whether the window is draggable +void CGUIWindow::setDraggable(bool draggable) +{ + IsDraggable = draggable; + + if (Dragging && !IsDraggable) + Dragging = false; +} + + +//! Set if the window background will be drawn +void CGUIWindow::setDrawBackground(bool draw) +{ + DrawBackground = draw; +} + + +//! Get if the window background will be drawn +bool CGUIWindow::getDrawBackground() const +{ + return DrawBackground; +} + + +//! Set if the window titlebar will be drawn +void CGUIWindow::setDrawTitlebar(bool draw) +{ + DrawTitlebar = draw; +} + + +//! Get if the window titlebar will be drawn +bool CGUIWindow::getDrawTitlebar() const +{ + return DrawTitlebar; +} + + +void CGUIWindow::updateClientRect() +{ + if (! DrawBackground ) + { + ClientRect = core::rect(0,0, AbsoluteRect.getWidth(), AbsoluteRect.getHeight()); + return; + } + IGUISkin* skin = Environment->getSkin(); + skin->draw3DWindowBackground(this, DrawTitlebar, + skin->getColor(IsActive ? EGDC_ACTIVE_BORDER : EGDC_INACTIVE_BORDER), + AbsoluteRect, &AbsoluteClippingRect, &ClientRect); + ClientRect -= AbsoluteRect.UpperLeftCorner; +} + + +//! Returns the rectangle of the drawable area (without border, without titlebar and without scrollbars) +core::rect CGUIWindow::getClientRect() const +{ + return ClientRect; +} + + +//! Writes attributes of the element. +void CGUIWindow::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const +{ + IGUIWindow::serializeAttributes(out,options); + + out->addBool("IsDraggable", IsDraggable); + out->addBool("DrawBackground", DrawBackground); + out->addBool("DrawTitlebar", DrawTitlebar); + + // Currently we can't just serialize attributes of sub-elements. + // To do this we either + // a) allow further serialization after attribute serialiation (second function, callback or event) + // b) add an IGUIElement attribute + // c) extend the attribute system to allow attributes to have sub-attributes + // We just serialize the most important info for now until we can do one of the above solutions. + out->addBool("IsCloseVisible", CloseButton->isVisible()); + out->addBool("IsMinVisible", MinButton->isVisible()); + out->addBool("IsRestoreVisible", RestoreButton->isVisible()); +} + + +//! Reads attributes of the element +void CGUIWindow::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) +{ +IGUIWindow::deserializeAttributes(in,options); + + Dragging = false; + IsActive = false; + IsDraggable = in->getAttributeAsBool("IsDraggable"); + DrawBackground = in->getAttributeAsBool("DrawBackground"); + DrawTitlebar = in->getAttributeAsBool("DrawTitlebar"); + + CloseButton->setVisible(in->getAttributeAsBool("IsCloseVisible")); + MinButton->setVisible(in->getAttributeAsBool("IsMinVisible")); + RestoreButton->setVisible(in->getAttributeAsBool("IsRestoreVisible")); + + updateClientRect(); +} + + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIWindow.h b/source/Irrlicht/CGUIWindow.h new file mode 100644 index 00000000..8fb4bb24 --- /dev/null +++ b/source/Irrlicht/CGUIWindow.h @@ -0,0 +1,99 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_WINDOW_H_INCLUDED__ +#define __C_GUI_WINDOW_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_GUI_ + +#include "IGUIWindow.h" + +namespace irr +{ +namespace gui +{ + class IGUIButton; + + class CGUIWindow : public IGUIWindow + { + public: + + //! constructor + CGUIWindow(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle); + + //! destructor + virtual ~CGUIWindow(); + + //! called if an event happened. + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! update absolute position + virtual void updateAbsolutePosition() _IRR_OVERRIDE_; + + //! draws the element and its children + virtual void draw() _IRR_OVERRIDE_; + + //! Returns pointer to the close button + virtual IGUIButton* getCloseButton() const _IRR_OVERRIDE_; + + //! Returns pointer to the minimize button + virtual IGUIButton* getMinimizeButton() const _IRR_OVERRIDE_; + + //! Returns pointer to the maximize button + virtual IGUIButton* getMaximizeButton() const _IRR_OVERRIDE_; + + //! Returns true if the window is draggable, false if not + virtual bool isDraggable() const _IRR_OVERRIDE_; + + //! Sets whether the window is draggable + virtual void setDraggable(bool draggable) _IRR_OVERRIDE_; + + //! Set if the window background will be drawn + virtual void setDrawBackground(bool draw) _IRR_OVERRIDE_; + + //! Get if the window background will be drawn + virtual bool getDrawBackground() const _IRR_OVERRIDE_; + + //! Set if the window titlebar will be drawn + //! Note: If the background is not drawn, then the titlebar is automatically also not drawn + virtual void setDrawTitlebar(bool draw) _IRR_OVERRIDE_; + + //! Get if the window titlebar will be drawn + virtual bool getDrawTitlebar() const _IRR_OVERRIDE_; + + //! Returns the rectangle of the drawable area (without border and without titlebar) + virtual core::rect getClientRect() const _IRR_OVERRIDE_; + + //! Writes attributes of the element. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the element + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + + protected: + + void updateClientRect(); + void refreshSprites(); + + IGUIButton* CloseButton; + IGUIButton* MinButton; + IGUIButton* RestoreButton; + core::rect ClientRect; + video::SColor CurrentIconColor; + + core::position2d DragStart; + bool Dragging, IsDraggable; + bool DrawBackground; + bool DrawTitlebar; + bool IsActive; + }; + +} // end namespace gui +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_GUI_ + +#endif + diff --git a/source/Irrlicht/CGeometryCreator.cpp b/source/Irrlicht/CGeometryCreator.cpp new file mode 100644 index 00000000..22ce7170 --- /dev/null +++ b/source/Irrlicht/CGeometryCreator.cpp @@ -0,0 +1,1084 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGeometryCreator.h" +#include "SAnimatedMesh.h" +#include "SMeshBuffer.h" +#include "SMesh.h" +#include "IMesh.h" +#include "IVideoDriver.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + +IMesh* CGeometryCreator::createCubeMesh(const core::vector3df& size, ECUBE_MESH_TYPE type) const +{ + SMesh* mesh = new SMesh; + + const video::SColor clr(255,255,255,255); + + if ( type == ECMT_1BUF_12VTX_NA ) + { + SMeshBuffer* buffer = new SMeshBuffer(); + + // Create indices (pos, neg describes normal direction of front-face) + const u16 u[36] = { 0,2,1, 0,3,2, // NEG_Z + 1,5,4, 1,2,5, // POS_X + 4,6,7, 4,5,6, // POS_Z + 7,3,0, 7,6,3, // NEG_X + 9,5,2, 9,8,5, // POS_Y + 0,11,10, 0,10,7}; // NEG_Y + + buffer->Indices.set_used(36); + + for (u32 i=0; i<36; ++i) + buffer->Indices[i] = u[i]; + + // Create vertices + buffer->Vertices.reallocate(12); + + buffer->Vertices.push_back(video::S3DVertex(0,0,0, -1,-1,-1, clr, 0, 1)); // 0 + buffer->Vertices.push_back(video::S3DVertex(1,0,0, 1,-1,-1, clr, 1, 1)); // 1 + buffer->Vertices.push_back(video::S3DVertex(1,1,0, 1, 1,-1, clr, 1, 0)); // 2 + buffer->Vertices.push_back(video::S3DVertex(0,1,0, -1, 1,-1, clr, 0, 0)); // 3 + buffer->Vertices.push_back(video::S3DVertex(1,0,1, 1,-1, 1, clr, 0, 1)); // 4 + buffer->Vertices.push_back(video::S3DVertex(1,1,1, 1, 1, 1, clr, 0, 0)); // 5 + buffer->Vertices.push_back(video::S3DVertex(0,1,1, -1, 1, 1, clr, 1, 0)); // 6 + buffer->Vertices.push_back(video::S3DVertex(0,0,1, -1,-1, 1, clr, 1, 1)); // 7 + buffer->Vertices.push_back(video::S3DVertex(0,1,1, -1, 1, 1, clr, 0, 1)); // 8 + buffer->Vertices.push_back(video::S3DVertex(0,1,0, -1, 1,-1, clr, 1, 1)); // 9 + buffer->Vertices.push_back(video::S3DVertex(1,0,1, 1,-1, 1, clr, 1, 0)); // 10 + buffer->Vertices.push_back(video::S3DVertex(1,0,0, 1,-1,-1, clr, 0, 0)); // 11 + + // Recalculate bounding box and set cube size + buffer->BoundingBox.reset(0,0,0); + + for (u32 i=0; i<12; ++i) + { + buffer->Vertices[i].Pos -= core::vector3df(0.5f, 0.5f, 0.5f); + buffer->Vertices[i].Pos *= size; + buffer->Vertices[i].Normal.normalize(); + buffer->BoundingBox.addInternalPoint(buffer->Vertices[i].Pos); + } + + mesh->addMeshBuffer(buffer); + buffer->drop(); + } + else if ( type == ECMT_6BUF_4VTX_NP ) + { + for ( int b=0; b<6; ++b ) + { + SMeshBuffer* buffer = new SMeshBuffer(); + + // Create indices + const u16 u[6] = { 0,2,1,0,3,2}; + + buffer->Indices.set_used(6); + + for ( int i=0; i<6; ++i ) + buffer->Indices[i] = u[i]; + + // Create vertices + buffer->Vertices.reallocate(4); + + switch ( b ) + { + case 0: + buffer->Vertices.push_back(video::S3DVertex(0,0,0, 0, 0,-1, clr, 0, 1)); + buffer->Vertices.push_back(video::S3DVertex(1,0,0, 0, 0,-1, clr, 1, 1)); + buffer->Vertices.push_back(video::S3DVertex(1,1,0, 0, 0,-1, clr, 1, 0)); + buffer->Vertices.push_back(video::S3DVertex(0,1,0, 0, 0,-1, clr, 0, 0)); + break; + case 1: + buffer->Vertices.push_back(video::S3DVertex(1,0,0, 1, 0, 0, clr, 0, 1)); + buffer->Vertices.push_back(video::S3DVertex(1,0,1, 1, 0, 0, clr, 1, 1)); + buffer->Vertices.push_back(video::S3DVertex(1,1,1, 1, 0, 0, clr, 1, 0)); + buffer->Vertices.push_back(video::S3DVertex(1,1,0, 1, 0, 0, clr, 0, 0)); + break; + case 2: + buffer->Vertices.push_back(video::S3DVertex(1,0,1, 0, 0, 1, clr, 0, 1)); + buffer->Vertices.push_back(video::S3DVertex(0,0,1, 0, 0, 1, clr, 1, 1)); + buffer->Vertices.push_back(video::S3DVertex(0,1,1, 0, 0, 1, clr, 1, 0)); + buffer->Vertices.push_back(video::S3DVertex(1,1,1, 0, 0, 1, clr, 0, 0)); + break; + case 3: + buffer->Vertices.push_back(video::S3DVertex(0,0,1, -1, 0, 0, clr, 0, 1)); + buffer->Vertices.push_back(video::S3DVertex(0,0,0, -1, 0, 0, clr, 1, 1)); + buffer->Vertices.push_back(video::S3DVertex(0,1,0, -1, 0, 0, clr, 1, 0)); + buffer->Vertices.push_back(video::S3DVertex(0,1,1, -1, 0, 0, clr, 0, 0)); + break; + case 4: + buffer->Vertices.push_back(video::S3DVertex(0,1,0, 0, 1, 0, clr, 0, 1)); + buffer->Vertices.push_back(video::S3DVertex(1,1,0, 0, 1, 0, clr, 1, 1)); + buffer->Vertices.push_back(video::S3DVertex(1,1,1, 0, 1, 0, clr, 1, 0)); + buffer->Vertices.push_back(video::S3DVertex(0,1,1, 0, 1, 0, clr, 0, 0)); + break; + case 5: + buffer->Vertices.push_back(video::S3DVertex(0,0,1, 0, -1, 0, clr, 0, 1)); + buffer->Vertices.push_back(video::S3DVertex(1,0,1, 0, -1, 0, clr, 1, 1)); + buffer->Vertices.push_back(video::S3DVertex(1,0,0, 0, -1, 0, clr, 1, 0)); + buffer->Vertices.push_back(video::S3DVertex(0,0,0, 0, -1, 0, clr, 0, 0)); + break; + } + + // Recalculate bounding box and set cube size + for (u32 i=0; i<4; ++i) + { + buffer->Vertices[i].Pos -= core::vector3df(0.5f, 0.5f, 0.5f); + buffer->Vertices[i].Pos *= size; + if ( i == 0 ) + buffer->BoundingBox.reset(buffer->Vertices[i].Pos); + else + buffer->BoundingBox.addInternalPoint(buffer->Vertices[i].Pos); + } + + mesh->addMeshBuffer(buffer); + buffer->drop(); + } + } + + mesh->recalculateBoundingBox(); + return mesh; +} + + +// creates a hill plane +IMesh* CGeometryCreator::createHillPlaneMesh( + const core::dimension2d& tileSize, + const core::dimension2d& tc, video::SMaterial* material, + f32 hillHeight, const core::dimension2d& ch, + const core::dimension2d& textureRepeatCount) const +{ + core::dimension2d tileCount = tc; + core::dimension2d countHills = ch; + + if (countHills.Width < 0.01f) + countHills.Width = 1.f; + if (countHills.Height < 0.01f) + countHills.Height = 1.f; + + // center + const core::position2d center((tileSize.Width * tileCount.Width) * 0.5f, (tileSize.Height * tileCount.Height) * 0.5f); + + // texture coord step + const core::dimension2d tx( + textureRepeatCount.Width / tileCount.Width, + textureRepeatCount.Height / tileCount.Height); + + // add one more point in each direction for proper tile count + ++tileCount.Height; + ++tileCount.Width; + + SMeshBuffer* buffer = new SMeshBuffer(); + video::S3DVertex vtx; + vtx.Color.set(255,255,255,255); + + // create vertices from left-front to right-back + u32 x; + + f32 sx=0.f, tsx=0.f; + for (x=0; xVertices.push_back(vtx); + sy += tileSize.Height; + tsy += tx.Height; + } + sx += tileSize.Width; + tsx += tx.Width; + } + + // create indices + + for (x=0; xIndices.push_back(current); + buffer->Indices.push_back(current + 1); + buffer->Indices.push_back(current + tileCount.Height); + + buffer->Indices.push_back(current + 1); + buffer->Indices.push_back(current + 1 + tileCount.Height); + buffer->Indices.push_back(current + tileCount.Height); + } + } + + // recalculate normals + for (u32 i=0; iIndices.size(); i+=3) + { + const core::vector3df normal = core::plane3d( + buffer->Vertices[buffer->Indices[i+0]].Pos, + buffer->Vertices[buffer->Indices[i+1]].Pos, + buffer->Vertices[buffer->Indices[i+2]].Pos).Normal; + + buffer->Vertices[buffer->Indices[i+0]].Normal = normal; + buffer->Vertices[buffer->Indices[i+1]].Normal = normal; + buffer->Vertices[buffer->Indices[i+2]].Normal = normal; + } + + if (material) + buffer->Material = *material; + + buffer->recalculateBoundingBox(); + buffer->setHardwareMappingHint(EHM_STATIC); + + SMesh* mesh = new SMesh(); + mesh->addMeshBuffer(buffer); + mesh->recalculateBoundingBox(); + buffer->drop(); + return mesh; +} + +namespace +{ + +// Return the position on an exponential curve. Input from 0 to 1. +float geopos(float pos) +{ + pos = core::clamp(pos, 0, 1); + pos *= 5; + + const float out = powf(2.5f, pos - 5); + + return out; +} + +} + +//! Create a geoplane. +IMesh* CGeometryCreator::createGeoplaneMesh(f32 radius, u32 rows, u32 columns) const +{ + using namespace core; + using namespace video; + + rows = clamp(rows, 3, 2048); + columns = clamp(columns, 3, 2048); + + SMeshBuffer * const mb = new SMeshBuffer(); + S3DVertex v(0, 0, 0, 0, 1, 0, SColor(255, 255, 255, 255), 0, 0); + const float anglestep = (2 * PI) / columns; + + mb->Vertices.reallocate((rows * columns) + 1); + mb->Indices.reallocate((((rows - 2) * columns * 2) + columns) * 3); + + u32 i, j; + mb->Vertices.push_back(v); + for (j = 1; j < rows; j++) + { + const float len = radius * geopos((float) j/(rows-1)); + + for (i = 0; i < columns; i++) + { + const float angle = anglestep * i; + v.Pos = vector3df(len * sinf(angle), 0, len * cosf(angle)); + + mb->Vertices.push_back(v); + } + } + + // Indices + // First the inner fan + for (i = 0; i < columns; i++) + { + mb->Indices.push_back(0); + mb->Indices.push_back(1 + i); + + if (i == columns - 1) + mb->Indices.push_back(1); + else + mb->Indices.push_back(2 + i); + } + + // Then the surrounding quads + for (j = 0; j < rows - 2; j++) + { + for (i = 0; i < columns; i++) + { + u32 start = ((j * columns) + i) + 1; + u32 next = start + 1; + u32 far = (((j + 1) * columns) + i) + 1; + u32 farnext = far + 1; + + if (i == columns - 1) + { + next = ((j * columns)) + 1; + farnext = (((j + 1) * columns)) + 1; + } + + mb->Indices.push_back(start); + mb->Indices.push_back(far); + mb->Indices.push_back(next); + + mb->Indices.push_back(next); + mb->Indices.push_back(far); + mb->Indices.push_back(farnext); + } + } + + // Done + SMesh * const mesh = new SMesh(); + mesh->addMeshBuffer(mb); + mb->recalculateBoundingBox(); + mb->setHardwareMappingHint(EHM_STATIC); + mesh->recalculateBoundingBox(); + mb->drop(); + + return mesh; +} + +IMesh* CGeometryCreator::createTerrainMesh(video::IImage* texture, + video::IImage* heightmap, const core::dimension2d& stretchSize, + f32 maxHeight, video::IVideoDriver* driver, + const core::dimension2d& maxVtxBlockSize, + bool debugBorders) const +{ + if (!texture || !heightmap) + return 0; + + // debug border + const s32 borderSkip = debugBorders ? 0 : 1; + + video::S3DVertex vtx; + vtx.Color.set(255,255,255,255); + + 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::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); + while (processed.Y blockSize = maxVtxBlockSize; + if (processed.X + blockSize.Width > hMapSize.Width) + blockSize.Width = hMapSize.Width - processed.X; + if (processed.Y + blockSize.Height > hMapSize.Height) + blockSize.Height = hMapSize.Height - processed.Y; + + SMeshBuffer* buffer = new SMeshBuffer(); + buffer->setHardwareMappingHint(scene::EHM_STATIC); + buffer->Vertices.reallocate(blockSize.getArea()); + // add vertices of vertex block + 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); + for (y=0; ygetPixel(x+processed.X, y+processed.Y).getAverage() * maxHeight; + + vtx.Pos.set(pos.X, height, pos.Y); + vtx.TCoords.set(tc); + buffer->Vertices.push_back(vtx); + pos.X += stretchSize.Width; + tc.X += bs.X; + } + pos.Y += stretchSize.Height; + tc.Y += bs.Y; + } + + buffer->Indices.reallocate((blockSize.Height-1)*(blockSize.Width-1)*6); + // add indices of vertex block + s32 c1 = 0; + for (y=0; yIndices.push_back(c); + buffer->Indices.push_back(c + blockSize.Width); + buffer->Indices.push_back(c + 1); + + buffer->Indices.push_back(c + 1); + buffer->Indices.push_back(c + blockSize.Width); + buffer->Indices.push_back(c + 1 + blockSize.Width); + } + c1 += blockSize.Width; + } + + // recalculate normals + for (u32 i=0; iIndices.size(); i+=3) + { + const core::vector3df normal = core::plane3d( + buffer->Vertices[buffer->Indices[i+0]].Pos, + buffer->Vertices[buffer->Indices[i+1]].Pos, + buffer->Vertices[buffer->Indices[i+2]].Pos).Normal; + + buffer->Vertices[buffer->Indices[i+0]].Normal = normal; + buffer->Vertices[buffer->Indices[i+1]].Normal = normal; + buffer->Vertices[buffer->Indices[i+2]].Normal = normal; + } + + if (buffer->Vertices.size()) + { + c8 textureName[64]; + // create texture for this block + video::IImage* img = driver->createImage(texture->getColorFormat(), core::dimension2d(core::floor32(blockSize.Width*thRel.X), core::floor32(blockSize.Height*thRel.Y))); + texture->copyTo(img, core::position2di(0,0), core::recti( + core::position2d(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))), 0); + + sprintf(textureName, "terrain%u_%u", tm, mesh->getMeshBufferCount()); + + buffer->Material.setTexture(0, driver->addTexture(textureName, img)); + + if (buffer->Material.getTexture(0)) + { + c8 tmp[255]; + sprintf(tmp, "Generated terrain texture (%ux%u): %s", + buffer->Material.getTexture(0)->getSize().Width, + buffer->Material.getTexture(0)->getSize().Height, + textureName); + os::Printer::log(tmp); + } + else + os::Printer::log("Could not create terrain texture.", textureName, ELL_ERROR); + + img->drop(); + } + + buffer->recalculateBoundingBox(); + mesh->addMeshBuffer(buffer); + buffer->drop(); + + // keep on processing + processed.X += maxVtxBlockSize.Width - borderSkip; + } + + // keep on processing + processed.X = 0; + processed.Y += maxVtxBlockSize.Height - borderSkip; + } + + mesh->recalculateBoundingBox(); + return mesh; +} + + +/* + a cylinder, a cone and a cross + point up on (0,1.f, 0.f ) +*/ +IMesh* CGeometryCreator::createArrowMesh(const u32 tesselationCylinder, + const u32 tesselationCone, + const f32 height, + const f32 cylinderHeight, + const f32 width0, + const f32 width1, + const video::SColor vtxColor0, + const video::SColor vtxColor1) const +{ + SMesh* mesh = (SMesh*)createCylinderMesh(width0, cylinderHeight, tesselationCylinder, vtxColor0, false); + + IMesh* mesh2 = createConeMesh(width1, height-cylinderHeight, tesselationCone, vtxColor1, vtxColor0); + for (u32 i=0; igetMeshBufferCount(); ++i) + { + scene::IMeshBuffer* buffer = mesh2->getMeshBuffer(i); + for (u32 j=0; jgetVertexCount(); ++j) + buffer->getPosition(j).Y += cylinderHeight; + buffer->setDirty(EBT_VERTEX); + buffer->recalculateBoundingBox(); + mesh->addMeshBuffer(buffer); + } + mesh2->drop(); + mesh->setHardwareMappingHint(EHM_STATIC); + + mesh->recalculateBoundingBox(); + return mesh; +} + + +/* A sphere with proper normals and texture coords */ +IMesh* CGeometryCreator::createSphereMesh(f32 radius, u32 polyCountX, u32 polyCountY) const +{ + // thanks to Alfaz93 who made his code available for Irrlicht on which + // this one is based! + + // we are creating the sphere mesh here. + + if (polyCountX < 2) + polyCountX = 2; + if (polyCountY < 2) + polyCountY = 2; + while (polyCountX * polyCountY > 32767) // prevent u16 overflow + { + polyCountX /= 2; + polyCountY /= 2; + } + + const u32 polyCountXPitch = polyCountX+1; // get to same vertex on next level + + SMeshBuffer* buffer = new SMeshBuffer(); + + buffer->Indices.reallocate((polyCountX * polyCountY) * 6); + + const video::SColor clr(255, 255,255,255); + + u32 level = 0; + + for (u32 p1 = 0; p1 < polyCountY-1; ++p1) + { + //main quads, top to bottom + for (u32 p2 = 0; p2 < polyCountX - 1; ++p2) + { + const u32 curr = level + p2; + buffer->Indices.push_back(curr + polyCountXPitch); + buffer->Indices.push_back(curr); + buffer->Indices.push_back(curr + 1); + buffer->Indices.push_back(curr + polyCountXPitch); + buffer->Indices.push_back(curr+1); + buffer->Indices.push_back(curr + 1 + polyCountXPitch); + } + + // the connectors from front to end + buffer->Indices.push_back(level + polyCountX - 1 + polyCountXPitch); + buffer->Indices.push_back(level + polyCountX - 1); + buffer->Indices.push_back(level + polyCountX); + + buffer->Indices.push_back(level + polyCountX - 1 + polyCountXPitch); + buffer->Indices.push_back(level + polyCountX); + buffer->Indices.push_back(level + polyCountX + polyCountXPitch); + level += polyCountXPitch; + } + + const u32 polyCountSq = polyCountXPitch * polyCountY; // top point + const u32 polyCountSq1 = polyCountSq + 1; // bottom point + const u32 polyCountSqM1 = (polyCountY - 1) * polyCountXPitch; // last row's first vertex + + for (u32 p2 = 0; p2 < polyCountX - 1; ++p2) + { + // create triangles which are at the top of the sphere + + buffer->Indices.push_back(polyCountSq); + buffer->Indices.push_back(p2 + 1); + buffer->Indices.push_back(p2); + + // create triangles which are at the bottom of the sphere + + buffer->Indices.push_back(polyCountSqM1 + p2); + buffer->Indices.push_back(polyCountSqM1 + p2 + 1); + buffer->Indices.push_back(polyCountSq1); + } + + // create final triangle which is at the top of the sphere + + buffer->Indices.push_back(polyCountSq); + buffer->Indices.push_back(polyCountX); + buffer->Indices.push_back(polyCountX-1); + + // create final triangle which is at the bottom of the sphere + + buffer->Indices.push_back(polyCountSqM1 + polyCountX - 1); + buffer->Indices.push_back(polyCountSqM1); + buffer->Indices.push_back(polyCountSq1); + + // calculate the angle which separates all points in a circle + const f64 AngleX = 2 * core::PI / polyCountX; + const f64 AngleY = core::PI / polyCountY; + + u32 i=0; + f64 axz; + + // we don't start at 0. + + f64 ay = 0;//AngleY / 2; + + buffer->Vertices.set_used((polyCountXPitch * polyCountY) + 2); + for (u32 y = 0; y < polyCountY; ++y) + { + ay += AngleY; + const f64 sinay = sin(ay); + axz = 0; + + // calculate the necessary vertices without the doubled one + for (u32 xz = 0;xz < polyCountX; ++xz) + { + // calculate points position + + const core::vector3df pos(static_cast(radius * cos(axz) * sinay), + static_cast(radius * cos(ay)), + static_cast(radius * sin(axz) * sinay)); + // for spheres the normal is the position + core::vector3df normal(pos); + normal.normalize(); + + // calculate texture coordinates via sphere mapping + // tu is the same on each level, so only calculate once + f32 tu = 0.5f; + if (y==0) + { + if (normal.Y != -1.0f && normal.Y != 1.0f) + tu = static_cast(acos(core::clamp(normal.X/sinay, -1.0, 1.0)) * 0.5 *core::RECIPROCAL_PI64); + if (normal.Z < 0.0f) + tu=1-tu; + } + else + tu = buffer->Vertices[i-polyCountXPitch].TCoords.X; + buffer->Vertices[i] = video::S3DVertex(pos.X, pos.Y, pos.Z, + normal.X, normal.Y, normal.Z, + clr, tu, + static_cast(ay*core::RECIPROCAL_PI64)); + ++i; + axz += AngleX; + } + // This is the doubled vertex on the initial position + buffer->Vertices[i] = video::S3DVertex(buffer->Vertices[i-polyCountX]); + buffer->Vertices[i].TCoords.X=1.0f; + ++i; + } + + // the vertex at the top of the sphere + buffer->Vertices[i] = video::S3DVertex(0.0f,radius,0.0f, 0.0f,1.0f,0.0f, clr, 0.5f, 0.0f); + + // the vertex at the bottom of the sphere + ++i; + buffer->Vertices[i] = video::S3DVertex(0.0f,-radius,0.0f, 0.0f,-1.0f,0.0f, clr, 0.5f, 1.0f); + + // recalculate bounding box + + buffer->BoundingBox.reset(buffer->Vertices[i].Pos); + buffer->BoundingBox.addInternalPoint(buffer->Vertices[i-1].Pos); + buffer->BoundingBox.addInternalPoint(radius,0.0f,0.0f); + buffer->BoundingBox.addInternalPoint(-radius,0.0f,0.0f); + buffer->BoundingBox.addInternalPoint(0.0f,0.0f,radius); + buffer->BoundingBox.addInternalPoint(0.0f,0.0f,-radius); + + SMesh* mesh = new SMesh(); + mesh->addMeshBuffer(buffer); + buffer->drop(); + + mesh->setHardwareMappingHint(EHM_STATIC); + mesh->recalculateBoundingBox(); + return mesh; +} + + +/* A cylinder with proper normals and texture coords */ +IMesh* CGeometryCreator::createCylinderMesh(f32 radius, f32 length, + u32 tesselation, const video::SColor& color, + bool closeTop, f32 oblique, u32 normalType) const +{ + SMeshBuffer* buffer = new SMeshBuffer(); + + const f32 recTesselation = core::reciprocal((f32)tesselation); + const f32 recTesselationHalf = recTesselation * 0.5f; + const f32 angleStep = (core::PI * 2.f ) * recTesselation; + const f32 angleStepHalf = angleStep*0.5f; + + u32 i; + video::S3DVertex v; + v.Color = color; + buffer->Vertices.reallocate(tesselation*4+4+(closeTop?2:1)); + buffer->Indices.reallocate((tesselation*2+1)*(closeTop?12:9)); + f32 tcx = 0.f; + for ( i = 0; i <= tesselation; ++i ) + { + const f32 angle = angleStep * i; + v.Pos.X = radius * cosf(angle); + v.Pos.Y = 0.f; + v.Pos.Z = radius * sinf(angle); + switch (normalType) + { + case 0: v.Normal = v.Pos; break; + case 1: v.Normal = v.Pos; break; + } + v.Normal.normalize(); + v.TCoords.X=tcx; + v.TCoords.Y=0.f; + buffer->Vertices.push_back(v); + + v.Pos.X += oblique; + v.Pos.Y = length; + switch (normalType) + { + case 0: v.Normal = v.Pos; break; + case 1: v.Normal = core::vector3df(v.Pos.X-oblique, 0, v.Pos.Z); break; + } + v.Normal.normalize(); + v.TCoords.Y=1.f; + buffer->Vertices.push_back(v); + + v.Pos.X = radius * cosf(angle + angleStepHalf); + v.Pos.Y = 0.f; + v.Pos.Z = radius * sinf(angle + angleStepHalf); + switch (normalType) + { + case 0: v.Normal = v.Pos; break; + case 1: v.Normal = v.Pos; break; + } + v.Normal.normalize(); + v.TCoords.X=tcx+recTesselationHalf; + v.TCoords.Y=0.f; + buffer->Vertices.push_back(v); + + v.Pos.X += oblique; + v.Pos.Y = length; + switch (normalType) + { + case 0: v.Normal = v.Pos; break; + case 1: v.Normal = core::vector3df(v.Pos.X-oblique, 0, v.Pos.Z); break; + } + v.Normal.normalize(); + v.TCoords.Y=1.f; + buffer->Vertices.push_back(v); + tcx += recTesselation; + } + + // indices for the main hull part + const u32 nonWrappedSize = tesselation* 4; + for (i=0; i != nonWrappedSize; i += 2) + { + buffer->Indices.push_back(i + 2); + buffer->Indices.push_back(i + 0); + buffer->Indices.push_back(i + 1); + + buffer->Indices.push_back(i + 2); + buffer->Indices.push_back(i + 1); + buffer->Indices.push_back(i + 3); + } + + // two closing quads between end and start + buffer->Indices.push_back(0); + buffer->Indices.push_back(i + 0); + buffer->Indices.push_back(i + 1); + + buffer->Indices.push_back(0); + buffer->Indices.push_back(i + 1); + buffer->Indices.push_back(1); + + // close down + v.Pos.X = 0.f; + v.Pos.Y = 0.f; + v.Pos.Z = 0.f; + v.Normal.X = 0.f; + v.Normal.Y = -1.f; + v.Normal.Z = 0.f; + v.TCoords.X = 1.f; + v.TCoords.Y = 1.f; + buffer->Vertices.push_back(v); + + u32 index = buffer->Vertices.size() - 1; + + for ( i = 0; i != nonWrappedSize; i += 2 ) + { + buffer->Indices.push_back(index); + buffer->Indices.push_back(i + 0); + buffer->Indices.push_back(i + 2); + } + + buffer->Indices.push_back(index); + buffer->Indices.push_back(i + 0); + buffer->Indices.push_back(0); + + if (closeTop) + { + // close top + v.Pos.X = oblique; + v.Pos.Y = length; + v.Pos.Z = 0.f; + v.Normal.X = 0.f; + v.Normal.Y = 1.f; + v.Normal.Z = 0.f; + v.TCoords.X = 0.f; + v.TCoords.Y = 0.f; + buffer->Vertices.push_back(v); + + index = buffer->Vertices.size() - 1; + + for ( i = 0; i != nonWrappedSize; i += 2 ) + { + buffer->Indices.push_back(i + 1); + buffer->Indices.push_back(index); + buffer->Indices.push_back(i + 3); + } + + buffer->Indices.push_back(i + 1); + buffer->Indices.push_back(index); + buffer->Indices.push_back(1); + } + + buffer->recalculateBoundingBox(); + SMesh* mesh = new SMesh(); + mesh->addMeshBuffer(buffer); + mesh->setHardwareMappingHint(EHM_STATIC); + mesh->recalculateBoundingBox(); + buffer->drop(); + return mesh; +} + + +/* A cone with proper normals and texture coords */ +IMesh* CGeometryCreator::createConeMesh(f32 radius, f32 length, u32 tesselation, + const video::SColor& colorTop, + const video::SColor& colorBottom, + f32 oblique) const +{ + SMeshBuffer* buffer = new SMeshBuffer(); + + const f32 angleStep = (core::PI * 2.f ) / tesselation; + const f32 angleStepHalf = angleStep*0.5f; + + video::S3DVertex v; + u32 i; + + v.Color = colorTop; + for ( i = 0; i != tesselation; ++i ) + { + f32 angle = angleStep * f32(i); + + v.Pos.X = radius * cosf(angle); + v.Pos.Y = 0.f; + v.Pos.Z = radius * sinf(angle); + v.Normal = v.Pos; + v.Normal.normalize(); + buffer->Vertices.push_back(v); + + angle += angleStepHalf; + v.Pos.X = radius * cosf(angle); + v.Pos.Y = 0.f; + v.Pos.Z = radius * sinf(angle); + v.Normal = v.Pos; + v.Normal.normalize(); + buffer->Vertices.push_back(v); + } + const u32 nonWrappedSize = buffer->Vertices.size() - 1; + + // close top + v.Pos.X = oblique; + v.Pos.Y = length; + v.Pos.Z = 0.f; + v.Normal.X = 0.f; + v.Normal.Y = 1.f; + v.Normal.Z = 0.f; + buffer->Vertices.push_back(v); + + u32 index = buffer->Vertices.size() - 1; + + for ( i = 0; i != nonWrappedSize; i += 1 ) + { + buffer->Indices.push_back(i + 0); + buffer->Indices.push_back(index); + buffer->Indices.push_back(i + 1); + } + + buffer->Indices.push_back(i + 0); + buffer->Indices.push_back(index); + buffer->Indices.push_back(0); + + // close down + v.Color = colorBottom; + v.Pos.X = 0.f; + v.Pos.Y = 0.f; + v.Pos.Z = 0.f; + v.Normal.X = 0.f; + v.Normal.Y = -1.f; + v.Normal.Z = 0.f; + buffer->Vertices.push_back(v); + + index = buffer->Vertices.size() - 1; + + for ( i = 0; i != nonWrappedSize; i += 1 ) + { + buffer->Indices.push_back(index); + buffer->Indices.push_back(i + 0); + buffer->Indices.push_back(i + 1); + } + + buffer->Indices.push_back(index); + buffer->Indices.push_back(i + 0); + buffer->Indices.push_back(0); + + buffer->recalculateBoundingBox(); + SMesh* mesh = new SMesh(); + mesh->addMeshBuffer(buffer); + buffer->drop(); + + mesh->setHardwareMappingHint(EHM_STATIC); + mesh->recalculateBoundingBox(); + return mesh; +} + + +void CGeometryCreator::addToBuffer(const video::S3DVertex& v, SMeshBuffer* Buffer) const +{ + const s32 tnidx = Buffer->Vertices.linear_reverse_search(v); + const bool alreadyIn = (tnidx != -1); + u16 nidx = (u16)tnidx; + if (!alreadyIn) + { + nidx = (u16)Buffer->Vertices.size(); + Buffer->Indices.push_back(nidx); + Buffer->Vertices.push_back(v); + } + else + Buffer->Indices.push_back(nidx); +} + + +IMesh* CGeometryCreator::createVolumeLightMesh( + const u32 subdivideU, const u32 subdivideV, + const video::SColor footColor, const video::SColor tailColor, + const f32 lpDistance, const core::vector3df& lightDim) const +{ + SMeshBuffer* Buffer = new SMeshBuffer(); + Buffer->setHardwareMappingHint(EHM_STATIC); + + const core::vector3df lightPoint(0, -(lpDistance*lightDim.Y), 0); + const f32 ax = lightDim.X * 0.5f; // X Axis + const f32 az = lightDim.Z * 0.5f; // Z Axis + + Buffer->Vertices.clear(); + Buffer->Vertices.reallocate(6+12*(subdivideU+subdivideV)); + Buffer->Indices.clear(); + Buffer->Indices.reallocate(6+12*(subdivideU+subdivideV)); + //draw the bottom foot.. the glowing region + addToBuffer(video::S3DVertex(-ax, 0, az, 0,0,0, footColor, 0, 1),Buffer); + addToBuffer(video::S3DVertex( ax, 0, az, 0,0,0, footColor, 1, 1),Buffer); + addToBuffer(video::S3DVertex( ax, 0,-az, 0,0,0, footColor, 1, 0),Buffer); + + addToBuffer(video::S3DVertex( ax, 0,-az, 0,0,0, footColor, 1, 0),Buffer); + addToBuffer(video::S3DVertex(-ax, 0,-az, 0,0,0, footColor, 0, 0),Buffer); + addToBuffer(video::S3DVertex(-ax, 0, az, 0,0,0, footColor, 0, 1),Buffer); + + f32 tu = 0.f; + const f32 tuStep = 1.f/subdivideU; + f32 bx = -ax; + const f32 bxStep = lightDim.X * tuStep; + // Slices in X/U space + for (u32 i = 0; i <= subdivideU; ++i) + { + // These are the two endpoints for a slice at the foot + core::vector3df end1(bx, 0.0f, -az); + core::vector3df end2(bx, 0.0f, az); + + end1 -= lightPoint; // get a vector from point to lightsource + end1.normalize(); // normalize vector + end1 *= lightDim.Y; // multiply it out by shootlength + + end1.X += bx; // Add the original point location to the vector + end1.Z -= az; + + // Do it again for the other point. + end2 -= lightPoint; + end2.normalize(); + end2 *= lightDim.Y; + + end2.X += bx; + end2.Z += az; + + addToBuffer(video::S3DVertex(bx , 0, az, 0,0,0, footColor, tu, 1),Buffer); + addToBuffer(video::S3DVertex(bx , 0, -az, 0,0,0, footColor, tu, 0),Buffer); + addToBuffer(video::S3DVertex(end2.X , end2.Y, end2.Z, 0,0,0, tailColor, tu, 1),Buffer); + + addToBuffer(video::S3DVertex(bx , 0, -az, 0,0,0, footColor, tu, 0),Buffer); + addToBuffer(video::S3DVertex(end1.X , end1.Y, end1.Z, 0,0,0, tailColor, tu, 0),Buffer); + addToBuffer(video::S3DVertex(end2.X , end2.Y, end2.Z, 0,0,0, tailColor, tu, 1),Buffer); + + //back side + addToBuffer(video::S3DVertex(-end2.X , end2.Y, -end2.Z, 0,0,0, tailColor, tu, 1),Buffer); + addToBuffer(video::S3DVertex(-bx , 0, -az, 0,0,0, footColor, tu, 1),Buffer); + addToBuffer(video::S3DVertex(-bx , 0, az, 0,0,0, footColor, tu, 0),Buffer); + + addToBuffer(video::S3DVertex(-bx , 0, az, 0,0,0, footColor, tu, 0),Buffer); + addToBuffer(video::S3DVertex(-end1.X , end1.Y, -end1.Z, 0,0,0, tailColor, tu, 0),Buffer); + addToBuffer(video::S3DVertex(-end2.X , end2.Y, -end2.Z, 0,0,0, tailColor, tu, 1),Buffer); + tu += tuStep; + bx += bxStep; + } + + f32 tv = 0.f; + const f32 tvStep = 1.f/subdivideV; + f32 bz = -az; + const f32 bzStep = lightDim.Z * tvStep; + // Slices in Z/V space + for(u32 i = 0; i <= subdivideV; ++i) + { + // These are the two endpoints for a slice at the foot + core::vector3df end1(-ax, 0.0f, bz); + core::vector3df end2(ax, 0.0f, bz); + + end1 -= lightPoint; // get a vector from point to lightsource + end1.normalize(); // normalize vector + end1 *= lightDim.Y; // multiply it out by shootlength + + end1.X -= ax; // Add the original point location to the vector + end1.Z += bz; + + // Do it again for the other point. + end2 -= lightPoint; + end2.normalize(); + end2 *= lightDim.Y; + + end2.X += ax; + end2.Z += bz; + + addToBuffer(video::S3DVertex(-ax , 0, bz, 0,0,0, footColor, 0, tv),Buffer); + addToBuffer(video::S3DVertex(ax , 0, bz, 0,0,0, footColor, 1, tv),Buffer); + addToBuffer(video::S3DVertex(end2.X , end2.Y, end2.Z, 0,0,0, tailColor, 1, tv),Buffer); + + addToBuffer(video::S3DVertex(end2.X , end2.Y, end2.Z, 0,0,0, tailColor, 1, tv),Buffer); + addToBuffer(video::S3DVertex(end1.X , end1.Y, end1.Z, 0,0,0, tailColor, 0, tv),Buffer); + addToBuffer(video::S3DVertex(-ax , 0, bz, 0,0,0, footColor, 0, tv),Buffer); + + //back side + addToBuffer(video::S3DVertex(ax , 0, -bz, 0,0,0, footColor, 0, tv),Buffer); + addToBuffer(video::S3DVertex(-ax , 0, -bz, 0,0,0, footColor, 1, tv),Buffer); + addToBuffer(video::S3DVertex(-end2.X , end2.Y, -end2.Z, 0,0,0, tailColor, 1, tv),Buffer); + + addToBuffer(video::S3DVertex(-end2.X , end2.Y, -end2.Z, 0,0,0, tailColor, 1, tv),Buffer); + addToBuffer(video::S3DVertex(-end1.X , end1.Y, -end1.Z, 0,0,0, tailColor, 0, tv),Buffer); + addToBuffer(video::S3DVertex(ax , 0, -bz, 0,0,0, footColor, 0, tv),Buffer); + tv += tvStep; + bz += bzStep; + } + + Buffer->recalculateBoundingBox(); + + Buffer->Material.MaterialType = video::EMT_ONETEXTURE_BLEND; + Buffer->Material.MaterialTypeParam = pack_textureBlendFunc( video::EBF_SRC_COLOR, video::EBF_SRC_ALPHA, video::EMFN_MODULATE_1X ); + + Buffer->Material.Lighting = false; + Buffer->Material.ZWriteEnable = video::EZW_OFF; + + Buffer->setDirty(EBT_VERTEX_AND_INDEX); + + Buffer->recalculateBoundingBox(); + SMesh* mesh = new SMesh(); + mesh->addMeshBuffer(Buffer); + Buffer->drop(); + + mesh->recalculateBoundingBox(); + return mesh; +} + + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CGeometryCreator.h b/source/Irrlicht/CGeometryCreator.h new file mode 100644 index 00000000..4c918bdc --- /dev/null +++ b/source/Irrlicht/CGeometryCreator.h @@ -0,0 +1,67 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GEOMETRY_CREATOR_H_INCLUDED__ +#define __C_GEOMETRY_CREATOR_H_INCLUDED__ + +#include "IGeometryCreator.h" +#include "SMeshBuffer.h" + +namespace irr +{ + +namespace scene +{ + +//! class for creating geometry on the fly +class CGeometryCreator : public IGeometryCreator +{ + void addToBuffer(const video::S3DVertex& v, SMeshBuffer* Buffer) const; +public: + virtual IMesh* createCubeMesh(const core::vector3df& size, ECUBE_MESH_TYPE type) const _IRR_OVERRIDE_; + + virtual IMesh* createHillPlaneMesh( + const core::dimension2d& tileSize, const core::dimension2d& tileCount, + video::SMaterial* material, f32 hillHeight, const core::dimension2d& countHills, + const core::dimension2d& textureRepeatCount) const _IRR_OVERRIDE_; + + virtual IMesh* createGeoplaneMesh(f32 radius, u32 rows, u32 columns) const _IRR_OVERRIDE_; + + virtual IMesh* createTerrainMesh(video::IImage* texture, + video::IImage* heightmap, const core::dimension2d& stretchSize, + f32 maxHeight, video::IVideoDriver* driver, + const core::dimension2d& defaultVertexBlockSize, + bool debugBorders=false) const _IRR_OVERRIDE_; + + virtual IMesh* createArrowMesh(const u32 tesselationCylinder, + const u32 tesselationCone, const f32 height, + const f32 cylinderHeight, const f32 width0, + const f32 width1, const video::SColor vtxColor0, + const video::SColor vtxColor1) const _IRR_OVERRIDE_; + + virtual IMesh* createSphereMesh(f32 radius, u32 polyCountX, u32 polyCountY) const _IRR_OVERRIDE_; + + virtual IMesh* createCylinderMesh(f32 radius, f32 length, u32 tesselation, + const video::SColor& color=0xffffffff, + bool closeTop=true, f32 oblique=0.f, u32 normalType=0) const _IRR_OVERRIDE_; + + virtual IMesh* createConeMesh(f32 radius, f32 length, u32 tesselation, + const video::SColor& colorTop=0xffffffff, + const video::SColor& colorBottom=0xffffffff, + f32 oblique=0.f) const _IRR_OVERRIDE_; + + virtual IMesh* createVolumeLightMesh( + const u32 subdivideU=32, const u32 subdivideV=32, + const video::SColor footColor=0xffffffff, + const video::SColor tailColor=0xffffffff, + const f32 lpDistance = 8.f, + const core::vector3df& lightDim = core::vector3df(1.f,1.2f,1.f)) const _IRR_OVERRIDE_; +}; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CImage.cpp b/source/Irrlicht/CImage.cpp new file mode 100644 index 00000000..f21b76f3 --- /dev/null +++ b/source/Irrlicht/CImage.cpp @@ -0,0 +1,384 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CImage.h" +#include "irrString.h" +#include "CColorConverter.h" +#include "CBlit.h" +#include "os.h" + +namespace irr +{ +namespace video +{ + +//! Constructor from raw data +CImage::CImage(ECOLOR_FORMAT format, const core::dimension2d& size, void* data, + bool ownForeignMemory, bool deleteMemory) : IImage(format, size, deleteMemory) +{ + if (ownForeignMemory) + { + Data = (u8*)data; + } + else + { + const u32 dataSize = getDataSizeFromFormat(Format, Size.Width, Size.Height); + + Data = new u8[dataSize]; + memcpy(Data, data, dataSize); + DeleteMemory = true; + } +} + + +//! Constructor of empty image +CImage::CImage(ECOLOR_FORMAT format, const core::dimension2d& size) : IImage(format, size, true) +{ + Data = new u8[getDataSizeFromFormat(Format, Size.Width, Size.Height)]; + DeleteMemory = true; +} + + +//! sets a pixel +void CImage::setPixel(u32 x, u32 y, const SColor &color, bool blend) +{ + if (IImage::isCompressedFormat(Format)) + { + os::Printer::log("IImage::setPixel method doesn't work with compressed images.", ELL_WARNING); + return; + } + + if (x >= Size.Width || y >= Size.Height) + return; + + switch(Format) + { + case ECF_A1R5G5B5: + { + u16 * dest = (u16*) (Data + ( y * Pitch ) + ( x << 1 )); + *dest = video::A8R8G8B8toA1R5G5B5( color.color ); + } break; + + case ECF_R5G6B5: + { + u16 * dest = (u16*) (Data + ( y * Pitch ) + ( x << 1 )); + *dest = video::A8R8G8B8toR5G6B5( color.color ); + } break; + + case ECF_R8G8B8: + { + u8* dest = Data + ( y * Pitch ) + ( x * 3 ); + dest[0] = (u8)color.getRed(); + dest[1] = (u8)color.getGreen(); + dest[2] = (u8)color.getBlue(); + } break; + + case ECF_A8R8G8B8: + { + u32 * dest = (u32*) (Data + ( y * Pitch ) + ( x << 2 )); + *dest = blend ? PixelBlend32 ( *dest, color.color ) : color.color; + } break; + default: + break; + } +} + + +//! returns a pixel +SColor CImage::getPixel(u32 x, u32 y) const +{ + if (IImage::isCompressedFormat(Format)) + { + os::Printer::log("IImage::getPixel method doesn't work with compressed images.", ELL_WARNING); + return SColor(0); + } + + if (x >= Size.Width || y >= Size.Height) + return SColor(0); + + switch(Format) + { + case ECF_A1R5G5B5: + return A1R5G5B5toA8R8G8B8(((u16*)Data)[y*Size.Width + x]); + case ECF_R5G6B5: + return R5G6B5toA8R8G8B8(((u16*)Data)[y*Size.Width + x]); + case ECF_A8R8G8B8: + return ((u32*)Data)[y*Size.Width + x]; + case ECF_R8G8B8: + { + u8* p = Data+(y*3)*Size.Width + (x*3); + return SColor(255,p[0],p[1],p[2]); + } + default: + break; + } + + return SColor(0); +} + + +//! copies this surface into another at given position +void CImage::copyTo(IImage* target, const core::position2d& pos) +{ + if (IImage::isCompressedFormat(Format)) + { + os::Printer::log("IImage::copyTo method doesn't work with compressed images.", ELL_WARNING); + return; + } + + if ( !Blit(BLITTER_TEXTURE, target, 0, &pos, this, 0, 0) + && target && pos.X == 0 && pos.Y == 0 && + CColorConverter::canConvertFormat(Format, target->getColorFormat()) ) + { + // No fast blitting, but copyToScaling uses other color conversions and might work + irr::core::dimension2du dim(target->getDimension()); + copyToScaling(target->getData(), dim.Width, dim.Height, target->getColorFormat(), target->getPitch()); + } +} + + +//! copies this surface partially into another at given position +void CImage::copyTo(IImage* target, const core::position2d& pos, const core::rect& sourceRect, const core::rect* clipRect) +{ + if (IImage::isCompressedFormat(Format)) + { + os::Printer::log("IImage::copyTo method doesn't work with compressed images.", ELL_WARNING); + return; + } + + Blit(BLITTER_TEXTURE, target, clipRect, &pos, this, &sourceRect, 0); +} + + +//! copies this surface into another, using the alpha mask, a cliprect and a color to add with +void CImage::copyToWithAlpha(IImage* target, const core::position2d& pos, const core::rect& sourceRect, const SColor &color, const core::rect* clipRect, bool combineAlpha) +{ + if (IImage::isCompressedFormat(Format)) + { + os::Printer::log("IImage::copyToWithAlpha method doesn't work with compressed images.", ELL_WARNING); + return; + } + + if ( combineAlpha ) + { + Blit(BLITTER_TEXTURE_COMBINE_ALPHA, target, clipRect, &pos, this, &sourceRect, color.color); + } + else + { + // color blend only necessary on not full spectrum aka. color.color != 0xFFFFFFFF + Blit(color.color == 0xFFFFFFFF ? BLITTER_TEXTURE_ALPHA_BLEND: BLITTER_TEXTURE_ALPHA_COLOR_BLEND, + target, clipRect, &pos, this, &sourceRect, color.color); + } +} + + +//! copies this surface into another, scaling it to the target image size +// note: this is very very slow. +void CImage::copyToScaling(void* target, u32 width, u32 height, ECOLOR_FORMAT format, u32 pitch) +{ + if (IImage::isCompressedFormat(Format)) + { + os::Printer::log("IImage::copyToScaling method doesn't work with compressed images.", ELL_WARNING); + return; + } + + if (!target || !width || !height) + return; + + const u32 bpp=getBitsPerPixelFromFormat(format)/8; + if (0==pitch) + pitch = width*bpp; + + if (Format==format && Size.Width==width && Size.Height==height) + { + if (pitch==Pitch) + { + memcpy(target, Data, height*pitch); + return; + } + else + { + u8* tgtpos = (u8*) target; + u8* srcpos = Data; + const u32 bwidth = width*bpp; + const u32 rest = pitch-bwidth; + for (u32 y=0; y& targetSize = target->getDimension(); + + if (targetSize==Size) + { + copyTo(target); + return; + } + + copyToScaling(target->getData(), targetSize.Width, targetSize.Height, target->getColorFormat()); +} + + +//! copies this surface into another, scaling it to fit it. +void CImage::copyToScalingBoxFilter(IImage* target, s32 bias, bool blend) +{ + if (IImage::isCompressedFormat(Format)) + { + os::Printer::log("IImage::copyToScalingBoxFilter method doesn't work with compressed images.", ELL_WARNING); + return; + } + + const core::dimension2d destSize = target->getDimension(); + + const f32 sourceXStep = (f32) Size.Width / (f32) destSize.Width; + const f32 sourceYStep = (f32) Size.Height / (f32) destSize.Height; + + target->getData(); + + s32 fx = core::ceil32( sourceXStep ); + s32 fy = core::ceil32( sourceYStep ); + f32 sx; + f32 sy; + + sy = 0.f; + for ( u32 y = 0; y != destSize.Height; ++y ) + { + sx = 0.f; + for ( u32 x = 0; x != destSize.Width; ++x ) + { + target->setPixel( x, y, + getPixelBox( core::floor32(sx), core::floor32(sy), fx, fy, bias ), blend ); + sx += sourceXStep; + } + sy += sourceYStep; + } +} + + +//! fills the surface with given color +void CImage::fill(const SColor &color) +{ + if (IImage::isCompressedFormat(Format)) + { + os::Printer::log("IImage::fill method doesn't work with compressed images.", ELL_WARNING); + return; + } + + u32 c; + + switch ( Format ) + { + case ECF_A1R5G5B5: + c = color.toA1R5G5B5(); + c |= c << 16; + break; + case ECF_R5G6B5: + c = video::A8R8G8B8toR5G6B5( color.color ); + c |= c << 16; + break; + case ECF_A8R8G8B8: + c = color.color; + break; + case ECF_R8G8B8: + { + u8 rgb[3]; + CColorConverter::convert_A8R8G8B8toR8G8B8(&color, 1, rgb); + const u32 size = getImageDataSizeInBytes(); + for (u32 i=0; i> sdiv ) + bias, 0, 255 ); + r = core::s32_clamp( ( r >> sdiv ) + bias, 0, 255 ); + g = core::s32_clamp( ( g >> sdiv ) + bias, 0, 255 ); + b = core::s32_clamp( ( b >> sdiv ) + bias, 0, 255 ); + + c.set( a, r, g, b ); + return c; +} + + +} // end namespace video +} // end namespace irr diff --git a/source/Irrlicht/CImage.h b/source/Irrlicht/CImage.h new file mode 100644 index 00000000..0662ff5f --- /dev/null +++ b/source/Irrlicht/CImage.h @@ -0,0 +1,70 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_IMAGE_H_INCLUDED__ +#define __C_IMAGE_H_INCLUDED__ + +#include "IImage.h" +#include "rect.h" + +namespace irr +{ +namespace video +{ + +//! IImage implementation with a lot of special image operations for +//! 16 bit A1R5G5B5/32 Bit A8R8G8B8 images, which are used by the SoftwareDevice. +class CImage : public IImage +{ +public: + + //! constructor from raw image data + /** \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, void* data, + bool ownForeignMemory = true, bool deleteMemory = true); + + //! constructor for empty image + CImage(ECOLOR_FORMAT format, const core::dimension2d& size); + + //! returns a pixel + virtual SColor getPixel(u32 x, u32 y) const _IRR_OVERRIDE_; + + //! sets a pixel + virtual void setPixel(u32 x, u32 y, const SColor &color, bool blend = false ) _IRR_OVERRIDE_; + + //! copies this surface into another, scaling it to fit. + virtual void copyToScaling(void* target, u32 width, u32 height, ECOLOR_FORMAT format, u32 pitch=0) _IRR_OVERRIDE_; + + //! copies this surface into another, scaling it to fit. + virtual void copyToScaling(IImage* target) _IRR_OVERRIDE_; + + //! copies this surface into another + virtual void copyTo(IImage* target, const core::position2d& pos=core::position2d(0,0)) _IRR_OVERRIDE_; + + //! copies this surface into another + virtual void copyTo(IImage* target, const core::position2d& pos, const core::rect& sourceRect, const core::rect* clipRect=0) _IRR_OVERRIDE_; + + //! copies this surface into another, using the alpha mask, an cliprect and a color to add with + virtual void copyToWithAlpha(IImage* target, const core::position2d& pos, + const core::rect& sourceRect, const SColor &color, + const core::rect* clipRect = 0, bool combineAlpha=false) _IRR_OVERRIDE_; + + //! copies this surface into another, scaling it to fit, applying a box filter + virtual void copyToScalingBoxFilter(IImage* target, s32 bias = 0, bool blend = false) _IRR_OVERRIDE_; + + //! fills the surface with given color + virtual void fill(const SColor &color) _IRR_OVERRIDE_; + +private: + inline SColor getPixelBox ( s32 x, s32 y, s32 fx, s32 fy, s32 bias ) const; +}; + +} // end namespace video +} // end namespace irr + + +#endif + diff --git a/source/Irrlicht/CImageLoaderBMP.cpp b/source/Irrlicht/CImageLoaderBMP.cpp new file mode 100644 index 00000000..675212b1 --- /dev/null +++ b/source/Irrlicht/CImageLoaderBMP.cpp @@ -0,0 +1,370 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CImageLoaderBMP.h" + +#ifdef _IRR_COMPILE_WITH_BMP_LOADER_ + +#include "IReadFile.h" +#include "SColor.h" +#include "CColorConverter.h" +#include "CImage.h" +#include "os.h" +#include "irrString.h" + +namespace irr +{ +namespace video +{ + + +//! constructor +CImageLoaderBMP::CImageLoaderBMP() +{ + #ifdef _DEBUG + setDebugName("CImageLoaderBMP"); + #endif +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".tga") +bool CImageLoaderBMP::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "bmp" ); +} + + +//! returns true if the file maybe is able to be loaded by this class +bool CImageLoaderBMP::isALoadableFileFormat(io::IReadFile* file) const +{ + u16 headerID; + file->read(&headerID, sizeof(u16)); +#ifdef __BIG_ENDIAN__ + headerID = os::Byteswap::byteswap(headerID); +#endif + return headerID == 0x4d42; +} + + +void CImageLoaderBMP::decompress8BitRLE(u8*& bmpData, s32 size, s32 width, s32 height, s32 pitch) const +{ + u8* p = bmpData; + u8* newBmp = new u8[(width+pitch)*height]; + u8* d = newBmp; + u8* destEnd = newBmp + (width+pitch)*height; + s32 line = 0; + + while (bmpData - p < size && d < destEnd) + { + if (*p == 0) + { + ++p; + + switch(*p) + { + case 0: // end of line + ++p; + ++line; + d = newBmp + (line*(width+pitch)); + break; + case 1: // end of bmp + delete [] bmpData; + bmpData = newBmp; + return; + case 2: + ++p; d +=(u8)*p; // delta + ++p; d += ((u8)*p)*(width+pitch); + ++p; + break; + default: + { + // absolute mode + s32 count = (u8)*p; ++p; + s32 readAdditional = ((2-(count%2))%2); + s32 i; + + for (i=0; i> readShift) & 0x0f; + readShift -= 4; + if (readShift < 0) + { + ++*p; + readShift = 4; + } + + u8 mask = 0x0f << shift; + *d = (*d & (~mask)) | ((color << shift) & mask); + + shift -= 4; + if (shift < 0) + { + shift = 4; + ++d; + } + + } + + for (i=0; i> 4) & 0x0f; + ++p; + + for (s32 i=0; iread(&header, sizeof(header)); + +#ifdef __BIG_ENDIAN__ + header.Id = os::Byteswap::byteswap(header.Id); + header.FileSize = os::Byteswap::byteswap(header.FileSize); + header.BitmapDataOffset = os::Byteswap::byteswap(header.BitmapDataOffset); + header.BitmapHeaderSize = os::Byteswap::byteswap(header.BitmapHeaderSize); + header.Width = os::Byteswap::byteswap(header.Width); + header.Height = os::Byteswap::byteswap(header.Height); + header.Planes = os::Byteswap::byteswap(header.Planes); + header.BPP = os::Byteswap::byteswap(header.BPP); + header.Compression = os::Byteswap::byteswap(header.Compression); + header.BitmapDataSize = os::Byteswap::byteswap(header.BitmapDataSize); + header.PixelPerMeterX = os::Byteswap::byteswap(header.PixelPerMeterX); + header.PixelPerMeterY = os::Byteswap::byteswap(header.PixelPerMeterY); + header.Colors = os::Byteswap::byteswap(header.Colors); + header.ImportantColors = os::Byteswap::byteswap(header.ImportantColors); +#endif + + s32 pitch = 0; + + //! return if the header is false + + if (header.Id != 0x4d42) + return 0; + + if (header.Compression > 2) // we'll only handle RLE-Compression + { + os::Printer::log("Compression mode not supported.", ELL_ERROR); + return 0; + } + + // adjust bitmap data size to dword boundary + header.BitmapDataSize += (4-(header.BitmapDataSize%4))%4; + + // read palette + + long pos = file->getPos(); + s32 paletteSize = (header.BitmapDataOffset - pos) / 4; + + s32* paletteData = 0; + if (paletteSize) + { + paletteData = new s32[paletteSize]; + file->read(paletteData, paletteSize * sizeof(s32)); +#ifdef __BIG_ENDIAN__ + for (s32 i=0; i(file->getSize()) - header.BitmapDataOffset; + } + + file->seek(header.BitmapDataOffset); + + f32 t = (header.Width) * (header.BPP / 8.0f); + s32 widthInBytes = (s32)t; + t -= widthInBytes; + if (t!=0.0f) + ++widthInBytes; + + s32 lineData = widthInBytes + ((4-(widthInBytes%4)))%4; + pitch = lineData - widthInBytes; + + u8* bmpData = new u8[header.BitmapDataSize]; + file->read(bmpData, header.BitmapDataSize); + + // decompress data if needed + switch(header.Compression) + { + case 1: // 8 bit rle + decompress8BitRLE(bmpData, header.BitmapDataSize, header.Width, header.Height, pitch); + break; + case 2: // 4 bit rle + decompress4BitRLE(bmpData, header.BitmapDataSize, header.Width, header.Height, pitch); + break; + } + + // create surface + + // no default constructor from packed area! ARM problem! + core::dimension2d dim; + dim.Width = header.Width; + dim.Height = header.Height; + + IImage* image = 0; + switch(header.BPP) + { + case 1: + image = new CImage(ECF_A1R5G5B5, dim); + if (image) + CColorConverter::convert1BitTo16Bit(bmpData, (s16*)image->getData(), header.Width, header.Height, pitch, true); + break; + case 4: + image = new CImage(ECF_A1R5G5B5, dim); + if (image) + CColorConverter::convert4BitTo16Bit(bmpData, (s16*)image->getData(), header.Width, header.Height, paletteData, pitch, true); + break; + case 8: + image = new CImage(ECF_A1R5G5B5, dim); + if (image) + CColorConverter::convert8BitTo16Bit(bmpData, (s16*)image->getData(), header.Width, header.Height, paletteData, pitch, true); + break; + case 16: + image = new CImage(ECF_A1R5G5B5, dim); + if (image) + CColorConverter::convert16BitTo16Bit((s16*)bmpData, (s16*)image->getData(), header.Width, header.Height, pitch, true); + break; + case 24: + image = new CImage(ECF_R8G8B8, dim); + if (image) + CColorConverter::convert24BitTo24Bit(bmpData, (u8*)image->getData(), header.Width, header.Height, pitch, true, true); + break; + case 32: // thx to Reinhard Ostermeier + image = new CImage(ECF_A8R8G8B8, dim); + if (image) + CColorConverter::convert32BitTo32Bit((s32*)bmpData, (s32*)image->getData(), header.Width, header.Height, pitch, true); + break; + }; + + // clean up + + delete [] paletteData; + delete [] bmpData; + + return image; +} + + +//! creates a loader which is able to load windows bitmaps +IImageLoader* createImageLoaderBMP() +{ + return new CImageLoaderBMP; +} + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CImageLoaderBMP.h b/source/Irrlicht/CImageLoaderBMP.h new file mode 100644 index 00000000..f345e1ea --- /dev/null +++ b/source/Irrlicht/CImageLoaderBMP.h @@ -0,0 +1,100 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_IMAGE_LOADER_BMP_H_INCLUDED__ +#define __C_IMAGE_LOADER_BMP_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#include "IImageLoader.h" + + +namespace irr +{ +namespace video +{ + +#if defined(_IRR_COMPILE_WITH_BMP_LOADER_) || defined(_IRR_COMPILE_WITH_BMP_WRITER_) + + +// byte-align structures +#include "irrpack.h" + + struct SBMPHeader + { + u16 Id; // BM - Windows 3.1x, 95, NT, 98, 2000, ME, XP + // BA - OS/2 Bitmap Array + // CI - OS/2 Color Icon + // CP - OS/2 Color Pointer + // IC - OS/2 Icon + // PT - OS/2 Pointer + u32 FileSize; + u32 Reserved; + u32 BitmapDataOffset; + u32 BitmapHeaderSize; // should be 28h for windows bitmaps or + // 0Ch for OS/2 1.x or F0h for OS/2 2.x + u32 Width; + u32 Height; + u16 Planes; + u16 BPP; // 1: Monochrome bitmap + // 4: 16 color bitmap + // 8: 256 color bitmap + // 16: 16bit (high color) bitmap + // 24: 24bit (true color) bitmap + // 32: 32bit (true color) bitmap + + u32 Compression; // 0: none (Also identified by BI_RGB) + // 1: RLE 8-bit / pixel (Also identified by BI_RLE4) + // 2: RLE 4-bit / pixel (Also identified by BI_RLE8) + // 3: Bitfields (Also identified by BI_BITFIELDS) + + u32 BitmapDataSize; // Size of the bitmap data in bytes. This number must be rounded to the next 4 byte boundary. + u32 PixelPerMeterX; + u32 PixelPerMeterY; + u32 Colors; + u32 ImportantColors; + } PACK_STRUCT; + +// Default alignment +#include "irrunpack.h" + +#endif // defined with loader or writer + +#ifdef _IRR_COMPILE_WITH_BMP_LOADER_ + +/*! + Surface Loader for Windows bitmaps +*/ +class CImageLoaderBMP : public IImageLoader +{ +public: + + //! constructor + CImageLoaderBMP(); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".tga") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! returns true if the file maybe is able to be loaded by this class + virtual bool isALoadableFileFormat(io::IReadFile* file) const _IRR_OVERRIDE_; + + //! creates a surface from the file + virtual IImage* loadImage(io::IReadFile* file) const _IRR_OVERRIDE_; + +private: + + void decompress8BitRLE(u8*& BmpData, s32 size, s32 width, s32 height, s32 pitch) const; + + void decompress4BitRLE(u8*& BmpData, s32 size, s32 width, s32 height, s32 pitch) const; +}; + + +#endif // compiled with loader + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CImageLoaderDDS.cpp b/source/Irrlicht/CImageLoaderDDS.cpp new file mode 100644 index 00000000..0a4ab3d7 --- /dev/null +++ b/source/Irrlicht/CImageLoaderDDS.cpp @@ -0,0 +1,887 @@ +// Copyright (C) 2013 Patryk Nadrowski +// Heavily based on the DDS loader implemented by Thomas Alten +// and DDS loader from IrrSpintz implemented by Thomas Ince +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +/* + Based on Code from Copyright (c) 2003 Randy Reddig + Based on code from Nvidia's DDS example: + http://www.nvidia.com/object/dxtc_decompression_code.html + + mainly c to cpp +*/ + +#include "CImageLoaderDDS.h" + +#if defined(_IRR_COMPILE_WITH_DDS_LOADER_) || defined(_IRR_COMPILE_WITH_DDS_DECODER_LOADER_) + +#include "IReadFile.h" +#include "os.h" +#include "CColorConverter.h" +#include "CImage.h" +#include "irrString.h" + +// Header flag values +#define DDSD_CAPS 0x00000001 +#define DDSD_HEIGHT 0x00000002 +#define DDSD_WIDTH 0x00000004 +#define DDSD_PITCH 0x00000008 +#define DDSD_PIXELFORMAT 0x00001000 +#define DDSD_MIPMAPCOUNT 0x00020000 +#define DDSD_LINEARSIZE 0x00080000 +#define DDSD_DEPTH 0x00800000 + +// Pixel format flag values +#define DDPF_ALPHAPIXELS 0x00000001 +#define DDPF_ALPHA 0x00000002 +#define DDPF_FOURCC 0x00000004 +#define DDPF_RGB 0x00000040 +#define DDPF_COMPRESSED 0x00000080 +#define DDPF_LUMINANCE 0x00020000 + +// Caps1 values +#define DDSCAPS1_COMPLEX 0x00000008 +#define DDSCAPS1_TEXTURE 0x00001000 +#define DDSCAPS1_MIPMAP 0x00400000 + +// Caps2 values +#define DDSCAPS2_CUBEMAP 0x00000200 +#define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400 +#define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800 +#define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000 +#define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000 +#define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000 +#define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000 +#define DDSCAPS2_VOLUME 0x00200000 + +namespace irr +{ + +namespace video +{ + +/* +DDSGetInfo() +extracts relevant info from a dds texture, returns 0 on success +*/ +s32 DDSGetInfo(ddsHeader* dds, s32* width, s32* height, eDDSPixelFormat* pf) +{ + /* dummy test */ + if( dds == NULL ) + return -1; + + /* test dds header */ + if( *((s32*) dds->Magic) != *((s32*) "DDS ") ) + return -1; + if( DDSLittleLong( dds->Size ) != 124 ) + return -1; + if( !(DDSLittleLong( dds->Flags ) & DDSD_PIXELFORMAT) ) + return -1; + if( !(DDSLittleLong( dds->Flags ) & DDSD_CAPS) ) + return -1; + + /* extract width and height */ + if( width != NULL ) + *width = DDSLittleLong( dds->Width ); + if( height != NULL ) + *height = DDSLittleLong( dds->Height ); + + /* get pixel format */ + + /* extract fourCC */ + const u32 fourCC = dds->PixelFormat.FourCC; + + /* test it */ + if( fourCC == 0 ) + *pf = DDS_PF_ARGB8888; + else if( fourCC == *((u32*) "DXT1") ) + *pf = DDS_PF_DXT1; + else if( fourCC == *((u32*) "DXT2") ) + *pf = DDS_PF_DXT2; + else if( fourCC == *((u32*) "DXT3") ) + *pf = DDS_PF_DXT3; + else if( fourCC == *((u32*) "DXT4") ) + *pf = DDS_PF_DXT4; + else if( fourCC == *((u32*) "DXT5") ) + *pf = DDS_PF_DXT5; + else + *pf = DDS_PF_UNKNOWN; + + /* return ok */ + return 0; +} + + +#ifdef _IRR_COMPILE_WITH_DDS_DECODER_LOADER_ + +/* +DDSDecompressARGB8888() +decompresses an argb 8888 format texture +*/ +s32 DDSDecompressARGB8888(ddsHeader* dds, u8* data, s32 width, s32 height, u8* pixels) +{ + /* setup */ + u8* in = data; + u8* out = pixels; + + /* walk y */ + for(s32 y = 0; y < height; y++) + { + /* walk x */ + for(s32 x = 0; x < width; x++) + { + *out++ = *in++; + *out++ = *in++; + *out++ = *in++; + *out++ = *in++; + } + } + + /* return ok */ + return 0; +} + + +/*! + DDSGetColorBlockColors() + extracts colors from a dds color block +*/ +void DDSGetColorBlockColors(ddsColorBlock* block, ddsColor colors[4]) +{ + u16 word; + + + /* color 0 */ + word = DDSLittleShort( block->colors[ 0 ] ); + colors[ 0 ].a = 0xff; + + /* extract rgb bits */ + colors[ 0 ].b = (u8) word; + colors[ 0 ].b <<= 3; + colors[ 0 ].b |= (colors[ 0 ].b >> 5); + word >>= 5; + colors[ 0 ].g = (u8) word; + colors[ 0 ].g <<= 2; + colors[ 0 ].g |= (colors[ 0 ].g >> 5); + word >>= 6; + colors[ 0 ].r = (u8) word; + colors[ 0 ].r <<= 3; + colors[ 0 ].r |= (colors[ 0 ].r >> 5); + + /* same for color 1 */ + word = DDSLittleShort( block->colors[ 1 ] ); + colors[ 1 ].a = 0xff; + + /* extract rgb bits */ + colors[ 1 ].b = (u8) word; + colors[ 1 ].b <<= 3; + colors[ 1 ].b |= (colors[ 1 ].b >> 5); + word >>= 5; + colors[ 1 ].g = (u8) word; + colors[ 1 ].g <<= 2; + colors[ 1 ].g |= (colors[ 1 ].g >> 5); + word >>= 6; + colors[ 1 ].r = (u8) word; + colors[ 1 ].r <<= 3; + colors[ 1 ].r |= (colors[ 1 ].r >> 5); + + /* use this for all but the super-freak math method */ + if( block->colors[ 0 ] > block->colors[ 1 ] ) + { + /* four-color block: derive the other two colors. + 00 = color 0, 01 = color 1, 10 = color 2, 11 = color 3 + these two bit codes correspond to the 2-bit fields + stored in the 64-bit block. */ + + word = ((u16) colors[ 0 ].r * 2 + (u16) colors[ 1 ].r ) / 3; + /* no +1 for rounding */ + /* as bits have been shifted to 888 */ + colors[ 2 ].r = (u8) word; + word = ((u16) colors[ 0 ].g * 2 + (u16) colors[ 1 ].g) / 3; + colors[ 2 ].g = (u8) word; + word = ((u16) colors[ 0 ].b * 2 + (u16) colors[ 1 ].b) / 3; + colors[ 2 ].b = (u8) word; + colors[ 2 ].a = 0xff; + + word = ((u16) colors[ 0 ].r + (u16) colors[ 1 ].r * 2) / 3; + colors[ 3 ].r = (u8) word; + word = ((u16) colors[ 0 ].g + (u16) colors[ 1 ].g * 2) / 3; + colors[ 3 ].g = (u8) word; + word = ((u16) colors[ 0 ].b + (u16) colors[ 1 ].b * 2) / 3; + colors[ 3 ].b = (u8) word; + colors[ 3 ].a = 0xff; + } + else + { + /* three-color block: derive the other color. + 00 = color 0, 01 = color 1, 10 = color 2, + 11 = transparent. + These two bit codes correspond to the 2-bit fields + stored in the 64-bit block */ + + word = ((u16) colors[ 0 ].r + (u16) colors[ 1 ].r) / 2; + colors[ 2 ].r = (u8) word; + word = ((u16) colors[ 0 ].g + (u16) colors[ 1 ].g) / 2; + colors[ 2 ].g = (u8) word; + word = ((u16) colors[ 0 ].b + (u16) colors[ 1 ].b) / 2; + colors[ 2 ].b = (u8) word; + colors[ 2 ].a = 0xff; + + /* random color to indicate alpha */ + colors[ 3 ].r = 0x00; + colors[ 3 ].g = 0xff; + colors[ 3 ].b = 0xff; + colors[ 3 ].a = 0x00; + } +} + + +/* +DDSDecodeColorBlock() +decodes a dds color block +fixme: make endian-safe +*/ + +void DDSDecodeColorBlock(u32* pixel, ddsColorBlock* block, s32 width, u32 colors[4]) +{ + s32 r, n; + u32 bits; + u32 masks[] = { 3, 12, 3 << 4, 3 << 6 }; /* bit masks = 00000011, 00001100, 00110000, 11000000 */ + s32 shift[] = { 0, 2, 4, 6 }; + + + /* r steps through lines in y */ + for( r = 0; r < 4; r++, pixel += (width - 4) ) /* no width * 4 as u32 ptr inc will * 4 */ + { + /* width * 4 bytes per pixel per line, each j dxtc row is 4 lines of pixels */ + + /* n steps through pixels */ + for( n = 0; n < 4; n++ ) + { + bits = block->row[ r ] & masks[ n ]; + bits >>= shift[ n ]; + + switch( bits ) + { + case 0: + *pixel = colors[ 0 ]; + pixel++; + break; + + case 1: + *pixel = colors[ 1 ]; + pixel++; + break; + + case 2: + *pixel = colors[ 2 ]; + pixel++; + break; + + case 3: + *pixel = colors[ 3 ]; + pixel++; + break; + + default: + /* invalid */ + pixel++; + break; + } + } + } +} + + +/* +DDSDecodeAlphaExplicit() +decodes a dds explicit alpha block +*/ +void DDSDecodeAlphaExplicit(u32* pixel, ddsAlphaBlockExplicit* alphaBlock, s32 width, u32 alphaZero) +{ + s32 row, pix; + u16 word; + ddsColor color; + + + /* clear color */ + color.r = 0; + color.g = 0; + color.b = 0; + + /* walk rows */ + for( row = 0; row < 4; row++, pixel += (width - 4) ) + { + word = DDSLittleShort( alphaBlock->row[ row ] ); + + /* walk pixels */ + for( pix = 0; pix < 4; pix++ ) + { + /* zero the alpha bits of image pixel */ + *pixel &= alphaZero; + color.a = word & 0x000F; + color.a = color.a | (color.a << 4); + *pixel |= *((u32*) &color); + word >>= 4; /* move next bits to lowest 4 */ + pixel++; /* move to next pixel in the row */ + } + } +} + + + +/* +DDSDecodeAlpha3BitLinear() +decodes interpolated alpha block +*/ +void DDSDecodeAlpha3BitLinear(u32* pixel, ddsAlphaBlock3BitLinear* alphaBlock, s32 width, u32 alphaZero) +{ + + s32 row, pix; + u32 stuff; + u8 bits[ 4 ][ 4 ]; + u16 alphas[ 8 ]; + ddsColor aColors[ 4 ][ 4 ]; + + /* get initial alphas */ + alphas[ 0 ] = alphaBlock->alpha0; + alphas[ 1 ] = alphaBlock->alpha1; + + /* 8-alpha block */ + if( alphas[ 0 ] > alphas[ 1 ] ) + { + /* 000 = alpha_0, 001 = alpha_1, others are interpolated */ + alphas[ 2 ] = ( 6 * alphas[ 0 ] + alphas[ 1 ]) / 7; /* bit code 010 */ + alphas[ 3 ] = ( 5 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 7; /* bit code 011 */ + alphas[ 4 ] = ( 4 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 7; /* bit code 100 */ + alphas[ 5 ] = ( 3 * alphas[ 0 ] + 4 * alphas[ 1 ]) / 7; /* bit code 101 */ + alphas[ 6 ] = ( 2 * alphas[ 0 ] + 5 * alphas[ 1 ]) / 7; /* bit code 110 */ + alphas[ 7 ] = ( alphas[ 0 ] + 6 * alphas[ 1 ]) / 7; /* bit code 111 */ + } + + /* 6-alpha block */ + else + { + /* 000 = alpha_0, 001 = alpha_1, others are interpolated */ + alphas[ 2 ] = (4 * alphas[ 0 ] + alphas[ 1 ]) / 5; /* bit code 010 */ + alphas[ 3 ] = (3 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 5; /* bit code 011 */ + alphas[ 4 ] = (2 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 5; /* bit code 100 */ + alphas[ 5 ] = ( alphas[ 0 ] + 4 * alphas[ 1 ]) / 5; /* bit code 101 */ + alphas[ 6 ] = 0; /* bit code 110 */ + alphas[ 7 ] = 255; /* bit code 111 */ + } + + /* decode 3-bit fields into array of 16 bytes with same value */ + + /* first two rows of 4 pixels each */ + stuff = *((u32*) &(alphaBlock->stuff[ 0 ])); + + bits[ 0 ][ 0 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 0 ][ 1 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 0 ][ 2 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 0 ][ 3 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 0 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 1 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 2 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 3 ] = (u8) (stuff & 0x00000007); + + /* last two rows */ + stuff = *((u32*) &(alphaBlock->stuff[ 3 ])); /* last 3 bytes */ + + bits[ 2 ][ 0 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 2 ][ 1 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 2 ][ 2 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 2 ][ 3 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 0 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 1 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 2 ] = (u8) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 3 ] = (u8) (stuff & 0x00000007); + + /* decode the codes into alpha values */ + for( row = 0; row < 4; row++ ) + { + for( pix=0; pix < 4; pix++ ) + { + aColors[ row ][ pix ].r = 0; + aColors[ row ][ pix ].g = 0; + aColors[ row ][ pix ].b = 0; + aColors[ row ][ pix ].a = (u8) alphas[ bits[ row ][ pix ] ]; + } + } + + /* write out alpha values to the image bits */ + for( row = 0; row < 4; row++, pixel += width-4 ) + { + for( pix = 0; pix < 4; pix++ ) + { + /* zero the alpha bits of image pixel */ + *pixel &= alphaZero; + + /* or the bits into the prev. nulled alpha */ + *pixel |= *((u32*) &(aColors[ row ][ pix ])); + pixel++; + } + } +} + + +/* +DDSDecompressDXT1() +decompresses a dxt1 format texture +*/ +s32 DDSDecompressDXT1(ddsHeader* dds, u8* data, s32 width, s32 height, u8* pixels) +{ + s32 x, y, xBlocks, yBlocks; + u32 *pixel; + ddsColorBlock *block; + ddsColor colors[ 4 ]; + + /* setup */ + xBlocks = width / 4; + yBlocks = height / 4; + + /* walk y */ + for( y = 0; y < yBlocks; y++ ) + { + /* 8 bytes per block */ + block = (ddsColorBlock*) (data + y * xBlocks * 8); + + /* walk x */ + for( x = 0; x < xBlocks; x++, block++ ) + { + DDSGetColorBlockColors( block, colors ); + pixel = (u32*) (pixels + x * 16 + (y * 4) * width * 4); + DDSDecodeColorBlock( pixel, block, width, (u32*) colors ); + } + } + + /* return ok */ + return 0; +} + + +/* +DDSDecompressDXT3() +decompresses a dxt3 format texture +*/ + +s32 DDSDecompressDXT3(ddsHeader* dds, u8* data, s32 width, s32 height, u8* pixels) +{ + s32 x, y, xBlocks, yBlocks; + u32 *pixel, alphaZero; + ddsColorBlock *block; + ddsAlphaBlockExplicit *alphaBlock; + ddsColor colors[ 4 ]; + + /* setup */ + xBlocks = width / 4; + yBlocks = height / 4; + + /* create zero alpha */ + colors[ 0 ].a = 0; + colors[ 0 ].r = 0xFF; + colors[ 0 ].g = 0xFF; + colors[ 0 ].b = 0xFF; + alphaZero = *((u32*) &colors[ 0 ]); + + /* walk y */ + for( y = 0; y < yBlocks; y++ ) + { + /* 8 bytes per block, 1 block for alpha, 1 block for color */ + block = (ddsColorBlock*) (data + y * xBlocks * 16); + + /* walk x */ + for( x = 0; x < xBlocks; x++, block++ ) + { + /* get alpha block */ + alphaBlock = (ddsAlphaBlockExplicit*) block; + + /* get color block */ + block++; + DDSGetColorBlockColors( block, colors ); + + /* decode color block */ + pixel = (u32*) (pixels + x * 16 + (y * 4) * width * 4); + DDSDecodeColorBlock( pixel, block, width, (u32*) colors ); + + /* overwrite alpha bits with alpha block */ + DDSDecodeAlphaExplicit( pixel, alphaBlock, width, alphaZero ); + } + } + + /* return ok */ + return 0; +} + + +/* +DDSDecompressDXT5() +decompresses a dxt5 format texture +*/ +s32 DDSDecompressDXT5(ddsHeader* dds, u8* data, s32 width, s32 height, u8* pixels) +{ + s32 x, y, xBlocks, yBlocks; + u32 *pixel, alphaZero; + ddsColorBlock *block; + ddsAlphaBlock3BitLinear *alphaBlock; + ddsColor colors[ 4 ]; + + /* setup */ + xBlocks = width / 4; + yBlocks = height / 4; + + /* create zero alpha */ + colors[ 0 ].a = 0; + colors[ 0 ].r = 0xFF; + colors[ 0 ].g = 0xFF; + colors[ 0 ].b = 0xFF; + alphaZero = *((u32*) &colors[ 0 ]); + + /* walk y */ + for( y = 0; y < yBlocks; y++ ) + { + /* 8 bytes per block, 1 block for alpha, 1 block for color */ + block = (ddsColorBlock*) (data + y * xBlocks * 16); + + /* walk x */ + for( x = 0; x < xBlocks; x++, block++ ) + { + /* get alpha block */ + alphaBlock = (ddsAlphaBlock3BitLinear*) block; + + /* get color block */ + block++; + DDSGetColorBlockColors( block, colors ); + + /* decode color block */ + pixel = (u32*) (pixels + x * 16 + (y * 4) * width * 4); + DDSDecodeColorBlock( pixel, block, width, (u32*) colors ); + + /* overwrite alpha bits with alpha block */ + DDSDecodeAlpha3BitLinear( pixel, alphaBlock, width, alphaZero ); + } + } + + /* return ok */ + return 0; +} + + +/* +DDSDecompressDXT2() +decompresses a dxt2 format texture (fixme: un-premultiply alpha) +*/ +s32 DDSDecompressDXT2(ddsHeader* dds, u8* data, s32 width, s32 height, u8* pixels) +{ + /* decompress dxt3 first */ + const s32 r = DDSDecompressDXT3( dds, data, width, height, pixels ); + + /* return to sender */ + return r; +} + + +/* +DDSDecompressDXT4() +decompresses a dxt4 format texture (fixme: un-premultiply alpha) +*/ +s32 DDSDecompressDXT4(ddsHeader* dds, u8* data, s32 width, s32 height, u8* pixels) +{ + /* decompress dxt5 first */ + const s32 r = DDSDecompressDXT5( dds, data, width, height, pixels ); + + /* return to sender */ + return r; +} + + +/* +DDSDecompress() +decompresses a dds texture into an rgba image buffer, returns 0 on success +*/ +s32 DDSDecompress(ddsHeader* dds, u8* data, u8* pixels) +{ + s32 width, height; + eDDSPixelFormat pf; + + /* get dds info */ + s32 r = DDSGetInfo( dds, &width, &height, &pf ); + if ( r ) + return r; + + /* decompress */ + switch( pf ) + { + case DDS_PF_ARGB8888: + /* fixme: support other [a]rgb formats */ + r = DDSDecompressARGB8888( dds, data, width, height, pixels ); + break; + + case DDS_PF_DXT1: + r = DDSDecompressDXT1( dds, data, width, height, pixels ); + break; + + case DDS_PF_DXT2: + r = DDSDecompressDXT2( dds, data, width, height, pixels ); + break; + + case DDS_PF_DXT3: + r = DDSDecompressDXT3( dds, data, width, height, pixels ); + break; + + case DDS_PF_DXT4: + r = DDSDecompressDXT4( dds, data, width, height, pixels ); + break; + + case DDS_PF_DXT5: + r = DDSDecompressDXT5( dds, data, width, height, pixels ); + break; + + default: // DDS_PF_UNKNOWN + r = -1; + break; + } + + /* return to sender */ + return r; +} + +#endif + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".tga") +bool CImageLoaderDDS::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension(filename, "dds"); +} + + +//! returns true if the file maybe is able to be loaded by this class +bool CImageLoaderDDS::isALoadableFileFormat(io::IReadFile* file) const +{ + if (!file) + return false; + + c8 MagicWord[4]; + file->read(&MagicWord, 4); + + return (MagicWord[0] == 'D' && MagicWord[1] == 'D' && MagicWord[2] == 'S'); +} + + +//! creates a surface from the file +IImage* CImageLoaderDDS::loadImage(io::IReadFile* file) const +{ + ddsHeader header; + IImage* image = 0; + s32 width, height; + eDDSPixelFormat pixelFormat; + ECOLOR_FORMAT format = ECF_UNKNOWN; + u32 dataSize = 0; + u32 mipMapsDataSize = 0; + bool is3D = false; + bool useAlpha = false; + u32 mipMapCount = 0; + + file->seek(0); + file->read(&header, sizeof(ddsHeader)); + + if (0 == DDSGetInfo(&header, &width, &height, &pixelFormat)) + { + is3D = header.Depth > 0 && (header.Flags & DDSD_DEPTH); + + if (!is3D) + header.Depth = 1; + + useAlpha = header.PixelFormat.Flags & DDPF_ALPHAPIXELS; + + if (header.MipMapCount > 0 && (header.Flags & DDSD_MIPMAPCOUNT)) + mipMapCount = header.MipMapCount; + +#ifdef _IRR_COMPILE_WITH_DDS_DECODER_LOADER_ + u32 newSize = file->getSize() - sizeof(ddsHeader); + u8* memFile = new u8[newSize]; + file->read(memFile, newSize); + + image = new CImage(ECF_A8R8G8B8, core::dimension2d(width, height)); + + if (DDSDecompress(&header, memFile, (u8*)image->lock()) == -1) + { + image->unlock(); + image->drop(); + image = 0; + } + + delete[] memFile; +#else + if (header.PixelFormat.Flags & DDPF_RGB) // Uncompressed formats + { +// u32 byteCount = header.PixelFormat.RGBBitCount / 8; + + if( header.Flags & DDSD_PITCH ) + dataSize = header.PitchOrLinearSize * header.Height * header.Depth * (header.PixelFormat.RGBBitCount / 8); + else + dataSize = header.Width * header.Height * header.Depth * (header.PixelFormat.RGBBitCount / 8); + + u8* data = new u8[dataSize]; + file->read(data, dataSize); + + switch (header.PixelFormat.RGBBitCount) // Bytes per pixel + { + case 16: + { + if (useAlpha) + { + if (header.PixelFormat.ABitMask == 0x8000) + format = ECF_A1R5G5B5; + } + else + { + if (header.PixelFormat.RBitMask == 0xf800) + format = ECF_R5G6B5; + } + + break; + } + case 24: + { + if (!useAlpha) + { + if (header.PixelFormat.RBitMask == 0xff0000) + format = ECF_R8G8B8; + } + + break; + } + case 32: + { + if (useAlpha) + { + if (header.PixelFormat.RBitMask & 0xff0000) + format = ECF_A8R8G8B8; + else if (header.PixelFormat.RBitMask & 0xff) + { + // convert from A8B8G8R8 to A8R8G8B8 + u8 tmp = 0; + + for (u32 i = 0; i < dataSize; i += 4) + { + tmp = data[i]; + data[i] = data[i+2]; + data[i+2] = tmp; + } + } + } + + break; + } + } + + if (format != ECF_UNKNOWN) + { + if (!is3D) // Currently 3D textures are unsupported. + { + image = new CImage(format, core::dimension2d(header.Width, header.Height), data, true, true); + } + } + else + { + delete[] data; + } + } + else if (header.PixelFormat.Flags & DDPF_FOURCC) // Compressed formats + { + switch(pixelFormat) + { + case DDS_PF_DXT1: + { + format = ECF_DXT1; + break; + } + case DDS_PF_DXT2: + case DDS_PF_DXT3: + { + format = ECF_DXT3; + break; + } + case DDS_PF_DXT4: + case DDS_PF_DXT5: + { + format = ECF_DXT5; + break; + } + default: // either not compressed or unknown + break; + } + + if( format != ECF_UNKNOWN ) + { + if (!is3D) // Currently 3D textures are unsupported. + { + dataSize = IImage::getDataSizeFromFormat(format, header.Width, header.Height); + + u8* data = new u8[dataSize]; + file->read(data, dataSize); + + image = new CImage(format, core::dimension2d(header.Width, header.Height), data, true, true); + + if (mipMapCount > 0) + { + u32 tmpWidth = header.Width; + u32 tmpHeight = header.Height; + + do + { + if (tmpWidth > 1) + tmpWidth >>= 1; + + if (tmpHeight > 1) + tmpHeight >>= 1; + + mipMapsDataSize += IImage::getDataSizeFromFormat(format, tmpWidth, tmpHeight); + } + while (tmpWidth != 1 || tmpHeight != 1); + + u8* mipMapsData = new u8[mipMapsDataSize]; + file->read(mipMapsData, mipMapsDataSize); + + image->setMipMapsData(mipMapsData, true, true); + } + } + } + } +#endif + } + + return image; +} + + +//! creates a loader which is able to load dds images +IImageLoader* createImageLoaderDDS() +{ + return new CImageLoaderDDS(); +} + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CImageLoaderDDS.h b/source/Irrlicht/CImageLoaderDDS.h new file mode 100644 index 00000000..4f825397 --- /dev/null +++ b/source/Irrlicht/CImageLoaderDDS.h @@ -0,0 +1,215 @@ +// Copyright (C) 2002-2012 Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_IMAGE_LOADER_DDS_H_INCLUDED__ +#define __C_IMAGE_LOADER_DDS_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#if defined(_IRR_COMPILE_WITH_DDS_LOADER_) || defined(_IRR_COMPILE_WITH_DDS_DECODER_LOADER_) + +#include "IImageLoader.h" + +namespace irr +{ +namespace video +{ + +/* dds pixel format types */ +enum eDDSPixelFormat +{ + DDS_PF_ARGB8888, + DDS_PF_DXT1, + DDS_PF_DXT2, + DDS_PF_DXT3, + DDS_PF_DXT4, + DDS_PF_DXT5, + DDS_PF_UNKNOWN +}; + +// byte-align structures +#include "irrpack.h" + +/* structures */ + +struct ddsPixelFormat +{ + u32 Size; + u32 Flags; + u32 FourCC; + u32 RGBBitCount; + u32 RBitMask; + u32 GBitMask; + u32 BBitMask; + u32 ABitMask; +} PACK_STRUCT; + + +struct ddsCaps +{ + u32 caps1; + u32 caps2; + u32 caps3; + u32 caps4; +} PACK_STRUCT; + + +struct ddsHeader +{ + c8 Magic[4]; + u32 Size; + u32 Flags; + u32 Height; + u32 Width; + u32 PitchOrLinearSize; + u32 Depth; + u32 MipMapCount; + u32 Reserved1[11]; + ddsPixelFormat PixelFormat; + ddsCaps Caps; + u32 Reserved2; +} PACK_STRUCT; + + +#ifdef _IRR_COMPILE_WITH_DDS_DECODER_LOADER_ + +struct ddsColorBlock +{ + u16 colors[ 2 ]; + u8 row[ 4 ]; +} PACK_STRUCT; + + +struct ddsAlphaBlockExplicit +{ + u16 row[ 4 ]; +} PACK_STRUCT; + + +struct ddsAlphaBlock3BitLinear +{ + u8 alpha0; + u8 alpha1; + u8 stuff[ 6 ]; +} PACK_STRUCT; + + +struct ddsColor +{ + u8 r, g, b, a; +} PACK_STRUCT; + +#endif + + +// Default alignment +#include "irrunpack.h" + + +/* endian tomfoolery */ +typedef union +{ + f32 f; + c8 c[ 4 ]; +} +floatSwapUnion; + + +#ifndef __BIG_ENDIAN__ +#ifdef _SGI_SOURCE +#define __BIG_ENDIAN__ +#endif +#endif + + +#ifdef __BIG_ENDIAN__ + + s32 DDSBigLong( s32 src ) { return src; } + s16 DDSBigShort( s16 src ) { return src; } + f32 DDSBigFloat( f32 src ) { return src; } + + s32 DDSLittleLong( s32 src ) + { + return ((src & 0xFF000000) >> 24) | + ((src & 0x00FF0000) >> 8) | + ((src & 0x0000FF00) << 8) | + ((src & 0x000000FF) << 24); + } + + s16 DDSLittleShort( s16 src ) + { + return ((src & 0xFF00) >> 8) | + ((src & 0x00FF) << 8); + } + + f32 DDSLittleFloat( f32 src ) + { + floatSwapUnion in,out; + in.f = src; + out.c[ 0 ] = in.c[ 3 ]; + out.c[ 1 ] = in.c[ 2 ]; + out.c[ 2 ] = in.c[ 1 ]; + out.c[ 3 ] = in.c[ 0 ]; + return out.f; + } + +#else /*__BIG_ENDIAN__*/ + + s32 DDSLittleLong( s32 src ) { return src; } + s16 DDSLittleShort( s16 src ) { return src; } + f32 DDSLittleFloat( f32 src ) { return src; } + + s32 DDSBigLong( s32 src ) + { + return ((src & 0xFF000000) >> 24) | + ((src & 0x00FF0000) >> 8) | + ((src & 0x0000FF00) << 8) | + ((src & 0x000000FF) << 24); + } + + s16 DDSBigShort( s16 src ) + { + return ((src & 0xFF00) >> 8) | + ((src & 0x00FF) << 8); + } + + f32 DDSBigFloat( f32 src ) + { + floatSwapUnion in,out; + in.f = src; + out.c[ 0 ] = in.c[ 3 ]; + out.c[ 1 ] = in.c[ 2 ]; + out.c[ 2 ] = in.c[ 1 ]; + out.c[ 3 ] = in.c[ 0 ]; + return out.f; + } + +#endif /*__BIG_ENDIAN__*/ + + +/*! + Surface Loader for DDS images +*/ +class CImageLoaderDDS : public IImageLoader +{ +public: + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".tga") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! returns true if the file maybe is able to be loaded by this class + virtual bool isALoadableFileFormat(io::IReadFile* file) const _IRR_OVERRIDE_; + + //! creates a surface from the file + virtual IImage* loadImage(io::IReadFile* file) const _IRR_OVERRIDE_; +}; + + +} // end namespace video +} // end namespace irr + +#endif // compiled with DDS loader +#endif + diff --git a/source/Irrlicht/CImageLoaderJPG.cpp b/source/Irrlicht/CImageLoaderJPG.cpp new file mode 100644 index 00000000..6b51bd98 --- /dev/null +++ b/source/Irrlicht/CImageLoaderJPG.cpp @@ -0,0 +1,302 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CImageLoaderJPG.h" + +#ifdef _IRR_COMPILE_WITH_JPG_LOADER_ + +#include "IReadFile.h" +#include "CImage.h" +#include "os.h" +#include "irrString.h" + +namespace irr +{ +namespace video +{ + +#ifdef _IRR_COMPILE_WITH_LIBJPEG_ +// Static members +io::path CImageLoaderJPG::Filename; +#endif + +//! constructor +CImageLoaderJPG::CImageLoaderJPG() +{ + #ifdef _DEBUG + setDebugName("CImageLoaderJPG"); + #endif +} + + + +//! destructor +CImageLoaderJPG::~CImageLoaderJPG() +{ +} + + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".tga") +bool CImageLoaderJPG::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "jpg", "jpeg" ); +} + + +#ifdef _IRR_COMPILE_WITH_LIBJPEG_ + + // struct for handling jpeg errors + struct irr_jpeg_error_mgr + { + // public jpeg error fields + struct jpeg_error_mgr pub; + + // for longjmp, to return to caller on a fatal error + jmp_buf setjmp_buffer; + }; + +void CImageLoaderJPG::init_source (j_decompress_ptr cinfo) +{ + // DO NOTHING +} + + + +boolean CImageLoaderJPG::fill_input_buffer (j_decompress_ptr cinfo) +{ + // DO NOTHING + return TRUE; +} + + + +void CImageLoaderJPG::skip_input_data (j_decompress_ptr cinfo, long count) +{ + jpeg_source_mgr * src = cinfo->src; + if(count > 0) + { + src->bytes_in_buffer -= count; + src->next_input_byte += count; + } +} + + + +void CImageLoaderJPG::term_source (j_decompress_ptr cinfo) +{ + // DO NOTHING +} + + +void CImageLoaderJPG::error_exit (j_common_ptr cinfo) +{ + // unfortunately we need to use a goto rather than throwing an exception + // as gcc crashes under linux crashes when using throw from within + // extern c code + + // Always display the message + (*cinfo->err->output_message) (cinfo); + + // cinfo->err really points to a irr_error_mgr struct + irr_jpeg_error_mgr *myerr = (irr_jpeg_error_mgr*) cinfo->err; + + longjmp(myerr->setjmp_buffer, 1); +} + + +void CImageLoaderJPG::output_message(j_common_ptr cinfo) +{ + // display the error message. + c8 temp1[JMSG_LENGTH_MAX]; + (*cinfo->err->format_message)(cinfo, temp1); + core::stringc errMsg("JPEG FATAL ERROR in "); + errMsg += core::stringc(Filename); + os::Printer::log(errMsg.c_str(),temp1, ELL_ERROR); +} +#endif // _IRR_COMPILE_WITH_LIBJPEG_ + +//! returns true if the file maybe is able to be loaded by this class +bool CImageLoaderJPG::isALoadableFileFormat(io::IReadFile* file) const +{ + #ifndef _IRR_COMPILE_WITH_LIBJPEG_ + return false; + #else + + if (!(file && file->seek(0))) + return false; + unsigned char header[3]; + size_t headerLen = file->read(header, sizeof(header)); + return headerLen >= 3 && !memcmp(header, "\xFF\xD8\xFF", 3); + #endif +} + +//! creates a surface from the file +IImage* CImageLoaderJPG::loadImage(io::IReadFile* file) const +{ + #ifndef _IRR_COMPILE_WITH_LIBJPEG_ + os::Printer::log("Can't load as not compiled with _IRR_COMPILE_WITH_LIBJPEG_:", file->getFileName(), ELL_DEBUG); + return 0; + #else + + if (!file) + return 0; + + Filename = file->getFileName(); + + u8 **rowPtr=0; + u8* input = new u8[file->getSize()]; + file->read(input, file->getSize()); + + // allocate and initialize JPEG decompression object + struct jpeg_decompress_struct cinfo; + struct irr_jpeg_error_mgr jerr; + + //We have to set up the error handler first, in case the initialization + //step fails. (Unlikely, but it could happen if you are out of memory.) + //This routine fills in the contents of struct jerr, and returns jerr's + //address which we place into the link field in cinfo. + + cinfo.err = jpeg_std_error(&jerr.pub); + cinfo.err->error_exit = error_exit; + cinfo.err->output_message = output_message; + + // compatibility fudge: + // we need to use setjmp/longjmp for error handling as gcc-linux + // crashes when throwing within external c code + if (setjmp(jerr.setjmp_buffer)) + { + // If we get here, the JPEG code has signaled an error. + // We need to clean up the JPEG object and return. + + jpeg_destroy_decompress(&cinfo); + + delete [] input; + delete [] rowPtr; + + // return null pointer + return 0; + } + + // Now we can initialize the JPEG decompression object. + jpeg_create_decompress(&cinfo); + + // specify data source + jpeg_source_mgr jsrc; + + // Set up data pointer + jsrc.bytes_in_buffer = file->getSize(); + jsrc.next_input_byte = (JOCTET*)input; + cinfo.src = &jsrc; + + jsrc.init_source = init_source; + jsrc.fill_input_buffer = fill_input_buffer; + jsrc.skip_input_data = skip_input_data; + jsrc.resync_to_restart = jpeg_resync_to_restart; + jsrc.term_source = term_source; + + // Decodes JPG input from whatever source + // Does everything AFTER jpeg_create_decompress + // and BEFORE jpeg_destroy_decompress + // Caller is responsible for arranging these + setting up cinfo + + // read file parameters with jpeg_read_header() + jpeg_read_header(&cinfo, TRUE); + + bool useCMYK=false; + if (cinfo.jpeg_color_space==JCS_CMYK) + { + cinfo.out_color_space=JCS_CMYK; + cinfo.out_color_components=4; + useCMYK=true; + } + else + { + cinfo.out_color_space=JCS_RGB; + cinfo.out_color_components=3; + } + cinfo.output_gamma=2.2; + cinfo.do_fancy_upsampling=FALSE; + + // Start decompressor + jpeg_start_decompress(&cinfo); + + // Get image data + u16 rowspan = cinfo.image_width * cinfo.out_color_components; + u32 width = cinfo.image_width; + u32 height = cinfo.image_height; + + // Allocate memory for buffer + u8* output = new u8[rowspan * height]; + + // Here we use the library's state variable cinfo.output_scanline as the + // loop counter, so that we don't have to keep track ourselves. + // Create array of row pointers for lib + rowPtr = new u8* [height]; + + for( u32 i = 0; i < height; i++ ) + rowPtr[i] = &output[ i * rowspan ]; + + u32 rowsRead = 0; + + while( cinfo.output_scanline < cinfo.output_height ) + rowsRead += jpeg_read_scanlines( &cinfo, &rowPtr[rowsRead], cinfo.output_height - rowsRead ); + + delete [] rowPtr; + // Finish decompression + + jpeg_finish_decompress(&cinfo); + + // Release JPEG decompression object + // This is an important step since it will release a good deal of memory. + jpeg_destroy_decompress(&cinfo); + + // convert image + IImage* image = 0; + if (useCMYK) + { + image = new CImage(ECF_R8G8B8, + core::dimension2d(width, height)); + const u32 size = 3*width*height; + u8* data = (u8*)image->getData(); + if (data) + { + for (u32 i=0,j=0; i(width, height), output); + + delete [] input; + + return image; + + #endif +} + + + +//! creates a loader which is able to load jpeg images +IImageLoader* createImageLoaderJPG() +{ + return new CImageLoaderJPG(); +} + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CImageLoaderJPG.h b/source/Irrlicht/CImageLoaderJPG.h new file mode 100644 index 00000000..1726e264 --- /dev/null +++ b/source/Irrlicht/CImageLoaderJPG.h @@ -0,0 +1,116 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_IMAGE_LOADER_JPG_H_INCLUDED__ +#define __C_IMAGE_LOADER_JPG_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_JPG_LOADER_ + +#include "IImageLoader.h" + +#include // required for jpeglib.h +#ifdef _IRR_COMPILE_WITH_LIBJPEG_ +extern "C" { + #ifndef _IRR_USE_NON_SYSTEM_JPEG_LIB_ + #include // use system lib + #else + #include "jpeglib/jpeglib.h" // use irrlicht jpeglib + #endif + #include +} +#endif // _IRR_COMPILE_WITH_LIBJPEG_ + + +namespace irr +{ +namespace video +{ + + +//! Surface Loader for JPG images +class CImageLoaderJPG : public IImageLoader +{ +public: + + //! constructor + CImageLoaderJPG(); + + //! destructor + virtual ~CImageLoaderJPG(); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".tga") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! returns true if the file maybe is able to be loaded by this class + virtual bool isALoadableFileFormat(io::IReadFile* file) const _IRR_OVERRIDE_; + + //! creates a surface from the file + virtual IImage* loadImage(io::IReadFile* file) const _IRR_OVERRIDE_; + +private: + +#ifdef _IRR_COMPILE_WITH_LIBJPEG_ + // several methods used via function pointers by jpeglib + + /* Receives control for a fatal error. Information sufficient to + generate the error message has been stored in cinfo->err; call + output_message to display it. Control must NOT return to the caller; + generally this routine will exit() or longjmp() somewhere. + Typically you would override this routine to get rid of the exit() + default behavior. Note that if you continue processing, you should + clean up the JPEG object with jpeg_abort() or jpeg_destroy(). + */ + static void error_exit (j_common_ptr cinfo); + + /* output error messages via Irrlicht logger. */ + static void output_message(j_common_ptr cinfo); + + /* Initialize source. This is called by jpeg_read_header() before any + data is actually read. Unlike init_destination(), it may leave + bytes_in_buffer set to 0 (in which case a fill_input_buffer() call + will occur immediately). */ + static void init_source (j_decompress_ptr cinfo); + + /* This is called whenever bytes_in_buffer has reached zero and more + data is wanted. In typical applications, it should read fresh data + into the buffer (ignoring the current state of next_input_byte and + bytes_in_buffer), reset the pointer & count to the start of the + buffer, and return TRUE indicating that the buffer has been reloaded. + It is not necessary to fill the buffer entirely, only to obtain at + least one more byte. bytes_in_buffer MUST be set to a positive value + if TRUE is returned. A FALSE return should only be used when I/O + suspension is desired (this mode is discussed in the next section). */ + static boolean fill_input_buffer (j_decompress_ptr cinfo); + + /* Skip num_bytes worth of data. The buffer pointer and count should + be advanced over num_bytes input bytes, refilling the buffer as + needed. This is used to skip over a potentially large amount of + uninteresting data (such as an APPn marker). In some applications + it may be possible to optimize away the reading of the skipped data, + but it's not clear that being smart is worth much trouble; large + skips are uncommon. bytes_in_buffer may be zero on return. + A zero or negative skip count should be treated as a no-op. */ + static void skip_input_data (j_decompress_ptr cinfo, long num_bytes); + + /* Terminate source --- called by jpeg_finish_decompress() after all + data has been read. Often a no-op. */ + static void term_source (j_decompress_ptr cinfo); + + // Copy filename to have it around for error-messages + static io::path Filename; + + #endif // _IRR_COMPILE_WITH_LIBJPEG_ +}; + + +} // end namespace video +} // end namespace irr + + +#endif +#endif + diff --git a/source/Irrlicht/CImageLoaderPCX.cpp b/source/Irrlicht/CImageLoaderPCX.cpp new file mode 100644 index 00000000..1c594472 --- /dev/null +++ b/source/Irrlicht/CImageLoaderPCX.cpp @@ -0,0 +1,229 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CImageLoaderPCX.h" + +#ifdef _IRR_COMPILE_WITH_PCX_LOADER_ + +#include "IReadFile.h" +#include "SColor.h" +#include "CColorConverter.h" +#include "CImage.h" +#include "os.h" +#include "irrString.h" + + +namespace irr +{ +namespace video +{ + + +//! constructor +CImageLoaderPCX::CImageLoaderPCX() +{ + #ifdef _DEBUG + setDebugName("CImageLoaderPCX"); + #endif +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".tga") +bool CImageLoaderPCX::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "pcx" ); +} + + + +//! returns true if the file maybe is able to be loaded by this class +bool CImageLoaderPCX::isALoadableFileFormat(io::IReadFile* file) const +{ + u8 headerID; + file->read(&headerID, sizeof(headerID)); + return headerID == 0x0a; +} + + +//! creates a image from the file +IImage* CImageLoaderPCX::loadImage(io::IReadFile* file) const +{ + SPCXHeader header; + s32* paletteData = 0; + + file->read(&header, sizeof(header)); + #ifdef __BIG_ENDIAN__ + header.XMin = os::Byteswap::byteswap(header.XMin); + header.YMin = os::Byteswap::byteswap(header.YMin); + header.XMax = os::Byteswap::byteswap(header.XMax); + header.YMax = os::Byteswap::byteswap(header.YMax); + header.HorizDPI = os::Byteswap::byteswap(header.HorizDPI); + header.VertDPI = os::Byteswap::byteswap(header.VertDPI); + header.BytesPerLine = os::Byteswap::byteswap(header.BytesPerLine); + header.PaletteType = os::Byteswap::byteswap(header.PaletteType); + header.HScrSize = os::Byteswap::byteswap(header.HScrSize); + header.VScrSize = os::Byteswap::byteswap(header.VScrSize); + #endif + + //! return if the header is wrong + if (header.Manufacturer != 0x0a && header.Encoding != 0x01) + return 0; + + // return if this isn't a supported type + if ((header.BitsPerPixel != 8) && (header.BitsPerPixel != 4) && (header.BitsPerPixel != 1)) + { + os::Printer::log("Unsupported bits per pixel in PCX file.", + file->getFileName(), irr::ELL_WARNING); + return 0; + } + + // read palette + if( (header.BitsPerPixel == 8) && (header.Planes == 1) ) + { + // the palette indicator (usually a 0x0c is found infront of the actual palette data) + // is ignored because some exporters seem to forget to write it. This would result in + // no image loaded before, now only wrong colors will be set. + const long pos = file->getPos(); + file->seek( file->getSize()-256*3, false ); + + u8 *tempPalette = new u8[768]; + paletteData = new s32[256]; + file->read( tempPalette, 768 ); + + for( s32 i=0; i<256; i++ ) + { + paletteData[i] = (0xff000000 | + (tempPalette[i*3+0] << 16) | + (tempPalette[i*3+1] << 8) | + (tempPalette[i*3+2])); + } + + delete [] tempPalette; + + file->seek(pos); + } + else if( header.BitsPerPixel == 4 ) + { + paletteData = new s32[16]; + for( s32 i=0; i<16; i++ ) + { + paletteData[i] = (0xff000000 | + (header.Palette[i*3+0] << 16) | + (header.Palette[i*3+1] << 8) | + (header.Palette[i*3+2])); + } + } + + // read image data + const s32 width = header.XMax - header.XMin + 1; + const s32 height = header.YMax - header.YMin + 1; + const s32 imagebytes = header.BytesPerLine * header.Planes * header.BitsPerPixel * height / 8; + u8* PCXData = new u8[imagebytes]; + + u8 cnt, value; + s32 lineoffset=0, linestart=0, nextmode=1; + for(s32 offset = 0; offset < imagebytes; offset += cnt) + { + file->read(&cnt, 1); + if( !((cnt & 0xc0) == 0xc0) ) + { + value = cnt; + cnt = 1; + } + else + { + cnt &= 0x3f; + file->read(&value, 1); + } + if (header.Planes==1) + memset(PCXData+offset, value, cnt); + else + { + for (u8 i=0; i=3*header.BytesPerLine) + { + lineoffset=nextmode; + if (++nextmode==3) + nextmode=0; + if (lineoffset==0) + linestart += 3*header.BytesPerLine; + } + } + } + } + + // create image + video::IImage* image = 0; + s32 pad = (header.BytesPerLine - width * header.BitsPerPixel / 8) * header.Planes; + + if (pad < 0) + pad = -pad; + + if (header.BitsPerPixel==8) + { + switch(header.Planes) // TODO: Other formats + { + case 1: + image = new CImage(ECF_A1R5G5B5, core::dimension2d(width, height)); + if (image) + CColorConverter::convert8BitTo16Bit(PCXData, (s16*)image->getData(), width, height, paletteData, pad); + break; + case 3: + image = new CImage(ECF_R8G8B8, core::dimension2d(width, height)); + if (image) + CColorConverter::convert24BitTo24Bit(PCXData, (u8*)image->getData(), width, height, pad); + break; + } + } + else if (header.BitsPerPixel==4) + { + if (header.Planes==1) + { + image = new CImage(ECF_A1R5G5B5, core::dimension2d(width, height)); + if (image) + CColorConverter::convert4BitTo16Bit(PCXData, (s16*)image->getData(), width, height, paletteData, pad); + } + } + else if (header.BitsPerPixel==1) + { + if (header.Planes==4) + { + image = new CImage(ECF_A1R5G5B5, core::dimension2d(width, height)); + if (image) + CColorConverter::convert4BitTo16Bit(PCXData, (s16*)image->getData(), width, height, paletteData, pad); + } + else if (header.Planes==1) + { + image = new CImage(ECF_A1R5G5B5, core::dimension2d(width, height)); + if (image) + CColorConverter::convert1BitTo16Bit(PCXData, (s16*)image->getData(), width, height, pad); + } + } + + // clean up + + delete [] paletteData; + delete [] PCXData; + + return image; +} + + +//! creates a loader which is able to load pcx images +IImageLoader* createImageLoaderPCX() +{ + return new CImageLoaderPCX(); +} + + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CImageLoaderPCX.h b/source/Irrlicht/CImageLoaderPCX.h new file mode 100644 index 00000000..4809d7b7 --- /dev/null +++ b/source/Irrlicht/CImageLoaderPCX.h @@ -0,0 +1,82 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_IMAGE_LOADER_PCX_H_INCLUDED__ +#define __C_IMAGE_LOADER_PCX_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#include "IImageLoader.h" + +namespace irr +{ +namespace video +{ + +#if defined(_IRR_COMPILE_WITH_PCX_LOADER_) || defined(_IRR_COMPILE_WITH_PCX_WRITER_) + +// byte-align structures +#include "irrpack.h" + + struct SPCXHeader + { + u8 Manufacturer; + u8 Version; + u8 Encoding; + u8 BitsPerPixel; + u16 XMin; + u16 YMin; + u16 XMax; + u16 YMax; + u16 HorizDPI; + u16 VertDPI; + u8 Palette[48]; + u8 Reserved; + u8 Planes; + u16 BytesPerLine; + u16 PaletteType; + u16 HScrSize; + u16 VScrSize; + u8 Filler[54]; + } PACK_STRUCT; + + +// Default alignment +#include "irrunpack.h" + +#endif // compile with loader or writer + +#ifdef _IRR_COMPILE_WITH_PCX_LOADER_ + +/*! + Image Loader for Windows PCX bitmaps. + This loader was written and sent in by Dean P. Macri. I modified + only some small bits of it. +*/ +class CImageLoaderPCX : public IImageLoader +{ +public: + + //! constructor + CImageLoaderPCX(); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".tga") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! returns true if the file maybe is able to be loaded by this class + virtual bool isALoadableFileFormat(io::IReadFile* file) const _IRR_OVERRIDE_; + + //! creates a surface from the file + virtual IImage* loadImage(io::IReadFile* file) const _IRR_OVERRIDE_; + +}; + +#endif // compile with loader + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CImageLoaderPNG.cpp b/source/Irrlicht/CImageLoaderPNG.cpp new file mode 100644 index 00000000..1df1eada --- /dev/null +++ b/source/Irrlicht/CImageLoaderPNG.cpp @@ -0,0 +1,287 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CImageLoaderPNG.h" + +#ifdef _IRR_COMPILE_WITH_PNG_LOADER_ + +#ifdef _IRR_COMPILE_WITH_LIBPNG_ + #ifndef _IRR_USE_NON_SYSTEM_LIB_PNG_ + #include // use system lib png + #else // _IRR_USE_NON_SYSTEM_LIB_PNG_ + #include "libpng/png.h" // use irrlicht included lib png + #endif // _IRR_USE_NON_SYSTEM_LIB_PNG_ +#endif // _IRR_COMPILE_WITH_LIBPNG_ + +#include "CImage.h" +#include "CReadFile.h" +#include "os.h" + +namespace irr +{ +namespace video +{ + +#ifdef _IRR_COMPILE_WITH_LIBPNG_ +// PNG function for error handling +static void png_cpexcept_error(png_structp png_ptr, png_const_charp msg) +{ + os::Printer::log("PNG fatal error", msg, ELL_ERROR); + longjmp(png_jmpbuf(png_ptr), 1); +} + +// PNG function for warning handling +static void png_cpexcept_warn(png_structp png_ptr, png_const_charp msg) +{ + os::Printer::log("PNG warning", msg, ELL_WARNING); +} + +// PNG function for file reading +void PNGAPI user_read_data_fcn(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check; + + // changed by zola { + io::IReadFile* file=(io::IReadFile*)png_get_io_ptr(png_ptr); + check=(png_size_t) file->read((void*)data,(u32)length); + // } + + if (check != length) + png_error(png_ptr, "Read Error"); +} +#endif // _IRR_COMPILE_WITH_LIBPNG_ + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".tga") +bool CImageLoaderPng::isALoadableFileExtension(const io::path& filename) const +{ +#ifdef _IRR_COMPILE_WITH_LIBPNG_ + return core::hasFileExtension ( filename, "png" ); +#else + return false; +#endif // _IRR_COMPILE_WITH_LIBPNG_ +} + + +//! returns true if the file maybe is able to be loaded by this class +bool CImageLoaderPng::isALoadableFileFormat(io::IReadFile* file) const +{ +#ifdef _IRR_COMPILE_WITH_LIBPNG_ + if (!file) + return false; + + png_byte buffer[8]; + // Read the first few bytes of the PNG file + if (file->read(buffer, 8) != 8) + return false; + + // Check if it really is a PNG file + return !png_sig_cmp(buffer, 0, 8); +#else + return false; +#endif // _IRR_COMPILE_WITH_LIBPNG_ +} + + +// load in the image data +IImage* CImageLoaderPng::loadImage(io::IReadFile* file) const +{ +#ifdef _IRR_COMPILE_WITH_LIBPNG_ + if (!file) + return 0; + + //Used to point to image rows + u8** RowPointers = 0; + + png_byte buffer[8]; + // Read the first few bytes of the PNG file + if( file->read(buffer, 8) != 8 ) + { + os::Printer::log("LOAD PNG: can't read file\n", file->getFileName(), ELL_ERROR); + return 0; + } + + // Check if it really is a PNG file + if( png_sig_cmp(buffer, 0, 8) ) + { + os::Printer::log("LOAD PNG: not really a png\n", file->getFileName(), ELL_ERROR); + return 0; + } + + // Allocate the png read struct + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + NULL, (png_error_ptr)png_cpexcept_error, (png_error_ptr)png_cpexcept_warn); + if (!png_ptr) + { + os::Printer::log("LOAD PNG: Internal PNG create read struct failure\n", file->getFileName(), ELL_ERROR); + return 0; + } + + // Allocate the png info struct + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + os::Printer::log("LOAD PNG: Internal PNG create info struct failure\n", file->getFileName(), ELL_ERROR); + png_destroy_read_struct(&png_ptr, NULL, NULL); + return 0; + } + + // for proper error handling + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + delete [] RowPointers; + return 0; + } + + // changed by zola so we don't need to have public FILE pointers + png_set_read_fn(png_ptr, file, user_read_data_fcn); + + png_set_sig_bytes(png_ptr, 8); // Tell png that we read the signature + + png_read_info(png_ptr, info_ptr); // Read the info section of the png file + + u32 Width; + u32 Height; + s32 BitDepth; + s32 ColorType; + { + // Use temporary variables to avoid passing cast 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 palette color to true color + if (ColorType==PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + + // Convert low bit colors to 8 bit colors + if (BitDepth < 8) + { + if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_expand_gray_1_2_4_to_8(png_ptr); + else + png_set_packing(png_ptr); + } + + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha(png_ptr); + + // Convert high bit colors to 8 bit colors + if (BitDepth == 16) + png_set_strip_16(png_ptr); + + // Convert gray color to true color + if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + + int intent; + const double screen_gamma = 2.2; + + if (png_get_sRGB(png_ptr, info_ptr, &intent)) + png_set_gamma(png_ptr, screen_gamma, 0.45455); + else + { + double image_gamma; + if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) + png_set_gamma(png_ptr, screen_gamma, image_gamma); + else + png_set_gamma(png_ptr, screen_gamma, 0.45455); + } + + // Update the changes in between, as we need to get the new color type + // for proper processing of the RGBA type + png_read_update_info(png_ptr, info_ptr); + { + // Use temporary variables to avoid passing cast 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) + { +#ifdef __BIG_ENDIAN__ + png_set_swap_alpha(png_ptr); +#else + png_set_bgr(png_ptr); +#endif + } + + // Create the image structure to be filled by png data + video::IImage* image = 0; + if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA) + image = new CImage(ECF_A8R8G8B8, core::dimension2d(Width, Height)); + else + 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); + png_destroy_read_struct(&png_ptr, NULL, NULL); + return 0; + } + + // Create array of pointers to rows in image data + RowPointers = new png_bytep[Height]; + if (!RowPointers) + { + os::Printer::log("LOAD PNG: Internal PNG create row pointers failure\n", file->getFileName(), ELL_ERROR); + png_destroy_read_struct(&png_ptr, NULL, NULL); + delete image; + return 0; + } + + // Fill array of pointers to rows in image data + unsigned char* data = (unsigned char*)image->getData(); + for (u32 i=0; igetPitch(); + } + + // for proper error handling + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + delete [] RowPointers; + delete image; + return 0; + } + + // Read data using the library function that handles all transformations including interlacing + png_read_image(png_ptr, RowPointers); + + png_read_end(png_ptr, NULL); + delete [] RowPointers; + png_destroy_read_struct(&png_ptr,&info_ptr, 0); // Clean up memory + + return image; +#else + return 0; +#endif // _IRR_COMPILE_WITH_LIBPNG_ +} + + +IImageLoader* createImageLoaderPNG() +{ + return new CImageLoaderPng(); +} + + +}// end namespace irr +}//end namespace video + +#endif + diff --git a/source/Irrlicht/CImageLoaderPNG.h b/source/Irrlicht/CImageLoaderPNG.h new file mode 100644 index 00000000..fbe448ad --- /dev/null +++ b/source/Irrlicht/CImageLoaderPNG.h @@ -0,0 +1,45 @@ +// Copyright (C) 2002-2012 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 created by rt (www.tomkorp.com), based on ttk's png-reader +// i wanted to be able to read in PNG images with irrlicht :) +// why? lossless compression with 8-bit alpha channel! + +#ifndef __C_IMAGE_LOADER_PNG_H_INCLUDED__ +#define __C_IMAGE_LOADER_PNG_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_PNG_LOADER_ + +#include "IImageLoader.h" + +namespace irr +{ +namespace video +{ + +//! Surface Loader for PNG files +class CImageLoaderPng : public IImageLoader +{ +public: + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".png") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! returns true if the file maybe is able to be loaded by this class + virtual bool isALoadableFileFormat(io::IReadFile* file) const _IRR_OVERRIDE_; + + //! creates a surface from the file + virtual IImage* loadImage(io::IReadFile* file) const _IRR_OVERRIDE_; +}; + + +} // end namespace video +} // end namespace irr + +#endif +#endif + diff --git a/source/Irrlicht/CImageLoaderPPM.cpp b/source/Irrlicht/CImageLoaderPPM.cpp new file mode 100644 index 00000000..7ebf6955 --- /dev/null +++ b/source/Irrlicht/CImageLoaderPPM.cpp @@ -0,0 +1,274 @@ +// Copyright (C) 2007-2012 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CImageLoaderPPM.h" + +#ifdef _IRR_COMPILE_WITH_PPM_LOADER_ + +#include "IReadFile.h" +#include "CColorConverter.h" +#include "CImage.h" +#include "os.h" +#include "fast_atof.h" +#include "coreutil.h" + +namespace irr +{ +namespace video +{ + + +//! constructor +CImageLoaderPPM::CImageLoaderPPM() +{ + #ifdef _DEBUG + setDebugName("CImageLoaderPPM"); + #endif +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".tga") +bool CImageLoaderPPM::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "ppm", "pgm", "pbm" ); +} + + +//! returns true if the file maybe is able to be loaded by this class +bool CImageLoaderPPM::isALoadableFileFormat(io::IReadFile* file) const +{ + c8 id[2]={0}; + file->read(&id, 2); + return (id[0]=='P' && id[1]>'0' && id[1]<'7'); +} + + +//! creates a surface from the file +IImage* CImageLoaderPPM::loadImage(io::IReadFile* file) const +{ + IImage* image; + + if (file->getSize() < 12) + return 0; + + c8 id[2]; + file->read(&id, 2); + + if (id[0]!='P' || id[1]<'1' || id[1]>'6') + return 0; + + const u8 format = id[1] - '0'; + const bool binary = format>3; + + core::stringc token; + getNextToken(file, token); + const u32 width = core::strtoul10(token.c_str()); + + getNextToken(file, token); + const u32 height = core::strtoul10(token.c_str()); + + u8* data = 0; + const u32 size = width*height; + if (format==1 || format==4) + { + skipToNextToken(file); // go to start of data + + const u32 bytesize = size/8+(size & 3)?1:0; + if (binary) + { + if (file->getSize()-file->getPos() < (long)bytesize) + return 0; + data = new u8[bytesize]; + file->read(data, bytesize); + } + else + { + if (file->getSize()-file->getPos() < (long)(2*size)) // optimistic test + return 0; + data = new u8[bytesize]; + memset(data, 0, bytesize); + u32 shift=0; + for (u32 i=0; i(width, height)); + if (image) + CColorConverter::convert1BitTo16Bit(data, (s16*)image->getData(), width, height); + } + else + { + getNextToken(file, token); + const u32 maxDepth = core::strtoul10(token.c_str()); + if (maxDepth > 255) // no double bytes yet + return 0; + + skipToNextToken(file); // go to start of data + + if (format==2 || format==5) + { + if (binary) + { + if (file->getSize()-file->getPos() < (long)size) + return 0; + data = new u8[size]; + file->read(data, size); + image = new CImage(ECF_A8R8G8B8, core::dimension2d(width, height)); + if (image) + { + u8* ptr = (u8*)image->getData(); + for (u32 i=0; igetSize()-file->getPos() < (long)(2*size)) // optimistic test + return 0; + image = new CImage(ECF_A8R8G8B8, core::dimension2d(width, height)); + if (image) + { + u8* ptr = (u8*)image->getData(); + for (u32 i=0; igetSize()-file->getPos() < (long)bytesize) + return 0; + data = new u8[bytesize]; + file->read(data, bytesize); + image = new CImage(ECF_A8R8G8B8, core::dimension2d(width, height)); + if (image) + { + u8* ptr = (u8*)image->getData(); + for (u32 i=0; igetSize()-file->getPos() < (long)(2*bytesize)) // optimistic test + return 0; + image = new CImage(ECF_A8R8G8B8, core::dimension2d(width, height)); + if (image) + { + u8* ptr = (u8*)image->getData(); + for (u32 i=0; igetPos()getSize()) + { + file->read(&c, 1); + if (c=='#') + { + while (c!='\n' && c!='\r' && (file->getPos()getSize())) + file->read(&c, 1); + } + else if (!core::isspace(c)) + { + token.append(c); + break; + } + } + while(file->getPos()getSize()) + { + file->read(&c, 1); + if (c=='#') + { + while (c!='\n' && c!='\r' && (file->getPos()getSize())) + file->read(&c, 1); + } + else if (!core::isspace(c)) + token.append(c); + else + break; + } +} + + +//! skip to next token (skip whitespace) +void CImageLoaderPPM::skipToNextToken(io::IReadFile* file) const +{ + c8 c; + while(file->getPos()getSize()) + { + file->read(&c, 1); + if (c=='#') + { + while (c!='\n' && c!='\r' && (file->getPos()getSize())) + file->read(&c, 1); + } + else if (!core::isspace(c)) + { + file->seek(-1, true); // put back + break; + } + } +} + + +//! creates a loader which is able to load windows bitmaps +IImageLoader* createImageLoaderPPM() +{ + return new CImageLoaderPPM; +} + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CImageLoaderPPM.h b/source/Irrlicht/CImageLoaderPPM.h new file mode 100644 index 00000000..8fe1c603 --- /dev/null +++ b/source/Irrlicht/CImageLoaderPPM.h @@ -0,0 +1,55 @@ +// Copyright (C) 2007-2012 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_IMAGE_LOADER_PPM_H_INCLUDED__ +#define __C_IMAGE_LOADER_PPM_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_PPM_LOADER_ + +#include "IImageLoader.h" +#include "irrString.h" + + +namespace irr +{ +namespace video +{ + + +/*! + Surface Loader for SUN Pixmaps +*/ +class CImageLoaderPPM : public IImageLoader +{ +public: + + //! constructor + CImageLoaderPPM(); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".tga") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! returns true if the file maybe is able to be loaded by this class + virtual bool isALoadableFileFormat(io::IReadFile* file) const _IRR_OVERRIDE_; + + //! creates a surface from the file + virtual IImage* loadImage(io::IReadFile* file) const _IRR_OVERRIDE_; + +private: + //! read the next token from file + void getNextToken(io::IReadFile* file, core::stringc& token) const; + //! skip to next token (skip whitespace) + void skipToNextToken(io::IReadFile* file) const; +}; + +} // end namespace video +} // end namespace irr + + +#endif +#endif + diff --git a/source/Irrlicht/CImageLoaderPSD.cpp b/source/Irrlicht/CImageLoaderPSD.cpp new file mode 100644 index 00000000..3eb5c3b8 --- /dev/null +++ b/source/Irrlicht/CImageLoaderPSD.cpp @@ -0,0 +1,375 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CImageLoaderPSD.h" + +#ifdef _IRR_COMPILE_WITH_PSD_LOADER_ + +#include "IReadFile.h" +#include "os.h" +#include "CImage.h" +#include "irrString.h" + + +namespace irr +{ +namespace video +{ + + +//! constructor +CImageLoaderPSD::CImageLoaderPSD() +{ + #ifdef _DEBUG + setDebugName("CImageLoaderPSD"); + #endif +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".tga") +bool CImageLoaderPSD::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "psd" ); +} + + + +//! returns true if the file maybe is able to be loaded by this class +bool CImageLoaderPSD::isALoadableFileFormat(io::IReadFile* file) const +{ + if (!file) + return false; + + u8 type[3]; + file->read(&type, sizeof(u8)*3); + return (type[2]==2); // we currently only handle tgas of type 2. +} + + + +//! creates a surface from the file +IImage* CImageLoaderPSD::loadImage(io::IReadFile* file) const +{ + u32* imageData = 0; + + PsdHeader header; + file->read(&header, sizeof(PsdHeader)); + +#ifndef __BIG_ENDIAN__ + header.version = os::Byteswap::byteswap(header.version); + header.channels = os::Byteswap::byteswap(header.channels); + header.height = os::Byteswap::byteswap(header.height); + header.width = os::Byteswap::byteswap(header.width); + header.depth = os::Byteswap::byteswap(header.depth); + header.mode = os::Byteswap::byteswap(header.mode); +#endif + + if (header.signature[0] != '8' || + header.signature[1] != 'B' || + header.signature[2] != 'P' || + header.signature[3] != 'S') + return 0; + + if (header.version != 1) + { + os::Printer::log("Unsupported PSD file version", file->getFileName(), ELL_ERROR); + return 0; + } + + if (header.mode != 3 || header.depth != 8) + { + os::Printer::log("Unsupported PSD color mode or depth.\n", file->getFileName(), ELL_ERROR); + return 0; + } + + // skip color mode data + + u32 l; + file->read(&l, sizeof(u32)); +#ifndef __BIG_ENDIAN__ + l = os::Byteswap::byteswap(l); +#endif + if (!file->seek(l, true)) + { + os::Printer::log("Error seeking file pos to image resources.\n", file->getFileName(), ELL_ERROR); + return 0; + } + + // skip image resources + + file->read(&l, sizeof(u32)); +#ifndef __BIG_ENDIAN__ + l = os::Byteswap::byteswap(l); +#endif + if (!file->seek(l, true)) + { + os::Printer::log("Error seeking file pos to layer and mask.\n", file->getFileName(), ELL_ERROR); + return 0; + } + + // skip layer & mask + + file->read(&l, sizeof(u32)); +#ifndef __BIG_ENDIAN__ + l = os::Byteswap::byteswap(l); +#endif + if (!file->seek(l, true)) + { + os::Printer::log("Error seeking file pos to image data section.\n", file->getFileName(), ELL_ERROR); + return 0; + } + + // read image data + + u16 compressionType; + file->read(&compressionType, sizeof(u16)); +#ifndef __BIG_ENDIAN__ + compressionType = os::Byteswap::byteswap(compressionType); +#endif + + if (compressionType != 1 && compressionType != 0) + { + os::Printer::log("Unsupported psd compression mode.\n", file->getFileName(), ELL_ERROR); + return 0; + } + + // create image data block + + imageData = new u32[header.width * header.height]; + + bool res = false; + + if (compressionType == 0) + res = readRawImageData(file, header, imageData); // RAW image data + else + res = readRLEImageData(file, header, imageData); // RLE compressed data + + video::IImage* image = 0; + + if (res) + { + // create surface + image = new CImage(ECF_A8R8G8B8, + core::dimension2d(header.width, header.height), imageData); + } + + if (!image) + delete [] imageData; + imageData = 0; + + return image; +} + + +bool CImageLoaderPSD::readRawImageData(io::IReadFile* file, const PsdHeader& header, u32* imageData) const +{ + u8* tmpData = new u8[header.width * header.height]; + + for (s32 channel=0; channelread(tmpData, sizeof(c8) * header.width * header.height)) + { + os::Printer::log("Error reading color channel\n", file->getFileName(), ELL_ERROR); + break; + } + + s16 shift = getShiftFromChannel((c8)channel, header); + if (shift != -1) + { + u32 mask = 0xff << shift; + + for (u32 x=0; xread(&rleCount[y], sizeof(u16))) + { + delete [] tmpData; + delete [] rleCount; + os::Printer::log("Error reading rle rows\n", file->getFileName(), ELL_ERROR); + return false; + } + +#ifndef __BIG_ENDIAN__ + rleCount[y] = os::Byteswap::byteswap(rleCount[y]); +#endif + size += rleCount[y]; + } + + s8 *buf = new s8[size]; + if (!file->read(buf, size)) + { + delete [] rleCount; + delete [] buf; + delete [] tmpData; + os::Printer::log("Error reading rle rows\n", file->getFileName(), ELL_ERROR); + return false; + } + + u16 *rcount=rleCount; + + s8 rh; + u16 bytesRead; + u8 *dest; + s8 *pBuf = buf; + + // decompress packbit rle + + for (s32 channel=0; channel= 0) + { + ++rh; + + while (rh--) + { + *dest = *pBuf++; + ++bytesRead; + ++dest; + } + } + else + if (rh > -128) + { + rh = -rh +1; + + while (rh--) + { + *dest = *pBuf; + ++dest; + } + + ++pBuf; + ++bytesRead; + } + } + } + + s16 shift = getShiftFromChannel((c8)channel, header); + + if (shift != -1) + { + u32 mask = 0xff << shift; + + for (u32 x=0; xseek(0); + file->read(&fourCC, 4); + + /*if (header.Version == 0x03525650) // TO-DO - fix endiannes + { + fourCC[0] = os::Byteswap::byteswap(fourCC[0]); + fourCC[1] = os::Byteswap::byteswap(fourCC[1]); + fourCC[2] = os::Byteswap::byteswap(fourCC[2]); + fourCC[3] = os::Byteswap::byteswap(fourCC[3]); + }*/ + + return (fourCC[0] == 'P' && fourCC[1] == 'V' && fourCC[2] == 'R'); +} + +IImage* CImageLoaderPVR::loadImage(io::IReadFile* file) const +{ + core::array imageArray = loadImages(file, 0); + + const u32 imageCount = imageArray.size(); + + for (u32 i = 1; i < imageCount; ++i) + { + if (imageArray[i]) + imageArray[i]->drop(); + } + + if (imageCount > 1) + imageArray.erase(1, imageCount - 1); + + return (imageCount > 1) ? imageArray[0] : 0; +} + +core::array CImageLoaderPVR::loadImages(io::IReadFile* file, E_TEXTURE_TYPE* type) const +{ + // TO-DO -> use 'move' feature from C++11 standard. + + SPVRHeader header; + + core::array imageArray; + core::array mipMapsDataArray; + + ECOLOR_FORMAT format = ECF_UNKNOWN; + u32 dataSize = 0; + + file->seek(0); + file->read(&header, sizeof(SPVRHeader)); + + /*if (header.Version == 0x03525650) // TO-DO - fix endiannes + { + header.Flags = os::Byteswap::byteswap(header.Flags); + header.PixelFormat = os::Byteswap::byteswap(header.PixelFormat); + header.ColourSpace = os::Byteswap::byteswap(header.ColourSpace); + header.ChannelType = os::Byteswap::byteswap(header.ChannelType); + header.Height = os::Byteswap::byteswap(header.Height); + header.Width = os::Byteswap::byteswap(header.Width); + header.Depth = os::Byteswap::byteswap(header.Depth); + header.NumSurfaces = os::Byteswap::byteswap(header.NumSurfaces); + header.NumFaces = os::Byteswap::byteswap(header.NumFaces); + header.MipMapCount = os::Byteswap::byteswap(header.MipMapCount); + header.MetDataSize = os::Byteswap::byteswap(header.MetDataSize); + }*/ + + c8 fourCC[4]; + u32 key; + u32 helperDataSize; + + if (header.MetDataSize > 0) + { + file->read(&fourCC, 4); + file->read(&key, sizeof(u32)); + file->read(&helperDataSize, sizeof(u32)); + file->seek(helperDataSize, true); + } + + if (header.PixelFormat & 0xFFFFFFFF00000000) + { + switch (header.PixelFormat) + { + case 0x505050162677261: + format = ECF_A1R5G5B5; + break; + case 0x5060500626772: + format = ECF_R5G6B5; + break; + case 0x8080800626772: + format = ECF_R8G8B8; + break; + case 0x808080861726762: + format = ECF_A8R8G8B8; + break; + default: + break; + } + } + else // Compressed texture formats + { + switch (header.PixelFormat) + { + case 0: // PVRTC 2bpp RGB + format = ECF_PVRTC_RGB2; + break; + case 1: // PVRTC 2bpp RGBA + format = ECF_PVRTC_ARGB2; + break; + case 2: // PVRTC 4bpp RGB + format = ECF_PVRTC_RGB4; + break; + case 3: // PVRTC 4bpp RGBA + format = ECF_PVRTC_ARGB4; + break; + case 4: // PVRTC-II 2bpp + format = ECF_PVRTC2_ARGB2; + break; + case 5: // PVRTC-II 4bpp + format = ECF_PVRTC2_ARGB4; + break; + case 6: // ETC1 + format = ECF_ETC1; + break; + case 7: // DXT1 / BC1 + format = ECF_DXT1; + break; + case 8: // DXT2 + case 9: // DXT3 / BC2 + format = ECF_DXT3; + break; + case 10: // DXT4 + case 11: // DXT5 / BC3 + format = ECF_DXT5; + break; + case 22: // ETC2 RGB + format = ECF_ETC2_RGB; + break; + case 23: // ETC2 RGBA + format = ECF_ETC2_ARGB; + break; + default: + format = ECF_UNKNOWN; + break; + } + } + + if (format != ECF_UNKNOWN) + { + imageArray.set_used(1); + E_TEXTURE_TYPE tmpType = ETT_2D; + + // check for texture type + + if (header.NumFaces == 6) // cube map + { + imageArray.set_used(6); + tmpType = ETT_CUBEMAP; + } + else if (header.Depth > 1) // 3d texture + { + // TO-DO + } + else if (header.NumSurfaces > 1) // texture array + { + // To-DO + } + + if (type) + *type = tmpType; + + // prepare mipmaps data + + dataSize = 0; + + for (u32 i = 1; i < header.MipMapCount; ++i) + { + u32 tmpWidth = header.Width >> i; + u32 tmpHeight = header.Height >> i; + + dataSize += IImage::getDataSizeFromFormat(format, tmpWidth, tmpHeight); + } + + if (header.MipMapCount > 1) + { + mipMapsDataArray.set_used(imageArray.size()); + + for (u32 j = 0; j < mipMapsDataArray.size(); ++j) + mipMapsDataArray[j] = new u8[dataSize]; + } + + // read texture + + dataSize = 0; + long offset = 0; + + for (u32 i = 0; i < header.MipMapCount; ++i) + { + if (i == 0) + { + for (u32 j = 0; j < imageArray.size(); ++j) + { + dataSize = IImage::getDataSizeFromFormat(format, header.Width, header.Height); + + u8* data = new u8[dataSize]; + file->read(data, dataSize); + + imageArray[j] = new CImage(format, core::dimension2d(header.Width, header.Height), data, true, true); + } + } + else + { + u32 tmpWidth = header.Width >> i; + u32 tmpHeight = header.Height >> i; + + dataSize = IImage::getDataSizeFromFormat(format, tmpWidth, tmpHeight); + + for (u32 j = 0; j < imageArray.size(); ++j) + file->read(mipMapsDataArray[j] + offset, dataSize); + + offset += dataSize; + } + } + + // assign mipmaps data + + for (u32 i = 0; i < mipMapsDataArray.size(); ++i) + imageArray[i]->setMipMapsData(mipMapsDataArray[i], true, true); + } + + return imageArray; +} + +IImageLoader* createImageLoaderPVR() +{ + return new CImageLoaderPVR(); +} + +} +} + +#endif diff --git a/source/Irrlicht/CImageLoaderPVR.h b/source/Irrlicht/CImageLoaderPVR.h new file mode 100644 index 00000000..4a4cfee3 --- /dev/null +++ b/source/Irrlicht/CImageLoaderPVR.h @@ -0,0 +1,55 @@ +// Copyright (C) 2013-2016 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_IMAGE_LOADER_PVR_H_INCLUDED__ +#define __C_IMAGE_LOADER_PVR_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_PVR_LOADER_ + +#include "IImageLoader.h" + +namespace irr +{ +namespace video +{ + +#include "irrpack.h" + +struct SPVRHeader +{ + u32 Version; + u32 Flags; + u64 PixelFormat; + u32 ColourSpace; + u32 ChannelType; + u32 Height; + u32 Width; + u32 Depth; + u32 NumSurfaces; + u32 NumFaces; + u32 MipMapCount; + u32 MetDataSize; +} PACK_STRUCT; + +#include "irrunpack.h" + +class CImageLoaderPVR : public IImageLoader +{ +public: + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + virtual bool isALoadableFileFormat(io::IReadFile* file) const _IRR_OVERRIDE_; + + virtual IImage* loadImage(io::IReadFile* file) const _IRR_OVERRIDE_; + + virtual core::array loadImages(io::IReadFile* file, E_TEXTURE_TYPE* type) const _IRR_OVERRIDE_; +}; + +} +} + +#endif +#endif diff --git a/source/Irrlicht/CImageLoaderRGB.cpp b/source/Irrlicht/CImageLoaderRGB.cpp new file mode 100644 index 00000000..1f0b141e --- /dev/null +++ b/source/Irrlicht/CImageLoaderRGB.cpp @@ -0,0 +1,651 @@ +//! Copyright (C) 2009-2012 Gary Conway +//! This file is part of the "Irrlicht Engine". +//! For conditions of distribution and use, see copyright notice in irrlicht.h + +/* + Author: Gary Conway (Viper) - co-author of the ZIP file format, Feb 1989, + see the story at http://www.idcnet.us/ziphistory.html + Website: http://idcnet.us + Email: codeslinger@vipergc.com + Created: March 1, 2009 + Version: 1.0 + Updated: + + This module will load SGI .rgb files (along with the other extensions). The module complies + with version 1.0 of the SGI Image File Format by Paul Haeberli of Silicon Graphics Computer Systems + The module handles BW, RGB and RGBA images. + + RGB images are stored with either 8 bits per COLOR VALUE, one each for red,green,blue (24bpp) + or 16 bits per COLOR VALUE, again one each for red,green,blue (48 bpp), not including the alpha channel + + + OPTIONS NOT SUPPORTED + + 1. 16 bit COLOR VALUES (48bpp modes) + 2. COLORMAP = DITHERED mode + + + +For non- run length encoded files, this is the structure + + The Header + The Image Data + +If the image is run length encoded, this is the structure: + The Header + The Offset Tables + The Image Data + +The Header consists of the following: + + Size | Type | Name | Description + + 2 bytes | short | MAGIC | IRIS image file magic number + 1 byte | char | STORAGE | Storage format + 1 byte | char | BPC | Number of bytes per pixel channel + 2 bytes | ushort | DIMENSION | Number of dimensions + 2 bytes | ushort | XSIZE | X size in pixels + 2 bytes | ushort | YSIZE | Y size in pixels + 2 bytes | ushort | ZSIZE | Number of channels + 4 bytes | long | PIXMIN | Minimum pixel value + 4 bytes | long | PIXMAX | Maximum pixel value + 4 bytes | char | DUMMY | Ignored + 80 bytes | char | IMAGENAME | Image name + 4 bytes | long | COLORMAP | Colormap ID + 404 bytes | char | DUMMY | Ignored + +Here is a description of each field in the image file Header: + +MAGIC - This is the decimal value 474 saved as a short. This identifies the file as an SGI image file. + +STORAGE - specifies whether the image is stored using run length encoding (RLE) or not (VERBATIM). + If RLE is used, the value of this byte will be 1. Otherwise the value of this byte will + be 0. The only allowed values for this field are 0 or 1. + +BPC - describes the precision that is used to store each channel of an image. This is the number of + bytes per pixel component. The majority of SGI image files use 1 byte per pixel component, + giving 256 levels. Some SGI image files use 2 bytes per component. The only allowed values + for this field are 1 or 2. + +DIMENSION - described the number of dimensions in the data stored in the image file. + The only allowed values are 1, 2, or 3. If this value is 1, the image file + consists of only 1 channel and only 1 scanline (row). The length of this + scanline is given by the value of XSIZE below. If this value is 2, the file + consists of a single channel with a number of scanlines. The width and height + of the image are given by the values of XSIZE and YSIZE below. + If this value is 3, the file consists of a number of channels. + The width and height of the image are given by the values of XSIZE and YSIZE below. + The number of channels is given by the value of ZSIZE below. + +XSIZE - The width of the image in pixels + +YSIZE - The height of the image in pixels + +ZSIZE - The number of channels in the image. B/W (greyscale) images are stored as 2 dimensional + images with a ZSIZE of 1. RGB color images are stored as 3 dimensional images with a + ZSIZE of 3. An RGB image with an ALPHA channel is stored as a 3 dimensional image with + a ZSIZE of 4. There are no inherent limitations in the SGI image file format that would + preclude the creation of image files with more than 4 channels. + +PINMIN - The minimum pixel value in the image. The value of 0 may be used if no pixel has a value + that is smaller than 0. + +PINMAX - The maximum pixel value in the image. The value of 255 may be used if no pixel has a + value that is greater than 255. This is the value that is considered to be full + brightness in the image. + +DUMMY - This 4 bytes of data should be set to 0. + +IMAGENAME - An null terminated ascii string of up to 79 characters terminated by a null may be + included here. This is not commonly used. + +COLORMAP - This controls how the pixel values in the file should be interpreted. It can have one + of these four values: + +0: NORMAL - The data in the channels represent B/W values for images with 1 channel, RGB values + for images with 3 channels, and RGBA values for images with 4 channels. Almost all + the SGI image files are of this type. + +1: DITHERED - The image will have only 1 channel of data. For each pixel, RGB data is packed + into one 8 bit value. 3 bits are used for red and green, while blue uses 2 bits. + Red data is found in bits[2..0], green data in bits[5..3], and blue data in + bits[7..6]. This format is obsolete. + +2: SCREEN - The image will have only 1 channel of data. This format was used to store + color-indexed pixels. To convert the pixel values into RGB values a colormap + must be used. The appropriate color map varies from image to image. This format is obsolete. + +3: COLORMAP - The image is used to store a color map from an SGI machine. In this case the + image is not displayable in the conventional sense. + +DUMMY - This 404 bytes of data should be set to 0. This makes the Header exactly 512 bytes. +*/ + +#include "CImageLoaderRGB.h" + +#ifdef _IRR_COMPILE_WITH_RGB_LOADER_ + +#include "IReadFile.h" +#include "SColor.h" +#include "CColorConverter.h" +#include "CImage.h" +#include "os.h" +#include "irrString.h" + + +namespace irr +{ +namespace video +{ + +//! constructor +CImageLoaderRGB::CImageLoaderRGB() +{ + #ifdef _DEBUG + setDebugName("CImageLoaderRGB"); + #endif +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extensions listed here +bool CImageLoaderRGB::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension( filename, "rgb", "rgba", "sgi" ) || + core::hasFileExtension( filename, "int", "inta", "bw" ); +} + + +//! returns true if the file maybe is able to be loaded by this class +bool CImageLoaderRGB::isALoadableFileFormat(io::IReadFile* file) const +{ + rgbStruct rgb; + return checkFormat(file, rgb); +} + + +/** The main entry point, read and format the image file. +\return Pointer to the image data on success + null pointer on fail */ +IImage* CImageLoaderRGB::loadImage(io::IReadFile* file) const +{ + IImage* image = 0; + s32* paletteData = 0; + + rgbStruct rgb; // construct our structure for holding data + + // read Header information + if (checkFormat(file, rgb)) + { + // 16 bits per COLOR VALUE, not supported, this is 48bpp mode + if (rgb.Header.BPC != 1) + { + os::Printer::log("Only one byte per pixel RGB files are supported", file->getFileName(), ELL_ERROR); + } + else if (rgb.Header.Colormap != 0) + { + os::Printer::log("Dithered, Screen and Colormap RGB files are not supported", file->getFileName(), ELL_ERROR); + } + else if (rgb.Header.Storage == 1 && !readOffsetTables(file, rgb)) + { + os::Printer::log("Failed to read RLE table in RGB file", file->getFileName(), ELL_ERROR); + } + else if (!rgb.allocateTemps()) + { + os::Printer::log("Out of memory in RGB file loader", file->getFileName(), ELL_ERROR); + } + else + { + // read and process the file to rgbData + processFile(file, rgb); + +/* + ZSIZE Description + 1 BW (grayscale) image + 3 RGB image + 4 RGBa image with one alpha channel + + When the Alpha channel is present, I am not sure with RGB files if + it's a precomputed RGB color or it needs to be completely calculated. My guess + would be that it's not precomputed for two reasons. + + 1. the loss of precision when calculating the fraction, then storing the result as an int + 2. the loss of the original color data when the image might be composited with another. Yes + the original color data could be computed, however, not without another loss in precision + + Also, I don't know where to find the background color + Pixmin and Pixmax are apparently the min and max alpha blend values (0-100%) + + Complete Alpha blending computation + The actual resulting merged color is computed this way: + (image color ◊ alpha) + (background color ◊ (100% - alpha)). + + Using precomputed blending + (image color) + (background color ◊ (100% - alpha)). + + Alternatively, the RGB files could use another blending technique entirely +*/ + + switch (rgb.Header.Zsize) + { + case 1: + // BW (grayscale) image + paletteData = new s32[256]; + for (int n=0; n<256; n++) + paletteData[n] = n; + + image = new CImage(ECF_A1R5G5B5, core::dimension2d(rgb.Header.Xsize, rgb.Header.Ysize)); + if (image) + CColorConverter::convert8BitTo16Bit(rgb.rgbData, (s16*)image->getData(), rgb.Header.Xsize, rgb.Header.Ysize, paletteData, 0, true); + break; + case 3: + // RGB image + // one byte per COLOR VALUE, eg, 24bpp + image = new CImage(ECF_R8G8B8, core::dimension2d(rgb.Header.Xsize, rgb.Header.Ysize)); + if (image) + CColorConverter::convert24BitTo24Bit(rgb.rgbData, (u8*)image->getData(), rgb.Header.Xsize, rgb.Header.Ysize, 0, true, false); + break; + case 4: + // RGBa image with one alpha channel (32bpp) + // image is stored in rgbData as RGBA + + converttoARGB(reinterpret_cast(rgb.rgbData), rgb.Header.Ysize * rgb.Header.Xsize); + + image = new CImage(ECF_A8R8G8B8, core::dimension2d(rgb.Header.Xsize, rgb.Header.Ysize)); + if (image) + CColorConverter::convert32BitTo32Bit((s32*)rgb.rgbData, (s32*)image->getData(), rgb.Header.Xsize, rgb.Header.Ysize, 0, true); + + break; + default: + // Format unknown + os::Printer::log("Unsupported pixel format in RGB file", file->getFileName(), ELL_ERROR); + } + } + } + + // and tidy up allocated memory + delete [] paletteData; + + return image; +} + +// returns true on success +bool CImageLoaderRGB::readHeader(io::IReadFile* file, rgbStruct& rgb) const +{ + if ( file->read(&rgb.Header, sizeof(rgb.Header)) < s32(sizeof(rgb.Header)) ) + return false; + + // test for INTEL or BIG ENDIAN processor + // if INTEL, then swap the byte order on 16 bit INT's to make them BIG ENDIAN + // because that is the native format for the .rgb file +#ifndef __BIG_ENDIAN__ + rgb.Header.Magic = os::Byteswap::byteswap(rgb.Header.Magic); + rgb.Header.Storage = os::Byteswap::byteswap(rgb.Header.Storage); + rgb.Header.Dimension = os::Byteswap::byteswap(rgb.Header.Dimension); + rgb.Header.Xsize = os::Byteswap::byteswap(rgb.Header.Xsize); + rgb.Header.Ysize = os::Byteswap::byteswap(rgb.Header.Ysize); + rgb.Header.Zsize = os::Byteswap::byteswap(rgb.Header.Zsize); + rgb.Header.Pixmin = os::Byteswap::byteswap(rgb.Header.Pixmin); + rgb.Header.Pixmax = os::Byteswap::byteswap(rgb.Header.Pixmax); + rgb.Header.Colormap = os::Byteswap::byteswap(rgb.Header.Colormap); +#endif + + // calculate the size of the buffer needed: XSIZE * YSIZE * ZSIZE * BPC + rgb.ImageSize = (rgb.Header.Xsize)*(rgb.Header.Ysize)*(rgb.Header.Zsize)*(rgb.Header.BPC); + + return true; +} + + +bool CImageLoaderRGB::checkFormat(io::IReadFile* file, rgbStruct& rgb) const +{ + if (!readHeader(file, rgb)) + return false; + + return (rgb.Header.Magic == 0x1DA); +} + +/* +If the image is stored using run length encoding, offset tables follow the Header that +describe what the file offsets are to the RLE for each scanline. This information only +applies if the value for STORAGE above is 1. + + Size | Type | Name | Description + + tablen longs | long | STARTTAB | Start table + tablen longs | long | LENGTHTAB | Length table + +One entry in each table is needed for each scanline of RLE data. The total number of scanlines in the image (tablen) is determined by the product of the YSIZE and ZSIZE. There are two tables of longs that are written. Each consists of tablen longs of data. The first table has the file offsets to the RLE data for each scanline in the image. In a file with more than 1 channel (ZSIZE > 1) this table first has all the offsets for the scanlines in the first channel, followed be offsets for the scanlines in the second channel, etc. The second table has the RLE data length for each scanline in the image. In a file with more than 1 channel (ZSIZE > 1) this table first has all the RLE data lengths for the scanlines in the first channel, followed be RLE data lengths for the scanlines in the second channel, etc. + +To find the the file offset, and the number of bytes in the RLE data for a particular scanline, these +two arrays may be read in and indexed as follows: + +To read in the tables: + + unsigned long *starttab, *lengthtab; + + tablen = YSIZE*ZSIZE*sizeof(long); + starttab = (unsigned long *)mymalloc(tablen); + lengthtab = (unsigned long *)mymalloc(tablen); + fseek(rgb->inf,512,SEEK_SET); + readlongtab(rgb->inf,starttab); + readlongtab(rgb->inf,lengthtab); + +To find the file offset and RLE data length for a scanline: + +rowno is an integer in the range 0 to YSIZE-1 channo is an integer in the range 0 to ZSIZE-1 + + rleoffset = starttab[rowno+channo*YSIZE] + rlelength = lengthtab[rowno+channo*YSIZE] + +It is possible for two identical rows (scanlines) to share compressed data. A completely +white image could be written as a single compressed row and having all table entries point +to that row. Another little hack that should work is if you are writing out a RGB RLE file, +and a particular scanline is achromatic (greyscale), you could just make the r, g and b rows +point to the same data!! + + RETURNS: on success true, else returns false +*/ + +bool CImageLoaderRGB::readOffsetTables(io::IReadFile* file, rgbStruct& rgb) const +{ + rgb.TableLen = rgb.Header.Ysize * rgb.Header.Zsize ; // calc size of tables + + // return error if unable to allocate tables + rgb.StartTable = new u32[rgb.TableLen]; + if (!rgb.StartTable) + return false; + rgb.LengthTable = new u32[rgb.TableLen]; + if (!rgb.LengthTable) + return false; + + file->seek(512); + file->read(rgb.StartTable, rgb.TableLen* sizeof(u32)); + file->read(rgb.LengthTable, rgb.TableLen* sizeof(u32)); + + // if we are on an INTEL platform, swap the bytes +#ifndef __BIG_ENDIAN__ + const u32 length = rgb.TableLen; + for (u32 i=0; i=0; --i) +#endif + { + // check the number of channels and read a row of data + if (rgb.Header.Zsize >= 1) + readRGBrow( rgb.tmpR, i, 0, file, rgb); + if (rgb.Header.Zsize >= 2) + readRGBrow( rgb.tmpG, i, 1, file, rgb); + if (rgb.Header.Zsize >= 3) + readRGBrow( rgb.tmpB, i, 2, file, rgb); + if (rgb.Header.Zsize >= 4) + readRGBrow( rgb.tmpA, i, 3, file, rgb); + + // cycle thru all values for this row + for (u16 j = 0; j < rgb.Header.Xsize; ++j) + { + if(rgb.Header.BPC == 1) + { + // ONE byte per color + if (rgb.Header.Zsize >= 1) + *ptr++ = rgb.tmpR[j]; + if (rgb.Header.Zsize >= 2) + *ptr++ = rgb.tmpG[j]; + if (rgb.Header.Zsize >= 3) + *ptr++ = rgb.tmpB[j]; + if (rgb.Header.Zsize >= 4) + *ptr++ = rgb.tmpA[j]; + } + else + { + // TWO bytes per color + if( rgb.Header.Zsize >= 1 ) + { + // two bytes of color data + tempShort = (u16 *) (ptr); + *tempShort = *( (u16 *) (rgb.tmpR) + j); + tempShort++; + ptr = ( u8 *)(tempShort); + } + if( rgb.Header.Zsize >= 2 ) + { + tempShort = ( u16 *) (ptr); + *tempShort = *( ( u16 *) (rgb.tmpG) + j); + tempShort++; + ptr = ( u8 *) (tempShort); + } + if( rgb.Header.Zsize >= 3 ) + { + tempShort = ( u16 *) (ptr); + *tempShort = *( ( u16 *) (rgb.tmpB) + j); + tempShort++; + ptr = ( u8 *)(tempShort); + } + if( rgb.Header.Zsize >= 4 ) + { + tempShort = ( u16 *) (ptr); + *tempShort = *( ( u16 *) (rgb.tmpA) + j); + tempShort++; + ptr = ( u8 *)(tempShort); + } + } // end if(rgb.Header.BPC == 1) + } // end for + } // end for +} + + +/* + This information only applies if the value for STORAGE is 1. If the image is + stored using run length encoding, the image data follows the offset/length tables. + The RLE data is not in any particular order. The offset tables are used to + locate the rle data for any scanline. + + The RLE data must be read in from the file and expanded into pixel data in the following manner: + + If BPC is 1, then there is one byte per pixel. In this case the RLE data should be + read into an array of chars. To expand data, the low order seven bits of the first + byte: bits[6..0] are used to form a count. If the high order bit of the first byte + is 1: bit[7], then the count is used to specify how many bytes to copy from the RLE + data buffer to the destination. Otherwise, if the high order bit of the first byte + is 0: bit[7], then the count is used to specify how many times to repeat the value + of the following byte, in the destination. This process continues until a count + of 0 is found. This should decompress exactly XSIZE pixels. + + + One entry in each table is needed for each scanline of RLE data. The total number of + scanlines in the image (tablen) is determined by the product of the YSIZE and ZSIZE. + There are two tables of longs that are written. Each consists of tablen longs of data. + The first table has the file offsets to the RLE data for each scanline in the image. In + a file with more than 1 channel (ZSIZE > 1) this table first has all the offsets for the + scanlines in the first channel, followed be offsets for the scanlines in the second + channel, etc. The second table has the RLE data length for each scanline in the image. + In a file with more than 1 channel (ZSIZE > 1) this table first has all the RLE data + lengths for the scanlines in the first channel, followed be RLE data lengths for the + scanlines in the second channel, etc. + + Return a row of data, expanding RLE compression if necessary +*/ +void CImageLoaderRGB::readRGBrow(u8 *buf, int y, int z, io::IReadFile* file, rgbStruct& rgb) const +{ + if (rgb.Header.Storage != 1) + { + // stored VERBATIM + + file->seek(512+(y*rgb.Header.Xsize * rgb.Header.BPC)+(z* rgb.Header.Xsize * rgb.Header.Ysize * rgb.Header.BPC)); + file->read(buf, rgb.Header.Xsize * rgb.Header.BPC); + +#ifndef __BIG_ENDIAN__ + if (rgb.Header.BPC != 1) + { + u16* tmpbuf = reinterpret_cast(buf); + for (u16 i=0; iseek((long) rgb.StartTable[y+z * rgb.Header.Ysize]); + file->read(rgb.tmp, rgb.LengthTable[y+z * rgb.Header.Ysize]); + + // rgb.tmp has the data + + u16 pixel; + u16 *tempShort; + u8* iPtr = rgb.tmp; + u8* oPtr = buf; + while (true) + { + // if BPC = 1, then one byte per pixel + if (rgb.Header.BPC == 1) + { + pixel = *iPtr++; + } + else + { + // BPC = 2, so two bytes per pixel + tempShort = (u16 *) iPtr; + pixel = *tempShort; + tempShort++; + iPtr = (u8 *) tempShort; + } + +#ifndef __BIG_ENDIAN__ + if (rgb.Header.BPC != 1) + pixel = os::Byteswap::byteswap(pixel); +#endif + + s32 count = (s32)(pixel & 0x7F); + + // limit the count value to the remaining row size + if (oPtr + count*rgb.Header.BPC > buf + rgb.Header.Xsize * rgb.Header.BPC) + { + count = ( (buf + rgb.Header.Xsize * rgb.Header.BPC) - oPtr ) / rgb.Header.BPC; + } + + if (count<=0) + break; + else if (pixel & 0x80) + { + // repeat the byte pointed to by iPtr, count times + while (count--) + { + if(rgb.Header.BPC == 1) + { + *oPtr++ = *iPtr++; + } + else + { + // write pixel from iPtr to oPtr, move both two bytes ahead + tempShort = (u16 *) (iPtr); + pixel = *tempShort; + tempShort++; + iPtr = (u8 *) (tempShort); +#ifndef __BIG_ENDIAN__ + pixel = os::Byteswap::byteswap(pixel); +#endif + tempShort = (u16 *) (oPtr); + *tempShort = pixel; + tempShort++; + oPtr = (u8 *) (tempShort); + } + } + } + else + { + if (rgb.Header.BPC == 1) + { + pixel = *iPtr++; + } + else + { + tempShort = (u16 *) (iPtr); + pixel = *tempShort; + tempShort++; + iPtr = (u8 *) (tempShort); + } + +#ifndef __BIG_ENDIAN__ + if (rgb.Header.BPC != 1) + pixel = os::Byteswap::byteswap(pixel); +#endif + + while (count--) + { + if(rgb.Header.BPC == 1) + { + *oPtr++ = (u8) pixel; + } + else + { + tempShort = (u16 *) (oPtr); + *tempShort = pixel; + tempShort++; + oPtr = (u8 *) (tempShort); + } + } + } // else if (pixel & 0x80) + } // while (true) +} + + +// we have 1 byte per COLOR VALUE, eg 24bpp and 1 alpha channel +// color values are stored as RGBA, convert to ARGB +// todo: replace with CColorConverter method +void CImageLoaderRGB::converttoARGB(u32* in, const u32 size) const +{ + for (u32 x=0; x < size; ++x) + { + *in=(*in>>8)|(*in<<24); + ++in; + } +} + + +//! creates a loader which is able to load SGI RGB images +IImageLoader* createImageLoaderRGB() +{ + return new CImageLoaderRGB; +} + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CImageLoaderRGB.h b/source/Irrlicht/CImageLoaderRGB.h new file mode 100644 index 00000000..4360cffb --- /dev/null +++ b/source/Irrlicht/CImageLoaderRGB.h @@ -0,0 +1,164 @@ +// Copyright (C) 2009-2012 Gary Conway +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + + +/* + Author: Gary Conway (Viper) - co-author of the ZIP file format, Feb 1989, + see the story at http://www.idcnet.us/ziphistory.html + Website: http://idcnet.us + Email: codeslinger@vipergc.com + Created: March 1, 2009 + Version: 1.0 + Updated: +*/ + +#ifndef __C_IMAGE_LOADER_RGB_H_INCLUDED__ +#define __C_IMAGE_LOADER_RGB_H_INCLUDED__ + +// define _IRR_RGB_FILE_INVERTED_IMAGE_ to preserve the inverted format of the RGB file +// commenting this out will invert the inverted image,resulting in the image being upright +#define _IRR_RGB_FILE_INVERTED_IMAGE_ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_RGB_LOADER_ + +#include "IImageLoader.h" + +namespace irr +{ +namespace video +{ + +// byte-align structures +#include "irrpack.h" + + // the RGB image file header structure + + struct SRGBHeader + { + u16 Magic; // IRIS image file magic number + u8 Storage; // Storage format + u8 BPC; // Number of bytes per pixel channel + u16 Dimension; // Number of dimensions + u16 Xsize; // X size in pixels + u16 Ysize; // Y size in pixels + u16 Zsize; // Z size in pixels + u32 Pixmin; // Minimum pixel value + u32 Pixmax; // Maximum pixel value + u32 Dummy1; // ignored + char Imagename[80];// Image name + u32 Colormap; // Colormap ID +// char Dummy2[404];// Ignored + } PACK_STRUCT; + +// Default alignment +#include "irrunpack.h" + + // this structure holds context specific data about the file being loaded. + + typedef struct _RGBdata + { + u8 *tmp; + u8 *tmpR; + u8 *tmpG; + u8 *tmpB; + u8 *tmpA; + + u32 *StartTable; // compressed data table, holds file offsets + u32 *LengthTable; // length for the above data, hold lengths for above + u32 TableLen; // len of above tables + + SRGBHeader Header; // define the .rgb file header + u32 ImageSize; + u8 *rgbData; + + public: + _RGBdata() : tmp(0), tmpR(0), tmpG(0), tmpB(0), tmpA(0), + StartTable(0), LengthTable(0), TableLen(0), ImageSize(0), rgbData(0) + { + } + + ~_RGBdata() + { + delete [] tmp; + delete [] tmpR; + delete [] tmpG; + delete [] tmpB; + delete [] tmpA; + delete [] StartTable; + delete [] LengthTable; + delete [] rgbData; + } + + bool allocateTemps() + { + tmp = tmpR = tmpG = tmpB = tmpA = 0; + tmp = new u8 [Header.Xsize * 256 * Header.BPC]; + if (!tmp) + return false; + + if (Header.Zsize >= 1) + { + tmpR = new u8[Header.Xsize * Header.BPC]; + if (!tmpR) + return false; + } + if (Header.Zsize >= 2) + { + tmpG = new u8[Header.Xsize * Header.BPC]; + if (!tmpG) + return false; + } + if (Header.Zsize >= 3) + { + tmpB = new u8[Header.Xsize * Header.BPC]; + if (!tmpB) + return false; + } + if (Header.Zsize >= 4) + { + tmpA = new u8[Header.Xsize * Header.BPC]; + if (!tmpA) + return false; + } + return true; + } + } rgbStruct; + + +//! Surface Loader for Silicon Graphics RGB files +class CImageLoaderRGB : public IImageLoader +{ +public: + + //! constructor + CImageLoaderRGB(); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".tga") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! returns true if the file maybe is able to be loaded by this class + virtual bool isALoadableFileFormat(io::IReadFile* file) const _IRR_OVERRIDE_; + + //! creates a surface from the file + virtual IImage* loadImage(io::IReadFile* file) const _IRR_OVERRIDE_; + +private: + + bool readHeader(io::IReadFile* file, rgbStruct& rgb) const; + void readRGBrow(u8 *buf, int y, int z, io::IReadFile* file, rgbStruct& rgb) const; + void processFile(io::IReadFile *file, rgbStruct& rgb) const; + bool checkFormat(io::IReadFile *file, rgbStruct& rgb) const; + bool readOffsetTables(io::IReadFile* file, rgbStruct& rgb) const; + void converttoARGB(u32* in, const u32 size) const; +}; + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_RGB_LOADER_ +#endif // __C_IMAGE_LOADER_RGB_H_INCLUDED__ + diff --git a/source/Irrlicht/CImageLoaderTGA.cpp b/source/Irrlicht/CImageLoaderTGA.cpp new file mode 100644 index 00000000..c9b3a9d5 --- /dev/null +++ b/source/Irrlicht/CImageLoaderTGA.cpp @@ -0,0 +1,237 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CImageLoaderTGA.h" + +#ifdef _IRR_COMPILE_WITH_TGA_LOADER_ + +#include "IReadFile.h" +#include "os.h" +#include "CColorConverter.h" +#include "CImage.h" +#include "irrString.h" + + +namespace irr +{ +namespace video +{ + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".tga") +bool CImageLoaderTGA::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "tga" ); +} + + +//! loads a compressed tga. +u8 *CImageLoaderTGA::loadCompressedImage(io::IReadFile *file, const STGAHeader& header) const +{ + // This was written and sent in by Jon Pry, thank you very much! + // I only changed the formatting a little bit. + + s32 bytesPerPixel = header.PixelDepth/8; + s32 imageSize = header.ImageHeight * header.ImageWidth * bytesPerPixel; + u8* data = new u8[imageSize]; + s32 currentByte = 0; + + while(currentByte < imageSize) + { + u8 chunkheader = 0; + file->read(&chunkheader, sizeof(u8)); // Read The Chunk's Header + + if(chunkheader < 128) // If The Chunk Is A 'RAW' Chunk + { + chunkheader++; // Add 1 To The Value To Get Total Number Of Raw Pixels + + file->read(&data[currentByte], bytesPerPixel * chunkheader); + currentByte += bytesPerPixel * chunkheader; + } + else + { + // thnx to neojzs for some fixes with this code + + // If It's An RLE Header + chunkheader -= 127; // Subtract 127 To Get Rid Of The ID Bit + + s32 dataOffset = currentByte; + file->read(&data[dataOffset], bytesPerPixel); + + currentByte += bytesPerPixel; + + for(s32 counter = 1; counter < chunkheader; counter++) + { + for(s32 elementCounter=0; elementCounter < bytesPerPixel; elementCounter++) + data[currentByte + elementCounter] = data[dataOffset + elementCounter]; + + currentByte += bytesPerPixel; + } + } + } + + return data; +} + + + +//! returns true if the file maybe is able to be loaded by this class +bool CImageLoaderTGA::isALoadableFileFormat(io::IReadFile* file) const +{ + if (!file) + return false; + + STGAFooter footer; + memset(&footer, 0, sizeof(STGAFooter)); + file->seek(file->getSize()-sizeof(STGAFooter)); + file->read(&footer, sizeof(STGAFooter)); + return (!strcmp(footer.Signature,"TRUEVISION-XFILE.")); // very old tgas are refused. +} + + + +//! creates a surface from the file +IImage* CImageLoaderTGA::loadImage(io::IReadFile* file) const +{ + STGAHeader header; + u32 *palette = 0; + + file->read(&header, sizeof(STGAHeader)); + +#ifdef __BIG_ENDIAN__ + header.ColorMapLength = os::Byteswap::byteswap(header.ColorMapLength); + header.ImageWidth = os::Byteswap::byteswap(header.ImageWidth); + header.ImageHeight = os::Byteswap::byteswap(header.ImageHeight); +#endif + + // skip image identification field + if (header.IdLength) + file->seek(header.IdLength, true); + + if (header.ColorMapType) + { + // create 32 bit palette + palette = new u32[ header.ColorMapLength]; + + // read color map + u8 * colorMap = new u8[header.ColorMapEntrySize/8 * header.ColorMapLength]; + file->read(colorMap,header.ColorMapEntrySize/8 * header.ColorMapLength); + + // convert to 32-bit palette + switch ( header.ColorMapEntrySize ) + { + case 16: + CColorConverter::convert_A1R5G5B5toA8R8G8B8(colorMap, header.ColorMapLength, palette); + break; + case 24: + CColorConverter::convert_B8G8R8toA8R8G8B8(colorMap, header.ColorMapLength, palette); + break; + case 32: + CColorConverter::convert_B8G8R8A8toA8R8G8B8(colorMap, header.ColorMapLength, palette); + break; + } + delete [] colorMap; + } + + // read image + + u8* data = 0; + + if ( header.ImageType == 1 || // Uncompressed, color-mapped images. + header.ImageType == 2 || // Uncompressed, RGB images + header.ImageType == 3 // Uncompressed, black and white images + ) + { + const s32 imageSize = header.ImageHeight * header.ImageWidth * header.PixelDepth/8; + data = new u8[imageSize]; + file->read(data, imageSize); + } + else + if(header.ImageType == 10) + { + // Runlength encoded RGB images + data = loadCompressedImage(file, header); + } + else + { + os::Printer::log("Unsupported TGA file type", file->getFileName(), ELL_ERROR); + delete [] palette; + return 0; + } + + IImage* image = 0; + + switch(header.PixelDepth) + { + case 8: + { + if (header.ImageType==3) // grey image + { + image = new CImage(ECF_R8G8B8, + core::dimension2d(header.ImageWidth, header.ImageHeight)); + if (image) + CColorConverter::convert8BitTo24Bit((u8*)data, + (u8*)image->getData(), + header.ImageWidth,header.ImageHeight, + 0, 0, (header.ImageDescriptor&0x20)==0); + } + else + { + image = new CImage(ECF_A1R5G5B5, + core::dimension2d(header.ImageWidth, header.ImageHeight)); + if (image) + CColorConverter::convert8BitTo16Bit((u8*)data, + (s16*)image->getData(), + header.ImageWidth,header.ImageHeight, + (s32*) palette, 0, + (header.ImageDescriptor&0x20)==0); + } + } + break; + case 16: + image = new CImage(ECF_A1R5G5B5, + core::dimension2d(header.ImageWidth, header.ImageHeight)); + if (image) + CColorConverter::convert16BitTo16Bit((s16*)data, + (s16*)image->getData(), header.ImageWidth, header.ImageHeight, 0, (header.ImageDescriptor&0x20)==0); + break; + case 24: + image = new CImage(ECF_R8G8B8, + core::dimension2d(header.ImageWidth, header.ImageHeight)); + if (image) + CColorConverter::convert24BitTo24Bit( + (u8*)data, (u8*)image->getData(), header.ImageWidth, header.ImageHeight, 0, (header.ImageDescriptor&0x20)==0, true); + break; + case 32: + image = new CImage(ECF_A8R8G8B8, + core::dimension2d(header.ImageWidth, header.ImageHeight)); + if (image) + CColorConverter::convert32BitTo32Bit((s32*)data, + (s32*)image->getData(), header.ImageWidth, header.ImageHeight, 0, (header.ImageDescriptor&0x20)==0); + break; + default: + os::Printer::log("Unsupported TGA format", file->getFileName(), ELL_ERROR); + break; + } + + delete [] data; + delete [] palette; + + return image; +} + + +//! creates a loader which is able to load tgas +IImageLoader* createImageLoaderTGA() +{ + return new CImageLoaderTGA(); +} + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CImageLoaderTGA.h b/source/Irrlicht/CImageLoaderTGA.h new file mode 100644 index 00000000..8ea0246f --- /dev/null +++ b/source/Irrlicht/CImageLoaderTGA.h @@ -0,0 +1,82 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_IMAGE_LOADER_TGA_H_INCLUDED__ +#define __C_IMAGE_LOADER_TGA_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#include "IImageLoader.h" + + +namespace irr +{ +namespace video +{ + +#if defined(_IRR_COMPILE_WITH_TGA_LOADER_) || defined(_IRR_COMPILE_WITH_TGA_WRITER_) + +// byte-align structures +#include "irrpack.h" + + // these structs are also used in the TGA writer + struct STGAHeader{ + u8 IdLength; + u8 ColorMapType; + u8 ImageType; + u8 FirstEntryIndex[2]; + u16 ColorMapLength; + u8 ColorMapEntrySize; + u8 XOrigin[2]; + u8 YOrigin[2]; + u16 ImageWidth; + u16 ImageHeight; + u8 PixelDepth; + u8 ImageDescriptor; + } PACK_STRUCT; + + struct STGAFooter + { + u32 ExtensionOffset; + u32 DeveloperOffset; + c8 Signature[18]; + } PACK_STRUCT; + +// Default alignment +#include "irrunpack.h" + +#endif // compiled with loader or reader + +#ifdef _IRR_COMPILE_WITH_TGA_LOADER_ + +/*! + Surface Loader for targa images +*/ +class CImageLoaderTGA : public IImageLoader +{ +public: + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".tga") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! returns true if the file maybe is able to be loaded by this class + virtual bool isALoadableFileFormat(io::IReadFile* file) const _IRR_OVERRIDE_; + + //! creates a surface from the file + virtual IImage* loadImage(io::IReadFile* file) const _IRR_OVERRIDE_; + +private: + + //! loads a compressed tga. Was written and sent in by Jon Pry, thank you very much! + u8* loadCompressedImage(io::IReadFile *file, const STGAHeader& header) const; +}; + +#endif // compiled with loader + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CImageLoaderWAL.cpp b/source/Irrlicht/CImageLoaderWAL.cpp new file mode 100644 index 00000000..cd210ded --- /dev/null +++ b/source/Irrlicht/CImageLoaderWAL.cpp @@ -0,0 +1,282 @@ +// Copyright (C) 2004 Murphy McCauley +// Copyright (C) 2007-2012 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CImageLoaderWAL.h" + +#include "CColorConverter.h" +#include "CImage.h" +#include "os.h" +#include "dimension2d.h" +#include "IVideoDriver.h" +#include "IFileSystem.h" +#include "IReadFile.h" +#include "irrString.h" + +namespace irr +{ +namespace video +{ + +#ifdef _IRR_COMPILE_WITH_LMP_LOADER_ + +// Palette quake2 colormap.h, 768 byte, last is transparent +static const u32 colormap_h[256] = { + 0xFF000000,0xFF0F0F0F,0xFF1F1F1F,0xFF2F2F2F,0xFF3F3F3F,0xFF4B4B4B,0xFF5B5B5B,0xFF6B6B6B, + 0xFF7B7B7B,0xFF8B8B8B,0xFF9B9B9B,0xFFABABAB,0xFFBBBBBB,0xFFCBCBCB,0xFFDBDBDB,0xFFEBEBEB, + 0xFF0F0B07,0xFF170F0B,0xFF1F170B,0xFF271B0F,0xFF2F2313,0xFF372B17,0xFF3F2F17,0xFF4B371B, + 0xFF533B1B,0xFF5B431F,0xFF634B1F,0xFF6B531F,0xFF73571F,0xFF7B5F23,0xFF836723,0xFF8F6F23, + 0xFF0B0B0F,0xFF13131B,0xFF1B1B27,0xFF272733,0xFF2F2F3F,0xFF37374B,0xFF3F3F57,0xFF474767, + 0xFF4F4F73,0xFF5B5B7F,0xFF63638B,0xFF6B6B97,0xFF7373A3,0xFF7B7BAF,0xFF8383BB,0xFF8B8BCB, + 0xFF000000,0xFF070700,0xFF0B0B00,0xFF131300,0xFF1B1B00,0xFF232300,0xFF2B2B07,0xFF2F2F07, + 0xFF373707,0xFF3F3F07,0xFF474707,0xFF4B4B0B,0xFF53530B,0xFF5B5B0B,0xFF63630B,0xFF6B6B0F, + 0xFF070000,0xFF0F0000,0xFF170000,0xFF1F0000,0xFF270000,0xFF2F0000,0xFF370000,0xFF3F0000, + 0xFF470000,0xFF4F0000,0xFF570000,0xFF5F0000,0xFF670000,0xFF6F0000,0xFF770000,0xFF7F0000, + 0xFF131300,0xFF1B1B00,0xFF232300,0xFF2F2B00,0xFF372F00,0xFF433700,0xFF4B3B07,0xFF574307, + 0xFF5F4707,0xFF6B4B0B,0xFF77530F,0xFF835713,0xFF8B5B13,0xFF975F1B,0xFFA3631F,0xFFAF6723, + 0xFF231307,0xFF2F170B,0xFF3B1F0F,0xFF4B2313,0xFF572B17,0xFF632F1F,0xFF733723,0xFF7F3B2B, + 0xFF8F4333,0xFF9F4F33,0xFFAF632F,0xFFBF772F,0xFFCF8F2B,0xFFDFAB27,0xFFEFCB1F,0xFFFFF31B, + 0xFF0B0700,0xFF1B1300,0xFF2B230F,0xFF372B13,0xFF47331B,0xFF533723,0xFF633F2B,0xFF6F4733, + 0xFF7F533F,0xFF8B5F47,0xFF9B6B53,0xFFA77B5F,0xFFB7876B,0xFFC3937B,0xFFD3A38B,0xFFE3B397, + 0xFFAB8BA3,0xFF9F7F97,0xFF937387,0xFF8B677B,0xFF7F5B6F,0xFF775363,0xFF6B4B57,0xFF5F3F4B, + 0xFF573743,0xFF4B2F37,0xFF43272F,0xFF371F23,0xFF2B171B,0xFF231313,0xFF170B0B,0xFF0F0707, + 0xFFBB739F,0xFFAF6B8F,0xFFA35F83,0xFF975777,0xFF8B4F6B,0xFF7F4B5F,0xFF734353,0xFF6B3B4B, + 0xFF5F333F,0xFF532B37,0xFF47232B,0xFF3B1F23,0xFF2F171B,0xFF231313,0xFF170B0B,0xFF0F0707, + 0xFFDBC3BB,0xFFCBB3A7,0xFFBFA39B,0xFFAF978B,0xFFA3877B,0xFF977B6F,0xFF876F5F,0xFF7B6353, + 0xFF6B5747,0xFF5F4B3B,0xFF533F33,0xFF433327,0xFF372B1F,0xFF271F17,0xFF1B130F,0xFF0F0B07, + 0xFF6F837B,0xFF677B6F,0xFF5F7367,0xFF576B5F,0xFF4F6357,0xFF475B4F,0xFF3F5347,0xFF374B3F, + 0xFF2F4337,0xFF2B3B2F,0xFF233327,0xFF1F2B1F,0xFF172317,0xFF0F1B13,0xFF0B130B,0xFF070B07, + 0xFFFFF31B,0xFFEFDF17,0xFFDBCB13,0xFFCBB70F,0xFFBBA70F,0xFFAB970B,0xFF9B8307,0xFF8B7307, + 0xFF7B6307,0xFF6B5300,0xFF5B4700,0xFF4B3700,0xFF3B2B00,0xFF2B1F00,0xFF1B0F00,0xFF0B0700, + 0xFF0000FF,0xFF0B0BEF,0xFF1313DF,0xFF1B1BCF,0xFF2323BF,0xFF2B2BAF,0xFF2F2F9F,0xFF2F2F8F, + 0xFF2F2F7F,0xFF2F2F6F,0xFF2F2F5F,0xFF2B2B4F,0xFF23233F,0xFF1B1B2F,0xFF13131F,0xFF0B0B0F, + 0xFF2B0000,0xFF3B0000,0xFF4B0700,0xFF5F0700,0xFF6F0F00,0xFF7F1707,0xFF931F07,0xFFA3270B, + 0xFFB7330F,0xFFC34B1B,0xFFCF632B,0xFFDB7F3B,0xFFE3974F,0xFFE7AB5F,0xFFEFBF77,0xFFF7D38B, + 0xFFA77B3B,0xFFB79B37,0xFFC7C337,0xFFE7E357,0xFF7FBFFF,0xFFABE7FF,0xFFD7FFFF,0xFF670000, + 0xFF8B0000,0xFFB30000,0xFFD70000,0xFFFF0000,0xFFFFF393,0xFFFFF7C7,0xFFFFFFFF,0x009F5B53 +}; + +bool CImageLoaderLMP::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "lmp" ); +} + + +bool CImageLoaderLMP::isALoadableFileFormat(irr::io::IReadFile* file) const +{ + return false; +} + +/*! + Quake1, Quake2, Hallife lmp texture +*/ +IImage* CImageLoaderLMP::loadImage(irr::io::IReadFile* file) const +{ + SLMPHeader header; + + file->seek(0); + file->read(&header, sizeof(header)); + + // maybe palette file + u32 rawtexsize = header.width * header.height; + if ( rawtexsize + sizeof ( header ) != (u32)file->getSize() ) + return 0; + + u8 *rawtex = new u8 [ rawtexsize ]; + + file->read(rawtex, rawtexsize); + + IImage* image = new CImage(ECF_A8R8G8B8, core::dimension2d(header.width, header.height)); + + CColorConverter::convert8BitTo32Bit(rawtex, (u8*)image->getData(), header.width, header.height, (u8*) colormap_h, 0, false); + + delete [] rawtex; + + return image; +} + + +IImageLoader* createImageLoaderLMP() +{ + return new irr::video::CImageLoaderLMP(); +} + +#endif + +#ifdef _IRR_COMPILE_WITH_WAL_LOADER_ + +// Palette quake2 demo pics/colormap.pcx, last is transparent +static const u32 colormap_pcx[256] = { + 0xFF000000,0xFF0F0F0F,0xFF1F1F1F,0xFF2F2F2F,0xFF3F3F3F,0xFF4B4B4B,0xFF5B5B5B,0xFF6B6B6B, + 0xFF7B7B7B,0xFF8B8B8B,0xFF9B9B9B,0xFFABABAB,0xFFBBBBBB,0xFFCBCBCB,0xFFDBDBDB,0xFFEBEBEB, + 0xFF634B23,0xFF5B431F,0xFF533F1F,0xFF4F3B1B,0xFF47371B,0xFF3F2F17,0xFF3B2B17,0xFF332713, + 0xFF2F2313,0xFF2B1F13,0xFF271B0F,0xFF23170F,0xFF1B130B,0xFF170F0B,0xFF130F07,0xFF0F0B07, + 0xFF5F5F6F,0xFF5B5B67,0xFF5B535F,0xFF574F5B,0xFF534B53,0xFF4F474B,0xFF473F43,0xFF3F3B3B, + 0xFF3B3737,0xFF332F2F,0xFF2F2B2B,0xFF272727,0xFF232323,0xFF1B1B1B,0xFF171717,0xFF131313, + 0xFF8F7753,0xFF7B6343,0xFF735B3B,0xFF674F2F,0xFFCF974B,0xFFA77B3B,0xFF8B672F,0xFF6F5327, + 0xFFEB9F27,0xFFCB8B23,0xFFAF771F,0xFF93631B,0xFF774F17,0xFF5B3B0F,0xFF3F270B,0xFF231707, + 0xFFA73B2B,0xFF9F2F23,0xFF972B1B,0xFF8B2713,0xFF7F1F0F,0xFF73170B,0xFF671707,0xFF571300, + 0xFF4B0F00,0xFF430F00,0xFF3B0F00,0xFF330B00,0xFF2B0B00,0xFF230B00,0xFF1B0700,0xFF130700, + 0xFF7B5F4B,0xFF735743,0xFF6B533F,0xFF674F3B,0xFF5F4737,0xFF574333,0xFF533F2F,0xFF4B372B, + 0xFF433327,0xFF3F2F23,0xFF37271B,0xFF2F2317,0xFF271B13,0xFF1F170F,0xFF170F0B,0xFF0F0B07, + 0xFF6F3B17,0xFF5F3717,0xFF532F17,0xFF432B17,0xFF372313,0xFF271B0F,0xFF1B130B,0xFF0F0B07, + 0xFFB35B4F,0xFFBF7B6F,0xFFCB9B93,0xFFD7BBB7,0xFFCBD7DF,0xFFB3C7D3,0xFF9FB7C3,0xFF87A7B7, + 0xFF7397A7,0xFF5B879B,0xFF47778B,0xFF2F677F,0xFF17536F,0xFF134B67,0xFF0F435B,0xFF0B3F53, + 0xFF07374B,0xFF072F3F,0xFF072733,0xFF001F2B,0xFF00171F,0xFF000F13,0xFF00070B,0xFF000000, + 0xFF8B5757,0xFF834F4F,0xFF7B4747,0xFF734343,0xFF6B3B3B,0xFF633333,0xFF5B2F2F,0xFF572B2B, + 0xFF4B2323,0xFF3F1F1F,0xFF331B1B,0xFF2B1313,0xFF1F0F0F,0xFF130B0B,0xFF0B0707,0xFF000000, + 0xFF979F7B,0xFF8F9773,0xFF878B6B,0xFF7F8363,0xFF777B5F,0xFF737357,0xFF6B6B4F,0xFF636347, + 0xFF5B5B43,0xFF4F4F3B,0xFF434333,0xFF37372B,0xFF2F2F23,0xFF23231B,0xFF171713,0xFF0F0F0B, + 0xFF9F4B3F,0xFF934337,0xFF8B3B2F,0xFF7F3727,0xFF772F23,0xFF6B2B1B,0xFF632317,0xFF571F13, + 0xFF4F1B0F,0xFF43170B,0xFF37130B,0xFF2B0F07,0xFF1F0B07,0xFF170700,0xFF0B0000,0xFF000000, + 0xFF777BCF,0xFF6F73C3,0xFF676BB7,0xFF6363A7,0xFF5B5B9B,0xFF53578F,0xFF4B4F7F,0xFF474773, + 0xFF3F3F67,0xFF373757,0xFF2F2F4B,0xFF27273F,0xFF231F2F,0xFF1B1723,0xFF130F17,0xFF0B0707, + 0xFF9BAB7B,0xFF8F9F6F,0xFF879763,0xFF7B8B57,0xFF73834B,0xFF677743,0xFF5F6F3B,0xFF576733, + 0xFF4B5B27,0xFF3F4F1B,0xFF374313,0xFF2F3B0B,0xFF232F07,0xFF1B2300,0xFF131700,0xFF0B0F00, + 0xFF00FF00,0xFF23E70F,0xFF3FD31B,0xFF53BB27,0xFF5FA72F,0xFF5F8F33,0xFF5F7B33,0xFFFFFFFF, + 0xFFFFFFD3,0xFFFFFFA7,0xFFFFFF7F,0xFFFFFF53,0xFFFFFF27,0xFFFFEB1F,0xFFFFD717,0xFFFFBF0F, + 0xFFFFAB07,0xFFFF9300,0xFFEF7F00,0xFFE36B00,0xFFD35700,0xFFC74700,0xFFB73B00,0xFFAB2B00, + 0xFF9B1F00,0xFF8F1700,0xFF7F0F00,0xFF730700,0xFF5F0000,0xFF470000,0xFF2F0000,0xFF1B0000, + 0xFFEF0000,0xFF3737FF,0xFFFF0000,0xFF0000FF,0xFF2B2B23,0xFF1B1B17,0xFF13130F,0xFFEB977F, + 0xFFC37353,0xFF9F5733,0xFF7B3F1B,0xFFEBD3C7,0xFFC7AB9B,0xFFA78B77,0xFF876B57,0x009F5B53 +}; + +/*! + Halflife +*/ +bool CImageLoaderWAL2::isALoadableFileExtension(const io::path& filename) const +{ + // embedded in Wad(WAD3 format). originally it has no extension + return core::hasFileExtension ( filename, "wal2" ); +} + + +bool CImageLoaderWAL2::isALoadableFileFormat(irr::io::IReadFile* file) const +{ + return false; +} + +/* + Halflite Texture WAD +*/ +IImage* CImageLoaderWAL2::loadImage(irr::io::IReadFile* file) const +{ + miptex_halflife header; + + file->seek(0); + file->read(&header, sizeof(header)); + +#ifdef __BIG_ENDIAN__ + header.width = os::Byteswap::byteswap(header.width); + header.height = os::Byteswap::byteswap(header.height); +#endif + + // palette + //u32 paletteofs = header.mipmap[0] + ((rawtexsize * 85) >> 6) + 2; + u32 *pal = new u32 [ 192 + 256 ]; + u8 *s = (u8*) pal; + + file->seek ( file->getSize() - 768 - 2 ); + file->read ( s, 768 ); + u32 i; + + for ( i = 0; i < 256; ++i, s+= 3 ) + { + pal [ 192 + i ] = 0xFF000000 | s[0] << 16 | s[1] << 8 | s[2]; + } + + ECOLOR_FORMAT format = ECF_R8G8B8; + + // transparency in filename;-) funny. rgb:0x0000FF is colorkey + if ( file->getFileName().findFirst ( '{' ) >= 0 ) + { + format = ECF_A8R8G8B8; + pal [ 192 + 255 ] &= 0x00FFFFFF; + } + + u32 rawtexsize = header.width * header.height; + u8 *rawtex = new u8 [ rawtexsize ]; + + file->seek ( header.mipmap[0] ); + file->read(rawtex, rawtexsize); + + IImage* image = new CImage(format, core::dimension2d(header.width, header.height)); + + switch ( format ) + { + case ECF_R8G8B8: + CColorConverter::convert8BitTo24Bit(rawtex, (u8*)image->getData(), header.width, header.height, (u8*) pal + 768, 0, false); + break; + case ECF_A8R8G8B8: + CColorConverter::convert8BitTo32Bit(rawtex, (u8*)image->getData(), header.width, header.height, (u8*) pal + 768, 0, false); + break; + default: + // Assuming there are no other color formats (I found no information about this format) + break; + } + + delete [] rawtex; + delete [] pal; + + return image; +} + +bool CImageLoaderWAL::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "wal" ); +} + + +bool CImageLoaderWAL::isALoadableFileFormat(irr::io::IReadFile* file) const +{ + return false; +} + + +/*! + quake2 +*/ +IImage* CImageLoaderWAL::loadImage(irr::io::IReadFile* file) const +{ + miptex_quake2 header; + + file->seek(0); + file->read(&header, sizeof(header)); + +#ifdef __BIG_ENDIAN__ + header.width = os::Byteswap::byteswap(header.width); + header.height = os::Byteswap::byteswap(header.height); +#endif + + u32 rawtexsize = header.width * header.height; + + u8 *rawtex = new u8 [ rawtexsize ]; + + file->seek ( header.mipmap[0] ); + file->read(rawtex, rawtexsize); + + IImage* image = new CImage(ECF_A8R8G8B8, core::dimension2d(header.width, header.height)); + + CColorConverter::convert8BitTo32Bit(rawtex, (u8*)image->getData(), header.width, header.height, (u8*) colormap_pcx, 0, false); + + delete [] rawtex; + + return image; +} + +IImageLoader* createImageLoaderWAL() +{ + return new irr::video::CImageLoaderWAL(); +} + +IImageLoader* createImageLoaderHalfLife() +{ + return new irr::video::CImageLoaderWAL2(); +} + +#endif + +} // end namespace video +} // end namespace irr + diff --git a/source/Irrlicht/CImageLoaderWAL.h b/source/Irrlicht/CImageLoaderWAL.h new file mode 100644 index 00000000..7c8ab6ec --- /dev/null +++ b/source/Irrlicht/CImageLoaderWAL.h @@ -0,0 +1,100 @@ +// Copyright (C) 2004 Murphy McCauley +// Copyright (C) 2007-2012 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +/* + Thanks to: + Max McGuire for his Flipcode article about WAL textures + Nikolaus Gebhardt for the Irrlicht 3D engine +*/ + +#ifndef __C_IMAGE_LOADER_WAL_H_INCLUDED__ +#define __C_IMAGE_LOADER_WAL_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#include "IImageLoader.h" + +namespace irr +{ +namespace video +{ + +#ifdef _IRR_COMPILE_WITH_LMP_LOADER_ + +// byte-align structures +#include "irrpack.h" + + struct SLMPHeader { + u32 width; // width + u32 height; // height + // variably sized + } PACK_STRUCT; + +// Default alignment +#include "irrunpack.h" + +//! An Irrlicht image loader for Quake1,2 engine lmp textures/palette +class CImageLoaderLMP : public irr::video::IImageLoader +{ +public: + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + virtual bool isALoadableFileFormat(irr::io::IReadFile* file) const _IRR_OVERRIDE_; + virtual irr::video::IImage* loadImage(irr::io::IReadFile* file) const _IRR_OVERRIDE_; +}; + +#endif + +#ifdef _IRR_COMPILE_WITH_WAL_LOADER_ + +//! An Irrlicht image loader for quake2 wal engine textures +class CImageLoaderWAL : public irr::video::IImageLoader +{ +public: + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + virtual bool isALoadableFileFormat(irr::io::IReadFile* file) const _IRR_OVERRIDE_; + virtual irr::video::IImage* loadImage(irr::io::IReadFile* file) const _IRR_OVERRIDE_; +}; + +//! An Irrlicht image loader for Halflife 1 engine textures +class CImageLoaderWAL2 : public irr::video::IImageLoader +{ +public: + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + virtual bool isALoadableFileFormat(irr::io::IReadFile* file) const _IRR_OVERRIDE_; + virtual irr::video::IImage* loadImage(irr::io::IReadFile* file) const _IRR_OVERRIDE_; +}; + +// byte-align structures +#include "irrpack.h" + + // Halfelife wad3 type 67 file + struct miptex_halflife + { + c8 name[16]; + u32 width, height; + u32 mipmap[4]; // four mip maps stored + } PACK_STRUCT; + + //quake2 texture + struct miptex_quake2 + { + c8 name[32]; + u32 width; + u32 height; + u32 mipmap[4]; // four mip maps stored + c8 animname[32]; // next frame in animation chain + s32 flags; + s32 contents; + s32 value; + } PACK_STRUCT; + +// Default alignment +#include "irrunpack.h" + +#endif + +} +} + +#endif + diff --git a/source/Irrlicht/CImageWriterBMP.cpp b/source/Irrlicht/CImageWriterBMP.cpp new file mode 100644 index 00000000..c5fe2b8d --- /dev/null +++ b/source/Irrlicht/CImageWriterBMP.cpp @@ -0,0 +1,135 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CImageWriterBMP.h" + +#ifdef _IRR_COMPILE_WITH_BMP_WRITER_ + +#include "CImageLoaderBMP.h" +#include "IWriteFile.h" +#include "CColorConverter.h" +#include "irrString.h" + +namespace irr +{ +namespace video +{ + +IImageWriter* createImageWriterBMP() +{ + return new CImageWriterBMP; +} + +CImageWriterBMP::CImageWriterBMP() +{ +#ifdef _DEBUG + setDebugName("CImageWriterBMP"); +#endif +} + +bool CImageWriterBMP::isAWriteableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "bmp" ); +} + +bool CImageWriterBMP::writeImage(io::IWriteFile* file, IImage* image, u32 param) const +{ + // we always write 24-bit color because nothing really reads 32-bit + + SBMPHeader imageHeader; + imageHeader.Id = 0x4d42; + imageHeader.Reserved = 0; + imageHeader.BitmapDataOffset = sizeof(imageHeader); + imageHeader.BitmapHeaderSize = 0x28; + imageHeader.Width = image->getDimension().Width; + imageHeader.Height = image->getDimension().Height; + imageHeader.Planes = 1; + imageHeader.BPP = 24; + imageHeader.Compression = 0; + imageHeader.PixelPerMeterX = 0; + imageHeader.PixelPerMeterY = 0; + imageHeader.Colors = 0; + imageHeader.ImportantColors = 0; + + // data size is rounded up to next larger 4 bytes boundary + imageHeader.BitmapDataSize = imageHeader.Width * imageHeader.BPP / 8; + imageHeader.BitmapDataSize = (imageHeader.BitmapDataSize + 3) & ~3; + imageHeader.BitmapDataSize *= imageHeader.Height; + + // file size is data size plus offset to data + imageHeader.FileSize = imageHeader.BitmapDataOffset + imageHeader.BitmapDataSize; + + // bitmaps are stored upside down and padded so we always do this + void (*CColorConverter_convertFORMATtoFORMAT)(const void*, s32, void*) = 0; + switch(image->getColorFormat()) + { + case ECF_R8G8B8: + CColorConverter_convertFORMATtoFORMAT + = CColorConverter::convert_R8G8B8toR8G8B8; + break; + case ECF_A8R8G8B8: + CColorConverter_convertFORMATtoFORMAT + = CColorConverter::convert_A8R8G8B8toB8G8R8; + break; + case ECF_A1R5G5B5: + CColorConverter_convertFORMATtoFORMAT + = CColorConverter::convert_A1R5G5B5toR8G8B8; + break; + case ECF_R5G6B5: + CColorConverter_convertFORMATtoFORMAT + = CColorConverter::convert_R5G6B5toR8G8B8; + break; + default: + break; + } + + // couldn't find a color converter + if (!CColorConverter_convertFORMATtoFORMAT) + return false; + + // write the bitmap header + if (file->write(&imageHeader, sizeof(imageHeader)) != sizeof(imageHeader)) + return false; + + u8* scan_lines = (u8*)image->getData(); + if (!scan_lines) + return false; + + // size of one pixel in bytes + u32 pixel_size = image->getBytesPerPixel(); + + // length of one row of the source image in bytes + u32 row_stride = (pixel_size * imageHeader.Width); + + // length of one row in bytes, rounded up to nearest 4-byte boundary + size_t row_size = ((3 * imageHeader.Width) + 3) & ~3; + + // allocate and clear memory for our scan line + u8* row_pointer = new u8[row_size]; + memset(row_pointer, 0, row_size); + + // convert the image to 24-bit BGR and flip it over + s32 y; + for (y = imageHeader.Height - 1; 0 <= y; --y) + { + if (image->getColorFormat()==ECF_R8G8B8) + CColorConverter::convert24BitTo24Bit(&scan_lines[y * row_stride], row_pointer, imageHeader.Width, 1, 0, false, true); + else + // source, length [pixels], destination + CColorConverter_convertFORMATtoFORMAT(&scan_lines[y * row_stride], imageHeader.Width, row_pointer); + if (file->write(row_pointer, row_size) < row_size) + break; + } + + // clean up our scratch area + delete [] row_pointer; + + return y < 0; +} + +} // namespace video +} // namespace irr + +#endif + diff --git a/source/Irrlicht/CImageWriterBMP.h b/source/Irrlicht/CImageWriterBMP.h new file mode 100644 index 00000000..3d9584c0 --- /dev/null +++ b/source/Irrlicht/CImageWriterBMP.h @@ -0,0 +1,37 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef _C_IMAGE_WRITER_BMP_H_INCLUDED__ +#define _C_IMAGE_WRITER_BMP_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_BMP_WRITER_ + +#include "IImageWriter.h" + +namespace irr +{ +namespace video +{ + +class CImageWriterBMP : public IImageWriter +{ +public: + //! constructor + CImageWriterBMP(); + + //! return true if this writer can write a file with the given extension + virtual bool isAWriteableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! write image to file + virtual bool writeImage(io::IWriteFile *file, IImage *image, u32 param) const _IRR_OVERRIDE_; +}; + +} // namespace video +} // namespace irr + +#endif +#endif // _C_IMAGE_WRITER_BMP_H_INCLUDED__ + diff --git a/source/Irrlicht/CImageWriterJPG.cpp b/source/Irrlicht/CImageWriterJPG.cpp new file mode 100644 index 00000000..3e3b4d57 --- /dev/null +++ b/source/Irrlicht/CImageWriterJPG.cpp @@ -0,0 +1,226 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CImageWriterJPG.h" + +#ifdef _IRR_COMPILE_WITH_JPG_WRITER_ + +#include "CColorConverter.h" +#include "IWriteFile.h" +#include "CImage.h" +#include "irrString.h" + +#ifdef _IRR_COMPILE_WITH_LIBJPEG_ +#include // required for jpeglib.h +extern "C" +{ +#ifndef _IRR_USE_NON_SYSTEM_JPEG_LIB_ + #include + #include +#else + #include "jpeglib/jpeglib.h" + #include "jpeglib/jerror.h" +#endif +} + + +namespace irr +{ +namespace video +{ + +// The writer uses a 4k buffer and flushes to disk each time it's filled +#define OUTPUT_BUF_SIZE 4096 +typedef struct +{ + struct jpeg_destination_mgr pub;/* public fields */ + + io::IWriteFile* file; /* target file */ + JOCTET buffer[OUTPUT_BUF_SIZE]; /* image buffer */ +} mem_destination_mgr; + + +typedef mem_destination_mgr * mem_dest_ptr; + + +// init +static void jpeg_init_destination(j_compress_ptr cinfo) +{ + mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest; + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + + +// flush to disk and reset buffer +static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo) +{ + mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest; + + // for now just exit upon file error + if (dest->file->write(dest->buffer, OUTPUT_BUF_SIZE) != OUTPUT_BUF_SIZE) + ERREXIT (cinfo, JERR_FILE_WRITE); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + + return TRUE; +} + + +static void jpeg_term_destination(j_compress_ptr cinfo) +{ + mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest; + const size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + // for now just exit upon file error + if (dest->file->write(dest->buffer, datacount) != datacount) + ERREXIT (cinfo, JERR_FILE_WRITE); +} + + +// set up buffer data +static void jpeg_file_dest(j_compress_ptr cinfo, io::IWriteFile* file) +{ + if (cinfo->dest == NULL) + { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, + JPOOL_PERMANENT, + sizeof(mem_destination_mgr)); + } + + mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest; /* for casting */ + + /* Initialize method pointers */ + dest->pub.init_destination = jpeg_init_destination; + dest->pub.empty_output_buffer = jpeg_empty_output_buffer; + dest->pub.term_destination = jpeg_term_destination; + + /* Initialize private member */ + dest->file = file; +} + + +/* write_JPEG_memory: store JPEG compressed image into memory. +*/ +static bool writeJPEGFile(io::IWriteFile* file, IImage* image, u32 quality) +{ + void (*format)(const void*, s32, void*) = 0; + switch( image->getColorFormat () ) + { + case ECF_R8G8B8: + format = CColorConverter::convert_R8G8B8toR8G8B8; + break; + case ECF_A8R8G8B8: + format = CColorConverter::convert_A8R8G8B8toR8G8B8; + break; + case ECF_A1R5G5B5: + format = CColorConverter::convert_A1R5G5B5toB8G8R8; + break; + case ECF_R5G6B5: + format = CColorConverter::convert_R5G6B5toR8G8B8; + break; + default: + break; + } + + // couldn't find a color converter + if ( 0 == format ) + return false; + + const core::dimension2du dim = image->getDimension(); + + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + cinfo.err = jpeg_std_error(&jerr); + + jpeg_create_compress(&cinfo); + jpeg_file_dest(&cinfo, file); + cinfo.image_width = dim.Width; + cinfo.image_height = dim.Height; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + + jpeg_set_defaults(&cinfo); + + if ( 0 == quality ) + quality = 75; + + jpeg_set_quality(&cinfo, quality, TRUE); + jpeg_start_compress(&cinfo, TRUE); + + u8 * dest = new u8[dim.Width*3]; + + if (dest) + { + const u32 pitch = image->getPitch(); + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ + row_pointer[0] = dest; + + u8* src = (u8*)image->getData(); + + while (cinfo.next_scanline < cinfo.image_height) + { + // convert next line + format( src, dim.Width, dest ); + src += pitch; + jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + delete [] dest; + + /* Step 6: Finish compression */ + jpeg_finish_compress(&cinfo); + } + + /* Step 7: Destroy */ + jpeg_destroy_compress(&cinfo); + + return (dest != 0); +} + + +} // namespace video +} // namespace irr + +#endif // _IRR_COMPILE_WITH_LIBJPEG_ + +namespace irr +{ +namespace video +{ + +IImageWriter* createImageWriterJPG() +{ + return new CImageWriterJPG; +} + +CImageWriterJPG::CImageWriterJPG() +{ +#ifdef _DEBUG + setDebugName("CImageWriterJPG"); +#endif +} + + +bool CImageWriterJPG::isAWriteableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "jpg", "jpeg" ); +} + + +bool CImageWriterJPG::writeImage(io::IWriteFile *file, IImage *image, u32 quality) const +{ +#ifndef _IRR_COMPILE_WITH_LIBJPEG_ + return false; +#else + return writeJPEGFile(file, image, quality); +#endif +} + +} // namespace video +} // namespace irr + +#endif + diff --git a/source/Irrlicht/CImageWriterJPG.h b/source/Irrlicht/CImageWriterJPG.h new file mode 100644 index 00000000..e9d01385 --- /dev/null +++ b/source/Irrlicht/CImageWriterJPG.h @@ -0,0 +1,37 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef _C_IMAGE_WRITER_JPG_H_INCLUDED__ +#define _C_IMAGE_WRITER_JPG_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_JPG_WRITER_ + +#include "IImageWriter.h" + +namespace irr +{ +namespace video +{ + +class CImageWriterJPG : public IImageWriter +{ +public: + //! constructor + CImageWriterJPG(); + + //! return true if this writer can write a file with the given extension + virtual bool isAWriteableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! write image to file + virtual bool writeImage(io::IWriteFile *file, IImage *image, u32 param) const _IRR_OVERRIDE_; +}; + +} +} + +#endif // _C_IMAGE_WRITER_JPG_H_INCLUDED__ +#endif + diff --git a/source/Irrlicht/CImageWriterPCX.cpp b/source/Irrlicht/CImageWriterPCX.cpp new file mode 100644 index 00000000..5ace3426 --- /dev/null +++ b/source/Irrlicht/CImageWriterPCX.cpp @@ -0,0 +1,162 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CImageWriterPCX.h" + +#ifdef _IRR_COMPILE_WITH_PCX_WRITER_ + +#include "CImageLoaderPCX.h" +#include "IWriteFile.h" +#include "os.h" // for logging +#include "irrString.h" + +namespace irr +{ +namespace video +{ + +IImageWriter* createImageWriterPCX() +{ + return new CImageWriterPCX; +} + +CImageWriterPCX::CImageWriterPCX() +{ +#ifdef _DEBUG + setDebugName("CImageWriterPCX"); +#endif +} + +bool CImageWriterPCX::isAWriteableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "pcx" ); +} + +bool CImageWriterPCX::writeImage(io::IWriteFile *file, IImage *image,u32 param) const +{ + if (!file || !image) + return false; + + u8 d1; + u16 d2; + u32 i; + + d1 = 10; // Manufacturer + file->write(&d1, 1); + d1 = 5; // Version + file->write(&d1, 1); + d1 = 1; // Encoding + file->write(&d1, 1); + d1 = 8; // Bits per Pixel + file->write(&d1, 1); + d2 = 0; // pixel origin + file->write(&d2, 2); + file->write(&d2, 2); + d2 = image->getDimension().Width-1; // width +#ifdef __BIG_ENDIAN__ + d2 = os::Byteswap::byteswap(d2); +#endif + file->write(&d2, 2); + d2 = image->getDimension().Height-1; // height +#ifdef __BIG_ENDIAN__ + d2 = os::Byteswap::byteswap(d2); +#endif + file->write(&d2, 2); + d2 = 300; // dpi +#ifdef __BIG_ENDIAN__ + d2 = os::Byteswap::byteswap(d2); +#endif + file->write(&d2, 2); + file->write(&d2, 2); + d2 = 0; // palette (not used) + for (i=0; i<24; ++i) + { + file->write(&d2, 2); + } + d1 = 0; // reserved + file->write(&d1, 1); + d1 = 3; // planes + file->write(&d1, 1); + d2 = image->getDimension().Width; // pitch + if (d2&0x0001) // must be even + ++d2; +#ifdef __BIG_ENDIAN__ + d2 = os::Byteswap::byteswap(d2); +#endif + file->write(&d2, 2); + d2 = 1; // color mode +#ifdef __BIG_ENDIAN__ + d2 = os::Byteswap::byteswap(d2); +#endif + file->write(&d2, 2); + d2 = 800; // screen width +#ifdef __BIG_ENDIAN__ + d2 = os::Byteswap::byteswap(d2); +#endif + file->write(&d2, 2); + d2 = 600; // screen height +#ifdef __BIG_ENDIAN__ + d2 = os::Byteswap::byteswap(d2); +#endif + file->write(&d2, 2); + d2 = 0; // filler (not used) + for (i=0; i<27; ++i) + { + file->write(&d2, 2); + } + + u8 cnt, value; + for (i=0; igetDimension().Height; ++i) + { + cnt = 0; + value = 0; + for (u32 j=0; j<3; ++j) // color planes + { + for (u32 k=0; kgetDimension().Width; ++k) + { + const SColor pix = image->getPixel(k,i); + if ((cnt!=0) && (cnt<63) && + (((j==0) && (value==pix.getRed())) || + ((j==1) && (value==pix.getGreen())) || + ((j==2) && (value==pix.getBlue())))) + { + ++cnt; + } + else + { + if (cnt!=0) + { + if ((cnt>1) || ((value&0xc0)==0xc0)) + { + cnt |= 0xc0; + file->write(&cnt, 1); + } + file->write(&value, 1); + } + cnt=1; + if (j==0) + value=(u8)pix.getRed(); + else if (j==1) + value=(u8)pix.getGreen(); + else if (j==2) + value=(u8)pix.getBlue(); + } + } + } + if ((cnt>1) || ((value&0xc0)==0xc0)) + { + cnt |= 0xc0; + file->write(&cnt, 1); + } + file->write(&value, 1); + } + + return true; +} + +} // namespace video +} // namespace irr + +#endif + diff --git a/source/Irrlicht/CImageWriterPCX.h b/source/Irrlicht/CImageWriterPCX.h new file mode 100644 index 00000000..b819d119 --- /dev/null +++ b/source/Irrlicht/CImageWriterPCX.h @@ -0,0 +1,37 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef _C_IMAGE_WRITER_PCX_H_INCLUDED__ +#define _C_IMAGE_WRITER_PCX_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_PCX_WRITER_ + +#include "IImageWriter.h" + +namespace irr +{ +namespace video +{ + +class CImageWriterPCX : public IImageWriter +{ +public: + //! constructor + CImageWriterPCX(); + + //! return true if this writer can write a file with the given extension + virtual bool isAWriteableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! write image to file + virtual bool writeImage(io::IWriteFile *file, IImage *image, u32 param) const _IRR_OVERRIDE_; +}; + +} // namespace video +} // namespace irr + +#endif +#endif // _C_IMAGE_WRITER_PCX_H_INCLUDED__ + diff --git a/source/Irrlicht/CImageWriterPNG.cpp b/source/Irrlicht/CImageWriterPNG.cpp new file mode 100644 index 00000000..5c2ead81 --- /dev/null +++ b/source/Irrlicht/CImageWriterPNG.cpp @@ -0,0 +1,219 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CImageWriterPNG.h" + +#ifdef _IRR_COMPILE_WITH_PNG_WRITER_ + +#include "CImageLoaderPNG.h" +#include "CColorConverter.h" +#include "IWriteFile.h" +#include "irrString.h" +#include "os.h" // for logging + +#ifdef _IRR_COMPILE_WITH_LIBPNG_ +#ifndef _IRR_USE_NON_SYSTEM_LIB_PNG_ + #include // use system lib png +#else // _IRR_USE_NON_SYSTEM_LIB_PNG_ + #include "libpng/png.h" // use irrlicht included lib png +#endif // _IRR_USE_NON_SYSTEM_LIB_PNG_ +#endif // _IRR_COMPILE_WITH_LIBPNG_ + +namespace irr +{ +namespace video +{ + +IImageWriter* createImageWriterPNG() +{ + return new CImageWriterPNG; +} + +#ifdef _IRR_COMPILE_WITH_LIBPNG_ +// PNG function for error handling +static void png_cpexcept_error(png_structp png_ptr, png_const_charp msg) +{ + os::Printer::log("PNG fatal error", msg, ELL_ERROR); + longjmp(png_jmpbuf(png_ptr), 1); +} + +// PNG function for warning handling +static void png_cpexcept_warning(png_structp png_ptr, png_const_charp msg) +{ + os::Printer::log("PNG warning", msg, ELL_WARNING); +} + +// PNG function for file writing +void PNGAPI user_write_data_fcn(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check; + + io::IWriteFile* file=(io::IWriteFile*)png_get_io_ptr(png_ptr); + check=(png_size_t) file->write((const void*)data,(u32)length); + + if (check != length) + png_error(png_ptr, "Write Error"); +} +#endif // _IRR_COMPILE_WITH_LIBPNG_ + +CImageWriterPNG::CImageWriterPNG() +{ +#ifdef _DEBUG + setDebugName("CImageWriterPNG"); +#endif +} + +bool CImageWriterPNG::isAWriteableFileExtension(const io::path& filename) const +{ +#ifdef _IRR_COMPILE_WITH_LIBPNG_ + return core::hasFileExtension ( filename, "png" ); +#else + return false; +#endif +} + +bool CImageWriterPNG::writeImage(io::IWriteFile* file, IImage* image,u32 param) const +{ +#ifdef _IRR_COMPILE_WITH_LIBPNG_ + if (!file || !image) + return false; + + // Allocate the png write struct + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, (png_error_ptr)png_cpexcept_error, (png_error_ptr)png_cpexcept_warning); + if (!png_ptr) + { + os::Printer::log("PNGWriter: Internal PNG create write struct failure\n", file->getFileName(), ELL_ERROR); + return false; + } + + // Allocate the png info struct + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + os::Printer::log("PNGWriter: Internal PNG create info struct failure\n", file->getFileName(), ELL_ERROR); + png_destroy_write_struct(&png_ptr, NULL); + return false; + } + + // for proper error handling + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_write_struct(&png_ptr, &info_ptr); + return false; + } + + png_set_write_fn(png_ptr, file, user_write_data_fcn, NULL); + + // Set info + switch(image->getColorFormat()) + { + case ECF_A8R8G8B8: + case ECF_A1R5G5B5: + png_set_IHDR(png_ptr, info_ptr, + image->getDimension().Width, image->getDimension().Height, + 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + break; + default: + png_set_IHDR(png_ptr, info_ptr, + image->getDimension().Width, image->getDimension().Height, + 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + } + + s32 lineWidth = image->getDimension().Width; + switch(image->getColorFormat()) + { + case ECF_R8G8B8: + case ECF_R5G6B5: + lineWidth*=3; + break; + case ECF_A8R8G8B8: + case ECF_A1R5G5B5: + lineWidth*=4; + break; + // TODO: Error handling in case of unsupported color format + default: + break; + } + u8* tmpImage = new u8[image->getDimension().Height*lineWidth]; + if (!tmpImage) + { + os::Printer::log("PNGWriter: Internal PNG create image failure\n", file->getFileName(), ELL_ERROR); + png_destroy_write_struct(&png_ptr, &info_ptr); + return false; + } + + u8* data = (u8*)image->getData(); + switch(image->getColorFormat()) + { + case ECF_R8G8B8: + CColorConverter::convert_R8G8B8toR8G8B8(data,image->getDimension().Height*image->getDimension().Width,tmpImage); + break; + case ECF_A8R8G8B8: + CColorConverter::convert_A8R8G8B8toA8R8G8B8(data,image->getDimension().Height*image->getDimension().Width,tmpImage); + break; + case ECF_R5G6B5: + CColorConverter::convert_R5G6B5toR8G8B8(data,image->getDimension().Height*image->getDimension().Width,tmpImage); + break; + case ECF_A1R5G5B5: + CColorConverter::convert_A1R5G5B5toA8R8G8B8(data,image->getDimension().Height*image->getDimension().Width,tmpImage); + break; + // TODO: Error handling in case of unsupported color format + default: + break; + } + + // Create array of pointers to rows in image data + + //Used to point to image rows + u8** RowPointers = new png_bytep[image->getDimension().Height]; + if (!RowPointers) + { + os::Printer::log("PNGWriter: Internal PNG create row pointers failure\n", file->getFileName(), ELL_ERROR); + png_destroy_write_struct(&png_ptr, &info_ptr); + delete [] tmpImage; + return false; + } + + data=tmpImage; + // Fill array of pointers to rows in image data + for (u32 i=0; igetDimension().Height; ++i) + { + RowPointers[i]=data; + data += lineWidth; + } + // for proper error handling + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_write_struct(&png_ptr, &info_ptr); + delete [] RowPointers; + delete [] tmpImage; + return false; + } + + png_set_rows(png_ptr, info_ptr, RowPointers); + + if (image->getColorFormat()==ECF_A8R8G8B8 || image->getColorFormat()==ECF_A1R5G5B5) + png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_BGR, NULL); + else + { + png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + } + + delete [] RowPointers; + delete [] tmpImage; + png_destroy_write_struct(&png_ptr, &info_ptr); + return true; +#else + return false; +#endif +} + +} // namespace video +} // namespace irr + +#endif + diff --git a/source/Irrlicht/CImageWriterPNG.h b/source/Irrlicht/CImageWriterPNG.h new file mode 100644 index 00000000..37e4953d --- /dev/null +++ b/source/Irrlicht/CImageWriterPNG.h @@ -0,0 +1,37 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef _C_IMAGE_WRITER_PNG_H_INCLUDED__ +#define _C_IMAGE_WRITER_PNG_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_PNG_WRITER_ + +#include "IImageWriter.h" + +namespace irr +{ +namespace video +{ + +class CImageWriterPNG : public IImageWriter +{ +public: + //! constructor + CImageWriterPNG(); + + //! return true if this writer can write a file with the given extension + virtual bool isAWriteableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! write image to file + virtual bool writeImage(io::IWriteFile *file, IImage *image, u32 param) const _IRR_OVERRIDE_; +}; + +} // namespace video +} // namespace irr + +#endif // _C_IMAGE_WRITER_PNG_H_INCLUDED__ +#endif + diff --git a/source/Irrlicht/CImageWriterPPM.cpp b/source/Irrlicht/CImageWriterPPM.cpp new file mode 100644 index 00000000..fd0db971 --- /dev/null +++ b/source/Irrlicht/CImageWriterPPM.cpp @@ -0,0 +1,113 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CImageWriterPPM.h" + +#ifdef _IRR_COMPILE_WITH_PPM_WRITER_ + +#include "IWriteFile.h" +#include "IImage.h" +#include "dimension2d.h" +#include "irrString.h" + +namespace irr +{ +namespace video +{ + + +IImageWriter* createImageWriterPPM() +{ + return new CImageWriterPPM; +} + + +CImageWriterPPM::CImageWriterPPM() +{ +#ifdef _DEBUG + setDebugName("CImageWriterPPM"); +#endif +} + + +bool CImageWriterPPM::isAWriteableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "ppm" ); +} + + +bool CImageWriterPPM::writeImage(io::IWriteFile *file, IImage *image, u32 param) const +{ + char cache[70]; + int size; + + const core::dimension2d& imageSize = image->getDimension(); + + const bool binary = false; + + if (binary) + size = snprintf_irr(cache, 70, "P6\n"); + else + size = snprintf_irr(cache, 70, "P3\n"); + if ( size < 0 ) + return false; + + if (file->write(cache, (size_t)size) != (size_t)size) + return false; + + size = snprintf_irr(cache, 70, "%u %u\n", imageSize.Width, imageSize.Height); + if ( size < 0 ) + return false; + if (file->write(cache, (size_t)size) != (size_t)size) + return false; + + size = snprintf_irr(cache, 70, "255\n"); + if ( size < 0 ) + return false; + if (file->write(cache, (size_t)size) != (size_t)size) + return false; + + if (binary) + { + for (u32 h = 0; h < imageSize.Height; ++h) + { + for (u32 c = 0; c < imageSize.Width; ++c) + { + const video::SColor& pixel = image->getPixel(c, h); + const u8 r = (u8)(pixel.getRed() & 0xff); + const u8 g = (u8)(pixel.getGreen() & 0xff); + const u8 b = (u8)(pixel.getBlue() & 0xff); + file->write(&r, 1); + file->write(&g, 1); + file->write(&b, 1); + } + } + } + else + { + s32 n = 0; + + for (u32 h = 0; h < imageSize.Height; ++h) + { + for (u32 c = 0; c < imageSize.Width; ++c, ++n) + { + const video::SColor& pixel = image->getPixel(c, h); + size = snprintf_irr(cache, 70, "%.3u %.3u %.3u%s", pixel.getRed(), pixel.getGreen(), pixel.getBlue(), n % 5 == 4 ? "\n" : " "); + if ( size < 0 ) + return false; + if (file->write(cache, (size_t)size) != (size_t)size) + return false; + } + } + } + + return true; +} + + +} // namespace video +} // namespace irr + +#endif + diff --git a/source/Irrlicht/CImageWriterPPM.h b/source/Irrlicht/CImageWriterPPM.h new file mode 100644 index 00000000..c7df272d --- /dev/null +++ b/source/Irrlicht/CImageWriterPPM.h @@ -0,0 +1,37 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef _C_IMAGE_WRITER_PPM_H_INCLUDED__ +#define _C_IMAGE_WRITER_PPM_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_PPM_WRITER_ + +#include "IImageWriter.h" + +namespace irr +{ +namespace video +{ + +class CImageWriterPPM : public IImageWriter +{ +public: + //! constructor + CImageWriterPPM(); + + //! return true if this writer can write a file with the given extension + virtual bool isAWriteableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! write image to file + virtual bool writeImage(io::IWriteFile *file, IImage *image, u32 param) const _IRR_OVERRIDE_; +}; + +} // namespace video +} // namespace irr + +#endif // _C_IMAGE_WRITER_PPM_H_INCLUDED__ +#endif + diff --git a/source/Irrlicht/CImageWriterPSD.cpp b/source/Irrlicht/CImageWriterPSD.cpp new file mode 100644 index 00000000..952eb0b3 --- /dev/null +++ b/source/Irrlicht/CImageWriterPSD.cpp @@ -0,0 +1,46 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CImageWriterPSD.h" + +#ifdef _IRR_COMPILE_WITH_PSD_WRITER_ + +#include "CImageLoaderPSD.h" +#include "IWriteFile.h" +#include "os.h" // for logging +#include "irrString.h" + +namespace irr +{ +namespace video +{ + +IImageWriter* createImageWriterPSD() +{ + return new CImageWriterPSD; +} + +CImageWriterPSD::CImageWriterPSD() +{ +#ifdef _DEBUG + setDebugName("CImageWriterPSD"); +#endif +} + +bool CImageWriterPSD::isAWriteableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "psd" ); +} + +bool CImageWriterPSD::writeImage(io::IWriteFile *file, IImage *image,u32 param) const +{ + os::Printer::log("PSD writer not yet implemented. Image not written.", ELL_WARNING); + return false; +} + +} // namespace video +} // namespace irr + +#endif + diff --git a/source/Irrlicht/CImageWriterPSD.h b/source/Irrlicht/CImageWriterPSD.h new file mode 100644 index 00000000..2ca92ded --- /dev/null +++ b/source/Irrlicht/CImageWriterPSD.h @@ -0,0 +1,37 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef _C_IMAGE_WRITER_PSD_H_INCLUDED__ +#define _C_IMAGE_WRITER_PSD_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_PSD_WRITER_ + +#include "IImageWriter.h" + +namespace irr +{ +namespace video +{ + +class CImageWriterPSD : public IImageWriter +{ +public: + //! constructor + CImageWriterPSD(); + + //! return true if this writer can write a file with the given extension + virtual bool isAWriteableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! write image to file + virtual bool writeImage(io::IWriteFile *file, IImage *image,u32 param) const _IRR_OVERRIDE_; +}; + +} // namespace video +} // namespace irr + +#endif // _I_IMAGE_WRITER_PSD_H_INCLUDED__ +#endif + diff --git a/source/Irrlicht/CImageWriterTGA.cpp b/source/Irrlicht/CImageWriterTGA.cpp new file mode 100644 index 00000000..e5632b5a --- /dev/null +++ b/source/Irrlicht/CImageWriterTGA.cpp @@ -0,0 +1,143 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CImageWriterTGA.h" + +#ifdef _IRR_COMPILE_WITH_TGA_WRITER_ + +#include "CImageLoaderTGA.h" +#include "IWriteFile.h" +#include "CColorConverter.h" +#include "irrString.h" + +namespace irr +{ +namespace video +{ + +IImageWriter* createImageWriterTGA() +{ + return new CImageWriterTGA; +} + +CImageWriterTGA::CImageWriterTGA() +{ +#ifdef _DEBUG + setDebugName("CImageWriterTGA"); +#endif +} + +bool CImageWriterTGA::isAWriteableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "tga" ); +} + +bool CImageWriterTGA::writeImage(io::IWriteFile *file, IImage *image,u32 param) const +{ + STGAHeader imageHeader; + imageHeader.IdLength = 0; + imageHeader.ColorMapType = 0; + imageHeader.ImageType = 2; + imageHeader.FirstEntryIndex[0] = 0; + imageHeader.FirstEntryIndex[1] = 0; + imageHeader.ColorMapLength = 0; + imageHeader.ColorMapEntrySize = 0; + imageHeader.XOrigin[0] = 0; + imageHeader.XOrigin[1] = 0; + imageHeader.YOrigin[0] = 0; + imageHeader.YOrigin[1] = 0; + imageHeader.ImageWidth = image->getDimension().Width; + imageHeader.ImageHeight = image->getDimension().Height; + + // top left of image is the top. the image loader needs to + // be fixed to only swap/flip + imageHeader.ImageDescriptor = (1 << 5); + + // chances are good we'll need to swizzle data, so i'm going + // to convert and write one scan line at a time. it's also + // a bit cleaner this way + void (*CColorConverter_convertFORMATtoFORMAT)(const void*, s32, void*) = 0; + switch(image->getColorFormat()) + { + case ECF_A8R8G8B8: + CColorConverter_convertFORMATtoFORMAT + = CColorConverter::convert_A8R8G8B8toA8R8G8B8; + imageHeader.PixelDepth = 32; + imageHeader.ImageDescriptor |= 8; + break; + case ECF_A1R5G5B5: + CColorConverter_convertFORMATtoFORMAT + = CColorConverter::convert_A1R5G5B5toA1R5G5B5; + imageHeader.PixelDepth = 16; + imageHeader.ImageDescriptor |= 1; + break; + case ECF_R5G6B5: + CColorConverter_convertFORMATtoFORMAT + = CColorConverter::convert_R5G6B5toA1R5G5B5; + imageHeader.PixelDepth = 16; + imageHeader.ImageDescriptor |= 1; + break; + case ECF_R8G8B8: + CColorConverter_convertFORMATtoFORMAT + = CColorConverter::convert_R8G8B8toR8G8B8; + imageHeader.PixelDepth = 24; + imageHeader.ImageDescriptor |= 0; + break; + default: + break; + } + + // couldn't find a color converter + if (!CColorConverter_convertFORMATtoFORMAT) + return false; + + if (file->write(&imageHeader, sizeof(imageHeader)) != sizeof(imageHeader)) + return false; + + u8* scan_lines = (u8*)image->getData(); + if (!scan_lines) + return false; + + // size of one pixel in bytes + u32 pixel_size = image->getBytesPerPixel(); + + // length of one row of the source image in bytes + u32 row_stride = (pixel_size * imageHeader.ImageWidth); + + // length of one output row in bytes + size_t row_size = ((imageHeader.PixelDepth / 8) * imageHeader.ImageWidth); + + // allocate a row do translate data into + u8* row_pointer = new u8[row_size]; + + u32 y; + for (y = 0; y < imageHeader.ImageHeight; ++y) + { + // source, length [pixels], destination + if (image->getColorFormat()==ECF_R8G8B8) + CColorConverter::convert24BitTo24Bit(&scan_lines[y * row_stride], row_pointer, imageHeader.ImageWidth, 1, 0, 0, true); + else + CColorConverter_convertFORMATtoFORMAT(&scan_lines[y * row_stride], imageHeader.ImageWidth, row_pointer); + if (file->write(row_pointer, row_size) != row_size) + break; + } + + delete [] row_pointer; + + STGAFooter imageFooter; + imageFooter.ExtensionOffset = 0; + imageFooter.DeveloperOffset = 0; + strncpy(imageFooter.Signature, "TRUEVISION-XFILE.", 18); + + if (file->write(&imageFooter, sizeof(imageFooter)) < (s32)sizeof(imageFooter)) + return false; + + return imageHeader.ImageHeight <= y; +} + +} // namespace video +} // namespace irr + +#endif + diff --git a/source/Irrlicht/CImageWriterTGA.h b/source/Irrlicht/CImageWriterTGA.h new file mode 100644 index 00000000..0d3fd3d7 --- /dev/null +++ b/source/Irrlicht/CImageWriterTGA.h @@ -0,0 +1,37 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef _C_IMAGE_WRITER_TGA_H_INCLUDED__ +#define _C_IMAGE_WRITER_TGA_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_TGA_WRITER_ + +#include "IImageWriter.h" + +namespace irr +{ +namespace video +{ + +class CImageWriterTGA : public IImageWriter +{ +public: + //! constructor + CImageWriterTGA(); + + //! return true if this writer can write a file with the given extension + virtual bool isAWriteableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! write image to file + virtual bool writeImage(io::IWriteFile *file, IImage *image,u32 param) const _IRR_OVERRIDE_; +}; + +} // namespace video +} // namespace irr + +#endif // _C_IMAGE_WRITER_TGA_H_INCLUDED__ +#endif + diff --git a/source/Irrlicht/CIrrDeviceConsole.cpp b/source/Irrlicht/CIrrDeviceConsole.cpp new file mode 100644 index 00000000..8a2414a3 --- /dev/null +++ b/source/Irrlicht/CIrrDeviceConsole.cpp @@ -0,0 +1,477 @@ +// Copyright (C) 2009-2012 Gaz Davidson +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CIrrDeviceConsole.h" + +#ifdef _IRR_COMPILE_WITH_CONSOLE_DEVICE_ + +#include "os.h" +#include "IGUISkin.h" +#include "IGUIEnvironment.h" + +// to close the device on terminate signal +irr::CIrrDeviceConsole *DeviceToClose; + +#ifdef _IRR_WINDOWS_NT_CONSOLE_ +// Callback for Windows +BOOL WINAPI ConsoleHandler(DWORD CEvent) +{ + switch(CEvent) + { + case CTRL_C_EVENT: + irr::os::Printer::log("Closing console device", "CTRL+C"); + break; + case CTRL_BREAK_EVENT: + irr::os::Printer::log("Closing console device", "CTRL+Break"); + break; + case CTRL_CLOSE_EVENT: + irr::os::Printer::log("Closing console device", "User closed console"); + break; + case CTRL_LOGOFF_EVENT: + irr::os::Printer::log("Closing console device", "User is logging off"); + break; + case CTRL_SHUTDOWN_EVENT: + irr::os::Printer::log("Closing console device", "Computer shutting down"); + break; + } + DeviceToClose->closeDevice(); + return TRUE; +} +#elif defined(_IRR_POSIX_API_) +// sigterm handler +#include + +void sighandler(int sig) +{ + irr::core::stringc code = "Signal "; + code += sig; + code += " received"; + irr::os::Printer::log("Closing console device", code.c_str()); + + DeviceToClose->closeDevice(); +} +#endif + +namespace irr +{ + +const c8 ASCIIArtChars[] = " .,'~:;!+>=icopjtJY56SB8XDQKHNWM"; //MWNHKQDX8BS65YJtjpoci=+>!;:~',. "; +const u16 ASCIIArtCharsCount = 32; + +//const c8 ASCIIArtChars[] = " \xb0\xb1\xf9\xb2\xdb"; +//const u16 ASCIIArtCharsCount = 5; + +//! constructor +CIrrDeviceConsole::CIrrDeviceConsole(const SIrrlichtCreationParameters& params) + : CIrrDeviceStub(params), IsWindowFocused(true), ConsoleFont(0), OutFile(stdout) +{ + DeviceToClose = this; + +#ifdef _IRR_WINDOWS_NT_CONSOLE_ + MouseButtonStates = 0; + + WindowsSTDIn = GetStdHandle(STD_INPUT_HANDLE); + WindowsSTDOut = GetStdHandle(STD_OUTPUT_HANDLE); + + if (CreationParams.Fullscreen) + { +// Some mingw versions lack this define, so avoid it in case it does not exist +#if (_WIN32_WINNT >= 0x0501) && defined(CONSOLE_FULLSCREEN_MODE) + PCOORD dimensions = 0; + if (SetConsoleDisplayMode(WindowsSTDOut, CONSOLE_FULLSCREEN_MODE, dimensions)) + { + CreationParams.WindowSize.Width = dimensions->X; + CreationParams.WindowSize.Width = dimensions->Y; + } +#endif + } + else + { + COORD ConsoleSize; + ConsoleSize.X = CreationParams.WindowSize.Width; + ConsoleSize.X = CreationParams.WindowSize.Height; + SetConsoleScreenBufferSize(WindowsSTDOut, ConsoleSize); + } + + // catch windows close/break signals + SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleHandler, TRUE); + +#elif defined(_IRR_POSIX_API_) + // catch other signals + signal(SIGABRT, &sighandler); + signal(SIGTERM, &sighandler); + signal(SIGINT, &sighandler); + + // set output stream + if (params.WindowId) + OutFile = (FILE*)(params.WindowId); +#endif + +#ifdef _IRR_VT100_CONSOLE_ + // reset terminal + fprintf(OutFile, "%cc", 27); + // disable line wrapping + fprintf(OutFile, "%c[7l", 27); +#endif + + switch (params.DriverType) + { + case video::EDT_SOFTWARE: + #ifdef _IRR_COMPILE_WITH_SOFTWARE_ + VideoDriver = video::createSoftwareDriver(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this); + #else + os::Printer::log("Software driver was not compiled in.", ELL_ERROR); + #endif + break; + + case video::EDT_BURNINGSVIDEO: + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + VideoDriver = video::createBurningVideoDriver(CreationParams, FileSystem, this); + #else + os::Printer::log("Burning's Video driver was not compiled in.", ELL_ERROR); + #endif + break; + + case video::EDT_DIRECT3D9: + case video::EDT_OPENGL: + os::Printer::log("The console device cannot use hardware drivers yet.", ELL_ERROR); + break; + case video::EDT_NULL: + VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize); + break; + default: + os::Printer::log("Unsupported device.", ELL_ERROR); + break; + } + + // set up output buffer + for (u32 y=0; ygetSkin(); + if (skin) + { + for (u32 i=0; i < gui::EGDF_COUNT; ++i) + skin->setFont(ConsoleFont, gui::EGUI_DEFAULT_FONT(i)); + } + } +#endif + } +} + +//! destructor +CIrrDeviceConsole::~CIrrDeviceConsole() +{ + // GUI and scene are dropped in the stub + if (CursorControl) + { + CursorControl->drop(); + CursorControl = 0; + } + if (ConsoleFont) + { + ConsoleFont->drop(); + ConsoleFont = 0; + } +#ifdef _IRR_VT100_CONSOLE_ + // reset terminal + fprintf(OutFile, "%cc", 27); +#endif +} + +//! runs the device. Returns false if device wants to be deleted +bool CIrrDeviceConsole::run() +{ + // increment timer + os::Timer::tick(); + + // process Windows console input +#ifdef _IRR_WINDOWS_NT_CONSOLE_ + + INPUT_RECORD in; + DWORD oldMode; + DWORD count, waste; + + // get old input mode + GetConsoleMode(WindowsSTDIn, &oldMode); + SetConsoleMode(WindowsSTDIn, ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT); + + GetNumberOfConsoleInputEvents(WindowsSTDIn, &count); + + // read keyboard and mouse input + while (count) + { + ReadConsoleInput(WindowsSTDIn, &in, 1, &waste ); + switch(in.EventType) + { + case KEY_EVENT: + { + SEvent e; + e.EventType = EET_KEY_INPUT_EVENT; + e.KeyInput.PressedDown = (in.Event.KeyEvent.bKeyDown == TRUE); + e.KeyInput.Control = (in.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0; + e.KeyInput.Shift = (in.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) != 0; + e.KeyInput.Key = EKEY_CODE(in.Event.KeyEvent.wVirtualKeyCode); + e.KeyInput.Char = in.Event.KeyEvent.uChar.UnicodeChar; + postEventFromUser(e); + break; + } + case MOUSE_EVENT: + { + SEvent e; + e.EventType = EET_MOUSE_INPUT_EVENT; + e.MouseInput.X = in.Event.MouseEvent.dwMousePosition.X; + e.MouseInput.Y = in.Event.MouseEvent.dwMousePosition.Y; + e.MouseInput.Wheel = 0.f; + e.MouseInput.ButtonStates = + ( (in.Event.MouseEvent.dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED) ? EMBSM_LEFT : 0 ) | + ( (in.Event.MouseEvent.dwButtonState & RIGHTMOST_BUTTON_PRESSED) ? EMBSM_RIGHT : 0 ) | + ( (in.Event.MouseEvent.dwButtonState & FROM_LEFT_2ND_BUTTON_PRESSED) ? EMBSM_MIDDLE : 0 ) | + ( (in.Event.MouseEvent.dwButtonState & FROM_LEFT_3RD_BUTTON_PRESSED) ? EMBSM_EXTRA1 : 0 ) | + ( (in.Event.MouseEvent.dwButtonState & FROM_LEFT_4TH_BUTTON_PRESSED) ? EMBSM_EXTRA2 : 0 ); + + if (in.Event.MouseEvent.dwEventFlags & MOUSE_MOVED) + { + CursorControl->setPosition(core::position2di(e.MouseInput.X, e.MouseInput.Y)); + + // create mouse moved event + e.MouseInput.Event = EMIE_MOUSE_MOVED; + postEventFromUser(e); + } + + if (in.Event.MouseEvent.dwEventFlags & MOUSE_WHEELED) + { + e.MouseInput.Event = EMIE_MOUSE_WHEEL; + e.MouseInput.Wheel = (in.Event.MouseEvent.dwButtonState & 0xFF000000) ? -1.0f : 1.0f; + postEventFromUser(e); + } + + if ( (MouseButtonStates & EMBSM_LEFT) != (e.MouseInput.ButtonStates & EMBSM_LEFT) ) + { + e.MouseInput.Event = (e.MouseInput.ButtonStates & EMBSM_LEFT) ? EMIE_LMOUSE_PRESSED_DOWN : EMIE_LMOUSE_LEFT_UP; + postEventFromUser(e); + } + + if ( (MouseButtonStates & EMBSM_RIGHT) != (e.MouseInput.ButtonStates & EMBSM_RIGHT) ) + { + e.MouseInput.Event = (e.MouseInput.ButtonStates & EMBSM_RIGHT) ? EMIE_RMOUSE_PRESSED_DOWN : EMIE_RMOUSE_LEFT_UP; + postEventFromUser(e); + } + + if ( (MouseButtonStates & EMBSM_MIDDLE) != (e.MouseInput.ButtonStates & EMBSM_MIDDLE) ) + { + e.MouseInput.Event = (e.MouseInput.ButtonStates & EMBSM_MIDDLE) ? EMIE_MMOUSE_PRESSED_DOWN : EMIE_MMOUSE_LEFT_UP; + postEventFromUser(e); + } + + // save current button states + MouseButtonStates = e.MouseInput.ButtonStates; + + break; + } + case WINDOW_BUFFER_SIZE_EVENT: + VideoDriver->OnResize( + core::dimension2d(in.Event.WindowBufferSizeEvent.dwSize.X, + in.Event.WindowBufferSizeEvent.dwSize.Y)); + break; + case FOCUS_EVENT: + IsWindowFocused = (in.Event.FocusEvent.bSetFocus == TRUE); + break; + default: + break; + } + GetNumberOfConsoleInputEvents(WindowsSTDIn, &count); + } + + // set input mode + SetConsoleMode(WindowsSTDIn, oldMode); +#else + // todo: keyboard input from terminal in raw mode +#endif + + return !Close; +} + +//! Cause the device to temporarily pause execution and let other processes to run +// This should bring down processor usage without major performance loss for Irrlicht +void CIrrDeviceConsole::yield() +{ +#ifdef _IRR_WINDOWS_API_ + Sleep(1); +#else + struct timespec ts = {0,0}; + nanosleep(&ts, NULL); +#endif +} + +//! Pause execution and let other processes to run for a specified amount of time. +void CIrrDeviceConsole::sleep(u32 timeMs, bool pauseTimer) +{ + const bool wasStopped = Timer ? Timer->isStopped() : true; + +#ifdef _IRR_WINDOWS_API_ + Sleep(timeMs); +#else + struct timespec ts; + ts.tv_sec = (time_t) (timeMs / 1000); + ts.tv_nsec = (long) (timeMs % 1000) * 1000000; + + if (pauseTimer && !wasStopped) + Timer->stop(); + + nanosleep(&ts, NULL); +#endif + + if (pauseTimer && !wasStopped) + Timer->start(); +} + +//! sets the caption of the window +void CIrrDeviceConsole::setWindowCaption(const wchar_t* text) +{ +#ifdef _IRR_WINDOWS_NT_CONSOLE_ + SetConsoleTitleW(text); +#endif +} + +//! returns if window is active. if not, nothing need to be drawn +bool CIrrDeviceConsole::isWindowActive() const +{ + // there is no window, but we always assume it is active + return true; +} + +//! returns if window has focus +bool CIrrDeviceConsole::isWindowFocused() const +{ + return IsWindowFocused; +} + +//! returns if window is minimized +bool CIrrDeviceConsole::isWindowMinimized() const +{ + return false; +} + +//! presents a surface in the client area +bool CIrrDeviceConsole::present(video::IImage* surface, void* windowId, core::rect* src) +{ + + if (surface) + { + for (u32 y=0; y < surface->getDimension().Height; ++y) + { + for (u32 x=0; x< surface->getDimension().Width; ++x) + { + // get average pixel + u32 avg = surface->getPixel(x,y).getAverage() * (ASCIIArtCharsCount-1); + avg /= 255; + OutputBuffer[y] [x] = ASCIIArtChars[avg]; + } + } + } +#ifdef _IRR_USE_CONSOLE_FONT_ + for (u32 i=0; i< Text.size(); ++i) + { + s32 y = Text[i].Pos.Y; + + if ( y < (s32)OutputBuffer.size() && y > 0) + for (u32 c=0; c < Text[i].Text.size() && c + Text[i].Pos.X < OutputBuffer[y].size(); ++c) + //if (Text[i].Text[c] != ' ') + OutputBuffer[y] [c+Text[i].Pos.X] = Text[i].Text[c]; + } + Text.clear(); +#endif + + // draw output + for (u32 y=0; y +#endif +#if(_WIN32_WINNT >= 0x0500) +#define _IRR_WINDOWS_NT_CONSOLE_ +#endif +#else +#include +#endif + +// for now we assume all other terminal types are VT100 +#ifndef _IRR_WINDOWS_NT_CONSOLE_ +#define _IRR_VT100_CONSOLE_ +#endif + +namespace irr +{ + + class CIrrDeviceConsole : public CIrrDeviceStub, video::IImagePresenter + { + public: + + //! constructor + CIrrDeviceConsole(const SIrrlichtCreationParameters& params); + + //! destructor + virtual ~CIrrDeviceConsole(); + + //! runs the device. Returns false if device wants to be deleted + virtual bool run() _IRR_OVERRIDE_; + + //! Cause the device to temporarily pause execution and let other processes to run + // This should bring down processor usage without major performance loss for Irrlicht + virtual void yield() _IRR_OVERRIDE_; + + //! Pause execution and let other processes to run for a specified amount of time. + virtual void sleep(u32 timeMs, bool pauseTimer) _IRR_OVERRIDE_; + + //! sets the caption of the window + virtual void setWindowCaption(const wchar_t* text) _IRR_OVERRIDE_; + + //! returns if window is active. if not, nothing need to be drawn + virtual bool isWindowActive() const _IRR_OVERRIDE_; + + //! returns if window has focus + virtual bool isWindowFocused() const _IRR_OVERRIDE_; + + //! returns if window is minimized + virtual bool isWindowMinimized() const _IRR_OVERRIDE_; + + //! returns current window position (not supported for this device) + virtual core::position2di getWindowPosition() _IRR_OVERRIDE_ + { + return core::position2di(-1, -1); + } + + //! presents a surface in the client area + virtual bool present(video::IImage* surface, void* windowId=0, core::rect* src=0) _IRR_OVERRIDE_; + + //! notifies the device that it should close itself + virtual void closeDevice() _IRR_OVERRIDE_; + + //! Sets if the window should be resizable in windowed mode. + virtual void setResizable(bool resize=false) _IRR_OVERRIDE_; + + //! Minimizes the window. + virtual void minimizeWindow() _IRR_OVERRIDE_; + + //! Maximizes the window. + virtual void maximizeWindow() _IRR_OVERRIDE_; + + //! Restores the window size. + virtual void restoreWindow() _IRR_OVERRIDE_; + + //! Get the device type + virtual E_DEVICE_TYPE getType() const _IRR_OVERRIDE_ + { + return EIDT_CONSOLE; + } + + void addPostPresentText(s16 X, s16 Y, const wchar_t *text); + + //! Implementation of the win32 console mouse cursor + class CCursorControl : public gui::ICursorControl + { + public: + + CCursorControl(const core::dimension2d& wsize) + : WindowSize(wsize), InvWindowSize(0.0f, 0.0f), IsVisible(true), UseReferenceRect(false) + { + if (WindowSize.Width!=0) + InvWindowSize.Width = 1.0f / WindowSize.Width; + + if (WindowSize.Height!=0) + InvWindowSize.Height = 1.0f / WindowSize.Height; + } + + //! Changes the visible state of the mouse cursor. + virtual void setVisible(bool visible) _IRR_OVERRIDE_ + { + if(visible != IsVisible) + { + IsVisible = visible; + setPosition(CursorPos.X, CursorPos.Y); + } + } + + //! Returns if the cursor is currently visible. + virtual bool isVisible() const _IRR_OVERRIDE_ + { + return IsVisible; + } + + //! Sets the new position of the cursor. + virtual void setPosition(const core::position2d &pos) _IRR_OVERRIDE_ + { + setPosition(pos.X, pos.Y); + } + + //! Sets the new position of the cursor. + virtual void setPosition(f32 x, f32 y) _IRR_OVERRIDE_ + { + if (!UseReferenceRect) + setPosition((s32)(x*WindowSize.Width), (s32)(y*WindowSize.Height)); + else + setPosition((s32)(x*ReferenceRect.getWidth()), (s32)(y*ReferenceRect.getHeight())); + } + + //! Sets the new position of the cursor. + virtual void setPosition(const core::position2d &pos) _IRR_OVERRIDE_ + { + setPosition(pos.X, pos.Y); + } + + //! Sets the new position of the cursor. + virtual void setPosition(s32 x, s32 y) _IRR_OVERRIDE_ + { + setInternalCursorPosition(core::position2di(x,y)); + } + + //! Returns the current position of the mouse cursor. + virtual const core::position2d& getPosition(bool updateCursor) _IRR_OVERRIDE_ + { + return CursorPos; + } + + //! Returns the current position of the mouse cursor. + virtual core::position2d getRelativePosition(bool updateCursor) _IRR_OVERRIDE_ + { + if (!UseReferenceRect) + { + return core::position2d(CursorPos.X * InvWindowSize.Width, + CursorPos.Y * InvWindowSize.Height); + } + + return core::position2d(CursorPos.X / (f32)ReferenceRect.getWidth(), + CursorPos.Y / (f32)ReferenceRect.getHeight()); + } + + //! Sets an absolute reference rect for calculating the cursor position. + virtual void setReferenceRect(core::rect* rect=0) _IRR_OVERRIDE_ + { + if (rect) + { + ReferenceRect = *rect; + UseReferenceRect = true; + + // prevent division through zero and uneven sizes + + if (!ReferenceRect.getHeight() || ReferenceRect.getHeight()%2) + ReferenceRect.LowerRightCorner.Y += 1; + + if (!ReferenceRect.getWidth() || ReferenceRect.getWidth()%2) + ReferenceRect.LowerRightCorner.X += 1; + } + else + UseReferenceRect = false; + } + + + //! Updates the internal cursor position + void setInternalCursorPosition(const core::position2di &pos) + { + CursorPos = pos; + + if (UseReferenceRect) + CursorPos -= ReferenceRect.UpperLeftCorner; + } + + private: + + core::position2d CursorPos; + core::dimension2d WindowSize; + core::dimension2d InvWindowSize; + bool IsVisible; + bool UseReferenceRect; + core::rect ReferenceRect; + }; + + private: + + //! Set the position of the text caret + void setTextCursorPos(s16 x, s16 y); + + // text to be added after drawing the screen + struct SPostPresentText + { + core::position2d Pos; + core::stringc Text; + }; + + bool IsWindowFocused; + + core::array OutputBuffer; + gui::IGUIFont *ConsoleFont; + core::array Text; + + FILE *OutFile; + +#ifdef _IRR_WINDOWS_NT_CONSOLE_ + HANDLE WindowsSTDIn, WindowsSTDOut; + u32 MouseButtonStates; +#endif + }; + +#ifdef _IRR_USE_CONSOLE_FONT_ + +namespace gui +{ + class CGUIConsoleFont : public IGUIFont + { + public: + + CGUIConsoleFont(CIrrDeviceConsole* device) : Device(device) { } + + //! Draws some text and clips it to the specified rectangle if wanted. + virtual void draw(const wchar_t* text, const core::rect& position, + video::SColor color, bool hcenter=false, bool vcenter=false, + const core::rect* clip=0) _IRR_OVERRIDE_ + { + core::rect Area = clip ? *clip : position; + + if (Area.UpperLeftCorner.X < 0) + Area.UpperLeftCorner.X = 0; + + if (Area.UpperLeftCorner.Y < 0) + Area.UpperLeftCorner.Y = 0; + + core::position2d pos; + + // centre vertically + pos.Y = vcenter ? (position.UpperLeftCorner.Y + position.LowerRightCorner.Y) / 2 : position.UpperLeftCorner.Y; + + // nothing to display? + if (pos.Y < Area.UpperLeftCorner.Y || pos.Y > Area.LowerRightCorner.Y) + return; + + tempText = text; + + // centre horizontally + pos.X = hcenter ? position.getCenter().X - ( tempText.size() / 2) : position.UpperLeftCorner.X; + + // clip + u32 xlclip = 0, + xrclip = 0; + + // get right clip + if (pos.X + (s32)tempText.size() > Area.LowerRightCorner.X) + xrclip = Area.LowerRightCorner.X - pos.X; + + // get left clip + if (pos.X < Area.UpperLeftCorner.X) + xlclip = Area.UpperLeftCorner.X - pos.X; + + // totally clipped? + if ((s32)tempText.size() - xlclip - xrclip < 0) + return; + + // null terminate the string + if (xrclip > 0) + tempText[xrclip] = L'\0'; + + Device->addPostPresentText(pos.X + xlclip, pos.Y, &(tempText.c_str()[xlclip])); + } + + //! Calculates the dimension of some text. + virtual core::dimension2d getDimension(const wchar_t* text) const _IRR_OVERRIDE_ + { + return core::dimension2d(wcslen(text),1); + } + + //! 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 _IRR_OVERRIDE_ { return pixel_x; } _IRR_OVERRIDE_; + + //! No kerning + virtual void setKerningWidth (s32 kerning) _IRR_OVERRIDE_ { } + virtual void setKerningHeight (s32 kerning) _IRR_OVERRIDE_ { } + virtual s32 getKerningWidth(const wchar_t* thisLetter=0, const wchar_t* previousLetter=0) const _IRR_OVERRIDE_ {return 0;} + virtual s32 getKerningHeight() const _IRR_OVERRIDE_ { return 0;} + virtual void setInvisibleCharacters( const wchar_t *s ) _IRR_OVERRIDE_ { } + // I guess this is an OS specific font + virtual EGUI_FONT_TYPE getType() const _IRR_OVERRIDE_ { return EGFT_OS; } + private: + CIrrDeviceConsole* Device; + core::stringw tempText; + }; + +} // end namespace gui + +#endif // _IRR_USE_CONSOLE_FONT_ + +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_CONSOLE_DEVICE_ +#endif // __C_IRR_DEVICE_CONSOLE_H_INCLUDED__ + diff --git a/source/Irrlicht/CIrrDeviceFB.cpp b/source/Irrlicht/CIrrDeviceFB.cpp new file mode 100644 index 00000000..f3f3e4b0 --- /dev/null +++ b/source/Irrlicht/CIrrDeviceFB.cpp @@ -0,0 +1,536 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// Copyright (C) 2007-2012 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CIrrDeviceFB.h" + +#ifdef _IRR_COMPILE_WITH_FB_DEVICE_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "IEventReceiver.h" +#include "os.h" +#include "CTimer.h" +#include "irrString.h" +#include "Keycodes.h" +#include "COSOperator.h" +#include "CColorConverter.h" +#include "SIrrCreationParameters.h" +#include "CEGLManager.h" + +#include + +namespace irr +{ + namespace video + { +#ifdef _IRR_COMPILE_WITH_OGLES1_ + IVideoDriver* createOGLES1Driver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io, video::IContextManager* contextManager); +#endif + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + IVideoDriver* createOGLES2Driver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io, video::IContextManager* contextManager); +#endif + } +} + +namespace irr +{ + +//! constructor +CIrrDeviceFB::CIrrDeviceFB(const SIrrlichtCreationParameters& params) + : CIrrDeviceStub(params), Framebuffer(-1), EventDevice(-1), SoftwareImage(0), + Pitch(0), FBColorFormat(video::ECF_A8R8G8B8), Close(false) +{ + #ifdef _DEBUG + setDebugName("CIrrDeviceFB"); + #endif + + // print version, distribution etc. + // thx to LynxLuna for pointing me to the uname function + core::stringc linuxversion; + struct utsname FBInfo; + uname(&FBInfo); + + linuxversion += FBInfo.sysname; + linuxversion += " "; + linuxversion += FBInfo.release; + linuxversion += " "; + linuxversion += FBInfo.version; + linuxversion += " "; + linuxversion += FBInfo.machine; + + Operator = new COSOperator(linuxversion); + os::Printer::log(linuxversion.c_str(), ELL_INFORMATION); + + // create window + if (params.DriverType != video::EDT_NULL) + { + // create the window, only if we do not use the null device + if (!createWindow(params.WindowSize, params.Bits)) + return; + } + + // create cursor control + CursorControl = new CCursorControl(this, params.DriverType == video::EDT_NULL); + + // create driver + createDriver(); + + if (!VideoDriver) + return; + + createGUIAndScene(); +} + + + +//! destructor +CIrrDeviceFB::~CIrrDeviceFB() +{ + if (SoftwareImage) + munmap(SoftwareImage, CreationParams.WindowSize.Height*Pitch); + // go back to previous format + if (ioctl(Framebuffer, FBIOPUT_VSCREENINFO, &oldscreeninfo) <0) + perror("Restoring old fb mode"); + + if (KeyboardDevice != -1) + if (ioctl(KeyboardDevice, KDSETMODE, &KeyboardMode) <0) + perror("Restoring keyboard mode"); + if (EventDevice != -1) + close(EventDevice); + if (KeyboardDevice != -1) + close(KeyboardDevice); + if (Framebuffer != -1) + close(Framebuffer); +} + + +bool CIrrDeviceFB::createWindow(const core::dimension2d& windowSize, u32 bits) +{ + char buf[256]; + CreationParams.WindowSize.Width = windowSize.Width; + CreationParams.WindowSize.Height = windowSize.Height; + + KeyboardDevice = open("/dev/tty", O_RDWR); + if (KeyboardDevice == -1) + perror("Open keyboard"); + if (ioctl(KeyboardDevice, KDGETMODE, &KeyboardMode) <0) + perror("Read keyboard mode"); + if (ioctl(KeyboardDevice, KDSETMODE, KD_GRAPHICS) <0) + perror("Set keyboard mode"); + + Framebuffer=open("/dev/fb/0", O_RDWR); + if (Framebuffer == -1) + { + Framebuffer=open("/dev/fb0", O_RDWR); + if (Framebuffer == -1) + { + perror("Open framebuffer"); + return false; + } + } + EventDevice = open("/dev/input/event0", O_RDONLY | O_NONBLOCK); + if (EventDevice == -1) + perror("Open event device"); + + // make format settings + ioctl(Framebuffer, FBIOGET_FSCREENINFO, &fbfixscreeninfo); + ioctl(Framebuffer, FBIOGET_VSCREENINFO, &oldscreeninfo); + snprintf_irr(buf, 256, "Original resolution: %d x %d\nARGB%d%d%d%d\n",oldscreeninfo.xres,oldscreeninfo.yres, + oldscreeninfo.transp.length,oldscreeninfo.red.length,oldscreeninfo.green.length,oldscreeninfo.blue.length); + os::Printer::log(buf); + memcpy(&fbscreeninfo, &oldscreeninfo, sizeof(struct fb_var_screeninfo)); + if (CreationParams.DriverType != video::EDT_NULL) + { + fbscreeninfo.xres = fbscreeninfo.xres_virtual = CreationParams.WindowSize.Width; + fbscreeninfo.yres = fbscreeninfo.yres_virtual = CreationParams.WindowSize.Height; + fbscreeninfo.bits_per_pixel = 16; + fbscreeninfo.red.offset = 10; + fbscreeninfo.red.length = 5; + fbscreeninfo.green.offset = 5; + fbscreeninfo.green.length = 5; + fbscreeninfo.blue.offset = 0; + fbscreeninfo.blue.length = 5; + fbscreeninfo.transp.offset = 15; + fbscreeninfo.transp.length = 1; + ioctl(Framebuffer, FBIOPUT_VSCREENINFO, &fbscreeninfo); + ioctl(Framebuffer, FBIOGET_VSCREENINFO, &fbscreeninfo); + + snprintf_irr(buf, 256, "New resolution: %d x %d (%d x %d)\nARGB%d%d%d%d\n",fbscreeninfo.xres,fbscreeninfo.yres,fbscreeninfo.xres_virtual,fbscreeninfo.yres_virtual, + fbscreeninfo.transp.length,fbscreeninfo.red.length,fbscreeninfo.green.length,fbscreeninfo.blue.length); + os::Printer::log(buf); + + CreationParams.WindowSize.Width = fbscreeninfo.xres; + CreationParams.WindowSize.Height = fbscreeninfo.yres; + CreationParams.Bits = fbscreeninfo.bits_per_pixel; + Pitch = fbfixscreeninfo.line_length; + if (fbscreeninfo.bits_per_pixel == 16) + { + if (fbscreeninfo.transp.length == 0) + FBColorFormat = video::ECF_R5G6B5; + else + FBColorFormat = video::ECF_A1R5G5B5; + } + else + { + if (fbscreeninfo.transp.length == 0) + FBColorFormat = video::ECF_R8G8B8; + else + FBColorFormat = video::ECF_A8R8G8B8; + } + if (MAP_FAILED==(SoftwareImage=(u8*)mmap(0, CreationParams.WindowSize.Height*Pitch, PROT_READ|PROT_WRITE, MAP_SHARED, Framebuffer, 0))) + { + perror("mmap render target"); + return false; + } + } + return true; +} + + +//! create the driver +void CIrrDeviceFB::createDriver() +{ + switch(CreationParams.DriverType) + { + case video::EDT_SOFTWARE: + #ifdef _IRR_COMPILE_WITH_SOFTWARE_ + VideoDriver = video::createSoftwareDriver(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this); + #else + os::Printer::log("No Software driver support compiled in.", ELL_WARNING); + #endif + break; + + case video::EDT_BURNINGSVIDEO: + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + VideoDriver = video::createBurningVideoDriver(CreationParams, FileSystem, this); + #else + os::Printer::log("Burning's video driver was not compiled in.", ELL_WARNING); + #endif + break; + + case video::EDT_OGLES2: + #ifdef _IRR_COMPILE_WITH_OGLES2_ + { + video::SExposedVideoData data; + s32 width = 0; + s32 height = 0; + NativeDisplayType display = fbGetDisplay(0); + fbGetDisplayGeometry(display, &width, &height); + data.OpenGLFB.Window = (void*)fbCreateWindow(display, 0, 0, width, height); + ContextManager = new video::CEGLManager(); + ContextManager->initialize(CreationParams, data); + VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager); + } + #else + os::Printer::log("No OpenGL-ES2 support compiled in.", ELL_ERROR); + #endif + break; + + case video::EDT_OGLES1: + #ifdef _IRR_COMPILE_WITH_OGLES1_ + { + video::SExposedVideoData data; + s32 width = 0; + s32 height = 0; + NativeDisplayType display = fbGetDisplay(0); + fbGetDisplayGeometry(display, &width, &height); + data.OpenGLFB.Window = (void*)fbCreateWindow(display, 0, 0, width, height); + ContextManager = new video::CEGLManager(); + ContextManager->initialize(CreationParams, data); + VideoDriver = video::createOGLES1Driver(CreationParams, FileSystem, ContextManager); + } + #else + os::Printer::log("No OpenGL-ES1 support compiled in.", ELL_ERROR); + #endif + break; + + case video::DEPRECATED_EDT_DIRECT3D8_NO_LONGER_EXISTS: + case video::EDT_OPENGL: + case video::EDT_DIRECT3D9: + os::Printer::log("This driver is not available in FB. Try Software renderer.", + ELL_WARNING); + break; + + default: + VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize); + break; + } +} + + +//! runs the device. Returns false if device wants to be deleted +bool CIrrDeviceFB::run() +{ + os::Timer::tick(); + + struct input_event ev; + if (EventDevice>=0) + { + if ((read(EventDevice, &ev, sizeof(input_event)) < 0) && + errno != EAGAIN) + perror("Read input event"); + if (ev.type == EV_KEY) + { + irr::SEvent irrevent; + irrevent.EventType = irr::EET_KEY_INPUT_EVENT; + irrevent.KeyInput.PressedDown = (ev.value == 1); + + switch (ev.code) + { + case KEY_RIGHTCTRL: + case KEY_LEFTCTRL: + irrevent.KeyInput.Control = true; + break; + case KEY_RIGHTSHIFT: + case KEY_LEFTSHIFT: + irrevent.KeyInput.Shift = true; + break; + case KEY_ESC: + irrevent.KeyInput.Key = (EKEY_CODE)0x1B; + break; + case KEY_SPACE: + irrevent.KeyInput.Key = (EKEY_CODE)0x20; + break; + case KEY_UP: + irrevent.KeyInput.Key = (EKEY_CODE)0x26; + break; + case KEY_LEFT: + irrevent.KeyInput.Key = (EKEY_CODE)0x25; + break; + case KEY_RIGHT: + irrevent.KeyInput.Key = (EKEY_CODE)0x27; + break; + case KEY_DOWN: + irrevent.KeyInput.Key = (EKEY_CODE)0x28; + break; + case KEY_A: + irrevent.KeyInput.Key = (EKEY_CODE)0x41; + break; + case KEY_B: + irrevent.KeyInput.Key = (EKEY_CODE)0x42; + break; + case KEY_C: + irrevent.KeyInput.Key = (EKEY_CODE)0x43; + break; + case KEY_D: + irrevent.KeyInput.Key = (EKEY_CODE)0x44; + break; + case KEY_E: + irrevent.KeyInput.Key = (EKEY_CODE)0x45; + break; + case KEY_F: + irrevent.KeyInput.Key = (EKEY_CODE)0x46; + break; + case KEY_G: + irrevent.KeyInput.Key = (EKEY_CODE)0x47; + break; + case KEY_H: + irrevent.KeyInput.Key = (EKEY_CODE)0x48; + break; + case KEY_I: + irrevent.KeyInput.Key = (EKEY_CODE)0x49; + break; + case KEY_J: + irrevent.KeyInput.Key = (EKEY_CODE)0x4A; + break; + case KEY_K: + irrevent.KeyInput.Key = (EKEY_CODE)0x4B; + break; + case KEY_L: + irrevent.KeyInput.Key = (EKEY_CODE)0x4C; + break; + case KEY_M: + irrevent.KeyInput.Key = (EKEY_CODE)0x4D; + break; + case KEY_N: + irrevent.KeyInput.Key = (EKEY_CODE)0x4E; + break; + case KEY_O: + irrevent.KeyInput.Key = (EKEY_CODE)0x4F; + break; + case KEY_P: + irrevent.KeyInput.Key = (EKEY_CODE)0x50; + break; + case KEY_Q: + irrevent.KeyInput.Key = (EKEY_CODE)0x51; + break; + case KEY_R: + irrevent.KeyInput.Key = (EKEY_CODE)0x52; + break; + case KEY_S: + irrevent.KeyInput.Key = (EKEY_CODE)0x53; + break; + case KEY_T: + irrevent.KeyInput.Key = (EKEY_CODE)0x54; + break; + case KEY_U: + irrevent.KeyInput.Key = (EKEY_CODE)0x55; + break; + case KEY_V: + irrevent.KeyInput.Key = (EKEY_CODE)0x56; + break; + case KEY_W: + irrevent.KeyInput.Key = (EKEY_CODE)0x57; + break; + case KEY_X: + irrevent.KeyInput.Key = (EKEY_CODE)0x58; + break; + case KEY_Y: + irrevent.KeyInput.Key = (EKEY_CODE)0x59; + break; + case KEY_Z: + irrevent.KeyInput.Key = (EKEY_CODE)0x5A; + break; + default: + irrevent.KeyInput.Key = (EKEY_CODE)0; + break; + } + postEventFromUser(irrevent); + } + } + + return !Close; +} + + +//! Pause the current process for the minimum time allowed only to allow other processes to execute +void CIrrDeviceFB::yield() +{ + struct timespec ts = {0,0}; + nanosleep(&ts, NULL); +} + + +//! Pause execution and let other processes to run for a specified amount of time. +void CIrrDeviceFB::sleep(u32 timeMs, bool pauseTimer=false) +{ + bool wasStopped = Timer ? Timer->isStopped() : true; + + struct timespec ts; + ts.tv_sec = (time_t) (timeMs / 1000); + ts.tv_nsec = (long) (timeMs % 1000) * 1000000; + + if (pauseTimer && !wasStopped) + Timer->stop(); + + nanosleep(&ts, NULL); + + if (pauseTimer && !wasStopped) + Timer->start(); +} + + +//! presents a surface in the client area +bool CIrrDeviceFB::present(video::IImage* image, void* windowId, core::rect* src ) +{ + // this is only necessary for software drivers. + if (CreationParams.DriverType != video::EDT_SOFTWARE && CreationParams.DriverType != video::EDT_BURNINGSVIDEO) + return false; + + if (!SoftwareImage) + return false; + + u8* destData = SoftwareImage; + u32 srcwidth = (u32)image->getDimension().Width; + u32 srcheight = (u32)image->getDimension().Height; + // clip images + srcheight = core::min_(srcheight, CreationParams.WindowSize.Height); + srcwidth = core::min_(srcwidth, CreationParams.WindowSize.Width); + + u8* srcdata = (u8*)image->lock(); + for (u32 y=0; ygetColorFormat(), srcwidth, destData, FBColorFormat); + srcdata+=image->getPitch(); + destData+=Pitch; + } + image->unlock(); + msync(SoftwareImage,CreationParams.WindowSize.Width*CreationParams.WindowSize.Height,MS_ASYNC); + return true; +} + + +//! notifies the device that it should close itself +void CIrrDeviceFB::closeDevice() +{ + Close = true; +} + + +//! returns if window is active. if not, nothing need to be drawn +bool CIrrDeviceFB::isWindowActive() const +{ + return true; +} + + +//! returns if window has focus +bool CIrrDeviceFB::isWindowFocused() const +{ + return true; +} + + +//! returns if window is minimized +bool CIrrDeviceFB::isWindowMinimized() const +{ + return false; +} + + +//! sets the caption of the window +void CIrrDeviceFB::setWindowCaption(const wchar_t* text) +{ +} + + +//! Sets if the window should be resizeable in windowed mode. +void CIrrDeviceFB::setResizable(bool resize) +{ +} + + +//! Minimizes window +void CIrrDeviceFB::minimizeWindow() +{ +} + + +//! Maximizes window +void CIrrDeviceFB::maximizeWindow() +{ +} + + +//! Restores original window size +void CIrrDeviceFB::restoreWindow() +{ +} + + +//! Returns the type of this device +E_DEVICE_TYPE CIrrDeviceFB::getType() const +{ + return EIDT_FRAMEBUFFER; +} + + +} // end namespace irr + +#endif // _IRR_USE_FB_DEVICE_ + diff --git a/source/Irrlicht/CIrrDeviceFB.h b/source/Irrlicht/CIrrDeviceFB.h new file mode 100644 index 00000000..62286583 --- /dev/null +++ b/source/Irrlicht/CIrrDeviceFB.h @@ -0,0 +1,215 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// Copyright (C) 2007-2012 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_IRR_DEVICE_FB_H_INCLUDED__ +#define __C_IRR_DEVICE_FB_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_FB_DEVICE_ + +#include "CIrrDeviceStub.h" +#include "SIrrCreationParameters.h" +#include "IrrlichtDevice.h" +#include "IImagePresenter.h" +#include "ICursorControl.h" + +#define KeySym s32 +#include +#include + +namespace irr +{ + class CIrrDeviceFB : public CIrrDeviceStub, public video::IImagePresenter + { + public: + + //! constructor + CIrrDeviceFB(const SIrrlichtCreationParameters& params); + + //! destructor + virtual ~CIrrDeviceFB(); + + //! runs the device. Returns false if device wants to be deleted + virtual bool run() _IRR_OVERRIDE_; + + //! Cause the device to temporarily pause execution and let other processes to run + // This should bring down processor usage without major performance loss for Irrlicht + virtual void yield() _IRR_OVERRIDE_; + + //! Pause execution and let other processes to run for a specified amount of time. + virtual void sleep(u32 timeMs, bool pauseTimer) _IRR_OVERRIDE_; + + //! sets the caption of the window + virtual void setWindowCaption(const wchar_t* text) _IRR_OVERRIDE_; + + //! returns if window is active. if not, nothing need to be drawn + virtual bool isWindowActive() const _IRR_OVERRIDE_; + + //! returns if window has focus + virtual bool isWindowFocused() const _IRR_OVERRIDE_; + + //! returns if window is minimized + virtual bool isWindowMinimized() const _IRR_OVERRIDE_; + + //! Minimizes window + virtual void minimizeWindow() _IRR_OVERRIDE_; + + //! Maximizes window + virtual void maximizeWindow() _IRR_OVERRIDE_; + + //! Restores original window size + virtual void restoreWindow() _IRR_OVERRIDE_; + + //! returns current window position (not supported for this device) + virtual core::position2di getWindowPosition() _IRR_OVERRIDE_ + { + return core::position2di(-1, -1); + } + + //! presents a surface in the client area + virtual bool present(video::IImage* surface, void* windowId = 0, core::rect* src=0 ) _IRR_OVERRIDE_; + + //! notifies the device that it should close itself + virtual void closeDevice() _IRR_OVERRIDE_; + + //! Sets if the window should be resizeable in windowed mode. + virtual void setResizable(bool resize=false) _IRR_OVERRIDE_; + + //! Returns the type of this device + virtual E_DEVICE_TYPE getType() const _IRR_OVERRIDE_; + + private: + + //! create the driver + void createDriver(); + + bool createWindow(const core::dimension2d& windowSize, u32 bits); + + //! Implementation of the cursor control + class CCursorControl : public gui::ICursorControl + { + public: + + CCursorControl(CIrrDeviceFB* dev, bool null) + : Device(dev), IsVisible(true), Null(null) + { + Device->grab(); + } + + ~CCursorControl() + { + Device->drop(); + } + + //! Changes the visible state of the mouse cursor. + virtual void setVisible(bool visible) _IRR_OVERRIDE_ + { + IsVisible = visible; + } + + //! Returns if the cursor is currently visible. + virtual bool isVisible() const _IRR_OVERRIDE_ + { + return IsVisible; + } + + //! Sets the new position of the cursor. + virtual void setPosition(const core::position2d &pos) _IRR_OVERRIDE_ + { + setPosition(pos.X, pos.Y); + } + + //! Sets the new position of the cursor. + virtual void setPosition(f32 x, f32 y) _IRR_OVERRIDE_ + { + setPosition((s32)(x*Device->CreationParams.WindowSize.Width), (s32)(y*Device->CreationParams.WindowSize.Height)); + } + + //! Sets the new position of the cursor. + virtual void setPosition(const core::position2d &pos) _IRR_OVERRIDE_ + { + setPosition(pos.X, pos.Y); + } + + //! Sets the new position of the cursor. + virtual void setPosition(s32 x, s32 y) _IRR_OVERRIDE_ + { + } + + //! Returns the current position of the mouse cursor. + virtual const core::position2d& getPosition(bool updateCursor) _IRR_OVERRIDE_ + { + if ( updateCursor ) + updateCursorPos(); + return CursorPos; + } + + //! Returns the current position of the mouse cursor. + virtual core::position2d getRelativePosition(bool updateCursor) _IRR_OVERRIDE_ + { + if ( updateCursor) + updateCursorPos(); + return core::position2d(CursorPos.X / (f32)Device->CreationParams.WindowSize.Width, + CursorPos.Y / (f32)Device->CreationParams.WindowSize.Height); + } + + virtual void setReferenceRect(core::rect* rect=0) _IRR_OVERRIDE_ + { + } + + private: + + void updateCursorPos() + { + } + + core::position2d CursorPos; + CIrrDeviceFB* Device; + bool IsVisible; + bool Null; + }; + + friend class CCursorControl; + + int Framebuffer; + int EventDevice; + int KeyboardDevice; + struct fb_fix_screeninfo fbfixscreeninfo; + struct fb_var_screeninfo fbscreeninfo; + struct fb_var_screeninfo oldscreeninfo; + long KeyboardMode; + u8* SoftwareImage; + + u32 Pitch; + video::ECOLOR_FORMAT FBColorFormat; + bool Close; + + struct SKeyMap + { + SKeyMap() {} + SKeyMap(s32 x11, s32 win32) + : X11Key(x11), Win32Key(win32) + { + } + + KeySym X11Key; + s32 Win32Key; + + bool operator<(const SKeyMap& o) const + { + return X11Key KeyMap; + }; + + +} // end namespace irr + +#endif // _IRR_USE_FB_DEVICE_ +#endif // __C_IRR_DEVICE_FB_H_INCLUDED__ + diff --git a/source/Irrlicht/CIrrDeviceLinux.cpp b/source/Irrlicht/CIrrDeviceLinux.cpp new file mode 100644 index 00000000..34f0b2cd --- /dev/null +++ b/source/Irrlicht/CIrrDeviceLinux.cpp @@ -0,0 +1,2309 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CIrrDeviceLinux.h" + +#ifdef _IRR_COMPILE_WITH_X11_DEVICE_ + +#include +#include +#include +#include +#include +#include "IEventReceiver.h" +#include "ISceneManager.h" +#include "IGUIEnvironment.h" +#include "os.h" +#include "CTimer.h" +#include "irrString.h" +#include "Keycodes.h" +#include "COSOperator.h" +#include "CColorConverter.h" +#include "SIrrCreationParameters.h" +#include "SExposedVideoData.h" +#include "IGUISpriteBank.h" +#include +#include + +#if defined(_IRR_COMPILE_WITH_OGLES1_) || defined(_IRR_COMPILE_WITH_OGLES2_) +#include "CEGLManager.h" +#endif + +#if defined(_IRR_COMPILE_WITH_OPENGL_) +#include "CGLXManager.h" +#endif + +#ifdef _IRR_LINUX_XCURSOR_ +#include +#endif + +#if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ +#include +#include + +#ifdef __FreeBSD__ +#include +#else + +// linux/joystick.h includes linux/input.h, which #defines values for various KEY_FOO keys. +// These override the irr::KEY_FOO equivalents, which stops key handling from working. +// As a workaround, defining _INPUT_H stops linux/input.h from being included; it +// doesn't actually seem to be necessary except to pull in sys/ioctl.h. +#define _INPUT_H +#include // Would normally be included in linux/input.h +#include +#undef _INPUT_H +#endif + +#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ + +namespace irr +{ + namespace video + { +#ifdef _IRR_COMPILE_WITH_OPENGL_ + IVideoDriver* createOpenGLDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager); +#endif + +#ifdef _IRR_COMPILE_WITH_OGLES1_ + IVideoDriver* createOGLES1Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager); +#endif + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + IVideoDriver* createOGLES2Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager); +#endif + +#ifdef _IRR_COMPILE_WITH_WEBGL1_ + IVideoDriver* createWebGL1Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager); +#endif + } +} // end namespace irr + +namespace +{ + Atom X_ATOM_CLIPBOARD; + Atom X_ATOM_TARGETS; + Atom X_ATOM_UTF8_STRING; + Atom X_ATOM_TEXT; + Atom X_ATOM_NETWM_MAXIMIZE_VERT; + Atom X_ATOM_NETWM_MAXIMIZE_HORZ; + Atom X_ATOM_NETWM_STATE; +}; + +namespace irr +{ + +const char wmDeleteWindow[] = "WM_DELETE_WINDOW"; + +//! constructor +CIrrDeviceLinux::CIrrDeviceLinux(const SIrrlichtCreationParameters& param) + : CIrrDeviceStub(param), +#ifdef _IRR_COMPILE_WITH_X11_ + XDisplay(0), VisualInfo(0), Screennr(0), XWindow(0), StdHints(0), SoftwareImage(0), + XInputMethod(0), XInputContext(0), + HasNetWM(false), +#endif + Width(param.WindowSize.Width), Height(param.WindowSize.Height), + WindowHasFocus(false), WindowMinimized(false), + UseXVidMode(false), UseXRandR(false), + ExternalWindow(false), AutorepeatSupport(0) +{ + #ifdef _DEBUG + setDebugName("CIrrDeviceLinux"); + #endif + + // print version, distribution etc. + // thx to LynxLuna for pointing me to the uname function + core::stringc linuxversion; + struct utsname LinuxInfo; + uname(&LinuxInfo); + + linuxversion += LinuxInfo.sysname; + linuxversion += " "; + linuxversion += LinuxInfo.release; + linuxversion += " "; + linuxversion += LinuxInfo.version; + linuxversion += " "; + linuxversion += LinuxInfo.machine; + + Operator = new COSOperator(linuxversion, this); + os::Printer::log(linuxversion.c_str(), ELL_INFORMATION); + + // create keymap + createKeyMap(); + + // create window + if (CreationParams.DriverType != video::EDT_NULL) + { + // create the window, only if we do not use the null device + if (!createWindow()) + return; + setResizable(param.WindowResizable); + } + + // create cursor control + CursorControl = new CCursorControl(this, CreationParams.DriverType == video::EDT_NULL); + + // create driver + createDriver(); + + if (!VideoDriver) + return; + +#ifdef _IRR_COMPILE_WITH_X11_ + createInputContext(); +#endif + + createGUIAndScene(); +} + + +//! destructor +CIrrDeviceLinux::~CIrrDeviceLinux() +{ +#ifdef _IRR_COMPILE_WITH_X11_ + if (StdHints) + XFree(StdHints); + // Disable cursor (it is drop'ed in stub) + if (CursorControl) + { + CursorControl->setVisible(false); + static_cast(CursorControl)->clearCursors(); + } + + // Must free OpenGL textures etc before destroying context, so can't wait for stub destructor + if ( GUIEnvironment ) + { + GUIEnvironment->drop(); + GUIEnvironment = NULL; + } + if ( SceneManager ) + { + SceneManager->drop(); + SceneManager = NULL; + } + if ( VideoDriver ) + { + VideoDriver->drop(); + VideoDriver = NULL; + } + + destroyInputContext(); + + if (XDisplay) + { + if (ContextManager) + { + ContextManager->destroyContext(); + ContextManager->destroySurface(); + } + + // Reset fullscreen resolution change + switchToFullscreen(true); + + if (SoftwareImage) + XDestroyImage(SoftwareImage); + + if (!ExternalWindow) + { + XDestroyWindow(XDisplay,XWindow); + XCloseDisplay(XDisplay); + } + } + if (VisualInfo) + XFree(VisualInfo); + +#endif // #ifdef _IRR_COMPILE_WITH_X11_ + +#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) + for (u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) + { + if (ActiveJoysticks[joystick].fd >= 0) + { + close(ActiveJoysticks[joystick].fd); + } + } +#endif +} + + +#if defined(_IRR_COMPILE_WITH_X11_) && defined(_DEBUG) +int IrrPrintXError(Display *display, XErrorEvent *event) +{ + char msg[256]; + char msg2[256]; + + snprintf_irr(msg, 256, "%d", event->request_code); + XGetErrorDatabaseText(display, "XRequest", msg, "unknown", msg2, 256); + XGetErrorText(display, event->error_code, msg, 256); + os::Printer::log("X Error", msg, ELL_WARNING); + os::Printer::log("From call ", msg2, ELL_WARNING); + return 0; +} +#endif + + +bool CIrrDeviceLinux::switchToFullscreen(bool reset) +{ + if (!CreationParams.Fullscreen) + return true; + if (reset) + { +#ifdef _IRR_LINUX_X11_VIDMODE_ + if (UseXVidMode && CreationParams.Fullscreen) + { + XF86VidModeSwitchToMode(XDisplay, Screennr, &OldVideoMode); + XF86VidModeSetViewPort(XDisplay, Screennr, 0, 0); + } + #endif + #ifdef _IRR_LINUX_X11_RANDR_ + if (UseXRandR && CreationParams.Fullscreen) + { + XRRScreenConfiguration *config=XRRGetScreenInfo(XDisplay,DefaultRootWindow(XDisplay)); + XRRSetScreenConfig(XDisplay,config,DefaultRootWindow(XDisplay),OldRandrMode,OldRandrRotation,CurrentTime); + XRRFreeScreenConfigInfo(config); + } + #endif + return true; + } + + getVideoModeList(); + #if defined(_IRR_LINUX_X11_VIDMODE_) || defined(_IRR_LINUX_X11_RANDR_) + s32 eventbase, errorbase; + s32 bestMode = -1; + #endif + + #ifdef _IRR_LINUX_X11_VIDMODE_ + if (XF86VidModeQueryExtension(XDisplay, &eventbase, &errorbase)) + { + // enumerate video modes + s32 modeCount; + XF86VidModeModeInfo** modes; + + XF86VidModeGetAllModeLines(XDisplay, Screennr, &modeCount, &modes); + + // find fitting mode + for (s32 i = 0; ihdisplay >= Width && modes[i]->vdisplay >= Height) + bestMode = i; + else if (bestMode!=-1 && + modes[i]->hdisplay >= Width && + modes[i]->vdisplay >= Height && + modes[i]->hdisplay <= modes[bestMode]->hdisplay && + modes[i]->vdisplay <= modes[bestMode]->vdisplay) + bestMode = i; + } + if (bestMode != -1) + { + os::Printer::log("Starting vidmode fullscreen mode...", ELL_INFORMATION); + os::Printer::log("hdisplay: ", core::stringc(modes[bestMode]->hdisplay).c_str(), ELL_INFORMATION); + os::Printer::log("vdisplay: ", core::stringc(modes[bestMode]->vdisplay).c_str(), ELL_INFORMATION); + + XF86VidModeSwitchToMode(XDisplay, Screennr, modes[bestMode]); + XF86VidModeSetViewPort(XDisplay, Screennr, 0, 0); + UseXVidMode=true; + } + else + { + os::Printer::log("Could not find specified video mode, running windowed.", ELL_WARNING); + CreationParams.Fullscreen = false; + } + + XFree(modes); + } + else + #endif + #ifdef _IRR_LINUX_X11_RANDR_ + if (XRRQueryExtension(XDisplay, &eventbase, &errorbase)) + { + s32 modeCount; + XRRScreenConfiguration *config=XRRGetScreenInfo(XDisplay,DefaultRootWindow(XDisplay)); + XRRScreenSize *modes=XRRConfigSizes(config,&modeCount); + for (s32 i = 0; i= Width && (u32)modes[i].height >= Height) + bestMode = i; + else if (bestMode!=-1 && + (u32)modes[i].width >= Width && + (u32)modes[i].height >= Height && + modes[i].width <= modes[bestMode].width && + modes[i].height <= modes[bestMode].height) + bestMode = i; + } + if (bestMode != -1) + { + os::Printer::log("Starting randr fullscreen mode...", ELL_INFORMATION); + os::Printer::log("width: ", core::stringc(modes[bestMode].width).c_str(), ELL_INFORMATION); + os::Printer::log("height: ", core::stringc(modes[bestMode].height).c_str(), ELL_INFORMATION); + + XRRSetScreenConfig(XDisplay,config,DefaultRootWindow(XDisplay),bestMode,OldRandrRotation,CurrentTime); + UseXRandR=true; + } + XRRFreeScreenConfigInfo(config); + } + else + #endif + { + os::Printer::log("VidMode or RandR extension must be installed to allow Irrlicht " + "to switch to fullscreen mode. Running in windowed mode instead.", ELL_WARNING); + CreationParams.Fullscreen = false; + } + return CreationParams.Fullscreen; +} + + +#if defined(_IRR_COMPILE_WITH_X11_) +void IrrPrintXGrabError(int grabResult, const c8 * grabCommand ) +{ + if ( grabResult == GrabSuccess ) + { +// os::Printer::log(grabCommand, ": GrabSuccess", ELL_INFORMATION); + return; + } + + switch ( grabResult ) + { + case AlreadyGrabbed: + os::Printer::log(grabCommand, ": AlreadyGrabbed", ELL_WARNING); + break; + case GrabNotViewable: + os::Printer::log(grabCommand, ": GrabNotViewable", ELL_WARNING); + break; + case GrabFrozen: + os::Printer::log(grabCommand, ": GrabFrozen", ELL_WARNING); + break; + case GrabInvalidTime: + os::Printer::log(grabCommand, ": GrabInvalidTime", ELL_WARNING); + break; + default: + os::Printer::log(grabCommand, ": grab failed with unknown problem", ELL_WARNING); + break; + } +} +#endif + + +bool CIrrDeviceLinux::createWindow() +{ +#ifdef _IRR_COMPILE_WITH_X11_ +#ifdef _DEBUG + os::Printer::log("Creating X window...", ELL_INFORMATION); + XSetErrorHandler(IrrPrintXError); +#endif + + XDisplay = XOpenDisplay(0); + if (!XDisplay) + { + os::Printer::log("Error: Need running XServer to start Irrlicht Engine.", ELL_ERROR); + if (XDisplayName(0)[0]) + os::Printer::log("Could not open display", XDisplayName(0), ELL_ERROR); + else + os::Printer::log("Could not open display, set DISPLAY variable", ELL_ERROR); + return false; + } + + Screennr = DefaultScreen(XDisplay); + + switchToFullscreen(); + +#if defined(_IRR_COMPILE_WITH_OPENGL_) + // don't use the XVisual with OpenGL, because it ignores all requested + // properties of the CreationParams + if (CreationParams.DriverType == video::EDT_OPENGL) + { + video::SExposedVideoData data; + data.OpenGLLinux.X11Display = XDisplay; + ContextManager = new video::CGLXManager(CreationParams, data, Screennr); + VisualInfo = ((video::CGLXManager*)ContextManager)->getVisual(); + } +#endif + + if (!VisualInfo) + { + // create visual with standard X methods + os::Printer::log("Using plain X visual"); + XVisualInfo visTempl; //Template to hold requested values + int visNumber; // Return value of available visuals + + visTempl.screen = Screennr; + // ARGB visuals should be avoided for usual applications + visTempl.depth = CreationParams.WithAlphaChannel?32:24; + while ((!VisualInfo) && (visTempl.depth>=16)) + { + VisualInfo = XGetVisualInfo(XDisplay, VisualScreenMask|VisualDepthMask, + &visTempl, &visNumber); + visTempl.depth -= 8; + } + } + + if (!VisualInfo) + { + os::Printer::log("Fatal error, could not get visual.", ELL_ERROR); + XCloseDisplay(XDisplay); + XDisplay=0; + return false; + } +#ifdef _DEBUG + else + os::Printer::log("Visual chosen: ", core::stringc(static_cast(VisualInfo->visualid)).c_str(), ELL_DEBUG); +#endif + + // create color map + Colormap colormap; + colormap = XCreateColormap(XDisplay, + RootWindow(XDisplay, VisualInfo->screen), + VisualInfo->visual, AllocNone); + + WndAttributes.colormap = colormap; + WndAttributes.border_pixel = 0; + WndAttributes.event_mask = StructureNotifyMask | FocusChangeMask | ExposureMask; + if (!CreationParams.IgnoreInput) + WndAttributes.event_mask |= PointerMotionMask | + ButtonPressMask | KeyPressMask | + ButtonReleaseMask | KeyReleaseMask; + + if (!CreationParams.WindowId) + { + int x = 0; + int y = 0; + + if (!CreationParams.Fullscreen) + { + if (CreationParams.WindowPosition.X > 0) + x = CreationParams.WindowPosition.X; + if (CreationParams.WindowPosition.Y > 0) + y = CreationParams.WindowPosition.Y; + } + + // create new Window + // Remove window manager decoration in fullscreen + WndAttributes.override_redirect = CreationParams.Fullscreen; + XWindow = XCreateWindow(XDisplay, + RootWindow(XDisplay, VisualInfo->screen), + x, y, Width, Height, 0, VisualInfo->depth, + InputOutput, VisualInfo->visual, + CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, + &WndAttributes); + + XMapRaised(XDisplay, XWindow); + CreationParams.WindowId = (void*)XWindow; + Atom wmDelete; + wmDelete = XInternAtom(XDisplay, wmDeleteWindow, True); + XSetWMProtocols(XDisplay, XWindow, &wmDelete, 1); + if (CreationParams.Fullscreen) + { + XSetInputFocus(XDisplay, XWindow, RevertToParent, CurrentTime); + int grabKb = XGrabKeyboard(XDisplay, XWindow, True, GrabModeAsync, + GrabModeAsync, CurrentTime); + IrrPrintXGrabError(grabKb, "XGrabKeyboard"); + int grabPointer = XGrabPointer(XDisplay, XWindow, True, ButtonPressMask, + GrabModeAsync, GrabModeAsync, XWindow, None, CurrentTime); + IrrPrintXGrabError(grabPointer, "XGrabPointer"); + XWarpPointer(XDisplay, None, XWindow, 0, 0, 0, 0, 0, 0); + } + else if (CreationParams.WindowPosition.X >= 0 || CreationParams.WindowPosition.Y >= 0) // default is -1, -1 + { + // Window managers are free to ignore positions above, so give it another shot + XMoveWindow(XDisplay,XWindow,x,y); + } + } + else + { + // attach external window + XWindow = (Window)CreationParams.WindowId; + if (!CreationParams.IgnoreInput) + { + XCreateWindow(XDisplay, + XWindow, + 0, 0, Width, Height, 0, VisualInfo->depth, + InputOutput, VisualInfo->visual, + CWBorderPixel | CWColormap | CWEventMask, + &WndAttributes); + } + XWindowAttributes wa; + XGetWindowAttributes(XDisplay, XWindow, &wa); + CreationParams.WindowSize.Width = wa.width; + CreationParams.WindowSize.Height = wa.height; + CreationParams.Fullscreen = false; + ExternalWindow = true; + } + + WindowMinimized=false; + // Currently broken in X, see Bug ID 2795321 + // XkbSetDetectableAutoRepeat(XDisplay, True, &AutorepeatSupport); + + Window tmp; + u32 borderWidth; + int x,y; + unsigned int bits; + + XGetGeometry(XDisplay, XWindow, &tmp, &x, &y, &Width, &Height, &borderWidth, &bits); + CreationParams.Bits = bits; + CreationParams.WindowSize.Width = Width; + CreationParams.WindowSize.Height = Height; + + StdHints = XAllocSizeHints(); + long num; + XGetWMNormalHints(XDisplay, XWindow, StdHints, &num); + + // create an XImage for the software renderer + //(thx to Nadav for some clues on how to do that!) + + if (CreationParams.DriverType == video::EDT_SOFTWARE || CreationParams.DriverType == video::EDT_BURNINGSVIDEO) + { + SoftwareImage = XCreateImage(XDisplay, + VisualInfo->visual, VisualInfo->depth, + ZPixmap, 0, 0, Width, Height, + BitmapPad(XDisplay), 0); + + // use malloc because X will free it later on + if (SoftwareImage) + SoftwareImage->data = (char*) malloc(SoftwareImage->bytes_per_line * SoftwareImage->height * sizeof(char)); + } + + initXAtoms(); + + // check netwm support + Atom WMCheck = XInternAtom(XDisplay, "_NET_SUPPORTING_WM_CHECK", true); + if (WMCheck != None) + HasNetWM = true; + +#endif // #ifdef _IRR_COMPILE_WITH_X11_ + return true; +} + + +//! create the driver +void CIrrDeviceLinux::createDriver() +{ + switch(CreationParams.DriverType) + { +#ifdef _IRR_COMPILE_WITH_X11_ + case video::EDT_SOFTWARE: +#ifdef _IRR_COMPILE_WITH_SOFTWARE_ + VideoDriver = video::createSoftwareDriver(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this); +#else + os::Printer::log("No Software driver support compiled in.", ELL_ERROR); +#endif + break; + case video::EDT_BURNINGSVIDEO: +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + VideoDriver = video::createBurningVideoDriver(CreationParams, FileSystem, this); +#else + os::Printer::log("Burning's video driver was not compiled in.", ELL_ERROR); +#endif + break; + case video::EDT_OPENGL: +#ifdef _IRR_COMPILE_WITH_OPENGL_ + { + video::SExposedVideoData data; + data.OpenGLLinux.X11Window = XWindow; + data.OpenGLLinux.X11Display = XDisplay; + + ContextManager->initialize(CreationParams, data); + + VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, ContextManager); + } +#else + os::Printer::log("No OpenGL support compiled in.", ELL_ERROR); +#endif + break; + case video::EDT_OGLES1: +#ifdef _IRR_COMPILE_WITH_OGLES1_ + { + video::SExposedVideoData data; + data.OpenGLLinux.X11Window = XWindow; + data.OpenGLLinux.X11Display = XDisplay; + + ContextManager = new video::CEGLManager(); + ContextManager->initialize(CreationParams, data); + + VideoDriver = video::createOGLES1Driver(CreationParams, FileSystem, ContextManager); + } +#else + os::Printer::log("No OpenGL-ES1 support compiled in.", ELL_ERROR); +#endif + break; + case video::EDT_OGLES2: +#ifdef _IRR_COMPILE_WITH_OGLES2_ + { + video::SExposedVideoData data; + data.OpenGLLinux.X11Window = XWindow; + data.OpenGLLinux.X11Display = XDisplay; + + ContextManager = new video::CEGLManager(); + ContextManager->initialize(CreationParams, data); + + VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager); + } +#else + os::Printer::log("No OpenGL-ES2 support compiled in.", ELL_ERROR); +#endif + break; + case video::EDT_WEBGL1: +#ifdef _IRR_COMPILE_WITH_WEBGL1_ + { + video::SExposedVideoData data; + data.OpenGLLinux.X11Window = XWindow; + data.OpenGLLinux.X11Display = XDisplay; + + ContextManager = new video::CEGLManager(); + ContextManager->initialize(CreationParams, data); + + VideoDriver = video::createWebGL1Driver(CreationParams, FileSystem, ContextManager); + } +#else + os::Printer::log("No WebGL1 support compiled in.", ELL_ERROR); +#endif + break; + case video::DEPRECATED_EDT_DIRECT3D8_NO_LONGER_EXISTS: + case video::EDT_DIRECT3D9: + os::Printer::log("This driver is not available in Linux. Try OpenGL or Software renderer.", + ELL_ERROR); + break; + case video::EDT_NULL: + VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize); + break; + default: + os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR); + break; +#else + case video::EDT_NULL: + VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize); + break; + default: + os::Printer::log("No X11 support compiled in. Only Null driver available.", ELL_ERROR); + break; +#endif + } +} + +#ifdef _IRR_COMPILE_WITH_X11_ +bool CIrrDeviceLinux::createInputContext() +{ + // One one side it would be nicer to let users do that - on the other hand + // not setting the environment locale will not work when using i18n X11 functions. + // So users would have to call it always or their input is broken badly. + // We can restore immediately - so won't mess with anything in users apps. + core::stringc oldLocale(setlocale(LC_CTYPE, NULL)); + setlocale(LC_CTYPE, ""); // use environment locale + + if ( !XSupportsLocale() ) + { + os::Printer::log("Locale not supported. Falling back to non-i18n input.", ELL_WARNING); + setlocale(LC_CTYPE, oldLocale.c_str()); + return false; + } + + XInputMethod = XOpenIM(XDisplay, NULL, NULL, NULL); + if ( !XInputMethod ) + { + setlocale(LC_CTYPE, oldLocale.c_str()); + os::Printer::log("XOpenIM failed to create an input method. Falling back to non-i18n input.", ELL_WARNING); + return false; + } + + XIMStyles *im_supported_styles; + XGetIMValues(XInputMethod, XNQueryInputStyle, &im_supported_styles, (char*)NULL); + XIMStyle bestStyle = 0; + // TODO: If we want to support languages like chinese or japanese as well we probably have to work with callbacks here. + XIMStyle supportedStyle = XIMPreeditNone | XIMStatusNone; + for(int i=0; i < im_supported_styles->count_styles; ++i) + { + XIMStyle style = im_supported_styles->supported_styles[i]; + if ((style & supportedStyle) == style) /* if we can handle it */ + { + bestStyle = style; + break; + } + } + XFree(im_supported_styles); + + if ( !bestStyle ) + { + XDestroyIC(XInputContext); + XInputContext = 0; + + os::Printer::log("XInputMethod has no input style we can use. Falling back to non-i18n input.", ELL_WARNING); + setlocale(LC_CTYPE, oldLocale.c_str()); + return false; + } + + XInputContext = XCreateIC(XInputMethod, + XNInputStyle, bestStyle, + XNClientWindow, XWindow, + (char*)NULL); + if (!XInputContext ) + { + os::Printer::log("XInputContext failed to create an input context. Falling back to non-i18n input.", ELL_WARNING); + setlocale(LC_CTYPE, oldLocale.c_str()); + return false; + } + XSetICFocus(XInputContext); + setlocale(LC_CTYPE, oldLocale.c_str()); + return true; +} + +void CIrrDeviceLinux::destroyInputContext() +{ + if ( XInputContext ) + { + XUnsetICFocus(XInputContext); + XDestroyIC(XInputContext); + XInputContext = 0; + } + if ( XInputMethod ) + { + XCloseIM(XInputMethod); + XInputMethod = 0; + } +} + +EKEY_CODE CIrrDeviceLinux::getKeyCode(XEvent &event) +{ + EKEY_CODE keyCode = (EKEY_CODE)0; + + SKeyMap mp; + mp.X11Key = XkbKeycodeToKeysym(XDisplay, event.xkey.keycode, 0, 0); + // mp.X11Key = XKeycodeToKeysym(XDisplay, event.xkey.keycode, 0); // deprecated, if we still find platforms which need that we have to use some define + const s32 idx = KeyMap.binary_search(mp); + if (idx != -1) + { + keyCode = (EKEY_CODE)KeyMap[idx].Win32Key; + } + if (keyCode == 0) + { + // Any value is better than none, that allows at least using the keys. + // Worst case is that some keys will be identical, still better than _all_ + // unknown keys being identical. + if ( !mp.X11Key ) + { + keyCode = (EKEY_CODE)event.xkey.keycode; + os::Printer::log("No such X11Key, using event keycode", core::stringc(event.xkey.keycode).c_str(), ELL_INFORMATION); + } + else if (idx == -1) + { + keyCode = (EKEY_CODE)mp.X11Key; + os::Printer::log("EKEY_CODE not found, using orig. X11 keycode", core::stringc(mp.X11Key).c_str(), ELL_INFORMATION); + } + else + { + keyCode = (EKEY_CODE)mp.X11Key; + os::Printer::log("EKEY_CODE is 0, using orig. X11 keycode", core::stringc(mp.X11Key).c_str(), ELL_INFORMATION); + } + } + return keyCode; +} +#endif + +//! runs the device. Returns false if device wants to be deleted +bool CIrrDeviceLinux::run() +{ + os::Timer::tick(); + +#ifdef _IRR_COMPILE_WITH_X11_ + + if ( CursorControl ) + static_cast(CursorControl)->update(); + + if ((CreationParams.DriverType != video::EDT_NULL) && XDisplay) + { + SEvent irrevent; + irrevent.MouseInput.ButtonStates = 0xffffffff; + + while (XPending(XDisplay) > 0 && !Close) + { + XEvent event; + XNextEvent(XDisplay, &event); + + switch (event.type) + { + case ConfigureNotify: + // check for changed window size + if ((event.xconfigure.width != (int) Width) || + (event.xconfigure.height != (int) Height)) + { + Width = event.xconfigure.width; + Height = event.xconfigure.height; + + // resize image data + if (SoftwareImage) + { + XDestroyImage(SoftwareImage); + + SoftwareImage = XCreateImage(XDisplay, + VisualInfo->visual, VisualInfo->depth, + ZPixmap, 0, 0, Width, Height, + BitmapPad(XDisplay), 0); + + // use malloc because X will free it later on + if (SoftwareImage) + SoftwareImage->data = (char*) malloc(SoftwareImage->bytes_per_line * SoftwareImage->height * sizeof(char)); + } + + if (VideoDriver) + VideoDriver->OnResize(core::dimension2d(Width, Height)); + } + break; + + case MapNotify: + WindowMinimized=false; + break; + + case UnmapNotify: + WindowMinimized=true; + break; + + case FocusIn: + WindowHasFocus=true; + break; + + case FocusOut: + WindowHasFocus=false; + break; + + case MotionNotify: + irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT; + irrevent.MouseInput.Event = irr::EMIE_MOUSE_MOVED; + irrevent.MouseInput.X = event.xbutton.x; + irrevent.MouseInput.Y = event.xbutton.y; + irrevent.MouseInput.Control = (event.xkey.state & ControlMask) != 0; + irrevent.MouseInput.Shift = (event.xkey.state & ShiftMask) != 0; + + // mouse button states + irrevent.MouseInput.ButtonStates = (event.xbutton.state & Button1Mask) ? irr::EMBSM_LEFT : 0; + irrevent.MouseInput.ButtonStates |= (event.xbutton.state & Button3Mask) ? irr::EMBSM_RIGHT : 0; + irrevent.MouseInput.ButtonStates |= (event.xbutton.state & Button2Mask) ? irr::EMBSM_MIDDLE : 0; + + postEventFromUser(irrevent); + break; + + case ButtonPress: + case ButtonRelease: + + irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT; + irrevent.MouseInput.X = event.xbutton.x; + irrevent.MouseInput.Y = event.xbutton.y; + irrevent.MouseInput.Control = (event.xkey.state & ControlMask) != 0; + irrevent.MouseInput.Shift = (event.xkey.state & ShiftMask) != 0; + + // mouse button states + // This sets the state which the buttons had _prior_ to the event. + // So unlike on Windows the button which just got changed has still the old state here. + // We handle that below by flipping the corresponding bit later. + irrevent.MouseInput.ButtonStates = (event.xbutton.state & Button1Mask) ? irr::EMBSM_LEFT : 0; + irrevent.MouseInput.ButtonStates |= (event.xbutton.state & Button3Mask) ? irr::EMBSM_RIGHT : 0; + irrevent.MouseInput.ButtonStates |= (event.xbutton.state & Button2Mask) ? irr::EMBSM_MIDDLE : 0; + + irrevent.MouseInput.Event = irr::EMIE_COUNT; + + switch(event.xbutton.button) + { + case Button1: + irrevent.MouseInput.Event = + (event.type == ButtonPress) ? irr::EMIE_LMOUSE_PRESSED_DOWN : irr::EMIE_LMOUSE_LEFT_UP; + irrevent.MouseInput.ButtonStates ^= irr::EMBSM_LEFT; + break; + + case Button3: + irrevent.MouseInput.Event = + (event.type == ButtonPress) ? irr::EMIE_RMOUSE_PRESSED_DOWN : irr::EMIE_RMOUSE_LEFT_UP; + irrevent.MouseInput.ButtonStates ^= irr::EMBSM_RIGHT; + break; + + case Button2: + irrevent.MouseInput.Event = + (event.type == ButtonPress) ? irr::EMIE_MMOUSE_PRESSED_DOWN : irr::EMIE_MMOUSE_LEFT_UP; + irrevent.MouseInput.ButtonStates ^= irr::EMBSM_MIDDLE; + break; + + case Button4: + if (event.type == ButtonPress) + { + irrevent.MouseInput.Event = EMIE_MOUSE_WHEEL; + irrevent.MouseInput.Wheel = 1.0f; + } + break; + + case Button5: + if (event.type == ButtonPress) + { + irrevent.MouseInput.Event = EMIE_MOUSE_WHEEL; + irrevent.MouseInput.Wheel = -1.0f; + } + break; + } + + if (irrevent.MouseInput.Event != irr::EMIE_COUNT) + { + postEventFromUser(irrevent); + + if ( irrevent.MouseInput.Event >= EMIE_LMOUSE_PRESSED_DOWN && irrevent.MouseInput.Event <= EMIE_MMOUSE_PRESSED_DOWN ) + { + u32 clicks = checkSuccessiveClicks(irrevent.MouseInput.X, irrevent.MouseInput.Y, irrevent.MouseInput.Event); + if ( clicks == 2 ) + { + irrevent.MouseInput.Event = (EMOUSE_INPUT_EVENT)(EMIE_LMOUSE_DOUBLE_CLICK + irrevent.MouseInput.Event-EMIE_LMOUSE_PRESSED_DOWN); + postEventFromUser(irrevent); + } + else if ( clicks == 3 ) + { + irrevent.MouseInput.Event = (EMOUSE_INPUT_EVENT)(EMIE_LMOUSE_TRIPLE_CLICK + irrevent.MouseInput.Event-EMIE_LMOUSE_PRESSED_DOWN); + postEventFromUser(irrevent); + } + } + } + break; + + case MappingNotify: + XRefreshKeyboardMapping (&event.xmapping) ; + break; + + case KeyRelease: + if (0 == AutorepeatSupport && (XPending( XDisplay ) > 0) ) + { + // check for Autorepeat manually + // We'll do the same as Windows does: Only send KeyPressed + // So every KeyRelease is a real release + XEvent next_event; + XPeekEvent (event.xkey.display, &next_event); + if ((next_event.type == KeyPress) && + (next_event.xkey.keycode == event.xkey.keycode) && + (next_event.xkey.time - event.xkey.time) < 2) // usually same time, but on some systems a difference of 1 is possible + { + // Ignore the key release event + break; + } + } + + irrevent.EventType = irr::EET_KEY_INPUT_EVENT; + irrevent.KeyInput.PressedDown = false; + irrevent.KeyInput.Char = 0; // on release that's undefined + irrevent.KeyInput.Control = (event.xkey.state & ControlMask) != 0; + irrevent.KeyInput.Shift = (event.xkey.state & ShiftMask) != 0; + irrevent.KeyInput.Key = getKeyCode(event); + + postEventFromUser(irrevent); + break; + + case KeyPress: + { + SKeyMap mp; + if ( XInputContext ) + { + wchar_t buf[8]={0}; + Status status; + int strLen = XwcLookupString(XInputContext, &event.xkey, buf, sizeof(buf), &mp.X11Key, &status); + if ( status == XBufferOverflow ) + { + os::Printer::log("XwcLookupString needs a larger buffer", ELL_INFORMATION); + } + if ( strLen > 0 && (status == XLookupChars || status == XLookupBoth) ) + { + if ( strLen > 1 ) + os::Printer::log("Additional returned characters dropped", ELL_INFORMATION); + irrevent.KeyInput.Char = buf[0]; + } + else + { +#if 0 // Most of those are fine - but useful to have the info when debugging Irrlicht itself. + if ( status == XLookupNone ) + os::Printer::log("XLookupNone", ELL_INFORMATION); + else if ( status == XLookupKeySym ) + // Getting this also when user did not set setlocale(LC_ALL, ""); and using an unknown locale + // XSupportsLocale doesn't seeem to catch that unfortunately - any other ideas to catch it are welcome. + os::Printer::log("XLookupKeySym", ELL_INFORMATION); + else if ( status == XBufferOverflow ) + os::Printer::log("XBufferOverflow", ELL_INFORMATION); + else if ( strLen == 0 ) + os::Printer::log("no string", ELL_INFORMATION); +#endif + irrevent.KeyInput.Char = 0; + } + } + else // Old version without InputContext. Does not support i18n, but good to have as fallback. + { + union + { + char buf[8]; + wchar_t wbuf[2]; + } tmp = {{0}}; + XLookupString(&event.xkey, tmp.buf, sizeof(tmp.buf), &mp.X11Key, NULL); + irrevent.KeyInput.Char = tmp.wbuf[0]; + } + + irrevent.EventType = irr::EET_KEY_INPUT_EVENT; + irrevent.KeyInput.PressedDown = true; + irrevent.KeyInput.Control = (event.xkey.state & ControlMask) != 0; + irrevent.KeyInput.Shift = (event.xkey.state & ShiftMask) != 0; + irrevent.KeyInput.Key = getKeyCode(event); + + postEventFromUser(irrevent); + } + break; + + case ClientMessage: + { + char *atom = XGetAtomName(XDisplay, event.xclient.message_type); + if (*atom == *wmDeleteWindow) + { + os::Printer::log("Quit message received.", ELL_INFORMATION); + Close = true; + } + else + { + // we assume it's a user message + irrevent.EventType = irr::EET_USER_EVENT; + irrevent.UserEvent.UserData1 = static_cast(event.xclient.data.l[0]); + irrevent.UserEvent.UserData2 = static_cast(event.xclient.data.l[1]); + postEventFromUser(irrevent); + } + XFree(atom); + } + break; + + case SelectionRequest: + { + XEvent respond; + XSelectionRequestEvent *req = &(event.xselectionrequest); + if ( req->target == XA_STRING) + { + XChangeProperty (XDisplay, + req->requestor, + req->property, req->target, + 8, // format + PropModeReplace, + (unsigned char*) Clipboard.c_str(), + Clipboard.size()); + respond.xselection.property = req->property; + } + else if ( req->target == X_ATOM_TARGETS ) + { + long data[2]; + + data[0] = X_ATOM_TEXT; + data[1] = XA_STRING; + + XChangeProperty (XDisplay, req->requestor, + req->property, req->target, + 8, PropModeReplace, + (unsigned char *) &data, + sizeof (data)); + respond.xselection.property = req->property; + } + else + { + respond.xselection.property= None; + } + respond.xselection.type= SelectionNotify; + respond.xselection.display= req->display; + respond.xselection.requestor= req->requestor; + respond.xselection.selection=req->selection; + respond.xselection.target= req->target; + respond.xselection.time = req->time; + XSendEvent (XDisplay, req->requestor,0,0,&respond); + XFlush (XDisplay); + } + break; + + default: + break; + } // end switch + + } // end while + } +#endif //_IRR_COMPILE_WITH_X11_ + + if (!Close) + pollJoysticks(); + + return !Close; +} + + +//! Pause the current process for the minimum time allowed only to allow other processes to execute +void CIrrDeviceLinux::yield() +{ + struct timespec ts = {0,1}; + nanosleep(&ts, NULL); +} + + +//! Pause execution and let other processes to run for a specified amount of time. +void CIrrDeviceLinux::sleep(u32 timeMs, bool pauseTimer=false) +{ + const bool wasStopped = Timer ? Timer->isStopped() : true; + + struct timespec ts; + ts.tv_sec = (time_t) (timeMs / 1000); + ts.tv_nsec = (long) (timeMs % 1000) * 1000000; + + if (pauseTimer && !wasStopped) + Timer->stop(); + + nanosleep(&ts, NULL); + + if (pauseTimer && !wasStopped) + Timer->start(); +} + + +//! sets the caption of the window +void CIrrDeviceLinux::setWindowCaption(const wchar_t* text) +{ +#ifdef _IRR_COMPILE_WITH_X11_ + if (CreationParams.DriverType == video::EDT_NULL) + return; + + XTextProperty txt; + if (Success==XwcTextListToTextProperty(XDisplay, const_cast(&text), + 1, XStdICCTextStyle, &txt)) + { + XSetWMName(XDisplay, XWindow, &txt); + XSetWMIconName(XDisplay, XWindow, &txt); + XFree(txt.value); + } +#endif +} + + +//! presents a surface in the client area +bool CIrrDeviceLinux::present(video::IImage* image, void* windowId, core::rect* srcRect) +{ +#ifdef _IRR_COMPILE_WITH_X11_ + // this is only necessary for software drivers. + if (!SoftwareImage) + return true; + + // thx to Nadav, who send me some clues of how to display the image + // to the X Server. + + 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) + { + case 16: + if (SoftwareImage->depth==16) + destColor = video::ECF_R5G6B5; + else + destColor = video::ECF_A1R5G5B5; + break; + case 24: destColor = video::ECF_R8G8B8; break; + case 32: destColor = video::ECF_A8R8G8B8; break; + default: + os::Printer::log("Unsupported screen depth."); + return false; + } + + u8* srcdata = reinterpret_cast(image->getData()); + u8* destData = reinterpret_cast(SoftwareImage->data); + + 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; + destData+=destPitch; + } + + GC gc = DefaultGC(XDisplay, DefaultScreen(XDisplay)); + Window myWindow=XWindow; + if (windowId) + myWindow = reinterpret_cast(windowId); + XPutImage(XDisplay, myWindow, gc, SoftwareImage, 0, 0, 0, 0, destwidth, destheight); +#endif + return true; +} + + +//! notifies the device that it should close itself +void CIrrDeviceLinux::closeDevice() +{ + Close = true; +} + + +//! returns if window is active. if not, nothing need to be drawn +bool CIrrDeviceLinux::isWindowActive() const +{ + return (WindowHasFocus && !WindowMinimized); +} + + +//! returns if window has focus. +bool CIrrDeviceLinux::isWindowFocused() const +{ + return WindowHasFocus; +} + + +//! returns if window is minimized. +bool CIrrDeviceLinux::isWindowMinimized() const +{ + return WindowMinimized; +} + + +//! returns color format of the window. +video::ECOLOR_FORMAT CIrrDeviceLinux::getColorFormat() const +{ +#ifdef _IRR_COMPILE_WITH_X11_ + if (VisualInfo && (VisualInfo->depth != 16)) + return video::ECF_R8G8B8; + else +#endif + return video::ECF_R5G6B5; +} + + +//! Sets if the window should be resizable in windowed mode. +void CIrrDeviceLinux::setResizable(bool resize) +{ +#ifdef _IRR_COMPILE_WITH_X11_ + if (CreationParams.DriverType == video::EDT_NULL || CreationParams.Fullscreen ) + return; + + if ( !resize ) + { + // Must be heap memory because data size depends on X Server + XSizeHints *hints = XAllocSizeHints(); + hints->flags=PSize|PMinSize|PMaxSize; + hints->min_width=hints->max_width=hints->base_width=Width; + hints->min_height=hints->max_height=hints->base_height=Height; + XSetWMNormalHints(XDisplay, XWindow, hints); + XFree(hints); + } + else + { + XSetWMNormalHints(XDisplay, XWindow, StdHints); + } + XFlush(XDisplay); +#endif // #ifdef _IRR_COMPILE_WITH_X11_ +} + +//! Resize the render window. +void CIrrDeviceLinux::setWindowSize(const irr::core::dimension2d& size) +{ +#ifdef _IRR_COMPILE_WITH_X11_ + if (CreationParams.DriverType == video::EDT_NULL || CreationParams.Fullscreen ) + return; + + XWindowChanges values; + values.width = size.Width; + values.height = size.Height; + XConfigureWindow(XDisplay, XWindow, CWWidth | CWHeight, &values); + XFlush(XDisplay); +#endif // #ifdef _IRR_COMPILE_WITH_X11_ +} + +//! Return pointer to a list with all video modes supported by the gfx adapter. +video::IVideoModeList* CIrrDeviceLinux::getVideoModeList() +{ +#ifdef _IRR_COMPILE_WITH_X11_ + if (!VideoModeList->getVideoModeCount()) + { + bool temporaryDisplay = false; + + if (!XDisplay) + { + XDisplay = XOpenDisplay(0); + temporaryDisplay=true; + } + if (XDisplay) + { + #if defined(_IRR_LINUX_X11_VIDMODE_) || defined(_IRR_LINUX_X11_RANDR_) + s32 eventbase, errorbase; + s32 defaultDepth=DefaultDepth(XDisplay,Screennr); + #endif + + #ifdef _IRR_LINUX_X11_VIDMODE_ + if (XF86VidModeQueryExtension(XDisplay, &eventbase, &errorbase)) + { + // enumerate video modes + int modeCount; + XF86VidModeModeInfo** modes; + + XF86VidModeGetAllModeLines(XDisplay, Screennr, &modeCount, &modes); + + // save current video mode + OldVideoMode = *modes[0]; + + // find fitting mode + + VideoModeList->setDesktop(defaultDepth, core::dimension2d( + modes[0]->hdisplay, modes[0]->vdisplay)); + for (int i = 0; iaddMode(core::dimension2d( + modes[i]->hdisplay, modes[i]->vdisplay), defaultDepth); + } + XFree(modes); + } + else + #endif + #ifdef _IRR_LINUX_X11_RANDR_ + if (XRRQueryExtension(XDisplay, &eventbase, &errorbase)) + { + int modeCount; + XRRScreenConfiguration *config=XRRGetScreenInfo(XDisplay,DefaultRootWindow(XDisplay)); + OldRandrMode=XRRConfigCurrentConfiguration(config,&OldRandrRotation); + XRRScreenSize *modes=XRRConfigSizes(config,&modeCount); + VideoModeList->setDesktop(defaultDepth, core::dimension2d( + modes[OldRandrMode].width, modes[OldRandrMode].height)); + for (int i = 0; iaddMode(core::dimension2d( + modes[i].width, modes[i].height), defaultDepth); + } + XRRFreeScreenConfigInfo(config); + } + else + #endif + { + os::Printer::log("VidMode or RandR X11 extension requireed for VideoModeList." , ELL_WARNING); + } + } + if (XDisplay && temporaryDisplay) + { + XCloseDisplay(XDisplay); + XDisplay=0; + } + } +#endif + + return VideoModeList; +} + + +//! Minimize window +void CIrrDeviceLinux::minimizeWindow() +{ +#ifdef _IRR_COMPILE_WITH_X11_ + XIconifyWindow(XDisplay, XWindow, Screennr); +#endif +} + + +//! Maximize window +void CIrrDeviceLinux::maximizeWindow() +{ +#ifdef _IRR_COMPILE_WITH_X11_ + // Maximize is not implemented in bare X, it's a WM construct. + if (HasNetWM) + { + XEvent ev = {0}; + + ev.type = ClientMessage; + ev.xclient.window = XWindow; + ev.xclient.message_type = X_ATOM_NETWM_STATE; + ev.xclient.format = 32; + ev.xclient.data.l[0] = 1; // _NET_WM_STATE_ADD + ev.xclient.data.l[1] = X_ATOM_NETWM_MAXIMIZE_VERT; + ev.xclient.data.l[2] = X_ATOM_NETWM_MAXIMIZE_HORZ; + + XSendEvent(XDisplay, DefaultRootWindow(XDisplay), false, + SubstructureNotifyMask|SubstructureRedirectMask, &ev); + } + + XMapWindow(XDisplay, XWindow); +#endif +} + + +//! Restore original window size +void CIrrDeviceLinux::restoreWindow() +{ +#ifdef _IRR_COMPILE_WITH_X11_ + // Maximize is not implemented in bare X, it's a WM construct. + if (HasNetWM) + { + XEvent ev = {0}; + + ev.type = ClientMessage; + ev.xclient.window = XWindow; + ev.xclient.message_type = X_ATOM_NETWM_STATE; + ev.xclient.format = 32; + ev.xclient.data.l[0] = 0; // _NET_WM_STATE_REMOVE + ev.xclient.data.l[1] = X_ATOM_NETWM_MAXIMIZE_VERT; + ev.xclient.data.l[2] = X_ATOM_NETWM_MAXIMIZE_HORZ; + + XSendEvent(XDisplay, DefaultRootWindow(XDisplay), false, + SubstructureNotifyMask|SubstructureRedirectMask, &ev); + } + + XMapWindow(XDisplay, XWindow); +#endif +} + +core::position2di CIrrDeviceLinux::getWindowPosition() +{ + int wx = 0, wy = 0; +#ifdef _IRR_COMPILE_WITH_X11_ + Window child; + XTranslateCoordinates(XDisplay, XWindow, DefaultRootWindow(XDisplay), 0, 0, &wx, &wy, &child); +#endif + return core::position2di(wx, wy); +} + +void CIrrDeviceLinux::createKeyMap() +{ + // I don't know if this is the best method to create + // the lookuptable, but I'll leave it like that until + // I find a better version. + // Search for missing numbers in keysymdef.h + +#ifdef _IRR_COMPILE_WITH_X11_ + KeyMap.reallocate(190); + KeyMap.push_back(SKeyMap(XK_BackSpace, KEY_BACK)); + KeyMap.push_back(SKeyMap(XK_Tab, KEY_TAB)); + KeyMap.push_back(SKeyMap(XK_ISO_Left_Tab, KEY_TAB)); + KeyMap.push_back(SKeyMap(XK_Linefeed, 0)); // ??? + KeyMap.push_back(SKeyMap(XK_Clear, KEY_CLEAR)); + KeyMap.push_back(SKeyMap(XK_Return, KEY_RETURN)); + KeyMap.push_back(SKeyMap(XK_Pause, KEY_PAUSE)); + KeyMap.push_back(SKeyMap(XK_Scroll_Lock, KEY_SCROLL)); + KeyMap.push_back(SKeyMap(XK_Sys_Req, 0)); // ??? + KeyMap.push_back(SKeyMap(XK_Escape, KEY_ESCAPE)); + KeyMap.push_back(SKeyMap(XK_Insert, KEY_INSERT)); + KeyMap.push_back(SKeyMap(XK_Delete, KEY_DELETE)); + KeyMap.push_back(SKeyMap(XK_Home, KEY_HOME)); + KeyMap.push_back(SKeyMap(XK_Left, KEY_LEFT)); + KeyMap.push_back(SKeyMap(XK_Up, KEY_UP)); + KeyMap.push_back(SKeyMap(XK_Right, KEY_RIGHT)); + KeyMap.push_back(SKeyMap(XK_Down, KEY_DOWN)); + KeyMap.push_back(SKeyMap(XK_Prior, KEY_PRIOR)); + KeyMap.push_back(SKeyMap(XK_Page_Up, KEY_PRIOR)); + KeyMap.push_back(SKeyMap(XK_Next, KEY_NEXT)); + KeyMap.push_back(SKeyMap(XK_Page_Down, KEY_NEXT)); + KeyMap.push_back(SKeyMap(XK_End, KEY_END)); + KeyMap.push_back(SKeyMap(XK_Begin, KEY_HOME)); + KeyMap.push_back(SKeyMap(XK_Num_Lock, KEY_NUMLOCK)); + KeyMap.push_back(SKeyMap(XK_KP_Space, KEY_SPACE)); + KeyMap.push_back(SKeyMap(XK_KP_Tab, KEY_TAB)); + KeyMap.push_back(SKeyMap(XK_KP_Enter, KEY_RETURN)); + KeyMap.push_back(SKeyMap(XK_KP_F1, KEY_F1)); + KeyMap.push_back(SKeyMap(XK_KP_F2, KEY_F2)); + KeyMap.push_back(SKeyMap(XK_KP_F3, KEY_F3)); + KeyMap.push_back(SKeyMap(XK_KP_F4, KEY_F4)); + KeyMap.push_back(SKeyMap(XK_KP_Home, KEY_HOME)); + KeyMap.push_back(SKeyMap(XK_KP_Left, KEY_LEFT)); + KeyMap.push_back(SKeyMap(XK_KP_Up, KEY_UP)); + KeyMap.push_back(SKeyMap(XK_KP_Right, KEY_RIGHT)); + KeyMap.push_back(SKeyMap(XK_KP_Down, KEY_DOWN)); + KeyMap.push_back(SKeyMap(XK_Print, KEY_PRINT)); + KeyMap.push_back(SKeyMap(XK_KP_Prior, KEY_PRIOR)); + KeyMap.push_back(SKeyMap(XK_KP_Page_Up, KEY_PRIOR)); + KeyMap.push_back(SKeyMap(XK_KP_Next, KEY_NEXT)); + KeyMap.push_back(SKeyMap(XK_KP_Page_Down, KEY_NEXT)); + KeyMap.push_back(SKeyMap(XK_KP_End, KEY_END)); + KeyMap.push_back(SKeyMap(XK_KP_Begin, KEY_HOME)); + KeyMap.push_back(SKeyMap(XK_KP_Insert, KEY_INSERT)); + KeyMap.push_back(SKeyMap(XK_KP_Delete, KEY_DELETE)); + KeyMap.push_back(SKeyMap(XK_KP_Equal, 0)); // ??? + KeyMap.push_back(SKeyMap(XK_KP_Multiply, KEY_MULTIPLY)); + KeyMap.push_back(SKeyMap(XK_KP_Add, KEY_ADD)); + KeyMap.push_back(SKeyMap(XK_KP_Separator, KEY_SEPARATOR)); + KeyMap.push_back(SKeyMap(XK_KP_Subtract, KEY_SUBTRACT)); + KeyMap.push_back(SKeyMap(XK_KP_Decimal, KEY_DECIMAL)); + KeyMap.push_back(SKeyMap(XK_KP_Divide, KEY_DIVIDE)); + KeyMap.push_back(SKeyMap(XK_KP_0, KEY_NUMPAD0)); + KeyMap.push_back(SKeyMap(XK_KP_1, KEY_NUMPAD1)); + KeyMap.push_back(SKeyMap(XK_KP_2, KEY_NUMPAD2)); + KeyMap.push_back(SKeyMap(XK_KP_3, KEY_NUMPAD3)); + KeyMap.push_back(SKeyMap(XK_KP_4, KEY_NUMPAD4)); + KeyMap.push_back(SKeyMap(XK_KP_5, KEY_NUMPAD5)); + KeyMap.push_back(SKeyMap(XK_KP_6, KEY_NUMPAD6)); + KeyMap.push_back(SKeyMap(XK_KP_7, KEY_NUMPAD7)); + KeyMap.push_back(SKeyMap(XK_KP_8, KEY_NUMPAD8)); + KeyMap.push_back(SKeyMap(XK_KP_9, KEY_NUMPAD9)); + KeyMap.push_back(SKeyMap(XK_F1, KEY_F1)); + KeyMap.push_back(SKeyMap(XK_F2, KEY_F2)); + KeyMap.push_back(SKeyMap(XK_F3, KEY_F3)); + KeyMap.push_back(SKeyMap(XK_F4, KEY_F4)); + KeyMap.push_back(SKeyMap(XK_F5, KEY_F5)); + KeyMap.push_back(SKeyMap(XK_F6, KEY_F6)); + KeyMap.push_back(SKeyMap(XK_F7, KEY_F7)); + KeyMap.push_back(SKeyMap(XK_F8, KEY_F8)); + KeyMap.push_back(SKeyMap(XK_F9, KEY_F9)); + KeyMap.push_back(SKeyMap(XK_F10, KEY_F10)); + KeyMap.push_back(SKeyMap(XK_F11, KEY_F11)); + KeyMap.push_back(SKeyMap(XK_F12, KEY_F12)); + KeyMap.push_back(SKeyMap(XK_Shift_L, KEY_LSHIFT)); + KeyMap.push_back(SKeyMap(XK_Shift_R, KEY_RSHIFT)); + KeyMap.push_back(SKeyMap(XK_Control_L, KEY_LCONTROL)); + KeyMap.push_back(SKeyMap(XK_Control_R, KEY_RCONTROL)); + KeyMap.push_back(SKeyMap(XK_Caps_Lock, KEY_CAPITAL)); + KeyMap.push_back(SKeyMap(XK_Shift_Lock, KEY_CAPITAL)); + KeyMap.push_back(SKeyMap(XK_Meta_L, KEY_LWIN)); + KeyMap.push_back(SKeyMap(XK_Meta_R, KEY_RWIN)); + KeyMap.push_back(SKeyMap(XK_Alt_L, KEY_LMENU)); + KeyMap.push_back(SKeyMap(XK_Alt_R, KEY_RMENU)); + KeyMap.push_back(SKeyMap(XK_ISO_Level3_Shift, KEY_RMENU)); + KeyMap.push_back(SKeyMap(XK_Menu, KEY_MENU)); + KeyMap.push_back(SKeyMap(XK_space, KEY_SPACE)); + KeyMap.push_back(SKeyMap(XK_exclam, 0)); //? + KeyMap.push_back(SKeyMap(XK_quotedbl, 0)); //? + KeyMap.push_back(SKeyMap(XK_section, 0)); //? + KeyMap.push_back(SKeyMap(XK_numbersign, KEY_OEM_2)); + KeyMap.push_back(SKeyMap(XK_dollar, 0)); //? + KeyMap.push_back(SKeyMap(XK_percent, 0)); //? + KeyMap.push_back(SKeyMap(XK_ampersand, 0)); //? + KeyMap.push_back(SKeyMap(XK_apostrophe, KEY_OEM_7)); + KeyMap.push_back(SKeyMap(XK_parenleft, 0)); //? + KeyMap.push_back(SKeyMap(XK_parenright, 0)); //? + KeyMap.push_back(SKeyMap(XK_asterisk, 0)); //? + KeyMap.push_back(SKeyMap(XK_plus, KEY_PLUS)); //? + KeyMap.push_back(SKeyMap(XK_comma, KEY_COMMA)); //? + KeyMap.push_back(SKeyMap(XK_minus, KEY_MINUS)); //? + KeyMap.push_back(SKeyMap(XK_period, KEY_PERIOD)); //? + KeyMap.push_back(SKeyMap(XK_slash, KEY_OEM_2)); //? + KeyMap.push_back(SKeyMap(XK_0, KEY_KEY_0)); + KeyMap.push_back(SKeyMap(XK_1, KEY_KEY_1)); + KeyMap.push_back(SKeyMap(XK_2, KEY_KEY_2)); + KeyMap.push_back(SKeyMap(XK_3, KEY_KEY_3)); + KeyMap.push_back(SKeyMap(XK_4, KEY_KEY_4)); + KeyMap.push_back(SKeyMap(XK_5, KEY_KEY_5)); + KeyMap.push_back(SKeyMap(XK_6, KEY_KEY_6)); + KeyMap.push_back(SKeyMap(XK_7, KEY_KEY_7)); + KeyMap.push_back(SKeyMap(XK_8, KEY_KEY_8)); + KeyMap.push_back(SKeyMap(XK_9, KEY_KEY_9)); + KeyMap.push_back(SKeyMap(XK_colon, 0)); //? + KeyMap.push_back(SKeyMap(XK_semicolon, KEY_OEM_1)); + KeyMap.push_back(SKeyMap(XK_less, KEY_OEM_102)); + KeyMap.push_back(SKeyMap(XK_equal, KEY_PLUS)); + KeyMap.push_back(SKeyMap(XK_greater, 0)); //? + KeyMap.push_back(SKeyMap(XK_question, 0)); //? + KeyMap.push_back(SKeyMap(XK_at, KEY_KEY_2)); //? + KeyMap.push_back(SKeyMap(XK_mu, 0)); //? + KeyMap.push_back(SKeyMap(XK_EuroSign, 0)); //? + KeyMap.push_back(SKeyMap(XK_A, KEY_KEY_A)); + KeyMap.push_back(SKeyMap(XK_B, KEY_KEY_B)); + KeyMap.push_back(SKeyMap(XK_C, KEY_KEY_C)); + KeyMap.push_back(SKeyMap(XK_D, KEY_KEY_D)); + KeyMap.push_back(SKeyMap(XK_E, KEY_KEY_E)); + KeyMap.push_back(SKeyMap(XK_F, KEY_KEY_F)); + KeyMap.push_back(SKeyMap(XK_G, KEY_KEY_G)); + KeyMap.push_back(SKeyMap(XK_H, KEY_KEY_H)); + KeyMap.push_back(SKeyMap(XK_I, KEY_KEY_I)); + KeyMap.push_back(SKeyMap(XK_J, KEY_KEY_J)); + KeyMap.push_back(SKeyMap(XK_K, KEY_KEY_K)); + KeyMap.push_back(SKeyMap(XK_L, KEY_KEY_L)); + KeyMap.push_back(SKeyMap(XK_M, KEY_KEY_M)); + KeyMap.push_back(SKeyMap(XK_N, KEY_KEY_N)); + KeyMap.push_back(SKeyMap(XK_O, KEY_KEY_O)); + KeyMap.push_back(SKeyMap(XK_P, KEY_KEY_P)); + KeyMap.push_back(SKeyMap(XK_Q, KEY_KEY_Q)); + KeyMap.push_back(SKeyMap(XK_R, KEY_KEY_R)); + KeyMap.push_back(SKeyMap(XK_S, KEY_KEY_S)); + KeyMap.push_back(SKeyMap(XK_T, KEY_KEY_T)); + KeyMap.push_back(SKeyMap(XK_U, KEY_KEY_U)); + KeyMap.push_back(SKeyMap(XK_V, KEY_KEY_V)); + KeyMap.push_back(SKeyMap(XK_W, KEY_KEY_W)); + KeyMap.push_back(SKeyMap(XK_X, KEY_KEY_X)); + KeyMap.push_back(SKeyMap(XK_Y, KEY_KEY_Y)); + KeyMap.push_back(SKeyMap(XK_Z, KEY_KEY_Z)); + KeyMap.push_back(SKeyMap(XK_bracketleft, KEY_OEM_4)); + KeyMap.push_back(SKeyMap(XK_backslash, KEY_OEM_5)); + KeyMap.push_back(SKeyMap(XK_bracketright, KEY_OEM_6)); + KeyMap.push_back(SKeyMap(XK_asciicircum, KEY_OEM_5)); + KeyMap.push_back(SKeyMap(XK_dead_circumflex, KEY_OEM_5)); + KeyMap.push_back(SKeyMap(XK_degree, 0)); //? + KeyMap.push_back(SKeyMap(XK_underscore, KEY_MINUS)); //? + KeyMap.push_back(SKeyMap(XK_grave, KEY_OEM_3)); + KeyMap.push_back(SKeyMap(XK_dead_grave, KEY_OEM_3)); + KeyMap.push_back(SKeyMap(XK_acute, KEY_OEM_6)); + KeyMap.push_back(SKeyMap(XK_dead_acute, KEY_OEM_6)); + KeyMap.push_back(SKeyMap(XK_a, KEY_KEY_A)); + KeyMap.push_back(SKeyMap(XK_b, KEY_KEY_B)); + KeyMap.push_back(SKeyMap(XK_c, KEY_KEY_C)); + KeyMap.push_back(SKeyMap(XK_d, KEY_KEY_D)); + KeyMap.push_back(SKeyMap(XK_e, KEY_KEY_E)); + KeyMap.push_back(SKeyMap(XK_f, KEY_KEY_F)); + KeyMap.push_back(SKeyMap(XK_g, KEY_KEY_G)); + KeyMap.push_back(SKeyMap(XK_h, KEY_KEY_H)); + KeyMap.push_back(SKeyMap(XK_i, KEY_KEY_I)); + KeyMap.push_back(SKeyMap(XK_j, KEY_KEY_J)); + KeyMap.push_back(SKeyMap(XK_k, KEY_KEY_K)); + KeyMap.push_back(SKeyMap(XK_l, KEY_KEY_L)); + KeyMap.push_back(SKeyMap(XK_m, KEY_KEY_M)); + KeyMap.push_back(SKeyMap(XK_n, KEY_KEY_N)); + KeyMap.push_back(SKeyMap(XK_o, KEY_KEY_O)); + KeyMap.push_back(SKeyMap(XK_p, KEY_KEY_P)); + KeyMap.push_back(SKeyMap(XK_q, KEY_KEY_Q)); + KeyMap.push_back(SKeyMap(XK_r, KEY_KEY_R)); + KeyMap.push_back(SKeyMap(XK_s, KEY_KEY_S)); + KeyMap.push_back(SKeyMap(XK_t, KEY_KEY_T)); + KeyMap.push_back(SKeyMap(XK_u, KEY_KEY_U)); + KeyMap.push_back(SKeyMap(XK_v, KEY_KEY_V)); + KeyMap.push_back(SKeyMap(XK_w, KEY_KEY_W)); + KeyMap.push_back(SKeyMap(XK_x, KEY_KEY_X)); + KeyMap.push_back(SKeyMap(XK_y, KEY_KEY_Y)); + KeyMap.push_back(SKeyMap(XK_z, KEY_KEY_Z)); + KeyMap.push_back(SKeyMap(XK_ssharp, KEY_OEM_4)); + KeyMap.push_back(SKeyMap(XK_adiaeresis, KEY_OEM_7)); + KeyMap.push_back(SKeyMap(XK_odiaeresis, KEY_OEM_3)); + KeyMap.push_back(SKeyMap(XK_udiaeresis, KEY_OEM_1)); + KeyMap.push_back(SKeyMap(XK_Super_L, KEY_LWIN)); + KeyMap.push_back(SKeyMap(XK_Super_R, KEY_RWIN)); + + KeyMap.sort(); +#endif +} + +bool CIrrDeviceLinux::activateJoysticks(core::array & joystickInfo) +{ +#if defined (_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) + + joystickInfo.clear(); + + u32 joystick; + for (joystick = 0; joystick < 32; ++joystick) + { + // The joystick device could be here... + core::stringc devName = "/dev/js"; + devName += joystick; + + SJoystickInfo returnInfo; + JoystickInfo info; + + info.fd = open(devName.c_str(), O_RDONLY); + if (-1 == info.fd) + { + // ...but Ubuntu and possibly other distros + // create the devices in /dev/input + devName = "/dev/input/js"; + devName += joystick; + info.fd = open(devName.c_str(), O_RDONLY); + if (-1 == info.fd) + { + // and BSD here + devName = "/dev/joy"; + devName += joystick; + info.fd = open(devName.c_str(), O_RDONLY); + } + } + + if (-1 == info.fd) + continue; + +#ifdef __FreeBSD__ + info.axes=2; + info.buttons=2; +#else + ioctl( info.fd, JSIOCGAXES, &(info.axes) ); + ioctl( info.fd, JSIOCGBUTTONS, &(info.buttons) ); + fcntl( info.fd, F_SETFL, O_NONBLOCK ); +#endif + + (void)memset(&info.persistentData, 0, sizeof(info.persistentData)); + info.persistentData.EventType = irr::EET_JOYSTICK_INPUT_EVENT; + info.persistentData.JoystickEvent.Joystick = ActiveJoysticks.size(); + + // There's no obvious way to determine which (if any) axes represent a POV + // hat, so we'll just set it to "not used" and forget about it. + info.persistentData.JoystickEvent.POV = 65535; + + ActiveJoysticks.push_back(info); + + returnInfo.Joystick = joystick; + returnInfo.PovHat = SJoystickInfo::POV_HAT_UNKNOWN; + returnInfo.Axes = info.axes; + returnInfo.Buttons = info.buttons; + +#ifndef __FreeBSD__ + char name[80]; + ioctl( info.fd, JSIOCGNAME(80), name); + returnInfo.Name = name; +#endif + + joystickInfo.push_back(returnInfo); + } + + for (joystick = 0; joystick < joystickInfo.size(); ++joystick) + { + char logString[256]; + (void)sprintf(logString, "Found joystick %u, %u axes, %u buttons '%s'", + joystick, joystickInfo[joystick].Axes, + joystickInfo[joystick].Buttons, joystickInfo[joystick].Name.c_str()); + os::Printer::log(logString, ELL_INFORMATION); + } + + return true; +#else + return false; +#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ +} + + +void CIrrDeviceLinux::pollJoysticks() +{ +#if defined (_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) + if (0 == ActiveJoysticks.size()) + return; + + for (u32 j= 0; j< ActiveJoysticks.size(); ++j) + { + JoystickInfo & info = ActiveJoysticks[j]; + +#ifdef __FreeBSD__ + struct joystick js; + if (read(info.fd, &js, sizeof(js)) == sizeof(js)) + { + info.persistentData.JoystickEvent.ButtonStates = js.b1 | (js.b2 << 1); /* should be a two-bit field */ + info.persistentData.JoystickEvent.Axis[0] = js.x; /* X axis */ + info.persistentData.JoystickEvent.Axis[1] = js.y; /* Y axis */ + } +#else + struct js_event event; + while (sizeof(event) == read(info.fd, &event, sizeof(event))) + { + switch(event.type & ~JS_EVENT_INIT) + { + case JS_EVENT_BUTTON: + if (event.value) + info.persistentData.JoystickEvent.ButtonStates |= (1 << event.number); + else + info.persistentData.JoystickEvent.ButtonStates &= ~(1 << event.number); + break; + + case JS_EVENT_AXIS: + if (event.number < SEvent::SJoystickEvent::NUMBER_OF_AXES) + info.persistentData.JoystickEvent.Axis[event.number] = event.value; + break; + + default: + break; + } + } +#endif + + // Send an irrlicht joystick event once per ::run() even if no new data were received. + (void)postEventFromUser(info.persistentData); + } +#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ +} + + +//! Set the current Gamma Value for the Display +bool CIrrDeviceLinux::setGammaRamp( f32 red, f32 green, f32 blue, f32 brightness, f32 contrast ) +{ + #if defined(_IRR_LINUX_X11_VIDMODE_) || defined(_IRR_LINUX_X11_RANDR_) + s32 eventbase, errorbase; + #ifdef _IRR_LINUX_X11_VIDMODE_ + if (XF86VidModeQueryExtension(XDisplay, &eventbase, &errorbase)) + { + XF86VidModeGamma gamma; + gamma.red=red; + gamma.green=green; + gamma.blue=blue; + XF86VidModeSetGamma(XDisplay, Screennr, &gamma); + return true; + } + #endif + #if defined(_IRR_LINUX_X11_VIDMODE_) && defined(_IRR_LINUX_X11_RANDR_) + else + #endif + #ifdef _IRR_LINUX_X11_RANDR_ + if (XRRQueryExtension(XDisplay, &eventbase, &errorbase)) + { + XRRQueryVersion(XDisplay, &eventbase, &errorbase); // major, minor + if (eventbase>=1 && errorbase>1) + { + #if (RANDR_MAJOR>1 || RANDR_MINOR>1) + XRRCrtcGamma *gamma = XRRGetCrtcGamma(XDisplay, Screennr); + if (gamma) + { + *gamma->red=(u16)red; + *gamma->green=(u16)green; + *gamma->blue=(u16)blue; + XRRSetCrtcGamma(XDisplay, Screennr, gamma); + XRRFreeGamma(gamma); + return true; + } + #endif + } + } + #endif + #endif + return false; +} + + +//! Get the current Gamma Value for the Display +bool CIrrDeviceLinux::getGammaRamp( f32 &red, f32 &green, f32 &blue, f32 &brightness, f32 &contrast ) +{ + brightness = 0.f; + contrast = 0.f; + #if defined(_IRR_LINUX_X11_VIDMODE_) || defined(_IRR_LINUX_X11_RANDR_) + s32 eventbase, errorbase; + #ifdef _IRR_LINUX_X11_VIDMODE_ + if (XF86VidModeQueryExtension(XDisplay, &eventbase, &errorbase)) + { + XF86VidModeGamma gamma; + XF86VidModeGetGamma(XDisplay, Screennr, &gamma); + red = gamma.red; + green = gamma.green; + blue = gamma.blue; + return true; + } + #endif + #if defined(_IRR_LINUX_X11_VIDMODE_) && defined(_IRR_LINUX_X11_RANDR_) + else + #endif + #ifdef _IRR_LINUX_X11_RANDR_ + if (XRRQueryExtension(XDisplay, &eventbase, &errorbase)) + { + XRRQueryVersion(XDisplay, &eventbase, &errorbase); // major, minor + if (eventbase>=1 && errorbase>1) + { + #if (RANDR_MAJOR>1 || RANDR_MINOR>1) + XRRCrtcGamma *gamma = XRRGetCrtcGamma(XDisplay, Screennr); + if (gamma) + { + red = *gamma->red; + green = *gamma->green; + blue= *gamma->blue; + XRRFreeGamma(gamma); + return true; + } + #endif + } + } + #endif + #endif + return false; +} + + +//! gets text from the clipboard +//! \return Returns 0 if no string is in there. +const c8* CIrrDeviceLinux::getTextFromClipboard() const +{ +#if defined(_IRR_COMPILE_WITH_X11_) + Window ownerWindow = XGetSelectionOwner (XDisplay, X_ATOM_CLIPBOARD); + if ( ownerWindow == XWindow ) + { + return Clipboard.c_str(); + } + Clipboard = ""; + if (ownerWindow != None ) + { + XConvertSelection (XDisplay, X_ATOM_CLIPBOARD, XA_STRING, XA_PRIMARY, ownerWindow, CurrentTime); + XFlush (XDisplay); + + // check for data + Atom type; + int format; + unsigned long numItems, bytesLeft, dummy; + unsigned char *data; + XGetWindowProperty (XDisplay, ownerWindow, + XA_PRIMARY, // property name + 0, // offset + 0, // length (we only check for data, so 0) + 0, // Delete 0==false + AnyPropertyType, // AnyPropertyType or property identifier + &type, // return type + &format, // return format + &numItems, // number items + &bytesLeft, // remaining bytes for partial reads + &data); // data + if ( bytesLeft > 0 ) + { + // there is some data to get + int result = XGetWindowProperty (XDisplay, ownerWindow, XA_PRIMARY, 0, + bytesLeft, 0, AnyPropertyType, &type, &format, + &numItems, &dummy, &data); + if (result == Success) + Clipboard = (irr::c8*)data; + XFree (data); + } + } + + return Clipboard.c_str(); + +#else + return 0; +#endif +} + +//! copies text to the clipboard +void CIrrDeviceLinux::copyToClipboard(const c8* text) const +{ +#if defined(_IRR_COMPILE_WITH_X11_) + // Actually there is no clipboard on X but applications just say they own the clipboard and return text when asked. + // Which btw. also means that on X you lose clipboard content when closing applications. + Clipboard = text; + XSetSelectionOwner (XDisplay, X_ATOM_CLIPBOARD, XWindow, CurrentTime); + XFlush (XDisplay); +#endif +} + +#ifdef _IRR_COMPILE_WITH_X11_ +// return true if the passed event has the type passed in parameter arg +Bool PredicateIsEventType(Display *display, XEvent *event, XPointer arg) +{ + if ( event && event->type == *(int*)arg ) + { +// os::Printer::log("remove event:", core::stringc((int)arg).c_str(), ELL_INFORMATION); + return True; + } + return False; +} +#endif //_IRR_COMPILE_WITH_X11_ + +//! Remove all messages pending in the system message loop +void CIrrDeviceLinux::clearSystemMessages() +{ +#ifdef _IRR_COMPILE_WITH_X11_ + if (CreationParams.DriverType != video::EDT_NULL) + { + XEvent event; + int usrArg = ButtonPress; + while ( XCheckIfEvent(XDisplay, &event, PredicateIsEventType, XPointer(&usrArg)) == True ) {} + usrArg = ButtonRelease; + while ( XCheckIfEvent(XDisplay, &event, PredicateIsEventType, XPointer(&usrArg)) == True ) {} + usrArg = MotionNotify; + while ( XCheckIfEvent(XDisplay, &event, PredicateIsEventType, XPointer(&usrArg)) == True ) {} + usrArg = KeyRelease; + while ( XCheckIfEvent(XDisplay, &event, PredicateIsEventType, XPointer(&usrArg)) == True ) {} + usrArg = KeyPress; + while ( XCheckIfEvent(XDisplay, &event, PredicateIsEventType, XPointer(&usrArg)) == True ) {} + } +#endif //_IRR_COMPILE_WITH_X11_ +} + +void CIrrDeviceLinux::initXAtoms() +{ +#ifdef _IRR_COMPILE_WITH_X11_ + X_ATOM_CLIPBOARD = XInternAtom(XDisplay, "CLIPBOARD", False); + X_ATOM_TARGETS = XInternAtom(XDisplay, "TARGETS", False); + X_ATOM_UTF8_STRING = XInternAtom (XDisplay, "UTF8_STRING", False); + X_ATOM_TEXT = XInternAtom (XDisplay, "TEXT", False); + X_ATOM_NETWM_MAXIMIZE_VERT = XInternAtom(XDisplay, "_NET_WM_STATE_MAXIMIZED_VERT", true); + X_ATOM_NETWM_MAXIMIZE_HORZ = XInternAtom(XDisplay, "_NET_WM_STATE_MAXIMIZED_HORZ", true); + X_ATOM_NETWM_STATE = XInternAtom(XDisplay, "_NET_WM_STATE", true); +#endif +} + + +#ifdef _IRR_COMPILE_WITH_X11_ + +Cursor CIrrDeviceLinux::TextureToMonochromeCursor(irr::video::ITexture * tex, const core::rect& sourceRect, const core::position2d &hotspot) +{ + XImage * sourceImage = XCreateImage(XDisplay, VisualInfo->visual, + 1, // depth, + ZPixmap, // XYBitmap (depth=1), ZPixmap(depth=x) + 0, 0, sourceRect.getWidth(), sourceRect.getHeight(), + 32, // bitmap_pad, + 0// bytes_per_line (0 means continuos in memory) + ); + sourceImage->data = new char[sourceImage->height * sourceImage->bytes_per_line]; + XImage * maskImage = XCreateImage(XDisplay, VisualInfo->visual, + 1, // depth, + ZPixmap, + 0, 0, sourceRect.getWidth(), sourceRect.getHeight(), + 32, // bitmap_pad, + 0 // bytes_per_line + ); + maskImage->data = new char[maskImage->height * maskImage->bytes_per_line]; + + // write texture into XImage + video::ECOLOR_FORMAT format = tex->getColorFormat(); + u32 bytesPerPixel = video::IImage::getBitsPerPixelFromFormat(format) / 8; + u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel; + u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel; + const u8* data = (const u8*)tex->lock(video::ETLM_READ_ONLY, 0); + data += sourceRect.UpperLeftCorner.Y*tex->getPitch(); + for ( s32 y = 0; y < sourceRect.getHeight(); ++y ) + { + data += bytesLeftGap; + for ( s32 x = 0; x < sourceRect.getWidth(); ++x ) + { + video::SColor pixelCol; + pixelCol.setData((const void*)data, format); + data += bytesPerPixel; + + if ( pixelCol.getAlpha() == 0 ) // transparent + { + XPutPixel(maskImage, x, y, 0); + XPutPixel(sourceImage, x, y, 0); + } + else // color + { + if ( pixelCol.getAverage() >= 127 ) + XPutPixel(sourceImage, x, y, 1); + else + XPutPixel(sourceImage, x, y, 0); + XPutPixel(maskImage, x, y, 1); + } + } + data += bytesRightGap; + } + tex->unlock(); + + Pixmap sourcePixmap = XCreatePixmap(XDisplay, XWindow, sourceImage->width, sourceImage->height, sourceImage->depth); + Pixmap maskPixmap = XCreatePixmap(XDisplay, XWindow, maskImage->width, maskImage->height, maskImage->depth); + + XGCValues values; + values.foreground = 1; + values.background = 1; + GC gc = XCreateGC( XDisplay, sourcePixmap, GCForeground | GCBackground, &values ); + + XPutImage(XDisplay, sourcePixmap, gc, sourceImage, 0, 0, 0, 0, sourceImage->width, sourceImage->height); + XPutImage(XDisplay, maskPixmap, gc, maskImage, 0, 0, 0, 0, maskImage->width, maskImage->height); + + XFreeGC(XDisplay, gc); + XDestroyImage(sourceImage); + XDestroyImage(maskImage); + + Cursor cursorResult = 0; + XColor foreground, background; + foreground.red = 65535; + foreground.green = 65535; + foreground.blue = 65535; + foreground.flags = DoRed | DoGreen | DoBlue; + background.red = 0; + background.green = 0; + background.blue = 0; + background.flags = DoRed | DoGreen | DoBlue; + + cursorResult = XCreatePixmapCursor(XDisplay, sourcePixmap, maskPixmap, &foreground, &background, hotspot.X, hotspot.Y); + + XFreePixmap(XDisplay, sourcePixmap); + XFreePixmap(XDisplay, maskPixmap); + + return cursorResult; +} + +#ifdef _IRR_LINUX_XCURSOR_ +Cursor CIrrDeviceLinux::TextureToARGBCursor(irr::video::ITexture * tex, const core::rect& sourceRect, const core::position2d &hotspot) +{ + XcursorImage * image = XcursorImageCreate (sourceRect.getWidth(), sourceRect.getHeight()); + image->xhot = hotspot.X; + image->yhot = hotspot.Y; + + // write texture into XcursorImage + video::ECOLOR_FORMAT format = tex->getColorFormat(); + u32 bytesPerPixel = video::IImage::getBitsPerPixelFromFormat(format) / 8; + u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel; + u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel; + XcursorPixel* target = image->pixels; + const u8* data = (const u8*)tex->lock(video::ETLM_READ_ONLY, 0); + data += sourceRect.UpperLeftCorner.Y*tex->getPitch(); + for ( s32 y = 0; y < sourceRect.getHeight(); ++y ) + { + data += bytesLeftGap; + for ( s32 x = 0; x < sourceRect.getWidth(); ++x ) + { + video::SColor pixelCol; + pixelCol.setData((const void*)data, format); + data += bytesPerPixel; + + *target = (XcursorPixel)pixelCol.color; + ++target; + } + data += bytesRightGap; + } + tex->unlock(); + + Cursor cursorResult=XcursorImageLoadCursor(XDisplay, image); + + XcursorImageDestroy(image); + + + return cursorResult; +} +#endif // #ifdef _IRR_LINUX_XCURSOR_ + +Cursor CIrrDeviceLinux::TextureToCursor(irr::video::ITexture * tex, const core::rect& sourceRect, const core::position2d &hotspot) +{ +#ifdef _IRR_LINUX_XCURSOR_ + return TextureToARGBCursor( tex, sourceRect, hotspot ); +#else + return TextureToMonochromeCursor( tex, sourceRect, hotspot ); +#endif +} +#endif // _IRR_COMPILE_WITH_X11_ + + +CIrrDeviceLinux::CCursorControl::CCursorControl(CIrrDeviceLinux* dev, bool null) + : Device(dev) +#ifdef _IRR_COMPILE_WITH_X11_ + , PlatformBehavior(gui::ECPB_NONE), LastQuery(0) +#endif + , IsVisible(true), Null(null), UseReferenceRect(false) + , ActiveIcon(gui::ECI_NORMAL), ActiveIconStartTime(0) +{ +#ifdef _IRR_COMPILE_WITH_X11_ + if (!Null) + { + XGCValues values; + unsigned long valuemask = 0; + + XColor fg, bg; + + // this code, for making the cursor invisible was sent in by + // Sirshane, thank your very much! + + + Pixmap invisBitmap = XCreatePixmap(Device->XDisplay, Device->XWindow, 32, 32, 1); + Pixmap maskBitmap = XCreatePixmap(Device->XDisplay, Device->XWindow, 32, 32, 1); + Colormap screen_colormap = DefaultColormap( Device->XDisplay, DefaultScreen( Device->XDisplay ) ); + XAllocNamedColor( Device->XDisplay, screen_colormap, "black", &fg, &fg ); + XAllocNamedColor( Device->XDisplay, screen_colormap, "white", &bg, &bg ); + + GC gc = XCreateGC( Device->XDisplay, invisBitmap, valuemask, &values ); + + XSetForeground( Device->XDisplay, gc, BlackPixel( Device->XDisplay, DefaultScreen( Device->XDisplay ) ) ); + XFillRectangle( Device->XDisplay, invisBitmap, gc, 0, 0, 32, 32 ); + XFillRectangle( Device->XDisplay, maskBitmap, gc, 0, 0, 32, 32 ); + + InvisCursor = XCreatePixmapCursor( Device->XDisplay, invisBitmap, maskBitmap, &fg, &bg, 1, 1 ); + XFreeGC(Device->XDisplay, gc); + XFreePixmap(Device->XDisplay, invisBitmap); + XFreePixmap(Device->XDisplay, maskBitmap); + + initCursors(); + } +#endif +} + +CIrrDeviceLinux::CCursorControl::~CCursorControl() +{ + // Do not clearCursors here as the display is already closed + // TODO (cutealien): droping cursorcontrol earlier might work, not sure about reason why that's done in stub currently. +} + +#ifdef _IRR_COMPILE_WITH_X11_ +void CIrrDeviceLinux::CCursorControl::clearCursors() +{ + if (!Null) + XFreeCursor(Device->XDisplay, InvisCursor); + for ( u32 i=0; i < Cursors.size(); ++i ) + { + for ( u32 f=0; f < Cursors[i].Frames.size(); ++f ) + { + XFreeCursor(Device->XDisplay, Cursors[i].Frames[f].IconHW); + } + } +} + +void CIrrDeviceLinux::CCursorControl::initCursors() +{ + Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_top_left_arrow)) ); // (or XC_arrow?) + Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_crosshair)) ); + Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_hand2)) ); // (or XC_hand1? ) + Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_question_arrow)) ); + Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_xterm)) ); + Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_X_cursor)) ); // (or XC_pirate?) + Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_watch)) ); // (or XC_clock?) + Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_fleur)) ); + Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_top_right_corner)) ); // NESW not available in X11 + Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_top_left_corner)) ); // NWSE not available in X11 + Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_sb_v_double_arrow)) ); + Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_sb_h_double_arrow)) ); + Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_sb_up_arrow)) ); // (or XC_center_ptr?) +} + +void CIrrDeviceLinux::CCursorControl::update() +{ + if ( (u32)ActiveIcon < Cursors.size() && !Cursors[ActiveIcon].Frames.empty() && Cursors[ActiveIcon].FrameTime ) + { + // update animated cursors. This could also be done by X11 in case someone wants to figure that out (this way was just easier to implement) + u32 now = Device->getTimer()->getRealTime(); + u32 frame = ((now - ActiveIconStartTime) / Cursors[ActiveIcon].FrameTime) % Cursors[ActiveIcon].Frames.size(); + XDefineCursor(Device->XDisplay, Device->XWindow, Cursors[ActiveIcon].Frames[frame].IconHW); + } +} +#endif + +//! Sets the active cursor icon +void CIrrDeviceLinux::CCursorControl::setActiveIcon(gui::ECURSOR_ICON iconId) +{ +#ifdef _IRR_COMPILE_WITH_X11_ + if ( iconId >= (s32)Cursors.size() ) + return; + + if ( Cursors[iconId].Frames.size() ) + XDefineCursor(Device->XDisplay, Device->XWindow, Cursors[iconId].Frames[0].IconHW); + + ActiveIconStartTime = Device->getTimer()->getRealTime(); + ActiveIcon = iconId; +#endif +} + + +//! Add a custom sprite as cursor icon. +gui::ECURSOR_ICON CIrrDeviceLinux::CCursorControl::addIcon(const gui::SCursorSprite& icon) +{ +#ifdef _IRR_COMPILE_WITH_X11_ + if ( icon.SpriteId >= 0 ) + { + CursorX11 cX11; + cX11.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime; + for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i ) + { + irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber; + irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber; + irr::core::rect rectIcon = icon.SpriteBank->getPositions()[rectId]; + Cursor cursor = Device->TextureToCursor(icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot); + cX11.Frames.push_back( CursorFrameX11(cursor) ); + } + + Cursors.push_back( cX11 ); + + return (gui::ECURSOR_ICON)(Cursors.size() - 1); + } +#endif + return gui::ECI_NORMAL; +} + +//! replace the given cursor icon. +void CIrrDeviceLinux::CCursorControl::changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite& icon) +{ +#ifdef _IRR_COMPILE_WITH_X11_ + if ( iconId >= (s32)Cursors.size() ) + return; + + for ( u32 i=0; i < Cursors[iconId].Frames.size(); ++i ) + XFreeCursor(Device->XDisplay, Cursors[iconId].Frames[i].IconHW); + + if ( icon.SpriteId >= 0 ) + { + CursorX11 cX11; + cX11.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime; + for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i ) + { + irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber; + irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber; + irr::core::rect rectIcon = icon.SpriteBank->getPositions()[rectId]; + Cursor cursor = Device->TextureToCursor(icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot); + cX11.Frames.push_back( CursorFrameX11(cursor) ); + } + + Cursors[iconId] = cX11; + } +#endif +} + +irr::core::dimension2di CIrrDeviceLinux::CCursorControl::getSupportedIconSize() const +{ + // this returns the closest match that is smaller or same size, so we just pass a value which should be large enough for cursors + unsigned int width=0, height=0; +#ifdef _IRR_COMPILE_WITH_X11_ + XQueryBestCursor(Device->XDisplay, Device->XWindow, 64, 64, &width, &height); +#endif + return core::dimension2di(width, height); +} + +} // end namespace + +#endif // _IRR_COMPILE_WITH_X11_DEVICE_ + diff --git a/source/Irrlicht/CIrrDeviceLinux.h b/source/Irrlicht/CIrrDeviceLinux.h new file mode 100644 index 00000000..344149e1 --- /dev/null +++ b/source/Irrlicht/CIrrDeviceLinux.h @@ -0,0 +1,446 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_IRR_DEVICE_LINUX_H_INCLUDED__ +#define __C_IRR_DEVICE_LINUX_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_X11_DEVICE_ + +#include "CIrrDeviceStub.h" +#include "IrrlichtDevice.h" +#include "IImagePresenter.h" +#include "ICursorControl.h" +#include "os.h" + +#ifdef _IRR_COMPILE_WITH_X11_ + +#include +#include +#include +#ifdef _IRR_LINUX_X11_VIDMODE_ +#include +#endif +#ifdef _IRR_LINUX_X11_RANDR_ +#include +#endif +#include + +#else +#define KeySym s32 +#endif + +namespace irr +{ + + class CIrrDeviceLinux : public CIrrDeviceStub, public video::IImagePresenter + { + public: + + //! constructor + CIrrDeviceLinux(const SIrrlichtCreationParameters& param); + + //! destructor + virtual ~CIrrDeviceLinux(); + + //! runs the device. Returns false if device wants to be deleted + virtual bool run() _IRR_OVERRIDE_; + + //! Cause the device to temporarily pause execution and let other processes to run + // This should bring down processor usage without major performance loss for Irrlicht + virtual void yield() _IRR_OVERRIDE_; + + //! Pause execution and let other processes to run for a specified amount of time. + virtual void sleep(u32 timeMs, bool pauseTimer) _IRR_OVERRIDE_; + + //! sets the caption of the window + virtual void setWindowCaption(const wchar_t* text) _IRR_OVERRIDE_; + + //! returns if window is active. if not, nothing need to be drawn + virtual bool isWindowActive() const _IRR_OVERRIDE_; + + //! returns if window has focus. + virtual bool isWindowFocused() const _IRR_OVERRIDE_; + + //! returns if window is minimized. + virtual bool isWindowMinimized() const _IRR_OVERRIDE_; + + //! returns color format of the window. + virtual video::ECOLOR_FORMAT getColorFormat() const _IRR_OVERRIDE_; + + //! presents a surface in the client area + virtual bool present(video::IImage* surface, void* windowId=0, core::rect* src=0 ) _IRR_OVERRIDE_; + + //! notifies the device that it should close itself + virtual void closeDevice() _IRR_OVERRIDE_; + + //! \return Returns a pointer to a list with all video modes + //! supported by the gfx adapter. + virtual video::IVideoModeList* getVideoModeList() _IRR_OVERRIDE_; + + //! Sets if the window should be resizable in windowed mode. + virtual void setResizable(bool resize=false) _IRR_OVERRIDE_; + + //! Resize the render window. + virtual void setWindowSize(const irr::core::dimension2d& size) _IRR_OVERRIDE_; + + //! Minimizes the window. + virtual void minimizeWindow() _IRR_OVERRIDE_; + + //! Maximizes the window. + virtual void maximizeWindow() _IRR_OVERRIDE_; + + //! Restores the window size. + virtual void restoreWindow() _IRR_OVERRIDE_; + + //! Get the position of this window on screen + virtual core::position2di getWindowPosition() _IRR_OVERRIDE_; + + //! Activate any joysticks, and generate events for them. + virtual bool activateJoysticks(core::array & joystickInfo) _IRR_OVERRIDE_; + + //! Set the current Gamma Value for the Display + virtual bool setGammaRamp( f32 red, f32 green, f32 blue, f32 brightness, f32 contrast ) _IRR_OVERRIDE_; + + //! Get the current Gamma Value for the Display + virtual bool getGammaRamp( f32 &red, f32 &green, f32 &blue, f32 &brightness, f32 &contrast ) _IRR_OVERRIDE_; + + //! gets text from the clipboard + //! \return Returns 0 if no string is in there. + virtual const c8* getTextFromClipboard() const; + + //! copies text to the clipboard + //! This sets the clipboard selection and _not_ the primary selection which you have on X on the middle mouse button. + virtual void copyToClipboard(const c8* text) const; + + //! Remove all messages pending in the system message loop + virtual void clearSystemMessages() _IRR_OVERRIDE_; + + //! Get the device type + virtual E_DEVICE_TYPE getType() const _IRR_OVERRIDE_ + { + return EIDT_X11; + } + +#ifdef _IRR_COMPILE_WITH_X11_ + // convert an Irrlicht texture to a X11 cursor + Cursor TextureToCursor(irr::video::ITexture * tex, const core::rect& sourceRect, const core::position2d &hotspot); + Cursor TextureToMonochromeCursor(irr::video::ITexture * tex, const core::rect& sourceRect, const core::position2d &hotspot); +#ifdef _IRR_LINUX_XCURSOR_ + Cursor TextureToARGBCursor(irr::video::ITexture * tex, const core::rect& sourceRect, const core::position2d &hotspot); +#endif +#endif + + private: + + //! create the driver + void createDriver(); + + bool createWindow(); + + void createKeyMap(); + + void pollJoysticks(); + + void initXAtoms(); + + bool switchToFullscreen(bool reset=false); + +#ifdef _IRR_COMPILE_WITH_X11_ + bool createInputContext(); + void destroyInputContext(); + EKEY_CODE getKeyCode(XEvent &event); +#endif + + //! Implementation of the linux cursor control + class CCursorControl : public gui::ICursorControl + { + public: + + CCursorControl(CIrrDeviceLinux* dev, bool null); + + ~CCursorControl(); + + //! Changes the visible state of the mouse cursor. + virtual void setVisible(bool visible) _IRR_OVERRIDE_ + { + if (visible==IsVisible) + return; + IsVisible = visible; +#ifdef _IRR_COMPILE_WITH_X11_ + if (!Null) + { + if ( !IsVisible ) + XDefineCursor( Device->XDisplay, Device->XWindow, InvisCursor ); + else + XUndefineCursor( Device->XDisplay, Device->XWindow ); + } +#endif + } + + //! Returns if the cursor is currently visible. + virtual bool isVisible() const _IRR_OVERRIDE_ + { + return IsVisible; + } + + //! Sets the new position of the cursor. + virtual void setPosition(const core::position2d &pos) _IRR_OVERRIDE_ + { + setPosition(pos.X, pos.Y); + } + + //! Sets the new position of the cursor. + virtual void setPosition(f32 x, f32 y) _IRR_OVERRIDE_ + { + setPosition((s32)(x*Device->Width), (s32)(y*Device->Height)); + } + + //! Sets the new position of the cursor. + virtual void setPosition(const core::position2d &pos) _IRR_OVERRIDE_ + { + setPosition(pos.X, pos.Y); + } + + //! Sets the new position of the cursor. + virtual void setPosition(s32 x, s32 y) _IRR_OVERRIDE_ + { +#ifdef _IRR_COMPILE_WITH_X11_ + + if (!Null) + { + if (UseReferenceRect) + { + XWarpPointer(Device->XDisplay, + None, + Device->XWindow, 0, 0, + Device->Width, + Device->Height, + ReferenceRect.UpperLeftCorner.X + x, + ReferenceRect.UpperLeftCorner.Y + y); + + } + else + { + XWarpPointer(Device->XDisplay, + None, + Device->XWindow, 0, 0, + Device->Width, + Device->Height, x, y); + } + XFlush(Device->XDisplay); + } +#endif + CursorPos.X = x; + CursorPos.Y = y; + } + + //! Returns the current position of the mouse cursor. + virtual const core::position2d& getPosition(bool updateCursor) _IRR_OVERRIDE_ + { + if ( updateCursor ) + updateCursorPos(); + return CursorPos; + } + + //! Returns the current position of the mouse cursor. + virtual core::position2d getRelativePosition(bool updateCursor) _IRR_OVERRIDE_ + { + if ( updateCursor ) + updateCursorPos(); + + if (!UseReferenceRect) + { + return core::position2d(CursorPos.X / (f32)Device->Width, + CursorPos.Y / (f32)Device->Height); + } + + return core::position2d(CursorPos.X / (f32)ReferenceRect.getWidth(), + CursorPos.Y / (f32)ReferenceRect.getHeight()); + } + + virtual void setReferenceRect(core::rect* rect=0) _IRR_OVERRIDE_ + { + if (rect) + { + ReferenceRect = *rect; + UseReferenceRect = true; + + // prevent division through zero and uneven sizes + + if (!ReferenceRect.getHeight() || ReferenceRect.getHeight()%2) + ReferenceRect.LowerRightCorner.Y += 1; + + if (!ReferenceRect.getWidth() || ReferenceRect.getWidth()%2) + ReferenceRect.LowerRightCorner.X += 1; + } + else + UseReferenceRect = false; + } + + //! Sets the active cursor icon + virtual void setActiveIcon(gui::ECURSOR_ICON iconId) _IRR_OVERRIDE_; + + //! Gets the currently active icon + virtual gui::ECURSOR_ICON getActiveIcon() const _IRR_OVERRIDE_ + { + return ActiveIcon; + } + + //! Add a custom sprite as cursor icon. + virtual gui::ECURSOR_ICON addIcon(const gui::SCursorSprite& icon) _IRR_OVERRIDE_; + + //! replace the given cursor icon. + virtual void changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite& icon) _IRR_OVERRIDE_; + + //! Return a system-specific size which is supported for cursors. Larger icons will fail, smaller icons might work. + virtual core::dimension2di getSupportedIconSize() const _IRR_OVERRIDE_; + +#ifdef _IRR_COMPILE_WITH_X11_ + //! Set platform specific behavior flags. + virtual void setPlatformBehavior(gui::ECURSOR_PLATFORM_BEHAVIOR behavior) _IRR_OVERRIDE_ {PlatformBehavior = behavior; } + + //! Return platform specific behavior. + virtual gui::ECURSOR_PLATFORM_BEHAVIOR getPlatformBehavior() const _IRR_OVERRIDE_ { return PlatformBehavior; } + + void update(); + void clearCursors(); +#endif + private: + + void updateCursorPos() + { +#ifdef _IRR_COMPILE_WITH_X11_ + if (Null) + return; + + if ( PlatformBehavior&gui::ECPB_X11_CACHE_UPDATES && !os::Timer::isStopped() ) + { + u32 now = os::Timer::getTime(); + if (now <= LastQuery) + return; + LastQuery = now; + } + + Window tmp; + int itmp1, itmp2; + unsigned int maskreturn; + XQueryPointer(Device->XDisplay, Device->XWindow, + &tmp, &tmp, + &itmp1, &itmp2, + &CursorPos.X, &CursorPos.Y, &maskreturn); +#endif + } + + CIrrDeviceLinux* Device; + core::position2d CursorPos; + core::rect ReferenceRect; +#ifdef _IRR_COMPILE_WITH_X11_ + gui::ECURSOR_PLATFORM_BEHAVIOR PlatformBehavior; + u32 LastQuery; + Cursor InvisCursor; + + struct CursorFrameX11 + { + CursorFrameX11() : IconHW(0) {} + CursorFrameX11(Cursor icon) : IconHW(icon) {} + + Cursor IconHW; // hardware cursor + }; + + struct CursorX11 + { + CursorX11() {} + explicit CursorX11(Cursor iconHw, u32 frameTime=0) : FrameTime(frameTime) + { + Frames.push_back( CursorFrameX11(iconHw) ); + } + core::array Frames; + u32 FrameTime; + }; + + core::array Cursors; + + void initCursors(); +#endif + bool IsVisible; + bool Null; + bool UseReferenceRect; + gui::ECURSOR_ICON ActiveIcon; + u32 ActiveIconStartTime; + }; + + friend class CCursorControl; + +#ifdef _IRR_COMPILE_WITH_X11_ + friend class COpenGLDriver; + + Display *XDisplay; + XVisualInfo* VisualInfo; + int Screennr; + Window XWindow; + XSetWindowAttributes WndAttributes; + XSizeHints* StdHints; + XImage* SoftwareImage; + XIM XInputMethod; + XIC XInputContext; + bool HasNetWM; + mutable core::stringc Clipboard; + #ifdef _IRR_LINUX_X11_VIDMODE_ + XF86VidModeModeInfo OldVideoMode; + #endif + #ifdef _IRR_LINUX_X11_RANDR_ + SizeID OldRandrMode; + Rotation OldRandrRotation; + #endif +#endif + u32 Width, Height; + bool WindowHasFocus; + bool WindowMinimized; + bool UseXVidMode; + bool UseXRandR; + bool ExternalWindow; + int AutorepeatSupport; + + struct SKeyMap + { + SKeyMap() {} + SKeyMap(s32 x11, s32 win32) + : X11Key(x11), Win32Key(win32) + { + } + + KeySym X11Key; + s32 Win32Key; + + bool operator<(const SKeyMap& o) const + { + return X11Key KeyMap; + +#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) + struct JoystickInfo + { + int fd; + int axes; + int buttons; + + SEvent persistentData; + + JoystickInfo() : fd(-1), axes(0), buttons(0) { } + }; + core::array ActiveJoysticks; +#endif + }; + + +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_X11_DEVICE_ +#endif // __C_IRR_DEVICE_LINUX_H_INCLUDED__ + diff --git a/source/Irrlicht/CIrrDeviceOSX.h b/source/Irrlicht/CIrrDeviceOSX.h new file mode 100644 index 00000000..701c5aaa --- /dev/null +++ b/source/Irrlicht/CIrrDeviceOSX.h @@ -0,0 +1,264 @@ +// Copyright (C) 2005-2006 Etienne Petitjean +// Copyright (C) 2007-2012 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __C_IRR_DEVICE_OSX_H_INCLUDED__ +#define __C_IRR_DEVICE_OSX_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OSX_DEVICE_ + +#include "CIrrDeviceStub.h" +#include "IrrlichtDevice.h" +#include "IImagePresenter.h" +#include "IGUIEnvironment.h" +#include "ICursorControl.h" + +#import +#import + +#include + +namespace irr +{ + class CIrrDeviceMacOSX; +} + +@interface CIrrDelegateOSX : NSObject + +- (id)initWithDevice:(irr::CIrrDeviceMacOSX*)device; +- (void)terminate:(id)sender; +- (BOOL)isQuit; + +@end + +namespace irr +{ + class CIrrDeviceMacOSX : public CIrrDeviceStub, video::IImagePresenter + { + public: + + //! constructor + CIrrDeviceMacOSX(const SIrrlichtCreationParameters& params); + + //! destructor + virtual ~CIrrDeviceMacOSX(); + + //! runs the device. Returns false if device wants to be deleted + virtual bool run() _IRR_OVERRIDE_; + + //! Cause the device to temporarily pause execution and let other processes to run + // This should bring down processor usage without major performance loss for Irrlicht + virtual void yield() _IRR_OVERRIDE_; + + //! Pause execution and let other processes to run for a specified amount of time. + virtual void sleep(u32 timeMs, bool pauseTimer) _IRR_OVERRIDE_; + + //! sets the caption of the window + virtual void setWindowCaption(const wchar_t* text) _IRR_OVERRIDE_; + + //! returns if window is active. if not, nothing need to be drawn + virtual bool isWindowActive() const _IRR_OVERRIDE_; + + //! Checks if the Irrlicht window has focus + virtual bool isWindowFocused() const _IRR_OVERRIDE_; + + //! Checks if the Irrlicht window is minimized + virtual bool isWindowMinimized() const _IRR_OVERRIDE_; + + //! presents a surface in the client area + virtual bool present(video::IImage* surface, void* windowId=0, core::rect* src=0 ) _IRR_OVERRIDE_; + + //! notifies the device that it should close itself + virtual void closeDevice() _IRR_OVERRIDE_; + + //! Sets if the window should be resizable in windowed mode. + virtual void setResizable(bool resize) _IRR_OVERRIDE_; + + //! Returns true if the window is resizable, false if not + virtual bool isResizable() const; + + //! Minimizes the window if possible + virtual void minimizeWindow() _IRR_OVERRIDE_; + + //! Maximizes the window if possible. + virtual void maximizeWindow() _IRR_OVERRIDE_; + + //! Restore the window to normal size if possible. + virtual void restoreWindow() _IRR_OVERRIDE_; + + //! Get the position of this window on screen + virtual core::position2di getWindowPosition() _IRR_OVERRIDE_; + + //! Activate any joysticks, and generate events for them. + virtual bool activateJoysticks(core::array & joystickInfo) _IRR_OVERRIDE_; + + //! \return Returns a pointer to a list with all video modes + //! supported by the gfx adapter. + virtual video::IVideoModeList* getVideoModeList() _IRR_OVERRIDE_; + + //! Get the device type + virtual E_DEVICE_TYPE getType() const _IRR_OVERRIDE_ + { + return EIDT_OSX; + } + + void setMouseLocation(int x, int y); + void setResize(int width, int height); + void setCursorVisible(bool visible); + void setWindow(NSWindow* window); + + private: + + //! create the driver + void createDriver(); + + //! Implementation of the macos x cursor control + class CCursorControl : public gui::ICursorControl + { + public: + + CCursorControl(const core::dimension2d& wsize, CIrrDeviceMacOSX *device) + : WindowSize(wsize), InvWindowSize(0.0f, 0.0f), Device(device), IsVisible(true), UseReferenceRect(false) + { + CursorPos.X = CursorPos.Y = 0; + if (WindowSize.Width!=0) + InvWindowSize.Width = 1.0f / WindowSize.Width; + if (WindowSize.Height!=0) + InvWindowSize.Height = 1.0f / WindowSize.Height; + } + + //! Changes the visible state of the mouse cursor. + virtual void setVisible(bool visible) + { + IsVisible = visible; + Device->setCursorVisible(visible); + } + + //! Returns if the cursor is currently visible. + virtual bool isVisible() const + { + return IsVisible; + } + + //! Sets the new position of the cursor. + virtual void setPosition(const core::position2d &pos) + { + setPosition(pos.X, pos.Y); + } + + //! Sets the new position of the cursor. + virtual void setPosition(f32 x, f32 y) + { + setPosition((s32)(x*WindowSize.Width), (s32)(y*WindowSize.Height)); + } + + //! Sets the new position of the cursor. + virtual void setPosition(const core::position2d &pos) + { + if (CursorPos.X != pos.X || CursorPos.Y != pos.Y) + setPosition(pos.X, pos.Y); + } + + //! Sets the new position of the cursor. + virtual void setPosition(s32 x, s32 y) + { + if (UseReferenceRect) + { + Device->setMouseLocation(ReferenceRect.UpperLeftCorner.X + x, ReferenceRect.UpperLeftCorner.Y + y); + } + else + { + Device->setMouseLocation(x,y); + } + } + + //! Returns the current position of the mouse cursor. + virtual const core::position2d& getPosition() + { + return CursorPos; + } + + //! Returns the current position of the mouse cursor. + virtual core::position2d getRelativePosition() + { + if (!UseReferenceRect) + { + return core::position2d(CursorPos.X * InvWindowSize.Width, + CursorPos.Y * InvWindowSize.Height); + } + + return core::position2d(CursorPos.X / (f32)ReferenceRect.getWidth(), + CursorPos.Y / (f32)ReferenceRect.getHeight()); + } + + //! Sets an absolute reference rect for calculating the cursor position. + virtual void setReferenceRect(core::rect* rect=0) + { + if (rect) + { + ReferenceRect = *rect; + UseReferenceRect = true; + + // prevent division through zero and uneven sizes + + if (!ReferenceRect.getHeight() || ReferenceRect.getHeight()%2) + ReferenceRect.LowerRightCorner.Y += 1; + + if (!ReferenceRect.getWidth() || ReferenceRect.getWidth()%2) + ReferenceRect.LowerRightCorner.X += 1; + } + else + UseReferenceRect = false; + } + + //! Updates the internal cursor position + void updateInternalCursorPosition(int x,int y) + { + CursorPos.X = x; + CursorPos.Y = y; + } + + private: + + core::position2d CursorPos; + core::dimension2d WindowSize; + core::dimension2d InvWindowSize; + core::rect ReferenceRect; + CIrrDeviceMacOSX *Device; + bool IsVisible; + bool UseReferenceRect; + }; + + bool createWindow(); + void initKeycodes(); + void storeMouseLocation(); + void postMouseEvent(void *event, irr::SEvent &ievent); + void postKeyEvent(void *event, irr::SEvent &ievent, bool pressed); + void pollJoysticks(); + + NSWindow* Window; + CGDirectDisplayID Display; + NSBitmapImageRep* SoftwareDriverTarget; + std::map KeyCodes; + int DeviceWidth; + int DeviceHeight; + int ScreenWidth; + int ScreenHeight; + u32 MouseButtonStates; + u32 SoftwareRendererType; + bool IsFullscreen; + bool IsActive; + bool IsShiftDown; + bool IsControlDown; + bool IsResizable; + }; + + +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_OSX_DEVICE_ +#endif // __C_IRR_DEVICE_MACOSX_H_INCLUDED__ + diff --git a/source/Irrlicht/CIrrDeviceOSX.mm b/source/Irrlicht/CIrrDeviceOSX.mm new file mode 100644 index 00000000..801a330c --- /dev/null +++ b/source/Irrlicht/CIrrDeviceOSX.mm @@ -0,0 +1,1840 @@ +// Copyright (C) 2005-2006 Etienne Petitjean +// Copyright (C) 2007-2012 Christian Stehno +// Copyright (C) 2013-2015 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OSX_DEVICE_ + +#import +#import +#ifndef __MAC_10_6 +#import +#endif + +#include "CIrrDeviceOSX.h" + +#include "IEventReceiver.h" +#include "irrList.h" +#include "os.h" +#include "CTimer.h" +#include "irrString.h" +#include "Keycodes.h" +#include +#include +#include "COSOperator.h" +#include "CColorConverter.h" +#include "irrlicht.h" +#include + +#include +#include + +#include "CNSOGLManager.h" + +#if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ + +#include +#include +#ifdef MACOS_10_0_4 +#include +#else +/* The header was moved here in Mac OS X 10.1 */ +#include +#endif +#include +#include + +struct JoystickComponent +{ + IOHIDElementCookie cookie; // unique value which identifies element, will NOT change + long min; // reported min value possible + long max; // reported max value possible + + long minRead; //min read value + long maxRead; //max read value + + JoystickComponent() : min(0), minRead(0), max(0), maxRead(0) + { + } +}; + +struct JoystickInfo +{ + irr::core::array axisComp; + irr::core::array buttonComp; + irr::core::array hatComp; + + int hats; + int axes; + int buttons; + int numActiveJoysticks; + + irr::SEvent persistentData; + + IOHIDDeviceInterface ** interface; + bool removed; + char joystickName[256]; + long usage; // usage page from IOUSBHID Parser.h which defines general usage + long usagePage; // usage within above page from IOUSBHID Parser.h which defines specific usage + + JoystickInfo() : hats(0), axes(0), buttons(0), interface(0), removed(false), usage(0), usagePage(0), numActiveJoysticks(0) + { + interface = NULL; + memset(joystickName, '\0', 256); + axisComp.clear(); + buttonComp.clear(); + hatComp.clear(); + + persistentData.EventType = irr::EET_JOYSTICK_INPUT_EVENT; + persistentData.JoystickEvent.POV = 65535; + persistentData.JoystickEvent.ButtonStates = 0; + } +}; +irr::core::array ActiveJoysticks; + +//helper functions for init joystick +static IOReturn closeJoystickDevice (JoystickInfo* joyInfo) +{ + IOReturn result = kIOReturnSuccess; + if (joyInfo && joyInfo->interface) + { + /* close the interface */ + result = (*(joyInfo->interface))->close (joyInfo->interface); + if (kIOReturnNotOpen == result) + { + /* do nothing as device was not opened, thus can't be closed */ + } + else if (kIOReturnSuccess != result) + irr::os::Printer::log("IOHIDDeviceInterface failed to close", irr::ELL_ERROR); + /* release the interface */ + result = (*(joyInfo->interface))->Release (joyInfo->interface); + if (kIOReturnSuccess != result) + irr::os::Printer::log("IOHIDDeviceInterface failed to release", irr::ELL_ERROR); + joyInfo->interface = NULL; + } + return result; +} + +static void addComponentInfo (CFTypeRef refElement, JoystickComponent *pComponent, int numActiveJoysticks) +{ + long number; + CFTypeRef refType; + + refType = CFDictionaryGetValue ((CFDictionaryRef)refElement, CFSTR(kIOHIDElementCookieKey)); + if (refType && CFNumberGetValue ((CFNumberRef)refType, kCFNumberLongType, &number)) + pComponent->cookie = (IOHIDElementCookie) number; + refType = CFDictionaryGetValue ((CFDictionaryRef)refElement, CFSTR(kIOHIDElementMinKey)); + if (refType && CFNumberGetValue ((CFNumberRef)refType, kCFNumberLongType, &number)) + pComponent->minRead = pComponent->min = number; + refType = CFDictionaryGetValue ((CFDictionaryRef)refElement, CFSTR(kIOHIDElementMaxKey)); + if (refType && CFNumberGetValue ((CFNumberRef)refType, kCFNumberLongType, &number)) + pComponent->maxRead = pComponent->max = number; +} + +static void getJoystickComponentArrayHandler (const void * value, void * parameter); + +static void addJoystickComponent (CFTypeRef refElement, JoystickInfo* joyInfo) +{ + long elementType, usagePage, usage; + CFTypeRef refElementType = CFDictionaryGetValue ((CFDictionaryRef)refElement, CFSTR(kIOHIDElementTypeKey)); + CFTypeRef refUsagePage = CFDictionaryGetValue ((CFDictionaryRef)refElement, CFSTR(kIOHIDElementUsagePageKey)); + CFTypeRef refUsage = CFDictionaryGetValue ((CFDictionaryRef)refElement, CFSTR(kIOHIDElementUsageKey)); + + if ((refElementType) && (CFNumberGetValue ((CFNumberRef)refElementType, kCFNumberLongType, &elementType))) + { + /* look at types of interest */ + if ((elementType == kIOHIDElementTypeInput_Misc) || (elementType == kIOHIDElementTypeInput_Button) || + (elementType == kIOHIDElementTypeInput_Axis)) + { + if (refUsagePage && CFNumberGetValue ((CFNumberRef)refUsagePage, kCFNumberLongType, &usagePage) && + refUsage && CFNumberGetValue ((CFNumberRef)refUsage, kCFNumberLongType, &usage)) + { + switch (usagePage) /* only interested in kHIDPage_GenericDesktop and kHIDPage_Button */ + { + case kHIDPage_GenericDesktop: + { + switch (usage) /* look at usage to determine function */ + { + case kHIDUsage_GD_X: + case kHIDUsage_GD_Y: + case kHIDUsage_GD_Z: + case kHIDUsage_GD_Rx: + case kHIDUsage_GD_Ry: + case kHIDUsage_GD_Rz: + case kHIDUsage_GD_Slider: + case kHIDUsage_GD_Dial: + case kHIDUsage_GD_Wheel: + { + joyInfo->axes++; + JoystickComponent newComponent; + addComponentInfo(refElement, &newComponent, joyInfo->numActiveJoysticks); + joyInfo->axisComp.push_back(newComponent); + } + break; + case kHIDUsage_GD_Hatswitch: + { + joyInfo->hats++; + JoystickComponent newComponent; + addComponentInfo(refElement, &newComponent, joyInfo->numActiveJoysticks); + joyInfo->hatComp.push_back(newComponent); + } + break; + } + } + break; + case kHIDPage_Button: + { + joyInfo->buttons++; + JoystickComponent newComponent; + addComponentInfo(refElement, &newComponent, joyInfo->numActiveJoysticks); + joyInfo->buttonComp.push_back(newComponent); + } + break; + default: + break; + } + } + } + else if (kIOHIDElementTypeCollection == elementType) + { + //get elements + CFTypeRef refElementTop = CFDictionaryGetValue ((CFMutableDictionaryRef) refElement, CFSTR(kIOHIDElementKey)); + if (refElementTop) + { + CFTypeID type = CFGetTypeID (refElementTop); + if (type == CFArrayGetTypeID()) + { + CFRange range = {0, CFArrayGetCount ((CFArrayRef)refElementTop)}; + CFArrayApplyFunction ((CFArrayRef)refElementTop, range, getJoystickComponentArrayHandler, joyInfo); + } + } + } + } +} + +static void getJoystickComponentArrayHandler (const void * value, void * parameter) +{ + if (CFGetTypeID (value) == CFDictionaryGetTypeID ()) + addJoystickComponent ((CFTypeRef) value, (JoystickInfo *) parameter); +} + +static void joystickTopLevelElementHandler (const void * value, void * parameter) +{ + CFTypeRef refCF = 0; + if (CFGetTypeID (value) != CFDictionaryGetTypeID ()) + return; + refCF = CFDictionaryGetValue ((CFDictionaryRef)value, CFSTR(kIOHIDElementUsagePageKey)); + if (!CFNumberGetValue ((CFNumberRef)refCF, kCFNumberLongType, &((JoystickInfo *) parameter)->usagePage)) + irr::os::Printer::log("CFNumberGetValue error retrieving JoystickInfo->usagePage", irr::ELL_ERROR); + refCF = CFDictionaryGetValue ((CFDictionaryRef)value, CFSTR(kIOHIDElementUsageKey)); + if (!CFNumberGetValue ((CFNumberRef)refCF, kCFNumberLongType, &((JoystickInfo *) parameter)->usage)) + irr::os::Printer::log("CFNumberGetValue error retrieving JoystickInfo->usage", irr::ELL_ERROR); +} + +static void getJoystickDeviceInfo (io_object_t hidDevice, CFMutableDictionaryRef hidProperties, JoystickInfo *joyInfo) +{ + CFMutableDictionaryRef usbProperties = 0; + io_registry_entry_t parent1, parent2; + + /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also + * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties + */ + if ((KERN_SUCCESS == IORegistryEntryGetParentEntry (hidDevice, kIOServicePlane, &parent1)) && + (KERN_SUCCESS == IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2)) && + (KERN_SUCCESS == IORegistryEntryCreateCFProperties (parent2, &usbProperties, kCFAllocatorDefault, kNilOptions))) + { + if (usbProperties) + { + CFTypeRef refCF = 0; + /* get device info + * try hid dictionary first, if fail then go to usb dictionary + */ + + /* get joystickName name */ + refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDProductKey)); + if (!refCF) + refCF = CFDictionaryGetValue (usbProperties, CFSTR("USB Product Name")); + if (refCF) + { + if (!CFStringGetCString ((CFStringRef)refCF, joyInfo->joystickName, 256, CFStringGetSystemEncoding ())) + irr::os::Printer::log("CFStringGetCString error getting joyInfo->joystickName", irr::ELL_ERROR); + } + + /* get usage page and usage */ + refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDPrimaryUsagePageKey)); + if (refCF) + { + if (!CFNumberGetValue ((CFNumberRef)refCF, kCFNumberLongType, &joyInfo->usagePage)) + irr::os::Printer::log("CFNumberGetValue error getting joyInfo->usagePage", irr::ELL_ERROR); + refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDPrimaryUsageKey)); + if (refCF) + if (!CFNumberGetValue ((CFNumberRef)refCF, kCFNumberLongType, &joyInfo->usage)) + irr::os::Printer::log("CFNumberGetValue error getting joyInfo->usage", irr::ELL_ERROR); + } + + if (NULL == refCF) /* get top level element HID usage page or usage */ + { + /* use top level element instead */ + CFTypeRef refCFTopElement = 0; + refCFTopElement = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDElementKey)); + { + /* refCFTopElement points to an array of element dictionaries */ + CFRange range = {0, CFArrayGetCount ((CFArrayRef)refCFTopElement)}; + CFArrayApplyFunction ((CFArrayRef)refCFTopElement, range, joystickTopLevelElementHandler, joyInfo); + } + } + + CFRelease (usbProperties); + } + else + irr::os::Printer::log("IORegistryEntryCreateCFProperties failed to create usbProperties", irr::ELL_ERROR); + + if (kIOReturnSuccess != IOObjectRelease (parent2)) + irr::os::Printer::log("IOObjectRelease failed to release parent2", irr::ELL_ERROR); + if (kIOReturnSuccess != IOObjectRelease (parent1)) + irr::os::Printer::log("IOObjectRelease failed to release parent1", irr::ELL_ERROR); + } +} + +#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ + +// only OSX 10.5 seems to not need these defines... +#if !defined(__MAC_10_5) || defined(__MAC_10_6) +// Contents from Events.h from Carbon/HIToolbox but we need it with Cocoa too +// and for some reason no Cocoa equivalent of these constants seems provided. +// So I'm doing like everyone else and using copy-and-paste. + +/* + * Summary: + * Virtual keycodes + * + * Discussion: + * These constants are the virtual keycodes defined originally in + * Inside Mac Volume V, pg. V-191. They identify physical keys on a + * keyboard. Those constants with "ANSI" in the name are labeled + * according to the key position on an ANSI-standard US keyboard. + * For example, kVK_ANSI_A indicates the virtual keycode for the key + * with the letter 'A' in the US keyboard layout. Other keyboard + * layouts may have the 'A' key label on a different physical key; + * in this case, pressing 'A' will generate a different virtual + * keycode. + */ +enum { + kVK_ANSI_A = 0x00, + kVK_ANSI_S = 0x01, + kVK_ANSI_D = 0x02, + kVK_ANSI_F = 0x03, + kVK_ANSI_H = 0x04, + kVK_ANSI_G = 0x05, + kVK_ANSI_Z = 0x06, + kVK_ANSI_X = 0x07, + kVK_ANSI_C = 0x08, + kVK_ANSI_V = 0x09, + kVK_ANSI_B = 0x0B, + kVK_ANSI_Q = 0x0C, + kVK_ANSI_W = 0x0D, + kVK_ANSI_E = 0x0E, + kVK_ANSI_R = 0x0F, + kVK_ANSI_Y = 0x10, + kVK_ANSI_T = 0x11, + kVK_ANSI_1 = 0x12, + kVK_ANSI_2 = 0x13, + kVK_ANSI_3 = 0x14, + kVK_ANSI_4 = 0x15, + kVK_ANSI_6 = 0x16, + kVK_ANSI_5 = 0x17, + kVK_ANSI_Equal = 0x18, + kVK_ANSI_9 = 0x19, + kVK_ANSI_7 = 0x1A, + kVK_ANSI_Minus = 0x1B, + kVK_ANSI_8 = 0x1C, + kVK_ANSI_0 = 0x1D, + kVK_ANSI_RightBracket = 0x1E, + kVK_ANSI_O = 0x1F, + kVK_ANSI_U = 0x20, + kVK_ANSI_LeftBracket = 0x21, + kVK_ANSI_I = 0x22, + kVK_ANSI_P = 0x23, + kVK_ANSI_L = 0x25, + kVK_ANSI_J = 0x26, + kVK_ANSI_Quote = 0x27, + kVK_ANSI_K = 0x28, + kVK_ANSI_Semicolon = 0x29, + kVK_ANSI_Backslash = 0x2A, + kVK_ANSI_Comma = 0x2B, + kVK_ANSI_Slash = 0x2C, + kVK_ANSI_N = 0x2D, + kVK_ANSI_M = 0x2E, + kVK_ANSI_Period = 0x2F, + kVK_ANSI_Grave = 0x32, + kVK_ANSI_KeypadDecimal = 0x41, + kVK_ANSI_KeypadMultiply = 0x43, + kVK_ANSI_KeypadPlus = 0x45, + kVK_ANSI_KeypadClear = 0x47, + kVK_ANSI_KeypadDivide = 0x4B, + kVK_ANSI_KeypadEnter = 0x4C, + kVK_ANSI_KeypadMinus = 0x4E, + kVK_ANSI_KeypadEquals = 0x51, + kVK_ANSI_Keypad0 = 0x52, + kVK_ANSI_Keypad1 = 0x53, + kVK_ANSI_Keypad2 = 0x54, + kVK_ANSI_Keypad3 = 0x55, + kVK_ANSI_Keypad4 = 0x56, + kVK_ANSI_Keypad5 = 0x57, + kVK_ANSI_Keypad6 = 0x58, + kVK_ANSI_Keypad7 = 0x59, + kVK_ANSI_Keypad8 = 0x5B, + kVK_ANSI_Keypad9 = 0x5C +}; + +/* keycodes for keys that are independent of keyboard layout*/ +enum { + kVK_Return = 0x24, + kVK_Tab = 0x30, + kVK_Space = 0x31, + kVK_Delete = 0x33, + kVK_Escape = 0x35, + kVK_Command = 0x37, + kVK_Shift = 0x38, + kVK_CapsLock = 0x39, + kVK_Option = 0x3A, + kVK_Control = 0x3B, + kVK_RightShift = 0x3C, + kVK_RightOption = 0x3D, + kVK_RightControl = 0x3E, + kVK_Function = 0x3F, + kVK_F17 = 0x40, + kVK_VolumeUp = 0x48, + kVK_VolumeDown = 0x49, + kVK_Mute = 0x4A, + kVK_F18 = 0x4F, + kVK_F19 = 0x50, + kVK_F20 = 0x5A, + kVK_F5 = 0x60, + kVK_F6 = 0x61, + kVK_F7 = 0x62, + kVK_F3 = 0x63, + kVK_F8 = 0x64, + kVK_F9 = 0x65, + kVK_F11 = 0x67, + kVK_F13 = 0x69, + kVK_F16 = 0x6A, + kVK_F14 = 0x6B, + kVK_F10 = 0x6D, + kVK_F12 = 0x6F, + kVK_F15 = 0x71, + kVK_Help = 0x72, + kVK_Home = 0x73, + kVK_PageUp = 0x74, + kVK_ForwardDelete = 0x75, + kVK_F4 = 0x76, + kVK_End = 0x77, + kVK_F2 = 0x78, + kVK_PageDown = 0x79, + kVK_F1 = 0x7A, + kVK_LeftArrow = 0x7B, + kVK_RightArrow = 0x7C, + kVK_DownArrow = 0x7D, + kVK_UpArrow = 0x7E +}; +#endif + +//------------------------------------------------------------------------------------------ +Boolean GetDictionaryBoolean(CFDictionaryRef theDict, const void* key) +{ + // get a boolean from the dictionary + Boolean value = false; + CFBooleanRef boolRef; + boolRef = (CFBooleanRef)CFDictionaryGetValue(theDict, key); + if (boolRef != NULL) + value = CFBooleanGetValue(boolRef); + return value; +} +//------------------------------------------------------------------------------------------ +long GetDictionaryLong(CFDictionaryRef theDict, const void* key) +{ + // get a long from the dictionary + long value = 0; + CFNumberRef numRef; + numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key); + if (numRef != NULL) + CFNumberGetValue(numRef, kCFNumberLongType, &value); + return value; +} + +namespace irr +{ + namespace video + { + IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& param, io::IFileSystem* io, IContextManager* contextManager); + } +} // end namespace irr + +static bool firstLaunch = true; + +@implementation CIrrDelegateOSX +{ + irr::CIrrDeviceMacOSX* Device; + bool Quit; +} + +- (id)initWithDevice:(irr::CIrrDeviceMacOSX*)device +{ + self = [super init]; + + if (self) + Device = device; + + Quit = false; + + return (self); +} + +- (void)applicationDidFinishLaunching:(NSNotification*)notification +{ + Quit = false; +} + +- (void)orderFrontStandardAboutPanel:(id)sender +{ + [NSApp orderFrontStandardAboutPanel:sender]; +} + +- (void)unhideAllApplications:(id)sender +{ + [NSApp unhideAllApplications:sender]; +} + +- (void)hide:(id)sender +{ + [NSApp hide:sender]; +} + +- (void)hideOtherApplications:(id)sender +{ + [NSApp hideOtherApplications:sender]; +} + +- (void)terminate:(id)sender +{ + Quit = true; +} + +- (void)windowWillClose:(id)sender +{ + Device->setWindow(nil); + Quit = true; +} + +- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize +{ + if (Device->isResizable()) + return proposedFrameSize; + else + return [window frame].size; +} + +- (void)windowDidResize:(NSNotification *)aNotification +{ + NSWindow *window; + NSRect frame; + + window = [aNotification object]; + frame = [window frame]; + Device->setResize((int)frame.size.width,(int)frame.size.height); +} + +- (BOOL)isQuit +{ + return (Quit); +} + +@end + +namespace irr +{ +//! constructor +CIrrDeviceMacOSX::CIrrDeviceMacOSX(const SIrrlichtCreationParameters& param) + : CIrrDeviceStub(param), Window(NULL), Display(NULL), + SoftwareDriverTarget(0), DeviceWidth(0), DeviceHeight(0), + ScreenWidth(0), ScreenHeight(0), MouseButtonStates(0), SoftwareRendererType(0), + IsActive(true), IsFullscreen(false), IsShiftDown(false), IsControlDown(false), IsResizable(false) +{ + struct utsname name; + NSString *path; + +#ifdef _DEBUG + setDebugName("CIrrDeviceMacOSX"); +#endif + + if (firstLaunch) + { + firstLaunch = false; + + if (!CreationParams.WindowId) + { + [[NSAutoreleasePool alloc] init]; + [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; + [NSApp setDelegate:(id)[[[CIrrDelegateOSX alloc] initWithDevice:this] autorelease]]; + + // Create menu + + NSString* bundleName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; + + NSMenu* mainMenu = [[[NSMenu alloc] initWithTitle:@"MainMenu"] autorelease]; + NSMenu* menu = [[[NSMenu alloc] initWithTitle:bundleName] autorelease]; + NSMenuItem* menuItem = [mainMenu addItemWithTitle:bundleName action:nil keyEquivalent:@""]; + [mainMenu setSubmenu:menu forItem:menuItem]; + menuItem = [menu addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"]; + [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask]; + + [NSApp setMainMenu:mainMenu]; + + [NSApp finishLaunching]; + } + + path = [[NSBundle mainBundle] bundlePath]; + path = [path stringByAppendingString:@"/Contents/Resources"]; + chdir([path fileSystemRepresentation]); + [path release]; + } + + uname(&name); + Operator = new COSOperator(name.version); + os::Printer::log(name.version,ELL_INFORMATION); + + initKeycodes(); + + VideoModeList->setDesktop(CreationParams.Bits, core::dimension2d([[NSScreen mainScreen] frame].size.width, [[NSScreen mainScreen] frame].size.height)); + + bool success = true; + + if (CreationParams.DriverType != video::EDT_NULL) + success = createWindow(); + + // in case of failure, one can check VideoDriver for initialization + if (!success) + return; + + setResizable(false); + CursorControl = new CCursorControl(CreationParams.WindowSize, this); + + createDriver(); + createGUIAndScene(); +} + +CIrrDeviceMacOSX::~CIrrDeviceMacOSX() +{ + [SoftwareDriverTarget release]; +#ifdef __MAC_10_6 + [NSApp setPresentationOptions:(NSApplicationPresentationDefault)]; +#else + SetSystemUIMode(kUIModeNormal, kUIOptionAutoShowMenuBar); +#endif + closeDevice(); +#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) + for (u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) + { + if (ActiveJoysticks[joystick].interface) + closeJoystickDevice(&ActiveJoysticks[joystick]); + } +#endif +} + +void CIrrDeviceMacOSX::closeDevice() +{ + if (Window != nil) + { + [Window setIsVisible:FALSE]; + [Window setReleasedWhenClosed:TRUE]; + [Window release]; + Window = nil; + } + + if (IsFullscreen) + CGReleaseAllDisplays(); + + IsFullscreen = false; + IsActive = false; +} + +bool CIrrDeviceMacOSX::createWindow() +{ + CGDisplayErr error; + bool result = false; + Display = CGMainDisplayID(); + + CGRect displayRect; +#ifdef __MAC_10_6 + CGDisplayModeRef displaymode, olddisplaymode; +#else + CFDictionaryRef displaymode, olddisplaymode; +#endif + + ScreenWidth = (int)CGDisplayPixelsWide(Display); + ScreenHeight = (int)CGDisplayPixelsHigh(Display); + + const NSBackingStoreType type = (CreationParams.DriverType == video::EDT_OPENGL) ? NSBackingStoreBuffered : NSBackingStoreNonretained; + + if (!CreationParams.Fullscreen) + { + if (!CreationParams.WindowId) //create another window when WindowId is null + { + int x = (CreationParams.WindowPosition.X > 0) ? CreationParams.WindowPosition.X : 0; + int y = (CreationParams.WindowPosition.Y > 0) ? CreationParams.WindowPosition.Y : 0; + + if (CreationParams.WindowPosition.Y > -1) + { + int screenHeight = [[[NSScreen screens] objectAtIndex:0] frame].size.height; + y = screenHeight - y - CreationParams.WindowSize.Height; + } + + Window = [[NSWindow alloc] initWithContentRect:NSMakeRect(x, y, CreationParams.WindowSize.Width,CreationParams.WindowSize.Height) styleMask:NSTitledWindowMask+NSClosableWindowMask+NSResizableWindowMask backing:type defer:FALSE]; + + if (CreationParams.WindowPosition.X == -1 && CreationParams.WindowPosition.Y == -1) + [Window center]; + } + + DeviceWidth = CreationParams.WindowSize.Width; + DeviceHeight = CreationParams.WindowSize.Height; + + result = true; + } + else + { + IsFullscreen = true; + +#ifdef __MAC_10_6 + displaymode = CGDisplayCopyDisplayMode(Display); + + CFArrayRef Modes = CGDisplayCopyAllDisplayModes(Display, NULL); + + for(int i = 0; i < CFArrayGetCount(Modes); ++i) + { + CGDisplayModeRef CurrentMode = (CGDisplayModeRef)CFArrayGetValueAtIndex(Modes, i); + + u8 Depth = 0; + + CFStringRef pixEnc = CGDisplayModeCopyPixelEncoding(CurrentMode); + + if (CFStringCompare(pixEnc, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) + Depth = 32; + else if(CFStringCompare(pixEnc, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) + Depth = 16; + else if(CFStringCompare(pixEnc, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) + Depth = 8; + + if(Depth == CreationParams.Bits) + if((CGDisplayModeGetWidth(CurrentMode) == CreationParams.WindowSize.Width) && (CGDisplayModeGetHeight(CurrentMode) == CreationParams.WindowSize.Height)) + { + displaymode = CurrentMode; + break; + } + } +#else + displaymode = CGDisplayBestModeForParameters(Display,CreationParams.Bits,CreationParams.WindowSize.Width,CreationParams.WindowSize.Height,NULL); +#endif + + if (displaymode != NULL) + { +#ifdef __MAC_10_6 + olddisplaymode = CGDisplayCopyDisplayMode(Display); +#else + olddisplaymode = CGDisplayCurrentMode(Display); +#endif + + error = CGCaptureAllDisplays(); + if (error == CGDisplayNoErr) + { +#ifdef __MAC_10_6 + error = CGDisplaySetDisplayMode(Display, displaymode, NULL); +#else + error = CGDisplaySwitchToMode(Display, displaymode); +#endif + + if (error == CGDisplayNoErr) + { + Window = [[NSWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame] styleMask:NSBorderlessWindowMask backing:type defer:FALSE screen:[NSScreen mainScreen]]; + + [Window setLevel: CGShieldingWindowLevel()]; + [Window setBackgroundColor:[NSColor blackColor]]; + + displayRect = CGDisplayBounds(Display); + ScreenWidth = DeviceWidth = (int)displayRect.size.width; + ScreenHeight = DeviceHeight = (int)displayRect.size.height; + CreationParams.WindowSize.set(ScreenWidth, ScreenHeight); + + result = true; + } + + if (!result) + CGReleaseAllDisplays(); + } + } + } + + if (result) + { + if (Window) + { + [Window setDelegate:(id)[NSApp delegate]]; + [Window setAcceptsMouseMovedEvents:TRUE]; + [Window setIsVisible:TRUE]; + [Window makeKeyAndOrderFront:nil]; + } + + if (IsFullscreen) //hide menus in fullscreen mode only + { +#ifdef __MAC_10_6 + [NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)]; +#else + SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar); +#endif + } + } + + return result; +} + +void CIrrDeviceMacOSX::setResize(int width, int height) +{ + // set new window size + DeviceWidth = width; + DeviceHeight = height; + +#if defined(_IRR_COMPILE_WITH_OPENGL_) + // update the size of the opengl rendering context + if (CreationParams.DriverType == video::EDT_OPENGL) + { + NSOpenGLContext* Context = (NSOpenGLContext*)ContextManager->getContext().OpenGLOSX.Context; + + if (Context) + [Context update]; + } +#endif + + // resize the driver to the inner pane size + if (Window) + { + NSRect driverFrame = [Window contentRectForFrameRect:[Window frame]]; + getVideoDriver()->OnResize(core::dimension2d( (s32)driverFrame.size.width, (s32)driverFrame.size.height)); + } + else + getVideoDriver()->OnResize(core::dimension2d( (s32)width, (s32)height)); +} + + +void CIrrDeviceMacOSX::createDriver() +{ + switch (CreationParams.DriverType) + { + case video::EDT_SOFTWARE: +#ifdef _IRR_COMPILE_WITH_SOFTWARE_ + VideoDriver = video::createSoftwareDriver(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this); + SoftwareRendererType = 2; +#else + os::Printer::log("No Software driver support compiled in.", ELL_ERROR); +#endif + break; + + case video::EDT_BURNINGSVIDEO: +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + VideoDriver = video::createBurningVideoDriver(CreationParams, FileSystem, this); + SoftwareRendererType = 1; +#else + os::Printer::log("Burning's video driver was not compiled in.", ELL_ERROR); +#endif + break; + + case video::EDT_OPENGL: +#ifdef _IRR_COMPILE_WITH_OPENGL_ + { + video::SExposedVideoData data; + data.OpenGLOSX.Window = Window; + ContextManager = new video::CNSOGLManager(); + ContextManager->initialize(CreationParams, data); + VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, ContextManager); + if (!VideoDriver) + { + os::Printer::log("Could not create OpenGL driver.", ELL_ERROR); + } + + if (Window) + [(NSOpenGLContext*)ContextManager->getContext().OpenGLOSX.Context setView:[Window contentView]]; + else + [(NSOpenGLContext*)ContextManager->getContext().OpenGLOSX.Context setView:(NSView*)CreationParams.WindowId]; + +#ifndef __MAC_10_6 + CGLContextObj CGLContext = (CGLContextObj)[(NSOpenGLContext*)ContextManager->getContext().OpenGLOSX.Context CGLContextObj]; + CGLSetFullScreen(CGLContext); +#endif + } +#else + os::Printer::log("No OpenGL support compiled in.", ELL_ERROR); +#endif + break; + + case video::DEPRECATED_EDT_DIRECT3D8_NO_LONGER_EXISTS: + case video::EDT_DIRECT3D9: + case video::EDT_OGLES1: + case video::EDT_OGLES2: + os::Printer::log("This driver is not available in OSX. Try OpenGL or Software renderer.", ELL_ERROR); + break; + + case video::EDT_NULL: + VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize); + break; + + default: + os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR); + break; + } +} + +bool CIrrDeviceMacOSX::run() +{ + NSAutoreleasePool* Pool = [[NSAutoreleasePool alloc] init]; + + NSEvent *event; + irr::SEvent ievent; + + os::Timer::tick(); + storeMouseLocation(); + + event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; + if (event != nil) + { + bzero(&ievent,sizeof(ievent)); + + switch([(NSEvent *)event type]) + { + case NSKeyDown: + postKeyEvent(event,ievent,true); + break; + + case NSKeyUp: + 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; + MouseButtonStates |= irr::EMBSM_LEFT; + ievent.MouseInput.ButtonStates = MouseButtonStates; + postMouseEvent(event,ievent); + break; + + case NSLeftMouseUp: + ievent.EventType = irr::EET_MOUSE_INPUT_EVENT; + MouseButtonStates &= !irr::EMBSM_LEFT; + ievent.MouseInput.ButtonStates = MouseButtonStates; + ievent.MouseInput.Event = irr::EMIE_LMOUSE_LEFT_UP; + postMouseEvent(event,ievent); + break; + + case NSOtherMouseDown: + ievent.EventType = irr::EET_MOUSE_INPUT_EVENT; + ievent.MouseInput.Event = irr::EMIE_MMOUSE_PRESSED_DOWN; + MouseButtonStates |= irr::EMBSM_MIDDLE; + ievent.MouseInput.ButtonStates = MouseButtonStates; + postMouseEvent(event,ievent); + break; + + case NSOtherMouseUp: + ievent.EventType = irr::EET_MOUSE_INPUT_EVENT; + MouseButtonStates &= !irr::EMBSM_MIDDLE; + ievent.MouseInput.ButtonStates = MouseButtonStates; + ievent.MouseInput.Event = irr::EMIE_MMOUSE_LEFT_UP; + postMouseEvent(event,ievent); + break; + + case NSMouseMoved: + case NSLeftMouseDragged: + case NSRightMouseDragged: + case NSOtherMouseDragged: + ievent.EventType = irr::EET_MOUSE_INPUT_EVENT; + ievent.MouseInput.Event = irr::EMIE_MOUSE_MOVED; + ievent.MouseInput.ButtonStates = MouseButtonStates; + postMouseEvent(event,ievent); + break; + + case NSRightMouseDown: + ievent.EventType = irr::EET_MOUSE_INPUT_EVENT; + ievent.MouseInput.Event = irr::EMIE_RMOUSE_PRESSED_DOWN; + MouseButtonStates |= irr::EMBSM_RIGHT; + ievent.MouseInput.ButtonStates = MouseButtonStates; + postMouseEvent(event,ievent); + break; + + case NSRightMouseUp: + ievent.EventType = irr::EET_MOUSE_INPUT_EVENT; + ievent.MouseInput.Event = irr::EMIE_RMOUSE_LEFT_UP; + MouseButtonStates &= !irr::EMBSM_RIGHT; + ievent.MouseInput.ButtonStates = MouseButtonStates; + postMouseEvent(event,ievent); + break; + + case NSScrollWheel: + ievent.EventType = irr::EET_MOUSE_INPUT_EVENT; + ievent.MouseInput.Event = irr::EMIE_MOUSE_WHEEL; + ievent.MouseInput.Wheel = [(NSEvent *)event deltaY]; + if (ievent.MouseInput.Wheel < 1.0f) + ievent.MouseInput.Wheel *= 10.0f; + else + ievent.MouseInput.Wheel *= 5.0f; + postMouseEvent(event,ievent); + break; + + default: + [NSApp sendEvent:event]; + break; + } + } + + pollJoysticks(); + + [Pool release]; + + return (![[NSApp delegate] isQuit] && IsActive); +} + + +//! Pause the current process for the minimum time allowed only to allow other processes to execute +void CIrrDeviceMacOSX::yield() +{ + struct timespec ts = {0,0}; + nanosleep(&ts, NULL); +} + + +//! Pause execution and let other processes to run for a specified amount of time. +void CIrrDeviceMacOSX::sleep(u32 timeMs, bool pauseTimer=false) +{ + bool wasStopped = Timer ? Timer->isStopped() : true; + + struct timespec ts; + ts.tv_sec = (time_t) (timeMs / 1000); + ts.tv_nsec = (long) (timeMs % 1000) * 1000000; + + if (pauseTimer && !wasStopped) + Timer->stop(); + + nanosleep(&ts, NULL); + + if (pauseTimer && !wasStopped) + Timer->start(); +} + + +void CIrrDeviceMacOSX::setWindowCaption(const wchar_t* text) +{ + size_t size; + char title[1024]; + + if (Window != NULL) + { + size = wcstombs(title,text,1024); + title[1023] = 0; +#ifdef __MAC_10_6 + NSString* name = [NSString stringWithCString:title encoding:NSUTF8StringEncoding]; +#else + NSString* name = [NSString stringWithCString:title length:size]; +#endif + [Window setTitle:name]; + [name release]; + } +} + + +bool CIrrDeviceMacOSX::isWindowActive() const +{ + return (IsActive); +} + + +bool CIrrDeviceMacOSX::isWindowFocused() const +{ + if (Window != NULL) + return [Window isKeyWindow]; + return false; +} + + +bool CIrrDeviceMacOSX::isWindowMinimized() const +{ + if (Window != NULL) + return [Window isMiniaturized]; + return false; +} + + +void CIrrDeviceMacOSX::postKeyEvent(void *event,irr::SEvent &ievent,bool pressed) +{ + NSString *str; + std::map::const_iterator iter; + unsigned int c,mkey,mchar; + const unsigned char *cStr; + BOOL skipCommand; + + str = [(NSEvent *)event characters]; + if ((str != nil) && ([str length] > 0)) + { + mkey = mchar = 0; + skipCommand = false; + c = [str characterAtIndex:0]; + mchar = c; + + iter = KeyCodes.find([(NSEvent *)event keyCode]); + if (iter != KeyCodes.end()) + mkey = (*iter).second; + else if ((iter = KeyCodes.find(c)) != KeyCodes.end()) + mkey = (*iter).second; + else + { + // workaround for period character + if (c == 0x2E) + { + mkey = irr::KEY_PERIOD; + mchar = '.'; + } + else + { + cStr = (unsigned char *)[str cStringUsingEncoding:NSWindowsCP1252StringEncoding]; + if (cStr != NULL && strlen((char*)cStr) > 0) + { + mchar = cStr[0]; + mkey = toupper(mchar); + if ([(NSEvent *)event modifierFlags] & NSCommandKeyMask) + { + if (mkey == 'C' || mkey == 'V' || mkey == 'X') + { + mchar = 0; + skipCommand = true; + } + } + } + } + } + + ievent.EventType = irr::EET_KEY_INPUT_EVENT; + ievent.KeyInput.Key = (irr::EKEY_CODE)mkey; + ievent.KeyInput.PressedDown = pressed; + ievent.KeyInput.Shift = ([(NSEvent *)event modifierFlags] & NSShiftKeyMask) != 0; + ievent.KeyInput.Control = ([(NSEvent *)event modifierFlags] & NSControlKeyMask) != 0; + ievent.KeyInput.Char = mchar; + + if (skipCommand) + ievent.KeyInput.Control = true; + else if ([(NSEvent *)event modifierFlags] & NSCommandKeyMask) + [NSApp sendEvent:(NSEvent *)event]; + + postEventFromUser(ievent); + } +} + + +void CIrrDeviceMacOSX::postMouseEvent(void *event,irr::SEvent &ievent) +{ + bool post = true; + + if (Window != NULL) + { + ievent.MouseInput.X = (int)[(NSEvent *)event locationInWindow].x; + ievent.MouseInput.Y = DeviceHeight - (int)[(NSEvent *)event locationInWindow].y; + + if (ievent.MouseInput.Y < 0) + post = false; + } + else + { + CGEventRef ourEvent = CGEventCreate(NULL); + CGPoint point = CGEventGetLocation(ourEvent); + CFRelease(ourEvent); + + ievent.MouseInput.X = (int)point.x; + ievent.MouseInput.Y = (int)point.y; + + if (ievent.MouseInput.Y < 0) + post = false; + } + + if (post) + { + ievent.MouseInput.Shift = ([(NSEvent *)event modifierFlags] & NSShiftKeyMask) != 0; + ievent.MouseInput.Control = ([(NSEvent *)event modifierFlags] & NSControlKeyMask) != 0; + + postEventFromUser(ievent); + } + + [NSApp sendEvent:(NSEvent *)event]; +} + + +void CIrrDeviceMacOSX::storeMouseLocation() +{ + int x,y; + + if (Window != NULL) + { + NSPoint p; + p = [NSEvent mouseLocation]; + p = [Window convertScreenToBase:p]; + x = (int)p.x; + y = DeviceHeight - (int)p.y; + } + else + { + CGEventRef ourEvent = CGEventCreate(NULL); + CGPoint point = CGEventGetLocation(ourEvent); + CFRelease(ourEvent); + + x = (int)point.x; + y = (int)point.y; + + const core::position2di& curr = ((CCursorControl *)CursorControl)->getPosition(); + if (curr.X != x || curr.Y != y) + { + // In fullscreen mode, events are not sent regularly so rely on polling + irr::SEvent ievent; + ievent.EventType = irr::EET_MOUSE_INPUT_EVENT; + ievent.MouseInput.Event = irr::EMIE_MOUSE_MOVED; + ievent.MouseInput.X = x; + ievent.MouseInput.Y = y; + postEventFromUser(ievent); + } + } + + ((CCursorControl *)CursorControl)->updateInternalCursorPosition(x,y); +} + + +void CIrrDeviceMacOSX::setMouseLocation(int x,int y) +{ + NSPoint p; + CGPoint c; + + if (Window != NULL) + { + // Irrlicht window exists + p.x = (float) x; + p.y = (float) (DeviceHeight - y); + p = [Window convertBaseToScreen:p]; + p.y = ScreenHeight - p.y; + } + else + { + p.x = (float) x; + p.y = (float) y + (ScreenHeight - DeviceHeight); + } + + c.x = p.x; + c.y = p.y; + +#ifdef __MAC_10_6 + CGEventRef ev = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, c, kCGMouseButtonLeft); + CGEventPost(kCGHIDEventTap, ev); + CFRelease(ev); +#else + CGSetLocalEventsSuppressionInterval(0); + CGWarpMouseCursorPosition(c); +#endif +} + + +void CIrrDeviceMacOSX::setCursorVisible(bool visible) +{ + if (visible) + CGDisplayShowCursor(CGMainDisplayID()); + else + CGDisplayHideCursor(CGMainDisplayID()); +} + + +void CIrrDeviceMacOSX::setWindow(NSWindow* window) +{ + Window = window; +} + + +void CIrrDeviceMacOSX::initKeycodes() +{ + KeyCodes[kVK_UpArrow] = irr::KEY_UP; + KeyCodes[kVK_DownArrow] = irr::KEY_DOWN; + KeyCodes[kVK_LeftArrow] = irr::KEY_LEFT; + KeyCodes[kVK_RightArrow] = irr::KEY_RIGHT; + KeyCodes[kVK_F1] = irr::KEY_F1; + KeyCodes[kVK_F2] = irr::KEY_F2; + KeyCodes[kVK_F3] = irr::KEY_F3; + KeyCodes[kVK_F4] = irr::KEY_F4; + KeyCodes[kVK_F5] = irr::KEY_F5; + KeyCodes[kVK_F6] = irr::KEY_F6; + KeyCodes[kVK_F7] = irr::KEY_F7; + KeyCodes[kVK_F8] = irr::KEY_F8; + KeyCodes[kVK_F9] = irr::KEY_F9; + KeyCodes[kVK_F10] = irr::KEY_F10; + KeyCodes[kVK_F11] = irr::KEY_F11; + KeyCodes[kVK_F12] = irr::KEY_F12; + KeyCodes[kVK_F13] = irr::KEY_F13; + KeyCodes[kVK_F14] = irr::KEY_F14; + KeyCodes[kVK_F15] = irr::KEY_F15; + KeyCodes[kVK_F16] = irr::KEY_F16; + KeyCodes[kVK_F17] = irr::KEY_F17; + KeyCodes[kVK_F18] = irr::KEY_F18; + KeyCodes[kVK_F19] = irr::KEY_F19; + KeyCodes[kVK_F20] = irr::KEY_F20; + KeyCodes[kVK_Home] = irr::KEY_HOME; + KeyCodes[kVK_End] = irr::KEY_END; + KeyCodes[NSInsertFunctionKey] = irr::KEY_INSERT; + KeyCodes[kVK_ForwardDelete] = irr::KEY_DELETE; + KeyCodes[kVK_Help] = irr::KEY_HELP; + KeyCodes[NSSelectFunctionKey] = irr::KEY_SELECT; + KeyCodes[NSPrintFunctionKey] = irr::KEY_PRINT; + KeyCodes[NSExecuteFunctionKey] = irr::KEY_EXECUT; + KeyCodes[NSPrintScreenFunctionKey] = irr::KEY_SNAPSHOT; + KeyCodes[NSPauseFunctionKey] = irr::KEY_PAUSE; + KeyCodes[NSScrollLockFunctionKey] = irr::KEY_SCROLL; + KeyCodes[kVK_Delete] = irr::KEY_BACK; + KeyCodes[kVK_Tab] = irr::KEY_TAB; + KeyCodes[kVK_Return] = irr::KEY_RETURN; + KeyCodes[kVK_Escape] = irr::KEY_ESCAPE; + KeyCodes[kVK_Control] = irr::KEY_CONTROL; + KeyCodes[kVK_RightControl] = irr::KEY_RCONTROL; + KeyCodes[kVK_Command] = irr::KEY_MENU; + KeyCodes[kVK_Shift] = irr::KEY_SHIFT; + KeyCodes[kVK_RightShift] = irr::KEY_RSHIFT; + KeyCodes[kVK_Space] = irr::KEY_SPACE; + + KeyCodes[kVK_ANSI_A] = irr::KEY_KEY_A; + KeyCodes[kVK_ANSI_B] = irr::KEY_KEY_B; + KeyCodes[kVK_ANSI_C] = irr::KEY_KEY_C; + KeyCodes[kVK_ANSI_D] = irr::KEY_KEY_D; + KeyCodes[kVK_ANSI_E] = irr::KEY_KEY_E; + KeyCodes[kVK_ANSI_F] = irr::KEY_KEY_F; + KeyCodes[kVK_ANSI_G] = irr::KEY_KEY_G; + KeyCodes[kVK_ANSI_H] = irr::KEY_KEY_H; + KeyCodes[kVK_ANSI_I] = irr::KEY_KEY_I; + KeyCodes[kVK_ANSI_J] = irr::KEY_KEY_J; + KeyCodes[kVK_ANSI_K] = irr::KEY_KEY_K; + KeyCodes[kVK_ANSI_L] = irr::KEY_KEY_L; + KeyCodes[kVK_ANSI_M] = irr::KEY_KEY_M; + KeyCodes[kVK_ANSI_N] = irr::KEY_KEY_N; + KeyCodes[kVK_ANSI_O] = irr::KEY_KEY_O; + KeyCodes[kVK_ANSI_P] = irr::KEY_KEY_P; + KeyCodes[kVK_ANSI_Q] = irr::KEY_KEY_Q; + KeyCodes[kVK_ANSI_R] = irr::KEY_KEY_R; + KeyCodes[kVK_ANSI_S] = irr::KEY_KEY_S; + KeyCodes[kVK_ANSI_T] = irr::KEY_KEY_T; + KeyCodes[kVK_ANSI_U] = irr::KEY_KEY_U; + KeyCodes[kVK_ANSI_V] = irr::KEY_KEY_V; + KeyCodes[kVK_ANSI_W] = irr::KEY_KEY_W; + KeyCodes[kVK_ANSI_X] = irr::KEY_KEY_X; + KeyCodes[kVK_ANSI_X] = irr::KEY_KEY_X; + KeyCodes[kVK_ANSI_Y] = irr::KEY_KEY_Y; + KeyCodes[kVK_ANSI_Z] = irr::KEY_KEY_Z; + + KeyCodes[kVK_ANSI_0] = irr::KEY_KEY_0; + KeyCodes[kVK_ANSI_1] = irr::KEY_KEY_1; + KeyCodes[kVK_ANSI_2] = irr::KEY_KEY_2; + KeyCodes[kVK_ANSI_3] = irr::KEY_KEY_3; + KeyCodes[kVK_ANSI_4] = irr::KEY_KEY_4; + KeyCodes[kVK_ANSI_5] = irr::KEY_KEY_5; + KeyCodes[kVK_ANSI_6] = irr::KEY_KEY_6; + KeyCodes[kVK_ANSI_7] = irr::KEY_KEY_7; + KeyCodes[kVK_ANSI_8] = irr::KEY_KEY_8; + KeyCodes[kVK_ANSI_9] = irr::KEY_KEY_9; + + KeyCodes[kVK_ANSI_Slash] = irr::KEY_DIVIDE; + KeyCodes[kVK_ANSI_Comma] = irr::KEY_COMMA; + KeyCodes[kVK_ANSI_Period] = irr::KEY_PERIOD; + KeyCodes[kVK_PageUp] = irr::KEY_PRIOR; + KeyCodes[kVK_PageDown] = irr::KEY_NEXT; + + KeyCodes[kVK_ANSI_Keypad0] = irr::KEY_NUMPAD0; + KeyCodes[kVK_ANSI_Keypad1] = irr::KEY_NUMPAD1; + KeyCodes[kVK_ANSI_Keypad2] = irr::KEY_NUMPAD2; + KeyCodes[kVK_ANSI_Keypad3] = irr::KEY_NUMPAD3; + KeyCodes[kVK_ANSI_Keypad4] = irr::KEY_NUMPAD4; + KeyCodes[kVK_ANSI_Keypad5] = irr::KEY_NUMPAD5; + KeyCodes[kVK_ANSI_Keypad6] = irr::KEY_NUMPAD6; + KeyCodes[kVK_ANSI_Keypad7] = irr::KEY_NUMPAD7; + KeyCodes[kVK_ANSI_Keypad8] = irr::KEY_NUMPAD8; + KeyCodes[kVK_ANSI_Keypad9] = irr::KEY_NUMPAD9; + + KeyCodes[kVK_ANSI_KeypadDecimal] = irr::KEY_DECIMAL; + KeyCodes[kVK_ANSI_KeypadMultiply] = irr::KEY_MULTIPLY; + KeyCodes[kVK_ANSI_KeypadPlus] = irr::KEY_PLUS; + KeyCodes[kVK_ANSI_KeypadClear] = irr::KEY_OEM_CLEAR; + KeyCodes[kVK_ANSI_KeypadDivide] = irr::KEY_DIVIDE; + KeyCodes[kVK_ANSI_KeypadEnter] = irr::KEY_RETURN; + KeyCodes[kVK_ANSI_KeypadMinus] = irr::KEY_SUBTRACT; + + KeyCodes[kVK_ANSI_LeftBracket] = irr::KEY_OEM_4; + KeyCodes[kVK_ANSI_Backslash] = irr::KEY_OEM_5; + KeyCodes[kVK_ANSI_RightBracket] = irr::KEY_OEM_6; +} + + +//! Sets if the window should be resizable in windowed mode. +void CIrrDeviceMacOSX::setResizable(bool resize) +{ + IsResizable = resize; +#if 0 + if (resize) + [Window setStyleMask:NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask]; + else + [Window setStyleMask:NSTitledWindowMask|NSClosableWindowMask]; +#endif +} + + +bool CIrrDeviceMacOSX::isResizable() const +{ + return IsResizable; +} + + +void CIrrDeviceMacOSX::minimizeWindow() +{ + if (Window != NULL) + [Window miniaturize:[NSApp self]]; +} + + +//! Maximizes the window if possible. +void CIrrDeviceMacOSX::maximizeWindow() +{ + // todo: implement +} + + +//! get the window to normal size if possible. +void CIrrDeviceMacOSX::restoreWindow() +{ + [Window deminiaturize:[NSApp self]]; +} + +//! Get the position of this window on screen +core::position2di CIrrDeviceMacOSX::getWindowPosition() +{ + NSRect rect = [Window frame]; + int screenHeight = [[[NSScreen screens] objectAtIndex:0] frame].size.height; + return core::position2di(rect.origin.x, screenHeight - rect.origin.y - rect.size.height); +} + + + +bool CIrrDeviceMacOSX::present(video::IImage* surface, void* windowId, core::rect* src ) +{ + // todo: implement window ID and src rectangle + + if (!surface) + return false; + + if (SoftwareRendererType > 0) + { + const u32 colorSamples=3; + // do we need to change the size? + const bool updateSize = !SoftwareDriverTarget || + s32([SoftwareDriverTarget size].width) != surface->getDimension().Width || + s32([SoftwareDriverTarget size].height) != surface->getDimension().Height; + + NSRect areaRect = NSMakeRect(0.0, 0.0, surface->getDimension().Width, surface->getDimension().Height); + const u32 destPitch = (colorSamples * areaRect.size.width); + + // create / update the target + if (updateSize) + { + [SoftwareDriverTarget release]; + // allocate target for IImage + SoftwareDriverTarget = [[NSBitmapImageRep alloc] + initWithBitmapDataPlanes: nil + pixelsWide: areaRect.size.width + pixelsHigh: areaRect.size.height + bitsPerSample: 8 + samplesPerPixel: colorSamples + hasAlpha: NO + isPlanar: NO + colorSpaceName: NSCalibratedRGBColorSpace + bytesPerRow: destPitch + bitsPerPixel: 8*colorSamples]; + } + + if (SoftwareDriverTarget==nil) + return false; + + // get pointer to image data + unsigned char* imgData = (unsigned char*)surface->getData(); + + u8* srcdata = reinterpret_cast(imgData); + u8* destData = reinterpret_cast([SoftwareDriverTarget bitmapData]); + const u32 srcheight = core::min_(surface->getDimension().Height, (u32)areaRect.size.height); + const u32 srcPitch = surface->getPitch(); + const u32 minWidth = core::min_(surface->getDimension().Width, (u32)areaRect.size.width); + for (u32 y=0; y!=srcheight; ++y) + { + if(SoftwareRendererType == 2) + { + if (surface->getColorFormat() == video::ECF_A8R8G8B8) + video::CColorConverter::convert_A8R8G8B8toB8G8R8(srcdata, minWidth, destData); + else if (surface->getColorFormat() == video::ECF_A1R5G5B5) + video::CColorConverter::convert_A1R5G5B5toB8G8R8(srcdata, minWidth, destData); + else + video::CColorConverter::convert_viaFormat(srcdata, surface->getColorFormat(), minWidth, destData, video::ECF_R8G8B8); + } + else + { + if (surface->getColorFormat() == video::ECF_A8R8G8B8) + video::CColorConverter::convert_A8R8G8B8toR8G8B8(srcdata, minWidth, destData); + else if (surface->getColorFormat() == video::ECF_A1R5G5B5) + video::CColorConverter::convert_A1R5G5B5toR8G8B8(srcdata, minWidth, destData); + else + video::CColorConverter::convert_viaFormat(srcdata, surface->getColorFormat(), minWidth, destData, video::ECF_R8G8B8); + } + + srcdata += srcPitch; + destData += destPitch; + } + + // todo: draw properly into a sub-view + [SoftwareDriverTarget draw]; + } + + return false; +} + + +#if defined (_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) +static void joystickRemovalCallback(void * target, + IOReturn result, void * refcon, void * sender) +{ + JoystickInfo *joy = (JoystickInfo *) refcon; + joy->removed = 1; +} +#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ + + +bool CIrrDeviceMacOSX::activateJoysticks(core::array & joystickInfo) +{ +#if defined (_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) + ActiveJoysticks.clear(); + joystickInfo.clear(); + + io_object_t hidObject = 0; + io_iterator_t hidIterator = 0; + IOReturn result = kIOReturnSuccess; + mach_port_t masterPort = 0; + CFMutableDictionaryRef hidDictionaryRef = NULL; + + result = IOMasterPort (bootstrap_port, &masterPort); + if (kIOReturnSuccess != result) + { + os::Printer::log("initialiseJoysticks IOMasterPort failed", ELL_ERROR); + return false; + } + + hidDictionaryRef = IOServiceMatching (kIOHIDDeviceKey); + if (!hidDictionaryRef) + { + os::Printer::log("initialiseJoysticks IOServiceMatching failed", ELL_ERROR); + return false; + } + result = IOServiceGetMatchingServices (masterPort, hidDictionaryRef, &hidIterator); + + if (kIOReturnSuccess != result) + { + os::Printer::log("initialiseJoysticks IOServiceGetMatchingServices failed", ELL_ERROR); + return false; + } + + //no joysticks just return + if (!hidIterator) + return false; + + u32 jindex = 0u; + while ((hidObject = IOIteratorNext (hidIterator))) + { + JoystickInfo info; + + // get dictionary for HID properties + CFMutableDictionaryRef hidProperties = 0; + + kern_return_t kern_result = IORegistryEntryCreateCFProperties (hidObject, &hidProperties, kCFAllocatorDefault, kNilOptions); + if ((kern_result == KERN_SUCCESS) && hidProperties) + { + HRESULT plugInResult = S_OK; + SInt32 score = 0; + IOCFPlugInInterface ** ppPlugInInterface = NULL; + result = IOCreatePlugInInterfaceForService (hidObject, kIOHIDDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, &ppPlugInInterface, &score); + if (kIOReturnSuccess == result) + { + plugInResult = (*ppPlugInInterface)->QueryInterface (ppPlugInInterface, + CFUUIDGetUUIDBytes (kIOHIDDeviceInterfaceID), (void **) &(info.interface)); + if (plugInResult != S_OK) + os::Printer::log("initialiseJoysticks query HID class device interface failed", ELL_ERROR); + (*ppPlugInInterface)->Release(ppPlugInInterface); + } + else + continue; + + if (info.interface != NULL) + { + result = (*(info.interface))->open (info.interface, 0); + if (result == kIOReturnSuccess) + { + (*(info.interface))->setRemovalCallback (info.interface, joystickRemovalCallback, &info, &info); + getJoystickDeviceInfo(hidObject, hidProperties, &info); + + // get elements + CFTypeRef refElementTop = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDElementKey)); + if (refElementTop) + { + CFTypeID type = CFGetTypeID (refElementTop); + if (type == CFArrayGetTypeID()) + { + CFRange range = {0, CFArrayGetCount ((CFArrayRef)refElementTop)}; + info.numActiveJoysticks = ActiveJoysticks.size(); + CFArrayApplyFunction ((CFArrayRef)refElementTop, range, getJoystickComponentArrayHandler, &info); + } + } + } + else + { + CFRelease (hidProperties); + os::Printer::log("initialiseJoysticks Open interface failed", ELL_ERROR); + continue; + } + + CFRelease (hidProperties); + + result = IOObjectRelease (hidObject); + + if ( (info.usagePage != kHIDPage_GenericDesktop) || + ((info.usage != kHIDUsage_GD_Joystick && + info.usage != kHIDUsage_GD_GamePad && + info.usage != kHIDUsage_GD_MultiAxisController)) ) + { + closeJoystickDevice (&info); + continue; + } + + for (u32 i = 0; i < 6; ++i) + info.persistentData.JoystickEvent.Axis[i] = 0; + + ActiveJoysticks.push_back(info); + + SJoystickInfo returnInfo; + returnInfo.Joystick = jindex; + returnInfo.Axes = info.axes; + //returnInfo.Hats = info.hats; + returnInfo.Buttons = info.buttons; + returnInfo.Name = info.joystickName; + returnInfo.PovHat = SJoystickInfo::POV_HAT_UNKNOWN; + ++ jindex; + + //if (info.hatComp.size()) + // returnInfo.PovHat = SJoystickInfo::POV_HAT_PRESENT; + //else + // returnInfo.PovHat = SJoystickInfo::POV_HAT_ABSENT; + + joystickInfo.push_back(returnInfo); + } + + } + else + { + continue; + } + } + result = IOObjectRelease (hidIterator); + + return true; +#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ + + return false; +} + +void CIrrDeviceMacOSX::pollJoysticks() +{ +#if defined (_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) + if(0 == ActiveJoysticks.size()) + return; + + u32 joystick; + for (joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) + { + if (ActiveJoysticks[joystick].removed) + continue; + + bool found = false; + ActiveJoysticks[joystick].persistentData.JoystickEvent.Joystick = joystick; + + if (ActiveJoysticks[joystick].interface) + { + for (u32 n = 0; n < ActiveJoysticks[joystick].axisComp.size(); n++) + { + IOReturn result = kIOReturnSuccess; + IOHIDEventStruct hidEvent; + hidEvent.value = 0; + result = (*(ActiveJoysticks[joystick].interface))->getElementValue(ActiveJoysticks[joystick].interface, ActiveJoysticks[joystick].axisComp[n].cookie, &hidEvent); + if (kIOReturnSuccess == result) + { + const f32 min = -32768.0f; + const f32 max = 32767.0f; + const f32 deviceScale = max - min; + const f32 readScale = (f32)ActiveJoysticks[joystick].axisComp[n].maxRead - (f32)ActiveJoysticks[joystick].axisComp[n].minRead; + + if (hidEvent.value < ActiveJoysticks[joystick].axisComp[n].minRead) + ActiveJoysticks[joystick].axisComp[n].minRead = hidEvent.value; + if (hidEvent.value > ActiveJoysticks[joystick].axisComp[n].maxRead) + ActiveJoysticks[joystick].axisComp[n].maxRead = hidEvent.value; + + if (readScale != 0.0f) + hidEvent.value = (int)(((f32)((f32)hidEvent.value - (f32)ActiveJoysticks[joystick].axisComp[n].minRead) * deviceScale / readScale) + min); + + if (ActiveJoysticks[joystick].persistentData.JoystickEvent.Axis[n] != (s16)hidEvent.value) + found = true; + ActiveJoysticks[joystick].persistentData.JoystickEvent.Axis[n] = (s16)hidEvent.value; + } + }//axis check + + for (u32 n = 0; n < ActiveJoysticks[joystick].buttonComp.size(); n++) + { + IOReturn result = kIOReturnSuccess; + IOHIDEventStruct hidEvent; + hidEvent.value = 0; + result = (*(ActiveJoysticks[joystick].interface))->getElementValue(ActiveJoysticks[joystick].interface, ActiveJoysticks[joystick].buttonComp[n].cookie, &hidEvent); + if (kIOReturnSuccess == result) + { + if (hidEvent.value && !((ActiveJoysticks[joystick].persistentData.JoystickEvent.ButtonStates & (1 << n)) ? true : false) ) + found = true; + else if (!hidEvent.value && ((ActiveJoysticks[joystick].persistentData.JoystickEvent.ButtonStates & (1 << n)) ? true : false)) + found = true; + + if (hidEvent.value) + ActiveJoysticks[joystick].persistentData.JoystickEvent.ButtonStates |= (1 << n); + else + ActiveJoysticks[joystick].persistentData.JoystickEvent.ButtonStates &= ~(1 << n); + } + }//button check + //still ToDo..will be done soon :) +/* + for (u32 n = 0; n < ActiveJoysticks[joystick].hatComp.size(); n++) + { + IOReturn result = kIOReturnSuccess; + IOHIDEventStruct hidEvent; + hidEvent.value = 0; + result = (*(ActiveJoysticks[joystick].interface))->getElementValue(ActiveJoysticks[joystick].interface, ActiveJoysticks[joystick].hatComp[n].cookie, &hidEvent); + if (kIOReturnSuccess == result) + { + if (ActiveJoysticks[joystick].persistentData.JoystickEvent.POV != hidEvent.value) + found = true; + ActiveJoysticks[joystick].persistentData.JoystickEvent.POV = hidEvent.value; + } + }//hat check +*/ + } + + if (found) + postEventFromUser(ActiveJoysticks[joystick].persistentData); + } +#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ +} + +video::IVideoModeList* CIrrDeviceMacOSX::getVideoModeList() +{ + if (!VideoModeList->getVideoModeCount()) + { + CGDirectDisplayID display; + display = CGMainDisplayID(); + +#ifdef __MAC_10_6 + CFArrayRef Modes = CGDisplayCopyAllDisplayModes(display, NULL); + + for(int i = 0; i < CFArrayGetCount(Modes); ++i) + { + CGDisplayModeRef CurrentMode = (CGDisplayModeRef)CFArrayGetValueAtIndex(Modes, i); + + u8 Depth = 0; + + CFStringRef pixEnc = CGDisplayModeCopyPixelEncoding(CurrentMode); + + if(CFStringCompare(pixEnc, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) + Depth = 32; + else + if(CFStringCompare(pixEnc, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) + Depth = 16; + else + if(CFStringCompare(pixEnc, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) + Depth = 8; + + if(Depth) + { + unsigned int Width = CGDisplayModeGetWidth(CurrentMode); + unsigned int Height = CGDisplayModeGetHeight(CurrentMode); + + VideoModeList->addMode(core::dimension2d(Width, Height), Depth); + } + } +#else + CFArrayRef availableModes = CGDisplayAvailableModes(display); + unsigned int numberOfAvailableModes = CFArrayGetCount(availableModes); + for (u32 i= 0; i(width, height), + bitsPerPixel); + } +#endif + } + return VideoModeList; +} + +} // end namespace + +#endif // _IRR_COMPILE_WITH_OSX_DEVICE_ + diff --git a/source/Irrlicht/CIrrDeviceSDL.cpp b/source/Irrlicht/CIrrDeviceSDL.cpp new file mode 100644 index 00000000..cad7dffb --- /dev/null +++ b/source/Irrlicht/CIrrDeviceSDL.cpp @@ -0,0 +1,1332 @@ +// Copyright (C) 2002-2012 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" + +#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ + +#include "CIrrDeviceSDL.h" +#include "IEventReceiver.h" +#include "irrList.h" +#include "os.h" +#include "CTimer.h" +#include "irrString.h" +#include "Keycodes.h" +#include "COSOperator.h" +#include +#include +#include "SIrrCreationParameters.h" +#include +#include + +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ +#ifdef _IRR_COMPILE_WITH_OGLES2_ +#include "CEGLManager.h" +#endif +#include +#endif + +#ifdef _MSC_VER +#pragma comment(lib, "SDL.lib") +#endif // _MSC_VER + +static int SDLDeviceInstances = 0; + +namespace irr +{ + namespace video + { + #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ + IVideoDriver* createDirectX9Driver(const irr::SIrrlichtCreationParameters& params, + io::IFileSystem* io, HWND window); + #endif + + #ifdef _IRR_COMPILE_WITH_OPENGL_ + IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io, CIrrDeviceSDL* device); + #endif + + #if defined(_IRR_COMPILE_WITH_OGLES2_) && defined(_IRR_EMSCRIPTEN_PLATFORM_) + IVideoDriver* createOGLES2Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager); + #endif + + #if defined(_IRR_COMPILE_WITH_WEBGL1_) && defined(_IRR_EMSCRIPTEN_PLATFORM_) + IVideoDriver* createWebGL1Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager); + #endif + } // end namespace video + +} // end namespace irr + + +namespace irr +{ +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ +EM_BOOL CIrrDeviceSDL::MouseUpDownCallback(int eventType, const EmscriptenMouseEvent * event, void* userData) +{ + // We need this callback so far only because otherwise "emscripten_request_pointerlock" calls will + // fail as their request are infinitely deferred. + // Not exactly certain why, maybe SDL does catch those mouse-events otherwise and not pass them on. + return EM_FALSE; +} + +EM_BOOL CIrrDeviceSDL::MouseEnterCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) +{ + CIrrDeviceSDL * This = static_cast(userData); + + SEvent irrevent; + + irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT; + irrevent.MouseInput.Event = irr::EMIE_MOUSE_ENTER_CANVAS; + This->MouseX = irrevent.MouseInput.X = mouseEvent->canvasX; + This->MouseY = irrevent.MouseInput.Y = mouseEvent->canvasY; + This->MouseXRel = mouseEvent->movementX; // should be 0 I guess? Or can it enter while pointer is locked()? + This->MouseYRel = mouseEvent->movementY; + irrevent.MouseInput.ButtonStates = This->MouseButtonStates; // TODO: not correct, but couldn't figure out the bitset of mouseEvent->buttons yet. + irrevent.MouseInput.Shift = mouseEvent->shiftKey; + irrevent.MouseInput.Control = mouseEvent->ctrlKey; + + This->postEventFromUser(irrevent); + + return EM_FALSE; +} + +EM_BOOL CIrrDeviceSDL::MouseLeaveCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) +{ + CIrrDeviceSDL * This = static_cast(userData); + + SEvent irrevent; + + irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT; + irrevent.MouseInput.Event = irr::EMIE_MOUSE_LEAVE_CANVAS; + This->MouseX = irrevent.MouseInput.X = mouseEvent->canvasX; + This->MouseY = irrevent.MouseInput.Y = mouseEvent->canvasY; + This->MouseXRel = mouseEvent->movementX; // should be 0 I guess? Or can it enter while pointer is locked()? + This->MouseYRel = mouseEvent->movementY; + irrevent.MouseInput.ButtonStates = This->MouseButtonStates; // TODO: not correct, but couldn't figure out the bitset of mouseEvent->buttons yet. + irrevent.MouseInput.Shift = mouseEvent->shiftKey; + irrevent.MouseInput.Control = mouseEvent->ctrlKey; + + This->postEventFromUser(irrevent); + + return EM_FALSE; +} + +bool CIrrDeviceSDL::isNoUnicodeKey(EKEY_CODE key) const +{ + switch ( key ) + { + // keys which should not be mapped to a Unicode char + case KEY_UNKNOWN: + case KEY_SHIFT: + case KEY_CONTROL: + case KEY_MENU: + case KEY_PAUSE: + case KEY_CAPITAL: + case KEY_ESCAPE: + case KEY_PRIOR: + case KEY_NEXT: + case KEY_END: + case KEY_HOME: + case KEY_LEFT: + case KEY_UP: + case KEY_RIGHT: + case KEY_DOWN: + case KEY_PRINT: + case KEY_SNAPSHOT: + case KEY_INSERT: + case KEY_DELETE: + case KEY_HELP: + case KEY_LWIN: + case KEY_RWIN: + case KEY_APPS: + case KEY_SLEEP: + case KEY_F1: + case KEY_F2: + case KEY_F3: + case KEY_F4: + case KEY_F5: + case KEY_F6: + case KEY_F7: + case KEY_F8: + case KEY_F9: + case KEY_F10: + case KEY_F11: + case KEY_F12: + case KEY_F13: + case KEY_F14: + case KEY_F15: + case KEY_F16: + case KEY_F17: + case KEY_F18: + case KEY_F19: + case KEY_F20: + case KEY_F21: + case KEY_F22: + case KEY_F23: + case KEY_F24: + case KEY_NUMLOCK: + case KEY_SCROLL: + case KEY_LSHIFT: + case KEY_RSHIFT: + case KEY_LCONTROL: + case KEY_RCONTROL: + case KEY_LMENU: + case KEY_RMENU: + return true; + + default: + return false; + } +} +#endif + +//! constructor +CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters& param) + : CIrrDeviceStub(param), + Screen((SDL_Surface*)param.WindowId), SDL_Flags(SDL_ANYFORMAT), + MouseX(0), MouseY(0), MouseXRel(0), MouseYRel(0), MouseButtonStates(0), + Width(param.WindowSize.Width), Height(param.WindowSize.Height), + Resizable(param.WindowResizable), WindowMinimized(false) +{ + #ifdef _DEBUG + setDebugName("CIrrDeviceSDL"); + #endif + + if ( ++SDLDeviceInstances == 1 ) + { + // Initialize SDL... Timer for sleep, video for the obvious, and + // noparachute prevents SDL from catching fatal errors. + if (SDL_Init( SDL_INIT_TIMER|SDL_INIT_VIDEO| +#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) + SDL_INIT_JOYSTICK| +#endif + SDL_INIT_NOPARACHUTE ) < 0) + { + os::Printer::log( "Unable to initialize SDL!", SDL_GetError()); + Close = true; + } + else + { + os::Printer::log("SDL initialized", ELL_INFORMATION); + } + +#if defined(_IRR_WINDOWS_) + SDL_putenv("SDL_VIDEODRIVER=directx"); +#elif defined(_IRR_OSX_PLATFORM_) + SDL_putenv("SDL_VIDEODRIVER=Quartz"); +#elif !defined(_IRR_EMSCRIPTEN_PLATFORM_) + SDL_putenv("SDL_VIDEODRIVER=x11"); +#endif + } + +// SDL_putenv("SDL_WINDOWID="); + + SDL_VERSION(&Info.version); + +#ifndef _IRR_EMSCRIPTEN_PLATFORM_ + SDL_GetWMInfo(&Info); +#endif //_IRR_EMSCRIPTEN_PLATFORM_ + core::stringc sdlversion = "SDL Version "; + sdlversion += Info.version.major; + sdlversion += "."; + sdlversion += Info.version.minor; + sdlversion += "."; + sdlversion += Info.version.patch; + + Operator = new COSOperator(sdlversion); + if ( SDLDeviceInstances == 1 ) + { + os::Printer::log(sdlversion.c_str(), ELL_INFORMATION); + } + + // create keymap + createKeyMap(); + // enable key to character translation + SDL_EnableUNICODE(1); + + (void)SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); + + if ( CreationParams.Fullscreen ) + SDL_Flags |= SDL_FULLSCREEN; + else if ( Resizable ) + SDL_Flags |= SDL_RESIZABLE; + if (CreationParams.DriverType == video::EDT_OPENGL) + SDL_Flags |= SDL_OPENGL; + else if (CreationParams.Doublebuffer) + SDL_Flags |= SDL_DOUBLEBUF; +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ + SDL_Flags |= SDL_OPENGL; +#endif //_IRR_EMSCRIPTEN_PLATFORM_ + + // create window + if (CreationParams.DriverType != video::EDT_NULL) + { + // create the window, only if we do not use the null device + createWindow(); + } + + // create cursor control + CursorControl = new CCursorControl(this); + + // create driver + createDriver(); + + if (VideoDriver) + createGUIAndScene(); +} + + +//! destructor +CIrrDeviceSDL::~CIrrDeviceSDL() +{ + if ( --SDLDeviceInstances == 0 ) + { +#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) + const u32 numJoysticks = Joysticks.size(); + for (u32 i=0; i1) + { + SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 1 ); + SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, CreationParams.AntiAlias ); + } + else + { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); + } + + Screen = SDL_SetVideoMode( 0, 0, 32, SDL_Flags); // 0,0 will use the canvas size + + logAttributes(); + + // "#canvas" is for the opengl context + emscripten_set_mousedown_callback("#canvas", (void*)this, true, MouseUpDownCallback); + emscripten_set_mouseup_callback("#canvas", (void*)this, true, MouseUpDownCallback); + emscripten_set_mouseenter_callback("#canvas", (void*)this, false, MouseEnterCallback); + emscripten_set_mouseleave_callback("#canvas", (void*)this, false, MouseLeaveCallback); + + return true; +#else // !_IRR_EMSCRIPTEN_PLATFORM_ + if ( Close ) + return false; + + if (CreationParams.DriverType == video::EDT_OPENGL) + { + if (CreationParams.Bits==16) + { + SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 4 ); + SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 4 ); + SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 4 ); + SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, CreationParams.WithAlphaChannel?1:0 ); + } + else + { + SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 ); + SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 ); + SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 ); + SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, CreationParams.WithAlphaChannel?8:0 ); + } + SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, CreationParams.ZBufferBits); + if (CreationParams.Doublebuffer) + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); + SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, CreationParams.Stencilbuffer ? 8 : 0); + 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!" ); + } + } + } + else if ( !Screen ) + Screen = SDL_SetVideoMode( Width, Height, CreationParams.Bits, SDL_Flags ); + + if ( !Screen && CreationParams.Doublebuffer) + { + // Try single buffer + if (CreationParams.DriverType == video::EDT_OPENGL) + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); + SDL_Flags &= ~SDL_DOUBLEBUF; + Screen = SDL_SetVideoMode( Width, Height, CreationParams.Bits, SDL_Flags ); + } + if ( !Screen ) + { + os::Printer::log( "Could not initialize display!" ); + return false; + } + + return true; +#endif // !_IRR_EMSCRIPTEN_PLATFORM_ +} + + +//! create the driver +void CIrrDeviceSDL::createDriver() +{ + switch(CreationParams.DriverType) + { + case video::DEPRECATED_EDT_DIRECT3D8_NO_LONGER_EXISTS: + os::Printer::log("DIRECT3D8 Driver is no longer supported in Irrlicht. Try another one.", ELL_ERROR); + break; + + case video::EDT_DIRECT3D9: + #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ + os::Printer::log("SDL device does not support DIRECT3D9 driver. Try another one.", ELL_ERROR); + #else + os::Printer::log("DIRECT3D9 Driver was not compiled into this dll. Try another one.", ELL_ERROR); + #endif // _IRR_COMPILE_WITH_DIRECT3D_9_ + + break; + + case video::EDT_SOFTWARE: + #ifdef _IRR_COMPILE_WITH_SOFTWARE_ + VideoDriver = video::createSoftwareDriver(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this); + #else + os::Printer::log("No Software driver support compiled in.", ELL_ERROR); + #endif + break; + + case video::EDT_BURNINGSVIDEO: + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + VideoDriver = video::createBurningVideoDriver(CreationParams, FileSystem, this); + #else + os::Printer::log("Burning's video driver was not compiled in.", ELL_ERROR); + #endif + break; + + case video::EDT_OPENGL: + #ifdef _IRR_COMPILE_WITH_OPENGL_ + VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, this); + #else + os::Printer::log("No OpenGL support compiled in.", ELL_ERROR); + #endif + break; + + case video::EDT_OGLES2: +#if defined(_IRR_COMPILE_WITH_OGLES2_) && defined(_IRR_EMSCRIPTEN_PLATFORM_) + { + video::SExposedVideoData data; + + ContextManager = new video::CEGLManager(); + ContextManager->initialize(CreationParams, data); + + VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager); + } +#else + os::Printer::log("No OpenGL-ES2 support compiled in.", ELL_ERROR); +#endif + break; + + case video::EDT_WEBGL1: +#if defined(_IRR_COMPILE_WITH_WEBGL1_) && defined(_IRR_EMSCRIPTEN_PLATFORM_) + { + video::SExposedVideoData data; + + ContextManager = new video::CEGLManager(); + ContextManager->initialize(CreationParams, data); + + VideoDriver = video::createWebGL1Driver(CreationParams, FileSystem, ContextManager); + } +#else + os::Printer::log("No WebGL1 support compiled in.", ELL_ERROR); +#endif + break; + + case video::EDT_NULL: + VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize); + break; + + default: + os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR); + break; + } + + // In case we got the size from the canvas + if ( VideoDriver && CreationParams.WindowSize.Width == 0 && CreationParams.WindowSize.Height == 0 && Width > 0 && Height > 0 ) + { +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ + Screen = SDL_SetVideoMode( Width, Height, 32, SDL_Flags ); +#else //_IRR_EMSCRIPTEN_PLATFORM_ + Screen = SDL_SetVideoMode( Width, Height, 0, SDL_Flags ); +#endif //_IRR_EMSCRIPTEN_PLATFOR + VideoDriver->OnResize(core::dimension2d(Width, Height)); + } +} + + +//! runs the device. Returns false if device wants to be deleted +bool CIrrDeviceSDL::run() +{ + os::Timer::tick(); + + SEvent irrevent; + SDL_Event SDL_event; + + while ( !Close && SDL_PollEvent( &SDL_event ) ) + { + // os::Printer::log("event: ", core::stringc((int)SDL_event.type).c_str(), ELL_INFORMATION); // just for debugging + + switch ( SDL_event.type ) + { + case SDL_MOUSEMOTION: + irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT; + irrevent.MouseInput.Event = irr::EMIE_MOUSE_MOVED; + MouseX = irrevent.MouseInput.X = SDL_event.motion.x; + MouseY = irrevent.MouseInput.Y = SDL_event.motion.y; + MouseXRel = SDL_event.motion.xrel; + MouseYRel = SDL_event.motion.yrel; + irrevent.MouseInput.ButtonStates = MouseButtonStates; + + postEventFromUser(irrevent); + break; + + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + + irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT; + irrevent.MouseInput.X = SDL_event.button.x; + irrevent.MouseInput.Y = SDL_event.button.y; + + irrevent.MouseInput.Event = irr::EMIE_MOUSE_MOVED; + + +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ + // Handle mouselocking in emscripten in Windowed mode. + // In fullscreen SDL will handle it. + // The behavior we want windowed is - when the canvas was clicked then + // we will lock the mouse-pointer if it should be invisible. + // For security reasons this will be delayed until the next mouse-up event. + // We do not pass on this event as we don't want the activation click to do anything. + if ( SDL_event.type == SDL_MOUSEBUTTONDOWN && !isFullscreen() ) + { + EmscriptenPointerlockChangeEvent pointerlockStatus; // let's hope that test is not expensive ... + if ( emscripten_get_pointerlock_status(&pointerlockStatus) == EMSCRIPTEN_RESULT_SUCCESS ) + { + if ( CursorControl->isVisible() && pointerlockStatus.isActive ) + { + emscripten_exit_pointerlock(); + return !Close; + } + else if ( !CursorControl->isVisible() && !pointerlockStatus.isActive ) + { + emscripten_request_pointerlock(0, true); + return !Close; + } + } + } +#endif + + switch(SDL_event.button.button) + { + case SDL_BUTTON_LEFT: + if (SDL_event.type == SDL_MOUSEBUTTONDOWN) + { + irrevent.MouseInput.Event = irr::EMIE_LMOUSE_PRESSED_DOWN; + MouseButtonStates |= irr::EMBSM_LEFT; + } + else + { + irrevent.MouseInput.Event = irr::EMIE_LMOUSE_LEFT_UP; + MouseButtonStates &= !irr::EMBSM_LEFT; + } + break; + + case SDL_BUTTON_RIGHT: + if (SDL_event.type == SDL_MOUSEBUTTONDOWN) + { + irrevent.MouseInput.Event = irr::EMIE_RMOUSE_PRESSED_DOWN; + MouseButtonStates |= irr::EMBSM_RIGHT; + } + else + { + irrevent.MouseInput.Event = irr::EMIE_RMOUSE_LEFT_UP; + MouseButtonStates &= !irr::EMBSM_RIGHT; + } + break; + + case SDL_BUTTON_MIDDLE: + if (SDL_event.type == SDL_MOUSEBUTTONDOWN) + { + irrevent.MouseInput.Event = irr::EMIE_MMOUSE_PRESSED_DOWN; + MouseButtonStates |= irr::EMBSM_MIDDLE; + } + else + { + irrevent.MouseInput.Event = irr::EMIE_MMOUSE_LEFT_UP; + MouseButtonStates &= !irr::EMBSM_MIDDLE; + } + break; + + case SDL_BUTTON_WHEELUP: + irrevent.MouseInput.Event = irr::EMIE_MOUSE_WHEEL; + irrevent.MouseInput.Wheel = 1.0f; + break; + + case SDL_BUTTON_WHEELDOWN: + irrevent.MouseInput.Event = irr::EMIE_MOUSE_WHEEL; + irrevent.MouseInput.Wheel = -1.0f; + break; + } + + irrevent.MouseInput.ButtonStates = MouseButtonStates; + + if (irrevent.MouseInput.Event != irr::EMIE_MOUSE_MOVED) + { + postEventFromUser(irrevent); + + if ( irrevent.MouseInput.Event >= EMIE_LMOUSE_PRESSED_DOWN && irrevent.MouseInput.Event <= EMIE_MMOUSE_PRESSED_DOWN ) + { + u32 clicks = checkSuccessiveClicks(irrevent.MouseInput.X, irrevent.MouseInput.Y, irrevent.MouseInput.Event); + if ( clicks == 2 ) + { + irrevent.MouseInput.Event = (EMOUSE_INPUT_EVENT)(EMIE_LMOUSE_DOUBLE_CLICK + irrevent.MouseInput.Event-EMIE_LMOUSE_PRESSED_DOWN); + postEventFromUser(irrevent); + } + else if ( clicks == 3 ) + { + irrevent.MouseInput.Event = (EMOUSE_INPUT_EVENT)(EMIE_LMOUSE_TRIPLE_CLICK + irrevent.MouseInput.Event-EMIE_LMOUSE_PRESSED_DOWN); + postEventFromUser(irrevent); + } + } + } + break; + + case SDL_KEYDOWN: + case SDL_KEYUP: + { + SKeyMap mp; + mp.SDLKey = SDL_event.key.keysym.sym; + s32 idx = KeyMap.binary_search(mp); + + EKEY_CODE key; + if (idx == -1) + key = (EKEY_CODE)0; + else + key = (EKEY_CODE)KeyMap[idx].Win32Key; + +#ifdef _IRR_WINDOWS_API_ + // handle alt+f4 in Windows, because SDL seems not to + if ( (SDL_event.key.keysym.mod & KMOD_LALT) && key == KEY_F4) + { + Close = true; + break; + } +#endif + irrevent.EventType = irr::EET_KEY_INPUT_EVENT; + irrevent.KeyInput.Char = SDL_event.key.keysym.unicode; + irrevent.KeyInput.Key = key; +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ + // On emscripten SDL does not (yet?) return 0 for invalid keysym.unicode's. + // Instead it sets keysym.unicode to keysym.sym. + // But we need to distinguish control keys from characters here as that info + // is necessary in other places like the editbox. + if ( isNoUnicodeKey(key) ) + irrevent.KeyInput.Char = 0; +#endif + irrevent.KeyInput.PressedDown = (SDL_event.type == SDL_KEYDOWN); + irrevent.KeyInput.Shift = (SDL_event.key.keysym.mod & KMOD_SHIFT) != 0; + irrevent.KeyInput.Control = (SDL_event.key.keysym.mod & KMOD_CTRL ) != 0; + postEventFromUser(irrevent); + } + break; + + case SDL_QUIT: + Close = true; + break; + + case SDL_ACTIVEEVENT: + if (SDL_event.active.state == SDL_APPACTIVE) + WindowMinimized = (SDL_event.active.gain!=1); + break; + + case SDL_VIDEORESIZE: + if ((SDL_event.resize.w != (int)Width) || (SDL_event.resize.h != (int)Height)) + { + Width = SDL_event.resize.w; + Height = SDL_event.resize.h; +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ + Screen = SDL_SetVideoMode( 0, 0, 32, SDL_Flags ); // 0,0 will use the canvas size +#else //_IRR_EMSCRIPTEN_PLATFORM_ + Screen = SDL_SetVideoMode( Width, Height, 0, SDL_Flags ); +#endif //_IRR_EMSCRIPTEN_PLATFOR + if (VideoDriver) + VideoDriver->OnResize(core::dimension2d(Width, Height)); + } + break; + + case SDL_USEREVENT: + irrevent.EventType = irr::EET_USER_EVENT; + irrevent.UserEvent.UserData1 = reinterpret_cast(SDL_event.user.data1); + irrevent.UserEvent.UserData2 = reinterpret_cast(SDL_event.user.data2); + + postEventFromUser(irrevent); + break; + + default: + break; + } // end switch + + } // end while + +#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) + // TODO: Check if the multiple open/close calls are too expensive, then + // open/close in the constructor/destructor instead + + // update joystick states manually + SDL_JoystickUpdate(); + // we'll always send joystick input events... + SEvent joyevent; + joyevent.EventType = EET_JOYSTICK_INPUT_EVENT; + for (u32 i=0; i0) + { + switch (SDL_JoystickGetHat(joystick, 0)) + { + case SDL_HAT_UP: + joyevent.JoystickEvent.POV=0; + break; + case SDL_HAT_RIGHTUP: + joyevent.JoystickEvent.POV=4500; + break; + case SDL_HAT_RIGHT: + joyevent.JoystickEvent.POV=9000; + break; + case SDL_HAT_RIGHTDOWN: + joyevent.JoystickEvent.POV=13500; + break; + case SDL_HAT_DOWN: + joyevent.JoystickEvent.POV=18000; + break; + case SDL_HAT_LEFTDOWN: + joyevent.JoystickEvent.POV=22500; + break; + case SDL_HAT_LEFT: + joyevent.JoystickEvent.POV=27000; + break; + case SDL_HAT_LEFTUP: + joyevent.JoystickEvent.POV=31500; + break; + case SDL_HAT_CENTERED: + default: + joyevent.JoystickEvent.POV=65535; + break; + } + } + else + { + joyevent.JoystickEvent.POV=65535; + } + + // we map the number directly + joyevent.JoystickEvent.Joystick=static_cast(i); + // now post the event + postEventFromUser(joyevent); + // and close the joystick + } + } +#endif + return !Close; +} + +//! Activate any joysticks, and generate events for them. +bool CIrrDeviceSDL::activateJoysticks(core::array & joystickInfo) +{ +#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) + joystickInfo.clear(); + + // we can name up to 256 different joysticks + const int numJoysticks = core::min_(SDL_NumJoysticks(), 256); + Joysticks.reallocate(numJoysticks); + joystickInfo.reallocate(numJoysticks); + + int joystick = 0; + for (; joystick 0) + ? SJoystickInfo::POV_HAT_PRESENT : SJoystickInfo::POV_HAT_ABSENT; + + joystickInfo.push_back(info); + } + + for(joystick = 0; joystick < (int)joystickInfo.size(); ++joystick) + { + char logString[256]; + (void)sprintf(logString, "Found joystick %d, %d axes, %d buttons '%s'", + joystick, joystickInfo[joystick].Axes, + joystickInfo[joystick].Buttons, joystickInfo[joystick].Name.c_str()); + os::Printer::log(logString, ELL_INFORMATION); + } + + return true; + +#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ + + return false; +} + + + +//! pause execution temporarily +void CIrrDeviceSDL::yield() +{ + SDL_Delay(0); +} + + +//! pause execution for a specified time +void CIrrDeviceSDL::sleep(u32 timeMs, bool pauseTimer) +{ + const bool wasStopped = Timer ? Timer->isStopped() : true; + if (pauseTimer && !wasStopped) + Timer->stop(); + + SDL_Delay(timeMs); + + if (pauseTimer && !wasStopped) + Timer->start(); +} + + +//! sets the caption of the window +void CIrrDeviceSDL::setWindowCaption(const wchar_t* text) +{ + core::stringc textc = text; + SDL_WM_SetCaption( textc.c_str( ), textc.c_str( ) ); +} + + +//! presents a surface in the client area +bool CIrrDeviceSDL::present(video::IImage* surface, void* windowId, core::rect* srcClip) +{ +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ + return true; +#else // !_IRR_EMSCRIPTEN_PLATFORM_ + SDL_Surface *sdlSurface = SDL_CreateRGBSurfaceFrom( + surface->getData(), surface->getDimension().Width, surface->getDimension().Height, + surface->getBitsPerPixel(), surface->getPitch(), + surface->getRedMask(), surface->getGreenMask(), surface->getBlueMask(), surface->getAlphaMask()); + if (!sdlSurface) + return false; + SDL_SetAlpha(sdlSurface, 0, 0); + SDL_SetColorKey(sdlSurface, 0, 0); + sdlSurface->format->BitsPerPixel=surface->getBitsPerPixel(); + sdlSurface->format->BytesPerPixel=surface->getBytesPerPixel(); + if ((surface->getColorFormat()==video::ECF_R8G8B8) || + (surface->getColorFormat()==video::ECF_A8R8G8B8)) + { + sdlSurface->format->Rloss=0; + sdlSurface->format->Gloss=0; + sdlSurface->format->Bloss=0; + sdlSurface->format->Rshift=16; + sdlSurface->format->Gshift=8; + sdlSurface->format->Bshift=0; + if (surface->getColorFormat()==video::ECF_R8G8B8) + { + sdlSurface->format->Aloss=8; + sdlSurface->format->Ashift=32; + } + else + { + sdlSurface->format->Aloss=0; + sdlSurface->format->Ashift=24; + } + } + else if (surface->getColorFormat()==video::ECF_R5G6B5) + { + sdlSurface->format->Rloss=3; + sdlSurface->format->Gloss=2; + sdlSurface->format->Bloss=3; + sdlSurface->format->Aloss=8; + sdlSurface->format->Rshift=11; + sdlSurface->format->Gshift=5; + sdlSurface->format->Bshift=0; + sdlSurface->format->Ashift=16; + } + else if (surface->getColorFormat()==video::ECF_A1R5G5B5) + { + sdlSurface->format->Rloss=3; + sdlSurface->format->Gloss=3; + sdlSurface->format->Bloss=3; + sdlSurface->format->Aloss=7; + sdlSurface->format->Rshift=10; + sdlSurface->format->Gshift=5; + sdlSurface->format->Bshift=0; + sdlSurface->format->Ashift=15; + } + + SDL_Surface* scr = (SDL_Surface* )windowId; + if (!scr) + scr = Screen; + if (scr) + { + if (srcClip) + { + SDL_Rect sdlsrcClip; + sdlsrcClip.x = srcClip->UpperLeftCorner.X; + sdlsrcClip.y = srcClip->UpperLeftCorner.Y; + sdlsrcClip.w = srcClip->getWidth(); + sdlsrcClip.h = srcClip->getHeight(); + SDL_BlitSurface(sdlSurface, &sdlsrcClip, scr, NULL); + } + else + SDL_BlitSurface(sdlSurface, NULL, scr, NULL); + SDL_Flip(scr); + } + + SDL_FreeSurface(sdlSurface); + return (scr != 0); +#endif // !_IRR_EMSCRIPTEN_PLATFORM_ +} + + +//! notifies the device that it should close itself +void CIrrDeviceSDL::closeDevice() +{ + Close = true; +} + + +//! \return Pointer to a list with all video modes supported +video::IVideoModeList* CIrrDeviceSDL::getVideoModeList() +{ +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ + os::Printer::log("VideoModeList not available on the web." , ELL_WARNING); + return VideoModeList; +#else // !_IRR_EMSCRIPTEN_PLATFORM_ + if (!VideoModeList->getVideoModeCount()) + { + // enumerate video modes. + const SDL_VideoInfo *vi = SDL_GetVideoInfo(); + + SDL_PixelFormat pixelFormat = *(vi->vfmt); + + core::array checkBitsPerPixel; + checkBitsPerPixel.push_back(8); + checkBitsPerPixel.push_back(16); + checkBitsPerPixel.push_back(24); + checkBitsPerPixel.push_back(32); + if ( pixelFormat.BitsPerPixel > 32 ) + checkBitsPerPixel.push_back(pixelFormat.BitsPerPixel); + + for ( u32 i=0; iaddMode(core::dimension2d(modes[i]->w, modes[i]->h), vi->vfmt->BitsPerPixel); + } + } + } + } + + return VideoModeList; +#endif // !_IRR_EMSCRIPTEN_PLATFORM_ +} + +//! Sets if the window should be resizable in windowed mode. +void CIrrDeviceSDL::setResizable(bool resize) +{ +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ + os::Printer::log("Resizable not available on the web." , ELL_WARNING); + return; +#else // !_IRR_EMSCRIPTEN_PLATFORM_ + if (resize != Resizable) + { +#if defined(_IRR_COMPILE_WITH_OPENGL_) && defined(_IRR_WINDOWS_) + if ( SDL_Flags & SDL_OPENGL ) + { + // For unknown reasons the hack with sharing resources which was added in Irrlicht 1.8.5 for this no longer works in 1.9 + // But at least we got a new WindowResizable flag since Irrlicht 1.9. + os::Printer::log("setResizable not supported with this device/driver combination. Use SIrrCreationParameters.WindowResizable instead.", ELL_WARNING); + return; + } +#endif + + if (resize) + SDL_Flags |= SDL_RESIZABLE; + else + SDL_Flags &= ~SDL_RESIZABLE; + + Screen = SDL_SetVideoMode( 0, 0, 0, SDL_Flags ); + Resizable = resize; + } +#endif // !_IRR_EMSCRIPTEN_PLATFORM_ +} + + +//! Minimizes window if possible +void CIrrDeviceSDL::minimizeWindow() +{ + SDL_WM_IconifyWindow(); +} + + +//! Maximize window +void CIrrDeviceSDL::maximizeWindow() +{ + // do nothing +} + +//! Get the position of this window on screen +core::position2di CIrrDeviceSDL::getWindowPosition() +{ + return core::position2di(-1, -1); +} + + +//! Restore original window size +void CIrrDeviceSDL::restoreWindow() +{ + // do nothing +} + +bool CIrrDeviceSDL::isFullscreen() const +{ +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ + return SDL_GetWindowFlags(0) == SDL_WINDOW_FULLSCREEN; +#else + + return CIrrDeviceStub::isFullscreen(); +#endif +} + + +//! returns if window is active. if not, nothing need to be drawn +bool CIrrDeviceSDL::isWindowActive() const +{ +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ + // Hidden test only does something in some browsers (when tab in background or window is minimized) + // In other browsers code automatically doesn't seem to be called anymore. + EmscriptenVisibilityChangeEvent emVisibility; + if ( emscripten_get_visibility_status(&emVisibility) == EMSCRIPTEN_RESULT_SUCCESS) + { + if ( emVisibility.hidden ) + return false; + } +#endif + const Uint8 appState = SDL_GetAppState(); + return (appState&SDL_APPACTIVE && appState&SDL_APPINPUTFOCUS) ? true : false; +} + + +//! returns if window has focus. +bool CIrrDeviceSDL::isWindowFocused() const +{ + return (SDL_GetAppState()&SDL_APPINPUTFOCUS) ? true : false; +} + + +//! returns if window is minimized. +bool CIrrDeviceSDL::isWindowMinimized() const +{ + return WindowMinimized; +} + + +//! Set the current Gamma Value for the Display +bool CIrrDeviceSDL::setGammaRamp( f32 red, f32 green, f32 blue, f32 brightness, f32 contrast ) +{ + /* + // todo: Gamma in SDL takes ints, what does Irrlicht use? + return (SDL_SetGamma(red, green, blue) != -1); + */ + return false; +} + +//! Get the current Gamma Value for the Display +bool CIrrDeviceSDL::getGammaRamp( f32 &red, f32 &green, f32 &blue, f32 &brightness, f32 &contrast ) +{ +/* brightness = 0.f; + contrast = 0.f; + return (SDL_GetGamma(&red, &green, &blue) != -1);*/ + return false; +} + +//! returns color format of the window. +video::ECOLOR_FORMAT CIrrDeviceSDL::getColorFormat() const +{ + if (Screen) + { + if (Screen->format->BitsPerPixel==16) + { + if (Screen->format->Amask != 0) + return video::ECF_A1R5G5B5; + else + return video::ECF_R5G6B5; + } + else + { + if (Screen->format->Amask != 0) + return video::ECF_A8R8G8B8; + else + return video::ECF_R8G8B8; + } + } + else + return CIrrDeviceStub::getColorFormat(); +} + + +void CIrrDeviceSDL::createKeyMap() +{ + // I don't know if this is the best method to create + // the lookuptable, but I'll leave it like that until + // I find a better version. + + KeyMap.reallocate(105); + + // buttons missing + + KeyMap.push_back(SKeyMap(SDLK_BACKSPACE, KEY_BACK)); + KeyMap.push_back(SKeyMap(SDLK_TAB, KEY_TAB)); + KeyMap.push_back(SKeyMap(SDLK_CLEAR, KEY_CLEAR)); + KeyMap.push_back(SKeyMap(SDLK_RETURN, KEY_RETURN)); + + // combined modifiers missing + + KeyMap.push_back(SKeyMap(SDLK_PAUSE, KEY_PAUSE)); + KeyMap.push_back(SKeyMap(SDLK_CAPSLOCK, KEY_CAPITAL)); + + // asian letter keys missing + + KeyMap.push_back(SKeyMap(SDLK_ESCAPE, KEY_ESCAPE)); + + // asian letter keys missing + + KeyMap.push_back(SKeyMap(SDLK_SPACE, KEY_SPACE)); + KeyMap.push_back(SKeyMap(SDLK_PAGEUP, KEY_PRIOR)); + KeyMap.push_back(SKeyMap(SDLK_PAGEDOWN, KEY_NEXT)); + KeyMap.push_back(SKeyMap(SDLK_END, KEY_END)); + KeyMap.push_back(SKeyMap(SDLK_HOME, KEY_HOME)); + KeyMap.push_back(SKeyMap(SDLK_LEFT, KEY_LEFT)); + KeyMap.push_back(SKeyMap(SDLK_UP, KEY_UP)); + KeyMap.push_back(SKeyMap(SDLK_RIGHT, KEY_RIGHT)); + KeyMap.push_back(SKeyMap(SDLK_DOWN, KEY_DOWN)); + + // select missing + KeyMap.push_back(SKeyMap(SDLK_PRINT, KEY_PRINT)); + // execute missing + KeyMap.push_back(SKeyMap(SDLK_PRINT, KEY_SNAPSHOT)); + + KeyMap.push_back(SKeyMap(SDLK_INSERT, KEY_INSERT)); + KeyMap.push_back(SKeyMap(SDLK_DELETE, KEY_DELETE)); + KeyMap.push_back(SKeyMap(SDLK_HELP, KEY_HELP)); + + KeyMap.push_back(SKeyMap(SDLK_0, KEY_KEY_0)); + KeyMap.push_back(SKeyMap(SDLK_1, KEY_KEY_1)); + KeyMap.push_back(SKeyMap(SDLK_2, KEY_KEY_2)); + KeyMap.push_back(SKeyMap(SDLK_3, KEY_KEY_3)); + KeyMap.push_back(SKeyMap(SDLK_4, KEY_KEY_4)); + KeyMap.push_back(SKeyMap(SDLK_5, KEY_KEY_5)); + KeyMap.push_back(SKeyMap(SDLK_6, KEY_KEY_6)); + KeyMap.push_back(SKeyMap(SDLK_7, KEY_KEY_7)); + KeyMap.push_back(SKeyMap(SDLK_8, KEY_KEY_8)); + KeyMap.push_back(SKeyMap(SDLK_9, KEY_KEY_9)); + + KeyMap.push_back(SKeyMap(SDLK_a, KEY_KEY_A)); + KeyMap.push_back(SKeyMap(SDLK_b, KEY_KEY_B)); + KeyMap.push_back(SKeyMap(SDLK_c, KEY_KEY_C)); + KeyMap.push_back(SKeyMap(SDLK_d, KEY_KEY_D)); + KeyMap.push_back(SKeyMap(SDLK_e, KEY_KEY_E)); + KeyMap.push_back(SKeyMap(SDLK_f, KEY_KEY_F)); + KeyMap.push_back(SKeyMap(SDLK_g, KEY_KEY_G)); + KeyMap.push_back(SKeyMap(SDLK_h, KEY_KEY_H)); + KeyMap.push_back(SKeyMap(SDLK_i, KEY_KEY_I)); + KeyMap.push_back(SKeyMap(SDLK_j, KEY_KEY_J)); + KeyMap.push_back(SKeyMap(SDLK_k, KEY_KEY_K)); + KeyMap.push_back(SKeyMap(SDLK_l, KEY_KEY_L)); + KeyMap.push_back(SKeyMap(SDLK_m, KEY_KEY_M)); + KeyMap.push_back(SKeyMap(SDLK_n, KEY_KEY_N)); + KeyMap.push_back(SKeyMap(SDLK_o, KEY_KEY_O)); + KeyMap.push_back(SKeyMap(SDLK_p, KEY_KEY_P)); + KeyMap.push_back(SKeyMap(SDLK_q, KEY_KEY_Q)); + KeyMap.push_back(SKeyMap(SDLK_r, KEY_KEY_R)); + KeyMap.push_back(SKeyMap(SDLK_s, KEY_KEY_S)); + KeyMap.push_back(SKeyMap(SDLK_t, KEY_KEY_T)); + KeyMap.push_back(SKeyMap(SDLK_u, KEY_KEY_U)); + KeyMap.push_back(SKeyMap(SDLK_v, KEY_KEY_V)); + KeyMap.push_back(SKeyMap(SDLK_w, KEY_KEY_W)); + KeyMap.push_back(SKeyMap(SDLK_x, KEY_KEY_X)); + KeyMap.push_back(SKeyMap(SDLK_y, KEY_KEY_Y)); + KeyMap.push_back(SKeyMap(SDLK_z, KEY_KEY_Z)); + + KeyMap.push_back(SKeyMap(SDLK_LSUPER, KEY_LWIN)); + KeyMap.push_back(SKeyMap(SDLK_RSUPER, KEY_RWIN)); + // apps missing + KeyMap.push_back(SKeyMap(SDLK_POWER, KEY_SLEEP)); //?? + + KeyMap.push_back(SKeyMap(SDLK_KP0, KEY_NUMPAD0)); + KeyMap.push_back(SKeyMap(SDLK_KP1, KEY_NUMPAD1)); + KeyMap.push_back(SKeyMap(SDLK_KP2, KEY_NUMPAD2)); + KeyMap.push_back(SKeyMap(SDLK_KP3, KEY_NUMPAD3)); + KeyMap.push_back(SKeyMap(SDLK_KP4, KEY_NUMPAD4)); + KeyMap.push_back(SKeyMap(SDLK_KP5, KEY_NUMPAD5)); + KeyMap.push_back(SKeyMap(SDLK_KP6, KEY_NUMPAD6)); + KeyMap.push_back(SKeyMap(SDLK_KP7, KEY_NUMPAD7)); + KeyMap.push_back(SKeyMap(SDLK_KP8, KEY_NUMPAD8)); + KeyMap.push_back(SKeyMap(SDLK_KP9, KEY_NUMPAD9)); + KeyMap.push_back(SKeyMap(SDLK_KP_MULTIPLY, KEY_MULTIPLY)); + KeyMap.push_back(SKeyMap(SDLK_KP_PLUS, KEY_ADD)); +// KeyMap.push_back(SKeyMap(SDLK_KP_, KEY_SEPARATOR)); + KeyMap.push_back(SKeyMap(SDLK_KP_MINUS, KEY_SUBTRACT)); + KeyMap.push_back(SKeyMap(SDLK_KP_PERIOD, KEY_DECIMAL)); + KeyMap.push_back(SKeyMap(SDLK_KP_DIVIDE, KEY_DIVIDE)); + + KeyMap.push_back(SKeyMap(SDLK_F1, KEY_F1)); + KeyMap.push_back(SKeyMap(SDLK_F2, KEY_F2)); + KeyMap.push_back(SKeyMap(SDLK_F3, KEY_F3)); + KeyMap.push_back(SKeyMap(SDLK_F4, KEY_F4)); + KeyMap.push_back(SKeyMap(SDLK_F5, KEY_F5)); + KeyMap.push_back(SKeyMap(SDLK_F6, KEY_F6)); + KeyMap.push_back(SKeyMap(SDLK_F7, KEY_F7)); + KeyMap.push_back(SKeyMap(SDLK_F8, KEY_F8)); + KeyMap.push_back(SKeyMap(SDLK_F9, KEY_F9)); + KeyMap.push_back(SKeyMap(SDLK_F10, KEY_F10)); + KeyMap.push_back(SKeyMap(SDLK_F11, KEY_F11)); + KeyMap.push_back(SKeyMap(SDLK_F12, KEY_F12)); + KeyMap.push_back(SKeyMap(SDLK_F13, KEY_F13)); + KeyMap.push_back(SKeyMap(SDLK_F14, KEY_F14)); + KeyMap.push_back(SKeyMap(SDLK_F15, KEY_F15)); + // no higher F-keys + + KeyMap.push_back(SKeyMap(SDLK_NUMLOCK, KEY_NUMLOCK)); + KeyMap.push_back(SKeyMap(SDLK_SCROLLOCK, KEY_SCROLL)); + KeyMap.push_back(SKeyMap(SDLK_LSHIFT, KEY_LSHIFT)); + KeyMap.push_back(SKeyMap(SDLK_RSHIFT, KEY_RSHIFT)); + KeyMap.push_back(SKeyMap(SDLK_LCTRL, KEY_LCONTROL)); + KeyMap.push_back(SKeyMap(SDLK_RCTRL, KEY_RCONTROL)); + KeyMap.push_back(SKeyMap(SDLK_LALT, KEY_LMENU)); + KeyMap.push_back(SKeyMap(SDLK_RALT, KEY_RMENU)); + + KeyMap.push_back(SKeyMap(SDLK_PLUS, KEY_PLUS)); + KeyMap.push_back(SKeyMap(SDLK_COMMA, KEY_COMMA)); + KeyMap.push_back(SKeyMap(SDLK_MINUS, KEY_MINUS)); + KeyMap.push_back(SKeyMap(SDLK_PERIOD, KEY_PERIOD)); + + // some special keys missing + + KeyMap.sort(); +} + +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_SDL_DEVICE_ + diff --git a/source/Irrlicht/CIrrDeviceSDL.h b/source/Irrlicht/CIrrDeviceSDL.h new file mode 100644 index 00000000..9047f526 --- /dev/null +++ b/source/Irrlicht/CIrrDeviceSDL.h @@ -0,0 +1,280 @@ +// Copyright (C) 2002-2012 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 +// contributed by Shane Parker (sirshane). + +#ifndef __C_IRR_DEVICE_SDL_H_INCLUDED__ +#define __C_IRR_DEVICE_SDL_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ + +#include "IrrlichtDevice.h" +#include "CIrrDeviceStub.h" +#include "IImagePresenter.h" +#include "ICursorControl.h" + +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ +#include +#endif + +#include +#include + +namespace irr +{ + + class CIrrDeviceSDL : public CIrrDeviceStub, video::IImagePresenter + { + public: + + //! constructor + CIrrDeviceSDL(const SIrrlichtCreationParameters& param); + + //! destructor + virtual ~CIrrDeviceSDL(); + + //! runs the device. Returns false if device wants to be deleted + virtual bool run() _IRR_OVERRIDE_; + + //! pause execution temporarily + virtual void yield() _IRR_OVERRIDE_; + + //! pause execution for a specified time + virtual void sleep(u32 timeMs, bool pauseTimer) _IRR_OVERRIDE_; + + //! sets the caption of the window + virtual void setWindowCaption(const wchar_t* text) _IRR_OVERRIDE_; + + //! returns if window is active. if not, nothing need to be drawn + virtual bool isWindowActive() const _IRR_OVERRIDE_; + + //! returns if window has focus. + bool isWindowFocused() const _IRR_OVERRIDE_; + + //! returns if window is minimized. + bool isWindowMinimized() const _IRR_OVERRIDE_; + + //! returns color format of the window. + video::ECOLOR_FORMAT getColorFormat() const _IRR_OVERRIDE_; + + //! presents a surface in the client area + virtual bool present(video::IImage* surface, void* windowId=0, core::rect* src=0) _IRR_OVERRIDE_; + + //! notifies the device that it should close itself + virtual void closeDevice() _IRR_OVERRIDE_; + + //! \return Returns a pointer to a list with all video modes supported + virtual video::IVideoModeList* getVideoModeList() _IRR_OVERRIDE_; + + //! Sets if the window should be resizable in windowed mode. + virtual void setResizable(bool resize=false) _IRR_OVERRIDE_; + + //! Minimizes the window. + virtual void minimizeWindow() _IRR_OVERRIDE_; + + //! Maximizes the window. + virtual void maximizeWindow() _IRR_OVERRIDE_; + + //! Restores the window size. + virtual void restoreWindow() _IRR_OVERRIDE_; + + //! Checks if the Irrlicht window is running in fullscreen mode + /** \return True if window is fullscreen. */ + virtual bool isFullscreen() const _IRR_OVERRIDE_; + + //! Get the position of this window on screen + virtual core::position2di getWindowPosition() _IRR_OVERRIDE_; + + //! Activate any joysticks, and generate events for them. + virtual bool activateJoysticks(core::array & joystickInfo) _IRR_OVERRIDE_; + + //! Set the current Gamma Value for the Display + virtual bool setGammaRamp( f32 red, f32 green, f32 blue, f32 brightness, f32 contrast ) _IRR_OVERRIDE_; + + //! Get the current Gamma Value for the Display + virtual bool getGammaRamp( f32 &red, f32 &green, f32 &blue, f32 &brightness, f32 &contrast ) _IRR_OVERRIDE_; + + //! Get the device type + virtual E_DEVICE_TYPE getType() const _IRR_OVERRIDE_ + { + return EIDT_SDL; + } + + //! Implementation of the linux cursor control + class CCursorControl : public gui::ICursorControl + { + public: + + CCursorControl(CIrrDeviceSDL* dev) + : Device(dev), IsVisible(true) + { + } + + //! Changes the visible state of the mouse cursor. + virtual void setVisible(bool visible) _IRR_OVERRIDE_ + { + IsVisible = visible; + if ( visible ) + SDL_ShowCursor( SDL_ENABLE ); + else + { + SDL_ShowCursor( SDL_DISABLE ); + } + } + + //! Returns if the cursor is currently visible. + virtual bool isVisible() const _IRR_OVERRIDE_ + { + return IsVisible; + } + + //! Sets the new position of the cursor. + virtual void setPosition(const core::position2d &pos) _IRR_OVERRIDE_ + { + setPosition(pos.X, pos.Y); + } + + //! Sets the new position of the cursor. + virtual void setPosition(f32 x, f32 y) _IRR_OVERRIDE_ + { + setPosition((s32)(x*Device->Width), (s32)(y*Device->Height)); + } + + //! Sets the new position of the cursor. + virtual void setPosition(const core::position2d &pos) _IRR_OVERRIDE_ + { + setPosition(pos.X, pos.Y); + } + + //! Sets the new position of the cursor. + virtual void setPosition(s32 x, s32 y) _IRR_OVERRIDE_ + { + SDL_WarpMouse( x, y ); + } + + //! Returns the current position of the mouse cursor. + virtual const core::position2d& getPosition(bool updateCursor) _IRR_OVERRIDE_ + { + if ( updateCursor ) + updateCursorPos(); + return CursorPos; + } + + //! Returns the current position of the mouse cursor. + virtual core::position2d getRelativePosition(bool updateCursor) _IRR_OVERRIDE_ + { + if ( updateCursor ) + updateCursorPos(); + return core::position2d(CursorPos.X / (f32)Device->Width, + CursorPos.Y / (f32)Device->Height); + } + + virtual void setReferenceRect(core::rect* rect=0) _IRR_OVERRIDE_ + { + } + + private: + + void updateCursorPos() + { +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ + EmscriptenPointerlockChangeEvent pointerlockStatus; // let's hope that test is not expensive ... + if ( emscripten_get_pointerlock_status(&pointerlockStatus) == EMSCRIPTEN_RESULT_SUCCESS ) + { + if ( pointerlockStatus.isActive ) + { + CursorPos.X += Device->MouseXRel; + CursorPos.Y += Device->MouseYRel; + Device->MouseXRel = 0; + Device->MouseYRel = 0; + } + else + { + CursorPos.X = Device->MouseX; + CursorPos.Y = Device->MouseY; + } + } +#else + CursorPos.X = Device->MouseX; + CursorPos.Y = Device->MouseY; + + if (CursorPos.X < 0) + CursorPos.X = 0; + if (CursorPos.X > (s32)Device->Width) + CursorPos.X = Device->Width; + if (CursorPos.Y < 0) + CursorPos.Y = 0; + if (CursorPos.Y > (s32)Device->Height) + CursorPos.Y = Device->Height; +#endif + } + + CIrrDeviceSDL* Device; + core::position2d CursorPos; + bool IsVisible; + }; + + private: + +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ + static EM_BOOL MouseUpDownCallback(int eventType, const EmscriptenMouseEvent * event, void* userData); + static EM_BOOL MouseEnterCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData); + static EM_BOOL MouseLeaveCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData); + + // Check if it's a special key like left, right, up down and so on which shouldn't have a Unicode character. + bool isNoUnicodeKey(EKEY_CODE key) const; +#endif + + //! create the driver + void createDriver(); + + bool createWindow(); + + void createKeyMap(); + + void logAttributes(); + + SDL_Surface* Screen; + int SDL_Flags; +#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) + core::array Joysticks; +#endif + + s32 MouseX, MouseY; + s32 MouseXRel, MouseYRel; + u32 MouseButtonStates; + + u32 Width, Height; + + bool Resizable; + bool WindowMinimized; + + struct SKeyMap + { + SKeyMap() {} + SKeyMap(s32 x11, s32 win32) + : SDLKey(x11), Win32Key(win32) + { + } + + s32 SDLKey; + s32 Win32Key; + + bool operator<(const SKeyMap& o) const + { + return SDLKey KeyMap; + SDL_SysWMinfo Info; + }; + +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_SDL_DEVICE_ +#endif // __C_IRR_DEVICE_SDL_H_INCLUDED__ + diff --git a/source/Irrlicht/CIrrDeviceStub.cpp b/source/Irrlicht/CIrrDeviceStub.cpp new file mode 100644 index 00000000..0ecf128e --- /dev/null +++ b/source/Irrlicht/CIrrDeviceStub.cpp @@ -0,0 +1,509 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CIrrDeviceStub.h" +#include "ISceneManager.h" +#include "IEventReceiver.h" +#include "IFileSystem.h" +#include "IGUIEnvironment.h" +#include "os.h" +#include "IrrCompileConfig.h" +#include "CTimer.h" +#include "CLogger.h" +#include "irrString.h" +#include "IRandomizer.h" + +namespace irr +{ +//! constructor +CIrrDeviceStub::CIrrDeviceStub(const SIrrlichtCreationParameters& params) +: IrrlichtDevice(), VideoDriver(0), GUIEnvironment(0), SceneManager(0), + Timer(0), CursorControl(0), UserReceiver(params.EventReceiver), + Logger(0), Operator(0), Randomizer(0), FileSystem(0), + InputReceivingSceneManager(0), VideoModeList(0), ContextManager(0), + CreationParams(params), Close(false) +{ + Timer = new CTimer(params.UsePerformanceTimer); + if (os::Printer::Logger) + { + os::Printer::Logger->grab(); + Logger = (CLogger*)os::Printer::Logger; + Logger->setReceiver(UserReceiver); + } + else + { + Logger = new CLogger(UserReceiver); + os::Printer::Logger = Logger; + } + Logger->setLogLevel(CreationParams.LoggingLevel); + + os::Printer::Logger = Logger; + Randomizer = createDefaultRandomizer(); + + FileSystem = io::createFileSystem(); + VideoModeList = new video::CVideoModeList(); + + core::stringc s = "Irrlicht Engine version "; + s.append(getVersion()); + os::Printer::log(s.c_str(), ELL_INFORMATION); + + checkVersion(params.SDK_version_do_not_use); +} + + +CIrrDeviceStub::~CIrrDeviceStub() +{ + VideoModeList->drop(); + + if (GUIEnvironment) + GUIEnvironment->drop(); + + if (SceneManager) + SceneManager->drop(); + + if (VideoDriver) + VideoDriver->drop(); + + if (ContextManager) + ContextManager->drop(); + + if ( FileSystem ) + FileSystem->drop(); + + if (InputReceivingSceneManager) + InputReceivingSceneManager->drop(); + + if (CursorControl) + CursorControl->drop(); + + if (Operator) + Operator->drop(); + + if (Randomizer) + Randomizer->drop(); + + CursorControl = 0; + + if (Timer) + Timer->drop(); + + if (Logger->drop()) + os::Printer::Logger = 0; +} + + +void CIrrDeviceStub::createGUIAndScene() +{ + #ifdef _IRR_COMPILE_WITH_GUI_ + // create gui environment + GUIEnvironment = gui::createGUIEnvironment(FileSystem, VideoDriver, Operator); + #endif + + // create Scene manager + SceneManager = scene::createSceneManager(VideoDriver, FileSystem, CursorControl, GUIEnvironment); + + setEventReceiver(UserReceiver); +} + + +//! returns the video driver +video::IVideoDriver* CIrrDeviceStub::getVideoDriver() +{ + return VideoDriver; +} + + +//! return file system +io::IFileSystem* CIrrDeviceStub::getFileSystem() +{ + return FileSystem; +} + + + +//! returns the gui environment +gui::IGUIEnvironment* CIrrDeviceStub::getGUIEnvironment() +{ + return GUIEnvironment; +} + + + +//! returns the scene manager +scene::ISceneManager* CIrrDeviceStub::getSceneManager() +{ + return SceneManager; +} + + +//! \return Returns a pointer to the ITimer object. With it the +//! current Time can be received. +ITimer* CIrrDeviceStub::getTimer() +{ + return Timer; +} + + +//! Returns the version of the engine. +const char* CIrrDeviceStub::getVersion() const +{ + return IRRLICHT_SDK_VERSION; +} + +//! \return Returns a pointer to the mouse cursor control interface. +gui::ICursorControl* CIrrDeviceStub::getCursorControl() +{ + return CursorControl; +} + + +//! \return Returns a pointer to a list with all video modes supported +//! by the gfx adapter. +video::IVideoModeList* CIrrDeviceStub::getVideoModeList() +{ + return VideoModeList; +} + +//! return the context manager +video::IContextManager* CIrrDeviceStub::getContextManager() +{ + return ContextManager; +} + +//! checks version of sdk and prints warning if there might be a problem +bool CIrrDeviceStub::checkVersion(const char* version) +{ + if (strcmp(getVersion(), version)) + { + core::stringc w; + w = "Warning: The library version of the Irrlicht Engine ("; + w += getVersion(); + w += ") does not match the version the application was compiled with ("; + w += version; + w += "). This may cause problems."; + os::Printer::log(w.c_str(), ELL_WARNING); + + return false; + } + + return true; +} + + +//! Compares to the last call of this function to return double and triple clicks. +u32 CIrrDeviceStub::checkSuccessiveClicks(s32 mouseX, s32 mouseY, EMOUSE_INPUT_EVENT inputEvent ) +{ + const s32 MAX_MOUSEMOVE = 3; + + irr::u32 clickTime = getTimer()->getRealTime(); + + if ( (clickTime-MouseMultiClicks.LastClickTime) < MouseMultiClicks.DoubleClickTime + && core::abs_(MouseMultiClicks.LastClick.X - mouseX ) <= MAX_MOUSEMOVE + && core::abs_(MouseMultiClicks.LastClick.Y - mouseY ) <= MAX_MOUSEMOVE + && MouseMultiClicks.CountSuccessiveClicks < 3 + && MouseMultiClicks.LastMouseInputEvent == inputEvent + ) + { + ++MouseMultiClicks.CountSuccessiveClicks; + } + else + { + MouseMultiClicks.CountSuccessiveClicks = 1; + } + + MouseMultiClicks.LastMouseInputEvent = inputEvent; + MouseMultiClicks.LastClickTime = clickTime; + MouseMultiClicks.LastClick.X = mouseX; + MouseMultiClicks.LastClick.Y = mouseY; + + return MouseMultiClicks.CountSuccessiveClicks; +} + + +//! send the event to the right receiver +bool CIrrDeviceStub::postEventFromUser(const SEvent& event) +{ + bool absorbed = false; + + if (UserReceiver) + absorbed = UserReceiver->OnEvent(event); + + if (!absorbed && GUIEnvironment) + absorbed = GUIEnvironment->postEventFromUser(event); + + scene::ISceneManager* inputReceiver = InputReceivingSceneManager; + if (!inputReceiver) + inputReceiver = SceneManager; + + if (!absorbed && inputReceiver) + absorbed = inputReceiver->postEventFromUser(event); + + return absorbed; +} + + +//! Sets a new event receiver to receive events +void CIrrDeviceStub::setEventReceiver(IEventReceiver* receiver) +{ + UserReceiver = receiver; + Logger->setReceiver(receiver); + if (GUIEnvironment) + GUIEnvironment->setUserEventReceiver(receiver); +} + + +//! Returns poinhter to the current event receiver. Returns 0 if there is none. +IEventReceiver* CIrrDeviceStub::getEventReceiver() +{ + return UserReceiver; +} + + +//! \return Returns a pointer to the logger. +ILogger* CIrrDeviceStub::getLogger() +{ + return Logger; +} + + +//! Returns the operation system opertator object. +IOSOperator* CIrrDeviceStub::getOSOperator() +{ + return Operator; +} + + +//! Provides access to the engine's currently set randomizer. +IRandomizer* CIrrDeviceStub::getRandomizer() const +{ + return Randomizer; +} + +//! Sets a new randomizer. +void CIrrDeviceStub::setRandomizer(IRandomizer* r) +{ + if (r!=Randomizer) + { + if (Randomizer) + Randomizer->drop(); + Randomizer=r; + if (Randomizer) + Randomizer->grab(); + } +} + +namespace +{ + struct SDefaultRandomizer : public IRandomizer + { + virtual void reset(s32 value=0x0f0f0f0f) _IRR_OVERRIDE_ + { + os::Randomizer::reset(value); + } + + virtual s32 rand() const _IRR_OVERRIDE_ + { + return os::Randomizer::rand(); + } + + virtual f32 frand() const _IRR_OVERRIDE_ + { + return os::Randomizer::frand(); + } + + virtual s32 randMax() const _IRR_OVERRIDE_ + { + return os::Randomizer::randMax(); + } + }; +} + +//! Creates a new default randomizer. +IRandomizer* CIrrDeviceStub::createDefaultRandomizer() const +{ + IRandomizer* r = new SDefaultRandomizer(); + if (r) + r->reset(); + return r; +} + + +//! Sets the input receiving scene manager. +void CIrrDeviceStub::setInputReceivingSceneManager(scene::ISceneManager* sceneManager) +{ + if (sceneManager) + sceneManager->grab(); + if (InputReceivingSceneManager) + InputReceivingSceneManager->drop(); + + InputReceivingSceneManager = sceneManager; +} + + +//! Checks if the window is running in fullscreen mode +bool CIrrDeviceStub::isFullscreen() const +{ + return CreationParams.Fullscreen; +} + + +//! returns color format +video::ECOLOR_FORMAT CIrrDeviceStub::getColorFormat() const +{ + return video::ECF_R5G6B5; +} + +//! No-op in this implementation +bool CIrrDeviceStub::activateJoysticks(core::array & joystickInfo) +{ + return false; +} + +//! No-op in this implementation +bool CIrrDeviceStub::activateAccelerometer(float updateInterval) +{ + return false; +} + +//! No-op in this implementation +bool CIrrDeviceStub::deactivateAccelerometer() +{ + return false; +} + +//! No-op in this implementation +bool CIrrDeviceStub::isAccelerometerActive() +{ + return false; +} + +//! No-op in this implementation +bool CIrrDeviceStub::isAccelerometerAvailable() +{ + return false; +} + +//! No-op in this implementation +bool CIrrDeviceStub::activateGyroscope(float updateInterval) +{ + return false; +} + +//! No-op in this implementation +bool CIrrDeviceStub::deactivateGyroscope() +{ + return false; +} + +//! No-op in this implementation +bool CIrrDeviceStub::isGyroscopeActive() +{ + return false; +} + +//! No-op in this implementation +bool CIrrDeviceStub::isGyroscopeAvailable() +{ + return false; +} + +//! No-op in this implementation +bool CIrrDeviceStub::activateDeviceMotion(float updateInterval) +{ + return false; +} + +//! No-op in this implementation +bool CIrrDeviceStub::deactivateDeviceMotion() +{ + return false; +} + +//! No-op in this implementation +bool CIrrDeviceStub::isDeviceMotionActive() +{ + return false; +} + +//! No-op in this implementation +bool CIrrDeviceStub::isDeviceMotionAvailable() +{ + return false; +} + +/*! +*/ +void CIrrDeviceStub::calculateGammaRamp ( u16 *ramp, f32 gamma, f32 relativebrightness, f32 relativecontrast ) +{ + s32 i; + s32 value; + s32 rbright = (s32) ( relativebrightness * (65535.f / 4 ) ); + f32 rcontrast = 1.f / (255.f - ( relativecontrast * 127.5f ) ); + + gamma = gamma > 0.f ? 1.0f / gamma : 0.f; + + for ( i = 0; i < 256; ++i ) + { + value = (s32)(pow( rcontrast * i, gamma)*65535.f + 0.5f ); + ramp[i] = (u16) core::s32_clamp ( value + rbright, 0, 65535 ); + } + +} + +void CIrrDeviceStub::calculateGammaFromRamp ( f32 &gamma, const u16 *ramp ) +{ + /* The following is adapted from a post by Garrett Bass on OpenGL + Gamedev list, March 4, 2000. + */ + f32 sum = 0.0; + s32 i, count = 0; + + gamma = 1.0; + for ( i = 1; i < 256; ++i ) { + if ( (ramp[i] != 0) && (ramp[i] != 65535) ) { + f32 B = (f32)i / 256.f; + f32 A = ramp[i] / 65535.f; + sum += (f32) ( logf(A) / logf(B) ); + count++; + } + } + if ( count && sum ) { + gamma = 1.0f / (sum / count); + } + +} + +//! Set the current Gamma Value for the Display +bool CIrrDeviceStub::setGammaRamp( f32 red, f32 green, f32 blue, f32 brightness, f32 contrast ) +{ + return false; +} + +//! Get the current Gamma Value for the Display +bool CIrrDeviceStub::getGammaRamp( f32 &red, f32 &green, f32 &blue, f32 &brightness, f32 &contrast ) +{ + return false; +} + +//! Set the maximal elapsed time between 2 clicks to generate doubleclicks for the mouse. It also affects tripleclick behavior. +void CIrrDeviceStub::setDoubleClickTime( u32 timeMs ) +{ + MouseMultiClicks.DoubleClickTime = timeMs; +} + +//! Get the maximal elapsed time between 2 clicks to generate double- and tripleclicks for the mouse. +u32 CIrrDeviceStub::getDoubleClickTime() const +{ + return MouseMultiClicks.DoubleClickTime; +} + +//! Remove all messages pending in the system message loop +void CIrrDeviceStub::clearSystemMessages() +{ +} + + + +} // end namespace irr + diff --git a/source/Irrlicht/CIrrDeviceStub.h b/source/Irrlicht/CIrrDeviceStub.h new file mode 100644 index 00000000..367faf13 --- /dev/null +++ b/source/Irrlicht/CIrrDeviceStub.h @@ -0,0 +1,231 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_IRR_DEVICE_STUB_H_INCLUDED__ +#define __C_IRR_DEVICE_STUB_H_INCLUDED__ + +#include "IrrlichtDevice.h" +#include "IImagePresenter.h" +#include "SIrrCreationParameters.h" +#include "CVideoModeList.h" +#include "IContextManager.h" + +namespace irr +{ + // lots of prototypes: + class ILogger; + class CLogger; + class IRandomizer; + + namespace gui + { + class IGUIEnvironment; + IGUIEnvironment* createGUIEnvironment(io::IFileSystem* fs, + video::IVideoDriver* Driver, IOSOperator* op); + } + + namespace scene + { + ISceneManager* createSceneManager(video::IVideoDriver* driver, + io::IFileSystem* fs, gui::ICursorControl* cc, gui::IGUIEnvironment *gui); + } + + namespace io + { + IFileSystem* createFileSystem(); + } + + namespace video + { + IVideoDriver* createSoftwareDriver(const core::dimension2d& windowSize, + bool fullscreen, io::IFileSystem* io, + video::IImagePresenter* presenter); + IVideoDriver* createBurningVideoDriver(const irr::SIrrlichtCreationParameters& params, + io::IFileSystem* io, video::IImagePresenter* presenter); + IVideoDriver* createNullDriver(io::IFileSystem* io, const core::dimension2d& screenSize); + } + + + + //! Stub for an Irrlicht Device implementation + class CIrrDeviceStub : public IrrlichtDevice + { + public: + + //! constructor + CIrrDeviceStub(const SIrrlichtCreationParameters& param); + + //! destructor + virtual ~CIrrDeviceStub(); + + //! returns the video driver + virtual video::IVideoDriver* getVideoDriver() _IRR_OVERRIDE_; + + //! return file system + virtual io::IFileSystem* getFileSystem() _IRR_OVERRIDE_; + + //! returns the gui environment + virtual gui::IGUIEnvironment* getGUIEnvironment() _IRR_OVERRIDE_; + + //! returns the scene manager + virtual scene::ISceneManager* getSceneManager() _IRR_OVERRIDE_; + + //! \return Returns a pointer to the mouse cursor control interface. + virtual gui::ICursorControl* getCursorControl() _IRR_OVERRIDE_; + + //! Returns a pointer to a list with all video modes supported by the gfx adapter. + virtual video::IVideoModeList* getVideoModeList() _IRR_OVERRIDE_; + + //! return the context manager + virtual video::IContextManager* getContextManager() _IRR_OVERRIDE_; + + //! Returns a pointer to the ITimer object. With it the current Time can be received. + virtual ITimer* getTimer() _IRR_OVERRIDE_; + + //! Returns the version of the engine. + virtual const char* getVersion() const _IRR_OVERRIDE_; + + //! send the event to the right receiver + virtual bool postEventFromUser(const SEvent& event) _IRR_OVERRIDE_; + + //! Sets a new event receiver to receive events + virtual void setEventReceiver(IEventReceiver* receiver) _IRR_OVERRIDE_; + + //! Returns pointer to the current event receiver. Returns 0 if there is none. + virtual IEventReceiver* getEventReceiver() _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! Returns a pointer to the logger. + virtual ILogger* getLogger() _IRR_OVERRIDE_; + + //! Provides access to the engine's currently set randomizer. + virtual IRandomizer* getRandomizer() const _IRR_OVERRIDE_; + + //! Sets a new randomizer. + virtual void setRandomizer(IRandomizer* r) _IRR_OVERRIDE_; + + //! Creates a new default randomizer. + virtual IRandomizer* createDefaultRandomizer() const _IRR_OVERRIDE_; + + //! Returns the operation system opertator object. + virtual IOSOperator* getOSOperator() _IRR_OVERRIDE_; + + //! Checks if the window is running in fullscreen mode. + virtual bool isFullscreen() const _IRR_OVERRIDE_; + + //! get color format of the current window + virtual video::ECOLOR_FORMAT getColorFormat() const _IRR_OVERRIDE_; + + //! Activate any joysticks, and generate events for them. + virtual bool activateJoysticks(core::array & joystickInfo) _IRR_OVERRIDE_; + + //! Activate accelerometer. + virtual bool activateAccelerometer(float updateInterval = 0.016666f) _IRR_OVERRIDE_; + + //! Deactivate accelerometer. + virtual bool deactivateAccelerometer() _IRR_OVERRIDE_; + + //! Is accelerometer active. + virtual bool isAccelerometerActive() _IRR_OVERRIDE_; + + //! Is accelerometer available. + virtual bool isAccelerometerAvailable() _IRR_OVERRIDE_; + + //! Activate gyroscope. + virtual bool activateGyroscope(float updateInterval = 0.016666f) _IRR_OVERRIDE_; + + //! Deactivate gyroscope. + virtual bool deactivateGyroscope() _IRR_OVERRIDE_; + + //! Is gyroscope active. + virtual bool isGyroscopeActive() _IRR_OVERRIDE_; + + //! Is gyroscope available. + virtual bool isGyroscopeAvailable() _IRR_OVERRIDE_; + + //! Activate device motion. + virtual bool activateDeviceMotion(float updateInterval = 0.016666f) _IRR_OVERRIDE_; + + //! Deactivate device motion. + virtual bool deactivateDeviceMotion() _IRR_OVERRIDE_; + + //! Is device motion active. + virtual bool isDeviceMotionActive() _IRR_OVERRIDE_; + + //! Is device motion available. + virtual bool isDeviceMotionAvailable() _IRR_OVERRIDE_; + + //! Set the current Gamma Value for the Display + virtual bool setGammaRamp( f32 red, f32 green, f32 blue, f32 brightness, f32 contrast ) _IRR_OVERRIDE_; + + //! Get the current Gamma Value for the Display + virtual bool getGammaRamp( f32 &red, f32 &green, f32 &blue, f32 &brightness, f32 &contrast ) _IRR_OVERRIDE_; + + //! Set the maximal elapsed time between 2 clicks to generate doubleclicks for the mouse. It also affects tripleclick behavior. + //! When set to 0 no double- and tripleclicks will be generated. + virtual void setDoubleClickTime( u32 timeMs ) _IRR_OVERRIDE_; + + //! Get the maximal elapsed time between 2 clicks to generate double- and tripleclicks for the mouse. + virtual u32 getDoubleClickTime() const _IRR_OVERRIDE_; + + //! Remove all messages pending in the system message loop + virtual void clearSystemMessages() _IRR_OVERRIDE_; + + //! Resize the render window. + virtual void setWindowSize(const irr::core::dimension2d& size) _IRR_OVERRIDE_ {} + + protected: + + void createGUIAndScene(); + + //! checks version of SDK and prints warning if there might be a problem + bool checkVersion(const char* version); + + //! Compares to the last call of this function to return double and triple clicks. + /** Needed for win32 device event handling + \return Returns only 1,2 or 3. A 4th click will start with 1 again. + */ + virtual u32 checkSuccessiveClicks(s32 mouseX, s32 mouseY, EMOUSE_INPUT_EVENT inputEvent); + + void calculateGammaRamp ( u16 *ramp, f32 gamma, f32 relativebrightness, f32 relativecontrast ); + void calculateGammaFromRamp ( f32 &gamma, const u16 *ramp ); + + video::IVideoDriver* VideoDriver; + gui::IGUIEnvironment* GUIEnvironment; + scene::ISceneManager* SceneManager; + ITimer* Timer; + gui::ICursorControl* CursorControl; + IEventReceiver* UserReceiver; + CLogger* Logger; + IOSOperator* Operator; + IRandomizer* Randomizer; + io::IFileSystem* FileSystem; + scene::ISceneManager* InputReceivingSceneManager; + + struct SMouseMultiClicks + { + SMouseMultiClicks() + : DoubleClickTime(500), CountSuccessiveClicks(0), LastClickTime(0), LastMouseInputEvent(EMIE_COUNT) + {} + + u32 DoubleClickTime; + u32 CountSuccessiveClicks; + u32 LastClickTime; + core::position2di LastClick; + EMOUSE_INPUT_EVENT LastMouseInputEvent; + }; + SMouseMultiClicks MouseMultiClicks; + video::CVideoModeList* VideoModeList; + video::IContextManager* ContextManager; + SIrrlichtCreationParameters CreationParams; + bool Close; + }; + +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CIrrDeviceWin32.cpp b/source/Irrlicht/CIrrDeviceWin32.cpp new file mode 100644 index 00000000..270be368 --- /dev/null +++ b/source/Irrlicht/CIrrDeviceWin32.cpp @@ -0,0 +1,2235 @@ +// Copyright (C) 2002-2012 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" + +#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ + +#if defined (__STRICT_ANSI__) + #error Compiling with __STRICT_ANSI__ not supported. g++ does set this when compiling with -std=c++11 or -std=c++0x. Use instead -std=gnu++11 or -std=gnu++0x. Or use -U__STRICT_ANSI__ to disable strict ansi. +#endif + +#include "CIrrDeviceWin32.h" +#include "IEventReceiver.h" +#include "irrList.h" +#include "os.h" + +#include "CTimer.h" +#include "irrString.h" +#include "COSOperator.h" +#include "dimension2d.h" +#include "IGUISpriteBank.h" +#include +#include "SExposedVideoData.h" +#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) +#include +#include +#ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ +#define DIRECTINPUT_VERSION 0x0800 +#include +#ifdef _MSC_VER +#pragma comment(lib, "dinput8.lib") +#pragma comment(lib, "dxguid.lib") +#endif +#else +#ifdef _MSC_VER +#pragma comment(lib, "winmm.lib") +#endif +#endif +#endif + +#if defined(_IRR_COMPILE_WITH_OGLES1_) || defined(_IRR_COMPILE_WITH_OGLES2_) +#include "CEGLManager.h" +#endif + +#if defined(_IRR_COMPILE_WITH_OPENGL_) +#include "CWGLManager.h" +#endif + +namespace irr +{ + namespace video + { +#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ + IVideoDriver* createDirectX9Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, HWND window); +#endif + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + IVideoDriver* createOpenGLDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager); +#endif + +#ifdef _IRR_COMPILE_WITH_OGLES1_ + IVideoDriver* createOGLES1Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager); +#endif + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + IVideoDriver* createOGLES2Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager); +#endif + } +} // end namespace irr + +namespace irr +{ + struct SJoystickWin32Control + { + CIrrDeviceWin32* Device; + + #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_) + IDirectInput8* DirectInputDevice; + #endif + #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) + struct JoystickInfo + { + u32 Index; + #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ + core::stringc Name; + GUID guid; + LPDIRECTINPUTDEVICE8 lpdijoy; + DIDEVCAPS devcaps; + u8 axisValid[8]; + #else + JOYCAPS Caps; + #endif + }; + core::array ActiveJoysticks; + #endif + + SJoystickWin32Control(CIrrDeviceWin32* dev); + ~SJoystickWin32Control(); + + #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_) + static BOOL CALLBACK EnumJoysticks(LPCDIDEVICEINSTANCE lpddi, LPVOID cp); + void directInputAddJoystick(LPCDIDEVICEINSTANCE lpddi); + #endif + + void pollJoysticks(); + bool activateJoysticks(core::array & joystickInfo); + irr::core::stringc findJoystickName(int index, const JOYCAPS &caps) const; + }; + + + SJoystickWin32Control::SJoystickWin32Control(CIrrDeviceWin32* dev) : Device(dev) + { +#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_) + DirectInputDevice=0; + if (DI_OK != (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&DirectInputDevice, NULL))) + { + os::Printer::log("Could not create DirectInput8 Object", ELL_WARNING); + return; + } +#endif + } + + SJoystickWin32Control::~SJoystickWin32Control() + { +#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_) + for(u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) + { + LPDIRECTINPUTDEVICE8 dev = ActiveJoysticks[joystick].lpdijoy; + if (dev) + { + dev->Unacquire(); + } + dev->Release(); + } + + if (DirectInputDevice) + DirectInputDevice->Release(); +#endif + } + +#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_) + BOOL CALLBACK SJoystickWin32Control::EnumJoysticks(LPCDIDEVICEINSTANCE lpddi, LPVOID cp) + { + SJoystickWin32Control* p=(SJoystickWin32Control*)cp; + p->directInputAddJoystick(lpddi); + return DIENUM_CONTINUE; + } + void SJoystickWin32Control::directInputAddJoystick(LPCDIDEVICEINSTANCE lpddi) + { + //Get the GUID of the joystuck + const GUID guid = lpddi->guidInstance; + + JoystickInfo activeJoystick; + activeJoystick.Index=ActiveJoysticks.size(); + activeJoystick.guid=guid; + activeJoystick.Name=lpddi->tszProductName; + if (FAILED(DirectInputDevice->CreateDevice(guid, &activeJoystick.lpdijoy, NULL))) + { + os::Printer::log("Could not create DirectInput device", ELL_WARNING); + return; + } + + activeJoystick.devcaps.dwSize=sizeof(activeJoystick.devcaps); + if (FAILED(activeJoystick.lpdijoy->GetCapabilities(&activeJoystick.devcaps))) + { + os::Printer::log("Could not create DirectInput device", ELL_WARNING); + return; + } + + if (FAILED(activeJoystick.lpdijoy->SetCooperativeLevel(Device->HWnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE))) + { + os::Printer::log("Could not set DirectInput device cooperative level", ELL_WARNING); + return; + } + + if (FAILED(activeJoystick.lpdijoy->SetDataFormat(&c_dfDIJoystick2))) + { + os::Printer::log("Could not set DirectInput device data format", ELL_WARNING); + return; + } + + if (FAILED(activeJoystick.lpdijoy->Acquire())) + { + os::Printer::log("Could not set DirectInput cooperative level", ELL_WARNING); + return; + } + + DIJOYSTATE2 info; + if (FAILED(activeJoystick.lpdijoy->GetDeviceState(sizeof(info),&info))) + { + os::Printer::log("Could not read DirectInput device state", ELL_WARNING); + return; + } + + ZeroMemory(activeJoystick.axisValid,sizeof(activeJoystick.axisValid)); + activeJoystick.axisValid[0]= (info.lX!=0) ? 1 : 0; + activeJoystick.axisValid[1]= (info.lY!=0) ? 1 : 0; + activeJoystick.axisValid[2]= (info.lZ!=0) ? 1 : 0; + activeJoystick.axisValid[3]= (info.lRx!=0) ? 1 : 0; + activeJoystick.axisValid[4]= (info.lRy!=0) ? 1 : 0; + activeJoystick.axisValid[5]= (info.lRz!=0) ? 1 : 0; + + int caxis=0; + for (u8 i=0; i<6; i++) + { + if (activeJoystick.axisValid[i]) + caxis++; + } + + for (u8 i=0; i<(activeJoystick.devcaps.dwAxes)-caxis; i++) + { + if (i+caxis < 8) + activeJoystick.axisValid[i+caxis]=1; + } + + ActiveJoysticks.push_back(activeJoystick); + } +#endif + +void SJoystickWin32Control::pollJoysticks() +{ +#if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ +#ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ + if(0 == ActiveJoysticks.size()) + return; + + u32 joystick; + DIJOYSTATE2 info; + + for(joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) + { + // needs to be reset for each joystick + // request ALL values and POV as continuous if possible + + const DIDEVCAPS & caps = ActiveJoysticks[joystick].devcaps; + // if no POV is available don't ask for POV values + + if (!FAILED(ActiveJoysticks[joystick].lpdijoy->GetDeviceState(sizeof(info),&info))) + { + SEvent event; + + event.EventType = irr::EET_JOYSTICK_INPUT_EVENT; + event.JoystickEvent.Joystick = (u8)joystick; + + event.JoystickEvent.POV = (u16)info.rgdwPOV[0]; + // set to undefined if no POV value was returned or the value + // is out of range + if ((caps.dwPOVs==0) || (event.JoystickEvent.POV > 35900)) + event.JoystickEvent.POV = 65535; + + for(int axis = 0; axis < SEvent::SJoystickEvent::NUMBER_OF_AXES; ++axis) + event.JoystickEvent.Axis[axis] = 0; + + u16 dxAxis=0; + u16 irrAxis=0; + + while (dxAxis < 6 && irrAxis 0) + axisFound=1; + + if (axisFound) + { + s32 val=axisValue - 32768; + + if (val <-32767) val=-32767; + if (val > 32767) val=32767; + event.JoystickEvent.Axis[irrAxis]=(s16)(val); + irrAxis++; + } + + dxAxis++; + } + + u32 buttons=0; + BYTE* bytebuttons=info.rgbButtons; + for (u16 i=0; i<32; i++) + { + if (bytebuttons[i] >0) + { + buttons |= (1 << i); + } + } + event.JoystickEvent.ButtonStates = buttons; + + (void)Device->postEventFromUser(event); + } + } +#else + if (0 == ActiveJoysticks.size()) + return; + + u32 joystick; + JOYINFOEX info; + + for(joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) + { + // needs to be reset for each joystick + // request ALL values and POV as continuous if possible + info.dwSize = sizeof(info); + info.dwFlags = JOY_RETURNALL|JOY_RETURNPOVCTS; + const JOYCAPS & caps = ActiveJoysticks[joystick].Caps; + // if no POV is available don't ask for POV values + if (!(caps.wCaps & JOYCAPS_HASPOV)) + info.dwFlags &= ~(JOY_RETURNPOV|JOY_RETURNPOVCTS); + if(JOYERR_NOERROR == joyGetPosEx(ActiveJoysticks[joystick].Index, &info)) + { + SEvent event; + + event.EventType = irr::EET_JOYSTICK_INPUT_EVENT; + event.JoystickEvent.Joystick = (u8)joystick; + + event.JoystickEvent.POV = (u16)info.dwPOV; + // set to undefined if no POV value was returned or the value + // is out of range + if (!(info.dwFlags & JOY_RETURNPOV) || (event.JoystickEvent.POV > 35900)) + event.JoystickEvent.POV = 65535; + + for(int axis = 0; axis < SEvent::SJoystickEvent::NUMBER_OF_AXES; ++axis) + event.JoystickEvent.Axis[axis] = 0; + + event.JoystickEvent.ButtonStates = info.dwButtons; + + switch(caps.wNumAxes) + { + default: + case 6: + 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] = + (s16)((65535 * (info.dwUpos - caps.wUmin)) / (caps.wUmax - caps.wUmin) - 32768); + + case 4: + event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_R] = + (s16)((65535 * (info.dwRpos - caps.wRmin)) / (caps.wRmax - caps.wRmin) - 32768); + + case 3: + 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] = + (s16)((65535 * (info.dwXpos - caps.wXmin)) / (caps.wXmax - caps.wXmin) - 32768); + } + + (void)Device->postEventFromUser(event); + } + } +#endif +#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ +} + +/** This function is ported from SDL and released under zlib-license: + * Copyright (C) 1997-2014 Sam Lantinga */ +irr::core::stringc SJoystickWin32Control::findJoystickName(int index, const JOYCAPS &caps) const +{ +#if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ + + // As a default use the name given in the joystick structure. + // It is always the same name, independent of joystick. + irr::core::stringc result(caps.szPname); + + core::stringc key = core::stringc(REGSTR_PATH_JOYCONFIG)+ "\\" + caps.szRegKey + "\\" + REGSTR_KEY_JOYCURR; + HKEY hTopKey = HKEY_LOCAL_MACHINE; + HKEY hKey; + long regresult = RegOpenKeyExA(hTopKey, key.c_str(), 0, KEY_READ, &hKey); + if (regresult != ERROR_SUCCESS) + { + hTopKey = HKEY_CURRENT_USER; + regresult = RegOpenKeyExA(hTopKey, key.c_str(), 0, KEY_READ, &hKey); + } + if (regresult != ERROR_SUCCESS) + return result; + + /* find the registry key name for the joystick's properties */ + char regname[256]; + DWORD regsize = sizeof(regname); + core::stringc regvalue = core::stringc("Joystick")+core::stringc(index+1) + REGSTR_VAL_JOYOEMNAME; + regresult = RegQueryValueExA(hKey, regvalue.c_str(), 0, 0, (LPBYTE)regname, ®size); + RegCloseKey(hKey); + if (regresult != ERROR_SUCCESS) + return result; + + /* open that registry key */ + core::stringc regkey = core::stringc(REGSTR_PATH_JOYOEM) + "\\" + regname; + regresult = RegOpenKeyExA(hTopKey, regkey.c_str(), 0, KEY_READ, &hKey); + if (regresult != ERROR_SUCCESS) + return result; + + /* find the size for the OEM name text */ + regsize = sizeof(regvalue); + regresult = RegQueryValueEx(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, + NULL, ®size); + if (regresult == ERROR_SUCCESS) + { + char *name; + /* allocate enough memory for the OEM name text ... */ + name = new char[regsize]; + if (name) + { + /* ... and read it from the registry */ + regresult = RegQueryValueEx(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, + (LPBYTE)name, ®size ); + result = name; + } + delete[] name; + } + RegCloseKey(hKey); + + return result; +#endif + return ""; +} + +bool SJoystickWin32Control::activateJoysticks(core::array & joystickInfo) +{ +#if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ + joystickInfo.clear(); + ActiveJoysticks.clear(); +#ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ + if (!DirectInputDevice || (DirectInputDevice->EnumDevices(DI8DEVCLASS_GAMECTRL, SJoystickWin32Control::EnumJoysticks, this, DIEDFL_ATTACHEDONLY ))) + { + os::Printer::log("Could not enum DirectInput8 controllers", ELL_WARNING); + return false; + } + + for(u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) + { + JoystickInfo& activeJoystick = ActiveJoysticks[joystick]; + SJoystickInfo info; + info.Axes=activeJoystick.devcaps.dwAxes; + info.Buttons=activeJoystick.devcaps.dwButtons; + info.Name=activeJoystick.Name; + info.PovHat = (activeJoystick.devcaps.dwPOVs != 0) + ? SJoystickInfo::POV_HAT_PRESENT : SJoystickInfo::POV_HAT_ABSENT; + joystickInfo.push_back(info); + } + return true; +#else + const u32 numberOfJoysticks = ::joyGetNumDevs(); + JOYINFOEX info; + info.dwSize = sizeof(info); + info.dwFlags = JOY_RETURNALL; + + JoystickInfo activeJoystick; + SJoystickInfo returnInfo; + + joystickInfo.reallocate(numberOfJoysticks); + ActiveJoysticks.reallocate(numberOfJoysticks); + + u32 joystick = 0; + for(; joystick < numberOfJoysticks; ++joystick) + { + if(JOYERR_NOERROR == joyGetPosEx(joystick, &info) + && + JOYERR_NOERROR == joyGetDevCaps(joystick, + &activeJoystick.Caps, + sizeof(activeJoystick.Caps))) + { + activeJoystick.Index = joystick; + ActiveJoysticks.push_back(activeJoystick); + + returnInfo.Joystick = (u8)joystick; + returnInfo.Axes = activeJoystick.Caps.wNumAxes; + returnInfo.Buttons = activeJoystick.Caps.wNumButtons; + returnInfo.Name = findJoystickName(joystick, activeJoystick.Caps); + returnInfo.PovHat = ((activeJoystick.Caps.wCaps & JOYCAPS_HASPOV) == JOYCAPS_HASPOV) + ? SJoystickInfo::POV_HAT_PRESENT : SJoystickInfo::POV_HAT_ABSENT; + + joystickInfo.push_back(returnInfo); + } + } + + for(joystick = 0; joystick < joystickInfo.size(); ++joystick) + { + char logString[256]; + (void)sprintf(logString, "Found joystick %d, %d axes, %d buttons '%s'", + joystick, joystickInfo[joystick].Axes, + joystickInfo[joystick].Buttons, joystickInfo[joystick].Name.c_str()); + os::Printer::log(logString, ELL_INFORMATION); + } + + return true; +#endif +#else + return false; +#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ +} +} // end namespace irr + +// Get the codepage from the locale language id +// Based on the table from http://www.science.co.il/Language/Locale-Codes.asp?s=decimal +static unsigned int LocaleIdToCodepage(unsigned int lcid) +{ + switch ( lcid ) + { + case 1098: // Telugu + case 1095: // Gujarati + case 1094: // Punjabi + case 1103: // Sanskrit + case 1111: // Konkani + case 1114: // Syriac + case 1099: // Kannada + case 1102: // Marathi + case 1125: // Divehi + case 1067: // Armenian + case 1081: // Hindi + case 1079: // Georgian + case 1097: // Tamil + return 0; + case 1054: // Thai + return 874; + case 1041: // Japanese + return 932; + case 2052: // Chinese (PRC) + case 4100: // Chinese (Singapore) + return 936; + case 1042: // Korean + return 949; + case 5124: // Chinese (Macau S.A.R.) + case 3076: // Chinese (Hong Kong S.A.R.) + case 1028: // Chinese (Taiwan) + return 950; + case 1048: // Romanian + case 1060: // Slovenian + case 1038: // Hungarian + case 1051: // Slovak + case 1045: // Polish + case 1052: // Albanian + case 2074: // Serbian (Latin) + case 1050: // Croatian + case 1029: // Czech + return 1250; + case 1104: // Mongolian (Cyrillic) + case 1071: // FYRO Macedonian + case 2115: // Uzbek (Cyrillic) + case 1058: // Ukrainian + case 2092: // Azeri (Cyrillic) + case 1092: // Tatar + case 1087: // Kazakh + case 1059: // Belarusian + case 1088: // Kyrgyz (Cyrillic) + case 1026: // Bulgarian + case 3098: // Serbian (Cyrillic) + case 1049: // Russian + return 1251; + case 8201: // English (Jamaica) + case 3084: // French (Canada) + case 1036: // French (France) + case 5132: // French (Luxembourg) + case 5129: // English (New Zealand) + case 6153: // English (Ireland) + case 1043: // Dutch (Netherlands) + case 9225: // English (Caribbean) + case 4108: // French (Switzerland) + case 4105: // English (Canada) + case 1110: // Galician + case 10249: // English (Belize) + case 3079: // German (Austria) + case 6156: // French (Monaco) + case 12297: // English (Zimbabwe) + case 1069: // Basque + case 2067: // Dutch (Belgium) + case 2060: // French (Belgium) + case 1035: // Finnish + case 1080: // Faroese + case 1031: // German (Germany) + case 3081: // English (Australia) + case 1033: // English (United States) + case 2057: // English (United Kingdom) + case 1027: // Catalan + case 11273: // English (Trinidad) + case 7177: // English (South Africa) + case 1030: // Danish + case 13321: // English (Philippines) + case 15370: // Spanish (Paraguay) + case 9226: // Spanish (Colombia) + case 5130: // Spanish (Costa Rica) + case 7178: // Spanish (Dominican Republic) + case 12298: // Spanish (Ecuador) + case 17418: // Spanish (El Salvador) + case 4106: // Spanish (Guatemala) + case 18442: // Spanish (Honduras) + case 3082: // Spanish (International Sort) + case 13322: // Spanish (Chile) + case 19466: // Spanish (Nicaragua) + case 2058: // Spanish (Mexico) + case 10250: // Spanish (Peru) + case 20490: // Spanish (Puerto Rico) + case 1034: // Spanish (Traditional Sort) + case 14346: // Spanish (Uruguay) + case 8202: // Spanish (Venezuela) + case 1089: // Swahili + case 1053: // Swedish + case 2077: // Swedish (Finland) + case 5127: // German (Liechtenstein) + case 1078: // Afrikaans + case 6154: // Spanish (Panama) + case 4103: // German (Luxembourg) + case 16394: // Spanish (Bolivia) + case 2055: // German (Switzerland) + case 1039: // Icelandic + case 1057: // Indonesian + case 1040: // Italian (Italy) + case 2064: // Italian (Switzerland) + case 2068: // Norwegian (Nynorsk) + case 11274: // Spanish (Argentina) + case 1046: // Portuguese (Brazil) + case 1044: // Norwegian (Bokmal) + case 1086: // Malay (Malaysia) + case 2110: // Malay (Brunei Darussalam) + case 2070: // Portuguese (Portugal) + return 1252; + case 1032: // Greek + return 1253; + case 1091: // Uzbek (Latin) + case 1068: // Azeri (Latin) + case 1055: // Turkish + return 1254; + case 1037: // Hebrew + return 1255; + case 5121: // Arabic (Algeria) + case 15361: // Arabic (Bahrain) + case 9217: // Arabic (Yemen) + case 3073: // Arabic (Egypt) + case 2049: // Arabic (Iraq) + case 11265: // Arabic (Jordan) + case 13313: // Arabic (Kuwait) + case 12289: // Arabic (Lebanon) + case 4097: // Arabic (Libya) + case 6145: // Arabic (Morocco) + case 8193: // Arabic (Oman) + case 16385: // Arabic (Qatar) + case 1025: // Arabic (Saudi Arabia) + case 10241: // Arabic (Syria) + case 14337: // Arabic (U.A.E.) + case 1065: // Farsi + case 1056: // Urdu + case 7169: // Arabic (Tunisia) + return 1256; + case 1061: // Estonian + case 1062: // Latvian + case 1063: // Lithuanian + return 1257; + case 1066: // Vietnamese + return 1258; + } + return 65001; // utf-8 +} + +namespace +{ + struct SEnvMapper + { + HWND hWnd; + irr::CIrrDeviceWin32* irrDev; + }; + // NOTE: This is global. We can have more than one Irrlicht Device at same time. + irr::core::array EnvMap; + + HKL KEYBOARD_INPUT_HKL=0; + unsigned int KEYBOARD_INPUT_CODEPAGE = 1252; +} + +irr::CIrrDeviceWin32* getDeviceFromHWnd(HWND hWnd) +{ + const irr::u32 end = EnvMap.size(); + for ( irr::u32 i=0; i < end; ++i ) + { + const SEnvMapper& env = EnvMap[i]; + if ( env.hWnd == hWnd ) + return env.irrDev; + } + + return 0; +} + + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + #ifndef WM_MOUSEWHEEL + #define WM_MOUSEWHEEL 0x020A + #endif + #ifndef WHEEL_DELTA + #define WHEEL_DELTA 120 + #endif + + irr::CIrrDeviceWin32* dev = 0; + irr::SEvent event; + + static irr::s32 ClickCount=0; + if (GetCapture() != hWnd && ClickCount > 0) + ClickCount = 0; + + + struct messageMap + { + irr::s32 group; + UINT winMessage; + irr::s32 irrMessage; + }; + + static messageMap mouseMap[] = + { + {0, WM_LBUTTONDOWN, irr::EMIE_LMOUSE_PRESSED_DOWN}, + {1, WM_LBUTTONUP, irr::EMIE_LMOUSE_LEFT_UP}, + {0, WM_RBUTTONDOWN, irr::EMIE_RMOUSE_PRESSED_DOWN}, + {1, WM_RBUTTONUP, irr::EMIE_RMOUSE_LEFT_UP}, + {0, WM_MBUTTONDOWN, irr::EMIE_MMOUSE_PRESSED_DOWN}, + {1, WM_MBUTTONUP, irr::EMIE_MMOUSE_LEFT_UP}, + {2, WM_MOUSEMOVE, irr::EMIE_MOUSE_MOVED}, + {3, WM_MOUSEWHEEL, irr::EMIE_MOUSE_WHEEL}, + {-1, 0, 0} + }; + + // handle grouped events + messageMap * m = mouseMap; + while ( m->group >=0 && m->winMessage != message ) + m += 1; + + if ( m->group >= 0 ) + { + if ( m->group == 0 ) // down + { + ClickCount++; + SetCapture(hWnd); + } + else + if ( m->group == 1 ) // up + { + ClickCount--; + if (ClickCount<1) + { + ClickCount=0; + ReleaseCapture(); + } + } + + event.EventType = irr::EET_MOUSE_INPUT_EVENT; + event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT) m->irrMessage; + event.MouseInput.X = (short)LOWORD(lParam); + event.MouseInput.Y = (short)HIWORD(lParam); + event.MouseInput.Shift = ((LOWORD(wParam) & MK_SHIFT) != 0); + event.MouseInput.Control = ((LOWORD(wParam) & MK_CONTROL) != 0); + // left and right mouse buttons + event.MouseInput.ButtonStates = wParam & ( MK_LBUTTON | MK_RBUTTON); + // middle and extra buttons + if (wParam & MK_MBUTTON) + event.MouseInput.ButtonStates |= irr::EMBSM_MIDDLE; +#if(_WIN32_WINNT >= 0x0500) + if (wParam & MK_XBUTTON1) + event.MouseInput.ButtonStates |= irr::EMBSM_EXTRA1; + if (wParam & MK_XBUTTON2) + event.MouseInput.ButtonStates |= irr::EMBSM_EXTRA2; +#endif + event.MouseInput.Wheel = 0.f; + + // wheel + if ( m->group == 3 ) + { + POINT p; // fixed by jox + p.x = 0; p.y = 0; + ClientToScreen(hWnd, &p); + event.MouseInput.X -= p.x; + event.MouseInput.Y -= p.y; + event.MouseInput.Wheel = ((irr::f32)((short)HIWORD(wParam))) / (irr::f32)WHEEL_DELTA; + } + + dev = getDeviceFromHWnd(hWnd); + if (dev) + { + dev->postEventFromUser(event); + + if ( event.MouseInput.Event >= irr::EMIE_LMOUSE_PRESSED_DOWN && event.MouseInput.Event <= irr::EMIE_MMOUSE_PRESSED_DOWN ) + { + irr::u32 clicks = dev->checkSuccessiveClicks(event.MouseInput.X, event.MouseInput.Y, event.MouseInput.Event); + if ( clicks == 2 ) + { + event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT)(irr::EMIE_LMOUSE_DOUBLE_CLICK + event.MouseInput.Event-irr::EMIE_LMOUSE_PRESSED_DOWN); + dev->postEventFromUser(event); + } + else if ( clicks == 3 ) + { + event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT)(irr::EMIE_LMOUSE_TRIPLE_CLICK + event.MouseInput.Event-irr::EMIE_LMOUSE_PRESSED_DOWN); + dev->postEventFromUser(event); + } + } + } + return 0; + } + + switch (message) + { + case WM_PAINT: + { + PAINTSTRUCT ps; + BeginPaint(hWnd, &ps); + EndPaint(hWnd, &ps); + } + return 0; + + case WM_ERASEBKGND: + return 0; + + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + case WM_KEYDOWN: + case WM_KEYUP: + { + BYTE allKeys[256]; + + event.EventType = irr::EET_KEY_INPUT_EVENT; + event.KeyInput.Key = (irr::EKEY_CODE)wParam; + event.KeyInput.PressedDown = (message==WM_KEYDOWN || message == WM_SYSKEYDOWN); + + const UINT MY_MAPVK_VSC_TO_VK_EX = 3; // MAPVK_VSC_TO_VK_EX should be in SDK according to MSDN, but isn't in mine. + if ( event.KeyInput.Key == irr::KEY_SHIFT ) + { + // this will fail on systems before windows NT/2000/XP, not sure _what_ will return there instead. + event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MY_MAPVK_VSC_TO_VK_EX ); + } + if ( event.KeyInput.Key == irr::KEY_CONTROL ) + { + event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MY_MAPVK_VSC_TO_VK_EX ); + // some keyboards will just return LEFT for both - left and right keys. So also check extend bit. + if (lParam & 0x1000000) + event.KeyInput.Key = irr::KEY_RCONTROL; + } + if ( event.KeyInput.Key == irr::KEY_MENU ) + { + event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MY_MAPVK_VSC_TO_VK_EX ); + if (lParam & 0x1000000) + event.KeyInput.Key = irr::KEY_RMENU; + } + + GetKeyboardState(allKeys); + + event.KeyInput.Shift = ((allKeys[VK_SHIFT] & 0x80)!=0); + event.KeyInput.Control = ((allKeys[VK_CONTROL] & 0x80)!=0); + + // Handle unicode and deadkeys in a way that works since Windows 95 and nt4.0 + // Using ToUnicode instead would be shorter, but would to my knowledge not run on 95 and 98. + WORD keyChars[2]; + UINT scanCode = HIWORD(lParam); + int conversionResult = ToAsciiEx(static_cast(wParam),scanCode,allKeys,keyChars,0,KEYBOARD_INPUT_HKL); + if (conversionResult == 1) + { + WORD unicodeChar; + MultiByteToWideChar( + KEYBOARD_INPUT_CODEPAGE, + MB_PRECOMPOSED, // default + (LPCSTR)keyChars, + sizeof(keyChars), + (WCHAR*)&unicodeChar, + 1 ); + event.KeyInput.Char = unicodeChar; + } + else + event.KeyInput.Char = 0; + + // allow composing characters like '@' with Alt Gr on non-US keyboards + if ((allKeys[VK_MENU] & 0x80) != 0) + event.KeyInput.Control = 0; + + dev = getDeviceFromHWnd(hWnd); + if (dev) + dev->postEventFromUser(event); + + if (message == WM_SYSKEYDOWN || message == WM_SYSKEYUP) + return DefWindowProc(hWnd, message, wParam, lParam); + else + return 0; + } + + case WM_SIZE: + { + // resize + dev = getDeviceFromHWnd(hWnd); + if (dev) + dev->OnResized(); + } + return 0; + + case WM_DESTROY: + PostQuitMessage(0); + return 0; + + case WM_SYSCOMMAND: + // prevent screensaver or monitor powersave mode from starting + if ((wParam & 0xFFF0) == SC_SCREENSAVE || + (wParam & 0xFFF0) == SC_MONITORPOWER || + (wParam & 0xFFF0) == SC_KEYMENU + ) + return 0; + + break; + + case WM_ACTIVATE: + // we need to take care for screen changes, e.g. Alt-Tab + dev = getDeviceFromHWnd(hWnd); + if (dev && dev->isFullscreen()) + { + if ((wParam&0xFF)==WA_INACTIVE) + { + // If losing focus we minimize the app to show other one + ShowWindow(hWnd,SW_MINIMIZE); + // and switch back to default resolution + dev->switchToFullScreen(true); + } + else + { + // Otherwise we retore the fullscreen Irrlicht app + SetForegroundWindow(hWnd); + ShowWindow(hWnd, SW_RESTORE); + // and set the fullscreen resolution again + dev->switchToFullScreen(); + } + } + break; + + case WM_USER: + event.EventType = irr::EET_USER_EVENT; + event.UserEvent.UserData1 = static_cast(wParam); + event.UserEvent.UserData2 = static_cast(lParam); + dev = getDeviceFromHWnd(hWnd); + + if (dev) + dev->postEventFromUser(event); + + return 0; + + case WM_SETCURSOR: + // because Windows forgot about that in the meantime + dev = getDeviceFromHWnd(hWnd); + if (dev) + { + dev->getCursorControl()->setActiveIcon( dev->getCursorControl()->getActiveIcon() ); + dev->getCursorControl()->setVisible( dev->getCursorControl()->isVisible() ); + } + break; + + case WM_INPUTLANGCHANGE: + // get the new codepage used for keyboard input + KEYBOARD_INPUT_HKL = GetKeyboardLayout(0); + KEYBOARD_INPUT_CODEPAGE = LocaleIdToCodepage( LOWORD(KEYBOARD_INPUT_HKL) ); + return 0; + } + return DefWindowProc(hWnd, message, wParam, lParam); +} + + +namespace irr +{ + +//! constructor +CIrrDeviceWin32::CIrrDeviceWin32(const SIrrlichtCreationParameters& params) +: CIrrDeviceStub(params), HWnd(0), ChangedToFullScreen(false), Resized(false), + ExternalWindow(false), Win32CursorControl(0), JoyControl(0) +{ + #ifdef _DEBUG + setDebugName("CIrrDeviceWin32"); + #endif + + // get windows version and create OS operator + core::stringc winversion; + getWindowsVersion(winversion); + Operator = new COSOperator(winversion); + os::Printer::log(winversion.c_str(), ELL_INFORMATION); + + // get handle to exe file + HINSTANCE hInstance = GetModuleHandle(0); + + // Store original desktop mode. + + memset(&DesktopMode, 0, sizeof(DesktopMode)); + DesktopMode.dmSize = sizeof(DesktopMode); + + EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &DesktopMode); + + // create the window if we need to and we do not use the null device + if (!CreationParams.WindowId && CreationParams.DriverType != video::EDT_NULL) + { + const fschar_t* ClassName = __TEXT("CIrrDeviceWin32"); + + // Register Class + WNDCLASSEX wcex; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = NULL; + wcex.hCursor = 0; // LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = 0; + wcex.lpszClassName = ClassName; + wcex.hIconSm = 0; + + // if there is an icon, load it + wcex.hIcon = (HICON)LoadImage(hInstance, __TEXT("irrlicht.ico"), IMAGE_ICON, 0,0, LR_LOADFROMFILE | LR_DEFAULTSIZE); + + RegisterClassEx(&wcex); + + // calculate client size + + RECT clientSize; + clientSize.top = 0; + clientSize.left = 0; + clientSize.right = CreationParams.WindowSize.Width; + clientSize.bottom = CreationParams.WindowSize.Height; + + DWORD style = getWindowStyle(CreationParams.Fullscreen, CreationParams.WindowResizable); + AdjustWindowRect(&clientSize, style, FALSE); + + const s32 realWidth = clientSize.right - clientSize.left; + const s32 realHeight = clientSize.bottom - clientSize.top; + + s32 windowLeft = (CreationParams.WindowPosition.X == -1 ? + (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2 : + CreationParams.WindowPosition.X); + s32 windowTop = (CreationParams.WindowPosition.Y == -1 ? + (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2 : + CreationParams.WindowPosition.Y); + + if ( windowLeft < 0 ) + windowLeft = 0; + if ( windowTop < 0 ) + windowTop = 0; // make sure window menus are in screen on creation + + if (CreationParams.Fullscreen) + { + windowLeft = 0; + windowTop = 0; + } + + // create window + HWnd = CreateWindow( ClassName, __TEXT(""), style, windowLeft, windowTop, + realWidth, realHeight, NULL, NULL, hInstance, NULL); + if (!HWnd) + { + os::Printer::log("Window could not be created.", ELL_ERROR); + } + + CreationParams.WindowId = HWnd; +// CreationParams.WindowSize.Width = realWidth; +// CreationParams.WindowSize.Height = realHeight; + + ShowWindow(HWnd, SW_SHOWNORMAL); + UpdateWindow(HWnd); + + // fix ugly ATI driver bugs. Thanks to ariaci + MoveWindow(HWnd, windowLeft, windowTop, realWidth, realHeight, TRUE); + + // make sure everything gets updated to the real sizes + Resized = true; + } + else if (CreationParams.WindowId) + { + // attach external window + HWnd = static_cast(CreationParams.WindowId); + RECT r; + GetWindowRect(HWnd, &r); + CreationParams.WindowSize.Width = r.right - r.left; + CreationParams.WindowSize.Height = r.bottom - r.top; + CreationParams.Fullscreen = false; + ExternalWindow = true; + } + + // create cursor control + + Win32CursorControl = new CCursorControl(this, CreationParams.WindowSize, HWnd, CreationParams.Fullscreen); + CursorControl = Win32CursorControl; + JoyControl = new SJoystickWin32Control(this); + + // initialize doubleclicks with system values + MouseMultiClicks.DoubleClickTime = GetDoubleClickTime(); + + // create driver + + createDriver(); + + if (VideoDriver) + createGUIAndScene(); + + // register environment + + SEnvMapper em; + em.irrDev = this; + em.hWnd = HWnd; + EnvMap.push_back(em); + + // set this as active window + if (!ExternalWindow) + { + SetActiveWindow(HWnd); + SetForegroundWindow(HWnd); + } + + // get the codepage used for keyboard input + KEYBOARD_INPUT_HKL = GetKeyboardLayout(0); + KEYBOARD_INPUT_CODEPAGE = LocaleIdToCodepage( LOWORD(KEYBOARD_INPUT_HKL) ); + + // inform driver about the window size etc. + resizeIfNecessary(); +} + + +//! destructor +CIrrDeviceWin32::~CIrrDeviceWin32() +{ + delete JoyControl; + + // unregister environment + for (u32 i=0; i< EnvMap.size(); ++i) + { + if (EnvMap[i].hWnd == HWnd) + { + EnvMap.erase(i); + break; + } + } + + switchToFullScreen(true); +} + + +//! create the driver +void CIrrDeviceWin32::createDriver() +{ + switch(CreationParams.DriverType) + { + case video::DEPRECATED_EDT_DIRECT3D8_NO_LONGER_EXISTS: + os::Printer::log("DIRECT3D8 Driver is no longer supported in Irrlicht. Try another one.", ELL_ERROR); + break; + case video::EDT_DIRECT3D9: +#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ + VideoDriver = video::createDirectX9Driver(CreationParams, FileSystem, HWnd); + + if (!VideoDriver) + os::Printer::log("Could not create DIRECT3D9 Driver.", ELL_ERROR); +#else + os::Printer::log("DIRECT3D9 Driver was not compiled into this dll. Try another one.", ELL_ERROR); +#endif + break; + case video::EDT_OPENGL: +#ifdef _IRR_COMPILE_WITH_OPENGL_ + switchToFullScreen(); + + ContextManager = new video::CWGLManager(); + ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd)); + + VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, ContextManager); + + if (!VideoDriver) + os::Printer::log("Could not create OpenGL driver.", ELL_ERROR); +#else + os::Printer::log("OpenGL driver was not compiled in.", ELL_ERROR); +#endif + break; + case video::EDT_OGLES1: +#ifdef _IRR_COMPILE_WITH_OGLES1_ + switchToFullScreen(); + + ContextManager = new video::CEGLManager(); + ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd)); + + VideoDriver = video::createOGLES1Driver(CreationParams, FileSystem, ContextManager); + + if (!VideoDriver) + os::Printer::log("Could not create OpenGL-ES1 driver.", ELL_ERROR); +#else + os::Printer::log("OpenGL-ES1 driver was not compiled in.", ELL_ERROR); +#endif + break; + case video::EDT_OGLES2: +#ifdef _IRR_COMPILE_WITH_OGLES2_ + switchToFullScreen(); + + ContextManager = new video::CEGLManager(); + ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd)); + + VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager); + + if (!VideoDriver) + os::Printer::log("Could not create OpenGL-ES2 driver.", ELL_ERROR); +#else + os::Printer::log("OpenGL-ES2 driver was not compiled in.", ELL_ERROR); +#endif + break; + case EDT_WEBGL1: + os::Printer::log("WebGL1 driver not supported on Win32 device.", ELL_ERROR); + break; + case video::EDT_SOFTWARE: +#ifdef _IRR_COMPILE_WITH_SOFTWARE_ + switchToFullScreen(); + + VideoDriver = video::createSoftwareDriver(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this); +#else + os::Printer::log("Software driver was not compiled in.", ELL_ERROR); +#endif + break; + case video::EDT_BURNINGSVIDEO: +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + switchToFullScreen(); + + VideoDriver = video::createBurningVideoDriver(CreationParams, FileSystem, this); +#else + os::Printer::log("Burning's Video driver was not compiled in.", ELL_ERROR); +#endif + break; + case video::EDT_NULL: + VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize); + break; + default: + os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR); + break; + } +} + + +//! runs the device. Returns false if device wants to be deleted +bool CIrrDeviceWin32::run() +{ + os::Timer::tick(); + + static_cast(CursorControl)->update(); + + handleSystemMessages(); + + if (!Close) + resizeIfNecessary(); + + if(!Close && JoyControl) + JoyControl->pollJoysticks(); + + return !Close; +} + + +//! Pause the current process for the minimum time allowed only to allow other processes to execute +void CIrrDeviceWin32::yield() +{ + Sleep(1); +} + +//! Pause execution and let other processes to run for a specified amount of time. +void CIrrDeviceWin32::sleep(u32 timeMs, bool pauseTimer) +{ + const bool wasStopped = Timer ? Timer->isStopped() : true; + if (pauseTimer && !wasStopped) + Timer->stop(); + + Sleep(timeMs); + + if (pauseTimer && !wasStopped) + Timer->start(); +} + + +void CIrrDeviceWin32::resizeIfNecessary() +{ + if (!Resized || !getVideoDriver()) + return; + + RECT r; + GetClientRect(HWnd, &r); + + char tmp[255]; + + if (r.right < 2 || r.bottom < 2) + { + sprintf(tmp, "Ignoring resize operation to (%ld %ld)", r.right, r.bottom); + os::Printer::log(tmp); + } + else + { + sprintf(tmp, "Resizing window (%ld %ld)", r.right, r.bottom); + os::Printer::log(tmp); + + getVideoDriver()->OnResize(irr::core::dimension2du((u32)r.right, (u32)r.bottom)); + getWin32CursorControl()->OnResize(getVideoDriver()->getScreenSize()); + } + + Resized = false; +} + + +DWORD CIrrDeviceWin32::getWindowStyle(bool fullscreen, bool resizable) const +{ + if ( fullscreen ) + return WS_POPUP; + + if ( resizable ) + return WS_THICKFRAME | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; + + return WS_BORDER | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; +} + +//! sets the caption of the window +void CIrrDeviceWin32::setWindowCaption(const wchar_t* text) +{ + // We use SendMessage instead of SetText to ensure proper + // function even in cases where the HWND was created in a different thread + DWORD_PTR dwResult; + SendMessageTimeoutW(HWnd, WM_SETTEXT, 0, + reinterpret_cast(text), + SMTO_ABORTIFHUNG, 2000, &dwResult); +} + + +//! presents a surface in the client area +bool CIrrDeviceWin32::present(video::IImage* image, void* windowId, core::rect* src) +{ + HWND hwnd = HWnd; + if ( windowId ) + hwnd = reinterpret_cast(windowId); + + HDC dc = GetDC(hwnd); + + if ( dc ) + { + RECT rect; + GetClientRect(hwnd, &rect); + const void* memory = (const void *)image->getData(); + + BITMAPV4HEADER bi; + ZeroMemory (&bi, sizeof(bi)); + bi.bV4Size = sizeof(BITMAPINFOHEADER); + bi.bV4BitCount = (WORD)image->getBitsPerPixel(); + bi.bV4Planes = 1; + bi.bV4Width = image->getDimension().Width; + bi.bV4Height = -((s32)image->getDimension().Height); + bi.bV4V4Compression = BI_BITFIELDS; + bi.bV4AlphaMask = image->getAlphaMask(); + bi.bV4RedMask = image->getRedMask(); + bi.bV4GreenMask = image->getGreenMask(); + bi.bV4BlueMask = image->getBlueMask(); + + if ( src ) + { + StretchDIBits(dc, 0,0, rect.right, rect.bottom, + src->UpperLeftCorner.X, src->UpperLeftCorner.Y, + src->getWidth(), src->getHeight(), + memory, (const BITMAPINFO*)(&bi), DIB_RGB_COLORS, SRCCOPY); + } + else + { + StretchDIBits(dc, 0,0, rect.right, rect.bottom, + 0, 0, image->getDimension().Width, image->getDimension().Height, + memory, (const BITMAPINFO*)(&bi), DIB_RGB_COLORS, SRCCOPY); + } + + ReleaseDC(hwnd, dc); + } + return true; +} + + +//! notifies the device that it should close itself +void CIrrDeviceWin32::closeDevice() +{ + MSG msg; + PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE); + PostQuitMessage(0); + PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE); + if (!ExternalWindow) + { + DestroyWindow(HWnd); + const fschar_t* ClassName = __TEXT("CIrrDeviceWin32"); + HINSTANCE hInstance = GetModuleHandle(0); + UnregisterClass(ClassName, hInstance); + } + Close=true; +} + + +//! returns if window is active. if not, nothing needs to be drawn +bool CIrrDeviceWin32::isWindowActive() const +{ + return (GetActiveWindow() == HWnd); +} + + +//! returns if window has focus +bool CIrrDeviceWin32::isWindowFocused() const +{ + bool ret = (GetFocus() == HWnd); + return ret; +} + + +//! returns if window is minimized +bool CIrrDeviceWin32::isWindowMinimized() const +{ + WINDOWPLACEMENT plc; + plc.length=sizeof(WINDOWPLACEMENT); + bool ret=false; + if (GetWindowPlacement(HWnd,&plc)) + ret = plc.showCmd == SW_SHOWMINIMIZED; + return ret; +} + + +//! switches to fullscreen +bool CIrrDeviceWin32::switchToFullScreen(bool reset) +{ + if (!CreationParams.Fullscreen) + return true; + + if (reset) + { + if (ChangedToFullScreen) + { + return (ChangeDisplaySettings(&DesktopMode,0)==DISP_CHANGE_SUCCESSFUL); + } + else + return true; + } + + // use default values from current setting + + DEVMODE dm; + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + + EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm); + dm.dmPelsWidth = CreationParams.WindowSize.Width; + dm.dmPelsHeight = CreationParams.WindowSize.Height; + dm.dmBitsPerPel = CreationParams.Bits; + dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; + + LONG res = ChangeDisplaySettings(&dm, CDS_FULLSCREEN); + if (res != DISP_CHANGE_SUCCESSFUL) + { // try again without forcing display frequency + dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; + res = ChangeDisplaySettings(&dm, CDS_FULLSCREEN); + } + + bool ret = false; + switch(res) + { + case DISP_CHANGE_SUCCESSFUL: + ChangedToFullScreen = true; + ret = true; + break; + case DISP_CHANGE_RESTART: + os::Printer::log("Switch to fullscreen: The computer must be restarted in order for the graphics mode to work.", ELL_ERROR); + break; + case DISP_CHANGE_BADFLAGS: + os::Printer::log("Switch to fullscreen: An invalid set of flags was passed in.", ELL_ERROR); + break; + case DISP_CHANGE_BADPARAM: + os::Printer::log("Switch to fullscreen: An invalid parameter was passed in. This can include an invalid flag or combination of flags.", ELL_ERROR); + break; + case DISP_CHANGE_FAILED: + os::Printer::log("Switch to fullscreen: The display driver failed the specified graphics mode.", ELL_ERROR); + break; + case DISP_CHANGE_BADMODE: + os::Printer::log("Switch to fullscreen: The graphics mode is not supported.", ELL_ERROR); + break; + default: + os::Printer::log("An unknown error occurred while changing to fullscreen.", ELL_ERROR); + break; + } + return ret; +} + + +//! returns the win32 cursor control +CIrrDeviceWin32::CCursorControl* CIrrDeviceWin32::getWin32CursorControl() +{ + return Win32CursorControl; +} + + +//! \return Returns a pointer to a list with all video modes supported +//! by the gfx adapter. +video::IVideoModeList* CIrrDeviceWin32::getVideoModeList() +{ + if (!VideoModeList->getVideoModeCount()) + { + // enumerate video modes. + DWORD i=0; + DEVMODE mode; + memset(&mode, 0, sizeof(mode)); + mode.dmSize = sizeof(mode); + + while (EnumDisplaySettings(NULL, i, &mode)) + { + 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)); + } + + return VideoModeList; +} + +typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD); +// Needed for old windows apis +// depending on the SDK version and compilers some defines might be available +// or not +#ifndef PRODUCT_ULTIMATE +#define PRODUCT_ULTIMATE 0x00000001 +#define PRODUCT_HOME_BASIC 0x00000002 +#define PRODUCT_HOME_PREMIUM 0x00000003 +#define PRODUCT_ENTERPRISE 0x00000004 +#define PRODUCT_HOME_BASIC_N 0x00000005 +#define PRODUCT_BUSINESS 0x00000006 +#define PRODUCT_STARTER 0x0000000B +#endif +#ifndef PRODUCT_ULTIMATE_N +#define PRODUCT_BUSINESS_N 0x00000010 +#define PRODUCT_HOME_PREMIUM_N 0x0000001A +#define PRODUCT_ENTERPRISE_N 0x0000001B +#define PRODUCT_ULTIMATE_N 0x0000001C +#endif +#ifndef PRODUCT_STARTER_N +#define PRODUCT_STARTER_N 0x0000002F +#endif +#ifndef PRODUCT_PROFESSIONAL +#define PRODUCT_PROFESSIONAL 0x00000030 +#define PRODUCT_PROFESSIONAL_N 0x00000031 +#endif +#ifndef PRODUCT_ULTIMATE_E +#define PRODUCT_STARTER_E 0x00000042 +#define PRODUCT_HOME_BASIC_E 0x00000043 +#define PRODUCT_HOME_PREMIUM_E 0x00000044 +#define PRODUCT_PROFESSIONAL_E 0x00000045 +#define PRODUCT_ENTERPRISE_E 0x00000046 +#define PRODUCT_ULTIMATE_E 0x00000047 +#endif + +void CIrrDeviceWin32::getWindowsVersion(core::stringc& out) +{ + OSVERSIONINFOEX osvi; + PGPI pGPI; + BOOL bOsVersionInfoEx; + + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + + bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO*) &osvi); + if (!bOsVersionInfoEx) + { + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if (! GetVersionEx((OSVERSIONINFO *) &osvi)) + return; + } + + switch (osvi.dwPlatformId) + { + case VER_PLATFORM_WIN32_NT: + if (osvi.dwMajorVersion <= 4) + out.append("Microsoft Windows NT "); + else + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) + out.append("Microsoft Windows 2000 "); + else + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) + out.append("Microsoft Windows XP "); + else + if (osvi.dwMajorVersion == 6 ) + { + if (osvi.dwMinorVersion == 0) + { + if (osvi.wProductType == VER_NT_WORKSTATION) + out.append("Microsoft Windows Vista "); + else + out.append("Microsoft Windows Server 2008 "); + } + else if (osvi.dwMinorVersion == 1) + { + if (osvi.wProductType == VER_NT_WORKSTATION) + out.append("Microsoft Windows 7 "); + else + out.append("Microsoft Windows Server 2008 R2 "); + } + else if (osvi.dwMinorVersion == 2) + { + out.append("Microsoft Windows 8 or later "); + } + } + + if (bOsVersionInfoEx) + { + if (osvi.dwMajorVersion == 6) + { + DWORD dwType; + pGPI = (PGPI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetProductInfo"); + pGPI(osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType); + + switch (dwType) + { + case PRODUCT_ULTIMATE: + case PRODUCT_ULTIMATE_E: + case PRODUCT_ULTIMATE_N: + out.append("Ultimate Edition "); + break; + case PRODUCT_PROFESSIONAL: + case PRODUCT_PROFESSIONAL_E: + case PRODUCT_PROFESSIONAL_N: + out.append("Professional Edition "); + break; + case PRODUCT_HOME_BASIC: + case PRODUCT_HOME_BASIC_E: + case PRODUCT_HOME_BASIC_N: + out.append("Home Basic Edition "); + break; + case PRODUCT_HOME_PREMIUM: + case PRODUCT_HOME_PREMIUM_E: + case PRODUCT_HOME_PREMIUM_N: + out.append("Home Premium Edition "); + break; + case PRODUCT_ENTERPRISE: + case PRODUCT_ENTERPRISE_E: + case PRODUCT_ENTERPRISE_N: + out.append("Enterprise Edition "); + break; + case PRODUCT_BUSINESS: + case PRODUCT_BUSINESS_N: + out.append("Business Edition "); + break; + case PRODUCT_STARTER: + case PRODUCT_STARTER_E: + case PRODUCT_STARTER_N: + out.append("Starter Edition "); + break; + } + } +#ifdef VER_SUITE_ENTERPRISE + else + if (osvi.wProductType == VER_NT_WORKSTATION) + { +#ifndef __BORLANDC__ + if( osvi.wSuiteMask & VER_SUITE_PERSONAL ) + out.append("Personal "); + else + out.append("Professional "); +#endif + } + else if (osvi.wProductType == VER_NT_SERVER) + { + if( osvi.wSuiteMask & VER_SUITE_DATACENTER ) + out.append("DataCenter Server "); + else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) + out.append("Advanced Server "); + else + out.append("Server "); + } +#endif + } + else + { + HKEY hKey; + char szProductType[80]; + DWORD dwBufLen; + + RegOpenKeyEx( HKEY_LOCAL_MACHINE, + __TEXT("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"), + 0, KEY_QUERY_VALUE, &hKey ); + RegQueryValueEx( hKey, __TEXT("ProductType"), NULL, NULL, + (LPBYTE) szProductType, &dwBufLen); + RegCloseKey( hKey ); + + + if (irr::core::stringc("WINNT").equals_ignore_case(szProductType)) + out.append("Professional "); + if (irr::core::stringc("LANMANNT").equals_ignore_case(szProductType)) + out.append("Server "); + if (irr::core::stringc("SERVERNT").equals_ignore_case(szProductType)) + out.append("Advanced Server "); + } + + // Display version, service pack (if any), and build number. + + char tmp[255]; + + if (osvi.dwMajorVersion <= 4 ) + { + sprintf(tmp, "version %lu.%lu %s (Build %lu)", + osvi.dwMajorVersion, + osvi.dwMinorVersion, + irr::core::stringc(osvi.szCSDVersion).c_str(), + osvi.dwBuildNumber & 0xFFFF); + } + else + { + sprintf(tmp, "%s (Build %lu)", irr::core::stringc(osvi.szCSDVersion).c_str(), + osvi.dwBuildNumber & 0xFFFF); + } + + out.append(tmp); + break; + + case VER_PLATFORM_WIN32_WINDOWS: + + if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) + { + out.append("Microsoft Windows 95 "); + if ( osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B' ) + out.append("OSR2 " ); + } + + if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) + { + out.append("Microsoft Windows 98 "); + if ( osvi.szCSDVersion[1] == 'A' ) + out.append( "SE " ); + } + + if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) + out.append("Microsoft Windows Me "); + + break; + + case VER_PLATFORM_WIN32s: + out.append("Microsoft Win32s "); + break; + } +} + +//! Notifies the device, that it has been resized +void CIrrDeviceWin32::OnResized() +{ + Resized = true; +} + +//! Resize the render window. +void CIrrDeviceWin32::setWindowSize(const irr::core::dimension2d& size) +{ + if (ExternalWindow || !getVideoDriver() || CreationParams.Fullscreen) + return; + + // get size of the window for the give size of the client area + DWORD style = static_cast(GetWindowLongPtr(HWnd, GWL_STYLE)); + DWORD exStyle = static_cast(GetWindowLongPtr(HWnd, GWL_EXSTYLE)); + RECT clientSize; + clientSize.top = 0; + clientSize.left = 0; + clientSize.right = size.Width; + clientSize.bottom = size.Height; + AdjustWindowRectEx(&clientSize, style, false, exStyle); + const s32 realWidth = clientSize.right - clientSize.left; + const s32 realHeight = clientSize.bottom - clientSize.top; + + UINT flags = SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER; + SetWindowPos(HWnd, HWND_TOP, 0, 0, realWidth, realHeight, flags); +} + +//! Sets if the window should be resizable in windowed mode. +void CIrrDeviceWin32::setResizable(bool resize) +{ + if (ExternalWindow || !getVideoDriver() || CreationParams.Fullscreen) + return; + + LONG_PTR style = (LONG_PTR)getWindowStyle(false, resize); + if (!SetWindowLongPtr(HWnd, GWL_STYLE, style)) + os::Printer::log("Could not change window style."); + + RECT clientSize; + clientSize.top = 0; + clientSize.left = 0; + clientSize.right = getVideoDriver()->getScreenSize().Width; + clientSize.bottom = getVideoDriver()->getScreenSize().Height; + + AdjustWindowRect(&clientSize, static_cast(style), FALSE); + + const s32 realWidth = clientSize.right - clientSize.left; + const s32 realHeight = clientSize.bottom - clientSize.top; + + const s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2; + const s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2; + + SetWindowPos(HWnd, HWND_TOP, windowLeft, windowTop, realWidth, realHeight, + SWP_FRAMECHANGED | SWP_NOMOVE | SWP_SHOWWINDOW); + + static_cast(CursorControl)->updateBorderSize(CreationParams.Fullscreen, resize); +} + + +//! Minimizes the window. +void CIrrDeviceWin32::minimizeWindow() +{ + WINDOWPLACEMENT wndpl; + wndpl.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement(HWnd, &wndpl); + wndpl.showCmd = SW_SHOWMINNOACTIVE; + SetWindowPlacement(HWnd, &wndpl); +} + + +//! Maximizes the window. +void CIrrDeviceWin32::maximizeWindow() +{ + WINDOWPLACEMENT wndpl; + wndpl.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement(HWnd, &wndpl); + wndpl.showCmd = SW_SHOWMAXIMIZED; + SetWindowPlacement(HWnd, &wndpl); +} + + +//! Restores the window to its original size. +void CIrrDeviceWin32::restoreWindow() +{ + WINDOWPLACEMENT wndpl; + wndpl.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement(HWnd, &wndpl); + wndpl.showCmd = SW_SHOWNORMAL; + SetWindowPlacement(HWnd, &wndpl); +} + +core::position2di CIrrDeviceWin32::getWindowPosition() +{ + WINDOWPLACEMENT wndpl; + wndpl.length = sizeof(WINDOWPLACEMENT); + if (GetWindowPlacement(HWnd, &wndpl)) + { + return core::position2di((int)wndpl.rcNormalPosition.left, + (int)wndpl.rcNormalPosition.top); + } + else + { + // No reason for this to happen + os::Printer::log("Failed to retrieve window location", ELL_ERROR); + return core::position2di(-1, -1); + } +} + +bool CIrrDeviceWin32::activateJoysticks(core::array & joystickInfo) +{ + if (JoyControl) + return JoyControl->activateJoysticks(joystickInfo); + else + return false; +} + + +//! Set the current Gamma Value for the Display +bool CIrrDeviceWin32::setGammaRamp( f32 red, f32 green, f32 blue, f32 brightness, f32 contrast ) +{ + bool r; + u16 ramp[3][256]; + + calculateGammaRamp( ramp[0], red, brightness, contrast ); + calculateGammaRamp( ramp[1], green, brightness, contrast ); + calculateGammaRamp( ramp[2], blue, brightness, contrast ); + + HDC dc = GetDC(0); + r = SetDeviceGammaRamp ( dc, ramp ) == TRUE; + ReleaseDC(HWnd, dc); + return r; +} + +//! Get the current Gamma Value for the Display +bool CIrrDeviceWin32::getGammaRamp( f32 &red, f32 &green, f32 &blue, f32 &brightness, f32 &contrast ) +{ + bool r; + u16 ramp[3][256]; + + HDC dc = GetDC(0); + r = GetDeviceGammaRamp ( dc, ramp ) == TRUE; + ReleaseDC(HWnd, dc); + + if (r) + { + calculateGammaFromRamp(red, ramp[0]); + calculateGammaFromRamp(green, ramp[1]); + calculateGammaFromRamp(blue, ramp[2]); + } + + brightness = 0.f; + contrast = 0.f; + + return r; +} + + +//! Process system events +void CIrrDeviceWin32::handleSystemMessages() +{ + MSG msg; + + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (ExternalWindow && msg.hwnd == HWnd) + { + if (msg.hwnd == HWnd) + { + WndProc(HWnd, msg.message, msg.wParam, msg.lParam); + } + else + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + else + { + // No message translation because we don't use WM_CHAR and it would conflict with our + // deadkey handling. + DispatchMessage(&msg); + } + + if (msg.message == WM_QUIT) + Close = true; + } +} + + +//! Remove all messages pending in the system message loop +void CIrrDeviceWin32::clearSystemMessages() +{ + MSG msg; + while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)) + {} + while (PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE)) + {} +} + +// shows last error in a messagebox to help internal debugging. +void CIrrDeviceWin32::ReportLastWinApiError() +{ + // (based on code from ovidiucucu from http://www.codeguru.com/forum/showthread.php?t=318721) + LPCTSTR pszCaption = __TEXT("Windows SDK Error Report"); + DWORD dwError = GetLastError(); + + if(NOERROR == dwError) + { + MessageBox(NULL, __TEXT("No error"), pszCaption, MB_OK); + } + else + { + const DWORD dwFormatControl = FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_FROM_SYSTEM; + + LPVOID pTextBuffer = NULL; + DWORD dwCount = FormatMessage(dwFormatControl, + NULL, + dwError, + 0, + (LPTSTR) &pTextBuffer, + 0, + NULL); + if(0 != dwCount) + { + MessageBox(NULL, (LPCTSTR)pTextBuffer, pszCaption, MB_OK|MB_ICONERROR); + LocalFree(pTextBuffer); + } + else + { + MessageBox(NULL, __TEXT("Unknown error"), pszCaption, MB_OK|MB_ICONERROR); + } + } +} + +// Same function Windows offers in VersionHelpers.h, but we can't use that as it's not available in older sdk's (minimum is SDK 8.1) +bool CIrrDeviceWin32::isWindowsVistaOrGreater() +{ +#if (_WIN32_WINNT >= 0x0500) + OSVERSIONINFOEX osvi; + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + osvi.dwMajorVersion = 6; // Windows Vista + + if ( !GetVersionEx((OSVERSIONINFO*)&osvi) ) + { + return false; + } + + return VerifyVersionInfo(&osvi, VER_MAJORVERSION, VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL)) ? true : false; +#else + return false; +#endif +} + +// Convert an Irrlicht texture to a Windows cursor +// Based on http://www.codeguru.com/cpp/w-p/win32/cursors/article.php/c4529/ +HCURSOR CIrrDeviceWin32::TextureToCursor(HWND hwnd, irr::video::ITexture * tex, const core::rect& sourceRect, const core::position2d &hotspot) +{ + // + // create the bitmaps needed for cursors from the texture + + HDC dc = GetDC(hwnd); + HDC andDc = CreateCompatibleDC(dc); + HDC xorDc = CreateCompatibleDC(dc); + HBITMAP andBitmap = CreateCompatibleBitmap(dc, sourceRect.getWidth(), sourceRect.getHeight()); + HBITMAP xorBitmap = CreateCompatibleBitmap(dc, sourceRect.getWidth(), sourceRect.getHeight()); + + HBITMAP oldAndBitmap = (HBITMAP)SelectObject(andDc, andBitmap); + HBITMAP oldXorBitmap = (HBITMAP)SelectObject(xorDc, xorBitmap); + + + video::ECOLOR_FORMAT format = tex->getColorFormat(); + u32 bytesPerPixel = video::IImage::getBitsPerPixelFromFormat(format) / 8; + u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel; + u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel; + const u8* data = (const u8*)tex->lock(video::ETLM_READ_ONLY, 0); + data += sourceRect.UpperLeftCorner.Y*tex->getPitch(); + for ( s32 y = 0; y < sourceRect.getHeight(); ++y ) + { + data += bytesLeftGap; + for ( s32 x = 0; x < sourceRect.getWidth(); ++x ) + { + video::SColor pixelCol; + pixelCol.setData((const void*)data, format); + data += bytesPerPixel; + + if ( pixelCol.getAlpha() == 0 ) // transparent + { + SetPixel(andDc, x, y, RGB(255,255,255)); + SetPixel(xorDc, x, y, RGB(0,0,0)); + } + else // color + { + SetPixel(andDc, x, y, RGB(0,0,0)); + SetPixel(xorDc, x, y, RGB(pixelCol.getRed(), pixelCol.getGreen(), pixelCol.getBlue())); + } + } + data += bytesRightGap; + } + tex->unlock(); + + SelectObject(andDc, oldAndBitmap); + SelectObject(xorDc, oldXorBitmap); + + DeleteDC(xorDc); + DeleteDC(andDc); + + ReleaseDC(hwnd, dc); + + // create the cursor + + ICONINFO iconinfo; + iconinfo.fIcon = false; // type is cursor not icon + iconinfo.xHotspot = hotspot.X; + iconinfo.yHotspot = hotspot.Y; + iconinfo.hbmMask = andBitmap; + iconinfo.hbmColor = xorBitmap; + + HCURSOR cursor = CreateIconIndirect(&iconinfo); + + DeleteObject(andBitmap); + DeleteObject(xorBitmap); + + return cursor; +} + + +CIrrDeviceWin32::CCursorControl::CCursorControl(CIrrDeviceWin32* device, const core::dimension2d& wsize, HWND hwnd, bool fullscreen) + : Device(device), WindowSize(wsize), InvWindowSize(0.0f, 0.0f), + HWnd(hwnd), BorderX(0), BorderY(0), + UseReferenceRect(false), IsVisible(true) + , ActiveIcon(gui::ECI_NORMAL), ActiveIconStartTime(0) +{ + if (WindowSize.Width!=0) + InvWindowSize.Width = 1.0f / WindowSize.Width; + + if (WindowSize.Height!=0) + InvWindowSize.Height = 1.0f / WindowSize.Height; + + updateBorderSize(fullscreen, false); + initCursors(); +} + +CIrrDeviceWin32::CCursorControl::~CCursorControl() +{ + for ( u32 i=0; i < Cursors.size(); ++i ) + { + for ( u32 f=0; f < Cursors[i].Frames.size(); ++f ) + { + DestroyCursor(Cursors[i].Frames[f].IconHW); + } + } +} + + +void CIrrDeviceWin32::CCursorControl::initCursors() +{ + Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_ARROW)) ); + Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_CROSS)) ); + Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_HAND)) ); + Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_HELP)) ); + Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_IBEAM)) ); + Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_NO)) ); + Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_WAIT)) ); + Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZEALL)) ); + Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENESW)) ); + Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENWSE)) ); + Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENS)) ); + Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZEWE)) ); + Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_UPARROW)) ); +} + + +void CIrrDeviceWin32::CCursorControl::update() +{ + if ( !Cursors[ActiveIcon].Frames.empty() && Cursors[ActiveIcon].FrameTime ) + { + // update animated cursors. This could also be done by X11 in case someone wants to figure that out (this way was just easier to implement) + u32 now = Device->getTimer()->getRealTime(); + u32 frame = ((now - ActiveIconStartTime) / Cursors[ActiveIcon].FrameTime) % Cursors[ActiveIcon].Frames.size(); + SetCursor( Cursors[ActiveIcon].Frames[frame].IconHW ); + } +} + +//! Sets the active cursor icon +void CIrrDeviceWin32::CCursorControl::setActiveIcon(gui::ECURSOR_ICON iconId) +{ + if ( iconId >= (s32)Cursors.size() ) + return; + + ActiveIcon = iconId; + ActiveIconStartTime = Device->getTimer()->getRealTime(); + if ( Cursors[ActiveIcon].Frames.size() ) + SetCursor( Cursors[ActiveIcon].Frames[0].IconHW ); +} + + +//! Add a custom sprite as cursor icon. +gui::ECURSOR_ICON CIrrDeviceWin32::CCursorControl::addIcon(const gui::SCursorSprite& icon) +{ + if ( icon.SpriteId >= 0 ) + { + CursorW32 cW32; + cW32.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime; + + for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i ) + { + irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber; + irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber; + irr::core::rect rectIcon = icon.SpriteBank->getPositions()[rectId]; + + HCURSOR hc = Device->TextureToCursor(HWnd, icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot); + cW32.Frames.push_back( CursorFrameW32(hc) ); + } + + Cursors.push_back( cW32 ); + return (gui::ECURSOR_ICON)(Cursors.size() - 1); + } + return gui::ECI_NORMAL; +} + + +//! replace the given cursor icon. +void CIrrDeviceWin32::CCursorControl::changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite& icon) +{ + if ( iconId >= (s32)Cursors.size() ) + return; + + for ( u32 i=0; i < Cursors[iconId].Frames.size(); ++i ) + DestroyCursor(Cursors[iconId].Frames[i].IconHW); + + if ( icon.SpriteId >= 0 ) + { + CursorW32 cW32; + cW32.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime; + for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i ) + { + irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber; + irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber; + irr::core::rect rectIcon = icon.SpriteBank->getPositions()[rectId]; + + HCURSOR hc = Device->TextureToCursor(HWnd, icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot); + cW32.Frames.push_back( CursorFrameW32(hc) ); + } + + Cursors[iconId] = cW32; + } +} + + +//! Return a system-specific size which is supported for cursors. Larger icons will fail, smaller icons might work. +core::dimension2di CIrrDeviceWin32::CCursorControl::getSupportedIconSize() const +{ + core::dimension2di result; + + result.Width = GetSystemMetrics(SM_CXCURSOR); + result.Height = GetSystemMetrics(SM_CYCURSOR); + + return result; +} + + + +} // end namespace + +#endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_ diff --git a/source/Irrlicht/CIrrDeviceWin32.h b/source/Irrlicht/CIrrDeviceWin32.h new file mode 100644 index 00000000..b32da282 --- /dev/null +++ b/source/Irrlicht/CIrrDeviceWin32.h @@ -0,0 +1,439 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_IRR_DEVICE_WIN32_H_INCLUDED__ +#define __C_IRR_DEVICE_WIN32_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ + +#include "CIrrDeviceStub.h" +#include "IrrlichtDevice.h" +#include "IImagePresenter.h" + +#define WIN32_LEAN_AND_MEAN +#if !defined(_IRR_XBOX_PLATFORM_) + #include + #include // For JOYCAPS + #include +#endif +#if !defined(GET_X_LPARAM) +#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp)) +#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp)) +#endif + +namespace irr +{ + struct SJoystickWin32Control; + + class CIrrDeviceWin32 : public CIrrDeviceStub, video::IImagePresenter + { + friend struct SJoystickWin32Control; + public: + + //! constructor + CIrrDeviceWin32(const SIrrlichtCreationParameters& params); + + //! destructor + virtual ~CIrrDeviceWin32(); + + //! runs the device. Returns false if device wants to be deleted + virtual bool run() _IRR_OVERRIDE_; + + //! Cause the device to temporarily pause execution and let other processes to run + // This should bring down processor usage without major performance loss for Irrlicht + virtual void yield() _IRR_OVERRIDE_; + + //! Pause execution and let other processes to run for a specified amount of time. + virtual void sleep(u32 timeMs, bool pauseTimer) _IRR_OVERRIDE_; + + //! sets the caption of the window + virtual void setWindowCaption(const wchar_t* text) _IRR_OVERRIDE_; + + //! returns if window is active. if not, nothing need to be drawn + virtual bool isWindowActive() const _IRR_OVERRIDE_; + + //! returns if window has focus + virtual bool isWindowFocused() const _IRR_OVERRIDE_; + + //! returns if window is minimized + virtual bool isWindowMinimized() const _IRR_OVERRIDE_; + + //! presents a surface in the client area + virtual bool present(video::IImage* surface, void* windowId=0, core::rect* src=0) _IRR_OVERRIDE_; + + //! notifies the device that it should close itself + virtual void closeDevice() _IRR_OVERRIDE_; + + //! \return Returns a pointer to a list with all video modes + //! supported by the gfx adapter. + virtual video::IVideoModeList* getVideoModeList() _IRR_OVERRIDE_; + + //! Notifies the device, that it has been resized + /** Must be publis as it is called from free function (event handler) */ + void OnResized(); + + //! Sets if the window should be resizable in windowed mode. + virtual void setResizable(bool resize=false) _IRR_OVERRIDE_; + + //! Resize the render window. + virtual void setWindowSize(const irr::core::dimension2d& size) _IRR_OVERRIDE_; + + //! Minimizes the window. + virtual void minimizeWindow() _IRR_OVERRIDE_; + + //! Maximizes the window. + virtual void maximizeWindow() _IRR_OVERRIDE_; + + //! Restores the window size. + virtual void restoreWindow() _IRR_OVERRIDE_; + + //! Get the position of the window on screen + virtual core::position2di getWindowPosition() _IRR_OVERRIDE_; + + //! Activate any joysticks, and generate events for them. + virtual bool activateJoysticks(core::array & joystickInfo) _IRR_OVERRIDE_; + + //! Set the current Gamma Value for the Display + virtual bool setGammaRamp( f32 red, f32 green, f32 blue, f32 brightness, f32 contrast ) _IRR_OVERRIDE_; + + //! Get the current Gamma Value for the Display + virtual bool getGammaRamp( f32 &red, f32 &green, f32 &blue, f32 &brightness, f32 &contrast ) _IRR_OVERRIDE_; + + //! Remove all messages pending in the system message loop + virtual void clearSystemMessages() _IRR_OVERRIDE_; + + //! Get the device type + virtual E_DEVICE_TYPE getType() const _IRR_OVERRIDE_ + { + return EIDT_WIN32; + } + + //! Compares to the last call of this function to return double and triple clicks. + //! \return Returns only 1,2 or 3. A 4th click will start with 1 again. + virtual u32 checkSuccessiveClicks(s32 mouseX, s32 mouseY, EMOUSE_INPUT_EVENT inputEvent ) _IRR_OVERRIDE_ + { + // we just have to make it public + return CIrrDeviceStub::checkSuccessiveClicks(mouseX, mouseY, inputEvent ); + } + + //! Switch to fullscreen + bool switchToFullScreen(bool reset=false); + + //! Check for and show last Windows API error to help internal debugging. + //! Does call GetLastError and on errors formats the error text and displays it in a messagebox. + static void ReportLastWinApiError(); + + //! Same function Windows offers in VersionHelpers.h, but we can't use that as it's not available before SDK 8.1 + static bool isWindowsVistaOrGreater(); + + // convert an Irrlicht texture to a windows cursor + HCURSOR TextureToCursor(HWND hwnd, irr::video::ITexture * tex, const core::rect& sourceRect, const core::position2d &hotspot); + + //! Implementation of the win32 cursor control + class CCursorControl : public gui::ICursorControl + { + public: + + CCursorControl(CIrrDeviceWin32* device, const core::dimension2d& wsize, HWND hwnd, bool fullscreen); + ~CCursorControl(); + + //! Changes the visible state of the mouse cursor. + virtual void setVisible(bool visible) _IRR_OVERRIDE_ + { + CURSORINFO info; + info.cbSize = sizeof(CURSORINFO); + BOOL gotCursorInfo = GetCursorInfo(&info); + while ( gotCursorInfo ) + { +#ifdef CURSOR_SUPPRESSED + // new flag for Windows 8, where cursor + // might be suppressed for touch interface + if (info.flags == CURSOR_SUPPRESSED) + { + visible=false; + break; + } +#endif + if ( (visible && info.flags == CURSOR_SHOWING) || // visible + (!visible && info.flags == 0 ) ) // hidden + { + break; + } + // this only increases an internal + // display counter in windows, so it + // might have to be called some more + const int showResult = ShowCursor(visible); + // if result has correct sign we can + // stop here as well + if (( !visible && showResult < 0 ) || + (visible && showResult >= 0)) + break; + // yes, it really must be set each time + info.cbSize = sizeof(CURSORINFO); + gotCursorInfo = GetCursorInfo(&info); + } + IsVisible = visible; + } + + //! Returns if the cursor is currently visible. + virtual bool isVisible() const _IRR_OVERRIDE_ + { + return IsVisible; + } + + //! Sets the new position of the cursor. + virtual void setPosition(const core::position2d &pos) _IRR_OVERRIDE_ + { + setPosition(pos.X, pos.Y); + } + + //! Sets the new position of the cursor. + virtual void setPosition(f32 x, f32 y) _IRR_OVERRIDE_ + { + if (!UseReferenceRect) + setPosition(core::round32(x*WindowSize.Width), core::round32(y*WindowSize.Height)); + else + setPosition(core::round32(x*ReferenceRect.getWidth()), core::round32(y*ReferenceRect.getHeight())); + } + + //! Sets the new position of the cursor. + virtual void setPosition(const core::position2d &pos) _IRR_OVERRIDE_ + { + setPosition(pos.X, pos.Y); + } + + //! Sets the new position of the cursor. + virtual void setPosition(s32 x, s32 y) _IRR_OVERRIDE_ + { + if (UseReferenceRect) + { + 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); + } + + CursorPos.X = x; + CursorPos.Y = y; + } + + //! Returns the current position of the mouse cursor. + virtual const core::position2d& getPosition(bool updateCursor) _IRR_OVERRIDE_ + { + if ( updateCursor ) + updateInternalCursorPosition(); + return CursorPos; + } + + //! Returns the current position of the mouse cursor. + virtual core::position2d getRelativePosition(bool updateCursor) _IRR_OVERRIDE_ + { + if ( updateCursor ) + updateInternalCursorPosition(); + + if (!UseReferenceRect) + { + return core::position2d(CursorPos.X * InvWindowSize.Width, + CursorPos.Y * InvWindowSize.Height); + } + + return core::position2d(CursorPos.X / (f32)ReferenceRect.getWidth(), + CursorPos.Y / (f32)ReferenceRect.getHeight()); + } + + //! Sets an absolute reference rect for calculating the cursor position. + virtual void setReferenceRect(core::rect* rect=0) _IRR_OVERRIDE_ + { + if (rect) + { + ReferenceRect = *rect; + UseReferenceRect = true; + + // prevent division through zero and uneven sizes + + if (!ReferenceRect.getHeight() || ReferenceRect.getHeight()%2) + ReferenceRect.LowerRightCorner.Y += 1; + + if (!ReferenceRect.getWidth() || ReferenceRect.getWidth()%2) + ReferenceRect.LowerRightCorner.X += 1; + } + else + UseReferenceRect = false; + } + + /** Used to notify the cursor that the window was resized. */ + void OnResize(const core::dimension2d& size) + { + WindowSize = size; + if (size.Width!=0) + InvWindowSize.Width = 1.0f / size.Width; + else + InvWindowSize.Width = 0.f; + + if (size.Height!=0) + InvWindowSize.Height = 1.0f / size.Height; + else + InvWindowSize.Height = 0.f; + } + + /** Used to notify the cursor that the window resizable settings changed. */ + void updateBorderSize(bool fullscreen, bool resizable) + { + if (!fullscreen) + { + s32 paddingBorder = 0; + #if defined (SM_CXPADDEDBORDER) + if (CIrrDeviceWin32::isWindowsVistaOrGreater()) + paddingBorder = GetSystemMetrics(SM_CXPADDEDBORDER); + #endif + + if (resizable) + { + BorderX = GetSystemMetrics(SM_CXSIZEFRAME) + paddingBorder; + BorderY = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYSIZEFRAME) + paddingBorder; + } + else + { + BorderX = GetSystemMetrics(SM_CXDLGFRAME) + paddingBorder; + BorderY = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYDLGFRAME) + paddingBorder; + } + } + else + { + BorderX = BorderY = 0; + } + } + + + //! Sets the active cursor icon + virtual void setActiveIcon(gui::ECURSOR_ICON iconId) _IRR_OVERRIDE_; + + //! Gets the currently active icon + virtual gui::ECURSOR_ICON getActiveIcon() const _IRR_OVERRIDE_ + { + return ActiveIcon; + } + + //! Add a custom sprite as cursor icon. + virtual gui::ECURSOR_ICON addIcon(const gui::SCursorSprite& icon) _IRR_OVERRIDE_; + + //! replace the given cursor icon. + virtual void changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite& icon) _IRR_OVERRIDE_; + + //! Return a system-specific size which is supported for cursors. Larger icons will fail, smaller icons might work. + virtual core::dimension2di getSupportedIconSize() const _IRR_OVERRIDE_; + + void update(); + + private: + + //! Updates the internal cursor position + void updateInternalCursorPosition() + { + POINT p; + if (!GetCursorPos(&p)) + { + DWORD xy = GetMessagePos(); + p.x = GET_X_LPARAM(xy); + p.y = GET_Y_LPARAM(xy); + } + + if (UseReferenceRect) + { + CursorPos.X = p.x - ReferenceRect.UpperLeftCorner.X; + CursorPos.Y = p.y - ReferenceRect.UpperLeftCorner.Y; + } + else + { + RECT rect; + if (GetWindowRect(HWnd, &rect)) + { + CursorPos.X = p.x-rect.left-BorderX; + CursorPos.Y = p.y-rect.top-BorderY; + } + else + { + // window seems not to be existent, so set cursor to + // a negative value + CursorPos.X = -1; + CursorPos.Y = -1; + } + } + } + + CIrrDeviceWin32* Device; + core::position2d CursorPos; + core::dimension2d WindowSize; + core::dimension2d InvWindowSize; + HWND HWnd; + + s32 BorderX, BorderY; + core::rect ReferenceRect; + bool UseReferenceRect; + bool IsVisible; + + + struct CursorFrameW32 + { + CursorFrameW32() : IconHW(0) {} + CursorFrameW32(HCURSOR icon) : IconHW(icon) {} + + HCURSOR IconHW; // hardware cursor + }; + + struct CursorW32 + { + CursorW32() {} + explicit CursorW32(HCURSOR iconHw, u32 frameTime=0) : FrameTime(frameTime) + { + Frames.push_back( CursorFrameW32(iconHw) ); + } + core::array Frames; + u32 FrameTime; + }; + + core::array Cursors; + gui::ECURSOR_ICON ActiveIcon; + u32 ActiveIconStartTime; + + void initCursors(); + }; + + //! returns the win32 cursor control + CCursorControl* getWin32CursorControl(); + + private: + + //! create the driver + void createDriver(); + + //! Process system events + void handleSystemMessages(); + + void getWindowsVersion(core::stringc& version); + + void resizeIfNecessary(); + + DWORD getWindowStyle(bool fullscreen, bool resizable) const; + + HWND HWnd; + + bool ChangedToFullScreen; + bool Resized; + bool ExternalWindow; + CCursorControl* Win32CursorControl; + DEVMODE DesktopMode; + + SJoystickWin32Control* JoyControl; + }; + +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_ +#endif // __C_IRR_DEVICE_WIN32_H_INCLUDED__ diff --git a/source/Irrlicht/CIrrDeviceiOS.h b/source/Irrlicht/CIrrDeviceiOS.h new file mode 100644 index 00000000..6a80e410 --- /dev/null +++ b/source/Irrlicht/CIrrDeviceiOS.h @@ -0,0 +1,80 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2008 Redshift Software, Inc. +// Copyright (C) 2012-2015 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_IRR_DEVICE_IOS_H_INCLUDED__ +#define __C_IRR_DEVICE_IOS_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_IOS_DEVICE_ + +#include "CIrrDeviceStub.h" +#include "IrrlichtDevice.h" +#include "IImagePresenter.h" + +namespace irr +{ + + class CIrrDeviceiOS : public CIrrDeviceStub, public video::IImagePresenter + { + public: + CIrrDeviceiOS(const SIrrlichtCreationParameters& params); + virtual ~CIrrDeviceiOS(); + + virtual bool run() _IRR_OVERRIDE_; + virtual void yield() _IRR_OVERRIDE_; + virtual void sleep(u32 timeMs, bool pauseTimer) _IRR_OVERRIDE_; + + virtual void setWindowCaption(const wchar_t* text) _IRR_OVERRIDE_; + + virtual bool isWindowActive() const _IRR_OVERRIDE_; + virtual bool isWindowFocused() const _IRR_OVERRIDE_; + virtual bool isWindowMinimized() const _IRR_OVERRIDE_; + + virtual bool present(video::IImage* surface, void * windowId = 0, core::rect* src = 0) _IRR_OVERRIDE_; + + virtual void closeDevice() _IRR_OVERRIDE_; + + virtual void setResizable(bool resize = false) _IRR_OVERRIDE_; + + virtual void minimizeWindow() _IRR_OVERRIDE_; + virtual void maximizeWindow() _IRR_OVERRIDE_; + virtual void restoreWindow() _IRR_OVERRIDE_; + + virtual core::position2di getWindowPosition() _IRR_OVERRIDE_; + + virtual bool activateAccelerometer(float updateInterval = 0.016666f) _IRR_OVERRIDE_; + virtual bool deactivateAccelerometer() _IRR_OVERRIDE_; + virtual bool isAccelerometerActive() _IRR_OVERRIDE_; + virtual bool isAccelerometerAvailable() _IRR_OVERRIDE_; + virtual bool activateGyroscope(float updateInterval = 0.016666f) _IRR_OVERRIDE_; + virtual bool deactivateGyroscope() _IRR_OVERRIDE_; + virtual bool isGyroscopeActive() _IRR_OVERRIDE_; + virtual bool isGyroscopeAvailable() _IRR_OVERRIDE_; + virtual bool activateDeviceMotion(float updateInterval = 0.016666f) _IRR_OVERRIDE_; + virtual bool deactivateDeviceMotion() _IRR_OVERRIDE_; + virtual bool isDeviceMotionActive() _IRR_OVERRIDE_; + virtual bool isDeviceMotionAvailable() _IRR_OVERRIDE_; + + virtual E_DEVICE_TYPE getType() const _IRR_OVERRIDE_; + + private: + void createWindow(); + void createViewAndDriver(); + + void* DataStorage; + + bool Close; + }; + +} + +#ifdef _IRR_COMPILE_WITH_IOS_BUILTIN_MAIN_ +extern void irrlicht_main(); +#endif + +#endif +#endif diff --git a/source/Irrlicht/CIrrDeviceiOS.mm b/source/Irrlicht/CIrrDeviceiOS.mm new file mode 100644 index 00000000..8386e1e3 --- /dev/null +++ b/source/Irrlicht/CIrrDeviceiOS.mm @@ -0,0 +1,824 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2008 Redshift Software, Inc. +// Copyright (C) 2012 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#import "CIrrDeviceiOS.h" + +#ifdef _IRR_COMPILE_WITH_IOS_DEVICE_ + +#include "IFileSystem.h" +#include "CTimer.h" +#include "CEAGLManager.h" + +#import +#import + +/* Important information */ + +// The application state events and following methods: IrrlichtDevice::isWindowActive, IrrlichtDevice::isWindowFocused +// and IrrlichtDevice::isWindowMinimized works out of box only if you'll use built-in CIrrDelegateiOS, +// so _IRR_COMPILE_WITH_IOS_BUILTIN_MAIN_ must be enabled in this case. If you need a custom UIApplicationDelegate you must +// handle all application events yourself. + +#ifdef _IRR_COMPILE_WITH_IOS_BUILTIN_MAIN_ + +namespace irr +{ + class CIrrDeviceiOS; +} + +/* CIrrDelegateiOS */ + +@interface CIrrDelegateiOS : NSObject + +- (void)setDevice:(irr::CIrrDeviceiOS*)device; +- (bool)isActive; +- (bool)hasFocus; + +@property (strong, nonatomic) UIWindow* window; + +@end + +@implementation CIrrDelegateiOS +{ + irr::CIrrDeviceiOS* Device; + bool Active; + bool Focus; +} + +- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)options +{ + Device = nil; + Active = true; + Focus = false; + + [self performSelectorOnMainThread:@selector(runIrrlicht) withObject:nil waitUntilDone:NO]; + + return YES; +} + +- (void)applicationWillTerminate:(UIApplication*)application +{ + if (Device != nil) + { + irr::SEvent ev; + ev.EventType = irr::EET_APPLICATION_EVENT; + ev.ApplicationEvent.EventType = irr::EAET_WILL_TERMINATE; + + Device->postEventFromUser(ev); + + Device->closeDevice(); + } +} + +- (void)applicationDidReceiveMemoryWarning:(UIApplication*)application +{ + if (Device != nil) + { + irr::SEvent ev; + ev.EventType = irr::EET_APPLICATION_EVENT; + ev.ApplicationEvent.EventType = irr::EAET_MEMORY_WARNING; + + Device->postEventFromUser(ev); + } +} + +- (void)applicationWillResignActive:(UIApplication*)application +{ + if (Device != nil) + { + irr::SEvent ev; + ev.EventType = irr::EET_APPLICATION_EVENT; + ev.ApplicationEvent.EventType = irr::EAET_WILL_PAUSE; + + Device->postEventFromUser(ev); + } + + Focus = false; +} + +- (void)applicationDidEnterBackground:(UIApplication*)application +{ + if (Device != nil) + { + irr::SEvent ev; + ev.EventType = irr::EET_APPLICATION_EVENT; + ev.ApplicationEvent.EventType = irr::EAET_DID_PAUSE; + + Device->postEventFromUser(ev); + } + + Active = false; +} + +- (void)applicationWillEnterForeground:(UIApplication*)application +{ + if (Device != nil) + { + irr::SEvent ev; + ev.EventType = irr::EET_APPLICATION_EVENT; + ev.ApplicationEvent.EventType = irr::EAET_WILL_RESUME; + + Device->postEventFromUser(ev); + } + + Active = true; +} + +- (void)applicationDidBecomeActive:(UIApplication*)application +{ + if (Device != nil) + { + irr::SEvent ev; + ev.EventType = irr::EET_APPLICATION_EVENT; + ev.ApplicationEvent.EventType = irr::EAET_DID_RESUME; + + Device->postEventFromUser(ev); + } + + Focus = true; +} + +- (void)runIrrlicht +{ + irrlicht_main(); +} + +- (void)setDevice:(irr::CIrrDeviceiOS*)device +{ + Device = device; +} + +- (bool)isActive +{ + return Active; +} + +- (bool)hasFocus +{ + return Focus; +} + +@end + +#endif + +/* CIrrViewiOS */ + +@interface CIrrViewiOS : UIView + +- (id)initWithFrame:(CGRect)frame forDevice:(irr::CIrrDeviceiOS*)device; + +@end + +@implementation CIrrViewiOS +{ + irr::CIrrDeviceiOS* Device; + float Scale; +} + +- (id)initWithFrame:(CGRect)frame forDevice:(irr::CIrrDeviceiOS*)device; +{ + self = [super initWithFrame:frame]; + + if (self) + { + Device = device; + Scale = ([self respondsToSelector:@selector(setContentScaleFactor:)]) ? [[UIScreen mainScreen] scale] : 1.f; + } + + return self; +} + +- (BOOL)isMultipleTouchEnabled +{ + return YES; +} + +- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event +{ + irr::SEvent ev; + ev.EventType = irr::EET_TOUCH_INPUT_EVENT; + ev.TouchInput.Event = irr::ETIE_PRESSED_DOWN; + + for (UITouch* touch in touches) + { + ev.TouchInput.ID = (size_t)touch; + + CGPoint touchPoint = [touch locationInView:self]; + + ev.TouchInput.X = touchPoint.x*Scale; + ev.TouchInput.Y = touchPoint.y*Scale; + + Device->postEventFromUser(ev); + } +} + +- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event +{ + irr::SEvent ev; + ev.EventType = irr::EET_TOUCH_INPUT_EVENT; + ev.TouchInput.Event = irr::ETIE_MOVED; + + for (UITouch* touch in touches) + { + ev.TouchInput.ID = (size_t)touch; + + CGPoint touchPoint = [touch locationInView:self]; + + ev.TouchInput.X = touchPoint.x*Scale; + ev.TouchInput.Y = touchPoint.y*Scale; + + Device->postEventFromUser(ev); + } +} + +- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event +{ + irr::SEvent ev; + ev.EventType = irr::EET_TOUCH_INPUT_EVENT; + ev.TouchInput.Event = irr::ETIE_LEFT_UP; + + for (UITouch* touch in touches) + { + ev.TouchInput.ID = (size_t)touch; + + CGPoint touchPoint = [touch locationInView:self]; + + ev.TouchInput.X = touchPoint.x*Scale; + ev.TouchInput.Y = touchPoint.y*Scale; + + Device->postEventFromUser(ev); + } +} + +- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event +{ + irr::SEvent ev; + ev.EventType = irr::EET_TOUCH_INPUT_EVENT; + ev.TouchInput.Event = irr::ETIE_LEFT_UP; + + for (UITouch* touch in touches) + { + ev.TouchInput.ID = (size_t)touch; + + CGPoint touchPoint = [touch locationInView:self]; + + ev.TouchInput.X = touchPoint.x*Scale; + ev.TouchInput.Y = touchPoint.y*Scale; + + Device->postEventFromUser(ev); + } +} + +@end + +/* CIrrViewEAGLiOS */ + +@interface CIrrViewEAGLiOS : CIrrViewiOS + +@end + +@implementation CIrrViewEAGLiOS + ++ (Class)layerClass +{ + return [CAEAGLLayer class]; +} + +@end + +namespace irr +{ + namespace video + { + IVideoDriver* createOGLES1Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager); + + IVideoDriver* createOGLES2Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager); + } + + struct SIrrDeviceiOSDataStorage + { + SIrrDeviceiOSDataStorage() : Window(0), ViewController(0), View(0), MotionManager(0), ReferenceAttitude(0) + { + MotionManager = [[CMMotionManager alloc] init]; + } + + UIWindow* Window; + UIViewController* ViewController; + CIrrViewiOS* View; + CMMotionManager* MotionManager; + CMAttitude* ReferenceAttitude; + }; + + CIrrDeviceiOS::CIrrDeviceiOS(const SIrrlichtCreationParameters& params) : CIrrDeviceStub(params), DataStorage(0), Close(false) + { +#ifdef _DEBUG + setDebugName("CIrrDeviceiOS"); +#endif + +#ifdef _IRR_COMPILE_WITH_IOS_BUILTIN_MAIN_ + CIrrDelegateiOS* delegate = [UIApplication sharedApplication].delegate; + [delegate setDevice:this]; +#endif + + DataStorage = new SIrrDeviceiOSDataStorage(); + + FileSystem->changeWorkingDirectoryTo([[[NSBundle mainBundle] resourcePath] UTF8String]); + + createWindow(); + createViewAndDriver(); + + if (!VideoDriver) + return; + + createGUIAndScene(); + } + + CIrrDeviceiOS::~CIrrDeviceiOS() + { + deactivateDeviceMotion(); + deactivateGyroscope(); + deactivateAccelerometer(); + + delete static_cast(DataStorage); + +#ifdef _IRR_COMPILE_WITH_IOS_BUILTIN_MAIN_ + CIrrDelegateiOS* delegate = [UIApplication sharedApplication].delegate; + [delegate setDevice:nil]; +#endif + } + + bool CIrrDeviceiOS::run() + { + if (!Close) + { + const CFTimeInterval timeInSeconds = 0.000002; + + s32 result = 0; + + do + { + result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeInSeconds, TRUE); + } + while (result == kCFRunLoopRunHandledSource); + + os::Timer::tick(); + + //! Update events + + SIrrDeviceiOSDataStorage* dataStorage = static_cast(DataStorage); + CMMotionManager* motionManager = dataStorage->MotionManager; + + //! Accelerometer + if (motionManager.isAccelerometerActive) + { + irr::SEvent ev; + ev.EventType = irr::EET_ACCELEROMETER_EVENT; + ev.AccelerometerEvent.X = motionManager.accelerometerData.acceleration.x; + ev.AccelerometerEvent.Y = motionManager.accelerometerData.acceleration.y; + ev.AccelerometerEvent.Z = motionManager.accelerometerData.acceleration.z; + + postEventFromUser(ev); + } + + //! Gyroscope + if (motionManager.isGyroActive) + { + irr::SEvent ev; + ev.EventType = irr::EET_GYROSCOPE_EVENT; + ev.GyroscopeEvent.X = motionManager.gyroData.rotationRate.x; + ev.GyroscopeEvent.Y = motionManager.gyroData.rotationRate.y; + ev.GyroscopeEvent.Z = motionManager.gyroData.rotationRate.z; + + postEventFromUser(ev); + } + + //! Device Motion + if (motionManager.isDeviceMotionActive) + { + CMAttitude* currentAttitude = motionManager.deviceMotion.attitude; + CMAttitude* referenceAttitude = dataStorage->ReferenceAttitude; + + if (referenceAttitude != nil) + [currentAttitude multiplyByInverseOfAttitude: referenceAttitude]; + else + referenceAttitude = motionManager.deviceMotion.attitude; + + irr::SEvent ev; + ev.EventType = irr::EET_DEVICE_MOTION_EVENT; + ev.AccelerometerEvent.X = currentAttitude.roll; + ev.AccelerometerEvent.Y = currentAttitude.pitch; + ev.AccelerometerEvent.Z = currentAttitude.yaw; + + postEventFromUser(ev); + } + } + + return !Close; + } + + void CIrrDeviceiOS::yield() + { + struct timespec ts = {0,0}; + nanosleep(&ts, NULL); + } + + void CIrrDeviceiOS::sleep(u32 timeMs, bool pauseTimer=false) + { + bool wasStopped = Timer ? Timer->isStopped() : true; + + struct timespec ts; + ts.tv_sec = (time_t) (timeMs / 1000); + ts.tv_nsec = (long) (timeMs % 1000) * 1000000; + + if (pauseTimer && !wasStopped) + Timer->stop(); + + nanosleep(&ts, NULL); + + if (pauseTimer && !wasStopped) + Timer->start(); + } + + void CIrrDeviceiOS::setWindowCaption(const wchar_t* text) + { + } + + bool CIrrDeviceiOS::isWindowActive() const + { +#ifdef _IRR_COMPILE_WITH_IOS_BUILTIN_MAIN_ + CIrrDelegateiOS* delegate = [UIApplication sharedApplication].delegate; + + return [delegate isActive]; +#else + return false; +#endif + } + + bool CIrrDeviceiOS::isWindowFocused() const + { +#ifdef _IRR_COMPILE_WITH_IOS_BUILTIN_MAIN_ + CIrrDelegateiOS* delegate = [UIApplication sharedApplication].delegate; + + return [delegate hasFocus]; +#else + return false; +#endif + } + + bool CIrrDeviceiOS::isWindowMinimized() const + { +#ifdef _IRR_COMPILE_WITH_IOS_BUILTIN_MAIN_ + CIrrDelegateiOS* delegate = [UIApplication sharedApplication].delegate; + + return ![delegate isActive]; +#else + return false; +#endif + } + + bool CIrrDeviceiOS::present(video::IImage* image, void * windowId, core::rect* src) + { + return false; + } + + void CIrrDeviceiOS::closeDevice() + { + CFRunLoopStop(CFRunLoopGetMain()); + + Close = true; + } + + void CIrrDeviceiOS::setResizable(bool resize) + { + } + + void CIrrDeviceiOS::minimizeWindow() + { + } + + void CIrrDeviceiOS::maximizeWindow() + { + } + + void CIrrDeviceiOS::restoreWindow() + { + } + + core::position2di CIrrDeviceiOS::getWindowPosition() + { + return core::position2di(0, 0); + } + + bool CIrrDeviceiOS::activateAccelerometer(float updateInterval) + { + bool status = false; + + SIrrDeviceiOSDataStorage* dataStorage = static_cast(DataStorage); + CMMotionManager* motionManager = dataStorage->MotionManager; + + if (motionManager.isAccelerometerAvailable) + { + if (!motionManager.isAccelerometerActive) + { + motionManager.accelerometerUpdateInterval = updateInterval; + [motionManager startAccelerometerUpdates]; + } + + status = true; + } + + return status; + } + + bool CIrrDeviceiOS::deactivateAccelerometer() + { + bool status = false; + + SIrrDeviceiOSDataStorage* dataStorage = static_cast(DataStorage); + CMMotionManager* motionManager = dataStorage->MotionManager; + + if (motionManager.isAccelerometerAvailable) + { + if (motionManager.isAccelerometerActive) + [motionManager stopAccelerometerUpdates]; + + status = true; + } + + return status; + } + + bool CIrrDeviceiOS::isAccelerometerActive() + { + SIrrDeviceiOSDataStorage* dataStorage = static_cast(DataStorage); + + return (dataStorage->MotionManager.isAccelerometerActive); + } + + bool CIrrDeviceiOS::isAccelerometerAvailable() + { + SIrrDeviceiOSDataStorage* dataStorage = static_cast(DataStorage); + + return (dataStorage->MotionManager.isAccelerometerAvailable); + } + + bool CIrrDeviceiOS::activateGyroscope(float updateInterval) + { + bool status = false; + + SIrrDeviceiOSDataStorage* dataStorage = static_cast(DataStorage); + CMMotionManager* motionManager = dataStorage->MotionManager; + + if (motionManager.isGyroAvailable) + { + if (!motionManager.isGyroActive) + { + motionManager.gyroUpdateInterval = updateInterval; + [motionManager startGyroUpdates]; + } + + status = true; + } + + return status; + } + + bool CIrrDeviceiOS::deactivateGyroscope() + { + bool status = false; + + SIrrDeviceiOSDataStorage* dataStorage = static_cast(DataStorage); + CMMotionManager* motionManager = dataStorage->MotionManager; + + if (motionManager.isGyroAvailable) + { + if (motionManager.isGyroActive) + [motionManager stopGyroUpdates]; + + status = true; + } + + return status; + } + + bool CIrrDeviceiOS::isGyroscopeActive() + { + SIrrDeviceiOSDataStorage* dataStorage = static_cast(DataStorage); + + return (dataStorage->MotionManager.isGyroActive); + } + + bool CIrrDeviceiOS::isGyroscopeAvailable() + { + SIrrDeviceiOSDataStorage* dataStorage = static_cast(DataStorage); + + return (dataStorage->MotionManager.isGyroAvailable); + } + + bool CIrrDeviceiOS::activateDeviceMotion(float updateInterval) + { + bool status = false; + + SIrrDeviceiOSDataStorage* dataStorage = static_cast(DataStorage); + CMMotionManager* motionManager = dataStorage->MotionManager; + + if (motionManager.isDeviceMotionAvailable) + { + if (!motionManager.isDeviceMotionActive) + { + dataStorage->ReferenceAttitude = nil; + + motionManager.deviceMotionUpdateInterval = updateInterval; + [motionManager startDeviceMotionUpdates]; + } + + status = true; + } + + return status; + } + + bool CIrrDeviceiOS::deactivateDeviceMotion() + { + bool status = false; + + SIrrDeviceiOSDataStorage* dataStorage = static_cast(DataStorage); + CMMotionManager* motionManager = dataStorage->MotionManager; + + if (motionManager.isDeviceMotionAvailable) + { + if (motionManager.isDeviceMotionActive) + { + [motionManager stopDeviceMotionUpdates]; + + dataStorage->ReferenceAttitude = nil; + } + + status = true; + } + + return status; + } + + bool CIrrDeviceiOS::isDeviceMotionActive() + { + SIrrDeviceiOSDataStorage* dataStorage = static_cast(DataStorage); + + return (dataStorage->MotionManager.isDeviceMotionActive); + } + + bool CIrrDeviceiOS::isDeviceMotionAvailable() + { + SIrrDeviceiOSDataStorage* dataStorage = static_cast(DataStorage); + + return (dataStorage->MotionManager.isDeviceMotionAvailable); + } + + E_DEVICE_TYPE CIrrDeviceiOS::getType() const + { + return EIDT_IOS; + } + + void CIrrDeviceiOS::createWindow() + { + if (CreationParams.DriverType != video::EDT_NULL) + { + SIrrDeviceiOSDataStorage* dataStorage = static_cast(DataStorage); + + UIView* externalView = (__bridge UIView*)CreationParams.WindowId; + + if (externalView == nil) + { + dataStorage->Window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + dataStorage->ViewController = [[UIViewController alloc] init]; + dataStorage->Window.rootViewController = dataStorage->ViewController; + + [dataStorage->Window makeKeyAndVisible]; + } + else + { + dataStorage->Window = externalView.window; + + UIResponder* currentResponder = externalView.nextResponder; + + do + { + if ([currentResponder isKindOfClass:[UIViewController class]]) + { + dataStorage->ViewController = (UIViewController*)currentResponder; + + currentResponder = nil; + } + else if ([currentResponder isKindOfClass:[UIView class]]) + { + currentResponder = currentResponder.nextResponder; + } + else + { + currentResponder = nil; + + // Could not find view controller. + _IRR_DEBUG_BREAK_IF(true); + } + } + while (currentResponder != nil); + } + } + } + + void CIrrDeviceiOS::createViewAndDriver() + { + SIrrDeviceiOSDataStorage* dataStorage = static_cast(DataStorage); + + video::SExposedVideoData data; + data.OpenGLiOS.Window = (__bridge void*)dataStorage->Window; + data.OpenGLiOS.ViewController = (__bridge void*)dataStorage->ViewController; + + UIView* externalView = (__bridge UIView*)CreationParams.WindowId; + + CGRect resolution = (externalView == nil) ? [[UIScreen mainScreen] bounds] : externalView.bounds; + + switch (CreationParams.DriverType) + { + case video::EDT_OGLES1: +#ifdef _IRR_COMPILE_WITH_OGLES1_ + { + CIrrViewEAGLiOS* view = [[CIrrViewEAGLiOS alloc] initWithFrame:resolution forDevice:this]; + CreationParams.WindowSize = core::dimension2d(view.frame.size.width, view.frame.size.height); + + dataStorage->View = view; + data.OpenGLiOS.View = (__bridge void*)view; + + ContextManager = new video::CEAGLManager(); + ContextManager->initialize(CreationParams, data); + + VideoDriver = video::createOGLES1Driver(CreationParams, FileSystem, ContextManager); + + if (!VideoDriver) + os::Printer::log("Could not create OpenGL ES 1.x driver.", ELL_ERROR); + } +#else + os::Printer::log("No OpenGL ES 1.x support compiled in.", ELL_ERROR); +#endif + break; + + case video::EDT_OGLES2: +#ifdef _IRR_COMPILE_WITH_OGLES2_ + { + CIrrViewEAGLiOS* view = [[CIrrViewEAGLiOS alloc] initWithFrame:resolution forDevice:this]; + CreationParams.WindowSize = core::dimension2d(view.frame.size.width, view.frame.size.height); + + dataStorage->View = view; + data.OpenGLiOS.View = (__bridge void*)view; + + ContextManager = new video::CEAGLManager(); + ContextManager->initialize(CreationParams, data); + + VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager); + + if (!VideoDriver) + os::Printer::log("Could not create OpenGL ES 2.x driver.", ELL_ERROR); + } +#else + os::Printer::log("No OpenGL ES 2.x support compiled in.", ELL_ERROR); +#endif + break; + + case video::EDT_SOFTWARE: + case video::EDT_BURNINGSVIDEO: + case video::DEPRECATED_EDT_DIRECT3D8_NO_LONGER_EXISTS: + case video::EDT_DIRECT3D9: + case video::EDT_OPENGL: + os::Printer::log("This driver is not available in iOS. Try OpenGL ES.", ELL_ERROR); + break; + + case video::EDT_NULL: + VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize); + break; + + default: + os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR); + break; + } + + if (externalView == nil) + dataStorage->ViewController.view = dataStorage->View; + else + [externalView addSubview:dataStorage->View]; + } +} + +#ifdef _IRR_COMPILE_WITH_IOS_BUILTIN_MAIN_ +int main(int argc, char** argv) +{ + int result = UIApplicationMain(argc, argv, 0, NSStringFromClass([CIrrDelegateiOS class])); + + return result; +} +#endif + +#endif diff --git a/source/Irrlicht/CIrrMeshFileLoader.cpp b/source/Irrlicht/CIrrMeshFileLoader.cpp new file mode 100644 index 00000000..f92b2dc8 --- /dev/null +++ b/source/Irrlicht/CIrrMeshFileLoader.cpp @@ -0,0 +1,556 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_IRR_MESH_LOADER_ + +#include "CIrrMeshFileLoader.h" +#include "os.h" +#include "IXMLReader.h" +#include "SAnimatedMesh.h" +#include "fast_atof.h" +#include "IReadFile.h" +#include "IAttributes.h" +#include "IMeshSceneNode.h" +#include "CDynamicMeshBuffer.h" +#include "SMeshBufferLightMap.h" + +namespace irr +{ +namespace scene +{ + + +//! Constructor +CIrrMeshFileLoader::CIrrMeshFileLoader(scene::ISceneManager* smgr, + io::IFileSystem* fs) + : SceneManager(smgr), FileSystem(fs) +{ + + #ifdef _DEBUG + setDebugName("CIrrMeshFileLoader"); + #endif + +} + + +//! Returns true if the file maybe is able to be loaded by this class. +/** This decision should be based only on the file extension (e.g. ".cob") */ +bool CIrrMeshFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "xml", "irrmesh" ); +} + + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IReferenceCounted::drop() for more information. +IAnimatedMesh* CIrrMeshFileLoader::createMesh(io::IReadFile* file) +{ + io::IXMLReader* reader = FileSystem->createXMLReader(file); + if (!reader) + return 0; + + // read until mesh section, skip other parts + + const core::stringc meshTagName = "mesh"; + IAnimatedMesh* mesh = 0; + + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (meshTagName == reader->getNodeName()) + { + mesh = readMesh(reader); + break; + } + else + skipSection(reader, true); // unknown section + } + } + + reader->drop(); + + return mesh; +} + + +//! reads a mesh sections and creates a mesh from it +IAnimatedMesh* CIrrMeshFileLoader::readMesh(io::IXMLReader* reader) +{ + SAnimatedMesh* animatedmesh = new SAnimatedMesh(); + SMesh* mesh = new SMesh(); + + animatedmesh->addMesh(mesh); + mesh->drop(); + + core::stringc bbSectionName = "boundingBox"; + core::stringc bufferSectionName = "buffer"; + core::stringc meshSectionName = "mesh"; + + if (!reader->isEmptyElement()) + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + const wchar_t* nodeName = reader->getNodeName(); + if (bbSectionName == nodeName) + { + // inside a bounding box, ignore it for now because + // we are calculating this anyway ourselves later. + } + else + if (bufferSectionName == nodeName) + { + // we've got a mesh buffer + + IMeshBuffer* buffer = readMeshBuffer(reader); + if (buffer) + { + mesh->addMeshBuffer(buffer); + buffer->drop(); + } + } + else + skipSection(reader, true); // unknown section + + } // end if node type is element + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + { + if (meshSectionName == reader->getNodeName()) + { + // end of mesh section reached, cancel out + break; + } + } + } // end while reader->read(); + + mesh->recalculateBoundingBox(); + animatedmesh->recalculateBoundingBox(); + + return animatedmesh; +} + + +//! reads a mesh sections and creates a mesh buffer from it +IMeshBuffer* CIrrMeshFileLoader::readMeshBuffer(io::IXMLReader* reader) +{ + CDynamicMeshBuffer* buffer = 0; + + core::stringc verticesSectionName = "vertices"; + core::stringc bbSectionName = "boundingBox"; + core::stringc materialSectionName = "material"; + core::stringc indicesSectionName = "indices"; + core::stringc bufferSectionName = "buffer"; + + bool insideVertexSection = false; + bool insideIndexSection = false; + + int vertexCount = 0; + int indexCount = 0; + + video::SMaterial material; + + if (!reader->isEmptyElement()) + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + const wchar_t* nodeName = reader->getNodeName(); + if (bbSectionName == nodeName) + { + // inside a bounding box, ignore it for now because + // we are calculating this anyway ourselves later. + } + else + if (materialSectionName == nodeName) + { + //we've got a material + + material = video::SMaterial(); // reset + + io::IAttributes* attributes = FileSystem->createEmptyAttributes(SceneManager->getVideoDriver()); + attributes->read(reader, true, L"material"); + + SceneManager->getVideoDriver()->fillMaterialStructureFromAttributes(material, attributes); + attributes->drop(); + } + else + if (verticesSectionName == nodeName) + { + // vertices section + + const core::stringc vertexTypeName1 = "standard"; + const core::stringc vertexTypeName2 = "2tcoords"; + const core::stringc vertexTypeName3 = "tangents"; + + const wchar_t* vertexType = reader->getAttributeValue(L"type"); + vertexCount = reader->getAttributeValueAsInt(L"vertexCount"); + + insideVertexSection = true; + + video::E_INDEX_TYPE itype = (vertexCount > 65536)?irr::video::EIT_32BIT:irr::video::EIT_16BIT; + if (vertexTypeName1 == vertexType) + { + buffer = new CDynamicMeshBuffer(irr::video::EVT_STANDARD, itype); + + } + else + if (vertexTypeName2 == vertexType) + { + buffer = new CDynamicMeshBuffer(irr::video::EVT_2TCOORDS, itype); + } + else + if (vertexTypeName3 == vertexType) + { + buffer = new CDynamicMeshBuffer(irr::video::EVT_TANGENTS, itype); + } + buffer->getVertexBuffer().reallocate(vertexCount); + buffer->Material = material; + } + else + if (indicesSectionName == nodeName) + { + // indices section + + indexCount = reader->getAttributeValueAsInt(L"indexCount"); + insideIndexSection = true; + } + + } // end if node type is element + else + if (reader->getNodeType() == io::EXN_TEXT) + { + // read vertex data + if (insideVertexSection) + { + readMeshBuffer(reader, vertexCount, buffer); + insideVertexSection = false; + + } // end reading vertex array + else + if (insideIndexSection) + { + readIndices(reader, indexCount, buffer->getIndexBuffer()); + insideIndexSection = false; + } + + } // end if node type is text + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + { + if (bufferSectionName == reader->getNodeName()) + { + // end of buffer section reached, cancel out + break; + } + } + } // end while reader->read(); + + if (buffer) + buffer->recalculateBoundingBox(); + + return buffer; +} + + +//! read indices +void CIrrMeshFileLoader::readIndices(io::IXMLReader* reader, int indexCount, IIndexBuffer& indices) +{ + indices.reallocate(indexCount); + + core::stringc data = reader->getNodeData(); + const c8* p = &data[0]; + + for (int i=0; igetNodeData(); + const c8* p = &data[0]; + scene::IVertexBuffer& Vertices = sbuffer->getVertexBuffer(); + video::E_VERTEX_TYPE vType = Vertices.getType(); + + if (sbuffer) + { + for (int i=0; igetNodeName()).c_str()); +#endif + + // skip if this element is empty anyway. + if (reader->isEmptyElement()) + return; + + // read until we've reached the last element in this section + u32 tagCounter = 1; + + while(tagCounter && reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT && + !reader->isEmptyElement()) + { + #ifdef _DEBUG + if (reportSkipping) + os::Printer::log("irrMesh unknown element:", core::stringc(reader->getNodeName()).c_str()); + #endif + + ++tagCounter; + } + else + if (reader->getNodeType() == io::EXN_ELEMENT_END) + --tagCounter; + } +} + + +//! parses a float from a char pointer and moves the pointer +//! to the end of the parsed float +inline f32 CIrrMeshFileLoader::readFloat(const c8** p) +{ + f32 ftmp; + *p = core::fast_atof_move(*p, ftmp); + return ftmp; +} + + +//! parses an int from a char pointer and moves the pointer to +//! the end of the parsed float +inline s32 CIrrMeshFileLoader::readInt(const c8** p) +{ + return (s32)readFloat(p); +} + + +//! places pointer to next begin of a token +void CIrrMeshFileLoader::skipCurrentNoneWhiteSpace(const c8** start) +{ + const c8* p = *start; + + while(*p && !(*p==' ' || *p=='\n' || *p=='\r' || *p=='\t')) + ++p; + + // TODO: skip comments + + *start = p; +} + +//! places pointer to next begin of a token +void CIrrMeshFileLoader::findNextNoneWhiteSpace(const c8** start) +{ + const c8* p = *start; + + while(*p && (*p==' ' || *p=='\n' || *p=='\r' || *p=='\t')) + ++p; + + // TODO: skip comments + + *start = p; +} + + +//! reads floats from inside of xml element until end of xml element +void CIrrMeshFileLoader::readFloatsInsideElement(io::IXMLReader* reader, f32* floats, u32 count) +{ + if (reader->isEmptyElement()) + return; + + while(reader->read()) + { + // TODO: check for comments inside the element + // and ignore them. + + if (reader->getNodeType() == io::EXN_TEXT) + { + // parse float data + core::stringc data = reader->getNodeData(); + const c8* p = &data[0]; + + for (u32 i=0; igetNodeType() == io::EXN_ELEMENT_END) + break; // end parsing text + } +} + + + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_IRR_MESH_LOADER_ diff --git a/source/Irrlicht/CIrrMeshFileLoader.h b/source/Irrlicht/CIrrMeshFileLoader.h new file mode 100644 index 00000000..c190844a --- /dev/null +++ b/source/Irrlicht/CIrrMeshFileLoader.h @@ -0,0 +1,90 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_IRR_MESH_FILE_LOADER_H_INCLUDED__ +#define __C_IRR_MESH_FILE_LOADER_H_INCLUDED__ + +#include "IMeshLoader.h" +#include "IFileSystem.h" +#include "IVideoDriver.h" +#include "irrString.h" +#include "SMesh.h" +#include "SMeshBuffer.h" +#include "CDynamicMeshBuffer.h" +#include "ISceneManager.h" + +namespace irr +{ +namespace scene +{ + + +//! Meshloader capable of loading .irrmesh meshes, the Irrlicht Engine mesh format for static meshes +class CIrrMeshFileLoader : public IMeshLoader +{ +public: + + //! Constructor + CIrrMeshFileLoader(scene::ISceneManager* smgr, io::IFileSystem* fs); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".cob") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! creates/loads an animated mesh from the file. + //! \return Pointer to the created mesh. Returns 0 if loading failed. + //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). + //! See IReferenceCounted::drop() for more information. + virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_; + +private: + + //! reads a mesh sections and creates a mesh from it + IAnimatedMesh* readMesh(io::IXMLReader* reader); + + //! reads a mesh sections and creates a mesh buffer from it + IMeshBuffer* readMeshBuffer(io::IXMLReader* reader); + + //! skips an (unknown) section in the irrmesh file + void skipSection(io::IXMLReader* reader, bool reportSkipping); + + //! reads a element and stores it in the material section + void readMaterial(io::IXMLReader* reader); + + //! parses a float from a char pointer and moves the pointer to + //! the end of the parsed float + inline f32 readFloat(const c8** p); + + //! parses an int from a char pointer and moves the pointer to + //! the end of the parsed float + inline s32 readInt(const c8** p); + + //! places pointer to next begin of a token + void findNextNoneWhiteSpace(const c8** p); + + //! places pointer to next begin of a token + void skipCurrentNoneWhiteSpace(const c8** p); + + //! reads floats from inside of xml element until end of xml element + void readFloatsInsideElement(io::IXMLReader* reader, f32* floats, u32 count); + + //! read the mesh buffers + void readMeshBuffer(io::IXMLReader* reader, int vertexCount, CDynamicMeshBuffer* sbuffer); + + //! read indices + void readIndices(io::IXMLReader* reader, int indexCount, IIndexBuffer& indices); + + + // member variables + + scene::ISceneManager* SceneManager; + io::IFileSystem* FileSystem; +}; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CIrrMeshWriter.cpp b/source/Irrlicht/CIrrMeshWriter.cpp new file mode 100644 index 00000000..cb33fe95 --- /dev/null +++ b/source/Irrlicht/CIrrMeshWriter.cpp @@ -0,0 +1,312 @@ +// Copyright (C) 2002-2012 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" + +#ifdef _IRR_COMPILE_WITH_IRR_WRITER_ + +#include "CIrrMeshWriter.h" +#include "os.h" +#include "IWriteFile.h" +#include "IXMLWriter.h" +#include "IMesh.h" +#include "IAttributes.h" + +namespace irr +{ +namespace scene +{ + + +CIrrMeshWriter::CIrrMeshWriter(video::IVideoDriver* driver, + io::IFileSystem* fs) + : FileSystem(fs), VideoDriver(driver), Writer(0) +{ + #ifdef _DEBUG + setDebugName("CIrrMeshWriter"); + #endif + + if (VideoDriver) + VideoDriver->grab(); + + if (FileSystem) + FileSystem->grab(); +} + + +CIrrMeshWriter::~CIrrMeshWriter() +{ + if (VideoDriver) + VideoDriver->drop(); + + if (FileSystem) + FileSystem->drop(); +} + + +//! Returns the type of the mesh writer +EMESH_WRITER_TYPE CIrrMeshWriter::getType() const +{ + return EMWT_IRR_MESH; +} + + +//! writes a mesh +bool CIrrMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags) +{ + if (!file) + return false; + + Writer = FileSystem->createXMLWriter(file); + + if (!Writer) + { + os::Printer::log("Could not write file", file->getFileName()); + return false; + } + + os::Printer::log("Writing mesh", file->getFileName()); + + // write IRR MESH header + + Writer->writeXMLHeader(); + + Writer->writeElement(L"mesh", false, + L"xmlns", L"http://irrlicht.sourceforge.net/IRRMESH_09_2007", + L"version", L"1.0"); + Writer->writeLineBreak(); + + // add some informational comment. Add a space after and before the comment + // tags so that some braindead xml parsers (AS anyone?) are able to parse this too. + + core::stringw infoComment = L" This file contains a static mesh in the Irrlicht Engine format with "; + infoComment += core::stringw(mesh->getMeshBufferCount()); + infoComment += L" materials."; + + Writer->writeComment(infoComment.c_str()); + Writer->writeLineBreak(); + + // write mesh bounding box + + writeBoundingBox(mesh->getBoundingBox()); + Writer->writeLineBreak(); + + // write mesh buffers + + for (int i=0; i<(int)mesh->getMeshBufferCount(); ++i) + { + scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i); + if (buffer) + { + writeMeshBuffer(buffer); + Writer->writeLineBreak(); + } + } + + Writer->writeClosingTag(L"mesh"); + + Writer->drop(); + return true; +} + + +void CIrrMeshWriter::writeBoundingBox(const core::aabbox3df& box) +{ + Writer->writeElement(L"boundingBox", true, + L"minEdge", getVectorAsStringLine(box.MinEdge).c_str(), + L"maxEdge", getVectorAsStringLine(box.MaxEdge).c_str()); +} + + +core::stringw CIrrMeshWriter::getVectorAsStringLine(const core::vector3df& v) const +{ + core::stringw str; + + str = core::stringw(v.X); + str += L" "; + str += core::stringw(v.Y); + str += L" "; + str += core::stringw(v.Z); + + return str; +} + + +core::stringw CIrrMeshWriter::getVectorAsStringLine(const core::vector2df& v) const +{ + core::stringw str; + + str = core::stringw(v.X); + str += L" "; + str += core::stringw(v.Y); + + return str; +} + + +void CIrrMeshWriter::writeMeshBuffer(const scene::IMeshBuffer* buffer) +{ + Writer->writeElement(L"buffer", false); + Writer->writeLineBreak(); + + // write bounding box + + writeBoundingBox(buffer->getBoundingBox()); + Writer->writeLineBreak(); + + // write material + + writeMaterial(buffer->getMaterial()); + + // write vertices + + const core::stringw vertexTypeStr = video::sBuiltInVertexTypeNames[buffer->getVertexType()]; + + Writer->writeElement(L"vertices", false, + L"type", vertexTypeStr.c_str(), + L"vertexCount", core::stringw(buffer->getVertexCount()).c_str()); + + Writer->writeLineBreak(); + + u32 vertexCount = buffer->getVertexCount(); + + switch(buffer->getVertexType()) + { + case video::EVT_STANDARD: + { + video::S3DVertex* vtx = (video::S3DVertex*)buffer->getVertices(); + for (u32 j=0; jwriteText(str.c_str()); + Writer->writeLineBreak(); + } + } + break; + case video::EVT_2TCOORDS: + { + video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices(); + for (u32 j=0; jwriteText(str.c_str()); + Writer->writeLineBreak(); + } + } + break; + case video::EVT_TANGENTS: + { + video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices(); + for (u32 j=0; jwriteText(str.c_str()); + Writer->writeLineBreak(); + } + } + break; + } + + Writer->writeClosingTag(L"vertices"); + Writer->writeLineBreak(); + + // write indices + + Writer->writeElement(L"indices", false, + L"indexCount", core::stringw(buffer->getIndexCount()).c_str()); + + Writer->writeLineBreak(); + + int indexCount = (int)buffer->getIndexCount(); + + video::E_INDEX_TYPE iType = buffer->getIndexType(); + + const u16* idx16 = buffer->getIndices(); + const u32* idx32 = (u32*) buffer->getIndices(); + const int maxIndicesPerLine = 25; + + for (int i=0; iwriteText(str.c_str()); + } + else + { + core::stringw str((int)idx32[i]); + Writer->writeText(str.c_str()); + } + + if (i % maxIndicesPerLine == maxIndicesPerLine-1) + Writer->writeLineBreak(); + else + Writer->writeText(L" "); + } + + if ((indexCount-1) % maxIndicesPerLine != maxIndicesPerLine-1) + Writer->writeLineBreak(); + + Writer->writeClosingTag(L"indices"); + Writer->writeLineBreak(); + + // close buffer tag + + Writer->writeClosingTag(L"buffer"); +} + + +void CIrrMeshWriter::writeMaterial(const video::SMaterial& material) +{ + // simply use irrlichts built-in attribute serialization capabilities here: + + io::IAttributes* attributes = + VideoDriver->createAttributesFromMaterial(material); + + if (attributes) + { + attributes->write(Writer, false, L"material"); + attributes->drop(); + } +} + + +} // end namespace +} // end namespace + +#endif + diff --git a/source/Irrlicht/CIrrMeshWriter.h b/source/Irrlicht/CIrrMeshWriter.h new file mode 100644 index 00000000..c69d8bfd --- /dev/null +++ b/source/Irrlicht/CIrrMeshWriter.h @@ -0,0 +1,61 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_IRR_MESH_WRITER_H_INCLUDED__ +#define __IRR_IRR_MESH_WRITER_H_INCLUDED__ + +#include "IMeshWriter.h" +#include "S3DVertex.h" +#include "IVideoDriver.h" +#include "IFileSystem.h" +#include "IXMLWriter.h" + +namespace irr +{ + +namespace scene +{ + class IMeshBuffer; + + + //! class to write meshes, implementing a IrrMesh (.irrmesh, .xml) writer + /** This writer implementation has been originally developed for irrEdit and then + merged out to the Irrlicht Engine */ + class CIrrMeshWriter : public IMeshWriter + { + public: + + CIrrMeshWriter(video::IVideoDriver* driver, io::IFileSystem* fs); + virtual ~CIrrMeshWriter(); + + //! Returns the type of the mesh writer + virtual EMESH_WRITER_TYPE getType() const _IRR_OVERRIDE_; + + //! writes a mesh + virtual bool writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags=EMWF_NONE) _IRR_OVERRIDE_; + + protected: + + void writeBoundingBox(const core::aabbox3df& box); + + void writeMeshBuffer(const scene::IMeshBuffer* buffer); + + void writeMaterial(const video::SMaterial& material); + + core::stringw getVectorAsStringLine(const core::vector3df& v) const; + + core::stringw getVectorAsStringLine(const core::vector2df& v) const; + + // member variables: + + io::IFileSystem* FileSystem; + video::IVideoDriver* VideoDriver; + io::IXMLWriter* Writer; + }; + +} // end namespace +} // end namespace + +#endif + diff --git a/source/Irrlicht/CLMTSMeshFileLoader.cpp b/source/Irrlicht/CLMTSMeshFileLoader.cpp new file mode 100644 index 00000000..b972ec51 --- /dev/null +++ b/source/Irrlicht/CLMTSMeshFileLoader.cpp @@ -0,0 +1,380 @@ +// Copyright (C) 2002-2012 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. +// See CLMTSMeshFileLoder.h for details. +/* + +CLMTSMeshFileLoader.cpp + +LMTSMeshFileLoader +Written by Jonas Petersen (a.k.a. jox) + +Version 1.5 - 15 March 2005 + +Get the latest version here: http://development.mindfloaters.de/ + +This class allows loading meshes with lightmaps (*.lmts + *.tga files) that were created +using Pulsar LMTools by Lord Trancos (http://www.geocities.com/dxlab/index_en.html) + +Notes: +- This version does not support user data in the *.lmts files, but still loads those files (by skipping the extra data). + +License: +-------- + +It's free. You are encouraged to give me credit if you use it in your software. + +Version History: +---------------- + +Version 1.5 - 15 March 2005 +- Did a better cleanup. No memory leaks in case of an loading error. +- Added "#include " for sprintf. + +Version 1.4 - 12 March 2005 +- Fixed bug in texture and subset loading code that would possibly cause crash. +- Fixed memory cleanup to avoid leak when loading more then one mesh +- Used the irrlicht Logger instead of cerr to output warnings and errors. + For this I had to change the constructor + from: + CLMTSMeshFileLoader(io::IFileSystem* fs, video::IVideoDriver* driver) + to: + CLMTSMeshFileLoader(IrrlichtDevice* device) + +Version 1.3 - 15 February 2005 +- Fixed bug that prevented loading more than one different lmts files. +- Removed unnecessary "#include ". +- Added "std::" in front of "cerr". This was necessary for Visual Studio .NET, + I hope it's not disturbing other compilers. +- Added warning message when a texture can not be loaded. +- Changed the documentation a bit (minor). + +Version 1.2 +- To avoid confusion I skipped version 1.2 because the website was offering +version 1.2 even though it was only version 1.1. Sorry about that. + +Version 1.1 - 29 July 2004 +- Added setTexturePath() function +- Minor improvements + +Version 1.0 - 29 July 2004 +- Initial release + + +*/ +////////////////////////////////////////////////////////////////////// + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_LMTS_LOADER_ + +#include "CLMTSMeshFileLoader.h" +#include "CMeshTextureLoader.h" +#include "SMeshBufferLightMap.h" +#include "SAnimatedMesh.h" +#include "SMeshBuffer.h" +#include "irrString.h" +#include "IReadFile.h" +#include "IAttributes.h" +#include "ISceneManager.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + +CLMTSMeshFileLoader::CLMTSMeshFileLoader(io::IFileSystem* fs, + video::IVideoDriver* driver, io::IAttributes* parameters) + : Textures(0), Subsets(0), Triangles(0), + Parameters(parameters), Driver(driver), FileSystem(fs), FlipEndianess(false) +{ + #ifdef _DEBUG + setDebugName("CLMTSMeshFileLoader"); + #endif + + if (Driver) + Driver->grab(); + + if (FileSystem) + FileSystem->grab(); + + TextureLoader = new CMeshTextureLoader( FileSystem, Driver ); +} + + +CLMTSMeshFileLoader::~CLMTSMeshFileLoader() +{ + cleanup(); + + if (Driver) + Driver->drop(); + + if (FileSystem) + FileSystem->drop(); +} + + +void CLMTSMeshFileLoader::cleanup() +{ + delete [] Textures; + Textures = 0; + delete [] Subsets; + Subsets = 0; + delete [] Triangles; + Triangles = 0; +} + + +bool CLMTSMeshFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "lmts" ); +} + + +IAnimatedMesh* CLMTSMeshFileLoader::createMesh(io::IReadFile* file) +{ + if ( getMeshTextureLoader() ) + getMeshTextureLoader()->setMeshFile(file); + + u32 i; + u32 id; + + // HEADER + + file->read(&Header, sizeof(SLMTSHeader)); + if (Header.MagicID == 0x4C4D5354) + { + FlipEndianess = true; + Header.MagicID = os::Byteswap::byteswap(Header.MagicID); + Header.Version = os::Byteswap::byteswap(Header.Version); + Header.HeaderSize = os::Byteswap::byteswap(Header.HeaderSize); + Header.TextureCount = os::Byteswap::byteswap(Header.TextureCount); + Header.SubsetCount = os::Byteswap::byteswap(Header.SubsetCount); + Header.TriangleCount = os::Byteswap::byteswap(Header.TriangleCount); + Header.SubsetSize = os::Byteswap::byteswap(Header.SubsetSize); + Header.VertexSize = os::Byteswap::byteswap(Header.VertexSize); + } + if (Header.MagicID != 0x53544D4C) { // "LMTS" + os::Printer::log("LMTS ERROR: wrong header magic id!", ELL_ERROR); + return 0; + } + + //Skip any User Data (arbitrary app specific data) + + const s32 userSize = Header.HeaderSize - sizeof(SLMTSHeader); + if (userSize>0) + file->seek(userSize,true); + + // TEXTURES + + file->read(&id, sizeof(u32)); + if (FlipEndianess) + id = os::Byteswap::byteswap(id); + if (id != 0x54584554) { // "TEXT" + os::Printer::log("LMTS ERROR: wrong texture magic id!", ELL_ERROR); + return 0; + } + + Textures = new SLMTSTextureInfoEntry[Header.TextureCount]; + + file->read(Textures, sizeof(SLMTSTextureInfoEntry)*Header.TextureCount); + if (FlipEndianess) + { + for (i=0; iread(&id, sizeof(u32)); + if (FlipEndianess) + id = os::Byteswap::byteswap(id); + if (id != 0x53425553) // "SUBS" + { + os::Printer::log("LMTS ERROR: wrong subset magic id!", ELL_ERROR); + cleanup(); + return 0; + } + + Subsets = new SLMTSSubsetInfoEntry[Header.SubsetCount]; + const s32 subsetUserSize = Header.SubsetSize - sizeof(SLMTSSubsetInfoEntry); + + for (i=0; iread(&Subsets[i], sizeof(SLMTSSubsetInfoEntry)); + if (FlipEndianess) + { + Subsets[i].Offset = os::Byteswap::byteswap(Subsets[i].Offset); + Subsets[i].Count = os::Byteswap::byteswap(Subsets[i].Count); + Subsets[i].TextID1 = os::Byteswap::byteswap(Subsets[i].TextID1); + Subsets[i].TextID2 = os::Byteswap::byteswap(Subsets[i].TextID2); + } + if (subsetUserSize>0) + file->seek(subsetUserSize,true); + } + + // TRIANGLES + + file->read(&id, sizeof(u32)); + if (FlipEndianess) + id = os::Byteswap::byteswap(id); + if (id != 0x53495254) // "TRIS" + { + os::Printer::log("LMTS ERROR: wrong triangle magic id!", ELL_ERROR); + cleanup(); + return 0; + } + + Triangles = new SLMTSTriangleDataEntry[(Header.TriangleCount*3)]; + const s32 triUserSize = Header.VertexSize - sizeof(SLMTSTriangleDataEntry); + + for (i=0; i<(Header.TriangleCount*3); ++i) + { + file->read(&Triangles[i], sizeof(SLMTSTriangleDataEntry)); + if (FlipEndianess) + { + Triangles[i].X = os::Byteswap::byteswap(Triangles[i].X); + Triangles[i].Y = os::Byteswap::byteswap(Triangles[i].Y); + Triangles[i].Z = os::Byteswap::byteswap(Triangles[i].Z); + Triangles[i].U1 = os::Byteswap::byteswap(Triangles[i].U1); + Triangles[i].V1 = os::Byteswap::byteswap(Triangles[i].U2); + Triangles[i].U2 = os::Byteswap::byteswap(Triangles[i].V1); + Triangles[i].V2 = os::Byteswap::byteswap(Triangles[i].V2); + } + if (triUserSize>0) + file->seek(triUserSize,true); + } + + ///////////////////////////////////////////////////////////////// + + SMesh* mesh = new SMesh(); + + constructMesh(mesh); + + loadTextures(mesh); + + cleanup(); + + SAnimatedMesh* am = new SAnimatedMesh(); + am->Type = EAMT_LMTS; // not unknown to irrlicht anymore + + am->addMesh(mesh); + am->recalculateBoundingBox(); + mesh->drop(); + return am; +} + + +void CLMTSMeshFileLoader::constructMesh(SMesh* mesh) +{ + for (s32 i=0; iMaterial.MaterialType = video::EMT_LIGHTMAP; + meshBuffer->Material.Wireframe = false; + meshBuffer->Material.Lighting = false; + + mesh->addMeshBuffer(meshBuffer); + + const u32 offs = Subsets[i].Offset * 3; + + for (u32 sc=0; scgetVertexCount(); + + for (u32 vu=0; vu<3; ++vu) + { + const SLMTSTriangleDataEntry& v = Triangles[offs+(3*sc)+vu]; + meshBuffer->Vertices.push_back( + video::S3DVertex2TCoords( + v.X, v.Y, v.Z, + video::SColor(255,255,255,255), + v.U1, v.V1, v.U2, v.V2)); + } + const core::vector3df normal = core::plane3df( + meshBuffer->Vertices[idx].Pos, + meshBuffer->Vertices[idx+1].Pos, + meshBuffer->Vertices[idx+2].Pos).Normal; + + meshBuffer->Vertices[idx].Normal = normal; + meshBuffer->Vertices[idx+1].Normal = normal; + meshBuffer->Vertices[idx+2].Normal = normal; + + meshBuffer->Indices.push_back(idx); + meshBuffer->Indices.push_back(idx+1); + meshBuffer->Indices.push_back(idx+2); + } + meshBuffer->drop(); + } + + for (u32 j=0; jMeshBuffers.size(); ++j) + mesh->MeshBuffers[j]->recalculateBoundingBox(); + + mesh->recalculateBoundingBox(); +} + + +void CLMTSMeshFileLoader::loadTextures(SMesh* mesh) +{ + if (!Driver || !FileSystem) + return; + + // load textures + + // a little too much space, but won't matter here + core::array tex; + tex.reallocate(Header.TextureCount); + core::array lig; + lig.reallocate(Header.TextureCount); + core::array id2id; + id2id.reallocate(Header.TextureCount); + + if ( getMeshTextureLoader() ) + { + if ( Parameters->existsAttribute(LMTS_TEXTURE_PATH) ) + getMeshTextureLoader()->setTexturePath(Parameters->getAttributeAsString(LMTS_TEXTURE_PATH)); + } + + core::stringc s; + for (u32 t=0; tgetTexture(Textures[t].Filename) : NULL; + if ( !tmptex ) + { + os::Printer::log("LMTS WARNING: Texture does not exist", s.c_str(), ELL_WARNING); + } + + if (Textures[t].Flags & 0x01) + { + id2id.push_back(lig.size()); + lig.push_back(tmptex); + } + else + { + id2id.push_back(tex.size()); + tex.push_back(tmptex); + } + } + + // attach textures to materials. + + for (u32 i=0; igetMeshBuffer(i)->getMaterial().setTexture(0, tex[id2id[Subsets[i].TextID1]]); + if (Subsets[i].TextID2 < Header.TextureCount && id2id[Subsets[i].TextID2] < lig.size()) + mesh->getMeshBuffer(i)->getMaterial().setTexture(1, lig[id2id[Subsets[i].TextID2]]); + + if (!mesh->getMeshBuffer(i)->getMaterial().getTexture(1)) + mesh->getMeshBuffer(i)->getMaterial().MaterialType = video::EMT_SOLID; + } +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_LMTS_LOADER_ diff --git a/source/Irrlicht/CLMTSMeshFileLoader.h b/source/Irrlicht/CLMTSMeshFileLoader.h new file mode 100644 index 00000000..b607f910 --- /dev/null +++ b/source/Irrlicht/CLMTSMeshFileLoader.h @@ -0,0 +1,109 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +// +// I (Nikolaus Gebhardt) did some few changes to Jonas Petersen's original loader: +// - removed setTexturePath() and replaced with the ISceneManager::getStringParameter()-stuff. +// - added EAMT_LMTS enumeration value +// Thanks a lot to Jonas Petersen for his work +// on this and that he gave me his permission to add it into Irrlicht. +/* + +CLMTSMeshFileLoader.h + +LMTSMeshFileLoader +Written by Jonas Petersen (a.k.a. jox) + +Version 1.5 - 15 March 2005 + +*/ + +#if !defined(__C_LMTS_MESH_FILE_LOADER_H_INCLUDED__) +#define __C_LMTS_MESH_FILE_LOADER_H_INCLUDED__ + +#include "IMeshLoader.h" +#include "SMesh.h" +#include "IFileSystem.h" +#include "IVideoDriver.h" + +namespace irr +{ +namespace scene +{ + +class CLMTSMeshFileLoader : public IMeshLoader +{ +public: + + CLMTSMeshFileLoader(io::IFileSystem* fs, + video::IVideoDriver* driver, io::IAttributes* parameters); + + virtual ~CLMTSMeshFileLoader(); + + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_; + +private: + void constructMesh(SMesh* mesh); + void loadTextures(SMesh* mesh); + void cleanup(); + +// byte-align structures +#include "irrpack.h" + + struct SLMTSHeader + { + u32 MagicID; + u32 Version; + u32 HeaderSize; + u16 TextureCount; + u16 SubsetCount; + u32 TriangleCount; + u16 SubsetSize; + u16 VertexSize; + } PACK_STRUCT; + + struct SLMTSTextureInfoEntry + { + c8 Filename[256]; + u16 Flags; + } PACK_STRUCT; + + struct SLMTSSubsetInfoEntry + { + u32 Offset; + u32 Count; + u16 TextID1; + u16 TextID2; + } PACK_STRUCT; + + struct SLMTSTriangleDataEntry + { + f32 X; + f32 Y; + f32 Z; + f32 U1; + f32 V1; + f32 U2; + f32 V2; + } PACK_STRUCT; + +// Default alignment +#include "irrunpack.h" + + SLMTSHeader Header; + SLMTSTextureInfoEntry* Textures; + SLMTSSubsetInfoEntry* Subsets; + SLMTSTriangleDataEntry* Triangles; + + io::IAttributes* Parameters; + video::IVideoDriver* Driver; + io::IFileSystem* FileSystem; + bool FlipEndianess; +}; + +} // end namespace scene +} // end namespace irr + +#endif // !defined(__C_LMTS_MESH_FILE_LOADER_H_INCLUDED__) diff --git a/source/Irrlicht/CLWOMeshFileLoader.cpp b/source/Irrlicht/CLWOMeshFileLoader.cpp new file mode 100644 index 00000000..ce158440 --- /dev/null +++ b/source/Irrlicht/CLWOMeshFileLoader.cpp @@ -0,0 +1,2115 @@ +// Copyright (C) 2007-2012 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" +#ifdef _IRR_COMPILE_WITH_LWO_LOADER_ + +#include "CLWOMeshFileLoader.h" +#include "CMeshTextureLoader.h" +#include "os.h" +#include "SAnimatedMesh.h" +#include "SMesh.h" +#include "IReadFile.h" +#include "ISceneManager.h" +#include "IFileSystem.h" +#include "IVideoDriver.h" +#include "IMeshManipulator.h" + +namespace irr +{ +namespace scene +{ + +#ifdef _DEBUG +#define LWO_READER_DEBUG +#endif + +#define charsToUIntD(a, b, c, d) ((a << 24) | (b << 16) | (c << 8) | d) +inline unsigned int charsToUInt(const char *str) +{ + return (str[0] << 24) | (str[1] << 16) | (str[2] << 8) | str[3]; +} + + +struct tLWOTextureInfo +{ + tLWOTextureInfo() : UVTag(0), DUVTag(0), Flags(0), WidthWrap(2), + HeightWrap(2), OpacType(0), Color(0xffffffff), + Value(0.0f), AntiAliasing(1.0f), Opacity(1.0f), + Axis(255), Projection(0), Active(false) {} + core::stringc Type; + core::stringc Map; + core::stringc AlphaMap; + core::stringc UVname; + u16 UVTag; + u16 DUVTag; + u16 Flags; + u16 WidthWrap; + u16 HeightWrap; + u16 OpacType; + u16 IParam[3]; + core::vector3df Size; + core::vector3df Center; + core::vector3df Falloff; + core::vector3df Velocity; + video::SColor Color; + f32 Value; + f32 AntiAliasing; + f32 Opacity; + f32 FParam[3]; + u8 Axis; + u8 Projection; + bool Active; +}; + +struct CLWOMeshFileLoader::tLWOMaterial +{ + tLWOMaterial() : Meshbuffer(0), TagType(0), Flags(0), ReflMode(3), TranspMode(3), + Glow(0), AlphaMode(2), Luminance(0.0f), Diffuse(1.0f), Specular(0.0f), + Reflection(0.0f), Transparency(0.0f), Translucency(0.0f), + Sharpness(0.0f), ReflSeamAngle(0.0f), ReflBlur(0.0f), + RefrIndex(1.0f), TranspBlur(0.0f), SmoothingAngle(0.0f), + EdgeTransparency(0.0f), HighlightColor(0.0f), ColorFilter(0.0f), + AdditiveTransparency(0.0f), GlowIntensity(0.0f), GlowSize(0.0f), + AlphaValue(0.0f), VertexColorIntensity(0.0f), VertexColor() {} + + core::stringc Name; + scene::SMeshBuffer *Meshbuffer; + core::stringc ReflMap; + u16 TagType; + u16 Flags; + u16 ReflMode; + u16 TranspMode; + u16 Glow; + u16 AlphaMode; + f32 Luminance; + f32 Diffuse; + f32 Specular; + f32 Reflection; + f32 Transparency; + f32 Translucency; + f32 Sharpness; + f32 ReflSeamAngle; + f32 ReflBlur; + f32 RefrIndex; + f32 TranspBlur; + f32 SmoothingAngle; + f32 EdgeTransparency; + f32 HighlightColor; + f32 ColorFilter; + f32 AdditiveTransparency; + f32 GlowIntensity; + f32 GlowSize; + f32 AlphaValue; + f32 VertexColorIntensity; + video::SColorf VertexColor; + u32 Envelope[23]; + tLWOTextureInfo Texture[7]; +}; + +struct tLWOLayerInfo +{ + u16 Number; + u16 Parent; + u16 Flags; + bool Active; + core::stringc Name; + core::vector3df Pivot; +}; + + +//! Constructor +CLWOMeshFileLoader::CLWOMeshFileLoader(scene::ISceneManager* smgr, + io::IFileSystem* fs) +: SceneManager(smgr), FileSystem(fs), File(0), Mesh(0) +{ + #ifdef _DEBUG + setDebugName("CLWOMeshFileLoader"); + #endif + + TextureLoader = new CMeshTextureLoader( FileSystem, SceneManager->getVideoDriver() ); +} + + +//! destructor +CLWOMeshFileLoader::~CLWOMeshFileLoader() +{ + if (Mesh) + Mesh->drop(); +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool CLWOMeshFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension(filename, "lwo"); +} + + +//! creates/loads an animated mesh from the file. +IAnimatedMesh* CLWOMeshFileLoader::createMesh(io::IReadFile* file) +{ + if ( getMeshTextureLoader() ) + getMeshTextureLoader()->setMeshFile(file); + + File = file; + + if (Mesh) + Mesh->drop(); + + Mesh = new SMesh(); + + if (!readFileHeader()) + return 0; + + if (!readChunks()) + return 0; + +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: Creating geometry."); + os::Printer::log("LWO loader: Assigning UV maps."); +#endif + for (u32 i=0; iTexture[j].UVname.size()) + { + for (uvTag=0; uvTagTexture[j].UVname == UvName[uvTag]) + { + Materials[i]->Texture[j].UVTag=uvTag; + break; + } + } + for (uvTag=0; uvTagTexture[j].UVname == DUvName[uvTag]) + { + Materials[i]->Texture[j].DUVTag=uvTag; + break; + } + } + } + } + } +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: Creating polys."); +#endif + // create actual geometry for lwo2 + if (FormatVersion==2) + { + core::array vertexCount; + vertexCount.reallocate(Materials.size()); + for (u32 i=0; iMeshbuffer->Vertices.reallocate(vertexCount[i]); + Materials[i]->Meshbuffer->Indices.reallocate(vertexCount[i]); + } + } + // create actual geometry for lwo2 + for (u32 polyIndex=0; polyIndexMeshbuffer; + const core::array& poly = Indices[polyIndex]; + const u32 polySize=poly.size(); + const u16 uvTag = Materials[tag]->Texture[0].UVTag; + const u16 duvTag = Materials[tag]->Texture[0].DUVTag; + video::S3DVertex vertex; + vertex.Color=0xffffffff; + const u32 vertCount=mb->Vertices.size(); + for (u32 i=0; iVertices.push_back(vertex); + } + // triangulate as trifan + if (polySize>2) + { + for (u32 i=1; iIndices.push_back(vertCount); + mb->Indices.push_back(vertCount+i); + mb->Indices.push_back(vertCount+i+1); + } + } + } +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: Fixing meshbuffers."); +#endif + for (u32 i=0; iName); + os::Printer::log("LWO loader: Vertex count", core::stringc(Materials[i]->Meshbuffer->Vertices.size())); +#endif + if (!Materials[i]->Meshbuffer->Vertices.size()) + { + Materials[i]->Meshbuffer->drop(); + delete Materials[i]; + continue; + } + for (u32 j=0; jMeshbuffer->Vertices.size(); ++j) + Materials[i]->Meshbuffer->Vertices[j].Color=Materials[i]->Meshbuffer->Material.DiffuseColor; + Materials[i]->Meshbuffer->recalculateBoundingBox(); + + // load textures + video::SMaterial& irrMat=Materials[i]->Meshbuffer->Material; + if (Materials[i]->Texture[0].Map != "") // diffuse + irrMat.setTexture(0,loadTexture(Materials[i]->Texture[0].Map)); + if (Materials[i]->Texture[3].Map != "") // reflection + { +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading reflection texture."); +#endif + video::ITexture* reflTexture = loadTexture(Materials[i]->Texture[3].Map); + if (reflTexture && irrMat.getTexture(0)) + irrMat.setTexture(1, irrMat.getTexture(0)); + irrMat.setTexture(0, reflTexture); + irrMat.MaterialType=video::EMT_REFLECTION_2_LAYER; + } + if (Materials[i]->Texture[4].Map != "") // transparency + { +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading transparency texture."); +#endif + video::ITexture* transTexture = loadTexture(Materials[i]->Texture[4].Map); + if (transTexture && irrMat.getTexture(0)) + irrMat.setTexture(1, irrMat.getTexture(0)); + irrMat.setTexture(0, transTexture); + irrMat.MaterialType=video::EMT_TRANSPARENT_ADD_COLOR; + } + if (Materials[i]->Texture[6].Map != "") // bump + { +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading bump texture."); +#endif + const u8 pos = irrMat.getTexture(0)?1:0; + irrMat.setTexture(pos, loadTexture(Materials[i]->Texture[6].Map)); + if (irrMat.getTexture(pos)) + { + // SceneManager->getVideoDriver()->makeNormalMapTexture(irrMat.getTexture(1)); + // irrMat.MaterialType=video::EMT_NORMAL_MAP_SOLID; + } + } + + // cope with planar mapping texture coords + if (Materials[i]->Texture[0].Projection != 5) + { + if (FormatVersion!=2) + { + if (Materials[i]->Texture[0].Flags&1) + Materials[i]->Texture[0].Axis=0; + else if (Materials[i]->Texture[0].Flags&2) + Materials[i]->Texture[0].Axis=1; + else if (Materials[i]->Texture[0].Flags&4) + Materials[i]->Texture[0].Axis=2; + } + // if no axis given choose the dominant one + else if (Materials[i]->Texture[0].Axis>2) + { + if (Materials[i]->Meshbuffer->getBoundingBox().getExtent().YMeshbuffer->getBoundingBox().getExtent().X) + { + if (Materials[i]->Meshbuffer->getBoundingBox().getExtent().YMeshbuffer->getBoundingBox().getExtent().Z) + Materials[i]->Texture[0].Axis=1; + else + Materials[i]->Texture[0].Axis=2; + } + else + { + if (Materials[i]->Meshbuffer->getBoundingBox().getExtent().XMeshbuffer->getBoundingBox().getExtent().Z) + Materials[i]->Texture[0].Axis=0; + else + Materials[i]->Texture[0].Axis=2; + } + } + // get the resolution for this axis + f32 resolutionS = core::reciprocal(Materials[i]->Texture[0].Size.Z); + f32 resolutionT = core::reciprocal(Materials[i]->Texture[0].Size.Y); + if (Materials[i]->Texture[0].Axis==1) + { + resolutionS = core::reciprocal(Materials[i]->Texture[0].Size.X); + resolutionT = core::reciprocal(Materials[i]->Texture[0].Size.Z); + } + else if (Materials[i]->Texture[0].Axis==2) + { + resolutionS = core::reciprocal(Materials[i]->Texture[0].Size.X); + resolutionT = core::reciprocal(Materials[i]->Texture[0].Size.Y); + } + // use the two-way planar mapping + SceneManager->getMeshManipulator()->makePlanarTextureMapping(Materials[i]->Meshbuffer, resolutionS, resolutionT, Materials[i]->Texture[0].Axis, Materials[i]->Texture[0].Center); + } + + // add bump maps + if (Materials[i]->Meshbuffer->Material.MaterialType==video::EMT_NORMAL_MAP_SOLID) + { + SMesh* tmpmesh = new SMesh(); + tmpmesh->addMeshBuffer(Materials[i]->Meshbuffer); + SceneManager->getMeshManipulator()->createMeshWithTangents(tmpmesh, true, true); + Mesh->addMeshBuffer(tmpmesh->getMeshBuffer(0)); + tmpmesh->getMeshBuffer(0)->drop(); + tmpmesh->drop(); + } + else + { + SceneManager->getMeshManipulator()->recalculateNormals(Materials[i]->Meshbuffer); + Mesh->addMeshBuffer(Materials[i]->Meshbuffer); + } + Materials[i]->Meshbuffer->drop(); + // clear the material array elements + delete Materials[i]; + } + Mesh->recalculateBoundingBox(); + + SAnimatedMesh* am = new SAnimatedMesh(); + am->Type = EAMT_3DS; + am->addMesh(Mesh); + am->recalculateBoundingBox(); + Mesh->drop(); + Mesh = 0; + + Points.clear(); + Indices.clear(); + MaterialMapping.clear(); + TCoords.clear(); + Materials.clear(); + Images.clear(); + VmPolyPointsIndex.clear(); + VmCoordsIndex.clear(); + UvIndex.clear(); + UvName.clear(); + + return am; +} + + +bool CLWOMeshFileLoader::readChunks() +{ + s32 lastPos; + u32 size; + unsigned int uiType; + char type[5]; + type[4]=0; + tLWOLayerInfo layer; + + while(File->getPos()getSize()) + { + File->read(&type, 4); + //Convert 4-char string to 4-byte integer + //Makes it possible to do a switch statement + uiType = charsToUInt(type); + File->read(&size, 4); +#ifndef __BIG_ENDIAN__ + size=os::Byteswap::byteswap(size); +#endif + lastPos=File->getPos(); + + switch(uiType) + { + case charsToUIntD('L','A','Y','R'): + { +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading layer."); +#endif + u16 tmp16; + File->read(&tmp16, 2); // number + File->read(&tmp16, 2); // flags + size -= 4; +#ifndef __BIG_ENDIAN__ + tmp16=os::Byteswap::byteswap(tmp16); +#endif + if (((FormatVersion==1)&&(tmp16!=1)) || + ((FormatVersion==2)&&(tmp16&1))) + layer.Active=false; + else + layer.Active=true; + if (FormatVersion==2) + size -= readVec(layer.Pivot); + size -= readString(layer.Name); + if (size) + { + File->read(&tmp16, 2); +#ifndef __BIG_ENDIAN__ + tmp16=os::Byteswap::byteswap(tmp16); +#endif + layer.Parent = tmp16; + } + } + break; + case charsToUIntD('P','N','T','S'): + { +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading points."); +#endif + core::vector3df vec; + Points.clear(); + const u32 tmpsize = size/12; + Points.reallocate(tmpsize); + for (u32 i=0; iName=""; + mat->Meshbuffer=new scene::SMeshBuffer(); + size -= readString(mat->Name); + if (FormatVersion!=2) + mat->TagType = 1; // format 2 has more types + Materials.push_back(mat); + } + } + break; + case charsToUIntD('P','T','A','G'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading tag mapping."); +#endif + readTagMapping(size); + break; + case charsToUIntD('V','M','A','D'): // discontinuous vertex mapping, i.e. additional texcoords +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading Vertex mapping VMAD."); +#endif + readDiscVertexMapping(size); +// case charsToUIntD('V','M','P','A'): +// case charsToUIntD('E','N','V','L'): + break; + case charsToUIntD('C','L','I','P'): + { +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading clips."); +#endif + u32 index; + u16 subsize; + File->read(&index, 4); +#ifndef __BIG_ENDIAN__ + index=os::Byteswap::byteswap(index); +#endif + size -= 4; + while (size != 0) + { + File->read(&type, 4); + File->read(&subsize, 2); +#ifndef __BIG_ENDIAN__ + subsize=os::Byteswap::byteswap(subsize); +#endif + size -= 6; + if (strncmp(type, "STIL", 4)) + { + File->seek(subsize, true); + size -= subsize; + continue; + } + core::stringc path; + size -= readString(path, subsize); + #ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loaded clip", path.c_str()); + #endif + Images.push_back(path); + } + } + break; + case charsToUIntD('S','U','R','F'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading material."); +#endif + readMat(size); + break; + case charsToUIntD('B','B','O','X'): + { +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading bbox."); +#endif + // not stored + core::vector3df vec; + for (u32 i=0; i<2; ++i) + readVec(vec); + size -= 24; + } + break; + case charsToUIntD('D','E','S','C'): + case charsToUIntD('T','E','X','T'): + { + core::stringc text; + size -= readString(text, size); +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader text", text); +#endif + } + break; + // not needed + case charsToUIntD('I','C','O','N'): + // not yet supported + case charsToUIntD('P','C','H','S'): + case charsToUIntD('C','R','V','S'): + default: +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: skipping ", type); +#endif + //Go to next chunk + File->seek(lastPos + size, false); + break; + } + } + return true; +} + + +void CLWOMeshFileLoader::readObj1(u32 size) +{ + u32 pos; + u16 numVerts, vertIndex; + s16 material; + video::S3DVertex vertex; + vertex.Color=0xffffffff; + + while (size!=0) + { + File->read(&numVerts, 2); +#ifndef __BIG_ENDIAN__ + numVerts=os::Byteswap::byteswap(numVerts); +#endif + pos=File->getPos(); + // skip forward to material number + File->seek(2*numVerts, true); + File->read(&material, 2); +#ifndef __BIG_ENDIAN__ + material=os::Byteswap::byteswap(material); +#endif + size -=2*numVerts+4; + // detail meshes ? + scene::SMeshBuffer *mb; + if (material<0) + mb=Materials[-material-1]->Meshbuffer; + else + mb=Materials[material-1]->Meshbuffer; + // back to vertex list start + File->seek(pos, false); + + const u16 vertCount=mb->Vertices.size(); + for (u16 i=0; iread(&vertIndex, 2); +#ifndef __BIG_ENDIAN__ + vertIndex=os::Byteswap::byteswap(vertIndex); +#endif + vertex.Pos=Points[vertIndex]; + mb->Vertices.push_back(vertex); + } + for (u16 i=1; iIndices.push_back(vertCount); + mb->Indices.push_back(vertCount+i); + mb->Indices.push_back(vertCount+i+1); + } + // skip material number and detail surface count + // detail surface can be read just as a normal one now + if (material<0) + File->read(&material, 2); + File->read(&material, 2); + } +} + + +void CLWOMeshFileLoader::readVertexMapping(u32 size) +{ + char type[5]={0}; + u16 dimension; + core::stringc name; + File->read(&type, 4); +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: Vertex map type", type); +#endif + File->read(&dimension,2); +#ifndef __BIG_ENDIAN__ + dimension=os::Byteswap::byteswap(dimension); +#endif + size -= 6; + size -= readString(name); +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: Vertex map", name.c_str()); +#endif + if (strncmp(type, "TXUV", 4)) // also support RGB, RGBA, WGHT, ... + { + File->seek(size, true); + return; + } + UvName.push_back(name); + + TCoords.push_back(core::array()); + core::array& UvCoords=TCoords.getLast(); + UvCoords.reallocate(Points.size()); + UvIndex.push_back(core::array()); + core::array& UvPointsArray=UvIndex.getLast(); + UvPointsArray.reallocate(Points.size()); + + u32 index; + core::vector2df tcoord; + while (size) + { + size -= readVX(index); + File->read(&tcoord.X, 4); + File->read(&tcoord.Y, 4); + size -= 8; +#ifndef __BIG_ENDIAN__ + index=os::Byteswap::byteswap(index); + tcoord.X=os::Byteswap::byteswap(tcoord.X); + tcoord.Y=os::Byteswap::byteswap(tcoord.Y); +#endif + UvCoords.push_back(tcoord); + UvPointsArray.push_back(index); + } +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: UvCoords", core::stringc(UvCoords.size())); +#endif +} + + +void CLWOMeshFileLoader::readDiscVertexMapping(u32 size) +{ + char type[5]={0}; + u16 dimension; + core::stringc name; + File->read(&type, 4); +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: Discontinuous vertex map type", type); +#endif + File->read(&dimension,2); +#ifndef __BIG_ENDIAN__ + dimension=os::Byteswap::byteswap(dimension); +#endif + size -= 6; + size -= readString(name); +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: Discontinuous vertex map", name.c_str()); +#endif + if (strncmp(type, "TXUV", 4)) + { + File->seek(size, true); + return; + } + DUvName.push_back(name); + VmPolyPointsIndex.push_back(core::array()); + core::array& VmPolyPoints=VmPolyPointsIndex.getLast(); + + VmCoordsIndex.push_back(core::array()); + core::array& VmCoords=VmCoordsIndex.getLast(); + + u32 vmpolys; + u32 vmpoints; + core::vector2df vmcoords; + while (size) + { + size-=readVX(vmpoints); + size-=readVX(vmpolys); + File->read(&vmcoords.X, 4); + File->read(&vmcoords.Y, 4); + size -= 8; +#ifndef __BIG_ENDIAN__ + vmpoints=os::Byteswap::byteswap(vmpoints); + vmpolys=os::Byteswap::byteswap(vmpolys); + vmcoords.X=os::Byteswap::byteswap(vmcoords.X); + vmcoords.Y=os::Byteswap::byteswap(vmcoords.Y); +#endif + VmCoords.push_back(vmcoords); + VmPolyPoints.push_back(vmpolys); + VmPolyPoints.push_back(vmpoints); + } +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: VmCoords", core::stringc(VmCoords.size())); +#endif +} + + +void CLWOMeshFileLoader::readTagMapping(u32 size) +{ + char type[5]; + type[4]=0; + File->read(&type, 4); + size -= 4; + if ((strncmp(type, "SURF", 4))||(Indices.size()==0)) + { + File->seek(size, true); + return; + } + + while (size!=0) + { + u16 tag; + u32 polyIndex; + size-=readVX(polyIndex); + File->read(&tag, 2); +#ifndef __BIG_ENDIAN__ + tag=os::Byteswap::byteswap(tag); +#endif + size -= 2; + MaterialMapping[polyIndex]=tag; + Materials[tag]->TagType=1; + } +} + + +void CLWOMeshFileLoader::readObj2(u32 size) +{ + char type[5]; + type[4]=0; + File->read(&type, 4); + size -= 4; + Indices.clear(); + if (strncmp(type, "FACE", 4)) // also possible are splines, subdivision patches, metaballs, and bones + { + File->seek(size, true); + return; + } + u16 numVerts=0; + while (size!=0) + { + File->read(&numVerts, 2); +#ifndef __BIG_ENDIAN__ + numVerts=os::Byteswap::byteswap(numVerts); +#endif + // mask out flags + numVerts &= 0x03FF; + + size -= 2; + Indices.push_back(core::array()); + u32 vertIndex; + core::array& polyArray = Indices.getLast(); + polyArray.reallocate(numVerts); + for (u16 i=0; iTagType==1) && (Materials[i]->Name==name)) + { + mat=Materials[i]; + break; + } + } + if (!mat) + { + File->seek(size, true); + return; + } + if (FormatVersion==2) + size -= readString(name); + + video::SMaterial& irrMat=mat->Meshbuffer->Material; + + u8 currTexture=0; + while (size!=0) + { + char type[5]; + type[4]=0; + u32 uiType; + u32 tmp32; + u16 subsize, tmp16; + f32 tmpf32; + File->read(&type, 4); + //Convert 4-char string to 4-byte integer + //Makes it possible to do a switch statement + uiType = charsToUInt(type); + File->read(&subsize, 2); +#ifndef __BIG_ENDIAN__ + subsize=os::Byteswap::byteswap(subsize); +#endif + size -= 6; + switch (uiType) + { + case charsToUIntD('C','O','L','R'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading Ambient color."); +#endif + { + s32 colSize = readColor(irrMat.DiffuseColor); + irrMat.AmbientColor=irrMat.DiffuseColor; + size -= colSize; + subsize -= colSize; + if (FormatVersion==2) + size -= readVX(mat->Envelope[0]); + } + break; + case charsToUIntD('D','I','F','F'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading Diffuse color."); +#endif + { + if (FormatVersion==2) + { + File->read(&mat->Diffuse, 4); +#ifndef __BIG_ENDIAN__ + mat->Diffuse=os::Byteswap::byteswap(mat->Diffuse); +#endif + size -= 4; + subsize -= 4; + size -= readVX(mat->Envelope[1]); + } + else + { + File->read(&tmp16, 2); +#ifndef __BIG_ENDIAN__ + tmp16=os::Byteswap::byteswap(tmp16); +#endif + mat->Diffuse=tmp16/256.0f; + size -= 2; + subsize -= 2; + } + } + break; + case charsToUIntD('V','D','I','F'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading Diffuse color."); +#endif + { + File->read(&mat->Diffuse, 4); +#ifndef __BIG_ENDIAN__ + mat->Diffuse=os::Byteswap::byteswap(mat->Diffuse); +#endif + size -= 4; + } + break; + case charsToUIntD('L','U','M','I'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading luminance."); +#endif + { + if (FormatVersion==2) + { + File->read(&mat->Luminance, 4); +#ifndef __BIG_ENDIAN__ + mat->Luminance=os::Byteswap::byteswap(mat->Luminance); +#endif + size -= 4; + subsize -= 4; + size -= readVX(mat->Envelope[2]); + } + else + { + File->read(&tmp16, 2); +#ifndef __BIG_ENDIAN__ + tmp16=os::Byteswap::byteswap(tmp16); +#endif + mat->Luminance=tmp16/256.0f; + size -= 2; + subsize -= 2; + } } + break; + case charsToUIntD('V','L','U','M'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading luminance."); +#endif + { + File->read(&mat->Luminance, 4); +#ifndef __BIG_ENDIAN__ + mat->Luminance=os::Byteswap::byteswap(mat->Luminance); +#endif + size -= 4; + } + break; + case charsToUIntD('S','P','E','C'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading specular."); +#endif + { + if (FormatVersion==2) + { + File->read(&mat->Specular, 4); +#ifndef __BIG_ENDIAN__ + mat->Specular=os::Byteswap::byteswap(mat->Specular); +#endif + size -= 4; + subsize -= 4; + size -= readVX(mat->Envelope[3]); + } + else + { + File->read(&tmp16, 2); +#ifndef __BIG_ENDIAN__ + tmp16=os::Byteswap::byteswap(tmp16); +#endif + mat->Specular=tmp16/256.0f;; + size -= 2; + subsize -= 2; + } + } + break; + case charsToUIntD('V','S','P','C'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading specular."); +#endif + { + File->read(&mat->Specular, 4); +#ifndef __BIG_ENDIAN__ + mat->Specular=os::Byteswap::byteswap(mat->Specular); +#endif + size -= 4; + } + break; + case charsToUIntD('R','E','F','L'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading reflection."); +#endif + { + if (FormatVersion==2) + { + File->read(&mat->Reflection, 4); +#ifndef __BIG_ENDIAN__ + mat->Reflection=os::Byteswap::byteswap(mat->Reflection); +#endif + size -= 4; + subsize -= 4; + size -= readVX(mat->Envelope[4]); + } + else + { + File->read(&tmp16, 2); +#ifndef __BIG_ENDIAN__ + tmp16=os::Byteswap::byteswap(tmp16); +#endif + mat->Reflection=tmp16/256.0f; + size -= 2; + subsize -= 2; + } + } + break; + case charsToUIntD('V','R','F','L'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading reflection."); +#endif + { + File->read(&mat->Reflection, 4); +#ifndef __BIG_ENDIAN__ + mat->Reflection=os::Byteswap::byteswap(mat->Reflection); +#endif + size -= 4; + } + break; + case charsToUIntD('T','R','A','N'): + { + if (FormatVersion==2) + { + File->read(&mat->Transparency, 4); +#ifndef __BIG_ENDIAN__ + mat->Transparency=os::Byteswap::byteswap(mat->Transparency); +#endif + size -= 4; + subsize -= 4; + size -= readVX(mat->Envelope[5]); + } + else + { + File->read(&tmp16, 2); +#ifndef __BIG_ENDIAN__ + tmp16=os::Byteswap::byteswap(tmp16); +#endif + mat->Transparency=tmp16/256.0f; + size -= 2; + subsize -= 2; + } +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading transparency", core::stringc(mat->Transparency).c_str()); +#endif + } + break; + case charsToUIntD('V','T','R','N'): + { + File->read(&mat->Transparency, 4); +#ifndef __BIG_ENDIAN__ + mat->Transparency=os::Byteswap::byteswap(mat->Transparency); +#endif + size -= 4; + } +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading transparency", core::stringc(mat->Transparency).c_str()); +#endif + break; + case charsToUIntD('T','R','N','L'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading translucency."); +#endif + { + File->read(&mat->Translucency, 4); +#ifndef __BIG_ENDIAN__ + mat->Translucency=os::Byteswap::byteswap(mat->Translucency); +#endif + size -= 4; + subsize -= 4; + if (FormatVersion==2) + size -= readVX(mat->Envelope[6]); + } + break; + case charsToUIntD('G','L','O','S'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading glossy."); +#endif + { + if (FormatVersion == 2) + { + File->read(&irrMat.Shininess, 4); +#ifndef __BIG_ENDIAN__ + irrMat.Shininess=os::Byteswap::byteswap(irrMat.Shininess); +#endif + size -= 4; + subsize -= 4; + size -= readVX(mat->Envelope[7]); + } + else + { + File->read(&tmp16, 2); +#ifndef __BIG_ENDIAN__ + tmp16=os::Byteswap::byteswap(tmp16); +#endif + irrMat.Shininess=tmp16/16.f; + size -= 2; + subsize -= 2; + } + } + break; + case charsToUIntD('S','H','R','P'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading sharpness."); +#endif + { + File->read(&mat->Sharpness, 4); +#ifndef __BIG_ENDIAN__ + mat->Sharpness=os::Byteswap::byteswap(mat->Sharpness); +#endif + size -= 4; + subsize -= 4; + if (FormatVersion==2) + size -= readVX(mat->Envelope[8]); + } + break; + case charsToUIntD('B','U','M','P'): + case charsToUIntD('T','A','M','P'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading bumpiness."); +#endif + { + File->read(&tmpf32, 4); +#ifndef __BIG_ENDIAN__ + tmpf32=os::Byteswap::byteswap(tmpf32); +#endif + if (currTexture==6) + irrMat.MaterialTypeParam=tmpf32; + size -= 4; + subsize -= 4; + if (FormatVersion==2) + size -= readVX(mat->Envelope[9]); + } + break; + case charsToUIntD('S','I','D','E'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading backface culled."); +#endif + { + File->read(&tmp16, 2); +#ifndef __BIG_ENDIAN__ + tmp16=os::Byteswap::byteswap(tmp16); +#endif + if (tmp16==1) + irrMat.BackfaceCulling=true; + else if (tmp16==3) + irrMat.BackfaceCulling=false; + size -= 2; + } + break; + case charsToUIntD('S','M','A','N'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading smoothing angle."); +#endif + { + File->read(&mat->SmoothingAngle, 4); +#ifndef __BIG_ENDIAN__ + mat->SmoothingAngle=os::Byteswap::byteswap(mat->SmoothingAngle); +#endif + size -= 4; + } + break; + case charsToUIntD('R','F','O','P'): + case charsToUIntD('R','F','L','T'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading reflection mode."); +#endif + { + File->read(&mat->ReflMode, 2); +#ifndef __BIG_ENDIAN__ + mat->ReflMode=os::Byteswap::byteswap(mat->ReflMode); +#endif + size -= 2; + } + break; + case charsToUIntD('R','I','M','G'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading reflection map."); +#endif + { + if (FormatVersion==2) + { + size -= readVX(tmp32); + if (tmp32) + mat->ReflMap=Images[tmp32-1]; + } + else + size -= readString(mat->ReflMap, size); + } + break; + case charsToUIntD('R','S','A','N'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading reflection seam angle."); +#endif + { + File->read(&mat->ReflSeamAngle, 4); +#ifndef __BIG_ENDIAN__ + mat->ReflSeamAngle=os::Byteswap::byteswap(mat->ReflSeamAngle); +#endif + size -= 4; + if (FormatVersion==2) + size -= readVX(mat->Envelope[10]); + } + break; + case charsToUIntD('R','B','L','R'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading reflection blur."); +#endif + { + File->read(&mat->ReflBlur, 4); +#ifndef __BIG_ENDIAN__ + mat->ReflBlur=os::Byteswap::byteswap(mat->ReflBlur); +#endif + size -= 4; + if (FormatVersion==2) + size -= readVX(mat->Envelope[11]); + } + break; + case charsToUIntD('R','I','N','D'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading refraction index."); +#endif + { + File->read(&mat->RefrIndex, 4); +#ifndef __BIG_ENDIAN__ + mat->RefrIndex=os::Byteswap::byteswap(mat->RefrIndex); +#endif + size -= 4; + subsize -= 4; + if (FormatVersion==2) + size -= readVX(mat->Envelope[12]); + } + break; + case charsToUIntD('T','R','O','P'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading refraction options."); +#endif + { + File->read(&mat->TranspMode, 2); +#ifndef __BIG_ENDIAN__ + mat->TranspMode=os::Byteswap::byteswap(mat->TranspMode); +#endif + size -= 2; + } + break; + case charsToUIntD('T','I','M','G'): + { + if (FormatVersion==2) + { +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading refraction map."); +#endif + size -= readVX(tmp32); +#ifndef __BIG_ENDIAN__ + tmp32=os::Byteswap::byteswap(tmp32); +#endif + if (tmp32) + mat->Texture[currTexture].Map=Images[tmp32-1]; + } + else + { + size -= readString(mat->Texture[currTexture].Map, size); +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading image", mat->Texture[currTexture].Map.c_str()); +#endif + } + } + break; + case charsToUIntD('T','B','L','R'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading transparency blur."); +#endif + { + File->read(&mat->TranspBlur, 4); +#ifndef __BIG_ENDIAN__ + mat->TranspBlur=os::Byteswap::byteswap(mat->TranspBlur); +#endif + size -= 4; + if (FormatVersion==2) + size -= readVX(mat->Envelope[13]); + } + break; + case charsToUIntD('C','L','R','H'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading highlight color."); +#endif + { + File->read(&mat->HighlightColor, 4); +#ifndef __BIG_ENDIAN__ + mat->HighlightColor=os::Byteswap::byteswap(mat->HighlightColor); +#endif + size -= 4; + if (FormatVersion==2) + size -= readVX(mat->Envelope[14]); + } + break; + case charsToUIntD('C','L','R','F'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading color filter."); +#endif + { + File->read(&mat->ColorFilter, 4); +#ifndef __BIG_ENDIAN__ + mat->ColorFilter=os::Byteswap::byteswap(mat->ColorFilter); +#endif + size -= 4; + if (FormatVersion==2) + size -= readVX(mat->Envelope[15]); + } + break; + case charsToUIntD('A','D','T','R'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading additive transparency."); +#endif + { + File->read(&mat->AdditiveTransparency, 4); +#ifndef __BIG_ENDIAN__ + mat->AdditiveTransparency=os::Byteswap::byteswap(mat->AdditiveTransparency); +#endif + size -= 4; + if (FormatVersion==2) + size -= readVX(mat->Envelope[16]); + } + break; + case charsToUIntD('G','L','O','W'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading glow."); +#endif + { + if (FormatVersion==0) + { + File->read(&mat->GlowIntensity, 4); +#ifndef __BIG_ENDIAN__ + mat->GlowIntensity=os::Byteswap::byteswap(mat->GlowIntensity); +#endif + size -= 4; + } + else + { + File->read(&mat->Glow, 2); +#ifndef __BIG_ENDIAN__ + mat->Glow=os::Byteswap::byteswap(mat->Glow); +#endif + size -= 2; + File->read(&mat->GlowIntensity, 4); +#ifndef __BIG_ENDIAN__ + mat->GlowIntensity=os::Byteswap::byteswap(mat->GlowIntensity); +#endif + size -= 4; + if (FormatVersion==2) + size -= readVX(mat->Envelope[17]); + File->read(&mat->GlowSize, 4); +#ifndef __BIG_ENDIAN__ + mat->GlowSize=os::Byteswap::byteswap(mat->GlowSize); +#endif + size -= 4; + if (FormatVersion==2) + size -= readVX(mat->Envelope[18]); + } + } + break; + case charsToUIntD('G','V','A','L'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading glow intensity."); +#endif + { + File->read(&mat->GlowIntensity, 4); +#ifndef __BIG_ENDIAN__ + mat->GlowIntensity=os::Byteswap::byteswap(mat->GlowIntensity); +#endif + size -= 4; + if (FormatVersion==2) + size -= readVX(mat->Envelope[17]); + } + break; + case charsToUIntD('L','I','N','E'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading isWireframe."); +#endif + { + File->read(&tmp16, 2); +#ifndef __BIG_ENDIAN__ + tmp16=os::Byteswap::byteswap(tmp16); +#endif + if (tmp16&1) + irrMat.Wireframe=true; + size -= 2; + if (size!=0) + { + File->read(&irrMat.Thickness, 4); +#ifndef __BIG_ENDIAN__ + irrMat.Thickness=os::Byteswap::byteswap(irrMat.Thickness); +#endif + size -= 4; + if (FormatVersion==2) + size -= readVX(mat->Envelope[19]); + } + if (size!=0) + { + video::SColor lineColor; + size -= readColor(lineColor); + if (FormatVersion==2) + size -= readVX(mat->Envelope[20]); + } + } + break; + case charsToUIntD('A','L','P','H'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading alpha mode."); +#endif + { + File->read(&mat->AlphaMode, 2); +#ifndef __BIG_ENDIAN__ + mat->AlphaMode=os::Byteswap::byteswap(mat->AlphaMode); +#endif + size -= 2; + File->read(&mat->AlphaValue, 4); +#ifndef __BIG_ENDIAN__ + mat->AlphaValue=os::Byteswap::byteswap(mat->AlphaValue); +#endif + size -= 4; + } + break; + case charsToUIntD('V','C','O','L'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading vertex color."); +#endif + { + File->read(&mat->VertexColorIntensity, 4); +#ifndef __BIG_ENDIAN__ + mat->VertexColorIntensity=os::Byteswap::byteswap(mat->VertexColorIntensity); +#endif + size -= 4; + if (FormatVersion==2) + size -= readVX(mat->Envelope[21]); + File->read(&tmp32, 4); // skip type + size -= 4; + core::stringc tmpname; + size -= readString(tmpname, size); +// mat->VertexColor = getColorVMAP(tmpname); + } + break; + case charsToUIntD('F','L','A','G'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading flag."); +#endif + { + File->read(&mat->Flags, 2); +#ifndef __BIG_ENDIAN__ + mat->Flags=os::Byteswap::byteswap(mat->Flags); +#endif + if (mat->Flags&1) + mat->Luminance=1.0f; + if (mat->Flags&256) + irrMat.BackfaceCulling=false; + size -= 2; + } + break; + case charsToUIntD('E','D','G','E'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading edge."); +#endif + { + File->read(&mat->EdgeTransparency, 4); +#ifndef __BIG_ENDIAN__ + mat->EdgeTransparency=os::Byteswap::byteswap(mat->EdgeTransparency); +#endif + size -= 4; + } + break; + case charsToUIntD('C','T','E','X'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading ctex."); +#endif + currTexture=0; + size -= readString(mat->Texture[currTexture].Type, size); + break; + case charsToUIntD('D','T','E','X'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading dtex."); +#endif + currTexture=1; + size -= readString(mat->Texture[currTexture].Type, size); + break; + case charsToUIntD('S','T','E','X'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading stex."); +#endif + currTexture=2; + size -= readString(mat->Texture[currTexture].Type, size); + break; + case charsToUIntD('R','T','E','X'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading rtex."); +#endif + currTexture=3; + size -= readString(mat->Texture[currTexture].Type, size); + break; + case charsToUIntD('T','T','E','X'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading ttex."); +#endif + currTexture=4; + size -= readString(mat->Texture[currTexture].Type, size); + break; + case charsToUIntD('L','T','E','X'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading ltex."); +#endif + currTexture=5; + size -= readString(mat->Texture[currTexture].Type, size); + break; + case charsToUIntD('B','T','E','X'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading btex."); +#endif + currTexture=6; + size -= readString(mat->Texture[currTexture].Type, size); + break; + case charsToUIntD('T','A','L','P'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading alpha map."); +#endif + size -= readString(mat->Texture[currTexture].AlphaMap, size); + break; + case charsToUIntD('T','F','L','G'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading texture flag."); +#endif + { + File->read(&mat->Texture[currTexture].Flags, 2); +#ifndef __BIG_ENDIAN__ + mat->Texture[currTexture].Flags=os::Byteswap::byteswap(mat->Texture[currTexture].Flags); +#endif + size -= 2; + } + break; + case charsToUIntD('E','N','A','B'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading isEnabled."); +#endif + { + File->read(&tmp16, 2); +#ifndef __BIG_ENDIAN__ + tmp16=os::Byteswap::byteswap(tmp16); +#endif + mat->Texture[currTexture].Active=(tmp16!=0); + size -= 2; + } + break; + case charsToUIntD('W','R','A','P'): + case charsToUIntD('T','W','R','P'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading texture wrap."); +#endif + { + File->read(&mat->Texture[currTexture].WidthWrap, 2); +#ifndef __BIG_ENDIAN__ + mat->Texture[currTexture].WidthWrap=os::Byteswap::byteswap(mat->Texture[currTexture].WidthWrap); +#endif + File->read(&mat->Texture[currTexture].HeightWrap, 2); +#ifndef __BIG_ENDIAN__ + mat->Texture[currTexture].HeightWrap=os::Byteswap::byteswap(mat->Texture[currTexture].HeightWrap); +#endif + size -= 4; + } + break; + case charsToUIntD('T','V','E','L'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading texture velocity."); +#endif + size -= readVec(mat->Texture[currTexture].Velocity); + break; + case charsToUIntD('T','C','L','R'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading texture color."); +#endif + size -= readColor(mat->Texture[currTexture].Color); + break; + case charsToUIntD('A','A','S','T'): + case charsToUIntD('T','A','A','S'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading texture antialias."); +#endif + { + tmp16=0; + if (FormatVersion==2) + { + File->read(&tmp16, 2); +#ifndef __BIG_ENDIAN__ + tmp16=os::Byteswap::byteswap(tmp16); +#endif + size -= 2; + } + File->read(&mat->Texture[currTexture].AntiAliasing, 4); +#ifndef __BIG_ENDIAN__ + mat->Texture[currTexture].AntiAliasing=os::Byteswap::byteswap(mat->Texture[currTexture].AntiAliasing); +#endif + if (tmp16 & ~0x01) + mat->Texture[currTexture].AntiAliasing=0.0f; // disabled + size -= 4; + } + break; + case charsToUIntD('T','O','P','C'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading texture opacity."); +#endif + { + File->read(&mat->Texture[currTexture].Opacity, 4); +#ifndef __BIG_ENDIAN__ + mat->Texture[currTexture].Opacity=os::Byteswap::byteswap(mat->Texture[currTexture].Opacity); +#endif + size -= 4; + } + break; + case charsToUIntD('O','P','A','C'): + { +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading texture opacity and type."); +#endif + File->read(&mat->Texture[currTexture].OpacType, 2); +#ifndef __BIG_ENDIAN__ + mat->Texture[currTexture].OpacType=os::Byteswap::byteswap(mat->Texture[currTexture].OpacType); +#endif + File->read(&mat->Texture[currTexture].Opacity, 4); +#ifndef __BIG_ENDIAN__ + mat->Texture[currTexture].Opacity=os::Byteswap::byteswap(mat->Texture[currTexture].Opacity); +#endif + size -= 6; + subsize -= 6; + if (FormatVersion==2) + size -= readVX(mat->Envelope[22]); + } + break; + case charsToUIntD('A','X','I','S'): + { + File->read(&tmp16, 2); +#ifndef __BIG_ENDIAN__ + tmp16=os::Byteswap::byteswap(tmp16); +#endif + mat->Texture[currTexture].Axis=(u8)tmp16; + size -= 2; +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading axis value", core::stringc(tmp16).c_str()); +#endif + } + break; + case charsToUIntD('T','M','A','P'): // empty separation chunk + break; + case charsToUIntD('T','C','T','R'): + case charsToUIntD('C','N','T','R'): + { + core::vector3df& center=mat->Texture[currTexture].Center; + size -= readVec(center); + if (FormatVersion==2) + size -= readVX(mat->Envelope[22]); +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading texture center", (core::stringc(center.X)+" "+core::stringc(center.Y)+" "+core::stringc(center.Z)).c_str()); +#endif + } + break; + case charsToUIntD('T','S','I','Z'): + case charsToUIntD('S','I','Z','E'): + { + core::vector3df& tsize=mat->Texture[currTexture].Size; + size -= readVec(tsize); + if (FormatVersion==2) + size -= readVX(mat->Envelope[22]); +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading texture size", (core::stringc(tsize.X)+" "+core::stringc(tsize.Y)+" "+core::stringc(tsize.Z)).c_str()); +#endif + } + break; + case charsToUIntD('R','O','T','A'): + { + core::vector3df rotation; + size -= readVec(rotation); + if (FormatVersion==2) + size -= readVX(mat->Envelope[22]); +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading texture rotation", (core::stringc(rotation.X)+" "+core::stringc(rotation.Y)+" "+core::stringc(rotation.Z)).c_str()); +#endif + } + break; + case charsToUIntD('O','R','E','F'): + { + core::stringc tmpname; + size -= readString(tmpname); +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: texture reference object", tmpname.c_str()); +#endif + } + break; + case charsToUIntD('T','F','A','L'): + case charsToUIntD('F','A','L','L'): + { + if (FormatVersion==2) + { + u16 tmp16; + File->read(&tmp16, 2); + size -= 2; +#ifndef __BIG_ENDIAN__ + tmp16=os::Byteswap::byteswap(tmp16); +#endif + } + + core::vector3df& falloff=mat->Texture[currTexture].Falloff; + size -= readVec(falloff); + if (FormatVersion==2) + size -= readVX(mat->Envelope[22]); +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading texture falloff"); +#endif + } + break; + case charsToUIntD('C','S','Y','S'): + { + u16 tmp16; + File->read(&tmp16, 2); + size -= 2; +#ifndef __BIG_ENDIAN__ + tmp16=os::Byteswap::byteswap(tmp16); +#endif +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: texture coordinate system", tmp16==0?"object coords":"world coords"); +#endif + } + break; + case charsToUIntD('T','V','A','L'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading texture value."); +#endif + { + File->read(&tmp16, 2); +#ifndef __BIG_ENDIAN__ + tmp16=os::Byteswap::byteswap(tmp16); +#endif + mat->Texture[currTexture].Value=tmp16/256.0f; + size -= 2; + } + break; + case charsToUIntD('T','F','P','0'): + case charsToUIntD('T','S','P','0'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading texture param 0."); +#endif + { + File->read(&mat->Texture[currTexture].FParam[0], 4); +#ifndef __BIG_ENDIAN__ + mat->Texture[currTexture].FParam[0]=os::Byteswap::byteswap(mat->Texture[currTexture].FParam[0]); +#endif + size -= 4; + } + break; + case charsToUIntD('T','F','P','1'): + case charsToUIntD('T','S','P','1'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading texture param 1."); +#endif + { + File->read(&mat->Texture[currTexture].FParam[1], 4); +#ifndef __BIG_ENDIAN__ + mat->Texture[currTexture].FParam[1]=os::Byteswap::byteswap(mat->Texture[currTexture].FParam[1]); +#endif + size -= 4; + } + break; + case charsToUIntD('T','F','P','2'): + case charsToUIntD('T','S','P','2'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading texture param 2."); +#endif + { + File->read(&mat->Texture[currTexture].FParam[2], 4); +#ifndef __BIG_ENDIAN__ + mat->Texture[currTexture].FParam[2]=os::Byteswap::byteswap(mat->Texture[currTexture].FParam[2]); +#endif + size -= 4; + } + break; + case charsToUIntD('T','F','R','Q'): + case charsToUIntD('T','I','P','0'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading texture iparam 0."); +#endif + { + File->read(&mat->Texture[currTexture].IParam[0], 2); +#ifndef __BIG_ENDIAN__ + mat->Texture[currTexture].IParam[0]=os::Byteswap::byteswap(mat->Texture[currTexture].IParam[0]); +#endif + size -= 2; + } + break; + case charsToUIntD('T','I','P','1'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading texture param 1."); +#endif + { + File->read(&mat->Texture[currTexture].IParam[1], 2); +#ifndef __BIG_ENDIAN__ + mat->Texture[currTexture].IParam[1]=os::Byteswap::byteswap(mat->Texture[currTexture].IParam[1]); +#endif + size -= 2; + } + break; + case charsToUIntD('T','I','P','2'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading texture param 2."); +#endif + { + File->read(&mat->Texture[currTexture].IParam[2], 2); +#ifndef __BIG_ENDIAN__ + mat->Texture[currTexture].IParam[2]=os::Byteswap::byteswap(mat->Texture[currTexture].IParam[2]); +#endif + size -= 2; + } + break; + case charsToUIntD('V','M','A','P'): + { + size -= readString(mat->Texture[currTexture].UVname); +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading material vmap binding",mat->Texture[currTexture].UVname.c_str()); +#endif + } + break; + case charsToUIntD('B','L','O','K'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading blok."); +#endif + { + core::stringc ordinal; + File->read(&type, 4); + File->read(&subsize, 2); +#ifndef __BIG_ENDIAN__ + subsize=os::Byteswap::byteswap(subsize); +#endif + size -= 6; + size -= readString(ordinal, size); + } + break; + case charsToUIntD('C','H','A','N'): + { + File->read(&type, 4); + size -= 4; + if (!strncmp(type, "COLR", 4)) + currTexture=0; + else if (!strncmp(type, "DIFF", 4)) + currTexture=1; + else if (!strncmp(type, "LUMI", 4)) + currTexture=5; + else if (!strncmp(type, "SPEC", 4)) + currTexture=2; + else if (!strncmp(type, "REFL", 4)) + currTexture=3; + else if (!strncmp(type, "TRAN", 4)) + currTexture=4; + else if (!strncmp(type, "BUMP", 4)) + currTexture=6; + } +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading channel ", type); +#endif + break; + case charsToUIntD('I','M','A','G'): +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading channel map."); +#endif + { + u16 index; + File->read(&index, 2); +#ifndef __BIG_ENDIAN__ + index=os::Byteswap::byteswap(index); +#endif + size -= 2; + if (index) + mat->Texture[currTexture].Map=Images[index-1]; + } + break; + case charsToUIntD('P','R','O','J'): // define the projection type +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: loading channel projection type."); +#endif + { + u16 index; + File->read(&index, 2); +#ifndef __BIG_ENDIAN__ + index=os::Byteswap::byteswap(index); +#endif + size -= 2; +#ifdef LWO_READER_DEBUG + if (index != 5) + os::Printer::log("LWO loader: wrong channel projection type", core::stringc(index).c_str()); +#endif + mat->Texture[currTexture].Projection=(u8)index; + } + break; + case charsToUIntD('W','R','P','W'): // for cylindrical and spherical projections + case charsToUIntD('W','R','P','H'): // for cylindrical and spherical projections + default: + { +#ifdef LWO_READER_DEBUG + os::Printer::log("LWO loader: skipping ", core::stringc((char*)&uiType, 4)); +#endif + File->seek(subsize, true); + size -= subsize; + } + } + } + + if (mat->Transparency != 0.f) + { + irrMat.MaterialType=video::EMT_TRANSPARENT_ADD_COLOR; + } +} + + +u32 CLWOMeshFileLoader::readColor(video::SColor& color) +{ + if (FormatVersion!=2) + { + u8 colorComponent; + File->read(&colorComponent, 1); + color.setRed(colorComponent); + File->read(&colorComponent, 1); + color.setGreen(colorComponent); + File->read(&colorComponent, 1); + color.setBlue(colorComponent); + // unknown value + File->read(&colorComponent, 1); + return 4; + } + else + { + video::SColorf col; + File->read(&col.r, 4); +#ifndef __BIG_ENDIAN__ + col.r=os::Byteswap::byteswap(col.r); +#endif + File->read(&col.g, 4); +#ifndef __BIG_ENDIAN__ + col.g=os::Byteswap::byteswap(col.g); +#endif + File->read(&col.b, 4); +#ifndef __BIG_ENDIAN__ + col.b=os::Byteswap::byteswap(col.b); +#endif + color=col.toSColor(); + return 12; + } +} + +u32 CLWOMeshFileLoader::readString(core::stringc& name, u32 size) +{ + c8 c; + + name=""; + if (size) + name.reserve(size); + File->read(&c, 1); + while (c) + { + name.append(c); + File->read(&c, 1); + } + // read extra 0 upon odd file position + if (File->getPos() & 0x1) + { + File->read(&c, 1); + return (name.size()+2); + } + return (name.size()+1); +} + + +u32 CLWOMeshFileLoader::readVec(core::vector3df& vec) +{ + File->read(&vec.X, 4); +#ifndef __BIG_ENDIAN__ + vec.X=os::Byteswap::byteswap(vec.X); +#endif + File->read(&vec.Y, 4); +#ifndef __BIG_ENDIAN__ + vec.Y=os::Byteswap::byteswap(vec.Y); +#endif + File->read(&vec.Z, 4); +#ifndef __BIG_ENDIAN__ + vec.Z=os::Byteswap::byteswap(vec.Z); +#endif + return 12; +} + + +u32 CLWOMeshFileLoader::readVX(u32& num) +{ + u16 tmpIndex; + + File->read(&tmpIndex, 2); +#ifndef __BIG_ENDIAN__ + tmpIndex=os::Byteswap::byteswap(tmpIndex); +#endif + num=tmpIndex; + if (num >= 0xFF00) + { + File->read(&tmpIndex, 2); +#ifndef __BIG_ENDIAN__ + tmpIndex=os::Byteswap::byteswap(tmpIndex); +#endif + num=((num << 16)|tmpIndex) & ~0xFF000000; + return 4; + } + return 2; +} + + +bool CLWOMeshFileLoader::readFileHeader() +{ + u32 Id; + + File->read(&Id, 4); +#ifndef __BIG_ENDIAN__ + Id=os::Byteswap::byteswap(Id); +#endif + if (Id != 0x464f524d) // FORM + return false; + + //skip the file length + File->read(&Id, 4); + + File->read(&Id, 4); +#ifndef __BIG_ENDIAN__ + Id=os::Byteswap::byteswap(Id); +#endif + // Currently supported: LWOB, LWLO, LWO2 + switch (Id) + { + case 0x4c574f42: + FormatVersion = 0; // LWOB + break; + case 0x4c574c4f: + FormatVersion = 1; // LWLO + break; + case 0x4c574f32: + FormatVersion = 2; // LWO2 + break; + default: + return false; // unsupported + } + + return true; +} + + +video::ITexture* CLWOMeshFileLoader::loadTexture(const core::stringc& file) +{ + video::ITexture* texture = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture(file) : NULL; + + if (!texture) + { + os::Printer::log("Could not load texture", file.c_str(), ELL_WARNING); + } + + return texture; +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_LWO_LOADER_ diff --git a/source/Irrlicht/CLWOMeshFileLoader.h b/source/Irrlicht/CLWOMeshFileLoader.h new file mode 100644 index 00000000..5f77ed0e --- /dev/null +++ b/source/Irrlicht/CLWOMeshFileLoader.h @@ -0,0 +1,87 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_LWO_MESH_FILE_LOADER_H_INCLUDED__ +#define __C_LWO_MESH_FILE_LOADER_H_INCLUDED__ + +#include "IMeshLoader.h" +#include "SMeshBuffer.h" +#include "irrString.h" + +namespace irr +{ +namespace io +{ + class IReadFile; + class IFileSystem; +} // end namespace io +namespace scene +{ + + struct SMesh; + class ISceneManager; + +//! Meshloader capable of loading Lightwave 3D meshes. +class CLWOMeshFileLoader : public IMeshLoader +{ +public: + + //! Constructor + CLWOMeshFileLoader(scene::ISceneManager* smgr, io::IFileSystem* fs); + + //! destructor + virtual ~CLWOMeshFileLoader(); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".bsp") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! creates/loads an animated mesh from the file. + //! \return Pointer to the created mesh. Returns 0 if loading failed. + //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). + //! See IUnknown::drop() for more information. + virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_; + +private: + + struct tLWOMaterial; + + bool readFileHeader(); + bool readChunks(); + void readObj1(u32 size); + void readTagMapping(u32 size); + void readVertexMapping(u32 size); + void readDiscVertexMapping (u32 size); + void readObj2(u32 size); + void readMat(u32 size); + u32 readString(core::stringc& name, u32 size=0); + u32 readVec(core::vector3df& vec); + u32 readVX(u32& num); + u32 readColor(video::SColor& color); + video::ITexture* loadTexture(const core::stringc& file); + + scene::ISceneManager* SceneManager; + io::IFileSystem* FileSystem; + io::IReadFile* File; + SMesh* Mesh; + + core::array Points; + core::array > Indices; + core::array UvName; + core::array > UvIndex; + core::array DUvName; + core::array > VmPolyPointsIndex; + core::array > VmCoordsIndex; + + core::array MaterialMapping; + core::array > TCoords; + core::array Materials; + core::array Images; + u8 FormatVersion; +}; + +} // end namespace scene +} // end namespace irr + +#endif diff --git a/source/Irrlicht/CLightSceneNode.cpp b/source/Irrlicht/CLightSceneNode.cpp new file mode 100644 index 00000000..7728ba82 --- /dev/null +++ b/source/Irrlicht/CLightSceneNode.cpp @@ -0,0 +1,281 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CLightSceneNode.h" +#include "IVideoDriver.h" +#include "ISceneManager.h" +#include "ICameraSceneNode.h" + +#include "os.h" + +namespace irr +{ +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), DriverLightIndex(-1), LightIsOn(true) +{ + #ifdef _DEBUG + setDebugName("CLightSceneNode"); + #endif + + LightData.DiffuseColor = color; + // set some useful specular color + LightData.SpecularColor = color.getInterpolated(video::SColor(255,255,255,255),0.7f); + + setRadius(radius); +} + + +//! pre render event +void CLightSceneNode::OnRegisterSceneNode() +{ + doLightRecalc(); // TODO: since doLightRecalc has now been added to updateAbsolutePosition it might be possible to remove this one. + + if (IsVisible) + SceneManager->registerNodeForRendering(this, ESNRP_LIGHT); + + ISceneNode::OnRegisterSceneNode(); +} + + +//! render +void CLightSceneNode::render() +{ + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + if (!driver) + return; + + if ( DebugDataVisible & scene::EDS_BBOX ) + { + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + video::SMaterial m; + m.Lighting = false; + driver->setMaterial(m); + + switch ( LightData.Type ) + { + case video::ELT_POINT: + case video::ELT_SPOT: + driver->draw3DBox(BBox, LightData.DiffuseColor.toSColor()); + break; + + case video::ELT_DIRECTIONAL: + driver->draw3DLine(core::vector3df(0.f, 0.f, 0.f), + LightData.Direction * LightData.Radius, + LightData.DiffuseColor.toSColor()); + break; + default: + break; + } + } + + DriverLightIndex = driver->addDynamicLight(LightData); + setVisible(LightIsOn); +} + + +//! sets the light data +void CLightSceneNode::setLightData(const video::SLight& light) +{ + LightData = light; +} + + +//! \return Returns the light data. +const video::SLight& CLightSceneNode::getLightData() const +{ + return LightData; +} + + +//! \return Returns the light data. +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 +{ + return BBox; +} + + +//! 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 +it to (0,1/radius,0). If you want to override this behavior, set the +attenuation after the radius. +\param radius The new radius. */ +void CLightSceneNode::setRadius(f32 radius) +{ + LightData.Radius=radius; + LightData.Attenuation.set(0.f, 1.f/radius, 0.f); + doLightRecalc(); +} + + +//! Gets the light's radius of influence. +/** \return The current radius. */ +f32 CLightSceneNode::getRadius() const +{ + return LightData.Radius; +} + + +//! Sets the light type. +/** \param type The new type. */ +void CLightSceneNode::setLightType(video::E_LIGHT_TYPE type) +{ + LightData.Type=type; +} + + +//! Gets the light type. +/** \return The current light type. */ +video::E_LIGHT_TYPE CLightSceneNode::getLightType() const +{ + return LightData.Type; +} + + +//! Sets whether this light casts shadows. +/** Enabling this flag won't automatically cast shadows, the meshes +will still need shadow scene nodes attached. But one can enable or +disable distinct lights for shadow casting for performance reasons. +\param shadow True if this light shall cast shadows. */ +void CLightSceneNode::enableCastShadow(bool shadow) +{ + LightData.CastShadows=shadow; +} + + +//! Check whether this light casts shadows. +/** \return True if light would cast shadows, else false. */ +bool CLightSceneNode::getCastShadow() const +{ + return LightData.CastShadows; +} + + +void CLightSceneNode::doLightRecalc() +{ + if ((LightData.Type == video::ELT_SPOT) || (LightData.Type == video::ELT_DIRECTIONAL)) + { + LightData.Direction = core::vector3df(.0f,.0f,1.0f); + getAbsoluteTransformation().rotateVect(LightData.Direction); + LightData.Direction.normalize(); + } + if ((LightData.Type == video::ELT_SPOT) || (LightData.Type == video::ELT_POINT)) + { + const f32 r = LightData.Radius * LightData.Radius * 0.5f; + BBox.MaxEdge.set( r, r, r ); + BBox.MinEdge.set( -r, -r, -r ); + //setAutomaticCulling( scene::EAC_BOX ); + setAutomaticCulling( scene::EAC_OFF ); + LightData.Position = getAbsolutePosition(); + } + if (LightData.Type == video::ELT_DIRECTIONAL) + { + BBox.reset( 0, 0, 0 ); + setAutomaticCulling( scene::EAC_OFF ); + } +} + +void CLightSceneNode::updateAbsolutePosition() +{ + ILightSceneNode::updateAbsolutePosition(); + doLightRecalc(); +} + + +//! Writes attributes of the scene node. +void CLightSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + ILightSceneNode::serializeAttributes(out, options); + + out->addColorf ("AmbientColor", LightData.AmbientColor); + out->addColorf ("DiffuseColor", LightData.DiffuseColor); + out->addColorf ("SpecularColor", LightData.SpecularColor); + out->addVector3d("Attenuation", LightData.Attenuation); + out->addFloat ("Radius", LightData.Radius); + out->addFloat ("OuterCone", LightData.OuterCone); + out->addFloat ("InnerCone", LightData.InnerCone); + out->addFloat ("Falloff", LightData.Falloff); + out->addBool ("CastShadows", LightData.CastShadows); + out->addEnum ("LightType", LightData.Type, video::LightTypeNames); +} + +//! Reads attributes of the scene node. +void CLightSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + LightData.AmbientColor = in->getAttributeAsColorf("AmbientColor"); + LightData.DiffuseColor = in->getAttributeAsColorf("DiffuseColor"); + LightData.SpecularColor = in->getAttributeAsColorf("SpecularColor"); + + //TODO: clearify Radius and Linear Attenuation +#if 0 + setRadius ( in->getAttributeAsFloat("Radius") ); +#else + LightData.Radius = in->getAttributeAsFloat("Radius"); +#endif + + if (in->existsAttribute("Attenuation")) // might not exist in older files + LightData.Attenuation = in->getAttributeAsVector3d("Attenuation"); + + if (in->existsAttribute("OuterCone")) // might not exist in older files + LightData.OuterCone = in->getAttributeAsFloat("OuterCone"); + if (in->existsAttribute("InnerCone")) // might not exist in older files + LightData.InnerCone = in->getAttributeAsFloat("InnerCone"); + if (in->existsAttribute("Falloff")) // might not exist in older files + LightData.Falloff = in->getAttributeAsFloat("Falloff"); + LightData.CastShadows = in->getAttributeAsBool("CastShadows"); + LightData.Type = (video::E_LIGHT_TYPE)in->getAttributeAsEnumeration("LightType", video::LightTypeNames); + + doLightRecalc (); + + ILightSceneNode::deserializeAttributes(in, options); +} + +//! Creates a clone of this scene node and its children. +ISceneNode* CLightSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager) +{ + if (!newParent) + newParent = Parent; + if (!newManager) + newManager = SceneManager; + + CLightSceneNode* nb = new CLightSceneNode(newParent, + newManager, ID, RelativeTranslation, LightData.DiffuseColor, LightData.Radius); + + nb->cloneMembers(this, newManager); + nb->LightData = LightData; + nb->BBox = BBox; + + if ( newParent ) + nb->drop(); + return nb; +} + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CLightSceneNode.h b/source/Irrlicht/CLightSceneNode.h new file mode 100644 index 00000000..a3c96c88 --- /dev/null +++ b/source/Irrlicht/CLightSceneNode.h @@ -0,0 +1,109 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_LIGHT_SCENE_NODE_H_INCLUDED__ +#define __C_LIGHT_SCENE_NODE_H_INCLUDED__ + +#include "ILightSceneNode.h" + +namespace irr +{ +namespace scene +{ + +//! Scene node which is a dynamic light. You can switch the light on and off by +//! making it visible or not, and let it be animated by ordinary scene node animators. +class CLightSceneNode : public ILightSceneNode +{ +public: + + //! constructor + CLightSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position, video::SColorf color, f32 range); + + //! pre render event + virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; + + //! render + virtual void render() _IRR_OVERRIDE_; + + //! set node light data from light info + virtual void setLightData(const video::SLight& light) _IRR_OVERRIDE_; + + //! \return Returns the light data. + virtual const video::SLight& getLightData() const _IRR_OVERRIDE_; + + //! \return Returns the light data. + virtual video::SLight& getLightData() _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_LIGHT; } + + //! Writes attributes of the scene node. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! Creates a clone of this scene node and its children. + virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + //! 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 + it to (0,1/radius,0). If you want to override this behavior, set the + attenuation after the radius. + \param radius The new radius. */ + virtual void setRadius(f32 radius) _IRR_OVERRIDE_; + + //! Gets the light's radius of influence. + /** \return The current radius. */ + virtual f32 getRadius() const _IRR_OVERRIDE_; + + //! Sets the light type. + /** \param type The new type. */ + virtual void setLightType(video::E_LIGHT_TYPE type) _IRR_OVERRIDE_; + + //! Gets the light type. + /** \return The current light type. */ + virtual video::E_LIGHT_TYPE getLightType() const _IRR_OVERRIDE_; + + //! Sets whether this light casts shadows. + /** Enabling this flag won't automatically cast shadows, the meshes + will still need shadow scene nodes attached. But one can enable or + disable distinct lights for shadow casting for performance reasons. + \param shadow True if this light shall cast shadows. */ + virtual void enableCastShadow(bool shadow=true) _IRR_OVERRIDE_; + + //! Check whether this light casts shadows. + /** \return True if light would cast shadows, else false. */ + virtual bool getCastShadow() const _IRR_OVERRIDE_; + + //! Updates the absolute position based on the relative and the parents position + virtual void updateAbsolutePosition() _IRR_OVERRIDE_; + +private: + + video::SLight LightData; + core::aabbox3d BBox; + s32 DriverLightIndex; + bool LightIsOn; + void doLightRecalc(); +}; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CLimitReadFile.cpp b/source/Irrlicht/CLimitReadFile.cpp new file mode 100644 index 00000000..f65b7004 --- /dev/null +++ b/source/Irrlicht/CLimitReadFile.cpp @@ -0,0 +1,127 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CLimitReadFile.h" +#include "irrString.h" + +namespace irr +{ +namespace io +{ + + +CLimitReadFile::CLimitReadFile(IReadFile* alreadyOpenedFile, long pos, + long areaSize, const io::path& name) + : Filename(name), AreaStart(0), AreaEnd(0), Pos(0), + File(alreadyOpenedFile) +{ + #ifdef _DEBUG + setDebugName("CLimitReadFile"); + #endif + + if (File) + { + File->grab(); + AreaStart = pos; + AreaEnd = AreaStart + areaSize; + } +} + + +CLimitReadFile::~CLimitReadFile() +{ + if (File) + File->drop(); +} + + +//! returns how much was read +size_t CLimitReadFile::read(void* buffer, size_t sizeToRead) +{ + if (0 == File) + return 0; + +#if 1 + long r = AreaStart + Pos; + long toRead = core::min_(AreaEnd, r + (long)sizeToRead) - core::max_(AreaStart, r); + if (toRead < 0) + return 0; + File->seek(r); + r = (long)File->read(buffer, toRead); + Pos += r; + return r; +#else + const long pos = File->getPos(); + + if (pos >= AreaEnd) + return 0; + + if (pos + (long)sizeToRead >= AreaEnd) + sizeToRead = AreaEnd - pos; + + return File->read(buffer, sizeToRead); +#endif +} + + +//! changes position in file, returns true if successful +bool CLimitReadFile::seek(long finalPos, bool relativeMovement) +{ +#if 1 + Pos = core::s32_clamp(finalPos + (relativeMovement ? Pos : 0 ), 0, AreaEnd - AreaStart); + return true; +#else + const long pos = File->getPos(); + + if (relativeMovement) + { + if (pos + finalPos > AreaEnd) + finalPos = AreaEnd - pos; + } + else + { + finalPos += AreaStart; + if (finalPos > AreaEnd) + return false; + } + + return File->seek(finalPos, relativeMovement); +#endif +} + + +//! returns size of file +long CLimitReadFile::getSize() const +{ + return AreaEnd - AreaStart; +} + + +//! returns where in the file we are. +long CLimitReadFile::getPos() const +{ +#if 1 + return Pos; +#else + return File->getPos() - AreaStart; +#endif +} + + +//! returns name of file +const io::path& CLimitReadFile::getFileName() const +{ + return Filename; +} + + +IReadFile* createLimitReadFile(const io::path& fileName, IReadFile* alreadyOpenedFile, long pos, long areaSize) +{ + return new CLimitReadFile(alreadyOpenedFile, pos, areaSize, fileName); +} + + +} // end namespace io +} // end namespace irr + diff --git a/source/Irrlicht/CLimitReadFile.h b/source/Irrlicht/CLimitReadFile.h new file mode 100644 index 00000000..d95511fe --- /dev/null +++ b/source/Irrlicht/CLimitReadFile.h @@ -0,0 +1,68 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_LIMIT_READ_FILE_H_INCLUDED__ +#define __C_LIMIT_READ_FILE_H_INCLUDED__ + +#include "IReadFile.h" +#include "irrString.h" + +namespace irr +{ + class CUnicodeConverter; + +namespace io +{ + + /*! this is a read file, which is limited to some boundaries, + so that it may only start from a certain file position + and may only read until a certain file position. + This can be useful, for example for reading uncompressed files + in an archive (zip, tar). + !*/ + class CLimitReadFile : public IReadFile + { + public: + + CLimitReadFile(IReadFile* alreadyOpenedFile, long pos, long areaSize, const io::path& name); + + virtual ~CLimitReadFile(); + + //! returns how much was read + virtual size_t read(void* buffer, size_t sizeToRead) _IRR_OVERRIDE_; + + //! changes position in file, returns true if successful + //! if relativeMovement==true, the pos is changed relative to current pos, + //! otherwise from begin of file + virtual bool seek(long finalPos, bool relativeMovement = false) _IRR_OVERRIDE_; + + //! returns size of file + virtual long getSize() const _IRR_OVERRIDE_; + + //! returns where in the file we are. + virtual long getPos() const _IRR_OVERRIDE_; + + //! returns name of file + virtual const io::path& getFileName() const _IRR_OVERRIDE_; + + //! Get the type of the class implementing this interface + virtual EREAD_FILE_TYPE getType() const _IRR_OVERRIDE_ + { + return ERFT_LIMIT_READ_FILE; + } + + private: + + io::path Filename; + long AreaStart; + long AreaEnd; + long Pos; + IReadFile* File; + }; + +} // end namespace io +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CLogger.cpp b/source/Irrlicht/CLogger.cpp new file mode 100644 index 00000000..5b3feeca --- /dev/null +++ b/source/Irrlicht/CLogger.cpp @@ -0,0 +1,102 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CLogger.h" + +namespace irr +{ + + CLogger::CLogger(IEventReceiver* r) + : LogLevel(ELL_INFORMATION), Receiver(r) + { + #ifdef _DEBUG + setDebugName("CLogger"); + #endif + } + + //! Returns the current set log level. + ELOG_LEVEL CLogger::getLogLevel() const + { + return LogLevel; + } + + //! Sets a new log level. + void CLogger::setLogLevel(ELOG_LEVEL ll) + { + LogLevel = ll; + } + + //! Prints out a text into the log + void CLogger::log(const c8* text, ELOG_LEVEL ll) + { + if (ll < LogLevel) + return; + + if (Receiver) + { + SEvent event; + event.EventType = EET_LOG_TEXT_EVENT; + event.LogEvent.Text = text; + event.LogEvent.Level = ll; + if (Receiver->OnEvent(event)) + return; + } + + os::Printer::print(text); + } + + + //! Prints out a text into the log + void CLogger::log(const c8* text, const c8* hint, ELOG_LEVEL ll) + { + if (ll < LogLevel) + return; + + core::stringc s = text; + s += ": "; + s += hint; + log (s.c_str(), ll); + } + + //! Prints out a text into the log + void CLogger::log(const wchar_t* text, ELOG_LEVEL ll) + { + if (ll < LogLevel) + return; + + core::stringc s = text; + log(s.c_str(), ll); + } + + + //! Prints out a text into the log + void CLogger::log(const wchar_t* text, const wchar_t* hint, ELOG_LEVEL ll) + { + if (ll < LogLevel) + return; + + core::stringc s1 = text; + core::stringc s2 = hint; + log(s1.c_str(), s2.c_str(), ll); + } + + //! Prints out a text into the log + void CLogger::log(const c8* text, const wchar_t* hint, ELOG_LEVEL ll) + { + if (ll < LogLevel) + return; + + core::stringc s2 = hint; + log( text, s2.c_str(), ll); + } + + //! Sets a new event receiver + void CLogger::setReceiver(IEventReceiver* r) + { + Receiver = r; + } + + +} // end namespace irr + diff --git a/source/Irrlicht/CLogger.h b/source/Irrlicht/CLogger.h new file mode 100644 index 00000000..2f58da66 --- /dev/null +++ b/source/Irrlicht/CLogger.h @@ -0,0 +1,56 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_LOGGER_H_INCLUDED__ +#define __C_LOGGER_H_INCLUDED__ + +#include "ILogger.h" +#include "os.h" +#include "irrString.h" +#include "IEventReceiver.h" + +namespace irr +{ + +//! Class for logging messages, warnings and errors to stdout +class CLogger : public ILogger +{ +public: + + CLogger(IEventReceiver* r); + + //! Returns the current set log level. + virtual ELOG_LEVEL getLogLevel() const _IRR_OVERRIDE_; + + //! Sets a new log level. virtual void setLogLevel(ELOG_LEVEL ll) _IRR_OVERRIDE_; + virtual void setLogLevel(ELOG_LEVEL ll) _IRR_OVERRIDE_; + + //! Prints out a text into the log + virtual void log(const c8* text, ELOG_LEVEL ll=ELL_INFORMATION) _IRR_OVERRIDE_; + + //! Prints out a text into the log + virtual void log(const wchar_t* text, ELOG_LEVEL ll=ELL_INFORMATION) _IRR_OVERRIDE_; + + //! Prints out a text into the log + virtual void log(const c8* text, const c8* hint, ELOG_LEVEL ll=ELL_INFORMATION) _IRR_OVERRIDE_; + + //! Prints out a text into the log + virtual void log(const c8* text, const wchar_t* hint, ELOG_LEVEL ll=ELL_INFORMATION) _IRR_OVERRIDE_; + + //! Prints out a text into the log + virtual void log(const wchar_t* text, const wchar_t* hint, ELOG_LEVEL ll=ELL_INFORMATION) _IRR_OVERRIDE_; + + //! Sets a new event receiver + void setReceiver(IEventReceiver* r); + +private: + + ELOG_LEVEL LogLevel; + IEventReceiver* Receiver; +}; + +} // end namespace + +#endif + diff --git a/source/Irrlicht/CMD2MeshFileLoader.cpp b/source/Irrlicht/CMD2MeshFileLoader.cpp new file mode 100644 index 00000000..f32e4e3a --- /dev/null +++ b/source/Irrlicht/CMD2MeshFileLoader.cpp @@ -0,0 +1,363 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_MD2_LOADER_ + +#include "CMD2MeshFileLoader.h" +#include "CAnimatedMeshMD2.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + + + // structs needed to load the md2-format + + const s32 MD2_MAGIC_NUMBER = 844121161; + const s32 MD2_VERSION = 8; + const s32 MD2_MAX_VERTS = 2048; + +// byte-align structures +#include "irrpack.h" + + 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 +#include "irrunpack.h" + +//! Constructor +CMD2MeshFileLoader::CMD2MeshFileLoader() +{ + #ifdef _DEBUG + setDebugName("CMD2MeshFileLoader"); + #endif +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool CMD2MeshFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "md2" ); +} + + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IReferenceCounted::drop() for more information. +IAnimatedMesh* CMD2MeshFileLoader::createMesh(io::IReadFile* file) +{ + IAnimatedMesh* msh = new CAnimatedMeshMD2(); + if (msh) + { + if (loadFile(file, (CAnimatedMeshMD2*)msh) ) + return msh; + + msh->drop(); + } + + 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 + 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)) + { + delete[] textureCoords; + 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))) + { + delete[] triangles; + delete[] textureCoords; + + 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 colors + 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; + + // init buffer with start frame. + mesh->getMesh(0); + return true; +} + +} // end namespace scene +} // end namespace irr + + +#endif // _IRR_COMPILE_WITH_MD2_LOADER_ diff --git a/source/Irrlicht/CMD2MeshFileLoader.h b/source/Irrlicht/CMD2MeshFileLoader.h new file mode 100644 index 00000000..73711a52 --- /dev/null +++ b/source/Irrlicht/CMD2MeshFileLoader.h @@ -0,0 +1,45 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_MD2_MESH_FILE_LOADER_H_INCLUDED__ +#define __C_MD2_MESH_FILE_LOADER_H_INCLUDED__ + +#include "IMeshLoader.h" + +namespace irr +{ +namespace scene +{ + +class CAnimatedMeshMD2; + +//! Meshloader capable of loading MD2 files +class CMD2MeshFileLoader : public IMeshLoader +{ +public: + + //! Constructor + CMD2MeshFileLoader(); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".bsp") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! creates/loads an animated mesh from the file. + //! \return Pointer to the created mesh. Returns 0 if loading failed. + //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). + //! See IReferenceCounted::drop() for more information. + virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_; + +private: + //! Loads the file data into the mesh + bool loadFile(io::IReadFile* file, CAnimatedMeshMD2* mesh); + +}; + +} // end namespace scene +} // end namespace irr + +#endif // __C_MD2_MESH_LOADER_H_INCLUDED__ + diff --git a/source/Irrlicht/CMD3MeshFileLoader.cpp b/source/Irrlicht/CMD3MeshFileLoader.cpp new file mode 100644 index 00000000..68f8d80d --- /dev/null +++ b/source/Irrlicht/CMD3MeshFileLoader.cpp @@ -0,0 +1,53 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_MD3_LOADER_ + +#include "CMD3MeshFileLoader.h" +#include "CAnimatedMeshMD3.h" +#include "irrString.h" + +namespace irr +{ +namespace scene +{ + +//! Constructor +CMD3MeshFileLoader::CMD3MeshFileLoader( scene::ISceneManager* smgr) +: SceneManager(smgr) +{ +} + + +//! destructor +CMD3MeshFileLoader::~CMD3MeshFileLoader() +{ +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool CMD3MeshFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "md3" ); +} + + +IAnimatedMesh* CMD3MeshFileLoader::createMesh(io::IReadFile* file) +{ + CAnimatedMeshMD3 * mesh = new CAnimatedMeshMD3(); + + if ( mesh->loadModelFile ( 0, file, SceneManager->getFileSystem(), SceneManager->getVideoDriver() ) ) + return mesh; + + mesh->drop (); + return 0; +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_MD3_LOADER_ diff --git a/source/Irrlicht/CMD3MeshFileLoader.h b/source/Irrlicht/CMD3MeshFileLoader.h new file mode 100644 index 00000000..c2684502 --- /dev/null +++ b/source/Irrlicht/CMD3MeshFileLoader.h @@ -0,0 +1,49 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_MD3_MESH_FILE_LOADER_H_INCLUDED__ +#define __C_MD3_MESH_FILE_LOADER_H_INCLUDED__ + +#include "IMeshLoader.h" +#include "IFileSystem.h" +#include "IVideoDriver.h" +#include "ISceneManager.h" +#include "IQ3Shader.h" + +namespace irr +{ +namespace scene +{ + +//! Meshloader capable of loading md3 files. +class CMD3MeshFileLoader : public IMeshLoader +{ +public: + + //! Constructor + CMD3MeshFileLoader( scene::ISceneManager* smgr ); + + //! destructor + virtual ~CMD3MeshFileLoader(); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".bsp") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! creates/loads an animated mesh from the file. + //! \return Pointer to the created mesh. Returns 0 if loading failed. + //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). + //! See IReferenceCounted::drop() for more information. + virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_; + +private: + scene::ISceneManager* SceneManager; + +}; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CMS3DMeshFileLoader.cpp b/source/Irrlicht/CMS3DMeshFileLoader.cpp new file mode 100644 index 00000000..4ad18aa2 --- /dev/null +++ b/source/Irrlicht/CMS3DMeshFileLoader.cpp @@ -0,0 +1,872 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// 2019 additional alignment and big_endian fixes by Corto and Salas00 +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_MS3D_LOADER_ + +#include "IReadFile.h" +#include "os.h" +#include "CMS3DMeshFileLoader.h" +#include "CSkinnedMesh.h" + + +namespace irr +{ +namespace scene +{ + +#ifdef _DEBUG +#define _IRR_DEBUG_MS3D_LOADER_ +#endif + +// byte-align structures +#include "irrpack.h" + +namespace { +// File header +struct MS3DHeader +{ + char ID[10]; + int Version; +} PACK_STRUCT; + +// Vertex information +struct MS3DVertex +{ + u8 pad1[3]; + u8 Flags; + float Vertex[3]; + char BoneID; + u8 RefCount; + u8 pad2[2]; +} PACK_STRUCT; + +#define MS3DVERTEX_NUM_PAD_BYTES 5 + +// Triangle information +struct MS3DTriangle +{ + u16 Flags; + u16 VertexIndices[3]; + float VertexNormals[3][3]; + float S[3], T[3]; + u8 SmoothingGroup; + u8 GroupIndex; + u8 pad1[2]; +} PACK_STRUCT; + +#define MS3DTRIANGLE_NUM_PAD_BYTES 2 + +// Material information +struct MS3DMaterial +{ + char Name[32]; + float Ambient[4]; + float Diffuse[4]; + float Specular[4]; + float Emissive[4]; + float Shininess; // 0.0f - 128.0f + float Transparency; // 0.0f - 1.0f + u8 Mode; // 0, 1, 2 is unused now + char Texture[128]; + char Alphamap[128]; + u8 pad1[3]; +} PACK_STRUCT; + +#define MS3DMATERIAL_NUM_PAD_BYTES 3 + +// Joint information +struct MS3DJoint +{ + u8 pad[3]; + u8 Flags; + char Name[32]; + char ParentName[32]; + float Rotation[3]; + float Translation[3]; + u16 NumRotationKeyframes; + u16 NumTranslationKeyframes; +} PACK_STRUCT; + +#define MS3DJOINT_NUM_PAD_BYTES 3 + +// Keyframe data +struct MS3DKeyframe +{ + float Time; + float Parameter[3]; +} PACK_STRUCT; + +// vertex weights in 1.8.x +struct MS3DVertexWeights +{ + char boneIds[3]; + u8 weights[3]; +} PACK_STRUCT; + +} // end namespace + +// Default alignment +#include "irrunpack.h" + +// Get float encoded in little endian in way not causing troubles when floats have to be memory aligned. +static inline float get_unaligned_le_float(const u8 *ptr) +{ + union { + u8 u[4]; + float f; + } tmp; +#ifdef __BIG_ENDIAN__ + tmp.u[0] = ptr[3]; + tmp.u[1] = ptr[2]; + tmp.u[2] = ptr[1]; + tmp.u[3] = ptr[0]; +#else + tmp.f = *(float*)ptr; +#endif + return tmp.f; +} + + +struct SGroup +{ + core::stringc Name; + core::array VertexIds; + u16 MaterialIdx; +}; + +//! Constructor +CMS3DMeshFileLoader::CMS3DMeshFileLoader(video::IVideoDriver *driver) +: Driver(driver), AnimatedMesh(0) +{ + #ifdef _DEBUG + setDebugName("CMS3DMeshFileLoader"); + #endif +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool CMS3DMeshFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "ms3d" ); +} + + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IReferenceCounted::drop() for more information. +IAnimatedMesh* CMS3DMeshFileLoader::createMesh(io::IReadFile* file) +{ + if (!file) + return 0; + + AnimatedMesh = new CSkinnedMesh(); + + if ( load(file) ) + { + AnimatedMesh->finalize(); + } + else + { + AnimatedMesh->drop(); + AnimatedMesh = 0; + } + + return AnimatedMesh; +} + + +//! loads a milkshape file +bool CMS3DMeshFileLoader::load(io::IReadFile* file) +{ + if (!file) + return false; + + // find file size + const long fileSize = file->getSize(); + + // read whole file + + u8* buffer = new u8[fileSize]; + size_t read = file->read(buffer, fileSize); + if (read != (size_t)fileSize) + { + delete [] buffer; + os::Printer::log("Could not read full file. Loading failed", file->getFileName(), ELL_ERROR); + return false; + } + + // read header + + const u8 *pPtr = (u8*)((void*)buffer); + MS3DHeader *pHeader = (MS3DHeader*)pPtr; + pPtr += sizeof(MS3DHeader); + + if ( strncmp( pHeader->ID, "MS3D000000", 10 ) != 0 ) + { + delete [] buffer; + os::Printer::log("Not a valid Milkshape3D Model File. Loading failed", file->getFileName(), ELL_ERROR); + return false; + } + +#ifdef __BIG_ENDIAN__ + pHeader->Version = os::Byteswap::byteswap(pHeader->Version); +#endif + if ( pHeader->Version < 3 || pHeader->Version > 4 ) + { + delete [] buffer; + os::Printer::log("Only Milkshape3D version 3 and 4 (1.3 to 1.8) is supported. Loading failed", file->getFileName(), ELL_ERROR); + return false; + } +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("Loaded header version", core::stringc(pHeader->Version).c_str()); +#endif + + // get pointers to data + + // vertices + u16 numVertices = *(u16*)pPtr; +#ifdef __BIG_ENDIAN__ + numVertices = os::Byteswap::byteswap(numVertices); +#endif +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("Load vertices", core::stringc(numVertices).c_str()); +#endif + + pPtr += sizeof(u16); + MS3DVertex *vertices = new MS3DVertex[numVertices]; + if (pPtr + ((sizeof(MS3DVertex) - MS3DVERTEX_NUM_PAD_BYTES) * numVertices) > buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + for (u16 tmp=0; tmp buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + for (u16 tmp=0; tmp groups; + groups.reallocate(numGroups); + + //store groups + u32 i; + for (i=0; i buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + } + + // load materials + u16 numMaterials = *(u16*)pPtr; +#ifdef __BIG_ENDIAN__ + numMaterials = os::Byteswap::byteswap(numMaterials); +#endif +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("Load Materials", core::stringc(numMaterials).c_str()); +#endif + pPtr += sizeof(u16); + + if(numMaterials == 0) + { + // if there are no materials, add at least one buffer + AnimatedMesh->addMeshBuffer(); + } + + MS3DMaterial *material = new MS3DMaterial; + for (i=0; iAmbient[j] = os::Byteswap::byteswap(material->Ambient[j]); + for (u16 j=0; j<4; ++j) + material->Diffuse[j] = os::Byteswap::byteswap(material->Diffuse[j]); + for (u16 j=0; j<4; ++j) + material->Specular[j] = os::Byteswap::byteswap(material->Specular[j]); + for (u16 j=0; j<4; ++j) + material->Emissive[j] = os::Byteswap::byteswap(material->Emissive[j]); + material->Shininess = os::Byteswap::byteswap(material->Shininess); + material->Transparency = os::Byteswap::byteswap(material->Transparency); +#endif + pPtr += (sizeof(MS3DMaterial) - MS3DMATERIAL_NUM_PAD_BYTES); + if (pPtr > buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + + scene::SSkinMeshBuffer *tmpBuffer = AnimatedMesh->addMeshBuffer(); + + tmpBuffer->Material.MaterialType = video::EMT_SOLID; + + tmpBuffer->Material.AmbientColor = video::SColorf(material->Ambient[0], material->Ambient[1], material->Ambient[2], material->Ambient[3]).toSColor (); + tmpBuffer->Material.DiffuseColor = video::SColorf(material->Diffuse[0], material->Diffuse[1], material->Diffuse[2], material->Diffuse[3]).toSColor (); + tmpBuffer->Material.EmissiveColor = video::SColorf(material->Emissive[0], material->Emissive[1], material->Emissive[2], material->Emissive[3]).toSColor (); + tmpBuffer->Material.SpecularColor = video::SColorf(material->Specular[0], material->Specular[1], material->Specular[2], material->Specular[3]).toSColor (); + tmpBuffer->Material.Shininess = material->Shininess; + + core::stringc TexturePath(material->Texture); + if (TexturePath.trim()!="") + { + TexturePath=stripPathFromString(file->getFileName(),true) + stripPathFromString(TexturePath,false); + tmpBuffer->Material.setTexture(0, Driver->getTexture(TexturePath)); + } + + core::stringc AlphamapPath=(const c8*)material->Alphamap; + if (AlphamapPath.trim()!="") + { + AlphamapPath=stripPathFromString(file->getFileName(),true) + stripPathFromString(AlphamapPath,false); + tmpBuffer->Material.setTexture(2, Driver->getTexture(AlphamapPath)); + } + } + delete material; + + // animation time + + + f32 framesPerSecond = get_unaligned_le_float(pPtr); + +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("FPS", core::stringc(framesPerSecond).c_str()); +#endif + pPtr += sizeof(float) * 2; // fps and current time + + if (framesPerSecond<1.f) + framesPerSecond=1.f; + AnimatedMesh->setAnimationSpeed(framesPerSecond); + +// ignore, calculated inside SkinnedMesh +// s32 frameCount = *(int*)pPtr; +#ifdef __BIG_ENDIAN__ +// frameCount = os::Byteswap::byteswap(frameCount); +#endif + pPtr += sizeof(int); + + u16 jointCount = *(u16*)pPtr; +#ifdef __BIG_ENDIAN__ + jointCount = os::Byteswap::byteswap(jointCount); +#endif +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("Joints", core::stringc(jointCount).c_str()); +#endif + pPtr += sizeof(u16); + if (pPtr > buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + + core::array parentNames; + parentNames.reallocate(jointCount); + + // load joints + for (i=0; iRotation[0] = %p (%d)\n", &pJoint->Rotation[0], (int)((long long)(&pJoint->Rotation[0]) % 4)); + memcpy(&pJoint->Flags, pPtr, sizeof(MS3DJoint) - MS3DJOINT_NUM_PAD_BYTES); + +#ifdef __BIG_ENDIAN__ + for (j=0; j<3; ++j) + pJoint->Rotation[j] = os::Byteswap::byteswap(pJoint->Rotation[j]); + for (j=0; j<3; ++j) + pJoint->Translation[j] = os::Byteswap::byteswap(pJoint->Translation[j]); + pJoint->NumRotationKeyframes= os::Byteswap::byteswap(pJoint->NumRotationKeyframes); + pJoint->NumTranslationKeyframes = os::Byteswap::byteswap(pJoint->NumTranslationKeyframes); +#endif + pPtr = pPtr + sizeof(MS3DJoint) - MS3DJOINT_NUM_PAD_BYTES; + if (pPtr > buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + + ISkinnedMesh::SJoint *jnt = AnimatedMesh->addJoint(); + + jnt->Name = pJoint->Name; +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("Joint", jnt->Name.c_str()); + os::Printer::log("Rotation keyframes", core::stringc(pJoint->NumRotationKeyframes).c_str()); + os::Printer::log("Translation keyframes", core::stringc(pJoint->NumTranslationKeyframes).c_str()); +#endif + jnt->LocalMatrix.makeIdentity(); + jnt->LocalMatrix.setRotationRadians( + core::vector3df(pJoint->Rotation[0], pJoint->Rotation[1], pJoint->Rotation[2]) ); + // convert right-handed to left-handed + jnt->LocalMatrix[2]=-jnt->LocalMatrix[2]; + jnt->LocalMatrix[6]=-jnt->LocalMatrix[6]; + jnt->LocalMatrix[8]=-jnt->LocalMatrix[8]; + jnt->LocalMatrix[9]=-jnt->LocalMatrix[9]; + + jnt->LocalMatrix.setTranslation( + core::vector3df(pJoint->Translation[0], pJoint->Translation[1], -pJoint->Translation[2]) ); + jnt->Animatedposition.set(jnt->LocalMatrix.getTranslation()); + jnt->Animatedrotation.set(jnt->LocalMatrix.getRotationDegrees()); + + parentNames.push_back( (c8*)pJoint->ParentName ); + + /*if (pJoint->NumRotationKeyframes || + pJoint->NumTranslationKeyframes) + HasAnimation = true; + */ + + MS3DKeyframe* kf = new MS3DKeyframe; + + // get rotation keyframes + const u16 numRotationKeyframes = pJoint->NumRotationKeyframes; + for (j=0; j < numRotationKeyframes; ++j) + { + memcpy(kf, pPtr, sizeof(MS3DKeyframe)); + //printf("rotation kf = %p (%d)\n", kf, (int)((long long)kf % 4)); +#ifdef __BIG_ENDIAN__ + kf->Time = os::Byteswap::byteswap(kf->Time); + for (u32 l=0; l<3; ++l) + kf->Parameter[l] = os::Byteswap::byteswap(kf->Parameter[l]); +#endif + pPtr += sizeof(MS3DKeyframe); + if (pPtr > buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + + ISkinnedMesh::SRotationKey *k=AnimatedMesh->addRotationKey(jnt); + k->frame = kf->Time * framesPerSecond-1; + + core::matrix4 tmpMatrix; + + tmpMatrix.setRotationRadians( + core::vector3df(kf->Parameter[0], kf->Parameter[1], kf->Parameter[2]) ); + // convert right-handed to left-handed + tmpMatrix[2]=-tmpMatrix[2]; + tmpMatrix[6]=-tmpMatrix[6]; + tmpMatrix[8]=-tmpMatrix[8]; + tmpMatrix[9]=-tmpMatrix[9]; + + tmpMatrix=jnt->LocalMatrix*tmpMatrix; + + // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched from tmpMatrix to tmpMatrix.getTransposed() for downward compatibility. + // Not tested so far if this was correct or wrong before quaternion fix! + k->rotation = core::quaternion(tmpMatrix.getTransposed()); + } + + // get translation keyframes + const u16 numTranslationKeyframes = pJoint->NumTranslationKeyframes; + for (j=0; jTime = os::Byteswap::byteswap(kf->Time); + for (u32 l=0; l<3; ++l) + kf->Parameter[l] = os::Byteswap::byteswap(kf->Parameter[l]); +#endif + pPtr += sizeof(MS3DKeyframe); + if (pPtr > buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + + ISkinnedMesh::SPositionKey *k=AnimatedMesh->addPositionKey(jnt); + k->frame = kf->Time * framesPerSecond-1; + + k->position = core::vector3df + (kf->Parameter[0]+pJoint->Translation[0], + kf->Parameter[1]+pJoint->Translation[1], + -kf->Parameter[2]-pJoint->Translation[2]); + } + + delete kf; + delete pJoint; + } + + core::array vertexWeights; + f32 weightFactor=0; + + if (jointCount && (pHeader->Version == 4) && (pPtr < buffer+fileSize)) + { + s32 subVersion = *(s32*)pPtr; // comment subVersion, always 1 +#ifdef __BIG_ENDIAN__ + subVersion = os::Byteswap::byteswap(subVersion); +#endif + pPtr += sizeof(s32); + + for (u32 j=0; j<4; ++j) // four comment groups + { +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("Skipping comment group", core::stringc(j+1).c_str()); +#endif + u32 numComments = *(u32*)pPtr; +#ifdef __BIG_ENDIAN__ + numComments = os::Byteswap::byteswap(numComments); +#endif + pPtr += sizeof(u32); + for (i=0; i buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + } + + if (pPtr < buffer+fileSize) + { + subVersion = *(s32*)pPtr; // vertex subVersion, 1 or 2 +#ifdef __BIG_ENDIAN__ + subVersion = os::Byteswap::byteswap(subVersion); +#endif + if (subVersion==1) + weightFactor=1.f/255.f; + else + weightFactor=1.f/100.f; + pPtr += sizeof(s32); + +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("Reading vertex weights"); +#endif + // read vertex weights, ignoring data 'extra' from 1.8.2 + vertexWeights.reallocate(numVertices); + const char offset = (subVersion==1)?6:10; + for (i=0; i buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found.", file->getFileName(), ELL_ERROR); + return false; + } + } + + if (pPtr < buffer+fileSize) + { + subVersion = *(s32*)pPtr; // joint subVersion, 1 or 2 +#ifdef __BIG_ENDIAN__ + subVersion = os::Byteswap::byteswap(subVersion); +#endif + pPtr += sizeof(s32); + // skip joint colors +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("Skip joint color"); +#endif + pPtr += 3*sizeof(float)*jointCount; + + if (pPtr > buffer+fileSize) + { + delete [] buffer; + os::Printer::log("Loading failed. Corrupted data found", file->getFileName(), ELL_ERROR); + return false; + } + } + + if (pPtr < buffer+fileSize) + { + subVersion = *(s32*)pPtr; // model subVersion, 1 or 2 +#ifdef __BIG_ENDIAN__ + subVersion = os::Byteswap::byteswap(subVersion); +#endif + pPtr += sizeof(s32); +#ifdef _IRR_DEBUG_MS3D_LOADER_ + os::Printer::log("Skip model extra information"); +#endif + // now the model extra information would follow + // we also skip this for now + } + } + + //find parent of every joint + for (u32 jointnum=0; jointnumgetAllJoints().size(); ++jointnum) + { + for (u32 j2=0; j2getAllJoints().size(); ++j2) + { + if (jointnum != j2 && parentNames[jointnum] == AnimatedMesh->getAllJoints()[j2]->Name ) + { + AnimatedMesh->getAllJoints()[j2]->Children.push_back(AnimatedMesh->getAllJoints()[jointnum]); + break; + } + } + } + + // create vertices and indices, attach them to the joints. + video::S3DVertex v; + core::array *Vertices; + core::array Indices; + + for (i=0; igetMeshBuffers()[tmp]->Vertices_Standard; + + for (s32 j = 2; j!=-1; --j) + { + const u32 vertidx = triangles[i].VertexIndices[j]; + + v.TCoords.X = triangles[i].S[j]; + v.TCoords.Y = triangles[i].T[j]; + + v.Normal.X = triangles[i].VertexNormals[j][0]; + v.Normal.Y = triangles[i].VertexNormals[j][1]; + v.Normal.Z = triangles[i].VertexNormals[j][2]; + + if(triangles[i].GroupIndex < groups.size() && + groups[triangles[i].GroupIndex].MaterialIdx < AnimatedMesh->getMeshBuffers().size()) + v.Color = AnimatedMesh->getMeshBuffers()[groups[triangles[i].GroupIndex].MaterialIdx]->Material.DiffuseColor; + else + v.Color.set(255,255,255,255); + + v.Pos.X = vertices[vertidx].Vertex[0]; + v.Pos.Y = vertices[vertidx].Vertex[1]; + v.Pos.Z = vertices[vertidx].Vertex[2]; + + // check if we already have this vertex in our vertex array + s32 index = -1; + for (u32 iV = 0; iV < Vertices->size(); ++iV) + { + if (v == (*Vertices)[iV]) + { + index = (s32)iV; + break; + } + } + + if (index == -1) + { + index = Vertices->size(); + const u32 matidx = groups[triangles[i].GroupIndex].MaterialIdx; + if (vertexWeights.size()==0) + { + const s32 boneid = vertices[vertidx].BoneID; + if ((u32)boneid < AnimatedMesh->getAllJoints().size()) + { + ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]); + w->buffer_id = matidx; + w->strength = 1.0f; + w->vertex_id = index; + } + } + else if (jointCount) // new weights from 1.8.x + { + f32 sum = 1.0f; + s32 boneid = vertices[vertidx].BoneID; + if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (vertexWeights[vertidx].weights[0] != 0)) + { + ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]); + w->buffer_id = matidx; + sum -= (w->strength = vertexWeights[vertidx].weights[0]*weightFactor); + w->vertex_id = index; + } + boneid = vertexWeights[vertidx].boneIds[0]; + if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (vertexWeights[vertidx].weights[1] != 0)) + { + ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]); + w->buffer_id = matidx; + sum -= (w->strength = vertexWeights[vertidx].weights[1]*weightFactor); + w->vertex_id = index; + } + boneid = vertexWeights[vertidx].boneIds[1]; + if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (vertexWeights[vertidx].weights[2] != 0)) + { + ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]); + w->buffer_id = matidx; + sum -= (w->strength = vertexWeights[vertidx].weights[2]*weightFactor); + w->vertex_id = index; + } + boneid = vertexWeights[vertidx].boneIds[2]; + if (((u32)boneid < AnimatedMesh->getAllJoints().size()) && (sum > 0.f)) + { + ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]); + w->buffer_id = matidx; + w->strength = sum; + w->vertex_id = index; + } + // fallback, if no bone chosen. Seems to be an error in the specs + boneid = vertices[vertidx].BoneID; + if ((sum == 1.f) && ((u32)boneid < AnimatedMesh->getAllJoints().size())) + { + ISkinnedMesh::SWeight *w=AnimatedMesh->addWeight(AnimatedMesh->getAllJoints()[boneid]); + w->buffer_id = matidx; + w->strength = 1.f; + w->vertex_id = index; + } + } + + Vertices->push_back(v); + } + Indices.push_back(index); + } + } + + //create groups + s32 iIndex = -1; + for (i=0; i= AnimatedMesh->getMeshBuffers().size()) + grp.MaterialIdx = 0; + + core::array& indices = AnimatedMesh->getMeshBuffers()[grp.MaterialIdx]->Indices; + + for (u32 k=0; k < grp.VertexIds.size(); ++k) + for (u32 l=0; l<3; ++l) + indices.push_back(Indices[++iIndex]); + } + + delete [] buffer; + delete [] triangles; + delete [] vertices; + + return true; +} + + +core::stringc CMS3DMeshFileLoader::stripPathFromString(const core::stringc& inString, bool returnPath) const +{ + s32 slashIndex=inString.findLast('/'); // forward slash + s32 backSlash=inString.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 inString; + } + + if (returnPath) + return inString.subString(0, slashIndex + 1); + else + return inString.subString(slashIndex+1, inString.size() - (slashIndex+1)); +} + + +} // end namespace scene +} // end namespace irr + +#endif diff --git a/source/Irrlicht/CMS3DMeshFileLoader.h b/source/Irrlicht/CMS3DMeshFileLoader.h new file mode 100644 index 00000000..5bcefb41 --- /dev/null +++ b/source/Irrlicht/CMS3DMeshFileLoader.h @@ -0,0 +1,49 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_MS3D_MESH_FILE_LOADER_H_INCLUDED__ +#define __C_MS3D_MESH_FILE_LOADER_H_INCLUDED__ + +#include "IMeshLoader.h" +#include "IVideoDriver.h" +#include "CSkinnedMesh.h" + +namespace irr +{ +namespace scene +{ + +//! Meshloader capable of loading Milkshape 3D files +class CMS3DMeshFileLoader : public IMeshLoader +{ +public: + + //! Constructor + CMS3DMeshFileLoader(video::IVideoDriver* driver); + + //! returns true if the file might be loadable by this class + //! based on the file extension (e.g. ".bsp") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! creates/loads an animated mesh from the file. + //! \return Pointer to the created mesh. Returns 0 if loading failed. + //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). + //! See IReferenceCounted::drop() for more information. + virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_; + +private: + + core::stringc stripPathFromString(const core::stringc& inString, bool returnPath) const; + + bool load(io::IReadFile* file); + video::IVideoDriver* Driver; + CSkinnedMesh* AnimatedMesh; +}; + +} // end namespace scene +} // end namespace irr + +#endif + + diff --git a/source/Irrlicht/CMY3DHelper.h b/source/Irrlicht/CMY3DHelper.h new file mode 100644 index 00000000..c1566d11 --- /dev/null +++ b/source/Irrlicht/CMY3DHelper.h @@ -0,0 +1,445 @@ +// Copyright (C) 2002-2012 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 originally written by ZDimitor. + +//---------------------------------------------------------------------- +// somefuncs.h - part of the My3D Tools +// +// This tool was created by Zhuck Dmitry (ZDimitor). +// Everyone can use it as wants ( i'll be happy if it helps to someone :) ). +//---------------------------------------------------------------------- + +//********************************************************************** +// some useful functions +//********************************************************************** + +#ifndef __C_MY3D_HELPER_H_INCLUDED__ +#define __C_MY3D_HELPER_H_INCLUDED__ + +#include "irrTypes.h" + +namespace irr +{ +namespace scene +{ + +//********************************************************************** +// MY3D stuff +//********************************************************************** + +// byte-align structures +#include "irrpack.h" + +struct SMyVector3 +{ SMyVector3 () {;} + SMyVector3 (f32 __X, f32 __Y, f32 __Z) + : X(__X), Y(__Y), Z(__Z) {} + f32 X, Y, Z; +} PACK_STRUCT; + +struct SMyVector2 +{ SMyVector2 () {;} + SMyVector2(f32 __X, f32 __Y) + : X(__X), Y(__Y) {} + f32 X, Y; +} PACK_STRUCT; + +struct SMyVertex +{ SMyVertex () {;} + SMyVertex (SMyVector3 _Coord, SMyColor _Color, SMyVector3 _Normal) + :Coord(_Coord), Color(_Color), Normal(_Normal) {;} + SMyVector3 Coord; + SMyColor Color; + SMyVector3 Normal; +} PACK_STRUCT; + +struct SMyTVertex +{ SMyTVertex () {;} + SMyTVertex (SMyVector2 _TCoord) + : TCoord(_TCoord) {;} + SMyVector2 TCoord; +} PACK_STRUCT; + +struct SMyFace +{ SMyFace() {;} + SMyFace(u32 __A, u32 __B, u32 __C) + : A(__A), B(__B), C(__C) {} + u32 A, B, C; +} PACK_STRUCT; + +// file header (6 bytes) +struct SMyFileHeader +{ u32 MyId; // MY3D + u16 Ver; // Version +} PACK_STRUCT; + +// scene header +struct SMySceneHeader +{ SMyColor BackgrColor; // background color + SMyColor AmbientColor; // ambient color + s32 MaterialCount; // material count + s32 MeshCount; // mesh count +} PACK_STRUCT; + +// mesh header +struct SMyMeshHeader +{ c8 Name[256]; // material name + u32 MatIndex; // index of the mesh material + u32 TChannelCnt; // mesh mapping channels count +} PACK_STRUCT; + +// texture data header +struct SMyTexDataHeader +{ c8 Name[256]; // texture name + u32 ComprMode; //compression mode + u32 PixelFormat; + u32 Width; // image width + u32 Height; // image height +} PACK_STRUCT; + +// pixel color 24bit (R8G8B8) +struct SMyPixelColor24 +{ SMyPixelColor24() {;} + SMyPixelColor24(u8 __r, u8 __g, u8 __b) + : r(__r), g(__g), b(__b) {} + u8 r, g, b; +} PACK_STRUCT; + +// pixel color 16bit (A1R5G5B5) +struct SMyPixelColor16 +{ SMyPixelColor16() {;} + SMyPixelColor16(s16 _argb): argb(_argb) {;} + SMyPixelColor16(u8 r, u8 g, u8 b) + { argb = ((r&0x1F)<<10) | ((g&0x1F)<<5) | (b&0x1F); + } + s16 argb; +} PACK_STRUCT; + +// RLE Header +struct SMyRLEHeader +{ SMyRLEHeader() {} + u32 nEncodedBytes; + u32 nDecodedBytes; +} PACK_STRUCT; + +// Default alignment +#include "irrunpack.h" + +} // end namespace +} // end namespace + +//----------------------------------------------------------------------------- +namespace irr +{ +namespace core +{ + +//-----------------RLE stuff----------------------------------------- + +int rle_encode ( + unsigned char *in_buf, int in_buf_size, + unsigned char *out_buf, int out_buf_size + ); +unsigned long process_comp( + unsigned char *buf, int buf_size, + unsigned char *out_buf, int out_buf_size + ); +void process_uncomp( + unsigned char, unsigned char *out_buf, int out_buf_size + ); +void flush_outbuf( + unsigned char *out_buf, int out_buf_size + ); +unsigned long get_byte ( + unsigned char *ch, + unsigned char *in_buf, int in_buf_size, + unsigned char *out_buf, int out_buf_size + ); +void put_byte( + unsigned char ch, unsigned char *out_buf, int out_buf_size + ); +//----------------------------------------------------------- +const unsigned long LIMIT = 1; // was #define LIMIT 1 +const unsigned long NON_MATCH = 2; // was: #define NON_MATCH 2 +const unsigned long EOD_FOUND = 3; // was: #define EOD_FOUND 3 +const unsigned long EOD = 0x00454f44; // was: #define EOD 'EOD' +//----------------------------------------------------------- +// number of decoded bytes +static int nDecodedBytes=0; +// number of coded bytes +static int nCodedBytes=0; +// number of read bytes +static int nReadedBytes=0; +// table used to look for sequences of repeating bytes +static unsigned char tmpbuf[4]; // we use subscripts 1 - 3 +static int tmpbuf_cnt; +// output buffer for non-compressed output data +static unsigned char outbuf[128]; +static int outbuf_cnt; + + +//----------------------------------------------------------- +int rle_encode ( + unsigned char *in_buf, int in_buf_size, + unsigned char *out_buf, int out_buf_size + ) +{ + unsigned long ret_code; + + unsigned char ch=0; + + nCodedBytes=0; + nReadedBytes=0; + + tmpbuf_cnt = 0; // no. of char's in tmpbuf + outbuf_cnt = 0; // no. of char's in outbuf + while (1) + { + if (get_byte(&ch, in_buf, in_buf_size, + out_buf, out_buf_size) == (int)EOD) // read next byte into ch + break; + + tmpbuf[++tmpbuf_cnt] = (unsigned char) ch; + if (tmpbuf_cnt == 3) + { + // see if all 3 match each other + if ((tmpbuf[1] == tmpbuf[2]) && (tmpbuf[2] == tmpbuf[3])) + { + // they do - add compression + // this will process all bytes in input file until + // a non-match occurs, or 128 bytes are processed, + // or we find eod */ + ret_code = process_comp(in_buf, in_buf_size, out_buf, out_buf_size); + if (ret_code == (int)EOD_FOUND) + break; // stop compressing + if (ret_code == (int)NON_MATCH) + tmpbuf_cnt=1; /* save the char that didn't match */ + else + // we just compressed the max. of 128 bytes + tmpbuf_cnt=0; /* start over for next chunk */ + } + else + { + // we know the first byte doesn't match 2 or more + // others, so just send it out as uncompressed. */ + process_uncomp(tmpbuf[1], out_buf, out_buf_size); + + // see if the last 2 bytes in the buffer match + if (tmpbuf[2] == tmpbuf[3]) + { + // move byte 3 to position 1 and pretend we just + // have 2 bytes -- note that the first byte was + // already sent to output */ + tmpbuf[1]=tmpbuf[3]; + tmpbuf_cnt=2; + } + else + { + // send byte 2 and keep byte 3 - it may match the + // next byte. Move byte 3 to position 1 and set + // count to 1. Note that the first byte was + // already sent to output + process_uncomp(tmpbuf[2], out_buf, out_buf_size); + tmpbuf[1]=tmpbuf[3]; + tmpbuf_cnt=1; + } + } + } + } // end while + flush_outbuf(out_buf, out_buf_size); + + return nCodedBytes; +} + + +//------------------------------------------------------------------ +// This flushes any non-compressed data not yet sent, then it processes +// repeating bytes until > 128, or EOD, or non-match. +// return values: LIMIT, EOD_FOUND, NON_MATCH +// Prior to ANY return, it writes out the 2 byte compressed code. +// If a NON_MATCH was found, this returns with the non-matching char +// residing in tmpbuf[0]. +// Inputs: tmpbuf[0], input file +// Outputs: tmpbuf[0] (sometimes), output file, and return code +//------------------------------------------------------------------ +unsigned long process_comp( + unsigned char *buf, int buf_size, + unsigned char *out_buf, int out_buf_size) +{ + // we start out with 3 repeating bytes + int len = 3; + + unsigned char ch = 0; + + // we're starting a repeating chunk - end the non-repeaters + flush_outbuf(out_buf, out_buf_size); + + while (get_byte(&ch, buf, buf_size, out_buf, out_buf_size) != (int)EOD) + { + if (ch != tmpbuf[1]) + { + // send no. of repeated bytes to be encoded + put_byte((unsigned char)((--len) | 0x80), out_buf, out_buf_size); + // send the byte's value being repeated + put_byte((unsigned char)tmpbuf[1], out_buf, out_buf_size); + /* save the non-matching character just read */ + tmpbuf[1]=(unsigned char) ch; + return NON_MATCH; + } + /* we know the new byte is part of the repeating seq */ + len++; + if (len == 128) + { + // send no. of repeated bytes to be encoded + put_byte((unsigned char)((--len) | 0x80), out_buf, out_buf_size); + // send the byte's value being repeated + put_byte((unsigned char)tmpbuf[1], out_buf, out_buf_size); + return LIMIT; + } + } // end while + + // if flow comes here, we just read an EOD + // send no. of repeated bytes to be encoded + put_byte((unsigned char)((--len) | 0x80), out_buf, out_buf_size); + // send the byte's value being repeated + put_byte((unsigned char)tmpbuf[1], out_buf, out_buf_size); + return EOD_FOUND; +} + + +//---------------------------------------------------------------- +// This adds 1 non-repeating byte to outbuf. If outbuf becomes full +// with 128 bytes, it flushes outbuf. +// There are no return codes and no bytes are read from the input. +//---------------------------------------------------------------- +void process_uncomp( + unsigned char char1, unsigned char *out_buf, int out_buf_size + ) +{ + outbuf[outbuf_cnt++] = char1; + if (outbuf_cnt == 128) + flush_outbuf(out_buf, out_buf_size); +} +//----------------------------------------------------------- +// This flushes any non-compressed data not yet sent. +// On exit, outbuf_cnt will equal zero. +//----------------------------------------------------------- +void flush_outbuf(unsigned char *out_buf, int out_buf_size) +{ + if (!outbuf_cnt) + return; // nothing to do */ + + // send no. of unencoded bytes to be sent + put_byte((unsigned char)(outbuf_cnt - 1), out_buf, out_buf_size); + + for (int pos=0; outbuf_cnt; outbuf_cnt--) + put_byte((unsigned char)outbuf[pos++], out_buf, out_buf_size); +} +//--------------------------------------------------- +void put_byte(unsigned char b, unsigned char *out_buf, int out_buf_size) +{ + if (nCodedBytes<=(out_buf_size-1)) + { + out_buf[nCodedBytes++] = b; + out_buf[nCodedBytes] = 0; + } +} +//--------------------------------------------------- +// This reads the next byte into ch. It returns EOD +// at end-of-data +//--------------------------------------------------- +unsigned long get_byte( + unsigned char *ch, + unsigned char *in_buf, int in_buf_size, + unsigned char *out_buf, int out_buf_size + ) +{ + if (nReadedBytes>=in_buf_size) + { + // there are either 0, 1, or 2 char's to write before we quit + if (tmpbuf_cnt == 1) + process_uncomp(tmpbuf[1], out_buf, out_buf_size); + else + { + if (tmpbuf_cnt == 2) + { + process_uncomp(tmpbuf[1], out_buf, out_buf_size); + process_uncomp(tmpbuf[2], out_buf, out_buf_size); + } + } + nReadedBytes =0; + + return EOD; + } + + (*ch) = (unsigned char)in_buf[nReadedBytes++]; + + return 0; +} +//----------------------------------------------------------- +int rle_decode ( + unsigned char *in_buf, int in_buf_size, + unsigned char *out_buf, int out_buf_size + ) +{ + nDecodedBytes=0; + nReadedBytes=0; + + int ch, i; + while (1) + { + + if (nReadedBytes>=in_buf_size) + break; + else + ch=in_buf[nReadedBytes]; + nReadedBytes++; + + if (ch > 127) + { + i = ch - 127; // i is the number of repetitions + // get the byte to be repeated + if (nReadedBytes>=in_buf_size) + break; + else + ch=in_buf[nReadedBytes]; + nReadedBytes++; + + // uncompress a chunk + for (; i; --i) + { + if (nDecodedBytes=in_buf_size) + break; + else + ch=in_buf[nReadedBytes]; + nReadedBytes++; + + if (nDecodedBytesgrab(); + + TextureLoader = new CMeshTextureLoader( FileSystem, SceneManager->getVideoDriver() ); +} + + +CMY3DMeshFileLoader::~CMY3DMeshFileLoader() +{ + if (FileSystem) + FileSystem->drop(); +} + + +bool CMY3DMeshFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "my3d" ); +} + + +IAnimatedMesh* CMY3DMeshFileLoader::createMesh(io::IReadFile* file) +{ + if ( getMeshTextureLoader() ) + { + getMeshTextureLoader()->setMeshFile(file); + if ( SceneManager->getParameters()->existsAttribute(MY3D_TEXTURE_PATH) ) + getMeshTextureLoader()->setTexturePath(SceneManager->getParameters()->getAttributeAsString(MY3D_TEXTURE_PATH)); + } + + MaterialEntry.clear(); + MeshBufferEntry.clear(); + ChildNodes.clear(); + + // read file into memory + SMyFileHeader fileHeader; + file->read(&fileHeader, sizeof(SMyFileHeader)); +#ifdef __BIG_ENDIAN__ + fileHeader.MyId = os::Byteswap::byteswap(fileHeader.MyId); + fileHeader.Ver = os::Byteswap::byteswap(fileHeader.Ver); +#endif + + if (fileHeader.MyId!=MY3D_ID || fileHeader.Ver!=MY3D_VER) + { + os::Printer::log("Bad MY3D file header, loading failed!", ELL_ERROR); + return 0; + } + + u16 id; + + file->read(&id, sizeof(id)); +#ifdef __BIG_ENDIAN__ + id = os::Byteswap::byteswap(id); +#endif + + if (id!=MY3D_SCENE_HEADER_ID) + { + os::Printer::log("Cannot find MY3D_SCENE_HEADER_ID, loading failed!", ELL_ERROR); + return 0; + } + + SMySceneHeader sceneHeader; + file->read(&sceneHeader, sizeof(SMySceneHeader)); +#ifdef __BIG_ENDIAN__ + sceneHeader.MaterialCount = os::Byteswap::byteswap(sceneHeader.MaterialCount); + sceneHeader.MeshCount = os::Byteswap::byteswap(sceneHeader.MeshCount); +#endif + + file->read(&id, sizeof(id)); +#ifdef __BIG_ENDIAN__ + id = os::Byteswap::byteswap(id); +#endif + + if (id!=MY3D_MAT_LIST_ID) + { + os::Printer::log("Can not find MY3D_MAT_LIST_ID, loading failed!", ELL_ERROR); + return 0; + } + + file->read(&id, sizeof(id)); +#ifdef __BIG_ENDIAN__ + id = os::Byteswap::byteswap(id); +#endif + + c8 namebuf[256]; + for (s32 m=0; mread(&(me.Header), sizeof(SMyMaterialHeader)); + + // read next identificator + file->read(&id, sizeof(id)); +#ifdef __BIG_ENDIAN__ + id = os::Byteswap::byteswap(id); +#endif + + bool gotLightMap=false, gotMainMap=false; + + for (u32 t=0; tread(namebuf, 256); + else + { + me.Texture2 = readEmbeddedLightmap(file, namebuf); + if (!me.Texture2) + return 0; + gotLightMap = true; + } + + const core::stringc name(namebuf); + const s32 pos = name.findLast('.'); + const core::stringc LightingMapStr = "LightingMap"; + const s32 ls = LightingMapStr.size(); + const bool isSubString = (LightingMapStr == name.subString(core::max_(0, (pos - ls)), ls)); + if ((isSubString || (name[pos-1]=='m' && + name[pos-2]=='l' && name[pos-3]=='_')) && + !gotLightMap) + { + const bool oldMipMapState = SceneManager->getVideoDriver()->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); + SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); + + me.Texture2FileName = "Lightmaps/"; + me.Texture2FileName.append(name); + me.Texture2 = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture(me.Texture2FileName) : NULL; + + me.MaterialType = video::EMT_LIGHTMAP_M2; + gotLightMap = true; + + SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, oldMipMapState); + } + else + if (!gotLightMap && gotMainMap) + { + if ( getMeshTextureLoader() ) + { + me.Texture2 = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture(name) : NULL; + if ( me.Texture2 ) + me.Texture2FileName = me.Texture2->getName(); + } + else + me.Texture2FileName = name; + + me.MaterialType = video::EMT_REFLECTION_2_LAYER; + } + else + if (!gotMainMap && !gotLightMap) + { + if ( getMeshTextureLoader() ) + { + me.Texture1 = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture(name) : NULL; + if ( me.Texture1 ) + me.Texture1FileName = me.Texture1->getName(); + } + else + me.Texture1FileName = name; + + gotMainMap = true; + me.MaterialType = video::EMT_SOLID; + } + else + if (gotLightMap) + { + me.MaterialType = video::EMT_LIGHTMAP_M2; + } + + file->read(&id, sizeof(id)); +#ifdef __BIG_ENDIAN__ + id = os::Byteswap::byteswap(id); +#endif + } + + // override material types based on their names + if (!strncmp(me.Header.Name, "AlphaChannel-", 13)) + me.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + else + if (!strncmp(me.Header.Name, "SphereMap-", 10)) + me.MaterialType = video::EMT_SPHERE_MAP; + } + + // loading meshes + + if (id!=MY3D_MESH_LIST_ID) + { + os::Printer::log("Can not find MY3D_MESH_LIST_ID, loading failed!", ELL_ERROR); + return 0; + } + + file->read(&id, sizeof(id)); +#ifdef __BIG_ENDIAN__ + id = os::Byteswap::byteswap(id); +#endif + + for (s32 mesh_id=0; mesh_idread(&meshHeader, sizeof(SMyMeshHeader)); + + core::array Vertex; + core::array Face; + core::array TVertex1, TVertex2; + core::array TFace1, TFace2; + + s32 vertsNum=0; + s32 facesNum=0; + + // vertices + file->read(&id, sizeof(id)); +#ifdef __BIG_ENDIAN__ + id = os::Byteswap::byteswap(id); +#endif + if (id!=MY3D_VERTS_ID) + { + os::Printer::log("Can not find MY3D_VERTS_ID, loading failed!", ELL_ERROR); + return 0; + } + + file->read(&vertsNum, sizeof(vertsNum)); + Vertex.set_used(vertsNum); + file->read(Vertex.pointer(), sizeof(SMyVertex)*vertsNum); + + // faces + file->read(&id, sizeof(id)); +#ifdef __BIG_ENDIAN__ + id = os::Byteswap::byteswap(id); +#endif + if (id!=MY3D_FACES_ID) + { + os::Printer::log("Can not find MY3D_FACES_ID, loading failed!", ELL_ERROR); + return 0; + } + + file->read(&facesNum, sizeof(facesNum)); + Face.set_used(facesNum); + file->read(Face.pointer(), sizeof(SMyFace)*facesNum); + + // reading texture channels + for (s32 tex=0; tex<(s32)meshHeader.TChannelCnt; tex++) + { + // Max 2 texture channels allowed (but in format .my3d can be more) + s32 tVertsNum=0, tFacesNum=0; + + // reading texture coords + file->read(&id, sizeof(id)); +#ifdef __BIG_ENDIAN__ + id = os::Byteswap::byteswap(id); +#endif + + if (id!=MY3D_TVERTS_ID) + { + core::stringc msg="Can not find MY3D_TVERTS_ID ("; + msg.append(core::stringc(tex)); + msg.append("texture channel), loading failed!"); + os::Printer::log(msg.c_str(), ELL_ERROR); + return 0; + } + + file->read(&tVertsNum, sizeof(tVertsNum)); + + if (tex==0) + { + // 1st texture channel + TVertex1.set_used(tVertsNum); + file->read(TVertex1.pointer(), sizeof(SMyTVertex)*tVertsNum); + } + else + if (tex==1) + { + // 2nd texture channel + TVertex2.set_used(tVertsNum); + file->read(TVertex2.pointer(), sizeof(SMyTVertex)*tVertsNum); + } + else + { + // skip other texture channels + file->seek(file->getPos()+sizeof(SMyTVertex)*tVertsNum); + } + + // reading texture faces + file->read(&id, sizeof(id)); +#ifdef __BIG_ENDIAN__ + id = os::Byteswap::byteswap(id); +#endif + + if (id!=MY3D_TFACES_ID) + { + core::stringc msg="Can not find MY3D_TFACES_ID ("; + msg.append(core::stringc(tex)); + msg.append("texture channel), loading failed!"); + os::Printer::log(msg.c_str(), ELL_ERROR); + return 0; + } + + file->read(&tFacesNum, sizeof(tFacesNum)); + + if (tex==0) + { + // 1st texture channel + TFace1.set_used(tFacesNum); + file->read(TFace1.pointer(), sizeof(SMyFace)*tFacesNum); + } + else if (tex==1) + { + // 2nd texture channel + TFace2.set_used(tFacesNum); + file->read(TFace2.pointer(), sizeof(SMyFace)*tFacesNum); + } + else + { + // skip other texture channels + file->seek(file->getPos()+sizeof(SMyFace)*tFacesNum); + } + } + + // trying to find material + + SMyMaterialEntry* matEnt = getMaterialEntryByIndex(meshHeader.MatIndex); + + // creating geometry for the mesh + + // trying to find mesh buffer for this material + SMeshBufferLightMap* buffer = getMeshBufferByMaterialIndex(meshHeader.MatIndex); + + if (!buffer || + (buffer->Vertices.size()+vertsNum) > SceneManager->getVideoDriver()->getMaximalPrimitiveCount()) + { + // creating new mesh buffer for this material + buffer = new scene::SMeshBufferLightMap(); + + buffer->Material.MaterialType = video::EMT_LIGHTMAP_M2; // EMT_LIGHTMAP_M4 also possible + buffer->Material.Wireframe = false; + buffer->Material.Lighting = false; + + if (matEnt) + { + buffer->Material.MaterialType = matEnt->MaterialType; + + if (buffer->Material.MaterialType == video::EMT_REFLECTION_2_LAYER) + { + buffer->Material.Lighting = true; + buffer->Material.setTexture(1, matEnt->Texture1); + buffer->Material.setTexture(0, matEnt->Texture2); + } + else + { + buffer->Material.setTexture(0, matEnt->Texture1); + buffer->Material.setTexture(1, matEnt->Texture2); + } + + if (buffer->Material.MaterialType == video::EMT_TRANSPARENT_ALPHA_CHANNEL) + { + buffer->Material.BackfaceCulling = true; + buffer->Material.Lighting = true; + } + else + if (buffer->Material.MaterialType == video::EMT_SPHERE_MAP) + { + buffer->Material.Lighting = true; + } + + buffer->Material.AmbientColor = video::SColor( + matEnt->Header.AmbientColor.A, matEnt->Header.AmbientColor.R, + matEnt->Header.AmbientColor.G, matEnt->Header.AmbientColor.B + ); + buffer->Material.DiffuseColor = video::SColor( + matEnt->Header.DiffuseColor.A, matEnt->Header.DiffuseColor.R, + matEnt->Header.DiffuseColor.G, matEnt->Header.DiffuseColor.B + ); + buffer->Material.EmissiveColor = video::SColor( + matEnt->Header.EmissiveColor.A, matEnt->Header.EmissiveColor.R, + matEnt->Header.EmissiveColor.G, matEnt->Header.EmissiveColor.B + ); + buffer->Material.SpecularColor = video::SColor( + matEnt->Header.SpecularColor.A, matEnt->Header.SpecularColor.R, + matEnt->Header.SpecularColor.G, matEnt->Header.SpecularColor.B + ); + } + else + { + buffer->Material.setTexture(0, 0); + buffer->Material.setTexture(1, 0); + + buffer->Material.AmbientColor = video::SColor(255, 255, 255, 255); + buffer->Material.DiffuseColor = video::SColor(255, 255, 255, 255); + buffer->Material.EmissiveColor = video::SColor(0, 0, 0, 0); + buffer->Material.SpecularColor = video::SColor(0, 0, 0, 0); + } + + if (matEnt && matEnt->Header.Transparency!=0) + { + if (buffer->Material.MaterialType == video::EMT_REFLECTION_2_LAYER ) + { + buffer->Material.MaterialType = video::EMT_TRANSPARENT_REFLECTION_2_LAYER; + buffer->Material.Lighting = true; + buffer->Material.BackfaceCulling = true; + } + else + { + buffer->Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + buffer->Material.Lighting = false; + buffer->Material.BackfaceCulling = false; + } + } + else if ( + !buffer->Material.getTexture(1) && + buffer->Material.MaterialType != video::EMT_TRANSPARENT_ALPHA_CHANNEL && + buffer->Material.MaterialType != video::EMT_SPHERE_MAP) + { + buffer->Material.MaterialType = video::EMT_SOLID; + buffer->Material.Lighting = true; + } + + MeshBufferEntry.push_back( + SMyMeshBufferEntry(meshHeader.MatIndex, buffer)); + } + + video::S3DVertex2TCoords VertexA, VertexB, VertexC; + + // vertices (A, B, C) color + video::SColor vert_color; + if (matEnt && + (buffer->Material.MaterialType == video::EMT_TRANSPARENT_VERTEX_ALPHA || + buffer->Material.MaterialType == video::EMT_TRANSPARENT_REFLECTION_2_LAYER)) + { + video::SColor color( + matEnt->Header.DiffuseColor.A, matEnt->Header.DiffuseColor.R, + matEnt->Header.DiffuseColor.G, matEnt->Header.DiffuseColor.B); + + vert_color = color.getInterpolated(video::SColor(0,0,0,0), + 1-matEnt->Header.Transparency); + } + else + { + vert_color = buffer->Material.DiffuseColor; + } + + VertexA.Color = VertexB.Color = VertexC.Color = vert_color; + + if (buffer->Material.MaterialType == video::EMT_TRANSPARENT_ALPHA_CHANNEL) + { + buffer->Indices.reallocate(buffer->Indices.size()+6*facesNum); + buffer->Vertices.reallocate(buffer->Vertices.size()+6*facesNum); + } + else + { + buffer->Indices.reallocate(buffer->Indices.size()+3*facesNum); + buffer->Vertices.reallocate(buffer->Vertices.size()+3*facesNum); + } + for (int f=0; f0) + { + VertexA.TCoords.X = TVertex1[TFace1[f].C].TCoord.X; + VertexA.TCoords.Y = TVertex1[TFace1[f].C].TCoord.Y; + } + + if (meshHeader.TChannelCnt>1) + { + VertexA.TCoords2.X = TVertex2[TFace2[f].C].TCoord.X; + VertexA.TCoords2.Y = TVertex2[TFace2[f].C].TCoord.Y; + } + + // vertex B + + VertexB.Pos.X = Vertex[Face[f].B].Coord.X; + VertexB.Pos.Y = Vertex[Face[f].B].Coord.Y; + VertexB.Pos.Z = Vertex[Face[f].B].Coord.Z; + + VertexB.Normal.X = Vertex[Face[f].B].Normal.X; + VertexB.Normal.Y = Vertex[Face[f].B].Normal.Y; + VertexB.Normal.Z = Vertex[Face[f].B].Normal.Z; + + if (meshHeader.TChannelCnt>0) + { + VertexB.TCoords.X = TVertex1[TFace1[f].B].TCoord.X; + VertexB.TCoords.Y = TVertex1[TFace1[f].B].TCoord.Y; + } + + if (meshHeader.TChannelCnt>1) + { + VertexB.TCoords2.X = TVertex2[TFace2[f].B].TCoord.X; + VertexB.TCoords2.Y = TVertex2[TFace2[f].B].TCoord.Y; + } + + // vertex C + + VertexC.Pos.X = Vertex[Face[f].A].Coord.X; + VertexC.Pos.Y = Vertex[Face[f].A].Coord.Y; + VertexC.Pos.Z = Vertex[Face[f].A].Coord.Z; + + VertexC.Normal.X = Vertex[Face[f].A].Normal.X; + VertexC.Normal.Y = Vertex[Face[f].A].Normal.Y; + VertexC.Normal.Z = Vertex[Face[f].A].Normal.Z; + + if (meshHeader.TChannelCnt>0) + { + VertexC.TCoords.X = TVertex1[TFace1[f].A].TCoord.X; + VertexC.TCoords.Y = TVertex1[TFace1[f].A].TCoord.Y; + } + if (meshHeader.TChannelCnt>1) + { + VertexC.TCoords2.X = TVertex2[TFace2[f].A].TCoord.X; + VertexC.TCoords2.Y = TVertex2[TFace2[f].A].TCoord.Y; + } + + // store 3d data in mesh buffer + + buffer->Indices.push_back(buffer->Vertices.size()); + buffer->Vertices.push_back(VertexA); + + buffer->Indices.push_back(buffer->Vertices.size()); + buffer->Vertices.push_back(VertexB); + + buffer->Indices.push_back(buffer->Vertices.size()); + buffer->Vertices.push_back(VertexC); + + //***************************************************************** + // !!!!!! W A R N I N G !!!!!!! + //***************************************************************** + // For materials with alpha channel we duplicate all faces. + // This has be done for proper lighting calculation of the back faces. + // So you must remember this while you creating your models !!!!! + //***************************************************************** + // !!!!!! W A R N I N G !!!!!!! + //***************************************************************** + + if (buffer->Material.MaterialType == video::EMT_TRANSPARENT_ALPHA_CHANNEL) + { + VertexA.Normal = core::vector3df(-VertexA.Normal.X, -VertexA.Normal.Y, -VertexA.Normal.Z); + VertexB.Normal = core::vector3df(-VertexB.Normal.X, -VertexB.Normal.Y, -VertexB.Normal.Z); + VertexC.Normal = core::vector3df(-VertexC.Normal.X, -VertexC.Normal.Y, -VertexC.Normal.Z); + + buffer->Indices.push_back(buffer->Vertices.size()); + buffer->Vertices.push_back(VertexC); + + buffer->Indices.push_back(buffer->Vertices.size()); + buffer->Vertices.push_back(VertexB); + + buffer->Indices.push_back(buffer->Vertices.size()); + buffer->Vertices.push_back(VertexA); + } + } + file->read(&id, sizeof(id)); +#ifdef __BIG_ENDIAN__ + id = os::Byteswap::byteswap(id); +#endif + } + + // creating mesh + SMesh* mesh = new SMesh(); + + for (u32 num=0; numaddMeshBuffer(buffer); + + buffer->recalculateBoundingBox(); + buffer->drop(); + } + + mesh->recalculateBoundingBox(); + + if (id != MY3D_FILE_END_ID) + os::Printer::log("Loading finished, but can not find MY3D_FILE_END_ID token.", ELL_WARNING); + + SAnimatedMesh* am = new SAnimatedMesh(); + + am->addMesh(mesh); + mesh->drop(); + am->recalculateBoundingBox(); + + return am; +} + + +video::ITexture* CMY3DMeshFileLoader::readEmbeddedLightmap(io::IReadFile* file, char* namebuf) +{ + static int LightMapIndex=0; + u16 id; + file->read(&id, sizeof(id)); +#ifdef __BIG_ENDIAN__ + id = os::Byteswap::byteswap(id); +#endif + if (id!=MY3D_TEXDATA_HEADER_ID) + { + os::Printer::log("Can not find MY3D_TEXDATA_HEADER_ID, loading failed!", ELL_ERROR); + return 0; + } + + SMyTexDataHeader texDataHeader; + + file->read(&texDataHeader, sizeof(SMyTexDataHeader)); + + strcpy(texDataHeader.Name, namebuf); + + char LightMapName[255]; + sprintf(LightMapName,"My3D.Lightmap.%d",++LightMapIndex); + + core::stringc pixFormatStr; + if (texDataHeader.PixelFormat == MY3D_PIXEL_FORMAT_24) + pixFormatStr = "24bit,"; + else + if (texDataHeader.PixelFormat == MY3D_PIXEL_FORMAT_16) + pixFormatStr = "16bit,"; + else + { + core::stringc msg="Unknown format of image data ("; + msg.append(LightMapName); + msg.append("), loading failed!"); + os::Printer::log(msg.c_str(), ELL_ERROR); + return 0; + } + + if (texDataHeader.ComprMode != MY3D_TEXDATA_COMPR_NONE_ID && + texDataHeader.ComprMode != MY3D_TEXDATA_COMPR_RLE_ID && + texDataHeader.ComprMode != MY3D_TEXDATA_COMPR_SIMPLE_ID ) + { + os::Printer::log("Unknown method of compression image data, loading failed!", ELL_ERROR); + return 0; + } + + const u32 num_pixels = texDataHeader.Width*texDataHeader.Height; + + void* data = 0; + + if (texDataHeader.ComprMode==MY3D_TEXDATA_COMPR_NONE_ID) + { + // none compressed image data + if (texDataHeader.PixelFormat == MY3D_PIXEL_FORMAT_24) + { + data = (void*) new SMyPixelColor24[num_pixels]; + file->read(data, sizeof(SMyPixelColor24)*num_pixels); + } + else + { + data = (void*) new SMyPixelColor16[num_pixels]; + file->read(data, sizeof(SMyPixelColor16)*num_pixels); + } + } + else + if (texDataHeader.ComprMode==MY3D_TEXDATA_COMPR_RLE_ID) + { + // read RLE header identificator + file->read(&id, sizeof(id)); +#ifdef __BIG_ENDIAN__ + id = os::Byteswap::byteswap(id); +#endif + if (id!=MY3D_TEXDATA_RLE_HEADER_ID) + { + os::Printer::log("Can not find MY3D_TEXDATA_RLE_HEADER_ID, loading failed!", ELL_ERROR); + return 0; + } + + // read RLE header + SMyRLEHeader rleHeader; + file->read(&rleHeader, sizeof(SMyRLEHeader)); + + //allocate memory for input and output buffers + void *input_buffer = (void*) new unsigned char[rleHeader.nEncodedBytes]; + void *output_buffer = (void*) new unsigned char[rleHeader.nDecodedBytes]; + + // read encoded data + file->read(input_buffer, rleHeader.nEncodedBytes); + + // decode data + data = 0;//(void*) new unsigned char[rleHeader.nDecodedBytes]; + s32 decodedBytes = core::rle_decode( + (unsigned char*)input_buffer, rleHeader.nEncodedBytes, + (unsigned char*)output_buffer, rleHeader.nDecodedBytes); + + if (decodedBytes!=(s32)rleHeader.nDecodedBytes) + { + os::Printer::log("Error extracting data from RLE compression, loading failed!", ELL_ERROR); + return 0; + } + + // free input buffer + delete [] (unsigned char*)input_buffer; + + // here decoded data + data = output_buffer; + } + else if (texDataHeader.ComprMode==MY3D_TEXDATA_COMPR_SIMPLE_ID) + { + // simple compressed image data + if (texDataHeader.PixelFormat == MY3D_PIXEL_FORMAT_24) + data = (void*) new SMyPixelColor24[num_pixels]; + else + data = (void*) new SMyPixelColor16[num_pixels]; + + u32 nReadedPixels=0, nToRead=0; + while (true) + { + file->read(&nToRead, sizeof(nToRead)); + + if ((nReadedPixels+nToRead) > num_pixels) + break; + + if (texDataHeader.PixelFormat == MY3D_PIXEL_FORMAT_24) + { + SMyPixelColor24 col24; + file->read(&col24, sizeof(SMyPixelColor24)); + for (u32 p=0; pread(&col16, sizeof(SMyPixelColor16)); + for (u32 p=0; p= num_pixels) + break; + } + + if (nReadedPixels != num_pixels) + { + os::Printer::log("Image data seems to be corrupted, loading failed!", ELL_ERROR); + return 0; + } + } + + //! Creates a software image from a byte array. + video::IImage* light_img = 0; + + if (texDataHeader.PixelFormat == MY3D_PIXEL_FORMAT_24) + { + // 24 bit lightmap format + light_img = SceneManager->getVideoDriver()->createImageFromData( + video::ECF_R8G8B8, + core::dimension2d(texDataHeader.Width, texDataHeader.Height), + data, true); + } + else + { + // 16 bit lightmap format + light_img = SceneManager->getVideoDriver()->createImageFromData( + video::ECF_A1R5G5B5, + core::dimension2d(texDataHeader.Width, texDataHeader.Height), + data, true); + } + + const bool oldMipMapState = SceneManager->getVideoDriver()->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); + SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); + video::ITexture* lmtex = SceneManager->getVideoDriver()->addTexture(LightMapName, light_img); + SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, oldMipMapState); + + light_img->drop(); + return lmtex; +} + + +CMY3DMeshFileLoader::SMyMaterialEntry* CMY3DMeshFileLoader::getMaterialEntryByIndex(u32 matInd) +{ + for (u32 m=0; m& CMY3DMeshFileLoader::getChildNodes() const +{ + return ChildNodes; +} + + +} // end namespace scnene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_MY3D_LOADER_ + diff --git a/source/Irrlicht/CMY3DMeshFileLoader.h b/source/Irrlicht/CMY3DMeshFileLoader.h new file mode 100644 index 00000000..0c29802e --- /dev/null +++ b/source/Irrlicht/CMY3DMeshFileLoader.h @@ -0,0 +1,129 @@ +// Copyright (C) 2002-2012 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 originally written by ZDimitor. +// I (Nikolaus Gebhardt) did some few changes to this: +// - replaced logging calls to their os:: counterparts +// - removed some logging calls +// - removed setTexture path and replaced it with the directory of the mesh +// - added EAMT_MY3D file type +// - fixed a memory leak when decompressing RLE data. +// - cleaned multi character constant problems with gcc +// - removed octree child scene node generation because irrlicht is now able to draw +// scene nodes with transparent and sold materials in them at the same time. (see changes.txt) +// Thanks a lot to ZDimitor for his work on this and that he gave me +// his permission to add it into Irrlicht. + +//-------------------------------------------------------------------------------- +// This tool created by ZDimitor everyone can use it as wants +//-------------------------------------------------------------------------------- + +#ifndef __CMY3D_MESH_FILE_LOADER_H_INCLUDED__ +#define __CMY3D_MESH_FILE_LOADER_H_INCLUDED__ + + +#ifdef _MSC_VER +#pragma once +#endif + + +#include "IMeshLoader.h" +#include "SMesh.h" +#include "SMeshBufferLightMap.h" +#include "IFileSystem.h" +#include "IVideoDriver.h" +#include "irrString.h" +#include "ISceneManager.h" + +namespace irr +{ +namespace scene +{ + +// byte-align structures +#include "irrpack.h" + +struct SMyColor +{ SMyColor () {;} + SMyColor (s32 __R, s32 __G, s32 __B, s32 __A) + : R(__R), G(__G), B(__B), A(__A) {} + s32 R, G, B, A; +} PACK_STRUCT; + +// material header +struct SMyMaterialHeader +{ c8 Name[256]; // material name + u32 Index; + SMyColor AmbientColor; + SMyColor DiffuseColor; + SMyColor EmissiveColor; + SMyColor SpecularColor; + f32 Shininess; + f32 Transparency; + u32 TextureCount; // texture count +} PACK_STRUCT; + +// Default alignment +#include "irrunpack.h" + +class CMY3DMeshFileLoader : public IMeshLoader +{ +public: + CMY3DMeshFileLoader(ISceneManager *scmgr, io::IFileSystem* fs); + virtual ~CMY3DMeshFileLoader(); + + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_; + + //! getting access to the nodes (with transparent material), creating + //! while loading .my3d file + const core::array& getChildNodes() const; + +private: + + video::ITexture* readEmbeddedLightmap(io::IReadFile* file, char* namebuf); + + scene::ISceneManager* SceneManager; + io::IFileSystem* FileSystem; + + struct SMyMaterialEntry + { + SMyMaterialEntry () + : Texture1FileName("null"), Texture2FileName("null"), + Texture1(0), Texture2(0), MaterialType(video::EMT_SOLID) {} + + SMyMaterialHeader Header; + core::stringc Texture1FileName; + core::stringc Texture2FileName; + video::ITexture *Texture1; + video::ITexture *Texture2; + video::E_MATERIAL_TYPE MaterialType; + }; + + struct SMyMeshBufferEntry + { + SMyMeshBufferEntry() : MaterialIndex(-1), MeshBuffer(0) {} + SMyMeshBufferEntry(s32 mi, SMeshBufferLightMap* mb) + : MaterialIndex(mi), MeshBuffer(mb) {} + + s32 MaterialIndex; + SMeshBufferLightMap* MeshBuffer; + }; + + SMyMaterialEntry* getMaterialEntryByIndex (u32 matInd); + SMeshBufferLightMap* getMeshBufferByMaterialIndex(u32 matInd); + + core::array MaterialEntry; + core::array MeshBufferEntry; + + core::array ChildNodes; +}; + + +} // end namespace scene +} // end namespace irr + + +#endif // __CMY3D_MESH_FILE_LOADER_H_INCLUDED__ diff --git a/source/Irrlicht/CMemoryFile.cpp b/source/Irrlicht/CMemoryFile.cpp new file mode 100644 index 00000000..22c57e65 --- /dev/null +++ b/source/Irrlicht/CMemoryFile.cpp @@ -0,0 +1,187 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CMemoryFile.h" +#include "irrString.h" + +namespace irr +{ +namespace io +{ + + +CMemoryReadFile::CMemoryReadFile(const void* memory, long len, const io::path& fileName, bool d) +: Buffer(memory), Len(len), Pos(0), Filename(fileName), deleteMemoryWhenDropped(d) +{ + #ifdef _DEBUG + setDebugName("CMemoryReadFile"); + #endif +} + + +CMemoryReadFile::~CMemoryReadFile() +{ + if (deleteMemoryWhenDropped) + delete [] (c8*)Buffer; +} + + +//! returns how much was read +size_t CMemoryReadFile::read(void* buffer, size_t sizeToRead) +{ + long amount = static_cast(sizeToRead); + if (Pos + amount > Len) + amount -= Pos + amount - Len; + + if (amount <= 0) + return 0; + + c8* p = (c8*)Buffer; + memcpy(buffer, p + Pos, amount); + + Pos += amount; + + return static_cast(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) +{ + if (relativeMovement) + { + if (Pos + finalPos > Len) + return false; + + Pos += finalPos; + } + else + { + if (finalPos > Len) + return false; + + Pos = finalPos; + } + + return true; +} + + +//! returns size of file +long CMemoryReadFile::getSize() const +{ + return Len; +} + + +//! returns where in the file we are. +long CMemoryReadFile::getPos() const +{ + return Pos; +} + + +//! returns name of file +const io::path& CMemoryReadFile::getFileName() const +{ + return Filename; +} + + +CMemoryWriteFile::CMemoryWriteFile(void* memory, long len, const io::path& fileName, bool d) +: Buffer(memory), Len(len), Pos(0), Filename(fileName), deleteMemoryWhenDropped(d) +{ + #ifdef _DEBUG + setDebugName("CMemoryWriteFile"); + #endif +} + + +CMemoryWriteFile::~CMemoryWriteFile() +{ + if (deleteMemoryWhenDropped) + delete [] (c8*)Buffer; +} + + +//! returns how much was written +size_t CMemoryWriteFile::write(const void* buffer, size_t sizeToWrite) +{ + long amount = (long)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 (size_t)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 CMemoryWriteFile::seek(long finalPos, bool relativeMovement) +{ + if (relativeMovement) + { + if (Pos + finalPos > Len) + return false; + + Pos += finalPos; + } + else + { + if (finalPos > Len) + return false; + + Pos = finalPos; + } + + return true; +} + + +//! returns where in the file we are. +long CMemoryWriteFile::getPos() const +{ + return Pos; +} + + +//! returns name of file +const io::path& CMemoryWriteFile::getFileName() const +{ + return Filename; +} + +bool CMemoryWriteFile::flush() +{ + return true; // no buffering, so nothing to do +} + +IReadFile* createMemoryReadFile(const void* memory, long size, const io::path& fileName, bool deleteMemoryWhenDropped) +{ + CMemoryReadFile* file = new CMemoryReadFile(memory, size, fileName, deleteMemoryWhenDropped); + return file; +} + + +IWriteFile* createMemoryWriteFile(void* memory, long size, const io::path& fileName, bool deleteMemoryWhenDropped) +{ + CMemoryWriteFile* file = new CMemoryWriteFile(memory, size, fileName, deleteMemoryWhenDropped); + return file; +} + + +} // end namespace io +} // end namespace irr + diff --git a/source/Irrlicht/CMemoryFile.h b/source/Irrlicht/CMemoryFile.h new file mode 100644 index 00000000..b86c175e --- /dev/null +++ b/source/Irrlicht/CMemoryFile.h @@ -0,0 +1,107 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_MEMORY_READ_FILE_H_INCLUDED__ +#define __C_MEMORY_READ_FILE_H_INCLUDED__ + +#include "IMemoryReadFile.h" +#include "IWriteFile.h" +#include "irrString.h" + +namespace irr +{ + +namespace io +{ + + /*! + Class for reading from memory. + */ + class CMemoryReadFile : public IMemoryReadFile + { + public: + + //! Constructor + CMemoryReadFile(const void* memory, long len, const io::path& fileName, bool deleteMemoryWhenDropped); + + //! Destructor + virtual ~CMemoryReadFile(); + + //! returns how much was read + virtual size_t read(void* buffer, size_t sizeToRead) _IRR_OVERRIDE_; + + //! changes position in file, returns true if successful + virtual bool seek(long finalPos, bool relativeMovement = false) _IRR_OVERRIDE_; + + //! returns size of file + virtual long getSize() const _IRR_OVERRIDE_; + + //! returns where in the file we are. + virtual long getPos() const _IRR_OVERRIDE_; + + //! returns name of file + virtual const io::path& getFileName() const _IRR_OVERRIDE_; + + //! Get the type of the class implementing this interface + virtual EREAD_FILE_TYPE getType() const _IRR_OVERRIDE_ + { + return ERFT_MEMORY_READ_FILE; + } + + //! Get direct access to internal buffer + virtual const void *getBuffer() const _IRR_OVERRIDE_ + { + return Buffer; + } + + private: + + const void *Buffer; + long Len; + long Pos; + io::path Filename; + bool deleteMemoryWhenDropped; + }; + + /*! + Class for writing to memory. + */ + class CMemoryWriteFile : public IWriteFile + { + public: + + //! Constructor + CMemoryWriteFile(void* memory, long len, const io::path& fileName, bool deleteMemoryWhenDropped); + + //! Destructor + virtual ~CMemoryWriteFile(); + + //! returns how much was written + virtual size_t write(const void* buffer, size_t sizeToWrite) _IRR_OVERRIDE_; + + //! changes position in file, returns true if successful + virtual bool seek(long finalPos, bool relativeMovement = false) _IRR_OVERRIDE_; + + //! returns where in the file we are. + virtual long getPos() const _IRR_OVERRIDE_; + + //! returns name of file + virtual const io::path& getFileName() const _IRR_OVERRIDE_; + + virtual bool flush() _IRR_OVERRIDE_; + + private: + + void *Buffer; + long Len; + long Pos; + io::path Filename; + bool deleteMemoryWhenDropped; + }; + +} // end namespace io +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CMeshCache.cpp b/source/Irrlicht/CMeshCache.cpp new file mode 100644 index 00000000..5bcce193 --- /dev/null +++ b/source/Irrlicht/CMeshCache.cpp @@ -0,0 +1,178 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CMeshCache.h" +#include "IAnimatedMesh.h" +#include "IMesh.h" + +namespace irr +{ +namespace scene +{ + +static const io::SNamedPath emptyNamedPath; + + +CMeshCache::~CMeshCache() +{ + clear(); +} + + +//! adds a mesh to the list +void CMeshCache::addMesh(const io::path& filename, IAnimatedMesh* mesh) +{ + mesh->grab(); + + MeshEntry e ( filename ); + e.Mesh = mesh; + + Meshes.push_back(e); +} + + +//! Removes a mesh from the cache. +void CMeshCache::removeMesh(const IMesh* const mesh) +{ + if ( !mesh ) + return; + for (u32 i=0; igetMesh(0) == mesh)) + { + Meshes[i].Mesh->drop(); + Meshes.erase(i); + return; + } + } +} + + +//! Returns amount of loaded meshes +u32 CMeshCache::getMeshCount() const +{ + return Meshes.size(); +} + + +//! Returns current number of the mesh +s32 CMeshCache::getMeshIndex(const IMesh* const mesh) const +{ + for (u32 i=0; igetMesh(0) == mesh)) + return (s32)i; + } + + return -1; +} + + +//! Returns a mesh based on its index number +IAnimatedMesh* CMeshCache::getMeshByIndex(u32 number) +{ + if (number >= Meshes.size()) + return 0; + + return Meshes[number].Mesh; +} + + +//! Returns a mesh based on its name. +IAnimatedMesh* CMeshCache::getMeshByName(const io::path& name) +{ + MeshEntry e ( name ); + s32 id = Meshes.binary_search(e); + return (id != -1) ? Meshes[id].Mesh : 0; +} + + +//! Get the name of a loaded mesh, based on its index. +const io::SNamedPath& CMeshCache::getMeshName(u32 index) const +{ + if (index >= Meshes.size()) + return emptyNamedPath; + + return Meshes[index].NamedPath; +} + + +//! Get the name of a loaded mesh, if there is any. +const io::SNamedPath& CMeshCache::getMeshName(const IMesh* const mesh) const +{ + if (!mesh) + return emptyNamedPath; + + for (u32 i=0; igetMesh(0) == mesh)) + return Meshes[i].NamedPath; + } + + return emptyNamedPath; +} + +//! Renames a loaded mesh. +bool CMeshCache::renameMesh(u32 index, const io::path& name) +{ + if (index >= Meshes.size()) + return false; + + Meshes[index].NamedPath.setPath(name); + Meshes.sort(); + return true; +} + + +//! Renames a loaded mesh. +bool CMeshCache::renameMesh(const IMesh* const mesh, const io::path& name) +{ + for (u32 i=0; igetMesh(0) == mesh)) + { + Meshes[i].NamedPath.setPath(name); + Meshes.sort(); + return true; + } + } + + return false; +} + + +//! returns if a mesh already was loaded +bool CMeshCache::isMeshLoaded(const io::path& name) +{ + return getMeshByName(name) != 0; +} + + +//! Clears the whole mesh cache, removing all meshes. +void CMeshCache::clear() +{ + for (u32 i=0; idrop(); + + Meshes.clear(); +} + +//! Clears all meshes that are held in the mesh cache but not used anywhere else. +void CMeshCache::clearUnusedMeshes() +{ + for (u32 i=0; igetReferenceCount() == 1) + { + Meshes[i].Mesh->drop(); + Meshes.erase(i); + --i; + } + } +} + + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CMeshCache.h b/source/Irrlicht/CMeshCache.h new file mode 100644 index 00000000..839a4ab7 --- /dev/null +++ b/source/Irrlicht/CMeshCache.h @@ -0,0 +1,123 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_MESH_CACHE_H_INCLUDED__ +#define __C_MESH_CACHE_H_INCLUDED__ + +#include "IMeshCache.h" +#include "irrArray.h" + +namespace irr +{ + +namespace scene +{ + class CMeshCache : public IMeshCache + { + public: + + virtual ~CMeshCache(); + + //! Adds a mesh to the internal list of loaded meshes. + /** Usually, ISceneManager::getMesh() is called to load a mesh from file. + That method searches the list of loaded meshes if a mesh has already been loaded and + returns a pointer to if it is in that list and already in memory. Otherwise it loads + the mesh. With IMeshCache::addMesh(), it is possible to pretend that a mesh already + has been loaded. This method can be used for example by mesh loaders who need to + load more than one mesh with one call. They can add additional meshes with this + method to the scene manager. The COLLADA loader for example uses this method. + \param filename: Filename of the mesh. When called ISceneManager::getMesh() with this + parameter, the method will return the mesh parameter given with this method. + \param mesh: Pointer to a mesh which will now be referenced by this name. */ + virtual void addMesh(const io::path& filename, IAnimatedMesh* mesh) _IRR_OVERRIDE_; + + //! Removes a mesh from the cache. + /** After loading a mesh with getMesh(), the mesh can be removed from the cache + using this method, freeing a lot of memory. */ + virtual void removeMesh(const IMesh* const mesh) _IRR_OVERRIDE_; + + //! Returns amount of loaded meshes in the cache. + /** You can load new meshes into the cache using getMesh() and addMesh(). + If you ever need to access the internal mesh cache, you can do this using + removeMesh(), getMeshNumber(), getMeshByIndex() and getMeshFilename() */ + virtual u32 getMeshCount() const _IRR_OVERRIDE_; + + //! Returns current index number of the mesh, and -1 if it is not in the cache. + virtual s32 getMeshIndex(const IMesh* const mesh) const _IRR_OVERRIDE_; + + //! Returns a mesh based on its index number. + /** \param index: Index of the mesh, number between 0 and getMeshCount()-1. + Note that this number is only valid until a new mesh is loaded or removed * + \return Returns pointer to the mesh or 0 if there is none with this number. */ + virtual IAnimatedMesh* getMeshByIndex(u32 index) _IRR_OVERRIDE_; + + //! Returns a mesh based on its name. + /** \param name Name of the mesh. Usually a filename. + \return Pointer to the mesh or 0 if there is none with this number. */ + virtual IAnimatedMesh* getMeshByName(const io::path& name) _IRR_OVERRIDE_; + + //! Get the name of a loaded mesh, based on its index. + /** \param index: Index of the mesh, number between 0 and getMeshCount()-1. + \return The name if mesh was found and has a name, else the path is empty. */ + virtual const io::SNamedPath& getMeshName(u32 index) const _IRR_OVERRIDE_; + + //! Get the name of a loaded mesh, if there is any. + /** \param mesh Pointer to mesh to query. + \return The name if mesh was found and has a name, else the path is empty. */ + virtual const io::SNamedPath& getMeshName(const IMesh* const mesh) const _IRR_OVERRIDE_; + + //! Renames a loaded mesh. + /** Note that renaming meshes might change the ordering of the + meshes, and so the index of the meshes as returned by + getMeshIndex() or taken by some methods will change. + \param index The index of the mesh in the cache. + \param name New name for the mesh. + \return True if mesh was renamed. */ + virtual bool renameMesh(u32 index, const io::path& name) _IRR_OVERRIDE_; + + //! Renames a loaded mesh. + /** Note that renaming meshes might change the ordering of the + meshes, and so the index of the meshes as returned by + getMeshIndex() or taken by some methods will change. + \param mesh Mesh to be renamed. + \param name New name for the mesh. + \return True if mesh was renamed. */ + virtual bool renameMesh(const IMesh* const mesh, const io::path& name) _IRR_OVERRIDE_; + + //! returns if a mesh already was loaded + virtual bool isMeshLoaded(const io::path& name) _IRR_OVERRIDE_; + + //! Clears the whole mesh cache, removing all meshes. + virtual void clear() _IRR_OVERRIDE_; + + //! Clears all meshes that are held in the mesh cache but not used anywhere else. + virtual void clearUnusedMeshes() _IRR_OVERRIDE_; + + protected: + + struct MeshEntry + { + MeshEntry ( const io::path& name ) + : NamedPath ( name ) + { + } + io::SNamedPath NamedPath; + IAnimatedMesh* Mesh; + + bool operator < (const MeshEntry& other) const + { + return (NamedPath < other.NamedPath); + } + }; + + //! loaded meshes + core::array Meshes; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CMeshManipulator.cpp b/source/Irrlicht/CMeshManipulator.cpp new file mode 100644 index 00000000..f177fc26 --- /dev/null +++ b/source/Irrlicht/CMeshManipulator.cpp @@ -0,0 +1,2118 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CMeshManipulator.h" +#include "SMesh.h" +#include "CMeshBuffer.h" +#include "SAnimatedMesh.h" +#include "os.h" +#include "irrMap.h" +#include "triangle3d.h" + +namespace irr +{ +namespace scene +{ + +static inline core::vector3df getAngleWeight(const core::vector3df& v1, + const core::vector3df& v2, + const core::vector3df& v3) +{ + // Calculate this triangle's weight for each of its three vertices + // start by calculating the lengths of its sides + const f32 a = v2.getDistanceFromSQ(v3); + const f32 asqrt = sqrtf(a); + const f32 b = v1.getDistanceFromSQ(v3); + const f32 bsqrt = sqrtf(b); + const f32 c = v1.getDistanceFromSQ(v2); + const f32 csqrt = sqrtf(c); + + // use them to find the angle at each vertex + return core::vector3df( + acosf((b + c - a) / (2.f * bsqrt * csqrt)), + acosf((-b + c + a) / (2.f * asqrt * csqrt)), + acosf((b - c + a) / (2.f * bsqrt * asqrt))); +} + + +//! Flips the direction of surfaces. Changes backfacing triangles to frontfacing +//! triangles and vice versa. +//! \param mesh: Mesh on which the operation is performed. +void CMeshManipulator::flipSurfaces(scene::IMesh* mesh) const +{ + if (!mesh) + return; + + const u32 bcount = mesh->getMeshBufferCount(); + for (u32 b=0; bgetMeshBuffer(b); + const u32 idxcnt = buffer->getIndexCount(); + if (buffer->getIndexType() == video::EIT_16BIT) + { + u16* idx = buffer->getIndices(); + for (u32 i=0; i(buffer->getIndices()); + for (u32 i=0; i +void recalculateNormalsT(IMeshBuffer* buffer, bool smooth, bool angleWeighted) +{ + const u32 vtxcnt = buffer->getVertexCount(); + const u32 idxcnt = buffer->getIndexCount(); + const T* idx = reinterpret_cast(buffer->getIndices()); + + if (!smooth) + { + for (u32 i=0; igetPosition(idx[i+0]); + const core::vector3df& v2 = buffer->getPosition(idx[i+1]); + const core::vector3df& v3 = buffer->getPosition(idx[i+2]); + const core::vector3df normal = core::plane3d(v1, v2, v3).Normal; + buffer->getNormal(idx[i+0]) = normal; + buffer->getNormal(idx[i+1]) = normal; + buffer->getNormal(idx[i+2]) = normal; + } + } + else + { + u32 i; + + for ( i = 0; i!= vtxcnt; ++i ) + buffer->getNormal(i).set(0.f, 0.f, 0.f); + + for ( i=0; igetPosition(idx[i+0]); + const core::vector3df& v2 = buffer->getPosition(idx[i+1]); + const core::vector3df& v3 = buffer->getPosition(idx[i+2]); + const core::vector3df normal = core::plane3d(v1, v2, v3).Normal; + + core::vector3df weight(1.f,1.f,1.f); + if (angleWeighted) + weight = irr::scene::getAngleWeight(v1,v2,v3); // writing irr::scene:: necessary for borland + + buffer->getNormal(idx[i+0]) += weight.X*normal; + buffer->getNormal(idx[i+1]) += weight.Y*normal; + buffer->getNormal(idx[i+2]) += weight.Z*normal; + } + + for ( i = 0; i!= vtxcnt; ++i ) + buffer->getNormal(i).normalize(); + } +} +} + + +//! Recalculates all normals of the mesh buffer. +/** \param buffer: Mesh buffer on which the operation is performed. */ +void CMeshManipulator::recalculateNormals(IMeshBuffer* buffer, bool smooth, bool angleWeighted) const +{ + if (!buffer) + return; + + if (buffer->getIndexType()==video::EIT_16BIT) + recalculateNormalsT(buffer, smooth, angleWeighted); + else + recalculateNormalsT(buffer, smooth, angleWeighted); +} + + +//! Recalculates all normals of the mesh. +//! \param mesh: Mesh on which the operation is performed. +void CMeshManipulator::recalculateNormals(scene::IMesh* mesh, bool smooth, bool angleWeighted) const +{ + if (!mesh) + return; + + const u32 bcount = mesh->getMeshBufferCount(); + for ( u32 b=0; bgetMeshBuffer(b), smooth, angleWeighted); +} + + +namespace +{ +void calculateTangents( + core::vector3df& normal, + core::vector3df& tangent, + core::vector3df& binormal, + const core::vector3df& vt1, const core::vector3df& vt2, const core::vector3df& vt3, // vertices + const core::vector2df& tc1, const core::vector2df& tc2, const core::vector2df& tc3) // texture coords +{ + // choose one of them: + //#define USE_NVIDIA_GLH_VERSION // use version used by nvidia in glh headers + #define USE_IRR_VERSION + +#ifdef USE_IRR_VERSION + + core::vector3df v1 = vt1 - vt2; + core::vector3df v2 = vt3 - vt1; + normal = v2.crossProduct(v1); + normal.normalize(); + + // binormal + + f32 deltaX1 = tc1.X - tc2.X; + f32 deltaX2 = tc3.X - tc1.X; + binormal = (v1 * deltaX2) - (v2 * deltaX1); + binormal.normalize(); + + // tangent + + f32 deltaY1 = tc1.Y - tc2.Y; + f32 deltaY2 = tc3.Y - tc1.Y; + tangent = (v1 * deltaY2) - (v2 * deltaY1); + tangent.normalize(); + + // adjust + + core::vector3df txb = tangent.crossProduct(binormal); + if (txb.dotProduct(normal) < 0.0f) + { + tangent *= -1.0f; + binormal *= -1.0f; + } + +#endif // USE_IRR_VERSION + +#ifdef USE_NVIDIA_GLH_VERSION + + tangent.set(0,0,0); + binormal.set(0,0,0); + + core::vector3df v1(vt2.X - vt1.X, tc2.X - tc1.X, tc2.Y - tc1.Y); + core::vector3df v2(vt3.X - vt1.X, tc3.X - tc1.X, tc3.Y - tc1.Y); + + core::vector3df txb = v1.crossProduct(v2); + if ( !core::iszero ( txb.X ) ) + { + tangent.X = -txb.Y / txb.X; + binormal.X = -txb.Z / txb.X; + } + + v1.X = vt2.Y - vt1.Y; + v2.X = vt3.Y - vt1.Y; + txb = v1.crossProduct(v2); + + if ( !core::iszero ( txb.X ) ) + { + tangent.Y = -txb.Y / txb.X; + binormal.Y = -txb.Z / txb.X; + } + + v1.X = vt2.Z - vt1.Z; + v2.X = vt3.Z - vt1.Z; + txb = v1.crossProduct(v2); + + if ( !core::iszero ( txb.X ) ) + { + tangent.Z = -txb.Y / txb.X; + binormal.Z = -txb.Z / txb.X; + } + + tangent.normalize(); + binormal.normalize(); + + normal = tangent.crossProduct(binormal); + normal.normalize(); + + binormal = tangent.crossProduct(normal); + binormal.normalize(); + + core::plane3d pl(vt1, vt2, vt3); + + if(normal.dotProduct(pl.Normal) < 0.0f ) + normal *= -1.0f; + +#endif // USE_NVIDIA_GLH_VERSION +} + + +//! Recalculates tangents for a tangent mesh buffer +template +void recalculateTangentsT(IMeshBuffer* buffer, bool recalculateNormals, bool smooth, bool angleWeighted) +{ + if (!buffer || (buffer->getVertexType()!= video::EVT_TANGENTS)) + return; + + const u32 vtxCnt = buffer->getVertexCount(); + const u32 idxCnt = buffer->getIndexCount(); + + T* idx = reinterpret_cast(buffer->getIndices()); + video::S3DVertexTangents* v = + (video::S3DVertexTangents*)buffer->getVertices(); + + if (smooth) + { + u32 i; + + for ( i = 0; i!= vtxCnt; ++i ) + { + if (recalculateNormals) + v[i].Normal.set( 0.f, 0.f, 0.f ); + v[i].Tangent.set( 0.f, 0.f, 0.f ); + v[i].Binormal.set( 0.f, 0.f, 0.f ); + } + + //Each vertex gets the sum of the tangents and binormals from the faces around it + for ( i=0; igetVertexType() == video::EVT_TANGENTS)) + { + if (buffer->getIndexType() == video::EIT_16BIT) + recalculateTangentsT(buffer, recalculateNormals, smooth, angleWeighted); + else + recalculateTangentsT(buffer, recalculateNormals, smooth, angleWeighted); + } +} + + +//! Recalculates tangents for all tangent mesh buffers +void CMeshManipulator::recalculateTangents(IMesh* mesh, bool recalculateNormals, bool smooth, bool angleWeighted) const +{ + if (!mesh) + return; + + const u32 meshBufferCount = mesh->getMeshBufferCount(); + for (u32 b=0; bgetMeshBuffer(b), recalculateNormals, smooth, angleWeighted); + } +} + + +namespace +{ +//! Creates a planar texture mapping on the meshbuffer +template +void makePlanarTextureMappingT(scene::IMeshBuffer* buffer, f32 resolution) +{ + u32 idxcnt = buffer->getIndexCount(); + T* idx = reinterpret_cast(buffer->getIndices()); + + for (u32 i=0; igetPosition(idx[i+0]), buffer->getPosition(idx[i+1]), buffer->getPosition(idx[i+2])); + p.Normal.X = fabsf(p.Normal.X); + p.Normal.Y = fabsf(p.Normal.Y); + p.Normal.Z = fabsf(p.Normal.Z); + // calculate planar mapping worldspace coordinates + + if (p.Normal.X > p.Normal.Y && p.Normal.X > p.Normal.Z) + { + for (u32 o=0; o!=3; ++o) + { + buffer->getTCoords(idx[i+o]).X = buffer->getPosition(idx[i+o]).Y * resolution; + buffer->getTCoords(idx[i+o]).Y = buffer->getPosition(idx[i+o]).Z * resolution; + } + } + else + if (p.Normal.Y > p.Normal.X && p.Normal.Y > p.Normal.Z) + { + for (u32 o=0; o!=3; ++o) + { + buffer->getTCoords(idx[i+o]).X = buffer->getPosition(idx[i+o]).X * resolution; + buffer->getTCoords(idx[i+o]).Y = buffer->getPosition(idx[i+o]).Z * resolution; + } + } + else + { + for (u32 o=0; o!=3; ++o) + { + buffer->getTCoords(idx[i+o]).X = buffer->getPosition(idx[i+o]).X * resolution; + buffer->getTCoords(idx[i+o]).Y = buffer->getPosition(idx[i+o]).Y * resolution; + } + } + } +} +} + + +//! Creates a planar texture mapping on the meshbuffer +void CMeshManipulator::makePlanarTextureMapping(scene::IMeshBuffer* buffer, f32 resolution) const +{ + if (!buffer) + return; + + if (buffer->getIndexType()==video::EIT_16BIT) + makePlanarTextureMappingT(buffer, resolution); + else + makePlanarTextureMappingT(buffer, resolution); +} + + +//! Creates a planar texture mapping on the mesh +void CMeshManipulator::makePlanarTextureMapping(scene::IMesh* mesh, f32 resolution) const +{ + if (!mesh) + return; + + const u32 bcount = mesh->getMeshBufferCount(); + for ( u32 b=0; bgetMeshBuffer(b), resolution); + } +} + + +namespace +{ +//! Creates a planar texture mapping on the meshbuffer +template +void makePlanarTextureMappingT(scene::IMeshBuffer* buffer, f32 resolutionS, f32 resolutionT, u8 axis, const core::vector3df& offset) +{ + u32 idxcnt = buffer->getIndexCount(); + T* idx = reinterpret_cast(buffer->getIndices()); + + for (u32 i=0; igetTCoords(idx[i+o]).X = 0.5f+(buffer->getPosition(idx[i+o]).Z + offset.Z) * resolutionS; + buffer->getTCoords(idx[i+o]).Y = 0.5f-(buffer->getPosition(idx[i+o]).Y + offset.Y) * resolutionT; + } + } + else if (axis==1) + { + for (u32 o=0; o!=3; ++o) + { + buffer->getTCoords(idx[i+o]).X = 0.5f+(buffer->getPosition(idx[i+o]).X + offset.X) * resolutionS; + buffer->getTCoords(idx[i+o]).Y = 1.f-(buffer->getPosition(idx[i+o]).Z + offset.Z) * resolutionT; + } + } + else if (axis==2) + { + for (u32 o=0; o!=3; ++o) + { + buffer->getTCoords(idx[i+o]).X = 0.5f+(buffer->getPosition(idx[i+o]).X + offset.X) * resolutionS; + buffer->getTCoords(idx[i+o]).Y = 0.5f-(buffer->getPosition(idx[i+o]).Y + offset.Y) * resolutionT; + } + } + } +} +} + + +//! Creates a planar texture mapping on the meshbuffer +void CMeshManipulator::makePlanarTextureMapping(scene::IMeshBuffer* buffer, f32 resolutionS, f32 resolutionT, u8 axis, const core::vector3df& offset) const +{ + if (!buffer) + return; + + if (buffer->getIndexType()==video::EIT_16BIT) + makePlanarTextureMappingT(buffer, resolutionS, resolutionT, axis, offset); + else + makePlanarTextureMappingT(buffer, resolutionS, resolutionT, axis, offset); +} + + +//! Creates a planar texture mapping on the mesh +void CMeshManipulator::makePlanarTextureMapping(scene::IMesh* mesh, f32 resolutionS, f32 resolutionT, u8 axis, const core::vector3df& offset) const +{ + if (!mesh) + return; + + const u32 bcount = mesh->getMeshBufferCount(); + for ( u32 b=0; bgetMeshBuffer(b), resolutionS, resolutionT, axis, offset); + } +} + + +//! Clones a static IMesh into a modifyable SMesh. +// not yet 32bit +SMesh* CMeshManipulator::createMeshCopy(scene::IMesh* mesh) const +{ + if (!mesh) + return 0; + + SMesh* clone = new SMesh(); + + const u32 meshBufferCount = mesh->getMeshBufferCount(); + + for ( u32 b=0; bgetMeshBuffer(b); + switch(mb->getVertexType()) + { + case video::EVT_STANDARD: + { + SMeshBuffer* buffer = new SMeshBuffer(); + buffer->Material = mb->getMaterial(); + const u32 vcount = mb->getVertexCount(); + buffer->Vertices.reallocate(vcount); + video::S3DVertex* vertices = (video::S3DVertex*)mb->getVertices(); + for (u32 i=0; i < vcount; ++i) + buffer->Vertices.push_back(vertices[i]); + const u32 icount = mb->getIndexCount(); + buffer->Indices.reallocate(icount); + const u16* indices = mb->getIndices(); + for (u32 i=0; i < icount; ++i) + buffer->Indices.push_back(indices[i]); + clone->addMeshBuffer(buffer); + buffer->drop(); + } + break; + case video::EVT_2TCOORDS: + { + SMeshBufferLightMap* buffer = new SMeshBufferLightMap(); + buffer->Material = mb->getMaterial(); + const u32 vcount = mb->getVertexCount(); + buffer->Vertices.reallocate(vcount); + video::S3DVertex2TCoords* vertices = (video::S3DVertex2TCoords*)mb->getVertices(); + for (u32 i=0; i < vcount; ++i) + buffer->Vertices.push_back(vertices[i]); + const u32 icount = mb->getIndexCount(); + buffer->Indices.reallocate(icount); + const u16* indices = mb->getIndices(); + for (u32 i=0; i < icount; ++i) + buffer->Indices.push_back(indices[i]); + clone->addMeshBuffer(buffer); + buffer->drop(); + } + break; + case video::EVT_TANGENTS: + { + SMeshBufferTangents* buffer = new SMeshBufferTangents(); + buffer->Material = mb->getMaterial(); + const u32 vcount = mb->getVertexCount(); + buffer->Vertices.reallocate(vcount); + video::S3DVertexTangents* vertices = (video::S3DVertexTangents*)mb->getVertices(); + for (u32 i=0; i < vcount; ++i) + buffer->Vertices.push_back(vertices[i]); + const u32 icount = mb->getIndexCount(); + buffer->Indices.reallocate(icount); + const u16* indices = mb->getIndices(); + for (u32 i=0; i < icount; ++i) + buffer->Indices.push_back(indices[i]); + clone->addMeshBuffer(buffer); + buffer->drop(); + } + break; + }// end switch + + }// end for all mesh buffers + + clone->BoundingBox = mesh->getBoundingBox(); + return clone; +} + + +//! Creates a copy of the mesh, which will only consist of unique primitives +// not yet 32bit +IMesh* CMeshManipulator::createMeshUniquePrimitives(IMesh* mesh) const +{ + if (!mesh) + return 0; + + SMesh* clone = new SMesh(); + + const u32 meshBufferCount = mesh->getMeshBufferCount(); + + for ( u32 b=0; bgetMeshBuffer(b); + const s32 idxCnt = mb->getIndexCount(); + const u16* idx = mb->getIndices(); + + switch(mb->getVertexType()) + { + case video::EVT_STANDARD: + { + SMeshBuffer* buffer = new SMeshBuffer(); + buffer->Material = mb->getMaterial(); + + video::S3DVertex* v = + (video::S3DVertex*)mb->getVertices(); + + buffer->Vertices.reallocate(idxCnt); + buffer->Indices.reallocate(idxCnt); + for (s32 i=0; iVertices.push_back( v[idx[i + 0 ]] ); + buffer->Vertices.push_back( v[idx[i + 1 ]] ); + buffer->Vertices.push_back( v[idx[i + 2 ]] ); + + buffer->Indices.push_back( i + 0 ); + buffer->Indices.push_back( i + 1 ); + buffer->Indices.push_back( i + 2 ); + } + + buffer->setBoundingBox(mb->getBoundingBox()); + clone->addMeshBuffer(buffer); + buffer->drop(); + } + break; + case video::EVT_2TCOORDS: + { + SMeshBufferLightMap* buffer = new SMeshBufferLightMap(); + buffer->Material = mb->getMaterial(); + + video::S3DVertex2TCoords* v = + (video::S3DVertex2TCoords*)mb->getVertices(); + + buffer->Vertices.reallocate(idxCnt); + buffer->Indices.reallocate(idxCnt); + for (s32 i=0; iVertices.push_back( v[idx[i + 0 ]] ); + buffer->Vertices.push_back( v[idx[i + 1 ]] ); + buffer->Vertices.push_back( v[idx[i + 2 ]] ); + + buffer->Indices.push_back( i + 0 ); + buffer->Indices.push_back( i + 1 ); + buffer->Indices.push_back( i + 2 ); + } + buffer->setBoundingBox(mb->getBoundingBox()); + clone->addMeshBuffer(buffer); + buffer->drop(); + } + break; + case video::EVT_TANGENTS: + { + SMeshBufferTangents* buffer = new SMeshBufferTangents(); + buffer->Material = mb->getMaterial(); + + video::S3DVertexTangents* v = + (video::S3DVertexTangents*)mb->getVertices(); + + buffer->Vertices.reallocate(idxCnt); + buffer->Indices.reallocate(idxCnt); + for (s32 i=0; iVertices.push_back( v[idx[i + 0 ]] ); + buffer->Vertices.push_back( v[idx[i + 1 ]] ); + buffer->Vertices.push_back( v[idx[i + 2 ]] ); + + buffer->Indices.push_back( i + 0 ); + buffer->Indices.push_back( i + 1 ); + buffer->Indices.push_back( i + 2 ); + } + + buffer->setBoundingBox(mb->getBoundingBox()); + clone->addMeshBuffer(buffer); + buffer->drop(); + } + break; + }// end switch + + }// end for all mesh buffers + + clone->BoundingBox = mesh->getBoundingBox(); + return clone; +} + + +//! Creates a copy of a mesh, which will have identical vertices welded together +// not yet 32bit +IMesh* CMeshManipulator::createMeshWelded(IMesh *mesh, f32 tolerance) const +{ + SMesh* clone = new SMesh(); + clone->BoundingBox = mesh->getBoundingBox(); + + core::array redirects; + + for (u32 b=0; bgetMeshBufferCount(); ++b) + { + const IMeshBuffer* const mb = mesh->getMeshBuffer(b); + // reset redirect list + redirects.set_used(mb->getVertexCount()); + + const u16* indices = 0; + u32 indexCount = 0; + core::array* outIdx = 0; + + switch(mb->getVertexType()) + { + case video::EVT_STANDARD: + { + SMeshBuffer* buffer = new SMeshBuffer(); + buffer->BoundingBox = mb->getBoundingBox(); + buffer->Material = mb->getMaterial(); + clone->addMeshBuffer(buffer); + buffer->drop(); + + video::S3DVertex* v = + (video::S3DVertex*)mb->getVertices(); + + u32 vertexCount = mb->getVertexCount(); + + indices = mb->getIndices(); + indexCount = mb->getIndexCount(); + outIdx = &buffer->Indices; + + buffer->Vertices.reallocate(vertexCount); + + for (u32 i=0; i < vertexCount; ++i) + { + bool found = false; + for (u32 j=0; j < i; ++j) + { + if ( v[i].Pos.equals( v[j].Pos, tolerance) && + v[i].Normal.equals( v[j].Normal, tolerance) && + v[i].TCoords.equals( v[j].TCoords ) && + (v[i].Color == v[j].Color) ) + { + redirects[i] = redirects[j]; + found = true; + break; + } + } + if (!found) + { + redirects[i] = buffer->Vertices.size(); + buffer->Vertices.push_back(v[i]); + } + } + + break; + } + case video::EVT_2TCOORDS: + { + SMeshBufferLightMap* buffer = new SMeshBufferLightMap(); + buffer->BoundingBox = mb->getBoundingBox(); + buffer->Material = mb->getMaterial(); + clone->addMeshBuffer(buffer); + buffer->drop(); + + video::S3DVertex2TCoords* v = + (video::S3DVertex2TCoords*)mb->getVertices(); + + u32 vertexCount = mb->getVertexCount(); + + indices = mb->getIndices(); + indexCount = mb->getIndexCount(); + outIdx = &buffer->Indices; + + buffer->Vertices.reallocate(vertexCount); + + for (u32 i=0; i < vertexCount; ++i) + { + bool found = false; + for (u32 j=0; j < i; ++j) + { + if ( v[i].Pos.equals( v[j].Pos, tolerance) && + v[i].Normal.equals( v[j].Normal, tolerance) && + v[i].TCoords.equals( v[j].TCoords ) && + v[i].TCoords2.equals( v[j].TCoords2 ) && + (v[i].Color == v[j].Color) ) + { + redirects[i] = redirects[j]; + found = true; + break; + } + } + if (!found) + { + redirects[i] = buffer->Vertices.size(); + buffer->Vertices.push_back(v[i]); + } + } + break; + } + case video::EVT_TANGENTS: + { + SMeshBufferTangents* buffer = new SMeshBufferTangents(); + buffer->BoundingBox = mb->getBoundingBox(); + buffer->Material = mb->getMaterial(); + clone->addMeshBuffer(buffer); + buffer->drop(); + + video::S3DVertexTangents* v = + (video::S3DVertexTangents*)mb->getVertices(); + + u32 vertexCount = mb->getVertexCount(); + + indices = mb->getIndices(); + indexCount = mb->getIndexCount(); + outIdx = &buffer->Indices; + + buffer->Vertices.reallocate(vertexCount); + + for (u32 i=0; i < vertexCount; ++i) + { + bool found = false; + for (u32 j=0; j < i; ++j) + { + if ( v[i].Pos.equals( v[j].Pos, tolerance) && + v[i].Normal.equals( v[j].Normal, tolerance) && + v[i].TCoords.equals( v[j].TCoords ) && + v[i].Tangent.equals( v[j].Tangent, tolerance ) && + v[i].Binormal.equals( v[j].Binormal, tolerance ) && + (v[i].Color == v[j].Color) ) + { + redirects[i] = redirects[j]; + found = true; + break; + } + } + if (!found) + { + redirects[i] = buffer->Vertices.size(); + buffer->Vertices.push_back(v[i]); + } + } + break; + } + default: + os::Printer::log("Cannot create welded mesh, vertex type unsupported", ELL_ERROR); + break; + } + + // Clean up any degenerate tris + core::array &Indices = *outIdx; + Indices.clear(); + Indices.reallocate(indexCount); + for (u32 i = 0; i < indexCount; i+=3) + { + u16 a, b, c; + a = redirects[indices[i]]; + b = redirects[indices[i+1]]; + c = redirects[indices[i+2]]; + + bool drop = false; + + if (a == b || b == c || a == c) + drop = true; + + // Open for other checks + + if (!drop) + { + Indices.push_back(a); + Indices.push_back(b); + Indices.push_back(c); + } + } + } + return clone; +} + + +//! Creates a copy of the mesh, which will only consist of S3DVertexTangents vertices. +// not yet 32bit +IMesh* CMeshManipulator::createMeshWithTangents(IMesh* mesh, bool recalculateNormals, bool smooth, bool angleWeighted, bool calculateTangents) const +{ + using namespace video; + + if (!mesh) + return 0; + + // copy mesh and fill data into SMeshBufferTangents + SMesh* clone = new SMesh(); + const u32 meshBufferCount = mesh->getMeshBufferCount(); + + for (u32 b=0; bgetMeshBuffer(b); + SMeshBufferTangents* buffer = new SMeshBufferTangents(); + + // copy material + buffer->Material = original->getMaterial(); + + // copy indices + const u32 idxCnt = original->getIndexCount(); + const u16* indices = original->getIndices(); + buffer->Indices.reallocate(idxCnt); + for (u32 i=0; i < idxCnt; ++i) + buffer->Indices.push_back(indices[i]); + + // copy vertices + const u32 vtxCnt = original->getVertexCount(); + buffer->Vertices.reallocate(vtxCnt); + + const E_VERTEX_TYPE vType = original->getVertexType(); + switch(vType) + { + case video::EVT_STANDARD: + { + const S3DVertex* v = (const S3DVertex*)original->getVertices(); + + for (u32 i=0; i < vtxCnt; ++i) + buffer->Vertices.push_back( S3DVertexTangents( + v[i].Pos, v[i].Normal, v[i].Color, v[i].TCoords) ); + } + break; + case video::EVT_2TCOORDS: + { + const S3DVertex2TCoords* v =(const S3DVertex2TCoords*)original->getVertices(); + + for (u32 i=0; i < vtxCnt; ++i) + buffer->Vertices.push_back( S3DVertexTangents( + v[i].Pos, v[i].Normal, v[i].Color, v[i].TCoords) ); + } + break; + case video::EVT_TANGENTS: + { + const S3DVertexTangents* v =(const S3DVertexTangents*)original->getVertices(); + + for (u32 i=0; i < vtxCnt; ++i) + buffer->Vertices.push_back(v[i]); + } + break; + } + buffer->recalculateBoundingBox(); + + // add new buffer + clone->addMeshBuffer(buffer); + buffer->drop(); + } + + clone->recalculateBoundingBox(); + if (calculateTangents) + recalculateTangents(clone, recalculateNormals, smooth, angleWeighted); + + return clone; +} + +namespace +{ + +struct height_edge +{ + u32 far; + + u32 polycount; + u32 polys[2]; + core::vector3df normal[2]; +}; + +enum +{ + HEIGHT_TRIACCEL_MAX = 1024 +}; + +} + +//! Optimizes the mesh using an algorithm tuned for heightmaps. +void CMeshManipulator::heightmapOptimizeMesh(IMesh * const m, const f32 tolerance) const +{ + const u32 max = m->getMeshBufferCount(); + + for (u32 i = 0; i < max; i++) + { + IMeshBuffer * const mb = m->getMeshBuffer(i); + + heightmapOptimizeMesh(mb, tolerance); + } +} + +//! Optimizes the mesh using an algorithm tuned for heightmaps. +void CMeshManipulator::heightmapOptimizeMesh(IMeshBuffer * const mb, const f32 tolerance) const +{ + using namespace core; + using namespace video; + + array edges; + + const u32 idxs = mb->getIndexCount(); + const u32 verts = mb->getVertexCount(); + + u16 *ind = mb->getIndices(); + S3DVertex *vert = (S3DVertex *) mb->getVertices(); + + // First an acceleration structure: given this vert, which triangles touch it? + // Using this drops two exponents off the algorightm complexity, O(n^4) > O(n^2) + // Other optimizations brought it down to O(n). + u32 **accel = (u32 **) malloc(verts * sizeof(u32 *)); + for (u32 i = 0; i < verts; i++) + { + accel[i] = (u32 *) calloc(HEIGHT_TRIACCEL_MAX, sizeof(u32)); + for (u32 j = 0; j < HEIGHT_TRIACCEL_MAX; j++) + { + accel[i][j] = USHRT_MAX; + } + } + + u16 *cur = (u16 *) calloc(verts, sizeof(u16)); + for (u32 j = 0; j < idxs; j+=3) + { + u32 v = ind[j]; + + if (cur[v] >= HEIGHT_TRIACCEL_MAX) + { + os::Printer::log("Too complex mesh to optimize, aborting."); + goto donehere; + } + + accel[v][cur[v]] = j; + cur[v]++; + + // Unrolled tri loop, parts 2 and 3 + v = ind[j+1]; + + if (cur[v] >= HEIGHT_TRIACCEL_MAX) + { + os::Printer::log("Too complex mesh to optimize, aborting."); + goto donehere; + } + + accel[v][cur[v]] = j; + cur[v]++; + + v = ind[j+2]; + + if (cur[v] >= HEIGHT_TRIACCEL_MAX) + { + os::Printer::log("Too complex mesh to optimize, aborting."); + goto donehere; + } + + accel[v][cur[v]] = j; + cur[v]++; + } + free(cur); + + // Built, go + for (u32 i = 0; i < verts; i++) + { + const vector3df &mypos = vert[i].Pos; + + // find all edges of this vert + edges.clear(); + + bool gotonext = false; + u32 j; + u16 cur; + for (cur = 0; accel[i][cur] != USHRT_MAX && cur < HEIGHT_TRIACCEL_MAX; cur++) + { + j = accel[i][cur]; + + u32 far1 = -1, far2 = -1; + if (ind[j] == i) + { + far1 = ind[j+1]; + far2 = ind[j+2]; + } + else if (ind[j+1] == i) + { + far1 = ind[j]; + far2 = ind[j+2]; + } + else if (ind[j+2] == i) + { + far1 = ind[j]; + far2 = ind[j+1]; + } + + // Skip degenerate tris + if (vert[i].Pos == vert[far1].Pos || + vert[far1].Pos == vert[far2].Pos) + { +// puts("skipping degenerate tri"); + continue; + } + + // Edges found, check if we already added them + const u32 ecount = edges.size(); + bool far1new = true, far2new = true; + + for (u32 e = 0; e < ecount; e++) + { + if (edges[e].far == far1 || + edges[e].far == far2) + { + + // Skip if over 2 polys + if (edges[e].polycount > 2) + { + gotonext = true; + goto almostnext; + } + edges[e].polys[edges[e].polycount] = j; + edges[e].normal[edges[e].polycount] = + vert[i].Normal; + edges[e].polycount++; + + if (edges[e].far == far1) + far1new = false; + else + far2new = false; + } + } + + if (far1new) + { + // New edge + height_edge ed; + + ed.far = far1; + ed.polycount = 1; + ed.polys[0] = j; + ed.normal[0] = vert[i].Normal; + + edges.push_back(ed); + } + if (far2new) + { + // New edge + height_edge ed; + + ed.far = far2; + ed.polycount = 1; + ed.polys[0] = j; + ed.normal[0] = vert[i].Normal; + + edges.push_back(ed); + } + } + + almostnext: + if (gotonext) + continue; + + // Edges found. Possible to simplify? + + const u32 ecount = edges.size(); +// printf("Vert %u has %u edges\n", i, ecount); + for (u32 e = 0; e < ecount; e++) + { + for (u32 f = 0; f < ecount; f++) + { + if (f == e) continue; + + vector3df one = mypos - vert[edges[e].far].Pos; + vector3df two = vert[edges[f].far].Pos - mypos; + + one.normalize(); + two.normalize(); + + // Straight line ? + if (!one.equals(two, tolerance) || one.getLengthSQ() < 0.5f) + continue; + + // All other edges must have two polys + for (u32 g = 0; g < ecount; g++) + { + if (g == e || g == f) + continue; + + if (edges[g].polycount != 2) + { +// printf("%u: polycount not 2 (%u)\n", +// g, edges[g].polycount); + goto testnext; + } + + // Normals must match + if (!edges[g].normal[0].equals(edges[g].normal[1], + tolerance)) + { +// puts("Normals don't match"); + goto testnext; + } + + // Normals must not flip + for (u32 z = 0; z < edges[g].polycount; z++) + { + bool flat = false; + vector3df pos[3]; + pos[0] = + vert[ind[edges[g].polys[z]]].Pos; + pos[1] = + vert[ind[edges[g].polys[z] + 1]].Pos; + pos[2] = + vert[ind[edges[g].polys[z] + 2]].Pos; + + for (u32 y = 0; y < 3; y++) + { + if (edges[g].polys[z] + y == i) + { + pos[y] = vert[edges[e].far].Pos; + } + else if (edges[g].polys[z] + y + == edges[e].far) + { + flat = true; + break; + } + } + if (!flat) + { + triangle3df temp(pos[0], + pos[1], pos[2]); + vector3df N = temp.getNormal(); + N.normalize(); +// if (N.getLengthSQ() < 0.5f) +// puts("empty"); + + if (!N.equals(edges[g].normal[z], tolerance)) + { +// puts("wouldflip"); + goto testnext; + } + } + } + + // Must not be on model edge + if (edges[g].polycount == 1) + { + goto testnext; + } + + } + + // Must not be on model edge + if (edges[e].polycount == 1) + { + goto testnext; + } + + // OK, moving to welding position + vert[i] = vert[edges[e].far]; +// printf("Contracted vert %u to %u\n", +// i, edges[e].far); + } + } + + + testnext:; + } + +donehere: + for (u32 i = 0; i < verts; i++) + { + free(accel[i]); + } + free(accel); +} + +//! Creates a copy of the mesh, which will only consist of S3DVertex2TCoords vertices. +// not yet 32bit +IMesh* CMeshManipulator::createMeshWith2TCoords(IMesh* mesh) const +{ + using namespace video; + + if (!mesh) + return 0; + + // copy mesh and fill data into SMeshBufferLightMap + + SMesh* clone = new SMesh(); + const u32 meshBufferCount = mesh->getMeshBufferCount(); + + for (u32 b=0; bgetMeshBuffer(b); + SMeshBufferLightMap* buffer = new SMeshBufferLightMap(); + + // copy material + buffer->Material = original->getMaterial(); + + // copy indices + const u32 idxCnt = original->getIndexCount(); + const u16* indices = original->getIndices(); + buffer->Indices.reallocate(idxCnt); + for (u32 i=0; i < idxCnt; ++i) + buffer->Indices.push_back(indices[i]); + + // copy vertices + const u32 vtxCnt = original->getVertexCount(); + buffer->Vertices.reallocate(vtxCnt); + + const video::E_VERTEX_TYPE vType = original->getVertexType(); + switch(vType) + { + case video::EVT_STANDARD: + { + const S3DVertex* v = (const S3DVertex*)original->getVertices(); + + for (u32 i=0; i < vtxCnt; ++i) + buffer->Vertices.push_back( video::S3DVertex2TCoords( + v[i].Pos, v[i].Normal, v[i].Color, v[i].TCoords, v[i].TCoords)); + } + break; + case video::EVT_2TCOORDS: + { + const S3DVertex2TCoords* v =(const S3DVertex2TCoords*)original->getVertices(); + for (u32 i=0; i < vtxCnt; ++i) + buffer->Vertices.push_back(v[i]); + } + break; + case video::EVT_TANGENTS: + { + const S3DVertexTangents* v =(const S3DVertexTangents*)original->getVertices(); + + for (u32 i=0; i < vtxCnt; ++i) + buffer->Vertices.push_back( S3DVertex2TCoords( + v[i].Pos, v[i].Normal, v[i].Color, v[i].TCoords, v[i].TCoords) ); + } + break; + } + buffer->recalculateBoundingBox(); + + // add new buffer + clone->addMeshBuffer(buffer); + buffer->drop(); + } + + clone->recalculateBoundingBox(); + return clone; +} + + +//! Creates a copy of the mesh, which will only consist of S3DVertex vertices. +// not yet 32bit +IMesh* CMeshManipulator::createMeshWith1TCoords(IMesh* mesh) const +{ + using namespace video; + + if (!mesh) + return 0; + + // copy mesh and fill data into SMeshBuffer + SMesh* clone = new SMesh(); + const u32 meshBufferCount = mesh->getMeshBufferCount(); + + for (u32 b=0; bgetMeshBuffer(b); + SMeshBuffer* buffer = new SMeshBuffer(); + + // copy material + buffer->Material = original->getMaterial(); + + // copy indices + const u32 idxCnt = original->getIndexCount(); + const u16* indices = original->getIndices(); + buffer->Indices.reallocate(idxCnt); + for (u32 i=0; i < idxCnt; ++i) + buffer->Indices.push_back(indices[i]); + + // copy vertices + const u32 vtxCnt = original->getVertexCount(); + buffer->Vertices.reallocate(vtxCnt); + + const video::E_VERTEX_TYPE vType = original->getVertexType(); + switch(vType) + { + case video::EVT_STANDARD: + { + const S3DVertex* v = (const S3DVertex*)original->getVertices(); + + for (u32 i=0; i < vtxCnt; ++i) + buffer->Vertices.push_back( v[i] ); + } + break; + case video::EVT_2TCOORDS: + { + const S3DVertex2TCoords* v =(const S3DVertex2TCoords*)original->getVertices(); + + for (u32 i=0; i < vtxCnt; ++i) + buffer->Vertices.push_back( S3DVertex( + v[i].Pos, v[i].Normal, v[i].Color, v[i].TCoords) ); + } + break; + case video::EVT_TANGENTS: + { + const S3DVertexTangents* v =(const S3DVertexTangents*)original->getVertices(); + + for (u32 i=0; i < vtxCnt; ++i) + buffer->Vertices.push_back( S3DVertex( + v[i].Pos, v[i].Normal, v[i].Color, v[i].TCoords) ); + } + break; + } + + buffer->recalculateBoundingBox(); + // add new buffer + clone->addMeshBuffer(buffer); + buffer->drop(); + } + + clone->recalculateBoundingBox(); + return clone; +} + + +//! Returns amount of polygons in mesh. +s32 CMeshManipulator::getPolyCount(scene::IMesh* mesh) const +{ + if (!mesh) + return 0; + + s32 trianglecount = 0; + + for (u32 g=0; ggetMeshBufferCount(); ++g) + trianglecount += mesh->getMeshBuffer(g)->getIndexCount() / 3; + + return trianglecount; +} + + +//! Returns amount of polygons in mesh. +s32 CMeshManipulator::getPolyCount(scene::IAnimatedMesh* mesh) const +{ + if (mesh && mesh->getFrameCount() != 0) + return getPolyCount(mesh->getMesh(0)); + + return 0; +} + + +//! create a new AnimatedMesh and adds the mesh to it +IAnimatedMesh * CMeshManipulator::createAnimatedMesh(scene::IMesh* mesh, scene::E_ANIMATED_MESH_TYPE type) const +{ + return new SAnimatedMesh(mesh, type); +} + +namespace +{ + +struct vcache +{ + core::array tris; + float score; + s16 cachepos; + u16 NumActiveTris; +}; + +struct tcache +{ + u16 ind[3]; + float score; + bool drawn; +}; + +const u16 cachesize = 32; + +float FindVertexScore(vcache *v) +{ + const float CacheDecayPower = 1.5f; + const float LastTriScore = 0.75f; + const float ValenceBoostScale = 2.0f; + const float ValenceBoostPower = 0.5f; + const float MaxSizeVertexCache = 32.0f; + + if (v->NumActiveTris == 0) + { + // No tri needs this vertex! + return -1.0f; + } + + float Score = 0.0f; + int CachePosition = v->cachepos; + if (CachePosition < 0) + { + // Vertex is not in FIFO cache - no score. + } + else + { + if (CachePosition < 3) + { + // This vertex was used in the last triangle, + // so it has a fixed score. + Score = LastTriScore; + } + else + { + // Points for being high in the cache. + const float Scaler = 1.0f / (MaxSizeVertexCache - 3); + Score = 1.0f - (CachePosition - 3) * Scaler; + Score = powf(Score, CacheDecayPower); + } + } + + // Bonus points for having a low number of tris still to + // use the vert, so we get rid of lone verts quickly. + float ValenceBoost = powf(v->NumActiveTris, + -ValenceBoostPower); + Score += ValenceBoostScale * ValenceBoost; + + return Score; +} + +/* + A specialized LRU cache for the Forsyth algorithm. +*/ + +class f_lru +{ + +public: + f_lru(vcache *v, tcache *t): vc(v), tc(t) + { + for (u16 i = 0; i < cachesize; i++) + { + cache[i] = -1; + } + } + + // Adds this vertex index and returns the highest-scoring triangle index + u32 add(u16 vert, bool updatetris = false) + { + bool found = false; + + // Mark existing pos as empty + for (u16 i = 0; i < cachesize; i++) + { + if (cache[i] == vert) + { + // Move everything down + for (u16 j = i; j; j--) + { + cache[j] = cache[j - 1]; + } + + found = true; + break; + } + } + + if (!found) + { + if (cache[cachesize-1] != -1) + vc[cache[cachesize-1]].cachepos = -1; + + // Move everything down + for (u16 i = cachesize - 1; i; i--) + { + cache[i] = cache[i - 1]; + } + } + + cache[0] = vert; + + u32 highest = 0; + float hiscore = 0; + + if (updatetris) + { + // Update cache positions + for (u16 i = 0; i < cachesize; i++) + { + if (cache[i] == -1) + break; + + vc[cache[i]].cachepos = i; + vc[cache[i]].score = FindVertexScore(&vc[cache[i]]); + } + + // Update triangle scores + for (u16 i = 0; i < cachesize; i++) + { + if (cache[i] == -1) + break; + + const u16 trisize = vc[cache[i]].tris.size(); + for (u16 t = 0; t < trisize; t++) + { + tcache *tri = &tc[vc[cache[i]].tris[t]]; + + tri->score = + vc[tri->ind[0]].score + + vc[tri->ind[1]].score + + vc[tri->ind[2]].score; + + if (tri->score > hiscore) + { + hiscore = tri->score; + highest = vc[cache[i]].tris[t]; + } + } + } + } + + return highest; + } + +private: + s32 cache[cachesize]; + vcache *vc; + tcache *tc; +}; + +} // end anonymous namespace + +/** +Vertex cache optimization according to the Forsyth paper: +http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html + +The function is thread-safe (read: you can optimize several meshes in different threads) + +\param mesh Source mesh for the operation. */ +IMesh* CMeshManipulator::createForsythOptimizedMesh(const IMesh *mesh) const +{ + if (!mesh) + return 0; + + SMesh *newmesh = new SMesh(); + newmesh->BoundingBox = mesh->getBoundingBox(); + + const u32 mbcount = mesh->getMeshBufferCount(); + + for (u32 b = 0; b < mbcount; ++b) + { + const IMeshBuffer *mb = mesh->getMeshBuffer(b); + + if (mb->getIndexType() != video::EIT_16BIT) + { + os::Printer::log("Cannot optimize a mesh with 32bit indices", ELL_ERROR); + newmesh->drop(); + return 0; + } + + const u32 icount = mb->getIndexCount(); + const u32 tcount = icount / 3; + const u32 vcount = mb->getVertexCount(); + const u16 *ind = mb->getIndices(); + + vcache *vc = new vcache[vcount]; + tcache *tc = new tcache[tcount]; + + f_lru lru(vc, tc); + + // init + for (u16 i = 0; i < vcount; i++) + { + vc[i].score = 0; + vc[i].cachepos = -1; + vc[i].NumActiveTris = 0; + } + + // First pass: count how many times a vert is used + for (u32 i = 0; i < icount; i += 3) + { + vc[ind[i]].NumActiveTris++; + vc[ind[i + 1]].NumActiveTris++; + vc[ind[i + 2]].NumActiveTris++; + + const u32 tri_ind = i/3; + tc[tri_ind].ind[0] = ind[i]; + tc[tri_ind].ind[1] = ind[i + 1]; + tc[tri_ind].ind[2] = ind[i + 2]; + } + + // Second pass: list of each triangle + for (u32 i = 0; i < tcount; i++) + { + vc[tc[i].ind[0]].tris.push_back(i); + vc[tc[i].ind[1]].tris.push_back(i); + vc[tc[i].ind[2]].tris.push_back(i); + + tc[i].drawn = false; + } + + // Give initial scores + for (u16 i = 0; i < vcount; i++) + { + vc[i].score = FindVertexScore(&vc[i]); + } + for (u32 i = 0; i < tcount; i++) + { + tc[i].score = + vc[tc[i].ind[0]].score + + vc[tc[i].ind[1]].score + + vc[tc[i].ind[2]].score; + } + + switch(mb->getVertexType()) + { + case video::EVT_STANDARD: + { + video::S3DVertex *v = (video::S3DVertex *) mb->getVertices(); + + SMeshBuffer *buf = new SMeshBuffer(); + buf->Material = mb->getMaterial(); + + buf->Vertices.reallocate(vcount); + buf->Indices.reallocate(icount); + + core::map sind; // search index for fast operation + typedef core::map::Node snode; + + // Main algorithm + u32 highest = 0; + u32 drawcalls = 0; + for (;;) + { + if (tc[highest].drawn) + { + bool found = false; + float hiscore = 0; + for (u32 t = 0; t < tcount; t++) + { + if (!tc[t].drawn) + { + if (tc[t].score > hiscore) + { + highest = t; + hiscore = tc[t].score; + found = true; + } + } + } + if (!found) + break; + } + + // Output the best triangle + u16 newind = buf->Vertices.size(); + + snode *s = sind.find(v[tc[highest].ind[0]]); + + if (!s) + { + buf->Vertices.push_back(v[tc[highest].ind[0]]); + buf->Indices.push_back(newind); + sind.insert(v[tc[highest].ind[0]], newind); + newind++; + } + else + { + buf->Indices.push_back(s->getValue()); + } + + s = sind.find(v[tc[highest].ind[1]]); + + if (!s) + { + buf->Vertices.push_back(v[tc[highest].ind[1]]); + buf->Indices.push_back(newind); + sind.insert(v[tc[highest].ind[1]], newind); + newind++; + } + else + { + buf->Indices.push_back(s->getValue()); + } + + s = sind.find(v[tc[highest].ind[2]]); + + if (!s) + { + buf->Vertices.push_back(v[tc[highest].ind[2]]); + buf->Indices.push_back(newind); + sind.insert(v[tc[highest].ind[2]], newind); + } + else + { + buf->Indices.push_back(s->getValue()); + } + + vc[tc[highest].ind[0]].NumActiveTris--; + vc[tc[highest].ind[1]].NumActiveTris--; + vc[tc[highest].ind[2]].NumActiveTris--; + + tc[highest].drawn = true; + + for (u16 j = 0; j < 3; j++) + { + vcache *vert = &vc[tc[highest].ind[j]]; + for (u16 t = 0; t < vert->tris.size(); t++) + { + if (highest == vert->tris[t]) + { + vert->tris.erase(t); + break; + } + } + } + + lru.add(tc[highest].ind[0]); + lru.add(tc[highest].ind[1]); + highest = lru.add(tc[highest].ind[2], true); + drawcalls++; + } + + buf->setBoundingBox(mb->getBoundingBox()); + newmesh->addMeshBuffer(buf); + buf->drop(); + } + break; + case video::EVT_2TCOORDS: + { + video::S3DVertex2TCoords *v = (video::S3DVertex2TCoords *) mb->getVertices(); + + SMeshBufferLightMap *buf = new SMeshBufferLightMap(); + buf->Material = mb->getMaterial(); + + buf->Vertices.reallocate(vcount); + buf->Indices.reallocate(icount); + + core::map sind; // search index for fast operation + typedef core::map::Node snode; + + // Main algorithm + u32 highest = 0; + u32 drawcalls = 0; + for (;;) + { + if (tc[highest].drawn) + { + bool found = false; + float hiscore = 0; + for (u32 t = 0; t < tcount; t++) + { + if (!tc[t].drawn) + { + if (tc[t].score > hiscore) + { + highest = t; + hiscore = tc[t].score; + found = true; + } + } + } + if (!found) + break; + } + + // Output the best triangle + u16 newind = buf->Vertices.size(); + + snode *s = sind.find(v[tc[highest].ind[0]]); + + if (!s) + { + buf->Vertices.push_back(v[tc[highest].ind[0]]); + buf->Indices.push_back(newind); + sind.insert(v[tc[highest].ind[0]], newind); + newind++; + } + else + { + buf->Indices.push_back(s->getValue()); + } + + s = sind.find(v[tc[highest].ind[1]]); + + if (!s) + { + buf->Vertices.push_back(v[tc[highest].ind[1]]); + buf->Indices.push_back(newind); + sind.insert(v[tc[highest].ind[1]], newind); + newind++; + } + else + { + buf->Indices.push_back(s->getValue()); + } + + s = sind.find(v[tc[highest].ind[2]]); + + if (!s) + { + buf->Vertices.push_back(v[tc[highest].ind[2]]); + buf->Indices.push_back(newind); + sind.insert(v[tc[highest].ind[2]], newind); + } + else + { + buf->Indices.push_back(s->getValue()); + } + + vc[tc[highest].ind[0]].NumActiveTris--; + vc[tc[highest].ind[1]].NumActiveTris--; + vc[tc[highest].ind[2]].NumActiveTris--; + + tc[highest].drawn = true; + + for (u16 j = 0; j < 3; j++) + { + vcache *vert = &vc[tc[highest].ind[j]]; + for (u16 t = 0; t < vert->tris.size(); t++) + { + if (highest == vert->tris[t]) + { + vert->tris.erase(t); + break; + } + } + } + + lru.add(tc[highest].ind[0]); + lru.add(tc[highest].ind[1]); + highest = lru.add(tc[highest].ind[2]); + drawcalls++; + } + + buf->setBoundingBox(mb->getBoundingBox()); + newmesh->addMeshBuffer(buf); + buf->drop(); + + } + break; + case video::EVT_TANGENTS: + { + video::S3DVertexTangents *v = (video::S3DVertexTangents *) mb->getVertices(); + + SMeshBufferTangents *buf = new SMeshBufferTangents(); + buf->Material = mb->getMaterial(); + + buf->Vertices.reallocate(vcount); + buf->Indices.reallocate(icount); + + core::map sind; // search index for fast operation + typedef core::map::Node snode; + + // Main algorithm + u32 highest = 0; + u32 drawcalls = 0; + for (;;) + { + if (tc[highest].drawn) + { + bool found = false; + float hiscore = 0; + for (u32 t = 0; t < tcount; t++) + { + if (!tc[t].drawn) + { + if (tc[t].score > hiscore) + { + highest = t; + hiscore = tc[t].score; + found = true; + } + } + } + if (!found) + break; + } + + // Output the best triangle + u16 newind = buf->Vertices.size(); + + snode *s = sind.find(v[tc[highest].ind[0]]); + + if (!s) + { + buf->Vertices.push_back(v[tc[highest].ind[0]]); + buf->Indices.push_back(newind); + sind.insert(v[tc[highest].ind[0]], newind); + newind++; + } + else + { + buf->Indices.push_back(s->getValue()); + } + + s = sind.find(v[tc[highest].ind[1]]); + + if (!s) + { + buf->Vertices.push_back(v[tc[highest].ind[1]]); + buf->Indices.push_back(newind); + sind.insert(v[tc[highest].ind[1]], newind); + newind++; + } + else + { + buf->Indices.push_back(s->getValue()); + } + + s = sind.find(v[tc[highest].ind[2]]); + + if (!s) + { + buf->Vertices.push_back(v[tc[highest].ind[2]]); + buf->Indices.push_back(newind); + sind.insert(v[tc[highest].ind[2]], newind); + } + else + { + buf->Indices.push_back(s->getValue()); + } + + vc[tc[highest].ind[0]].NumActiveTris--; + vc[tc[highest].ind[1]].NumActiveTris--; + vc[tc[highest].ind[2]].NumActiveTris--; + + tc[highest].drawn = true; + + for (u16 j = 0; j < 3; j++) + { + vcache *vert = &vc[tc[highest].ind[j]]; + for (u16 t = 0; t < vert->tris.size(); t++) + { + if (highest == vert->tris[t]) + { + vert->tris.erase(t); + break; + } + } + } + + lru.add(tc[highest].ind[0]); + lru.add(tc[highest].ind[1]); + highest = lru.add(tc[highest].ind[2]); + drawcalls++; + } + + buf->setBoundingBox(mb->getBoundingBox()); + newmesh->addMeshBuffer(buf); + buf->drop(); + } + break; + } + + delete [] vc; + delete [] tc; + + } // for each meshbuffer + + return newmesh; +} + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CMeshManipulator.h b/source/Irrlicht/CMeshManipulator.h new file mode 100644 index 00000000..c7518a67 --- /dev/null +++ b/source/Irrlicht/CMeshManipulator.h @@ -0,0 +1,101 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_MESH_MANIPULATOR_H_INCLUDED__ +#define __C_MESH_MANIPULATOR_H_INCLUDED__ + +#include "IMeshManipulator.h" + +namespace irr +{ +namespace scene +{ + +//! An interface for easy manipulation of meshes. +/** Scale, set alpha value, flip surfaces, and so on. This exists for fixing +problems with wrong imported or exported meshes quickly after loading. It is +not intended for doing mesh modifications and/or animations during runtime. +*/ +class CMeshManipulator : public IMeshManipulator +{ +public: + //! Flips the direction of surfaces. + /** Changes backfacing triangles to frontfacing triangles and vice versa. + \param mesh: Mesh on which the operation is performed. */ + virtual void flipSurfaces(scene::IMesh* mesh) const _IRR_OVERRIDE_; + + //! Recalculates all normals of the mesh. + /** \param mesh: Mesh on which the operation is performed. + \param smooth: Whether to use smoothed normals. */ + virtual void recalculateNormals(scene::IMesh* mesh, bool smooth = false, bool angleWeighted = false) const _IRR_OVERRIDE_; + + //! Recalculates all normals of the mesh buffer. + /** \param buffer: Mesh buffer on which the operation is performed. + \param smooth: Whether to use smoothed normals. */ + virtual void recalculateNormals(IMeshBuffer* buffer, bool smooth = false, bool angleWeighted = false) const _IRR_OVERRIDE_; + + //! Clones a static IMesh into a modifiable SMesh. + virtual SMesh* createMeshCopy(scene::IMesh* mesh) const _IRR_OVERRIDE_; + + //! Creates a planar texture mapping on the mesh + /** \param mesh: Mesh on which the operation is performed. + \param resolution: resolution of the planar mapping. This is the value + specifying which is the relation between world space and + texture coordinate space. */ + virtual void makePlanarTextureMapping(scene::IMesh* mesh, f32 resolution=0.001f) const _IRR_OVERRIDE_; + + //! Creates a planar texture mapping on the meshbuffer + virtual void makePlanarTextureMapping(scene::IMeshBuffer* meshbuffer, f32 resolution=0.001f) const _IRR_OVERRIDE_; + + //! Creates a planar texture mapping on the meshbuffer + void makePlanarTextureMapping(scene::IMeshBuffer* buffer, f32 resolutionS, f32 resolutionT, u8 axis, const core::vector3df& offset) const _IRR_OVERRIDE_; + + //! Creates a planar texture mapping on the mesh + void makePlanarTextureMapping(scene::IMesh* mesh, f32 resolutionS, f32 resolutionT, u8 axis, const core::vector3df& offset) const _IRR_OVERRIDE_; + + //! Recalculates tangents, requires a tangent mesh buffer + virtual void recalculateTangents(IMeshBuffer* buffer, bool recalculateNormals=false, bool smooth=false, bool angleWeighted=false) const _IRR_OVERRIDE_; + + //! Recalculates tangents, requires a tangent mesh + virtual void recalculateTangents(IMesh* mesh, bool recalculateNormals=false, bool smooth=false, bool angleWeighted=false) const _IRR_OVERRIDE_; + + //! Creates a copy of the mesh, which will only consist of S3DVertexTangents vertices. + virtual IMesh* createMeshWithTangents(IMesh* mesh, bool recalculateNormals=false, bool smooth=false, bool angleWeighted=false, bool recalculateTangents=true) const _IRR_OVERRIDE_; + + //! Creates a copy of the mesh, which will only consist of S3D2TCoords vertices. + virtual IMesh* createMeshWith2TCoords(IMesh* mesh) const _IRR_OVERRIDE_; + + //! Creates a copy of the mesh, which will only consist of S3DVertex vertices. + virtual IMesh* createMeshWith1TCoords(IMesh* mesh) const _IRR_OVERRIDE_; + + //! Creates a copy of the mesh, which will only consist of unique triangles, i.e. no vertices are shared. + virtual IMesh* createMeshUniquePrimitives(IMesh* mesh) const _IRR_OVERRIDE_; + + //! Creates a copy of the mesh, which will have all duplicated vertices removed, i.e. maximal amount of vertices are shared via indexing. + virtual IMesh* createMeshWelded(IMesh *mesh, f32 tolerance=core::ROUNDING_ERROR_f32) const _IRR_OVERRIDE_; + + //! Returns amount of polygons in mesh. + virtual s32 getPolyCount(scene::IMesh* mesh) const _IRR_OVERRIDE_; + + //! Returns amount of polygons in mesh. + virtual s32 getPolyCount(scene::IAnimatedMesh* mesh) const _IRR_OVERRIDE_; + + //! create a new AnimatedMesh and adds the mesh to it + virtual IAnimatedMesh * createAnimatedMesh(scene::IMesh* mesh,scene::E_ANIMATED_MESH_TYPE type) const _IRR_OVERRIDE_; + + //! create a mesh optimized for the vertex cache + virtual IMesh* createForsythOptimizedMesh(const scene::IMesh *mesh) const _IRR_OVERRIDE_; + + //! Optimizes the mesh using an algorithm tuned for heightmaps + virtual void heightmapOptimizeMesh(IMesh * const m, const f32 tolerance = core::ROUNDING_ERROR_f32) const _IRR_OVERRIDE_; + + //! Optimizes the mesh using an algorithm tuned for heightmaps + virtual void heightmapOptimizeMesh(IMeshBuffer * const m, const f32 tolerance = core::ROUNDING_ERROR_f32) const _IRR_OVERRIDE_; +}; + +} // end namespace scene +} // end namespace irr + + +#endif diff --git a/source/Irrlicht/CMeshSceneNode.cpp b/source/Irrlicht/CMeshSceneNode.cpp new file mode 100644 index 00000000..59d1c1cd --- /dev/null +++ b/source/Irrlicht/CMeshSceneNode.cpp @@ -0,0 +1,429 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CMeshSceneNode.h" +#include "IVideoDriver.h" +#include "ISceneManager.h" +#include "S3DVertex.h" +#include "ICameraSceneNode.h" +#include "IMeshCache.h" +#include "IAnimatedMesh.h" +#include "IMaterialRenderer.h" +#include "IFileSystem.h" +#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ +#include "CShadowVolumeSceneNode.h" +#else +#include "IShadowVolumeSceneNode.h" +#endif // _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ + +namespace irr +{ +namespace scene +{ + + + +//! constructor +CMeshSceneNode::CMeshSceneNode(IMesh* mesh, ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position, const core::vector3df& rotation, + const core::vector3df& scale) +: IMeshSceneNode(parent, mgr, id, position, rotation, scale), Mesh(0), Shadow(0), + PassCount(0), ReadOnlyMaterials(false) +{ + #ifdef _DEBUG + setDebugName("CMeshSceneNode"); + #endif + + setMesh(mesh); +} + + +//! destructor +CMeshSceneNode::~CMeshSceneNode() +{ + if (Shadow) + Shadow->drop(); + if (Mesh) + Mesh->drop(); +} + + +//! frame +void CMeshSceneNode::OnRegisterSceneNode() +{ + if (IsVisible && Mesh) + { + // because this node supports rendering of mixed mode meshes consisting of + // transparent and solid material at the same time, we need to go through all + // materials, check of what type they are and register this node for the right + // render pass according to that. + + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + + PassCount = 0; + int transparentCount = 0; + int solidCount = 0; + + // count transparent and solid materials in this scene node + const u32 numMaterials = ReadOnlyMaterials ? Mesh->getMeshBufferCount() : Materials.size(); + for (u32 i=0; igetMeshBuffer(i)->getMaterial() : Materials[i]; + + if ( driver->needsTransparentRenderPass(material) ) + ++transparentCount; + else + ++solidCount; + + if (solidCount && transparentCount) + break; + } + + // register according to material types counted + + if (solidCount) + SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID); + + if (transparentCount) + SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT); + + ISceneNode::OnRegisterSceneNode(); + } +} + + +//! renders the node. +void CMeshSceneNode::render() +{ + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + + if (!Mesh || !driver) + return; + + const bool isTransparentPass = + SceneManager->getSceneNodeRenderPass() == scene::ESNRP_TRANSPARENT; + + ++PassCount; + + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + Box = Mesh->getBoundingBox(); + + if (Shadow && PassCount==1) + Shadow->updateShadowVolumes(); + + // for debug purposes only: + + bool renderMeshes = true; + video::SMaterial mat; + if (DebugDataVisible && PassCount==1) + { + // overwrite half transparency + if (DebugDataVisible & scene::EDS_HALF_TRANSPARENCY) + { + for (u32 g=0; ggetMeshBufferCount(); ++g) + { + mat = Materials[g]; + mat.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR; + driver->setMaterial(mat); + driver->drawMeshBuffer(Mesh->getMeshBuffer(g)); + } + renderMeshes = false; + } + } + + // render original meshes + if (renderMeshes) + { + for (u32 i=0; igetMeshBufferCount(); ++i) + { + scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i); + if (mb) + { + const video::SMaterial& material = ReadOnlyMaterials ? mb->getMaterial() : Materials[i]; + + const bool transparent = driver->needsTransparentRenderPass(material); + + // only render transparent buffer if this is the transparent render pass + // and solid only in solid pass + if (transparent == isTransparentPass) + { + driver->setMaterial(material); + driver->drawMeshBuffer(mb); + } + } + } + } + + // for debug purposes only: + if (DebugDataVisible && PassCount==1) + { + video::SMaterial m; + m.Lighting = false; + m.AntiAliasing=0; + driver->setMaterial(m); + + if (DebugDataVisible & scene::EDS_BBOX) + { + driver->draw3DBox(Box, video::SColor(255,255,255,255)); + } + if (DebugDataVisible & scene::EDS_BBOX_BUFFERS) + { + for (u32 g=0; ggetMeshBufferCount(); ++g) + { + driver->draw3DBox( + Mesh->getMeshBuffer(g)->getBoundingBox(), + video::SColor(255,190,128,128)); + } + } + + if (DebugDataVisible & scene::EDS_NORMALS) + { + // draw normals + const f32 debugNormalLength = SceneManager->getParameters()->getAttributeAsFloat(DEBUG_NORMAL_LENGTH); + const video::SColor debugNormalColor = SceneManager->getParameters()->getAttributeAsColor(DEBUG_NORMAL_COLOR); + const u32 count = Mesh->getMeshBufferCount(); + + for (u32 i=0; i != count; ++i) + { + driver->drawMeshBufferNormals(Mesh->getMeshBuffer(i), debugNormalLength, debugNormalColor); + } + } + + // show mesh + if (DebugDataVisible & scene::EDS_MESH_WIRE_OVERLAY) + { + m.Wireframe = true; + driver->setMaterial(m); + + for (u32 g=0; ggetMeshBufferCount(); ++g) + { + driver->drawMeshBuffer(Mesh->getMeshBuffer(g)); + } + } + } +} + + +//! Removes a child from this scene node. +//! Implemented here, to be able to remove the shadow properly, if there is one, +//! or to remove attached childs. +bool CMeshSceneNode::removeChild(ISceneNode* child) +{ + if (child && Shadow == child) + { + Shadow->drop(); + Shadow = 0; + } + + return ISceneNode::removeChild(child); +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CMeshSceneNode::getBoundingBox() const +{ + return Mesh ? Mesh->getBoundingBox() : Box; +} + + +//! returns the material based on the zero based index i. To get the amount +//! of materials used by this scene node, use getMaterialCount(). +//! This function is needed for inserting the node into the scene hierarchy on a +//! optimal position for minimizing renderstate changes, but can also be used +//! to directly modify the material of a scene node. +video::SMaterial& CMeshSceneNode::getMaterial(u32 i) +{ + if (Mesh && ReadOnlyMaterials && igetMeshBufferCount()) + { + ReadOnlyMaterial = Mesh->getMeshBuffer(i)->getMaterial(); + return ReadOnlyMaterial; + } + + if (i >= Materials.size()) + return ISceneNode::getMaterial(i); + + return Materials[i]; +} + + +//! returns amount of materials used by this scene node. +u32 CMeshSceneNode::getMaterialCount() const +{ + if (Mesh && ReadOnlyMaterials) + return Mesh->getMeshBufferCount(); + + return Materials.size(); +} + + +//! Sets a new mesh +void CMeshSceneNode::setMesh(IMesh* mesh) +{ + if (mesh) + { + mesh->grab(); + if (Mesh) + Mesh->drop(); + + Mesh = mesh; + copyMaterials(); + } +} + + +//! Creates shadow volume scene node as child of this node +//! and returns a pointer to it. +IShadowVolumeSceneNode* CMeshSceneNode::addShadowVolumeSceneNode( + const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity) +{ +#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ + if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER)) + return 0; + + if (!shadowMesh) + shadowMesh = Mesh; // if null is given, use the mesh of node + + if (Shadow) + Shadow->drop(); + + Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity); + return Shadow; +#else + return 0; +#endif +} + + +void CMeshSceneNode::copyMaterials() +{ + Materials.clear(); + + if (Mesh) + { + video::SMaterial mat; + + for (u32 i=0; igetMeshBufferCount(); ++i) + { + IMeshBuffer* mb = Mesh->getMeshBuffer(i); + if (mb) + mat = mb->getMaterial(); + + Materials.push_back(mat); + } + } +} + + +//! Writes attributes of the scene node. +void CMeshSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + IMeshSceneNode::serializeAttributes(out, options); + + if (options && (options->Flags&io::EARWF_USE_RELATIVE_PATHS) && options->Filename) + { + const io::path path = SceneManager->getFileSystem()->getRelativeFilename( + SceneManager->getFileSystem()->getAbsolutePath(SceneManager->getMeshCache()->getMeshName(Mesh).getPath()), + options->Filename); + out->addString("Mesh", path.c_str()); + } + else + out->addString("Mesh", SceneManager->getMeshCache()->getMeshName(Mesh).getPath().c_str()); + out->addBool("ReadOnlyMaterials", ReadOnlyMaterials); +} + + +//! Reads attributes of the scene node. +void CMeshSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + io::path oldMeshStr = SceneManager->getMeshCache()->getMeshName(Mesh); + io::path newMeshStr = in->getAttributeAsString("Mesh"); + ReadOnlyMaterials = in->getAttributeAsBool("ReadOnlyMaterials"); + + if (newMeshStr != "" && oldMeshStr != newMeshStr) + { + IMesh* newMesh = 0; + IAnimatedMesh* newAnimatedMesh = SceneManager->getMesh(newMeshStr.c_str()); + + if (newAnimatedMesh) + newMesh = newAnimatedMesh->getMesh(0); + + if (newMesh) + setMesh(newMesh); + } + + // optional attribute to assign the hint to the whole mesh + if (in->existsAttribute("HardwareMappingHint") && + in->existsAttribute("HardwareMappingBufferType")) + { + scene::E_HARDWARE_MAPPING mapping = scene::EHM_NEVER; + scene::E_BUFFER_TYPE bufferType = scene::EBT_NONE; + + core::stringc smapping = in->getAttributeAsString("HardwareMappingHint"); + if (smapping.equals_ignore_case("static")) + mapping = scene::EHM_STATIC; + else if (smapping.equals_ignore_case("dynamic")) + mapping = scene::EHM_DYNAMIC; + else if (smapping.equals_ignore_case("stream")) + mapping = scene::EHM_STREAM; + + core::stringc sbufferType = in->getAttributeAsString("HardwareMappingBufferType"); + if (sbufferType.equals_ignore_case("vertex")) + bufferType = scene::EBT_VERTEX; + else if (sbufferType.equals_ignore_case("index")) + bufferType = scene::EBT_INDEX; + else if (sbufferType.equals_ignore_case("vertexindex")) + bufferType = scene::EBT_VERTEX_AND_INDEX; + + IMesh* mesh = getMesh(); + if (mesh) + mesh->setHardwareMappingHint(mapping, bufferType); + } + + IMeshSceneNode::deserializeAttributes(in, options); +} + + +//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style. +/* In this way it is possible to change the materials a mesh causing all mesh scene nodes +referencing this mesh to change too. */ +void CMeshSceneNode::setReadOnlyMaterials(bool readonly) +{ + ReadOnlyMaterials = readonly; +} + + +//! Returns if the scene node should not copy the materials of the mesh but use them in a read only style +bool CMeshSceneNode::isReadOnlyMaterials() const +{ + return ReadOnlyMaterials; +} + + +//! Creates a clone of this scene node and its children. +ISceneNode* CMeshSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager) +{ + if (!newParent) + newParent = Parent; + if (!newManager) + newManager = SceneManager; + + CMeshSceneNode* nb = new CMeshSceneNode(Mesh, newParent, + newManager, ID, RelativeTranslation, RelativeRotation, RelativeScale); + + nb->cloneMembers(this, newManager); + nb->ReadOnlyMaterials = ReadOnlyMaterials; + nb->Materials = Materials; + nb->Shadow = Shadow; + if ( nb->Shadow ) + nb->Shadow->grab(); + + if (newParent) + nb->drop(); + return nb; +} + + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CMeshSceneNode.h b/source/Irrlicht/CMeshSceneNode.h new file mode 100644 index 00000000..b7b10be3 --- /dev/null +++ b/source/Irrlicht/CMeshSceneNode.h @@ -0,0 +1,103 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_MESH_SCENE_NODE_H_INCLUDED__ +#define __C_MESH_SCENE_NODE_H_INCLUDED__ + +#include "IMeshSceneNode.h" +#include "IMesh.h" + +namespace irr +{ +namespace scene +{ + + class CMeshSceneNode : public IMeshSceneNode + { + public: + + //! constructor + CMeshSceneNode(IMesh* mesh, ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)); + + //! destructor + virtual ~CMeshSceneNode(); + + //! frame + virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; + + //! renders the node. + virtual void render() _IRR_OVERRIDE_; + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + //! returns the material based on the zero based index i. To get the amount + //! of materials used by this scene node, use getMaterialCount(). + //! This function is needed for inserting the node into the scene hierarchy on a + //! optimal position for minimizing renderstate changes, but can also be used + //! to directly modify the material of a scene node. + virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_; + + //! returns amount of materials used by this scene node. + virtual u32 getMaterialCount() const _IRR_OVERRIDE_; + + //! Writes attributes of the scene node. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_MESH; } + + //! Sets a new mesh + virtual void setMesh(IMesh* mesh) _IRR_OVERRIDE_; + + //! Returns the current mesh + virtual IMesh* getMesh(void) _IRR_OVERRIDE_ { return Mesh; } + + //! Creates shadow volume scene node as child of this node + //! and returns a pointer to it. + virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh, + s32 id, bool zfailmethod=true, f32 infinity=10000.0f) _IRR_OVERRIDE_; + + //! Sets if the scene node should not copy the materials of the mesh but use them in a read only style. + /* In this way it is possible to change the materials a mesh causing all mesh scene nodes + referencing this mesh to change too. */ + virtual void setReadOnlyMaterials(bool readonly) _IRR_OVERRIDE_; + + //! Returns if the scene node should not copy the materials of the mesh but use them in a read only style + virtual bool isReadOnlyMaterials() const _IRR_OVERRIDE_; + + //! Creates a clone of this scene node and its children. + virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + //! Removes a child from this scene node. + //! Implemented here, to be able to remove the shadow properly, if there is one, + //! or to remove attached child. + virtual bool removeChild(ISceneNode* child) _IRR_OVERRIDE_; + + protected: + + void copyMaterials(); + + core::array Materials; + core::aabbox3d Box; + video::SMaterial ReadOnlyMaterial; + + IMesh* Mesh; + IShadowVolumeSceneNode* Shadow; + + s32 PassCount; + bool ReadOnlyMaterials; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CMeshTextureLoader.cpp b/source/Irrlicht/CMeshTextureLoader.cpp new file mode 100644 index 00000000..08f4678a --- /dev/null +++ b/source/Irrlicht/CMeshTextureLoader.cpp @@ -0,0 +1,130 @@ +#include "CMeshTextureLoader.h" +#include "IFileSystem.h" +#include "IVideoDriver.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + +CMeshTextureLoader::CMeshTextureLoader(irr::io::IFileSystem* fs, irr::video::IVideoDriver* driver) +: FileSystem(fs) +, VideoDriver(driver) +, MeshFile(0) +, MaterialFile(0) +{ +} + +//! Set a custom texture path. +void CMeshTextureLoader::setTexturePath(const irr::io::path& path) +{ + TexturePath = path; + preparePath(TexturePath); +} + +//! Get the current custom texture path. +const irr::io::path& CMeshTextureLoader::getTexturePath() const +{ + return TexturePath; +} + +bool CMeshTextureLoader::checkTextureName( const irr::io::path& filename) +{ + //os::Printer::log("CheckTextureName:", core::stringc(filename).c_str(), ELL_DEBUG); + if (FileSystem->existFile(filename)) + { + //os::Printer::log("file exists", ELL_DEBUG); + TextureName = filename; + return true; + } + + return false; +} + +//! Get the texture by searching for it in all paths that makes sense for the given textureName. +irr::video::ITexture* CMeshTextureLoader::getTexture(const irr::io::path& textureName) +{ + if ( textureName.empty() || !FileSystem || !VideoDriver) + return NULL; + + // Pre-process texture filename. + irr::io::path simplifiedTexName(textureName); + simplifiedTexName.replace(_IRR_TEXT('\\'),_IRR_TEXT('/')); + + // user defined texture path + if ( !TexturePath.empty() ) + { + if ( checkTextureName(TexturePath + simplifiedTexName) ) + return VideoDriver->getTexture(TextureName); + + if ( checkTextureName(TexturePath + FileSystem->getFileBasename(simplifiedTexName)) ) + return VideoDriver->getTexture(TextureName); + } + + // just the name itself + if ( checkTextureName(simplifiedTexName) ) + return VideoDriver->getTexture(TextureName); + + // look in files relative to the folder of the meshfile + if ( MeshFile ) + { + if ( MeshPath.empty() ) + { + MeshPath = FileSystem->getFileDir(MeshFile->getFileName()); + preparePath(MeshPath); + } + if ( !MeshPath.empty() ) + { + if ( checkTextureName(MeshPath + simplifiedTexName) ) + return VideoDriver->getTexture(TextureName); + + if ( checkTextureName(MeshPath + FileSystem->getFileBasename(simplifiedTexName)) ) + return VideoDriver->getTexture(TextureName); + } + } + + // look in files relative to the folder of the materialfile + if ( MaterialFile ) + { + if ( MaterialPath.empty() ) + { + MaterialPath = FileSystem->getFileDir(MaterialFile->getFileName()); + preparePath(MaterialPath); + } + if ( !MaterialPath.empty() ) + { + if ( checkTextureName(MaterialPath + simplifiedTexName) ) + return VideoDriver->getTexture(TextureName); + + if ( checkTextureName(MaterialPath + FileSystem->getFileBasename(simplifiedTexName)) ) + return VideoDriver->getTexture(TextureName); + } + } + + // check current working directory + if ( checkTextureName(FileSystem->getFileBasename(simplifiedTexName)) ) + return VideoDriver->getTexture(TextureName); + + TextureName = _IRR_TEXT(""); + return NULL; +} + +//! Meshloaders will search paths relative to the meshFile. +void CMeshTextureLoader::setMeshFile(const irr::io::IReadFile* meshFile) +{ + // no grab (would need a weak_ptr) + MeshFile = meshFile; + MeshPath = _IRR_TEXT(""); // do a lazy evaluation later +} + +//! Meshloaders will try to look relative to the path of the materialFile +void CMeshTextureLoader::setMaterialFile(const irr::io::IReadFile* materialFile) +{ + // no grab (would need a weak_ptr) + MaterialFile = materialFile; + MaterialPath = _IRR_TEXT(""); // do a lazy evaluation later +} + +} // end namespace scnene +} // end namespace irr diff --git a/source/Irrlicht/CMeshTextureLoader.h b/source/Irrlicht/CMeshTextureLoader.h new file mode 100644 index 00000000..dac4929e --- /dev/null +++ b/source/Irrlicht/CMeshTextureLoader.h @@ -0,0 +1,81 @@ +#ifndef IRR_C_MESH_TEXTURE_LOADER_H_INCLUDED +#define IRR_C_MESH_TEXTURE_LOADER_H_INCLUDED + +#include "IMeshTextureLoader.h" + +namespace irr +{ +namespace io +{ + class IFileSystem; +} // end namespace io +namespace video +{ + class IVideoDriver; +} + +namespace scene +{ + +class CMeshTextureLoader : public IMeshTextureLoader +{ +public: + CMeshTextureLoader(irr::io::IFileSystem* fs, irr::video::IVideoDriver* driver); + + //! Set a custom texture path. + /** This is the first path the texture-loader should search. */ + virtual void setTexturePath(const irr::io::path& path) _IRR_OVERRIDE_; + + //! Get the current custom texture path. + virtual const irr::io::path& getTexturePath() const _IRR_OVERRIDE_; + + //! Get the texture by searching for it in all paths that makes sense for the given textureName. + /** Usually you do not have to use this method, it is used internally by IMeshLoader's. + \param textureName Texturename as used in the mesh-format + \return Pointer to the texture. Returns 0 if loading failed.*/ + virtual irr::video::ITexture* getTexture(const irr::io::path& textureName) _IRR_OVERRIDE_; + + //! Meshloaders will search paths relative to the meshFile. + /** Usually you do not have to use this method, it is used internally by IMeshLoader's. + Any values you set here will likely be overwritten internally. */ + virtual void setMeshFile(const irr::io::IReadFile* meshFile) _IRR_OVERRIDE_; + + //! Meshloaders will try to look relative to the path of the materialFile + /** Usually you do not have to use this method, it is used internally by IMeshLoader's. + Any values you set here will likely be overwritten internally. */ + virtual void setMaterialFile(const irr::io::IReadFile* materialFile) _IRR_OVERRIDE_; + +protected: + // make certain path's have a certain internal format + void preparePath(irr::io::path& directory) + { + if (!directory.empty()) + { + if (directory == _IRR_TEXT(".")) + directory = _IRR_TEXT(""); + + directory.replace(_IRR_TEXT('\\'),_IRR_TEXT('/')); + if (directory.lastChar() != _IRR_TEXT('/')) + directory.append(_IRR_TEXT('/')); + } + } + + // Save the texturename when it's a an existing file + bool checkTextureName( const irr::io::path& filename); + +private: + irr::io::IFileSystem * FileSystem; + irr::video::IVideoDriver* VideoDriver; + irr::io::path TexturePath; + const irr::io::IReadFile* MeshFile; + irr::io::path MeshPath; + const irr::io::IReadFile* MaterialFile; + irr::io::path MaterialPath; + irr::io::path TextureName; +}; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CMetaTriangleSelector.cpp b/source/Irrlicht/CMetaTriangleSelector.cpp new file mode 100644 index 00000000..9675268b --- /dev/null +++ b/source/Irrlicht/CMetaTriangleSelector.cpp @@ -0,0 +1,225 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CMetaTriangleSelector.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CMetaTriangleSelector::CMetaTriangleSelector() +{ + #ifdef _DEBUG + setDebugName("CMetaTriangleSelector"); + #endif +} + + +//! destructor +CMetaTriangleSelector::~CMetaTriangleSelector() +{ + removeAllTriangleSelectors(); +} + + +//! Returns amount of all available triangles in this selector +s32 CMetaTriangleSelector::getTriangleCount() const +{ + s32 count = 0; + for (u32 i=0; igetTriangleCount(); + + return count; +} + + +//! Gets all triangles. +void CMetaTriangleSelector::getTriangles(core::triangle3df* triangles, s32 arraySize, + s32& outTriangleCount, const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const +{ + s32 outWritten = 0; + irr::u32 outTriangleInfoSize = outTriangleInfo ? outTriangleInfo->size() : 0; + for (u32 i=0; igetTriangles(triangles + outWritten, + arraySize - outWritten, t, transform, useNodeTransform, outTriangleInfo); + + if ( outTriangleInfo ) + { + irr::u32 newTriangleInfoSize = outTriangleInfo->size(); + for ( u32 ti=outTriangleInfoSize; ti& box, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const +{ + s32 outWritten = 0; + irr::u32 outTriangleInfoSize = outTriangleInfo ? outTriangleInfo->size() : 0; + for (u32 i=0; igetTriangles(triangles + outWritten, + arraySize - outWritten, t, box, transform, useNodeTransform, outTriangleInfo); + + if ( outTriangleInfo ) + { + irr::u32 newTriangleInfoSize = outTriangleInfo->size(); + for ( u32 ti=outTriangleInfoSize; ti& line, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const +{ + s32 outWritten = 0; + irr::u32 outTriangleInfoSize = outTriangleInfo ? outTriangleInfo->size() : 0; + for (u32 i=0; igetTriangles(triangles + outWritten, + arraySize - outWritten, t, line, transform, useNodeTransform, outTriangleInfo); + + if ( outTriangleInfo ) + { + irr::u32 newTriangleInfoSize = outTriangleInfo->size(); + for ( u32 ti=outTriangleInfoSize; tigrab(); +} + + +//! Removes a specific triangle selector which was added before from the collection. +bool CMetaTriangleSelector::removeTriangleSelector(ITriangleSelector* toRemove) +{ + for (u32 i=0; idrop(); + TriangleSelectors.erase(i); + return true; + } + } + + return false; +} + + +//! Removes all triangle selectors from the collection. +void CMetaTriangleSelector::removeAllTriangleSelectors() +{ + for (u32 i=0; idrop(); + + TriangleSelectors.clear(); +} + + +//! Return the scene node associated with a given triangle. +ISceneNode* CMetaTriangleSelector::getSceneNodeForTriangle(u32 triangleIndex) const +{ + u32 totalTriangles = 0; + + for (u32 i=0; igetTriangleCount(); + + if(totalTriangles > triangleIndex) + return TriangleSelectors[i]->getSceneNodeForTriangle(0); + } + + return 0; +} + +/* Return the number of TriangleSelectors that are inside this one, +Only useful for MetaTriangleSelector others return 1 +*/ +u32 CMetaTriangleSelector::getSelectorCount() const +{ + return TriangleSelectors.size(); +} + + +/* Returns the TriangleSelector based on index based on getSelectorCount +Only useful for MetaTriangleSelector others return 'this' +*/ +ITriangleSelector* CMetaTriangleSelector::getSelector(u32 index) +{ + if (index >= TriangleSelectors.size()) + return 0; + return TriangleSelectors[index]; +} + + +/* Returns the TriangleSelector based on index based on getSelectorCount +Only useful for MetaTriangleSelector others return 'this' +*/ +const ITriangleSelector* CMetaTriangleSelector::getSelector(u32 index) const +{ + if (index >= TriangleSelectors.size()) + return 0; + return TriangleSelectors[index]; +} + + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CMetaTriangleSelector.h b/source/Irrlicht/CMetaTriangleSelector.h new file mode 100644 index 00000000..b5202621 --- /dev/null +++ b/source/Irrlicht/CMetaTriangleSelector.h @@ -0,0 +1,79 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_META_TRIANGLE_SELECTOR_H_INCLUDED__ +#define __C_META_TRIANGLE_SELECTOR_H_INCLUDED__ + +#include "IMetaTriangleSelector.h" +#include "irrArray.h" + +namespace irr +{ +namespace scene +{ + +//! Interface for making multiple triangle selectors work as one big selector. +class CMetaTriangleSelector : public IMetaTriangleSelector +{ +public: + + //! constructor + CMetaTriangleSelector(); + + //! destructor + virtual ~CMetaTriangleSelector(); + + //! Get amount of all available triangles in this selector + virtual s32 getTriangleCount() const _IRR_OVERRIDE_; + + //! Gets all triangles. + virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, + s32& outTriangleCount, const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; + + //! Gets all triangles which lie within a specific bounding box. + virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, + s32& outTriangleCount, const core::aabbox3d& box, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; + + //! Gets all triangles which have or may have contact with a 3d line. + virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, + s32& outTriangleCount, const core::line3d& line, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; + + //! Adds a triangle selector to the collection of triangle selectors + //! in this metaTriangleSelector. + virtual void addTriangleSelector(ITriangleSelector* toAdd) _IRR_OVERRIDE_; + + //! Removes a specific triangle selector which was added before from the collection. + virtual bool removeTriangleSelector(ITriangleSelector* toRemove) _IRR_OVERRIDE_; + + //! Removes all triangle selectors from the collection. + virtual void removeAllTriangleSelectors() _IRR_OVERRIDE_; + + //! Get the scene node associated with a given triangle. + virtual ISceneNode* getSceneNodeForTriangle(u32 triangleIndex) const _IRR_OVERRIDE_; + + // Get the number of TriangleSelectors that are part of this one + virtual u32 getSelectorCount() const _IRR_OVERRIDE_; + + // Get the TriangleSelector based on index based on getSelectorCount + virtual ITriangleSelector* getSelector(u32 index) _IRR_OVERRIDE_; + + // Get the TriangleSelector based on index based on getSelectorCount + virtual const ITriangleSelector* getSelector(u32 index) const _IRR_OVERRIDE_; + +private: + + core::array TriangleSelectors; +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/source/Irrlicht/CMountPointReader.cpp b/source/Irrlicht/CMountPointReader.cpp new file mode 100644 index 00000000..1f5049db --- /dev/null +++ b/source/Irrlicht/CMountPointReader.cpp @@ -0,0 +1,175 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CMountPointReader.h" + +#ifdef __IRR_COMPILE_WITH_MOUNT_ARCHIVE_LOADER_ + +#include "CReadFile.h" +#include "os.h" + +namespace irr +{ +namespace io +{ + +//! Constructor +CArchiveLoaderMount::CArchiveLoaderMount( io::IFileSystem* fs) +: FileSystem(fs) +{ + #ifdef _DEBUG + setDebugName("CArchiveLoaderMount"); + #endif +} + + +//! returns true if the file maybe is able to be loaded by this class +bool CArchiveLoaderMount::isALoadableFileFormat(const io::path& filename) const +{ + io::path fname(filename); + deletePathFromFilename(fname); + + if (!fname.size()) + return true; + IFileList* list = FileSystem->createFileList(); + bool ret = false; + if (list) + { + // check if name is found as directory + if (list->findFile(filename, true)) + ret=true; + list->drop(); + } + return ret; +} + +//! Check to see if the loader can create archives of this type. +bool CArchiveLoaderMount::isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const +{ + return fileType == EFAT_FOLDER; +} + +//! Check if the file might be loaded by this class +bool CArchiveLoaderMount::isALoadableFileFormat(io::IReadFile* file) const +{ + return false; +} + +//! Creates an archive from the filename +IFileArchive* CArchiveLoaderMount::createArchive(const io::path& filename, bool ignoreCase, bool ignorePaths) const +{ + IFileArchive *archive = 0; + + EFileSystemType current = FileSystem->setFileListSystem(FILESYSTEM_NATIVE); + + const io::path save = FileSystem->getWorkingDirectory(); + io::path fullPath = FileSystem->getAbsolutePath(filename); + FileSystem->flattenFilename(fullPath); + + if (FileSystem->changeWorkingDirectoryTo(fullPath)) + { + archive = new CMountPointReader(FileSystem, fullPath, ignoreCase, ignorePaths); + } + + FileSystem->changeWorkingDirectoryTo(save); + FileSystem->setFileListSystem(current); + + return archive; +} + +//! creates/loads an archive from the file. +//! \return Pointer to the created archive. Returns 0 if loading failed. +IFileArchive* CArchiveLoaderMount::createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const +{ + return 0; +} + +//! compatible Folder Architecture +CMountPointReader::CMountPointReader(IFileSystem * parent, const io::path& basename, bool ignoreCase, bool ignorePaths) + : CFileList(basename, ignoreCase, ignorePaths), Parent(parent) +{ + //! ensure CFileList path ends in a slash + if (Path.lastChar() != '/' ) + Path.append('/'); + + const io::path& work = Parent->getWorkingDirectory(); + + Parent->changeWorkingDirectoryTo(basename); + buildDirectory(); + Parent->changeWorkingDirectoryTo(work); + + sort(); +} + + +//! returns the list of files +const IFileList* CMountPointReader::getFileList() const +{ + return this; +} + +void CMountPointReader::buildDirectory() +{ + IFileList * list = Parent->createFileList(); + if (!list) + return; + + const u32 size = list->getFileCount(); + for (u32 i=0; i < size; ++i) + { + io::path full = list->getFullFileName(i); + full = full.subString(Path.size(), full.size() - Path.size()); + + if (!list->isDirectory(i)) + { + addItem(full, list->getFileOffset(i), list->getFileSize(i), false, RealFileNames.size()); + RealFileNames.push_back(list->getFullFileName(i)); + } + else + { + const io::path rel = list->getFileName(i); + RealFileNames.push_back(list->getFullFileName(i)); + + io::path pwd = Parent->getWorkingDirectory(); + if (pwd.lastChar() != '/') + pwd.append('/'); + pwd.append(rel); + + if ( rel != "." && rel != ".." ) + { + addItem(full, 0, 0, true, 0); + Parent->changeWorkingDirectoryTo(pwd); + buildDirectory(); + Parent->changeWorkingDirectoryTo(".."); + } + } + } + + list->drop(); +} + +//! opens a file by index +IReadFile* CMountPointReader::createAndOpenFile(u32 index) +{ + if (index >= Files.size()) + return 0; + + return CReadFile::createReadFile(RealFileNames[Files[index].ID]); +} + +//! opens a file by file name +IReadFile* CMountPointReader::createAndOpenFile(const io::path& filename) +{ + s32 index = findFile(filename, false); + if (index != -1) + return createAndOpenFile(index); + else + return 0; +} + + +} // io +} // irr + +#endif // __IRR_COMPILE_WITH_MOUNT_ARCHIVE_LOADER_ diff --git a/source/Irrlicht/CMountPointReader.h b/source/Irrlicht/CMountPointReader.h new file mode 100644 index 00000000..24f49720 --- /dev/null +++ b/source/Irrlicht/CMountPointReader.h @@ -0,0 +1,92 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_MOUNT_READER_H_INCLUDED__ +#define __C_MOUNT_READER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef __IRR_COMPILE_WITH_MOUNT_ARCHIVE_LOADER_ + +#include "IFileSystem.h" +#include "CFileList.h" + +namespace irr +{ +namespace io +{ + + //! Archiveloader capable of loading MountPoint Archives + class CArchiveLoaderMount : public IArchiveLoader + { + public: + + //! Constructor + CArchiveLoaderMount(io::IFileSystem* fs); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".zip") + virtual bool isALoadableFileFormat(const io::path& filename) const _IRR_OVERRIDE_; + + //! Check if the file might be loaded by this class + /** Check might look into the file. + \param file File handle to check. + \return True if file seems to be loadable. */ + virtual bool isALoadableFileFormat(io::IReadFile* file) const _IRR_OVERRIDE_; + + //! Check to see if the loader can create archives of this type. + /** Check based on the archive type. + \param fileType The archive type to check. + \return True if the archile loader supports this type, false if not */ + virtual bool isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const _IRR_OVERRIDE_; + + //! Creates an archive from the filename + /** \param file File handle to check. + \return Pointer to newly created archive, or 0 upon error. */ + virtual IFileArchive* createArchive(const io::path& filename, bool ignoreCase, bool ignorePaths) const _IRR_OVERRIDE_; + + //! creates/loads an archive from the file. + //! \return Pointer to the created archive. Returns 0 if loading failed. + virtual IFileArchive* createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const _IRR_OVERRIDE_; + + private: + io::IFileSystem* FileSystem; + }; + + //! A File Archive which uses a mountpoint + class CMountPointReader : public virtual IFileArchive, virtual CFileList + { + public: + + //! Constructor + CMountPointReader(IFileSystem *parent, const io::path& basename, + bool ignoreCase, bool ignorePaths); + + //! opens a file by index + virtual IReadFile* createAndOpenFile(u32 index) _IRR_OVERRIDE_; + + //! opens a file by file name + virtual IReadFile* createAndOpenFile(const io::path& filename) _IRR_OVERRIDE_; + + //! returns the list of files + virtual const IFileList* getFileList() const _IRR_OVERRIDE_; + + //! get the class Type + virtual E_FILE_ARCHIVE_TYPE getType() const _IRR_OVERRIDE_ { return EFAT_FOLDER; } + + //! return the name (id) of the file Archive + virtual const io::path& getArchiveName() const _IRR_OVERRIDE_ {return Path;} + + private: + + core::array RealFileNames; + + IFileSystem *Parent; + void buildDirectory(); + }; +} // io +} // irr + +#endif // __IRR_COMPILE_WITH_MOUNT_ARCHIVE_LOADER_ +#endif // __C_MOUNT_READER_H_INCLUDED__ diff --git a/source/Irrlicht/CNPKReader.cpp b/source/Irrlicht/CNPKReader.cpp new file mode 100644 index 00000000..fc02786c --- /dev/null +++ b/source/Irrlicht/CNPKReader.cpp @@ -0,0 +1,277 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// Copyright (C) 2009-2012 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +// Based on the NPK reader from Irrlicht + +#include "CNPKReader.h" + +#ifdef __IRR_COMPILE_WITH_NPK_ARCHIVE_LOADER_ + +#include "os.h" +#include "coreutil.h" + +#ifdef _DEBUG +#define IRR_DEBUG_NPK_READER +#endif + +namespace irr +{ +namespace io +{ + +namespace +{ + bool isHeaderValid(const SNPKHeader& header) + { + const c8* const tag = header.Tag; + return tag[0] == '0' && + tag[1] == 'K' && + tag[2] == 'P' && + tag[3] == 'N'; + } +} // end namespace + + +//! Constructor +CArchiveLoaderNPK::CArchiveLoaderNPK( io::IFileSystem* fs) +: FileSystem(fs) +{ +#ifdef _DEBUG + setDebugName("CArchiveLoaderNPK"); +#endif +} + + +//! returns true if the file maybe is able to be loaded by this class +bool CArchiveLoaderNPK::isALoadableFileFormat(const io::path& filename) const +{ + return core::hasFileExtension(filename, "npk"); +} + +//! Check to see if the loader can create archives of this type. +bool CArchiveLoaderNPK::isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const +{ + return fileType == EFAT_NPK; +} + +//! Creates an archive from the filename +/** \param file File handle to check. +\return Pointer to newly created archive, or 0 upon error. */ +IFileArchive* CArchiveLoaderNPK::createArchive(const io::path& filename, bool ignoreCase, bool ignorePaths) const +{ + IFileArchive *archive = 0; + io::IReadFile* file = FileSystem->createAndOpenFile(filename); + + if (file) + { + archive = createArchive(file, ignoreCase, ignorePaths); + file->drop (); + } + + return archive; +} + +//! creates/loads an archive from the file. +//! \return Pointer to the created archive. Returns 0 if loading failed. +IFileArchive* CArchiveLoaderNPK::createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const +{ + IFileArchive *archive = 0; + if ( file ) + { + file->seek ( 0 ); + archive = new CNPKReader(file, ignoreCase, ignorePaths); + } + return archive; +} + + +//! Check if the file might be loaded by this class +/** Check might look into the file. +\param file File handle to check. +\return True if file seems to be loadable. */ +bool CArchiveLoaderNPK::isALoadableFileFormat(io::IReadFile* file) const +{ + SNPKHeader header; + + file->read(&header, sizeof(header)); + + return isHeaderValid(header); +} + + +/*! + NPK Reader +*/ +CNPKReader::CNPKReader(IReadFile* file, bool ignoreCase, bool ignorePaths) +: CFileList((file ? file->getFileName() : io::path("")), ignoreCase, ignorePaths), File(file) +{ +#ifdef _DEBUG + setDebugName("CNPKReader"); +#endif + + if (File) + { + File->grab(); + if (scanLocalHeader()) + sort(); + else + os::Printer::log("Failed to load NPK archive."); + } +} + + +CNPKReader::~CNPKReader() +{ + if (File) + File->drop(); +} + + +const IFileList* CNPKReader::getFileList() const +{ + return this; +} + + +bool CNPKReader::scanLocalHeader() +{ + SNPKHeader header; + + // Read and validate the header + File->read(&header, sizeof(header)); + if (!isHeaderValid(header)) + return false; + + // Seek to the table of contents +#ifdef __BIG_ENDIAN__ + header.Offset = os::Byteswap::byteswap(header.Offset); + header.Length = os::Byteswap::byteswap(header.Length); +#endif + header.Offset += 8; + core::stringc dirName; + bool inTOC=true; + // Loop through each entry in the table of contents + while (inTOC && (File->getPos() < File->getSize())) + { + // read an entry + char tag[4]={0}; + SNPKFileEntry entry; + File->read(tag, 4); + const int numTag = MAKE_IRR_ID(tag[3],tag[2],tag[1],tag[0]); + int size; + + bool isDir=true; + + switch (numTag) + { + case MAKE_IRR_ID('D','I','R','_'): + { + File->read(&size, 4); + readString(entry.Name); + entry.Length=0; + entry.Offset=0; +#ifdef IRR_DEBUG_NPK_READER + os::Printer::log("Dir", entry.Name); +#endif + } + break; + case MAKE_IRR_ID('F','I','L','E'): + { + File->read(&size, 4); + File->read(&entry.Offset, 4); + File->read(&entry.Length, 4); + readString(entry.Name); + isDir=false; +#ifdef IRR_DEBUG_NPK_READER + os::Printer::log("File", entry.Name); +#endif +#ifdef __BIG_ENDIAN__ + entry.Offset = os::Byteswap::byteswap(entry.Offset); + entry.Length = os::Byteswap::byteswap(entry.Length); +#endif + } + break; + case MAKE_IRR_ID('D','E','N','D'): + { + File->read(&size, 4); + entry.Name=""; + entry.Length=0; + entry.Offset=0; + const s32 pos = dirName.findLast('/', dirName.size()-2); + if (pos==-1) + dirName=""; + else + dirName=dirName.subString(0, pos); +#ifdef IRR_DEBUG_NPK_READER + os::Printer::log("Dirend", dirName); +#endif + } + break; + default: + inTOC=false; + } + // skip root dir + if (isDir) + { + if (!entry.Name.size() || (entry.Name==".") || (entry.Name=="")) + continue; + dirName += entry.Name; + dirName += "/"; + } +#ifdef IRR_DEBUG_NPK_READER + os::Printer::log("Name", entry.Name); +#endif + addItem((isDir?dirName:dirName+entry.Name), entry.Offset+header.Offset, entry.Length, isDir); + } + return true; +} + + +//! opens a file by file name +IReadFile* CNPKReader::createAndOpenFile(const io::path& filename) +{ + s32 index = findFile(filename, false); + + if (index != -1) + return createAndOpenFile(index); + + return 0; +} + + +//! opens a file by index +IReadFile* CNPKReader::createAndOpenFile(u32 index) +{ + if (index >= Files.size() ) + return 0; + + const SFileListEntry &entry = Files[index]; + return createLimitReadFile( entry.FullName, File, entry.Offset, entry.Size ); +} + +void CNPKReader::readString(core::stringc& name) +{ + short stringSize; + char buf[256]; + File->read(&stringSize, 2); +#ifdef __BIG_ENDIAN__ + stringSize = os::Byteswap::byteswap(stringSize); +#endif + name.reserve(stringSize); + while(stringSize) + { + const short next = core::min_(stringSize, (short)255); + File->read(buf,next); + buf[next]=0; + name.append(buf); + stringSize -= next; + } +} + + +} // end namespace io +} // end namespace irr + +#endif // __IRR_COMPILE_WITH_NPK_ARCHIVE_LOADER_ + diff --git a/source/Irrlicht/CNPKReader.h b/source/Irrlicht/CNPKReader.h new file mode 100644 index 00000000..204a34c3 --- /dev/null +++ b/source/Irrlicht/CNPKReader.h @@ -0,0 +1,125 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// Copyright (C) 2009-2012 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_NPK_READER_H_INCLUDED__ +#define __C_NPK_READER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef __IRR_COMPILE_WITH_NPK_ARCHIVE_LOADER_ + +#include "IReferenceCounted.h" +#include "IReadFile.h" +#include "irrArray.h" +#include "irrString.h" +#include "IFileSystem.h" +#include "CFileList.h" + +namespace irr +{ +namespace io +{ + namespace + { + //! File header containing location and size of the table of contents + struct SNPKHeader + { + // Don't change the order of these fields! They must match the order stored on disk. + c8 Tag[4]; + u32 Length; + u32 Offset; + }; + + //! An entry in the NPK file's table of contents. + struct SNPKFileEntry + { + core::stringc Name; + u32 Offset; + u32 Length; + }; + } // end namespace + + //! Archiveloader capable of loading Nebula Device 2 NPK Archives + class CArchiveLoaderNPK : public IArchiveLoader + { + public: + + //! Constructor + CArchiveLoaderNPK(io::IFileSystem* fs); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".zip") + virtual bool isALoadableFileFormat(const io::path& filename) const _IRR_OVERRIDE_; + + //! Check if the file might be loaded by this class + /** Check might look into the file. + \param file File handle to check. + \return True if file seems to be loadable. */ + virtual bool isALoadableFileFormat(io::IReadFile* file) const _IRR_OVERRIDE_; + + //! Check to see if the loader can create archives of this type. + /** Check based on the archive type. + \param fileType The archive type to check. + \return True if the archile loader supports this type, false if not */ + virtual bool isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const _IRR_OVERRIDE_; + + //! Creates an archive from the filename + /** \param file File handle to check. + \return Pointer to newly created archive, or 0 upon error. */ + virtual IFileArchive* createArchive(const io::path& filename, bool ignoreCase, bool ignorePaths) const _IRR_OVERRIDE_; + + //! creates/loads an archive from the file. + //! \return Pointer to the created archive. Returns 0 if loading failed. + virtual io::IFileArchive* createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const _IRR_OVERRIDE_; + + private: + io::IFileSystem* FileSystem; + }; + + + //! reads from NPK + class CNPKReader : public virtual IFileArchive, virtual CFileList + { + public: + + CNPKReader(IReadFile* file, bool ignoreCase, bool ignorePaths); + virtual ~CNPKReader(); + + // file archive methods + + //! return the id of the file Archive + virtual const io::path& getArchiveName() const _IRR_OVERRIDE_ + { + return File->getFileName(); + } + + //! opens a file by file name + virtual IReadFile* createAndOpenFile(const io::path& filename) _IRR_OVERRIDE_; + + //! opens a file by index + virtual IReadFile* createAndOpenFile(u32 index) _IRR_OVERRIDE_; + + //! returns the list of files + virtual const IFileList* getFileList() const _IRR_OVERRIDE_; + + //! get the class Type + virtual E_FILE_ARCHIVE_TYPE getType() const _IRR_OVERRIDE_ { return EFAT_NPK; } + + private: + + //! scans for a local header, returns false if the header is invalid + bool scanLocalHeader(); + void readString(core::stringc& name); + + IReadFile* File; + }; + +} // end namespace io +} // end namespace irr + +#endif // __IRR_COMPILE_WITH_NPK_ARCHIVE_LOADER_ + +#endif // __C_NPK_READER_H_INCLUDED__ + diff --git a/source/Irrlicht/CNSOGLManager.h b/source/Irrlicht/CNSOGLManager.h new file mode 100644 index 00000000..42a6317f --- /dev/null +++ b/source/Irrlicht/CNSOGLManager.h @@ -0,0 +1,72 @@ +// Copyright (C) 2014 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __C_NSOGL_MANAGER_H_INCLUDED__ +#define __C_NSOGL_MANAGER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_NSOGL_MANAGER_ + +#include "SIrrCreationParameters.h" +#include "SExposedVideoData.h" +#include "IContextManager.h" +#include "SColor.h" + +#import + +namespace irr +{ +namespace video +{ + // NSOpenGL manager. + class CNSOGLManager : public IContextManager + { + public: + //! Constructor. + CNSOGLManager(); + + //! Destructor + ~CNSOGLManager(); + + // Initialize + bool initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& data); + + // Terminate + void terminate(); + + // Create surface. + bool generateSurface(); + + // Destroy surface. + void destroySurface(); + + // Create context. + bool generateContext(); + + // Destroy EGL context. + void destroyContext(); + + //! Get current context + const SExposedVideoData& getContext() const; + + //! Change render context, disable old and activate new defined by videoData + bool activateContext(const SExposedVideoData& videoData); + + // Swap buffers. + bool swapBuffers(); + + private: + SIrrlichtCreationParameters Params; + SExposedVideoData PrimaryContext; + SExposedVideoData CurrentContext; + + NSOpenGLPixelFormat* PixelFormat; + }; +} +} + +#endif + +#endif diff --git a/source/Irrlicht/CNSOGLManager.mm b/source/Irrlicht/CNSOGLManager.mm new file mode 100644 index 00000000..4a842073 --- /dev/null +++ b/source/Irrlicht/CNSOGLManager.mm @@ -0,0 +1,242 @@ +// Copyright (C) 2014 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#include "CNSOGLManager.h" + +#ifdef _IRR_COMPILE_WITH_NSOGL_MANAGER_ + +#include "os.h" + +namespace irr +{ +namespace video +{ + +CNSOGLManager::CNSOGLManager() + : PrimaryContext(SExposedVideoData(0)), PixelFormat(nil) +{ +#ifdef _DEBUG + setDebugName("CNSOGLManager"); +#endif +} + +CNSOGLManager::~CNSOGLManager() +{ +} + +bool CNSOGLManager::initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& videodata) +{ + Params = params; + + return true; +} + +void CNSOGLManager::terminate() +{ +} + +bool CNSOGLManager::generateSurface() +{ + if (Params.DriverType == video::EDT_OPENGL) + { + int alphaSize = Params.WithAlphaChannel ? 4 : 0; + int depthSize = Params.ZBufferBits; + + if (Params.WithAlphaChannel && Params.Bits == 32) + alphaSize = 8; + + NSOpenGLPixelFormatAttribute Attribs[] = + { + NSOpenGLPFANoRecovery, + NSOpenGLPFAAccelerated, + NSOpenGLPFADoubleBuffer, + NSOpenGLPFADepthSize, static_cast(depthSize), + NSOpenGLPFAColorSize, Params.Bits, + NSOpenGLPFAAlphaSize, static_cast(alphaSize), + NSOpenGLPFASampleBuffers, 1, + NSOpenGLPFASamples, Params.AntiAlias, + NSOpenGLPFAStencilSize, static_cast(Params.Stencilbuffer ? 1 : 0), + //NSOpenGLPFAFullScreen, + 0 + }; + + u32 Steps = 6; + + // Choose the best pixel format. + do + { + switch (Steps) + { + case 6: // decrease step. + --Steps; + break; + case 5: // samples + if (Attribs[12] > 2) + --Attribs[12]; + else + { + Attribs[10] = 0; + Attribs[12] = 0; + --Steps; + } + break; + case 4: // alpha + if (Attribs[8]) + { + Attribs[8] = 0; + + if (Params.AntiAlias) + { + Attribs[10] = 1; + Attribs[12] = Params.AntiAlias; + Steps = 5; + } + } + else + --Steps; + break; + case 3: // stencil + if (Attribs[14]) + { + Attribs[14] = 0; + + if (Params.AntiAlias) + { + Attribs[10] = 1; + Attribs[12] = Params.AntiAlias; + Steps = 5; + } + } + else + --Steps; + break; + case 2: // depth size + if (Attribs[4] > 16) + { + Attribs[4] = Attribs[4] - 8; + } + else + --Steps; + break; + case 1: // buffer size + if (Attribs[6] > 16) + { + Attribs[6] = Attribs[6] - 8; + } + else + --Steps; + break; + default: + os::Printer::log("Could not get pixel format."); + return false; + } + + PixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:Attribs]; + } + while (PixelFormat == nil); + + if (Params.AntiAlias && !Attribs[10]) + os::Printer::log("No multisampling."); + + if (Params.WithAlphaChannel && !Attribs[8]) + os::Printer::log("No alpha."); + + if (Params.Stencilbuffer && !Attribs[14]) + os::Printer::log("No stencil buffer."); + + if (Params.ZBufferBits > Attribs[4]) + os::Printer::log("No full depth buffer."); + + if (Params.Bits > Attribs[6]) + os::Printer::log("No full color buffer."); + } + + return true; +} + +void CNSOGLManager::destroySurface() +{ + [PixelFormat release]; + PixelFormat = nil; +} + +bool CNSOGLManager::generateContext() +{ + NSOpenGLContext* Context = [[NSOpenGLContext alloc] initWithFormat:PixelFormat shareContext:nil]; + + GLint Vsync = Params.Vsync ? 1 : 0; + [Context setValues:&Vsync forParameter:NSOpenGLCPSwapInterval]; + + if (Context == nil) + { + os::Printer::log("Could not create OpenGL context.", ELL_ERROR); + return false; + } + + // set exposed data + CurrentContext.OpenGLOSX.Context = Context; + + if (!PrimaryContext.OpenGLOSX.Context) + PrimaryContext.OpenGLOSX.Context = CurrentContext.OpenGLOSX.Context; + + return true; +} + +const SExposedVideoData& CNSOGLManager::getContext() const +{ + return CurrentContext; +} + +bool CNSOGLManager::activateContext(const SExposedVideoData& videoData) +{ + if (videoData.OpenGLOSX.Context) + { + if ((NSOpenGLContext*)videoData.OpenGLOSX.Context != [NSOpenGLContext currentContext]) + { + [(NSOpenGLContext*)videoData.OpenGLOSX.Context makeCurrentContext]; + + CurrentContext = videoData; + } + } + // set back to main context + else + { + if ((NSOpenGLContext*)PrimaryContext.OpenGLOSX.Context != [NSOpenGLContext currentContext]) + { + [(NSOpenGLContext*)PrimaryContext.OpenGLOSX.Context makeCurrentContext]; + + CurrentContext = PrimaryContext; + } + } + + return true; +} + +void CNSOGLManager::destroyContext() +{ + if (CurrentContext.OpenGLOSX.Context) + { + if (PrimaryContext.OpenGLOSX.Context == CurrentContext.OpenGLOSX.Context) + PrimaryContext.OpenGLOSX.Context = nil; + + [(NSOpenGLContext*)CurrentContext.OpenGLOSX.Context makeCurrentContext]; + [(NSOpenGLContext *)CurrentContext.OpenGLOSX.Context clearDrawable]; + [(NSOpenGLContext *)CurrentContext.OpenGLOSX.Context release]; + [NSOpenGLContext clearCurrentContext]; + + CurrentContext.OpenGLOSX.Context = nil; + } +} + +bool CNSOGLManager::swapBuffers() +{ + [(NSOpenGLContext*)CurrentContext.OpenGLOSX.Context flushBuffer]; + + return true; +} + +} +} + +#endif diff --git a/source/Irrlicht/CNullDriver.cpp b/source/Irrlicht/CNullDriver.cpp new file mode 100644 index 00000000..23110e33 --- /dev/null +++ b/source/Irrlicht/CNullDriver.cpp @@ -0,0 +1,2793 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CNullDriver.h" +#include "os.h" +#include "CImage.h" +#include "CAttributes.h" +#include "IReadFile.h" +#include "IWriteFile.h" +#include "IImageLoader.h" +#include "IImageWriter.h" +#include "IMaterialRenderer.h" +#include "IAnimatedMeshSceneNode.h" +#include "CMeshManipulator.h" +#include "CColorConverter.h" +#include "IAttributeExchangingObject.h" +#include "IRenderTarget.h" + + +namespace irr +{ +namespace video +{ + +//! creates a loader which is able to load windows bitmaps +IImageLoader* createImageLoaderBMP(); + +//! creates a loader which is able to load jpeg images +IImageLoader* createImageLoaderJPG(); + +//! creates a loader which is able to load targa images +IImageLoader* createImageLoaderTGA(); + +//! creates a loader which is able to load psd images +IImageLoader* createImageLoaderPSD(); + +//! creates a loader which is able to load psd images +IImageLoader* createImageLoaderPVR(); + +//! creates a loader which is able to load dds images +IImageLoader* createImageLoaderDDS(); + +//! creates a loader which is able to load pcx images +IImageLoader* createImageLoaderPCX(); + +//! creates a loader which is able to load png images +IImageLoader* createImageLoaderPNG(); + +//! creates a loader which is able to load WAL images +IImageLoader* createImageLoaderWAL(); + +//! creates a loader which is able to load halflife images +IImageLoader* createImageLoaderHalfLife(); + +//! creates a loader which is able to load lmp images +IImageLoader* createImageLoaderLMP(); + +//! creates a loader which is able to load ppm/pgm/pbm images +IImageLoader* createImageLoaderPPM(); + +//! creates a loader which is able to load rgb images +IImageLoader* createImageLoaderRGB(); + + +//! creates a writer which is able to save bmp images +IImageWriter* createImageWriterBMP(); + +//! creates a writer which is able to save jpg images +IImageWriter* createImageWriterJPG(); + +//! creates a writer which is able to save tga images +IImageWriter* createImageWriterTGA(); + +//! creates a writer which is able to save psd images +IImageWriter* createImageWriterPSD(); + +//! creates a writer which is able to save pcx images +IImageWriter* createImageWriterPCX(); + +//! creates a writer which is able to save png images +IImageWriter* createImageWriterPNG(); + +//! creates a writer which is able to save ppm images +IImageWriter* createImageWriterPPM(); + +//! constructor +CNullDriver::CNullDriver(io::IFileSystem* io, const core::dimension2d& screenSize) + : SharedRenderTarget(0), CurrentRenderTarget(0), CurrentRenderTargetSize(0, 0), FileSystem(io), MeshManipulator(0), + ViewPort(0, 0, 0, 0), ScreenSize(screenSize), PrimitivesDrawn(0), MinVertexCountForVBO(500), + TextureCreationFlags(0), OverrideMaterial2DEnabled(false), AllowZWriteOnTransparent(false) +{ + #ifdef _DEBUG + setDebugName("CNullDriver"); + #endif + + DriverAttributes = new io::CAttributes(); + DriverAttributes->addInt("MaxTextures", _IRR_MATERIAL_MAX_TEXTURES_); + DriverAttributes->addInt("MaxSupportedTextures", _IRR_MATERIAL_MAX_TEXTURES_); + DriverAttributes->addInt("MaxLights", getMaximalDynamicLightAmount()); + DriverAttributes->addInt("MaxAnisotropy", 1); +// DriverAttributes->addInt("MaxUserClipPlanes", 0); +// DriverAttributes->addInt("MaxAuxBuffers", 0); + DriverAttributes->addInt("MaxMultipleRenderTargets", 1); + DriverAttributes->addInt("MaxIndices", -1); + DriverAttributes->addInt("MaxTextureSize", -1); +// DriverAttributes->addInt("MaxGeometryVerticesOut", 0); +// DriverAttributes->addFloat("MaxTextureLODBias", 0.f); + DriverAttributes->addInt("Version", 1); +// DriverAttributes->addInt("ShaderLanguageVersion", 0); +// DriverAttributes->addInt("AntiAlias", 0); + + setFog(); + + setTextureCreationFlag(ETCF_ALWAYS_32_BIT, true); + setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, true); + setTextureCreationFlag(ETCF_AUTO_GENERATE_MIP_MAPS, true); + setTextureCreationFlag(ETCF_ALLOW_MEMORY_COPY, true); + + ViewPort = core::rect(core::position2d(0,0), core::dimension2di(screenSize)); + + // create manipulator + MeshManipulator = new scene::CMeshManipulator(); + + if (FileSystem) + FileSystem->grab(); + + // create surface loader + +#ifdef _IRR_COMPILE_WITH_WAL_LOADER_ + SurfaceLoader.push_back(video::createImageLoaderHalfLife()); + SurfaceLoader.push_back(video::createImageLoaderWAL()); +#endif +#ifdef _IRR_COMPILE_WITH_LMP_LOADER_ + SurfaceLoader.push_back(video::createImageLoaderLMP()); +#endif +#ifdef _IRR_COMPILE_WITH_PPM_LOADER_ + SurfaceLoader.push_back(video::createImageLoaderPPM()); +#endif +#ifdef _IRR_COMPILE_WITH_RGB_LOADER_ + SurfaceLoader.push_back(video::createImageLoaderRGB()); +#endif +#ifdef _IRR_COMPILE_WITH_PSD_LOADER_ + SurfaceLoader.push_back(video::createImageLoaderPSD()); +#endif +#ifdef _IRR_COMPILE_WITH_PVR_LOADER_ + SurfaceLoader.push_back(video::createImageLoaderPVR()); +#endif +#if defined(_IRR_COMPILE_WITH_DDS_LOADER_) || defined(_IRR_COMPILE_WITH_DDS_DECODER_LOADER_) + SurfaceLoader.push_back(video::createImageLoaderDDS()); +#endif +#ifdef _IRR_COMPILE_WITH_PCX_LOADER_ + SurfaceLoader.push_back(video::createImageLoaderPCX()); +#endif +#ifdef _IRR_COMPILE_WITH_TGA_LOADER_ + SurfaceLoader.push_back(video::createImageLoaderTGA()); +#endif +#ifdef _IRR_COMPILE_WITH_PNG_LOADER_ + SurfaceLoader.push_back(video::createImageLoaderPNG()); +#endif +#ifdef _IRR_COMPILE_WITH_JPG_LOADER_ + SurfaceLoader.push_back(video::createImageLoaderJPG()); +#endif +#ifdef _IRR_COMPILE_WITH_BMP_LOADER_ + SurfaceLoader.push_back(video::createImageLoaderBMP()); +#endif + + +#ifdef _IRR_COMPILE_WITH_PPM_WRITER_ + SurfaceWriter.push_back(video::createImageWriterPPM()); +#endif +#ifdef _IRR_COMPILE_WITH_PCX_WRITER_ + SurfaceWriter.push_back(video::createImageWriterPCX()); +#endif +#ifdef _IRR_COMPILE_WITH_PSD_WRITER_ + SurfaceWriter.push_back(video::createImageWriterPSD()); +#endif +#ifdef _IRR_COMPILE_WITH_TGA_WRITER_ + SurfaceWriter.push_back(video::createImageWriterTGA()); +#endif +#ifdef _IRR_COMPILE_WITH_JPG_WRITER_ + SurfaceWriter.push_back(video::createImageWriterJPG()); +#endif +#ifdef _IRR_COMPILE_WITH_PNG_WRITER_ + SurfaceWriter.push_back(video::createImageWriterPNG()); +#endif +#ifdef _IRR_COMPILE_WITH_BMP_WRITER_ + SurfaceWriter.push_back(video::createImageWriterBMP()); +#endif + + + // set ExposedData to 0 + memset(&ExposedData, 0, sizeof(ExposedData)); + for (u32 i=0; idrop(); + + if (FileSystem) + FileSystem->drop(); + + if (MeshManipulator) + MeshManipulator->drop(); + + removeAllRenderTargets(); + + deleteAllTextures(); + + u32 i; + for (i=0; idrop(); + + for (i=0; idrop(); + + // delete material renderers + deleteMaterialRenders(); + + // delete hardware mesh buffers + removeAllHardwareBuffers(); +} + + +//! Adds an external surface loader to the engine. +void CNullDriver::addExternalImageLoader(IImageLoader* loader) +{ + if (!loader) + return; + + loader->grab(); + SurfaceLoader.push_back(loader); +} + + +//! Adds an external surface writer to the engine. +void CNullDriver::addExternalImageWriter(IImageWriter* writer) +{ + if (!writer) + return; + + writer->grab(); + SurfaceWriter.push_back(writer); +} + + +//! Retrieve the number of image loaders +u32 CNullDriver::getImageLoaderCount() const +{ + return SurfaceLoader.size(); +} + + +//! Retrieve the given image loader +IImageLoader* CNullDriver::getImageLoader(u32 n) +{ + if (n < SurfaceLoader.size()) + return SurfaceLoader[n]; + return 0; +} + + +//! Retrieve the number of image writers +u32 CNullDriver::getImageWriterCount() const +{ + return SurfaceWriter.size(); +} + + +//! Retrieve the given image writer +IImageWriter* CNullDriver::getImageWriter(u32 n) +{ + if (n < SurfaceWriter.size()) + return SurfaceWriter[n]; + return 0; +} + + +//! deletes all textures +void CNullDriver::deleteAllTextures() +{ + // we need to remove previously set textures which might otherwise be kept in the + // last set material member. Could be optimized to reduce state changes. + setMaterial(SMaterial()); + + // reset render targets. + + for (u32 i=0; isetTexture(0, 0); + + // remove textures. + + for (u32 i=0; idrop(); + + Textures.clear(); + + SharedDepthTextures.clear(); +} + +bool CNullDriver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil, const SExposedVideoData& videoData, core::rect* sourceRect) +{ + PrimitivesDrawn = 0; + return true; +} + +bool CNullDriver::endScene() +{ + FPSCounter.registerFrame(os::Timer::getRealTime(), PrimitivesDrawn); + updateAllHardwareBuffers(); + updateAllOcclusionQueries(); + return true; +} + + +//! Disable a feature of the driver. +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 +{ + return false; +} + + +//! Get attributes of the actual video driver +const io::IAttributes& CNullDriver::getDriverAttributes() const +{ + return *DriverAttributes; +} + + +//! sets transformation +void CNullDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) +{ +} + + +//! Returns the transformation set by setTransform +const core::matrix4& CNullDriver::getTransform(E_TRANSFORMATION_STATE state) const +{ + return TransformationMatrix; +} + + +//! sets a material +void CNullDriver::setMaterial(const SMaterial& material) +{ +} + + +//! Removes a texture from the texture cache and deletes it, freeing lot of +//! memory. +void CNullDriver::removeTexture(ITexture* texture) +{ + if (!texture) + return; + + for (u32 i=0; idrop(); + Textures.erase(i); + return; + } + } +} + + +//! Removes all texture from the texture cache and deletes them, freeing lot of +//! memory. +void CNullDriver::removeAllTextures() +{ + setMaterial ( SMaterial() ); + deleteAllTextures(); +} + + +//! Returns a texture by index +ITexture* CNullDriver::getTextureByIndex(u32 i) +{ + if ( i < Textures.size() ) + return Textures[i].Surface; + + return 0; +} + + +//! Returns amount of textures currently loaded +u32 CNullDriver::getTextureCount() const +{ + return Textures.size(); +} + + +//! Renames a texture +void CNullDriver::renameTexture(ITexture* texture, const io::path& newName) +{ + // we can do a const_cast here safely, the name of the ITexture interface + // is just readonly to prevent the user changing the texture name without invoking + // this method, because the textures will need resorting afterwards + + io::SNamedPath& name = const_cast(texture->getName()); + name.setPath(newName); + + Textures.sort(); +} + +ITexture* CNullDriver::addTexture(const core::dimension2d& size, const io::path& name, ECOLOR_FORMAT format) +{ + if (0 == name.size()) + { + os::Printer::log("Could not create ITexture, texture needs to have a non-empty name.", ELL_WARNING); + return 0; + } + + IImage* image = new CImage(format, size); + ITexture* t = 0; + + core::array imageArray(1); + imageArray.push_back(image); + + if (checkImage(imageArray)) + { + t = createDeviceDependentTexture(name, image); + } + + image->drop(); + + if (t) + { + addTexture(t); + t->drop(); + } + + return t; +} + +ITexture* CNullDriver::addTexture(const io::path& name, IImage* image) +{ + if (0 == name.size()) + { + os::Printer::log("Could not create ITexture, texture needs to have a non-empty name.", ELL_WARNING); + return 0; + } + + if (!image) + return 0; + + ITexture* t = 0; + + core::array imageArray(1); + imageArray.push_back(image); + + if (checkImage(imageArray)) + { + t = createDeviceDependentTexture(name, image); + } + + if (t) + { + addTexture(t); + t->drop(); + } + + return t; +} + +ITexture* CNullDriver::addTextureCubemap(const io::path& name, IImage* imagePosX, IImage* imageNegX, IImage* imagePosY, + IImage* imageNegY, IImage* imagePosZ, IImage* imageNegZ) +{ + if (0 == name.size() || !imagePosX || !imageNegX || !imagePosY || !imageNegY || !imagePosZ || !imageNegZ) + return 0; + + ITexture* t = 0; + + core::array imageArray(6); + imageArray.push_back(imagePosX); + imageArray.push_back(imageNegX); + imageArray.push_back(imagePosY); + imageArray.push_back(imageNegY); + imageArray.push_back(imagePosZ); + imageArray.push_back(imageNegZ); + + if (checkImage(imageArray)) + { + t = createDeviceDependentTextureCubemap(name, imageArray); + } + + if (t) + { + addTexture(t); + t->drop(); + } + + return t; +} + +ITexture* CNullDriver::addTextureCubemap(const irr::u32 sideLen, const io::path& name, ECOLOR_FORMAT format) +{ + if ( 0 == sideLen ) + return 0; + + if (0 == name.size()) + { + os::Printer::log("Could not create ITexture, texture needs to have a non-empty name.", ELL_WARNING); + return 0; + } + + core::array imageArray(6); + for ( int i=0; i < 6; ++i ) + imageArray.push_back(new CImage(format, core::dimension2du(sideLen, sideLen))); + + ITexture* t = 0; + if (checkImage(imageArray)) + { + t = createDeviceDependentTextureCubemap(name, imageArray); + + if (t) + { + addTexture(t); + t->drop(); + } + } + + for ( int i=0; i < 6; ++i ) + imageArray[i]->drop(); + + return t; +} + +//! loads a Texture +ITexture* CNullDriver::getTexture(const io::path& filename) +{ + // Identify textures by their absolute filenames if possible. + const io::path absolutePath = FileSystem->getAbsolutePath(filename); + + ITexture* texture = findTexture(absolutePath); + if (texture) + { + texture->updateSource(ETS_FROM_CACHE); + return texture; + } + + // Then try the raw filename, which might be in an Archive + texture = findTexture(filename); + if (texture) + { + texture->updateSource(ETS_FROM_CACHE); + return texture; + } + + // Now try to open the file using the complete path. + io::IReadFile* file = FileSystem->createAndOpenFile(absolutePath); + + if (!file) + { + // Try to open it using the raw filename. + file = FileSystem->createAndOpenFile(filename); + } + + if (file) + { + // Re-check name for actual archive names + texture = findTexture(file->getFileName()); + if (texture) + { + texture->updateSource(ETS_FROM_CACHE); + file->drop(); + return texture; + } + + texture = loadTextureFromFile(file); + file->drop(); + + if (texture) + { + texture->updateSource(ETS_FROM_FILE); + addTexture(texture); + texture->drop(); // drop it because we created it, one grab too much + } + else + os::Printer::log("Could not load texture", filename, ELL_ERROR); + return texture; + } + else + { + os::Printer::log("Could not open file of texture", filename, ELL_WARNING); + return 0; + } +} + + +//! loads a Texture +ITexture* CNullDriver::getTexture(io::IReadFile* file) +{ + ITexture* texture = 0; + + if (file) + { + texture = findTexture(file->getFileName()); + + if (texture) + { + texture->updateSource(ETS_FROM_CACHE); + return texture; + } + + texture = loadTextureFromFile(file); + + if (texture) + { + texture->updateSource(ETS_FROM_FILE); + addTexture(texture); + texture->drop(); // drop it because we created it, one grab too much + } + + if (!texture) + os::Printer::log("Could not load texture", file->getFileName(), ELL_WARNING); + } + + return texture; +} + + +//! opens the file and loads it into the surface +video::ITexture* CNullDriver::loadTextureFromFile(io::IReadFile* file, const io::path& hashName ) +{ + ITexture* texture = 0; + + E_TEXTURE_TYPE type = ETT_2D; + + core::array imageArray = createImagesFromFile(file, &type); + + if (checkImage(imageArray)) + { + switch (type) + { + case ETT_2D: + texture = createDeviceDependentTexture(hashName.size() ? hashName : file->getFileName(), imageArray[0]); + break; + case ETT_CUBEMAP: + if (imageArray.size() >= 6 && imageArray[0] && imageArray[1] && imageArray[2] && imageArray[3] && imageArray[4] && imageArray[5]) + { + texture = createDeviceDependentTextureCubemap(hashName.size() ? hashName : file->getFileName(), imageArray); + } + break; + default: + _IRR_DEBUG_BREAK_IF(true); + break; + } + + if (texture) + os::Printer::log("Loaded texture", file->getFileName(), ELL_DEBUG); + } + + for (u32 i = 0; i < imageArray.size(); ++i) + { + if (imageArray[i]) + imageArray[i]->drop(); + } + + return texture; +} + + +//! adds a surface, not loaded or created by the Irrlicht Engine +void CNullDriver::addTexture(video::ITexture* texture) +{ + if (texture) + { + SSurface s; + s.Surface = texture; + texture->grab(); + + Textures.push_back(s); + + // the new texture is now at the end of the texture list. when searching for + // the next new texture, the texture array will be sorted and the index of this texture + // will be changed. to let the order be more consistent to the user, sort + // the textures now already although this isn't necessary: + + Textures.sort(); + } +} + + +//! looks if the image is already loaded +video::ITexture* CNullDriver::findTexture(const io::path& filename) +{ + SSurface s; + SDummyTexture dummy(filename, ETT_2D); + s.Surface = &dummy; + + s32 index = Textures.binary_search(s); + if (index != -1) + return Textures[index].Surface; + + return 0; +} + +ITexture* CNullDriver::createDeviceDependentTexture(const io::path& name, IImage* image) +{ + return new SDummyTexture(name, ETT_2D); +} + +ITexture* CNullDriver::createDeviceDependentTextureCubemap(const io::path& name, const core::array& image) +{ + return new SDummyTexture(name, ETT_CUBEMAP); +} + +bool CNullDriver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil) +{ + return false; +} + +bool CNullDriver::setRenderTarget(ITexture* texture, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil) +{ + if (texture) + { + // create render target if require. + if (!SharedRenderTarget) + SharedRenderTarget = addRenderTarget(); + + ITexture* depthTexture = 0; + + // try to find available depth texture with require size. + for (u32 i = 0; i < SharedDepthTextures.size(); ++i) + { + if (SharedDepthTextures[i]->getSize() == texture->getSize()) + { + depthTexture = SharedDepthTextures[i]; + + break; + } + } + + // create depth texture if require. + if (!depthTexture) + { + depthTexture = addRenderTargetTexture(texture->getSize(), "IRR_DEPTH_STENCIL", video::ECF_D24S8); + SharedDepthTextures.push_back(depthTexture); + } + + SharedRenderTarget->setTexture(texture, depthTexture); + + return setRenderTargetEx(SharedRenderTarget, clearFlag, clearColor, clearDepth, clearStencil); + } + else + { + return setRenderTargetEx(0, clearFlag, clearColor, clearDepth, clearStencil); + } +} + +//! sets a viewport +void CNullDriver::setViewPort(const core::rect& area) +{ +} + + +//! gets the area of the current viewport +const core::rect& CNullDriver::getViewPort() const +{ + return ViewPort; +} + + +//! 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) +{ + if ((iType==EIT_16BIT) && (vertexCount>65536)) + os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur."); + PrimitivesDrawn += primitiveCount; +} + + +//! draws a vertex primitive list in 2d +void CNullDriver::draw2DVertexPrimitiveList(const void* vertices, u32 vertexCount, const void* indexList, u32 primitiveCount, E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) +{ + if ((iType==EIT_16BIT) && (vertexCount>65536)) + os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur."); + PrimitivesDrawn += primitiveCount; +} + + +//! Draws a 3d line. +void CNullDriver::draw3DLine(const core::vector3df& start, + const core::vector3df& end, SColor color) +{ +} + + +//! Draws a 3d triangle. +void CNullDriver::draw3DTriangle(const core::triangle3df& triangle, SColor color) +{ + S3DVertex vertices[3]; + vertices[0].Pos=triangle.pointA; + vertices[0].Color=color; + vertices[0].Normal=triangle.getNormal().normalize(); + vertices[0].TCoords.set(0.f,0.f); + vertices[1].Pos=triangle.pointB; + vertices[1].Color=color; + vertices[1].Normal=vertices[0].Normal; + vertices[1].TCoords.set(0.5f,1.f); + vertices[2].Pos=triangle.pointC; + vertices[2].Color=color; + vertices[2].Normal=vertices[0].Normal; + vertices[2].TCoords.set(1.f,0.f); + const u16 indexList[] = {0,1,2}; + drawVertexPrimitiveList(vertices, 3, indexList, 1, EVT_STANDARD, scene::EPT_TRIANGLES, EIT_16BIT); +} + + +//! Draws a 3d axis aligned box. +void CNullDriver::draw3DBox(const core::aabbox3d& box, SColor color) +{ + core::vector3df edges[8]; + box.getEdges(edges); + + // TODO: optimize into one big drawIndexPrimitive call. + + draw3DLine(edges[5], edges[1], color); + draw3DLine(edges[1], edges[3], color); + draw3DLine(edges[3], edges[7], color); + draw3DLine(edges[7], edges[5], color); + draw3DLine(edges[0], edges[2], color); + draw3DLine(edges[2], edges[6], color); + draw3DLine(edges[6], edges[4], color); + draw3DLine(edges[4], edges[0], color); + draw3DLine(edges[1], edges[0], color); + draw3DLine(edges[3], edges[2], color); + draw3DLine(edges[7], edges[6], color); + draw3DLine(edges[5], edges[4], color); +} + + + +//! draws an 2d image +void CNullDriver::draw2DImage(const video::ITexture* texture, const core::position2d& destPos, bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + draw2DImage(texture,destPos, core::rect(core::position2d(0,0), + core::dimension2di(texture->getOriginalSize())), + 0, + SColor(255,255,255,255), + useAlphaChannelOfTexture + ); +} + + + +//! draws a set of 2d images, using a color and the alpha channel of the +//! texture if desired. The images are drawn beginning at pos and concatenated +//! in one line. All drawings are clipped against clipRect (if != 0). +//! The subtextures are defined by the array of sourceRects and are chosen +//! by the indices given. +void CNullDriver::draw2DImageBatch(const video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, + s32 kerningWidth, + const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture) +{ + core::position2d target(pos); + + for (u32 i=0; i >& positions, + const core::array >& sourceRects, + const core::rect* clipRect, + SColor color, + bool useAlphaChannelOfTexture) +{ + const irr::u32 drawCount = core::min_(positions.size(), sourceRects.size()); + + for (u32 i=0; i& destRect, + const core::rect& sourceRect, const core::rect* clipRect, + const video::SColor* const colors, bool useAlphaChannelOfTexture) +{ + if (destRect.isValid()) + draw2DImage(texture, core::position2d(destRect.UpperLeftCorner), + sourceRect, clipRect, colors?colors[0]:video::SColor(0xffffffff), + useAlphaChannelOfTexture); +} + + +//! 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. +void CNullDriver::draw2DImage(const video::ITexture* texture, const core::position2d& destPos, + const core::rect& sourceRect, + const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture) +{ +} + + +//! 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 a 2d rectangle +void CNullDriver::draw2DRectangle(SColor color, const core::rect& pos, const core::rect* clip) +{ + draw2DRectangle(pos, color, color, color, color, clip); +} + + + +//! 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) +{ +} + + + +//! Draws a 2d line. +void CNullDriver::draw2DLine(const core::position2d& start, + const core::position2d& end, SColor color) +{ +} + +//! Draws a pixel +void CNullDriver::drawPixel(u32 x, u32 y, const SColor & color) +{ +} + + +//! Draws a non filled concyclic regular 2d polygon. +void CNullDriver::draw2DPolygon(core::position2d center, + f32 radius, video::SColor color, s32 count) +{ + if (count < 2) + return; + + core::position2d first; + core::position2d a,b; + + for (s32 j=0; j((s32)(sin(p)*radius), (s32)(cos(p)*radius)); + + if (j==0) + first = a; + else + draw2DLine(a, b, color); + } + + draw2DLine(a, first, color); +} + + +//! returns color format +ECOLOR_FORMAT CNullDriver::getColorFormat() const +{ + return ECF_R5G6B5; +} + + +//! returns screen size +const core::dimension2d& CNullDriver::getScreenSize() const +{ + return ScreenSize; +} + + +//! get current render target +IRenderTarget* CNullDriver::getCurrentRenderTarget() const +{ + return CurrentRenderTarget; +} + + +const core::dimension2d& CNullDriver::getCurrentRenderTargetSize() const +{ + if (CurrentRenderTargetSize.Width == 0) + return ScreenSize; + else + return CurrentRenderTargetSize; +} + + +// returns current frames per second value +s32 CNullDriver::getFPS() const +{ + return FPSCounter.getFPS(); +} + + + +//! returns amount of primitives (mostly triangles) were drawn in the last frame. +//! very useful method for statistics. +u32 CNullDriver::getPrimitiveCountDrawn( u32 param ) const +{ + return (0 == param) ? FPSCounter.getPrimitive() : (1 == param) ? FPSCounter.getPrimitiveAverage() : FPSCounter.getPrimitiveTotal(); +} + + + +//! 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. +void CNullDriver::setAmbientLight(const SColorf& color) +{ + AmbientLight = color; +} + +const SColorf& CNullDriver::getAmbientLight() const +{ + return AmbientLight; +} + +//! \return Returns the name of the video driver. Example: In case of the DIRECT3D8 +//! driver, it would return "Direct3D8". + +const wchar_t* CNullDriver::getName() const +{ + return L"Irrlicht NullDevice"; +} + + + +//! 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. +void CNullDriver::drawStencilShadowVolume(const core::array& triangles, bool zfail, u32 debugDataVisible) +{ +} + + +//! 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. +void CNullDriver::drawStencilShadow(bool clearStencilBuffer, + video::SColor leftUpEdge, video::SColor rightUpEdge, + video::SColor leftDownEdge, video::SColor rightDownEdge) +{ +} + + +//! deletes all dynamic lights there are +void CNullDriver::deleteAllDynamicLights() +{ + Lights.set_used(0); +} + + +//! adds a dynamic 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 +u32 CNullDriver::getMaximalDynamicLightAmount() const +{ + return 0; +} + + +//! Returns current amount of dynamic lights set +//! \return Current amount of dynamic lights set +u32 CNullDriver::getDynamicLightCount() const +{ + return Lights.size(); +} + + +//! Returns light data which was previously set by IVideoDriver::addDynamicLight(). +//! \param idx: Zero based index of the light. Must be greater than 0 and smaller +//! than IVideoDriver()::getDynamicLightCount. +//! \return Light data. +const SLight& CNullDriver::getDynamicLight(u32 idx) const +{ + if ( idx < Lights.size() ) + return Lights[idx]; + else + { + _IRR_DEBUG_BREAK_IF(true) + static const SLight dummy; + return dummy; + } +} + + +//! 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; + + if (texture->getColorFormat() != ECF_A1R5G5B5 && + texture->getColorFormat() != ECF_A8R8G8B8 ) + { + os::Printer::log("Error: Unsupported texture color format for making color key channel.", ELL_ERROR); + return; + } + + if (texture->getColorFormat() == ECF_A1R5G5B5) + { + u16 *p = (u16*)texture->lock(); + + if (!p) + { + os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR); + return; + } + + const core::dimension2d dim = texture->getSize(); + const u32 pitch = texture->getPitch() / 2; + + // color with alpha disabled (i.e. fully transparent) + const u16 refZeroAlpha = (0x7fff & color.toA1R5G5B5()); + + const u32 pixels = pitch * dim.Height; + + for (u32 pixel = 0; pixel < pixels; ++ pixel) + { + // If the color matches the reference color, ignoring alphas, + // set the alpha to zero. + if(((*p) & 0x7fff) == refZeroAlpha) + { + if(zeroTexels) + (*p) = 0; + else + (*p) = refZeroAlpha; + } + + ++p; + } + + texture->unlock(); + } + else + { + u32 *p = (u32*)texture->lock(); + + if (!p) + { + os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR); + return; + } + + core::dimension2d dim = texture->getSize(); + u32 pitch = texture->getPitch() / 4; + + // color with alpha disabled (fully transparent) + const u32 refZeroAlpha = 0x00ffffff & color.color; + + const u32 pixels = pitch * dim.Height; + for (u32 pixel = 0; pixel < pixels; ++ pixel) + { + // If the color matches the reference color, ignoring alphas, + // set the alpha to zero. + if(((*p) & 0x00ffffff) == refZeroAlpha) + { + if(zeroTexels) + (*p) = 0; + else + (*p) = refZeroAlpha; + } + + ++p; + } + + texture->unlock(); + } + texture->regenerateMipMapLevels(); +} + + + +//! Creates an boolean alpha channel of the texture based of an color key position. +void CNullDriver::makeColorKeyTexture(video::ITexture* texture, + core::position2d colorKeyPixelPos, + bool zeroTexels) const +{ + if (!texture) + return; + + if (texture->getColorFormat() != ECF_A1R5G5B5 && + texture->getColorFormat() != ECF_A8R8G8B8 ) + { + os::Printer::log("Error: Unsupported texture color format for making color key channel.", ELL_ERROR); + return; + } + + SColor colorKey; + + if (texture->getColorFormat() == ECF_A1R5G5B5) + { + u16 *p = (u16*)texture->lock(ETLM_READ_ONLY); + + if (!p) + { + os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR); + return; + } + + u32 pitch = texture->getPitch() / 2; + + const u16 key16Bit = 0x7fff & p[colorKeyPixelPos.Y*pitch + colorKeyPixelPos.X]; + + colorKey = video::A1R5G5B5toA8R8G8B8(key16Bit); + } + else + { + u32 *p = (u32*)texture->lock(ETLM_READ_ONLY); + + if (!p) + { + os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR); + return; + } + + u32 pitch = texture->getPitch() / 4; + colorKey = 0x00ffffff & p[colorKeyPixelPos.Y*pitch + colorKeyPixelPos.X]; + } + + texture->unlock(); + makeColorKeyTexture(texture, colorKey, zeroTexels); +} + + + +//! Creates a normal map from a height map texture. +//! \param amplitude: Constant value by which the height information is multiplied. +void CNullDriver::makeNormalMapTexture(video::ITexture* texture, f32 amplitude) const +{ + if (!texture) + return; + + if (texture->getColorFormat() != ECF_A1R5G5B5 && + texture->getColorFormat() != ECF_A8R8G8B8 ) + { + os::Printer::log("Error: Unsupported texture color format for making normal map.", ELL_ERROR); + return; + } + + core::dimension2d dim = texture->getSize(); + amplitude = amplitude / 255.0f; + f32 vh = dim.Height / (f32)dim.Width; + f32 hh = dim.Width / (f32)dim.Height; + + if (texture->getColorFormat() == ECF_A8R8G8B8) + { + // ECF_A8R8G8B8 version + + s32 *p = (s32*)texture->lock(); + + if (!p) + { + os::Printer::log("Could not lock texture for making normal map.", ELL_ERROR); + return; + } + + // copy texture + + u32 pitch = texture->getPitch() / 4; + + s32* in = new s32[dim.Height * pitch]; + memcpy(in, p, dim.Height * pitch * 4); + + for (s32 x=0; x < s32(pitch); ++x) + for (s32 y=0; y < s32(dim.Height); ++y) + { + // TODO: this could be optimized really a lot + + core::vector3df h1((x-1)*hh, nml32(x-1, y, pitch, dim.Height, in)*amplitude, y*vh); + core::vector3df h2((x+1)*hh, nml32(x+1, y, pitch, dim.Height, in)*amplitude, y*vh); + //core::vector3df v1(x*hh, nml32(x, y-1, pitch, dim.Height, in)*amplitude, (y-1)*vh); + //core::vector3df v2(x*hh, nml32(x, y+1, pitch, dim.Height, in)*amplitude, (y+1)*vh); + core::vector3df v1(x*hh, nml32(x, y+1, pitch, dim.Height, in)*amplitude, (y-1)*vh); + core::vector3df v2(x*hh, nml32(x, y-1, pitch, dim.Height, in)*amplitude, (y+1)*vh); + + core::vector3df v = v1-v2; + core::vector3df h = h1-h2; + + core::vector3df n = v.crossProduct(h); + n.normalize(); + n *= 0.5f; + n += core::vector3df(0.5f,0.5f,0.5f); // now between 0 and 1 + n *= 255.0f; + + s32 height = (s32)nml32(x, y, pitch, dim.Height, in); + p[y*pitch + x] = video::SColor( + height, // store height in alpha + (s32)n.X, (s32)n.Z, (s32)n.Y).color; + } + + delete [] in; + texture->unlock(); + } + else + { + // ECF_A1R5G5B5 version + + s16 *p = (s16*)texture->lock(); + + if (!p) + { + os::Printer::log("Could not lock texture for making normal map.", ELL_ERROR); + return; + } + + 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; x < s32(pitch); ++x) + for (s32 y=0; y < s32(dim.Height); ++y) + { + // TODO: this could be optimized really a lot + + core::vector3df h1((x-1)*hh, nml16(x-1, y, pitch, dim.Height, in)*amplitude, y*vh); + core::vector3df h2((x+1)*hh, nml16(x+1, y, pitch, dim.Height, in)*amplitude, y*vh); + core::vector3df v1(x*hh, nml16(x, y-1, pitch, dim.Height, in)*amplitude, (y-1)*vh); + core::vector3df v2(x*hh, nml16(x, y+1, pitch, dim.Height, in)*amplitude, (y+1)*vh); + + core::vector3df v = v1-v2; + core::vector3df h = h1-h2; + + core::vector3df n = v.crossProduct(h); + n.normalize(); + n *= 0.5f; + n += core::vector3df(0.5f,0.5f,0.5f); // now between 0 and 1 + n *= 255.0f; + + p[y*pitch + x] = video::RGBA16((u32)n.X, (u32)n.Z, (u32)n.Y); + } + + delete [] in; + texture->unlock(); + } + + texture->regenerateMipMapLevels(); +} + + +//! Returns the maximum amount of primitives (mostly vertices) which +//! the device is able to render with one drawIndexedTriangleList +//! call. +u32 CNullDriver::getMaximalPrimitiveCount() const +{ + return 0xFFFFFFFF; +} + + +//! checks triangle count and print warning if wrong +bool CNullDriver::checkPrimitiveCount(u32 prmCount) const +{ + const u32 m = getMaximalPrimitiveCount(); + + if (prmCount > m) + { + char tmp[1024]; + sprintf(tmp,"Could not draw triangles, too many primitives(%u), maximum is %u.", prmCount, m); + os::Printer::log(tmp, ELL_ERROR); + return false; + } + + return true; +} + +bool CNullDriver::checkImage(const core::array& image) const +{ + bool status = true; + + if (image.size() > 0) + { + ECOLOR_FORMAT lastFormat = image[0]->getColorFormat(); + core::dimension2d lastSize = image[0]->getDimension(); + + for (u32 i = 0; i < image.size() && status; ++i) + { + ECOLOR_FORMAT format = image[i]->getColorFormat(); + core::dimension2d size = image[i]->getDimension(); + + switch (format) + { + case ECF_DXT1: + case ECF_DXT2: + case ECF_DXT3: + case ECF_DXT4: + case ECF_DXT5: + if (!queryFeature(EVDF_TEXTURE_COMPRESSED_DXT)) + { + os::Printer::log("DXT texture compression not available.", ELL_ERROR); + status = false; + } + else if (size.getOptimalSize(true, false) != size) + { + os::Printer::log("Invalid size of image for DXT texture, size of image must be power of two.", ELL_ERROR); + status = false; + } + break; + case ECF_PVRTC_RGB2: + case ECF_PVRTC_ARGB2: + case ECF_PVRTC_RGB4: + case ECF_PVRTC_ARGB4: + if (!queryFeature(EVDF_TEXTURE_COMPRESSED_PVRTC)) + { + os::Printer::log("PVRTC texture compression not available.", ELL_ERROR); + status = false; + } + else if (size.getOptimalSize(true, false) != size) + { + os::Printer::log("Invalid size of image for PVRTC compressed texture, size of image must be power of two and squared.", ELL_ERROR); + status = false; + } + break; + case ECF_PVRTC2_ARGB2: + case ECF_PVRTC2_ARGB4: + if (!queryFeature(EVDF_TEXTURE_COMPRESSED_PVRTC2)) + { + os::Printer::log("PVRTC2 texture compression not available.", ELL_ERROR); + status = false; + } + break; + case ECF_ETC1: + if (!queryFeature(EVDF_TEXTURE_COMPRESSED_ETC1)) + { + os::Printer::log("ETC1 texture compression not available.", ELL_ERROR); + status = false; + } + break; + case ECF_ETC2_RGB: + case ECF_ETC2_ARGB: + if (!queryFeature(EVDF_TEXTURE_COMPRESSED_ETC2)) + { + os::Printer::log("ETC2 texture compression not available.", ELL_ERROR); + status = false; + } + break; + default: + break; + } + + if (format != lastFormat || size != lastSize) + status = false; + } + } + else + { + status = false; + } + + return status; +} + +//! Enables or disables a texture creation flag. +void CNullDriver::setTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag, bool enabled) +{ + if (enabled && ((flag == ETCF_ALWAYS_16_BIT) || (flag == ETCF_ALWAYS_32_BIT) + || (flag == ETCF_OPTIMIZED_FOR_QUALITY) || (flag == ETCF_OPTIMIZED_FOR_SPEED))) + { + // disable other formats + setTextureCreationFlag(ETCF_ALWAYS_16_BIT, false); + setTextureCreationFlag(ETCF_ALWAYS_32_BIT, false); + setTextureCreationFlag(ETCF_OPTIMIZED_FOR_QUALITY, false); + setTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED, false); + } + + // set flag + TextureCreationFlags = (TextureCreationFlags & (~flag)) | + ((((u32)!enabled)-1) & flag); +} + + +//! Returns if a texture creation flag is enabled or disabled. +bool CNullDriver::getTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag) const +{ + return (TextureCreationFlags & flag)!=0; +} + +core::array CNullDriver::createImagesFromFile(const io::path& filename, E_TEXTURE_TYPE* type) +{ + // TO-DO -> use 'move' feature from C++11 standard. + + core::array imageArray; + + if (filename.size() > 0) + { + io::IReadFile* file = FileSystem->createAndOpenFile(filename); + + if (file) + { + imageArray = createImagesFromFile(file, type); + file->drop(); + } + else + os::Printer::log("Could not open file of image", filename, ELL_WARNING); + } + + return imageArray; +} + +core::array CNullDriver::createImagesFromFile(io::IReadFile* file, E_TEXTURE_TYPE* type) +{ + // TO-DO -> use 'move' feature from C++11 standard. + + core::array imageArray; + + if (file) + { + s32 i; + + // try to load file based on file extension + for (i = SurfaceLoader.size() - 1; i >= 0; --i) + { + if (SurfaceLoader[i]->isALoadableFileExtension(file->getFileName())) + { + // reset file position which might have changed due to previous loadImage calls + file->seek(0); + imageArray = SurfaceLoader[i]->loadImages(file, type); + + if (imageArray.size() == 0) + { + file->seek(0); + IImage* image = SurfaceLoader[i]->loadImage(file); + + if (image) + imageArray.push_back(image); + } + + if (imageArray.size() > 0) + return imageArray; + } + } + + // try to load file based on what is in it + for (i = SurfaceLoader.size() - 1; i >= 0; --i) + { + // dito + file->seek(0); + if (SurfaceLoader[i]->isALoadableFileFormat(file)) + { + file->seek(0); + imageArray = SurfaceLoader[i]->loadImages(file, type); + + if (imageArray.size() == 0) + { + file->seek(0); + IImage* image = SurfaceLoader[i]->loadImage(file); + + if (image) + imageArray.push_back(image); + } + + if (imageArray.size() > 0) + return imageArray; + } + } + } + + return imageArray; +} + + +//! Writes the provided image to disk file +bool CNullDriver::writeImageToFile(IImage* image, const io::path& filename,u32 param) +{ + io::IWriteFile* file = FileSystem->createAndWriteFile(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 (s32 i=SurfaceWriter.size()-1; i>=0; --i) + { + if (SurfaceWriter[i]->isAWriteableFileExtension(file->getFileName())) + { + 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, void *data, bool ownForeignMemory, + bool deleteMemory) +{ + return new CImage(format, size, data, ownForeignMemory, deleteMemory); +} + + +//! Creates an empty software image. +IImage* CNullDriver::createImage(ECOLOR_FORMAT format, const core::dimension2d& size) +{ + return new CImage(format, size); +} + + +//! Creates a software image from another image. +IImage* CNullDriver::createImage(ECOLOR_FORMAT format, IImage *imageToCopy) +{ + os::Printer::log("Deprecated method, please create an empty image instead and use copyTo().", ELL_WARNING); + + CImage* tmp = new CImage(format, imageToCopy->getDimension()); + imageToCopy->copyTo(tmp); + return tmp; +} + + +//! Creates a software image from part of another image. +IImage* CNullDriver::createImage(IImage* imageToCopy, const core::position2d& pos, const core::dimension2d& size) +{ + os::Printer::log("Deprecated method, please create an empty image instead and use copyTo().", ELL_WARNING); + CImage* tmp = new CImage(imageToCopy->getColorFormat(), imageToCopy->getDimension()); + imageToCopy->copyTo(tmp, core::position2di(0,0), core::recti(pos,size)); + return tmp; +} + + +//! Creates a software image from part of a texture. +IImage* CNullDriver::createImage(ITexture* texture, const core::position2d& pos, const core::dimension2d& size) +{ + if ((pos==core::position2di(0,0)) && (size == texture->getSize())) + { + void * data = texture->lock(ETLM_READ_ONLY); + if ( !data) + return 0; + IImage* image = new CImage(texture->getColorFormat(), size, data, false, false); + texture->unlock(); + return image; + } + else + { + // make sure to avoid buffer overruns + // make the vector a separate variable for g++ 3.x + const core::vector2d leftUpper(core::clamp(static_cast(pos.X), 0u, texture->getSize().Width), + core::clamp(static_cast(pos.Y), 0u, texture->getSize().Height)); + const core::rect clamped(leftUpper, + core::dimension2du(core::clamp(static_cast(size.Width), 0u, texture->getSize().Width), + core::clamp(static_cast(size.Height), 0u, texture->getSize().Height))); + if (!clamped.isValid()) + return 0; + u8* src = static_cast(texture->lock(ETLM_READ_ONLY)); + if (!src) + return 0; + IImage* image = new CImage(texture->getColorFormat(), clamped.getSize()); + u8* dst = static_cast(image->getData()); + src += clamped.UpperLeftCorner.Y * texture->getPitch() + image->getBytesPerPixel() * clamped.UpperLeftCorner.X; + for (u32 i=0; igetColorFormat(), clamped.getWidth(), dst, image->getColorFormat()); + src += texture->getPitch(); + dst += image->getPitch(); + } + texture->unlock(); + return image; + } +} + + +//! Sets the fog mode. +void CNullDriver::setFog(SColor color, E_FOG_TYPE fogType, f32 start, f32 end, + f32 density, bool pixelFog, bool rangeFog) +{ + FogColor = color; + FogType = fogType; + FogStart = start; + FogEnd = end; + FogDensity = density; + PixelFog = pixelFog; + RangeFog = rangeFog; +} + +//! Gets the fog mode. +void CNullDriver::getFog(SColor& color, E_FOG_TYPE& fogType, f32& start, f32& end, + f32& density, bool& pixelFog, bool& rangeFog) +{ + color = FogColor; + fogType = FogType; + start = FogStart; + end = FogEnd; + density = FogDensity; + pixelFog = PixelFog; + rangeFog = RangeFog; +} + +//! Draws a mesh buffer +void CNullDriver::drawMeshBuffer(const scene::IMeshBuffer* mb) +{ + if (!mb) + return; + + //IVertexBuffer and IIndexBuffer later + SHWBufferLink *HWBuffer=getBufferLink(mb); + + if (HWBuffer) + drawHardwareBuffer(HWBuffer); + else + drawVertexPrimitiveList(mb->getVertices(), mb->getVertexCount(), mb->getIndices(), mb->getPrimitiveCount(), mb->getVertexType(), mb->getPrimitiveType(), mb->getIndexType()); +} + + +//! Draws the normals of a mesh buffer +void CNullDriver::drawMeshBufferNormals(const scene::IMeshBuffer* mb, f32 length, SColor color) +{ + const u32 count = mb->getVertexCount(); + const bool normalize = mb->getMaterial().NormalizeNormals; + + for (u32 i=0; i < count; ++i) + { + core::vector3df normalizedNormal = mb->getNormal(i); + if (normalize) + normalizedNormal.normalize(); + + const core::vector3df& pos = mb->getPosition(i); + draw3DLine(pos, pos + (normalizedNormal * length), color); + } +} + + +CNullDriver::SHWBufferLink *CNullDriver::getBufferLink(const scene::IMeshBuffer* mb) +{ + if (!mb || !isHardwareBufferRecommend(mb)) + return 0; + + //search for hardware links + core::map< const scene::IMeshBuffer*,SHWBufferLink* >::Node* node = HWBufferMap.find(mb); + 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() +{ + core::map::ParentFirstIterator Iterator=HWBufferMap.getParentFirstIterator(); + + for (;!Iterator.atEnd();Iterator++) + { + SHWBufferLink *Link=Iterator.getNode()->getValue(); + + Link->LastUsed++; + if (Link->LastUsed>20000) + { + deleteHardwareBuffer(Link); + + // todo: needs better fix + Iterator = HWBufferMap.getParentFirstIterator(); + } + } +} + + +void CNullDriver::deleteHardwareBuffer(SHWBufferLink *HWBuffer) +{ + 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()); +} + + +//! Remove all hardware buffers +void CNullDriver::removeAllHardwareBuffers() +{ + while (HWBufferMap.size()) + 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()getType() != scene::ESNT_MESH) && (node->getType() != scene::ESNT_ANIMATED_MESH)) + return; + else if (node->getType() == scene::ESNT_MESH) + mesh = static_cast(node)->getMesh(); + else + mesh = static_cast(node)->getMesh()->getMesh(0); + if (!mesh) + return; + } + + //search for query + s32 index = OcclusionQueries.linear_search(SOccQuery(node)); + if (index != -1) + { + if (OcclusionQueries[index].Mesh != mesh) + { + OcclusionQueries[index].Mesh->drop(); + OcclusionQueries[index].Mesh = mesh; + mesh->grab(); + } + } + else + { + OcclusionQueries.push_back(SOccQuery(node, mesh)); + node->setAutomaticCulling(node->getAutomaticCulling() | scene::EAC_OCC_QUERY); + } +} + + +//! Remove occlusion query. +void CNullDriver::removeOcclusionQuery(scene::ISceneNode* node) +{ + //search for query + s32 index = OcclusionQueries.linear_search(SOccQuery(node)); + if (index != -1) + { + node->setAutomaticCulling(node->getAutomaticCulling() & ~scene::EAC_OCC_QUERY); + OcclusionQueries.erase(index); + } +} + + +//! Remove all occlusion queries. +void CNullDriver::removeAllOcclusionQueries() +{ + for (s32 i=OcclusionQueries.size()-1; i>=0; --i) + { + removeOcclusionQuery(OcclusionQueries[i].Node); + } +} + + +//! Run occlusion query. Draws mesh stored in query. +/** If the mesh shall be rendered visible, use +flag to enable the proper material setting. */ +void CNullDriver::runOcclusionQuery(scene::ISceneNode* node, bool visible) +{ + if(!node) + return; + s32 index = OcclusionQueries.linear_search(SOccQuery(node)); + if (index==-1) + return; + OcclusionQueries[index].Run=0; + if (!visible) + { + SMaterial mat; + mat.Lighting=false; + mat.AntiAliasing=0; + mat.ColorMask=ECP_NONE; + mat.GouraudShading=false; + mat.ZWriteEnable=EZW_OFF; + setMaterial(mat); + } + setTransform(video::ETS_WORLD, node->getAbsoluteTransformation()); + const scene::IMesh* mesh = OcclusionQueries[index].Mesh; + for (u32 i=0; igetMeshBufferCount(); ++i) + { + if (visible) + setMaterial(mesh->getMeshBuffer(i)->getMaterial()); + drawMeshBuffer(mesh->getMeshBuffer(i)); + } +} + + +//! Run all occlusion queries. Draws all meshes stored in queries. +/** If the meshes shall not be rendered visible, use +overrideMaterial to disable the color and depth buffer. */ +void CNullDriver::runAllOcclusionQueries(bool visible) +{ + for (u32 i=0; i1000) + removeOcclusionQuery(OcclusionQueries[i].Node); + } +} + + +//! Return query result. +/** Return value is the number of visible pixels/fragments. +The value is a safe approximation, i.e. can be larger then the +actual value of pixels. */ +u32 CNullDriver::getOcclusionQueryResult(scene::ISceneNode* node) const +{ + return ~0; +} + + +//! Create render target. +IRenderTarget* CNullDriver::addRenderTarget() +{ + return 0; +} + + +//! Remove render target. +void CNullDriver::removeRenderTarget(IRenderTarget* renderTarget) +{ + if (!renderTarget) + return; + + for (u32 i = 0; i < RenderTargets.size(); ++i) + { + if (RenderTargets[i] == renderTarget) + { + RenderTargets[i]->drop(); + RenderTargets.erase(i); + + return; + } + } +} + + +//! Remove all render targets. +void CNullDriver::removeAllRenderTargets() +{ + for (u32 i = 0; i < RenderTargets.size(); ++i) + RenderTargets[i]->drop(); + + RenderTargets.clear(); + + SharedRenderTarget = 0; +} + + +//! Only used by the internal engine. Used to notify the driver that +//! the window was resized. +void CNullDriver::OnResize(const core::dimension2d& 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) +{ + s32 i = addMaterialRenderer(m); + + if (m) + m->drop(); + + return i; +} + + +//! Adds a new material renderer to the video device. +s32 CNullDriver::addMaterialRenderer(IMaterialRenderer* renderer, const char* name) +{ + if (!renderer) + return -1; + + SMaterialRenderer r; + r.Renderer = renderer; + r.Name = name; + + if (name == 0 && (MaterialRenderers.size() < (sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 )) + { + // set name of built in renderer so that we don't have to implement name + // setting in all available renderers. + r.Name = sBuiltInMaterialTypeNames[MaterialRenderers.size()]; + } + + MaterialRenderers.push_back(r); + renderer->grab(); + + return MaterialRenderers.size()-1; +} + + +//! Sets the name of a material renderer. +void CNullDriver::setMaterialRendererName(s32 idx, const char* name) +{ + if (idx < s32(sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 || + idx >= (s32)MaterialRenderers.size()) + return; + + MaterialRenderers[idx].Name = name; +} + +void CNullDriver::swapMaterialRenderers(u32 idx1, u32 idx2, bool swapNames) +{ + if ( idx1 < MaterialRenderers.size() && idx2 < MaterialRenderers.size() ) + { + irr::core::swap(MaterialRenderers[idx1].Renderer, MaterialRenderers[idx2].Renderer); + if ( swapNames ) + irr::core::swap(MaterialRenderers[idx1].Name, MaterialRenderers[idx2].Name); + } +} + +//! Creates material attributes list from a material, usable for serialization and more. +io::IAttributes* CNullDriver::createAttributesFromMaterial(const video::SMaterial& material, + io::SAttributeReadWriteOptions* options) +{ + io::CAttributes* attr = new io::CAttributes(this); + + attr->addEnum("Type", material.MaterialType, sBuiltInMaterialTypeNames); + + attr->addColor("Ambient", material.AmbientColor); + attr->addColor("Diffuse", material.DiffuseColor); + attr->addColor("Emissive", material.EmissiveColor); + attr->addColor("Specular", material.SpecularColor); + + attr->addFloat("Shininess", material.Shininess); + attr->addFloat("Param1", material.MaterialTypeParam); + attr->addFloat("Param2", material.MaterialTypeParam2); + attr->addFloat("Thickness", material.Thickness); + + core::stringc prefix="Texture"; + u32 i; + for (i=0; iFlags&io::EARWF_USE_RELATIVE_PATHS) && options->Filename && texture) + { + io::path path = FileSystem->getRelativeFilename( + FileSystem->getAbsolutePath(material.getTexture(i)->getName()), options->Filename); + attr->addTexture((prefix+core::stringc(i+1)).c_str(), material.getTexture(i), path); + } + else + { + attr->addTexture((prefix+core::stringc(i+1)).c_str(), texture); + } + } + + attr->addBool("Wireframe", material.Wireframe); + attr->addBool("PointCloud", material.PointCloud); + attr->addBool("GouraudShading", material.GouraudShading); + attr->addBool("Lighting", material.Lighting); + attr->addEnum("ZWriteEnable", (irr::s32)material.ZWriteEnable, video::ZWriteNames); + attr->addInt("ZBuffer", material.ZBuffer); + attr->addBool("BackfaceCulling", material.BackfaceCulling); + attr->addBool("FrontfaceCulling", material.FrontfaceCulling); + attr->addBool("FogEnable", material.FogEnable); + attr->addBool("NormalizeNormals", material.NormalizeNormals); + attr->addBool("UseMipMaps", material.UseMipMaps); + attr->addInt("AntiAliasing", material.AntiAliasing); + attr->addInt("ColorMask", material.ColorMask); + attr->addInt("ColorMaterial", material.ColorMaterial); + attr->addInt("BlendOperation", material.BlendOperation); + attr->addFloat("BlendFactor", material.BlendFactor); + attr->addInt("PolygonOffsetFactor", material.PolygonOffsetFactor); + attr->addEnum("PolygonOffsetDirection", material.PolygonOffsetDirection, video::PolygonOffsetDirectionNames); + attr->addFloat("PolygonOffsetDepthBias", material.PolygonOffsetDepthBias); + attr->addFloat("PolygonOffsetSlopeScale", material.PolygonOffsetSlopeScale); + + // TODO: Would be nice to have a flag that only serializes rest of texture data when a texture pointer exists. + prefix = "BilinearFilter"; + for (i=0; iaddBool((prefix+core::stringc(i+1)).c_str(), material.TextureLayer[i].BilinearFilter); + prefix = "TrilinearFilter"; + for (i=0; iaddBool((prefix+core::stringc(i+1)).c_str(), material.TextureLayer[i].TrilinearFilter); + prefix = "AnisotropicFilter"; + for (i=0; iaddInt((prefix+core::stringc(i+1)).c_str(), material.TextureLayer[i].AnisotropicFilter); + prefix="TextureWrapU"; + for (i=0; iaddEnum((prefix+core::stringc(i+1)).c_str(), material.TextureLayer[i].TextureWrapU, aTextureClampNames); + prefix="TextureWrapV"; + for (i=0; iaddEnum((prefix+core::stringc(i+1)).c_str(), material.TextureLayer[i].TextureWrapV, aTextureClampNames); + prefix="TextureWrapW"; + for (i=0; iaddEnum((prefix+core::stringc(i+1)).c_str(), material.TextureLayer[i].TextureWrapW, aTextureClampNames); + prefix="LODBias"; + for (i=0; iaddInt((prefix+core::stringc(i+1)).c_str(), material.TextureLayer[i].LODBias); + + return attr; +} + + +//! Fills an SMaterial structure from attributes. +void CNullDriver::fillMaterialStructureFromAttributes(video::SMaterial& outMaterial, io::IAttributes* attr) +{ + outMaterial.MaterialType = video::EMT_SOLID; + + core::stringc name = attr->getAttributeAsString("Type"); + + u32 i; + + for ( i=0; i < MaterialRenderers.size(); ++i) + if ( name == MaterialRenderers[i].Name ) + { + outMaterial.MaterialType = (video::E_MATERIAL_TYPE)i; + break; + } + + outMaterial.AmbientColor = attr->getAttributeAsColor("Ambient", outMaterial.AmbientColor); + outMaterial.DiffuseColor = attr->getAttributeAsColor("Diffuse", outMaterial.DiffuseColor); + outMaterial.EmissiveColor = attr->getAttributeAsColor("Emissive", outMaterial.EmissiveColor); + outMaterial.SpecularColor = attr->getAttributeAsColor("Specular", outMaterial.SpecularColor); + + outMaterial.Shininess = attr->getAttributeAsFloat("Shininess", outMaterial.Shininess); + outMaterial.MaterialTypeParam = attr->getAttributeAsFloat("Param1", outMaterial.MaterialTypeParam); + outMaterial.MaterialTypeParam2 = attr->getAttributeAsFloat("Param2", outMaterial.MaterialTypeParam2); + outMaterial.Thickness = attr->getAttributeAsFloat("Thickness", outMaterial.Thickness); + + core::stringc prefix="Texture"; + for (i=0; igetAttributeAsTexture((prefix+core::stringc(i+1)).c_str())); + + outMaterial.Wireframe = attr->getAttributeAsBool("Wireframe", outMaterial.Wireframe); + outMaterial.PointCloud = attr->getAttributeAsBool("PointCloud", outMaterial.PointCloud); + outMaterial.GouraudShading = attr->getAttributeAsBool("GouraudShading", outMaterial.GouraudShading); + outMaterial.Lighting = attr->getAttributeAsBool("Lighting", outMaterial.Lighting); + + io::E_ATTRIBUTE_TYPE attType = attr->getAttributeType("ZWriteEnable"); + if (attType == io::EAT_BOOL ) // Before Irrlicht 1.9 + outMaterial.ZWriteEnable = attr->getAttributeAsBool("ZWriteEnable", outMaterial.ZWriteEnable != video::EZW_OFF ) ? video::EZW_AUTO : video::EZW_OFF; + else if (attType == io::EAT_ENUM ) + outMaterial.ZWriteEnable = (video::E_ZWRITE)attr->getAttributeAsEnumeration("ZWriteEnable", video::ZWriteNames, outMaterial.ZWriteEnable); + + outMaterial.ZBuffer = (u8)attr->getAttributeAsInt("ZBuffer", outMaterial.ZBuffer); + outMaterial.BackfaceCulling = attr->getAttributeAsBool("BackfaceCulling", outMaterial.BackfaceCulling); + outMaterial.FrontfaceCulling = attr->getAttributeAsBool("FrontfaceCulling", outMaterial.FrontfaceCulling); + outMaterial.FogEnable = attr->getAttributeAsBool("FogEnable", outMaterial.FogEnable); + outMaterial.NormalizeNormals = attr->getAttributeAsBool("NormalizeNormals", outMaterial.NormalizeNormals); + outMaterial.UseMipMaps = attr->getAttributeAsBool("UseMipMaps", outMaterial.UseMipMaps); + + outMaterial.AntiAliasing = attr->getAttributeAsInt("AntiAliasing", outMaterial.AntiAliasing); + outMaterial.ColorMask = attr->getAttributeAsInt("ColorMask", outMaterial.ColorMask); + outMaterial.ColorMaterial = attr->getAttributeAsInt("ColorMaterial", outMaterial.ColorMaterial); + outMaterial.BlendOperation = (video::E_BLEND_OPERATION)attr->getAttributeAsInt("BlendOperation", outMaterial.BlendOperation); + outMaterial.BlendFactor = attr->getAttributeAsFloat("BlendFactor", outMaterial.BlendFactor); + outMaterial.PolygonOffsetFactor = attr->getAttributeAsInt("PolygonOffsetFactor", outMaterial.PolygonOffsetFactor); + outMaterial.PolygonOffsetDirection = (video::E_POLYGON_OFFSET)attr->getAttributeAsEnumeration("PolygonOffsetDirection", video::PolygonOffsetDirectionNames, outMaterial.PolygonOffsetDirection); + outMaterial.PolygonOffsetDepthBias = attr->getAttributeAsFloat("PolygonOffsetDepthBias", outMaterial.PolygonOffsetDepthBias); + outMaterial.PolygonOffsetSlopeScale = attr->getAttributeAsFloat("PolygonOffsetSlopeScale", outMaterial.PolygonOffsetSlopeScale); + + prefix = "BilinearFilter"; + if (attr->existsAttribute(prefix.c_str())) // legacy + outMaterial.setFlag(EMF_BILINEAR_FILTER, attr->getAttributeAsBool(prefix.c_str())); + else + for (i=0; igetAttributeAsBool((prefix+core::stringc(i+1)).c_str(), outMaterial.TextureLayer[i].BilinearFilter); + + prefix = "TrilinearFilter"; + if (attr->existsAttribute(prefix.c_str())) // legacy + outMaterial.setFlag(EMF_TRILINEAR_FILTER, attr->getAttributeAsBool(prefix.c_str())); + else + for (i=0; igetAttributeAsBool((prefix+core::stringc(i+1)).c_str(), outMaterial.TextureLayer[i].TrilinearFilter); + + prefix = "AnisotropicFilter"; + if (attr->existsAttribute(prefix.c_str())) // legacy + outMaterial.setFlag(EMF_ANISOTROPIC_FILTER, attr->getAttributeAsBool(prefix.c_str())); + else + for (i=0; igetAttributeAsInt((prefix+core::stringc(i+1)).c_str(), outMaterial.TextureLayer[i].AnisotropicFilter); + + prefix = "TextureWrap"; + if (attr->existsAttribute(prefix.c_str())) // legacy + { + for (i=0; igetAttributeAsEnumeration((prefix+core::stringc(i+1)).c_str(), aTextureClampNames); + outMaterial.TextureLayer[i].TextureWrapV = outMaterial.TextureLayer[i].TextureWrapU; + outMaterial.TextureLayer[i].TextureWrapW = outMaterial.TextureLayer[i].TextureWrapW; + } + } + else + { + for (i=0; igetAttributeAsEnumeration((prefix+"U"+core::stringc(i+1)).c_str(), aTextureClampNames, outMaterial.TextureLayer[i].TextureWrapU); + outMaterial.TextureLayer[i].TextureWrapV = (E_TEXTURE_CLAMP)attr->getAttributeAsEnumeration((prefix+"V"+core::stringc(i+1)).c_str(), aTextureClampNames, outMaterial.TextureLayer[i].TextureWrapV); + outMaterial.TextureLayer[i].TextureWrapW = (E_TEXTURE_CLAMP)attr->getAttributeAsEnumeration((prefix+"W"+core::stringc(i+1)).c_str(), aTextureClampNames, outMaterial.TextureLayer[i].TextureWrapW); + } + } + + prefix="LODBias"; + for (i=0; igetAttributeAsInt((prefix+core::stringc(i+1)).c_str(), outMaterial.TextureLayer[i].LODBias); +} + + +//! Returns driver and operating system specific data about the IVideoDriver. +const SExposedVideoData& CNullDriver::getExposedVideoData() +{ + return ExposedData; +} + + +//! Returns type of video driver +E_DRIVER_TYPE CNullDriver::getDriverType() const +{ + return EDT_NULL; +} + + +//! deletes all material renderers +void CNullDriver::deleteMaterialRenders() +{ + // delete material renderers + for (u32 i=0; idrop(); + + MaterialRenderers.clear(); +} + + +//! Returns pointer to material renderer or null +IMaterialRenderer* CNullDriver::getMaterialRenderer(u32 idx) const +{ + if ( idx < MaterialRenderers.size() ) + return MaterialRenderers[idx].Renderer; + else + return 0; +} + + +//! Returns amount of currently available material renderers. +u32 CNullDriver::getMaterialRendererCount() const +{ + return MaterialRenderers.size(); +} + + +//! Returns name of the material renderer +const char* CNullDriver::getMaterialRendererName(u32 idx) const +{ + if ( idx < MaterialRenderers.size() ) + return MaterialRenderers[idx].Name.c_str(); + + return 0; +} + + +//! Returns pointer to the IGPUProgrammingServices interface. +IGPUProgrammingServices* CNullDriver::getGPUProgrammingServices() +{ + return this; +} + + +//! Adds a new material renderer to the VideoDriver, based on a high level shading language. +s32 CNullDriver::addHighLevelShaderMaterial( + const c8* vertexShaderProgram, + const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, + const c8* pixelShaderProgram, + const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, + const c8* geometryShaderProgram, + const c8* geometryShaderEntryPointName, + E_GEOMETRY_SHADER_TYPE gsCompileTarget, + scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType, + u32 verticesOut, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, + s32 userData) +{ + os::Printer::log("High level shader materials not available (yet) in this driver, sorry"); + return -1; +} + + +//! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description), +//! but tries to load the programs from files. +s32 CNullDriver::addHighLevelShaderMaterialFromFiles( + const io::path& vertexShaderProgramFileName, + const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, + const io::path& pixelShaderProgramFileName, + const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, + const io::path& geometryShaderProgramFileName, + const c8* geometryShaderEntryPointName, + E_GEOMETRY_SHADER_TYPE gsCompileTarget, + scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType, + u32 verticesOut, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, + s32 userData) +{ + io::IReadFile* vsfile = 0; + io::IReadFile* psfile = 0; + io::IReadFile* gsfile = 0; + + if (vertexShaderProgramFileName.size() ) + { + vsfile = FileSystem->createAndOpenFile(vertexShaderProgramFileName); + if (!vsfile) + { + os::Printer::log("Could not open vertex shader program file", + vertexShaderProgramFileName, ELL_WARNING); + } + } + + if (pixelShaderProgramFileName.size() ) + { + psfile = FileSystem->createAndOpenFile(pixelShaderProgramFileName); + if (!psfile) + { + os::Printer::log("Could not open pixel shader program file", + pixelShaderProgramFileName, ELL_WARNING); + } + } + + if (geometryShaderProgramFileName.size() ) + { + gsfile = FileSystem->createAndOpenFile(geometryShaderProgramFileName); + if (!gsfile) + { + os::Printer::log("Could not open geometry shader program file", + geometryShaderProgramFileName, ELL_WARNING); + } + } + + s32 result = addHighLevelShaderMaterialFromFiles( + vsfile, vertexShaderEntryPointName, vsCompileTarget, + psfile, pixelShaderEntryPointName, psCompileTarget, + gsfile, geometryShaderEntryPointName, gsCompileTarget, + inType, outType, verticesOut, + callback, baseMaterial, userData); + + if (psfile) + psfile->drop(); + + if (vsfile) + vsfile->drop(); + + if (gsfile) + gsfile->drop(); + + return result; +} + + +//! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description), +//! but tries to load the programs from files. +s32 CNullDriver::addHighLevelShaderMaterialFromFiles( + io::IReadFile* vertexShaderProgram, + const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, + io::IReadFile* pixelShaderProgram, + const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, + io::IReadFile* geometryShaderProgram, + const c8* geometryShaderEntryPointName, + E_GEOMETRY_SHADER_TYPE gsCompileTarget, + scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType, + u32 verticesOut, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, + s32 userData) +{ + c8* vs = 0; + c8* ps = 0; + c8* gs = 0; + + if (vertexShaderProgram) + { + const long size = vertexShaderProgram->getSize(); + if (size) + { + vs = new c8[size+1]; + vertexShaderProgram->read(vs, size); + vs[size] = 0; + } + } + + if (pixelShaderProgram) + { + const long size = pixelShaderProgram->getSize(); + if (size) + { + // if both handles are the same we must reset the file + if (pixelShaderProgram==vertexShaderProgram) + pixelShaderProgram->seek(0); + ps = new c8[size+1]; + pixelShaderProgram->read(ps, size); + ps[size] = 0; + } + } + + if (geometryShaderProgram) + { + const long size = geometryShaderProgram->getSize(); + if (size) + { + // if both handles are the same we must reset the file + if ((geometryShaderProgram==vertexShaderProgram) || + (geometryShaderProgram==pixelShaderProgram)) + geometryShaderProgram->seek(0); + gs = new c8[size+1]; + geometryShaderProgram->read(gs, size); + gs[size] = 0; + } + } + + s32 result = this->addHighLevelShaderMaterial( + vs, vertexShaderEntryPointName, vsCompileTarget, + ps, pixelShaderEntryPointName, psCompileTarget, + gs, geometryShaderEntryPointName, gsCompileTarget, + inType, outType, verticesOut, + callback, baseMaterial, userData); + + delete [] vs; + delete [] ps; + delete [] gs; + + return result; +} + + +//! Adds a new material renderer to the VideoDriver, using pixel and/or +//! vertex shaders to render geometry. +s32 CNullDriver::addShaderMaterial(const c8* vertexShaderProgram, + const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, + s32 userData) +{ + os::Printer::log("Shader materials not implemented yet in this driver, sorry."); + return -1; +} + + +//! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the +//! programs from files. +s32 CNullDriver::addShaderMaterialFromFiles(io::IReadFile* vertexShaderProgram, + io::IReadFile* pixelShaderProgram, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, + s32 userData) +{ + c8* vs = 0; + c8* ps = 0; + + if (vertexShaderProgram) + { + const long size = vertexShaderProgram->getSize(); + if (size) + { + vs = new c8[size+1]; + vertexShaderProgram->read(vs, size); + vs[size] = 0; + } + } + + if (pixelShaderProgram) + { + const long size = pixelShaderProgram->getSize(); + if (size) + { + ps = new c8[size+1]; + pixelShaderProgram->read(ps, size); + ps[size] = 0; + } + } + + s32 result = addShaderMaterial(vs, ps, callback, baseMaterial, userData); + + delete [] vs; + delete [] ps; + + return result; +} + + +//! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the +//! programs from files. +s32 CNullDriver::addShaderMaterialFromFiles(const io::path& vertexShaderProgramFileName, + const io::path& pixelShaderProgramFileName, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, + s32 userData) +{ + io::IReadFile* vsfile = 0; + io::IReadFile* psfile = 0; + + if (vertexShaderProgramFileName.size()) + { + vsfile = FileSystem->createAndOpenFile(vertexShaderProgramFileName); + if (!vsfile) + { + os::Printer::log("Could not open vertex shader program file", + vertexShaderProgramFileName, ELL_WARNING); + return -1; + } + } + + if (pixelShaderProgramFileName.size()) + { + psfile = FileSystem->createAndOpenFile(pixelShaderProgramFileName); + if (!psfile) + { + os::Printer::log("Could not open pixel shader program file", + pixelShaderProgramFileName, ELL_WARNING); + if (vsfile) + vsfile->drop(); + return -1; + } + } + + s32 result = addShaderMaterialFromFiles(vsfile, psfile, callback, + baseMaterial, userData); + + if (psfile) + psfile->drop(); + + if (vsfile) + vsfile->drop(); + + return result; +} + + +//! Creates a render target texture. +ITexture* CNullDriver::addRenderTargetTexture(const core::dimension2d& size, + const io::path&name, const ECOLOR_FORMAT format) +{ + return 0; +} + +ITexture* CNullDriver::addRenderTargetTextureCubemap(const irr::u32 sideLen, + const io::path& name, const ECOLOR_FORMAT format) +{ + return 0; +} + +void CNullDriver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil) +{ +} + + +//! Returns a pointer to the mesh manipulator. +scene::IMeshManipulator* CNullDriver::getMeshManipulator() +{ + return MeshManipulator; +} + + +//! Returns an image created from the last rendered frame. +IImage* CNullDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target) +{ + return 0; +} + + +// prints renderer version +void CNullDriver::printVersion() +{ + core::stringw namePrint = L"Using renderer: "; + namePrint += getName(); + os::Printer::log(namePrint.c_str(), ELL_INFORMATION); +} + + +//! creates a video driver +IVideoDriver* createNullDriver(io::IFileSystem* io, const core::dimension2d& screenSize) +{ + CNullDriver* nullDriver = new CNullDriver(io, screenSize); + + // create empty material renderers + for(u32 i=0; sBuiltInMaterialTypeNames[i]; ++i) + { + IMaterialRenderer* imr = new IMaterialRenderer(); + nullDriver->addMaterialRenderer(imr); + imr->drop(); + } + + return nullDriver; +} + + +//! Set/unset 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 plane: The plane itself. +//! \param enable: If true, enable the clipping plane else disable it. +bool CNullDriver::setClipPlane(u32 index, const core::plane3df& plane, bool enable) +{ + return false; +} + + +//! Enable/disable a clipping plane. +void CNullDriver::enableClipPlane(u32 index, bool enable) +{ + // not necessary +} + + +ITexture* CNullDriver::createRenderTargetTexture(const core::dimension2d& size, + const c8* name) +{ + os::Printer::log("createRenderTargetTexture is deprecated, use addRenderTargetTexture instead"); + ITexture* tex = addRenderTargetTexture(size, name); + tex->grab(); + return tex; +} + + +void CNullDriver::setMinHardwareBufferVertexCount(u32 count) +{ + MinVertexCountForVBO = count; +} + + +SOverrideMaterial& CNullDriver::getOverrideMaterial() +{ + return OverrideMaterial; +} + + +//! Get the 2d override material for altering its values +SMaterial& CNullDriver::getMaterial2D() +{ + return OverrideMaterial2D; +} + + +//! Enable the 2d override material +void CNullDriver::enableMaterial2D(bool enable) +{ + OverrideMaterial2DEnabled=enable; +} + + +core::dimension2du CNullDriver::getMaxTextureSize() const +{ + return core::dimension2du(0x10000,0x10000); // maybe large enough +} + +bool CNullDriver::needsTransparentRenderPass(const irr::video::SMaterial& material) const +{ + // TODO: I suspect it would be nice if the material had an enum for further control. + // Especially it probably makes sense to allow disabling transparent render pass as soon as material.ZWriteEnable is on. + // But then we might want an enum for the renderpass in material instead of just a transparency flag in material - and that's more work. + // Or we could at least set return false when material.ZWriteEnable is EZW_ON? Still considering that... + // Be careful - this function is deeply connected to getWriteZBuffer as transparent render passes are usually about rendering with + // zwrite disabled and getWriteZBuffer calls this function. + + video::IMaterialRenderer* rnd = getMaterialRenderer(material.MaterialType); + // TODO: I suspect IMaterialRenderer::isTransparent also often could use SMaterial as parameter + // We could for example then get rid of IsTransparent function in SMaterial and move that to the software material renderer. + if (rnd && rnd->isTransparent()) + return true; + + return false; +} + + +//! Color conversion convenience function +/** Convert an image (as array of pixels) from source to destination +array, thereby converting the color format. The pixel size is +determined by the color formats. +\param sP Pointer to source +\param sF Color format of source +\param sN Number of pixels to convert, both array must be large enough +\param dP Pointer to destination +\param dF Color format of destination +*/ +void CNullDriver::convertColor(const void* sP, ECOLOR_FORMAT sF, s32 sN, + void* dP, ECOLOR_FORMAT dF) const +{ + video::CColorConverter::convert_viaFormat(sP, sF, sN, dP, dF); +} + + +} // end namespace +} // end namespace diff --git a/source/Irrlicht/CNullDriver.h b/source/Irrlicht/CNullDriver.h new file mode 100644 index 00000000..ebd700de --- /dev/null +++ b/source/Irrlicht/CNullDriver.h @@ -0,0 +1,909 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_VIDEO_NULL_H_INCLUDED__ +#define __C_VIDEO_NULL_H_INCLUDED__ + +#include "IVideoDriver.h" +#include "IFileSystem.h" +#include "IImagePresenter.h" +#include "IGPUProgrammingServices.h" +#include "irrArray.h" +#include "irrString.h" +#include "irrMap.h" +#include "IAttributes.h" +#include "IMesh.h" +#include "IMeshBuffer.h" +#include "IMeshSceneNode.h" +#include "CFPSCounter.h" +#include "S3DVertex.h" +#include "SVertexIndex.h" +#include "SLight.h" +#include "SExposedVideoData.h" + +#ifdef _MSC_VER +#pragma warning( disable: 4996) +#endif + +namespace irr +{ +namespace io +{ + class IWriteFile; + class IReadFile; +} // end namespace io +namespace video +{ + class IImageLoader; + class IImageWriter; + + class CNullDriver : public IVideoDriver, public IGPUProgrammingServices + { + public: + + //! constructor + CNullDriver(io::IFileSystem* io, const core::dimension2d& screenSize); + + //! destructor + virtual ~CNullDriver(); + + virtual bool beginScene(u16 clearFlag, SColor clearColor = SColor(255,0,0,0), f32 clearDepth = 1.f, u8 clearStencil = 0, + const SExposedVideoData& videoData = SExposedVideoData(), core::rect* sourceRect = 0) _IRR_OVERRIDE_; + + virtual bool endScene() _IRR_OVERRIDE_; + + //! Disable a feature of the driver. + virtual void disableFeature(E_VIDEO_DRIVER_FEATURE feature, bool flag=true) _IRR_OVERRIDE_; + + //! queries the features of the driver, returns true if feature is available + virtual bool queryFeature(E_VIDEO_DRIVER_FEATURE feature) const _IRR_OVERRIDE_; + + //! Get attributes of the actual video driver + virtual const io::IAttributes& getDriverAttributes() const _IRR_OVERRIDE_; + + //! sets transformation + virtual void setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) _IRR_OVERRIDE_; + + //! Retrieve the number of image loaders + virtual u32 getImageLoaderCount() const _IRR_OVERRIDE_; + + //! Retrieve the given image loader + virtual IImageLoader* getImageLoader(u32 n) _IRR_OVERRIDE_; + + //! Retrieve the number of image writers + virtual u32 getImageWriterCount() const _IRR_OVERRIDE_; + + //! Retrieve the given image writer + virtual IImageWriter* getImageWriter(u32 n) _IRR_OVERRIDE_; + + //! sets a material + virtual void setMaterial(const SMaterial& material) _IRR_OVERRIDE_; + + //! loads a Texture + virtual ITexture* getTexture(const io::path& filename) _IRR_OVERRIDE_; + + //! loads a Texture + virtual ITexture* getTexture(io::IReadFile* file) _IRR_OVERRIDE_; + + //! Returns a texture by index + virtual ITexture* getTextureByIndex(u32 index) _IRR_OVERRIDE_; + + //! Returns amount of textures currently loaded + virtual u32 getTextureCount() const _IRR_OVERRIDE_; + + //! Renames a texture + virtual void renameTexture(ITexture* texture, const io::path& newName) _IRR_OVERRIDE_; + + virtual ITexture* addTexture(const core::dimension2d& size, const io::path& name, ECOLOR_FORMAT format = ECF_A8R8G8B8) _IRR_OVERRIDE_; + + virtual ITexture* addTexture(const io::path& name, IImage* image) _IRR_OVERRIDE_; + + virtual ITexture* addTextureCubemap(const io::path& name, IImage* imagePosX, IImage* imageNegX, IImage* imagePosY, + IImage* imageNegY, IImage* imagePosZ, IImage* imageNegZ) _IRR_OVERRIDE_; + + virtual ITexture* addTextureCubemap(const irr::u32 sideLen, const io::path& name, ECOLOR_FORMAT format = ECF_A8R8G8B8) _IRR_OVERRIDE_; + + virtual bool setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor = SColor(255,0,0,0), + f32 clearDepth = 1.f, u8 clearStencil = 0) _IRR_OVERRIDE_; + + virtual bool setRenderTarget(ITexture* texture, u16 clearFlag, SColor clearColor = SColor(255,0,0,0), + f32 clearDepth = 1.f, u8 clearStencil = 0) _IRR_OVERRIDE_; + + //! sets a viewport + virtual void setViewPort(const core::rect& area) _IRR_OVERRIDE_; + + //! gets the area of the current viewport + virtual const core::rect& getViewPort() const _IRR_OVERRIDE_; + + //! draws a vertex primitive list + virtual void drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType=EVT_STANDARD, scene::E_PRIMITIVE_TYPE pType=scene::EPT_TRIANGLES, + E_INDEX_TYPE iType=EIT_16BIT) _IRR_OVERRIDE_; + + //! draws a vertex primitive list in 2d + virtual void draw2DVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType=EVT_STANDARD, scene::E_PRIMITIVE_TYPE pType=scene::EPT_TRIANGLES, + E_INDEX_TYPE iType=EIT_16BIT) _IRR_OVERRIDE_; + + //! Draws a 3d line. + virtual void draw3DLine(const core::vector3df& start, + const core::vector3df& end, SColor color = SColor(255,255,255,255)) _IRR_OVERRIDE_; + + //! Draws a 3d triangle. + virtual void draw3DTriangle(const core::triangle3df& triangle, + SColor color = SColor(255,255,255,255)) _IRR_OVERRIDE_; + + //! Draws a 3d axis aligned box. + virtual void draw3DBox(const core::aabbox3d& box, + SColor color = SColor(255,255,255,255)) _IRR_OVERRIDE_; + + //! draws an 2d image + virtual void draw2DImage(const video::ITexture* texture, const core::position2d& destPos, bool useAlphaChannelOfTexture) _IRR_OVERRIDE_; + + //! draws a set of 2d images, using a color and the alpha + /** channel of the texture if desired. The images are drawn + beginning at pos and concatenated in one line. All drawings + are clipped against clipRect (if != 0). + The subtextures are defined by the array of sourceRects + and are chosen by the indices given. + \param texture: Texture to be drawn. + \param pos: Upper left 2d destination position where the image will be drawn. + \param sourceRects: Source rectangles of the image. + \param indices: List of indices which choose the actual rectangle used each time. + \param kerningWidth: offset on position + \param clipRect: Pointer to rectangle on the screen where the image is clipped to. + This pointer can be 0. Then the image is not clipped. + \param color: Color with which the image is colored. + Note that the alpha component is used: If alpha is other than 255, the image will be transparent. + \param useAlphaChannelOfTexture: If true, the alpha channel of the texture is + used to draw the image. */ + virtual void draw2DImageBatch(const video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, + s32 kerningWidth = 0, + const core::rect* clipRect = 0, + SColor color=SColor(255,255,255,255), + bool useAlphaChannelOfTexture=false) _IRR_OVERRIDE_; + + //! Draws a set of 2d images, using a color and the alpha channel of the texture. + /** All drawings are clipped against clipRect (if != 0). + The subtextures are defined by the array of sourceRects and are + positioned using the array of positions. + \param texture Texture to be drawn. + \param pos Array of upper left 2d destinations where the images + will be drawn. + \param sourceRects Source rectangles of the image. + \param clipRect Pointer to rectangle on the screen where the + images are clipped to. + If this pointer is 0 then the image is not clipped. + \param color Color with which the image is drawn. + Note that the alpha component is used. If alpha is other than + 255, the image will be transparent. + \param useAlphaChannelOfTexture: If true, the alpha channel of + the texture is used to draw the image. */ + virtual void draw2DImageBatch(const video::ITexture* texture, + const core::array >& positions, + const core::array >& sourceRects, + const core::rect* clipRect=0, + SColor color=SColor(255,255,255,255), + bool useAlphaChannelOfTexture=false) _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! Draws a part of the texture into the rectangle. + 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) _IRR_OVERRIDE_; + + //! Draws a 2d rectangle + virtual void draw2DRectangle(SColor color, const core::rect& pos, const core::rect* clip = 0) _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! Draws the outline of a 2d rectangle + virtual void draw2DRectangleOutline(const core::recti& pos, SColor color=SColor(255,255,255,255)) _IRR_OVERRIDE_; + + //! Draws a 2d line. + virtual void draw2DLine(const core::position2d& start, + const core::position2d& end, + SColor color=SColor(255,255,255,255)) _IRR_OVERRIDE_; + + //! Draws a pixel + virtual void drawPixel(u32 x, u32 y, const SColor & color) _IRR_OVERRIDE_; + + //! Draws a non filled concyclic reqular 2d polygon. + virtual void draw2DPolygon(core::position2d center, + f32 radius, video::SColor Color, s32 vertexCount) _IRR_OVERRIDE_; + + virtual void setFog(SColor color=SColor(0,255,255,255), + E_FOG_TYPE fogType=EFT_FOG_LINEAR, + f32 start=50.0f, f32 end=100.0f, f32 density=0.01f, + bool pixelFog=false, bool rangeFog=false) _IRR_OVERRIDE_; + + virtual void getFog(SColor& color, E_FOG_TYPE& fogType, + f32& start, f32& end, f32& density, + bool& pixelFog, bool& rangeFog) _IRR_OVERRIDE_; + + //! get color format of the current color buffer + virtual ECOLOR_FORMAT getColorFormat() const _IRR_OVERRIDE_; + + //! get screen size + virtual const core::dimension2d& getScreenSize() const _IRR_OVERRIDE_; + + //! get current render target + IRenderTarget* getCurrentRenderTarget() const; + + //! get render target size + virtual const core::dimension2d& getCurrentRenderTargetSize() const _IRR_OVERRIDE_; + + // get current frames per second value + virtual s32 getFPS() const _IRR_OVERRIDE_; + + //! returns amount of primitives (mostly triangles) were drawn in the last frame. + //! very useful method for statistics. + virtual u32 getPrimitiveCountDrawn( u32 param = 0 ) const _IRR_OVERRIDE_; + + //! deletes all dynamic lights there are + virtual void deleteAllDynamicLights() _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! returns the maximal amount of dynamic lights the device can handle + virtual u32 getMaximalDynamicLightAmount() const _IRR_OVERRIDE_; + + //! \return Returns the name of the video driver. Example: In case of the DIRECT3D8 + //! driver, it would return "Direct3D8.1". + virtual const wchar_t* getName() const _IRR_OVERRIDE_; + + //! 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. + virtual void setAmbientLight(const SColorf& color) _IRR_OVERRIDE_; + + //! Get the global ambient light currently used by the driver + virtual const SColorf& getAmbientLight() const _IRR_OVERRIDE_; + + //! Adds an external image loader to the engine. + virtual void addExternalImageLoader(IImageLoader* loader) _IRR_OVERRIDE_; + + //! Adds an external image writer to the engine. + virtual void addExternalImageWriter(IImageWriter* writer) _IRR_OVERRIDE_; + + //! 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. + virtual void drawStencilShadowVolume(const core::array& triangles, + bool zfail=true, u32 debugDataVisible=0) _IRR_OVERRIDE_; + + //! 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. + virtual void drawStencilShadow(bool clearStencilBuffer=false, + video::SColor leftUpEdge = video::SColor(0,0,0,0), + video::SColor rightUpEdge = video::SColor(0,0,0,0), + video::SColor leftDownEdge = video::SColor(0,0,0,0), + video::SColor rightDownEdge = video::SColor(0,0,0,0)) _IRR_OVERRIDE_; + + //! Returns current amount of dynamic lights set + //! \return Current amount of dynamic lights set + virtual u32 getDynamicLightCount() const _IRR_OVERRIDE_; + + //! Returns light data which was previously set with IVideDriver::addDynamicLight(). + //! \param idx: Zero based index of the light. Must be greater than 0 and smaller + //! than IVideoDriver()::getDynamicLightCount. + //! \return Light data. + virtual const SLight& getDynamicLight(u32 idx) const _IRR_OVERRIDE_; + + //! Removes a texture from the texture cache and deletes it, freeing lot of + //! memory. + virtual void removeTexture(ITexture* texture) _IRR_OVERRIDE_; + + //! Removes all texture from the texture cache and deletes them, freeing lot of + //! memory. + virtual void removeAllTextures() _IRR_OVERRIDE_; + + //! Creates a render target texture. + virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, + const io::path& name, const ECOLOR_FORMAT format = ECF_UNKNOWN) _IRR_OVERRIDE_; + + //! Creates a render target texture for a cubemap + ITexture* addRenderTargetTextureCubemap(const irr::u32 sideLen, + const io::path& name, const ECOLOR_FORMAT format) _IRR_OVERRIDE_; + + //! Creates an 1bit alpha channel of the texture based of an color key. + virtual void makeColorKeyTexture(video::ITexture* texture, video::SColor color, bool zeroTexels) const _IRR_OVERRIDE_; + + //! Creates an 1bit alpha channel of the texture based of an color key position. + virtual void makeColorKeyTexture(video::ITexture* texture, core::position2d colorKeyPixelPos, + bool zeroTexels) const _IRR_OVERRIDE_; + + //! Creates a normal map from a height map texture. + //! \param amplitude: Constant value by which the height information is multiplied. + virtual void makeNormalMapTexture(video::ITexture* texture, f32 amplitude=1.0f) const _IRR_OVERRIDE_; + + //! Returns the maximum amount of primitives (mostly vertices) which + //! the device is able to render with one drawIndexedTriangleList + //! call. + virtual u32 getMaximalPrimitiveCount() const _IRR_OVERRIDE_; + + //! Enables or disables a texture creation flag. + virtual void setTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag, bool enabled) _IRR_OVERRIDE_; + + //! Returns if a texture creation flag is enabled or disabled. + virtual bool getTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag) const _IRR_OVERRIDE_; + + virtual core::array createImagesFromFile(const io::path& filename, E_TEXTURE_TYPE* type = 0) _IRR_OVERRIDE_; + + virtual core::array createImagesFromFile(io::IReadFile* file, E_TEXTURE_TYPE* type = 0) _IRR_OVERRIDE_; + + //! Creates a software image from a byte array. + /** \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. */ + virtual IImage* createImageFromData(ECOLOR_FORMAT format, + const core::dimension2d& size, void *data, bool ownForeignMemory = false, + bool deleteMemory = true) _IRR_OVERRIDE_; + + //! Creates an empty software image. + virtual IImage* createImage(ECOLOR_FORMAT format, const core::dimension2d& size) _IRR_OVERRIDE_; + + //! Creates a software image from another image. + virtual IImage* createImage(ECOLOR_FORMAT format, IImage *imageToCopy) _IRR_OVERRIDE_; + + //! Creates a software image from part of another image. + virtual IImage* createImage(IImage* imageToCopy, + const core::position2d& pos, + const core::dimension2d& size) _IRR_OVERRIDE_; + + //! Creates a software image from part of a texture. + virtual IImage* createImage(ITexture* texture, + const core::position2d& pos, + const core::dimension2d& size) _IRR_OVERRIDE_; + + //! Draws a mesh buffer + virtual void drawMeshBuffer(const scene::IMeshBuffer* mb) _IRR_OVERRIDE_; + + //! Draws the normals of a mesh buffer + virtual void drawMeshBufferNormals(const scene::IMeshBuffer* mb, f32 length=10.f, + SColor color=0xffffffff) _IRR_OVERRIDE_; + + //! Check if the driver supports creating textures with the given color format + virtual bool queryTextureFormat(ECOLOR_FORMAT format) const _IRR_OVERRIDE_ + { + return false; + } + + protected: + struct SHWBufferLink + { + SHWBufferLink(const scene::IMeshBuffer *_MeshBuffer) + :MeshBuffer(_MeshBuffer), + ChangedID_Vertex(0),ChangedID_Index(0),LastUsed(0), + Mapped_Vertex(scene::EHM_NEVER),Mapped_Index(scene::EHM_NEVER) + { + if (MeshBuffer) + MeshBuffer->grab(); + } + + virtual ~SHWBufferLink() + { + if (MeshBuffer) + MeshBuffer->drop(); + } + + const scene::IMeshBuffer *MeshBuffer; + u32 ChangedID_Vertex; + u32 ChangedID_Index; + u32 LastUsed; + scene::E_HARDWARE_MAPPING Mapped_Vertex; + scene::E_HARDWARE_MAPPING Mapped_Index; + }; + + //! Gets hardware buffer link from a meshbuffer (may create or update buffer) + virtual SHWBufferLink *getBufferLink(const scene::IMeshBuffer* mb); + + //! updates hardware buffer if needed (only some drivers can) + virtual bool updateHardwareBuffer(SHWBufferLink *HWBuffer) {return false;} + + //! Draw hardware buffer (only some drivers can) + virtual void drawHardwareBuffer(SHWBufferLink *HWBuffer) {} + + //! Delete hardware buffer + virtual void deleteHardwareBuffer(SHWBufferLink *HWBuffer); + + //! Create hardware buffer from mesh (only some drivers can) + virtual SHWBufferLink *createHardwareBuffer(const scene::IMeshBuffer* mb) {return 0;} + + public: + //! Remove hardware buffer + virtual void removeHardwareBuffer(const scene::IMeshBuffer* mb) _IRR_OVERRIDE_; + + //! Remove all hardware buffers + virtual void removeAllHardwareBuffers() _IRR_OVERRIDE_; + + //! Update all hardware buffers, remove unused ones + virtual void updateAllHardwareBuffers(); + + //! is vbo recommended on this mesh? + virtual bool isHardwareBufferRecommend(const scene::IMeshBuffer* mb); + + //! Create occlusion query. + /** Use node for identification and mesh for occlusion test. */ + virtual void addOcclusionQuery(scene::ISceneNode* node, + const scene::IMesh* mesh=0) _IRR_OVERRIDE_; + + //! Remove occlusion query. + virtual void removeOcclusionQuery(scene::ISceneNode* node) _IRR_OVERRIDE_; + + //! Remove all occlusion queries. + virtual void removeAllOcclusionQueries() _IRR_OVERRIDE_; + + //! Run occlusion query. Draws mesh stored in query. + /** If the mesh shall not be rendered visible, use + overrideMaterial to disable the color and depth buffer. */ + virtual void runOcclusionQuery(scene::ISceneNode* node, bool visible=false) _IRR_OVERRIDE_; + + //! Run all occlusion queries. Draws all meshes stored in queries. + /** If the meshes shall not be rendered visible, use + overrideMaterial to disable the color and depth buffer. */ + virtual void runAllOcclusionQueries(bool visible=false) _IRR_OVERRIDE_; + + //! Update occlusion query. Retrieves results from GPU. + /** If the query shall not block, set the flag to false. + Update might not occur in this case, though */ + virtual void updateOcclusionQuery(scene::ISceneNode* node, bool block=true) _IRR_OVERRIDE_; + + //! Update all occlusion queries. Retrieves results from GPU. + /** If the query shall not block, set the flag to false. + Update might not occur in this case, though */ + virtual void updateAllOcclusionQueries(bool block=true) _IRR_OVERRIDE_; + + //! Return query result. + /** Return value is the number of visible pixels/fragments. + The value is a safe approximation, i.e. can be larger than the + actual value of pixels. */ + virtual u32 getOcclusionQueryResult(scene::ISceneNode* node) const _IRR_OVERRIDE_; + + //! Create render target. + virtual IRenderTarget* addRenderTarget() _IRR_OVERRIDE_; + + //! Remove render target. + virtual void removeRenderTarget(IRenderTarget* renderTarget) _IRR_OVERRIDE_; + + //! Remove all render targets. + virtual void removeAllRenderTargets() _IRR_OVERRIDE_; + + //! Only used by the engine internally. + /** Used to notify the driver that the window was resized. */ + virtual void OnResize(const core::dimension2d& size) _IRR_OVERRIDE_; + + //! Adds a new material renderer to the video device. + virtual s32 addMaterialRenderer(IMaterialRenderer* renderer, + const char* name = 0) _IRR_OVERRIDE_; + + //! Returns driver and operating system specific data about the IVideoDriver. + virtual const SExposedVideoData& getExposedVideoData() _IRR_OVERRIDE_; + + //! Returns type of video driver + virtual E_DRIVER_TYPE getDriverType() const _IRR_OVERRIDE_; + + //! Returns the transformation set by setTransform + virtual const core::matrix4& getTransform(E_TRANSFORMATION_STATE state) const _IRR_OVERRIDE_; + + //! Returns pointer to the IGPUProgrammingServices interface. + virtual IGPUProgrammingServices* getGPUProgrammingServices() _IRR_OVERRIDE_; + + //! Adds a new material renderer to the VideoDriver, using pixel and/or + //! vertex shaders to render geometry. + virtual s32 addShaderMaterial(const c8* vertexShaderProgram = 0, + const c8* pixelShaderProgram = 0, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData=0) _IRR_OVERRIDE_; + + //! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the + //! programs from files. + virtual s32 addShaderMaterialFromFiles(io::IReadFile* vertexShaderProgram = 0, + io::IReadFile* pixelShaderProgram = 0, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData=0) _IRR_OVERRIDE_; + + //! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the + //! programs from files. + virtual s32 addShaderMaterialFromFiles(const io::path& vertexShaderProgramFileName, + const io::path& pixelShaderProgramFileName, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData=0) _IRR_OVERRIDE_; + + //! Returns pointer to material renderer or null + virtual IMaterialRenderer* getMaterialRenderer(u32 idx) const _IRR_OVERRIDE_; + + //! Returns amount of currently available material renderers. + virtual u32 getMaterialRendererCount() const _IRR_OVERRIDE_; + + //! Returns name of the material renderer + virtual const char* getMaterialRendererName(u32 idx) const _IRR_OVERRIDE_; + + //! Adds a new material renderer to the VideoDriver, based on a high level shading + //! language. Currently only HLSL in D3D9 is supported. + virtual s32 addHighLevelShaderMaterial( + const c8* vertexShaderProgram, + const c8* vertexShaderEntryPointName = 0, + E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1, + const c8* pixelShaderProgram = 0, + const c8* pixelShaderEntryPointName = 0, + E_PIXEL_SHADER_TYPE psCompileTarget = EPST_PS_1_1, + const c8* geometryShaderProgram = 0, + const c8* geometryShaderEntryPointName = "main", + E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0, + scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES, + scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP, + u32 verticesOut = 0, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData = 0) _IRR_OVERRIDE_; + + //! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description), + //! but tries to load the programs from files. + virtual s32 addHighLevelShaderMaterialFromFiles( + const io::path& vertexShaderProgramFile, + const c8* vertexShaderEntryPointName = "main", + E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1, + const io::path& pixelShaderProgramFile = "", + const c8* pixelShaderEntryPointName = "main", + E_PIXEL_SHADER_TYPE psCompileTarget = EPST_PS_1_1, + const io::path& geometryShaderProgramFileName="", + const c8* geometryShaderEntryPointName = "main", + E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0, + scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES, + scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP, + u32 verticesOut = 0, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData = 0) _IRR_OVERRIDE_; + + //! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description), + //! but tries to load the programs from files. + virtual s32 addHighLevelShaderMaterialFromFiles( + io::IReadFile* vertexShaderProgram, + const c8* vertexShaderEntryPointName = "main", + E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1, + io::IReadFile* pixelShaderProgram = 0, + const c8* pixelShaderEntryPointName = "main", + E_PIXEL_SHADER_TYPE psCompileTarget = EPST_PS_1_1, + io::IReadFile* geometryShaderProgram= 0, + const c8* geometryShaderEntryPointName = "main", + E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0, + scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES, + scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP, + u32 verticesOut = 0, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData = 0) _IRR_OVERRIDE_; + + //! Returns a pointer to the mesh manipulator. + virtual scene::IMeshManipulator* getMeshManipulator() _IRR_OVERRIDE_; + + virtual void clearBuffers(u16 flag, SColor color = SColor(255,0,0,0), f32 depth = 1.f, u8 stencil = 0) _IRR_OVERRIDE_; + + //! Returns an image created from the last rendered frame. + virtual IImage* createScreenShot(video::ECOLOR_FORMAT format=video::ECF_UNKNOWN, video::E_RENDER_TARGET target=video::ERT_FRAME_BUFFER) _IRR_OVERRIDE_; + + //! Writes the provided image to disk file + virtual bool writeImageToFile(IImage* image, const io::path& filename, u32 param = 0) _IRR_OVERRIDE_; + + //! Writes the provided image to a file. + virtual bool writeImageToFile(IImage* image, io::IWriteFile * file, u32 param = 0) _IRR_OVERRIDE_; + + //! Sets the name of a material renderer. + virtual void setMaterialRendererName(s32 idx, const char* name) _IRR_OVERRIDE_; + + //! Swap the material renderers used for certain id's + virtual void swapMaterialRenderers(u32 idx1, u32 idx2, bool swapNames) _IRR_OVERRIDE_; + + //! Creates material attributes list from a material, usable for serialization and more. + virtual io::IAttributes* createAttributesFromMaterial(const video::SMaterial& material, + io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! Fills an SMaterial structure from attributes. + virtual void fillMaterialStructureFromAttributes(video::SMaterial& outMaterial, io::IAttributes* attributes) _IRR_OVERRIDE_; + + //! looks if the image is already loaded + virtual video::ITexture* findTexture(const io::path& filename) _IRR_OVERRIDE_; + + //! Set/unset 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 plane: The plane itself. + //! \param enable: If true, enable the clipping plane else disable it. + virtual bool setClipPlane(u32 index, const core::plane3df& plane, bool enable=false) _IRR_OVERRIDE_; + + //! 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. + virtual void enableClipPlane(u32 index, bool enable) _IRR_OVERRIDE_; + + //! Returns the graphics card vendor name. + virtual core::stringc getVendorInfo() _IRR_OVERRIDE_ {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) _IRR_OVERRIDE_; + + //! Get the global Material, which might override local materials. + /** Depending on the enable flags, values from this Material + are used to override those of local materials of some + meshbuffer being rendered. */ + virtual SOverrideMaterial& getOverrideMaterial() _IRR_OVERRIDE_; + + //! Get the 2d override material for altering its values + virtual SMaterial& getMaterial2D() _IRR_OVERRIDE_; + + //! Enable the 2d override material + virtual void enableMaterial2D(bool enable=true) _IRR_OVERRIDE_; + + //! Only used by the engine internally. + virtual void setAllowZWriteOnTransparent(bool flag) _IRR_OVERRIDE_ + { AllowZWriteOnTransparent=flag; } + + //! Returns the maximum texture size supported. + virtual core::dimension2du getMaxTextureSize() const _IRR_OVERRIDE_; + + //! Used by some SceneNodes to check if a material should be rendered in the transparent render pass + virtual bool needsTransparentRenderPass(const irr::video::SMaterial& material) const _IRR_OVERRIDE_; + + //! Color conversion convenience function + /** Convert an image (as array of pixels) from source to destination + array, thereby converting the color format. The pixel size is + determined by the color formats. + \param sP Pointer to source + \param sF Color format of source + \param sN Number of pixels to convert, both array must be large enough + \param dP Pointer to destination + \param dF Color format of destination + */ + virtual void convertColor(const void* sP, ECOLOR_FORMAT sF, s32 sN, + void* dP, ECOLOR_FORMAT dF) const _IRR_OVERRIDE_; + + //! deprecated method + virtual ITexture* createRenderTargetTexture(const core::dimension2d& size, + const c8* name=0); + + virtual bool checkDriverReset() _IRR_OVERRIDE_ {return false;} + protected: + + //! deletes all textures + void deleteAllTextures(); + + //! opens the file and loads it into the surface + ITexture* loadTextureFromFile(io::IReadFile* file, const io::path& hashName = ""); + + //! adds a surface, not loaded or created by the Irrlicht Engine + void addTexture(ITexture* surface); + + virtual ITexture* createDeviceDependentTexture(const io::path& name, IImage* image); + + virtual ITexture* createDeviceDependentTextureCubemap(const io::path& name, const core::array& image); + + //! checks triangle count and print warning if wrong + bool checkPrimitiveCount(u32 prmcnt) const; + + bool checkImage(const core::array& image) const; + + // adds a material renderer and drops it afterwards. To be used for internal creation + s32 addAndDropMaterialRenderer(IMaterialRenderer* m); + + //! deletes all material renderers + void deleteMaterialRenders(); + + // prints renderer version + void printVersion(); + + //! normal map lookup 32 bit version + inline f32 nml32(int x, int y, int pitch, int height, s32 *p) const + { + if (x < 0) + x = pitch-1; + if (x >= pitch) + x = 0; + if (y < 0) + y = height-1; + if (y >= height) + y = 0; + return (f32)(((p[(y * pitch) + x])>>16) & 0xff); + } + + //! normal map lookup 16 bit version + inline f32 nml16(int x, int y, int pitch, int height, s16 *p) const + { + if (x < 0) + x = pitch-1; + if (x >= pitch) + x = 0; + if (y < 0) + y = height-1; + if (y >= height) + y = 0; + + return (f32) getAverage ( p[(y * pitch) + x] ); + } + + inline bool getWriteZBuffer(const SMaterial& material) const + { + switch ( material.ZWriteEnable ) + { + case video::EZW_OFF: + return false; + case video::EZW_AUTO: + return AllowZWriteOnTransparent || ! needsTransparentRenderPass(material); + case video::EZW_ON: + return true; + } + return true; // never should get here, but some compilers don't know and complain + } + + struct SSurface + { + video::ITexture* Surface; + + bool operator < (const SSurface& other) const + { + return Surface->getName() < other.Surface->getName(); + } + }; + + struct SMaterialRenderer + { + core::stringc Name; + IMaterialRenderer* Renderer; + }; + + struct SDummyTexture : public ITexture + { + SDummyTexture(const io::path& name, E_TEXTURE_TYPE type) : ITexture(name, type) {}; + + virtual void* lock(E_TEXTURE_LOCK_MODE mode = ETLM_READ_WRITE, u32 mipmapLevel=0, u32 layer = 0, E_TEXTURE_LOCK_FLAGS lockFlags = ETLF_FLIP_Y_UP_RTT) _IRR_OVERRIDE_ { return 0; } + virtual void unlock()_IRR_OVERRIDE_ {} + virtual void regenerateMipMapLevels(void* data = 0, u32 layer = 0) _IRR_OVERRIDE_ {} + }; + core::array Textures; + + struct SOccQuery + { + SOccQuery(scene::ISceneNode* node, const scene::IMesh* mesh=0) : Node(node), Mesh(mesh), PID(0), Result(0xffffffff), Run(0xffffffff) + { + if (Node) + Node->grab(); + if (Mesh) + Mesh->grab(); + } + + SOccQuery(const SOccQuery& other) : Node(other.Node), Mesh(other.Mesh), PID(other.PID), Result(other.Result), Run(other.Run) + { + if (Node) + Node->grab(); + if (Mesh) + Mesh->grab(); + } + + ~SOccQuery() + { + if (Node) + Node->drop(); + if (Mesh) + Mesh->drop(); + } + + SOccQuery& operator=(const SOccQuery& other) + { + Node=other.Node; + Mesh=other.Mesh; + PID=other.PID; + Result=other.Result; + Run=other.Run; + if (Node) + Node->grab(); + if (Mesh) + Mesh->grab(); + return *this; + } + + bool operator==(const SOccQuery& other) const + { + return other.Node==Node; + } + + scene::ISceneNode* Node; + const scene::IMesh* Mesh; + union + { + void* PID; + unsigned int UID; + }; + u32 Result; + u32 Run; + }; + core::array OcclusionQueries; + + core::array RenderTargets; + + // Shared objects used with simplified IVideoDriver::setRenderTarget method with ITexture* param. + IRenderTarget* SharedRenderTarget; + core::array SharedDepthTextures; + + IRenderTarget* CurrentRenderTarget; + core::dimension2d CurrentRenderTargetSize; + + core::array SurfaceLoader; + core::array SurfaceWriter; + core::array Lights; + core::array MaterialRenderers; + + //core::array HWBufferLinks; + core::map< const scene::IMeshBuffer* , SHWBufferLink* > HWBufferMap; + + io::IFileSystem* FileSystem; + + //! mesh manipulator + scene::IMeshManipulator* MeshManipulator; + + core::rect ViewPort; + core::dimension2d ScreenSize; + core::matrix4 TransformationMatrix; + + CFPSCounter FPSCounter; + + u32 PrimitivesDrawn; + u32 MinVertexCountForVBO; + + u32 TextureCreationFlags; + + f32 FogStart; + f32 FogEnd; + f32 FogDensity; + SColor FogColor; + SExposedVideoData ExposedData; + + io::IAttributes* DriverAttributes; + + SOverrideMaterial OverrideMaterial; + SMaterial OverrideMaterial2D; + SMaterial InitMaterial2D; + bool OverrideMaterial2DEnabled; + + E_FOG_TYPE FogType; + bool PixelFog; + bool RangeFog; + bool AllowZWriteOnTransparent; + + bool FeatureEnabled[video::EVDF_COUNT]; + + SColorf AmbientLight; + }; + +} // end namespace video +} // end namespace irr + + +#endif diff --git a/source/Irrlicht/COBJMeshFileLoader.cpp b/source/Irrlicht/COBJMeshFileLoader.cpp new file mode 100644 index 00000000..d4ce82ed --- /dev/null +++ b/source/Irrlicht/COBJMeshFileLoader.cpp @@ -0,0 +1,974 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_OBJ_LOADER_ + +#include "COBJMeshFileLoader.h" +#include "CMeshTextureLoader.h" +#include "IMeshManipulator.h" +#include "IVideoDriver.h" +#include "SMesh.h" +#include "SMeshBuffer.h" +#include "SAnimatedMesh.h" +#include "IReadFile.h" +#include "IAttributes.h" +#include "fast_atof.h" +#include "coreutil.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + +#ifdef _DEBUG +#define _IRR_DEBUG_OBJ_LOADER_ +#endif + +static const u32 WORD_BUFFER_LENGTH = 512; + +//! Constructor +COBJMeshFileLoader::COBJMeshFileLoader(scene::ISceneManager* smgr, io::IFileSystem* fs) +: SceneManager(smgr), FileSystem(fs) +{ + #ifdef _DEBUG + setDebugName("COBJMeshFileLoader"); + #endif + + if (FileSystem) + FileSystem->grab(); + + TextureLoader = new CMeshTextureLoader( FileSystem, SceneManager->getVideoDriver() ); +} + + +//! destructor +COBJMeshFileLoader::~COBJMeshFileLoader() +{ + if (FileSystem) + FileSystem->drop(); +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool COBJMeshFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "obj" ); +} + + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IReferenceCounted::drop() for more information. +IAnimatedMesh* COBJMeshFileLoader::createMesh(io::IReadFile* file) +{ + if (!file) + return 0; + + if ( getMeshTextureLoader() ) + getMeshTextureLoader()->setMeshFile(file); + + const long filesize = file->getSize(); + if (!filesize) + return 0; + + const u32 WORD_BUFFER_LENGTH = 512; + + core::array > vertexBuffer(1000); + core::array > normalsBuffer(1000); + core::array > textureCoordBuffer(1000); + + SObjMtl * currMtl = new SObjMtl(); + Materials.push_back(currMtl); + u32 smoothingGroup=0; + + const io::path fullName = file->getFileName(); + const io::path relPath = FileSystem->getFileDir(fullName)+"/"; + + c8* buf = new c8[filesize]; + memset(buf, 0, filesize); + file->read((void*)buf, filesize); + const c8* const bufEnd = buf+filesize; + + // Process obj information + const c8* bufPtr = buf; + core::stringc grpName, mtlName; + bool mtlChanged=false; + bool useGroups = !SceneManager->getParameters()->getAttributeAsBool(OBJ_LOADER_IGNORE_GROUPS); + bool useMaterials = !SceneManager->getParameters()->getAttributeAsBool(OBJ_LOADER_IGNORE_MATERIAL_FILES); + irr::u32 lineNr = 1; // only counts non-empty lines, still useful in debugging to locate errors + core::array faceCorners; + faceCorners.reallocate(32); // should be large enough + const core::stringc TAG_OFF = "off"; + irr::u32 degeneratedFaces = 0; + + while(bufPtr != bufEnd) + { + switch(bufPtr[0]) + { + case 'm': // mtllib (material) + { + if (useMaterials) + { + c8 name[WORD_BUFFER_LENGTH]; + bufPtr = goAndCopyNextWord(name, bufPtr, WORD_BUFFER_LENGTH, bufEnd); +#ifdef _IRR_DEBUG_OBJ_LOADER_ + os::Printer::log("Reading material file",name); +#endif + readMTL(name, relPath); + } + } + break; + + case 'v': // v, vn, vt + switch(bufPtr[1]) + { + case ' ': // vertex + { + core::vector3df vec; + bufPtr = readVec3(bufPtr, vec, bufEnd); + vertexBuffer.push_back(vec); + } + break; + + case 'n': // normal + { + core::vector3df vec; + bufPtr = readVec3(bufPtr, vec, bufEnd); + normalsBuffer.push_back(vec); + } + break; + + case 't': // texcoord + { + core::vector2df vec; + bufPtr = readUV(bufPtr, vec, bufEnd); + textureCoordBuffer.push_back(vec); + } + break; + } + break; + + case 'g': // group name + { + c8 grp[WORD_BUFFER_LENGTH]; + bufPtr = goAndCopyNextWord(grp, bufPtr, WORD_BUFFER_LENGTH, bufEnd); +#ifdef _IRR_DEBUG_OBJ_LOADER_ + os::Printer::log("Loaded group start",grp, ELL_DEBUG); +#endif + if (useGroups) + { + if (0 != grp[0]) + grpName = grp; + else + grpName = "default"; + } + mtlChanged=true; + } + break; + + case 's': // smoothing can be a group or off (equiv. to 0) + { + c8 smooth[WORD_BUFFER_LENGTH]; + bufPtr = goAndCopyNextWord(smooth, bufPtr, WORD_BUFFER_LENGTH, bufEnd); +#ifdef _IRR_DEBUG_OBJ_LOADER_ + os::Printer::log("Loaded smoothing group start",smooth, ELL_DEBUG); +#endif + if (TAG_OFF==smooth) + smoothingGroup=0; + else + smoothingGroup=core::strtoul10(smooth); + } + break; + + case 'u': // usemtl + // get name of material + { + c8 matName[WORD_BUFFER_LENGTH]; + bufPtr = goAndCopyNextWord(matName, bufPtr, WORD_BUFFER_LENGTH, bufEnd); +#ifdef _IRR_DEBUG_OBJ_LOADER_ + os::Printer::log("Loaded material start",matName, ELL_DEBUG); +#endif + mtlName=matName; + mtlChanged=true; + } + break; + + case 'f': // face + { + c8 vertexWord[WORD_BUFFER_LENGTH]; // for retrieving vertex data + video::S3DVertex v; + // Assign vertex color from currently active material's diffuse color + if (mtlChanged) + { + // retrieve the material + SObjMtl *useMtl = findMtl(mtlName, grpName); + // only change material if we found it + if (useMtl) + currMtl = useMtl; + mtlChanged=false; + } + if (currMtl) + v.Color = currMtl->Meshbuffer->Material.DiffuseColor; + + // get all vertices data in this face (current line of obj file) + const core::stringc wordBuffer = copyLine(bufPtr, bufEnd); + const c8* linePtr = wordBuffer.c_str(); + const c8* const endPtr = linePtr+wordBuffer.size(); + + faceCorners.set_used(0); // fast clear + + // read in all vertices + linePtr = goNextWord(linePtr, endPtr); + while (0 != linePtr[0]) + { + // Array to communicate with retrieveVertexIndices() + // sends the buffer sizes and gets the actual indices + // if index not set returns -1 + s32 Idx[3]; + Idx[0] = Idx[1] = Idx[2] = -1; + + // read in next vertex's data + u32 wlength = copyWord(vertexWord, linePtr, WORD_BUFFER_LENGTH, endPtr); + // this function will also convert obj's 1-based index to c++'s 0-based index + retrieveVertexIndices(vertexWord, Idx, vertexWord+wlength+1, vertexBuffer.size(), textureCoordBuffer.size(), normalsBuffer.size()); + if ( -1 != Idx[0] && Idx[0] < (irr::s32)vertexBuffer.size() ) + v.Pos = vertexBuffer[Idx[0]]; + else + { + os::Printer::log("Invalid vertex index in this line:", wordBuffer.c_str(), ELL_ERROR); + delete [] buf; + return 0; + } + if ( -1 != Idx[1] && Idx[1] < (irr::s32)textureCoordBuffer.size() ) + v.TCoords = textureCoordBuffer[Idx[1]]; + else + v.TCoords.set(0.0f,0.0f); + if ( -1 != Idx[2] && Idx[2] < (irr::s32)normalsBuffer.size() ) + v.Normal = normalsBuffer[Idx[2]]; + else + { + v.Normal.set(0.0f,0.0f,0.0f); + currMtl->RecalculateNormals=true; + } + + int vertLocation; + core::map::Node* n = currMtl->VertMap.find(v); + if (n) + { + vertLocation = n->getValue(); + } + else + { + currMtl->Meshbuffer->Vertices.push_back(v); + vertLocation = currMtl->Meshbuffer->Vertices.size() -1; + currMtl->VertMap.insert(v, vertLocation); + } + + faceCorners.push_back(vertLocation); + + // go to next vertex + linePtr = goNextWord(linePtr, endPtr); + } + + // triangulate the face + const int c = faceCorners[0]; + for ( u32 i = 1; i < faceCorners.size() - 1; ++i ) + { + // Add a triangle + const int a = faceCorners[i + 1]; + const int b = faceCorners[i]; + if (a != b && a != c && b != c) // ignore degenerated faces. We can get them when we merge vertices above in the VertMap. + { + currMtl->Meshbuffer->Indices.push_back(a); + currMtl->Meshbuffer->Indices.push_back(b); + currMtl->Meshbuffer->Indices.push_back(c); + } + else + { + ++degeneratedFaces; + } + } + } + break; + + case '#': // comment + default: + break; + } // end switch(bufPtr[0]) + // eat up rest of line + bufPtr = goNextLine(bufPtr, bufEnd); + ++lineNr; + } // end while(bufPtr && (bufPtr-buf 0 ) + { + irr::core::stringc log(degeneratedFaces); + log += " degenerated faces removed in "; + log += irr::core::stringc(fullName); + os::Printer::log(log.c_str(), ELL_INFORMATION); + } + + SMesh* mesh = new SMesh(); + + // Combine all the groups (meshbuffers) into the mesh + for ( u32 m = 0; m < Materials.size(); ++m ) + { + if ( Materials[m]->Meshbuffer->getIndexCount() > 0 ) + { + Materials[m]->Meshbuffer->recalculateBoundingBox(); + if (Materials[m]->RecalculateNormals) + SceneManager->getMeshManipulator()->recalculateNormals(Materials[m]->Meshbuffer); + if (Materials[m]->Meshbuffer->Material.MaterialType == video::EMT_PARALLAX_MAP_SOLID) + { + SMesh tmp; + tmp.addMeshBuffer(Materials[m]->Meshbuffer); + IMesh* tangentMesh = SceneManager->getMeshManipulator()->createMeshWithTangents(&tmp); + mesh->addMeshBuffer(tangentMesh->getMeshBuffer(0)); + tangentMesh->drop(); + } + else + mesh->addMeshBuffer( Materials[m]->Meshbuffer ); + } + } + + // Create the Animated mesh if there's anything in the mesh + SAnimatedMesh* animMesh = 0; + if ( 0 != mesh->getMeshBufferCount() ) + { + mesh->recalculateBoundingBox(); + animMesh = new SAnimatedMesh(); + animMesh->Type = EAMT_OBJ; + animMesh->addMesh(mesh); + animMesh->recalculateBoundingBox(); + } + + // Clean up the allocate obj file contents + delete [] buf; + // more cleaning up + cleanUp(); + mesh->drop(); + + return animMesh; +} + + +const c8* COBJMeshFileLoader::readTextures(const c8* bufPtr, const c8* const bufEnd, SObjMtl* currMaterial, const io::path& relPath) +{ + u8 type=0; // map_Kd - diffuse color texture map + // map_Ks - specular color texture map + // map_Ka - ambient color texture map + // map_Ns - shininess texture map + if ((!strncmp(bufPtr,"map_bump",8)) || (!strncmp(bufPtr,"bump",4))) + type=1; // normal map + else if ((!strncmp(bufPtr,"map_d",5)) || (!strncmp(bufPtr,"map_opacity",11))) + type=2; // opacity map + else if (!strncmp(bufPtr,"map_refl",8)) + type=3; // reflection map + // extract new material's name + c8 textureNameBuf[WORD_BUFFER_LENGTH]; + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + + f32 bumpiness = 6.0f; + bool clamp = false; + core::vector3df tscale(1.f); //For map_Kd texture scaling + core::vector3df tpos(0.f); //For map_Kd texture translation + // handle options + while (textureNameBuf[0]=='-') + { + if (!strncmp(bufPtr,"-bm",3)) + { + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + currMaterial->Meshbuffer->Material.MaterialTypeParam=core::fast_atof(textureNameBuf); + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + continue; + } + else + if (!strncmp(bufPtr,"-blendu",7)) + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + else + if (!strncmp(bufPtr,"-blendv",7)) + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + else + if (!strncmp(bufPtr,"-cc",3)) + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + else + if (!strncmp(bufPtr,"-clamp",6)) + bufPtr = readBool(bufPtr, clamp, bufEnd); + else + if (!strncmp(bufPtr,"-texres",7)) + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + else + if (!strncmp(bufPtr,"-type",5)) + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + else + if (!strncmp(bufPtr,"-mm",3)) + { + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + } + else + if (!strncmp(bufPtr,"-o",2)) // texture coord translation + { + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + if (core::isdigit(textureNameBuf[0]) || (textureNameBuf[0] == '-' && core::isdigit(textureNameBuf[1]))) + tpos.X = core::fast_atof(textureNameBuf); + + // next parameters are optional, so skip rest of loop if no number is found + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + if (!(core::isdigit(textureNameBuf[0]) || (textureNameBuf[0] == '-' && core::isdigit(textureNameBuf[1])))) + continue; + tpos.Y = core::fast_atof(textureNameBuf); + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + if (!(core::isdigit(textureNameBuf[0]) || (textureNameBuf[0] == '-' && core::isdigit(textureNameBuf[1])))) + continue; + tpos.Z = core::fast_atof(textureNameBuf); + } + else + if (!strncmp(bufPtr,"-s",2)) // texture coord scale + { + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + if (core::isdigit(textureNameBuf[0]) || (textureNameBuf[0] == '-' && core::isdigit(textureNameBuf[1]))) + tscale.X = core::fast_atof(textureNameBuf); + + // next parameters are optional, so skip rest of loop if no number is found + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + if (!(core::isdigit(textureNameBuf[0]) || (textureNameBuf[0] == '-' && core::isdigit(textureNameBuf[1])))) + continue; + tscale.Y = core::fast_atof(textureNameBuf); + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + if (!(core::isdigit(textureNameBuf[0]) || (textureNameBuf[0] == '-' && core::isdigit(textureNameBuf[1])))) + continue; + tscale.Z = core::fast_atof(textureNameBuf); + } + else + if (!strncmp(bufPtr,"-t",2)) + { + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + // next parameters are optional, so skip rest of loop if no number is found + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + if (!(core::isdigit(textureNameBuf[0]) || (textureNameBuf[0] == '-' && core::isdigit(textureNameBuf[1])))) + continue; + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + if (!(core::isdigit(textureNameBuf[0]) || (textureNameBuf[0] == '-' && core::isdigit(textureNameBuf[1])))) + continue; + } + // get next word + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + } + + if ((type==1) && (core::isdigit(textureNameBuf[0]))) + { + currMaterial->Meshbuffer->Material.MaterialTypeParam=core::fast_atof(textureNameBuf); + bufPtr = goAndCopyNextWord(textureNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + } + if (clamp) + currMaterial->Meshbuffer->Material.setFlag(video::EMF_TEXTURE_WRAP, video::ETC_CLAMP); + + io::path texname(textureNameBuf); + if (texname.size() && getMeshTextureLoader()) + { + video::ITexture * texture = getMeshTextureLoader()->getTexture(texname); + if ( texture ) + { + if (type==0) + { + currMaterial->Meshbuffer->Material.setTexture(0, texture); + bool needsTextureMatrix = tscale != core::vector3df(1.f) || tpos != core::vector3df(0.f); + if (needsTextureMatrix) + { + currMaterial->Meshbuffer->Material.getTextureMatrix(0).setTextureScale(tscale.X, tscale.Y); + currMaterial->Meshbuffer->Material.getTextureMatrix(0).setTextureTranslate(tpos.X, tpos.Y); + } + } + else if (type==1) + { + if ( texture->getSource() == video::ETS_FROM_FILE) + SceneManager->getVideoDriver()->makeNormalMapTexture(texture, bumpiness); + currMaterial->Meshbuffer->Material.setTexture(1, texture); + currMaterial->Meshbuffer->Material.MaterialType=video::EMT_PARALLAX_MAP_SOLID; + currMaterial->Meshbuffer->Material.MaterialTypeParam=0.035f; + } + else if (type==2) + { + currMaterial->Meshbuffer->Material.setTexture(0, texture); + currMaterial->Meshbuffer->Material.MaterialType=video::EMT_TRANSPARENT_ADD_COLOR; + } + else if (type==3) + { + // currMaterial->Meshbuffer->Material.Textures[1] = texture; + // currMaterial->Meshbuffer->Material.MaterialType=video::EMT_REFLECTION_2_LAYER; + } + // Set diffuse material color to white so as not to affect texture color + // Because Maya set diffuse color Kd to black when you use a diffuse color map + // But is this the right thing to do? + currMaterial->Meshbuffer->Material.DiffuseColor.set( + currMaterial->Meshbuffer->Material.DiffuseColor.getAlpha(), 255, 255, 255 ); + } + } + return bufPtr; +} + + +void COBJMeshFileLoader::readMTL(const c8* fileName, const io::path& relPath) +{ + const io::path realFile(fileName); + io::IReadFile * mtlReader; + + if (FileSystem->existFile(realFile)) + mtlReader = FileSystem->createAndOpenFile(realFile); + else if (FileSystem->existFile(relPath + realFile)) + mtlReader = FileSystem->createAndOpenFile(relPath + realFile); + else if (FileSystem->existFile(FileSystem->getFileBasename(realFile))) + mtlReader = FileSystem->createAndOpenFile(FileSystem->getFileBasename(realFile)); + else + mtlReader = FileSystem->createAndOpenFile(relPath + FileSystem->getFileBasename(realFile)); + if (!mtlReader) // fail to open and read file + { + os::Printer::log("Could not open material file", realFile, ELL_WARNING); + return; + } + + if ( getMeshTextureLoader() ) + { + getMeshTextureLoader()->setMaterialFile(mtlReader); + if ( SceneManager->getParameters()->existsAttribute(OBJ_TEXTURE_PATH) ) + getMeshTextureLoader()->setTexturePath(SceneManager->getParameters()->getAttributeAsString(OBJ_TEXTURE_PATH)); + } + + const long filesize = mtlReader->getSize(); + if (!filesize) + { + os::Printer::log("Skipping empty material file", realFile, ELL_WARNING); + mtlReader->drop(); + return; + } + + c8* buf = new c8[filesize]; + mtlReader->read((void*)buf, filesize); + const c8* bufEnd = buf+filesize; + + SObjMtl* currMaterial = 0; + + const c8* bufPtr = buf; + while(bufPtr != bufEnd) + { + switch(*bufPtr) + { + case 'n': // newmtl + { + // if there's an existing material, store it first + if ( currMaterial ) + Materials.push_back( currMaterial ); + + // extract new material's name + c8 mtlNameBuf[WORD_BUFFER_LENGTH]; + bufPtr = goAndCopyNextWord(mtlNameBuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + + currMaterial = new SObjMtl; + currMaterial->Name = mtlNameBuf; + } + break; + case 'i': // illum - illumination + if ( currMaterial ) + { + const u32 COLOR_BUFFER_LENGTH = 16; + c8 illumStr[COLOR_BUFFER_LENGTH]; + + bufPtr = goAndCopyNextWord(illumStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd); + currMaterial->Illumination = (c8)atol(illumStr); + } + break; + case 'N': + if ( currMaterial ) + { + switch(bufPtr[1]) + { + case 's': // Ns - shininess + { + const u32 COLOR_BUFFER_LENGTH = 16; + c8 nsStr[COLOR_BUFFER_LENGTH]; + + bufPtr = goAndCopyNextWord(nsStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd); + f32 shininessValue = core::fast_atof(nsStr); + + // wavefront shininess is from [0, 1000], so scale for OpenGL + shininessValue *= 0.128f; + currMaterial->Meshbuffer->Material.Shininess = shininessValue; + } + break; + case 'i': // Ni - refraction index + { + c8 tmpbuf[WORD_BUFFER_LENGTH]; + bufPtr = goAndCopyNextWord(tmpbuf, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + } + break; + } + } + break; + case 'K': + if ( currMaterial ) + { + switch(bufPtr[1]) + { + case 'd': // Kd = diffuse + { + bufPtr = readColor(bufPtr, currMaterial->Meshbuffer->Material.DiffuseColor, bufEnd); + + } + break; + + case 's': // Ks = specular + { + bufPtr = readColor(bufPtr, currMaterial->Meshbuffer->Material.SpecularColor, bufEnd); + } + break; + + case 'a': // Ka = ambience + { + bufPtr=readColor(bufPtr, currMaterial->Meshbuffer->Material.AmbientColor, bufEnd); + } + break; + case 'e': // Ke = emissive + { + currMaterial->Meshbuffer->Material.EmissiveColor.setAlpha(255); + bufPtr=readColor(bufPtr, currMaterial->Meshbuffer->Material.EmissiveColor, bufEnd); + } + break; + } // end switch(bufPtr[1]) + } // end case 'K': if ( 0 != currMaterial )... + break; + case 'b': // bump + case 'm': // texture maps + if (currMaterial) + { + bufPtr=readTextures(bufPtr, bufEnd, currMaterial, relPath); + } + break; + case 'd': // d - transparency + if ( currMaterial ) + { + const u32 COLOR_BUFFER_LENGTH = 16; + c8 dStr[COLOR_BUFFER_LENGTH]; + + bufPtr = goAndCopyNextWord(dStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd); + f32 dValue = core::fast_atof(dStr); + + currMaterial->Meshbuffer->Material.DiffuseColor.setAlpha( (s32)(dValue * 255) ); + if (dValue<1.0f) + currMaterial->Meshbuffer->Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + } + break; + case 'T': + if ( currMaterial ) + { + switch ( bufPtr[1] ) + { + case 'f': // Tf - Transmitivity + const u32 COLOR_BUFFER_LENGTH = 16; + c8 redStr[COLOR_BUFFER_LENGTH]; + c8 greenStr[COLOR_BUFFER_LENGTH]; + c8 blueStr[COLOR_BUFFER_LENGTH]; + + bufPtr = goAndCopyNextWord(redStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd); + bufPtr = goAndCopyNextWord(greenStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd); + bufPtr = goAndCopyNextWord(blueStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd); + + f32 transparency = ( core::fast_atof(redStr) + core::fast_atof(greenStr) + core::fast_atof(blueStr) ) / 3; + + currMaterial->Meshbuffer->Material.DiffuseColor.setAlpha( (s32)(transparency * 255) ); + if (transparency < 1.0f) + currMaterial->Meshbuffer->Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + } + } + break; + default: // comments or not recognised + break; + } // end switch(bufPtr[0]) + // go to next line + bufPtr = goNextLine(bufPtr, bufEnd); + } // end while (bufPtr) + + // end of file. if there's an existing material, store it + if ( currMaterial ) + Materials.push_back( currMaterial ); + + delete [] buf; + mtlReader->drop(); +} + + +//! Read RGB color +const c8* COBJMeshFileLoader::readColor(const c8* bufPtr, video::SColor& color, const c8* const bufEnd) +{ + const u32 COLOR_BUFFER_LENGTH = 16; + c8 colStr[COLOR_BUFFER_LENGTH]; + + bufPtr = goAndCopyNextWord(colStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd); + color.setRed((s32)(core::fast_atof(colStr) * 255.0f)); + bufPtr = goAndCopyNextWord(colStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd); + color.setGreen((s32)(core::fast_atof(colStr) * 255.0f)); + bufPtr = goAndCopyNextWord(colStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd); + color.setBlue((s32)(core::fast_atof(colStr) * 255.0f)); + return bufPtr; +} + + +//! Read 3d vector of floats +const c8* COBJMeshFileLoader::readVec3(const c8* bufPtr, core::vector3df& vec, const c8* const bufEnd) +{ + const u32 WORD_BUFFER_LENGTH = 256; + c8 wordBuffer[WORD_BUFFER_LENGTH]; + + bufPtr = goAndCopyNextWord(wordBuffer, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + vec.X=-core::fast_atof(wordBuffer); // change handedness + bufPtr = goAndCopyNextWord(wordBuffer, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + vec.Y=core::fast_atof(wordBuffer); + bufPtr = goAndCopyNextWord(wordBuffer, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + vec.Z=core::fast_atof(wordBuffer); + return bufPtr; +} + + +//! Read 2d vector of floats +const c8* COBJMeshFileLoader::readUV(const c8* bufPtr, core::vector2df& vec, const c8* const bufEnd) +{ + const u32 WORD_BUFFER_LENGTH = 256; + c8 wordBuffer[WORD_BUFFER_LENGTH]; + + bufPtr = goAndCopyNextWord(wordBuffer, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + vec.X=core::fast_atof(wordBuffer); + bufPtr = goAndCopyNextWord(wordBuffer, bufPtr, WORD_BUFFER_LENGTH, bufEnd); + vec.Y=1-core::fast_atof(wordBuffer); // change handedness + return bufPtr; +} + + +//! Read boolean value represented as 'on' or 'off' +const c8* COBJMeshFileLoader::readBool(const c8* bufPtr, bool& tf, const c8* const bufEnd) +{ + const u32 BUFFER_LENGTH = 8; + c8 tfStr[BUFFER_LENGTH]; + + bufPtr = goAndCopyNextWord(tfStr, bufPtr, BUFFER_LENGTH, bufEnd); + tf = strcmp(tfStr, "off") != 0; + return bufPtr; +} + + +COBJMeshFileLoader::SObjMtl* COBJMeshFileLoader::findMtl(const core::stringc& mtlName, const core::stringc& grpName) +{ + COBJMeshFileLoader::SObjMtl* defMaterial = 0; + // search existing Materials for best match + // exact match does return immediately, only name match means a new group + for (u32 i = 0; i < Materials.size(); ++i) + { + if ( Materials[i]->Name == mtlName ) + { + if ( Materials[i]->Group == grpName ) + return Materials[i]; + else + defMaterial = Materials[i]; + } + } + // we found a partial match + if (defMaterial) + { + Materials.push_back(new SObjMtl(*defMaterial)); + Materials.getLast()->Group = grpName; + return Materials.getLast(); + } + // we found a new group for a non-existant material + else if (grpName.size()) + { + Materials.push_back(new SObjMtl(*Materials[0])); + Materials.getLast()->Group = grpName; + return Materials.getLast(); + } + return 0; +} + + +//! skip space characters and stop on first non-space +const c8* COBJMeshFileLoader::goFirstWord(const c8* buf, const c8* const bufEnd, bool acrossNewlines) +{ + // skip space characters + if (acrossNewlines) + while((buf != bufEnd) && core::isspace(*buf)) + ++buf; + else + while((buf != bufEnd) && core::isspace(*buf) && (*buf != '\n')) + ++buf; + + return buf; +} + + +//! skip current word and stop at beginning of next one +const c8* COBJMeshFileLoader::goNextWord(const c8* buf, const c8* const bufEnd, bool acrossNewlines) +{ + // skip current word + while(( buf != bufEnd ) && !core::isspace(*buf)) + ++buf; + + return goFirstWord(buf, bufEnd, acrossNewlines); +} + + +//! Read until line break is reached and stop at the next non-space character +const c8* COBJMeshFileLoader::goNextLine(const c8* buf, const c8* const bufEnd) +{ + // look for newline characters + while(buf != bufEnd) + { + // found it, so leave + if (*buf=='\n' || *buf=='\r') + break; + ++buf; + } + return goFirstWord(buf, bufEnd); +} + + +u32 COBJMeshFileLoader::copyWord(c8* outBuf, const c8* const inBuf, u32 outBufLength, const c8* const bufEnd) +{ + if (!outBufLength) + return 0; + if (!inBuf) + { + *outBuf = 0; + return 0; + } + + u32 i = 0; + while(inBuf[i]) + { + if (core::isspace(inBuf[i]) || &(inBuf[i]) == bufEnd) + break; + ++i; + } + + u32 length = core::min_(i, outBufLength-1); + for (u32 j=0; j 2 ) + { + // error checking, shouldn't reach here unless file is wrong + idxType = 0; + } + } + else + { + // set all missing values to disable (=-1) + while (++idxType < 3) + idx[idxType]=-1; + ++p; + break; // while + } + } + + // go to the next char + ++p; + } + + return true; +} + + +void COBJMeshFileLoader::cleanUp() +{ + for (u32 i=0; i < Materials.size(); ++i ) + { + Materials[i]->Meshbuffer->drop(); + delete Materials[i]; + } + + Materials.clear(); +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_OBJ_LOADER_ + diff --git a/source/Irrlicht/COBJMeshFileLoader.h b/source/Irrlicht/COBJMeshFileLoader.h new file mode 100644 index 00000000..22183eb6 --- /dev/null +++ b/source/Irrlicht/COBJMeshFileLoader.h @@ -0,0 +1,122 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OBJ_MESH_FILE_LOADER_H_INCLUDED__ +#define __C_OBJ_MESH_FILE_LOADER_H_INCLUDED__ + +#include "IMeshLoader.h" +#include "IFileSystem.h" +#include "ISceneManager.h" +#include "irrString.h" +#include "SMeshBuffer.h" +#include "irrMap.h" + +namespace irr +{ +namespace scene +{ + +//! Meshloader capable of loading obj meshes. +class COBJMeshFileLoader : public IMeshLoader +{ +public: + + //! Constructor + COBJMeshFileLoader(scene::ISceneManager* smgr, io::IFileSystem* fs); + + //! destructor + virtual ~COBJMeshFileLoader(); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".obj") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! creates/loads an animated mesh from the file. + //! \return Pointer to the created mesh. Returns 0 if loading failed. + //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). + //! See IReferenceCounted::drop() for more information. + virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_; + +private: + + struct SObjMtl + { + SObjMtl() : Meshbuffer(0), Bumpiness (1.0f), Illumination(0), + RecalculateNormals(false) + { + Meshbuffer = new SMeshBuffer(); + Meshbuffer->Material.Shininess = 0.0f; + Meshbuffer->Material.AmbientColor = video::SColorf(0.2f, 0.2f, 0.2f, 1.0f).toSColor(); + Meshbuffer->Material.DiffuseColor = video::SColorf(0.8f, 0.8f, 0.8f, 1.0f).toSColor(); + Meshbuffer->Material.SpecularColor = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f).toSColor(); + } + + SObjMtl(const SObjMtl& o) + : Name(o.Name), Group(o.Group), + Bumpiness(o.Bumpiness), Illumination(o.Illumination), + RecalculateNormals(false) + { + Meshbuffer = new SMeshBuffer(); + Meshbuffer->Material = o.Meshbuffer->Material; + } + + core::map VertMap; + scene::SMeshBuffer *Meshbuffer; + core::stringc Name; + core::stringc Group; + f32 Bumpiness; + c8 Illumination; + bool RecalculateNormals; + }; + + // helper method for material reading + const c8* readTextures(const c8* bufPtr, const c8* const bufEnd, SObjMtl* currMaterial, const io::path& relPath); + + // returns a pointer to the first printable character available in the buffer + const c8* goFirstWord(const c8* buf, const c8* const bufEnd, bool acrossNewlines=true); + // returns a pointer to the first printable character after the first non-printable + const c8* goNextWord(const c8* buf, const c8* const bufEnd, bool acrossNewlines=true); + // returns a pointer to the next printable character after the first line break + const c8* goNextLine(const c8* buf, const c8* const bufEnd); + // copies the current word from the inBuf to the outBuf + u32 copyWord(c8* outBuf, const c8* inBuf, u32 outBufLength, const c8* const pBufEnd); + // copies the current line from the inBuf to the outBuf + core::stringc copyLine(const c8* inBuf, const c8* const bufEnd); + + // combination of goNextWord followed by copyWord + const c8* goAndCopyNextWord(c8* outBuf, const c8* inBuf, u32 outBufLength, const c8* const pBufEnd); + + //! Read the material from the given file + void readMTL(const c8* fileName, const io::path& relPath); + + //! Find and return the material with the given name + SObjMtl* findMtl(const core::stringc& mtlName, const core::stringc& grpName); + + //! Read RGB color + const c8* readColor(const c8* bufPtr, video::SColor& color, const c8* const pBufEnd); + //! Read 3d vector of floats + const c8* readVec3(const c8* bufPtr, core::vector3df& vec, const c8* const pBufEnd); + //! Read 2d vector of floats + const c8* readUV(const c8* bufPtr, core::vector2df& vec, const c8* const pBufEnd); + //! Read boolean value represented as 'on' or 'off' + const c8* readBool(const c8* bufPtr, bool& tf, const c8* const bufEnd); + + // reads and convert to integer the vertex indices in a line of obj file's face statement + // -1 for the index if it doesn't exist + // indices are changed to 0-based index instead of 1-based from the obj file + bool retrieveVertexIndices(c8* vertexData, s32* idx, const c8* bufEnd, u32 vbsize, u32 vtsize, u32 vnsize); + + void cleanUp(); + + scene::ISceneManager* SceneManager; + io::IFileSystem* FileSystem; + + core::array Materials; +}; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/COBJMeshWriter.cpp b/source/Irrlicht/COBJMeshWriter.cpp new file mode 100644 index 00000000..c784caf1 --- /dev/null +++ b/source/Irrlicht/COBJMeshWriter.cpp @@ -0,0 +1,282 @@ +// Copyright (C) 2008-2012 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OBJ_WRITER_ + +#include "COBJMeshWriter.h" +#include "os.h" +#include "IMesh.h" +#include "IMeshBuffer.h" +#include "IAttributes.h" +#include "ISceneManager.h" +#include "IMeshCache.h" +#include "IWriteFile.h" +#include "IFileSystem.h" +#include "ITexture.h" + +namespace irr +{ +namespace scene +{ + +COBJMeshWriter::COBJMeshWriter(scene::ISceneManager* smgr, io::IFileSystem* fs) + : SceneManager(smgr), FileSystem(fs) +{ + #ifdef _DEBUG + setDebugName("COBJMeshWriter"); + #endif + + if (SceneManager) + SceneManager->grab(); + + if (FileSystem) + FileSystem->grab(); +} + + +COBJMeshWriter::~COBJMeshWriter() +{ + if (SceneManager) + SceneManager->drop(); + + if (FileSystem) + FileSystem->drop(); +} + + +//! Returns the type of the mesh writer +EMESH_WRITER_TYPE COBJMeshWriter::getType() const +{ + return EMWT_OBJ; +} + + +//! writes a mesh +bool COBJMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags) +{ + if (!file) + return false; + + os::Printer::log("Writing mesh", file->getFileName()); + + // write OBJ MESH header + + io::path name; + core::cutFilenameExtension(name,file->getFileName()) += ".mtl"; + file->write("# exported by Irrlicht\n",23); + file->write("mtllib ",7); + file->write(name.c_str(),name.size()); + file->write("\n\n",2); + + // write mesh buffers + + core::array mat; + + u32 allVertexCount=1; // count vertices over the whole file + for (u32 i=0; igetMeshBufferCount(); ++i) + { + core::stringc num(i+1); + IMeshBuffer* buffer = mesh->getMeshBuffer(i); + if (buffer && buffer->getVertexCount()) + { + file->write("g grp", 5); + file->write(num.c_str(), num.size()); + file->write("\n",1); + + u32 j; + const u32 vertexCount = buffer->getVertexCount(); + for (j=0; jwrite("v ",2); + getVectorAsStringLine(buffer->getPosition(j), num); + file->write(num.c_str(), num.size()); + } + + for (j=0; jwrite("vt ",3); + getVectorAsStringLine(buffer->getTCoords(j), num); + file->write(num.c_str(), num.size()); + } + + for (j=0; jwrite("vn ",3); + getVectorAsStringLine(buffer->getNormal(j), num); + file->write(num.c_str(), num.size()); + } + + file->write("usemtl mat",10); + num = ""; + for (j=0; jgetMaterial()) + { + num = core::stringc(j); + break; + } + } + if (num == "") + { + num = core::stringc(mat.size()); + mat.push_back(&buffer->getMaterial()); + } + file->write(num.c_str(), num.size()); + file->write("\n",1); + + const u32 indexCount = buffer->getIndexCount(); + for (j=0; jwrite("f ",2); + num = core::stringc(buffer->getIndices()[j+2]+allVertexCount); + file->write(num.c_str(), num.size()); + file->write("/",1); + file->write(num.c_str(), num.size()); + file->write("/",1); + file->write(num.c_str(), num.size()); + file->write(" ",1); + + num = core::stringc(buffer->getIndices()[j+1]+allVertexCount); + file->write(num.c_str(), num.size()); + file->write("/",1); + file->write(num.c_str(), num.size()); + file->write("/",1); + file->write(num.c_str(), num.size()); + file->write(" ",1); + + num = core::stringc(buffer->getIndices()[j+0]+allVertexCount); + file->write(num.c_str(), num.size()); + file->write("/",1); + file->write(num.c_str(), num.size()); + file->write("/",1); + file->write(num.c_str(), num.size()); + file->write(" ",1); + + file->write("\n",1); + } + file->write("\n",1); + allVertexCount += vertexCount; + } + } + + if (mat.size() == 0) + return true; + + file = FileSystem->createAndWriteFile( name ); + if (file) + { + os::Printer::log("Writing material", file->getFileName()); + + file->write("# exported by Irrlicht\n\n",24); + for (u32 i=0; iwrite("newmtl mat",10); + file->write(num.c_str(),num.size()); + file->write("\n",1); + + getColorAsStringLine(mat[i]->AmbientColor, "Ka", num); + file->write(num.c_str(),num.size()); + getColorAsStringLine(mat[i]->DiffuseColor, "Kd", num); + file->write(num.c_str(),num.size()); + getColorAsStringLine(mat[i]->SpecularColor, "Ks", num); + file->write(num.c_str(),num.size()); + getColorAsStringLine(mat[i]->EmissiveColor, "Ke", num); + file->write(num.c_str(),num.size()); + num = core::stringc((double)(mat[i]->Shininess/0.128f)); + file->write("Ns ", 3); + file->write(num.c_str(),num.size()); + file->write("\n", 1); + if (mat[i]->getTexture(0)) + { + file->write("map_Kd ", 7); + + f32 tposX, tposY, tscaleX, tscaleY; + const core::matrix4& textureMatrix = mat[i]->getTextureMatrix(0); + textureMatrix.getTextureTranslate(tposX, tposY); + textureMatrix.getTextureScale(tscaleX, tscaleY); + + //Write texture translation values + if ( !core::equals(tposX, 0.f) || !core::equals(tposY, 0.f) ) + { + file->write("-o ", 3); + core::stringc tx(tposX); + core::stringc ty(tposY); + + file->write(tx.c_str(), tx.size()); + file->write(" ", 1); + file->write(ty.c_str(), ty.size()); + file->write(" ", 1); + } + + //Write texture scaling values + if ( !core::equals(tscaleX, 1.f) || !core::equals(tscaleY, 1.f) ) + { + file->write("-s ", 3); + + core::stringc sx(tscaleX); + core::stringc sy(tscaleY); + + file->write(sx.c_str(), sx.size()); + file->write(" ", 1); + file->write(sy.c_str(), sy.size()); + file->write(" ", 1); + } + + io::path tname = FileSystem->getRelativeFilename(mat[i]->getTexture(0)->getName(), + FileSystem->getFileDir(file->getFileName())); + // avoid blanks as .obj cannot handle strings with spaces + if (tname.findFirst(' ') != -1) + tname = FileSystem->getFileBasename(tname); + file->write(tname.c_str(), tname.size()); + file->write("\n",1); + } + file->write("\n",1); + } + file->drop(); + } + return true; +} + + +void COBJMeshWriter::getVectorAsStringLine(const core::vector3df& v, core::stringc& s) const +{ + s = core::stringc(-v.X); + s += " "; + s += core::stringc(v.Y); + s += " "; + s += core::stringc(v.Z); + s += "\n"; +} + + +void COBJMeshWriter::getVectorAsStringLine(const core::vector2df& v, core::stringc& s) const +{ + s = core::stringc(v.X); + s += " "; + s += core::stringc(1-v.Y); + s += "\n"; +} + + +void COBJMeshWriter::getColorAsStringLine(const video::SColor& color, const c8* const prefix, core::stringc& s) const +{ + s = prefix; + s += " "; + s += core::stringc((double)(color.getRed()/255.f)); + s += " "; + s += core::stringc((double)(color.getGreen()/255.f)); + s += " "; + s += core::stringc((double)(color.getBlue()/255.f)); + s += "\n"; +} + + +} // end namespace +} // end namespace + +#endif + diff --git a/source/Irrlicht/COBJMeshWriter.h b/source/Irrlicht/COBJMeshWriter.h new file mode 100644 index 00000000..962b1795 --- /dev/null +++ b/source/Irrlicht/COBJMeshWriter.h @@ -0,0 +1,58 @@ +// Copyright (C) 2008-2012 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_OBJ_MESH_WRITER_H_INCLUDED__ +#define __IRR_OBJ_MESH_WRITER_H_INCLUDED__ + +#include "IMeshWriter.h" +#include "S3DVertex.h" +#include "irrString.h" + +namespace irr +{ +namespace io +{ + class IFileSystem; +} // end namespace io +namespace scene +{ + class IMeshBuffer; + class ISceneManager; + + //! class to write meshes, implementing a OBJ writer + class COBJMeshWriter : public IMeshWriter + { + public: + + COBJMeshWriter(scene::ISceneManager* smgr, io::IFileSystem* fs); + virtual ~COBJMeshWriter(); + + //! Returns the type of the mesh writer + virtual EMESH_WRITER_TYPE getType() const _IRR_OVERRIDE_; + + //! writes a mesh + virtual bool writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags=EMWF_NONE) _IRR_OVERRIDE_; + + protected: + // create vector output with line end into string + void getVectorAsStringLine(const core::vector3df& v, + core::stringc& s) const; + + // create vector output with line end into string + void getVectorAsStringLine(const core::vector2df& v, + core::stringc& s) const; + + // create color output with line end into string + void getColorAsStringLine(const video::SColor& color, + const c8* const prefix, core::stringc& s) const; + + scene::ISceneManager* SceneManager; + io::IFileSystem* FileSystem; + }; + +} // end namespace +} // end namespace + +#endif + diff --git a/source/Irrlicht/COCTLoader.cpp b/source/Irrlicht/COCTLoader.cpp new file mode 100644 index 00000000..fb7025f7 --- /dev/null +++ b/source/Irrlicht/COCTLoader.cpp @@ -0,0 +1,335 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +// +// originally written by Murphy McCauley, see COCTLoader.h for details. +// +// COCTLoader by Murphy McCauley (February 2005) +// An Irrlicht loader for OCT files +// +// See the header file for additional information including use and distribution rights. + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_OCT_LOADER_ + +#include "COCTLoader.h" +#include "CMeshTextureLoader.h" +#include "IVideoDriver.h" +#include "IFileSystem.h" +#include "os.h" +#include "SAnimatedMesh.h" +#include "SMeshBufferLightMap.h" +#include "irrString.h" +#include "ISceneManager.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +COCTLoader::COCTLoader(ISceneManager* smgr, io::IFileSystem* fs) + : SceneManager(smgr), FileSystem(fs) +{ + #ifdef _DEBUG + setDebugName("COCTLoader"); + #endif + if (FileSystem) + FileSystem->grab(); + + TextureLoader = new CMeshTextureLoader( FileSystem, SceneManager->getVideoDriver() ); +} + + +//! destructor +COCTLoader::~COCTLoader() +{ + if (FileSystem) + FileSystem->drop(); +} + + +// Doesn't really belong here, but it's jammed in for now. +void COCTLoader::OCTLoadLights(io::IReadFile* file, scene::ISceneNode * parent, f32 radius, f32 intensityScale, bool rewind) +{ + if (rewind) + file->seek(0); + + octHeader header; + file->read(&header, sizeof(octHeader)); + + file->seek(sizeof(octVert)*header.numVerts, true); + file->seek(sizeof(octFace)*header.numFaces, true); + file->seek(sizeof(octTexture)*header.numTextures, true); + file->seek(sizeof(octLightmap)*header.numLightmaps, true); + + octLight * lights = new octLight[header.numLights]; + file->read(lights, header.numLights * sizeof(octLight)); + + //TODO: Skip past my extended data just for good form + + for (u32 i = 0; i < header.numLights; i++) + { + const f32 intensity = lights[i].intensity * intensityScale; + + SceneManager->addLightSceneNode(parent, core::vector3df(lights[i].pos[0], lights[i].pos[2], lights[i].pos[1]), + video::SColorf(lights[i].color[0] * intensity, lights[i].color[1] * intensity, lights[i].color[2] * intensity, 1.0f), + radius); + } +} + + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IReferenceCounted::drop() for more information. +IAnimatedMesh* COCTLoader::createMesh(io::IReadFile* file) +{ + if (!file) + return 0; + + if ( getMeshTextureLoader() ) + getMeshTextureLoader()->setMeshFile(file); + + octHeader header; + file->read(&header, sizeof(octHeader)); + + octVert * verts = new octVert[header.numVerts]; + octFace * faces = new octFace[header.numFaces]; + octTexture * textures = new octTexture[header.numTextures]; + octLightmap * lightmaps = new octLightmap[header.numLightmaps]; + octLight * lights = new octLight[header.numLights]; + + file->read(verts, sizeof(octVert) * header.numVerts); + file->read(faces, sizeof(octFace) * header.numFaces); + //TODO: Make sure id is in the legal range for Textures and Lightmaps + + u32 i; + for (i = 0; i < header.numTextures; i++) { + octTexture t; + file->read(&t, sizeof(octTexture)); + textures[t.id] = t; + } + for (i = 0; i < header.numLightmaps; i++) { + octLightmap t; + file->read(&t, sizeof(octLightmap)); + lightmaps[t.id] = t; + } + file->read(lights, sizeof(octLight) * header.numLights); + + //TODO: Now read in my extended OCT header (flexible lightmaps and vertex normals) + + + // This is the method Nikolaus Gebhardt used in the Q3 loader -- create a + // meshbuffer for every possible combination of lightmap and texture including + // a "null" texture and "null" lightmap. Ones that end up with nothing in them + // will be removed later. + + SMesh * Mesh = new SMesh(); + for (i=0; i<(header.numTextures+1) * (header.numLightmaps+1); ++i) + { + scene::SMeshBufferLightMap* buffer = new scene::SMeshBufferLightMap(); + + buffer->Material.MaterialType = video::EMT_LIGHTMAP; + buffer->Material.Lighting = false; + Mesh->addMeshBuffer(buffer); + buffer->drop(); + } + + + // Build the mesh buffers + for (i = 0; i < header.numFaces; i++) + { + if (faces[i].numVerts < 3) + continue; + + const f32* const a = verts[faces[i].firstVert].pos; + const f32* const b = verts[faces[i].firstVert+1].pos; + const f32* const c = verts[faces[i].firstVert+2].pos; + const core::vector3df normal = + core::plane3df(core::vector3df(a[0],a[1],a[2]), core::vector3df(b[0],c[1],c[2]), core::vector3df(c[0],c[1],c[2])).Normal; + + const u32 textureID = core::min_(s32(faces[i].textureID), s32(header.numTextures - 1)) + 1; + const u32 lightmapID = core::min_(s32(faces[i].lightmapID),s32(header.numLightmaps - 1)) + 1; + SMeshBufferLightMap * meshBuffer = (SMeshBufferLightMap*)Mesh->getMeshBuffer(lightmapID * (header.numTextures + 1) + textureID); + const u32 base = meshBuffer->Vertices.size(); + + // Add this face's verts + u32 v; + for (v = 0; v < faces[i].numVerts; ++v) + { + octVert * vv = &verts[faces[i].firstVert + v]; + video::S3DVertex2TCoords vert; + vert.Pos.set(vv->pos[0], vv->pos[1], vv->pos[2]); + vert.Color = video::SColor(0,255,255,255); + vert.Normal.set(normal); + + if (textureID == 0) + { + // No texture -- just a lightmap. Thus, use lightmap coords for texture 1. + // (the actual texture will be swapped later) + vert.TCoords.set(vv->lc[0], vv->lc[1]); + } + else + { + vert.TCoords.set(vv->tc[0], vv->tc[1]); + vert.TCoords2.set(vv->lc[0], vv->lc[1]); + } + + meshBuffer->Vertices.push_back(vert); + } + + // Now add the indices + // This weird loop turns convex polygons into triangle strips. + // I do it this way instead of a simple fan because it usually looks a lot better in wireframe, for example. + // High, Low + u32 h = faces[i].numVerts - 1; + u32 l = 0; + for (v = 0; v < faces[i].numVerts - 2; ++v) + { + const u32 center = (v & 1)? h - 1: l + 1; + + meshBuffer->Indices.push_back(base + h); + meshBuffer->Indices.push_back(base + l); + meshBuffer->Indices.push_back(base + center); + + if (v & 1) + --h; + else + ++l; + } + } + + // load textures + core::array tex; + tex.reallocate(header.numTextures + 1); + tex.push_back(0); + + for (i = 1; i < (header.numTextures + 1); i++) + { + tex.push_back( getMeshTextureLoader() ? getMeshTextureLoader()->getTexture(textures[i-1].fileName) : NULL ); + } + + // prepare lightmaps + core::array lig; + lig.set_used(header.numLightmaps + 1); + lig[0] = 0; + + const u32 lightmapWidth = 128; + const u32 lightmapHeight = 128; + 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); + + video::IImage* tmpImage = SceneManager->getVideoDriver()->createImage(video::ECF_R8G8B8, lmapsize); + for (i = 1; i < (header.numLightmaps + 1); ++i) + { + core::stringc lightmapname = file->getFileName(); + lightmapname += ".lightmap."; + lightmapname += (int)i; + + const octLightmap* lm = &lightmaps[i-1]; + + for (u32 x=0; xsetPixel(x, y, + video::SColor(255, + lm->data[x][y][2], + lm->data[x][y][1], + lm->data[x][y][0])); + } + } + + lig[i] = SceneManager->getVideoDriver()->addTexture(lightmapname.c_str(), tmpImage); + } + tmpImage->drop(); + SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, oldMipMapState); + + // Free stuff + delete [] verts; + delete [] faces; + delete [] textures; + delete [] lightmaps; + delete [] lights; + + // attach materials + for (i = 0; i < header.numLightmaps + 1; i++) + { + for (u32 j = 0; j < header.numTextures + 1; j++) + { + u32 mb = i * (header.numTextures + 1) + j; + SMeshBufferLightMap * meshBuffer = (SMeshBufferLightMap*)Mesh->getMeshBuffer(mb); + meshBuffer->Material.setTexture(0, tex[j]); + meshBuffer->Material.setTexture(1, lig[i]); + + if (meshBuffer->Material.getTexture(0) == 0) + { + // This material has no texture, so we'll just show the lightmap if there is one. + // We swapped the texture coordinates earlier. + meshBuffer->Material.setTexture(0, meshBuffer->Material.getTexture(1)); + meshBuffer->Material.setTexture(1, 0); + } + if (meshBuffer->Material.getTexture(1) == 0) + { + // If there is only one texture, it should be solid and lit. + // Among other things, this way you can preview OCT lights. + meshBuffer->Material.MaterialType = video::EMT_SOLID; + meshBuffer->Material.Lighting = true; + } + } + } + + // delete all buffers without geometry in it. + i = 0; + while(i < Mesh->MeshBuffers.size()) + { + if (Mesh->MeshBuffers[i]->getVertexCount() == 0 || + Mesh->MeshBuffers[i]->getIndexCount() == 0 || + Mesh->MeshBuffers[i]->getMaterial().getTexture(0) == 0) + { + // Meshbuffer is empty -- drop it + Mesh->MeshBuffers[i]->drop(); + Mesh->MeshBuffers.erase(i); + } + else + { + ++i; + } + } + + + // create bounding box + for (i = 0; i < Mesh->MeshBuffers.size(); ++i) + { + Mesh->MeshBuffers[i]->recalculateBoundingBox(); + } + Mesh->recalculateBoundingBox(); + + + // Set up an animated mesh to hold the mesh + SAnimatedMesh* AMesh = new SAnimatedMesh(); + AMesh->Type = EAMT_OCT; + AMesh->addMesh(Mesh); + AMesh->recalculateBoundingBox(); + Mesh->drop(); + + return AMesh; +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool COCTLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "oct" ); +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_OCT_LOADER_ + diff --git a/source/Irrlicht/COCTLoader.h b/source/Irrlicht/COCTLoader.h new file mode 100644 index 00000000..560d1190 --- /dev/null +++ b/source/Irrlicht/COCTLoader.h @@ -0,0 +1,141 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +// +// Because I (Nikolaus Gebhardt) did some changes to Murphy McCauley's loader, +// I'm writing this down here: +// - Replaced all dependencies to STL and stdio with irr:: methods/constructs +// - Disabled logging define +// - Changed some minor things (Don't remember what exactly.) +// Thanks a lot to Murphy McCauley for writing this loader. + +// +// COCTLoader by Murphy McCauley (February 2005) +// An Irrlicht loader for OCT files +// +// OCT file format information comes from the sourcecode of the Fluid Studios +// Radiosity Processor by Paul Nettle. You can get that sourcecode from +// http://www.fluidstudios.com . +// +// Parts of this code are from Irrlicht's CQ3LevelMesh and C3DSMeshFileLoader, +// and are Copyright (C) 2002-2004 Nikolaus Gebhardt. +// +// Use of this code is subject to the following: +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// 4. You may not use this software to directly or indirectly cause harm to others. + + +#ifndef __C_OCT_LOADER_H_INCLUDED__ +#define __C_OCT_LOADER_H_INCLUDED__ + +#include "IMeshLoader.h" +#include "IReadFile.h" +#include "SMesh.h" +#include "irrString.h" + +namespace irr +{ +namespace io +{ + class IFileSystem; +} // end namespace io +namespace scene +{ + class ISceneManager; + class ISceneNode; + + class COCTLoader : public IMeshLoader + { + public: + //! constructor + COCTLoader(ISceneManager* smgr, io::IFileSystem* fs); + + //! destructor + virtual ~COCTLoader(); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".cob") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! creates/loads an animated mesh from the file. + //! \return Pointer to the created mesh. Returns 0 if loading failed. + //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). + //! See IReferenceCounted::drop() for more information. + virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_; + + void OCTLoadLights(io::IReadFile* file, + ISceneNode * parent = 0, f32 radius = 500.0f, + f32 intensityScale = 0.0000001f*2.5, + bool rewind = true); + + private: + struct octHeader { + u32 numVerts; + u32 numFaces; + u32 numTextures; + u32 numLightmaps; + u32 numLights; + }; + + struct octHeaderEx { + u32 magic; // 'OCTX' - 0x4F435458L + u32 numLightmaps; + u32 lightmapWidth; + u32 lightmapHeight; + u32 containsVertexNormals; + }; + + struct octFace { + u32 firstVert; + u32 numVerts; + u32 textureID; + u32 lightmapID; + f32 plane[4]; + }; + + struct octVert { + f32 tc[2]; + f32 lc[2]; + f32 pos[3]; + }; + + struct octTexture { + u32 id; + char fileName[64]; + }; + + struct octLightmap { + u32 id; + u8 data[128][128][3]; + }; + + struct octLight { + f32 pos[3]; + f32 color[3]; + u32 intensity; + }; + + ISceneManager* SceneManager; + io::IFileSystem* FileSystem; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/COGLES2Common.h b/source/Irrlicht/COGLES2Common.h new file mode 100644 index 00000000..8b01c8e6 --- /dev/null +++ b/source/Irrlicht/COGLES2Common.h @@ -0,0 +1,76 @@ +// Copyright (C) 2015 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OGLES2_COMMON_H_INCLUDED__ +#define __C_OGLES2_COMMON_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#if defined(_IRR_COMPILE_WITH_IOS_DEVICE_) +#include +#include +#elif defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_) +#include +#include +#include +#elif defined(_IRR_EMSCRIPTEN_PLATFORM_) +#include +#include +#include +#else +#if defined(_IRR_OGLES2_USE_EXTPOINTER_) + #define GL_GLEXT_PROTOTYPES 1 + #define GLX_GLXEXT_PROTOTYPES 1 +#endif +#include +#include +typedef char GLchar; +#if defined(_IRR_OGLES2_USE_EXTPOINTER_) +#include "gles2-ext.h" +#endif +#endif + +#ifndef GL_BGRA +#define GL_BGRA 0x80E1; +#endif + +// FBO definitions. + +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 1 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 2 +#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS 3 + +// to check if this header is in the current compile unit (different GL implementation used different "GLCommon" headers in Irrlicht +#define IRR_COMPILE_GLES2_COMMON + +namespace irr +{ +namespace video +{ + + // Forward declarations. + + class COpenGLCoreFeature; + + template + class COpenGLCoreTexture; + + template + class COpenGLCoreRenderTarget; + + template + class COpenGLCoreCacheHandler; + + class COGLES2Driver; + typedef COpenGLCoreTexture COGLES2Texture; + typedef COpenGLCoreRenderTarget COGLES2RenderTarget; + typedef COpenGLCoreCacheHandler COGLES2CacheHandler; + +} +} + +#endif +#endif diff --git a/source/Irrlicht/COGLES2Driver.cpp b/source/Irrlicht/COGLES2Driver.cpp new file mode 100644 index 00000000..5f5c6b39 --- /dev/null +++ b/source/Irrlicht/COGLES2Driver.cpp @@ -0,0 +1,3003 @@ +// Copyright (C) 2014 Patryk Nadrowski +// Copyright (C) 2009-2010 Amundis +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#include "COGLES2Driver.h" +#include "CNullDriver.h" +#include "IContextManager.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "COpenGLCoreTexture.h" +#include "COpenGLCoreRenderTarget.h" +#include "COpenGLCoreCacheHandler.h" + +#include "COGLES2MaterialRenderer.h" +#include "COGLES2FixedPipelineRenderer.h" +#include "COGLES2NormalMapRenderer.h" +#include "COGLES2ParallaxMapRenderer.h" +#include "COGLES2Renderer2D.h" + +#include "EVertexAttributes.h" +#include "CImage.h" +#include "os.h" +#include "EProfileIDs.h" +#include "IProfiler.h" + +#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_ +#include "android_native_app_glue.h" +#endif + +namespace irr +{ +namespace video +{ + +COGLES2Driver::COGLES2Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager) : + CNullDriver(io, params.WindowSize), COGLES2ExtensionHandler(), CacheHandler(0), + Params(params), ResetRenderStates(true), LockRenderStateMode(false), AntiAlias(params.AntiAlias), + MaterialRenderer2DActive(0), MaterialRenderer2DTexture(0), MaterialRenderer2DNoTexture(0), + CurrentRenderMode(ERM_NONE), Transformation3DChanged(true), + OGLES2ShaderPath(params.OGLES2ShaderPath), + ColorFormat(ECF_R8G8B8), ContextManager(contextManager) +{ +#ifdef _DEBUG + setDebugName("COGLES2Driver"); +#endif + + IRR_PROFILE( + static bool initProfile = false; + if (!initProfile ) + { + initProfile = true; + getProfiler().add(EPID_ES2_END_SCENE, L"endScene", L"ES2"); + getProfiler().add(EPID_ES2_BEGIN_SCENE, L"beginScene", L"ES2"); + getProfiler().add(EPID_ES2_UPDATE_VERTEX_HW_BUF, L"upVertBuf", L"ES2"); + getProfiler().add(EPID_ES2_UPDATE_INDEX_HW_BUF, L"upIdxBuf", L"ES2"); + getProfiler().add(EPID_ES2_DRAW_PRIMITIVES, L"drawPrim", L"ES2"); + getProfiler().add(EPID_ES2_DRAW_2DIMAGE, L"draw2dImg", L"ES2"); + getProfiler().add(EPID_ES2_DRAW_2DIMAGE_BATCH, L"draw2dImgB", L"ES2"); + getProfiler().add(EPID_ES2_DRAW_2DRECTANGLE, L"draw2dRect", L"ES2"); + getProfiler().add(EPID_ES2_DRAW_2DLINE, L"draw2dLine", L"ES2"); + getProfiler().add(EPID_ES2_DRAW_3DLINE, L"draw3dLine", L"ES2"); + getProfiler().add(EPID_ES2_SET_RENDERSTATE_2D, L"rstate2d", L"ES2"); + getProfiler().add(EPID_ES2_SET_RENDERSTATE_3D, L"rstate3d", L"ES2"); + getProfiler().add(EPID_ES2_SET_RENDERSTATE_BASIC, L"rstateBasic", L"ES2"); + getProfiler().add(EPID_ES2_SET_RENDERSTATE_TEXTURE, L"rstateTex", L"ES2"); + getProfiler().add(EPID_ES2_DRAW_SHADOW, L"shadows", L"ES2"); + } + ) + if (!ContextManager) + return; + + ContextManager->grab(); + ContextManager->generateSurface(); + ContextManager->generateContext(); + ExposedData = ContextManager->getContext(); + ContextManager->activateContext(ExposedData, false); +} + +COGLES2Driver::~COGLES2Driver() +{ + RequestedLights.clear(); + + deleteMaterialRenders(); + + CacheHandler->getTextureCache().clear(); + + removeAllRenderTargets(); + deleteAllTextures(); + removeAllOcclusionQueries(); + removeAllHardwareBuffers(); + + delete MaterialRenderer2DTexture; + delete MaterialRenderer2DNoTexture; + delete CacheHandler; + + if (ContextManager) + { + ContextManager->destroyContext(); + ContextManager->destroySurface(); + ContextManager->terminate(); + ContextManager->drop(); + } +} + + bool COGLES2Driver::genericDriverInit(const core::dimension2d& screenSize, bool stencilBuffer) + { + Name = glGetString(GL_VERSION); + printVersion(); + + // print renderer information + VendorName = glGetString(GL_VENDOR); + os::Printer::log(VendorName.c_str(), ELL_INFORMATION); + + // load extensions + initExtensions(); + + // reset cache handler + delete CacheHandler; + CacheHandler = new COGLES2CacheHandler(this); + + StencilBuffer = stencilBuffer; + + DriverAttributes->setAttribute("MaxTextures", (s32)Feature.MaxTextureUnits); + DriverAttributes->setAttribute("MaxSupportedTextures", (s32)Feature.MaxTextureUnits); +// DriverAttributes->setAttribute("MaxLights", MaxLights); + DriverAttributes->setAttribute("MaxAnisotropy", MaxAnisotropy); +// DriverAttributes->setAttribute("MaxUserClipPlanes", MaxUserClipPlanes); +// DriverAttributes->setAttribute("MaxAuxBuffers", MaxAuxBuffers); +// DriverAttributes->setAttribute("MaxMultipleRenderTargets", MaxMultipleRenderTargets); + DriverAttributes->setAttribute("MaxIndices", (s32)MaxIndices); + DriverAttributes->setAttribute("MaxTextureSize", (s32)MaxTextureSize); + DriverAttributes->setAttribute("MaxTextureLODBias", MaxTextureLODBias); + DriverAttributes->setAttribute("Version", Version); + DriverAttributes->setAttribute("AntiAlias", AntiAlias); + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + UserClipPlane.reallocate(0); + + for (s32 i = 0; i < ETS_COUNT; ++i) + setTransform(static_cast(i), core::IdentityMatrix); + + setAmbientLight(SColorf(0.0f, 0.0f, 0.0f, 0.0f)); + glClearDepthf(1.0f); + + glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST); + glFrontFace(GL_CW); + + // create material renderers + createMaterialRenderers(); + + // set the renderstates + setRenderStates3DMode(); + + // set fog mode + setFog(FogColor, FogType, FogStart, FogEnd, FogDensity, PixelFog, RangeFog); + + // create matrix for flipping textures + TextureFlipMatrix.buildTextureTransform(0.0f, core::vector2df(0, 0), core::vector2df(0, 1.0f), core::vector2df(1.0f, -1.0f)); + + // We need to reset once more at the beginning of the first rendering. + // This fixes problems with intermediate changes to the material during texture load. + ResetRenderStates = true; + + testGLError(__LINE__); + + return true; + } + + void COGLES2Driver::loadShaderData(const io::path& vertexShaderName, const io::path& fragmentShaderName, c8** vertexShaderData, c8** fragmentShaderData) + { + io::path vsPath(OGLES2ShaderPath); + vsPath += vertexShaderName; + + io::path fsPath(OGLES2ShaderPath); + fsPath += fragmentShaderName; + + *vertexShaderData = 0; + *fragmentShaderData = 0; + + io::IReadFile* vsFile = FileSystem->createAndOpenFile(vsPath); + if ( !vsFile ) + { + core::stringw warning(L"Warning: Missing shader files needed to simulate fixed function materials:\n"); + warning += core::stringw(vsPath) + L"\n"; + warning += L"Shaderpath can be changed in SIrrCreationParamters::OGLES2ShaderPath"; + os::Printer::log(warning.c_str(), ELL_WARNING); + return; + } + + io::IReadFile* fsFile = FileSystem->createAndOpenFile(fsPath); + if ( !fsFile ) + { + core::stringw warning(L"Warning: Missing shader files needed to simulate fixed function materials:\n"); + warning += core::stringw(fsPath) + L"\n"; + warning += L"Shaderpath can be changed in SIrrCreationParamters::OGLES2ShaderPath"; + os::Printer::log(warning.c_str(), ELL_WARNING); + return; + } + + long size = vsFile->getSize(); + if (size) + { + *vertexShaderData = new c8[size+1]; + vsFile->read(*vertexShaderData, size); + (*vertexShaderData)[size] = 0; + } + + size = fsFile->getSize(); + if (size) + { + // if both handles are the same we must reset the file + if (fsFile == vsFile) + fsFile->seek(0); + + *fragmentShaderData = new c8[size+1]; + fsFile->read(*fragmentShaderData, size); + (*fragmentShaderData)[size] = 0; + } + + vsFile->drop(); + fsFile->drop(); + } + + void COGLES2Driver::createMaterialRenderers() + { + // Create callbacks. + + COGLES2MaterialSolidCB* SolidCB = new COGLES2MaterialSolidCB(); + COGLES2MaterialSolid2CB* Solid2LayerCB = new COGLES2MaterialSolid2CB(); + COGLES2MaterialLightmapCB* LightmapCB = new COGLES2MaterialLightmapCB(1.f); + COGLES2MaterialLightmapCB* LightmapAddCB = new COGLES2MaterialLightmapCB(1.f); + COGLES2MaterialLightmapCB* LightmapM2CB = new COGLES2MaterialLightmapCB(2.f); + COGLES2MaterialLightmapCB* LightmapM4CB = new COGLES2MaterialLightmapCB(4.f); + COGLES2MaterialLightmapCB* LightmapLightingCB = new COGLES2MaterialLightmapCB(1.f); + COGLES2MaterialLightmapCB* LightmapLightingM2CB = new COGLES2MaterialLightmapCB(2.f); + COGLES2MaterialLightmapCB* LightmapLightingM4CB = new COGLES2MaterialLightmapCB(4.f); + COGLES2MaterialSolid2CB* DetailMapCB = new COGLES2MaterialSolid2CB(); + COGLES2MaterialReflectionCB* SphereMapCB = new COGLES2MaterialReflectionCB(); + COGLES2MaterialReflectionCB* Reflection2LayerCB = new COGLES2MaterialReflectionCB(); + COGLES2MaterialSolidCB* TransparentAddColorCB = new COGLES2MaterialSolidCB(); + COGLES2MaterialSolidCB* TransparentAlphaChannelCB = new COGLES2MaterialSolidCB(); + COGLES2MaterialSolidCB* TransparentAlphaChannelRefCB = new COGLES2MaterialSolidCB(); + COGLES2MaterialSolidCB* TransparentVertexAlphaCB = new COGLES2MaterialSolidCB(); + COGLES2MaterialReflectionCB* TransparentReflection2LayerCB = new COGLES2MaterialReflectionCB(); + COGLES2MaterialNormalMapCB* NormalMapCB = new COGLES2MaterialNormalMapCB(); + COGLES2MaterialNormalMapCB* NormalMapAddColorCB = new COGLES2MaterialNormalMapCB(); + COGLES2MaterialNormalMapCB* NormalMapVertexAlphaCB = new COGLES2MaterialNormalMapCB(); + COGLES2MaterialParallaxMapCB* ParallaxMapCB = new COGLES2MaterialParallaxMapCB(); + COGLES2MaterialParallaxMapCB* ParallaxMapAddColorCB = new COGLES2MaterialParallaxMapCB(); + COGLES2MaterialParallaxMapCB* ParallaxMapVertexAlphaCB = new COGLES2MaterialParallaxMapCB(); + COGLES2MaterialOneTextureBlendCB* OneTextureBlendCB = new COGLES2MaterialOneTextureBlendCB(); + + // Create built-in materials. + + core::stringc VertexShader = OGLES2ShaderPath + "COGLES2Solid.vsh"; + core::stringc FragmentShader = OGLES2ShaderPath + "COGLES2Solid.fsh"; + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, SolidCB, EMT_SOLID, 0); + + VertexShader = OGLES2ShaderPath + "COGLES2Solid2.vsh"; + FragmentShader = OGLES2ShaderPath + "COGLES2Solid2Layer.fsh"; + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, Solid2LayerCB, EMT_SOLID, 0); + + VertexShader = OGLES2ShaderPath + "COGLES2Solid2.vsh"; + FragmentShader = OGLES2ShaderPath + "COGLES2LightmapModulate.fsh"; + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, LightmapCB, EMT_SOLID, 0); + + FragmentShader = OGLES2ShaderPath + "COGLES2LightmapAdd.fsh"; + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, LightmapAddCB, EMT_SOLID, 0); + + FragmentShader = OGLES2ShaderPath + "COGLES2LightmapModulate.fsh"; + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, LightmapM2CB, EMT_SOLID, 0); + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, LightmapM4CB, EMT_SOLID, 0); + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, LightmapLightingCB, EMT_SOLID, 0); + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, LightmapLightingM2CB, EMT_SOLID, 0); + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, LightmapLightingM4CB, EMT_SOLID, 0); + + VertexShader = OGLES2ShaderPath + "COGLES2Solid2.vsh"; + FragmentShader = OGLES2ShaderPath + "COGLES2DetailMap.fsh"; + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, DetailMapCB, EMT_SOLID, 0); + + VertexShader = OGLES2ShaderPath + "COGLES2SphereMap.vsh"; + FragmentShader = OGLES2ShaderPath + "COGLES2SphereMap.fsh"; + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, SphereMapCB, EMT_SOLID, 0); + + VertexShader = OGLES2ShaderPath + "COGLES2Reflection2Layer.vsh"; + FragmentShader = OGLES2ShaderPath + "COGLES2Reflection2Layer.fsh"; + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, Reflection2LayerCB, EMT_SOLID, 0); + + VertexShader = OGLES2ShaderPath + "COGLES2Solid.vsh"; + FragmentShader = OGLES2ShaderPath + "COGLES2Solid.fsh"; + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentAddColorCB, EMT_TRANSPARENT_ADD_COLOR, 0); + + FragmentShader = OGLES2ShaderPath + "COGLES2TransparentAlphaChannel.fsh"; + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentAlphaChannelCB, EMT_TRANSPARENT_ALPHA_CHANNEL, 0); + + FragmentShader = OGLES2ShaderPath + "COGLES2TransparentAlphaChannelRef.fsh"; + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentAlphaChannelRefCB, EMT_SOLID, 0); + + FragmentShader = OGLES2ShaderPath + "COGLES2TransparentVertexAlpha.fsh"; + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentVertexAlphaCB, EMT_TRANSPARENT_ALPHA_CHANNEL, 0); + + VertexShader = OGLES2ShaderPath + "COGLES2Reflection2Layer.vsh"; + FragmentShader = OGLES2ShaderPath + "COGLES2Reflection2Layer.fsh"; + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, TransparentReflection2LayerCB, EMT_TRANSPARENT_ALPHA_CHANNEL, 0); + + VertexShader = OGLES2ShaderPath + "COGLES2NormalMap.vsh"; + FragmentShader = OGLES2ShaderPath + "COGLES2NormalMap.fsh"; + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, NormalMapCB, EMT_SOLID, 0); + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, NormalMapAddColorCB, EMT_TRANSPARENT_ADD_COLOR, 0); + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, NormalMapVertexAlphaCB, EMT_TRANSPARENT_ALPHA_CHANNEL, 0); + + VertexShader = OGLES2ShaderPath + "COGLES2ParallaxMap.vsh"; + FragmentShader = OGLES2ShaderPath + "COGLES2ParallaxMap.fsh"; + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, ParallaxMapCB, EMT_SOLID, 0); + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, ParallaxMapAddColorCB, EMT_TRANSPARENT_ADD_COLOR, 0); + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, ParallaxMapVertexAlphaCB, EMT_TRANSPARENT_ALPHA_CHANNEL, 0); + + VertexShader = OGLES2ShaderPath + "COGLES2Solid.vsh"; + FragmentShader = OGLES2ShaderPath + "COGLES2OneTextureBlend.fsh"; + + addHighLevelShaderMaterialFromFiles(VertexShader, "main", EVST_VS_2_0, FragmentShader, "main", EPST_PS_2_0, "", "main", + EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, OneTextureBlendCB, EMT_ONETEXTURE_BLEND, 0); + + // Drop callbacks. + + SolidCB->drop(); + Solid2LayerCB->drop(); + LightmapCB->drop(); + LightmapAddCB->drop(); + LightmapM2CB->drop(); + LightmapM4CB->drop(); + LightmapLightingCB->drop(); + LightmapLightingM2CB->drop(); + LightmapLightingM4CB->drop(); + DetailMapCB->drop(); + SphereMapCB->drop(); + Reflection2LayerCB->drop(); + TransparentAddColorCB->drop(); + TransparentAlphaChannelCB->drop(); + TransparentAlphaChannelRefCB->drop(); + TransparentVertexAlphaCB->drop(); + TransparentReflection2LayerCB->drop(); + NormalMapCB->drop(); + NormalMapAddColorCB->drop(); + NormalMapVertexAlphaCB->drop(); + ParallaxMapCB->drop(); + ParallaxMapAddColorCB->drop(); + ParallaxMapVertexAlphaCB->drop(); + OneTextureBlendCB->drop(); + + // Create 2D material renderers + + c8* vs2DData = 0; + c8* fs2DData = 0; + loadShaderData(io::path("COGLES2Renderer2D.vsh"), io::path("COGLES2Renderer2D.fsh"), &vs2DData, &fs2DData); + MaterialRenderer2DTexture = new COGLES2Renderer2D(vs2DData, fs2DData, this, true); + delete[] vs2DData; + delete[] fs2DData; + vs2DData = 0; + fs2DData = 0; + + loadShaderData(io::path("COGLES2Renderer2D.vsh"), io::path("COGLES2Renderer2D_noTex.fsh"), &vs2DData, &fs2DData); + MaterialRenderer2DNoTexture = new COGLES2Renderer2D(vs2DData, fs2DData, this, false); + delete[] vs2DData; + delete[] fs2DData; + } + + bool COGLES2Driver::setMaterialTexture(irr::u32 layerIdx, const irr::video::ITexture* texture) + { + Material.TextureLayer[layerIdx].Texture = const_cast(texture); // function uses const-pointer for texture because all draw functions use const-pointers already + return CacheHandler->getTextureCache().set(0, texture); + } + + bool COGLES2Driver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil, const SExposedVideoData& videoData, core::rect* sourceRect) + { + IRR_PROFILE(CProfileScope p1(EPID_ES2_BEGIN_SCENE);) + + CNullDriver::beginScene(clearFlag, clearColor, clearDepth, clearStencil, videoData, sourceRect); + + if (ContextManager) + ContextManager->activateContext(videoData, true); + + clearBuffers(clearFlag, clearColor, clearDepth, clearStencil); + + return true; + } + + bool COGLES2Driver::endScene() + { + IRR_PROFILE(CProfileScope p1(EPID_ES2_END_SCENE);) + + CNullDriver::endScene(); + + glFlush(); + + if (ContextManager) + return ContextManager->swapBuffers(); + + return false; + } + + + //! Returns the transformation set by setTransform + const core::matrix4& COGLES2Driver::getTransform(E_TRANSFORMATION_STATE state) const + { + return Matrices[state]; + } + + + //! sets transformation + void COGLES2Driver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) + { + Matrices[state] = mat; + Transformation3DChanged = true; + } + + + bool COGLES2Driver::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) + { + if (!HWBuffer) + return false; + + IRR_PROFILE(CProfileScope p1(EPID_ES2_UPDATE_VERTEX_HW_BUF);) + + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + const void* vertices = mb->getVertices(); + const u32 vertexCount = mb->getVertexCount(); + const E_VERTEX_TYPE vType = mb->getVertexType(); + const u32 vertexSize = getVertexPitchFromType(vType); + + //buffer vertex data, and convert colours... + core::array buffer(vertexSize * vertexCount); + memcpy(buffer.pointer(), vertices, vertexSize * vertexCount); + + //get or create buffer + bool newBuffer = false; + if (!HWBuffer->vbo_verticesID) + { + glGenBuffers(1, &HWBuffer->vbo_verticesID); + if (!HWBuffer->vbo_verticesID) return false; + newBuffer = true; + } + else if (HWBuffer->vbo_verticesSize < vertexCount*vertexSize) + { + newBuffer = true; + } + + glBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID); + + // copy data to graphics card + if (!newBuffer) + glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * vertexSize, buffer.const_pointer()); + else + { + HWBuffer->vbo_verticesSize = vertexCount * vertexSize; + + if (HWBuffer->Mapped_Vertex == scene::EHM_STATIC) + glBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, buffer.const_pointer(), GL_STATIC_DRAW); + else + glBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, buffer.const_pointer(), GL_DYNAMIC_DRAW); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + + return (!testGLError(__LINE__)); + } + + + bool COGLES2Driver::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) + { + if (!HWBuffer) + return false; + + IRR_PROFILE(CProfileScope p1(EPID_ES2_UPDATE_INDEX_HW_BUF);) + + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + + const void* indices = mb->getIndices(); + u32 indexCount = mb->getIndexCount(); + + GLenum indexSize; + switch (mb->getIndexType()) + { + case(EIT_16BIT): + { + indexSize = sizeof(u16); + break; + } + case(EIT_32BIT): + { + indexSize = sizeof(u32); + break; + } + default: + { + return false; + } + } + + //get or create buffer + bool newBuffer = false; + if (!HWBuffer->vbo_indicesID) + { + glGenBuffers(1, &HWBuffer->vbo_indicesID); + if (!HWBuffer->vbo_indicesID) return false; + newBuffer = true; + } + else if (HWBuffer->vbo_indicesSize < indexCount*indexSize) + { + newBuffer = true; + } + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID); + + // copy data to graphics card + if (!newBuffer) + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexCount * indexSize, indices); + else + { + HWBuffer->vbo_indicesSize = indexCount * indexSize; + + if (HWBuffer->Mapped_Index == scene::EHM_STATIC) + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STATIC_DRAW); + else + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_DYNAMIC_DRAW); + } + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + return (!testGLError(__LINE__)); + } + + + //! updates hardware buffer if needed + bool COGLES2Driver::updateHardwareBuffer(SHWBufferLink *HWBuffer) + { + if (!HWBuffer) + return false; + + if (HWBuffer->Mapped_Vertex != scene::EHM_NEVER) + { + if (HWBuffer->ChangedID_Vertex != HWBuffer->MeshBuffer->getChangedID_Vertex() + || !static_cast(HWBuffer)->vbo_verticesID) + { + + HWBuffer->ChangedID_Vertex = HWBuffer->MeshBuffer->getChangedID_Vertex(); + + if (!updateVertexHardwareBuffer(static_cast(HWBuffer))) + return false; + } + } + + if (HWBuffer->Mapped_Index != scene::EHM_NEVER) + { + if (HWBuffer->ChangedID_Index != HWBuffer->MeshBuffer->getChangedID_Index() + || !static_cast(HWBuffer)->vbo_indicesID) + { + + HWBuffer->ChangedID_Index = HWBuffer->MeshBuffer->getChangedID_Index(); + + if (!updateIndexHardwareBuffer((SHWBufferLink_opengl*)HWBuffer)) + return false; + } + } + + return true; + } + + + //! Create hardware buffer from meshbuffer + COGLES2Driver::SHWBufferLink *COGLES2Driver::createHardwareBuffer(const scene::IMeshBuffer* mb) + { + if (!mb || (mb->getHardwareMappingHint_Index() == scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex() == scene::EHM_NEVER)) + return 0; + + SHWBufferLink_opengl *HWBuffer = new SHWBufferLink_opengl(mb); + + //add to map + HWBufferMap.insert(HWBuffer->MeshBuffer, HWBuffer); + + HWBuffer->ChangedID_Vertex = HWBuffer->MeshBuffer->getChangedID_Vertex(); + HWBuffer->ChangedID_Index = HWBuffer->MeshBuffer->getChangedID_Index(); + HWBuffer->Mapped_Vertex = mb->getHardwareMappingHint_Vertex(); + HWBuffer->Mapped_Index = mb->getHardwareMappingHint_Index(); + HWBuffer->LastUsed = 0; + HWBuffer->vbo_verticesID = 0; + HWBuffer->vbo_indicesID = 0; + HWBuffer->vbo_verticesSize = 0; + HWBuffer->vbo_indicesSize = 0; + + if (!updateHardwareBuffer(HWBuffer)) + { + deleteHardwareBuffer(HWBuffer); + return 0; + } + + return HWBuffer; + } + + + void COGLES2Driver::deleteHardwareBuffer(SHWBufferLink *_HWBuffer) + { + if (!_HWBuffer) + return; + + SHWBufferLink_opengl *HWBuffer = static_cast(_HWBuffer); + if (HWBuffer->vbo_verticesID) + { + glDeleteBuffers(1, &HWBuffer->vbo_verticesID); + HWBuffer->vbo_verticesID = 0; + } + if (HWBuffer->vbo_indicesID) + { + glDeleteBuffers(1, &HWBuffer->vbo_indicesID); + HWBuffer->vbo_indicesID = 0; + } + + CNullDriver::deleteHardwareBuffer(_HWBuffer); + } + + + //! Draw hardware buffer + void COGLES2Driver::drawHardwareBuffer(SHWBufferLink *_HWBuffer) + { + if (!_HWBuffer) + return; + + SHWBufferLink_opengl *HWBuffer = static_cast(_HWBuffer); + + updateHardwareBuffer(HWBuffer); //check if update is needed + + HWBuffer->LastUsed = 0;//reset count + + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + const void *vertices = mb->getVertices(); + const void *indexList = mb->getIndices(); + + if (HWBuffer->Mapped_Vertex != scene::EHM_NEVER) + { + glBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID); + vertices = 0; + } + + if (HWBuffer->Mapped_Index != scene::EHM_NEVER) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID); + indexList = 0; + } + + + drawVertexPrimitiveList(vertices, mb->getVertexCount(), + indexList, mb->getPrimitiveCount(), + mb->getVertexType(), mb->getPrimitiveType(), + mb->getIndexType()); + + if (HWBuffer->Mapped_Vertex != scene::EHM_NEVER) + glBindBuffer(GL_ARRAY_BUFFER, 0); + + if (HWBuffer->Mapped_Index != scene::EHM_NEVER) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + + + IRenderTarget* COGLES2Driver::addRenderTarget() + { + COGLES2RenderTarget* renderTarget = new COGLES2RenderTarget(this); + RenderTargets.push_back(renderTarget); + + return renderTarget; + } + + + // small helper function to create vertex buffer object adress offsets + static inline u8* buffer_offset(const long offset) + { + return ((u8*)0 + offset); + } + + + //! draws a vertex primitive list + void COGLES2Driver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) + { + if (!primitiveCount || !vertexCount) + return; + + if (!checkPrimitiveCount(primitiveCount)) + return; + + IRR_PROFILE(CProfileScope p1(EPID_ES2_DRAW_PRIMITIVES);) + + CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType); + + setRenderStates3DMode(); + + glEnableVertexAttribArray(EVA_POSITION); + glEnableVertexAttribArray(EVA_COLOR); + glEnableVertexAttribArray(EVA_NORMAL); + glEnableVertexAttribArray(EVA_TCOORD0); + + switch (vType) + { + case EVT_STANDARD: + if (vertices) + { + glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast(vertices))[0].Pos); + glVertexAttribPointer(EVA_NORMAL, 3, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast(vertices))[0].Normal); + glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex), &(static_cast(vertices))[0].Color); + glVertexAttribPointer(EVA_TCOORD0, 2, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); + } + else + { + glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex), 0); + glVertexAttribPointer(EVA_NORMAL, 3, GL_FLOAT, false, sizeof(S3DVertex), buffer_offset(12)); + glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex), buffer_offset(24)); + glVertexAttribPointer(EVA_TCOORD0, 2, GL_FLOAT, false, sizeof(S3DVertex), buffer_offset(28)); + } + + break; + case EVT_2TCOORDS: + glEnableVertexAttribArray(EVA_TCOORD1); + + if (vertices) + { + glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Pos); + glVertexAttribPointer(EVA_NORMAL, 3, GL_FLOAT, false, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Normal); + glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Color); + glVertexAttribPointer(EVA_TCOORD0, 2, GL_FLOAT, false, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords); + glVertexAttribPointer(EVA_TCOORD1, 2, GL_FLOAT, false, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords2); + } + else + { + glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex2TCoords), buffer_offset(0)); + glVertexAttribPointer(EVA_NORMAL, 3, GL_FLOAT, false, sizeof(S3DVertex2TCoords), buffer_offset(12)); + glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex2TCoords), buffer_offset(24)); + glVertexAttribPointer(EVA_TCOORD0, 2, GL_FLOAT, false, sizeof(S3DVertex2TCoords), buffer_offset(28)); + glVertexAttribPointer(EVA_TCOORD1, 2, GL_FLOAT, false, sizeof(S3DVertex2TCoords), buffer_offset(36)); + } + break; + case EVT_TANGENTS: + glEnableVertexAttribArray(EVA_TANGENT); + glEnableVertexAttribArray(EVA_BINORMAL); + + if (vertices) + { + glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Pos); + glVertexAttribPointer(EVA_NORMAL, 3, GL_FLOAT, false, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Normal); + glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Color); + glVertexAttribPointer(EVA_TCOORD0, 2, GL_FLOAT, false, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].TCoords); + glVertexAttribPointer(EVA_TANGENT, 3, GL_FLOAT, false, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Tangent); + glVertexAttribPointer(EVA_BINORMAL, 3, GL_FLOAT, false, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Binormal); + } + else + { + glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertexTangents), buffer_offset(0)); + glVertexAttribPointer(EVA_NORMAL, 3, GL_FLOAT, false, sizeof(S3DVertexTangents), buffer_offset(12)); + glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertexTangents), buffer_offset(24)); + glVertexAttribPointer(EVA_TCOORD0, 2, GL_FLOAT, false, sizeof(S3DVertexTangents), buffer_offset(28)); + glVertexAttribPointer(EVA_TANGENT, 3, GL_FLOAT, false, sizeof(S3DVertexTangents), buffer_offset(36)); + glVertexAttribPointer(EVA_BINORMAL, 3, GL_FLOAT, false, sizeof(S3DVertexTangents), buffer_offset(48)); + } + break; + } + + GLenum indexSize = 0; + + switch (iType) + { + case(EIT_16BIT): + { + indexSize = GL_UNSIGNED_SHORT; + break; + } + case(EIT_32BIT): + { +#ifdef GL_OES_element_index_uint +#ifndef GL_UNSIGNED_INT +#define GL_UNSIGNED_INT 0x1405 +#endif + if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_element_index_uint]) + indexSize = GL_UNSIGNED_INT; + else +#endif + indexSize = GL_UNSIGNED_SHORT; + break; + } + } + + switch (pType) + { + case scene::EPT_POINTS: + case scene::EPT_POINT_SPRITES: + glDrawArrays(GL_POINTS, 0, primitiveCount); + break; + case scene::EPT_LINE_STRIP: + glDrawElements(GL_LINE_STRIP, primitiveCount + 1, indexSize, indexList); + break; + case scene::EPT_LINE_LOOP: + glDrawElements(GL_LINE_LOOP, primitiveCount, indexSize, indexList); + break; + case scene::EPT_LINES: + glDrawElements(GL_LINES, primitiveCount*2, indexSize, indexList); + break; + case scene::EPT_TRIANGLE_STRIP: + glDrawElements(GL_TRIANGLE_STRIP, primitiveCount + 2, indexSize, indexList); + break; + case scene::EPT_TRIANGLE_FAN: + glDrawElements(GL_TRIANGLE_FAN, primitiveCount + 2, indexSize, indexList); + break; + case scene::EPT_TRIANGLES: + glDrawElements((LastMaterial.Wireframe) ? GL_LINES : (LastMaterial.PointCloud) ? GL_POINTS : GL_TRIANGLES, primitiveCount*3, indexSize, indexList); + break; + default: + break; + } + + switch (vType) + { + case EVT_2TCOORDS: + glDisableVertexAttribArray(EVA_TCOORD1); + break; + case EVT_TANGENTS: + glDisableVertexAttribArray(EVA_TANGENT); + glDisableVertexAttribArray(EVA_BINORMAL); + break; + default: + break; + } + + glDisableVertexAttribArray(EVA_POSITION); + glDisableVertexAttribArray(EVA_NORMAL); + glDisableVertexAttribArray(EVA_COLOR); + glDisableVertexAttribArray(EVA_TCOORD0); + } + + + void COGLES2Driver::draw2DImage(const video::ITexture* texture, const core::position2d& destPos, + const core::rect& sourceRect, const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture) + { + if (!texture) + return; + + if (!sourceRect.isValid()) + return; + + IRR_PROFILE(CProfileScope p1(EPID_ES2_DRAW_2DIMAGE);) + + core::position2d targetPos(destPos); + core::position2d sourcePos(sourceRect.UpperLeftCorner); + core::dimension2d sourceSize(sourceRect.getSize()); + if (clipRect) + { + if (targetPos.X < clipRect->UpperLeftCorner.X) + { + sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X; + if (sourceSize.Width <= 0) + return; + + sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X; + targetPos.X = clipRect->UpperLeftCorner.X; + } + + if (targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X; + if (sourceSize.Width <= 0) + return; + } + + if (targetPos.Y < clipRect->UpperLeftCorner.Y) + { + sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y; + if (sourceSize.Height <= 0) + return; + + sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y; + targetPos.Y = clipRect->UpperLeftCorner.Y; + } + + if (targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y; + if (sourceSize.Height <= 0) + return; + } + } + + // clip these coordinates + + if (targetPos.X < 0) + { + sourceSize.Width += targetPos.X; + if (sourceSize.Width <= 0) + return; + + sourcePos.X -= targetPos.X; + targetPos.X = 0; + } + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width; + if (sourceSize.Width <= 0) + return; + } + + if (targetPos.Y < 0) + { + sourceSize.Height += targetPos.Y; + if (sourceSize.Height <= 0) + return; + + sourcePos.Y -= targetPos.Y; + targetPos.Y = 0; + } + + if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height; + if (sourceSize.Height <= 0) + return; + } + + // ok, we've clipped everything. + // now draw it. + + // texcoords need to be flipped horizontally for RTTs + const bool isRTT = texture->isRenderTarget(); + 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( + sourcePos.X * invW, + (isRTT ? (sourcePos.Y + sourceSize.Height) : sourcePos.Y) * invH, + (sourcePos.X + sourceSize.Width) * invW, + (isRTT ? sourcePos.Y : (sourcePos.Y + sourceSize.Height)) * invH); + + const core::rect poss(targetPos, sourceSize); + + chooseMaterial2D(); + if (!setMaterialTexture(0, texture )) + return; + + setRenderStates2DMode(color.getAlpha() < 255, true, useAlphaChannelOfTexture); + + f32 left = (f32)poss.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 right = (f32)poss.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 down = 2.f - (f32)poss.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + f32 top = 2.f - (f32)poss.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + + u16 indices[] = {0, 1, 2, 3}; + S3DVertex vertices[4]; + vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, color, tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, color, tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, color, tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, color, tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + + glEnableVertexAttribArray(EVA_POSITION); + glEnableVertexAttribArray(EVA_COLOR); + glEnableVertexAttribArray(EVA_TCOORD0); + glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast(vertices))[0].Pos); + glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex), &(static_cast(vertices))[0].Color); + glVertexAttribPointer(EVA_TCOORD0, 2, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); + glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, indices); + glDisableVertexAttribArray(EVA_TCOORD0); + glDisableVertexAttribArray(EVA_COLOR); + glDisableVertexAttribArray(EVA_POSITION); + } + + + void COGLES2Driver::draw2DImage(const video::ITexture* texture, const core::rect& destRect, + const core::rect& sourceRect, const core::rect* clipRect, + const video::SColor* const colors, bool useAlphaChannelOfTexture) + { + if (!texture) + return; + + IRR_PROFILE(CProfileScope p1(EPID_ES2_DRAW_2DIMAGE);) + + // texcoords need to be flipped horizontally for RTTs + const bool isRTT = texture->isRenderTarget(); + const core::dimension2du& 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( + sourceRect.UpperLeftCorner.X * invW, + (isRTT ? sourceRect.LowerRightCorner.Y : sourceRect.UpperLeftCorner.Y) * invH, + sourceRect.LowerRightCorner.X * invW, + (isRTT ? sourceRect.UpperLeftCorner.Y : sourceRect.LowerRightCorner.Y) *invH); + + const video::SColor temp[4] = + { + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF + }; + + const video::SColor* const useColor = colors ? colors : temp; + + chooseMaterial2D(); + if (!setMaterialTexture(0, texture )) + return; + + setRenderStates2DMode(useColor[0].getAlpha() < 255 || useColor[1].getAlpha() < 255 || + useColor[2].getAlpha() < 255 || useColor[3].getAlpha() < 255, + true, useAlphaChannelOfTexture); + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + if (clipRect) + { + if (!clipRect->isValid()) + return; + + glEnable(GL_SCISSOR_TEST); + glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height - clipRect->LowerRightCorner.Y, + clipRect->getWidth(), clipRect->getHeight()); + } + + f32 left = (f32)destRect.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 right = (f32)destRect.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 down = 2.f - (f32)destRect.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + f32 top = 2.f - (f32)destRect.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + + u16 indices[] = { 0, 1, 2, 3 }; + S3DVertex vertices[4]; + vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, useColor[0], tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, useColor[3], tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, useColor[2], tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, useColor[1], tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + + glEnableVertexAttribArray(EVA_POSITION); + glEnableVertexAttribArray(EVA_COLOR); + glEnableVertexAttribArray(EVA_TCOORD0); + glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast(vertices))[0].Pos); + glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex), &(static_cast(vertices))[0].Color); + glVertexAttribPointer(EVA_TCOORD0, 2, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); + glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, indices); + glDisableVertexAttribArray(EVA_TCOORD0); + glDisableVertexAttribArray(EVA_COLOR); + glDisableVertexAttribArray(EVA_POSITION); + + if (clipRect) + glDisable(GL_SCISSOR_TEST); + + testGLError(__LINE__); + } + + void COGLES2Driver::draw2DImage(const video::ITexture* texture, u32 layer, bool flip) + { + if (!texture) + return; + + chooseMaterial2D(); + if (!setMaterialTexture(0, texture )) + return; + + setRenderStates2DMode(false, true, true); + + u16 quad2DIndices[] = { 0, 1, 2, 3 }; + S3DVertex quad2DVertices[4]; + + quad2DVertices[0].Pos = core::vector3df(-1.f, 1.f, 0.f); + quad2DVertices[1].Pos = core::vector3df(1.f, 1.f, 0.f); + quad2DVertices[2].Pos = core::vector3df(1.f, -1.f, 0.f); + quad2DVertices[3].Pos = core::vector3df(-1.f, -1.f, 0.f); + + f32 modificator = (flip) ? 1.f : 0.f; + + quad2DVertices[0].TCoords = core::vector2df(0.f, 0.f + modificator); + quad2DVertices[1].TCoords = core::vector2df(1.f, 0.f + modificator); + quad2DVertices[2].TCoords = core::vector2df(1.f, 1.f - modificator); + quad2DVertices[3].TCoords = core::vector2df(0.f, 1.f - modificator); + + quad2DVertices[0].Color = SColor(0xFFFFFFFF); + quad2DVertices[1].Color = SColor(0xFFFFFFFF); + quad2DVertices[2].Color = SColor(0xFFFFFFFF); + quad2DVertices[3].Color = SColor(0xFFFFFFFF); + + glEnableVertexAttribArray(EVA_POSITION); + glEnableVertexAttribArray(EVA_COLOR); + glEnableVertexAttribArray(EVA_TCOORD0); + glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast(quad2DVertices))[0].Pos); + glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex), &(static_cast(quad2DVertices))[0].Color); + glVertexAttribPointer(EVA_TCOORD0, 2, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast(quad2DVertices))[0].TCoords); + glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, quad2DIndices); + glDisableVertexAttribArray(EVA_TCOORD0); + glDisableVertexAttribArray(EVA_COLOR); + glDisableVertexAttribArray(EVA_POSITION); + } + + + void COGLES2Driver::draw2DImageBatch(const video::ITexture* texture, + const core::array >& positions, + const core::array >& sourceRects, + const core::rect* clipRect, + SColor color, bool useAlphaChannelOfTexture) + { + if (!texture) + return; + + IRR_PROFILE(CProfileScope p1(EPID_ES2_DRAW_2DIMAGE_BATCH);) + + const irr::u32 drawCount = core::min_(positions.size(), sourceRects.size()); + + core::array vtx(drawCount * 4); + core::array indices(drawCount * 6); + + for (u32 i = 0; i < drawCount; i++) + { + core::position2d targetPos = positions[i]; + core::position2d sourcePos = sourceRects[i].UpperLeftCorner; + // This needs to be signed as it may go negative. + core::dimension2d sourceSize(sourceRects[i].getSize()); + + if (clipRect) + { + if (targetPos.X < clipRect->UpperLeftCorner.X) + { + sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X; + if (sourceSize.Width <= 0) + continue; + + sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X; + targetPos.X = clipRect->UpperLeftCorner.X; + } + + if (targetPos.X + (s32)sourceSize.Width > clipRect->LowerRightCorner.X) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X; + if (sourceSize.Width <= 0) + continue; + } + + if (targetPos.Y < clipRect->UpperLeftCorner.Y) + { + sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y; + if (sourceSize.Height <= 0) + continue; + + sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y; + targetPos.Y = clipRect->UpperLeftCorner.Y; + } + + if (targetPos.Y + (s32)sourceSize.Height > clipRect->LowerRightCorner.Y) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y; + if (sourceSize.Height <= 0) + continue; + } + } + + // clip these coordinates + + if (targetPos.X < 0) + { + sourceSize.Width += targetPos.X; + if (sourceSize.Width <= 0) + continue; + + sourcePos.X -= targetPos.X; + targetPos.X = 0; + } + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width; + if (sourceSize.Width <= 0) + continue; + } + + if (targetPos.Y < 0) + { + sourceSize.Height += targetPos.Y; + if (sourceSize.Height <= 0) + continue; + + sourcePos.Y -= targetPos.Y; + targetPos.Y = 0; + } + + if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height; + if (sourceSize.Height <= 0) + continue; + } + + // ok, we've clipped everything. + // now draw it. + + core::rect tcoords; + tcoords.UpperLeftCorner.X = (((f32)sourcePos.X)) / texture->getOriginalSize().Width ; + tcoords.UpperLeftCorner.Y = (((f32)sourcePos.Y)) / texture->getOriginalSize().Height; + tcoords.LowerRightCorner.X = tcoords.UpperLeftCorner.X + ((f32)(sourceSize.Width) / texture->getOriginalSize().Width); + tcoords.LowerRightCorner.Y = tcoords.UpperLeftCorner.Y + ((f32)(sourceSize.Height) / texture->getOriginalSize().Height); + + const core::rect poss(targetPos, sourceSize); + + chooseMaterial2D(); + if (!setMaterialTexture(0, texture)) + return; + + setRenderStates2DMode(color.getAlpha() < 255, true, useAlphaChannelOfTexture); + + f32 left = (f32)poss.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 right = (f32)poss.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 down = 2.f - (f32)poss.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + f32 top = 2.f - (f32)poss.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + + vtx.push_back(S3DVertex(left, top, 0.0f, + 0.0f, 0.0f, 0.0f, color, + tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y)); + vtx.push_back(S3DVertex(right, top, 0.0f, + 0.0f, 0.0f, 0.0f, color, + tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y)); + vtx.push_back(S3DVertex(right, down, 0.0f, + 0.0f, 0.0f, 0.0f, color, + tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y)); + vtx.push_back(S3DVertex(left, down, 0.0f, + 0.0f, 0.0f, 0.0f, color, + tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y)); + + const u32 curPos = vtx.size() - 4; + indices.push_back(0 + curPos); + indices.push_back(1 + curPos); + indices.push_back(2 + curPos); + + indices.push_back(0 + curPos); + indices.push_back(2 + curPos); + indices.push_back(3 + curPos); + } + + if (vtx.size()) + { + glEnableVertexAttribArray(EVA_POSITION); + glEnableVertexAttribArray(EVA_COLOR); + glEnableVertexAttribArray(EVA_TCOORD0); + glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex), &vtx[0].Pos); + glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex), &vtx[0].Color); + glVertexAttribPointer(EVA_TCOORD0, 2, GL_FLOAT, false, sizeof(S3DVertex), &vtx[0].TCoords); + glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, indices.pointer()); + glDisableVertexAttribArray(EVA_TCOORD0); + glDisableVertexAttribArray(EVA_COLOR); + glDisableVertexAttribArray(EVA_POSITION); + } + } + + + //! draws a set of 2d images, using a color and the alpha channel + void COGLES2Driver::draw2DImageBatch(const video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, s32 kerningWidth, + const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture) + { + if (!texture) + return; + + IRR_PROFILE(CProfileScope p1(EPID_ES2_DRAW_2DIMAGE_BATCH);) + + chooseMaterial2D(); + if (!setMaterialTexture(0, texture)) + return; + + setRenderStates2DMode(color.getAlpha() < 255, true, useAlphaChannelOfTexture); + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + if (clipRect) + { + if (!clipRect->isValid()) + return; + + glEnable(GL_SCISSOR_TEST); + glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height - clipRect->LowerRightCorner.Y, + clipRect->getWidth(), clipRect->getHeight()); + } + + const core::dimension2du& ss = texture->getOriginalSize(); + core::position2d targetPos(pos); + // texcoords need to be flipped horizontally for RTTs + const bool isRTT = texture->isRenderTarget(); + const f32 invW = 1.f / static_cast(ss.Width); + const f32 invH = 1.f / static_cast(ss.Height); + + core::array vertices; + core::array quadIndices; + vertices.reallocate(indices.size()*4); + quadIndices.reallocate(indices.size()*3); + + for (u32 i = 0; i < indices.size(); ++i) + { + const s32 currentIndex = indices[i]; + if (!sourceRects[currentIndex].isValid()) + break; + + const core::rect tcoords( + sourceRects[currentIndex].UpperLeftCorner.X * invW, + (isRTT ? sourceRects[currentIndex].LowerRightCorner.Y : sourceRects[currentIndex].UpperLeftCorner.Y) * invH, + sourceRects[currentIndex].LowerRightCorner.X * invW, + (isRTT ? sourceRects[currentIndex].UpperLeftCorner.Y : sourceRects[currentIndex].LowerRightCorner.Y) * invH); + + const core::rect poss(targetPos, sourceRects[currentIndex].getSize()); + + f32 left = (f32)poss.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 right = (f32)poss.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 down = 2.f - (f32)poss.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + f32 top = 2.f - (f32)poss.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + + const u32 vstart = vertices.size(); + vertices.push_back(S3DVertex(left, top, 0, 0, 0, 1, color, tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y)); + vertices.push_back(S3DVertex(right, top, 0, 0, 0, 1, color, tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y)); + vertices.push_back(S3DVertex(right, down, 0, 0, 0, 1, color, tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y)); + vertices.push_back(S3DVertex(left, down, 0, 0, 0, 1, color, tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y)); + quadIndices.push_back(vstart); + quadIndices.push_back(vstart+1); + quadIndices.push_back(vstart+2); + quadIndices.push_back(vstart); + quadIndices.push_back(vstart+2); + quadIndices.push_back(vstart+3); + + targetPos.X += sourceRects[currentIndex].getWidth(); + } + + if (vertices.size()) + { + glEnableVertexAttribArray(EVA_POSITION); + glEnableVertexAttribArray(EVA_COLOR); + glEnableVertexAttribArray(EVA_TCOORD0); + glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex), &vertices[0].Pos); + glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex), &vertices[0].Color); + glVertexAttribPointer(EVA_TCOORD0, 2, GL_FLOAT, false, sizeof(S3DVertex), &vertices[0].TCoords); + glDrawElements(GL_TRIANGLES, quadIndices.size(), GL_UNSIGNED_SHORT, quadIndices.pointer()); + glDisableVertexAttribArray(EVA_TCOORD0); + glDisableVertexAttribArray(EVA_COLOR); + glDisableVertexAttribArray(EVA_POSITION); + } + + if (clipRect) + glDisable(GL_SCISSOR_TEST); + + testGLError(__LINE__); + } + + + //! draw a 2d rectangle + void COGLES2Driver::draw2DRectangle(SColor color, + const core::rect& position, + const core::rect* clip) + { + IRR_PROFILE(CProfileScope p1(EPID_ES2_DRAW_2DRECTANGLE);) + + chooseMaterial2D(); + setMaterialTexture(0, 0); + + setRenderStates2DMode(color.getAlpha() < 255, false, false); + + core::rect pos = position; + + if (clip) + pos.clipAgainst(*clip); + + if (!pos.isValid()) + return; + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + f32 left = (f32)pos.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 right = (f32)pos.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 down = 2.f - (f32)pos.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + f32 top = 2.f - (f32)pos.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + + u16 indices[] = {0, 1, 2, 3}; + S3DVertex vertices[4]; + vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, color, 0, 0); + vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, color, 0, 0); + vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, color, 0, 0); + vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, color, 0, 0); + + glEnableVertexAttribArray(EVA_POSITION); + glEnableVertexAttribArray(EVA_COLOR); + glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast(vertices))[0].Pos); + glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex), &(static_cast(vertices))[0].Color); + glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, indices); + glDisableVertexAttribArray(EVA_COLOR); + glDisableVertexAttribArray(EVA_POSITION); + } + + + //! draw an 2d rectangle + void COGLES2Driver::draw2DRectangle(const core::rect& position, + SColor colorLeftUp, SColor colorRightUp, + SColor colorLeftDown, SColor colorRightDown, + const core::rect* clip) + { + IRR_PROFILE(CProfileScope p1(EPID_ES2_DRAW_2DRECTANGLE);) + + core::rect pos = position; + + if (clip) + pos.clipAgainst(*clip); + + if (!pos.isValid()) + return; + + chooseMaterial2D(); + setMaterialTexture(0, 0); + + setRenderStates2DMode(colorLeftUp.getAlpha() < 255 || + colorRightUp.getAlpha() < 255 || + colorLeftDown.getAlpha() < 255 || + colorRightDown.getAlpha() < 255, false, false); + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + f32 left = (f32)pos.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 right = (f32)pos.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 down = 2.f - (f32)pos.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + f32 top = 2.f - (f32)pos.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + + u16 indices[] = {0, 1, 2, 3}; + S3DVertex vertices[4]; + vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, colorLeftUp, 0, 0); + vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, colorRightUp, 0, 0); + vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, colorRightDown, 0, 0); + vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, colorLeftDown, 0, 0); + + glEnableVertexAttribArray(EVA_POSITION); + glEnableVertexAttribArray(EVA_COLOR); + glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast(vertices))[0].Pos); + glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex), &(static_cast(vertices))[0].Color); + glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, indices); + glDisableVertexAttribArray(EVA_COLOR); + glDisableVertexAttribArray(EVA_POSITION); + } + + + //! Draws a 2d line. + void COGLES2Driver::draw2DLine(const core::position2d& start, + const core::position2d& end, SColor color) + { + IRR_PROFILE(CProfileScope p1(EPID_ES2_DRAW_2DLINE);) + + if (start==end) + drawPixel(start.X, start.Y, color); + else + { + chooseMaterial2D(); + setMaterialTexture(0, 0); + + setRenderStates2DMode(color.getAlpha() < 255, false, false); + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + f32 startX = (f32)start.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 endX = (f32)end.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 startY = 2.f - (f32)start.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + f32 endY = 2.f - (f32)end.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + + u16 indices[] = {0, 1}; + S3DVertex vertices[2]; + vertices[0] = S3DVertex(startX, startY, 0, 0, 0, 1, color, 0, 0); + vertices[1] = S3DVertex(endX, endY, 0, 0, 0, 1, color, 1, 1); + + glEnableVertexAttribArray(EVA_POSITION); + glEnableVertexAttribArray(EVA_COLOR); + glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast(vertices))[0].Pos); + glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex), &(static_cast(vertices))[0].Color); + glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, indices); + glDisableVertexAttribArray(EVA_COLOR); + glDisableVertexAttribArray(EVA_POSITION); + } + } + + + //! Draws a pixel + void COGLES2Driver::drawPixel(u32 x, u32 y, const SColor &color) + { + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + if (x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height) + return; + + chooseMaterial2D(); + setMaterialTexture(0, 0); + + setRenderStates2DMode(color.getAlpha() < 255, false, false); + + f32 X = (f32)x / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 Y = 2.f - (f32)y / (f32)renderTargetSize.Height * 2.f - 1.f; + + S3DVertex vertices[1]; + vertices[0] = S3DVertex(X, Y, 0, 0, 0, 1, color, 0, 0); + + glEnableVertexAttribArray(EVA_POSITION); + glEnableVertexAttribArray(EVA_COLOR); + glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast(vertices))[0].Pos); + glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex), &(static_cast(vertices))[0].Color); + glDrawArrays(GL_POINTS, 0, 1); + glDisableVertexAttribArray(EVA_COLOR); + glDisableVertexAttribArray(EVA_POSITION); + } + + ITexture* COGLES2Driver::createDeviceDependentTexture(const io::path& name, IImage* image) + { + core::array imageArray(1); + imageArray.push_back(image); + + COGLES2Texture* texture = new COGLES2Texture(name, imageArray, ETT_2D, this); + + return texture; + } + + ITexture* COGLES2Driver::createDeviceDependentTextureCubemap(const io::path& name, const core::array& image) + { + COGLES2Texture* texture = new COGLES2Texture(name, image, ETT_CUBEMAP, this); + + return texture; + } + + //! Sets a material. + void COGLES2Driver::setMaterial(const SMaterial& material) + { + Material = material; + OverrideMaterial.apply(Material); + + for (u32 i = 0; i < Feature.MaxTextureUnits; ++i) + { + CacheHandler->getTextureCache().set(i, material.getTexture(i)); + setTransform((E_TRANSFORMATION_STATE)(ETS_TEXTURE_0 + i), material.getTextureMatrix(i)); + } + } + + //! prints error if an error happened. + bool COGLES2Driver::testGLError(int code) + { +#ifdef _DEBUG + GLenum g = glGetError(); + switch (g) + { + case GL_NO_ERROR: + return false; + case GL_INVALID_ENUM: + os::Printer::log("GL_INVALID_ENUM", core::stringc(code).c_str(), ELL_ERROR); + break; + case GL_INVALID_VALUE: + os::Printer::log("GL_INVALID_VALUE", core::stringc(code).c_str(), ELL_ERROR); + break; + case GL_INVALID_OPERATION: + os::Printer::log("GL_INVALID_OPERATION", core::stringc(code).c_str(), ELL_ERROR); + break; + case GL_OUT_OF_MEMORY: + os::Printer::log("GL_OUT_OF_MEMORY", core::stringc(code).c_str(), ELL_ERROR); + break; + }; + return true; +#else + return false; +#endif + } + + //! prints error if an error happened. + bool COGLES2Driver::testEGLError() + { +#if defined(EGL_VERSION_1_0) && defined(_DEBUG) + EGLint g = eglGetError(); + switch (g) + { + case EGL_SUCCESS: + return false; + case EGL_NOT_INITIALIZED : + os::Printer::log("Not Initialized", ELL_ERROR); + break; + case EGL_BAD_ACCESS: + os::Printer::log("Bad Access", ELL_ERROR); + break; + case EGL_BAD_ALLOC: + os::Printer::log("Bad Alloc", ELL_ERROR); + break; + case EGL_BAD_ATTRIBUTE: + os::Printer::log("Bad Attribute", ELL_ERROR); + break; + case EGL_BAD_CONTEXT: + os::Printer::log("Bad Context", ELL_ERROR); + break; + case EGL_BAD_CONFIG: + os::Printer::log("Bad Config", ELL_ERROR); + break; + case EGL_BAD_CURRENT_SURFACE: + os::Printer::log("Bad Current Surface", ELL_ERROR); + break; + case EGL_BAD_DISPLAY: + os::Printer::log("Bad Display", ELL_ERROR); + break; + case EGL_BAD_SURFACE: + os::Printer::log("Bad Surface", ELL_ERROR); + break; + case EGL_BAD_MATCH: + os::Printer::log("Bad Match", ELL_ERROR); + break; + case EGL_BAD_PARAMETER: + os::Printer::log("Bad Parameter", ELL_ERROR); + break; + case EGL_BAD_NATIVE_PIXMAP: + os::Printer::log("Bad Native Pixmap", ELL_ERROR); + break; + case EGL_BAD_NATIVE_WINDOW: + os::Printer::log("Bad Native Window", ELL_ERROR); + break; + case EGL_CONTEXT_LOST: + os::Printer::log("Context Lost", ELL_ERROR); + break; + }; + return true; +#else + return false; +#endif + } + + + void COGLES2Driver::setRenderStates3DMode() + { + IRR_PROFILE(CProfileScope p1(EPID_ES2_SET_RENDERSTATE_3D);) + + if ( LockRenderStateMode ) + return; + + if (CurrentRenderMode != ERM_3D) + { + // Reset Texture Stages + CacheHandler->setBlend(false); + CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + ResetRenderStates = true; + } + + if (ResetRenderStates || LastMaterial != Material) + { + // unset old material + + // unset last 3d material + if (CurrentRenderMode == ERM_2D && MaterialRenderer2DActive) + { + MaterialRenderer2DActive->OnUnsetMaterial(); + MaterialRenderer2DActive = 0; + } + else if (LastMaterial.MaterialType != Material.MaterialType && + static_cast(LastMaterial.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); + + // set new material. + if (static_cast(Material.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[Material.MaterialType].Renderer->OnSetMaterial( + Material, LastMaterial, ResetRenderStates, this); + + LastMaterial = Material; + CacheHandler->correctCacheMaterial(LastMaterial); + ResetRenderStates = false; + } + + if (static_cast(Material.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[Material.MaterialType].Renderer->OnRender(this, video::EVT_STANDARD); + + CurrentRenderMode = ERM_3D; + } + + //! Can be called by an IMaterialRenderer to make its work easier. + void COGLES2Driver::setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial, bool resetAllRenderStates) + { + IRR_PROFILE(CProfileScope p1(EPID_ES2_SET_RENDERSTATE_BASIC);) + + // ZBuffer + switch (material.ZBuffer) + { + case ECFN_DISABLED: + CacheHandler->setDepthTest(false); + break; + case ECFN_LESSEQUAL: + CacheHandler->setDepthTest(true); + CacheHandler->setDepthFunc(GL_LEQUAL); + break; + case ECFN_EQUAL: + CacheHandler->setDepthTest(true); + CacheHandler->setDepthFunc(GL_EQUAL); + break; + case ECFN_LESS: + CacheHandler->setDepthTest(true); + CacheHandler->setDepthFunc(GL_LESS); + break; + case ECFN_NOTEQUAL: + CacheHandler->setDepthTest(true); + CacheHandler->setDepthFunc(GL_NOTEQUAL); + break; + case ECFN_GREATEREQUAL: + CacheHandler->setDepthTest(true); + CacheHandler->setDepthFunc(GL_GEQUAL); + break; + case ECFN_GREATER: + CacheHandler->setDepthTest(true); + CacheHandler->setDepthFunc(GL_GREATER); + break; + case ECFN_ALWAYS: + CacheHandler->setDepthTest(true); + CacheHandler->setDepthFunc(GL_ALWAYS); + break; + case ECFN_NEVER: + CacheHandler->setDepthTest(true); + CacheHandler->setDepthFunc(GL_NEVER); + break; + default: + break; + } + + // ZWrite + if (getWriteZBuffer(material)) + { + CacheHandler->setDepthMask(true); + } + else + { + CacheHandler->setDepthMask(false); + } + + // Back face culling + if ((material.FrontfaceCulling) && (material.BackfaceCulling)) + { + CacheHandler->setCullFaceFunc(GL_FRONT_AND_BACK); + CacheHandler->setCullFace(true); + } + else if (material.BackfaceCulling) + { + CacheHandler->setCullFaceFunc(GL_BACK); + CacheHandler->setCullFace(true); + } + else if (material.FrontfaceCulling) + { + CacheHandler->setCullFaceFunc(GL_FRONT); + CacheHandler->setCullFace(true); + } + else + { + CacheHandler->setCullFace(false); + } + + // Color Mask + CacheHandler->setColorMask(material.ColorMask); + + // Blend Equation + if (material.BlendOperation == EBO_NONE) + CacheHandler->setBlend(false); + else + { + CacheHandler->setBlend(true); + + switch (material.BlendOperation) + { + case EBO_ADD: + CacheHandler->setBlendEquation(GL_FUNC_ADD); + break; + case EBO_SUBTRACT: + CacheHandler->setBlendEquation(GL_FUNC_SUBTRACT); + break; + case EBO_REVSUBTRACT: + CacheHandler->setBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + break; + default: + break; + } + } + + // Blend Factor + if (IR(material.BlendFactor) & 0xFFFFFFFF // TODO: why the & 0xFFFFFFFF? + && material.MaterialType != EMT_ONETEXTURE_BLEND + ) + { + E_BLEND_FACTOR srcRGBFact = EBF_ZERO; + E_BLEND_FACTOR dstRGBFact = EBF_ZERO; + E_BLEND_FACTOR srcAlphaFact = EBF_ZERO; + E_BLEND_FACTOR dstAlphaFact = EBF_ZERO; + E_MODULATE_FUNC modulo = EMFN_MODULATE_1X; + u32 alphaSource = 0; + + unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulo, alphaSource, material.BlendFactor); + + CacheHandler->setBlendFuncSeparate(getGLBlend(srcRGBFact), getGLBlend(dstRGBFact), + getGLBlend(srcAlphaFact), getGLBlend(dstAlphaFact)); + } + + // TODO: Polygon Offset. Not sure if it was left out deliberately or if it won't work with this driver. + + if (resetAllRenderStates || lastmaterial.Thickness != material.Thickness) + glLineWidth(core::clamp(static_cast(material.Thickness), DimAliasedLine[0], DimAliasedLine[1])); + + // Anti aliasing + if (resetAllRenderStates || lastmaterial.AntiAliasing != material.AntiAliasing) + { + if (material.AntiAliasing & EAAM_ALPHA_TO_COVERAGE) + glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); + else if (lastmaterial.AntiAliasing & EAAM_ALPHA_TO_COVERAGE) + glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); + } + + // Texture parameters + setTextureRenderStates(material, resetAllRenderStates); + } + + //! Compare in SMaterial doesn't check texture parameters, so we should call this on each OnRender call. + void COGLES2Driver::setTextureRenderStates(const SMaterial& material, bool resetAllRenderstates) + { + IRR_PROFILE(CProfileScope p1(EPID_ES2_SET_RENDERSTATE_TEXTURE);) + + // Set textures to TU/TIU and apply filters to them + + for (s32 i = Feature.MaxTextureUnits - 1; i >= 0; --i) + { + const COGLES2Texture* tmpTexture = CacheHandler->getTextureCache()[i]; + + if (!tmpTexture) + continue; + + GLenum tmpTextureType = tmpTexture->getOpenGLTextureType(); + + CacheHandler->setActiveTexture(GL_TEXTURE0 + i); + + if (resetAllRenderstates) + tmpTexture->getStatesCache().IsCached = false; + + if (!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].BilinearFilter != tmpTexture->getStatesCache().BilinearFilter || + material.TextureLayer[i].TrilinearFilter != tmpTexture->getStatesCache().TrilinearFilter) + { + glTexParameteri(tmpTextureType, GL_TEXTURE_MAG_FILTER, + (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST); + + tmpTexture->getStatesCache().BilinearFilter = material.TextureLayer[i].BilinearFilter; + tmpTexture->getStatesCache().TrilinearFilter = material.TextureLayer[i].TrilinearFilter; + } + + if (material.UseMipMaps && tmpTexture->hasMipMaps()) + { + if (!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].BilinearFilter != tmpTexture->getStatesCache().BilinearFilter || + material.TextureLayer[i].TrilinearFilter != tmpTexture->getStatesCache().TrilinearFilter || !tmpTexture->getStatesCache().MipMapStatus) + { + glTexParameteri(tmpTextureType, GL_TEXTURE_MIN_FILTER, + material.TextureLayer[i].TrilinearFilter ? GL_LINEAR_MIPMAP_LINEAR : + material.TextureLayer[i].BilinearFilter ? GL_LINEAR_MIPMAP_NEAREST : + GL_NEAREST_MIPMAP_NEAREST); + + tmpTexture->getStatesCache().BilinearFilter = material.TextureLayer[i].BilinearFilter; + tmpTexture->getStatesCache().TrilinearFilter = material.TextureLayer[i].TrilinearFilter; + tmpTexture->getStatesCache().MipMapStatus = true; + } + } + else + { + if (!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].BilinearFilter != tmpTexture->getStatesCache().BilinearFilter || + material.TextureLayer[i].TrilinearFilter != tmpTexture->getStatesCache().TrilinearFilter || tmpTexture->getStatesCache().MipMapStatus) + { + glTexParameteri(tmpTextureType, GL_TEXTURE_MIN_FILTER, + (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST); + + tmpTexture->getStatesCache().BilinearFilter = material.TextureLayer[i].BilinearFilter; + tmpTexture->getStatesCache().TrilinearFilter = material.TextureLayer[i].TrilinearFilter; + tmpTexture->getStatesCache().MipMapStatus = false; + } + } + + #ifdef GL_EXT_texture_filter_anisotropic + if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_EXT_texture_filter_anisotropic] && + (!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].AnisotropicFilter != tmpTexture->getStatesCache().AnisotropicFilter)) + { + glTexParameteri(tmpTextureType, GL_TEXTURE_MAX_ANISOTROPY_EXT, + material.TextureLayer[i].AnisotropicFilter>1 ? core::min_(MaxAnisotropy, material.TextureLayer[i].AnisotropicFilter) : 1); + + tmpTexture->getStatesCache().AnisotropicFilter = material.TextureLayer[i].AnisotropicFilter; + } + #endif + + if (!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].TextureWrapU != tmpTexture->getStatesCache().WrapU) + { + glTexParameteri(tmpTextureType, GL_TEXTURE_WRAP_S, getTextureWrapMode(material.TextureLayer[i].TextureWrapU)); + tmpTexture->getStatesCache().WrapU = material.TextureLayer[i].TextureWrapU; + } + + if (!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].TextureWrapV != tmpTexture->getStatesCache().WrapV) + { + glTexParameteri(tmpTextureType, GL_TEXTURE_WRAP_T, getTextureWrapMode(material.TextureLayer[i].TextureWrapV)); + tmpTexture->getStatesCache().WrapV = material.TextureLayer[i].TextureWrapV; + } + + tmpTexture->getStatesCache().IsCached = true; + } + } + + + // Get OpenGL ES2.0 texture wrap mode from Irrlicht wrap mode. + GLint COGLES2Driver::getTextureWrapMode(u8 clamp) const + { + switch (clamp) + { + case ETC_CLAMP: + case ETC_CLAMP_TO_EDGE: + case ETC_CLAMP_TO_BORDER: + return GL_CLAMP_TO_EDGE; + case ETC_MIRROR: + return GL_REPEAT; + default: + return GL_REPEAT; + } + } + + + //! sets the needed renderstates + void COGLES2Driver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel) + { + IRR_PROFILE(CProfileScope p1(EPID_ES2_SET_RENDERSTATE_2D);) + + if ( LockRenderStateMode ) + return; + + COGLES2Renderer2D* nextActiveRenderer = texture ? MaterialRenderer2DTexture : MaterialRenderer2DNoTexture; + + if (CurrentRenderMode != ERM_2D) + { + // unset last 3d material + if (CurrentRenderMode == ERM_3D) + { + if (static_cast(LastMaterial.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); + } + + CurrentRenderMode = ERM_2D; + } + else if ( MaterialRenderer2DActive && MaterialRenderer2DActive != nextActiveRenderer) + { + MaterialRenderer2DActive->OnUnsetMaterial(); + } + + MaterialRenderer2DActive = nextActiveRenderer; + + MaterialRenderer2DActive->OnSetMaterial(Material, LastMaterial, true, 0); + LastMaterial = Material; + CacheHandler->correctCacheMaterial(LastMaterial); + + // no alphaChannel without texture + alphaChannel &= texture; + + if (alphaChannel || alpha) + { + CacheHandler->setBlend(true); + CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + else + CacheHandler->setBlend(false); + + Material.setTexture(0, const_cast(CacheHandler->getTextureCache().get(0))); + setTransform(ETS_TEXTURE_0, core::IdentityMatrix); + + if (texture) + { + if (OverrideMaterial2DEnabled) + setTextureRenderStates(OverrideMaterial2D, false); + else + setTextureRenderStates(InitMaterial2D, false); + } + + MaterialRenderer2DActive->OnRender(this, video::EVT_STANDARD); + } + + + void COGLES2Driver::chooseMaterial2D() + { + if (!OverrideMaterial2DEnabled) + Material = InitMaterial2D; + + if (OverrideMaterial2DEnabled) + { + OverrideMaterial2D.Lighting=false; + OverrideMaterial2D.ZWriteEnable=EZW_OFF; + OverrideMaterial2D.ZBuffer=ECFN_DISABLED; // it will be ECFN_DISABLED after merge + OverrideMaterial2D.Lighting=false; + + Material = OverrideMaterial2D; + } + } + + + //! \return Returns the name of the video driver. + const wchar_t* COGLES2Driver::getName() const + { + return Name.c_str(); + } + + + //! deletes all dynamic lights there are + void COGLES2Driver::deleteAllDynamicLights() + { + RequestedLights.clear(); + CNullDriver::deleteAllDynamicLights(); + } + + + //! adds a dynamic light + s32 COGLES2Driver::addDynamicLight(const SLight& light) + { + CNullDriver::addDynamicLight(light); + + RequestedLights.push_back(RequestedLight(light)); + + u32 newLightIndex = RequestedLights.size() - 1; + + return (s32)newLightIndex; + } + + //! 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 COGLES2Driver::turnLightOn(s32 lightIndex, bool turnOn) + { + if (lightIndex < 0 || lightIndex >= (s32)RequestedLights.size()) + return; + + RequestedLight & requestedLight = RequestedLights[lightIndex]; + requestedLight.DesireToBeOn = turnOn; + } + + + //! returns the maximal amount of dynamic lights the device can handle + u32 COGLES2Driver::getMaximalDynamicLightAmount() const + { + return 8; + } + + void COGLES2Driver::setViewPort(const core::rect& area) + { + core::rect vp = area; + core::rect rendert(0, 0, getCurrentRenderTargetSize().Width, getCurrentRenderTargetSize().Height); + vp.clipAgainst(rendert); + + if (vp.getHeight() > 0 && vp.getWidth() > 0) + CacheHandler->setViewport(vp.UpperLeftCorner.X, getCurrentRenderTargetSize().Height - vp.UpperLeftCorner.Y - vp.getHeight(), vp.getWidth(), vp.getHeight()); + + ViewPort = vp; + } + + + //! Draws a shadow volume into the stencil buffer. + void COGLES2Driver::drawStencilShadowVolume(const core::array& triangles, bool zfail, u32 debugDataVisible) + { + IRR_PROFILE(CProfileScope p1(EPID_ES2_DRAW_SHADOW);) + + const u32 count=triangles.size(); + if (!StencilBuffer || !count) + return; + + bool fog = Material.FogEnable; + bool lighting = Material.Lighting; + E_MATERIAL_TYPE materialType = Material.MaterialType; + + Material.FogEnable = false; + Material.Lighting = false; + Material.MaterialType = EMT_SOLID; // Dedicated material in future. + + setRenderStates3DMode(); + + CacheHandler->setDepthTest(true); + CacheHandler->setDepthFunc(GL_LESS); + CacheHandler->setDepthMask(false); + + if (!(debugDataVisible & (scene::EDS_SKELETON|scene::EDS_MESH_WIRE_OVERLAY))) + { + CacheHandler->setColorMask(ECP_NONE); + glEnable(GL_STENCIL_TEST); + } + + glEnableVertexAttribArray(EVA_POSITION); + glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(core::vector3df), triangles.const_pointer()); + + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + + GLenum decr = GL_DECR; + GLenum incr = GL_INCR; + +#if defined(GL_OES_stencil_wrap) + if (FeatureAvailable[IRR_OES_stencil_wrap]) + { + decr = GL_DECR_WRAP_OES; + incr = GL_INCR_WRAP_OES; + } +#endif + + CacheHandler->setCullFace(true); + + if (zfail) + { + CacheHandler->setCullFaceFunc(GL_FRONT); + glStencilOp(GL_KEEP, incr, GL_KEEP); + glDrawArrays(GL_TRIANGLES, 0, count); + + CacheHandler->setCullFaceFunc(GL_BACK); + glStencilOp(GL_KEEP, decr, GL_KEEP); + glDrawArrays(GL_TRIANGLES, 0, count); + } + else // zpass + { + CacheHandler->setCullFaceFunc(GL_BACK); + glStencilOp(GL_KEEP, GL_KEEP, incr); + glDrawArrays(GL_TRIANGLES, 0, count); + + CacheHandler->setCullFaceFunc(GL_FRONT); + glStencilOp(GL_KEEP, GL_KEEP, decr); + glDrawArrays(GL_TRIANGLES, 0, count); + } + + glDisableVertexAttribArray(EVA_POSITION); + + glDisable(GL_STENCIL_TEST); + + Material.FogEnable = fog; + Material.Lighting = lighting; + Material.MaterialType = materialType; + } + + + void COGLES2Driver::drawStencilShadow(bool clearStencilBuffer, + video::SColor leftUpEdge, video::SColor rightUpEdge, + video::SColor leftDownEdge, video::SColor rightDownEdge) + { + IRR_PROFILE(CProfileScope p1(EPID_ES2_DRAW_SHADOW);) + + if (!StencilBuffer) + return; + + chooseMaterial2D(); + setMaterialTexture(0, 0); + + setRenderStates2DMode(true, false, false); + + CacheHandler->setDepthMask(false); + CacheHandler->setColorMask(ECP_ALL); + + CacheHandler->setBlend(true); + CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_STENCIL_TEST); + glStencilFunc(GL_NOTEQUAL, 0, ~0); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + + u16 indices[] = {0, 1, 2, 3}; + S3DVertex vertices[4]; + vertices[0] = S3DVertex(-1.f, 1.f, 0.9f, 0, 0, 1, leftDownEdge, 0, 0); + vertices[1] = S3DVertex(1.f, 1.f, 0.9f, 0, 0, 1, leftUpEdge, 0, 0); + vertices[2] = S3DVertex(1.f, -1.f, 0.9f, 0, 0, 1, rightUpEdge, 0, 0); + vertices[3] = S3DVertex(-1.f, -1.f, 0.9f, 0, 0, 1, rightDownEdge, 0, 0); + + glEnableVertexAttribArray(EVA_POSITION); + glEnableVertexAttribArray(EVA_COLOR); + glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast(vertices))[0].Pos); + glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex), &(static_cast(vertices))[0].Color); + glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, indices); + glDisableVertexAttribArray(EVA_COLOR); + glDisableVertexAttribArray(EVA_POSITION); + + if (clearStencilBuffer) + glClear(GL_STENCIL_BUFFER_BIT); + + glDisable(GL_STENCIL_TEST); + } + + + //! Draws a 3d line. + void COGLES2Driver::draw3DLine(const core::vector3df& start, + const core::vector3df& end, SColor color) + { + IRR_PROFILE(CProfileScope p1(EPID_ES2_DRAW_3DLINE);) + + setRenderStates3DMode(); + + u16 indices[] = {0, 1}; + S3DVertex vertices[2]; + vertices[0] = S3DVertex(start.X, start.Y, start.Z, 0, 0, 1, color, 0, 0); + vertices[1] = S3DVertex(end.X, end.Y, end.Z, 0, 0, 1, color, 0, 0); + + glEnableVertexAttribArray(EVA_POSITION); + glEnableVertexAttribArray(EVA_COLOR); + glVertexAttribPointer(EVA_POSITION, 3, GL_FLOAT, false, sizeof(S3DVertex), &(static_cast(vertices))[0].Pos); + glVertexAttribPointer(EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(S3DVertex), &(static_cast(vertices))[0].Color); + glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, indices); + glDisableVertexAttribArray(EVA_COLOR); + glDisableVertexAttribArray(EVA_POSITION); + } + + + //! Only used by the internal engine. Used to notify the driver that + //! the window was resized. + void COGLES2Driver::OnResize(const core::dimension2d& size) + { + CNullDriver::OnResize(size); + CacheHandler->setViewport(0, 0, size.Width, size.Height); + Transformation3DChanged = true; + } + + + //! Returns type of video driver + E_DRIVER_TYPE COGLES2Driver::getDriverType() const + { + return EDT_OGLES2; + } + + + //! returns color format + ECOLOR_FORMAT COGLES2Driver::getColorFormat() const + { + return ColorFormat; + } + + + //! Get a vertex shader constant index. + s32 COGLES2Driver::getVertexShaderConstantID(const c8* name) + { + return getPixelShaderConstantID(name); + } + + //! Get a pixel shader constant index. + s32 COGLES2Driver::getPixelShaderConstantID(const c8* name) + { + os::Printer::log("Error: Please call services->getPixelShaderConstantID(), not VideoDriver->getPixelShaderConstantID()."); + return -1; + } + + //! Sets a vertex shader constant. + void COGLES2Driver::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount) + { + os::Printer::log("Error: Please call services->setVertexShaderConstant(), not VideoDriver->setPixelShaderConstant()."); + } + + //! Sets a pixel shader constant. + void COGLES2Driver::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount) + { + os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant()."); + } + + //! Sets a constant for the vertex shader based on an index. + bool COGLES2Driver::setVertexShaderConstant(s32 index, const f32* floats, int count) + { + //pass this along, as in GLSL the same routine is used for both vertex and fragment shaders + return setPixelShaderConstant(index, floats, count); + } + + //! Int interface for the above. + bool COGLES2Driver::setVertexShaderConstant(s32 index, const s32* ints, int count) + { + return setPixelShaderConstant(index, ints, count); + } + + //! Sets a constant for the pixel shader based on an index. + bool COGLES2Driver::setPixelShaderConstant(s32 index, const f32* floats, int count) + { + os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant()."); + return false; + } + + //! Int interface for the above. + bool COGLES2Driver::setPixelShaderConstant(s32 index, const s32* ints, int count) + { + os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant()."); + return false; + } + + + //! Adds a new material renderer to the VideoDriver, using pixel and/or + //! vertex shaders to render geometry. + s32 COGLES2Driver::addShaderMaterial(const c8* vertexShaderProgram, + const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, s32 userData) + { + os::Printer::log("No shader support."); + return -1; + } + + + //! Adds a new material renderer to the VideoDriver, using GLSL to render geometry. + s32 COGLES2Driver::addHighLevelShaderMaterial( + const c8* vertexShaderProgram, + const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, + const c8* pixelShaderProgram, + const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, + const c8* geometryShaderProgram, + const c8* geometryShaderEntryPointName, + E_GEOMETRY_SHADER_TYPE gsCompileTarget, + scene::E_PRIMITIVE_TYPE inType, + scene::E_PRIMITIVE_TYPE outType, + u32 verticesOut, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, + s32 userData) + { + s32 nr = -1; + COGLES2MaterialRenderer* r = new COGLES2MaterialRenderer( + this, nr, vertexShaderProgram, + pixelShaderProgram, + callback, baseMaterial, userData); + + r->drop(); + return nr; + } + + //! Returns a pointer to the IVideoDriver interface. (Implementation for + //! IMaterialRendererServices) + IVideoDriver* COGLES2Driver::getVideoDriver() + { + return this; + } + + + //! Returns pointer to the IGPUProgrammingServices interface. + IGPUProgrammingServices* COGLES2Driver::getGPUProgrammingServices() + { + return this; + } + + ITexture* COGLES2Driver::addRenderTargetTexture(const core::dimension2d& size, + const io::path& name, const ECOLOR_FORMAT format) + { + //disable mip-mapping + bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS); + setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false); + + COGLES2Texture* renderTargetTexture = new COGLES2Texture(name, size, ETT_2D, format, this); + addTexture(renderTargetTexture); + renderTargetTexture->drop(); + + //restore mip-mapping + setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels); + + return renderTargetTexture; + } + + ITexture* COGLES2Driver::addRenderTargetTextureCubemap(const irr::u32 sideLen, const io::path& name, const ECOLOR_FORMAT format) + { + //disable mip-mapping + bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS); + setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false); + + bool supportForFBO = (Feature.ColorAttachment > 0); + + const core::dimension2d size(sideLen, sideLen); + core::dimension2du destSize(size); + + if (!supportForFBO) + { + destSize = core::dimension2d(core::min_(size.Width, ScreenSize.Width), core::min_(size.Height, ScreenSize.Height)); + destSize = destSize.getOptimalSize((size == size.getOptimalSize()), false, false); + } + + COGLES2Texture* renderTargetTexture = new COGLES2Texture(name, destSize, ETT_CUBEMAP, format, this); + addTexture(renderTargetTexture); + renderTargetTexture->drop(); + + //restore mip-mapping + setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels); + + return renderTargetTexture; + } + + + //! Returns the maximum amount of primitives + u32 COGLES2Driver::getMaximalPrimitiveCount() const + { + return 65535; + } + + bool COGLES2Driver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil) + { + if (target && target->getDriverType() != EDT_OGLES2 && target->getDriverType() != EDT_WEBGL1) + { + os::Printer::log("Fatal Error: Tried to set a render target not owned by OGLES2 driver.", ELL_ERROR); + return false; + } + + core::dimension2d destRenderTargetSize(0, 0); + + if (target) + { + COGLES2RenderTarget* renderTarget = static_cast(target); + + CacheHandler->setFBO(renderTarget->getBufferID()); + renderTarget->update(); + + destRenderTargetSize = renderTarget->getSize(); + + CacheHandler->setViewport(0, 0, destRenderTargetSize.Width, destRenderTargetSize.Height); + } + else + { + CacheHandler->setFBO(0); + + destRenderTargetSize = core::dimension2d(0, 0); + + CacheHandler->setViewport(0, 0, ScreenSize.Width, ScreenSize.Height); + } + + if (CurrentRenderTargetSize != destRenderTargetSize) + { + CurrentRenderTargetSize = destRenderTargetSize; + + Transformation3DChanged = true; + } + + CurrentRenderTarget = target; + + clearBuffers(clearFlag, clearColor, clearDepth, clearStencil); + + return true; + } + + void COGLES2Driver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil) + { + GLbitfield mask = 0; + u8 colorMask = 0; + bool depthMask = false; + + CacheHandler->getColorMask(colorMask); + CacheHandler->getDepthMask(depthMask); + + if (flag & ECBF_COLOR) + { + CacheHandler->setColorMask(ECP_ALL); + + 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 (flag & ECBF_DEPTH) + { + CacheHandler->setDepthMask(true); + glClearDepthf(depth); + mask |= GL_DEPTH_BUFFER_BIT; + } + + if (flag & ECBF_STENCIL) + { + glClearStencil(stencil); + mask |= GL_STENCIL_BUFFER_BIT; + } + + if (mask) + glClear(mask); + + CacheHandler->setColorMask(colorMask); + CacheHandler->setDepthMask(depthMask); + } + + + //! Returns an image created from the last rendered frame. + // We want to read the front buffer to get the latest render finished. + // This is not possible under ogl-es, though, so one has to call this method + // outside of the render loop only. + IImage* COGLES2Driver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target) + { + if (target==video::ERT_MULTI_RENDER_TEXTURES || target==video::ERT_RENDER_TEXTURE || target==video::ERT_STEREO_BOTH_BUFFERS) + return 0; + + GLint internalformat = GL_RGBA; + GLint type = GL_UNSIGNED_BYTE; + { +// glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &internalformat); +// glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &type); + // there's a format we don't support ATM + if (GL_UNSIGNED_SHORT_4_4_4_4 == type) + { + internalformat = GL_RGBA; + type = GL_UNSIGNED_BYTE; + } + } + + IImage* newImage = 0; + if (GL_RGBA == internalformat) + { + if (GL_UNSIGNED_BYTE == type) + newImage = new CImage(ECF_A8R8G8B8, ScreenSize); + else + newImage = new CImage(ECF_A1R5G5B5, ScreenSize); + } + else + { + if (GL_UNSIGNED_BYTE == type) + newImage = new CImage(ECF_R8G8B8, ScreenSize); + else + newImage = new CImage(ECF_R5G6B5, ScreenSize); + } + + if (!newImage) + return 0; + + u8* pixels = static_cast(newImage->getData()); + if (!pixels) + { + newImage->drop(); + return 0; + } + + glReadPixels(0, 0, ScreenSize.Width, ScreenSize.Height, internalformat, type, pixels); + testGLError(__LINE__); + + // opengl images are horizontally flipped, so we have to fix that here. + const s32 pitch = newImage->getPitch(); + u8* p2 = pixels + (ScreenSize.Height - 1) * pitch; + u8* tmpBuffer = new u8[pitch]; + for (u32 i = 0; i < ScreenSize.Height; i += 2) + { + memcpy(tmpBuffer, pixels, pitch); + memcpy(pixels, p2, pitch); + memcpy(p2, tmpBuffer, pitch); + pixels += pitch; + p2 -= pitch; + } + delete [] tmpBuffer; + + if (testGLError(__LINE__)) + { + newImage->drop(); + return 0; + } + testGLError(__LINE__); + return newImage; + } + + void COGLES2Driver::removeTexture(ITexture* texture) + { + CacheHandler->getTextureCache().remove(texture); + CNullDriver::removeTexture(texture); + } + + //! Set/unset a clipping plane. + bool COGLES2Driver::setClipPlane(u32 index, const core::plane3df& plane, bool enable) + { + if (index >= UserClipPlane.size()) + UserClipPlane.push_back(SUserClipPlane()); + + UserClipPlane[index].Plane = plane; + UserClipPlane[index].Enabled = enable; + return true; + } + + //! Enable/disable a clipping plane. + void COGLES2Driver::enableClipPlane(u32 index, bool enable) + { + UserClipPlane[index].Enabled = enable; + } + + //! Get the ClipPlane Count + u32 COGLES2Driver::getClipPlaneCount() const + { + return UserClipPlane.size(); + } + + const core::plane3df& COGLES2Driver::getClipPlane(irr::u32 index) const + { + if (index < UserClipPlane.size()) + return UserClipPlane[index].Plane; + else + { + _IRR_DEBUG_BREAK_IF(true) // invalid index + static const core::plane3df dummy; + return dummy; + } + } + + core::dimension2du COGLES2Driver::getMaxTextureSize() const + { + return core::dimension2du(MaxTextureSize, MaxTextureSize); + } + + GLenum COGLES2Driver::getGLBlend(E_BLEND_FACTOR factor) const + { + static GLenum const blendTable[] = + { + GL_ZERO, + GL_ONE, + GL_DST_COLOR, + GL_ONE_MINUS_DST_COLOR, + GL_SRC_COLOR, + GL_ONE_MINUS_SRC_COLOR, + GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, + GL_DST_ALPHA, + GL_ONE_MINUS_DST_ALPHA, + GL_SRC_ALPHA_SATURATE + }; + + return blendTable[factor]; + } + + GLenum COGLES2Driver::getZBufferBits() const + { + // TODO: never used, so not sure what this was really about (zbuffer used by device? Or for RTT's?) + + GLenum bits = 0; + + switch (Params.ZBufferBits) + { + case 24: +#if defined(GL_OES_depth24) + if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_depth24)) + bits = GL_DEPTH_COMPONENT24_OES; + else +#endif + bits = GL_DEPTH_COMPONENT16; + break; + case 32: +#if defined(GL_OES_depth32) + if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_depth32)) + bits = GL_DEPTH_COMPONENT32_OES; + else +#endif + bits = GL_DEPTH_COMPONENT16; + break; + default: + bits = GL_DEPTH_COMPONENT16; + break; + } + + return bits; + } + + bool COGLES2Driver::getColorFormatParameters(ECOLOR_FORMAT format, GLint& internalFormat, GLenum& pixelFormat, + GLenum& pixelType, void(**converter)(const void*, s32, void*)) const + { + bool supported = false; + pixelFormat = GL_RGBA; + pixelType = GL_UNSIGNED_BYTE; + *converter = 0; + + switch (format) + { + case ECF_A1R5G5B5: + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_UNSIGNED_SHORT_5_5_5_1; + *converter = CColorConverter::convert_A1R5G5B5toR5G5B5A1; + break; + case ECF_R5G6B5: + supported = true; + pixelFormat = GL_RGB; + pixelType = GL_UNSIGNED_SHORT_5_6_5; + break; + case ECF_R8G8B8: + supported = true; + pixelFormat = GL_RGB; + pixelType = GL_UNSIGNED_BYTE; + break; + case ECF_A8R8G8B8: + supported = true; + if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_IMG_texture_format_BGRA8888) || + queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_format_BGRA8888) || + queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_APPLE_texture_format_BGRA8888)) + { + pixelFormat = GL_BGRA; + } + else + { + pixelFormat = GL_RGBA; + *converter = CColorConverter::convert_A8R8G8B8toA8B8G8R8; + } + pixelType = GL_UNSIGNED_BYTE; + break; +#ifdef GL_EXT_texture_compression_s3tc + case ECF_DXT1: + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; +#endif +#ifdef GL_EXT_texture_compression_s3tc + case ECF_DXT2: + case ECF_DXT3: + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; +#endif +#ifdef GL_EXT_texture_compression_s3tc + case ECF_DXT4: + case ECF_DXT5: + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; +#endif +#ifdef GL_IMG_texture_compression_pvrtc + case ECF_PVRTC_RGB2: + supported = true; + pixelFormat = GL_RGB; + pixelType = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + break; +#endif +#ifdef GL_IMG_texture_compression_pvrtc + case ECF_PVRTC_ARGB2: + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + break; +#endif +#ifdef GL_IMG_texture_compression_pvrtc + case ECF_PVRTC_RGB4: + supported = true; + pixelFormat = GL_RGB; + pixelType = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + break; +#endif +#ifdef GL_IMG_texture_compression_pvrtc + case ECF_PVRTC_ARGB4: + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + break; +#endif +#ifdef GL_IMG_texture_compression_pvrtc2 + case ECF_PVRTC2_ARGB2: + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG; + break; +#endif +#ifdef GL_IMG_texture_compression_pvrtc2 + case ECF_PVRTC2_ARGB4: + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG; + break; +#endif +#ifdef GL_OES_compressed_ETC1_RGB8_texture + case ECF_ETC1: + supported = true; + pixelFormat = GL_RGB; + pixelType = GL_ETC1_RGB8_OES; + break; +#endif +#ifdef GL_ES_VERSION_3_0 // TO-DO - fix when extension name will be available + case ECF_ETC2_RGB: + supported = true; + pixelFormat = GL_RGB; + pixelType = GL_COMPRESSED_RGB8_ETC2; + break; +#endif +#ifdef GL_ES_VERSION_3_0 // TO-DO - fix when extension name will be available + case ECF_ETC2_ARGB: + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA8_ETC2_EAC; + break; +#endif + case ECF_D16: + supported = true; + pixelFormat = GL_DEPTH_COMPONENT; + pixelType = GL_UNSIGNED_SHORT; + break; + case ECF_D32: +#if defined(GL_OES_depth32) + if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_depth32)) + { + supported = true; + pixelFormat = GL_DEPTH_COMPONENT; + pixelType = GL_UNSIGNED_INT; + } +#endif + break; + case ECF_D24S8: +#ifdef GL_OES_packed_depth_stencil + if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_packed_depth_stencil)) + { + supported = true; + pixelFormat = GL_DEPTH_STENCIL_OES; + pixelType = GL_UNSIGNED_INT_24_8_OES; + } +#endif + break; + case ECF_R8: +#if defined(GL_EXT_texture_rg) + if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg)) + { + supported = true; + pixelFormat = GL_RED_EXT; + pixelType = GL_UNSIGNED_BYTE; + } +#endif + break; + case ECF_R8G8: +#if defined(GL_EXT_texture_rg) + if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg)) + { + supported = true; + pixelFormat = GL_RG_EXT; + pixelType = GL_UNSIGNED_BYTE; + } +#endif + break; + case ECF_R16: + break; + case ECF_R16G16: + break; + case ECF_R16F: +#if defined(GL_OES_texture_half_float) && defined(GL_EXT_texture_rg) + if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg) + && queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_half_float) + ) + { + supported = true; + pixelFormat = GL_RED_EXT; + pixelType = GL_HALF_FLOAT_OES ; + } +#endif + break; + case ECF_G16R16F: +#if defined(GL_OES_texture_half_float) && defined(GL_EXT_texture_rg) + if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg) + && queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_half_float) + ) + { + supported = true; + pixelFormat = GL_RG_EXT; + pixelType = GL_HALF_FLOAT_OES ; + } +#endif + break; + case ECF_A16B16G16R16F: +#if defined(GL_OES_texture_half_float) + if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_half_float)) + { + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_HALF_FLOAT_OES ; + } +#endif + break; + case ECF_R32F: +#if defined(GL_OES_texture_float) && defined(GL_EXT_texture_rg) + if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg) + && queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_float) + ) + { + supported = true; + pixelFormat = GL_RED_EXT; + pixelType = GL_FLOAT; + } +#endif + break; + case ECF_G32R32F: +#if defined(GL_OES_texture_float) && defined(GL_EXT_texture_rg) + if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg) + && queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_float) + ) + { + supported = true; + pixelFormat = GL_RG_EXT; + pixelType = GL_FLOAT; + } +#endif + break; + case ECF_A32B32G32R32F: +#if defined(GL_OES_texture_float) + if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_half_float)) + { + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_FLOAT ; + } +#endif + break; + default: + break; + } + + // ES 2.0 says internalFormat must match pixelFormat (chapter 3.7.1 in Spec). + // Doesn't mention if "match" means "equal" or some other way of matching, but + // some bug on Emscripten and browsing discussions by others lead me to believe + // it means they have to be equal. Note that this was different in OpenGL. + internalFormat = pixelFormat; + +#ifdef _IRR_IOS_PLATFORM_ + if (internalFormat == GL_BGRA) + internalFormat = GL_RGBA; +#endif + + return supported; + } + + bool COGLES2Driver::queryTextureFormat(ECOLOR_FORMAT format) const + { + GLint dummyInternalFormat; + GLenum dummyPixelFormat; + GLenum dummyPixelType; + void (*dummyConverter)(const void*, s32, void*); + return getColorFormatParameters(format, dummyInternalFormat, dummyPixelFormat, dummyPixelType, &dummyConverter); + } + + bool COGLES2Driver::needsTransparentRenderPass(const irr::video::SMaterial& material) const + { + return CNullDriver::needsTransparentRenderPass(material) || material.isAlphaBlendOperation(); + } + + const SMaterial& COGLES2Driver::getCurrentMaterial() const + { + return Material; + } + + COGLES2CacheHandler* COGLES2Driver::getCacheHandler() const + { + return CacheHandler; + } + + +} // end namespace +} // end namespace + +#endif // _IRR_COMPILE_WITH_OGLES2_ + +namespace irr +{ +namespace video +{ + +#ifndef _IRR_COMPILE_WITH_OGLES2_ +class IVideoDriver; +class IContextManager; +#endif + +IVideoDriver* createOGLES2Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager) +{ +#ifdef _IRR_COMPILE_WITH_OGLES2_ + COGLES2Driver* driver = new COGLES2Driver(params, io, contextManager); + driver->genericDriverInit(params.WindowSize, params.Stencilbuffer); // don't call in constructor, it uses virtual function calls of driver + return driver; +#else + return 0; +#endif // _IRR_COMPILE_WITH_OGLES2_ +} + +} // end namespace +} // end namespace diff --git a/source/Irrlicht/COGLES2Driver.h b/source/Irrlicht/COGLES2Driver.h new file mode 100644 index 00000000..e7e2ac4b --- /dev/null +++ b/source/Irrlicht/COGLES2Driver.h @@ -0,0 +1,442 @@ +// Copyright (C) 2014 Patryk Nadrowski +// Copyright (C) 2009-2010 Amundis +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __C_OGLES2_DRIVER_H_INCLUDED__ +#define __C_OGLES2_DRIVER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#include "SIrrCreationParameters.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "CNullDriver.h" +#include "IMaterialRendererServices.h" +#include "EDriverFeatures.h" +#include "fast_atof.h" +#include "COGLES2ExtensionHandler.h" +#include "IContextManager.h" + +#if defined(_IRR_WINDOWS_API_) +// include windows headers for HWND +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#endif + +#ifdef _MSC_VER +#pragma comment(lib, "libGLESv2.lib") +#endif + +namespace irr +{ +namespace video +{ + + class COGLES2FixedPipelineRenderer; + class COGLES2NormalMapRenderer; + class COGLES2ParallaxMapRenderer; + class COGLES2Renderer2D; + + class COGLES2Driver : public CNullDriver, public IMaterialRendererServices, public COGLES2ExtensionHandler + { + friend class COpenGLCoreTexture; + friend IVideoDriver* createOGLES2Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager); + + protected: + //! constructor (use createOGLES2Driver instead) + COGLES2Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager); + + public: + + //! destructor + virtual ~COGLES2Driver(); + + virtual bool beginScene(u16 clearFlag, SColor clearColor = SColor(255, 0, 0, 0), f32 clearDepth = 1.f, u8 clearStencil = 0, + const SExposedVideoData& videoData = SExposedVideoData(), core::rect* sourceRect = 0) _IRR_OVERRIDE_; + + virtual bool endScene() _IRR_OVERRIDE_; + + //! sets transformation + virtual void setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) _IRR_OVERRIDE_; + + struct SHWBufferLink_opengl : public SHWBufferLink + { + SHWBufferLink_opengl(const scene::IMeshBuffer *meshBuffer) + : SHWBufferLink(meshBuffer), vbo_verticesID(0), vbo_indicesID(0) + , vbo_verticesSize(0), vbo_indicesSize(0) + {} + + u32 vbo_verticesID; //tmp + u32 vbo_indicesID; //tmp + + u32 vbo_verticesSize; //tmp + u32 vbo_indicesSize; //tmp + }; + + bool updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer); + bool updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer); + + //! updates hardware buffer if needed + virtual bool updateHardwareBuffer(SHWBufferLink *HWBuffer) _IRR_OVERRIDE_; + + //! Create hardware buffer from mesh + virtual SHWBufferLink *createHardwareBuffer(const scene::IMeshBuffer* mb) _IRR_OVERRIDE_; + + //! Delete hardware buffer (only some drivers can) + virtual void deleteHardwareBuffer(SHWBufferLink *HWBuffer) _IRR_OVERRIDE_; + + //! Draw hardware buffer + virtual void drawHardwareBuffer(SHWBufferLink *HWBuffer) _IRR_OVERRIDE_; + + virtual IRenderTarget* addRenderTarget() _IRR_OVERRIDE_; + + //! draws a vertex primitive list + virtual void drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) _IRR_OVERRIDE_; + + //! queries the features of the driver, returns true if feature is available + virtual bool queryFeature(E_VIDEO_DRIVER_FEATURE feature) const _IRR_OVERRIDE_ + { + return FeatureEnabled[feature] && COGLES2ExtensionHandler::queryFeature(feature); + } + + //! Sets a material. + virtual void setMaterial(const SMaterial& material) _IRR_OVERRIDE_; + + 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) _IRR_OVERRIDE_; + + 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) _IRR_OVERRIDE_; + + // internally used + virtual void draw2DImage(const video::ITexture* texture, u32 layer, bool flip); + + //! draws a set of 2d images + virtual void draw2DImageBatch(const video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, s32 kerningWidth = 0, + const core::rect* clipRect = 0, + SColor color = SColor(255, 255, 255, 255), + bool useAlphaChannelOfTexture = false) _IRR_OVERRIDE_; + + void draw2DImageBatch(const video::ITexture* texture, + const core::array >& positions, + const core::array >& sourceRects, + const core::rect* clipRect, + SColor color, + bool useAlphaChannelOfTexture) _IRR_OVERRIDE_; + + //! draw an 2d rectangle + virtual void draw2DRectangle(SColor color, const core::rect& pos, + const core::rect* clip = 0) _IRR_OVERRIDE_; + + //!Draws an 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) _IRR_OVERRIDE_; + + //! Draws a 2d line. + virtual void draw2DLine(const core::position2d& start, + const core::position2d& end, + SColor color = SColor(255, 255, 255, 255)) _IRR_OVERRIDE_; + + //! Draws a single pixel + virtual void drawPixel(u32 x, u32 y, const SColor & color) _IRR_OVERRIDE_; + + //! Draws a 3d line. + virtual void draw3DLine(const core::vector3df& start, + const core::vector3df& end, + SColor color = SColor(255, 255, 255, 255)) _IRR_OVERRIDE_; + + //! Draws a pixel +// virtual void drawPixel(u32 x, u32 y, const SColor & color); + + //! Returns the name of the video driver. + virtual const wchar_t* getName() const _IRR_OVERRIDE_; + + //! deletes all dynamic lights there are + virtual void deleteAllDynamicLights() _IRR_OVERRIDE_; + + //! adds a dynamic light + virtual s32 addDynamicLight(const SLight& light) _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! returns the maximal amount of dynamic lights the device can handle + virtual u32 getMaximalDynamicLightAmount() const _IRR_OVERRIDE_; + + //! Returns the maximum texture size supported. + virtual core::dimension2du getMaxTextureSize() const _IRR_OVERRIDE_; + + //! Draws a shadow volume into the stencil buffer. + virtual void drawStencilShadowVolume(const core::array& triangles, bool zfail, u32 debugDataVisible=0) _IRR_OVERRIDE_; + + //! Fills the stencil shadow with color. + virtual void drawStencilShadow(bool clearStencilBuffer=false, + video::SColor leftUpEdge = video::SColor(0,0,0,0), + video::SColor rightUpEdge = video::SColor(0,0,0,0), + video::SColor leftDownEdge = video::SColor(0,0,0,0), + video::SColor rightDownEdge = video::SColor(0,0,0,0)) _IRR_OVERRIDE_; + + //! sets a viewport + virtual void setViewPort(const core::rect& area) _IRR_OVERRIDE_; + + //! Only used internally by the engine + virtual void OnResize(const core::dimension2d& size) _IRR_OVERRIDE_; + + //! Returns type of video driver + virtual E_DRIVER_TYPE getDriverType() const _IRR_OVERRIDE_; + + //! get color format of the current color buffer + virtual ECOLOR_FORMAT getColorFormat() const _IRR_OVERRIDE_; + + //! Returns the transformation set by setTransform + virtual const core::matrix4& getTransform(E_TRANSFORMATION_STATE state) const _IRR_OVERRIDE_; + + //! Can be called by an IMaterialRenderer to make its work easier. + virtual void setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial, bool resetAllRenderstates) _IRR_OVERRIDE_; + + //! Compare in SMaterial doesn't check texture parameters, so we should call this on each OnRender call. + void setTextureRenderStates(const SMaterial& material, bool resetAllRenderstates); + + //! Get a vertex shader constant index. + virtual s32 getVertexShaderConstantID(const c8* name) _IRR_OVERRIDE_; + + //! Get a pixel shader constant index. + virtual s32 getPixelShaderConstantID(const c8* name) _IRR_OVERRIDE_; + + //! Sets a vertex shader constant. + virtual void setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount = 1) _IRR_OVERRIDE_; + + //! Sets a pixel shader constant. + virtual void setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount = 1) _IRR_OVERRIDE_; + + //! Sets a constant for the vertex shader based on an index. + virtual bool setVertexShaderConstant(s32 index, const f32* floats, int count) _IRR_OVERRIDE_; + + //! Int interface for the above. + virtual bool setVertexShaderConstant(s32 index, const s32* ints, int count) _IRR_OVERRIDE_; + + //! Sets a constant for the pixel shader based on an index. + virtual bool setPixelShaderConstant(s32 index, const f32* floats, int count) _IRR_OVERRIDE_; + + //! Int interface for the above. + virtual bool setPixelShaderConstant(s32 index, const s32* ints, int count) _IRR_OVERRIDE_; + + //! Adds a new material renderer to the VideoDriver + virtual s32 addShaderMaterial(const c8* vertexShaderProgram, const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, E_MATERIAL_TYPE baseMaterial, s32 userData) _IRR_OVERRIDE_; + + //! Adds a new material renderer to the VideoDriver + virtual s32 addHighLevelShaderMaterial( + const c8* vertexShaderProgram, + const c8* vertexShaderEntryPointName = 0, + E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1, + const c8* pixelShaderProgram = 0, + const c8* pixelShaderEntryPointName = 0, + E_PIXEL_SHADER_TYPE psCompileTarget = EPST_PS_1_1, + const c8* geometryShaderProgram = 0, + const c8* geometryShaderEntryPointName = "main", + E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0, + scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES, + scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP, + u32 verticesOut = 0, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData=0) _IRR_OVERRIDE_; + + //! Returns pointer to the IGPUProgrammingServices interface. + virtual IGPUProgrammingServices* getGPUProgrammingServices() _IRR_OVERRIDE_; + + //! Returns a pointer to the IVideoDriver interface. + virtual IVideoDriver* getVideoDriver() _IRR_OVERRIDE_; + + //! Returns the maximum amount of primitives + virtual u32 getMaximalPrimitiveCount() const _IRR_OVERRIDE_; + + virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, + const io::path& name, const ECOLOR_FORMAT format = ECF_UNKNOWN) _IRR_OVERRIDE_; + + //! Creates a render target texture for a cubemap + ITexture* addRenderTargetTextureCubemap(const irr::u32 sideLen, + const io::path& name, const ECOLOR_FORMAT format) _IRR_OVERRIDE_; + + virtual bool setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor = SColor(255, 0, 0, 0), + f32 clearDepth = 1.f, u8 clearStencil = 0) _IRR_OVERRIDE_; + + virtual void clearBuffers(u16 flag, SColor color = SColor(255, 0, 0, 0), f32 depth = 1.f, u8 stencil = 0) _IRR_OVERRIDE_; + + //! Returns an image created from the last rendered frame. + virtual IImage* createScreenShot(video::ECOLOR_FORMAT format=video::ECF_UNKNOWN, video::E_RENDER_TARGET target=video::ERT_FRAME_BUFFER) _IRR_OVERRIDE_; + + //! checks if an OpenGL error has happened and prints it (+ some internal code which is usually the line number) + bool testGLError(int code=0); + + //! checks if an OGLES1 error has happened and prints it + bool testEGLError(); + + //! Set/unset a clipping plane. + virtual bool setClipPlane(u32 index, const core::plane3df& plane, bool enable = false) _IRR_OVERRIDE_; + + //! returns the current amount of user clip planes set. + u32 getClipPlaneCount() const; + + //! returns the 0 indexed Plane + const core::plane3df& getClipPlane(u32 index) const; + + //! Enable/disable a clipping plane. + virtual void enableClipPlane(u32 index, bool enable) _IRR_OVERRIDE_; + + //! Returns the graphics card vendor name. + virtual core::stringc getVendorInfo() _IRR_OVERRIDE_ + { + return VendorName; + }; + + virtual void removeTexture(ITexture* texture) _IRR_OVERRIDE_; + + //! Check if the driver supports creating textures with the given color format + virtual bool queryTextureFormat(ECOLOR_FORMAT format) const _IRR_OVERRIDE_; + + //! Used by some SceneNodes to check if a material should be rendered in the transparent render pass + virtual bool needsTransparentRenderPass(const irr::video::SMaterial& material) const _IRR_OVERRIDE_; + + //! Convert E_BLEND_FACTOR to OpenGL equivalent + GLenum getGLBlend(E_BLEND_FACTOR factor) const; + + //! Get ZBuffer bits. + virtual GLenum getZBufferBits() const; + + virtual bool getColorFormatParameters(ECOLOR_FORMAT format, GLint& internalFormat, GLenum& pixelFormat, + GLenum& pixelType, void(**converter)(const void*, s32, void*)) const; + + //! Get current material. + const SMaterial& getCurrentMaterial() const; + + COGLES2CacheHandler* getCacheHandler() const; + + protected: + //! inits the opengl-es driver + virtual bool genericDriverInit(const core::dimension2d& screenSize, bool stencilBuffer); + + void chooseMaterial2D(); + + virtual ITexture* createDeviceDependentTexture(const io::path& name, IImage* image) _IRR_OVERRIDE_; + + virtual ITexture* createDeviceDependentTextureCubemap(const io::path& name, const core::array& image) _IRR_OVERRIDE_; + + //! Map Irrlicht wrap mode to OpenGL enum + GLint getTextureWrapMode(u8 clamp) const; + + //! sets the needed renderstates + void setRenderStates3DMode(); + + //! sets the needed renderstates + void setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel); + + //! Prevent setRenderStateMode calls to do anything. + // hack to allow drawing meshbuffers in 2D mode. + // Better solution would be passing this flag through meshbuffers, + // but the way this is currently implemented in Irrlicht makes this tricky to implement + void lockRenderStateMode() + { + LockRenderStateMode = true; + } + + //! Allow setRenderStateMode calls to work again + void unlockRenderStateMode() + { + LockRenderStateMode = false; + } + + void draw2D3DVertexPrimitiveList(const void* vertices, + u32 vertexCount, const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, + E_INDEX_TYPE iType, bool is3D); + + void createMaterialRenderers(); + + void loadShaderData(const io::path& vertexShaderName, const io::path& fragmentShaderName, c8** vertexShaderData, c8** fragmentShaderData); + + bool setMaterialTexture(irr::u32 layerIdx, const irr::video::ITexture* texture); + + COGLES2CacheHandler* CacheHandler; + core::stringw Name; + core::stringc VendorName; + SIrrlichtCreationParameters Params; + + //! bool to make all renderstates reset if set to true. + bool ResetRenderStates; + bool LockRenderStateMode; + u8 AntiAlias; + + struct SUserClipPlane + { + core::plane3df Plane; + bool Enabled; + }; + + core::array UserClipPlane; + + core::matrix4 TextureFlipMatrix; + +private: + + COGLES2Renderer2D* MaterialRenderer2DActive; + COGLES2Renderer2D* MaterialRenderer2DTexture; + COGLES2Renderer2D* MaterialRenderer2DNoTexture; + + core::matrix4 Matrices[ETS_COUNT]; + + //! enumeration for rendering modes such as 2d and 3d for minimizing the switching of renderStates. + enum E_RENDER_MODE + { + ERM_NONE = 0, // no render state has been set yet. + ERM_2D, // 2d drawing rendermode + ERM_3D // 3d rendering mode + }; + + E_RENDER_MODE CurrentRenderMode; + bool Transformation3DChanged; + irr::io::path OGLES2ShaderPath; + + SMaterial Material, LastMaterial; + + //! Color buffer format + ECOLOR_FORMAT ColorFormat; + + //! 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), DesireToBeOn(true) { } + + SLight LightData; + bool DesireToBeOn; + }; + + core::array RequestedLights; + + IContextManager* ContextManager; + }; + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_OGLES2_ + +#endif // __C_OGLES2_DRIVER_H_INCLUDED__ diff --git a/source/Irrlicht/COGLES2ExtensionHandler.cpp b/source/Irrlicht/COGLES2ExtensionHandler.cpp new file mode 100644 index 00000000..416e5947 --- /dev/null +++ b/source/Irrlicht/COGLES2ExtensionHandler.cpp @@ -0,0 +1,58 @@ +// Copyright (C) 2015 Patryk Nadrowski +// Copyright (C) 2009-2010 Amundis +// 2017 modified by Michael Zeilfelder (unifying extension handlers) +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#include "COGLES2ExtensionHandler.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "irrString.h" +#include "SMaterial.h" +#include "fast_atof.h" + +namespace irr +{ +namespace video +{ + void COGLES2ExtensionHandler::initExtensions() + { + getGLVersion(); + + getGLExtensions(); + + GLint val=0; + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &val); + Feature.MaxTextureUnits = static_cast(val); + + #ifdef GL_EXT_texture_filter_anisotropic + if (FeatureAvailable[IRR_GL_EXT_texture_filter_anisotropic]) + { + glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &val); + MaxAnisotropy = static_cast(val); + } + #endif + #ifdef GL_MAX_ELEMENTS_INDICES + glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &val); + MaxIndices=val; + #endif + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &val); + MaxTextureSize=static_cast(val); + #ifdef GL_EXT_texture_lod_bias + if (FeatureAvailable[IRR_EXT_texture_lod_bias]) + glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS_EXT, &MaxTextureLODBias); + #endif + glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, DimAliasedLine); + glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, DimAliasedPoint); + + Feature.MaxTextureUnits = core::min_(Feature.MaxTextureUnits, static_cast(MATERIAL_MAX_TEXTURES)); + Feature.MaxTextureUnits = core::min_(Feature.MaxTextureUnits, static_cast(MATERIAL_MAX_TEXTURES_USED)); + Feature.ColorAttachment = 1; + } + +} // end namespace video +} // end namespace irr + + +#endif // _IRR_COMPILE_WITH_OGLES2_ diff --git a/source/Irrlicht/COGLES2ExtensionHandler.h b/source/Irrlicht/COGLES2ExtensionHandler.h new file mode 100644 index 00000000..2e81b373 --- /dev/null +++ b/source/Irrlicht/COGLES2ExtensionHandler.h @@ -0,0 +1,194 @@ +// Copyright (C) 2015 Patryk Nadrowski +// Copyright (C) 2009-2010 Amundis +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __C_OGLES2_EXTENSION_HANDLER_H_INCLUDED__ +#define __C_OGLES2_EXTENSION_HANDLER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "EDriverFeatures.h" +#include "irrTypes.h" +#include "os.h" + +#include "COGLES2Common.h" + +#include "COGLESCoreExtensionHandler.h" + +namespace irr +{ +namespace video +{ + + class COGLES2ExtensionHandler : public COGLESCoreExtensionHandler + { + public: + COGLES2ExtensionHandler() : COGLESCoreExtensionHandler() {} + + void initExtensions(); + + bool queryFeature(video::E_VIDEO_DRIVER_FEATURE feature) const + { + switch (feature) + { + case EVDF_RENDER_TO_TARGET: + case EVDF_HARDWARE_TL: + case EVDF_MULTITEXTURE: + case EVDF_BILINEAR_FILTER: + case EVDF_MIP_MAP: + case EVDF_MIP_MAP_AUTO_UPDATE: + case EVDF_VERTEX_SHADER_1_1: + case EVDF_PIXEL_SHADER_1_1: + case EVDF_PIXEL_SHADER_1_2: + case EVDF_PIXEL_SHADER_2_0: + case EVDF_VERTEX_SHADER_2_0: + case EVDF_ARB_GLSL: + case EVDF_TEXTURE_NSQUARE: + case EVDF_TEXTURE_NPOT: + case EVDF_FRAMEBUFFER_OBJECT: + case EVDF_VERTEX_BUFFER_OBJECT: + case EVDF_COLOR_MASK: + case EVDF_ALPHA_TO_COVERAGE: + case EVDF_POLYGON_OFFSET: + case EVDF_BLEND_OPERATIONS: + case EVDF_BLEND_SEPARATE: + case EVDF_TEXTURE_MATRIX: + case EVDF_TEXTURE_CUBEMAP: + return true; + case EVDF_ARB_VERTEX_PROGRAM_1: + case EVDF_ARB_FRAGMENT_PROGRAM_1: + case EVDF_GEOMETRY_SHADER: + case EVDF_MULTIPLE_RENDER_TARGETS: + case EVDF_MRT_BLEND: + case EVDF_MRT_COLOR_MASK: + case EVDF_MRT_BLEND_FUNC: + case EVDF_OCCLUSION_QUERY: + return false; + case EVDF_TEXTURE_COMPRESSED_DXT: + return false; // NV Tegra need improvements here + case EVDF_TEXTURE_COMPRESSED_PVRTC: + return FeatureAvailable[IRR_GL_IMG_texture_compression_pvrtc]; + case EVDF_TEXTURE_COMPRESSED_PVRTC2: + return FeatureAvailable[IRR_GL_IMG_texture_compression_pvrtc2]; + case EVDF_TEXTURE_COMPRESSED_ETC1: + return FeatureAvailable[IRR_GL_OES_compressed_ETC1_RGB8_texture]; + case EVDF_TEXTURE_COMPRESSED_ETC2: + return false; + case EVDF_STENCIL_BUFFER: + return StencilBuffer; + default: + return false; + }; + } + + inline void irrGlActiveTexture(GLenum texture) + { + glActiveTexture(texture); + } + + inline void irrGlCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, + GLsizei imageSize, const void* data) + { + glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); + } + + inline void irrGlCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLsizei imageSize, const void* data) + { + glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); + } + + inline void irrGlUseProgram(GLuint prog) + { + glUseProgram(prog); + } + + inline void irrGlBindFramebuffer(GLenum target, GLuint framebuffer) + { + glBindFramebuffer(target, framebuffer); + } + + inline void irrGlDeleteFramebuffers(GLsizei n, const GLuint *framebuffers) + { + glDeleteFramebuffers(n, framebuffers); + } + + inline void irrGlGenFramebuffers(GLsizei n, GLuint *framebuffers) + { + glGenFramebuffers(n, framebuffers); + } + + inline GLenum irrGlCheckFramebufferStatus(GLenum target) + { + return glCheckFramebufferStatus(target); + } + + inline void irrGlFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) + { + glFramebufferTexture2D(target, attachment, textarget, texture, level); + } + + inline void irrGlGenerateMipmap(GLenum target) + { + glGenerateMipmap(target); + } + + inline void irrGlActiveStencilFace(GLenum face) + { + } + + inline void irrGlDrawBuffer(GLenum mode) + { + } + + inline void irrGlDrawBuffers(GLsizei n, const GLenum *bufs) + { + } + + inline void irrGlBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) + { + glBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); + } + + inline void irrGlBlendEquation(GLenum mode) + { + glBlendEquation(mode); + } + + inline void irrGlEnableIndexed(GLenum target, GLuint index) + { + } + + inline void irrGlDisableIndexed(GLenum target, GLuint index) + { + } + + inline void irrGlColorMaskIndexed(GLuint buf, GLboolean r, GLboolean g, GLboolean b, GLboolean a) + { + } + + inline void irrGlBlendFuncIndexed(GLuint buf, GLenum src, GLenum dst) + { + } + + inline void irrGlBlendFuncSeparateIndexed(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) + { + } + + inline void irrGlBlendEquationIndexed(GLuint buf, GLenum mode) + { + } + + inline void irrGlBlendEquationSeparateIndexed(GLuint buf, GLenum modeRGB, GLenum modeAlpha) + { + } + }; + +} +} + +#endif +#endif diff --git a/source/Irrlicht/COGLES2FixedPipelineRenderer.cpp b/source/Irrlicht/COGLES2FixedPipelineRenderer.cpp new file mode 100644 index 00000000..369e422d --- /dev/null +++ b/source/Irrlicht/COGLES2FixedPipelineRenderer.cpp @@ -0,0 +1,412 @@ +// Copyright (C) 2014 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#include "COGLES2FixedPipelineRenderer.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "IVideoDriver.h" +#include "SLight.h" + +namespace irr +{ +namespace video +{ + +// Base callback + +COGLES2MaterialBaseCB::COGLES2MaterialBaseCB() : + FirstUpdateBase(true), WVPMatrixID(-1), WVMatrixID(-1), NMatrixID(-1), GlobalAmbientID(-1), MaterialAmbientID(-1), MaterialDiffuseID(-1), MaterialEmissiveID(-1), MaterialSpecularID(-1), MaterialShininessID(-1), LightCountID(-1), LightTypeID(-1), + LightPositionID(-1), LightDirectionID(-1), LightAttenuationID(-1), LightAmbientID(-1), LightDiffuseID(-1), LightSpecularID(-1), FogEnableID(-1), FogTypeID(-1), FogColorID(-1), FogStartID(-1), + FogEndID(-1), FogDensityID(-1), ThicknessID(-1), LightEnable(false), MaterialAmbient(SColorf(0.f, 0.f, 0.f)), MaterialDiffuse(SColorf(0.f, 0.f, 0.f)), MaterialEmissive(SColorf(0.f, 0.f, 0.f)), MaterialSpecular(SColorf(0.f, 0.f, 0.f)), + MaterialShininess(0.f), FogEnable(0), FogType(1), FogColor(SColorf(0.f, 0.f, 0.f, 1.f)), FogStart(0.f), FogEnd(0.f), FogDensity(0.f), Thickness(1.f) +{ + for (u32 i = 0; i < 8; ++i) + { + LightType[i] = 0; + LightPosition[i] = core::vector3df(0.f, 0.f, 0.f); + LightDirection[i] = core::vector3df(0.f, 0.f, 0.f); + LightAttenuation[i] = core::vector3df(0.f, 0.f, 0.f); + LightAmbient[i] = SColorf(0.f, 0.f, 0.f); + LightDiffuse[i] = SColorf(0.f, 0.f, 0.f); + LightSpecular[i] = SColorf(0.f, 0.f, 0.f); + } +} + +void COGLES2MaterialBaseCB::OnSetMaterial(const SMaterial& material) +{ + LightEnable = material.Lighting; + MaterialAmbient = SColorf(material.AmbientColor); + MaterialDiffuse = SColorf(material.DiffuseColor); + MaterialEmissive = SColorf(material.EmissiveColor); + MaterialSpecular = SColorf(material.SpecularColor); + MaterialShininess = material.Shininess; + + FogEnable = material.FogEnable ? 1 : 0; + + Thickness = (material.Thickness > 0.f) ? material.Thickness : 1.f; +} + +void COGLES2MaterialBaseCB::OnSetConstants(IMaterialRendererServices* services, s32 userData) +{ + IVideoDriver* driver = services->getVideoDriver(); + + if (FirstUpdateBase) + { + WVPMatrixID = services->getVertexShaderConstantID("uWVPMatrix"); + WVMatrixID = services->getVertexShaderConstantID("uWVMatrix"); + NMatrixID = services->getVertexShaderConstantID("uNMatrix"); + GlobalAmbientID = services->getVertexShaderConstantID("uGlobalAmbient"); + MaterialAmbientID = services->getVertexShaderConstantID("uMaterialAmbient"); + MaterialDiffuseID = services->getVertexShaderConstantID("uMaterialDiffuse"); + MaterialEmissiveID = services->getVertexShaderConstantID("uMaterialEmissive"); + MaterialSpecularID = services->getVertexShaderConstantID("uMaterialSpecular"); + MaterialShininessID = services->getVertexShaderConstantID("uMaterialShininess"); + LightCountID = services->getVertexShaderConstantID("uLightCount"); + LightTypeID = services->getVertexShaderConstantID("uLightType"); + LightPositionID = services->getVertexShaderConstantID("uLightPosition"); + LightDirectionID = services->getVertexShaderConstantID("uLightDirection"); + LightAttenuationID = services->getVertexShaderConstantID("uLightAttenuation"); + LightAmbientID = services->getVertexShaderConstantID("uLightAmbient"); + LightDiffuseID = services->getVertexShaderConstantID("uLightDiffuse"); + LightSpecularID = services->getVertexShaderConstantID("uLightSpecular"); + FogEnableID = services->getVertexShaderConstantID("uFogEnable"); + FogTypeID = services->getVertexShaderConstantID("uFogType"); + FogColorID = services->getVertexShaderConstantID("uFogColor"); + FogStartID = services->getVertexShaderConstantID("uFogStart"); + FogEndID = services->getVertexShaderConstantID("uFogEnd"); + FogDensityID = services->getVertexShaderConstantID("uFogDensity"); + ThicknessID = services->getVertexShaderConstantID("uThickness"); + + FirstUpdateBase = false; + } + + const core::matrix4 W = driver->getTransform(ETS_WORLD); + const core::matrix4 V = driver->getTransform(ETS_VIEW); + const core::matrix4 P = driver->getTransform(ETS_PROJECTION); + + core::matrix4 Matrix = P * V * W; + services->setPixelShaderConstant(WVPMatrixID, Matrix.pointer(), 16); + + Matrix = V * W; + services->setPixelShaderConstant(WVMatrixID, Matrix.pointer(), 16); + + Matrix.makeInverse(); + services->setPixelShaderConstant(NMatrixID, Matrix.getTransposed().pointer(), 16); + + s32 LightCount = LightEnable ? driver->getDynamicLightCount() : 0; + services->setPixelShaderConstant(LightCountID, &LightCount, 1); + + if (LightCount > 0) + { + video::SColorf globalAmbient(driver->getAmbientLight()); + services->setVertexShaderConstant(GlobalAmbientID, reinterpret_cast(&globalAmbient), 4); + + // TODO: this are all vertex shader constants, why are they all set as pixel shader constants? (it currently works so I'm scared to change it...) + services->setPixelShaderConstant(MaterialAmbientID, reinterpret_cast(&MaterialAmbient), 4); + services->setPixelShaderConstant(MaterialDiffuseID, reinterpret_cast(&MaterialDiffuse), 4); + services->setPixelShaderConstant(MaterialEmissiveID, reinterpret_cast(&MaterialEmissive), 4); + services->setPixelShaderConstant(MaterialSpecularID, reinterpret_cast(&MaterialSpecular), 4); + services->setPixelShaderConstant(MaterialShininessID, &MaterialShininess, 1); + + Matrix = V; + + for (s32 i = 0; i < LightCount; ++i) + { + SLight CurrentLight = driver->getDynamicLight(i); + + Matrix.transformVect(CurrentLight.Position); + + switch (CurrentLight.Type) + { + case ELT_DIRECTIONAL: + LightType[i] = 2; + break; + case ELT_SPOT: + LightType[i] = 1; + break; + default: // ELT_POINT + LightType[i] = 0; + break; + } + + LightPosition[i] = CurrentLight.Position; + LightDirection[i] = CurrentLight.Direction; + LightAttenuation[i] = CurrentLight.Attenuation; + LightAmbient[i] = CurrentLight.AmbientColor; + LightDiffuse[i] = CurrentLight.DiffuseColor; + LightSpecular[i] = CurrentLight.SpecularColor; + } + + const int MAX_SHADER_LIGHTS = 8; // must be the same as MAX_LIGHTS define in the shader + services->setPixelShaderConstant(LightTypeID, LightType, MAX_SHADER_LIGHTS); + services->setPixelShaderConstant(LightPositionID, reinterpret_cast(LightPosition), 3*MAX_SHADER_LIGHTS); + services->setPixelShaderConstant(LightDirectionID, reinterpret_cast(LightDirection), 3*MAX_SHADER_LIGHTS); + services->setPixelShaderConstant(LightAttenuationID, reinterpret_cast(LightAttenuation), 3*MAX_SHADER_LIGHTS); + services->setPixelShaderConstant(LightAmbientID, reinterpret_cast(LightAmbient), 4*MAX_SHADER_LIGHTS); + services->setPixelShaderConstant(LightDiffuseID, reinterpret_cast(LightDiffuse), 4*MAX_SHADER_LIGHTS); + services->setPixelShaderConstant(LightSpecularID, reinterpret_cast(LightSpecular), 4*MAX_SHADER_LIGHTS); + } + + services->setPixelShaderConstant(FogEnableID, &FogEnable, 1); + + if (FogEnable) + { + SColor TempColor(0); + E_FOG_TYPE TempType = EFT_FOG_LINEAR; + bool TempPerFragment = false; + bool TempRange = false; + + driver->getFog(TempColor, TempType, FogStart, FogEnd, FogDensity, TempPerFragment, TempRange); + + FogType = (s32)TempType; + FogColor = SColorf(TempColor); + + services->setPixelShaderConstant(FogTypeID, &FogType, 1); + services->setPixelShaderConstant(FogColorID, reinterpret_cast(&FogColor), 4); + services->setPixelShaderConstant(FogStartID, &FogStart, 1); + services->setPixelShaderConstant(FogEndID, &FogEnd, 1); + services->setPixelShaderConstant(FogDensityID, &FogDensity, 1); + } + + services->setPixelShaderConstant(ThicknessID, &Thickness, 1); +} + +// EMT_SOLID + EMT_TRANSPARENT_ADD_COLOR + EMT_TRANSPARENT_ALPHA_CHANNEL + EMT_TRANSPARENT_VERTEX_ALPHA + +COGLES2MaterialSolidCB::COGLES2MaterialSolidCB() : + FirstUpdate(true), TMatrix0ID(-1), AlphaRefID(-1), TextureUsage0ID(-1), TextureUnit0ID(-1), AlphaRef(0.5f), TextureUsage0(0), TextureUnit0(0) +{ +} + +void COGLES2MaterialSolidCB::OnSetMaterial(const SMaterial& material) +{ + COGLES2MaterialBaseCB::OnSetMaterial(material); + + AlphaRef = material.MaterialTypeParam; + TextureUsage0 = (material.TextureLayer[0].Texture) ? 1 : 0; +} + +void COGLES2MaterialSolidCB::OnSetConstants(IMaterialRendererServices* services, s32 userData) +{ + COGLES2MaterialBaseCB::OnSetConstants(services, userData); + + IVideoDriver* driver = services->getVideoDriver(); + + if (FirstUpdate) + { + TMatrix0ID = services->getVertexShaderConstantID("uTMatrix0"); + AlphaRefID = services->getVertexShaderConstantID("uAlphaRef"); + TextureUsage0ID = services->getVertexShaderConstantID("uTextureUsage0"); + TextureUnit0ID = services->getVertexShaderConstantID("uTextureUnit0"); + + FirstUpdate = false; + } + + core::matrix4 Matrix = driver->getTransform(ETS_TEXTURE_0); + services->setPixelShaderConstant(TMatrix0ID, Matrix.pointer(), 16); + + services->setPixelShaderConstant(AlphaRefID, &AlphaRef, 1); + services->setPixelShaderConstant(TextureUsage0ID, &TextureUsage0, 1); + services->setPixelShaderConstant(TextureUnit0ID, &TextureUnit0, 1); +} + +// EMT_SOLID_2_LAYER + EMT_DETAIL_MAP + +COGLES2MaterialSolid2CB::COGLES2MaterialSolid2CB() : + FirstUpdate(true), TMatrix0ID(-1), TMatrix1ID(-1), TextureUsage0ID(-1), TextureUsage1ID(-1), TextureUnit0ID(-1), TextureUnit1ID(-1), + TextureUsage0(0), TextureUsage1(0), TextureUnit0(0), TextureUnit1(1) +{ +} + +void COGLES2MaterialSolid2CB::OnSetMaterial(const SMaterial& material) +{ + COGLES2MaterialBaseCB::OnSetMaterial(material); + + TextureUsage0 = (material.TextureLayer[0].Texture) ? 1 : 0; + TextureUsage1 = (material.TextureLayer[1].Texture) ? 1 : 0; +} + +void COGLES2MaterialSolid2CB::OnSetConstants(IMaterialRendererServices* services, s32 userData) +{ + COGLES2MaterialBaseCB::OnSetConstants(services, userData); + + IVideoDriver* driver = services->getVideoDriver(); + + if (FirstUpdate) + { + TMatrix0ID = services->getVertexShaderConstantID("uTMatrix0"); + TMatrix1ID = services->getVertexShaderConstantID("uTMatrix1"); + TextureUsage0ID = services->getVertexShaderConstantID("uTextureUsage0"); + TextureUsage1ID = services->getVertexShaderConstantID("uTextureUsage1"); + TextureUnit0ID = services->getVertexShaderConstantID("uTextureUnit0"); + TextureUnit1ID = services->getVertexShaderConstantID("uTextureUnit1"); + + FirstUpdate = false; + } + + core::matrix4 Matrix = driver->getTransform(ETS_TEXTURE_0); + services->setPixelShaderConstant(TMatrix0ID, Matrix.pointer(), 16); + + Matrix = driver->getTransform(ETS_TEXTURE_1); + services->setPixelShaderConstant(TMatrix1ID, Matrix.pointer(), 16); + + services->setPixelShaderConstant(TextureUsage0ID, &TextureUsage0, 1); + services->setPixelShaderConstant(TextureUsage1ID, &TextureUsage1, 1); + services->setPixelShaderConstant(TextureUnit0ID, &TextureUnit0, 1); + services->setPixelShaderConstant(TextureUnit1ID, &TextureUnit1, 1); +} + +// EMT_LIGHTMAP + EMT_LIGHTMAP_ADD + EMT_LIGHTMAP_M2 + EMT_LIGHTMAP_M4 + +COGLES2MaterialLightmapCB::COGLES2MaterialLightmapCB(float modulate) : + FirstUpdate(true), TMatrix0ID(-1), TMatrix1ID(-1), ModulateID(-1), TextureUsage0ID(-1), TextureUsage1ID(-1), TextureUnit0ID(-1), TextureUnit1ID(-1), + Modulate(modulate), TextureUsage0(0), TextureUsage1(0), TextureUnit0(0), TextureUnit1(1) +{ +} + +void COGLES2MaterialLightmapCB::OnSetMaterial(const SMaterial& material) +{ + COGLES2MaterialBaseCB::OnSetMaterial(material); + + TextureUsage0 = (material.TextureLayer[0].Texture) ? 1 : 0; + TextureUsage1 = (material.TextureLayer[1].Texture) ? 1 : 0; +} + +void COGLES2MaterialLightmapCB::OnSetConstants(IMaterialRendererServices* services, s32 userData) +{ + COGLES2MaterialBaseCB::OnSetConstants(services, userData); + + IVideoDriver* driver = services->getVideoDriver(); + + if (FirstUpdate) + { + TMatrix0ID = services->getVertexShaderConstantID("uTMatrix0"); + TMatrix1ID = services->getVertexShaderConstantID("uTMatrix1"); + ModulateID = services->getVertexShaderConstantID("uModulate"); + TextureUsage0ID = services->getVertexShaderConstantID("uTextureUsage0"); + TextureUsage1ID = services->getVertexShaderConstantID("uTextureUsage1"); + TextureUnit0ID = services->getVertexShaderConstantID("uTextureUnit0"); + TextureUnit1ID = services->getVertexShaderConstantID("uTextureUnit1"); + + FirstUpdate = false; + } + + core::matrix4 Matrix = driver->getTransform(ETS_TEXTURE_0); + services->setPixelShaderConstant(TMatrix0ID, Matrix.pointer(), 16); + + Matrix = driver->getTransform(ETS_TEXTURE_1); + services->setPixelShaderConstant(TMatrix1ID, Matrix.pointer(), 16); + + services->setPixelShaderConstant(ModulateID, &Modulate, 1); + services->setPixelShaderConstant(TextureUsage0ID, &TextureUsage0, 1); + services->setPixelShaderConstant(TextureUsage1ID, &TextureUsage1, 1); + services->setPixelShaderConstant(TextureUnit0ID, &TextureUnit0, 1); + services->setPixelShaderConstant(TextureUnit1ID, &TextureUnit1, 1); +} + +// EMT_SPHERE_MAP + EMT_REFLECTION_2_LAYER + EMT_TRANSPARENT_REFLECTION_2_LAYER + +COGLES2MaterialReflectionCB::COGLES2MaterialReflectionCB() : + FirstUpdate(true), TMatrix0ID(-1), TextureUsage0ID(-1), TextureUsage1ID(-1), TextureUnit0ID(-1), TextureUnit1ID(-1), + TextureUsage0(0), TextureUsage1(0), TextureUnit0(0), TextureUnit1(1) +{ +} + +void COGLES2MaterialReflectionCB::OnSetMaterial(const SMaterial& material) +{ + COGLES2MaterialBaseCB::OnSetMaterial(material); + + TextureUsage0 = (material.TextureLayer[0].Texture) ? 1 : 0; + TextureUsage1 = (material.TextureLayer[1].Texture) ? 1 : 0; +} + +void COGLES2MaterialReflectionCB::OnSetConstants(IMaterialRendererServices* services, s32 userData) +{ + COGLES2MaterialBaseCB::OnSetConstants(services, userData); + + IVideoDriver* driver = services->getVideoDriver(); + + if (FirstUpdate) + { + TMatrix0ID = services->getVertexShaderConstantID("uTMatrix0"); + TextureUsage0ID = services->getVertexShaderConstantID("uTextureUsage0"); + TextureUsage1ID = services->getVertexShaderConstantID("uTextureUsage1"); + TextureUnit0ID = services->getVertexShaderConstantID("uTextureUnit0"); + TextureUnit1ID = services->getVertexShaderConstantID("uTextureUnit1"); + + FirstUpdate = false; + } + + core::matrix4 Matrix = driver->getTransform(ETS_TEXTURE_0); + services->setPixelShaderConstant(TMatrix0ID, Matrix.pointer(), 16); + + services->setPixelShaderConstant(TextureUsage0ID, &TextureUsage0, 1); + services->setPixelShaderConstant(TextureUsage1ID, &TextureUsage1, 1); + services->setPixelShaderConstant(TextureUnit0ID, &TextureUnit0, 1); + services->setPixelShaderConstant(TextureUnit1ID, &TextureUnit1, 1); +} + +// EMT_ONETEXTURE_BLEND + +COGLES2MaterialOneTextureBlendCB::COGLES2MaterialOneTextureBlendCB() : + FirstUpdate(true), TMatrix0ID(-1), BlendTypeID(-1), TextureUsage0ID(-1), TextureUnit0ID(-1), BlendType(0), TextureUsage0(0), TextureUnit0(0) +{ +} + +void COGLES2MaterialOneTextureBlendCB::OnSetMaterial(const SMaterial& material) +{ + COGLES2MaterialBaseCB::OnSetMaterial(material); + + BlendType = 0; + + E_BLEND_FACTOR srcRGBFact,dstRGBFact,srcAlphaFact,dstAlphaFact; + E_MODULATE_FUNC modulate; + u32 alphaSource; + unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulate, alphaSource, material.MaterialTypeParam); + + if (textureBlendFunc_hasAlpha(srcRGBFact) || textureBlendFunc_hasAlpha(dstRGBFact) || textureBlendFunc_hasAlpha(srcAlphaFact) || textureBlendFunc_hasAlpha(dstAlphaFact)) + { + if (alphaSource == EAS_VERTEX_COLOR) + { + BlendType = 1; + } + else if (alphaSource == EAS_TEXTURE) + { + BlendType = 2; + } + } + + TextureUsage0 = (material.TextureLayer[0].Texture) ? 1 : 0; +} + +void COGLES2MaterialOneTextureBlendCB::OnSetConstants(IMaterialRendererServices* services, s32 userData) +{ + COGLES2MaterialBaseCB::OnSetConstants(services, userData); + + IVideoDriver* driver = services->getVideoDriver(); + + if (FirstUpdate) + { + TMatrix0ID = services->getVertexShaderConstantID("uTMatrix0"); + BlendTypeID = services->getVertexShaderConstantID("uBlendType"); + TextureUsage0ID = services->getVertexShaderConstantID("uTextureUsage0"); + TextureUnit0ID = services->getVertexShaderConstantID("uTextureUnit0"); + + FirstUpdate = false; + } + + core::matrix4 Matrix = driver->getTransform(ETS_TEXTURE_0); + services->setPixelShaderConstant(TMatrix0ID, Matrix.pointer(), 16); + + services->setPixelShaderConstant(BlendTypeID, &BlendType, 1); + services->setPixelShaderConstant(TextureUsage0ID, &TextureUsage0, 1); + services->setPixelShaderConstant(TextureUnit0ID, &TextureUnit0, 1); +} + +} +} + +#endif + diff --git a/source/Irrlicht/COGLES2FixedPipelineRenderer.h b/source/Irrlicht/COGLES2FixedPipelineRenderer.h new file mode 100644 index 00000000..78ae4939 --- /dev/null +++ b/source/Irrlicht/COGLES2FixedPipelineRenderer.h @@ -0,0 +1,206 @@ +// Copyright (C) 2014 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __C_OGLES2_FIXED_PIPELINE_SHADER_H_INCLUDED__ +#define __C_OGLES2_FIXED_PIPELINE_SHADER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "IShaderConstantSetCallBack.h" +#include "IMaterialRendererServices.h" + +namespace irr +{ +namespace video +{ + +class COGLES2MaterialBaseCB : public IShaderConstantSetCallBack +{ +public: + COGLES2MaterialBaseCB(); + + virtual void OnSetMaterial(const SMaterial& material); + virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData); + +protected: + bool FirstUpdateBase; + + s32 WVPMatrixID; + s32 WVMatrixID; + s32 NMatrixID; + + s32 GlobalAmbientID; + s32 MaterialAmbientID; + s32 MaterialDiffuseID; + s32 MaterialEmissiveID; + s32 MaterialSpecularID; + s32 MaterialShininessID; + + s32 LightCountID; + s32 LightTypeID; + s32 LightPositionID; + s32 LightDirectionID; + s32 LightAttenuationID; + s32 LightAmbientID; + s32 LightDiffuseID; + s32 LightSpecularID; + + s32 FogEnableID; + s32 FogTypeID; + s32 FogColorID; + s32 FogStartID; + s32 FogEndID; + s32 FogDensityID; + + s32 ThicknessID; + + bool LightEnable; + SColorf GlobalAmbient; + SColorf MaterialAmbient; + SColorf MaterialDiffuse; + SColorf MaterialEmissive; + SColorf MaterialSpecular; + f32 MaterialShininess; + + s32 LightType[8]; + core::vector3df LightPosition[8]; + core::vector3df LightDirection[8]; + core::vector3df LightAttenuation[8]; + SColorf LightAmbient[8]; + SColorf LightDiffuse[8]; + SColorf LightSpecular[8]; + + s32 FogEnable; + s32 FogType; + SColorf FogColor; + f32 FogStart; + f32 FogEnd; + f32 FogDensity; + + f32 Thickness; +}; + +class COGLES2MaterialSolidCB : public COGLES2MaterialBaseCB +{ +public: + COGLES2MaterialSolidCB(); + + virtual void OnSetMaterial(const SMaterial& material); + virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData); + +protected: + bool FirstUpdate; + + s32 TMatrix0ID; + s32 AlphaRefID; + s32 TextureUsage0ID; + s32 TextureUnit0ID; + + f32 AlphaRef; + s32 TextureUsage0; + s32 TextureUnit0; +}; + +class COGLES2MaterialSolid2CB : public COGLES2MaterialBaseCB +{ +public: + COGLES2MaterialSolid2CB(); + + virtual void OnSetMaterial(const SMaterial& material); + virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData); + +protected: + bool FirstUpdate; + + s32 TMatrix0ID; + s32 TMatrix1ID; + s32 TextureUsage0ID; + s32 TextureUsage1ID; + s32 TextureUnit0ID; + s32 TextureUnit1ID; + + s32 TextureUsage0; + s32 TextureUsage1; + s32 TextureUnit0; + s32 TextureUnit1; +}; + +class COGLES2MaterialLightmapCB : public COGLES2MaterialBaseCB +{ +public: + COGLES2MaterialLightmapCB(float modulate); + + virtual void OnSetMaterial(const SMaterial& material); + virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData); + +protected: + bool FirstUpdate; + + s32 TMatrix0ID; + s32 TMatrix1ID; + s32 ModulateID; + s32 TextureUsage0ID; + s32 TextureUsage1ID; + s32 TextureUnit0ID; + s32 TextureUnit1ID; + + f32 Modulate; + s32 TextureUsage0; + s32 TextureUsage1; + s32 TextureUnit0; + s32 TextureUnit1; +}; + +class COGLES2MaterialReflectionCB : public COGLES2MaterialBaseCB +{ +public: + COGLES2MaterialReflectionCB(); + + virtual void OnSetMaterial(const SMaterial& material); + virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData); + +protected: + bool FirstUpdate; + + s32 TMatrix0ID; + s32 TextureUsage0ID; + s32 TextureUsage1ID; + s32 TextureUnit0ID; + s32 TextureUnit1ID; + + s32 TextureUsage0; + s32 TextureUsage1; + s32 TextureUnit0; + s32 TextureUnit1; +}; + +class COGLES2MaterialOneTextureBlendCB : public COGLES2MaterialBaseCB +{ +public: + COGLES2MaterialOneTextureBlendCB(); + + virtual void OnSetMaterial(const SMaterial& material); + virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData); + +protected: + bool FirstUpdate; + + s32 TMatrix0ID; + s32 BlendTypeID; + s32 TextureUsage0ID; + s32 TextureUnit0ID; + + s32 BlendType; + s32 TextureUsage0; + s32 TextureUnit0; +}; + +} +} + +#endif +#endif + diff --git a/source/Irrlicht/COGLES2MaterialRenderer.cpp b/source/Irrlicht/COGLES2MaterialRenderer.cpp new file mode 100644 index 00000000..e7cdfb57 --- /dev/null +++ b/source/Irrlicht/COGLES2MaterialRenderer.cpp @@ -0,0 +1,484 @@ +// Copyright (C) 2014 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "COGLES2MaterialRenderer.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "EVertexAttributes.h" +#include "IGPUProgrammingServices.h" +#include "IShaderConstantSetCallBack.h" +#include "IVideoDriver.h" +#include "os.h" + +#include "COGLES2Driver.h" + +#include "COpenGLCoreTexture.h" +#include "COpenGLCoreCacheHandler.h" + +namespace irr +{ +namespace video +{ + + +COGLES2MaterialRenderer::COGLES2MaterialRenderer(COGLES2Driver* driver, + s32& outMaterialTypeNr, + const c8* vertexShaderProgram, + const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, + s32 userData) + : Driver(driver), CallBack(callback), Alpha(false), Blending(false), FixedBlending(false), Program(0), UserData(userData) +{ +#ifdef _DEBUG + setDebugName("COGLES2MaterialRenderer"); +#endif + + switch (baseMaterial) + { + case EMT_TRANSPARENT_VERTEX_ALPHA: + case EMT_TRANSPARENT_ALPHA_CHANNEL: + case EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA: + case EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA: + Alpha = true; + break; + case EMT_TRANSPARENT_ADD_COLOR: + case EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR: + case EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR: + FixedBlending = true; + break; + case EMT_ONETEXTURE_BLEND: + Blending = true; + break; + default: + break; + } + + if (CallBack) + CallBack->grab(); + + init(outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram); +} + + +COGLES2MaterialRenderer::COGLES2MaterialRenderer(COGLES2Driver* driver, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, s32 userData) +: Driver(driver), CallBack(callback), Alpha(false), Blending(false), FixedBlending(false), Program(0), UserData(userData) +{ + switch (baseMaterial) + { + case EMT_TRANSPARENT_VERTEX_ALPHA: + case EMT_TRANSPARENT_ALPHA_CHANNEL: + case EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA: + case EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA: + Alpha = true; + break; + case EMT_TRANSPARENT_ADD_COLOR: + case EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR: + case EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR: + FixedBlending = true; + break; + case EMT_ONETEXTURE_BLEND: + Blending = true; + break; + default: + break; + } + + if (CallBack) + CallBack->grab(); +} + + +COGLES2MaterialRenderer::~COGLES2MaterialRenderer() +{ + if (CallBack) + CallBack->drop(); + + if (Program) + { + GLuint shaders[8]; + GLint count; + glGetAttachedShaders(Program, 8, &count, shaders); + + count=core::min_(count,8); + for (GLint i=0; iaddMaterialRenderer(this); +} + + +bool COGLES2MaterialRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) +{ + if (CallBack && Program) + CallBack->OnSetConstants(this, UserData); + + return true; +} + + +void COGLES2MaterialRenderer::OnSetMaterial(const video::SMaterial& material, + const video::SMaterial& lastMaterial, + bool resetAllRenderstates, + video::IMaterialRendererServices* services) +{ + COGLES2CacheHandler* cacheHandler = Driver->getCacheHandler(); + + cacheHandler->setProgram(Program); + + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (Alpha) + { + cacheHandler->setBlend(true); + cacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + else if (FixedBlending) + { + cacheHandler->setBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); + cacheHandler->setBlend(true); + } + else if (Blending) + { + E_BLEND_FACTOR srcRGBFact,dstRGBFact,srcAlphaFact,dstAlphaFact; + E_MODULATE_FUNC modulate; + u32 alphaSource; + unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulate, alphaSource, material.MaterialTypeParam); + + cacheHandler->setBlendFuncSeparate(Driver->getGLBlend(srcRGBFact), Driver->getGLBlend(dstRGBFact), + Driver->getGLBlend(srcAlphaFact), Driver->getGLBlend(dstAlphaFact)); + + cacheHandler->setBlend(true); + } + + if (CallBack) + CallBack->OnSetMaterial(material); +} + + +void COGLES2MaterialRenderer::OnUnsetMaterial() +{ +} + + +bool COGLES2MaterialRenderer::isTransparent() const +{ + return (Alpha || Blending || FixedBlending); +} + + +s32 COGLES2MaterialRenderer::getRenderCapability() const +{ + return 0; +} + + +bool COGLES2MaterialRenderer::createShader(GLenum shaderType, const char* shader) +{ + if (Program) + { + GLuint shaderHandle = glCreateShader(shaderType); + glShaderSource(shaderHandle, 1, &shader, NULL); + glCompileShader(shaderHandle); + + GLint status = 0; + + glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &status); + + if (status != GL_TRUE) + { + os::Printer::log("GLSL shader failed to compile", ELL_ERROR); + + GLint maxLength=0; + GLint length; + + glGetShaderiv(shaderHandle, GL_INFO_LOG_LENGTH, + &maxLength); + + if (maxLength) + { + GLchar *infoLog = new GLchar[maxLength]; + glGetShaderInfoLog(shaderHandle, maxLength, &length, infoLog); + os::Printer::log(reinterpret_cast(infoLog), ELL_ERROR); + delete [] infoLog; + } + + return false; + } + + glAttachShader(Program, shaderHandle); + } + + return true; +} + + +bool COGLES2MaterialRenderer::linkProgram() +{ + if (Program) + { + glLinkProgram(Program); + + GLint status = 0; + + glGetProgramiv(Program, GL_LINK_STATUS, &status); + + if (!status) + { + os::Printer::log("GLSL shader program failed to link", ELL_ERROR); + + GLint maxLength=0; + GLsizei length; + + glGetProgramiv(Program, GL_INFO_LOG_LENGTH, &maxLength); + + if (maxLength) + { + GLchar *infoLog = new GLchar[maxLength]; + glGetProgramInfoLog(Program, maxLength, &length, infoLog); + os::Printer::log(reinterpret_cast(infoLog), ELL_ERROR); + delete [] infoLog; + } + + return false; + } + + GLint num = 0; + + glGetProgramiv(Program, GL_ACTIVE_UNIFORMS, &num); + + if (num == 0) + return true; + + GLint maxlen = 0; + + glGetProgramiv(Program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxlen); + + if (maxlen == 0) + { + os::Printer::log("GLSL: failed to retrieve uniform information", ELL_ERROR); + return false; + } + + // seems that some implementations use an extra null terminator. + ++maxlen; + c8 *buf = new c8[maxlen]; + + UniformInfo.clear(); + UniformInfo.reallocate(num); + + for (GLint i=0; i < num; ++i) + { + SUniformInfo ui; + memset(buf, 0, maxlen); + + GLint size; + glGetActiveUniform(Program, i, maxlen, 0, &size, &ui.type, reinterpret_cast(buf)); + + core::stringc name = ""; + + // array support, workaround for some bugged drivers. + for (s32 i = 0; i < maxlen; ++i) + { + if (buf[i] == '[' || buf[i] == '\0') + break; + + name += buf[i]; + } + + ui.name = name; + ui.location = glGetUniformLocation(Program, buf); + + UniformInfo.push_back(ui); + } + + delete [] buf; + } + + return true; +} + + +void COGLES2MaterialRenderer::setBasicRenderStates(const SMaterial& material, + const SMaterial& lastMaterial, + bool resetAllRenderstates) +{ + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); +} + +s32 COGLES2MaterialRenderer::getVertexShaderConstantID(const c8* name) +{ + return getPixelShaderConstantID(name); +} + +s32 COGLES2MaterialRenderer::getPixelShaderConstantID(const c8* name) +{ + for (u32 i = 0; i < UniformInfo.size(); ++i) + { + if (UniformInfo[i].name == name) + return i; + } + + return -1; +} + +void COGLES2MaterialRenderer::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount) +{ + os::Printer::log("Cannot set constant, please use high level shader call instead.", ELL_WARNING); +} + +void COGLES2MaterialRenderer::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount) +{ + os::Printer::log("Cannot set constant, use high level shader call.", ELL_WARNING); +} + +bool COGLES2MaterialRenderer::setVertexShaderConstant(s32 index, const f32* floats, int count) +{ + return setPixelShaderConstant(index, floats, count); +} + +bool COGLES2MaterialRenderer::setVertexShaderConstant(s32 index, const s32* ints, int count) +{ + return setPixelShaderConstant(index, ints, count); +} + +bool COGLES2MaterialRenderer::setPixelShaderConstant(s32 index, const f32* floats, int count) +{ + if(index < 0 || UniformInfo[index].location < 0) + return false; + + bool status = true; + + switch (UniformInfo[index].type) + { + case GL_FLOAT: + glUniform1fv(UniformInfo[index].location, count, floats); + break; + case GL_FLOAT_VEC2: + glUniform2fv(UniformInfo[index].location, count/2, floats); + break; + case GL_FLOAT_VEC3: + glUniform3fv(UniformInfo[index].location, count/3, floats); + break; + case GL_FLOAT_VEC4: + glUniform4fv(UniformInfo[index].location, count/4, floats); + break; + case GL_FLOAT_MAT2: + glUniformMatrix2fv(UniformInfo[index].location, count/4, false, floats); + break; + case GL_FLOAT_MAT3: + glUniformMatrix3fv(UniformInfo[index].location, count/9, false, floats); + break; + case GL_FLOAT_MAT4: + glUniformMatrix4fv(UniformInfo[index].location, count/16, false, floats); + break; + case GL_SAMPLER_2D: + case GL_SAMPLER_CUBE: + { + if(floats) + { + const GLint id = (GLint)(*floats); + glUniform1iv(UniformInfo[index].location, 1, &id); + } + else + status = false; + } + break; + default: + status = false; + break; + } + + return status; +} + +bool COGLES2MaterialRenderer::setPixelShaderConstant(s32 index, const s32* ints, int count) +{ + if(index < 0 || UniformInfo[index].location < 0) + return false; + + bool status = true; + + switch (UniformInfo[index].type) + { + case GL_INT: + case GL_BOOL: + glUniform1iv(UniformInfo[index].location, count, ints); + break; + case GL_INT_VEC2: + case GL_BOOL_VEC2: + glUniform2iv(UniformInfo[index].location, count/2, ints); + break; + case GL_INT_VEC3: + case GL_BOOL_VEC3: + glUniform3iv(UniformInfo[index].location, count/3, ints); + break; + case GL_INT_VEC4: + case GL_BOOL_VEC4: + glUniform4iv(UniformInfo[index].location, count/4, ints); + break; + case GL_SAMPLER_2D: + case GL_SAMPLER_CUBE: + glUniform1iv(UniformInfo[index].location, 1, ints); + break; + default: + status = false; + break; + } + + return status; +} + +IVideoDriver* COGLES2MaterialRenderer::getVideoDriver() +{ + return Driver; +} + +} +} + + +#endif + diff --git a/source/Irrlicht/COGLES2MaterialRenderer.h b/source/Irrlicht/COGLES2MaterialRenderer.h new file mode 100644 index 00000000..5a2bb5bb --- /dev/null +++ b/source/Irrlicht/COGLES2MaterialRenderer.h @@ -0,0 +1,106 @@ +// Copyright (C) 2014 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OGLES2_SL_MATERIAL_RENDERER_H_INCLUDED__ +#define __C_OGLES2_SL_MATERIAL_RENDERER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "EMaterialTypes.h" +#include "IMaterialRenderer.h" +#include "IMaterialRendererServices.h" +#include "IGPUProgrammingServices.h" +#include "irrArray.h" +#include "irrString.h" + +#include "COGLES2Common.h" + +namespace irr +{ +namespace video +{ + +class COGLES2Driver; + +class COGLES2MaterialRenderer : public IMaterialRenderer, public IMaterialRendererServices +{ +public: + + COGLES2MaterialRenderer( + COGLES2Driver* driver, + s32& outMaterialTypeNr, + const c8* vertexShaderProgram = 0, + const c8* pixelShaderProgram = 0, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = EMT_SOLID, + s32 userData = 0); + + virtual ~COGLES2MaterialRenderer(); + + GLuint getProgram() const; + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services); + + virtual bool OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype); + + virtual void OnUnsetMaterial(); + + virtual bool isTransparent() const; + + virtual s32 getRenderCapability() const; + + virtual void setBasicRenderStates(const SMaterial& material, const SMaterial& lastMaterial, bool resetAllRenderstates); + + virtual s32 getVertexShaderConstantID(const c8* name); + virtual s32 getPixelShaderConstantID(const c8* name); + virtual void setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1); + virtual void setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1); + virtual bool setVertexShaderConstant(s32 index, const f32* floats, int count); + virtual bool setVertexShaderConstant(s32 index, const s32* ints, int count); + virtual bool setPixelShaderConstant(s32 index, const f32* floats, int count); + virtual bool setPixelShaderConstant(s32 index, const s32* ints, int count); + + virtual IVideoDriver* getVideoDriver(); + +protected: + + COGLES2MaterialRenderer(COGLES2Driver* driver, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = EMT_SOLID, + s32 userData = 0); + + void init(s32& outMaterialTypeNr, const c8* vertexShaderProgram, const c8* pixelShaderProgram, bool addMaterial = true); + + bool createShader(GLenum shaderType, const char* shader); + bool linkProgram(); + + COGLES2Driver* Driver; + IShaderConstantSetCallBack* CallBack; + + bool Alpha; + bool Blending; + bool FixedBlending; + + struct SUniformInfo + { + core::stringc name; + GLenum type; + GLint location; + }; + + GLuint Program; + core::array UniformInfo; + s32 UserData; +}; + + +} +} + +#endif +#endif + diff --git a/source/Irrlicht/COGLES2NormalMapRenderer.cpp b/source/Irrlicht/COGLES2NormalMapRenderer.cpp new file mode 100644 index 00000000..cca941c5 --- /dev/null +++ b/source/Irrlicht/COGLES2NormalMapRenderer.cpp @@ -0,0 +1,132 @@ +// Copyright (C) 2014 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "COGLES2NormalMapRenderer.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "IMaterialRendererServices.h" +#include "IGPUProgrammingServices.h" +#include "IShaderConstantSetCallBack.h" +#include "IVideoDriver.h" +#include "SLight.h" +#include "os.h" + +namespace irr +{ +namespace video +{ + +// EMT_NORMAL_MAP_SOLID + EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR + EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA + +COGLES2MaterialNormalMapCB::COGLES2MaterialNormalMapCB() : + FirstUpdate(true), WVPMatrixID(-1), WVMatrixID(-1), LightPositionID(-1), LightColorID(-1), TextureUnit0ID(-1), TextureUnit1ID(-1), + FogEnableID(-1), FogTypeID(-1), FogColorID(-1), FogStartID(-1), FogEndID(-1), FogDensityID(-1), TextureUnit0(0), TextureUnit1(1), + FogEnable(0), FogType(1), FogColor(SColorf(0.f, 0.f, 0.f, 1.f)), FogStart(0.f), FogEnd(0.f), FogDensity(0.f) +{ + for (u32 i = 0; i < 2; ++i) + { + LightPosition[i] = core::vector3df(0.f, 0.f, 0.f); + LightColor[i] = SColorf(0.f, 0.f, 0.f, 1.f); + } +} + +void COGLES2MaterialNormalMapCB::OnSetMaterial(const SMaterial& material) +{ + if (material.FogEnable) + FogEnable = 1; + else + FogEnable = 0; +} + +void COGLES2MaterialNormalMapCB::OnSetConstants(IMaterialRendererServices* services, s32 userData) +{ + IVideoDriver* driver = services->getVideoDriver(); + + if (FirstUpdate) + { + WVPMatrixID = services->getVertexShaderConstantID("uWVPMatrix"); + WVMatrixID = services->getVertexShaderConstantID("uWVMatrix"); + LightPositionID = services->getVertexShaderConstantID("uLightPosition"); + LightColorID = services->getVertexShaderConstantID("uLightColor"); + TextureUnit0ID = services->getVertexShaderConstantID("uTextureUnit0"); + TextureUnit1ID = services->getVertexShaderConstantID("uTextureUnit1"); + FogEnableID = services->getVertexShaderConstantID("uFogEnable"); + FogTypeID = services->getVertexShaderConstantID("uFogType"); + FogColorID = services->getVertexShaderConstantID("uFogColor"); + FogStartID = services->getVertexShaderConstantID("uFogStart"); + FogEndID = services->getVertexShaderConstantID("uFogEnd"); + FogDensityID = services->getVertexShaderConstantID("uFogDensity"); + + FirstUpdate = false; + } + + const core::matrix4 W = driver->getTransform(ETS_WORLD); + const core::matrix4 V = driver->getTransform(ETS_VIEW); + const core::matrix4 P = driver->getTransform(ETS_PROJECTION); + + core::matrix4 Matrix = P * V * W; + services->setPixelShaderConstant(WVPMatrixID, Matrix.pointer(), 16); + + Matrix = V * W; + services->setPixelShaderConstant(WVMatrixID, Matrix.pointer(), 16); + + Matrix = W; + Matrix.makeInverse(); + + const u32 LightCount = driver->getDynamicLightCount(); + + for (u32 i = 0; i < 2; ++i) + { + SLight CurrentLight; + + if (i < LightCount) + CurrentLight = driver->getDynamicLight(i); + else + { + CurrentLight.DiffuseColor.set(0.f, 0.f, 0.f); + CurrentLight.Radius = 1.f; + } + + CurrentLight.DiffuseColor.a = 1.f / (CurrentLight.Radius*CurrentLight.Radius); + + Matrix.transformVect(CurrentLight.Position); + + LightPosition[i] = CurrentLight.Position; + LightColor[i] = CurrentLight.DiffuseColor; + } + + services->setPixelShaderConstant(LightPositionID, reinterpret_cast(LightPosition), 6); + services->setPixelShaderConstant(LightColorID, reinterpret_cast(LightColor), 8); + + services->setPixelShaderConstant(TextureUnit0ID, &TextureUnit0, 1); + services->setPixelShaderConstant(TextureUnit1ID, &TextureUnit1, 1); + + services->setPixelShaderConstant(FogEnableID, &FogEnable, 1); + + if (FogEnable) + { + SColor TempColor(0); + E_FOG_TYPE TempType = EFT_FOG_LINEAR; + bool TempPerFragment = false; + bool TempRange = false; + + driver->getFog(TempColor, TempType, FogStart, FogEnd, FogDensity, TempPerFragment, TempRange); + + FogType = (s32)TempType; + FogColor = SColorf(TempColor); + + services->setPixelShaderConstant(FogTypeID, &FogType, 1); + services->setPixelShaderConstant(FogColorID, reinterpret_cast(&FogColor), 4); + services->setPixelShaderConstant(FogStartID, &FogStart, 1); + services->setPixelShaderConstant(FogEndID, &FogEnd, 1); + services->setPixelShaderConstant(FogDensityID, &FogDensity, 1); + } +} + +} +} + +#endif + diff --git a/source/Irrlicht/COGLES2NormalMapRenderer.h b/source/Irrlicht/COGLES2NormalMapRenderer.h new file mode 100644 index 00000000..36ae5c4f --- /dev/null +++ b/source/Irrlicht/COGLES2NormalMapRenderer.h @@ -0,0 +1,62 @@ +// Copyright (C) 2014 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OGLES2_NORMAL_MAP_RENDERER_H_INCLUDED__ +#define __C_OGLES2_NORMAL_MAP_RENDERER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "IMaterialRenderer.h" +#include "IShaderConstantSetCallBack.h" + +#include "COGLES2Common.h" + +namespace irr +{ +namespace video +{ + +class COGLES2MaterialNormalMapCB : public IShaderConstantSetCallBack +{ +public: + COGLES2MaterialNormalMapCB(); + + virtual void OnSetMaterial(const SMaterial& material); + virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData); + +protected: + bool FirstUpdate; + s32 WVPMatrixID; + s32 WVMatrixID; + s32 LightPositionID; + s32 LightColorID; + s32 TextureUnit0ID; + s32 TextureUnit1ID; + s32 FogEnableID; + s32 FogTypeID; + s32 FogColorID; + s32 FogStartID; + s32 FogEndID; + s32 FogDensityID; + + core::vector3df LightPosition[2]; + SColorf LightColor[2]; + s32 TextureUnit0; + s32 TextureUnit1; + s32 FogEnable; + s32 FogType; + SColorf FogColor; + f32 FogStart; + f32 FogEnd; + f32 FogDensity; +}; + +} +} + +#endif +#endif + diff --git a/source/Irrlicht/COGLES2ParallaxMapRenderer.cpp b/source/Irrlicht/COGLES2ParallaxMapRenderer.cpp new file mode 100644 index 00000000..9f1fa078 --- /dev/null +++ b/source/Irrlicht/COGLES2ParallaxMapRenderer.cpp @@ -0,0 +1,146 @@ +// Copyright (C) 2014 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "COGLES2ParallaxMapRenderer.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "IMaterialRendererServices.h" +#include "IGPUProgrammingServices.h" +#include "IShaderConstantSetCallBack.h" +#include "IVideoDriver.h" +#include "SLight.h" +#include "os.h" + +namespace irr +{ +namespace video +{ + +// EMT_PARALLAX_MAP_SOLID + EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR + EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA + +COGLES2MaterialParallaxMapCB::COGLES2MaterialParallaxMapCB() : + FirstUpdate(true), WVPMatrixID(-1), WVMatrixID(-1), EyePositionID(-1), LightPositionID(-1), LightColorID(-1), FactorID(-1), TextureUnit0ID(-1), TextureUnit1ID(-1), + FogEnableID(-1), FogTypeID(-1), FogColorID(-1), FogStartID(-1), FogEndID(-1), FogDensityID(-1), Factor(0.02f), TextureUnit0(0), TextureUnit1(1), + FogEnable(0), FogType(1), FogColor(SColorf(0.f, 0.f, 0.f, 1.f)), FogStart(0.f), FogEnd(0.f), FogDensity(0.f) +{ + for (u32 i = 0; i < 2; ++i) + { + LightPosition[i] = core::vector3df(0.f, 0.f, 0.f); + LightColor[i] = SColorf(0.f, 0.f, 0.f, 1.f); + } +} + +void COGLES2MaterialParallaxMapCB::OnSetMaterial(const SMaterial& material) +{ + if (!core::equals(material.MaterialTypeParam, 0.f)) + Factor = material.MaterialTypeParam; + else + Factor = 0.02f; + + if (material.FogEnable) + FogEnable = 1; + else + FogEnable = 0; +} + +void COGLES2MaterialParallaxMapCB::OnSetConstants(IMaterialRendererServices* services, s32 userData) +{ + IVideoDriver* driver = services->getVideoDriver(); + + if (FirstUpdate) + { + WVPMatrixID = services->getVertexShaderConstantID("uWVPMatrix"); + WVMatrixID = services->getVertexShaderConstantID("uWVMatrix"); + EyePositionID = services->getVertexShaderConstantID("uEyePosition"); + LightPositionID = services->getVertexShaderConstantID("uLightPosition"); + LightColorID = services->getVertexShaderConstantID("uLightColor"); + FactorID = services->getVertexShaderConstantID("uFactor"); + TextureUnit0ID = services->getVertexShaderConstantID("uTextureUnit0"); + TextureUnit1ID = services->getVertexShaderConstantID("uTextureUnit1"); + FogEnableID = services->getVertexShaderConstantID("uFogEnable"); + FogTypeID = services->getVertexShaderConstantID("uFogType"); + FogColorID = services->getVertexShaderConstantID("uFogColor"); + FogStartID = services->getVertexShaderConstantID("uFogStart"); + FogEndID = services->getVertexShaderConstantID("uFogEnd"); + FogDensityID = services->getVertexShaderConstantID("uFogDensity"); + + FirstUpdate = false; + } + + const core::matrix4 W = driver->getTransform(ETS_WORLD); + const core::matrix4 V = driver->getTransform(ETS_VIEW); + const core::matrix4 P = driver->getTransform(ETS_PROJECTION); + + core::matrix4 Matrix = P * V * W; + services->setPixelShaderConstant(WVPMatrixID, Matrix.pointer(), 16); + + Matrix = V * W; + services->setPixelShaderConstant(WVMatrixID, Matrix.pointer(), 16); + + core::vector3df EyePosition(0.0f, 0.0f, 0.0f); + + Matrix.makeInverse(); + Matrix.transformVect(EyePosition); + services->setPixelShaderConstant(EyePositionID, reinterpret_cast(&EyePosition), 3); + + Matrix = W; + Matrix.makeInverse(); + + const u32 LightCount = driver->getDynamicLightCount(); + + for (u32 i = 0; i < 2; ++i) + { + SLight CurrentLight; + + if (i < LightCount) + CurrentLight = driver->getDynamicLight(i); + else + { + CurrentLight.DiffuseColor.set(0.f, 0.f, 0.f); + CurrentLight.Radius = 1.f; + } + + CurrentLight.DiffuseColor.a = 1.f / (CurrentLight.Radius*CurrentLight.Radius); + + Matrix.transformVect(CurrentLight.Position); + + LightPosition[i] = CurrentLight.Position; + LightColor[i] = CurrentLight.DiffuseColor; + } + + services->setPixelShaderConstant(LightPositionID, reinterpret_cast(LightPosition), 6); + services->setPixelShaderConstant(LightColorID, reinterpret_cast(LightColor), 8); + + services->setPixelShaderConstant(FactorID, &Factor, 1); + services->setPixelShaderConstant(TextureUnit0ID, &TextureUnit0, 1); + services->setPixelShaderConstant(TextureUnit1ID, &TextureUnit1, 1); + + services->setPixelShaderConstant(FogEnableID, &FogEnable, 1); + + if (FogEnable) + { + SColor TempColor(0); + E_FOG_TYPE TempType = EFT_FOG_LINEAR; + bool TempPerFragment = false; + bool TempRange = false; + + driver->getFog(TempColor, TempType, FogStart, FogEnd, FogDensity, TempPerFragment, TempRange); + + FogType = (s32)TempType; + FogColor = SColorf(TempColor); + + services->setPixelShaderConstant(FogTypeID, &FogType, 1); + services->setPixelShaderConstant(FogColorID, reinterpret_cast(&FogColor), 4); + services->setPixelShaderConstant(FogStartID, &FogStart, 1); + services->setPixelShaderConstant(FogEndID, &FogEnd, 1); + services->setPixelShaderConstant(FogDensityID, &FogDensity, 1); + } +} + +} +} + +#endif + diff --git a/source/Irrlicht/COGLES2ParallaxMapRenderer.h b/source/Irrlicht/COGLES2ParallaxMapRenderer.h new file mode 100644 index 00000000..ea9c1dbc --- /dev/null +++ b/source/Irrlicht/COGLES2ParallaxMapRenderer.h @@ -0,0 +1,65 @@ +// Copyright (C) 2014 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OGLES2_PARALLAX_MAP_RENDERER_H_INCLUDED__ +#define __C_OGLES2_PARALLAX_MAP_RENDERER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "IMaterialRenderer.h" +#include "IShaderConstantSetCallBack.h" + +#include "COGLES2Common.h" + +namespace irr +{ +namespace video +{ + +class COGLES2MaterialParallaxMapCB : public IShaderConstantSetCallBack +{ +public: + COGLES2MaterialParallaxMapCB(); + + virtual void OnSetMaterial(const SMaterial& material); + virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData); + +protected: + bool FirstUpdate; + s32 WVPMatrixID; + s32 WVMatrixID; + s32 EyePositionID; + s32 LightPositionID; + s32 LightColorID; + s32 FactorID; + s32 TextureUnit0ID; + s32 TextureUnit1ID; + s32 FogEnableID; + s32 FogTypeID; + s32 FogColorID; + s32 FogStartID; + s32 FogEndID; + s32 FogDensityID; + + core::vector3df LightPosition[2]; + SColorf LightColor[2]; + f32 Factor; + s32 TextureUnit0; + s32 TextureUnit1; + s32 FogEnable; + s32 FogType; + SColorf FogColor; + f32 FogStart; + f32 FogEnd; + f32 FogDensity; +}; + +} +} + +#endif +#endif + diff --git a/source/Irrlicht/COGLES2Renderer2D.cpp b/source/Irrlicht/COGLES2Renderer2D.cpp new file mode 100644 index 00000000..b891d98f --- /dev/null +++ b/source/Irrlicht/COGLES2Renderer2D.cpp @@ -0,0 +1,87 @@ +// Copyright (C) 2014 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#include "COGLES2Renderer2D.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "IGPUProgrammingServices.h" +#include "os.h" + +#include "COGLES2Driver.h" + +#include "COpenGLCoreFeature.h" +#include "COpenGLCoreTexture.h" +#include "COpenGLCoreCacheHandler.h" + +namespace irr +{ +namespace video +{ + +COGLES2Renderer2D::COGLES2Renderer2D(const c8* vertexShaderProgram, const c8* pixelShaderProgram, COGLES2Driver* driver, bool withTexture) : + COGLES2MaterialRenderer(driver, 0, EMT_SOLID), + WithTexture(withTexture) +{ +#ifdef _DEBUG + setDebugName("COGLES2Renderer2D"); +#endif + + int Temp = 0; + + init(Temp, vertexShaderProgram, pixelShaderProgram, false); + + COGLES2CacheHandler* cacheHandler = Driver->getCacheHandler(); + + cacheHandler->setProgram(Program); + + // These states don't change later. + + ThicknessID = getPixelShaderConstantID("uThickness"); + if ( WithTexture ) + { + TextureUsageID = getPixelShaderConstantID("uTextureUsage"); + s32 TextureUnitID = getPixelShaderConstantID("uTextureUnit"); + + s32 TextureUnit = 0; + setPixelShaderConstant(TextureUnitID, &TextureUnit, 1); + + s32 TextureUsage = 0; + setPixelShaderConstant(TextureUsageID, &TextureUsage, 1); + } + + cacheHandler->setProgram(0); +} + +COGLES2Renderer2D::~COGLES2Renderer2D() +{ +} + +void COGLES2Renderer2D::OnSetMaterial(const video::SMaterial& material, + const video::SMaterial& lastMaterial, + bool resetAllRenderstates, + video::IMaterialRendererServices* services) +{ + Driver->getCacheHandler()->setProgram(Program); + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + f32 Thickness = (material.Thickness > 0.f) ? material.Thickness : 1.f; + setPixelShaderConstant(ThicknessID, &Thickness, 1); + + if ( WithTexture ) + { + s32 TextureUsage = material.TextureLayer[0].Texture ? 1 : 0; + setPixelShaderConstant(TextureUsageID, &TextureUsage, 1); + } +} + +bool COGLES2Renderer2D::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) +{ + return true; +} + +} +} + +#endif diff --git a/source/Irrlicht/COGLES2Renderer2D.h b/source/Irrlicht/COGLES2Renderer2D.h new file mode 100644 index 00000000..25217580 --- /dev/null +++ b/source/Irrlicht/COGLES2Renderer2D.h @@ -0,0 +1,42 @@ +// Copyright (C) 2014 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __C_OGLES2_RENDERER_2D_H_INCLUDED__ +#define __C_OGLES2_RENDERER_2D_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "COGLES2MaterialRenderer.h" + +namespace irr +{ +namespace video +{ + +class COGLES2Renderer2D : public COGLES2MaterialRenderer +{ +public: + COGLES2Renderer2D(const c8* vertexShaderProgram, const c8* pixelShaderProgram, COGLES2Driver* driver, bool withTexture); + ~COGLES2Renderer2D(); + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services); + + virtual bool OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype); + +protected: + bool WithTexture; + s32 ThicknessID; + s32 TextureUsageID; +}; + + +} +} + +#endif +#endif + diff --git a/source/Irrlicht/COGLESCommon.h b/source/Irrlicht/COGLESCommon.h new file mode 100644 index 00000000..c7988f7a --- /dev/null +++ b/source/Irrlicht/COGLESCommon.h @@ -0,0 +1,126 @@ +// Copyright (C) 2015 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OGLES_COMMON_H_INCLUDED__ +#define __C_OGLES_COMMON_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OGLES1_ + +#if defined(_IRR_COMPILE_WITH_IOS_DEVICE_) +#include +#include +#elif defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_) +#include +#include +#include +#else +#include +#include +typedef char GLchar; +#if defined(_IRR_OGLES1_USE_EXTPOINTER_) +#include "gles-ext.h" +#endif +#endif + +#ifndef GL_BGRA +#define GL_BGRA 0x80E1; +#endif + +// Blending definitions. + +#if defined(GL_OES_blend_subtract) +#define GL_FUNC_ADD GL_FUNC_ADD_OES +#else +#define GL_FUNC_ADD 0 +#endif + +// FBO definitions. + +#ifdef GL_OES_framebuffer_object +#define GL_NONE 0 // iOS has missing definition of GL_NONE_OES +#define GL_FRAMEBUFFER GL_FRAMEBUFFER_OES +#define GL_DEPTH_COMPONENT16 GL_DEPTH_COMPONENT16_OES +#define GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_OES +#define GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT_OES +#define GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT_OES +#define GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_OES +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 1 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 2 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES +#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES +#define GL_FRAMEBUFFER_UNSUPPORTED GL_FRAMEBUFFER_UNSUPPORTED_OES +#else +#define GL_NONE 0 +#define GL_FRAMEBUFFER 0 +#define GL_DEPTH_COMPONENT16 0 +#define GL_COLOR_ATTACHMENT0 0 +#define GL_DEPTH_ATTACHMENT 0 +#define GL_STENCIL_ATTACHMENT 0 +#define GL_FRAMEBUFFER_COMPLETE 0 +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 1 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 2 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 3 +#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS 4 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 5 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 6 +#define GL_FRAMEBUFFER_UNSUPPORTED 7 +#endif + +#define GL_DEPTH_COMPONENT 0x1902 + +// Texture definitions. + +#ifdef GL_OES_texture_cube_map +#define GL_TEXTURE_CUBE_MAP GL_TEXTURE_CUBE_MAP_OES +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES +#else +#define GL_TEXTURE_CUBE_MAP 0 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0 +#endif + +// to check if this header is in the current compile unit (different GL implementation used different "GLCommon" headers in Irrlicht +#define IRR_COMPILE_GLES_COMMON + +namespace irr +{ +namespace video +{ + + // Forward declarations. + + class COpenGLCoreFeature; + + template + class COpenGLCoreTexture; + + template + class COpenGLCoreRenderTarget; + + template + class COpenGLCoreCacheHandler; + + class COGLES1Driver; + typedef COpenGLCoreTexture COGLES1Texture; + typedef COpenGLCoreRenderTarget COGLES1RenderTarget; + typedef COpenGLCoreCacheHandler COGLES1CacheHandler; + +} +} + +#endif +#endif diff --git a/source/Irrlicht/COGLESCoreExtensionHandler.h b/source/Irrlicht/COGLESCoreExtensionHandler.h new file mode 100644 index 00000000..57f156d7 --- /dev/null +++ b/source/Irrlicht/COGLESCoreExtensionHandler.h @@ -0,0 +1,778 @@ +// Copyright (C) 2017 Michael Zeilfelder +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __E_OGLES_CORE_EXTENSION_HANDLER_H_INCLUDED__ +#define __E_OGLES_CORE_EXTENSION_HANDLER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +// Can be included from different ES versions +// (this is also the reason why this file is header-only as correct OGL ES headers have to be included first) +#if defined(_IRR_COMPILE_WITH_OGLES2_) || defined(_IRR_COMPILE_WITH_OGLES1_) + +#include "COpenGLCoreFeature.h" + +namespace irr +{ +namespace video +{ + + class COGLESCoreExtensionHandler + { + public: + // Enums used internally to check for ES extensions quickly. + // We buffer all extensions on start once in an array. + // All OpenGL ES versions share the same extensions (WebGL adds it's own extensions on top of ES2) + enum EOGLESFeatures + { + // If you update this enum also update the corresponding OGLESFeatureStrings string-array + // Last updated was up to (including) extension number 290 (GL_EXT_clip_control) + IRR_GLX_ARB_context_flush_control, // 191 + IRR_GL_AMD_compressed_3DC_texture, // 39 + IRR_GL_AMD_compressed_ATC_texture, // 40 + IRR_GL_AMD_performance_monitor, // 50 + IRR_GL_AMD_program_binary_Z400, // 48 + IRR_GL_ANDROID_extension_pack_es31a, // 187 + IRR_GL_ANGLE_depth_texture, // 138 + IRR_GL_ANGLE_framebuffer_blit, // 83 + IRR_GL_ANGLE_framebuffer_multisample, // 84 + IRR_GL_ANGLE_instanced_arrays, // 109 + IRR_GL_ANGLE_pack_reverse_row_order, // 110 + IRR_GL_ANGLE_program_binary, //139 + IRR_GL_ANGLE_texture_compression_dxt1, // 111 + IRR_GL_ANGLE_texture_compression_dxt3, // 111 + IRR_GL_ANGLE_texture_compression_dxt5, // 111 + IRR_GL_ANGLE_texture_usage, // 112 + IRR_GL_ANGLE_translated_shader_source, // 113 + IRR_GL_APPLE_clip_distance, // 193 + IRR_GL_APPLE_color_buffer_packed_float, // 194 + IRR_GL_APPLE_copy_texture_levels, // 123 + IRR_GL_APPLE_framebuffer_multisample, // 78 + IRR_GL_APPLE_rgb_422, // 76 + IRR_GL_APPLE_sync, // 124 + IRR_GL_APPLE_texture_2D_limited_npot, // 59 + IRR_GL_APPLE_texture_format_BGRA8888, // 79 + IRR_GL_APPLE_texture_max_level, // 80 + IRR_GL_APPLE_texture_packed_float, // 195 + IRR_ARB_texture_env_combine, //ogl, IMG simulator + IRR_ARB_texture_env_dot3, //ogl, IMG simulator + IRR_GL_ARM_mali_program_binary, // 120 + IRR_GL_ARM_mali_shader_binary, // 81 + IRR_GL_ARM_rgba8, // 82 + IRR_GL_ARM_shader_framebuffer_fetch, // 165 + IRR_GL_ARM_shader_framebuffer_fetch_depth_stencil, // 166 + IRR_GL_DMP_program_binary, // 192 + IRR_GL_DMP_shader_binary, // 88 + IRR_GL_EXT_EGL_image_array, // 278 + IRR_GL_EXT_YUV_target, // 222 + IRR_GL_EXT_base_instance, // 203 + IRR_GL_EXT_blend_func_extended, // 247 + IRR_GL_EXT_blend_minmax, // 65 + IRR_GL_EXT_buffer_storage, // 239 + IRR_GL_EXT_clear_texture, // 269 + IRR_GL_EXT_clip_control, // 290 + IRR_GL_EXT_clip_cull_distance, // 257 + IRR_GL_EXT_color_buffer_float, // 137 + IRR_GL_EXT_color_buffer_half_float, // 97 + IRR_GL_EXT_compressed_ETC1_RGB8_sub_texture, // 188 + IRR_GL_EXT_conservative_depth, // 268 + IRR_GL_EXT_copy_image, // 175 + IRR_GL_EXT_debug_label, // 98 + IRR_GL_EXT_debug_marker, // 99 + IRR_GL_EXT_discard_framebuffer, // 64 + IRR_GL_EXT_disjoint_timer_query, // 150 + IRR_GL_EXT_draw_buffers, // 151 + IRR_GL_EXT_draw_buffers_indexed, // 176 + IRR_GL_EXT_draw_elements_base_vertex, // 204 + IRR_GL_EXT_draw_instanced, // 157 + IRR_GL_EXT_draw_transform_feedback, // 272 + IRR_GL_EXT_external_buffer, // 284 + IRR_GL_EXT_float_blend, // 225 + IRR_GL_EXT_frag_depth, // 86 + IRR_GL_EXT_geometry_point_size, // 177 + IRR_GL_EXT_geometry_shader, // 177 + IRR_GL_EXT_gpu_shader5, // 178 + IRR_GL_EXT_instanced_arrays, // 156 + IRR_GL_EXT_map_buffer_range, // 121 + IRR_GL_EXT_memory_object, // 280 + IRR_GL_EXT_memory_object_fd, // 281 + IRR_GL_EXT_memory_object_win32, // 282 + IRR_GL_EXT_multi_draw_arrays, // 69 + IRR_GL_EXT_multi_draw_indirect, // 205 + IRR_GL_EXT_multisample_compatibility, // 248 + IRR_GL_EXT_multisampled_render_to_texture, // 106 + IRR_GL_EXT_multisampled_render_to_texture2, // 275 + IRR_GL_EXT_multiview_draw_buffers, // 125 + IRR_GL_EXT_occlusion_query_boolean, // 100 + IRR_GL_EXT_polygon_offset_clamp, // 252 + IRR_GL_EXT_post_depth_coverage, // 225 + IRR_GL_EXT_primitive_bounding_box, // 186 + IRR_GL_EXT_protected_textures, // 256 + IRR_GL_EXT_pvrtc_sRGB, // 155 + IRR_GL_EXT_raster_multisample, // 226 + IRR_GL_EXT_read_format_bgra, // 66 + IRR_GL_EXT_render_snorm, // 206 + IRR_GL_EXT_robustness, // 107 + IRR_GL_EXT_sRGB, // 105 + IRR_GL_EXT_sRGB_write_control, // 153 + IRR_GL_EXT_semaphore, // 280 + IRR_GL_EXT_semaphore_fd, // 281 + IRR_GL_EXT_semaphore_win32, // 282 + IRR_GL_EXT_separate_shader_objects, // 101 + IRR_GL_EXT_shader_framebuffer_fetch, // 122 + IRR_GL_EXT_shader_group_vote, // 254 + IRR_GL_EXT_shader_implicit_conversions, // 179 + IRR_GL_EXT_shader_integer_mix, // 161 + IRR_GL_EXT_shader_io_blocks, // 180 + IRR_GL_EXT_shader_non_constant_global_initializers, // 264 + IRR_GL_EXT_shader_pixel_local_storage, // 167 + IRR_GL_EXT_shader_pixel_local_storage2, // 253 + IRR_GL_EXT_shader_texture_lod, // 77 + IRR_GL_EXT_shadow_samplers, // 102 + IRR_GL_EXT_sparse_texture, // 240 + IRR_GL_EXT_sparse_texture2, // 259 + IRR_GL_EXT_tessellation_point_size, // 181 + IRR_GL_EXT_tessellation_shader, // 181 + IRR_GL_EXT_texture_border_clamp, // 182 + IRR_GL_EXT_texture_buffer, // 183 + IRR_GL_EXT_texture_compression_astc_decode_mode, // 276 + IRR_GL_EXT_texture_compression_astc_decode_mode_rgb9e5, // 276 + IRR_GL_EXT_texture_compression_bptc, // 287 + IRR_GL_EXT_texture_compression_dxt1, // 49 + IRR_GL_EXT_texture_compression_rgtc, // 286 + IRR_GL_EXT_texture_compression_s3tc, // 154 + IRR_GL_EXT_texture_compression_s3tc_srgb, // 289 + IRR_GL_EXT_texture_cube_map_array, // 184 + IRR_GL_EXT_texture_filter_anisotropic, // 41 + IRR_GL_EXT_texture_filter_minmax, // 227 + IRR_GL_EXT_texture_format_BGRA8888, // 51 + IRR_GL_EXT_texture_lod_bias, // 60 + IRR_GL_EXT_texture_norm16, // 207 + IRR_GL_EXT_texture_rg, // 103 + IRR_GL_EXT_texture_sRGB_R8, // 221 + IRR_GL_EXT_texture_sRGB_RG8, // 223 + IRR_GL_EXT_texture_sRGB_decode, // 152 + IRR_GL_EXT_texture_storage, // 108 + IRR_GL_EXT_texture_type_2_10_10_10_REV, // 42 + IRR_GL_EXT_texture_view, // 185 + IRR_GL_EXT_unpack_subimage, // 90 + IRR_GL_EXT_win32_keyed_mutex, // 283 + IRR_GL_EXT_window_rectangles, // 263 + IRR_GL_FJ_shader_binary_GCCSO, // 114 + IRR_GL_IMG_bindless_texture, // 270 + IRR_GL_IMG_framebuffer_downsample, // 255 + IRR_GL_IMG_multisampled_render_to_texture, // 74 + IRR_GL_IMG_program_binary, // 67 + IRR_GL_IMG_read_format, // 53 + IRR_GL_IMG_shader_binary, // 68 + IRR_GL_IMG_texture_compression_pvrtc, // 54 + IRR_GL_IMG_texture_compression_pvrtc2, // 140 + IRR_GL_IMG_texture_env_enhanced_fixed_function, // 58 + IRR_GL_IMG_texture_format_BGRA8888, // replaced by EXT version + IRR_GL_IMG_texture_filter_cubic, // 251 + IRR_GL_IMG_user_clip_plane, // 57, was clip_planes + IRR_GL_IMG_vertex_program, // non-standard + IRR_GL_INTEL_conservative_rasterization, // 265 + IRR_GL_INTEL_framebuffer_CMAA, // 246 + IRR_GL_INTEL_performance_query, // 164 + IRR_GL_KHR_blend_equation_advanced, // 168 + IRR_GL_KHR_blend_equation_advanced_coherent, // 168 + IRR_GL_KHR_context_flush_control, // 191 + IRR_GL_KHR_debug, // 118 + IRR_GL_KHR_no_error, // 243 + IRR_GL_KHR_parallel_shader_compile, // 288 + IRR_GL_KHR_robust_buffer_access_behavior, // 189 + IRR_GL_KHR_robustness, // 190 + IRR_GL_KHR_texture_compression_astc_hdr, // 117 + IRR_GL_KHR_texture_compression_astc_ldr, // 117 + IRR_GL_KHR_texture_compression_astc_sliced_3d, // 249 + IRR_GL_NVX_blend_equation_advanced_multi_draw_buffers, // 266 + IRR_GL_NV_3dvision_settings, // 129 + IRR_GL_NV_EGL_stream_consumer_external, // 104 + IRR_GL_NV_bgr, // 135 + IRR_GL_NV_bindless_texture, // 197 + IRR_GL_NV_blend_equation_advanced, // 163 + IRR_GL_NV_blend_equation_advanced_coherent, // 163 + IRR_GL_NV_blend_minmax_factor, // 285 + IRR_GL_NV_conditional_render, // 198 + IRR_GL_NV_conservative_raster, // 228 + IRR_GL_NV_conservative_raster_pre_snap_triangles, // 262 + IRR_GL_NV_copy_buffer, // 158 + IRR_GL_NV_coverage_sample, // 72 + IRR_GL_NV_depth_nonlinear, // 73 + IRR_GL_NV_draw_buffers, // 91 + IRR_GL_NV_draw_instanced, // 141 + IRR_GL_NV_draw_texture, // 126 + IRR_GL_NV_draw_vulkan_image, // 274 + IRR_GL_NV_explicit_attrib_location, // 159 + IRR_GL_NV_fbo_color_attachments, // 92 + IRR_GL_NV_fence, // 52 + IRR_GL_NV_fill_rectangle, // 232 + IRR_GL_NV_fragment_coverage_to_color, // 229 + IRR_GL_NV_fragment_shader_interlock, // 230 + IRR_GL_NV_framebuffer_blit, // 142 + IRR_GL_NV_framebuffer_mixed_samples, // 231 + IRR_GL_NV_framebuffer_multisample, // 143 + IRR_GL_NV_generate_mipmap_sRGB, // 144 + IRR_GL_NV_geometry_shader_passthrough, // 233 + IRR_GL_NV_gpu_shader5, // 260 + IRR_GL_NV_image_formats, // 200 + IRR_GL_NV_instanced_arrays, // 145 + IRR_GL_NV_internalformat_sample_query, // 196 + IRR_GL_NV_non_square_matrices, // 160 + IRR_GL_NV_pack_subimage, // 132 + IRR_GL_NV_packed_float, // 127 + IRR_GL_NV_path_rendering, // 199 + IRR_GL_NV_path_rendering_shared_edge, // 234 + IRR_GL_NV_pixel_buffer_object, // 134 + IRR_GL_NV_platform_binary, // 131 + IRR_GL_NV_polygon_mode, // 238 + IRR_GL_NV_read_buffer, // 93 + IRR_GL_NV_read_buffer_front, // part of 93 (non standard) + IRR_GL_NV_read_depth, // part of 94 (non standard) + IRR_GL_NV_read_depth_stencil, // 94 + IRR_GL_NV_read_stencil, // part of 94 (non standard) + IRR_GL_NV_sRGB_formats, // 148 + IRR_GL_NV_sample_locations, // 235 + IRR_GL_NV_sample_mask_override_coverage, // 236 + IRR_GL_NV_shader_atomic_fp16_vector, // 261 + IRR_GL_NV_shader_noperspective_interpolation, // 201 + IRR_GL_NV_shadow_samplers_array, // 146 + IRR_GL_NV_shadow_samplers_cube, // 147 + IRR_GL_NV_texture_array, // 133 + IRR_GL_NV_texture_barrier, // 271 + IRR_GL_NV_texture_border_clamp, // 149 + IRR_GL_NV_texture_compression_latc, // 130 + IRR_GL_NV_texture_compression_s3tc, // 128 + IRR_GL_NV_texture_compression_s3tc_update, // 95 + IRR_GL_NV_texture_npot_2D_mipmap, // 96 + IRR_GL_NV_viewport_array, // 202 + IRR_GL_NV_viewport_array2, // 237 + IRR_GL_NV_viewport_swizzle, // 258 + IRR_GL_OES_EGL_image, // 23 + IRR_GL_OES_EGL_image_external, // 87 + IRR_GL_OES_EGL_image_external_essl3, // 220 + IRR_GL_OES_EGL_sync, // 75 + IRR_GL_OES_blend_equation_separate, // 1 + IRR_GL_OES_blend_func_separate, // 2 + IRR_GL_OES_blend_subtract, // 3 + IRR_GL_OES_byte_coordinates, // 4 + IRR_GL_OES_compressed_ETC1_RGB8_texture, // 5 + IRR_GL_OES_compressed_paletted_texture, // 6 + IRR_GL_OES_copy_image, // 208 + IRR_GL_OES_depth24, // 24 + IRR_GL_OES_depth32, // 25 + IRR_GL_OES_depth_texture, // 43 + IRR_GL_OES_depth_texture_cube_map, // 136 + IRR_GL_OES_draw_buffers_indexed, // 209 + IRR_GL_OES_draw_elements_base_vertex, // 219 + IRR_GL_OES_draw_texture, // 7 + IRR_GL_OES_element_index_uint, // 26 + IRR_GL_OES_extended_matrix_palette, // 8 + IRR_GL_OES_fbo_render_mipmap, // 27 + IRR_GL_OES_fixed_point, // 9 + IRR_GL_OES_fragment_precision_high, // 28 + IRR_GL_OES_framebuffer_object, // 10 + IRR_GL_OES_geometry_shader, // 210 + IRR_GL_OES_get_program_binary, // 47 + IRR_GL_OES_gpu_shader5, // 211 + IRR_GL_OES_mapbuffer, // 29 + IRR_GL_OES_matrix_get, // 11 + IRR_GL_OES_matrix_palette, // 12 + IRR_GL_OES_packed_depth_stencil, // 44 + IRR_GL_OES_point_size_array, // 14 + IRR_GL_OES_point_sprite, // 15 + IRR_GL_OES_primitive_bounding_box, // 212 + IRR_GL_OES_query_matrix, // 16 + IRR_GL_OES_read_format, // 17 + IRR_GL_OES_required_internalformat, // 115 + IRR_GL_OES_rgb8_rgba8, // 30 + IRR_GL_OES_sample_shading, // 169 + IRR_GL_OES_sample_variables, // 170 + IRR_GL_OES_shader_image_atomic, // 171 + IRR_GL_OES_shader_io_blocks, // 213 + IRR_GL_OES_shader_multisample_interpolation, // 172 + IRR_GL_OES_single_precision, // 18 + IRR_GL_OES_standard_derivatives, // 45 + IRR_GL_OES_stencil1, // 31 + IRR_GL_OES_stencil4, // 32 + IRR_GL_OES_stencil8, // 33 + IRR_GL_OES_stencil_wrap, // 19 + IRR_GL_OES_surfaceless_context, // 116 + IRR_GL_OES_tessellation_shader, // 214 + IRR_GL_OES_texture_3D, // 34 + IRR_GL_OES_texture_border_clamp, // 215 + IRR_GL_OES_texture_buffer, // 216 + IRR_GL_OES_texture_compression_astc, // 162 + IRR_GL_OES_texture_cube_map, // 20 + IRR_GL_OES_texture_cube_map_array, // 217 + IRR_GL_OES_texture_env_crossbar, // 21 + IRR_GL_OES_texture_float, // 36 + IRR_GL_OES_texture_float_linear, // 35 + IRR_GL_OES_texture_half_float, // 36 + IRR_GL_OES_texture_half_float_linear, // 35 + IRR_GL_OES_texture_mirrored_repeat, // 22 + IRR_GL_OES_texture_npot, // 37 + IRR_GL_OES_texture_stencil8, // 173 + IRR_GL_OES_texture_storage_multisample_2d_array, // 174 + IRR_GL_OES_texture_view, // 218 + IRR_GL_OES_vertex_array_object, // 71 + IRR_GL_OES_vertex_half_float, // 38 + IRR_GL_OES_vertex_type_10_10_10_2, // 46 + IRR_GL_OES_viewport_array, // 267 + IRR_GL_OVR_multiview, // 241 + IRR_GL_OVR_multiview2, // 242 + IRR_GL_OVR_multiview_multisampled_render_to_texture, // 250 + IRR_GL_QCOM_alpha_test, // 89 + IRR_GL_QCOM_binning_control, // 119 + IRR_GL_QCOM_driver_control, // 55 + IRR_GL_QCOM_extended_get, // 62 + IRR_GL_QCOM_extended_get2, // 63 + IRR_GL_QCOM_framebuffer_foveated, // 273 + IRR_GL_QCOM_performance_monitor_global_mode, // 56 + IRR_GL_QCOM_shader_framebuffer_fetch_noncoherent, // 277 + IRR_GL_QCOM_tiled_rendering, // 70 + IRR_GL_QCOM_writeonly_rendering, // 61 + IRR_GL_SUN_multi_draw_arrays, // 69 + IRR_GL_VIV_shader_binary, // 85 + WGL_ARB_context_flush_control, // 191 + + IRR_OGLES_Feature_Count + }; + + COGLESCoreExtensionHandler() + : Version(0), MaxAnisotropy(1), MaxIndices(0xffff), + MaxTextureSize(1), MaxTextureLODBias(0.f), StencilBuffer(false) + { + for (u32 i = 0; i < IRR_OGLES_Feature_Count; ++i) + FeatureAvailable[i] = false; + + DimAliasedLine[0] = 1.f; + DimAliasedLine[1] = 1.f; + DimAliasedPoint[0] = 1.f; + DimAliasedPoint[1] = 1.f; + } + + virtual ~COGLESCoreExtensionHandler() {} + + const COpenGLCoreFeature& getFeature() const + { + return Feature; + } + + void dump() const + { + for (u32 i = 0; i < IRR_OGLES_Feature_Count; ++i) + os::Printer::log(getFeatureString(i), FeatureAvailable[i] ? " true" : " false"); + } + + bool queryGLESFeature(EOGLESFeatures feature) const + { + return FeatureAvailable[feature]; + } + + protected: + + const char* getFeatureString(size_t index) const + { + // Extension names from https://www.khronos.org/registry/OpenGL/index_es.php + // One for each EOGLESFeatures + static const char* const OGLESFeatureStrings[IRR_OGLES_Feature_Count] = + { + "GLX_ARB_context_flush_control", + "GL_AMD_compressed_3DC_texture", + "GL_AMD_compressed_ATC_texture", + "GL_AMD_performance_monitor", + "GL_AMD_program_binary_Z400", + "GL_ANDROID_extension_pack_es31a", + "GL_ANGLE_depth_texture", + "GL_ANGLE_framebuffer_blit", + "GL_ANGLE_framebuffer_multisample", + "GL_ANGLE_instanced_arrays", + "GL_ANGLE_pack_reverse_row_order", + "GL_ANGLE_program_binary", + "GL_ANGLE_texture_compression_dxt1", + "GL_ANGLE_texture_compression_dxt3", + "GL_ANGLE_texture_compression_dxt5", + "GL_ANGLE_texture_usage", + "GL_ANGLE_translated_shader_source", + "GL_APPLE_clip_distance", + "GL_APPLE_color_buffer_packed_float", + "GL_APPLE_copy_texture_levels", + "GL_APPLE_framebuffer_multisample", + "GL_APPLE_rgb_422", + "GL_APPLE_sync", + "GL_APPLE_texture_2D_limited_npot", + "GL_APPLE_texture_format_BGRA8888", + "GL_APPLE_texture_max_level", + "GL_APPLE_texture_packed_float", + "GL_ARB_texture_env_combine", + "GL_ARB_texture_env_dot3", + "GL_ARM_mali_program_binary", + "GL_ARM_mali_shader_binary", + "GL_ARM_rgba8", + "GL_ARM_shader_framebuffer_fetch", + "GL_ARM_shader_framebuffer_fetch_depth_stencil", + "GL_DMP_program_binary", + "GL_DMP_shader_binary", + "GL_EXT_EGL_image_array", + "GL_EXT_YUV_target", + "GL_EXT_base_instance", + "GL_EXT_blend_func_extended", + "GL_EXT_blend_minmax", + "GL_EXT_buffer_storage", + "GL_EXT_clear_texture", + "GL_EXT_clip_control", + "GL_EXT_clip_cull_distance", + "GL_EXT_color_buffer_float", + "GL_EXT_color_buffer_half_float", + "GL_EXT_compressed_ETC1_RGB8_sub_texture", + "GL_EXT_conservative_depth", + "GL_EXT_copy_image", + "GL_EXT_debug_label", + "GL_EXT_debug_marker", + "GL_EXT_discard_framebuffer", + "GL_EXT_disjoint_timer_query", + "GL_EXT_draw_buffers", + "GL_EXT_draw_buffers_indexed", + "GL_EXT_draw_elements_base_vertex", + "GL_EXT_draw_instanced", + "GL_EXT_draw_transform_feedback", + "GL_EXT_external_buffer", + "GL_EXT_float_blend", + "GL_EXT_frag_depth", + "GL_EXT_geometry_point_size", + "GL_EXT_geometry_shader", + "GL_EXT_gpu_shader5", + "GL_EXT_instanced_arrays", + "GL_EXT_map_buffer_range", + "GL_EXT_memory_object", + "GL_EXT_memory_object_fd", + "GL_EXT_memory_object_win32", + "GL_EXT_multi_draw_arrays", + "GL_EXT_multi_draw_indirect", + "GL_EXT_multisample_compatibility", + "GL_EXT_multisampled_render_to_texture", + "GL_EXT_multisampled_render_to_texture2", + "GL_EXT_multiview_draw_buffers", + "GL_EXT_occlusion_query_boolean", + "GL_EXT_polygon_offset_clamp", + "GL_EXT_post_depth_coverage", + "GL_EXT_primitive_bounding_box", + "GL_EXT_protected_textures", + "GL_EXT_pvrtc_sRGB", + "GL_EXT_raster_multisample", + "GL_EXT_read_format_bgra", + "GL_EXT_render_snorm", + "GL_EXT_robustness", + "GL_EXT_sRGB", + "GL_EXT_sRGB_write_control", + "GL_EXT_semaphore", + "GL_EXT_semaphore_fd", + "GL_EXT_semaphore_win32", + "GL_EXT_separate_shader_objects", + "GL_EXT_shader_framebuffer_fetch", + "GL_EXT_shader_group_vote", + "GL_EXT_shader_implicit_conversions", + "GL_EXT_shader_integer_mix", + "GL_EXT_shader_io_blocks", + "GL_EXT_shader_non_constant_global_initializers", + "GL_EXT_shader_pixel_local_storage", + "GL_EXT_shader_pixel_local_storage2", + "GL_EXT_shader_texture_lod", + "GL_EXT_shadow_samplers", + "GL_EXT_sparse_texture", + "GL_EXT_sparse_texture2", + "GL_EXT_tessellation_point_size", + "GL_EXT_tessellation_shader", + "GL_EXT_texture_border_clamp", + "GL_EXT_texture_buffer", + "GL_EXT_texture_compression_astc_decode_mode", + "GL_EXT_texture_compression_astc_decode_mode_rgb9e5", + "GL_EXT_texture_compression_bptc", + "GL_EXT_texture_compression_dxt1", + "GL_EXT_texture_compression_rgtc", + "GL_EXT_texture_compression_s3tc", + "GL_EXT_texture_compression_s3tc_srgb", + "GL_EXT_texture_cube_map_array", + "GL_EXT_texture_filter_anisotropic", + "GL_EXT_texture_filter_minmax", + "GL_EXT_texture_format_BGRA8888", + "GL_EXT_texture_lod_bias", + "GL_EXT_texture_norm16", + "GL_EXT_texture_rg", + "GL_EXT_texture_sRGB_R8", + "GL_EXT_texture_sRGB_RG8", + "GL_EXT_texture_sRGB_decode", + "GL_EXT_texture_storage", + "GL_EXT_texture_type_2_10_10_10_REV", + "GL_EXT_texture_view", + "GL_EXT_unpack_subimage", + "GL_EXT_win32_keyed_mutex", + "GL_EXT_window_rectangles", + "GL_FJ_shader_binary_GCCSO", + "GL_IMG_bindless_texture", + "GL_IMG_framebuffer_downsample", + "GL_IMG_multisampled_render_to_texture", + "GL_IMG_program_binary", + "GL_IMG_read_format", + "GL_IMG_shader_binary", + "GL_IMG_texture_compression_pvrtc", + "GL_IMG_texture_compression_pvrtc2", + "GL_IMG_texture_env_enhanced_fixed_function", + "GL_IMG_texture_format_BGRA8888", + "GL_IMG_texture_filter_cubic", + "GL_IMG_user_clip_plane", + "GL_IMG_vertex_program", + "GL_INTEL_conservative_rasterization", + "GL_INTEL_framebuffer_CMAA", + "GL_INTEL_performance_query", + "GL_KHR_blend_equation_advanced", + "GL_KHR_blend_equation_advanced_coherent", + "GL_KHR_context_flush_control", + "GL_KHR_debug", + "GL_KHR_no_error", + "GL_KHR_parallel_shader_compile", + "GL_KHR_robust_buffer_access_behavior", + "GL_KHR_robustness", + "GL_KHR_texture_compression_astc_hdr", + "GL_KHR_texture_compression_astc_ldr", + "GL_KHR_texture_compression_astc_sliced_3d", + "GL_NVX_blend_equation_advanced_multi_draw_buffers", + "GL_NV_3dvision_settings", + "GL_NV_EGL_stream_consumer_external", + "GL_NV_bgr", + "GL_NV_bindless_texture", + "GL_NV_blend_equation_advanced", + "GL_NV_blend_equation_advanced_coherent", + "GL_NV_blend_minmax_factor", + "GL_NV_conditional_render", + "GL_NV_conservative_raster", + "GL_NV_conservative_raster_pre_snap_triangles", + "GL_NV_copy_buffer", + "GL_NV_coverage_sample", + "GL_NV_depth_nonlinear", + "GL_NV_draw_buffers", + "GL_NV_draw_instanced", + "GL_NV_draw_texture", + "GL_NV_draw_vulkan_image", + "GL_NV_explicit_attrib_location", + "GL_NV_fbo_color_attachments", + "GL_NV_fence", + "GL_NV_fill_rectangle", + "GL_NV_fragment_coverage_to_color", + "GL_NV_fragment_shader_interlock", + "GL_NV_framebuffer_blit", + "GL_NV_framebuffer_mixed_samples", + "GL_NV_framebuffer_multisample", + "GL_NV_generate_mipmap_sRGB", + "GL_NV_geometry_shader_passthrough", + "GL_NV_gpu_shader5", + "GL_NV_image_formats", + "GL_NV_instanced_arrays", + "GL_NV_internalformat_sample_query", + "GL_NV_non_square_matrices", + "GL_NV_pack_subimage", + "GL_NV_packed_float", + "GL_NV_path_rendering", + "GL_NV_path_rendering_shared_edge", + "GL_NV_pixel_buffer_object", + "GL_NV_platform_binary", + "GL_NV_polygon_mode", + "GL_NV_read_buffer", + "GL_NV_read_buffer_front", + "GL_NV_read_depth", + "GL_NV_read_depth_stencil", + "GL_NV_read_stencil", + "GL_NV_sRGB_formats", + "GL_NV_sample_locations", + "GL_NV_sample_mask_override_coverage", + "GL_NV_shader_atomic_fp16_vector", + "GL_NV_shader_noperspective_interpolation", + "GL_NV_shadow_samplers_array", + "GL_NV_shadow_samplers_cube", + "GL_NV_texture_array", + "GL_NV_texture_barrier", + "GL_NV_texture_border_clamp", + "GL_NV_texture_compression_latc", + "GL_NV_texture_compression_s3tc", + "GL_NV_texture_compression_s3tc_update", + "GL_NV_texture_npot_2D_mipmap", + "GL_NV_viewport_array", + "GL_NV_viewport_array2", + "GL_NV_viewport_swizzle", + "GL_OES_EGL_image", + "GL_OES_EGL_image_external", + "GL_OES_EGL_image_external_essl3", + "GL_OES_EGL_sync", + "GL_OES_blend_equation_separate", + "GL_OES_blend_func_separate", + "GL_OES_blend_subtract", + "GL_OES_byte_coordinates", + "GL_OES_compressed_ETC1_RGB8_texture", + "GL_OES_compressed_paletted_texture", + "GL_OES_copy_image", + "GL_OES_depth24", + "GL_OES_depth32", + "GL_OES_depth_texture", + "GL_OES_depth_texture_cube_map", + "GL_OES_draw_buffers_indexed", + "GL_OES_draw_elements_base_vertex", + "GL_OES_draw_texture", + "GL_OES_element_index_uint", + "GL_OES_extended_matrix_palette", + "GL_OES_fbo_render_mipmap", + "GL_OES_fixed_point", + "GL_OES_fragment_precision_high", + "GL_OES_framebuffer_object", + "GL_OES_geometry_shader", + "GL_OES_get_program_binary", + "GL_OES_gpu_shader5", + "GL_OES_mapbuffer", + "GL_OES_matrix_get", + "GL_OES_matrix_palette", + "GL_OES_packed_depth_stencil", + "GL_OES_point_size_array", + "GL_OES_point_sprite", + "GL_OES_primitive_bounding_box", + "GL_OES_query_matrix", + "GL_OES_read_format", + "GL_OES_required_internalformat", + "GL_OES_rgb8_rgba8", + "GL_OES_sample_shading", + "GL_OES_sample_variables", + "GL_OES_shader_image_atomic", + "GL_OES_shader_io_blocks", + "GL_OES_shader_multisample_interpolation", + "GL_OES_single_precision", + "GL_OES_standard_derivatives", + "GL_OES_stencil1", + "GL_OES_stencil4", + "GL_OES_stencil8", + "GL_OES_stencil_wrap", + "GL_OES_surfaceless_context", + "GL_OES_tessellation_shader", + "GL_OES_texture_3D", + "GL_OES_texture_border_clamp", + "GL_OES_texture_buffer", + "GL_OES_texture_compression_astc", + "GL_OES_texture_cube_map", + "GL_OES_texture_cube_map_array", + "GL_OES_texture_env_crossbar", + "GL_OES_texture_float", + "GL_OES_texture_float_linear", + "GL_OES_texture_half_float", + "GL_OES_texture_half_float_linear", + "GL_OES_texture_mirrored_repeat", + "GL_OES_texture_npot", + "GL_OES_texture_stencil8", + "GL_OES_texture_storage_multisample_2d_array", + "GL_OES_texture_view", + "GL_OES_vertex_array_object", + "GL_OES_vertex_half_float", + "GL_OES_vertex_type_10_10_10_2", + "GL_OES_viewport_array", + "GL_OVR_multiview", + "GL_OVR_multiview2", + "GL_OVR_multiview_multisampled_render_to_texture", + "GL_QCOM_alpha_test", + "GL_QCOM_binning_control", + "GL_QCOM_driver_control", + "GL_QCOM_extended_get", + "GL_QCOM_extended_get2", + "GL_QCOM_framebuffer_foveated", + "GL_QCOM_performance_monitor_global_mode", + "GL_QCOM_shader_framebuffer_fetch_noncoherent", + "GL_QCOM_tiled_rendering", + "GL_QCOM_writeonly_rendering", + "GL_SUN_multi_draw_arrays", + "GL_VIV_shader_binary", + "WGL_ARB_context_flush_control" + }; + + return OGLESFeatureStrings[index]; + } + + + void getGLVersion() + { + Version = 0; + s32 multiplier = 100; + + core::stringc version(glGetString(GL_VERSION)); + + for (u32 i = 0; i < version.size(); ++i) + { + if (version[i] >= '0' && version[i] <= '9') + { + if (multiplier > 1) + { + Version += static_cast(core::floor32(atof(&(version[i]))) * multiplier); + multiplier /= 10; + } + else + { + break; + } + } + } + } + + void getGLExtensions() + { + core::stringc extensions = glGetString(GL_EXTENSIONS); + os::Printer::log(extensions.c_str()); + + // typo in the simulator (note the postfixed s) + if (extensions.find("GL_IMG_user_clip_planes")) + FeatureAvailable[IRR_GL_IMG_user_clip_plane] = true; + + const u32 size = extensions.size() + 1; + c8* str = new c8[size]; + strncpy(str, extensions.c_str(), extensions.size()); + str[extensions.size()] = ' '; + c8* p = str; + + for (u32 i=0; i windowSize(0, 0); + + if (!ContextManager) + return; + + ContextManager->grab(); + ContextManager->generateSurface(); + ContextManager->generateContext(); + ExposedData = ContextManager->getContext(); + ContextManager->activateContext(ExposedData, false); + + windowSize = params.WindowSize; + + genericDriverInit(windowSize, params.Stencilbuffer); +} + +COGLES1Driver::~COGLES1Driver() +{ + RequestedLights.clear(); + + deleteMaterialRenders(); + + CacheHandler->getTextureCache().clear(); + + removeAllRenderTargets(); + deleteAllTextures(); + removeAllOcclusionQueries(); + removeAllHardwareBuffers(); + + delete CacheHandler; + + if (ContextManager) + { + ContextManager->destroyContext(); + ContextManager->destroySurface(); + ContextManager->terminate(); + ContextManager->drop(); + } +} + +// ----------------------------------------------------------------------- +// METHODS +// ----------------------------------------------------------------------- + +bool COGLES1Driver::genericDriverInit(const core::dimension2d& screenSize, bool stencilBuffer) +{ + Name=glGetString(GL_VERSION); + printVersion(); + + // print renderer information + VendorName = glGetString(GL_VENDOR); + os::Printer::log(VendorName.c_str(), ELL_INFORMATION); + + // load extensions + initExtensions(); + + // reset cache handler + delete CacheHandler; + CacheHandler = new COGLES1CacheHandler(this); + + StencilBuffer = stencilBuffer; + + DriverAttributes->setAttribute("MaxTextures", (s32)Feature.MaxTextureUnits); + DriverAttributes->setAttribute("MaxSupportedTextures", (s32)Feature.MaxTextureUnits); + DriverAttributes->setAttribute("MaxAnisotropy", MaxAnisotropy); + DriverAttributes->setAttribute("MaxIndices", (s32)MaxIndices); + DriverAttributes->setAttribute("MaxTextureSize", (s32)MaxTextureSize); + DriverAttributes->setAttribute("MaxTextureLODBias", MaxTextureLODBias); + DriverAttributes->setAttribute("Version", Version); + DriverAttributes->setAttribute("AntiAlias", AntiAlias); + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + UserClipPlane.reallocate(MaxUserClipPlanes); + UserClipPlaneEnabled.reallocate(MaxUserClipPlanes); + + for (s32 i = 0; i < MaxUserClipPlanes; ++i) + { + UserClipPlane.push_back(core::plane3df()); + UserClipPlaneEnabled.push_back(false); + } + + for (s32 i = 0; i < ETS_COUNT; ++i) + setTransform(static_cast(i), core::IdentityMatrix); + + setAmbientLight(SColorf(0.0f, 0.0f, 0.0f, 0.0f)); + glClearDepthf(1.0f); + + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); + glHint(GL_GENERATE_MIPMAP_HINT, GL_FASTEST); + glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST); + glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST); + glDepthFunc(GL_LEQUAL); + glFrontFace(GL_CW); + glAlphaFunc(GL_GREATER, 0.f); + + // create material renderers + createMaterialRenderers(); + + // set the renderstates + setRenderStates3DMode(); + + // set fog mode + setFog(FogColor, FogType, FogStart, FogEnd, FogDensity, PixelFog, RangeFog); + + // create matrix for flipping textures + TextureFlipMatrix.buildTextureTransform(0.0f, core::vector2df(0, 0), core::vector2df(0, 1.0f), core::vector2df(1.0f, -1.0f)); + + // We need to reset once more at the beginning of the first rendering. + // This fixes problems with intermediate changes to the material during texture load. + ResetRenderStates = true; + + testGLError(__LINE__); + + return true; +} + + +void COGLES1Driver::createMaterialRenderers() +{ + // create OGLES1 material renderers + + addAndDropMaterialRenderer(new COGLES1MaterialRenderer_SOLID(this)); + addAndDropMaterialRenderer(new COGLES1MaterialRenderer_SOLID_2_LAYER(this)); + + // add the same renderer for all lightmap types + COGLES1MaterialRenderer_LIGHTMAP* lmr = new COGLES1MaterialRenderer_LIGHTMAP(this); + addMaterialRenderer(lmr); // for EMT_LIGHTMAP: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_ADD: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M2: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M4: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M2: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M4: + lmr->drop(); + + // add remaining material renderer + addAndDropMaterialRenderer(new COGLES1MaterialRenderer_DETAIL_MAP(this)); + addAndDropMaterialRenderer(new COGLES1MaterialRenderer_SPHERE_MAP(this)); + addAndDropMaterialRenderer(new COGLES1MaterialRenderer_REFLECTION_2_LAYER(this)); + addAndDropMaterialRenderer(new COGLES1MaterialRenderer_TRANSPARENT_ADD_COLOR(this)); + addAndDropMaterialRenderer(new COGLES1MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL(this)); + addAndDropMaterialRenderer(new COGLES1MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF(this)); + addAndDropMaterialRenderer(new COGLES1MaterialRenderer_TRANSPARENT_VERTEX_ALPHA(this)); + addAndDropMaterialRenderer(new COGLES1MaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER(this)); + + // add normal map renderers +// TODO ogl-es + addAndDropMaterialRenderer(new COGLES1MaterialRenderer_SOLID(this)); + addAndDropMaterialRenderer(new COGLES1MaterialRenderer_SOLID(this)); + addAndDropMaterialRenderer(new COGLES1MaterialRenderer_SOLID(this)); + + // add parallax map renderers + addAndDropMaterialRenderer(new COGLES1MaterialRenderer_SOLID(this)); + addAndDropMaterialRenderer(new COGLES1MaterialRenderer_SOLID(this)); + addAndDropMaterialRenderer(new COGLES1MaterialRenderer_SOLID(this)); + + // add basic 1 texture blending + addAndDropMaterialRenderer(new COGLES1MaterialRenderer_ONETEXTURE_BLEND(this)); +} + +bool COGLES1Driver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil, const SExposedVideoData& videoData, core::rect* sourceRect) +{ + IRR_PROFILE(CProfileScope p1(EPID_ES2_BEGIN_SCENE);) + + CNullDriver::beginScene(clearFlag, clearColor, clearDepth, clearStencil, videoData, sourceRect); + + if (ContextManager) + ContextManager->activateContext(videoData, true); + + clearBuffers(clearFlag, clearColor, clearDepth, clearStencil); + + return true; +} + +bool COGLES1Driver::endScene() +{ + IRR_PROFILE(CProfileScope p1(EPID_ES2_END_SCENE);) + + CNullDriver::endScene(); + + glFlush(); + + if (ContextManager) + return ContextManager->swapBuffers(); + + return false; +} + + +//! Returns the transformation set by setTransform +const core::matrix4& COGLES1Driver::getTransform(E_TRANSFORMATION_STATE state) const +{ + return Matrices[state]; +} + + +//! sets transformation +void COGLES1Driver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) +{ + Matrices[state] = mat; + Transformation3DChanged = true; + + switch(state) + { + case ETS_VIEW: + case ETS_WORLD: + { + // OGLES1 only has a model matrix, view and world is not existent. so lets fake these two. + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf((Matrices[ETS_VIEW] * Matrices[ETS_WORLD]).pointer()); + // we have to update the clip planes to the latest view matrix + for (u32 i=0; iMeshBuffer; + const void* vertices=mb->getVertices(); + const u32 vertexCount=mb->getVertexCount(); + const E_VERTEX_TYPE vType=mb->getVertexType(); + const u32 vertexSize = getVertexPitchFromType(vType); + + //buffer vertex data, and convert colours... + core::array buffer(vertexSize * vertexCount); + memcpy(buffer.pointer(), vertices, vertexSize * vertexCount); + + // in order to convert the colors into opengl format (RGBA) + switch (vType) + { + case EVT_STANDARD: + { + S3DVertex* pb = reinterpret_cast(buffer.pointer()); + const S3DVertex* po = static_cast(vertices); + for (u32 i=0; i(buffer.pointer()); + const S3DVertex2TCoords* po = static_cast(vertices); + for (u32 i=0; i(buffer.pointer()); + const S3DVertexTangents* po = static_cast(vertices); + for (u32 i=0; ivbo_verticesID) + { + glGenBuffers(1, &HWBuffer->vbo_verticesID); + if (!HWBuffer->vbo_verticesID) return false; + newBuffer=true; + } + else if (HWBuffer->vbo_verticesSize < vertexCount*vertexSize) + { + newBuffer=true; + } + + glBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID ); + + // copy data to graphics card + if (!newBuffer) + glBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * vertexSize, buffer.const_pointer()); + else + { + HWBuffer->vbo_verticesSize = vertexCount*vertexSize; + + if (HWBuffer->Mapped_Vertex==scene::EHM_STATIC) + glBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, buffer.const_pointer(), GL_STATIC_DRAW); + else + glBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, buffer.const_pointer(), GL_DYNAMIC_DRAW); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + + return (!testGLError(__LINE__)); +} + + +bool COGLES1Driver::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) +{ + if (!HWBuffer) + return false; + + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + + const void* indices=mb->getIndices(); + u32 indexCount= mb->getIndexCount(); + + GLenum indexSize; + switch (mb->getIndexType()) + { + case (EIT_16BIT): + { + indexSize=sizeof(u16); + break; + } + case (EIT_32BIT): + { + indexSize=sizeof(u32); + break; + } + default: + { + return false; + } + } + + + //get or create buffer + bool newBuffer=false; + if (!HWBuffer->vbo_indicesID) + { + glGenBuffers(1, &HWBuffer->vbo_indicesID); + if (!HWBuffer->vbo_indicesID) return false; + newBuffer=true; + } + else if (HWBuffer->vbo_indicesSize < indexCount*indexSize) + { + newBuffer=true; + } + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID); + + // copy data to graphics card + if (!newBuffer) + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexCount * indexSize, indices); + else + { + HWBuffer->vbo_indicesSize = indexCount*indexSize; + + if (HWBuffer->Mapped_Index==scene::EHM_STATIC) + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STATIC_DRAW); + else + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_DYNAMIC_DRAW); + } + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + return (!testGLError(__LINE__)); +} + + +//! updates hardware buffer if needed +bool COGLES1Driver::updateHardwareBuffer(SHWBufferLink *HWBuffer) +{ + if (!HWBuffer) + return false; + + if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER) + { + if (HWBuffer->ChangedID_Vertex != HWBuffer->MeshBuffer->getChangedID_Vertex() + || !static_cast(HWBuffer)->vbo_verticesID) + { + + HWBuffer->ChangedID_Vertex = HWBuffer->MeshBuffer->getChangedID_Vertex(); + + if (!updateVertexHardwareBuffer(static_cast(HWBuffer))) + return false; + } + } + + if (HWBuffer->Mapped_Index!=scene::EHM_NEVER) + { + if (HWBuffer->ChangedID_Index != HWBuffer->MeshBuffer->getChangedID_Index() + || !((SHWBufferLink_opengl*)HWBuffer)->vbo_indicesID) + { + + HWBuffer->ChangedID_Index = HWBuffer->MeshBuffer->getChangedID_Index(); + + if (!updateIndexHardwareBuffer(static_cast(HWBuffer))) + return false; + } + } + + return true; +} + + +//! Create hardware buffer from meshbuffer +COGLES1Driver::SHWBufferLink *COGLES1Driver::createHardwareBuffer(const scene::IMeshBuffer* mb) +{ + if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER)) + return 0; + + SHWBufferLink_opengl *HWBuffer=new SHWBufferLink_opengl(mb); + + //add to map + HWBufferMap.insert(HWBuffer->MeshBuffer, HWBuffer); + + HWBuffer->ChangedID_Vertex=HWBuffer->MeshBuffer->getChangedID_Vertex(); + HWBuffer->ChangedID_Index=HWBuffer->MeshBuffer->getChangedID_Index(); + HWBuffer->Mapped_Vertex=mb->getHardwareMappingHint_Vertex(); + HWBuffer->Mapped_Index=mb->getHardwareMappingHint_Index(); + HWBuffer->LastUsed=0; + HWBuffer->vbo_verticesID=0; + HWBuffer->vbo_indicesID=0; + HWBuffer->vbo_verticesSize=0; + HWBuffer->vbo_indicesSize=0; + + if (!updateHardwareBuffer(HWBuffer)) + { + deleteHardwareBuffer(HWBuffer); + return 0; + } + + return HWBuffer; +} + + +void COGLES1Driver::deleteHardwareBuffer(SHWBufferLink *_HWBuffer) +{ + if (!_HWBuffer) + return; + + SHWBufferLink_opengl *HWBuffer=static_cast(_HWBuffer); + if (HWBuffer->vbo_verticesID) + { + glDeleteBuffers(1, &HWBuffer->vbo_verticesID); + HWBuffer->vbo_verticesID=0; + } + if (HWBuffer->vbo_indicesID) + { + glDeleteBuffers(1, &HWBuffer->vbo_indicesID); + HWBuffer->vbo_indicesID=0; + } + + CNullDriver::deleteHardwareBuffer(_HWBuffer); +} + + +//! Draw hardware buffer +void COGLES1Driver::drawHardwareBuffer(SHWBufferLink *_HWBuffer) +{ + if (!_HWBuffer) + return; + + SHWBufferLink_opengl *HWBuffer=static_cast(_HWBuffer); + + updateHardwareBuffer(HWBuffer); //check if update is needed + + HWBuffer->LastUsed=0;//reset count + + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + const void *vertices=mb->getVertices(); + const void *indexList=mb->getIndices(); + + if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER) + { + glBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID); + vertices=0; + } + + if (HWBuffer->Mapped_Index!=scene::EHM_NEVER) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID); + indexList=0; + } + + + drawVertexPrimitiveList(vertices, mb->getVertexCount(), indexList, + mb->getPrimitiveCount(), mb->getVertexType(), + mb->getPrimitiveType(), mb->getIndexType()); + + if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER) + glBindBuffer(GL_ARRAY_BUFFER, 0); + + if (HWBuffer->Mapped_Index!=scene::EHM_NEVER) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + + +IRenderTarget* COGLES1Driver::addRenderTarget() +{ + COGLES1RenderTarget* renderTarget = new COGLES1RenderTarget(this); + RenderTargets.push_back(renderTarget); + + return renderTarget; +} + + +// small helper function to create vertex buffer object adress offsets +static inline u8* buffer_offset(const long offset) +{ + return ((u8*)0 + offset); +} + + +//! draws a vertex primitive list +void COGLES1Driver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) +{ + if (!checkPrimitiveCount(primitiveCount)) + return; + + setRenderStates3DMode(); + + drawVertexPrimitiveList2d3d(vertices, vertexCount, (const u16*)indexList, primitiveCount, vType, pType, iType); +} + + +void COGLES1Driver::drawVertexPrimitiveList2d3d(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType, bool threed) +{ + if (!primitiveCount || !vertexCount) + return; + + if (!threed && !checkPrimitiveCount(primitiveCount)) + return; + + CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType); + + if (vertices) + { + // convert colors to gl color format. + vertexCount *= 4; //reused as color component count + ColorBuffer.set_used(vertexCount); + u32 i; + + switch (vType) + { + case EVT_STANDARD: + { + const S3DVertex* p = static_cast(vertices); + for ( i=0; iColor.toOpenGLColor(&ColorBuffer[i]); + ++p; + } + } + break; + case EVT_2TCOORDS: + { + const S3DVertex2TCoords* p = static_cast(vertices); + for ( i=0; iColor.toOpenGLColor(&ColorBuffer[i]); + ++p; + } + } + break; + case EVT_TANGENTS: + { + const S3DVertexTangents* p = static_cast(vertices); + for ( i=0; iColor.toOpenGLColor(&ColorBuffer[i]); + ++p; + } + } + break; + } + } + + // draw everything + glClientActiveTexture(GL_TEXTURE0); + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES)) + glEnableClientState(GL_TEXTURE_COORD_ARRAY); +#ifdef GL_OES_point_size_array + else if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_point_size_array] && (Material.Thickness==0.0f)) + glEnableClientState(GL_POINT_SIZE_ARRAY_OES); +#endif + if (threed && (pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES)) + glEnableClientState(GL_NORMAL_ARRAY); + + if (vertices) + glColorPointer(4, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); + + switch (vType) + { + case EVT_STANDARD: + if (vertices) + { + if (threed) + glNormalPointer(GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].Normal); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); + glVertexPointer((threed ? 3 : 2), GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].Pos); + } + else + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertex), buffer_offset(12)); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(S3DVertex), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28)); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), 0); + } + + if (Feature.MaxTextureUnits > 0 && CacheHandler->getTextureCache().get(1)) + { + glClientActiveTexture(GL_TEXTURE0 + 1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); + else + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28)); + } + break; + case EVT_2TCOORDS: + if (vertices) + { + if (threed) + glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Normal); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords); + glVertexPointer((threed ? 3 : 2), GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Pos); + } + else + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(12)); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(28)); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(0)); + } + + if (Feature.MaxTextureUnits > 0) + { + glClientActiveTexture(GL_TEXTURE0 + 1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords2); + else + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(36)); + } + break; + case EVT_TANGENTS: + if (vertices) + { + if (threed) + glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Normal); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].TCoords); + glVertexPointer((threed ? 3 : 2), GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Pos); + } + else + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(12)); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(28)); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(0)); + } + + if (Feature.MaxTextureUnits > 0) + { + glClientActiveTexture(GL_TEXTURE0 + 1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Tangent); + else + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(36)); + + glClientActiveTexture(GL_TEXTURE0 + 2); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Binormal); + else + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(48)); + } + break; + } + + GLenum indexSize=0; + + switch (iType) + { + case (EIT_16BIT): + { + indexSize=GL_UNSIGNED_SHORT; + break; + } + case (EIT_32BIT): + { +#ifdef GL_OES_element_index_uint +#ifndef GL_UNSIGNED_INT +#define GL_UNSIGNED_INT 0x1405 +#endif + if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_element_index_uint]) + indexSize=GL_UNSIGNED_INT; + else +#endif + indexSize=GL_UNSIGNED_SHORT; + break; + } + } + + switch (pType) + { + case scene::EPT_POINTS: + case scene::EPT_POINT_SPRITES: + { +#ifdef GL_OES_point_sprite + if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_point_sprite]) + glEnable(GL_POINT_SPRITE_OES); +#endif + // if ==0 we use the point size array + if (Material.Thickness!=0.f) + { + float quadratic[] = {0.0f, 0.0f, 10.01f}; + glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, quadratic); + float maxParticleSize=1.0f; + glGetFloatv(GL_POINT_SIZE_MAX, &maxParticleSize); +// maxParticleSize=maxParticleSize 0) + { + if (vType == EVT_TANGENTS) + { + glClientActiveTexture(GL_TEXTURE0 + 2); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + if ((vType != EVT_STANDARD) || CacheHandler->getTextureCache().get(1)) + { + glClientActiveTexture(GL_TEXTURE0 + 1); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + glClientActiveTexture(GL_TEXTURE0); + } + +#ifdef GL_OES_point_size_array + if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_point_size_array] && (Material.Thickness==0.0f)) + glDisableClientState(GL_POINT_SIZE_ARRAY_OES); +#endif + + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +} + + +//! draws a 2d image, using a color and the alpha channel of the texture +void COGLES1Driver::draw2DImage(const video::ITexture* texture, + const core::position2d& pos, + const core::rect& sourceRect, + const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + if (!sourceRect.isValid()) + return; + + core::position2d targetPos(pos); + core::position2d sourcePos(sourceRect.UpperLeftCorner); + core::dimension2d sourceSize(sourceRect.getSize()); + if (clipRect) + { + if (targetPos.X < clipRect->UpperLeftCorner.X) + { + sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X; + if (sourceSize.Width <= 0) + return; + + sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X; + targetPos.X = clipRect->UpperLeftCorner.X; + } + + if (targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X; + if (sourceSize.Width <= 0) + return; + } + + if (targetPos.Y < clipRect->UpperLeftCorner.Y) + { + sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y; + if (sourceSize.Height <= 0) + return; + + sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y; + targetPos.Y = clipRect->UpperLeftCorner.Y; + } + + if (targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y; + if (sourceSize.Height <= 0) + return; + } + } + + // clip these coordinates + + if (targetPos.X<0) + { + sourceSize.Width += targetPos.X; + if (sourceSize.Width <= 0) + return; + + sourcePos.X -= targetPos.X; + targetPos.X = 0; + } + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width; + if (sourceSize.Width <= 0) + return; + } + + if (targetPos.Y<0) + { + sourceSize.Height += targetPos.Y; + if (sourceSize.Height <= 0) + return; + + sourcePos.Y -= targetPos.Y; + targetPos.Y = 0; + } + + if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height; + if (sourceSize.Height <= 0) + return; + } + + // ok, we've clipped everything. + // now draw it. + + // texcoords need to be flipped horizontally for RTTs + const bool isRTT = texture->isRenderTarget(); + 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( + sourcePos.X * invW, + (isRTT?(sourcePos.Y + sourceSize.Height):sourcePos.Y) * invH, + (sourcePos.X + sourceSize.Width) * invW, + (isRTT?sourcePos.Y:(sourcePos.Y + sourceSize.Height)) * invH); + + const core::rect poss(targetPos, sourceSize); + + if (!CacheHandler->getTextureCache().set(0, texture)) + return; + + setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); + + u16 indices[] = {0,1,2,3}; + S3DVertex vertices[4]; + vertices[0] = S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.UpperLeftCorner.Y, 0, 0,0,1, color, tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + vertices[1] = S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.UpperLeftCorner.Y, 0, 0,0,1, color, tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + vertices[2] = S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.LowerRightCorner.Y, 0, 0,0,1, color, tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + vertices[3] = S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.LowerRightCorner.Y, 0, 0,0,1, color, tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + drawVertexPrimitiveList2d3d(vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, EIT_16BIT, false); +} + + +//! The same, but with a four element array of colors, one for each vertex +void COGLES1Driver::draw2DImage(const video::ITexture* texture, const core::rect& destRect, + const core::rect& sourceRect, const core::rect* clipRect, + const video::SColor* const colors, bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + // texcoords need to be flipped horizontally for RTTs + const bool isRTT = texture->isRenderTarget(); + const core::dimension2du& 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( + sourceRect.UpperLeftCorner.X * invW, + (isRTT?sourceRect.LowerRightCorner.Y:sourceRect.UpperLeftCorner.Y) * invH, + sourceRect.LowerRightCorner.X * invW, + (isRTT?sourceRect.UpperLeftCorner.Y:sourceRect.LowerRightCorner.Y) *invH); + + const video::SColor temp[4] = + { + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF + }; + + const video::SColor* const useColor = colors ? colors : temp; + + if (!CacheHandler->getTextureCache().set(0, texture)) + return; + + setRenderStates2DMode(useColor[0].getAlpha()<255 || useColor[1].getAlpha()<255 || + useColor[2].getAlpha()<255 || useColor[3].getAlpha()<255, + true, useAlphaChannelOfTexture); + + if (clipRect) + { + if (!clipRect->isValid()) + return; + + glEnable(GL_SCISSOR_TEST); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height-clipRect->LowerRightCorner.Y, + clipRect->getWidth(), clipRect->getHeight()); + } + + u16 indices[] = {0,1,2,3}; + S3DVertex vertices[4]; + vertices[0] = S3DVertex((f32)destRect.UpperLeftCorner.X, (f32)destRect.UpperLeftCorner.Y, 0, 0,0,1, useColor[0], tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + vertices[1] = S3DVertex((f32)destRect.LowerRightCorner.X, (f32)destRect.UpperLeftCorner.Y, 0, 0,0,1, useColor[3], tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + vertices[2] = S3DVertex((f32)destRect.LowerRightCorner.X, (f32)destRect.LowerRightCorner.Y, 0, 0,0,1, useColor[2], tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + vertices[3] = S3DVertex((f32)destRect.UpperLeftCorner.X, (f32)destRect.LowerRightCorner.Y, 0, 0,0,1, useColor[1], tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + drawVertexPrimitiveList2d3d(vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, EIT_16BIT, false); + + if (clipRect) + glDisable(GL_SCISSOR_TEST); +} + +void COGLES1Driver::draw2DImage(const video::ITexture* texture, u32 layer, bool flip) +{ + if (!texture || !CacheHandler->getTextureCache().set(0, texture)) + return; + + setRenderStates2DMode(false, true, true); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + Transformation3DChanged = true; + + u16 indices[] = { 0,1,2,3 }; + S3DVertex vertices[4]; + + vertices[0].Pos = core::vector3df(-1.f, 1.f, 0.f); + vertices[1].Pos = core::vector3df(1.f, 1.f, 0.f); + vertices[2].Pos = core::vector3df(1.f, -1.f, 0.f); + vertices[3].Pos = core::vector3df(-1.f, -1.f, 0.f); + + f32 modificator = (flip) ? 1.f : 0.f; + + vertices[0].TCoords = core::vector2df(0.f, 0.f + modificator); + vertices[1].TCoords = core::vector2df(1.f, 0.f + modificator); + vertices[2].TCoords = core::vector2df(1.f, 1.f - modificator); + vertices[3].TCoords = core::vector2df(0.f, 1.f - modificator); + + vertices[0].Color = 0xFFFFFFFF; + vertices[1].Color = 0xFFFFFFFF; + vertices[2].Color = 0xFFFFFFFF; + vertices[3].Color = 0xFFFFFFFF; + + drawVertexPrimitiveList2d3d(vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, EIT_16BIT, false); +} + + +//! draws a set of 2d images, using a color and the alpha channel +void COGLES1Driver::draw2DImageBatch(const video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, s32 kerningWidth, + const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + if (!CacheHandler->getTextureCache().set(0, texture)) + return; + + setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); + + if (clipRect) + { + if (!clipRect->isValid()) + return; + + glEnable(GL_SCISSOR_TEST); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height-clipRect->LowerRightCorner.Y, + clipRect->getWidth(),clipRect->getHeight()); + } + + const core::dimension2du& ss = texture->getOriginalSize(); + core::position2d targetPos(pos); + // texcoords need to be flipped horizontally for RTTs + const bool isRTT = texture->isRenderTarget(); + const f32 invW = 1.f / static_cast(ss.Width); + const f32 invH = 1.f / static_cast(ss.Height); + + core::array vertices; + core::array quadIndices; + vertices.reallocate(indices.size()*4); + quadIndices.reallocate(indices.size()*6); + for (u32 i=0; i tcoords( + sourceRects[currentIndex].UpperLeftCorner.X * invW, + (isRTT?sourceRects[currentIndex].LowerRightCorner.Y:sourceRects[currentIndex].UpperLeftCorner.Y) * invH, + sourceRects[currentIndex].LowerRightCorner.X * invW, + (isRTT?sourceRects[currentIndex].UpperLeftCorner.Y:sourceRects[currentIndex].LowerRightCorner.Y) * invH); + + const core::rect poss(targetPos, sourceRects[currentIndex].getSize()); + + const u32 vstart = vertices.size(); + + vertices.push_back(S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.UpperLeftCorner.Y, 0, 0,0,1, color, tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y)); + vertices.push_back(S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.UpperLeftCorner.Y, 0, 0,0,1, color, tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y)); + vertices.push_back(S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.LowerRightCorner.Y, 0, 0,0,1, color, tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y)); + vertices.push_back(S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.LowerRightCorner.Y, 0, 0,0,1, color, tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y)); + + quadIndices.push_back(vstart); + quadIndices.push_back(vstart+1); + quadIndices.push_back(vstart+2); + quadIndices.push_back(vstart); + quadIndices.push_back(vstart+2); + quadIndices.push_back(vstart+3); + + targetPos.X += sourceRects[currentIndex].getWidth(); + } + if (vertices.size()) + drawVertexPrimitiveList2d3d(vertices.pointer(), vertices.size(), + quadIndices.pointer(), vertices.size()/2, + video::EVT_STANDARD, scene::EPT_TRIANGLES, + EIT_16BIT, false); + if (clipRect) + glDisable(GL_SCISSOR_TEST); +} + + +//! draws a set of 2d images, using a color and the alpha channel of the texture if desired. +void COGLES1Driver::draw2DImageBatch(const video::ITexture* texture, + const core::array >& positions, + const core::array >& sourceRects, + const core::rect* clipRect, + SColor color, + bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + const u32 drawCount = core::min_(positions.size(), sourceRects.size()); + if (!drawCount) + return; + + const core::dimension2d& ss = texture->getOriginalSize(); + if (!ss.Width || !ss.Height) + return; + const f32 invW = 1.f / static_cast(ss.Width); + const f32 invH = 1.f / static_cast(ss.Height); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + if (!CacheHandler->getTextureCache().set(0, texture)) + return; + + setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); + + core::array vertices; + core::array quadIndices; + vertices.reallocate(drawCount*4); + quadIndices.reallocate(drawCount*6); + + for (u32 i=0; i targetPos(positions[i]); + core::position2d sourcePos(sourceRects[i].UpperLeftCorner); + // This needs to be signed as it may go negative. + core::dimension2d sourceSize(sourceRects[i].getSize()); + if (clipRect) + { + if (targetPos.X < clipRect->UpperLeftCorner.X) + { + sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X; + if (sourceSize.Width <= 0) + continue; + + sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X; + targetPos.X = clipRect->UpperLeftCorner.X; + } + + if (targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X; + if (sourceSize.Width <= 0) + continue; + } + + if (targetPos.Y < clipRect->UpperLeftCorner.Y) + { + sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y; + if (sourceSize.Height <= 0) + continue; + + sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y; + targetPos.Y = clipRect->UpperLeftCorner.Y; + } + + if (targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y; + if (sourceSize.Height <= 0) + continue; + } + } + + // clip these coordinates + + if (targetPos.X<0) + { + sourceSize.Width += targetPos.X; + if (sourceSize.Width <= 0) + continue; + + sourcePos.X -= targetPos.X; + targetPos.X = 0; + } + + if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width; + if (sourceSize.Width <= 0) + continue; + } + + if (targetPos.Y<0) + { + sourceSize.Height += targetPos.Y; + if (sourceSize.Height <= 0) + continue; + + sourcePos.Y -= targetPos.Y; + targetPos.Y = 0; + } + + if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height; + if (sourceSize.Height <= 0) + continue; + } + + // ok, we've clipped everything. + + const core::rect tcoords( + sourcePos.X * invW, + sourcePos.Y * invH, + (sourcePos.X + sourceSize.Width) * invW, + (sourcePos.Y + sourceSize.Height) * invH); + + const core::rect poss(targetPos, sourceSize); + + const u32 vstart = vertices.size(); + + vertices.push_back(S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.UpperLeftCorner.Y, 0, 0,0,1, color, tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y)); + vertices.push_back(S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.UpperLeftCorner.Y, 0, 0,0,1, color, tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y)); + vertices.push_back(S3DVertex((f32)poss.LowerRightCorner.X, (f32)poss.LowerRightCorner.Y, 0, 0,0,1, color, tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y)); + vertices.push_back(S3DVertex((f32)poss.UpperLeftCorner.X, (f32)poss.LowerRightCorner.Y, 0, 0,0,1, color, tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y)); + + quadIndices.push_back(vstart); + quadIndices.push_back(vstart+1); + quadIndices.push_back(vstart+2); + quadIndices.push_back(vstart); + quadIndices.push_back(vstart+2); + quadIndices.push_back(vstart+3); + } + if (vertices.size()) + drawVertexPrimitiveList2d3d(vertices.pointer(), vertices.size(), + quadIndices.pointer(), vertices.size()/2, + video::EVT_STANDARD, scene::EPT_TRIANGLES, + EIT_16BIT, false); +} + + +//! draw a 2d rectangle +void COGLES1Driver::draw2DRectangle(SColor color, const core::rect& position, + const core::rect* clip) +{ + setRenderStates2DMode(color.getAlpha() < 255, false, false); + + core::rect pos = position; + + if (clip) + pos.clipAgainst(*clip); + + if (!pos.isValid()) + return; + + u16 indices[] = {0,1,2,3}; + S3DVertex vertices[4]; + vertices[0] = S3DVertex((f32)pos.UpperLeftCorner.X, (f32)pos.UpperLeftCorner.Y, 0, 0,0,1, color, 0,0); + vertices[1] = S3DVertex((f32)pos.LowerRightCorner.X, (f32)pos.UpperLeftCorner.Y, 0, 0,0,1, color, 0,0); + vertices[2] = S3DVertex((f32)pos.LowerRightCorner.X, (f32)pos.LowerRightCorner.Y, 0, 0,0,1, color, 0,0); + vertices[3] = S3DVertex((f32)pos.UpperLeftCorner.X, (f32)pos.LowerRightCorner.Y, 0, 0,0,1, color, 0,0); + drawVertexPrimitiveList2d3d(vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, EIT_16BIT, false); +} + + +//! draw an 2d rectangle +void COGLES1Driver::draw2DRectangle(const core::rect& position, + SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, + const core::rect* clip) +{ + core::rect pos = position; + + if (clip) + pos.clipAgainst(*clip); + + if (!pos.isValid()) + return; + + setRenderStates2DMode(colorLeftUp.getAlpha() < 255 || + colorRightUp.getAlpha() < 255 || + colorLeftDown.getAlpha() < 255 || + colorRightDown.getAlpha() < 255, false, false); + + u16 indices[] = {0,1,2,3}; + S3DVertex vertices[4]; + vertices[0] = S3DVertex((f32)pos.UpperLeftCorner.X, (f32)pos.UpperLeftCorner.Y, 0, 0,0,1, colorLeftUp, 0,0); + vertices[1] = S3DVertex((f32)pos.LowerRightCorner.X, (f32)pos.UpperLeftCorner.Y, 0, 0,0,1, colorRightUp, 0,0); + vertices[2] = S3DVertex((f32)pos.LowerRightCorner.X, (f32)pos.LowerRightCorner.Y, 0, 0,0,1, colorRightDown, 0,0); + vertices[3] = S3DVertex((f32)pos.UpperLeftCorner.X, (f32)pos.LowerRightCorner.Y, 0, 0,0,1, colorLeftDown, 0,0); + drawVertexPrimitiveList2d3d(vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, EIT_16BIT, false); +} + + +//! Draws a 2d line. +void COGLES1Driver::draw2DLine(const core::position2d& start, + const core::position2d& end, + SColor color) +{ + setRenderStates2DMode(color.getAlpha() < 255, false, false); + + u16 indices[] = {0,1}; + S3DVertex vertices[2]; + vertices[0] = S3DVertex((f32)start.X, (f32)start.Y, 0, 0,0,1, color, 0,0); + vertices[1] = S3DVertex((f32)end.X, (f32)end.Y, 0, 0,0,1, color, 1,1); + drawVertexPrimitiveList2d3d(vertices, 2, indices, 1, video::EVT_STANDARD, scene::EPT_LINES, EIT_16BIT, false); +} + + +//! Draws a pixel +void COGLES1Driver::drawPixel(u32 x, u32 y, const SColor &color) +{ + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + if (x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height) + return; + + setRenderStates2DMode(color.getAlpha() < 255, false, false); + + u16 indices[] = {0}; + S3DVertex vertices[1]; + vertices[0] = S3DVertex((f32)x, (f32)y, 0, 0, 0, 1, color, 0, 0); + drawVertexPrimitiveList2d3d(vertices, 1, indices, 1, video::EVT_STANDARD, scene::EPT_POINTS, EIT_16BIT, false); +} + + +//! creates a matrix in supplied GLfloat array to pass to OGLES1 +inline void COGLES1Driver::getGLMatrix(GLfloat gl_matrix[16], const core::matrix4& m) +{ + memcpy(gl_matrix, m.pointer(), 16 * sizeof(f32)); +} + + +//! creates a opengltexturematrix from a D3D style texture matrix +inline void COGLES1Driver::getGLTextureMatrix(GLfloat *o, const core::matrix4& m) +{ + o[0] = m[0]; + o[1] = m[1]; + o[2] = 0.f; + o[3] = 0.f; + + o[4] = m[4]; + o[5] = m[5]; + o[6] = 0.f; + o[7] = 0.f; + + o[8] = 0.f; + o[9] = 0.f; + o[10] = 1.f; + o[11] = 0.f; + + o[12] = m[8]; + o[13] = m[9]; + o[14] = 0.f; + o[15] = 1.f; +} + +ITexture* COGLES1Driver::createDeviceDependentTexture(const io::path& name, IImage* image) +{ + core::array imageArray(1); + imageArray.push_back(image); + + COGLES1Texture* texture = new COGLES1Texture(name, imageArray, ETT_2D, this); + + return texture; +} + +ITexture* COGLES1Driver::createDeviceDependentTextureCubemap(const io::path& name, const core::array& image) +{ + COGLES1Texture* texture = new COGLES1Texture(name, image, ETT_CUBEMAP, this); + + return texture; +} + +//! Sets a material. All 3d drawing functions draw geometry now using this material. +void COGLES1Driver::setMaterial(const SMaterial& material) +{ + Material = material; + OverrideMaterial.apply(Material); + + for (u32 i = 0; i < Feature.MaxTextureUnits; ++i) + setTransform((E_TRANSFORMATION_STATE)(ETS_TEXTURE_0 + i), material.getTextureMatrix(i)); +} + + +//! prints error if an error happened. +bool COGLES1Driver::testGLError(int code) +{ +#ifdef _DEBUG + GLenum g = glGetError(); + switch(g) + { + case GL_NO_ERROR: + return false; + case GL_INVALID_ENUM: + os::Printer::log("GL_INVALID_ENUM", core::stringc(code).c_str(), ELL_ERROR); break; + case GL_INVALID_VALUE: + os::Printer::log("GL_INVALID_VALUE", core::stringc(code).c_str(), ELL_ERROR); break; + case GL_INVALID_OPERATION: + os::Printer::log("GL_INVALID_OPERATION", core::stringc(code).c_str(), ELL_ERROR); break; + case GL_STACK_OVERFLOW: + os::Printer::log("GL_STACK_OVERFLOW", core::stringc(code).c_str(), ELL_ERROR); break; + case GL_STACK_UNDERFLOW: + os::Printer::log("GL_STACK_UNDERFLOW", core::stringc(code).c_str(), ELL_ERROR); break; + case GL_OUT_OF_MEMORY: + os::Printer::log("GL_OUT_OF_MEMORY", core::stringc(code).c_str(), ELL_ERROR); break; + }; +// _IRR_DEBUG_BREAK_IF(true); + return true; +#else + return false; +#endif +} + + +//! sets the needed renderstates +void COGLES1Driver::setRenderStates3DMode() +{ + if (CurrentRenderMode != ERM_3D) + { + // Reset Texture Stages + CacheHandler->setBlend(false); + glDisable(GL_ALPHA_TEST); + CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // switch back the matrices + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf((Matrices[ETS_VIEW] * Matrices[ETS_WORLD]).pointer()); + + GLfloat glmat[16]; + getGLMatrix(glmat, Matrices[ETS_PROJECTION]); + glmat[12] *= -1.0f; + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(glmat); + + ResetRenderStates = true; + } + + if ( ResetRenderStates || LastMaterial != Material) + { + // unset old material + + if (LastMaterial.MaterialType != Material.MaterialType && + static_cast(LastMaterial.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); + + // set new material. + if (static_cast(Material.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[Material.MaterialType].Renderer->OnSetMaterial( + Material, LastMaterial, ResetRenderStates, this); + + LastMaterial = Material; + CacheHandler->correctCacheMaterial(LastMaterial); + ResetRenderStates = false; + } + + if (static_cast(Material.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[Material.MaterialType].Renderer->OnRender(this, video::EVT_STANDARD); + + CurrentRenderMode = ERM_3D; +} + + +GLint COGLES1Driver::getTextureWrapMode(u8 clamp) const +{ + switch (clamp) + { + case ETC_CLAMP: + // return GL_CLAMP; not supported in ogl-es + return GL_CLAMP_TO_EDGE; + break; + case ETC_CLAMP_TO_EDGE: + return GL_CLAMP_TO_EDGE; + break; + case ETC_CLAMP_TO_BORDER: + // return GL_CLAMP_TO_BORDER; not supported in ogl-es + return GL_CLAMP_TO_EDGE; + break; + case ETC_MIRROR: +#ifdef GL_OES_texture_mirrored_repeat + if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_texture_mirrored_repeat]) + return GL_MIRRORED_REPEAT_OES; + else +#endif + return GL_REPEAT; + break; + // the next three are not yet supported at all + case ETC_MIRROR_CLAMP: + case ETC_MIRROR_CLAMP_TO_EDGE: + case ETC_MIRROR_CLAMP_TO_BORDER: +#ifdef GL_OES_texture_mirrored_repeat + if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_texture_mirrored_repeat]) + return GL_MIRRORED_REPEAT_OES; + else +#endif + return GL_CLAMP_TO_EDGE; + break; + case ETC_REPEAT: + default: + return GL_REPEAT; + break; + } +} + + +//! Can be called by an IMaterialRenderer to make its work easier. +void COGLES1Driver::setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial, + bool resetAllRenderStates) +{ + if (resetAllRenderStates || + lastmaterial.ColorMaterial != material.ColorMaterial) + { + // we only have diffuse_and_ambient in ogl-es + if (material.ColorMaterial == ECM_DIFFUSE_AND_AMBIENT) + glEnable(GL_COLOR_MATERIAL); + else + glDisable(GL_COLOR_MATERIAL); + } + + if (resetAllRenderStates || + lastmaterial.AmbientColor != material.AmbientColor || + lastmaterial.DiffuseColor != material.DiffuseColor || + lastmaterial.EmissiveColor != material.EmissiveColor || + lastmaterial.ColorMaterial != material.ColorMaterial) + { + GLfloat color[4]; + + const f32 inv = 1.0f / 255.0f; + + if ((material.ColorMaterial != video::ECM_AMBIENT) && + (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT)) + { + color[0] = material.AmbientColor.getRed() * inv; + color[1] = material.AmbientColor.getGreen() * inv; + color[2] = material.AmbientColor.getBlue() * inv; + color[3] = material.AmbientColor.getAlpha() * inv; + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color); + } + + if ((material.ColorMaterial != video::ECM_DIFFUSE) && + (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT)) + { + color[0] = material.DiffuseColor.getRed() * inv; + color[1] = material.DiffuseColor.getGreen() * inv; + color[2] = material.DiffuseColor.getBlue() * inv; + color[3] = material.DiffuseColor.getAlpha() * inv; + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color); + } + + if (material.ColorMaterial != video::ECM_EMISSIVE) + { + color[0] = material.EmissiveColor.getRed() * inv; + color[1] = material.EmissiveColor.getGreen() * inv; + color[2] = material.EmissiveColor.getBlue() * inv; + color[3] = material.EmissiveColor.getAlpha() * inv; + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, color); + } + } + + if (resetAllRenderStates || + lastmaterial.SpecularColor != material.SpecularColor || + lastmaterial.Shininess != material.Shininess) + { + GLfloat color[]={0.f,0.f,0.f,1.f}; + const f32 inv = 1.0f / 255.0f; + + // disable Specular colors if no shininess is set + if ((material.Shininess != 0.0f) && + (material.ColorMaterial != video::ECM_SPECULAR)) + { +#ifdef GL_EXT_separate_specular_color + if (FeatureAvailable[IRR_EXT_separate_specular_color]) + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); +#endif + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material.Shininess); + color[0] = material.SpecularColor.getRed() * inv; + color[1] = material.SpecularColor.getGreen() * inv; + color[2] = material.SpecularColor.getBlue() * inv; + color[3] = material.SpecularColor.getAlpha() * inv; + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color); + } +#ifdef GL_EXT_separate_specular_color + else + if (FeatureAvailable[IRR_EXT_separate_specular_color]) + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR); +#endif + } + +// TODO ogl-es + // fillmode +// if (resetAllRenderStates || (lastmaterial.Wireframe != material.Wireframe) || (lastmaterial.PointCloud != material.PointCloud)) +// glPolygonMode(GL_FRONT_AND_BACK, material.Wireframe ? GL_LINE : material.PointCloud? GL_POINT : GL_FILL); + + // shademode + if (resetAllRenderStates || (lastmaterial.GouraudShading != material.GouraudShading)) + { + if (material.GouraudShading) + glShadeModel(GL_SMOOTH); + else + glShadeModel(GL_FLAT); + } + + // lighting + if (resetAllRenderStates || (lastmaterial.Lighting != material.Lighting)) + { + if (material.Lighting) + glEnable(GL_LIGHTING); + else + glDisable(GL_LIGHTING); + } + + // zbuffer + if (resetAllRenderStates || lastmaterial.ZBuffer != material.ZBuffer) + { + switch (material.ZBuffer) + { + case ECFN_DISABLED: + glDisable(GL_DEPTH_TEST); + break; + case ECFN_LESSEQUAL: + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + break; + case ECFN_EQUAL: + glEnable(GL_DEPTH_TEST); + 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; + case ECFN_NEVER: + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_NEVER); + break; + } + } + + // zwrite + if (getWriteZBuffer(material)) + { + glDepthMask(GL_TRUE); + } + else + { + glDepthMask(GL_FALSE); + } + + // back face culling + if (resetAllRenderStates || (lastmaterial.FrontfaceCulling != material.FrontfaceCulling) || (lastmaterial.BackfaceCulling != material.BackfaceCulling)) + { + if ((material.FrontfaceCulling) && (material.BackfaceCulling)) + { + glCullFace(GL_FRONT_AND_BACK); + glEnable(GL_CULL_FACE); + } + else + if (material.BackfaceCulling) + { + glCullFace(GL_BACK); + glEnable(GL_CULL_FACE); + } + else + if (material.FrontfaceCulling) + { + glCullFace(GL_FRONT); + glEnable(GL_CULL_FACE); + } + else + glDisable(GL_CULL_FACE); + } + + // fog + if (resetAllRenderStates || lastmaterial.FogEnable != material.FogEnable) + { + if (material.FogEnable) + glEnable(GL_FOG); + else + glDisable(GL_FOG); + } + + // normalization + if (resetAllRenderStates || lastmaterial.NormalizeNormals != material.NormalizeNormals) + { + if (material.NormalizeNormals) + glEnable(GL_NORMALIZE); + else + 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); + } + + // Blend Equation + if (material.BlendOperation == EBO_NONE) + CacheHandler->setBlend(false); + else + { + CacheHandler->setBlend(true); + + if (queryFeature(EVDF_BLEND_OPERATIONS)) + { + switch (material.BlendOperation) + { + case EBO_ADD: +#if defined(GL_OES_blend_subtract) + CacheHandler->setBlendEquation(GL_FUNC_ADD_OES); +#endif + break; + case EBO_SUBTRACT: +#if defined(GL_OES_blend_subtract) + CacheHandler->setBlendEquation(GL_FUNC_SUBTRACT_OES); +#endif + break; + case EBO_REVSUBTRACT: +#if defined(GL_OES_blend_subtract) + CacheHandler->setBlendEquation(GL_FUNC_REVERSE_SUBTRACT_OES); +#endif + break; + default: + break; + } + } + } + + // Blend Factor + if (IR(material.BlendFactor) & 0xFFFFFFFF // TODO: why the & 0xFFFFFFFF? + && material.MaterialType != EMT_ONETEXTURE_BLEND + ) + { + E_BLEND_FACTOR srcRGBFact = EBF_ZERO; + E_BLEND_FACTOR dstRGBFact = EBF_ZERO; + E_BLEND_FACTOR srcAlphaFact = EBF_ZERO; + E_BLEND_FACTOR dstAlphaFact = EBF_ZERO; + E_MODULATE_FUNC modulo = EMFN_MODULATE_1X; + u32 alphaSource = 0; + + unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulo, alphaSource, material.BlendFactor); + + if (queryFeature(EVDF_BLEND_SEPARATE)) + { + CacheHandler->setBlendFuncSeparate(getGLBlend(srcRGBFact), getGLBlend(dstRGBFact), + getGLBlend(srcAlphaFact), getGLBlend(dstAlphaFact)); + } + else + { + CacheHandler->setBlendFunc(getGLBlend(srcRGBFact), getGLBlend(dstRGBFact)); + } + } + + // TODO: Polygon Offset. Not sure if it was left out deliberately or if it won't work with this driver. + + // thickness + if (resetAllRenderStates || lastmaterial.Thickness != material.Thickness) + { + if (AntiAlias) + { +// glPointSize(core::clamp(static_cast(material.Thickness), DimSmoothedPoint[0], DimSmoothedPoint[1])); + // we don't use point smoothing + glPointSize(core::clamp(static_cast(material.Thickness), DimAliasedPoint[0], DimAliasedPoint[1])); + } + else + { + glPointSize(core::clamp(static_cast(material.Thickness), DimAliasedPoint[0], DimAliasedPoint[1])); + glLineWidth(core::clamp(static_cast(material.Thickness), DimAliasedLine[0], DimAliasedLine[1])); + } + } + + // 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); + else if (lastmaterial.AntiAliasing & EAAM_ALPHA_TO_COVERAGE) + glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); + + if ((AntiAlias >= 2) && (material.AntiAliasing & (EAAM_SIMPLE|EAAM_QUALITY))) + glEnable(GL_MULTISAMPLE); + else + glDisable(GL_MULTISAMPLE); + } + if ((material.AntiAliasing & EAAM_LINE_SMOOTH) != (lastmaterial.AntiAliasing & EAAM_LINE_SMOOTH)) + { + 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) != (lastmaterial.AntiAliasing & EAAM_POINT_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); + } + } + + // Texture parameters + setTextureRenderStates(material, resetAllRenderStates); +} + +//! Compare in SMaterial doesn't check texture parameters, so we should call this on each OnRender call. +void COGLES1Driver::setTextureRenderStates(const SMaterial& material, bool resetAllRenderstates) +{ + // Set textures to TU/TIU and apply filters to them + + for (s32 i = Feature.MaxTextureUnits - 1; i >= 0; --i) + { + CacheHandler->getTextureCache().set(i, material.TextureLayer[i].Texture); + + const COGLES1Texture* tmpTexture = CacheHandler->getTextureCache().get(i); + + if (!tmpTexture) + continue; + + GLenum tmpTextureType = tmpTexture->getOpenGLTextureType(); + + CacheHandler->setActiveTexture(GL_TEXTURE0 + i); + + { + const bool isRTT = tmpTexture->isRenderTarget(); + + glMatrixMode(GL_TEXTURE); + + if (!isRTT && Matrices[ETS_TEXTURE_0 + i].isIdentity()) + glLoadIdentity(); + else + { + GLfloat glmat[16]; + if (isRTT) + getGLTextureMatrix(glmat, Matrices[ETS_TEXTURE_0 + i] * TextureFlipMatrix); + else + getGLTextureMatrix(glmat, Matrices[ETS_TEXTURE_0 + i]); + glLoadMatrixf(glmat); + } + } + + COGLES1Texture::SStatesCache& statesCache = tmpTexture->getStatesCache(); + + if (resetAllRenderstates) + statesCache.IsCached = false; + +#ifdef GL_VERSION_2_1 + if (Version >= 210) + { + if (!statesCache.IsCached || material.TextureLayer[i].LODBias != statesCache.LODBias) + { + if (material.TextureLayer[i].LODBias) + { + const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias); + glTexParameterf(tmpTextureType, GL_TEXTURE_LOD_BIAS, tmp); + } + else + glTexParameterf(tmpTextureType, GL_TEXTURE_LOD_BIAS, 0.f); + + statesCache.LODBias = material.TextureLayer[i].LODBias; + } + } + else if (FeatureAvailable[IRR_EXT_texture_lod_bias]) + { + if (material.TextureLayer[i].LODBias) + { + const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias); + glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, tmp); + } + else + glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.f); + } +#elif defined(GL_EXT_texture_lod_bias) + if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_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 + + if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter || + material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter) + { + glTexParameteri(tmpTextureType, GL_TEXTURE_MAG_FILTER, + (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST); + + statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter; + statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter; + } + + if (material.UseMipMaps && tmpTexture->hasMipMaps()) + { + if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter || + material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter || !statesCache.MipMapStatus) + { + glTexParameteri(tmpTextureType, GL_TEXTURE_MIN_FILTER, + material.TextureLayer[i].TrilinearFilter ? GL_LINEAR_MIPMAP_LINEAR : + material.TextureLayer[i].BilinearFilter ? GL_LINEAR_MIPMAP_NEAREST : + GL_NEAREST_MIPMAP_NEAREST); + + statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter; + statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter; + statesCache.MipMapStatus = true; + } + } + else + { + if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter || + material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter || statesCache.MipMapStatus) + { + glTexParameteri(tmpTextureType, GL_TEXTURE_MIN_FILTER, + (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST); + + statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter; + statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter; + statesCache.MipMapStatus = false; + } + } + +#ifdef GL_EXT_texture_filter_anisotropic + if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_EXT_texture_filter_anisotropic] && + (!statesCache.IsCached || material.TextureLayer[i].AnisotropicFilter != statesCache.AnisotropicFilter)) + { + glTexParameteri(tmpTextureType, GL_TEXTURE_MAX_ANISOTROPY_EXT, + material.TextureLayer[i].AnisotropicFilter>1 ? core::min_(MaxAnisotropy, material.TextureLayer[i].AnisotropicFilter) : 1); + + statesCache.AnisotropicFilter = material.TextureLayer[i].AnisotropicFilter; + } +#endif + + if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapU != statesCache.WrapU) + { + glTexParameteri(tmpTextureType, GL_TEXTURE_WRAP_S, getTextureWrapMode(material.TextureLayer[i].TextureWrapU)); + statesCache.WrapU = material.TextureLayer[i].TextureWrapU; + } + + if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapV != statesCache.WrapV) + { + glTexParameteri(tmpTextureType, GL_TEXTURE_WRAP_T, getTextureWrapMode(material.TextureLayer[i].TextureWrapV)); + statesCache.WrapV = material.TextureLayer[i].TextureWrapV; + } + + statesCache.IsCached = true; + } + + // be sure to leave in texture stage 0 + CacheHandler->setActiveTexture(GL_TEXTURE0); +} + + +//! sets the needed renderstates +void COGLES1Driver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel) +{ + if (CurrentRenderMode != ERM_2D || Transformation3DChanged) + { + // unset last 3d material + if (CurrentRenderMode == ERM_3D) + { + if (static_cast(LastMaterial.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); + } + if (Transformation3DChanged) + { + glMatrixMode(GL_PROJECTION); + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + core::matrix4 m(core::matrix4::EM4CONST_NOTHING); + m.buildProjectionMatrixOrthoLH(f32(renderTargetSize.Width), f32(-(s32)(renderTargetSize.Height)), -1.0f, 1.0f); + m.setTranslation(core::vector3df(-1, 1, 0)); + glLoadMatrixf(m.pointer()); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + Transformation3DChanged = false; + } + } + + Material = (OverrideMaterial2DEnabled) ? OverrideMaterial2D : InitMaterial2D; + Material.Lighting = false; + Material.TextureLayer[0].Texture = (texture) ? const_cast(CacheHandler->getTextureCache().get(0)) : 0; + setTransform(ETS_TEXTURE_0, core::IdentityMatrix); + + setBasicRenderStates(Material, LastMaterial, false); + + LastMaterial = Material; + CacheHandler->correctCacheMaterial(LastMaterial); + + // no alphaChannel without texture + alphaChannel &= texture; + + if (alphaChannel || alpha) + { + CacheHandler->setBlend(true); + CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0.f); + } + else + { + CacheHandler->setBlend(false); + glDisable(GL_ALPHA_TEST); + } + + if (texture) + { + // Due to the transformation change, the previous line would call a reset each frame + // but we can safely reset the variable as it was false before + Transformation3DChanged = false; + + if (alphaChannel) + { + // if alpha and alpha texture just modulate, otherwise use only the alpha channel + if (alpha) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + else + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE); + // rgb always modulates + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR); + } + } + else + { + if (alpha) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR); + // rgb always modulates + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR); + } + else + { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + } + } + + CurrentRenderMode = ERM_2D; +} + + +//! \return Returns the name of the video driver. +const wchar_t* COGLES1Driver::getName() const +{ + return Name.c_str(); +} + + +//! deletes all dynamic lights there are +void COGLES1Driver::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 COGLES1Driver::getMaximalDynamicLightAmount() const +{ + return MaxLights; +} + + +//! Sets the dynamic ambient light color. +void COGLES1Driver::setAmbientLight(const SColorf& color) +{ + CNullDriver::setAmbientLight(color); + GLfloat data[4] = {color.r, color.g, color.b, color.a}; + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, data); +} + + +// this code was sent in by Oliver Klems, thank you +void COGLES1Driver::setViewPort(const core::rect& area) +{ + core::rect vp = area; + core::rect rendert(0, 0, getCurrentRenderTargetSize().Width, getCurrentRenderTargetSize().Height); + vp.clipAgainst(rendert); + + if (vp.getHeight() > 0 && vp.getWidth() > 0) + CacheHandler->setViewport(vp.UpperLeftCorner.X, getCurrentRenderTargetSize().Height - vp.UpperLeftCorner.Y - vp.getHeight(), vp.getWidth(), vp.getHeight()); + + ViewPort = vp; +} + + +//! Draws a shadow volume into the stencil buffer. +void COGLES1Driver::drawStencilShadowVolume(const core::array& triangles, bool zfail, u32 debugDataVisible) +{ + const u32 count=triangles.size(); + if (!StencilBuffer || !count) + return; + + u8 colorMask = LastMaterial.ColorMask; + const GLboolean lightingEnabled = glIsEnabled(GL_LIGHTING); + const GLboolean fogEnabled = glIsEnabled(GL_FOG); + const GLboolean cullFaceEnabled = glIsEnabled(GL_CULL_FACE); + + GLint cullFaceMode = 0; + glGetIntegerv(GL_CULL_FACE_MODE, &cullFaceMode); + GLint depthFunc = 0; + glGetIntegerv(GL_DEPTH_FUNC, &depthFunc); + GLboolean depthMask = 0; + glGetBooleanv(GL_DEPTH_WRITEMASK, &depthMask); + + glDisable(GL_LIGHTING); + glDisable(GL_FOG); + glDepthFunc(GL_LEQUAL); + glDepthMask(GL_FALSE); + + if (!(debugDataVisible & (scene::EDS_SKELETON|scene::EDS_MESH_WIRE_OVERLAY))) + { + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glEnable(GL_STENCIL_TEST); + } + + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, sizeof(core::vector3df), triangles.const_pointer()); + + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + + GLenum decr = GL_DECR; + GLenum incr = GL_INCR; + +#if defined(GL_OES_stencil_wrap) + if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_stencil_wrap]) + { + decr = GL_DECR_WRAP_OES; + incr = GL_INCR_WRAP_OES; + } +#endif + + glEnable(GL_CULL_FACE); + + if (zfail) + { + glCullFace(GL_FRONT); + glStencilOp(GL_KEEP, incr, GL_KEEP); + glDrawArrays(GL_TRIANGLES, 0, count); + + glCullFace(GL_BACK); + glStencilOp(GL_KEEP, decr, GL_KEEP); + glDrawArrays(GL_TRIANGLES, 0, count); + } + else // zpass + { + glCullFace(GL_BACK); + glStencilOp(GL_KEEP, GL_KEEP, incr); + glDrawArrays(GL_TRIANGLES, 0, count); + + glCullFace(GL_FRONT); + glStencilOp(GL_KEEP, GL_KEEP, decr); + glDrawArrays(GL_TRIANGLES, 0, count); + } + + glDisableClientState(GL_VERTEX_ARRAY); + + glColorMask((colorMask & ECP_RED)?GL_TRUE:GL_FALSE, + (colorMask & ECP_GREEN)?GL_TRUE:GL_FALSE, + (colorMask & ECP_BLUE)?GL_TRUE:GL_FALSE, + (colorMask & ECP_ALPHA)?GL_TRUE:GL_FALSE); + + glDisable(GL_STENCIL_TEST); + + if (lightingEnabled) + glEnable(GL_LIGHTING); + + if (fogEnabled) + glEnable(GL_FOG); + + if (cullFaceEnabled) + glEnable(GL_CULL_FACE); + else + glDisable(GL_CULL_FACE); + + glCullFace(cullFaceMode); + glDepthFunc(depthFunc); + glDepthMask(depthMask); +} + + +void COGLES1Driver::drawStencilShadow(bool clearStencilBuffer, + video::SColor leftUpEdge, video::SColor rightUpEdge, + video::SColor leftDownEdge, video::SColor rightDownEdge) +{ + if (!StencilBuffer) + return; + + setTextureRenderStates(SMaterial(), false); + + u8 colorMask = LastMaterial.ColorMask; + const GLboolean lightingEnabled = glIsEnabled(GL_LIGHTING); + const GLboolean fogEnabled = glIsEnabled(GL_FOG); + const GLboolean blendEnabled = glIsEnabled(GL_BLEND); + + GLboolean depthMask = 0; + glGetBooleanv(GL_DEPTH_WRITEMASK, &depthMask); + GLint shadeModel = 0; + glGetIntegerv(GL_SHADE_MODEL, &shadeModel); + GLint blendSrc = 0, blendDst = 0; + glGetIntegerv(GL_BLEND_SRC, &blendSrc); + glGetIntegerv(GL_BLEND_DST, &blendDst); + + glDisable(GL_LIGHTING); + glDisable(GL_FOG); + glDepthMask(GL_FALSE); + + 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); + glStencilFunc(GL_NOTEQUAL, 0, ~0); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + u16 indices[] = {0, 1, 2, 3}; + S3DVertex vertices[4]; + vertices[0] = S3DVertex(-1.f, 1.f, 0.9f, 0, 0, 1, leftDownEdge, 0, 0); + vertices[1] = S3DVertex(1.f, 1.f, 0.9f, 0, 0, 1, leftUpEdge, 0, 0); + vertices[2] = S3DVertex(1.f, -1.f, 0.9f, 0, 0, 1, rightUpEdge, 0, 0); + vertices[3] = S3DVertex(-1.f, -1.f, 0.9f, 0, 0, 1, rightDownEdge, 0, 0); + drawVertexPrimitiveList2d3d(vertices, 4, indices, 2, EVT_STANDARD, scene::EPT_TRIANGLE_FAN, EIT_16BIT, false); + + if (clearStencilBuffer) + glClear(GL_STENCIL_BUFFER_BIT); + + glColorMask((colorMask & ECP_RED)?GL_TRUE:GL_FALSE, + (colorMask & ECP_GREEN)?GL_TRUE:GL_FALSE, + (colorMask & ECP_BLUE)?GL_TRUE:GL_FALSE, + (colorMask & ECP_ALPHA)?GL_TRUE:GL_FALSE); + + glDisable(GL_STENCIL_TEST); + + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + if (lightingEnabled) + glEnable(GL_LIGHTING); + + if (fogEnabled) + glEnable(GL_FOG); + + if (!blendEnabled) + glDisable(GL_BLEND); + + glDepthMask(depthMask); + glShadeModel(shadeModel); + glBlendFunc(blendSrc, blendDst); +} + + +//! Sets the fog mode. +void COGLES1Driver::setFog(SColor c, E_FOG_TYPE fogType, f32 start, + f32 end, f32 density, bool pixelFog, bool rangeFog) +{ + CNullDriver::setFog(c, fogType, start, end, density, pixelFog, rangeFog); + + glFogf(GL_FOG_MODE, GLfloat((fogType==EFT_FOG_LINEAR)? GL_LINEAR : (fogType==EFT_FOG_EXP)?GL_EXP:GL_EXP2)); + +#ifdef GL_EXT_fog_coord + if (FeatureAvailable[IRR_EXT_fog_coord]) + glFogi(GL_FOG_COORDINATE_SOURCE, GL_FRAGMENT_DEPTH); +#endif + + if (fogType==EFT_FOG_LINEAR) + { + glFogf(GL_FOG_START, start); + glFogf(GL_FOG_END, end); + } + else + glFogf(GL_FOG_DENSITY, density); + + if (pixelFog) + glHint(GL_FOG_HINT, GL_NICEST); + else + glHint(GL_FOG_HINT, GL_FASTEST); + + SColorf color(c); + GLfloat data[4] = {color.r, color.g, color.b, color.a}; + glFogfv(GL_FOG_COLOR, data); +} + + +//! Draws a 3d line. +void COGLES1Driver::draw3DLine(const core::vector3df& start, + const core::vector3df& end, SColor color) +{ + setRenderStates3DMode(); + + u16 indices[] = {0,1}; + S3DVertex vertices[2]; + vertices[0] = S3DVertex(start.X,start.Y,start.Z, 0,0,1, color, 0,0); + vertices[1] = S3DVertex(end.X,end.Y,end.Z, 0,0,1, color, 0,0); + drawVertexPrimitiveList2d3d(vertices, 2, indices, 1, video::EVT_STANDARD, scene::EPT_LINES); +} + + +//! Only used by the internal engine. Used to notify the driver that +//! the window was resized. +void COGLES1Driver::OnResize(const core::dimension2d& size) +{ + CNullDriver::OnResize(size); + CacheHandler->setViewport(0, 0, size.Width, size.Height); + Transformation3DChanged = true; +} + + +//! Returns type of video driver +E_DRIVER_TYPE COGLES1Driver::getDriverType() const +{ + return EDT_OGLES1; +} + + +//! returns color format +ECOLOR_FORMAT COGLES1Driver::getColorFormat() const +{ + return ColorFormat; +} + + +//! Get a vertex shader constant index. +s32 COGLES1Driver::getVertexShaderConstantID(const c8* name) +{ + return getPixelShaderConstantID(name); +} + +//! Get a pixel shader constant index. +s32 COGLES1Driver::getPixelShaderConstantID(const c8* name) +{ + os::Printer::log("Error: Please use IMaterialRendererServices from IShaderConstantSetCallBack::OnSetConstants not VideoDriver->getPixelShaderConstantID()."); + return -1; +} + +//! Sets a constant for the vertex shader based on an index. +bool COGLES1Driver::setVertexShaderConstant(s32 index, const f32* floats, int count) +{ + //pass this along, as in GLSL the same routine is used for both vertex and fragment shaders + return setPixelShaderConstant(index, floats, count); +} + +//! Int interface for the above. +bool COGLES1Driver::setVertexShaderConstant(s32 index, const s32* ints, int count) +{ + return setPixelShaderConstant(index, ints, count); +} + +//! Sets a constant for the pixel shader based on an index. +bool COGLES1Driver::setPixelShaderConstant(s32 index, const f32* floats, int count) +{ + os::Printer::log("Error: Please use IMaterialRendererServices from IShaderConstantSetCallBack::OnSetConstants not VideoDriver->setPixelShaderConstant()."); + return false; +} + +//! Int interface for the above. +bool COGLES1Driver::setPixelShaderConstant(s32 index, const s32* ints, int count) +{ + os::Printer::log("Error: Please use IMaterialRendererServices from IShaderConstantSetCallBack::OnSetConstants not VideoDriver->setPixelShaderConstant()."); + return false; +} + +//! Sets a vertex shader constant. +void COGLES1Driver::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount) +{ +#ifdef GL_vertex_program + for (s32 i=0; i& size, + const io::path& name, const ECOLOR_FORMAT format) +{ + //disable mip-mapping + bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS); + setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false); + + bool supportForFBO = (Feature.ColorAttachment > 0); + + core::dimension2du destSize(size); + + if (!supportForFBO) + { + destSize = core::dimension2d(core::min_(size.Width, ScreenSize.Width), core::min_(size.Height, ScreenSize.Height)); + destSize = destSize.getOptimalSize((size == size.getOptimalSize()), false, false); + } + + COGLES1Texture* renderTargetTexture = new COGLES1Texture(name, destSize, ETT_2D, format, this); + addTexture(renderTargetTexture); + renderTargetTexture->drop(); + + //restore mip-mapping + setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels); + + return renderTargetTexture; +} + +ITexture* COGLES1Driver::addRenderTargetTextureCubemap(const irr::u32 sideLen, const io::path& name, const ECOLOR_FORMAT format) +{ + //disable mip-mapping + bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS); + setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false); + + bool supportForFBO = (Feature.ColorAttachment > 0); + + const core::dimension2d size(sideLen, sideLen); + core::dimension2du destSize(size); + + if (!supportForFBO) + { + destSize = core::dimension2d(core::min_(size.Width, ScreenSize.Width), core::min_(size.Height, ScreenSize.Height)); + destSize = destSize.getOptimalSize((size == size.getOptimalSize()), false, false); + } + + COGLES1Texture* renderTargetTexture = new COGLES1Texture(name, destSize, ETT_CUBEMAP, format, this); + addTexture(renderTargetTexture); + renderTargetTexture->drop(); + + //restore mip-mapping + setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels); + + return renderTargetTexture; +} + +//! Returns the maximum amount of primitives +u32 COGLES1Driver::getMaximalPrimitiveCount() const +{ + return 65535; +} + +bool COGLES1Driver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil) +{ + if (target && target->getDriverType() != EDT_OGLES1) + { + os::Printer::log("Fatal Error: Tried to set a render target not owned by OpenGL driver.", ELL_ERROR); + return false; + } + + bool supportForFBO = (Feature.ColorAttachment > 0); + + core::dimension2d destRenderTargetSize(0, 0); + + if (target) + { + COGLES1RenderTarget* renderTarget = static_cast(target); + + if (supportForFBO) + { + CacheHandler->setFBO(renderTarget->getBufferID()); + renderTarget->update(); + } + + destRenderTargetSize = renderTarget->getSize(); + + CacheHandler->setViewport(0, 0, destRenderTargetSize.Width, destRenderTargetSize.Height); + } + else + { + if (supportForFBO) + CacheHandler->setFBO(0); + else + { + COGLES1RenderTarget* prevRenderTarget = static_cast(CurrentRenderTarget); + COGLES1Texture* renderTargetTexture = static_cast(prevRenderTarget->getTexture()); + + if (renderTargetTexture) + { + const COGLES1Texture* prevTexture = CacheHandler->getTextureCache().get(0); + + CacheHandler->getTextureCache().set(0, renderTargetTexture); + + const core::dimension2d size = renderTargetTexture->getSize(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, size.Width, size.Height); + + CacheHandler->getTextureCache().set(0, prevTexture); + } + } + + destRenderTargetSize = core::dimension2d(0, 0); + + CacheHandler->setViewport(0, 0, ScreenSize.Width, ScreenSize.Height); + } + + if (CurrentRenderTargetSize != destRenderTargetSize) + { + CurrentRenderTargetSize = destRenderTargetSize; + + Transformation3DChanged = true; + } + + CurrentRenderTarget = target; + + if (!supportForFBO) + { + clearFlag |= ECBF_COLOR; + clearFlag |= ECBF_DEPTH; + } + + clearBuffers(clearFlag, clearColor, clearDepth, clearStencil); + + return true; +} + +void COGLES1Driver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil) +{ + GLbitfield mask = 0; + + if (flag & ECBF_COLOR) + { + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + 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 (flag & ECBF_DEPTH) + { + glDepthMask(GL_TRUE); + glClearDepthf(depth); + mask |= GL_DEPTH_BUFFER_BIT; + } + + if (flag & ECBF_STENCIL) + { + glClearStencil(stencil); + mask |= GL_STENCIL_BUFFER_BIT; + } + + if (mask) + glClear(mask); +} + + +//! Returns an image created from the last rendered frame. +// We want to read the front buffer to get the latest render finished. +// This is not possible under ogl-es, though, so one has to call this method +// outside of the render loop only. +IImage* COGLES1Driver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target) +{ + if (target==video::ERT_MULTI_RENDER_TEXTURES || target==video::ERT_RENDER_TEXTURE || target==video::ERT_STEREO_BOTH_BUFFERS) + return 0; + GLint internalformat=GL_RGBA; + GLint type=GL_UNSIGNED_BYTE; + if (false + && (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_IMG_read_format] + || FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_read_format] + || FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_EXT_read_format_bgra])) + { +#ifdef GL_IMPLEMENTATION_COLOR_READ_TYPE_OES + glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, &internalformat); + glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, &type); +#endif + // there are formats we don't support ATM + if (GL_UNSIGNED_SHORT_4_4_4_4==type) + type=GL_UNSIGNED_SHORT_5_5_5_1; +#ifdef GL_EXT_read_format_bgra + else if (GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT==type) + type=GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT; +#endif + } + + IImage* newImage = 0; + if ((GL_RGBA==internalformat) +#ifdef GL_EXT_read_format_bgra + || (GL_BGRA_EXT==internalformat) +#endif + ) + { + if (GL_UNSIGNED_BYTE==type) + newImage = new CImage(ECF_A8R8G8B8, ScreenSize); + else + newImage = new CImage(ECF_A1R5G5B5, ScreenSize); + } + else + { + if (GL_UNSIGNED_BYTE==type) + newImage = new CImage(ECF_R8G8B8, ScreenSize); + else + newImage = new CImage(ECF_R5G6B5, ScreenSize); + } + + u8* pixels = static_cast(newImage->getData()); + if (!pixels) + { + newImage->drop(); + return 0; + } + + glReadPixels(0, 0, ScreenSize.Width, ScreenSize.Height, internalformat, type, pixels); + + // opengl images are horizontally flipped, so we have to fix that here. + const s32 pitch=newImage->getPitch(); + u8* p2 = pixels + (ScreenSize.Height - 1) * pitch; + u8* tmpBuffer = new u8[pitch]; + for (u32 i=0; i < ScreenSize.Height; i += 2) + { + memcpy(tmpBuffer, pixels, pitch); + memcpy(pixels, p2, pitch); + memcpy(p2, tmpBuffer, pitch); + pixels += pitch; + p2 -= pitch; + } + delete [] tmpBuffer; + + if (testGLError(__LINE__)) + { + newImage->drop(); + return 0; + } + + return newImage; +} + +void COGLES1Driver::removeTexture(ITexture* texture) +{ + CacheHandler->getTextureCache().remove(texture); + CNullDriver::removeTexture(texture); +} + + +//! Set/unset a clipping plane. +bool COGLES1Driver::setClipPlane(u32 index, const core::plane3df& plane, bool enable) +{ + if (index >= MaxUserClipPlanes) + return false; + + UserClipPlane[index]=plane; + enableClipPlane(index, enable); + return true; +} + + +void COGLES1Driver::uploadClipPlane(u32 index) +{ + // opengl needs an array of doubles for the plane equation + float clip_plane[4]; + clip_plane[0] = UserClipPlane[index].Normal.X; + clip_plane[1] = UserClipPlane[index].Normal.Y; + clip_plane[2] = UserClipPlane[index].Normal.Z; + clip_plane[3] = UserClipPlane[index].D; + glClipPlanef(GL_CLIP_PLANE0 + index, clip_plane); +} + + +//! Enable/disable a clipping plane. +void COGLES1Driver::enableClipPlane(u32 index, bool enable) +{ + if (index >= MaxUserClipPlanes) + return; + if (enable) + { + if (!UserClipPlaneEnabled[index]) + { + uploadClipPlane(index); + glEnable(GL_CLIP_PLANE0 + index); + } + } + else + glDisable(GL_CLIP_PLANE0 + index); + + UserClipPlaneEnabled[index]=enable; +} + + +core::dimension2du COGLES1Driver::getMaxTextureSize() const +{ + return core::dimension2du(MaxTextureSize, MaxTextureSize); +} + + +GLenum COGLES1Driver::getGLBlend(E_BLEND_FACTOR factor) const +{ + static GLenum const blendTable[] = + { + GL_ZERO, + GL_ONE, + GL_DST_COLOR, + GL_ONE_MINUS_DST_COLOR, + GL_SRC_COLOR, + GL_ONE_MINUS_SRC_COLOR, + GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, + GL_DST_ALPHA, + GL_ONE_MINUS_DST_ALPHA, + GL_SRC_ALPHA_SATURATE + }; + + return blendTable[factor]; +} + +GLenum COGLES1Driver::getZBufferBits() const +{ + GLenum bits = 0; + + switch (Params.ZBufferBits) + { + case 24: +#if defined(GL_OES_depth24) + if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_depth24)) + bits = GL_DEPTH_COMPONENT24_OES; + else +#endif + bits = GL_DEPTH_COMPONENT16; + break; + case 32: +#if defined(GL_OES_depth32) + if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_depth32)) + bits = GL_DEPTH_COMPONENT32_OES; + else +#endif + bits = GL_DEPTH_COMPONENT16; + break; + default: + bits = GL_DEPTH_COMPONENT16; + break; + } + + return bits; +} + +bool COGLES1Driver::getColorFormatParameters(ECOLOR_FORMAT format, GLint& internalFormat, GLenum& pixelFormat, + GLenum& pixelType, void(**converter)(const void*, s32, void*)) const +{ + bool supported = false; + internalFormat = GL_RGBA; + pixelFormat = GL_RGBA; + pixelType = GL_UNSIGNED_BYTE; + *converter = 0; + + switch (format) + { + case ECF_A1R5G5B5: + supported = true; + internalFormat = GL_RGBA; + pixelFormat = GL_RGBA; + pixelType = GL_UNSIGNED_SHORT_5_5_5_1; + *converter = CColorConverter::convert_A1R5G5B5toR5G5B5A1; + break; + case ECF_R5G6B5: + supported = true; + internalFormat = GL_RGB; + pixelFormat = GL_RGB; + pixelType = GL_UNSIGNED_SHORT_5_6_5; + break; + case ECF_R8G8B8: + supported = true; + internalFormat = GL_RGB; + pixelFormat = GL_RGB; + pixelType = GL_UNSIGNED_BYTE; + break; + case ECF_A8R8G8B8: + supported = true; + if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_IMG_texture_format_BGRA8888) || + queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_format_BGRA8888) || + queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_APPLE_texture_format_BGRA8888)) + { + internalFormat = GL_BGRA; + pixelFormat = GL_BGRA; + } + else + { + internalFormat = GL_RGBA; + pixelFormat = GL_RGBA; + *converter = CColorConverter::convert_A8R8G8B8toA8B8G8R8; + } + pixelType = GL_UNSIGNED_BYTE; + break; +#ifdef GL_EXT_texture_compression_s3tc + case ECF_DXT1: + supported = true; + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; +#endif +#ifdef GL_EXT_texture_compression_s3tc + case ECF_DXT2: + case ECF_DXT3: + supported = true; + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; +#endif +#ifdef GL_EXT_texture_compression_s3tc + case ECF_DXT4: + case ECF_DXT5: + supported = true; + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; +#endif +#ifdef GL_IMG_texture_compression_pvrtc + case ECF_PVRTC_RGB2: + supported = true; + internalFormat = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + pixelFormat = GL_RGB; + pixelType = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + break; +#endif +#ifdef GL_IMG_texture_compression_pvrtc + case ECF_PVRTC_ARGB2: + supported = true; + internalFormat = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + break; +#endif +#ifdef GL_IMG_texture_compression_pvrtc + case ECF_PVRTC_RGB4: + supported = true; + internalFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + pixelFormat = GL_RGB; + pixelType = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + break; +#endif +#ifdef GL_IMG_texture_compression_pvrtc + case ECF_PVRTC_ARGB4: + supported = true; + internalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + break; +#endif +#ifdef GL_IMG_texture_compression_pvrtc2 + case ECF_PVRTC2_ARGB2: + supported = true; + internalFormat = GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG; + break; +#endif +#ifdef GL_IMG_texture_compression_pvrtc2 + case ECF_PVRTC2_ARGB4: + supported = true; + internalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG; + break; +#endif +#ifdef GL_OES_compressed_ETC1_RGB8_texture + case ECF_ETC1: + supported = true; + internalFormat = GL_ETC1_RGB8_OES; + pixelFormat = GL_RGB; + pixelType = GL_ETC1_RGB8_OES; + break; +#endif +#ifdef GL_ES_VERSION_3_0 // TO-DO - fix when extension name will be available + case ECF_ETC2_RGB: + supported = true; + internalFormat = GL_COMPRESSED_RGB8_ETC2; + pixelFormat = GL_RGB; + pixelType = GL_COMPRESSED_RGB8_ETC2; + break; +#endif +#ifdef GL_ES_VERSION_3_0 // TO-DO - fix when extension name will be available + case ECF_ETC2_ARGB: + supported = true; + internalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA8_ETC2_EAC; + break; +#endif + case ECF_D16: + supported = true; + internalFormat = GL_DEPTH_COMPONENT16; + pixelFormat = GL_DEPTH_COMPONENT; + pixelType = GL_UNSIGNED_SHORT; + break; + case ECF_D32: +#if defined(GL_OES_depth32) + if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_depth32)) + { + supported = true; + internalFormat = GL_DEPTH_COMPONENT32_OES; + pixelFormat = GL_DEPTH_COMPONENT; + pixelType = GL_UNSIGNED_INT; + } +#endif + break; + case ECF_D24S8: +#ifdef GL_OES_packed_depth_stencil + if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_packed_depth_stencil)) + { + supported = true; + internalFormat = GL_DEPTH24_STENCIL8_OES; + pixelFormat = GL_DEPTH_STENCIL_OES; + pixelType = GL_UNSIGNED_INT_24_8_OES; + } +#endif + break; + case ECF_R8: + break; + case ECF_R8G8: + break; + case ECF_R16: + break; + case ECF_R16G16: + break; + case ECF_R16F: + break; + case ECF_G16R16F: + break; + case ECF_A16B16G16R16F: + break; + case ECF_R32F: + break; + case ECF_G32R32F: + break; + case ECF_A32B32G32R32F: + break; + default: + break; + } + +#ifdef _IRR_IOS_PLATFORM_ + if (internalFormat == GL_BGRA) + internalFormat = GL_RGBA; +#endif + + return supported; +} + +bool COGLES1Driver::queryTextureFormat(ECOLOR_FORMAT format) const +{ + GLint dummyInternalFormat; + GLenum dummyPixelFormat; + GLenum dummyPixelType; + void (*dummyConverter)(const void*, s32, void*); + return getColorFormatParameters(format, dummyInternalFormat, dummyPixelFormat, dummyPixelType, &dummyConverter); +} + +bool COGLES1Driver::needsTransparentRenderPass(const irr::video::SMaterial& material) const +{ + return CNullDriver::needsTransparentRenderPass(material) || material.isAlphaBlendOperation(); +} + +COGLES1CacheHandler* COGLES1Driver::getCacheHandler() const +{ + return CacheHandler; +} + +} // end namespace +} // end namespace + +#endif // _IRR_COMPILE_WITH_OGLES1_ + +namespace irr +{ +namespace video +{ + +#ifndef _IRR_COMPILE_WITH_OGLES1_ +class IVideoDriver; +class IContextManager; +#endif + +IVideoDriver* createOGLES1Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager) +{ +#ifdef _IRR_COMPILE_WITH_OGLES1_ + return new COGLES1Driver(params, io, contextManager); +#else + return 0; +#endif // _IRR_COMPILE_WITH_OGLES1_ +} + +} // end namespace +} // end namespace diff --git a/source/Irrlicht/COGLESDriver.h b/source/Irrlicht/COGLESDriver.h new file mode 100644 index 00000000..12017d6b --- /dev/null +++ b/source/Irrlicht/COGLESDriver.h @@ -0,0 +1,393 @@ +// Copyright (C) 2002-20014 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __C_OGLES1_DRIVER_H_INCLUDED__ +#define __C_OGLES1_DRIVER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#include "SIrrCreationParameters.h" + +#ifdef _IRR_COMPILE_WITH_OGLES1_ + +#include "CNullDriver.h" +#include "IMaterialRendererServices.h" +#include "EDriverFeatures.h" +#include "fast_atof.h" +#include "COGLESExtensionHandler.h" +#include "IContextManager.h" + +#if defined(_IRR_WINDOWS_API_) +// include windows headers for HWND +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#endif + +#ifdef _MSC_VER +#pragma comment(lib, "libGLES_CM.lib") +#endif + +namespace irr +{ +namespace video +{ + + class COGLES1Driver : public CNullDriver, public IMaterialRendererServices, public COGLES1ExtensionHandler + { + friend class COpenGLCoreTexture; + + public: + //! constructor + COGLES1Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager); + + //! destructor + virtual ~COGLES1Driver(); + + virtual bool beginScene(u16 clearFlag, SColor clearColor = SColor(255, 0, 0, 0), f32 clearDepth = 1.f, u8 clearStencil = 0, + const SExposedVideoData& videoData = SExposedVideoData(), core::rect* sourceRect = 0) _IRR_OVERRIDE_; + + virtual bool endScene() _IRR_OVERRIDE_; + + //! sets transformation + virtual void setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) _IRR_OVERRIDE_; + + + struct SHWBufferLink_opengl : public SHWBufferLink + { + SHWBufferLink_opengl(const scene::IMeshBuffer *_MeshBuffer): SHWBufferLink(_MeshBuffer), vbo_verticesID(0),vbo_indicesID(0){} + + GLuint vbo_verticesID; //tmp + GLuint vbo_indicesID; //tmp + + 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) _IRR_OVERRIDE_; + + //! Create hardware buffer from mesh + virtual SHWBufferLink *createHardwareBuffer(const scene::IMeshBuffer* mb) _IRR_OVERRIDE_; + + //! Delete hardware buffer (only some drivers can) + virtual void deleteHardwareBuffer(SHWBufferLink *HWBuffer) _IRR_OVERRIDE_; + + //! Draw hardware buffer + virtual void drawHardwareBuffer(SHWBufferLink *HWBuffer) _IRR_OVERRIDE_; + + virtual IRenderTarget* addRenderTarget() _IRR_OVERRIDE_; + + //! draws a vertex primitive list + virtual void drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) _IRR_OVERRIDE_; + + void drawVertexPrimitiveList2d3d(const void* vertices, u32 vertexCount, const void* indexList, u32 primitiveCount, E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType=EIT_16BIT, bool threed=true); + + //! queries the features of the driver, returns true if feature is available + virtual bool queryFeature(E_VIDEO_DRIVER_FEATURE feature) const _IRR_OVERRIDE_ + { +// return FeatureEnabled[feature] && COGLES1ExtensionHandler::queryFeature(feature); + return COGLES1ExtensionHandler::queryFeature(feature); + } + + //! Sets a material. + virtual void setMaterial(const SMaterial& material) _IRR_OVERRIDE_; + + 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) _IRR_OVERRIDE_; + + 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) _IRR_OVERRIDE_; + + virtual void draw2DImage(const video::ITexture* texture, u32 layer, bool flip); + + //! draws a set of 2d images + virtual void draw2DImageBatch(const video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, s32 kerningWidth = 0, + const core::rect* clipRect=0, + SColor color=SColor(255,255,255,255), + bool useAlphaChannelOfTexture=false) _IRR_OVERRIDE_; + + //! draws a set of 2d images, using a color and the alpha channel of the texture if desired. + virtual void draw2DImageBatch(const video::ITexture* texture, + const core::array >& positions, + const core::array >& sourceRects, + const core::rect* clipRect=0, + SColor color=SColor(255,255,255,255), + bool useAlphaChannelOfTexture=false) _IRR_OVERRIDE_; + + //! draw an 2d rectangle + virtual void draw2DRectangle(SColor color, const core::rect& pos, + const core::rect* clip = 0) _IRR_OVERRIDE_; + + //!Draws an 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) _IRR_OVERRIDE_; + + //! Draws a 2d line. + virtual void draw2DLine(const core::position2d& start, + const core::position2d& end, + SColor color=SColor(255,255,255,255)) _IRR_OVERRIDE_; + + //! Draws a single pixel + virtual void drawPixel(u32 x, u32 y, const SColor & color) _IRR_OVERRIDE_; + + //! Draws a 3d line. + virtual void draw3DLine(const core::vector3df& start, + const core::vector3df& end, + SColor color = SColor(255,255,255,255)) _IRR_OVERRIDE_; + + //! Returns the name of the video driver. + virtual const wchar_t* getName() const _IRR_OVERRIDE_; + + //! deletes all dynamic lights there are + virtual void deleteAllDynamicLights() _IRR_OVERRIDE_; + + //! adds a dynamic light + virtual s32 addDynamicLight(const SLight& light) _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! returns the maximal amount of dynamic lights the device can handle + virtual u32 getMaximalDynamicLightAmount() const _IRR_OVERRIDE_; + + //! Sets the dynamic ambient light color. + virtual void setAmbientLight(const SColorf& color) _IRR_OVERRIDE_; + + //! Draws a shadow volume into the stencil buffer. + virtual void drawStencilShadowVolume(const core::array& triangles, bool zfail, u32 debugDataVisible=0) _IRR_OVERRIDE_; + + //! Fills the stencil shadow with color. + virtual void drawStencilShadow(bool clearStencilBuffer=false, + video::SColor leftUpEdge = video::SColor(0,0,0,0), + video::SColor rightUpEdge = video::SColor(0,0,0,0), + video::SColor leftDownEdge = video::SColor(0,0,0,0), + video::SColor rightDownEdge = video::SColor(0,0,0,0)) _IRR_OVERRIDE_; + + //! sets a viewport + virtual void setViewPort(const core::rect& area) _IRR_OVERRIDE_; + + //! Sets the fog mode. + virtual void setFog(SColor color, E_FOG_TYPE fogType, f32 start, + f32 end, f32 density, bool pixelFog, bool rangeFog) _IRR_OVERRIDE_; + + //! Only used internally by the engine + virtual void OnResize(const core::dimension2d& size) _IRR_OVERRIDE_; + + //! Returns type of video driver + virtual E_DRIVER_TYPE getDriverType() const _IRR_OVERRIDE_; + + //! get color format of the current color buffer + virtual ECOLOR_FORMAT getColorFormat() const _IRR_OVERRIDE_; + + //! Returns the transformation set by setTransform + virtual const core::matrix4& getTransform(E_TRANSFORMATION_STATE state) const _IRR_OVERRIDE_; + + //! Can be called by an IMaterialRenderer to make its work easier. + virtual void setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial, + bool resetAllRenderstates) _IRR_OVERRIDE_; + + //! Compare in SMaterial doesn't check texture parameters, so we should call this on each OnRender call. + virtual void setTextureRenderStates(const SMaterial& material, bool resetAllRenderstates); + + //! Get a vertex shader constant index. + virtual s32 getVertexShaderConstantID(const c8* name) _IRR_OVERRIDE_; + + //! Get a pixel shader constant index. + virtual s32 getPixelShaderConstantID(const c8* name) _IRR_OVERRIDE_; + + //! Sets a constant for the vertex shader based on an index. + virtual bool setVertexShaderConstant(s32 index, const f32* floats, int count) _IRR_OVERRIDE_; + + //! Int interface for the above. + virtual bool setVertexShaderConstant(s32 index, const s32* ints, int count) _IRR_OVERRIDE_; + + //! Sets a constant for the pixel shader based on an index. + virtual bool setPixelShaderConstant(s32 index, const f32* floats, int count) _IRR_OVERRIDE_; + + //! Int interface for the above. + virtual bool setPixelShaderConstant(s32 index, const s32* ints, int count) _IRR_OVERRIDE_; + + //! Sets a vertex shader constant. + virtual void setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1) _IRR_OVERRIDE_; + + //! Sets a pixel shader constant. + virtual void setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1) _IRR_OVERRIDE_; + + //! Adds a new material renderer to the VideoDriver + virtual s32 addShaderMaterial(const c8* vertexShaderProgram, const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, E_MATERIAL_TYPE baseMaterial, s32 userData) _IRR_OVERRIDE_; + + //! Adds a new material renderer to the VideoDriver + virtual s32 addHighLevelShaderMaterial(const c8* vertexShaderProgram, const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, const c8* pixelShaderProgram, const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, const c8* geometryShaderProgram, const c8* geometryShaderEntryPointName, + E_GEOMETRY_SHADER_TYPE gsCompileTarget, scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType, + u32 verticesOut, IShaderConstantSetCallBack* callback, E_MATERIAL_TYPE baseMaterial, + s32 userData) _IRR_OVERRIDE_; + + //! Returns pointer to the IGPUProgrammingServices interface. + virtual IGPUProgrammingServices* getGPUProgrammingServices() _IRR_OVERRIDE_; + + //! Returns a pointer to the IVideoDriver interface. + virtual IVideoDriver* getVideoDriver() _IRR_OVERRIDE_; + + //! Returns the maximum amount of primitives + virtual u32 getMaximalPrimitiveCount() const _IRR_OVERRIDE_; + + virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, + const io::path& name, const ECOLOR_FORMAT format = ECF_UNKNOWN) _IRR_OVERRIDE_; + + //! Creates a render target texture for a cubemap + ITexture* addRenderTargetTextureCubemap(const irr::u32 sideLen, + const io::path& name, const ECOLOR_FORMAT format) _IRR_OVERRIDE_; + + virtual bool setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor = SColor(255, 0, 0, 0), + f32 clearDepth = 1.f, u8 clearStencil = 0) _IRR_OVERRIDE_; + + virtual void clearBuffers(u16 flag, SColor color = SColor(255, 0, 0, 0), f32 depth = 1.f, u8 stencil = 0) _IRR_OVERRIDE_; + + //! Returns an image created from the last rendered frame. + virtual IImage* createScreenShot(video::ECOLOR_FORMAT format=video::ECF_UNKNOWN, video::E_RENDER_TARGET target=video::ERT_FRAME_BUFFER) _IRR_OVERRIDE_; + + //! checks if an OpenGL error has happened and prints it (+ some internal code which is usually the line number) + bool testGLError(int code=0); + + //! Set/unset a clipping plane. + virtual bool setClipPlane(u32 index, const core::plane3df& plane, bool enable=false) _IRR_OVERRIDE_; + + //! Enable/disable a clipping plane. + virtual void enableClipPlane(u32 index, bool enable) _IRR_OVERRIDE_; + + //! Returns the graphics card vendor name. + virtual core::stringc getVendorInfo() _IRR_OVERRIDE_ + { + return VendorName; + } + + //! Get the maximal texture size for this driver + virtual core::dimension2du getMaxTextureSize() const _IRR_OVERRIDE_; + + virtual void removeTexture(ITexture* texture) _IRR_OVERRIDE_; + + //! Check if the driver supports creating textures with the given color format + virtual bool queryTextureFormat(ECOLOR_FORMAT format) const _IRR_OVERRIDE_; + + //! Used by some SceneNodes to check if a material should be rendered in the transparent render pass + virtual bool needsTransparentRenderPass(const irr::video::SMaterial& material) const _IRR_OVERRIDE_; + + //! Convert E_BLEND_FACTOR to OpenGL equivalent + GLenum getGLBlend(E_BLEND_FACTOR factor) const; + + //! Get ZBuffer bits. + GLenum getZBufferBits() const; + + bool getColorFormatParameters(ECOLOR_FORMAT format, GLint& internalFormat, GLenum& pixelFormat, + GLenum& pixelType, void(**converter)(const void*, s32, void*)) const; + + COGLES1CacheHandler* getCacheHandler() const; + + private: + void uploadClipPlane(u32 index); + + //! inits the opengl-es driver + bool genericDriverInit(const core::dimension2d& screenSize, bool stencilBuffer); + + virtual ITexture* createDeviceDependentTexture(const io::path& name, IImage* image) _IRR_OVERRIDE_; + + virtual ITexture* createDeviceDependentTextureCubemap(const io::path& name, const core::array& image) _IRR_OVERRIDE_; + + //! creates a transposed matrix in supplied GLfloat array to pass to OGLES1 + inline void getGLMatrix(GLfloat gl_matrix[16], const core::matrix4& m); + inline void getGLTextureMatrix(GLfloat gl_matrix[16], const core::matrix4& m); + + //! Set GL pipeline to desired texture wrap modes of the material + void setWrapMode(const SMaterial& material); + + //! Get OpenGL wrap enum from Irrlicht enum + GLint getTextureWrapMode(u8 clamp) const; + + //! sets the needed renderstates + void setRenderStates3DMode(); + + //! sets the needed renderstates + void setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel); + + 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); + + COGLES1CacheHandler* CacheHandler; + + core::stringw Name; + core::matrix4 Matrices[ETS_COUNT]; + core::array ColorBuffer; + + //! enumeration for rendering modes such as 2d and 3d for minimizing the switching of renderStates. + enum E_RENDER_MODE + { + ERM_NONE = 0, // no render state has been set yet. + ERM_2D, // 2d drawing rendermode + ERM_3D // 3d rendering mode + }; + + E_RENDER_MODE CurrentRenderMode; + //! bool to make all renderstates reset if set to true. + bool ResetRenderStates; + bool Transformation3DChanged; + u8 AntiAlias; + + SMaterial Material, LastMaterial; + core::array UserClipPlane; + core::array UserClipPlaneEnabled; + + core::stringc VendorName; + + core::matrix4 TextureFlipMatrix; + + //! Color buffer format + ECOLOR_FORMAT ColorFormat; + + SIrrlichtCreationParameters Params; + + //! 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; + + IContextManager* ContextManager; + }; + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_OGLES1_ + +#endif diff --git a/source/Irrlicht/COGLESExtensionHandler.cpp b/source/Irrlicht/COGLESExtensionHandler.cpp new file mode 100644 index 00000000..4badf221 --- /dev/null +++ b/source/Irrlicht/COGLESExtensionHandler.cpp @@ -0,0 +1,104 @@ +// Copyright (C) 2008 Christian Stehno +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// 2017 modified by Michael Zeilfelder (unifying extension handlers) +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#include "COGLESExtensionHandler.h" + +#ifdef _IRR_COMPILE_WITH_OGLES1_ + +#include "irrString.h" +#include "SMaterial.h" +#include "fast_atof.h" + +#if defined(_IRR_OGLES1_USE_EXTPOINTER_) +#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_) || defined(_IRR_COMPILE_WITH_FB_DEVICE_) || defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) +#include +#else +#include +#endif +#endif + +namespace irr +{ +namespace video +{ + + COGLES1ExtensionHandler::COGLES1ExtensionHandler() : COGLESCoreExtensionHandler(), + MaxUserClipPlanes(0), MaxLights(0) +#if defined(_IRR_OGLES1_USE_EXTPOINTER_) + , pGlBlendEquationOES(0), pGlBlendFuncSeparateOES(0), + pGlBindFramebufferOES(0), pGlDeleteFramebuffersOES(0), + pGlGenFramebuffersOES(0), pGlCheckFramebufferStatusOES(0), + pGlFramebufferTexture2DOES(0), pGlGenerateMipmapOES(0) +#endif + { + } + + void COGLES1ExtensionHandler::initExtensions() + { + getGLVersion(); + + if (Version >= 100) + os::Printer::log("OpenGL ES driver version is 1.1.", ELL_INFORMATION); + else + os::Printer::log("OpenGL ES driver version is 1.0.", ELL_WARNING); + + getGLExtensions(); + + GLint val = 0; + + if (Version > 100 || FeatureAvailable[IRR_GL_IMG_user_clip_plane]) + { + glGetIntegerv(GL_MAX_CLIP_PLANES, &val); + MaxUserClipPlanes = static_cast(val); + } + + glGetIntegerv(GL_MAX_LIGHTS, &val); + MaxLights = static_cast(val); + + glGetIntegerv(GL_MAX_TEXTURE_UNITS, &val); + Feature.MaxTextureUnits = static_cast(val); + +#ifdef GL_EXT_texture_filter_anisotropic + if (FeatureAvailable[IRR_GL_EXT_texture_filter_anisotropic]) + { + glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &val); + MaxAnisotropy = static_cast(val); + } +#endif +#ifdef GL_MAX_ELEMENTS_INDICES + glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &val); + MaxIndices = val; +#endif + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &val); + MaxTextureSize = static_cast(val); +#ifdef GL_EXT_texture_lod_bias + if (FeatureAvailable[IRR_GL_EXT_texture_lod_bias]) + glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS_EXT, &MaxTextureLODBias); +#endif + glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, DimAliasedLine); + glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, DimAliasedPoint); + + Feature.MaxTextureUnits = core::min_(Feature.MaxTextureUnits, static_cast(MATERIAL_MAX_TEXTURES)); + Feature.MaxTextureUnits = core::min_(Feature.MaxTextureUnits, static_cast(MATERIAL_MAX_TEXTURES_USED)); + Feature.ColorAttachment = 1; + +#if defined(_IRR_OGLES1_USE_EXTPOINTER_) + pGlBlendEquationOES = (PFNGLBLENDEQUATIONOESPROC)eglGetProcAddress("glBlendEquationOES"); + pGlBlendFuncSeparateOES = (PFNGLBLENDFUNCSEPARATEOESPROC)eglGetProcAddress("glBlendFuncSeparateOES"); + pGlBindFramebufferOES = (PFNGLBINDFRAMEBUFFEROESPROC)eglGetProcAddress("glBindFramebufferOES"); + pGlDeleteFramebuffersOES = (PFNGLDELETEFRAMEBUFFERSOESPROC)eglGetProcAddress("glDeleteFramebuffersOES"); + pGlGenFramebuffersOES = (PFNGLGENFRAMEBUFFERSOESPROC)eglGetProcAddress("glGenFramebuffersOES"); + pGlCheckFramebufferStatusOES = (PFNGLCHECKFRAMEBUFFERSTATUSOESPROC)eglGetProcAddress("glCheckFramebufferStatusOES"); + pGlFramebufferTexture2DOES = (PFNGLFRAMEBUFFERTEXTURE2DOESPROC)eglGetProcAddress("glFramebufferTexture2DOES"); + pGlGenerateMipmapOES = (PFNGLGENERATEMIPMAPOESPROC)eglGetProcAddress("glGenerateMipmapOES"); +#endif + } + +} // end namespace video +} // end namespace irr + + +#endif // _IRR_COMPILE_WITH_OGLES2_ diff --git a/source/Irrlicht/COGLESExtensionHandler.h b/source/Irrlicht/COGLESExtensionHandler.h new file mode 100644 index 00000000..efed7939 --- /dev/null +++ b/source/Irrlicht/COGLESExtensionHandler.h @@ -0,0 +1,240 @@ +// Copyright (C) 2008 Christian Stehno +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __C_OGLES_EXTENSION_HANDLER_H_INCLUDED__ +#define __C_OGLES_EXTENSION_HANDLER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OGLES1_ + +#include "EDriverFeatures.h" +#include "irrTypes.h" +#include "os.h" + +#include "COGLESCommon.h" + +#include "COGLESCoreExtensionHandler.h" + +namespace irr +{ +namespace video +{ + + class COGLES1ExtensionHandler : public COGLESCoreExtensionHandler + { + public: + COGLES1ExtensionHandler(); + + void initExtensions(); + + bool queryFeature(video::E_VIDEO_DRIVER_FEATURE feature) const + { + switch (feature) + { + case EVDF_RENDER_TO_TARGET: + case EVDF_HARDWARE_TL: + case EVDF_MULTITEXTURE: + case EVDF_BILINEAR_FILTER: + case EVDF_MIP_MAP: + case EVDF_TEXTURE_NSQUARE: + case EVDF_STENCIL_BUFFER: + case EVDF_ALPHA_TO_COVERAGE: + case EVDF_COLOR_MASK: + case EVDF_POLYGON_OFFSET: + case EVDF_TEXTURE_MATRIX: + return true; + case EVDF_TEXTURE_NPOT: + return FeatureAvailable[IRR_GL_APPLE_texture_2D_limited_npot] || FeatureAvailable[IRR_GL_OES_texture_npot]; + case EVDF_MIP_MAP_AUTO_UPDATE: + return Version>100; + case EVDF_BLEND_OPERATIONS: + return FeatureAvailable[IRR_GL_OES_blend_subtract]; + case EVDF_BLEND_SEPARATE: + return FeatureAvailable[IRR_GL_OES_blend_func_separate]; + case EVDF_FRAMEBUFFER_OBJECT: + return FeatureAvailable[IRR_GL_OES_framebuffer_object]; + case EVDF_VERTEX_BUFFER_OBJECT: + return Version>100; + case EVDF_TEXTURE_COMPRESSED_DXT: + return false; // NV Tegra need improvements here + case EVDF_TEXTURE_COMPRESSED_PVRTC: + return FeatureAvailable[IRR_GL_IMG_texture_compression_pvrtc]; + case EVDF_TEXTURE_COMPRESSED_ETC1: + return FeatureAvailable[IRR_GL_OES_compressed_ETC1_RGB8_texture]; + case EVDF_TEXTURE_CUBEMAP: + return FeatureAvailable[IRR_GL_OES_texture_cube_map]; + default: + return true; + }; + } + + inline void irrGlActiveTexture(GLenum texture) + { + glActiveTexture(texture); + } + + inline void irrGlCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, + GLsizei imageSize, const void* data) + { + glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); + } + + inline void irrGlCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLsizei imageSize, const void* data) + { + glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); + } + + inline void irrGlUseProgram(GLuint prog) + { + } + + inline void irrGlBindFramebuffer(GLenum target, GLuint framebuffer) + { +#ifdef _IRR_OGLES1_USE_EXTPOINTER_ + if (pGlBindFramebufferOES) + pGlBindFramebufferOES(target, framebuffer); +#elif defined(GL_OES_framebuffer_object) + glBindFramebufferOES(target, framebuffer); +#endif + } + + inline void irrGlDeleteFramebuffers(GLsizei n, const GLuint *framebuffers) + { +#ifdef _IRR_OGLES1_USE_EXTPOINTER_ + if (pGlDeleteFramebuffersOES) + pGlDeleteFramebuffersOES(n, framebuffers); +#elif defined(GL_OES_framebuffer_object) + glDeleteFramebuffersOES(n, framebuffers); +#endif + } + + inline void irrGlGenFramebuffers(GLsizei n, GLuint *framebuffers) + { +#ifdef _IRR_OGLES1_USE_EXTPOINTER_ + if (pGlGenFramebuffersOES) + pGlGenFramebuffersOES(n, framebuffers); +#elif defined(GL_OES_framebuffer_object) + glGenFramebuffersOES(n, framebuffers); +#endif + } + + inline GLenum irrGlCheckFramebufferStatus(GLenum target) + { +#ifdef _IRR_OGLES1_USE_EXTPOINTER_ + if (pGlCheckFramebufferStatusOES) + return pGlCheckFramebufferStatusOES(target); + else + return 0; +#elif defined(GL_OES_framebuffer_object) + return glCheckFramebufferStatusOES(target); +#else + return 0; +#endif + } + + inline void irrGlFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) + { +#ifdef _IRR_OGLES1_USE_EXTPOINTER_ + if (pGlFramebufferTexture2DOES) + pGlFramebufferTexture2DOES(target, attachment, textarget, texture, level); +#elif defined(GL_OES_framebuffer_object) + glFramebufferTexture2DOES(target, attachment, textarget, texture, level); +#endif + } + + inline void irrGlGenerateMipmap(GLenum target) + { +#ifdef _IRR_OGLES1_USE_EXTPOINTER_ + if (pGlGenerateMipmapOES) + pGlGenerateMipmapOES(target); +#elif defined(GL_OES_framebuffer_object) + glGenerateMipmapOES(target); +#endif + } + + inline void irrGlActiveStencilFace(GLenum face) + { + } + + inline void irrGlDrawBuffer(GLenum mode) + { + } + + inline void irrGlDrawBuffers(GLsizei n, const GLenum *bufs) + { + } + + inline void irrGlBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) + { +#ifdef _IRR_OGLES1_USE_EXTPOINTER_ + if (pGlBlendFuncSeparateOES) + pGlBlendFuncSeparateOES(srcRGB, dstRGB, srcAlpha, dstAlpha); +#elif defined(GL_OES_blend_func_separate) + glBlendFuncSeparateOES(srcRGB, dstRGB, srcAlpha, dstAlpha); +#endif + } + + inline void irrGlBlendEquation(GLenum mode) + { +#ifdef _IRR_OGLES1_USE_EXTPOINTER_ + if (pGlBlendEquationOES) + pGlBlendEquationOES(mode); +#elif defined(GL_OES_blend_subtract) + glBlendEquationOES(mode); +#endif + } + + inline void irrGlEnableIndexed(GLenum target, GLuint index) + { + } + + inline void irrGlDisableIndexed(GLenum target, GLuint index) + { + } + + inline void irrGlColorMaskIndexed(GLuint buf, GLboolean r, GLboolean g, GLboolean b, GLboolean a) + { + } + + inline void irrGlBlendFuncIndexed(GLuint buf, GLenum src, GLenum dst) + { + } + + inline void irrGlBlendFuncSeparateIndexed(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) + { + } + + inline void irrGlBlendEquationIndexed(GLuint buf, GLenum mode) + { + } + + inline void irrGlBlendEquationSeparateIndexed(GLuint buf, GLenum modeRGB, GLenum modeAlpha) + { + } + + protected: + + u8 MaxUserClipPlanes; + u8 MaxLights; + +#if defined(_IRR_OGLES1_USE_EXTPOINTER_) + PFNGLBLENDEQUATIONOESPROC pGlBlendEquationOES; + PFNGLBLENDFUNCSEPARATEOESPROC pGlBlendFuncSeparateOES; + PFNGLBINDFRAMEBUFFEROESPROC pGlBindFramebufferOES; + PFNGLDELETEFRAMEBUFFERSOESPROC pGlDeleteFramebuffersOES; + PFNGLGENFRAMEBUFFERSOESPROC pGlGenFramebuffersOES; + PFNGLCHECKFRAMEBUFFERSTATUSOESPROC pGlCheckFramebufferStatusOES; + PFNGLFRAMEBUFFERTEXTURE2DOESPROC pGlFramebufferTexture2DOES; + PFNGLGENERATEMIPMAPOESPROC pGlGenerateMipmapOES; +#endif + }; + +} +} + +#endif +#endif diff --git a/source/Irrlicht/COGLESMaterialRenderer.h b/source/Irrlicht/COGLESMaterialRenderer.h new file mode 100644 index 00000000..8a811cb9 --- /dev/null +++ b/source/Irrlicht/COGLESMaterialRenderer.h @@ -0,0 +1,615 @@ +// 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 __C_OGLES1_MATERIAL_RENDERER_H_INCLUDED__ +#define __C_OGLES1_MATERIAL_RENDERER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_OGLES1_ + +#include "COGLESDriver.h" +#include "IMaterialRenderer.h" + +namespace irr +{ +namespace video +{ + +//! Base class for all internal OGLES1 material renderers +class COGLES1MaterialRenderer : public IMaterialRenderer +{ +public: + + //! Constructor + COGLES1MaterialRenderer(video::COGLES1Driver* driver) : Driver(driver) + { + } + +protected: + + video::COGLES1Driver* Driver; +}; + + +//! Solid material renderer +class COGLES1MaterialRenderer_SOLID : public COGLES1MaterialRenderer +{ +public: + + COGLES1MaterialRenderer_SOLID(video::COGLES1Driver* d) + : COGLES1MaterialRenderer(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) + { + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (resetAllRenderstates || (material.MaterialType != lastMaterial.MaterialType)) + { + // thanks to Murphy, the following line removed some + // bugs with several OGLES1 implementations. + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + } +}; + + +//! Generic Texture Blend +class COGLES1MaterialRenderer_ONETEXTURE_BLEND : public COGLES1MaterialRenderer +{ +public: + + COGLES1MaterialRenderer_ONETEXTURE_BLEND(video::COGLES1Driver* d) + : COGLES1MaterialRenderer(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) + { + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + +// if (material.MaterialType != lastMaterial.MaterialType || +// material.MaterialTypeParam != lastMaterial.MaterialTypeParam || +// resetAllRenderstates) + { + E_BLEND_FACTOR srcRGBFact,dstRGBFact,srcAlphaFact,dstAlphaFact; + E_MODULATE_FUNC modulate; + u32 alphaSource; + unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulate, alphaSource, material.MaterialTypeParam); + + Driver->getCacheHandler()->setBlend(true); + + if (Driver->queryFeature(EVDF_BLEND_SEPARATE)) + { + Driver->getCacheHandler()->setBlendFuncSeparate(Driver->getGLBlend(srcRGBFact), Driver->getGLBlend(dstRGBFact), + Driver->getGLBlend(srcAlphaFact), Driver->getGLBlend(dstAlphaFact)); + } + else + { + Driver->getCacheHandler()->setBlendFunc(Driver->getGLBlend(srcRGBFact), Driver->getGLBlend(dstRGBFact)); + } + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS); + + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, (f32) modulate ); + + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0.f); + + if (textureBlendFunc_hasAlpha(srcRGBFact) || textureBlendFunc_hasAlpha(dstRGBFact) || + textureBlendFunc_hasAlpha(srcAlphaFact) || textureBlendFunc_hasAlpha(dstAlphaFact)) + { + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE); + + glTexEnvf(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR); + } + } + } + + virtual void OnUnsetMaterial() + { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 1.f ); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS); + + Driver->getCacheHandler()->setBlend(false); + glDisable(GL_ALPHA_TEST); + } + + //! Returns if the material is transparent. + /** Is not always transparent, but mostly. */ + virtual bool isTransparent() const + { + return true; + } + + private: + + u32 getGLBlend ( E_BLEND_FACTOR factor ) const + { + u32 r = 0; + switch ( factor ) + { + case EBF_ZERO: r = GL_ZERO; break; + case EBF_ONE: r = GL_ONE; break; + case EBF_DST_COLOR: r = GL_DST_COLOR; break; + case EBF_ONE_MINUS_DST_COLOR: r = GL_ONE_MINUS_DST_COLOR; break; + case EBF_SRC_COLOR: r = GL_SRC_COLOR; break; + case EBF_ONE_MINUS_SRC_COLOR: r = GL_ONE_MINUS_SRC_COLOR; break; + case EBF_SRC_ALPHA: r = GL_SRC_ALPHA; break; + case EBF_ONE_MINUS_SRC_ALPHA: r = GL_ONE_MINUS_SRC_ALPHA; break; + case EBF_DST_ALPHA: r = GL_DST_ALPHA; break; + case EBF_ONE_MINUS_DST_ALPHA: r = GL_ONE_MINUS_DST_ALPHA; break; + case EBF_SRC_ALPHA_SATURATE: r = GL_SRC_ALPHA_SATURATE; break; + } + return r; + } +}; + + +//! Solid 2 layer material renderer +class COGLES1MaterialRenderer_SOLID_2_LAYER : public COGLES1MaterialRenderer +{ +public: + + COGLES1MaterialRenderer_SOLID_2_LAYER(video::COGLES1Driver* d) + : COGLES1MaterialRenderer(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) + { + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR); + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_PRIMARY_COLOR); + glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA); + } + } + } + + virtual void OnUnsetMaterial() + { + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR); + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0); + } + } +}; + + +//! Transparent add color material renderer +class COGLES1MaterialRenderer_TRANSPARENT_ADD_COLOR : public COGLES1MaterialRenderer +{ +public: + + COGLES1MaterialRenderer_TRANSPARENT_ADD_COLOR(video::COGLES1Driver* d) + : COGLES1MaterialRenderer(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) + { + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + Driver->getCacheHandler()->setBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); + Driver->getCacheHandler()->setBlend(true); + + if ((material.MaterialType != lastMaterial.MaterialType) || resetAllRenderstates) + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + + virtual void OnUnsetMaterial() + { + Driver->getCacheHandler()->setBlend(false); + } + + //! Returns if the material is transparent. + virtual bool isTransparent() const + { + return true; + } +}; + + +//! Transparent vertex alpha material renderer +class COGLES1MaterialRenderer_TRANSPARENT_VERTEX_ALPHA : public COGLES1MaterialRenderer +{ +public: + + COGLES1MaterialRenderer_TRANSPARENT_VERTEX_ALPHA(video::COGLES1Driver* d) + : COGLES1MaterialRenderer(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) + { + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + Driver->getCacheHandler()->setBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + Driver->getCacheHandler()->setBlend(true); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR ); + + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR ); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE); + } + } + + virtual void OnUnsetMaterial() + { + // default values + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE ); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE ); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS ); + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE ); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS); + + Driver->getCacheHandler()->setBlend(false); + } + + //! Returns if the material is transparent. + virtual bool isTransparent() const + { + return true; + } +}; + + +//! Transparent alpha channel material renderer +class COGLES1MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL : public COGLES1MaterialRenderer +{ +public: + + COGLES1MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL(video::COGLES1Driver* d) + : COGLES1MaterialRenderer(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) + { + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + Driver->getCacheHandler()->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + Driver->getCacheHandler()->setBlend(true); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates + || material.MaterialTypeParam != lastMaterial.MaterialTypeParam ) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS); + + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE); + + glEnable(GL_ALPHA_TEST); + + glAlphaFunc(GL_GREATER, material.MaterialTypeParam); + } + } + + virtual void OnUnsetMaterial() + { + glDisable(GL_ALPHA_TEST); + Driver->getCacheHandler()->setBlend(false); + } + + //! Returns if the material is transparent. + virtual bool isTransparent() const + { + return true; + } +}; + + + +//! Transparent alpha channel material renderer +class COGLES1MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF : public COGLES1MaterialRenderer +{ +public: + + COGLES1MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF(video::COGLES1Driver* d) + : COGLES1MaterialRenderer(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) + { + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0.5f); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + } + + virtual void OnUnsetMaterial() + { + glDisable(GL_ALPHA_TEST); + } + + //! Returns if the material is transparent. + virtual bool isTransparent() const + { + return false; // this material is not really transparent because it does no blending. + } +}; + + +//! material renderer for all kinds of lightmaps +class COGLES1MaterialRenderer_LIGHTMAP : public COGLES1MaterialRenderer +{ +public: + + COGLES1MaterialRenderer_LIGHTMAP(video::COGLES1Driver* d) + : COGLES1MaterialRenderer(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) + { + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + // diffuse map + + switch (material.MaterialType) + { + case EMT_LIGHTMAP_LIGHTING: + case EMT_LIGHTMAP_LIGHTING_M2: + case EMT_LIGHTMAP_LIGHTING_M4: + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + break; + case EMT_LIGHTMAP_ADD: + case EMT_LIGHTMAP: + case EMT_LIGHTMAP_M2: + case EMT_LIGHTMAP_M4: + default: + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + break; + } + + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + // lightmap + + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + + if (material.MaterialType == EMT_LIGHTMAP_ADD) + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD); + else + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE); + + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS); + + switch (material.MaterialType) + { + case EMT_LIGHTMAP_M4: + case EMT_LIGHTMAP_LIGHTING_M4: + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 4.0f); + break; + case EMT_LIGHTMAP_M2: + case EMT_LIGHTMAP_LIGHTING_M2: + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 2.0f); + break; + default: + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 1.0f); + } + } + } + } + + virtual void OnUnsetMaterial() + { + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1); + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 1.f ); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + } +}; + +class COGLES1MaterialRenderer_DETAIL_MAP : public COGLES1MaterialRenderer +{ +public: + COGLES1MaterialRenderer_DETAIL_MAP(video::COGLES1Driver* d) : COGLES1MaterialRenderer(d) + { + } + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD_SIGNED); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE); + } + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0); + } +}; + + +//! sphere map material renderer +class COGLES1MaterialRenderer_SPHERE_MAP : public COGLES1MaterialRenderer +{ +public: + + COGLES1MaterialRenderer_SPHERE_MAP(video::COGLES1Driver* d) + : COGLES1MaterialRenderer(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) + { + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { +// glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); +// glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + +// glEnable(GL_TEXTURE_GEN_S); +// glEnable(GL_TEXTURE_GEN_T); + } + } + + virtual void OnUnsetMaterial() + { +// glDisable(GL_TEXTURE_GEN_S); +// glDisable(GL_TEXTURE_GEN_T); + } +}; + + +//! reflection 2 layer material renderer +class COGLES1MaterialRenderer_REFLECTION_2_LAYER : public COGLES1MaterialRenderer +{ +public: + + COGLES1MaterialRenderer_REFLECTION_2_LAYER(video::COGLES1Driver* d) + : COGLES1MaterialRenderer(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) + { + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE); + + } +// glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); +// glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); +// glEnable(GL_TEXTURE_GEN_S); +// glEnable(GL_TEXTURE_GEN_T); + } + } + + virtual void OnUnsetMaterial() + { + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } +// glDisable(GL_TEXTURE_GEN_S); +// glDisable(GL_TEXTURE_GEN_T); + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0); + } + } +}; + + +//! reflection 2 layer material renderer +class COGLES1MaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER : public COGLES1MaterialRenderer +{ +public: + + COGLES1MaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER(video::COGLES1Driver* d) + : COGLES1MaterialRenderer(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) + { + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + Driver->getCacheHandler()->setBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); + Driver->getCacheHandler()->setBlend(true); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE); + } +// glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); +// glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); +// glEnable(GL_TEXTURE_GEN_S); +// glEnable(GL_TEXTURE_GEN_T); + } + } + + virtual void OnUnsetMaterial() + { + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } +// glDisable(GL_TEXTURE_GEN_S); +// glDisable(GL_TEXTURE_GEN_T); + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0); + } + Driver->getCacheHandler()->setBlend(false); + } + + //! Returns if the material is transparent. + virtual bool isTransparent() const + { + return true; + } +}; + +} // end namespace video +} // end namespace irr + +#endif +#endif diff --git a/source/Irrlicht/COSOperator.cpp b/source/Irrlicht/COSOperator.cpp new file mode 100644 index 00000000..1bdbdc16 --- /dev/null +++ b/source/Irrlicht/COSOperator.cpp @@ -0,0 +1,276 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "COSOperator.h" + +#ifdef _IRR_WINDOWS_API_ +#ifndef _IRR_XBOX_PLATFORM_ +#include +#endif +#else +#include +#include +#ifndef _IRR_ANDROID_PLATFORM_ +#include +#ifdef _IRR_OSX_PLATFORM_ +#include +#endif +#endif +#endif + +#if defined(_IRR_COMPILE_WITH_X11_DEVICE_) +#include "CIrrDeviceLinux.h" +#endif +#if defined(_IRR_COMPILE_WITH_OSX_DEVICE_) +#import +#endif + +#include "fast_atof.h" + +namespace irr +{ + +#if defined(_IRR_COMPILE_WITH_X11_DEVICE_) +// constructor linux + COSOperator::COSOperator(const core::stringc& osVersion, CIrrDeviceLinux* device) +: OperatingSystem(osVersion), IrrDeviceLinux(device) +{ +} +#endif + +// constructor +COSOperator::COSOperator(const core::stringc& osVersion) : OperatingSystem(osVersion) +{ + #ifdef _DEBUG + setDebugName("COSOperator"); + #endif +} + + +//! returns the current operating system version as string. +const core::stringc& COSOperator::getOperatingSystemVersion() const +{ + return OperatingSystem; +} + + +//! copies text to the clipboard +void COSOperator::copyToClipboard(const c8* text) const +{ + if (strlen(text)==0) + return; + +// Windows version +#if defined(_IRR_XBOX_PLATFORM_) +#elif defined(_IRR_WINDOWS_API_) + if (!OpenClipboard(NULL) || text == 0) + return; + + EmptyClipboard(); + + HGLOBAL clipbuffer; + char * buffer; + + clipbuffer = GlobalAlloc(GMEM_DDESHARE, strlen(text)+1); + buffer = (char*)GlobalLock(clipbuffer); + + strcpy(buffer, text); + + GlobalUnlock(clipbuffer); + SetClipboardData(CF_TEXT, clipbuffer); + CloseClipboard(); + +#elif defined(_IRR_COMPILE_WITH_OSX_DEVICE_) + NSString *str = nil; + NSPasteboard *board = nil; + + if ((text != NULL) && (strlen(text) > 0)) + { + str = [NSString stringWithCString:text encoding:NSWindowsCP1252StringEncoding]; + board = [NSPasteboard generalPasteboard]; + [board declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:NSApp]; + [board setString:str forType:NSStringPboardType]; + } + +#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_) + if ( IrrDeviceLinux ) + IrrDeviceLinux->copyToClipboard(text); +#else + +#endif +} + + +//! gets text from the clipboard +//! \return Returns 0 if no string is in there. +const c8* COSOperator::getTextFromClipboard() const +{ +#if defined(_IRR_XBOX_PLATFORM_) + return 0; +#elif defined(_IRR_WINDOWS_API_) + if (!OpenClipboard(NULL)) + return 0; + + char * buffer = 0; + + HANDLE hData = GetClipboardData( CF_TEXT ); + buffer = (char*)GlobalLock( hData ); + GlobalUnlock( hData ); + CloseClipboard(); + return buffer; + +#elif defined(_IRR_COMPILE_WITH_OSX_DEVICE_) + NSString* str = nil; + NSPasteboard* board = nil; + char* result = 0; + + board = [NSPasteboard generalPasteboard]; + str = [board stringForType:NSStringPboardType]; + + if (str != nil) + result = (char*)[str cStringUsingEncoding:NSWindowsCP1252StringEncoding]; + + return (result); + +#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_) + if ( IrrDeviceLinux ) + return IrrDeviceLinux->getTextFromClipboard(); + return 0; + +#else + + return 0; +#endif +} + + +bool COSOperator::getProcessorSpeedMHz(u32* MHz) const +{ + if (MHz) + *MHz=0; +#if defined(_IRR_WINDOWS_API_) && !defined(_WIN32_WCE ) && !defined (_IRR_XBOX_PLATFORM_) + LONG Error; + + HKEY Key; + Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + __TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), + 0, KEY_READ, &Key); + + if(Error != ERROR_SUCCESS) + return false; + + DWORD Speed = 0; + DWORD Size = sizeof(Speed); + Error = RegQueryValueEx(Key, __TEXT("~MHz"), NULL, NULL, (LPBYTE)&Speed, &Size); + + RegCloseKey(Key); + + if (Error != ERROR_SUCCESS) + return false; + else if (MHz) + *MHz = Speed; + return true; + +#elif defined(_IRR_OSX_PLATFORM_) + struct clockinfo CpuClock; + size_t Size = sizeof(clockinfo); + + if (!sysctlbyname("kern.clockrate", &CpuClock, &Size, NULL, 0)) + return false; + else if (MHz) + *MHz = CpuClock.hz; + return true; +#else + // read from "/proc/cpuinfo" + FILE* file = fopen("/proc/cpuinfo", "r"); + if (file) + { + char buffer[1024]; + fread(buffer, 1, 1024, file); + buffer[1023]=0; + core::stringc str(buffer); + s32 pos = str.find("cpu MHz"); + if (pos != -1) + { + pos = str.findNext(':', pos); + if (pos != -1) + { + while ( str[++pos] == ' ' ); + *MHz = core::fast_atof(str.c_str()+pos); + } + } + fclose(file); + } + return (MHz && *MHz != 0); +#endif +} + +bool COSOperator::getSystemMemory(u32* Total, u32* Avail) const +{ +#if defined(_IRR_WINDOWS_API_) && !defined (_IRR_XBOX_PLATFORM_) + + #if (_WIN32_WINNT >= 0x0500) + MEMORYSTATUSEX MemoryStatusEx; + MemoryStatusEx.dwLength = sizeof(MEMORYSTATUSEX); + + // cannot fail + GlobalMemoryStatusEx(&MemoryStatusEx); + + if (Total) + *Total = (u32)(MemoryStatusEx.ullTotalPhys>>10); + if (Avail) + *Avail = (u32)(MemoryStatusEx.ullAvailPhys>>10); + return true; + #else + MEMORYSTATUS MemoryStatus; + MemoryStatus.dwLength = sizeof(MEMORYSTATUS); + + // cannot fail + GlobalMemoryStatus(&MemoryStatus); + + if (Total) + *Total = (u32)(MemoryStatus.dwTotalPhys>>10); + if (Avail) + *Avail = (u32)(MemoryStatus.dwAvailPhys>>10); + return true; + #endif + +#elif defined(_IRR_POSIX_API_) && !defined(__FreeBSD__) +#if defined(_SC_PHYS_PAGES) && defined(_SC_AVPHYS_PAGES) + long ps = sysconf(_SC_PAGESIZE); + long pp = sysconf(_SC_PHYS_PAGES); + long ap = sysconf(_SC_AVPHYS_PAGES); + + if ((ps==-1)||(pp==-1)||(ap==-1)) + return false; + + if (Total) + *Total = (u32)((ps*(long long)pp)>>10); + if (Avail) + *Avail = (u32)((ps*(long long)ap)>>10); + return true; +#else + // TODO: implement for non-availability of symbols/features + return false; +#endif +#elif defined(_IRR_OSX_PLATFORM_) + int mib[2]; + int64_t physical_memory; + size_t length; + + // Get the Physical memory size + mib[0] = CTL_HW; + mib[1] = HW_MEMSIZE; + length = sizeof(int64_t); + sysctl(mib, 2, &physical_memory, &length, NULL, 0); + return true; +#else + // TODO: implement for others + return false; +#endif +} + + +} // end namespace + diff --git a/source/Irrlicht/COSOperator.h b/source/Irrlicht/COSOperator.h new file mode 100644 index 00000000..d913b863 --- /dev/null +++ b/source/Irrlicht/COSOperator.h @@ -0,0 +1,60 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OS_OPERATOR_H_INCLUDED__ +#define __C_OS_OPERATOR_H_INCLUDED__ + +#include "IOSOperator.h" + +namespace irr +{ + +class CIrrDeviceLinux; + +//! The Operating system operator provides operation system specific methods and information. +class COSOperator : public IOSOperator +{ +public: + + // constructor +#if defined(_IRR_COMPILE_WITH_X11_DEVICE_) + COSOperator(const core::stringc& osversion, CIrrDeviceLinux* device); +#endif + COSOperator(const core::stringc& osversion); + + //! returns the current operation system version as string. + virtual const core::stringc& getOperatingSystemVersion() const _IRR_OVERRIDE_; + + //! copies text to the clipboard + virtual void copyToClipboard(const c8* text) const _IRR_OVERRIDE_; + + //! gets text from the clipboard + //! \return Returns 0 if no string is in there. + virtual const c8* getTextFromClipboard() const _IRR_OVERRIDE_; + + //! gets the processor speed in megahertz + //! \param Mhz: + //! \return Returns true if successful, false if not + virtual bool getProcessorSpeedMHz(u32* MHz) const _IRR_OVERRIDE_; + + //! gets the total and available system RAM in kB + //! \param Total: will contain the total system memory + //! \param Avail: will contain the available memory + //! \return Returns true if successful, false if not + virtual bool getSystemMemory(u32* Total, u32* Avail) const _IRR_OVERRIDE_; + +private: + + core::stringc OperatingSystem; + +#if defined(_IRR_COMPILE_WITH_X11_DEVICE_) + CIrrDeviceLinux * IrrDeviceLinux; +#endif + +}; + +} // end namespace + +#endif + diff --git a/source/Irrlicht/COctreeSceneNode.cpp b/source/Irrlicht/COctreeSceneNode.cpp new file mode 100644 index 00000000..16df1199 --- /dev/null +++ b/source/Irrlicht/COctreeSceneNode.cpp @@ -0,0 +1,677 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_OCTREE_SCENENODE_ + +#include "COctreeSceneNode.h" +#include "Octree.h" +#include "ISceneManager.h" +#include "IVideoDriver.h" +#include "ICameraSceneNode.h" +#include "IMeshCache.h" +#include "IAnimatedMesh.h" +#include "IMaterialRenderer.h" +#include "os.h" +#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ +#include "CShadowVolumeSceneNode.h" +#else +#include "IShadowVolumeSceneNode.h" +#endif // _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ +#include "EProfileIDs.h" +#include "IProfiler.h" + +namespace irr +{ +namespace scene +{ + + +//! constructor +COctreeSceneNode::COctreeSceneNode(ISceneNode* parent, ISceneManager* mgr, + s32 id, s32 minimalPolysPerNode) + : IOctreeSceneNode(parent, mgr, id), StdOctree(0), LightMapOctree(0), + TangentsOctree(0), VertexType((video::E_VERTEX_TYPE)-1), + MinimalPolysPerNode(minimalPolysPerNode), Mesh(0), Shadow(0), + UseVBOs(EOV_NO_VBO), PolygonChecks(EOPC_BOX) +{ +#ifdef _DEBUG + setDebugName("COctreeSceneNode"); +#endif + + IRR_PROFILE( + static bool initProfile = false; + if (!initProfile ) + { + initProfile = true; + getProfiler().add(EPID_OC_RENDER, L"render octnode", L"Irrlicht scene"); + getProfiler().add(EPID_OC_CALCPOLYS, L"calc octnode", L"Irrlicht scene"); + } + ) +} + + +//! destructor +COctreeSceneNode::~COctreeSceneNode() +{ + if (Shadow) + Shadow->drop(); + deleteTree(); +} + + +void COctreeSceneNode::OnRegisterSceneNode() +{ + if (IsVisible) + { + // because this node supports rendering of mixed mode meshes consisting of + // transparent and solid material at the same time, we need to go through all + // materials, check of what type they are and register this node for the right + // render pass according to that. + + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + + PassCount = 0; + u32 transparentCount = 0; + u32 solidCount = 0; + + // count transparent and solid materials in this scene node + for (u32 i=0; ineedsTransparentRenderPass(Materials[i])) + ++transparentCount; + else + ++solidCount; + + if (solidCount && transparentCount) + break; + } + + // register according to material types counted + + if (solidCount) + SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID); + + if (transparentCount) + SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT); + + ISceneNode::OnRegisterSceneNode(); + } +} + +template +void renderMeshBuffer(video::IVideoDriver* driver, EOCTREENODE_VBO useVBO, typename Octree::SMeshChunk& meshChunk, const typename Octree::SIndexData& indexData) +{ + switch ( useVBO ) + { + case EOV_NO_VBO: + driver->drawIndexedTriangleList( + &meshChunk.Vertices[0], + meshChunk.Vertices.size(), + indexData.Indices, indexData.CurrentSize / 3); + break; + case EOV_USE_VBO: + driver->drawMeshBuffer ( &meshChunk ); + break; + case EOV_USE_VBO_WITH_VISIBITLY: + { + u16* oldPointer = meshChunk.Indices.pointer(); + const u32 oldSize = meshChunk.Indices.size(); + meshChunk.Indices.set_free_when_destroyed(false); + meshChunk.Indices.set_pointer(indexData.Indices, indexData.CurrentSize, false, false); + meshChunk.setDirty(scene::EBT_INDEX); + driver->drawMeshBuffer ( &meshChunk ); + meshChunk.Indices.set_pointer(oldPointer, oldSize); + meshChunk.setDirty(scene::EBT_INDEX); + break; + } + } +} + +//! renders the node. +void COctreeSceneNode::render() +{ + IRR_PROFILE(CProfileScope psRender(EPID_OC_RENDER);) + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + + if (!driver) + return; + + ICameraSceneNode* camera = SceneManager->getActiveCamera(); + if (!camera) + return; + + const bool isTransparentPass = + SceneManager->getSceneNodeRenderPass() == scene::ESNRP_TRANSPARENT; + ++PassCount; + + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + + if (Shadow) + Shadow->updateShadowVolumes(); + + SViewFrustum frust = *camera->getViewFrustum(); + + //transform the frustum to the current absolute transformation + if ( !AbsoluteTransformation.isIdentity() ) + { + core::matrix4 invTrans(AbsoluteTransformation, core::matrix4::EM4CONST_INVERSE); + frust.transform(invTrans); + } + + const core::aabbox3d &box = frust.getBoundingBox(); + + switch (VertexType) + { + case video::EVT_STANDARD: + { + IRR_PROFILE(getProfiler().start(EPID_OC_CALCPOLYS)); + switch ( PolygonChecks ) + { + case EOPC_BOX: + StdOctree->calculatePolys(box); + break; + case EOPC_FRUSTUM: + StdOctree->calculatePolys(frust); + break; + } + IRR_PROFILE(getProfiler().stop(EPID_OC_CALCPOLYS)); + + const Octree::SIndexData* d = StdOctree->getIndexData(); + + for (u32 i=0; ineedsTransparentRenderPass(Materials[i]); + + // only render transparent buffer if this is the transparent render pass + // and solid only in solid pass + if (transparent == isTransparentPass) + { + driver->setMaterial(Materials[i]); + renderMeshBuffer(driver, UseVBOs, StdMeshes[i], d[i]); + } + } + } + break; + case video::EVT_2TCOORDS: + { + IRR_PROFILE(getProfiler().start(EPID_OC_CALCPOLYS)); + switch ( PolygonChecks ) + { + case EOPC_BOX: + LightMapOctree->calculatePolys(box); + break; + case EOPC_FRUSTUM: + LightMapOctree->calculatePolys(frust); + break; + } + IRR_PROFILE(getProfiler().stop(EPID_OC_CALCPOLYS)); + + const Octree::SIndexData* d = LightMapOctree->getIndexData(); + + for (u32 i=0; igetMaterialRenderer(Materials[i].MaterialType); + const bool transparent = (rnd && rnd->isTransparent()); + + // only render transparent buffer if this is the transparent render pass + // and solid only in solid pass + if (transparent == isTransparentPass) + { + driver->setMaterial(Materials[i]); + + renderMeshBuffer(driver, UseVBOs, LightMapMeshes[i], d[i]); + } + } + } + break; + case video::EVT_TANGENTS: + { + IRR_PROFILE(getProfiler().start(EPID_OC_CALCPOLYS)); + switch ( PolygonChecks ) + { + case EOPC_BOX: + TangentsOctree->calculatePolys(box); + break; + case EOPC_FRUSTUM: + TangentsOctree->calculatePolys(frust); + break; + } + IRR_PROFILE(getProfiler().stop(EPID_OC_CALCPOLYS)); + + const Octree::SIndexData* d = TangentsOctree->getIndexData(); + + for (u32 i=0; igetMaterialRenderer(Materials[i].MaterialType); + const bool transparent = (rnd && rnd->isTransparent()); + + // only render transparent buffer if this is the transparent render pass + // and solid only in solid pass + if (transparent == isTransparentPass) + { + driver->setMaterial(Materials[i]); + renderMeshBuffer(driver, UseVBOs, TangentsMeshes[i], d[i]); + } + } + } + break; + } + + // for debug purposes only + if (DebugDataVisible && !Materials.empty() && PassCount==1) + { + core::array< const core::aabbox3d* > boxes; + video::SMaterial m; + m.Lighting = false; + driver->setMaterial(m); + if ( DebugDataVisible & scene::EDS_BBOX_BUFFERS ) + { + switch (VertexType) + { + case video::EVT_STANDARD: + StdOctree->getBoundingBoxes(box, boxes); + break; + case video::EVT_2TCOORDS: + LightMapOctree->getBoundingBoxes(box, boxes); + break; + case video::EVT_TANGENTS: + TangentsOctree->getBoundingBoxes(box, boxes); + break; + } + + for (u32 b=0; b!=boxes.size(); ++b) + driver->draw3DBox(*boxes[b]); + } + + if ( DebugDataVisible & scene::EDS_BBOX ) + driver->draw3DBox(Box,video::SColor(0,255,0,0)); + } + +} + + +//! Removes a child from this scene node. +//! Implemented here, to be able to remove the shadow properly, if there is one, +//! or to remove attached childs. +bool COctreeSceneNode::removeChild(ISceneNode* child) +{ + if (child && Shadow == child) + { + Shadow->drop(); + Shadow = 0; + } + + return ISceneNode::removeChild(child); +} + +void COctreeSceneNode::setUseVBO(EOCTREENODE_VBO useVBO) +{ + UseVBOs = useVBO; + if ( Mesh ) + createTree(Mesh); +} + +EOCTREENODE_VBO COctreeSceneNode::getUseVBO() const +{ + return UseVBOs; +} + +void COctreeSceneNode::setPolygonChecks(EOCTREE_POLYGON_CHECKS checks) +{ + PolygonChecks = checks; +} + +EOCTREE_POLYGON_CHECKS COctreeSceneNode::getPolygonChecks() const +{ + return PolygonChecks; +} + +//! Creates shadow volume scene node as child of this node +//! and returns a pointer to it. +IShadowVolumeSceneNode* COctreeSceneNode::addShadowVolumeSceneNode( + const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity) +{ +#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ + if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER)) + return 0; + + if (!shadowMesh) + shadowMesh = Mesh; // if null is given, use the mesh of node + + if (Shadow) + Shadow->drop(); + + Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity); + return Shadow; +#else + return 0; +#endif +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& COctreeSceneNode::getBoundingBox() const +{ + return Box; +} + + +//! creates the tree +/* This method has a lot of duplication and overhead. Moreover, the tangents mesh conversion does not really work. I think we need a a proper mesh implementation for octrees, which handle all vertex types internally. Converting all structures to just one vertex type is always problematic. +Thanks to Auria for fixing major parts of this method. */ +bool COctreeSceneNode::createTree(IMesh* mesh) +{ + if (!mesh) + return false; + + MeshName = SceneManager->getMeshCache()->getMeshName(mesh); + + mesh->grab(); + deleteTree(); + + Mesh = mesh; + + const u32 beginTime = os::Timer::getRealTime(); + + u32 nodeCount = 0; + u32 polyCount = 0; + u32 i; + + Box = mesh->getBoundingBox(); + + if (mesh->getMeshBufferCount()) + { + // check for "largest" buffer types + // Also dropping buffers/materials for empty buffer + // (which looks like a horrible idea. If a user wanted that material without mesh he should still get it... + // but not going to change that now. Only documenting it after figuring out what happens here. + // It works at least as Materials are reset in deleteTree). + VertexType = video::EVT_STANDARD; + u32 meshReserve = 0; + for (i=0; igetMeshBufferCount(); ++i) + { + const IMeshBuffer* b = mesh->getMeshBuffer(i); + if (b->getVertexCount() && b->getIndexCount()) + { + ++meshReserve; + if (b->getVertexType() == video::EVT_2TCOORDS) + VertexType = video::EVT_2TCOORDS; + else if (b->getVertexType() == video::EVT_TANGENTS) + VertexType = video::EVT_TANGENTS; + } + } + Materials.reallocate(Materials.size()+meshReserve); + + switch(VertexType) + { + case video::EVT_STANDARD: + { + StdMeshes.reallocate(StdMeshes.size() + meshReserve); + for (i=0; igetMeshBufferCount(); ++i) + { + IMeshBuffer* b = mesh->getMeshBuffer(i); + + if (b->getVertexCount() && b->getIndexCount()) + { + Materials.push_back(b->getMaterial()); + + StdMeshes.push_back(Octree::SMeshChunk()); + Octree::SMeshChunk &nchunk = StdMeshes.getLast(); + nchunk.MaterialId = Materials.size() - 1; + + u32 v; + nchunk.Vertices.reallocate(b->getVertexCount()); + switch (b->getVertexType()) + { + case video::EVT_STANDARD: + for (v=0; vgetVertexCount(); ++v) + nchunk.Vertices.push_back(((video::S3DVertex*)b->getVertices())[v]); + break; + case video::EVT_2TCOORDS: + for (v=0; vgetVertexCount(); ++v) + nchunk.Vertices.push_back(((video::S3DVertex2TCoords*)b->getVertices())[v]); + break; + case video::EVT_TANGENTS: + for (v=0; vgetVertexCount(); ++v) + nchunk.Vertices.push_back(((video::S3DVertexTangents*)b->getVertices())[v]); + break; + } + + polyCount += b->getIndexCount(); + + nchunk.Indices.reallocate(b->getIndexCount()); + for (v=0; vgetIndexCount(); ++v) + nchunk.Indices.push_back(b->getIndices()[v]); + } + } + + StdOctree = new Octree(StdMeshes, MinimalPolysPerNode); + nodeCount = StdOctree->getNodeCount(); + } + break; + case video::EVT_2TCOORDS: + { + LightMapMeshes.reallocate(LightMapMeshes.size() + meshReserve); + + for ( i=0; i < mesh->getMeshBufferCount(); ++i) + { + IMeshBuffer* b = mesh->getMeshBuffer(i); + + if (b->getVertexCount() && b->getIndexCount()) + { + Materials.push_back(b->getMaterial()); + LightMapMeshes.push_back(Octree::SMeshChunk()); + Octree::SMeshChunk& nchunk = LightMapMeshes.getLast(); + nchunk.MaterialId = Materials.size() - 1; + + if (UseVBOs == EOV_USE_VBO_WITH_VISIBITLY) + { + nchunk.setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_VERTEX); + nchunk.setHardwareMappingHint(scene::EHM_DYNAMIC, scene::EBT_INDEX); + } + else + nchunk.setHardwareMappingHint(scene::EHM_STATIC); + + u32 v; + nchunk.Vertices.reallocate(b->getVertexCount()); + switch (b->getVertexType()) + { + case video::EVT_STANDARD: + for (v=0; vgetVertexCount(); ++v) + nchunk.Vertices.push_back(((video::S3DVertex*)b->getVertices())[v]); + break; + case video::EVT_2TCOORDS: + for (v=0; vgetVertexCount(); ++v) + nchunk.Vertices.push_back(((video::S3DVertex2TCoords*)b->getVertices())[v]); + break; + case video::EVT_TANGENTS: + for (v=0; vgetVertexCount(); ++v) + nchunk.Vertices.push_back(((video::S3DVertexTangents*)b->getVertices())[v]); + break; + } + + polyCount += b->getIndexCount(); + nchunk.Indices.reallocate(b->getIndexCount()); + for (v=0; vgetIndexCount(); ++v) + nchunk.Indices.push_back(b->getIndices()[v]); + } + } + + LightMapOctree = new Octree(LightMapMeshes, MinimalPolysPerNode); + nodeCount = LightMapOctree->getNodeCount(); + } + break; + case video::EVT_TANGENTS: + { + TangentsMeshes.reallocate(TangentsMeshes.size() + meshReserve); + + for (u32 i=0; igetMeshBufferCount(); ++i) + { + IMeshBuffer* b = mesh->getMeshBuffer(i); + + if (b->getVertexCount() && b->getIndexCount()) + { + Materials.push_back(b->getMaterial()); + TangentsMeshes.push_back(Octree::SMeshChunk()); + Octree::SMeshChunk& nchunk = TangentsMeshes.getLast(); + nchunk.MaterialId = Materials.size() - 1; + + u32 v; + nchunk.Vertices.reallocate(b->getVertexCount()); + switch (b->getVertexType()) + { + case video::EVT_STANDARD: + for (v=0; vgetVertexCount(); ++v) + { + const video::S3DVertex& tmpV = ((video::S3DVertex*)b->getVertices())[v]; + nchunk.Vertices.push_back(video::S3DVertexTangents(tmpV.Pos, tmpV.Color, tmpV.TCoords)); + } + break; + case video::EVT_2TCOORDS: + for (v=0; vgetVertexCount(); ++v) + { + const video::S3DVertex2TCoords& tmpV = ((video::S3DVertex2TCoords*)b->getVertices())[v]; + nchunk.Vertices.push_back(video::S3DVertexTangents(tmpV.Pos, tmpV.Color, tmpV.TCoords)); + } + break; + case video::EVT_TANGENTS: + for (v=0; vgetVertexCount(); ++v) + nchunk.Vertices.push_back(((video::S3DVertexTangents*)b->getVertices())[v]); + break; + } + + polyCount += b->getIndexCount(); + nchunk.Indices.reallocate(b->getIndexCount()); + for (v=0; vgetIndexCount(); ++v) + nchunk.Indices.push_back(b->getIndices()[v]); + } + } + + TangentsOctree = new Octree(TangentsMeshes, MinimalPolysPerNode); + nodeCount = TangentsOctree->getNodeCount(); + } + break; + } + } + + const u32 endTime = os::Timer::getRealTime(); + c8 tmp[255]; + sprintf(tmp, "Needed %ums to create Octree SceneNode.(%u nodes, %u polys)", + endTime - beginTime, nodeCount, polyCount/3); + os::Printer::log(tmp, ELL_INFORMATION); + + return true; +} + + +//! returns the material based on the zero based index i. +video::SMaterial& COctreeSceneNode::getMaterial(u32 i) +{ + if ( i >= Materials.size() ) + return ISceneNode::getMaterial(i); + + return Materials[i]; +} + + +//! returns amount of materials used by this scene node. +u32 COctreeSceneNode::getMaterialCount() const +{ + return Materials.size(); +} + + +//! Writes attributes of the scene node. +void COctreeSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + ISceneNode::serializeAttributes(out, options); + + out->addInt("MinimalPolysPerNode", MinimalPolysPerNode); + out->addString("Mesh", MeshName.c_str()); +} + + +//! Reads attributes of the scene node. +void COctreeSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + const s32 oldMinimal = MinimalPolysPerNode; + + MinimalPolysPerNode = in->getAttributeAsInt("MinimalPolysPerNode"); + io::path newMeshStr = in->getAttributeAsString("Mesh"); + + IMesh* newMesh = 0; + + if (newMeshStr == "") + newMeshStr = MeshName; + + IAnimatedMesh* newAnimatedMesh = SceneManager->getMesh(newMeshStr.c_str()); + + if (newAnimatedMesh) + newMesh = newAnimatedMesh->getMesh(0); + + if (newMesh && ((MeshName != newMeshStr) || (MinimalPolysPerNode != oldMinimal))) + { + // recalculate tree + createTree(newMesh); + } + + ISceneNode::deserializeAttributes(in, options); +} + + +void COctreeSceneNode::deleteTree() +{ + delete StdOctree; + StdOctree = 0; + StdMeshes.clear(); + + delete LightMapOctree; + LightMapOctree = 0; + LightMapMeshes.clear(); + + delete TangentsOctree; + TangentsOctree = 0; + TangentsMeshes.clear(); + + Materials.clear(); + + if(Mesh) + Mesh->drop(); +} + +void COctreeSceneNode::setMesh(IMesh* mesh) +{ + createTree(mesh); +} + +IMesh* COctreeSceneNode::getMesh(void) +{ + return Mesh; +} + +void COctreeSceneNode::setReadOnlyMaterials(bool readonly) +{ + // Do nothing +} + +bool COctreeSceneNode::isReadOnlyMaterials() const +{ + return false; +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_OCTREE_SCENENODE_ diff --git a/source/Irrlicht/COctreeSceneNode.h b/source/Irrlicht/COctreeSceneNode.h new file mode 100644 index 00000000..5ef28088 --- /dev/null +++ b/source/Irrlicht/COctreeSceneNode.h @@ -0,0 +1,132 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OCTREE_SCENE_NODE_H_INCLUDED__ +#define __C_OCTREE_SCENE_NODE_H_INCLUDED__ + +#include "IOctreeSceneNode.h" +#include "Octree.h" + +namespace irr +{ +namespace scene +{ + class COctreeSceneNode; + + //! implementation of the IOctreeSceneNode + class COctreeSceneNode : public IOctreeSceneNode + { + public: + + //! constructor + COctreeSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + s32 minimalPolysPerNode=512); + + //! destructor + virtual ~COctreeSceneNode(); + + virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; + + //! renders the node. + virtual void render() _IRR_OVERRIDE_; + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + //! creates the tree + bool createTree(IMesh* mesh); + + //! returns the material based on the zero based index i. To get the amount + //! of materials used by this scene node, use getMaterialCount(). + //! This function is needed for inserting the node into the scene hierarchy on a + //! optimal position for minimizing renderstate changes, but can also be used + //! to directly modify the material of a scene node. + virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_; + + //! returns amount of materials used by this scene node. + virtual u32 getMaterialCount() const _IRR_OVERRIDE_; + + //! Writes attributes of the scene node. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_OCTREE; } + + //! Sets a new mesh to display + virtual void setMesh(IMesh* mesh) _IRR_OVERRIDE_; + + //! Get the currently defined mesh for display. + virtual IMesh* getMesh(void) _IRR_OVERRIDE_; + + //! Sets if the scene node should not copy the materials of the mesh but use them in a read only style. + virtual void setReadOnlyMaterials(bool readonly) _IRR_OVERRIDE_; + + //! Check if the scene node should not copy the materials of the mesh but use them in a read only style + virtual bool isReadOnlyMaterials() const _IRR_OVERRIDE_; + + //! Creates shadow volume scene node as child of this node + //! and returns a pointer to it. + virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh, + s32 id, bool zfailmethod=true, f32 infinity=10000.0f) _IRR_OVERRIDE_; + + //! Removes a child from this scene node. + //! Implemented here, to be able to remove the shadow properly, if there is one, + //! or to remove attached child. + virtual bool removeChild(ISceneNode* child) _IRR_OVERRIDE_; + + // TODO: Currently using VBO's will crash when reloading the model. + // The reason is that COctreeSceneNode uses Octree::SMeshChunk + // which does use a an IReferenceCounted object on the stack. + // Which breaks VBO's which correctly use reference counting., + //! Set if/how vertex buffer object are used for the meshbuffers + /** NOTE: When there is already a mesh in the node this will rebuild + the octree. */ + virtual void setUseVBO(EOCTREENODE_VBO useVBO); + + //! Get if/how vertex buffer object are used for the meshbuffers + virtual EOCTREENODE_VBO getUseVBO() const _IRR_OVERRIDE_; + + //! Set the kind of tests polygons do for visibility against the camera + virtual void setPolygonChecks(EOCTREE_POLYGON_CHECKS checks) _IRR_OVERRIDE_; + + //! Get the kind of tests polygons do for visibility against the camera + virtual EOCTREE_POLYGON_CHECKS getPolygonChecks() const _IRR_OVERRIDE_; + + private: + + void deleteTree(); + + core::aabbox3d Box; + + Octree* StdOctree; + core::array< Octree::SMeshChunk > StdMeshes; + + Octree* LightMapOctree; + core::array< Octree::SMeshChunk > LightMapMeshes; + + Octree* TangentsOctree; + core::array< Octree::SMeshChunk > TangentsMeshes; + + video::E_VERTEX_TYPE VertexType; + core::array< video::SMaterial > Materials; + + core::stringc MeshName; + s32 MinimalPolysPerNode; + s32 PassCount; + + IMesh * Mesh; + IShadowVolumeSceneNode* Shadow; + + EOCTREENODE_VBO UseVBOs; + EOCTREE_POLYGON_CHECKS PolygonChecks; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/COctreeTriangleSelector.cpp b/source/Irrlicht/COctreeTriangleSelector.cpp new file mode 100644 index 00000000..a7627463 --- /dev/null +++ b/source/Irrlicht/COctreeTriangleSelector.cpp @@ -0,0 +1,327 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "COctreeTriangleSelector.h" +#include "ISceneNode.h" + +#include "os.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +COctreeTriangleSelector::COctreeTriangleSelector(const IMesh* mesh, + ISceneNode* node, s32 minimalPolysPerNode) + : CTriangleSelector(mesh, node, false) + , Root(0), NodeCount(0) + , MinimalPolysPerNode(minimalPolysPerNode) +{ + #ifdef _DEBUG + setDebugName("COctreeTriangleSelector"); + #endif + + if (!Triangles.empty()) + { + const u32 start = os::Timer::getRealTime(); + + // create the triangle octree + Root = new SOctreeNode(); + Root->Triangles = Triangles; + constructOctree(Root); + + c8 tmp[256]; + sprintf(tmp, "Needed %ums to create OctreeTriangleSelector.(%d nodes, %u polys)", + os::Timer::getRealTime() - start, NodeCount, Triangles.size()); + os::Printer::log(tmp, ELL_INFORMATION); + } +} + +COctreeTriangleSelector::COctreeTriangleSelector(const IMeshBuffer* meshBuffer, irr::u32 materialIndex, ISceneNode* node, s32 minimalPolysPerNode) + : CTriangleSelector(meshBuffer, materialIndex, node) + , Root(0), NodeCount(0) + , MinimalPolysPerNode(minimalPolysPerNode) +{ + #ifdef _DEBUG + setDebugName("COctreeTriangleSelector"); + #endif + + if (!Triangles.empty()) + { + const u32 start = os::Timer::getRealTime(); + + // create the triangle octree + Root = new SOctreeNode(); + Root->Triangles = Triangles; + constructOctree(Root); + + c8 tmp[256]; + sprintf(tmp, "Needed %ums to create OctreeTriangleSelector.(%d nodes, %u polys)", + os::Timer::getRealTime() - start, NodeCount, Triangles.size()); + os::Printer::log(tmp, ELL_INFORMATION); + } +} + +//! destructor +COctreeTriangleSelector::~COctreeTriangleSelector() +{ + delete Root; +} + + +void COctreeTriangleSelector::constructOctree(SOctreeNode* node) +{ + ++NodeCount; + + node->Box.reset(node->Triangles[0].pointA); + + // get bounding box + const u32 cnt = node->Triangles.size(); + for (u32 i=0; iBox.addInternalPoint(node->Triangles[i].pointA); + node->Box.addInternalPoint(node->Triangles[i].pointB); + node->Box.addInternalPoint(node->Triangles[i].pointC); + } + + // calculate children + + if (!node->Box.isEmpty() && (s32)node->Triangles.size() > MinimalPolysPerNode) + { + const core::vector3df& middle = node->Box.getCenter(); + core::vector3df edges[8]; + node->Box.getEdges(edges); + + core::aabbox3d box; + core::array keepTriangles(node->Triangles.size()); // reserving enough memory, so we don't get re-allocations per child + + for (s32 ch=0; ch<8; ++ch) + { + box.reset(middle); + box.addInternalPoint(edges[ch]); + node->Child[ch] = new SOctreeNode(); + + for (s32 i=0; i<(s32)node->Triangles.size(); ++i) + { + if (node->Triangles[i].isTotalInsideBox(box)) + { + node->Child[ch]->Triangles.push_back(node->Triangles[i]); + //node->Triangles.erase(i); + //--i; + } + else + { + keepTriangles.push_back(node->Triangles[i]); + } + } + memcpy(node->Triangles.pointer(), keepTriangles.pointer(), + sizeof(core::triangle3df)*keepTriangles.size()); + + node->Triangles.set_used(keepTriangles.size()); + keepTriangles.set_used(0); + } + keepTriangles.clear(); // release memory early, for large meshes it can matter. + node->Triangles.reallocate(node->Triangles.size(), true); // shrink memory to minimum necessary + + // Note: We use an extra loop to construct child-nodes instead of doing + // that in above loop to avoid memory fragmentation which happens if + // the code has to switch between allocating memory for this node and + // the child nodes (thanks @Squarefox for noting this). + for (s32 ch=0; ch<8; ++ch) + { + if (node->Child[ch]->Triangles.empty()) + { + delete node->Child[ch]; + node->Child[ch] = 0; + } + else + constructOctree(node->Child[ch]); + } + } +} + + +//! Gets all triangles which lie within a specific bounding box. +void COctreeTriangleSelector::getTriangles(core::triangle3df* triangles, + s32 arraySize, s32& outTriangleCount, + const core::aabbox3d& box, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const +{ + core::matrix4 mat(core::matrix4::EM4CONST_NOTHING); + core::aabbox3d invbox = box; + + if (SceneNode && useNodeTransform) + { + if ( SceneNode->getAbsoluteTransformation().getInverse(mat) ) + mat.transformBoxEx(invbox); + else + // TODO: case not handled well, we can only return all triangles + return CTriangleSelector::getTriangles(triangles, arraySize, outTriangleCount, transform, useNodeTransform, outTriangleInfo); + } + + if (transform) + mat = *transform; + else + mat.makeIdentity(); + + if (SceneNode && useNodeTransform) + mat *= SceneNode->getAbsoluteTransformation(); + + s32 trianglesWritten = 0; + + if (Root) + getTrianglesFromOctree(Root, trianglesWritten, + arraySize, invbox, &mat, triangles); + + if ( outTriangleInfo ) + { + SCollisionTriangleRange triRange; + triRange.RangeSize = trianglesWritten; + triRange.Selector = const_cast(this); + triRange.SceneNode = SceneNode; + triRange.MeshBuffer = MeshBuffer; + triRange.MaterialIndex = MaterialIndex; + outTriangleInfo->push_back(triRange); + } + + outTriangleCount = trianglesWritten; +} + + +void COctreeTriangleSelector::getTrianglesFromOctree( + SOctreeNode* node, s32& trianglesWritten, + s32 maximumSize, const core::aabbox3d& box, + const core::matrix4* mat, core::triangle3df* triangles) const +{ + if (!box.intersectsWithBox(node->Box)) + return; + + const u32 cnt = node->Triangles.size(); + + for (u32 i=0; iTriangles[i]; + // This isn't an accurate test, but it's fast, and the + // API contract doesn't guarantee complete accuracy. + if (srcTri.isTotalOutsideBox(box)) + continue; + + core::triangle3df& dstTri = triangles[trianglesWritten]; + mat->transformVect(dstTri.pointA, srcTri.pointA ); + mat->transformVect(dstTri.pointB, srcTri.pointB ); + mat->transformVect(dstTri.pointC, srcTri.pointC ); + ++trianglesWritten; + + // Halt when the out array is full. + if (trianglesWritten == maximumSize) + return; + } + + for (u32 i=0; i<8; ++i) + if (node->Child[i]) + getTrianglesFromOctree(node->Child[i], trianglesWritten, + maximumSize, box, mat, triangles); +} + + +//! Gets all triangles which have or may have contact with a 3d line. +// new version: from user Piraaate +void COctreeTriangleSelector::getTriangles(core::triangle3df* triangles, s32 arraySize, + s32& outTriangleCount, const core::line3d& line, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const +{ +#if 0 + core::aabbox3d box(line.start); + box.addInternalPoint(line.end); + + // TODO: Could be optimized for line a little bit more. + COctreeTriangleSelector::getTriangles(triangles, arraySize, outTriangleCount, + box, transform); +#else + + core::matrix4 mat ( core::matrix4::EM4CONST_NOTHING ); + + core::vector3df vectStartInv ( line.start ), vectEndInv ( line.end ); + if (SceneNode && useNodeTransform) + { + mat = SceneNode->getAbsoluteTransformation(); + mat.makeInverse(); + mat.transformVect(vectStartInv, line.start); + mat.transformVect(vectEndInv, line.end); + } + core::line3d invline(vectStartInv, vectEndInv); + + mat.makeIdentity(); + + if (transform) + mat = (*transform); + + if (SceneNode && useNodeTransform) + mat *= SceneNode->getAbsoluteTransformation(); + + s32 trianglesWritten = 0; + + if (Root) + getTrianglesFromOctree(Root, trianglesWritten, arraySize, invline, &mat, triangles); + + if ( outTriangleInfo ) + { + SCollisionTriangleRange triRange; + triRange.RangeSize = trianglesWritten; + triRange.Selector = const_cast(this); + triRange.SceneNode = SceneNode; + triRange.MeshBuffer = MeshBuffer; + triRange.MaterialIndex = MaterialIndex; + outTriangleInfo->push_back(triRange); + } + + outTriangleCount = trianglesWritten; +#endif +} + +void COctreeTriangleSelector::getTrianglesFromOctree(SOctreeNode* node, + s32& trianglesWritten, s32 maximumSize, const core::line3d& line, + const core::matrix4* transform, core::triangle3df* triangles) const +{ + if (!node->Box.intersectsWithLine(line)) + return; + + s32 cnt = node->Triangles.size(); + if (cnt + trianglesWritten > maximumSize) + cnt -= cnt + trianglesWritten - maximumSize; + + s32 i; + + if ( transform->isIdentity() ) + { + for (i=0; iTriangles[i]; + ++trianglesWritten; + } + } + else + { + for (i=0; iTriangles[i]; + transform->transformVect(triangles[trianglesWritten].pointA); + transform->transformVect(triangles[trianglesWritten].pointB); + transform->transformVect(triangles[trianglesWritten].pointC); + ++trianglesWritten; + } + } + + for (i=0; i<8; ++i) + if (node->Child[i]) + getTrianglesFromOctree(node->Child[i], trianglesWritten, + maximumSize, line, transform, triangles); +} + + +} // end namespace scene +} // end namespace irr diff --git a/source/Irrlicht/COctreeTriangleSelector.h b/source/Irrlicht/COctreeTriangleSelector.h new file mode 100644 index 00000000..b022b2ab --- /dev/null +++ b/source/Irrlicht/COctreeTriangleSelector.h @@ -0,0 +1,85 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OCTREE_TRIANGLE_SELECTOR_H_INCLUDED__ +#define __C_OCTREE_TRIANGLE_SELECTOR_H_INCLUDED__ + +#include "CTriangleSelector.h" + +namespace irr +{ +namespace scene +{ + +class ISceneNode; + +//! Stupid triangle selector without optimization +class COctreeTriangleSelector : public CTriangleSelector +{ +public: + + //! Constructs a selector based on a mesh + COctreeTriangleSelector(const IMesh* mesh, ISceneNode* node, s32 minimalPolysPerNode); + + //! Constructs a selector based on a meshbuffer + COctreeTriangleSelector(const IMeshBuffer* meshBuffer, irr::u32 materialIndex, ISceneNode* node, s32 minimalPolysPerNode); + + virtual ~COctreeTriangleSelector(); + + //! Gets all triangles which lie within a specific bounding box. + virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, + const core::aabbox3d& box, const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; + + //! Gets all triangles which have or may have contact with a 3d line. + virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, + s32& outTriangleCount, const core::line3d& line, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; + +private: + + struct SOctreeNode + { + SOctreeNode() + { + for (u32 i=0; i!=8; ++i) + Child[i] = 0; + } + + ~SOctreeNode() + { + for (u32 i=0; i!=8; ++i) + delete Child[i]; + } + + core::array Triangles; + SOctreeNode* Child[8]; + core::aabbox3d Box; + }; + + + void constructOctree(SOctreeNode* node); + void deleteEmptyNodes(SOctreeNode* node); + void getTrianglesFromOctree(SOctreeNode* node, s32& trianglesWritten, + s32 maximumSize, const core::aabbox3d& box, + const core::matrix4* transform, + core::triangle3df* triangles) const; + + void getTrianglesFromOctree(SOctreeNode* node, s32& trianglesWritten, + s32 maximumSize, const core::line3d& line, + const core::matrix4* transform, + core::triangle3df* triangles) const; + + SOctreeNode* Root; + s32 NodeCount; + s32 MinimalPolysPerNode; +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/source/Irrlicht/COgreMeshFileLoader.cpp b/source/Irrlicht/COgreMeshFileLoader.cpp new file mode 100644 index 00000000..9df20871 --- /dev/null +++ b/source/Irrlicht/COgreMeshFileLoader.cpp @@ -0,0 +1,1607 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +// Originally written by Christian Stehno, modified by Nikolaus Gebhardt + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_OGRE_LOADER_ + +#include "COgreMeshFileLoader.h" +#include "CMeshTextureLoader.h" +#include "os.h" +#include "SMeshBuffer.h" +#include "SAnimatedMesh.h" +#include "IReadFile.h" +#include "fast_atof.h" +#include "coreutil.h" + +#ifdef _DEBUG +#define IRR_OGRE_LOADER_DEBUG +#endif + +namespace irr +{ +namespace scene +{ + +namespace +{ + enum OGRE_CHUNKS + { + // Main Chunks + COGRE_HEADER= 0x1000, + COGRE_SKELETON= 0x2000, + COGRE_MESH= 0x3000, + + // sub chunks of COGRE_MESH + COGRE_SUBMESH= 0x4000, + COGRE_GEOMETRY= 0x5000, + COGRE_SKELETON_LINK= 0x6000, + COGRE_BONE_ASSIGNMENT= 0x7000, + COGRE_MESH_LOD= 0x8000, + COGRE_MESH_BOUNDS= 0x9000, + COGRE_MESH_SUBMESH_NAME_TABLE= 0xA000, + COGRE_MESH_EDGE_LISTS= 0xB000, + + // sub chunks of COGRE_SKELETON + COGRE_BONE_PARENT= 0x3000, + COGRE_ANIMATION= 0x4000, + COGRE_ANIMATION_TRACK= 0x4100, + COGRE_ANIMATION_KEYFRAME= 0x4110, + COGRE_ANIMATION_LINK= 0x5000, + + // sub chunks of COGRE_SUBMESH + COGRE_SUBMESH_OPERATION= 0x4010, + COGRE_SUBMESH_BONE_ASSIGNMENT= 0x4100, + COGRE_SUBMESH_TEXTURE_ALIAS= 0x4200, + + // sub chunks of COGRE_GEOMETRY + COGRE_GEOMETRY_VERTEX_DECLARATION= 0x5100, + COGRE_GEOMETRY_VERTEX_ELEMENT= 0x5110, + COGRE_GEOMETRY_VERTEX_BUFFER= 0x5200, + COGRE_GEOMETRY_VERTEX_BUFFER_DATA= 0x5210 + }; +} + +//! Constructor +COgreMeshFileLoader::COgreMeshFileLoader(io::IFileSystem* fs, video::IVideoDriver* driver) +: FileSystem(fs), Driver(driver), SwapEndian(false), Mesh(0), NumUV(0) +{ + + #ifdef _DEBUG + setDebugName("COgreMeshFileLoader"); + #endif + + if (FileSystem) + FileSystem->grab(); + + if (Driver) + Driver->grab(); + + TextureLoader = new CMeshTextureLoader( FileSystem, Driver ); +} + + +//! destructor +COgreMeshFileLoader::~COgreMeshFileLoader() +{ + clearMeshes(); + + if (FileSystem) + FileSystem->drop(); + + if (Driver) + Driver->drop(); + + if (Mesh) + Mesh->drop(); +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool COgreMeshFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "mesh" ); +} + + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IReferenceCounted::drop() for more information. +IAnimatedMesh* COgreMeshFileLoader::createMesh(io::IReadFile* file) +{ + if ( !file ) + return 0; + + if ( getMeshTextureLoader() ) + getMeshTextureLoader()->setMeshFile(file); + + s16 id; + + file->read(&id, 2); + + if (id == COGRE_HEADER) + SwapEndian=false; + else if (id == 0x0010) + SwapEndian=true; + else + return 0; + ChunkData data; + readString(file, data, Version); + if ((Version != "[MeshSerializer_v1.30]") && (Version != "[MeshSerializer_v1.40]") && (Version != "[MeshSerializer_v1.41]")) + { + os::Printer::log("Unsupported ogre mesh version", Version.c_str(), ELL_INFORMATION); + return 0; + } + + clearMeshes(); + if (Mesh) + Mesh->drop(); + + CurrentlyLoadingFromPath = FileSystem->getFileDir(file->getFileName()); + loadMaterials(file); + + if (readChunk(file)) + { + // delete data loaded from file + clearMeshes(); + + if (Skeleton.Bones.size()) + { + ISkinnedMesh* tmp = static_cast(Mesh); + static_cast(Mesh)->updateBoundingBox(); + Skeleton.Animations.clear(); + Skeleton.Bones.clear(); + Mesh=0; + return tmp; + } + else + { + for (u32 i=0; igetMeshBufferCount(); ++i) + ((SMeshBuffer*)Mesh->getMeshBuffer(i))->recalculateBoundingBox(); + + ((SMesh*)Mesh)->recalculateBoundingBox(); + SAnimatedMesh* am = new SAnimatedMesh(); + am->Type = EAMT_3DS; + am->addMesh(Mesh); + am->recalculateBoundingBox(); + Mesh->drop(); + Mesh = 0; + return am; + } + } + + Mesh->drop(); + Mesh = 0; + + return 0; +} + + +bool COgreMeshFileLoader::readChunk(io::IReadFile* file) +{ + while(file->getPos() < file->getSize()) + { + ChunkData data; + readChunkData(file, data); + + switch(data.header.id) + { + case COGRE_MESH: + { + Meshes.push_back(OgreMesh()); + readObjectChunk(file, data, Meshes.getLast()); + if (Skeleton.Bones.size()) + Mesh = new CSkinnedMesh(); + else + Mesh = new SMesh(); + composeObject(); + } + break; + default: + return true; + } + } + + return true; +} + + +bool COgreMeshFileLoader::readObjectChunk(io::IReadFile* file, ChunkData& parent, OgreMesh& mesh) +{ +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("Read Object Chunk", ELL_DEBUG); +#endif + readBool(file, parent, mesh.SkeletalAnimation); + bool skeleton_loaded=false; + while ((parent.read < parent.header.length)&&(file->getPos() < file->getSize())) + { + ChunkData data; + readChunkData(file, data); + + switch(data.header.id) + { + case COGRE_GEOMETRY: + readGeometry(file, data, mesh.Geometry); + break; + case COGRE_SUBMESH: + mesh.SubMeshes.push_back(OgreSubMesh()); + readSubMesh(file, data, mesh.SubMeshes.getLast()); + break; + case COGRE_MESH_BOUNDS: + { +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("Read Mesh Bounds", ELL_DEBUG); +#endif + readVector(file, data, mesh.BBoxMinEdge); + readVector(file, data, mesh.BBoxMaxEdge); + readFloat(file, data, &mesh.BBoxRadius); + } + break; + case COGRE_SKELETON_LINK: + { +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("Read Skeleton link", ELL_DEBUG); +#endif + core::stringc name; + readString(file, data, name); + loadSkeleton(file, name); + skeleton_loaded=true; + } + break; + case COGRE_BONE_ASSIGNMENT: + { + mesh.BoneAssignments.push_back(OgreBoneAssignment()); + readInt(file, data, &mesh.BoneAssignments.getLast().VertexID); + readShort(file, data, &mesh.BoneAssignments.getLast().BoneID); + readFloat(file, data, &mesh.BoneAssignments.getLast().Weight); + } + break; + case COGRE_MESH_LOD: + case COGRE_MESH_SUBMESH_NAME_TABLE: + case COGRE_MESH_EDGE_LISTS: + // ignore chunk + file->seek(data.header.length-data.read, true); + data.read += data.header.length-data.read; + break; + default: +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("Skipping", core::stringc(data.header.id), ELL_DEBUG); +#endif + // ignore chunk + file->seek(data.header.length-data.read, true); + data.read += data.header.length-data.read; + break; + } + parent.read += data.read; + } + if (!skeleton_loaded) + loadSkeleton(file, FileSystem->getFileBasename(file->getFileName(), false)); + return true; +} + + +bool COgreMeshFileLoader::readGeometry(io::IReadFile* file, ChunkData& parent, OgreGeometry& geometry) +{ +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("Read Geometry", ELL_DEBUG); +#endif + readInt(file, parent, &geometry.NumVertex); + while(parent.read < parent.header.length) + { + ChunkData data; + readChunkData(file, data); + + switch(data.header.id) + { + case COGRE_GEOMETRY_VERTEX_DECLARATION: + readVertexDeclaration(file, data, geometry); + break; + case COGRE_GEOMETRY_VERTEX_BUFFER: + readVertexBuffer(file, data, geometry); + break; + default: + // ignore chunk +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("Skipping", core::stringc(data.header.id), ELL_DEBUG); +#endif + file->seek(data.header.length-data.read, true); + data.read += data.header.length-data.read; + } + parent.read += data.read; + } + if (parent.read != parent.header.length) + os::Printer::log("Incorrect geometry length. File might be corrupted."); + return true; +} + + +bool COgreMeshFileLoader::readVertexDeclaration(io::IReadFile* file, ChunkData& parent, OgreGeometry& geometry) +{ +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("Read Vertex Declaration", ELL_DEBUG); +#endif + NumUV = 0; + while(parent.read < parent.header.length) + { + ChunkData data; + readChunkData(file, data); + + switch(data.header.id) + { + case COGRE_GEOMETRY_VERTEX_ELEMENT: + { + geometry.Elements.push_back(OgreVertexElement()); + OgreVertexElement& elem = geometry.Elements.getLast(); + readShort(file, data, &elem.Source); + readShort(file, data, &elem.Type); + readShort(file, data, &elem.Semantic); + if (elem.Semantic == 7) //Tex coords + { + ++NumUV; + } + readShort(file, data, &elem.Offset); + elem.Offset /= sizeof(f32); + readShort(file, data, &elem.Index); + } + break; + default: + // ignore chunk + file->seek(data.header.length-data.read, true); + data.read += data.header.length-data.read; + } + parent.read += data.read; + } + if (parent.read != parent.header.length) + os::Printer::log("Incorrect vertex declaration length. File might be corrupted."); + return true; +} + + +bool COgreMeshFileLoader::readVertexBuffer(io::IReadFile* file, ChunkData& parent, OgreGeometry& geometry) +{ +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("Read Vertex Buffer", ELL_DEBUG); +#endif + OgreVertexBuffer buf; + readShort(file, parent, &buf.BindIndex); + readShort(file, parent, &buf.VertexSize); + buf.VertexSize /= sizeof(f32); + ChunkData data; + readChunkData(file, data); + + if (data.header.id == COGRE_GEOMETRY_VERTEX_BUFFER_DATA) + { + buf.Data.set_used(geometry.NumVertex*buf.VertexSize); + readFloat(file, data, buf.Data.pointer(), geometry.NumVertex*buf.VertexSize); + } + + geometry.Buffers.push_back(buf); + parent.read += data.read; + if (parent.read != parent.header.length) + os::Printer::log("Incorrect vertex buffer length. File might be corrupted."); + return true; +} + + +bool COgreMeshFileLoader::readSubMesh(io::IReadFile* file, ChunkData& parent, OgreSubMesh& subMesh) +{ +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("Read Submesh", ELL_DEBUG); +#endif + readString(file, parent, subMesh.Material); +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("using material", subMesh.Material, ELL_DEBUG); +#endif + readBool(file, parent, subMesh.SharedVertices); + + s32 numIndices; + readInt(file, parent, &numIndices); + subMesh.Indices.set_used(numIndices); + + readBool(file, parent, subMesh.Indices32Bit); + + if (subMesh.Indices32Bit) + readInt(file, parent, subMesh.Indices.pointer(), numIndices); + else + { + for (s32 i=0; iseek(-(long)sizeof(ChunkHeader), true); + return true; + } + parent.read += data.read; + } + if (parent.read != parent.header.length) + os::Printer::log("Incorrect submesh length. File might be corrupted."); +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("Done with submesh", ELL_DEBUG); +#endif + return true; +} + + +void COgreMeshFileLoader::composeMeshBufferMaterial(scene::IMeshBuffer* mb, const core::stringc& materialName) +{ + video::SMaterial& material=mb->getMaterial(); + for (u32 k=0; kgetTexture(Materials[k].Techniques[0].Passes[0].Texture.Filename[i]); + if ( texture ) + material.setTexture(i, texture); + } + } + break; + } + } +} + + +scene::SMeshBuffer* COgreMeshFileLoader::composeMeshBuffer(const core::array& indices, const OgreGeometry& geom) +{ + scene::SMeshBuffer *mb=new scene::SMeshBuffer(); + + u32 i; + mb->Indices.set_used(indices.size()); + for (i=0; iIndices[i]=indices[i]; + + mb->Vertices.set_used(geom.NumVertex); + for (i=0; iVertices[k].Color=mb->Material.DiffuseColor; + mb->Vertices[k].Pos.set(geom.Buffers[j].Data[ePos],geom.Buffers[j].Data[ePos+1],geom.Buffers[j].Data[ePos+2]); + ePos += eSize; + } + } + } + } + + if (geom.Elements[i].Semantic==4) //Normal + { + for (u32 j=0; jVertices[k].Normal.set(geom.Buffers[j].Data[ePos],geom.Buffers[j].Data[ePos+1],geom.Buffers[j].Data[ePos+2]); + ePos += eSize; + } + } + } + } + + if (geom.Elements[i].Semantic==7) //TexCoord + { + for (u32 j=0; jVertices[k].TCoords.set(geom.Buffers[j].Data[ePos],geom.Buffers[j].Data[ePos+1]); + ePos += eSize; + } + } + } + } + } + return mb; +} + + +scene::SMeshBufferLightMap* COgreMeshFileLoader::composeMeshBufferLightMap(const core::array& indices, const OgreGeometry& geom) +{ + scene::SMeshBufferLightMap *mb=new scene::SMeshBufferLightMap(); + + u32 i; + mb->Indices.set_used(indices.size()); + for (i=0; iIndices[i]=indices[i]; + + mb->Vertices.set_used(geom.NumVertex); + + for (i=0; iVertices[k].Color=mb->Material.DiffuseColor; + mb->Vertices[k].Pos.set(geom.Buffers[j].Data[ePos],geom.Buffers[j].Data[ePos+1],geom.Buffers[j].Data[ePos+2]); + ePos += eSize; + } + } + } + } + + if (geom.Elements[i].Semantic==4) //Normal + { + for (u32 j=0; jVertices[k].Normal.set(geom.Buffers[j].Data[ePos],geom.Buffers[j].Data[ePos+1],geom.Buffers[j].Data[ePos+2]); + ePos += eSize; + } + } + } + } + + if (geom.Elements[i].Semantic==7) //TexCoord + { + for (u32 j=0; jePos+3); + for (s32 k=0; kVertices[k].TCoords.set(geom.Buffers[j].Data[ePos], geom.Buffers[j].Data[ePos+1]); + if (secondCoord) + mb->Vertices[k].TCoords2.set(geom.Buffers[j].Data[ePos+2], geom.Buffers[j].Data[ePos+3]); + else + mb->Vertices[k].TCoords2.set(geom.Buffers[j].Data[ePos], geom.Buffers[j].Data[ePos+1]); + ePos += eSize; + } + } + } + } + } + + return mb; +} + + +scene::IMeshBuffer* COgreMeshFileLoader::composeMeshBufferSkinned(scene::CSkinnedMesh& mesh, const core::array& indices, const OgreGeometry& geom) +{ + scene::SSkinMeshBuffer *mb=mesh.addMeshBuffer(); + if (NumUV>1) + { + mb->convertTo2TCoords(); + mb->Vertices_2TCoords.set_used(geom.NumVertex); + } + else + mb->Vertices_Standard.set_used(geom.NumVertex); + + u32 i; + mb->Indices.set_used(indices.size()); + for (i=0; iIndices[i+0]=indices[i+2]; + mb->Indices[i+1]=indices[i+1]; + mb->Indices[i+2]=indices[i+0]; + } + + for (i=0; i1) + mb->Vertices_2TCoords[k].Color=mb->Material.DiffuseColor; + else + mb->Vertices_Standard[k].Color=mb->Material.DiffuseColor; + mb->getPosition(k).set(-geom.Buffers[j].Data[ePos],geom.Buffers[j].Data[ePos+1],geom.Buffers[j].Data[ePos+2]); + ePos += eSize; + } + } + } + } + + if (geom.Elements[i].Semantic==4) //Normal + { + for (u32 j=0; jgetNormal(k).set(-geom.Buffers[j].Data[ePos],geom.Buffers[j].Data[ePos+1],geom.Buffers[j].Data[ePos+2]); + ePos += eSize; + } + } + } + } + + if (geom.Elements[i].Semantic==7) //TexCoord + { + for (u32 j=0; jePos+3); + for (s32 k=0; kgetTCoords(k).set(geom.Buffers[j].Data[ePos], geom.Buffers[j].Data[ePos+1]); + if (NumUV>1) + { + if (secondCoord) + mb->Vertices_2TCoords[k].TCoords2.set(geom.Buffers[j].Data[ePos+2], geom.Buffers[j].Data[ePos+3]); + else + mb->Vertices_2TCoords[k].TCoords2.set(geom.Buffers[j].Data[ePos], geom.Buffers[j].Data[ePos+1]); + } + ePos += eSize; + } + } + } + } + } + + return mb; +} + + +void COgreMeshFileLoader::composeObject(void) +{ + for (u32 i=0; iaddMeshBuffer(mb); + mb->drop(); + } + } + } + } + if (Skeleton.Bones.size()) + { + CSkinnedMesh* m = (CSkinnedMesh*)Mesh; + // Create Joints + for (u32 i=0; iaddJoint(); + joint->Name=Skeleton.Bones[i].Name; + + // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched to getMatrix_transposed instead of getMatrix for downward compatibility. + // Not tested so far if this was correct or wrong before quaternion fix! + Skeleton.Bones[i].Orientation.getMatrix_transposed(joint->LocalMatrix); + + if (Skeleton.Bones[i].Scale != core::vector3df(1,1,1)) + { + core::matrix4 scaleMatrix; + scaleMatrix.setScale( Skeleton.Bones[i].Scale ); + joint->LocalMatrix *= scaleMatrix; + } + joint->LocalMatrix.setTranslation( Skeleton.Bones[i].Position ); + } + // Joints hierarchy + for (u32 i=0; igetJointCount()) + { + m->getAllJoints()[Skeleton.Bones[i].Parent]->Children.push_back(m->getAllJoints()[Skeleton.Bones[i].Handle]); + } + } + + // Weights + u32 bufCount=0; + for (u32 i=0; igetJointCount()) + { + ISkinnedMesh::SWeight* w = m->addWeight(m->getAllJoints()[ba.BoneID]); + w->strength=ba.Weight; + w->vertex_id=ba.VertexID; + w->buffer_id=bufCount; + } + } + ++bufCount; + } + } + + for (u32 i=0; igetAllJoints()[frame.BoneID]; + ISkinnedMesh::SPositionKey* poskey = m->addPositionKey(keyjoint); + poskey->frame=frame.Time*25; + poskey->position=keyjoint->LocalMatrix.getTranslation()+frame.Position; + ISkinnedMesh::SRotationKey* rotkey = m->addRotationKey(keyjoint); + rotkey->frame=frame.Time*25; + + // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched from keyjoint->LocalMatrix to keyjoint->LocalMatrix.getTransposed() for downward compatibility. + // Not tested so far if this was correct or wrong before quaternion fix! + rotkey->rotation=core::quaternion(keyjoint->LocalMatrix.getTransposed())*frame.Orientation; + + ISkinnedMesh::SScaleKey* scalekey = m->addScaleKey(keyjoint); + scalekey->frame=frame.Time*25; + scalekey->scale=frame.Scale; + } + } + m->finalize(); + } +} + + +void COgreMeshFileLoader::getMaterialToken(io::IReadFile* file, core::stringc& token, bool noNewLine) +{ + bool parseString=false; + c8 c=0; + token = ""; + + if (file->getPos() >= file->getSize()) + return; + + file->read(&c, sizeof(c8)); + // search for word beginning + while ( core::isspace(c) && (file->getPos() < file->getSize())) + { + if (noNewLine && c=='\n') + { + file->seek(-1, true); + return; + } + file->read(&c, sizeof(c8)); + } + // check if we read a string + if (c=='"') + { + parseString = true; + file->read(&c, sizeof(c8)); + } + do + { + if (c=='/') + { + file->read(&c, sizeof(c8)); + // check for comments, cannot be part of strings + if (!parseString && (c=='/')) + { + // skip comments + while(c!='\n') + file->read(&c, sizeof(c8)); + if (!token.size()) + { + // if we start with a comment we need to skip + // following whitespaces, so restart + getMaterialToken(file, token, noNewLine); + return; + } + else + { + // else continue with next character + file->read(&c, sizeof(c8)); + continue; + } + } + else + { + // else append first slash and check if second char + // ends this token + token.append('/'); + if ((!parseString && core::isspace(c)) || + (parseString && (c=='"'))) + return; + } + } + token.append(c); + file->read(&c, sizeof(c8)); + // read until a token delimiter is found + } + while (((!parseString && !core::isspace(c)) || (parseString && (c!='"'))) && + (file->getPos() < file->getSize())); + // we want to skip the last quotes of a string , but other chars might be the next + // token already. + if (!parseString) + file->seek(-1, true); +} + + +bool COgreMeshFileLoader::readColor(io::IReadFile* file, video::SColor& col) +{ + core::stringc token; + + getMaterialToken(file, token); + if (token!="vertexcolour") + { + video::SColorf col_f; + col_f.r=core::fast_atof(token.c_str()); + getMaterialToken(file, token); + col_f.g=core::fast_atof(token.c_str()); + getMaterialToken(file, token); + col_f.b=core::fast_atof(token.c_str()); + getMaterialToken(file, token, true); + if (token.size()) + col_f.a=core::fast_atof(token.c_str()); + else + col_f.a=1.0f; + if ((col_f.r==0.0f)&&(col_f.g==0.0f)&&(col_f.b==0.0f)) + col.set(255,255,255,255); + else + col=col_f.toSColor(); + return false; + } + return true; +} + + +void COgreMeshFileLoader::readPass(io::IReadFile* file, OgreTechnique& technique) +{ +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("Read Pass"); +#endif + core::stringc token; + technique.Passes.push_back(OgrePass()); + OgrePass& pass=technique.Passes.getLast(); + + getMaterialToken(file, token); //open brace or name + if (token != "{") + getMaterialToken(file, token); //open brace + + getMaterialToken(file, token); + if (token == "}") + return; + u32 inBlocks=1; + u32 textureUnit=0; + while(inBlocks) + { + if (token=="ambient") + pass.AmbientTokenColor=readColor(file, pass.Material.AmbientColor); + else if (token=="diffuse") + pass.DiffuseTokenColor=readColor(file, pass.Material.DiffuseColor); + else if (token=="specular") + { + pass.SpecularTokenColor=readColor(file, pass.Material.SpecularColor); + getMaterialToken(file, token); + pass.Material.Shininess=core::fast_atof(token.c_str()); + } + else if (token=="emissive") + pass.EmissiveTokenColor=readColor(file, pass.Material.EmissiveColor); + else if (token=="scene_blend") + { // TODO: Choose correct values + getMaterialToken(file, token); + if (token=="add") + pass.Material.MaterialType=video::EMT_TRANSPARENT_ADD_COLOR; + else if (token=="modulate") + pass.Material.MaterialType=video::EMT_SOLID; + else if (token=="alpha_blend") + pass.Material.MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL; + else if (token=="colour_blend") + pass.Material.MaterialType=video::EMT_TRANSPARENT_VERTEX_ALPHA; + else + getMaterialToken(file, token); + } + else if (token=="depth_check") + { + getMaterialToken(file, token); + if (token!="on") + pass.Material.ZBuffer=video::ECFN_DISABLED; + } + else if (token=="depth_write") + { + getMaterialToken(file, token); + pass.Material.ZWriteEnable=(token=="on") ? video::EZW_ON : video::EZW_OFF; + } + else if (token=="depth_func") + { + getMaterialToken(file, token); // Function name + if (token=="always_fail") + pass.Material.ZBuffer=video::ECFN_NEVER; + else if (token=="always_pass") + pass.Material.ZBuffer=video::ECFN_ALWAYS; + else if (token=="equal") + pass.Material.ZBuffer=video::ECFN_EQUAL; + else if (token=="greater") + pass.Material.ZBuffer=video::ECFN_GREATER; + else if (token=="greater_equal") + pass.Material.ZBuffer=video::ECFN_GREATEREQUAL; + else if (token=="less") + pass.Material.ZBuffer=video::ECFN_LESS; + else if (token=="less_equal") + pass.Material.ZBuffer=video::ECFN_LESSEQUAL; + else if (token=="not_equal") + pass.Material.ZBuffer=video::ECFN_NOTEQUAL; + } + else if (token=="normalise_normals") + { + getMaterialToken(file, token); + pass.Material.NormalizeNormals=(token=="on"); + } + else if (token=="depth_bias") + { + getMaterialToken(file, token); // bias value + } + else if (token=="alpha_rejection") + { + getMaterialToken(file, token); // function name + getMaterialToken(file, token); // value + pass.Material.MaterialTypeParam=core::fast_atof(token.c_str()); + } + else if (token=="alpha_to_coverage") + { + getMaterialToken(file, token); + if (token=="on") + pass.Material.AntiAliasing |= video::EAAM_ALPHA_TO_COVERAGE; + } + else if (token=="colour_write") + { + getMaterialToken(file, token); + pass.Material.ColorMask = (token=="on")?video::ECP_ALL:video::ECP_NONE; + } + else if (token=="cull_hardware") + { + getMaterialToken(file, token); // rotation name + } + else if (token=="cull_software") + { + getMaterialToken(file, token); // culling side + } + else if (token=="lighting") + { + getMaterialToken(file, token); + pass.Material.Lighting=(token=="on"); + } + else if (token=="shading") + { + getMaterialToken(file, token); + // We take phong as gouraud + pass.Material.GouraudShading=(token!="flat"); + } + else if (token=="polygon_mode") + { + getMaterialToken(file, token); + pass.Material.Wireframe=(token=="wireframe"); + pass.Material.PointCloud=(token=="points"); + } + else if (token=="max_lights") + { + getMaterialToken(file, token); + pass.MaxLights=core::strtoul10(token.c_str()); + } + else if (token=="point_size") + { + getMaterialToken(file, token); + pass.PointSize=core::fast_atof(token.c_str()); + } + else if (token=="point_sprites") + { + getMaterialToken(file, token); + pass.PointSprites=(token=="on"); + } + else if (token=="point_size_min") + { + getMaterialToken(file, token); + pass.PointSizeMin=core::strtoul10(token.c_str()); + } + else if (token=="point_size_max") + { + getMaterialToken(file, token); + pass.PointSizeMax=core::strtoul10(token.c_str()); + } + else if (token=="texture_unit") + { +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("Read Texture unit", ELL_DEBUG); +#endif + getMaterialToken(file, token); //open brace + getMaterialToken(file, token); + while(token != "}") + { + if (token=="texture") + { + getMaterialToken(file, token); + pass.Texture.Filename.push_back(token); +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("Read Texture", token, ELL_DEBUG); +#endif + getMaterialToken(file, pass.Texture.CoordsType, true); + getMaterialToken(file, pass.Texture.MipMaps, true); + getMaterialToken(file, pass.Texture.Alpha, true); + // Hmm, we might need more hints for other material types using two textures... + if (textureUnit>0) + pass.Material.MaterialType=video::EMT_LIGHTMAP; + } + else if (token=="filtering") + { + getMaterialToken(file, token); + pass.Material.TextureLayer[textureUnit].AnisotropicFilter=0; + if (token=="point") + { + pass.Material.TextureLayer[textureUnit].BilinearFilter=false; + pass.Material.TextureLayer[textureUnit].TrilinearFilter=false; + getMaterialToken(file, token); + getMaterialToken(file, token); + } + else if (token=="linear") + { + getMaterialToken(file, token); + if (token=="point") + { + pass.Material.TextureLayer[textureUnit].BilinearFilter=false; + pass.Material.TextureLayer[textureUnit].TrilinearFilter=false; + getMaterialToken(file, token); + } + else + { + pass.Material.TextureLayer[textureUnit].BilinearFilter=true; + getMaterialToken(file, token); + pass.Material.TextureLayer[textureUnit].TrilinearFilter=(token=="linear"); + } + } + else + { + pass.Material.TextureLayer[textureUnit].BilinearFilter=(token=="bilinear"); + pass.Material.TextureLayer[textureUnit].TrilinearFilter=(token=="trilinear"); + pass.Material.TextureLayer[textureUnit].AnisotropicFilter=(token=="anisotropic")?2:1; + } + } + else if (token=="max_anisotropy") + { + getMaterialToken(file, token); + pass.Material.TextureLayer[textureUnit].AnisotropicFilter=(u8)core::strtoul10(token.c_str()); + } + else if (token=="texture_alias") + { + getMaterialToken(file, pass.Texture.Alias); + } + else if (token=="mipmap_bias") + { + getMaterialToken(file, token); + pass.Material.TextureLayer[textureUnit].LODBias=(s8)core::fast_atof(token.c_str()); + } + else if (token=="colour_op") + { // TODO: Choose correct values + getMaterialToken(file, token); + if (token=="add") + pass.Material.MaterialType=video::EMT_TRANSPARENT_ADD_COLOR; + else if (token=="modulate") + pass.Material.MaterialType=video::EMT_SOLID; + else if (token=="alpha_blend") + pass.Material.MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL; + else if (token=="colour_blend") + pass.Material.MaterialType=video::EMT_TRANSPARENT_VERTEX_ALPHA; + else + getMaterialToken(file, token); + } + getMaterialToken(file, token); + } + ++textureUnit; + } + else if (token=="shadow_caster_program_ref") + { + do + { + getMaterialToken(file, token); + } while (token != "}"); + } + else if (token=="shadow_caster_vertex_program_ref") + { + do + { + getMaterialToken(file, token); + } while (token != "}"); + } + else if (token=="vertex_program_ref") + { + do + { + getMaterialToken(file, token); + } while (token != "}"); + } + //fog_override, iteration, point_size_attenuation + //not considered yet! + getMaterialToken(file, token); + if (token=="{") + ++inBlocks; + else if (token=="}") + --inBlocks; + } +} + + +void COgreMeshFileLoader::readTechnique(io::IReadFile* file, OgreMaterial& mat) +{ +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("Read Technique"); +#endif + core::stringc token; + mat.Techniques.push_back(OgreTechnique()); + OgreTechnique& technique=mat.Techniques.getLast(); + + getMaterialToken(file, technique.Name); //open brace or name + if (technique.Name != "{") + getMaterialToken(file, token); //open brace + else + technique.Name=core::stringc((int)mat.Techniques.size()); + + getMaterialToken(file, token); + while (token != "}") + { + if (token == "pass") + readPass(file, technique); + else if (token == "scheme") + getMaterialToken(file, token); + else if (token == "lod_index") + getMaterialToken(file, token); + getMaterialToken(file, token); + } +} + + +void COgreMeshFileLoader::loadMaterials(io::IReadFile* meshFile) +{ +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("Load Materials", ELL_DEBUG); +#endif + core::stringc token; + io::IReadFile* file = 0; + io::path filename = FileSystem->getFileBasename(meshFile->getFileName(), false) + ".material"; + if (FileSystem->existFile(filename)) + file = FileSystem->createAndOpenFile(filename); + else + file = FileSystem->createAndOpenFile(FileSystem->getFileDir(meshFile->getFileName())+"/"+filename); + + if (!file) + { + os::Printer::log("Could not load OGRE material", filename); + return; + } + + getMaterialToken(file, token); + + while (file->getPos() < file->getSize()) + { + if ((token == "fragment_program") || (token == "vertex_program")) + { + // skip whole block + u32 blocks=1; + do + { + getMaterialToken(file, token); + } while (token != "{"); + do + { + getMaterialToken(file, token); + if (token == "{") + ++blocks; + else if (token == "}") + --blocks; + } while (blocks); + getMaterialToken(file, token); + continue; + } + if (token != "material") + { + if (token.trim().size()) + os::Printer::log("Unknown material group", token.c_str()); + break; + } + + Materials.push_back(OgreMaterial()); + OgreMaterial& mat = Materials.getLast(); + + getMaterialToken(file, mat.Name); +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("Load Material", mat.Name.c_str(), ELL_DEBUG); +#endif + getMaterialToken(file, token); //open brace + getMaterialToken(file, token); + while(token != "}") + { + if (token=="lod_distances") // can have several items + getMaterialToken(file, token); + else if (token=="receive_shadows") + { + getMaterialToken(file, token); + mat.ReceiveShadows=(token=="on"); + } + else if (token=="transparency_casts_shadows") + { + getMaterialToken(file, token); + mat.TransparencyCastsShadows=(token=="on"); + } + else if (token=="set_texture_alias") + { + getMaterialToken(file, token); + getMaterialToken(file, token); + } + else if (token=="technique") + readTechnique(file, mat); + getMaterialToken(file, token); + } + getMaterialToken(file, token); + } + + file->drop(); +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("Finished loading Materials", ELL_DEBUG); +#endif +} + + +bool COgreMeshFileLoader::loadSkeleton(io::IReadFile* meshFile, const core::stringc& name) +{ +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("Load Skeleton", name, ELL_DEBUG); +#endif + io::IReadFile* file = 0; + io::path filename; + if (FileSystem->existFile(name)) + file = FileSystem->createAndOpenFile(name); + else if (FileSystem->existFile(filename = FileSystem->getFileDir(meshFile->getFileName())+"/"+name)) + file = FileSystem->createAndOpenFile(filename); + else if (FileSystem->existFile(filename = FileSystem->getFileBasename(meshFile->getFileName(), false) + ".skeleton")) + file = FileSystem->createAndOpenFile(filename); + else + file = FileSystem->createAndOpenFile(FileSystem->getFileDir(meshFile->getFileName())+"/"+filename); + if (!file) + { + os::Printer::log("Could not load matching skeleton", name); + return false; + } + + s16 id; + file->read(&id, 2); + if (SwapEndian) + id = os::Byteswap::byteswap(id); + if (id != COGRE_HEADER) + { + file->drop(); + return false; + } + + core::stringc skeletonVersion; + ChunkData head; + readString(file, head, skeletonVersion); + if (skeletonVersion != "[Serializer_v1.10]") + { + file->drop(); + return false; + } + + u16 bone=0; + f32 animationTotal=0.f; + while(file->getPos() < file->getSize()) + { + ChunkData data; + readChunkData(file, data); + + switch(data.header.id) + { + case COGRE_SKELETON: + { + Skeleton.Bones.push_back(OgreBone()); + OgreBone& bone = Skeleton.Bones.getLast(); + readString(file, data, bone.Name); + readShort(file, data, &bone.Handle); + readVector(file, data, bone.Position); + readQuaternion(file, data, bone.Orientation); +#ifdef IRR_OGRE_LOADER_DEBUG + os::Printer::log("Bone", bone.Name+" ("+core::stringc(bone.Handle)+")", ELL_DEBUG); + os::Printer::log("Position", core::stringc(bone.Position.X)+" "+core::stringc(bone.Position.Y)+" "+core::stringc(bone.Position.Z), ELL_DEBUG); + os::Printer::log("Rotation quat", core::stringc(bone.Orientation.W)+" "+core::stringc(bone.Orientation.X)+" "+core::stringc(bone.Orientation.Y)+" "+core::stringc(bone.Orientation.Z), ELL_DEBUG); +// core::vector3df rot; +// bone.Orientation.toEuler(rot); +// rot *= core::RADTODEG; +// os::Printer::log("Rotation", core::stringc(rot.X)+" "+core::stringc(rot.Y)+" "+core::stringc(rot.Z)); +#endif + if (data.read<(data.header.length-bone.Name.size())) + { + readVector(file, data, bone.Scale); + bone.Scale.X *= -1.f; + } + else + bone.Scale=core::vector3df(1,1,1); + bone.Parent=0xffff; + } + break; + case COGRE_BONE_PARENT: + { + u16 parent; + readShort(file, data, &bone); + readShort(file, data, &parent); + if (bonedrop(); + return true; +} + + +void COgreMeshFileLoader::readChunkData(io::IReadFile* file, ChunkData& data) +{ + file->read(&data.header, sizeof(ChunkHeader)); + if (SwapEndian) + { + data.header.id = os::Byteswap::byteswap(data.header.id); + data.header.length = os::Byteswap::byteswap(data.header.length); + } + data.read += sizeof(ChunkHeader); +} + + +void COgreMeshFileLoader::readString(io::IReadFile* file, ChunkData& data, core::stringc& out) +{ + c8 c = 0; + out = ""; + + while (c!='\n') + { + file->read(&c, sizeof(c8)); + if (c!='\n') + out.append(c); + + } + data.read+=out.size()+1; +} + + +void COgreMeshFileLoader::readBool(io::IReadFile* file, ChunkData& data, bool& out) +{ + // normal C type because we read a bit string + char c = 0; + file->read(&c, sizeof(char)); + out=(c!=0); + ++data.read; +} + + +void COgreMeshFileLoader::readInt(io::IReadFile* file, ChunkData& data, s32* out, u32 num) +{ + // normal C type because we read a bit string + file->read(out, sizeof(int)*num); + if (SwapEndian) + { + for (u32 i=0; iread(out, sizeof(short)*num); + if (SwapEndian) + { + for (u32 i=0; iread(out, sizeof(float)*num); + if (SwapEndian) + { + for (u32 i=0; i Filename; + core::stringc Alias; + core::stringc CoordsType; + core::stringc MipMaps; + core::stringc Alpha; + }; + + struct OgrePass + { + OgrePass() : AmbientTokenColor(false), + DiffuseTokenColor(false), SpecularTokenColor(false), + EmissiveTokenColor(false), + MaxLights(8), PointSize(1.0f), PointSprites(false), + PointSizeMin(0), PointSizeMax(0) {} + + video::SMaterial Material; + OgreTexture Texture; + bool AmbientTokenColor; + bool DiffuseTokenColor; + bool SpecularTokenColor; + bool EmissiveTokenColor; + u32 MaxLights; + f32 PointSize; + bool PointSprites; + u32 PointSizeMin; + u32 PointSizeMax; + }; + + struct OgreTechnique + { + OgreTechnique() : Name(""), LODIndex(0) {} + + core::stringc Name; + core::stringc Scheme; + u16 LODIndex; + core::array Passes; + }; + + struct OgreMaterial + { + OgreMaterial() : Name(""), ReceiveShadows(true), + TransparencyCastsShadows(false) {} + + core::stringc Name; + bool ReceiveShadows; + bool TransparencyCastsShadows; + core::array LODDistances; + core::array Techniques; + }; + + struct OgreVertexBuffer + { + OgreVertexBuffer() : BindIndex(0), VertexSize(0), Data(0) {} + + u16 BindIndex; + u16 VertexSize; + core::array Data; + }; + + struct OgreVertexElement + { + u16 Source, + Type, + Semantic, + Offset, + Index; + }; + + struct OgreGeometry + { + s32 NumVertex; + core::array Elements; + core::array Buffers; + core::array Vertices; + core::array Normals; + core::array Colors; + core::array TexCoords; + }; + + struct OgreTextureAlias + { + OgreTextureAlias() {}; + OgreTextureAlias(const core::stringc& a, const core::stringc& b) : Texture(a), Alias(b) {}; + core::stringc Texture; + core::stringc Alias; + }; + + struct OgreBoneAssignment + { + s32 VertexID; + u16 BoneID; + f32 Weight; + }; + + struct OgreSubMesh + { + core::stringc Material; + bool SharedVertices; + core::array Indices; + OgreGeometry Geometry; + u16 Operation; + core::array TextureAliases; + core::array BoneAssignments; + bool Indices32Bit; + }; + + struct OgreMesh + { + bool SkeletalAnimation; + OgreGeometry Geometry; + core::array SubMeshes; + core::array BoneAssignments; + core::vector3df BBoxMinEdge; + core::vector3df BBoxMaxEdge; + f32 BBoxRadius; + }; + + struct OgreBone + { + core::stringc Name; + core::vector3df Position; + core::quaternion Orientation; + core::vector3df Scale; + u16 Handle; + u16 Parent; + }; + + struct OgreKeyframe + { + u16 BoneID; + f32 Time; + core::vector3df Position; + core::quaternion Orientation; + core::vector3df Scale; + }; + + struct OgreAnimation + { + core::stringc Name; + f32 Length; + core::array Keyframes; + }; + + struct OgreSkeleton + { + core::array Bones; + core::array Animations; + }; + + bool readChunk(io::IReadFile* file); + bool readObjectChunk(io::IReadFile* file, ChunkData& parent, OgreMesh& mesh); + bool readGeometry(io::IReadFile* file, ChunkData& parent, OgreGeometry& geometry); + bool readVertexDeclaration(io::IReadFile* file, ChunkData& parent, OgreGeometry& geometry); + bool readVertexBuffer(io::IReadFile* file, ChunkData& parent, OgreGeometry& geometry); + bool readSubMesh(io::IReadFile* file, ChunkData& parent, OgreSubMesh& subMesh); + + void readChunkData(io::IReadFile* file, ChunkData& data); + void readString(io::IReadFile* file, ChunkData& data, core::stringc& out); + void readBool(io::IReadFile* file, ChunkData& data, bool& out); + void readInt(io::IReadFile* file, ChunkData& data, s32* out, u32 num=1); + void readShort(io::IReadFile* file, ChunkData& data, u16* out, u32 num=1); + void readFloat(io::IReadFile* file, ChunkData& data, f32* out, u32 num=1); + void readVector(io::IReadFile* file, ChunkData& data, core::vector3df& out); + void readQuaternion(io::IReadFile* file, ChunkData& data, core::quaternion& out); + + void composeMeshBufferMaterial(scene::IMeshBuffer* mb, const core::stringc& materialName); + scene::SMeshBuffer* composeMeshBuffer(const core::array& indices, const OgreGeometry& geom); + scene::SMeshBufferLightMap* composeMeshBufferLightMap(const core::array& indices, const OgreGeometry& geom); + scene::IMeshBuffer* composeMeshBufferSkinned(scene::CSkinnedMesh& mesh, const core::array& indices, const OgreGeometry& geom); + void composeObject(void); + bool readColor(io::IReadFile* meshFile, video::SColor& col); + void getMaterialToken(io::IReadFile* file, core::stringc& token, bool noNewLine=false); + void readTechnique(io::IReadFile* meshFile, OgreMaterial& mat); + void readPass(io::IReadFile* file, OgreTechnique& technique); + void loadMaterials(io::IReadFile* file); + bool loadSkeleton(io::IReadFile* meshFile, const core::stringc& name); + void clearMeshes(); + + io::IFileSystem* FileSystem; + video::IVideoDriver* Driver; + + core::stringc Version; + bool SwapEndian; + core::array Meshes; + io::path CurrentlyLoadingFromPath; + + core::array Materials; + OgreSkeleton Skeleton; + + IMesh* Mesh; + u32 NumUV; +}; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/COpenGLCacheHandler.cpp b/source/Irrlicht/COpenGLCacheHandler.cpp new file mode 100644 index 00000000..a8cab54c --- /dev/null +++ b/source/Irrlicht/COpenGLCacheHandler.cpp @@ -0,0 +1,131 @@ +// Copyright (C) 2015 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#include "COpenGLCacheHandler.h" + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#include "COpenGLDriver.h" + +namespace irr +{ +namespace video +{ + +/* COpenGLCacheHandler */ + +COpenGLCacheHandler::COpenGLCacheHandler(COpenGLDriver* driver) : + COpenGLCoreCacheHandler(driver), AlphaMode(GL_ALWAYS), AlphaRef(0.f), AlphaTest(false), + MatrixMode(GL_MODELVIEW), ClientActiveTexture(GL_TEXTURE0), ClientStateVertex(false), + ClientStateNormal(false), ClientStateColor(false), ClientStateTexCoord0(false) +{ + // Initial OpenGL values from specification. + + glAlphaFunc(AlphaMode, AlphaRef); + glDisable(GL_ALPHA_TEST); + + glMatrixMode(MatrixMode); + + Driver->irrGlClientActiveTexture(ClientActiveTexture); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +} + +COpenGLCacheHandler::~COpenGLCacheHandler() +{ +} + +void COpenGLCacheHandler::setAlphaFunc(GLenum mode, GLclampf ref) +{ + if (AlphaMode != mode || AlphaRef != ref) + { + glAlphaFunc(mode, ref); + + AlphaMode = mode; + AlphaRef = ref; + } +} + +void COpenGLCacheHandler::setAlphaTest(bool enable) +{ + if (AlphaTest != enable) + { + if (enable) + glEnable(GL_ALPHA_TEST); + else + glDisable(GL_ALPHA_TEST); + AlphaTest = enable; + } +} + +void COpenGLCacheHandler::setClientState(bool vertex, bool normal, bool color, bool texCoord0) +{ + if (ClientStateVertex != vertex) + { + if (vertex) + glEnableClientState(GL_VERTEX_ARRAY); + else + glDisableClientState(GL_VERTEX_ARRAY); + + ClientStateVertex = vertex; + } + + if (ClientStateNormal != normal) + { + if (normal) + glEnableClientState(GL_NORMAL_ARRAY); + else + glDisableClientState(GL_NORMAL_ARRAY); + + ClientStateNormal = normal; + } + + if (ClientStateColor != color) + { + if (color) + glEnableClientState(GL_COLOR_ARRAY); + else + glDisableClientState(GL_COLOR_ARRAY); + + ClientStateColor = color; + } + + if (ClientStateTexCoord0 != texCoord0) + { + setClientActiveTexture(GL_TEXTURE0_ARB); + + if (texCoord0) + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + else + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + ClientStateTexCoord0 = texCoord0; + } +} + +void COpenGLCacheHandler::setMatrixMode(GLenum mode) +{ + if (MatrixMode != mode) + { + glMatrixMode(mode); + MatrixMode = mode; + } +} + +void COpenGLCacheHandler::setClientActiveTexture(GLenum texture) +{ + if (ClientActiveTexture != texture) + { + Driver->irrGlClientActiveTexture(texture); + ClientActiveTexture = texture; + } +} + +} // end namespace +} // end namespace + +#endif // _IRR_COMPILE_WITH_OPENGL_ diff --git a/source/Irrlicht/COpenGLCacheHandler.h b/source/Irrlicht/COpenGLCacheHandler.h new file mode 100644 index 00000000..f7d14c03 --- /dev/null +++ b/source/Irrlicht/COpenGLCacheHandler.h @@ -0,0 +1,66 @@ +// Copyright (C) 2015 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __C_OPENGL_CACHE_HANDLER_H_INCLUDED__ +#define __C_OPENGL_CACHE_HANDLER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#include "COpenGLCommon.h" + +#include "COpenGLCoreFeature.h" +#include "COpenGLCoreTexture.h" +#include "COpenGLCoreCacheHandler.h" + +namespace irr +{ +namespace video +{ + + class COpenGLCacheHandler : public COpenGLCoreCacheHandler + { + public: + COpenGLCacheHandler(COpenGLDriver* driver); + virtual ~COpenGLCacheHandler(); + + // Alpha calls. + + void setAlphaFunc(GLenum mode, GLclampf ref); + + void setAlphaTest(bool enable); + + // Client state calls. + + void setClientState(bool vertex, bool normal, bool color, bool texCoord0); + + // Matrix calls. + + void setMatrixMode(GLenum mode); + + // Texture calls. + + void setClientActiveTexture(GLenum texture); + + protected: + GLenum AlphaMode; + GLclampf AlphaRef; + bool AlphaTest; + + GLenum MatrixMode; + + GLenum ClientActiveTexture; + + bool ClientStateVertex; + bool ClientStateNormal; + bool ClientStateColor; + bool ClientStateTexCoord0; + }; + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_OPENGL_ +#endif diff --git a/source/Irrlicht/COpenGLCommon.h b/source/Irrlicht/COpenGLCommon.h new file mode 100644 index 00000000..4d38c3a0 --- /dev/null +++ b/source/Irrlicht/COpenGLCommon.h @@ -0,0 +1,202 @@ +// Copyright (C) 2015 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OPENGL_COMMON_H_INCLUDED__ +#define __C_OPENGL_COMMON_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#if defined(_IRR_WINDOWS_API_) + #define WIN32_LEAN_AND_MEAN + #include + #if defined(_IRR_OPENGL_USE_EXTPOINTER_) + #define GL_GLEXT_LEGACY 1 + #endif + #include + #if defined(_IRR_OPENGL_USE_EXTPOINTER_) + #include "glext.h" + #endif + #include "wglext.h" + + #ifdef _MSC_VER + #pragma comment(lib, "OpenGL32.lib") + #endif + +#elif defined(_IRR_COMPILE_WITH_OSX_DEVICE_) + #if defined(_IRR_OPENGL_USE_EXTPOINTER_) + #define GL_GLEXT_LEGACY 1 + #endif + #include + #if defined(_IRR_OPENGL_USE_EXTPOINTER_) + #include "glext.h" + #endif +#elif defined(_IRR_COMPILE_WITH_SDL_DEVICE_) && !defined(_IRR_COMPILE_WITH_X11_DEVICE_) + #if defined(_IRR_OPENGL_USE_EXTPOINTER_) + #define GL_GLEXT_LEGACY 1 + #define GLX_GLXEXT_LEGACY 1 + #else + #define GL_GLEXT_PROTOTYPES 1 + #define GLX_GLXEXT_PROTOTYPES 1 + #endif + #define NO_SDL_GLEXT + #include + #include + #include "glext.h" +#else + #if defined(_IRR_OPENGL_USE_EXTPOINTER_) + #define GL_GLEXT_LEGACY 1 + #define GLX_GLXEXT_LEGACY 1 + #else + #define GL_GLEXT_PROTOTYPES 1 + #define GLX_GLXEXT_PROTOTYPES 1 + #endif + #include + #include + #if defined(_IRR_OPENGL_USE_EXTPOINTER_) + #include "glext.h" + #undef GLX_ARB_get_proc_address + #include "glxext.h" + #endif +#endif + +#ifndef GL_ARB_shader_objects +typedef char GLcharARB; +typedef unsigned int GLhandleARB; +#endif + +#ifndef GL_VERSION_2_0 +typedef char GLchar; +#endif + +// Blending definitions. + +#if !defined(GL_VERSION_1_4) +#if defined(GL_EXT_blend_subtract) || defined(GL_EXT_blend_minmax) || defined(GL_EXT_blend_logic_op) +#define GL_FUNC_ADD GL_FUNC_ADD_EXT +#else +#define GL_FUNC_ADD 0 +#endif +#endif + +// FBO definitions. + +#if !defined(GL_VERSION_3_0) && !defined(GL_ARB_framebuffer_object) +#ifdef GL_EXT_framebuffer_object +#define GL_FRAMEBUFFER GL_FRAMEBUFFER_EXT +#define GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_EXT +#define GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT_EXT +#define GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT_EXT +#define GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_EXT +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT +#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT +#define GL_FRAMEBUFFER_UNSUPPORTED GL_FRAMEBUFFER_UNSUPPORTED_EXT +#else +#define GL_FRAMEBUFFER 0 +#define GL_COLOR_ATTACHMENT0 0 +#define GL_DEPTH_ATTACHMENT 0 +#define GL_STENCIL_ATTACHMENT 0 +#define GL_FRAMEBUFFER_COMPLETE 0 +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 1 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 2 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 3 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 4 +#define GL_FRAMEBUFFER_UNSUPPORTED 5 +#endif +#endif + +#ifdef GL_EXT_framebuffer_object +#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT +#else +#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS 6 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 7 +#endif + +// MipMaps definitions. + +#if !defined(GL_VERSION_1_4) +#ifdef GL_SGIS_generate_mipmap +#define GL_GENERATE_MIPMAP GL_GENERATE_MIPMAP_SGIS +#define GL_GENERATE_MIPMAP_HINT GL_GENERATE_MIPMAP_HINT_SGIS +#else +#define GL_GENERATE_MIPMAP 0 +#define GL_GENERATE_MIPMAP_HINT 0 +#endif +#endif + +// Texture definitions. + +#if !defined(GL_VERSION_1_3) +#ifdef GL_ARB_multitexture +#define GL_TEXTURE0 GL_TEXTURE0_ARB +#else +#define GL_TEXTURE0 0 +#endif +#endif + +#if !defined(GL_VERSION_1_3) +#ifdef GL_ARB_texture_cube_map +#define GL_TEXTURE_CUBE_MAP GL_TEXTURE_CUBE_MAP_ARB +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB +#elif defined(GL_EXT_texture_cube_map) +#define GL_TEXTURE_CUBE_MAP GL_TEXTURE_CUBE_MAP_EXT +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT +#else +#define GL_TEXTURE_CUBE_MAP 0 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0 +#endif +#endif + +// To check if this header is in the current compile unit (different GL driver implementations use different "GLCommon" headers in Irrlicht) +#define IRR_COMPILE_GL_COMMON + +namespace irr +{ +namespace video +{ + + // Forward declarations. + + class COpenGLCoreFeature; + + template + class COpenGLCoreTexture; + + template + class COpenGLCoreRenderTarget; + + template + class COpenGLCoreCacheHandler; + + class COpenGLDriver; + typedef COpenGLCoreTexture COpenGLTexture; + typedef COpenGLCoreRenderTarget COpenGLRenderTarget; + class COpenGLCacheHandler; + +} +} + +#endif +#endif diff --git a/source/Irrlicht/COpenGLCoreCacheHandler.h b/source/Irrlicht/COpenGLCoreCacheHandler.h new file mode 100644 index 00000000..5726e5f2 --- /dev/null +++ b/source/Irrlicht/COpenGLCoreCacheHandler.h @@ -0,0 +1,647 @@ +// Copyright (C) 2015 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OGLCORE_CACHE_HANDLER_H_INCLUDED__ +#define __C_OGLCORE_CACHE_HANDLER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#if defined(_IRR_COMPILE_WITH_OPENGL_) || defined(_IRR_COMPILE_WITH_OGLES1_) || defined(_IRR_COMPILE_WITH_OGLES2_) + +#include "SMaterial.h" +#include "ITexture.h" + +namespace irr +{ +namespace video +{ + +enum ESetTextureActive +{ + EST_ACTIVE_ALWAYS, // texture unit always active after set call + EST_ACTIVE_ON_CHANGE // texture unit only active after call when texture changed in cache +}; + + +template +class COpenGLCoreCacheHandler +{ + class STextureCache + { + public: + STextureCache(COpenGLCoreCacheHandler& cacheHandler, E_DRIVER_TYPE driverType, u32 textureCount) : + CacheHandler(cacheHandler), DriverType(driverType), TextureCount(textureCount) + { + for (u32 i = 0; i < MATERIAL_MAX_TEXTURES; ++i) + { + Texture[i] = 0; + } + } + + ~STextureCache() + { + clear(); + } + + const TOpenGLTexture* operator[](int index) const + { + if (static_cast(index) < MATERIAL_MAX_TEXTURES) + return Texture[static_cast(index)]; + + return 0; + } + + const TOpenGLTexture* get(u32 index) const + { + if (index < MATERIAL_MAX_TEXTURES) + return Texture[index]; + + return 0; + } + + bool set(u32 index, const ITexture* texture, ESetTextureActive esa=EST_ACTIVE_ALWAYS) + { + bool status = false; + + E_DRIVER_TYPE type = DriverType; + + if (index < MATERIAL_MAX_TEXTURES && index < TextureCount) + { + if ( esa == EST_ACTIVE_ALWAYS ) + CacheHandler.setActiveTexture(GL_TEXTURE0 + index); + + const TOpenGLTexture* prevTexture = Texture[index]; + + if (texture != prevTexture) + { + if ( esa == EST_ACTIVE_ON_CHANGE ) + CacheHandler.setActiveTexture(GL_TEXTURE0 + index); + + if (texture) + { + type = texture->getDriverType(); + + if (type == DriverType) + { + texture->grab(); + + const TOpenGLTexture* curTexture = static_cast(texture); + const GLenum curTextureType = curTexture->getOpenGLTextureType(); + const GLenum prevTextureType = (prevTexture) ? prevTexture->getOpenGLTextureType() : curTextureType; + + if (curTextureType != prevTextureType) + { + glBindTexture(prevTextureType, 0); + +#if ( defined(IRR_COMPILE_GL_COMMON) || defined(IRR_COMPILE_GLES_COMMON) ) + glDisable(prevTextureType); + glEnable(curTextureType); +#endif + } +#if ( defined(IRR_COMPILE_GL_COMMON) || defined(IRR_COMPILE_GLES_COMMON) ) + else if (!prevTexture) + glEnable(curTextureType); +#endif + + glBindTexture(curTextureType, static_cast(texture)->getOpenGLTextureName()); + } + else + { + texture = 0; + + os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR); + os::Printer::log("Texture type", irr::core::stringc((int)type), ELL_ERROR); + os::Printer::log("Driver (or cache handler) type", irr::core::stringc((int)DriverType), ELL_ERROR); + } + } + + if (!texture && prevTexture) + { + const GLenum prevTextureType = prevTexture->getOpenGLTextureType(); + + glBindTexture(prevTextureType, 0); + +#if ( defined(IRR_COMPILE_GL_COMMON) || defined(IRR_COMPILE_GLES_COMMON) ) + glDisable(prevTextureType); +#endif + } + + Texture[index] = static_cast(texture); + + if (prevTexture) + prevTexture->drop(); + } + + status = true; + } + + return (status && type == DriverType); + } + + void remove(ITexture* texture) + { + if (!texture) + return; + + for (u32 i = 0; i < MATERIAL_MAX_TEXTURES; ++i) + { + if (Texture[i] == texture) + { + Texture[i] = 0; + + texture->drop(); + } + } + } + + void clear() + { + for (u32 i = 0; i < MATERIAL_MAX_TEXTURES; ++i) + { + if (Texture[i]) + { + const TOpenGLTexture* prevTexture = Texture[i]; + + Texture[i] = 0; + + prevTexture->drop(); + } + } + } + + private: + COpenGLCoreCacheHandler& CacheHandler; + + E_DRIVER_TYPE DriverType; + + const TOpenGLTexture* Texture[MATERIAL_MAX_TEXTURES]; + u32 TextureCount; + }; + +public: + COpenGLCoreCacheHandler(TOpenGLDriver* driver) : + Driver(driver), +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable: 4355) // Warning: "'this' : used in base member initializer list. ". It's OK, we don't use the reference in STextureCache constructor. +#endif + TextureCache(STextureCache(*this, driver->getDriverType(), driver->getFeature().MaxTextureUnits)), +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + FrameBufferCount(0), BlendEquation(0), BlendSourceRGB(0), + BlendDestinationRGB(0), BlendSourceAlpha(0), BlendDestinationAlpha(0), Blend(0), BlendEquationInvalid(false), BlendFuncInvalid(false), BlendInvalid(false), + ColorMask(0), ColorMaskInvalid(false), CullFaceMode(GL_BACK), CullFace(false), DepthFunc(GL_LESS), DepthMask(true), DepthTest(false), FrameBufferID(0), + ProgramID(0), ActiveTexture(GL_TEXTURE0), ViewportX(0), ViewportY(0) + { + const COpenGLCoreFeature& feature = Driver->getFeature(); + + FrameBufferCount = core::max_(static_cast(1), static_cast(feature.MultipleRenderTarget)); + + BlendEquation = new GLenum[FrameBufferCount]; + BlendSourceRGB = new GLenum[FrameBufferCount]; + BlendDestinationRGB = new GLenum[FrameBufferCount]; + BlendSourceAlpha = new GLenum[FrameBufferCount]; + BlendDestinationAlpha = new GLenum[FrameBufferCount]; + Blend = new bool[FrameBufferCount]; + ColorMask = new u8[FrameBufferCount]; + + // Initial OpenGL values from specification. + + if (feature.BlendOperation) + { + Driver->irrGlBlendEquation(GL_FUNC_ADD); + } + + for (u32 i = 0; i < FrameBufferCount; ++i) + { + BlendEquation[i] = GL_FUNC_ADD; + + BlendSourceRGB[i] = GL_ONE; + BlendDestinationRGB[i] = GL_ZERO; + BlendSourceAlpha[i] = GL_ONE; + BlendDestinationAlpha[i] = GL_ZERO; + + Blend[i] = false; + ColorMask[i] = ECP_ALL; + } + + glBlendFunc(GL_ONE, GL_ZERO); + glDisable(GL_BLEND); + + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + glCullFace(CullFaceMode); + glDisable(GL_CULL_FACE); + + glDepthFunc(DepthFunc); + glDepthMask(GL_TRUE); + glDisable(GL_DEPTH_TEST); + + Driver->irrGlActiveTexture(ActiveTexture); + +#if ( defined(IRR_COMPILE_GL_COMMON) || defined(IRR_COMPILE_GLES_COMMON) ) + glDisable(GL_TEXTURE_2D); +#endif + + const core::dimension2d ScreenSize = Driver->getScreenSize(); + ViewportWidth = ScreenSize.Width; + ViewportHeight = ScreenSize.Height; + glViewport(ViewportX, ViewportY, ViewportWidth, ViewportHeight); + } + + virtual ~COpenGLCoreCacheHandler() + { + delete[] BlendEquation; + delete[] BlendSourceRGB; + delete[] BlendDestinationRGB; + delete[] BlendSourceAlpha; + delete[] BlendDestinationAlpha; + delete[] Blend; + + delete[] ColorMask; + } + + E_DRIVER_TYPE getDriverType() const + { + return Driver->getDriverType(); + } + + STextureCache& getTextureCache() + { + return TextureCache; + } + + // Blending calls. + + void setBlendEquation(GLenum mode) + { + if (BlendEquation[0] != mode || BlendEquationInvalid) + { + Driver->irrGlBlendEquation(mode); + + for (GLuint i = 0; i < FrameBufferCount; ++i) + BlendEquation[i] = mode; + + BlendEquationInvalid = false; + } + } + + void setBlendEquationIndexed(GLuint index, GLenum mode) + { + if (index < FrameBufferCount && BlendEquation[index] != mode) + { + Driver->irrGlBlendEquationIndexed(index, mode); + + BlendEquation[index] = mode; + BlendEquationInvalid = true; + } + } + + void setBlendFunc(GLenum source, GLenum destination) + { + if (BlendSourceRGB[0] != source || BlendDestinationRGB[0] != destination || + BlendSourceAlpha[0] != source || BlendDestinationAlpha[0] != destination || + BlendFuncInvalid) + { + glBlendFunc(source, destination); + + for (GLuint i = 0; i < FrameBufferCount; ++i) + { + BlendSourceRGB[i] = source; + BlendDestinationRGB[i] = destination; + BlendSourceAlpha[i] = source; + BlendDestinationAlpha[i] = destination; + } + + BlendFuncInvalid = false; + } + } + + void setBlendFuncSeparate(GLenum sourceRGB, GLenum destinationRGB, GLenum sourceAlpha, GLenum destinationAlpha) + { + if (sourceRGB != sourceAlpha || destinationRGB != destinationAlpha) + { + if (BlendSourceRGB[0] != sourceRGB || BlendDestinationRGB[0] != destinationRGB || + BlendSourceAlpha[0] != sourceAlpha || BlendDestinationAlpha[0] != destinationAlpha || + BlendFuncInvalid) + { + Driver->irrGlBlendFuncSeparate(sourceRGB, destinationRGB, sourceAlpha, destinationAlpha); + + for (GLuint i = 0; i < FrameBufferCount; ++i) + { + BlendSourceRGB[i] = sourceRGB; + BlendDestinationRGB[i] = destinationRGB; + BlendSourceAlpha[i] = sourceAlpha; + BlendDestinationAlpha[i] = destinationAlpha; + } + + BlendFuncInvalid = false; + } + } + else + { + setBlendFunc(sourceRGB, destinationRGB); + } + } + + void setBlendFuncIndexed(GLuint index, GLenum source, GLenum destination) + { + if (index < FrameBufferCount && (BlendSourceRGB[index] != source || BlendDestinationRGB[index] != destination || + BlendSourceAlpha[index] != source || BlendDestinationAlpha[index] != destination)) + { + Driver->irrGlBlendFuncIndexed(index, source, destination); + + BlendSourceRGB[index] = source; + BlendDestinationRGB[index] = destination; + BlendSourceAlpha[index] = source; + BlendDestinationAlpha[index] = destination; + BlendFuncInvalid = true; + } + } + + void setBlendFuncSeparateIndexed(GLuint index, GLenum sourceRGB, GLenum destinationRGB, GLenum sourceAlpha, GLenum destinationAlpha) + { + if (sourceRGB != sourceAlpha || destinationRGB != destinationAlpha) + { + if (index < FrameBufferCount && (BlendSourceRGB[index] != sourceRGB || BlendDestinationRGB[index] != destinationRGB || + BlendSourceAlpha[index] != sourceAlpha || BlendDestinationAlpha[index] != destinationAlpha)) + { + Driver->irrGlBlendFuncSeparateIndexed(index, sourceRGB, destinationRGB, sourceAlpha, destinationAlpha); + + BlendSourceRGB[index] = sourceRGB; + BlendDestinationRGB[index] = destinationRGB; + BlendSourceAlpha[index] = sourceAlpha; + BlendDestinationAlpha[index] = destinationAlpha; + BlendFuncInvalid = true; + } + } + else + { + setBlendFuncIndexed(index, sourceRGB, destinationRGB); + } + } + + void setBlend(bool enable) + { + if (Blend[0] != enable || BlendInvalid) + { + if (enable) + glEnable(GL_BLEND); + else + glDisable(GL_BLEND); + + for (GLuint i = 0; i < FrameBufferCount; ++i) + Blend[i] = enable; + + BlendInvalid = false; + } + } + + void setBlendIndexed(GLuint index, bool enable) + { + if (index < FrameBufferCount && Blend[index] != enable) + { + if (enable) + Driver->irrGlEnableIndexed(GL_BLEND, index); + else + Driver->irrGlDisableIndexed(GL_BLEND, index); + + Blend[index] = enable; + BlendInvalid = true; + } + } + + // Color Mask. + + void getColorMask(u8& mask) + { + mask = ColorMask[0]; + } + + void setColorMask(u8 mask) + { + if (ColorMask[0] != mask || ColorMaskInvalid) + { + glColorMask((mask & ECP_RED) ? GL_TRUE : GL_FALSE, (mask & ECP_GREEN) ? GL_TRUE : GL_FALSE, (mask & ECP_BLUE) ? GL_TRUE : GL_FALSE, (mask & ECP_ALPHA) ? GL_TRUE : GL_FALSE); + + for (GLuint i = 0; i < FrameBufferCount; ++i) + ColorMask[i] = mask; + + ColorMaskInvalid = false; + } + } + + void setColorMaskIndexed(GLuint index, u8 mask) + { + if (index < FrameBufferCount && ColorMask[index] != mask) + { + Driver->irrGlColorMaskIndexed(index, (mask & ECP_RED) ? GL_TRUE : GL_FALSE, (mask & ECP_GREEN) ? GL_TRUE : GL_FALSE, (mask & ECP_BLUE) ? GL_TRUE : GL_FALSE, (mask & ECP_ALPHA) ? GL_TRUE : GL_FALSE); + + ColorMask[index] = mask; + ColorMaskInvalid = true; + } + } + + // Cull face calls. + + void setCullFaceFunc(GLenum mode) + { + if (CullFaceMode != mode) + { + glCullFace(mode); + CullFaceMode = mode; + } + } + + void setCullFace(bool enable) + { + if (CullFace != enable) + { + if (enable) + glEnable(GL_CULL_FACE); + else + glDisable(GL_CULL_FACE); + + CullFace = enable; + } + } + + // Depth calls. + + void setDepthFunc(GLenum mode) + { + if (DepthFunc != mode) + { + glDepthFunc(mode); + DepthFunc = mode; + } + } + + void getDepthMask(bool& depth) + { + depth = DepthMask; + } + + void setDepthMask(bool enable) + { + if (DepthMask != enable) + { + if (enable) + glDepthMask(GL_TRUE); + else + glDepthMask(GL_FALSE); + + DepthMask = enable; + } + } + + void getDepthTest(bool& enable) + { + enable = DepthTest; + } + + void setDepthTest(bool enable) + { + if (DepthTest != enable) + { + if (enable) + glEnable(GL_DEPTH_TEST); + else + glDisable(GL_DEPTH_TEST); + + DepthTest = enable; + } + } + + // FBO calls. + + void getFBO(GLuint& frameBufferID) const + { + frameBufferID = FrameBufferID; + } + + void setFBO(GLuint frameBufferID) + { + if (FrameBufferID != frameBufferID) + { + Driver->irrGlBindFramebuffer(GL_FRAMEBUFFER, frameBufferID); + FrameBufferID = frameBufferID; + } + } + + // Shaders calls. + + void getProgram(GLuint& programID) const + { + programID = ProgramID; + } + + void setProgram(GLuint programID) + { + if (ProgramID != programID) + { + Driver->irrGlUseProgram(programID); + ProgramID = programID; + } + } + + // Texture calls. + + void getActiveTexture(GLenum& texture) const + { + texture = ActiveTexture; + } + + void setActiveTexture(GLenum texture) + { + if (ActiveTexture != texture) + { + Driver->irrGlActiveTexture(texture); + ActiveTexture = texture; + } + } + + // Viewport calls. + + void getViewport(GLint& viewportX, GLint& viewportY, GLsizei& viewportWidth, GLsizei& viewportHeight) const + { + viewportX = ViewportX; + viewportY = ViewportY; + viewportWidth = ViewportWidth; + viewportHeight = ViewportHeight; + } + + void setViewport(GLint viewportX, GLint viewportY, GLsizei viewportWidth, GLsizei viewportHeight) + { + if (ViewportX != viewportX || ViewportY != viewportY || ViewportWidth != viewportWidth || ViewportHeight != viewportHeight) + { + glViewport(viewportX, viewportY, viewportWidth, viewportHeight); + ViewportX = viewportX; + ViewportY = viewportY; + ViewportWidth = viewportWidth; + ViewportHeight = viewportHeight; + } + } + + //! Compare material to current cache and update it when there are differences + // Some material renderers do change the cache beyond the original material settings + // This corrects the material to represent the current cache state again. + void correctCacheMaterial(irr::video::SMaterial& material) + { + // Fix textures which got removed + for ( u32 i=0; i < MATERIAL_MAX_TEXTURES; ++i ) + { + if ( material.TextureLayer[i].Texture && !TextureCache[i] ) + { + material.TextureLayer[i].Texture = 0; + } + } + } + +protected: + TOpenGLDriver* Driver; + + STextureCache TextureCache; + + GLuint FrameBufferCount; + + GLenum* BlendEquation; + GLenum* BlendSourceRGB; + GLenum* BlendDestinationRGB; + GLenum* BlendSourceAlpha; + GLenum* BlendDestinationAlpha; + bool* Blend; + bool BlendEquationInvalid; + bool BlendFuncInvalid; + bool BlendInvalid; + + + u8* ColorMask; + bool ColorMaskInvalid; + + GLenum CullFaceMode; + bool CullFace; + + GLenum DepthFunc; + bool DepthMask; + bool DepthTest; + + GLuint FrameBufferID; + + GLuint ProgramID; + + GLenum ActiveTexture; + + GLint ViewportX; + GLint ViewportY; + GLsizei ViewportWidth; + GLsizei ViewportHeight; +}; + +} +} + +#endif +#endif diff --git a/source/Irrlicht/COpenGLCoreFeature.h b/source/Irrlicht/COpenGLCoreFeature.h new file mode 100644 index 00000000..6ec58227 --- /dev/null +++ b/source/Irrlicht/COpenGLCoreFeature.h @@ -0,0 +1,41 @@ +// Copyright (C) 2015 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OGLCORE_FEATURE_H_INCLUDED__ +#define __C_OGLCORE_FEATURE_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#if defined(_IRR_COMPILE_WITH_OPENGL_) || defined(_IRR_COMPILE_WITH_OGLES1_) || defined(_IRR_COMPILE_WITH_OGLES2_) + +#include "irrTypes.h" + +namespace irr +{ +namespace video +{ + +class COpenGLCoreFeature +{ +public: + COpenGLCoreFeature() : BlendOperation(false), ColorAttachment(0), MultipleRenderTarget(0), MaxTextureUnits(1) + { + } + + virtual ~COpenGLCoreFeature() + { + } + + bool BlendOperation; + + u8 ColorAttachment; + u8 MultipleRenderTarget; + u8 MaxTextureUnits; +}; + +} +} + +#endif +#endif diff --git a/source/Irrlicht/COpenGLCoreRenderTarget.h b/source/Irrlicht/COpenGLCoreRenderTarget.h new file mode 100644 index 00000000..95dbd395 --- /dev/null +++ b/source/Irrlicht/COpenGLCoreRenderTarget.h @@ -0,0 +1,393 @@ +// Copyright (C) 2015 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OGLCORE_RENDER_TARGET_H_INCLUDED__ +#define __C_OGLCORE_RENDER_TARGET_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#if defined(_IRR_COMPILE_WITH_OPENGL_) || defined(_IRR_COMPILE_WITH_OGLES1_) || defined(_IRR_COMPILE_WITH_OGLES2_) + +#include "IRenderTarget.h" + +namespace irr +{ +namespace video +{ + +template +class COpenGLCoreRenderTarget : public IRenderTarget +{ +public: + COpenGLCoreRenderTarget(TOpenGLDriver* driver) : AssignedDepth(false), AssignedStencil(false), RequestTextureUpdate(false), RequestDepthStencilUpdate(false), + BufferID(0), ColorAttachment(0), MultipleRenderTarget(0), Driver(driver) + { +#ifdef _DEBUG + setDebugName("COpenGLCoreRenderTarget"); +#endif + + DriverType = Driver->getDriverType(); + + Size = Driver->getScreenSize(); + + ColorAttachment = Driver->getFeature().ColorAttachment; + MultipleRenderTarget = Driver->getFeature().MultipleRenderTarget; + + if (ColorAttachment > 0) + Driver->irrGlGenFramebuffers(1, &BufferID); + + AssignedTexture.set_used(static_cast(ColorAttachment)); + + for (u32 i = 0; i < AssignedTexture.size(); ++i) + AssignedTexture[i] = GL_NONE; + } + + virtual ~COpenGLCoreRenderTarget() + { + if (ColorAttachment > 0 && BufferID != 0) + Driver->irrGlDeleteFramebuffers(1, &BufferID); + + for (u32 i = 0; i < Texture.size(); ++i) + { + if (Texture[i]) + Texture[i]->drop(); + } + + if (DepthStencil) + DepthStencil->drop(); + } + + virtual void setTexture(const core::array& textures, ITexture* depthStencil, const core::array& cubeSurfaces) _IRR_OVERRIDE_ + { + bool needSizeUpdate = false; + + // Set color attachments. + if ((Texture != textures) || (CubeSurfaces != cubeSurfaces)) + { + needSizeUpdate = true; + + core::array prevTextures(Texture); + + if (textures.size() > static_cast(ColorAttachment)) + { + core::stringc message = "This GPU supports up to "; + message += static_cast(ColorAttachment); + message += " textures per render target."; + + os::Printer::log(message.c_str(), ELL_WARNING); + } + + Texture.set_used(core::min_(textures.size(), static_cast(ColorAttachment))); + + for (u32 i = 0; i < Texture.size(); ++i) + { + TOpenGLTexture* currentTexture = (textures[i] && textures[i]->getDriverType() == DriverType) ? static_cast(textures[i]) : 0; + + GLuint textureID = 0; + + if (currentTexture) + { + textureID = currentTexture->getOpenGLTextureName(); + } + + if (textureID != 0) + { + Texture[i] = textures[i]; + Texture[i]->grab(); + } + else + { + Texture[i] = 0; + } + } + + for (u32 i = 0; i < prevTextures.size(); ++i) + { + if (prevTextures[i]) + prevTextures[i]->drop(); + } + + RequestTextureUpdate = true; + } + + if (CubeSurfaces != cubeSurfaces) + { + CubeSurfaces = cubeSurfaces; + RequestTextureUpdate = true; + } + + // Set depth and stencil attachments. + if (DepthStencil != depthStencil) + { + if (DepthStencil) + { + DepthStencil->drop(); + DepthStencil = 0; + } + + needSizeUpdate = true; + TOpenGLTexture* currentTexture = (depthStencil && depthStencil->getDriverType() == DriverType) ? static_cast(depthStencil) : 0; + + if (currentTexture) + { + if (currentTexture->getType() == ETT_2D) + { + GLuint textureID = currentTexture->getOpenGLTextureName(); + + const ECOLOR_FORMAT textureFormat = (textureID != 0) ? depthStencil->getColorFormat() : ECF_UNKNOWN; + if (IImage::isDepthFormat(textureFormat)) + { + DepthStencil = depthStencil; + DepthStencil->grab(); + } + else + { + os::Printer::log("Ignoring depth/stencil texture without depth color format.", ELL_WARNING); + } + } + else + { + os::Printer::log("This driver doesn't support depth/stencil to cubemaps.", ELL_WARNING); + } + } + + RequestDepthStencilUpdate = true; + } + + if (needSizeUpdate) + { + // Set size required for a viewport. + + ITexture* firstTexture = getTexture(); + + if (firstTexture) + Size = firstTexture->getSize(); + else + { + if (DepthStencil) + Size = DepthStencil->getSize(); + else + Size = Driver->getScreenSize(); + } + } + } + + void update() + { + if (RequestTextureUpdate || RequestDepthStencilUpdate) + { + // Set color attachments. + + if (RequestTextureUpdate) + { + // Set new color textures. + + const u32 textureSize = core::min_(Texture.size(), AssignedTexture.size()); + + for (u32 i = 0; i < textureSize; ++i) + { + TOpenGLTexture* currentTexture = static_cast(Texture[i]); + GLuint textureID = currentTexture ? currentTexture->getOpenGLTextureName() : 0; + + if (textureID != 0) + { + AssignedTexture[i] = GL_COLOR_ATTACHMENT0 + i; + GLenum textarget = currentTexture->getType() == ETT_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_POSITIVE_X + (int)CubeSurfaces[i]; + Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, AssignedTexture[i], textarget, textureID, 0); +#ifdef _DEBUG + Driver->testGLError(__LINE__); +#endif + } + else if (AssignedTexture[i] != GL_NONE) + { + AssignedTexture[i] = GL_NONE; + Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, AssignedTexture[i], GL_TEXTURE_2D, 0, 0); + + os::Printer::log("Error: Could not set render target.", ELL_ERROR); + } + } + + // Reset other render target channels. + + for (u32 i = textureSize; i < AssignedTexture.size(); ++i) + { + if (AssignedTexture[i] != GL_NONE) + { + Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, AssignedTexture[i], GL_TEXTURE_2D, 0, 0); + AssignedTexture[i] = GL_NONE; + } + } + + RequestTextureUpdate = false; + } + + // Set depth and stencil attachments. + + if (RequestDepthStencilUpdate) + { + const ECOLOR_FORMAT textureFormat = (DepthStencil) ? DepthStencil->getColorFormat() : ECF_UNKNOWN; + + if (IImage::isDepthFormat(textureFormat)) + { + GLuint textureID = static_cast(DepthStencil)->getOpenGLTextureName(); + +#ifdef _IRR_EMSCRIPTEN_PLATFORM_ // The WEBGL_depth_texture extension does not allow attaching stencil+depth separate. + if (textureFormat == ECF_D24S8) + { + GLenum attachment = 0x821A; // GL_DEPTH_STENCIL_ATTACHMENT + Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, textureID, 0); + AssignedStencil = true; + } + else + { + Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, textureID, 0); + AssignedStencil = false; + } +#else + Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, textureID, 0); + + if (textureFormat == ECF_D24S8) + { + Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, textureID, 0); + + AssignedStencil = true; + } + else + { + if (AssignedStencil) + Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); + + AssignedStencil = false; + } +#endif + AssignedDepth = true; + } + else + { + if (AssignedDepth) + Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0); + + if (AssignedStencil) + Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); + + AssignedDepth = false; + AssignedStencil = false; + } + + RequestDepthStencilUpdate = false; + } + + // Configure drawing operation. + + if (ColorAttachment > 0 && BufferID != 0) + { + const u32 textureSize = Texture.size(); + + if (textureSize == 0) + Driver->irrGlDrawBuffer(GL_NONE); + else if (textureSize == 1 || MultipleRenderTarget == 0) + Driver->irrGlDrawBuffer(GL_COLOR_ATTACHMENT0); + else + { + const u32 bufferCount = core::min_(MultipleRenderTarget, core::min_(textureSize, AssignedTexture.size())); + + Driver->irrGlDrawBuffers(bufferCount, AssignedTexture.pointer()); + } + +#ifdef _DEBUG + Driver->testGLError(__LINE__); +#endif + + } + +#ifdef _DEBUG + checkFBO(Driver); +#endif + } + } + + GLuint getBufferID() const + { + return BufferID; + } + + const core::dimension2d& getSize() const + { + return Size; + } + + ITexture* getTexture() const + { + for (u32 i = 0; i < Texture.size(); ++i) + { + if (Texture[i]) + return Texture[i]; + } + + return 0; + } + +protected: + bool checkFBO(TOpenGLDriver* driver) + { + if (ColorAttachment == 0) + return true; + + GLenum status = driver->irrGlCheckFramebufferStatus(GL_FRAMEBUFFER); + + switch (status) + { + case GL_FRAMEBUFFER_COMPLETE: + return true; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: + os::Printer::log("FBO has invalid read buffer", ELL_ERROR); + break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: + os::Printer::log("FBO has invalid draw buffer", ELL_ERROR); + break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + os::Printer::log("FBO has one or several incomplete image attachments", ELL_ERROR); + break; + case GL_FRAMEBUFFER_INCOMPLETE_FORMATS: + os::Printer::log("FBO has one or several image attachments with different internal formats", ELL_ERROR); + break; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + os::Printer::log("FBO has one or several image attachments with different dimensions", ELL_ERROR); + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + os::Printer::log("FBO missing an image attachment", ELL_ERROR); + break; + case GL_FRAMEBUFFER_UNSUPPORTED: + os::Printer::log("FBO format unsupported", ELL_ERROR); + break; + default: + os::Printer::log("FBO error", ELL_ERROR); + break; + } + + return false; + } + + core::array AssignedTexture; + bool AssignedDepth; + bool AssignedStencil; + + bool RequestTextureUpdate; + bool RequestDepthStencilUpdate; + + GLuint BufferID; + + core::dimension2d Size; + + u32 ColorAttachment; + u32 MultipleRenderTarget; + + TOpenGLDriver* Driver; +}; + +} +} + +#endif +#endif diff --git a/source/Irrlicht/COpenGLCoreTexture.h b/source/Irrlicht/COpenGLCoreTexture.h new file mode 100644 index 00000000..36ec66e2 --- /dev/null +++ b/source/Irrlicht/COpenGLCoreTexture.h @@ -0,0 +1,671 @@ +// Copyright (C) 2015 Patryk Nadrowski +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OGLCORE_TEXTURE_H_INCLUDED__ +#define __C_OGLCORE_TEXTURE_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#if defined(_IRR_COMPILE_WITH_OPENGL_) || defined(_IRR_COMPILE_WITH_OGLES1_) || defined(_IRR_COMPILE_WITH_OGLES2_) + +#include "irrArray.h" +#include "SMaterialLayer.h" +#include "ITexture.h" +#include "EDriverFeatures.h" +#include "os.h" +#include "CImage.h" +#include "CColorConverter.h" + +// Check if GL version we compile with should have the glGenerateMipmap function. +#if defined(GL_VERSION_3_0) || defined(GL_ES_VERSION_2_0) + #define IRR_OPENGL_HAS_glGenerateMipmap +#endif + +namespace irr +{ +namespace video +{ + +template +class COpenGLCoreTexture : public ITexture +{ +public: + struct SStatesCache + { + SStatesCache() : WrapU(ETC_REPEAT), WrapV(ETC_REPEAT), WrapW(ETC_REPEAT), + LODBias(0), AnisotropicFilter(0), BilinearFilter(false), TrilinearFilter(false), + MipMapStatus(false), IsCached(false) + { + } + + u8 WrapU; + u8 WrapV; + u8 WrapW; + s8 LODBias; + u8 AnisotropicFilter; + bool BilinearFilter; + bool TrilinearFilter; + bool MipMapStatus; + bool IsCached; + }; + + COpenGLCoreTexture(const io::path& name, const core::array& images, E_TEXTURE_TYPE type, TOpenGLDriver* driver) : ITexture(name, type), Driver(driver), TextureType(GL_TEXTURE_2D), + TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_RGBA), PixelType(GL_UNSIGNED_BYTE), Converter(0), LockReadOnly(false), LockImage(0), LockLayer(0), + KeepImage(false), MipLevelStored(0), LegacyAutoGenerateMipMaps(false) + { + _IRR_DEBUG_BREAK_IF(images.size() == 0) + + DriverType = Driver->getDriverType(); + TextureType = TextureTypeIrrToGL(Type); + HasMipMaps = Driver->getTextureCreationFlag(ETCF_CREATE_MIP_MAPS); + KeepImage = Driver->getTextureCreationFlag(ETCF_ALLOW_MEMORY_COPY); + + getImageValues(images[0]); + + const core::array* tmpImages = &images; + + if (KeepImage || OriginalSize != Size || OriginalColorFormat != ColorFormat) + { + Images.set_used(images.size()); + + for (u32 i = 0; i < images.size(); ++i) + { + Images[i] = Driver->createImage(ColorFormat, Size); + + if (images[i]->getDimension() == Size) + images[i]->copyTo(Images[i]); + else + images[i]->copyToScaling(Images[i]); + + if ( images[i]->getMipMapsData() ) + { + if ( OriginalSize == Size && OriginalColorFormat == ColorFormat ) + { + Images[i]->setMipMapsData( images[i]->getMipMapsData(), false, true); + } + else + { + // TODO: handle at least mipmap with changing color format + os::Printer::log("COpenGLCoreTexture: Can't handle format changes for mipmap data. Mipmap data dropped", ELL_WARNING); + } + } + } + + tmpImages = &Images; + } + + glGenTextures(1, &TextureName); + + const COpenGLCoreTexture* prevTexture = Driver->getCacheHandler()->getTextureCache().get(0); + Driver->getCacheHandler()->getTextureCache().set(0, this); + + glTexParameteri(TextureType, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(TextureType, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + +#ifdef GL_GENERATE_MIPMAP_HINT + if (HasMipMaps) + { + if (Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED)) + glHint(GL_GENERATE_MIPMAP_HINT, GL_FASTEST); + else if (Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_QUALITY)) + glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST); + else + glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE); + } +#endif + +#if !defined(IRR_OPENGL_HAS_glGenerateMipmap) && defined(GL_GENERATE_MIPMAP) + if (HasMipMaps) + { + LegacyAutoGenerateMipMaps = Driver->getTextureCreationFlag(ETCF_AUTO_GENERATE_MIP_MAPS) && + Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE); + glTexParameteri(TextureType, GL_GENERATE_MIPMAP, LegacyAutoGenerateMipMaps ? GL_TRUE : GL_FALSE); + } +#endif + + for (u32 i = 0; i < (*tmpImages).size(); ++i) + uploadTexture(true, i, 0, (*tmpImages)[i]->getData()); + + if (HasMipMaps && !LegacyAutoGenerateMipMaps) + { + // Create mipmaps (either from image mipmaps or generate them) + for (u32 i = 0; i < (*tmpImages).size(); ++i) + { + void* mipmapsData = (*tmpImages)[i]->getMipMapsData(); + regenerateMipMapLevels(mipmapsData, i); + } + } + + if (!KeepImage) + { + for (u32 i = 0; i < Images.size(); ++i) + Images[i]->drop(); + + Images.clear(); + } + + + Driver->getCacheHandler()->getTextureCache().set(0, prevTexture); + + Driver->testGLError(__LINE__); + } + + COpenGLCoreTexture(const io::path& name, const core::dimension2d& size, E_TEXTURE_TYPE type, ECOLOR_FORMAT format, TOpenGLDriver* driver) + : ITexture(name, type), + Driver(driver), TextureType(GL_TEXTURE_2D), + TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_RGBA), PixelType(GL_UNSIGNED_BYTE), Converter(0), LockReadOnly(false), LockImage(0), LockLayer(0), KeepImage(false), + MipLevelStored(0), LegacyAutoGenerateMipMaps(false) + { + DriverType = Driver->getDriverType(); + TextureType = TextureTypeIrrToGL(Type); + HasMipMaps = false; + IsRenderTarget = true; + + OriginalColorFormat = format; + + if (ECF_UNKNOWN == OriginalColorFormat) + ColorFormat = getBestColorFormat(Driver->getColorFormat()); + else + ColorFormat = OriginalColorFormat; + + OriginalSize = size; + Size = OriginalSize; + + Pitch = Size.Width * IImage::getBitsPerPixelFromFormat(ColorFormat) / 8; + + if ( !Driver->getColorFormatParameters(ColorFormat, InternalFormat, PixelFormat, PixelType, &Converter) ) + { + os::Printer::log("COpenGLCoreTexture: Color format is not supported", ColorFormatNames[ColorFormat < ECF_UNKNOWN?ColorFormat:ECF_UNKNOWN], ELL_ERROR); + } + + glGenTextures(1, &TextureName); + + const COpenGLCoreTexture* prevTexture = Driver->getCacheHandler()->getTextureCache().get(0); + Driver->getCacheHandler()->getTextureCache().set(0, this); + + + glTexParameteri(TextureType, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(TextureType, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(TextureType, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(TextureType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + +#if defined(GL_VERSION_1_2) + glTexParameteri(TextureType, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); +#endif + + StatesCache.WrapU = ETC_CLAMP_TO_EDGE; + StatesCache.WrapV = ETC_CLAMP_TO_EDGE; + StatesCache.WrapW = ETC_CLAMP_TO_EDGE; + + switch (Type) + { + case ETT_2D: + glTexImage2D(GL_TEXTURE_2D, 0, InternalFormat, Size.Width, Size.Height, 0, PixelFormat, PixelType, 0); + break; + case ETT_CUBEMAP: + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, InternalFormat, Size.Width, Size.Height, 0, PixelFormat, PixelType, 0); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, InternalFormat, Size.Width, Size.Height, 0, PixelFormat, PixelType, 0); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, InternalFormat, Size.Width, Size.Height, 0, PixelFormat, PixelType, 0); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, InternalFormat, Size.Width, Size.Height, 0, PixelFormat, PixelType, 0); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, InternalFormat, Size.Width, Size.Height, 0, PixelFormat, PixelType, 0); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, InternalFormat, Size.Width, Size.Height, 0, PixelFormat, PixelType, 0); + break; + } + + Driver->getCacheHandler()->getTextureCache().set(0, prevTexture); + if ( Driver->testGLError(__LINE__) ) + { + char msg[256]; + snprintf_irr(msg, 256, "COpenGLCoreTexture: InternalFormat:0x%04x PixelFormat:0x%04x", (int)InternalFormat, (int)PixelFormat); + os::Printer::log(msg, ELL_ERROR); + } + } + + virtual ~COpenGLCoreTexture() + { + if (TextureName) + glDeleteTextures(1, &TextureName); + + if (LockImage) + LockImage->drop(); + + for (u32 i = 0; i < Images.size(); ++i) + Images[i]->drop(); + } + + virtual void* lock(E_TEXTURE_LOCK_MODE mode = ETLM_READ_WRITE, u32 mipmapLevel=0, u32 layer = 0, E_TEXTURE_LOCK_FLAGS lockFlags = ETLF_FLIP_Y_UP_RTT) _IRR_OVERRIDE_ + { + if (LockImage) + return getLockImageData(MipLevelStored); + + if (IImage::isCompressedFormat(ColorFormat)) + return 0; + + LockReadOnly |= (mode == ETLM_READ_ONLY); + LockLayer = layer; + MipLevelStored = mipmapLevel; + + if (KeepImage) + { + _IRR_DEBUG_BREAK_IF(LockLayer > Images.size()) + + if ( mipmapLevel == 0 || (Images[LockLayer] && Images[LockLayer]->getMipMapsData(mipmapLevel)) ) + { + LockImage = Images[LockLayer]; + LockImage->grab(); + } + } + + if ( !LockImage ) + { + core::dimension2d lockImageSize( IImage::getMipMapsSize(Size, MipLevelStored)); + + // note: we save mipmap data also in the image because IImage doesn't allow saving single mipmap levels to the mipmap data + LockImage = Driver->createImage(ColorFormat, lockImageSize); + + if (LockImage && mode != ETLM_WRITE_ONLY) + { + bool passed = true; + +#ifdef IRR_COMPILE_GL_COMMON + IImage* tmpImage = LockImage; // not sure yet if the size required by glGetTexImage is always correct, if not we might have to allocate a different tmpImage and convert colors later on. + + Driver->getCacheHandler()->getTextureCache().set(0, this); + Driver->testGLError(__LINE__); + + GLenum tmpTextureType = TextureType; + + if (tmpTextureType == GL_TEXTURE_CUBE_MAP) + { + _IRR_DEBUG_BREAK_IF(layer > 5) + + tmpTextureType = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer; + } + + glGetTexImage(tmpTextureType, MipLevelStored, PixelFormat, PixelType, tmpImage->getData()); + Driver->testGLError(__LINE__); + + if (IsRenderTarget && lockFlags == ETLF_FLIP_Y_UP_RTT) + { + const s32 pitch = tmpImage->getPitch(); + + u8* srcA = static_cast(tmpImage->getData()); + u8* srcB = srcA + (tmpImage->getDimension().Height - 1) * pitch; + + u8* tmpBuffer = new u8[pitch]; + + for (u32 i = 0; i < tmpImage->getDimension().Height; i += 2) + { + memcpy(tmpBuffer, srcA, pitch); + memcpy(srcA, srcB, pitch); + memcpy(srcB, tmpBuffer, pitch); + srcA += pitch; + srcB -= pitch; + } + + delete[] tmpBuffer; + } +#elif (defined(IRR_COMPILE_GLES2_COMMON) || defined(IRR_COMPILE_GLES_COMMON)) +// TODO: on ES2 we can likely also work with glCopyTexImage2D instead of rendering which should be faster. + COpenGLCoreTexture* tmpTexture = new COpenGLCoreTexture("OGL_CORE_LOCK_TEXTURE", Size, ETT_2D, ColorFormat, Driver); + + GLuint tmpFBO = 0; + Driver->irrGlGenFramebuffers(1, &tmpFBO); + + GLint prevViewportX = 0; + GLint prevViewportY = 0; + GLsizei prevViewportWidth = 0; + GLsizei prevViewportHeight = 0; + Driver->getCacheHandler()->getViewport(prevViewportX, prevViewportY, prevViewportWidth, prevViewportHeight); + Driver->getCacheHandler()->setViewport(0, 0, Size.Width, Size.Height); + + GLuint prevFBO = 0; + Driver->getCacheHandler()->getFBO(prevFBO); + Driver->getCacheHandler()->setFBO(tmpFBO); + + Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmpTexture->getOpenGLTextureName(), 0); + + glClear(GL_COLOR_BUFFER_BIT); + + Driver->draw2DImage(this, layer, true); + + IImage* tmpImage = Driver->createImage(ECF_A8R8G8B8, Size); + glReadPixels(0, 0, Size.Width, Size.Height, GL_RGBA, GL_UNSIGNED_BYTE, tmpImage->getData()); + + Driver->getCacheHandler()->setFBO(prevFBO); + Driver->getCacheHandler()->setViewport(prevViewportX, prevViewportY, prevViewportWidth, prevViewportHeight); + + Driver->irrGlDeleteFramebuffers(1, &tmpFBO); + delete tmpTexture; + + void* src = tmpImage->getData(); + void* dest = LockImage->getData(); + + switch (ColorFormat) + { + case ECF_A1R5G5B5: + CColorConverter::convert_A8R8G8B8toA1B5G5R5(src, tmpImage->getDimension().getArea(), dest); + break; + case ECF_R5G6B5: + CColorConverter::convert_A8R8G8B8toR5G6B5(src, tmpImage->getDimension().getArea(), dest); + break; + case ECF_R8G8B8: + CColorConverter::convert_A8R8G8B8toB8G8R8(src, tmpImage->getDimension().getArea(), dest); + break; + case ECF_A8R8G8B8: + CColorConverter::convert_A8R8G8B8toA8B8G8R8(src, tmpImage->getDimension().getArea(), dest); + break; + default: + passed = false; + break; + } + tmpImage->drop(); +#endif + + if (!passed) + { + LockImage->drop(); + LockImage = 0; + } + } + + Driver->testGLError(__LINE__); + } + + return (LockImage) ? getLockImageData(MipLevelStored) : 0; + } + + virtual void unlock() _IRR_OVERRIDE_ + { + if (!LockImage) + return; + + if (!LockReadOnly) + { + const COpenGLCoreTexture* prevTexture = Driver->getCacheHandler()->getTextureCache().get(0); + Driver->getCacheHandler()->getTextureCache().set(0, this); + + uploadTexture(false, LockLayer, MipLevelStored, getLockImageData(MipLevelStored)); + + Driver->getCacheHandler()->getTextureCache().set(0, prevTexture); + } + + LockImage->drop(); + + LockReadOnly = false; + LockImage = 0; + LockLayer = 0; + } + + virtual void regenerateMipMapLevels(void* data = 0, u32 layer = 0) _IRR_OVERRIDE_ + { + if (!HasMipMaps || LegacyAutoGenerateMipMaps || (Size.Width <= 1 && Size.Height <= 1)) + return; + + const COpenGLCoreTexture* prevTexture = Driver->getCacheHandler()->getTextureCache().get(0); + Driver->getCacheHandler()->getTextureCache().set(0, this); + + if (data) + { + u32 width = Size.Width; + u32 height = Size.Height; + u8* tmpData = static_cast(data); + u32 dataSize = 0; + u32 level = 0; + + do + { + if (width > 1) + width >>= 1; + + if (height > 1) + height >>= 1; + + dataSize = IImage::getDataSizeFromFormat(ColorFormat, width, height); + ++level; + + uploadTexture(true, layer, level, tmpData); + + tmpData += dataSize; + } + while (width != 1 || height != 1); + } + else + { +#ifdef IRR_OPENGL_HAS_glGenerateMipmap + glEnable(GL_TEXTURE_2D); // Hack some ATI cards need this glEnable according to https://www.khronos.org/opengl/wiki/Common_Mistakes + Driver->irrGlGenerateMipmap(TextureType); +#endif + } + + Driver->getCacheHandler()->getTextureCache().set(0, prevTexture); + } + + GLenum getOpenGLTextureType() const + { + return TextureType; + } + + GLuint getOpenGLTextureName() const + { + return TextureName; + } + + SStatesCache& getStatesCache() const + { + return StatesCache; + } + +protected: + + void * getLockImageData(irr::u32 miplevel) const + { + if ( KeepImage && MipLevelStored > 0 + && LockImage->getMipMapsData(MipLevelStored) ) + { + return LockImage->getMipMapsData(MipLevelStored); + } + return LockImage->getData(); + } + + ECOLOR_FORMAT getBestColorFormat(ECOLOR_FORMAT format) + { + // We only try for to adapt "simple" formats + ECOLOR_FORMAT destFormat = (format <= ECF_A8R8G8B8) ? ECF_A8R8G8B8 : format; + + switch (format) + { + case ECF_A1R5G5B5: + if (!Driver->getTextureCreationFlag(ETCF_ALWAYS_32_BIT)) + destFormat = ECF_A1R5G5B5; + break; + case ECF_R5G6B5: + if (!Driver->getTextureCreationFlag(ETCF_ALWAYS_32_BIT)) + destFormat = ECF_R5G6B5; + break; + case ECF_A8R8G8B8: + if (Driver->getTextureCreationFlag(ETCF_ALWAYS_16_BIT) || + Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED)) + destFormat = ECF_A1R5G5B5; + break; + case ECF_R8G8B8: + // Note: Using ECF_A8R8G8B8 even when ETCF_ALWAYS_32_BIT is not set as 24 bit textures fail with too many cards + if (Driver->getTextureCreationFlag(ETCF_ALWAYS_16_BIT) || Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED)) + destFormat = ECF_A1R5G5B5; + default: + break; + } + + if (Driver->getTextureCreationFlag(ETCF_NO_ALPHA_CHANNEL)) + { + switch (destFormat) + { + case ECF_A1R5G5B5: + destFormat = ECF_R5G6B5; + break; + case ECF_A8R8G8B8: + destFormat = ECF_R8G8B8; + break; + default: + break; + } + } + + return destFormat; + } + + void getImageValues(const IImage* image) + { + OriginalColorFormat = image->getColorFormat(); + ColorFormat = getBestColorFormat(OriginalColorFormat); + + if ( !Driver->getColorFormatParameters(ColorFormat, InternalFormat, PixelFormat, PixelType, &Converter) ) + { + os::Printer::log("getImageValues: Color format is not supported", ColorFormatNames[ColorFormat < ECF_UNKNOWN?ColorFormat:ECF_UNKNOWN], ELL_ERROR); + // not quitting as it will use some alternative internal format + } + + if (IImage::isCompressedFormat(image->getColorFormat())) + { + KeepImage = false; + } + + OriginalSize = image->getDimension(); + Size = OriginalSize; + + if (Size.Width == 0 || Size.Height == 0) + { + os::Printer::log("Invalid size of image for texture.", ELL_ERROR); + return; + } + + const f32 ratio = (f32)Size.Width / (f32)Size.Height; + + if ((Size.Width > Driver->MaxTextureSize) && (ratio >= 1.f)) + { + Size.Width = Driver->MaxTextureSize; + Size.Height = (u32)(Driver->MaxTextureSize / ratio); + } + else if (Size.Height > Driver->MaxTextureSize) + { + Size.Height = Driver->MaxTextureSize; + Size.Width = (u32)(Driver->MaxTextureSize * ratio); + } + + bool needSquare = (!Driver->queryFeature(EVDF_TEXTURE_NSQUARE) || Type == ETT_CUBEMAP); + + Size = Size.getOptimalSize(!Driver->queryFeature(EVDF_TEXTURE_NPOT), needSquare, true, Driver->MaxTextureSize); + + Pitch = Size.Width * IImage::getBitsPerPixelFromFormat(ColorFormat) / 8; + } + + void uploadTexture(bool initTexture, u32 layer, u32 level, void* data) + { + if (!data) + return; + + u32 width = Size.Width >> level; + u32 height = Size.Height >> level; + + GLenum tmpTextureType = TextureType; + + if (tmpTextureType == GL_TEXTURE_CUBE_MAP) + { + _IRR_DEBUG_BREAK_IF(layer > 5) + + tmpTextureType = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer; + } + + if (!IImage::isCompressedFormat(ColorFormat)) + { + CImage* tmpImage = 0; + void* tmpData = data; + + if (Converter) + { + const core::dimension2d tmpImageSize(width, height); + + tmpImage = new CImage(ColorFormat, tmpImageSize); + tmpData = tmpImage->getData(); + + Converter(data, tmpImageSize.getArea(), tmpData); + } + + switch (TextureType) + { + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP: + if (initTexture) + glTexImage2D(tmpTextureType, level, InternalFormat, width, height, 0, PixelFormat, PixelType, tmpData); + else + glTexSubImage2D(tmpTextureType, level, 0, 0, width, height, PixelFormat, PixelType, tmpData); + Driver->testGLError(__LINE__); + break; + default: + break; + } + + delete tmpImage; + } + else + { + u32 dataSize = IImage::getDataSizeFromFormat(ColorFormat, width, height); + + switch (TextureType) + { + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP: + if (initTexture) + Driver->irrGlCompressedTexImage2D(tmpTextureType, level, InternalFormat, width, height, 0, dataSize, data); + else + Driver->irrGlCompressedTexSubImage2D(tmpTextureType, level, 0, 0, width, height, PixelFormat, dataSize, data); + Driver->testGLError(__LINE__); + break; + default: + break; + } + } + } + + GLenum TextureTypeIrrToGL(E_TEXTURE_TYPE type) const + { + switch ( type) + { + case ETT_2D: + return GL_TEXTURE_2D; + case ETT_CUBEMAP: + return GL_TEXTURE_CUBE_MAP; + } + + os::Printer::log("COpenGLCoreTexture::TextureTypeIrrToGL unknown texture type", ELL_WARNING); + return GL_TEXTURE_2D; + } + + TOpenGLDriver* Driver; + + GLenum TextureType; + GLuint TextureName; + GLint InternalFormat; + GLenum PixelFormat; + GLenum PixelType; + void (*Converter)(const void*, s32, void*); + + bool LockReadOnly; + IImage* LockImage; + u32 LockLayer; + + bool KeepImage; + core::array Images; + + u8 MipLevelStored; + bool LegacyAutoGenerateMipMaps; + + mutable SStatesCache StatesCache; +}; + +} +} + +#endif +#endif diff --git a/source/Irrlicht/COpenGLDriver.cpp b/source/Irrlicht/COpenGLDriver.cpp new file mode 100644 index 00000000..1eb81686 --- /dev/null +++ b/source/Irrlicht/COpenGLDriver.cpp @@ -0,0 +1,4476 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "COpenGLDriver.h" +#include "CNullDriver.h" +#include "IContextManager.h" + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#include "os.h" + +#include "COpenGLCacheHandler.h" +#include "COpenGLMaterialRenderer.h" +#include "COpenGLShaderMaterialRenderer.h" +#include "COpenGLSLMaterialRenderer.h" +#include "COpenGLNormalMapRenderer.h" +#include "COpenGLParallaxMapRenderer.h" + +#include "COpenGLCoreTexture.h" +#include "COpenGLCoreRenderTarget.h" + +#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ +#include +#endif + +namespace irr +{ +namespace video +{ + +// Statics variables +const u16 COpenGLDriver::Quad2DIndices[4] = { 0, 1, 2, 3 }; + +#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) || defined(_IRR_COMPILE_WITH_X11_DEVICE_) || defined(_IRR_COMPILE_WITH_OSX_DEVICE_) +COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager) + : CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), CacheHandler(0), CurrentRenderMode(ERM_NONE), ResetRenderStates(true), + Transformation3DChanged(true), AntiAlias(params.AntiAlias), ColorFormat(ECF_R8G8B8), FixedPipelineState(EOFPS_ENABLE), Params(params), + ContextManager(contextManager), +#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) + DeviceType(EIDT_WIN32) +#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_) + DeviceType(EIDT_X11) +#else + DeviceType(EIDT_OSX) +#endif +{ +#ifdef _DEBUG + setDebugName("COpenGLDriver"); +#endif +} +#endif + +#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ +COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, CIrrDeviceSDL* device) + : CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), CacheHandler(0), + CurrentRenderMode(ERM_NONE), ResetRenderStates(true), Transformation3DChanged(true), + AntiAlias(params.AntiAlias), ColorFormat(ECF_R8G8B8), FixedPipelineState(EOFPS_ENABLE), + Params(params), SDLDevice(device), ContextManager(0), DeviceType(EIDT_SDL) +{ +#ifdef _DEBUG + setDebugName("COpenGLDriver"); +#endif + + genericDriverInit(); +} + +#endif + +bool COpenGLDriver::initDriver() +{ + ContextManager->generateSurface(); + ContextManager->generateContext(); + ExposedData = ContextManager->getContext(); + ContextManager->activateContext(ExposedData, false); + + genericDriverInit(); + +#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) || defined(_IRR_COMPILE_WITH_X11_DEVICE_) + extGlSwapInterval(Params.Vsync ? 1 : 0); +#endif + + return true; +} + +//! destructor +COpenGLDriver::~COpenGLDriver() +{ + RequestedLights.clear(); + + deleteMaterialRenders(); + + CacheHandler->getTextureCache().clear(); + // I get a blue screen on my laptop, when I do not delete the + // textures manually before releasing the dc. Oh how I love this. + removeAllRenderTargets(); + deleteAllTextures(); + removeAllOcclusionQueries(); + removeAllHardwareBuffers(); + + delete CacheHandler; + + if (ContextManager) + { + ContextManager->destroyContext(); + ContextManager->destroySurface(); + ContextManager->terminate(); + ContextManager->drop(); + } +} + +// ----------------------------------------------------------------------- +// METHODS +// ----------------------------------------------------------------------- + +bool COpenGLDriver::genericDriverInit() +{ + if (ContextManager) + ContextManager->grab(); + + Name=L"OpenGL "; + Name.append(glGetString(GL_VERSION)); + s32 pos=Name.findNext(L' ', 7); + if (pos != -1) + Name=Name.subString(0, pos); + printVersion(); + + // print renderer information + const GLubyte* renderer = glGetString(GL_RENDERER); + const GLubyte* vendor = glGetString(GL_VENDOR); + if (renderer && vendor) + { + os::Printer::log(reinterpret_cast(renderer), reinterpret_cast(vendor), ELL_INFORMATION); + VendorName = reinterpret_cast(vendor); + } + + u32 i; + + // load extensions + initExtensions(Params.Stencilbuffer); + + // reset cache handler + delete CacheHandler; + CacheHandler = new COpenGLCacheHandler(this); + + if (queryFeature(EVDF_ARB_GLSL)) + { + char buf[32]; + const u32 maj = ShaderLanguageVersion/100; + snprintf_irr(buf, 32, "%u.%u", maj, ShaderLanguageVersion-maj*100); + os::Printer::log("GLSL version", buf, ELL_INFORMATION); + } + else + os::Printer::log("GLSL not available.", ELL_INFORMATION); + DriverAttributes->setAttribute("MaxTextures", (s32)Feature.MaxTextureUnits); + DriverAttributes->setAttribute("MaxSupportedTextures", (s32)Feature.MaxTextureUnits); + DriverAttributes->setAttribute("MaxLights", MaxLights); + DriverAttributes->setAttribute("MaxAnisotropy", MaxAnisotropy); + DriverAttributes->setAttribute("MaxUserClipPlanes", MaxUserClipPlanes); + DriverAttributes->setAttribute("MaxAuxBuffers", MaxAuxBuffers); + DriverAttributes->setAttribute("MaxMultipleRenderTargets", (s32)Feature.MultipleRenderTarget); + DriverAttributes->setAttribute("MaxIndices", (s32)MaxIndices); + DriverAttributes->setAttribute("MaxTextureSize", (s32)MaxTextureSize); + DriverAttributes->setAttribute("MaxGeometryVerticesOut", (s32)MaxGeometryVerticesOut); + DriverAttributes->setAttribute("MaxTextureLODBias", MaxTextureLODBias); + DriverAttributes->setAttribute("Version", Version); + DriverAttributes->setAttribute("ShaderLanguageVersion", ShaderLanguageVersion); + DriverAttributes->setAttribute("AntiAlias", AntiAlias); + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + UserClipPlanes.reallocate(MaxUserClipPlanes); + for (i=0; i(i), core::IdentityMatrix); + + setAmbientLight(SColorf(0.0f,0.0f,0.0f,0.0f)); +#ifdef GL_EXT_separate_specular_color + if (FeatureAvailable[IRR_EXT_separate_specular_color]) + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); +#endif + glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1); + + Params.HandleSRGB &= ((FeatureAvailable[IRR_ARB_framebuffer_sRGB] || FeatureAvailable[IRR_EXT_framebuffer_sRGB]) && + FeatureAvailable[IRR_EXT_texture_sRGB]); +#if defined(GL_ARB_framebuffer_sRGB) + if (Params.HandleSRGB) + glEnable(GL_FRAMEBUFFER_SRGB); +#elif defined(GL_EXT_framebuffer_sRGB) + if (Params.HandleSRGB) + glEnable(GL_FRAMEBUFFER_SRGB_EXT); +#endif + +// This is a fast replacement for NORMALIZE_NORMALS +// if ((Version>101) || FeatureAvailable[IRR_EXT_rescale_normal]) +// glEnable(GL_RESCALE_NORMAL_EXT); + + glClearDepth(1.0); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST); + glFrontFace(GL_CW); + // adjust flat coloring scheme to DirectX version +#if defined(GL_ARB_provoking_vertex) || defined(GL_EXT_provoking_vertex) + extGlProvokingVertex(GL_FIRST_VERTEX_CONVENTION_EXT); +#endif + + // Create built-in 2D quad for 2D rendering (both quads and lines). + Quad2DVertices[0] = S3DVertex(core::vector3df(-1.0f, 1.0f, 0.0f), core::vector3df(0.0f, 0.0f, 0.0f), SColor(255,255,255,255), core::vector2df(0.0f, 1.0f)); + Quad2DVertices[1] = S3DVertex(core::vector3df(1.0f, 1.0f, 0.0f), core::vector3df(0.0f, 0.0f, 0.0f), SColor(255,255,255,255), core::vector2df(1.0f, 1.0f)); + Quad2DVertices[2] = S3DVertex(core::vector3df(1.0f, -1.0f, 0.0f), core::vector3df(0.0f, 0.0f, 0.0f), SColor(255,255,255,255), core::vector2df(1.0f, 0.0f)); + Quad2DVertices[3] = S3DVertex(core::vector3df(-1.0f, -1.0f, 0.0f), core::vector3df(0.0f, 0.0f, 0.0f), SColor(255,255,255,255), core::vector2df(0.0f, 0.0f)); + + // create material renderers + createMaterialRenderers(); + + // set the renderstates + setRenderStates3DMode(); + + // set fog mode + setFog(FogColor, FogType, FogStart, FogEnd, FogDensity, PixelFog, RangeFog); + + // create matrix for flipping textures + TextureFlipMatrix.buildTextureTransform(0.0f, core::vector2df(0,0), core::vector2df(0,1.0f), core::vector2df(1.0f,-1.0f)); + + // We need to reset once more at the beginning of the first rendering. + // This fixes problems with intermediate changes to the material during texture load. + ResetRenderStates = true; + + return true; +} + + +void COpenGLDriver::createMaterialRenderers() +{ + // create OpenGL material renderers + + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SOLID(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SOLID_2_LAYER(this)); + + // add the same renderer for all lightmap types + COpenGLMaterialRenderer_LIGHTMAP* lmr = new COpenGLMaterialRenderer_LIGHTMAP(this); + addMaterialRenderer(lmr); // for EMT_LIGHTMAP: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_ADD: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M2: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_M4: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M2: + addMaterialRenderer(lmr); // for EMT_LIGHTMAP_LIGHTING_M4: + lmr->drop(); + + // add remaining material renderer + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_DETAIL_MAP(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_SPHERE_MAP(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_REFLECTION_2_LAYER(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ADD_COLOR(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_VERTEX_ALPHA(this)); + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER(this)); + + // add normal map renderers + s32 tmp = 0; + video::IMaterialRenderer* renderer = 0; + renderer = new COpenGLNormalMapRenderer(this, tmp, EMT_SOLID); + renderer->drop(); + renderer = new COpenGLNormalMapRenderer(this, tmp, EMT_TRANSPARENT_ADD_COLOR); + renderer->drop(); + renderer = new COpenGLNormalMapRenderer(this, tmp, EMT_TRANSPARENT_VERTEX_ALPHA); + renderer->drop(); + + // add parallax map renderers + renderer = new COpenGLParallaxMapRenderer(this, tmp, EMT_SOLID); + renderer->drop(); + renderer = new COpenGLParallaxMapRenderer(this, tmp, EMT_TRANSPARENT_ADD_COLOR); + renderer->drop(); + renderer = new COpenGLParallaxMapRenderer(this, tmp, EMT_TRANSPARENT_VERTEX_ALPHA); + renderer->drop(); + + // add basic 1 texture blending + addAndDropMaterialRenderer(new COpenGLMaterialRenderer_ONETEXTURE_BLEND(this)); +} + +bool COpenGLDriver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil, const SExposedVideoData& videoData, core::rect* sourceRect) +{ + CNullDriver::beginScene(clearFlag, clearColor, clearDepth, clearStencil, videoData, sourceRect); + + if (ContextManager) + ContextManager->activateContext(videoData, true); + +#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_) + if ( DeviceType == EIDT_SDL ) + glFrontFace(GL_CW); +#endif + + clearBuffers(clearFlag, clearColor, clearDepth, clearStencil); + + return true; +} + +bool COpenGLDriver::endScene() +{ + CNullDriver::endScene(); + + glFlush(); + + bool status = false; + + if (ContextManager) + status = ContextManager->swapBuffers(); + +#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ + if ( DeviceType == EIDT_SDL ) + { + SDL_GL_SwapBuffers(); + status = true; + } +#endif + + // todo: console device present + + return status; +} + + +//! Returns the transformation set by setTransform +const core::matrix4& COpenGLDriver::getTransform(E_TRANSFORMATION_STATE state) const +{ + return Matrices[state]; +} + + +//! sets transformation +void COpenGLDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) +{ + Matrices[state] = mat; + Transformation3DChanged = true; + + switch (state) + { + case ETS_VIEW: + case ETS_WORLD: + { + // OpenGL only has a model matrix, view and world is not existent. so lets fake these two. + CacheHandler->setMatrixMode(GL_MODELVIEW); + + // first load the viewing transformation for user clip planes + glLoadMatrixf((Matrices[ETS_VIEW]).pointer()); + + // we have to update the clip planes to the latest view matrix + for (u32 i=0; isetMatrixMode(GL_PROJECTION); + glLoadMatrixf(mat.pointer()); + } + break; + default: + break; + } +} + + +bool COpenGLDriver::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) +{ + if (!HWBuffer) + return false; + + if (!FeatureAvailable[IRR_ARB_vertex_buffer_object]) + return false; + +#if defined(GL_ARB_vertex_buffer_object) + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + const void* vertices=mb->getVertices(); + const u32 vertexCount=mb->getVertexCount(); + const E_VERTEX_TYPE vType=mb->getVertexType(); + const u32 vertexSize = getVertexPitchFromType(vType); + + const c8* vbuf = static_cast(vertices); + core::array buffer; + if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) + { + //buffer vertex data, and convert colors... + buffer.set_used(vertexSize * vertexCount); + memcpy(buffer.pointer(), vertices, vertexSize * vertexCount); + vbuf = buffer.const_pointer(); + + // in order to convert the colors into opengl format (RGBA) + switch (vType) + { + case EVT_STANDARD: + { + S3DVertex* pb = reinterpret_cast(buffer.pointer()); + const S3DVertex* po = static_cast(vertices); + for (u32 i=0; i(buffer.pointer()); + const S3DVertex2TCoords* po = static_cast(vertices); + for (u32 i=0; i(buffer.pointer()); + const S3DVertexTangents* po = static_cast(vertices); + for (u32 i=0; ivbo_verticesID) + { + extGlGenBuffers(1, &HWBuffer->vbo_verticesID); + if (!HWBuffer->vbo_verticesID) + return false; + newBuffer=true; + } + else if (HWBuffer->vbo_verticesSize < vertexCount*vertexSize) + { + newBuffer=true; + } + + extGlBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID); + + // copy data to graphics card + if (!newBuffer) + extGlBufferSubData(GL_ARRAY_BUFFER, 0, vertexCount * vertexSize, vbuf); + else + { + HWBuffer->vbo_verticesSize = vertexCount*vertexSize; + + if (HWBuffer->Mapped_Vertex==scene::EHM_STATIC) + extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, vbuf, GL_STATIC_DRAW); + else if (HWBuffer->Mapped_Vertex==scene::EHM_DYNAMIC) + extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, vbuf, GL_DYNAMIC_DRAW); + else //scene::EHM_STREAM + extGlBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize, vbuf, GL_STREAM_DRAW); + } + + extGlBindBuffer(GL_ARRAY_BUFFER, 0); + + return (!testGLError(__LINE__)); +#else + return false; +#endif +} + + +bool COpenGLDriver::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) +{ + if (!HWBuffer) + return false; + + if (!FeatureAvailable[IRR_ARB_vertex_buffer_object]) + return false; + +#if defined(GL_ARB_vertex_buffer_object) + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + + const void* indices=mb->getIndices(); + u32 indexCount= mb->getIndexCount(); + + GLenum indexSize; + switch (mb->getIndexType()) + { + case EIT_16BIT: + { + indexSize=sizeof(u16); + break; + } + case EIT_32BIT: + { + indexSize=sizeof(u32); + break; + } + default: + { + return false; + } + } + + + //get or create buffer + bool newBuffer=false; + if (!HWBuffer->vbo_indicesID) + { + extGlGenBuffers(1, &HWBuffer->vbo_indicesID); + if (!HWBuffer->vbo_indicesID) + return false; + newBuffer=true; + } + else if (HWBuffer->vbo_indicesSize < indexCount*indexSize) + { + newBuffer=true; + } + + extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID); + + // copy data to graphics card + if (!newBuffer) + extGlBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexCount * indexSize, indices); + else + { + HWBuffer->vbo_indicesSize = indexCount*indexSize; + + if (HWBuffer->Mapped_Index==scene::EHM_STATIC) + extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STATIC_DRAW); + else if (HWBuffer->Mapped_Index==scene::EHM_DYNAMIC) + extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_DYNAMIC_DRAW); + else //scene::EHM_STREAM + extGlBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STREAM_DRAW); + } + + extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + return (!testGLError(__LINE__)); +#else + return false; +#endif +} + + +//! updates hardware buffer if needed +bool COpenGLDriver::updateHardwareBuffer(SHWBufferLink *HWBuffer) +{ + if (!HWBuffer) + return false; + + if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER) + { + if (HWBuffer->ChangedID_Vertex != HWBuffer->MeshBuffer->getChangedID_Vertex() + || !((SHWBufferLink_opengl*)HWBuffer)->vbo_verticesID) + { + + HWBuffer->ChangedID_Vertex = HWBuffer->MeshBuffer->getChangedID_Vertex(); + + if (!updateVertexHardwareBuffer((SHWBufferLink_opengl*)HWBuffer)) + return false; + } + } + + if (HWBuffer->Mapped_Index!=scene::EHM_NEVER) + { + if (HWBuffer->ChangedID_Index != HWBuffer->MeshBuffer->getChangedID_Index() + || !((SHWBufferLink_opengl*)HWBuffer)->vbo_indicesID) + { + + HWBuffer->ChangedID_Index = HWBuffer->MeshBuffer->getChangedID_Index(); + + if (!updateIndexHardwareBuffer((SHWBufferLink_opengl*)HWBuffer)) + return false; + } + } + + return true; +} + + +//! Create hardware buffer from meshbuffer +COpenGLDriver::SHWBufferLink *COpenGLDriver::createHardwareBuffer(const scene::IMeshBuffer* mb) +{ +#if defined(GL_ARB_vertex_buffer_object) + if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER)) + return 0; + + SHWBufferLink_opengl *HWBuffer=new SHWBufferLink_opengl(mb); + + //add to map + HWBufferMap.insert(HWBuffer->MeshBuffer, HWBuffer); + + HWBuffer->ChangedID_Vertex=HWBuffer->MeshBuffer->getChangedID_Vertex(); + HWBuffer->ChangedID_Index=HWBuffer->MeshBuffer->getChangedID_Index(); + HWBuffer->Mapped_Vertex=mb->getHardwareMappingHint_Vertex(); + HWBuffer->Mapped_Index=mb->getHardwareMappingHint_Index(); + HWBuffer->LastUsed=0; + HWBuffer->vbo_verticesID=0; + HWBuffer->vbo_indicesID=0; + HWBuffer->vbo_verticesSize=0; + HWBuffer->vbo_indicesSize=0; + + if (!updateHardwareBuffer(HWBuffer)) + { + deleteHardwareBuffer(HWBuffer); + return 0; + } + + return HWBuffer; +#else + return 0; +#endif +} + + +void COpenGLDriver::deleteHardwareBuffer(SHWBufferLink *_HWBuffer) +{ + if (!_HWBuffer) + return; + +#if defined(GL_ARB_vertex_buffer_object) + SHWBufferLink_opengl *HWBuffer=(SHWBufferLink_opengl*)_HWBuffer; + if (HWBuffer->vbo_verticesID) + { + extGlDeleteBuffers(1, &HWBuffer->vbo_verticesID); + HWBuffer->vbo_verticesID=0; + } + if (HWBuffer->vbo_indicesID) + { + extGlDeleteBuffers(1, &HWBuffer->vbo_indicesID); + HWBuffer->vbo_indicesID=0; + } +#endif + + CNullDriver::deleteHardwareBuffer(_HWBuffer); +} + + +//! Draw hardware buffer +void COpenGLDriver::drawHardwareBuffer(SHWBufferLink *_HWBuffer) +{ + if (!_HWBuffer) + return; + + 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(); + + if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER) + { + extGlBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID); + vertices=0; + } + + if (HWBuffer->Mapped_Index!=scene::EHM_NEVER) + { + extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID); + indexList=0; + } + + drawVertexPrimitiveList(vertices, mb->getVertexCount(), indexList, mb->getPrimitiveCount(), mb->getVertexType(), mb->getPrimitiveType(), 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 +} + + +//! Create occlusion query. +/** Use node for identification and mesh for occlusion test. */ +void COpenGLDriver::addOcclusionQuery(scene::ISceneNode* node, + const scene::IMesh* mesh) +{ + if (!queryFeature(EVDF_OCCLUSION_QUERY)) + return; + + CNullDriver::addOcclusionQuery(node, mesh); + const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); + if ((index != -1) && (OcclusionQueries[index].UID == 0)) + extGlGenQueries(1, reinterpret_cast(&OcclusionQueries[index].UID)); +} + + +//! Remove occlusion query. +void COpenGLDriver::removeOcclusionQuery(scene::ISceneNode* node) +{ + const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); + if (index != -1) + { + if (OcclusionQueries[index].UID != 0) + extGlDeleteQueries(1, reinterpret_cast(&OcclusionQueries[index].UID)); + CNullDriver::removeOcclusionQuery(node); + } +} + + +//! Run occlusion query. Draws mesh stored in query. +/** If the mesh shall not be rendered visible, use +overrideMaterial to disable the color and depth buffer. */ +void COpenGLDriver::runOcclusionQuery(scene::ISceneNode* node, bool visible) +{ + if (!node) + return; + + const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); + if (index != -1) + { + if (OcclusionQueries[index].UID) + extGlBeginQuery( +#ifdef GL_ARB_occlusion_query + GL_SAMPLES_PASSED_ARB, +#else + 0, +#endif + OcclusionQueries[index].UID); + CNullDriver::runOcclusionQuery(node,visible); + if (OcclusionQueries[index].UID) + extGlEndQuery( +#ifdef GL_ARB_occlusion_query + GL_SAMPLES_PASSED_ARB); +#else + 0); +#endif + testGLError(__LINE__); + } +} + + +//! Update occlusion query. Retrieves results from GPU. +/** If the query shall not block, set the flag to false. +Update might not occur in this case, though */ +void COpenGLDriver::updateOcclusionQuery(scene::ISceneNode* node, bool block) +{ + const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); + if (index != -1) + { + // not yet started + if (OcclusionQueries[index].Run==u32(~0)) + return; + GLint available = block?GL_TRUE:GL_FALSE; + if (!block) + { + extGlGetQueryObjectiv(OcclusionQueries[index].UID, +#ifdef GL_ARB_occlusion_query + GL_QUERY_RESULT_AVAILABLE_ARB, +#elif defined(GL_NV_occlusion_query) + GL_PIXEL_COUNT_AVAILABLE_NV, +#else + 0, +#endif + &available); + testGLError(__LINE__); + } + if (available==GL_TRUE) + { + extGlGetQueryObjectiv(OcclusionQueries[index].UID, +#ifdef GL_ARB_occlusion_query + GL_QUERY_RESULT_ARB, +#elif defined(GL_NV_occlusion_query) + GL_PIXEL_COUNT_NV, +#else + 0, +#endif + &available); + if (queryFeature(EVDF_OCCLUSION_QUERY)) + OcclusionQueries[index].Result = available; + } + testGLError(__LINE__); + } +} + + +//! Return query result. +/** Return value is the number of visible pixels/fragments. +The value is a safe approximation, i.e. can be larger than the +actual value of pixels. */ +u32 COpenGLDriver::getOcclusionQueryResult(scene::ISceneNode* node) const +{ + const s32 index = OcclusionQueries.linear_search(SOccQuery(node)); + if (index != -1) + return OcclusionQueries[index].Result; + else + return ~0; +} + + +//! Create render target. +IRenderTarget* COpenGLDriver::addRenderTarget() +{ + COpenGLRenderTarget* renderTarget = new COpenGLRenderTarget(this); + RenderTargets.push_back(renderTarget); + + return renderTarget; +} + + +// small helper function to create vertex buffer object adress offsets +static inline u8* buffer_offset(const long offset) +{ + return ((u8*)0 + offset); +} + + +//! draws a vertex primitive list +void COpenGLDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) +{ + if (!primitiveCount || !vertexCount) + return; + + if (!checkPrimitiveCount(primitiveCount)) + return; + + CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType); + + if (vertices && !FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) + getColorBuffer(vertices, vertexCount, vType); + + // draw everything + setRenderStates3DMode(); + + if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES)) + CacheHandler->setClientState(true, true, true, true); + else + CacheHandler->setClientState(true, false, true, false); + +//due to missing defines in OSX headers, we have to be more specific with this check +//#if defined(GL_ARB_vertex_array_bgra) || defined(GL_EXT_vertex_array_bgra) +#ifdef GL_BGRA + const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4; +#else + const GLint colorSize=4; +#endif + if (vertices) + { + if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) + { + switch (vType) + { + case EVT_STANDARD: + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(vertices))[0].Color); + break; + case EVT_2TCOORDS: + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Color); + break; + case EVT_TANGENTS: + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Color); + break; + } + } + else + { + // avoid passing broken pointer to OpenGL + _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); + } + } + + switch (vType) + { + case EVT_STANDARD: + if (vertices) + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].Normal); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].Pos); + } + else + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertex), buffer_offset(12)); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28)); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), 0); + } + + if (Feature.MaxTextureUnits > 0 && CacheHandler->getTextureCache()[1]) + { + CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); + else + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28)); + } + break; + case EVT_2TCOORDS: + if (vertices) + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Normal); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Pos); + } + else + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(12)); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(28)); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(0)); + } + + + if (Feature.MaxTextureUnits > 0) + { + CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords2); + else + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(36)); + } + break; + case EVT_TANGENTS: + if (vertices) + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Normal); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].TCoords); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Pos); + } + else + { + glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(12)); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(28)); + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(0)); + } + + if (Feature.MaxTextureUnits > 0) + { + CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Tangent); + else + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(36)); + + CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 2); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Binormal); + else + glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(48)); + } + break; + } + + renderArray(indexList, primitiveCount, pType, iType); + + if (Feature.MaxTextureUnits > 0) + { + if (vType==EVT_TANGENTS) + { + CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 2); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + if ((vType!=EVT_STANDARD) || CacheHandler->getTextureCache()[1]) + { + CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + CacheHandler->setClientActiveTexture(GL_TEXTURE0); + } +} + + +void COpenGLDriver::getColorBuffer(const void* vertices, u32 vertexCount, E_VERTEX_TYPE vType) +{ + // convert colors to gl color format. + vertexCount *= 4; //reused as color component count + ColorBuffer.set_used(vertexCount); + u32 i; + + switch (vType) + { + case EVT_STANDARD: + { + const S3DVertex* p = static_cast(vertices); + for (i=0; iColor.toOpenGLColor(&ColorBuffer[i]); + ++p; + } + } + break; + case EVT_2TCOORDS: + { + const S3DVertex2TCoords* p = static_cast(vertices); + for (i=0; iColor.toOpenGLColor(&ColorBuffer[i]); + ++p; + } + } + break; + case EVT_TANGENTS: + { + const S3DVertexTangents* p = static_cast(vertices); + for (i=0; iColor.toOpenGLColor(&ColorBuffer[i]); + ++p; + } + } + break; + } +} + + +void COpenGLDriver::renderArray(const void* indexList, u32 primitiveCount, + scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) +{ + GLenum indexSize=0; + + switch (iType) + { + case EIT_16BIT: + { + indexSize=GL_UNSIGNED_SHORT; + break; + } + case EIT_32BIT: + { + indexSize=GL_UNSIGNED_INT; + break; + } + } + + switch (pType) + { + case scene::EPT_POINTS: + case scene::EPT_POINT_SPRITES: + { +#ifdef GL_ARB_point_sprite + if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite]) + glEnable(GL_POINT_SPRITE_ARB); +#endif + + // prepare size and attenuation (where supported) + GLfloat particleSize=Material.Thickness; +// if (AntiAlias) +// particleSize=core::clamp(particleSize, DimSmoothedPoint[0], DimSmoothedPoint[1]); +// else + particleSize=core::clamp(particleSize, DimAliasedPoint[0], DimAliasedPoint[1]); +#if defined(GL_VERSION_1_4) || defined(GL_ARB_point_parameters) || defined(GL_EXT_point_parameters) || defined(GL_SGIS_point_parameters) + const float att[] = {1.0f, 1.0f, 0.0f}; +#if defined(GL_VERSION_1_4) + extGlPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, att); +// extGlPointParameterf(GL_POINT_SIZE_MIN,1.f); + extGlPointParameterf(GL_POINT_SIZE_MAX, particleSize); + extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE, 1.0f); +#elif defined(GL_ARB_point_parameters) + extGlPointParameterfv(GL_POINT_DISTANCE_ATTENUATION_ARB, att); +// extGlPointParameterf(GL_POINT_SIZE_MIN_ARB,1.f); + extGlPointParameterf(GL_POINT_SIZE_MAX_ARB, particleSize); + extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 1.0f); +#elif defined(GL_EXT_point_parameters) + extGlPointParameterfv(GL_DISTANCE_ATTENUATION_EXT, att); +// extGlPointParameterf(GL_POINT_SIZE_MIN_EXT,1.f); + extGlPointParameterf(GL_POINT_SIZE_MAX_EXT, particleSize); + extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_EXT, 1.0f); +#elif defined(GL_SGIS_point_parameters) + extGlPointParameterfv(GL_DISTANCE_ATTENUATION_SGIS, att); +// extGlPointParameterf(GL_POINT_SIZE_MIN_SGIS,1.f); + extGlPointParameterf(GL_POINT_SIZE_MAX_SGIS, particleSize); + extGlPointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_SGIS, 1.0f); +#endif +#endif + glPointSize(particleSize); + +#ifdef GL_ARB_point_sprite + if (pType == scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite]) + { + CacheHandler->setActiveTexture(GL_TEXTURE0_ARB); + glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE, GL_TRUE); + } +#endif + glDrawArrays(GL_POINTS, 0, primitiveCount); +#ifdef GL_ARB_point_sprite + if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite]) + { + glDisable(GL_POINT_SPRITE_ARB); + + CacheHandler->setActiveTexture(GL_TEXTURE0_ARB); + glTexEnvf(GL_POINT_SPRITE_ARB,GL_COORD_REPLACE, GL_FALSE); + } +#endif + } + break; + case scene::EPT_LINE_STRIP: + glDrawElements(GL_LINE_STRIP, primitiveCount+1, indexSize, indexList); + break; + case scene::EPT_LINE_LOOP: + glDrawElements(GL_LINE_LOOP, primitiveCount, indexSize, indexList); + break; + case scene::EPT_LINES: + glDrawElements(GL_LINES, primitiveCount*2, indexSize, indexList); + break; + case scene::EPT_TRIANGLE_STRIP: + glDrawElements(GL_TRIANGLE_STRIP, primitiveCount+2, indexSize, indexList); + break; + case scene::EPT_TRIANGLE_FAN: + glDrawElements(GL_TRIANGLE_FAN, primitiveCount+2, indexSize, indexList); + break; + case scene::EPT_TRIANGLES: + glDrawElements(GL_TRIANGLES, primitiveCount*3, indexSize, indexList); + break; + case scene::EPT_QUAD_STRIP: + glDrawElements(GL_QUAD_STRIP, primitiveCount*2+2, indexSize, indexList); + break; + case scene::EPT_QUADS: + glDrawElements(GL_QUADS, primitiveCount*4, indexSize, indexList); + break; + case scene::EPT_POLYGON: + glDrawElements(GL_POLYGON, primitiveCount, indexSize, indexList); + break; + } +} + + +//! draws a vertex primitive list in 2d +void COpenGLDriver::draw2DVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) +{ + if (!primitiveCount || !vertexCount) + return; + + if (!checkPrimitiveCount(primitiveCount)) + return; + + CNullDriver::draw2DVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType); + + if (vertices && !FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) + getColorBuffer(vertices, vertexCount, vType); + + // draw everything + CacheHandler->getTextureCache().set(0, Material.getTexture(0)); + if (Material.MaterialType==EMT_ONETEXTURE_BLEND) + { + E_BLEND_FACTOR srcFact; + E_BLEND_FACTOR dstFact; + E_MODULATE_FUNC modulo; + u32 alphaSource; + unpack_textureBlendFunc ( srcFact, dstFact, modulo, alphaSource, Material.MaterialTypeParam); + setRenderStates2DMode(alphaSource&video::EAS_VERTEX_COLOR, (Material.getTexture(0) != 0), (alphaSource&video::EAS_TEXTURE) != 0); + } + else + setRenderStates2DMode(Material.MaterialType==EMT_TRANSPARENT_VERTEX_ALPHA, (Material.getTexture(0) != 0), Material.MaterialType==EMT_TRANSPARENT_ALPHA_CHANNEL); + + if ((pType!=scene::EPT_POINTS) && (pType!=scene::EPT_POINT_SPRITES)) + CacheHandler->setClientState(true, false, true, true); + else + CacheHandler->setClientState(true, false, true, false); + +//due to missing defines in OSX headers, we have to be more specific with this check +//#if defined(GL_ARB_vertex_array_bgra) || defined(GL_EXT_vertex_array_bgra) +#ifdef GL_BGRA + const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4; +#else + const GLint colorSize=4; +#endif + if (vertices) + { + if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) + { + switch (vType) + { + case EVT_STANDARD: + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(vertices))[0].Color); + break; + case EVT_2TCOORDS: + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Color); + break; + case EVT_TANGENTS: + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Color); + break; + } + } + else + { + // avoid passing broken pointer to OpenGL + _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); + } + } + + switch (vType) + { + case EVT_STANDARD: + if (vertices) + { + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); + glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].Pos); + } + else + { + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28)); + glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), 0); + } + + if (Feature.MaxTextureUnits > 0 && CacheHandler->getTextureCache()[1]) + { + CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(vertices))[0].TCoords); + else + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), buffer_offset(28)); + } + break; + case EVT_2TCOORDS: + if (vertices) + { + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords); + glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].Pos); + } + else + { + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex2TCoords), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(28)); + glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(0)); + } + + if (Feature.MaxTextureUnits > 0) + { + CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (vertices) + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), &(static_cast(vertices))[0].TCoords2); + else + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex2TCoords), buffer_offset(36)); + } + break; + case EVT_TANGENTS: + if (vertices) + { + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].TCoords); + glVertexPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Pos); + } + else + { + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), buffer_offset(24)); + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(28)); + glVertexPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(0)); + } + + break; + } + + renderArray(indexList, primitiveCount, pType, iType); + + if (Feature.MaxTextureUnits > 0) + { + if ((vType!=EVT_STANDARD) || CacheHandler->getTextureCache()[1]) + { + CacheHandler->setClientActiveTexture(GL_TEXTURE0 + 1); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + CacheHandler->setClientActiveTexture(GL_TEXTURE0); + } +} + + +void COpenGLDriver::draw2DImage(const video::ITexture* texture, const core::position2d& destPos, + const core::rect& sourceRect, const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + if (!sourceRect.isValid()) + return; + + // clip these coordinates + core::rect targetRect(destPos, sourceRect.getSize()); + if (clipRect) + { + targetRect.clipAgainst(*clipRect); + if ( targetRect.getWidth() < 0 || targetRect.getHeight() < 0 ) + return; + } + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + targetRect.clipAgainst( core::rect(0,0, (s32)renderTargetSize.Width, (s32)renderTargetSize.Height) ); + if ( targetRect.getWidth() < 0 || targetRect.getHeight() < 0 ) + return; + + // ok, we've clipped everything. + // now draw it. + const core::dimension2d sourceSize(targetRect.getSize()); + const core::position2d sourcePos(sourceRect.UpperLeftCorner + (targetRect.UpperLeftCorner-destPos)); + + 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( + sourcePos.X * invW, + sourcePos.Y * invH, + (sourcePos.X + sourceSize.Width) * invW, + (sourcePos.Y + sourceSize.Height) * invH); + + disableTextures(1); + if (!CacheHandler->getTextureCache().set(0, texture)) + return; + setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); + + Quad2DVertices[0].Color = color; + Quad2DVertices[1].Color = color; + Quad2DVertices[2].Color = color; + Quad2DVertices[3].Color = color; + + Quad2DVertices[0].Pos = core::vector3df((f32)targetRect.UpperLeftCorner.X, (f32)targetRect.UpperLeftCorner.Y, 0.0f); + Quad2DVertices[1].Pos = core::vector3df((f32)targetRect.LowerRightCorner.X, (f32)targetRect.UpperLeftCorner.Y, 0.0f); + Quad2DVertices[2].Pos = core::vector3df((f32)targetRect.LowerRightCorner.X, (f32)targetRect.LowerRightCorner.Y, 0.0f); + Quad2DVertices[3].Pos = core::vector3df((f32)targetRect.UpperLeftCorner.X, (f32)targetRect.LowerRightCorner.Y, 0.0f); + + Quad2DVertices[0].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + Quad2DVertices[1].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + Quad2DVertices[2].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + Quad2DVertices[3].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + + if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) + getColorBuffer(Quad2DVertices, 4, EVT_STANDARD); + + CacheHandler->setClientState(true, false, true, true); + + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].TCoords); + glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Pos); + +#ifdef GL_BGRA + const GLint colorSize = (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) ? GL_BGRA : 4; +#else + const GLint colorSize = 4; +#endif + if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Color); + else + { + _IRR_DEBUG_BREAK_IF(ColorBuffer.size() == 0); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); + } + + glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices); +} + + +void COpenGLDriver::draw2DImage(const video::ITexture* texture, const core::rect& destRect, + const core::rect& sourceRect, const core::rect* clipRect, + const video::SColor* const colors, bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + 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( + sourceRect.UpperLeftCorner.X * invW, + sourceRect.UpperLeftCorner.Y * invH, + sourceRect.LowerRightCorner.X * invW, + sourceRect.LowerRightCorner.Y *invH); + + const video::SColor temp[4] = + { + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF + }; + + const video::SColor* const useColor = colors ? colors : temp; + + disableTextures(1); + if (!CacheHandler->getTextureCache().set(0, texture)) + return; + setRenderStates2DMode(useColor[0].getAlpha()<255 || useColor[1].getAlpha()<255 || + useColor[2].getAlpha()<255 || useColor[3].getAlpha()<255, + true, useAlphaChannelOfTexture); + + if (clipRect) + { + if (!clipRect->isValid()) + return; + + glEnable(GL_SCISSOR_TEST); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height - clipRect->LowerRightCorner.Y, + clipRect->getWidth(), clipRect->getHeight()); + } + + Quad2DVertices[0].Color = useColor[0]; + Quad2DVertices[1].Color = useColor[3]; + Quad2DVertices[2].Color = useColor[2]; + Quad2DVertices[3].Color = useColor[1]; + + Quad2DVertices[0].Pos = core::vector3df((f32)destRect.UpperLeftCorner.X, (f32)destRect.UpperLeftCorner.Y, 0.0f); + Quad2DVertices[1].Pos = core::vector3df((f32)destRect.LowerRightCorner.X, (f32)destRect.UpperLeftCorner.Y, 0.0f); + Quad2DVertices[2].Pos = core::vector3df((f32)destRect.LowerRightCorner.X, (f32)destRect.LowerRightCorner.Y, 0.0f); + Quad2DVertices[3].Pos = core::vector3df((f32)destRect.UpperLeftCorner.X, (f32)destRect.LowerRightCorner.Y, 0.0f); + + Quad2DVertices[0].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + Quad2DVertices[1].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + Quad2DVertices[2].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + Quad2DVertices[3].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + + if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) + getColorBuffer(Quad2DVertices, 4, EVT_STANDARD); + + CacheHandler->setClientState(true, false, true, true); + + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].TCoords); + glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Pos); + +#ifdef GL_BGRA + const GLint colorSize = (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) ? GL_BGRA : 4; +#else + const GLint colorSize = 4; +#endif + if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Color); + else + { + _IRR_DEBUG_BREAK_IF(ColorBuffer.size() == 0); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); + } + + glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices); + + if (clipRect) + glDisable(GL_SCISSOR_TEST); +} + + +void COpenGLDriver::draw2DImage(const video::ITexture* texture, u32 layer, bool flip) +{ + if (!texture || !CacheHandler->getTextureCache().set(0, texture)) + return; + + disableTextures(1); + + setRenderStates2DMode(false, true, true); + + CacheHandler->setMatrixMode(GL_PROJECTION); + glLoadIdentity(); + CacheHandler->setMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + Transformation3DChanged = true; + + CacheHandler->setClientState(true, false, false, true); + + const core::vector3df positionData[4] = { + core::vector3df(-1.f, 1.f, 0.f), + core::vector3df(1.f, 1.f, 0.f), + core::vector3df(1.f, -1.f, 0.f), + core::vector3df(-1.f, -1.f, 0.f) + }; + + glVertexPointer(2, GL_FLOAT, sizeof(core::vector3df), positionData); + + if (texture && texture->getType() == ETT_CUBEMAP) + { + const core::vector3df texcoordCubeData[6][4] = { + + // GL_TEXTURE_CUBE_MAP_POSITIVE_X + { + core::vector3df(1.f, 1.f, 1.f), + core::vector3df(1.f, 1.f, -1.f), + core::vector3df(1.f, -1.f, -1.f), + core::vector3df(1.f, -1.f, 1.f) + }, + + // GL_TEXTURE_CUBE_MAP_NEGATIVE_X + { + core::vector3df(-1.f, 1.f, -1.f), + core::vector3df(-1.f, 1.f, 1.f), + core::vector3df(-1.f, -1.f, 1.f), + core::vector3df(-1.f, -1.f, -1.f) + }, + + // GL_TEXTURE_CUBE_MAP_POSITIVE_Y + { + core::vector3df(-1.f, 1.f, -1.f), + core::vector3df(1.f, 1.f, -1.f), + core::vector3df(1.f, 1.f, 1.f), + core::vector3df(-1.f, 1.f, 1.f) + }, + + // GL_TEXTURE_CUBE_MAP_NEGATIVE_Y + { + core::vector3df(-1.f, -1.f, 1.f), + core::vector3df(-1.f, -1.f, -1.f), + core::vector3df(1.f, -1.f, -1.f), + core::vector3df(1.f, -1.f, 1.f) + }, + + // GL_TEXTURE_CUBE_MAP_POSITIVE_Z + { + core::vector3df(-1.f, 1.f, 1.f), + core::vector3df(-1.f, -1.f, 1.f), + core::vector3df(1.f, -1.f, 1.f), + core::vector3df(1.f, 1.f, 1.f) + }, + + // GL_TEXTURE_CUBE_MAP_NEGATIVE_Z + { + core::vector3df(1.f, 1.f, -1.f), + core::vector3df(-1.f, 1.f, -1.f), + core::vector3df(-1.f, -1.f, -1.f), + core::vector3df(1.f, -1.f, -1.f) + } + }; + + const core::vector3df texcoordData[4] = { + texcoordCubeData[layer][(flip) ? 3 : 0], + texcoordCubeData[layer][(flip) ? 2 : 1], + texcoordCubeData[layer][(flip) ? 1 : 2], + texcoordCubeData[layer][(flip) ? 0 : 3] + }; + + glTexCoordPointer(3, GL_FLOAT, sizeof(core::vector3df), texcoordData); + } + else + { + f32 modificator = (flip) ? 1.f : 0.f; + + core::vector2df texcoordData[4] = { + core::vector2df(0.f, 0.f + modificator), + core::vector2df(1.f, 0.f + modificator), + core::vector2df(1.f, 1.f - modificator), + core::vector2df(0.f, 1.f - modificator) + }; + + glTexCoordPointer(2, GL_FLOAT, sizeof(core::vector2df), texcoordData); + } + + glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices); +} + + +//! draws a set of 2d images, using a color and the alpha channel of the +//! texture if desired. +void COpenGLDriver::draw2DImageBatch(const video::ITexture* texture, + const core::array >& positions, + const core::array >& sourceRects, + const core::rect* clipRect, + SColor color, + bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + const u32 drawCount = core::min_(positions.size(), sourceRects.size()); + + 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::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + disableTextures(1); + if (!CacheHandler->getTextureCache().set(0, texture)) + return; + setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); + + Quad2DVertices[0].Color = color; + Quad2DVertices[1].Color = color; + Quad2DVertices[2].Color = color; + Quad2DVertices[3].Color = color; + + if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) + getColorBuffer(Quad2DVertices, 4, EVT_STANDARD); + + CacheHandler->setClientState(true, false, true, true); + + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].TCoords); + glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Pos); + +#ifdef GL_BGRA + const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4; +#else + const GLint colorSize=4; +#endif + if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Color); + else + { + _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); + } + + for (u32 i=0; i targetPos(positions[i]); + core::position2d sourcePos(sourceRects[i].UpperLeftCorner); + // This needs to be signed as it may go negative. + core::dimension2d sourceSize(sourceRects[i].getSize()); + if (clipRect) + { + if (targetPos.X < clipRect->UpperLeftCorner.X) + { + sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X; + if (sourceSize.Width <= 0) + continue; + + sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X; + targetPos.X = clipRect->UpperLeftCorner.X; + } + + if (targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X; + if (sourceSize.Width <= 0) + continue; + } + + if (targetPos.Y < clipRect->UpperLeftCorner.Y) + { + sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y; + if (sourceSize.Height <= 0) + continue; + + sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y; + targetPos.Y = clipRect->UpperLeftCorner.Y; + } + + if (targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y; + if (sourceSize.Height <= 0) + continue; + } + } + + // clip these coordinates + + if (targetPos.X<0) + { + sourceSize.Width += targetPos.X; + if (sourceSize.Width <= 0) + continue; + + sourcePos.X -= targetPos.X; + targetPos.X = 0; + } + + if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width; + if (sourceSize.Width <= 0) + continue; + } + + if (targetPos.Y<0) + { + sourceSize.Height += targetPos.Y; + if (sourceSize.Height <= 0) + continue; + + sourcePos.Y -= targetPos.Y; + targetPos.Y = 0; + } + + if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height; + if (sourceSize.Height <= 0) + continue; + } + + // ok, we've clipped everything. + // now draw it. + + const core::rect tcoords( + sourcePos.X * invW, + sourcePos.Y * invH, + (sourcePos.X + sourceSize.Width) * invW, + (sourcePos.Y + sourceSize.Height) * invH); + + const core::rect poss(targetPos, sourceSize); + + Quad2DVertices[0].Pos = core::vector3df((f32)poss.UpperLeftCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f); + Quad2DVertices[1].Pos = core::vector3df((f32)poss.LowerRightCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f); + Quad2DVertices[2].Pos = core::vector3df((f32)poss.LowerRightCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f); + Quad2DVertices[3].Pos = core::vector3df((f32)poss.UpperLeftCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f); + + Quad2DVertices[0].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + Quad2DVertices[1].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + Quad2DVertices[2].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + Quad2DVertices[3].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + + glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices); + } +} + + +//! draws a set of 2d images, using a color and the alpha channel of the +//! texture if desired. The images are drawn beginning at pos and concatenated +//! in one line. All drawings are clipped against clipRect (if != 0). +//! The subtextures are defined by the array of sourceRects and are chosen +//! by the indices given. +void COpenGLDriver::draw2DImageBatch(const video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, + s32 kerningWidth, + const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + disableTextures(1); + if (!CacheHandler->getTextureCache().set(0, texture)) + return; + setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); + + if (clipRect) + { + if (!clipRect->isValid()) + return; + + glEnable(GL_SCISSOR_TEST); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height-clipRect->LowerRightCorner.Y, + clipRect->getWidth(),clipRect->getHeight()); + } + + const core::dimension2d& ss = texture->getOriginalSize(); + core::position2d targetPos(pos); + const f32 invW = 1.f / static_cast(ss.Width); + const f32 invH = 1.f / static_cast(ss.Height); + + Quad2DVertices[0].Color = color; + Quad2DVertices[1].Color = color; + Quad2DVertices[2].Color = color; + Quad2DVertices[3].Color = color; + + if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) + getColorBuffer(Quad2DVertices, 4, EVT_STANDARD); + + CacheHandler->setClientState(true, false, true, true); + + glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].TCoords); + glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Pos); + +#ifdef GL_BGRA + const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4; +#else + const GLint colorSize=4; +#endif + if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Color); + else + { + _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); + } + + for (u32 i=0; i tcoords( + sourceRects[currentIndex].UpperLeftCorner.X * invW, + sourceRects[currentIndex].UpperLeftCorner.Y * invH, + sourceRects[currentIndex].LowerRightCorner.X * invW, + sourceRects[currentIndex].LowerRightCorner.Y * invH); + + const core::rect poss(targetPos, sourceRects[currentIndex].getSize()); + + Quad2DVertices[0].Pos = core::vector3df((f32)poss.UpperLeftCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f); + Quad2DVertices[1].Pos = core::vector3df((f32)poss.LowerRightCorner.X, (f32)poss.UpperLeftCorner.Y, 0.0f); + Quad2DVertices[2].Pos = core::vector3df((f32)poss.LowerRightCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f); + Quad2DVertices[3].Pos = core::vector3df((f32)poss.UpperLeftCorner.X, (f32)poss.LowerRightCorner.Y, 0.0f); + + Quad2DVertices[0].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + Quad2DVertices[1].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + Quad2DVertices[2].TCoords = core::vector2df(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + Quad2DVertices[3].TCoords = core::vector2df(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + + glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices); + + targetPos.X += sourceRects[currentIndex].getWidth(); + } + + if (clipRect) + glDisable(GL_SCISSOR_TEST); +} + + +//! draw a 2d rectangle +void COpenGLDriver::draw2DRectangle(SColor color, const core::rect& position, + const core::rect* clip) +{ + disableTextures(); + setRenderStates2DMode(color.getAlpha() < 255, false, false); + + core::rect pos = position; + + if (clip) + pos.clipAgainst(*clip); + + if (!pos.isValid()) + return; + + glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + glRectf(GLfloat(pos.UpperLeftCorner.X), GLfloat(pos.UpperLeftCorner.Y), + GLfloat(pos.LowerRightCorner.X), GLfloat(pos.LowerRightCorner.Y)); +} + + +//! draw an 2d rectangle +void COpenGLDriver::draw2DRectangle(const core::rect& position, + SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, + const core::rect* clip) +{ + core::rect pos = position; + + if (clip) + pos.clipAgainst(*clip); + + if (!pos.isValid()) + return; + + disableTextures(); + + setRenderStates2DMode(colorLeftUp.getAlpha() < 255 || + colorRightUp.getAlpha() < 255 || + colorLeftDown.getAlpha() < 255 || + colorRightDown.getAlpha() < 255, false, false); + + Quad2DVertices[0].Color = colorLeftUp; + Quad2DVertices[1].Color = colorRightUp; + Quad2DVertices[2].Color = colorRightDown; + Quad2DVertices[3].Color = colorLeftDown; + + Quad2DVertices[0].Pos = core::vector3df((f32)pos.UpperLeftCorner.X, (f32)pos.UpperLeftCorner.Y, 0.0f); + Quad2DVertices[1].Pos = core::vector3df((f32)pos.LowerRightCorner.X, (f32)pos.UpperLeftCorner.Y, 0.0f); + Quad2DVertices[2].Pos = core::vector3df((f32)pos.LowerRightCorner.X, (f32)pos.LowerRightCorner.Y, 0.0f); + Quad2DVertices[3].Pos = core::vector3df((f32)pos.UpperLeftCorner.X, (f32)pos.LowerRightCorner.Y, 0.0f); + + if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) + getColorBuffer(Quad2DVertices, 4, EVT_STANDARD); + + CacheHandler->setClientState(true, false, true, false); + + glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Pos); + +#ifdef GL_BGRA + const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4; +#else + const GLint colorSize=4; +#endif + if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Color); + else + { + _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); + } + + glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices); +} + + +//! Draws a 2d line. +void COpenGLDriver::draw2DLine(const core::position2d& start, + const core::position2d& end, SColor color) +{ + // TODO: It's not pixel-exact. Reason is the way OpenGL handles line-drawing (search the web for "diamond exit rule"). + + if (start==end) + drawPixel(start.X, start.Y, color); + else + { + disableTextures(); + setRenderStates2DMode(color.getAlpha() < 255, false, false); + + Quad2DVertices[0].Color = color; + Quad2DVertices[1].Color = color; + + Quad2DVertices[0].Pos = core::vector3df((f32)start.X, (f32)start.Y, 0.0f); + Quad2DVertices[1].Pos = core::vector3df((f32)end.X, (f32)end.Y, 0.0f); + + if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) + getColorBuffer(Quad2DVertices, 2, EVT_STANDARD); + + CacheHandler->setClientState(true, false, true, false); + + glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Pos); + +#ifdef GL_BGRA + const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4; +#else + const GLint colorSize=4; +#endif + if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Color); + else + { + _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); + } + + glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, Quad2DIndices); + } +} + +//! 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) + return; + + disableTextures(); + setRenderStates2DMode(color.getAlpha() < 255, false, false); + + Quad2DVertices[0].Color = color; + + Quad2DVertices[0].Pos = core::vector3df((f32)x, (f32)y, 0.0f); + + if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) + getColorBuffer(Quad2DVertices, 1, EVT_STANDARD); + + CacheHandler->setClientState(true, false, true, false); + + glVertexPointer(2, GL_FLOAT, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Pos); + +#ifdef GL_BGRA + const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4; +#else + const GLint colorSize=4; +#endif + if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Color); + else + { + _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); + } + + glDrawArrays(GL_POINTS, 0, 1); +} + +//! disables all textures beginning with the optional fromStage parameter. Otherwise all texture stages are disabled. +//! Returns whether disabling was successful or not. +bool COpenGLDriver::disableTextures(u32 fromStage) +{ + bool result=true; + for (u32 i=fromStage; igetTextureCache().set(i, 0, EST_ACTIVE_ON_CHANGE); + } + return result; +} + + +//! creates a matrix in supplied GLfloat array to pass to OpenGL +inline void COpenGLDriver::getGLMatrix(GLfloat gl_matrix[16], const core::matrix4& m) +{ + memcpy(gl_matrix, m.pointer(), 16 * sizeof(f32)); +} + + +//! creates a opengltexturematrix from a D3D style texture matrix +inline void COpenGLDriver::getGLTextureMatrix(GLfloat *o, const core::matrix4& m) +{ + o[0] = m[0]; + o[1] = m[1]; + o[2] = 0.f; + o[3] = 0.f; + + o[4] = m[4]; + o[5] = m[5]; + o[6] = 0.f; + o[7] = 0.f; + + o[8] = 0.f; + o[9] = 0.f; + o[10] = 1.f; + o[11] = 0.f; + + o[12] = m[8]; + o[13] = m[9]; + o[14] = 0.f; + o[15] = 1.f; +} + +ITexture* COpenGLDriver::createDeviceDependentTexture(const io::path& name, IImage* image) +{ + core::array imageArray(1); + imageArray.push_back(image); + + COpenGLTexture* texture = new COpenGLTexture(name, imageArray, ETT_2D, this); + + return texture; +} + +ITexture* COpenGLDriver::createDeviceDependentTextureCubemap(const io::path& name, const core::array& image) +{ + COpenGLTexture* texture = new COpenGLTexture(name, image, ETT_CUBEMAP, this); + + return texture; +} + +void COpenGLDriver::disableFeature(E_VIDEO_DRIVER_FEATURE feature, bool flag) +{ + CNullDriver::disableFeature(feature, flag); + + if ( feature == EVDF_TEXTURE_CUBEMAP_SEAMLESS ) + { + if ( queryFeature(feature) ) + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + else if (COpenGLExtensionHandler::queryFeature(feature)) + glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + } +} + +//! Sets a material. All 3d drawing functions draw geometry now using this material. +void COpenGLDriver::setMaterial(const SMaterial& material) +{ + Material = material; + OverrideMaterial.apply(Material); + + for (u32 i = 0; i < Feature.MaxTextureUnits; ++i) + { + const ITexture* texture = Material.getTexture(i); + CacheHandler->getTextureCache().set(i, texture, EST_ACTIVE_ON_CHANGE); + if ( texture ) + { + setTransform((E_TRANSFORMATION_STATE)(ETS_TEXTURE_0 + i), material.getTextureMatrix(i)); + } + } +} + + +//! prints error if an error happened. +bool COpenGLDriver::testGLError(int code) +{ +#ifdef _DEBUG + GLenum g = glGetError(); + switch (g) + { + case GL_NO_ERROR: + return false; + case GL_INVALID_ENUM: + os::Printer::log("GL_INVALID_ENUM", core::stringc(code).c_str(), ELL_ERROR); break; + case GL_INVALID_VALUE: + os::Printer::log("GL_INVALID_VALUE", core::stringc(code).c_str(), ELL_ERROR); break; + case GL_INVALID_OPERATION: + os::Printer::log("GL_INVALID_OPERATION", core::stringc(code).c_str(), ELL_ERROR); break; + case GL_STACK_OVERFLOW: + os::Printer::log("GL_STACK_OVERFLOW", core::stringc(code).c_str(), ELL_ERROR); break; + case GL_STACK_UNDERFLOW: + os::Printer::log("GL_STACK_UNDERFLOW", core::stringc(code).c_str(), ELL_ERROR); break; + case GL_OUT_OF_MEMORY: + os::Printer::log("GL_OUT_OF_MEMORY", core::stringc(code).c_str(), ELL_ERROR); break; + case GL_TABLE_TOO_LARGE: + os::Printer::log("GL_TABLE_TOO_LARGE", core::stringc(code).c_str(), ELL_ERROR); break; +#if defined(GL_EXT_framebuffer_object) + case GL_INVALID_FRAMEBUFFER_OPERATION_EXT: + os::Printer::log("GL_INVALID_FRAMEBUFFER_OPERATION", core::stringc(code).c_str(), ELL_ERROR); break; +#endif + }; +// _IRR_DEBUG_BREAK_IF(true); + return true; +#else + return false; +#endif +} + + +//! sets the needed renderstates +void COpenGLDriver::setRenderStates3DMode() +{ + if (CurrentRenderMode != ERM_3D) + { + // Reset Texture Stages + CacheHandler->setBlend(false); + CacheHandler->setAlphaTest(false); + CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + CacheHandler->setActiveTexture(GL_TEXTURE0_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + // switch back the matrices + CacheHandler->setMatrixMode(GL_MODELVIEW); + glLoadMatrixf((Matrices[ETS_VIEW] * Matrices[ETS_WORLD]).pointer()); + + CacheHandler->setMatrixMode(GL_PROJECTION); + glLoadMatrixf(Matrices[ETS_PROJECTION].pointer()); + + ResetRenderStates = true; +#ifdef GL_EXT_clip_volume_hint + if (FeatureAvailable[IRR_EXT_clip_volume_hint]) + glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_NICEST); +#endif + } + + if (ResetRenderStates || LastMaterial != Material) + { + // unset old material + + if (LastMaterial.MaterialType != Material.MaterialType && + static_cast(LastMaterial.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); + + // set new material. + if (static_cast(Material.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[Material.MaterialType].Renderer->OnSetMaterial( + Material, LastMaterial, ResetRenderStates, this); + + LastMaterial = Material; + CacheHandler->correctCacheMaterial(LastMaterial); + ResetRenderStates = false; + } + + if (static_cast(Material.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[Material.MaterialType].Renderer->OnRender(this, video::EVT_STANDARD); + + CurrentRenderMode = ERM_3D; +} + + +//! Get native wrap mode value +GLint COpenGLDriver::getTextureWrapMode(const u8 clamp) +{ + GLint mode=GL_REPEAT; + switch (clamp) + { + case ETC_REPEAT: + mode=GL_REPEAT; + break; + case ETC_CLAMP: + mode=GL_CLAMP; + break; + case ETC_CLAMP_TO_EDGE: +#ifdef GL_VERSION_1_2 + if (Version>101) + mode=GL_CLAMP_TO_EDGE; + else +#endif +#ifdef GL_SGIS_texture_edge_clamp + if (FeatureAvailable[IRR_SGIS_texture_edge_clamp]) + mode=GL_CLAMP_TO_EDGE_SGIS; + else +#endif + // fallback + mode=GL_CLAMP; + break; + case ETC_CLAMP_TO_BORDER: +#ifdef GL_VERSION_1_3 + if (Version>102) + mode=GL_CLAMP_TO_BORDER; + else +#endif +#ifdef GL_ARB_texture_border_clamp + if (FeatureAvailable[IRR_ARB_texture_border_clamp]) + mode=GL_CLAMP_TO_BORDER_ARB; + else +#endif +#ifdef GL_SGIS_texture_border_clamp + if (FeatureAvailable[IRR_SGIS_texture_border_clamp]) + mode=GL_CLAMP_TO_BORDER_SGIS; + else +#endif + // fallback + mode=GL_CLAMP; + break; + case ETC_MIRROR: +#ifdef GL_VERSION_1_4 + if (Version>103) + mode=GL_MIRRORED_REPEAT; + else +#endif +#ifdef GL_ARB_texture_border_clamp + if (FeatureAvailable[IRR_ARB_texture_mirrored_repeat]) + mode=GL_MIRRORED_REPEAT_ARB; + else +#endif +#ifdef GL_IBM_texture_mirrored_repeat + if (FeatureAvailable[IRR_IBM_texture_mirrored_repeat]) + mode=GL_MIRRORED_REPEAT_IBM; + else +#endif + mode=GL_REPEAT; + break; + case ETC_MIRROR_CLAMP: +#ifdef GL_EXT_texture_mirror_clamp + if (FeatureAvailable[IRR_EXT_texture_mirror_clamp]) + mode=GL_MIRROR_CLAMP_EXT; + else +#endif +#if defined(GL_ATI_texture_mirror_once) + if (FeatureAvailable[IRR_ATI_texture_mirror_once]) + mode=GL_MIRROR_CLAMP_ATI; + else +#endif + mode=GL_CLAMP; + break; + case ETC_MIRROR_CLAMP_TO_EDGE: +#ifdef GL_EXT_texture_mirror_clamp + if (FeatureAvailable[IRR_EXT_texture_mirror_clamp]) + mode=GL_MIRROR_CLAMP_TO_EDGE_EXT; + else +#endif +#if defined(GL_ATI_texture_mirror_once) + if (FeatureAvailable[IRR_ATI_texture_mirror_once]) + mode=GL_MIRROR_CLAMP_TO_EDGE_ATI; + else +#endif + mode=GL_CLAMP; + break; + case ETC_MIRROR_CLAMP_TO_BORDER: +#ifdef GL_EXT_texture_mirror_clamp + if (FeatureAvailable[IRR_EXT_texture_mirror_clamp]) + mode=GL_MIRROR_CLAMP_TO_BORDER_EXT; + else +#endif + mode=GL_CLAMP; + break; + } + return mode; +} + + +//! Can be called by an IMaterialRenderer to make its work easier. +void COpenGLDriver::setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial, + bool resetAllRenderStates) +{ + // Fixed pipeline isn't important for shader based materials + + E_OPENGL_FIXED_PIPELINE_STATE tempState = FixedPipelineState; + + if (resetAllRenderStates || tempState == EOFPS_ENABLE || tempState == EOFPS_DISABLE_TO_ENABLE) + { + // material colors + if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE || + lastmaterial.ColorMaterial != material.ColorMaterial) + { + switch (material.ColorMaterial) + { + case ECM_NONE: + glDisable(GL_COLOR_MATERIAL); + break; + case ECM_DIFFUSE: + glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); + break; + case ECM_AMBIENT: + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT); + break; + case ECM_EMISSIVE: + glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION); + break; + case ECM_SPECULAR: + glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR); + break; + case ECM_DIFFUSE_AND_AMBIENT: + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); + break; + } + if (material.ColorMaterial != ECM_NONE) + glEnable(GL_COLOR_MATERIAL); + } + + if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE || + lastmaterial.AmbientColor != material.AmbientColor || + lastmaterial.DiffuseColor != material.DiffuseColor || + lastmaterial.EmissiveColor != material.EmissiveColor || + lastmaterial.ColorMaterial != material.ColorMaterial) + { + GLfloat color[4]; + + const f32 inv = 1.0f / 255.0f; + + if ((material.ColorMaterial != video::ECM_AMBIENT) && + (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT)) + { + color[0] = material.AmbientColor.getRed() * inv; + color[1] = material.AmbientColor.getGreen() * inv; + color[2] = material.AmbientColor.getBlue() * inv; + color[3] = material.AmbientColor.getAlpha() * inv; + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color); + } + + if ((material.ColorMaterial != video::ECM_DIFFUSE) && + (material.ColorMaterial != video::ECM_DIFFUSE_AND_AMBIENT)) + { + color[0] = material.DiffuseColor.getRed() * inv; + color[1] = material.DiffuseColor.getGreen() * inv; + color[2] = material.DiffuseColor.getBlue() * inv; + color[3] = material.DiffuseColor.getAlpha() * inv; + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color); + } + + if (material.ColorMaterial != video::ECM_EMISSIVE) + { + color[0] = material.EmissiveColor.getRed() * inv; + color[1] = material.EmissiveColor.getGreen() * inv; + color[2] = material.EmissiveColor.getBlue() * inv; + color[3] = material.EmissiveColor.getAlpha() * inv; + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, color); + } + } + + if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE || + lastmaterial.SpecularColor != material.SpecularColor || + lastmaterial.Shininess != material.Shininess || + lastmaterial.ColorMaterial != material.ColorMaterial) + { + GLfloat color[4]={0.f,0.f,0.f,1.f}; + const f32 inv = 1.0f / 255.0f; + + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material.Shininess); + // disable Specular colors if no shininess is set + if ((material.Shininess != 0.0f) && + (material.ColorMaterial != video::ECM_SPECULAR)) + { +#ifdef GL_EXT_separate_specular_color + if (FeatureAvailable[IRR_EXT_separate_specular_color]) + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); +#endif + color[0] = material.SpecularColor.getRed() * inv; + color[1] = material.SpecularColor.getGreen() * inv; + color[2] = material.SpecularColor.getBlue() * inv; + color[3] = material.SpecularColor.getAlpha() * inv; + } +#ifdef GL_EXT_separate_specular_color + else if (FeatureAvailable[IRR_EXT_separate_specular_color]) + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR); +#endif + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color); + } + + // shademode + if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE || + lastmaterial.GouraudShading != material.GouraudShading) + { + if (material.GouraudShading) + glShadeModel(GL_SMOOTH); + else + glShadeModel(GL_FLAT); + } + + // lighting + if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE || + lastmaterial.Lighting != material.Lighting) + { + if (material.Lighting) + glEnable(GL_LIGHTING); + else + glDisable(GL_LIGHTING); + } + + // fog + if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE || + lastmaterial.FogEnable != material.FogEnable) + { + if (material.FogEnable) + glEnable(GL_FOG); + else + glDisable(GL_FOG); + } + + // normalization + if (resetAllRenderStates || tempState == EOFPS_DISABLE_TO_ENABLE || + lastmaterial.NormalizeNormals != material.NormalizeNormals) + { + if (material.NormalizeNormals) + glEnable(GL_NORMALIZE); + else + glDisable(GL_NORMALIZE); + } + + // Set fixed pipeline as active. + tempState = EOFPS_ENABLE; + } + else if (tempState == EOFPS_ENABLE_TO_DISABLE) + { + glDisable(GL_COLOR_MATERIAL); + glDisable(GL_LIGHTING); + glDisable(GL_FOG); + glDisable(GL_NORMALIZE); + + // Set programmable pipeline as active. + tempState = EOFPS_DISABLE; + } + + // tempState == EOFPS_DISABLE - driver doesn't calls functions related to fixed pipeline. + + // fillmode - fixed pipeline call, but it emulate GL_LINES behaviour in rendering, so it stay here. + if (resetAllRenderStates || (lastmaterial.Wireframe != material.Wireframe) || (lastmaterial.PointCloud != material.PointCloud)) + glPolygonMode(GL_FRONT_AND_BACK, material.Wireframe ? GL_LINE : material.PointCloud? GL_POINT : GL_FILL); + + // ZBuffer + switch (material.ZBuffer) + { + case ECFN_DISABLED: + CacheHandler->setDepthTest(false); + break; + case ECFN_LESSEQUAL: + CacheHandler->setDepthTest(true); + CacheHandler->setDepthFunc(GL_LEQUAL); + break; + case ECFN_EQUAL: + CacheHandler->setDepthTest(true); + CacheHandler->setDepthFunc(GL_EQUAL); + break; + case ECFN_LESS: + CacheHandler->setDepthTest(true); + CacheHandler->setDepthFunc(GL_LESS); + break; + case ECFN_NOTEQUAL: + CacheHandler->setDepthTest(true); + CacheHandler->setDepthFunc(GL_NOTEQUAL); + break; + case ECFN_GREATEREQUAL: + CacheHandler->setDepthTest(true); + CacheHandler->setDepthFunc(GL_GEQUAL); + break; + case ECFN_GREATER: + CacheHandler->setDepthTest(true); + CacheHandler->setDepthFunc(GL_GREATER); + break; + case ECFN_ALWAYS: + CacheHandler->setDepthTest(true); + CacheHandler->setDepthFunc(GL_ALWAYS); + break; + case ECFN_NEVER: + CacheHandler->setDepthTest(true); + CacheHandler->setDepthFunc(GL_NEVER); + break; + default: + break; + } + + // ZWrite + if (getWriteZBuffer(material)) + { + CacheHandler->setDepthMask(true); + } + else + { + CacheHandler->setDepthMask(false); + } + + // Back face culling + if ((material.FrontfaceCulling) && (material.BackfaceCulling)) + { + CacheHandler->setCullFaceFunc(GL_FRONT_AND_BACK); + CacheHandler->setCullFace(true); + } + else if (material.BackfaceCulling) + { + CacheHandler->setCullFaceFunc(GL_BACK); + CacheHandler->setCullFace(true); + } + else if (material.FrontfaceCulling) + { + CacheHandler->setCullFaceFunc(GL_FRONT); + CacheHandler->setCullFace(true); + } + else + { + CacheHandler->setCullFace(false); + } + + // Color Mask + CacheHandler->setColorMask(material.ColorMask); + + // Blend Equation + if (material.BlendOperation == EBO_NONE) + CacheHandler->setBlend(false); + else + { + CacheHandler->setBlend(true); + +#if defined(GL_EXT_blend_subtract) || defined(GL_EXT_blend_minmax) || defined(GL_EXT_blend_logic_op) || defined(GL_VERSION_1_4) + if (queryFeature(EVDF_BLEND_OPERATIONS)) + { + switch (material.BlendOperation) + { + case EBO_SUBTRACT: +#if defined(GL_VERSION_1_4) + CacheHandler->setBlendEquation(GL_FUNC_SUBTRACT); +#elif defined(GL_EXT_blend_subtract) + CacheHandler->setBlendEquation(GL_FUNC_SUBTRACT_EXT); +#endif + break; + case EBO_REVSUBTRACT: +#if defined(GL_VERSION_1_4) + CacheHandler->setBlendEquation(GL_FUNC_REVERSE_SUBTRACT); +#elif defined(GL_EXT_blend_subtract) + CacheHandler->setBlendEquation(GL_FUNC_REVERSE_SUBTRACT_EXT); +#endif + break; + case EBO_MIN: +#if defined(GL_VERSION_1_4) + CacheHandler->setBlendEquation(GL_MIN); +#elif defined(GL_EXT_blend_minmax) + CacheHandler->setBlendEquation(GL_MIN_EXT); +#endif + break; + case EBO_MAX: +#if defined(GL_VERSION_1_4) + CacheHandler->setBlendEquation(GL_MAX); +#elif defined(GL_EXT_blend_minmax) + CacheHandler->setBlendEquation(GL_MAX_EXT); +#endif + break; + case EBO_MIN_FACTOR: +#if defined(GL_AMD_blend_minmax_factor) + if (FeatureAvailable[IRR_AMD_blend_minmax_factor]) + CacheHandler->setBlendEquation(GL_FACTOR_MIN_AMD); +#endif + // fallback in case of missing extension +#if defined(GL_VERSION_1_4) +#if defined(GL_AMD_blend_minmax_factor) + else +#endif + CacheHandler->setBlendEquation(GL_MIN); +#endif + break; + case EBO_MAX_FACTOR: +#if defined(GL_AMD_blend_minmax_factor) + if (FeatureAvailable[IRR_AMD_blend_minmax_factor]) + CacheHandler->setBlendEquation(GL_FACTOR_MAX_AMD); +#endif + // fallback in case of missing extension +#if defined(GL_VERSION_1_4) +#if defined(GL_AMD_blend_minmax_factor) + else +#endif + CacheHandler->setBlendEquation(GL_MAX); +#endif + break; + case EBO_MIN_ALPHA: +#if defined(GL_SGIX_blend_alpha_minmax) + if (FeatureAvailable[IRR_SGIX_blend_alpha_minmax]) + CacheHandler->setBlendEquation(GL_ALPHA_MIN_SGIX); + // fallback in case of missing extension + else + if (FeatureAvailable[IRR_EXT_blend_minmax]) + CacheHandler->setBlendEquation(GL_MIN_EXT); +#endif + break; + case EBO_MAX_ALPHA: +#if defined(GL_SGIX_blend_alpha_minmax) + if (FeatureAvailable[IRR_SGIX_blend_alpha_minmax]) + CacheHandler->setBlendEquation(GL_ALPHA_MAX_SGIX); + // fallback in case of missing extension + else + if (FeatureAvailable[IRR_EXT_blend_minmax]) + CacheHandler->setBlendEquation(GL_MAX_EXT); +#endif + break; + default: +#if defined(GL_VERSION_1_4) + CacheHandler->setBlendEquation(GL_FUNC_ADD); +#elif defined(GL_EXT_blend_subtract) || defined(GL_EXT_blend_minmax) || defined(GL_EXT_blend_logic_op) + CacheHandler->setBlendEquation(GL_FUNC_ADD_EXT); +#endif + break; + } + } +#endif + } + + // Blend Factor + if (IR(material.BlendFactor) & 0xFFFFFFFF // TODO: why the & 0xFFFFFFFF? + && material.MaterialType != EMT_ONETEXTURE_BLEND + ) + { + E_BLEND_FACTOR srcRGBFact = EBF_ZERO; + E_BLEND_FACTOR dstRGBFact = EBF_ZERO; + E_BLEND_FACTOR srcAlphaFact = EBF_ZERO; + E_BLEND_FACTOR dstAlphaFact = EBF_ZERO; + E_MODULATE_FUNC modulo = EMFN_MODULATE_1X; + u32 alphaSource = 0; + + unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulo, alphaSource, material.BlendFactor); + + if (queryFeature(EVDF_BLEND_SEPARATE)) + { + CacheHandler->setBlendFuncSeparate(getGLBlend(srcRGBFact), getGLBlend(dstRGBFact), + getGLBlend(srcAlphaFact), getGLBlend(dstAlphaFact)); + } + else + { + CacheHandler->setBlendFunc(getGLBlend(srcRGBFact), getGLBlend(dstRGBFact)); + } + } + + // Polygon Offset + if (queryFeature(EVDF_POLYGON_OFFSET) && (resetAllRenderStates || + lastmaterial.PolygonOffsetDirection != material.PolygonOffsetDirection || + lastmaterial.PolygonOffsetFactor != material.PolygonOffsetFactor || + lastmaterial.PolygonOffsetSlopeScale != material.PolygonOffsetSlopeScale || + lastmaterial.PolygonOffsetDepthBias != material.PolygonOffsetDepthBias )) + { + glDisable(lastmaterial.Wireframe?GL_POLYGON_OFFSET_LINE:lastmaterial.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL); + if ( material.PolygonOffsetSlopeScale || material.PolygonOffsetDepthBias ) + { + glEnable(material.Wireframe?GL_POLYGON_OFFSET_LINE:material.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL); + + glPolygonOffset(material.PolygonOffsetSlopeScale, material.PolygonOffsetDepthBias); + } + else if (material.PolygonOffsetFactor) + { + glEnable(material.Wireframe?GL_POLYGON_OFFSET_LINE:material.PointCloud?GL_POLYGON_OFFSET_POINT:GL_POLYGON_OFFSET_FILL); + + if (material.PolygonOffsetDirection==EPO_BACK) + glPolygonOffset(1.0f, (GLfloat)material.PolygonOffsetFactor); + else + glPolygonOffset(-1.0f, (GLfloat)-material.PolygonOffsetFactor); + } + else + { + glPolygonOffset(0.0f, 0.f); + } + } + + // thickness + if (resetAllRenderStates || lastmaterial.Thickness != material.Thickness) + { + if (AntiAlias) + { +// glPointSize(core::clamp(static_cast(material.Thickness), DimSmoothedPoint[0], DimSmoothedPoint[1])); + // we don't use point smoothing + glPointSize(core::clamp(static_cast(material.Thickness), DimAliasedPoint[0], DimAliasedPoint[1])); + glLineWidth(core::clamp(static_cast(material.Thickness), DimSmoothedLine[0], DimSmoothedLine[1])); + } + else + { + glPointSize(core::clamp(static_cast(material.Thickness), DimAliasedPoint[0], DimAliasedPoint[1])); + glLineWidth(core::clamp(static_cast(material.Thickness), DimAliasedLine[0], DimAliasedLine[1])); + } + } + + // 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]) + { + if ((material.AntiAliasing & EAAM_QUALITY) == EAAM_QUALITY) + glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST); + else + glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST); + } +#endif + } + else + glDisable(GL_MULTISAMPLE_ARB); + } + if ((material.AntiAliasing & EAAM_LINE_SMOOTH) != (lastmaterial.AntiAliasing & EAAM_LINE_SMOOTH)) + { + 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) != (lastmaterial.AntiAliasing & EAAM_POINT_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); + } + } + + // Texture parameters + setTextureRenderStates(material, resetAllRenderStates); + + // set current fixed pipeline state + FixedPipelineState = tempState; +} + +//! Compare in SMaterial doesn't check texture parameters, so we should call this on each OnRender call. +void COpenGLDriver::setTextureRenderStates(const SMaterial& material, bool resetAllRenderstates) +{ + // Set textures to TU/TIU and apply filters to them + + for (s32 i = Feature.MaxTextureUnits - 1; i >= 0; --i) + { + bool fixedPipeline = false; + + if (FixedPipelineState == EOFPS_ENABLE || FixedPipelineState == EOFPS_DISABLE_TO_ENABLE) + fixedPipeline = true; + + const COpenGLTexture* tmpTexture = CacheHandler->getTextureCache().get(i); + + if (tmpTexture) + { + CacheHandler->setActiveTexture(GL_TEXTURE0 + i); + + if (fixedPipeline) + { + const bool isRTT = tmpTexture->isRenderTarget(); + + CacheHandler->setMatrixMode(GL_TEXTURE); + + if (!isRTT && Matrices[ETS_TEXTURE_0 + i].isIdentity()) + glLoadIdentity(); + else + { + GLfloat glmat[16]; + if (isRTT) + getGLTextureMatrix(glmat, Matrices[ETS_TEXTURE_0 + i] * TextureFlipMatrix); + else + getGLTextureMatrix(glmat, Matrices[ETS_TEXTURE_0 + i]); + glLoadMatrixf(glmat); + } + } + + const GLenum tmpType = tmpTexture->getOpenGLTextureType(); + + COpenGLTexture::SStatesCache& statesCache = tmpTexture->getStatesCache(); + + if (resetAllRenderstates) + statesCache.IsCached = false; + +#ifdef GL_VERSION_2_1 + if (Version >= 210) + { + if (!statesCache.IsCached || material.TextureLayer[i].LODBias != statesCache.LODBias) + { + if (material.TextureLayer[i].LODBias) + { + const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias); + glTexParameterf(tmpType, GL_TEXTURE_LOD_BIAS, tmp); + } + else + glTexParameterf(tmpType, GL_TEXTURE_LOD_BIAS, 0.f); + + statesCache.LODBias = material.TextureLayer[i].LODBias; + } + } + else if (FeatureAvailable[IRR_EXT_texture_lod_bias]) + { + if (material.TextureLayer[i].LODBias) + { + const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias); + glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, tmp); + } + else + glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.f); + } +#elif defined(GL_EXT_texture_lod_bias) + if (FeatureAvailable[IRR_EXT_texture_lod_bias]) + { + if (material.TextureLayer[i].LODBias) + { + 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 + + if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter || + material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter) + { + glTexParameteri(tmpType, GL_TEXTURE_MAG_FILTER, + (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST); + + statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter; + statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter; + } + + if (material.UseMipMaps && tmpTexture->hasMipMaps()) + { + if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter || + material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter || !statesCache.MipMapStatus) + { + glTexParameteri(tmpType, GL_TEXTURE_MIN_FILTER, + material.TextureLayer[i].TrilinearFilter ? GL_LINEAR_MIPMAP_LINEAR : + material.TextureLayer[i].BilinearFilter ? GL_LINEAR_MIPMAP_NEAREST : + GL_NEAREST_MIPMAP_NEAREST); + + statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter; + statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter; + statesCache.MipMapStatus = true; + } + } + else + { + if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter || + material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter || statesCache.MipMapStatus) + { + glTexParameteri(tmpType, GL_TEXTURE_MIN_FILTER, + (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST); + + statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter; + statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter; + statesCache.MipMapStatus = false; + } + } + +#ifdef GL_EXT_texture_filter_anisotropic + if (FeatureAvailable[IRR_EXT_texture_filter_anisotropic] && + (!statesCache.IsCached || material.TextureLayer[i].AnisotropicFilter != statesCache.AnisotropicFilter)) + { + glTexParameteri(tmpType, GL_TEXTURE_MAX_ANISOTROPY_EXT, + material.TextureLayer[i].AnisotropicFilter > 1 ? core::min_(MaxAnisotropy, material.TextureLayer[i].AnisotropicFilter) : 1); + + statesCache.AnisotropicFilter = material.TextureLayer[i].AnisotropicFilter; + } +#endif + + if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapU != statesCache.WrapU) + { + glTexParameteri(tmpType, GL_TEXTURE_WRAP_S, getTextureWrapMode(material.TextureLayer[i].TextureWrapU)); + statesCache.WrapU = material.TextureLayer[i].TextureWrapU; + } + + if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapV != statesCache.WrapV) + { + glTexParameteri(tmpType, GL_TEXTURE_WRAP_T, getTextureWrapMode(material.TextureLayer[i].TextureWrapV)); + statesCache.WrapV = material.TextureLayer[i].TextureWrapV; + } + + if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapW != statesCache.WrapW) + { + glTexParameteri(tmpType, GL_TEXTURE_WRAP_R, getTextureWrapMode(material.TextureLayer[i].TextureWrapW)); + statesCache.WrapW = material.TextureLayer[i].TextureWrapW; + } + + statesCache.IsCached = true; + } + } +} + + +//! Enable the 2d override material +void COpenGLDriver::enableMaterial2D(bool enable) +{ + if (!enable) + CurrentRenderMode = ERM_NONE; + CNullDriver::enableMaterial2D(enable); +} + + +//! sets the needed renderstates +void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel) +{ + // 2d methods uses fixed pipeline + if (FixedPipelineState == COpenGLDriver::EOFPS_DISABLE) + FixedPipelineState = COpenGLDriver::EOFPS_DISABLE_TO_ENABLE; + else + FixedPipelineState = COpenGLDriver::EOFPS_ENABLE; + + bool resetAllRenderStates = false; + + if (CurrentRenderMode != ERM_2D || Transformation3DChanged) + { + // unset last 3d material + if (CurrentRenderMode == ERM_3D) + { + if (static_cast(LastMaterial.MaterialType) < MaterialRenderers.size()) + MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); + } + + if (Transformation3DChanged) + { + CacheHandler->setMatrixMode(GL_PROJECTION); + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + core::matrix4 m(core::matrix4::EM4CONST_NOTHING); + m.buildProjectionMatrixOrthoLH(f32(renderTargetSize.Width), f32(-(s32)(renderTargetSize.Height)), -1.0f, 1.0f); + m.setTranslation(core::vector3df(-1,1,0)); + glLoadMatrixf(m.pointer()); + + CacheHandler->setMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.375f, 0.375f, 0.0f); + + Transformation3DChanged = false; + } + + CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + +#ifdef GL_EXT_clip_volume_hint + if (FeatureAvailable[IRR_EXT_clip_volume_hint]) + glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_FASTEST); +#endif + + resetAllRenderStates = true; + } + + SMaterial currentMaterial = (!OverrideMaterial2DEnabled) ? InitMaterial2D : OverrideMaterial2D; + currentMaterial.Lighting = false; + + if (texture) + { + setTransform(ETS_TEXTURE_0, core::IdentityMatrix); + + // Due to the transformation change, the previous line would call a reset each frame + // but we can safely reset the variable as it was false before + Transformation3DChanged = false; + } + else + { + CacheHandler->getTextureCache().set(0, 0); + } + + setBasicRenderStates(currentMaterial, LastMaterial, resetAllRenderStates); + + LastMaterial = currentMaterial; + CacheHandler->correctCacheMaterial(LastMaterial); + + // no alphaChannel without texture + alphaChannel &= texture; + + if (alphaChannel || alpha) + { + CacheHandler->setBlend(true); + CacheHandler->setAlphaTest(true); + CacheHandler->setAlphaFunc(GL_GREATER, 0.f); + } + else + { + CacheHandler->setBlend(false); + CacheHandler->setAlphaTest(false); + } + + if (texture) + { + CacheHandler->setActiveTexture(GL_TEXTURE0_ARB); + + if (alphaChannel) + { + // if alpha and alpha texture just modulate, otherwise use only the alpha channel + if (alpha) + { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + else + { +#if defined(GL_ARB_texture_env_combine) || defined(GL_EXT_texture_env_combine) + if (FeatureAvailable[IRR_ARB_texture_env_combine]||FeatureAvailable[IRR_EXT_texture_env_combine]) + { +#ifdef GL_ARB_texture_env_combine + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); + // rgb always modulates + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB); +#else + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE); + // rgb always modulates + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); +#endif + } + else +#endif + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + } + else + { + if (alpha) + { +#if defined(GL_ARB_texture_env_combine) || defined(GL_EXT_texture_env_combine) + if (FeatureAvailable[IRR_ARB_texture_env_combine]||FeatureAvailable[IRR_EXT_texture_env_combine]) + { +#ifdef GL_ARB_texture_env_combine + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB); + // rgb always modulates + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB); +#else + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT); + // rgb always modulates + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); +#endif + } + else +#endif + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + else + { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + } + } + + CurrentRenderMode = ERM_2D; +} + + +//! \return Returns the name of the video driver. +const wchar_t* COpenGLDriver::getName() const +{ + return Name.c_str(); +} + + +//! 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 +{ + return MaxLights; +} + + +//! 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. +void COpenGLDriver::setAmbientLight(const SColorf& color) +{ + CNullDriver::setAmbientLight(color); + GLfloat data[4] = {color.r, color.g, color.b, color.a}; + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, data); +} + + +// this code was sent in by Oliver Klems, thank you! (I modified the glViewport +// method just a bit. +void COpenGLDriver::setViewPort(const core::rect& area) +{ + core::rect vp = area; + core::rect rendert(0, 0, getCurrentRenderTargetSize().Width, getCurrentRenderTargetSize().Height); + vp.clipAgainst(rendert); + + if (vp.getHeight() > 0 && vp.getWidth() > 0) + CacheHandler->setViewport(vp.UpperLeftCorner.X, getCurrentRenderTargetSize().Height - vp.UpperLeftCorner.Y - vp.getHeight(), vp.getWidth(), vp.getHeight()); + + ViewPort = vp; +} + + +//! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do +//! this: First, draw all geometry. Then use this method, to draw the shadow +//! volume. Next use IVideoDriver::drawStencilShadow() to visualize the shadow. +void COpenGLDriver::drawStencilShadowVolume(const core::array& triangles, bool zfail, u32 debugDataVisible) +{ + const u32 count=triangles.size(); + if (!StencilBuffer || !count) + return; + + // unset last 3d material + if (CurrentRenderMode == ERM_3D && + static_cast(Material.MaterialType) < MaterialRenderers.size()) + { + MaterialRenderers[Material.MaterialType].Renderer->OnUnsetMaterial(); + ResetRenderStates = true; + } + + // store current OpenGL state + glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | + GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT); + + glDisable(GL_LIGHTING); + glDisable(GL_FOG); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glDepthMask(GL_FALSE); + + if (debugDataVisible & scene::EDS_MESH_WIRE_OVERLAY) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + if (!(debugDataVisible & (scene::EDS_SKELETON|scene::EDS_MESH_WIRE_OVERLAY))) + { + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // no color buffer drawing + glEnable(GL_STENCIL_TEST); + } + + CacheHandler->setClientState(true, false, false, false); + glVertexPointer(3,GL_FLOAT,sizeof(core::vector3df),triangles.const_pointer()); + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + + GLenum incr = GL_INCR; + GLenum decr = GL_DECR; +#ifdef GL_EXT_stencil_wrap + if (FeatureAvailable[IRR_EXT_stencil_wrap]) + { + incr = GL_INCR_WRAP_EXT; + decr = GL_DECR_WRAP_EXT; + } +#endif +#ifdef GL_NV_depth_clamp + if (FeatureAvailable[IRR_NV_depth_clamp]) + glEnable(GL_DEPTH_CLAMP_NV); +#elif defined(GL_ARB_depth_clamp) + if (FeatureAvailable[IRR_ARB_depth_clamp]) + { + glEnable(GL_DEPTH_CLAMP); + } +#endif + + // The first parts are not correctly working, yet. +#if 0 +#ifdef GL_EXT_stencil_two_side + if (FeatureAvailable[IRR_EXT_stencil_two_side]) + { + glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT); + glDisable(GL_CULL_FACE); + if (zfail) + { + extGlActiveStencilFace(GL_BACK); + glStencilOp(GL_KEEP, incr, GL_KEEP); + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + + extGlActiveStencilFace(GL_FRONT); + glStencilOp(GL_KEEP, decr, GL_KEEP); + } + else // zpass + { + extGlActiveStencilFace(GL_BACK); + glStencilOp(GL_KEEP, GL_KEEP, decr); + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + + extGlActiveStencilFace(GL_FRONT); + glStencilOp(GL_KEEP, GL_KEEP, incr); + } + glStencilMask(~0); + glStencilFunc(GL_ALWAYS, 0, ~0); + glDrawArrays(GL_TRIANGLES,0,count); + glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT); + } + else +#endif + if (FeatureAvailable[IRR_ATI_separate_stencil]) + { + glDisable(GL_CULL_FACE); + if (zfail) + { + extGlStencilOpSeparate(GL_BACK, GL_KEEP, incr, GL_KEEP); + extGlStencilOpSeparate(GL_FRONT, GL_KEEP, decr, GL_KEEP); + } + else // zpass + { + extGlStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, decr); + extGlStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, incr); + } + extGlStencilFuncSeparate(GL_ALWAYS, GL_ALWAYS, 0, ~0); + glStencilMask(~0); + glDrawArrays(GL_TRIANGLES,0,count); + } + else +#endif + { + glEnable(GL_CULL_FACE); + if (zfail) + { + glCullFace(GL_FRONT); + glStencilOp(GL_KEEP, incr, GL_KEEP); + glDrawArrays(GL_TRIANGLES,0,count); + + glCullFace(GL_BACK); + glStencilOp(GL_KEEP, decr, GL_KEEP); + glDrawArrays(GL_TRIANGLES,0,count); + } + else // zpass + { + glCullFace(GL_BACK); + glStencilOp(GL_KEEP, GL_KEEP, incr); + glDrawArrays(GL_TRIANGLES,0,count); + + glCullFace(GL_FRONT); + glStencilOp(GL_KEEP, GL_KEEP, decr); + glDrawArrays(GL_TRIANGLES,0,count); + } + } +#ifdef GL_NV_depth_clamp + if (FeatureAvailable[IRR_NV_depth_clamp]) + glDisable(GL_DEPTH_CLAMP_NV); +#elif defined(GL_ARB_depth_clamp) + if (FeatureAvailable[IRR_ARB_depth_clamp]) + { + glDisable(GL_DEPTH_CLAMP); + } +#endif + + glDisable(GL_POLYGON_OFFSET_FILL); + glPopAttrib(); +} + +//! 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. +void COpenGLDriver::drawStencilShadow(bool clearStencilBuffer, video::SColor leftUpEdge, + video::SColor rightUpEdge, video::SColor leftDownEdge, video::SColor rightDownEdge) +{ + if (!StencilBuffer) + return; + + disableTextures(); + + // store attributes + glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT | GL_LIGHTING_BIT); + + glDisable(GL_LIGHTING); + glDisable(GL_FOG); + glDepthMask(GL_FALSE); + + 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); + glStencilFunc(GL_NOTEQUAL, 0, ~0); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + + // draw a shadow rectangle covering the entire screen using stencil buffer + CacheHandler->setMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + CacheHandler->setMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + Quad2DVertices[0].Color = leftDownEdge; + Quad2DVertices[1].Color = leftUpEdge; + Quad2DVertices[2].Color = rightUpEdge; + Quad2DVertices[3].Color = rightDownEdge; + + Quad2DVertices[0].Pos = core::vector3df(-1.0f, -1.0f, -0.9f); + Quad2DVertices[1].Pos = core::vector3df(-1.0f, 1.0f, -0.9f); + Quad2DVertices[2].Pos = core::vector3df(1.0f, 1.0f, -0.9f); + Quad2DVertices[3].Pos = core::vector3df(1.0f, -1.0f, -0.9f); + + if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) + getColorBuffer(Quad2DVertices, 4, EVT_STANDARD); + + CacheHandler->setClientState(true, false, true, false); + + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Pos); + +#ifdef GL_BGRA + const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4; +#else + const GLint colorSize=4; +#endif + if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Color); + else + { + _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); + } + + glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, Quad2DIndices); + + if (clearStencilBuffer) + glClear(GL_STENCIL_BUFFER_BIT); + + // restore settings + glPopMatrix(); + CacheHandler->setMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glPopAttrib(); +} + + +//! Sets the fog mode. +void COpenGLDriver::setFog(SColor c, E_FOG_TYPE fogType, f32 start, + f32 end, f32 density, bool pixelFog, bool rangeFog) +{ + CNullDriver::setFog(c, fogType, start, end, density, pixelFog, rangeFog); + + glFogf(GL_FOG_MODE, GLfloat((fogType==EFT_FOG_LINEAR)? GL_LINEAR : (fogType==EFT_FOG_EXP)?GL_EXP:GL_EXP2)); + +#ifdef GL_EXT_fog_coord + if (FeatureAvailable[IRR_EXT_fog_coord]) + glFogi(GL_FOG_COORDINATE_SOURCE, GL_FRAGMENT_DEPTH); +#endif +#ifdef GL_NV_fog_distance + if (FeatureAvailable[IRR_NV_fog_distance]) + { + if (rangeFog) + glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_RADIAL_NV); + else + glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV); + } +#endif + + if (fogType==EFT_FOG_LINEAR) + { + glFogf(GL_FOG_START, start); + glFogf(GL_FOG_END, end); + } + else + glFogf(GL_FOG_DENSITY, density); + + if (pixelFog) + glHint(GL_FOG_HINT, GL_NICEST); + else + glHint(GL_FOG_HINT, GL_FASTEST); + + SColorf color(c); + GLfloat data[4] = {color.r, color.g, color.b, color.a}; + glFogfv(GL_FOG_COLOR, data); +} + +//! Draws a 3d box. +void COpenGLDriver::draw3DBox( const core::aabbox3d& box, SColor color ) +{ + core::vector3df edges[8]; + box.getEdges(edges); + + setRenderStates3DMode(); + + video::S3DVertex v[24]; + + for(u32 i = 0; i < 24; i++) + v[i].Color = color; + + v[0].Pos = edges[5]; + v[1].Pos = edges[1]; + v[2].Pos = edges[1]; + v[3].Pos = edges[3]; + v[4].Pos = edges[3]; + v[5].Pos = edges[7]; + v[6].Pos = edges[7]; + v[7].Pos = edges[5]; + v[8].Pos = edges[0]; + v[9].Pos = edges[2]; + v[10].Pos = edges[2]; + v[11].Pos = edges[6]; + v[12].Pos = edges[6]; + v[13].Pos = edges[4]; + v[14].Pos = edges[4]; + v[15].Pos = edges[0]; + v[16].Pos = edges[1]; + v[17].Pos = edges[0]; + v[18].Pos = edges[3]; + v[19].Pos = edges[2]; + v[20].Pos = edges[7]; + v[21].Pos = edges[6]; + v[22].Pos = edges[5]; + v[23].Pos = edges[4]; + + if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) + getColorBuffer(v, 24, EVT_STANDARD); + + CacheHandler->setClientState(true, false, true, false); + + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast(v))[0].Pos); + +#ifdef GL_BGRA + const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4; +#else + const GLint colorSize=4; +#endif + if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(v))[0].Color); + else + { + _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); + } + + glDrawArrays(GL_LINES, 0, 24); +} + + +//! Draws a 3d line. +void COpenGLDriver::draw3DLine(const core::vector3df& start, + const core::vector3df& end, SColor color) +{ + setRenderStates3DMode(); + + Quad2DVertices[0].Color = color; + Quad2DVertices[1].Color = color; + + Quad2DVertices[0].Pos = core::vector3df((f32)start.X, (f32)start.Y, (f32)start.Z); + Quad2DVertices[1].Pos = core::vector3df((f32)end.X, (f32)end.Y, (f32)end.Z); + + if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) + getColorBuffer(Quad2DVertices, 2, EVT_STANDARD); + + CacheHandler->setClientState(true, false, true, false); + + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Pos); + +#ifdef GL_BGRA + const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4; +#else + const GLint colorSize=4; +#endif + if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(Quad2DVertices))[0].Color); + else + { + _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); + } + + glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, Quad2DIndices); +} + + +//! Removes a texture from the texture cache and deletes it, freeing lot of memory. +void COpenGLDriver::removeTexture(ITexture* texture) +{ + CacheHandler->getTextureCache().remove(texture); + CNullDriver::removeTexture(texture); +} + +//! Check if the driver supports creating textures with the given color format +bool COpenGLDriver::queryTextureFormat(ECOLOR_FORMAT format) const +{ + GLint dummyInternalFormat; + GLenum dummyPixelFormat; + GLenum dummyPixelType; + void (*dummyConverter)(const void*, s32, void*); + return getColorFormatParameters(format, dummyInternalFormat, dummyPixelFormat, dummyPixelType, &dummyConverter); +} + +bool COpenGLDriver::needsTransparentRenderPass(const irr::video::SMaterial& material) const +{ + return CNullDriver::needsTransparentRenderPass(material) || material.isAlphaBlendOperation(); +} + +//! Only used by the internal engine. Used to notify the driver that +//! the window was resized. +void COpenGLDriver::OnResize(const core::dimension2d& size) +{ + CNullDriver::OnResize(size); + CacheHandler->setViewport(0, 0, size.Width, size.Height); + Transformation3DChanged = true; +} + + +//! Returns type of video driver +E_DRIVER_TYPE COpenGLDriver::getDriverType() const +{ + return EDT_OPENGL; +} + + +//! returns color format +ECOLOR_FORMAT COpenGLDriver::getColorFormat() const +{ + return ColorFormat; +} + + +//! Get a vertex shader constant index. +s32 COpenGLDriver::getVertexShaderConstantID(const c8* name) +{ + return getPixelShaderConstantID(name); +} + +//! Get a pixel shader constant index. +s32 COpenGLDriver::getPixelShaderConstantID(const c8* name) +{ + os::Printer::log("Error: Please call services->getPixelShaderConstantID(), not VideoDriver->getPixelShaderConstantID()."); + return -1; +} + +//! Sets a vertex shader constant. +void COpenGLDriver::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount) +{ +#ifdef GL_ARB_vertex_program + for (s32 i=0; isetPixelShaderConstant(), not VideoDriver->setPixelShaderConstant()."); + return false; +} + +//! Int interface for the above. +bool COpenGLDriver::setPixelShaderConstant(s32 index, const s32* ints, int count) +{ + os::Printer::log("Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant()."); + return false; +} + + +//! Adds a new material renderer to the VideoDriver, using pixel and/or +//! vertex shaders to render geometry. +s32 COpenGLDriver::addShaderMaterial(const c8* vertexShaderProgram, + const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, s32 userData) +{ + s32 nr = -1; + COpenGLShaderMaterialRenderer* r = new COpenGLShaderMaterialRenderer( + this, nr, vertexShaderProgram, pixelShaderProgram, + callback, baseMaterial, userData); + + r->drop(); + return nr; +} + + +//! Adds a new material renderer to the VideoDriver, using GLSL to render geometry. +s32 COpenGLDriver::addHighLevelShaderMaterial( + const c8* vertexShaderProgram, + const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, + const c8* pixelShaderProgram, + const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, + const c8* geometryShaderProgram, + const c8* geometryShaderEntryPointName, + E_GEOMETRY_SHADER_TYPE gsCompileTarget, + scene::E_PRIMITIVE_TYPE inType, + scene::E_PRIMITIVE_TYPE outType, + u32 verticesOut, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, + s32 userData) +{ + s32 nr = -1; + + COpenGLSLMaterialRenderer* r = new COpenGLSLMaterialRenderer( + this, nr, + vertexShaderProgram, vertexShaderEntryPointName, vsCompileTarget, + pixelShaderProgram, pixelShaderEntryPointName, psCompileTarget, + geometryShaderProgram, geometryShaderEntryPointName, gsCompileTarget, + inType, outType, verticesOut, + callback,baseMaterial, userData); + + r->drop(); + + return nr; +} + + +//! Returns a pointer to the IVideoDriver interface. (Implementation for +//! IMaterialRendererServices) +IVideoDriver* COpenGLDriver::getVideoDriver() +{ + return this; +} + + +ITexture* COpenGLDriver::addRenderTargetTexture(const core::dimension2d& size, + const io::path& name, const ECOLOR_FORMAT format) +{ + //disable mip-mapping + bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS); + setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false); + + bool supportForFBO = (Feature.ColorAttachment > 0); + + core::dimension2du destSize(size); + + if (!supportForFBO) + { + destSize = core::dimension2d(core::min_(size.Width, ScreenSize.Width), core::min_(size.Height, ScreenSize.Height)); + destSize = destSize.getOptimalSize((size == size.getOptimalSize()), false, false); + } + + COpenGLTexture* renderTargetTexture = new COpenGLTexture(name, destSize, ETT_2D, format, this); + addTexture(renderTargetTexture); + renderTargetTexture->drop(); + + //restore mip-mapping + setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels); + + return renderTargetTexture; +} + +//! Creates a render target texture for a cubemap +ITexture* COpenGLDriver::addRenderTargetTextureCubemap(const irr::u32 sideLen, const io::path& name, const ECOLOR_FORMAT format) +{ + //disable mip-mapping + bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS); + setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false); + + bool supportForFBO = (Feature.ColorAttachment > 0); + + const core::dimension2d size(sideLen, sideLen); + core::dimension2du destSize(size); + + if (!supportForFBO) + { + destSize = core::dimension2d(core::min_(size.Width, ScreenSize.Width), core::min_(size.Height, ScreenSize.Height)); + destSize = destSize.getOptimalSize((size == size.getOptimalSize()), false, false); + } + + COpenGLTexture* renderTargetTexture = new COpenGLTexture(name, destSize, ETT_CUBEMAP, format, this); + addTexture(renderTargetTexture); + renderTargetTexture->drop(); + + //restore mip-mapping + setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, generateMipLevels); + + return renderTargetTexture; +} + + +//! Returns the maximum amount of primitives (mostly vertices) which +//! the device is able to render with one drawIndexedTriangleList +//! call. +u32 COpenGLDriver::getMaximalPrimitiveCount() const +{ + return 0x7fffffff; +} + +bool COpenGLDriver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil) +{ + if (target && target->getDriverType() != EDT_OPENGL) + { + os::Printer::log("Fatal Error: Tried to set a render target not owned by this driver.", ELL_ERROR); + return false; + } + + bool supportForFBO = (Feature.ColorAttachment > 0); + + core::dimension2d destRenderTargetSize(0, 0); + + if (target) + { + COpenGLRenderTarget* renderTarget = static_cast(target); + + if (supportForFBO) + { + CacheHandler->setFBO(renderTarget->getBufferID()); + renderTarget->update(); + } + + destRenderTargetSize = renderTarget->getSize(); + + CacheHandler->setViewport(0, 0, destRenderTargetSize.Width, destRenderTargetSize.Height); + } + else + { + if (supportForFBO) + CacheHandler->setFBO(0); + else + { + COpenGLRenderTarget* prevRenderTarget = static_cast(CurrentRenderTarget); + COpenGLTexture* renderTargetTexture = static_cast(prevRenderTarget->getTexture()); + + if (renderTargetTexture) + { + const COpenGLTexture* prevTexture = CacheHandler->getTextureCache()[0]; + + CacheHandler->getTextureCache().set(0, renderTargetTexture); + + const core::dimension2d size = renderTargetTexture->getSize(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, size.Width, size.Height); + + CacheHandler->getTextureCache().set(0, prevTexture); + } + } + + destRenderTargetSize = core::dimension2d(0, 0); + + CacheHandler->setViewport(0, 0, ScreenSize.Width, ScreenSize.Height); + } + + if (CurrentRenderTargetSize != destRenderTargetSize) + { + CurrentRenderTargetSize = destRenderTargetSize; + + Transformation3DChanged = true; + } + + CurrentRenderTarget = target; + + if (!supportForFBO) + { + clearFlag |= ECBF_COLOR; + clearFlag |= ECBF_DEPTH; + } + + clearBuffers(clearFlag, clearColor, clearDepth, clearStencil); + + return true; +} + + +void COpenGLDriver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil) +{ + GLbitfield mask = 0; + u8 colorMask = 0; + bool depthMask = false; + + CacheHandler->getColorMask(colorMask); + CacheHandler->getDepthMask(depthMask); + + if (flag & ECBF_COLOR) + { + CacheHandler->setColorMask(ECP_ALL); + + 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 (flag & ECBF_DEPTH) + { + CacheHandler->setDepthMask(true); + glClearDepth(depth); + mask |= GL_DEPTH_BUFFER_BIT; + } + + if (flag & ECBF_STENCIL) + { + glClearStencil(stencil); + mask |= GL_STENCIL_BUFFER_BIT; + } + + if (mask) + glClear(mask); + + CacheHandler->setColorMask(colorMask); + CacheHandler->setDepthMask(depthMask); +} + + +//! Returns an image created from the last rendered frame. +IImage* COpenGLDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target) +{ + if (target != video::ERT_FRAME_BUFFER) + return 0; + + if (format==video::ECF_UNKNOWN) + format=getColorFormat(); + + // TODO: Maybe we could support more formats (floating point and some of those beyond ECF_R8), didn't really try yet + if (IImage::isCompressedFormat(format) || IImage::isDepthFormat(format) || IImage::isFloatingPointFormat(format) || format >= ECF_R8) + return 0; + + // allows to read pixels in top-to-bottom order +#ifdef GL_MESA_pack_invert + if (FeatureAvailable[IRR_MESA_pack_invert]) + glPixelStorei(GL_PACK_INVERT_MESA, GL_TRUE); +#endif + + GLenum fmt; + GLenum type; + + switch (format) + { + case ECF_A1R5G5B5: + fmt = GL_BGRA; + type = GL_UNSIGNED_SHORT_1_5_5_5_REV; + break; + case ECF_R5G6B5: + fmt = GL_RGB; + type = GL_UNSIGNED_SHORT_5_6_5; + break; + case ECF_R8G8B8: + fmt = GL_RGB; + type = GL_UNSIGNED_BYTE; + break; + case ECF_A8R8G8B8: + fmt = GL_BGRA; + if (Version > 101) + type = GL_UNSIGNED_INT_8_8_8_8_REV; + else + type = GL_UNSIGNED_BYTE; + break; + default: + fmt = GL_BGRA; + type = GL_UNSIGNED_BYTE; + break; + } + IImage* newImage = createImage(format, ScreenSize); + + u8* pixels = 0; + if (newImage) + pixels = static_cast(newImage->getData()); + if (pixels) + { + GLenum tgt=GL_FRONT; + switch (target) + { + case video::ERT_FRAME_BUFFER: + break; + case video::ERT_STEREO_LEFT_BUFFER: + tgt=GL_FRONT_LEFT; + break; + case video::ERT_STEREO_RIGHT_BUFFER: + tgt=GL_FRONT_RIGHT; + break; + default: + tgt=GL_AUX0+(target-video::ERT_AUX_BUFFER0); + break; + } + glReadBuffer(tgt); + glReadPixels(0, 0, ScreenSize.Width, ScreenSize.Height, fmt, type, pixels); + testGLError(__LINE__); + glReadBuffer(GL_BACK); + } + +#ifdef GL_MESA_pack_invert + if (FeatureAvailable[IRR_MESA_pack_invert]) + glPixelStorei(GL_PACK_INVERT_MESA, GL_FALSE); + else +#endif + if (pixels) + { + // opengl images are horizontally flipped, so we have to fix that here. + const s32 pitch=newImage->getPitch(); + u8* p2 = pixels + (ScreenSize.Height - 1) * pitch; + u8* tmpBuffer = new u8[pitch]; + for (u32 i=0; i < ScreenSize.Height; i += 2) + { + memcpy(tmpBuffer, pixels, pitch); +// for (u32 j=0; jdrop(); + return 0; + } + } + return newImage; +} + +//! Set/unset a clipping plane. +bool COpenGLDriver::setClipPlane(u32 index, const core::plane3df& plane, bool enable) +{ + if (index >= MaxUserClipPlanes) + return false; + + UserClipPlanes[index].Plane=plane; + enableClipPlane(index, enable); + return true; +} + + +void COpenGLDriver::uploadClipPlane(u32 index) +{ + // opengl needs an array of doubles for the plane equation + GLdouble clip_plane[4]; + clip_plane[0] = UserClipPlanes[index].Plane.Normal.X; + clip_plane[1] = UserClipPlanes[index].Plane.Normal.Y; + clip_plane[2] = UserClipPlanes[index].Plane.Normal.Z; + clip_plane[3] = UserClipPlanes[index].Plane.D; + glClipPlane(GL_CLIP_PLANE0 + index, clip_plane); +} + + +//! Enable/disable a clipping plane. +void COpenGLDriver::enableClipPlane(u32 index, bool enable) +{ + if (index >= MaxUserClipPlanes) + return; + if (enable) + { + if (!UserClipPlanes[index].Enabled) + { + uploadClipPlane(index); + glEnable(GL_CLIP_PLANE0 + index); + } + } + else + glDisable(GL_CLIP_PLANE0 + index); + + UserClipPlanes[index].Enabled=enable; +} + + +core::dimension2du COpenGLDriver::getMaxTextureSize() const +{ + return core::dimension2du(MaxTextureSize, MaxTextureSize); +} + + +//! Convert E_PRIMITIVE_TYPE to OpenGL equivalent +GLenum COpenGLDriver::primitiveTypeToGL(scene::E_PRIMITIVE_TYPE type) const +{ + switch (type) + { + case scene::EPT_POINTS: + return GL_POINTS; + case scene::EPT_LINE_STRIP: + return GL_LINE_STRIP; + case scene::EPT_LINE_LOOP: + return GL_LINE_LOOP; + case scene::EPT_LINES: + return GL_LINES; + case scene::EPT_TRIANGLE_STRIP: + return GL_TRIANGLE_STRIP; + case scene::EPT_TRIANGLE_FAN: + return GL_TRIANGLE_FAN; + case scene::EPT_TRIANGLES: + return GL_TRIANGLES; + case scene::EPT_QUAD_STRIP: + return GL_QUAD_STRIP; + case scene::EPT_QUADS: + return GL_QUADS; + case scene::EPT_POLYGON: + return GL_POLYGON; + case scene::EPT_POINT_SPRITES: +#ifdef GL_ARB_point_sprite + return GL_POINT_SPRITE_ARB; +#else + return GL_POINTS; +#endif + } + return GL_TRIANGLES; +} + + +GLenum COpenGLDriver::getGLBlend(E_BLEND_FACTOR factor) const +{ + GLenum r = 0; + switch (factor) + { + case EBF_ZERO: r = GL_ZERO; break; + case EBF_ONE: r = GL_ONE; break; + case EBF_DST_COLOR: r = GL_DST_COLOR; break; + case EBF_ONE_MINUS_DST_COLOR: r = GL_ONE_MINUS_DST_COLOR; break; + case EBF_SRC_COLOR: r = GL_SRC_COLOR; break; + case EBF_ONE_MINUS_SRC_COLOR: r = GL_ONE_MINUS_SRC_COLOR; break; + case EBF_SRC_ALPHA: r = GL_SRC_ALPHA; break; + case EBF_ONE_MINUS_SRC_ALPHA: r = GL_ONE_MINUS_SRC_ALPHA; break; + case EBF_DST_ALPHA: r = GL_DST_ALPHA; break; + case EBF_ONE_MINUS_DST_ALPHA: r = GL_ONE_MINUS_DST_ALPHA; break; + case EBF_SRC_ALPHA_SATURATE: r = GL_SRC_ALPHA_SATURATE; break; + } + return r; +} + +GLenum COpenGLDriver::getZBufferBits() const +{ + GLenum bits = 0; + switch (Params.ZBufferBits) + { + case 16: + bits = GL_DEPTH_COMPONENT16; + break; + case 24: + bits = GL_DEPTH_COMPONENT24; + break; + case 32: + bits = GL_DEPTH_COMPONENT32; + break; + default: + bits = GL_DEPTH_COMPONENT; + break; + } + return bits; +} + +bool COpenGLDriver::getColorFormatParameters(ECOLOR_FORMAT format, GLint& internalFormat, GLenum& pixelFormat, + GLenum& pixelType, void(**converter)(const void*, s32, void*)) const +{ + // NOTE: Converter variable not used here, but don't remove, it's used in the OGL-ES drivers. + + bool supported = false; + internalFormat = GL_RGBA; + pixelFormat = GL_RGBA; + pixelType = GL_UNSIGNED_BYTE; + + switch (format) + { + case ECF_A1R5G5B5: + supported = true; + internalFormat = GL_RGBA; + pixelFormat = GL_BGRA_EXT; + pixelType = GL_UNSIGNED_SHORT_1_5_5_5_REV; + break; + case ECF_R5G6B5: + supported = true; + internalFormat = GL_RGB; + pixelFormat = GL_RGB; + pixelType = GL_UNSIGNED_SHORT_5_6_5; + break; + case ECF_R8G8B8: + supported = true; + internalFormat = GL_RGB; + pixelFormat = GL_RGB; + pixelType = GL_UNSIGNED_BYTE; + break; + case ECF_A8R8G8B8: + supported = true; + internalFormat = GL_RGBA; + pixelFormat = GL_BGRA_EXT; + if (Version > 101) + pixelType = GL_UNSIGNED_INT_8_8_8_8_REV; + break; + case ECF_DXT1: + supported = true; + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + pixelFormat = GL_BGRA_EXT; + pixelType = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; + case ECF_DXT2: + case ECF_DXT3: + supported = true; + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + pixelFormat = GL_BGRA_EXT; + pixelType = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; + case ECF_DXT4: + case ECF_DXT5: + supported = true; + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + pixelFormat = GL_BGRA_EXT; + pixelType = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + case ECF_D16: + supported = true; + internalFormat = GL_DEPTH_COMPONENT16; + pixelFormat = GL_DEPTH_COMPONENT; + pixelType = GL_UNSIGNED_SHORT; + break; + case ECF_D32: + supported = true; + internalFormat = GL_DEPTH_COMPONENT32; + pixelFormat = GL_DEPTH_COMPONENT; + pixelType = GL_UNSIGNED_INT; + break; + case ECF_D24S8: +#ifdef GL_VERSION_3_0 + if (Version >= 300) + { + supported = true; + internalFormat = GL_DEPTH_STENCIL; + pixelFormat = GL_DEPTH_STENCIL; + pixelType = GL_UNSIGNED_INT_24_8; + } + else +#endif +#ifdef GL_EXT_packed_depth_stencil + if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_EXT_packed_depth_stencil)) + { + supported = true; + internalFormat = GL_DEPTH_STENCIL_EXT; + pixelFormat = GL_DEPTH_STENCIL_EXT; + pixelType = GL_UNSIGNED_INT_24_8_EXT; + } +#endif + break; + case ECF_R8: + if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg)) + { + supported = true; + internalFormat = GL_R8; + pixelFormat = GL_RED; + pixelType = GL_UNSIGNED_BYTE; + } + break; + case ECF_R8G8: + if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg)) + { + supported = true; + internalFormat = GL_RG8; + pixelFormat = GL_RG; + pixelType = GL_UNSIGNED_BYTE; + } + break; + case ECF_R16: + if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg)) + { + supported = true; + internalFormat = GL_R16; + pixelFormat = GL_RED; + pixelType = GL_UNSIGNED_SHORT; + } + break; + case ECF_R16G16: + if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg)) + { + supported = true; + internalFormat = GL_RG16; + pixelFormat = GL_RG; + pixelType = GL_UNSIGNED_SHORT; + } + break; + case ECF_R16F: + if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg)) + { + supported = true; + internalFormat = GL_R16F; + pixelFormat = GL_RED; +#ifdef GL_ARB_half_float_pixel + if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_half_float_pixel)) + pixelType = GL_HALF_FLOAT_ARB; + else +#endif + pixelType = GL_FLOAT; + } + break; + case ECF_G16R16F: + if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg)) + { + supported = true; + internalFormat = GL_RG16F; + pixelFormat = GL_RG; +#ifdef GL_ARB_half_float_pixel + if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_half_float_pixel)) + pixelType = GL_HALF_FLOAT_ARB; + else +#endif + pixelType = GL_FLOAT; + } + break; + case ECF_A16B16G16R16F: + if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_float)) + { + supported = true; + internalFormat = GL_RGBA16F_ARB; + pixelFormat = GL_RGBA; +#ifdef GL_ARB_half_float_pixel + if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_half_float_pixel)) + pixelType = GL_HALF_FLOAT_ARB; + else +#endif + pixelType = GL_FLOAT; + } + break; + case ECF_R32F: + if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg)) + { + supported = true; + internalFormat = GL_R32F; + pixelFormat = GL_RED; + pixelType = GL_FLOAT; + } + break; + case ECF_G32R32F: + if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg)) + { + supported = true; + internalFormat = GL_RG32F; + pixelFormat = GL_RG; + pixelType = GL_FLOAT; + } + break; + case ECF_A32B32G32R32F: + if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_float)) + { + supported = true; + internalFormat = GL_RGBA32F_ARB; + pixelFormat = GL_RGBA; + pixelType = GL_FLOAT; + } + break; + default: + break; + } + +#if defined(GL_ARB_framebuffer_sRGB) || defined(GL_EXT_framebuffer_sRGB) + if (Params.HandleSRGB) + { + if (internalFormat == GL_RGBA) + internalFormat = GL_SRGB_ALPHA_EXT; + else if (internalFormat == GL_RGB) + internalFormat = GL_SRGB_EXT; + } +#endif + + return supported; +} + +COpenGLDriver::E_OPENGL_FIXED_PIPELINE_STATE COpenGLDriver::getFixedPipelineState() const +{ + return FixedPipelineState; +} + +void COpenGLDriver::setFixedPipelineState(COpenGLDriver::E_OPENGL_FIXED_PIPELINE_STATE state) +{ + FixedPipelineState = state; +} + +const SMaterial& COpenGLDriver::getCurrentMaterial() const +{ + return Material; +} + +COpenGLCacheHandler* COpenGLDriver::getCacheHandler() const +{ + return CacheHandler; +} + + +} // end namespace +} // end namespace + +#endif // _IRR_COMPILE_WITH_OPENGL_ + +namespace irr +{ +namespace video +{ + +#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) || defined(_IRR_COMPILE_WITH_X11_DEVICE_) || defined(_IRR_COMPILE_WITH_OSX_DEVICE_) + IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager) + { +#ifdef _IRR_COMPILE_WITH_OPENGL_ + COpenGLDriver* ogl = new COpenGLDriver(params, io, contextManager); + + if (!ogl->initDriver()) + { + ogl->drop(); + ogl = 0; + } + + return ogl; +#else + return 0; +#endif + } +#endif + +// ----------------------------------- +// SDL VERSION +// ----------------------------------- +#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ +IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, + io::IFileSystem* io, CIrrDeviceSDL* device) +{ +#ifdef _IRR_COMPILE_WITH_OPENGL_ + return new COpenGLDriver(params, io, device); +#else + return 0; +#endif // _IRR_COMPILE_WITH_OPENGL_ +} +#endif // _IRR_COMPILE_WITH_SDL_DEVICE_ + +} // end namespace +} // end namespace + + diff --git a/source/Irrlicht/COpenGLDriver.h b/source/Irrlicht/COpenGLDriver.h new file mode 100644 index 00000000..54660cbe --- /dev/null +++ b/source/Irrlicht/COpenGLDriver.h @@ -0,0 +1,526 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __C_VIDEO_OPEN_GL_H_INCLUDED__ +#define __C_VIDEO_OPEN_GL_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#include "SIrrCreationParameters.h" + +namespace irr +{ + class CIrrDeviceWin32; + class CIrrDeviceLinux; + class CIrrDeviceSDL; + class CIrrDeviceMacOSX; +} + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#include "IMaterialRendererServices.h" +#include "CNullDriver.h" + +#include "COpenGLExtensionHandler.h" +#include "IContextManager.h" + +namespace irr +{ + +namespace video +{ + class IContextManager; + + class COpenGLDriver : public CNullDriver, public IMaterialRendererServices, public COpenGLExtensionHandler + { + public: + // Information about state of fixed pipeline activity. + enum E_OPENGL_FIXED_PIPELINE_STATE + { + EOFPS_ENABLE = 0, // fixed pipeline. + EOFPS_DISABLE, // programmable pipeline. + EOFPS_ENABLE_TO_DISABLE, // switch from fixed to programmable pipeline. + EOFPS_DISABLE_TO_ENABLE // switch from programmable to fixed pipeline. + }; + +#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) || defined(_IRR_COMPILE_WITH_X11_DEVICE_) || defined(_IRR_COMPILE_WITH_OSX_DEVICE_) + COpenGLDriver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager); +#endif + +#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ + COpenGLDriver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, CIrrDeviceSDL* device); +#endif + + bool initDriver(); + + //! destructor + virtual ~COpenGLDriver(); + + virtual bool beginScene(u16 clearFlag, SColor clearColor = SColor(255,0,0,0), f32 clearDepth = 1.f, u8 clearStencil = 0, + const SExposedVideoData& videoData = SExposedVideoData(), core::rect* sourceRect = 0) _IRR_OVERRIDE_; + + virtual bool endScene() _IRR_OVERRIDE_; + + //! sets transformation + virtual void setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) _IRR_OVERRIDE_; + + + struct SHWBufferLink_opengl : public SHWBufferLink + { + SHWBufferLink_opengl(const scene::IMeshBuffer *_MeshBuffer): SHWBufferLink(_MeshBuffer), vbo_verticesID(0),vbo_indicesID(0){} + + GLuint vbo_verticesID; //tmp + GLuint vbo_indicesID; //tmp + + GLuint vbo_verticesSize; //tmp + GLuint vbo_indicesSize; //tmp + }; + + //! updates hardware buffer if needed + virtual bool updateHardwareBuffer(SHWBufferLink *HWBuffer) _IRR_OVERRIDE_; + + //! Create hardware buffer from mesh + virtual SHWBufferLink *createHardwareBuffer(const scene::IMeshBuffer* mb) _IRR_OVERRIDE_; + + //! Delete hardware buffer (only some drivers can) + virtual void deleteHardwareBuffer(SHWBufferLink *HWBuffer) _IRR_OVERRIDE_; + + //! Draw hardware buffer + virtual void drawHardwareBuffer(SHWBufferLink *HWBuffer) _IRR_OVERRIDE_; + + //! Create occlusion query. + /** Use node for identification and mesh for occlusion test. */ + virtual void addOcclusionQuery(scene::ISceneNode* node, + const scene::IMesh* mesh=0) _IRR_OVERRIDE_; + + //! Remove occlusion query. + virtual void removeOcclusionQuery(scene::ISceneNode* node) _IRR_OVERRIDE_; + + //! Run occlusion query. Draws mesh stored in query. + /** If the mesh shall not be rendered visible, use + overrideMaterial to disable the color and depth buffer. */ + virtual void runOcclusionQuery(scene::ISceneNode* node, bool visible=false) _IRR_OVERRIDE_; + + //! Update occlusion query. Retrieves results from GPU. + /** If the query shall not block, set the flag to false. + Update might not occur in this case, though */ + virtual void updateOcclusionQuery(scene::ISceneNode* node, bool block=true) _IRR_OVERRIDE_; + + //! Return query result. + /** Return value is the number of visible pixels/fragments. + The value is a safe approximation, i.e. can be larger then the + actual value of pixels. */ + virtual u32 getOcclusionQueryResult(scene::ISceneNode* node) const _IRR_OVERRIDE_; + + //! Create render target. + virtual IRenderTarget* addRenderTarget() _IRR_OVERRIDE_; + + //! draws a vertex primitive list + virtual void drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) _IRR_OVERRIDE_; + + //! draws a vertex primitive list in 2d + virtual void draw2DVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) _IRR_OVERRIDE_; + + //! queries the features of the driver, returns true if feature is available + virtual bool queryFeature(E_VIDEO_DRIVER_FEATURE feature) const _IRR_OVERRIDE_ + { + return FeatureEnabled[feature] && COpenGLExtensionHandler::queryFeature(feature); + } + + //! Disable a feature of the driver. + virtual void disableFeature(E_VIDEO_DRIVER_FEATURE feature, bool flag=true) _IRR_OVERRIDE_; + + //! Sets a material. All 3d drawing functions draw geometry now + //! using this material. + //! \param material: Material to be used from now on. + virtual void setMaterial(const SMaterial& material) _IRR_OVERRIDE_; + + 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) _IRR_OVERRIDE_; + + 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) _IRR_OVERRIDE_; + + virtual void draw2DImage(const video::ITexture* texture, u32 layer, bool flip); + + //! draws a set of 2d images, using a color and the alpha channel of the + //! texture if desired. + void draw2DImageBatch(const video::ITexture* texture, + const core::array >& positions, + const core::array >& sourceRects, + const core::rect* clipRect, + SColor color, + bool useAlphaChannelOfTexture) _IRR_OVERRIDE_; + + //! draws a set of 2d images, using a color and the alpha + /** channel of the texture if desired. The images are drawn + beginning at pos and concatenated in one line. All drawings + are clipped against clipRect (if != 0). + The subtextures are defined by the array of sourceRects + and are chosen by the indices given. + \param texture: Texture to be drawn. + \param pos: Upper left 2d destination position where the image will be drawn. + \param sourceRects: Source rectangles of the image. + \param indices: List of indices which choose the actual rectangle used each time. + \param clipRect: Pointer to rectangle on the screen where the image is clipped to. + This pointer can be 0. Then the image is not clipped. + \param color: Color with which the image is colored. + Note that the alpha component is used: If alpha is other than 255, the image will be transparent. + \param useAlphaChannelOfTexture: If true, the alpha channel of the texture is + used to draw the image. */ + virtual void draw2DImageBatch(const video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, + s32 kerningWidth=0, + const core::rect* clipRect=0, + SColor color=SColor(255,255,255,255), + bool useAlphaChannelOfTexture=false) _IRR_OVERRIDE_; + + //! draw an 2d rectangle + virtual void draw2DRectangle(SColor color, const core::rect& pos, + const core::rect* clip = 0) _IRR_OVERRIDE_; + + //!Draws an 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) _IRR_OVERRIDE_; + + //! Draws a 2d line. + virtual void draw2DLine(const core::position2d& start, + const core::position2d& end, + SColor color=SColor(255,255,255,255)) _IRR_OVERRIDE_; + + //! Draws a single pixel + virtual void drawPixel(u32 x, u32 y, const SColor & color) _IRR_OVERRIDE_; + + //! Draws a 3d box + virtual void draw3DBox( const core::aabbox3d& box, SColor color = SColor(255,255,255,255 ) ) _IRR_OVERRIDE_; + + //! Draws a 3d line. + virtual void draw3DLine(const core::vector3df& start, + const core::vector3df& end, + SColor color = SColor(255,255,255,255)) _IRR_OVERRIDE_; + + //! \return Returns the name of the video driver. Example: In case of the Direct3D8 + //! driver, it would return "Direct3D8.1". + virtual const wchar_t* getName() const _IRR_OVERRIDE_; + + //! deletes all dynamic lights there are + virtual void deleteAllDynamicLights() _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! returns the maximal amount of dynamic lights the device can handle + virtual u32 getMaximalDynamicLightAmount() const _IRR_OVERRIDE_; + + //! 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. + virtual void setAmbientLight(const SColorf& color) _IRR_OVERRIDE_; + + //! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do + //! this: First, draw all geometry. Then use this method, to draw the shadow + //! volume. Then, use IVideoDriver::drawStencilShadow() to visualize the shadow. + virtual void drawStencilShadowVolume(const core::array& triangles, bool zfail, u32 debugDataVisible=0) _IRR_OVERRIDE_; + + //! 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. + virtual void drawStencilShadow(bool clearStencilBuffer=false, + video::SColor leftUpEdge = video::SColor(0,0,0,0), + video::SColor rightUpEdge = video::SColor(0,0,0,0), + video::SColor leftDownEdge = video::SColor(0,0,0,0), + video::SColor rightDownEdge = video::SColor(0,0,0,0)) _IRR_OVERRIDE_; + + //! sets a viewport + virtual void setViewPort(const core::rect& area) _IRR_OVERRIDE_; + + //! Sets the fog mode. + virtual void setFog(SColor color, E_FOG_TYPE fogType, f32 start, + f32 end, f32 density, bool pixelFog, bool rangeFog) _IRR_OVERRIDE_; + + //! Only used by the internal engine. Used to notify the driver that + //! the window was resized. + virtual void OnResize(const core::dimension2d& size) _IRR_OVERRIDE_; + + //! Returns type of video driver + virtual E_DRIVER_TYPE getDriverType() const _IRR_OVERRIDE_; + + //! get color format of the current color buffer + virtual ECOLOR_FORMAT getColorFormat() const _IRR_OVERRIDE_; + + //! Returns the transformation set by setTransform + virtual const core::matrix4& getTransform(E_TRANSFORMATION_STATE state) const _IRR_OVERRIDE_; + + //! Can be called by an IMaterialRenderer to make its work easier. + virtual void setBasicRenderStates(const SMaterial& material, const SMaterial& lastmaterial, + bool resetAllRenderstates) _IRR_OVERRIDE_; + + //! Compare in SMaterial doesn't check texture parameters, so we should call this on each OnRender call. + virtual void setTextureRenderStates(const SMaterial& material, bool resetAllRenderstates); + + //! Get a vertex shader constant index. + virtual s32 getVertexShaderConstantID(const c8* name) _IRR_OVERRIDE_; + + //! Get a pixel shader constant index. + virtual s32 getPixelShaderConstantID(const c8* name) _IRR_OVERRIDE_; + + //! Sets a vertex shader constant. + virtual void setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1) _IRR_OVERRIDE_; + + //! Sets a pixel shader constant. + virtual void setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1) _IRR_OVERRIDE_; + + //! Sets a constant for the vertex shader based on an index. + virtual bool setVertexShaderConstant(s32 index, const f32* floats, int count) _IRR_OVERRIDE_; + + //! Int interface for the above. + virtual bool setVertexShaderConstant(s32 index, const s32* ints, int count) _IRR_OVERRIDE_; + + //! Sets a constant for the pixel shader based on an index. + virtual bool setPixelShaderConstant(s32 index, const f32* floats, int count) _IRR_OVERRIDE_; + + //! Int interface for the above. + virtual bool setPixelShaderConstant(s32 index, const s32* ints, int count) _IRR_OVERRIDE_; + + //! disables all textures beginning with the optional fromStage parameter. Otherwise all texture stages are disabled. + //! Returns whether disabling was successful or not. + bool disableTextures(u32 fromStage=0); + + //! Adds a new material renderer to the VideoDriver, using + //! extGLGetObjectParameteriv(shaderHandle, GL_OBJECT_COMPILE_STATUS_ARB, &status) + //! pixel and/or vertex shaders to render geometry. + virtual s32 addShaderMaterial(const c8* vertexShaderProgram, const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, E_MATERIAL_TYPE baseMaterial, s32 userData) _IRR_OVERRIDE_; + + //! Adds a new material renderer to the VideoDriver, using GLSL to render geometry. + virtual s32 addHighLevelShaderMaterial( + const c8* vertexShaderProgram, + const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, + const c8* pixelShaderProgram, + const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, + const c8* geometryShaderProgram, + const c8* geometryShaderEntryPointName = "main", + E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0, + scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES, + scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP, + u32 verticesOut = 0, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData = 0) _IRR_OVERRIDE_; + + //! Returns a pointer to the IVideoDriver interface. (Implementation for + //! IMaterialRendererServices) + virtual IVideoDriver* getVideoDriver() _IRR_OVERRIDE_; + + //! Returns the maximum amount of primitives (mostly vertices) which + //! the device is able to render with one drawIndexedTriangleList + //! call. + virtual u32 getMaximalPrimitiveCount() const _IRR_OVERRIDE_; + + virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, + const io::path& name, const ECOLOR_FORMAT format = ECF_UNKNOWN) _IRR_OVERRIDE_; + + //! Creates a render target texture for a cubemap + ITexture* addRenderTargetTextureCubemap(const irr::u32 sideLen, + const io::path& name, const ECOLOR_FORMAT format) _IRR_OVERRIDE_; + + virtual bool setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor = SColor(255,0,0,0), + f32 clearDepth = 1.f, u8 clearStencil = 0) _IRR_OVERRIDE_; + + virtual void clearBuffers(u16 flag, SColor color = SColor(255,0,0,0), f32 depth = 1.f, u8 stencil = 0) _IRR_OVERRIDE_; + + //! Returns an image created from the last rendered frame. + virtual IImage* createScreenShot(video::ECOLOR_FORMAT format=video::ECF_UNKNOWN, video::E_RENDER_TARGET target=video::ERT_FRAME_BUFFER) _IRR_OVERRIDE_; + + //! checks if an OpenGL error has happened and prints it (+ some internal code which is usually the line number) + //! for performance reasons only available in debug mode + bool testGLError(int code=0); + + //! Set/unset 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 plane: The plane itself. + //! \param enable: If true, enable the clipping plane else disable it. + virtual bool setClipPlane(u32 index, const core::plane3df& plane, bool enable=false) _IRR_OVERRIDE_; + + //! 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. + virtual void enableClipPlane(u32 index, bool enable) _IRR_OVERRIDE_; + + //! Enable the 2d override material + virtual void enableMaterial2D(bool enable=true) _IRR_OVERRIDE_; + + //! Returns the graphics card vendor name. + virtual core::stringc getVendorInfo() _IRR_OVERRIDE_ {return VendorName;} + + //! Returns the maximum texture size supported. + virtual core::dimension2du getMaxTextureSize() const _IRR_OVERRIDE_; + + //! Removes a texture from the texture cache and deletes it, freeing lot of memory. + virtual void removeTexture(ITexture* texture) _IRR_OVERRIDE_; + + //! Check if the driver supports creating textures with the given color format + virtual bool queryTextureFormat(ECOLOR_FORMAT format) const _IRR_OVERRIDE_; + + //! Used by some SceneNodes to check if a material should be rendered in the transparent render pass + virtual bool needsTransparentRenderPass(const irr::video::SMaterial& material) const _IRR_OVERRIDE_; + + //! Convert E_PRIMITIVE_TYPE to OpenGL equivalent + GLenum primitiveTypeToGL(scene::E_PRIMITIVE_TYPE type) const; + + //! Convert E_BLEND_FACTOR to OpenGL equivalent + GLenum getGLBlend(E_BLEND_FACTOR factor) const; + + //! Get ZBuffer bits. + GLenum getZBufferBits() const; + + bool getColorFormatParameters(ECOLOR_FORMAT format, GLint& internalFormat, GLenum& pixelFormat, + GLenum& pixelType, void(**converter)(const void*, s32, void*)) const; + + //! Return info about fixed pipeline state. + E_OPENGL_FIXED_PIPELINE_STATE getFixedPipelineState() const; + + //! Set info about fixed pipeline state. + void setFixedPipelineState(E_OPENGL_FIXED_PIPELINE_STATE state); + + //! Get current material. + const SMaterial& getCurrentMaterial() const; + + COpenGLCacheHandler* getCacheHandler() const; + + private: + + 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(); + + virtual ITexture* createDeviceDependentTexture(const io::path& name, IImage* image) _IRR_OVERRIDE_; + + virtual ITexture* createDeviceDependentTextureCubemap(const io::path& name, const core::array& image) _IRR_OVERRIDE_; + + //! creates a transposed matrix in supplied GLfloat array to pass to OpenGL + inline void getGLMatrix(GLfloat gl_matrix[16], const core::matrix4& m); + inline void getGLTextureMatrix(GLfloat gl_matrix[16], const core::matrix4& m); + + //! get native wrap mode value + GLint getTextureWrapMode(const u8 clamp); + + //! sets the needed renderstates + void setRenderStates3DMode(); + + //! sets the needed renderstates + void setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel); + + 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); + + //! helper function for render setup. + void getColorBuffer(const void* vertices, u32 vertexCount, E_VERTEX_TYPE vType); + + //! helper function doing the actual rendering. + void renderArray(const void* indexList, u32 primitiveCount, + scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType); + + COpenGLCacheHandler* CacheHandler; + + core::stringw Name; + core::matrix4 Matrices[ETS_COUNT]; + core::array ColorBuffer; + + //! enumeration for rendering modes such as 2d and 3d for minizing the switching of renderStates. + enum E_RENDER_MODE + { + ERM_NONE = 0, // no render state has been set yet. + ERM_2D, // 2d drawing rendermode + ERM_3D // 3d rendering mode + }; + + E_RENDER_MODE CurrentRenderMode; + //! bool to make all renderstates reset if set to true. + bool ResetRenderStates; + bool Transformation3DChanged; + u8 AntiAlias; + + SMaterial Material, LastMaterial; + + struct SUserClipPlane + { + SUserClipPlane() : Enabled(false) {} + core::plane3df Plane; + bool Enabled; + }; + core::array UserClipPlanes; + + core::stringc VendorName; + + core::matrix4 TextureFlipMatrix; + + //! Color buffer format + ECOLOR_FORMAT ColorFormat; + + E_OPENGL_FIXED_PIPELINE_STATE FixedPipelineState; + + SIrrlichtCreationParameters Params; + + //! 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; + + //! Built-in 2D quad for 2D rendering. + S3DVertex Quad2DVertices[4]; + static const u16 Quad2DIndices[4]; + + #ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ + CIrrDeviceSDL *SDLDevice; + #endif + + IContextManager* ContextManager; + + E_DEVICE_TYPE DeviceType; + }; + +} // end namespace video +} // end namespace irr + + +#endif // _IRR_COMPILE_WITH_OPENGL_ +#endif + diff --git a/source/Irrlicht/COpenGLExtensionHandler.cpp b/source/Irrlicht/COpenGLExtensionHandler.cpp new file mode 100644 index 00000000..16162640 --- /dev/null +++ b/source/Irrlicht/COpenGLExtensionHandler.cpp @@ -0,0 +1,878 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "COpenGLExtensionHandler.h" + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#include "irrString.h" +#include "SMaterial.h" +#include "fast_atof.h" + +namespace irr +{ +namespace video +{ + +bool COpenGLExtensionHandler::needsDSAFramebufferHack = true; + +COpenGLExtensionHandler::COpenGLExtensionHandler() : + StencilBuffer(false), TextureCompressionExtension(false), MaxLights(1), + MaxAnisotropy(1), MaxUserClipPlanes(0), MaxAuxBuffers(0), MaxIndices(65535), + MaxTextureSize(1), MaxGeometryVerticesOut(0), + MaxTextureLODBias(0.f), Version(0), ShaderLanguageVersion(0), + OcclusionQuerySupport(false) +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + ,pGlActiveTexture(0) + ,pGlActiveTextureARB(0), pGlClientActiveTextureARB(0), + pGlGenProgramsARB(0), pGlGenProgramsNV(0), + pGlBindProgramARB(0), pGlBindProgramNV(0), + pGlDeleteProgramsARB(0), pGlDeleteProgramsNV(0), + pGlProgramStringARB(0), pGlLoadProgramNV(0), + pGlProgramLocalParameter4fvARB(0), + pGlCreateShaderObjectARB(0), pGlShaderSourceARB(0), + pGlCompileShaderARB(0), pGlCreateProgramObjectARB(0), pGlAttachObjectARB(0), + pGlLinkProgramARB(0), pGlUseProgramObjectARB(0), pGlDeleteObjectARB(0), + pGlCreateProgram(0), pGlUseProgram(0), + pGlDeleteProgram(0), pGlDeleteShader(0), + pGlGetAttachedObjectsARB(0), pGlGetAttachedShaders(0), + pGlCreateShader(0), pGlShaderSource(0), pGlCompileShader(0), + pGlAttachShader(0), pGlLinkProgram(0), + pGlGetInfoLogARB(0), pGlGetShaderInfoLog(0), pGlGetProgramInfoLog(0), + pGlGetObjectParameterivARB(0), pGlGetShaderiv(0), pGlGetProgramiv(0), + pGlGetUniformLocationARB(0), pGlGetUniformLocation(0), + pGlUniform1fvARB(0), pGlUniform2fvARB(0), pGlUniform3fvARB(0), pGlUniform4fvARB(0), + pGlUniform1ivARB(0), pGlUniform2ivARB(0), pGlUniform3ivARB(0), pGlUniform4ivARB(0), + pGlUniformMatrix2fvARB(0), pGlUniformMatrix3fvARB(0), pGlUniformMatrix4fvARB(0), + pGlGetActiveUniformARB(0), pGlGetActiveUniform(0), + pGlPointParameterfARB(0), pGlPointParameterfvARB(0), + pGlStencilFuncSeparate(0), pGlStencilOpSeparate(0), + pGlStencilFuncSeparateATI(0), pGlStencilOpSeparateATI(0), + pGlCompressedTexImage2D(0), pGlCompressedTexSubImage2D(0), + // ARB framebuffer object + pGlBindFramebuffer(0), pGlDeleteFramebuffers(0), pGlGenFramebuffers(0), + pGlCheckFramebufferStatus(0), pGlFramebufferTexture2D(0), + pGlBindRenderbuffer(0), pGlDeleteRenderbuffers(0), pGlGenRenderbuffers(0), + pGlRenderbufferStorage(0), pGlFramebufferRenderbuffer(0), pGlGenerateMipmap(0), + // EXT framebuffer object + pGlBindFramebufferEXT(0), pGlDeleteFramebuffersEXT(0), pGlGenFramebuffersEXT(0), + pGlCheckFramebufferStatusEXT(0), pGlFramebufferTexture2DEXT(0), + pGlBindRenderbufferEXT(0), pGlDeleteRenderbuffersEXT(0), pGlGenRenderbuffersEXT(0), + pGlRenderbufferStorageEXT(0), pGlFramebufferRenderbufferEXT(0), pGlGenerateMipmapEXT(0), + pGlActiveStencilFaceEXT(0), + // MRTs + pGlDrawBuffersARB(0), pGlDrawBuffersATI(0), + pGlGenBuffersARB(0), pGlBindBufferARB(0), pGlBufferDataARB(0), pGlDeleteBuffersARB(0), + pGlBufferSubDataARB(0), pGlGetBufferSubDataARB(0), pGlMapBufferARB(0), pGlUnmapBufferARB(0), + pGlIsBufferARB(0), pGlGetBufferParameterivARB(0), pGlGetBufferPointervARB(0), + pGlProvokingVertexARB(0), pGlProvokingVertexEXT(0), + pGlProgramParameteriARB(0), pGlProgramParameteriEXT(0), + pGlGenQueriesARB(0), pGlDeleteQueriesARB(0), pGlIsQueryARB(0), + pGlBeginQueryARB(0), pGlEndQueryARB(0), pGlGetQueryivARB(0), + pGlGetQueryObjectivARB(0), pGlGetQueryObjectuivARB(0), + pGlGenOcclusionQueriesNV(0), pGlDeleteOcclusionQueriesNV(0), + pGlIsOcclusionQueryNV(0), pGlBeginOcclusionQueryNV(0), + pGlEndOcclusionQueryNV(0), pGlGetOcclusionQueryivNV(0), + pGlGetOcclusionQueryuivNV(0), + // Blend + pGlBlendFuncSeparateEXT(0), pGlBlendFuncSeparate(0), + pGlBlendEquationEXT(0), pGlBlendEquation(0), pGlBlendEquationSeparateEXT(0), pGlBlendEquationSeparate(0), + // Indexed + pGlEnableIndexedEXT(0), pGlDisableIndexedEXT(0), + pGlColorMaskIndexedEXT(0), + pGlBlendFuncIndexedAMD(0), pGlBlendFunciARB(0), pGlBlendFuncSeparateIndexedAMD(0), pGlBlendFuncSeparateiARB(0), + pGlBlendEquationIndexedAMD(0), pGlBlendEquationiARB(0), pGlBlendEquationSeparateIndexedAMD(0), pGlBlendEquationSeparateiARB(0), + // DSA + pGlTextureStorage2D(0), pGlTextureStorage3D(0), pGlTextureSubImage2D(0), pGlNamedFramebufferTexture(0), + pGlTextureParameteri(0), pGlCreateTextures(0), pGlCreateFramebuffers(0), pGlBindTextures(0), pGlGenerateTextureMipmap(0), + // DSA with EXT or functions to simulate it + pGlTextureSubImage2DEXT(0), pGlTextureStorage2DEXT(0), pGlTexStorage2D(0), pGlTextureStorage3DEXT(0), + pGlTexStorage3D(0), pGlNamedFramebufferTextureEXT(0), pGlFramebufferTexture(0), pGlGenerateTextureMipmapEXT(0) +#if defined(GLX_SGI_swap_control) + ,pGlxSwapIntervalSGI(0) +#endif +#if defined(GLX_EXT_swap_control) + ,pGlxSwapIntervalEXT(0) +#endif +#if defined(WGL_EXT_swap_control) + ,pWglSwapIntervalEXT(0) +#endif +#if defined(GLX_MESA_swap_control) + ,pGlxSwapIntervalMESA(0) +#endif +#endif // _IRR_OPENGL_USE_EXTPOINTER_ +{ + for (u32 i=0; i(glGetString(GL_VERSION))); + 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 + os::Printer::log("OpenGL driver version is not 1.2 or better.", ELL_WARNING); + + { + const char* t = reinterpret_cast(glGetString(GL_EXTENSIONS)); + size_t len = 0; + c8 *str = 0; + if (t) + { + len = strlen(t); + str = new c8[len+1]; + } + c8* p = str; + + for (size_t i=0; i(t[i]); + + if (str[i] == ' ') + { + str[i] = 0; + for (u32 j=0; j(x)) +#elif defined(_IRR_COMPILE_WITH_SDL_DEVICE_) && !defined(_IRR_COMPILE_WITH_X11_DEVICE_) + #define IRR_OGL_LOAD_EXTENSION(x) SDL_GL_GetProcAddress(reinterpret_cast(x)) +#else + // Accessing the correct function is quite complex + // All libraries should support the ARB version, however + // since GLX 1.4 the non-ARB version is the official one + // So we have to check the runtime environment and + // choose the proper symbol + // In case you still have problems please enable the + // next line by uncommenting it + // #define _IRR_GETPROCADDRESS_WORKAROUND_ + + #ifndef _IRR_GETPROCADDRESS_WORKAROUND_ + __GLXextFuncPtr (*IRR_OGL_LOAD_EXTENSION_FUNCP)(const GLubyte*)=0; + #ifdef GLX_VERSION_1_4 + int major=0,minor=0; + if (glXGetCurrentDisplay()) + glXQueryVersion(glXGetCurrentDisplay(), &major, &minor); + if ((major>1) || (minor>3)) + IRR_OGL_LOAD_EXTENSION_FUNCP=glXGetProcAddress; + else + #endif + IRR_OGL_LOAD_EXTENSION_FUNCP=glXGetProcAddressARB; + #define IRR_OGL_LOAD_EXTENSION(X) IRR_OGL_LOAD_EXTENSION_FUNCP(reinterpret_cast(X)) + #else + #define IRR_OGL_LOAD_EXTENSION(X) glXGetProcAddressARB(reinterpret_cast(X)) + #endif // workaround +#endif // Windows, SDL, or Linux + + // get multitexturing function pointers + pGlActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) IRR_OGL_LOAD_EXTENSION("glActiveTextureARB"); + pGlClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC) IRR_OGL_LOAD_EXTENSION("glClientActiveTextureARB"); + + // get fragment and vertex program function pointers + pGlGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) IRR_OGL_LOAD_EXTENSION("glGenProgramsARB"); + pGlGenProgramsNV = (PFNGLGENPROGRAMSNVPROC) IRR_OGL_LOAD_EXTENSION("glGenProgramsNV"); + pGlBindProgramARB = (PFNGLBINDPROGRAMARBPROC) IRR_OGL_LOAD_EXTENSION("glBindProgramARB"); + pGlBindProgramNV = (PFNGLBINDPROGRAMNVPROC) IRR_OGL_LOAD_EXTENSION("glBindProgramNV"); + pGlProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) IRR_OGL_LOAD_EXTENSION("glProgramStringARB"); + pGlLoadProgramNV = (PFNGLLOADPROGRAMNVPROC) IRR_OGL_LOAD_EXTENSION("glLoadProgramNV"); + pGlDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) IRR_OGL_LOAD_EXTENSION("glDeleteProgramsARB"); + pGlDeleteProgramsNV = (PFNGLDELETEPROGRAMSNVPROC) IRR_OGL_LOAD_EXTENSION("glDeleteProgramsNV"); + pGlProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) IRR_OGL_LOAD_EXTENSION("glProgramLocalParameter4fvARB"); + pGlCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) IRR_OGL_LOAD_EXTENSION("glCreateShaderObjectARB"); + pGlCreateShader = (PFNGLCREATESHADERPROC) IRR_OGL_LOAD_EXTENSION("glCreateShader"); + pGlShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) IRR_OGL_LOAD_EXTENSION("glShaderSourceARB"); + pGlShaderSource = (PFNGLSHADERSOURCEPROC) IRR_OGL_LOAD_EXTENSION("glShaderSource"); + pGlCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) IRR_OGL_LOAD_EXTENSION("glCompileShaderARB"); + pGlCompileShader = (PFNGLCOMPILESHADERPROC) IRR_OGL_LOAD_EXTENSION("glCompileShader"); + pGlCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) IRR_OGL_LOAD_EXTENSION("glCreateProgramObjectARB"); + pGlCreateProgram = (PFNGLCREATEPROGRAMPROC) IRR_OGL_LOAD_EXTENSION("glCreateProgram"); + pGlAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) IRR_OGL_LOAD_EXTENSION("glAttachObjectARB"); + pGlAttachShader = (PFNGLATTACHSHADERPROC) IRR_OGL_LOAD_EXTENSION("glAttachShader"); + pGlLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) IRR_OGL_LOAD_EXTENSION("glLinkProgramARB"); + pGlLinkProgram = (PFNGLLINKPROGRAMPROC) IRR_OGL_LOAD_EXTENSION("glLinkProgram"); + pGlUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) IRR_OGL_LOAD_EXTENSION("glUseProgramObjectARB"); + pGlUseProgram = (PFNGLUSEPROGRAMPROC) IRR_OGL_LOAD_EXTENSION("glUseProgram"); + pGlDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) IRR_OGL_LOAD_EXTENSION("glDeleteObjectARB"); + pGlDeleteProgram = (PFNGLDELETEPROGRAMPROC) IRR_OGL_LOAD_EXTENSION("glDeleteProgram"); + pGlDeleteShader = (PFNGLDELETESHADERPROC) IRR_OGL_LOAD_EXTENSION("glDeleteShader"); + pGlGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC) IRR_OGL_LOAD_EXTENSION("glGetAttachedShaders"); + pGlGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC) IRR_OGL_LOAD_EXTENSION("glGetAttachedObjectsARB"); + pGlGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) IRR_OGL_LOAD_EXTENSION("glGetInfoLogARB"); + pGlGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) IRR_OGL_LOAD_EXTENSION("glGetShaderInfoLog"); + pGlGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) IRR_OGL_LOAD_EXTENSION("glGetProgramInfoLog"); + pGlGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) IRR_OGL_LOAD_EXTENSION("glGetObjectParameterivARB"); + pGlGetShaderiv = (PFNGLGETSHADERIVPROC) IRR_OGL_LOAD_EXTENSION("glGetShaderiv"); + pGlGetProgramiv = (PFNGLGETPROGRAMIVPROC) IRR_OGL_LOAD_EXTENSION("glGetProgramiv"); + pGlGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) IRR_OGL_LOAD_EXTENSION("glGetUniformLocationARB"); + pGlGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) IRR_OGL_LOAD_EXTENSION("glGetUniformLocation"); + pGlUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) IRR_OGL_LOAD_EXTENSION("glUniform1fvARB"); + pGlUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) IRR_OGL_LOAD_EXTENSION("glUniform2fvARB"); + pGlUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) IRR_OGL_LOAD_EXTENSION("glUniform3fvARB"); + pGlUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) IRR_OGL_LOAD_EXTENSION("glUniform4fvARB"); + pGlUniform1ivARB = (PFNGLUNIFORM1IVARBPROC) IRR_OGL_LOAD_EXTENSION("glUniform1ivARB"); + pGlUniform2ivARB = (PFNGLUNIFORM2IVARBPROC) IRR_OGL_LOAD_EXTENSION("glUniform2ivARB"); + pGlUniform3ivARB = (PFNGLUNIFORM3IVARBPROC) IRR_OGL_LOAD_EXTENSION("glUniform3ivARB"); + pGlUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) IRR_OGL_LOAD_EXTENSION("glUniform4ivARB"); + pGlUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC) IRR_OGL_LOAD_EXTENSION("glUniformMatrix2fvARB"); + pGlUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC) IRR_OGL_LOAD_EXTENSION("glUniformMatrix3fvARB"); + pGlUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC) IRR_OGL_LOAD_EXTENSION("glUniformMatrix4fvARB"); + pGlGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC) IRR_OGL_LOAD_EXTENSION("glGetActiveUniformARB"); + pGlGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) IRR_OGL_LOAD_EXTENSION("glGetActiveUniform"); + + // get point parameter extension + pGlPointParameterfARB = (PFNGLPOINTPARAMETERFARBPROC) IRR_OGL_LOAD_EXTENSION("glPointParameterfARB"); + pGlPointParameterfvARB = (PFNGLPOINTPARAMETERFVARBPROC) IRR_OGL_LOAD_EXTENSION("glPointParameterfvARB"); + + // get stencil extension + pGlStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC) IRR_OGL_LOAD_EXTENSION("glStencilFuncSeparate"); + pGlStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC) IRR_OGL_LOAD_EXTENSION("glStencilOpSeparate"); + pGlStencilFuncSeparateATI = (PFNGLSTENCILFUNCSEPARATEATIPROC) IRR_OGL_LOAD_EXTENSION("glStencilFuncSeparateATI"); + pGlStencilOpSeparateATI = (PFNGLSTENCILOPSEPARATEATIPROC) IRR_OGL_LOAD_EXTENSION("glStencilOpSeparateATI"); + + // compressed textures + pGlCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) IRR_OGL_LOAD_EXTENSION("glCompressedTexImage2D"); + pGlCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) IRR_OGL_LOAD_EXTENSION("glCompressedTexSubImage2D"); + + // ARB FrameBufferObjects + pGlBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) IRR_OGL_LOAD_EXTENSION("glBindFramebuffer"); + pGlDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) IRR_OGL_LOAD_EXTENSION("glDeleteFramebuffers"); + pGlGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) IRR_OGL_LOAD_EXTENSION("glGenFramebuffers"); + pGlCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) IRR_OGL_LOAD_EXTENSION("glCheckFramebufferStatus"); + pGlFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) IRR_OGL_LOAD_EXTENSION("glFramebufferTexture2D"); + pGlBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) IRR_OGL_LOAD_EXTENSION("glBindRenderbuffer"); + pGlDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) IRR_OGL_LOAD_EXTENSION("glDeleteRenderbuffers"); + pGlGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) IRR_OGL_LOAD_EXTENSION("glGenRenderbuffers"); + pGlRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) IRR_OGL_LOAD_EXTENSION("glRenderbufferStorage"); + pGlFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) IRR_OGL_LOAD_EXTENSION("glFramebufferRenderbuffer"); + pGlGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) IRR_OGL_LOAD_EXTENSION("glGenerateMipmap"); + + // EXT FrameBufferObjects + pGlBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) IRR_OGL_LOAD_EXTENSION("glBindFramebufferEXT"); + pGlDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC) IRR_OGL_LOAD_EXTENSION("glDeleteFramebuffersEXT"); + pGlGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) IRR_OGL_LOAD_EXTENSION("glGenFramebuffersEXT"); + pGlCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) IRR_OGL_LOAD_EXTENSION("glCheckFramebufferStatusEXT"); + pGlFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) IRR_OGL_LOAD_EXTENSION("glFramebufferTexture2DEXT"); + pGlBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC) IRR_OGL_LOAD_EXTENSION("glBindRenderbufferEXT"); + pGlDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC) IRR_OGL_LOAD_EXTENSION("glDeleteRenderbuffersEXT"); + pGlGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC) IRR_OGL_LOAD_EXTENSION("glGenRenderbuffersEXT"); + pGlRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC) IRR_OGL_LOAD_EXTENSION("glRenderbufferStorageEXT"); + pGlFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) IRR_OGL_LOAD_EXTENSION("glFramebufferRenderbufferEXT"); + pGlGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC) IRR_OGL_LOAD_EXTENSION("glGenerateMipmapEXT"); + pGlDrawBuffersARB = (PFNGLDRAWBUFFERSARBPROC) IRR_OGL_LOAD_EXTENSION("glDrawBuffersARB"); + pGlDrawBuffersATI = (PFNGLDRAWBUFFERSATIPROC) IRR_OGL_LOAD_EXTENSION("glDrawBuffersATI"); + + // get vertex buffer extension + pGlGenBuffersARB = (PFNGLGENBUFFERSARBPROC) IRR_OGL_LOAD_EXTENSION("glGenBuffersARB"); + pGlBindBufferARB = (PFNGLBINDBUFFERARBPROC) IRR_OGL_LOAD_EXTENSION("glBindBufferARB"); + pGlBufferDataARB = (PFNGLBUFFERDATAARBPROC) IRR_OGL_LOAD_EXTENSION("glBufferDataARB"); + pGlDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) IRR_OGL_LOAD_EXTENSION("glDeleteBuffersARB"); + pGlBufferSubDataARB= (PFNGLBUFFERSUBDATAARBPROC) IRR_OGL_LOAD_EXTENSION("glBufferSubDataARB"); + pGlGetBufferSubDataARB= (PFNGLGETBUFFERSUBDATAARBPROC)IRR_OGL_LOAD_EXTENSION("glGetBufferSubDataARB"); + pGlMapBufferARB= (PFNGLMAPBUFFERARBPROC) IRR_OGL_LOAD_EXTENSION("glMapBufferARB"); + pGlUnmapBufferARB= (PFNGLUNMAPBUFFERARBPROC) IRR_OGL_LOAD_EXTENSION("glUnmapBufferARB"); + pGlIsBufferARB= (PFNGLISBUFFERARBPROC) IRR_OGL_LOAD_EXTENSION("glIsBufferARB"); + pGlGetBufferParameterivARB= (PFNGLGETBUFFERPARAMETERIVARBPROC) IRR_OGL_LOAD_EXTENSION("glGetBufferParameterivARB"); + pGlGetBufferPointervARB= (PFNGLGETBUFFERPOINTERVARBPROC) IRR_OGL_LOAD_EXTENSION("glGetBufferPointervARB"); + pGlProvokingVertexARB= (PFNGLPROVOKINGVERTEXPROC) IRR_OGL_LOAD_EXTENSION("glProvokingVertex"); + pGlProvokingVertexEXT= (PFNGLPROVOKINGVERTEXEXTPROC) IRR_OGL_LOAD_EXTENSION("glProvokingVertexEXT"); + pGlProgramParameteriARB= (PFNGLPROGRAMPARAMETERIARBPROC) IRR_OGL_LOAD_EXTENSION("glProgramParameteriARB"); + pGlProgramParameteriEXT= (PFNGLPROGRAMPARAMETERIEXTPROC) IRR_OGL_LOAD_EXTENSION("glProgramParameteriEXT"); + + // occlusion query + pGlGenQueriesARB = (PFNGLGENQUERIESARBPROC) IRR_OGL_LOAD_EXTENSION("glGenQueriesARB"); + pGlDeleteQueriesARB = (PFNGLDELETEQUERIESARBPROC) IRR_OGL_LOAD_EXTENSION("glDeleteQueriesARB"); + pGlIsQueryARB = (PFNGLISQUERYARBPROC) IRR_OGL_LOAD_EXTENSION("glIsQueryARB"); + pGlBeginQueryARB = (PFNGLBEGINQUERYARBPROC) IRR_OGL_LOAD_EXTENSION("glBeginQueryARB"); + pGlEndQueryARB = (PFNGLENDQUERYARBPROC) IRR_OGL_LOAD_EXTENSION("glEndQueryARB"); + pGlGetQueryivARB = (PFNGLGETQUERYIVARBPROC) IRR_OGL_LOAD_EXTENSION("glGetQueryivARB"); + pGlGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC) IRR_OGL_LOAD_EXTENSION("glGetQueryObjectivARB"); + pGlGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC) IRR_OGL_LOAD_EXTENSION("glGetQueryObjectuivARB"); + pGlGenOcclusionQueriesNV = (PFNGLGENOCCLUSIONQUERIESNVPROC) IRR_OGL_LOAD_EXTENSION("glGenOcclusionQueriesNV"); + pGlDeleteOcclusionQueriesNV = (PFNGLDELETEOCCLUSIONQUERIESNVPROC) IRR_OGL_LOAD_EXTENSION("glDeleteOcclusionQueriesNV"); + pGlIsOcclusionQueryNV = (PFNGLISOCCLUSIONQUERYNVPROC) IRR_OGL_LOAD_EXTENSION("glIsOcclusionQueryNV"); + pGlBeginOcclusionQueryNV = (PFNGLBEGINOCCLUSIONQUERYNVPROC) IRR_OGL_LOAD_EXTENSION("glBeginOcclusionQueryNV"); + pGlEndOcclusionQueryNV = (PFNGLENDOCCLUSIONQUERYNVPROC) IRR_OGL_LOAD_EXTENSION("glEndOcclusionQueryNV"); + pGlGetOcclusionQueryivNV = (PFNGLGETOCCLUSIONQUERYIVNVPROC) IRR_OGL_LOAD_EXTENSION("glGetOcclusionQueryivNV"); + pGlGetOcclusionQueryuivNV = (PFNGLGETOCCLUSIONQUERYUIVNVPROC) IRR_OGL_LOAD_EXTENSION("glGetOcclusionQueryuivNV"); + + // blend + pGlBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC) IRR_OGL_LOAD_EXTENSION("glBlendFuncSeparateEXT"); + pGlBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC) IRR_OGL_LOAD_EXTENSION("glBlendFuncSeparate"); + pGlBlendEquationEXT = (PFNGLBLENDEQUATIONEXTPROC) IRR_OGL_LOAD_EXTENSION("glBlendEquationEXT"); + pGlBlendEquation = (PFNGLBLENDEQUATIONPROC) IRR_OGL_LOAD_EXTENSION("glBlendEquation"); + pGlBlendEquationSeparateEXT = (PFNGLBLENDEQUATIONSEPARATEEXTPROC) IRR_OGL_LOAD_EXTENSION("glBlendEquationSeparateEXT"); + pGlBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC) IRR_OGL_LOAD_EXTENSION("glBlendEquationSeparate"); + + // indexed + pGlEnableIndexedEXT = (PFNGLENABLEINDEXEDEXTPROC) IRR_OGL_LOAD_EXTENSION("glEnableIndexedEXT"); + pGlDisableIndexedEXT = (PFNGLDISABLEINDEXEDEXTPROC) IRR_OGL_LOAD_EXTENSION("glDisableIndexedEXT"); + pGlColorMaskIndexedEXT = (PFNGLCOLORMASKINDEXEDEXTPROC) IRR_OGL_LOAD_EXTENSION("glColorMaskIndexedEXT"); + pGlBlendFuncIndexedAMD = (PFNGLBLENDFUNCINDEXEDAMDPROC) IRR_OGL_LOAD_EXTENSION("glBlendFuncIndexedAMD"); + pGlBlendFunciARB = (PFNGLBLENDFUNCIPROC) IRR_OGL_LOAD_EXTENSION("glBlendFunciARB"); + pGlBlendFuncSeparateIndexedAMD = (PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC) IRR_OGL_LOAD_EXTENSION("glBlendFuncSeparateIndexedAMD"); + pGlBlendFuncSeparateiARB = (PFNGLBLENDFUNCSEPARATEIPROC) IRR_OGL_LOAD_EXTENSION("glBlendFuncSeparateiARB"); + pGlBlendEquationIndexedAMD = (PFNGLBLENDEQUATIONINDEXEDAMDPROC) IRR_OGL_LOAD_EXTENSION("glBlendEquationIndexedAMD"); + pGlBlendEquationiARB = (PFNGLBLENDEQUATIONIPROC) IRR_OGL_LOAD_EXTENSION("glBlendEquationiARB"); + pGlBlendEquationSeparateIndexedAMD = (PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC) IRR_OGL_LOAD_EXTENSION("glBlendEquationSeparateIndexedAMD"); + pGlBlendEquationSeparateiARB = (PFNGLBLENDEQUATIONSEPARATEIPROC) IRR_OGL_LOAD_EXTENSION("glBlendEquationSeparateiARB"); + + pGlTextureSubImage2D = (PFNGLTEXTURESUBIMAGE2DPROC)IRR_OGL_LOAD_EXTENSION("glTextureSubImage2D"); + pGlTextureStorage2D = (PFNGLTEXTURESTORAGE2DPROC) IRR_OGL_LOAD_EXTENSION("glTextureStorage2D"); + pGlTextureStorage3D = (PFNGLTEXTURESTORAGE3DPROC) IRR_OGL_LOAD_EXTENSION("glTextureStorage3D"); + pGlNamedFramebufferTexture = (PFNGLNAMEDFRAMEBUFFERTEXTUREPROC) IRR_OGL_LOAD_EXTENSION("glNamedFramebufferTexture"); + pGlTextureParameteri = (PFNGLTEXTUREPARAMETERIPROC) IRR_OGL_LOAD_EXTENSION("glTextureParameteri"); + pGlCreateTextures = (PFNGLCREATETEXTURESPROC) IRR_OGL_LOAD_EXTENSION("glCreateTextures"); + pGlCreateFramebuffers = (PFNGLCREATEFRAMEBUFFERSPROC) IRR_OGL_LOAD_EXTENSION("glCreateFramebuffers"); + pGlBindTextures = (PFNGLBINDTEXTURESPROC) IRR_OGL_LOAD_EXTENSION("glBindTextures"); + pGlGenerateTextureMipmap = (PFNGLGENERATETEXTUREMIPMAPPROC) IRR_OGL_LOAD_EXTENSION("glGenerateTextureMipmap"); + //============================== + pGlTextureSubImage2DEXT = (PFNGLTEXTURESUBIMAGE2DEXTPROC)IRR_OGL_LOAD_EXTENSION("glTextureSubImage2DEXT"); + pGlTextureStorage2DEXT = (PFNGLTEXTURESTORAGE2DEXTPROC)IRR_OGL_LOAD_EXTENSION("glTextureStorage2DEXT"); + pGlTexStorage2D = (PFNGLTEXSTORAGE2DPROC)IRR_OGL_LOAD_EXTENSION("glTexStorage2D"); + pGlTextureStorage3DEXT = (PFNGLTEXTURESTORAGE3DEXTPROC)IRR_OGL_LOAD_EXTENSION("glTextureStorage3DEXT"); + pGlTexStorage3D = (PFNGLTEXSTORAGE3DPROC)IRR_OGL_LOAD_EXTENSION("glTexStorage3D"); + pGlNamedFramebufferTextureEXT = (PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC)IRR_OGL_LOAD_EXTENSION("glNamedFramebufferTextureEXT"); + pGlFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)IRR_OGL_LOAD_EXTENSION("glFramebufferTexture"); + pGlActiveTexture = (PFNGLACTIVETEXTUREPROC)IRR_OGL_LOAD_EXTENSION("glActiveTexture"); + pGlGenerateTextureMipmapEXT = (PFNGLGENERATETEXTUREMIPMAPEXTPROC) IRR_OGL_LOAD_EXTENSION("glGenerateTextureMipmapEXT"); + + // get vsync extension + #if defined(WGL_EXT_swap_control) && !defined(_IRR_COMPILE_WITH_SDL_DEVICE_) + pWglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) IRR_OGL_LOAD_EXTENSION("wglSwapIntervalEXT"); + #endif + #if defined(GLX_SGI_swap_control) && !defined(_IRR_COMPILE_WITH_SDL_DEVICE_) + pGlxSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)IRR_OGL_LOAD_EXTENSION("glXSwapIntervalSGI"); + #endif + #if defined(GLX_EXT_swap_control) && !defined(_IRR_COMPILE_WITH_SDL_DEVICE_) + pGlxSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)IRR_OGL_LOAD_EXTENSION("glXSwapIntervalEXT"); + #endif + #if defined(GLX_MESA_swap_control) && !defined(_IRR_COMPILE_WITH_SDL_DEVICE_) + pGlxSwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)IRR_OGL_LOAD_EXTENSION("glXSwapIntervalMESA"); + #endif +#endif // use extension pointer + + GLint num=0; + // set some properties +#if defined(GL_ARB_multitexture) || defined(GL_VERSION_1_3) + if (Version>102 || FeatureAvailable[IRR_ARB_multitexture]) + { +#if defined(GL_MAX_TEXTURE_UNITS) + glGetIntegerv(GL_MAX_TEXTURE_UNITS, &num); +#elif defined(GL_MAX_TEXTURE_UNITS_ARB) + glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &num); +#endif + Feature.MaxTextureUnits=static_cast(num); // MULTITEXTURING (fixed function pipeline texture units) + } +#endif +#if defined(GL_ARB_vertex_shader) || defined(GL_VERSION_2_0) + if (Version>=200 || FeatureAvailable[IRR_ARB_vertex_shader]) + { + num=0; +#if defined(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &num); +#elif defined(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB) + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, &num); +#endif + Feature.MaxTextureUnits =core::max_(Feature.MaxTextureUnits,static_cast(num)); + } +#endif + glGetIntegerv(GL_MAX_LIGHTS, &num); + MaxLights=static_cast(num); +#ifdef GL_EXT_texture_filter_anisotropic + if (FeatureAvailable[IRR_EXT_texture_filter_anisotropic]) + { + 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, &num); + MaxIndices=num; + } +#endif + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &num); + MaxTextureSize=static_cast(num); + if (queryFeature(EVDF_GEOMETRY_SHADER)) + { +#if defined(GL_ARB_geometry_shader4) || defined(GL_EXT_geometry_shader4) || defined(GL_NV_geometry_shader4) + glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT, &num); + MaxGeometryVerticesOut=static_cast(num); +#elif defined(GL_NV_geometry_program4) + extGlGetProgramiv(GEOMETRY_PROGRAM_NV, GL_MAX_PROGRAM_OUTPUT_VERTICES_NV, &num); + MaxGeometryVerticesOut=static_cast(num); +#endif + } +#ifdef GL_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); +#ifdef GL_ARB_draw_buffers + if (FeatureAvailable[IRR_ARB_draw_buffers]) + { + glGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &num); + Feature.MultipleRenderTarget = static_cast(num); + } +#endif +#if defined(GL_ATI_draw_buffers) +#ifdef GL_ARB_draw_buffers + else +#endif + if (FeatureAvailable[IRR_ATI_draw_buffers]) + { + glGetIntegerv(GL_MAX_DRAW_BUFFERS_ATI, &num); + Feature.MultipleRenderTarget = static_cast(num); + } +#endif +#ifdef GL_ARB_framebuffer_object + if (FeatureAvailable[IRR_ARB_framebuffer_object]) + { + glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &num); + Feature.ColorAttachment = static_cast(num); + } +#endif +#if defined(GL_EXT_framebuffer_object) +#ifdef GL_ARB_framebuffer_object + else +#endif + if (FeatureAvailable[IRR_EXT_framebuffer_object]) + { + glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &num); + Feature.ColorAttachment = static_cast(num); + } +#endif + + glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, DimAliasedLine); + glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, DimAliasedPoint); + glGetFloatv(GL_SMOOTH_LINE_WIDTH_RANGE, DimSmoothedLine); + glGetFloatv(GL_SMOOTH_POINT_SIZE_RANGE, DimSmoothedPoint); +#if defined(GL_ARB_shading_language_100) || defined (GL_VERSION_2_0) + if (FeatureAvailable[IRR_ARB_shading_language_100] || Version>=200) + { + glGetError(); // clean error buffer +#ifdef GL_SHADING_LANGUAGE_VERSION + const GLubyte* shaderVersion = glGetString(GL_SHADING_LANGUAGE_VERSION); +#else + const GLubyte* shaderVersion = glGetString(GL_SHADING_LANGUAGE_VERSION_ARB); +#endif + if (glGetError() == GL_INVALID_ENUM) + ShaderLanguageVersion = 100; + else + { + const f32 sl_ver = core::fast_atof(reinterpret_cast(shaderVersion)); + ShaderLanguageVersion = static_cast(core::floor32(sl_ver)*100+core::round32(core::fract(sl_ver)*10.0f)); + } + } +#endif + +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (!pGlActiveTextureARB || !pGlClientActiveTextureARB) + { + Feature.MaxTextureUnits = 1; + os::Printer::log("Failed to load OpenGL's multitexture extension, proceeding without.", ELL_WARNING); + } + else +#endif + Feature.MaxTextureUnits = core::min_(Feature.MaxTextureUnits, static_cast(MATERIAL_MAX_TEXTURES)); + Feature.MaxTextureUnits = core::min_(Feature.MaxTextureUnits, static_cast(MATERIAL_MAX_TEXTURES_USED)); + +#ifdef GL_ARB_occlusion_query + if (FeatureAvailable[IRR_ARB_occlusion_query]) + { + extGlGetQueryiv(GL_SAMPLES_PASSED_ARB,GL_QUERY_COUNTER_BITS_ARB, + &num); + OcclusionQuerySupport=(num>0); + } + else +#endif +#ifdef GL_NV_occlusion_query + if (FeatureAvailable[IRR_NV_occlusion_query]) + { + glGetIntegerv(GL_PIXEL_COUNTER_BITS_NV, &num); + OcclusionQuerySupport=(num>0); + } + else +#endif + OcclusionQuerySupport=false; + + Feature.BlendOperation = (Version >= 140) || + FeatureAvailable[IRR_EXT_blend_minmax] || + FeatureAvailable[IRR_EXT_blend_subtract] || + FeatureAvailable[IRR_EXT_blend_logic_op]; + +#ifdef _DEBUG + if (FeatureAvailable[IRR_NVX_gpu_memory_info]) + { + // undocumented flags, so use the RAW values + GLint val; + glGetIntegerv(0x9047, &val); + os::Printer::log("Dedicated video memory (kB)", core::stringc(val)); + glGetIntegerv(0x9048, &val); + os::Printer::log("Total video memory (kB)", core::stringc(val)); + glGetIntegerv(0x9049, &val); + os::Printer::log("Available video memory (kB)", core::stringc(val)); + } +#ifdef GL_ATI_meminfo + if (FeatureAvailable[IRR_ATI_meminfo]) + { + GLint val[4]; + glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, val); + os::Printer::log("Free texture memory (kB)", core::stringc(val[0])); + glGetIntegerv(GL_VBO_FREE_MEMORY_ATI, val); + os::Printer::log("Free VBO memory (kB)", core::stringc(val[0])); + glGetIntegerv(GL_RENDERBUFFER_FREE_MEMORY_ATI, val); + os::Printer::log("Free render buffer memory (kB)", core::stringc(val[0])); + } +#endif + + if (queryFeature(EVDF_TEXTURE_CUBEMAP_SEAMLESS)) + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + +#endif +} + +const COpenGLCoreFeature& COpenGLExtensionHandler::getFeature() const +{ + return Feature; +} + +bool COpenGLExtensionHandler::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const +{ + switch (feature) + { + case EVDF_RENDER_TO_TARGET: + return true; + case EVDF_HARDWARE_TL: + return true; // we cannot tell other things + case EVDF_MULTITEXTURE: + return Feature.MaxTextureUnits > 1; + case EVDF_BILINEAR_FILTER: + return true; + case EVDF_MIP_MAP: + return true; + case EVDF_MIP_MAP_AUTO_UPDATE: + return FeatureAvailable[IRR_SGIS_generate_mipmap] || FeatureAvailable[IRR_EXT_framebuffer_object] || FeatureAvailable[IRR_ARB_framebuffer_object]; + case EVDF_STENCIL_BUFFER: + return StencilBuffer; + case EVDF_VERTEX_SHADER_1_1: + case EVDF_ARB_VERTEX_PROGRAM_1: + return FeatureAvailable[IRR_ARB_vertex_program] || FeatureAvailable[IRR_NV_vertex_program1_1]; + case EVDF_PIXEL_SHADER_1_1: + case EVDF_PIXEL_SHADER_1_2: + case EVDF_ARB_FRAGMENT_PROGRAM_1: + return FeatureAvailable[IRR_ARB_fragment_program] || FeatureAvailable[IRR_NV_fragment_program]; + case EVDF_PIXEL_SHADER_2_0: + case EVDF_VERTEX_SHADER_2_0: + case EVDF_ARB_GLSL: + return (FeatureAvailable[IRR_ARB_shading_language_100]||Version>=200); + case EVDF_TEXTURE_NSQUARE: + return true; // non-square is always supported + case EVDF_TEXTURE_NPOT: + // Some ATI cards seem to have only SW support in OpenGL 2.0 + // drivers if the extension is not exposed, so we skip this + // extra test for now! + // return (FeatureAvailable[IRR_ARB_texture_non_power_of_two]||Version>=200); + return (FeatureAvailable[IRR_ARB_texture_non_power_of_two]); + case EVDF_FRAMEBUFFER_OBJECT: + return FeatureAvailable[IRR_EXT_framebuffer_object] || FeatureAvailable[IRR_ARB_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]; + case EVDF_GEOMETRY_SHADER: + return FeatureAvailable[IRR_ARB_geometry_shader4] || FeatureAvailable[IRR_EXT_geometry_shader4] || FeatureAvailable[IRR_NV_geometry_program4] || FeatureAvailable[IRR_NV_geometry_shader4]; + case EVDF_MULTIPLE_RENDER_TARGETS: + return FeatureAvailable[IRR_ARB_draw_buffers] || FeatureAvailable[IRR_ATI_draw_buffers]; + case EVDF_MRT_BLEND: + case EVDF_MRT_COLOR_MASK: + return FeatureAvailable[IRR_EXT_draw_buffers2]; + case EVDF_MRT_BLEND_FUNC: + return FeatureAvailable[IRR_ARB_draw_buffers_blend] || FeatureAvailable[IRR_AMD_draw_buffers_blend]; + case EVDF_OCCLUSION_QUERY: + return FeatureAvailable[IRR_ARB_occlusion_query] && OcclusionQuerySupport; + case EVDF_POLYGON_OFFSET: + // both features supported with OpenGL 1.1 + return Version>=110; + case EVDF_BLEND_OPERATIONS: + return Feature.BlendOperation; + case EVDF_BLEND_SEPARATE: + return (Version>=140) || FeatureAvailable[IRR_EXT_blend_func_separate]; + case EVDF_TEXTURE_MATRIX: + return true; + case EVDF_TEXTURE_COMPRESSED_DXT: + return FeatureAvailable[IRR_EXT_texture_compression_s3tc]; + case EVDF_TEXTURE_CUBEMAP: + return (Version >= 130) || FeatureAvailable[IRR_ARB_texture_cube_map] || FeatureAvailable[IRR_EXT_texture_cube_map]; + case EVDF_TEXTURE_CUBEMAP_SEAMLESS: + return FeatureAvailable[IRR_ARB_seamless_cube_map]; + case EVDF_DEPTH_CLAMP: + return FeatureAvailable[IRR_NV_depth_clamp] || FeatureAvailable[IRR_ARB_depth_clamp]; + + default: + return false; + }; +} + + +} +} + +#endif diff --git a/source/Irrlicht/COpenGLExtensionHandler.h b/source/Irrlicht/COpenGLExtensionHandler.h new file mode 100644 index 00000000..efe30234 --- /dev/null +++ b/source/Irrlicht/COpenGLExtensionHandler.h @@ -0,0 +1,3124 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __C_OPEN_GL_FEATURE_MAP_H_INCLUDED__ +#define __C_OPEN_GL_FEATURE_MAP_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#include "EDriverFeatures.h" +#include "irrTypes.h" +#include "os.h" + +#include "COpenGLCommon.h" + +#include "COpenGLCoreFeature.h" + +namespace irr +{ +namespace video +{ + +static const char* const OpenGLFeatureStrings[] = { + "GL_3DFX_multisample", + "GL_3DFX_tbuffer", + "GL_3DFX_texture_compression_FXT1", + "GL_AMD_blend_minmax_factor", + "GL_AMD_conservative_depth", + "GL_AMD_debug_output", + "GL_AMD_depth_clamp_separate", + "GL_AMD_draw_buffers_blend", + "GL_AMD_interleaved_elements", + "GL_AMD_multi_draw_indirect", + "GL_AMD_name_gen_delete", + "GL_AMD_performance_monitor", + "GL_AMD_pinned_memory", + "GL_AMD_query_buffer_object", + "GL_AMD_sample_positions", + "GL_AMD_seamless_cubemap_per_texture", + "GL_AMD_shader_atomic_counter_ops", + "GL_AMD_shader_stencil_export", + "GL_AMD_shader_trinary_minmax", + "GL_AMD_sparse_texture", + "GL_AMD_stencil_operation_extended", + "GL_AMD_texture_texture4", + "GL_AMD_transform_feedback3_lines_triangles", + "GL_AMD_vertex_shader_layer", + "GL_AMD_vertex_shader_tessellator", + "GL_AMD_vertex_shader_viewport_index", + "GL_APPLE_aux_depth_stencil", + "GL_APPLE_client_storage", + "GL_APPLE_element_array", + "GL_APPLE_fence", + "GL_APPLE_float_pixels", + "GL_APPLE_flush_buffer_range", + "GL_APPLE_object_purgeable", + "GL_APPLE_rgb_422", + "GL_APPLE_row_bytes", + "GL_APPLE_specular_vector", + "GL_APPLE_texture_range", + "GL_APPLE_transform_hint", + "GL_APPLE_vertex_array_object", + "GL_APPLE_vertex_array_range", + "GL_APPLE_vertex_program_evaluators", + "GL_APPLE_ycbcr_422", + "GL_ARB_arrays_of_arrays", + "GL_ARB_base_instance", + "GL_ARB_bindless_texture", + "GL_ARB_blend_func_extended", + "GL_ARB_buffer_storage", + "GL_ARB_cl_event", + "GL_ARB_clear_buffer_object", + "GL_ARB_clear_texture", + "GL_ARB_color_buffer_float", + "GL_ARB_compatibility", + "GL_ARB_compressed_texture_pixel_storage", + "GL_ARB_compute_shader", + "GL_ARB_compute_variable_group_size", + "GL_ARB_conservative_depth", + "GL_ARB_copy_buffer", + "GL_ARB_copy_image", + "GL_ARB_debug_output", + "GL_ARB_depth_buffer_float", + "GL_ARB_depth_clamp", + "GL_ARB_depth_texture", + "GL_ARB_draw_buffers", + "GL_ARB_draw_buffers_blend", + "GL_ARB_draw_elements_base_vertex", + "GL_ARB_draw_indirect", + "GL_ARB_draw_instanced", + "GL_ARB_ES2_compatibility", + "GL_ARB_ES3_compatibility", + "GL_ARB_enhanced_layouts", + "GL_ARB_explicit_attrib_location", + "GL_ARB_explicit_uniform_location", + "GL_ARB_fragment_coord_conventions", + "GL_ARB_fragment_layer_viewport", + "GL_ARB_fragment_program", + "GL_ARB_fragment_program_shadow", + "GL_ARB_fragment_shader", + "GL_ARB_framebuffer_no_attachments", + "GL_ARB_framebuffer_object", + "GL_ARB_framebuffer_sRGB", + "GL_ARB_geometry_shader4", + "GL_ARB_get_program_binary", + "GL_ARB_gpu_shader5", + "GL_ARB_gpu_shader_fp64", + "GL_ARB_half_float_pixel", + "GL_ARB_half_float_vertex", + "GL_ARB_imaging", + "GL_ARB_indirect_parameters", + "GL_ARB_instanced_arrays", + "GL_ARB_internalformat_query", + "GL_ARB_internalformat_query2", + "GL_ARB_invalidate_subdata", + "GL_ARB_map_buffer_alignment", + "GL_ARB_map_buffer_range", + "GL_ARB_matrix_palette", + "GL_ARB_multi_bind", + "GL_ARB_multi_draw_indirect", + "GL_ARB_multisample", + "GL_ARB_multitexture", + "GL_ARB_occlusion_query", + "GL_ARB_occlusion_query2", + "GL_ARB_pixel_buffer_object", + "GL_ARB_point_parameters", + "GL_ARB_point_sprite", + "GL_ARB_program_interface_query", + "GL_ARB_provoking_vertex", + "GL_ARB_query_buffer_object", + "GL_ARB_robust_buffer_access_behavior", + "GL_ARB_robustness", + "GL_ARB_robustness_isolation", + "GL_ARB_sample_shading", + "GL_ARB_sampler_objects", + "GL_ARB_seamless_cube_map", + "GL_ARB_seamless_cubemap_per_texture", + "GL_ARB_separate_shader_objects", + "GL_ARB_shader_atomic_counters", + "GL_ARB_shader_bit_encoding", + "GL_ARB_shader_draw_parameters", + "GL_ARB_shader_group_vote", + "GL_ARB_shader_image_load_store", + "GL_ARB_shader_image_size", + "GL_ARB_shader_objects", + "GL_ARB_shader_precision", + "GL_ARB_shader_stencil_export", + "GL_ARB_shader_storage_buffer_object", + "GL_ARB_shader_subroutine", + "GL_ARB_shader_texture_lod", + "GL_ARB_shading_language_100", + "GL_ARB_shading_language_420pack", + "GL_ARB_shading_language_include", + "GL_ARB_shading_language_packing", + "GL_ARB_shadow", + "GL_ARB_shadow_ambient", + "GL_ARB_sparse_texture", + "GL_ARB_stencil_texturing", + "GL_ARB_sync", + "GL_ARB_tessellation_shader", + "GL_ARB_texture_border_clamp", + "GL_ARB_texture_buffer_object", + "GL_ARB_texture_buffer_object_rgb32", + "GL_ARB_texture_buffer_range", + "GL_ARB_texture_compression", + "GL_ARB_texture_compression_bptc", + "GL_ARB_texture_compression_rgtc", + "GL_ARB_texture_cube_map", + "GL_ARB_texture_cube_map_array", + "GL_ARB_texture_env_add", + "GL_ARB_texture_env_combine", + "GL_ARB_texture_env_crossbar", + "GL_ARB_texture_env_dot3", + "GL_ARB_texture_float", + "GL_ARB_texture_gather", + "GL_ARB_texture_mirror_clamp_to_edge", + "GL_ARB_texture_mirrored_repeat", + "GL_ARB_texture_multisample", + "GL_ARB_texture_non_power_of_two", + "GL_ARB_texture_query_levels", + "GL_ARB_texture_query_lod", + "GL_ARB_texture_rectangle", + "GL_ARB_texture_rg", + "GL_ARB_texture_rgb10_a2ui", + "GL_ARB_texture_stencil8", + "GL_ARB_texture_storage", + "GL_ARB_texture_storage_multisample", + "GL_ARB_texture_swizzle", + "GL_ARB_texture_view", + "GL_ARB_timer_query", + "GL_ARB_transform_feedback2", + "GL_ARB_transform_feedback3", + "GL_ARB_transform_feedback_instanced", + "GL_ARB_transpose_matrix", + "GL_ARB_uniform_buffer_object", + "GL_ARB_vertex_array_bgra", + "GL_ARB_vertex_array_object", + "GL_ARB_vertex_attrib_64bit", + "GL_ARB_vertex_attrib_binding", + "GL_ARB_vertex_blend", + "GL_ARB_vertex_buffer_object", + "GL_ARB_vertex_program", + "GL_ARB_vertex_shader", + "GL_ARB_vertex_type_10f_11f_11f_rev", + "GL_ARB_vertex_type_2_10_10_10_rev", + "GL_ARB_viewport_array", + "GL_ARB_window_pos", + "GL_ATI_draw_buffers", + "GL_ATI_element_array", + "GL_ATI_envmap_bumpmap", + "GL_ATI_fragment_shader", + "GL_ATI_map_object_buffer", + "GL_ATI_meminfo", + "GL_ATI_pixel_format_float", + "GL_ATI_pn_triangles", + "GL_ATI_separate_stencil", + "GL_ATI_text_fragment_shader", + "GL_ATI_texture_env_combine3", + "GL_ATI_texture_float", + "GL_ATI_texture_mirror_once", + "GL_ATI_vertex_array_object", + "GL_ATI_vertex_attrib_array_object", + "GL_ATI_vertex_streams", + "GL_EXT_422_pixels", + "GL_EXT_abgr", + "GL_EXT_bgra", + "GL_EXT_bindable_uniform", + "GL_EXT_blend_color", + "GL_EXT_blend_equation_separate", + "GL_EXT_blend_func_separate", + "GL_EXT_blend_logic_op", + "GL_EXT_blend_minmax", + "GL_EXT_blend_subtract", + "GL_EXT_clip_volume_hint", + "GL_EXT_cmyka", + "GL_EXT_color_subtable", + "GL_EXT_compiled_vertex_array", + "GL_EXT_convolution", + "GL_EXT_coordinate_frame", + "GL_EXT_copy_texture", + "GL_EXT_cull_vertex", + "GL_EXT_debug_label", + "GL_EXT_debug_marker", + "GL_EXT_depth_bounds_test", + "GL_EXT_direct_state_access", + "GL_EXT_draw_buffers2", + "GL_EXT_draw_instanced", + "GL_EXT_draw_range_elements", + "GL_EXT_fog_coord", + "GL_EXT_framebuffer_blit", + "GL_EXT_framebuffer_multisample", + "GL_EXT_framebuffer_multisample_blit_scaled", + "GL_EXT_framebuffer_object", + "GL_EXT_framebuffer_sRGB", + "GL_EXT_geometry_shader4", + "GL_EXT_gpu_program_parameters", + "GL_EXT_gpu_shader4", + "GL_EXT_histogram", + "GL_EXT_index_array_formats", + "GL_EXT_index_func", + "GL_EXT_index_material", + "GL_EXT_index_texture", + "GL_EXT_light_texture", + "GL_EXT_misc_attribute", + "GL_EXT_multi_draw_arrays", + "GL_EXT_multisample", + "GL_EXT_packed_depth_stencil", + "GL_EXT_packed_float", + "GL_EXT_packed_pixels", + "GL_EXT_paletted_texture", + "GL_EXT_pixel_buffer_object", + "GL_EXT_pixel_transform", + "GL_EXT_pixel_transform_color_table", + "GL_EXT_point_parameters", + "GL_EXT_polygon_offset", + "GL_EXT_provoking_vertex", + "GL_EXT_rescale_normal", + "GL_EXT_secondary_color", + "GL_EXT_separate_shader_objects", + "GL_EXT_separate_specular_color", + "GL_EXT_shader_image_load_store", + "GL_EXT_shader_integer_mix", + "GL_EXT_shadow_funcs", + "GL_EXT_shared_texture_palette", + "GL_EXT_stencil_clear_tag", + "GL_EXT_stencil_two_side", + "GL_EXT_stencil_wrap", + "GL_EXT_subtexture", + "GL_EXT_texture", + "GL_EXT_texture3D", + "GL_EXT_texture_array", + "GL_EXT_texture_buffer_object", + "GL_EXT_texture_compression_latc", + "GL_EXT_texture_compression_rgtc", + "GL_EXT_texture_compression_s3tc", + "GL_EXT_texture_cube_map", + "GL_EXT_texture_env_add", + "GL_EXT_texture_env_combine", + "GL_EXT_texture_env_dot3", + "GL_EXT_texture_filter_anisotropic", + "GL_EXT_texture_integer", + "GL_EXT_texture_lod_bias", + "GL_EXT_texture_mirror_clamp", + "GL_EXT_texture_object", + "GL_EXT_texture_perturb_normal", + "GL_EXT_texture_shared_exponent", + "GL_EXT_texture_snorm", + "GL_EXT_texture_sRGB", + "GL_EXT_texture_sRGB_decode", + "GL_EXT_texture_swizzle", + "GL_EXT_timer_query", + "GL_EXT_transform_feedback", + "GL_EXT_vertex_array", + "GL_EXT_vertex_array_bgra", + "GL_EXT_vertex_attrib_64bit", + "GL_EXT_vertex_shader", + "GL_EXT_vertex_weighting", + "GL_EXT_x11_sync_object", + "GL_GREMEDY_frame_terminator", + "GL_GREMEDY_string_marker", + "GL_HP_convolution_border_modes", + "GL_HP_image_transform", + "GL_HP_occlusion_test", + "GL_HP_texture_lighting", + "GL_IBM_cull_vertex", + "GL_IBM_multimode_draw_arrays", + "GL_IBM_rasterpos_clip", + "GL_IBM_static_data", + "GL_IBM_texture_mirrored_repeat", + "GL_IBM_vertex_array_lists", + "GL_INGR_blend_func_separate", + "GL_INGR_color_clamp", + "GL_INGR_interlace_read", + "GL_INGR_palette_buffer", + "GL_INTEL_map_texture", + "GL_INTEL_parallel_arrays", + "GL_INTEL_texture_scissor", + "GL_KHR_debug", + "GL_KHR_texture_compression_astc_hdr", + "GL_KHR_texture_compression_astc_ldr", + "GL_MESA_pack_invert", + "GL_MESA_resize_buffers", + "GL_MESA_window_pos", + "GL_MESAX_texture_stack", + "GL_MESA_ycbcr_texture", + "GL_NVX_conditional_render", + "GL_NV_bindless_multi_draw_indirect", + "GL_NV_bindless_texture", + "GL_NV_blend_equation_advanced", + "GL_NV_blend_equation_advanced_coherent", + "GL_NV_blend_square", + "GL_NV_compute_program5", + "GL_NV_conditional_render", + "GL_NV_copy_depth_to_color", + "GL_NV_copy_image", + "GL_NV_deep_texture3D", + "GL_NV_depth_buffer_float", + "GL_NV_depth_clamp", + "GL_NV_draw_texture", + "GL_NV_evaluators", + "GL_NV_explicit_multisample", + "GL_NV_fence", + "GL_NV_float_buffer", + "GL_NV_fog_distance", + "GL_NV_fragment_program", + "GL_NV_fragment_program2", + "GL_NV_fragment_program4", + "GL_NV_fragment_program_option", + "GL_NV_framebuffer_multisample_coverage", + "GL_NV_geometry_program4", + "GL_NV_geometry_shader4", + "GL_NV_gpu_program4", + "GL_NV_gpu_program5", + "GL_NV_gpu_program5_mem_extended", + "GL_NV_gpu_shader5", + "GL_NV_half_float", + "GL_NV_light_max_exponent", + "GL_NV_multisample_coverage", + "GL_NV_multisample_filter_hint", + "GL_NV_occlusion_query", + "GL_NV_packed_depth_stencil", + "GL_NV_parameter_buffer_object", + "GL_NV_parameter_buffer_object2", + "GL_NV_path_rendering", + "GL_NV_pixel_data_range", + "GL_NV_point_sprite", + "GL_NV_present_video", + "GL_NV_primitive_restart", + "GL_NV_register_combiners", + "GL_NV_register_combiners2", + "GL_NV_shader_atomic_counters", + "GL_NV_shader_atomic_float", + "GL_NV_shader_buffer_load", + "GL_NV_shader_buffer_store", + "GL_NV_shader_storage_buffer_object", + "GL_NV_tessellation_program5", + "GL_NV_texgen_emboss", + "GL_NV_texgen_reflection", + "GL_NV_texture_barrier", + "GL_NV_texture_compression_vtc", + "GL_NV_texture_env_combine4", + "GL_NV_texture_expand_normal", + "GL_NV_texture_multisample", + "GL_NV_texture_rectangle", + "GL_NV_texture_shader", + "GL_NV_texture_shader2", + "GL_NV_texture_shader3", + "GL_NV_transform_feedback", + "GL_NV_transform_feedback2", + "GL_NV_vdpau_interop", + "GL_NV_vertex_array_range", + "GL_NV_vertex_array_range2", + "GL_NV_vertex_attrib_integer_64bit", + "GL_NV_vertex_buffer_unified_memory", + "GL_NV_vertex_program", + "GL_NV_vertex_program1_1", + "GL_NV_vertex_program2", + "GL_NV_vertex_program2_option", + "GL_NV_vertex_program3", + "GL_NV_vertex_program4", + "GL_NV_video_capture", + "GL_OES_byte_coordinates", + "GL_OES_compressed_paletted_texture", + "GL_OES_fixed_point", + "GL_OES_query_matrix", + "GL_OES_read_format", + "GL_OES_single_precision", + "GL_OML_interlace", + "GL_OML_resample", + "GL_OML_subsample", + "GL_PGI_misc_hints", + "GL_PGI_vertex_hints", + "GL_REND_screen_coordinates", + "GL_S3_s3tc", + "GL_SGI_color_matrix", + "GL_SGI_color_table", + "GL_SGI_texture_color_table", + "GL_SGIS_detail_texture", + "GL_SGIS_fog_function", + "GL_SGIS_generate_mipmap", + "GL_SGIS_multisample", + "GL_SGIS_pixel_texture", + "GL_SGIS_point_line_texgen", + "GL_SGIS_point_parameters", + "GL_SGIS_sharpen_texture", + "GL_SGIS_texture4D", + "GL_SGIS_texture_border_clamp", + "GL_SGIS_texture_color_mask", + "GL_SGIS_texture_edge_clamp", + "GL_SGIS_texture_filter4", + "GL_SGIS_texture_lod", + "GL_SGIS_texture_select", + "GL_SGIX_async", + "GL_SGIX_async_histogram", + "GL_SGIX_async_pixel", + "GL_SGIX_blend_alpha_minmax", + "GL_SGIX_calligraphic_fragment", + "GL_SGIX_clipmap", + "GL_SGIX_convolution_accuracy", + "GL_SGIX_depth_pass_instrument", + "GL_SGIX_depth_texture", + "GL_SGIX_flush_raster", + "GL_SGIX_fog_offset", + "GL_SGIX_fog_scale", + "GL_SGIX_fragment_lighting", + "GL_SGIX_framezoom", + "GL_SGIX_igloo_interface", + "GL_SGIX_instruments", + "GL_SGIX_interlace", + "GL_SGIX_ir_instrument1", + "GL_SGIX_list_priority", + "GL_SGIX_pixel_texture", + "GL_SGIX_pixel_tiles", + "GL_SGIX_polynomial_ffd", + "GL_SGIX_reference_plane", + "GL_SGIX_resample", + "GL_SGIX_scalebias_hint", + "GL_SGIX_shadow", + "GL_SGIX_shadow_ambient", + "GL_SGIX_sprite", + "GL_SGIX_subsample", + "GL_SGIX_tag_sample_buffer", + "GL_SGIX_texture_add_env", + "GL_SGIX_texture_coordinate_clamp", + "GL_SGIX_texture_lod_bias", + "GL_SGIX_texture_multi_buffer", + "GL_SGIX_texture_scale_bias", + "GL_SGIX_vertex_preclip", + "GL_SGIX_ycrcb", + "GL_SGIX_ycrcba", + "GL_SGIX_ycrcb_subsample", + "GL_SUN_convolution_border_modes", + "GL_SUN_global_alpha", + "GL_SUN_mesh_array", + "GL_SUN_slice_accum", + "GL_SUN_triangle_list", + "GL_SUN_vertex", + "GL_SUNX_constant_data", + "GL_WIN_phong_shading", + "GL_WIN_specular_fog", + // unofficial stuff + "GL_NVX_gpu_memory_info" +}; + + +class COpenGLExtensionHandler +{ + public: + enum EOpenGLFeatures { + IRR_3DFX_multisample = 0, + IRR_3DFX_tbuffer, + IRR_3DFX_texture_compression_FXT1, + IRR_AMD_blend_minmax_factor, + IRR_AMD_conservative_depth, + IRR_AMD_debug_output, + IRR_AMD_depth_clamp_separate, + IRR_AMD_draw_buffers_blend, + IRR_AMD_interleaved_elements, + IRR_AMD_multi_draw_indirect, + IRR_AMD_name_gen_delete, + IRR_AMD_performance_monitor, + IRR_AMD_pinned_memory, + IRR_AMD_query_buffer_object, + IRR_AMD_sample_positions, + IRR_AMD_seamless_cubemap_per_texture, + IRR_AMD_shader_atomic_counter_ops, + IRR_AMD_shader_stencil_export, + IRR_AMD_shader_trinary_minmax, + IRR_AMD_sparse_texture, + IRR_AMD_stencil_operation_extended, + IRR_AMD_texture_texture4, + IRR_AMD_transform_feedback3_lines_triangles, + IRR_AMD_vertex_shader_layer, + IRR_AMD_vertex_shader_tessellator, + IRR_AMD_vertex_shader_viewport_index, + IRR_APPLE_aux_depth_stencil, + IRR_APPLE_client_storage, + IRR_APPLE_element_array, + IRR_APPLE_fence, + IRR_APPLE_float_pixels, + IRR_APPLE_flush_buffer_range, + IRR_APPLE_object_purgeable, + IRR_APPLE_rgb_422, + IRR_APPLE_row_bytes, + IRR_APPLE_specular_vector, + IRR_APPLE_texture_range, + IRR_APPLE_transform_hint, + IRR_APPLE_vertex_array_object, + IRR_APPLE_vertex_array_range, + IRR_APPLE_vertex_program_evaluators, + IRR_APPLE_ycbcr_422, + IRR_ARB_arrays_of_arrays, + IRR_ARB_base_instance, + IRR_ARB_bindless_texture, + IRR_ARB_blend_func_extended, + IRR_ARB_buffer_storage, + IRR_ARB_cl_event, + IRR_ARB_clear_buffer_object, + IRR_ARB_clear_texture, + IRR_ARB_color_buffer_float, + IRR_ARB_compatibility, + IRR_ARB_compressed_texture_pixel_storage, + IRR_ARB_compute_shader, + IRR_ARB_compute_variable_group_size, + IRR_ARB_conservative_depth, + IRR_ARB_copy_buffer, + IRR_ARB_copy_image, + IRR_ARB_debug_output, + IRR_ARB_depth_buffer_float, + IRR_ARB_depth_clamp, + IRR_ARB_depth_texture, + IRR_ARB_draw_buffers, + IRR_ARB_draw_buffers_blend, + IRR_ARB_draw_elements_base_vertex, + IRR_ARB_draw_indirect, + IRR_ARB_draw_instanced, + IRR_ARB_ES2_compatibility, + IRR_ARB_ES3_compatibility, + IRR_ARB_enhanced_layouts, + IRR_ARB_explicit_attrib_location, + IRR_ARB_explicit_uniform_location, + IRR_ARB_fragment_coord_conventions, + IRR_ARB_fragment_layer_viewport, + IRR_ARB_fragment_program, + IRR_ARB_fragment_program_shadow, + IRR_ARB_fragment_shader, + IRR_ARB_framebuffer_no_attachments, + IRR_ARB_framebuffer_object, + IRR_ARB_framebuffer_sRGB, + IRR_ARB_geometry_shader4, + IRR_ARB_get_program_binary, + IRR_ARB_gpu_shader5, + IRR_ARB_gpu_shader_fp64, + IRR_ARB_half_float_pixel, + IRR_ARB_half_float_vertex, + IRR_ARB_imaging, + IRR_ARB_indirect_parameters, + IRR_ARB_instanced_arrays, + IRR_ARB_internalformat_query, + IRR_ARB_internalformat_query2, + IRR_ARB_invalidate_subdata, + IRR_ARB_map_buffer_alignment, + IRR_ARB_map_buffer_range, + IRR_ARB_matrix_palette, + IRR_ARB_multi_bind, + IRR_ARB_multi_draw_indirect, + IRR_ARB_multisample, + IRR_ARB_multitexture, + IRR_ARB_occlusion_query, + IRR_ARB_occlusion_query2, + IRR_ARB_pixel_buffer_object, + IRR_ARB_point_parameters, + IRR_ARB_point_sprite, + IRR_ARB_program_interface_query, + IRR_ARB_provoking_vertex, + IRR_ARB_query_buffer_object, + IRR_ARB_robust_buffer_access_behavior, + IRR_ARB_robustness, + IRR_ARB_robustness_isolation, + IRR_ARB_sample_shading, + IRR_ARB_sampler_objects, + IRR_ARB_seamless_cube_map, + IRR_ARB_seamless_cubemap_per_texture, + IRR_ARB_separate_shader_objects, + IRR_ARB_shader_atomic_counters, + IRR_ARB_shader_bit_encoding, + IRR_ARB_shader_draw_parameters, + IRR_ARB_shader_group_vote, + IRR_ARB_shader_image_load_store, + IRR_ARB_shader_image_size, + IRR_ARB_shader_objects, + IRR_ARB_shader_precision, + IRR_ARB_shader_stencil_export, + IRR_ARB_shader_storage_buffer_object, + IRR_ARB_shader_subroutine, + IRR_ARB_shader_texture_lod, + IRR_ARB_shading_language_100, + IRR_ARB_shading_language_420pack, + IRR_ARB_shading_language_include, + IRR_ARB_shading_language_packing, + IRR_ARB_shadow, + IRR_ARB_shadow_ambient, + IRR_ARB_sparse_texture, + IRR_ARB_stencil_texturing, + IRR_ARB_sync, + IRR_ARB_tessellation_shader, + IRR_ARB_texture_border_clamp, + IRR_ARB_texture_buffer_object, + IRR_ARB_texture_buffer_object_rgb32, + IRR_ARB_texture_buffer_range, + IRR_ARB_texture_compression, + IRR_ARB_texture_compression_bptc, + IRR_ARB_texture_compression_rgtc, + IRR_ARB_texture_cube_map, + IRR_ARB_texture_cube_map_array, + IRR_ARB_texture_env_add, + IRR_ARB_texture_env_combine, + IRR_ARB_texture_env_crossbar, + IRR_ARB_texture_env_dot3, + IRR_ARB_texture_float, + IRR_ARB_texture_gather, + IRR_ARB_texture_mirror_clamp_to_edge, + IRR_ARB_texture_mirrored_repeat, + IRR_ARB_texture_multisample, + IRR_ARB_texture_non_power_of_two, + IRR_ARB_texture_query_levels, + IRR_ARB_texture_query_lod, + IRR_ARB_texture_rectangle, + IRR_ARB_texture_rg, + IRR_ARB_texture_rgb10_a2ui, + IRR_ARB_texture_stencil8, + IRR_ARB_texture_storage, + IRR_ARB_texture_storage_multisample, + IRR_ARB_texture_swizzle, + IRR_ARB_texture_view, + IRR_ARB_timer_query, + IRR_ARB_transform_feedback2, + IRR_ARB_transform_feedback3, + IRR_ARB_transform_feedback_instanced, + IRR_ARB_transpose_matrix, + IRR_ARB_uniform_buffer_object, + IRR_ARB_vertex_array_bgra, + IRR_ARB_vertex_array_object, + IRR_ARB_vertex_attrib_64bit, + IRR_ARB_vertex_attrib_binding, + IRR_ARB_vertex_blend, + IRR_ARB_vertex_buffer_object, + IRR_ARB_vertex_program, + IRR_ARB_vertex_shader, + IRR_ARB_vertex_type_10f_11f_11f_rev, + IRR_ARB_vertex_type_2_10_10_10_rev, + IRR_ARB_viewport_array, + IRR_ARB_window_pos, + IRR_ATI_draw_buffers, + IRR_ATI_element_array, + IRR_ATI_envmap_bumpmap, + IRR_ATI_fragment_shader, + IRR_ATI_map_object_buffer, + IRR_ATI_meminfo, + IRR_ATI_pixel_format_float, + IRR_ATI_pn_triangles, + IRR_ATI_separate_stencil, + IRR_ATI_text_fragment_shader, + IRR_ATI_texture_env_combine3, + IRR_ATI_texture_float, + IRR_ATI_texture_mirror_once, + IRR_ATI_vertex_array_object, + IRR_ATI_vertex_attrib_array_object, + IRR_ATI_vertex_streams, + IRR_EXT_422_pixels, + IRR_EXT_abgr, + IRR_EXT_bgra, + IRR_EXT_bindable_uniform, + IRR_EXT_blend_color, + IRR_EXT_blend_equation_separate, + IRR_EXT_blend_func_separate, + IRR_EXT_blend_logic_op, + IRR_EXT_blend_minmax, + IRR_EXT_blend_subtract, + IRR_EXT_clip_volume_hint, + IRR_EXT_cmyka, + IRR_EXT_color_subtable, + IRR_EXT_compiled_vertex_array, + IRR_EXT_convolution, + IRR_EXT_coordinate_frame, + IRR_EXT_copy_texture, + IRR_EXT_cull_vertex, + IRR_EXT_debug_label, + IRR_EXT_debug_marker, + IRR_EXT_depth_bounds_test, + IRR_EXT_direct_state_access, + IRR_EXT_draw_buffers2, + IRR_EXT_draw_instanced, + IRR_EXT_draw_range_elements, + IRR_EXT_fog_coord, + IRR_EXT_framebuffer_blit, + IRR_EXT_framebuffer_multisample, + IRR_EXT_framebuffer_multisample_blit_scaled, + IRR_EXT_framebuffer_object, + IRR_EXT_framebuffer_sRGB, + IRR_EXT_geometry_shader4, + IRR_EXT_gpu_program_parameters, + IRR_EXT_gpu_shader4, + IRR_EXT_histogram, + IRR_EXT_index_array_formats, + IRR_EXT_index_func, + IRR_EXT_index_material, + IRR_EXT_index_texture, + IRR_EXT_light_texture, + IRR_EXT_misc_attribute, + IRR_EXT_multi_draw_arrays, + IRR_EXT_multisample, + IRR_EXT_packed_depth_stencil, + IRR_EXT_packed_float, + IRR_EXT_packed_pixels, + IRR_EXT_paletted_texture, + IRR_EXT_pixel_buffer_object, + IRR_EXT_pixel_transform, + IRR_EXT_pixel_transform_color_table, + IRR_EXT_point_parameters, + IRR_EXT_polygon_offset, + IRR_EXT_provoking_vertex, + IRR_EXT_rescale_normal, + IRR_EXT_secondary_color, + IRR_EXT_separate_shader_objects, + IRR_EXT_separate_specular_color, + IRR_EXT_shader_image_load_store, + IRR_EXT_shader_integer_mix, + IRR_EXT_shadow_funcs, + IRR_EXT_shared_texture_palette, + IRR_EXT_stencil_clear_tag, + IRR_EXT_stencil_two_side, + IRR_EXT_stencil_wrap, + IRR_EXT_subtexture, + IRR_EXT_texture, + IRR_EXT_texture3D, + IRR_EXT_texture_array, + IRR_EXT_texture_buffer_object, + IRR_EXT_texture_compression_latc, + IRR_EXT_texture_compression_rgtc, + IRR_EXT_texture_compression_s3tc, + IRR_EXT_texture_cube_map, + IRR_EXT_texture_env_add, + IRR_EXT_texture_env_combine, + IRR_EXT_texture_env_dot3, + IRR_EXT_texture_filter_anisotropic, + IRR_EXT_texture_integer, + IRR_EXT_texture_lod_bias, + IRR_EXT_texture_mirror_clamp, + IRR_EXT_texture_object, + IRR_EXT_texture_perturb_normal, + IRR_EXT_texture_shared_exponent, + IRR_EXT_texture_snorm, + IRR_EXT_texture_sRGB, + IRR_EXT_texture_sRGB_decode, + IRR_EXT_texture_swizzle, + IRR_EXT_timer_query, + IRR_EXT_transform_feedback, + IRR_EXT_vertex_array, + IRR_EXT_vertex_array_bgra, + IRR_EXT_vertex_attrib_64bit, + IRR_EXT_vertex_shader, + IRR_EXT_vertex_weighting, + IRR_EXT_x11_sync_object, + IRR_GREMEDY_frame_terminator, + IRR_GREMEDY_string_marker, + IRR_HP_convolution_border_modes, + IRR_HP_image_transform, + IRR_HP_occlusion_test, + IRR_HP_texture_lighting, + IRR_IBM_cull_vertex, + IRR_IBM_multimode_draw_arrays, + IRR_IBM_rasterpos_clip, + IRR_IBM_static_data, + IRR_IBM_texture_mirrored_repeat, + IRR_IBM_vertex_array_lists, + IRR_INGR_blend_func_separate, + IRR_INGR_color_clamp, + IRR_INGR_interlace_read, + IRR_INGR_palette_buffer, + IRR_INTEL_map_texture, + IRR_INTEL_parallel_arrays, + IRR_INTEL_texture_scissor, + IRR_KHR_debug, + IRR_KHR_texture_compression_astc_hdr, + IRR_KHR_texture_compression_astc_ldr, + IRR_MESA_pack_invert, + IRR_MESA_resize_buffers, + IRR_MESA_window_pos, + IRR_MESAX_texture_stack, + IRR_MESA_ycbcr_texture, + IRR_NVX_conditional_render, + IRR_NV_bindless_multi_draw_indirect, + IRR_NV_bindless_texture, + IRR_NV_blend_equation_advanced, + IRR_NV_blend_equation_advanced_coherent, + IRR_NV_blend_square, + IRR_NV_compute_program5, + IRR_NV_conditional_render, + IRR_NV_copy_depth_to_color, + IRR_NV_copy_image, + IRR_NV_deep_texture3D, + IRR_NV_depth_buffer_float, + IRR_NV_depth_clamp, + IRR_NV_draw_texture, + IRR_NV_evaluators, + IRR_NV_explicit_multisample, + IRR_NV_fence, + IRR_NV_float_buffer, + IRR_NV_fog_distance, + IRR_NV_fragment_program, + IRR_NV_fragment_program2, + IRR_NV_fragment_program4, + IRR_NV_fragment_program_option, + IRR_NV_framebuffer_multisample_coverage, + IRR_NV_geometry_program4, + IRR_NV_geometry_shader4, + IRR_NV_gpu_program4, + IRR_NV_gpu_program5, + IRR_NV_gpu_program5_mem_extended, + IRR_NV_gpu_shader5, + IRR_NV_half_float, + IRR_NV_light_max_exponent, + IRR_NV_multisample_coverage, + IRR_NV_multisample_filter_hint, + IRR_NV_occlusion_query, + IRR_NV_packed_depth_stencil, + IRR_NV_parameter_buffer_object, + IRR_NV_parameter_buffer_object2, + IRR_NV_path_rendering, + IRR_NV_pixel_data_range, + IRR_NV_point_sprite, + IRR_NV_present_video, + IRR_NV_primitive_restart, + IRR_NV_register_combiners, + IRR_NV_register_combiners2, + IRR_NV_shader_atomic_counters, + IRR_NV_shader_atomic_float, + IRR_NV_shader_buffer_load, + IRR_NV_shader_buffer_store, + IRR_NV_shader_storage_buffer_object, + IRR_NV_tessellation_program5, + IRR_NV_texgen_emboss, + IRR_NV_texgen_reflection, + IRR_NV_texture_barrier, + IRR_NV_texture_compression_vtc, + IRR_NV_texture_env_combine4, + IRR_NV_texture_expand_normal, + IRR_NV_texture_multisample, + IRR_NV_texture_rectangle, + IRR_NV_texture_shader, + IRR_NV_texture_shader2, + IRR_NV_texture_shader3, + IRR_NV_transform_feedback, + IRR_NV_transform_feedback2, + IRR_NV_vdpau_interop, + IRR_NV_vertex_array_range, + IRR_NV_vertex_array_range2, + IRR_NV_vertex_attrib_integer_64bit, + IRR_NV_vertex_buffer_unified_memory, + IRR_NV_vertex_program, + IRR_NV_vertex_program1_1, + IRR_NV_vertex_program2, + IRR_NV_vertex_program2_option, + IRR_NV_vertex_program3, + IRR_NV_vertex_program4, + IRR_NV_video_capture, + IRR_OES_byte_coordinates, + IRR_OES_compressed_paletted_texture, + IRR_OES_fixed_point, + IRR_OES_query_matrix, + IRR_OES_read_format, + IRR_OES_single_precision, + IRR_OML_interlace, + IRR_OML_resample, + IRR_OML_subsample, + IRR_PGI_misc_hints, + IRR_PGI_vertex_hints, + IRR_REND_screen_coordinates, + IRR_S3_s3tc, + IRR_SGI_color_matrix, + IRR_SGI_color_table, + IRR_SGI_texture_color_table, + IRR_SGIS_detail_texture, + IRR_SGIS_fog_function, + IRR_SGIS_generate_mipmap, + IRR_SGIS_multisample, + IRR_SGIS_pixel_texture, + IRR_SGIS_point_line_texgen, + IRR_SGIS_point_parameters, + IRR_SGIS_sharpen_texture, + IRR_SGIS_texture4D, + IRR_SGIS_texture_border_clamp, + IRR_SGIS_texture_color_mask, + IRR_SGIS_texture_edge_clamp, + IRR_SGIS_texture_filter4, + IRR_SGIS_texture_lod, + IRR_SGIS_texture_select, + IRR_SGIX_async, + IRR_SGIX_async_histogram, + IRR_SGIX_async_pixel, + IRR_SGIX_blend_alpha_minmax, + IRR_SGIX_calligraphic_fragment, + IRR_SGIX_clipmap, + IRR_SGIX_convolution_accuracy, + IRR_SGIX_depth_pass_instrument, + IRR_SGIX_depth_texture, + IRR_SGIX_flush_raster, + IRR_SGIX_fog_offset, + IRR_SGIX_fog_scale, + IRR_SGIX_fragment_lighting, + IRR_SGIX_framezoom, + IRR_SGIX_igloo_interface, + IRR_SGIX_instruments, + IRR_SGIX_interlace, + IRR_SGIX_ir_instrument1, + IRR_SGIX_list_priority, + IRR_SGIX_pixel_texture, + IRR_SGIX_pixel_tiles, + IRR_SGIX_polynomial_ffd, + IRR_SGIX_reference_plane, + IRR_SGIX_resample, + IRR_SGIX_scalebias_hint, + IRR_SGIX_shadow, + IRR_SGIX_shadow_ambient, + IRR_SGIX_sprite, + IRR_SGIX_subsample, + IRR_SGIX_tag_sample_buffer, + IRR_SGIX_texture_add_env, + IRR_SGIX_texture_coordinate_clamp, + IRR_SGIX_texture_lod_bias, + IRR_SGIX_texture_multi_buffer, + IRR_SGIX_texture_scale_bias, + IRR_SGIX_vertex_preclip, + IRR_SGIX_ycrcb, + IRR_SGIX_ycrcba, + IRR_SGIX_ycrcb_subsample, + IRR_SUN_convolution_border_modes, + IRR_SUN_global_alpha, + IRR_SUN_mesh_array, + IRR_SUN_slice_accum, + IRR_SUN_triangle_list, + IRR_SUN_vertex, + IRR_SUNX_constant_data, + IRR_WIN_phong_shading, + IRR_WIN_specular_fog, + IRR_NVX_gpu_memory_info, + IRR_OpenGL_Feature_Count + }; + + + // constructor + COpenGLExtensionHandler(); + + // deferred initialization + void initExtensions(bool stencilBuffer); + + const COpenGLCoreFeature& getFeature() const; + + //! queries the features of the driver, returns true if feature is available + bool queryFeature(E_VIDEO_DRIVER_FEATURE feature) const; + + //! queries the features of the driver, returns true if feature is available + bool queryOpenGLFeature(EOpenGLFeatures feature) const + { + return FeatureAvailable[feature]; + } + + //! show all features with availability + void dump(ELOG_LEVEL logLevel) const; + + void dumpFramebufferFormats() const; + + // Some variables for properties + bool StencilBuffer; + bool TextureCompressionExtension; + + // Some non-boolean properties + //! Maximum hardware lights supported + u8 MaxLights; + //! Maximal Anisotropy + u8 MaxAnisotropy; + //! Number of user clipplanes + u8 MaxUserClipPlanes; + //! Number of auxiliary buffers + u8 MaxAuxBuffers; + //! Optimal number of indices per meshbuffer + u32 MaxIndices; + //! Maximal texture dimension + u32 MaxTextureSize; + //! Maximal vertices handled by geometry shaders + u32 MaxGeometryVerticesOut; + //! Maximal LOD Bias + f32 MaxTextureLODBias; + //! Minimal and maximal supported thickness for lines without smoothing + GLfloat DimAliasedLine[2]; + //! Minimal and maximal supported thickness for points without smoothing + GLfloat DimAliasedPoint[2]; + //! Minimal and maximal supported thickness for lines with smoothing + GLfloat DimSmoothedLine[2]; + //! Minimal and maximal supported thickness for points with smoothing + GLfloat DimSmoothedPoint[2]; + + //! OpenGL version as Integer: 100*Major+Minor, i.e. 2.1 becomes 201 + u16 Version; + //! GLSL version as Integer: 100*Major+Minor + u16 ShaderLanguageVersion; + + bool OcclusionQuerySupport; + + //! Workaround until direct state access with framebuffers is stable enough in drivers + // https://devtalk.nvidia.com/default/topic/1030494/opengl/bug-amp-amp-spec-violation-checknamedframebufferstatus-returns-gl_framebuffer_incomplete_dimensions_ext-under-gl-4-5-core/ + // https://stackoverflow.com/questions/51304706/problems-with-attaching-textures-of-different-sizes-to-fbo + static bool needsDSAFramebufferHack; + + // public access to the (loaded) extensions. + // general functions + void irrGlActiveTexture(GLenum texture); + void irrGlClientActiveTexture(GLenum texture); + void extGlPointParameterf(GLint loc, GLfloat f); + void extGlPointParameterfv(GLint loc, const GLfloat *v); + void extGlStencilFuncSeparate (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); + void extGlStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass); + void irrGlCompressedTexImage2D(GLenum target, GLint level, + GLenum internalformat, GLsizei width, GLsizei height, + GLint border, GLsizei imageSize, const void* data); + void irrGlCompressedTexSubImage2D(GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLsizei imageSize, const void* data); + + // shader programming + void extGlGenPrograms(GLsizei n, GLuint *programs); + void extGlBindProgram(GLenum target, GLuint program); + void extGlProgramString(GLenum target, GLenum format, GLsizei len, const GLvoid *string); + void extGlLoadProgram(GLenum target, GLuint id, GLsizei len, const GLubyte *string); + void extGlDeletePrograms(GLsizei n, const GLuint *programs); + void extGlProgramLocalParameter4fv(GLenum, GLuint, const GLfloat *); + GLhandleARB extGlCreateShaderObject(GLenum shaderType); + GLuint extGlCreateShader(GLenum shaderType); + // note: Due to the type confusion between shader_objects and OpenGL 2.0 + // we have to add the ARB extension for proper method definitions in case + // that handleARB and uint are the same type + void extGlShaderSourceARB(GLhandleARB shader, GLsizei numOfStrings, const char **strings, const GLint *lenOfStrings); + void extGlShaderSource(GLuint shader, GLsizei numOfStrings, const char **strings, const GLint *lenOfStrings); + // note: Due to the type confusion between shader_objects and OpenGL 2.0 + // we have to add the ARB extension for proper method definitions in case + // that handleARB and uint are the same type + void extGlCompileShaderARB(GLhandleARB shader); + void extGlCompileShader(GLuint shader); + GLhandleARB extGlCreateProgramObject(void); + GLuint extGlCreateProgram(void); + void extGlAttachObject(GLhandleARB program, GLhandleARB shader); + void extGlAttachShader(GLuint program, GLuint shader); + void extGlLinkProgramARB(GLhandleARB program); + // note: Due to the type confusion between shader_objects and OpenGL 2.0 + // we have to add the ARB extension for proper method definitions in case + // that handleARB and uint are the same type + void extGlLinkProgram(GLuint program); + void extGlUseProgramObject(GLhandleARB prog); + void irrGlUseProgram(GLuint prog); + void extGlDeleteObject(GLhandleARB object); + void extGlDeleteProgram(GLuint object); + void extGlDeleteShader(GLuint shader); + void extGlGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders); + void extGlGetAttachedObjects(GLhandleARB program, GLsizei maxcount, GLsizei* count, GLhandleARB* shaders); + void extGlGetInfoLog(GLhandleARB object, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); + void extGlGetShaderInfoLog(GLuint shader, GLsizei maxLength, GLsizei *length, GLchar *infoLog); + void extGlGetProgramInfoLog(GLuint program, GLsizei maxLength, GLsizei *length, GLchar *infoLog); + void extGlGetObjectParameteriv(GLhandleARB object, GLenum type, GLint *param); + void extGlGetShaderiv(GLuint shader, GLenum type, GLint *param); + void extGlGetProgramiv(GLuint program, GLenum type, GLint *param); + GLint extGlGetUniformLocationARB(GLhandleARB program, const char *name); + GLint extGlGetUniformLocation(GLuint program, const char *name); + void extGlUniform1fv(GLint loc, GLsizei count, const GLfloat *v); + void extGlUniform2fv(GLint loc, GLsizei count, const GLfloat *v); + void extGlUniform3fv(GLint loc, GLsizei count, const GLfloat *v); + void extGlUniform4fv(GLint loc, GLsizei count, const GLfloat *v); + void extGlUniform1bv(GLint loc, GLsizei count, const bool *v); + void extGlUniform2bv(GLint loc, GLsizei count, const bool *v); + void extGlUniform3bv(GLint loc, GLsizei count, const bool *v); + void extGlUniform4bv(GLint loc, GLsizei count, const bool *v); + void extGlUniform1iv(GLint loc, GLsizei count, const GLint *v); + void extGlUniform2iv(GLint loc, GLsizei count, const GLint *v); + void extGlUniform3iv(GLint loc, GLsizei count, const GLint *v); + void extGlUniform4iv(GLint loc, GLsizei count, const GLint *v); + void extGlUniformMatrix2fv(GLint loc, GLsizei count, GLboolean transpose, const GLfloat *v); + void extGlUniformMatrix3fv(GLint loc, GLsizei count, GLboolean transpose, const GLfloat *v); + void extGlUniformMatrix4fv(GLint loc, GLsizei count, GLboolean transpose, const GLfloat *v); + void extGlGetActiveUniformARB(GLhandleARB program, GLuint index, GLsizei maxlength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); + void extGlGetActiveUniform(GLuint program, GLuint index, GLsizei maxlength, GLsizei *length, GLint *size, GLenum *type, GLchar *name); + + // framebuffer objects + void irrGlBindFramebuffer(GLenum target, GLuint framebuffer); + void irrGlDeleteFramebuffers(GLsizei n, const GLuint *framebuffers); + void irrGlGenFramebuffers(GLsizei n, GLuint *framebuffers); + GLenum irrGlCheckFramebufferStatus(GLenum target); + void irrGlFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); + void irrGlBindRenderbuffer(GLenum target, GLuint renderbuffer); + void irrGlDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers); + void irrGlGenRenderbuffers(GLsizei n, GLuint *renderbuffers); + void irrGlRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); + void irrGlFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); + void irrGlGenerateMipmap(GLenum target); + void irrGlActiveStencilFace(GLenum face); + void irrGlDrawBuffer(GLenum mode); + void irrGlDrawBuffers(GLsizei n, const GLenum *bufs); + + // vertex buffer object + void extGlGenBuffers(GLsizei n, GLuint *buffers); + void extGlBindBuffer(GLenum target, GLuint buffer); + void extGlBufferData(GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); + void extGlDeleteBuffers(GLsizei n, const GLuint *buffers); + void extGlBufferSubData (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); + void extGlGetBufferSubData (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); + void *extGlMapBuffer (GLenum target, GLenum access); + GLboolean extGlUnmapBuffer (GLenum target); + GLboolean extGlIsBuffer (GLuint buffer); + void extGlGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); + void extGlGetBufferPointerv (GLenum target, GLenum pname, GLvoid **params); + void extGlProvokingVertex(GLenum mode); + void extGlProgramParameteri(GLuint program, GLenum pname, GLint value); + + // occlusion query + void extGlGenQueries(GLsizei n, GLuint *ids); + void extGlDeleteQueries(GLsizei n, const GLuint *ids); + GLboolean extGlIsQuery(GLuint id); + void extGlBeginQuery(GLenum target, GLuint id); + void extGlEndQuery(GLenum target); + void extGlGetQueryiv(GLenum target, GLenum pname, GLint *params); + void extGlGetQueryObjectiv(GLuint id, GLenum pname, GLint *params); + void extGlGetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params); + + // blend + void irrGlBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); + void irrGlBlendEquation(GLenum mode); + + // indexed + void irrGlEnableIndexed(GLenum target, GLuint index); + void irrGlDisableIndexed(GLenum target, GLuint index); + void irrGlColorMaskIndexed(GLuint buf, GLboolean r, GLboolean g, GLboolean b, GLboolean a); + void irrGlBlendFuncIndexed(GLuint buf, GLenum src, GLenum dst); + void irrGlBlendFuncSeparateIndexed(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); + void irrGlBlendEquationIndexed(GLuint buf, GLenum mode); + void irrGlBlendEquationSeparateIndexed(GLuint buf, GLenum modeRGB, GLenum modeAlpha); + + void extGlTextureSubImage2D(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels); + void extGlTextureStorage2D(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); + void extGlTextureStorage3D(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); + void extGlNamedFramebufferTexture(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); + void extGlTextureParameteri(GLuint texture, GLenum pname, GLint param); + void extGlCreateTextures(GLenum target, GLsizei n, GLuint* textures); + void extGlCreateFramebuffers(GLsizei n, GLuint* framebuffers); + void extGlBindTextures(GLuint first, GLsizei count, const GLuint *textures, const GLenum* targets); + void extGlGenerateTextureMipmap(GLuint texture, GLenum target); + + + // generic vsync setting method for several extensions + void extGlSwapInterval(int interval); + + // the global feature array + bool FeatureAvailable[IRR_OpenGL_Feature_Count]; + + protected: + COpenGLCoreFeature Feature; + + #if defined(_IRR_OPENGL_USE_EXTPOINTER_) + PFNGLACTIVETEXTUREPROC pGlActiveTexture; + PFNGLACTIVETEXTUREARBPROC pGlActiveTextureARB; + PFNGLCLIENTACTIVETEXTUREARBPROC pGlClientActiveTextureARB; + PFNGLGENPROGRAMSARBPROC pGlGenProgramsARB; + PFNGLGENPROGRAMSNVPROC pGlGenProgramsNV; + PFNGLBINDPROGRAMARBPROC pGlBindProgramARB; + PFNGLBINDPROGRAMNVPROC pGlBindProgramNV; + PFNGLDELETEPROGRAMSARBPROC pGlDeleteProgramsARB; + PFNGLDELETEPROGRAMSNVPROC pGlDeleteProgramsNV; + PFNGLPROGRAMSTRINGARBPROC pGlProgramStringARB; + PFNGLLOADPROGRAMNVPROC pGlLoadProgramNV; + PFNGLPROGRAMLOCALPARAMETER4FVARBPROC pGlProgramLocalParameter4fvARB; + PFNGLCREATESHADEROBJECTARBPROC pGlCreateShaderObjectARB; + PFNGLSHADERSOURCEARBPROC pGlShaderSourceARB; + PFNGLCOMPILESHADERARBPROC pGlCompileShaderARB; + PFNGLCREATEPROGRAMOBJECTARBPROC pGlCreateProgramObjectARB; + PFNGLATTACHOBJECTARBPROC pGlAttachObjectARB; + PFNGLLINKPROGRAMARBPROC pGlLinkProgramARB; + PFNGLUSEPROGRAMOBJECTARBPROC pGlUseProgramObjectARB; + PFNGLDELETEOBJECTARBPROC pGlDeleteObjectARB; + PFNGLCREATEPROGRAMPROC pGlCreateProgram; + PFNGLUSEPROGRAMPROC pGlUseProgram; + PFNGLDELETEPROGRAMPROC pGlDeleteProgram; + PFNGLDELETESHADERPROC pGlDeleteShader; + PFNGLGETATTACHEDOBJECTSARBPROC pGlGetAttachedObjectsARB; + PFNGLGETATTACHEDSHADERSPROC pGlGetAttachedShaders; + PFNGLCREATESHADERPROC pGlCreateShader; + PFNGLSHADERSOURCEPROC pGlShaderSource; + PFNGLCOMPILESHADERPROC pGlCompileShader; + PFNGLATTACHSHADERPROC pGlAttachShader; + PFNGLLINKPROGRAMPROC pGlLinkProgram; + PFNGLGETINFOLOGARBPROC pGlGetInfoLogARB; + PFNGLGETSHADERINFOLOGPROC pGlGetShaderInfoLog; + PFNGLGETPROGRAMINFOLOGPROC pGlGetProgramInfoLog; + PFNGLGETOBJECTPARAMETERIVARBPROC pGlGetObjectParameterivARB; + PFNGLGETSHADERIVPROC pGlGetShaderiv; + PFNGLGETSHADERIVPROC pGlGetProgramiv; + PFNGLGETUNIFORMLOCATIONARBPROC pGlGetUniformLocationARB; + PFNGLGETUNIFORMLOCATIONPROC pGlGetUniformLocation; + PFNGLUNIFORM1FVARBPROC pGlUniform1fvARB; + PFNGLUNIFORM2FVARBPROC pGlUniform2fvARB; + PFNGLUNIFORM3FVARBPROC pGlUniform3fvARB; + PFNGLUNIFORM4FVARBPROC pGlUniform4fvARB; + PFNGLUNIFORM1IVARBPROC pGlUniform1ivARB; + PFNGLUNIFORM2IVARBPROC pGlUniform2ivARB; + PFNGLUNIFORM3IVARBPROC pGlUniform3ivARB; + PFNGLUNIFORM4IVARBPROC pGlUniform4ivARB; + PFNGLUNIFORMMATRIX2FVARBPROC pGlUniformMatrix2fvARB; + PFNGLUNIFORMMATRIX3FVARBPROC pGlUniformMatrix3fvARB; + PFNGLUNIFORMMATRIX4FVARBPROC pGlUniformMatrix4fvARB; + PFNGLGETACTIVEUNIFORMARBPROC pGlGetActiveUniformARB; + PFNGLGETACTIVEUNIFORMPROC pGlGetActiveUniform; + PFNGLPOINTPARAMETERFARBPROC pGlPointParameterfARB; + PFNGLPOINTPARAMETERFVARBPROC pGlPointParameterfvARB; + PFNGLSTENCILFUNCSEPARATEPROC pGlStencilFuncSeparate; + PFNGLSTENCILOPSEPARATEPROC pGlStencilOpSeparate; + PFNGLSTENCILFUNCSEPARATEATIPROC pGlStencilFuncSeparateATI; + PFNGLSTENCILOPSEPARATEATIPROC pGlStencilOpSeparateATI; + PFNGLCOMPRESSEDTEXIMAGE2DPROC pGlCompressedTexImage2D; + PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC pGlCompressedTexSubImage2D; + // ARB framebuffer object + PFNGLBINDFRAMEBUFFERPROC pGlBindFramebuffer; + PFNGLDELETEFRAMEBUFFERSPROC pGlDeleteFramebuffers; + PFNGLGENFRAMEBUFFERSPROC pGlGenFramebuffers; + PFNGLCHECKFRAMEBUFFERSTATUSPROC pGlCheckFramebufferStatus; + PFNGLFRAMEBUFFERTEXTURE2DPROC pGlFramebufferTexture2D; + PFNGLBINDRENDERBUFFERPROC pGlBindRenderbuffer; + PFNGLDELETERENDERBUFFERSPROC pGlDeleteRenderbuffers; + PFNGLGENRENDERBUFFERSPROC pGlGenRenderbuffers; + PFNGLRENDERBUFFERSTORAGEPROC pGlRenderbufferStorage; + PFNGLFRAMEBUFFERRENDERBUFFERPROC pGlFramebufferRenderbuffer; + PFNGLGENERATEMIPMAPPROC pGlGenerateMipmap; + // EXT framebuffer object + PFNGLBINDFRAMEBUFFEREXTPROC pGlBindFramebufferEXT; + PFNGLDELETEFRAMEBUFFERSEXTPROC pGlDeleteFramebuffersEXT; + PFNGLGENFRAMEBUFFERSEXTPROC pGlGenFramebuffersEXT; + PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC pGlCheckFramebufferStatusEXT; + PFNGLFRAMEBUFFERTEXTURE2DEXTPROC pGlFramebufferTexture2DEXT; + PFNGLBINDRENDERBUFFEREXTPROC pGlBindRenderbufferEXT; + PFNGLDELETERENDERBUFFERSEXTPROC pGlDeleteRenderbuffersEXT; + PFNGLGENRENDERBUFFERSEXTPROC pGlGenRenderbuffersEXT; + PFNGLRENDERBUFFERSTORAGEEXTPROC pGlRenderbufferStorageEXT; + PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC pGlFramebufferRenderbufferEXT; + PFNGLGENERATEMIPMAPEXTPROC pGlGenerateMipmapEXT; + PFNGLACTIVESTENCILFACEEXTPROC pGlActiveStencilFaceEXT; + PFNGLDRAWBUFFERSARBPROC pGlDrawBuffersARB; + PFNGLDRAWBUFFERSATIPROC pGlDrawBuffersATI; + PFNGLGENBUFFERSARBPROC pGlGenBuffersARB; + PFNGLBINDBUFFERARBPROC pGlBindBufferARB; + PFNGLBUFFERDATAARBPROC pGlBufferDataARB; + PFNGLDELETEBUFFERSARBPROC pGlDeleteBuffersARB; + PFNGLBUFFERSUBDATAARBPROC pGlBufferSubDataARB; + PFNGLGETBUFFERSUBDATAARBPROC pGlGetBufferSubDataARB; + PFNGLMAPBUFFERARBPROC pGlMapBufferARB; + PFNGLUNMAPBUFFERARBPROC pGlUnmapBufferARB; + PFNGLISBUFFERARBPROC pGlIsBufferARB; + PFNGLGETBUFFERPARAMETERIVARBPROC pGlGetBufferParameterivARB; + PFNGLGETBUFFERPOINTERVARBPROC pGlGetBufferPointervARB; + PFNGLPROVOKINGVERTEXPROC pGlProvokingVertexARB; + PFNGLPROVOKINGVERTEXEXTPROC pGlProvokingVertexEXT; + PFNGLPROGRAMPARAMETERIARBPROC pGlProgramParameteriARB; + PFNGLPROGRAMPARAMETERIEXTPROC pGlProgramParameteriEXT; + PFNGLGENQUERIESARBPROC pGlGenQueriesARB; + PFNGLDELETEQUERIESARBPROC pGlDeleteQueriesARB; + PFNGLISQUERYARBPROC pGlIsQueryARB; + PFNGLBEGINQUERYARBPROC pGlBeginQueryARB; + PFNGLENDQUERYARBPROC pGlEndQueryARB; + PFNGLGETQUERYIVARBPROC pGlGetQueryivARB; + PFNGLGETQUERYOBJECTIVARBPROC pGlGetQueryObjectivARB; + PFNGLGETQUERYOBJECTUIVARBPROC pGlGetQueryObjectuivARB; + PFNGLGENOCCLUSIONQUERIESNVPROC pGlGenOcclusionQueriesNV; + PFNGLDELETEOCCLUSIONQUERIESNVPROC pGlDeleteOcclusionQueriesNV; + PFNGLISOCCLUSIONQUERYNVPROC pGlIsOcclusionQueryNV; + PFNGLBEGINOCCLUSIONQUERYNVPROC pGlBeginOcclusionQueryNV; + PFNGLENDOCCLUSIONQUERYNVPROC pGlEndOcclusionQueryNV; + PFNGLGETOCCLUSIONQUERYIVNVPROC pGlGetOcclusionQueryivNV; + PFNGLGETOCCLUSIONQUERYUIVNVPROC pGlGetOcclusionQueryuivNV; + // Blend + PFNGLBLENDFUNCSEPARATEEXTPROC pGlBlendFuncSeparateEXT; + PFNGLBLENDFUNCSEPARATEPROC pGlBlendFuncSeparate; + PFNGLBLENDEQUATIONEXTPROC pGlBlendEquationEXT; + PFNGLBLENDEQUATIONPROC pGlBlendEquation; + PFNGLBLENDEQUATIONSEPARATEEXTPROC pGlBlendEquationSeparateEXT; + PFNGLBLENDEQUATIONSEPARATEPROC pGlBlendEquationSeparate; + // Indexed + PFNGLENABLEINDEXEDEXTPROC pGlEnableIndexedEXT; + PFNGLDISABLEINDEXEDEXTPROC pGlDisableIndexedEXT; + PFNGLCOLORMASKINDEXEDEXTPROC pGlColorMaskIndexedEXT; + PFNGLBLENDFUNCINDEXEDAMDPROC pGlBlendFuncIndexedAMD; + PFNGLBLENDFUNCIPROC pGlBlendFunciARB; + PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC pGlBlendFuncSeparateIndexedAMD; + PFNGLBLENDFUNCSEPARATEIPROC pGlBlendFuncSeparateiARB; + PFNGLBLENDEQUATIONINDEXEDAMDPROC pGlBlendEquationIndexedAMD; + PFNGLBLENDEQUATIONIPROC pGlBlendEquationiARB; + PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC pGlBlendEquationSeparateIndexedAMD; + PFNGLBLENDEQUATIONSEPARATEIPROC pGlBlendEquationSeparateiARB; + + // DSA + PFNGLTEXTURESTORAGE2DPROC pGlTextureStorage2D; + PFNGLTEXTURESTORAGE3DPROC pGlTextureStorage3D; + PFNGLTEXTURESUBIMAGE2DPROC pGlTextureSubImage2D; + PFNGLNAMEDFRAMEBUFFERTEXTUREPROC pGlNamedFramebufferTexture; + PFNGLTEXTUREPARAMETERIPROC pGlTextureParameteri; + PFNGLCREATETEXTURESPROC pGlCreateTextures; + PFNGLCREATEFRAMEBUFFERSPROC pGlCreateFramebuffers; + PFNGLBINDTEXTURESPROC pGlBindTextures; + PFNGLGENERATETEXTUREMIPMAPPROC pGlGenerateTextureMipmap; + // DSA with EXT or functions to simulate it + PFNGLTEXTURESUBIMAGE2DEXTPROC pGlTextureSubImage2DEXT; + PFNGLTEXTURESTORAGE2DEXTPROC pGlTextureStorage2DEXT; + PFNGLTEXSTORAGE2DPROC pGlTexStorage2D; + PFNGLTEXTURESTORAGE3DEXTPROC pGlTextureStorage3DEXT; + PFNGLTEXSTORAGE3DPROC pGlTexStorage3D; + PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC pGlNamedFramebufferTextureEXT; + PFNGLFRAMEBUFFERTEXTUREPROC pGlFramebufferTexture; + PFNGLGENERATETEXTUREMIPMAPEXTPROC pGlGenerateTextureMipmapEXT; + + #if defined(WGL_EXT_swap_control) + PFNWGLSWAPINTERVALEXTPROC pWglSwapIntervalEXT; + #endif + #if defined(GLX_SGI_swap_control) + PFNGLXSWAPINTERVALSGIPROC pGlxSwapIntervalSGI; + #endif + #if defined(GLX_EXT_swap_control) + PFNGLXSWAPINTERVALEXTPROC pGlxSwapIntervalEXT; + #endif + #if defined(GLX_MESA_swap_control) + PFNGLXSWAPINTERVALMESAPROC pGlxSwapIntervalMESA; + #endif + #endif +}; + +inline void COpenGLExtensionHandler::irrGlActiveTexture(GLenum texture) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlActiveTexture) + pGlActiveTexture(texture); + else if (pGlActiveTextureARB) + pGlActiveTextureARB(texture); +#else +#ifdef GL_ARB_multitexture + glActiveTextureARB(texture); +#else + glActiveTexture(texture); +#endif +#endif +} + +inline void COpenGLExtensionHandler::irrGlClientActiveTexture(GLenum texture) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlClientActiveTextureARB) + pGlClientActiveTextureARB(texture); +#else + glClientActiveTextureARB(texture); +#endif +} + +inline void COpenGLExtensionHandler::extGlGenPrograms(GLsizei n, GLuint *programs) +{ + if (programs) + memset(programs,0,n*sizeof(GLuint)); +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGenProgramsARB) + pGlGenProgramsARB(n, programs); + else if (pGlGenProgramsNV) + pGlGenProgramsNV(n, programs); +#elif defined(GL_ARB_vertex_program) || defined(GL_ARB_fragment_program) + glGenProgramsARB(n,programs); +#elif defined(GL_NV_vertex_program) || defined(GL_NV_fragment_program) + glGenProgramsNV(n,programs); +#else + os::Printer::log("glGenPrograms not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlBindProgram(GLenum target, GLuint program) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlBindProgramARB) + pGlBindProgramARB(target, program); + else if (pGlBindProgramNV) + pGlBindProgramNV(target, program); +#elif defined(GL_ARB_vertex_program) || defined(GL_ARB_fragment_program) + glBindProgramARB(target, program); +#elif defined(GL_NV_vertex_program) || defined(GL_NV_fragment_program) + glBindProgramNV(target, program); +#else + os::Printer::log("glBindProgram not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlProgramString(GLenum target, GLenum format, GLsizei len, const GLvoid *string) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlProgramStringARB) + pGlProgramStringARB(target, format, len, string); +#elif defined(GL_ARB_vertex_program) || defined(GL_ARB_fragment_program) + glProgramStringARB(target,format,len,string); +#else + os::Printer::log("glProgramString not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlLoadProgram(GLenum target, GLuint id, GLsizei len, const GLubyte *string) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlLoadProgramNV) + pGlLoadProgramNV(target, id, len, string); +#elif defined(GL_NV_vertex_program) || defined(GL_NV_fragment_program) + glLoadProgramNV(target,id,len,string); +#else + os::Printer::log("glLoadProgram not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlDeletePrograms(GLsizei n, const GLuint *programs) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlDeleteProgramsARB) + pGlDeleteProgramsARB(n, programs); + else if (pGlDeleteProgramsNV) + pGlDeleteProgramsNV(n, programs); +#elif defined(GL_ARB_vertex_program) || defined(GL_ARB_fragment_program) + glDeleteProgramsARB(n,programs); +#elif defined(GL_NV_vertex_program) || defined(GL_NV_fragment_program) + glDeleteProgramsNV(n,programs); +#else + os::Printer::log("glDeletePrograms not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlProgramLocalParameter4fv(GLenum n, GLuint i, const GLfloat *f) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlProgramLocalParameter4fvARB) + pGlProgramLocalParameter4fvARB(n,i,f); +#elif defined(GL_ARB_vertex_program) || defined(GL_ARB_fragment_program) + glProgramLocalParameter4fvARB(n,i,f); +#else + os::Printer::log("glProgramLocalParameter4fv not supported", ELL_ERROR); +#endif +} + +inline GLhandleARB COpenGLExtensionHandler::extGlCreateShaderObject(GLenum shaderType) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlCreateShaderObjectARB) + return pGlCreateShaderObjectARB(shaderType); +#elif defined(GL_ARB_shader_objects) + return glCreateShaderObjectARB(shaderType); +#else + os::Printer::log("glCreateShaderObject not supported", ELL_ERROR); +#endif + return 0; +} + +inline GLuint COpenGLExtensionHandler::extGlCreateShader(GLenum shaderType) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlCreateShader) + return pGlCreateShader(shaderType); +#elif defined(GL_VERSION_2_0) + return glCreateShader(shaderType); +#else + os::Printer::log("glCreateShader not supported", ELL_ERROR); +#endif + return 0; +} + +inline void COpenGLExtensionHandler::extGlShaderSourceARB(GLhandleARB shader, GLsizei numOfStrings, const char **strings, const GLint *lenOfStrings) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlShaderSourceARB) + pGlShaderSourceARB(shader, numOfStrings, strings, lenOfStrings); +#elif defined(GL_ARB_shader_objects) + glShaderSourceARB(shader, numOfStrings, strings, (GLint *)lenOfStrings); +#else + os::Printer::log("glShaderSource not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlShaderSource(GLuint shader, GLsizei numOfStrings, const char **strings, const GLint *lenOfStrings) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlShaderSource) + pGlShaderSource(shader, numOfStrings, strings, lenOfStrings); +#elif defined(GL_VERSION_2_0) + glShaderSource(shader, numOfStrings, strings, (GLint *)lenOfStrings); +#else + os::Printer::log("glShaderSource not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlCompileShaderARB(GLhandleARB shader) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlCompileShaderARB) + pGlCompileShaderARB(shader); +#elif defined(GL_ARB_shader_objects) + glCompileShaderARB(shader); +#else + os::Printer::log("glCompileShader not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlCompileShader(GLuint shader) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlCompileShader) + pGlCompileShader(shader); +#elif defined(GL_VERSION_2_0) + glCompileShader(shader); +#else + os::Printer::log("glCompileShader not supported", ELL_ERROR); +#endif +} + +inline GLhandleARB COpenGLExtensionHandler::extGlCreateProgramObject(void) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlCreateProgramObjectARB) + return pGlCreateProgramObjectARB(); +#elif defined(GL_ARB_shader_objects) + return glCreateProgramObjectARB(); +#else + os::Printer::log("glCreateProgramObject not supported", ELL_ERROR); +#endif + return 0; +} + +inline GLuint COpenGLExtensionHandler::extGlCreateProgram(void) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlCreateProgram) + return pGlCreateProgram(); +#elif defined(GL_VERSION_2_0) + return glCreateProgram(); +#else + os::Printer::log("glCreateProgram not supported", ELL_ERROR); +#endif + return 0; +} + +inline void COpenGLExtensionHandler::extGlAttachObject(GLhandleARB program, GLhandleARB shader) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlAttachObjectARB) + pGlAttachObjectARB(program, shader); +#elif defined(GL_ARB_shader_objects) + glAttachObjectARB(program, shader); +#else + os::Printer::log("glAttachObject not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlAttachShader(GLuint program, GLuint shader) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlAttachShader) + pGlAttachShader(program, shader); +#elif defined(GL_VERSION_2_0) + glAttachShader(program, shader); +#else + os::Printer::log("glAttachShader not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlLinkProgramARB(GLhandleARB program) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlLinkProgramARB) + pGlLinkProgramARB(program); +#elif defined(GL_ARB_shader_objects) + glLinkProgramARB(program); +#else + os::Printer::log("glLinkProgram not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlLinkProgram(GLuint program) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlLinkProgram) + pGlLinkProgram(program); +#elif defined(GL_VERSION_2_0) + glLinkProgram(program); +#else + os::Printer::log("glLinkProgram not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlUseProgramObject(GLhandleARB prog) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlUseProgramObjectARB) + pGlUseProgramObjectARB(prog); +#elif defined(GL_ARB_shader_objects) + glUseProgramObjectARB(prog); +#else + os::Printer::log("glUseProgramObject not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlUseProgram(GLuint prog) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlUseProgram) + pGlUseProgram(prog); +#elif defined(GL_VERSION_2_0) + glUseProgram(prog); +#else + os::Printer::log("glUseProgram not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlDeleteObject(GLhandleARB object) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlDeleteObjectARB) + pGlDeleteObjectARB(object); +#elif defined(GL_ARB_shader_objects) + glDeleteObjectARB(object); +#else + os::Printer::log("glDeleteObject not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlDeleteProgram(GLuint object) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlDeleteProgram) + pGlDeleteProgram(object); +#elif defined(GL_VERSION_2_0) + glDeleteProgram(object); +#else + os::Printer::log("glDeleteProgram not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlDeleteShader(GLuint shader) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlDeleteShader) + pGlDeleteShader(shader); +#elif defined(GL_VERSION_2_0) + glDeleteShader(shader); +#else + os::Printer::log("glDeleteShader not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlGetAttachedObjects(GLhandleARB program, GLsizei maxcount, GLsizei* count, GLhandleARB* shaders) +{ + if (count) + *count=0; +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGetAttachedObjectsARB) + pGlGetAttachedObjectsARB(program, maxcount, count, shaders); +#elif defined(GL_ARB_shader_objects) + glGetAttachedObjectsARB(program, maxcount, count, shaders); +#else + os::Printer::log("glGetAttachedObjects not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) +{ + if (count) + *count=0; +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGetAttachedShaders) + pGlGetAttachedShaders(program, maxcount, count, shaders); +#elif defined(GL_VERSION_2_0) + glGetAttachedShaders(program, maxcount, count, shaders); +#else + os::Printer::log("glGetAttachedShaders not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlGetInfoLog(GLhandleARB object, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog) +{ + if (length) + *length=0; +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGetInfoLogARB) + pGlGetInfoLogARB(object, maxLength, length, infoLog); +#elif defined(GL_ARB_shader_objects) + glGetInfoLogARB(object, maxLength, length, infoLog); +#else + os::Printer::log("glGetInfoLog not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlGetShaderInfoLog(GLuint shader, GLsizei maxLength, GLsizei *length, GLchar *infoLog) +{ + if (length) + *length=0; +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGetShaderInfoLog) + pGlGetShaderInfoLog(shader, maxLength, length, infoLog); +#elif defined(GL_VERSION_2_0) + glGetShaderInfoLog(shader, maxLength, length, infoLog); +#else + os::Printer::log("glGetShaderInfoLog not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlGetProgramInfoLog(GLuint program, GLsizei maxLength, GLsizei *length, GLchar *infoLog) +{ + if (length) + *length=0; +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGetProgramInfoLog) + pGlGetProgramInfoLog(program, maxLength, length, infoLog); +#elif defined(GL_VERSION_2_0) + glGetProgramInfoLog(program, maxLength, length, infoLog); +#else + os::Printer::log("glGetProgramInfoLog not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlGetObjectParameteriv(GLhandleARB object, GLenum type, GLint *param) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGetObjectParameterivARB) + pGlGetObjectParameterivARB(object, type, param); +#elif defined(GL_ARB_shader_objects) + glGetObjectParameterivARB(object, type, param); +#else + os::Printer::log("glGetObjectParameteriv not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlGetShaderiv(GLuint shader, GLenum type, GLint *param) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGetShaderiv) + pGlGetShaderiv(shader, type, param); +#elif defined(GL_VERSION_2_0) + glGetShaderiv(shader, type, param); +#else + os::Printer::log("glGetShaderiv not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlGetProgramiv(GLuint program, GLenum type, GLint *param) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGetProgramiv) + pGlGetProgramiv(program, type, param); +#elif defined(GL_VERSION_2_0) + glGetProgramiv(program, type, param); +#else + os::Printer::log("glGetProgramiv not supported", ELL_ERROR); +#endif +} + +inline GLint COpenGLExtensionHandler::extGlGetUniformLocationARB(GLhandleARB program, const char *name) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGetUniformLocationARB) + return pGlGetUniformLocationARB(program, name); +#elif defined(GL_ARB_shader_objects) + return glGetUniformLocationARB(program, name); +#else + os::Printer::log("glGetUniformLocation not supported", ELL_ERROR); +#endif + return 0; +} + +inline GLint COpenGLExtensionHandler::extGlGetUniformLocation(GLuint program, const char *name) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGetUniformLocation) + return pGlGetUniformLocation(program, name); +#elif defined(GL_VERSION_2_0) + return glGetUniformLocation(program, name); +#else + os::Printer::log("glGetUniformLocation not supported", ELL_ERROR); +#endif + return 0; +} + +inline void COpenGLExtensionHandler::extGlUniform1fv(GLint loc, GLsizei count, const GLfloat *v) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlUniform1fvARB) + pGlUniform1fvARB(loc, count, v); +#elif defined(GL_ARB_shader_objects) + glUniform1fvARB(loc, count, v); +#else + os::Printer::log("glUniform1fv not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlUniform2fv(GLint loc, GLsizei count, const GLfloat *v) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlUniform2fvARB) + pGlUniform2fvARB(loc, count, v); +#elif defined(GL_ARB_shader_objects) + glUniform2fvARB(loc, count, v); +#else + os::Printer::log("glUniform2fv not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlUniform3fv(GLint loc, GLsizei count, const GLfloat *v) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlUniform3fvARB) + pGlUniform3fvARB(loc, count, v); +#elif defined(GL_ARB_shader_objects) + glUniform3fvARB(loc, count, v); +#else + os::Printer::log("glUniform3fv not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlUniform4fv(GLint loc, GLsizei count, const GLfloat *v) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlUniform4fvARB) + pGlUniform4fvARB(loc, count, v); +#elif defined(GL_ARB_shader_objects) + glUniform4fvARB(loc, count, v); +#else + os::Printer::log("glUniform4fv not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlUniform1iv(GLint loc, GLsizei count, const GLint *v) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlUniform1ivARB) + pGlUniform1ivARB(loc, count, v); +#elif defined(GL_ARB_shader_objects) + glUniform1ivARB(loc, count, v); +#else + os::Printer::log("glUniform1iv not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlUniform2iv(GLint loc, GLsizei count, const GLint *v) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlUniform2ivARB) + pGlUniform2ivARB(loc, count, v); +#elif defined(GL_ARB_shader_objects) + glUniform2ivARB(loc, count, v); +#else + os::Printer::log("glUniform2iv not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlUniform3iv(GLint loc, GLsizei count, const GLint *v) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlUniform3ivARB) + pGlUniform3ivARB(loc, count, v); +#elif defined(GL_ARB_shader_objects) + glUniform3ivARB(loc, count, v); +#else + os::Printer::log("glUniform3iv not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlUniform4iv(GLint loc, GLsizei count, const GLint *v) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlUniform4ivARB) + pGlUniform4ivARB(loc, count, v); +#elif defined(GL_ARB_shader_objects) + glUniform4ivARB(loc, count, v); +#else + os::Printer::log("glUniform4iv not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlUniformMatrix2fv(GLint loc, GLsizei count, GLboolean transpose, const GLfloat *v) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlUniformMatrix2fvARB) + pGlUniformMatrix2fvARB(loc, count, transpose, v); +#elif defined(GL_ARB_shader_objects) + glUniformMatrix2fvARB(loc, count, transpose, v); +#else + os::Printer::log("glUniformMatrix2fv not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlUniformMatrix3fv(GLint loc, GLsizei count, GLboolean transpose, const GLfloat *v) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlUniformMatrix3fvARB) + pGlUniformMatrix3fvARB(loc, count, transpose, v); +#elif defined(GL_ARB_shader_objects) + glUniformMatrix3fvARB(loc, count, transpose, v); +#else + os::Printer::log("glUniformMatrix3fv not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlUniformMatrix4fv(GLint loc, GLsizei count, GLboolean transpose, const GLfloat *v) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlUniformMatrix4fvARB) + pGlUniformMatrix4fvARB(loc, count, transpose, v); +#elif defined(GL_ARB_shader_objects) + glUniformMatrix4fvARB(loc, count, transpose, v); +#else + os::Printer::log("glUniformMatrix4fv not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlGetActiveUniformARB(GLhandleARB program, + GLuint index, GLsizei maxlength, GLsizei *length, + GLint *size, GLenum *type, GLcharARB *name) +{ + if (length) + *length=0; +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGetActiveUniformARB) + pGlGetActiveUniformARB(program, index, maxlength, length, size, type, name); +#elif defined(GL_ARB_shader_objects) + glGetActiveUniformARB(program, index, maxlength, length, size, type, name); +#else + os::Printer::log("glGetActiveUniform not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlGetActiveUniform(GLuint program, + GLuint index, GLsizei maxlength, GLsizei *length, + GLint *size, GLenum *type, GLchar *name) +{ + if (length) + *length=0; +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGetActiveUniform) + pGlGetActiveUniform(program, index, maxlength, length, size, type, name); +#elif defined(GL_VERSION_2_0) + glGetActiveUniform(program, index, maxlength, length, size, type, name); +#else + os::Printer::log("glGetActiveUniform not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlPointParameterf(GLint loc, GLfloat f) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlPointParameterfARB) + pGlPointParameterfARB(loc, f); +#elif defined(GL_ARB_point_parameters) + glPointParameterfARB(loc, f); +#else + os::Printer::log("glPointParameterf not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlPointParameterfv(GLint loc, const GLfloat *v) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlPointParameterfvARB) + pGlPointParameterfvARB(loc, v); +#elif defined(GL_ARB_point_parameters) + glPointParameterfvARB(loc, v); +#else + os::Printer::log("glPointParameterfv not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlStencilFuncSeparate (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlStencilFuncSeparate) + pGlStencilFuncSeparate(frontfunc, backfunc, ref, mask); + else if (pGlStencilFuncSeparateATI) + pGlStencilFuncSeparateATI(frontfunc, backfunc, ref, mask); +#elif defined(GL_VERSION_2_0) + glStencilFuncSeparate(frontfunc, backfunc, ref, mask); +#elif defined(GL_ATI_separate_stencil) + glStencilFuncSeparateATI(frontfunc, backfunc, ref, mask); +#else + os::Printer::log("glStencilFuncSeparate not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlStencilOpSeparate) + pGlStencilOpSeparate(face, fail, zfail, zpass); + else if (pGlStencilOpSeparateATI) + pGlStencilOpSeparateATI(face, fail, zfail, zpass); +#elif defined(GL_VERSION_2_0) + glStencilOpSeparate(face, fail, zfail, zpass); +#elif defined(GL_ATI_separate_stencil) + glStencilOpSeparateATI(face, fail, zfail, zpass); +#else + os::Printer::log("glStencilOpSeparate not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, + GLsizei height, GLint border, GLsizei imageSize, const void* data) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlCompressedTexImage2D) + pGlCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); +#elif defined(GL_ARB_texture_compression) + glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); +#else + os::Printer::log("glCompressedTexImage2D not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlCompressedTexSubImage2D) + pGlCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); +#elif defined(GL_ARB_texture_compression) + glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); +#else + os::Printer::log("glCompressedTexSubImage2D not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlBindFramebuffer(GLenum target, GLuint framebuffer) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlBindFramebuffer) + pGlBindFramebuffer(target, framebuffer); + else if (pGlBindFramebufferEXT) + pGlBindFramebufferEXT(target, framebuffer); +#elif defined(GL_ARB_framebuffer_object) + glBindFramebuffer(target, framebuffer); +#elif defined(GL_EXT_framebuffer_object) + glBindFramebufferEXT(target, framebuffer); +#else + os::Printer::log("glBindFramebuffer not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlDeleteFramebuffers(GLsizei n, const GLuint *framebuffers) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlDeleteFramebuffers) + pGlDeleteFramebuffers(n, framebuffers); + else if (pGlDeleteFramebuffersEXT) + pGlDeleteFramebuffersEXT(n, framebuffers); +#elif defined(GL_ARB_framebuffer_object) + glDeleteFramebuffers(n, framebuffers); +#elif defined(GL_EXT_framebuffer_object) + glDeleteFramebuffersEXT(n, framebuffers); +#else + os::Printer::log("glDeleteFramebuffers not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlGenFramebuffers(GLsizei n, GLuint *framebuffers) +{ + if (framebuffers) + memset(framebuffers,0,n*sizeof(GLuint)); +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGenFramebuffers) + pGlGenFramebuffers(n, framebuffers); + else if (pGlGenFramebuffersEXT) + pGlGenFramebuffersEXT(n, framebuffers); +#elif defined(GL_ARB_framebuffer_object) + glGenFramebuffers(n, framebuffers); +#elif defined(GL_EXT_framebuffer_object) + glGenFramebuffersEXT(n, framebuffers); +#else + os::Printer::log("glGenFramebuffers not supported", ELL_ERROR); +#endif +} + +inline GLenum COpenGLExtensionHandler::irrGlCheckFramebufferStatus(GLenum target) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlCheckFramebufferStatus) + return pGlCheckFramebufferStatus(target); + else if (pGlCheckFramebufferStatusEXT) + return pGlCheckFramebufferStatusEXT(target); + else + return 0; +#elif defined(GL_ARB_framebuffer_object) + return glCheckFramebufferStatus(target); +#elif defined(GL_EXT_framebuffer_object) + return glCheckFramebufferStatusEXT(target); +#else + os::Printer::log("glCheckFramebufferStatus not supported", ELL_ERROR); + return 0; +#endif +} + +inline void COpenGLExtensionHandler::irrGlFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlFramebufferTexture2D) + pGlFramebufferTexture2D(target, attachment, textarget, texture, level); + else if (pGlFramebufferTexture2DEXT) + pGlFramebufferTexture2DEXT(target, attachment, textarget, texture, level); +#elif defined(GL_ARB_framebuffer_object) + glFramebufferTexture2D(target, attachment, textarget, texture, level); +#elif defined(GL_EXT_framebuffer_object) + glFramebufferTexture2DEXT(target, attachment, textarget, texture, level); +#else + os::Printer::log("glFramebufferTexture2D not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlBindRenderbuffer(GLenum target, GLuint renderbuffer) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlBindRenderbuffer) + pGlBindRenderbuffer(target, renderbuffer); + else if (pGlBindRenderbufferEXT) + pGlBindRenderbufferEXT(target, renderbuffer); +#elif defined(GL_ARB_framebuffer_object) + glBindRenderbuffer(target, renderbuffer); +#elif defined(GL_EXT_framebuffer_object) + glBindRenderbufferEXT(target, renderbuffer); +#else + os::Printer::log("glBindRenderbuffer not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlDeleteRenderbuffers) + pGlDeleteRenderbuffers(n, renderbuffers); + else if (pGlDeleteRenderbuffersEXT) + pGlDeleteRenderbuffersEXT(n, renderbuffers); +#elif defined(GL_ARB_framebuffer_object) + glDeleteRenderbuffers(n, renderbuffers); +#elif defined(GL_EXT_framebuffer_object) + glDeleteRenderbuffersEXT(n, renderbuffers); +#else + os::Printer::log("glDeleteRenderbuffers not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlGenRenderbuffers(GLsizei n, GLuint *renderbuffers) +{ + if (renderbuffers) + memset(renderbuffers,0,n*sizeof(GLuint)); +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGenRenderbuffers) + pGlGenRenderbuffers(n, renderbuffers); + else if (pGlGenRenderbuffersEXT) + pGlGenRenderbuffersEXT(n, renderbuffers); +#elif defined(GL_ARB_framebuffer_object) + glGenRenderbuffers(n, renderbuffers); +#elif defined(GL_EXT_framebuffer_object) + glGenRenderbuffersEXT(n, renderbuffers); +#else + os::Printer::log("glGenRenderbuffers not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlRenderbufferStorage) + pGlRenderbufferStorage(target, internalformat, width, height); + else if (pGlRenderbufferStorageEXT) + pGlRenderbufferStorageEXT(target, internalformat, width, height); +#elif defined(GL_ARB_framebuffer_object) + glRenderbufferStorage(target, internalformat, width, height); +#elif defined(GL_EXT_framebuffer_object) + glRenderbufferStorageEXT(target, internalformat, width, height); +#else + os::Printer::log("glRenderbufferStorage not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlFramebufferRenderbuffer) + pGlFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); + else if (pGlFramebufferRenderbufferEXT) + pGlFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, renderbuffer); +#elif defined(GL_ARB_framebuffer_object) + glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); +#elif defined(GL_EXT_framebuffer_object) + glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, renderbuffer); +#else + os::Printer::log("glFramebufferRenderbuffer not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlGenerateMipmap(GLenum target) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGenerateMipmap) + pGlGenerateMipmap(target); + else if (pGlGenerateMipmapEXT) + pGlGenerateMipmapEXT(target); +#elif defined(GL_ARB_framebuffer_object) + glGenerateMipmap(target); +#elif defined(GL_EXT_framebuffer_object) + glGenerateMipmapEXT(target); +#else + os::Printer::log("glGenerateMipmap not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlActiveStencilFace(GLenum face) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlActiveStencilFaceEXT) + pGlActiveStencilFaceEXT(face); +#elif defined(GL_EXT_stencil_two_side) + glActiveStencilFaceEXT(face); +#else + os::Printer::log("glActiveStencilFace not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlDrawBuffer(GLenum mode) +{ + glDrawBuffer(mode); +} + +inline void COpenGLExtensionHandler::irrGlDrawBuffers(GLsizei n, const GLenum *bufs) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlDrawBuffersARB) + pGlDrawBuffersARB(n, bufs); + else if (pGlDrawBuffersATI) + pGlDrawBuffersATI(n, bufs); +#elif defined(GL_ARB_draw_buffers) + glDrawBuffersARB(n, bufs); +#elif defined(GL_ATI_draw_buffers) + glDrawBuffersATI(n, bufs); +#else + os::Printer::log("glDrawBuffers not supported", ELL_ERROR); +#endif +} + + +inline void COpenGLExtensionHandler::extGlGenBuffers(GLsizei n, GLuint *buffers) +{ + if (buffers) + memset(buffers,0,n*sizeof(GLuint)); +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGenBuffersARB) + pGlGenBuffersARB(n, buffers); +#elif defined(GL_ARB_vertex_buffer_object) + glGenBuffers(n, buffers); +#else + os::Printer::log("glGenBuffers not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlBindBuffer(GLenum target, GLuint buffer) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlBindBufferARB) + pGlBindBufferARB(target, buffer); +#elif defined(GL_ARB_vertex_buffer_object) + glBindBuffer(target, buffer); +#else + os::Printer::log("glBindBuffer not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlBufferData(GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlBufferDataARB) + pGlBufferDataARB(target, size, data, usage); +#elif defined(GL_ARB_vertex_buffer_object) + glBufferData(target, size, data, usage); +#else + os::Printer::log("glBufferData not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlDeleteBuffers(GLsizei n, const GLuint *buffers) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlDeleteBuffersARB) + pGlDeleteBuffersARB(n, buffers); +#elif defined(GL_ARB_vertex_buffer_object) + glDeleteBuffers(n, buffers); +#else + os::Printer::log("glDeleteBuffers not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlBufferSubData(GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlBufferSubDataARB) + pGlBufferSubDataARB(target, offset, size, data); +#elif defined(GL_ARB_vertex_buffer_object) + glBufferSubData(target, offset, size, data); +#else + os::Printer::log("glBufferSubData not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlGetBufferSubData(GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGetBufferSubDataARB) + pGlGetBufferSubDataARB(target, offset, size, data); +#elif defined(GL_ARB_vertex_buffer_object) + glGetBufferSubData(target, offset, size, data); +#else + os::Printer::log("glGetBufferSubData not supported", ELL_ERROR); +#endif +} + +inline void *COpenGLExtensionHandler::extGlMapBuffer(GLenum target, GLenum access) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlMapBufferARB) + return pGlMapBufferARB(target, access); + return 0; +#elif defined(GL_ARB_vertex_buffer_object) + return glMapBuffer(target, access); +#else + os::Printer::log("glMapBuffer not supported", ELL_ERROR); + return 0; +#endif +} + +inline GLboolean COpenGLExtensionHandler::extGlUnmapBuffer(GLenum target) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlUnmapBufferARB) + return pGlUnmapBufferARB(target); + return false; +#elif defined(GL_ARB_vertex_buffer_object) + return glUnmapBuffer(target); +#else + os::Printer::log("glUnmapBuffer not supported", ELL_ERROR); + return false; +#endif +} + +inline GLboolean COpenGLExtensionHandler::extGlIsBuffer(GLuint buffer) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlIsBufferARB) + return pGlIsBufferARB(buffer); + return false; +#elif defined(GL_ARB_vertex_buffer_object) + return glIsBuffer(buffer); +#else + os::Printer::log("glDeleteBuffers not supported", ELL_ERROR); + return false; +#endif +} + +inline void COpenGLExtensionHandler::extGlGetBufferParameteriv(GLenum target, GLenum pname, GLint *params) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGetBufferParameterivARB) + pGlGetBufferParameterivARB(target, pname, params); +#elif defined(GL_ARB_vertex_buffer_object) + glGetBufferParameteriv(target, pname, params); +#else + os::Printer::log("glGetBufferParameteriv not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlGetBufferPointerv(GLenum target, GLenum pname, GLvoid **params) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGetBufferPointervARB) + pGlGetBufferPointervARB(target, pname, params); +#elif defined(GL_ARB_vertex_buffer_object) + glGetBufferPointerv(target, pname, params); +#else + os::Printer::log("glGetBufferPointerv not supported", ELL_ERROR); +#endif +} + + +inline void COpenGLExtensionHandler::extGlProvokingVertex(GLenum mode) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (FeatureAvailable[IRR_ARB_provoking_vertex] && pGlProvokingVertexARB) + pGlProvokingVertexARB(mode); + else if (FeatureAvailable[IRR_EXT_provoking_vertex] && pGlProvokingVertexEXT) + pGlProvokingVertexEXT(mode); +#elif defined(GL_ARB_provoking_vertex) + glProvokingVertex(mode); +#elif defined(GL_EXT_provoking_vertex) + glProvokingVertexEXT(mode); +#else + os::Printer::log("glProvokingVertex not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlProgramParameteri(GLuint program, GLenum pname, GLint value) +{ +#if defined(_IRR_OPENGL_USE_EXTPOINTER_) + if (queryFeature(EVDF_GEOMETRY_SHADER)) + { + if (pGlProgramParameteriARB) + pGlProgramParameteriARB(program, pname, value); + else if (pGlProgramParameteriEXT) + pGlProgramParameteriEXT(program, pname, value); + } +#elif defined(GL_ARB_geometry_shader4) + glProgramParameteriARB(program, pname, value); +#elif defined(GL_EXT_geometry_shader4) + glProgramParameteriEXT(program, pname, value); +#elif defined(GL_NV_geometry_program4) || defined(GL_NV_geometry_shader4) + glProgramParameteriNV(program, pname, value); +#else + os::Printer::log("glProgramParameteri not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlGenQueries(GLsizei n, GLuint *ids) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGenQueriesARB) + pGlGenQueriesARB(n, ids); + else if (pGlGenOcclusionQueriesNV) + pGlGenOcclusionQueriesNV(n, ids); +#elif defined(GL_ARB_occlusion_query) + glGenQueriesARB(n, ids); +#elif defined(GL_NV_occlusion_query) + glGenOcclusionQueriesNV(n, ids); +#else + os::Printer::log("glGenQueries not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlDeleteQueries(GLsizei n, const GLuint *ids) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlDeleteQueriesARB) + pGlDeleteQueriesARB(n, ids); + else if (pGlDeleteOcclusionQueriesNV) + pGlDeleteOcclusionQueriesNV(n, ids); +#elif defined(GL_ARB_occlusion_query) + glDeleteQueriesARB(n, ids); +#elif defined(GL_NV_occlusion_query) + glDeleteOcclusionQueriesNV(n, ids); +#else + os::Printer::log("glDeleteQueries not supported", ELL_ERROR); +#endif +} + +inline GLboolean COpenGLExtensionHandler::extGlIsQuery(GLuint id) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlIsQueryARB) + return pGlIsQueryARB(id); + else if (pGlIsOcclusionQueryNV) + return pGlIsOcclusionQueryNV(id); + return false; +#elif defined(GL_ARB_occlusion_query) + return glIsQueryARB(id); +#elif defined(GL_NV_occlusion_query) + return glIsOcclusionQueryNV(id); +#else + return false; +#endif +} + +inline void COpenGLExtensionHandler::extGlBeginQuery(GLenum target, GLuint id) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlBeginQueryARB) + pGlBeginQueryARB(target, id); + else if (pGlBeginOcclusionQueryNV) + pGlBeginOcclusionQueryNV(id); +#elif defined(GL_ARB_occlusion_query) + glBeginQueryARB(target, id); +#elif defined(GL_NV_occlusion_query) + glBeginOcclusionQueryNV(id); +#else + os::Printer::log("glBeginQuery not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlEndQuery(GLenum target) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlEndQueryARB) + pGlEndQueryARB(target); + else if (pGlEndOcclusionQueryNV) + pGlEndOcclusionQueryNV(); +#elif defined(GL_ARB_occlusion_query) + glEndQueryARB(target); +#elif defined(GL_NV_occlusion_query) + glEndOcclusionQueryNV(); +#else + os::Printer::log("glEndQuery not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlGetQueryiv(GLenum target, GLenum pname, GLint *params) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGetQueryivARB) + pGlGetQueryivARB(target, pname, params); +#elif defined(GL_ARB_occlusion_query) + glGetQueryivARB(target, pname, params); +#else + os::Printer::log("glGetQueryivARB not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlGetQueryObjectiv(GLuint id, GLenum pname, GLint *params) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGetQueryObjectivARB) + pGlGetQueryObjectivARB(id, pname, params); + else if (pGlGetOcclusionQueryivNV) + pGlGetOcclusionQueryivNV(id, pname, params); +#elif defined(GL_ARB_occlusion_query) + glGetQueryObjectivARB(id, pname, params); +#elif defined(GL_NV_occlusion_query) + glGetOcclusionQueryivNV(id, pname, params); +#else + os::Printer::log("glGetQueryObjectiv not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlGetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGetQueryObjectuivARB) + pGlGetQueryObjectuivARB(id, pname, params); + else if (pGlGetOcclusionQueryuivNV) + pGlGetOcclusionQueryuivNV(id, pname, params); +#elif defined(GL_ARB_occlusion_query) + glGetQueryObjectuivARB(id, pname, params); +#elif defined(GL_NV_occlusion_query) + glGetOcclusionQueryuivNV(id, pname, params); +#else + os::Printer::log("glGetQueryObjectuiv not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlBlendFuncSeparate) + pGlBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); + else if (pGlBlendFuncSeparateEXT) + pGlBlendFuncSeparateEXT(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); +#elif defined(GL_VERSION_1_4) + glBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); +#elif defined(GL_EXT_blend_func_separate) + glBlendFuncSeparateEXT(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); +#else + os::Printer::log("glBlendFuncSeparate not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlBlendEquation(GLenum mode) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlBlendEquation) + pGlBlendEquation(mode); + else if (pGlBlendEquationEXT) + pGlBlendEquationEXT(mode); +#elif defined(GL_VERSION_1_4) + glBlendEquation(mode); +#elif defined(GL_EXT_blend_minmax) + glBlendEquationEXT(mode); +#else + os::Printer::log("glBlendEquation not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlEnableIndexed(GLenum target, GLuint index) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (FeatureAvailable[IRR_EXT_draw_buffers2] && pGlEnableIndexedEXT) + pGlEnableIndexedEXT(target, index); +#elif defined(GL_EXT_draw_buffers2) + glEnableIndexedEXT(target, index); +#else + os::Printer::log("glEnableIndexed not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlDisableIndexed(GLenum target, GLuint index) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (FeatureAvailable[IRR_EXT_draw_buffers2] && pGlDisableIndexedEXT) + pGlDisableIndexedEXT(target, index); +#elif defined(GL_EXT_draw_buffers2) + glDisableIndexedEXT(target, index); +#else + os::Printer::log("glDisableIndexed not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlColorMaskIndexed(GLuint buf, GLboolean r, GLboolean g, GLboolean b, GLboolean a) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (FeatureAvailable[IRR_EXT_draw_buffers2] && pGlColorMaskIndexedEXT) + pGlColorMaskIndexedEXT(buf, r, g, b, a); +#elif defined(GL_EXT_draw_buffers2) + glColorMaskIndexedEXT(buf, r, g, b, a); +#else + os::Printer::log("glColorMaskIndexed not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlBlendFuncIndexed(GLuint buf, GLenum src, GLenum dst) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (FeatureAvailable[IRR_ARB_draw_buffers_blend] && pGlBlendFunciARB) + pGlBlendFunciARB(buf, src, dst); + else if (FeatureAvailable[IRR_AMD_draw_buffers_blend] && pGlBlendFuncIndexedAMD) + pGlBlendFuncIndexedAMD(buf, src, dst); +#elif defined(GL_ARB_draw_buffers_blend) + glBlendFunciARB(buf, src, dst); +#elif defined(GL_AMD_draw_buffers_blend) + glBlendFuncIndexedAMD(buf, src, dst); +#else + os::Printer::log("glBlendFuncIndexed not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlBlendFuncSeparateIndexed(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (FeatureAvailable[IRR_ARB_draw_buffers_blend] && pGlBlendFuncSeparateiARB) + pGlBlendFuncSeparateiARB(buf, srcRGB, dstRGB, srcAlpha, dstAlpha); + else if (FeatureAvailable[IRR_AMD_draw_buffers_blend] && pGlBlendFuncSeparateIndexedAMD) + pGlBlendFuncSeparateIndexedAMD(buf, srcRGB, dstRGB, srcAlpha, dstAlpha); +#elif defined(GL_ARB_draw_buffers_blend) + glBlendFuncSeparateiARB(buf, srcRGB, dstRGB, srcAlpha, dstAlpha); +#elif defined(GL_AMD_draw_buffers_blend) + glBlendFuncSeparateIndexedAMD(buf, srcRGB, dstRGB, srcAlpha, dstAlpha); +#else + os::Printer::log("glBlendFuncSeparateIndexed not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlBlendEquationIndexed(GLuint buf, GLenum mode) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (FeatureAvailable[IRR_ARB_draw_buffers_blend] && pGlBlendEquationiARB) + pGlBlendEquationiARB(buf, mode); + else if (FeatureAvailable[IRR_AMD_draw_buffers_blend] && pGlBlendEquationIndexedAMD) + pGlBlendEquationIndexedAMD(buf, mode); +#elif defined(GL_ARB_draw_buffers_blend) + glBlendEquationiARB(buf, mode); +#elif defined(GL_AMD_draw_buffers_blend) + glBlendEquationIndexedAMD(buf, mode); +#else + os::Printer::log("glBlendEquationIndexed not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::irrGlBlendEquationSeparateIndexed(GLuint buf, GLenum modeRGB, GLenum modeAlpha) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (FeatureAvailable[IRR_ARB_draw_buffers_blend] && pGlBlendEquationSeparateiARB) + pGlBlendEquationSeparateiARB(buf, modeRGB, modeAlpha); + else if (FeatureAvailable[IRR_AMD_draw_buffers_blend] && pGlBlendEquationSeparateIndexedAMD) + pGlBlendEquationSeparateIndexedAMD(buf, modeRGB, modeAlpha); +#elif defined(GL_ARB_draw_buffers_blend) + glBlendEquationSeparateiARB(buf, modeRGB, modeAlpha); +#elif defined(GL_AMD_draw_buffers_blend) + glBlendEquationSeparateIndexedAMD(buf, modeRGB, modeAlpha); +#else + os::Printer::log("glBlendEquationSeparateIndexed not supported", ELL_ERROR); +#endif +} + +inline void COpenGLExtensionHandler::extGlTextureSubImage2D(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels) +{ + if (Version>=450) + { +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlTextureSubImage2D) + pGlTextureSubImage2D(texture, level, xoffset, yoffset,width, height,format, type, pixels); +#else + glTextureSubImage2D(texture, level, xoffset, yoffset,width, height,format, type, pixels)); +#endif // _IRR_OPENGL_USE_EXTPOINTER_ + } + else if (FeatureAvailable[IRR_EXT_direct_state_access]) + { +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlTextureSubImage2DEXT) + pGlTextureSubImage2DEXT(texture, target, level, xoffset, yoffset,width, height,format, type, pixels); +#else + glTextureSubImage2DEXT(texture, target, level, xoffset, yoffset,width, height,format, type, pixels)); +#endif // _IRR_OPENGL_USE_EXTPOINTER_ + } + else + { + GLint bound; + switch (target) + { + case GL_TEXTURE_1D_ARRAY: + glGetIntegerv(GL_TEXTURE_BINDING_1D_ARRAY, &bound); + break; + case GL_TEXTURE_2D: + glGetIntegerv(GL_TEXTURE_BINDING_2D, &bound); + break; + case GL_TEXTURE_2D_MULTISAMPLE: + glGetIntegerv(GL_TEXTURE_BINDING_2D_MULTISAMPLE, &bound); + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &bound); + break; + case GL_TEXTURE_RECTANGLE: + glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE, &bound); + break; + default: + return; + } + glBindTexture(target, texture); + glTexSubImage2D(target, level, xoffset, yoffset,width, height,format, type, pixels); + glBindTexture(target, bound); + } +} + +inline void COpenGLExtensionHandler::extGlTextureStorage2D(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +{ + if (Version>=450) + { +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlTextureStorage2D) + pGlTextureStorage2D(texture,levels,internalformat,width,height); +#else + glTextureStorage2D(texture,levels,internalformat,width,height); +#endif // _IRR_OPENGL_USE_EXTPOINTER_ + } + else if (FeatureAvailable[IRR_EXT_direct_state_access]) + { +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlTextureStorage2DEXT) + pGlTextureStorage2DEXT(texture,target,levels,internalformat,width,height); +#else + glTextureStorage2DEXT(texture,target,levels,internalformat,width,height); +#endif // _IRR_OPENGL_USE_EXTPOINTER_ + } +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + else if (pGlTexStorage2D) +#else + else +#endif // _IRR_OPENGL_USE_EXTPOINTER_ + { + GLint bound; + switch (target) + { + case GL_TEXTURE_1D_ARRAY: + glGetIntegerv(GL_TEXTURE_BINDING_1D_ARRAY, &bound); + break; + case GL_TEXTURE_2D: + glGetIntegerv(GL_TEXTURE_BINDING_2D, &bound); + break; + case GL_TEXTURE_CUBE_MAP: + glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &bound); + break; + case GL_TEXTURE_RECTANGLE: + glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE, &bound); + break; + default: + return; + } + glBindTexture(target, texture); +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + pGlTexStorage2D(target,levels,internalformat,width,height); +#else + glTexStorage2D(target,levels,internalformat,width,height); +#endif // _IRR_OPENGL_USE_EXTPOINTER_ + glBindTexture(target, bound); + } +} + +inline void COpenGLExtensionHandler::extGlTextureStorage3D(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +{ + if (Version>=450) + { +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlTextureStorage3D) + pGlTextureStorage3D(texture,levels,internalformat,width,height,depth); +#else + glTextureStorage3D(texture,levels,internalformat,width,height,depth); +#endif // _IRR_OPENGL_USE_EXTPOINTER_ + } + else if (FeatureAvailable[IRR_EXT_direct_state_access]) + { +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlTextureStorage3DEXT) + pGlTextureStorage3DEXT(texture,target,levels,internalformat,width,height,depth); +#else + glTextureStorage3DEXT(texture,target,levels,internalformat,width,height,depth); +#endif // _IRR_OPENGL_USE_EXTPOINTER_ + } +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + else if (pGlTexStorage3D) +#else + else +#endif // _IRR_OPENGL_USE_EXTPOINTER_ + { + GLint bound; + switch (target) + { + case GL_TEXTURE_2D_ARRAY: + glGetIntegerv(GL_TEXTURE_BINDING_2D_ARRAY, &bound); + break; + case GL_TEXTURE_3D: + glGetIntegerv(GL_TEXTURE_BINDING_3D, &bound); + break; + case GL_TEXTURE_CUBE_MAP_ARRAY: + glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARRAY, &bound); + break; + default: + return; + } + glBindTexture(target, texture); +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + pGlTexStorage3D(target,levels,internalformat,width,height,depth); +#else + glTexStorage3D(target,levels,internalformat,width,height,depth); +#endif // _IRR_OPENGL_USE_EXTPOINTER_ + glBindTexture(target, bound); + } +} + +inline void COpenGLExtensionHandler::extGlNamedFramebufferTexture(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level) +{ + if (!needsDSAFramebufferHack) + { + if (Version>=450) + { + pGlNamedFramebufferTexture(framebuffer, attachment, texture, level); + return; + } + else if (FeatureAvailable[IRR_EXT_direct_state_access]) + { + pGlNamedFramebufferTextureEXT(framebuffer, attachment, texture, level); + return; + } + } + + GLuint bound; + glGetIntegerv(GL_FRAMEBUFFER_BINDING,reinterpret_cast(&bound)); + + if (bound!=framebuffer) + pGlBindFramebuffer(GL_FRAMEBUFFER,framebuffer); + pGlFramebufferTexture(GL_FRAMEBUFFER,attachment,texture,level); + if (bound!=framebuffer) + pGlBindFramebuffer(GL_FRAMEBUFFER,bound); +} + +inline void COpenGLExtensionHandler::extGlTextureParameteri(GLuint texture, GLenum pname, GLint param) +{ +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlTextureParameteri) + pGlTextureParameteri(texture, pname, param); +#else + // TODO +#endif//_IRR_OPENGL_USE_EXTPOINTER_ +} + +inline void COpenGLExtensionHandler::extGlCreateTextures(GLenum target, GLsizei n, GLuint* textures) +{ + if (Version>=450) + { +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlCreateTextures) + pGlCreateTextures(target,n,textures); + else if (textures) + memset(textures,0,n*sizeof(GLuint)); +#else + glCreateTextures(target,n,textures); +#endif // _IRR_OPENGL_USE_EXTPOINTER_ + } + else + { + glGenTextures(n,textures); + } +} + +inline void COpenGLExtensionHandler::extGlCreateFramebuffers(GLsizei n, GLuint* framebuffers) +{ + if (!needsDSAFramebufferHack) + { + if (Version>=450) + { + pGlCreateFramebuffers(n, framebuffers); + return; + } + } + + pGlGenFramebuffers(n, framebuffers); +} + +inline void COpenGLExtensionHandler::extGlBindTextures(GLuint first, GLsizei count, const GLuint *textures, const GLenum* targets) +{ + const GLenum supportedTargets[] = { GL_TEXTURE_1D,GL_TEXTURE_2D, // GL 1.x + GL_TEXTURE_3D,GL_TEXTURE_RECTANGLE,GL_TEXTURE_CUBE_MAP, // GL 2.x + GL_TEXTURE_1D_ARRAY,GL_TEXTURE_2D_ARRAY,GL_TEXTURE_BUFFER, // GL 3.x + GL_TEXTURE_CUBE_MAP_ARRAY,GL_TEXTURE_2D_MULTISAMPLE,GL_TEXTURE_2D_MULTISAMPLE_ARRAY}; // GL 4.x + + if (Version>=440||FeatureAvailable[IRR_ARB_multi_bind]) + { +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlBindTextures) + pGlBindTextures(first,count,textures); +#else + glBindTextures(first,count,textures); +#endif // _IRR_OPENGL_USE_EXTPOINTER_ + } + else + { + GLint activeTex = 0; + glGetIntegerv(GL_ACTIVE_TEXTURE,&activeTex); + + for (GLsizei i=0; i=450) + { +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGenerateTextureMipmap) + pGlGenerateTextureMipmap(texture); +#else + glGenerateTextureMipmap(texture); +#endif // _IRR_OPENGL_USE_EXTPOINTER_ + } + else if (FeatureAvailable[IRR_EXT_direct_state_access]) + { +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlGenerateTextureMipmapEXT) + pGlGenerateTextureMipmapEXT(texture,target); +#else + glGenerateTextureMipmapEXT(texture,target); +#endif // _IRR_OPENGL_USE_EXTPOINTER_ + } +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + else if (pGlGenerateMipmap) +#else + else +#endif // _IRR_OPENGL_USE_EXTPOINTER_ + { + GLint bound; + switch (target) + { + case GL_TEXTURE_1D: + glGetIntegerv(GL_TEXTURE_BINDING_1D, &bound); + break; + case GL_TEXTURE_1D_ARRAY: + glGetIntegerv(GL_TEXTURE_BINDING_1D_ARRAY, &bound); + break; + case GL_TEXTURE_2D: + glGetIntegerv(GL_TEXTURE_BINDING_2D, &bound); + break; + case GL_TEXTURE_2D_ARRAY: + glGetIntegerv(GL_TEXTURE_BINDING_2D_ARRAY, &bound); + break; + case GL_TEXTURE_2D_MULTISAMPLE: + glGetIntegerv(GL_TEXTURE_BINDING_2D_MULTISAMPLE, &bound); + break; + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + glGetIntegerv(GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY, &bound); + break; + case GL_TEXTURE_3D: + glGetIntegerv(GL_TEXTURE_BINDING_3D, &bound); + break; + case GL_TEXTURE_BUFFER: + glGetIntegerv(GL_TEXTURE_BINDING_BUFFER, &bound); + break; + case GL_TEXTURE_CUBE_MAP: + glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &bound); + break; + case GL_TEXTURE_CUBE_MAP_ARRAY: + glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARRAY, &bound); + break; + case GL_TEXTURE_RECTANGLE: + glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE, &bound); + break; + default: + os::Printer::log("DevSH would like to ask you what are you doing!!??\n",ELL_ERROR); + return; + } + glBindTexture(target, texture); +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + pGlGenerateMipmap(target); +#else + glGenerateMipmap(target); +#endif // _IRR_OPENGL_USE_EXTPOINTER_ + glBindTexture(target, bound); + } +} + +inline void COpenGLExtensionHandler::extGlSwapInterval(int interval) +{ + // we have wglext, so try to use that +#if defined(_IRR_WINDOWS_API_) && defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) +#ifdef WGL_EXT_swap_control + if (pWglSwapIntervalEXT) + pWglSwapIntervalEXT(interval); +#endif +#endif +#ifdef _IRR_COMPILE_WITH_X11_DEVICE_ + //TODO: Check GLX_EXT_swap_control and GLX_MESA_swap_control +#ifdef GLX_SGI_swap_control + // does not work with interval==0 +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (interval && pGlxSwapIntervalSGI) + pGlxSwapIntervalSGI(interval); +#else + if (interval) + glXSwapIntervalSGI(interval); +#endif +#elif defined(GLX_EXT_swap_control) +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + Display *dpy = glXGetCurrentDisplay(); + GLXDrawable drawable = glXGetCurrentDrawable(); + + if (pGlxSwapIntervalEXT) + pGlxSwapIntervalEXT(dpy, drawable, interval); +#else + pGlXSwapIntervalEXT(dpy, drawable, interval); +#endif +#elif defined(GLX_MESA_swap_control) +#ifdef _IRR_OPENGL_USE_EXTPOINTER_ + if (pGlxSwapIntervalMESA) + pGlxSwapIntervalMESA(interval); +#else + pGlXSwapIntervalMESA(interval); +#endif +#endif +#endif +} + + +} +} + +#endif + +#endif + diff --git a/source/Irrlicht/COpenGLMaterialRenderer.h b/source/Irrlicht/COpenGLMaterialRenderer.h new file mode 100644 index 00000000..43d72190 --- /dev/null +++ b/source/Irrlicht/COpenGLMaterialRenderer.h @@ -0,0 +1,858 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OPENGL_MATERIAL_RENDERER_H_INCLUDED__ +#define __C_OPENGL_MATERIAL_RENDERER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#include "IMaterialRenderer.h" + +#include "COpenGLDriver.h" +#include "COpenGLCacheHandler.h" + +namespace irr +{ +namespace video +{ + +//! Solid material renderer +class COpenGLMaterialRenderer_SOLID : public IMaterialRenderer +{ +public: + + COpenGLMaterialRenderer_SOLID(video::COpenGLDriver* d) : Driver(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + if (Driver->getFixedPipelineState() == COpenGLDriver::EOFPS_DISABLE) + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_DISABLE_TO_ENABLE); + else + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_ENABLE); + + Driver->disableTextures(1); + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + } + +protected: + + video::COpenGLDriver* Driver; +}; + + +//! Generic Texture Blend +class COpenGLMaterialRenderer_ONETEXTURE_BLEND : public IMaterialRenderer +{ +public: + + COpenGLMaterialRenderer_ONETEXTURE_BLEND(video::COpenGLDriver* d) : Driver(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + if (Driver->getFixedPipelineState() == COpenGLDriver::EOFPS_DISABLE) + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_DISABLE_TO_ENABLE); + else + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_ENABLE); + + Driver->disableTextures(1); + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + +// if (material.MaterialType != lastMaterial.MaterialType || +// material.MaterialTypeParam != lastMaterial.MaterialTypeParam || +// resetAllRenderstates) + { + E_BLEND_FACTOR srcRGBFact,dstRGBFact,srcAlphaFact,dstAlphaFact; + E_MODULATE_FUNC modulate; + u32 alphaSource; + unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulate, alphaSource, material.MaterialTypeParam); + + Driver->getCacheHandler()->setBlend(true); + + if (Driver->queryFeature(EVDF_BLEND_SEPARATE)) + { + Driver->getCacheHandler()->setBlendFuncSeparate(Driver->getGLBlend(srcRGBFact), Driver->getGLBlend(dstRGBFact), + Driver->getGLBlend(srcAlphaFact), Driver->getGLBlend(dstAlphaFact)); + } + else + { + Driver->getCacheHandler()->setBlendFunc(Driver->getGLBlend(srcRGBFact), Driver->getGLBlend(dstRGBFact)); + } + + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + +#ifdef GL_ARB_texture_env_combine + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (f32) modulate ); +#else + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, (f32) modulate ); +#endif + + if (textureBlendFunc_hasAlpha(srcRGBFact) || textureBlendFunc_hasAlpha(dstRGBFact) || + textureBlendFunc_hasAlpha(srcAlphaFact) || textureBlendFunc_hasAlpha(dstAlphaFact)) + { + if (alphaSource==EAS_VERTEX_COLOR) + { +#ifdef GL_ARB_texture_env_combine + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB); +#else + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT); +#endif + } + else if (alphaSource==EAS_TEXTURE) + { +#ifdef GL_ARB_texture_env_combine + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); +#else + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE); +#endif + } + else + { +#ifdef GL_ARB_texture_env_combine + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_TEXTURE); +#else + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_TEXTURE); +#endif + } + } + } + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + +#ifdef GL_ARB_texture_env_combine + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.f ); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); +#else + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE); + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.f ); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); +#endif + + Driver->getCacheHandler()->setBlend(false); + } + + //! Returns if the material is transparent. + /** Is not always transparent, but mostly. */ + virtual bool isTransparent() const _IRR_OVERRIDE_ + { + return true; + } + +protected: + + video::COpenGLDriver* Driver; +}; + + +//! Solid 2 layer material renderer +class COpenGLMaterialRenderer_SOLID_2_LAYER : public IMaterialRenderer +{ +public: + + COpenGLMaterialRenderer_SOLID_2_LAYER(video::COpenGLDriver* d) : Driver(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + if (Driver->getFixedPipelineState() == COpenGLDriver::EOFPS_DISABLE) + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_DISABLE_TO_ENABLE); + else + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_ENABLE); + + Driver->disableTextures(2); + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1_ARB); +#ifdef GL_ARB_texture_env_combine + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_PRIMARY_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA); +#else + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_INTERPOLATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_PRIMARY_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA); +#endif + } + } + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1_ARB); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + +#ifdef GL_ARB_texture_env_combine + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR); +#else + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR); +#endif + } + } + +protected: + + video::COpenGLDriver* Driver; +}; + + +//! Transparent add color material renderer +class COpenGLMaterialRenderer_TRANSPARENT_ADD_COLOR : public IMaterialRenderer +{ +public: + + COpenGLMaterialRenderer_TRANSPARENT_ADD_COLOR(video::COpenGLDriver* d) : Driver(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + if (Driver->getFixedPipelineState() == COpenGLDriver::EOFPS_DISABLE) + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_DISABLE_TO_ENABLE); + else + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_ENABLE); + + Driver->disableTextures(1); + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + Driver->getCacheHandler()->setBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); + Driver->getCacheHandler()->setBlend(true); + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + Driver->getCacheHandler()->setBlend(false); + } + + //! Returns if the material is transparent. + virtual bool isTransparent() const _IRR_OVERRIDE_ + { + return true; + } + +protected: + + video::COpenGLDriver* Driver; +}; + + +//! Transparent vertex alpha material renderer +class COpenGLMaterialRenderer_TRANSPARENT_VERTEX_ALPHA : public IMaterialRenderer +{ +public: + + COpenGLMaterialRenderer_TRANSPARENT_VERTEX_ALPHA(video::COpenGLDriver* d) : Driver(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + if (Driver->getFixedPipelineState() == COpenGLDriver::EOFPS_DISABLE) + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_DISABLE_TO_ENABLE); + else + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_ENABLE); + + Driver->disableTextures(1); + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + Driver->getCacheHandler()->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + Driver->getCacheHandler()->setBlend(true); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + +#ifdef GL_ARB_texture_env_combine + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); +#else + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT ); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); +#endif + } + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); +#ifdef GL_ARB_texture_env_combine + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE ); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE ); +#else + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE ); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE ); +#endif + + Driver->getCacheHandler()->setBlend(false); + } + + //! Returns if the material is transparent. + virtual bool isTransparent() const _IRR_OVERRIDE_ + { + return true; + } + +protected: + + video::COpenGLDriver* Driver; +}; + + +//! Transparent alpha channel material renderer +class COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL : public IMaterialRenderer +{ +public: + + COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL(video::COpenGLDriver* d) : Driver(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + if (Driver->getFixedPipelineState() == COpenGLDriver::EOFPS_DISABLE) + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_DISABLE_TO_ENABLE); + else + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_ENABLE); + + Driver->disableTextures(1); + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + Driver->getCacheHandler()->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + Driver->getCacheHandler()->setBlend(true); + Driver->getCacheHandler()->setAlphaTest(true); + Driver->getCacheHandler()->setAlphaFunc(GL_GREATER, material.MaterialTypeParam); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates || material.MaterialTypeParam != lastMaterial.MaterialTypeParam ) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + +#ifdef GL_ARB_texture_env_combine + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); +#else + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE); +#endif + } + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); +#ifdef GL_ARB_texture_env_combine + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE ); +#else + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE ); +#endif + Driver->getCacheHandler()->setAlphaTest(false); + Driver->getCacheHandler()->setBlend(false); + } + + //! Returns if the material is transparent. + virtual bool isTransparent() const _IRR_OVERRIDE_ + { + return true; + } + +protected: + + video::COpenGLDriver* Driver; +}; + + +//! Transparent alpha channel material renderer +class COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF : public IMaterialRenderer +{ +public: + + COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF(video::COpenGLDriver* d) : Driver(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + if (Driver->getFixedPipelineState() == COpenGLDriver::EOFPS_DISABLE) + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_DISABLE_TO_ENABLE); + else + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_ENABLE); + + Driver->disableTextures(1); + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + Driver->getCacheHandler()->setAlphaTest(true); + Driver->getCacheHandler()->setAlphaFunc(GL_GREATER, 0.5f); + } + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + Driver->getCacheHandler()->setAlphaTest(false); + } + + //! Returns if the material is transparent. + virtual bool isTransparent() const _IRR_OVERRIDE_ + { + return false; // this material is not really transparent because it does no blending. + } + +protected: + + video::COpenGLDriver* Driver; +}; + + +//! material renderer for all kinds of lightmaps +class COpenGLMaterialRenderer_LIGHTMAP : public IMaterialRenderer +{ +public: + + COpenGLMaterialRenderer_LIGHTMAP(video::COpenGLDriver* d) : Driver(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + if (Driver->getFixedPipelineState() == COpenGLDriver::EOFPS_DISABLE) + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_DISABLE_TO_ENABLE); + else + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_ENABLE); + + Driver->disableTextures(2); + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + + // diffuse map + + switch (material.MaterialType) + { + case EMT_LIGHTMAP_LIGHTING: + case EMT_LIGHTMAP_LIGHTING_M2: + case EMT_LIGHTMAP_LIGHTING_M4: + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + break; + case EMT_LIGHTMAP_ADD: + case EMT_LIGHTMAP: + case EMT_LIGHTMAP_M2: + case EMT_LIGHTMAP_M4: + default: + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + break; + } + + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + // lightmap + + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1_ARB); +#ifdef GL_ARB_texture_env_combine + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + + if (material.MaterialType == EMT_LIGHTMAP_ADD) + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD); + else + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB); +#else + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + + if (material.MaterialType == EMT_LIGHTMAP_ADD) + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD); + else + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_PREVIOUS_EXT); +#endif + + switch (material.MaterialType) + { + case EMT_LIGHTMAP_M4: + case EMT_LIGHTMAP_LIGHTING_M4: +#ifdef GL_ARB_texture_env_combine + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 4.0f); +#else + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 4.0f); +#endif + break; + case EMT_LIGHTMAP_M2: + case EMT_LIGHTMAP_LIGHTING_M2: +#ifdef GL_ARB_texture_env_combine + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 2.0f); +#else + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f); +#endif + break; + default: +#ifdef GL_ARB_texture_env_combine + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0f); +#else + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f); +#endif + } + } + } + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1_ARB); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); +#ifdef GL_ARB_texture_env_combine + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.f ); +#else + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.f ); +#endif + } + + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + +protected: + + video::COpenGLDriver* Driver; +}; + + + +//! detail map material renderer +class COpenGLMaterialRenderer_DETAIL_MAP : public IMaterialRenderer +{ +public: + + COpenGLMaterialRenderer_DETAIL_MAP(video::COpenGLDriver* d) : Driver(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + if (Driver->getFixedPipelineState() == COpenGLDriver::EOFPS_DISABLE) + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_DISABLE_TO_ENABLE); + else + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_ENABLE); + + Driver->disableTextures(2); + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + // detail map on second layer + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1_ARB); + +#ifdef GL_ARB_texture_env_combine + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD_SIGNED_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); +#else + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD_SIGNED_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); +#endif + } + } + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1_ARB); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + } + +protected: + + video::COpenGLDriver* Driver; +}; + + +//! sphere map material renderer +class COpenGLMaterialRenderer_SPHERE_MAP : public IMaterialRenderer +{ +public: + + COpenGLMaterialRenderer_SPHERE_MAP(video::COpenGLDriver* d) : Driver(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + if (Driver->getFixedPipelineState() == COpenGLDriver::EOFPS_DISABLE) + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_DISABLE_TO_ENABLE); + else + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_ENABLE); + + Driver->disableTextures(1); + // texture needs to be flipped for OpenGL + core::matrix4 tmp = Driver->getTransform(ETS_TEXTURE_0); + tmp[5]*=-1; + Driver->setTransform(ETS_TEXTURE_0, tmp); + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + } + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + } + +protected: + + video::COpenGLDriver* Driver; +}; + + +//! reflection 2 layer material renderer +class COpenGLMaterialRenderer_REFLECTION_2_LAYER : public IMaterialRenderer +{ +public: + + COpenGLMaterialRenderer_REFLECTION_2_LAYER(video::COpenGLDriver* d) : Driver(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + if (Driver->getFixedPipelineState() == COpenGLDriver::EOFPS_DISABLE) + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_DISABLE_TO_ENABLE); + else + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_ENABLE); + + Driver->disableTextures(2); + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1_ARB); + +#ifdef GL_ARB_texture_env_combine + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); +#else + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); +#endif + + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + } + } + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1_ARB); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + } + } + +protected: + + video::COpenGLDriver* Driver; +}; + + +//! reflection 2 layer material renderer +class COpenGLMaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER : public IMaterialRenderer +{ +public: + + COpenGLMaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER(video::COpenGLDriver* d) : Driver(d) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + if (Driver->getFixedPipelineState() == COpenGLDriver::EOFPS_DISABLE) + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_DISABLE_TO_ENABLE); + else + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_ENABLE); + + Driver->disableTextures(2); + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + Driver->getCacheHandler()->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + Driver->getCacheHandler()->setBlend(true); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + +#ifdef GL_ARB_texture_env_combine + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB); +#else + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PREVIOUS_ARB); +#endif + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1_ARB); +#ifdef GL_ARB_texture_env_combine + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB); +#else + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PREVIOUS_ARB); +#endif + + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + } + } + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + if (Driver->queryFeature(EVDF_MULTITEXTURE)) + { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1_ARB); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + } + + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + Driver->getCacheHandler()->setBlend(false); + } + + //! Returns if the material is transparent. + virtual bool isTransparent() const _IRR_OVERRIDE_ + { + return true; + } + +protected: + + video::COpenGLDriver* Driver; +}; + +} // end namespace video +} // end namespace irr + +#endif +#endif + diff --git a/source/Irrlicht/COpenGLNormalMapRenderer.cpp b/source/Irrlicht/COpenGLNormalMapRenderer.cpp new file mode 100644 index 00000000..5bbad4f0 --- /dev/null +++ b/source/Irrlicht/COpenGLNormalMapRenderer.cpp @@ -0,0 +1,292 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "COpenGLNormalMapRenderer.h" + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#include "IGPUProgrammingServices.h" +#include "IShaderConstantSetCallBack.h" +#include "IVideoDriver.h" +#include "os.h" + +#include "COpenGLDriver.h" + +namespace irr +{ +namespace video +{ + +// Irrlicht Engine OpenGL render path normal map vertex shader +// I guess it could be optimized a lot, because I wrote it in D3D ASM and +// transferred it 1:1 to OpenGL +const char OPENGL_NORMAL_MAP_VSH[] = + "!!ARBvp1.0\n"\ + "#input\n"\ + "# 0-3: transposed world matrix;\n"\ + "#;12: Light01 position \n"\ + "#;13: x,y,z: Light01 color; .w: 1/LightRadius^2 \n"\ + "#;14: Light02 position \n"\ + "#;15: x,y,z: Light02 color; .w: 1/LightRadius^2 \n"\ + "\n"\ + "ATTRIB InPos = vertex.position;\n"\ + "ATTRIB InColor = vertex.color;\n"\ + "ATTRIB InNormal = vertex.normal;\n"\ + "ATTRIB InTexCoord = vertex.texcoord[0];\n"\ + "ATTRIB InTangent = vertex.texcoord[1];\n"\ + "ATTRIB InBinormal = vertex.texcoord[2];\n"\ + "\n"\ + "#output\n"\ + "OUTPUT OutPos = result.position;\n"\ + "OUTPUT OutLightColor1 = result.color.primary;\n"\ + "OUTPUT OutLightColor2 = result.color.secondary;\n"\ + "OUTPUT OutTexCoord = result.texcoord[0];\n"\ + "OUTPUT OutLightVector1 = result.texcoord[1];\n"\ + "OUTPUT OutLightVector2 = result.texcoord[2];\n"\ + "\n"\ + "PARAM MVP[4] = { state.matrix.mvp }; # modelViewProjection matrix.\n"\ + "TEMP Temp;\n"\ + "TEMP TempColor;\n"\ + "TEMP TempLightVector1;\n"\ + "TEMP TempLightVector2;\n"\ + "TEMP TempTransLightV1;\n"\ + "TEMP TempTransLightV2;\n"\ + "\n"\ + "# transform position to clip space \n"\ + "DP4 OutPos.x, MVP[0], InPos;\n"\ + "DP4 OutPos.y, MVP[1], InPos;\n"\ + "DP4 Temp.z, MVP[2], InPos;\n"\ + "DP4 OutPos.w, MVP[3], InPos;\n"\ + "MOV OutPos.z, Temp.z;\n"\ + "MOV result.fogcoord.x, Temp.z;\n"\ + "\n"\ + "# vertex - lightpositions \n"\ + "SUB TempLightVector1, program.local[12], InPos; \n"\ + "SUB TempLightVector2, program.local[14], InPos; \n"\ + "\n"\ + "# transform the light vector 1 with U, V, W \n"\ + "DP3 TempTransLightV1.x, InTangent, TempLightVector1; \n"\ + "DP3 TempTransLightV1.y, InBinormal, TempLightVector1; \n"\ + "DP3 TempTransLightV1.z, InNormal, TempLightVector1; \n"\ + "\n"\ + "# transform the light vector 2 with U, V, W \n"\ + "DP3 TempTransLightV2.x, InTangent, TempLightVector2; \n"\ + "DP3 TempTransLightV2.y, InBinormal, TempLightVector2; \n"\ + "DP3 TempTransLightV2.z, InNormal, TempLightVector2; \n"\ + "\n"\ + "# normalize light vector 1 \n"\ + "DP3 TempTransLightV1.w, TempTransLightV1, TempTransLightV1; \n"\ + "RSQ TempTransLightV1.w, TempTransLightV1.w; \n"\ + "MUL TempTransLightV1, TempTransLightV1, TempTransLightV1.w;\n"\ + "\n"\ + "# normalize light vector 2 \n"\ + "DP3 TempTransLightV2.w, TempTransLightV2, TempTransLightV2; \n"\ + "RSQ TempTransLightV2.w, TempTransLightV2.w; \n"\ + "MUL TempTransLightV2, TempTransLightV2, TempTransLightV2.w;\n"\ + "\n"\ + "\n"\ + "# move light vectors out\n"\ + "MAD OutLightVector1, TempTransLightV1, {0.5,0.5,0.5,0.5}, {0.5,0.5,0.5,0.5}; \n"\ + "MAD OutLightVector2, TempTransLightV2, {0.5,0.5,0.5,0.5}, {0.5,0.5,0.5,0.5}; \n"\ + "\n"\ + "# calculate attenuation of light 1\n"\ + "MOV TempLightVector1.w, {0,0,0,0}; \n"\ + "DP3 TempLightVector1.x, TempLightVector1, TempLightVector1; \n"\ + "MUL TempLightVector1.x, TempLightVector1.x, program.local[13].w; \n"\ + "RSQ TempLightVector1, TempLightVector1.x; \n"\ + "MUL OutLightColor1, TempLightVector1, program.local[13]; # resulting light color = lightcolor * attenuation \n"\ + "\n"\ + "# calculate attenuation of light 2\n"\ + "MOV TempLightVector2.w, {0,0,0,0}; \n"\ + "DP3 TempLightVector2.x, TempLightVector2, TempLightVector2; \n"\ + "MUL TempLightVector2.x, TempLightVector2.x, program.local[15].w; \n"\ + "RSQ TempLightVector2, TempLightVector2.x; \n"\ + "MUL OutLightColor2, TempLightVector2, program.local[15]; # resulting light color = lightcolor * attenuation \n"\ + "\n"\ + "# move out texture coordinates and original alpha value\n"\ + "MOV OutTexCoord, InTexCoord; \n"\ + "MOV OutLightColor1.w, InColor.w; \n"\ + "\n"\ + "END\n"; + +// Irrlicht Engine OpenGL render path normal map pixel shader +// I guess it could be optimized a bit, because I wrote it in D3D ASM and +// transfered it 1:1 to OpenGL +const char OPENGL_NORMAL_MAP_PSH[] = + "!!ARBfp1.0\n"\ + "#_IRR_FOG_MODE_\n"\ + "\n"\ + "#Input\n"\ + "ATTRIB inTexCoord = fragment.texcoord[0]; \n"\ + "ATTRIB light1Vector = fragment.texcoord[1]; \n"\ + "ATTRIB light2Vector = fragment.texcoord[2]; \n"\ + "ATTRIB light1Color = fragment.color.primary; \n"\ + "ATTRIB light2Color = fragment.color.secondary; \n"\ + "\n"\ + "#Output\n"\ + "OUTPUT outColor = result.color;\n"\ + "TEMP temp;\n"\ + "TEMP temp2;\n"\ + "TEMP colorMapColor;\n"\ + "TEMP normalMapColor;\n"\ + "\n"\ + "# fetch color and normal map; \n"\ + "TXP colorMapColor, inTexCoord, texture[0], 2D; \n"\ + "TXP normalMapColor, inTexCoord, texture[1], 2D; \n"\ + "\n"\ + "# calculate color of light1; \n"\ + "MAD normalMapColor, normalMapColor, {2,2,2,2}, {-1,-1,-1,-1}; \n"\ + "MAD temp, light1Vector, {2,2,2,2}, {-1,-1,-1,-1}; \n"\ + "DP3_SAT temp, normalMapColor, temp; \n"\ + "MUL temp, light1Color, temp; \n"\ + "\n"\ + "# calculate color of light2; \n"\ + "MAD temp2, light2Vector, {2,2,2,2}, {-1,-1,-1,-1}; \n"\ + "DP3_SAT temp2, normalMapColor, temp2; \n"\ + "MAD temp, light2Color, temp2, temp; \n"\ + "\n"\ + "# luminance * base color; \n"\ + "MUL outColor, temp, colorMapColor; \n"\ + "MOV outColor.a, light1Color.a; #write interpolated vertex alpha value\n"\ + "\n"\ + "END\n"; + +//! Constructor +COpenGLNormalMapRenderer::COpenGLNormalMapRenderer(video::COpenGLDriver* driver, + s32& outMaterialTypeNr, E_MATERIAL_TYPE baseMaterial) + : COpenGLShaderMaterialRenderer(driver, 0, baseMaterial), CompiledShaders(true) +{ + + #ifdef _DEBUG + setDebugName("COpenGLNormalMapRenderer"); + #endif + + // set this as callback. We could have done this in + // the initialization list, but some compilers don't like it. + + CallBack = this; + + // basically, this thing simply compiles the hardcoded shaders if the + // hardware is able to do them, otherwise it maps to the base material + + if (!driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1) || + !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)) + { + // this hardware is not able to do shaders. Fall back to + // base material. + outMaterialTypeNr = driver->addMaterialRenderer(this); + return; + } + + // check if already compiled normal map shaders are there. + + video::IMaterialRenderer* renderer = driver->getMaterialRenderer(EMT_NORMAL_MAP_SOLID); + + if (renderer) + { + // use the already compiled shaders + video::COpenGLNormalMapRenderer* nmr = reinterpret_cast(renderer); + CompiledShaders = false; + + VertexShader = nmr->VertexShader; + PixelShader = nmr->PixelShader; + + outMaterialTypeNr = driver->addMaterialRenderer(this); + } + else + { + // compile shaders on our own + init(outMaterialTypeNr, OPENGL_NORMAL_MAP_VSH, OPENGL_NORMAL_MAP_PSH, EVT_TANGENTS); + } + + // fallback if compilation has failed + if (-1==outMaterialTypeNr) + outMaterialTypeNr = driver->addMaterialRenderer(this); +} + + +//! Destructor +COpenGLNormalMapRenderer::~COpenGLNormalMapRenderer() +{ + if (CallBack == this) + CallBack = 0; + + if (!CompiledShaders) + { + // prevent this from deleting shaders we did not create + VertexShader = 0; + PixelShader.clear(); + } +} + + +//! Returns the render capability of the material. +s32 COpenGLNormalMapRenderer::getRenderCapability() const +{ + if (Driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1) && + Driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)) + return 0; + + return 1; +} + + +//! Called by the engine when the vertex and/or pixel shader constants for an +//! material renderer should be set. +void COpenGLNormalMapRenderer::OnSetConstants(IMaterialRendererServices* services, s32 userData) +{ + video::IVideoDriver* driver = services->getVideoDriver(); + + // set transposed world matrix + const core::matrix4& tWorld = driver->getTransform(video::ETS_WORLD).getTransposed(); + services->setVertexShaderConstant(tWorld.pointer(), 0, 4); + + // set transposed worldViewProj matrix + core::matrix4 worldViewProj(driver->getTransform(video::ETS_PROJECTION)); + worldViewProj *= driver->getTransform(video::ETS_VIEW); + worldViewProj *= driver->getTransform(video::ETS_WORLD); + core::matrix4 tr(worldViewProj.getTransposed()); + services->setVertexShaderConstant(tr.pointer(), 8, 4); + + // here we fetch the fixed function lights from the driver + // and set them as constants + + u32 cnt = driver->getDynamicLightCount(); + + // Load the inverse world matrix. + core::matrix4 invWorldMat; + driver->getTransform(video::ETS_WORLD).getInverse(invWorldMat); + + for (u32 i=0; i<2; ++i) + { + video::SLight light; + + if (igetDynamicLight(i); + else + { + light.DiffuseColor.set(0,0,0); // make light dark + light.Radius = 1.0f; + } + + light.DiffuseColor.a = 1.0f/(light.Radius*light.Radius); // set attenuation + + // Transform the light by the inverse world matrix to get it into object space. + invWorldMat.transformVect(light.Position); + + services->setVertexShaderConstant( + reinterpret_cast(&light.Position), 12+(i*2), 1); + + services->setVertexShaderConstant( + reinterpret_cast(&light.DiffuseColor), 13+(i*2), 1); + } +} + + +} // end namespace video +} // end namespace irr + + +#endif + diff --git a/source/Irrlicht/COpenGLNormalMapRenderer.h b/source/Irrlicht/COpenGLNormalMapRenderer.h new file mode 100644 index 00000000..f9991ad1 --- /dev/null +++ b/source/Irrlicht/COpenGLNormalMapRenderer.h @@ -0,0 +1,51 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OPENGL_NORMAL_MAP_RENDERER_H_INCLUDED__ +#define __C_OPENGL_NORMAL_MAP_RENDERER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#include "IShaderConstantSetCallBack.h" + +#include "COpenGLShaderMaterialRenderer.h" + +namespace irr +{ +namespace video +{ + +//! Class for rendering normal maps with OpenGL +class COpenGLNormalMapRenderer : public COpenGLShaderMaterialRenderer, public IShaderConstantSetCallBack +{ +public: + + //! Constructor + COpenGLNormalMapRenderer(video::COpenGLDriver* driver, + s32& outMaterialTypeNr, E_MATERIAL_TYPE baseMaterial); + + //! Destructor + ~COpenGLNormalMapRenderer(); + + //! Called by the engine when the vertex and/or pixel shader constants for an + //! material renderer should be set. + virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData) _IRR_OVERRIDE_; + + //! Returns the render capability of the material. + virtual s32 getRenderCapability() const _IRR_OVERRIDE_; + +protected: + + bool CompiledShaders; +}; + + +} // end namespace video +} // end namespace irr + +#endif +#endif + diff --git a/source/Irrlicht/COpenGLParallaxMapRenderer.cpp b/source/Irrlicht/COpenGLParallaxMapRenderer.cpp new file mode 100644 index 00000000..065cea23 --- /dev/null +++ b/source/Irrlicht/COpenGLParallaxMapRenderer.cpp @@ -0,0 +1,355 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "COpenGLParallaxMapRenderer.h" + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#include "IGPUProgrammingServices.h" +#include "IShaderConstantSetCallBack.h" +#include "IVideoDriver.h" +#include "os.h" + +#include "COpenGLDriver.h" + +namespace irr +{ +namespace video +{ + +// Irrlicht Engine OpenGL render path parallax map vertex shader +// I guess it could be optimized a lot, because I wrote it in D3D ASM and +// transferred it 1:1 to OpenGL +const char OPENGL_PARALLAX_MAP_VSH[] = + "!!ARBvp1.0\n"\ + "#input\n"\ + "# 0-3: transposed world matrix;\n"\ + "#;12: Light01 position \n"\ + "#;13: x,y,z: Light01 color; .w: 1/LightRadius^2 \n"\ + "#;14: Light02 position \n"\ + "#;15: x,y,z: Light02 color; .w: 1/LightRadius^2 \n"\ + "#;16: Eye position \n"\ + "\n"\ + "ATTRIB InPos = vertex.position;\n"\ + "ATTRIB InColor = vertex.color;\n"\ + "ATTRIB InNormal = vertex.normal;\n"\ + "ATTRIB InTexCoord = vertex.texcoord[0];\n"\ + "ATTRIB InTangent = vertex.texcoord[1];\n"\ + "ATTRIB InBinormal = vertex.texcoord[2];\n"\ + "\n"\ + "#output\n"\ + "OUTPUT OutPos = result.position;\n"\ + "OUTPUT OutLightColor1 = result.color.primary;\n"\ + "OUTPUT OutLightColor2 = result.color.secondary;\n"\ + "OUTPUT OutTexCoord = result.texcoord[0];\n"\ + "OUTPUT OutLightVector1 = result.texcoord[1];\n"\ + "OUTPUT OutLightVector2 = result.texcoord[2];\n"\ + "OUTPUT OutEyeVector = result.texcoord[3];\n"\ + "\n"\ + "PARAM MVP[4] = { state.matrix.mvp }; # modelViewProjection matrix.\n"\ + "TEMP Temp;\n"\ + "TEMP TempColor;\n"\ + "TEMP TempLightVector1;\n"\ + "TEMP TempLightVector2;\n"\ + "TEMP TempEyeVector;\n"\ + "TEMP TempTransLightV1;\n"\ + "TEMP TempTransLightV2;\n"\ + "\n"\ + "# transform position to clip space \n"\ + "DP4 OutPos.x, MVP[0], InPos;\n"\ + "DP4 OutPos.y, MVP[1], InPos;\n"\ + "DP4 Temp.z, MVP[2], InPos;\n"\ + "DP4 OutPos.w, MVP[3], InPos;\n"\ + "MOV OutPos.z, Temp.z;\n"\ + "MOV result.fogcoord.x, Temp.z;\n"\ + "\n"\ + "# vertex - lightpositions \n"\ + "SUB TempLightVector1, program.local[12], InPos; \n"\ + "SUB TempLightVector2, program.local[14], InPos; \n"\ + "\n"\ + "# eye vector \n"\ + "SUB Temp, program.local[16], InPos; \n"\ + "\n"\ + "# transform the light vector 1 with U, V, W \n"\ + "DP3 TempTransLightV1.x, InTangent, TempLightVector1; \n"\ + "DP3 TempTransLightV1.y, InBinormal, TempLightVector1; \n"\ + "DP3 TempTransLightV1.z, InNormal, TempLightVector1; \n"\ + "\n"\ + "# transform the light vector 2 with U, V, W \n"\ + "DP3 TempTransLightV2.x, InTangent, TempLightVector2; \n"\ + "DP3 TempTransLightV2.y, InBinormal, TempLightVector2; \n"\ + "DP3 TempTransLightV2.z, InNormal, TempLightVector2; \n"\ + "\n"\ + "# transform the eye vector with U, V, W \n"\ + "DP3 TempEyeVector.x, InTangent, Temp; \n"\ + "DP3 TempEyeVector.y, InBinormal, Temp; \n"\ + "DP3 TempEyeVector.z, InNormal, Temp; \n"\ + "\n"\ + "# normalize light vector 1 \n"\ + "DP3 TempTransLightV1.w, TempTransLightV1, TempTransLightV1; \n"\ + "RSQ TempTransLightV1.w, TempTransLightV1.w; \n"\ + "MUL TempTransLightV1, TempTransLightV1, TempTransLightV1.w;\n"\ + "\n"\ + "# normalize light vector 2 \n"\ + "DP3 TempTransLightV2.w, TempTransLightV2, TempTransLightV2; \n"\ + "RSQ TempTransLightV2.w, TempTransLightV2.w; \n"\ + "MUL TempTransLightV2, TempTransLightV2, TempTransLightV2.w;\n"\ + "\n"\ + "# normalize eye vector \n"\ + "DP3 TempEyeVector.w, TempEyeVector, TempEyeVector; \n"\ + "RSQ TempEyeVector.w, TempEyeVector.w; \n"\ + "MUL TempEyeVector, TempEyeVector, TempEyeVector.w;\n"\ + "MUL TempEyeVector, TempEyeVector, {1,-1,-1,1}; # flip x \n"\ + "\n"\ + "\n"\ + "# move light and eye vectors out\n"\ + "MAD OutLightVector1, TempTransLightV1, {0.5,0.5,0.5,0.5}, {0.5,0.5,0.5,0.5}; \n"\ + "MAD OutLightVector2, TempTransLightV2, {0.5,0.5,0.5,0.5}, {0.5,0.5,0.5,0.5}; \n"\ + "MAD OutEyeVector, TempEyeVector, {0.5,0.5,0.5,0.5}, {0.5,0.5,0.5,0.5}; \n"\ + "\n"\ + "# calculate attenuation of light 1\n"\ + "MOV TempLightVector1.w, {0,0,0,0}; \n"\ + "DP3 TempLightVector1.x, TempLightVector1, TempLightVector1; \n"\ + "MUL TempLightVector1.x, TempLightVector1.x, program.local[13].w; \n"\ + "RSQ TempLightVector1, TempLightVector1.x; \n"\ + "MUL OutLightColor1, TempLightVector1, program.local[13]; # resulting light color = lightcolor * attenuation \n"\ + "\n"\ + "# calculate attenuation of light 2\n"\ + "MOV TempLightVector2.w, {0,0,0,0}; \n"\ + "DP3 TempLightVector2.x, TempLightVector2, TempLightVector2; \n"\ + "MUL TempLightVector2.x, TempLightVector2.x, program.local[15].w; \n"\ + "RSQ TempLightVector2, TempLightVector2.x; \n"\ + "MUL OutLightColor2, TempLightVector2, program.local[15]; # resulting light color = lightcolor * attenuation \n"\ + "\n"\ + "# move out texture coordinates and original alpha value\n"\ + "MOV OutTexCoord, InTexCoord; \n"\ + "MOV OutLightColor1.w, InColor.w; \n"\ + "\n"\ + "END\n"; + +// Irrlicht Engine OpenGL render path parallax map pixel shader +// I guess it could be optimized a bit, because I wrote it in D3D ASM and +// transfered it 1:1 to OpenGL +const char OPENGL_PARALLAX_MAP_PSH[] = + "!!ARBfp1.0\n"\ + "#_IRR_FOG_MODE_\n"\ + "\n"\ + "#Input\n"\ + "ATTRIB inTexCoord = fragment.texcoord[0]; \n"\ + "ATTRIB light1Vector = fragment.texcoord[1]; \n"\ + "ATTRIB light2Vector = fragment.texcoord[2]; \n"\ + "ATTRIB eyeVector = fragment.texcoord[3]; \n"\ + "ATTRIB light1Color = fragment.color.primary; \n"\ + "ATTRIB light2Color = fragment.color.secondary; \n"\ + "\n"\ + "#Output\n"\ + "OUTPUT outColor = result.color;\n"\ + "TEMP temp;\n"\ + "TEMP temp2;\n"\ + "TEMP colorMapColor;\n"\ + "TEMP normalMapColor;\n"\ + "\n"\ + "PARAM height_scale = program.local[0]; \n"\ + "# fetch color and normal map; \n"\ + "TXP normalMapColor, inTexCoord, texture[1], 2D; \n"\ + "MAD normalMapColor, normalMapColor, {2,2,2,2}, {-1,-1,-1,-1}; \n"\ + "\n"\ + "\n"\ + "# extract eye vector (so substract 0.5f and multiply by 2)\n"\ + "MAD temp, eyeVector, {2,2,2,2}, {-1,-1,-1,-1};\n"\ + "\n"\ + "# height = height * scale \n"\ + "MUL normalMapColor, normalMapColor, height_scale;\n"\ + "\n"\ + "# calculate new texture coord: height * eye + oldTexCoord\n"\ + "MAD temp, temp, normalMapColor.wwww, inTexCoord;\n"\ + "\n"\ + "# fetch new textures \n"\ + "TXP colorMapColor, temp, texture[0], 2D; \n"\ + "TXP normalMapColor, temp, texture[1], 2D; \n"\ + "\n"\ + "# calculate color of light1; \n"\ + "MAD normalMapColor, normalMapColor, {2,2,2,2}, {-1,-1,-1,-1}; \n"\ + "MAD temp, light1Vector, {2,2,2,2}, {-1,-1,-1,-1}; \n"\ + "DP3_SAT temp, normalMapColor, temp; \n"\ + "MUL temp, light1Color, temp; \n"\ + "\n"\ + "# calculate color of light2; \n"\ + "MAD temp2, light2Vector, {2,2,2,2}, {-1,-1,-1,-1}; \n"\ + "DP3_SAT temp2, normalMapColor, temp2; \n"\ + "MAD temp, light2Color, temp2, temp; \n"\ + "\n"\ + "# luminance * base color; \n"\ + "MUL outColor, temp, colorMapColor; \n"\ + "MOV outColor.a, light1Color.a; #write interpolated vertex alpha value\n"\ + "\n"\ + "END\n"; + +//! Constructor +COpenGLParallaxMapRenderer::COpenGLParallaxMapRenderer(video::COpenGLDriver* driver, + s32& outMaterialTypeNr, E_MATERIAL_TYPE baseMaterial) + : COpenGLShaderMaterialRenderer(driver, 0, baseMaterial), CompiledShaders(true) +{ + + #ifdef _DEBUG + setDebugName("COpenGLParallaxMapRenderer"); + #endif + + // set this as callback. We could have done this in + // the initialization list, but some compilers don't like it. + + CallBack = this; + + // basically, this simply compiles the hard coded shaders if the + // hardware is able to do them, otherwise it maps to the base material + + if (!driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1) || + !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)) + { + // this hardware is not able to do shaders. Fall back to + // base material. + outMaterialTypeNr = driver->addMaterialRenderer(this); + return; + } + + // check if already compiled normal map shaders are there. + + video::IMaterialRenderer* renderer = driver->getMaterialRenderer(EMT_PARALLAX_MAP_SOLID); + + if (renderer) + { + // use the already compiled shaders + video::COpenGLParallaxMapRenderer* nmr = reinterpret_cast(renderer); + CompiledShaders = false; + + VertexShader = nmr->VertexShader; + PixelShader = nmr->PixelShader; + + outMaterialTypeNr = driver->addMaterialRenderer(this); + } + else + { + // compile shaders on our own + init(outMaterialTypeNr, OPENGL_PARALLAX_MAP_VSH, OPENGL_PARALLAX_MAP_PSH, EVT_TANGENTS); + } + + // fallback if compilation has failed + if (-1==outMaterialTypeNr) + outMaterialTypeNr = driver->addMaterialRenderer(this); +} + + +//! Destructor +COpenGLParallaxMapRenderer::~COpenGLParallaxMapRenderer() +{ + if (CallBack == this) + CallBack = 0; + + if (!CompiledShaders) + { + // prevent this from deleting shaders we did not create + VertexShader = 0; + PixelShader.clear(); + } +} + + +void COpenGLParallaxMapRenderer::OnSetMaterial(const video::SMaterial& material, + const video::SMaterial& lastMaterial, + bool resetAllRenderstates, video::IMaterialRendererServices* services) +{ + COpenGLShaderMaterialRenderer::OnSetMaterial(material, lastMaterial, + resetAllRenderstates, services); + + CurrentScale = material.MaterialTypeParam; +} + + + +//! Returns the render capability of the material. +s32 COpenGLParallaxMapRenderer::getRenderCapability() const +{ + if (Driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1) && + Driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)) + return 0; + + return 1; +} + + +//! Called by the engine when the vertex and/or pixel shader constants for an +//! material renderer should be set. +void COpenGLParallaxMapRenderer::OnSetConstants(IMaterialRendererServices* services, s32 userData) +{ + video::IVideoDriver* driver = services->getVideoDriver(); + + // set transposed world matrix + const core::matrix4& tWorld = driver->getTransform(video::ETS_WORLD).getTransposed(); + services->setVertexShaderConstant(tWorld.pointer(), 0, 4); + + // set transposed worldViewProj matrix + core::matrix4 worldViewProj(driver->getTransform(video::ETS_PROJECTION)); + worldViewProj *= driver->getTransform(video::ETS_VIEW); + worldViewProj *= driver->getTransform(video::ETS_WORLD); + core::matrix4 tr(worldViewProj.getTransposed()); + services->setVertexShaderConstant(tr.pointer(), 8, 4); + + // here we fetch the fixed function lights from the driver + // and set them as constants + + u32 cnt = driver->getDynamicLightCount(); + + // Load the inverse world matrix. + core::matrix4 invWorldMat; + driver->getTransform(video::ETS_WORLD).getInverse(invWorldMat); + + for (u32 i=0; i<2; ++i) + { + video::SLight light; + + if (igetDynamicLight(i); + else + { + light.DiffuseColor.set(0,0,0); // make light dark + light.Radius = 1.0f; + } + + light.DiffuseColor.a = 1.0f/(light.Radius*light.Radius); // set attenuation + + // Transform the light by the inverse world matrix to get it into object space. + invWorldMat.transformVect(light.Position); + + services->setVertexShaderConstant( + reinterpret_cast(&light.Position), 12+(i*2), 1); + + services->setVertexShaderConstant( + reinterpret_cast(&light.DiffuseColor), 13+(i*2), 1); + } + + // Obtain the view position by transforming 0,0,0 by the inverse view matrix + // and then multiply this by the inverse world matrix. + core::vector3df viewPos(0.0f, 0.0f, 0.0f); + core::matrix4 inverseView; + driver->getTransform(video::ETS_VIEW).getInverse(inverseView); + inverseView.transformVect(viewPos); + invWorldMat.transformVect(viewPos); + services->setVertexShaderConstant(reinterpret_cast(&viewPos.X), 16, 1); + + // set scale factor + f32 factor = 0.02f; // default value + if (CurrentScale != 0.0f) + factor = CurrentScale; + + f32 c6[] = {factor, factor, factor, factor}; + services->setPixelShaderConstant(c6, 0, 1); +} + + +} // end namespace video +} // end namespace irr + + +#endif + diff --git a/source/Irrlicht/COpenGLParallaxMapRenderer.h b/source/Irrlicht/COpenGLParallaxMapRenderer.h new file mode 100644 index 00000000..f2d1c487 --- /dev/null +++ b/source/Irrlicht/COpenGLParallaxMapRenderer.h @@ -0,0 +1,57 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OPENGL_PARALLAX_MAP_RENDERER_H_INCLUDED__ +#define __C_OPENGL_PARALLAX_MAP_RENDERER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#include "IShaderConstantSetCallBack.h" + +#include "COpenGLShaderMaterialRenderer.h" + +namespace irr +{ +namespace video +{ + +//! Class for rendering normal maps with OpenGL +class COpenGLParallaxMapRenderer : public COpenGLShaderMaterialRenderer, public IShaderConstantSetCallBack +{ +public: + + //! Constructor + COpenGLParallaxMapRenderer(video::COpenGLDriver* driver, + s32& outMaterialTypeNr, E_MATERIAL_TYPE baseMaterial); + + //! Destructor + ~COpenGLParallaxMapRenderer(); + + //! Called by the engine when the vertex and/or pixel shader constants for an + //! material renderer should be set. + virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData) _IRR_OVERRIDE_; + + //! Returns the render capability of the material. + virtual s32 getRenderCapability() const _IRR_OVERRIDE_; + + virtual void OnSetMaterial(const SMaterial& material) _IRR_OVERRIDE_ { } + virtual void OnSetMaterial(const video::SMaterial& material, + const video::SMaterial& lastMaterial, + bool resetAllRenderstates, video::IMaterialRendererServices* services) _IRR_OVERRIDE_; + +protected: + + bool CompiledShaders; + f32 CurrentScale; +}; + + +} // end namespace video +} // end namespace irr + +#endif +#endif + diff --git a/source/Irrlicht/COpenGLSLMaterialRenderer.cpp b/source/Irrlicht/COpenGLSLMaterialRenderer.cpp new file mode 100644 index 00000000..5b2cabab --- /dev/null +++ b/source/Irrlicht/COpenGLSLMaterialRenderer.cpp @@ -0,0 +1,722 @@ +// Copyright (C) 2002-2012 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 originally written by William Finlayson. I (Nikolaus +// Gebhardt) did some minor modifications and changes to it and integrated it +// into Irrlicht. Thanks a lot to William for his work on this and that he gave +// me his permission to add it into Irrlicht using the zlib license. + +// After Irrlicht 0.12, Michael Zoech did some improvements to this renderer, I +// merged this into Irrlicht 0.14, thanks to him for his work. + +#include "COpenGLSLMaterialRenderer.h" + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#include "IGPUProgrammingServices.h" +#include "IShaderConstantSetCallBack.h" +#include "IMaterialRendererServices.h" +#include "IVideoDriver.h" +#include "os.h" + +#include "COpenGLDriver.h" +#include "COpenGLCacheHandler.h" +#include "COpenGLMaterialRenderer.h" + +#include "COpenGLCoreFeature.h" + +namespace irr +{ +namespace video +{ + + +//! Constructor +COpenGLSLMaterialRenderer::COpenGLSLMaterialRenderer(video::COpenGLDriver* driver, + s32& outMaterialTypeNr, const c8* vertexShaderProgram, + const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, + const c8* pixelShaderProgram, + const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, + const c8* geometryShaderProgram, + const c8* geometryShaderEntryPointName, + E_GEOMETRY_SHADER_TYPE gsCompileTarget, + scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType, + u32 verticesOut, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, + s32 userData) + : Driver(driver), CallBack(callback), Alpha(false), Blending(false), FixedBlending(false), AlphaTest(false), Program(0), Program2(0), UserData(userData) +{ + #ifdef _DEBUG + setDebugName("COpenGLSLMaterialRenderer"); + #endif + + switch (baseMaterial) + { + case EMT_TRANSPARENT_VERTEX_ALPHA: + case EMT_TRANSPARENT_ALPHA_CHANNEL: + case EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA: + case EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA: + Alpha = true; + break; + case EMT_TRANSPARENT_ADD_COLOR: + case EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR: + case EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR: + FixedBlending = true; + break; + case EMT_ONETEXTURE_BLEND: + Blending = true; + break; + case EMT_TRANSPARENT_ALPHA_CHANNEL_REF: + AlphaTest = true; + break; + default: + break; + } + + if (CallBack) + CallBack->grab(); + + if (!Driver->queryFeature(EVDF_ARB_GLSL)) + return; + + init(outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram, geometryShaderProgram); +} + + +//! constructor only for use by derived classes who want to +//! create a fall back material for example. +COpenGLSLMaterialRenderer::COpenGLSLMaterialRenderer(COpenGLDriver* driver, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, s32 userData) +: Driver(driver), CallBack(callback), Alpha(false), Blending(false), FixedBlending(false), AlphaTest(false), Program(0), Program2(0), UserData(userData) +{ + switch (baseMaterial) + { + case EMT_TRANSPARENT_VERTEX_ALPHA: + case EMT_TRANSPARENT_ALPHA_CHANNEL: + case EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA: + case EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA: + Alpha = true; + break; + case EMT_TRANSPARENT_ADD_COLOR: + case EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR: + case EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR: + FixedBlending = true; + break; + case EMT_ONETEXTURE_BLEND: + Blending = true; + break; + case EMT_TRANSPARENT_ALPHA_CHANNEL_REF: + AlphaTest = true; + break; + default: + break; + } + + if (CallBack) + CallBack->grab(); +} + + +//! Destructor +COpenGLSLMaterialRenderer::~COpenGLSLMaterialRenderer() +{ + if (CallBack) + CallBack->drop(); + + if (Program) + { + GLhandleARB shaders[8]; + GLint count; + Driver->extGlGetAttachedObjects(Program, 8, &count, shaders); + // avoid bugs in some drivers, which return larger numbers + // use int variable to avoid compiler problems with template + int mincount=core::min_((int)count,8); + for (int i=0; iextGlDeleteObject(shaders[i]); + Driver->extGlDeleteObject(Program); + Program = 0; + } + + if (Program2) + { + GLuint shaders[8]; + GLint count; + Driver->extGlGetAttachedShaders(Program2, 8, &count, shaders); + // avoid bugs in some drivers, which return larger numbers + // use int variable to avoid compiler problems with template + int mincount=core::min_((int)count,8); + for (int i=0; iextGlDeleteShader(shaders[i]); + Driver->extGlDeleteProgram(Program2); + Program2 = 0; + } + + UniformInfo.clear(); +} + + +void COpenGLSLMaterialRenderer::init(s32& outMaterialTypeNr, + const c8* vertexShaderProgram, + const c8* pixelShaderProgram, + const c8* geometryShaderProgram, + scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType, + u32 verticesOut) +{ + outMaterialTypeNr = -1; + + if (!createProgram()) + return; + +#if defined(GL_ARB_vertex_shader) && defined (GL_ARB_fragment_shader) + if (vertexShaderProgram) + if (!createShader(GL_VERTEX_SHADER_ARB, vertexShaderProgram)) + return; + + if (pixelShaderProgram) + if (!createShader(GL_FRAGMENT_SHADER_ARB, pixelShaderProgram)) + return; +#endif + +#if defined(GL_ARB_geometry_shader4) || defined(GL_EXT_geometry_shader4) || defined(GL_NV_geometry_program4) || defined(GL_NV_geometry_shader4) + if (geometryShaderProgram && Driver->queryFeature(EVDF_GEOMETRY_SHADER)) + { + if (!createShader(GL_GEOMETRY_SHADER_EXT, geometryShaderProgram)) + return; +#if defined(GL_ARB_geometry_shader4) || defined(GL_EXT_geometry_shader4) || defined(GL_NV_geometry_shader4) + if (Program2) // Geometry shaders are supported only in OGL2.x+ drivers. + { + Driver->extGlProgramParameteri(Program2, GL_GEOMETRY_INPUT_TYPE_EXT, Driver->primitiveTypeToGL(inType)); + Driver->extGlProgramParameteri(Program2, GL_GEOMETRY_OUTPUT_TYPE_EXT, Driver->primitiveTypeToGL(outType)); + if (verticesOut==0) + Driver->extGlProgramParameteri(Program2, GL_GEOMETRY_VERTICES_OUT_EXT, Driver->MaxGeometryVerticesOut); + else + Driver->extGlProgramParameteri(Program2, GL_GEOMETRY_VERTICES_OUT_EXT, core::min_(verticesOut, Driver->MaxGeometryVerticesOut)); + } +#elif defined(GL_NV_geometry_program4) + if (verticesOut==0) + Driver->extGlProgramVertexLimit(GL_GEOMETRY_PROGRAM_NV, Driver->MaxGeometryVerticesOut); + else + Driver->extGlProgramVertexLimit(GL_GEOMETRY_PROGRAM_NV, core::min_(verticesOut, Driver->MaxGeometryVerticesOut)); +#endif + } +#endif + + if (!linkProgram()) + return; + + // register myself as new material + outMaterialTypeNr = Driver->addMaterialRenderer(this); +} + + +bool COpenGLSLMaterialRenderer::OnRender(IMaterialRendererServices* service, + E_VERTEX_TYPE vtxtype) +{ + // call callback to set shader constants + if (CallBack && (Program||Program2)) + CallBack->OnSetConstants(this, UserData); + + return true; +} + + +void COpenGLSLMaterialRenderer::OnSetMaterial(const video::SMaterial& material, + const video::SMaterial& lastMaterial, + bool resetAllRenderstates, + video::IMaterialRendererServices* services) +{ + if (Driver->getFixedPipelineState() == COpenGLDriver::EOFPS_ENABLE) + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_ENABLE_TO_DISABLE); + else + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_DISABLE); + + COpenGLCacheHandler* cacheHandler = Driver->getCacheHandler(); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + if (Program2) + Driver->irrGlUseProgram(Program2); + else if (Program) + Driver->extGlUseProgramObject(Program); + } + + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (Alpha) + { + cacheHandler->setBlend(true); + cacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + else if (FixedBlending) + { + cacheHandler->setBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); + cacheHandler->setBlend(true); + } + else if (Blending) + { + E_BLEND_FACTOR srcRGBFact,dstRGBFact,srcAlphaFact,dstAlphaFact; + E_MODULATE_FUNC modulate; + u32 alphaSource; + unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulate, alphaSource, material.MaterialTypeParam); + + if (Driver->queryFeature(EVDF_BLEND_SEPARATE)) + { + cacheHandler->setBlendFuncSeparate(Driver->getGLBlend(srcRGBFact), Driver->getGLBlend(dstRGBFact), + Driver->getGLBlend(srcAlphaFact), Driver->getGLBlend(dstAlphaFact)); + } + else + { + cacheHandler->setBlendFunc(Driver->getGLBlend(srcRGBFact), Driver->getGLBlend(dstRGBFact)); + } + + cacheHandler->setBlend(true); + } + else if (AlphaTest) + { + cacheHandler->setAlphaTest(true); + cacheHandler->setAlphaFunc(GL_GREATER, 0.5f); + } + + if (CallBack) + CallBack->OnSetMaterial(material); +} + + +void COpenGLSLMaterialRenderer::OnUnsetMaterial() +{ + if (Program) + Driver->extGlUseProgramObject(0); + if (Program2) + Driver->irrGlUseProgram(0); + + COpenGLCacheHandler* cacheHandler = Driver->getCacheHandler(); + if (Alpha || FixedBlending || Blending) + { + cacheHandler->setBlend(false); + } + else if (AlphaTest) + { + cacheHandler->setAlphaTest(false); + } +} + + +//! Returns if the material is transparent. +bool COpenGLSLMaterialRenderer::isTransparent() const +{ + return (Alpha || Blending || FixedBlending); +} + + +bool COpenGLSLMaterialRenderer::createProgram() +{ + if (Driver->Version>=200) + Program2 = Driver->extGlCreateProgram(); + else + Program = Driver->extGlCreateProgramObject(); + return true; +} + + +bool COpenGLSLMaterialRenderer::createShader(GLenum shaderType, const char* shader) +{ + if (Program2) + { + GLuint shaderHandle = Driver->extGlCreateShader(shaderType); + Driver->extGlShaderSource(shaderHandle, 1, &shader, NULL); + Driver->extGlCompileShader(shaderHandle); + + GLint status = 0; + +#ifdef GL_VERSION_2_0 + Driver->extGlGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &status); +#endif + + if (status != GL_TRUE) + { + core::stringc typeInfo("shaderType: "); + typeInfo += core::stringc((unsigned long)shaderType); + os::Printer::log("GLSL (> 2.x) shader failed to compile", typeInfo.c_str(), ELL_ERROR); + // check error message and log it + GLint maxLength=0; + GLint length; +#ifdef GL_VERSION_2_0 + Driver->extGlGetShaderiv(shaderHandle, GL_INFO_LOG_LENGTH, + &maxLength); +#endif + if (maxLength) + { + GLchar *infoLog = new GLchar[maxLength]; + Driver->extGlGetShaderInfoLog(shaderHandle, maxLength, &length, infoLog); + os::Printer::log(reinterpret_cast(infoLog), ELL_ERROR); + delete [] infoLog; + } + + return false; + } + + Driver->extGlAttachShader(Program2, shaderHandle); + } + else + { + GLhandleARB shaderHandle = Driver->extGlCreateShaderObject(shaderType); + + Driver->extGlShaderSourceARB(shaderHandle, 1, &shader, NULL); + Driver->extGlCompileShaderARB(shaderHandle); + + GLint status = 0; + +#ifdef GL_ARB_shader_objects + Driver->extGlGetObjectParameteriv(shaderHandle, GL_OBJECT_COMPILE_STATUS_ARB, &status); +#endif + + if (!status) + { + core::stringc typeInfo("shaderType: "); + typeInfo += core::stringc((unsigned long)shaderType); + os::Printer::log("GLSL shader failed to compile", typeInfo.c_str(), ELL_ERROR); + // check error message and log it + GLint maxLength=0; + GLsizei length; +#ifdef GL_ARB_shader_objects + Driver->extGlGetObjectParameteriv(shaderHandle, + GL_OBJECT_INFO_LOG_LENGTH_ARB, &maxLength); +#endif + if (maxLength) + { + GLcharARB *infoLog = new GLcharARB[maxLength]; + Driver->extGlGetInfoLog(shaderHandle, maxLength, &length, infoLog); + os::Printer::log(reinterpret_cast(infoLog), ELL_ERROR); + delete [] infoLog; + } + + return false; + } + + Driver->extGlAttachObject(Program, shaderHandle); + } + return true; +} + + +bool COpenGLSLMaterialRenderer::linkProgram() +{ + if (Program2) + { + Driver->extGlLinkProgram(Program2); + + GLint status = 0; + +#ifdef GL_VERSION_2_0 + Driver->extGlGetProgramiv(Program2, GL_LINK_STATUS, &status); +#endif + + if (!status) + { + os::Printer::log("GLSL (> 2.x) shader program failed to link", ELL_ERROR); + // check error message and log it + GLint maxLength=0; + GLsizei length; +#ifdef GL_VERSION_2_0 + Driver->extGlGetProgramiv(Program2, GL_INFO_LOG_LENGTH, &maxLength); +#endif + if (maxLength) + { + GLchar *infoLog = new GLchar[maxLength]; + Driver->extGlGetProgramInfoLog(Program2, maxLength, &length, infoLog); + os::Printer::log(reinterpret_cast(infoLog), ELL_ERROR); + delete [] infoLog; + } + + return false; + } + + // get uniforms information + + GLint num = 0; +#ifdef GL_VERSION_2_0 + Driver->extGlGetProgramiv(Program2, GL_ACTIVE_UNIFORMS, &num); +#endif + + if (num == 0) + { + // no uniforms + return true; + } + + GLint maxlen = 0; +#ifdef GL_VERSION_2_0 + Driver->extGlGetProgramiv(Program2, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxlen); +#endif + + if (maxlen == 0) + { + os::Printer::log("GLSL (> 2.x): failed to retrieve uniform information", ELL_ERROR); + return false; + } + + // seems that some implementations use an extra null terminator + ++maxlen; + c8 *buf = new c8[maxlen]; + + UniformInfo.clear(); + UniformInfo.reallocate(num); + + for (GLint i=0; i < num; ++i) + { + SUniformInfo ui; + memset(buf, 0, maxlen); + + GLint size; + Driver->extGlGetActiveUniform(Program2, i, maxlen, 0, &size, &ui.type, reinterpret_cast(buf)); + ui.name = buf; + ui.location = Driver->extGlGetUniformLocation(Program2, buf); + + UniformInfo.push_back(ui); + } + + delete [] buf; + } + else + { + Driver->extGlLinkProgramARB(Program); + + GLint status = 0; + +#ifdef GL_ARB_shader_objects + Driver->extGlGetObjectParameteriv(Program, GL_OBJECT_LINK_STATUS_ARB, &status); +#endif + + if (!status) + { + os::Printer::log("GLSL shader program failed to link", ELL_ERROR); + // check error message and log it + GLint maxLength=0; + GLsizei length; +#ifdef GL_ARB_shader_objects + Driver->extGlGetObjectParameteriv(Program, + GL_OBJECT_INFO_LOG_LENGTH_ARB, &maxLength); +#endif + if (maxLength) + { + GLcharARB *infoLog = new GLcharARB[maxLength]; + Driver->extGlGetInfoLog(Program, maxLength, &length, infoLog); + os::Printer::log(reinterpret_cast(infoLog), ELL_ERROR); + delete [] infoLog; + } + + return false; + } + + // get uniforms information + + GLint num = 0; + #ifdef GL_ARB_shader_objects + Driver->extGlGetObjectParameteriv(Program, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &num); + #endif + + if (num == 0) + { + // no uniforms + return true; + } + + GLint maxlen = 0; + #ifdef GL_ARB_shader_objects + Driver->extGlGetObjectParameteriv(Program, GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB, &maxlen); + #endif + + if (maxlen == 0) + { + os::Printer::log("GLSL: failed to retrieve uniform information", ELL_ERROR); + return false; + } + + // seems that some implementations use an extra null terminator + ++maxlen; + c8 *buf = new c8[maxlen]; + + UniformInfo.clear(); + UniformInfo.reallocate(num); + + for (int i=0; i < num; ++i) + { + SUniformInfo ui; + memset(buf, 0, maxlen); + + GLint size; + Driver->extGlGetActiveUniformARB(Program, i, maxlen, 0, &size, &ui.type, reinterpret_cast(buf)); + ui.name = buf; + ui.location = Driver->extGlGetUniformLocationARB(Program, buf); + + UniformInfo.push_back(ui); + } + + delete [] buf; + } + + return true; +} + + +void COpenGLSLMaterialRenderer::setBasicRenderStates(const SMaterial& material, + const SMaterial& lastMaterial, + bool resetAllRenderstates) +{ + // forward + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); +} + +s32 COpenGLSLMaterialRenderer::getVertexShaderConstantID(const c8* name) +{ + return getPixelShaderConstantID(name); +} + +s32 COpenGLSLMaterialRenderer::getPixelShaderConstantID(const c8* name) +{ + for (u32 i = 0; i < UniformInfo.size(); ++i) + { + if (UniformInfo[i].name == name) + return i; + } + + return -1; +} + +void COpenGLSLMaterialRenderer::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount) +{ + os::Printer::log("Cannot set constant, please use high level shader call instead.", ELL_WARNING); +} + +void COpenGLSLMaterialRenderer::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount) +{ + os::Printer::log("Cannot set constant, use high level shader call.", ELL_WARNING); +} + +bool COpenGLSLMaterialRenderer::setVertexShaderConstant(s32 index, const f32* floats, int count) +{ + return setPixelShaderConstant(index, floats, count); +} + +bool COpenGLSLMaterialRenderer::setVertexShaderConstant(s32 index, const s32* ints, int count) +{ + return setPixelShaderConstant(index, ints, count); +} + +bool COpenGLSLMaterialRenderer::setPixelShaderConstant(s32 index, const f32* floats, int count) +{ +#ifdef GL_ARB_shader_objects + if(index < 0 || UniformInfo[index].location < 0) + return false; + + bool status = true; + + switch (UniformInfo[index].type) + { + case GL_FLOAT: + Driver->extGlUniform1fv(UniformInfo[index].location, count, floats); + break; + case GL_FLOAT_VEC2: + Driver->extGlUniform2fv(UniformInfo[index].location, count/2, floats); + break; + case GL_FLOAT_VEC3: + Driver->extGlUniform3fv(UniformInfo[index].location, count/3, floats); + break; + case GL_FLOAT_VEC4: + Driver->extGlUniform4fv(UniformInfo[index].location, count/4, floats); + break; + case GL_FLOAT_MAT2: + Driver->extGlUniformMatrix2fv(UniformInfo[index].location, count/4, false, floats); + break; + case GL_FLOAT_MAT3: + Driver->extGlUniformMatrix3fv(UniformInfo[index].location, count/9, false, floats); + break; + case GL_FLOAT_MAT4: + Driver->extGlUniformMatrix4fv(UniformInfo[index].location, count/16, false, floats); + break; + case GL_SAMPLER_1D: + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_1D_SHADOW: + case GL_SAMPLER_2D_SHADOW: + { + if(floats) + { + const GLint id = static_cast(*floats); + Driver->extGlUniform1iv(UniformInfo[index].location, 1, &id); + } + else + status = false; + } + break; + default: + status = false; + break; + } + return status; +#else + return false; +#endif +} + +bool COpenGLSLMaterialRenderer::setPixelShaderConstant(s32 index, const s32* ints, int count) +{ +#ifdef GL_ARB_shader_objects + if(index < 0 || UniformInfo[index].location < 0) + return false; + + bool status = true; + + switch (UniformInfo[index].type) + { + case GL_INT: + case GL_BOOL: + Driver->extGlUniform1iv(UniformInfo[index].location, count, reinterpret_cast(ints)); + break; + case GL_INT_VEC2: + case GL_BOOL_VEC2: + Driver->extGlUniform2iv(UniformInfo[index].location, count/2, reinterpret_cast(ints)); + break; + case GL_INT_VEC3: + case GL_BOOL_VEC3: + Driver->extGlUniform3iv(UniformInfo[index].location, count/3, reinterpret_cast(ints)); + break; + case GL_INT_VEC4: + case GL_BOOL_VEC4: + Driver->extGlUniform4iv(UniformInfo[index].location, count/4, reinterpret_cast(ints)); + break; + case GL_SAMPLER_1D: + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_1D_SHADOW: + case GL_SAMPLER_2D_SHADOW: + Driver->extGlUniform1iv(UniformInfo[index].location, 1, reinterpret_cast(ints)); + break; + default: + status = false; + break; + } + return status; +#else + return false; +#endif +} + +IVideoDriver* COpenGLSLMaterialRenderer::getVideoDriver() +{ + return Driver; +} + +} // end namespace video +} // end namespace irr + + +#endif + diff --git a/source/Irrlicht/COpenGLSLMaterialRenderer.h b/source/Irrlicht/COpenGLSLMaterialRenderer.h new file mode 100644 index 00000000..e3129eaa --- /dev/null +++ b/source/Irrlicht/COpenGLSLMaterialRenderer.h @@ -0,0 +1,134 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OPENGL_SHADER_LANGUAGE_MATERIAL_RENDERER_H_INCLUDED__ +#define __C_OPENGL_SHADER_LANGUAGE_MATERIAL_RENDERER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#include "EMaterialTypes.h" +#include "IMaterialRenderer.h" +#include "IMaterialRendererServices.h" +#include "IGPUProgrammingServices.h" +#include "irrArray.h" +#include "irrString.h" + +#include "COpenGLCommon.h" + +namespace irr +{ +namespace video +{ + +class COpenGLDriver; +class IShaderConstantSetCallBack; + +//! Class for using GLSL shaders with OpenGL +//! Please note: This renderer implements its own IMaterialRendererServices +class COpenGLSLMaterialRenderer : public IMaterialRenderer, public IMaterialRendererServices +{ +public: + + //! Constructor + COpenGLSLMaterialRenderer( + COpenGLDriver* driver, + s32& outMaterialTypeNr, + const c8* vertexShaderProgram = 0, + const c8* vertexShaderEntryPointName = 0, + E_VERTEX_SHADER_TYPE vsCompileTarget = video::EVST_VS_1_1, + const c8* pixelShaderProgram = 0, + const c8* pixelShaderEntryPointName = 0, + E_PIXEL_SHADER_TYPE psCompileTarget = video::EPST_PS_1_1, + const c8* geometryShaderProgram = 0, + const c8* geometryShaderEntryPointName = "main", + E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0, + scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES, + scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP, + u32 verticesOut = 0, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = EMT_SOLID, + s32 userData = 0); + + //! Destructor + virtual ~COpenGLSLMaterialRenderer(); + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_; + + virtual bool OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) _IRR_OVERRIDE_; + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_; + + //! Returns if the material is transparent. + virtual bool isTransparent() const _IRR_OVERRIDE_; + + //! Access the callback provided by the users when creating shader materials + virtual IShaderConstantSetCallBack* getShaderConstantSetCallBack() const _IRR_OVERRIDE_ + { + return CallBack; + } + + // implementations for the render services + virtual void setBasicRenderStates(const SMaterial& material, const SMaterial& lastMaterial, bool resetAllRenderstates) _IRR_OVERRIDE_; + virtual s32 getVertexShaderConstantID(const c8* name) _IRR_OVERRIDE_; + virtual s32 getPixelShaderConstantID(const c8* name) _IRR_OVERRIDE_; + virtual void setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1) _IRR_OVERRIDE_; + virtual void setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1) _IRR_OVERRIDE_; + virtual bool setVertexShaderConstant(s32 index, const f32* floats, int count) _IRR_OVERRIDE_; + virtual bool setVertexShaderConstant(s32 index, const s32* ints, int count) _IRR_OVERRIDE_; + virtual bool setPixelShaderConstant(s32 index, const f32* floats, int count) _IRR_OVERRIDE_; + virtual bool setPixelShaderConstant(s32 index, const s32* ints, int count) _IRR_OVERRIDE_; + virtual IVideoDriver* getVideoDriver() _IRR_OVERRIDE_; + +protected: + + //! constructor only for use by derived classes who want to + //! create a fall back material for example. + COpenGLSLMaterialRenderer(COpenGLDriver* driver, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, + s32 userData=0); + + void init(s32& outMaterialTypeNr, + const c8* vertexShaderProgram, + const c8* pixelShaderProgram, + const c8* geometryShaderProgram, + scene::E_PRIMITIVE_TYPE inType=scene::EPT_TRIANGLES, + scene::E_PRIMITIVE_TYPE outType=scene::EPT_TRIANGLE_STRIP, + u32 verticesOut=0); + + bool createProgram(); + bool createShader(GLenum shaderType, const char* shader); + bool linkProgram(); + + COpenGLDriver* Driver; + IShaderConstantSetCallBack* CallBack; + + bool Alpha; + bool Blending; + bool FixedBlending; + bool AlphaTest; + + struct SUniformInfo + { + core::stringc name; + GLenum type; + GLint location; + }; + + GLhandleARB Program; + GLuint Program2; + core::array UniformInfo; + s32 UserData; +}; + + +} // end namespace video +} // end namespace irr + +#endif // compile with OpenGL +#endif // if included + diff --git a/source/Irrlicht/COpenGLShaderMaterialRenderer.cpp b/source/Irrlicht/COpenGLShaderMaterialRenderer.cpp new file mode 100644 index 00000000..1dabd311 --- /dev/null +++ b/source/Irrlicht/COpenGLShaderMaterialRenderer.cpp @@ -0,0 +1,422 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "COpenGLShaderMaterialRenderer.h" + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#include "IGPUProgrammingServices.h" +#include "IShaderConstantSetCallBack.h" +#include "IVideoDriver.h" +#include "os.h" + +#include "COpenGLDriver.h" +#include "COpenGLCacheHandler.h" +#include "COpenGLMaterialRenderer.h" + +namespace irr +{ +namespace video +{ + + +//! Constructor +COpenGLShaderMaterialRenderer::COpenGLShaderMaterialRenderer(video::COpenGLDriver* driver, + s32& outMaterialTypeNr, const c8* vertexShaderProgram, const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, E_MATERIAL_TYPE baseMaterial, s32 userData) + : Driver(driver), CallBack(callback), Alpha(false), Blending(false), FixedBlending(false), + AlphaTest(false), VertexShader(0), UserData(userData) +{ + #ifdef _DEBUG + setDebugName("COpenGLShaderMaterialRenderer"); + #endif + + PixelShader.set_used(4); + for (u32 i=0; i<4; ++i) + { + PixelShader[i]=0; + } + + switch (baseMaterial) + { + case EMT_TRANSPARENT_VERTEX_ALPHA: + case EMT_TRANSPARENT_ALPHA_CHANNEL: + case EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA: + case EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA: + Alpha = true; + break; + case EMT_TRANSPARENT_ADD_COLOR: + case EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR: + case EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR: + FixedBlending = true; + break; + case EMT_ONETEXTURE_BLEND: + Blending = true; + break; + case EMT_TRANSPARENT_ALPHA_CHANNEL_REF: + AlphaTest = true; + break; + default: + break; + } + + if (CallBack) + CallBack->grab(); + + init(outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram, EVT_STANDARD); +} + + +//! constructor only for use by derived classes who want to +//! create a fall back material for example. +COpenGLShaderMaterialRenderer::COpenGLShaderMaterialRenderer(COpenGLDriver* driver, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, s32 userData) +: Driver(driver), CallBack(callback), Alpha(false), Blending(false), FixedBlending(false), + AlphaTest(false), VertexShader(0), UserData(userData) +{ + PixelShader.set_used(4); + for (u32 i=0; i<4; ++i) + { + PixelShader[i]=0; + } + + switch (baseMaterial) + { + case EMT_TRANSPARENT_VERTEX_ALPHA: + case EMT_TRANSPARENT_ALPHA_CHANNEL: + case EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA: + case EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA: + Alpha = true; + break; + case EMT_TRANSPARENT_ADD_COLOR: + case EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR: + case EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR: + FixedBlending = true; + break; + case EMT_ONETEXTURE_BLEND: + Blending = true; + break; + case EMT_TRANSPARENT_ALPHA_CHANNEL_REF: + AlphaTest = true; + break; + default: + break; + } + + if (CallBack) + CallBack->grab(); +} + + +//! Destructor +COpenGLShaderMaterialRenderer::~COpenGLShaderMaterialRenderer() +{ + if (CallBack) + CallBack->drop(); + + if (VertexShader) + Driver->extGlDeletePrograms(1, &VertexShader); + + for (u32 i=0; iextGlDeletePrograms(1, &PixelShader[i]); +} + + +void COpenGLShaderMaterialRenderer::init(s32& outMaterialTypeNr, + const c8* vertexShaderProgram, const c8* pixelShaderProgram, + E_VERTEX_TYPE type) +{ + outMaterialTypeNr = -1; + + bool success; + + // create vertex shader + success=createVertexShader(vertexShaderProgram); + + // create pixel shader + if (!createPixelShader(pixelShaderProgram) || !success) + return; + + // register as a new material + outMaterialTypeNr = Driver->addMaterialRenderer(this); +} + + +bool COpenGLShaderMaterialRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) +{ + // call callback to set shader constants + if (CallBack && (VertexShader || PixelShader[0])) + CallBack->OnSetConstants(service, UserData); + + return true; +} + + +void COpenGLShaderMaterialRenderer::OnSetMaterial(const video::SMaterial& material, const video::SMaterial& lastMaterial, + bool resetAllRenderstates, video::IMaterialRendererServices* services) +{ + if (Driver->getFixedPipelineState() == COpenGLDriver::EOFPS_ENABLE) + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_ENABLE_TO_DISABLE); + else + Driver->setFixedPipelineState(COpenGLDriver::EOFPS_DISABLE); + + COpenGLCacheHandler* cacheHandler = Driver->getCacheHandler(); + + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) + { + if (VertexShader) + { + // set new vertex shader +#ifdef GL_ARB_vertex_program + Driver->extGlBindProgram(GL_VERTEX_PROGRAM_ARB, VertexShader); + glEnable(GL_VERTEX_PROGRAM_ARB); +#elif defined(GL_NV_vertex_program) + Driver->extGlBindProgram(GL_VERTEX_PROGRAM_NV, VertexShader); + glEnable(GL_VERTEX_PROGRAM_NV); +#endif + } + + // set new pixel shader + if (PixelShader[0]) + { + GLuint nextShader=PixelShader[0]; + if (material.FogEnable) + { + GLint curFogMode; + glGetIntegerv(GL_FOG_MODE, &curFogMode); +// if (Driver->LinearFog && PixelShader[1]) + if (curFogMode==GL_LINEAR && PixelShader[1]) + nextShader=PixelShader[1]; +// else if (!Driver->LinearFog && PixelShader[2]) + else if (curFogMode==GL_EXP && PixelShader[2]) + nextShader=PixelShader[2]; + else if (curFogMode==GL_EXP2 && PixelShader[3]) + nextShader=PixelShader[3]; + } +#ifdef GL_ARB_fragment_program + Driver->extGlBindProgram(GL_FRAGMENT_PROGRAM_ARB, nextShader); + glEnable(GL_FRAGMENT_PROGRAM_ARB); +#elif defined(GL_NV_fragment_program) + Driver->extGlBindProgram(GL_FRAGMENT_PROGRAM_NV, nextShader); + glEnable(GL_FRAGMENT_PROGRAM_NV); +#endif + } + } + + Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); + + if (Alpha) + { + cacheHandler->setBlend(true); + cacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + else if (FixedBlending) + { + cacheHandler->setBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); + cacheHandler->setBlend(true); + } + else if (Blending) + { + E_BLEND_FACTOR srcRGBFact,dstRGBFact,srcAlphaFact,dstAlphaFact; + E_MODULATE_FUNC modulate; + u32 alphaSource; + unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulate, alphaSource, material.MaterialTypeParam); + + if (Driver->queryFeature(EVDF_BLEND_SEPARATE)) + { + cacheHandler->setBlendFuncSeparate(Driver->getGLBlend(srcRGBFact), Driver->getGLBlend(dstRGBFact), + Driver->getGLBlend(srcAlphaFact), Driver->getGLBlend(dstAlphaFact)); + } + else + { + cacheHandler->setBlendFunc(Driver->getGLBlend(srcRGBFact), Driver->getGLBlend(dstRGBFact)); + } + + cacheHandler->setBlend(true); + } + else if (AlphaTest) + { + cacheHandler->setAlphaTest(true); + cacheHandler->setAlphaFunc(GL_GREATER, 0.5f); + } + + if (CallBack) + CallBack->OnSetMaterial(material); +} + + +void COpenGLShaderMaterialRenderer::OnUnsetMaterial() +{ + // disable vertex shader +#ifdef GL_ARB_vertex_program + if (VertexShader) + glDisable(GL_VERTEX_PROGRAM_ARB); +#elif defined(GL_NV_vertex_program) + if (VertexShader) + glDisable(GL_VERTEX_PROGRAM_NV); +#endif + +#ifdef GL_ARB_fragment_program + if (PixelShader[0]) + glDisable(GL_FRAGMENT_PROGRAM_ARB); +#elif defined(GL_NV_fragment_program) + if (PixelShader[0]) + glDisable(GL_FRAGMENT_PROGRAM_NV); +#endif + + COpenGLCacheHandler* cacheHandler = Driver->getCacheHandler(); + if (Alpha || FixedBlending || Blending) + { + cacheHandler->setBlend(false); + } + else if (AlphaTest) + { + cacheHandler->setAlphaTest(false); + } +} + + +//! Returns if the material is transparent. +bool COpenGLShaderMaterialRenderer::isTransparent() const +{ + return (Alpha || Blending || FixedBlending); +} + + +// This method needs a properly cleaned error state before the checked instruction is called +bool COpenGLShaderMaterialRenderer::checkError(const irr::c8* type) +{ +#if defined(GL_ARB_vertex_program) || defined(GL_NV_vertex_program) || defined(GL_ARB_fragment_program) || defined(GL_NV_fragment_program) + GLenum g = glGetError(); + if (g == GL_NO_ERROR) + return false; + + core::stringc errString = type; + errString += " compilation failed"; + + errString += " at position "; + GLint errPos=-1; +#if defined(GL_ARB_vertex_program) || defined(GL_ARB_fragment_program) + glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos ); +#else + glGetIntegerv( GL_PROGRAM_ERROR_POSITION_NV, &errPos ); +#endif + errString += core::stringc(s32(errPos)); + errString += ":\n"; +#if defined(GL_ARB_vertex_program) || defined(GL_ARB_fragment_program) + errString += reinterpret_cast(glGetString(GL_PROGRAM_ERROR_STRING_ARB)); +#else + errString += reinterpret_cast(glGetString(GL_PROGRAM_ERROR_STRING_NV)); +#endif +#else + core::stringc errString("Shaders not supported."); +#endif + os::Printer::log(errString.c_str(), ELL_ERROR); + return true; +} + + +bool COpenGLShaderMaterialRenderer::createPixelShader(const c8* pxsh) +{ + if (!pxsh) + return true; + + const core::stringc inshdr(pxsh); + core::stringc shdr; + const s32 pos = inshdr.find("#_IRR_FOG_MODE_"); + const u32 numShaders = (-1 != pos)?4:1; + + for (u32 i=0; iextGlGenPrograms(1, &PixelShader[i]); +#ifdef GL_ARB_fragment_program + Driver->extGlBindProgram(GL_FRAGMENT_PROGRAM_ARB, PixelShader[i]); +#elif defined GL_NV_fragment_program + Driver->extGlBindProgram(GL_FRAGMENT_PROGRAM_NV, PixelShader[i]); +#endif + + // clear error buffer + while(glGetError() != GL_NO_ERROR) + {} + +#ifdef GL_ARB_fragment_program + // compile + Driver->extGlProgramString(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, + shdr.size(), shdr.c_str()); +#elif defined GL_NV_fragment_program + Driver->extGlLoadProgram(GL_FRAGMENT_PROGRAM_NV, PixelShader[i], + shdr.size(), shdr.c_str()); +#endif + + if (checkError("Pixel shader")) + { + Driver->extGlDeletePrograms(1, &PixelShader[i]); + PixelShader[i]=0; + + return false; + } + } + + return true; +} + + +bool COpenGLShaderMaterialRenderer::createVertexShader(const c8* vtxsh) +{ + if (!vtxsh) + return true; + + Driver->extGlGenPrograms(1, &VertexShader); +#ifdef GL_ARB_vertex_program + Driver->extGlBindProgram(GL_VERTEX_PROGRAM_ARB, VertexShader); +#elif defined GL_NV_vertex_program + Driver->extGlBindProgram(GL_VERTEX_PROGRAM_NV, VertexShader); +#endif + + // clear error buffer + while(glGetError() != GL_NO_ERROR) + {} + + // compile +#ifdef GL_ARB_vertex_program + Driver->extGlProgramString(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, + (GLsizei)strlen(vtxsh), vtxsh); +#elif defined GL_NV_vertex_program + Driver->extGlLoadProgram(GL_VERTEX_PROGRAM_NV, VertexShader, + (GLsizei)strlen(vtxsh), vtxsh); +#endif + + if (checkError("Vertex shader")) + { + Driver->extGlDeletePrograms(1, &VertexShader); + VertexShader=0; + + return false; + } + + return true; +} + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/COpenGLShaderMaterialRenderer.h b/source/Irrlicht/COpenGLShaderMaterialRenderer.h new file mode 100644 index 00000000..7cae915e --- /dev/null +++ b/source/Irrlicht/COpenGLShaderMaterialRenderer.h @@ -0,0 +1,97 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OPENGL_SHADER_MATERIAL_RENDERER_H_INCLUDED__ +#define __C_OPENGL_SHADER_MATERIAL_RENDERER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OPENGL_ + +#include "IMaterialRenderer.h" + +#include "COpenGLCommon.h" + +namespace irr +{ +namespace video +{ + +class COpenGLDriver; +class IShaderConstantSetCallBack; + +//! Class for using vertex and pixel shaders with OpenGL (asm not glsl!) +class COpenGLShaderMaterialRenderer : public IMaterialRenderer +{ +public: + + //! Constructor + COpenGLShaderMaterialRenderer(COpenGLDriver* driver, + s32& outMaterialTypeNr, const c8* vertexShaderProgram, const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, E_MATERIAL_TYPE baseMaterial, s32 userData); + + //! Destructor + virtual ~COpenGLShaderMaterialRenderer(); + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_; + + virtual bool OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) _IRR_OVERRIDE_; + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_; + + //! Returns if the material is transparent. + virtual bool isTransparent() const _IRR_OVERRIDE_; + + //! Access the callback provided by the users when creating shader materials + virtual IShaderConstantSetCallBack* getShaderConstantSetCallBack() const _IRR_OVERRIDE_ + { + return CallBack; + } + +protected: + + //! constructor only for use by derived classes who want to + //! create a fall back material for example. + COpenGLShaderMaterialRenderer(COpenGLDriver* driver, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, s32 userData=0); + + // must not be called more than once! + void init(s32& outMaterialTypeNr, const c8* vertexShaderProgram, + const c8* pixelShaderProgram, E_VERTEX_TYPE type); + + bool createPixelShader(const c8* pxsh); + bool createVertexShader(const c8* vtxsh); + bool checkError(const irr::c8* type); + + COpenGLDriver* Driver; + IShaderConstantSetCallBack* CallBack; + + // I didn't write this, but here's my understanding: + // Those flags seem to be exclusive so far (so could be an enum). + // Maybe the idea was to make them non-exclusive in future (basically having a shader-material) + // Actually currently there's not even any need to cache them (probably even slower than not doing so). + // They seem to be mostly for downward compatibility. + // I suppose the idea is to use SMaterial.BlendOperation + SMaterial.BlendFactor and a simple non-transparent type as base for more flexibility in the future. + // Note that SMaterial.BlendOperation + SMaterial.BlendFactor are in some drivers already evaluated before OnSetMaterial. + bool Alpha; + bool Blending; + bool FixedBlending; + bool AlphaTest; + + GLuint VertexShader; + // We have 4 values here, [0] is the non-fog version, the other three are + // ARB_fog_linear, ARB_fog_exp, and ARB_fog_exp2 in that order + core::array PixelShader; + s32 UserData; +}; + + +} // end namespace video +} // end namespace irr + +#endif +#endif + diff --git a/source/Irrlicht/CPLYMeshFileLoader.cpp b/source/Irrlicht/CPLYMeshFileLoader.cpp new file mode 100644 index 00000000..03b3e471 --- /dev/null +++ b/source/Irrlicht/CPLYMeshFileLoader.cpp @@ -0,0 +1,818 @@ +// Copyright (C) 2009-2012 Gaz Davidson +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_PLY_LOADER_ + +#include "CPLYMeshFileLoader.h" +#include "IMeshManipulator.h" +#include "SMesh.h" +#include "CDynamicMeshBuffer.h" +#include "SAnimatedMesh.h" +#include "IReadFile.h" +#include "fast_atof.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + +// input buffer must be at least twice as long as the longest line in the file +#define PLY_INPUT_BUFFER_SIZE 51200 // file is loaded in 50k chunks + +// constructor +CPLYMeshFileLoader::CPLYMeshFileLoader(scene::ISceneManager* smgr) +: SceneManager(smgr), File(0), Buffer(0) +{ +} + + +CPLYMeshFileLoader::~CPLYMeshFileLoader() +{ + // delete the buffer in case we didn't earlier + // (we do, but this could be disabled to increase the speed of loading hundreds of meshes) + if (Buffer) + { + delete [] Buffer; + Buffer = 0; + } + + // Destroy the element list if it exists + for (u32 i=0; igrab(); + + // attempt to allocate the buffer and fill with data + if (!allocateBuffer()) + { + File->drop(); + File = 0; + return 0; + } + + // start with empty mesh + SAnimatedMesh* animMesh = 0; + u32 vertCount=0; + + // Currently only supports ASCII meshes + if (strcmp(getNextLine(), "ply")) + { + os::Printer::log("Not a valid PLY file", file->getFileName().c_str(), ELL_ERROR); + } + else + { + // cut the next line out + getNextLine(); + // grab the word from this line + c8 *word = getNextWord(); + + // ignore comments + while (strcmp(word, "comment") == 0) + { + getNextLine(); + word = getNextWord(); + } + + bool readingHeader = true; + bool continueReading = true; + IsBinaryFile = false; + IsWrongEndian= false; + + do + { + if (strcmp(word, "format") == 0) + { + word = getNextWord(); + + if (strcmp(word, "binary_little_endian") == 0) + { + IsBinaryFile = true; +#ifdef __BIG_ENDIAN__ + IsWrongEndian = true; +#endif + + } + else if (strcmp(word, "binary_big_endian") == 0) + { + IsBinaryFile = true; +#ifndef __BIG_ENDIAN__ + IsWrongEndian = true; +#endif + } + else if (strcmp(word, "ascii")) + { + // abort if this isn't an ascii or a binary mesh + os::Printer::log("Unsupported PLY mesh format", word, ELL_ERROR); + continueReading = false; + } + + if (continueReading) + { + word = getNextWord(); + if (strcmp(word, "1.0")) + { + os::Printer::log("Unsupported PLY mesh version", word, ELL_WARNING); + } + } + } + else if (strcmp(word, "property") == 0) + { + word = getNextWord(); + + if (!ElementList.size()) + { + os::Printer::log("PLY property found before element", word, ELL_WARNING); + } + else + { + // get element + SPLYElement* el = ElementList[ElementList.size()-1]; + + // fill property struct + SPLYProperty prop; + prop.Type = getPropertyType(word); + el->KnownSize += prop.size(); + + if (prop.Type == EPLYPT_LIST) + { + el->IsFixedWidth = false; + + word = getNextWord(); + + prop.Data.List.CountType = getPropertyType(word); + if (IsBinaryFile && prop.Data.List.CountType == EPLYPT_UNKNOWN) + { + os::Printer::log("Cannot read binary PLY file containing data types of unknown length", word, ELL_ERROR); + continueReading = false; + } + else + { + word = getNextWord(); + prop.Data.List.ItemType = getPropertyType(word); + if (IsBinaryFile && prop.Data.List.ItemType == EPLYPT_UNKNOWN) + { + os::Printer::log("Cannot read binary PLY file containing data types of unknown length", word, ELL_ERROR); + continueReading = false; + } + } + } + else if (IsBinaryFile && prop.Type == EPLYPT_UNKNOWN) + { + os::Printer::log("Cannot read binary PLY file containing data types of unknown length", word, ELL_ERROR); + continueReading = false; + } + + prop.Name = getNextWord(); + + // add property to element + el->Properties.push_back(prop); + } + } + else if (strcmp(word, "element") == 0) + { + SPLYElement* el = new SPLYElement; + el->Name = getNextWord(); + el->Count = atoi(getNextWord()); + el->IsFixedWidth = true; + el->KnownSize = 0; + ElementList.push_back(el); + + if (el->Name == "vertex") + vertCount = el->Count; + + } + else if (strcmp(word, "end_header") == 0) + { + readingHeader = false; + if (IsBinaryFile) + { + StartPointer = LineEndPointer + 1; + } + } + else if (strcmp(word, "comment") == 0) + { + // ignore line + } + else + { + os::Printer::log("Unknown item in PLY file", word, ELL_WARNING); + } + + if (readingHeader && continueReading) + { + getNextLine(); + word = getNextWord(); + } + } + while (readingHeader && continueReading); + + // now to read the actual data from the file + if (continueReading) + { + // create a mesh buffer + CDynamicMeshBuffer *mb = new CDynamicMeshBuffer(video::EVT_STANDARD, vertCount > 65565 ? video::EIT_32BIT : video::EIT_16BIT); + mb->getVertexBuffer().reallocate(vertCount); + mb->getIndexBuffer().reallocate(vertCount); + mb->setHardwareMappingHint(EHM_STATIC); + + bool hasNormals=true; + // loop through each of the elements + for (u32 i=0; iName == "vertex") + { + // loop through vertex properties + for (u32 j=0; j < ElementList[i]->Count; ++j) + hasNormals &= readVertex(*ElementList[i], mb); + } + else if (ElementList[i]->Name == "face") + { + // read faces + for (u32 j=0; j < ElementList[i]->Count; ++j) + readFace(*ElementList[i], mb); + } + else + { + // skip these elements + for (u32 j=0; j < ElementList[i]->Count; ++j) + skipElement(*ElementList[i]); + } + } + mb->recalculateBoundingBox(); + if (!hasNormals) + SceneManager->getMeshManipulator()->recalculateNormals(mb); + SMesh* m = new SMesh(); + m->addMeshBuffer(mb); + m->recalculateBoundingBox(); + mb->drop(); + animMesh = new SAnimatedMesh(); + animMesh->addMesh(m); + animMesh->recalculateBoundingBox(); + m->drop(); + } + } + + + // free the buffer + delete [] Buffer; + Buffer = 0; + File->drop(); + File = 0; + + // if we managed to create a mesh, return it + return animMesh; +} + + +bool CPLYMeshFileLoader::readVertex(const SPLYElement &Element, scene::CDynamicMeshBuffer* mb) +{ + if (!IsBinaryFile) + getNextLine(); + + video::S3DVertex vert; + vert.Color.set(255,255,255,255); + vert.TCoords.X = 0.0f; + vert.TCoords.Y = 0.0f; + vert.Normal.X = 0.0f; + vert.Normal.Y = 1.0f; + vert.Normal.Z = 0.0f; + + bool result=false; + for (u32 i=0; i < Element.Properties.size(); ++i) + { + E_PLY_PROPERTY_TYPE t = Element.Properties[i].Type; + + if (Element.Properties[i].Name == "x") + vert.Pos.X = getFloat(t); + else if (Element.Properties[i].Name == "y") + vert.Pos.Z = getFloat(t); + else if (Element.Properties[i].Name == "z") + vert.Pos.Y = getFloat(t); + else if (Element.Properties[i].Name == "nx") + { + vert.Normal.X = getFloat(t); + result=true; + } + else if (Element.Properties[i].Name == "ny") + { + vert.Normal.Z = getFloat(t); + result=true; + } + else if (Element.Properties[i].Name == "nz") + { + vert.Normal.Y = getFloat(t); + result=true; + } + // there isn't a single convention for the UV, some software like Blender or Assimp uses "st" instead of "uv" + else if (Element.Properties[i].Name == "u" || Element.Properties[i].Name == "s") + vert.TCoords.X = getFloat(t); + else if (Element.Properties[i].Name == "v" || Element.Properties[i].Name == "t") + vert.TCoords.Y = getFloat(t); + else if (Element.Properties[i].Name == "red") + { + u32 value = Element.Properties[i].isFloat() ? (u32)(getFloat(t)*255.0f) : getInt(t); + vert.Color.setRed(value); + } + else if (Element.Properties[i].Name == "green") + { + u32 value = Element.Properties[i].isFloat() ? (u32)(getFloat(t)*255.0f) : getInt(t); + vert.Color.setGreen(value); + } + else if (Element.Properties[i].Name == "blue") + { + u32 value = Element.Properties[i].isFloat() ? (u32)(getFloat(t)*255.0f) : getInt(t); + vert.Color.setBlue(value); + } + else if (Element.Properties[i].Name == "alpha") + { + u32 value = Element.Properties[i].isFloat() ? (u32)(getFloat(t)*255.0f) : getInt(t); + vert.Color.setAlpha(value); + } + else + skipProperty(Element.Properties[i]); + } + + mb->getVertexBuffer().push_back(vert); + + return result; +} + + +bool CPLYMeshFileLoader::readFace(const SPLYElement &Element, scene::CDynamicMeshBuffer* mb) +{ + if (!IsBinaryFile) + getNextLine(); + + for (u32 i=0; i < Element.Properties.size(); ++i) + { + if ( (Element.Properties[i].Name == "vertex_indices" || + Element.Properties[i].Name == "vertex_index") && Element.Properties[i].Type == EPLYPT_LIST) + { + // get count + s32 count = getInt(Element.Properties[i].Data.List.CountType); + u32 a = getInt(Element.Properties[i].Data.List.ItemType), + b = getInt(Element.Properties[i].Data.List.ItemType), + c = getInt(Element.Properties[i].Data.List.ItemType); + s32 j = 3; + + mb->getIndexBuffer().push_back(a); + mb->getIndexBuffer().push_back(c); + mb->getIndexBuffer().push_back(b); + + for (; j < count; ++j) + { + b = c; + c = getInt(Element.Properties[i].Data.List.ItemType); + mb->getIndexBuffer().push_back(a); + mb->getIndexBuffer().push_back(c); + mb->getIndexBuffer().push_back(b); + } + } + else if (Element.Properties[i].Name == "intensity") + { + // todo: face intensity + skipProperty(Element.Properties[i]); + } + else + skipProperty(Element.Properties[i]); + } + return true; +} + + +// skips an element and all properties. return false on EOF +void CPLYMeshFileLoader::skipElement(const SPLYElement &Element) +{ + if (IsBinaryFile) + if (Element.IsFixedWidth) + moveForward(Element.KnownSize); + else + for (u32 i=0; i < Element.Properties.size(); ++i) + skipProperty(Element.Properties[i]); + else + getNextLine(); +} + + +void CPLYMeshFileLoader::skipProperty(const SPLYProperty &Property) +{ + if (Property.Type == EPLYPT_LIST) + { + s32 count = getInt(Property.Data.List.CountType); + + for (s32 i=0; i < count; ++i) + getInt(Property.Data.List.CountType); + } + else + { + if (IsBinaryFile) + moveForward(Property.size()); + else + getNextWord(); + } +} + + +bool CPLYMeshFileLoader::allocateBuffer() +{ + // Destroy the element list if it exists + for (u32 i=0; igetPos() == File->getSize()) + { + EndOfFile = true; + } + else + { + // read data from the file + size_t count = File->read(EndPointer, PLY_INPUT_BUFFER_SIZE - length); + + // increment the end pointer by the number of bytes read + EndPointer = EndPointer + count; + + // if we didn't completely fill the buffer + if (count != PLY_INPUT_BUFFER_SIZE - length) + { + // blank the rest of the memory + memset(EndPointer, 0, Buffer + PLY_INPUT_BUFFER_SIZE - EndPointer); + + // end of file + EndOfFile = true; + } + } +} + + +// skips x bytes in the file, getting more data if required +void CPLYMeshFileLoader::moveForward(u32 bytes) +{ + if (StartPointer + bytes >= EndPointer) + fillBuffer(); + if (StartPointer + bytes < EndPointer) + StartPointer += bytes; + else + StartPointer = EndPointer; +} + + +E_PLY_PROPERTY_TYPE CPLYMeshFileLoader::getPropertyType(const c8* typeString) const +{ + if (strcmp(typeString, "char") == 0 || + strcmp(typeString, "uchar") == 0 || + strcmp(typeString, "int8") == 0 || + strcmp(typeString, "uint8") == 0) + { + return EPLYPT_INT8; + } + else if (strcmp(typeString, "uint") == 0 || + strcmp(typeString, "int16") == 0 || + strcmp(typeString, "uint16") == 0 || + strcmp(typeString, "short") == 0 || + strcmp(typeString, "ushort") == 0) + { + return EPLYPT_INT16; + } + else if (strcmp(typeString, "int") == 0 || + strcmp(typeString, "long") == 0 || + strcmp(typeString, "ulong") == 0 || + strcmp(typeString, "int32") == 0 || + strcmp(typeString, "uint32") == 0) + { + return EPLYPT_INT32; + } + else if (strcmp(typeString, "float") == 0 || + strcmp(typeString, "float32") == 0) + { + return EPLYPT_FLOAT32; + } + else if (strcmp(typeString, "float64") == 0 || + strcmp(typeString, "double") == 0) + { + return EPLYPT_FLOAT64; + } + else if ( strcmp(typeString, "list") == 0 ) + { + return EPLYPT_LIST; + } + else + { + // unsupported type. + // cannot be loaded in binary mode + return EPLYPT_UNKNOWN; + } +} + + +// Split the string data into a line in place by terminating it instead of copying. +c8* CPLYMeshFileLoader::getNextLine() +{ + // move the start pointer along + StartPointer = LineEndPointer + 1; + + // crlf split across buffer move + if (*StartPointer == '\n') + { + *StartPointer = '\0'; + ++StartPointer; + } + + // begin at the start of the next line + c8* pos = StartPointer; + while (pos < EndPointer && *pos && *pos != '\r' && *pos != '\n') + ++pos; + + if ( pos < EndPointer && ( *(pos+1) == '\r' || *(pos+1) == '\n') ) + { + *pos = '\0'; + ++pos; + } + + // we have reached the end of the buffer + if (pos >= EndPointer) + { + // get data from the file + if (!EndOfFile) + { + fillBuffer(); + // reset line end pointer + LineEndPointer = StartPointer - 1; + + if (StartPointer != EndPointer) + return getNextLine(); + else + return Buffer; + } + else + { + // EOF + StartPointer = EndPointer-1; + *StartPointer = '\0'; + return StartPointer; + } + } + else + { + // null terminate the string in place + *pos = '\0'; + LineEndPointer = pos; + WordLength = -1; + // return pointer to the start of the line + return StartPointer; + } +} + + +// null terminate the next word on the previous line and move the next word pointer along +// since we already have a full line in the buffer, we never need to retrieve more data +c8* CPLYMeshFileLoader::getNextWord() +{ + // move the start pointer along + StartPointer += WordLength + 1; + + if (StartPointer == LineEndPointer) + { + WordLength = -1; // + return LineEndPointer; + } + // begin at the start of the next word + c8* pos = StartPointer; + while (*pos && pos < LineEndPointer && pos < EndPointer && *pos != ' ' && *pos != '\t') + ++pos; + + while(*pos && pos < LineEndPointer && pos < EndPointer && (*pos == ' ' || *pos == '\t') ) + { + // null terminate the string in place + *pos = '\0'; + ++pos; + } + --pos; + WordLength = (s32)(pos-StartPointer); + // return pointer to the start of the word + return StartPointer; +} + + +// read the next float from the file and move the start pointer along +f32 CPLYMeshFileLoader::getFloat(E_PLY_PROPERTY_TYPE t) +{ + f32 retVal = 0.0f; + + if (IsBinaryFile) + { + if (EndPointer - StartPointer < 8) + fillBuffer(); + + if (EndPointer - StartPointer > 0) + { + switch (t) + { + case EPLYPT_INT8: + retVal = *StartPointer; + StartPointer++; + break; + case EPLYPT_INT16: + if (IsWrongEndian) + retVal = os::Byteswap::byteswap(*(reinterpret_cast(StartPointer))); + else + retVal = *(reinterpret_cast(StartPointer)); + StartPointer += 2; + break; + case EPLYPT_INT32: + if (IsWrongEndian) + retVal = f32(os::Byteswap::byteswap(*(reinterpret_cast(StartPointer)))); + else + retVal = f32(*(reinterpret_cast(StartPointer))); + StartPointer += 4; + break; + case EPLYPT_FLOAT32: + if (IsWrongEndian) + retVal = os::Byteswap::byteswap(*(reinterpret_cast(StartPointer))); + else + retVal = *(reinterpret_cast(StartPointer)); + StartPointer += 4; + break; + case EPLYPT_FLOAT64: + // todo: byteswap 64-bit + retVal = f32(*(reinterpret_cast(StartPointer))); + StartPointer += 8; + break; + case EPLYPT_LIST: + case EPLYPT_UNKNOWN: + default: + retVal = 0.0f; + StartPointer++; // ouch! + } + } + else + retVal = 0.0f; + } + else + { + c8* word = getNextWord(); + switch (t) + { + case EPLYPT_INT8: + case EPLYPT_INT16: + case EPLYPT_INT32: + retVal = f32(atoi(word)); + break; + case EPLYPT_FLOAT32: + case EPLYPT_FLOAT64: + retVal = f32(atof(word)); + break; + case EPLYPT_LIST: + case EPLYPT_UNKNOWN: + default: + retVal = 0.0f; + } + } + return retVal; +} + + +// read the next int from the file and move the start pointer along +u32 CPLYMeshFileLoader::getInt(E_PLY_PROPERTY_TYPE t) +{ + u32 retVal = 0; + + if (IsBinaryFile) + { + if (!EndOfFile && EndPointer - StartPointer < 8) + fillBuffer(); + + if (EndPointer - StartPointer) + { + switch (t) + { + case EPLYPT_INT8: + retVal = *StartPointer; + StartPointer++; + break; + case EPLYPT_INT16: + if (IsWrongEndian) + retVal = os::Byteswap::byteswap(*(reinterpret_cast(StartPointer))); + else + retVal = *(reinterpret_cast(StartPointer)); + StartPointer += 2; + break; + case EPLYPT_INT32: + if (IsWrongEndian) + retVal = os::Byteswap::byteswap(*(reinterpret_cast(StartPointer))); + else + retVal = *(reinterpret_cast(StartPointer)); + StartPointer += 4; + break; + case EPLYPT_FLOAT32: + if (IsWrongEndian) + retVal = (u32)os::Byteswap::byteswap(*(reinterpret_cast(StartPointer))); + else + retVal = (u32)(*(reinterpret_cast(StartPointer))); + StartPointer += 4; + break; + case EPLYPT_FLOAT64: + // todo: byteswap 64-bit + retVal = (u32)(*(reinterpret_cast(StartPointer))); + StartPointer += 8; + break; + case EPLYPT_LIST: + case EPLYPT_UNKNOWN: + default: + retVal = 0; + StartPointer++; // ouch! + } + } + else + retVal = 0; + } + else + { + c8* word = getNextWord(); + switch (t) + { + case EPLYPT_INT8: + case EPLYPT_INT16: + case EPLYPT_INT32: + retVal = atoi(word); + break; + case EPLYPT_FLOAT32: + case EPLYPT_FLOAT64: + retVal = u32(atof(word)); + break; + case EPLYPT_LIST: + case EPLYPT_UNKNOWN: + default: + retVal = 0; + } + } + return retVal; +} + + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PLY_LOADER_ + diff --git a/source/Irrlicht/CPLYMeshFileLoader.h b/source/Irrlicht/CPLYMeshFileLoader.h new file mode 100644 index 00000000..4335c924 --- /dev/null +++ b/source/Irrlicht/CPLYMeshFileLoader.h @@ -0,0 +1,148 @@ +// Copyright (C) 2009-2012 Gaz Davidson +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_PLY_MESH_FILE_LOADER_H_INCLUDED__ +#define __C_PLY_MESH_FILE_LOADER_H_INCLUDED__ + +#include "IMeshLoader.h" +#include "ISceneManager.h" +#include "CDynamicMeshBuffer.h" + +namespace irr +{ +namespace scene +{ + +enum E_PLY_PROPERTY_TYPE +{ + EPLYPT_INT8 = 0, + EPLYPT_INT16, + EPLYPT_INT32, + EPLYPT_FLOAT32, + EPLYPT_FLOAT64, + EPLYPT_LIST, + EPLYPT_UNKNOWN +}; + +//! Meshloader capable of loading obj meshes. +class CPLYMeshFileLoader : public IMeshLoader +{ +public: + + //! Constructor + CPLYMeshFileLoader(scene::ISceneManager* smgr); + + //! Destructor + virtual ~CPLYMeshFileLoader(); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".ply") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! creates/loads an animated mesh from the file. + virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_; + +private: + + struct SPLYProperty + { + core::stringc Name; + E_PLY_PROPERTY_TYPE Type; + union + { + u8 Int8; + u16 Int16; + u32 Int32; + f32 Float32; + f64 Double; + struct SPLYListProperty + { + E_PLY_PROPERTY_TYPE CountType; + E_PLY_PROPERTY_TYPE ItemType; + } List; + + } Data; + + inline u32 size() const + { + switch(Type) + { + case EPLYPT_INT8: + return 1; + case EPLYPT_INT16: + return 2; + case EPLYPT_INT32: + case EPLYPT_FLOAT32: + return 4; + case EPLYPT_FLOAT64: + return 8; + case EPLYPT_LIST: + case EPLYPT_UNKNOWN: + default: + return 0; + } + } + + inline bool isFloat() const + { + switch(Type) + { + case EPLYPT_FLOAT32: + case EPLYPT_FLOAT64: + return true; + case EPLYPT_INT8: + case EPLYPT_INT16: + case EPLYPT_INT32: + case EPLYPT_LIST: + case EPLYPT_UNKNOWN: + default: + return false; + } + } + }; + + struct SPLYElement + { + // name of the element. We only want "vertex" and "face" elements + // but we have to parse the others anyway. + core::stringc Name; + // The number of elements in the file + u32 Count; + // Properties of this element + core::array Properties; + // in binary files, true if this is a fixed size + bool IsFixedWidth; + // known size in bytes, 0 if unknown + u32 KnownSize; + }; + + bool allocateBuffer(); + c8* getNextLine(); + c8* getNextWord(); + void fillBuffer(); + E_PLY_PROPERTY_TYPE getPropertyType(const c8* typeString) const; + + bool readVertex(const SPLYElement &Element, scene::CDynamicMeshBuffer* mb); + bool readFace(const SPLYElement &Element, scene::CDynamicMeshBuffer* mb); + void skipElement(const SPLYElement &Element); + void skipProperty(const SPLYProperty &Property); + f32 getFloat(E_PLY_PROPERTY_TYPE t); + u32 getInt(E_PLY_PROPERTY_TYPE t); + void moveForward(u32 bytes); + + core::array ElementList; + + scene::ISceneManager* SceneManager; + io::IReadFile *File; + c8 *Buffer; + bool IsBinaryFile, IsWrongEndian, EndOfFile; + s32 WordLength; + c8 *StartPointer, *EndPointer, *LineEndPointer; +}; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CPLYMeshWriter.cpp b/source/Irrlicht/CPLYMeshWriter.cpp new file mode 100644 index 00000000..8713c582 --- /dev/null +++ b/source/Irrlicht/CPLYMeshWriter.cpp @@ -0,0 +1,220 @@ +// Copyright (C) 2008-2012 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_PLY_WRITER_ + +#include "CPLYMeshWriter.h" +#include "os.h" +#include "IMesh.h" +#include "IMeshBuffer.h" +#include "IWriteFile.h" + +namespace irr +{ +namespace scene +{ + +CPLYMeshWriter::CPLYMeshWriter() +{ + #ifdef _DEBUG + setDebugName("CPLYMeshWriter"); + #endif +} + + +//! Returns the type of the mesh writer +EMESH_WRITER_TYPE CPLYMeshWriter::getType() const +{ + return EMWT_PLY; +} + +//! writes a mesh +bool CPLYMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags) +{ + if (!file || !mesh) + return false; + + os::Printer::log("Writing mesh", file->getFileName()); + + // write PLY header + core::stringc header = "ply\n"; + + if (flags & scene::EMWF_WRITE_BINARY) + { + #ifdef __BIG_ENDIAN__ + header += "format binary_big_endian 1.0\n"; + #else + header += "format binary_little_endian 1.0\n"; + #endif + } + else + header += "format ascii 1.0\n"; + + header += "comment Irrlicht Engine "; + header += IRRLICHT_SDK_VERSION; + + // get vertex and triangle counts + u32 VertexCount = 0; + u32 TriangleCount = 0; + + for (u32 i=0; i < mesh->getMeshBufferCount(); ++i) + { + VertexCount += mesh->getMeshBuffer(i)->getVertexCount(); + TriangleCount += mesh->getMeshBuffer(i)->getIndexCount() / 3; + } + + // vertex definition + header += "\nelement vertex "; + header += VertexCount; + + header += "\n" + "property float x\n" + "property float y\n" + "property float z\n" + "property float nx\n" + "property float ny\n" + "property float nz\n" + "property float s\n" + "property float t\n" + "property uchar red\n" + "property uchar green\n" + "property uchar blue\n"; + // "property float tx\n" + // "property float ty\n" + // "property float tz\n" + + // face definition + + header += "element face "; + header += TriangleCount; + header += "\n" + "property list uchar int vertex_indices\n" + "end_header\n"; + + // write header + file->write(header.c_str(), header.size()); + + // write vertices + + c8 outLine[1024]; + + for (u32 i=0; i < mesh->getMeshBufferCount(); ++i) + { + const scene::IMeshBuffer* mb = mesh->getMeshBuffer(i); + u32 vertexSize = 0; + switch(mb->getVertexType()) + { + case video::EVT_STANDARD: + vertexSize = sizeof(video::S3DVertex); + break; + case video::EVT_2TCOORDS: + vertexSize = sizeof(video::S3DVertex2TCoords); + break; + case video::EVT_TANGENTS: + vertexSize = sizeof(video::S3DVertexTangents); + break; + } + u8 *vertices = (u8*)mb->getVertices() ; + + for (u32 j=0; j < mb->getVertexCount(); ++j) + { + u8 *buf = vertices + j * vertexSize; + const video::S3DVertex* vertex = ( (video::S3DVertex*)buf ); + const core::vector3df& pos = vertex->Pos; + const core::vector3df& n = vertex->Normal; + const core::vector2df& uv = vertex->TCoords; + const video::SColor& color = vertex->Color; + + if (flags & scene::EMWF_WRITE_BINARY) + { + // Y and Z are flipped + file->write(&pos.X, 4); + file->write(&pos.Z, 4); + file->write(&pos.Y, 4); + + file->write(&n.X, 4); + file->write(&n.Z, 4); + file->write(&n.Y, 4); + + file->write(&uv, 8); + + const u32 r = color.getRed(), g = color.getGreen(), b = color.getBlue(); + file->write(&r, 1); + file->write(&g, 1); + file->write(&b, 1); + } + else + { + // x y z nx ny nz u v red green blue [u1 v1 | tx ty tz]\n + snprintf_irr(outLine, 1024, + "%f %f %f %f %f %f %f %f %d %d %d\n",// %u %u %u %u %f %f\n", + pos.X, pos.Z, pos.Y, // Y and Z are flipped + n.X, n.Z, n.Y, + uv.X, uv.Y, + color.getRed(), color.getGreen(), color.getBlue()); + + file->write(outLine, strlen(outLine)); + } + } + } + + // index of the first vertex in the current mesh buffer + u32 StartOffset = 0; + + // write triangles + const unsigned char nbIndicesParFace = 3; + for (u32 i=0; i < mesh->getMeshBufferCount(); ++i) + { + scene::IMeshBuffer* mb = mesh->getMeshBuffer(i); + for (u32 j=0; j < mb->getIndexCount(); j+=3) + { + // y and z are flipped so triangles are reversed + u32 a=StartOffset; + u32 b=StartOffset; + u32 c=StartOffset; + + switch(mb->getIndexType()) + { + case video::EIT_16BIT: + a += mb->getIndices()[j+0]; + c += mb->getIndices()[j+1]; + b += mb->getIndices()[j+2]; + break; + case video::EIT_32BIT: + a += ((u32*)mb->getIndices()) [j+0]; + c += ((u32*)mb->getIndices()) [j+1]; + b += ((u32*)mb->getIndices()) [j+2]; + break; + } + + if (flags & scene::EMWF_WRITE_BINARY) + { + file->write(&nbIndicesParFace, 1); + file->write(&a, 4); + file->write(&b, 4); + file->write(&c, 4); + } + else + { + // count a b c\n + snprintf_irr(outLine, 1024, "3 %u %u %u\n", a, b, c); + file->write(outLine, strlen(outLine)); + } + } + + // increment offset + StartOffset += mb->getVertexCount(); + } + + // all done! + return true; +} + +} // end namespace +} // end namespace + +#endif // _IRR_COMPILE_WITH_PLY_WRITER_ + diff --git a/source/Irrlicht/CPLYMeshWriter.h b/source/Irrlicht/CPLYMeshWriter.h new file mode 100644 index 00000000..d87a1d05 --- /dev/null +++ b/source/Irrlicht/CPLYMeshWriter.h @@ -0,0 +1,35 @@ +// Copyright (C) 2009-2012 Gaz Davidson +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_PLY_MESH_WRITER_H_INCLUDED__ +#define __IRR_PLY_MESH_WRITER_H_INCLUDED__ + +#include "IMeshWriter.h" + +namespace irr +{ + +namespace scene +{ + class IMeshBuffer; + + //! class to write PLY mesh files + class CPLYMeshWriter : public IMeshWriter + { + public: + + CPLYMeshWriter(); + + //! Returns the type of the mesh writer + virtual EMESH_WRITER_TYPE getType() const _IRR_OVERRIDE_; + + //! writes a mesh + virtual bool writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags=EMWF_NONE) _IRR_OVERRIDE_; + + }; + +} // end namespace +} // end namespace + +#endif diff --git a/source/Irrlicht/CPakReader.cpp b/source/Irrlicht/CPakReader.cpp new file mode 100644 index 00000000..7b968425 --- /dev/null +++ b/source/Irrlicht/CPakReader.cpp @@ -0,0 +1,196 @@ +// Copyright (C) 2002-2012 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 + +#include "CPakReader.h" + +#ifdef __IRR_COMPILE_WITH_PAK_ARCHIVE_LOADER_ + +#include "os.h" +#include "coreutil.h" + +namespace irr +{ +namespace io +{ + +namespace +{ + +inline bool isHeaderValid(const SPAKFileHeader& header) +{ + const c8* tag = header.tag; + return tag[0] == 'P' && + tag[1] == 'A' && + tag[2] == 'C' && + tag[3] == 'K'; +} + +} // end namespace + +//! Constructor +CArchiveLoaderPAK::CArchiveLoaderPAK( io::IFileSystem* fs) +: FileSystem(fs) +{ +#ifdef _DEBUG + setDebugName("CArchiveLoaderPAK"); +#endif +} + + +//! returns true if the file maybe is able to be loaded by this class +bool CArchiveLoaderPAK::isALoadableFileFormat(const io::path& filename) const +{ + return core::hasFileExtension(filename, "pak"); +} + +//! Check to see if the loader can create archives of this type. +bool CArchiveLoaderPAK::isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const +{ + return fileType == EFAT_PAK; +} + +//! Creates an archive from the filename +/** \param file File handle to check. +\return Pointer to newly created archive, or 0 upon error. */ +IFileArchive* CArchiveLoaderPAK::createArchive(const io::path& filename, bool ignoreCase, bool ignorePaths) const +{ + IFileArchive *archive = 0; + io::IReadFile* file = FileSystem->createAndOpenFile(filename); + + if (file) + { + archive = createArchive(file, ignoreCase, ignorePaths); + file->drop (); + } + + return archive; +} + +//! creates/loads an archive from the file. +//! \return Pointer to the created archive. Returns 0 if loading failed. +IFileArchive* CArchiveLoaderPAK::createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const +{ + IFileArchive *archive = 0; + if ( file ) + { + file->seek ( 0 ); + archive = new CPakReader(file, ignoreCase, ignorePaths); + } + return archive; +} + + +//! Check if the file might be loaded by this class +/** Check might look into the file. +\param file File handle to check. +\return True if file seems to be loadable. */ +bool CArchiveLoaderPAK::isALoadableFileFormat(io::IReadFile* file) const +{ + SPAKFileHeader header; + + file->read(&header, sizeof(header)); + + return isHeaderValid(header); +} + + +/*! + PAK Reader +*/ +CPakReader::CPakReader(IReadFile* file, bool ignoreCase, bool ignorePaths) +: CFileList((file ? file->getFileName() : io::path("")), ignoreCase, ignorePaths), File(file) +{ +#ifdef _DEBUG + setDebugName("CPakReader"); +#endif + + if (File) + { + File->grab(); + scanLocalHeader(); + sort(); + } +} + + +CPakReader::~CPakReader() +{ + if (File) + File->drop(); +} + + +const IFileList* CPakReader::getFileList() const +{ + return this; +} + +bool CPakReader::scanLocalHeader() +{ + SPAKFileHeader header; + + // Read and validate the header + File->read(&header, sizeof(header)); + if (!isHeaderValid(header)) + return false; + + // Seek to the table of contents +#ifdef __BIG_ENDIAN__ + header.offset = os::Byteswap::byteswap(header.offset); + header.length = os::Byteswap::byteswap(header.length); +#endif + File->seek(header.offset); + + const int numberOfFiles = header.length / sizeof(SPAKFileEntry); + + // Loop through each entry in the table of contents + for(int i = 0; i < numberOfFiles; i++) + { + // read an entry + SPAKFileEntry entry; + File->read(&entry, sizeof(entry)); + +#ifdef _DEBUG + os::Printer::log(entry.name); +#endif + +#ifdef __BIG_ENDIAN__ + entry.offset = os::Byteswap::byteswap(entry.offset); + entry.length = os::Byteswap::byteswap(entry.length); +#endif + + addItem(io::path(entry.name), entry.offset, entry.length, false ); + } + return true; +} + + +//! opens a file by file name +IReadFile* CPakReader::createAndOpenFile(const io::path& filename) +{ + s32 index = findFile(filename, false); + + if (index != -1) + return createAndOpenFile(index); + + return 0; +} + + +//! opens a file by index +IReadFile* CPakReader::createAndOpenFile(u32 index) +{ + if (index >= Files.size() ) + return 0; + + const SFileListEntry &entry = Files[index]; + return createLimitReadFile( entry.FullName, File, entry.Offset, entry.Size ); +} + +} // end namespace io +} // end namespace irr + +#endif // __IRR_COMPILE_WITH_PAK_ARCHIVE_LOADER_ + diff --git a/source/Irrlicht/CPakReader.h b/source/Irrlicht/CPakReader.h new file mode 100644 index 00000000..2301b170 --- /dev/null +++ b/source/Irrlicht/CPakReader.h @@ -0,0 +1,122 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_PAK_READER_H_INCLUDED__ +#define __C_PAK_READER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef __IRR_COMPILE_WITH_PAK_ARCHIVE_LOADER_ + +#include "IReferenceCounted.h" +#include "IReadFile.h" +#include "irrArray.h" +#include "irrString.h" +#include "IFileSystem.h" +#include "CFileList.h" + +namespace irr +{ +namespace io +{ + //! File header containing location and size of the table of contents + struct SPAKFileHeader + { + // Don't change the order of these fields! They must match the order stored on disk. + c8 tag[4]; + u32 offset; + u32 length; + }; + + //! An entry in the PAK file's table of contents. + struct SPAKFileEntry + { + // Don't change the order of these fields! They must match the order stored on disk. + c8 name[56]; + u32 offset; + u32 length; + }; + + //! Archiveloader capable of loading PAK Archives + class CArchiveLoaderPAK : public IArchiveLoader + { + public: + + //! Constructor + CArchiveLoaderPAK(io::IFileSystem* fs); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".zip") + virtual bool isALoadableFileFormat(const io::path& filename) const _IRR_OVERRIDE_; + + //! Check if the file might be loaded by this class + /** Check might look into the file. + \param file File handle to check. + \return True if file seems to be loadable. */ + virtual bool isALoadableFileFormat(io::IReadFile* file) const _IRR_OVERRIDE_; + + //! Check to see if the loader can create archives of this type. + /** Check based on the archive type. + \param fileType The archive type to check. + \return True if the archile loader supports this type, false if not */ + virtual bool isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const _IRR_OVERRIDE_; + + //! Creates an archive from the filename + /** \param file File handle to check. + \return Pointer to newly created archive, or 0 upon error. */ + virtual IFileArchive* createArchive(const io::path& filename, bool ignoreCase, bool ignorePaths) const _IRR_OVERRIDE_; + + //! creates/loads an archive from the file. + //! \return Pointer to the created archive. Returns 0 if loading failed. + virtual io::IFileArchive* createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const _IRR_OVERRIDE_; + + private: + io::IFileSystem* FileSystem; + }; + + + //! reads from pak + class CPakReader : public virtual IFileArchive, virtual CFileList + { + public: + + CPakReader(IReadFile* file, bool ignoreCase, bool ignorePaths); + virtual ~CPakReader(); + + // file archive methods + + //! return the id of the file Archive + virtual const io::path& getArchiveName() const _IRR_OVERRIDE_ + { + return File->getFileName(); + } + + //! opens a file by file name + virtual IReadFile* createAndOpenFile(const io::path& filename) _IRR_OVERRIDE_; + + //! opens a file by index + virtual IReadFile* createAndOpenFile(u32 index) _IRR_OVERRIDE_; + + //! returns the list of files + virtual const IFileList* getFileList() const _IRR_OVERRIDE_; + + //! get the class Type + virtual E_FILE_ARCHIVE_TYPE getType() const _IRR_OVERRIDE_ { return EFAT_PAK; } + + private: + + //! scans for a local header, returns false if the header is invalid + bool scanLocalHeader(); + + IReadFile* File; + + }; + +} // end namespace io +} // end namespace irr + +#endif // __IRR_COMPILE_WITH_PAK_ARCHIVE_LOADER_ + +#endif // __C_PAK_READER_H_INCLUDED__ + diff --git a/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.cpp b/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.cpp new file mode 100644 index 00000000..c0549916 --- /dev/null +++ b/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.cpp @@ -0,0 +1,200 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CParticleAnimatedMeshSceneNodeEmitter.h" +#include "IAnimatedMeshSceneNode.h" +#include "IMesh.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CParticleAnimatedMeshSceneNodeEmitter::CParticleAnimatedMeshSceneNodeEmitter( + IAnimatedMeshSceneNode* node, bool useNormalDirection, + const core::vector3df& direction, f32 normalDirectionModifier, + s32 mbNumber, bool everyMeshVertex, + u32 minParticlesPerSecond, u32 maxParticlesPerSecond, + const video::SColor& minStartColor, const video::SColor& maxStartColor, + u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees, + const core::dimension2df& minStartSize, const core::dimension2df& maxStartSize ) + : Node(0), AnimatedMesh(0), BaseMesh(0), TotalVertices(0), MBCount(0), MBNumber(mbNumber), + Direction(direction), NormalDirectionModifier(normalDirectionModifier), + MinParticlesPerSecond(minParticlesPerSecond), MaxParticlesPerSecond(maxParticlesPerSecond), + MinStartColor(minStartColor), MaxStartColor(maxStartColor), + MinLifeTime(lifeTimeMin), MaxLifeTime(lifeTimeMax), + MaxStartSize(maxStartSize), MinStartSize(minStartSize), + Time(0), MaxAngleDegrees(maxAngleDegrees), + EveryMeshVertex(everyMeshVertex), UseNormalDirection(useNormalDirection) +{ + #ifdef _DEBUG + setDebugName("CParticleAnimatedMeshSceneNodeEmitter"); + #endif + setAnimatedMeshSceneNode(node); +} + + +//! Prepares an array with new particles to emitt into the system +//! and returns how much new particles there are. +s32 CParticleAnimatedMeshSceneNodeEmitter::emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray) +{ + Time += timeSinceLastCall; + + const u32 pps = (MaxParticlesPerSecond - MinParticlesPerSecond); + const f32 perSecond = pps ? ((f32)MinParticlesPerSecond + os::Randomizer::frand() * pps) : MinParticlesPerSecond; + const f32 everyWhatMillisecond = 1000.0f / perSecond; + + if(Time > everyWhatMillisecond) + { + Particles.set_used(0); + u32 amount = (u32)((Time / everyWhatMillisecond) + 0.5f); + Time = 0; + SParticle p; + + if(amount > MaxParticlesPerSecond * 2) + amount = MaxParticlesPerSecond * 2; + + // Get Mesh for this frame + IMesh* frameMesh = AnimatedMesh->getMesh( core::floor32(Node->getFrameNr()), + 255, Node->getStartFrame(), Node->getEndFrame() ); + for(u32 i=0; igetMeshBufferCount(); ++j ) + { + for( u32 k=0; kgetMeshBuffer(j)->getVertexCount(); ++k ) + { + p.pos = frameMesh->getMeshBuffer(j)->getPosition(k); + if( UseNormalDirection ) + p.vector = frameMesh->getMeshBuffer(j)->getNormal(k) / + NormalDirectionModifier; + else + p.vector = Direction; + + p.startTime = now; + + if( MaxAngleDegrees ) + { + core::vector3df tgt = p.vector; + tgt.rotateXYBy(os::Randomizer::frand() * MaxAngleDegrees); + tgt.rotateYZBy(os::Randomizer::frand() * MaxAngleDegrees); + tgt.rotateXZBy(os::Randomizer::frand() * MaxAngleDegrees); + p.vector = tgt; + } + + p.endTime = now + MinLifeTime; + if (MaxLifeTime != MinLifeTime) + p.endTime += os::Randomizer::rand() % (MaxLifeTime - MinLifeTime); + + if (MinStartColor==MaxStartColor) + p.color=MinStartColor; + else + p.color = MinStartColor.getInterpolated(MaxStartColor, os::Randomizer::frand()); + + p.startColor = p.color; + p.startVector = p.vector; + + if (MinStartSize==MaxStartSize) + p.startSize = MinStartSize; + else + p.startSize = MinStartSize.getInterpolated(MaxStartSize, os::Randomizer::frand()); + p.size = p.startSize; + + Particles.push_back(p); + } + } + } + else + { + s32 randomMB = 0; + if( MBNumber < 0 ) + randomMB = os::Randomizer::rand() % MBCount; + else + randomMB = MBNumber; + + u32 vertexNumber = frameMesh->getMeshBuffer(randomMB)->getVertexCount(); + if (!vertexNumber) + continue; + vertexNumber = os::Randomizer::rand() % vertexNumber; + + p.pos = frameMesh->getMeshBuffer(randomMB)->getPosition(vertexNumber); + if( UseNormalDirection ) + p.vector = frameMesh->getMeshBuffer(randomMB)->getNormal(vertexNumber) / + NormalDirectionModifier; + else + p.vector = Direction; + + p.startTime = now; + + if( MaxAngleDegrees ) + { + core::vector3df tgt = Direction; + tgt.rotateXYBy(os::Randomizer::frand() * MaxAngleDegrees); + tgt.rotateYZBy(os::Randomizer::frand() * MaxAngleDegrees); + tgt.rotateXZBy(os::Randomizer::frand() * MaxAngleDegrees); + p.vector = tgt; + } + + p.endTime = now + MinLifeTime; + if (MaxLifeTime != MinLifeTime) + p.endTime += os::Randomizer::rand() % (MaxLifeTime - MinLifeTime); + + if (MinStartColor==MaxStartColor) + p.color=MinStartColor; + else + p.color = MinStartColor.getInterpolated(MaxStartColor, os::Randomizer::frand()); + + p.startColor = p.color; + p.startVector = p.vector; + + if (MinStartSize==MaxStartSize) + p.startSize = MinStartSize; + else + p.startSize = MinStartSize.getInterpolated(MaxStartSize, os::Randomizer::frand()); + p.size = p.startSize; + + Particles.push_back(p); + } + } + + outArray = Particles.pointer(); + + return Particles.size(); + } + + return 0; +} + + +//! Set Mesh to emit particles from +void CParticleAnimatedMeshSceneNodeEmitter::setAnimatedMeshSceneNode( IAnimatedMeshSceneNode* node ) +{ + Node = node; + AnimatedMesh = 0; + BaseMesh = 0; + TotalVertices = 0; + VertexPerMeshBufferList.clear(); + if ( !node ) + { + return; + } + + AnimatedMesh = node->getMesh(); + BaseMesh = AnimatedMesh->getMesh(0); + + MBCount = BaseMesh->getMeshBufferCount(); + VertexPerMeshBufferList.reallocate(MBCount); + for( u32 i = 0; i < MBCount; ++i ) + { + VertexPerMeshBufferList.push_back( BaseMesh->getMeshBuffer(i)->getVertexCount() ); + TotalVertices += BaseMesh->getMeshBuffer(i)->getVertexCount(); + } +} + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.h b/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.h new file mode 100644 index 00000000..176abf97 --- /dev/null +++ b/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.h @@ -0,0 +1,160 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_PARTICLE_ANIMATED_MESH_SCENE_NODE_EMITTER_H_INCLUDED__ +#define __C_PARTICLE_ANIMATED_MESH_SCENE_NODE_EMITTER_H_INCLUDED__ + +#include "IParticleAnimatedMeshSceneNodeEmitter.h" +#include "irrArray.h" + +namespace irr +{ +namespace scene +{ + +//! An animated mesh emitter +class CParticleAnimatedMeshSceneNodeEmitter : public IParticleAnimatedMeshSceneNodeEmitter +{ +public: + + //! constructor + CParticleAnimatedMeshSceneNodeEmitter( + IAnimatedMeshSceneNode* node, + bool useNormalDirection = true, + const core::vector3df& direction = core::vector3df(0.0f,0.0f,-1.0f), + f32 normalDirectionModifier = 100.0f, + s32 mbNumber = -1, + bool everyMeshVertex = false, + u32 minParticlesPerSecond = 20, + u32 maxParticlesPerSecond = 40, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin = 2000, + u32 lifeTimeMax = 4000, + s32 maxAngleDegrees = 0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) + ); + + //! Prepares an array with new particles to emitt into the system + //! and returns how much new particles there are. + virtual s32 emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray) _IRR_OVERRIDE_; + + //! Set Mesh to emit particles from + virtual void setAnimatedMeshSceneNode( IAnimatedMeshSceneNode* node ) _IRR_OVERRIDE_; + + //! Set whether to use vertex normal for direction, or direction specified + virtual void setUseNormalDirection( bool useNormalDirection ) _IRR_OVERRIDE_ { UseNormalDirection = useNormalDirection; } + + //! Set direction the emitter emits particles + virtual void setDirection( const core::vector3df& newDirection ) _IRR_OVERRIDE_ { Direction = newDirection; } + + //! Set the amount that the normal is divided by for getting a particles direction + virtual void setNormalDirectionModifier( f32 normalDirectionModifier ) _IRR_OVERRIDE_ { NormalDirectionModifier = normalDirectionModifier; } + + //! Sets whether to emit min<->max particles for every vertex per second, or to pick + //! min<->max vertices every second + virtual void setEveryMeshVertex( bool everyMeshVertex ) _IRR_OVERRIDE_ { EveryMeshVertex = everyMeshVertex; } + + //! Set minimum number of particles the emitter emits per second + virtual void setMinParticlesPerSecond( u32 minPPS ) _IRR_OVERRIDE_ { MinParticlesPerSecond = minPPS; } + + //! Set maximum number of particles the emitter emits per second + virtual void setMaxParticlesPerSecond( u32 maxPPS ) _IRR_OVERRIDE_ { MaxParticlesPerSecond = maxPPS; } + + //! Set minimum starting color for particles + virtual void setMinStartColor( const video::SColor& color ) _IRR_OVERRIDE_ { MinStartColor = color; } + + //! Set maximum starting color for particles + virtual void setMaxStartColor( const video::SColor& color ) _IRR_OVERRIDE_ { MaxStartColor = color; } + + //! Set the maximum starting size for particles + virtual void setMaxStartSize( const core::dimension2df& size ) _IRR_OVERRIDE_ { MaxStartSize = size; } + + //! Set the minimum starting size for particles + virtual void setMinStartSize( const core::dimension2df& size ) _IRR_OVERRIDE_ { MinStartSize = size; } + + //! Set the minimum particle life-time in milliseconds + virtual void setMinLifeTime( u32 lifeTimeMin ) _IRR_OVERRIDE_ { MinLifeTime = lifeTimeMin; } + + //! Set the maximum particle life-time in milliseconds + virtual void setMaxLifeTime( u32 lifeTimeMax ) _IRR_OVERRIDE_ { MaxLifeTime = lifeTimeMax; } + + //! Maximal random derivation from the direction + virtual void setMaxAngleDegrees( s32 maxAngleDegrees ) _IRR_OVERRIDE_ { MaxAngleDegrees = maxAngleDegrees; } + + //! Get Mesh we're emitting particles from + virtual const IAnimatedMeshSceneNode* getAnimatedMeshSceneNode() const _IRR_OVERRIDE_ { return Node; } + + //! Get whether to use vertex normal for direciton, or direction specified + virtual bool isUsingNormalDirection() const _IRR_OVERRIDE_ { return UseNormalDirection; } + + //! Get direction the emitter emits particles + virtual const core::vector3df& getDirection() const _IRR_OVERRIDE_ { return Direction; } + + //! Get the amount that the normal is divided by for getting a particles direction + virtual f32 getNormalDirectionModifier() const _IRR_OVERRIDE_ { return NormalDirectionModifier; } + + //! Gets whether to emit min<->max particles for every vertex per second, or to pick + //! min<->max vertices every second + virtual bool getEveryMeshVertex() const _IRR_OVERRIDE_ { return EveryMeshVertex; } + + //! Get the minimum number of particles the emitter emits per second + virtual u32 getMinParticlesPerSecond() const _IRR_OVERRIDE_ { return MinParticlesPerSecond; } + + //! Get the maximum number of particles the emitter emits per second + virtual u32 getMaxParticlesPerSecond() const _IRR_OVERRIDE_ { return MaxParticlesPerSecond; } + + //! Get the minimum starting color for particles + virtual const video::SColor& getMinStartColor() const _IRR_OVERRIDE_ { return MinStartColor; } + + //! Get the maximum starting color for particles + virtual const video::SColor& getMaxStartColor() const _IRR_OVERRIDE_ { return MaxStartColor; } + + //! Get the maximum starting size for particles + virtual const core::dimension2df& getMaxStartSize() const _IRR_OVERRIDE_ { return MaxStartSize; } + + //! Get the minimum starting size for particles + virtual const core::dimension2df& getMinStartSize() const _IRR_OVERRIDE_ { return MinStartSize; } + + //! Get the minimum particle life-time in milliseconds + virtual u32 getMinLifeTime() const _IRR_OVERRIDE_ { return MinLifeTime; } + + //! Get the maximum particle life-time in milliseconds + virtual u32 getMaxLifeTime() const _IRR_OVERRIDE_ { return MaxLifeTime; } + + //! Maximal random derivation from the direction + virtual s32 getMaxAngleDegrees() const _IRR_OVERRIDE_ { return MaxAngleDegrees; } + +private: + + IAnimatedMeshSceneNode* Node; + IAnimatedMesh* AnimatedMesh; + const IMesh* BaseMesh; + s32 TotalVertices; + u32 MBCount; + s32 MBNumber; + core::array VertexPerMeshBufferList; + + core::array Particles; + core::vector3df Direction; + f32 NormalDirectionModifier; + u32 MinParticlesPerSecond, MaxParticlesPerSecond; + video::SColor MinStartColor, MaxStartColor; + u32 MinLifeTime, MaxLifeTime; + core::dimension2df MaxStartSize, MinStartSize; + + u32 Time; + s32 MaxAngleDegrees; + + bool EveryMeshVertex; + bool UseNormalDirection; +}; + +} // end namespace scene +} // end namespace irr + + +#endif // __C_PARTICLE_ANIMATED_MESH_SCENE_NODE_EMITTER_H_INCLUDED__ + diff --git a/source/Irrlicht/CParticleAttractionAffector.cpp b/source/Irrlicht/CParticleAttractionAffector.cpp new file mode 100644 index 00000000..8ae7367e --- /dev/null +++ b/source/Irrlicht/CParticleAttractionAffector.cpp @@ -0,0 +1,88 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CParticleAttractionAffector.h" + +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "IAttributes.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CParticleAttractionAffector::CParticleAttractionAffector( + const core::vector3df& point, f32 speed, bool attract, + bool affectX, bool affectY, bool affectZ ) + : Point(point), Speed(speed), AffectX(affectX), AffectY(affectY), + AffectZ(affectZ), Attract(attract), LastTime(0) +{ + #ifdef _DEBUG + setDebugName("CParticleAttractionAffector"); + #endif +} + + +//! Affects an array of particles. +void CParticleAttractionAffector::affect(u32 now, SParticle* particlearray, u32 count) +{ + if( LastTime == 0 ) + { + LastTime = now; + return; + } + + f32 timeDelta = ( now - LastTime ) / 1000.0f; + LastTime = now; + + if( !Enabled ) + return; + + for(u32 i=0; iaddVector3d("Point", Point); + out->addFloat("Speed", Speed); + out->addBool("AffectX", AffectX); + out->addBool("AffectY", AffectY); + out->addBool("AffectZ", AffectZ); + out->addBool("Attract", Attract); +} + +//! Reads attributes of the object. +void CParticleAttractionAffector::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + Point = in->getAttributeAsVector3d("Point"); + Speed = in->getAttributeAsFloat("Speed"); + AffectX = in->getAttributeAsBool("AffectX"); + AffectY = in->getAttributeAsBool("AffectY"); + AffectZ = in->getAttributeAsBool("AffectZ"); + Attract = in->getAttributeAsBool("Attract"); +} + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ diff --git a/source/Irrlicht/CParticleAttractionAffector.h b/source/Irrlicht/CParticleAttractionAffector.h new file mode 100644 index 00000000..6e126cd9 --- /dev/null +++ b/source/Irrlicht/CParticleAttractionAffector.h @@ -0,0 +1,90 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_PARTICLE_ATTRACTION_AFFECTOR_H_INCLUDED__ +#define __C_PARTICLE_ATTRACTION_AFFECTOR_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "IParticleAttractionAffector.h" + +namespace irr +{ +namespace scene +{ + +//! Particle Affector for attracting particles to a point +class CParticleAttractionAffector : public IParticleAttractionAffector +{ +public: + + CParticleAttractionAffector( + const core::vector3df& point = core::vector3df(), f32 speed = 1.0f, + bool attract = true, bool affectX = true, + bool affectY = true, bool affectZ = true ); + + //! Affects a particle. + virtual void affect(u32 now, SParticle* particlearray, u32 count) _IRR_OVERRIDE_; + + //! Set the point that particles will attract to + virtual void setPoint( const core::vector3df& point ) _IRR_OVERRIDE_ { Point = point; } + + //! Set the speed, in game units per second that the particles will attract to the specified point + virtual void setSpeed( f32 speed ) _IRR_OVERRIDE_ { Speed = speed; } + + //! Set whether or not the particles are attracting or detracting + virtual void setAttract( bool attract ) _IRR_OVERRIDE_ { Attract = attract; } + + //! Set whether or not this will affect particles in the X direction + virtual void setAffectX( bool affect ) _IRR_OVERRIDE_ { AffectX = affect; } + + //! Set whether or not this will affect particles in the Y direction + virtual void setAffectY( bool affect ) _IRR_OVERRIDE_ { AffectY = affect; } + + //! Set whether or not this will affect particles in the Z direction + virtual void setAffectZ( bool affect ) _IRR_OVERRIDE_ { AffectZ = affect; } + + //! Get the point that particles are attracted to + virtual const core::vector3df& getPoint() const _IRR_OVERRIDE_ { return Point; } + + //! Get the speed that points attract to the specified point + virtual f32 getSpeed() const _IRR_OVERRIDE_ { return Speed; } + + //! Get whether or not the particles are attracting or detracting + virtual bool getAttract() const _IRR_OVERRIDE_ { return Attract; } + + //! Get whether or not the particles X position are affected + virtual bool getAffectX() const _IRR_OVERRIDE_ { return AffectX; } + + //! Get whether or not the particles Y position are affected + virtual bool getAffectY() const _IRR_OVERRIDE_ { return AffectY; } + + //! Get whether or not the particles Z position are affected + virtual bool getAffectZ() const _IRR_OVERRIDE_ { return AffectZ; } + + //! Writes attributes of the object. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the object. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + +private: + + core::vector3df Point; + f32 Speed; + bool AffectX; + bool AffectY; + bool AffectZ; + bool Attract; + u32 LastTime; +}; + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ + +#endif // __C_PARTICLE_ATTRACTION_AFFECTOR_H_INCLUDED__ + diff --git a/source/Irrlicht/CParticleBoxEmitter.cpp b/source/Irrlicht/CParticleBoxEmitter.cpp new file mode 100644 index 00000000..1ff40ee7 --- /dev/null +++ b/source/Irrlicht/CParticleBoxEmitter.cpp @@ -0,0 +1,192 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CParticleBoxEmitter.h" + +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "os.h" +#include "IAttributes.h" +#include "irrMath.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CParticleBoxEmitter::CParticleBoxEmitter( + const core::aabbox3df& box, const core::vector3df& direction, + u32 minParticlesPerSecond, u32 maxParticlesPerSecond, + video::SColor minStartColor, video::SColor maxStartColor, + u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees, + const core::dimension2df& minStartSize, const core::dimension2df& maxStartSize) + : Box(box), Direction(direction), + MaxStartSize(maxStartSize), MinStartSize(minStartSize), + MinParticlesPerSecond(minParticlesPerSecond), + MaxParticlesPerSecond(maxParticlesPerSecond), + MinStartColor(minStartColor), MaxStartColor(maxStartColor), + MinLifeTime(lifeTimeMin), MaxLifeTime(lifeTimeMax), + Time(0), MaxAngleDegrees(maxAngleDegrees) +{ + #ifdef _DEBUG + setDebugName("CParticleBoxEmitter"); + #endif +} + + +//! Prepares an array with new particles to emitt into the system +//! and returns how much new particles there are. +s32 CParticleBoxEmitter::emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray) +{ + Time += timeSinceLastCall; + + const u32 pps = (MaxParticlesPerSecond - MinParticlesPerSecond); + const f32 perSecond = pps ? ((f32)MinParticlesPerSecond + os::Randomizer::frand() * pps) : MinParticlesPerSecond; + const f32 everyWhatMillisecond = 1000.0f / perSecond; + + if (Time > everyWhatMillisecond) + { + Particles.set_used(0); + u32 amount = (u32)((Time / everyWhatMillisecond) + 0.5f); + Time = 0; + SParticle p; + const core::vector3df& extent = Box.getExtent(); + + if (amount > MaxParticlesPerSecond*2) + amount = MaxParticlesPerSecond * 2; + + for (u32 i=0; iaddVector3d("Box", b); + out->addVector3d("Direction", Direction); + out->addFloat("MinStartSizeWidth", MinStartSize.Width); + out->addFloat("MinStartSizeHeight", MinStartSize.Height); + out->addFloat("MaxStartSizeWidth", MaxStartSize.Width); + out->addFloat("MaxStartSizeHeight", MaxStartSize.Height); + out->addInt("MinParticlesPerSecond", MinParticlesPerSecond); + out->addInt("MaxParticlesPerSecond", MaxParticlesPerSecond); + out->addColor("MinStartColor", MinStartColor); + out->addColor("MaxStartColor", MaxStartColor); + out->addInt("MinLifeTime", MinLifeTime); + out->addInt("MaxLifeTime", MaxLifeTime); + out->addInt("MaxAngleDegrees", MaxAngleDegrees); +} + + +//! Reads attributes of the object. +void CParticleBoxEmitter::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + // read data and correct input values here + + core::vector3df b = in->getAttributeAsVector3d("Box"); + + if (b.X <= 0) + b.X = 1.0f; + if (b.Y <= 0) + b.Y = 1.0f; + if (b.Z <= 0) + b.Z = 1.0f; + + Box.MinEdge.X = -b.X; + Box.MinEdge.Y = -b.Y; + Box.MinEdge.Z = -b.Z; + Box.MaxEdge.X = b.X; + Box.MaxEdge.Y = b.Y; + Box.MaxEdge.Z = b.Z; + + Direction = in->getAttributeAsVector3d("Direction"); + if (Direction.getLength() == 0) + Direction.set(0,0.01f,0); + + int idx = -1; + idx = in->findAttribute("MinStartSizeWidth"); + if ( idx >= 0 ) + MinStartSize.Width = in->getAttributeAsFloat(idx); + idx = in->findAttribute("MinStartSizeHeight"); + if ( idx >= 0 ) + MinStartSize.Height = in->getAttributeAsFloat(idx); + idx = in->findAttribute("MaxStartSizeWidth"); + if ( idx >= 0 ) + MaxStartSize.Width = in->getAttributeAsFloat(idx); + idx = in->findAttribute("MaxStartSizeHeight"); + if ( idx >= 0 ) + MaxStartSize.Height = in->getAttributeAsFloat(idx); + + MinParticlesPerSecond = in->getAttributeAsInt("MinParticlesPerSecond"); + MaxParticlesPerSecond = in->getAttributeAsInt("MaxParticlesPerSecond"); + + MinParticlesPerSecond = core::max_(1u, MinParticlesPerSecond); + MaxParticlesPerSecond = core::max_(MaxParticlesPerSecond, 1u); + MaxParticlesPerSecond = core::min_(MaxParticlesPerSecond, 200u); + MinParticlesPerSecond = core::min_(MinParticlesPerSecond, MaxParticlesPerSecond); + + MinStartColor = in->getAttributeAsColor("MinStartColor"); + MaxStartColor = in->getAttributeAsColor("MaxStartColor"); + MinLifeTime = in->getAttributeAsInt("MinLifeTime"); + MaxLifeTime = in->getAttributeAsInt("MaxLifeTime"); + MaxAngleDegrees = in->getAttributeAsInt("MaxAngleDegrees"); + + MinLifeTime = core::max_(0u, MinLifeTime); + MaxLifeTime = core::max_(MaxLifeTime, MinLifeTime); + MinLifeTime = core::min_(MinLifeTime, MaxLifeTime); + +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ diff --git a/source/Irrlicht/CParticleBoxEmitter.h b/source/Irrlicht/CParticleBoxEmitter.h new file mode 100644 index 00000000..21d8dd3e --- /dev/null +++ b/source/Irrlicht/CParticleBoxEmitter.h @@ -0,0 +1,136 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_PARTICLE_BOX_EMITTER_H_INCLUDED__ +#define __C_PARTICLE_BOX_EMITTER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "IParticleBoxEmitter.h" +#include "irrArray.h" +#include "aabbox3d.h" + +namespace irr +{ +namespace scene +{ + +//! A default box emitter +class CParticleBoxEmitter : public IParticleBoxEmitter +{ +public: + + //! constructor + CParticleBoxEmitter( + const core::aabbox3df& box, + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 20, + u32 maxParticlesPerSecond = 40, + video::SColor minStartColor = video::SColor(255,0,0,0), + video::SColor maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin=2000, + u32 lifeTimeMax=4000, + s32 maxAngleDegrees=0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) + ); + + //! Prepares an array with new particles to emitt into the system + //! and returns how much new particles there are. + virtual s32 emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray) _IRR_OVERRIDE_; + + //! Set direction the emitter emits particles. + virtual void setDirection( const core::vector3df& newDirection ) _IRR_OVERRIDE_ { Direction = newDirection; } + + //! Set minimum number of particles emitted per second. + virtual void setMinParticlesPerSecond( u32 minPPS ) _IRR_OVERRIDE_ { MinParticlesPerSecond = minPPS; } + + //! Set maximum number of particles emitted per second. + virtual void setMaxParticlesPerSecond( u32 maxPPS ) _IRR_OVERRIDE_ { MaxParticlesPerSecond = maxPPS; } + + //! Set minimum start color. + virtual void setMinStartColor( const video::SColor& color ) _IRR_OVERRIDE_ { MinStartColor = color; } + + //! Set maximum start color. + virtual void setMaxStartColor( const video::SColor& color ) _IRR_OVERRIDE_ { MaxStartColor = color; } + + //! Set the maximum starting size for particles + virtual void setMaxStartSize( const core::dimension2df& size ) _IRR_OVERRIDE_ { MaxStartSize = size; } + + //! Set the minimum starting size for particles + virtual void setMinStartSize( const core::dimension2df& size ) _IRR_OVERRIDE_ { MinStartSize = size; } + + //! Set the minimum particle life-time in milliseconds + virtual void setMinLifeTime( u32 lifeTimeMin ) _IRR_OVERRIDE_ { MinLifeTime = lifeTimeMin; } + + //! Set the maximum particle life-time in milliseconds + virtual void setMaxLifeTime( u32 lifeTimeMax ) _IRR_OVERRIDE_ { MaxLifeTime = lifeTimeMax; } + + //! Maximal random derivation from the direction + virtual void setMaxAngleDegrees( s32 maxAngleDegrees ) _IRR_OVERRIDE_ { MaxAngleDegrees = maxAngleDegrees; } + + //! Set box from which the particles are emitted. + virtual void setBox( const core::aabbox3df& box ) _IRR_OVERRIDE_ { Box = box; } + + //! Gets direction the emitter emits particles. + virtual const core::vector3df& getDirection() const _IRR_OVERRIDE_ { return Direction; } + + //! Gets minimum number of particles emitted per second. + virtual u32 getMinParticlesPerSecond() const _IRR_OVERRIDE_ { return MinParticlesPerSecond; } + + //! Gets maximum number of particles emitted per second. + virtual u32 getMaxParticlesPerSecond() const _IRR_OVERRIDE_ { return MaxParticlesPerSecond; } + + //! Gets minimum start color. + virtual const video::SColor& getMinStartColor() const _IRR_OVERRIDE_ { return MinStartColor; } + + //! Gets maximum start color. + virtual const video::SColor& getMaxStartColor() const _IRR_OVERRIDE_ { return MaxStartColor; } + + //! Gets the maximum starting size for particles + virtual const core::dimension2df& getMaxStartSize() const _IRR_OVERRIDE_ { return MaxStartSize; } + + //! Gets the minimum starting size for particles + virtual const core::dimension2df& getMinStartSize() const _IRR_OVERRIDE_ { return MinStartSize; } + + //! Get the minimum particle life-time in milliseconds + virtual u32 getMinLifeTime() const _IRR_OVERRIDE_ { return MinLifeTime; } + + //! Get the maximum particle life-time in milliseconds + virtual u32 getMaxLifeTime() const _IRR_OVERRIDE_ { return MaxLifeTime; } + + //! Maximal random derivation from the direction + virtual s32 getMaxAngleDegrees() const _IRR_OVERRIDE_ { return MaxAngleDegrees; } + + //! Get box from which the particles are emitted. + virtual const core::aabbox3df& getBox() const _IRR_OVERRIDE_ { return Box; } + + //! Writes attributes of the object. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the object. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + +private: + + core::array Particles; + core::aabbox3df Box; + core::vector3df Direction; + core::dimension2df MaxStartSize, MinStartSize; + u32 MinParticlesPerSecond, MaxParticlesPerSecond; + video::SColor MinStartColor, MaxStartColor; + u32 MinLifeTime, MaxLifeTime; + + u32 Time; + s32 MaxAngleDegrees; +}; + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ + +#endif + diff --git a/source/Irrlicht/CParticleCylinderEmitter.cpp b/source/Irrlicht/CParticleCylinderEmitter.cpp new file mode 100644 index 00000000..a0d0ef2e --- /dev/null +++ b/source/Irrlicht/CParticleCylinderEmitter.cpp @@ -0,0 +1,193 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CParticleCylinderEmitter.h" + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "os.h" +#include "IAttributes.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CParticleCylinderEmitter::CParticleCylinderEmitter( + const core::vector3df& center, f32 radius, + const core::vector3df& normal, f32 length, + bool outlineOnly, const core::vector3df& direction, + u32 minParticlesPerSecond, u32 maxParticlesPerSecond, + const video::SColor& minStartColor, const video::SColor& maxStartColor, + u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees, + const core::dimension2df& minStartSize, + const core::dimension2df& maxStartSize ) + : Center(center), Normal(normal), Direction(direction), + MaxStartSize(maxStartSize), MinStartSize(minStartSize), + MinParticlesPerSecond(minParticlesPerSecond), + MaxParticlesPerSecond(maxParticlesPerSecond), + MinStartColor(minStartColor), MaxStartColor(maxStartColor), + MinLifeTime(lifeTimeMin), MaxLifeTime(lifeTimeMax), + Radius(radius), Length(length), Time(0), + MaxAngleDegrees(maxAngleDegrees), OutlineOnly(outlineOnly) +{ + #ifdef _DEBUG + setDebugName("CParticleCylinderEmitter"); + #endif +} + + +//! Prepares an array with new particles to emitt into the system +//! and returns how much new particles there are. +s32 CParticleCylinderEmitter::emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray) +{ + Time += timeSinceLastCall; + + const u32 pps = (MaxParticlesPerSecond - MinParticlesPerSecond); + const f32 perSecond = pps ? ((f32)MinParticlesPerSecond + os::Randomizer::frand() * pps) : MinParticlesPerSecond; + const f32 everyWhatMillisecond = 1000.0f / perSecond; + + if(Time > everyWhatMillisecond) + { + Particles.set_used(0); + u32 amount = (u32)((Time / everyWhatMillisecond) + 0.5f); + Time = 0; + SParticle p; + + if(amount > MaxParticlesPerSecond*2) + amount = MaxParticlesPerSecond * 2; + + for(u32 i=0; iaddVector3d("Center", Center); + out->addVector3d("Normal", Normal); + out->addVector3d("Direction", Direction); + out->addFloat("MinStartSizeWidth", MinStartSize.Width); + out->addFloat("MinStartSizeHeight", MinStartSize.Height); + out->addFloat("MaxStartSizeWidth", MaxStartSize.Width); + out->addFloat("MaxStartSizeHeight", MaxStartSize.Height); + out->addInt("MinParticlesPerSecond", MinParticlesPerSecond); + out->addInt("MaxParticlesPerSecond", MaxParticlesPerSecond); + out->addColor("MinStartColor", MinStartColor); + out->addColor("MaxStartColor", MaxStartColor); + out->addInt("MinLifeTime", MinLifeTime); + out->addInt("MaxLifeTime", MaxLifeTime); + out->addFloat("Radius", Radius); + out->addFloat("Length", Length); + out->addInt("MaxAngleDegrees", MaxAngleDegrees); + out->addBool("OutlineOnly", OutlineOnly); +} + +//! Reads attributes of the object. +void CParticleCylinderEmitter::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + Center = in->getAttributeAsVector3d("Center"); + Normal = in->getAttributeAsVector3d("Normal"); + if (Normal.getLength() == 0) + Normal.set(0,1.f,0); + Direction = in->getAttributeAsVector3d("Direction"); + if (Direction.getLength() == 0) + Direction.set(0,0.01f,0); + + int idx = -1; + idx = in->findAttribute("MinStartSizeWidth"); + if ( idx >= 0 ) + MinStartSize.Width = in->getAttributeAsFloat(idx); + idx = in->findAttribute("MinStartSizeHeight"); + if ( idx >= 0 ) + MinStartSize.Height = in->getAttributeAsFloat(idx); + idx = in->findAttribute("MaxStartSizeWidth"); + if ( idx >= 0 ) + MaxStartSize.Width = in->getAttributeAsFloat(idx); + idx = in->findAttribute("MaxStartSizeHeight"); + if ( idx >= 0 ) + MaxStartSize.Height = in->getAttributeAsFloat(idx); + + MinParticlesPerSecond = in->getAttributeAsInt("MinParticlesPerSecond"); + MaxParticlesPerSecond = in->getAttributeAsInt("MaxParticlesPerSecond"); + + MinParticlesPerSecond = core::max_(1u, MinParticlesPerSecond); + MaxParticlesPerSecond = core::max_(MaxParticlesPerSecond, 1u); + MaxParticlesPerSecond = core::min_(MaxParticlesPerSecond, 200u); + MinParticlesPerSecond = core::min_(MinParticlesPerSecond, MaxParticlesPerSecond); + + MinStartColor = in->getAttributeAsColor("MinStartColor"); + MaxStartColor = in->getAttributeAsColor("MaxStartColor"); + MinLifeTime = in->getAttributeAsInt("MinLifeTime"); + MaxLifeTime = in->getAttributeAsInt("MaxLifeTime"); + MinLifeTime = core::max_(0u, MinLifeTime); + MaxLifeTime = core::max_(MaxLifeTime, MinLifeTime); + MinLifeTime = core::min_(MinLifeTime, MaxLifeTime); + + Radius = in->getAttributeAsFloat("Radius"); + Length = in->getAttributeAsFloat("Length"); + MaxAngleDegrees = in->getAttributeAsInt("MaxAngleDegrees"); + OutlineOnly = in->getAttributeAsBool("OutlineOnly"); +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ + diff --git a/source/Irrlicht/CParticleCylinderEmitter.h b/source/Irrlicht/CParticleCylinderEmitter.h new file mode 100644 index 00000000..c49c939a --- /dev/null +++ b/source/Irrlicht/CParticleCylinderEmitter.h @@ -0,0 +1,167 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_PARTICLE_CYLINDER_EMITTER_H_INCLUDED__ +#define __C_PARTICLE_CYLINDER_EMITTER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "IParticleCylinderEmitter.h" +#include "irrArray.h" + +namespace irr +{ +namespace scene +{ + +//! A default box emitter +class CParticleCylinderEmitter : public IParticleCylinderEmitter +{ +public: + + //! constructor + CParticleCylinderEmitter( + const core::vector3df& center, f32 radius, + const core::vector3df& normal, f32 length, + bool outlineOnly = false, const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 20, + u32 maxParticlesPerSecond = 40, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin=2000, + u32 lifeTimeMax=4000, + s32 maxAngleDegrees=0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) + ); + + //! Prepares an array with new particles to emitt into the system + //! and returns how much new particles there are. + virtual s32 emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray) _IRR_OVERRIDE_; + + //! Set the center of the radius for the cylinder, at one end of the cylinder + virtual void setCenter( const core::vector3df& center ) _IRR_OVERRIDE_ { Center = center; } + + //! Set the normal of the cylinder + virtual void setNormal( const core::vector3df& normal ) _IRR_OVERRIDE_ { Normal = normal; } + + //! Set the radius of the cylinder + virtual void setRadius( f32 radius ) _IRR_OVERRIDE_ { Radius = radius; } + + //! Set the length of the cylinder + virtual void setLength( f32 length ) _IRR_OVERRIDE_ { Length = length; } + + //! Set whether or not to draw points inside the cylinder + virtual void setOutlineOnly( bool outlineOnly ) _IRR_OVERRIDE_ { OutlineOnly = outlineOnly; } + + //! Set direction the emitter emits particles + virtual void setDirection( const core::vector3df& newDirection ) _IRR_OVERRIDE_ { Direction = newDirection; } + + //! Set direction the emitter emits particles + virtual void setMinParticlesPerSecond( u32 minPPS ) _IRR_OVERRIDE_ { MinParticlesPerSecond = minPPS; } + + //! Set direction the emitter emits particles + virtual void setMaxParticlesPerSecond( u32 maxPPS ) _IRR_OVERRIDE_ { MaxParticlesPerSecond = maxPPS; } + + //! Set direction the emitter emits particles + virtual void setMinStartColor( const video::SColor& color ) _IRR_OVERRIDE_ { MinStartColor = color; } + + //! Set direction the emitter emits particles + virtual void setMaxStartColor( const video::SColor& color ) _IRR_OVERRIDE_ { MaxStartColor = color; } + + //! Set the maximum starting size for particles + virtual void setMaxStartSize( const core::dimension2df& size ) _IRR_OVERRIDE_ { MaxStartSize = size; } + + //! Set the minimum starting size for particles + virtual void setMinStartSize( const core::dimension2df& size ) _IRR_OVERRIDE_ { MinStartSize = size; } + + //! Set the minimum particle life-time in milliseconds + virtual void setMinLifeTime( u32 lifeTimeMin ) _IRR_OVERRIDE_ { MinLifeTime = lifeTimeMin; } + + //! Set the maximum particle life-time in milliseconds + virtual void setMaxLifeTime( u32 lifeTimeMax ) _IRR_OVERRIDE_ { MaxLifeTime = lifeTimeMax; } + + //! Maximal random derivation from the direction + virtual void setMaxAngleDegrees( s32 maxAngleDegrees ) _IRR_OVERRIDE_ { MaxAngleDegrees = maxAngleDegrees; } + + //! Get the center of the cylinder + virtual const core::vector3df& getCenter() const _IRR_OVERRIDE_ { return Center; } + + //! Get the normal of the cylinder + virtual const core::vector3df& getNormal() const _IRR_OVERRIDE_ { return Normal; } + + //! Get the radius of the cylinder + virtual f32 getRadius() const _IRR_OVERRIDE_ { return Radius; } + + //! Get the center of the cylinder + virtual f32 getLength() const _IRR_OVERRIDE_ { return Length; } + + //! Get whether or not to draw points inside the cylinder + virtual bool getOutlineOnly() const _IRR_OVERRIDE_ { return OutlineOnly; } + + //! Gets direction the emitter emits particles + virtual const core::vector3df& getDirection() const _IRR_OVERRIDE_ { return Direction; } + + //! Gets direction the emitter emits particles + virtual u32 getMinParticlesPerSecond() const _IRR_OVERRIDE_ { return MinParticlesPerSecond; } + + //! Gets direction the emitter emits particles + virtual u32 getMaxParticlesPerSecond() const _IRR_OVERRIDE_ { return MaxParticlesPerSecond; } + + //! Gets direction the emitter emits particles + virtual const video::SColor& getMinStartColor() const _IRR_OVERRIDE_ { return MinStartColor; } + + //! Gets direction the emitter emits particles + virtual const video::SColor& getMaxStartColor() const _IRR_OVERRIDE_ { return MaxStartColor; } + + //! Gets the maximum starting size for particles + virtual const core::dimension2df& getMaxStartSize() const _IRR_OVERRIDE_ { return MaxStartSize; } + + //! Gets the minimum starting size for particles + virtual const core::dimension2df& getMinStartSize() const _IRR_OVERRIDE_ { return MinStartSize; } + + //! Get the minimum particle life-time in milliseconds + virtual u32 getMinLifeTime() const _IRR_OVERRIDE_ { return MinLifeTime; } + + //! Get the maximum particle life-time in milliseconds + virtual u32 getMaxLifeTime() const _IRR_OVERRIDE_ { return MaxLifeTime; } + + //! Maximal random derivation from the direction + virtual s32 getMaxAngleDegrees() const _IRR_OVERRIDE_ { return MaxAngleDegrees; } + + //! Writes attributes of the object. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the object. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + +private: + + core::array Particles; + + core::vector3df Center; + core::vector3df Normal; + core::vector3df Direction; + core::dimension2df MaxStartSize, MinStartSize; + u32 MinParticlesPerSecond, MaxParticlesPerSecond; + video::SColor MinStartColor, MaxStartColor; + u32 MinLifeTime, MaxLifeTime; + + f32 Radius; + f32 Length; + + u32 Time; + s32 MaxAngleDegrees; + + bool OutlineOnly; +}; + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ + +#endif + diff --git a/source/Irrlicht/CParticleFadeOutAffector.cpp b/source/Irrlicht/CParticleFadeOutAffector.cpp new file mode 100644 index 00000000..4c6957e8 --- /dev/null +++ b/source/Irrlicht/CParticleFadeOutAffector.cpp @@ -0,0 +1,74 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CParticleFadeOutAffector.h" + +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "IAttributes.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CParticleFadeOutAffector::CParticleFadeOutAffector( + const video::SColor& targetColor, u32 fadeOutTime) + : IParticleFadeOutAffector(), TargetColor(targetColor) +{ + + #ifdef _DEBUG + setDebugName("CParticleFadeOutAffector"); + #endif + + FadeOutTime = fadeOutTime ? static_cast(fadeOutTime) : 1.0f; +} + + +//! Affects an array of particles. +void CParticleFadeOutAffector::affect(u32 now, SParticle* particlearray, u32 count) +{ + if (!Enabled) + return; + f32 d; + + for (u32 i=0; iaddColor("TargetColor", TargetColor); + out->addFloat("FadeOutTime", FadeOutTime); +} + +//! Reads attributes of the object. +//! Implement this to set the attributes of your scene node animator for +//! scripting languages, editors, debuggers or xml deserialization purposes. +//! \param startIndex: start index where to start reading attributes. +//! \return: returns last index of an attribute read by this affector +void CParticleFadeOutAffector::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + TargetColor = in->getAttributeAsColor("TargetColor"); + FadeOutTime = in->getAttributeAsFloat("FadeOutTime"); +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ diff --git a/source/Irrlicht/CParticleFadeOutAffector.h b/source/Irrlicht/CParticleFadeOutAffector.h new file mode 100644 index 00000000..f0bbf057 --- /dev/null +++ b/source/Irrlicht/CParticleFadeOutAffector.h @@ -0,0 +1,68 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_PARTICLE_FADE_OUT_AFFECTOR_H_INCLUDED__ +#define __C_PARTICLE_FADE_OUT_AFFECTOR_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "IParticleFadeOutAffector.h" +#include "SColor.h" + +namespace irr +{ +namespace scene +{ + +//! Particle Affector for fading out a color +class CParticleFadeOutAffector : public IParticleFadeOutAffector +{ +public: + + CParticleFadeOutAffector(const video::SColor& targetColor, u32 fadeOutTime); + + //! Affects a particle. + virtual void affect(u32 now, SParticle* particlearray, u32 count) _IRR_OVERRIDE_; + + //! Sets the targetColor, i.e. the color the particles will interpolate + //! to over time. + virtual void setTargetColor( const video::SColor& targetColor ) _IRR_OVERRIDE_ { TargetColor = targetColor; } + + //! Sets the amount of time it takes for each particle to fade out. + virtual void setFadeOutTime( u32 fadeOutTime ) _IRR_OVERRIDE_ { FadeOutTime = fadeOutTime ? static_cast(fadeOutTime) : 1.0f; } + + //! Sets the targetColor, i.e. the color the particles will interpolate + //! to over time. + virtual const video::SColor& getTargetColor() const _IRR_OVERRIDE_ { return TargetColor; } + + //! Sets the amount of time it takes for each particle to fade out. + virtual u32 getFadeOutTime() const _IRR_OVERRIDE_ { return static_cast(FadeOutTime); } + + //! Writes attributes of the object. + //! 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) const _IRR_OVERRIDE_; + + //! Reads attributes of the object. + //! Implement this to set the attributes of your scene node animator for + //! scripting languages, editors, debuggers or xml deserialization purposes. + //! \param startIndex: start index where to start reading attributes. + //! \return: returns last index of an attribute read by this affector + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + +private: + + video::SColor TargetColor; + f32 FadeOutTime; +}; + +} // end namespace scene +} // end namespace irr + + +#endif // _IRR_COMPILE_WITH_PARTICLES_ + +#endif + diff --git a/source/Irrlicht/CParticleGravityAffector.cpp b/source/Irrlicht/CParticleGravityAffector.cpp new file mode 100644 index 00000000..1938a542 --- /dev/null +++ b/source/Irrlicht/CParticleGravityAffector.cpp @@ -0,0 +1,68 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CParticleGravityAffector.h" + +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "os.h" +#include "IAttributes.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CParticleGravityAffector::CParticleGravityAffector( + const core::vector3df& gravity, u32 timeForceLost) + : IParticleGravityAffector(), TimeForceLost(static_cast(timeForceLost)), Gravity(gravity) +{ + #ifdef _DEBUG + setDebugName("CParticleGravityAffector"); + #endif +} + + +//! Affects an array of particles. +void CParticleGravityAffector::affect(u32 now, SParticle* particlearray, u32 count) +{ + if (!Enabled) + return; + f32 d; + + for (u32 i=0; i 1.0f) + d = 1.0f; + if (d < 0.0f) + d = 0.0f; + d = 1.0f - d; + + particlearray[i].vector = particlearray[i].startVector.getInterpolated(Gravity, d); + } +} + +//! Writes attributes of the object. +void CParticleGravityAffector::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + out->addVector3d("Gravity", Gravity); + out->addFloat("TimeForceLost", TimeForceLost); +} + + +//! Reads attributes of the object. +void CParticleGravityAffector::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + Gravity = in->getAttributeAsVector3d("Gravity"); + TimeForceLost = in->getAttributeAsFloat("TimeForceLost"); +} + + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ diff --git a/source/Irrlicht/CParticleGravityAffector.h b/source/Irrlicht/CParticleGravityAffector.h new file mode 100644 index 00000000..1c926fc2 --- /dev/null +++ b/source/Irrlicht/CParticleGravityAffector.h @@ -0,0 +1,68 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_PARTICLE_GRAVITY_AFFECTOR_H_INCLUDED__ +#define __C_PARTICLE_GRAVITY_AFFECTOR_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "IParticleGravityAffector.h" +#include "SColor.h" + +namespace irr +{ +namespace scene +{ + +//! Particle Affector for affecting direction of particle +class CParticleGravityAffector : public IParticleGravityAffector +{ +public: + + CParticleGravityAffector( + const core::vector3df& gravity = core::vector3df(0.0f,-0.03f,0.0f), + u32 timeForceLost = 1000); + + //! Affects a particle. + virtual void affect(u32 now, SParticle* particlearray, u32 count) _IRR_OVERRIDE_; + + //! Set the time in milliseconds when the gravity force is totally + //! lost and the particle does not move any more. + virtual void setTimeForceLost( f32 timeForceLost ) _IRR_OVERRIDE_ { TimeForceLost = timeForceLost; } + + //! Set the direction and force of gravity. + virtual void setGravity( const core::vector3df& gravity ) _IRR_OVERRIDE_ { Gravity = gravity; } + + //! Set the time in milliseconds when the gravity force is totally + //! lost and the particle does not move any more. + virtual f32 getTimeForceLost() const _IRR_OVERRIDE_ { return TimeForceLost; } + + //! Set the direction and force of gravity. + virtual const core::vector3df& getGravity() const _IRR_OVERRIDE_ { return Gravity; } + + //! Writes attributes of the object. + //! 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) const _IRR_OVERRIDE_; + + //! Reads attributes of the object. + //! Implement this to set the attributes of your scene node animator for + //! scripting languages, editors, debuggers or xml deserialization purposes. + //! \param startIndex: start index where to start reading attributes. + //! \return: returns last index of an attribute read by this affector + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + +private: + f32 TimeForceLost; + core::vector3df Gravity; +}; + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ + +#endif + diff --git a/source/Irrlicht/CParticleMeshEmitter.cpp b/source/Irrlicht/CParticleMeshEmitter.cpp new file mode 100644 index 00000000..ef667c52 --- /dev/null +++ b/source/Irrlicht/CParticleMeshEmitter.cpp @@ -0,0 +1,194 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CParticleMeshEmitter.h" + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "os.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CParticleMeshEmitter::CParticleMeshEmitter( + IMesh* mesh, bool useNormalDirection, + const core::vector3df& direction, f32 normalDirectionModifier, + s32 mbNumber, bool everyMeshVertex, + u32 minParticlesPerSecond, u32 maxParticlesPerSecond, + const video::SColor& minStartColor, const video::SColor& maxStartColor, + u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees, + const core::dimension2df& minStartSize, + const core::dimension2df& maxStartSize ) + : Mesh(0), TotalVertices(0), MBCount(0), MBNumber(mbNumber), + NormalDirectionModifier(normalDirectionModifier), Direction(direction), + MaxStartSize(maxStartSize), MinStartSize(minStartSize), + MinParticlesPerSecond(minParticlesPerSecond), MaxParticlesPerSecond(maxParticlesPerSecond), + MinStartColor(minStartColor), MaxStartColor(maxStartColor), + MinLifeTime(lifeTimeMin), MaxLifeTime(lifeTimeMax), + Time(0), MaxAngleDegrees(maxAngleDegrees), + EveryMeshVertex(everyMeshVertex), UseNormalDirection(useNormalDirection) +{ + #ifdef _DEBUG + setDebugName("CParticleMeshEmitter"); + #endif + setMesh(mesh); +} + + +//! Prepares an array with new particles to emitt into the system +//! and returns how much new particles there are. +s32 CParticleMeshEmitter::emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray) +{ + Time += timeSinceLastCall; + + const u32 pps = (MaxParticlesPerSecond - MinParticlesPerSecond); + const f32 perSecond = pps ? ((f32)MinParticlesPerSecond + os::Randomizer::frand() * pps) : MinParticlesPerSecond; + const f32 everyWhatMillisecond = 1000.0f / perSecond; + + if(Time > everyWhatMillisecond) + { + Particles.set_used(0); + u32 amount = (u32)((Time / everyWhatMillisecond) + 0.5f); + Time = 0; + SParticle p; + + if(amount > MaxParticlesPerSecond * 2) + amount = MaxParticlesPerSecond * 2; + + for(u32 i=0; igetMeshBufferCount(); ++j ) + { + for( u32 k=0; kgetMeshBuffer(j)->getVertexCount(); ++k ) + { + p.pos = Mesh->getMeshBuffer(j)->getPosition(k); + if( UseNormalDirection ) + p.vector = Mesh->getMeshBuffer(j)->getNormal(k) / + NormalDirectionModifier; + else + p.vector = Direction; + + p.startTime = now; + + if( MaxAngleDegrees ) + { + core::vector3df tgt = p.vector; + tgt.rotateXYBy(os::Randomizer::frand() * MaxAngleDegrees); + tgt.rotateYZBy(os::Randomizer::frand() * MaxAngleDegrees); + tgt.rotateXZBy(os::Randomizer::frand() * MaxAngleDegrees); + p.vector = tgt; + } + + p.endTime = now + MinLifeTime; + if (MaxLifeTime != MinLifeTime) + p.endTime += os::Randomizer::rand() % (MaxLifeTime - MinLifeTime); + + if (MinStartColor==MaxStartColor) + p.color=MinStartColor; + else + p.color = MinStartColor.getInterpolated(MaxStartColor, os::Randomizer::frand()); + + p.startColor = p.color; + p.startVector = p.vector; + + if (MinStartSize==MaxStartSize) + p.startSize = MinStartSize; + else + p.startSize = MinStartSize.getInterpolated(MaxStartSize, os::Randomizer::frand()); + p.size = p.startSize; + + Particles.push_back(p); + } + } + } + else + { + const s32 randomMB = (MBNumber < 0) ? (os::Randomizer::rand() % MBCount) : MBNumber; + + u32 vertexNumber = Mesh->getMeshBuffer(randomMB)->getVertexCount(); + if (!vertexNumber) + continue; + vertexNumber = os::Randomizer::rand() % vertexNumber; + + p.pos = Mesh->getMeshBuffer(randomMB)->getPosition(vertexNumber); + if( UseNormalDirection ) + p.vector = Mesh->getMeshBuffer(randomMB)->getNormal(vertexNumber) / + NormalDirectionModifier; + else + p.vector = Direction; + + p.startTime = now; + + if( MaxAngleDegrees ) + { + core::vector3df tgt = Direction; + tgt.rotateXYBy(os::Randomizer::frand() * MaxAngleDegrees); + tgt.rotateYZBy(os::Randomizer::frand() * MaxAngleDegrees); + tgt.rotateXZBy(os::Randomizer::frand() * MaxAngleDegrees); + p.vector = tgt; + } + + p.endTime = now + MinLifeTime; + if (MaxLifeTime != MinLifeTime) + p.endTime += os::Randomizer::rand() % (MaxLifeTime - MinLifeTime); + + if (MinStartColor==MaxStartColor) + p.color=MinStartColor; + else + p.color = MinStartColor.getInterpolated(MaxStartColor, os::Randomizer::frand()); + + p.startColor = p.color; + p.startVector = p.vector; + + if (MinStartSize==MaxStartSize) + p.startSize = MinStartSize; + else + p.startSize = MinStartSize.getInterpolated(MaxStartSize, os::Randomizer::frand()); + p.size = p.startSize; + + Particles.push_back(p); + } + } + + outArray = Particles.pointer(); + + return Particles.size(); + } + + return 0; +} + + +//! Set Mesh to emit particles from +void CParticleMeshEmitter::setMesh(IMesh* mesh) +{ + Mesh = mesh; + + TotalVertices = 0; + MBCount = 0; + VertexPerMeshBufferList.clear(); + + if ( !Mesh ) + return; + + MBCount = Mesh->getMeshBufferCount(); + VertexPerMeshBufferList.reallocate(MBCount); + for( u32 i = 0; i < MBCount; ++i ) + { + VertexPerMeshBufferList.push_back( Mesh->getMeshBuffer(i)->getVertexCount() ); + TotalVertices += Mesh->getMeshBuffer(i)->getVertexCount(); + } +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ diff --git a/source/Irrlicht/CParticleMeshEmitter.h b/source/Irrlicht/CParticleMeshEmitter.h new file mode 100644 index 00000000..08a076c1 --- /dev/null +++ b/source/Irrlicht/CParticleMeshEmitter.h @@ -0,0 +1,163 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_PARTICLE_MESH_EMITTER_H_INCLUDED__ +#define __C_PARTICLE_MESH_EMITTER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "IParticleMeshEmitter.h" +#include "irrArray.h" +#include "aabbox3d.h" +#include "IMeshBuffer.h" + +namespace irr +{ +namespace scene +{ + +//! A default box emitter +class CParticleMeshEmitter : public IParticleMeshEmitter +{ +public: + + //! constructor + CParticleMeshEmitter( + IMesh* mesh, bool useNormalDirection = true, + const core::vector3df& direction = core::vector3df(0.0f,0.0f,0.0f), + f32 normalDirectionModifier = 100.0f, + s32 mbNumber = -1, + bool everyMeshVertex = false, + u32 minParticlesPerSecond = 20, + u32 maxParticlesPerSecond = 40, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin = 2000, + u32 lifeTimeMax = 4000, + s32 maxAngleDegrees = 0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) + ); + + //! Prepares an array with new particles to emitt into the system + //! and returns how much new particles there are. + virtual s32 emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray) _IRR_OVERRIDE_; + + //! Set Mesh to emit particles from + virtual void setMesh( IMesh* mesh ) _IRR_OVERRIDE_; + + //! Set whether to use vertex normal for direction, or direction specified + virtual void setUseNormalDirection( bool useNormalDirection ) _IRR_OVERRIDE_ { UseNormalDirection = useNormalDirection; } + + //! Set direction the emitter emits particles + virtual void setDirection( const core::vector3df& newDirection ) _IRR_OVERRIDE_ { Direction = newDirection; } + + //! Set the amount that the normal is divided by for getting a particles direction + virtual void setNormalDirectionModifier( f32 normalDirectionModifier ) _IRR_OVERRIDE_ { NormalDirectionModifier = normalDirectionModifier; } + + //! Sets whether to emit min<->max particles for every vertex per second, or to pick + //! min<->max vertices every second + virtual void setEveryMeshVertex( bool everyMeshVertex ) _IRR_OVERRIDE_ { EveryMeshVertex = everyMeshVertex; } + + //! Set minimum number of particles the emitter emits per second + virtual void setMinParticlesPerSecond( u32 minPPS ) _IRR_OVERRIDE_ { MinParticlesPerSecond = minPPS; } + + //! Set maximum number of particles the emitter emits per second + virtual void setMaxParticlesPerSecond( u32 maxPPS ) _IRR_OVERRIDE_ { MaxParticlesPerSecond = maxPPS; } + + //! Set minimum starting color for particles + virtual void setMinStartColor( const video::SColor& color ) _IRR_OVERRIDE_ { MinStartColor = color; } + + //! Set maximum starting color for particles + virtual void setMaxStartColor( const video::SColor& color ) _IRR_OVERRIDE_ { MaxStartColor = color; } + + //! Set the maximum starting size for particles + virtual void setMaxStartSize( const core::dimension2df& size ) _IRR_OVERRIDE_ { MaxStartSize = size; } + + //! Set the minimum starting size for particles + virtual void setMinStartSize( const core::dimension2df& size ) _IRR_OVERRIDE_ { MinStartSize = size; } + + //! Set the minimum particle life-time in milliseconds + virtual void setMinLifeTime( u32 lifeTimeMin ) _IRR_OVERRIDE_ { MinLifeTime = lifeTimeMin; } + + //! Set the maximum particle life-time in milliseconds + virtual void setMaxLifeTime( u32 lifeTimeMax ) _IRR_OVERRIDE_ { MaxLifeTime = lifeTimeMax; } + + //! Set maximal random derivation from the direction + virtual void setMaxAngleDegrees( s32 maxAngleDegrees ) _IRR_OVERRIDE_ { MaxAngleDegrees = maxAngleDegrees; } + + //! Get Mesh we're emitting particles from + virtual const IMesh* getMesh() const _IRR_OVERRIDE_ { return Mesh; } + + //! Get whether to use vertex normal for direciton, or direction specified + virtual bool isUsingNormalDirection() const _IRR_OVERRIDE_ { return UseNormalDirection; } + + //! Get direction the emitter emits particles + virtual const core::vector3df& getDirection() const _IRR_OVERRIDE_ { return Direction; } + + //! Get the amount that the normal is divided by for getting a particles direction + virtual f32 getNormalDirectionModifier() const _IRR_OVERRIDE_ { return NormalDirectionModifier; } + + //! Gets whether to emit min<->max particles for every vertex per second, or to pick + //! min<->max vertices every second + virtual bool getEveryMeshVertex() const _IRR_OVERRIDE_ { return EveryMeshVertex; } + + //! Get the minimum number of particles the emitter emits per second + virtual u32 getMinParticlesPerSecond() const _IRR_OVERRIDE_ { return MinParticlesPerSecond; } + + //! Get the maximum number of particles the emitter emits per second + virtual u32 getMaxParticlesPerSecond() const _IRR_OVERRIDE_ { return MaxParticlesPerSecond; } + + //! Get the minimum starting color for particles + virtual const video::SColor& getMinStartColor() const _IRR_OVERRIDE_ { return MinStartColor; } + + //! Get the maximum starting color for particles + virtual const video::SColor& getMaxStartColor() const _IRR_OVERRIDE_ { return MaxStartColor; } + + //! Gets the maximum starting size for particles + virtual const core::dimension2df& getMaxStartSize() const _IRR_OVERRIDE_ { return MaxStartSize; } + + //! Gets the minimum starting size for particles + virtual const core::dimension2df& getMinStartSize() const _IRR_OVERRIDE_ { return MinStartSize; } + + //! Get the minimum particle life-time in milliseconds + virtual u32 getMinLifeTime() const _IRR_OVERRIDE_ { return MinLifeTime; } + + //! Get the maximum particle life-time in milliseconds + virtual u32 getMaxLifeTime() const _IRR_OVERRIDE_ { return MaxLifeTime; } + + //! Get maximal random derivation from the direction + virtual s32 getMaxAngleDegrees() const _IRR_OVERRIDE_ { return MaxAngleDegrees; } + +private: + + const IMesh* Mesh; + core::array VertexPerMeshBufferList; + s32 TotalVertices; + u32 MBCount; + s32 MBNumber; + + f32 NormalDirectionModifier; + core::array Particles; + core::vector3df Direction; + core::dimension2df MaxStartSize, MinStartSize; + u32 MinParticlesPerSecond, MaxParticlesPerSecond; + video::SColor MinStartColor, MaxStartColor; + u32 MinLifeTime, MaxLifeTime; + + u32 Time; + s32 MaxAngleDegrees; + + bool EveryMeshVertex; + bool UseNormalDirection; +}; + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ + +#endif // __C_PARTICLE_MESH_EMITTER_H_INCLUDED__ + diff --git a/source/Irrlicht/CParticlePointEmitter.cpp b/source/Irrlicht/CParticlePointEmitter.cpp new file mode 100644 index 00000000..38c7e276 --- /dev/null +++ b/source/Irrlicht/CParticlePointEmitter.cpp @@ -0,0 +1,151 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CParticlePointEmitter.h" + +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "os.h" +#include "IAttributes.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CParticlePointEmitter::CParticlePointEmitter( + const core::vector3df& direction, u32 minParticlesPerSecond, + u32 maxParticlesPerSecond, video::SColor minStartColor, + video::SColor maxStartColor, u32 lifeTimeMin, u32 lifeTimeMax, + s32 maxAngleDegrees, + const core::dimension2df& minStartSize, + const core::dimension2df& maxStartSize) + : Direction(direction), + MinStartSize(minStartSize), MaxStartSize(maxStartSize), + MinParticlesPerSecond(minParticlesPerSecond), + MaxParticlesPerSecond(maxParticlesPerSecond), + MinStartColor(minStartColor), MaxStartColor(maxStartColor), + MinLifeTime(lifeTimeMin), MaxLifeTime(lifeTimeMax), + MaxAngleDegrees(maxAngleDegrees), Time(0) +{ + #ifdef _DEBUG + setDebugName("CParticlePointEmitter"); + #endif +} + + +//! Prepares an array with new particles to emitt into the system +//! and returns how much new particles there are. +s32 CParticlePointEmitter::emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray) +{ + Time += timeSinceLastCall; + + const u32 pps = (MaxParticlesPerSecond - MinParticlesPerSecond); + const f32 perSecond = pps ? ((f32)MinParticlesPerSecond + os::Randomizer::frand() * pps) : MinParticlesPerSecond; + const f32 everyWhatMillisecond = 1000.0f / perSecond; + + if (Time > everyWhatMillisecond) + { + Time = 0; + Particle.startTime = now; + Particle.vector = Direction; + + if (MaxAngleDegrees) + { + core::vector3df tgt = Direction; + tgt.rotateXYBy(os::Randomizer::frand() * MaxAngleDegrees); + tgt.rotateYZBy(os::Randomizer::frand() * MaxAngleDegrees); + tgt.rotateXZBy(os::Randomizer::frand() * MaxAngleDegrees); + Particle.vector = tgt; + } + + Particle.endTime = now + MinLifeTime; + if (MaxLifeTime != MinLifeTime) + Particle.endTime += os::Randomizer::rand() % (MaxLifeTime - MinLifeTime); + + if (MinStartColor==MaxStartColor) + Particle.color=MinStartColor; + else + Particle.color = MinStartColor.getInterpolated(MaxStartColor, os::Randomizer::frand()); + + Particle.startColor = Particle.color; + Particle.startVector = Particle.vector; + + if (MinStartSize==MaxStartSize) + Particle.startSize = MinStartSize; + else + Particle.startSize = MinStartSize.getInterpolated(MaxStartSize, os::Randomizer::frand()); + Particle.size = Particle.startSize; + + outArray = &Particle; + return 1; + } + + return 0; +} + + +//! Writes attributes of the object. +void CParticlePointEmitter::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + out->addVector3d("Direction", Direction); + out->addFloat("MinStartSizeWidth", MinStartSize.Width); + out->addFloat("MinStartSizeHeight", MinStartSize.Height); + out->addFloat("MaxStartSizeWidth", MaxStartSize.Width); + out->addFloat("MaxStartSizeHeight", MaxStartSize.Height); + out->addInt("MinParticlesPerSecond", MinParticlesPerSecond); + out->addInt("MaxParticlesPerSecond", MaxParticlesPerSecond); + out->addColor("MinStartColor", MinStartColor); + out->addColor("MaxStartColor", MaxStartColor); + out->addInt("MinLifeTime", MinLifeTime); + out->addInt("MaxLifeTime", MaxLifeTime); + out->addInt("MaxAngleDegrees", MaxAngleDegrees); +} + +//! Reads attributes of the object. +void CParticlePointEmitter::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + Direction = in->getAttributeAsVector3d("Direction"); + if (Direction.getLength() == 0) + Direction.set(0,0.01f,0); + + int idx = -1; + idx = in->findAttribute("MinStartSizeWidth"); + if ( idx >= 0 ) + MinStartSize.Width = in->getAttributeAsFloat(idx); + idx = in->findAttribute("MinStartSizeHeight"); + if ( idx >= 0 ) + MinStartSize.Height = in->getAttributeAsFloat(idx); + idx = in->findAttribute("MaxStartSizeWidth"); + if ( idx >= 0 ) + MaxStartSize.Width = in->getAttributeAsFloat(idx); + idx = in->findAttribute("MaxStartSizeHeight"); + if ( idx >= 0 ) + MaxStartSize.Height = in->getAttributeAsFloat(idx); + + MinParticlesPerSecond = in->getAttributeAsInt("MinParticlesPerSecond"); + MaxParticlesPerSecond = in->getAttributeAsInt("MaxParticlesPerSecond"); + + MinParticlesPerSecond = core::max_(1u, MinParticlesPerSecond); + MaxParticlesPerSecond = core::max_(MaxParticlesPerSecond, 1u); + MaxParticlesPerSecond = core::min_(MaxParticlesPerSecond, 200u); + MinParticlesPerSecond = core::min_(MinParticlesPerSecond, MaxParticlesPerSecond); + + MinStartColor = in->getAttributeAsColor("MinStartColor"); + MaxStartColor = in->getAttributeAsColor("MaxStartColor"); + MinLifeTime = in->getAttributeAsInt("MinLifeTime"); + MaxLifeTime = in->getAttributeAsInt("MaxLifeTime"); + MaxAngleDegrees = in->getAttributeAsInt("MaxAngleDegrees"); + + MinLifeTime = core::max_(0u, MinLifeTime); + MaxLifeTime = core::max_(MaxLifeTime, MinLifeTime); + MinLifeTime = core::min_(MinLifeTime, MaxLifeTime); +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ diff --git a/source/Irrlicht/CParticlePointEmitter.h b/source/Irrlicht/CParticlePointEmitter.h new file mode 100644 index 00000000..985bb490 --- /dev/null +++ b/source/Irrlicht/CParticlePointEmitter.h @@ -0,0 +1,125 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_PARTICLE_POINT_EMITTER_H_INCLUDED__ +#define __C_PARTICLE_POINT_EMITTER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "IParticleEmitter.h" +#include "irrArray.h" + +namespace irr +{ +namespace scene +{ + +//! A default point emitter +class CParticlePointEmitter : public IParticlePointEmitter +{ +public: + + //! constructor + CParticlePointEmitter( + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 5, + u32 maxParticlesPerSecond = 10, + video::SColor minStartColor = video::SColor(255,0,0,0), + video::SColor maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin=2000, + u32 lifeTimeMax=4000, + s32 maxAngleDegrees=0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) ); + + //! Prepares an array with new particles to emitt into the system + //! and returns how much new particles there are. + virtual s32 emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray) _IRR_OVERRIDE_; + + //! Set direction the emitter emits particles. + virtual void setDirection( const core::vector3df& newDirection ) _IRR_OVERRIDE_ { Direction = newDirection; } + + //! Set minimum number of particles emitted per second. + virtual void setMinParticlesPerSecond( u32 minPPS ) _IRR_OVERRIDE_ { MinParticlesPerSecond = minPPS; } + + //! Set maximum number of particles emitted per second. + virtual void setMaxParticlesPerSecond( u32 maxPPS ) _IRR_OVERRIDE_ { MaxParticlesPerSecond = maxPPS; } + + //! Set minimum start color. + virtual void setMinStartColor( const video::SColor& color ) _IRR_OVERRIDE_ { MinStartColor = color; } + + //! Set maximum start color. + virtual void setMaxStartColor( const video::SColor& color ) _IRR_OVERRIDE_ { MaxStartColor = color; } + + //! Set the maximum starting size for particles + virtual void setMaxStartSize( const core::dimension2df& size ) _IRR_OVERRIDE_ { MaxStartSize = size; } + + //! Set the minimum starting size for particles + virtual void setMinStartSize( const core::dimension2df& size ) _IRR_OVERRIDE_ { MinStartSize = size; } + + //! Set the minimum particle life-time in milliseconds + virtual void setMinLifeTime( u32 lifeTimeMin ) _IRR_OVERRIDE_ { MinLifeTime = lifeTimeMin; } + + //! Set the maximum particle life-time in milliseconds + virtual void setMaxLifeTime( u32 lifeTimeMax ) _IRR_OVERRIDE_ { MaxLifeTime = lifeTimeMax; } + + //! Set maximal random derivation from the direction + virtual void setMaxAngleDegrees( s32 maxAngleDegrees ) _IRR_OVERRIDE_ { MaxAngleDegrees = maxAngleDegrees; } + + //! Gets direction the emitter emits particles. + virtual const core::vector3df& getDirection() const _IRR_OVERRIDE_ { return Direction; } + + //! Gets minimum number of particles emitted per second. + virtual u32 getMinParticlesPerSecond() const _IRR_OVERRIDE_ { return MinParticlesPerSecond; } + + //! Gets maximum number of particles emitted per second. + virtual u32 getMaxParticlesPerSecond() const _IRR_OVERRIDE_ { return MaxParticlesPerSecond; } + + //! Gets minimum start color. + virtual const video::SColor& getMinStartColor() const _IRR_OVERRIDE_ { return MinStartColor; } + + //! Gets maximum start color. + virtual const video::SColor& getMaxStartColor() const _IRR_OVERRIDE_ { return MaxStartColor; } + + //! Gets the maximum starting size for particles + virtual const core::dimension2df& getMaxStartSize() const _IRR_OVERRIDE_ { return MaxStartSize; } + + //! Gets the minimum starting size for particles + virtual const core::dimension2df& getMinStartSize() const _IRR_OVERRIDE_ { return MinStartSize; } + + //! Get the minimum particle life-time in milliseconds + virtual u32 getMinLifeTime() const _IRR_OVERRIDE_ { return MinLifeTime; } + + //! Get the maximum particle life-time in milliseconds + virtual u32 getMaxLifeTime() const _IRR_OVERRIDE_ { return MaxLifeTime; } + + //! Get maximal random derivation from the direction + virtual s32 getMaxAngleDegrees() const _IRR_OVERRIDE_ { return MaxAngleDegrees; } + + //! Writes attributes of the object. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the object. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + +private: + + SParticle Particle; + core::vector3df Direction; + core::dimension2df MinStartSize, MaxStartSize; + u32 MinParticlesPerSecond, MaxParticlesPerSecond; + video::SColor MinStartColor, MaxStartColor; + u32 MinLifeTime, MaxLifeTime; + s32 MaxAngleDegrees; + + u32 Time; +}; + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ + +#endif diff --git a/source/Irrlicht/CParticleRingEmitter.cpp b/source/Irrlicht/CParticleRingEmitter.cpp new file mode 100644 index 00000000..7fc6ec86 --- /dev/null +++ b/source/Irrlicht/CParticleRingEmitter.cpp @@ -0,0 +1,181 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CParticleRingEmitter.h" + +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "os.h" +#include "IAttributes.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CParticleRingEmitter::CParticleRingEmitter( + const core::vector3df& center, f32 radius, f32 ringThickness, + const core::vector3df& direction, u32 minParticlesPerSecond, + u32 maxParticlesPerSecond, const video::SColor& minStartColor, + const video::SColor& maxStartColor, u32 lifeTimeMin, u32 lifeTimeMax, + s32 maxAngleDegrees, + const core::dimension2df& minStartSize, + const core::dimension2df& maxStartSize ) + : Center(center), Radius(radius), RingThickness(ringThickness), + Direction(direction), + MaxStartSize(maxStartSize), MinStartSize(minStartSize), + MinParticlesPerSecond(minParticlesPerSecond), + MaxParticlesPerSecond(maxParticlesPerSecond), + MinStartColor(minStartColor), MaxStartColor(maxStartColor), + MinLifeTime(lifeTimeMin), MaxLifeTime(lifeTimeMax), + Time(0), MaxAngleDegrees(maxAngleDegrees) +{ + #ifdef _DEBUG + setDebugName("CParticleRingEmitter"); + #endif +} + + +//! Prepares an array with new particles to emitt into the system +//! and returns how much new particles there are. +s32 CParticleRingEmitter::emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray) +{ + Time += timeSinceLastCall; + + u32 pps = (MaxParticlesPerSecond - MinParticlesPerSecond); + f32 perSecond = pps ? ((f32)MinParticlesPerSecond + os::Randomizer::frand() * pps) : MinParticlesPerSecond; + f32 everyWhatMillisecond = 1000.0f / perSecond; + + if(Time > everyWhatMillisecond) + { + Particles.set_used(0); + u32 amount = (u32)((Time / everyWhatMillisecond) + 0.5f); + Time = 0; + SParticle p; + + if(amount > MaxParticlesPerSecond*2) + amount = MaxParticlesPerSecond * 2; + + for(u32 i=0; iaddVector3d("Center", Center); + out->addFloat("Radius", Radius); + out->addFloat("RingThickness", RingThickness); + + out->addVector3d("Direction", Direction); + out->addFloat("MinStartSizeWidth", MinStartSize.Width); + out->addFloat("MinStartSizeHeight", MinStartSize.Height); + out->addFloat("MaxStartSizeWidth", MaxStartSize.Width); + out->addFloat("MaxStartSizeHeight", MaxStartSize.Height); + out->addInt("MinParticlesPerSecond", MinParticlesPerSecond); + out->addInt("MaxParticlesPerSecond", MaxParticlesPerSecond); + out->addColor("MinStartColor", MinStartColor); + out->addColor("MaxStartColor", MaxStartColor); + out->addInt("MinLifeTime", MinLifeTime); + out->addInt("MaxLifeTime", MaxLifeTime); + out->addInt("MaxAngleDegrees", MaxAngleDegrees); +} + +//! Reads attributes of the object. +void CParticleRingEmitter::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + Center = in->getAttributeAsVector3d("Center"); + Radius = in->getAttributeAsFloat("Radius"); + RingThickness = in->getAttributeAsFloat("RingThickness"); + + Direction = in->getAttributeAsVector3d("Direction"); + if (Direction.getLength() == 0) + Direction.set(0,0.01f,0); + + int idx = -1; + idx = in->findAttribute("MinStartSizeWidth"); + if ( idx >= 0 ) + MinStartSize.Width = in->getAttributeAsFloat(idx); + idx = in->findAttribute("MinStartSizeHeight"); + if ( idx >= 0 ) + MinStartSize.Height = in->getAttributeAsFloat(idx); + idx = in->findAttribute("MaxStartSizeWidth"); + if ( idx >= 0 ) + MaxStartSize.Width = in->getAttributeAsFloat(idx); + idx = in->findAttribute("MaxStartSizeHeight"); + if ( idx >= 0 ) + MaxStartSize.Height = in->getAttributeAsFloat(idx); + + MinParticlesPerSecond = in->getAttributeAsInt("MinParticlesPerSecond"); + MaxParticlesPerSecond = in->getAttributeAsInt("MaxParticlesPerSecond"); + + MinParticlesPerSecond = core::max_(1u, MinParticlesPerSecond); + MaxParticlesPerSecond = core::max_(MaxParticlesPerSecond, 1u); + MaxParticlesPerSecond = core::min_(MaxParticlesPerSecond, 200u); + MinParticlesPerSecond = core::min_(MinParticlesPerSecond, MaxParticlesPerSecond); + + MinStartColor = in->getAttributeAsColor("MinStartColor"); + MaxStartColor = in->getAttributeAsColor("MaxStartColor"); + MinLifeTime = in->getAttributeAsInt("MinLifeTime"); + MaxLifeTime = in->getAttributeAsInt("MaxLifeTime"); + MinLifeTime = core::max_(0u, MinLifeTime); + MaxLifeTime = core::max_(MaxLifeTime, MinLifeTime); + MinLifeTime = core::min_(MinLifeTime, MaxLifeTime); + + MaxAngleDegrees = in->getAttributeAsInt("MaxAngleDegrees"); +} + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ diff --git a/source/Irrlicht/CParticleRingEmitter.h b/source/Irrlicht/CParticleRingEmitter.h new file mode 100644 index 00000000..f36254dd --- /dev/null +++ b/source/Irrlicht/CParticleRingEmitter.h @@ -0,0 +1,151 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_PARTICLE_RING_EMITTER_H_INCLUDED__ +#define __C_PARTICLE_RING_EMITTER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "IParticleRingEmitter.h" +#include "irrArray.h" + +namespace irr +{ +namespace scene +{ + +//! A ring emitter +class CParticleRingEmitter : public IParticleRingEmitter +{ +public: + + //! constructor + CParticleRingEmitter( + const core::vector3df& center, f32 radius, f32 ringThickness, + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 20, + u32 maxParticlesPerSecond = 40, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin=2000, + u32 lifeTimeMax=4000, + s32 maxAngleDegrees=0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) + ); + + //! Prepares an array with new particles to emitt into the system + //! and returns how much new particles there are. + virtual s32 emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray) _IRR_OVERRIDE_; + + //! Set direction the emitter emits particles + virtual void setDirection( const core::vector3df& newDirection ) _IRR_OVERRIDE_ { Direction = newDirection; } + + //! Set minimum number of particles the emitter emits per second + virtual void setMinParticlesPerSecond( u32 minPPS ) _IRR_OVERRIDE_ { MinParticlesPerSecond = minPPS; } + + //! Set maximum number of particles the emitter emits per second + virtual void setMaxParticlesPerSecond( u32 maxPPS ) _IRR_OVERRIDE_ { MaxParticlesPerSecond = maxPPS; } + + //! Set minimum starting color for particles + virtual void setMinStartColor( const video::SColor& color ) _IRR_OVERRIDE_ { MinStartColor = color; } + + //! Set maximum starting color for particles + virtual void setMaxStartColor( const video::SColor& color ) _IRR_OVERRIDE_ { MaxStartColor = color; } + + //! Set the maximum starting size for particles + virtual void setMaxStartSize( const core::dimension2df& size ) _IRR_OVERRIDE_ { MaxStartSize = size; } + + //! Set the minimum starting size for particles + virtual void setMinStartSize( const core::dimension2df& size ) _IRR_OVERRIDE_ { MinStartSize = size; } + + //! Set the minimum particle life-time in milliseconds + virtual void setMinLifeTime( u32 lifeTimeMin ) _IRR_OVERRIDE_ { MinLifeTime = lifeTimeMin; } + + //! Set the maximum particle life-time in milliseconds + virtual void setMaxLifeTime( u32 lifeTimeMax ) _IRR_OVERRIDE_ { MaxLifeTime = lifeTimeMax; } + + //! Set maximal random derivation from the direction + virtual void setMaxAngleDegrees( s32 maxAngleDegrees ) _IRR_OVERRIDE_ { MaxAngleDegrees = maxAngleDegrees; } + + //! Set the center of the ring + virtual void setCenter( const core::vector3df& center ) _IRR_OVERRIDE_ { Center = center; } + + //! Set the radius of the ring + virtual void setRadius( f32 radius ) _IRR_OVERRIDE_ { Radius = radius; } + + //! Set the thickness of the ring + virtual void setRingThickness( f32 ringThickness ) _IRR_OVERRIDE_ { RingThickness = ringThickness; } + + //! Gets direction the emitter emits particles + virtual const core::vector3df& getDirection() const _IRR_OVERRIDE_ { return Direction; } + + //! Gets the minimum number of particles the emitter emits per second + virtual u32 getMinParticlesPerSecond() const _IRR_OVERRIDE_ { return MinParticlesPerSecond; } + + //! Gets the maximum number of particles the emitter emits per second + virtual u32 getMaxParticlesPerSecond() const _IRR_OVERRIDE_ { return MaxParticlesPerSecond; } + + //! Gets the minimum starting color for particles + virtual const video::SColor& getMinStartColor() const _IRR_OVERRIDE_ { return MinStartColor; } + + //! Gets the maximum starting color for particles + virtual const video::SColor& getMaxStartColor() const _IRR_OVERRIDE_ { return MaxStartColor; } + + //! Gets the maximum starting size for particles + virtual const core::dimension2df& getMaxStartSize() const _IRR_OVERRIDE_ { return MaxStartSize; } + + //! Gets the minimum starting size for particles + virtual const core::dimension2df& getMinStartSize() const _IRR_OVERRIDE_ { return MinStartSize; } + + //! Get the minimum particle life-time in milliseconds + virtual u32 getMinLifeTime() const _IRR_OVERRIDE_ { return MinLifeTime; } + + //! Get the maximum particle life-time in milliseconds + virtual u32 getMaxLifeTime() const _IRR_OVERRIDE_ { return MaxLifeTime; } + + //! Get maximal random derivation from the direction + virtual s32 getMaxAngleDegrees() const _IRR_OVERRIDE_ { return MaxAngleDegrees; } + + //! Get the center of the ring + virtual const core::vector3df& getCenter() const _IRR_OVERRIDE_ { return Center; } + + //! Get the radius of the ring + virtual f32 getRadius() const _IRR_OVERRIDE_ { return Radius; } + + //! Get the thickness of the ring + virtual f32 getRingThickness() const _IRR_OVERRIDE_ { return RingThickness; } + + //! Writes attributes of the object. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the object. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + +private: + + core::array Particles; + + core::vector3df Center; + f32 Radius; + f32 RingThickness; + + core::vector3df Direction; + core::dimension2df MaxStartSize, MinStartSize; + u32 MinParticlesPerSecond, MaxParticlesPerSecond; + video::SColor MinStartColor, MaxStartColor; + u32 MinLifeTime, MaxLifeTime; + + u32 Time; + s32 MaxAngleDegrees; +}; + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ + +#endif + diff --git a/source/Irrlicht/CParticleRotationAffector.cpp b/source/Irrlicht/CParticleRotationAffector.cpp new file mode 100644 index 00000000..f30ab964 --- /dev/null +++ b/source/Irrlicht/CParticleRotationAffector.cpp @@ -0,0 +1,72 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CParticleRotationAffector.h" + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "IAttributes.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CParticleRotationAffector::CParticleRotationAffector( const core::vector3df& speed, const core::vector3df& pivotPoint ) + : PivotPoint(pivotPoint), Speed(speed), LastTime(0) +{ + #ifdef _DEBUG + setDebugName("CParticleRotationAffector"); + #endif +} + + +//! Affects an array of particles. +void CParticleRotationAffector::affect(u32 now, SParticle* particlearray, u32 count) +{ + if( LastTime == 0 ) + { + LastTime = now; + return; + } + + f32 timeDelta = ( now - LastTime ) / 1000.0f; + LastTime = now; + + if( !Enabled ) + return; + + for(u32 i=0; iaddVector3d("PivotPoint", PivotPoint); + out->addVector3d("Speed", Speed); +} + +//! Reads attributes of the object. +void CParticleRotationAffector::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + PivotPoint = in->getAttributeAsVector3d("PivotPoint"); + Speed = in->getAttributeAsVector3d("Speed"); +} + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ diff --git a/source/Irrlicht/CParticleRotationAffector.h b/source/Irrlicht/CParticleRotationAffector.h new file mode 100644 index 00000000..2828b8ef --- /dev/null +++ b/source/Irrlicht/CParticleRotationAffector.h @@ -0,0 +1,59 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_PARTICLE_ROTATION_AFFECTOR_H_INCLUDED__ +#define __C_PARTICLE_ROTATION_AFFECTOR_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "IParticleRotationAffector.h" + +namespace irr +{ +namespace scene +{ + +//! Particle Affector for rotating particles about a point +class CParticleRotationAffector : public IParticleRotationAffector +{ +public: + + CParticleRotationAffector( const core::vector3df& speed = core::vector3df(5.0f, 5.0f, 5.0f), + const core::vector3df& point = core::vector3df() ); + + //! Affects a particle. + virtual void affect(u32 now, SParticle* particlearray, u32 count) _IRR_OVERRIDE_; + + //! Set the point that particles will attract to + virtual void setPivotPoint( const core::vector3df& point ) _IRR_OVERRIDE_ { PivotPoint = point; } + + //! Set the speed in degrees per second + virtual void setSpeed( const core::vector3df& speed ) _IRR_OVERRIDE_ { Speed = speed; } + + //! Get the point that particles are attracted to + virtual const core::vector3df& getPivotPoint() const _IRR_OVERRIDE_ { return PivotPoint; } + + //! Get the speed in degrees per second + virtual const core::vector3df& getSpeed() const _IRR_OVERRIDE_ { return Speed; } + + //! Writes attributes of the object. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the object. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + +private: + + core::vector3df PivotPoint; + core::vector3df Speed; + u32 LastTime; +}; + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ + +#endif // __C_PARTICLE_ROTATION_AFFECTOR_H_INCLUDED__ diff --git a/source/Irrlicht/CParticleScaleAffector.cpp b/source/Irrlicht/CParticleScaleAffector.cpp new file mode 100644 index 00000000..9b8d0262 --- /dev/null +++ b/source/Irrlicht/CParticleScaleAffector.cpp @@ -0,0 +1,57 @@ +// Copyright (C) 2010-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CParticleScaleAffector.h" + +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "IAttributes.h" + +namespace irr +{ + namespace scene + { + CParticleScaleAffector::CParticleScaleAffector(const core::dimension2df& scaleTo) + : ScaleTo(scaleTo) + { + #ifdef _DEBUG + setDebugName("CParticleScaleAffector"); + #endif + } + + + void CParticleScaleAffector::affect (u32 now, SParticle *particlearray, u32 count) + { + for(u32 i=0;iaddFloat("ScaleToWidth", ScaleTo.Width); + out->addFloat("ScaleToHeight", ScaleTo.Height); + } + + + void CParticleScaleAffector::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) + { + ScaleTo.Width = in->getAttributeAsFloat("ScaleToWidth"); + ScaleTo.Height = in->getAttributeAsFloat("ScaleToHeight"); + } + + + E_PARTICLE_AFFECTOR_TYPE CParticleScaleAffector::getType() const + { + return scene::EPAT_SCALE; + } + } +} + +#endif // _IRR_COMPILE_WITH_PARTICLES_ diff --git a/source/Irrlicht/CParticleScaleAffector.h b/source/Irrlicht/CParticleScaleAffector.h new file mode 100644 index 00000000..0f403c91 --- /dev/null +++ b/source/Irrlicht/CParticleScaleAffector.h @@ -0,0 +1,48 @@ +// Copyright (C) 2010-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef C_PARTICLE_SCALE_AFFECTOR_H +#define C_PARTICLE_SCALE_AFFECTOR_H + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "IParticleAffector.h" + +namespace irr +{ + namespace scene + { + class CParticleScaleAffector : public IParticleAffector + { + public: + CParticleScaleAffector(const core::dimension2df& scaleTo = core::dimension2df(1.0f, 1.0f)); + + virtual void affect(u32 now, SParticle *particlearray, u32 count) _IRR_OVERRIDE_; + + //! Writes attributes of the object. + //! 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) const _IRR_OVERRIDE_; + + //! Reads attributes of the object. + //! Implement this to set the attributes of your scene node animator for + //! scripting languages, editors, debuggers or xml deserialization purposes. + //! \param startIndex: start index where to start reading attributes. + //! \return: returns last index of an attribute read by this affector + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + + //! Get emitter type + virtual E_PARTICLE_AFFECTOR_TYPE getType() const _IRR_OVERRIDE_; + + protected: + core::dimension2df ScaleTo; + }; + } +} + +#endif // _IRR_COMPILE_WITH_PARTICLES_ + +#endif // C_PARTICLE_SCALE_AFFECTOR_H + diff --git a/source/Irrlicht/CParticleSphereEmitter.cpp b/source/Irrlicht/CParticleSphereEmitter.cpp new file mode 100644 index 00000000..c97d6daa --- /dev/null +++ b/source/Irrlicht/CParticleSphereEmitter.cpp @@ -0,0 +1,178 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CParticleSphereEmitter.h" + +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "os.h" +#include "IAttributes.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CParticleSphereEmitter::CParticleSphereEmitter( + const core::vector3df& center, f32 radius, + const core::vector3df& direction, u32 minParticlesPerSecond, + u32 maxParticlesPerSecond, const video::SColor& minStartColor, + const video::SColor& maxStartColor, u32 lifeTimeMin, u32 lifeTimeMax, + s32 maxAngleDegrees, + const core::dimension2df& minStartSize, + const core::dimension2df& maxStartSize ) + : Center(center), Radius(radius), Direction(direction), + MinStartSize(minStartSize), MaxStartSize(maxStartSize), + MinParticlesPerSecond(minParticlesPerSecond), + MaxParticlesPerSecond(maxParticlesPerSecond), + MinStartColor(minStartColor), MaxStartColor(maxStartColor), + MinLifeTime(lifeTimeMin), MaxLifeTime(lifeTimeMax), + Time(0), MaxAngleDegrees(maxAngleDegrees) +{ + #ifdef _DEBUG + setDebugName("CParticleSphereEmitter"); + #endif + +} + + +//! Prepares an array with new particles to emitt into the system +//! and returns how much new particles there are. +s32 CParticleSphereEmitter::emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray) +{ + Time += timeSinceLastCall; + + const u32 pps = (MaxParticlesPerSecond - MinParticlesPerSecond); + const f32 perSecond = pps ? ((f32)MinParticlesPerSecond + os::Randomizer::frand() * pps) : MinParticlesPerSecond; + const f32 everyWhatMillisecond = 1000.0f / perSecond; + + if(Time > everyWhatMillisecond) + { + Particles.set_used(0); + u32 amount = (u32)((Time / everyWhatMillisecond) + 0.5f); + Time = 0; + SParticle p; + + if(amount > MaxParticlesPerSecond*2) + amount = MaxParticlesPerSecond * 2; + + for(u32 i=0; iaddVector3d("Center", Direction); + out->addFloat("Radius", Radius); + + out->addVector3d("Direction", Direction); + out->addFloat("MinStartSizeWidth", MinStartSize.Width); + out->addFloat("MinStartSizeHeight", MinStartSize.Height); + out->addFloat("MaxStartSizeWidth", MaxStartSize.Width); + out->addFloat("MaxStartSizeHeight", MaxStartSize.Height); + out->addInt("MinParticlesPerSecond", MinParticlesPerSecond); + out->addInt("MaxParticlesPerSecond", MaxParticlesPerSecond); + out->addColor("MinStartColor", MinStartColor); + out->addColor("MaxStartColor", MaxStartColor); + out->addInt("MinLifeTime", MinLifeTime); + out->addInt("MaxLifeTime", MaxLifeTime); + out->addInt("MaxAngleDegrees", MaxAngleDegrees); +} + +//! Reads attributes of the object. +void CParticleSphereEmitter::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + Center = in->getAttributeAsVector3d("Center"); + Radius = in->getAttributeAsFloat("Radius"); + + Direction = in->getAttributeAsVector3d("Direction"); + if (Direction.getLength() == 0) + Direction.set(0,0.01f,0); + + int idx = -1; + idx = in->findAttribute("MinStartSizeWidth"); + if ( idx >= 0 ) + MinStartSize.Width = in->getAttributeAsFloat(idx); + idx = in->findAttribute("MinStartSizeHeight"); + if ( idx >= 0 ) + MinStartSize.Height = in->getAttributeAsFloat(idx); + idx = in->findAttribute("MaxStartSizeWidth"); + if ( idx >= 0 ) + MaxStartSize.Width = in->getAttributeAsFloat(idx); + idx = in->findAttribute("MaxStartSizeHeight"); + if ( idx >= 0 ) + MaxStartSize.Height = in->getAttributeAsFloat(idx); + MinParticlesPerSecond = in->getAttributeAsInt("MinParticlesPerSecond"); + MaxParticlesPerSecond = in->getAttributeAsInt("MaxParticlesPerSecond"); + + MinParticlesPerSecond = core::max_(1u, MinParticlesPerSecond); + MaxParticlesPerSecond = core::max_(MaxParticlesPerSecond, 1u); + MaxParticlesPerSecond = core::min_(MaxParticlesPerSecond, 200u); + MinParticlesPerSecond = core::min_(MinParticlesPerSecond, MaxParticlesPerSecond); + + MinStartColor = in->getAttributeAsColor("MinStartColor"); + MaxStartColor = in->getAttributeAsColor("MaxStartColor"); + MinLifeTime = in->getAttributeAsInt("MinLifeTime"); + MaxLifeTime = in->getAttributeAsInt("MaxLifeTime"); + MinLifeTime = core::max_(0u, MinLifeTime); + MaxLifeTime = core::max_(MaxLifeTime, MinLifeTime); + MinLifeTime = core::min_(MinLifeTime, MaxLifeTime); + + MaxAngleDegrees = in->getAttributeAsInt("MaxAngleDegrees"); +} + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ diff --git a/source/Irrlicht/CParticleSphereEmitter.h b/source/Irrlicht/CParticleSphereEmitter.h new file mode 100644 index 00000000..1d9475bd --- /dev/null +++ b/source/Irrlicht/CParticleSphereEmitter.h @@ -0,0 +1,144 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_PARTICLE_SPHERE_EMITTER_H_INCLUDED__ +#define __C_PARTICLE_SPHERE_EMITTER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "IParticleSphereEmitter.h" +#include "irrArray.h" +#include "aabbox3d.h" + +namespace irr +{ +namespace scene +{ + +//! A default box emitter +class CParticleSphereEmitter : public IParticleSphereEmitter +{ +public: + + //! constructor + CParticleSphereEmitter( + const core::vector3df& center, f32 radius, + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 20, + u32 maxParticlesPerSecond = 40, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin=2000, + u32 lifeTimeMax=4000, + s32 maxAngleDegrees=0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) ); + + //! Prepares an array with new particles to emitt into the system + //! and returns how much new particles there are. + virtual s32 emitt(u32 now, u32 timeSinceLastCall, SParticle*& outArray) _IRR_OVERRIDE_; + + //! Set direction the emitter emits particles + virtual void setDirection( const core::vector3df& newDirection ) _IRR_OVERRIDE_ { Direction = newDirection; } + + //! Set minimum number of particles per second. + virtual void setMinParticlesPerSecond( u32 minPPS ) _IRR_OVERRIDE_ { MinParticlesPerSecond = minPPS; } + + //! Set maximum number of particles per second. + virtual void setMaxParticlesPerSecond( u32 maxPPS ) _IRR_OVERRIDE_ { MaxParticlesPerSecond = maxPPS; } + + //! Set minimum start color + virtual void setMinStartColor( const video::SColor& color ) _IRR_OVERRIDE_ { MinStartColor = color; } + + //! Set maximum start color + virtual void setMaxStartColor( const video::SColor& color ) _IRR_OVERRIDE_ { MaxStartColor = color; } + + //! Set the maximum starting size for particles + virtual void setMaxStartSize( const core::dimension2df& size ) _IRR_OVERRIDE_ { MaxStartSize = size; } + + //! Set the minimum starting size for particles + virtual void setMinStartSize( const core::dimension2df& size ) _IRR_OVERRIDE_ { MinStartSize = size; } + + //! Set the minimum particle life-time in milliseconds + virtual void setMinLifeTime( u32 lifeTimeMin ) _IRR_OVERRIDE_ { MinLifeTime = lifeTimeMin; } + + //! Set the maximum particle life-time in milliseconds + virtual void setMaxLifeTime( u32 lifeTimeMax ) _IRR_OVERRIDE_ { MaxLifeTime = lifeTimeMax; } + + //! Set maximal random derivation from the direction + virtual void setMaxAngleDegrees( s32 maxAngleDegrees ) _IRR_OVERRIDE_ { MaxAngleDegrees = maxAngleDegrees; } + + //! Set the center of the sphere for particle emissions + virtual void setCenter( const core::vector3df& center ) _IRR_OVERRIDE_ { Center = center; } + + //! Set the radius of the sphere for particle emissions + virtual void setRadius( f32 radius ) _IRR_OVERRIDE_ { Radius = radius; } + + //! Gets direction the emitter emits particles + virtual const core::vector3df& getDirection() const _IRR_OVERRIDE_ { return Direction; } + + //! Get minimum number of particles per second. + virtual u32 getMinParticlesPerSecond() const _IRR_OVERRIDE_ { return MinParticlesPerSecond; } + + //! Get maximum number of particles per second. + virtual u32 getMaxParticlesPerSecond() const _IRR_OVERRIDE_ { return MaxParticlesPerSecond; } + + //! Get minimum start color + virtual const video::SColor& getMinStartColor() const _IRR_OVERRIDE_ { return MinStartColor; } + + //! Get maximum start color + virtual const video::SColor& getMaxStartColor() const _IRR_OVERRIDE_ { return MaxStartColor; } + + //! Gets the maximum starting size for particles + virtual const core::dimension2df& getMaxStartSize() const _IRR_OVERRIDE_ { return MaxStartSize; } + + //! Gets the minimum starting size for particles + virtual const core::dimension2df& getMinStartSize() const _IRR_OVERRIDE_ { return MinStartSize; } + + //! Get the minimum particle life-time in milliseconds + virtual u32 getMinLifeTime() const _IRR_OVERRIDE_ { return MinLifeTime; } + + //! Get the maximum particle life-time in milliseconds + virtual u32 getMaxLifeTime() const _IRR_OVERRIDE_ { return MaxLifeTime; } + + //! Get maximal random derivation from the direction + virtual s32 getMaxAngleDegrees() const _IRR_OVERRIDE_ { return MaxAngleDegrees; } + + //! Get the center of the sphere for particle emissions + virtual const core::vector3df& getCenter() const _IRR_OVERRIDE_ { return Center; } + + //! Get the radius of the sphere for particle emissions + virtual f32 getRadius() const _IRR_OVERRIDE_ { return Radius; } + + //! Writes attributes of the object. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the object. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + +private: + + core::array Particles; + + core::vector3df Center; + f32 Radius; + core::vector3df Direction; + + core::dimension2df MinStartSize, MaxStartSize; + u32 MinParticlesPerSecond, MaxParticlesPerSecond; + video::SColor MinStartColor, MaxStartColor; + u32 MinLifeTime, MaxLifeTime; + + u32 Time; + s32 MaxAngleDegrees; +}; + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ + +#endif + diff --git a/source/Irrlicht/CParticleSystemSceneNode.cpp b/source/Irrlicht/CParticleSystemSceneNode.cpp new file mode 100644 index 00000000..994a43c3 --- /dev/null +++ b/source/Irrlicht/CParticleSystemSceneNode.cpp @@ -0,0 +1,786 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CParticleSystemSceneNode.h" + +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "os.h" +#include "ISceneManager.h" +#include "ICameraSceneNode.h" +#include "IVideoDriver.h" + +#include "CParticleAnimatedMeshSceneNodeEmitter.h" +#include "CParticleBoxEmitter.h" +#include "CParticleCylinderEmitter.h" +#include "CParticleMeshEmitter.h" +#include "CParticlePointEmitter.h" +#include "CParticleRingEmitter.h" +#include "CParticleSphereEmitter.h" +#include "CParticleAttractionAffector.h" +#include "CParticleFadeOutAffector.h" +#include "CParticleGravityAffector.h" +#include "CParticleRotationAffector.h" +#include "CParticleScaleAffector.h" +#include "SViewFrustum.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CParticleSystemSceneNode::CParticleSystemSceneNode(bool createDefaultEmitter, + ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position, const core::vector3df& rotation, + const core::vector3df& scale) + : IParticleSystemSceneNode(parent, mgr, id, position, rotation, scale), + Emitter(0), ParticleSize(core::dimension2d(5.0f, 5.0f)), LastEmitTime(0), + Buffer(0), ParticlesAreGlobal(true) +{ + #ifdef _DEBUG + setDebugName("CParticleSystemSceneNode"); + #endif + + Buffer = new SMeshBuffer(); + if (createDefaultEmitter) + { + IParticleEmitter* e = createBoxEmitter(); + setEmitter(e); + e->drop(); + } +} + + +//! destructor +CParticleSystemSceneNode::~CParticleSystemSceneNode() +{ + if (Emitter) + Emitter->drop(); + if (Buffer) + Buffer->drop(); + + removeAllAffectors(); +} + + +//! Gets the particle emitter, which creates the particles. +IParticleEmitter* CParticleSystemSceneNode::getEmitter() +{ + return Emitter; +} + + +//! Sets the particle emitter, which creates the particles. +void CParticleSystemSceneNode::setEmitter(IParticleEmitter* emitter) +{ + if (emitter == Emitter) + return; + if (Emitter) + Emitter->drop(); + + Emitter = emitter; + + if (Emitter) + Emitter->grab(); +} + + +//! Adds new particle effector to the particle system. +void CParticleSystemSceneNode::addAffector(IParticleAffector* affector) +{ + affector->grab(); + AffectorList.push_back(affector); +} + +//! Get a list of all particle affectors. +const core::list& CParticleSystemSceneNode::getAffectors() const +{ + return AffectorList; +} + +//! Removes all particle affectors in the particle system. +void CParticleSystemSceneNode::removeAllAffectors() +{ + core::list::Iterator it = AffectorList.begin(); + while (it != AffectorList.end()) + { + (*it)->drop(); + it = AffectorList.erase(it); + } +} + + +//! Returns the material based on the zero based index i. +video::SMaterial& CParticleSystemSceneNode::getMaterial(u32 i) +{ + return Buffer->Material; +} + + +//! Returns amount of materials used by this scene node. +u32 CParticleSystemSceneNode::getMaterialCount() const +{ + return 1; +} + + +//! Creates a particle emitter for an animated mesh scene node +IParticleAnimatedMeshSceneNodeEmitter* +CParticleSystemSceneNode::createAnimatedMeshSceneNodeEmitter( + scene::IAnimatedMeshSceneNode* node, bool useNormalDirection, + const core::vector3df& direction, f32 normalDirectionModifier, + s32 mbNumber, bool everyMeshVertex, + u32 minParticlesPerSecond, u32 maxParticlesPerSecond, + const video::SColor& minStartColor, const video::SColor& maxStartColor, + u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees, + const core::dimension2df& minStartSize, + const core::dimension2df& maxStartSize ) +{ + return new CParticleAnimatedMeshSceneNodeEmitter( node, + useNormalDirection, direction, normalDirectionModifier, + mbNumber, everyMeshVertex, + minParticlesPerSecond, maxParticlesPerSecond, + minStartColor, maxStartColor, + lifeTimeMin, lifeTimeMax, maxAngleDegrees, + minStartSize, maxStartSize ); +} + + +//! Creates a box particle emitter. +IParticleBoxEmitter* CParticleSystemSceneNode::createBoxEmitter( + const core::aabbox3df& box, const core::vector3df& direction, + u32 minParticlesPerSecond, u32 maxParticlesPerSecond, + const video::SColor& minStartColor, const video::SColor& maxStartColor, + u32 lifeTimeMin, u32 lifeTimeMax, + s32 maxAngleDegrees, const core::dimension2df& minStartSize, + const core::dimension2df& maxStartSize ) +{ + return new CParticleBoxEmitter(box, direction, minParticlesPerSecond, + maxParticlesPerSecond, minStartColor, maxStartColor, + lifeTimeMin, lifeTimeMax, maxAngleDegrees, + minStartSize, maxStartSize ); +} + + +//! Creates a particle emitter for emitting from a cylinder +IParticleCylinderEmitter* CParticleSystemSceneNode::createCylinderEmitter( + const core::vector3df& center, f32 radius, + const core::vector3df& normal, f32 length, + bool outlineOnly, const core::vector3df& direction, + u32 minParticlesPerSecond, u32 maxParticlesPerSecond, + const video::SColor& minStartColor, const video::SColor& maxStartColor, + u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees, + const core::dimension2df& minStartSize, + const core::dimension2df& maxStartSize ) +{ + return new CParticleCylinderEmitter( center, radius, normal, length, + outlineOnly, direction, + minParticlesPerSecond, maxParticlesPerSecond, + minStartColor, maxStartColor, + lifeTimeMin, lifeTimeMax, maxAngleDegrees, + minStartSize, maxStartSize ); +} + + +//! Creates a mesh particle emitter. +IParticleMeshEmitter* CParticleSystemSceneNode::createMeshEmitter( + scene::IMesh* mesh, bool useNormalDirection, + const core::vector3df& direction, f32 normalDirectionModifier, + s32 mbNumber, bool everyMeshVertex, + u32 minParticlesPerSecond, u32 maxParticlesPerSecond, + const video::SColor& minStartColor, const video::SColor& maxStartColor, + u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees, + const core::dimension2df& minStartSize, + const core::dimension2df& maxStartSize) +{ + return new CParticleMeshEmitter( mesh, useNormalDirection, direction, + normalDirectionModifier, mbNumber, everyMeshVertex, + minParticlesPerSecond, maxParticlesPerSecond, + minStartColor, maxStartColor, + lifeTimeMin, lifeTimeMax, maxAngleDegrees, + minStartSize, maxStartSize ); +} + + +//! Creates a point particle emitter. +IParticlePointEmitter* CParticleSystemSceneNode::createPointEmitter( + const core::vector3df& direction, u32 minParticlesPerSecond, + u32 maxParticlesPerSecond, const video::SColor& minStartColor, + const video::SColor& maxStartColor, u32 lifeTimeMin, u32 lifeTimeMax, + s32 maxAngleDegrees, const core::dimension2df& minStartSize, + const core::dimension2df& maxStartSize ) +{ + return new CParticlePointEmitter(direction, minParticlesPerSecond, + maxParticlesPerSecond, minStartColor, maxStartColor, + lifeTimeMin, lifeTimeMax, maxAngleDegrees, + minStartSize, maxStartSize ); +} + + +//! Creates a ring particle emitter. +IParticleRingEmitter* CParticleSystemSceneNode::createRingEmitter( + const core::vector3df& center, f32 radius, f32 ringThickness, + const core::vector3df& direction, + u32 minParticlesPerSecond, u32 maxParticlesPerSecond, + const video::SColor& minStartColor, const video::SColor& maxStartColor, + u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees, + const core::dimension2df& minStartSize, const core::dimension2df& maxStartSize ) +{ + return new CParticleRingEmitter( center, radius, ringThickness, direction, + minParticlesPerSecond, maxParticlesPerSecond, minStartColor, + maxStartColor, lifeTimeMin, lifeTimeMax, maxAngleDegrees, + minStartSize, maxStartSize ); +} + + +//! Creates a sphere particle emitter. +IParticleSphereEmitter* CParticleSystemSceneNode::createSphereEmitter( + const core::vector3df& center, f32 radius, const core::vector3df& direction, + u32 minParticlesPerSecond, u32 maxParticlesPerSecond, + const video::SColor& minStartColor, const video::SColor& maxStartColor, + u32 lifeTimeMin, u32 lifeTimeMax, + s32 maxAngleDegrees, const core::dimension2df& minStartSize, + const core::dimension2df& maxStartSize ) +{ + return new CParticleSphereEmitter(center, radius, direction, + minParticlesPerSecond, maxParticlesPerSecond, + minStartColor, maxStartColor, + lifeTimeMin, lifeTimeMax, maxAngleDegrees, + minStartSize, maxStartSize ); +} + + +//! Creates a point attraction affector. This affector modifies the positions of the +//! particles and attracts them to a specified point at a specified speed per second. +IParticleAttractionAffector* CParticleSystemSceneNode::createAttractionAffector( + const core::vector3df& point, f32 speed, bool attract, + bool affectX, bool affectY, bool affectZ ) +{ + return new CParticleAttractionAffector( point, speed, attract, affectX, affectY, affectZ ); +} + +//! Creates a scale particle affector. +IParticleAffector* CParticleSystemSceneNode::createScaleParticleAffector(const core::dimension2df& scaleTo) +{ + return new CParticleScaleAffector(scaleTo); +} + + +//! Creates a fade out particle affector. +IParticleFadeOutAffector* CParticleSystemSceneNode::createFadeOutParticleAffector( + const video::SColor& targetColor, u32 timeNeededToFadeOut) +{ + return new CParticleFadeOutAffector(targetColor, timeNeededToFadeOut); +} + + +//! Creates a gravity affector. +IParticleGravityAffector* CParticleSystemSceneNode::createGravityAffector( + const core::vector3df& gravity, u32 timeForceLost) +{ + return new CParticleGravityAffector(gravity, timeForceLost); +} + + +//! Creates a rotation affector. This affector rotates the particles around a specified pivot +//! point. The speed represents Degrees of rotation per second. +IParticleRotationAffector* CParticleSystemSceneNode::createRotationAffector( + const core::vector3df& speed, const core::vector3df& pivotPoint ) +{ + return new CParticleRotationAffector( speed, pivotPoint ); +} + + +//! pre render event +void CParticleSystemSceneNode::OnRegisterSceneNode() +{ + doParticleSystem(os::Timer::getTime()); + + if (IsVisible && (Particles.size() != 0)) + { + SceneManager->registerNodeForRendering(this); + ISceneNode::OnRegisterSceneNode(); + } +} + + +//! render +void CParticleSystemSceneNode::render() +{ + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + ICameraSceneNode* camera = SceneManager->getActiveCamera(); + + if (!camera || !driver) + return; + + +#if 0 + // calculate vectors for letting particles look to camera + core::vector3df view(camera->getTarget() - camera->getAbsolutePosition()); + view.normalize(); + + view *= -1.0f; + +#else + + const core::matrix4 &m = camera->getViewFrustum()->getTransform( video::ETS_VIEW ); + + const core::vector3df view ( -m[2], -m[6] , -m[10] ); + +#endif + + // reallocate arrays, if they are too small + reallocateBuffers(); + + // create particle vertex data + s32 idx = 0; + for (u32 i=0; igetUpVector().crossProduct(view); + horizontal.normalize(); + horizontal *= 0.5f * particle.size.Width; + + core::vector3df vertical = horizontal.crossProduct(view); + vertical.normalize(); + vertical *= 0.5f * particle.size.Height; + + #else + f32 f; + + f = 0.5f * particle.size.Width; + const core::vector3df horizontal ( m[0] * f, m[4] * f, m[8] * f ); + + f = -0.5f * particle.size.Height; + const core::vector3df vertical ( m[1] * f, m[5] * f, m[9] * f ); + #endif + + Buffer->Vertices[0+idx].Pos = particle.pos + horizontal + vertical; + Buffer->Vertices[0+idx].Color = particle.color; + Buffer->Vertices[0+idx].Normal = view; + + Buffer->Vertices[1+idx].Pos = particle.pos + horizontal - vertical; + Buffer->Vertices[1+idx].Color = particle.color; + Buffer->Vertices[1+idx].Normal = view; + + Buffer->Vertices[2+idx].Pos = particle.pos - horizontal - vertical; + Buffer->Vertices[2+idx].Color = particle.color; + Buffer->Vertices[2+idx].Normal = view; + + Buffer->Vertices[3+idx].Pos = particle.pos - horizontal + vertical; + Buffer->Vertices[3+idx].Color = particle.color; + Buffer->Vertices[3+idx].Normal = view; + + idx +=4; + } + + // render all + core::matrix4 mat; + if (!ParticlesAreGlobal) + mat.setTranslation(AbsoluteTransformation.getTranslation()); + driver->setTransform(video::ETS_WORLD, mat); + + driver->setMaterial(Buffer->Material); + + driver->drawVertexPrimitiveList(Buffer->getVertices(), Particles.size()*4, + Buffer->getIndices(), Particles.size()*2, video::EVT_STANDARD, EPT_TRIANGLES,Buffer->getIndexType()); + + // for debug purposes only: + if ( DebugDataVisible & scene::EDS_BBOX ) + { + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + video::SMaterial deb_m; + deb_m.Lighting = false; + driver->setMaterial(deb_m); + driver->draw3DBox(Buffer->BoundingBox, video::SColor(0,255,255,255)); + } +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CParticleSystemSceneNode::getBoundingBox() const +{ + return Buffer->getBoundingBox(); +} + + +void CParticleSystemSceneNode::doParticleSystem(u32 time) +{ + if (LastEmitTime==0) + { + LastEmitTime = time; + LastAbsoluteTransformation = AbsoluteTransformation; + return; + } + + u32 now = time; + u32 timediff = time - LastEmitTime; + LastEmitTime = time; + + + bool visible = isVisible(); + int behavior = getParticleBehavior(); + // run emitter + + if (Emitter && (visible || behavior & EPB_INVISIBLE_EMITTING) ) + { + SParticle* array = 0; + s32 newParticles = Emitter->emitt(now, timediff, array); + + if (newParticles && array) + { + s32 j=Particles.size(); + if (newParticles > 16250-j) // avoid having more than 64k vertices in the scenenode + newParticles=16250-j; + Particles.set_used(j+newParticles); + for (s32 i=j; i::Iterator ait = AffectorList.begin(); + for (; ait != AffectorList.end(); ++ait) + (*ait)->affect(now, Particles.pointer(), Particles.size()); + } + + if (ParticlesAreGlobal) + Buffer->BoundingBox.reset(AbsoluteTransformation.getTranslation()); + else + Buffer->BoundingBox.reset(core::vector3df(0,0,0)); + + // animate all particles + if ( visible || behavior & EPB_INVISIBLE_ANIMATING ) + { + f32 scale = (f32)timediff; + + for (u32 i=0; i Particles[i].endTime) + { + // Particle order does not seem to matter. + // So we can delete by switching with last particle and deleting that one. + // This is a lot faster and speed is very important here as the erase otherwise + // can cause noticable freezes. + Particles[i] = Particles[Particles.size()-1]; + Particles.erase( Particles.size()-1 ); + } + else + { + Particles[i].pos += (Particles[i].vector * scale); + Buffer->BoundingBox.addInternalPoint(Particles[i].pos); + ++i; + } + } + } + + const f32 m = (ParticleSize.Width > ParticleSize.Height ? ParticleSize.Width : ParticleSize.Height) * 0.5f; + Buffer->BoundingBox.MaxEdge.X += m; + Buffer->BoundingBox.MaxEdge.Y += m; + Buffer->BoundingBox.MaxEdge.Z += m; + + Buffer->BoundingBox.MinEdge.X -= m; + Buffer->BoundingBox.MinEdge.Y -= m; + Buffer->BoundingBox.MinEdge.Z -= m; + + if (ParticlesAreGlobal) + { + core::matrix4 absinv( AbsoluteTransformation, core::matrix4::EM4CONST_INVERSE ); + absinv.transformBoxEx(Buffer->BoundingBox); + } + + LastAbsoluteTransformation = AbsoluteTransformation; +} + + +//! Sets if the particles should be global. If it is, the particles are affected by +//! the movement of the particle system scene node too, otherwise they completely +//! ignore it. Default is true. +void CParticleSystemSceneNode::setParticlesAreGlobal(bool global) +{ + ParticlesAreGlobal = global; +} + +//! Remove all currently visible particles +void CParticleSystemSceneNode::clearParticles() +{ + Particles.set_used(0); +} + +//! Sets if the node should be visible or not. +void CParticleSystemSceneNode::setVisible(bool isVisible) +{ + IParticleSystemSceneNode::setVisible(isVisible); + if ( !isVisible && getParticleBehavior() & EPB_CLEAR_ON_INVISIBLE ) + { + clearParticles(); + LastEmitTime = 0; + } +} + +//! Sets the size of all particles. +void CParticleSystemSceneNode::setParticleSize(const core::dimension2d &size) +{ + os::Printer::log("setParticleSize is deprecated, use setMinStartSize/setMaxStartSize in emitter.", irr::ELL_WARNING); + //A bit of a hack, but better here than in the particle code + if (Emitter) + { + Emitter->setMinStartSize(size); + Emitter->setMaxStartSize(size); + } + ParticleSize = size; +} + + +void CParticleSystemSceneNode::reallocateBuffers() +{ + if (Particles.size() * 4 > Buffer->getVertexCount() || + Particles.size() * 6 > Buffer->getIndexCount()) + { + u32 oldSize = Buffer->getVertexCount(); + Buffer->Vertices.set_used(Particles.size() * 4); + + u32 i; + + // fill remaining vertices + for (i=oldSize; iVertices.size(); i+=4) + { + Buffer->Vertices[0+i].TCoords.set(0.0f, 0.0f); + Buffer->Vertices[1+i].TCoords.set(0.0f, 1.0f); + Buffer->Vertices[2+i].TCoords.set(1.0f, 1.0f); + Buffer->Vertices[3+i].TCoords.set(1.0f, 0.0f); + } + + // fill remaining indices + u32 oldIdxSize = Buffer->getIndexCount(); + u32 oldvertices = oldSize; + Buffer->Indices.set_used(Particles.size() * 6); + + for (i=oldIdxSize; iIndices.size(); i+=6) + { + Buffer->Indices[0+i] = (u16)0+oldvertices; + Buffer->Indices[1+i] = (u16)2+oldvertices; + Buffer->Indices[2+i] = (u16)1+oldvertices; + Buffer->Indices[3+i] = (u16)0+oldvertices; + Buffer->Indices[4+i] = (u16)3+oldvertices; + Buffer->Indices[5+i] = (u16)2+oldvertices; + oldvertices += 4; + } + } +} + + +//! Writes attributes of the scene node. +void CParticleSystemSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + IParticleSystemSceneNode::serializeAttributes(out, options); + + out->addBool("GlobalParticles", ParticlesAreGlobal); + out->addFloat("ParticleWidth", ParticleSize.Width); + out->addFloat("ParticleHeight", ParticleSize.Height); + + // write emitter + + E_PARTICLE_EMITTER_TYPE type = EPET_COUNT; + if (Emitter) + type = Emitter->getType(); + + out->addEnum("Emitter", (s32)type, ParticleEmitterTypeNames); + + if (Emitter) + Emitter->serializeAttributes(out, options); + + // write affectors + + E_PARTICLE_AFFECTOR_TYPE atype = EPAT_NONE; + + for (core::list::ConstIterator it = AffectorList.begin(); + it != AffectorList.end(); ++it) + { + atype = (*it)->getType(); + + out->addEnum("Affector", (s32)atype, ParticleAffectorTypeNames); + + (*it)->serializeAttributes(out); + } + + // add empty affector to make it possible to add further affectors + + if (options && options->Flags & io::EARWF_FOR_EDITOR) + out->addEnum("Affector", EPAT_NONE, ParticleAffectorTypeNames); +} + + +//! Reads attributes of the scene node. +void CParticleSystemSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + IParticleSystemSceneNode::deserializeAttributes(in, options); + + ParticlesAreGlobal = in->getAttributeAsBool("GlobalParticles"); + ParticleSize.Width = in->getAttributeAsFloat("ParticleWidth"); + ParticleSize.Height = in->getAttributeAsFloat("ParticleHeight"); + + // read emitter + + int emitterIdx = in->findAttribute("Emitter"); + if (emitterIdx == -1) + return; + + if (Emitter) + Emitter->drop(); + Emitter = 0; + + E_PARTICLE_EMITTER_TYPE type = (E_PARTICLE_EMITTER_TYPE) + in->getAttributeAsEnumeration("Emitter", ParticleEmitterTypeNames); + + switch(type) + { + case EPET_POINT: + Emitter = createPointEmitter(); + break; + case EPET_ANIMATED_MESH: + Emitter = createAnimatedMeshSceneNodeEmitter(NULL); // we can't set the node - the user will have to do this + break; + case EPET_BOX: + Emitter = createBoxEmitter(); + break; + case EPET_CYLINDER: + Emitter = createCylinderEmitter(core::vector3df(0,0,0), 10.f, core::vector3df(0,1,0), 10.f); // (values here don't matter) + break; + case EPET_MESH: + Emitter = createMeshEmitter(NULL); // we can't set the mesh - the user will have to do this + break; + case EPET_RING: + Emitter = createRingEmitter(core::vector3df(0,0,0), 10.f, 10.f); // (values here don't matter) + break; + case EPET_SPHERE: + Emitter = createSphereEmitter(core::vector3df(0,0,0), 10.f); // (values here don't matter) + break; + default: + break; + } + + u32 idx = 0; + +#if 0 + if (Emitter) + idx = Emitter->deserializeAttributes(idx, in); + + ++idx; +#else + if (Emitter) + Emitter->deserializeAttributes(in); +#endif + + // read affectors + + removeAllAffectors(); + u32 cnt = in->getAttributeCount(); + + while(idx < cnt) + { + const char* name = in->getAttributeName(idx); + + if (!name || strcmp("Affector", name)) + return; + + E_PARTICLE_AFFECTOR_TYPE atype = + (E_PARTICLE_AFFECTOR_TYPE)in->getAttributeAsEnumeration(idx, ParticleAffectorTypeNames); + + IParticleAffector* aff = 0; + + switch(atype) + { + case EPAT_ATTRACT: + aff = createAttractionAffector(core::vector3df(0,0,0)); + break; + case EPAT_FADE_OUT: + aff = createFadeOutParticleAffector(); + break; + case EPAT_GRAVITY: + aff = createGravityAffector(); + break; + case EPAT_ROTATE: + aff = createRotationAffector(); + break; + case EPAT_SCALE: + aff = createScaleParticleAffector(); + break; + case EPAT_NONE: + default: + break; + } + + ++idx; + + if (aff) + { +#if 0 + idx = aff->deserializeAttributes(idx, in, options); + ++idx; +#else + aff->deserializeAttributes(in, options); +#endif + + addAffector(aff); + aff->drop(); + } + } +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ diff --git a/source/Irrlicht/CParticleSystemSceneNode.h b/source/Irrlicht/CParticleSystemSceneNode.h new file mode 100644 index 00000000..779f7141 --- /dev/null +++ b/source/Irrlicht/CParticleSystemSceneNode.h @@ -0,0 +1,249 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_PARTICLE_SYSTEM_SCENE_NODE_H_INCLUDED__ +#define __C_PARTICLE_SYSTEM_SCENE_NODE_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + +#include "IParticleSystemSceneNode.h" +#include "irrArray.h" +#include "irrList.h" +#include "SMeshBuffer.h" + +namespace irr +{ +namespace scene +{ + +//! A particle system scene node. +/** A scene node controlling a particle system. The behavior of the particles +can be controlled by setting the right particle emitters and affectors. +*/ +class CParticleSystemSceneNode : public IParticleSystemSceneNode +{ +public: + + //! constructor + CParticleSystemSceneNode(bool createDefaultEmitter, + ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position, + const core::vector3df& rotation, + const core::vector3df& scale); + + //! destructor + virtual ~CParticleSystemSceneNode(); + + //! Gets the particle emitter, which creates the particles. + virtual IParticleEmitter* getEmitter() _IRR_OVERRIDE_; + + //! Sets the particle emitter, which creates the particles. + virtual void setEmitter(IParticleEmitter* emitter) _IRR_OVERRIDE_; + + //! Adds new particle affector to the particle system. + virtual void addAffector(IParticleAffector* affector) _IRR_OVERRIDE_; + + //! Get a list of all particle affectors. + virtual const core::list& getAffectors() const _IRR_OVERRIDE_; + + //! Removes all particle affectors in the particle system. + virtual void removeAllAffectors() _IRR_OVERRIDE_; + + //! Returns the material based on the zero based index i. + virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_; + + //! Returns amount of materials used by this scene node. + virtual u32 getMaterialCount() const _IRR_OVERRIDE_; + + //! pre render event + virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; + + //! render + virtual void render() _IRR_OVERRIDE_; + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + //! Creates a particle emitter for an animated mesh scene node + virtual IParticleAnimatedMeshSceneNodeEmitter* createAnimatedMeshSceneNodeEmitter( + scene::IAnimatedMeshSceneNode* node, bool useNormalDirection = true, + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + f32 normalDirectionModifier = 100.0f, s32 mbNumber = -1, + bool everyMeshVertex = false, u32 minParticlesPerSecond = 5, + u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin = 2000, u32 lifeTimeMax = 4000, + s32 maxAngleDegrees = 0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) ) _IRR_OVERRIDE_; + + //! Creates a box particle emitter. + virtual IParticleBoxEmitter* createBoxEmitter( + const core::aabbox3df& box = core::aabbox3d(-10,0,-10,5,30,10), + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 5, + u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin=2000, u32 lifeTimeMax=4000, + s32 maxAngleDegrees=0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) ) _IRR_OVERRIDE_; + + //! Creates a particle emitter for emitting from a cylinder + virtual IParticleCylinderEmitter* createCylinderEmitter( + const core::vector3df& center, f32 radius, + const core::vector3df& normal, f32 length, + bool outlineOnly = false, const core::vector3df& direction = core::vector3df(0.0f,0.5f,0.0f), + u32 minParticlesPerSecond = 5, u32 maxParticlesPersSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin = 2000, u32 lifeTimeMax = 4000, + s32 maxAngleDegrees = 0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) ) _IRR_OVERRIDE_; + + //! Creates a mesh particle emitter. + virtual IParticleMeshEmitter* createMeshEmitter( + scene::IMesh* mesh, bool useNormalDirection = true, + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + f32 normalDirectionModifier = 100.0f, s32 mbNumber = -1, + bool everyMeshVertex = false, + u32 minParticlesPerSecond = 5, + u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin = 2000, u32 lifeTimeMax = 4000, + s32 maxAngleDegrees = 0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) ) _IRR_OVERRIDE_; + + //! Creates a point particle emitter. + virtual IParticlePointEmitter* createPointEmitter( + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 5, + u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin=2000, u32 lifeTimeMax=4000, + s32 maxAngleDegrees=0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) ) _IRR_OVERRIDE_; + + //! Creates a ring particle emitter. + virtual IParticleRingEmitter* createRingEmitter( + const core::vector3df& center, f32 radius, f32 ringThickness, + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 5, + u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin=2000, u32 lifeTimeMax=4000, + s32 maxAngleDegrees=0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) ) _IRR_OVERRIDE_; + + //! Creates a sphere particle emitter. + virtual IParticleSphereEmitter* createSphereEmitter( + const core::vector3df& center, f32 radius, + const core::vector3df& direction = core::vector3df(0.0f,0.03f,0.0f), + u32 minParticlesPerSecond = 5, + u32 maxParticlesPerSecond = 10, + const video::SColor& minStartColor = video::SColor(255,0,0,0), + const video::SColor& maxStartColor = video::SColor(255,255,255,255), + u32 lifeTimeMin=2000, u32 lifeTimeMax=4000, + s32 maxAngleDegrees=0, + const core::dimension2df& minStartSize = core::dimension2df(5.0f,5.0f), + const core::dimension2df& maxStartSize = core::dimension2df(5.0f,5.0f) ) _IRR_OVERRIDE_; + + //! Creates a point attraction affector. This affector modifies the positions of the + //! particles and attracts them to a specified point at a specified speed per second. + virtual IParticleAttractionAffector* createAttractionAffector( + const core::vector3df& point, f32 speed = 1.0f, bool attract = true, + bool affectX = true, bool affectY = true, bool affectZ = true) _IRR_OVERRIDE_; + + //! Creates a scale particle affector. + virtual IParticleAffector* createScaleParticleAffector( + const core::dimension2df& scaleTo = core::dimension2df(1.0f, 1.0f)) _IRR_OVERRIDE_; + + //! Creates a fade out particle affector. + virtual IParticleFadeOutAffector* createFadeOutParticleAffector( + const video::SColor& targetColor = video::SColor(0,0,0,0), + u32 timeNeededToFadeOut = 1000) _IRR_OVERRIDE_; + + //! Creates a gravity affector. + virtual IParticleGravityAffector* createGravityAffector( + const core::vector3df& gravity = core::vector3df(0.0f,-0.03f,0.0f), + u32 timeForceLost = 1000) _IRR_OVERRIDE_; + + //! Creates a rotation affector. This affector rotates the particles + //! around a specified pivot point. The speed is in Degrees per second. + virtual IParticleRotationAffector* createRotationAffector( + const core::vector3df& speed = core::vector3df(5.0f,5.0f,5.0f), + const core::vector3df& pivotPoint = core::vector3df(0.0f,0.0f,0.0f) ) _IRR_OVERRIDE_; + + //! Sets the size of all particles. + virtual void setParticleSize( + const core::dimension2d &size = core::dimension2d(5.0f, 5.0f)) _IRR_OVERRIDE_; + + //! Sets if the particles should be global. If they are, the particles are affected by + //! the movement of the particle system scene node too, otherwise they completely + //! ignore it. Default is true. + virtual void setParticlesAreGlobal(bool global=true) _IRR_OVERRIDE_; + + //! Remove all currently visible particles + virtual void clearParticles() _IRR_OVERRIDE_; + + //! Sets if the node should be visible or not. + virtual void setVisible(bool isVisible) _IRR_OVERRIDE_; + + //! Do manually update the particles. + //! This should only be called when you want to render the node outside the scenegraph, + //! as the node will care about this otherwise automatically. + virtual void doParticleSystem(u32 time) _IRR_OVERRIDE_; + + //! Writes attributes of the scene node. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_PARTICLE_SYSTEM; } + +private: + + void reallocateBuffers(); + + core::list AffectorList; + IParticleEmitter* Emitter; + core::array Particles; + core::dimension2d ParticleSize; + u32 LastEmitTime; + core::matrix4 LastAbsoluteTransformation; + + SMeshBuffer* Buffer; + +// TODO: That was obviously planned by someone at some point and sounds like a good idea. +// But seems it was never implemented. +// enum E_PARTICLES_PRIMITIVE +// { +// EPP_POINT=0, +// EPP_BILLBOARD, +// EPP_POINTSPRITE +// }; +// E_PARTICLES_PRIMITIVE ParticlePrimitive; + + bool ParticlesAreGlobal; +}; + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_PARTICLES_ + +#endif + diff --git a/source/Irrlicht/CProfiler.cpp b/source/Irrlicht/CProfiler.cpp new file mode 100644 index 00000000..537bea44 --- /dev/null +++ b/source/Irrlicht/CProfiler.cpp @@ -0,0 +1,104 @@ +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +// Written by Michael Zeilfelder + +#include "CProfiler.h" +#include "CTimer.h" + +namespace irr +{ +IRRLICHT_API IProfiler& IRRCALLCONV getProfiler() +{ + static CProfiler profiler; + return profiler; +} + +CProfiler::CProfiler() +{ + Timer = new CTimer(true); + + addGroup(L"overview"); +} + +CProfiler::~CProfiler() +{ + if ( Timer ) + Timer->drop(); +} + +void CProfiler::printAll(core::stringw &ostream, bool includeOverview, bool suppressUncalled) const +{ + ostream += makeTitleString(); + ostream += L"\n"; + for ( u32 i=includeOverview ?0:1; i 0) + { + ostream += getAsString(ProfileGroups[i]); + ostream += L"\n"; + } + } + } + // print all data in a group + else + { + for ( u32 i=0; i 0) + && ProfileDatas[i].getGroupIndex() == idxGroup ) + { + ostream += getAsString(ProfileDatas[i]); + ostream += L"\n"; + } + } + } +} + +//! Convert the whole data into a string +core::stringw CProfiler::getAsString(const SProfileData& data) const +{ + if ( data.getCallsCounter() > 0 ) + { +#ifdef _MSC_VER +#pragma warning(disable:4996) // 'sprintf' was declared deprecated +#endif + // Can't use swprintf as it fails on some platforms (especially mobile platforms) + // Can't use Irrlicht functions because we have no string formatting. + char dummy[1023]; + sprintf(dummy, "%-15.15s%-12u%-12u%-12u%-12u", + core::stringc(data.getName()).c_str(), data.getCallsCounter(), data.getTimeSum(), + data.getTimeSum() / data.getCallsCounter(), data.getLongestTime()); + dummy[1022] = 0; + + return core::stringw(dummy); +#ifdef _MSC_VER +#pragma warning(default :4996) // 'sprintf' was declared deprecated +#endif + } + else + { + return data.getName(); + } +} + +//! Return a string which describes the columns returned by getAsString +core::stringw CProfiler::makeTitleString() const +{ + return core::stringw("name calls time(sum) time(avg) time(max)"); +} + +} // namespace irr diff --git a/source/Irrlicht/CProfiler.h b/source/Irrlicht/CProfiler.h new file mode 100644 index 00000000..d86f9e0a --- /dev/null +++ b/source/Irrlicht/CProfiler.h @@ -0,0 +1,32 @@ +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +// Written by Michael Zeilfelder + +#ifndef __C_PROFILER_H_INCLUDED__ +#define __C_PROFILER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#include "IProfiler.h" + +namespace irr +{ +class CProfiler : public IProfiler +{ +public: + + CProfiler(); + virtual ~CProfiler(); + + //! Write all profile-data into a string + virtual void printAll(core::stringw &result, bool includeOverview,bool suppressUncalled) const _IRR_OVERRIDE_; + + //! Write the profile data of one group into a string + virtual void printGroup(core::stringw &result, u32 groupIndex, bool suppressUncalled) const _IRR_OVERRIDE_; + +protected: + core::stringw makeTitleString() const; + core::stringw getAsString(const SProfileData& data) const; +}; +} // namespace irr + +#endif // __C_PROFILER_H_INCLUDED__ diff --git a/source/Irrlicht/CQ3LevelMesh.cpp b/source/Irrlicht/CQ3LevelMesh.cpp new file mode 100644 index 00000000..b2f9060e --- /dev/null +++ b/source/Irrlicht/CQ3LevelMesh.cpp @@ -0,0 +1,2082 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_BSP_LOADER_ + +#include "CQ3LevelMesh.h" +#include "ISceneManager.h" +#include "os.h" +#include "SMeshBufferLightMap.h" +#include "irrString.h" +#include "ILightSceneNode.h" +#include "IQ3Shader.h" +#include "IFileList.h" + +//#define TJUNCTION_SOLVER_ROUND +//#define TJUNCTION_SOLVER_0125 + +namespace irr +{ +namespace scene +{ + + using namespace quake3; + +//! constructor +CQ3LevelMesh::CQ3LevelMesh(io::IFileSystem* fs, scene::ISceneManager* smgr, + const Q3LevelLoadParameter &loadParam) + : LoadParam(loadParam), Textures(0), NumTextures(0), LightMaps(0), NumLightMaps(0), + Vertices(0), NumVertices(0), Faces(0), NumFaces(0), Models(0), NumModels(0), + Planes(0), NumPlanes(0), Nodes(0), NumNodes(0), Leafs(0), NumLeafs(0), + LeafFaces(0), NumLeafFaces(0), MeshVerts(0), NumMeshVerts(0), + Brushes(0), NumBrushes(0), BrushEntities(0), FileSystem(fs), + SceneManager(smgr), FramesPerSecond(25.f) +{ + #ifdef _DEBUG + IReferenceCounted::setDebugName("CQ3LevelMesh"); + #endif + + for ( s32 i = 0; i!= E_Q3_MESH_SIZE; ++i ) + { + Mesh[i] = 0; + } + + Driver = smgr ? smgr->getVideoDriver() : 0; + if (Driver) + Driver->grab(); + + if (FileSystem) + FileSystem->grab(); + + // load default shaders + InitShader(); +} + + +//! destructor +CQ3LevelMesh::~CQ3LevelMesh() +{ + cleanLoader (); + + if (Driver) + Driver->drop(); + + if (FileSystem) + FileSystem->drop(); + + s32 i; + + for ( i = 0; i!= E_Q3_MESH_SIZE; ++i ) + { + if ( Mesh[i] ) + { + Mesh[i]->drop(); + Mesh[i] = 0; + } + } + + for ( i = 1; i < NumModels; i++ ) + { + BrushEntities[i]->drop(); + } + delete [] BrushEntities; BrushEntities = 0; + + ReleaseShader(); + ReleaseEntity(); +} + + +//! loads a level from a .bsp-File. Also tries to load all needed textures. Returns true if successful. +bool CQ3LevelMesh::loadFile(io::IReadFile* file) +{ + if (!file) + return false; + + LevelName = file->getFileName(); + + file->read(&header, sizeof(tBSPHeader)); + + #ifdef __BIG_ENDIAN__ + header.strID = os::Byteswap::byteswap(header.strID); + header.version = os::Byteswap::byteswap(header.version); + #endif + + if ( (header.strID != 0x50534249 || // IBSP + ( header.version != 0x2e // quake3 + && header.version != 0x2f // rtcw + ) + ) + && + ( header.strID != 0x50534252 || header.version != 1 ) // RBSP, starwars jedi, sof + ) + { + os::Printer::log("Could not load .bsp file, unknown header.", file->getFileName(), ELL_ERROR); + return false; + } + +#if 0 + if ( header.strID == 0x50534252 ) // RBSP Raven + { + LoadParam.swapHeader = 1; + } +#endif + + // now read lumps + file->read(&Lumps[0], sizeof(tBSPLump)*kMaxLumps); + + s32 i; + if ( LoadParam.swapHeader ) + { + for ( i=0; i< kMaxLumps;++i) + { + Lumps[i].offset = os::Byteswap::byteswap(Lumps[i].offset); + Lumps[i].length = os::Byteswap::byteswap(Lumps[i].length); + } + } + + ReleaseEntity(); + + // load everything + loadEntities(&Lumps[kEntities], file); // load the entities + loadTextures(&Lumps[kShaders], file); // Load the textures + loadLightmaps(&Lumps[kLightmaps], file); // Load the lightmaps + loadVerts(&Lumps[kVertices], file); // Load the vertices + loadFaces(&Lumps[kFaces], file); // Load the faces + loadPlanes(&Lumps[kPlanes], file); // Load the Planes of the BSP + loadNodes(&Lumps[kNodes], file); // load the Nodes of the BSP + loadLeafs(&Lumps[kLeafs], file); // load the Leafs of the BSP + loadLeafFaces(&Lumps[kLeafFaces], file); // load the Faces of the Leafs of the BSP + loadVisData(&Lumps[kVisData], file); // load the visibility data of the clusters + loadModels(&Lumps[kModels], file); // load the models + loadMeshVerts(&Lumps[kMeshVerts], file); // load the mesh vertices + loadBrushes(&Lumps[kBrushes], file); // load the brushes of the BSP + loadBrushSides(&Lumps[kBrushSides], file); // load the brushsides of the BSP + loadLeafBrushes(&Lumps[kLeafBrushes], file); // load the brushes of the leaf + loadFogs(&Lumps[kFogs], file ); // load the fogs + + loadTextures(); + constructMesh(); + solveTJunction(); + + cleanMeshes(); + calcBoundingBoxes(); + cleanLoader(); + + return true; +} + +/*! +*/ +void CQ3LevelMesh::cleanLoader () +{ + delete [] Textures; Textures = 0; + delete [] LightMaps; LightMaps = 0; + delete [] Vertices; Vertices = 0; + delete [] Faces; Faces = 0; + delete [] Models; Models = 0; + delete [] Planes; Planes = 0; + delete [] Nodes; Nodes = 0; + delete [] Leafs; Leafs = 0; + delete [] LeafFaces; LeafFaces = 0; + delete [] MeshVerts; MeshVerts = 0; + delete [] Brushes; Brushes = 0; + + Lightmap.clear(); + Tex.clear(); +} + +//! returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh. +u32 CQ3LevelMesh::getFrameCount() const +{ + return 1; +} + + +//! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level. +IMesh* CQ3LevelMesh::getMesh(s32 frameInMs, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) +{ + return Mesh[frameInMs]; +} + + +void CQ3LevelMesh::loadTextures(tBSPLump* l, io::IReadFile* file) +{ + NumTextures = l->length / sizeof(tBSPTexture); + if ( !NumTextures ) + return; + Textures = new tBSPTexture[NumTextures]; + + file->seek(l->offset); + file->read(Textures, l->length); + + if ( LoadParam.swapHeader ) + { + for (s32 i=0;ilength / sizeof(tBSPLightmap); + if ( !NumLightMaps ) + return; + LightMaps = new tBSPLightmap[NumLightMaps]; + + file->seek(l->offset); + file->read(LightMaps, l->length); +} + +/*! +*/ +void CQ3LevelMesh::loadVerts(tBSPLump* l, io::IReadFile* file) +{ + NumVertices = l->length / sizeof(tBSPVertex); + if ( !NumVertices ) + return; + Vertices = new tBSPVertex[NumVertices]; + + file->seek(l->offset); + file->read(Vertices, l->length); + + if ( LoadParam.swapHeader ) + for (s32 i=0;ilength / sizeof(tBSPFace); + if (!NumFaces) + return; + Faces = new tBSPFace[NumFaces]; + + file->seek(l->offset); + file->read(Faces, l->length); + + if ( LoadParam.swapHeader ) + { + for ( s32 i=0;i entity; + entity.set_used( l->length + 2 ); + entity[l->length + 1 ] = 0; + + file->seek(l->offset); + file->read( entity.pointer(), l->length); + + parser_parse( entity.pointer(), l->length, &CQ3LevelMesh::scriptcallback_entity ); +} + + +/*! + load fog brushes +*/ +void CQ3LevelMesh::loadFogs(tBSPLump* l, io::IReadFile* file) +{ + u32 files = l->length / sizeof(tBSPFog); + + file->seek( l->offset ); + tBSPFog fog; + const IShader *shader; + STexShader t; + for ( u32 i = 0; i!= files; ++i ) + { + file->read( &fog, sizeof( fog ) ); + + shader = getShader( fog.shader ); + t.Texture = 0; + t.ShaderID = shader ? shader->ID : -1; + + FogMap.push_back ( t ); + } +} + + +/*! + load models named in bsp +*/ +void CQ3LevelMesh::loadModels(tBSPLump* l, io::IReadFile* file) +{ + NumModels = l->length / sizeof(tBSPModel); + Models = new tBSPModel[NumModels]; + + file->seek( l->offset ); + file->read(Models, l->length); + + if ( LoadParam.swapHeader ) + { + for ( s32 i = 0; i < NumModels; i++) + { + Models[i].min[0] = os::Byteswap::byteswap(Models[i].min[0]); + Models[i].min[1] = os::Byteswap::byteswap(Models[i].min[1]); + Models[i].min[2] = os::Byteswap::byteswap(Models[i].min[2]); + Models[i].max[0] = os::Byteswap::byteswap(Models[i].max[0]); + Models[i].max[1] = os::Byteswap::byteswap(Models[i].max[1]); + Models[i].max[2] = os::Byteswap::byteswap(Models[i].max[2]); + + Models[i].faceIndex = os::Byteswap::byteswap(Models[i].faceIndex); + Models[i].numOfFaces = os::Byteswap::byteswap(Models[i].numOfFaces); + Models[i].brushIndex = os::Byteswap::byteswap(Models[i].brushIndex); + Models[i].numOfBrushes = os::Byteswap::byteswap(Models[i].numOfBrushes); + } + } + + BrushEntities = new SMesh*[NumModels]; +} + +/*! +*/ +void CQ3LevelMesh::loadMeshVerts(tBSPLump* l, io::IReadFile* file) +{ + NumMeshVerts = l->length / sizeof(s32); + if (!NumMeshVerts) + return; + MeshVerts = new s32[NumMeshVerts]; + + file->seek(l->offset); + file->read(MeshVerts, l->length); + + if ( LoadParam.swapHeader ) + { + for (int i=0;i= 'a' && symbol <= 'z' ) || + (symbol >= 'A' && symbol <= 'Z' ) || + (symbol >= '0' && symbol <= '9' ) || + (symbol == '/' || symbol == '_' || symbol == '.' ); +} + +/*! +*/ +void CQ3LevelMesh::parser_nextToken() +{ + u8 symbol; + + Parser.token = ""; + Parser.tokenresult = Q3_TOKEN_UNRESOLVED; + + // skip white space + do + { + if ( Parser.index >= Parser.sourcesize ) + { + Parser.tokenresult = Q3_TOKEN_EOF; + return; + } + + symbol = Parser.source [ Parser.index ]; + Parser.index += 1; + } while ( isQ3WhiteSpace( symbol ) ); + + // first symbol, one symbol + switch ( symbol ) + { + case 0: + Parser.tokenresult = Q3_TOKEN_EOF; + return; + + case '/': + // comment or divide + if ( Parser.index >= Parser.sourcesize ) + { + Parser.tokenresult = Q3_TOKEN_EOF; + return; + } + symbol = Parser.source [ Parser.index ]; + Parser.index += 1; + if ( isQ3WhiteSpace( symbol ) ) + { + Parser.tokenresult = Q3_TOKEN_MATH_DIVIDE; + return; + } + else + if ( symbol == '*' ) + { + // C-style comment in quake? + } + else + if ( symbol == '/' ) + { + // skip to eol + do + { + if ( Parser.index >= Parser.sourcesize ) + { + Parser.tokenresult = Q3_TOKEN_EOF; + return; + } + symbol = Parser.source [ Parser.index ]; + Parser.index += 1; + } while ( symbol != '\n' ); + Parser.tokenresult = Q3_TOKEN_COMMENT; + return; + } + // take /[name] as valid token..?!?!?. mhmm, maybe + break; + + case '\n': + Parser.tokenresult = Q3_TOKEN_EOL; + return; + case '{': + Parser.tokenresult = Q3_TOKEN_START_LIST; + return; + case '}': + Parser.tokenresult = Q3_TOKEN_END_LIST; + return; + + case '"': + // string literal + do + { + if ( Parser.index >= Parser.sourcesize ) + { + Parser.tokenresult = Q3_TOKEN_EOF; + return; + } + symbol = Parser.source [ Parser.index ]; + Parser.index += 1; + if ( symbol != '"' ) + Parser.token.append( symbol ); + } while ( symbol != '"' ); + Parser.tokenresult = Q3_TOKEN_ENTITY; + return; + } + + // user identity + Parser.token.append( symbol ); + + // continue till whitespace + bool validName = true; + do + { + if ( Parser.index >= Parser.sourcesize ) + { + Parser.tokenresult = Q3_TOKEN_EOF; + return; + } + symbol = Parser.source [ Parser.index ]; + + validName = isQ3ValidName( symbol ); + if ( validName ) + { + Parser.token.append( symbol ); + Parser.index += 1; + } + } while ( validName ); + + Parser.tokenresult = Q3_TOKEN_TOKEN; + return; +} + + +/* + parse entity & shader + calls callback on content in {} +*/ +void CQ3LevelMesh::parser_parse( const void * data, const u32 size, CQ3LevelMesh::tParserCallback callback ) +{ + Parser.source = static_cast(data); + Parser.sourcesize = size; + Parser.index = 0; + + SVarGroupList *groupList; + + s32 active; + s32 last; + + SVariable entity ( "" ); + + groupList = new SVarGroupList(); + + groupList->VariableGroup.push_back( SVarGroup() ); + active = last = 0; + + do + { + parser_nextToken(); + + switch ( Parser.tokenresult ) + { + case Q3_TOKEN_START_LIST: + { + //stack = core::min_( stack + 1, 7 ); + + groupList->VariableGroup.push_back( SVarGroup() ); + last = active; + active = groupList->VariableGroup.size() - 1; + entity.clear(); + } break; + + // a unregisterd variable is finished + case Q3_TOKEN_EOL: + { + if ( entity.isValid() ) + { + groupList->VariableGroup[active].Variable.push_back( entity ); + entity.clear(); + } + } break; + + case Q3_TOKEN_TOKEN: + case Q3_TOKEN_ENTITY: + { + Parser.token.make_lower(); + + // store content based on line-delemiter + if ( 0 == entity.isValid() ) + { + entity.name = Parser.token; + entity.content = ""; + + } + else + { + if ( entity.content.size() ) + { + entity.content += " "; + } + entity.content += Parser.token; + } + } break; + + case Q3_TOKEN_END_LIST: + { + //stack = core::max_( stack - 1, 0 ); + + // close tag for first + if ( active == 1 ) + { + (this->*callback)( groupList, Q3_TOKEN_END_LIST ); + + // new group + groupList->drop(); + groupList = new SVarGroupList(); + groupList->VariableGroup.push_back( SVarGroup() ); + last = 0; + } + + active = last; + entity.clear(); + + } break; + + default: + break; + } + + } while ( Parser.tokenresult != Q3_TOKEN_EOF ); + + (this->*callback)( groupList, Q3_TOKEN_EOF ); + + groupList->drop(); +} + + +/* + this loader applies only textures for stage 1 & 2 +*/ +s32 CQ3LevelMesh::setShaderFogMaterial( video::SMaterial &material, const tBSPFace * face ) const +{ + material.MaterialType = video::EMT_SOLID; + material.Wireframe = false; + material.Lighting = false; + material.BackfaceCulling = false; + material.setTexture(0, 0); + material.setTexture(1, 0); + material.setTexture(2, 0); + material.setTexture(3, 0); + material.ZBuffer = video::ECFN_LESSEQUAL; + material.ZWriteEnable = video::EZW_OFF; + material.MaterialTypeParam = 0.f; + + s32 shaderState = -1; + + if ( (u32) face->fogNum < FogMap.size() ) + { + material.setTexture(0, FogMap [ face->fogNum ].Texture); + shaderState = FogMap [ face->fogNum ].ShaderID; + } + + return shaderState; + +} +/* + this loader applies only textures for stage 1 & 2 +*/ +s32 CQ3LevelMesh::setShaderMaterial( video::SMaterial &material, const tBSPFace * face ) const +{ + material.MaterialType = video::EMT_SOLID; + material.Wireframe = false; + material.Lighting = false; + material.BackfaceCulling = true; + material.setTexture(0, 0); + material.setTexture(1, 0); + material.setTexture(2, 0); + material.setTexture(3, 0); + material.ZBuffer = video::ECFN_LESSEQUAL; + material.ZWriteEnable = video::EZW_AUTO; + material.MaterialTypeParam = 0.f; + + s32 shaderState = -1; + + if ( face->textureID >= 0 && face->textureID < (s32)Tex.size() ) + { + material.setTexture(0, Tex [ face->textureID ].Texture); + shaderState = Tex [ face->textureID ].ShaderID; + } + + if ( face->lightmapID >= 0 && face->lightmapID < (s32)Lightmap.size() ) + { + material.setTexture(1, Lightmap [ face->lightmapID ]); + material.MaterialType = LoadParam.defaultLightMapMaterial; + } + + // store shader ID + material.MaterialTypeParam2 = (f32) shaderState; + + const IShader *shader = getShader(shaderState); + if ( 0 == shader ) + return shaderState; + + return shaderState; + +#if 0 + const SVarGroup *group; + + + // generic + group = shader->getGroup( 1 ); + if ( group ) + { + material.BackfaceCulling = getCullingFunction( group->get( "cull" ) ); + + if ( group->isDefined( "surfaceparm", "nolightmap" ) ) + { + material.MaterialType = video::EMT_SOLID; + material.setTexture(1, 0); + } + + } + + // try to get the best of the 8 texture stages.. + + // texture 1, texture 2 + u32 startPos; + for ( s32 g = 2; g <= 3; ++g ) + { + group = shader->getGroup( g ); + if ( 0 == group ) + continue; + + startPos = 0; + + if ( group->isDefined( "depthwrite" ) ) + { + material.ZWriteEnable = video::EZW_ON; + } + + SBlendFunc blendfunc ( LoadParam.defaultModulate ); + getBlendFunc( group->get( "blendfunc" ), blendfunc ); + getBlendFunc( group->get( "alphafunc" ), blendfunc ); + + if ( 0 == LoadParam.alpharef && + ( blendfunc.type == video::EMT_TRANSPARENT_ALPHA_CHANNEL || + blendfunc.type == video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF + ) + ) + { + blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + blendfunc.param0 = 0.f; + } + + material.MaterialType = blendfunc.type; + material.MaterialTypeParam = blendfunc.param0; + + // try if we can match better + shaderState |= (material.MaterialType == video::EMT_SOLID ) ? 0x00020000 : 0; + } + + //material.BackfaceCulling = false; + + if ( shader->VarGroup->VariableGroup.size() <= 4 ) + { + shaderState |= 0x00010000; + } + + material.MaterialTypeParam2 = (f32) shaderState; + return shaderState; +#endif +} + +/*! + Internal function to build a mesh. +*/ +scene::SMesh** CQ3LevelMesh::buildMesh(s32 num) +{ + scene::SMesh** newmesh = new SMesh *[quake3::E_Q3_MESH_SIZE]; + + s32 i, j, k,s; + + for (i = 0; i < E_Q3_MESH_SIZE; i++) + { + newmesh[i] = new SMesh(); + } + + s32 *index; + + video::S3DVertex2TCoords temp[3]; + video::SMaterial material; + video::SMaterial material2; + + SToBuffer item [ E_Q3_MESH_SIZE ]; + u32 itemSize; + + for (i = Models[num].faceIndex; i < Models[num].numOfFaces + Models[num].faceIndex; ++i) + { + const tBSPFace * face = Faces + i; + + s32 shaderState = setShaderMaterial( material, face ); + itemSize = 0; + + const IShader *shader = getShader(shaderState); + + if ( face->fogNum >= 0 ) + { + setShaderFogMaterial ( material2, face ); + item[itemSize].index = E_Q3_MESH_FOG; + item[itemSize].takeVertexColor = 1; + itemSize += 1; + } + + switch( face->type ) + { + case 1: // normal polygons + case 2: // patches + case 3: // meshes + if ( 0 == shader ) + { + if ( LoadParam.cleanUnResolvedMeshes || material.getTexture(0) ) + { + item[itemSize].takeVertexColor = 1; + item[itemSize].index = E_Q3_MESH_GEOMETRY; + itemSize += 1; + } + else + { + item[itemSize].takeVertexColor = 1; + item[itemSize].index = E_Q3_MESH_UNRESOLVED; + itemSize += 1; + } + } + else + { + item[itemSize].takeVertexColor = 1; + item[itemSize].index = E_Q3_MESH_ITEMS; + itemSize += 1; + } + break; + + case 4: // billboards + //item[itemSize].takeVertexColor = 1; + //item[itemSize].index = E_Q3_MESH_ITEMS; + //itemSize += 1; + break; + + } + + for ( u32 g = 0; g != itemSize; ++g ) + { + scene::SMeshBufferLightMap* buffer = 0; + + if ( item[g].index == E_Q3_MESH_GEOMETRY ) + { + if ( 0 == item[g].takeVertexColor ) + { + item[g].takeVertexColor = material.getTexture(0) == 0 || material.getTexture(1) == 0; + } + + if (Faces[i].lightmapID < -1 || Faces[i].lightmapID > NumLightMaps-1) + { + Faces[i].lightmapID = -1; + } + +#if 0 + // there are lightmapsids and textureid with -1 + const s32 tmp_index = ((Faces[i].lightmapID+1) * (NumTextures+1)) + (Faces[i].textureID+1); + buffer = (SMeshBufferLightMap*) newmesh[E_Q3_MESH_GEOMETRY]->getMeshBuffer(tmp_index); + buffer->setHardwareMappingHint ( EHM_STATIC ); + buffer->getMaterial() = material; +#endif + } + + // Construct a unique mesh for each shader or combine meshbuffers for same shader + if ( 0 == buffer ) + { + + if ( LoadParam.mergeShaderBuffer == 1 ) + { + // combine + buffer = (SMeshBufferLightMap*) newmesh[ item[g].index ]->getMeshBuffer( + item[g].index != E_Q3_MESH_FOG ? material : material2 ); + } + + // create a seperate mesh buffer + if ( 0 == buffer ) + { + buffer = new scene::SMeshBufferLightMap(); + newmesh[ item[g].index ]->addMeshBuffer( buffer ); + buffer->drop(); + buffer->getMaterial() = item[g].index != E_Q3_MESH_FOG ? material : material2; + if ( item[g].index == E_Q3_MESH_GEOMETRY ) + buffer->setHardwareMappingHint ( EHM_STATIC ); + } + } + + + switch(Faces[i].type) + { + case 4: // billboards + break; + case 2: // patches + createCurvedSurface_bezier( buffer, i, + LoadParam.patchTesselation, + item[g].takeVertexColor + ); + break; + + case 1: // normal polygons + case 3: // mesh vertices + index = MeshVerts + face->meshVertIndex; + k = buffer->getVertexCount(); + + // reallocate better if many small meshes are used + s = buffer->getIndexCount()+face->numMeshVerts; + if ( buffer->Indices.allocated_size () < (u32) s ) + { + if ( buffer->Indices.allocated_size () > 0 && + face->numMeshVerts < 20 && NumFaces > 1000 + ) + { + s = buffer->getIndexCount() + (NumFaces >> 3 * face->numMeshVerts ); + } + buffer->Indices.reallocate( s); + } + + for ( j = 0; j < face->numMeshVerts; ++j ) + { + buffer->Indices.push_back( k + index [j] ); + } + + s = k+face->numOfVerts; + if ( buffer->Vertices.allocated_size () < (u32) s ) + { + if ( buffer->Indices.allocated_size () > 0 && + face->numOfVerts < 20 && NumFaces > 1000 + ) + { + s = buffer->getIndexCount() + (NumFaces >> 3 * face->numOfVerts ); + } + buffer->Vertices.reallocate( s); + } + for ( j = 0; j != face->numOfVerts; ++j ) + { + copy( &temp[0], &Vertices[ j + face->vertexIndex ], item[g].takeVertexColor ); + buffer->Vertices.push_back( temp[0] ); + } + break; + + } // end switch + } + } + + return newmesh; +} + +/*! +*/ +void CQ3LevelMesh::solveTJunction() +{ +} + +/*! + constructs a mesh from the quake 3 level file. +*/ +void CQ3LevelMesh::constructMesh() +{ + if ( LoadParam.verbose > 0 ) + { + LoadParam.startTime = os::Timer::getRealTime(); + + if ( LoadParam.verbose > 1 ) + { + snprintf_irr( buf, sizeof ( buf ), + "quake3::constructMesh start to create %d faces, %d vertices,%d mesh vertices", + NumFaces, + NumVertices, + NumMeshVerts + ); + os::Printer::log(buf, ELL_INFORMATION); + } + + } + + s32 i, j; + + // First the main level + SMesh **tmp = buildMesh(0); + + for (i = 0; i < E_Q3_MESH_SIZE; i++) + { + Mesh[i] = tmp[i]; + } + delete [] tmp; + + // Then the brush entities + + for (i = 1; i < NumModels; i++) + { + tmp = buildMesh(i); + BrushEntities[i] = tmp[0]; + + // We only care about the main geometry here + for (j = 1; j < E_Q3_MESH_SIZE; j++) + { + tmp[j]->drop(); + } + delete [] tmp; + } + + if ( LoadParam.verbose > 0 ) + { + LoadParam.endTime = os::Timer::getRealTime(); + + snprintf_irr( buf, sizeof ( buf ), + "quake3::constructMesh needed %04u ms to create %d faces, %d vertices,%d mesh vertices", + LoadParam.endTime - LoadParam.startTime, + NumFaces, + NumVertices, + NumMeshVerts + ); + os::Printer::log(buf, ELL_INFORMATION); + } + +} + + +void CQ3LevelMesh::S3DVertex2TCoords_64::copy( video::S3DVertex2TCoords &dest ) const +{ +#if defined (TJUNCTION_SOLVER_ROUND) + dest.Pos.X = core::round_( (f32) Pos.X ); + dest.Pos.Y = core::round_( (f32) Pos.Y ); + dest.Pos.Z = core::round_( (f32) Pos.Z ); +#elif defined (TJUNCTION_SOLVER_0125) + dest.Pos.X = (f32) ( floor ( Pos.X * 8.f + 0.5 ) * 0.125 ); + dest.Pos.Y = (f32) ( floor ( Pos.Y * 8.f + 0.5 ) * 0.125 ); + dest.Pos.Z = (f32) ( floor ( Pos.Z * 8.f + 0.5 ) * 0.125 ); +#else + dest.Pos.X = (f32) Pos.X; + dest.Pos.Y = (f32) Pos.Y; + dest.Pos.Z = (f32) Pos.Z; +#endif + + dest.Normal.X = (f32) Normal.X; + dest.Normal.Y = (f32) Normal.Y; + dest.Normal.Z = (f32) Normal.Z; + dest.Normal.normalize(); + + dest.Color = Color.toSColor(); + + dest.TCoords.X = (f32) TCoords.X; + dest.TCoords.Y = (f32) TCoords.Y; + + dest.TCoords2.X = (f32) TCoords2.X; + dest.TCoords2.Y = (f32) TCoords2.Y; +} + + +void CQ3LevelMesh::copy( S3DVertex2TCoords_64 * dest, const tBSPVertex * source, s32 vertexcolor ) const +{ +#if defined (TJUNCTION_SOLVER_ROUND) + dest->Pos.X = core::round_( source->vPosition[0] ); + dest->Pos.Y = core::round_( source->vPosition[2] ); + dest->Pos.Z = core::round_( source->vPosition[1] ); +#elif defined (TJUNCTION_SOLVER_0125) + dest->Pos.X = (f32) ( floor ( source->vPosition[0] * 8.f + 0.5 ) * 0.125 ); + dest->Pos.Y = (f32) ( floor ( source->vPosition[2] * 8.f + 0.5 ) * 0.125 ); + dest->Pos.Z = (f32) ( floor ( source->vPosition[1] * 8.f + 0.5 ) * 0.125 ); +#else + dest->Pos.X = source->vPosition[0]; + dest->Pos.Y = source->vPosition[2]; + dest->Pos.Z = source->vPosition[1]; +#endif + + dest->Normal.X = source->vNormal[0]; + dest->Normal.Y = source->vNormal[2]; + dest->Normal.Z = source->vNormal[1]; + dest->Normal.normalize(); + + dest->TCoords.X = source->vTextureCoord[0]; + dest->TCoords.Y = source->vTextureCoord[1]; + dest->TCoords2.X = source->vLightmapCoord[0]; + dest->TCoords2.Y = source->vLightmapCoord[1]; + + if ( vertexcolor ) + { + //u32 a = core::s32_min( source->color[3] * LoadParam.defaultModulate, 255 ); + u32 a = source->color[3]; + u32 r = core::s32_min( source->color[0] * LoadParam.defaultModulate, 255 ); + u32 g = core::s32_min( source->color[1] * LoadParam.defaultModulate, 255 ); + u32 b = core::s32_min( source->color[2] * LoadParam.defaultModulate, 255 ); + + dest->Color.set(a * 1.f/255.f, r * 1.f/255.f, + g * 1.f/255.f, b * 1.f/255.f); + } + else + { + dest->Color.set( 1.f, 1.f, 1.f, 1.f ); + } +} + + +inline void CQ3LevelMesh::copy( video::S3DVertex2TCoords * dest, const tBSPVertex * source, s32 vertexcolor ) const +{ +#if defined (TJUNCTION_SOLVER_ROUND) + dest->Pos.X = core::round_( source->vPosition[0] ); + dest->Pos.Y = core::round_( source->vPosition[2] ); + dest->Pos.Z = core::round_( source->vPosition[1] ); +#elif defined (TJUNCTION_SOLVER_0125) + dest->Pos.X = (f32) ( floor ( source->vPosition[0] * 8.f + 0.5 ) * 0.125 ); + dest->Pos.Y = (f32) ( floor ( source->vPosition[2] * 8.f + 0.5 ) * 0.125 ); + dest->Pos.Z = (f32) ( floor ( source->vPosition[1] * 8.f + 0.5 ) * 0.125 ); +#else + dest->Pos.X = source->vPosition[0]; + dest->Pos.Y = source->vPosition[2]; + dest->Pos.Z = source->vPosition[1]; +#endif + + dest->Normal.X = source->vNormal[0]; + dest->Normal.Y = source->vNormal[2]; + dest->Normal.Z = source->vNormal[1]; + dest->Normal.normalize(); + + dest->TCoords.X = source->vTextureCoord[0]; + dest->TCoords.Y = source->vTextureCoord[1]; + dest->TCoords2.X = source->vLightmapCoord[0]; + dest->TCoords2.Y = source->vLightmapCoord[1]; + + if ( vertexcolor ) + { + //u32 a = core::s32_min( source->color[3] * LoadParam.defaultModulate, 255 ); + u32 a = source->color[3]; + u32 r = core::s32_min( source->color[0] * LoadParam.defaultModulate, 255 ); + u32 g = core::s32_min( source->color[1] * LoadParam.defaultModulate, 255 ); + u32 b = core::s32_min( source->color[2] * LoadParam.defaultModulate, 255 ); + + dest->Color.set(a << 24 | r << 16 | g << 8 | b); + } + else + { + dest->Color.set(0xFFFFFFFF); + } +} + + +void CQ3LevelMesh::SBezier::tesselate( s32 level ) +{ + //Calculate how many vertices across/down there are + s32 j, k; + + column[0].set_used( level + 1 ); + column[1].set_used( level + 1 ); + column[2].set_used( level + 1 ); + + const f64 w = 0.0 + (1.0 / (f64) level ); + + //Tesselate along the columns + for( j = 0; j <= level; ++j) + { + const f64 f = w * (f64) j; + + column[0][j] = control[0].getInterpolated_quadratic(control[3], control[6], f ); + column[1][j] = control[1].getInterpolated_quadratic(control[4], control[7], f ); + column[2][j] = control[2].getInterpolated_quadratic(control[5], control[8], f ); + } + + const u32 idx = Patch->Vertices.size(); + Patch->Vertices.reallocate(idx+level*level); + //Tesselate across the rows to get final vertices + video::S3DVertex2TCoords v; + S3DVertex2TCoords_64 f; + for( j = 0; j <= level; ++j) + { + for( k = 0; k <= level; ++k) + { + f = column[0][j].getInterpolated_quadratic(column[1][j], column[2][j], w * (f64) k); + f.copy( v ); + Patch->Vertices.push_back( v ); + } + } + + Patch->Indices.reallocate(Patch->Indices.size()+6*level*level); + // connect + for( j = 0; j < level; ++j) + { + for( k = 0; k < level; ++k) + { + const s32 inx = idx + ( k * ( level + 1 ) ) + j; + + Patch->Indices.push_back( inx + 0 ); + Patch->Indices.push_back( inx + (level + 1 ) + 0 ); + Patch->Indices.push_back( inx + (level + 1 ) + 1 ); + + Patch->Indices.push_back( inx + 0 ); + Patch->Indices.push_back( inx + (level + 1 ) + 1 ); + Patch->Indices.push_back( inx + 1 ); + } + } +} + + +/*! + no subdivision +*/ +void CQ3LevelMesh::createCurvedSurface_nosubdivision(SMeshBufferLightMap* meshBuffer, + s32 faceIndex, + s32 patchTesselation, + s32 storevertexcolor) +{ + tBSPFace * face = &Faces[faceIndex]; + u32 j,k,m; + + // number of control points across & up + const u32 controlWidth = face->size[0]; + const u32 controlHeight = face->size[1]; + if ( 0 == controlWidth || 0 == controlHeight ) + return; + + video::S3DVertex2TCoords v; + + m = meshBuffer->Vertices.size(); + meshBuffer->Vertices.reallocate(m+controlHeight * controlWidth); + for ( j = 0; j!= controlHeight * controlWidth; ++j ) + { + copy( &v, &Vertices [ face->vertexIndex + j ], storevertexcolor ); + meshBuffer->Vertices.push_back( v ); + } + + meshBuffer->Indices.reallocate(meshBuffer->Indices.size()+6*(controlHeight-1) * (controlWidth-1)); + for ( j = 0; j!= controlHeight - 1; ++j ) + { + for ( k = 0; k!= controlWidth - 1; ++k ) + { + meshBuffer->Indices.push_back( m + k + 0 ); + meshBuffer->Indices.push_back( m + k + controlWidth + 0 ); + meshBuffer->Indices.push_back( m + k + controlWidth + 1 ); + + meshBuffer->Indices.push_back( m + k + 0 ); + meshBuffer->Indices.push_back( m + k + controlWidth + 1 ); + meshBuffer->Indices.push_back( m + k + 1 ); + } + m += controlWidth; + } +} + + +/*! +*/ +void CQ3LevelMesh::createCurvedSurface_bezier(SMeshBufferLightMap* meshBuffer, + s32 faceIndex, + s32 patchTesselation, + s32 storevertexcolor) +{ + + tBSPFace * face = &Faces[faceIndex]; + u32 j,k; + + // number of control points across & up + const u32 controlWidth = face->size[0]; + const u32 controlHeight = face->size[1]; + + if ( 0 == controlWidth || 0 == controlHeight ) + return; + + // number of biquadratic patches + const u32 biquadWidth = (controlWidth - 1)/2; + const u32 biquadHeight = (controlHeight -1)/2; + + if ( LoadParam.verbose > 1 ) + { + LoadParam.startTime = os::Timer::getRealTime(); + } + + // Create space for a temporary array of the patch's control points + core::array controlPoint; + controlPoint.set_used( controlWidth * controlHeight ); + + for( j = 0; j < controlPoint.size(); ++j) + { + copy( &controlPoint[j], &Vertices [ face->vertexIndex + j ], storevertexcolor ); + } + + // create a temporary patch + Bezier.Patch = new scene::SMeshBufferLightMap(); + + //Loop through the biquadratic patches + for( j = 0; j < biquadHeight; ++j) + { + for( k = 0; k < biquadWidth; ++k) + { + // set up this patch + const s32 inx = j*controlWidth*2 + k*2; + + // setup bezier control points for this patch + Bezier.control[0] = controlPoint[ inx + 0]; + Bezier.control[1] = controlPoint[ inx + 1]; + Bezier.control[2] = controlPoint[ inx + 2]; + Bezier.control[3] = controlPoint[ inx + controlWidth + 0 ]; + Bezier.control[4] = controlPoint[ inx + controlWidth + 1 ]; + Bezier.control[5] = controlPoint[ inx + controlWidth + 2 ]; + Bezier.control[6] = controlPoint[ inx + controlWidth * 2 + 0]; + Bezier.control[7] = controlPoint[ inx + controlWidth * 2 + 1]; + Bezier.control[8] = controlPoint[ inx + controlWidth * 2 + 2]; + + Bezier.tesselate( patchTesselation ); + } + } + + // stitch together with existing geometry + // TODO: only border needs to be checked + const u32 bsize = Bezier.Patch->getVertexCount(); + const u32 msize = meshBuffer->getVertexCount(); +/* + for ( j = 0; j!= bsize; ++j ) + { + const core::vector3df &v = Bezier.Patch->Vertices[j].Pos; + + for ( k = 0; k!= msize; ++k ) + { + const core::vector3df &m = meshBuffer->Vertices[k].Pos; + + if ( !v.equals( m, tolerance ) ) + continue; + + meshBuffer->Vertices[k].Pos = v; + //Bezier.Patch->Vertices[j].Pos = m; + } + } +*/ + + // add Patch to meshbuffer + meshBuffer->Vertices.reallocate(msize+bsize); + for ( j = 0; j!= bsize; ++j ) + { + meshBuffer->Vertices.push_back( Bezier.Patch->Vertices[j] ); + } + + // add indices to meshbuffer + meshBuffer->Indices.reallocate(meshBuffer->getIndexCount()+Bezier.Patch->getIndexCount()); + for ( j = 0; j!= Bezier.Patch->getIndexCount(); ++j ) + { + meshBuffer->Indices.push_back( msize + Bezier.Patch->Indices[j] ); + } + + delete Bezier.Patch; + + if ( LoadParam.verbose > 1 ) + { + LoadParam.endTime = os::Timer::getRealTime(); + + snprintf_irr( buf, sizeof ( buf ), + "quake3::createCurvedSurface_bezier needed %04u ms to create bezier patch.(%ux%u)", + LoadParam.endTime - LoadParam.startTime, + biquadWidth, + biquadHeight + ); + os::Printer::log(buf, ELL_INFORMATION); + } + +} + + + +/*! + Loads entities from file +*/ +void CQ3LevelMesh::getConfiguration( io::IReadFile* file ) +{ + tBSPLump l; + l.offset = file->getPos(); + l.length = file->getSize (); + + core::array entity; + entity.set_used( l.length + 2 ); + entity[l.length + 1 ] = 0; + + file->seek(l.offset); + file->read( entity.pointer(), l.length); + + parser_parse( entity.pointer(), l.length, &CQ3LevelMesh::scriptcallback_config ); + + if ( Entity.size () ) + Entity.getLast().name = file->getFileName(); +} + + +//! get's an interface to the entities +tQ3EntityList & CQ3LevelMesh::getEntityList() +{ +// Entity.sort(); + return Entity; +} + +//! returns the requested brush entity +IMesh* CQ3LevelMesh::getBrushEntityMesh(s32 num) const +{ + if (num < 1 || num >= NumModels) + return 0; + + return BrushEntities[num]; +} + +//! returns the requested brush entity +IMesh* CQ3LevelMesh::getBrushEntityMesh(quake3::IEntity &ent) const +{ + // This is a helper function to parse the entity, + // so you don't have to. + + s32 num; + + const quake3::SVarGroup* group = ent.getGroup(1); + const core::stringc& modnum = group->get("model"); + + if (!group->isDefined("model")) + return 0; + + const char *temp = modnum.c_str() + 1; // We skip the first character. + num = core::strtol10(temp); + + return getBrushEntityMesh(num); +} + + +/*! +*/ +const IShader * CQ3LevelMesh::getShader(u32 index) const +{ + index &= 0xFFFF; + + if ( index < Shader.size() ) + { + return &Shader[index]; + } + + return 0; +} + + +/*! + loads the shader definition +*/ +const IShader* CQ3LevelMesh::getShader( const c8 * filename, bool fileNameIsValid ) +{ + core::stringc searchName ( filename ); + + IShader search; + search.name = searchName; + search.name.replace( '\\', '/' ); + search.name.make_lower(); + + + core::stringc message; + s32 index; + + //! is Shader already in cache? + index = Shader.linear_search( search ); + if ( index >= 0 ) + { + if ( LoadParam.verbose > 1 ) + { + message = searchName + " found " + Shader[index].name; + os::Printer::log("quake3:getShader", message.c_str(), ELL_INFORMATION); + } + + return &Shader[index]; + } + + io::path loadFile; + + if ( !fileNameIsValid ) + { + // extract the shader name from the last path component in filename + // "scripts/[name].shader" + core::stringc cut( search.name ); + + s32 end = cut.findLast( '/' ); + s32 start = cut.findLast( '/', end - 1 ); + + loadFile = LoadParam.scriptDir; + loadFile.append( cut.subString( start, end - start ) ); + loadFile.append( ".shader" ); + } + else + { + loadFile = search.name; + } + + // already loaded the file ? + index = ShaderFile.binary_search( loadFile ); + if ( index >= 0 ) + return 0; + + // add file to loaded files + ShaderFile.push_back( loadFile ); + + if ( !FileSystem->existFile( loadFile.c_str() ) ) + { + if ( LoadParam.verbose > 1 ) + { + message = loadFile + " for " + searchName + " failed "; + os::Printer::log("quake3:getShader", message.c_str(), ELL_INFORMATION); + } + return 0; + } + + if ( LoadParam.verbose ) + { + message = loadFile + " for " + searchName; + os::Printer::log("quake3:getShader Load shader", message.c_str(), ELL_INFORMATION); + } + + + io::IReadFile *file = FileSystem->createAndOpenFile( loadFile.c_str() ); + if ( file ) + { + getShader ( file ); + file->drop (); + } + + + // search again + index = Shader.linear_search( search ); + return index >= 0 ? &Shader[index] : 0; +} + +/*! + loads the shader definition +*/ +void CQ3LevelMesh::getShader( io::IReadFile* file ) +{ + if ( 0 == file ) + return; + + // load script + core::array script; + const long len = file->getSize(); + + script.set_used( len + 2 ); + + file->seek( 0 ); + file->read( script.pointer(), len ); + script[ len + 1 ] = 0; + + // start a parser instance + parser_parse( script.pointer(), len, &CQ3LevelMesh::scriptcallback_shader ); +} + + +//! adding default shaders +void CQ3LevelMesh::InitShader() +{ + ReleaseShader(); + + IShader element; + + SVarGroup group; + SVariable variable ( "noshader" ); + + group.Variable.push_back( variable ); + + element.VarGroup = new SVarGroupList(); + element.VarGroup->VariableGroup.push_back( group ); + element.VarGroup->VariableGroup.push_back( SVarGroup() ); + element.name = element.VarGroup->VariableGroup[0].Variable[0].name; + element.ID = Shader.size(); + Shader.push_back( element ); + + if ( LoadParam.loadAllShaders ) + { + io::EFileSystemType current = FileSystem->setFileListSystem ( io::FILESYSTEM_VIRTUAL ); + io::path save = FileSystem->getWorkingDirectory(); + + io::path newDir; + newDir = "/"; + newDir += LoadParam.scriptDir; + newDir += "/"; + FileSystem->changeWorkingDirectoryTo ( newDir.c_str() ); + + core::stringc s; + io::IFileList *fileList = FileSystem->createFileList (); + for (u32 i=0; i< fileList->getFileCount(); ++i) + { + s = fileList->getFullFileName(i); + if ( s.find ( ".shader" ) >= 0 ) + { + if ( 0 == LoadParam.loadSkyShader && s.find ( "sky.shader" ) >= 0 ) + { + } + else + { + getShader ( s.c_str () ); + } + } + } + fileList->drop (); + + FileSystem->changeWorkingDirectoryTo ( save ); + FileSystem->setFileListSystem ( current ); + } +} + + +//! script callback for shaders +//! i'm having troubles with the reference counting, during callback.. resorting.. +void CQ3LevelMesh::ReleaseShader() +{ + for ( u32 i = 0; i!= Shader.size(); ++i ) + { + Shader[i].VarGroup->drop(); + } + Shader.clear(); + ShaderFile.clear(); +} + + +/*! +*/ +void CQ3LevelMesh::ReleaseEntity() +{ + for ( u32 i = 0; i!= Entity.size(); ++i ) + { + Entity[i].VarGroup->drop(); + } + Entity.clear(); +} + + +// config in simple (quake3) and advanced style +void CQ3LevelMesh::scriptcallback_config( SVarGroupList *& grouplist, eToken token ) +{ + IShader element; + + if ( token == Q3_TOKEN_END_LIST ) + { + if ( 0 == grouplist->VariableGroup[0].Variable.size() ) + return; + + element.name = grouplist->VariableGroup[0].Variable[0].name; + } + else + { + if ( grouplist->VariableGroup.size() != 2 ) + return; + + element.name = "configuration"; + } + + grouplist->grab(); + element.VarGroup = grouplist; + element.ID = Entity.size(); + Entity.push_back( element ); +} + + +// entity only has only one valid level.. and no assoziative name.. +void CQ3LevelMesh::scriptcallback_entity( SVarGroupList *& grouplist, eToken token ) +{ + if ( token != Q3_TOKEN_END_LIST || grouplist->VariableGroup.size() != 2 ) + return; + + grouplist->grab(); + + IEntity element; + element.VarGroup = grouplist; + element.ID = Entity.size(); + element.name = grouplist->VariableGroup[1].get( "classname" ); + + + Entity.push_back( element ); +} + + +//!. script callback for shaders +void CQ3LevelMesh::scriptcallback_shader( SVarGroupList *& grouplist,eToken token ) +{ + if ( token != Q3_TOKEN_END_LIST || grouplist->VariableGroup[0].Variable.size()==0) + return; + + + IShader element; + + grouplist->grab(); + element.VarGroup = grouplist; + element.name = element.VarGroup->VariableGroup[0].Variable[0].name; + element.ID = Shader.size(); +/* + core::stringc s; + dumpShader ( s, &element ); + printf ( s.c_str () ); +*/ + Shader.push_back( element ); +} + + +/*! + delete all buffers without geometry in it. +*/ +void CQ3LevelMesh::cleanMeshes() +{ + if ( 0 == LoadParam.cleanUnResolvedMeshes ) + return; + + s32 i; + + // First the main level + for (i = 0; i < E_Q3_MESH_SIZE; i++) + { + bool texture0important = ( i == 0 ); + + cleanMesh(Mesh[i], texture0important); + } + + // Then the brush entities + for (i = 1; i < NumModels; i++) + { + cleanMesh(BrushEntities[i], true); + } +} + +void CQ3LevelMesh::cleanMesh(SMesh *m, const bool texture0important) +{ + // delete all buffers without geometry in it. + u32 run = 0; + u32 remove = 0; + + IMeshBuffer *b; + + run = 0; + remove = 0; + + if ( LoadParam.verbose > 0 ) + { + LoadParam.startTime = os::Timer::getRealTime(); + if ( LoadParam.verbose > 1 ) + { + snprintf_irr( buf, sizeof ( buf ), + "quake3::cleanMeshes start for %u meshes", + m->MeshBuffers.size() + ); + os::Printer::log(buf, ELL_INFORMATION); + } + } + + u32 i = 0; + s32 blockstart = -1; + s32 blockcount = 0; + + while( i < m->MeshBuffers.size()) + { + run += 1; + + b = m->MeshBuffers[i]; + + if ( b->getVertexCount() == 0 || b->getIndexCount() == 0 || + ( texture0important && b->getMaterial().getTexture(0) == 0 ) + ) + { + if ( blockstart < 0 ) + { + blockstart = i; + blockcount = 0; + } + blockcount += 1; + i += 1; + + // delete Meshbuffer + i -= 1; + remove += 1; + b->drop(); + m->MeshBuffers.erase(i); + } + else + { + // clean blockwise + if ( blockstart >= 0 ) + { + if ( LoadParam.verbose > 1 ) + { + snprintf_irr( buf, sizeof ( buf ), + "quake3::cleanMeshes cleaning mesh %d %d size", + blockstart, + blockcount + ); + os::Printer::log(buf, ELL_INFORMATION); + } + blockstart = -1; + } + i += 1; + } + } + + if ( LoadParam.verbose > 0 ) + { + LoadParam.endTime = os::Timer::getRealTime(); + snprintf_irr( buf, sizeof ( buf ), + "quake3::cleanMeshes needed %04u ms to clean %u of %u meshes", + LoadParam.endTime - LoadParam.startTime, + remove, + run + ); + os::Printer::log(buf, ELL_INFORMATION); + } +} + + +// recalculate bounding boxes +void CQ3LevelMesh::calcBoundingBoxes() +{ + if ( LoadParam.verbose > 0 ) + { + LoadParam.startTime = os::Timer::getRealTime(); + + if ( LoadParam.verbose > 1 ) + { + snprintf_irr( buf, sizeof ( buf ), + "quake3::calcBoundingBoxes start create %d textures and %d lightmaps", + NumTextures, + NumLightMaps + ); + os::Printer::log(buf, ELL_INFORMATION); + } + } + + s32 g; + + // create bounding box + for ( g = 0; g != E_Q3_MESH_SIZE; ++g ) + { + for ( u32 j=0; j < Mesh[g]->MeshBuffers.size(); ++j) + { + ((SMeshBufferLightMap*)Mesh[g]->MeshBuffers[j])->recalculateBoundingBox(); + } + + Mesh[g]->recalculateBoundingBox(); + // Mesh[0] is the main bbox + if (g!=0) + Mesh[0]->BoundingBox.addInternalBox(Mesh[g]->getBoundingBox()); + } + + for (g = 1; g < NumModels; g++) + { + for ( u32 j=0; j < BrushEntities[g]->MeshBuffers.size(); ++j) + { + ((SMeshBufferLightMap*)BrushEntities[g]->MeshBuffers[j])-> + recalculateBoundingBox(); + } + + BrushEntities[g]->recalculateBoundingBox(); + } + + if ( LoadParam.verbose > 0 ) + { + LoadParam.endTime = os::Timer::getRealTime(); + + snprintf_irr( buf, sizeof ( buf ), + "quake3::calcBoundingBoxes needed %04u ms to create %d textures and %d lightmaps", + LoadParam.endTime - LoadParam.startTime, + NumTextures, + NumLightMaps + ); + os::Printer::log( buf, ELL_INFORMATION); + } +} + + +//! loads the textures +void CQ3LevelMesh::loadTextures() +{ + if (!Driver) + return; + + if ( LoadParam.verbose > 0 ) + { + LoadParam.startTime = os::Timer::getRealTime(); + + if ( LoadParam.verbose > 1 ) + { + snprintf_irr( buf, sizeof ( buf ), + "quake3::loadTextures start create %d textures and %d lightmaps", + NumTextures, + NumLightMaps + ); + os::Printer::log( buf, ELL_INFORMATION); + } + } + + c8 lightmapname[255]; + s32 t; + + // load lightmaps. + Lightmap.set_used(NumLightMaps); + +/* + bool oldMipMapState = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); + Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); +*/ + core::dimension2d lmapsize(128,128); + + video::IImage* lmapImg; + for ( t = 0; t < NumLightMaps ; ++t) + { + sprintf(lightmapname, "%s.lightmap.%d", LevelName.c_str(), t); + + // lightmap is a CTexture::R8G8B8 format + lmapImg = Driver->createImageFromData( + video::ECF_R8G8B8, lmapsize, + LightMaps[t].imageBits, false, true ); + + Lightmap[t] = Driver->addTexture( lightmapname, lmapImg ); + lmapImg->drop(); + } + +// Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, oldMipMapState); + + // load textures + Tex.set_used( NumTextures ); + + const IShader* shader; + + core::stringc list; + io::path check; + tTexArray textureArray; + + // pre-load shaders + for ( t=0; t< NumTextures; ++t) + { + shader = getShader(Textures[t].strName, false); + } + + for ( t=0; t< NumTextures; ++t) + { + Tex[t].ShaderID = -1; + Tex[t].Texture = 0; + + list = ""; + + // get a shader ( if one exists ) + shader = getShader( Textures[t].strName, false); + if ( shader ) + { + Tex[t].ShaderID = shader->ID; + + // if texture name == stage1 Texture map + const SVarGroup * group; + + group = shader->getGroup( 2 ); + if ( group ) + { + if ( core::cutFilenameExtension( check, group->get( "map" ) ) == Textures[t].strName ) + { + list += check; + } + else + if ( check == "$lightmap" ) + { + // we check if lightmap is in stage 1 and texture in stage 2 + group = shader->getGroup( 3 ); + if ( group ) + list += group->get( "map" ); + } + } + } + else + { + // no shader, take it + list += Textures[t].strName; + } + + u32 pos = 0; + getTextures( textureArray, list, pos, FileSystem, Driver ); + + Tex[t].Texture = textureArray[0]; + } + + if ( LoadParam.verbose > 0 ) + { + LoadParam.endTime = os::Timer::getRealTime(); + + snprintf_irr( buf, sizeof ( buf ), + "quake3::loadTextures needed %04u ms to create %d textures and %d lightmaps", + LoadParam.endTime - LoadParam.startTime, + NumTextures, + NumLightMaps + ); + os::Printer::log( buf, ELL_INFORMATION); + } +} + + +//! Returns an axis aligned bounding box of the mesh. +const core::aabbox3d& CQ3LevelMesh::getBoundingBox() const +{ + return Mesh[0]->getBoundingBox(); +} + + +void CQ3LevelMesh::setBoundingBox(const core::aabbox3df& box) +{ + Mesh[0]->setBoundingBox(box); +} + + +//! Returns the type of the animated mesh. +E_ANIMATED_MESH_TYPE CQ3LevelMesh::getMeshType() const +{ + return scene::EAMT_BSP; +} + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BSP_LOADER_ diff --git a/source/Irrlicht/CQ3LevelMesh.h b/source/Irrlicht/CQ3LevelMesh.h new file mode 100644 index 00000000..595f6c95 --- /dev/null +++ b/source/Irrlicht/CQ3LevelMesh.h @@ -0,0 +1,488 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_Q3_LEVEL_MESH_H_INCLUDED__ +#define __C_Q3_LEVEL_MESH_H_INCLUDED__ + +#include "IQ3LevelMesh.h" +#include "IReadFile.h" +#include "IFileSystem.h" +#include "SMesh.h" +#include "SMeshBufferLightMap.h" +#include "IVideoDriver.h" +#include "irrString.h" +#include "ISceneManager.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + class CQ3LevelMesh : public IQ3LevelMesh + { + public: + + //! constructor + CQ3LevelMesh(io::IFileSystem* fs, scene::ISceneManager* smgr, + const quake3::Q3LevelLoadParameter &loadParam); + + //! destructor + virtual ~CQ3LevelMesh(); + + //! loads a level from a .bsp-File. Also tries to load all + //! needed textures. Returns true if successful. + 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 _IRR_OVERRIDE_; + + //! Gets the default animation speed of the animated mesh. + /** \return Amount of frames per second. If the amount is 0, it is a static, non animated mesh. */ + virtual f32 getAnimationSpeed() const _IRR_OVERRIDE_ + { + return FramesPerSecond; + } + + //! Gets the frame count of the animated mesh. + /** \param fps Frames per second to play the animation with. If the amount is 0, it is not animated. + The actual speed is set in the scene node the mesh is instantiated in.*/ + virtual void setAnimationSpeed(f32 fps) _IRR_OVERRIDE_ + { + FramesPerSecond=fps; + } + + //! returns the animated mesh based on a detail level. 0 is the + //! lowest, 255 the highest detail. Note, that some Meshes will + //! ignore the detail level. + virtual IMesh* getMesh(s32 frameInMs, s32 detailLevel=255, + s32 startFrameLoop=-1, s32 endFrameLoop=-1) _IRR_OVERRIDE_; + + //! Returns an axis aligned bounding box of the mesh. + //! \return A bounding box of this mesh is returned. + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + virtual void setBoundingBox( const core::aabbox3df& box) _IRR_OVERRIDE_; + + //! Returns the type of the animated mesh. + virtual E_ANIMATED_MESH_TYPE getMeshType() const _IRR_OVERRIDE_; + + //! loads the shader definition + void getShader( io::IReadFile* file ); + + //! loads the shader definition + virtual const quake3::IShader * getShader( const c8 * filename, bool fileNameIsValid=true ) _IRR_OVERRIDE_; + + //! returns a already loaded Shader + virtual const quake3::IShader * getShader( u32 index ) const _IRR_OVERRIDE_; + + + //! loads a configuration file + void getConfiguration( io::IReadFile* file ); + //! get's an interface to the entities + virtual quake3::tQ3EntityList & getEntityList() _IRR_OVERRIDE_; + + //! returns the requested brush entity + virtual IMesh* getBrushEntityMesh(s32 num) const _IRR_OVERRIDE_; + + //! returns the requested brush entity + virtual IMesh* getBrushEntityMesh(quake3::IEntity &ent) const _IRR_OVERRIDE_; + + //Link to held meshes? ... + + + //! returns amount of mesh buffers. + virtual u32 getMeshBufferCount() const _IRR_OVERRIDE_ + { + return 0; + } + + //! returns pointer to a mesh buffer + virtual IMeshBuffer* getMeshBuffer(u32 nr) const _IRR_OVERRIDE_ + { + return 0; + } + + //! Returns pointer to a mesh buffer which fits a material + /** \param material: material to search for + \return Pointer to the mesh buffer or 0 if there is no such mesh buffer. */ + virtual IMeshBuffer* getMeshBuffer( const video::SMaterial &material) const _IRR_OVERRIDE_ + { + return 0; + } + + virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) _IRR_OVERRIDE_ + { + return; + } + + //! set the hardware mapping hint, for driver + virtual void setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_ + { + return; + } + + //! flags the meshbuffer as changed, reloads hardware buffers + virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_ + { + return; + } + + private: + + + void constructMesh(); + void solveTJunction(); + void loadTextures(); + scene::SMesh** buildMesh(s32 num); + + struct STexShader + { + video::ITexture* Texture; + s32 ShaderID; + }; + + core::array< STexShader > Tex; + core::array Lightmap; + + enum eLumps + { + kEntities = 0, // Stores player/object positions, etc... + kShaders = 1, // Stores texture information + kPlanes = 2, // Stores the splitting planes + kNodes = 3, // Stores the BSP nodes + kLeafs = 4, // Stores the leafs of the nodes + kLeafFaces = 5, // Stores the leaf's indices into the faces + kLeafBrushes = 6, // Stores the leaf's indices into the brushes + kModels = 7, // Stores the info of world models + kBrushes = 8, // Stores the brushes info (for collision) + kBrushSides = 9, // Stores the brush surfaces info + kVertices = 10, // Stores the level vertices + kMeshVerts = 11, // Stores the model vertices offsets + kFogs = 12, // Stores the shader files (blending, anims..) + kFaces = 13, // Stores the faces for the level + kLightmaps = 14, // Stores the lightmaps for the level + kLightGrid = 15, // Stores extra world lighting information + kVisData = 16, // Stores PVS and cluster info (visibility) + kLightArray = 17, // RBSP + kMaxLumps // A constant to store the number of lumps + }; + + enum eBspSurfaceType + { + BSP_MST_BAD, + BSP_MST_PLANAR, + BSP_MST_PATCH, + BSP_MST_TRIANGLE_SOUP, + BSP_MST_FLARE, + BSP_MST_FOLIAGE + + }; + + struct tBSPHeader + { + s32 strID; // This should always be 'IBSP' + s32 version; // This should be 0x2e for Quake 3 files + }; + tBSPHeader header; + + struct tBSPLump + { + s32 offset; + s32 length; + }; + + + struct tBSPVertex + { + f32 vPosition[3]; // (x, y, z) position. + f32 vTextureCoord[2]; // (u, v) texture coordinate + f32 vLightmapCoord[2]; // (u, v) lightmap coordinate + f32 vNormal[3]; // (x, y, z) normal vector + u8 color[4]; // RGBA color for the vertex + }; + + struct tBSPFace + { + s32 textureID; // The index into the texture array + s32 fogNum; // The index for the effects (or -1 = n/a) + s32 type; // 1=polygon, 2=patch, 3=mesh, 4=billboard + s32 vertexIndex; // The index into this face's first vertex + s32 numOfVerts; // The number of vertices for this face + s32 meshVertIndex; // The index into the first meshvertex + s32 numMeshVerts; // The number of mesh vertices + s32 lightmapID; // The texture index for the lightmap + s32 lMapCorner[2]; // The face's lightmap corner in the image + s32 lMapSize[2]; // The size of the lightmap section + f32 lMapPos[3]; // The 3D origin of lightmap. + f32 lMapBitsets[2][3]; // The 3D space for s and t unit vectors. + f32 vNormal[3]; // The face normal. + s32 size[2]; // The bezier patch dimensions. + }; + + struct tBSPTexture + { + c8 strName[64]; // The name of the texture w/o the extension + u32 flags; // The surface flags (unknown) + u32 contents; // The content flags (unknown) + }; + + struct tBSPLightmap + { + u8 imageBits[128][128][3]; // The RGB data in a 128x128 image + }; + + struct tBSPNode + { + s32 plane; // The index into the planes array + s32 front; // The child index for the front node + s32 back; // The child index for the back node + s32 mins[3]; // The bounding box min position. + s32 maxs[3]; // The bounding box max position. + }; + + struct tBSPLeaf + { + s32 cluster; // The visibility cluster + s32 area; // The area portal + s32 mins[3]; // The bounding box min position + s32 maxs[3]; // The bounding box max position + s32 leafface; // The first index into the face array + s32 numOfLeafFaces; // The number of faces for this leaf + s32 leafBrush; // The first index for into the brushes + s32 numOfLeafBrushes; // The number of brushes for this leaf + }; + + struct tBSPPlane + { + f32 vNormal[3]; // Plane normal. + f32 d; // The plane distance from origin + }; + + struct tBSPVisData + { + s32 numOfClusters; // The number of clusters + s32 bytesPerCluster; // Bytes (8 bits) in the cluster's bitset + c8 *pBitsets; // Array of bytes holding the cluster vis. + }; + + struct tBSPBrush + { + s32 brushSide; // The starting brush side for the brush + s32 numOfBrushSides; // Number of brush sides for the brush + s32 textureID; // The texture index for the brush + }; + + struct tBSPBrushSide + { + s32 plane; // The plane index + s32 textureID; // The texture index + }; + + struct tBSPModel + { + f32 min[3]; // The min position for the bounding box + f32 max[3]; // The max position for the bounding box. + s32 faceIndex; // The first face index in the model + s32 numOfFaces; // The number of faces in the model + s32 brushIndex; // The first brush index in the model + s32 numOfBrushes; // The number brushes for the model + }; + + struct tBSPFog + { + c8 shader[64]; // The name of the shader file + s32 brushIndex; // The brush index for this shader + s32 visibleSide; // the brush side that ray tests need to clip against (-1 == none + }; + core::array < STexShader > FogMap; + + struct tBSPLights + { + u8 ambient[3]; // This is the ambient color in RGB + u8 directional[3]; // This is the directional color in RGB + u8 direction[2]; // The direction of the light: [phi,theta] + }; + + void loadTextures (tBSPLump* l, io::IReadFile* file); // Load the textures + void loadLightmaps (tBSPLump* l, io::IReadFile* file); // Load the lightmaps + void loadVerts (tBSPLump* l, io::IReadFile* file); // Load the vertices + void loadFaces (tBSPLump* l, io::IReadFile* file); // Load the faces + void loadPlanes (tBSPLump* l, io::IReadFile* file); // Load the Planes of the BSP + void loadNodes (tBSPLump* l, io::IReadFile* file); // load the Nodes of the BSP + void loadLeafs (tBSPLump* l, io::IReadFile* file); // load the Leafs of the BSP + void loadLeafFaces (tBSPLump* l, io::IReadFile* file); // load the Faces of the Leafs of the BSP + void loadVisData (tBSPLump* l, io::IReadFile* file); // load the visibility data of the clusters + void loadEntities (tBSPLump* l, io::IReadFile* file); // load the entities + void loadModels (tBSPLump* l, io::IReadFile* file); // load the models + void loadMeshVerts (tBSPLump* l, io::IReadFile* file); // load the mesh vertices + void loadBrushes (tBSPLump* l, io::IReadFile* file); // load the brushes of the BSP + void loadBrushSides (tBSPLump* l, io::IReadFile* file); // load the brushsides of the BSP + void loadLeafBrushes(tBSPLump* l, io::IReadFile* file); // load the brushes of the leaf + void loadFogs (tBSPLump* l, io::IReadFile* file); // load the shaders + + //bi-quadratic bezier patches + void createCurvedSurface_bezier(SMeshBufferLightMap* meshBuffer, + s32 faceIndex, s32 patchTesselation, s32 storevertexcolor); + + void createCurvedSurface_nosubdivision(SMeshBufferLightMap* meshBuffer, + s32 faceIndex, s32 patchTesselation, s32 storevertexcolor); + + struct S3DVertex2TCoords_64 + { + core::vector3d Pos; + core::vector3d Normal; + video::SColorf Color; + core::vector2d TCoords; + core::vector2d TCoords2; + + void copy( video::S3DVertex2TCoords &dest ) const; + + S3DVertex2TCoords_64() {} + S3DVertex2TCoords_64(const core::vector3d& pos, const core::vector3d& normal, const video::SColorf& color, + const core::vector2d& tcoords, const core::vector2d& tcoords2) + : Pos(pos), Normal(normal), Color(color), TCoords(tcoords), TCoords2(tcoords2) {} + + S3DVertex2TCoords_64 getInterpolated_quadratic(const S3DVertex2TCoords_64& v2, + const S3DVertex2TCoords_64& v3, const f64 d) const + { + return S3DVertex2TCoords_64 ( + Pos.getInterpolated_quadratic ( v2.Pos, v3.Pos, d ), + Normal.getInterpolated_quadratic ( v2.Normal, v3.Normal, d ), + Color.getInterpolated_quadratic ( v2.Color, v3.Color, (f32) d ), + TCoords.getInterpolated_quadratic ( v2.TCoords, v3.TCoords, d ), + TCoords2.getInterpolated_quadratic ( v2.TCoords2, v3.TCoords2, d )); + } + }; + + inline void copy( video::S3DVertex2TCoords * dest, const tBSPVertex * source, + s32 vertexcolor ) const; + void copy( S3DVertex2TCoords_64 * dest, const tBSPVertex * source, s32 vertexcolor ) const; + + + struct SBezier + { + SMeshBufferLightMap *Patch; + S3DVertex2TCoords_64 control[9]; + + void tesselate(s32 level); + + private: + core::array column[3]; + }; + SBezier Bezier; + + quake3::Q3LevelLoadParameter LoadParam; + + tBSPLump Lumps[kMaxLumps]; + + tBSPTexture* Textures; + s32 NumTextures; + + tBSPLightmap* LightMaps; + s32 NumLightMaps; + + tBSPVertex* Vertices; + s32 NumVertices; + + tBSPFace* Faces; + s32 NumFaces; + + tBSPModel* Models; + s32 NumModels; + + tBSPPlane* Planes; + s32 NumPlanes; + + tBSPNode* Nodes; + s32 NumNodes; + + tBSPLeaf* Leafs; + s32 NumLeafs; + + s32 *LeafFaces; + s32 NumLeafFaces; + + s32 *MeshVerts; // The vertex offsets for a mesh + s32 NumMeshVerts; + + tBSPBrush* Brushes; + s32 NumBrushes; + + scene::SMesh** BrushEntities; + + scene::SMesh* Mesh[quake3::E_Q3_MESH_SIZE]; + video::IVideoDriver* Driver; + core::stringc LevelName; + io::IFileSystem* FileSystem; // needs because there are no file extenstions stored in .bsp files. + + // Additional content + scene::ISceneManager* SceneManager; + enum eToken + { + Q3_TOKEN_UNRESOLVED = 0, + Q3_TOKEN_EOF = 1, + Q3_TOKEN_START_LIST, + Q3_TOKEN_END_LIST, + Q3_TOKEN_ENTITY, + Q3_TOKEN_TOKEN, + Q3_TOKEN_EOL, + Q3_TOKEN_COMMENT, + Q3_TOKEN_MATH_DIVIDE, + Q3_TOKEN_MATH_ADD, + Q3_TOKEN_MATH_MULTIPY + }; + struct SQ3Parser + { + const c8 *source; + u32 sourcesize; + u32 index; + core::stringc token; + eToken tokenresult; + }; + SQ3Parser Parser; + + + typedef void( CQ3LevelMesh::*tParserCallback ) ( quake3::SVarGroupList *& groupList, eToken token ); + void parser_parse( const void * data, u32 size, tParserCallback callback ); + void parser_nextToken(); + + void dumpVarGroup( const quake3::SVarGroup * group, s32 stack ) const; + + void scriptcallback_entity( quake3::SVarGroupList *& grouplist, eToken token ); + void scriptcallback_shader( quake3::SVarGroupList *& grouplist, eToken token ); + void scriptcallback_config( quake3::SVarGroupList *& grouplist, eToken token ); + + core::array < quake3::IShader > Shader; + core::array < quake3::IShader > Entity; //quake3::tQ3EntityList Entity; + + + quake3::tStringList ShaderFile; + void InitShader(); + void ReleaseShader(); + void ReleaseEntity(); + + + s32 setShaderMaterial( video::SMaterial & material, const tBSPFace * face ) const; + s32 setShaderFogMaterial( video::SMaterial &material, const tBSPFace * face ) const; + + struct SToBuffer + { + s32 takeVertexColor; + u32 index; + }; + + void cleanMeshes(); + void cleanMesh(SMesh *m, const bool texture0important = false); + void cleanLoader (); + void calcBoundingBoxes(); + c8 buf[128]; + f32 FramesPerSecond; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CQuake3ShaderSceneNode.cpp b/source/Irrlicht/CQuake3ShaderSceneNode.cpp new file mode 100644 index 00000000..972f131d --- /dev/null +++ b/source/Irrlicht/CQuake3ShaderSceneNode.cpp @@ -0,0 +1,1385 @@ +// Copyright (C) 2002-2012 Thomas Alten / 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" + +#ifdef _IRR_COMPILE_WITH_BSP_LOADER_ + +#include "CQuake3ShaderSceneNode.h" +#include "ISceneManager.h" +#include "IVideoDriver.h" +#include "ICameraSceneNode.h" +#include "SViewFrustum.h" +#include "IMeshManipulator.h" +#include "SMesh.h" +#include "IMaterialRenderer.h" +#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ +#include "CShadowVolumeSceneNode.h" +#else +#include "IShadowVolumeSceneNode.h" +#endif + +namespace irr +{ +namespace scene +{ + +// who, if not you.. +using namespace quake3; + +/*! +*/ +CQuake3ShaderSceneNode::CQuake3ShaderSceneNode( + scene::ISceneNode* parent, scene::ISceneManager* mgr,s32 id, + io::IFileSystem *fileSystem, const scene::IMeshBuffer *original, + const IShader * shader) +: scene::IMeshSceneNode(parent, mgr, id, + core::vector3df(0.f, 0.f, 0.f), + core::vector3df(0.f, 0.f, 0.f), + core::vector3df(1.f, 1.f, 1.f)), + Shader(shader), Mesh(0), Shadow(0), Original(0), MeshBuffer(0), TimeAbs(0.f) +{ + #ifdef _DEBUG + core::stringc dName = "CQuake3ShaderSceneNode "; + dName += Shader->name; + + setDebugName( dName.c_str() ); + #endif + + // name the Scene Node + this->Name = Shader->name; + + // take lightmap vertex type + MeshBuffer = new SMeshBuffer(); + + Mesh = new SMesh (); + Mesh->addMeshBuffer ( MeshBuffer ); + MeshBuffer->drop (); + + //Original = new SMeshBufferLightMap(); + Original = (const scene::SMeshBufferLightMap*) original; + Original->grab(); + + // clone meshbuffer to modifiable buffer + cloneBuffer(MeshBuffer, Original, + Original->getMaterial().ColorMask != 0); + + // load all Textures in all stages + loadTextures( fileSystem ); + + setAutomaticCulling( scene::EAC_OFF ); +} + + +/*! +*/ +CQuake3ShaderSceneNode::~CQuake3ShaderSceneNode() +{ + if (Shadow) + Shadow->drop(); + + if (Mesh) + Mesh->drop(); + + if (Original) + Original->drop(); +} + + + +/* + create single copies +*/ +void CQuake3ShaderSceneNode::cloneBuffer( scene::SMeshBuffer *dest, const scene::SMeshBufferLightMap * buffer, bool translateCenter ) +{ + dest->Material = buffer->Material; + dest->Indices = buffer->Indices; + + const u32 vsize = buffer->Vertices.size(); + + dest->Vertices.set_used( vsize ); + for ( u32 i = 0; i!= vsize; ++i ) + { + const video::S3DVertex2TCoords& src = buffer->Vertices[i]; + video::S3DVertex &dst = dest->Vertices[i]; + + dst.Pos = src.Pos; + dst.Normal = src.Normal; + dst.Color = 0xFFFFFFFF; + dst.TCoords = src.TCoords; + + if ( i == 0 ) + dest->BoundingBox.reset ( src.Pos ); + else + dest->BoundingBox.addInternalPoint ( src.Pos ); + } + + // move the (temp) Mesh to a ScenePosititon + // set Scene Node Position + + if ( translateCenter ) + { + MeshOffset = dest->BoundingBox.getCenter(); + setPosition( MeshOffset ); + + core::matrix4 m; + m.setTranslation( -MeshOffset ); + SceneManager->getMeshManipulator()->transform( dest, m ); + } + + // No Texture!. Use Shader-Pointer for sorting + dest->Material.setTexture(0, (video::ITexture*) Shader); +} + + +/* + load the textures for all stages +*/ +void CQuake3ShaderSceneNode::loadTextures( io::IFileSystem * fileSystem ) +{ + const SVarGroup *group; + u32 i; + + video::IVideoDriver *driver = SceneManager->getVideoDriver(); + + // generic stage + u32 mipmap = 0; + group = Shader->getGroup( 1 ); + if ( group->isDefined ( "nomipmaps" ) ) + { + mipmap = 2 | (driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS)? 1: 0 ); + driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); + } + + // clear all stages and prefill empty + Q3Texture.setAllocStrategy ( core::ALLOC_STRATEGY_SAFE ); + Q3Texture.clear(); + for ( i = 0; i != Shader->VarGroup->VariableGroup.size(); ++i ) + { + Q3Texture.push_back( SQ3Texture() ); + } + + u32 pos; + + // get texture map + for ( i = 0; i < Shader->VarGroup->VariableGroup.size(); ++i ) + { + group = Shader->getGroup( i ); + + const core::stringc &mapname = group->get( "map" ); + if ( 0 == mapname.size() ) + continue; + + // our lightmap is passed in material.Texture[2] + if ( mapname == "$lightmap" ) + { + Q3Texture [i].Texture.push_back( Original->getMaterial().getTexture(1) ); + } + else + { + pos = 0; + getTextures( Q3Texture [i].Texture, mapname, pos, fileSystem, driver ); + } + } + + // get anim map + for ( i = 0; i < Shader->VarGroup->VariableGroup.size(); ++i ) + { + if ( Q3Texture [i].Texture.size() ) + continue; + + group = Shader->getGroup( i ); + + const core::stringc &animmap = group->get( "animmap" ); + if ( 0 == animmap.size() ) + continue; + + // first parameter is frequency + pos = 0; + Q3Texture [i].TextureFrequency = core::max_( 0.0001f, getAsFloat( animmap, pos ) ); + + getTextures( Q3Texture [i].Texture, animmap, pos,fileSystem, driver ); + } + + // get clamp map + for ( i = 0; i < Shader->VarGroup->VariableGroup.size(); ++i ) + { + if ( Q3Texture [i].Texture.size() ) + continue; + + group = Shader->getGroup( i ); + + const core::stringc &clampmap = group->get( "clampmap" ); + if ( 0 == clampmap.size() ) + continue; + + Q3Texture [i].TextureAddressMode = video::ETC_CLAMP_TO_EDGE; + pos = 0; + getTextures( Q3Texture [i].Texture, clampmap, pos,fileSystem, driver ); + } + + if ( mipmap & 2 ) + driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, mipmap & 1); +} + +/* + Register each texture stage, if first is visible +*/ +void CQuake3ShaderSceneNode::OnRegisterSceneNode() +{ + if ( isVisible() ) + { + SceneManager->registerNodeForRendering(this, getRenderStage() ); + } + ISceneNode::OnRegisterSceneNode(); +} + +/* + is this a transparent node ? +*/ +E_SCENE_NODE_RENDER_PASS CQuake3ShaderSceneNode::getRenderStage() const +{ + E_SCENE_NODE_RENDER_PASS ret = ESNRP_SOLID; + + // generic stage + const SVarGroup *group; + + group = Shader->getGroup( 1 ); +/* + else + if ( group->getIndex( "portal" ) >= 0 ) + { + ret = ESNRP_TRANSPARENT_EFFECT; + } + else +*/ + if ( group->isDefined( "sort", "opaque" ) ) + { + ret = ESNRP_SOLID; + } + else + if ( group->isDefined( "sort", "additive" ) ) + { + ret = ESNRP_TRANSPARENT; + } + else + if ( strstr ( Shader->name.c_str(), "flame" ) || + group->isDefined( "surfaceparm", "water" ) || + group->isDefined( "sort", "underwater" ) + ) + { + ret = ESNRP_TRANSPARENT_EFFECT; + } + else + { + // Look if first drawing stage needs graphical underlay + for ( u32 stage = 2; stage < Shader->VarGroup->VariableGroup.size(); ++stage ) + { + if ( 0 == Q3Texture [ stage ].Texture.size() ) + continue; + + group = Shader->getGroup( stage ); + + SBlendFunc blendfunc ( video::EMFN_MODULATE_1X ); + getBlendFunc( group->get( "blendfunc" ), blendfunc ); + getBlendFunc( group->get( "alphafunc" ), blendfunc ); + + //ret = blendfunc.isTransparent ? ESNRP_TRANSPARENT : ESNRP_SOLID; + if ( blendfunc.isTransparent ) + { + ret = ESNRP_TRANSPARENT; + } + break; + } + } + + return ret; +} + + +/* + render in multipass technique +*/ +void CQuake3ShaderSceneNode::render() +{ + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + E_SCENE_NODE_RENDER_PASS pass = SceneManager->getSceneNodeRenderPass(); + + video::SMaterial material; + const SVarGroup *group; + + material.Lighting = false; + material.setTexture(1, 0); + material.NormalizeNormals = false; + + // generic stage + group = Shader->getGroup( 1 ); + material.BackfaceCulling = getCullingFunction( group->get( "cull" ) ); + + u32 pushProjection = 0; + core::matrix4 projection ( core::matrix4::EM4CONST_NOTHING ); + + // decal ( solve z-fighting ) + if ( group->isDefined( "polygonoffset" ) ) + { + projection = driver->getTransform( video::ETS_PROJECTION ); + + core::matrix4 decalProjection ( projection ); + +/* + f32 n = SceneManager->getActiveCamera()->getNearValue(); + f32 f = SceneManager->getActiveCamera()->getFarValue (); + + f32 delta = 0.01f; + f32 pz = 0.2f; + f32 epsilon = -2.f * f * n * delta / ( ( f + n ) * pz * ( pz + delta ) ); + decalProjection[10] *= 1.f + epsilon; +*/ + // TODO: involve camera + decalProjection[10] -= 0.0002f; + driver->setTransform( video::ETS_PROJECTION, decalProjection ); + pushProjection |= 1; + } + + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation ); + if (Shadow) + Shadow->updateShadowVolumes(); + + //! render all stages + u32 drawCount = (pass == ESNRP_TRANSPARENT_EFFECT) ? 1 : 0; + core::matrix4 textureMatrix ( core::matrix4::EM4CONST_NOTHING ); + for ( u32 stage = 1; stage < Shader->VarGroup->VariableGroup.size(); ++stage ) + { + SQ3Texture &q = Q3Texture[stage]; + + // advance current stage + textureMatrix.makeIdentity(); + animate( stage, textureMatrix ); + + // stage finished, no drawing stage ( vertex transform only ) + video::ITexture * tex = q.Texture.size() ? q.Texture [ q.TextureIndex ] : 0; + if ( 0 == tex ) + continue; + + // current stage + group = Shader->getGroup( stage ); + + material.setTexture(0, tex ); + material.ZBuffer = getDepthFunction( group->get( "depthfunc" ) ); + + // TODO: maybe should be video::EZW_ON instead of EZW_AUTO now (we didn't have that before and I just kept old values here when introducing it to not break anything) + if ( group->isDefined( "depthwrite" ) ) + { + material.ZWriteEnable = video::EZW_AUTO; + } + else + { + material.ZWriteEnable = drawCount == 0 ? video::EZW_AUTO : video::EZW_OFF; + } + + //resolve quake3 blendfunction to irrlicht Material Type + SBlendFunc blendfunc ( video::EMFN_MODULATE_1X ); + getBlendFunc( group->get( "blendfunc" ), blendfunc ); + getBlendFunc( group->get( "alphafunc" ), blendfunc ); + + material.MaterialType = blendfunc.type; + material.MaterialTypeParam = blendfunc.param0; + + material.TextureLayer[0].TextureWrapU = q.TextureAddressMode; + material.TextureLayer[0].TextureWrapV = q.TextureAddressMode; + material.TextureLayer[0].TextureWrapW = q.TextureAddressMode; + //material.TextureLayer[0].TrilinearFilter = 1; + //material.TextureLayer[0].AnisotropicFilter = 0xFF; + material.setTextureMatrix( 0, textureMatrix ); + + driver->setMaterial( material ); + driver->drawMeshBuffer( MeshBuffer ); + drawCount += 1; + + } + + if ( DebugDataVisible & scene::EDS_MESH_WIRE_OVERLAY ) + { + video::SMaterial deb_m; + deb_m.Wireframe = true; + deb_m.Lighting = false; + deb_m.BackfaceCulling = material.BackfaceCulling; + driver->setMaterial( deb_m ); + + driver->drawMeshBuffer( MeshBuffer ); + } + + // show normals + if ( DebugDataVisible & scene::EDS_NORMALS ) + { + video::SMaterial deb_m; + + IAnimatedMesh * arrow = SceneManager->addArrowMesh ( + "__debugnormalq3", + 0xFFECEC00,0xFF999900, + 4, 8, + 8.f, 6.f, + 0.5f,1.f + ); + if ( 0 == arrow ) + { + arrow = SceneManager->getMesh ( "__debugnormalq3" ); + } + const IMesh *mesh = arrow->getMesh ( 0 ); + + // find a good scaling factor + + core::matrix4 m2; + + // draw normals + const scene::IMeshBuffer* mb = MeshBuffer; + const u32 vSize = video::getVertexPitchFromType(mb->getVertexType()); + const video::S3DVertex* v = ( const video::S3DVertex*)mb->getVertices(); + + //f32 colCycle = 270.f / (f32) core::s32_max ( mb->getVertexCount() - 1, 1 ); + + for ( u32 i=0; i != mb->getVertexCount(); ++i ) + { + // Align to v->normal + m2.buildRotateFromTo ( core::vector3df ( 0.f, 1.f, 0 ), v->Normal ); + m2.setTranslation ( v->Pos + AbsoluteTransformation.getTranslation () ); +/* + core::quaternion quatRot( v->Normal.Z, 0.f, -v->Normal.X, 1 + v->Normal.Y ); + quatRot.normalize(); + quatRot.getMatrix ( m2, v->Pos ); + + m2 [ 12 ] += AbsoluteTransformation [ 12 ]; + m2 [ 13 ] += AbsoluteTransformation [ 13 ]; + m2 [ 14 ] += AbsoluteTransformation [ 14 ]; +*/ + driver->setTransform(video::ETS_WORLD, m2 ); + + deb_m.Lighting = true; +/* + irr::video::SColorHSL color; + irr::video::SColor rgb(0); + color.Hue = i * colCycle * core::DEGTORAD; + color.Saturation = 1.f; + color.Luminance = 0.5f; + color.toRGB( deb_m.EmissiveColor ); +*/ + switch ( i ) + { + case 0: deb_m.EmissiveColor.set(0xFFFFFFFF); break; + case 1: deb_m.EmissiveColor.set(0xFFFF0000); break; + case 2: deb_m.EmissiveColor.set(0xFF00FF00); break; + case 3: deb_m.EmissiveColor.set(0xFF0000FF); break; + default: + deb_m.EmissiveColor = v->Color; break; + } + driver->setMaterial( deb_m ); + + for ( u32 a = 0; a != mesh->getMeshBufferCount(); ++a ) + driver->drawMeshBuffer ( mesh->getMeshBuffer ( a ) ); + + v = (const video::S3DVertex*) ( (u8*) v + vSize ); + } + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + } + + + if ( pushProjection & 1 ) + { + driver->setTransform( video::ETS_PROJECTION, projection ); + } + + if ( DebugDataVisible & scene::EDS_BBOX ) + { + video::SMaterial deb_m; + deb_m.Lighting = false; + driver->setMaterial(deb_m); + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + driver->draw3DBox( getBoundingBox(), video::SColor(255,255,0,0)); + } + +} + + +//! Removes a child from this scene node. +//! Implemented here, to be able to remove the shadow properly, if there is one, +//! or to remove attached childs. +bool CQuake3ShaderSceneNode::removeChild(ISceneNode* child) +{ + if (child && Shadow == child) + { + Shadow->drop(); + Shadow = 0; + } + + return ISceneNode::removeChild(child); +} + + +//! Creates shadow volume scene node as child of this node +//! and returns a pointer to it. +IShadowVolumeSceneNode* CQuake3ShaderSceneNode::addShadowVolumeSceneNode( + const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity) +{ +#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ + if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER)) + return 0; + + if (!shadowMesh) + shadowMesh = Mesh; // if null is given, use the mesh of node + + if (Shadow) + Shadow->drop(); + + Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity); + return Shadow; +#else + return 0; +#endif +} + + +/*! +3.3.1 deformVertexes wave
+ Designed for water surfaces, modifying the values differently at each point. + It accepts the standard wave functions of the type sin, triangle, square, sawtooth + or inversesawtooth. The "div" parameter is used to control the wave "spread" + - a value equal to the tessSize of the surface is a good default value + (tessSize is subdivision size, in game units, used for the shader when seen in the game world) . +*/ +void CQuake3ShaderSceneNode::deformvertexes_wave( f32 dt, SModifierFunction &function ) +{ + function.wave = core::reciprocal( function.wave ); + + const f32 phase = function.phase; + + const u32 vsize = Original->Vertices.size(); + for ( u32 i = 0; i != vsize; ++i ) + { + const video::S3DVertex2TCoords &src = Original->Vertices[i]; + video::S3DVertex &dst = MeshBuffer->Vertices[i]; + + if ( 0 == function.count ) + dst.Pos = src.Pos - MeshOffset; + + const f32 wavephase = (dst.Pos.X + dst.Pos.Y + dst.Pos.Z) * function.wave; + function.phase = phase + wavephase; + + const f32 f = function.evaluate( dt ); + + dst.Pos.X += f * src.Normal.X; + dst.Pos.Y += f * src.Normal.Y; + dst.Pos.Z += f * src.Normal.Z; + + if ( i == 0 ) + MeshBuffer->BoundingBox.reset ( dst.Pos ); + else + MeshBuffer->BoundingBox.addInternalPoint ( dst.Pos ); + } + function.count = 1; +} + +/*! + deformVertexes move x y z func base amplitude phase freq + The move parameter is used to make a brush, curve patch or model + appear to move together as a unit. The x y z values are the distance + and direction in game units the object appears to move relative to + it's point of origin in the map. The func base amplitude phase freq values are + the same as found in other waveform manipulations. + + The product of the function modifies the values x, y, and z. + Therefore, if you have an amplitude of 5 and an x value of 2, + the object will travel 10 units from its point of origin along the x axis. + This results in a total of 20 units of motion along the x axis, since the + amplitude is the variation both above and below the base. + + It must be noted that an object made with this shader does not actually + change position, it only appears to. + + Design Notes: + If an object is made up of surfaces with different shaders, all must have + matching deformVertexes move values or the object will appear to tear itself apart. +*/ +void CQuake3ShaderSceneNode::deformvertexes_move( f32 dt, SModifierFunction &function ) +{ + function.wave = core::reciprocal( function.wave ); + const f32 f = function.evaluate( dt ); + + const u32 vsize = Original->Vertices.size(); + for ( u32 i = 0; i != vsize; ++i ) + { + const video::S3DVertex2TCoords &src = Original->Vertices[i]; + video::S3DVertex &dst = MeshBuffer->Vertices[i]; + + if ( 0 == function.count ) + dst.Pos = src.Pos - MeshOffset; + + dst.Pos.X += f * function.x; + dst.Pos.Y += f * function.y; + dst.Pos.Z += f * function.z; + + if ( i == 0 ) + MeshBuffer->BoundingBox.reset ( dst.Pos ); + else + MeshBuffer->BoundingBox.addInternalPoint ( dst.Pos ); + } + function.count = 1; + +} + +/*! + 3.3.2 deformVertexes normal
+ This deformation affects the normals of a vertex without actually moving it, + which will effect later shader options like lighting and especially environment mapping. + If the shader stages don't use normals in any of their calculations, there will + be no visible effect. + + Design Notes: Putting values of 0.1 t o 0.5 in Amplitude and 1.0 to 4.0 in the + Frequency can produce some satisfying results. Some things that have been + done with it: A small fluttering bat, falling leaves, rain, flags. +*/ +void CQuake3ShaderSceneNode::deformvertexes_normal( f32 dt, SModifierFunction &function ) +{ + function.func = SINUS; + const u32 vsize = Original->Vertices.size(); + for ( u32 i = 0; i != vsize; ++i ) + { + const video::S3DVertex2TCoords &src = Original->Vertices[i]; + video::S3DVertex &dst = MeshBuffer->Vertices[i]; + + function.base = atan2f ( src.Pos.X, src.Pos.Y ); + function.phase = src.Pos.X + src.Pos.Z; + + const f32 lat = function.evaluate( dt ); + + function.base = src.Normal.Y; + function.phase = src.Normal.Z + src.Normal.X; + + const f32 lng = function.evaluate( dt ); + + dst.Normal.X = cosf ( lat ) * sinf ( lng ); + dst.Normal.Y = sinf ( lat ) * sinf ( lng ); + dst.Normal.Z = cosf ( lng ); + + } +} + + +/*! + 3.3.3 deformVertexes bulge + This forces a bulge to move along the given s and t directions. Designed for use + on curved pipes. + + Specific parameter definitions for deform keywords: +
This is roughly defined as the size of the waves that occur. + It is measured in game units. Smaller values create a greater + density of smaller wave forms occurring in a given area. + Larger values create a lesser density of waves, or otherwise put, + the appearance of larger waves. To look correct this value should + closely correspond to the value (in pixels) set for tessSize (tessellation size) + of the texture. A value of 100.0 is a good default value + (which means your tessSize should be close to that for things to look "wavelike"). + + This is the type of wave form being created. Sin stands for sine wave, + a regular smoothly flowing wave. Triangle is a wave with a sharp ascent + and a sharp decay. It will make a choppy looking wave forms. + A square wave is simply on or off for the period of the + frequency with no in between. The sawtooth wave has the ascent of a + triangle wave, but has the decay cut off sharply like a square wave. + An inversesawtooth wave reverses this. + + This is the distance, in game units that the apparent surface of the + texture is displaced from the actual surface of the brush as placed + in the editor. A positive value appears above the brush surface. + A negative value appears below the brush surface. + An example of this is the Quad effect, which essentially is a + shell with a positive base value to stand it away from the model + surface and a 0 (zero) value for amplitude. + + The distance that the deformation moves away from the base value. + See Wave Forms in the introduction for a description of amplitude. + + See Wave Forms in the introduction for a description of phase) + + See Wave Forms in the introduction for a description of frequency) + + Design Note: The div and amplitude parameters, when used in conjunction with + liquid volumes like water should take into consideration how much the water + will be moving. A large ocean area would have have massive swells (big div values) + that rose and fell dramatically (big amplitude values). While a small, quiet pool + may move very little. +*/ +void CQuake3ShaderSceneNode::deformvertexes_bulge( f32 dt, SModifierFunction &function ) +{ + function.func = SINUS; + function.wave = core::reciprocal( function.bulgewidth ); + + dt *= function.bulgespeed * 0.1f; + const f32 phase = function.phase; + + const u32 vsize = Original->Vertices.size(); + for ( u32 i = 0; i != vsize; ++i ) + { + const video::S3DVertex2TCoords &src = Original->Vertices[i]; + video::S3DVertex &dst = MeshBuffer->Vertices[i]; + + const f32 wavephase = (Original->Vertices[i].TCoords.X ) * function.wave; + function.phase = phase + wavephase; + + const f32 f = function.evaluate( dt ); + + if ( 0 == function.count ) + dst.Pos = src.Pos - MeshOffset; + + dst.Pos.X += f * src.Normal.X; + dst.Pos.Y += f * src.Normal.Y; + dst.Pos.Z += f * src.Normal.Z; + + if ( i == 0 ) + MeshBuffer->BoundingBox.reset ( dst.Pos ); + else + MeshBuffer->BoundingBox.addInternalPoint ( dst.Pos ); + } + + function.count = 1; +} + + +/*! + deformVertexes autosprite + + This function can be used to make any given triangle quad + (pair of triangles that form a square rectangle) automatically behave + like a sprite without having to make it a separate entity. This means + that the "sprite" on which the texture is placed will rotate to always + appear at right angles to the player's view as a sprite would. Any four-sided + brush side, flat patch, or pair of triangles in a model can have the autosprite + effect on it. The brush face containing a texture with this shader keyword must + be square. +*/ +void CQuake3ShaderSceneNode::deformvertexes_autosprite( f32 dt, SModifierFunction &function ) +{ + u32 vsize = Original->Vertices.size(); + u32 g; + u32 i; + + const core::vector3df& camPos = SceneManager->getActiveCamera()->getPosition(); + + video::S3DVertex * dv = MeshBuffer->Vertices.pointer(); + const video::S3DVertex2TCoords * vin = Original->Vertices.const_pointer(); + + core::matrix4 lookat ( core::matrix4::EM4CONST_NOTHING ); + core::quaternion q; + for ( i = 0; i < vsize; i += 4 ) + { + // quad-plane + core::vector3df center = 0.25f * ( vin[i+0].Pos + vin[i+1].Pos + vin[i+2].Pos + vin[i+3].Pos ); + core::vector3df forward = camPos - center; + + q.rotationFromTo ( vin[i].Normal, forward ); + q.getMatrixCenter ( lookat, center, MeshOffset ); + + for ( g = 0; g < 4; ++g ) + { + lookat.transformVect ( dv[i+g].Pos, vin[i+g].Pos ); + lookat.rotateVect ( dv[i+g].Normal, vin[i+g].Normal ); + } + + } + function.count = 1; +} + + +/*! + deformVertexes autosprite2 + Is a slightly modified "sprite" that only rotates around the middle of its longest axis. + This allows you to make a pillar of fire that you can walk around, or an energy beam + stretched across the room. +*/ + +struct sortaxis +{ + core::vector3df v; + bool operator < ( const sortaxis &other ) const + { + return v.getLengthSQ () < other.v.getLengthSQ (); + } +}; +/*! +*/ +void CQuake3ShaderSceneNode::deformvertexes_autosprite2( f32 dt, SModifierFunction &function ) +{ + u32 vsize = Original->Vertices.size(); + u32 g; + u32 i; + + const core::vector3df camPos = SceneManager->getActiveCamera()->getAbsolutePosition(); + + video::S3DVertex * dv = MeshBuffer->Vertices.pointer(); + const video::S3DVertex2TCoords * vin = Original->Vertices.const_pointer(); + + core::matrix4 lookat ( core::matrix4::EM4CONST_NOTHING ); + + core::array < sortaxis > axis; + axis.set_used ( 3 ); + + for ( i = 0; i < vsize; i += 4 ) + { + // quad-plane + core::vector3df center = 0.25f * ( vin[i+0].Pos + vin[i+1].Pos + vin[i+2].Pos + vin[i+3].Pos ); + + // longes axe + axis[0].v = vin[i+1].Pos - vin[i+0].Pos; + axis[1].v = vin[i+2].Pos - vin[i+0].Pos; + axis[2].v = vin[i+3].Pos - vin[i+0].Pos; + axis.set_sorted ( false ); + axis.sort (); + + lookat.buildAxisAlignedBillboard ( camPos, center, MeshOffset, axis[1].v, vin[i+0].Normal ); + + for ( g = 0; g < 4; ++g ) + { + lookat.transformVect ( dv[i+g].Pos, vin[i+g].Pos ); + lookat.rotateVect ( dv[i+g].Normal, vin[i+g].Normal ); + } + } + function.count = 1; +} + +/* + Generate Vertex Color +*/ +void CQuake3ShaderSceneNode::vertextransform_rgbgen( f32 dt, SModifierFunction &function ) +{ + u32 i; + const u32 vsize = Original->Vertices.size(); + + switch ( function.rgbgen ) + { + case IDENTITY: + //rgbgen identity + for ( i = 0; i != vsize; ++i ) + MeshBuffer->Vertices[i].Color.set(0xFFFFFFFF); + break; + + case IDENTITYLIGHTING: + // rgbgen identitylighting TODO: overbright + for ( i = 0; i != vsize; ++i ) + MeshBuffer->Vertices[i].Color.set(0xFF7F7F7F); + break; + + case EXACTVERTEX: + // alphagen exactvertex TODO lighting + case VERTEX: + // rgbgen vertex + for ( i = 0; i != vsize; ++i ) + MeshBuffer->Vertices[i].Color=Original->Vertices[i].Color; + break; + case WAVE: + { + // rgbGen wave + f32 f = function.evaluate( dt ) * 255.f; + s32 value = core::clamp( core::floor32(f), 0, 255 ); + value = 0xFF000000 | value << 16 | value << 8 | value; + + for ( i = 0; i != vsize; ++i ) + MeshBuffer->Vertices[i].Color.set(value); + } break; + case CONSTANT: + { + //rgbgen const ( x y z ) + video::SColorf cf( function.x, function.y, function.z ); + video::SColor col = cf.toSColor(); + for ( i = 0; i != vsize; ++i ) + MeshBuffer->Vertices[i].Color=col; + } break; + default: + break; + } +} + +/* + Generate Vertex Color, Alpha +*/ +void CQuake3ShaderSceneNode::vertextransform_alphagen( f32 dt, SModifierFunction &function ) +{ + u32 i; + const u32 vsize = Original->Vertices.size(); + + switch ( function.alphagen ) + { + case IDENTITY: + //alphagen identity + for ( i = 0; i != vsize; ++i ) + MeshBuffer->Vertices[i].Color.setAlpha ( 0xFF ); + break; + + case EXACTVERTEX: + // alphagen exactvertex TODO lighting + case VERTEX: + // alphagen vertex + for ( i = 0; i != vsize; ++i ) + MeshBuffer->Vertices[i].Color.setAlpha ( Original->Vertices[i].Color.getAlpha() ); + break; + case CONSTANT: + { + // alphagen const + u32 a = (u32) ( function.x * 255.f ); + for ( i = 0; i != vsize; ++i ) + MeshBuffer->Vertices[i].Color.setAlpha ( a ); + } break; + + case LIGHTINGSPECULAR: + { + // alphagen lightingspecular TODO!!! + const SViewFrustum *frustum = SceneManager->getActiveCamera()->getViewFrustum(); + const core::matrix4 &view = frustum->getTransform ( video::ETS_VIEW ); + + const f32 *m = view.pointer(); + + for ( i = 0; i != vsize; ++i ) + { + const core::vector3df &n = Original->Vertices[i].Normal; + MeshBuffer->Vertices[i].Color.setAlpha ((u32)( 128.f *(1.f+(n.X*m[0]+n.Y*m[1]+n.Z*m[2])))); + } + + } break; + + + case WAVE: + { + // alphagen wave + f32 f = function.evaluate( dt ) * 255.f; + s32 value = core::clamp( core::floor32(f), 0, 255 ); + + for ( i = 0; i != vsize; ++i ) + MeshBuffer->Vertices[i].Color.setAlpha ( value ); + } break; + default: + break; + } +} + + + +/* + Generate Texture Coordinates +*/ +void CQuake3ShaderSceneNode::vertextransform_tcgen( f32 dt, SModifierFunction &function ) +{ + u32 i; + const u32 vsize = Original->Vertices.size(); + + switch ( function.tcgen ) + { + case TURBULENCE: + //tcgen turb + { + function.wave = core::reciprocal( function.phase ); + + const f32 phase = function.phase; + + for ( i = 0; i != vsize; ++i ) + { + const video::S3DVertex2TCoords &src = Original->Vertices[i]; + video::S3DVertex &dst = MeshBuffer->Vertices[i]; + + const f32 wavephase = (src.Pos.X + src.Pos.Y + src.Pos.Z) * function.wave; + function.phase = phase + wavephase; + + const f32 f = function.evaluate( dt ); + + dst.TCoords.X = src.TCoords.X + f * src.Normal.X; + dst.TCoords.Y = src.TCoords.Y + f * src.Normal.Y; + } + } + break; + + case TEXTURE: + // tcgen texture + for ( i = 0; i != vsize; ++i ) + MeshBuffer->Vertices[i].TCoords = Original->Vertices[i].TCoords; + break; + case LIGHTMAP: + // tcgen lightmap + for ( i = 0; i != vsize; ++i ) + MeshBuffer->Vertices[i].TCoords = Original->Vertices[i].TCoords2; + break; + case ENVIRONMENT: + { + // tcgen environment + const SViewFrustum *frustum = SceneManager->getActiveCamera()->getViewFrustum(); + const core::matrix4 &view = frustum->getTransform ( video::ETS_VIEW ); + + const f32 *m = view.pointer(); + + core::vector3df n; + for ( i = 0; i != vsize; ++i ) + { + //const core::vector3df &n = Original->Vertices[i].Normal; + + n = frustum->cameraPosition - Original->Vertices[i].Pos; + n.normalize(); + n += Original->Vertices[i].Normal; + n.normalize(); + + MeshBuffer->Vertices[i].TCoords.X = 0.5f*(1.f+(n.X*m[0]+n.Y*m[1]+n.Z*m[2])); + MeshBuffer->Vertices[i].TCoords.Y = 0.5f*(1.f+(n.X*m[4]+n.Y*m[5]+n.Z*m[6])); + } + + } break; + default: + break; + } +} + + +#if 0 +/* + Transform Texture Coordinates +*/ +void CQuake3ShaderSceneNode::transformtex( const core::matrix4 &m, const u32 addressMode ) +{ + u32 i; + const u32 vsize = MeshBuffer->Vertices.size(); + + f32 tx1; + f32 ty1; + + if ( addressMode ) + { + for ( i = 0; i != vsize; ++i ) + { + core::vector2df &tx = MeshBuffer->Vertices[i].TCoords; + + tx1 = m[0] * tx.X + m[4] * tx.Y + m[8]; + ty1 = m[1] * tx.X + m[5] * tx.Y + m[9]; + + tx.X = tx1; + tx.Y = ty1; + } + } + else + { + + for ( i = 0; i != vsize; ++i ) + { + core::vector2df &tx = MeshBuffer->Vertices[i].TCoords; + + tx1 = m[0] * tx.X + m[4] * tx.Y + m[8]; + ty1 = m[1] * tx.X + m[5] * tx.Y + m[9]; + + tx.X = tx1 <= 0.f ? 0.f : tx1 >= 1.f ? 1.f : tx1; + tx.Y = ty1 <= 0.f ? 0.f : ty1 >= 1.f ? 1.f : ty1; + + //tx.X = core::clamp( tx1, 0.f, 1.f ); + //tx.Y = core::clamp( ty1, 0.f, 1.f ); + } + } +} + +#endif + + +/* + Texture & Vertex Transform Animator + + Return a Texture Transformation for this stage + Vertex transformation are called if found + +*/ +void CQuake3ShaderSceneNode::animate( u32 stage,core::matrix4 &texture ) +{ + const SVarGroup *group = Shader->getGroup( stage ); + + // select current texture + SQ3Texture &q3Tex = Q3Texture [ stage ]; + if ( q3Tex.TextureFrequency != 0.f ) + { + s32 v = core::floor32( TimeAbs * q3Tex.TextureFrequency ); + q3Tex.TextureIndex = v % q3Tex.Texture.size(); + } + + core::matrix4 m2; + SModifierFunction function; + + f32 f[16]; + + // walk group for all modifiers + for ( u32 g = 0; g != group->Variable.size(); ++g ) + { + const SVariable &v = group->Variable[g]; + + // get the modifier + static const c8 * const modifierList[] = + { + "tcmod","deformvertexes","rgbgen","tcgen","map","alphagen" + }; + + u32 pos = 0; + function.masterfunc0 = (eQ3ModifierFunction) isEqual( v.name, pos, modifierList, 6 ); + + if ( UNKNOWN == function.masterfunc0 ) + continue; + + switch ( function.masterfunc0 ) + { + //tcmod + case TCMOD: + m2.makeIdentity(); + break; + default: + break; + } + + // get the modifier function + static const c8 * const funclist[] = + { + "scroll","scale","rotate","stretch","turb", + "wave","identity","vertex", + "texture","lightmap","environment","$lightmap", + "bulge","autosprite","autosprite2","transform", + "exactvertex","const","lightingspecular","move","normal", + "identitylighting" + }; + static const c8 * const groupToken[] = { "(", ")" }; + + pos = 0; + function.masterfunc1 = (eQ3ModifierFunction) isEqual( v.content, pos, funclist, 22 ); + if ( function.masterfunc1 != UNKNOWN ) + function.masterfunc1 = (eQ3ModifierFunction) ((u32) function.masterfunc1 + FUNCTION2 + 1); + + switch ( function.masterfunc1 ) + { + case SCROLL: + // tcMod scroll + f[0] = getAsFloat( v.content, pos ) * TimeAbs; + f[1] = getAsFloat( v.content, pos ) * TimeAbs; + m2.setTextureTranslate( f[0], f[1] ); + break; + case SCALE: + // tcmod scale + f[0] = getAsFloat( v.content, pos ); + f[1] = getAsFloat( v.content, pos ); + m2.setTextureScale( f[0], f[1] ); + break; + case ROTATE: + // tcmod rotate + m2.setTextureRotationCenter( getAsFloat( v.content, pos ) * + core::DEGTORAD * + TimeAbs + ); + break; + case TRANSFORM: + // tcMod + memset(f, 0, sizeof ( f )); + f[10] = f[15] = 1.f; + + f[0] = getAsFloat( v.content, pos ); + f[1] = getAsFloat( v.content, pos ); + f[4] = getAsFloat( v.content, pos ); + f[5] = getAsFloat( v.content, pos ); + f[8] = getAsFloat( v.content, pos ); + f[9] = getAsFloat( v.content, pos ); + m2.setM ( f ); + break; + + case STRETCH: // stretch + case TURBULENCE: // turb + case WAVE: // wave + case IDENTITY: // identity + case IDENTITYLIGHTING: + case VERTEX: // vertex + case MOVE: + case CONSTANT: + { + // turb == sin, default == sin + function.func = SINUS; + + if ( function.masterfunc0 == DEFORMVERTEXES ) + { + switch ( function.masterfunc1 ) + { + case WAVE: + // deformvertexes wave + function.wave = getAsFloat( v.content, pos ); + break; + case MOVE: + //deformvertexes move + function.x = getAsFloat( v.content, pos ); + function.z = getAsFloat( v.content, pos ); + function.y = getAsFloat( v.content, pos ); + break; + default: + break; + } + } + + switch ( function.masterfunc1 ) + { + case STRETCH: + case TURBULENCE: + case WAVE: + case MOVE: + getModifierFunc( function, v.content, pos ); + break; + default: + break; + } + + switch ( function.masterfunc1 ) + { + case STRETCH: + //tcMod stretch + f[0] = core::reciprocal( function.evaluate(TimeAbs) ); + m2.setTextureScaleCenter( f[0], f[0] ); + break; + case TURBULENCE: + //tcMod turb + //function.tcgen = TURBULENCE; + m2.setTextureRotationCenter( function.frequency * + core::DEGTORAD * + TimeAbs + ); + break; + case WAVE: + case IDENTITY: + case IDENTITYLIGHTING: + case VERTEX: + case EXACTVERTEX: + case CONSTANT: + case LIGHTINGSPECULAR: + case MOVE: + switch ( function.masterfunc0 ) + { + case DEFORMVERTEXES: + switch ( function.masterfunc1 ) + { + case WAVE: + deformvertexes_wave( TimeAbs, function ); + break; + case MOVE: + deformvertexes_move( TimeAbs, function ); + break; + default: + break; + } + break; + case RGBGEN: + function.rgbgen = function.masterfunc1; + if ( function.rgbgen == CONSTANT ) + { + isEqual ( v.content, pos, groupToken, 2 ); + function.x = getAsFloat( v.content, pos ); + function.y = getAsFloat( v.content, pos ); + function.z = getAsFloat( v.content, pos ); + } + //vertextransform_rgbgen( TimeAbs, function ); + break; + case ALPHAGEN: + function.alphagen = function.masterfunc1; + if ( function.alphagen == CONSTANT ) + { + function.x = getAsFloat( v.content, pos ); + } + + //vertextransform_alphagen( TimeAbs, function ); + break; + default: + break; + } + break; + default: + break; + } + + } break; + case TEXTURE: + case LIGHTMAP: + case ENVIRONMENT: + // "texture","lightmap","environment" + function.tcgen = function.masterfunc1; + break; + case DOLLAR_LIGHTMAP: + // map == lightmap, tcgen == lightmap + function.tcgen = LIGHTMAP; + break; + case BULGE: + // deformvertexes bulge + function.bulgewidth = getAsFloat( v.content, pos ); + function.bulgeheight = getAsFloat( v.content, pos ); + function.bulgespeed = getAsFloat( v.content, pos ); + + deformvertexes_bulge(TimeAbs, function); + break; + + case NORMAL: + // deformvertexes normal + function.amp = getAsFloat( v.content, pos ); + function.frequency = getAsFloat( v.content, pos ); + + deformvertexes_normal(TimeAbs, function); + break; + + case AUTOSPRITE: + // deformvertexes autosprite + deformvertexes_autosprite(TimeAbs, function); + break; + + case AUTOSPRITE2: + // deformvertexes autosprite2 + deformvertexes_autosprite2(TimeAbs, function); + break; + default: + break; + } // func + + switch ( function.masterfunc0 ) + { + case TCMOD: + texture *= m2; + break; + default: + break; + } + + } // group + + vertextransform_rgbgen( TimeAbs, function ); + vertextransform_alphagen( TimeAbs, function ); + vertextransform_tcgen( TimeAbs, function ); +} + + +void CQuake3ShaderSceneNode::OnAnimate(u32 timeMs) +{ + TimeAbs = f32( timeMs ) * (1.f/1000.f); + ISceneNode::OnAnimate( timeMs ); +} + +const core::aabbox3d& CQuake3ShaderSceneNode::getBoundingBox() const +{ + return MeshBuffer->getBoundingBox(); +} + + +u32 CQuake3ShaderSceneNode::getMaterialCount() const +{ + return Q3Texture.size(); +} + +video::SMaterial& CQuake3ShaderSceneNode::getMaterial(u32 i) +{ + video::SMaterial& m = MeshBuffer->Material; + m.setTexture(0, 0); + if ( Q3Texture [ i ].TextureIndex ) + m.setTexture(0, Q3Texture [ i ].Texture [ Q3Texture [ i ].TextureIndex ]); + return m; +} + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CQuake3ShaderSceneNode.h b/source/Irrlicht/CQuake3ShaderSceneNode.h new file mode 100644 index 00000000..874bae83 --- /dev/null +++ b/source/Irrlicht/CQuake3ShaderSceneNode.h @@ -0,0 +1,118 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_QUAKE3_SCENE_NODE_H_INCLUDED__ +#define __C_QUAKE3_SCENE_NODE_H_INCLUDED__ + +#include "IMeshSceneNode.h" +#include "IQ3Shader.h" +#include "IFileSystem.h" +#include "SMeshBuffer.h" +#include "SMeshBufferLightMap.h" +#include "SMesh.h" +#include "ISceneManager.h" + +namespace irr +{ +namespace scene +{ + +//! Scene node which is a quake3 shader. +class CQuake3ShaderSceneNode : public scene::IMeshSceneNode +{ +public: + + CQuake3ShaderSceneNode( ISceneNode* parent, ISceneManager* mgr, s32 id, + io::IFileSystem* fileSystem, + const IMeshBuffer* original, + const quake3::IShader* shader + ); + + virtual ~CQuake3ShaderSceneNode(); + + virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; + virtual void render() _IRR_OVERRIDE_; + virtual void OnAnimate(u32 timeMs) _IRR_OVERRIDE_; + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + virtual u32 getMaterialCount() const _IRR_OVERRIDE_; + virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_Q3SHADER_SCENE_NODE; } + + virtual void setMesh(IMesh* mesh)_IRR_OVERRIDE_ {} + virtual IMesh* getMesh() _IRR_OVERRIDE_ { return Mesh; } + virtual void setReadOnlyMaterials(bool readonly) _IRR_OVERRIDE_ {} + virtual bool isReadOnlyMaterials() const _IRR_OVERRIDE_ { return true; } + + //! Creates shadow volume scene node as child of this node + //! and returns a pointer to it. + virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh, + s32 id, bool zfailmethod=true, f32 infinity=10000.0f) _IRR_OVERRIDE_; + + //! Removes a child from this scene node. + //! Implemented here, to be able to remove the shadow properly, if there is one, + //! or to remove attached childs. + virtual bool removeChild(ISceneNode* child) _IRR_OVERRIDE_; + +private: + const quake3::IShader* Shader; + SMesh *Mesh; + IShadowVolumeSceneNode* Shadow; + const SMeshBufferLightMap* Original; + SMeshBuffer* MeshBuffer; + core::vector3df MeshOffset; + + struct SQ3Texture + { + SQ3Texture () : + TextureIndex ( 0 ), + TextureFrequency(0.f), + TextureAddressMode( video::ETC_REPEAT ) + { + Texture.setAllocStrategy ( core::ALLOC_STRATEGY_SAFE ); + } + + quake3::tTexArray Texture; + + u32 TextureIndex; + f32 TextureFrequency; + video::E_TEXTURE_CLAMP TextureAddressMode; // Wrapping/Clamping + }; + + core::array< SQ3Texture > Q3Texture; + + void loadTextures ( io::IFileSystem * fileSystem ); + void addBuffer ( scene::SMeshBufferLightMap * buffer ); + void cloneBuffer ( scene::SMeshBuffer *dest, const scene::SMeshBufferLightMap * buffer, bool translateCenter ); + + void deformvertexes_wave ( f32 dt, quake3::SModifierFunction &function ); + void deformvertexes_move ( f32 dt, quake3::SModifierFunction &function ); + void deformvertexes_bulge( f32 dt, quake3::SModifierFunction &function ); + void deformvertexes_autosprite( f32 dt, quake3::SModifierFunction &function ); + void deformvertexes_autosprite2( f32 dt, quake3::SModifierFunction &function ); + void deformvertexes_normal ( f32 dt, quake3::SModifierFunction &function ); + + void vertextransform_tcgen ( f32 dt, quake3::SModifierFunction &function ); + void vertextransform_rgbgen ( f32 dt, quake3::SModifierFunction &function ); + void vertextransform_alphagen ( f32 dt, quake3::SModifierFunction &function ); + + void transformtex ( const core::matrix4 &m, const u32 clamp ); + + f32 TimeAbs; + + void animate( u32 stage, core::matrix4 &texture ); + + E_SCENE_NODE_RENDER_PASS getRenderStage() const; + +}; + + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/source/Irrlicht/CReadFile.cpp b/source/Irrlicht/CReadFile.cpp new file mode 100644 index 00000000..cf90f54b --- /dev/null +++ b/source/Irrlicht/CReadFile.cpp @@ -0,0 +1,113 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CReadFile.h" + +namespace irr +{ +namespace io +{ + + +CReadFile::CReadFile(const io::path& fileName) +: File(0), FileSize(0), Filename(fileName) +{ + #ifdef _DEBUG + setDebugName("CReadFile"); + #endif + + openFile(); +} + + +CReadFile::~CReadFile() +{ + if (File) + fclose(File); +} + + +//! returns how much was read +size_t CReadFile::read(void* buffer, size_t sizeToRead) +{ + if (!isOpen()) + return 0; + + return fread(buffer, 1, sizeToRead, File); +} + + +//! 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 CReadFile::seek(long finalPos, bool relativeMovement) +{ + if (!isOpen()) + return false; + + return fseek(File, finalPos, relativeMovement ? SEEK_CUR : SEEK_SET) == 0; +} + + +//! returns size of file +long CReadFile::getSize() const +{ + return FileSize; +} + + +//! returns where in the file we are. +long CReadFile::getPos() const +{ + return ftell(File); +} + + +//! opens the file +void CReadFile::openFile() +{ + if (Filename.size() == 0) // bugfix posted by rt + { + File = 0; + return; + } + +#if defined ( _IRR_WCHAR_FILESYSTEM ) + File = _wfopen(Filename.c_str(), L"rb"); +#else + File = fopen(Filename.c_str(), "rb"); +#endif + + if (File) + { + // get FileSize + + fseek(File, 0, SEEK_END); + FileSize = getPos(); + fseek(File, 0, SEEK_SET); + } +} + + +//! returns name of file +const io::path& CReadFile::getFileName() const +{ + return Filename; +} + + +IReadFile* CReadFile::createReadFile(const io::path& fileName) +{ + CReadFile* file = new CReadFile(fileName); + if (file->isOpen()) + return file; + + file->drop(); + return 0; +} + + +} // end namespace io +} // end namespace irr + diff --git a/source/Irrlicht/CReadFile.h b/source/Irrlicht/CReadFile.h new file mode 100644 index 00000000..d0a3cac3 --- /dev/null +++ b/source/Irrlicht/CReadFile.h @@ -0,0 +1,73 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_READ_FILE_H_INCLUDED__ +#define __C_READ_FILE_H_INCLUDED__ + +#include +#include "IReadFile.h" +#include "irrString.h" + +namespace irr +{ + +namespace io +{ + + /*! + Class for reading a real file from disk. + */ + class CReadFile : public IReadFile + { + public: + + CReadFile(const io::path& fileName); + + virtual ~CReadFile(); + + //! returns how much was read + virtual size_t read(void* buffer, size_t sizeToRead) _IRR_OVERRIDE_; + + //! changes position in file, returns true if successful + virtual bool seek(long finalPos, bool relativeMovement = false) _IRR_OVERRIDE_; + + //! returns size of file + virtual long getSize() const _IRR_OVERRIDE_; + + //! returns if file is open + bool isOpen() const + { + return File != 0; + } + + //! returns where in the file we are. + virtual long getPos() const _IRR_OVERRIDE_; + + //! returns name of file + virtual const io::path& getFileName() const _IRR_OVERRIDE_; + + //! Get the type of the class implementing this interface + virtual EREAD_FILE_TYPE getType() const _IRR_OVERRIDE_ + { + return ERFT_READ_FILE; + } + + //! create read file on disk. + static IReadFile* createReadFile(const io::path& fileName); + + private: + + //! opens the file + void openFile(); + + FILE* File; + long FileSize; + io::path Filename; + }; + +} // end namespace io +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CSMFMeshFileLoader.cpp b/source/Irrlicht/CSMFMeshFileLoader.cpp new file mode 100644 index 00000000..d6ddb133 --- /dev/null +++ b/source/Irrlicht/CSMFMeshFileLoader.cpp @@ -0,0 +1,242 @@ +// Copyright (C) 2010-2012 Gaz Davidson / Joseph Ellis +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_SMF_LOADER_ + +#include "CSMFMeshFileLoader.h" +#include "CMeshTextureLoader.h" +#include "SAnimatedMesh.h" +#include "SMeshBuffer.h" +#include "IReadFile.h" +#include "coreutil.h" +#include "os.h" +#include "IVideoDriver.h" + +namespace irr +{ +namespace scene +{ + +CSMFMeshFileLoader::CSMFMeshFileLoader(irr::io::IFileSystem* fs, video::IVideoDriver* driver) +{ + TextureLoader = new CMeshTextureLoader( fs, driver ); +} + +//! Returns true if the file might be loaded by this class. +bool CSMFMeshFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension(filename, "smf"); +} + +//! Creates/loads an animated mesh from the file. +IAnimatedMesh* CSMFMeshFileLoader::createMesh(io::IReadFile* file) +{ + if ( !file ) + return 0; + + if ( getMeshTextureLoader() ) + getMeshTextureLoader()->setMeshFile(file); + + // create empty mesh + SMesh *mesh = new SMesh(); + + // load file + u16 version; + u8 flags; + s32 limbCount; + s32 i; + + io::BinaryFile::read(file, version); + io::BinaryFile::read(file, flags); + io::BinaryFile::read(file, limbCount); + + // load mesh data + core::matrix4 identity; + for (i=0; i < limbCount; ++i) + loadLimb(file, mesh, identity); + + // recalculate buffer bounding boxes + for (i=0; i < (s32)mesh->getMeshBufferCount(); ++i) + mesh->getMeshBuffer(i)->recalculateBoundingBox(); + + mesh->recalculateBoundingBox(); + SAnimatedMesh *am = new SAnimatedMesh(); + am->addMesh(mesh); + mesh->drop(); + am->recalculateBoundingBox(); + + return am; +} + +void CSMFMeshFileLoader::loadLimb(io::IReadFile* file, SMesh* mesh, const core::matrix4 &parentTransformation) +{ + core::matrix4 transformation; + + // limb transformation + core::vector3df translate, rotate, scale; + io::BinaryFile::read(file, translate); + io::BinaryFile::read(file, rotate); + io::BinaryFile::read(file, scale); + + transformation.setTranslation(translate); + transformation.setRotationDegrees(rotate); + transformation.setScale(scale); + + transformation = parentTransformation * transformation; + + core::stringc textureName, textureGroupName; + + // texture information + io::BinaryFile::read(file, textureGroupName); + io::BinaryFile::read(file, textureName); + + // attempt to load texture using known formats + video::ITexture* texture = 0; + + const c8* extensions[] = {".jpg", ".png", ".tga", ".bmp", 0}; + + for (const c8 **ext = extensions; !texture && *ext; ++ext) + { + texture = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture(textureName + *ext) : NULL; + if (texture) + { + textureName = textureName + *ext; + break; + } + } + // find the correct mesh buffer + u32 i; + for (i=0; iMeshBuffers.size(); ++i) + if (mesh->MeshBuffers[i]->getMaterial().TextureLayer[0].Texture == texture) + break; + + // create mesh buffer if none was found + if (i == mesh->MeshBuffers.size()) + { + CMeshBuffer* mb = new CMeshBuffer(); + mb->Material.TextureLayer[0].Texture = texture; + + // horribly hacky way to do this, maybe it's in the flags? + if (core::hasFileExtension(textureName, "tga", "png")) + mb->Material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + else + mb->Material.MaterialType = video::EMT_SOLID; + + mesh->MeshBuffers.push_back(mb); + } + + CMeshBuffer* mb = (CMeshBuffer*)mesh->MeshBuffers[i]; + + u16 vertexCount, firstVertex = mb->getVertexCount(); + + io::BinaryFile::read(file, vertexCount); + mb->Vertices.reallocate(mb->Vertices.size() + vertexCount); + + // add vertices and set positions + for (i=0; iVertices.push_back(vert); + } + + // set vertex normals + for (i=0; i < vertexCount; ++i) + { + core::vector3df normal; + io::BinaryFile::read(file, normal); + transformation.rotateVect(normal); + mb->Vertices[firstVertex + i].Normal = normal; + } + // set texture coordinates + + for (i=0; i < vertexCount; ++i) + { + core::vector2df tcoords; + io::BinaryFile::read(file, tcoords); + mb->Vertices[firstVertex + i].TCoords = tcoords; + } + + // triangles + u32 triangleCount; + // vertexCount used as temporary + io::BinaryFile::read(file, vertexCount); + triangleCount=3*vertexCount; + mb->Indices.reallocate(mb->Indices.size() + triangleCount); + + for (i=0; i < triangleCount; ++i) + { + u16 index; + io::BinaryFile::read(file, index); + mb->Indices.push_back(firstVertex + index); + } + + // read limbs + s32 limbCount; + io::BinaryFile::read(file, limbCount); + + for (s32 l=0; l < limbCount; ++l) + loadLimb(file, mesh, transformation); +} + +} // namespace scene + +// todo: at some point in the future let's move these to a place where everyone can use them. +namespace io +{ + +#if _BIGENDIAN +#define _SYSTEM_BIG_ENDIAN_ (true) +#else +#define _SYSTEM_BIG_ENDIAN_ (false) +#endif + +template +void BinaryFile::read(io::IReadFile* file, T &out, bool bigEndian) +{ + file->read((void*)&out, sizeof(out)); + if (bigEndian != (_SYSTEM_BIG_ENDIAN_)) + out = os::Byteswap::byteswap(out); +} + +//! reads a 3d vector from the file, moving the file pointer along +void BinaryFile::read(io::IReadFile* file, core::vector3df &outVector2d, bool bigEndian) +{ + BinaryFile::read(file, outVector2d.X, bigEndian); + BinaryFile::read(file, outVector2d.Y, bigEndian); + BinaryFile::read(file, outVector2d.Z, bigEndian); +} + +//! reads a 2d vector from the file, moving the file pointer along +void BinaryFile::read(io::IReadFile* file, core::vector2df &outVector2d, bool bigEndian) +{ + BinaryFile::read(file, outVector2d.X, bigEndian); + BinaryFile::read(file, outVector2d.Y, bigEndian); +} + +//! reads a null terminated string from the file, moving the file pointer along +void BinaryFile::read(io::IReadFile* file, core::stringc &outString, bool bigEndian) +{ + c8 c; + file->read((void*)&c, 1); + + while (c) + { + outString += c; + file->read((void*)&c, 1); + } +} + +} // namespace io + +} // namespace irr + +#endif // compile with SMF loader + diff --git a/source/Irrlicht/CSMFMeshFileLoader.h b/source/Irrlicht/CSMFMeshFileLoader.h new file mode 100644 index 00000000..9f89ef75 --- /dev/null +++ b/source/Irrlicht/CSMFMeshFileLoader.h @@ -0,0 +1,69 @@ +// Copyright (C) 2010-2012 Gaz Davidson +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_SMF_MESH_LOADER_H_INCLUDED__ +#define __C_SMF_MESH_LOADER_H_INCLUDED__ + +#include "IMeshLoader.h" +#include "SMesh.h" + +namespace irr +{ + +namespace video +{ + class IVideoDriver; +} +namespace io +{ + class IFileSystem; +} + +namespace scene +{ + +//! Class which can load +class CSMFMeshFileLoader : public virtual IMeshLoader +{ +public: + + CSMFMeshFileLoader(irr::io::IFileSystem* fs, video::IVideoDriver* driver); + + //! Returns true if the file might be loaded by this class. + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! Creates/loads an animated mesh from the file. + virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_; +private: + + void loadLimb(io::IReadFile* file, scene::SMesh* mesh, const core::matrix4 &parentTransformation); +}; + +} // end namespace scene + +namespace io +{ + class BinaryFile + { + public: + //! reads most types from the given file, moving the file pointer along + template + static void read(io::IReadFile* file, T &out, bool bigEndian=false); + + //! reads a 3d vector from the file, moving the file pointer along + static void read(io::IReadFile* file, core::vector3df &outVector2d, bool bigEndian=false); + + //! reads a 2d vector from the file, moving the file pointer along + static void read(io::IReadFile* file, core::vector2df &outVector2d, bool bigEndian=false); + + //! reads a null terminated string from the file, moving the file pointer along + static void read(io::IReadFile* file, core::stringc &outString, bool bigEndian=false); + + }; +} + +} // end namespace irr + +#endif // __C_SMF_MESH_LOADER_H_INCLUDED__ + diff --git a/source/Irrlicht/CSTLMeshFileLoader.cpp b/source/Irrlicht/CSTLMeshFileLoader.cpp new file mode 100644 index 00000000..bf9ffb30 --- /dev/null +++ b/source/Irrlicht/CSTLMeshFileLoader.cpp @@ -0,0 +1,253 @@ +// Copyright (C) 2007-2012 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_STL_LOADER_ + +#include "CSTLMeshFileLoader.h" +#include "SMesh.h" +#include "SMeshBuffer.h" +#include "SAnimatedMesh.h" +#include "IReadFile.h" +#include "fast_atof.h" +#include "coreutil.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool CSTLMeshFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "stl" ); +} + + + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IReferenceCounted::drop() for more information. +IAnimatedMesh* CSTLMeshFileLoader::createMesh(io::IReadFile* file) +{ + const long filesize = file->getSize(); + if (filesize < 6) // we need a header + return 0; + + SMesh* mesh = new SMesh(); + SMeshBuffer* meshBuffer = new SMeshBuffer(); + mesh->addMeshBuffer(meshBuffer); + meshBuffer->drop(); + + core::vector3df vertex[3]; + core::vector3df normal; + + bool binary = false; + core::stringc token; + if (getNextToken(file, token) != "solid") + binary = true; + // read/skip header + u32 binFaceCount = 0; + if (binary) + { + file->seek(80); + file->read(&binFaceCount, 4); +#ifdef __BIG_ENDIAN__ + binFaceCount = os::Byteswap::byteswap(binFaceCount); +#endif + } + else + goNextLine(file); + + u16 attrib=0; + token.reserve(32); + + while (file->getPos() < filesize) + { + if (!binary) + { + if (getNextToken(file, token) != "facet") + { + if (token=="endsolid") + break; + mesh->drop(); + return 0; + } + if (getNextToken(file, token) != "normal") + { + mesh->drop(); + return 0; + } + } + getNextVector(file, normal, binary); + if (!binary) + { + if (getNextToken(file, token) != "outer") + { + mesh->drop(); + return 0; + } + if (getNextToken(file, token) != "loop") + { + mesh->drop(); + return 0; + } + } + for (u32 i=0; i<3; ++i) + { + if (!binary) + { + if (getNextToken(file, token) != "vertex") + { + mesh->drop(); + return 0; + } + } + getNextVector(file, vertex[i], binary); + } + if (!binary) + { + if (getNextToken(file, token) != "endloop") + { + mesh->drop(); + return 0; + } + if (getNextToken(file, token) != "endfacet") + { + mesh->drop(); + return 0; + } + } + else + { + file->read(&attrib, 2); +#ifdef __BIG_ENDIAN__ + attrib = os::Byteswap::byteswap(attrib); +#endif + } + + SMeshBuffer* mb = reinterpret_cast(mesh->getMeshBuffer(mesh->getMeshBufferCount()-1)); + u32 vCount = mb->getVertexCount(); + video::SColor color(0xffffffff); + if (attrib & 0x8000) + color = video::A1R5G5B5toA8R8G8B8(attrib); + if (normal==core::vector3df()) + normal=core::plane3df(vertex[2],vertex[1],vertex[0]).Normal; + mb->Vertices.push_back(video::S3DVertex(vertex[2],normal,color, core::vector2df())); + mb->Vertices.push_back(video::S3DVertex(vertex[1],normal,color, core::vector2df())); + mb->Vertices.push_back(video::S3DVertex(vertex[0],normal,color, core::vector2df())); + mb->Indices.push_back(vCount); + mb->Indices.push_back(vCount+1); + mb->Indices.push_back(vCount+2); + } // end while (file->getPos() < filesize) + mesh->getMeshBuffer(0)->recalculateBoundingBox(); + + // Create the Animated mesh if there's anything in the mesh + SAnimatedMesh* pAM = 0; + if ( 0 != mesh->getMeshBufferCount() ) + { + mesh->recalculateBoundingBox(); + pAM = new SAnimatedMesh(); + pAM->Type = EAMT_OBJ; + pAM->addMesh(mesh); + pAM->recalculateBoundingBox(); + } + + mesh->drop(); + + return pAM; +} + + +//! Read 3d vector of floats +void CSTLMeshFileLoader::getNextVector(io::IReadFile* file, core::vector3df& vec, bool binary) const +{ + if (binary) + { + file->read(&vec.X, 4); + file->read(&vec.Y, 4); + file->read(&vec.Z, 4); +#ifdef __BIG_ENDIAN__ + vec.X = os::Byteswap::byteswap(vec.X); + vec.Y = os::Byteswap::byteswap(vec.Y); + vec.Z = os::Byteswap::byteswap(vec.Z); +#endif + } + else + { + goNextWord(file); + core::stringc tmp; + + getNextToken(file, tmp); + core::fast_atof_move(tmp.c_str(), vec.X); + getNextToken(file, tmp); + core::fast_atof_move(tmp.c_str(), vec.Y); + getNextToken(file, tmp); + core::fast_atof_move(tmp.c_str(), vec.Z); + } + vec.X=-vec.X; +} + + +//! Read next word +const core::stringc& CSTLMeshFileLoader::getNextToken(io::IReadFile* file, core::stringc& token) const +{ + goNextWord(file); + u8 c; + token = ""; + while(file->getPos() != file->getSize()) + { + file->read(&c, 1); + // found it, so leave + if (core::isspace(c)) + break; + token.append(c); + } + return token; +} + + +//! skip to next word +void CSTLMeshFileLoader::goNextWord(io::IReadFile* file) const +{ + u8 c; + while(file->getPos() != file->getSize()) + { + file->read(&c, 1); + // found it, so leave + if (!core::isspace(c)) + { + file->seek(-1, true); + break; + } + } +} + + +//! Read until line break is reached and stop at the next non-space character +void CSTLMeshFileLoader::goNextLine(io::IReadFile* file) const +{ + u8 c; + // look for newline characters + while(file->getPos() != file->getSize()) + { + file->read(&c, 1); + // found it, so leave + if (c=='\n' || c=='\r') + break; + } +} + + +} // end namespace scene +} // end namespace irr + + +#endif // _IRR_COMPILE_WITH_STL_LOADER_ + diff --git a/source/Irrlicht/CSTLMeshFileLoader.h b/source/Irrlicht/CSTLMeshFileLoader.h new file mode 100644 index 00000000..d15a9f42 --- /dev/null +++ b/source/Irrlicht/CSTLMeshFileLoader.h @@ -0,0 +1,49 @@ +// Copyright (C) 2007-2012 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_STL_MESH_FILE_LOADER_H_INCLUDED__ +#define __C_STL_MESH_FILE_LOADER_H_INCLUDED__ + +#include "IMeshLoader.h" +#include "irrString.h" +#include "vector3d.h" + +namespace irr +{ +namespace scene +{ + +//! Meshloader capable of loading STL meshes. +class CSTLMeshFileLoader : public IMeshLoader +{ +public: + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (i.e. ".stl") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! creates/loads an animated mesh from the file. + //! \return Pointer to the created mesh. Returns 0 if loading failed. + //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). + //! See IReferenceCounted::drop() for more information. + virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_; + +private: + + // skips to the first non-space character available + void goNextWord(io::IReadFile* file) const; + // returns the next word + const core::stringc& getNextToken(io::IReadFile* file, core::stringc& token) const; + // skip to next printable character after the first line break + void goNextLine(io::IReadFile* file) const; + + //! Read 3d vector of floats + void getNextVector(io::IReadFile* file, core::vector3df& vec, bool binary) const; +}; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CSTLMeshWriter.cpp b/source/Irrlicht/CSTLMeshWriter.cpp new file mode 100644 index 00000000..f3b14133 --- /dev/null +++ b/source/Irrlicht/CSTLMeshWriter.cpp @@ -0,0 +1,187 @@ +// Copyright (C) 2002-2012 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" + +#ifdef _IRR_COMPILE_WITH_STL_WRITER_ + +#include "CSTLMeshWriter.h" +#include "os.h" +#include "IMesh.h" +#include "IMeshBuffer.h" +#include "IAttributes.h" +#include "ISceneManager.h" +#include "IMeshCache.h" +#include "IWriteFile.h" + +namespace irr +{ +namespace scene +{ + +CSTLMeshWriter::CSTLMeshWriter(scene::ISceneManager* smgr) + : SceneManager(smgr) +{ + #ifdef _DEBUG + setDebugName("CSTLMeshWriter"); + #endif + + if (SceneManager) + SceneManager->grab(); +} + + +CSTLMeshWriter::~CSTLMeshWriter() +{ + if (SceneManager) + SceneManager->drop(); +} + + +//! Returns the type of the mesh writer +EMESH_WRITER_TYPE CSTLMeshWriter::getType() const +{ + return EMWT_STL; +} + + +//! writes a mesh +bool CSTLMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags) +{ + if (!file) + return false; + + os::Printer::log("Writing mesh", file->getFileName()); + + if (flags & (scene::EMWF_WRITE_BINARY|scene::EMWF_WRITE_COMPRESSED) ) + return writeMeshBinary(file, mesh, flags); + else + return writeMeshASCII(file, mesh, flags); +} + + +bool CSTLMeshWriter::writeMeshBinary(io::IWriteFile* file, scene::IMesh* mesh, s32 flags) +{ + // write STL MESH header + + file->write("binary ",7); + const core::stringc name(SceneManager->getMeshCache()->getMeshName(mesh)); + const s32 sizeleft = 73-name.size(); // 80 byte header + if (sizeleft<0) + file->write(name.c_str(),73); + else + { + char* buf = new char[80]; + memset(buf, 0, 80); + file->write(name.c_str(),name.size()); + file->write(buf,sizeleft); + delete [] buf; + } + u32 facenum = 0; + for (u32 j=0; jgetMeshBufferCount(); ++j) + facenum += mesh->getMeshBuffer(j)->getIndexCount()/3; + file->write(&facenum,4); + + // write mesh buffers + + for (u32 i=0; igetMeshBufferCount(); ++i) + { + IMeshBuffer* buffer = mesh->getMeshBuffer(i); + if (buffer) + { + const u32 indexCount = buffer->getIndexCount(); + const u16 attributes = 0; + for (u32 j=0; jgetPosition(buffer->getIndices()[j]); + const core::vector3df& v2 = buffer->getPosition(buffer->getIndices()[j+1]); + const core::vector3df& v3 = buffer->getPosition(buffer->getIndices()[j+2]); + const core::plane3df tmpplane(v1,v2,v3); + file->write(&tmpplane.Normal, 12); + file->write(&v1, 12); + file->write(&v2, 12); + file->write(&v3, 12); + file->write(&attributes, 2); + } + } + } + return true; +} + + +bool CSTLMeshWriter::writeMeshASCII(io::IWriteFile* file, scene::IMesh* mesh, s32 flags) +{ + // write STL MESH header + + file->write("solid ",6); + const core::stringc name(SceneManager->getMeshCache()->getMeshName(mesh)); + file->write(name.c_str(),name.size()); + file->write("\n\n",2); + + // write mesh buffers + + for (u32 i=0; igetMeshBufferCount(); ++i) + { + IMeshBuffer* buffer = mesh->getMeshBuffer(i); + if (buffer) + { + const u32 indexCount = buffer->getIndexCount(); + for (u32 j=0; jgetPosition(buffer->getIndices()[j]), + buffer->getPosition(buffer->getIndices()[j+1]), + buffer->getPosition(buffer->getIndices()[j+2])); + } + file->write("\n",1); + } + } + + file->write("endsolid ",9); + file->write(name.c_str(),name.size()); + + return true; +} + + +void CSTLMeshWriter::getVectorAsStringLine(const core::vector3df& v, core::stringc& s) const +{ + s = core::stringc(v.X); + s += " "; + s += core::stringc(v.Y); + s += " "; + s += core::stringc(v.Z); + s += "\n"; +} + + +void CSTLMeshWriter::writeFace(io::IWriteFile* file, + const core::vector3df& v1, + const core::vector3df& v2, + const core::vector3df& v3) +{ + core::stringc tmp; + file->write("facet normal ",13); + getVectorAsStringLine(core::plane3df(v1,v2,v3).Normal, tmp); + file->write(tmp.c_str(),tmp.size()); + file->write(" outer loop\n",13); + file->write(" vertex ",11); + getVectorAsStringLine(v1, tmp); + file->write(tmp.c_str(),tmp.size()); + file->write(" vertex ",11); + getVectorAsStringLine(v2, tmp); + file->write(tmp.c_str(),tmp.size()); + file->write(" vertex ",11); + getVectorAsStringLine(v3, tmp); + file->write(tmp.c_str(),tmp.size()); + file->write(" endloop\n",10); + file->write("endfacet\n",9); +} + + +} // end namespace +} // end namespace + +#endif + diff --git a/source/Irrlicht/CSTLMeshWriter.h b/source/Irrlicht/CSTLMeshWriter.h new file mode 100644 index 00000000..18ac6b70 --- /dev/null +++ b/source/Irrlicht/CSTLMeshWriter.h @@ -0,0 +1,55 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_STL_MESH_WRITER_H_INCLUDED__ +#define __IRR_STL_MESH_WRITER_H_INCLUDED__ + +#include "IMeshWriter.h" +#include "S3DVertex.h" +#include "irrString.h" + +namespace irr +{ +namespace scene +{ + class IMeshBuffer; + class ISceneManager; + + //! class to write meshes, implementing a STL writer + class CSTLMeshWriter : public IMeshWriter + { + public: + + CSTLMeshWriter(scene::ISceneManager* smgr); + virtual ~CSTLMeshWriter(); + + //! Returns the type of the mesh writer + virtual EMESH_WRITER_TYPE getType() const _IRR_OVERRIDE_; + + //! writes a mesh + virtual bool writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags=EMWF_NONE) _IRR_OVERRIDE_; + + protected: + // write binary format + bool writeMeshBinary(io::IWriteFile* file, scene::IMesh* mesh, s32 flags); + + // write text format + bool writeMeshASCII(io::IWriteFile* file, scene::IMesh* mesh, s32 flags); + + // create vector output with line end into string + void getVectorAsStringLine(const core::vector3df& v, + core::stringc& s) const; + + // write face information to file + void writeFace(io::IWriteFile* file, const core::vector3df& v1, + const core::vector3df& v2, const core::vector3df& v3); + + scene::ISceneManager* SceneManager; + }; + +} // end namespace +} // end namespace + +#endif + diff --git a/source/Irrlicht/CSceneCollisionManager.cpp b/source/Irrlicht/CSceneCollisionManager.cpp new file mode 100644 index 00000000..78ba1318 --- /dev/null +++ b/source/Irrlicht/CSceneCollisionManager.cpp @@ -0,0 +1,983 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CSceneCollisionManager.h" +#include "ISceneNode.h" +#include "ICameraSceneNode.h" +#include "ITriangleSelector.h" +#include "SViewFrustum.h" + +#include "os.h" +#include "irrMath.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CSceneCollisionManager::CSceneCollisionManager(ISceneManager* smanager, video::IVideoDriver* driver) +: SceneManager(smanager), Driver(driver) +{ + #ifdef _DEBUG + setDebugName("CSceneCollisionManager"); + #endif + + if (Driver) + Driver->grab(); +} + + +//! destructor +CSceneCollisionManager::~CSceneCollisionManager() +{ + if (Driver) + Driver->drop(); +} + + +//! Returns the scene node, which is currently visible at the given +//! screen coordinates, viewed from the currently active camera. +ISceneNode* CSceneCollisionManager::getSceneNodeFromScreenCoordinatesBB( + const core::position2d& pos, s32 idBitMask, bool noDebugObjects, scene::ISceneNode* root) +{ + const core::line3d ln = getRayFromScreenCoordinates(pos, 0); + + if ( ln.start == ln.end ) + return 0; + + return getSceneNodeFromRayBB(ln, idBitMask, noDebugObjects, root); +} + + +//! Returns the nearest scene node which collides with a 3d ray and +//! which id matches a bitmask. +ISceneNode* CSceneCollisionManager::getSceneNodeFromRayBB( + const core::line3d& ray, + s32 idBitMask, bool noDebugObjects, scene::ISceneNode* root) +{ + ISceneNode* best = 0; + f32 dist = FLT_MAX; + + core::line3d truncatableRay(ray); + + getPickedNodeBB((root==0)?SceneManager->getRootSceneNode():root, truncatableRay, + idBitMask, noDebugObjects, dist, best); + + return best; +} + + +//! recursive method for going through all scene nodes +void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root, + core::line3df& ray, s32 bits, bool noDebugObjects, + f32& outbestdistance, ISceneNode*& outbestnode) +{ + const ISceneNodeList& children = root->getChildren(); + const core::vector3df rayVector = ray.getVector().normalize(); + + ISceneNodeList::ConstIterator it = children.begin(); + for (; it != children.end(); ++it) + { + ISceneNode* current = *it; + + if (current->isVisible()) + { + if((noDebugObjects ? !current->isDebugObject() : true) && + (bits==0 || (bits != 0 && (current->getID() & bits)))) + { + // Assume that single-point bounding-boxes are not meant for collision + const core::aabbox3df & objectBox = current->getBoundingBox(); + if ( objectBox.isEmpty() ) + continue; + + // 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 objectRay(ray); + worldToObject.transformVect(objectRay.start); + worldToObject.transformVect(objectRay.end); + + // Do the initial intersection test in object space, since the + // object space box test is more accurate. + if(objectBox.isPointInside(objectRay.start)) + { + // use fast bbox intersection to find distance to hitpoint + // algorithm from Kay et al., code from gamedev.net + const core::vector3df dir = (objectRay.end-objectRay.start).normalize(); + const core::vector3df minDist = (objectBox.MinEdge - objectRay.start)/dir; + const core::vector3df maxDist = (objectBox.MaxEdge - objectRay.start)/dir; + const core::vector3df realMin(core::min_(minDist.X, maxDist.X),core::min_(minDist.Y, maxDist.Y),core::min_(minDist.Z, maxDist.Z)); + const core::vector3df realMax(core::max_(minDist.X, maxDist.X),core::max_(minDist.Y, maxDist.Y),core::max_(minDist.Z, maxDist.Z)); + + const f32 minmax = core::min_(realMax.X, realMax.Y, realMax.Z); + // nearest distance to intersection + const f32 maxmin = core::max_(realMin.X, realMin.Y, realMin.Z); + + const f32 toIntersectionSq = (maxmin>0?maxmin*maxmin:minmax*minmax); + if (toIntersectionSq < outbestdistance) + { + outbestdistance = toIntersectionSq; + outbestnode = current; + + // 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().transformBoxEx(worldBox); + + core::vector3df edges[8]; + worldBox.getEdges(edges); + + /* 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; + f32 bestDistToBoxBorder = FLT_MAX; + f32 bestToIntersectionSq = FLT_MAX; + + for(s32 face = 0; face < 6; ++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. + worldToObject.transformVect(intersection); + + // find the closest point on the box borders. Have to do this as exact checks will fail due to floating point problems. + f32 distToBorder = core::max_ ( core::min_ (core::abs_(objectBox.MinEdge.X-intersection.X), core::abs_(objectBox.MaxEdge.X-intersection.X)), + core::min_ (core::abs_(objectBox.MinEdge.Y-intersection.Y), core::abs_(objectBox.MaxEdge.Y-intersection.Y)), + core::min_ (core::abs_(objectBox.MinEdge.Z-intersection.Z), core::abs_(objectBox.MaxEdge.Z-intersection.Z)) ); + if ( distToBorder < bestDistToBoxBorder ) + { + bestDistToBoxBorder = distToBorder; + bestToIntersectionSq = toIntersectionSq; + } + } + } + + // 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 (!(face & 0x01)) + ++face; + } + + if ( bestDistToBoxBorder < FLT_MAX ) + { + outbestdistance = bestToIntersectionSq; + outbestnode = current; + + // If we got a hit, we can now truncate the ray to stop us hitting further nodes. + ray.end = ray.start + (rayVector * sqrtf(outbestdistance)); + } + } + } + + // Only check the children if this node is visible. + getPickedNodeBB(current, ray, bits, noDebugObjects, outbestdistance, outbestnode); + } + } +} + + +ISceneNode* CSceneCollisionManager::getSceneNodeAndCollisionPointFromRay( + SCollisionHit& hitResult, + const core::line3df& ray, + s32 idBitMask, + ISceneNode * collisionRootNode, + bool noDebugObjects) +{ + if(0 == collisionRootNode) + collisionRootNode = SceneManager->getRootSceneNode(); + + // We don't try to do anything too clever, like sorting the candidate + // nodes by distance to bounding-box. In the example below, we could do the + // triangle collision check with node A first, but we'd have to check node B + // anyway, as the actual collision point could be (and is) closer than the + // collision point in node A. + // + // ray end + // | + // AAAAAAAAAA + // A | + // A | B + // A | B + // A BBBBB + // A | + // A | + // | + // | + // ray start + // + // We therefore have to do a full BB and triangle collision on every scene + // node in order to find the nearest collision point, so sorting them by + // bounding box would be pointless. + + f32 bestDistanceSquared = FLT_MAX; + core::line3df rayRest(ray); + getPickedNodeFromBBAndSelector(hitResult, collisionRootNode, rayRest, idBitMask, + noDebugObjects, bestDistanceSquared); + return hitResult.Node; +} + + +void CSceneCollisionManager::getPickedNodeFromBBAndSelector( + SCollisionHit& hitResult, + ISceneNode * root, + core::line3df & ray, + s32 bits, + bool noDebugObjects, + f32 & outBestDistanceSquared) +{ + const ISceneNodeList& children = root->getChildren(); + + ISceneNodeList::ConstIterator it = children.begin(); + for (; it != children.end(); ++it) + { + ISceneNode* current = *it; + ITriangleSelector * selector = current->getTriangleSelector(); + + if (selector && current->isVisible() && + (noDebugObjects ? !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; + + // transform vector from world space to object space + core::line3df line(ray); + mat.transformVect(line.start); + mat.transformVect(line.end); + + const core::aabbox3df& box = current->getBoundingBox(); + + SCollisionHit candidateHitResult; + + // do intersection test in object space + if (box.intersectsWithLine(line) && + getCollisionPoint(candidateHitResult, ray, selector)) + { + const f32 distanceSquared = (candidateHitResult.Intersection - ray.start).getLengthSQ(); + + if(distanceSquared < outBestDistanceSquared) + { + outBestDistanceSquared = distanceSquared; + hitResult = candidateHitResult; + const core::vector3df rayVector = ray.getVector().normalize(); + ray.end = ray.start + (rayVector * sqrtf(distanceSquared)); + } + } + } + + getPickedNodeFromBBAndSelector(hitResult, current, ray, bits, noDebugObjects, + outBestDistanceSquared); + } +} + + +//! Returns the scene node, at which the given camera is looking at and +//! which id matches the bitmask. +ISceneNode* CSceneCollisionManager::getSceneNodeFromCameraBB( + const ICameraSceneNode* camera, s32 idBitMask, bool noDebugObjects) +{ + if (!camera) + return 0; + + const core::vector3df start = camera->getAbsolutePosition(); + core::vector3df end = camera->getTarget(); + + end = start + ((end - start).normalize() * camera->getFarValue()); + + return getSceneNodeFromRayBB(core::line3d(start, end), idBitMask, noDebugObjects); +} + +bool CSceneCollisionManager::getCollisionPoint(SCollisionHit& hitResult, const core::line3d& ray, ITriangleSelector* selector) +{ + if (!selector) + { + return false; + } + + s32 totalcnt = selector->getTriangleCount(); + if ( totalcnt <= 0 ) + return false; + + Triangles.set_used(totalcnt); + + s32 cnt = 0; + irr::core::array outTriangleInfo; + selector->getTriangles(Triangles.pointer(), totalcnt, cnt, ray, 0, true, &outTriangleInfo); + + const core::vector3df linevect = ray.getVector().normalize(); + core::vector3df intersection; + f32 nearest = FLT_MAX; + irr::s32 foundIndex = -1; + const f32 raylength = ray.getLengthSQ(); + + const f32 minX = core::min_(ray.start.X, ray.end.X); + const f32 maxX = core::max_(ray.start.X, ray.end.X); + const f32 minY = core::min_(ray.start.Y, ray.end.Y); + const f32 maxY = core::max_(ray.start.Y, ray.end.Y); + const f32 minZ = core::min_(ray.start.Z, ray.end.Z); + const f32 maxZ = core::max_(ray.start.Z, ray.end.Z); + + for (s32 i=0; i triangle.pointA.X && minX > triangle.pointB.X && minX > triangle.pointC.X) + continue; + if(maxX < triangle.pointA.X && maxX < triangle.pointB.X && maxX < triangle.pointC.X) + continue; + if(minY > triangle.pointA.Y && minY > triangle.pointB.Y && minY > triangle.pointC.Y) + continue; + if(maxY < triangle.pointA.Y && maxY < triangle.pointB.Y && maxY < triangle.pointC.Y) + continue; + if(minZ > triangle.pointA.Z && minZ > triangle.pointB.Z && minZ > triangle.pointC.Z) + continue; + if(maxZ < triangle.pointA.Z && maxZ < triangle.pointB.Z && maxZ < triangle.pointC.Z) + continue; + + if (triangle.getIntersectionWithLine(ray.start, linevect, intersection)) + { + const f32 tmp = intersection.getDistanceFromSQ(ray.start); + const f32 tmp2 = intersection.getDistanceFromSQ(ray.end); + + if (tmp < raylength && tmp2 < raylength && tmp < nearest) + { + nearest = tmp; + + hitResult.Triangle = triangle; + hitResult.Intersection = intersection; + foundIndex = i; + } + } + } + + if ( foundIndex >= 0 ) + { + for ( irr::u32 t=0; t trianglePlane = triangle.getPlane(); + + // only check front facing polygons + if ( !trianglePlane.isFrontFacing(colData->normalizedVelocity) ) + return false; + + // get interval of plane intersection + + f32 t1, t0; + bool embeddedInPlane = false; + + // calculate signed distance from sphere position to triangle plane + f32 signedDistToTrianglePlane = trianglePlane.getDistanceTo( + colData->basePoint); + + f32 normalDotVelocity = + trianglePlane.Normal.dotProduct(colData->velocity); + + if ( core::iszero ( normalDotVelocity ) ) + { + // sphere is traveling parallel to plane + + if (fabs(signedDistToTrianglePlane) >= 1.0f) + return false; // no collision possible + else + { + // sphere is embedded in plane + embeddedInPlane = true; + t0 = 0.0; + t1 = 1.0; + } + } + else + { + normalDotVelocity = core::reciprocal ( normalDotVelocity ); + + // N.D is not 0. Calculate intersection interval + t0 = (-1.f - signedDistToTrianglePlane) * normalDotVelocity; + t1 = (1.f - signedDistToTrianglePlane) * normalDotVelocity; + + // Swap so t0 < t1 + if (t0 > t1) { f32 tmp = t1; t1 = t0; t0 = tmp; } + + // check if at least one value is within the range + if (t0 > 1.0f || t1 < 0.0f) + 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 ); + t1 = core::clamp ( t1, 0.f, 1.f ); + } + + // at this point we have t0 and t1, if there is any intersection, it + // is between this interval + core::vector3df collisionPoint; + bool foundCollision = false; + f32 t = 1.0f; + + // first check the easy case: Collision within the triangle; + // if this happens, it must be at t0 and this is when the sphere + // rests on the front side of the triangle plane. This can only happen + // if the sphere is not embedded in the triangle plane. + + if (!embeddedInPlane) + { + core::vector3df planeIntersectionPoint = + (colData->basePoint - trianglePlane.Normal) + + (colData->velocity * t0); + + if (triangle.isPointInside(planeIntersectionPoint)) + { + foundCollision = true; + t = t0; + collisionPoint = planeIntersectionPoint; + } + } + + // if we haven't found a collision already we will have to sweep + // the sphere against points and edges of the triangle. Note: A + // collision inside the triangle will always happen before a + // vertex or edge collision. + + if (!foundCollision) + { + core::vector3df velocity = colData->velocity; + core::vector3df base = colData->basePoint; + + f32 velocitySqaredLength = velocity.getLengthSQ(); + f32 a,b,c; + f32 newT; + + // for each edge or vertex a quadratic equation has to be solved: + // a*t^2 + b*t + c = 0. We calculate a,b, and c for each test. + + // check against points + a = velocitySqaredLength; + + // p1 + b = 2.0f * (velocity.dotProduct(base - triangle.pointA)); + c = (triangle.pointA-base).getLengthSQ() - 1.f; + if (getLowestRoot(a,b,c,t, &newT)) + { + t = newT; + foundCollision = true; + collisionPoint = triangle.pointA; + } + + // p2 + if (!foundCollision) + { + b = 2.0f * (velocity.dotProduct(base - triangle.pointB)); + c = (triangle.pointB-base).getLengthSQ() - 1.f; + if (getLowestRoot(a,b,c,t, &newT)) + { + t = newT; + foundCollision = true; + collisionPoint = triangle.pointB; + } + } + + // p3 + if (!foundCollision) + { + b = 2.0f * (velocity.dotProduct(base - triangle.pointC)); + c = (triangle.pointC-base).getLengthSQ() - 1.f; + if (getLowestRoot(a,b,c,t, &newT)) + { + t = newT; + foundCollision = true; + collisionPoint = triangle.pointC; + } + } + + // check against edges: + + // p1 --- p2 + core::vector3df edge = triangle.pointB - triangle.pointA; + core::vector3df baseToVertex = triangle.pointA - base; + f32 edgeSqaredLength = edge.getLengthSQ(); + f32 edgeDotVelocity = edge.dotProduct(velocity); + f32 edgeDotBaseToVertex = edge.dotProduct(baseToVertex); + + // calculate parameters for equation + a = edgeSqaredLength* -velocitySqaredLength + + edgeDotVelocity*edgeDotVelocity; + b = edgeSqaredLength* (2.f *velocity.dotProduct(baseToVertex)) - + 2.0f*edgeDotVelocity*edgeDotBaseToVertex; + c = edgeSqaredLength* (1.f -baseToVertex.getLengthSQ()) + + edgeDotBaseToVertex*edgeDotBaseToVertex; + + // does the swept sphere collide against infinite edge? + if (getLowestRoot(a,b,c,t,&newT)) + { + f32 f = (edgeDotVelocity*newT - edgeDotBaseToVertex) / edgeSqaredLength; + if (f >=0.0f && f <= 1.0f) + { + // intersection took place within segment + t = newT; + foundCollision = true; + collisionPoint = triangle.pointA + (edge*f); + } + } + + // p2 --- p3 + edge = triangle.pointC-triangle.pointB; + baseToVertex = triangle.pointB - base; + edgeSqaredLength = edge.getLengthSQ(); + edgeDotVelocity = edge.dotProduct(velocity); + edgeDotBaseToVertex = edge.dotProduct(baseToVertex); + + // calculate parameters for equation + a = edgeSqaredLength* -velocitySqaredLength + + edgeDotVelocity*edgeDotVelocity; + b = edgeSqaredLength* (2*velocity.dotProduct(baseToVertex)) - + 2.0f*edgeDotVelocity*edgeDotBaseToVertex; + c = edgeSqaredLength* (1-baseToVertex.getLengthSQ()) + + edgeDotBaseToVertex*edgeDotBaseToVertex; + + // does the swept sphere collide against infinite edge? + if (getLowestRoot(a,b,c,t,&newT)) + { + f32 f = (edgeDotVelocity*newT-edgeDotBaseToVertex) / + edgeSqaredLength; + if (f >=0.0f && f <= 1.0f) + { + // intersection took place within segment + t = newT; + foundCollision = true; + collisionPoint = triangle.pointB + (edge*f); + } + } + + + // p3 --- p1 + edge = triangle.pointA-triangle.pointC; + baseToVertex = triangle.pointC - base; + edgeSqaredLength = edge.getLengthSQ(); + edgeDotVelocity = edge.dotProduct(velocity); + edgeDotBaseToVertex = edge.dotProduct(baseToVertex); + + // calculate parameters for equation + a = edgeSqaredLength* -velocitySqaredLength + + edgeDotVelocity*edgeDotVelocity; + b = edgeSqaredLength* (2*velocity.dotProduct(baseToVertex)) - + 2.0f*edgeDotVelocity*edgeDotBaseToVertex; + c = edgeSqaredLength* (1-baseToVertex.getLengthSQ()) + + edgeDotBaseToVertex*edgeDotBaseToVertex; + + // does the swept sphere collide against infinite edge? + if (getLowestRoot(a,b,c,t,&newT)) + { + f32 f = (edgeDotVelocity*newT-edgeDotBaseToVertex) / + edgeSqaredLength; + if (f >=0.0f && f <= 1.0f) + { + // intersection took place within segment + t = newT; + foundCollision = true; + collisionPoint = triangle.pointC + (edge*f); + } + } + }// end no collision found + + // set result: + if (foundCollision) + { + ++colData->triangleHits; + + // distance to collision is t + f32 distToCollision = t*colData->velocity.getLength(); + + // does this triangle qualify for closest hit? + if (!colData->foundCollision || + distToCollision < colData->nearestDistance) + { + colData->nearestDistance = distToCollision; + colData->intersectionPoint = collisionPoint; + colData->foundCollision = true; + colData->intersectionTriangle = triangle; + return true; + } + }// end found collision + + return false; +} + + +//! Collides a moving ellipsoid with a 3d world with gravity and returns +//! the resulting new position of the ellipsoid. +core::vector3df CSceneCollisionManager::collideEllipsoidWithWorld( + ITriangleSelector* selector, const core::vector3df &position, + const core::vector3df& radius, const core::vector3df& velocity, + f32 slidingSpeed, + const core::vector3df& gravity, + core::triangle3df& triout, + core::vector3df& hitPosition, + bool& outFalling, + ISceneNode*& outNode) +{ + if (!selector || radius.X == 0.0f || radius.Y == 0.0f || radius.Z == 0.0f) + return position; + + // This code is based on the paper "Improved Collision detection and Response" + // by Kasper Fauerby, but some parts are modified. + + SCollisionData colData; + colData.R3Position = position; + colData.R3Velocity = velocity; + colData.eRadius = radius; + colData.nearestDistance = FLT_MAX; + colData.selector = selector; + colData.slidingSpeed = slidingSpeed; + colData.triangleHits = 0; + colData.node = 0; + + core::vector3df eSpacePosition = colData.R3Position / colData.eRadius; + core::vector3df eSpaceVelocity = colData.R3Velocity / colData.eRadius; + + // iterate until we have our final position + + core::vector3df finalPos = collideWithWorld( + 0, colData, eSpacePosition, eSpaceVelocity); + + outFalling = false; + + // add gravity + + if (gravity != core::vector3df(0,0,0)) + { + colData.R3Position = finalPos * colData.eRadius; + colData.R3Velocity = gravity; + colData.triangleHits = 0; + + eSpaceVelocity = gravity/colData.eRadius; + + finalPos = collideWithWorld(0, colData, + finalPos, eSpaceVelocity); + + outFalling = (colData.triangleHits == 0); + } + + if (colData.triangleHits) + { + triout = colData.intersectionTriangle; + triout.pointA *= colData.eRadius; + triout.pointB *= colData.eRadius; + triout.pointC *= colData.eRadius; + outNode = colData.node; + } + + finalPos *= colData.eRadius; + hitPosition = colData.intersectionPoint * colData.eRadius; + return finalPos; +} + + +core::vector3df CSceneCollisionManager::collideWithWorld(s32 recursionDepth, + SCollisionData &colData, const core::vector3df& pos, const core::vector3df& vel) +{ + f32 veryCloseDistance = colData.slidingSpeed; + + if (recursionDepth > 5) + return pos; + + colData.velocity = vel; + colData.normalizedVelocity = vel; + colData.normalizedVelocity.normalize(); + colData.basePoint = pos; + colData.foundCollision = false; + colData.nearestDistance = FLT_MAX; + + //------------------ collide with world + + // get all triangles with which we might collide + core::aabbox3d box(colData.R3Position); + box.addInternalPoint(colData.R3Position + colData.R3Velocity); + box.MinEdge -= colData.eRadius; + box.MaxEdge += colData.eRadius; + + s32 totalTriangleCnt = colData.selector->getTriangleCount(); + Triangles.set_used(totalTriangleCnt); + + core::matrix4 scaleMatrix; + scaleMatrix.setScale( + core::vector3df(1.0f / colData.eRadius.X, + 1.0f / colData.eRadius.Y, + 1.0f / colData.eRadius.Z)); + + irr::core::array outTriangleInfo; + s32 triangleCnt = 0; + colData.selector->getTriangles(Triangles.pointer(), totalTriangleCnt, triangleCnt, box, &scaleMatrix, true, &outTriangleInfo); + + // Find closest intersection + irr::s32 nearestTriangleIndex = -1; + for (s32 i=0; i= 0 ) + { + for ( irr::u32 t=0; t= veryCloseDistance) + { + core::vector3df v = vel; + v.setLength( colData.nearestDistance - veryCloseDistance ); + newBasePoint = colData.basePoint + v; + + v.normalize(); + colData.intersectionPoint -= (v * veryCloseDistance); + } + + // calculate sliding plane + + const core::vector3df slidePlaneOrigin = colData.intersectionPoint; + const core::vector3df slidePlaneNormal = (newBasePoint - colData.intersectionPoint).normalize(); + core::plane3d slidingPlane(slidePlaneOrigin, slidePlaneNormal); + + core::vector3df newDestinationPoint = + destinationPoint - + (slidePlaneNormal * slidingPlane.getDistanceTo(destinationPoint)); + + // generate slide vector + + const core::vector3df newVelocityVector = newDestinationPoint - + colData.intersectionPoint; + + if (newVelocityVector.getLength() < veryCloseDistance) + return newBasePoint; + + return collideWithWorld(recursionDepth+1, colData, + newBasePoint, newVelocityVector); +} + + +//! Returns a 3d ray which would go through the 2d screen coordinates. +core::line3d CSceneCollisionManager::getRayFromScreenCoordinates( + const core::position2d & pos, const ICameraSceneNode* camera) +{ + core::line3d ln(0,0,0,0,0,0); + + if (!SceneManager) + return ln; + + if (!camera) + camera = SceneManager->getActiveCamera(); + + if (!camera) + return ln; + + const scene::SViewFrustum* f = camera->getViewFrustum(); + + core::vector3df farLeftUp = f->getFarLeftUp(); + core::vector3df lefttoright = f->getFarRightUp() - farLeftUp; + core::vector3df uptodown = f->getFarLeftDown() - farLeftUp; + + const core::rect& viewPort = Driver->getViewPort(); + core::dimension2d screenSize(viewPort.getWidth(), viewPort.getHeight()); + + f32 dx = pos.X / (f32)screenSize.Width; + f32 dy = pos.Y / (f32)screenSize.Height; + + if (camera->isOrthogonal()) + ln.start = f->cameraPosition + (lefttoright * (dx-0.5f)) + (uptodown * (dy-0.5f)); + else + ln.start = f->cameraPosition; + + ln.end = farLeftUp + (lefttoright * dx) + (uptodown * dy); + + return ln; +} + + +//! Calculates 2d screen position from a 3d position. +core::position2d CSceneCollisionManager::getScreenCoordinatesFrom3DPosition( + const core::vector3df & pos3d, const ICameraSceneNode* camera, bool useViewPort) +{ + if (!SceneManager || !Driver) + return core::position2d(-1000,-1000); + + if (!camera) + camera = SceneManager->getActiveCamera(); + + if (!camera) + return core::position2d(-1000,-1000); + + core::dimension2d dim; + if (useViewPort) + dim.set(Driver->getViewPort().getWidth(), Driver->getViewPort().getHeight()); + else + dim=(Driver->getCurrentRenderTargetSize()); + + dim.Width /= 2; + dim.Height /= 2; + + core::matrix4 trans = camera->getProjectionMatrix(); + trans *= camera->getViewMatrix(); + + f32 transformedPos[4] = { pos3d.X, pos3d.Y, pos3d.Z, 1.0f }; + + trans.multiplyWith1x4Matrix(transformedPos); + + if (transformedPos[3] < 0) + return core::position2d(-10000,-10000); + + const f32 zDiv = transformedPos[3] == 0.0f ? 1.0f : + core::reciprocal(transformedPos[3]); + + return core::position2d( + dim.Width + core::round32(dim.Width * (transformedPos[0] * zDiv)), + dim.Height - core::round32(dim.Height * (transformedPos[1] * zDiv))); +} + + +inline bool CSceneCollisionManager::getLowestRoot(f32 a, f32 b, f32 c, f32 maxR, f32* root) const +{ + // check if solution exists + const f32 determinant = b*b - 4.0f*a*c; + + // if determinant is negative, no solution + if (determinant < 0.0f || a == 0.f ) + return false; + + // calculate two roots: (if det==0 then x1==x2 + // but lets disregard that slight optimization) + + const f32 sqrtD = sqrtf(determinant); + const f32 invDA = core::reciprocal(2*a); + f32 r1 = (-b - sqrtD) * invDA; + f32 r2 = (-b + sqrtD) * invDA; + + // sort so x1 <= x2 + if (r1 > r2) + core::swap(r1,r2); + + // get lowest root + if (r1 > 0 && r1 < maxR) + { + *root = r1; + return true; + } + + // its possible that we want x2, this can happen if x1 < 0 + if (r2 > 0 && r2 < maxR) + { + *root = r2; + return true; + } + + return false; +} + + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CSceneCollisionManager.h b/source/Irrlicht/CSceneCollisionManager.h new file mode 100644 index 00000000..93d0d277 --- /dev/null +++ b/source/Irrlicht/CSceneCollisionManager.h @@ -0,0 +1,153 @@ +// Copyright (C) 2002-2012 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_COLLISION_MANAGER_H_INCLUDED__ +#define __C_SCENE_COLLISION_MANAGER_H_INCLUDED__ + +#include "ISceneCollisionManager.h" +#include "ISceneManager.h" +#include "IVideoDriver.h" + +namespace irr +{ +namespace scene +{ + + //! The Scene Collision Manager provides methods for performing collision tests and picking on scene nodes. + class CSceneCollisionManager : public ISceneCollisionManager + { + public: + + //! constructor + CSceneCollisionManager(ISceneManager* smanager, video::IVideoDriver* driver); + + //! destructor + virtual ~CSceneCollisionManager(); + + //! Returns the scene node, which is currently visible at the given + //! screen coordinates, viewed from the currently active camera. + virtual ISceneNode* getSceneNodeFromScreenCoordinatesBB(const core::position2d& pos, + s32 idBitMask=0, bool bNoDebugObjects=false, ISceneNode* root=0) _IRR_OVERRIDE_; + + //! Returns the nearest scene node which collides with a 3d ray and + //! whose id matches a bitmask. + virtual ISceneNode* getSceneNodeFromRayBB(const core::line3d& ray, + s32 idBitMask=0, bool bNoDebugObjects=false, + ISceneNode* root=0) _IRR_OVERRIDE_; + + //! Returns the scene node, at which the given camera is looking at and + //! which id matches the bitmask. + virtual ISceneNode* getSceneNodeFromCameraBB(const ICameraSceneNode* camera, + s32 idBitMask=0, bool bNoDebugObjects = false) _IRR_OVERRIDE_; + + //! Finds the nearest collision point of a line and lots of triangles, if there is one. + virtual bool getCollisionPoint(SCollisionHit& hitResult, const core::line3d& ray, + ITriangleSelector* selector) _IRR_OVERRIDE_; + + //! Collides a moving ellipsoid with a 3d world with gravity and returns + //! the resulting new position of the ellipsoid. + virtual core::vector3df getCollisionResultPosition( + ITriangleSelector* selector, + const core::vector3df &ellipsoidPosition, + const core::vector3df& ellipsoidRadius, + const core::vector3df& ellipsoidDirectionAndSpeed, + core::triangle3df& triout, + core::vector3df& hitPosition, + bool& outFalling, + ISceneNode*& outNode, + f32 slidingSpeed, + const core::vector3df& gravityDirectionAndSpeed) _IRR_OVERRIDE_; + + //! Returns a 3d ray which would go through the 2d screen coordinates. + virtual core::line3d getRayFromScreenCoordinates( + const core::position2d & pos, const ICameraSceneNode* camera = 0) _IRR_OVERRIDE_; + + //! Calculates 2d screen position from a 3d position. + virtual core::position2d getScreenCoordinatesFrom3DPosition( + const core::vector3df & pos, const ICameraSceneNode* camera=0, bool useViewPort=false) _IRR_OVERRIDE_; + + //! Gets the scene node and nearest collision point for a ray based on + //! the nodes' id bitmasks, bounding boxes and triangle selectors. + virtual ISceneNode* getSceneNodeAndCollisionPointFromRay( + SCollisionHit& hitResult, + const core::line3df& ray, + s32 idBitMask = 0, + ISceneNode * collisionRootNode = 0, + bool noDebugObjects = false) _IRR_OVERRIDE_; + + private: + + //! recursive method for going through all scene nodes + void getPickedNodeBB(ISceneNode* root, core::line3df& ray, s32 bits, + bool bNoDebugObjects, + f32& outbestdistance, ISceneNode*& outbestnode); + + //! recursive method for going through all scene nodes + void getPickedNodeFromBBAndSelector( + SCollisionHit& hitResult, + ISceneNode * root, + core::line3df & ray, + s32 bits, + bool noDebugObjects, + f32 & outBestDistanceSquared); + + + struct SCollisionData + { + core::vector3df eRadius; + + core::vector3df R3Velocity; + core::vector3df R3Position; + + core::vector3df velocity; + core::vector3df normalizedVelocity; + core::vector3df basePoint; + + bool foundCollision; + f32 nearestDistance; + core::vector3df intersectionPoint; + + core::triangle3df intersectionTriangle; + irr::scene::ISceneNode* node; + s32 triangleHits; + + f32 slidingSpeed; + + ITriangleSelector* selector; + }; + + //! 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 + core::vector3df collideEllipsoidWithWorld(ITriangleSelector* selector, + const core::vector3df &position, + const core::vector3df& radius, const core::vector3df& velocity, + f32 slidingSpeed, + const core::vector3df& gravity, core::triangle3df& triout, + core::vector3df& hitPosition, + bool& outFalling, + ISceneNode*& outNode); + + core::vector3df collideWithWorld(s32 recursionDepth, SCollisionData &colData, + const core::vector3df& pos, const core::vector3df& vel); + + inline bool getLowestRoot(f32 a, f32 b, f32 c, f32 maxR, f32* root) const; + + ISceneManager* SceneManager; + video::IVideoDriver* Driver; + core::array Triangles; // triangle buffer + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CSceneLoaderIrr.cpp b/source/Irrlicht/CSceneLoaderIrr.cpp new file mode 100644 index 00000000..77054368 --- /dev/null +++ b/source/Irrlicht/CSceneLoaderIrr.cpp @@ -0,0 +1,284 @@ +// Copyright (C) 2010-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CSceneLoaderIrr.h" +#include "ISceneNodeAnimatorFactory.h" +#include "ISceneUserDataSerializer.h" +#include "ISceneManager.h" +#include "IVideoDriver.h" +#include "IFileSystem.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + +//! Constructor +CSceneLoaderIrr::CSceneLoaderIrr(ISceneManager *smgr, io::IFileSystem* fs) + : SceneManager(smgr), FileSystem(fs), + IRR_XML_FORMAT_SCENE(L"irr_scene"), IRR_XML_FORMAT_NODE(L"node"), IRR_XML_FORMAT_NODE_ATTR_TYPE(L"type"), + IRR_XML_FORMAT_ATTRIBUTES(L"attributes"), IRR_XML_FORMAT_MATERIALS(L"materials"), + IRR_XML_FORMAT_ANIMATORS(L"animators"), IRR_XML_FORMAT_USERDATA(L"userData") +{ + +} + +//! Destructor +CSceneLoaderIrr::~CSceneLoaderIrr() +{ + +} + +//! Returns true if the class might be able to load this file. +bool CSceneLoaderIrr::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension(filename, "irr"); +} + +//! Returns true if the class might be able to load this file. +bool CSceneLoaderIrr::isALoadableFileFormat(io::IReadFile *file) const +{ + // todo: check inside the file + return true; +} + +//! Loads the scene into the scene manager. +bool CSceneLoaderIrr::loadScene(io::IReadFile* file, ISceneUserDataSerializer* userDataSerializer, + ISceneNode* rootNode) +{ + if (!file) + { + os::Printer::log("Unable to open scene file", ELL_ERROR); + return false; + } + + io::IXMLReader* reader = FileSystem->createXMLReader(file); + if (!reader) + { + os::Printer::log("Scene is not a valid XML file", file->getFileName().c_str(), ELL_ERROR); + return false; + } + + // TODO: COLLADA_CREATE_SCENE_INSTANCES can be removed when the COLLADA loader is a scene loader + bool oldColladaSingleMesh = SceneManager->getParameters()->getAttributeAsBool(COLLADA_CREATE_SCENE_INSTANCES); + SceneManager->getParameters()->setAttribute(COLLADA_CREATE_SCENE_INSTANCES, false); + + // read file + while (reader->read()) + { + readSceneNode(reader, rootNode, userDataSerializer); + } + + // restore old collada parameters + SceneManager->getParameters()->setAttribute(COLLADA_CREATE_SCENE_INSTANCES, oldColladaSingleMesh); + + // clean up + reader->drop(); + return true; +} + + +//! Reads the next node +void CSceneLoaderIrr::readSceneNode(io::IXMLReader* reader, ISceneNode* parent, + ISceneUserDataSerializer* userDataSerializer) +{ + if (!reader) + return; + + scene::ISceneNode* node = 0; + + if (!parent && IRR_XML_FORMAT_SCENE==reader->getNodeName()) + node = SceneManager->getRootSceneNode(); + else if (parent && IRR_XML_FORMAT_NODE==reader->getNodeName()) + { + // find node type and create it + core::stringc attrName = reader->getAttributeValue(IRR_XML_FORMAT_NODE_ATTR_TYPE.c_str()); + + node = SceneManager->addSceneNode(attrName.c_str(), parent); + + if (!node) + os::Printer::log("Could not create scene node of unknown type", attrName.c_str()); + } + else + node=parent; + + // read attributes + while(reader->read()) + { + bool endreached = false; + + const wchar_t* name = reader->getNodeName(); + + switch (reader->getNodeType()) + { + case io::EXN_ELEMENT_END: + if ((IRR_XML_FORMAT_NODE == name) || + (IRR_XML_FORMAT_SCENE == name)) + { + endreached = true; + } + break; + case io::EXN_ELEMENT: + if (IRR_XML_FORMAT_ATTRIBUTES == name) + { + // read attributes + io::IAttributes* attr = FileSystem->createEmptyAttributes(SceneManager->getVideoDriver()); + attr->read(reader, true); + + if (node) + node->deserializeAttributes(attr); + + attr->drop(); + } + else + if (IRR_XML_FORMAT_MATERIALS == name) + readMaterials(reader, node); + else + if (IRR_XML_FORMAT_ANIMATORS == name) + readAnimators(reader, node); + else + if (IRR_XML_FORMAT_USERDATA == name) + readUserData(reader, node, userDataSerializer); + else + if ((IRR_XML_FORMAT_NODE == name) || + (IRR_XML_FORMAT_SCENE == name)) + { + readSceneNode(reader, node, userDataSerializer); + } + else + { + os::Printer::log("Found unknown element in irrlicht scene file", + core::stringc(name).c_str()); + } + break; + default: + break; + } + + if (endreached) + break; + } + if (node && userDataSerializer) + userDataSerializer->OnCreateNode(node); +} + +//! reads materials of a node +void CSceneLoaderIrr::readMaterials(io::IXMLReader* reader, ISceneNode* node) +{ + u32 nr = 0; + + while(reader->read()) + { + const wchar_t* name = reader->getNodeName(); + + switch(reader->getNodeType()) + { + case io::EXN_ELEMENT_END: + if (IRR_XML_FORMAT_MATERIALS == name) + return; + break; + case io::EXN_ELEMENT: + if (IRR_XML_FORMAT_ATTRIBUTES == name) + { + // read materials from attribute list + io::IAttributes* attr = FileSystem->createEmptyAttributes(SceneManager->getVideoDriver()); + attr->read(reader); + + if (node && node->getMaterialCount() > nr) + { + SceneManager->getVideoDriver()->fillMaterialStructureFromAttributes( + node->getMaterial(nr), attr); + } + + attr->drop(); + ++nr; + } + break; + default: + break; + } + } +} + + +//! reads animators of a node +void CSceneLoaderIrr::readAnimators(io::IXMLReader* reader, ISceneNode* node) +{ + while(reader->read()) + { + const wchar_t* name = reader->getNodeName(); + + switch(reader->getNodeType()) + { + case io::EXN_ELEMENT_END: + if (IRR_XML_FORMAT_ANIMATORS == name) + return; + break; + case io::EXN_ELEMENT: + if (IRR_XML_FORMAT_ATTRIBUTES == name) + { + // read animator data from attribute list + io::IAttributes* attr = FileSystem->createEmptyAttributes(SceneManager->getVideoDriver()); + attr->read(reader); + + if (node) + { + core::stringc typeName = attr->getAttributeAsString("Type"); + ISceneNodeAnimator* anim = SceneManager->createSceneNodeAnimator(typeName.c_str(), node); + + if (anim) + { + anim->deserializeAttributes(attr); + anim->drop(); + } + } + + attr->drop(); + } + break; + default: + break; + } + } +} + + +//! reads user data of a node +void CSceneLoaderIrr::readUserData(io::IXMLReader* reader, ISceneNode* node, ISceneUserDataSerializer* userDataSerializer) +{ + while(reader->read()) + { + const wchar_t* name = reader->getNodeName(); + + switch(reader->getNodeType()) + { + case io::EXN_ELEMENT_END: + if (IRR_XML_FORMAT_USERDATA == name) + return; + break; + case io::EXN_ELEMENT: + if (IRR_XML_FORMAT_ATTRIBUTES == name) + { + // read user data from attribute list + io::IAttributes* attr = FileSystem->createEmptyAttributes(SceneManager->getVideoDriver()); + attr->read(reader); + + if (node && userDataSerializer) + { + userDataSerializer->OnReadUserData(node, attr); + } + + attr->drop(); + } + break; + default: + break; + } + } +} + +} // scene +} // irr + diff --git a/source/Irrlicht/CSceneLoaderIrr.h b/source/Irrlicht/CSceneLoaderIrr.h new file mode 100644 index 00000000..2ac73e4f --- /dev/null +++ b/source/Irrlicht/CSceneLoaderIrr.h @@ -0,0 +1,83 @@ +// Copyright (C) 2010-2012 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_LOADER_IRR_H_INCLUDED__ +#define __C_SCENE_LOADER_IRR_H_INCLUDED__ + +#include "ISceneLoader.h" + +#include "IXMLReader.h" + +namespace irr +{ + +namespace io +{ + class IFileSystem; +} + +namespace scene +{ + +class ISceneManager; + +//! Class which can load a scene into the scene manager. +class CSceneLoaderIrr : public virtual ISceneLoader +{ +public: + + //! Constructor + CSceneLoaderIrr(ISceneManager *smgr, io::IFileSystem* fs); + + //! Destructor + virtual ~CSceneLoaderIrr(); + + //! Returns true if the class might be able to load this file. + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! Returns true if the class might be able to load this file. + virtual bool isALoadableFileFormat(io::IReadFile *file) const _IRR_OVERRIDE_; + + //! Loads the scene into the scene manager. + virtual bool loadScene(io::IReadFile* file, + ISceneUserDataSerializer* userDataSerializer=0, + ISceneNode* rootNode=0) _IRR_OVERRIDE_; + +private: + + //! Recursively reads nodes from the xml file + void readSceneNode(io::IXMLReader* reader, ISceneNode* parent, + ISceneUserDataSerializer* userDataSerializer); + + //! read a node's materials + void readMaterials(io::IXMLReader* reader, ISceneNode* node); + + //! read a node's animators + void readAnimators(io::IXMLReader* reader, ISceneNode* node); + + //! read any other data into the user serializer + void readUserData(io::IXMLReader* reader, ISceneNode* node, + ISceneUserDataSerializer* userDataSerializer); + + ISceneManager *SceneManager; + io::IFileSystem *FileSystem; + + //! constants for reading and writing XML. + //! Not made static due to portability problems. + // TODO: move to own header + const core::stringw IRR_XML_FORMAT_SCENE; + const core::stringw IRR_XML_FORMAT_NODE; + const core::stringw IRR_XML_FORMAT_NODE_ATTR_TYPE; + const core::stringw IRR_XML_FORMAT_ATTRIBUTES; + const core::stringw IRR_XML_FORMAT_MATERIALS; + const core::stringw IRR_XML_FORMAT_ANIMATORS; + const core::stringw IRR_XML_FORMAT_USERDATA; +}; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CSceneManager.cpp b/source/Irrlicht/CSceneManager.cpp new file mode 100644 index 00000000..0d1f7c9d --- /dev/null +++ b/source/Irrlicht/CSceneManager.cpp @@ -0,0 +1,2666 @@ +// Copyright (C) 2002-2012 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" +#include "CSceneManager.h" +#include "IVideoDriver.h" +#include "IFileSystem.h" +#include "SAnimatedMesh.h" +#include "CMeshCache.h" +#include "IXMLWriter.h" +#include "ISceneUserDataSerializer.h" +#include "IGUIEnvironment.h" +#include "IMaterialRenderer.h" +#include "IReadFile.h" +#include "IWriteFile.h" +#include "ISceneLoader.h" +#include "EProfileIDs.h" +#include "IProfiler.h" + +#include "os.h" + +// We need this include for the case of skinned mesh support without +// any such loader +#ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ +#include "CSkinnedMesh.h" +#endif + +#ifdef _IRR_COMPILE_WITH_IRR_MESH_LOADER_ +#include "CIrrMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_BSP_LOADER_ +#include "CBSPMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_MD2_LOADER_ +#include "CMD2MeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_HALFLIFE_LOADER_ +#include "CAnimatedMeshHalfLife.h" +#endif + +#ifdef _IRR_COMPILE_WITH_MS3D_LOADER_ +#include "CMS3DMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_3DS_LOADER_ +#include "C3DSMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_X_LOADER_ +#include "CXMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_OCT_LOADER_ +#include "COCTLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_CSM_LOADER_ +#include "CCSMLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_LMTS_LOADER_ +#include "CLMTSMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_MY3D_LOADER_ +#include "CMY3DMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_COLLADA_LOADER_ +#include "CColladaFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_DMF_LOADER_ +#include "CDMFLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_OGRE_LOADER_ +#include "COgreMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_OBJ_LOADER_ +#include "COBJMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_MD3_LOADER_ +#include "CMD3MeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_B3D_LOADER_ +#include "CB3DMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_LWO_LOADER_ +#include "CLWOMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_STL_LOADER_ +#include "CSTLMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_PLY_LOADER_ +#include "CPLYMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_SMF_LOADER_ +#include "CSMFMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_IRR_SCENE_LOADER_ +#include "CSceneLoaderIrr.h" +#endif + +#ifdef _IRR_COMPILE_WITH_COLLADA_WRITER_ +#include "CColladaMeshWriter.h" +#endif + +#ifdef _IRR_COMPILE_WITH_IRR_WRITER_ +#include "CIrrMeshWriter.h" +#endif + +#ifdef _IRR_COMPILE_WITH_STL_WRITER_ +#include "CSTLMeshWriter.h" +#endif + +#ifdef _IRR_COMPILE_WITH_OBJ_WRITER_ +#include "COBJMeshWriter.h" +#endif + +#ifdef _IRR_COMPILE_WITH_PLY_WRITER_ +#include "CPLYMeshWriter.h" +#endif + +#ifdef _IRR_COMPILE_WITH_B3D_WRITER_ +#include "CB3DMeshWriter.h" +#endif + +#ifdef _IRR_COMPILE_WITH_CUBE_SCENENODE_ +#include "CCubeSceneNode.h" +#endif // _IRR_COMPILE_WITH_CUBE_SCENENODE_ +#ifdef _IRR_COMPILE_WITH_SPHERE_SCENENODE_ +#include "CSphereSceneNode.h" +#endif +#include "CAnimatedMeshSceneNode.h" +#ifdef _IRR_COMPILE_WITH_OCTREE_SCENENODE_ +#include "COctreeSceneNode.h" +#endif // #ifdef _IRR_COMPILE_WITH_OCTREE_SCENENODE_ +#include "CCameraSceneNode.h" +#include "CLightSceneNode.h" +#ifdef _IRR_COMPILE_WITH_BILLBOARD_SCENENODE_ +#include "CBillboardSceneNode.h" +#endif // _IRR_COMPILE_WITH_BILLBOARD_SCENENODE_ +#include "CMeshSceneNode.h" +#include "CSkyBoxSceneNode.h" +#ifdef _IRR_COMPILE_WITH_SKYDOME_SCENENODE_ +#include "CSkyDomeSceneNode.h" +#endif // _IRR_COMPILE_WITH_SKYDOME_SCENENODE_ + +#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ +#include "CShadowVolumeSceneNode.h" +#else +#include "IShadowVolumeSceneNode.h" +#endif // _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ + +#ifdef _IRR_COMPILE_WITH_PARTICLES_ +#include "CParticleSystemSceneNode.h" +#endif // _IRR_COMPILE_WITH_PARTICLES_ + +#include "CDummyTransformationSceneNode.h" +#ifdef _IRR_COMPILE_WITH_WATER_SURFACE_SCENENODE_ +#include "CWaterSurfaceSceneNode.h" +#endif // _IRR_COMPILE_WITH_WATER_SURFACE_SCENENODE_ +#ifdef _IRR_COMPILE_WITH_TERRAIN_SCENENODE_ +#include "CTerrainSceneNode.h" +#endif // _IRR_COMPILE_WITH_TERRAIN_SCENENODE_ +#include "CEmptySceneNode.h" +#include "CTextSceneNode.h" +#include "CQuake3ShaderSceneNode.h" +#include "CVolumeLightSceneNode.h" + +#include "CDefaultSceneNodeFactory.h" + +#include "CSceneCollisionManager.h" +#include "CTriangleSelector.h" +#include "COctreeTriangleSelector.h" +#include "CTriangleBBSelector.h" +#include "CMetaTriangleSelector.h" +#ifdef _IRR_COMPILE_WITH_TERRAIN_SCENENODE_ +#include "CTerrainTriangleSelector.h" +#endif // _IRR_COMPILE_WITH_TERRAIN_SCENENODE_ + +#include "CSceneNodeAnimatorRotation.h" +#include "CSceneNodeAnimatorFlyCircle.h" +#include "CSceneNodeAnimatorFlyStraight.h" +#include "CSceneNodeAnimatorTexture.h" +#include "CSceneNodeAnimatorCollisionResponse.h" +#include "CSceneNodeAnimatorDelete.h" +#include "CSceneNodeAnimatorFollowSpline.h" +#include "CSceneNodeAnimatorCameraFPS.h" +#include "CSceneNodeAnimatorCameraMaya.h" +#include "CDefaultSceneNodeAnimatorFactory.h" + +#include "CGeometryCreator.h" + +#include + +namespace irr +{ +namespace scene +{ + +//! constructor +CSceneManager::CSceneManager(video::IVideoDriver* driver, io::IFileSystem* fs, + gui::ICursorControl* cursorControl, IMeshCache* cache, + gui::IGUIEnvironment* gui) +: 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), Parameters(0), + MeshCache(cache), CurrentRenderPass(ESNRP_NONE), 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 + ISceneManager::setDebugName("CSceneManager ISceneManager"); + ISceneNode::setDebugName("CSceneManager ISceneNode"); + #endif + + // root node's scene manager + SceneManager = this; + + if (Driver) + Driver->grab(); + + if (FileSystem) + FileSystem->grab(); + + if (CursorControl) + CursorControl->grab(); + + if (GUIEnvironment) + GUIEnvironment->grab(); + + // create mesh cache if not there already + if (!MeshCache) + MeshCache = new CMeshCache(); + else + MeshCache->grab(); + + // set scene parameters + Parameters = new io::CAttributes(); + Parameters->setAttribute(DEBUG_NORMAL_LENGTH, 1.f); + Parameters->setAttribute(DEBUG_NORMAL_COLOR, video::SColor(255, 34, 221, 221)); + + // create collision manager + CollisionManager = new CSceneCollisionManager(this, Driver); + + // create geometry creator + GeometryCreator = new CGeometryCreator(); + + // add file format loaders. add the least commonly used ones first, + // as these are checked last + + // TODO: now that we have multiple scene managers, these should be + // shallow copies from the previous manager if there is one. + + #ifdef _IRR_COMPILE_WITH_STL_LOADER_ + MeshLoaderList.push_back(new CSTLMeshFileLoader()); + #endif + #ifdef _IRR_COMPILE_WITH_PLY_LOADER_ + MeshLoaderList.push_back(new CPLYMeshFileLoader(this)); + #endif + #ifdef _IRR_COMPILE_WITH_SMF_LOADER_ + MeshLoaderList.push_back(new CSMFMeshFileLoader(FileSystem, Driver)); + #endif + #ifdef _IRR_COMPILE_WITH_OCT_LOADER_ + MeshLoaderList.push_back(new COCTLoader(this, FileSystem)); + #endif + #ifdef _IRR_COMPILE_WITH_CSM_LOADER_ + MeshLoaderList.push_back(new CCSMLoader(this, FileSystem)); + #endif + #ifdef _IRR_COMPILE_WITH_LMTS_LOADER_ + MeshLoaderList.push_back(new CLMTSMeshFileLoader(FileSystem, Driver, Parameters)); + #endif + #ifdef _IRR_COMPILE_WITH_MY3D_LOADER_ + MeshLoaderList.push_back(new CMY3DMeshFileLoader(this, FileSystem)); + #endif + #ifdef _IRR_COMPILE_WITH_DMF_LOADER_ + MeshLoaderList.push_back(new CDMFLoader(this, FileSystem)); + #endif + #ifdef _IRR_COMPILE_WITH_OGRE_LOADER_ + MeshLoaderList.push_back(new COgreMeshFileLoader(FileSystem, Driver)); + #endif + #ifdef _IRR_COMPILE_WITH_HALFLIFE_LOADER_ + MeshLoaderList.push_back(new CHalflifeMDLMeshFileLoader( this )); + #endif + #ifdef _IRR_COMPILE_WITH_MD3_LOADER_ + MeshLoaderList.push_back(new CMD3MeshFileLoader( this)); + #endif + #ifdef _IRR_COMPILE_WITH_LWO_LOADER_ + MeshLoaderList.push_back(new CLWOMeshFileLoader(this, FileSystem)); + #endif + #ifdef _IRR_COMPILE_WITH_MD2_LOADER_ + MeshLoaderList.push_back(new CMD2MeshFileLoader()); + #endif + #ifdef _IRR_COMPILE_WITH_IRR_MESH_LOADER_ + MeshLoaderList.push_back(new CIrrMeshFileLoader(this, FileSystem)); + #endif + #ifdef _IRR_COMPILE_WITH_BSP_LOADER_ + MeshLoaderList.push_back(new CBSPMeshFileLoader(this, FileSystem)); + #endif + #ifdef _IRR_COMPILE_WITH_COLLADA_LOADER_ + MeshLoaderList.push_back(new CColladaFileLoader(this, FileSystem)); + #endif + #ifdef _IRR_COMPILE_WITH_3DS_LOADER_ + MeshLoaderList.push_back(new C3DSMeshFileLoader(this, FileSystem)); + #endif + #ifdef _IRR_COMPILE_WITH_X_LOADER_ + MeshLoaderList.push_back(new CXMeshFileLoader(this, FileSystem)); + #endif + #ifdef _IRR_COMPILE_WITH_MS3D_LOADER_ + MeshLoaderList.push_back(new CMS3DMeshFileLoader(Driver)); + #endif + #ifdef _IRR_COMPILE_WITH_OBJ_LOADER_ + MeshLoaderList.push_back(new COBJMeshFileLoader(this, FileSystem)); + #endif + #ifdef _IRR_COMPILE_WITH_B3D_LOADER_ + MeshLoaderList.push_back(new CB3DMeshFileLoader(this)); + #endif + + // scene loaders + #ifdef _IRR_COMPILE_WITH_IRR_SCENE_LOADER_ + SceneLoaderList.push_back(new CSceneLoaderIrr(this, FileSystem)); + #endif + + // factories + ISceneNodeFactory* factory = new CDefaultSceneNodeFactory(this); + registerSceneNodeFactory(factory); + factory->drop(); + + ISceneNodeAnimatorFactory* animatorFactory = new CDefaultSceneNodeAnimatorFactory(this, CursorControl); + registerSceneNodeAnimatorFactory(animatorFactory); + animatorFactory->drop(); + + IRR_PROFILE( + static bool initProfile = false; + if (!initProfile ) + { + initProfile = true; + getProfiler().add(EPID_SM_DRAW_ALL, L"drawAll", L"Irrlicht scene"); + getProfiler().add(EPID_SM_ANIMATE, L"animate", L"Irrlicht scene"); + getProfiler().add(EPID_SM_RENDER_CAMERAS, L"cameras", L"Irrlicht scene"); + getProfiler().add(EPID_SM_RENDER_LIGHTS, L"lights", L"Irrlicht scene"); + getProfiler().add(EPID_SM_RENDER_SKYBOXES, L"skyboxes", L"Irrlicht scene"); + getProfiler().add(EPID_SM_RENDER_DEFAULT, L"defaultnodes", L"Irrlicht scene"); + getProfiler().add(EPID_SM_RENDER_SHADOWS, L"shadows", L"Irrlicht scene"); + getProfiler().add(EPID_SM_RENDER_TRANSPARENT, L"transp.nodes", L"Irrlicht scene"); + getProfiler().add(EPID_SM_RENDER_EFFECT, L"effectnodes", L"Irrlicht scene"); + getProfiler().add(EPID_SM_REGISTER, L"reg.render.node", L"Irrlicht scene"); + } + ) +} + + +//! destructor +CSceneManager::~CSceneManager() +{ + clearDeletionList(); + + //! force to remove hardwareTextures from the driver + //! because Scenes may hold internally data bounded to sceneNodes + //! which may be destroyed twice + if (Driver) + Driver->removeAllHardwareBuffers(); + + if (FileSystem) + FileSystem->drop(); + + if (CursorControl) + CursorControl->drop(); + + if (CollisionManager) + CollisionManager->drop(); + + if (GeometryCreator) + GeometryCreator->drop(); + + if (GUIEnvironment) + GUIEnvironment->drop(); + + u32 i; + for (i=0; idrop(); + + for (i=0; idrop(); + + if (ActiveCamera) + ActiveCamera->drop(); + ActiveCamera = 0; + + if (MeshCache) + MeshCache->drop(); + + if (Parameters) + Parameters->drop(); + + for (i=0; idrop(); + + 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(); + removeAnimators(); + + if (Driver) + Driver->drop(); +} + + +//! gets an animateable mesh. loads it if needed. returned pointer must not be dropped. +IAnimatedMesh* CSceneManager::getMesh(const io::path& filename, const io::path& alternativeCacheName) +{ + io::path cacheName = alternativeCacheName.empty() ? filename : alternativeCacheName; + IAnimatedMesh* msh = MeshCache->getMeshByName(cacheName); + if (msh) + return msh; + + io::IReadFile* file = FileSystem->createAndOpenFile(filename); + if (!file) + { + os::Printer::log("Could not load mesh, because file could not be opened: ", filename, ELL_ERROR); + return 0; + } + + msh = getUncachedMesh(file, filename, cacheName); + + file->drop(); + + return msh; +} + + +//! gets an animateable mesh. loads it if needed. returned pointer must not be dropped. +IAnimatedMesh* CSceneManager::getMesh(io::IReadFile* file) +{ + if (!file) + return 0; + + io::path name = file->getFileName(); + IAnimatedMesh* msh = MeshCache->getMeshByName(name); + if (msh) + return msh; + + msh = getUncachedMesh(file, name, name); + + return msh; +} + +// load and create a mesh which we know already isn't in the cache and put it in there +IAnimatedMesh* CSceneManager::getUncachedMesh(io::IReadFile* file, const io::path& filename, const io::path& cachename) +{ + IAnimatedMesh* msh = 0; + + // iterate the list in reverse order so user-added loaders can override the built-in ones + s32 count = MeshLoaderList.size(); + for (s32 i=count-1; i>=0; --i) + { + if (MeshLoaderList[i]->isALoadableFileExtension(filename)) + { + // reset file to avoid side effects of previous calls to createMesh + file->seek(0); + msh = MeshLoaderList[i]->createMesh(file); + if (msh) + { + MeshCache->addMesh(cachename, msh); + msh->drop(); + break; + } + } + } + + if (!msh) + os::Printer::log("Could not load mesh, file format seems to be unsupported", filename, ELL_ERROR); + else + os::Printer::log("Loaded mesh", filename, ELL_DEBUG); + + return msh; +} + +//! returns the video driver +video::IVideoDriver* CSceneManager::getVideoDriver() +{ + return Driver; +} + + +//! returns the GUI Environment +gui::IGUIEnvironment* CSceneManager::getGUIEnvironment() +{ + return GUIEnvironment; +} + +//! Get the active FileSystem +/** \return Pointer to the FileSystem +This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ +io::IFileSystem* CSceneManager::getFileSystem() +{ + return FileSystem; +} + +//! Adds a text scene node, which is able to display +//! 2d text at a position in three dimensional space +ITextSceneNode* CSceneManager::addTextSceneNode(gui::IGUIFont* font, + const wchar_t* text, video::SColor color, ISceneNode* parent, + const core::vector3df& position, s32 id) +{ + if (!font) + return 0; + + if (!parent) + parent = this; + + ITextSceneNode* t = new CTextSceneNode(parent, this, id, font, + getSceneCollisionManager(), position, text, color); + t->drop(); + + return t; +} + + +//! Adds a text scene node, which uses billboards +IBillboardTextSceneNode* CSceneManager::addBillboardTextSceneNode(gui::IGUIFont* font, + const wchar_t* text, ISceneNode* parent, + const core::dimension2d& size, + const core::vector3df& position, s32 id, + video::SColor colorTop, video::SColor colorBottom) +{ + if (!font && GUIEnvironment) + font = GUIEnvironment->getBuiltInFont(); + + if (!font) + return 0; + + if (!parent) + parent = this; + + IBillboardTextSceneNode* node = new CBillboardTextSceneNode(parent, this, id, font, text, position, size, + colorTop, colorBottom); + node->drop(); + + return node; + +} + + +//! Adds a scene node, which can render a quake3 shader +IMeshSceneNode* CSceneManager::addQuake3SceneNode(const IMeshBuffer* meshBuffer, + const quake3::IShader * shader, + ISceneNode* parent, s32 id ) +{ +#ifdef _IRR_COMPILE_WITH_BSP_LOADER_ + if (!shader) + return 0; + + if (!parent) + parent = this; + + CQuake3ShaderSceneNode* node = new CQuake3ShaderSceneNode( parent, + this, id, FileSystem, + meshBuffer, shader ); + node->drop(); + + return node; +#else + return 0; +#endif +} + + +//! adds Volume Lighting Scene Node. +//! the returned pointer must not be dropped. +IVolumeLightSceneNode* CSceneManager::addVolumeLightSceneNode( + ISceneNode* parent, s32 id, + const u32 subdivU, const u32 subdivV, + const video::SColor foot, const video::SColor tail, + const core::vector3df& position, const core::vector3df& rotation, const core::vector3df& scale) +{ + if (!parent) + parent = this; + + IVolumeLightSceneNode* node = new CVolumeLightSceneNode(parent, this, id, subdivU, subdivV, foot, tail, position, rotation, scale); + node->drop(); + + return node; +} + + +//! adds a test scene node for test purposes to the scene. It is a simple cube of (1,1,1) size. +//! the returned pointer must not be dropped. +IMeshSceneNode* CSceneManager::addCubeSceneNode(f32 size, ISceneNode* parent, + s32 id, const core::vector3df& position, + const core::vector3df& rotation, const core::vector3df& scale) +{ +#ifdef _IRR_COMPILE_WITH_CUBE_SCENENODE_ + if (!parent) + parent = this; + + IMeshSceneNode* node = new CCubeSceneNode(size, parent, this, id, position, rotation, scale); + node->drop(); + + return node; +#else + return 0; +#endif +} + + +//! Adds a sphere scene node for test purposes to the scene. +IMeshSceneNode* CSceneManager::addSphereSceneNode(f32 radius, s32 polyCount, + ISceneNode* parent, s32 id, const core::vector3df& position, + const core::vector3df& rotation, const core::vector3df& scale) +{ +#ifdef _IRR_COMPILE_WITH_SPHERE_SCENENODE_ + if (!parent) + parent = this; + + IMeshSceneNode* node = new CSphereSceneNode(radius, polyCount, polyCount, parent, this, id, position, rotation, scale); + node->drop(); + + return node; +#else + return 0; +#endif // _IRR_COMPILE_WITH_SPHERE_SCENENODE_ +} + + +//! adds a scene node for rendering a static mesh +//! the returned pointer must not be dropped. +IMeshSceneNode* CSceneManager::addMeshSceneNode(IMesh* mesh, ISceneNode* parent, s32 id, + const core::vector3df& position, const core::vector3df& rotation, + const core::vector3df& scale, bool alsoAddIfMeshPointerZero) +{ + if (!alsoAddIfMeshPointerZero && !mesh) + return 0; + + if (!parent) + parent = this; + + IMeshSceneNode* node = new CMeshSceneNode(mesh, parent, this, id, position, rotation, scale); + node->drop(); + + return node; +} + + +//! Adds a scene node for rendering a animated water surface mesh. +ISceneNode* CSceneManager::addWaterSurfaceSceneNode(IMesh* mesh, f32 waveHeight, f32 waveSpeed, f32 waveLength, + ISceneNode* parent, s32 id, const core::vector3df& position, + const core::vector3df& rotation, const core::vector3df& scale) +{ +#ifdef _IRR_COMPILE_WITH_WATER_SURFACE_SCENENODE_ + if (!parent) + parent = this; + + ISceneNode* node = new CWaterSurfaceSceneNode(waveHeight, waveSpeed, waveLength, + mesh, parent, this, id, position, rotation, scale); + + node->drop(); + + return node; +#else + return 0; +#endif +} + + +//! adds a scene node for rendering an animated mesh model +IAnimatedMeshSceneNode* CSceneManager::addAnimatedMeshSceneNode(IAnimatedMesh* mesh, ISceneNode* parent, s32 id, + const core::vector3df& position, const core::vector3df& rotation, + const core::vector3df& scale, bool alsoAddIfMeshPointerZero) +{ + if (!alsoAddIfMeshPointerZero && !mesh) + return 0; + + if (!parent) + parent = this; + + IAnimatedMeshSceneNode* node = + new CAnimatedMeshSceneNode(mesh, parent, this, id, position, rotation, scale); + node->drop(); + + return node; +} + + +//! Adds a scene node for rendering using a octree 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, much +//! faster then a bsp tree. +IOctreeSceneNode* CSceneManager::addOctreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent, + s32 id, s32 minimalPolysPerNode, bool alsoAddIfMeshPointerZero) +{ + if (!alsoAddIfMeshPointerZero && (!mesh || !mesh->getFrameCount())) + return 0; + + return addOctreeSceneNode(mesh ? mesh->getMesh(0) : 0, + parent, id, minimalPolysPerNode, + alsoAddIfMeshPointerZero); +} + + +//! Adds a scene node for rendering using a octree. This a good method for rendering +//! scenes with lots of geometry. The Octree is built on the fly from the mesh, much +//! faster then a bsp tree. +IOctreeSceneNode* CSceneManager::addOctreeSceneNode(IMesh* mesh, ISceneNode* parent, + s32 id, s32 minimalPolysPerNode, bool alsoAddIfMeshPointerZero) +{ +#ifdef _IRR_COMPILE_WITH_OCTREE_SCENENODE_ + if (!alsoAddIfMeshPointerZero && !mesh) + return 0; + + if (!parent) + parent = this; + + COctreeSceneNode* node = new COctreeSceneNode(parent, this, id, minimalPolysPerNode); + + if (node) + { + node->setMesh(mesh); + node->drop(); + } + + return node; +#else + return 0; +#endif +} + + +//! Adds a camera scene node to the tree and sets it as active camera. +//! \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. +//! \return Returns pointer to interface to camera +ICameraSceneNode* CSceneManager::addCameraSceneNode(ISceneNode* parent, + const core::vector3df& position, const core::vector3df& lookat, s32 id, + bool makeActive) +{ + if (!parent) + parent = this; + + ICameraSceneNode* node = new CCameraSceneNode(parent, this, id, position, lookat); + + if (makeActive) + setActiveCamera(node); + node->drop(); + + return node; +} + + +//! Adds a camera scene node which is able to be controlled with the mouse similar +//! to in the 3D Software Maya by Alias Wavefront. +//! The returned pointer must not be dropped. +ICameraSceneNode* CSceneManager::addCameraSceneNodeMaya(ISceneNode* parent, + f32 rotateSpeed, f32 zoomSpeed, f32 translationSpeed, s32 id, f32 distance, + bool makeActive) +{ + ICameraSceneNode* node = addCameraSceneNode(parent, core::vector3df(), + core::vector3df(0,0,100), id, makeActive); + if (node) + { + ISceneNodeAnimator* anm = new CSceneNodeAnimatorCameraMaya(CursorControl, + rotateSpeed, zoomSpeed, translationSpeed, distance); + + node->addAnimator(anm); + anm->drop(); + } + + return node; +} + + +//! Adds a camera scene node which is able to be controlled with the mouse and keys +//! 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, + bool invertMouseY, bool makeActive) +{ + ICameraSceneNode* node = addCameraSceneNode(parent, core::vector3df(), + core::vector3df(0,0,100), id, makeActive); + if (node) + { + ISceneNodeAnimator* anm = new CSceneNodeAnimatorCameraFPS(CursorControl, + rotateSpeed, moveSpeed, jumpSpeed, + keyMapArray, keyMapSize, noVerticalMovement, invertMouseY); + + // Bind the node's rotation to its target. This is consistent with 1.4.2 and below. + node->bindTargetAndRotation(true); + node->addAnimator(anm); + anm->drop(); + } + + return node; +} + + +//! 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 +//! turned on. (This is the default setting in most scene nodes). +ILightSceneNode* CSceneManager::addLightSceneNode(ISceneNode* parent, + const core::vector3df& position, video::SColorf color, f32 range, s32 id) +{ + if (!parent) + parent = this; + + ILightSceneNode* node = new CLightSceneNode(parent, this, id, position, color, range); + node->drop(); + + return node; +} + + +//! Adds a billboard scene node to the scene. 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. +IBillboardSceneNode* CSceneManager::addBillboardSceneNode(ISceneNode* parent, + const core::dimension2d& size, const core::vector3df& position, s32 id, + video::SColor colorTop, video::SColor colorBottom + ) +{ +#ifdef _IRR_COMPILE_WITH_BILLBOARD_SCENENODE_ + if (!parent) + parent = this; + + IBillboardSceneNode* node = new CBillboardSceneNode(parent, this, id, position, size, + colorTop, colorBottom); + node->drop(); + + return node; +#else + return 0; +#endif +} + + +//! Adds a skybox scene node. A skybox is a big cube with 6 textures on it and +//! is drawn around the camera position. +ISceneNode* CSceneManager::addSkyBoxSceneNode(video::ITexture* top, video::ITexture* bottom, + video::ITexture* left, video::ITexture* right, video::ITexture* front, + video::ITexture* back, ISceneNode* parent, s32 id) +{ + if (!parent) + parent = this; + + ISceneNode* node = new CSkyBoxSceneNode(top, bottom, left, right, + front, back, parent, this, id); + + node->drop(); + return node; +} + + +//! Adds a skydome scene node. A skydome is a large (half-) sphere with a +//! panoramic texture on it and is drawn around the camera position. +ISceneNode* CSceneManager::addSkyDomeSceneNode(video::ITexture* texture, + u32 horiRes, u32 vertRes, f32 texturePercentage,f32 spherePercentage, f32 radius, + ISceneNode* parent, s32 id) +{ +#ifdef _IRR_COMPILE_WITH_SKYDOME_SCENENODE_ + if (!parent) + parent = this; + + ISceneNode* node = new CSkyDomeSceneNode(texture, horiRes, vertRes, + texturePercentage, spherePercentage, radius, parent, this, id); + + node->drop(); + return node; +#else + return 0; +#endif +} + + +//! Adds a particle system scene node. +IParticleSystemSceneNode* CSceneManager::addParticleSystemSceneNode( + bool withDefaultEmitter, ISceneNode* parent, s32 id, + const core::vector3df& position, const core::vector3df& rotation, + const core::vector3df& scale) +{ +#ifdef _IRR_COMPILE_WITH_PARTICLES_ + if (!parent) + parent = this; + + IParticleSystemSceneNode* node = new CParticleSystemSceneNode(withDefaultEmitter, + parent, this, id, position, rotation, scale); + node->drop(); + + return node; +#else + return 0; +#endif // _IRR_COMPILE_WITH_PARTICLES_ +} + + +//! Adds a terrain scene node to the scene graph. +ITerrainSceneNode* CSceneManager::addTerrainSceneNode( + const io::path& heightMapFileName, + ISceneNode* parent, s32 id, + const core::vector3df& position, + const core::vector3df& rotation, + const core::vector3df& scale, + video::SColor vertexColor, + s32 maxLOD, E_TERRAIN_PATCH_SIZE patchSize, s32 smoothFactor, + bool addAlsoIfHeightmapEmpty) +{ + io::IReadFile* file = FileSystem->createAndOpenFile(heightMapFileName); + + if (!file && !addAlsoIfHeightmapEmpty) + { + os::Printer::log("Could not load terrain, because file could not be opened.", + heightMapFileName, ELL_ERROR); + return 0; + } + + ITerrainSceneNode* terrain = addTerrainSceneNode(file, parent, id, + position, rotation, scale, vertexColor, maxLOD, patchSize, + smoothFactor, addAlsoIfHeightmapEmpty); + + if (file) + file->drop(); + + return terrain; +} + +//! Adds a terrain scene node to the scene graph. +ITerrainSceneNode* CSceneManager::addTerrainSceneNode( + io::IReadFile* heightMapFile, + ISceneNode* parent, s32 id, + const core::vector3df& position, + const core::vector3df& rotation, + const core::vector3df& scale, + video::SColor vertexColor, + s32 maxLOD, E_TERRAIN_PATCH_SIZE patchSize, + s32 smoothFactor, + bool addAlsoIfHeightmapEmpty) +{ +#ifdef _IRR_COMPILE_WITH_TERRAIN_SCENENODE_ + if (!parent) + parent = this; + + if (!heightMapFile && !addAlsoIfHeightmapEmpty) + { + os::Printer::log("Could not load terrain, because file could not be opened.", ELL_ERROR); + return 0; + } + + CTerrainSceneNode* node = new CTerrainSceneNode(parent, this, FileSystem, id, + maxLOD, patchSize, position, rotation, scale); + + if (!node->loadHeightMap(heightMapFile, vertexColor, smoothFactor)) + { + if (!addAlsoIfHeightmapEmpty) + { + node->remove(); + node->drop(); + return 0; + } + } + + node->drop(); + return node; +#else + return 0; +#endif // _IRR_COMPILE_WITH_TERRAIN_SCENENODE_ +} + + +//! Adds an empty scene node. +ISceneNode* CSceneManager::addEmptySceneNode(ISceneNode* parent, s32 id) +{ + if (!parent) + parent = this; + + ISceneNode* node = new CEmptySceneNode(parent, this, id); + node->drop(); + + return node; +} + + +//! Adds a dummy transformation scene node to the scene graph. +IDummyTransformationSceneNode* CSceneManager::addDummyTransformationSceneNode( + ISceneNode* parent, s32 id) +{ + if (!parent) + parent = this; + + IDummyTransformationSceneNode* node = new CDummyTransformationSceneNode( + parent, this, id); + node->drop(); + + return node; +} + +//! 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. 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. +IAnimatedMesh* CSceneManager::addHillPlaneMesh(const io::path& name, + const core::dimension2d& tileSize, + const core::dimension2d& tileCount, + video::SMaterial* material, f32 hillHeight, + const core::dimension2d& countHills, + const core::dimension2d& textureRepeatCount) +{ + if (MeshCache->isMeshLoaded(name)) + return MeshCache->getMeshByName(name); + + IMesh* mesh = GeometryCreator->createHillPlaneMesh(tileSize, + tileCount, material, hillHeight, countHills, + textureRepeatCount); + if (!mesh) + return 0; + + SAnimatedMesh* animatedMesh = new SAnimatedMesh(); + if (!animatedMesh) + { + mesh->drop(); + return 0; + } + + animatedMesh->addMesh(mesh); + mesh->drop(); + animatedMesh->recalculateBoundingBox(); + + MeshCache->addMesh(name, animatedMesh); + animatedMesh->drop(); + + return animatedMesh; +} + + +//! Adds a terrain mesh to the mesh pool. +IAnimatedMesh* CSceneManager::addTerrainMesh(const io::path& name, + video::IImage* texture, video::IImage* heightmap, + const core::dimension2d& stretchSize, + f32 maxHeight, + const core::dimension2d& defaultVertexBlockSize) +{ + if (MeshCache->isMeshLoaded(name)) + return MeshCache->getMeshByName(name); + + const bool debugBorders=false; + IMesh* mesh = GeometryCreator->createTerrainMesh(texture, heightmap, + stretchSize, maxHeight, Driver, + defaultVertexBlockSize, debugBorders); + if (!mesh) + return 0; + + SAnimatedMesh* animatedMesh = new SAnimatedMesh(); + if (!animatedMesh) + { + mesh->drop(); + return 0; + } + + animatedMesh->addMesh(mesh); + mesh->drop(); + animatedMesh->recalculateBoundingBox(); + + MeshCache->addMesh(name, animatedMesh); + animatedMesh->drop(); + + return animatedMesh; +} + + +//! Adds an arrow mesh to the mesh pool. +IAnimatedMesh* CSceneManager::addArrowMesh(const io::path& name, + video::SColor vtxColor0, video::SColor vtxColor1, + u32 tesselationCylinder, u32 tesselationCone, f32 height, + f32 cylinderHeight, f32 width0,f32 width1) +{ + if (MeshCache->isMeshLoaded(name)) + return MeshCache->getMeshByName(name); + + IMesh* mesh = GeometryCreator->createArrowMesh( tesselationCylinder, + tesselationCone, height, cylinderHeight, width0,width1, + vtxColor0, vtxColor1); + if (!mesh) + return 0; + + SAnimatedMesh* animatedMesh = new SAnimatedMesh(); + if (!animatedMesh) + { + mesh->drop(); + return 0; + } + + animatedMesh->addMesh(mesh); + mesh->drop(); + animatedMesh->recalculateBoundingBox(); + + MeshCache->addMesh(name, animatedMesh); + animatedMesh->drop(); + + return animatedMesh; +} + + +//! Adds a static sphere mesh to the mesh pool. +IAnimatedMesh* CSceneManager::addSphereMesh(const io::path& name, + f32 radius, u32 polyCountX, u32 polyCountY) +{ + if (MeshCache->isMeshLoaded(name)) + return MeshCache->getMeshByName(name); + + IMesh* mesh = GeometryCreator->createSphereMesh(radius, polyCountX, polyCountY); + if (!mesh) + return 0; + + SAnimatedMesh* animatedMesh = new SAnimatedMesh(); + if (!animatedMesh) + { + mesh->drop(); + return 0; + } + + animatedMesh->addMesh(mesh); + mesh->drop(); + animatedMesh->recalculateBoundingBox(); + + MeshCache->addMesh(name, animatedMesh); + animatedMesh->drop(); + + return animatedMesh; +} + + + +//! Adds a static volume light mesh to the mesh pool. +IAnimatedMesh* CSceneManager::addVolumeLightMesh(const io::path& name, + const u32 SubdivideU, const u32 SubdivideV, + const video::SColor FootColor, const video::SColor TailColor) +{ + if (MeshCache->isMeshLoaded(name)) + return MeshCache->getMeshByName(name); + + IMesh* mesh = GeometryCreator->createVolumeLightMesh(SubdivideU, SubdivideV, FootColor, TailColor); + if (!mesh) + return 0; + + SAnimatedMesh* animatedMesh = new SAnimatedMesh(); + if (!animatedMesh) + { + mesh->drop(); + return 0; + } + + animatedMesh->addMesh(mesh); + mesh->drop(); + animatedMesh->recalculateBoundingBox(); + + MeshCache->addMesh(name, animatedMesh); + animatedMesh->drop(); + + return animatedMesh; +} + + +//! Returns 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 is not rendered and cannot +//! be removed from the scene. +//! \return Returns a pointer to the root scene node. +ISceneNode* CSceneManager::getRootSceneNode() +{ + return this; +} + + +//! Returns the current active camera. +//! \return The active camera is returned. Note that this can be NULL, if there +//! was no camera created yet. +ICameraSceneNode* CSceneManager::getActiveCamera() const +{ + return ActiveCamera; +} + + +//! Sets the active camera. The previous active camera will be deactivated. +//! \param camera: The new camera which should be active. +void CSceneManager::setActiveCamera(ICameraSceneNode* camera) +{ + if (camera) + camera->grab(); + if (ActiveCamera) + ActiveCamera->drop(); + + ActiveCamera = camera; +} + + +//! renders the node. +void CSceneManager::render() +{ +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CSceneManager::getBoundingBox() const +{ + _IRR_DEBUG_BREAK_IF(true) // Bounding Box of Scene Manager should never be used. + + static const core::aabbox3d dummy; + return dummy; +} + + +//! returns if node is culled +bool CSceneManager::isCulled(const ISceneNode* node) const +{ + const ICameraSceneNode* cam = getActiveCamera(); + if (!cam) + { + return false; + } + bool result = false; + + // has occlusion query information + if (node->getAutomaticCulling() & scene::EAC_OCC_QUERY) + { + result = (Driver->getOcclusionQueryResult(const_cast(node))==0); + } + + // can be seen by a bounding box ? + if (!result && (node->getAutomaticCulling() & scene::EAC_BOX)) + { + core::aabbox3d tbox = node->getBoundingBox(); + node->getAbsoluteTransformation().transformBoxEx(tbox); + result = !(tbox.intersectsWithBox(cam->getViewFrustum()->getBoundingBox() )); + } + + // can be seen by a bounding sphere + if (!result && (node->getAutomaticCulling() & scene::EAC_FRUSTUM_SPHERE)) + { + const core::aabbox3df nbox = node->getTransformedBoundingBox(); + const float rad = nbox.getRadius(); + const core::vector3df center = nbox.getCenter(); + + const float camrad = cam->getViewFrustum()->getBoundingRadius(); + const core::vector3df camcenter = cam->getViewFrustum()->getBoundingCenter(); + + const float dist = (center - camcenter).getLengthSQ(); + const float maxdist = (rad + camrad) * (rad + camrad); + + result = dist > maxdist; + } + + // can be seen by cam pyramid planes ? + if (!result && (node->getAutomaticCulling() & scene::EAC_FRUSTUM_BOX)) + { + SViewFrustum frust = *cam->getViewFrustum(); + + //transform the frustum to the node's current absolute transformation + core::matrix4 invTrans(node->getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE); + //invTrans.makeInverse(); + frust.transform(invTrans); + + core::vector3df edges[8]; + node->getBoundingBox().getEdges(edges); + + for (s32 i=0; igetMaterialCount(); + + taken = 0; + for (u32 i=0; ineedsTransparentRenderPass(node->getMaterial(i))) + { + // register as transparent node + TransparentNodeEntry e(node, camWorldPos); + TransparentNodeList.push_back(e); + taken = 1; + break; + } + } + + // not transparent, register as solid + if (!taken) + { + SolidNodeList.push_back(node); + taken = 1; + } + } + break; + case ESNRP_SHADOW: + if (!isCulled(node)) + { + ShadowNodeList.push_back(node); + taken = 1; + } + break; + + case ESNRP_NONE: // ignore this one + break; + } + +#ifdef _IRR_SCENEMANAGER_DEBUG + s32 index = Parameters->findAttribute("calls"); + Parameters->setAttribute(index, Parameters->getAttributeAsInt(index)+1); + + if (!taken) + { + index = Parameters->findAttribute("culled"); + Parameters->setAttribute(index, Parameters->getAttributeAsInt(index)+1); + } +#endif + + return taken; +} + +void CSceneManager::clearAllRegisteredNodesForRendering() +{ + CameraList.clear(); + LightList.clear(); + SkyBoxList.clear(); + SolidNodeList.clear(); + TransparentNodeList.clear(); + TransparentEffectNodeList.clear(); + ShadowNodeList.clear(); +} + +//! This method is called just before the rendering process of the whole scene. +//! draws all scene nodes +void CSceneManager::drawAll() +{ + IRR_PROFILE(CProfileScope psAll(EPID_SM_DRAW_ALL);) + + if (!Driver) + return; + +#ifdef _IRR_SCENEMANAGER_DEBUG + // reset attributes + Parameters->setAttribute("culled", 0); + Parameters->setAttribute("calls", 0); + Parameters->setAttribute("drawn_solid", 0); + Parameters->setAttribute("drawn_transparent", 0); + Parameters->setAttribute("drawn_transparent_effect", 0); +#endif + + u32 i; // new ISO for scoping problem in some compilers + + // reset all transforms + Driver->setMaterial(video::SMaterial()); + Driver->setTransform ( video::ETS_PROJECTION, core::IdentityMatrix ); + Driver->setTransform ( video::ETS_VIEW, core::IdentityMatrix ); + Driver->setTransform ( video::ETS_WORLD, core::IdentityMatrix ); + for (i=video::ETS_COUNT-1; i>=video::ETS_TEXTURE_0; --i) + Driver->setTransform ( (video::E_TRANSFORMATION_STATE)i, core::IdentityMatrix ); + // TODO: This should not use an attribute here but a real parameter when necessary (too slow!) + Driver->setAllowZWriteOnTransparent(Parameters->getAttributeAsBool(ALLOW_ZWRITE_ON_TRANSPARENT)); + + // do animations and other stuff. + IRR_PROFILE(getProfiler().start(EPID_SM_ANIMATE)); + OnAnimate(os::Timer::getTime()); + IRR_PROFILE(getProfiler().stop(EPID_SM_ANIMATE)); + + /*! + First Scene Node for prerendering should be the active camera + consistent Camera is needed for culling + */ + IRR_PROFILE(getProfiler().start(EPID_SM_RENDER_CAMERAS)); + camWorldPos.set(0,0,0); + if (ActiveCamera) + { + ActiveCamera->render(); + camWorldPos = ActiveCamera->getAbsolutePosition(); + } + IRR_PROFILE(getProfiler().stop(EPID_SM_RENDER_CAMERAS)); + + // let all nodes register themselves + OnRegisterSceneNode(); + + if (LightManager) + LightManager->OnPreRender(LightList); + + //render camera scenes + { + IRR_PROFILE(CProfileScope psCam(EPID_SM_RENDER_CAMERAS);) + CurrentRenderPass = ESNRP_CAMERA; + Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0); + + if (LightManager) + LightManager->OnRenderPassPreRender(CurrentRenderPass); + + for (i=0; irender(); + + CameraList.set_used(0); + + if (LightManager) + LightManager->OnRenderPassPostRender(CurrentRenderPass); + } + + //render lights scenes + { + IRR_PROFILE(CProfileScope psLights(EPID_SM_RENDER_LIGHTS);) + CurrentRenderPass = ESNRP_LIGHT; + Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0); + + if (LightManager) + { + LightManager->OnRenderPassPreRender(CurrentRenderPass); + } + 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] = SortedLights[light].Node; + } + + Driver->deleteAllDynamicLights(); + + Driver->setAmbientLight(AmbientLight); + + u32 maxLights = LightList.size(); + + if (!LightManager) + maxLights = core::min_ ( Driver->getMaximalDynamicLightAmount(), maxLights); + + for (i=0; i< maxLights; ++i) + LightList[i]->render(); + + if (LightManager) + LightManager->OnRenderPassPostRender(CurrentRenderPass); + } + + // render skyboxes + { + IRR_PROFILE(CProfileScope psSkyBox(EPID_SM_RENDER_SKYBOXES);) + CurrentRenderPass = ESNRP_SKY_BOX; + Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0); + + if (LightManager) + { + LightManager->OnRenderPassPreRender(CurrentRenderPass); + for (i=0; iOnNodePreRender(node); + node->render(); + LightManager->OnNodePostRender(node); + } + } + else + { + for (i=0; irender(); + } + + SkyBoxList.set_used(0); + + if (LightManager) + LightManager->OnRenderPassPostRender(CurrentRenderPass); + } + + + // render default objects + { + IRR_PROFILE(CProfileScope psDefault(EPID_SM_RENDER_DEFAULT);) + CurrentRenderPass = ESNRP_SOLID; + Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0); + + SolidNodeList.sort(); // sort by textures + + if (LightManager) + { + LightManager->OnRenderPassPreRender(CurrentRenderPass); + for (i=0; iOnNodePreRender(node); + node->render(); + LightManager->OnNodePostRender(node); + } + } + else + { + for (i=0; irender(); + } + +#ifdef _IRR_SCENEMANAGER_DEBUG + Parameters->setAttribute("drawn_solid", (s32) SolidNodeList.size() ); +#endif + SolidNodeList.set_used(0); + + if (LightManager) + LightManager->OnRenderPassPostRender(CurrentRenderPass); + } + + // render shadows + { + IRR_PROFILE(CProfileScope psShadow(EPID_SM_RENDER_SHADOWS);) + CurrentRenderPass = ESNRP_SHADOW; + Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0); + + if (LightManager) + { + LightManager->OnRenderPassPreRender(CurrentRenderPass); + 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(CurrentRenderPass); + } + + // render transparent objects. + { + IRR_PROFILE(CProfileScope psTrans(EPID_SM_RENDER_TRANSPARENT);) + CurrentRenderPass = ESNRP_TRANSPARENT; + Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0); + + TransparentNodeList.sort(); // sort by distance from camera + if (LightManager) + { + LightManager->OnRenderPassPreRender(CurrentRenderPass); + + for (i=0; iOnNodePreRender(node); + node->render(); + LightManager->OnNodePostRender(node); + } + } + else + { + for (i=0; irender(); + } + +#ifdef _IRR_SCENEMANAGER_DEBUG + Parameters->setAttribute ( "drawn_transparent", (s32) TransparentNodeList.size() ); +#endif + TransparentNodeList.set_used(0); + + if (LightManager) + LightManager->OnRenderPassPostRender(CurrentRenderPass); + } + + // render transparent effect objects. + { + IRR_PROFILE(CProfileScope psEffect(EPID_SM_RENDER_EFFECT);) + CurrentRenderPass = ESNRP_TRANSPARENT_EFFECT; + Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0); + + TransparentEffectNodeList.sort(); // sort by distance from camera + + if (LightManager) + { + LightManager->OnRenderPassPreRender(CurrentRenderPass); + + for (i=0; iOnNodePreRender(node); + node->render(); + LightManager->OnNodePostRender(node); + } + } + else + { + for (i=0; irender(); + } +#ifdef _IRR_SCENEMANAGER_DEBUG + Parameters->setAttribute("drawn_transparent_effect", (s32) TransparentEffectNodeList.size()); +#endif + TransparentEffectNodeList.set_used(0); + } + + if (LightManager) + LightManager->OnPostRender(); + + LightList.set_used(0); + clearDeletionList(); + + CurrentRenderPass = ESNRP_NONE; +} + +void CSceneManager::setLightManager(ILightManager* lightManager) +{ + if (lightManager) + lightManager->grab(); + if (LightManager) + LightManager->drop(); + + LightManager = lightManager; +} + + +//! Sets the color of stencil buffers shadows drawn by the scene manager. +void CSceneManager::setShadowColor(video::SColor color) +{ + ShadowColor = color; +} + + +//! Returns the current color of shadows. +video::SColor CSceneManager::getShadowColor() const +{ + return ShadowColor; +} + +IShadowVolumeSceneNode* CSceneManager::createShadowVolumeSceneNode(const IMesh* shadowMesh, ISceneNode* parent, s32 id, bool zfailmethod, f32 infinity) +{ +#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ + return new CShadowVolumeSceneNode(shadowMesh, parent, this, id, zfailmethod, infinity); +#else + return 0; +#endif +} + + + +//! creates a rotation animator, which rotates the attached scene node around itself. +ISceneNodeAnimator* CSceneManager::createRotationAnimator(const core::vector3df& rotationPerSecond) +{ + ISceneNodeAnimator* anim = new CSceneNodeAnimatorRotation(os::Timer::getTime(), + rotationPerSecond); + + return anim; +} + + +//! 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, + f32 startPosition, + f32 radiusEllipsoid) +{ + const f32 orbitDurationMs = (core::DEGTORAD * 360.f) / speed; + const u32 effectiveTime = os::Timer::getTime() + (u32)(orbitDurationMs * startPosition); + + ISceneNodeAnimator* anim = new CSceneNodeAnimatorFlyCircle( + effectiveTime, center, + radius, speed, direction,radiusEllipsoid); + return anim; +} + + +//! Creates a fly straight animator, which lets the attached scene node +//! fly or move along a line between two points. +ISceneNodeAnimator* CSceneManager::createFlyStraightAnimator(const core::vector3df& startPoint, + const core::vector3df& endPoint, u32 timeForWay, bool loop,bool pingpong) +{ + ISceneNodeAnimator* anim = new CSceneNodeAnimatorFlyStraight(startPoint, + endPoint, timeForWay, loop, os::Timer::getTime(), pingpong); + + return anim; +} + + +//! Creates a texture animator, which switches the textures of the target scene +//! node based on a list of textures. +ISceneNodeAnimator* CSceneManager::createTextureAnimator(const core::array& textures, + s32 timePerFrame, bool loop) +{ + ISceneNodeAnimator* anim = new CSceneNodeAnimatorTexture(textures, + timePerFrame, loop, os::Timer::getTime()); + + return anim; +} + + +//! Creates a scene node animator, which deletes the scene node after +//! some time automatically. +ISceneNodeAnimator* CSceneManager::createDeleteAnimator(u32 when) +{ + return new CSceneNodeAnimatorDelete(this, os::Timer::getTime() + when); +} + + +//! Creates a special scene node animator for doing automatic collision detection +//! and response. +ISceneNodeAnimatorCollisionResponse* CSceneManager::createCollisionResponseAnimator( + ITriangleSelector* world, ISceneNode* sceneNode, const core::vector3df& ellipsoidRadius, + const core::vector3df& gravityPerSecond, + const core::vector3df& ellipsoidTranslation, f32 slidingValue) +{ + ISceneNodeAnimatorCollisionResponse* anim = new + CSceneNodeAnimatorCollisionResponse(this, world, sceneNode, + ellipsoidRadius, gravityPerSecond, + ellipsoidTranslation, slidingValue); + + return anim; +} + + +//! Creates a follow spline animator. +ISceneNodeAnimator* CSceneManager::createFollowSplineAnimator(s32 startTime, + const core::array< core::vector3df >& points, + f32 speed, f32 tightness, bool loop, bool pingpong) +{ + ISceneNodeAnimator* a = new CSceneNodeAnimatorFollowSpline(startTime, points, + speed, tightness, loop, pingpong); + return a; +} + + +//! Adds an external mesh loader. +void CSceneManager::addExternalMeshLoader(IMeshLoader* externalLoader) +{ + if (!externalLoader) + return; + + externalLoader->grab(); + MeshLoaderList.push_back(externalLoader); +} + + +//! Returns the number of mesh loaders supported by Irrlicht at this time +u32 CSceneManager::getMeshLoaderCount() const +{ + return MeshLoaderList.size(); +} + + +//! Retrieve the given mesh loader +IMeshLoader* CSceneManager::getMeshLoader(u32 index) const +{ + if (index < MeshLoaderList.size()) + return MeshLoaderList[index]; + else + return 0; +} + + +//! Adds an external scene loader. +void CSceneManager::addExternalSceneLoader(ISceneLoader* externalLoader) +{ + if (!externalLoader) + return; + + externalLoader->grab(); + SceneLoaderList.push_back(externalLoader); +} + + +//! Returns the number of scene loaders +u32 CSceneManager::getSceneLoaderCount() const +{ + return SceneLoaderList.size(); +} + + +//! Retrieve the given scene loader +ISceneLoader* CSceneManager::getSceneLoader(u32 index) const +{ + if (index < SceneLoaderList.size()) + return SceneLoaderList[index]; + else + return 0; +} + + +//! Returns a pointer to the scene collision manager. +ISceneCollisionManager* CSceneManager::getSceneCollisionManager() +{ + return CollisionManager; +} + + +//! Returns a pointer to the mesh manipulator. +IMeshManipulator* CSceneManager::getMeshManipulator() +{ + return Driver->getMeshManipulator(); +} + + +//! Creates a simple ITriangleSelector, based on a mesh. +ITriangleSelector* CSceneManager::createTriangleSelector(IMesh* mesh, ISceneNode* node, bool separateMeshbuffers) +{ + if (!mesh) + return 0; + + return new CTriangleSelector(mesh, node, separateMeshbuffers); +} + +ITriangleSelector* CSceneManager::createTriangleSelector(const IMeshBuffer* meshBuffer, irr::u32 materialIndex, ISceneNode* node) +{ + if ( !meshBuffer) + return 0; + return new CTriangleSelector(meshBuffer, materialIndex, node); +} + + +//! Creates a ITriangleSelector, based on a the mesh owned by an animated scene node +ITriangleSelector* CSceneManager::createTriangleSelector(IAnimatedMeshSceneNode* node, bool separateMeshbuffers) +{ + if (!node || !node->getMesh()) + return 0; + + return new CTriangleSelector(node, separateMeshbuffers); +} + + +//! Creates a simple dynamic ITriangleSelector, based on a axis aligned bounding box. +ITriangleSelector* CSceneManager::createTriangleSelectorFromBoundingBox(ISceneNode* node) +{ + if (!node) + return 0; + + return new CTriangleBBSelector(node); +} + + +//! Creates a simple ITriangleSelector, based on a mesh. +ITriangleSelector* CSceneManager::createOctreeTriangleSelector(IMesh* mesh, + ISceneNode* node, s32 minimalPolysPerNode) +{ + if (!mesh) + return 0; + + return new COctreeTriangleSelector(mesh, node, minimalPolysPerNode); +} + +ITriangleSelector* CSceneManager::createOctreeTriangleSelector(IMeshBuffer* meshBuffer, irr::u32 materialIndex, + ISceneNode* node, s32 minimalPolysPerNode) +{ + if ( !meshBuffer) + return 0; + + return new COctreeTriangleSelector(meshBuffer, materialIndex, node, minimalPolysPerNode); +} + +//! Creates a meta triangle selector. +IMetaTriangleSelector* CSceneManager::createMetaTriangleSelector() +{ + return new CMetaTriangleSelector(); +} + + +//! Creates a triangle selector which can select triangles from a terrain scene node +ITriangleSelector* CSceneManager::createTerrainTriangleSelector( + ITerrainSceneNode* node, s32 LOD) +{ +#ifdef _IRR_COMPILE_WITH_TERRAIN_SCENENODE_ + return new CTerrainTriangleSelector(node, LOD); +#else + return 0; +#endif +} + + + +//! Adds a scene node to the deletion queue. +void CSceneManager::addToDeletionQueue(ISceneNode* node) +{ + if (!node) + return; + + node->grab(); + DeletionList.push_back(node); +} + + +//! clears the deletion list +void CSceneManager::clearDeletionList() +{ + if (DeletionList.empty()) + return; + + for (u32 i=0; iremove(); + DeletionList[i]->drop(); + } + + DeletionList.clear(); +} + + +//! Returns the first scene node with the specified name. +ISceneNode* CSceneManager::getSceneNodeFromName(const char* name, ISceneNode* start) +{ + if (start == 0) + start = getRootSceneNode(); + + if (!strcmp(start->getName(),name)) + return start; + + ISceneNode* node = 0; + + const ISceneNodeList& list = start->getChildren(); + ISceneNodeList::ConstIterator it = list.begin(); + for (; it!=list.end(); ++it) + { + node = getSceneNodeFromName(name, *it); + if (node) + return node; + } + + return 0; +} + + +//! Returns the first scene node with the specified id. +ISceneNode* CSceneManager::getSceneNodeFromId(s32 id, ISceneNode* start) +{ + if (start == 0) + start = getRootSceneNode(); + + if (start->getID() == id) + return start; + + ISceneNode* node = 0; + + const ISceneNodeList& list = start->getChildren(); + ISceneNodeList::ConstIterator it = list.begin(); + for (; it!=list.end(); ++it) + { + node = getSceneNodeFromId(id, *it); + if (node) + return node; + } + + return 0; +} + + +//! Returns the first scene node with the specified type. +ISceneNode* CSceneManager::getSceneNodeFromType(scene::ESCENE_NODE_TYPE type, ISceneNode* start) +{ + if (start == 0) + start = getRootSceneNode(); + + if (start->getType() == type || ESNT_ANY == type) + return start; + + ISceneNode* node = 0; + + const ISceneNodeList& list = start->getChildren(); + ISceneNodeList::ConstIterator it = list.begin(); + for (; it!=list.end(); ++it) + { + node = getSceneNodeFromType(type, *it); + if (node) + return node; + } + + return 0; +} + + +//! returns scene nodes by type. +void CSceneManager::getSceneNodesFromType(ESCENE_NODE_TYPE type, core::array& outNodes, ISceneNode* start) +{ + if (start == 0) + start = getRootSceneNode(); + + if (start->getType() == type || ESNT_ANY == type) + outNodes.push_back(start); + + const ISceneNodeList& list = start->getChildren(); + ISceneNodeList::ConstIterator it = list.begin(); + + for (; it!=list.end(); ++it) + { + getSceneNodesFromType(type, outNodes, *it); + } +} + + +//! Posts an input event to the environment. Usually you do not have to +//! use this method, it is used by the internal engine. +bool CSceneManager::postEventFromUser(const SEvent& event) +{ + bool ret = false; + ICameraSceneNode* cam = getActiveCamera(); + if (cam) + ret = cam->OnEvent(event); + + return ret; +} + + +//! Removes all children of this scene node +void CSceneManager::removeAll() +{ + ISceneNode::removeAll(); + setActiveCamera(0); + // Make sure the driver is reset, might need a more complex method at some point + if (Driver) + Driver->setMaterial(video::SMaterial()); +} + + +//! Clears the whole scene. All scene nodes are removed. +void CSceneManager::clear() +{ + removeAll(); +} + + +//! Returns interface to the parameters set in this scene. +io::IAttributes* CSceneManager::getParameters() +{ + return Parameters; +} + + +//! Returns current render pass. +E_SCENE_NODE_RENDER_PASS CSceneManager::getSceneNodeRenderPass() const +{ + return CurrentRenderPass; +} + + +//! Returns an interface to the mesh cache which is shared between all existing scene managers. +IMeshCache* CSceneManager::getMeshCache() +{ + return MeshCache; +} + + +//! Creates a new scene manager. +ISceneManager* CSceneManager::createNewSceneManager(bool cloneContent) +{ + CSceneManager* manager = new CSceneManager(Driver, FileSystem, CursorControl, MeshCache, GUIEnvironment); + + if (cloneContent) + manager->cloneMembers(this, manager); + + return manager; +} + + +//! Returns the default scene node factory which can create all built in scene nodes +ISceneNodeFactory* CSceneManager::getDefaultSceneNodeFactory() +{ + return getSceneNodeFactory(0); +} + + +//! Adds a scene node factory to the scene manager. +void CSceneManager::registerSceneNodeFactory(ISceneNodeFactory* factoryToAdd) +{ + if (factoryToAdd) + { + factoryToAdd->grab(); + SceneNodeFactoryList.push_back(factoryToAdd); + } +} + + +//! Returns amount of registered scene node factories. +u32 CSceneManager::getRegisteredSceneNodeFactoryCount() const +{ + return SceneNodeFactoryList.size(); +} + + +//! Returns a scene node factory by index +ISceneNodeFactory* CSceneManager::getSceneNodeFactory(u32 index) +{ + if (index < SceneNodeFactoryList.size()) + return SceneNodeFactoryList[index]; + + return 0; +} + + +//! Returns the default scene node animator factory which can create all built-in scene node animators +ISceneNodeAnimatorFactory* CSceneManager::getDefaultSceneNodeAnimatorFactory() +{ + return getSceneNodeAnimatorFactory(0); +} + +//! Adds a scene node animator factory to the scene manager. +void CSceneManager::registerSceneNodeAnimatorFactory(ISceneNodeAnimatorFactory* factoryToAdd) +{ + if (factoryToAdd) + { + factoryToAdd->grab(); + SceneNodeAnimatorFactoryList.push_back(factoryToAdd); + } +} + + +//! Returns amount of registered scene node animator factories. +u32 CSceneManager::getRegisteredSceneNodeAnimatorFactoryCount() const +{ + return SceneNodeAnimatorFactoryList.size(); +} + + +//! Returns a scene node animator factory by index +ISceneNodeAnimatorFactory* CSceneManager::getSceneNodeAnimatorFactory(u32 index) +{ + if (index < SceneNodeAnimatorFactoryList.size()) + return SceneNodeAnimatorFactoryList[index]; + + return 0; +} + + +//! Saves the current scene into a file. +//! \param filename: Name of the file . +bool CSceneManager::saveScene(const io::path& filename, ISceneUserDataSerializer* userDataSerializer, ISceneNode* node) +{ + bool ret = false; + io::IWriteFile* file = FileSystem->createAndWriteFile(filename); + if (file) + { + ret = saveScene(file, userDataSerializer, node); + file->drop(); + } + else + os::Printer::log("Unable to open file", filename, ELL_ERROR); + + return ret; +} + + +//! Saves the current scene into a file. +bool CSceneManager::saveScene(io::IWriteFile* file, ISceneUserDataSerializer* userDataSerializer, ISceneNode* node) +{ + if (!file) + { + return false; + } + + bool result=false; + io::IXMLWriter* writer = FileSystem->createXMLWriter(file); + if (!writer) + { + os::Printer::log("Unable to create XML writer", file->getFileName(), ELL_ERROR); + } + else + { + result = saveScene(writer, FileSystem->getFileDir(FileSystem->getAbsolutePath(file->getFileName())), userDataSerializer, node); + writer->drop(); + } + return result; +} + + +//! Saves the current scene into a file. +bool CSceneManager::saveScene(io::IXMLWriter* writer, const io::path& currentPath, ISceneUserDataSerializer* userDataSerializer, ISceneNode* node) +{ + if (!writer) + return false; + + if (!node) + node=this; + + char* oldLocale = setlocale(LC_NUMERIC, NULL); + setlocale(LC_NUMERIC, "C"); // float number should to be saved with dots in this format independent of current locale settings. + + writer->writeXMLHeader(); + writeSceneNode(writer, node, userDataSerializer, currentPath.c_str(), true); + + setlocale(LC_NUMERIC, oldLocale); + + return true; +} + + +//! Loads a scene. +bool CSceneManager::loadScene(const io::path& filename, ISceneUserDataSerializer* userDataSerializer, ISceneNode* rootNode) +{ + io::IReadFile* file = FileSystem->createAndOpenFile(filename); + if (!file) + { + os::Printer::log("Unable to open scene file", filename.c_str(), ELL_ERROR); + return false; + } + + const bool ret = loadScene(file, userDataSerializer, rootNode); + file->drop(); + + return ret; +} + + +//! Loads a scene. Note that the current scene is not cleared before. +bool CSceneManager::loadScene(io::IReadFile* file, ISceneUserDataSerializer* userDataSerializer, ISceneNode* rootNode) +{ + if (!file) + { + os::Printer::log("Unable to open scene file", ELL_ERROR); + return false; + } + + bool ret = false; + + // try scene loaders in reverse order + s32 i = SceneLoaderList.size()-1; + for (; i >= 0 && !ret; --i) + if (SceneLoaderList[i]->isALoadableFileFormat(file)) + ret = SceneLoaderList[i]->loadScene(file, userDataSerializer, rootNode); + + if (!ret) + os::Printer::log("Could not load scene file, perhaps the format is unsupported: ", file->getFileName().c_str(), ELL_ERROR); + + return ret; +} + + +//! writes a scene node +void CSceneManager::writeSceneNode(io::IXMLWriter* writer, ISceneNode* node, ISceneUserDataSerializer* userDataSerializer, + const fschar_t* currentPath, bool init) +{ + if (!writer || !node || node->isDebugObject()) + return; + + const wchar_t* name; + ISceneNode* tmpNode=node; + + if (init) + { + name = IRR_XML_FORMAT_SCENE.c_str(); + writer->writeElement(name, false); + node=this; + } + else + { + name = IRR_XML_FORMAT_NODE.c_str(); + writer->writeElement(name, false, IRR_XML_FORMAT_NODE_ATTR_TYPE.c_str(), + core::stringw(getSceneNodeTypeName(node->getType())).c_str()); + } + + writer->writeLineBreak(); + + // write properties + + io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver); + io::SAttributeReadWriteOptions options; + if (currentPath) + { + options.Filename=currentPath; + options.Flags|=io::EARWF_USE_RELATIVE_PATHS; + } + node->serializeAttributes(attr, &options); + + if (attr->getAttributeCount() != 0) + { + attr->write(writer); + writer->writeLineBreak(); + } + + // write materials + + if (node->getMaterialCount() && Driver) + { + const wchar_t* materialElement = L"materials"; + + writer->writeElement(materialElement); + writer->writeLineBreak(); + + for (u32 i=0; i < node->getMaterialCount(); ++i) + { + io::IAttributes* tmp_attr = + Driver->createAttributesFromMaterial(node->getMaterial(i), &options); + tmp_attr->write(writer); + tmp_attr->drop(); + } + + writer->writeClosingTag(materialElement); + writer->writeLineBreak(); + } + + // write animators + + if (!node->getAnimators().empty()) + { + const wchar_t* animatorElement = L"animators"; + writer->writeElement(animatorElement); + writer->writeLineBreak(); + + ISceneNodeAnimatorList::ConstIterator it = node->getAnimators().begin(); + for (; it != node->getAnimators().end(); ++it) + { + attr->clear(); + attr->addString("Type", getAnimatorTypeName((*it)->getType())); + + (*it)->serializeAttributes(attr); + + attr->write(writer); + } + + writer->writeClosingTag(animatorElement); + writer->writeLineBreak(); + } + + // write possible user data + + if (userDataSerializer) + { + io::IAttributes* userData = userDataSerializer->createUserData(node); + if (userData) + { + const wchar_t* userDataElement = L"userData"; + + writer->writeLineBreak(); + writer->writeElement(userDataElement); + writer->writeLineBreak(); + + userData->write(writer); + + writer->writeClosingTag(userDataElement); + writer->writeLineBreak(); + writer->writeLineBreak(); + + userData->drop(); + } + } + // reset to actual root node + if (init) + node=tmpNode; + + // write children once root node is written + // if parent is not scene manager, we need to write out node first + if (init && (node != this)) + { + writeSceneNode(writer, node, userDataSerializer, currentPath); + } + else + { + ISceneNodeList::ConstIterator it = node->getChildren().begin(); + for (; it != node->getChildren().end(); ++it) + writeSceneNode(writer, (*it), userDataSerializer, currentPath); + } + + attr->drop(); + + writer->writeClosingTag(name); + writer->writeLineBreak(); + writer->writeLineBreak(); +} + + +//! Returns a typename from a scene node type or null if not found +const c8* CSceneManager::getSceneNodeTypeName(ESCENE_NODE_TYPE type) +{ + const char* name = 0; + + for (s32 i=(s32)SceneNodeFactoryList.size()-1; !name && i>=0; --i) + name = SceneNodeFactoryList[i]->getCreateableSceneNodeTypeName(type); + + return name; +} + +//! Adds a scene node to the scene by name +ISceneNode* CSceneManager::addSceneNode(const char* sceneNodeTypeName, ISceneNode* parent) +{ + ISceneNode* node = 0; + + for (s32 i=(s32)SceneNodeFactoryList.size()-1; i>=0 && !node; --i) + node = SceneNodeFactoryList[i]->addSceneNode(sceneNodeTypeName, parent); + + return node; +} + +ISceneNodeAnimator* CSceneManager::createSceneNodeAnimator(const char* typeName, ISceneNode* target) +{ + ISceneNodeAnimator *animator = 0; + + for (s32 i=(s32)SceneNodeAnimatorFactoryList.size()-1; i>=0 && !animator; --i) + animator = SceneNodeAnimatorFactoryList[i]->createSceneNodeAnimator(typeName, target); + + return animator; +} + + +//! Returns a typename from a scene node animator type or null if not found +const c8* CSceneManager::getAnimatorTypeName(ESCENE_NODE_ANIMATOR_TYPE type) +{ + const char* name = 0; + + for (s32 i=SceneNodeAnimatorFactoryList.size()-1; !name && i >= 0; --i) + name = SceneNodeAnimatorFactoryList[i]->getCreateableSceneNodeAnimatorTypeName(type); + + return name; +} + + +//! Writes attributes of the scene node. +void CSceneManager::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + out->addString ("Name", Name.c_str()); + out->addInt ("Id", ID ); + out->addColorf ("AmbientLight", AmbientLight); + + // fog attributes from video driver + video::SColor color; + video::E_FOG_TYPE fogType; + f32 start, end, density; + bool pixelFog, rangeFog; + + Driver->getFog(color, fogType, start, end, density, pixelFog, rangeFog); + + out->addEnum("FogType", fogType, video::FogTypeNames); + out->addColorf("FogColor", color); + out->addFloat("FogStart", start); + out->addFloat("FogEnd", end); + out->addFloat("FogDensity", density); + out->addBool("FogPixel", pixelFog); + out->addBool("FogRange", rangeFog); +} + +//! Reads attributes of the scene node. +void CSceneManager::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + Name = in->getAttributeAsString("Name"); + ID = in->getAttributeAsInt("Id"); + AmbientLight = in->getAttributeAsColorf("AmbientLight"); + + // fog attributes + video::SColor color; + video::E_FOG_TYPE fogType; + f32 start, end, density; + bool pixelFog, rangeFog; + if (in->existsAttribute("FogType")) + { + fogType = (video::E_FOG_TYPE) in->getAttributeAsEnumeration("FogType", video::FogTypeNames); + color = in->getAttributeAsColorf("FogColor").toSColor(); + start = in->getAttributeAsFloat("FogStart"); + end = in->getAttributeAsFloat("FogEnd"); + density = in->getAttributeAsFloat("FogDensity"); + pixelFog = in->getAttributeAsBool("FogPixel"); + rangeFog = in->getAttributeAsBool("FogRange"); + Driver->setFog(color, fogType, start, end, density, pixelFog, rangeFog); + } + + RelativeTranslation.set(0,0,0); + RelativeRotation.set(0,0,0); + RelativeScale.set(1,1,1); + IsVisible = true; + AutomaticCullingState = scene::EAC_BOX; + DebugDataVisible = scene::EDS_OFF; + IsDebugObject = false; + + updateAbsolutePosition(); +} + + +//! Sets ambient color of the scene +void CSceneManager::setAmbientLight(const video::SColorf &ambientColor) +{ + AmbientLight = ambientColor; +} + + +//! Returns ambient color of the scene +const video::SColorf& CSceneManager::getAmbientLight() const +{ + return AmbientLight; +} + + +//! Get a skinned mesh, which is not available as header-only code +ISkinnedMesh* CSceneManager::createSkinnedMesh() +{ +#ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ + return new CSkinnedMesh(); +#else + return 0; +#endif +} + +//! Returns a mesh writer implementation if available +IMeshWriter* CSceneManager::createMeshWriter(EMESH_WRITER_TYPE type) +{ + switch(type) + { + case EMWT_IRR_MESH: +#ifdef _IRR_COMPILE_WITH_IRR_WRITER_ + return new CIrrMeshWriter(Driver, FileSystem); +#else + return 0; +#endif + case EMWT_COLLADA: +#ifdef _IRR_COMPILE_WITH_COLLADA_WRITER_ + return new CColladaMeshWriter(this, Driver, FileSystem); +#else + return 0; +#endif + case EMWT_STL: +#ifdef _IRR_COMPILE_WITH_STL_WRITER_ + return new CSTLMeshWriter(this); +#else + return 0; +#endif + case EMWT_OBJ: +#ifdef _IRR_COMPILE_WITH_OBJ_WRITER_ + return new COBJMeshWriter(this, FileSystem); +#else + return 0; +#endif + + case EMWT_PLY: +#ifdef _IRR_COMPILE_WITH_PLY_WRITER_ + return new CPLYMeshWriter(); +#else + return 0; +#endif + + case EMWT_B3D: +#ifdef _IRR_COMPILE_WITH_B3D_WRITER_ + return new CB3DMeshWriter(); +#else + return 0; +#endif + } + + return 0; +} + + +// creates a scenemanager +ISceneManager* createSceneManager(video::IVideoDriver* driver, + io::IFileSystem* fs, gui::ICursorControl* cursorcontrol, + gui::IGUIEnvironment *guiEnvironment) +{ + return new CSceneManager(driver, fs, cursorcontrol, 0, guiEnvironment ); +} + + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CSceneManager.h b/source/Irrlicht/CSceneManager.h new file mode 100644 index 00000000..a83ab48b --- /dev/null +++ b/source/Irrlicht/CSceneManager.h @@ -0,0 +1,675 @@ +// Copyright (C) 2002-2012 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_MANAGER_H_INCLUDED__ +#define __C_SCENE_MANAGER_H_INCLUDED__ + +#include "ISceneManager.h" +#include "ISceneNode.h" +#include "ICursorControl.h" +#include "irrString.h" +#include "irrArray.h" +#include "IMeshLoader.h" +#include "CAttributes.h" +#include "ILightManager.h" + +namespace irr +{ +namespace io +{ + class IFileSystem; +} +namespace scene +{ + class IMeshCache; + class IGeometryCreator; + + /*! + The Scene Manager manages scene nodes, mesh resources, cameras and all the other stuff. + */ + class CSceneManager : public ISceneManager, public ISceneNode + { + public: + + //! constructor + CSceneManager(video::IVideoDriver* driver, io::IFileSystem* fs, + gui::ICursorControl* cursorControl, IMeshCache* cache = 0, + gui::IGUIEnvironment *guiEnvironment = 0); + + //! destructor + virtual ~CSceneManager(); + + //! gets an animateable mesh. loads it if needed. returned pointer must not be dropped. + virtual IAnimatedMesh* getMesh(const io::path& filename, const io::path& alternativeCacheName) _IRR_OVERRIDE_; + + //! gets an animateable mesh. loads it if needed. returned pointer must not be dropped. + virtual IAnimatedMesh* getMesh(io::IReadFile* file) _IRR_OVERRIDE_; + + //! Returns an interface to the mesh cache which is shared between all existing scene managers. + virtual IMeshCache* getMeshCache() _IRR_OVERRIDE_; + + //! returns the video driver + virtual video::IVideoDriver* getVideoDriver() _IRR_OVERRIDE_; + + //! return the gui environment + virtual gui::IGUIEnvironment* getGUIEnvironment() _IRR_OVERRIDE_; + + //! return the filesystem + virtual io::IFileSystem* getFileSystem() _IRR_OVERRIDE_; + + //! adds Volume Lighting Scene Node. + //! the returned pointer must not be dropped. + 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), + const video::SColor tail = video::SColor(0, 0, 0, 0), + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) _IRR_OVERRIDE_; + + //! adds a cube scene node to the scene. It is a simple cube of (1,1,1) size. + //! the returned pointer must not be dropped. + virtual IMeshSceneNode* addCubeSceneNode(f32 size=10.0f, ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) _IRR_OVERRIDE_; + + //! Adds a sphere scene node to the scene. + virtual IMeshSceneNode* addSphereSceneNode(f32 radius=5.0f, s32 polyCount=16, ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) _IRR_OVERRIDE_; + + //! adds a scene node for rendering an animated mesh model + virtual IAnimatedMeshSceneNode* addAnimatedMeshSceneNode(IAnimatedMesh* mesh, ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f), + bool alsoAddIfMeshPointerZero=false) _IRR_OVERRIDE_; + + //! adds a scene node for rendering a static mesh + //! the returned pointer must not be dropped. + virtual IMeshSceneNode* addMeshSceneNode(IMesh* mesh, ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f), + bool alsoAddIfMeshPointerZero=false) _IRR_OVERRIDE_; + + //! Adds a scene node for rendering a animated water surface mesh. + virtual ISceneNode* addWaterSurfaceSceneNode(IMesh* mesh, f32 waveHeight, f32 waveSpeed, f32 wlength, ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) _IRR_OVERRIDE_; + + //! renders the node. + virtual void render() _IRR_OVERRIDE_; + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + //! registers a node for rendering it at a specific time. + virtual u32 registerNodeForRendering(ISceneNode* node, E_SCENE_NODE_RENDER_PASS pass = ESNRP_AUTOMATIC) _IRR_OVERRIDE_; + + //! Clear all nodes which are currently registered for rendering + virtual void clearAllRegisteredNodesForRendering() _IRR_OVERRIDE_; + + //! draws all scene nodes + virtual void drawAll() _IRR_OVERRIDE_; + + //! Adds a scene node for rendering using a octree 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, much + //! faster then a bsp tree. + virtual IOctreeSceneNode* addOctreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent=0, + s32 id=-1, s32 minimalPolysPerNode=512, bool alsoAddIfMeshPointerZero=false) _IRR_OVERRIDE_; + + //! Adss a scene node for rendering using a octree. This a good method for rendering + //! scenes with lots of geometry. The Octree is built on the fly from the mesh, much + //! faster then a bsp tree. + virtual IOctreeSceneNode* addOctreeSceneNode(IMesh* mesh, ISceneNode* parent=0, + s32 id=-1, s32 minimalPolysPerNode=128, bool alsoAddIfMeshPointerZero=false) _IRR_OVERRIDE_; + + //! Adds a camera scene node to the tree and sets it as active camera. + //! \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. + //! \return Pointer to interface to camera + 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, bool makeActive=true) _IRR_OVERRIDE_; + + //! Adds a camera scene node which is able to be controlle with the mouse similar + //! like in the 3D Software Maya by Alias Wavefront. + //! The returned pointer must not be dropped. + virtual ICameraSceneNode* addCameraSceneNodeMaya(ISceneNode* parent=0, + f32 rotateSpeed=-1500.f, f32 zoomSpeed=200.f, + f32 translationSpeed=1500.f, s32 id=-1, f32 distance=70.f, + bool makeActive=true) _IRR_OVERRIDE_; + + //! Adds a camera scene node which is able to be controled with the mouse and keys + //! like in most first person shooters (FPS): + 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, + bool invertMouseY=false, bool makeActive=true) _IRR_OVERRIDE_; + + //! 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 + //! turned on. (This is the default setting in most scene nodes). + 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), + f32 range=100.0f, s32 id=-1) _IRR_OVERRIDE_; + + //! Adds a billboard scene node to the scene. 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. + 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, + video::SColor shadeTop = 0xFFFFFFFF, video::SColor shadeBottom = 0xFFFFFFFF) _IRR_OVERRIDE_; + + //! Adds a skybox scene node. A skybox is a big cube with 6 textures on it and + //! is drawn around the camera position. + 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) _IRR_OVERRIDE_; + + //! Adds a skydome scene node. A skydome is a large (half-) sphere with a + //! panoramic texture on it and is drawn around the camera position. + virtual ISceneNode* addSkyDomeSceneNode(video::ITexture* texture, + u32 horiRes=16, u32 vertRes=8, + f32 texturePercentage=0.9, f32 spherePercentage=2.0,f32 radius = 1000.f, + ISceneNode* parent=0, s32 id=-1) _IRR_OVERRIDE_; + + //! Adds a text scene node, which is able to display + //! 2d text at a position in three dimensional space + virtual ITextSceneNode* addTextSceneNode(gui::IGUIFont* font, const wchar_t* text, + video::SColor color=video::SColor(100,255,255,255), + ISceneNode* parent = 0, const core::vector3df& position = core::vector3df(0,0,0), + s32 id=-1) _IRR_OVERRIDE_; + + //! Adds a text scene node, which uses billboards + virtual IBillboardTextSceneNode* addBillboardTextSceneNode(gui::IGUIFont* font, const wchar_t* text, + 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, + video::SColor colorTop = 0xFFFFFFFF, video::SColor colorBottom = 0xFFFFFFFF) _IRR_OVERRIDE_; + + //! Adds a scene node, which can render a quake3 shader + virtual IMeshSceneNode* addQuake3SceneNode(const IMeshBuffer* meshBuffer, const quake3::IShader * shader, + ISceneNode* parent=0, s32 id=-1) _IRR_OVERRIDE_; + + + //! 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. You can specify how many hills 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 back using ISceneManager::getMesh with the + //! name as parameter. + virtual IAnimatedMesh* addHillPlaneMesh(const io::path& name, + const core::dimension2d& tileSize, const core::dimension2d& tileCount, + video::SMaterial* material = 0, f32 hillHeight = 0.0f, + const core::dimension2d& countHills = core::dimension2d(1.0f, 1.0f), + const core::dimension2d& textureRepeatCount = core::dimension2d(1.0f, 1.0f)) _IRR_OVERRIDE_; + + //! Adds a terrain mesh to the mesh pool. + virtual IAnimatedMesh* addTerrainMesh(const io::path& 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)) _IRR_OVERRIDE_; + + //! Add a arrow mesh to the mesh pool + virtual IAnimatedMesh* addArrowMesh(const io::path& name, + video::SColor vtxColor0, video::SColor vtxColor1, + u32 tesselationCylinder, u32 tesselationCone, + f32 height, f32 cylinderHeight, f32 width0, + f32 width1) _IRR_OVERRIDE_; + + //! Adds a static sphere mesh to the mesh pool. + virtual IAnimatedMesh* addSphereMesh(const io::path& name, + f32 radius=5.f, u32 polyCountX=16, u32 polyCountY=16) _IRR_OVERRIDE_; + + //! Adds a static volume light mesh to the mesh pool. + virtual IAnimatedMesh* addVolumeLightMesh(const io::path& name, + const u32 SubdivideU = 32, const u32 SubdivideV = 32, + const video::SColor FootColor = video::SColor(51, 0, 230, 180), + const video::SColor TailColor = video::SColor(0, 0, 0, 0)) _IRR_OVERRIDE_; + + //! Adds a particle system scene node. + virtual IParticleSystemSceneNode* addParticleSystemSceneNode( + bool withDefaultEmitter=true, ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) _IRR_OVERRIDE_; + + //! Adds a terrain scene node to the scene graph. + virtual ITerrainSceneNode* addTerrainSceneNode( + const io::path& heightMapFileName, + ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& rotation = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& scale = core::vector3df(1.0f,1.0f,1.0f), + video::SColor vertexColor = video::SColor(255,255,255,255), + s32 maxLOD=4, E_TERRAIN_PATCH_SIZE patchSize=ETPS_17,s32 smoothFactor=0, + bool addAlsoIfHeightmapEmpty = false) _IRR_OVERRIDE_; + + //! Adds a terrain scene node to the scene graph. + virtual ITerrainSceneNode* addTerrainSceneNode( + io::IReadFile* heightMap, + ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& rotation = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& scale = core::vector3df(1.0f,1.0f,1.0f), + video::SColor vertexColor = video::SColor(255,255,255,255), + s32 maxLOD=4, E_TERRAIN_PATCH_SIZE patchSize=ETPS_17,s32 smoothFactor=0, + bool addAlsoIfHeightmapEmpty=false) _IRR_OVERRIDE_; + + //! Adds a dummy transformation scene node to the scene graph. + virtual IDummyTransformationSceneNode* addDummyTransformationSceneNode( + ISceneNode* parent=0, s32 id=-1) _IRR_OVERRIDE_; + + //! Adds an empty scene node. + virtual ISceneNode* addEmptySceneNode(ISceneNode* parent, s32 id=-1) _IRR_OVERRIDE_; + + //! Returns 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 is not rendered and cannot + //! be removed from the scene. + //! \return Pointer to the root scene node. + virtual ISceneNode* getRootSceneNode() _IRR_OVERRIDE_; + + //! Returns the current active camera. + //! \return The active camera is returned. Note that this can be NULL, if there + //! was no camera created yet. + virtual ICameraSceneNode* getActiveCamera() const _IRR_OVERRIDE_; + + //! Sets the active camera. The previous active camera will be deactivated. + //! \param camera: The new camera which should be active. + virtual void setActiveCamera(ICameraSceneNode* camera) _IRR_OVERRIDE_; + + //! 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. + virtual ISceneNodeAnimator* createRotationAnimator(const core::vector3df& rotationPerSecond) _IRR_OVERRIDE_; + + //! creates a fly circle animator + /** Lets the attached scene node fly around a center. + \param center Center relative to node origin + \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), + f32 startPosition = 0.f, + f32 radiusEllipsoid = 0.f) _IRR_OVERRIDE_; + + //! Creates a fly straight animator, which lets the attached scene node + //! fly or move along a line between two points. + virtual ISceneNodeAnimator* createFlyStraightAnimator(const core::vector3df& startPoint, + const core::vector3df& endPoint, u32 timeForWay, bool loop=false,bool pingpong = false) _IRR_OVERRIDE_; + + //! Creates a texture animator, which switches the textures of the target scene + //! node based on a list of textures. + virtual ISceneNodeAnimator* createTextureAnimator(const core::array& textures, + s32 timePerFrame, bool loop) _IRR_OVERRIDE_; + + //! Creates a scene node animator, which deletes the scene node after + //! some time automatically. + virtual ISceneNodeAnimator* createDeleteAnimator(u32 timeMS) _IRR_OVERRIDE_; + + + //! Creates a special scene node animator for doing automatic collision detection + //! and response. + virtual ISceneNodeAnimatorCollisionResponse* createCollisionResponseAnimator( + ITriangleSelector* world, ISceneNode* sceneNode, + const core::vector3df& ellipsoidRadius = core::vector3df(30,60,30), + const core::vector3df& gravityPerSecond = core::vector3df(0,-1.0f,0), + const core::vector3df& ellipsoidTranslation = core::vector3df(0,0,0), + f32 slidingValue = 0.0005f) _IRR_OVERRIDE_; + + //! Creates a follow spline animator. + virtual ISceneNodeAnimator* createFollowSplineAnimator(s32 startTime, + const core::array< core::vector3df >& points, + f32 speed, f32 tightness, bool loop, bool pingpong) _IRR_OVERRIDE_; + + + //! Creates a simple ITriangleSelector, based on a mesh. + virtual ITriangleSelector* createTriangleSelector(IMesh* mesh, ISceneNode* node, bool separateMeshbuffers) _IRR_OVERRIDE_; + + //! Creates a simple ITriangleSelector, based on a meshbuffer. + virtual ITriangleSelector* createTriangleSelector(const IMeshBuffer* meshBuffer, irr::u32 materialIndex, ISceneNode* node) _IRR_OVERRIDE_; + + //! Creates a simple ITriangleSelector, based on an animated mesh scene node. + //! Details of the mesh associated with the node will be extracted internally. + //! Call ITriangleSelector::update() to have the triangle selector updated based + //! on the current frame of the animated mesh scene node. + //! \param: The animated mesh scene node from which to build the selector + virtual ITriangleSelector* createTriangleSelector(IAnimatedMeshSceneNode* node, bool separateMeshbuffers) _IRR_OVERRIDE_; + + //! Creates a simple ITriangleSelector, based on a mesh. + virtual ITriangleSelector* createOctreeTriangleSelector(IMesh* mesh, + ISceneNode* node, s32 minimalPolysPerNode) _IRR_OVERRIDE_; + + //! Creates a simple ITriangleSelector, based on a meshbuffer. + virtual ITriangleSelector* createOctreeTriangleSelector(IMeshBuffer* meshBuffer, irr::u32 materialIndex, + ISceneNode* node, s32 minimalPolysPerNode=32) _IRR_OVERRIDE_; + + //! Creates a simple dynamic ITriangleSelector, based on a axis aligned bounding box. + virtual ITriangleSelector* createTriangleSelectorFromBoundingBox( + ISceneNode* node) _IRR_OVERRIDE_; + + //! Creates a meta triangle selector. + virtual IMetaTriangleSelector* createMetaTriangleSelector() _IRR_OVERRIDE_; + + //! Creates a triangle selector which can select triangles from a terrain scene node + //! \param: Pointer to the created terrain scene node + //! \param: Level of detail, 0 for highest detail. + virtual ITriangleSelector* createTerrainTriangleSelector( + ITerrainSceneNode* node, s32 LOD=0) _IRR_OVERRIDE_; + + //! Adds an external mesh loader. + virtual void addExternalMeshLoader(IMeshLoader* externalLoader) _IRR_OVERRIDE_; + + //! Returns the number of mesh loaders supported by Irrlicht at this time + virtual u32 getMeshLoaderCount() const _IRR_OVERRIDE_; + + //! Retrieve the given mesh loader + virtual IMeshLoader* getMeshLoader(u32 index) const _IRR_OVERRIDE_; + + //! Adds an external scene loader. + virtual void addExternalSceneLoader(ISceneLoader* externalLoader) _IRR_OVERRIDE_; + + //! Returns the number of scene loaders supported by Irrlicht at this time + virtual u32 getSceneLoaderCount() const _IRR_OVERRIDE_; + + //! Retrieve the given scene loader + virtual ISceneLoader* getSceneLoader(u32 index) const _IRR_OVERRIDE_; + + //! Returns a pointer to the scene collision manager. + virtual ISceneCollisionManager* getSceneCollisionManager() _IRR_OVERRIDE_; + + //! Returns a pointer to the mesh manipulator. + virtual IMeshManipulator* getMeshManipulator() _IRR_OVERRIDE_; + + //! Sets the color of stencil buffers shadows drawn by the scene manager. + virtual void setShadowColor(video::SColor color) _IRR_OVERRIDE_; + + //! Returns the current color of shadows. + virtual video::SColor getShadowColor() const _IRR_OVERRIDE_; + + //! Create a shadow volume scene node to be used with custom nodes + virtual IShadowVolumeSceneNode* createShadowVolumeSceneNode(const IMesh* shadowMesh, ISceneNode* parent, s32 id, bool zfailmethod, f32 infinity) _IRR_OVERRIDE_; + + //! Adds a scene node to the deletion queue. + virtual void addToDeletionQueue(ISceneNode* node) _IRR_OVERRIDE_; + + //! Returns the first scene node with the specified id. + virtual ISceneNode* getSceneNodeFromId(s32 id, ISceneNode* start=0) _IRR_OVERRIDE_; + + //! Returns the first scene node with the specified name. + virtual ISceneNode* getSceneNodeFromName(const c8* name, ISceneNode* start=0) _IRR_OVERRIDE_; + + //! Returns the first scene node with the specified type. + virtual ISceneNode* getSceneNodeFromType(scene::ESCENE_NODE_TYPE type, ISceneNode* start=0) _IRR_OVERRIDE_; + + //! returns scene nodes by type. + virtual void getSceneNodesFromType(ESCENE_NODE_TYPE type, core::array& outNodes, ISceneNode* start=0) _IRR_OVERRIDE_; + + //! Posts an input event to the environment. Usually you do not have to + //! use this method, it is used by the internal engine. + virtual bool postEventFromUser(const SEvent& event) _IRR_OVERRIDE_; + + //! Clears the whole scene. All scene nodes are removed. + virtual void clear() _IRR_OVERRIDE_; + + //! Removes all children of this scene node + virtual void removeAll() _IRR_OVERRIDE_; + + //! Returns interface to the parameters set in this scene. + virtual io::IAttributes* getParameters() _IRR_OVERRIDE_; + + //! Returns current render pass. + virtual E_SCENE_NODE_RENDER_PASS getSceneNodeRenderPass() const _IRR_OVERRIDE_; + + //! Creates a new scene manager. + virtual ISceneManager* createNewSceneManager(bool cloneContent) _IRR_OVERRIDE_; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_SCENE_MANAGER; } + + //! Returns the default scene node factory which can create all built in scene nodes + virtual ISceneNodeFactory* getDefaultSceneNodeFactory() _IRR_OVERRIDE_; + + //! Adds a scene node factory to the scene manager. + /** Use this to extend the scene manager with new scene node types which it should be + able to create automatically, for example when loading data from xml files. */ + virtual void registerSceneNodeFactory(ISceneNodeFactory* factoryToAdd) _IRR_OVERRIDE_; + + //! Returns amount of registered scene node factories. + virtual u32 getRegisteredSceneNodeFactoryCount() const _IRR_OVERRIDE_; + + //! Returns a scene node factory by index + virtual ISceneNodeFactory* getSceneNodeFactory(u32 index) _IRR_OVERRIDE_; + + //! Returns a typename from a scene node type or null if not found + virtual const c8* getSceneNodeTypeName(ESCENE_NODE_TYPE type) _IRR_OVERRIDE_; + + //! Returns a typename from a scene node animator type or null if not found + virtual const c8* getAnimatorTypeName(ESCENE_NODE_ANIMATOR_TYPE type) _IRR_OVERRIDE_; + + //! Adds a scene node to the scene by name + virtual ISceneNode* addSceneNode(const char* sceneNodeTypeName, ISceneNode* parent=0) _IRR_OVERRIDE_; + + //! creates a scene node animator based on its type name + virtual ISceneNodeAnimator* createSceneNodeAnimator(const char* typeName, ISceneNode* target=0) _IRR_OVERRIDE_; + + //! Returns the default scene node animator factory which can create all built-in scene node animators + virtual ISceneNodeAnimatorFactory* getDefaultSceneNodeAnimatorFactory() _IRR_OVERRIDE_; + + //! Adds a scene node animator factory to the scene manager. + virtual void registerSceneNodeAnimatorFactory(ISceneNodeAnimatorFactory* factoryToAdd) _IRR_OVERRIDE_; + + //! Returns amount of registered scene node animator factories. + virtual u32 getRegisteredSceneNodeAnimatorFactoryCount() const _IRR_OVERRIDE_; + + //! Returns a scene node animator factory by index + virtual ISceneNodeAnimatorFactory* getSceneNodeAnimatorFactory(u32 index) _IRR_OVERRIDE_; + + //! Saves the current scene into a file. + virtual bool saveScene(const io::path& filename, ISceneUserDataSerializer* userDataSerializer=0, ISceneNode* node=0) _IRR_OVERRIDE_; + + //! Saves the current scene into a file. + virtual bool saveScene(io::IWriteFile* file, ISceneUserDataSerializer* userDataSerializer=0, ISceneNode* node=0) _IRR_OVERRIDE_; + + //! Saves the current scene into a file. + virtual bool saveScene(io::IXMLWriter* writer, const io::path& currentPath, ISceneUserDataSerializer* userDataSerializer=0, ISceneNode* node=0) _IRR_OVERRIDE_; + + //! Loads a scene. Note that the current scene is not cleared before. + virtual bool loadScene(const io::path& filename, ISceneUserDataSerializer* userDataSerializer=0, ISceneNode* rootNode=0) _IRR_OVERRIDE_; + + //! Loads a scene. Note that the current scene is not cleared before. + virtual bool loadScene(io::IReadFile* file, ISceneUserDataSerializer* userDataSerializer=0, ISceneNode* rootNode=0) _IRR_OVERRIDE_; + + //! Writes attributes of the scene node. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! Returns a mesh writer implementation if available + virtual IMeshWriter* createMeshWriter(EMESH_WRITER_TYPE type) _IRR_OVERRIDE_; + + //! Get a skinned mesh, which is not available as header-only code + virtual ISkinnedMesh* createSkinnedMesh() _IRR_OVERRIDE_; + + //! Sets ambient color of the scene + virtual void setAmbientLight(const video::SColorf &ambientColor) _IRR_OVERRIDE_; + + //! Returns ambient color of the scene + virtual const video::SColorf& getAmbientLight() const _IRR_OVERRIDE_; + + //! Register a custom callbacks manager which gets callbacks during scene rendering. + virtual void setLightManager(ILightManager* lightManager) _IRR_OVERRIDE_; + + //! Get current render time. + virtual E_SCENE_NODE_RENDER_PASS getCurrentRenderPass() const _IRR_OVERRIDE_ { return CurrentRenderPass; } + + //! Set current render time. + virtual void setCurrentRenderPass(E_SCENE_NODE_RENDER_PASS nextPass) _IRR_OVERRIDE_ { CurrentRenderPass = nextPass; } + + //! Get an instance of a geometry creator. + virtual const IGeometryCreator* getGeometryCreator(void) const _IRR_OVERRIDE_ { return GeometryCreator; } + + //! returns if node is culled + virtual bool isCulled(const ISceneNode* node) const _IRR_OVERRIDE_; + + private: + + // load and create a mesh which we know already isn't in the cache and put it in there + IAnimatedMesh* getUncachedMesh(io::IReadFile* file, const io::path& filename, const io::path& cachename); + + //! clears the deletion list + void clearDeletionList(); + + //! writes a scene node + void writeSceneNode(io::IXMLWriter* writer, ISceneNode* node, ISceneUserDataSerializer* userDataSerializer, const fschar_t* currentPath=0, bool init=false); + + struct DefaultNodeEntry + { + DefaultNodeEntry(ISceneNode* n) : + Node(n), TextureValue(0) + { + if (n->getMaterialCount()) + TextureValue = (n->getMaterial(0).getTexture(0)); + } + + bool operator < (const DefaultNodeEntry& other) const + { + return (TextureValue < other.TextureValue); + } + + ISceneNode* Node; + private: + void* TextureValue; + }; + + //! sort on distance (center) to camera + struct TransparentNodeEntry + { + TransparentNodeEntry(ISceneNode* n, const core::vector3df& camera) + : Node(n) + { + Distance = Node->getAbsoluteTransformation().getTranslation().getDistanceFromSQ(camera); + } + + bool operator < (const TransparentNodeEntry& other) const + { + return Distance > other.Distance; + } + + ISceneNode* Node; + private: + f64 Distance; + }; + + //! sort on distance (sphere) to camera + struct DistanceNodeEntry + { + DistanceNodeEntry(ISceneNode* n, const core::vector3df& cameraPos) + : Node(n) + { + setNodeAndDistanceFromPosition(n, cameraPos); + } + + bool operator < (const DistanceNodeEntry& other) const + { + 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; + }; + + //! video driver + video::IVideoDriver* Driver; + + //! file system + io::IFileSystem* FileSystem; + + //! GUI Enviroment ( Debug Purpose ) + gui::IGUIEnvironment* GUIEnvironment; + + //! cursor control + gui::ICursorControl* CursorControl; + + //! collision manager + ISceneCollisionManager* CollisionManager; + + //! render pass lists + core::array CameraList; + core::array LightList; + core::array ShadowNodeList; + core::array SkyBoxList; + core::array SolidNodeList; + core::array TransparentNodeList; + core::array TransparentEffectNodeList; + + core::array MeshLoaderList; + core::array SceneLoaderList; + core::array DeletionList; + core::array SceneNodeFactoryList; + core::array SceneNodeAnimatorFactoryList; + + //! current active camera + ICameraSceneNode* ActiveCamera; + core::vector3df camWorldPos; // Position of camera for transparent nodes. + + video::SColor ShadowColor; + video::SColorf AmbientLight; + + //! String parameters + // NOTE: Attributes are slow and should only be used for debug-info and not in release + io::CAttributes* Parameters; + + //! Mesh cache + IMeshCache* MeshCache; + + E_SCENE_NODE_RENDER_PASS CurrentRenderPass; + + //! 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; + const core::stringw IRR_XML_FORMAT_NODE; + const core::stringw IRR_XML_FORMAT_NODE_ATTR_TYPE; + + IGeometryCreator* GeometryCreator; + }; + +} // end namespace video +} // end namespace scene + +#endif + diff --git a/source/Irrlicht/CSceneNodeAnimatorCameraFPS.cpp b/source/Irrlicht/CSceneNodeAnimatorCameraFPS.cpp new file mode 100644 index 00000000..89d377ab --- /dev/null +++ b/source/Irrlicht/CSceneNodeAnimatorCameraFPS.cpp @@ -0,0 +1,420 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CSceneNodeAnimatorCameraFPS.h" +#include "IVideoDriver.h" +#include "ISceneManager.h" +#include "Keycodes.h" +#include "ICursorControl.h" +#include "ICameraSceneNode.h" +#include "ISceneNodeAnimatorCollisionResponse.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CSceneNodeAnimatorCameraFPS::CSceneNodeAnimatorCameraFPS(gui::ICursorControl* cursorControl, + f32 rotateSpeed, f32 moveSpeed, f32 jumpSpeed, + SKeyMap* keyMapArray, u32 keyMapSize, bool noVerticalMovement, bool invertY, float rotateSpeedKeyboard) +: CursorControl(cursorControl), MaxVerticalAngle(88.0f), NoVerticalMovement(noVerticalMovement), + MoveSpeed(moveSpeed), RotateSpeedKeyboard(rotateSpeedKeyboard), RotateSpeed(rotateSpeed), + JumpSpeed(jumpSpeed), + MouseYDirection(invertY ? -1.0f : 1.0f), + LastAnimationTime(0), firstUpdate(true), firstInput(true) +{ + #ifdef _DEBUG + setDebugName("CCameraSceneNodeAnimatorFPS"); + #endif + + if (CursorControl) + CursorControl->grab(); + + allKeysUp(); + + // create key map + if (!keyMapArray || !keyMapSize) + { + // create default key map + KeyMap.push_back(SKeyMap(EKA_MOVE_FORWARD, irr::KEY_UP)); + KeyMap.push_back(SKeyMap(EKA_MOVE_BACKWARD, irr::KEY_DOWN)); + KeyMap.push_back(SKeyMap(EKA_STRAFE_LEFT, irr::KEY_LEFT)); + KeyMap.push_back(SKeyMap(EKA_STRAFE_RIGHT, irr::KEY_RIGHT)); + KeyMap.push_back(SKeyMap(EKA_JUMP_UP, irr::KEY_KEY_J)); + } + else + { + // create custom key map + setKeyMap(keyMapArray, keyMapSize); + } +} + + +//! destructor +CSceneNodeAnimatorCameraFPS::~CSceneNodeAnimatorCameraFPS() +{ + if (CursorControl) + CursorControl->drop(); +} + + +//! It is possible to send mouse and key events to the camera. Most cameras +//! may ignore this input, but camera scene nodes which are created for +//! example with scene::ISceneManager::addMayaCameraSceneNode or +//! scene::ISceneManager::addFPSCameraSceneNode, may want to get this input +//! for changing their position, look at target or whatever. +bool CSceneNodeAnimatorCameraFPS::OnEvent(const SEvent& evt) +{ + switch(evt.EventType) + { + case EET_KEY_INPUT_EVENT: + for (u32 i=0; isetPosition(0.5f, 0.5f); + CenterCursor = CursorControl->getRelativePosition(false); + CursorPos = CenterCursor; + } + break; + + default: + break; + } + + return false; +} + + +void CSceneNodeAnimatorCameraFPS::animateNode(ISceneNode* node, u32 timeMs) +{ + if (!node || node->getType() != ESNT_CAMERA) + return; + + timeMs = os::Timer::getRealTime(); // User input is always in real-time + + ICameraSceneNode* camera = static_cast(node); + + if (firstUpdate) + { + camera->updateAbsolutePosition(); + if (CursorControl ) + { + CursorControl->setPosition(0.5f, 0.5f); + CursorPos = CenterCursor = CursorControl->getRelativePosition(false); + } + + LastAnimationTime = timeMs; + + firstUpdate = false; + } + + // If the camera isn't the active camera, and receiving input, then don't process it. + if(!camera->isInputReceiverEnabled()) + { + firstInput = true; + return; + } + + if ( firstInput ) + { + allKeysUp(); + firstInput = false; + } + + scene::ISceneManager * smgr = camera->getSceneManager(); + if(smgr && smgr->getActiveCamera() != camera) + return; + + if ( CursorControl ) + CursorPos = CursorControl->getRelativePosition(); + + // get time + f32 timeDiff = (f32) ( timeMs - LastAnimationTime ); + LastAnimationTime = timeMs; + + // Update rotation + core::vector3df target = (camera->getTarget() - camera->getAbsolutePosition()); + core::vector3df relativeRotation = target.getHorizontalAngle(); + + if (CursorControl) + { + bool reset = false; + + if (CursorPos != CenterCursor) + { + relativeRotation.Y -= (CenterCursor.X - CursorPos.X) * RotateSpeed; + relativeRotation.X -= (CenterCursor.Y - CursorPos.Y) * RotateSpeed * MouseYDirection; + + reset = true; + } + + if ( !reset ) + { + // TODO: not sure if this case is still needed. Might be it was only something + // that was necessary when someone tried to use mouse-events in the past. + // But not too expensive, test on all platforms before removing. + + // Special case, mouse is whipped outside of window before it can update. + video::IVideoDriver* driver = smgr->getVideoDriver(); + core::vector2d mousepos(u32(CursorPos.X), u32(CursorPos.Y)); + core::rect screenRect(0, 0, driver->getScreenSize().Width, driver->getScreenSize().Height); + + // Only if we are moving outside quickly. + reset = !screenRect.isPointInside(mousepos); + } + + if(reset) + { + CursorControl->setPosition(0.5f, 0.5f); + CenterCursor = CursorControl->getRelativePosition(false); // often no longer 0.5 due to int/float conversions + CursorPos = CenterCursor; + } + } + + // keyboard rotation + if (CursorKeys[EKA_ROTATE_LEFT]) + relativeRotation.Y -= timeDiff * RotateSpeedKeyboard; + + if (CursorKeys[EKA_ROTATE_RIGHT]) + relativeRotation.Y += timeDiff * RotateSpeedKeyboard; + + // X < MaxVerticalAngle or X > 360-MaxVerticalAngle + + if (relativeRotation.X > MaxVerticalAngle*2 && + relativeRotation.X < 360.0f-MaxVerticalAngle) + { + relativeRotation.X = 360.0f-MaxVerticalAngle; + } + else + if (relativeRotation.X > MaxVerticalAngle && + relativeRotation.X < 360.0f-MaxVerticalAngle) + { + relativeRotation.X = MaxVerticalAngle; + } + + // set target + core::vector3df pos = camera->getPosition(); + target.set(0,0, core::max_(1.f, pos.getLength())); // better float precision than (0,0,1) in target-pos calculation in camera + core::vector3df movedir(target); + + core::matrix4 mat; + mat.setRotationDegrees(core::vector3df(relativeRotation.X, relativeRotation.Y, 0)); + mat.transformVect(target); + + if (NoVerticalMovement) + { + mat.setRotationDegrees(core::vector3df(0, relativeRotation.Y, 0)); + mat.transformVect(movedir); + } + else + { + movedir = target; + } + + movedir.normalize(); + + if (CursorKeys[EKA_MOVE_FORWARD]) + pos += movedir * timeDiff * MoveSpeed; + + if (CursorKeys[EKA_MOVE_BACKWARD]) + pos -= movedir * timeDiff * MoveSpeed; + + // strafing + + core::vector3df strafevect(target); + strafevect = strafevect.crossProduct(camera->getUpVector()); + + if (NoVerticalMovement) + strafevect.Y = 0.0f; + + strafevect.normalize(); + + if (CursorKeys[EKA_STRAFE_LEFT]) + pos += strafevect * timeDiff * MoveSpeed; + + if (CursorKeys[EKA_STRAFE_RIGHT]) + pos -= strafevect * timeDiff * MoveSpeed; + + // For jumping, we find the collision response animator attached to our camera + // and if it's not falling, we tell it to jump. + if (CursorKeys[EKA_JUMP_UP]) + { + const ISceneNodeAnimatorList& animators = camera->getAnimators(); + ISceneNodeAnimatorList::ConstIterator it = animators.begin(); + while(it != animators.end()) + { + if(ESNAT_COLLISION_RESPONSE == (*it)->getType()) + { + ISceneNodeAnimatorCollisionResponse * collisionResponse = + static_cast(*it); + + if(!collisionResponse->isFalling()) + collisionResponse->jump(JumpSpeed); + } + + it++; + } + } + + // write translation + camera->setPosition(pos); + + // write right target + target += pos; + camera->setTarget(target); +} + +void CSceneNodeAnimatorCameraFPS::allKeysUp() +{ + for (u32 i=0; i& keymap) +{ + KeyMap=keymap; +} + +const core::array& CSceneNodeAnimatorCameraFPS::getKeyMap() const +{ + return KeyMap; +} + + +//! Sets whether vertical movement should be allowed. +void CSceneNodeAnimatorCameraFPS::setVerticalMovement(bool allow) +{ + NoVerticalMovement = !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 = + new CSceneNodeAnimatorCameraFPS(CursorControl, RotateSpeed, MoveSpeed, JumpSpeed, + 0, 0, NoVerticalMovement); + newAnimator->cloneMembers(this); + newAnimator->setKeyMap(KeyMap); + return newAnimator; +} + +void CSceneNodeAnimatorCameraFPS::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + ISceneNodeAnimator::serializeAttributes(out, options); + + out->addFloat("MaxVerticalAngle", MaxVerticalAngle); + out->addBool("NoVerticalMovement", NoVerticalMovement); + out->addFloat("MoveSpeed", MoveSpeed); + out->addFloat("RotateSpeedKeyboard", RotateSpeedKeyboard); + out->addFloat("RotateSpeed", RotateSpeed); + out->addFloat("JumpSpeed", JumpSpeed); + out->addFloat("MouseYDirection", MouseYDirection); + + out->addInt("KeyMapSize", (s32)KeyMap.size()); + for ( u32 i=0; i < KeyMap.size(); ++i ) + { + core::stringc name("Action"); + name += core::stringc(i); + out->addInt(name.c_str(), (int)KeyMap[i].Action); + name = core::stringc("KeyCode") + core::stringc(i); + out->addInt(name.c_str(), (int)KeyMap[i].KeyCode); + } +} + +void CSceneNodeAnimatorCameraFPS::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + ISceneNodeAnimator::deserializeAttributes(in, options); + + MaxVerticalAngle = in->getAttributeAsFloat("MaxVerticalAngle", MaxVerticalAngle); + NoVerticalMovement = in->getAttributeAsBool("NoVerticalMovement", NoVerticalMovement); + MoveSpeed = in->getAttributeAsFloat("MoveSpeed", MoveSpeed); + RotateSpeedKeyboard = in->getAttributeAsFloat("RotateSpeedKeyboard", RotateSpeedKeyboard); + RotateSpeed = in->getAttributeAsFloat("RotateSpeed", RotateSpeed); + JumpSpeed = in->getAttributeAsFloat("JumpSpeed", JumpSpeed); + MouseYDirection = in->getAttributeAsFloat("MouseYDirection", MouseYDirection); + + if ( in->findAttribute("KeyMapSize") ) + { + KeyMap.clear(); + s32 keyMapSize = in->getAttributeAsInt("KeyMapSize"); + for ( u32 i=0; i < (u32)keyMapSize; ++i ) + { + SKeyMap keyMapEntry; + core::stringc name("Action"); + name += core::stringc(i); + keyMapEntry.Action = static_cast(in->getAttributeAsInt(name.c_str())); + name = core::stringc("KeyCode") + core::stringc(i); + keyMapEntry.KeyCode = static_cast(in->getAttributeAsInt(name.c_str())); + KeyMap.push_back(keyMapEntry); + } + } +} + + +} // namespace scene +} // namespace irr + diff --git a/source/Irrlicht/CSceneNodeAnimatorCameraFPS.h b/source/Irrlicht/CSceneNodeAnimatorCameraFPS.h new file mode 100644 index 00000000..b79dad68 --- /dev/null +++ b/source/Irrlicht/CSceneNodeAnimatorCameraFPS.h @@ -0,0 +1,143 @@ +// Copyright (C) 2002-2012 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_CAMERA_FPS_H_INCLUDED__ +#define __C_SCENE_NODE_ANIMATOR_CAMERA_FPS_H_INCLUDED__ + +#include "ISceneNodeAnimatorCameraFPS.h" +#include "vector2d.h" +#include "position2d.h" +#include "SKeyMap.h" +#include "irrArray.h" + +namespace irr +{ +namespace gui +{ + class ICursorControl; +} + +namespace scene +{ + + //! Special scene node animator for FPS cameras + class CSceneNodeAnimatorCameraFPS : public ISceneNodeAnimatorCameraFPS + { + public: + + //! 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, + bool invertY=false, float rotateSpeedKeyboard = 0.3f); + + //! Destructor + virtual ~CSceneNodeAnimatorCameraFPS(); + + //! Animates the scene node, currently only works on cameras + virtual void animateNode(ISceneNode* node, u32 timeMs) _IRR_OVERRIDE_; + + //! Event receiver + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! Returns the speed of movement in units per second + virtual f32 getMoveSpeed() const _IRR_OVERRIDE_; + + //! Sets the speed of movement in units per second + virtual void setMoveSpeed(f32 moveSpeed) _IRR_OVERRIDE_; + + //! Returns the rotation speed when moving mouse + virtual f32 getRotateSpeed() const _IRR_OVERRIDE_; + + //! Set the rotation speed when moving mouse + virtual void setRotateSpeed(f32 rotateSpeed) _IRR_OVERRIDE_; + + //! Returns the rotation speed when using keyboard + virtual f32 getRotateSpeedKeyboard() const _IRR_OVERRIDE_ + { + return RotateSpeedKeyboard; + } + + //! Set the rotation speed when using keyboard + virtual void setRotateSpeedKeyboard(f32 rotateSpeed) _IRR_OVERRIDE_ + { + RotateSpeedKeyboard = rotateSpeed; + } + + //! Sets the keyboard mapping for this animator (old style) + //! \param keymap: an array of keyboard mappings, see SKeyMap + //! \param count: the size of the keyboard map array + virtual void setKeyMap(SKeyMap *map, u32 count) _IRR_OVERRIDE_; + + //! Sets the keyboard mapping for this animator + //! \param keymap The new keymap array + virtual void setKeyMap(const core::array& keymap) _IRR_OVERRIDE_; + + //! Gets the keyboard mapping for this animator + virtual const core::array& getKeyMap() const _IRR_OVERRIDE_; + + //! Sets whether vertical movement should be allowed. + virtual void setVerticalMovement(bool allow) _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! This animator will receive events when attached to the active camera + virtual bool isEventReceiverEnabled() const _IRR_OVERRIDE_ + { + return true; + } + + //! Returns the type of this animator + virtual ESCENE_NODE_ANIMATOR_TYPE getType() const _IRR_OVERRIDE_ + { + return ESNAT_CAMERA_FPS; + } + + //! Creates a clone of this animator. + /** Please note that you will have to drop + (IReferenceCounted::drop()) the returned pointer once you're + done with it. */ + virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + //! Writes attributes of the scene node animator. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node animator. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + private: + + void allKeysUp(); + + gui::ICursorControl *CursorControl; + + f32 MaxVerticalAngle; + bool NoVerticalMovement; + + f32 MoveSpeed; + f32 RotateSpeedKeyboard; + f32 RotateSpeed; + f32 JumpSpeed; + // -1.0f for inverted mouse, defaults to 1.0f + f32 MouseYDirection; + + s32 LastAnimationTime; + + core::array KeyMap; + core::position2d CenterCursor, CursorPos; + + bool CursorKeys[EKA_COUNT]; + + bool firstUpdate; + bool firstInput; + }; + +} // end namespace scene +} // end namespace irr + +#endif // __C_SCENE_NODE_ANIMATOR_CAMERA_FPS_H_INCLUDED__ + diff --git a/source/Irrlicht/CSceneNodeAnimatorCameraMaya.cpp b/source/Irrlicht/CSceneNodeAnimatorCameraMaya.cpp new file mode 100644 index 00000000..69fee69f --- /dev/null +++ b/source/Irrlicht/CSceneNodeAnimatorCameraMaya.cpp @@ -0,0 +1,362 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CSceneNodeAnimatorCameraMaya.h" +#include "ICursorControl.h" +#include "ICameraSceneNode.h" +#include "SViewFrustum.h" +#include "ISceneManager.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CSceneNodeAnimatorCameraMaya::CSceneNodeAnimatorCameraMaya(gui::ICursorControl* cursor, + f32 rotateSpeed, f32 zoomSpeed, f32 translateSpeed, f32 distance) + : CursorControl(cursor), OldCamera(0), MousePos(0.5f, 0.5f), + TargetMinDistance(0.f), + ZoomSpeed(zoomSpeed), RotateSpeed(rotateSpeed), TranslateSpeed(translateSpeed), + CurrentZoom(distance), RotX(0.0f), RotY(0.0f), + Zooming(false), Rotating(false), Moving(false), Translating(false) +{ + #ifdef _DEBUG + setDebugName("CSceneNodeAnimatorCameraMaya"); + #endif + + if (CursorControl) + { + CursorControl->grab(); + MousePos = CursorControl->getRelativePosition(); + } + + allKeysUp(); +} + + +//! destructor +CSceneNodeAnimatorCameraMaya::~CSceneNodeAnimatorCameraMaya() +{ + if (CursorControl) + CursorControl->drop(); +} + + +//! It is possible to send mouse and key events to the camera. Most cameras +//! may ignore this input, but camera scene nodes which are created for +//! example with scene::ISceneManager::addMayaCameraSceneNode or +//! scene::ISceneManager::addMeshViewerCameraSceneNode, may want to get this input +//! for changing their position, look at target or whatever. +bool CSceneNodeAnimatorCameraMaya::OnEvent(const SEvent& event) +{ + if (event.EventType != EET_MOUSE_INPUT_EVENT) + return false; + + switch(event.MouseInput.Event) + { + case EMIE_LMOUSE_PRESSED_DOWN: + MouseKeys[0] = true; + updateMousePos(); + break; + case EMIE_RMOUSE_PRESSED_DOWN: + MouseKeys[2] = true; + updateMousePos(); + break; + case EMIE_MMOUSE_PRESSED_DOWN: + MouseKeys[1] = true; + updateMousePos(); + break; + case EMIE_LMOUSE_LEFT_UP: + MouseKeys[0] = false; + updateMousePos(); + break; + case EMIE_RMOUSE_LEFT_UP: + MouseKeys[2] = false; + updateMousePos(); + break; + case EMIE_MMOUSE_LEFT_UP: + MouseKeys[1] = false; + updateMousePos(); + break; + case EMIE_MOUSE_MOVED: + // check states again because sometimes the gui has already caught events + MouseKeys[0] = event.MouseInput.isLeftPressed(); + MouseKeys[2] = event.MouseInput.isRightPressed(); + MouseKeys[1] = event.MouseInput.isMiddlePressed(); + updateMousePos(); + break; + default: + return false; + } + return true; +} + +void CSceneNodeAnimatorCameraMaya::updateMousePos() +{ + if ( CursorControl ) + { + MousePos = CursorControl->getRelativePosition(); + } +} + +//! OnAnimate() is called just before rendering the whole scene. +void CSceneNodeAnimatorCameraMaya::animateNode(ISceneNode *node, u32 timeMs) +{ + //Alt + LM = Rotate around camera pivot + //Alt + LM + MM = Dolly forth/back in view direction (speed % distance camera pivot - max distance to pivot) + //Alt + MM = Move on camera plane (Screen center is about the mouse pointer, depending on move speed) + + if (!node || node->getType() != ESNT_CAMERA) + return; + + ICameraSceneNode* camera = static_cast(node); + + // If the camera isn't the active camera, and receiving input, then don't process it. + if (!camera->isInputReceiverEnabled()) + return; + + scene::ISceneManager * smgr = camera->getSceneManager(); + if (smgr && smgr->getActiveCamera() != camera) + return; + + if (OldCamera != camera) + { + LastCameraTarget = OldTarget = camera->getTarget(); + OldCamera = camera; + } + else + { + OldTarget += camera->getTarget() - LastCameraTarget; + } + + f32 nRotX = RotX; + f32 nRotY = RotY; + f32 nZoom = CurrentZoom; + + if ( (isMouseKeyDown(0) && isMouseKeyDown(2)) || isMouseKeyDown(1) ) + { + if (!Zooming) + { + ZoomStart = MousePos; + Zooming = true; + } + else + { + nZoom += (ZoomStart.X - MousePos.X) * ZoomSpeed; + + if (nZoom < TargetMinDistance+0.1f) // jox: fixed bug: bounce back when zooming too close + nZoom = TargetMinDistance+0.1f; + } + } + else if (Zooming) + { + const f32 old = CurrentZoom; + CurrentZoom = CurrentZoom + (ZoomStart.X - MousePos.X ) * ZoomSpeed; + nZoom = CurrentZoom; + + if (nZoom < TargetMinDistance) + nZoom = CurrentZoom = old; + Zooming = false; + } + + // Translation --------------------------------- + + core::vector3df translate(OldTarget); + const core::vector3df upVector(camera->getUpVector()); + const core::vector3df target = camera->getTarget(); + + core::vector3df pos = camera->getPosition(); + core::vector3df tvectX = pos - target; + tvectX = tvectX.crossProduct(upVector); + tvectX.normalize(); + + const SViewFrustum* const va = camera->getViewFrustum(); + core::vector3df tvectY = (va->getFarLeftDown() - va->getFarRightDown()); + tvectY = tvectY.crossProduct(upVector.Y > 0 ? pos - target : target - pos); + tvectY.normalize(); + + if (isMouseKeyDown(2) && !Zooming) + { + if (!Translating) + { + TranslateStart = MousePos; + Translating = true; + } + else + { + translate += tvectX * (TranslateStart.X - MousePos.X)*TranslateSpeed + + tvectY * (TranslateStart.Y - MousePos.Y)*TranslateSpeed; + } + } + else if (Translating) + { + translate += tvectX * (TranslateStart.X - MousePos.X)*TranslateSpeed + + tvectY * (TranslateStart.Y - MousePos.Y)*TranslateSpeed; + OldTarget = translate; + Translating = false; + } + + // Rotation ------------------------------------ + + if (isMouseKeyDown(0) && !Zooming) + { + if (!Rotating) + { + RotateStart = MousePos; + Rotating = true; + nRotX = RotX; + nRotY = RotY; + } + else + { + nRotX += (RotateStart.X - MousePos.X) * RotateSpeed; + nRotY += (RotateStart.Y - MousePos.Y) * RotateSpeed; + } + } + else if (Rotating) + { + RotX += (RotateStart.X - MousePos.X) * RotateSpeed; + RotY += (RotateStart.Y - MousePos.Y) * RotateSpeed; + nRotX = RotX; + nRotY = RotY; + Rotating = false; + } + + // Set pos ------------------------------------ + + pos = translate; + pos.X += nZoom; + + pos.rotateXYBy(nRotY, translate); + pos.rotateXZBy(-nRotX, translate); + + camera->setPosition(pos); + camera->setTarget(translate); + + // Rotation Error ---------------------------- + + // jox: fixed bug: jitter when rotating to the top and bottom of y + pos.set(0,1,0); + pos.rotateXYBy(-nRotY); + pos.rotateXZBy(-nRotX+180.f); + camera->setUpVector(pos); + LastCameraTarget = camera->getTarget(); +} + + +bool CSceneNodeAnimatorCameraMaya::isMouseKeyDown(s32 key) const +{ + return MouseKeys[key]; +} + + +void CSceneNodeAnimatorCameraMaya::allKeysUp() +{ + for (s32 i=0; i<3; ++i) + MouseKeys[i] = false; +} + + +//! Sets the rotation speed +void CSceneNodeAnimatorCameraMaya::setRotateSpeed(f32 speed) +{ + RotateSpeed = speed; +} + + +//! Sets the movement speed +void CSceneNodeAnimatorCameraMaya::setMoveSpeed(f32 speed) +{ + TranslateSpeed = speed; +} + + +//! Sets the zoom speed +void CSceneNodeAnimatorCameraMaya::setZoomSpeed(f32 speed) +{ + ZoomSpeed = speed; +} + + +//! Set the distance +void CSceneNodeAnimatorCameraMaya::setDistance(f32 distance) +{ + CurrentZoom=distance; +} + + +//! Gets the rotation speed +f32 CSceneNodeAnimatorCameraMaya::getRotateSpeed() const +{ + return RotateSpeed; +} + + +// Gets the movement speed +f32 CSceneNodeAnimatorCameraMaya::getMoveSpeed() const +{ + return TranslateSpeed; +} + + +//! Gets the zoom speed +f32 CSceneNodeAnimatorCameraMaya::getZoomSpeed() const +{ + return ZoomSpeed; +} + + +//! Returns the current distance, i.e. orbit radius +f32 CSceneNodeAnimatorCameraMaya::getDistance() const +{ + return CurrentZoom; +} + +void CSceneNodeAnimatorCameraMaya::setTargetMinDistance(f32 minDistance) +{ + TargetMinDistance = minDistance; + if ( CurrentZoom < TargetMinDistance ) + CurrentZoom = TargetMinDistance; +} + +f32 CSceneNodeAnimatorCameraMaya::getTargetMinDistance() const +{ + return TargetMinDistance; +} + + +ISceneNodeAnimator* CSceneNodeAnimatorCameraMaya::createClone(ISceneNode* node, ISceneManager* newManager) +{ + CSceneNodeAnimatorCameraMaya * newAnimator = + new CSceneNodeAnimatorCameraMaya(CursorControl, RotateSpeed, ZoomSpeed, TranslateSpeed); + newAnimator->cloneMembers(this); + return newAnimator; +} + +void CSceneNodeAnimatorCameraMaya::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + ISceneNodeAnimator::serializeAttributes(out, options); + + out->addFloat("TargetMinDistance", TargetMinDistance); + out->addFloat("ZoomSpeed", ZoomSpeed); + out->addFloat("RotateSpeed", RotateSpeed); + out->addFloat("TranslateSpeed", TranslateSpeed); + out->addFloat("CurrentZoom", CurrentZoom); +} + +void CSceneNodeAnimatorCameraMaya::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + ISceneNodeAnimator::deserializeAttributes(in, options); + + TargetMinDistance = in->getAttributeAsFloat("TargetMinDistance", TargetMinDistance); + ZoomSpeed = in->getAttributeAsFloat("ZoomSpeed", ZoomSpeed); + RotateSpeed = in->getAttributeAsFloat("RotateSpeed", RotateSpeed); + TranslateSpeed = in->getAttributeAsFloat("TranslateSpeed", TranslateSpeed); + CurrentZoom = in->getAttributeAsFloat("CurrentZoom", CurrentZoom); +} + +} // end namespace +} // end namespace + diff --git a/source/Irrlicht/CSceneNodeAnimatorCameraMaya.h b/source/Irrlicht/CSceneNodeAnimatorCameraMaya.h new file mode 100644 index 00000000..de03358e --- /dev/null +++ b/source/Irrlicht/CSceneNodeAnimatorCameraMaya.h @@ -0,0 +1,130 @@ +// Copyright (C) 2002-2012 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_CAMERA_MAYA_H_INCLUDED__ +#define __C_SCENE_NODE_ANIMATOR_CAMERA_MAYA_H_INCLUDED__ + +#include "ISceneNodeAnimatorCameraMaya.h" +#include "ICameraSceneNode.h" +#include "vector2d.h" + +namespace irr +{ + +namespace gui +{ + class ICursorControl; +} + +namespace scene +{ + + //! Special scene node animator for FPS cameras + /** This scene node animator can be attached to a camera to make it act + like a 3d modeling tool camera + */ + class CSceneNodeAnimatorCameraMaya : public ISceneNodeAnimatorCameraMaya + { + public: + //! Constructor + CSceneNodeAnimatorCameraMaya(gui::ICursorControl* cursor, f32 rotateSpeed = -1500.f, + f32 zoomSpeed = 200.f, f32 translationSpeed = 1500.f, f32 distance=70.f); + + //! Destructor + virtual ~CSceneNodeAnimatorCameraMaya(); + + //! Animates the scene node, currently only works on cameras + virtual void animateNode(ISceneNode* node, u32 timeMs) _IRR_OVERRIDE_; + + //! Event receiver + virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_; + + //! Returns the speed of movement in units per millisecond + virtual f32 getMoveSpeed() const _IRR_OVERRIDE_; + + //! Sets the speed of movement in units per millisecond + virtual void setMoveSpeed(f32 moveSpeed) _IRR_OVERRIDE_; + + //! Returns the rotation speed + virtual f32 getRotateSpeed() const _IRR_OVERRIDE_; + + //! Set the rotation speed + virtual void setRotateSpeed(f32 rotateSpeed) _IRR_OVERRIDE_; + + //! Returns the zoom speed + virtual f32 getZoomSpeed() const _IRR_OVERRIDE_; + + //! Set the zoom speed + virtual void setZoomSpeed(f32 zoomSpeed) _IRR_OVERRIDE_; + + //! Returns the current distance, i.e. orbit radius + virtual f32 getDistance() const _IRR_OVERRIDE_; + + //! Set the distance + virtual void setDistance(f32 distance) _IRR_OVERRIDE_; + + //! Set the minimal distance to the camera target for zoom + virtual void setTargetMinDistance(f32 minDistance) _IRR_OVERRIDE_; + + //! Returns the minimal distance to the camera target for zoom + virtual f32 getTargetMinDistance() const _IRR_OVERRIDE_; + + //! This animator will receive events when attached to the active camera + virtual bool isEventReceiverEnabled() const _IRR_OVERRIDE_ + { + return true; + } + + //! Returns type of the scene node + virtual ESCENE_NODE_ANIMATOR_TYPE getType() const _IRR_OVERRIDE_ + { + return ESNAT_CAMERA_MAYA; + } + + //! Creates a clone of this animator. + /** Please note that you will have to drop + (IReferenceCounted::drop()) the returned pointer after calling + this. */ + virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + //! Writes attributes of the scene node animator. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node animator. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + private: + + void updateMousePos(); + void allKeysUp(); + void animate(); + bool isMouseKeyDown(s32 key) const; + + bool MouseKeys[3]; + + gui::ICursorControl *CursorControl; + scene::ICameraSceneNode* OldCamera; + core::vector3df OldTarget; + core::vector3df LastCameraTarget; // to find out if the camera target was moved outside this animator + core::position2df RotateStart; + core::position2df ZoomStart; + core::position2df TranslateStart; + core::position2df MousePos; + f32 TargetMinDistance; + f32 ZoomSpeed; + f32 RotateSpeed; + f32 TranslateSpeed; + f32 CurrentZoom; + f32 RotX, RotY; + bool Zooming; + bool Rotating; + bool Moving; + bool Translating; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.cpp b/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.cpp new file mode 100644 index 00000000..8d5b1701 --- /dev/null +++ b/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.cpp @@ -0,0 +1,310 @@ +// Copyright (C) 2002-2012 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), CollisionNode(0), CollisionCallback(0), + Falling(false), IsCamera(false), AnimateCameraTarget(true), CollisionOccurred(false), + FirstUpdate(true) +{ + #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 +{ + 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; + FirstUpdate = true; +} + + +//! Returns the radius of the ellipsoid with which 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; + FirstUpdate = true; +} + + +//! 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) +{ + if (newWorld) + newWorld->grab(); + + if (World) + World->drop(); + + World = newWorld; + + FirstUpdate = true; +} + + +//! 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; + + // trigger reset + if ( timeMs == 0 ) + { + FirstUpdate = true; + timeMs = LastTime; + } + + if ( FirstUpdate ) + { + LastPosition = Object->getPosition(); + Falling = false; + LastTime = timeMs; + FallingVelocity.set ( 0, 0, 0 ); + + FirstUpdate = false; + } + + const f32 diffSec = (f32)(timeMs - LastTime)*0.001f; + LastTime = timeMs; + + CollisionResultPosition = Object->getPosition(); + core::vector3df vel = CollisionResultPosition - LastPosition; + + FallingVelocity += Gravity * diffSec; + + CollisionTriangle = RefTriangle; + CollisionPoint = core::vector3df(); + CollisionResultPosition = core::vector3df(); + CollisionNode = 0; + + // core::vector3df force = vel + FallingVelocity; + + if ( AnimateCameraTarget ) + { + // TODO: divide SlidingSpeed by frame time + + bool f = false; + CollisionResultPosition + = SceneManager->getSceneCollisionManager()->getCollisionResultPosition( + World, LastPosition-Translation, + Radius, vel, CollisionTriangle, CollisionPoint, f, + CollisionNode, SlidingSpeed, FallingVelocity*diffSec); + + CollisionOccurred = (CollisionTriangle != RefTriangle); + + CollisionResultPosition += Translation; + + if ( diffSec > 0 ) // don't change the state when there was no time + { + if (f)//CollisionTriangle == RefTriangle) + { + Falling = true; + } + else + { + if ( CollisionOccurred ) // f can also happen to be false when FallingVelocity was already 0 (p.e. at top of a jump) + Falling = false; + FallingVelocity.set(0, 0, 0); + } + } + + 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 +{ + ISceneNodeAnimatorCollisionResponse::serializeAttributes(out, options); + + 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) +{ + ISceneNodeAnimatorCollisionResponse::deserializeAttributes(in, options); + + Radius = in->getAttributeAsVector3d("Radius", Radius); + Gravity = in->getAttributeAsVector3d("Gravity", Gravity); + Translation = in->getAttributeAsVector3d("Translation", Translation); + AnimateCameraTarget = in->getAttributeAsBool("AnimateCameraTarget", AnimateCameraTarget); +} + + +ISceneNodeAnimator* CSceneNodeAnimatorCollisionResponse::createClone(ISceneNode* node, ISceneManager* newManager) +{ + if (!newManager) newManager = SceneManager; + + CSceneNodeAnimatorCollisionResponse * newAnimator = + new CSceneNodeAnimatorCollisionResponse(newManager, World, Object, Radius, + Gravity, Translation, SlidingSpeed); + newAnimator->cloneMembers(this); + return newAnimator; +} + +void CSceneNodeAnimatorCollisionResponse::setCollisionCallback(ICollisionCallback* callback) +{ + if ( CollisionCallback == callback ) + return; + + if (CollisionCallback) + CollisionCallback->drop(); + + CollisionCallback = callback; + + if (CollisionCallback) + CollisionCallback->grab(); +} + +//! Should the Target react on collision ( default = true ) +void CSceneNodeAnimatorCollisionResponse::setAnimateTarget ( bool enable ) +{ + AnimateCameraTarget = enable; + FirstUpdate = true; +} + +//! Should the Target react on collision ( default = true ) +bool CSceneNodeAnimatorCollisionResponse::getAnimateTarget () const +{ + return AnimateCameraTarget; +} + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.h b/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.h new file mode 100644 index 00000000..1d490a9e --- /dev/null +++ b/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.h @@ -0,0 +1,157 @@ +// Copyright (C) 2002-2012 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_COLLISION_RESPONSE_H_INCLUDED__ +#define __C_SCENE_NODE_ANIMATOR_COLLISION_RESPONSE_H_INCLUDED__ + +#include "ISceneNodeAnimatorCollisionResponse.h" + +namespace irr +{ +namespace scene +{ + + //! Special scene node animator for doing automatic collision detection and response. + /** This scene node animator can be attached to any scene node modifying it in that + way, that it cannot move through walls of the world, is influenced by gravity and + acceleration. This animator is useful for example for first person shooter + games. Attach it for example to a first person shooter camera, and the camera will + behave as the player control in a first person shooter game: The camera stops and + slides at walls, walks up stairs, falls down if there is no floor under it, and so on. + */ + class CSceneNodeAnimatorCollisionResponse : public ISceneNodeAnimatorCollisionResponse + { + public: + + //! constructor + CSceneNodeAnimatorCollisionResponse(ISceneManager* scenemanager, + ITriangleSelector* world, ISceneNode* object, + const core::vector3df& ellipsoidRadius = core::vector3df(30,60,30), + const core::vector3df& gravityPerSecond = core::vector3df(0,-100.0f,0), + const core::vector3df& ellipsoidTranslation = core::vector3df(0,0,0), + f32 slidingSpeed = 0.0005f); + + //! destructor + virtual ~CSceneNodeAnimatorCollisionResponse(); + + //! 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. + virtual bool isFalling() const _IRR_OVERRIDE_; + + //! Sets the radius of the ellipsoid with which collision detection and + //! response is done. + virtual void setEllipsoidRadius(const core::vector3df& radius) _IRR_OVERRIDE_; + + //! Returns the radius of the ellipsoid with which the collision detection and + //! response is done. + virtual core::vector3df getEllipsoidRadius() const _IRR_OVERRIDE_; + + //! Sets the gravity of the environment. + virtual void setGravity(const core::vector3df& gravity) _IRR_OVERRIDE_; + + //! 'Jump' the animator, by adding a jump speed opposite to its gravity + virtual void jump(f32 jumpSpeed) _IRR_OVERRIDE_; + + //! Should the Target react on collision ( default = true ) + virtual void setAnimateTarget ( bool enable ) _IRR_OVERRIDE_; + virtual bool getAnimateTarget () const _IRR_OVERRIDE_; + + //! Returns current vector of gravity. + virtual core::vector3df getGravity() const _IRR_OVERRIDE_; + + //! Sets the translation of the ellipsoid for collision detection. + virtual void setEllipsoidTranslation(const core::vector3df &translation) _IRR_OVERRIDE_; + + //! Returns the translation of the ellipsoid for collision detection. + virtual core::vector3df getEllipsoidTranslation() const _IRR_OVERRIDE_; + + //! Sets a triangle selector holding all triangles of the world with which + //! the scene node may collide. + virtual void setWorld(ITriangleSelector* newWorld) _IRR_OVERRIDE_; + + //! Returns the current triangle selector containing all triangles for + //! collision detection. + virtual ITriangleSelector* getWorld() const _IRR_OVERRIDE_; + + //! animates a scene node + virtual void animateNode(ISceneNode* node, u32 timeMs) _IRR_OVERRIDE_; + + //! Writes attributes of the scene node animator. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node animator. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! Returns type of the scene node animator + virtual ESCENE_NODE_ANIMATOR_TYPE getType() const _IRR_OVERRIDE_ { return ESNAT_COLLISION_RESPONSE; } + + //! Creates a clone of this animator. + /** Please note that you will have to drop + (IReferenceCounted::drop()) the returned pointer after calling + this. */ + virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + //! Set the single node that this animator will act on. + virtual void setTargetNode(ISceneNode * node) _IRR_OVERRIDE_ { setNode(node); } + + //! Gets the single node that this animator is acting on. + virtual ISceneNode* getTargetNode(void) const _IRR_OVERRIDE_ { return Object; } + + //! Returns true if a collision occurred during the last animateNode() + virtual bool collisionOccurred() const _IRR_OVERRIDE_ { return CollisionOccurred; } + + //! Returns the last point of collision. + virtual const core::vector3df & getCollisionPoint() const _IRR_OVERRIDE_ { return CollisionPoint; } + + //! Returns the last triangle that caused a collision. + virtual const core::triangle3df & getCollisionTriangle() const _IRR_OVERRIDE_ { return CollisionTriangle; } + + virtual const core::vector3df & getCollisionResultPosition(void) const _IRR_OVERRIDE_ { return CollisionResultPosition; } + + virtual ISceneNode* getCollisionNode(void) const _IRR_OVERRIDE_ { 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) _IRR_OVERRIDE_; + + private: + + void setNode(ISceneNode* node); + + core::vector3df Radius; + core::vector3df Gravity; + core::vector3df Translation; + core::vector3df FallingVelocity; // In the direction of Gravity. + + core::vector3df LastPosition; + core::triangle3df RefTriangle; + + ITriangleSelector* World; + ISceneNode* Object; + ISceneManager* SceneManager; + u32 LastTime; + f32 SlidingSpeed; + + core::vector3df CollisionPoint; + core::triangle3df CollisionTriangle; + core::vector3df CollisionResultPosition; + ISceneNode * CollisionNode; + ICollisionCallback* CollisionCallback; + + bool Falling; + bool IsCamera; + bool AnimateCameraTarget; + bool CollisionOccurred; + bool FirstUpdate; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CSceneNodeAnimatorDelete.cpp b/source/Irrlicht/CSceneNodeAnimatorDelete.cpp new file mode 100644 index 00000000..d152e06c --- /dev/null +++ b/source/Irrlicht/CSceneNodeAnimatorDelete.cpp @@ -0,0 +1,55 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CSceneNodeAnimatorDelete.h" +#include "ISceneManager.h" + +namespace irr +{ +namespace scene +{ + + +//! constructor +CSceneNodeAnimatorDelete::CSceneNodeAnimatorDelete(ISceneManager* manager, u32 time) +: ISceneNodeAnimatorFinishing(time), SceneManager(manager) +{ + #ifdef _DEBUG + setDebugName("CSceneNodeAnimatorDelete"); + #endif +} + + +//! animates a scene node +void CSceneNodeAnimatorDelete::animateNode(ISceneNode* node, u32 timeMs) +{ + if (timeMs > FinishTime+PauseTimeSum) + { + 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) +{ + if (!newManager) + newManager = SceneManager; + + CSceneNodeAnimatorDelete* newAnimator = + new CSceneNodeAnimatorDelete(newManager, FinishTime); + newAnimator->cloneMembers(this); + + return newAnimator; +} + + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CSceneNodeAnimatorDelete.h b/source/Irrlicht/CSceneNodeAnimatorDelete.h new file mode 100644 index 00000000..2e78b416 --- /dev/null +++ b/source/Irrlicht/CSceneNodeAnimatorDelete.h @@ -0,0 +1,46 @@ +// Copyright (C) 2002-2012 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 "ISceneNodeAnimatorFinishing.h" + +namespace irr +{ +namespace scene +{ + class CSceneNodeAnimatorDelete : public ISceneNodeAnimatorFinishing + { + public: + + //! constructor + CSceneNodeAnimatorDelete(ISceneManager* manager, u32 when); + + //! animates a scene node + virtual void animateNode(ISceneNode* node, u32 timeMs) _IRR_OVERRIDE_; + + //! Returns type of the scene node animator + virtual ESCENE_NODE_ANIMATOR_TYPE getType() const _IRR_OVERRIDE_ + { + return ESNAT_DELETION; + } + + //! Creates a clone of this animator. + /** Please note that you will have to drop + (IReferenceCounted::drop()) the returned pointer after calling + this. */ + virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + private: + + ISceneManager* SceneManager; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CSceneNodeAnimatorFlyCircle.cpp b/source/Irrlicht/CSceneNodeAnimatorFlyCircle.cpp new file mode 100644 index 00000000..243ada68 --- /dev/null +++ b/source/Irrlicht/CSceneNodeAnimatorFlyCircle.cpp @@ -0,0 +1,107 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CSceneNodeAnimatorFlyCircle.h" + +namespace irr +{ +namespace scene +{ + + +//! constructor +CSceneNodeAnimatorFlyCircle::CSceneNodeAnimatorFlyCircle(u32 time, + const core::vector3df& center, f32 radius, f32 speed, + const core::vector3df& direction, f32 radiusEllipsoid) + : Center(center), Direction(direction), Radius(radius), + RadiusEllipsoid(radiusEllipsoid), Speed(speed) +{ + #ifdef _DEBUG + setDebugName("CSceneNodeAnimatorFlyCircle"); + #endif + + StartTime = time; + + init(); +} + + +void CSceneNodeAnimatorFlyCircle::init() +{ + Direction.normalize(); + + if (Direction.Y != 0) + VecV = core::vector3df(50,0,0).crossProduct(Direction).normalize(); + else + VecV = core::vector3df(0,50,0).crossProduct(Direction).normalize(); + VecU = VecV.crossProduct(Direction).normalize(); +} + + +//! animates a scene node +void CSceneNodeAnimatorFlyCircle::animateNode(ISceneNode* node, u32 timeMs) +{ + if ( 0 == node ) + return; + + f32 time; + + // Check for the condition where the StartTime is in the future. + if(StartTime+PauseTimeSum > timeMs) + time = ((s32)timeMs - (s32)(StartTime+PauseTimeSum)) * Speed; + else + time = (timeMs-(StartTime+PauseTimeSum)) * Speed; + +// node->setPosition(Center + Radius * ((VecU*cosf(time)) + (VecV*sinf(time)))); + f32 r2 = RadiusEllipsoid == 0.f ? Radius : RadiusEllipsoid; + node->setPosition(Center + (Radius*cosf(time)*VecU) + (r2*sinf(time)*VecV ) ); +} + + +//! Writes attributes of the scene node animator. +void CSceneNodeAnimatorFlyCircle::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + ISceneNodeAnimator::serializeAttributes(out, options); + + out->addVector3d("Center", Center); + out->addFloat("Radius", Radius); + out->addFloat("Speed", Speed); + out->addVector3d("Direction", Direction); + out->addFloat("RadiusEllipsoid", RadiusEllipsoid); +} + + +//! Reads attributes of the scene node animator. +void CSceneNodeAnimatorFlyCircle::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + ISceneNodeAnimator::deserializeAttributes(in, options); + + Center = in->getAttributeAsVector3d("Center"); + Radius = in->getAttributeAsFloat("Radius"); + Speed = in->getAttributeAsFloat("Speed"); + Direction = in->getAttributeAsVector3d("Direction"); + + if (Direction.equals(core::vector3df(0,0,0))) + Direction.set(0,1,0); // irrlicht 1.1 backwards compatibility + else + Direction.normalize(); + + RadiusEllipsoid = in->getAttributeAsFloat("RadiusEllipsoid"); + init(); +} + + +ISceneNodeAnimator* CSceneNodeAnimatorFlyCircle::createClone(ISceneNode* node, ISceneManager* newManager) +{ + CSceneNodeAnimatorFlyCircle * newAnimator = + new CSceneNodeAnimatorFlyCircle(StartTime, Center, Radius, Speed, Direction, RadiusEllipsoid); + newAnimator->cloneMembers(this); + + return newAnimator; +} + + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CSceneNodeAnimatorFlyCircle.h b/source/Irrlicht/CSceneNodeAnimatorFlyCircle.h new file mode 100644 index 00000000..ee838755 --- /dev/null +++ b/source/Irrlicht/CSceneNodeAnimatorFlyCircle.h @@ -0,0 +1,63 @@ +// Copyright (C) 2002-2012 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_CIRCLE_H_INCLUDED__ +#define __C_SCENE_NODE_ANIMATOR_FLY_CIRCLE_H_INCLUDED__ + +#include "ISceneNode.h" + +namespace irr +{ +namespace scene +{ + class CSceneNodeAnimatorFlyCircle : public ISceneNodeAnimator + { + public: + + //! constructor + CSceneNodeAnimatorFlyCircle(u32 time, + const core::vector3df& center, f32 radius, + f32 speed, const core::vector3df& direction, + f32 radiusEllipsoid); + + //! animates a scene node + virtual void animateNode(ISceneNode* node, u32 timeMs) _IRR_OVERRIDE_; + + //! Writes attributes of the scene node animator. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node animator. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! Returns type of the scene node animator + virtual ESCENE_NODE_ANIMATOR_TYPE getType() const _IRR_OVERRIDE_ { return ESNAT_FLY_CIRCLE; } + + //! Creates a clone of this animator. + /** Please note that you will have to drop + (IReferenceCounted::drop()) the returned pointer after calling + this. */ + virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + private: + // do some initial calculations + void init(); + + // circle center + core::vector3df Center; + // up-vector, normal to the circle's plane + core::vector3df Direction; + // Two helper vectors + core::vector3df VecU; + core::vector3df VecV; + f32 Radius; + f32 RadiusEllipsoid; + f32 Speed; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CSceneNodeAnimatorFlyStraight.cpp b/source/Irrlicht/CSceneNodeAnimatorFlyStraight.cpp new file mode 100644 index 00000000..1cc6af1b --- /dev/null +++ b/source/Irrlicht/CSceneNodeAnimatorFlyStraight.cpp @@ -0,0 +1,119 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CSceneNodeAnimatorFlyStraight.h" + +namespace irr +{ +namespace scene +{ + + +//! constructor +CSceneNodeAnimatorFlyStraight::CSceneNodeAnimatorFlyStraight(const core::vector3df& startPoint, + const core::vector3df& endPoint, u32 timeForWay, + bool loop, u32 now, bool pingpong) +: ISceneNodeAnimatorFinishing(now + timeForWay), + Start(startPoint), End(endPoint), TimeFactor(0.0f), + TimeForWay(timeForWay), Loop(loop), PingPong(pingpong) +{ + #ifdef _DEBUG + setDebugName("CSceneNodeAnimatorFlyStraight"); + #endif + + StartTime = now; + + recalculateIntermediateValues(); +} + + +void CSceneNodeAnimatorFlyStraight::recalculateIntermediateValues() +{ + Vector = End - Start; + TimeFactor = (f32)Vector.getLength() / TimeForWay; + Vector.normalize(); +} + + +//! animates a scene node +void CSceneNodeAnimatorFlyStraight::animateNode(ISceneNode* node, u32 timeMs) +{ + if (!node) + return; + + u32 t = (timeMs-(StartTime+PauseTimeSum)); + + core::vector3df pos; + + if (!Loop && !PingPong && t >= TimeForWay) + { + pos = End; + HasFinished = true; + } + else if (!Loop && PingPong && t >= TimeForWay * 2.f ) + { + pos = Start; + HasFinished = true; + } + else + { + f32 phase = fmodf( (f32) t, (f32) TimeForWay ); + core::vector3df rel = Vector * phase * TimeFactor; + const bool pong = PingPong && fmodf( (f32) t, (f32) TimeForWay*2.f ) >= TimeForWay; + + if ( !pong ) + { + pos += Start + rel; + } + else + { + pos = End - rel; + } + } + + node->setPosition(pos); +} + + +//! Writes attributes of the scene node animator. +void CSceneNodeAnimatorFlyStraight::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + ISceneNodeAnimatorFinishing::serializeAttributes(out, options); + + out->addVector3d("Start", Start); + out->addVector3d("End", End); + out->addInt("TimeForWay", TimeForWay); + out->addBool("Loop", Loop); + out->addBool("PingPong", PingPong); +} + + +//! Reads attributes of the scene node animator. +void CSceneNodeAnimatorFlyStraight::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + ISceneNodeAnimatorFinishing::deserializeAttributes(in, options); + + Start = in->getAttributeAsVector3d("Start"); + End = in->getAttributeAsVector3d("End"); + TimeForWay = in->getAttributeAsInt("TimeForWay"); + Loop = in->getAttributeAsBool("Loop"); + PingPong = in->getAttributeAsBool("PingPong"); + + recalculateIntermediateValues(); +} + + +ISceneNodeAnimator* CSceneNodeAnimatorFlyStraight::createClone(ISceneNode* node, ISceneManager* newManager) +{ + CSceneNodeAnimatorFlyStraight * newAnimator = + new CSceneNodeAnimatorFlyStraight(Start, End, TimeForWay, Loop, StartTime, PingPong); + newAnimator->cloneMembers(this); + + return newAnimator; +} + + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CSceneNodeAnimatorFlyStraight.h b/source/Irrlicht/CSceneNodeAnimatorFlyStraight.h new file mode 100644 index 00000000..c7040a00 --- /dev/null +++ b/source/Irrlicht/CSceneNodeAnimatorFlyStraight.h @@ -0,0 +1,58 @@ +// Copyright (C) 2002-2012 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 "ISceneNodeAnimatorFinishing.h" + +namespace irr +{ +namespace scene +{ + class CSceneNodeAnimatorFlyStraight : public ISceneNodeAnimatorFinishing + { + public: + + //! constructor + CSceneNodeAnimatorFlyStraight(const core::vector3df& startPoint, + const core::vector3df& endPoint, + u32 timeForWay, + bool loop, u32 now, bool pingpong); + + //! animates a scene node + virtual void animateNode(ISceneNode* node, u32 timeMs) _IRR_OVERRIDE_; + + //! Writes attributes of the scene node animator. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node animator. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! Returns type of the scene node animator + virtual ESCENE_NODE_ANIMATOR_TYPE getType() const _IRR_OVERRIDE_ { return ESNAT_FLY_STRAIGHT; } + + //! Creates a clone of this animator. + /** Please note that you will have to drop + (IReferenceCounted::drop()) the returned pointer after calling this. */ + virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + private: + + void recalculateIntermediateValues(); + + core::vector3df Start; + core::vector3df End; + core::vector3df Vector; + f32 TimeFactor; + u32 TimeForWay; + bool Loop; + bool PingPong; + }; + + +} // end namespace scene +} // end namespace irr + +#endif diff --git a/source/Irrlicht/CSceneNodeAnimatorFollowSpline.cpp b/source/Irrlicht/CSceneNodeAnimatorFollowSpline.cpp new file mode 100644 index 00000000..6bbf20c3 --- /dev/null +++ b/source/Irrlicht/CSceneNodeAnimatorFollowSpline.cpp @@ -0,0 +1,168 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CSceneNodeAnimatorFollowSpline.h" + +namespace irr +{ +namespace scene +{ + + +//! constructor +CSceneNodeAnimatorFollowSpline::CSceneNodeAnimatorFollowSpline(u32 time, + const core::array& points, f32 speed, + f32 tightness, bool loop, bool pingpong) +: ISceneNodeAnimatorFinishing(0), Points(points), Speed(speed), Tightness(tightness) +, Loop(loop), PingPong(pingpong) +{ + #ifdef _DEBUG + setDebugName("CSceneNodeAnimatorFollowSpline"); + #endif + + StartTime = time; +} + + +inline s32 CSceneNodeAnimatorFollowSpline::clamp(s32 idx, s32 size) +{ + return ( idx<0 ? size+idx : ( idx>=size ? idx-size : idx ) ); +} + + +//! animates a scene node +void CSceneNodeAnimatorFollowSpline::animateNode(ISceneNode* node, u32 timeMs) +{ + if(!node) + return; + + const u32 pSize = Points.size(); + if (pSize==0) + { + if ( !Loop ) + HasFinished = true; + return; + } + if (pSize==1) + { + if ( timeMs > (StartTime+PauseTimeSum) ) + { + node->setPosition(Points[0]); + if ( !Loop ) + HasFinished = true; + } + return; + } + + const f32 dt = ( (timeMs-(StartTime+PauseTimeSum)) * Speed * 0.001f ); + const s32 unwrappedIdx = core::floor32( dt ); + if ( !Loop && unwrappedIdx >= (s32)pSize-1 ) + { + node->setPosition(Points[pSize-1]); + HasFinished = true; + return; + } + const bool pong = PingPong && (unwrappedIdx/(pSize-1))%2; + const f32 u = pong ? 1.f-core::fract ( dt ) : core::fract ( dt ); + const s32 idx = pong ? (pSize-2) - (unwrappedIdx % (pSize-1)) + : (PingPong ? unwrappedIdx % (pSize-1) + : unwrappedIdx % pSize); + //const f32 u = 0.001f * fmodf( dt, 1000.0f ); + + const core::vector3df& p0 = Points[ clamp( idx - 1, pSize ) ]; + const core::vector3df& p1 = Points[ clamp( idx + 0, pSize ) ]; // starting point + const core::vector3df& p2 = Points[ clamp( idx + 1, pSize ) ]; // end point + const core::vector3df& p3 = Points[ clamp( idx + 2, pSize ) ]; + + // hermite polynomials + const f32 h1 = 2.0f * u * u * u - 3.0f * u * u + 1.0f; + const f32 h2 = -2.0f * u * u * u + 3.0f * u * u; + const f32 h3 = u * u * u - 2.0f * u * u + u; + const f32 h4 = u * u * u - u * u; + + // tangents + const core::vector3df t1 = ( p2 - p0 ) * Tightness; + const core::vector3df t2 = ( p3 - p1 ) * Tightness; + + // interpolated point + node->setPosition(p1 * h1 + p2 * h2 + t1 * h3 + t2 * h4); +} + + +//! Writes attributes of the scene node animator. +void CSceneNodeAnimatorFollowSpline::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + ISceneNodeAnimatorFinishing::serializeAttributes(out, options); + + out->addFloat("Speed", Speed); + out->addFloat("Tightness", Tightness); + out->addBool("Loop", Loop); + out->addBool("PingPong", PingPong); + + u32 count = Points.size(); + + if ( options && (options->Flags & io::EARWF_FOR_EDITOR)) + { + // add one point in addition when serializing for editors + // to make it easier to add points quickly + count += 1; + } + + for (u32 i=0; iaddVector3d(tname.c_str(), igetAttributeAsFloat("Speed"); + Tightness = in->getAttributeAsFloat("Tightness"); + Loop = in->getAttributeAsBool("Loop"); + PingPong = in->getAttributeAsBool("PingPong"); + Points.clear(); + + for(u32 i=1; true; ++i) + { + core::stringc pname = "Point"; + pname += i; + + if (in->existsAttribute(pname.c_str())) + Points.push_back(in->getAttributeAsVector3d(pname.c_str())); + else + break; + } + + // remove last point if double entry from editor + if ( options && (options->Flags & io::EARWF_FOR_EDITOR) && + Points.size() > 2 && Points.getLast() == core::vector3df(0,0,0)) + { + Points.erase(Points.size()-1); + + if (Points.size() > 2 && Points.getLast() == core::vector3df(0,0,0)) + Points.erase(Points.size()-1); + } +} + + +ISceneNodeAnimator* CSceneNodeAnimatorFollowSpline::createClone(ISceneNode* node, ISceneManager* newManager) +{ + CSceneNodeAnimatorFollowSpline * newAnimator = + new CSceneNodeAnimatorFollowSpline(StartTime, Points, Speed, Tightness); + newAnimator->cloneMembers(this); + + return newAnimator; +} + + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CSceneNodeAnimatorFollowSpline.h b/source/Irrlicht/CSceneNodeAnimatorFollowSpline.h new file mode 100644 index 00000000..b0eec698 --- /dev/null +++ b/source/Irrlicht/CSceneNodeAnimatorFollowSpline.h @@ -0,0 +1,62 @@ +// Copyright (C) 2002-2012 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_FOLLOW_SPLINE_H_INCLUDED__ +#define __C_SCENE_NODE_ANIMATOR_FOLLOW_SPLINE_H_INCLUDED__ + +#include "ISceneNode.h" +#include "irrArray.h" +#include "ISceneNodeAnimatorFinishing.h" + +namespace irr +{ +namespace scene +{ + //! Scene node animator based free code Matthias Gall wrote and sent in. (Most of + //! this code is written by him, I only modified bits.) + class CSceneNodeAnimatorFollowSpline : public ISceneNodeAnimatorFinishing + { + public: + + //! constructor + CSceneNodeAnimatorFollowSpline(u32 startTime, + const core::array< core::vector3df >& points, + f32 speed = 1.0f, f32 tightness = 0.5f, bool loop=true, bool pingpong=false); + + //! animates a scene node + virtual void animateNode(ISceneNode* node, u32 timeMs) _IRR_OVERRIDE_; + + //! Writes attributes of the scene node animator. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node animator. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! Returns type of the scene node animator + virtual ESCENE_NODE_ANIMATOR_TYPE getType() const _IRR_OVERRIDE_ { return ESNAT_FOLLOW_SPLINE; } + + //! Creates a clone of this animator. + /** Please note that you will have to drop + (IReferenceCounted::drop()) the returned pointer after calling + this. */ + virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + protected: + + //! clamps a the value idx to fit into range 0..size-1 + s32 clamp(s32 idx, s32 size); + + core::array< core::vector3df > Points; + f32 Speed; + f32 Tightness; + bool Loop; + bool PingPong; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CSceneNodeAnimatorRotation.cpp b/source/Irrlicht/CSceneNodeAnimatorRotation.cpp new file mode 100644 index 00000000..d9119f90 --- /dev/null +++ b/source/Irrlicht/CSceneNodeAnimatorRotation.cpp @@ -0,0 +1,80 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CSceneNodeAnimatorRotation.h" + +namespace irr +{ +namespace scene +{ + + +//! constructor +CSceneNodeAnimatorRotation::CSceneNodeAnimatorRotation(u32 time, const core::vector3df& rotation) +: Rotation(rotation) +{ + #ifdef _DEBUG + setDebugName("CSceneNodeAnimatorRotation"); + #endif + + StartTime = time; +} + + +//! animates a scene node +void CSceneNodeAnimatorRotation::animateNode(ISceneNode* node, u32 timeMs) +{ + if (node) // thanks to warui for this fix + { + const u32 diffTime = timeMs - StartTime; + + if (diffTime != 0) + { + // clip the rotation to small values, to avoid + // precision problems with huge floats. + core::vector3df rot = node->getRotation() + Rotation*(diffTime*0.1f); + if (rot.X>360.f) + rot.X=fmodf(rot.X, 360.f); + if (rot.Y>360.f) + rot.Y=fmodf(rot.Y, 360.f); + if (rot.Z>360.f) + rot.Z=fmodf(rot.Z, 360.f); + node->setRotation(rot); + StartTime=timeMs; + } + } +} + + +//! Writes attributes of the scene node animator. +void CSceneNodeAnimatorRotation::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + ISceneNodeAnimator::serializeAttributes(out, options); + + out->addVector3d("Rotation", Rotation); +} + + +//! Reads attributes of the scene node animator. +void CSceneNodeAnimatorRotation::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + ISceneNodeAnimator::deserializeAttributes(in, options); + + Rotation = in->getAttributeAsVector3d("Rotation"); +} + + +ISceneNodeAnimator* CSceneNodeAnimatorRotation::createClone(ISceneNode* node, ISceneManager* newManager) +{ + CSceneNodeAnimatorRotation * newAnimator = + new CSceneNodeAnimatorRotation(StartTime, Rotation); + newAnimator->cloneMembers(this); + + return newAnimator; +} + + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CSceneNodeAnimatorRotation.h b/source/Irrlicht/CSceneNodeAnimatorRotation.h new file mode 100644 index 00000000..a62a8ed4 --- /dev/null +++ b/source/Irrlicht/CSceneNodeAnimatorRotation.h @@ -0,0 +1,48 @@ +// Copyright (C) 2002-2012 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_ROTATION_H_INCLUDED__ +#define __C_SCENE_NODE_ANIMATOR_ROTATION_H_INCLUDED__ + +#include "ISceneNode.h" + +namespace irr +{ +namespace scene +{ + class CSceneNodeAnimatorRotation : public ISceneNodeAnimator + { + public: + + //! constructor + CSceneNodeAnimatorRotation(u32 time, const core::vector3df& rotation); + + //! animates a scene node + virtual void animateNode(ISceneNode* node, u32 timeMs) _IRR_OVERRIDE_; + + //! Writes attributes of the scene node animator. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node animator. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! Returns type of the scene node animator + virtual ESCENE_NODE_ANIMATOR_TYPE getType() const _IRR_OVERRIDE_ { return ESNAT_ROTATION; } + + //! Creates a clone of this animator. + /** Please note that you will have to drop + (IReferenceCounted::drop()) the returned pointer after calling this. */ + virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + private: + + core::vector3df Rotation; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CSceneNodeAnimatorTexture.cpp b/source/Irrlicht/CSceneNodeAnimatorTexture.cpp new file mode 100644 index 00000000..149639b4 --- /dev/null +++ b/source/Irrlicht/CSceneNodeAnimatorTexture.cpp @@ -0,0 +1,146 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CSceneNodeAnimatorTexture.h" +#include "ITexture.h" + +namespace irr +{ +namespace scene +{ + + +//! constructor +CSceneNodeAnimatorTexture::CSceneNodeAnimatorTexture(const core::array& textures, + s32 timePerFrame, bool loop, u32 now) +: ISceneNodeAnimatorFinishing(0), + TimePerFrame(timePerFrame), Loop(loop) +{ + #ifdef _DEBUG + setDebugName("CSceneNodeAnimatorTexture"); + #endif + + for (u32 i=0; igrab(); + + Textures.push_back(textures[i]); + } + + StartTime = now; + FinishTime = now + (timePerFrame * Textures.size()); +} + + +//! destructor +CSceneNodeAnimatorTexture::~CSceneNodeAnimatorTexture() +{ + clearTextures(); +} + + +void CSceneNodeAnimatorTexture::clearTextures() +{ + for (u32 i=0; idrop(); +} + + +//! animates a scene node +void CSceneNodeAnimatorTexture::animateNode(ISceneNode* node, u32 timeMs) +{ + if(!node) + return; + + if (Textures.size()) + { + const u32 t = (timeMs-(StartTime+PauseTimeSum)); + + u32 idx = 0; + if (!Loop && timeMs >= FinishTime+PauseTimeSum) + { + idx = Textures.size() - 1; + HasFinished = true; + } + else + { + idx = (t/TimePerFrame) % Textures.size(); + } + + if (idx < Textures.size()) + node->setMaterialTexture(0, Textures[idx]); + } +} + + +//! Writes attributes of the scene node animator. +void CSceneNodeAnimatorTexture::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + ISceneNodeAnimatorFinishing::serializeAttributes(out, options); + + out->addInt("TimePerFrame", TimePerFrame); + out->addBool("Loop", Loop); + + // add one texture in addition when serializing for editors + // to make it easier to add textures quickly + + u32 count = Textures.size(); + if ( options && (options->Flags & io::EARWF_FOR_EDITOR)) + count += 1; + + for (u32 i=0; iaddTexture(tname.c_str(), igetAttributeAsInt("TimePerFrame"); + Loop = in->getAttributeAsBool("Loop"); + + clearTextures(); + + for(u32 i=1; true; ++i) + { + core::stringc tname = "Texture"; + tname += (int)i; + + if (in->existsAttribute(tname.c_str())) + { + video::ITexture* tex = in->getAttributeAsTexture(tname.c_str()); + if (tex) + { + tex->grab(); + Textures.push_back(tex); + } + } + else + break; + } +} + + +ISceneNodeAnimator* CSceneNodeAnimatorTexture::createClone(ISceneNode* node, ISceneManager* newManager) +{ + CSceneNodeAnimatorTexture * newAnimator = + new CSceneNodeAnimatorTexture(Textures, TimePerFrame, Loop, StartTime); + newAnimator->cloneMembers(this); + + return newAnimator; +} + + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CSceneNodeAnimatorTexture.h b/source/Irrlicht/CSceneNodeAnimatorTexture.h new file mode 100644 index 00000000..08c1a727 --- /dev/null +++ b/source/Irrlicht/CSceneNodeAnimatorTexture.h @@ -0,0 +1,59 @@ +// Copyright (C) 2002-2012 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_TEXTURE_H_INCLUDED__ +#define __C_SCENE_NODE_ANIMATOR_TEXTURE_H_INCLUDED__ + +#include "irrArray.h" +#include "ISceneNodeAnimatorFinishing.h" + +namespace irr +{ +namespace scene +{ + class CSceneNodeAnimatorTexture : public ISceneNodeAnimatorFinishing + { + public: + + //! constructor + CSceneNodeAnimatorTexture(const core::array& textures, + s32 timePerFrame, bool loop, u32 now); + + //! destructor + virtual ~CSceneNodeAnimatorTexture(); + + //! animates a scene node + virtual void animateNode(ISceneNode* node, u32 timeMs) _IRR_OVERRIDE_; + + //! Writes attributes of the scene node animator. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node animator. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! Returns type of the scene node animator + virtual ESCENE_NODE_ANIMATOR_TYPE getType() const _IRR_OVERRIDE_ { return ESNAT_TEXTURE; } + + //! Creates a clone of this animator. + /** Please note that you will have to drop + (IReferenceCounted::drop()) the returned pointer after calling + this. */ + virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + + private: + + void clearTextures(); + + core::array Textures; + u32 TimePerFrame; + bool Loop; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CShadowVolumeSceneNode.cpp b/source/Irrlicht/CShadowVolumeSceneNode.cpp new file mode 100644 index 00000000..9c7b3ab1 --- /dev/null +++ b/source/Irrlicht/CShadowVolumeSceneNode.cpp @@ -0,0 +1,531 @@ +// Copyright (C) 2002-2012 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" + +#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ + +#include "CShadowVolumeSceneNode.h" +#include "ISceneManager.h" +#include "IMesh.h" +#include "IVideoDriver.h" +#include "ICameraSceneNode.h" +#include "SViewFrustum.h" +#include "SLight.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + + +//! constructor +CShadowVolumeSceneNode::CShadowVolumeSceneNode(const IMesh* shadowMesh, ISceneNode* parent, + ISceneManager* mgr, s32 id, bool zfailmethod, f32 infinity) +: IShadowVolumeSceneNode(parent, mgr, id), + AdjacencyDirtyFlag(true), + ShadowMesh(0), IndexCount(0), VertexCount(0), ShadowVolumesUsed(0), + Infinity(infinity), UseZFailMethod(zfailmethod), Optimization(ESV_SILHOUETTE_BY_POS) +{ + #ifdef _DEBUG + setDebugName("CShadowVolumeSceneNode"); + #endif + setShadowMesh(shadowMesh); + setAutomaticCulling(scene::EAC_OFF); +} + + +//! destructor +CShadowVolumeSceneNode::~CShadowVolumeSceneNode() +{ + if (ShadowMesh) + ShadowMesh->drop(); +} + + +void CShadowVolumeSceneNode::createShadowVolume(const core::vector3df& light, bool isDirectional) +{ + SShadowVolume* svp = 0; + core::aabbox3d* bb = 0; + + // builds the shadow volume and adds it to the shadow volume list. + + if (ShadowVolumes.size() > ShadowVolumesUsed) + { + // get the next unused buffer + + svp = &ShadowVolumes[ShadowVolumesUsed]; + svp->set_used(0); + + bb = &ShadowBBox[ShadowVolumesUsed]; + } + else + { + ShadowVolumes.push_back(SShadowVolume()); + svp = &ShadowVolumes.getLast(); + + ShadowBBox.push_back(core::aabbox3d()); + bb = &ShadowBBox.getLast(); + } + svp->reallocate(IndexCount*5); + ++ShadowVolumesUsed; + + // We use triangle lists + Edges.set_used(IndexCount*2); + u32 numEdges = 0; + + numEdges=createEdgesAndCaps(light, isDirectional, svp, bb); + + // for all edges add the near->far quads + core::vector3df lightDir1(light*Infinity); + core::vector3df lightDir2(light*Infinity); + for (u32 i=0; isize() >= svp->allocated_size()-5) + os::Printer::log("Allocation too small.", ELL_DEBUG); +#endif + svp->push_back(v1); + svp->push_back(v2); + svp->push_back(v3); + + svp->push_back(v2); + svp->push_back(v4); + svp->push_back(v3); + } +} + +// TODO. +// Not sure what's going on. Either FaceData should mean the opposite and true should mean facing away from light +// or I'm missing something else. Anyway - when not setting this then Shadows will look wrong on Burnings driver +// while they seem to look OK on first view either way on other drivers. Only tested with z-fail so far. +// Maybe errors only show up close to near/far plane on other drivers as otherwise the stencil-buffer-count +// is probably ending up with same value anyway +#define IRR_USE_REVERSE_EXTRUDED + +u32 CShadowVolumeSceneNode::createEdgesAndCaps(const core::vector3df& light, bool isDirectional, + SShadowVolume* svp, core::aabbox3d* bb) +{ + u32 numEdges=0; + const u32 faceCount = IndexCount / 3; + + if(faceCount >= 1) + bb->reset(Vertices[Indices[0]]); + else + bb->reset(0,0,0); + + // Check every face if it is front or back facing the light. + core::vector3df lightDir0(light); + core::vector3df lightDir1(light); + core::vector3df lightDir2(light); + for (u32 i=0; igetVideoDriver()->setMaterial(m); +#ifdef IRR_USE_REVERSE_EXTRUDED + SceneManager->getVideoDriver()->draw3DTriangle(core::triangle3df(v0+lightDir0,v1+lightDir0,v2+lightDir0), irr::video::SColor(255,255, 0, 0)); +#else + SceneManager->getVideoDriver()->draw3DTriangle(core::triangle3df(v0-lightDir0,v1-lightDir0,v2-lightDir0), irr::video::SColor(255,255, 0, 0)); +#endif + } +#endif + + if (UseZFailMethod && FaceData[i]) + { +#ifdef _DEBUG + if (svp->size() >= svp->allocated_size()-5) + os::Printer::log("Allocation too small.", ELL_DEBUG); +#endif + // add front cap from light-facing faces + svp->push_back(v2); + svp->push_back(v1); + svp->push_back(v0); + + // add back cap + if ( !isDirectional ) + { + lightDir1 = (v1-light).normalize(); + lightDir2 = (v2-light).normalize(); + } + const core::vector3df i0 = v0+lightDir0*Infinity; + const core::vector3df i1 = v1+lightDir1*Infinity; + const core::vector3df i2 = v2+lightDir2*Infinity; + + svp->push_back(i0); + svp->push_back(i1); + svp->push_back(i2); + + bb->addInternalPoint(i0); + bb->addInternalPoint(i1); + bb->addInternalPoint(i2); + } + } + + // Create edges + for (u32 i=0; idrop(); + ShadowMesh = mesh; + if (ShadowMesh) + { + ShadowMesh->grab(); + Box = ShadowMesh->getBoundingBox(); + } +} + + +void CShadowVolumeSceneNode::updateShadowVolumes() +{ + const u32 oldIndexCount = IndexCount; + const u32 oldVertexCount = VertexCount; + + VertexCount = 0; + IndexCount = 0; + ShadowVolumesUsed = 0; + + const IMesh* const mesh = ShadowMesh; + if (!mesh) + return; + + // create as much shadow volumes as there are lights but + // do not ignore the max light settings. + const u32 lightCount = SceneManager->getVideoDriver()->getDynamicLightCount(); + if (!lightCount) + return; + + // calculate total amount of vertices and indices + + u32 i; + u32 totalVertices = 0; + u32 totalIndices = 0; + const u32 bufcnt = mesh->getMeshBufferCount(); + + for (i=0; igetMeshBuffer(i); + if ( buf->getIndexType() == video::EIT_16BIT + && buf->getPrimitiveType() == scene::EPT_TRIANGLES ) + { + totalIndices += buf->getIndexCount(); + totalVertices += buf->getVertexCount(); + } + else + { + os::Printer::log("ShadowVolumeSceneNode only supports meshbuffers with 16 bit indices and triangles", ELL_WARNING); + return; + } + } + if ( totalIndices != (u32)(u16)totalIndices) + { + // We could switch to 32-bit indices, not much work and just bit of extra memory (< 192k) per shadow volume. + // If anyone ever complains and really needs that just switch it. But huge shadows are usually a bad idea as they will be slow. + os::Printer::log("ShadowVolumeSceneNode does not yet support shadowvolumes which need more than 16 bit indices", ELL_WARNING); + return; + } + + // allocate memory if necessary + + Vertices.set_used(totalVertices); + Indices.set_used(totalIndices); + FaceData.set_used(totalIndices / 3); + + // copy mesh + // (could speed this up for static meshes by adding some user flag to prevents copying) + for (i=0; igetMeshBuffer(i); + + const u16* idxp = buf->getIndices(); + const u16* idxpend = idxp + buf->getIndexCount(); + for (; idxp!=idxpend; ++idxp) + Indices[IndexCount++] = *idxp + VertexCount; + + const u32 vtxcnt = buf->getVertexCount(); + for (u32 j=0; jgetPosition(j); + } + + // recalculate adjacency if necessary + if (oldVertexCount != VertexCount || oldIndexCount != IndexCount || AdjacencyDirtyFlag) + calculateAdjacency(); + + core::matrix4 matInv(Parent->getAbsoluteTransformation()); + matInv.makeInverse(); + core::matrix4 matTransp(Parent->getAbsoluteTransformation(), core::matrix4::EM4CONST_TRANSPOSED); + const core::vector3df parentpos = Parent->getAbsolutePosition(); + + for (i=0; igetVideoDriver()->getDynamicLight(i); + + if ( dl.Type == video::ELT_DIRECTIONAL ) + { + core::vector3df ldir(dl.Direction); + matTransp.transformVect(ldir); + createShadowVolume(ldir, true); + } + else + { + core::vector3df lpos(dl.Position); + if (dl.CastShadows && + fabs((lpos - parentpos).getLengthSQ()) <= (dl.Radius*dl.Radius*4.0f)) + { + matInv.transformVect(lpos); + createShadowVolume(lpos, false); + } + } + } +} + +void CShadowVolumeSceneNode::setOptimization(ESHADOWVOLUME_OPTIMIZATION optimization) +{ + if ( Optimization != optimization ) + { + Optimization = optimization; + AdjacencyDirtyFlag = true; + } +} + +//! pre render method +void CShadowVolumeSceneNode::OnRegisterSceneNode() +{ + if (IsVisible) + { + SceneManager->registerNodeForRendering(this, scene::ESNRP_SHADOW); + ISceneNode::OnRegisterSceneNode(); + } +} + +//! renders the node. +void CShadowVolumeSceneNode::render() +{ + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + + if (!ShadowVolumesUsed || !driver) + return; + + driver->setTransform(video::ETS_WORLD, Parent->getAbsoluteTransformation()); + + bool checkFarPlaneClipping = UseZFailMethod && !driver->queryFeature(video::EVDF_DEPTH_CLAMP); + + // get camera frustum converted to local coordinates when we have to check for far plane clipping + SViewFrustum frust; + if ( checkFarPlaneClipping ) + { + const irr::scene::ICameraSceneNode* camera = SceneManager->getActiveCamera(); + if ( camera ) + { + frust = *camera->getViewFrustum(); + core::matrix4 invTrans(Parent->getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE); + frust.transform(invTrans); + } + else + checkFarPlaneClipping = false; + } + + for (u32 i=0; idrawStencilShadowVolume(ShadowVolumes[i], UseZFailMethod, DebugDataVisible); + else + { + // TODO: For some reason (not yet further investigated), Direct3D needs a call to drawStencilShadowVolume + // even if we have nothing to draw here to set the renderstate into a StencilShadowMode. + // If that's not done it has effect on further render calls. + core::array triangles; + driver->drawStencilShadowVolume(triangles, UseZFailMethod, DebugDataVisible); + } + } +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CShadowVolumeSceneNode::getBoundingBox() const +{ + return Box; +} + + +//! Generates adjacency information based on mesh indices. +void CShadowVolumeSceneNode::calculateAdjacency() +{ + AdjacencyDirtyFlag = false; + + if ( Optimization == ESV_NONE ) + { + Adjacency.clear(); + } + else if ( Optimization == ESV_SILHOUETTE_BY_POS ) + { + Adjacency.set_used(IndexCount); + + // go through all faces and fetch their three neighbours + for (u32 f=0; f store face number, else store adjacent face + if (of >= IndexCount) + Adjacency[f + edge] = f/3; + else + Adjacency[f + edge] = of/3; + } + } + } +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ diff --git a/source/Irrlicht/CShadowVolumeSceneNode.h b/source/Irrlicht/CShadowVolumeSceneNode.h new file mode 100644 index 00000000..6501652e --- /dev/null +++ b/source/Irrlicht/CShadowVolumeSceneNode.h @@ -0,0 +1,99 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_SHADOW_VOLUME_SCENE_NODE_H_INCLUDED__ +#define __C_SHADOW_VOLUME_SCENE_NODE_H_INCLUDED__ + +#include "IShadowVolumeSceneNode.h" + +namespace irr +{ +namespace scene +{ + + //! Scene node for rendering a shadow volume into a stencil buffer. + class CShadowVolumeSceneNode : public IShadowVolumeSceneNode + { + public: + + //! constructor + CShadowVolumeSceneNode(const IMesh* shadowMesh, ISceneNode* parent, ISceneManager* mgr, + s32 id, bool zfailmethod=true, f32 infinity=10000.0f); + + //! destructor + virtual ~CShadowVolumeSceneNode(); + + //! Sets the mesh from which the shadow volume should be generated. + /** To optimize shadow rendering, use a simpler mesh for shadows. + */ + virtual void setShadowMesh(const IMesh* mesh) _IRR_OVERRIDE_; + + //! Updates the shadow volumes for current light positions. + /** Called each render cycle from Animated Mesh SceneNode render method. */ + virtual void updateShadowVolumes() _IRR_OVERRIDE_; + + //! Set optimization used to create shadow volumes + /** Default is ESV_SILHOUETTE_BY_POS. If the shadow + looks bad then give ESV_NONE a try (which will be slower). */ + virtual void setOptimization(ESHADOWVOLUME_OPTIMIZATION optimization) _IRR_OVERRIDE_; + + //! Get currently active optimization used to create shadow volumes + virtual ESHADOWVOLUME_OPTIMIZATION getOptimization() const _IRR_OVERRIDE_ + { + return Optimization; + } + + //! pre render method + virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; + + //! renders the node. + virtual void render() _IRR_OVERRIDE_; + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_SHADOW_VOLUME; } + + private: + + typedef core::array SShadowVolume; + + void createShadowVolume(const core::vector3df& pos, bool isDirectional); + u32 createEdgesAndCaps(const core::vector3df& light, bool isDirectional, SShadowVolume* svp, core::aabbox3d* bb); + + //! Generates adjacency information based on mesh indices. + void calculateAdjacency(); + + core::aabbox3d Box; + + // a shadow volume for every light + core::array ShadowVolumes; + + // a back cap bounding box for every light + core::array > ShadowBBox; + + core::array Vertices; + core::array Indices; + core::array Adjacency; + core::array Edges; + // tells if face is front facing + core::array FaceData; + bool AdjacencyDirtyFlag; + + const scene::IMesh* ShadowMesh; + + u32 IndexCount; + u32 VertexCount; + u32 ShadowVolumesUsed; + + f32 Infinity; + bool UseZFailMethod; + ESHADOWVOLUME_OPTIMIZATION Optimization; + }; + +} // end namespace scene +} // end namespace irr + +#endif diff --git a/source/Irrlicht/CSkinnedMesh.cpp b/source/Irrlicht/CSkinnedMesh.cpp new file mode 100644 index 00000000..bc94759f --- /dev/null +++ b/source/Irrlicht/CSkinnedMesh.cpp @@ -0,0 +1,1511 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ + +#include "CSkinnedMesh.h" +#include "CBoneSceneNode.h" +#include "IAnimatedMeshSceneNode.h" +#include "os.h" + +namespace +{ + // Frames must always be increasing, so we remove objects where this isn't the case + // return number of kicked keys + template // T = objects containing a "frame" variable + irr::u32 dropBadKeys(irr::core::array& array) + { + if (array.size()<2) + return 0; + + irr::u32 n=1; // new index + for(irr::u32 j=1;j 0 ) + { + array.erase(n, d); + } + return d; + } + + // drop identical middle keys - we only need the first and last + // return number of kicked keys + template // Cmp = comparison for keys of type T + irr::u32 dropMiddleKeys(irr::core::array& array, Cmp & cmp) + { + if ( array.size() < 3 ) + return 0; + + irr::u32 s = 0; // old index for current key + irr::u32 n = 1; // new index for next key + for(irr::u32 j=1;j s+1 ) // had there been identical keys? + array[n++] = array[j-1]; // keep the last + array[n++] = array[j]; // keep the new one + s = j; + } + if ( array.size() > s+1 ) // identical keys at the array end? + array[n++] = array[array.size()-1]; // keep the last + + irr::u32 d = array.size()-n; // remove already copied keys + if ( d > 0 ) + { + array.erase(n, d); + } + return d; + } + + bool identicalPos(const irr::scene::ISkinnedMesh::SPositionKey& a, const irr::scene::ISkinnedMesh::SPositionKey& b) + { + return a.position == b.position; + } + + bool identicalScale(const irr::scene::ISkinnedMesh::SScaleKey& a, const irr::scene::ISkinnedMesh::SScaleKey& b) + { + return a.scale == b.scale; + } + + bool identicalRotation(const irr::scene::ISkinnedMesh::SRotationKey& a, const irr::scene::ISkinnedMesh::SRotationKey& b) + { + return a.rotation == b.rotation; + } +}; + +namespace irr +{ +namespace scene +{ + + +//! constructor +CSkinnedMesh::CSkinnedMesh() +: SkinningBuffers(0), EndFrame(0.f), FramesPerSecond(25.f), + LastAnimatedFrame(-1), SkinnedLastFrame(false), + InterpolationMode(EIM_LINEAR), + HasAnimation(false), PreparedForSkinning(false), + AnimateNormals(true), HardwareSkinning(false) +{ + #ifdef _DEBUG + setDebugName("CSkinnedMesh"); + #endif + + SkinningBuffers=&LocalBuffers; +} + + +//! destructor +CSkinnedMesh::~CSkinnedMesh() +{ + for (u32 i=0; idrop(); + } +} + + +//! returns the amount of frames in milliseconds. +//! If the amount is 1, it is a static (=non animated) mesh. +u32 CSkinnedMesh::getFrameCount() const +{ + return core::floor32(EndFrame+1.f); +} + + +//! Gets the default animation speed of the animated mesh. +/** \return Amount of frames per second. If the amount is 0, it is a static, non animated mesh. */ +f32 CSkinnedMesh::getAnimationSpeed() const +{ + return FramesPerSecond; +} + + +//! Gets the frame count of the animated mesh. +/** \param fps Frames per second to play the animation with. If the amount is 0, it is not animated. +The actual speed is set in the scene node the mesh is instantiated in.*/ +void CSkinnedMesh::setAnimationSpeed(f32 fps) +{ + FramesPerSecond=fps; +} + + +//! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level. +IMesh* CSkinnedMesh::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) +{ + //animate(frame,startFrameLoop, endFrameLoop); + if (frame==-1) + return this; + + animateMesh((f32)frame, 1.0f); + skinMesh(); + return this; +} + + +//-------------------------------------------------------------------------- +// Keyframe Animation +//-------------------------------------------------------------------------- + + +//! Animates this mesh's joints based on frame input +//! blend: {0-old position, 1-New position} +void CSkinnedMesh::animateMesh(f32 frame, f32 blend) +{ + if (!HasAnimation || LastAnimatedFrame==frame) + return; + + LastAnimatedFrame=frame; + SkinnedLastFrame=false; + + if (blend<=0.f) + return; //No need to animate + + for (u32 i=0; iAnimatedposition; + const core::vector3df oldScale = joint->Animatedscale; + const core::quaternion oldRotation = joint->Animatedrotation; + + core::vector3df position = oldPosition; + core::vector3df scale = oldScale; + core::quaternion rotation = oldRotation; + + getFrameData(frame, joint, + position, joint->positionHint, + scale, joint->scaleHint, + rotation, joint->rotationHint); + + if (blend==1.0f) + { + //No blending needed + joint->Animatedposition = position; + joint->Animatedscale = scale; + joint->Animatedrotation = rotation; + } + else + { + //Blend animation + joint->Animatedposition = core::lerp(oldPosition, position, blend); + joint->Animatedscale = core::lerp(oldScale, scale, blend); + joint->Animatedrotation.slerp(oldRotation, rotation, blend); + } + } + + //Note: + //LocalAnimatedMatrix needs to be built at some point, but this function may be called lots of times for + //one render (to play two animations at the same time) LocalAnimatedMatrix only needs to be built once. + //a call to buildAllLocalAnimatedMatrices is needed before skinning the mesh, and before the user gets the joints to move + + //---------------- + // Temp! + buildAllLocalAnimatedMatrices(); + //----------------- + + updateBoundingBox(); +} + + +void CSkinnedMesh::buildAllLocalAnimatedMatrices() +{ + for (u32 i=0; iUseAnimationFrom && + (joint->UseAnimationFrom->PositionKeys.size() || + joint->UseAnimationFrom->ScaleKeys.size() || + joint->UseAnimationFrom->RotationKeys.size() )) + { + joint->GlobalSkinningSpace=false; + + // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched to getMatrix_transposed instead of getMatrix for downward compatibility. + // Not tested so far if this was correct or wrong before quaternion fix! + joint->Animatedrotation.getMatrix_transposed(joint->LocalAnimatedMatrix); + + // --- joint->LocalAnimatedMatrix *= joint->Animatedrotation.getMatrix() --- + f32 *m1 = joint->LocalAnimatedMatrix.pointer(); + core::vector3df &Pos = joint->Animatedposition; + m1[0] += Pos.X*m1[3]; + m1[1] += Pos.Y*m1[3]; + m1[2] += Pos.Z*m1[3]; + m1[4] += Pos.X*m1[7]; + m1[5] += Pos.Y*m1[7]; + m1[6] += Pos.Z*m1[7]; + m1[8] += Pos.X*m1[11]; + m1[9] += Pos.Y*m1[11]; + m1[10] += Pos.Z*m1[11]; + m1[12] += Pos.X*m1[15]; + m1[13] += Pos.Y*m1[15]; + m1[14] += Pos.Z*m1[15]; + // ----------------------------------- + + if (joint->ScaleKeys.size()) + { + /* + core::matrix4 scaleMatrix; + scaleMatrix.setScale(joint->Animatedscale); + joint->LocalAnimatedMatrix *= scaleMatrix; + */ + + // -------- joint->LocalAnimatedMatrix *= scaleMatrix ----------------- + core::matrix4& mat = joint->LocalAnimatedMatrix; + mat[0] *= joint->Animatedscale.X; + mat[1] *= joint->Animatedscale.X; + mat[2] *= joint->Animatedscale.X; + mat[3] *= joint->Animatedscale.X; + mat[4] *= joint->Animatedscale.Y; + mat[5] *= joint->Animatedscale.Y; + mat[6] *= joint->Animatedscale.Y; + mat[7] *= joint->Animatedscale.Y; + mat[8] *= joint->Animatedscale.Z; + mat[9] *= joint->Animatedscale.Z; + mat[10] *= joint->Animatedscale.Z; + mat[11] *= joint->Animatedscale.Z; + // ----------------------------------- + } + } + else + { + joint->LocalAnimatedMatrix=joint->LocalMatrix; + } + } + SkinnedLastFrame=false; +} + + +void CSkinnedMesh::buildAllGlobalAnimatedMatrices(SJoint *joint, SJoint *parentJoint) +{ + if (!joint) + { + for (u32 i=0; iGlobalSkinningSpace) + joint->GlobalAnimatedMatrix = joint->LocalAnimatedMatrix; + else + joint->GlobalAnimatedMatrix = parentJoint->GlobalAnimatedMatrix * joint->LocalAnimatedMatrix; + } + + for (u32 j=0; jChildren.size(); ++j) + buildAllGlobalAnimatedMatrices(joint->Children[j], joint); +} + + +void CSkinnedMesh::getFrameData(f32 frame, SJoint *joint, + core::vector3df &position, s32 &positionHint, + core::vector3df &scale, s32 &scaleHint, + core::quaternion &rotation, s32 &rotationHint) +{ + s32 foundPositionIndex = -1; + s32 foundScaleIndex = -1; + s32 foundRotationIndex = -1; + + if (joint->UseAnimationFrom) + { + const core::array &PositionKeys=joint->UseAnimationFrom->PositionKeys; + const core::array &ScaleKeys=joint->UseAnimationFrom->ScaleKeys; + const core::array &RotationKeys=joint->UseAnimationFrom->RotationKeys; + + if (PositionKeys.size()) + { + foundPositionIndex = -1; + + //Test the Hints... + if (positionHint>=0 && (u32)positionHint < PositionKeys.size()) + { + //check this hint + if (positionHint>0 && PositionKeys[positionHint].frame>=frame && PositionKeys[positionHint-1].frame=frame && + PositionKeys[positionHint+0].frame= frame) //Keys should to be sorted by frame + { + foundPositionIndex=i; + positionHint=i; + break; + } + } + } + + //Do interpolation... + if (foundPositionIndex!=-1) + { + if (InterpolationMode==EIM_CONSTANT || foundPositionIndex==0) + { + position = PositionKeys[foundPositionIndex].position; + } + else if (InterpolationMode==EIM_LINEAR) + { + const SPositionKey& KeyA = PositionKeys[foundPositionIndex]; + const SPositionKey& KeyB = PositionKeys[foundPositionIndex-1]; + + const f32 fd1 = frame - KeyA.frame; + const f32 fd2 = KeyB.frame - frame; + position = ((KeyB.position-KeyA.position)/(fd1+fd2))*fd1 + KeyA.position; + } + } + } + + //------------------------------------------------------------ + + if (ScaleKeys.size()) + { + foundScaleIndex = -1; + + //Test the Hints... + if (scaleHint>=0 && (u32)scaleHint < ScaleKeys.size()) + { + //check this hint + if (scaleHint>0 && ScaleKeys[scaleHint].frame>=frame && ScaleKeys[scaleHint-1].frame=frame && + ScaleKeys[scaleHint+0].frame= frame) //Keys should to be sorted by frame + { + foundScaleIndex=i; + scaleHint=i; + break; + } + } + } + + //Do interpolation... + if (foundScaleIndex!=-1) + { + if (InterpolationMode==EIM_CONSTANT || foundScaleIndex==0) + { + scale = ScaleKeys[foundScaleIndex].scale; + } + else if (InterpolationMode==EIM_LINEAR) + { + const SScaleKey& KeyA = ScaleKeys[foundScaleIndex]; + const SScaleKey& KeyB = ScaleKeys[foundScaleIndex-1]; + + const f32 fd1 = frame - KeyA.frame; + const f32 fd2 = KeyB.frame - frame; + scale = ((KeyB.scale-KeyA.scale)/(fd1+fd2))*fd1 + KeyA.scale; + } + } + } + + //------------------------------------------------------------- + + if (RotationKeys.size()) + { + foundRotationIndex = -1; + + //Test the Hints... + if (rotationHint>=0 && (u32)rotationHint < RotationKeys.size()) + { + //check this hint + if (rotationHint>0 && RotationKeys[rotationHint].frame>=frame && RotationKeys[rotationHint-1].frame=frame && + RotationKeys[rotationHint+0].frame= frame) //Keys should be sorted by frame + { + foundRotationIndex=i; + rotationHint=i; + break; + } + } + } + + //Do interpolation... + if (foundRotationIndex!=-1) + { + if (InterpolationMode==EIM_CONSTANT || foundRotationIndex==0) + { + rotation = RotationKeys[foundRotationIndex].rotation; + } + else if (InterpolationMode==EIM_LINEAR) + { + const SRotationKey& KeyA = RotationKeys[foundRotationIndex]; + const SRotationKey& KeyB = RotationKeys[foundRotationIndex-1]; + + const f32 fd1 = frame - KeyA.frame; + const f32 fd2 = KeyB.frame - frame; + const f32 t = fd1/(fd1+fd2); + + /* + f32 t = 0; + if (KeyA.frame!=KeyB.frame) + t = (frame-KeyA.frame) / (KeyB.frame - KeyA.frame); + */ + + rotation.slerp(KeyA.rotation, KeyB.rotation, t); + } + } + } + } +} + +//-------------------------------------------------------------------------- +// Software Skinning +//-------------------------------------------------------------------------- + +//! Preforms a software skin on this mesh based of joint positions +void CSkinnedMesh::skinMesh() +{ + if (!HasAnimation || SkinnedLastFrame) + return; + + //---------------- + // This is marked as "Temp!". A shiny dubloon to whomever can tell me why. + buildAllGlobalAnimatedMatrices(); + //----------------- + + SkinnedLastFrame=true; + if (!HardwareSkinning) + { + //Software skin.... + u32 i; + + //rigid animation + for (i=0; iAttachedMeshes.size(); ++j) + { + SSkinMeshBuffer* Buffer=(*SkinningBuffers)[ AllJoints[i]->AttachedMeshes[j] ]; + Buffer->Transformation=AllJoints[i]->GlobalAnimatedMatrix; + } + } + + //clear skinning helper array + for (i=0; isize(); ++i) + (*SkinningBuffers)[i]->setDirty(EBT_VERTEX); + } + updateBoundingBox(); +} + + +void CSkinnedMesh::skinJoint(SJoint *joint, SJoint *parentJoint) +{ + if (joint->Weights.size()) + { + //Find this joints pull on vertices... + core::matrix4 jointVertexPull(core::matrix4::EM4CONST_NOTHING); + jointVertexPull.setbyproduct(joint->GlobalAnimatedMatrix, joint->GlobalInversedMatrix); + + core::vector3df thisVertexMove, thisNormalMove; + + core::array &buffersUsed=*SkinningBuffers; + + //Skin Vertices Positions and Normals... + for (u32 i=0; iWeights.size(); ++i) + { + SWeight& weight = joint->Weights[i]; + + // Pull this vertex... + jointVertexPull.transformVect(thisVertexMove, weight.StaticPos); + + if (AnimateNormals) + jointVertexPull.rotateVect(thisNormalMove, weight.StaticNormal); + + if (! (*(weight.Moved)) ) + { + *(weight.Moved) = true; + + buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos = thisVertexMove * weight.strength; + + if (AnimateNormals) + buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal = thisNormalMove * weight.strength; + + //*(weight._Pos) = thisVertexMove * weight.strength; + } + else + { + buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos += thisVertexMove * weight.strength; + + if (AnimateNormals) + buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal += thisNormalMove * weight.strength; + + //*(weight._Pos) += thisVertexMove * weight.strength; + } + + buffersUsed[weight.buffer_id]->boundingBoxNeedsRecalculated(); + } + } + + //Skin all children + for (u32 j=0; jChildren.size(); ++j) + skinJoint(joint->Children[j], joint); +} + + +E_ANIMATED_MESH_TYPE CSkinnedMesh::getMeshType() const +{ + return EAMT_SKINNED; +} + + +//! Gets joint count. +u32 CSkinnedMesh::getJointCount() const +{ + return AllJoints.size(); +} + + +//! Gets the name of a joint. +const c8* CSkinnedMesh::getJointName(u32 number) const +{ + if (number >= AllJoints.size()) + return 0; + return AllJoints[number]->Name.c_str(); +} + + +//! Gets a joint number from its name +s32 CSkinnedMesh::getJointNumber(const c8* name) const +{ + for (u32 i=0; iName == name) + return i; + } + + return -1; +} + + +//! returns amount of mesh buffers. +u32 CSkinnedMesh::getMeshBufferCount() const +{ + return LocalBuffers.size(); +} + + +//! returns pointer to a mesh buffer +IMeshBuffer* CSkinnedMesh::getMeshBuffer(u32 nr) const +{ + if (nr < LocalBuffers.size()) + return LocalBuffers[nr]; + else + return 0; +} + + +//! Returns pointer to a mesh buffer which fits a material +IMeshBuffer* CSkinnedMesh::getMeshBuffer(const video::SMaterial &material) const +{ + for (u32 i=0; igetMaterial() == material) + return LocalBuffers[i]; + } + return 0; +} + + +//! returns an axis aligned bounding box +const core::aabbox3d& CSkinnedMesh::getBoundingBox() const +{ + return BoundingBox; +} + + +//! set user axis aligned bounding box +void CSkinnedMesh::setBoundingBox( const core::aabbox3df& box) +{ + BoundingBox = box; +} + + +//! sets a flag of all contained materials to a new value +void CSkinnedMesh::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) +{ + for (u32 i=0; iMaterial.setFlag(flag,newvalue); +} + + +//! set the hardware mapping hint, for driver +void CSkinnedMesh::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, + E_BUFFER_TYPE buffer) +{ + for (u32 i=0; isetHardwareMappingHint(newMappingHint, buffer); +} + + +//! flags the meshbuffer as changed, reloads hardware buffers +void CSkinnedMesh::setDirty(E_BUFFER_TYPE buffer) +{ + for (u32 i=0; isetDirty(buffer); +} + + +//! uses animation from another mesh +bool CSkinnedMesh::useAnimationFrom(const ISkinnedMesh *mesh) +{ + bool unmatched=false; + + for(u32 i=0;iUseAnimationFrom=0; + + if (joint->Name=="") + unmatched=true; + else + { + for(u32 j=0;jgetAllJoints().size();++j) + { + SJoint *otherJoint=mesh->getAllJoints()[j]; + if (joint->Name==otherJoint->Name) + { + joint->UseAnimationFrom=otherJoint; + } + } + if (!joint->UseAnimationFrom) + unmatched=true; + } + } + + checkForAnimation(); + + return !unmatched; +} + + +//!Update Normals when Animating +//!False= Don't animate them, faster +//!True= Update normals (default) +void CSkinnedMesh::updateNormalsWhenAnimating(bool on) +{ + AnimateNormals = on; +} + + +//!Sets Interpolation Mode +void CSkinnedMesh::setInterpolationMode(E_INTERPOLATION_MODE mode) +{ + InterpolationMode = mode; +} + + +core::array &CSkinnedMesh::getMeshBuffers() +{ + return LocalBuffers; +} + + +core::array &CSkinnedMesh::getAllJoints() +{ + return AllJoints; +} + + +const core::array &CSkinnedMesh::getAllJoints() const +{ + return AllJoints; +} + + +//! (This feature is not implemented in irrlicht yet) +bool CSkinnedMesh::setHardwareSkinning(bool on) +{ + if (HardwareSkinning!=on) + { + if (on) + { + + //set mesh to static pose... + for (u32 i=0; iWeights.size(); ++j) + { + const u16 buffer_id=joint->Weights[j].buffer_id; + const u32 vertex_id=joint->Weights[j].vertex_id; + LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos = joint->Weights[j].StaticPos; + LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal = joint->Weights[j].StaticNormal; + LocalBuffers[buffer_id]->boundingBoxNeedsRecalculated(); + } + } + } + + HardwareSkinning=on; + } + return HardwareSkinning; +} + + +void CSkinnedMesh::calculateGlobalMatrices(SJoint *joint,SJoint *parentJoint) +{ + if (!joint && parentJoint) // bit of protection from endless loops + return; + + //Go through the root bones + if (!joint) + { + for (u32 i=0; iGlobalMatrix = joint->LocalMatrix; + else + joint->GlobalMatrix = parentJoint->GlobalMatrix * joint->LocalMatrix; + + joint->LocalAnimatedMatrix=joint->LocalMatrix; + joint->GlobalAnimatedMatrix=joint->GlobalMatrix; + + if (joint->GlobalInversedMatrix.isIdentity())//might be pre calculated + { + joint->GlobalInversedMatrix = joint->GlobalMatrix; + joint->GlobalInversedMatrix.makeInverse(); // slow + } + + for (u32 j=0; jChildren.size(); ++j) + calculateGlobalMatrices(joint->Children[j],joint); + SkinnedLastFrame=false; +} + + +void CSkinnedMesh::checkForAnimation() +{ + u32 i,j; + //Check for animation... + HasAnimation = false; + for(i=0;iUseAnimationFrom) + { + if (AllJoints[i]->UseAnimationFrom->PositionKeys.size() || + AllJoints[i]->UseAnimationFrom->ScaleKeys.size() || + AllJoints[i]->UseAnimationFrom->RotationKeys.size() ) + { + HasAnimation = true; + } + } + } + + //meshes with weights, are still counted as animated for ragdolls, etc + if (!HasAnimation) + { + for(i=0;iWeights.size()) + HasAnimation = true; + } + } + + if (HasAnimation) + { + //--- Find the length of the animation --- + EndFrame=0; + for(i=0;iUseAnimationFrom) + { + if (AllJoints[i]->UseAnimationFrom->PositionKeys.size()) + if (AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame > EndFrame) + EndFrame=AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame; + + if (AllJoints[i]->UseAnimationFrom->ScaleKeys.size()) + if (AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame > EndFrame) + EndFrame=AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame; + + if (AllJoints[i]->UseAnimationFrom->RotationKeys.size()) + if (AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame > EndFrame) + EndFrame=AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame; + } + } + } + + if (HasAnimation && !PreparedForSkinning) + { + PreparedForSkinning=true; + + //check for bugs: + for(i=0; i < AllJoints.size(); ++i) + { + SJoint *joint = AllJoints[i]; + for (j=0; jWeights.size(); ++j) + { + const u16 buffer_id=joint->Weights[j].buffer_id; + const u32 vertex_id=joint->Weights[j].vertex_id; + + //check for invalid ids + if (buffer_id>=LocalBuffers.size()) + { + os::Printer::log("Skinned Mesh: Weight buffer id too large", ELL_WARNING); + joint->Weights[j].buffer_id = joint->Weights[j].vertex_id =0; + } + else if (vertex_id>=LocalBuffers[buffer_id]->getVertexCount()) + { + os::Printer::log("Skinned Mesh: Weight vertex id too large", ELL_WARNING); + joint->Weights[j].buffer_id = joint->Weights[j].vertex_id =0; + } + } + } + + //An array used in skinning + + for (i=0; iWeights.size(); ++j) + { + const u16 buffer_id=joint->Weights[j].buffer_id; + const u32 vertex_id=joint->Weights[j].vertex_id; + + joint->Weights[j].Moved = &Vertices_Moved[buffer_id] [vertex_id]; + joint->Weights[j].StaticPos = LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos; + joint->Weights[j].StaticNormal = LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal; + + //joint->Weights[j]._Pos=&Buffers[buffer_id]->getVertex(vertex_id)->Pos; + } + } + + // normalize weights + normalizeWeights(); + } + SkinnedLastFrame=false; +} + +//! called by loader after populating with mesh and bone data +void CSkinnedMesh::finalize() +{ + os::Printer::log("Skinned Mesh - finalize", ELL_DEBUG); + u32 i; + + // Make sure we recalc the next frame + LastAnimatedFrame=-1; + SkinnedLastFrame=false; + + //calculate bounding box + for (i=0; irecalculateBoundingBox(); + } + + if (AllJoints.size() || RootJoints.size()) + { + // populate AllJoints or RootJoints, depending on which is empty + if (!RootJoints.size()) + { + + for(u32 CheckingIdx=0; CheckingIdx < AllJoints.size(); ++CheckingIdx) + { + + bool foundParent=false; + for(i=0; i < AllJoints.size(); ++i) + { + for(u32 n=0; n < AllJoints[i]->Children.size(); ++n) + { + if (AllJoints[i]->Children[n] == AllJoints[CheckingIdx]) + foundParent=true; + } + } + + if (!foundParent) + RootJoints.push_back(AllJoints[CheckingIdx]); + } + } + else + { + AllJoints=RootJoints; + } + } + + for(i=0; i < AllJoints.size(); ++i) + { + AllJoints[i]->UseAnimationFrom=AllJoints[i]; + } + + //Set array sizes... + + for (i=0; i() ); + Vertices_Moved[i].set_used(LocalBuffers[i]->getVertexCount()); + } + + checkForAnimation(); + + if (HasAnimation) + { + irr::u32 redundantPosKeys = 0; + irr::u32 unorderedPosKeys = 0; + irr::u32 redundantScaleKeys = 0; + irr::u32 unorderedScaleKeys = 0; + irr::u32 redundantRotationKeys = 0; + irr::u32 unorderedRotationKeys = 0; + + //--- optimize and check keyframes --- + for(i=0;i &PositionKeys =AllJoints[i]->PositionKeys; + core::array &ScaleKeys = AllJoints[i]->ScaleKeys; + core::array &RotationKeys = AllJoints[i]->RotationKeys; + + // redundant = identical middle keys - we only need the first and last frame + // unordered = frames which are out of order - we can't handle those + redundantPosKeys += dropMiddleKeys(PositionKeys, identicalPos); + unorderedPosKeys += dropBadKeys(PositionKeys); + redundantScaleKeys += dropMiddleKeys(ScaleKeys, identicalScale); + unorderedScaleKeys += dropBadKeys(ScaleKeys); + redundantRotationKeys += dropMiddleKeys(RotationKeys, identicalRotation); + unorderedRotationKeys += dropBadKeys(RotationKeys); + + //Fill empty keyframe areas + if (PositionKeys.size()) + { + SPositionKey *Key; + Key=&PositionKeys[0];//getFirst + if (Key->frame!=0) + { + PositionKeys.push_front(*Key); + Key=&PositionKeys[0];//getFirst + Key->frame=0; + } + + Key=&PositionKeys.getLast(); + if (Key->frame!=EndFrame) + { + PositionKeys.push_back(*Key); + Key=&PositionKeys.getLast(); + Key->frame=EndFrame; + } + } + + if (ScaleKeys.size()) + { + SScaleKey *Key; + Key=&ScaleKeys[0];//getFirst + if (Key->frame!=0) + { + ScaleKeys.push_front(*Key); + Key=&ScaleKeys[0];//getFirst + Key->frame=0; + } + + Key=&ScaleKeys.getLast(); + if (Key->frame!=EndFrame) + { + ScaleKeys.push_back(*Key); + Key=&ScaleKeys.getLast(); + Key->frame=EndFrame; + } + } + + if (RotationKeys.size()) + { + SRotationKey *Key; + Key=&RotationKeys[0];//getFirst + if (Key->frame!=0) + { + RotationKeys.push_front(*Key); + Key=&RotationKeys[0];//getFirst + Key->frame=0; + } + + Key=&RotationKeys.getLast(); + if (Key->frame!=EndFrame) + { + RotationKeys.push_back(*Key); + Key=&RotationKeys.getLast(); + Key->frame=EndFrame; + } + } + } + + if ( redundantPosKeys > 0 ) + { + os::Printer::log("Skinned Mesh - redundant position frames kicked:", core::stringc(redundantPosKeys).c_str(), ELL_DEBUG); + } + if ( unorderedPosKeys > 0 ) + { + irr::os::Printer::log("Skinned Mesh - unsorted position frames kicked:", irr::core::stringc(unorderedPosKeys).c_str(), irr::ELL_DEBUG); + } + if ( redundantScaleKeys > 0 ) + { + os::Printer::log("Skinned Mesh - redundant scale frames kicked:", core::stringc(redundantScaleKeys).c_str(), ELL_DEBUG); + } + if ( unorderedScaleKeys > 0 ) + { + irr::os::Printer::log("Skinned Mesh - unsorted scale frames kicked:", irr::core::stringc(unorderedScaleKeys).c_str(), irr::ELL_DEBUG); + } + if ( redundantRotationKeys > 0 ) + { + os::Printer::log("Skinned Mesh - redundant rotation frames kicked:", core::stringc(redundantRotationKeys).c_str(), ELL_DEBUG); + } + if ( unorderedRotationKeys > 0 ) + { + irr::os::Printer::log("Skinned Mesh - unsorted rotation frames kicked:", irr::core::stringc(unorderedRotationKeys).c_str(), irr::ELL_DEBUG); + } + } + + //Needed for animation and skinning... + + calculateGlobalMatrices(0,0); + + //animateMesh(0, 1); + //buildAllLocalAnimatedMatrices(); + //buildAllGlobalAnimatedMatrices(); + + //rigid animation for non animated meshes + for (i=0; iAttachedMeshes.size(); ++j) + { + SSkinMeshBuffer* Buffer=(*SkinningBuffers)[ AllJoints[i]->AttachedMeshes[j] ]; + Buffer->Transformation=AllJoints[i]->GlobalAnimatedMatrix; + } + } + + //calculate bounding box + if (LocalBuffers.empty()) + BoundingBox.reset(0,0,0); + else + { + irr::core::aabbox3df bb(LocalBuffers[0]->BoundingBox); + LocalBuffers[0]->Transformation.transformBoxEx(bb); + BoundingBox.reset(bb); + + for (u32 j=1; jBoundingBox; + LocalBuffers[j]->Transformation.transformBoxEx(bb); + + BoundingBox.addInternalBox(bb); + } + } +} + + +void CSkinnedMesh::updateBoundingBox(void) +{ + if(!SkinningBuffers) + return; + + core::array & buffer = *SkinningBuffers; + BoundingBox.reset(0,0,0); + + if (!buffer.empty()) + { + for (u32 j=0; jrecalculateBoundingBox(); + core::aabbox3df bb = buffer[j]->BoundingBox; + buffer[j]->Transformation.transformBoxEx(bb); + + BoundingBox.addInternalBox(bb); + } + } +} + + +scene::SSkinMeshBuffer *CSkinnedMesh::addMeshBuffer() +{ + scene::SSkinMeshBuffer *buffer=new scene::SSkinMeshBuffer(); + LocalBuffers.push_back(buffer); + return buffer; +} + + +CSkinnedMesh::SJoint *CSkinnedMesh::addJoint(SJoint *parent) +{ + SJoint *joint=new SJoint; + + AllJoints.push_back(joint); + if (!parent) + { + //Add root joints to array in finalize() + } + else + { + //Set parent (Be careful of the mesh loader also setting the parent) + parent->Children.push_back(joint); + } + + return joint; +} + + +CSkinnedMesh::SPositionKey *CSkinnedMesh::addPositionKey(SJoint *joint) +{ + if (!joint) + return 0; + + joint->PositionKeys.push_back(SPositionKey()); + return &joint->PositionKeys.getLast(); +} + + +CSkinnedMesh::SScaleKey *CSkinnedMesh::addScaleKey(SJoint *joint) +{ + if (!joint) + return 0; + + joint->ScaleKeys.push_back(SScaleKey()); + return &joint->ScaleKeys.getLast(); +} + + +CSkinnedMesh::SRotationKey *CSkinnedMesh::addRotationKey(SJoint *joint) +{ + if (!joint) + return 0; + + joint->RotationKeys.push_back(SRotationKey()); + return &joint->RotationKeys.getLast(); +} + + +CSkinnedMesh::SWeight *CSkinnedMesh::addWeight(SJoint *joint) +{ + if (!joint) + return 0; + + joint->Weights.push_back(SWeight()); + return &joint->Weights.getLast(); +} + + +bool CSkinnedMesh::isStatic() +{ + return !HasAnimation; +} + + +void CSkinnedMesh::normalizeWeights() +{ + // note: unsure if weights ids are going to be used. + + // Normalise the weights on bones.... + + u32 i,j; + core::array< core::array > verticesTotalWeight; + + verticesTotalWeight.reallocate(LocalBuffers.size()); + for (i=0; i()); + verticesTotalWeight[i].set_used(LocalBuffers[i]->getVertexCount()); + } + + for (i=0; iWeights.size(); ++j) + { + if (joint->Weights[j].strength<=0)//Check for invalid weights + { + joint->Weights.erase(j); + --j; + } + else + { + verticesTotalWeight[joint->Weights[j].buffer_id] [joint->Weights[j].vertex_id] += joint->Weights[j].strength; + } + } + } + + for (i=0; iWeights.size(); ++j) + { + const f32 total = verticesTotalWeight[joint->Weights[j].buffer_id] [joint->Weights[j].vertex_id]; + if (total != 0 && total != 1) + joint->Weights[j].strength /= total; + } + } +} + + +void CSkinnedMesh::recoverJointsFromMesh(core::array &jointChildSceneNodes) +{ + for (u32 i=0; isetPosition(joint->LocalAnimatedMatrix.getTranslation()); + node->setRotation(joint->LocalAnimatedMatrix.getRotationDegrees()); + node->setScale(joint->LocalAnimatedMatrix.getScale()); + + node->positionHint=joint->positionHint; + node->scaleHint=joint->scaleHint; + node->rotationHint=joint->rotationHint; + + node->updateAbsolutePosition(); + } +} + + +void CSkinnedMesh::transferJointsToMesh(const core::array &jointChildSceneNodes) +{ + for (u32 i=0; iLocalAnimatedMatrix.setRotationDegrees(node->getRotation()); + joint->LocalAnimatedMatrix.setTranslation(node->getPosition()); + joint->LocalAnimatedMatrix *= core::matrix4().setScale(node->getScale()); + + joint->positionHint=node->positionHint; + joint->scaleHint=node->scaleHint; + joint->rotationHint=node->rotationHint; + + joint->GlobalSkinningSpace=(node->getSkinningSpace()==EBSS_GLOBAL); + } + // Make sure we recalc the next frame + LastAnimatedFrame=-1; + SkinnedLastFrame=false; +} + + +void CSkinnedMesh::transferOnlyJointsHintsToMesh(const core::array &jointChildSceneNodes) +{ + for (u32 i=0; ipositionHint=node->positionHint; + joint->scaleHint=node->scaleHint; + joint->rotationHint=node->rotationHint; + } + SkinnedLastFrame=false; +} + + +void CSkinnedMesh::addJoints(core::array &jointChildSceneNodes, + IAnimatedMeshSceneNode* node, ISceneManager* smgr) +{ + //Create new joints + for (u32 i=0; iName.c_str())); + } + + //Match up parents + for (u32 i=0; iChildren.size(); ++n) + { + if (parentTest->Children[n]==joint) + { + parentID=j; + break; + } + } + } + } + + IBoneSceneNode* bone=jointChildSceneNodes[i]; + if (parentID!=-1) + bone->setParent(jointChildSceneNodes[parentID]); + else + bone->setParent(node); + + bone->drop(); + } + SkinnedLastFrame=false; +} + + +void CSkinnedMesh::convertMeshToTangents() +{ + // now calculate tangents + for (u32 b=0; b < LocalBuffers.size(); ++b) + { + if (LocalBuffers[b]) + { + LocalBuffers[b]->convertToTangents(); + + const s32 idxCnt = LocalBuffers[b]->getIndexCount(); + + u16* idx = LocalBuffers[b]->getIndices(); + video::S3DVertexTangents* v = + (video::S3DVertexTangents*)LocalBuffers[b]->getVertices(); + + for (s32 i=0; i& getBoundingBox() const _IRR_OVERRIDE_; + + //! set user axis aligned bounding box + virtual void setBoundingBox( const core::aabbox3df& box) _IRR_OVERRIDE_; + + //! sets a flag of all contained materials to a new value + virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) _IRR_OVERRIDE_; + + //! set the hardware mapping hint, for driver + virtual void setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_; + + //! flags the meshbuffer as changed, reloads hardware buffers + virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_; + + //! Returns the type of the animated mesh. + virtual E_ANIMATED_MESH_TYPE getMeshType() const _IRR_OVERRIDE_; + + //! Gets joint count. + virtual u32 getJointCount() const _IRR_OVERRIDE_; + + //! Gets the name of a joint. + virtual const c8* getJointName(u32 number) const _IRR_OVERRIDE_; + + //! Gets a joint number from its name + virtual s32 getJointNumber(const c8* name) const _IRR_OVERRIDE_; + + //! uses animation from another mesh + virtual bool useAnimationFrom(const ISkinnedMesh *mesh) _IRR_OVERRIDE_; + + //! Update Normals when Animating + //! False= Don't (default) + //! True = Update normals, slower + virtual void updateNormalsWhenAnimating(bool on) _IRR_OVERRIDE_; + + //! Sets Interpolation Mode + virtual void setInterpolationMode(E_INTERPOLATION_MODE mode) _IRR_OVERRIDE_; + + //! Convertes the mesh to contain tangent information + virtual void convertMeshToTangents() _IRR_OVERRIDE_; + + //! Does the mesh have no animation + virtual bool isStatic() _IRR_OVERRIDE_; + + //! (This feature is not implemented in irrlicht yet) + virtual bool setHardwareSkinning(bool on) _IRR_OVERRIDE_; + + //Interface for the mesh loaders (finalize should lock these functions, and they should have some prefix like loader_ + //these functions will use the needed arrays, set values, etc to help the loaders + + //! exposed for loaders to add mesh buffers + virtual core::array &getMeshBuffers() _IRR_OVERRIDE_; + + //! alternative method for adding joints + virtual core::array &getAllJoints() _IRR_OVERRIDE_; + + //! alternative method for adding joints + virtual const core::array &getAllJoints() const _IRR_OVERRIDE_; + + //! loaders should call this after populating the mesh + virtual void finalize() _IRR_OVERRIDE_; + + //! Adds a new meshbuffer to the mesh, access it as last one + virtual SSkinMeshBuffer *addMeshBuffer() _IRR_OVERRIDE_; + + //! Adds a new joint to the mesh, access it as last one + virtual SJoint *addJoint(SJoint *parent=0) _IRR_OVERRIDE_; + + //! Adds a new position key to the mesh, access it as last one + virtual SPositionKey *addPositionKey(SJoint *joint) _IRR_OVERRIDE_; + //! Adds a new rotation key to the mesh, access it as last one + virtual SRotationKey *addRotationKey(SJoint *joint) _IRR_OVERRIDE_; + //! Adds a new scale key to the mesh, access it as last one + virtual SScaleKey *addScaleKey(SJoint *joint) _IRR_OVERRIDE_; + + //! Adds a new weight to the mesh, access it as last one + virtual SWeight *addWeight(SJoint *joint) _IRR_OVERRIDE_; + + virtual void updateBoundingBox(void); + + //! Recovers the joints from the mesh + void recoverJointsFromMesh(core::array &jointChildSceneNodes); + + //! Tranfers the joint data to the mesh + void transferJointsToMesh(const core::array &jointChildSceneNodes); + + //! Tranfers the joint hints to the mesh + void transferOnlyJointsHintsToMesh(const core::array &jointChildSceneNodes); + + //! Creates an array of joints from this mesh as children of node + void addJoints(core::array &jointChildSceneNodes, + IAnimatedMeshSceneNode* node, + ISceneManager* smgr); + +private: + void checkForAnimation(); + + void normalizeWeights(); + + void buildAllLocalAnimatedMatrices(); + + void buildAllGlobalAnimatedMatrices(SJoint *Joint=0, SJoint *ParentJoint=0); + + void getFrameData(f32 frame, SJoint *Node, + core::vector3df &position, s32 &positionHint, + core::vector3df &scale, s32 &scaleHint, + core::quaternion &rotation, s32 &rotationHint); + + void calculateGlobalMatrices(SJoint *Joint,SJoint *ParentJoint); + + void skinJoint(SJoint *Joint, SJoint *ParentJoint); + + void calculateTangents(core::vector3df& normal, + core::vector3df& tangent, core::vector3df& binormal, + const core::vector3df& vt1, const core::vector3df& vt2, const core::vector3df& vt3, + const core::vector2df& tc1, const core::vector2df& tc2, const core::vector2df& tc3); + + core::array *SkinningBuffers; //Meshbuffer to skin, default is to skin localBuffers + + core::array LocalBuffers; + + core::array AllJoints; + core::array RootJoints; + + core::array< core::array > Vertices_Moved; + + core::aabbox3d BoundingBox; + + f32 EndFrame; + f32 FramesPerSecond; + + f32 LastAnimatedFrame; + bool SkinnedLastFrame; + + E_INTERPOLATION_MODE InterpolationMode:8; + + bool HasAnimation; + bool PreparedForSkinning; + bool AnimateNormals; + bool HardwareSkinning; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CSkyBoxSceneNode.cpp b/source/Irrlicht/CSkyBoxSceneNode.cpp new file mode 100644 index 00000000..2ad3fe6e --- /dev/null +++ b/source/Irrlicht/CSkyBoxSceneNode.cpp @@ -0,0 +1,260 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CSkyBoxSceneNode.h" +#include "IVideoDriver.h" +#include "ISceneManager.h" +#include "ICameraSceneNode.h" +#include "S3DVertex.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CSkyBoxSceneNode::CSkyBoxSceneNode(video::ITexture* top, video::ITexture* bottom, video::ITexture* left, + video::ITexture* right, video::ITexture* front, video::ITexture* back, ISceneNode* parent, ISceneManager* mgr, s32 id) +: ISceneNode(parent, mgr, id) +{ + #ifdef _DEBUG + setDebugName("CSkyBoxSceneNode"); + #endif + + setAutomaticCulling(scene::EAC_OFF); + Box.MaxEdge.set(0,0,0); + Box.MinEdge.set(0,0,0); + + // create indices + + Indices[0] = 0; + Indices[1] = 1; + Indices[2] = 2; + Indices[3] = 3; + + // create material + + video::SMaterial mat; + mat.Lighting = false; + mat.ZBuffer = video::ECFN_DISABLED; + mat.ZWriteEnable = video::EZW_OFF; + mat.AntiAliasing=0; + mat.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE; + mat.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE; + mat.TextureLayer[0].TextureWrapW = video::ETC_CLAMP_TO_EDGE; + + /* Hey, I am no artist, but look at that + cool ASCII art I made! ;) + + -111 111 + /6--------/5 y + / | / | ^ z + / | 11-1 | | / + -11-1 3---------2 | |/ + | 7- - -| -4 1-11 *---->x + | -1-11 | / 3-------|2 + |/ | / | //| + 0---------1/ | // | + -1-1-1 1-1-1 |// | + 0--------1 + */ + + video::ITexture* tex = front; + if (!tex) tex = left; + if (!tex) tex = back; + if (!tex) tex = right; + if (!tex) tex = top; + if (!tex) tex = bottom; + + const f32 onepixel = tex?(1.0f / (tex->getSize().Width * 1.5f)) : 0.0f; + const f32 t = 1.0f - onepixel; + const f32 o = 0.0f + onepixel; + + // create front side + + Material[0] = mat; + Material[0].setTexture(0, front); + Vertices[0] = video::S3DVertex(-1,-1,-1, 0,0,1, video::SColor(255,255,255,255), t, t); + Vertices[1] = video::S3DVertex( 1,-1,-1, 0,0,1, video::SColor(255,255,255,255), o, t); + Vertices[2] = video::S3DVertex( 1, 1,-1, 0,0,1, video::SColor(255,255,255,255), o, o); + Vertices[3] = video::S3DVertex(-1, 1,-1, 0,0,1, video::SColor(255,255,255,255), t, o); + + // create left side + + Material[1] = mat; + Material[1].setTexture(0, left); + Vertices[4] = video::S3DVertex( 1,-1,-1, -1,0,0, video::SColor(255,255,255,255), t, t); + Vertices[5] = video::S3DVertex( 1,-1, 1, -1,0,0, video::SColor(255,255,255,255), o, t); + Vertices[6] = video::S3DVertex( 1, 1, 1, -1,0,0, video::SColor(255,255,255,255), o, o); + Vertices[7] = video::S3DVertex( 1, 1,-1, -1,0,0, video::SColor(255,255,255,255), t, o); + + // create back side + + Material[2] = mat; + Material[2].setTexture(0, back); + Vertices[8] = video::S3DVertex( 1,-1, 1, 0,0,-1, video::SColor(255,255,255,255), t, t); + Vertices[9] = video::S3DVertex(-1,-1, 1, 0,0,-1, video::SColor(255,255,255,255), o, t); + Vertices[10] = video::S3DVertex(-1, 1, 1, 0,0,-1, video::SColor(255,255,255,255), o, o); + Vertices[11] = video::S3DVertex( 1, 1, 1, 0,0,-1, video::SColor(255,255,255,255), t, o); + + // create right side + + Material[3] = mat; + Material[3].setTexture(0, right); + Vertices[12] = video::S3DVertex(-1,-1, 1, 1,0,0, video::SColor(255,255,255,255), t, t); + Vertices[13] = video::S3DVertex(-1,-1,-1, 1,0,0, video::SColor(255,255,255,255), o, t); + Vertices[14] = video::S3DVertex(-1, 1,-1, 1,0,0, video::SColor(255,255,255,255), o, o); + Vertices[15] = video::S3DVertex(-1, 1, 1, 1,0,0, video::SColor(255,255,255,255), t, o); + + // create top side + + Material[4] = mat; + Material[4].setTexture(0, top); + Vertices[16] = video::S3DVertex( 1, 1,-1, 0,-1,0, video::SColor(255,255,255,255), t, t); + Vertices[17] = video::S3DVertex( 1, 1, 1, 0,-1,0, video::SColor(255,255,255,255), o, t); + Vertices[18] = video::S3DVertex(-1, 1, 1, 0,-1,0, video::SColor(255,255,255,255), o, o); + Vertices[19] = video::S3DVertex(-1, 1,-1, 0,-1,0, video::SColor(255,255,255,255), t, o); + + // create bottom side + + Material[5] = mat; + Material[5].setTexture(0, bottom); + Vertices[20] = video::S3DVertex( 1,-1, 1, 0,1,0, video::SColor(255,255,255,255), o, o); + Vertices[21] = video::S3DVertex( 1,-1,-1, 0,1,0, video::SColor(255,255,255,255), t, o); + Vertices[22] = video::S3DVertex(-1,-1,-1, 0,1,0, video::SColor(255,255,255,255), t, t); + Vertices[23] = video::S3DVertex(-1,-1, 1, 0,1,0, video::SColor(255,255,255,255), o, t); +} + + +//! renders the node. +void CSkyBoxSceneNode::render() +{ + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + scene::ICameraSceneNode* camera = SceneManager->getActiveCamera(); + + if (!camera || !driver) + return; + + if ( !camera->isOrthogonal() ) + { + // draw perspective skybox + + 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; + scale.setScale(core::vector3df(viewDistance, viewDistance, viewDistance)); + + driver->setTransform(video::ETS_WORLD, translate * scale); + + for (s32 i=0; i<6; ++i) + { + driver->setMaterial(Material[i]); + driver->drawIndexedTriangleFan(&Vertices[i*4], 4, Indices, 2); + } + } + else + { + // draw orthogonal skybox, + // simply choose one texture and draw it as 2d picture. + // there could be better ways to do this, but currently I think this is ok. + + core::vector3df lookVect = camera->getTarget() - camera->getAbsolutePosition(); + lookVect.normalize(); + core::vector3df absVect( core::abs_(lookVect.X), + core::abs_(lookVect.Y), + core::abs_(lookVect.Z)); + + int idx = 0; + + if ( absVect.X >= absVect.Y && absVect.X >= absVect.Z ) + { + // x direction + idx = lookVect.X > 0 ? 0 : 2; + } + else + if ( absVect.Y >= absVect.X && absVect.Y >= absVect.Z ) + { + // y direction + idx = lookVect.Y > 0 ? 4 : 5; + } + else + if ( absVect.Z >= absVect.X && absVect.Z >= absVect.Y ) + { + // z direction + idx = lookVect.Z > 0 ? 1 : 3; + } + + video::ITexture* tex = Material[idx].getTexture(0); + + if ( tex ) + { + core::rect rctDest(core::position2d(-1,0), + core::dimension2di(driver->getCurrentRenderTargetSize())); + core::rect rctSrc(core::position2d(0,0), + core::dimension2di(tex->getOriginalSize())); + + driver->draw2DImage(tex, rctDest, rctSrc); + } + } +} + + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CSkyBoxSceneNode::getBoundingBox() const +{ + return Box; +} + + +void CSkyBoxSceneNode::OnRegisterSceneNode() +{ + if (IsVisible) + SceneManager->registerNodeForRendering(this, ESNRP_SKY_BOX); + + ISceneNode::OnRegisterSceneNode(); +} + + +//! returns the material based on the zero based index i. +video::SMaterial& CSkyBoxSceneNode::getMaterial(u32 i) +{ + return Material[i]; +} + + +//! returns amount of materials used by this scene node. +u32 CSkyBoxSceneNode::getMaterialCount() const +{ + return 6; +} + + +//! Creates a clone of this scene node and its children. +ISceneNode* CSkyBoxSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager) +{ + if (!newParent) newParent = Parent; + if (!newManager) newManager = SceneManager; + + CSkyBoxSceneNode* nb = new CSkyBoxSceneNode(0,0,0,0,0,0, newParent, + newManager, ID); + + nb->cloneMembers(this, newManager); + + for (u32 i=0; i<6; ++i) + nb->Material[i] = Material[i]; + + if ( newParent ) + nb->drop(); + return nb; +} + + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CSkyBoxSceneNode.h b/source/Irrlicht/CSkyBoxSceneNode.h new file mode 100644 index 00000000..a153b50a --- /dev/null +++ b/source/Irrlicht/CSkyBoxSceneNode.h @@ -0,0 +1,62 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_SKY_BOX_SCENE_NODE_H_INCLUDED__ +#define __C_SKY_BOX_SCENE_NODE_H_INCLUDED__ + +#include "ISceneNode.h" +#include "S3DVertex.h" + +namespace irr +{ +namespace scene +{ + + // Skybox, rendered with zbuffer turned off, before all other nodes. + class CSkyBoxSceneNode : public ISceneNode + { + public: + + //! constructor + CSkyBoxSceneNode(video::ITexture* top, video::ITexture* bottom, video::ITexture* left, + video::ITexture* right, video::ITexture* front, video::ITexture* back, + ISceneNode* parent, ISceneManager* mgr, s32 id); + + virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; + + //! renders the node. + virtual void render() _IRR_OVERRIDE_; + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + //! returns the material based on the zero based index i. To get the amount + //! of materials used by this scene node, use getMaterialCount(). + //! This function is needed for inserting the node into the scene hierarchy on a + //! optimal position for minimizing renderstate changes, but can also be used + //! to directly modify the material of a scene node. + virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_; + + //! returns amount of materials used by this scene node. + virtual u32 getMaterialCount() const _IRR_OVERRIDE_; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_SKY_BOX; } + + //! Creates a clone of this scene node and its children. + virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + private: + + core::aabbox3d Box; + u16 Indices[4]; + video::S3DVertex Vertices[4*6]; + video::SMaterial Material[6]; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CSkyDomeSceneNode.cpp b/source/Irrlicht/CSkyDomeSceneNode.cpp new file mode 100644 index 00000000..7cf81f39 --- /dev/null +++ b/source/Irrlicht/CSkyDomeSceneNode.cpp @@ -0,0 +1,264 @@ +// Copyright (C) 2002-2012 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) + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_SKYDOME_SCENENODE_ +#include "CSkyDomeSceneNode.h" +#include "IVideoDriver.h" +#include "ISceneManager.h" +#include "ICameraSceneNode.h" +#include "IAnimatedMesh.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + +/* horiRes and vertRes: + Controls the number of faces along the horizontal axis (30 is a good value) + and the number of faces along the vertical axis (8 is a good value). + + texturePercentage: + Only the top texturePercentage of the image is used, e.g. 0.8 uses the top 80% of the image, + 1.0 uses the entire image. This is useful as some landscape images have a small banner + at the bottom that you don't want. + + spherePercentage: + This controls how far around the sphere the sky dome goes. For value 1.0 you get exactly the upper + hemisphere, for 1.1 you get slightly more, and for 2.0 you get a full sphere. It is sometimes useful + to use a value slightly bigger than 1 to avoid a gap between some ground place and the sky. This + parameters stretches the image to fit the chosen "sphere-size". */ + +CSkyDomeSceneNode::CSkyDomeSceneNode(video::ITexture* sky, u32 horiRes, u32 vertRes, + f32 texturePercentage, f32 spherePercentage, f32 radius, + ISceneNode* parent, ISceneManager* mgr, s32 id) + : ISceneNode(parent, mgr, id), Buffer(0), + HorizontalResolution(horiRes), VerticalResolution(vertRes), + TexturePercentage(texturePercentage), + SpherePercentage(spherePercentage), Radius(radius) +{ + #ifdef _DEBUG + setDebugName("CSkyDomeSceneNode"); + #endif + + setAutomaticCulling(scene::EAC_OFF); + + Buffer = new SMeshBuffer(); + Buffer->Material.Lighting = false; + Buffer->Material.ZBuffer = video::ECFN_DISABLED; + Buffer->Material.ZWriteEnable = video::EZW_OFF; + Buffer->Material.AntiAliasing = video::EAAM_OFF; + Buffer->Material.setTexture(0, sky); + Buffer->BoundingBox.MaxEdge.set(0,0,0); + Buffer->BoundingBox.MinEdge.set(0,0,0); + + // regenerate the mesh + generateMesh(); +} + + +CSkyDomeSceneNode::~CSkyDomeSceneNode() +{ + if (Buffer) + Buffer->drop(); +} + + +void CSkyDomeSceneNode::generateMesh() +{ + f32 azimuth; + u32 k; + + Buffer->Vertices.clear(); + Buffer->Indices.clear(); + + const f32 azimuth_step = (core::PI * 2.f) / HorizontalResolution; + if (SpherePercentage < 0.f) + SpherePercentage = -SpherePercentage; + if (SpherePercentage > 2.f) + SpherePercentage = 2.f; + const f32 elevation_step = SpherePercentage * core::HALF_PI / (f32)VerticalResolution; + + Buffer->Vertices.reallocate( (HorizontalResolution + 1) * (VerticalResolution + 1) ); + Buffer->Indices.reallocate(3 * (2*VerticalResolution - 1) * HorizontalResolution); + + video::S3DVertex vtx; + vtx.Color.set(255,255,255,255); + vtx.Normal.set(0.0f,-1.f,0.0f); + + const f32 tcV = TexturePercentage / VerticalResolution; + for (k = 0, azimuth = 0; k <= HorizontalResolution; ++k) + { + f32 elevation = core::HALF_PI; + const f32 tcU = (f32)k / (f32)HorizontalResolution; + const f32 sinA = sinf(azimuth); + const f32 cosA = cosf(azimuth); + for (u32 j = 0; j <= VerticalResolution; ++j) + { + const f32 cosEr = Radius * cosf(elevation); + vtx.Pos.set(cosEr*sinA, Radius*sinf(elevation), cosEr*cosA); + vtx.TCoords.set(tcU, j*tcV); + + vtx.Normal = -vtx.Pos; + vtx.Normal.normalize(); + + Buffer->Vertices.push_back(vtx); + elevation -= elevation_step; + } + azimuth += azimuth_step; + } + + for (k = 0; k < HorizontalResolution; ++k) + { + Buffer->Indices.push_back(VerticalResolution + 2 + (VerticalResolution + 1)*k); + Buffer->Indices.push_back(1 + (VerticalResolution + 1)*k); + Buffer->Indices.push_back(0 + (VerticalResolution + 1)*k); + + for (u32 j = 1; j < VerticalResolution; ++j) + { + Buffer->Indices.push_back(VerticalResolution + 2 + (VerticalResolution + 1)*k + j); + Buffer->Indices.push_back(1 + (VerticalResolution + 1)*k + j); + Buffer->Indices.push_back(0 + (VerticalResolution + 1)*k + j); + + Buffer->Indices.push_back(VerticalResolution + 1 + (VerticalResolution + 1)*k + j); + Buffer->Indices.push_back(VerticalResolution + 2 + (VerticalResolution + 1)*k + j); + Buffer->Indices.push_back(0 + (VerticalResolution + 1)*k + j); + } + } + Buffer->setHardwareMappingHint(scene::EHM_STATIC); +} + + +//! renders the node. +void CSkyDomeSceneNode::render() +{ + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + scene::ICameraSceneNode* camera = SceneManager->getActiveCamera(); + + if (!camera || !driver) + return; + + if ( !camera->isOrthogonal() ) + { + core::matrix4 mat(AbsoluteTransformation); + mat.setTranslation(camera->getAbsolutePosition()); + + driver->setTransform(video::ETS_WORLD, mat); + + driver->setMaterial(Buffer->Material); + driver->drawMeshBuffer(Buffer); + } + + // for debug purposes only: + if ( DebugDataVisible ) + { + video::SMaterial m; + m.Lighting = false; + driver->setMaterial(m); + + if ( DebugDataVisible & scene::EDS_NORMALS ) + { + // draw normals + const f32 debugNormalLength = SceneManager->getParameters()->getAttributeAsFloat(DEBUG_NORMAL_LENGTH); + const video::SColor debugNormalColor = SceneManager->getParameters()->getAttributeAsColor(DEBUG_NORMAL_COLOR); + driver->drawMeshBufferNormals(Buffer, debugNormalLength, debugNormalColor); + } + + // show mesh + if ( DebugDataVisible & scene::EDS_MESH_WIRE_OVERLAY ) + { + m.Wireframe = true; + driver->setMaterial(m); + + driver->drawMeshBuffer(Buffer); + } + } +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CSkyDomeSceneNode::getBoundingBox() const +{ + return Buffer->BoundingBox; +} + + +void CSkyDomeSceneNode::OnRegisterSceneNode() +{ + if (IsVisible) + { + SceneManager->registerNodeForRendering(this, ESNRP_SKY_BOX ); + } + + ISceneNode::OnRegisterSceneNode(); +} + + +//! returns the material based on the zero based index i. +video::SMaterial& CSkyDomeSceneNode::getMaterial(u32 i) +{ + return Buffer->Material; +} + + +//! returns amount of materials used by this scene node. +u32 CSkyDomeSceneNode::getMaterialCount() const +{ + return 1; +} + + +//! Writes attributes of the scene node. +void CSkyDomeSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + ISceneNode::serializeAttributes(out, options); + + out->addInt ("HorizontalResolution", HorizontalResolution); + out->addInt ("VerticalResolution", VerticalResolution); + out->addFloat("TexturePercentage", TexturePercentage); + out->addFloat("SpherePercentage", SpherePercentage); + out->addFloat("Radius", Radius); +} + + +//! Reads attributes of the scene node. +void CSkyDomeSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + HorizontalResolution = in->getAttributeAsInt ("HorizontalResolution"); + VerticalResolution = in->getAttributeAsInt ("VerticalResolution"); + TexturePercentage = in->getAttributeAsFloat("TexturePercentage"); + SpherePercentage = in->getAttributeAsFloat("SpherePercentage"); + Radius = in->getAttributeAsFloat("Radius"); + + ISceneNode::deserializeAttributes(in, options); + + // regenerate the mesh + generateMesh(); +} + +//! Creates a clone of this scene node and its children. +ISceneNode* CSkyDomeSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager) +{ + if (!newParent) + newParent = Parent; + if (!newManager) + newManager = SceneManager; + + CSkyDomeSceneNode* nb = new CSkyDomeSceneNode(Buffer->Material.TextureLayer[0].Texture, HorizontalResolution, VerticalResolution, TexturePercentage, + SpherePercentage, Radius, newParent, newManager, ID); + + nb->cloneMembers(this, newManager); + + if ( newParent ) + nb->drop(); + return nb; +} + + +} // namespace scene +} // namespace irr + +#endif // _IRR_COMPILE_WITH_SKYDOME_SCENENODE_ diff --git a/source/Irrlicht/CSkyDomeSceneNode.h b/source/Irrlicht/CSkyDomeSceneNode.h new file mode 100644 index 00000000..e1a8be0a --- /dev/null +++ b/source/Irrlicht/CSkyDomeSceneNode.h @@ -0,0 +1,50 @@ +// Copyright (C) 2002-2012 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) + +#ifndef __C_SKY_DOME_SCENE_NODE_H_INCLUDED__ +#define __C_SKY_DOME_SCENE_NODE_H_INCLUDED__ + +#include "ISceneNode.h" +#include "SMeshBuffer.h" + +namespace irr +{ +namespace scene +{ + +class CSkyDomeSceneNode : public ISceneNode +{ + public: + CSkyDomeSceneNode(video::ITexture* texture, u32 horiRes, u32 vertRes, + f32 texturePercentage, f32 spherePercentage, f32 radius, + ISceneNode* parent, ISceneManager* smgr, s32 id); + virtual ~CSkyDomeSceneNode(); + virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; + virtual void render() _IRR_OVERRIDE_; + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_; + virtual u32 getMaterialCount() const _IRR_OVERRIDE_; + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_SKY_DOME; } + + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + private: + + void generateMesh(); + + SMeshBuffer* Buffer; + + u32 HorizontalResolution, VerticalResolution; + f32 TexturePercentage, SpherePercentage, Radius; +}; + + +} +} + +#endif + diff --git a/source/Irrlicht/CSoftware2MaterialRenderer.h b/source/Irrlicht/CSoftware2MaterialRenderer.h new file mode 100644 index 00000000..7a88bc2a --- /dev/null +++ b/source/Irrlicht/CSoftware2MaterialRenderer.h @@ -0,0 +1,118 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_SOFTWARE2_MATERIAL_RENDERER_H_INCLUDED__ +#define __C_SOFTWARE2_MATERIAL_RENDERER_H_INCLUDED__ + +#include "SoftwareDriver2_compile_config.h" + +#include "IMaterialRenderer.h" +#include "CSoftwareDriver2.h" + +namespace irr +{ +namespace video +{ + +//! Base class for all internal Software2 material renderers +class CSoftware2MaterialRenderer : public IMaterialRenderer +{ +public: + + //! Constructor + CSoftware2MaterialRenderer(video::CBurningVideoDriver* driver) + : Driver(driver) + { + } + +protected: + + video::CBurningVideoDriver* Driver; +}; + +//! solid material renderer +class CSoftware2MaterialRenderer_SOLID : public CSoftware2MaterialRenderer +{ +public: + CSoftware2MaterialRenderer_SOLID ( video::CBurningVideoDriver* driver ) + :CSoftware2MaterialRenderer ( driver ) {} + + //! Returns if the material is transparent. + virtual bool isTransparent() const _IRR_OVERRIDE_ + { + return false; + } + +}; + + + +//! Transparent material renderer +class CSoftware2MaterialRenderer_TRANSPARENT_ADD_COLOR : public CSoftware2MaterialRenderer +{ +public: + CSoftware2MaterialRenderer_TRANSPARENT_ADD_COLOR ( video::CBurningVideoDriver* driver ) + : CSoftware2MaterialRenderer ( driver ) {} + + + //! Returns if the material is transparent. + virtual bool isTransparent() const _IRR_OVERRIDE_ + { + return true; + } + +}; + +//! unsupported material renderer +class CSoftware2MaterialRenderer_UNSUPPORTED : public CSoftware2MaterialRenderer +{ +public: + CSoftware2MaterialRenderer_UNSUPPORTED ( video::CBurningVideoDriver* driver ) + : CSoftware2MaterialRenderer ( driver ) {} + + virtual s32 getRenderCapability() const _IRR_OVERRIDE_ { return 1; } + +}; + +//! unsupported material renderer +class CBurningShader_REFERENCE : public CSoftware2MaterialRenderer +{ +public: + CBurningShader_REFERENCE ( video::CBurningVideoDriver* driver ) + : CSoftware2MaterialRenderer ( driver ) {} + + virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_ + { + } + + virtual void OnUnsetMaterial() _IRR_OVERRIDE_ + { + } + + virtual bool isTransparent() const _IRR_OVERRIDE_ + { + return false; + } + + virtual bool OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) _IRR_OVERRIDE_ + { + return true; + }; + + + virtual s32 getRenderCapability() const _IRR_OVERRIDE_ + { + return 1; + } + +}; + + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CSoftwareDriver.cpp b/source/Irrlicht/CSoftwareDriver.cpp new file mode 100644 index 00000000..426aac29 --- /dev/null +++ b/source/Irrlicht/CSoftwareDriver.cpp @@ -0,0 +1,976 @@ +// Copyright (C) 2002-2012 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" +#include "CSoftwareDriver.h" + +#ifdef _IRR_COMPILE_WITH_SOFTWARE_ + +#include "CSoftwareTexture.h" +#include "CBlit.h" +#include "os.h" +#include "S3DVertex.h" + +namespace irr +{ +namespace video +{ + + +//! constructor +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) +{ + #ifdef _DEBUG + setDebugName("CSoftwareDriver"); + #endif + + // create backbuffer + + BackBuffer = new CImage(ECF_A1R5G5B5, windowSize); + if (BackBuffer) + { + BackBuffer->fill(SColor(0)); + + // create z buffer + ZBuffer = video::createZBuffer(BackBuffer->getDimension()); + } + + DriverAttributes->setAttribute("MaxTextures", 1); + DriverAttributes->setAttribute("MaxIndices", 1<<16); + DriverAttributes->setAttribute("MaxTextureSize", 1024); + DriverAttributes->setAttribute("Version", 1); + + // create triangle renderers + + TriangleRenderers[ETR_FLAT] = createTriangleRendererFlat(ZBuffer); + TriangleRenderers[ETR_FLAT_WIRE] = createTriangleRendererFlatWire(ZBuffer); + TriangleRenderers[ETR_GOURAUD] = createTriangleRendererGouraud(ZBuffer); + TriangleRenderers[ETR_GOURAUD_WIRE] = createTriangleRendererGouraudWire(ZBuffer); + TriangleRenderers[ETR_TEXTURE_FLAT] = createTriangleRendererTextureFlat(ZBuffer); + TriangleRenderers[ETR_TEXTURE_FLAT_WIRE] = createTriangleRendererTextureFlatWire(ZBuffer); + TriangleRenderers[ETR_TEXTURE_GOURAUD] = createTriangleRendererTextureGouraud(ZBuffer); + TriangleRenderers[ETR_TEXTURE_GOURAUD_WIRE] = createTriangleRendererTextureGouraudWire(ZBuffer); + TriangleRenderers[ETR_TEXTURE_GOURAUD_NOZ] = createTriangleRendererTextureGouraudNoZ(); + TriangleRenderers[ETR_TEXTURE_GOURAUD_ADD] = createTriangleRendererTextureGouraudAdd(ZBuffer); + + // select render target + + setRenderTargetImage(BackBuffer); + + // select the right renderer + + selectRightTriangleRenderer(); +} + + + +//! destructor +CSoftwareDriver::~CSoftwareDriver() +{ + // delete Backbuffer + if (BackBuffer) + BackBuffer->drop(); + + // delete triangle renderers + + for (s32 i=0; idrop(); + + // delete zbuffer + + if (ZBuffer) + ZBuffer->drop(); + + // delete current texture + + if (Texture) + Texture->drop(); + + if (RenderTargetTexture) + RenderTargetTexture->drop(); + + if (RenderTargetSurface) + RenderTargetSurface->drop(); +} + + + +//! switches to a triangle renderer +void CSoftwareDriver::switchToTriangleRenderer(ETriangleRenderer renderer) +{ + video::IImage* s = 0; + if (Texture) + s = ((CSoftwareTexture*)Texture)->getTexture(); + + CurrentTriangleRenderer = TriangleRenderers[renderer]; + CurrentTriangleRenderer->setBackfaceCulling(Material.BackfaceCulling == true); + CurrentTriangleRenderer->setTexture(s); + CurrentTriangleRenderer->setRenderTarget(RenderTargetSurface, ViewPort); +} + + +//! void selects the right triangle renderer based on the render states. +void CSoftwareDriver::selectRightTriangleRenderer() +{ + + ETriangleRenderer renderer = ETR_FLAT; + + if (Texture) + { + if (!Material.GouraudShading) + renderer = (!Material.Wireframe) ? ETR_TEXTURE_FLAT : ETR_TEXTURE_FLAT_WIRE; + else + { + if (Material.Wireframe) + renderer = ETR_TEXTURE_GOURAUD_WIRE; + else + { + if (Material.MaterialType == EMT_TRANSPARENT_ADD_COLOR || + Material.MaterialType == EMT_TRANSPARENT_ALPHA_CHANNEL || + Material.MaterialType == EMT_TRANSPARENT_VERTEX_ALPHA) + { + // simply draw all transparent stuff with the same renderer. at + // least it is transparent then. + renderer = ETR_TEXTURE_GOURAUD_ADD; + } + else + if ((Material.ZBuffer==ECFN_DISABLED) && Material.ZWriteEnable == video::EZW_OFF) + renderer = ETR_TEXTURE_GOURAUD_NOZ; + else + { + renderer = ETR_TEXTURE_GOURAUD; + } + } + } + } + else + { + if (!Material.GouraudShading) + renderer = (!Material.Wireframe) ? ETR_FLAT : ETR_FLAT_WIRE; + else + renderer = (!Material.Wireframe) ? ETR_GOURAUD : ETR_GOURAUD_WIRE; + } + + switchToTriangleRenderer(renderer); +} + + +//! queries the features of the driver, returns true if feature is available +bool CSoftwareDriver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const +{ + switch (feature) + { + case EVDF_RENDER_TO_TARGET: + case EVDF_TEXTURE_NSQUARE: + return FeatureEnabled[feature]; + default: + return false; + }; +} + + +//! Create render target. +IRenderTarget* CSoftwareDriver::addRenderTarget() +{ + CSoftwareRenderTarget* renderTarget = new CSoftwareRenderTarget(this); + RenderTargets.push_back(renderTarget); + + return renderTarget; +} + + +//! sets transformation +void CSoftwareDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) +{ + TransformationMatrix[state] = mat; +} + + +//! sets the current Texture +bool CSoftwareDriver::setActiveTexture(u32 stage, video::ITexture* texture) +{ + if (texture && texture->getDriverType() != EDT_SOFTWARE) + { + os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR); + return false; + } + + if (Texture) + Texture->drop(); + + Texture = texture; + + if (Texture) + Texture->grab(); + + selectRightTriangleRenderer(); + return true; +} + + +//! sets a material +void CSoftwareDriver::setMaterial(const SMaterial& material) +{ + Material = material; + OverrideMaterial.apply(Material); + + for (u32 i = 0; i < 1; ++i) + { + setActiveTexture(i, Material.getTexture(i)); + setTransform ((E_TRANSFORMATION_STATE) ( ETS_TEXTURE_0 + i ), + material.getTextureMatrix(i)); + } +} + +bool CSoftwareDriver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil, const SExposedVideoData& videoData, core::rect* sourceRect) +{ + CNullDriver::beginScene(clearFlag, clearColor, clearDepth, clearStencil, videoData, sourceRect); + WindowId=videoData.D3D9.HWnd; + SceneSourceRect = sourceRect; + + clearBuffers(clearFlag, clearColor, clearDepth, clearStencil); + + return true; +} + +bool CSoftwareDriver::endScene() +{ + CNullDriver::endScene(); + + return Presenter->present(BackBuffer, WindowId, SceneSourceRect); +} + +ITexture* CSoftwareDriver::createDeviceDependentTexture(const io::path& name, IImage* image) +{ + CSoftwareTexture* texture = new CSoftwareTexture(image, name, false); + + return texture; +} + +ITexture* CSoftwareDriver::createDeviceDependentTextureCubemap(const io::path& name, const core::array& image) +{ + return 0; +} + +bool CSoftwareDriver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil) +{ + if (target && target->getDriverType() != EDT_SOFTWARE) + { + os::Printer::log("Fatal Error: Tried to set a render target not owned by this driver.", ELL_ERROR); + return false; + } + + if (RenderTargetTexture) + RenderTargetTexture->drop(); + + CSoftwareRenderTarget* renderTarget = static_cast(target); + RenderTargetTexture = (renderTarget) ? renderTarget->getTexture() : 0; + + if (RenderTargetTexture) + { + RenderTargetTexture->grab(); + setRenderTargetImage(((CSoftwareTexture*)RenderTargetTexture)->getTexture()); + } + else + { + setRenderTargetImage(BackBuffer); + } + + clearBuffers(clearFlag, clearColor, clearDepth, clearStencil); + + return true; +} + + +//! sets a render target +void CSoftwareDriver::setRenderTargetImage(video::CImage* image) +{ + if (RenderTargetSurface) + RenderTargetSurface->drop(); + + RenderTargetSurface = image; + RenderTargetSize.Width = 0; + RenderTargetSize.Height = 0; + Render2DTranslation.X = 0; + Render2DTranslation.Y = 0; + + if (RenderTargetSurface) + { + RenderTargetSurface->grab(); + RenderTargetSize = RenderTargetSurface->getDimension(); + } + + setViewPort(core::rect(0,0,RenderTargetSize.Width,RenderTargetSize.Height)); + + if (ZBuffer) + ZBuffer->setSize(RenderTargetSize); +} + + +//! sets a viewport +void CSoftwareDriver::setViewPort(const core::rect& area) +{ + ViewPort = area; + + //TODO: the clipping is not correct, because the projection is affected. + // to correct this, ViewPortSize and Render2DTranslation will have to be corrected. + core::rect rendert(0,0,RenderTargetSize.Width,RenderTargetSize.Height); + ViewPort.clipAgainst(rendert); + + 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; + + if (CurrentTriangleRenderer) + CurrentTriangleRenderer->setRenderTarget(RenderTargetSurface, ViewPort); +} + + +void CSoftwareDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) + +{ + switch (iType) + { + case (EIT_16BIT): + { + drawVertexPrimitiveList16(vertices, vertexCount, (const u16*)indexList, primitiveCount, vType, pType); + break; + } + case (EIT_32BIT): + { + os::Printer::log("Software driver can not render 32bit buffers", ELL_ERROR); + break; + } + } +} + + +//! draws a vertex primitive list +void CSoftwareDriver::drawVertexPrimitiveList16(const void* vertices, u32 vertexCount, const u16* indexList, u32 primitiveCount, E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType) +{ + const u16* indexPointer=0; + core::array newBuffer; + switch (pType) + { + case scene::EPT_LINE_STRIP: + { + switch (vType) + { + case EVT_STANDARD: + { + for (u32 i=0; i < primitiveCount-1; ++i) + draw3DLine(((S3DVertex*)vertices)[indexList[i]].Pos, + ((S3DVertex*)vertices)[indexList[i+1]].Pos, + ((S3DVertex*)vertices)[indexList[i]].Color); + } + break; + case EVT_2TCOORDS: + { + for (u32 i=0; i < primitiveCount-1; ++i) + draw3DLine(((S3DVertex2TCoords*)vertices)[indexList[i]].Pos, + ((S3DVertex2TCoords*)vertices)[indexList[i+1]].Pos, + ((S3DVertex2TCoords*)vertices)[indexList[i]].Color); + } + break; + case EVT_TANGENTS: + { + for (u32 i=0; i < primitiveCount-1; ++i) + draw3DLine(((S3DVertexTangents*)vertices)[indexList[i]].Pos, + ((S3DVertexTangents*)vertices)[indexList[i+1]].Pos, + ((S3DVertexTangents*)vertices)[indexList[i]].Color); + } + break; + } + } + return; + case scene::EPT_LINE_LOOP: + drawVertexPrimitiveList16(vertices, vertexCount, indexList, primitiveCount-1, vType, scene::EPT_LINE_STRIP); + switch (vType) + { + case EVT_STANDARD: + draw3DLine(((S3DVertex*)vertices)[indexList[primitiveCount-1]].Pos, + ((S3DVertex*)vertices)[indexList[0]].Pos, + ((S3DVertex*)vertices)[indexList[primitiveCount-1]].Color); + break; + case EVT_2TCOORDS: + draw3DLine(((S3DVertex2TCoords*)vertices)[indexList[primitiveCount-1]].Pos, + ((S3DVertex2TCoords*)vertices)[indexList[0]].Pos, + ((S3DVertex2TCoords*)vertices)[indexList[primitiveCount-1]].Color); + break; + case EVT_TANGENTS: + draw3DLine(((S3DVertexTangents*)vertices)[indexList[primitiveCount-1]].Pos, + ((S3DVertexTangents*)vertices)[indexList[0]].Pos, + ((S3DVertexTangents*)vertices)[indexList[primitiveCount-1]].Color); + break; + } + return; + case scene::EPT_LINES: + { + switch (vType) + { + case EVT_STANDARD: + { + for (u32 i=0; i < 2*primitiveCount; i+=2) + draw3DLine(((S3DVertex*)vertices)[indexList[i]].Pos, + ((S3DVertex*)vertices)[indexList[i+1]].Pos, + ((S3DVertex*)vertices)[indexList[i]].Color); + } + break; + case EVT_2TCOORDS: + { + for (u32 i=0; i < 2*primitiveCount; i+=2) + draw3DLine(((S3DVertex2TCoords*)vertices)[indexList[i]].Pos, + ((S3DVertex2TCoords*)vertices)[indexList[i+1]].Pos, + ((S3DVertex2TCoords*)vertices)[indexList[i]].Color); + } + break; + case EVT_TANGENTS: + { + for (u32 i=0; i < 2*primitiveCount; i+=2) + draw3DLine(((S3DVertexTangents*)vertices)[indexList[i]].Pos, + ((S3DVertexTangents*)vertices)[indexList[i+1]].Pos, + ((S3DVertexTangents*)vertices)[indexList[i]].Color); + } + break; + } + } + return; + case scene::EPT_TRIANGLE_FAN: + { + // TODO: don't convert fan to list + newBuffer.reallocate(primitiveCount*3); + for( u32 t=0; t +void CSoftwareDriver::drawClippedIndexedTriangleListT(const VERTEXTYPE* vertices, + s32 vertexCount, const u16* indexList, s32 triangleCount) +{ + if (!RenderTargetSurface || !ZBuffer || !triangleCount) + return; + + if (!checkPrimitiveCount(triangleCount)) + return; + + // arrays for storing clipped vertices + core::array clippedVertices; + core::array clippedIndices; + + // calculate inverse world transformation + core::matrix4 worldinv(TransformationMatrix[ETS_WORLD]); + worldinv.makeInverse(); + + // calculate view frustum planes + scene::SViewFrustum frustum(TransformationMatrix[ETS_PROJECTION] * TransformationMatrix[ETS_VIEW], true); + + // copy and transform clipping planes ignoring far plane + core::plane3df planes[5]; // ordered by near, left, right, bottom, top + for (int p=0; p<5; ++p) + worldinv.transformPlane(frustum.planes[p+1], planes[p]); + + core::EIntersectionRelation3D inout[3]; // is point in front or back of plane? + + // temporary buffer for vertices to be clipped by all planes + core::array tClpBuf; + int t; + + int i; + for (i=0; i textureSize(0,0); + f32 zDiv; + + if (Texture) + textureSize = ((CSoftwareTexture*)Texture)->getTexture()->getDimension(); + + f32 transformedPos[4]; // transform all points in the list + + core::matrix4 matrix(TransformationMatrix[ETS_PROJECTION]); + matrix *= TransformationMatrix[ETS_VIEW]; + matrix *= TransformationMatrix[ETS_WORLD]; + + s32 ViewTransformWidth = (ViewPortSize.Width>>1); + s32 ViewTransformHeight = (ViewPortSize.Height>>1); + + for (i=0; i<(int)clippedVertices.size(); ++i) + { + transformedPos[0] = currentVertex->Pos.X; + transformedPos[1] = currentVertex->Pos.Y; + transformedPos[2] = currentVertex->Pos.Z; + transformedPos[3] = 1.0f; + + matrix.multiplyWith1x4Matrix(transformedPos); + zDiv = transformedPos[3] == 0.0f ? 1.0f : (1.0f / transformedPos[3]); + + tp->Pos.X = (s32)(ViewTransformWidth * (transformedPos[0] * zDiv) + (Render2DTranslation.X)); + tp->Pos.Y = (Render2DTranslation.Y - (s32)(ViewTransformHeight * (transformedPos[1] * zDiv))); + tp->Color = currentVertex->Color.toA1R5G5B5(); + tp->ZValue = (TZBufferType)(32767.0f * zDiv); + + tp->TCoords.X = (s32)(currentVertex->TCoords.X * textureSize.Width); + tp->TCoords.X <<= 8; + tp->TCoords.Y = (s32)(currentVertex->TCoords.Y * textureSize.Height); + tp->TCoords.Y <<= 8; + + ++currentVertex; + ++tp; + } + + // draw all transformed points from the index list + CurrentTriangleRenderer->drawIndexedTriangleList(&TransformedPoints[0], + clippedVertices.size(), clippedIndices.pointer(), clippedIndices.size()/3); +} + + +//! Draws a 3d line. +void CSoftwareDriver::draw3DLine(const core::vector3df& start, + const core::vector3df& end, SColor color) +{ + core::vector3df vect = start.crossProduct(end); + vect.normalize(); + vect *= Material.Thickness*0.3f; + + S3DVertex vtx[4]; + + vtx[0].Color = color; + vtx[1].Color = color; + vtx[2].Color = color; + vtx[3].Color = color; + + vtx[0].Pos = start; + vtx[1].Pos = end; + + vtx[2].Pos = start + vect; + vtx[3].Pos = end + vect; + + u16 idx[12] = {0,1,2, 0,2,1, 0,1,3, 0,3,1}; + + drawIndexedTriangleList(vtx, 4, idx, 4); +} + + +//! clips a triangle against the viewing frustum +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) +{ + // make sure width and height are multiples of 2 + core::dimension2d realSize(size); + + if (realSize.Width % 2) + realSize.Width += 1; + + if (realSize.Height % 2) + realSize.Height += 1; + + if (ScreenSize != realSize) + { + if (ViewPort.getWidth() == (s32)ScreenSize.Width && + ViewPort.getHeight() == (s32)ScreenSize.Height) + { + ViewPort = core::rect(core::position2d(0,0), + core::dimension2di(realSize)); + } + + ScreenSize = realSize; + + bool resetRT = (RenderTargetSurface == BackBuffer); + + if (BackBuffer) + BackBuffer->drop(); + BackBuffer = new CImage(ECF_A1R5G5B5, realSize); + + if (resetRT) + setRenderTargetImage(BackBuffer); + } +} + +//! returns the current render target size +const core::dimension2d& CSoftwareDriver::getCurrentRenderTargetSize() const +{ + return RenderTargetSize; +} + + +//! 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. +void CSoftwareDriver::draw2DImage(const video::ITexture* texture, const core::position2d& destPos, + const core::rect& sourceRect, + const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture) +{ + if (texture) + { + if (texture->getDriverType() != EDT_SOFTWARE) + { + os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR); + return; + } + + if (useAlphaChannelOfTexture) + ((CSoftwareTexture*)texture)->getImage()->copyToWithAlpha( + RenderTargetSurface, destPos, sourceRect, color, clipRect); + else + ((CSoftwareTexture*)texture)->getImage()->copyTo( + RenderTargetSurface, destPos, sourceRect, clipRect); + } +} + + + +//! Draws a 2d line. +void CSoftwareDriver::draw2DLine(const core::position2d& start, + const core::position2d& end, + SColor color) +{ + drawLine(RenderTargetSurface, start, end, color ); +} + + +//! Draws a pixel +void CSoftwareDriver::drawPixel(u32 x, u32 y, const SColor & color) +{ + BackBuffer->setPixel(x, y, color, true); +} + + +//! draw a 2d rectangle +void CSoftwareDriver::draw2DRectangle(SColor color, const core::rect& pos, + const core::rect* clip) +{ + if (clip) + { + core::rect p(pos); + + p.clipAgainst(*clip); + + if(!p.isValid()) + return; + + drawRectangle(RenderTargetSurface, p, color); + } + else + { + if(!pos.isValid()) + return; + + drawRectangle(RenderTargetSurface, pos, color); + } +} + + +//!Draws an 2d rectangle with a gradient. +void CSoftwareDriver::draw2DRectangle(const core::rect& pos, + SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, + const core::rect* clip) +{ + // TODO: implement + draw2DRectangle(colorLeftUp, pos, clip); +} + + +//! \return Returns the name of the video driver. Example: In case of the Direct3D8 +//! driver, it would return "Direct3D8.1". +const wchar_t* CSoftwareDriver::getName() const +{ + return L"Irrlicht Software Driver 1.0"; +} + + +//! Returns type of video driver +E_DRIVER_TYPE CSoftwareDriver::getDriverType() const +{ + return EDT_SOFTWARE; +} + + +//! returns color format +ECOLOR_FORMAT CSoftwareDriver::getColorFormat() const +{ + if (BackBuffer) + return BackBuffer->getColorFormat(); + else + return CNullDriver::getColorFormat(); +} + + +//! Returns the transformation set by setTransform +const core::matrix4& CSoftwareDriver::getTransform(E_TRANSFORMATION_STATE state) const +{ + return TransformationMatrix[state]; +} + + +//! Creates a render target texture. +ITexture* CSoftwareDriver::addRenderTargetTexture(const core::dimension2d& size, + const io::path& name, + const ECOLOR_FORMAT format) +{ + IImage* img = createImage(video::ECF_A1R5G5B5, size); + ITexture* tex = new CSoftwareTexture(img, name, true); + img->drop(); + addTexture(tex); + tex->drop(); + return tex; +} + +void CSoftwareDriver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil) +{ + if ((flag & ECBF_COLOR) && RenderTargetSurface) + RenderTargetSurface->fill(color); + + if ((flag & ECBF_DEPTH) && ZBuffer) + ZBuffer->clear(); +} + + +//! Returns an image created from the last rendered frame. +IImage* CSoftwareDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target) +{ + if (target != video::ERT_FRAME_BUFFER) + return 0; + + if (BackBuffer) + { + IImage* tmp = createImage(BackBuffer->getColorFormat(), BackBuffer->getDimension()); + BackBuffer->copyTo(tmp); + return tmp; + } + else + return 0; +} + + +//! Returns the maximum amount of primitives (mostly vertices) which +//! the device is able to render with one drawIndexedTriangleList +//! call. +u32 CSoftwareDriver::getMaximalPrimitiveCount() const +{ + return 0x00800000; +} + +bool CSoftwareDriver::queryTextureFormat(ECOLOR_FORMAT format) const +{ + return format == ECF_A1R5G5B5; +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + + +//! creates a video driver +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); + #else + return 0; + #endif +} + + +} // end namespace video +} // end namespace irr + diff --git a/source/Irrlicht/CSoftwareDriver.h b/source/Irrlicht/CSoftwareDriver.h new file mode 100644 index 00000000..c816142e --- /dev/null +++ b/source/Irrlicht/CSoftwareDriver.h @@ -0,0 +1,180 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_VIDEO_SOFTWARE_H_INCLUDED__ +#define __C_VIDEO_SOFTWARE_H_INCLUDED__ + +#include "ITriangleRenderer.h" +#include "CNullDriver.h" +#include "SViewFrustum.h" +#include "CImage.h" + +namespace irr +{ +namespace video +{ + class CSoftwareDriver : public CNullDriver + { + public: + + //! constructor + CSoftwareDriver(const core::dimension2d& windowSize, bool fullscreen, io::IFileSystem* io, video::IImagePresenter* presenter); + + //! destructor + virtual ~CSoftwareDriver(); + + //! queries the features of the driver, returns true if feature is available + virtual bool queryFeature(E_VIDEO_DRIVER_FEATURE feature) const _IRR_OVERRIDE_; + + //! Create render target. + virtual IRenderTarget* addRenderTarget() _IRR_OVERRIDE_; + + //! sets transformation + virtual void setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) _IRR_OVERRIDE_; + + //! sets a material + virtual void setMaterial(const SMaterial& material) _IRR_OVERRIDE_; + + virtual bool setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor = SColor(255,0,0,0), + f32 clearDepth = 1.f, u8 clearStencil = 0) _IRR_OVERRIDE_; + + //! sets a viewport + virtual void setViewPort(const core::rect& area) _IRR_OVERRIDE_; + + virtual bool beginScene(u16 clearFlag, SColor clearColor = SColor(255,0,0,0), f32 clearDepth = 1.f, u8 clearStencil = 0, + const SExposedVideoData& videoData = SExposedVideoData(), core::rect* sourceRect = 0) _IRR_OVERRIDE_; + + virtual bool endScene() _IRR_OVERRIDE_; + + //! Only used by the internal engine. Used to notify the driver that + //! the window was resized. + virtual void OnResize(const core::dimension2d& size) _IRR_OVERRIDE_; + + //! returns size of the current render target + virtual const core::dimension2d& getCurrentRenderTargetSize() const _IRR_OVERRIDE_; + + //! draws a vertex primitive list + virtual void drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) _IRR_OVERRIDE_; + + //! Draws a 3d line. + virtual void draw3DLine(const core::vector3df& start, + const core::vector3df& end, SColor color = SColor(255,255,255,255)) _IRR_OVERRIDE_; + + //! 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. + 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) _IRR_OVERRIDE_; + + //! draw an 2d rectangle + virtual void draw2DRectangle(SColor color, const core::rect& pos, + const core::rect* clip = 0) _IRR_OVERRIDE_; + + //!Draws an 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) _IRR_OVERRIDE_; + + //! Draws a 2d line. + virtual void draw2DLine(const core::position2d& start, + const core::position2d& end, + SColor color=SColor(255,255,255,255)) _IRR_OVERRIDE_; + + //! Draws a single pixel + virtual void drawPixel(u32 x, u32 y, const SColor & color) _IRR_OVERRIDE_; + + //! \return Returns the name of the video driver. Example: In case of the Direct3D8 + //! driver, it would return "Direct3D8.1". + virtual const wchar_t* getName() const _IRR_OVERRIDE_; + + //! Returns type of video driver + virtual E_DRIVER_TYPE getDriverType() const _IRR_OVERRIDE_; + + //! get color format of the current color buffer + virtual ECOLOR_FORMAT getColorFormat() const _IRR_OVERRIDE_; + + //! Returns the transformation set by setTransform + virtual const core::matrix4& getTransform(E_TRANSFORMATION_STATE state) const _IRR_OVERRIDE_; + + virtual ITexture* createDeviceDependentTexture(const io::path& name, IImage* image) _IRR_OVERRIDE_; + virtual ITexture* createDeviceDependentTextureCubemap(const io::path& name, const core::array& image) _IRR_OVERRIDE_; + + //! Creates a render target texture. + virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, + const io::path& name, const ECOLOR_FORMAT format = ECF_UNKNOWN) _IRR_OVERRIDE_; + + virtual void clearBuffers(u16 flag, SColor color = SColor(255,0,0,0), f32 depth = 1.f, u8 stencil = 0) _IRR_OVERRIDE_; + + //! Returns an image created from the last rendered frame. + virtual IImage* createScreenShot(video::ECOLOR_FORMAT format=video::ECF_UNKNOWN, video::E_RENDER_TARGET target=video::ERT_FRAME_BUFFER) _IRR_OVERRIDE_; + + //! Returns the maximum amount of primitives (mostly vertices) which + //! the device is able to render with one drawIndexedTriangleList + //! call. + virtual u32 getMaximalPrimitiveCount() const _IRR_OVERRIDE_; + + //! Check if the driver supports creating textures with the given color format + virtual bool queryTextureFormat(ECOLOR_FORMAT format) const _IRR_OVERRIDE_; + + protected: + + //! sets a render target + void setRenderTargetImage(video::CImage* image); + + //! sets the current Texture + bool setActiveTexture(u32 stage, video::ITexture* texture); + + //! switches to a triangle renderer + void switchToTriangleRenderer(ETriangleRenderer renderer); + + //! void selects the right triangle renderer based on the render states. + void selectRightTriangleRenderer(); + + //! clips a triangle agains the viewing frustum + void clipTriangle(f32* transformedPos); + + + //! draws a vertex primitive list + void drawVertexPrimitiveList16(const void* vertices, u32 vertexCount, + const u16* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType); + + + template + void drawClippedIndexedTriangleListT(const VERTEXTYPE* vertices, + s32 vertexCount, const u16* indexList, s32 triangleCount); + + video::CImage* BackBuffer; + video::IImagePresenter* Presenter; + void* WindowId; + core::rect* SceneSourceRect; + + core::array TransformedPoints; + + video::ITexture* RenderTargetTexture; + video::CImage* RenderTargetSurface; + core::position2d Render2DTranslation; + core::dimension2d RenderTargetSize; + core::dimension2d ViewPortSize; + + core::matrix4 TransformationMatrix[ETS_COUNT]; + + ITriangleRenderer* CurrentTriangleRenderer; + ITriangleRenderer* TriangleRenderers[ETR_COUNT]; + ETriangleRenderer CurrentRenderer; + + IZBuffer* ZBuffer; + + video::ITexture* Texture; + + SMaterial Material; + }; + +} // end namespace video +} // end namespace irr + + +#endif + diff --git a/source/Irrlicht/CSoftwareDriver2.cpp b/source/Irrlicht/CSoftwareDriver2.cpp new file mode 100644 index 00000000..8b514c9d --- /dev/null +++ b/source/Irrlicht/CSoftwareDriver2.cpp @@ -0,0 +1,2463 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "CSoftwareDriver2.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +#include "SoftwareDriver2_helper.h" +#include "CSoftwareTexture2.h" +#include "CSoftware2MaterialRenderer.h" +#include "S3DVertex.h" +#include "S4DVertex.h" +#include "CBlit.h" + + +#define MAT_TEXTURE(tex) ( (video::CSoftwareTexture2*) Material.org.getTexture ( tex ) ) + + +namespace irr +{ +namespace video +{ + +//! constructor +CBurningVideoDriver::CBurningVideoDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, video::IImagePresenter* presenter) +: CNullDriver(io, params.WindowSize), BackBuffer(0), Presenter(presenter), + WindowId(0), SceneSourceRect(0), + RenderTargetTexture(0), RenderTargetSurface(0), CurrentShader(0), + DepthBuffer(0), StencilBuffer ( 0 ), + CurrentOut ( 16 * 2, 256 ), Temp ( 16 * 2, 256 ) +{ + #ifdef _DEBUG + setDebugName("CBurningVideoDriver"); + #endif + + // create backbuffer + BackBuffer = new CImage(BURNINGSHADER_COLOR_FORMAT, params.WindowSize); + if (BackBuffer) + { + BackBuffer->fill(SColor(0)); + + // create z buffer + if ( params.ZBufferBits ) + DepthBuffer = video::createDepthBuffer(BackBuffer->getDimension()); + + // create stencil buffer + if ( params.Stencilbuffer ) + StencilBuffer = video::createStencilBuffer(BackBuffer->getDimension()); + } + + DriverAttributes->setAttribute("MaxTextures", 2); + DriverAttributes->setAttribute("MaxIndices", 1<<16); + DriverAttributes->setAttribute("MaxTextureSize", SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE); + DriverAttributes->setAttribute("MaxLights", 1024 ); //glsl::gl_MaxLights); + DriverAttributes->setAttribute("MaxTextureLODBias", 16.f); + DriverAttributes->setAttribute("Version", 49); + + // create triangle renderers + + irr::memset32 ( BurningShader, 0, sizeof ( BurningShader ) ); + //BurningShader[ETR_FLAT] = createTRFlat2(DepthBuffer); + //BurningShader[ETR_FLAT_WIRE] = createTRFlatWire2(DepthBuffer); + BurningShader[ETR_GOURAUD] = createTriangleRendererGouraud2(this); + BurningShader[ETR_GOURAUD_ALPHA] = createTriangleRendererGouraudAlpha2(this ); + BurningShader[ETR_GOURAUD_ALPHA_NOZ] = createTRGouraudAlphaNoZ2(this ); + //BurningShader[ETR_GOURAUD_WIRE] = createTriangleRendererGouraudWire2(DepthBuffer); + //BurningShader[ETR_TEXTURE_FLAT] = createTriangleRendererTextureFlat2(DepthBuffer); + //BurningShader[ETR_TEXTURE_FLAT_WIRE] = createTriangleRendererTextureFlatWire2(DepthBuffer); + BurningShader[ETR_TEXTURE_GOURAUD] = createTriangleRendererTextureGouraud2(this); + BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_M1] = createTriangleRendererTextureLightMap2_M1(this); + BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_M2] = createTriangleRendererTextureLightMap2_M2(this); + BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_M4] = createTriangleRendererGTextureLightMap2_M4(this); + BurningShader[ETR_TEXTURE_LIGHTMAP_M4] = createTriangleRendererTextureLightMap2_M4(this); + BurningShader[ETR_TEXTURE_GOURAUD_LIGHTMAP_ADD] = createTriangleRendererTextureLightMap2_Add(this); + BurningShader[ETR_TEXTURE_GOURAUD_DETAIL_MAP] = createTriangleRendererTextureDetailMap2(this); + + BurningShader[ETR_TEXTURE_GOURAUD_WIRE] = createTriangleRendererTextureGouraudWire2(this); + BurningShader[ETR_TEXTURE_GOURAUD_NOZ] = createTRTextureGouraudNoZ2(this); + BurningShader[ETR_TEXTURE_GOURAUD_ADD] = createTRTextureGouraudAdd2(this); + BurningShader[ETR_TEXTURE_GOURAUD_ADD_NO_Z] = createTRTextureGouraudAddNoZ2(this); + BurningShader[ETR_TEXTURE_GOURAUD_VERTEX_ALPHA] = createTriangleRendererTextureVertexAlpha2 ( this ); + + BurningShader[ETR_TEXTURE_GOURAUD_ALPHA] = createTRTextureGouraudAlpha(this ); + BurningShader[ETR_TEXTURE_GOURAUD_ALPHA_NOZ] = createTRTextureGouraudAlphaNoZ( this ); + + BurningShader[ETR_NORMAL_MAP_SOLID] = createTRNormalMap ( this ); + BurningShader[ETR_STENCIL_SHADOW] = createTRStencilShadow ( this ); + BurningShader[ETR_TEXTURE_BLEND] = createTRTextureBlend( this ); + + BurningShader[ETR_REFERENCE] = createTriangleRendererReference ( this ); + + + // add the same renderer for all solid types + CSoftware2MaterialRenderer_SOLID* smr = new CSoftware2MaterialRenderer_SOLID( this); + CSoftware2MaterialRenderer_TRANSPARENT_ADD_COLOR* tmr = new CSoftware2MaterialRenderer_TRANSPARENT_ADD_COLOR( this); + CSoftware2MaterialRenderer_UNSUPPORTED * umr = new CSoftware2MaterialRenderer_UNSUPPORTED ( this ); + + //!TODO: addMaterialRenderer depends on pushing order.... + addMaterialRenderer ( smr ); // EMT_SOLID + addMaterialRenderer ( smr ); // EMT_SOLID_2_LAYER, + addMaterialRenderer ( smr ); // EMT_LIGHTMAP, + addMaterialRenderer ( tmr ); // EMT_LIGHTMAP_ADD, + addMaterialRenderer ( smr ); // EMT_LIGHTMAP_M2, + addMaterialRenderer ( smr ); // EMT_LIGHTMAP_M4, + addMaterialRenderer ( smr ); // EMT_LIGHTMAP_LIGHTING, + addMaterialRenderer ( smr ); // EMT_LIGHTMAP_LIGHTING_M2, + addMaterialRenderer ( smr ); // EMT_LIGHTMAP_LIGHTING_M4, + addMaterialRenderer ( smr ); // EMT_DETAIL_MAP, + addMaterialRenderer ( umr ); // EMT_SPHERE_MAP, + addMaterialRenderer ( smr ); // EMT_REFLECTION_2_LAYER, + addMaterialRenderer ( tmr ); // EMT_TRANSPARENT_ADD_COLOR, + addMaterialRenderer ( tmr ); // EMT_TRANSPARENT_ALPHA_CHANNEL, + addMaterialRenderer ( tmr ); // EMT_TRANSPARENT_ALPHA_CHANNEL_REF, + addMaterialRenderer ( tmr ); // EMT_TRANSPARENT_VERTEX_ALPHA, + addMaterialRenderer ( smr ); // EMT_TRANSPARENT_REFLECTION_2_LAYER, + addMaterialRenderer ( smr ); // EMT_NORMAL_MAP_SOLID, + addMaterialRenderer ( umr ); // EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR, + addMaterialRenderer ( tmr ); // EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA, + addMaterialRenderer ( smr ); // EMT_PARALLAX_MAP_SOLID, + addMaterialRenderer ( tmr ); // EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR, + addMaterialRenderer ( tmr ); // EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA, + addMaterialRenderer ( tmr ); // EMT_ONETEXTURE_BLEND + + smr->drop (); + tmr->drop (); + umr->drop (); + + // select render target + setRenderTargetImage(BackBuffer); + + //reset Lightspace + LightSpace.reset (); + + // select the right renderer + setCurrentShader(); +} + + +//! destructor +CBurningVideoDriver::~CBurningVideoDriver() +{ + // delete Backbuffer + if (BackBuffer) + BackBuffer->drop(); + + // delete triangle renderers + + for (s32 i=0; idrop(); + } + + // delete Additional buffer + if (StencilBuffer) + StencilBuffer->drop(); + + if (DepthBuffer) + DepthBuffer->drop(); + + if (RenderTargetTexture) + RenderTargetTexture->drop(); + + if (RenderTargetSurface) + RenderTargetSurface->drop(); +} + + +/*! + selects the right triangle renderer based on the render states. +*/ +void CBurningVideoDriver::setCurrentShader() +{ + ITexture *texture0 = Material.org.getTexture(0); + ITexture *texture1 = Material.org.getTexture(1); + + bool zMaterialTest = Material.org.ZBuffer != ECFN_DISABLED && + Material.org.ZWriteEnable != video::EZW_OFF && + ( AllowZWriteOnTransparent || !Material.org.isTransparent() ); + + EBurningFFShader shader = zMaterialTest ? ETR_TEXTURE_GOURAUD : ETR_TEXTURE_GOURAUD_NOZ; + + TransformationFlag[ ETS_TEXTURE_0] &= ~(ETF_TEXGEN_CAMERA_NORMAL|ETF_TEXGEN_CAMERA_REFLECTION); + LightSpace.Flags &= ~VERTEXTRANSFORM; + + switch ( Material.org.MaterialType ) + { + case EMT_ONETEXTURE_BLEND: + shader = ETR_TEXTURE_BLEND; + break; + + case EMT_TRANSPARENT_ALPHA_CHANNEL_REF: + Material.org.MaterialTypeParam = 0.5f; + // fall through + case EMT_TRANSPARENT_ALPHA_CHANNEL: + if ( texture0 && texture0->hasAlpha () ) + { + shader = zMaterialTest ? ETR_TEXTURE_GOURAUD_ALPHA : ETR_TEXTURE_GOURAUD_ALPHA_NOZ; + break; + } + else + { + shader = ETR_TEXTURE_GOURAUD_VERTEX_ALPHA; + } + break; + + case EMT_TRANSPARENT_ADD_COLOR: + shader = zMaterialTest ? ETR_TEXTURE_GOURAUD_ADD : ETR_TEXTURE_GOURAUD_ADD_NO_Z; + break; + + case EMT_TRANSPARENT_VERTEX_ALPHA: + shader = ETR_TEXTURE_GOURAUD_VERTEX_ALPHA; + break; + + case EMT_LIGHTMAP: + case EMT_LIGHTMAP_LIGHTING: + shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M1; + break; + + case EMT_LIGHTMAP_M2: + case EMT_LIGHTMAP_LIGHTING_M2: + shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M2; + break; + + case EMT_LIGHTMAP_LIGHTING_M4: + if ( texture1 ) + shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M4; + break; + case EMT_LIGHTMAP_M4: + if ( texture1 ) + shader = ETR_TEXTURE_LIGHTMAP_M4; + break; + + case EMT_LIGHTMAP_ADD: + if ( texture1 ) + shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_ADD; + break; + + case EMT_DETAIL_MAP: + if ( texture1 ) + shader = ETR_TEXTURE_GOURAUD_DETAIL_MAP; + break; + + case EMT_SPHERE_MAP: + TransformationFlag[ ETS_TEXTURE_0] |= ETF_TEXGEN_CAMERA_REFLECTION; // ETF_TEXGEN_CAMERA_NORMAL; + LightSpace.Flags |= VERTEXTRANSFORM; + break; + case EMT_REFLECTION_2_LAYER: + shader = ETR_TEXTURE_GOURAUD_LIGHTMAP_M1; + TransformationFlag[ ETS_TEXTURE_1] |= ETF_TEXGEN_CAMERA_REFLECTION; + LightSpace.Flags |= VERTEXTRANSFORM; + break; + + case EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA: + case EMT_NORMAL_MAP_SOLID: + case EMT_PARALLAX_MAP_SOLID: + case EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA: + shader = ETR_NORMAL_MAP_SOLID; + LightSpace.Flags |= VERTEXTRANSFORM; + break; + + default: + break; + + } + + if ( !texture0 ) + { + shader = ETR_GOURAUD; + } + + if ( Material.org.Wireframe ) + { + shader = ETR_TEXTURE_GOURAUD_WIRE; + } + + //shader = ETR_REFERENCE; + + // switchToTriangleRenderer + CurrentShader = BurningShader[shader]; + if ( CurrentShader ) + { + CurrentShader->setZCompareFunc ( Material.org.ZBuffer ); + CurrentShader->setRenderTarget(RenderTargetSurface, ViewPort); + CurrentShader->setMaterial ( Material ); + + switch ( shader ) + { + case ETR_TEXTURE_GOURAUD_ALPHA: + case ETR_TEXTURE_GOURAUD_ALPHA_NOZ: + case ETR_TEXTURE_BLEND: + CurrentShader->setParam ( 0, Material.org.MaterialTypeParam ); + break; + default: + break; + } + } + +} + + + +//! queries the features of the driver, returns true if feature is available +bool CBurningVideoDriver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const +{ + if (!FeatureEnabled[feature]) + return false; + + switch (feature) + { +#ifdef SOFTWARE_DRIVER_2_BILINEAR + case EVDF_BILINEAR_FILTER: + return true; +#endif +#ifdef SOFTWARE_DRIVER_2_MIPMAPPING + case EVDF_MIP_MAP: + return true; +#endif + case EVDF_STENCIL_BUFFER: + return StencilBuffer != 0; + + case EVDF_RENDER_TO_TARGET: + case EVDF_MULTITEXTURE: + case EVDF_HARDWARE_TL: + case EVDF_TEXTURE_NSQUARE: + return true; + + default: + return false; + } +} + + + +//! Create render target. +IRenderTarget* CBurningVideoDriver::addRenderTarget() +{ + CSoftwareRenderTarget2* renderTarget = new CSoftwareRenderTarget2(this); + RenderTargets.push_back(renderTarget); + + return renderTarget; +} + + + +//! sets transformation +void CBurningVideoDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) +{ + Transformation[state] = mat; + core::setbit_cond ( TransformationFlag[state], mat.isIdentity(), ETF_IDENTITY ); + + switch ( state ) + { + case ETS_VIEW: + Transformation[ETS_VIEW_PROJECTION].setbyproduct_nocheck ( + Transformation[ETS_PROJECTION], + Transformation[ETS_VIEW] + ); + getCameraPosWorldSpace (); + break; + + case ETS_WORLD: + if ( TransformationFlag[state] & ETF_IDENTITY ) + { + Transformation[ETS_WORLD_INVERSE] = Transformation[ETS_WORLD]; + TransformationFlag[ETS_WORLD_INVERSE] |= ETF_IDENTITY; + Transformation[ETS_CURRENT] = Transformation[ETS_VIEW_PROJECTION]; + } + else + { + //Transformation[ETS_WORLD].getInversePrimitive ( Transformation[ETS_WORLD_INVERSE] ); + Transformation[ETS_CURRENT].setbyproduct_nocheck ( + Transformation[ETS_VIEW_PROJECTION], + Transformation[ETS_WORLD] + ); + } + TransformationFlag[ETS_CURRENT] = 0; + //getLightPosObjectSpace (); + break; + case ETS_TEXTURE_0: + case ETS_TEXTURE_1: + case ETS_TEXTURE_2: + case ETS_TEXTURE_3: + if ( 0 == (TransformationFlag[state] & ETF_IDENTITY ) ) + LightSpace.Flags |= VERTEXTRANSFORM; + default: + break; + } +} + +bool CBurningVideoDriver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil, const SExposedVideoData& videoData, core::rect* sourceRect) +{ + CNullDriver::beginScene(clearFlag, clearColor, clearDepth, clearStencil, videoData, sourceRect); + WindowId = videoData.D3D9.HWnd; + SceneSourceRect = sourceRect; + + clearBuffers(clearFlag, clearColor, clearDepth, clearStencil); + + memset ( TransformationFlag, 0, sizeof ( TransformationFlag ) ); + return true; +} + +bool CBurningVideoDriver::endScene() +{ + CNullDriver::endScene(); + + return Presenter->present(BackBuffer, WindowId, SceneSourceRect); +} + +bool CBurningVideoDriver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil) +{ + if (target && target->getDriverType() != EDT_BURNINGSVIDEO) + { + os::Printer::log("Fatal Error: Tried to set a render target not owned by this driver.", ELL_ERROR); + return false; + } + + if (RenderTargetTexture) + RenderTargetTexture->drop(); + + CSoftwareRenderTarget2* renderTarget = static_cast(target); + RenderTargetTexture = (renderTarget) ? renderTarget->getTexture() : 0; + + if (RenderTargetTexture) + { + RenderTargetTexture->grab(); + setRenderTargetImage(((CSoftwareTexture2*)RenderTargetTexture)->getTexture()); + } + else + { + setRenderTargetImage(BackBuffer); + } + + clearBuffers(clearFlag, clearColor, clearDepth, clearStencil); + + return true; +} + + +//! sets a render target +void CBurningVideoDriver::setRenderTargetImage(video::CImage* image) +{ + if (RenderTargetSurface) + RenderTargetSurface->drop(); + + RenderTargetSurface = image; + RenderTargetSize.Width = 0; + RenderTargetSize.Height = 0; + + if (RenderTargetSurface) + { + RenderTargetSurface->grab(); + RenderTargetSize = RenderTargetSurface->getDimension(); + } + + setViewPort(core::rect(0,0,RenderTargetSize.Width,RenderTargetSize.Height)); + + if (DepthBuffer) + DepthBuffer->setSize(RenderTargetSize); + + if (StencilBuffer) + StencilBuffer->setSize(RenderTargetSize); +} + + + +//! sets a viewport +void CBurningVideoDriver::setViewPort(const core::rect& area) +{ + ViewPort = area; + + core::rect rendert(0,0,RenderTargetSize.Width,RenderTargetSize.Height); + ViewPort.clipAgainst(rendert); + + Transformation [ ETS_CLIPSCALE ].buildNDCToDCMatrix ( ViewPort, 1 ); + + if (CurrentShader) + CurrentShader->setRenderTarget(RenderTargetSurface, ViewPort); +} + +/* + generic plane clipping in homogenous coordinates + special case ndc frustum <-w,w>,<-w,w>,<-w,w> + can be rewritten with compares e.q near plane, a.z < -a.w and b.z < -b.w +*/ + +const sVec4 CBurningVideoDriver::NDCPlane[6] = +{ + sVec4( 0.f, 0.f, -1.f, -1.f ), // near + sVec4( 0.f, 0.f, 1.f, -1.f ), // far + sVec4( 1.f, 0.f, 0.f, -1.f ), // left + sVec4( -1.f, 0.f, 0.f, -1.f ), // right + sVec4( 0.f, 1.f, 0.f, -1.f ), // bottom + sVec4( 0.f, -1.f, 0.f, -1.f ) // top +}; + + + +/* + test a vertex if it's inside the standard frustum + + this is the generic one.. + + f32 dotPlane; + for ( u32 i = 0; i!= 6; ++i ) + { + dotPlane = v->Pos.dotProduct ( NDCPlane[i] ); + core::setbit_cond( flag, dotPlane <= 0.f, 1 << i ); + } + + // this is the base for ndc frustum <-w,w>,<-w,w>,<-w,w> + core::setbit_cond( flag, ( v->Pos.z - v->Pos.w ) <= 0.f, 1 ); + core::setbit_cond( flag, (-v->Pos.z - v->Pos.w ) <= 0.f, 2 ); + core::setbit_cond( flag, ( v->Pos.x - v->Pos.w ) <= 0.f, 4 ); + core::setbit_cond( flag, (-v->Pos.x - v->Pos.w ) <= 0.f, 8 ); + core::setbit_cond( flag, ( v->Pos.y - v->Pos.w ) <= 0.f, 16 ); + core::setbit_cond( flag, (-v->Pos.y - v->Pos.w ) <= 0.f, 32 ); + +*/ +#ifdef IRRLICHT_FAST_MATH + +REALINLINE u32 CBurningVideoDriver::clipToFrustumTest ( const s4DVertex * v ) const +{ + f32 test[6]; + u32 flag; + const f32 w = - v->Pos.w; + + // a conditional move is needed....FCOMI ( but we don't have it ) + // so let the fpu calculate and write it back. + // cpu makes the compare, interleaving + + test[0] = v->Pos.z + w; + test[1] = -v->Pos.z + w; + test[2] = v->Pos.x + w; + test[3] = -v->Pos.x + w; + test[4] = v->Pos.y + w; + test[5] = -v->Pos.y + w; + + flag = (IR ( test[0] ) ) >> 31; + flag |= (IR ( test[1] ) & 0x80000000 ) >> 30; + flag |= (IR ( test[2] ) & 0x80000000 ) >> 29; + flag |= (IR ( test[3] ) & 0x80000000 ) >> 28; + flag |= (IR ( test[4] ) & 0x80000000 ) >> 27; + flag |= (IR ( test[5] ) & 0x80000000 ) >> 26; + +/* + flag = F32_LOWER_EQUAL_0 ( test[0] ); + flag |= F32_LOWER_EQUAL_0 ( test[1] ) << 1; + flag |= F32_LOWER_EQUAL_0 ( test[2] ) << 2; + flag |= F32_LOWER_EQUAL_0 ( test[3] ) << 3; + flag |= F32_LOWER_EQUAL_0 ( test[4] ) << 4; + flag |= F32_LOWER_EQUAL_0 ( test[5] ) << 5; +*/ + return flag; +} + +#else + + +REALINLINE u32 CBurningVideoDriver::clipToFrustumTest ( const s4DVertex * v ) const +{ + u32 flag = 0; + + flag |= v->Pos.z <= v->Pos.w ? 1 : 0; + flag |= -v->Pos.z <= v->Pos.w ? 2 : 0; + + flag |= v->Pos.x <= v->Pos.w ? 4 : 0; + flag |= -v->Pos.x <= v->Pos.w ? 8 : 0; + + flag |= v->Pos.y <= v->Pos.w ? 16 : 0; + flag |= -v->Pos.y <= v->Pos.w ? 32 : 0; + +/* + if ( v->Pos.z <= v->Pos.w ) flag |= 1; + if (-v->Pos.z <= v->Pos.w ) flag |= 2; + + if ( v->Pos.x <= v->Pos.w ) flag |= 4; + if (-v->Pos.x <= v->Pos.w ) flag |= 8; + + if ( v->Pos.y <= v->Pos.w ) flag |= 16; + if (-v->Pos.y <= v->Pos.w ) flag |= 32; +*/ +/* + for ( u32 i = 0; i!= 6; ++i ) + { + core::setbit_cond( flag, v->Pos.dotProduct ( NDCPlane[i] ) <= 0.f, 1 << i ); + } +*/ + return flag; +} + +#endif // _MSC_VER + +u32 CBurningVideoDriver::clipToHyperPlane ( s4DVertex * dest, const s4DVertex * source, u32 inCount, const sVec4 &plane ) +{ + u32 outCount = 0; + s4DVertex * out = dest; + + const s4DVertex * a; + const s4DVertex * b = source; + + f32 bDotPlane; + + bDotPlane = b->Pos.dotProduct ( plane ); + + for( u32 i = 1; i < inCount + 1; ++i) + { + // i really have problem + const s32 condition = i - inCount; + const s32 index = (( ( condition >> 31 ) & ( i ^ condition ) ) ^ condition ) << 1; + + a = &source[ index ]; + + // current point inside + if ( a->Pos.dotProduct ( plane ) <= 0.f ) + { + // last point outside + if ( F32_GREATER_0 ( bDotPlane ) ) + { + // intersect line segment with plane + out->interpolate ( *b, *a, bDotPlane / (b->Pos - a->Pos).dotProduct ( plane ) ); + out += 2; + outCount += 1; + } + + // copy current to out + //*out = *a; + irr::memcpy32_small ( out, a, SIZEOF_SVERTEX * 2 ); + b = out; + + out += 2; + outCount += 1; + } + else + { + // current point outside + + if ( F32_LOWER_EQUAL_0 ( bDotPlane ) ) + { + // previous was inside + // intersect line segment with plane + out->interpolate ( *b, *a, bDotPlane / (b->Pos - a->Pos).dotProduct ( plane ) ); + out += 2; + outCount += 1; + } + // pointer + b = a; + } + + bDotPlane = b->Pos.dotProduct ( plane ); + + } + + return outCount; +} + + +u32 CBurningVideoDriver::clipToFrustum ( s4DVertex *v0, s4DVertex * v1, const u32 vIn ) +{ + u32 vOut = vIn; + + vOut = clipToHyperPlane ( v1, v0, vOut, NDCPlane[0] ); if ( vOut < vIn ) return vOut; + vOut = clipToHyperPlane ( v0, v1, vOut, NDCPlane[1] ); if ( vOut < vIn ) return vOut; + vOut = clipToHyperPlane ( v1, v0, vOut, NDCPlane[2] ); if ( vOut < vIn ) return vOut; + vOut = clipToHyperPlane ( v0, v1, vOut, NDCPlane[3] ); if ( vOut < vIn ) return vOut; + vOut = clipToHyperPlane ( v1, v0, vOut, NDCPlane[4] ); if ( vOut < vIn ) return vOut; + vOut = clipToHyperPlane ( v0, v1, vOut, NDCPlane[5] ); + return vOut; +} + +/*! + Part I: + apply Clip Scale matrix + From Normalized Device Coordiante ( NDC ) Space to Device Coordinate Space ( DC ) + + Part II: + Project homogeneous vector + homogeneous to non-homogenous coordinates ( dividebyW ) + + Incoming: ( xw, yw, zw, w, u, v, 1, R, G, B, A ) + Outgoing: ( xw/w, yw/w, zw/w, w/w, u/w, v/w, 1/w, R/w, G/w, B/w, A/w ) + + + replace w/w by 1/w +*/ +inline void CBurningVideoDriver::ndc_2_dc_and_project ( s4DVertex *dest,s4DVertex *source, u32 vIn ) const +{ + u32 g; + + for ( g = 0; g != vIn; g += 2 ) + { + if ( (dest[g].flag & VERTEX4D_PROJECTED ) == VERTEX4D_PROJECTED ) + continue; + + dest[g].flag = source[g].flag | VERTEX4D_PROJECTED; + + const f32 w = source[g].Pos.w; + const f32 iw = core::reciprocal ( w ); + + // to device coordinates + dest[g].Pos.x = iw * ( source[g].Pos.x * Transformation [ ETS_CLIPSCALE ][ 0] + w * Transformation [ ETS_CLIPSCALE ][12] ); + dest[g].Pos.y = iw * ( source[g].Pos.y * Transformation [ ETS_CLIPSCALE ][ 5] + w * Transformation [ ETS_CLIPSCALE ][13] ); + +#ifndef SOFTWARE_DRIVER_2_USE_WBUFFER + dest[g].Pos.z = iw * source[g].Pos.z; +#endif + + #ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + dest[g].Color[0] = source[g].Color[0] * iw; + #else + dest[g].Color[0] = source[g].Color[0]; + #endif + + #endif + dest[g].LightTangent[0] = source[g].LightTangent[0] * iw; + dest[g].Pos.w = iw; + } +} + + +inline void CBurningVideoDriver::ndc_2_dc_and_project2 ( const s4DVertex **v, const u32 size ) const +{ + u32 g; + + for ( g = 0; g != size; g += 1 ) + { + s4DVertex * a = (s4DVertex*) v[g]; + + if ( (a[1].flag & VERTEX4D_PROJECTED ) == VERTEX4D_PROJECTED ) + continue; + + a[1].flag = a->flag | VERTEX4D_PROJECTED; + + // project homogenous vertex, store 1/w + const f32 w = a->Pos.w; + const f32 iw = core::reciprocal ( w ); + + // to device coordinates + const f32 * p = Transformation [ ETS_CLIPSCALE ].pointer(); + a[1].Pos.x = iw * ( a->Pos.x * p[ 0] + w * p[12] ); + a[1].Pos.y = iw * ( a->Pos.y * p[ 5] + w * p[13] ); + +#ifndef SOFTWARE_DRIVER_2_USE_WBUFFER + a[1].Pos.z = a->Pos.z * iw; +#endif + + #ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + a[1].Color[0] = a->Color[0] * iw; + #else + a[1].Color[0] = a->Color[0]; + #endif + #endif + + a[1].LightTangent[0] = a[0].LightTangent[0] * iw; + a[1].Pos.w = iw; + + } + +} + + +/*! + crossproduct in projected 2D -> screen area triangle +*/ +inline f32 CBurningVideoDriver::screenarea ( const s4DVertex *v ) const +{ + return ( ( v[3].Pos.x - v[1].Pos.x ) * ( v[5].Pos.y - v[1].Pos.y ) ) - + ( ( v[3].Pos.y - v[1].Pos.y ) * ( v[5].Pos.x - v[1].Pos.x ) ); +} + + +/*! +*/ +inline f32 CBurningVideoDriver::texelarea ( const s4DVertex *v, int tex ) const +{ + f32 z; + + z = ( (v[2].Tex[tex].x - v[0].Tex[tex].x ) * (v[4].Tex[tex].y - v[0].Tex[tex].y ) ) + - ( (v[4].Tex[tex].x - v[0].Tex[tex].x ) * (v[2].Tex[tex].y - v[0].Tex[tex].y ) ); + + return MAT_TEXTURE ( tex )->getLODFactor ( z ); +} + +/*! + crossproduct in projected 2D +*/ +inline f32 CBurningVideoDriver::screenarea2 ( const s4DVertex **v ) const +{ + return ( (( v[1] + 1 )->Pos.x - (v[0] + 1 )->Pos.x ) * ( (v[2] + 1 )->Pos.y - (v[0] + 1 )->Pos.y ) ) - + ( (( v[1] + 1 )->Pos.y - (v[0] + 1 )->Pos.y ) * ( (v[2] + 1 )->Pos.x - (v[0] + 1 )->Pos.x ) ); +} + +/*! +*/ +inline f32 CBurningVideoDriver::texelarea2 ( const s4DVertex **v, s32 tex ) const +{ + f32 z; + z = ( (v[1]->Tex[tex].x - v[0]->Tex[tex].x ) * (v[2]->Tex[tex].y - v[0]->Tex[tex].y ) ) + - ( (v[2]->Tex[tex].x - v[0]->Tex[tex].x ) * (v[1]->Tex[tex].y - v[0]->Tex[tex].y ) ); + + return MAT_TEXTURE ( tex )->getLODFactor ( z ); +} + + +/*! +*/ +inline void CBurningVideoDriver::select_polygon_mipmap ( s4DVertex *v, u32 vIn, u32 tex, const core::dimension2du& texSize ) const +{ + f32 f[2]; + + f[0] = (f32) texSize.Width - 0.25f; + f[1] = (f32) texSize.Height - 0.25f; + +#ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + for ( u32 g = 0; g != vIn; g += 2 ) + { + (v + g + 1 )->Tex[tex].x = (v + g + 0)->Tex[tex].x * ( v + g + 1 )->Pos.w * f[0]; + (v + g + 1 )->Tex[tex].y = (v + g + 0)->Tex[tex].y * ( v + g + 1 )->Pos.w * f[1]; + } +#else + for ( u32 g = 0; g != vIn; g += 2 ) + { + (v + g + 1 )->Tex[tex].x = (v + g + 0)->Tex[tex].x * f[0]; + (v + g + 1 )->Tex[tex].y = (v + g + 0)->Tex[tex].y * f[1]; + } +#endif +} + +inline void CBurningVideoDriver::select_polygon_mipmap2 ( s4DVertex **v, u32 tex, const core::dimension2du& texSize ) const +{ + f32 f[2]; + + f[0] = (f32) texSize.Width - 0.25f; + f[1] = (f32) texSize.Height - 0.25f; + +#ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + (v[0] + 1 )->Tex[tex].x = v[0]->Tex[tex].x * ( v[0] + 1 )->Pos.w * f[0]; + (v[0] + 1 )->Tex[tex].y = v[0]->Tex[tex].y * ( v[0] + 1 )->Pos.w * f[1]; + + (v[1] + 1 )->Tex[tex].x = v[1]->Tex[tex].x * ( v[1] + 1 )->Pos.w * f[0]; + (v[1] + 1 )->Tex[tex].y = v[1]->Tex[tex].y * ( v[1] + 1 )->Pos.w * f[1]; + + (v[2] + 1 )->Tex[tex].x = v[2]->Tex[tex].x * ( v[2] + 1 )->Pos.w * f[0]; + (v[2] + 1 )->Tex[tex].y = v[2]->Tex[tex].y * ( v[2] + 1 )->Pos.w * f[1]; + +#else + (v[0] + 1 )->Tex[tex].x = v[0]->Tex[tex].x * f[0]; + (v[0] + 1 )->Tex[tex].y = v[0]->Tex[tex].y * f[1]; + + (v[1] + 1 )->Tex[tex].x = v[1]->Tex[tex].x * f[0]; + (v[1] + 1 )->Tex[tex].y = v[1]->Tex[tex].y * f[1]; + + (v[2] + 1 )->Tex[tex].x = v[2]->Tex[tex].x * f[0]; + (v[2] + 1 )->Tex[tex].y = v[2]->Tex[tex].y * f[1]; +#endif +} + +// Vertex Cache +const SVSize CBurningVideoDriver::vSize[] = +{ + { VERTEX4D_FORMAT_TEXTURE_1 | VERTEX4D_FORMAT_COLOR_1, sizeof(S3DVertex), 1 }, + { VERTEX4D_FORMAT_TEXTURE_2 | VERTEX4D_FORMAT_COLOR_1, sizeof(S3DVertex2TCoords),2 }, + { VERTEX4D_FORMAT_TEXTURE_2 | VERTEX4D_FORMAT_COLOR_1 | VERTEX4D_FORMAT_BUMP_DOT3, sizeof(S3DVertexTangents),2 }, + { VERTEX4D_FORMAT_TEXTURE_2 | VERTEX4D_FORMAT_COLOR_1, sizeof(S3DVertex), 2 }, // reflection map + { 0, sizeof(f32) * 3, 0 }, // core::vector3df* +}; + + + +/*! + fill a cache line with transformed, light and clipp test triangles +*/ +void CBurningVideoDriver::VertexCache_fill(const u32 sourceIndex, const u32 destIndex) +{ + u8 * source; + s4DVertex *dest; + + source = (u8*) VertexCache.vertices + ( sourceIndex * vSize[VertexCache.vType].Pitch ); + + // it's a look ahead so we never hit it.. + // but give priority... + //VertexCache.info[ destIndex ].hit = hitCount; + + // store info + VertexCache.info[ destIndex ].index = sourceIndex; + VertexCache.info[ destIndex ].hit = 0; + + // destination Vertex + dest = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( destIndex << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); + + // transform Model * World * Camera * Projection * NDCSpace matrix + const S3DVertex *base = ((S3DVertex*) source ); + Transformation [ ETS_CURRENT].transformVect ( &dest->Pos.x, base->Pos ); + + //mhm ;-) maybe no goto + if ( VertexCache.vType == 4 ) goto clipandproject; + + +#if defined (SOFTWARE_DRIVER_2_LIGHTING) || defined ( SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM ) + + // vertex normal in light space + if ( Material.org.Lighting || (LightSpace.Flags & VERTEXTRANSFORM) ) + { + if ( TransformationFlag[ETS_WORLD] & ETF_IDENTITY ) + { + LightSpace.normal.set ( base->Normal.X, base->Normal.Y, base->Normal.Z, 1.f ); + LightSpace.vertex.set ( base->Pos.X, base->Pos.Y, base->Pos.Z, 1.f ); + } + else + { + Transformation[ETS_WORLD].rotateVect ( &LightSpace.normal.x, base->Normal ); + + // vertex in light space + if ( LightSpace.Flags & ( POINTLIGHT | FOG | SPECULAR | VERTEXTRANSFORM) ) + Transformation[ETS_WORLD].transformVect ( &LightSpace.vertex.x, base->Pos ); + } + + if ( LightSpace.Flags & NORMALIZE ) + LightSpace.normal.normalize_xyz(); + + } + +#endif + +#if defined ( SOFTWARE_DRIVER_2_USE_VERTEX_COLOR ) + // apply lighting model + #if defined (SOFTWARE_DRIVER_2_LIGHTING) + if ( Material.org.Lighting ) + { + lightVertex ( dest, base->Color.color ); + } + else + { + dest->Color[0].setA8R8G8B8 ( base->Color.color ); + } + #else + dest->Color[0].setA8R8G8B8 ( base->Color.color ); + #endif +#endif + + // Texture Transform +#if !defined ( SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM ) + irr::memcpy32_small ( &dest->Tex[0],&base->TCoords, + vSize[VertexCache.vType].TexSize << 3 // * ( sizeof ( f32 ) * 2 ) + ); +#else + + if ( 0 == (LightSpace.Flags & VERTEXTRANSFORM) ) + { + irr::memcpy32_small ( &dest->Tex[0],&base->TCoords, + vSize[VertexCache.vType].TexSize << 3 // * ( sizeof ( f32 ) * 2 ) + ); + } + else + { + /* + Generate texture coordinates as linear functions so that: + u = Ux*x + Uy*y + Uz*z + Uw + v = Vx*x + Vy*y + Vz*z + Vw + The matrix M for this case is: + Ux Vx 0 0 + Uy Vy 0 0 + Uz Vz 0 0 + Uw Vw 0 0 + */ + + u32 t; + sVec4 n; + sVec2 srcT; + + for ( t = 0; t != vSize[VertexCache.vType].TexSize; ++t ) + { + const core::matrix4& M = Transformation [ ETS_TEXTURE_0 + t ]; + + // texgen + if ( TransformationFlag [ ETS_TEXTURE_0 + t ] & (ETF_TEXGEN_CAMERA_NORMAL|ETF_TEXGEN_CAMERA_REFLECTION) ) + { + n.x = LightSpace.campos.x - LightSpace.vertex.x; + n.y = LightSpace.campos.x - LightSpace.vertex.y; + n.z = LightSpace.campos.x - LightSpace.vertex.z; + n.normalize_xyz(); + n.x += LightSpace.normal.x; + n.y += LightSpace.normal.y; + n.z += LightSpace.normal.z; + n.normalize_xyz(); + + const f32 *view = Transformation[ETS_VIEW].pointer(); + + if ( TransformationFlag [ ETS_TEXTURE_0 + t ] & ETF_TEXGEN_CAMERA_REFLECTION ) + { + srcT.x = 0.5f * ( 1.f + (n.x * view[0] + n.y * view[4] + n.z * view[8] )); + srcT.y = 0.5f * ( 1.f + (n.x * view[1] + n.y * view[5] + n.z * view[9] )); + } + else + { + srcT.x = 0.5f * ( 1.f + (n.x * view[0] + n.y * view[1] + n.z * view[2] )); + srcT.y = 0.5f * ( 1.f + (n.x * view[4] + n.y * view[5] + n.z * view[6] )); + } + } + else + { + irr::memcpy32_small ( &srcT,(&base->TCoords) + t, + sizeof ( f32 ) * 2 ); + } + + switch ( Material.org.TextureLayer[t].TextureWrapU ) + { + case ETC_CLAMP: + case ETC_CLAMP_TO_EDGE: + case ETC_CLAMP_TO_BORDER: + dest->Tex[t].x = core::clamp ( (f32) ( M[0] * srcT.x + M[4] * srcT.y + M[8] ), 0.f, 1.f ); + break; + case ETC_MIRROR: + dest->Tex[t].x = M[0] * srcT.x + M[4] * srcT.y + M[8]; + if (core::fract(dest->Tex[t].x)>0.5f) + dest->Tex[t].x=1.f-dest->Tex[t].x; + break; + case ETC_MIRROR_CLAMP: + case ETC_MIRROR_CLAMP_TO_EDGE: + case ETC_MIRROR_CLAMP_TO_BORDER: + dest->Tex[t].x = core::clamp ( (f32) ( M[0] * srcT.x + M[4] * srcT.y + M[8] ), 0.f, 1.f ); + if (core::fract(dest->Tex[t].x)>0.5f) + dest->Tex[t].x=1.f-dest->Tex[t].x; + break; + case ETC_REPEAT: + default: + dest->Tex[t].x = M[0] * srcT.x + M[4] * srcT.y + M[8]; + break; + } + switch ( Material.org.TextureLayer[t].TextureWrapV ) + { + case ETC_CLAMP: + case ETC_CLAMP_TO_EDGE: + case ETC_CLAMP_TO_BORDER: + dest->Tex[t].y = core::clamp ( (f32) ( M[1] * srcT.x + M[5] * srcT.y + M[9] ), 0.f, 1.f ); + break; + case ETC_MIRROR: + dest->Tex[t].y = M[1] * srcT.x + M[5] * srcT.y + M[9]; + if (core::fract(dest->Tex[t].y)>0.5f) + dest->Tex[t].y=1.f-dest->Tex[t].y; + break; + case ETC_MIRROR_CLAMP: + case ETC_MIRROR_CLAMP_TO_EDGE: + case ETC_MIRROR_CLAMP_TO_BORDER: + dest->Tex[t].y = core::clamp ( (f32) ( M[1] * srcT.x + M[5] * srcT.y + M[9] ), 0.f, 1.f ); + if (core::fract(dest->Tex[t].y)>0.5f) + dest->Tex[t].y=1.f-dest->Tex[t].y; + break; + case ETC_REPEAT: + default: + dest->Tex[t].y = M[1] * srcT.x + M[5] * srcT.y + M[9]; + break; + } + } + } + +#if 0 + // tangent space light vector, emboss + if ( Lights.size () && ( vSize[VertexCache.vType].Format & VERTEX4D_FORMAT_BUMP_DOT3 ) ) + { + const S3DVertexTangents *tangent = ((S3DVertexTangents*) source ); + const SBurningShaderLight &light = LightSpace.Light[0]; + + sVec4 vp; + + vp.x = light.pos.x - LightSpace.vertex.x; + vp.y = light.pos.y - LightSpace.vertex.y; + vp.z = light.pos.z - LightSpace.vertex.z; + + vp.normalize_xyz(); + + LightSpace.tangent.x = vp.x * tangent->Tangent.X + vp.y * tangent->Tangent.Y + vp.z * tangent->Tangent.Z; + LightSpace.tangent.y = vp.x * tangent->Binormal.X + vp.y * tangent->Binormal.Y + vp.z * tangent->Binormal.Z; + //LightSpace.tangent.z = vp.x * tangent->Normal.X + vp.y * tangent->Normal.Y + vp.z * tangent->Normal.Z; + LightSpace.tangent.z = 0.f; + LightSpace.tangent.normalize_xyz(); + + f32 scale = 1.f / 128.f; + if ( Material.org.MaterialTypeParam > 0.f ) + scale = Material.org.MaterialTypeParam; + + // emboss, shift coordinates + dest->Tex[1].x = dest->Tex[0].x + LightSpace.tangent.x * scale; + dest->Tex[1].y = dest->Tex[0].y + LightSpace.tangent.y * scale; + //dest->Tex[1].z = LightSpace.tangent.z * scale; + } +#endif + + if ( LightSpace.Light.size () && ( vSize[VertexCache.vType].Format & VERTEX4D_FORMAT_BUMP_DOT3 ) ) + { + const S3DVertexTangents *tangent = ((S3DVertexTangents*) source ); + + sVec4 vp; + + dest->LightTangent[0].x = 0.f; + dest->LightTangent[0].y = 0.f; + dest->LightTangent[0].z = 0.f; + for ( u32 i = 0; i < 2 && i < LightSpace.Light.size (); ++i ) + { + const SBurningShaderLight &light = LightSpace.Light[i]; + + if ( !light.LightIsOn ) + continue; + + vp.x = light.pos.x - LightSpace.vertex.x; + vp.y = light.pos.y - LightSpace.vertex.y; + vp.z = light.pos.z - LightSpace.vertex.z; + + /* + vp.x = light.pos_objectspace.x - base->Pos.X; + vp.y = light.pos_objectspace.y - base->Pos.Y; + vp.z = light.pos_objectspace.z - base->Pos.Z; + */ + + vp.normalize_xyz(); + + + // transform by tangent matrix + sVec3 l; + #if 1 + l.x = (vp.x * tangent->Tangent.X + vp.y * tangent->Tangent.Y + vp.z * tangent->Tangent.Z ); + l.y = (vp.x * tangent->Binormal.X + vp.y * tangent->Binormal.Y + vp.z * tangent->Binormal.Z ); + l.z = (vp.x * tangent->Normal.X + vp.y * tangent->Normal.Y + vp.z * tangent->Normal.Z ); + #else + l.x = (vp.x * tangent->Tangent.X + vp.y * tangent->Binormal.X + vp.z * tangent->Normal.X ); + l.y = (vp.x * tangent->Tangent.Y + vp.y * tangent->Binormal.Y + vp.z * tangent->Normal.Y ); + l.z = (vp.x * tangent->Tangent.Z + vp.y * tangent->Binormal.Z + vp.z * tangent->Normal.Z ); + #endif + + + /* + f32 scale = 1.f / 128.f; + scale /= dest->LightTangent[0].b; + + // emboss, shift coordinates + dest->Tex[1].x = dest->Tex[0].x + l.r * scale; + dest->Tex[1].y = dest->Tex[0].y + l.g * scale; + */ + dest->Tex[1].x = dest->Tex[0].x; + dest->Tex[1].y = dest->Tex[0].y; + + // scale bias + dest->LightTangent[0].x += l.x; + dest->LightTangent[0].y += l.y; + dest->LightTangent[0].z += l.z; + } + dest->LightTangent[0].setLength ( 0.5f ); + dest->LightTangent[0].x += 0.5f; + dest->LightTangent[0].y += 0.5f; + dest->LightTangent[0].z += 0.5f; + } + + +#endif + +clipandproject: + dest[0].flag = dest[1].flag = vSize[VertexCache.vType].Format; + + // test vertex + dest[0].flag |= clipToFrustumTest ( dest); + + // to DC Space, project homogenous vertex + if ( (dest[0].flag & VERTEX4D_CLIPMASK ) == VERTEX4D_INSIDE ) + { + ndc_2_dc_and_project2 ( (const s4DVertex**) &dest, 1 ); + } + + //return dest; +} + +// + +REALINLINE s4DVertex * CBurningVideoDriver::VertexCache_getVertex ( const u32 sourceIndex ) +{ + for ( s32 i = 0; i < VERTEXCACHE_ELEMENT; ++i ) + { + if ( VertexCache.info[ i ].index == sourceIndex ) + { + return (s4DVertex *) ( (u8*) VertexCache.mem.data + ( i << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); + } + } + return 0; +} + + +/* + Cache based on linear walk indices + fill blockwise on the next 16(Cache_Size) unique vertices in indexlist + merge the next 16 vertices with the current +*/ +REALINLINE void CBurningVideoDriver::VertexCache_get(const s4DVertex ** face) +{ + SCacheInfo info[VERTEXCACHE_ELEMENT]; + + // next primitive must be complete in cache + if ( VertexCache.indicesIndex - VertexCache.indicesRun < 3 && + VertexCache.indicesIndex < VertexCache.indexCount + ) + { + // rewind to start of primitive + VertexCache.indicesIndex = VertexCache.indicesRun; + + irr::memset32 ( info, VERTEXCACHE_MISS, sizeof ( info ) ); + + // get the next unique vertices cache line + u32 fillIndex = 0; + u32 dIndex = 0; + u32 i = 0; + u32 sourceIndex = 0; + + while ( VertexCache.indicesIndex < VertexCache.indexCount && + fillIndex < VERTEXCACHE_ELEMENT + ) + { + switch ( VertexCache.iType ) + { + case 1: + sourceIndex = ((u16*)VertexCache.indices) [ VertexCache.indicesIndex ]; + break; + case 2: + sourceIndex = ((u32*)VertexCache.indices) [ VertexCache.indicesIndex ]; + break; + case 4: + sourceIndex = VertexCache.indicesIndex; + break; + } + + VertexCache.indicesIndex += 1; + + // if not exist, push back + s32 exist = 0; + for ( dIndex = 0; dIndex < fillIndex; ++dIndex ) + { + if ( info[ dIndex ].index == sourceIndex ) + { + exist = 1; + break; + } + } + + if ( 0 == exist ) + { + info[fillIndex++].index = sourceIndex; + } + } + + // clear marks + for ( i = 0; i!= VERTEXCACHE_ELEMENT; ++i ) + { + VertexCache.info[i].hit = 0; + } + + // mark all existing + for ( i = 0; i!= fillIndex; ++i ) + { + for ( dIndex = 0; dIndex < VERTEXCACHE_ELEMENT; ++dIndex ) + { + if ( VertexCache.info[ dIndex ].index == info[i].index ) + { + info[i].hit = dIndex; + VertexCache.info[ dIndex ].hit = 1; + break; + } + } + } + + // fill new + for ( i = 0; i!= fillIndex; ++i ) + { + if ( info[i].hit != VERTEXCACHE_MISS ) + continue; + + for ( dIndex = 0; dIndex < VERTEXCACHE_ELEMENT; ++dIndex ) + { + if ( 0 == VertexCache.info[dIndex].hit ) + { + VertexCache_fill ( info[i].index, dIndex ); + VertexCache.info[dIndex].hit += 1; + info[i].hit = dIndex; + break; + } + } + } + } + + const u32 i0 = core::if_c_a_else_0 ( VertexCache.pType != scene::EPT_TRIANGLE_FAN, VertexCache.indicesRun ); + + switch ( VertexCache.iType ) + { + case 1: + { + const u16 *p = (const u16 *) VertexCache.indices; + face[0] = VertexCache_getVertex ( p[ i0 ] ); + face[1] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 1] ); + face[2] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 2] ); + } + break; + + case 2: + { + const u32 *p = (const u32 *) VertexCache.indices; + face[0] = VertexCache_getVertex ( p[ i0 ] ); + face[1] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 1] ); + face[2] = VertexCache_getVertex ( p[ VertexCache.indicesRun + 2] ); + } + break; + + case 4: + face[0] = VertexCache_getVertex ( VertexCache.indicesRun + 0 ); + face[1] = VertexCache_getVertex ( VertexCache.indicesRun + 1 ); + face[2] = VertexCache_getVertex ( VertexCache.indicesRun + 2 ); + break; + default: + face[0] = face[1] = face[2] = VertexCache_getVertex(VertexCache.indicesRun + 0); + break; + } + + VertexCache.indicesRun += VertexCache.primitivePitch; +} + +/*! +*/ +REALINLINE void CBurningVideoDriver::VertexCache_getbypass ( s4DVertex ** face ) +{ + const u32 i0 = core::if_c_a_else_0 ( VertexCache.pType != scene::EPT_TRIANGLE_FAN, VertexCache.indicesRun ); + + if ( VertexCache.iType == 1 ) + { + const u16 *p = (const u16 *) VertexCache.indices; + VertexCache_fill ( p[ i0 ], 0 ); + VertexCache_fill ( p[ VertexCache.indicesRun + 1], 1 ); + VertexCache_fill ( p[ VertexCache.indicesRun + 2], 2 ); + } + else + { + const u32 *p = (const u32 *) VertexCache.indices; + VertexCache_fill ( p[ i0 ], 0 ); + VertexCache_fill ( p[ VertexCache.indicesRun + 1], 1 ); + VertexCache_fill ( p[ VertexCache.indicesRun + 2], 2 ); + } + + VertexCache.indicesRun += VertexCache.primitivePitch; + + face[0] = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( 0 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); + face[1] = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( 1 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); + face[2] = (s4DVertex *) ( (u8*) VertexCache.mem.data + ( 2 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ); + +} + +/*! +*/ +void CBurningVideoDriver::VertexCache_reset ( const void* vertices, u32 vertexCount, + const void* indices, u32 primitiveCount, + E_VERTEX_TYPE vType, + scene::E_PRIMITIVE_TYPE pType, + E_INDEX_TYPE iType) +{ + VertexCache.vertices = vertices; + VertexCache.vertexCount = vertexCount; + + VertexCache.indices = indices; + VertexCache.indicesIndex = 0; + VertexCache.indicesRun = 0; + + if ( Material.org.MaterialType == video::EMT_REFLECTION_2_LAYER ) + VertexCache.vType = 3; + else + VertexCache.vType = vType; + VertexCache.pType = pType; + + switch ( iType ) + { + case EIT_16BIT: VertexCache.iType = 1; break; + case EIT_32BIT: VertexCache.iType = 2; break; + default: + VertexCache.iType = iType; break; + } + + switch ( VertexCache.pType ) + { + // most types here will not work as expected, only triangles/triangle_fan + // is known to work. + case scene::EPT_POINTS: + VertexCache.indexCount = primitiveCount; + VertexCache.primitivePitch = 1; + break; + case scene::EPT_LINE_STRIP: + VertexCache.indexCount = primitiveCount+1; + VertexCache.primitivePitch = 1; + break; + case scene::EPT_LINE_LOOP: + VertexCache.indexCount = primitiveCount+1; + VertexCache.primitivePitch = 1; + break; + case scene::EPT_LINES: + VertexCache.indexCount = 2*primitiveCount; + VertexCache.primitivePitch = 2; + break; + case scene::EPT_TRIANGLE_STRIP: + VertexCache.indexCount = primitiveCount+2; + VertexCache.primitivePitch = 1; + break; + case scene::EPT_TRIANGLES: + VertexCache.indexCount = primitiveCount + primitiveCount + primitiveCount; + VertexCache.primitivePitch = 3; + break; + case scene::EPT_TRIANGLE_FAN: + VertexCache.indexCount = primitiveCount + 2; + VertexCache.primitivePitch = 1; + break; + case scene::EPT_QUAD_STRIP: + VertexCache.indexCount = 2*primitiveCount + 2; + VertexCache.primitivePitch = 2; + break; + case scene::EPT_QUADS: + VertexCache.indexCount = 4*primitiveCount; + VertexCache.primitivePitch = 4; + break; + case scene::EPT_POLYGON: + VertexCache.indexCount = primitiveCount+1; + VertexCache.primitivePitch = 1; + break; + case scene::EPT_POINT_SPRITES: + VertexCache.indexCount = primitiveCount; + VertexCache.primitivePitch = 1; + break; + } + + irr::memset32 ( VertexCache.info, VERTEXCACHE_MISS, sizeof ( VertexCache.info ) ); +} + + +void CBurningVideoDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) + +{ + if (!checkPrimitiveCount(primitiveCount)) + return; + + CNullDriver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType); + + // These calls would lead to crashes due to wrong index usage. + // The vertex cache needs to be rewritten for these primitives. + if (pType==scene::EPT_POINTS || pType==scene::EPT_LINE_STRIP || + pType==scene::EPT_LINE_LOOP || pType==scene::EPT_LINES || + pType==scene::EPT_POLYGON || + pType==scene::EPT_POINT_SPRITES) + return; + + if ( 0 == CurrentShader ) + return; + + VertexCache_reset ( vertices, vertexCount, indexList, primitiveCount, vType, pType, iType ); + + const s4DVertex * face[3]; + + f32 dc_area; + s32 lodLevel; + u32 i; + u32 g; + u32 m; + video::CSoftwareTexture2* tex; + + for ( i = 0; i < (u32) primitiveCount; ++i ) + { + VertexCache_get(face); + + // if fully outside or outside on same side + if ( ( (face[0]->flag | face[1]->flag | face[2]->flag) & VERTEX4D_CLIPMASK ) + != VERTEX4D_INSIDE + ) + continue; + + // if fully inside + if ( ( face[0]->flag & face[1]->flag & face[2]->flag & VERTEX4D_CLIPMASK ) == VERTEX4D_INSIDE ) + { + dc_area = screenarea2 ( face ); + if ( Material.org.BackfaceCulling && F32_LOWER_EQUAL_0( dc_area ) ) + continue; + else + if ( Material.org.FrontfaceCulling && F32_GREATER_EQUAL_0( dc_area ) ) + continue; + + // select mipmap + dc_area = core::reciprocal ( dc_area ); + for ( m = 0; m != vSize[VertexCache.vType].TexSize; ++m ) + { + if ( 0 == (tex = MAT_TEXTURE ( m )) ) + { + CurrentShader->setTextureParam(m, 0, 0); + continue; + } + + lodLevel = s32_log2_f32 ( texelarea2 ( face, m ) * dc_area ); + CurrentShader->setTextureParam(m, tex, lodLevel ); + select_polygon_mipmap2 ( (s4DVertex**) face, m, tex->getSize() ); + } + + // rasterize + CurrentShader->drawTriangle ( face[0] + 1, face[1] + 1, face[2] + 1 ); + continue; + } + + // else if not complete inside clipping necessary + irr::memcpy32_small ( ( (u8*) CurrentOut.data + ( 0 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ), face[0], SIZEOF_SVERTEX * 2 ); + irr::memcpy32_small ( ( (u8*) CurrentOut.data + ( 1 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ), face[1], SIZEOF_SVERTEX * 2 ); + irr::memcpy32_small ( ( (u8*) CurrentOut.data + ( 2 << ( SIZEOF_SVERTEX_LOG2 + 1 ) ) ), face[2], SIZEOF_SVERTEX * 2 ); + + const u32 flag = CurrentOut.data->flag & VERTEX4D_FORMAT_MASK; + + for ( g = 0; g != CurrentOut.ElementSize; ++g ) + { + CurrentOut.data[g].flag = flag; + Temp.data[g].flag = flag; + } + + u32 vOut; + vOut = clipToFrustum ( CurrentOut.data, Temp.data, 3 ); + if ( vOut < 3 ) + continue; + + vOut <<= 1; + + // to DC Space, project homogenous vertex + ndc_2_dc_and_project ( CurrentOut.data + 1, CurrentOut.data, vOut ); + + // check 2d backface culling on first + dc_area = screenarea ( CurrentOut.data ); + if ( Material.org.BackfaceCulling && F32_LOWER_EQUAL_0 ( dc_area ) ) + continue; + else if ( Material.org.FrontfaceCulling && F32_GREATER_EQUAL_0( dc_area ) ) + continue; + + // select mipmap + dc_area = core::reciprocal ( dc_area ); + for ( m = 0; m != vSize[VertexCache.vType].TexSize; ++m ) + { + if ( 0 == (tex = MAT_TEXTURE ( m )) ) + { + CurrentShader->setTextureParam(m, 0, 0); + continue; + } + + lodLevel = s32_log2_f32 ( texelarea ( CurrentOut.data, m ) * dc_area ); + CurrentShader->setTextureParam(m, tex, lodLevel ); + select_polygon_mipmap ( CurrentOut.data, vOut, m, tex->getSize() ); + } + + + // re-tesselate ( triangle-fan, 0-1-2,0-2-3.. ) + for ( g = 0; g <= vOut - 6; g += 2 ) + { + // rasterize + CurrentShader->drawTriangle ( CurrentOut.data + 0 + 1, + CurrentOut.data + g + 3, + CurrentOut.data + g + 5); + } + + } + + // dump statistics +/* + char buf [64]; + sprintf ( buf,"VCount:%d PCount:%d CacheMiss: %d", + vertexCount, primitiveCount, + VertexCache.CacheMiss + ); + os::Printer::log( buf ); +*/ + +} + + +//! 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. +void CBurningVideoDriver::setAmbientLight(const SColorf& color) +{ + CNullDriver::setAmbientLight(color); + LightSpace.Global_AmbientLight.setColorf ( color ); +} + + +//! adds a dynamic light +s32 CBurningVideoDriver::addDynamicLight(const SLight& dl) +{ + (void) CNullDriver::addDynamicLight( dl ); + + SBurningShaderLight l; +// l.org = dl; + l.Type = dl.Type; + l.LightIsOn = true; + + l.AmbientColor.setColorf ( dl.AmbientColor ); + l.DiffuseColor.setColorf ( dl.DiffuseColor ); + l.SpecularColor.setColorf ( dl.SpecularColor ); + + switch ( dl.Type ) + { + case video::ELT_DIRECTIONAL: + l.pos.x = -dl.Direction.X; + l.pos.y = -dl.Direction.Y; + l.pos.z = -dl.Direction.Z; + l.pos.w = 1.f; + break; + case ELT_POINT: + case ELT_SPOT: + LightSpace.Flags |= POINTLIGHT; + l.pos.x = dl.Position.X; + l.pos.y = dl.Position.Y; + l.pos.z = dl.Position.Z; + l.pos.w = 1.f; +/* + l.radius = (1.f / dl.Attenuation.Y) * (1.f / dl.Attenuation.Y); + l.constantAttenuation = dl.Attenuation.X; + l.linearAttenuation = dl.Attenuation.Y; + l.quadraticAttenuation = dl.Attenuation.Z; +*/ + l.radius = dl.Radius * dl.Radius; + l.constantAttenuation = dl.Attenuation.X; + l.linearAttenuation = 1.f / dl.Radius; + l.quadraticAttenuation = dl.Attenuation.Z; + + break; + default: + break; + } + + LightSpace.Light.push_back ( l ); + 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() +{ + LightSpace.reset (); + CNullDriver::deleteAllDynamicLights(); + +} + +//! returns the maximal amount of dynamic lights the device can handle +u32 CBurningVideoDriver::getMaximalDynamicLightAmount() const +{ + return 8; +} + + +//! sets a material +void CBurningVideoDriver::setMaterial(const SMaterial& material) +{ + Material.org = material; + +#ifdef SOFTWARE_DRIVER_2_TEXTURE_TRANSFORM + for (u32 i = 0; i < 2; ++i) + { + setTransform((E_TRANSFORMATION_STATE) (ETS_TEXTURE_0 + i), + material.getTextureMatrix(i)); + } +#endif + +#ifdef SOFTWARE_DRIVER_2_LIGHTING + Material.AmbientColor.setR8G8B8 ( Material.org.AmbientColor.color ); + Material.DiffuseColor.setR8G8B8 ( Material.org.DiffuseColor.color ); + Material.EmissiveColor.setR8G8B8 ( Material.org.EmissiveColor.color ); + Material.SpecularColor.setR8G8B8 ( Material.org.SpecularColor.color ); + + core::setbit_cond ( LightSpace.Flags, Material.org.Shininess != 0.f, SPECULAR ); + core::setbit_cond ( LightSpace.Flags, Material.org.FogEnable, FOG ); + core::setbit_cond ( LightSpace.Flags, Material.org.NormalizeNormals, NORMALIZE ); +#endif + + setCurrentShader(); +} + + +/*! + Camera Position in World Space +*/ +void CBurningVideoDriver::getCameraPosWorldSpace () +{ + Transformation[ETS_VIEW_INVERSE] = Transformation[ ETS_VIEW ]; + Transformation[ETS_VIEW_INVERSE].makeInverse (); + TransformationFlag[ETS_VIEW_INVERSE] = 0; + + const f32 *M = Transformation[ETS_VIEW_INVERSE].pointer (); + + /* The viewpoint is at (0., 0., 0.) in eye space. + Turning this into a vector [0 0 0 1] and multiply it by + the inverse of the view matrix, the resulting vector is the + object space location of the camera. + */ + + LightSpace.campos.x = M[12]; + LightSpace.campos.y = M[13]; + LightSpace.campos.z = M[14]; + LightSpace.campos.w = 1.f; +} + +void CBurningVideoDriver::getLightPosObjectSpace () +{ + if ( TransformationFlag[ETS_WORLD] & ETF_IDENTITY ) + { + Transformation[ETS_WORLD_INVERSE] = Transformation[ETS_WORLD]; + TransformationFlag[ETS_WORLD_INVERSE] |= ETF_IDENTITY; + } + else + { + Transformation[ETS_WORLD].getInverse ( Transformation[ETS_WORLD_INVERSE] ); + TransformationFlag[ETS_WORLD_INVERSE] &= ~ETF_IDENTITY; + } + + for ( u32 i = 0; i < 1 && i < LightSpace.Light.size(); ++i ) + { + SBurningShaderLight &l = LightSpace.Light[i]; + + Transformation[ETS_WORLD_INVERSE].transformVec3 ( &l.pos_objectspace.x, &l.pos.x ); + } +} + + +#ifdef SOFTWARE_DRIVER_2_LIGHTING + +//! Sets the fog mode. +void CBurningVideoDriver::setFog(SColor color, E_FOG_TYPE fogType, f32 start, + f32 end, f32 density, bool pixelFog, bool rangeFog) +{ + CNullDriver::setFog(color, fogType, start, end, density, pixelFog, rangeFog); + LightSpace.FogColor.setA8R8G8B8 ( color.color ); +} + +/*! + applies lighting model +*/ +void CBurningVideoDriver::lightVertex ( s4DVertex *dest, u32 vertexargb ) +{ + sVec3 dColor; + + dColor = LightSpace.Global_AmbientLight; + dColor.add ( Material.EmissiveColor ); + + if ( Lights.size () == 0 ) + { + dColor.saturate( dest->Color[0], vertexargb); + return; + } + + sVec3 ambient; + sVec3 diffuse; + sVec3 specular; + + + // the universe started in darkness.. + ambient.set ( 0.f, 0.f, 0.f ); + diffuse.set ( 0.f, 0.f, 0.f ); + specular.set ( 0.f, 0.f, 0.f ); + + + u32 i; + f32 dot; + f32 len; + f32 attenuation; + sVec4 vp; // unit vector vertex to light + sVec4 lightHalf; // blinn-phong reflection + + for ( i = 0; i!= LightSpace.Light.size (); ++i ) + { + const SBurningShaderLight &light = LightSpace.Light[i]; + + if ( !light.LightIsOn ) + continue; + + // accumulate ambient + ambient.add ( light.AmbientColor ); + + switch ( light.Type ) + { + case video::ELT_SPOT: + case video::ELT_POINT: + // surface to light + vp.x = light.pos.x - LightSpace.vertex.x; + vp.y = light.pos.y - LightSpace.vertex.y; + vp.z = light.pos.z - LightSpace.vertex.z; + //vp.x = light.pos_objectspace.x - LightSpace.vertex.x; + //vp.y = light.pos_objectspace.y - LightSpace.vertex.x; + //vp.z = light.pos_objectspace.z - LightSpace.vertex.x; + + len = vp.get_length_xyz_square(); + if ( light.radius < len ) + continue; + + len = core::reciprocal_squareroot ( len ); + + // build diffuse reflection + + //angle between normal and light vector + vp.mul ( len ); + dot = LightSpace.normal.dot_xyz ( vp ); + if ( dot < 0.f ) + continue; + + attenuation = light.constantAttenuation + ( 1.f - ( len * light.linearAttenuation ) ); + + // diffuse component + diffuse.mulAdd ( light.DiffuseColor, 3.f * dot * attenuation ); + + if ( !(LightSpace.Flags & SPECULAR) ) + continue; + + // build specular + // surface to view + lightHalf.x = LightSpace.campos.x - LightSpace.vertex.x; + lightHalf.y = LightSpace.campos.y - LightSpace.vertex.y; + lightHalf.z = LightSpace.campos.z - LightSpace.vertex.z; + lightHalf.normalize_xyz(); + lightHalf += vp; + lightHalf.normalize_xyz(); + + // specular + dot = LightSpace.normal.dot_xyz ( lightHalf ); + if ( dot < 0.f ) + continue; + + //specular += light.SpecularColor * ( powf ( Material.org.Shininess ,dot ) * attenuation ); + specular.mulAdd ( light.SpecularColor, dot * attenuation ); + break; + + case video::ELT_DIRECTIONAL: + + //angle between normal and light vector + dot = LightSpace.normal.dot_xyz ( light.pos ); + if ( dot < 0.f ) + continue; + + // diffuse component + diffuse.mulAdd ( light.DiffuseColor, dot ); + break; + default: + break; + } + + } + + // sum up lights + dColor.mulAdd (ambient, Material.AmbientColor ); + dColor.mulAdd (diffuse, Material.DiffuseColor); + dColor.mulAdd (specular, Material.SpecularColor); + + dColor.saturate ( dest->Color[0], vertexargb ); +} + +#endif + + +//! 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. +void CBurningVideoDriver::draw2DImage(const video::ITexture* texture, const core::position2d& destPos, + const core::rect& sourceRect, + const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture) +{ + if (texture) + { + if (texture->getDriverType() != EDT_BURNINGSVIDEO) + { + os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR); + return; + } + +#if 0 + // 2d methods don't use viewPort + core::position2di dest = destPos; + core::recti clip=ViewPort; + if (ViewPort.getSize().Width != ScreenSize.Width) + { + dest.X=ViewPort.UpperLeftCorner.X+core::round32_fast(destPos.X*ViewPort.getWidth()/(f32)ScreenSize.Width); + dest.Y=ViewPort.UpperLeftCorner.Y+core::round32_fast(destPos.Y*ViewPort.getHeight()/(f32)ScreenSize.Height); + if (clipRect) + { + clip.constrainTo(*clipRect); + } + clipRect = &clip; + } +#endif + if (useAlphaChannelOfTexture) + ((CSoftwareTexture2*)texture)->getImage()->copyToWithAlpha( + RenderTargetSurface, destPos, sourceRect, color, clipRect); + else + ((CSoftwareTexture2*)texture)->getImage()->copyTo( + RenderTargetSurface, destPos, sourceRect, clipRect); + } +} + + +//! Draws a part of the texture into the rectangle. +void CBurningVideoDriver::draw2DImage(const video::ITexture* texture, const core::rect& destRect, + const core::rect& sourceRect, const core::rect* clipRect, + const video::SColor* const colors, bool useAlphaChannelOfTexture) +{ + if (texture) + { + if (texture->getDriverType() != EDT_BURNINGSVIDEO) + { + os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR); + return; + } + + if (useAlphaChannelOfTexture) + StretchBlit(BLITTER_TEXTURE_ALPHA_BLEND, RenderTargetSurface, &destRect, &sourceRect, + ((CSoftwareTexture2*)texture)->getImage(), (colors ? colors[0].color : 0)); + else + StretchBlit(BLITTER_TEXTURE, RenderTargetSurface, &destRect, &sourceRect, + ((CSoftwareTexture2*)texture)->getImage(), (colors ? colors[0].color : 0)); + } +} + +//! Draws a 2d line. +void CBurningVideoDriver::draw2DLine(const core::position2d& start, + const core::position2d& end, + SColor color) +{ + drawLine(BackBuffer, start, end, color ); +} + + +//! Draws a pixel +void CBurningVideoDriver::drawPixel(u32 x, u32 y, const SColor & color) +{ + BackBuffer->setPixel(x, y, color, true); +} + + +//! draw an 2d rectangle +void CBurningVideoDriver::draw2DRectangle(SColor color, const core::rect& pos, + const core::rect* clip) +{ + if (clip) + { + core::rect p(pos); + + p.clipAgainst(*clip); + + if(!p.isValid()) + return; + + drawRectangle(BackBuffer, p, color); + } + else + { + if(!pos.isValid()) + return; + + drawRectangle(BackBuffer, pos, color); + } +} + + +//! Only used by the internal engine. Used to notify the driver that +//! the window was resized. +void CBurningVideoDriver::OnResize(const core::dimension2d& size) +{ + // make sure width and height are multiples of 2 + core::dimension2d realSize(size); + + if (realSize.Width % 2) + realSize.Width += 1; + + if (realSize.Height % 2) + realSize.Height += 1; + + if (ScreenSize != realSize) + { + if (ViewPort.getWidth() == (s32)ScreenSize.Width && + ViewPort.getHeight() == (s32)ScreenSize.Height) + { + ViewPort.UpperLeftCorner.X = 0; + ViewPort.UpperLeftCorner.Y = 0; + ViewPort.LowerRightCorner.X = realSize.Width; + ViewPort.LowerRightCorner.X = realSize.Height; + } + + ScreenSize = realSize; + + bool resetRT = (RenderTargetSurface == BackBuffer); + + if (BackBuffer) + BackBuffer->drop(); + BackBuffer = new CImage(BURNINGSHADER_COLOR_FORMAT, realSize); + + if (resetRT) + setRenderTargetImage(BackBuffer); + } +} + + +//! returns the current render target size +const core::dimension2d& CBurningVideoDriver::getCurrentRenderTargetSize() const +{ + return RenderTargetSize; +} + + +//!Draws an 2d rectangle with a gradient. +void CBurningVideoDriver::draw2DRectangle(const core::rect& position, + SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, + const core::rect* clip) +{ +#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + + core::rect pos = position; + + if (clip) + pos.clipAgainst(*clip); + + if (!pos.isValid()) + return; + + const core::dimension2d renderTargetSize ( ViewPort.getSize() ); + + const s32 xPlus = -(renderTargetSize.Width>>1); + const f32 xFact = 1.0f / (renderTargetSize.Width>>1); + + const s32 yPlus = renderTargetSize.Height-(renderTargetSize.Height>>1); + const f32 yFact = 1.0f / (renderTargetSize.Height>>1); + + // fill VertexCache direct + s4DVertex *v; + + VertexCache.vertexCount = 4; + + VertexCache.info[0].index = 0; + VertexCache.info[1].index = 1; + VertexCache.info[2].index = 2; + VertexCache.info[3].index = 3; + + v = &VertexCache.mem.data [ 0 ]; + + v[0].Pos.set ( (f32)(pos.UpperLeftCorner.X+xPlus) * xFact, (f32)(yPlus-pos.UpperLeftCorner.Y) * yFact, 0.f, 1.f ); + v[0].Color[0].setA8R8G8B8 ( colorLeftUp.color ); + + v[2].Pos.set ( (f32)(pos.LowerRightCorner.X+xPlus) * xFact, (f32)(yPlus- pos.UpperLeftCorner.Y) * yFact, 0.f, 1.f ); + v[2].Color[0].setA8R8G8B8 ( colorRightUp.color ); + + v[4].Pos.set ( (f32)(pos.LowerRightCorner.X+xPlus) * xFact, (f32)(yPlus-pos.LowerRightCorner.Y) * yFact, 0.f ,1.f ); + v[4].Color[0].setA8R8G8B8 ( colorRightDown.color ); + + v[6].Pos.set ( (f32)(pos.UpperLeftCorner.X+xPlus) * xFact, (f32)(yPlus-pos.LowerRightCorner.Y) * yFact, 0.f, 1.f ); + v[6].Color[0].setA8R8G8B8 ( colorLeftDown.color ); + + s32 i; + u32 g; + + for ( i = 0; i!= 8; i += 2 ) + { + v[i + 0].flag = clipToFrustumTest ( v + i ); + v[i + 1].flag = 0; + if ( (v[i].flag & VERTEX4D_INSIDE ) == VERTEX4D_INSIDE ) + { + ndc_2_dc_and_project ( v + i + 1, v + i, 2 ); + } + } + + + IBurningShader * render; + + render = BurningShader [ ETR_GOURAUD_ALPHA_NOZ ]; + render->setRenderTarget(RenderTargetSurface, ViewPort); + + static const s16 indexList[6] = {0,1,2,0,2,3}; + + s4DVertex * face[3]; + + for ( i = 0; i!= 6; i += 3 ) + { + face[0] = VertexCache_getVertex ( indexList [ i + 0 ] ); + face[1] = VertexCache_getVertex ( indexList [ i + 1 ] ); + face[2] = VertexCache_getVertex ( indexList [ i + 2 ] ); + + // test clipping + u32 test = face[0]->flag & face[1]->flag & face[2]->flag & VERTEX4D_INSIDE; + + if ( test == VERTEX4D_INSIDE ) + { + render->drawTriangle ( face[0] + 1, face[1] + 1, face[2] + 1 ); + continue; + } + // Todo: all vertices are clipped in 2d.. + // is this true ? + u32 vOut = 6; + memcpy ( CurrentOut.data + 0, face[0], sizeof ( s4DVertex ) * 2 ); + memcpy ( CurrentOut.data + 2, face[1], sizeof ( s4DVertex ) * 2 ); + memcpy ( CurrentOut.data + 4, face[2], sizeof ( s4DVertex ) * 2 ); + + vOut = clipToFrustum ( CurrentOut.data, Temp.data, 3 ); + if ( vOut < 3 ) + continue; + + vOut <<= 1; + // to DC Space, project homogenous vertex + ndc_2_dc_and_project ( CurrentOut.data + 1, CurrentOut.data, vOut ); + + // re-tesselate ( triangle-fan, 0-1-2,0-2-3.. ) + for ( g = 0; g <= vOut - 6; g += 2 ) + { + // rasterize + render->drawTriangle ( CurrentOut.data + 1, &CurrentOut.data[g + 3], &CurrentOut.data[g + 5] ); + } + + } +#else + draw2DRectangle ( colorLeftUp, position, clip ); +#endif +} + + +//! Draws a 3d line. +void CBurningVideoDriver::draw3DLine(const core::vector3df& start, + const core::vector3df& end, SColor color) +{ + Transformation [ ETS_CURRENT].transformVect ( &CurrentOut.data[0].Pos.x, start ); + Transformation [ ETS_CURRENT].transformVect ( &CurrentOut.data[2].Pos.x, end ); + + u32 g; + u32 vOut; + + // no clipping flags + for ( g = 0; g != CurrentOut.ElementSize; ++g ) + { + CurrentOut.data[g].flag = 0; + Temp.data[g].flag = 0; + } + + // vertices count per line + vOut = clipToFrustum ( CurrentOut.data, Temp.data, 2 ); + if ( vOut < 2 ) + return; + + vOut <<= 1; + + IBurningShader * line; + line = BurningShader [ ETR_TEXTURE_GOURAUD_WIRE ]; + line->setRenderTarget(RenderTargetSurface, ViewPort); + + // to DC Space, project homogenous vertex + ndc_2_dc_and_project ( CurrentOut.data + 1, CurrentOut.data, vOut ); + + // unproject vertex color +#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + for ( g = 0; g != vOut; g+= 2 ) + { + CurrentOut.data[ g + 1].Color[0].setA8R8G8B8 ( color.color ); + } +#endif + + + for ( g = 0; g <= vOut - 4; g += 2 ) + { + // rasterize + line->drawLine ( CurrentOut.data + 1, CurrentOut.data + g + 3 ); + } +} + + +//! \return Returns the name of the video driver. Example: In case of the DirectX8 +//! driver, it would return "Direct3D8.1". +const wchar_t* CBurningVideoDriver::getName() const +{ +#ifdef BURNINGVIDEO_RENDERER_BEAUTIFUL + return L"Burning's Video 0.49 beautiful"; +#elif defined ( BURNINGVIDEO_RENDERER_ULTRA_FAST ) + return L"Burning's Video 0.49 ultra fast"; +#elif defined ( BURNINGVIDEO_RENDERER_FAST ) + return L"Burning's Video 0.49 fast"; +#else + return L"Burning's Video 0.49"; +#endif +} + +//! Returns the graphics card vendor name. +core::stringc CBurningVideoDriver::getVendorInfo() +{ + return "Burning's Video: Ing. Thomas Alten (c) 2006-2015"; +} + + +//! Returns type of video driver +E_DRIVER_TYPE CBurningVideoDriver::getDriverType() const +{ + return EDT_BURNINGSVIDEO; +} + + +//! returns color format +ECOLOR_FORMAT CBurningVideoDriver::getColorFormat() const +{ + return BURNINGSHADER_COLOR_FORMAT; +} + + +//! Returns the transformation set by setTransform +const core::matrix4& CBurningVideoDriver::getTransform(E_TRANSFORMATION_STATE state) const +{ + return Transformation[state]; +} + + +//! Creates a render target texture. +ITexture* CBurningVideoDriver::addRenderTargetTexture(const core::dimension2d& size, + const io::path& name, const ECOLOR_FORMAT format) +{ + IImage* img = createImage(BURNINGSHADER_COLOR_FORMAT, size); + ITexture* tex = new CSoftwareTexture2(img, name, CSoftwareTexture2::IS_RENDERTARGET ); + img->drop(); + addTexture(tex); + tex->drop(); + return tex; +} + +void CBurningVideoDriver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil) +{ + if ((flag & ECBF_COLOR) && RenderTargetSurface) + RenderTargetSurface->fill(color); + + if ((flag & ECBF_DEPTH) && DepthBuffer) + DepthBuffer->clear(); + + if ((flag & ECBF_STENCIL) && StencilBuffer) + StencilBuffer->clear(); +} + + +//! Returns an image created from the last rendered frame. +IImage* CBurningVideoDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target) +{ + if (target != video::ERT_FRAME_BUFFER) + return 0; + + if (BackBuffer) + { + IImage* tmp = createImage(BackBuffer->getColorFormat(), BackBuffer->getDimension()); + BackBuffer->copyTo(tmp); + return tmp; + } + else + return 0; +} + +ITexture* CBurningVideoDriver::createDeviceDependentTexture(const io::path& name, IImage* image) +{ + CSoftwareTexture2* texture = new CSoftwareTexture2(image, name, (getTextureCreationFlag(ETCF_CREATE_MIP_MAPS) ? CSoftwareTexture2::GEN_MIPMAP : 0) | + (getTextureCreationFlag(ETCF_ALLOW_NON_POWER_2) ? 0 : CSoftwareTexture2::NP2_SIZE)); + + return texture; +} + +ITexture* CBurningVideoDriver::createDeviceDependentTextureCubemap(const io::path& name, const core::array& image) +{ + return 0; +} + +//! Returns the maximum amount of primitives (mostly vertices) which +//! the device is able to render with one drawIndexedTriangleList +//! call. +u32 CBurningVideoDriver::getMaximalPrimitiveCount() const +{ + return 0xFFFFFFFF; +} + + +//! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do +//! this: First, draw all geometry. Then use this method, to draw the shadow +//! volume. Next use IVideoDriver::drawStencilShadow() to visualize the shadow. +void CBurningVideoDriver::drawStencilShadowVolume(const core::array& triangles, bool zfail, u32 debugDataVisible) +{ + const u32 count = triangles.size(); + IBurningShader *shader = BurningShader [ ETR_STENCIL_SHADOW ]; + + CurrentShader = shader; + shader->setRenderTarget(RenderTargetSurface, ViewPort); + + Material.org.MaterialType = video::EMT_SOLID; + Material.org.Lighting = false; + Material.org.ZWriteEnable = video::EZW_OFF; + Material.org.ZBuffer = ECFN_LESSEQUAL; + LightSpace.Flags &= ~VERTEXTRANSFORM; + + //glStencilMask(~0); + //glStencilFunc(GL_ALWAYS, 0, ~0); + + if (true)// zpass does not work yet + { + Material.org.BackfaceCulling = true; + Material.org.FrontfaceCulling = false; + shader->setParam ( 0, 0 ); + shader->setParam ( 1, 1 ); + shader->setParam ( 2, 0 ); + drawVertexPrimitiveList (triangles.const_pointer(), count, 0, count/3, (video::E_VERTEX_TYPE) 4, scene::EPT_TRIANGLES, (video::E_INDEX_TYPE) 4 ); + //glStencilOp(GL_KEEP, incr, GL_KEEP); + //glDrawArrays(GL_TRIANGLES,0,count); + + Material.org.BackfaceCulling = false; + Material.org.FrontfaceCulling = true; + shader->setParam ( 0, 0 ); + shader->setParam ( 1, 2 ); + shader->setParam ( 2, 0 ); + drawVertexPrimitiveList (triangles.const_pointer(), count, 0, count/3, (video::E_VERTEX_TYPE) 4, scene::EPT_TRIANGLES, (video::E_INDEX_TYPE) 4 ); + //glStencilOp(GL_KEEP, decr, GL_KEEP); + //glDrawArrays(GL_TRIANGLES,0,count); + } + else // zpass + { + Material.org.BackfaceCulling = true; + Material.org.FrontfaceCulling = false; + shader->setParam ( 0, 0 ); + shader->setParam ( 1, 0 ); + shader->setParam ( 2, 1 ); + //glStencilOp(GL_KEEP, GL_KEEP, incr); + //glDrawArrays(GL_TRIANGLES,0,count); + + Material.org.BackfaceCulling = false; + Material.org.FrontfaceCulling = true; + shader->setParam ( 0, 0 ); + shader->setParam ( 1, 0 ); + shader->setParam ( 2, 2 ); + //glStencilOp(GL_KEEP, GL_KEEP, decr); + //glDrawArrays(GL_TRIANGLES,0,count); + } +} + +//! 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. +void CBurningVideoDriver::drawStencilShadow(bool clearStencilBuffer, video::SColor leftUpEdge, + video::SColor rightUpEdge, video::SColor leftDownEdge, video::SColor rightDownEdge) +{ + if (!StencilBuffer) + return; + // draw a shadow rectangle covering the entire screen using stencil buffer + const u32 h = RenderTargetSurface->getDimension().Height; + const u32 w = RenderTargetSurface->getDimension().Width; + tVideoSample *dst; + u32 *stencil; + u32* const stencilBase=(u32*) StencilBuffer->lock(); + + for ( u32 y = 0; y < h; ++y ) + { + dst = (tVideoSample*)RenderTargetSurface->getData() + ( y * w ); + stencil = stencilBase + ( y * w ); + + for ( u32 x = 0; x < w; ++x ) + { + if ( stencil[x] > 1 ) + { + dst[x] = PixelBlend32 ( dst[x], leftUpEdge.color ); + } + } + } + + StencilBuffer->clear(); +} + + +core::dimension2du CBurningVideoDriver::getMaxTextureSize() const +{ + return core::dimension2du(SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE, SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE); +} + +bool CBurningVideoDriver::queryTextureFormat(ECOLOR_FORMAT format) const +{ + return format == BURNINGSHADER_COLOR_FORMAT; +} + +bool CBurningVideoDriver::needsTransparentRenderPass(const irr::video::SMaterial& material) const +{ + return CNullDriver::needsTransparentRenderPass(material) || material.isTransparent(); +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + + +#if defined(_IRR_WINDOWS_) && defined(_IRR_COMPILE_WITH_BURNINGSVIDEO_) + #include + +struct dreadglobal +{ + DWORD dreadid; + HANDLE dread; + irr::video::CBurningVideoDriver *driver; + HANDLE sync; + + const irr::SIrrlichtCreationParameters* params; + irr::io::IFileSystem* io; + irr::video::IImagePresenter* presenter; +}; + +namespace +{ + dreadglobal burning_dread; +} + +DWORD WINAPI dreadFun( void *p) +{ + printf("Hi This is burning dread\n"); + burning_dread.driver = new irr::video::CBurningVideoDriver(*burning_dread.params, burning_dread.io, burning_dread.presenter); + + SetEvent (burning_dread.sync ); + while ( 1 ) + { + Sleep ( 1000 ); + } + return 0; +} + +#endif + +namespace irr +{ +namespace video +{ + +//! creates a video driver +IVideoDriver* createBurningVideoDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, video::IImagePresenter* presenter) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + + #ifdef _IRR_WINDOWS_ + burning_dread.sync = CreateEventA ( 0, 0, 0, "burnevent0" ); + burning_dread.params = ¶ms; + burning_dread.io = io; + burning_dread.presenter = presenter; + burning_dread.dread = CreateThread ( 0, 0, dreadFun, 0, 0, &burning_dread.dreadid ); + WaitForSingleObject (burning_dread.sync, INFINITE ); + return burning_dread.driver; + #else + return new CBurningVideoDriver(params, io, presenter); + #endif + + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + + +} // end namespace video +} // end namespace irr + diff --git a/source/Irrlicht/CSoftwareDriver2.h b/source/Irrlicht/CSoftwareDriver2.h new file mode 100644 index 00000000..3e9d2aaf --- /dev/null +++ b/source/Irrlicht/CSoftwareDriver2.h @@ -0,0 +1,292 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_VIDEO_2_SOFTWARE_H_INCLUDED__ +#define __C_VIDEO_2_SOFTWARE_H_INCLUDED__ + +#include "SoftwareDriver2_compile_config.h" +#include "IBurningShader.h" +#include "CNullDriver.h" +#include "CImage.h" +#include "os.h" +#include "irrString.h" +#include "SIrrCreationParameters.h" + +namespace irr +{ +namespace video +{ + class CBurningVideoDriver : public CNullDriver + { + public: + + //! constructor + CBurningVideoDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, video::IImagePresenter* presenter); + + //! destructor + virtual ~CBurningVideoDriver(); + + //! queries the features of the driver, returns true if feature is available + virtual bool queryFeature(E_VIDEO_DRIVER_FEATURE feature) const _IRR_OVERRIDE_; + + //! Create render target. + virtual IRenderTarget* addRenderTarget() _IRR_OVERRIDE_; + + //! sets transformation + virtual void setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) _IRR_OVERRIDE_; + + //! sets a material + virtual void setMaterial(const SMaterial& material) _IRR_OVERRIDE_; + + virtual bool setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor = SColor(255,0,0,0), + f32 clearDepth = 1.f, u8 clearStencil = 0) _IRR_OVERRIDE_; + + //! sets a viewport + virtual void setViewPort(const core::rect& area) _IRR_OVERRIDE_; + + virtual bool beginScene(u16 clearFlag, SColor clearColor = SColor(255,0,0,0), f32 clearDepth = 1.f, u8 clearStencil = 0, + const SExposedVideoData& videoData = SExposedVideoData(), core::rect* sourceRect = 0) _IRR_OVERRIDE_; + + virtual bool endScene() _IRR_OVERRIDE_; + + //! Only used by the internal engine. Used to notify the driver that + //! the window was resized. + virtual void OnResize(const core::dimension2d& size) _IRR_OVERRIDE_; + + //! returns size of the current render target + virtual const core::dimension2d& getCurrentRenderTargetSize() const _IRR_OVERRIDE_; + + //! deletes all dynamic lights there are + virtual void deleteAllDynamicLights() _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! 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) _IRR_OVERRIDE_; + + //! returns the maximal amount of dynamic lights the device can handle + virtual u32 getMaximalDynamicLightAmount() const _IRR_OVERRIDE_; + + //! 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. + virtual void setAmbientLight(const SColorf& color) _IRR_OVERRIDE_; + + //! draws a vertex primitive list + virtual void drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) _IRR_OVERRIDE_; + + //! 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. + 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) _IRR_OVERRIDE_; + + //! Draws a part of the texture into the rectangle. + 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) _IRR_OVERRIDE_; + + //! Draws a 3d line. + virtual void draw3DLine(const core::vector3df& start, + const core::vector3df& end, SColor color = SColor(255,255,255,255)) _IRR_OVERRIDE_; + + //! draw an 2d rectangle + virtual void draw2DRectangle(SColor color, const core::rect& pos, + const core::rect* clip = 0) _IRR_OVERRIDE_; + + //!Draws an 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) _IRR_OVERRIDE_; + + //! Draws a 2d line. + virtual void draw2DLine(const core::position2d& start, + const core::position2d& end, + SColor color=SColor(255,255,255,255)) _IRR_OVERRIDE_; + + //! Draws a single pixel + virtual void drawPixel(u32 x, u32 y, const SColor & color) _IRR_OVERRIDE_; + + //! \return Returns the name of the video driver. Example: In case of the DirectX8 + //! driver, it would return "Direct3D8.1". + virtual const wchar_t* getName() const _IRR_OVERRIDE_; + + //! Returns type of video driver + virtual E_DRIVER_TYPE getDriverType() const _IRR_OVERRIDE_; + + //! get color format of the current color buffer + virtual ECOLOR_FORMAT getColorFormat() const _IRR_OVERRIDE_; + + //! Returns the transformation set by setTransform + virtual const core::matrix4& getTransform(E_TRANSFORMATION_STATE state) const _IRR_OVERRIDE_; + + //! Creates a render target texture. + virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, + const io::path& name, const ECOLOR_FORMAT format = ECF_UNKNOWN) _IRR_OVERRIDE_; + + virtual void clearBuffers(u16 flag, SColor color = SColor(255,0,0,0), f32 depth = 1.f, u8 stencil = 0) _IRR_OVERRIDE_; + + //! Returns an image created from the last rendered frame. + virtual IImage* createScreenShot(video::ECOLOR_FORMAT format=video::ECF_UNKNOWN, video::E_RENDER_TARGET target=video::ERT_FRAME_BUFFER) _IRR_OVERRIDE_; + + //! Returns the maximum amount of primitives (mostly vertices) which + //! the device is able to render with one drawIndexedTriangleList + //! call. + virtual u32 getMaximalPrimitiveCount() const _IRR_OVERRIDE_; + + //! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do + //! this: First, draw all geometry. Then use this method, to draw the shadow + //! volume. Then, use IVideoDriver::drawStencilShadow() to visualize the shadow. + virtual void drawStencilShadowVolume(const core::array& triangles, bool zfail=true, u32 debugDataVisible=0) _IRR_OVERRIDE_; + + //! 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. + virtual void drawStencilShadow(bool clearStencilBuffer=false, + video::SColor leftUpEdge = video::SColor(0,0,0,0), + video::SColor rightUpEdge = video::SColor(0,0,0,0), + video::SColor leftDownEdge = video::SColor(0,0,0,0), + video::SColor rightDownEdge = video::SColor(0,0,0,0)) _IRR_OVERRIDE_; + + //! Returns the graphics card vendor name. + virtual core::stringc getVendorInfo() _IRR_OVERRIDE_; + + //! Returns the maximum texture size supported. + virtual core::dimension2du getMaxTextureSize() const _IRR_OVERRIDE_; + + //! Check if the driver supports creating textures with the given color format + virtual bool queryTextureFormat(ECOLOR_FORMAT format) const _IRR_OVERRIDE_; + + //! Used by some SceneNodes to check if a material should be rendered in the transparent render pass + virtual bool needsTransparentRenderPass(const irr::video::SMaterial& material) const _IRR_OVERRIDE_; + + IDepthBuffer * getDepthBuffer () { return DepthBuffer; } + IStencilBuffer * getStencilBuffer () { return StencilBuffer; } + + protected: + + //! sets a render target + void setRenderTargetImage(video::CImage* image); + + //! sets the current Texture + //bool setTexture(u32 stage, video::ITexture* texture); + + virtual ITexture* createDeviceDependentTexture(const io::path& name, IImage* image) _IRR_OVERRIDE_; + virtual ITexture* createDeviceDependentTextureCubemap(const io::path& name, const core::array& image) _IRR_OVERRIDE_; + + video::CImage* BackBuffer; + video::IImagePresenter* Presenter; + + void* WindowId; + core::rect* SceneSourceRect; + + video::ITexture* RenderTargetTexture; + video::IImage* RenderTargetSurface; + core::dimension2d RenderTargetSize; + + //! selects the right triangle renderer based on the render states. + void setCurrentShader(); + + IBurningShader* CurrentShader; + IBurningShader* BurningShader[ETR2_COUNT]; + + IDepthBuffer* DepthBuffer; + IStencilBuffer* StencilBuffer; + + + /* + extend Matrix Stack + -> combined CameraProjection + -> combined CameraProjectionWorld + -> ClipScale from NDC to DC Space + */ + enum E_TRANSFORMATION_STATE_BURNING_VIDEO + { + ETS_VIEW_PROJECTION = ETS_COUNT, + ETS_CURRENT, + ETS_CLIPSCALE, + ETS_VIEW_INVERSE, + ETS_WORLD_INVERSE, + + ETS_COUNT_BURNING + }; + + enum E_TRANSFORMATION_FLAG + { + ETF_IDENTITY = 1, + ETF_TEXGEN_CAMERA_NORMAL = 2, + ETF_TEXGEN_CAMERA_REFLECTION = 4, + }; + u32 TransformationFlag[ETS_COUNT_BURNING]; + core::matrix4 Transformation[ETS_COUNT_BURNING]; + + void getCameraPosWorldSpace (); + void getLightPosObjectSpace (); + + + // Vertex Cache + static const SVSize vSize[]; + + SVertexCache VertexCache; + + void VertexCache_reset (const void* vertices, u32 vertexCount, + const void* indices, u32 indexCount, + E_VERTEX_TYPE vType,scene::E_PRIMITIVE_TYPE pType, + E_INDEX_TYPE iType); + void VertexCache_get ( const s4DVertex ** face ); + void VertexCache_getbypass ( s4DVertex ** face ); + + void VertexCache_fill ( const u32 sourceIndex,const u32 destIndex ); + s4DVertex * VertexCache_getVertex ( const u32 sourceIndex ); + + + // culling & clipping + u32 clipToHyperPlane ( s4DVertex * dest, const s4DVertex * source, u32 inCount, const sVec4 &plane ); + u32 clipToFrustumTest ( const s4DVertex * v ) const; + u32 clipToFrustum ( s4DVertex *source, s4DVertex * temp, const u32 vIn ); + + +#ifdef SOFTWARE_DRIVER_2_LIGHTING + + void lightVertex ( s4DVertex *dest, u32 vertexargb ); + //! Sets the fog mode. + virtual void setFog(SColor color, E_FOG_TYPE fogType, f32 start, + f32 end, f32 density, bool pixelFog, bool rangeFog) _IRR_OVERRIDE_; +#endif + + + // holds transformed, clipped vertices + SAlignedVertex CurrentOut; + SAlignedVertex Temp; + + void ndc_2_dc_and_project ( s4DVertex *dest,s4DVertex *source, u32 vIn ) const; + f32 screenarea ( const s4DVertex *v0 ) const; + void select_polygon_mipmap ( s4DVertex *source, u32 vIn, u32 tex, const core::dimension2du& texSize ) const; + f32 texelarea ( const s4DVertex *v0, int tex ) const; + + + void ndc_2_dc_and_project2 ( const s4DVertex **v, const u32 size ) const; + f32 screenarea2 ( const s4DVertex **v ) const; + f32 texelarea2 ( const s4DVertex **v, int tex ) const; + void select_polygon_mipmap2 ( s4DVertex **source, u32 tex, const core::dimension2du& texSize ) const; + + + SBurningShaderLightSpace LightSpace; + SBurningShaderMaterial Material; + + static const sVec4 NDCPlane[6]; + }; + +} // end namespace video +} // end namespace irr + + +#endif + diff --git a/source/Irrlicht/CSoftwareTexture.cpp b/source/Irrlicht/CSoftwareTexture.cpp new file mode 100644 index 00000000..8a0b5077 --- /dev/null +++ b/source/Irrlicht/CSoftwareTexture.cpp @@ -0,0 +1,170 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_SOFTWARE_ + +#include "CSoftwareTexture.h" +#include "CSoftwareDriver.h" +#include "os.h" + +namespace irr +{ +namespace video +{ + +//! constructor +CSoftwareTexture::CSoftwareTexture(IImage* image, const io::path& name, bool renderTarget) + : ITexture(name, ETT_2D), Texture(0) +{ + #ifdef _DEBUG + setDebugName("CSoftwareTexture"); + #endif + + DriverType = EDT_SOFTWARE; + ColorFormat = ECF_A1R5G5B5; + HasMipMaps = false; + IsRenderTarget = renderTarget; + + if (image) + { + bool IsCompressed = false; + + if(IImage::isCompressedFormat(image->getColorFormat())) + { + os::Printer::log("Texture compression not available.", ELL_ERROR); + IsCompressed = true; + } + + OriginalSize = image->getDimension(); + core::dimension2d optSize = OriginalSize.getOptimalSize(); + + Image = new CImage(ECF_A1R5G5B5, OriginalSize); + + if (!IsCompressed) + image->copyTo(Image); + + if (optSize == OriginalSize) + { + Texture = Image; + Texture->grab(); + } + else + { + Texture = new CImage(ECF_A1R5G5B5, optSize); + Image->copyToScaling(Texture); + } + + Size = Texture->getDimension(); + Pitch = Texture->getDimension().Width * 2; + } +} + + + +//! destructor +CSoftwareTexture::~CSoftwareTexture() +{ + if (Image) + Image->drop(); + + if (Texture) + Texture->drop(); +} + + + +//! lock function +void* CSoftwareTexture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel, u32 layer, E_TEXTURE_LOCK_FLAGS lockFlags) +{ + return Image->getData(); +} + + + +//! unlock function +void CSoftwareTexture::unlock() +{ + if (Image != Texture) + { + os::Printer::log("Performance warning, slow unlock of non power of 2 texture.", ELL_WARNING); + Image->copyToScaling(Texture); + } +} + + +//! returns unoptimized surface +CImage* CSoftwareTexture::getImage() +{ + return Image; +} + + +//! returns texture surface +CImage* CSoftwareTexture::getTexture() +{ + return Texture; +} + +void CSoftwareTexture::regenerateMipMapLevels(void* data, u32 layer) +{ + // our software textures don't have mip maps +} + + +/* Software Render Target */ + +CSoftwareRenderTarget::CSoftwareRenderTarget(CSoftwareDriver* driver) : Driver(driver) +{ + DriverType = EDT_SOFTWARE; + + Texture.set_used(1); + Texture[0] = 0; +} + +CSoftwareRenderTarget::~CSoftwareRenderTarget() +{ + if (Texture[0]) + Texture[0]->drop(); +} + +void CSoftwareRenderTarget::setTexture(const core::array& texture, ITexture* depthStencil, const core::array& cubeSurfaces) +{ + if (Texture != texture) + { + ITexture* prevTexture = Texture[0]; + + bool textureDetected = false; + + for (u32 i = 0; i < texture.size(); ++i) + { + if (texture[i] && texture[i]->getDriverType() == EDT_SOFTWARE) + { + Texture[0] = texture[i]; + Texture[0]->grab(); + textureDetected = true; + + break; + } + } + + if (prevTexture) + prevTexture->drop(); + + if (!textureDetected) + Texture[0] = 0; + } +} + +ITexture* CSoftwareRenderTarget::getTexture() const +{ + return Texture[0]; +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_SOFTWARE_ + diff --git a/source/Irrlicht/CSoftwareTexture.h b/source/Irrlicht/CSoftwareTexture.h new file mode 100644 index 00000000..5d6d97e4 --- /dev/null +++ b/source/Irrlicht/CSoftwareTexture.h @@ -0,0 +1,73 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_SOFTWARE_TEXTURE_H_INCLUDED__ +#define __C_SOFTWARE_TEXTURE_H_INCLUDED__ + +#include "ITexture.h" +#include "IRenderTarget.h" +#include "CImage.h" + +namespace irr +{ +namespace video +{ + +class CSoftwareDriver; + +/*! + interface for a Video Driver dependent Texture. +*/ +class CSoftwareTexture : public ITexture +{ +public: + + //! constructor + CSoftwareTexture(IImage* surface, const io::path& name, bool renderTarget=false); + + //! destructor + virtual ~CSoftwareTexture(); + + //! lock function + virtual void* lock(E_TEXTURE_LOCK_MODE mode = ETLM_READ_WRITE, u32 mipmapLevel=0, u32 layer = 0, E_TEXTURE_LOCK_FLAGS lockFlags = ETLF_FLIP_Y_UP_RTT) _IRR_OVERRIDE_; + + //! unlock function + virtual void unlock() _IRR_OVERRIDE_; + + //! returns unoptimized surface + virtual CImage* getImage(); + + //! returns texture surface + virtual CImage* getTexture(); + + virtual void regenerateMipMapLevels(void* data = 0, u32 layer = 0) _IRR_OVERRIDE_; + +private: + CImage* Image; + CImage* Texture; +}; + +/*! + interface for a Video Driver dependent render target. +*/ +class CSoftwareRenderTarget : public IRenderTarget +{ +public: + CSoftwareRenderTarget(CSoftwareDriver* driver); + virtual ~CSoftwareRenderTarget(); + + virtual void setTexture(const core::array& texture, ITexture* depthStencil, const core::array& cubeSurfaces) _IRR_OVERRIDE_; + + ITexture* getTexture() const; + +protected: + CSoftwareDriver* Driver; +}; + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CSoftwareTexture2.cpp b/source/Irrlicht/CSoftwareTexture2.cpp new file mode 100644 index 00000000..44a7e6be --- /dev/null +++ b/source/Irrlicht/CSoftwareTexture2.cpp @@ -0,0 +1,222 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +#include "SoftwareDriver2_compile_config.h" +#include "SoftwareDriver2_helper.h" +#include "CSoftwareTexture2.h" +#include "CSoftwareDriver2.h" +#include "os.h" + +namespace irr +{ +namespace video +{ + +//! constructor +CSoftwareTexture2::CSoftwareTexture2(IImage* image, const io::path& name, u32 flags) + : ITexture(name, ETT_2D), MipMapLOD(0), Flags ( flags ), OriginalFormat(video::ECF_UNKNOWN) +{ + #ifdef _DEBUG + setDebugName("CSoftwareTexture2"); + #endif + +#ifndef SOFTWARE_DRIVER_2_MIPMAPPING + Flags &= ~GEN_MIPMAP; +#endif + + DriverType = EDT_BURNINGSVIDEO; + ColorFormat = BURNINGSHADER_COLOR_FORMAT; + IsRenderTarget = (Flags & IS_RENDERTARGET) != 0; + + memset32 ( MipMap, 0, sizeof ( MipMap ) ); + + if (image) + { + bool IsCompressed = false; + + if (IImage::isCompressedFormat(image->getColorFormat())) + { + os::Printer::log("Texture compression not available.", ELL_ERROR); + IsCompressed = true; + } + + OriginalSize = image->getDimension(); + OriginalFormat = image->getColorFormat(); + + core::dimension2d optSize( + OriginalSize.getOptimalSize(0 != (Flags & NP2_SIZE), + false, true, + SOFTWARE_DRIVER_2_TEXTURE_MAXSIZE) + ); + + if (OriginalSize == optSize) + { + MipMap[0] = new CImage(BURNINGSHADER_COLOR_FORMAT, image->getDimension()); + + if (!IsCompressed) + image->copyTo(MipMap[0]); + } + else + { + char buf[256]; + core::stringw showName ( name ); + snprintf_irr ( buf, 256, "Burningvideo: Warning Texture %ls reformat %dx%d -> %dx%d,%d", + showName.c_str(), + OriginalSize.Width, OriginalSize.Height, optSize.Width, optSize.Height, + BURNINGSHADER_COLOR_FORMAT + ); + + OriginalSize = optSize; + os::Printer::log ( buf, ELL_WARNING ); + MipMap[0] = new CImage(BURNINGSHADER_COLOR_FORMAT, optSize); + + if (!IsCompressed) + image->copyToScalingBoxFilter ( MipMap[0],0, false ); + } + + Size = MipMap[MipMapLOD]->getDimension(); + Pitch = MipMap[MipMapLOD]->getPitch(); + + OrigImageDataSizeInPixels = (f32) 0.3f * MipMap[0]->getImageDataSizeInPixels(); + + HasMipMaps = (Flags & GEN_MIPMAP) != 0; + + regenerateMipMapLevels(image->getMipMapsData()); + } +} + + +//! destructor +CSoftwareTexture2::~CSoftwareTexture2() +{ + for ( s32 i = 0; i!= SOFTWARE_DRIVER_2_MIPMAPPING_MAX; ++i ) + { + if ( MipMap[i] ) + MipMap[i]->drop(); + } +} + + +//! Regenerates the mip map levels of the texture. Useful after locking and +//! modifying the texture +void CSoftwareTexture2::regenerateMipMapLevels(void* data, u32 layer) +{ + if (!hasMipMaps()) + return; + + s32 i; + + // release + for ( i = 1; i < SOFTWARE_DRIVER_2_MIPMAPPING_MAX; ++i ) + { + if ( MipMap[i] ) + MipMap[i]->drop(); + } + + core::dimension2d newSize; + core::dimension2d origSize = Size; + + for (i=1; i < SOFTWARE_DRIVER_2_MIPMAPPING_MAX; ++i) + { + newSize = MipMap[i-1]->getDimension(); + newSize.Width = core::s32_max ( 1, newSize.Width >> SOFTWARE_DRIVER_2_MIPMAPPING_SCALE ); + newSize.Height = core::s32_max ( 1, newSize.Height >> SOFTWARE_DRIVER_2_MIPMAPPING_SCALE ); + origSize.Width = core::s32_max(1, origSize.Width >> 1); + origSize.Height = core::s32_max(1, origSize.Height >> 1); + + if (data) + { + if (OriginalFormat != BURNINGSHADER_COLOR_FORMAT) + { + IImage* tmpImage = new CImage(OriginalFormat, origSize, data, true, false); + MipMap[i] = new CImage(BURNINGSHADER_COLOR_FORMAT, newSize); + if (origSize==newSize) + tmpImage->copyTo(MipMap[i]); + else + tmpImage->copyToScalingBoxFilter(MipMap[i]); + tmpImage->drop(); + } + else + { + if (origSize==newSize) + MipMap[i] = new CImage(BURNINGSHADER_COLOR_FORMAT, newSize, data, false); + else + { + MipMap[i] = new CImage(BURNINGSHADER_COLOR_FORMAT, newSize); + IImage* tmpImage = new CImage(BURNINGSHADER_COLOR_FORMAT, origSize, data, true, false); + tmpImage->copyToScalingBoxFilter(MipMap[i]); + tmpImage->drop(); + } + } + data = (u8*)data +origSize.getArea()*IImage::getBitsPerPixelFromFormat(OriginalFormat)/8; + } + else + { + MipMap[i] = new CImage(BURNINGSHADER_COLOR_FORMAT, newSize); + + //static u32 color[] = { 0, 0xFFFF0000, 0xFF00FF00,0xFF0000FF,0xFFFFFF00,0xFFFF00FF,0xFF00FFFF,0xFF0F0F0F }; + MipMap[i]->fill ( 0 ); + MipMap[0]->copyToScalingBoxFilter( MipMap[i], 0, false ); + } + } +} + + +/* Software Render Target 2 */ + +CSoftwareRenderTarget2::CSoftwareRenderTarget2(CBurningVideoDriver* driver) : Driver(driver) +{ + DriverType = EDT_BURNINGSVIDEO; + + Texture.set_used(1); + Texture[0] = 0; +} + +CSoftwareRenderTarget2::~CSoftwareRenderTarget2() +{ + if (Texture[0]) + Texture[0]->drop(); +} + +void CSoftwareRenderTarget2::setTexture(const core::array& texture, ITexture* depthStencil, const core::array& cubeSurfaces) +{ + if (Texture != texture) + { + ITexture* prevTexture = Texture[0]; + + bool textureDetected = false; + + for (u32 i = 0; i < texture.size(); ++i) + { + if (texture[i] && texture[i]->getDriverType() == EDT_BURNINGSVIDEO) + { + Texture[0] = texture[i]; + Texture[0]->grab(); + textureDetected = true; + + break; + } + } + + if (prevTexture) + prevTexture->drop(); + + if (!textureDetected) + Texture[0] = 0; + } +} + +ITexture* CSoftwareRenderTarget2::getTexture() const +{ + return Texture[0]; +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ diff --git a/source/Irrlicht/CSoftwareTexture2.h b/source/Irrlicht/CSoftwareTexture2.h new file mode 100644 index 00000000..ac3c1fc5 --- /dev/null +++ b/source/Irrlicht/CSoftwareTexture2.h @@ -0,0 +1,111 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_SOFTWARE_2_TEXTURE_H_INCLUDED__ +#define __C_SOFTWARE_2_TEXTURE_H_INCLUDED__ + +#include "SoftwareDriver2_compile_config.h" + +#include "ITexture.h" +#include "IRenderTarget.h" +#include "CImage.h" + +namespace irr +{ +namespace video +{ + +class CBurningVideoDriver; + +/*! + interface for a Video Driver dependent Texture. +*/ +class CSoftwareTexture2 : public ITexture +{ +public: + + //! constructor + enum eTex2Flags + { + GEN_MIPMAP = 1, + IS_RENDERTARGET = 2, + NP2_SIZE = 4, + }; + CSoftwareTexture2(IImage* surface, const io::path& name, u32 flags); + + //! destructor + virtual ~CSoftwareTexture2(); + + //! lock function + virtual void* lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel, u32 layer, E_TEXTURE_LOCK_FLAGS lockFlags = ETLF_FLIP_Y_UP_RTT) _IRR_OVERRIDE_ + { + if (Flags & GEN_MIPMAP) + { + MipMapLOD = mipmapLevel; + Size = MipMap[MipMapLOD]->getDimension(); + Pitch = MipMap[MipMapLOD]->getPitch(); + } + + return MipMap[MipMapLOD]->getData(); + } + + //! unlock function + virtual void unlock() _IRR_OVERRIDE_ + { + } + + //! Returns the size of the largest mipmap. + f32 getLODFactor( const f32 texArea ) const + { + return OrigImageDataSizeInPixels * texArea; + //return MipMap[0]->getImageDataSizeInPixels () * texArea; + } + + //! returns unoptimized surface + virtual CImage* getImage() const + { + return MipMap[0]; + } + + //! returns texture surface + virtual CImage* getTexture() const + { + return MipMap[MipMapLOD]; + } + + virtual void regenerateMipMapLevels(void* data = 0, u32 layer = 0) _IRR_OVERRIDE_; + +private: + f32 OrigImageDataSizeInPixels; + + CImage * MipMap[SOFTWARE_DRIVER_2_MIPMAPPING_MAX]; + + u32 MipMapLOD; + u32 Flags; + ECOLOR_FORMAT OriginalFormat; +}; + +/*! +interface for a Video Driver dependent render target. +*/ +class CSoftwareRenderTarget2 : public IRenderTarget +{ +public: + CSoftwareRenderTarget2(CBurningVideoDriver* driver); + virtual ~CSoftwareRenderTarget2(); + + virtual void setTexture(const core::array& texture, ITexture* depthStencil, const core::array& cubeSurfaces) _IRR_OVERRIDE_; + + ITexture* getTexture() const; + +protected: + CBurningVideoDriver* Driver; +}; + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CSphereSceneNode.cpp b/source/Irrlicht/CSphereSceneNode.cpp new file mode 100644 index 00000000..1693f5e2 --- /dev/null +++ b/source/Irrlicht/CSphereSceneNode.cpp @@ -0,0 +1,206 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_SPHERE_SCENENODE_ +#include "CSphereSceneNode.h" +#include "IVideoDriver.h" +#include "ISceneManager.h" +#include "S3DVertex.h" +#include "os.h" +#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ +#include "CShadowVolumeSceneNode.h" +#else +#include "IShadowVolumeSceneNode.h" +#endif // _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ + +namespace irr +{ +namespace scene +{ + +//! constructor +CSphereSceneNode::CSphereSceneNode(f32 radius, u32 polyCountX, u32 polyCountY, ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position, const core::vector3df& rotation, const core::vector3df& scale) +: IMeshSceneNode(parent, mgr, id, position, rotation, scale), Mesh(0), Shadow(0), + Radius(radius), PolyCountX(polyCountX), PolyCountY(polyCountY) +{ + #ifdef _DEBUG + setDebugName("CSphereSceneNode"); + #endif + + Mesh = SceneManager->getGeometryCreator()->createSphereMesh(radius, polyCountX, polyCountY); +} + + + +//! destructor +CSphereSceneNode::~CSphereSceneNode() +{ + if (Shadow) + Shadow->drop(); + if (Mesh) + Mesh->drop(); +} + + +//! renders the node. +void CSphereSceneNode::render() +{ + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + + if (Mesh && driver) + { + driver->setMaterial(Mesh->getMeshBuffer(0)->getMaterial()); + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + if (Shadow) + Shadow->updateShadowVolumes(); + + driver->drawMeshBuffer(Mesh->getMeshBuffer(0)); + if ( DebugDataVisible & scene::EDS_BBOX ) + { + video::SMaterial m; + m.Lighting = false; + driver->setMaterial(m); + driver->draw3DBox(Mesh->getMeshBuffer(0)->getBoundingBox(), video::SColor(255,255,255,255)); + } + } +} + + +//! Removes a child from this scene node. +//! Implemented here, to be able to remove the shadow properly, if there is one, +//! or to remove attached child. +bool CSphereSceneNode::removeChild(ISceneNode* child) +{ + if (child && Shadow == child) + { + Shadow->drop(); + Shadow = 0; + } + + return ISceneNode::removeChild(child); +} + + +//! Creates shadow volume scene node as child of this node +//! and returns a pointer to it. +IShadowVolumeSceneNode* CSphereSceneNode::addShadowVolumeSceneNode( + const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity) +{ +#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_ + if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER)) + return 0; + + if (!shadowMesh) + shadowMesh = Mesh; // if null is given, use the mesh of node + + if (Shadow) + Shadow->drop(); + + Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity); + return Shadow; +#else + return 0; +#endif +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CSphereSceneNode::getBoundingBox() const +{ + return Mesh ? Mesh->getBoundingBox() : Box; +} + + +void CSphereSceneNode::OnRegisterSceneNode() +{ + if (IsVisible) + SceneManager->registerNodeForRendering(this); + + ISceneNode::OnRegisterSceneNode(); +} + + +//! returns the material based on the zero based index i. +video::SMaterial& CSphereSceneNode::getMaterial(u32 i) +{ + if (i>0 || !Mesh) + return ISceneNode::getMaterial(i); + else + return Mesh->getMeshBuffer(i)->getMaterial(); +} + + +//! returns amount of materials used by this scene node. +u32 CSphereSceneNode::getMaterialCount() const +{ + return 1; +} + + +//! Writes attributes of the scene node. +void CSphereSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + ISceneNode::serializeAttributes(out, options); + + out->addFloat("Radius", Radius); + out->addInt("PolyCountX", PolyCountX); + out->addInt("PolyCountY", PolyCountY); +} + + +//! Reads attributes of the scene node. +void CSphereSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + f32 oldRadius = Radius; + u32 oldPolyCountX = PolyCountX; + u32 oldPolyCountY = PolyCountY; + + Radius = in->getAttributeAsFloat("Radius"); + PolyCountX = in->getAttributeAsInt("PolyCountX"); + PolyCountY = in->getAttributeAsInt("PolyCountY"); + // legacy values read for compatibility with older versions + u32 polyCount = in->getAttributeAsInt("PolyCount"); + if (PolyCountX ==0 && PolyCountY == 0) + PolyCountX = PolyCountY = polyCount; + + Radius = core::max_(Radius, 0.0001f); + + if ( !core::equals(Radius, oldRadius) || PolyCountX != oldPolyCountX || PolyCountY != oldPolyCountY) + { + if (Mesh) + Mesh->drop(); + Mesh = SceneManager->getGeometryCreator()->createSphereMesh(Radius, PolyCountX, PolyCountY); + } + + ISceneNode::deserializeAttributes(in, options); +} + +//! Creates a clone of this scene node and its children. +ISceneNode* CSphereSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager) +{ + if (!newParent) + newParent = Parent; + if (!newManager) + newManager = SceneManager; + + CSphereSceneNode* nb = new CSphereSceneNode(Radius, PolyCountX, PolyCountY, newParent, + newManager, ID, RelativeTranslation); + + nb->cloneMembers(this, newManager); + nb->getMaterial(0) = Mesh->getMeshBuffer(0)->getMaterial(); + nb->Shadow = Shadow; + if ( nb->Shadow ) + nb->Shadow->grab(); + + if ( newParent ) + nb->drop(); + return nb; +} + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_SPHERE_SCENENODE_ diff --git a/source/Irrlicht/CSphereSceneNode.h b/source/Irrlicht/CSphereSceneNode.h new file mode 100644 index 00000000..480881cb --- /dev/null +++ b/source/Irrlicht/CSphereSceneNode.h @@ -0,0 +1,96 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_SPHERE_SCENE_NODE_H_INCLUDED__ +#define __C_SPHERE_SCENE_NODE_H_INCLUDED__ + +#include "IMeshSceneNode.h" +#include "IMesh.h" + +namespace irr +{ +namespace scene +{ + class CSphereSceneNode : public IMeshSceneNode + { + public: + + //! constructor + CSphereSceneNode(f32 size, u32 polyCountX, u32 polyCountY, ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)); + + //! destructor + virtual ~CSphereSceneNode(); + + virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; + + //! renders the node. + virtual void render() _IRR_OVERRIDE_; + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + //! returns the material based on the zero based index i. To get the amount + //! of materials used by this scene node, use getMaterialCount(). + //! This function is needed for inserting the node into the scene hierarchy on a + //! optimal position for minimizing renderstate changes, but can also be used + //! to directly modify the material of a scene node. + virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_; + + //! returns amount of materials used by this scene node. + virtual u32 getMaterialCount() const _IRR_OVERRIDE_; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_SPHERE; } + + //! Writes attributes of the scene node. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! Creates a clone of this scene node and its children. + virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + //! The mesh cannot be changed + virtual void setMesh(IMesh* mesh) _IRR_OVERRIDE_ {} + + //! Returns the current mesh + virtual IMesh* getMesh() _IRR_OVERRIDE_ { return Mesh; } + + //! Sets if the scene node should not copy the materials of the mesh but use them in a read only style. + /* In this way it is possible to change the materials a mesh causing all mesh scene nodes + referencing this mesh to change too. */ + virtual void setReadOnlyMaterials(bool readonly) _IRR_OVERRIDE_ {} + + //! Returns if the scene node should not copy the materials of the mesh but use them in a read only style + virtual bool isReadOnlyMaterials() const _IRR_OVERRIDE_ { return false; } + + //! Creates shadow volume scene node as child of this node + //! and returns a pointer to it. + virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh, + s32 id, bool zfailmethod=true, f32 infinity=10000.0f) _IRR_OVERRIDE_; + + //! Removes a child from this scene node. + //! Implemented here, to be able to remove the shadow properly, if there is one, + //! or to remove attached child. + virtual bool removeChild(ISceneNode* child) _IRR_OVERRIDE_; + + private: + + IMesh* Mesh; + IShadowVolumeSceneNode* Shadow; + core::aabbox3d Box; + f32 Radius; + u32 PolyCountX; + u32 PolyCountY; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CTRFlat.cpp b/source/Irrlicht/CTRFlat.cpp new file mode 100644 index 00000000..b3910b1a --- /dev/null +++ b/source/Irrlicht/CTRFlat.cpp @@ -0,0 +1,299 @@ +// Copyright (C) 2002-2012 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" +#include "CTRTextureGouraud.h" + +#ifdef _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + +class CTRFlat : public CTRTextureGouraud +{ +public: + + CTRFlat(IZBuffer* zbuffer) + : CTRTextureGouraud(zbuffer) + { + #ifdef _DEBUG + setDebugName("CTRFlat"); + #endif + } + + //! draws an indexed triangle list + virtual void drawIndexedTriangleList(S2DVertex* vertices, s32 vertexCount, const u16* indexList, s32 triangleCount) _IRR_OVERRIDE_ + { + const S2DVertex *v1, *v2, *v3; + + u16 color; + f32 tmpDiv; // temporary division factor + f32 longest; // saves the longest span + s32 height; // saves height of triangle + u16* targetSurface; // target pointer where to plot pixels + s32 spanEnd; // saves end of spans + f32 leftdeltaxf; // amount of pixels to increase on left side of triangle + f32 rightdeltaxf; // amount of pixels to increase on right side of triangle + s32 leftx, rightx; // position where we are + f32 leftxf, rightxf; // same as above, but as f32 values + s32 span; // current span + u16 *hSpanBegin, *hSpanEnd; // pointer used when plotting pixels + core::rect TriangleRect; + + s32 leftZValue, rightZValue; + s32 leftZStep, rightZStep; + s32 spanZValue, spanZStep; // ZValues when drawing a span + TZBufferType* zTarget, *spanZTarget; // target of ZBuffer; + + lockedSurface = (u16*)RenderTarget->getData(); + lockedZBuffer = ZBuffer->lock(); + + for (s32 i=0; iPos.X - v1->Pos.X) * (v3->Pos.Y - v2->Pos.Y)) - + ((v3->Pos.Y - v1->Pos.Y) * (v3->Pos.X - v2->Pos.X)); + + if (z < 0) + continue; + } + + //near plane clipping + + if (v1->ZValue<0 && v2->ZValue<0 && v3->ZValue<0) + continue; + + // sort for width for inscreen clipping + + if (v1->Pos.X > v2->Pos.X) swapVertices(&v1, &v2); + if (v1->Pos.X > v3->Pos.X) swapVertices(&v1, &v3); + if (v2->Pos.X > v3->Pos.X) swapVertices(&v2, &v3); + + if ((v1->Pos.X - v3->Pos.X) == 0) + continue; + + TriangleRect.UpperLeftCorner.X = v1->Pos.X; + TriangleRect.LowerRightCorner.X = v3->Pos.X; + + // sort for height for faster drawing. + + if (v1->Pos.Y > v2->Pos.Y) swapVertices(&v1, &v2); + if (v1->Pos.Y > v3->Pos.Y) swapVertices(&v1, &v3); + if (v2->Pos.Y > v3->Pos.Y) swapVertices(&v2, &v3); + + TriangleRect.UpperLeftCorner.Y = v1->Pos.Y; + TriangleRect.LowerRightCorner.Y = v3->Pos.Y; + + if (!TriangleRect.isRectCollided(ViewPortRect)) + continue; + + // calculate height of triangle + height = v3->Pos.Y - v1->Pos.Y; + if (!height) + continue; + + // calculate longest span + + longest = (v2->Pos.Y - v1->Pos.Y) / (f32)height * (v3->Pos.X - v1->Pos.X) + (v1->Pos.X - v2->Pos.X); + + spanEnd = v2->Pos.Y; + span = v1->Pos.Y; + leftxf = (f32)v1->Pos.X; + rightxf = (f32)v1->Pos.X; + + leftZValue = v1->ZValue; + rightZValue = v1->ZValue; + + color = v1->Color; + + targetSurface = lockedSurface + span * SurfaceWidth; + zTarget = lockedZBuffer + span * SurfaceWidth; + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + rightdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + rightZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); + + tmpDiv = 1.0f / (f32)height; + leftdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + leftZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (f32)height; + rightdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + rightZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); + + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + leftdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + leftZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); + } + + + // do it twice, once for the first half of the triangle, + // end then for the second half. + + for (s32 triangleHalf=0; triangleHalf<2; ++triangleHalf) + { + if (spanEnd > ViewPortRect.LowerRightCorner.Y) + spanEnd = ViewPortRect.LowerRightCorner.Y; + + // if the span <0, than we can skip these spans, + // and proceed to the next spans which are really on the screen. + if (span < ViewPortRect.UpperLeftCorner.Y) + { + // we'll use leftx as temp variable + if (spanEnd < ViewPortRect.UpperLeftCorner.Y) + { + leftx = spanEnd - span; + span = spanEnd; + } + else + { + leftx = ViewPortRect.UpperLeftCorner.Y - span; + span = ViewPortRect.UpperLeftCorner.Y; + } + + leftxf += leftdeltaxf*leftx; + rightxf += rightdeltaxf*leftx; + targetSurface += SurfaceWidth*leftx; + zTarget += SurfaceWidth*leftx; + leftZValue += leftZStep*leftx; + rightZValue += rightZStep*leftx; + } + + + // the main loop. Go through every span and draw it. + + while (span < spanEnd) + { + leftx = (s32)(leftxf); + rightx = (s32)(rightxf + 0.5f); + + // perform some clipping + + // TODO: clipping is not correct when leftx is clipped. + + if (leftxViewPortRect.LowerRightCorner.X) + leftx = ViewPortRect.LowerRightCorner.X; + + if (rightxViewPortRect.LowerRightCorner.X) + rightx = ViewPortRect.LowerRightCorner.X; + + // draw the span + + if (rightx - leftx != 0) + { + tmpDiv = 1.0f / (rightx - leftx); + spanZValue = leftZValue; + spanZStep = (s32)((rightZValue - leftZValue) * tmpDiv); + + hSpanBegin = targetSurface + leftx; + spanZTarget = zTarget + leftx; + hSpanEnd = targetSurface + rightx; + + while (hSpanBegin < hSpanEnd) + { + if (spanZValue > *spanZTarget) + { + *spanZTarget = spanZValue; + *hSpanBegin = color; + } + + spanZValue += spanZStep; + ++hSpanBegin; + ++spanZTarget; + } + } + + leftxf += leftdeltaxf; + rightxf += rightdeltaxf; + ++span; + targetSurface += SurfaceWidth; + zTarget += SurfaceWidth; + leftZValue += leftZStep; + rightZValue += rightZStep; + } + + if (triangleHalf>0) // break, we've gout only two halves + break; + + + // setup variables for second half of the triangle. + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + rightdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + rightxf = (f32)v2->Pos.X; + + rightZValue = v2->ZValue; + rightZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + leftdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + leftxf = (f32)v2->Pos.X; + + leftZValue = v2->ZValue; + leftZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); + } + + + spanEnd = v3->Pos.Y; + } + + } + + ZBuffer->unlock(); + } +}; + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + +//! creates a flat triangle renderer +ITriangleRenderer* createTriangleRendererFlat(IZBuffer* zbuffer) +{ + #ifdef _IRR_COMPILE_WITH_SOFTWARE_ + return new CTRFlat(zbuffer); + #else + return 0; + #endif // _IRR_COMPILE_WITH_SOFTWARE_ +} + +} // end namespace video +} // end namespace irr + + + diff --git a/source/Irrlicht/CTRFlatWire.cpp b/source/Irrlicht/CTRFlatWire.cpp new file mode 100644 index 00000000..2f1cca56 --- /dev/null +++ b/source/Irrlicht/CTRFlatWire.cpp @@ -0,0 +1,280 @@ +// Copyright (C) 2002-2012 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" +#include "CTRTextureGouraud.h" + +#ifdef _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + +class CTRFlatWire : public CTRTextureGouraud +{ +public: + + CTRFlatWire(IZBuffer* zbuffer) + : CTRTextureGouraud(zbuffer) + { + #ifdef _DEBUG + setDebugName("CTRWire"); + #endif + } + + //! draws an indexed triangle list + virtual void drawIndexedTriangleList(S2DVertex* vertices, s32 vertexCount, const u16* indexList, s32 triangleCount) _IRR_OVERRIDE_ + { + const S2DVertex *v1, *v2, *v3; + + u16 color; + f32 tmpDiv; // temporary division factor + f32 longest; // saves the longest span + s32 height; // saves height of triangle + u16* targetSurface; // target pointer where to plot pixels + s32 spanEnd; // saves end of spans + f32 leftdeltaxf; // amount of pixels to increase on left side of triangle + f32 rightdeltaxf; // amount of pixels to increase on right side of triangle + s32 leftx, rightx; // position where we are + f32 leftxf, rightxf; // same as above, but as f32 values + s32 span; // current span + core::rect TriangleRect; + + s32 leftZValue, rightZValue; + s32 leftZStep, rightZStep; + TZBufferType* zTarget; // target of ZBuffer; + + lockedSurface = (u16*)RenderTarget->getData(); + lockedZBuffer = ZBuffer->lock(); + + for (s32 i=0; iPos.X - v1->Pos.X) * (v3->Pos.Y - v2->Pos.Y)) - + ((v3->Pos.Y - v1->Pos.Y) * (v3->Pos.X - v2->Pos.X)); + + if (z < 0) + continue; + } + + //near plane clipping + + if (v1->ZValue<0 && v2->ZValue<0 && v3->ZValue<0) + continue; + + // sort for width for inscreen clipping + + if (v1->Pos.X > v2->Pos.X) swapVertices(&v1, &v2); + if (v1->Pos.X > v3->Pos.X) swapVertices(&v1, &v3); + if (v2->Pos.X > v3->Pos.X) swapVertices(&v2, &v3); + + if ((v1->Pos.X - v3->Pos.X) == 0) + continue; + + TriangleRect.UpperLeftCorner.X = v1->Pos.X; + TriangleRect.LowerRightCorner.X = v3->Pos.X; + + // sort for height for faster drawing. + + if (v1->Pos.Y > v2->Pos.Y) swapVertices(&v1, &v2); + if (v1->Pos.Y > v3->Pos.Y) swapVertices(&v1, &v3); + if (v2->Pos.Y > v3->Pos.Y) swapVertices(&v2, &v3); + + TriangleRect.UpperLeftCorner.Y = v1->Pos.Y; + TriangleRect.LowerRightCorner.Y = v3->Pos.Y; + + if (!TriangleRect.isRectCollided(ViewPortRect)) + continue; + + // calculate height of triangle + height = v3->Pos.Y - v1->Pos.Y; + if (!height) + continue; + + // calculate longest span + + longest = (v2->Pos.Y - v1->Pos.Y) / (f32)height * (v3->Pos.X - v1->Pos.X) + (v1->Pos.X - v2->Pos.X); + + spanEnd = v2->Pos.Y; + span = v1->Pos.Y; + leftxf = (f32)v1->Pos.X; + rightxf = (f32)v1->Pos.X; + + leftZValue = v1->ZValue; + rightZValue = v1->ZValue; + + color = v1->Color; + + targetSurface = lockedSurface + span * SurfaceWidth; + zTarget = lockedZBuffer + span * SurfaceWidth; + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + rightdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + rightZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); + + tmpDiv = 1.0f / (f32)height; + leftdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + leftZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (f32)height; + rightdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + rightZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); + + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + leftdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + leftZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); + } + + + // do it twice, once for the first half of the triangle, + // end then for the second half. + + for (s32 triangleHalf=0; triangleHalf<2; ++triangleHalf) + { + if (spanEnd > ViewPortRect.LowerRightCorner.Y) + spanEnd = ViewPortRect.LowerRightCorner.Y; + + // if the span <0, than we can skip these spans, + // and proceed to the next spans which are really on the screen. + if (span < ViewPortRect.UpperLeftCorner.Y) + { + // we'll use leftx as temp variable + if (spanEnd < ViewPortRect.UpperLeftCorner.Y) + { + leftx = spanEnd - span; + span = spanEnd; + } + else + { + leftx = ViewPortRect.UpperLeftCorner.Y - span; + span = ViewPortRect.UpperLeftCorner.Y; + } + + leftxf += leftdeltaxf*leftx; + rightxf += rightdeltaxf*leftx; + targetSurface += SurfaceWidth*leftx; + zTarget += SurfaceWidth*leftx; + leftZValue += leftZStep*leftx; + rightZValue += rightZStep*leftx; + } + + + // the main loop. Go through every span and draw it. + + while (span < spanEnd) + { + leftx = (s32)(leftxf); + rightx = (s32)(rightxf + 0.5f); + + // perform some clipping + + if (leftx>=ViewPortRect.UpperLeftCorner.X && + leftx<=ViewPortRect.LowerRightCorner.X) + { + if (leftZValue > *(zTarget + leftx)) + { + *(zTarget + leftx) = leftZValue; + *(targetSurface + leftx) = color; + } + } + + + if (rightx>=ViewPortRect.UpperLeftCorner.X && + rightx<=ViewPortRect.LowerRightCorner.X) + { + if (rightZValue > *(zTarget + rightx)) + { + *(zTarget + rightx) = rightZValue; + *(targetSurface + rightx) = color; + } + + } + + // draw the span + + leftxf += leftdeltaxf; + rightxf += rightdeltaxf; + ++span; + targetSurface += SurfaceWidth; + zTarget += SurfaceWidth; + leftZValue += leftZStep; + rightZValue += rightZStep; + } + + if (triangleHalf>0) // break, we've gout only two halves + break; + + + // setup variables for second half of the triangle. + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + rightdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + rightxf = (f32)v2->Pos.X; + + rightZValue = v2->ZValue; + rightZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + leftdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + leftxf = (f32)v2->Pos.X; + + leftZValue = v2->ZValue; + leftZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); + } + + + spanEnd = v3->Pos.Y; + } + + } + + ZBuffer->unlock(); + } +}; + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + +//! creates a flat triangle renderer +ITriangleRenderer* createTriangleRendererFlatWire(IZBuffer* zbuffer) +{ + #ifdef _IRR_COMPILE_WITH_SOFTWARE_ + return new CTRFlatWire(zbuffer); + #else + return 0; + #endif // _IRR_COMPILE_WITH_SOFTWARE_ +} + +} // end namespace video +} // end namespace irr + + diff --git a/source/Irrlicht/CTRGouraud.cpp b/source/Irrlicht/CTRGouraud.cpp new file mode 100644 index 00000000..830aa55a --- /dev/null +++ b/source/Irrlicht/CTRGouraud.cpp @@ -0,0 +1,357 @@ +// Copyright (C) 2002-2012 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" +#include "CTRTextureGouraud.h" + +#ifdef _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + + +class CTRGouraud : public CTRTextureGouraud +{ +public: + + CTRGouraud(IZBuffer* zbuffer) + : CTRTextureGouraud(zbuffer) + { + #ifdef _DEBUG + setDebugName("CTRGouraud"); + #endif + } + + //! draws an indexed triangle list + virtual void drawIndexedTriangleList(S2DVertex* vertices, s32 vertexCount, const u16* indexList, s32 triangleCount) _IRR_OVERRIDE_ + { + const S2DVertex *v1, *v2, *v3; + + f32 tmpDiv; // temporary division factor + f32 longest; // saves the longest span + s32 height; // saves height of triangle + u16* targetSurface; // target pointer where to plot pixels + s32 spanEnd; // saves end of spans + f32 leftdeltaxf; // amount of pixels to increase on left side of triangle + f32 rightdeltaxf; // amount of pixels to increase on right side of triangle + s32 leftx, rightx; // position where we are + f32 leftxf, rightxf; // same as above, but as f32 values + s32 span; // current span + u16 *hSpanBegin, *hSpanEnd; // pointer used when plotting pixels + s32 leftR, leftG, leftB, rightR, rightG, rightB; // color values + s32 leftStepR, leftStepG, leftStepB, + rightStepR, rightStepG, rightStepB; // color steps + s32 spanR, spanG, spanB, spanStepR, spanStepG, spanStepB; // color interpolating values while drawing a span. + + core::rect TriangleRect; + + s32 leftZValue, rightZValue; + s32 leftZStep, rightZStep; + s32 spanZValue, spanZStep; // ZValues when drawing a span + TZBufferType* zTarget, *spanZTarget; // target of ZBuffer; + + lockedSurface = (u16*)RenderTarget->getData(); + lockedZBuffer = ZBuffer->lock(); + + for (s32 i=0; iPos.X - v1->Pos.X) * (v3->Pos.Y - v2->Pos.Y)) - + ((v3->Pos.Y - v1->Pos.Y) * (v3->Pos.X - v2->Pos.X)); + + if (z < 0) + continue; + } + + //near plane clipping + + if (v1->ZValue<0 && v2->ZValue<0 && v3->ZValue<0) + continue; + + // sort for width for inscreen clipping + + if (v1->Pos.X > v2->Pos.X) swapVertices(&v1, &v2); + if (v1->Pos.X > v3->Pos.X) swapVertices(&v1, &v3); + if (v2->Pos.X > v3->Pos.X) swapVertices(&v2, &v3); + + if ((v1->Pos.X - v3->Pos.X) == 0) + continue; + + TriangleRect.UpperLeftCorner.X = v1->Pos.X; + TriangleRect.LowerRightCorner.X = v3->Pos.X; + + // sort for height for faster drawing. + + if (v1->Pos.Y > v2->Pos.Y) swapVertices(&v1, &v2); + if (v1->Pos.Y > v3->Pos.Y) swapVertices(&v1, &v3); + if (v2->Pos.Y > v3->Pos.Y) swapVertices(&v2, &v3); + + TriangleRect.UpperLeftCorner.Y = v1->Pos.Y; + TriangleRect.LowerRightCorner.Y = v3->Pos.Y; + + if (!TriangleRect.isRectCollided(ViewPortRect)) + continue; + + // calculate height of triangle + height = v3->Pos.Y - v1->Pos.Y; + if (!height) + continue; + + // calculate longest span + + longest = (v2->Pos.Y - v1->Pos.Y) / (f32)height * (v3->Pos.X - v1->Pos.X) + (v1->Pos.X - v2->Pos.X); + + spanEnd = v2->Pos.Y; + span = v1->Pos.Y; + leftxf = (f32)v1->Pos.X; + rightxf = (f32)v1->Pos.X; + + leftZValue = v1->ZValue; + rightZValue = v1->ZValue; + + leftR = rightR = video::getRed(v1->Color)<<11; + leftG = rightG = video::getGreen(v1->Color)<<11; + leftB = rightB = video::getBlue(v1->Color)<<11; + + targetSurface = lockedSurface + span * SurfaceWidth; + zTarget = lockedZBuffer + span * SurfaceWidth; + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + rightdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + rightZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); + rightStepR = (s32)(((s32)(video::getRed(v2->Color)<<11) - rightR) * tmpDiv); + rightStepG = (s32)(((s32)(video::getGreen(v2->Color)<<11) - rightG) * tmpDiv); + rightStepB = (s32)(((s32)(video::getBlue(v2->Color)<<11) - rightB) * tmpDiv); + + tmpDiv = 1.0f / (f32)height; + leftdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + leftZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); + leftStepR = (s32)(((s32)(video::getRed(v3->Color)<<11) - leftR) * tmpDiv); + leftStepG = (s32)(((s32)(video::getGreen(v3->Color)<<11) - leftG) * tmpDiv); + leftStepB = (s32)(((s32)(video::getBlue(v3->Color)<<11) - leftB) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (f32)height; + rightdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + rightZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); + rightStepR = (s32)(((s32)(video::getRed(v3->Color)<<11) - rightR) * tmpDiv); + rightStepG = (s32)(((s32)(video::getGreen(v3->Color)<<11) - rightG) * tmpDiv); + rightStepB = (s32)(((s32)(video::getBlue(v3->Color)<<11) - rightB) * tmpDiv); + + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + leftdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + leftZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); + leftStepR = (s32)(((s32)(video::getRed(v2->Color)<<11) - leftR) * tmpDiv); + leftStepG = (s32)(((s32)(video::getGreen(v2->Color)<<11) - leftG) * tmpDiv); + leftStepB = (s32)(((s32)(video::getBlue(v2->Color)<<11) - leftB) * tmpDiv); + } + + + // do it twice, once for the first half of the triangle, + // end then for the second half. + + for (s32 triangleHalf=0; triangleHalf<2; ++triangleHalf) + { + if (spanEnd > ViewPortRect.LowerRightCorner.Y) + spanEnd = ViewPortRect.LowerRightCorner.Y; + + // if the span <0, than we can skip these spans, + // and proceed to the next spans which are really on the screen. + if (span < ViewPortRect.UpperLeftCorner.Y) + { + // we'll use leftx as temp variable + if (spanEnd < ViewPortRect.UpperLeftCorner.Y) + { + leftx = spanEnd - span; + span = spanEnd; + } + else + { + leftx = ViewPortRect.UpperLeftCorner.Y - span; + span = ViewPortRect.UpperLeftCorner.Y; + } + + leftxf += leftdeltaxf*leftx; + rightxf += rightdeltaxf*leftx; + targetSurface += SurfaceWidth*leftx; + zTarget += SurfaceWidth*leftx; + leftZValue += leftZStep*leftx; + rightZValue += rightZStep*leftx; + + leftR += leftStepR*leftx; + leftG += leftStepG*leftx; + leftB += leftStepB*leftx; + rightR += rightStepR*leftx; + rightG += rightStepG*leftx; + rightB += rightStepB*leftx; + } + + + // the main loop. Go through every span and draw it. + + while (span < spanEnd) + { + leftx = (s32)(leftxf); + rightx = (s32)(rightxf + 0.5f); + + // perform some clipping + + // TODO: clipping is not correct when leftx is clipped. + + if (leftxViewPortRect.LowerRightCorner.X) + leftx = ViewPortRect.LowerRightCorner.X; + + if (rightxViewPortRect.LowerRightCorner.X) + rightx = ViewPortRect.LowerRightCorner.X; + + // draw the span + + if (rightx - leftx != 0) + { + tmpDiv = 1.0f / (rightx - leftx); + spanZValue = leftZValue; + spanZStep = (s32)((rightZValue - leftZValue) * tmpDiv); + + hSpanBegin = targetSurface + leftx; + spanZTarget = zTarget + leftx; + hSpanEnd = targetSurface + rightx; + + spanR = leftR; + spanG = leftG; + spanB = leftB; + spanStepR = (s32)((rightR - leftR) * tmpDiv); + spanStepG = (s32)((rightG - leftG) * tmpDiv); + spanStepB = (s32)((rightB - leftB) * tmpDiv); + + while (hSpanBegin < hSpanEnd) + { + if (spanZValue > *spanZTarget) + { + *spanZTarget = spanZValue; + *hSpanBegin = video::RGB16(spanR>>8, spanG>>8, spanB>>8); + } + + spanR += spanStepR; + spanG += spanStepG; + spanB += spanStepB; + + spanZValue += spanZStep; + ++hSpanBegin; + ++spanZTarget; + } + } + + leftxf += leftdeltaxf; + rightxf += rightdeltaxf; + ++span; + targetSurface += SurfaceWidth; + zTarget += SurfaceWidth; + leftZValue += leftZStep; + rightZValue += rightZStep; + + leftR += leftStepR; + leftG += leftStepG; + leftB += leftStepB; + rightR += rightStepR; + rightG += rightStepG; + rightB += rightStepB; + } + + if (triangleHalf>0) // break, we've gout only two halves + break; + + + // setup variables for second half of the triangle. + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + rightdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + rightxf = (f32)v2->Pos.X; + + rightZValue = v2->ZValue; + rightZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); + + rightR = video::getRed(v2->Color)<<11; + rightG = video::getGreen(v2->Color)<<11; + rightB = video::getBlue(v2->Color)<<11; + rightStepR = (s32)(((s32)(video::getRed(v3->Color)<<11) - rightR) * tmpDiv); + rightStepG = (s32)(((s32)(video::getGreen(v3->Color)<<11) - rightG) * tmpDiv); + rightStepB = (s32)(((s32)(video::getBlue(v3->Color)<<11) - rightB) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + leftdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + leftxf = (f32)v2->Pos.X; + + leftZValue = v2->ZValue; + leftZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); + + leftR = video::getRed(v2->Color)<<11; + leftG = video::getGreen(v2->Color)<<11; + leftB = video::getBlue(v2->Color)<<11; + leftStepR = (s32)(((s32)(video::getRed(v3->Color)<<11) - leftR) * tmpDiv); + leftStepG = (s32)(((s32)(video::getGreen(v3->Color)<<11) - leftG) * tmpDiv); + leftStepB = (s32)(((s32)(video::getBlue(v3->Color)<<11) - leftB) * tmpDiv); + } + + + spanEnd = v3->Pos.Y; + } + + } + + ZBuffer->unlock(); + } + +}; + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + +//! creates a flat triangle renderer +ITriangleRenderer* createTriangleRendererGouraud(IZBuffer* zbuffer) +{ + #ifdef _IRR_COMPILE_WITH_SOFTWARE_ + return new CTRGouraud(zbuffer); + #else + return 0; + #endif // _IRR_COMPILE_WITH_SOFTWARE_ +} + +} // end namespace video +} // end namespace irr + + diff --git a/source/Irrlicht/CTRGouraud2.cpp b/source/Irrlicht/CTRGouraud2.cpp new file mode 100644 index 00000000..194cc68b --- /dev/null +++ b/source/Irrlicht/CTRGouraud2.cpp @@ -0,0 +1,645 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 + +// define render case +#define SUBTEXEL +#define INVERSE_W + +#define USE_ZBUFFER +#define IPOL_W +#define CMP_W +#define WRITE_W + +#define IPOL_C0 +//#define IPOL_T0 +//#define IPOL_T1 + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #undef IPOL_C0 +#endif + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif + #define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + + +namespace irr +{ + +namespace video +{ + +class CTRGouraud2 : public IBurningShader +{ +public: + + //! constructor + CTRGouraud2(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + + +private: + void scanline_bilinear (); + sScanConvertData scan; + sScanLineData line; + +}; + +//! constructor +CTRGouraud2::CTRGouraud2(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRGouraud2"); + #endif +} + + + +/*! +*/ +void CTRGouraud2::scanline_bilinear () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + +#ifdef IPOL_C0 + tFixPoint r0, g0, b0; + +#ifdef INVERSE_W + f32 inversew; +#endif + +#endif + + for ( s32 i = 0; i <= dx; ++i ) + { +#ifdef CMP_Z + if ( line.z[0] < z[i] ) +#endif +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + + { +#ifdef IPOL_C0 +#ifdef INVERSE_W + inversew = core::reciprocal ( line.w[0] ); + + getSample_color ( r0, g0, b0, line.c[0][0] * inversew ); +#else + getSample_color ( r0, g0, b0, line.c[0][0] ); +#endif + + dst[i] = fix_to_color ( r0, g0, b0 ); +#else + dst[i] = COLOR_BRIGHT_WHITE; +#endif + +#ifdef WRITE_Z + z[i] = line.z[0]; +#endif +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + + } + +#ifdef IPOL_Z + line.z[0] += slopeZ; +#endif +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1]; +#endif + } + +} + +void CTRGouraud2::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + // sort on height, y + if ( a->Pos.y > b->Pos.y ) swapVertexPointer(&a, &b); + if ( a->Pos.y > c->Pos.y ) swapVertexPointer(&a, &c); + if ( b->Pos.y > c->Pos.y ) swapVertexPointer(&b, &c); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) ) + return; + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0][0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + + // rasterize upper sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[1] ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[0][1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + // rasterize lower sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[2] ) + { + // advance to middle point + if( (f32) 0.0 != scan.invDeltaY[1] ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0][0] = a->Color[0] + scan.slopeC[0][0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[0][1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + +//! creates a flat triangle renderer +IBurningShader* createTriangleRendererGouraud2(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRGouraud2(driver); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + + diff --git a/source/Irrlicht/CTRGouraudAlpha2.cpp b/source/Irrlicht/CTRGouraudAlpha2.cpp new file mode 100644 index 00000000..837ab3e4 --- /dev/null +++ b/source/Irrlicht/CTRGouraudAlpha2.cpp @@ -0,0 +1,657 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 + +// define render case +#define SUBTEXEL +#define INVERSE_W + +#define USE_ZBUFFER +#define IPOL_W +#define CMP_W +#define WRITE_W + +#define IPOL_C0 +//#define IPOL_T0 +//#define IPOL_T1 + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #undef IPOL_C0 +#endif + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif + #define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + + + +namespace irr +{ + +namespace video +{ + +class CTRGouraudAlpha2 : public IBurningShader +{ +public: + + //! constructor + CTRGouraudAlpha2(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + + +private: + void scanline_bilinear (); + + sScanConvertData scan; + sScanLineData line; + +}; + +//! constructor +CTRGouraudAlpha2::CTRGouraudAlpha2(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRGouraudAlpha2"); + #endif +} + + + +/*! +*/ +void CTRGouraudAlpha2::scanline_bilinear () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[0]; +#endif +#ifdef IPOL_T1 + sVec2 slopeT[1]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + +#ifdef IPOL_C0 + +#ifdef INVERSE_W + f32 inversew; +#endif + + tFixPoint a0; + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; + tFixPoint r2, g2, b2; +#endif + + for ( s32 i = 0; i <= dx; ++i ) + { +#ifdef CMP_Z + if ( line.z[0] < z[i] ) +#endif +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + + { +#ifdef IPOL_C0 +#ifdef INVERSE_W + inversew = core::reciprocal ( line.w[0] ); + + getSample_color ( a0, r0, g0, b0, line.c[0][0] * inversew ); +#else + getSample_color ( a0, r0, g0, b0, line.c[0][0] ); +#endif + + color_to_fix ( r1, g1, b1, dst[i] ); + + r2 = r1 + imulFix ( a0, r0 - r1 ); + g2 = g1 + imulFix ( a0, g0 - g1 ); + b2 = b1 + imulFix ( a0, b0 - b1 ); + + dst[i] = fix_to_color ( r2, g2, b2 ); +#else + dst[i] = COLOR_BRIGHT_WHITE; +#endif +#ifdef WRITE_Z + z[i] = line.z[0]; +#endif +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + + } + +#ifdef IPOL_Z + line.z[0] += slopeZ; +#endif +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1]; +#endif + } + +} + +void CTRGouraudAlpha2::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) ) + return; + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0][0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + + // rasterize upper sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[1] ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[0][1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear ( ); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + // rasterize lower sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[2] ) + { + // advance to middle point + if( (f32) 0.0 != scan.invDeltaY[1] ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0][0] = a->Color[0] + scan.slopeC[0][0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[0][1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear ( ); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + +} + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + +//! creates a flat triangle renderer +IBurningShader* createTriangleRendererGouraudAlpha2(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRGouraudAlpha2(driver); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + + diff --git a/source/Irrlicht/CTRGouraudAlphaNoZ2.cpp b/source/Irrlicht/CTRGouraudAlphaNoZ2.cpp new file mode 100644 index 00000000..b5453df0 --- /dev/null +++ b/source/Irrlicht/CTRGouraudAlphaNoZ2.cpp @@ -0,0 +1,654 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 + +// define render case +#define SUBTEXEL +//#define INVERSE_W + +//#define USE_ZBUFFER +//#define IPOL_W +//#define CMP_W +//#define WRITE_W + +#define IPOL_C0 +//#define IPOL_T0 +//#define IPOL_T1 + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #undef IPOL_C0 +#endif + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif + //#define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + + + +namespace irr +{ + +namespace video +{ + +class CTRGouraudAlphaNoZ2 : public IBurningShader +{ +public: + + //! constructor + CTRGouraudAlphaNoZ2(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + + +private: + void scanline_bilinear (); + sScanConvertData scan; + sScanLineData line; + +}; + +//! constructor +CTRGouraudAlphaNoZ2::CTRGouraudAlphaNoZ2(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRGouraudAlphaNoZ2"); + #endif +} + + + +/*! +*/ +void CTRGouraudAlphaNoZ2::scanline_bilinear () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + +#ifdef IPOL_C0 + +#ifdef INVERSE_W + f32 inversew; +#endif + + tFixPoint a0; + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; + tFixPoint r2, g2, b2; +#endif + + for ( s32 i = 0; i <= dx; ++i ) + { +#ifdef CMP_Z + if ( line.z[0] < z[i] ) +#endif +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + { + +#ifdef WRITE_Z + z[i] = line.z[0]; +#endif + +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef IPOL_C0 +#ifdef IPOL_W + inversew = core::reciprocal ( line.w[0] ); + + getSample_color ( a0, r0, g0, b0, line.c[0][0] * inversew ); +#else + getSample_color ( a0, r0, g0, b0, line.c[0][0] ); +#endif + + color_to_fix ( r1, g1, b1, dst[i] ); + + r2 = r1 + imulFix ( a0, r0 - r1 ); + g2 = g1 + imulFix ( a0, g0 - g1 ); + b2 = b1 + imulFix ( a0, b0 - b1 ); + + dst[i] = fix_to_color ( r2, g2, b2 ); +#else + dst[i] = COLOR_BRIGHT_WHITE; +#endif + + + } + +#ifdef IPOL_Z + line.z[0] += slopeZ; +#endif +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1]; +#endif + } + +} + +void CTRGouraudAlphaNoZ2::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) ) + return; + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0][0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + // rasterize upper sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[1] ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[0][1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + // rasterize lower sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[2] ) + { + // advance to middle point + if( (f32) 0.0 != scan.invDeltaY[1] ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0][0] = a->Color[0] + scan.slopeC[0][0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[0][1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + +} + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + +//! creates a flat triangle renderer +IBurningShader* createTRGouraudAlphaNoZ2(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRGouraudAlphaNoZ2(driver); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + diff --git a/source/Irrlicht/CTRGouraudWire.cpp b/source/Irrlicht/CTRGouraudWire.cpp new file mode 100644 index 00000000..fa3402c1 --- /dev/null +++ b/source/Irrlicht/CTRGouraudWire.cpp @@ -0,0 +1,325 @@ +// Copyright (C) 2002-2012 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" +#include "CTRTextureGouraud.h" + +#ifdef _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + +class CTRGouraudWire : public CTRTextureGouraud +{ +public: + + CTRGouraudWire(IZBuffer* zbuffer) + : CTRTextureGouraud(zbuffer) + { + #ifdef _DEBUG + setDebugName("CTRGouraudWire"); + #endif + } + + //! draws an indexed triangle list + virtual void drawIndexedTriangleList(S2DVertex* vertices, s32 vertexCount, const u16* indexList, s32 triangleCount) _IRR_OVERRIDE_ + { + const S2DVertex *v1, *v2, *v3; + + f32 tmpDiv; // temporary division factor + f32 longest; // saves the longest span + s32 height; // saves height of triangle + u16* targetSurface; // target pointer where to plot pixels + s32 spanEnd; // saves end of spans + f32 leftdeltaxf; // amount of pixels to increase on left side of triangle + f32 rightdeltaxf; // amount of pixels to increase on right side of triangle + s32 leftx, rightx; // position where we are + f32 leftxf, rightxf; // same as above, but as f32 values + s32 span; // current span + s32 leftR, leftG, leftB, rightR, rightG, rightB; // color values + s32 leftStepR, leftStepG, leftStepB, + rightStepR, rightStepG, rightStepB; // color steps + + core::rect TriangleRect; + + s32 leftZValue, rightZValue; + s32 leftZStep, rightZStep; + TZBufferType* zTarget; // target of ZBuffer; + + lockedSurface = (u16*)RenderTarget->getData(); + lockedZBuffer = ZBuffer->lock(); + + for (s32 i=0; iPos.X - v1->Pos.X) * (v3->Pos.Y - v2->Pos.Y)) - + ((v3->Pos.Y - v1->Pos.Y) * (v3->Pos.X - v2->Pos.X)); + + if (z < 0) + continue; + } + + //near plane clipping + + if (v1->ZValue<0 && v2->ZValue<0 && v3->ZValue<0) + continue; + + // sort for width for inscreen clipping + + if (v1->Pos.X > v2->Pos.X) swapVertices(&v1, &v2); + if (v1->Pos.X > v3->Pos.X) swapVertices(&v1, &v3); + if (v2->Pos.X > v3->Pos.X) swapVertices(&v2, &v3); + + if ((v1->Pos.X - v3->Pos.X) == 0) + continue; + + TriangleRect.UpperLeftCorner.X = v1->Pos.X; + TriangleRect.LowerRightCorner.X = v3->Pos.X; + + // sort for height for faster drawing. + + if (v1->Pos.Y > v2->Pos.Y) swapVertices(&v1, &v2); + if (v1->Pos.Y > v3->Pos.Y) swapVertices(&v1, &v3); + if (v2->Pos.Y > v3->Pos.Y) swapVertices(&v2, &v3); + + TriangleRect.UpperLeftCorner.Y = v1->Pos.Y; + TriangleRect.LowerRightCorner.Y = v3->Pos.Y; + + if (!TriangleRect.isRectCollided(ViewPortRect)) + continue; + + // calculate height of triangle + height = v3->Pos.Y - v1->Pos.Y; + if (!height) + continue; + + // calculate longest span + + longest = (v2->Pos.Y - v1->Pos.Y) / (f32)height * (v3->Pos.X - v1->Pos.X) + (v1->Pos.X - v2->Pos.X); + + spanEnd = v2->Pos.Y; + span = v1->Pos.Y; + leftxf = (f32)v1->Pos.X; + rightxf = (f32)v1->Pos.X; + + leftZValue = v1->ZValue; + rightZValue = v1->ZValue; + + leftR = rightR = video::getRed(v1->Color)<<11; + leftG = rightG = video::getGreen(v1->Color)<<11; + leftB = rightB = video::getBlue(v1->Color)<<11; + + targetSurface = lockedSurface + span * SurfaceWidth; + zTarget = lockedZBuffer + span * SurfaceWidth; + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + rightdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + rightZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); + rightStepR = (s32)(((s32)(video::getRed(v2->Color)<<11) - rightR) * tmpDiv); + rightStepG = (s32)(((s32)(video::getGreen(v2->Color)<<11) - rightG) * tmpDiv); + rightStepB = (s32)(((s32)(video::getBlue(v2->Color)<<11) - rightB) * tmpDiv); + + tmpDiv = 1.0f / (f32)height; + leftdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + leftZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); + leftStepR = (s32)(((s32)(video::getRed(v3->Color)<<11) - leftR) * tmpDiv); + leftStepG = (s32)(((s32)(video::getGreen(v3->Color)<<11) - leftG) * tmpDiv); + leftStepB = (s32)(((s32)(video::getBlue(v3->Color)<<11) - leftB) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (f32)height; + rightdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + rightZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); + rightStepR = (s32)(((s32)(video::getRed(v3->Color)<<11) - rightR) * tmpDiv); + rightStepG = (s32)(((s32)(video::getGreen(v3->Color)<<11) - rightG) * tmpDiv); + rightStepB = (s32)(((s32)(video::getBlue(v3->Color)<<11) - rightB) * tmpDiv); + + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + leftdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + leftZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); + leftStepR = (s32)(((s32)(video::getRed(v2->Color)<<11) - leftR) * tmpDiv); + leftStepG = (s32)(((s32)(video::getGreen(v2->Color)<<11) - leftG) * tmpDiv); + leftStepB = (s32)(((s32)(video::getBlue(v2->Color)<<11) - leftB) * tmpDiv); + } + + + // do it twice, once for the first half of the triangle, + // end then for the second half. + + for (s32 triangleHalf=0; triangleHalf<2; ++triangleHalf) + { + if (spanEnd > ViewPortRect.LowerRightCorner.Y) + spanEnd = ViewPortRect.LowerRightCorner.Y; + + // if the span <0, than we can skip these spans, + // and proceed to the next spans which are really on the screen. + if (span < ViewPortRect.UpperLeftCorner.Y) + { + // we'll use leftx as temp variable + if (spanEnd < ViewPortRect.UpperLeftCorner.Y) + { + leftx = spanEnd - span; + span = spanEnd; + } + else + { + leftx = ViewPortRect.UpperLeftCorner.Y - span; + span = ViewPortRect.UpperLeftCorner.Y; + } + + leftxf += leftdeltaxf*leftx; + rightxf += rightdeltaxf*leftx; + targetSurface += SurfaceWidth*leftx; + zTarget += SurfaceWidth*leftx; + leftZValue += leftZStep*leftx; + rightZValue += rightZStep*leftx; + + leftR += leftStepR*leftx; + leftG += leftStepG*leftx; + leftB += leftStepB*leftx; + rightR += rightStepR*leftx; + rightG += rightStepG*leftx; + rightB += rightStepB*leftx; + } + + + // the main loop. Go through every span and draw it. + + while (span < spanEnd) + { + leftx = (s32)(leftxf); + rightx = (s32)(rightxf + 0.5f); + + // perform some clipping + + if (leftx>=ViewPortRect.UpperLeftCorner.X && + leftx<=ViewPortRect.LowerRightCorner.X) + { + if (leftZValue > *(zTarget + leftx)) + { + *(zTarget + leftx) = leftZValue; + *(targetSurface + leftx) = video::RGB16(leftR>>8, leftG>>8, leftB>>8); + } + } + + + if (rightx>=ViewPortRect.UpperLeftCorner.X && + rightx<=ViewPortRect.LowerRightCorner.X) + { + if (rightZValue > *(zTarget + rightx)) + { + *(zTarget + rightx) = rightZValue; + *(targetSurface + rightx) = video::RGB16(rightR, rightG, rightB); + } + + } + + leftxf += leftdeltaxf; + rightxf += rightdeltaxf; + ++span; + targetSurface += SurfaceWidth; + zTarget += SurfaceWidth; + leftZValue += leftZStep; + rightZValue += rightZStep; + + leftR += leftStepR; + leftG += leftStepG; + leftB += leftStepB; + rightR += rightStepR; + rightG += rightStepG; + rightB += rightStepB; + } + + if (triangleHalf>0) // break, we've gout only two halves + break; + + + // setup variables for second half of the triangle. + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + rightdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + rightxf = (f32)v2->Pos.X; + + rightZValue = v2->ZValue; + rightZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); + + rightR = video::getRed(v2->Color)<<11; + rightG = video::getGreen(v2->Color)<<11; + rightB = video::getBlue(v2->Color)<<11; + rightStepR = (s32)(((s32)(video::getRed(v3->Color)<<11) - rightR) * tmpDiv); + rightStepG = (s32)(((s32)(video::getGreen(v3->Color)<<11) - rightG) * tmpDiv); + rightStepB = (s32)(((s32)(video::getBlue(v3->Color)<<11) - rightB) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + leftdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + leftxf = (f32)v2->Pos.X; + + leftZValue = v2->ZValue; + leftZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); + + leftR = video::getRed(v2->Color)<<11; + leftG = video::getGreen(v2->Color)<<11; + leftB = video::getBlue(v2->Color)<<11; + leftStepR = (s32)(((s32)(video::getRed(v3->Color)<<11) - leftR) * tmpDiv); + leftStepG = (s32)(((s32)(video::getGreen(v3->Color)<<11) - leftG) * tmpDiv); + leftStepB = (s32)(((s32)(video::getBlue(v3->Color)<<11) - leftB) * tmpDiv); + } + + + spanEnd = v3->Pos.Y; + } + + } + + ZBuffer->unlock(); + } + +}; + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + + +//! creates a flat triangle renderer +ITriangleRenderer* createTriangleRendererGouraudWire(IZBuffer* zbuffer) +{ + #ifdef _IRR_COMPILE_WITH_SOFTWARE_ + return new CTRGouraudWire(zbuffer); + #else + return 0; + #endif // _IRR_COMPILE_WITH_SOFTWARE_ +} + +} // end namespace video +} // end namespace irr + + diff --git a/source/Irrlicht/CTRNormalMap.cpp b/source/Irrlicht/CTRNormalMap.cpp new file mode 100644 index 00000000..bc72b75c --- /dev/null +++ b/source/Irrlicht/CTRNormalMap.cpp @@ -0,0 +1,847 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 +#undef IPOL_T2 +#undef IPOL_L0 + +// define render case +#define SUBTEXEL +#define INVERSE_W + +#define USE_ZBUFFER +#define IPOL_W +#define CMP_W +#define WRITE_W + +#define IPOL_C0 +#define IPOL_T0 +#define IPOL_T1 +#define IPOL_L0 + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #undef IPOL_C0 +#endif + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif + #define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + + +namespace irr +{ + +namespace video +{ + + +class CTRNormalMap : public IBurningShader +{ +public: + + //! constructor + CTRNormalMap(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + + +private: + void scanline_bilinear (); + + sScanConvertData scan; + sScanLineData line; + +}; + +//! constructor +CTRNormalMap::CTRNormalMap(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRNormalMap"); + #endif +} + + + +/*! +*/ +void CTRNormalMap::scanline_bilinear () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC[MATERIAL_MAX_COLORS]; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif +#ifdef IPOL_L0 + sVec3 slopeL[BURNING_MATERIAL_MAX_TANGENT]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC[0] = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif +#ifdef IPOL_T2 + slopeT[2] = (line.t[2][1] - line.t[2][0]) * invDeltaX; +#endif +#ifdef IPOL_L0 + slopeL[0] = (line.l[0][1] - line.l[0][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0] * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#ifdef IPOL_T2 + line.t[2][0] += slopeT[2] * subPixel; +#endif +#ifdef IPOL_L0 + line.l[0][0] += slopeL[0] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + f32 inversew; + + tFixPoint tx0, tx1; + tFixPoint ty0, ty1; + + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; + tFixPoint r2, g2, b2; + + tFixPoint lx, ly, lz; + tFixPoint ndotl; + + sVec3 light; + + +#ifdef IPOL_C0 + tFixPoint r3, g3, b3; +#endif + + for ( s32 i = 0; i <= dx; i++ ) + { +#ifdef CMP_Z + if ( line.z[0] < z[i] ) +#endif +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + { +#ifdef INVERSE_W + inversew = fix_inverse32 ( line.w[0] ); + + tx0 = tofix ( line.t[0][0].x,inversew); + ty0 = tofix ( line.t[0][0].y,inversew); + tx1 = tofix ( line.t[1][0].x,inversew); + ty1 = tofix ( line.t[1][0].y,inversew); + + +#ifdef IPOL_C0 + r3 = tofix ( line.c[0][0].y ,inversew ); + g3 = tofix ( line.c[0][0].z ,inversew ); + b3 = tofix ( line.c[0][0].w ,inversew ); +#endif + +#else + inversew = FIX_POINT_F32_MUL; + tx0 = tofix(line.t[0][0].x, inversew); + ty0 = tofix(line.t[0][0].y, inversew); + tx1 = tofix(line.t[1][0].x, inversew); + ty1 = tofix(line.t[1][0].y, inversew); + +#ifdef IPOL_C0 + r3 = tofix ( line.c[0][0].y ); + g3 = tofix ( line.c[0][0].z ); + b3 = tofix ( line.c[0][0].w ); +#endif + +#endif + getSample_texture ( r0, g0, b0, &IT[0], tx0, ty0 ); + + // normal map + getSample_texture ( r1, g1, b1, &IT[1], tx1, ty1 ); + + r1 = ( r1 - FIX_POINT_HALF_COLOR) >> (COLOR_MAX_LOG2-1); + g1 = ( g1 - FIX_POINT_HALF_COLOR) >> (COLOR_MAX_LOG2-1); + b1 = ( b1 - FIX_POINT_HALF_COLOR) >> (COLOR_MAX_LOG2-1); + +/* + sVec3 l = line.l[0][0] * inversew; + l.setLength( 2.f ); + + lx = tofix ( l.x - 0.5f ); + ly = tofix ( l.y - 0.5f ); + lz = tofix ( l.z - 0.5f ); +*/ + + lx = tofix ( line.l[0][0].x, inversew ); + ly = tofix ( line.l[0][0].y, inversew ); + lz = tofix ( line.l[0][0].z, inversew ); + + // DOT 3 Normal Map light in tangent space + ndotl = saturateFix ( FIX_POINT_HALF_COLOR + (( imulFix ( r1, lx ) + imulFix ( g1, ly ) + imulFix ( b1, lz ) ) << (COLOR_MAX_LOG2-1)) ); + +#ifdef IPOL_C0 + + // N . L + r2 = imulFix ( imulFix_tex1 ( r0, ndotl ), r3 ); + g2 = imulFix ( imulFix_tex1 ( g0, ndotl ), g3 ); + b2 = imulFix ( imulFix_tex1 ( b0, ndotl ), b3 ); + +/* + // heightmap: (1 - neu ) + alt - 0.5, on_minus_srcalpha + add signed + // emboss bump map + a4 -= a1; + r2 = clampfix_maxcolor ( clampfix_mincolor ( imulFix ( r0 + a4, r3 ) ) ); + g2 = clampfix_maxcolor ( clampfix_mincolor ( imulFix ( g0 + a4, g3 ) ) ); + b2 = clampfix_maxcolor ( clampfix_mincolor ( imulFix ( b0 + a4, b3 ) ) ); +*/ + +/* + r2 = clampfix_maxcolor ( imulFix_tex1 ( r2, r1 ) ); + g2 = clampfix_maxcolor ( imulFix_tex1 ( g2, g1 ) ); + b2 = clampfix_maxcolor ( imulFix_tex1 ( b2, b1 ) ); +*/ +#else + r2 = clampfix_maxcolor ( imulFix_tex4 ( r0, r1 ) ); + g2 = clampfix_maxcolor ( imulFix_tex4 ( g0, g1 ) ); + b2 = clampfix_maxcolor ( imulFix_tex4 ( b0, b1 ) ); +#endif + + + dst[i] = fix_to_color ( r2, g2, b2 ); + +#ifdef WRITE_Z + z[i] = line.z[0]; +#endif +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + } + +#ifdef IPOL_Z + line.z[0] += slopeZ; +#endif +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1]; +#endif +#ifdef IPOL_T2 + line.t[2][0] += slopeT[2]; +#endif +#ifdef IPOL_L0 + line.l[0][0] += slopeL[0]; +#endif + } + +} + +void CTRNormalMap::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) ) + return; + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0][0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + +#ifdef IPOL_T2 + scan.slopeT[2][0] = (c->Tex[2] - a->Tex[2]) * scan.invDeltaY[0]; + scan.t[2][0] = a->Tex[2]; +#endif + +#ifdef IPOL_L0 + scan.slopeL[0][0] = (c->LightTangent[0] - a->LightTangent[0]) * scan.invDeltaY[0]; + scan.l[0][0] = a->LightTangent[0]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + + // rasterize upper sub-triangle + //if ( (f32) 0.0 != scan.invDeltaY[1] ) + if ( F32_GREATER_0 ( scan.invDeltaY[1] ) ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[0][1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + +#ifdef IPOL_T2 + scan.slopeT[2][1] = (b->Tex[2] - a->Tex[2]) * scan.invDeltaY[1]; + scan.t[2][1] = a->Tex[2]; +#endif + +#ifdef IPOL_L0 + scan.slopeL[0][1] = (b->LightTangent[0] - a->LightTangent[0]) * scan.invDeltaY[1]; + scan.l[0][1] = a->LightTangent[0]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#ifdef IPOL_T2 + scan.t[2][0] += scan.slopeT[2][0] * subPixel; + scan.t[2][1] += scan.slopeT[2][1] * subPixel; +#endif + +#ifdef IPOL_L0 + scan.l[0][0] += scan.slopeL[0][0] * subPixel; + scan.l[0][1] += scan.slopeL[0][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + +#ifdef IPOL_T2 + line.t[2][scan.left] = scan.t[2][0]; + line.t[2][scan.right] = scan.t[2][1]; +#endif + +#ifdef IPOL_L0 + line.l[0][scan.left] = scan.l[0][0]; + line.l[0][scan.right] = scan.l[0][1]; +#endif + + // render a scanline + scanline_bilinear (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + +#ifdef IPOL_T2 + scan.t[2][0] += scan.slopeT[2][0]; + scan.t[2][1] += scan.slopeT[2][1]; +#endif + +#ifdef IPOL_L0 + scan.l[0][0] += scan.slopeL[0][0]; + scan.l[0][1] += scan.slopeL[0][1]; +#endif + + } + } + + // rasterize lower sub-triangle + //if ( (f32) 0.0 != scan.invDeltaY[2] ) + if ( F32_GREATER_0 ( scan.invDeltaY[2] ) ) + { + // advance to middle point + //if( (f32) 0.0 != scan.invDeltaY[1] ) + if ( F32_GREATER_0 ( scan.invDeltaY[1] ) ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0][0] = a->Color[0] + scan.slopeC[0][0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif +#ifdef IPOL_T2 + scan.t[2][0] = a->Tex[2] + scan.slopeT[2][0] * temp[0]; +#endif +#ifdef IPOL_L0 + scan.l[0][0] = a->LightTangent[0] + scan.slopeL[0][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[0][1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + +#ifdef IPOL_T2 + scan.slopeT[2][1] = (c->Tex[2] - b->Tex[2]) * scan.invDeltaY[2]; + scan.t[2][1] = b->Tex[2]; +#endif + +#ifdef IPOL_L0 + scan.slopeL[0][1] = (c->LightTangent[0] - b->LightTangent[0]) * scan.invDeltaY[2]; + scan.l[0][1] = b->LightTangent[0]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#ifdef IPOL_T2 + scan.t[2][0] += scan.slopeT[2][0] * subPixel; + scan.t[2][1] += scan.slopeT[2][1] * subPixel; +#endif + +#ifdef IPOL_L0 + scan.l[0][0] += scan.slopeL[0][0] * subPixel; + scan.l[0][1] += scan.slopeL[0][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + +#ifdef IPOL_T2 + line.t[2][scan.left] = scan.t[2][0]; + line.t[2][scan.right] = scan.t[2][1]; +#endif + +#ifdef IPOL_L0 + line.l[0][scan.left] = scan.l[0][0]; + line.l[0][scan.right] = scan.l[0][1]; +#endif + + // render a scanline + scanline_bilinear (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif +#ifdef IPOL_T2 + scan.t[2][0] += scan.slopeT[2][0]; + scan.t[2][1] += scan.slopeT[2][1]; +#endif + +#ifdef IPOL_L0 + scan.l[0][0] += scan.slopeL[0][0]; + scan.l[0][1] += scan.slopeL[0][1]; +#endif + + } + } + +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + + +//! creates a triangle renderer +IBurningShader* createTRNormalMap(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRNormalMap(driver); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + + diff --git a/source/Irrlicht/CTRStencilShadow.cpp b/source/Irrlicht/CTRStencilShadow.cpp new file mode 100644 index 00000000..02ed525d --- /dev/null +++ b/source/Irrlicht/CTRStencilShadow.cpp @@ -0,0 +1,930 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef USE_SBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 +#undef IPOL_T2 +#undef IPOL_L0 + +// define render case +#define SUBTEXEL +//#define INVERSE_W + +#define USE_ZBUFFER +#define USE_SBUFFER +#define IPOL_W +#define CMP_W +//#define WRITE_W + + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #undef IPOL_C0 +#endif + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif + #define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + + +namespace irr +{ + +namespace video +{ + +class CTRStencilShadow : public IBurningShader +{ +public: + + //! constructor + CTRStencilShadow(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + virtual void setParam ( u32 index, f32 value) _IRR_OVERRIDE_; + +private: + // fragment shader + typedef void (CTRStencilShadow::*tFragmentShader) (); + void fragment_zfail_decr (); + void fragment_zfail_incr (); + + tFragmentShader fragmentShader; + + sScanConvertData scan; + sScanLineData line; + +}; + +//! constructor +CTRStencilShadow::CTRStencilShadow(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRStencilShadow"); + #endif +} + + +/*! +*/ +void CTRStencilShadow::setParam ( u32 index, f32 value) +{ + u32 val = (u32) value; + + // glStencilOp (fail,zfail,zpass + if ( index == 1 && val == 1 ) + { + fragmentShader = &CTRStencilShadow::fragment_zfail_incr; + } + else + if ( index == 1 && val == 2 ) + { + fragmentShader = &CTRStencilShadow::fragment_zfail_decr; + } +} + +/*! +*/ +void CTRStencilShadow::fragment_zfail_decr () +{ + if (!Stencil) + return; + //tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + +#ifdef USE_SBUFFER + u32 *stencil; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC[MATERIAL_MAX_COLORS]; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif +#ifdef IPOL_L0 + sVec3 slopeL[BURNING_MATERIAL_MAX_TANGENT]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC[0] = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif +#ifdef IPOL_T2 + slopeT[2] = (line.t[2][1] - line.t[2][0]) * invDeltaX; +#endif +#ifdef IPOL_L0 + slopeL[0] = (line.l[0][1] - line.l[0][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0] * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#ifdef IPOL_T2 + line.t[2][0] += slopeT[2] * subPixel; +#endif +#ifdef IPOL_L0 + line.l[0][0] += slopeL[0] * subPixel; +#endif +#endif + + //dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + +#ifdef USE_SBUFFER + stencil = (u32*) Stencil->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + +#ifdef INVERSE_W + f32 inversew; +#endif + + +#ifdef IPOL_C0 + tFixPoint r3, g3, b3; +#endif + + for ( s32 i = 0; i <= dx; i++ ) + { +#ifdef CMP_Z + if ( line.z[0] < z[i] ) +#endif +#ifdef CMP_W + if ( line.w[0] < z[i] ) +#endif + { + // zfail + stencil[i] -= 1; + } + +#ifdef IPOL_Z + line.z[0] += slopeZ; +#endif +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1]; +#endif +#ifdef IPOL_T2 + line.t[2][0] += slopeT[2]; +#endif +#ifdef IPOL_L0 + line.l[0][0] += slopeL[0]; +#endif + } +} + +/*! +*/ +void CTRStencilShadow::fragment_zfail_incr() +{ + if (!Stencil) + return; + //tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + +#ifdef USE_SBUFFER + u32 *stencil; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC[MATERIAL_MAX_COLORS]; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif +#ifdef IPOL_L0 + sVec3 slopeL[BURNING_MATERIAL_MAX_TANGENT]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC[0] = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif +#ifdef IPOL_T2 + slopeT[2] = (line.t[2][1] - line.t[2][0]) * invDeltaX; +#endif +#ifdef IPOL_L0 + slopeL[0] = (line.l[0][1] - line.l[0][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0] * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#ifdef IPOL_T2 + line.t[2][0] += slopeT[2] * subPixel; +#endif +#ifdef IPOL_L0 + line.l[0][0] += slopeL[0] * subPixel; +#endif +#endif + + //dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + +#ifdef USE_SBUFFER + stencil = (u32*) Stencil->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + +#ifdef INVERSE_W + f32 inversew; +#endif + +#ifdef IPOL_C0 + tFixPoint r3, g3, b3; +#endif + + for ( s32 i = 0; i <= dx; i++ ) + { +#ifdef CMP_Z + if ( line.z[0] < z[i] ) +#endif +#ifdef CMP_W + if ( line.w[0] < z[i] ) +#endif + { + // zfail + stencil[i] += 1; + } + +#ifdef IPOL_Z + line.z[0] += slopeZ; +#endif +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1]; +#endif +#ifdef IPOL_T2 + line.t[2][0] += slopeT[2]; +#endif +#ifdef IPOL_L0 + line.l[0][0] += slopeL[0]; +#endif + } +} + +void CTRStencilShadow::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) ) + return; + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0][0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + +#ifdef IPOL_T2 + scan.slopeT[2][0] = (c->Tex[2] - a->Tex[2]) * scan.invDeltaY[0]; + scan.t[2][0] = a->Tex[2]; +#endif + +#ifdef IPOL_L0 + scan.slopeL[0][0] = (c->LightTangent[0] - a->LightTangent[0]) * scan.invDeltaY[0]; + scan.l[0][0] = a->LightTangent[0]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + // rasterize upper sub-triangle + //if ( (f32) 0.0 != scan.invDeltaY[1] ) + if ( F32_GREATER_0 ( scan.invDeltaY[1] ) ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[0][1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + +#ifdef IPOL_T2 + scan.slopeT[2][1] = (b->Tex[2] - a->Tex[2]) * scan.invDeltaY[1]; + scan.t[2][1] = a->Tex[2]; +#endif + +#ifdef IPOL_L0 + scan.slopeL[0][1] = (b->LightTangent[0] - a->LightTangent[0]) * scan.invDeltaY[1]; + scan.l[0][1] = a->LightTangent[0]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#ifdef IPOL_T2 + scan.t[2][0] += scan.slopeT[2][0] * subPixel; + scan.t[2][1] += scan.slopeT[2][1] * subPixel; +#endif + +#ifdef IPOL_L0 + scan.l[0][0] += scan.slopeL[0][0] * subPixel; + scan.l[0][1] += scan.slopeL[0][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + +#ifdef IPOL_T2 + line.t[2][scan.left] = scan.t[2][0]; + line.t[2][scan.right] = scan.t[2][1]; +#endif + +#ifdef IPOL_L0 + line.l[0][scan.left] = scan.l[0][0]; + line.l[0][scan.right] = scan.l[0][1]; +#endif + + // render a scanline + (this->*fragmentShader) (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + +#ifdef IPOL_T2 + scan.t[2][0] += scan.slopeT[2][0]; + scan.t[2][1] += scan.slopeT[2][1]; +#endif + +#ifdef IPOL_L0 + scan.l[0][0] += scan.slopeL[0][0]; + scan.l[0][1] += scan.slopeL[0][1]; +#endif + + } + } + + // rasterize lower sub-triangle + //if ( (f32) 0.0 != scan.invDeltaY[2] ) + if ( F32_GREATER_0 ( scan.invDeltaY[2] ) ) + { + // advance to middle point + //if( (f32) 0.0 != scan.invDeltaY[1] ) + if ( F32_GREATER_0 ( scan.invDeltaY[1] ) ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0][0] = a->Color[0] + scan.slopeC[0][0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif +#ifdef IPOL_T2 + scan.t[2][0] = a->Tex[2] + scan.slopeT[2][0] * temp[0]; +#endif +#ifdef IPOL_L0 + scan.l[0][0] = a->LightTangent[0] + scan.slopeL[0][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[0][1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + +#ifdef IPOL_T2 + scan.slopeT[2][1] = (c->Tex[2] - b->Tex[2]) * scan.invDeltaY[2]; + scan.t[2][1] = b->Tex[2]; +#endif + +#ifdef IPOL_L0 + scan.slopeL[0][1] = (c->LightTangent[0] - b->LightTangent[0]) * scan.invDeltaY[2]; + scan.l[0][1] = b->LightTangent[0]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#ifdef IPOL_T2 + scan.t[2][0] += scan.slopeT[2][0] * subPixel; + scan.t[2][1] += scan.slopeT[2][1] * subPixel; +#endif + +#ifdef IPOL_L0 + scan.l[0][0] += scan.slopeL[0][0] * subPixel; + scan.l[0][1] += scan.slopeL[0][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + +#ifdef IPOL_T2 + line.t[2][scan.left] = scan.t[2][0]; + line.t[2][scan.right] = scan.t[2][1]; +#endif + +#ifdef IPOL_L0 + line.l[0][scan.left] = scan.l[0][0]; + line.l[0][scan.right] = scan.l[0][1]; +#endif + + // render a scanline + (this->*fragmentShader) (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif +#ifdef IPOL_T2 + scan.t[2][0] += scan.slopeT[2][0]; + scan.t[2][1] += scan.slopeT[2][1]; +#endif + +#ifdef IPOL_L0 + scan.l[0][0] += scan.slopeL[0][0]; + scan.l[0][1] += scan.slopeL[0][1]; +#endif + + } + } + +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + + +//! creates a triangle renderer +IBurningShader* createTRStencilShadow(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRStencilShadow(driver); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + + diff --git a/source/Irrlicht/CTRTextureBlend.cpp b/source/Irrlicht/CTRTextureBlend.cpp new file mode 100644 index 00000000..e3ba0791 --- /dev/null +++ b/source/Irrlicht/CTRTextureBlend.cpp @@ -0,0 +1,2385 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 + +// define render case +#define SUBTEXEL +#define INVERSE_W + +#define USE_ZBUFFER +#define IPOL_W +#define CMP_W +#define WRITE_W + +#define IPOL_C0 +#define IPOL_T0 +//#define IPOL_T1 + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #undef IPOL_C0 +#endif + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif + #define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + + + +namespace irr +{ + +namespace video +{ + +class CTRTextureBlend : public IBurningShader +{ +public: + + //! constructor + CTRTextureBlend(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + + virtual void setZCompareFunc ( u32 func) _IRR_OVERRIDE_; + virtual void setParam ( u32 index, f32 value) _IRR_OVERRIDE_; + + +private: + // fragment shader + typedef void (CTRTextureBlend::*tFragmentShader) (); + void fragment_dst_color_zero (); + void fragment_dst_color_one (); + void fragment_dst_color_src_alpha (); + void fragment_dst_color_one_minus_dst_alpha (); + void fragment_zero_one_minus_scr_color (); + void fragment_src_color_src_alpha (); + void fragment_one_one_minus_src_alpha (); + void fragment_one_minus_dst_alpha_one(); + void fragment_src_alpha_one(); + + tFragmentShader fragmentShader; + sScanConvertData scan; + sScanLineData line; + + u32 ZCompare; +}; + +//! constructor +CTRTextureBlend::CTRTextureBlend(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRTextureBlend"); + #endif + + ZCompare = 1; +} + +/*! +*/ +void CTRTextureBlend::setZCompareFunc ( u32 func) +{ + ZCompare = func; +} + +/*! +*/ +void CTRTextureBlend::setParam ( u32 index, f32 value) +{ + u8 showname = 0; + + E_BLEND_FACTOR srcFact,dstFact; + E_MODULATE_FUNC modulate; + u32 alphaSrc; + unpack_textureBlendFunc ( srcFact, dstFact, modulate, alphaSrc, value ); + + fragmentShader = 0; + + if ( srcFact == EBF_DST_COLOR && dstFact == EBF_ZERO ) + { + fragmentShader = &CTRTextureBlend::fragment_dst_color_zero; + } + else + if ( srcFact == EBF_DST_COLOR && dstFact == EBF_ONE ) + { + fragmentShader = &CTRTextureBlend::fragment_dst_color_one; + } + else + if ( srcFact == EBF_DST_COLOR && dstFact == EBF_SRC_ALPHA) + { + fragmentShader = &CTRTextureBlend::fragment_dst_color_src_alpha; + } + else + if ( srcFact == EBF_DST_COLOR && dstFact == EBF_ONE_MINUS_DST_ALPHA) + { + fragmentShader = &CTRTextureBlend::fragment_dst_color_one_minus_dst_alpha; + } + else + if ( srcFact == EBF_ZERO && dstFact == EBF_ONE_MINUS_SRC_COLOR ) + { + fragmentShader = &CTRTextureBlend::fragment_zero_one_minus_scr_color; + } + else + if ( srcFact == EBF_ONE && dstFact == EBF_ONE_MINUS_SRC_ALPHA) + { + fragmentShader = &CTRTextureBlend::fragment_one_one_minus_src_alpha; + } + else + if ( srcFact == EBF_ONE_MINUS_DST_ALPHA && dstFact == EBF_ONE ) + { + fragmentShader = &CTRTextureBlend::fragment_one_minus_dst_alpha_one; + } + else + if ( srcFact == EBF_SRC_ALPHA && dstFact == EBF_ONE ) + { + fragmentShader = &CTRTextureBlend::fragment_src_alpha_one; + } + else + if ( srcFact == EBF_SRC_COLOR && dstFact == EBF_SRC_ALPHA ) + { + fragmentShader = &CTRTextureBlend::fragment_src_color_src_alpha; + } + else + { + showname = 1; + fragmentShader = &CTRTextureBlend::fragment_dst_color_zero; + } + + static const c8 *n[] = + { + "gl_zero", + "gl_one", + "gl_dst_color", + "gl_one_minus_dst_color", + "gl_src_color", + "gl_one_minus_src_color", + "gl_src_alpha", + "gl_one_minus_src_alpha", + "gl_dst_alpha", + "gl_one_minus_dst_alpha", + "gl_src_alpha_saturate" + }; + + static E_BLEND_FACTOR lsrcFact = EBF_ZERO; + static E_BLEND_FACTOR ldstFact = EBF_ZERO; + + if ( showname && ( lsrcFact != srcFact || ldstFact != dstFact ) ) + { + char buf[128]; + snprintf_irr ( buf, 128, "missing shader: %s %s",n[srcFact], n[dstFact] ); + os::Printer::log( buf, ELL_INFORMATION ); + + lsrcFact = srcFact; + ldstFact = dstFact; + } + +} + + +/*! +*/ +void CTRTextureBlend::fragment_dst_color_src_alpha () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC[MATERIAL_MAX_COLORS]; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC[0] = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0] * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + f32 iw = FIX_POINT_F32_MUL; + + tFixPoint a0, r0, g0, b0; + tFixPoint r1, g1, b1; + + s32 i; + + switch ( ZCompare ) + { + case 1: + for ( i = 0; i <= dx; ++i ) + { +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + + { + +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef INVERSE_W + iw = fix_inverse32 ( line.w[0] ); +#endif + + getSample_texture ( a0,r0,g0,b0, + &IT[0], + tofix(line.t[0][0].x, iw), + tofix(line.t[0][0].y, iw) + ); + + color_to_fix ( r1, g1, b1, dst[i] ); + + dst[i] = fix_to_color ( clampfix_maxcolor ( imulFix_tex2 ( r0, r1 ) ), + clampfix_maxcolor ( imulFix_tex2 ( g0, g1 ) ), + clampfix_maxcolor ( imulFix_tex2 ( b0, b1 ) ) + ); + } + +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif + } + break; + + case 2: + for ( i = 0; i <= dx; ++i ) + { +#ifdef CMP_W + if ( line.w[0] == z[i] ) +#endif + + { + +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef INVERSE_W + iw = fix_inverse32 ( line.w[0] ); +#endif + + getSample_texture ( a0,r0,g0,b0, + &IT[0], + tofix ( line.t[0][0].x,iw), + tofix ( line.t[0][0].y,iw) + ); + + color_to_fix ( r1, g1, b1, dst[i] ); + + dst[i] = fix_to_color ( clampfix_maxcolor ( imulFix_tex2 ( r0, r1 ) ), + clampfix_maxcolor ( imulFix_tex2 ( g0, g1 ) ), + clampfix_maxcolor ( imulFix_tex2 ( b0, b1 ) ) + ); + + } + +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif + }break; + } // zcompare + +} + +/*! +*/ +void CTRTextureBlend::fragment_src_color_src_alpha () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC[MATERIAL_MAX_COLORS]; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC[0] = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0] * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + f32 iw = FIX_POINT_F32_MUL; + + tFixPoint a0, r0, g0, b0; + tFixPoint r1, g1, b1; + + s32 i; + + switch ( ZCompare ) + { + case 1: + for ( i = 0; i <= dx; ++i ) + { +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + + { + +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef INVERSE_W + iw = fix_inverse32 ( line.w[0] ); +#endif + + getSample_texture ( a0, r0, g0, b0, &IT[0], tofix ( line.t[0][0].x,iw), tofix ( line.t[0][0].y,iw) ); + color_to_fix ( r1, g1, b1, dst[i] ); + +// u32 check = imulFix_tex1( r0, r1 ); + dst[i] = fix_to_color ( clampfix_maxcolor ( imulFix_tex1( r0, r1 ) + imulFix_tex1( r1, a0 ) ), + clampfix_maxcolor ( imulFix_tex1( g0, g1 ) + imulFix_tex1( g1, a0 ) ), + clampfix_maxcolor ( imulFix_tex1( b0, b1 ) + imulFix_tex1( b1, a0 ) ) + ); + } + +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif + } + break; + + case 2: + for ( i = 0; i <= dx; ++i ) + { +#ifdef CMP_W + if ( line.w[0] == z[i] ) +#endif + + { + +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef INVERSE_W + iw = fix_inverse32 ( line.w[0] ); +#endif + + getSample_texture ( a0,r0,g0,b0, + &IT[0], + tofix ( line.t[0][0].x,iw), + tofix ( line.t[0][0].y,iw) + ); + + color_to_fix ( r1, g1, b1, dst[i] ); + + dst[i] = fix_to_color ( clampfix_maxcolor ( imulFix_tex2 ( r0, r1 ) ), + clampfix_maxcolor ( imulFix_tex2 ( g0, g1 ) ), + clampfix_maxcolor ( imulFix_tex2 ( b0, b1 ) ) + ); + + } + +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif + }break; + } // zcompare + +} + +/*! +*/ +void CTRTextureBlend::fragment_one_one_minus_src_alpha() +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC[MATERIAL_MAX_COLORS]; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC[0] = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0] * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + f32 iw = FIX_POINT_F32_MUL; + + tFixPoint a0,r0, g0, b0; + tFixPoint r1, g1, b1; + tFixPoint r2, g2, b2; + + s32 i; + + switch ( ZCompare ) + { + case 1: + for ( i = 0; i <= dx; ++i ) + { +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + + { + +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef INVERSE_W + iw = fix_inverse32 ( line.w[0] ); +#endif + + getSample_texture ( a0, r0, g0, b0, IT + 0, tofix ( line.t[0][0].x,iw),tofix ( line.t[0][0].y,iw) ); + a0 = FIX_POINT_ONE - a0; + + color_to_fix1 ( r1, g1, b1, dst[i] ); +#ifdef IPOL_C0 + getSample_color ( r2, g2, b2, line.c[0][0],iw ); + + dst[i] = fix_to_color ( imulFix ( r0 + imulFix ( r1, a0 ), r2 ), + imulFix ( g0 + imulFix ( g1, a0 ), g2 ), + imulFix ( b0 + imulFix ( b1, a0 ), b2 ) + ); +#else + dst[i] = fix_to_color ( r0 + imulFix ( r1, a0 ), + g0 + imulFix ( g1, a0 ), + b0 + imulFix ( b1, a0 ) + ); + +#endif + + } + +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif + } + break; + + case 2: + for ( i = 0; i <= dx; ++i ) + { +#ifdef CMP_W + if ( line.w[0] == z[i] ) +#endif + + { + +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef INVERSE_W + iw = fix_inverse32 ( line.w[0] ); +#endif + getSample_texture ( a0, r0, g0, b0, IT + 0, tofix ( line.t[0][0].x,iw),tofix ( line.t[0][0].y,iw) ); + a0 = FIX_POINT_ONE - a0; + + color_to_fix1 ( r1, g1, b1, dst[i] ); +#ifdef IPOL_C0 + getSample_color ( r2, g2, b2, line.c[0][0],iw ); + + dst[i] = fix_to_color ( imulFix ( r0 + imulFix ( r1, a0 ), r2 ), + imulFix ( g0 + imulFix ( g1, a0 ), g2 ), + imulFix ( b0 + imulFix ( b1, a0 ), b2 ) + ); +#else + dst[i] = fix_to_color ( r0 + imulFix ( r1, a0 ), + g0 + imulFix ( g1, a0 ), + b0 + imulFix ( b1, a0 ) + ); + +#endif + + } + +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif + }break; + } // zcompare + +} + +/*! +*/ +void CTRTextureBlend::fragment_one_minus_dst_alpha_one () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC[MATERIAL_MAX_COLORS]; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC[0] = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0] * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + f32 iw = FIX_POINT_F32_MUL; + + tFixPoint r0, g0, b0; + tFixPoint a1, r1, g1, b1; + tFixPoint r2, g2, b2; + + s32 i; + + switch ( ZCompare ) + { + case 1: + for ( i = 0; i <= dx; ++i ) + { +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + + { + +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef INVERSE_W + iw = fix_inverse32 ( line.w[0] ); +#endif + + getSample_texture ( r0, g0, b0, IT + 0, tofix ( line.t[0][0].x,iw),tofix ( line.t[0][0].y,iw) ); + color_to_fix1 ( a1, r1, g1, b1, dst[i] ); +#ifdef IPOL_C0 + getSample_color ( r2, g2, b2, line.c[0][0],iw ); + + a1 = FIX_POINT_ONE - a1; + dst[i] = fix_to_color ( imulFix ( imulFix ( r0, a1 ) + r1, r2 ), + imulFix ( imulFix ( g0, a1 ) + g1, g2 ), + imulFix ( imulFix ( b0, a1 ) + b1, b2 ) + ); +#else + dst[i] = fix_to_color ( imulFix ( r0, a1) + r0, + imulFix ( g0, a1) + g0, + imulFix ( b0, a1) + b0 + ); + +#endif + + } + +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif + } + break; + + case 2: + for ( i = 0; i <= dx; ++i ) + { +#ifdef CMP_W + if ( line.w[0] == z[i] ) +#endif + + { + +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef INVERSE_W + iw = fix_inverse32 ( line.w[0] ); +#endif + getSample_texture ( r0, g0, b0, IT + 0, tofix ( line.t[0][0].x,iw),tofix ( line.t[0][0].y,iw) ); + color_to_fix1 ( a1, r1, g1, b1, dst[i] ); + +#ifdef IPOL_C0 + getSample_color ( r2, g2, b2, line.c[0][0],iw ); + + a1 = FIX_POINT_ONE - a1; + dst[i] = fix_to_color ( imulFix ( imulFix ( r0, a1 ) + r1, r2 ), + imulFix ( imulFix ( g0, a1 ) + g1, g2 ), + imulFix ( imulFix ( b0, a1 ) + b1, b2 ) + ); +#else + dst[i] = fix_to_color ( imulFix ( r0, a1) + r0, + imulFix ( g0, a1) + g0, + imulFix ( b0, a1) + b0 + ); + +#endif + + } + +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif + }break; + } // zcompare + +} + +/*! +*/ +void CTRTextureBlend::fragment_src_alpha_one () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC[MATERIAL_MAX_COLORS]; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC[0] = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0] * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + f32 iw = FIX_POINT_F32_MUL; + + tFixPoint a0, r0, g0, b0; + tFixPoint r1, g1, b1; + tFixPoint r2, g2, b2; + + s32 i; + + switch ( ZCompare ) + { + case 1: + for ( i = 0; i <= dx; ++i ) + { +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + + { + + +#ifdef INVERSE_W + iw = fix_inverse32 ( line.w[0] ); +#endif + + getSample_texture ( a0, r0, g0, b0, IT + 0, tofix ( line.t[0][0].x,iw),tofix ( line.t[0][0].y,iw) ); + if ( a0 > 0 ) + { + a0 >>= 8; + + color_to_fix ( r1, g1, b1, dst[i] ); + +#ifdef IPOL_C0 + getSample_color ( r2, g2, b2, line.c[0][0],iw ); + + dst[i] = fix4_to_color ( a0, + clampfix_maxcolor ( imulFix (r0,a0 ) + r1), + clampfix_maxcolor ( imulFix (g0,a0 ) + g1), + clampfix_maxcolor ( imulFix (b0,a0 ) + b1) + ); + +/* + a0 >>= 8; + dst[i] = fix4_to_color ( a0, + imulFix ( imulFix ( r0, a0 ) + r1, r2 ), + imulFix ( imulFix ( g0, a0 ) + g1, g2 ), + imulFix ( imulFix ( b0, a0 ) + b1, b2 ) + ); +*/ +#else + dst[i] = fix4_to_color ( a0, + clampfix_maxcolor ( imulFix (r0,a0 ) + r1 ), + clampfix_maxcolor ( imulFix (g0,a0 ) + g1 ), + clampfix_maxcolor ( imulFix (b0,a0 ) + b1 ) + ); + +#endif + +#ifdef WRITE_W + //z[i] = line.w[0]; +#endif + } + + } + +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif + } + break; + + case 2: + for ( i = 0; i <= dx; ++i ) + { +#ifdef CMP_W + if ( line.w[0] == z[i] ) +#endif + { + +#ifdef INVERSE_W + iw = fix_inverse32 ( line.w[0] ); +#endif + + getSample_texture ( a0, r0, g0, b0, IT + 0, tofix ( line.t[0][0].x,iw),tofix ( line.t[0][0].y,iw) ); + if ( a0 > 0 ) + { + a0 >>= 8; + + color_to_fix ( r1, g1, b1, dst[i] ); + +#ifdef IPOL_C0 + getSample_color ( r2, g2, b2, line.c[0][0],iw ); + + dst[i] = fix4_to_color ( a0, + clampfix_maxcolor ( imulFix ( imulFix (r0,a0 ) + r1, r2 ) ), + clampfix_maxcolor ( imulFix ( imulFix (g0,a0 ) + g1, g2 ) ), + clampfix_maxcolor ( imulFix ( imulFix (b0,a0 ) + b1, b2 ) ) + ); + +/* + a0 >>= 8; + dst[i] = fix4_to_color ( a0, + imulFix ( imulFix ( r0, a0 ) + r1, r2 ), + imulFix ( imulFix ( g0, a0 ) + g1, g2 ), + imulFix ( imulFix ( b0, a0 ) + b1, b2 ) + ); +*/ +#else + dst[i] = fix4_to_color ( a0, + clampfix_maxcolor ( imulFix (r0,a0 ) + r1 ), + clampfix_maxcolor ( imulFix (g0,a0 ) + g1 ), + clampfix_maxcolor ( imulFix (b0,a0 ) + b1 ) + ); + +#endif + +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + } + } +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif + }break; + } // zcompare + +} + + +/*! +*/ +void CTRTextureBlend::fragment_dst_color_one_minus_dst_alpha () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC[MATERIAL_MAX_COLORS]; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC[0] = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0] * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + f32 iw = FIX_POINT_F32_MUL; + + tFixPoint r0, g0, b0; + tFixPoint a1, r1, g1, b1; + tFixPoint r2, g2, b2; + + s32 i; + + switch ( ZCompare ) + { + case 1: + for ( i = 0; i <= dx; ++i ) + { +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + + { + +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef INVERSE_W + iw = fix_inverse32 ( line.w[0] ); +#endif + + getSample_texture ( r0, g0, b0, IT + 0, tofix ( line.t[0][0].x,iw),tofix ( line.t[0][0].y,iw) ); + color_to_fix1 ( a1, r1, g1, b1, dst[i] ); +#ifdef IPOL_C0 + getSample_color ( r2, g2, b2, line.c[0][0],iw ); + + a1 = FIX_POINT_ONE - a1; + dst[i] = fix_to_color ( imulFix ( imulFix ( r1, r0 + a1 ), r2 ), + imulFix ( imulFix ( g1, g0 + a1 ), g2 ), + imulFix ( imulFix ( b1, b0 + a1 ), b2 ) + ); +#else + dst[i] = fix_to_color ( imulFix ( r1, r0 + a1 ), + imulFix ( g1, g0 + a1 ), + imulFix ( b1, b0 + a1 ) + ); + +#endif + + } + +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif + } + break; + + case 2: + for ( i = 0; i <= dx; ++i ) + { +#ifdef CMP_W + if ( line.w[0] == z[i] ) +#endif + + { + +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef INVERSE_W + iw = fix_inverse32 ( line.w[0] ); +#endif + getSample_texture ( r0, g0, b0, IT + 0, tofix ( line.t[0][0].x,iw),tofix ( line.t[0][0].y,iw) ); + color_to_fix1 ( a1, r1, g1, b1, dst[i] ); + +#ifdef IPOL_C0 + getSample_color ( r2, g2, b2, line.c[0][0],iw ); + + a1 = FIX_POINT_ONE - a1; + dst[i] = fix_to_color ( imulFix ( imulFix ( r1, r0 + a1 ), r2 ), + imulFix ( imulFix ( g1, g0 + a1 ), g2 ), + imulFix ( imulFix ( b1, b0 + a1 ), b2 ) + ); +#else + dst[i] = fix_to_color ( imulFix ( r1, r0 + a1 ), + imulFix ( g1, g0 + a1 ), + imulFix ( b1, b0 + a1 ) + ); + +#endif + + } + +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif + }break; + } // zcompare + +} + +/*! +*/ +void CTRTextureBlend::fragment_dst_color_zero () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC[MATERIAL_MAX_COLORS]; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC[0] = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0] * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + f32 iw = FIX_POINT_F32_MUL; + + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; + tFixPoint r2, g2, b2; + + s32 i; + + switch ( ZCompare ) + { + case 1: + for ( i = 0; i <= dx; ++i ) + { +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + + { + +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef INVERSE_W + iw = fix_inverse32 ( line.w[0] ); +#endif + + getSample_texture ( r0, g0, b0, IT + 0, tofix ( line.t[0][0].x,iw),tofix ( line.t[0][0].y,iw) ); + color_to_fix1 ( r1, g1, b1, dst[i] ); + +#ifdef IPOL_C0 + getSample_color ( r2, g2, b2, line.c[0][0],iw ); + + dst[i] = fix_to_color ( imulFix ( imulFix ( r0, r1 ), r2 ), + imulFix ( imulFix ( g0, g1 ), g2 ), + imulFix ( imulFix ( b0, b1 ), b2 ) ); +#else + dst[i] = fix_to_color ( imulFix ( r0, r1 ), + imulFix ( g0, g1 ), + imulFix ( b0, b1 ) + ); + +#endif + + } + +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif + } + break; + + case 2: + for ( i = 0; i <= dx; ++i ) + { +#ifdef CMP_W + if ( line.w[0] == z[i] ) +#endif + + { + +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef INVERSE_W + iw = fix_inverse32 ( line.w[0] ); +#endif + getSample_texture ( r0, g0, b0, IT + 0, tofix ( line.t[0][0].x,iw),tofix ( line.t[0][0].y,iw) ); + color_to_fix1 ( r1, g1, b1, dst[i] ); + +#ifdef IPOL_C0 + getSample_color ( r2, g2, b2, line.c[0][0],iw ); + + dst[i] = fix_to_color ( imulFix ( imulFix ( r0, r1 ), r2 ), + imulFix ( imulFix ( g0, g1 ), g2 ), + imulFix ( imulFix ( b0, b1 ), b2 ) + ); +#else + dst[i] = fix_to_color ( imulFix ( r0, r1 ), + imulFix ( g0, g1 ), + imulFix ( b0, b1 ) + ); + +#endif + + } + +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif + }break; + } // zcompare + +} + +/*! +*/ +void CTRTextureBlend::fragment_dst_color_one () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC[MATERIAL_MAX_COLORS]; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC[0] = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0] * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + f32 iw = FIX_POINT_F32_MUL; + + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; + tFixPoint r2, g2, b2; + + s32 i; + + switch ( ZCompare ) + { + case 1: + for ( i = 0; i <= dx; ++i ) + { +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + + { + +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef INVERSE_W + iw = fix_inverse32 ( line.w[0] ); +#endif + + getSample_texture ( r0, g0, b0, IT + 0, tofix ( line.t[0][0].x,iw),tofix ( line.t[0][0].y,iw) ); + color_to_fix ( r1, g1, b1, dst[i] ); +#ifdef IPOL_C0 + getSample_color ( r2, g2, b2, line.c[0][0],iw ); + + dst[i] = fix_to_color ( clampfix_maxcolor ( imulFix_tex1 ( r0, r1 ) + r1 ), + clampfix_maxcolor ( imulFix_tex1 ( g0, g1 ) + g1 ), + clampfix_maxcolor ( imulFix_tex1 ( b0, b1 ) + b1 ) + ); + +#else + dst[i] = fix_to_color ( clampfix_maxcolor ( imulFix_tex1 ( r0, r1 ) + r1 ), + clampfix_maxcolor ( imulFix_tex1 ( g0, g1 ) + g1 ), + clampfix_maxcolor ( imulFix_tex1 ( b0, b1 ) + b1 ) + ); + +#endif + + } + +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif + } + break; + + case 2: + for ( i = 0; i <= dx; ++i ) + { +#ifdef CMP_W + if ( line.w[0] == z[i] ) +#endif + + { + +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef INVERSE_W + iw = fix_inverse32 ( line.w[0] ); +#endif + getSample_texture ( r0, g0, b0, IT + 0, tofix ( line.t[0][0].x,iw),tofix ( line.t[0][0].y,iw) ); + color_to_fix ( r1, g1, b1, dst[i] ); + +#ifdef IPOL_C0 + getSample_color ( r2, g2, b2, line.c[0][0],iw ); + + dst[i] = fix_to_color ( clampfix_maxcolor ( imulFix_tex1 ( r0, r1 ) + r1 ), + clampfix_maxcolor ( imulFix_tex1 ( g0, g1 ) + g1 ), + clampfix_maxcolor ( imulFix_tex1 ( b0, b1 ) + b1 ) + ); + +#else + dst[i] = fix_to_color ( clampfix_maxcolor ( imulFix_tex1 ( r0, r1 ) + r1 ), + clampfix_maxcolor ( imulFix_tex1 ( g0, g1 ) + g1 ), + clampfix_maxcolor ( imulFix_tex1 ( b0, b1 ) + b1 ) + ); + +#endif + + + } + +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif + }break; + } // zcompare + +} + +/*! +*/ +void CTRTextureBlend::fragment_zero_one_minus_scr_color () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC[MATERIAL_MAX_COLORS]; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC[0] = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0] * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + f32 iw = FIX_POINT_F32_MUL; + + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; + tFixPoint r2, g2, b2; + + s32 i; + + switch ( ZCompare ) + { + case 1: + for ( i = 0; i <= dx; ++i ) + { +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + + { + +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef INVERSE_W + iw = fix_inverse32 ( line.w[0] ); +#endif + + getSample_texture ( r0, g0, b0, IT + 0, tofix ( line.t[0][0].x,iw),tofix ( line.t[0][0].y,iw) ); + color_to_fix1 ( r1, g1, b1, dst[i] ); +#ifdef IPOL_C0 + getSample_color ( r2, g2, b2, line.c[0][0],iw ); + + dst[i] = fix_to_color ( imulFix ( FIX_POINT_ONE - r0, r1 ), + imulFix ( FIX_POINT_ONE - g0, g1 ), + imulFix ( FIX_POINT_ONE - b0, b1 ) + ); + +#else + dst[i] = fix_to_color ( imulFix ( FIX_POINT_ONE - r0, r1 ), + imulFix ( FIX_POINT_ONE - g0, g1 ), + imulFix ( FIX_POINT_ONE - b0, b1 ) + ); + +#endif + + } + +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif + } + break; + + case 2: + for ( i = 0; i <= dx; ++i ) + { +#ifdef CMP_W + if ( line.w[0] == z[i] ) +#endif + + { + +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef INVERSE_W + iw = fix_inverse32 ( line.w[0] ); +#endif + getSample_texture ( r0, g0, b0, IT + 0, tofix ( line.t[0][0].x,iw),tofix ( line.t[0][0].y,iw) ); + color_to_fix1 ( r1, g1, b1, dst[i] ); +#ifdef IPOL_C0 + getSample_color ( r2, g2, b2, line.c[0][0],iw ); + + dst[i] = fix_to_color ( imulFix ( FIX_POINT_ONE - r0, r1 ), + imulFix ( FIX_POINT_ONE - g0, g1 ), + imulFix ( FIX_POINT_ONE - b0, b1 ) + ); + +#else + dst[i] = fix_to_color ( imulFix ( FIX_POINT_ONE - r0, r1 ), + imulFix ( FIX_POINT_ONE - g0, g1 ), + imulFix ( FIX_POINT_ONE - b0, b1 ) + ); + +#endif + + } + +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif + }break; + } // zcompare + +} + + + +void CTRTextureBlend::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + if ( 0 == fragmentShader ) + return; + + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) ) + return; + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0][0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + // rasterize upper sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[1] ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[0][1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + (this->*fragmentShader) (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + // rasterize lower sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[2] ) + { + // advance to middle point + if( (f32) 0.0 != scan.invDeltaY[1] ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0][0] = a->Color[0] + scan.slopeC[0][0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[0][1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + (this->*fragmentShader) (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + +} + + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + +//! creates a flat triangle renderer +IBurningShader* createTRTextureBlend(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRTextureBlend(driver); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + diff --git a/source/Irrlicht/CTRTextureDetailMap2.cpp b/source/Irrlicht/CTRTextureDetailMap2.cpp new file mode 100644 index 00000000..f5653ab5 --- /dev/null +++ b/source/Irrlicht/CTRTextureDetailMap2.cpp @@ -0,0 +1,651 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 + +// define render case +#define SUBTEXEL +#define INVERSE_W + +#define USE_ZBUFFER +#define IPOL_W +#define CMP_W +#define WRITE_W + +#define IPOL_C0 +#define IPOL_T0 +#define IPOL_T1 + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #undef IPOL_C0 +#endif + + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif + #define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + + +namespace irr +{ + +namespace video +{ + +class CTRTextureDetailMap2 : public IBurningShader +{ +public: + + //! constructor + CTRTextureDetailMap2(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + + +private: + void scanline_bilinear (); + sScanConvertData scan; + sScanLineData line; + +}; + +//! constructor +CTRTextureDetailMap2::CTRTextureDetailMap2(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRTextureDetailMap2"); + #endif +} + + + +/*! +*/ +void CTRTextureDetailMap2::scanline_bilinear () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + f32 inversew = FIX_POINT_F32_MUL; + + tFixPoint tx0, tx1; + tFixPoint ty0, ty1; + + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; + tFixPoint r2, g2, b2; + + + for ( s32 i = 0; i <= dx; ++i ) + { +#ifdef CMP_Z + if ( line.z[0] < z[i] ) +#endif +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + + { +#ifdef INVERSE_W + inversew = fix_inverse32 ( line.w[0] ); +#endif + tx0 = tofix ( line.t[0][0].x,inversew); + ty0 = tofix ( line.t[0][0].y,inversew); + tx1 = tofix ( line.t[1][0].x,inversew); + ty1 = tofix ( line.t[1][0].y,inversew); + + getSample_texture ( r0, g0, b0, &IT[0], tx0,ty0 ); + getSample_texture ( r1, g1, b1, &IT[1], tx1,ty1 ); + + // bias half color + r1 += -FIX_POINT_HALF_COLOR; + g1 += -FIX_POINT_HALF_COLOR; + b1 += -FIX_POINT_HALF_COLOR; + + r2 = clampfix_mincolor ( clampfix_maxcolor ( r0 + r1 ) ); + g2 = clampfix_mincolor ( clampfix_maxcolor ( g0 + g1 ) ); + b2 = clampfix_mincolor ( clampfix_maxcolor ( b0 + b1 ) ); + + dst[i] = fix_to_color ( r2, g2, b2 ); + +#ifdef WRITE_Z + z[i] = line.z[0]; +#endif +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + + } + +#ifdef IPOL_Z + line.z[0] += slopeZ; +#endif +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1]; +#endif + } + +} + +void CTRTextureDetailMap2::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) ) + return; + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0][0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + // rasterize upper sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[1] ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[0][1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + // rasterize lower sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[2] ) + { + // advance to middle point + if( (f32) 0.0 != scan.invDeltaY[1] ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0][0] = a->Color[0] + scan.slopeC[0][0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[0][1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + +} + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + +//! creates a flat triangle renderer +IBurningShader* createTriangleRendererTextureDetailMap2(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRTextureDetailMap2(driver); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + diff --git a/source/Irrlicht/CTRTextureFlat.cpp b/source/Irrlicht/CTRTextureFlat.cpp new file mode 100644 index 00000000..9ef5ade0 --- /dev/null +++ b/source/Irrlicht/CTRTextureFlat.cpp @@ -0,0 +1,336 @@ +// Copyright (C) 2002-2012 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" +#include "CTRTextureGouraud.h" + +#ifdef _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + +class CTRTextureFlat : public CTRTextureGouraud +{ +public: + + CTRTextureFlat(IZBuffer* zbuffer) + : CTRTextureGouraud(zbuffer) + { + #ifdef _DEBUG + setDebugName("CTRTextureFlat"); + #endif + } + + //! draws an indexed triangle list + virtual void drawIndexedTriangleList(S2DVertex* vertices, s32 vertexCount, const u16* indexList, s32 triangleCount) _IRR_OVERRIDE_ + { + const S2DVertex *v1, *v2, *v3; + + f32 tmpDiv; // temporary division factor + f32 longest; // saves the longest span + s32 height; // saves height of triangle + u16* targetSurface; // target pointer where to plot pixels + s32 spanEnd; // saves end of spans + f32 leftdeltaxf; // amount of pixels to increase on left side of triangle + f32 rightdeltaxf; // amount of pixels to increase on right side of triangle + s32 leftx, rightx; // position where we are + f32 leftxf, rightxf; // same as above, but as f32 values + s32 span; // current span + u16 *hSpanBegin, *hSpanEnd; // pointer used when plotting pixels + s32 leftTx, rightTx, leftTy, rightTy; // texture interpolating values + s32 leftTxStep, rightTxStep, leftTyStep, rightTyStep; // texture interpolating values + s32 spanTx, spanTy, spanTxStep, spanTyStep; // values of Texturecoords when drawing a span + core::rect TriangleRect; + + s32 leftZValue, rightZValue; + s32 leftZStep, rightZStep; + s32 spanZValue, spanZStep; // ZValues when drawing a span + TZBufferType* zTarget, *spanZTarget; // target of ZBuffer; + + lockedSurface = (u16*)RenderTarget->getData(); + lockedZBuffer = ZBuffer->lock(); + lockedTexture = (u16*)Texture->getData(); + + for (s32 i=0; iPos.X - v1->Pos.X) * (v3->Pos.Y - v2->Pos.Y)) - + ((v3->Pos.Y - v1->Pos.Y) * (v3->Pos.X - v2->Pos.X)); + + if (z < 0) + continue; + } + + //near plane clipping + + if (v1->ZValue<0 && v2->ZValue<0 && v3->ZValue<0) + continue; + + // sort for width for inscreen clipping + + if (v1->Pos.X > v2->Pos.X) swapVertices(&v1, &v2); + if (v1->Pos.X > v3->Pos.X) swapVertices(&v1, &v3); + if (v2->Pos.X > v3->Pos.X) swapVertices(&v2, &v3); + + if ((v1->Pos.X - v3->Pos.X) == 0) + continue; + + TriangleRect.UpperLeftCorner.X = v1->Pos.X; + TriangleRect.LowerRightCorner.X = v3->Pos.X; + + // sort for height for faster drawing. + + if (v1->Pos.Y > v2->Pos.Y) swapVertices(&v1, &v2); + if (v1->Pos.Y > v3->Pos.Y) swapVertices(&v1, &v3); + if (v2->Pos.Y > v3->Pos.Y) swapVertices(&v2, &v3); + + TriangleRect.UpperLeftCorner.Y = v1->Pos.Y; + TriangleRect.LowerRightCorner.Y = v3->Pos.Y; + + if (!TriangleRect.isRectCollided(ViewPortRect)) + continue; + + // calculate height of triangle + height = v3->Pos.Y - v1->Pos.Y; + if (!height) + continue; + + // calculate longest span + + longest = (v2->Pos.Y - v1->Pos.Y) / (f32)height * (v3->Pos.X - v1->Pos.X) + (v1->Pos.X - v2->Pos.X); + + spanEnd = v2->Pos.Y; + span = v1->Pos.Y; + leftxf = (f32)v1->Pos.X; + rightxf = (f32)v1->Pos.X; + + leftZValue = v1->ZValue; + rightZValue = v1->ZValue; + + leftTx = rightTx = v1->TCoords.X; + leftTy = rightTy = v1->TCoords.Y; + + targetSurface = lockedSurface + span * SurfaceWidth; + zTarget = lockedZBuffer + span * SurfaceWidth; + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + rightdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + rightZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); + rightTxStep = (s32)((v2->TCoords.X - rightTx) * tmpDiv); + rightTyStep = (s32)((v2->TCoords.Y - rightTy) * tmpDiv); + + tmpDiv = 1.0f / (f32)height; + leftdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + leftZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); + leftTxStep = (s32)((v3->TCoords.X - leftTx) * tmpDiv); + leftTyStep = (s32)((v3->TCoords.Y - leftTy) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (f32)height; + rightdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + rightZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); + rightTxStep = (s32)((v3->TCoords.X - rightTx) * tmpDiv); + rightTyStep = (s32)((v3->TCoords.Y - rightTy) * tmpDiv); + + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + leftdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + leftZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); + leftTxStep = (s32)((v2->TCoords.X - leftTx) * tmpDiv); + leftTyStep = (s32)((v2->TCoords.Y - leftTy) * tmpDiv); + } + + + // do it twice, once for the first half of the triangle, + // end then for the second half. + + for (s32 triangleHalf=0; triangleHalf<2; ++triangleHalf) + { + if (spanEnd > ViewPortRect.LowerRightCorner.Y) + spanEnd = ViewPortRect.LowerRightCorner.Y; + + // if the span <0, than we can skip these spans, + // and proceed to the next spans which are really on the screen. + if (span < ViewPortRect.UpperLeftCorner.Y) + { + // we'll use leftx as temp variable + if (spanEnd < ViewPortRect.UpperLeftCorner.Y) + { + leftx = spanEnd - span; + span = spanEnd; + } + else + { + leftx = ViewPortRect.UpperLeftCorner.Y - span; + span = ViewPortRect.UpperLeftCorner.Y; + } + + leftxf += leftdeltaxf*leftx; + rightxf += rightdeltaxf*leftx; + targetSurface += SurfaceWidth*leftx; + zTarget += SurfaceWidth*leftx; + leftZValue += leftZStep*leftx; + rightZValue += rightZStep*leftx; + + leftTx += leftTxStep*leftx; + leftTy += leftTyStep*leftx; + rightTx += rightTxStep*leftx; + rightTy += rightTyStep*leftx; + } + + + // the main loop. Go through every span and draw it. + + while (span < spanEnd) + { + leftx = (s32)(leftxf); + rightx = (s32)(rightxf + 0.5f); + + // perform some clipping + + // TODO: clipping is not correct when leftx is clipped. + + if (leftxViewPortRect.LowerRightCorner.X) + leftx = ViewPortRect.LowerRightCorner.X; + + if (rightxViewPortRect.LowerRightCorner.X) + rightx = ViewPortRect.LowerRightCorner.X; + + // draw the span + + if (rightx - leftx != 0) + { + tmpDiv = 1.0f / (rightx - leftx); + spanZValue = leftZValue; + spanZStep = (s32)((rightZValue - leftZValue) * tmpDiv); + + hSpanBegin = targetSurface + leftx; + spanZTarget = zTarget + leftx; + hSpanEnd = targetSurface + rightx; + + spanTx = leftTx; + spanTy = leftTy; + spanTxStep = (s32)((rightTx - leftTx) * tmpDiv); + spanTyStep = (s32)((rightTy - leftTy) * tmpDiv); + + while (hSpanBegin < hSpanEnd) + { + if (spanZValue > *spanZTarget) + { + *spanZTarget = spanZValue; + *hSpanBegin = lockedTexture[((spanTy>>8)&textureYMask) * lockedTextureWidth + ((spanTx>>8)&textureXMask)]; + } + + spanTx += spanTxStep; + spanTy += spanTyStep; + + spanZValue += spanZStep; + ++hSpanBegin; + ++spanZTarget; + } + } + + leftxf += leftdeltaxf; + rightxf += rightdeltaxf; + ++span; + targetSurface += SurfaceWidth; + zTarget += SurfaceWidth; + leftZValue += leftZStep; + rightZValue += rightZStep; + + leftTx += leftTxStep; + leftTy += leftTyStep; + rightTx += rightTxStep; + rightTy += rightTyStep; + } + + if (triangleHalf>0) // break, we've gout only two halves + break; + + + // setup variables for second half of the triangle. + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + rightdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + rightxf = (f32)v2->Pos.X; + + rightZValue = v2->ZValue; + rightZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); + + rightTx = v2->TCoords.X; + rightTy = v2->TCoords.Y; + rightTxStep = (s32)((v3->TCoords.X - rightTx) * tmpDiv); + rightTyStep = (s32)((v3->TCoords.Y - rightTy) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + leftdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + leftxf = (f32)v2->Pos.X; + + leftZValue = v2->ZValue; + leftZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); + + leftTx = v2->TCoords.X; + leftTy = v2->TCoords.Y; + leftTxStep = (s32)((v3->TCoords.X - leftTx) * tmpDiv); + leftTyStep = (s32)((v3->TCoords.Y - leftTy) * tmpDiv); + } + + + spanEnd = v3->Pos.Y; + } + + } + + ZBuffer->unlock(); + } +}; + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + +//! creates a flat triangle renderer +ITriangleRenderer* createTriangleRendererTextureFlat(IZBuffer* zbuffer) +{ + #ifdef _IRR_COMPILE_WITH_SOFTWARE_ + return new CTRTextureFlat(zbuffer); + #else + return 0; + #endif // _IRR_COMPILE_WITH_SOFTWARE_ +} + +} // end namespace video +} // end namespace irr diff --git a/source/Irrlicht/CTRTextureFlatWire.cpp b/source/Irrlicht/CTRTextureFlatWire.cpp new file mode 100644 index 00000000..2147edd0 --- /dev/null +++ b/source/Irrlicht/CTRTextureFlatWire.cpp @@ -0,0 +1,310 @@ +// Copyright (C) 2002-2012 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" +#include "CTRTextureGouraud.h" + +#ifdef _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + +class CTRTextureFlatWire : public CTRTextureGouraud +{ +public: + + CTRTextureFlatWire(IZBuffer* zbuffer) + : CTRTextureGouraud(zbuffer) + { + #ifdef _DEBUG + setDebugName("CTRTextureFlatWire"); + #endif + } + + //! draws an indexed triangle list + virtual void drawIndexedTriangleList(S2DVertex* vertices, s32 vertexCount, const u16* indexList, s32 triangleCount) _IRR_OVERRIDE_ + { + const S2DVertex *v1, *v2, *v3; + + f32 tmpDiv; // temporary division factor + f32 longest; // saves the longest span + s32 height; // saves height of triangle + u16* targetSurface; // target pointer where to plot pixels + s32 spanEnd; // saves end of spans + f32 leftdeltaxf; // amount of pixels to increase on left side of triangle + f32 rightdeltaxf; // amount of pixels to increase on right side of triangle + s32 leftx, rightx; // position where we are + f32 leftxf, rightxf; // same as above, but as f32 values + s32 span; // current span + s32 leftTx, rightTx, leftTy, rightTy; // texture interpolating values + s32 leftTxStep, rightTxStep, leftTyStep, rightTyStep; // texture interpolating values + core::rect TriangleRect; + + s32 leftZValue, rightZValue; + s32 leftZStep, rightZStep; + TZBufferType* zTarget; // target of ZBuffer; + + lockedSurface = (u16*)RenderTarget->getData(); + lockedZBuffer = ZBuffer->lock(); + lockedTexture = (u16*)Texture->getData(); + + for (s32 i=0; iPos.X - v1->Pos.X) * (v3->Pos.Y - v2->Pos.Y)) - + ((v3->Pos.Y - v1->Pos.Y) * (v3->Pos.X - v2->Pos.X)); + + if (z < 0) + continue; + } + + //near plane clipping + + if (v1->ZValue<0 && v2->ZValue<0 && v3->ZValue<0) + continue; + + // sort for width for inscreen clipping + + if (v1->Pos.X > v2->Pos.X) swapVertices(&v1, &v2); + if (v1->Pos.X > v3->Pos.X) swapVertices(&v1, &v3); + if (v2->Pos.X > v3->Pos.X) swapVertices(&v2, &v3); + + if ((v1->Pos.X - v3->Pos.X) == 0) + continue; + + TriangleRect.UpperLeftCorner.X = v1->Pos.X; + TriangleRect.LowerRightCorner.X = v3->Pos.X; + + // sort for height for faster drawing. + + if (v1->Pos.Y > v2->Pos.Y) swapVertices(&v1, &v2); + if (v1->Pos.Y > v3->Pos.Y) swapVertices(&v1, &v3); + if (v2->Pos.Y > v3->Pos.Y) swapVertices(&v2, &v3); + + TriangleRect.UpperLeftCorner.Y = v1->Pos.Y; + TriangleRect.LowerRightCorner.Y = v3->Pos.Y; + + if (!TriangleRect.isRectCollided(ViewPortRect)) + continue; + + // calculate height of triangle + height = v3->Pos.Y - v1->Pos.Y; + if (!height) + continue; + + // calculate longest span + + longest = (v2->Pos.Y - v1->Pos.Y) / (f32)height * (v3->Pos.X - v1->Pos.X) + (v1->Pos.X - v2->Pos.X); + + spanEnd = v2->Pos.Y; + span = v1->Pos.Y; + leftxf = (f32)v1->Pos.X; + rightxf = (f32)v1->Pos.X; + + leftZValue = v1->ZValue; + rightZValue = v1->ZValue; + + leftTx = rightTx = v1->TCoords.X; + leftTy = rightTy = v1->TCoords.Y; + + targetSurface = lockedSurface + span * SurfaceWidth; + zTarget = lockedZBuffer + span * SurfaceWidth; + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + rightdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + rightZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); + rightTxStep = (s32)((v2->TCoords.X - rightTx) * tmpDiv); + rightTyStep = (s32)((v2->TCoords.Y - rightTy) * tmpDiv); + + tmpDiv = 1.0f / (f32)height; + leftdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + leftZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); + leftTxStep = (s32)((v3->TCoords.X - leftTx) * tmpDiv); + leftTyStep = (s32)((v3->TCoords.Y - leftTy) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (f32)height; + rightdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + rightZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); + rightTxStep = (s32)((v3->TCoords.X - rightTx) * tmpDiv); + rightTyStep = (s32)((v3->TCoords.Y - rightTy) * tmpDiv); + + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + leftdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + leftZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); + leftTxStep = (s32)((v2->TCoords.X - leftTx) * tmpDiv); + leftTyStep = (s32)((v2->TCoords.Y - leftTy) * tmpDiv); + } + + + // do it twice, once for the first half of the triangle, + // end then for the second half. + + for (s32 triangleHalf=0; triangleHalf<2; ++triangleHalf) + { + if (spanEnd > ViewPortRect.LowerRightCorner.Y) + spanEnd = ViewPortRect.LowerRightCorner.Y; + + // if the span <0, than we can skip these spans, + // and proceed to the next spans which are really on the screen. + if (span < ViewPortRect.UpperLeftCorner.Y) + { + // we'll use leftx as temp variable + if (spanEnd < ViewPortRect.UpperLeftCorner.Y) + { + leftx = spanEnd - span; + span = spanEnd; + } + else + { + leftx = ViewPortRect.UpperLeftCorner.Y - span; + span = ViewPortRect.UpperLeftCorner.Y; + } + + leftxf += leftdeltaxf*leftx; + rightxf += rightdeltaxf*leftx; + targetSurface += SurfaceWidth*leftx; + zTarget += SurfaceWidth*leftx; + leftZValue += leftZStep*leftx; + rightZValue += rightZStep*leftx; + + leftTx += leftTxStep*leftx; + leftTy += leftTyStep*leftx; + rightTx += rightTxStep*leftx; + rightTy += rightTyStep*leftx; + } + + + // the main loop. Go through every span and draw it. + + while (span < spanEnd) + { + leftx = (s32)(leftxf); + rightx = (s32)(rightxf + 0.5f); + + // perform some clipping + + if (leftx>=ViewPortRect.UpperLeftCorner.X && + leftx<=ViewPortRect.LowerRightCorner.X) + { + if (leftZValue > *(zTarget + leftx)) + { + *(zTarget + leftx) = leftZValue; + *(targetSurface + leftx) = lockedTexture[((leftTy>>8)&textureYMask) * lockedTextureWidth + ((rightTx>>8)&textureXMask)]; + } + } + + + if (rightx>=ViewPortRect.UpperLeftCorner.X && + rightx<=ViewPortRect.LowerRightCorner.X) + { + if (rightZValue > *(zTarget + rightx)) + { + *(zTarget + rightx) = rightZValue; + *(targetSurface + rightx) = lockedTexture[((rightTy>>8)&textureYMask) * lockedTextureWidth + ((rightTx>>8)&textureXMask)]; + } + + } + + + leftxf += leftdeltaxf; + rightxf += rightdeltaxf; + ++span; + targetSurface += SurfaceWidth; + zTarget += SurfaceWidth; + leftZValue += leftZStep; + rightZValue += rightZStep; + + leftTx += leftTxStep; + leftTy += leftTyStep; + rightTx += rightTxStep; + rightTy += rightTyStep; + } + + if (triangleHalf>0) // break, we've gout only two halves + break; + + + // setup variables for second half of the triangle. + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + rightdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + rightxf = (f32)v2->Pos.X; + + rightZValue = v2->ZValue; + rightZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); + + rightTx = v2->TCoords.X; + rightTy = v2->TCoords.Y; + rightTxStep = (s32)((v3->TCoords.X - rightTx) * tmpDiv); + rightTyStep = (s32)((v3->TCoords.Y - rightTy) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + leftdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + leftxf = (f32)v2->Pos.X; + + leftZValue = v2->ZValue; + leftZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); + + leftTx = v2->TCoords.X; + leftTy = v2->TCoords.Y; + leftTxStep = (s32)((v3->TCoords.X - leftTx) * tmpDiv); + leftTyStep = (s32)((v3->TCoords.Y - leftTy) * tmpDiv); + } + + + spanEnd = v3->Pos.Y; + } + + } + + ZBuffer->unlock(); + } +}; + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + +//! creates a flat triangle renderer +ITriangleRenderer* createTriangleRendererTextureFlatWire(IZBuffer* zbuffer) +{ + #ifdef _IRR_COMPILE_WITH_SOFTWARE_ + return new CTRTextureFlatWire(zbuffer); + #else + return 0; + #endif // _IRR_COMPILE_WITH_SOFTWARE_ +} + +} // end namespace video +} // end namespace irr + + diff --git a/source/Irrlicht/CTRTextureGouraud.cpp b/source/Irrlicht/CTRTextureGouraud.cpp new file mode 100644 index 00000000..74641a37 --- /dev/null +++ b/source/Irrlicht/CTRTextureGouraud.cpp @@ -0,0 +1,466 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CTRTextureGouraud.h" + +#ifdef _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + +//! constructor +CTRTextureGouraud::CTRTextureGouraud(IZBuffer* zbuffer) + : RenderTarget(0), ZBuffer(zbuffer), SurfaceWidth(0), SurfaceHeight(0), + BackFaceCullingEnabled(true), lockedZBuffer(0), + lockedSurface(0), lockedTexture(0), lockedTextureWidth(0), + textureXMask(0), textureYMask(0), Texture(0) +{ + #ifdef _DEBUG + setDebugName("CTRTextureGouraud"); + #endif + + if (ZBuffer) + zbuffer->grab(); +} + + + +//! destructor +CTRTextureGouraud::~CTRTextureGouraud() +{ + if (RenderTarget) + RenderTarget->drop(); + + if (ZBuffer) + ZBuffer->drop(); + + if (Texture) + Texture->drop(); +} + + + +//! sets the Texture +void CTRTextureGouraud::setTexture(video::IImage* texture) +{ + if (Texture) + Texture->drop(); + + Texture = texture; + + if (Texture) + { + Texture->grab(); + lockedTextureWidth = Texture->getDimension().Width; + + textureXMask = lockedTextureWidth-1; + textureYMask = Texture->getDimension().Height-1; + } +} + + + + +//! en or disables the backface culling +void CTRTextureGouraud::setBackfaceCulling(bool enabled) +{ + BackFaceCullingEnabled = enabled; +} + + + +//! sets a render target +void CTRTextureGouraud::setRenderTarget(video::IImage* surface, const core::rect& viewPort) +{ + if (RenderTarget) + RenderTarget->drop(); + + RenderTarget = surface; + + if (RenderTarget) + { + SurfaceWidth = RenderTarget->getDimension().Width; + SurfaceHeight = RenderTarget->getDimension().Height; + RenderTarget->grab(); + ViewPortRect = viewPort; + } +} + + + +//! draws an indexed triangle list +void CTRTextureGouraud::drawIndexedTriangleList(S2DVertex* vertices, s32 vertexCount, const u16* indexList, s32 triangleCount) +{ + const S2DVertex *v1, *v2, *v3; + + f32 tmpDiv; // temporary division factor + f32 longest; // saves the longest span + s32 height; // saves height of triangle + u16* targetSurface; // target pointer where to plot pixels + s32 spanEnd; // saves end of spans + f32 leftdeltaxf; // amount of pixels to increase on left side of triangle + f32 rightdeltaxf; // amount of pixels to increase on right side of triangle + s32 leftx, rightx; // position where we are + f32 leftxf, rightxf; // same as above, but as f32 values + s32 span; // current span + u16 *hSpanBegin, *hSpanEnd; // pointer used when plotting pixels + s32 leftR, leftG, leftB, rightR, rightG, rightB; // color values + s32 leftStepR, leftStepG, leftStepB, + rightStepR, rightStepG, rightStepB; // color steps + s32 spanR, spanG, spanB, spanStepR, spanStepG, spanStepB; // color interpolating values while drawing a span. + s32 leftTx, rightTx, leftTy, rightTy; // texture interpolating values + s32 leftTxStep, rightTxStep, leftTyStep, rightTyStep; // texture interpolating values + s32 spanTx, spanTy, spanTxStep, spanTyStep; // values of Texturecoords when drawing a span + core::rect TriangleRect; + + s32 leftZValue, rightZValue; + s32 leftZStep, rightZStep; + s32 spanZValue, spanZStep; // ZValues when drawing a span + TZBufferType* zTarget, *spanZTarget; // target of ZBuffer; + + lockedSurface = (u16*)RenderTarget->getData(); + lockedZBuffer = ZBuffer->lock(); + lockedTexture = (u16*)Texture->getData(); + + for (s32 i=0; iPos.X - v1->Pos.X) * (v3->Pos.Y - v2->Pos.Y)) - + ((v3->Pos.Y - v1->Pos.Y) * (v3->Pos.X - v2->Pos.X)); + + if (z < 0) + continue; + } + + //near plane clipping + + if (v1->ZValue<0 && v2->ZValue<0 && v3->ZValue<0) + continue; + + // sort for width for inscreen clipping + + if (v1->Pos.X > v2->Pos.X) swapVertices(&v1, &v2); + if (v1->Pos.X > v3->Pos.X) swapVertices(&v1, &v3); + if (v2->Pos.X > v3->Pos.X) swapVertices(&v2, &v3); + + if ((v1->Pos.X - v3->Pos.X) == 0) + continue; + + TriangleRect.UpperLeftCorner.X = v1->Pos.X; + TriangleRect.LowerRightCorner.X = v3->Pos.X; + + // sort for height for faster drawing. + + if (v1->Pos.Y > v2->Pos.Y) swapVertices(&v1, &v2); + if (v1->Pos.Y > v3->Pos.Y) swapVertices(&v1, &v3); + if (v2->Pos.Y > v3->Pos.Y) swapVertices(&v2, &v3); + + TriangleRect.UpperLeftCorner.Y = v1->Pos.Y; + TriangleRect.LowerRightCorner.Y = v3->Pos.Y; + + if (!TriangleRect.isRectCollided(ViewPortRect)) + continue; + + // calculate height of triangle + height = v3->Pos.Y - v1->Pos.Y; + if (!height) + continue; + + // calculate longest span + + longest = (v2->Pos.Y - v1->Pos.Y) / (f32)height * (v3->Pos.X - v1->Pos.X) + (v1->Pos.X - v2->Pos.X); + + spanEnd = v2->Pos.Y; + span = v1->Pos.Y; + leftxf = (f32)v1->Pos.X; + rightxf = (f32)v1->Pos.X; + + leftZValue = v1->ZValue; + rightZValue = v1->ZValue; + + leftR = rightR = video::getRed(v1->Color)<<8; + leftG = rightG = video::getGreen(v1->Color)<<8; + leftB = rightB = video::getBlue(v1->Color)<<8; + leftTx = rightTx = v1->TCoords.X; + leftTy = rightTy = v1->TCoords.Y; + + targetSurface = lockedSurface + span * SurfaceWidth; + zTarget = lockedZBuffer + span * SurfaceWidth; + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + rightdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + rightZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); + rightStepR = (s32)(((s32)(video::getRed(v2->Color)<<8) - rightR) * tmpDiv); + rightStepG = (s32)(((s32)(video::getGreen(v2->Color)<<8) - rightG) * tmpDiv); + rightStepB = (s32)(((s32)(video::getBlue(v2->Color)<<8) - rightB) * tmpDiv); + rightTxStep = (s32)((v2->TCoords.X - rightTx) * tmpDiv); + rightTyStep = (s32)((v2->TCoords.Y - rightTy) * tmpDiv); + + tmpDiv = 1.0f / (f32)height; + leftdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + leftZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); + leftStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - leftR) * tmpDiv); + leftStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - leftG) * tmpDiv); + leftStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - leftB) * tmpDiv); + leftTxStep = (s32)((v3->TCoords.X - leftTx) * tmpDiv); + leftTyStep = (s32)((v3->TCoords.Y - leftTy) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (f32)height; + rightdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + rightZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); + rightStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - rightR) * tmpDiv); + rightStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - rightG) * tmpDiv); + rightStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - rightB) * tmpDiv); + rightTxStep = (s32)((v3->TCoords.X - rightTx) * tmpDiv); + rightTyStep = (s32)((v3->TCoords.Y - rightTy) * tmpDiv); + + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + leftdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + leftZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); + leftStepR = (s32)(((s32)(video::getRed(v2->Color)<<8) - leftR) * tmpDiv); + leftStepG = (s32)(((s32)(video::getGreen(v2->Color)<<8) - leftG) * tmpDiv); + leftStepB = (s32)(((s32)(video::getBlue(v2->Color)<<8) - leftB) * tmpDiv); + leftTxStep = (s32)((v2->TCoords.X - leftTx) * tmpDiv); + leftTyStep = (s32)((v2->TCoords.Y - leftTy) * tmpDiv); + } + + + // do it twice, once for the first half of the triangle, + // end then for the second half. + + for (s32 triangleHalf=0; triangleHalf<2; ++triangleHalf) + { + if (spanEnd > ViewPortRect.LowerRightCorner.Y) + spanEnd = ViewPortRect.LowerRightCorner.Y; + + // if the span <0, than we can skip these spans, + // and proceed to the next spans which are really on the screen. + if (span < ViewPortRect.UpperLeftCorner.Y) + { + // we'll use leftx as temp variable + if (spanEnd < ViewPortRect.UpperLeftCorner.Y) + { + leftx = spanEnd - span; + span = spanEnd; + } + else + { + leftx = ViewPortRect.UpperLeftCorner.Y - span; + span = ViewPortRect.UpperLeftCorner.Y; + } + + leftxf += leftdeltaxf*leftx; + rightxf += rightdeltaxf*leftx; + targetSurface += SurfaceWidth*leftx; + zTarget += SurfaceWidth*leftx; + leftZValue += leftZStep*leftx; + rightZValue += rightZStep*leftx; + + leftR += leftStepR*leftx; + leftG += leftStepG*leftx; + leftB += leftStepB*leftx; + rightR += rightStepR*leftx; + rightG += rightStepG*leftx; + rightB += rightStepB*leftx; + + leftTx += leftTxStep*leftx; + leftTy += leftTyStep*leftx; + rightTx += rightTxStep*leftx; + rightTy += rightTyStep*leftx; + } + + + // the main loop. Go through every span and draw it. + + while (span < spanEnd) + { + leftx = (s32)(leftxf); + rightx = (s32)(rightxf + 0.5f); + + // perform some clipping + // thanks to a correction by hybrid + // calculations delayed to correctly propagate to textures etc. + s32 tDiffLeft=0, tDiffRight=0; + if (leftxViewPortRect.LowerRightCorner.X) + tDiffLeft=ViewPortRect.LowerRightCorner.X-leftx; + + if (rightxViewPortRect.LowerRightCorner.X) + tDiffRight=ViewPortRect.LowerRightCorner.X-rightx; + + // draw the span + if (rightx + tDiffRight - leftx - tDiffLeft) + { + tmpDiv = 1.0f / (f32)(rightx - leftx); + spanZStep = (s32)((rightZValue - leftZValue) * tmpDiv); + spanZValue = leftZValue+tDiffLeft*spanZStep; + + spanStepR = (s32)((rightR - leftR) * tmpDiv); + spanR = leftR+tDiffLeft*spanStepR; + spanStepG = (s32)((rightG - leftG) * tmpDiv); + spanG = leftG+tDiffLeft*spanStepG; + spanStepB = (s32)((rightB - leftB) * tmpDiv); + spanB = leftB+tDiffLeft*spanStepB; + + spanTxStep = (s32)((rightTx - leftTx) * tmpDiv); + spanTx = leftTx + tDiffLeft*spanTxStep; + spanTyStep = (s32)((rightTy - leftTy) * tmpDiv); + spanTy = leftTy+tDiffLeft*spanTyStep; + + hSpanBegin = targetSurface + leftx+tDiffLeft; + spanZTarget = zTarget + leftx+tDiffLeft; + hSpanEnd = targetSurface + rightx+tDiffRight; + + while (hSpanBegin < hSpanEnd) + { + if (spanZValue > *spanZTarget) + { + *spanZTarget = spanZValue; + u16 color = lockedTexture[((spanTy>>8)&textureYMask) * lockedTextureWidth + ((spanTx>>8)&textureXMask)]; + *hSpanBegin = video::RGB16(video::getRed(color) * (spanR>>8) >>2, + video::getGreen(color) * (spanG>>8) >>2, + video::getBlue(color) * (spanB>>8) >>2); + } + + spanR += spanStepR; + spanG += spanStepG; + spanB += spanStepB; + + spanTx += spanTxStep; + spanTy += spanTyStep; + + spanZValue += spanZStep; + ++hSpanBegin; + ++spanZTarget; + } + } + + leftxf += leftdeltaxf; + rightxf += rightdeltaxf; + ++span; + targetSurface += SurfaceWidth; + zTarget += SurfaceWidth; + leftZValue += leftZStep; + rightZValue += rightZStep; + + leftR += leftStepR; + leftG += leftStepG; + leftB += leftStepB; + rightR += rightStepR; + rightG += rightStepG; + rightB += rightStepB; + + leftTx += leftTxStep; + leftTy += leftTyStep; + rightTx += rightTxStep; + rightTy += rightTyStep; + } + + if (triangleHalf>0) // break, we've gout only two halves + break; + + + // setup variables for second half of the triangle. + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + rightdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + rightxf = (f32)v2->Pos.X; + + rightZValue = v2->ZValue; + rightZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); + + rightR = video::getRed(v2->Color)<<8; + rightG = video::getGreen(v2->Color)<<8; + rightB = video::getBlue(v2->Color)<<8; + rightStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - rightR) * tmpDiv); + rightStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - rightG) * tmpDiv); + rightStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - rightB) * tmpDiv); + + rightTx = v2->TCoords.X; + rightTy = v2->TCoords.Y; + rightTxStep = (s32)((v3->TCoords.X - rightTx) * tmpDiv); + rightTyStep = (s32)((v3->TCoords.Y - rightTy) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + leftdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + leftxf = (f32)v2->Pos.X; + + leftZValue = v2->ZValue; + leftZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); + + leftR = video::getRed(v2->Color)<<8; + leftG = video::getGreen(v2->Color)<<8; + leftB = video::getBlue(v2->Color)<<8; + leftStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - leftR) * tmpDiv); + leftStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - leftG) * tmpDiv); + leftStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - leftB) * tmpDiv); + + leftTx = v2->TCoords.X; + leftTy = v2->TCoords.Y; + leftTxStep = (s32)((v3->TCoords.X - leftTx) * tmpDiv); + leftTyStep = (s32)((v3->TCoords.Y - leftTy) * tmpDiv); + } + + + spanEnd = v3->Pos.Y; + } + + } + + ZBuffer->unlock(); +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + +//! creates a flat triangle renderer +ITriangleRenderer* createTriangleRendererTextureGouraud(IZBuffer* zbuffer) +{ + #ifdef _IRR_COMPILE_WITH_SOFTWARE_ + return new CTRTextureGouraud(zbuffer); + #else + return 0; + #endif // _IRR_COMPILE_WITH_SOFTWARE_ +} + + +} // end namespace video +} // end namespace irr + + diff --git a/source/Irrlicht/CTRTextureGouraud.h b/source/Irrlicht/CTRTextureGouraud.h new file mode 100644 index 00000000..02cc6033 --- /dev/null +++ b/source/Irrlicht/CTRTextureGouraud.h @@ -0,0 +1,85 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_TRIANGLE_RENDERER_TEXTURE_GOURAUD_H_INCLUDED__ +#define __C_TRIANGLE_RENDERER_TEXTURE_GOURAUD_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifndef _IRR_COMPILE_WITH_SOFTWARE_ +// forward declarations for create methods +namespace irr +{ +namespace video +{ + class ITriangleRenderer; + class IZBuffer; +} // end namespace video +} // end namespace irr + +#else + +#include "ITriangleRenderer.h" +#include "IImage.h" + +namespace irr +{ +namespace video +{ + //! CTRTextureGouraud class + class CTRTextureGouraud : public ITriangleRenderer + { + public: + + //! constructor + CTRTextureGouraud(IZBuffer* zbuffer); + + //! destructor + virtual ~CTRTextureGouraud(); + + //! sets a render target + virtual void setRenderTarget(video::IImage* surface, const core::rect& viewPort) _IRR_OVERRIDE_; + + //! draws an indexed triangle list + virtual void drawIndexedTriangleList(S2DVertex* vertices, s32 vertexCount, const u16* indexList, s32 triangleCount) _IRR_OVERRIDE_; + + //! en or disables the backface culling + virtual void setBackfaceCulling(bool enabled = true) _IRR_OVERRIDE_; + + //! sets the Texture + virtual void setTexture(video::IImage* texture) _IRR_OVERRIDE_; + + protected: + + //! vertauscht zwei vertizen + inline void swapVertices(const S2DVertex** v1, const S2DVertex** v2) + { + const S2DVertex* b = *v1; + *v1 = *v2; + *v2 = b; + } + + video::IImage* RenderTarget; + core::rect ViewPortRect; + + IZBuffer* ZBuffer; + + s32 SurfaceWidth; + s32 SurfaceHeight; + bool BackFaceCullingEnabled; + TZBufferType* lockedZBuffer; + u16* lockedSurface; + u16* lockedTexture; + s32 lockedTextureWidth; + s32 textureXMask, textureYMask; + video::IImage* Texture; + }; + +} // end namespace video +} // end namespace irr + +#endif + +#endif + diff --git a/source/Irrlicht/CTRTextureGouraud2.cpp b/source/Irrlicht/CTRTextureGouraud2.cpp new file mode 100644 index 00000000..7bcc512b --- /dev/null +++ b/source/Irrlicht/CTRTextureGouraud2.cpp @@ -0,0 +1,672 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 + +// define render case +#define SUBTEXEL +#define INVERSE_W + +#define USE_ZBUFFER +#define IPOL_W +#define CMP_W +#define WRITE_W + +#define IPOL_C0 +#define IPOL_T0 +//#define IPOL_T1 + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #undef IPOL_C0 +#endif + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif + #define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + + +namespace irr +{ + +namespace video +{ + +class CTRTextureGouraud2 : public IBurningShader +{ +public: + + //! constructor + CTRTextureGouraud2(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + + +private: + void scanline_bilinear (); + sScanConvertData scan; + sScanLineData line; + +}; + +//! constructor +CTRTextureGouraud2::CTRTextureGouraud2(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRTextureGouraud2"); + #endif +} + + + +/*! +*/ +void CTRTextureGouraud2::scanline_bilinear () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + f32 inversew = FIX_POINT_F32_MUL; + + tFixPoint tx0; + tFixPoint ty0; + + tFixPoint r0, g0, b0; + +#ifdef IPOL_C0 + tFixPoint r1, g1, b1; +#endif + +#ifdef BURNINGVIDEO_RENDERER_FAST + u32 dIndex = ( line.y & 3 ) << 2; +#endif + + for ( s32 i = 0; i <= dx; ++i ) + { +#ifdef CMP_Z + if ( line.z[0] < z[i] ) +#endif +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + { +#ifdef WRITE_Z + z[i] = line.z[0]; +#endif +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + + +#ifdef INVERSE_W + inversew = fix_inverse32 ( line.w[0] ); + tx0 = tofix ( line.t[0][0].x, inversew); + ty0 = tofix ( line.t[0][0].y, inversew); + +#ifdef IPOL_C0 + r1 = tofix ( line.c[0][0].y ,inversew ); + g1 = tofix ( line.c[0][0].z ,inversew ); + b1 = tofix ( line.c[0][0].w ,inversew ); +#endif + +#else + tx0 = tofix(line.t[0][0].x, inversew); + ty0 = tofix(line.t[0][0].y, inversew); +#ifdef IPOL_C0 + getTexel_plain2 ( r1, g1, b1, line.c[0][0] ); +#endif +#endif + +#ifdef IPOL_C0 + getSample_texture ( r0, g0, b0, &IT[0], tx0,ty0 ); + + dst[i] = fix_to_color ( imulFix ( r0, r1 ), + imulFix ( g0, g1 ), + imulFix ( b0, b1 ) + ); +#else + +#ifdef BURNINGVIDEO_RENDERER_FAST + const tFixPointu d = dithermask [ dIndex | ( i ) & 3 ]; + dst[i] = getTexel_plain ( &IT[0], d + tx0, d + ty0 ); +#else + getSample_texture ( r0, g0, b0, &IT[0], tx0,ty0 ); + dst[i] = fix_to_color ( r0, g0, b0 ); +#endif + +#endif + + } + +#ifdef IPOL_Z + line.z[0] += slopeZ; +#endif +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1]; +#endif + } + +} + +void CTRTextureGouraud2::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) ) + return; + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0][0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + // rasterize upper sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[1] ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[0][1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + // rasterize lower sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[2] ) + { + // advance to middle point + if( (f32) 0.0 != scan.invDeltaY[1] ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0][0] = a->Color[0] + scan.slopeC[0][0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[0][1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear ( ); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + +} + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + +//! creates a flat triangle renderer +IBurningShader* createTriangleRendererTextureGouraud2(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRTextureGouraud2(driver); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + + diff --git a/source/Irrlicht/CTRTextureGouraudAdd.cpp b/source/Irrlicht/CTRTextureGouraudAdd.cpp new file mode 100644 index 00000000..853bef27 --- /dev/null +++ b/source/Irrlicht/CTRTextureGouraudAdd.cpp @@ -0,0 +1,417 @@ +// Copyright (C) 2002-2012 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" +#include "CTRTextureGouraud.h" + +#ifdef _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + +class CTRTextureGouraudAdd : public CTRTextureGouraud +{ +public: + + //! constructor + CTRTextureGouraudAdd(IZBuffer* zbuffer); + + //! draws an indexed triangle list + virtual void drawIndexedTriangleList(S2DVertex* vertices, s32 vertexCount, const u16* indexList, s32 triangleCount) _IRR_OVERRIDE_; + +protected: + +}; + +//! constructor +CTRTextureGouraudAdd::CTRTextureGouraudAdd(IZBuffer* zbuffer) +: CTRTextureGouraud(zbuffer) +{ + #ifdef _DEBUG + setDebugName("CTRTextureGouraudAdd"); + #endif +} + + +//! draws an indexed triangle list +void CTRTextureGouraudAdd::drawIndexedTriangleList(S2DVertex* vertices, s32 vertexCount, const u16* indexList, s32 triangleCount) +{ + const S2DVertex *v1, *v2, *v3; + + u16 color; + f32 tmpDiv; // temporary division factor + f32 longest; // saves the longest span + s32 height; // saves height of triangle + u16* targetSurface; // target pointer where to plot pixels + s32 spanEnd; // saves end of spans + f32 leftdeltaxf; // amount of pixels to increase on left side of triangle + f32 rightdeltaxf; // amount of pixels to increase on right side of triangle + s32 leftx, rightx; // position where we are + f32 leftxf, rightxf; // same as above, but as f32 values + s32 span; // current span + u16 *hSpanBegin, *hSpanEnd; // pointer used when plotting pixels + s32 leftR, leftG, leftB, rightR, rightG, rightB; // color values + s32 leftStepR, leftStepG, leftStepB, + rightStepR, rightStepG, rightStepB; // color steps + s32 spanR, spanG, spanB, spanStepR, spanStepG, spanStepB; // color interpolating values while drawing a span. + s32 leftTx, rightTx, leftTy, rightTy; // texture interpolating values + s32 leftTxStep, rightTxStep, leftTyStep, rightTyStep; // texture interpolating values + s32 spanTx, spanTy, spanTxStep, spanTyStep; // values of Texturecoords when drawing a span + core::rect TriangleRect; + + s32 leftZValue, rightZValue; + s32 leftZStep, rightZStep; + s32 spanZValue, spanZStep; // ZValues when drawing a span + TZBufferType* zTarget, *spanZTarget; // target of ZBuffer; + + lockedSurface = (u16*)RenderTarget->getData(); + lockedZBuffer = ZBuffer->lock(); + lockedTexture = (u16*)Texture->getData(); + + for (s32 i=0; iPos.X - v1->Pos.X) * (v3->Pos.Y - v2->Pos.Y)) - + ((v3->Pos.Y - v1->Pos.Y) * (v3->Pos.X - v2->Pos.X)); + + if (z < 0) + continue; + } + + //near plane clipping + + if (v1->ZValue<0 && v2->ZValue<0 && v3->ZValue<0) + continue; + + // sort for width for inscreen clipping + + if (v1->Pos.X > v2->Pos.X) swapVertices(&v1, &v2); + if (v1->Pos.X > v3->Pos.X) swapVertices(&v1, &v3); + if (v2->Pos.X > v3->Pos.X) swapVertices(&v2, &v3); + + if ((v1->Pos.X - v3->Pos.X) == 0) + continue; + + TriangleRect.UpperLeftCorner.X = v1->Pos.X; + TriangleRect.LowerRightCorner.X = v3->Pos.X; + + // sort for height for faster drawing. + + if (v1->Pos.Y > v2->Pos.Y) swapVertices(&v1, &v2); + if (v1->Pos.Y > v3->Pos.Y) swapVertices(&v1, &v3); + if (v2->Pos.Y > v3->Pos.Y) swapVertices(&v2, &v3); + + TriangleRect.UpperLeftCorner.Y = v1->Pos.Y; + TriangleRect.LowerRightCorner.Y = v3->Pos.Y; + + if (!TriangleRect.isRectCollided(ViewPortRect)) + continue; + + // calculate height of triangle + height = v3->Pos.Y - v1->Pos.Y; + if (!height) + continue; + + // calculate longest span + + longest = (v2->Pos.Y - v1->Pos.Y) / (f32)height * (v3->Pos.X - v1->Pos.X) + (v1->Pos.X - v2->Pos.X); + + spanEnd = v2->Pos.Y; + span = v1->Pos.Y; + leftxf = (f32)v1->Pos.X; + rightxf = (f32)v1->Pos.X; + + leftZValue = v1->ZValue; + rightZValue = v1->ZValue; + + leftR = rightR = video::getRed(v1->Color)<<8; + leftG = rightG = video::getGreen(v1->Color)<<8; + leftB = rightB = video::getBlue(v1->Color)<<8; + leftTx = rightTx = v1->TCoords.X; + leftTy = rightTy = v1->TCoords.Y; + + targetSurface = lockedSurface + span * SurfaceWidth; + zTarget = lockedZBuffer + span * SurfaceWidth; + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + rightdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + rightZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); + rightStepR = (s32)(((s32)(video::getRed(v2->Color)<<8) - rightR) * tmpDiv); + rightStepG = (s32)(((s32)(video::getGreen(v2->Color)<<8) - rightG) * tmpDiv); + rightStepB = (s32)(((s32)(video::getBlue(v2->Color)<<8) - rightB) * tmpDiv); + rightTxStep = (s32)((v2->TCoords.X - rightTx) * tmpDiv); + rightTyStep = (s32)((v2->TCoords.Y - rightTy) * tmpDiv); + + tmpDiv = 1.0f / (f32)height; + leftdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + leftZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); + leftStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - leftR) * tmpDiv); + leftStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - leftG) * tmpDiv); + leftStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - leftB) * tmpDiv); + leftTxStep = (s32)((v3->TCoords.X - leftTx) * tmpDiv); + leftTyStep = (s32)((v3->TCoords.Y - leftTy) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (f32)height; + rightdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + rightZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); + rightStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - rightR) * tmpDiv); + rightStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - rightG) * tmpDiv); + rightStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - rightB) * tmpDiv); + rightTxStep = (s32)((v3->TCoords.X - rightTx) * tmpDiv); + rightTyStep = (s32)((v3->TCoords.Y - rightTy) * tmpDiv); + + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + leftdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + leftZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); + leftStepR = (s32)(((s32)(video::getRed(v2->Color)<<8) - leftR) * tmpDiv); + leftStepG = (s32)(((s32)(video::getGreen(v2->Color)<<8) - leftG) * tmpDiv); + leftStepB = (s32)(((s32)(video::getBlue(v2->Color)<<8) - leftB) * tmpDiv); + leftTxStep = (s32)((v2->TCoords.X - leftTx) * tmpDiv); + leftTyStep = (s32)((v2->TCoords.Y - leftTy) * tmpDiv); + } + + + // do it twice, once for the first half of the triangle, + // end then for the second half. + + for (s32 triangleHalf=0; triangleHalf<2; ++triangleHalf) + { + if (spanEnd > ViewPortRect.LowerRightCorner.Y) + spanEnd = ViewPortRect.LowerRightCorner.Y; + + // if the span <0, than we can skip these spans, + // and proceed to the next spans which are really on the screen. + if (span < ViewPortRect.UpperLeftCorner.Y) + { + // we'll use leftx as temp variable + if (spanEnd < ViewPortRect.UpperLeftCorner.Y) + { + leftx = spanEnd - span; + span = spanEnd; + } + else + { + leftx = ViewPortRect.UpperLeftCorner.Y - span; + span = ViewPortRect.UpperLeftCorner.Y; + } + + leftxf += leftdeltaxf*leftx; + rightxf += rightdeltaxf*leftx; + targetSurface += SurfaceWidth*leftx; + zTarget += SurfaceWidth*leftx; + leftZValue += leftZStep*leftx; + rightZValue += rightZStep*leftx; + + leftR += leftStepR*leftx; + leftG += leftStepG*leftx; + leftB += leftStepB*leftx; + rightR += rightStepR*leftx; + rightG += rightStepG*leftx; + rightB += rightStepB*leftx; + + leftTx += leftTxStep*leftx; + leftTy += leftTyStep*leftx; + rightTx += rightTxStep*leftx; + rightTy += rightTyStep*leftx; + } + + + // the main loop. Go through every span and draw it. + + while (span < spanEnd) + { + leftx = (s32)(leftxf); + rightx = (s32)(rightxf + 0.5f); + + // perform some clipping + // thanks to a correction by hybrid + // calculations delayed to correctly propagate to textures etc. + s32 tDiffLeft=0, tDiffRight=0; + if (leftxViewPortRect.LowerRightCorner.X) + tDiffLeft=ViewPortRect.LowerRightCorner.X-leftx; + + if (rightxViewPortRect.LowerRightCorner.X) + tDiffRight=ViewPortRect.LowerRightCorner.X-rightx; + + // draw the span + if (rightx + tDiffRight - leftx - tDiffLeft) + { + tmpDiv = 1.0f / (f32)(rightx - leftx); + spanZStep = (s32)((rightZValue - leftZValue) * tmpDiv); + spanZValue = leftZValue+tDiffLeft*spanZStep; + + spanStepR = (s32)((rightR - leftR) * tmpDiv); + spanR = leftR+tDiffLeft*spanStepR; + spanStepG = (s32)((rightG - leftG) * tmpDiv); + spanG = leftG+tDiffLeft*spanStepG; + spanStepB = (s32)((rightB - leftB) * tmpDiv); + spanB = leftB+tDiffLeft*spanStepB; + + spanTxStep = (s32)((rightTx - leftTx) * tmpDiv); + spanTx = leftTx + tDiffLeft*spanTxStep; + spanTyStep = (s32)((rightTy - leftTy) * tmpDiv); + spanTy = leftTy+tDiffLeft*spanTyStep; + + hSpanBegin = targetSurface + leftx+tDiffLeft; + spanZTarget = zTarget + leftx+tDiffLeft; + hSpanEnd = targetSurface + rightx+tDiffRight; + + while (hSpanBegin < hSpanEnd) + { + if (spanZValue > *spanZTarget) + { + //*spanZTarget = spanZValue; + color = lockedTexture[((spanTy>>8)&textureYMask) * lockedTextureWidth + ((spanTx>>8)&textureXMask)]; + + s32 basis = *hSpanBegin; + s32 r = (video::getRed(basis)<<3) + (video::getRed(color)<<3); + if (r > 255) r = 255; + s32 g = (video::getGreen(basis)<<3) + (video::getGreen(color)<<3); + if (g > 255) g = 255; + s32 b = (video::getBlue(basis)<<3) + (video::getBlue(color)<<3); + if (b > 255) b = 255; + + *hSpanBegin = video::RGB16(r, g, b); + } + + spanR += spanStepR; + spanG += spanStepG; + spanB += spanStepB; + + spanTx += spanTxStep; + spanTy += spanTyStep; + + spanZValue += spanZStep; + ++hSpanBegin; + ++spanZTarget; + } + } + + leftxf += leftdeltaxf; + rightxf += rightdeltaxf; + ++span; + targetSurface += SurfaceWidth; + zTarget += SurfaceWidth; + leftZValue += leftZStep; + rightZValue += rightZStep; + + leftR += leftStepR; + leftG += leftStepG; + leftB += leftStepB; + rightR += rightStepR; + rightG += rightStepG; + rightB += rightStepB; + + leftTx += leftTxStep; + leftTy += leftTyStep; + rightTx += rightTxStep; + rightTy += rightTyStep; + } + + if (triangleHalf>0) // break, we've gout only two halves + break; + + + // setup variables for second half of the triangle. + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + rightdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + rightxf = (f32)v2->Pos.X; + + rightZValue = v2->ZValue; + rightZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); + + rightR = video::getRed(v2->Color)<<8; + rightG = video::getGreen(v2->Color)<<8; + rightB = video::getBlue(v2->Color)<<8; + rightStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - rightR) * tmpDiv); + rightStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - rightG) * tmpDiv); + rightStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - rightB) * tmpDiv); + + rightTx = v2->TCoords.X; + rightTy = v2->TCoords.Y; + rightTxStep = (s32)((v3->TCoords.X - rightTx) * tmpDiv); + rightTyStep = (s32)((v3->TCoords.Y - rightTy) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + leftdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + leftxf = (f32)v2->Pos.X; + + leftZValue = v2->ZValue; + leftZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); + + leftR = video::getRed(v2->Color)<<8; + leftG = video::getGreen(v2->Color)<<8; + leftB = video::getBlue(v2->Color)<<8; + leftStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - leftR) * tmpDiv); + leftStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - leftG) * tmpDiv); + leftStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - leftB) * tmpDiv); + + leftTx = v2->TCoords.X; + leftTy = v2->TCoords.Y; + leftTxStep = (s32)((v3->TCoords.X - leftTx) * tmpDiv); + leftTyStep = (s32)((v3->TCoords.Y - leftTy) * tmpDiv); + } + + + spanEnd = v3->Pos.Y; + } + + } + + ZBuffer->unlock(); +} + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + +ITriangleRenderer* createTriangleRendererTextureGouraudAdd(IZBuffer* zbuffer) +{ + #ifdef _IRR_COMPILE_WITH_SOFTWARE_ + return new CTRTextureGouraudAdd(zbuffer); + #else + return 0; + #endif // _IRR_COMPILE_WITH_SOFTWARE_ +} + +} // end namespace video +} // end namespace irr + + + diff --git a/source/Irrlicht/CTRTextureGouraudAdd2.cpp b/source/Irrlicht/CTRTextureGouraudAdd2.cpp new file mode 100644 index 00000000..0f54928f --- /dev/null +++ b/source/Irrlicht/CTRTextureGouraudAdd2.cpp @@ -0,0 +1,666 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 + +// define render case +#define SUBTEXEL +#define INVERSE_W + +#define USE_ZBUFFER +#define IPOL_W +#define CMP_W +#define WRITE_W + +//#define IPOL_C0 +#define IPOL_T0 +//#define IPOL_T1 + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #undef IPOL_C0 +#endif + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif + #define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + + + +namespace irr +{ + +namespace video +{ + +class CTRTextureGouraudAdd2 : public IBurningShader +{ +public: + + //! constructor + CTRTextureGouraudAdd2(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + + +private: + void scanline_bilinear (); + sScanLineData line; + +}; + +//! constructor +CTRTextureGouraudAdd2::CTRTextureGouraudAdd2(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRTextureGouraudAdd2"); + #endif +} + + + +/*! +*/ +void CTRTextureGouraudAdd2::scanline_bilinear () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC = (line.c[1] - line.c[0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0] += slopeC * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + f32 inversew = FIX_POINT_F32_MUL; + + +#ifdef BURNINGVIDEO_RENDERER_FAST + u32 dIndex = ( line.y & 3 ) << 2; + +#else + tFixPoint tx0; + tFixPoint ty0; + + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; +#endif + + + for ( s32 i = 0; i <= dx; ++i ) + { +#ifdef CMP_Z + if ( line.z[0] < z[i] ) +#endif +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + + { + + +#ifdef BURNINGVIDEO_RENDERER_FAST + + const tFixPointu d = dithermask [ dIndex | ( i ) & 3 ]; + + +#ifdef INVERSE_W + inversew = fix_inverse32 ( line.w[0] ); +#endif + dst[i] = PixelAdd32 ( + dst[i], + getTexel_plain ( &IT[0], d + tofix ( line.t[0][0].x,inversew), + d + tofix ( line.t[0][0].y,inversew) ) + ); +#else + +#ifdef INVERSE_W + inversew = fix_inverse32 ( line.w[0] ); +#endif + tx0 = tofix ( line.t[0][0].x,inversew); + ty0 = tofix ( line.t[0][0].y,inversew); + getSample_texture ( r0, g0, b0, &IT[0], tx0,ty0 ); + + color_to_fix ( r1, g1, b1, dst[i] ); + + dst[i] = fix_to_color ( clampfix_maxcolor ( r1 + r0 ), + clampfix_maxcolor ( g1 + g0 ), + clampfix_maxcolor ( b1 + b0 ) + ); +#endif + +#ifdef WRITE_Z + z[i] = line.z[0]; +#endif +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + + } + +#ifdef IPOL_Z + line.z[0] += slopeZ; +#endif +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_C0 + line.c[0] += slopeC; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1]; +#endif + } + +} + +void CTRTextureGouraudAdd2::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + sScanConvertData scan; + + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + // rasterize upper sub-triangle + if ( F32_GREATER_0 ( scan.invDeltaY[1] ) ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0] * subPixel; + scan.c[1] += scan.slopeC[1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[scan.left] = scan.c[0]; + line.c[scan.right] = scan.c[1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0]; + scan.c[1] += scan.slopeC[1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + // rasterize lower sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[2] ) + { + // advance to middle point + if( (f32) 0.0 != scan.invDeltaY[1] ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0] = a->Color[0] + scan.slopeC[0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0] * subPixel; + scan.c[1] += scan.slopeC[1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[scan.left] = scan.c[0]; + line.c[scan.right] = scan.c[1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0]; + scan.c[1] += scan.slopeC[1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + +//! creates a flat triangle renderer +IBurningShader* createTRTextureGouraudAdd2(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRTextureGouraudAdd2(driver); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + + diff --git a/source/Irrlicht/CTRTextureGouraudAddNoZ2.cpp b/source/Irrlicht/CTRTextureGouraudAddNoZ2.cpp new file mode 100644 index 00000000..1c7f586b --- /dev/null +++ b/source/Irrlicht/CTRTextureGouraudAddNoZ2.cpp @@ -0,0 +1,639 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 + +// define render case +#define SUBTEXEL +#define INVERSE_W + +#define USE_ZBUFFER +#define IPOL_W +#define CMP_W +//#define WRITE_W + +//#define IPOL_C0 +#define IPOL_T0 +//#define IPOL_T1 + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #undef IPOL_C0 +#endif + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + + +namespace irr +{ + +namespace video +{ + +class CTRTextureGouraudAddNoZ2 : public IBurningShader +{ +public: + + //! constructor + CTRTextureGouraudAddNoZ2(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + + +private: + void scanline_bilinear (); + sScanConvertData scan; + sScanLineData line; + +}; + +//! constructor +CTRTextureGouraudAddNoZ2::CTRTextureGouraudAddNoZ2(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRTextureGouraudAddNoZ2"); + #endif +} + + + +/*! +*/ +void CTRTextureGouraudAddNoZ2::scanline_bilinear () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC = (line.c[1] - line.c[0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0] += slopeC * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + f32 inversew = FIX_POINT_F32_MUL; + + tFixPoint tx0; + tFixPoint ty0; + + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; + + for ( s32 i = 0; i <= dx; ++i ) + { +#ifdef CMP_Z + if ( line.z[0] < z[i] ) +#endif +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + { +#ifdef IPOL_W + inversew = fix_inverse32 ( line.w[0] ); +#endif + tx0 = tofix ( line.t[0][0].x,inversew); + ty0 = tofix ( line.t[0][0].y,inversew); + + getSample_texture ( r0, g0, b0, &IT[0], tx0,ty0 ); + + color_to_fix ( r1, g1, b1, dst[i] ); + + dst[i] = fix_to_color ( clampfix_maxcolor ( r1 + (r0 >> 1 ) ), + clampfix_maxcolor ( g1 + (g0 >> 1 ) ), + clampfix_maxcolor ( b1 + (b0 >> 1) ) + ); + +#ifdef WRITE_Z + z[i] = line.z[0]; +#endif +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + } + +#ifdef IPOL_Z + line.z[0] += slopeZ; +#endif +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_C0 + line.c[0] += slopeC; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1]; +#endif + } + +} + +void CTRTextureGouraudAddNoZ2::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) ) + return; + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + // rasterize upper sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[1] ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0] * subPixel; + scan.c[1] += scan.slopeC[1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[scan.left] = scan.c[0]; + line.c[scan.right] = scan.c[1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0]; + scan.c[1] += scan.slopeC[1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + // rasterize lower sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[2] ) + { + // advance to middle point + if( (f32) 0.0 != scan.invDeltaY[1] ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0] = a->Color[0] + scan.slopeC[0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0] * subPixel; + scan.c[1] += scan.slopeC[1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[scan.left] = scan.c[0]; + line.c[scan.right] = scan.c[1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear ( ); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0]; + scan.c[1] += scan.slopeC[1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + +} + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + +//! creates a flat triangle renderer +IBurningShader* createTRTextureGouraudAddNoZ2(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRTextureGouraudAddNoZ2(driver); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + diff --git a/source/Irrlicht/CTRTextureGouraudAlpha.cpp b/source/Irrlicht/CTRTextureGouraudAlpha.cpp new file mode 100644 index 00000000..37bb477c --- /dev/null +++ b/source/Irrlicht/CTRTextureGouraudAlpha.cpp @@ -0,0 +1,734 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 + +// define render case +#define SUBTEXEL +#define INVERSE_W + +#define USE_ZBUFFER +#define IPOL_W +#define CMP_W +#define WRITE_W + +#define IPOL_C0 +#define IPOL_T0 +//#define IPOL_T1 + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #undef IPOL_C0 +#endif + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif + #define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + + + +namespace irr +{ + +namespace video +{ + +class CTRTextureGouraudAlpha2 : public IBurningShader +{ +public: + + //! constructor + CTRTextureGouraudAlpha2(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + + virtual void setParam ( u32 index, f32 value) _IRR_OVERRIDE_; + + +private: + void scanline_bilinear (); + + sScanConvertData scan; + sScanLineData line; + + u32 AlphaRef; +}; + +//! constructor +CTRTextureGouraudAlpha2::CTRTextureGouraudAlpha2(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRTextureGouraudAlpha2"); + #endif + + AlphaRef = 0; +} + + +/*! +*/ +void CTRTextureGouraudAlpha2::setParam ( u32 index, f32 value) +{ +#ifdef BURNINGVIDEO_RENDERER_FAST + AlphaRef = core::floor32_fast( value * 256.f ); +#else + AlphaRef = u32_to_fixPoint ( core::floor32_fast( value * 256.f ) ); +#endif +} + +/*! +*/ +void CTRTextureGouraudAlpha2::scanline_bilinear () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC[MATERIAL_MAX_COLORS]; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC[0] = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0] * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + f32 inversew = FIX_POINT_F32_MUL; + +#ifdef BURNINGVIDEO_RENDERER_FAST + u32 dIndex = ( line.y & 3 ) << 2; + +#else + tFixPoint a0; + tFixPoint r0, g0, b0; +#endif + +#ifdef IPOL_C0 + tFixPoint r1, g1, b1; + tFixPoint r2, g2, b2; +#endif + + for ( s32 i = 0; i <= dx; ++i ) + { +#ifdef CMP_Z + if ( line.z[0] < z[i] ) +#endif +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + + { + +#ifdef BURNINGVIDEO_RENDERER_FAST + + const tFixPointu d = dithermask [ dIndex | ( i ) & 3 ]; + +#ifdef INVERSE_W + inversew = fix_inverse32 ( line.w[0] ); +#endif + + u32 argb = getTexel_plain ( &IT[0], d + tofix ( line.t[0][0].x,inversew), + d + tofix ( line.t[0][0].y,inversew) + ); + + const u32 alpha = ( argb >> 24 ); + if ( alpha > AlphaRef ) + { +#ifdef WRITE_Z + z[i] = line.z[0]; +#endif +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + + dst[i] = PixelBlend32 ( dst[i], argb, alpha ); + } + + +#else + +#ifdef INVERSE_W + inversew = fix_inverse32 ( line.w[0] ); + getSample_texture ( a0,r0,g0,b0, + &IT[0], + tofix ( line.t[0][0].x,inversew), + tofix ( line.t[0][0].y,inversew) + ); +#else + getSample_texture ( a0,r0,g0,b0, + &IT[0], + tofix ( line.t[0][0].x), + tofix ( line.t[0][0].y) + ); +#endif + if ( (tFixPointu) a0 > AlphaRef ) + { +#ifdef WRITE_Z + z[i] = line.z[0]; +#endif +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef INVERSE_W + getSample_color ( r2, g2, b2, line.c[0][0], inversew ); +#else + getSample_color ( r2, g2, b2, line.c[0][0] ); +#endif + r0 = imulFix ( r0, r2 ); + g0 = imulFix ( g0, g2 ); + b0 = imulFix ( b0, b2 ); + + color_to_fix ( r1, g1, b1, dst[i] ); + + a0 >>= 8; + + r2 = r1 + imulFix ( a0, r0 - r1 ); + g2 = g1 + imulFix ( a0, g0 - g1 ); + b2 = b1 + imulFix ( a0, b0 - b1 ); + dst[i] = fix4_to_color ( a0, r2, g2, b2 ); + +/* + dst[i] = PixelBlend32 ( dst[i], + fix_to_color ( r0,g0, b0 ), + fixPointu_to_u32 ( a0 ) + ); +*/ +/* + getSample_color ( r2, g2, b2, line.c[0][0], inversew * COLOR_MAX ); + color_to_fix ( r1, g1, b1, dst[i] ); + + r2 = r0 + imulFix ( a0, r1 - r0 ); + g2 = g0 + imulFix ( a0, g1 - g0 ); + b2 = b0 + imulFix ( a0, b1 - b0 ); + dst[i] = fix_to_color ( r2, g2, b2 ); +*/ + + } +#endif + + } + +#ifdef IPOL_Z + line.z[0] += slopeZ; +#endif +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1]; +#endif + } + +} + +void CTRTextureGouraudAlpha2::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) ) + return; + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0][0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + // rasterize upper sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[1] ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[0][1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear ( ); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + // rasterize lower sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[2] ) + { + // advance to middle point + if( (f32) 0.0 != scan.invDeltaY[1] ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0][0] = a->Color[0] + scan.slopeC[0][0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[0][1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear ( ); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + + +//! creates a flat triangle renderer +IBurningShader* createTRTextureGouraudAlpha(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRTextureGouraudAlpha2(driver); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + diff --git a/source/Irrlicht/CTRTextureGouraudAlphaNoZ.cpp b/source/Irrlicht/CTRTextureGouraudAlphaNoZ.cpp new file mode 100644 index 00000000..2830247e --- /dev/null +++ b/source/Irrlicht/CTRTextureGouraudAlphaNoZ.cpp @@ -0,0 +1,734 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 + +// define render case +#define SUBTEXEL +#define INVERSE_W + +#define USE_ZBUFFER +#define IPOL_W +#define CMP_W +//#define WRITE_W + +#define IPOL_C0 +#define IPOL_T0 +//#define IPOL_T1 + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #undef IPOL_C0 +#endif + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif + #define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + + + +namespace irr +{ + +namespace video +{ + +class CTRTextureGouraudAlphaNoZ : public IBurningShader +{ +public: + + //! constructor + CTRTextureGouraudAlphaNoZ(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + + virtual void setParam ( u32 index, f32 value) _IRR_OVERRIDE_; + + +private: + void scanline_bilinear (); + + sScanConvertData scan; + sScanLineData line; + + u32 AlphaRef; +}; + +//! constructor +CTRTextureGouraudAlphaNoZ::CTRTextureGouraudAlphaNoZ(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRTextureGouraudAlphaNoZ"); + #endif + + AlphaRef = 0; +} + + +/*! +*/ +void CTRTextureGouraudAlphaNoZ::setParam ( u32 index, f32 value) +{ +#ifdef BURNINGVIDEO_RENDERER_FAST + AlphaRef = core::floor32_fast( value * 256.f ); +#else + AlphaRef = u32_to_fixPoint ( core::floor32_fast( value * 256.f ) ); +#endif +} + +/*! +*/ +void CTRTextureGouraudAlphaNoZ::scanline_bilinear () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC[MATERIAL_MAX_COLORS]; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC[0] = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0] * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + f32 inversew = FIX_POINT_F32_MUL; + +#ifdef BURNINGVIDEO_RENDERER_FAST + u32 dIndex = ( line.y & 3 ) << 2; + +#else + tFixPoint a0; + tFixPoint r0, g0, b0; +#endif + +#ifdef IPOL_C0 + tFixPoint r1, g1, b1; + tFixPoint r2, g2, b2; +#endif + + for ( s32 i = 0; i <= dx; ++i ) + { +#ifdef CMP_Z + if ( line.z[0] < z[i] ) +#endif +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + + { + +#ifdef BURNINGVIDEO_RENDERER_FAST + + const tFixPointu d = dithermask [ dIndex | ( i ) & 3 ]; + +#ifdef INVERSE_W + inversew = fix_inverse32 ( line.w[0] ); +#endif + u32 argb = getTexel_plain ( &IT[0], d + tofix ( line.t[0][0].x,inversew), + d + tofix ( line.t[0][0].y,inversew) + ); + + const u32 alpha = ( argb >> 24 ); + if ( alpha > AlphaRef ) + { +#ifdef WRITE_Z + z[i] = line.z[0]; +#endif +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + + dst[i] = PixelBlend32 ( dst[i], argb, alpha ); + } + + +#else + +#ifdef INVERSE_W + inversew = fix_inverse32 ( line.w[0] ); + getSample_texture ( a0, r0, g0, b0, + &IT[0], + tofix ( line.t[0][0].x,inversew), + tofix ( line.t[0][0].y,inversew) + ); +#else + getSample_texture ( a0, r0, g0,b0, + &IT[0], + tofix ( line.t[0][0].x), + tofix ( line.t[0][0].y) + ); +#endif + if ( (tFixPointu) a0 > AlphaRef ) + { +#ifdef WRITE_Z + z[i] = line.z[0]; +#endif +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef INVERSE_W + getSample_color ( r2, g2, b2, line.c[0][0], inversew ); +#else + getSample_color ( r2, g2, b2, line.c[0][0] ); +#endif + r0 = imulFix ( r0, r2 ); + g0 = imulFix ( g0, g2 ); + b0 = imulFix ( b0, b2 ); + + color_to_fix ( r1, g1, b1, dst[i] ); + + a0 >>= 8; + + r2 = r1 + imulFix ( a0, r0 - r1 ); + g2 = g1 + imulFix ( a0, g0 - g1 ); + b2 = b1 + imulFix ( a0, b0 - b1 ); + dst[i] = fix4_to_color ( a0, r2, g2, b2 ); + +/* + dst[i] = PixelBlend32 ( dst[i], + fix_to_color ( r0,g0, b0 ), + fixPointu_to_u32 ( a0 ) + ); +*/ +/* + getSample_color ( r2, g2, b2, line.c[0][0], inversew * COLOR_MAX ); + color_to_fix ( r1, g1, b1, dst[i] ); + + r2 = r0 + imulFix ( a0, r1 - r0 ); + g2 = g0 + imulFix ( a0, g1 - g0 ); + b2 = b0 + imulFix ( a0, b1 - b0 ); + dst[i] = fix_to_color ( r2, g2, b2 ); +*/ + + } +#endif + + } + +#ifdef IPOL_Z + line.z[0] += slopeZ; +#endif +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC[0]; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1]; +#endif + } + +} + +void CTRTextureGouraudAlphaNoZ::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) ) + return; + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0][0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + // rasterize upper sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[1] ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[0][1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear ( ); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + // rasterize lower sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[2] ) + { + // advance to middle point + if( (f32) 0.0 != scan.invDeltaY[1] ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0][0] = a->Color[0] + scan.slopeC[0][0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[0][1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear ( ); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + + +//! creates a flat triangle renderer +IBurningShader* createTRTextureGouraudAlphaNoZ(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRTextureGouraudAlphaNoZ(driver); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + diff --git a/source/Irrlicht/CTRTextureGouraudNoZ.cpp b/source/Irrlicht/CTRTextureGouraudNoZ.cpp new file mode 100644 index 00000000..f6cd1456 --- /dev/null +++ b/source/Irrlicht/CTRTextureGouraudNoZ.cpp @@ -0,0 +1,364 @@ +// Copyright (C) 2002-2012 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" +#include "CTRTextureGouraud.h" +#include "SColor.h" + +#ifdef _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + +class CTRTextureGouraudNoZ : public CTRTextureGouraud +{ +public: + + CTRTextureGouraudNoZ() + : CTRTextureGouraud(0) + { + #ifdef _DEBUG + setDebugName("CTRGouraudWireNoZ"); + #endif + } + + //! draws an indexed triangle list + virtual void drawIndexedTriangleList(S2DVertex* vertices, s32 vertexCount, const u16* indexList, s32 triangleCount) _IRR_OVERRIDE_ + { + const S2DVertex *v1, *v2, *v3; + + u16 color; + f32 tmpDiv; // temporary division factor + f32 longest; // saves the longest span + s32 height; // saves height of triangle + u16* targetSurface; // target pointer where to plot pixels + s32 spanEnd; // saves end of spans + f32 leftdeltaxf; // amount of pixels to increase on left side of triangle + f32 rightdeltaxf; // amount of pixels to increase on right side of triangle + s32 leftx, rightx; // position where we are + f32 leftxf, rightxf; // same as above, but as f32 values + s32 span; // current span + u16 *hSpanBegin, *hSpanEnd; // pointer used when plotting pixels + s32 leftR, leftG, leftB, rightR, rightG, rightB; // color values + s32 leftStepR, leftStepG, leftStepB, + rightStepR, rightStepG, rightStepB; // color steps + s32 spanR, spanG, spanB, spanStepR, spanStepG, spanStepB; // color interpolating values while drawing a span. + s32 leftTx, rightTx, leftTy, rightTy; // texture interpolating values + s32 leftTxStep, rightTxStep, leftTyStep, rightTyStep; // texture interpolating values + s32 spanTx, spanTy, spanTxStep, spanTyStep; // values of Texturecoords when drawing a span + core::rect TriangleRect; + + lockedSurface = (u16*)RenderTarget->getData(); + lockedTexture = (u16*)Texture->getData(); + + for (s32 i=0; iPos.X - v1->Pos.X) * (v3->Pos.Y - v2->Pos.Y)) - + ((v3->Pos.Y - v1->Pos.Y) * (v3->Pos.X - v2->Pos.X)); + + if (z < 0) + continue; + } + + //near plane clipping + + if (v1->ZValue<0 && v2->ZValue<0 && v3->ZValue<0) + continue; + + // sort for width for inscreen clipping + + if (v1->Pos.X > v2->Pos.X) swapVertices(&v1, &v2); + if (v1->Pos.X > v3->Pos.X) swapVertices(&v1, &v3); + if (v2->Pos.X > v3->Pos.X) swapVertices(&v2, &v3); + + if ((v1->Pos.X - v3->Pos.X) == 0) + continue; + + TriangleRect.UpperLeftCorner.X = v1->Pos.X; + TriangleRect.LowerRightCorner.X = v3->Pos.X; + + // sort for height for faster drawing. + + if (v1->Pos.Y > v2->Pos.Y) swapVertices(&v1, &v2); + if (v1->Pos.Y > v3->Pos.Y) swapVertices(&v1, &v3); + if (v2->Pos.Y > v3->Pos.Y) swapVertices(&v2, &v3); + + TriangleRect.UpperLeftCorner.Y = v1->Pos.Y; + TriangleRect.LowerRightCorner.Y = v3->Pos.Y; + + if (!TriangleRect.isRectCollided(ViewPortRect)) + continue; + + // calculate height of triangle + height = v3->Pos.Y - v1->Pos.Y; + if (!height) + continue; + + // calculate longest span + + longest = (v2->Pos.Y - v1->Pos.Y) / (f32)height * (v3->Pos.X - v1->Pos.X) + (v1->Pos.X - v2->Pos.X); + + spanEnd = v2->Pos.Y; + span = v1->Pos.Y; + leftxf = (f32)v1->Pos.X; + rightxf = (f32)v1->Pos.X; + + leftR = rightR = video::getRed(v1->Color)<<8; + leftG = rightG = video::getGreen(v1->Color)<<8; + leftB = rightB = video::getBlue(v1->Color)<<8; + leftTx = rightTx = v1->TCoords.X; + leftTy = rightTy = v1->TCoords.Y; + + targetSurface = lockedSurface + span * SurfaceWidth; + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + rightdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + rightStepR = (s32)(((s32)(video::getRed(v2->Color)<<8) - rightR) * tmpDiv); + rightStepG = (s32)(((s32)(video::getGreen(v2->Color)<<8) - rightG) * tmpDiv); + rightStepB = (s32)(((s32)(video::getBlue(v2->Color)<<8) - rightB) * tmpDiv); + rightTxStep = (s32)((v2->TCoords.X - rightTx) * tmpDiv); + rightTyStep = (s32)((v2->TCoords.Y - rightTy) * tmpDiv); + + tmpDiv = 1.0f / (f32)height; + leftdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + leftStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - leftR) * tmpDiv); + leftStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - leftG) * tmpDiv); + leftStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - leftB) * tmpDiv); + leftTxStep = (s32)((v3->TCoords.X - leftTx) * tmpDiv); + leftTyStep = (s32)((v3->TCoords.Y - leftTy) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (f32)height; + rightdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + rightStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - rightR) * tmpDiv); + rightStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - rightG) * tmpDiv); + rightStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - rightB) * tmpDiv); + rightTxStep = (s32)((v3->TCoords.X - rightTx) * tmpDiv); + rightTyStep = (s32)((v3->TCoords.Y - rightTy) * tmpDiv); + + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + leftdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + leftStepR = (s32)(((s32)(video::getRed(v2->Color)<<8) - leftR) * tmpDiv); + leftStepG = (s32)(((s32)(video::getGreen(v2->Color)<<8) - leftG) * tmpDiv); + leftStepB = (s32)(((s32)(video::getBlue(v2->Color)<<8) - leftB) * tmpDiv); + leftTxStep = (s32)((v2->TCoords.X - leftTx) * tmpDiv); + leftTyStep = (s32)((v2->TCoords.Y - leftTy) * tmpDiv); + } + + + // do it twice, once for the first half of the triangle, + // end then for the second half. + + for (s32 triangleHalf=0; triangleHalf<2; ++triangleHalf) + { + if (spanEnd > ViewPortRect.LowerRightCorner.Y) + spanEnd = ViewPortRect.LowerRightCorner.Y; + + // if the span <0, than we can skip these spans, + // and proceed to the next spans which are really on the screen. + if (span < ViewPortRect.UpperLeftCorner.Y) + { + // we'll use leftx as temp variable + if (spanEnd < ViewPortRect.UpperLeftCorner.Y) + { + leftx = spanEnd - span; + span = spanEnd; + } + else + { + leftx = ViewPortRect.UpperLeftCorner.Y - span; + span = ViewPortRect.UpperLeftCorner.Y; + } + + leftxf += leftdeltaxf*leftx; + rightxf += rightdeltaxf*leftx; + targetSurface += SurfaceWidth*leftx; + + leftR += leftStepR*leftx; + leftG += leftStepG*leftx; + leftB += leftStepB*leftx; + rightR += rightStepR*leftx; + rightG += rightStepG*leftx; + rightB += rightStepB*leftx; + + leftTx += leftTxStep*leftx; + leftTy += leftTyStep*leftx; + rightTx += rightTxStep*leftx; + rightTy += rightTyStep*leftx; + } + + + // the main loop. Go through every span and draw it. + + while (span < spanEnd) + { + leftx = (s32)(leftxf); + rightx = (s32)(rightxf + 0.5f); + + // perform some clipping + // thanks to a correction by hybrid + // calculations delayed to correctly propagate to textures etc. + s32 tDiffLeft=0, tDiffRight=0; + if (leftxViewPortRect.LowerRightCorner.X) + tDiffLeft=ViewPortRect.LowerRightCorner.X-leftx; + + if (rightxViewPortRect.LowerRightCorner.X) + tDiffRight=ViewPortRect.LowerRightCorner.X-rightx; + + // draw the span + if (rightx + tDiffRight - leftx - tDiffLeft) + { + tmpDiv = 1.0f / (f32)(rightx - leftx); + + spanStepR = (s32)((rightR - leftR) * tmpDiv); + spanR = leftR+tDiffLeft*spanStepR; + spanStepG = (s32)((rightG - leftG) * tmpDiv); + spanG = leftG+tDiffLeft*spanStepG; + spanStepB = (s32)((rightB - leftB) * tmpDiv); + spanB = leftB+tDiffLeft*spanStepB; + + spanTxStep = (s32)((rightTx - leftTx) * tmpDiv); + spanTx = leftTx + tDiffLeft*spanTxStep; + spanTyStep = (s32)((rightTy - leftTy) * tmpDiv); + spanTy = leftTy+tDiffLeft*spanTyStep; + + hSpanBegin = targetSurface + leftx+tDiffLeft; + hSpanEnd = targetSurface + rightx+tDiffRight; + + while (hSpanBegin < hSpanEnd) + { + color = lockedTexture[((spanTy>>8)&textureYMask) * lockedTextureWidth + ((spanTx>>8)&textureXMask)]; + *hSpanBegin = video::RGB16(video::getRed(color) * (spanR>>8) >>2, + video::getGreen(color) * (spanG>>8) >>2, + video::getBlue(color) * (spanB>>8) >>2); + + spanR += spanStepR; + spanG += spanStepG; + spanB += spanStepB; + + spanTx += spanTxStep; + spanTy += spanTyStep; + + ++hSpanBegin; + } + } + + leftxf += leftdeltaxf; + rightxf += rightdeltaxf; + ++span; + targetSurface += SurfaceWidth; + + leftR += leftStepR; + leftG += leftStepG; + leftB += leftStepB; + rightR += rightStepR; + rightG += rightStepG; + rightB += rightStepB; + + leftTx += leftTxStep; + leftTy += leftTyStep; + rightTx += rightTxStep; + rightTy += rightTyStep; + } + + if (triangleHalf>0) // break, we've gout only two halves + break; + + + // setup variables for second half of the triangle. + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + rightdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + rightxf = (f32)v2->Pos.X; + + rightR = video::getRed(v2->Color)<<8; + rightG = video::getGreen(v2->Color)<<8; + rightB = video::getBlue(v2->Color)<<8; + rightStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - rightR) * tmpDiv); + rightStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - rightG) * tmpDiv); + rightStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - rightB) * tmpDiv); + + rightTx = v2->TCoords.X; + rightTy = v2->TCoords.Y; + rightTxStep = (s32)((v3->TCoords.X - rightTx) * tmpDiv); + rightTyStep = (s32)((v3->TCoords.Y - rightTy) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + leftdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + leftxf = (f32)v2->Pos.X; + + leftR = video::getRed(v2->Color)<<8; + leftG = video::getGreen(v2->Color)<<8; + leftB = video::getBlue(v2->Color)<<8; + leftStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - leftR) * tmpDiv); + leftStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - leftG) * tmpDiv); + leftStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - leftB) * tmpDiv); + + leftTx = v2->TCoords.X; + leftTy = v2->TCoords.Y; + leftTxStep = (s32)((v3->TCoords.X - leftTx) * tmpDiv); + leftTyStep = (s32)((v3->TCoords.Y - leftTy) * tmpDiv); + } + + + spanEnd = v3->Pos.Y; + } + + } + } + +}; + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + +//! creates a flat triangle renderer +ITriangleRenderer* createTriangleRendererTextureGouraudNoZ() +{ + #ifdef _IRR_COMPILE_WITH_SOFTWARE_ + return new CTRTextureGouraudNoZ(); + #else + return 0; + #endif // _IRR_COMPILE_WITH_SOFTWARE_ +} + +} // end namespace video +} // end namespace irr + + diff --git a/source/Irrlicht/CTRTextureGouraudNoZ2.cpp b/source/Irrlicht/CTRTextureGouraudNoZ2.cpp new file mode 100644 index 00000000..6abc6e11 --- /dev/null +++ b/source/Irrlicht/CTRTextureGouraudNoZ2.cpp @@ -0,0 +1,641 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 + +// define render case +#ifdef BURNINGVIDEO_RENDERER_FAST + #define SUBTEXEL + #define INVERSE_W +#else + #define SUBTEXEL + #define INVERSE_W +#endif + +//#define USE_ZBUFFER +#define IPOL_W +//#define CMP_W +//#define WRITE_W + +//#define IPOL_C0 +#define IPOL_T0 +//#define IPOL_T1 + +#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #undef IPOL_C0 +#endif + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + + +namespace irr +{ + +namespace video +{ + +class CTRTextureGouraudNoZ2 : public IBurningShader +{ +public: + + //! constructor + CTRTextureGouraudNoZ2(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + + +private: + void scanline_bilinear (); + sScanConvertData scan; + sScanLineData line; + +}; + +//! constructor +CTRTextureGouraudNoZ2::CTRTextureGouraudNoZ2(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRTextureGouraudNoZ2"); + #endif +} + + + +/*! +*/ +void CTRTextureGouraudNoZ2::scanline_bilinear ( ) +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC = (line.c[1] - line.c[0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0] += slopeC * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + f32 inversew = FIX_POINT_F32_MUL; + + tFixPoint tx0; + tFixPoint ty0; + + + for ( s32 i = 0; i <= dx; ++i ) + { +#ifdef CMP_Z + if ( line.z[0] < z[i] ) +#endif +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + + { +#ifdef INVERSE_W + inversew = fix_inverse32 ( line.w[0] ); +#endif + tx0 = tofix ( line.t[0][0].x,inversew); + ty0 = tofix ( line.t[0][0].y,inversew); + dst[i] = getTexel_plain ( &IT[0], tx0, ty0 ); + +/* + getSample_texture ( r0, g0, b0, &IT[0], tx0, ty0 ); + dst[i] = fix_to_color ( r0, g0, b0 ); +*/ +#ifdef WRITE_Z + z[i] = line.z[0]; +#endif +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + } + +#ifdef IPOL_Z + line.z[0] += slopeZ; +#endif +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_C0 + line.c[0] += slopeC; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1]; +#endif + } + +} + +void CTRTextureGouraudNoZ2::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) ) + return; + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + // rasterize upper sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[1] ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0] * subPixel; + scan.c[1] += scan.slopeC[1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[scan.left] = scan.c[0]; + line.c[scan.right] = scan.c[1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear ( ); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0]; + scan.c[1] += scan.slopeC[1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + // rasterize lower sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[2] ) + { + // advance to middle point + if( (f32) 0.0 != scan.invDeltaY[1] ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0] = a->Color[0] + scan.slopeC[0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0] * subPixel; + scan.c[1] += scan.slopeC[1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[scan.left] = scan.c[0]; + line.c[scan.right] = scan.c[1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0]; + scan.c[1] += scan.slopeC[1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + +//! creates a flat triangle renderer +IBurningShader* createTRTextureGouraudNoZ2(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRTextureGouraudNoZ2( driver ); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + + diff --git a/source/Irrlicht/CTRTextureGouraudVertexAlpha2.cpp b/source/Irrlicht/CTRTextureGouraudVertexAlpha2.cpp new file mode 100644 index 00000000..8da8e872 --- /dev/null +++ b/source/Irrlicht/CTRTextureGouraudVertexAlpha2.cpp @@ -0,0 +1,677 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 + +// define render case +#define SUBTEXEL +#define INVERSE_W + +#define USE_ZBUFFER +#define IPOL_W +#define CMP_W +//#define WRITE_W + +#define IPOL_C0 +#define IPOL_T0 +//#define IPOL_T1 + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #undef IPOL_C0 +#endif + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif + #define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + +namespace irr +{ + +namespace video +{ + +class CTRTextureVertexAlpha2 : public IBurningShader +{ +public: + + //! constructor + CTRTextureVertexAlpha2(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + + +private: + void scanline_bilinear (); + sScanConvertData scan; + sScanLineData line; + +}; + +//! constructor +CTRTextureVertexAlpha2::CTRTextureVertexAlpha2(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRTextureVertexAlpha2"); + #endif +} + + + +/*! +*/ +void CTRTextureVertexAlpha2::scanline_bilinear ( ) +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + f32 inversew = FIX_POINT_F32_MUL; + +//#define __TEST_THIS + +#ifdef __TEST_THIS + +#else + tFixPoint tx0; + tFixPoint ty0; + + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; + tFixPoint r2, g2, b2; +#endif + + +#ifdef IPOL_C0 + tFixPoint a3; +#endif + + + for ( s32 i = 0; i <= dx; ++i ) + { +#ifdef CMP_Z + if ( line.z[0] < z[i] ) +#endif +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + + { +#ifdef __TEST_THIS + + inversew = fix_inverse32 ( line.w[0] ); + + dst[i] = PixelAdd32 ( + dst[i], + getTexel_plain ( &IT[0], tofix ( line.t[0][0].x,inversew), + tofix ( line.t[0][0].y,inversew) ) + ); + +#else + +#ifdef INVERSE_W + inversew = fix_inverse32 ( line.w[0] ); +#endif + tx0 = tofix ( line.t[0][0].x,inversew); + ty0 = tofix ( line.t[0][0].y,inversew); + +#ifdef IPOL_C0 + a3 = tofix ( line.c[0][0].y,inversew ); +#endif + + getSample_texture ( r0, g0, b0, &IT[0], tx0, ty0 ); + color_to_fix ( r1, g1, b1, dst[i] ); + +#ifdef IPOL_C0 + r2 = clampfix_maxcolor ( r1 + imulFix ( r0, a3 ) ); + g2 = clampfix_maxcolor ( g1 + imulFix ( g0, a3 ) ); + b2 = clampfix_maxcolor ( b1 + imulFix ( b0, a3 ) ); +#else + r2 = clampfix_maxcolor ( r1 + r0 ); + g2 = clampfix_maxcolor ( g1 + g0 ); + b2 = clampfix_maxcolor ( b1 + b0 ); +#endif + + dst[i] = fix_to_color ( r2, g2, b2 ); + +#ifdef WRITE_Z + z[i] = line.z[0]; +#endif +#ifdef WRITE_W + z[i] = line.w[0]; +#endif +#endif + } + +#ifdef IPOL_Z + line.z[0] += slopeZ; +#endif +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1]; +#endif + } + +} + +void CTRTextureVertexAlpha2::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) ) + return; + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0][0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + // rasterize upper sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[1] ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[0][1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + // rasterize lower sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[2] ) + { + // advance to middle point + if( (f32) 0.0 != scan.invDeltaY[1] ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0][0] = a->Color[0] + scan.slopeC[0][0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[0][1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + +//! creates a flat triangle renderer +IBurningShader* createTriangleRendererTextureVertexAlpha2(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRTextureVertexAlpha2(driver); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + + diff --git a/source/Irrlicht/CTRTextureGouraudWire.cpp b/source/Irrlicht/CTRTextureGouraudWire.cpp new file mode 100644 index 00000000..369b91ac --- /dev/null +++ b/source/Irrlicht/CTRTextureGouraudWire.cpp @@ -0,0 +1,362 @@ +// Copyright (C) 2002-2012 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" +#include "CTRTextureGouraud.h" + +#ifdef _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + +class CTRTextureGouraudWire : public CTRTextureGouraud +{ +public: + + CTRTextureGouraudWire(IZBuffer* zbuffer) + : CTRTextureGouraud(zbuffer) + { + #ifdef _DEBUG + setDebugName("CTRGouraudWire"); + #endif + } + + //! draws an indexed triangle list + virtual void drawIndexedTriangleList(S2DVertex* vertices, s32 vertexCount, const u16* indexList, s32 triangleCount) _IRR_OVERRIDE_ + { + const S2DVertex *v1, *v2, *v3; + + u16 color; + f32 tmpDiv; // temporary division factor + f32 longest; // saves the longest span + s32 height; // saves height of triangle + u16* targetSurface; // target pointer where to plot pixels + s32 spanEnd; // saves end of spans + f32 leftdeltaxf; // amount of pixels to increase on left side of triangle + f32 rightdeltaxf; // amount of pixels to increase on right side of triangle + s32 leftx, rightx; // position where we are + f32 leftxf, rightxf; // same as above, but as f32 values + s32 span; // current span + s32 leftR, leftG, leftB, rightR, rightG, rightB; // color values + s32 leftStepR, leftStepG, leftStepB, + rightStepR, rightStepG, rightStepB; // color steps + s32 leftTx, rightTx, leftTy, rightTy; // texture interpolating values + s32 leftTxStep, rightTxStep, leftTyStep, rightTyStep; // texture interpolating values + core::rect TriangleRect; + + s32 leftZValue, rightZValue; + s32 leftZStep, rightZStep; + TZBufferType* zTarget;//, *spanZTarget; // target of ZBuffer; + + lockedSurface = (u16*)RenderTarget->getData(); + lockedZBuffer = ZBuffer->lock(); + lockedTexture = (u16*)Texture->getData(); + + for (s32 i=0; iPos.X - v1->Pos.X) * (v3->Pos.Y - v2->Pos.Y)) - + ((v3->Pos.Y - v1->Pos.Y) * (v3->Pos.X - v2->Pos.X)); + + if (z < 0) + continue; + } + + //near plane clipping + + if (v1->ZValue<0 && v2->ZValue<0 && v3->ZValue<0) + continue; + + // sort for width for inscreen clipping + + if (v1->Pos.X > v2->Pos.X) swapVertices(&v1, &v2); + if (v1->Pos.X > v3->Pos.X) swapVertices(&v1, &v3); + if (v2->Pos.X > v3->Pos.X) swapVertices(&v2, &v3); + + if ((v1->Pos.X - v3->Pos.X) == 0) + continue; + + TriangleRect.UpperLeftCorner.X = v1->Pos.X; + TriangleRect.LowerRightCorner.X = v3->Pos.X; + + // sort for height for faster drawing. + + if (v1->Pos.Y > v2->Pos.Y) swapVertices(&v1, &v2); + if (v1->Pos.Y > v3->Pos.Y) swapVertices(&v1, &v3); + if (v2->Pos.Y > v3->Pos.Y) swapVertices(&v2, &v3); + + TriangleRect.UpperLeftCorner.Y = v1->Pos.Y; + TriangleRect.LowerRightCorner.Y = v3->Pos.Y; + + if (!TriangleRect.isRectCollided(ViewPortRect)) + continue; + + // calculate height of triangle + height = v3->Pos.Y - v1->Pos.Y; + if (!height) + continue; + + // calculate longest span + + longest = (v2->Pos.Y - v1->Pos.Y) / (f32)height * (v3->Pos.X - v1->Pos.X) + (v1->Pos.X - v2->Pos.X); + + spanEnd = v2->Pos.Y; + span = v1->Pos.Y; + leftxf = (f32)v1->Pos.X; + rightxf = (f32)v1->Pos.X; + + leftZValue = v1->ZValue; + rightZValue = v1->ZValue; + + leftR = rightR = video::getRed(v1->Color)<<8; + leftG = rightG = video::getGreen(v1->Color)<<8; + leftB = rightB = video::getBlue(v1->Color)<<8; + leftTx = rightTx = v1->TCoords.X; + leftTy = rightTy = v1->TCoords.Y; + + targetSurface = lockedSurface + span * SurfaceWidth; + zTarget = lockedZBuffer + span * SurfaceWidth; + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + rightdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + rightZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); + rightStepR = (s32)(((s32)(video::getRed(v2->Color)<<8) - rightR) * tmpDiv); + rightStepG = (s32)(((s32)(video::getGreen(v2->Color)<<8) - rightG) * tmpDiv); + rightStepB = (s32)(((s32)(video::getBlue(v2->Color)<<8) - rightB) * tmpDiv); + rightTxStep = (s32)((v2->TCoords.X - rightTx) * tmpDiv); + rightTyStep = (s32)((v2->TCoords.Y - rightTy) * tmpDiv); + + tmpDiv = 1.0f / (f32)height; + leftdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + leftZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); + leftStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - leftR) * tmpDiv); + leftStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - leftG) * tmpDiv); + leftStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - leftB) * tmpDiv); + leftTxStep = (s32)((v3->TCoords.X - leftTx) * tmpDiv); + leftTyStep = (s32)((v3->TCoords.Y - leftTy) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (f32)height; + rightdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv; + rightZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv); + rightStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - rightR) * tmpDiv); + rightStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - rightG) * tmpDiv); + rightStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - rightB) * tmpDiv); + rightTxStep = (s32)((v3->TCoords.X - rightTx) * tmpDiv); + rightTyStep = (s32)((v3->TCoords.Y - rightTy) * tmpDiv); + + tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y); + leftdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv; + leftZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv); + leftStepR = (s32)(((s32)(video::getRed(v2->Color)<<8) - leftR) * tmpDiv); + leftStepG = (s32)(((s32)(video::getGreen(v2->Color)<<8) - leftG) * tmpDiv); + leftStepB = (s32)(((s32)(video::getBlue(v2->Color)<<8) - leftB) * tmpDiv); + leftTxStep = (s32)((v2->TCoords.X - leftTx) * tmpDiv); + leftTyStep = (s32)((v2->TCoords.Y - leftTy) * tmpDiv); + } + + + // do it twice, once for the first half of the triangle, + // end then for the second half. + + for (s32 triangleHalf=0; triangleHalf<2; ++triangleHalf) + { + if (spanEnd > ViewPortRect.LowerRightCorner.Y) + spanEnd = ViewPortRect.LowerRightCorner.Y; + + // if the span <0, than we can skip these spans, + // and proceed to the next spans which are really on the screen. + if (span < ViewPortRect.UpperLeftCorner.Y) + { + // we'll use leftx as temp variable + if (spanEnd < ViewPortRect.UpperLeftCorner.Y) + { + leftx = spanEnd - span; + span = spanEnd; + } + else + { + leftx = ViewPortRect.UpperLeftCorner.Y - span; + span = ViewPortRect.UpperLeftCorner.Y; + } + + leftxf += leftdeltaxf*leftx; + rightxf += rightdeltaxf*leftx; + targetSurface += SurfaceWidth*leftx; + zTarget += SurfaceWidth*leftx; + leftZValue += leftZStep*leftx; + rightZValue += rightZStep*leftx; + + leftR += leftStepR*leftx; + leftG += leftStepG*leftx; + leftB += leftStepB*leftx; + rightR += rightStepR*leftx; + rightG += rightStepG*leftx; + rightB += rightStepB*leftx; + + leftTx += leftTxStep*leftx; + leftTy += leftTyStep*leftx; + rightTx += rightTxStep*leftx; + rightTy += rightTyStep*leftx; + } + + + // the main loop. Go through every span and draw it. + + while (span < spanEnd) + { + leftx = (s32)(leftxf); + rightx = (s32)(rightxf + 0.5f); + + // perform some clipping + + if (leftx>=ViewPortRect.UpperLeftCorner.X && + leftx<=ViewPortRect.LowerRightCorner.X) + { + if (leftZValue > *(zTarget + leftx)) + { + *(zTarget + leftx) = leftZValue; + color = lockedTexture[((leftTy>>8)&textureYMask) * lockedTextureWidth + ((leftTx>>8)&textureXMask)]; + *(targetSurface + leftx) = video::RGB16(video::getRed(color) * (leftR>>8) >>2, + video::getGreen(color) * (leftG>>8) >>2, + video::getBlue(color) * (leftR>>8) >>2); + } + } + + + if (rightx>=ViewPortRect.UpperLeftCorner.X && + rightx<=ViewPortRect.LowerRightCorner.X) + { + if (rightZValue > *(zTarget + rightx)) + { + *(zTarget + rightx) = rightZValue; + color = lockedTexture[((rightTy>>8)&textureYMask) * lockedTextureWidth + ((rightTx>>8)&textureXMask)]; + *(targetSurface + rightx) = video::RGB16(video::getRed(color) * (rightR>>8) >>2, + video::getGreen(color) * (rightG>>8) >>2, + video::getBlue(color) * (rightR>>8) >>2); + } + + } + + leftxf += leftdeltaxf; + rightxf += rightdeltaxf; + ++span; + targetSurface += SurfaceWidth; + zTarget += SurfaceWidth; + leftZValue += leftZStep; + rightZValue += rightZStep; + + leftR += leftStepR; + leftG += leftStepG; + leftB += leftStepB; + rightR += rightStepR; + rightG += rightStepG; + rightB += rightStepB; + + leftTx += leftTxStep; + leftTy += leftTyStep; + rightTx += rightTxStep; + rightTy += rightTyStep; + } + + if (triangleHalf>0) // break, we've gout only two halves + break; + + + // setup variables for second half of the triangle. + + if (longest < 0.0f) + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + rightdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + rightxf = (f32)v2->Pos.X; + + rightZValue = v2->ZValue; + rightZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); + + rightR = video::getRed(v2->Color)<<8; + rightG = video::getGreen(v2->Color)<<8; + rightB = video::getBlue(v2->Color)<<8; + rightStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - rightR) * tmpDiv); + rightStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - rightG) * tmpDiv); + rightStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - rightB) * tmpDiv); + + rightTx = v2->TCoords.X; + rightTy = v2->TCoords.Y; + rightTxStep = (s32)((v3->TCoords.X - rightTx) * tmpDiv); + rightTyStep = (s32)((v3->TCoords.Y - rightTy) * tmpDiv); + } + else + { + tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y); + + leftdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv; + leftxf = (f32)v2->Pos.X; + + leftZValue = v2->ZValue; + leftZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv); + + leftR = video::getRed(v2->Color)<<8; + leftG = video::getGreen(v2->Color)<<8; + leftB = video::getBlue(v2->Color)<<8; + leftStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - leftR) * tmpDiv); + leftStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - leftG) * tmpDiv); + leftStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - leftB) * tmpDiv); + + leftTx = v2->TCoords.X; + leftTy = v2->TCoords.Y; + leftTxStep = (s32)((v3->TCoords.X - leftTx) * tmpDiv); + leftTyStep = (s32)((v3->TCoords.Y - leftTy) * tmpDiv); + } + + + spanEnd = v3->Pos.Y; + } + + } + + ZBuffer->unlock(); + } +}; + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + +//! creates a flat triangle renderer +ITriangleRenderer* createTriangleRendererTextureGouraudWire(IZBuffer* zbuffer) +{ + #ifdef _IRR_COMPILE_WITH_SOFTWARE_ + return new CTRTextureGouraudWire(zbuffer); + #else + return 0; + #endif // _IRR_COMPILE_WITH_SOFTWARE_ +} + +} // end namespace video +} // end namespace irr + diff --git a/source/Irrlicht/CTRTextureLightMap2_Add.cpp b/source/Irrlicht/CTRTextureLightMap2_Add.cpp new file mode 100644 index 00000000..db49d530 --- /dev/null +++ b/source/Irrlicht/CTRTextureLightMap2_Add.cpp @@ -0,0 +1,659 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 + +// define render case +#define SUBTEXEL +#define INVERSE_W + +#define USE_ZBUFFER +#define IPOL_W +#define CMP_W +#define WRITE_W + +//#define IPOL_C0 +#define IPOL_T0 +#define IPOL_T1 + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #undef IPOL_C0 +#endif + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif + #define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + +namespace irr +{ + +namespace video +{ + +class CTRTextureLightMap2_Add : public IBurningShader +{ +public: + + //! constructor + CTRTextureLightMap2_Add(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + + +private: + void scanline_bilinear (); + + sScanConvertData scan; + sScanLineData line; + +}; + +//! constructor +CTRTextureLightMap2_Add::CTRTextureLightMap2_Add(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRTextureLightMap2_Add"); + #endif +} + + + +/*! +*/ +REALINLINE void CTRTextureLightMap2_Add::scanline_bilinear () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC = (line.c[1] - line.c[0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0] += slopeC * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + +#ifdef BURNINGVIDEO_RENDERER_FAST + f32 inversew = FIX_POINT_F32_MUL; + u32 dIndex = ( line.y & 3 ) << 2; + + +#else + // + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; +#endif + + + for ( s32 i = 0; i <= dx; i++ ) + { +#ifdef CMP_Z + if ( line.z[0] < z[i] ) +#endif +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + { + +#ifdef WRITE_Z + z[i] = line.z[0]; +#endif +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + +#ifdef BURNINGVIDEO_RENDERER_FAST + +#ifdef INVERSE_W + inversew = fix_inverse32 ( line.w[0] ); +#endif + const tFixPointu d = dithermask [ dIndex | ( i ) & 3 ]; + + dst[i] = PixelAdd32 ( + getTexel_plain ( &IT[0], d + tofix ( line.t[0][0].x,inversew), + d + tofix ( line.t[0][0].y,inversew) ), + getTexel_plain ( &IT[1], d + tofix ( line.t[1][0].x,inversew), + d + tofix ( line.t[1][0].y,inversew) ) + ); + +#else + const f32 inversew = fix_inverse32 ( line.w[0] ); + + getSample_texture ( r0, g0, b0, &IT[0], tofix ( line.t[0][0].x,inversew), tofix ( line.t[0][0].y,inversew) ); + getSample_texture ( r1, g1, b1, &IT[1], tofix ( line.t[0][1].x,inversew), tofix ( line.t[0][1].y,inversew) ); + + dst[i] = fix_to_color ( clampfix_maxcolor ( r0 + r1 ), + clampfix_maxcolor ( g0 + g1 ), + clampfix_maxcolor ( b0 + b1 ) + ); +#endif + + } + +#ifdef IPOL_Z + line.z[0] += slopeZ; +#endif +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_C0 + line.c[0] += slopeC; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1]; +#endif + } + +} + +void CTRTextureLightMap2_Add::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) ) + return; + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + // rasterize upper sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[1] ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0] * subPixel; + scan.c[1] += scan.slopeC[1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[scan.left] = scan.c[0]; + line.c[scan.right] = scan.c[1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0]; + scan.c[1] += scan.slopeC[1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + // rasterize lower sub-triangle + if ( (f32) 0.0 != scan.invDeltaY[2] ) + { + // advance to middle point + if( (f32) 0.0 != scan.invDeltaY[1] ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0] = a->Color[0] + scan.slopeC[0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0] * subPixel; + scan.c[1] += scan.slopeC[1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[scan.left] = scan.c[0]; + line.c[scan.right] = scan.c[1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0]; + scan.c[1] += scan.slopeC[1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + +//! creates a flat triangle renderer +IBurningShader* createTriangleRendererTextureLightMap2_Add(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRTextureLightMap2_Add(driver); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + + diff --git a/source/Irrlicht/CTRTextureLightMap2_M1.cpp b/source/Irrlicht/CTRTextureLightMap2_M1.cpp new file mode 100644 index 00000000..71952749 --- /dev/null +++ b/source/Irrlicht/CTRTextureLightMap2_M1.cpp @@ -0,0 +1,641 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 + +// define render case +#define SUBTEXEL +#define INVERSE_W + +#define USE_ZBUFFER +#define IPOL_W +#define CMP_W +#define WRITE_W + +//#define IPOL_C0 +#define IPOL_T0 +#define IPOL_T1 + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #undef IPOL_C0 +#endif + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif + #define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + +namespace irr +{ + +namespace video +{ + +class CTRTextureLightMap2_M1 : public IBurningShader +{ +public: + + //! constructor + CTRTextureLightMap2_M1(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + + +private: + void scanline_bilinear2 (); + + sScanLineData line; + +}; + +//! constructor +CTRTextureLightMap2_M1::CTRTextureLightMap2_M1(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRTextureLightMap2_M1"); + #endif +} + +/*! +*/ +REALINLINE void CTRTextureLightMap2_M1::scanline_bilinear2 () +{ + tVideoSample *dst; + fp24 *z; + + s32 xStart; + s32 xEnd; + s32 dx; + s32 i; + + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + + // search z-buffer for first not occulled pixel + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + + // subTexel + const f32 subPixel = ( (f32) xStart ) - line.x[0]; + +#ifdef IPOL_W + const f32 b = (line.w[1] - line.w[0]) * invDeltaX; + f32 a = line.w[0] + ( b * subPixel ); + + i = 0; + + while ( a <= z[i] ) + { + a += b; + + i += 1; + if ( i > dx ) + return; + } + + // lazy setup rest of scanline + + line.w[0] = a; + line.w[1] = b; +#else + const f32 b = (line.z[1] - line.z[0]) * invDeltaX; + f32 a = line.z[0] + ( b * subPixel ); + + i = 0; + + while ( a > z[i] ) + { + a += b; + + i += 1; + if ( i > dx ) + return; + } + + // lazy setup rest of scanline + + line.z[0] = a; + line.z[1] = b; +#endif + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + + a = (f32) i + subPixel; + + line.t[0][1] = (line.t[0][1] - line.t[0][0]) * invDeltaX; + line.t[1][1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; + + line.t[0][0] += line.t[0][1] * a; + line.t[1][0] += line.t[1][1] * a; + + +#ifdef BURNINGVIDEO_RENDERER_FAST + u32 dIndex = ( line.y & 3 ) << 2; + + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; + +#else + // + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; +#endif + + + for ( ;i <= dx; i++ ) + { +#ifdef IPOL_W + if ( line.w[0] >= z[i] ) + { + z[i] = line.w[0]; +#else + if ( line.z[0] < z[i] ) + { + z[i] = line.z[0]; +#endif + +#ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + f32 inversew = fix_inverse32 ( line.w[0] ); +#else + f32 inversew = FIX_POINT_F32_MUL; +#endif + + + +#ifdef BURNINGVIDEO_RENDERER_FAST + + const tFixPointu d = dithermask [ dIndex | ( i ) & 3 ]; + + getSample_texture ( r0, g0, b0, &IT[0], d + tofix ( line.t[0][0].x,inversew), d + tofix ( line.t[0][0].y,inversew) ); + getSample_texture ( r1, g1, b1, &IT[1], d + tofix ( line.t[1][0].x,inversew), d + tofix ( line.t[1][0].y,inversew) ); +#else + getSample_texture ( r0, g0, b0, &IT[0], tofix ( line.t[0][0].x,inversew), tofix ( line.t[0][0].y,inversew) ); + getSample_texture ( r1, g1, b1, &IT[1], tofix ( line.t[1][0].x,inversew), tofix ( line.t[1][0].y,inversew) ); + +#endif + + dst[i] = fix_to_color ( imulFix_tex1 ( r0, r1 ), + imulFix_tex1 ( g0, g1 ), + imulFix_tex1 ( b0, b1 ) + ); + } + +#ifdef IPOL_W + line.w[0] += line.w[1]; +#else + line.z[0] += line.z[1]; +#endif + line.t[0][0] += line.t[0][1]; + line.t[1][0] += line.t[1][1]; + } + +} + + +void CTRTextureLightMap2_M1::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + sScanConvertData scan; + + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) ) + return; + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + // rasterize upper sub-triangle + if ( F32_GREATER_0 ( scan.invDeltaY[1] ) ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0] * subPixel; + scan.c[1] += scan.slopeC[1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[scan.left] = scan.c[0]; + line.c[scan.right] = scan.c[1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear2 (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0]; + scan.c[1] += scan.slopeC[1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + // rasterize lower sub-triangle + //if ( (f32) 0.0 != scan.invDeltaY[2] ) + if ( F32_GREATER_0 ( scan.invDeltaY[2] ) ) + { + // advance to middle point + if ( F32_GREATER_0 ( scan.invDeltaY[1] ) ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0] = a->Color[0] + scan.slopeC[0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0] * subPixel; + scan.c[1] += scan.slopeC[1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[scan.left] = scan.c[0]; + line.c[scan.right] = scan.c[1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear2 (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0]; + scan.c[1] += scan.slopeC[1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + + + +//! creates a flat triangle renderer +IBurningShader* createTriangleRendererTextureLightMap2_M1(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRTextureLightMap2_M1(driver); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + + diff --git a/source/Irrlicht/CTRTextureLightMap2_M2.cpp b/source/Irrlicht/CTRTextureLightMap2_M2.cpp new file mode 100644 index 00000000..f748990b --- /dev/null +++ b/source/Irrlicht/CTRTextureLightMap2_M2.cpp @@ -0,0 +1,641 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 + +// define render case +#define SUBTEXEL +#define INVERSE_W + +#define USE_ZBUFFER +#define IPOL_W +#define CMP_W +#define WRITE_W + +//#define IPOL_C0 +#define IPOL_T0 +#define IPOL_T1 + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #undef IPOL_C0 +#endif + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif + #define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + +namespace irr +{ + +namespace video +{ + +class CTRTextureLightMap2_M2 : public IBurningShader +{ +public: + + //! constructor + CTRTextureLightMap2_M2(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + + +private: + void scanline_bilinear2 (); + + sScanLineData line; + +}; + +//! constructor +CTRTextureLightMap2_M2::CTRTextureLightMap2_M2(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRTextureLightMap2_M2"); + #endif +} + +/*! +*/ +REALINLINE void CTRTextureLightMap2_M2::scanline_bilinear2 () +{ + tVideoSample *dst; + fp24 *z; + + s32 xStart; + s32 xEnd; + s32 dx; + s32 i; + + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + + // search z-buffer for first not occulled pixel + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + + // subTexel + const f32 subPixel = ( (f32) xStart ) - line.x[0]; + +#ifdef IPOL_W + const f32 b = (line.w[1] - line.w[0]) * invDeltaX; + f32 a = line.w[0] + ( b * subPixel ); + + i = 0; + + while ( a <= z[i] ) + { + a += b; + + i += 1; + if ( i > dx ) + return; + } + + // lazy setup rest of scanline + + line.w[0] = a; + line.w[1] = b; +#else + const f32 b = (line.z[1] - line.z[0]) * invDeltaX; + f32 a = line.z[0] + ( b * subPixel ); + + i = 0; + + while ( a > z[i] ) + { + a += b; + + i += 1; + if ( i > dx ) + return; + } + + // lazy setup rest of scanline + + line.z[0] = a; + line.z[1] = b; +#endif + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + + a = (f32) i + subPixel; + + line.t[0][1] = (line.t[0][1] - line.t[0][0]) * invDeltaX; + line.t[1][1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; + + line.t[0][0] += line.t[0][1] * a; + line.t[1][0] += line.t[1][1] * a; + + +#ifdef BURNINGVIDEO_RENDERER_FAST + u32 dIndex = ( line.y & 3 ) << 2; + + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; + +#else + // + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; +#endif + + + for ( ;i <= dx; i++ ) + { +#ifdef IPOL_W + if ( line.w[0] >= z[i] ) + { + z[i] = line.w[0]; +#else + if ( line.z[0] < z[i] ) + { + z[i] = line.z[0]; +#endif + +#ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + f32 inversew = fix_inverse32 ( line.w[0] ); +#else + f32 inversew = FIX_POINT_F32_MUL; +#endif + + + +#ifdef BURNINGVIDEO_RENDERER_FAST + + const tFixPointu d = dithermask [ dIndex | ( i ) & 3 ]; + + getSample_texture ( r0, g0, b0, &IT[0], d + tofix ( line.t[0][0].x,inversew), d + tofix ( line.t[0][0].y,inversew) ); + getSample_texture ( r1, g1, b1, &IT[1], d + tofix ( line.t[1][0].x,inversew), d + tofix ( line.t[1][0].y,inversew) ); +#else + getSample_texture ( r0, g0, b0, &IT[0], tofix ( line.t[0][0].x,inversew), tofix ( line.t[0][0].y,inversew) ); + getSample_texture ( r1, g1, b1, &IT[1], tofix ( line.t[1][0].x,inversew), tofix ( line.t[1][0].y,inversew) ); + +#endif + + dst[i] = fix_to_color ( clampfix_maxcolor ( imulFix_tex2 ( r0, r1 ) ), + clampfix_maxcolor ( imulFix_tex2 ( g0, g1 ) ), + clampfix_maxcolor ( imulFix_tex2 ( b0, b1 ) ) + ); + } + +#ifdef IPOL_W + line.w[0] += line.w[1]; +#else + line.z[0] += line.z[1]; +#endif + line.t[0][0] += line.t[0][1]; + line.t[1][0] += line.t[1][1]; + } + +} + + +void CTRTextureLightMap2_M2::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + sScanConvertData scan; + + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) ) + return; + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + // rasterize upper sub-triangle + if ( F32_GREATER_0 ( scan.invDeltaY[1] ) ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0] * subPixel; + scan.c[1] += scan.slopeC[1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[scan.left] = scan.c[0]; + line.c[scan.right] = scan.c[1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear2 (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0]; + scan.c[1] += scan.slopeC[1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + // rasterize lower sub-triangle + //if ( (f32) 0.0 != scan.invDeltaY[2] ) + if ( F32_GREATER_0 ( scan.invDeltaY[2] ) ) + { + // advance to middle point + if ( F32_GREATER_0 ( scan.invDeltaY[1] ) ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0] = a->Color[0] + scan.slopeC[0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0] * subPixel; + scan.c[1] += scan.slopeC[1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[scan.left] = scan.c[0]; + line.c[scan.right] = scan.c[1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear2 (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0]; + scan.c[1] += scan.slopeC[1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + + + +//! creates a flat triangle renderer +IBurningShader* createTriangleRendererTextureLightMap2_M2(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRTextureLightMap2_M2(driver); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + + diff --git a/source/Irrlicht/CTRTextureLightMap2_M4.cpp b/source/Irrlicht/CTRTextureLightMap2_M4.cpp new file mode 100644 index 00000000..3fd726cf --- /dev/null +++ b/source/Irrlicht/CTRTextureLightMap2_M4.cpp @@ -0,0 +1,1149 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 + +// define render case +#define SUBTEXEL +#define INVERSE_W + +#define USE_ZBUFFER +#define IPOL_W +#define CMP_W +#define WRITE_W + +//#define IPOL_C0 +#define IPOL_T0 +#define IPOL_T1 + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #undef IPOL_C0 +#endif + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif + #define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + +namespace irr +{ + +namespace video +{ + +class CTRTextureLightMap2_M4 : public IBurningShader +{ +public: + + //! constructor + CTRTextureLightMap2_M4(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + + +private: + + void drawTriangle_Min ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ); + void drawTriangle_Mag ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ); + + void scanline_bilinear (); + void scanline_bilinear2_mag (); + void scanline_bilinear2_min (); + + sScanLineData line; + +}; + +//! constructor +CTRTextureLightMap2_M4::CTRTextureLightMap2_M4(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRTextureLightMap2_M4"); + #endif +} + +/*! +*/ +REALINLINE void CTRTextureLightMap2_M4::scanline_bilinear2_mag () +{ + tVideoSample *dst; + fp24 *z; + + // apply top-left fill-convention, left + const s32 xStart = irr::core::ceil32_fast( line.x[0] ); + const s32 xEnd = irr::core::ceil32_fast( line.x[1] ) - 1; + s32 dx; + s32 i; + + + dx = xEnd - xStart; + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + + // search z-buffer for first not occulled pixel + i = ( line.y * RenderTarget->getDimension().Width ) + xStart; + z = (fp24*) DepthBuffer->lock() + i; + dst = (tVideoSample*)RenderTarget->getData() + i; + + // subTexel + const f32 subPixel = ( (f32) xStart ) - line.x[0]; + +#ifdef IPOL_W + const fp24 b = (line.w[1] - line.w[0]) * invDeltaX; + fp24 a = line.w[0] + ( b * subPixel ); + + i = 0; + + while ( a < z[i] ) + { + a += b; + + i += 1; + if ( i > dx ) + return; + } + + // lazy setup rest of scanline + + line.w[0] = a; + line.w[1] = b; +#else + const f32 b = (line.z[1] - line.z[0]) * invDeltaX; + f32 a = line.z[0] + ( b * subPixel ); + + i = 0; + + while ( a > z[i] ) + { + a += b; + + i += 1; + if ( i > dx ) + return; + } + + // lazy setup rest of scanline + + line.z[0] = a; + line.z[1] = b; +#endif + + a = (f32) i + subPixel; + + line.t[0][1] = (line.t[0][1] - line.t[0][0]) * invDeltaX; + line.t[1][1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; + + line.t[0][0] += line.t[0][1] * a; + line.t[1][0] += line.t[1][1] * a; + + +#ifdef BURNINGVIDEO_RENDERER_FAST + u32 dIndex = ( line.y & 3 ) << 2; + + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; + +#else + // + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; +#endif + + + for ( ;i <= dx; i++ ) + { +#ifdef IPOL_W + if ( line.w[0] >= z[i] ) + { + z[i] = line.w[0]; +#else + if ( line.z[0] < z[i] ) + { + z[i] = line.z[0]; +#endif + +#ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + f32 inversew = fix_inverse32 ( line.w[0] ); +#else + f32 inversew = FIX_POINT_F32_MUL; +#endif + + + +#ifdef BURNINGVIDEO_RENDERER_FAST + + const tFixPointu d = dithermask [ dIndex | ( i ) & 3 ]; + + getSample_texture ( r0, g0, b0, &IT[0], d + tofix ( line.t[0][0].x,inversew), d + tofix ( line.t[0][0].y,inversew) ); + getSample_texture ( r1, g1, b1, &IT[1], d + tofix ( line.t[1][0].x,inversew), d + tofix ( line.t[1][0].y,inversew) ); +#else + getSample_texture ( r0, g0, b0, &IT[0], tofix ( line.t[0][0].x,inversew), tofix ( line.t[0][0].y,inversew) ); + getSample_texture ( r1, g1, b1, &IT[1], tofix ( line.t[1][0].x,inversew), tofix ( line.t[1][0].y,inversew) ); + +#endif + + dst[i] = fix_to_color ( clampfix_maxcolor ( imulFix_tex4 ( r0, r1 ) ), + clampfix_maxcolor ( imulFix_tex4 ( g0, g1 ) ), + clampfix_maxcolor ( imulFix_tex4 ( b0, b1 ) ) + ); + } + +#ifdef IPOL_W + line.w[0] += line.w[1]; +#else + line.z[0] += line.z[1]; +#endif + line.t[0][0] += line.t[0][1]; + line.t[1][0] += line.t[1][1]; + } + +} + + +REALINLINE void CTRTextureLightMap2_M4::scanline_bilinear2_min () +{ + tVideoSample *dst; + fp24 *z; + + s32 xStart; + s32 xEnd; + s32 dx; + s32 i; + + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + + // search z-buffer for first not occulled pixel + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + + // subTexel + const f32 subPixel = ( (f32) xStart ) - line.x[0]; + +#ifdef IPOL_W + const f32 b = (line.w[1] - line.w[0]) * invDeltaX; + f32 a = line.w[0] + ( b * subPixel ); + + i = 0; + + while ( a <= z[i] ) + { + a += b; + + i += 1; + if ( i > dx ) + return; + } + + // lazy setup rest of scanline + + line.w[0] = a; + line.w[1] = b; +#else + const f32 b = (line.z[1] - line.z[0]) * invDeltaX; + f32 a = line.z[0] + ( b * subPixel ); + + i = 0; + + while ( a > z[i] ) + { + a += b; + + i += 1; + if ( i > dx ) + return; + } + + // lazy setup rest of scanline + + line.z[0] = a; + line.z[1] = b; +#endif + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + + a = (f32) i + subPixel; + + line.t[0][1] = (line.t[0][1] - line.t[0][0]) * invDeltaX; + line.t[1][1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; + + line.t[0][0] += line.t[0][1] * a; + line.t[1][0] += line.t[1][1] * a; + + + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; + + + for ( ;i <= dx; i++ ) + { +#ifdef IPOL_W + if ( line.w[0] >= z[i] ) + { + z[i] = line.w[0]; +#else + if ( line.z[0] < z[i] ) + { + z[i] = line.z[0]; +#endif + +#ifdef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + f32 inversew = fix_inverse32 ( line.w[0] ); +#else + f32 inversew = FIX_POINT_F32_MUL; +#endif + + + getTexel_fix ( r0, g0, b0, &IT[0], tofix ( line.t[0][0].x,inversew), tofix ( line.t[0][0].y,inversew) ); + getTexel_fix ( r1, g1, b1, &IT[1], tofix ( line.t[1][0].x,inversew), tofix ( line.t[1][0].y,inversew) ); + + dst[i] = fix_to_color ( clampfix_maxcolor ( imulFix_tex4 ( r0, r1 ) ), + clampfix_maxcolor ( imulFix_tex4 ( g0, g1 ) ), + clampfix_maxcolor ( imulFix_tex4 ( b0, b1 ) ) + ); + } + +#ifdef IPOL_W + line.w[0] += line.w[1]; +#else + line.z[0] += line.z[1]; +#endif + line.t[0][0] += line.t[0][1]; + line.t[1][0] += line.t[1][1]; + } + +} + +//#ifdef BURNINGVIDEO_RENDERER_FAST +#if 1 + +void CTRTextureLightMap2_M4::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + if ( IT[0].lodLevel <= 2 ) + drawTriangle_Mag ( a, b, c ); + else + drawTriangle_Min ( a, b, c ); +} + +void CTRTextureLightMap2_M4::drawTriangle_Min ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + sScanConvertData scan; + + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) ) + return; + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + // rasterize upper sub-triangle + if ( F32_GREATER_0 ( scan.invDeltaY[1] ) ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0] * subPixel; + scan.c[1] += scan.slopeC[1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[scan.left] = scan.c[0]; + line.c[scan.right] = scan.c[1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear2_min (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0]; + scan.c[1] += scan.slopeC[1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + // rasterize lower sub-triangle + //if ( (f32) 0.0 != scan.invDeltaY[2] ) + if ( F32_GREATER_0 ( scan.invDeltaY[2] ) ) + { + // advance to middle point + if ( F32_GREATER_0 ( scan.invDeltaY[1] ) ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0] = a->Color[0] + scan.slopeC[0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0] * subPixel; + scan.c[1] += scan.slopeC[1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[scan.left] = scan.c[0]; + line.c[scan.right] = scan.c[1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear2_min (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0]; + scan.c[1] += scan.slopeC[1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + +} + +void CTRTextureLightMap2_M4::drawTriangle_Mag ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) + +#else + +void CTRTextureLightMap2_M4::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) + +#endif + +{ + sScanConvertData scan; + + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + if ( F32_LOWER_EQUAL_0 ( scan.invDeltaY[0] ) ) + return; + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + + // rasterize upper sub-triangle + if ( F32_GREATER_0 ( scan.invDeltaY[1] ) ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0] * subPixel; + scan.c[1] += scan.slopeC[1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[scan.left] = scan.c[0]; + line.c[scan.right] = scan.c[1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear2_mag (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0]; + scan.c[1] += scan.slopeC[1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + // rasterize lower sub-triangle + //if ( (f32) 0.0 != scan.invDeltaY[2] ) + if ( F32_GREATER_0 ( scan.invDeltaY[2] ) ) + { + // advance to middle point + if ( F32_GREATER_0 ( scan.invDeltaY[1] ) ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0] = a->Color[0] + scan.slopeC[0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0] * subPixel; + scan.c[1] += scan.slopeC[1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[scan.left] = scan.c[0]; + line.c[scan.right] = scan.c[1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear2_mag (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0] += scan.slopeC[0]; + scan.c[1] += scan.slopeC[1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + +} + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + + +//! creates a flat triangle renderer +IBurningShader* createTriangleRendererTextureLightMap2_M4(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRTextureLightMap2_M4(driver); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + + diff --git a/source/Irrlicht/CTRTextureLightMapGouraud2_M4.cpp b/source/Irrlicht/CTRTextureLightMapGouraud2_M4.cpp new file mode 100644 index 00000000..64a14ab4 --- /dev/null +++ b/source/Irrlicht/CTRTextureLightMapGouraud2_M4.cpp @@ -0,0 +1,675 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 + +// define render case +#define SUBTEXEL +#define INVERSE_W + +#define USE_ZBUFFER +#define IPOL_W +#define CMP_W +#define WRITE_W + +#define IPOL_C0 +#define IPOL_T0 +#define IPOL_T1 + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#ifndef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + #undef IPOL_C0 +#endif + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif + #define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + +namespace irr +{ + +namespace video +{ + +class CTRGTextureLightMap2_M4 : public IBurningShader +{ +public: + + //! constructor + CTRGTextureLightMap2_M4(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + + +private: + void scanline_bilinear (); + + sScanConvertData scan; + sScanLineData line; + +}; + +//! constructor +CTRGTextureLightMap2_M4::CTRGTextureLightMap2_M4(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRGTextureLightMap2_M4"); + #endif +} + + + +/*! +*/ +void CTRGTextureLightMap2_M4::scanline_bilinear () +{ + tVideoSample *dst; + +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + s32 xStart; + s32 xEnd; + s32 dx; + + +#ifdef SUBTEXEL + f32 subPixel; +#endif + +#ifdef IPOL_Z + f32 slopeZ; +#endif +#ifdef IPOL_W + fp24 slopeW; +#endif +#ifdef IPOL_C0 + sVec4 slopeC; +#endif +#ifdef IPOL_T0 + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES]; +#endif + + // apply top-left fill-convention, left + xStart = core::ceil32_fast( line.x[0] ); + xEnd = core::ceil32_fast( line.x[1] ) - 1; + + dx = xEnd - xStart; + + if ( dx < 0 ) + return; + + // slopes + const f32 invDeltaX = core::reciprocal_approxim ( line.x[1] - line.x[0] ); + +#ifdef IPOL_Z + slopeZ = (line.z[1] - line.z[0]) * invDeltaX; +#endif +#ifdef IPOL_W + slopeW = (line.w[1] - line.w[0]) * invDeltaX; +#endif +#ifdef IPOL_C0 + slopeC = (line.c[0][1] - line.c[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T0 + slopeT[0] = (line.t[0][1] - line.t[0][0]) * invDeltaX; +#endif +#ifdef IPOL_T1 + slopeT[1] = (line.t[1][1] - line.t[1][0]) * invDeltaX; +#endif + +#ifdef SUBTEXEL + subPixel = ( (f32) xStart ) - line.x[0]; +#ifdef IPOL_Z + line.z[0] += slopeZ * subPixel; +#endif +#ifdef IPOL_W + line.w[0] += slopeW * subPixel; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC * subPixel; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0] * subPixel; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1] * subPixel; +#endif +#endif + + dst = (tVideoSample*)RenderTarget->getData() + ( line.y * RenderTarget->getDimension().Width ) + xStart; + +#ifdef USE_ZBUFFER + z = (fp24*) DepthBuffer->lock() + ( line.y * RenderTarget->getDimension().Width ) + xStart; +#endif + + + f32 inversew = FIX_POINT_F32_MUL; + + tFixPoint tx0, tx1; + tFixPoint ty0, ty1; + + tFixPoint r0, g0, b0; + tFixPoint r1, g1, b1; + tFixPoint r2, g2, b2; + +#ifdef IPOL_C0 + tFixPoint r3, g3, b3; +#endif + + for ( s32 i = 0; i <= dx; i++ ) + { +#ifdef CMP_Z + if ( line.z[0] < z[i] ) +#endif +#ifdef CMP_W + if ( line.w[0] >= z[i] ) +#endif + { +#ifdef INVERSE_W + inversew = fix_inverse32 ( line.w[0] ); +#endif + tx0 = tofix ( line.t[0][0].x,inversew); + ty0 = tofix ( line.t[0][0].y,inversew); + tx1 = tofix ( line.t[1][0].x,inversew); + ty1 = tofix ( line.t[1][0].y,inversew); + +#ifdef IPOL_C0 + r3 = tofix ( line.c[0][0].y ,inversew ); + g3 = tofix ( line.c[0][0].z ,inversew ); + b3 = tofix ( line.c[0][0].w ,inversew ); +#endif + + getSample_texture ( r0, g0, b0, &IT[0], tx0, ty0 ); + getSample_texture ( r1, g1, b1, &IT[1], tx1, ty1 ); + +#ifdef IPOL_C0 + r2 = imulFix ( r0, r3 ); + g2 = imulFix ( g0, g3 ); + b2 = imulFix ( b0, b3 ); + + r2 = clampfix_maxcolor ( imulFix_tex4 ( r2, r1 ) ); + g2 = clampfix_maxcolor ( imulFix_tex4 ( g2, g1 ) ); + b2 = clampfix_maxcolor ( imulFix_tex4 ( b2, b1 ) ); +/* + r2 = r3 << 8; + g2 = g3 << 8; + b2 = b3 << 8; +*/ +#else + r2 = clampfix_maxcolor ( imulFix_tex4 ( r0, r1 ) ); + g2 = clampfix_maxcolor ( imulFix_tex4 ( g0, g1 ) ); + b2 = clampfix_maxcolor ( imulFix_tex4 ( b0, b1 ) ); +#endif + + + dst[i] = fix_to_color ( r2, g2, b2 ); + +#ifdef WRITE_Z + z[i] = line.z[0]; +#endif +#ifdef WRITE_W + z[i] = line.w[0]; +#endif + } + +#ifdef IPOL_Z + line.z[0] += slopeZ; +#endif +#ifdef IPOL_W + line.w[0] += slopeW; +#endif +#ifdef IPOL_C0 + line.c[0][0] += slopeC; +#endif +#ifdef IPOL_T0 + line.t[0][0] += slopeT[0]; +#endif +#ifdef IPOL_T1 + line.t[1][0] += slopeT[1]; +#endif + } + +} + +void CTRGTextureLightMap2_M4::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + const f32 ca = c->Pos.y - a->Pos.y; + const f32 ba = b->Pos.y - a->Pos.y; + const f32 cb = c->Pos.y - b->Pos.y; + // calculate delta y of the edges + scan.invDeltaY[0] = core::reciprocal( ca ); + scan.invDeltaY[1] = core::reciprocal( ba ); + scan.invDeltaY[2] = core::reciprocal( cb ); + + if ( F32_LOWER_0 ( scan.invDeltaY[0] ) ) + return; + + // find if the major edge is left or right aligned + f32 temp[4]; + + temp[0] = a->Pos.x - c->Pos.x; + temp[1] = -ca; + temp[2] = b->Pos.x - a->Pos.x; + temp[3] = ba; + + scan.left = ( temp[0] * temp[3] - temp[1] * temp[2] ) > 0.f ? 0 : 1; + scan.right = 1 - scan.left; + + // calculate slopes for the major edge + scan.slopeX[0] = (c->Pos.x - a->Pos.x) * scan.invDeltaY[0]; + scan.x[0] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[0] = (c->Pos.z - a->Pos.z) * scan.invDeltaY[0]; + scan.z[0] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[0] = (c->Pos.w - a->Pos.w) * scan.invDeltaY[0]; + scan.w[0] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][0] = (c->Color[0] - a->Color[0]) * scan.invDeltaY[0]; + scan.c[0][0] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][0] = (c->Tex[0] - a->Tex[0]) * scan.invDeltaY[0]; + scan.t[0][0] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][0] = (c->Tex[1] - a->Tex[1]) * scan.invDeltaY[0]; + scan.t[1][0] = a->Tex[1]; +#endif + + // top left fill convention y run + s32 yStart; + s32 yEnd; + +#ifdef SUBTEXEL + f32 subPixel; +#endif + + + // rasterize upper sub-triangle + //if ( (f32) 0.0 != scan.invDeltaY[1] ) + if ( F32_GREATER_0 ( scan.invDeltaY[1] ) ) + { + // calculate slopes for top edge + scan.slopeX[1] = (b->Pos.x - a->Pos.x) * scan.invDeltaY[1]; + scan.x[1] = a->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (b->Pos.z - a->Pos.z) * scan.invDeltaY[1]; + scan.z[1] = a->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (b->Pos.w - a->Pos.w) * scan.invDeltaY[1]; + scan.w[1] = a->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (b->Color[0] - a->Color[0]) * scan.invDeltaY[1]; + scan.c[0][1] = a->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (b->Tex[0] - a->Tex[0]) * scan.invDeltaY[1]; + scan.t[0][1] = a->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (b->Tex[1] - a->Tex[1]) * scan.invDeltaY[1]; + scan.t[1][1] = a->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( a->Pos.y ); + yEnd = core::ceil32_fast( b->Pos.y ) - 1; + +#ifdef SUBTEXEL + subPixel = ( (f32) yStart ) - a->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + + // rasterize lower sub-triangle + //if ( (f32) 0.0 != scan.invDeltaY[2] ) + if ( F32_GREATER_0 ( scan.invDeltaY[2] ) ) + { + // advance to middle point + //if( (f32) 0.0 != scan.invDeltaY[1] ) + if ( F32_GREATER_0 ( scan.invDeltaY[1] ) ) + { + temp[0] = b->Pos.y - a->Pos.y; // dy + + scan.x[0] = a->Pos.x + scan.slopeX[0] * temp[0]; +#ifdef IPOL_Z + scan.z[0] = a->Pos.z + scan.slopeZ[0] * temp[0]; +#endif +#ifdef IPOL_W + scan.w[0] = a->Pos.w + scan.slopeW[0] * temp[0]; +#endif +#ifdef IPOL_C0 + scan.c[0][0] = a->Color[0] + scan.slopeC[0][0] * temp[0]; +#endif +#ifdef IPOL_T0 + scan.t[0][0] = a->Tex[0] + scan.slopeT[0][0] * temp[0]; +#endif +#ifdef IPOL_T1 + scan.t[1][0] = a->Tex[1] + scan.slopeT[1][0] * temp[0]; +#endif + + } + + // calculate slopes for bottom edge + scan.slopeX[1] = (c->Pos.x - b->Pos.x) * scan.invDeltaY[2]; + scan.x[1] = b->Pos.x; + +#ifdef IPOL_Z + scan.slopeZ[1] = (c->Pos.z - b->Pos.z) * scan.invDeltaY[2]; + scan.z[1] = b->Pos.z; +#endif + +#ifdef IPOL_W + scan.slopeW[1] = (c->Pos.w - b->Pos.w) * scan.invDeltaY[2]; + scan.w[1] = b->Pos.w; +#endif + +#ifdef IPOL_C0 + scan.slopeC[0][1] = (c->Color[0] - b->Color[0]) * scan.invDeltaY[2]; + scan.c[0][1] = b->Color[0]; +#endif + +#ifdef IPOL_T0 + scan.slopeT[0][1] = (c->Tex[0] - b->Tex[0]) * scan.invDeltaY[2]; + scan.t[0][1] = b->Tex[0]; +#endif + +#ifdef IPOL_T1 + scan.slopeT[1][1] = (c->Tex[1] - b->Tex[1]) * scan.invDeltaY[2]; + scan.t[1][1] = b->Tex[1]; +#endif + + // apply top-left fill convention, top part + yStart = core::ceil32_fast( b->Pos.y ); + yEnd = core::ceil32_fast( c->Pos.y ) - 1; + +#ifdef SUBTEXEL + + subPixel = ( (f32) yStart ) - b->Pos.y; + + // correct to pixel center + scan.x[0] += scan.slopeX[0] * subPixel; + scan.x[1] += scan.slopeX[1] * subPixel; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0] * subPixel; + scan.z[1] += scan.slopeZ[1] * subPixel; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0] * subPixel; + scan.w[1] += scan.slopeW[1] * subPixel; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0] * subPixel; + scan.c[0][1] += scan.slopeC[0][1] * subPixel; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0] * subPixel; + scan.t[0][1] += scan.slopeT[0][1] * subPixel; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0] * subPixel; + scan.t[1][1] += scan.slopeT[1][1] * subPixel; +#endif + +#endif + + // rasterize the edge scanlines + for( line.y = yStart; line.y <= yEnd; ++line.y) + { + line.x[scan.left] = scan.x[0]; + line.x[scan.right] = scan.x[1]; + +#ifdef IPOL_Z + line.z[scan.left] = scan.z[0]; + line.z[scan.right] = scan.z[1]; +#endif + +#ifdef IPOL_W + line.w[scan.left] = scan.w[0]; + line.w[scan.right] = scan.w[1]; +#endif + +#ifdef IPOL_C0 + line.c[0][scan.left] = scan.c[0][0]; + line.c[0][scan.right] = scan.c[0][1]; +#endif + +#ifdef IPOL_T0 + line.t[0][scan.left] = scan.t[0][0]; + line.t[0][scan.right] = scan.t[0][1]; +#endif + +#ifdef IPOL_T1 + line.t[1][scan.left] = scan.t[1][0]; + line.t[1][scan.right] = scan.t[1][1]; +#endif + + // render a scanline + scanline_bilinear (); + + scan.x[0] += scan.slopeX[0]; + scan.x[1] += scan.slopeX[1]; + +#ifdef IPOL_Z + scan.z[0] += scan.slopeZ[0]; + scan.z[1] += scan.slopeZ[1]; +#endif + +#ifdef IPOL_W + scan.w[0] += scan.slopeW[0]; + scan.w[1] += scan.slopeW[1]; +#endif + +#ifdef IPOL_C0 + scan.c[0][0] += scan.slopeC[0][0]; + scan.c[0][1] += scan.slopeC[0][1]; +#endif + +#ifdef IPOL_T0 + scan.t[0][0] += scan.slopeT[0][0]; + scan.t[0][1] += scan.slopeT[0][1]; +#endif + +#ifdef IPOL_T1 + scan.t[1][0] += scan.slopeT[1][0]; + scan.t[1][1] += scan.slopeT[1][1]; +#endif + + } + } + +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + + +//! creates a flat triangle renderer +IBurningShader* createTriangleRendererGTextureLightMap2_M4(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRGTextureLightMap2_M4(driver); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + + diff --git a/source/Irrlicht/CTRTextureWire2.cpp b/source/Irrlicht/CTRTextureWire2.cpp new file mode 100644 index 00000000..e1bb8ba6 --- /dev/null +++ b/source/Irrlicht/CTRTextureWire2.cpp @@ -0,0 +1,297 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "IBurningShader.h" + +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +// compile flag for this file +#undef USE_ZBUFFER +#undef IPOL_Z +#undef CMP_Z +#undef WRITE_Z + +#undef IPOL_W +#undef CMP_W +#undef WRITE_W + +#undef SUBTEXEL +#undef INVERSE_W + +#undef IPOL_C0 +#undef IPOL_T0 +#undef IPOL_T1 + +// define render case +#define SUBTEXEL +#define INVERSE_W + +#define USE_ZBUFFER +#define IPOL_W +#define CMP_W +#define WRITE_W + + +//#define IPOL_C0 +#define IPOL_T0 +//#define IPOL_T1 + +// apply global override +#ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef INVERSE_W +#endif + +#ifndef SOFTWARE_DRIVER_2_SUBTEXEL + #undef SUBTEXEL +#endif + +#if !defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) && defined ( USE_ZBUFFER ) + #ifndef SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT + #undef IPOL_W + #endif + #define IPOL_Z + + #ifdef CMP_W + #undef CMP_W + #define CMP_Z + #endif + + #ifdef WRITE_W + #undef WRITE_W + #define WRITE_Z + #endif + +#endif + + +namespace irr +{ + +namespace video +{ + +class CTRTextureWire2 : public IBurningShader +{ +public: + + //! constructor + CTRTextureWire2(CBurningVideoDriver* driver); + + //! draws an indexed triangle list + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) _IRR_OVERRIDE_; + virtual void drawLine ( const s4DVertex *a,const s4DVertex *b) _IRR_OVERRIDE_; + + + +private: + void renderAlphaLine ( const s4DVertex *a,const s4DVertex *b ) const; + void renderLine ( const s4DVertex *a,const s4DVertex *b ) const; + +}; + +//! constructor +CTRTextureWire2::CTRTextureWire2(CBurningVideoDriver* driver) +: IBurningShader(driver) +{ + #ifdef _DEBUG + setDebugName("CTRTextureWire2"); + #endif +} + + +// swap integer with xor +static inline void swap_xor ( s32 &a, s32 &b ) +{ + a ^= b; + b ^= a; + a ^= b; +} + + +/*! +*/ +void CTRTextureWire2::renderLine ( const s4DVertex *a,const s4DVertex *b ) const +{ + int pitch0 = RenderTarget->getDimension().Width << VIDEO_SAMPLE_GRANULARITY; + int pitch1 = RenderTarget->getDimension().Width << 2; + + int aposx = (int) a->Pos.x; + int aposy = (int) a->Pos.y; + int bposx = (int) b->Pos.x; + int bposy = (int) b->Pos.y; + + int dx = bposx - aposx; + int dy = bposy - aposy; + + int c; + int m; + int d = 0; + int run; + + tVideoSample *dst; +#ifdef USE_ZBUFFER + fp24 *z; +#endif + + int xInc0 = 1 << VIDEO_SAMPLE_GRANULARITY; + int yInc0 = pitch0; + + int xInc1 = 4; + int yInc1 = pitch1; + + tVideoSample color; + +#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + tFixPoint r0, g0, b0; + getSample_color ( r0, g0, b0, a->Color[0] ); + color = fix_to_color ( r0, g0, b0 ); +#else + color = (tVideoSample) 0xFFFFFFFF; +#endif + + if ( dx < 0 ) + { + xInc0 = - ( 1 << VIDEO_SAMPLE_GRANULARITY); + xInc1 = -4; + dx = -dx; + } + + if ( dy > dx ) + { + swap_xor ( dx, dy ); + swap_xor ( xInc0, yInc0 ); + swap_xor ( xInc1, yInc1 ); + } + + if ( 0 == dx ) + return; + + dst = (tVideoSample*) ( (u8*) (tVideoSample*)RenderTarget->getData() + ( aposy * pitch0 ) + (aposx << VIDEO_SAMPLE_GRANULARITY ) ); +#ifdef USE_ZBUFFER + z = (fp24*) ( (u8*) (fp24*) DepthBuffer->lock() + ( aposy * pitch1 ) + (aposx << 2 ) ); +#endif + + c = dx << 1; + m = dy << 1; + +#ifdef IPOL_Z + f32 slopeZ = (b->Pos.z - a->Pos.z) / f32(dx); + f32 dataZ = a->Pos.z; +#endif + +#ifdef IPOL_W + fp24 slopeW = (b->Pos.w - a->Pos.w) / f32( dx ); + fp24 dataW = a->Pos.w; +#endif + + run = dx; + while ( run ) + { +#ifdef CMP_Z + if ( *z >= dataZ ) +#endif +#ifdef CMP_W + if ( dataW >= *z ) +#endif + { +#ifdef WRITE_Z + *z = dataZ; +#endif +#ifdef WRITE_W + *z = dataW; +#endif + + *dst = color; + + } + + dst = (tVideoSample*) ( (u8*) dst + xInc0 ); // x += xInc +#ifdef IPOL_Z + z = (fp24*) ( (u8*) z + xInc1 ); +#endif +#ifdef IPOL_W + z = (fp24*) ( (u8*) z + xInc1 ); +#endif + + d += m; + if ( d > dx ) + { + dst = (tVideoSample*) ( (u8*) dst + yInc0 ); // y += yInc +#ifdef IPOL_Z + z = (fp24*) ( (u8*) z + yInc1 ); +#endif +#ifdef IPOL_W + z = (fp24*) ( (u8*) z + yInc1 ); +#endif + + d -= c; + } + run -= 1; +#ifdef IPOL_Z + dataZ += slopeZ; +#endif +#ifdef IPOL_W + dataW += slopeW; +#endif + + } + +} + +void CTRTextureWire2::drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) +{ + sScanLineData line; + + // sort on height, y + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + if ( F32_A_GREATER_B ( b->Pos.y , c->Pos.y ) ) swapVertexPointer(&b, &c); + if ( F32_A_GREATER_B ( a->Pos.y , b->Pos.y ) ) swapVertexPointer(&a, &b); + + renderLine ( a, b ); + renderLine ( b, c ); + renderLine ( a, c ); + +} + + +void CTRTextureWire2::drawLine ( const s4DVertex *a,const s4DVertex *b) +{ + + // query access to TexMaps + + // sort on height, y + if ( a->Pos.y > b->Pos.y ) swapVertexPointer(&a, &b); + + renderLine ( a, b ); + +} + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +namespace irr +{ +namespace video +{ + + +//! creates a flat triangle renderer +IBurningShader* createTriangleRendererTextureGouraudWire2(CBurningVideoDriver* driver) +{ + #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + return new CTRTextureWire2(driver); + #else + return 0; + #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ +} + + +} // end namespace video +} // end namespace irr + + diff --git a/source/Irrlicht/CTarReader.cpp b/source/Irrlicht/CTarReader.cpp new file mode 100644 index 00000000..6fd5ea7f --- /dev/null +++ b/source/Irrlicht/CTarReader.cpp @@ -0,0 +1,256 @@ +// Copyright (C) 2009-2012 Gaz Davidson +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CTarReader.h" + +#ifdef __IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_ + +#include "CFileList.h" +#include "CLimitReadFile.h" +#include "os.h" +#include "coreutil.h" +#include "errno.h" + +namespace irr +{ +namespace io +{ + +//! Constructor +CArchiveLoaderTAR::CArchiveLoaderTAR(io::IFileSystem* fs) +: FileSystem(fs) +{ + #ifdef _DEBUG + setDebugName("CArchiveLoaderTAR"); + #endif +} + + +//! returns true if the file maybe is able to be loaded by this class +bool CArchiveLoaderTAR::isALoadableFileFormat(const io::path& filename) const +{ + return core::hasFileExtension(filename, "tar"); +} + +//! Check to see if the loader can create archives of this type. +bool CArchiveLoaderTAR::isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const +{ + return fileType == EFAT_TAR; +} + +//! Creates an archive from the filename +/** \param file File handle to check. +\return Pointer to newly created archive, or 0 upon error. */ +IFileArchive* CArchiveLoaderTAR::createArchive(const io::path& filename, bool ignoreCase, bool ignorePaths) const +{ + IFileArchive *archive = 0; + io::IReadFile* file = FileSystem->createAndOpenFile(filename); + + if (file) + { + archive = createArchive(file, ignoreCase, ignorePaths); + file->drop(); + } + + return archive; +} + + +//! creates/loads an archive from the file. +//! \return Pointer to the created archive. Returns 0 if loading failed. +IFileArchive* CArchiveLoaderTAR::createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const +{ + IFileArchive *archive = 0; + if (file) + { + file->seek(0); + archive = new CTarReader(file, ignoreCase, ignorePaths); + } + return archive; +} + +//! Check if the file might be loaded by this class +/** Check might look into the file. +\param file File handle to check. +\return True if file seems to be loadable. */ +bool CArchiveLoaderTAR::isALoadableFileFormat(io::IReadFile* file) const +{ + // TAR files consist of blocks of 512 bytes + // if it isn't a multiple of 512 then it's not a TAR file. + if (file->getSize() % 512) + return false; + + file->seek(0); + + // read header of first file + STarHeader fHead; + file->read(&fHead, sizeof(STarHeader)); + + u32 checksum = 0; + sscanf(fHead.Checksum, "%o", &checksum); + + // verify checksum + + // some old TAR writers assume that chars are signed, others assume unsigned + // USTAR archives have a longer header, old TAR archives end after linkname + + u32 checksum1=0; + s32 checksum2=0; + + // remember to blank the checksum field! + memset(fHead.Checksum, ' ', 8); + + // old header + for (u8* p = (u8*)(&fHead); p < (u8*)(&fHead.Magic[0]); ++p) + { + checksum1 += *p; + checksum2 += c8(*p); + } + + if (!strncmp(fHead.Magic, "ustar", 5)) + { + for (u8* p = (u8*)(&fHead.Magic[0]); p < (u8*)(&fHead) + sizeof(fHead); ++p) + { + checksum1 += *p; + checksum2 += c8(*p); + } + } + return checksum1 == checksum || checksum2 == (s32)checksum; +} + +/* + TAR Archive +*/ +CTarReader::CTarReader(IReadFile* file, bool ignoreCase, bool ignorePaths) + : CFileList((file ? file->getFileName() : io::path("")), ignoreCase, ignorePaths), File(file) +{ + #ifdef _DEBUG + setDebugName("CTarReader"); + #endif + + if (File) + { + File->grab(); + + // fill the file list + populateFileList(); + + sort(); + } +} + + +CTarReader::~CTarReader() +{ + if (File) + File->drop(); +} + + +const IFileList* CTarReader::getFileList() const +{ + return this; +} + + +u32 CTarReader::populateFileList() +{ + STarHeader fHead; + Files.clear(); + + u32 pos = 0; + while ( s32(pos + sizeof(STarHeader)) < File->getSize()) + { + // seek to next file header + File->seek(pos); + + // read the header + File->read(&fHead, sizeof(fHead)); + + // only add standard files for now + if (fHead.Link == ETLI_REGULAR_FILE || ETLI_REGULAR_FILE_OLD) + { + io::path fullPath = ""; + fullPath.reserve(255); + + // USTAR archives have a filename prefix + // may not be null terminated, copy carefully! + if (!strncmp(fHead.Magic, "ustar", 5)) + { + c8* np = fHead.FileNamePrefix; + while(*np && (np - fHead.FileNamePrefix) < 155) + fullPath.append(*np); + np++; + } + + // append the file name + c8* np = fHead.FileName; + while(*np && (np - fHead.FileName) < 100) + { + fullPath.append(*np); + np++; + } + + // get size + core::stringc sSize = ""; + sSize.reserve(12); + np = fHead.Size; + while(*np && (np - fHead.Size) < 12) + { + sSize.append(*np); + np++; + } + + u32 size = strtoul(sSize.c_str(), NULL, 8); + + if (errno == ERANGE) + os::Printer::log("File too large", fullPath, ELL_WARNING); + + // save start position + u32 offset = pos + 512; + + // move to next file header block + pos = offset + (size / 512) * 512 + ((size % 512) ? 512 : 0); + + // add file to list + addItem(fullPath, offset, size, false ); + } + else + { + // todo: ETLI_DIRECTORY, ETLI_LINK_TO_ARCHIVED_FILE + + // move to next block + pos += 512; + } + + } + + return Files.size(); +} + +//! opens a file by file name +IReadFile* CTarReader::createAndOpenFile(const io::path& filename) +{ + const s32 index = findFile(filename, false); + + if (index != -1) + return createAndOpenFile(index); + + return 0; +} + +//! opens a file by index +IReadFile* CTarReader::createAndOpenFile(u32 index) +{ + if (index >= Files.size() ) + return 0; + + const SFileListEntry &entry = Files[index]; + return createLimitReadFile( entry.FullName, File, entry.Offset, entry.Size ); +} + +} // end namespace io +} // end namespace irr + +#endif // __IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_ diff --git a/source/Irrlicht/CTarReader.h b/source/Irrlicht/CTarReader.h new file mode 100644 index 00000000..3759f5b1 --- /dev/null +++ b/source/Irrlicht/CTarReader.h @@ -0,0 +1,136 @@ +// Copyright (C) 2009-2012 Gaz Davidson +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_TAR_READER_H_INCLUDED__ +#define __C_TAR_READER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef __IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_ + +#include "IReferenceCounted.h" +#include "IReadFile.h" +#include "irrArray.h" +#include "irrString.h" +#include "IFileSystem.h" +#include "CFileList.h" + +namespace irr +{ +namespace io +{ + + enum E_TAR_LINK_INDICATOR + { + ETLI_REGULAR_FILE_OLD = 0 , + ETLI_REGULAR_FILE = '0', + ETLI_LINK_TO_ARCHIVED_FILE = '1', // Hard link + ETLI_SYMBOLIC_LINK = '2', + ETLI_CHAR_SPECIAL_DEVICE = '3', + ETLI_BLOCK_SPECIAL_DEVICE = '4', + ETLI_DIRECTORY = '5', + ETLI_FIFO_SPECIAL_FILE = '6', + ETLI_CONTIGUOUS_FILE = '7' + }; + +// byte-align structures +#include "irrpack.h" + + struct STarHeader + { + c8 FileName[100]; + c8 FileMode[8]; + c8 UserID[8]; + c8 GroupID[8]; + c8 Size[12]; + c8 ModifiedTime[12]; + c8 Checksum[8]; + c8 Link; + c8 LinkName[100]; + c8 Magic[6]; + c8 USTARVersion[2]; + c8 UserName[32]; + c8 GroupName[32]; + c8 DeviceMajor[8]; + c8 DeviceMinor[8]; + c8 FileNamePrefix[155]; + } PACK_STRUCT; + +// Default alignment +#include "irrunpack.h" + + //! Archiveloader capable of loading ZIP Archives + class CArchiveLoaderTAR : public IArchiveLoader + { + public: + + //! Constructor + CArchiveLoaderTAR(io::IFileSystem* fs); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".tar") + virtual bool isALoadableFileFormat(const io::path& filename) const _IRR_OVERRIDE_; + + //! Check if the file might be loaded by this class + /** Check might look into the file. + \param file File handle to check. + \return True if file seems to be loadable. */ + virtual bool isALoadableFileFormat(io::IReadFile* file) const _IRR_OVERRIDE_; + + //! Check to see if the loader can create archives of this type. + /** Check based on the archive type. + \param fileType The archive type to check. + \return True if the archile loader supports this type, false if not */ + virtual bool isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const _IRR_OVERRIDE_; + + //! Creates an archive from the filename + /** \param file File handle to check. + \return Pointer to newly created archive, or 0 upon error. */ + virtual IFileArchive* createArchive(const io::path& filename, bool ignoreCase, bool ignorePaths) const _IRR_OVERRIDE_; + + //! creates/loads an archive from the file. + //! \return Pointer to the created archive. Returns 0 if loading failed. + virtual io::IFileArchive* createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const _IRR_OVERRIDE_; + + private: + io::IFileSystem* FileSystem; + }; + + + + class CTarReader : public virtual IFileArchive, virtual CFileList + { + public: + + CTarReader(IReadFile* file, bool ignoreCase, bool ignorePaths); + + virtual ~CTarReader(); + + //! opens a file by file name + virtual IReadFile* createAndOpenFile(const io::path& filename) _IRR_OVERRIDE_; + + //! opens a file by index + virtual IReadFile* createAndOpenFile(u32 index) _IRR_OVERRIDE_; + + //! returns the list of files + virtual const IFileList* getFileList() const _IRR_OVERRIDE_; + + //! get the class Type + virtual E_FILE_ARCHIVE_TYPE getType() const _IRR_OVERRIDE_ { return EFAT_TAR; } + + //! return the name (id) of the file Archive + virtual const io::path& getArchiveName() const _IRR_OVERRIDE_ {return Path;} + + private: + + u32 populateFileList(); + + IReadFile* File; + }; + +} // end namespace io +} // end namespace irr + +#endif // __IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_ +#endif // __C_TAR_READER_H_INCLUDED__ diff --git a/source/Irrlicht/CTerrainSceneNode.cpp b/source/Irrlicht/CTerrainSceneNode.cpp new file mode 100644 index 00000000..395a45da --- /dev/null +++ b/source/Irrlicht/CTerrainSceneNode.cpp @@ -0,0 +1,1518 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +// The code for the TerrainSceneNode is based on the GeoMipMapSceneNode +// developed by Spintz. He made it available for Irrlicht and allowed it to be +// distributed under this licence. I only modified some parts. A lot of thanks +// go to him. + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_TERRAIN_SCENENODE_ + +#include "CTerrainSceneNode.h" +#include "CTerrainTriangleSelector.h" +#include "IVideoDriver.h" +#include "ISceneManager.h" +#include "ICameraSceneNode.h" +#include "SViewFrustum.h" +#include "irrMath.h" +#include "os.h" +#include "IGUIFont.h" +#include "IFileSystem.h" +#include "IReadFile.h" +#include "ITextSceneNode.h" +#include "IAnimatedMesh.h" +#include "SMesh.h" +#include "CDynamicMeshBuffer.h" + +namespace irr +{ +namespace scene +{ + + //! constructor + CTerrainSceneNode::CTerrainSceneNode(ISceneNode* parent, ISceneManager* mgr, + io::IFileSystem* fs, s32 id, s32 maxLOD, E_TERRAIN_PATCH_SIZE patchSize, + const core::vector3df& position, + const core::vector3df& rotation, + const core::vector3df& scale) + : ITerrainSceneNode(parent, mgr, id, position, rotation, scale), + TerrainData(patchSize, maxLOD, position, rotation, scale), RenderBuffer(0), + VerticesToRender(0), IndicesToRender(0), DynamicSelectorUpdate(false), + OverrideDistanceThreshold(false), UseDefaultRotationPivot(true), ForceRecalculation(true), + FixedBorderLOD(-1), + CameraMovementDelta(10.0f), CameraRotationDelta(1.0f),CameraFOVDelta(0.1f), + TCoordScale1(1.0f), TCoordScale2(1.0f), SmoothFactor(0), FileSystem(fs) + { + #ifdef _DEBUG + setDebugName("CTerrainSceneNode"); + #endif + + Mesh = new SMesh(); + 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); + } + + + //! destructor + CTerrainSceneNode::~CTerrainSceneNode() + { + delete [] TerrainData.Patches; + + if (FileSystem) + FileSystem->drop(); + + if (Mesh) + Mesh->drop(); + + if (RenderBuffer) + RenderBuffer->drop(); + } + + + //! Initializes the terrain data. Loads the vertices from the heightMapFile + bool CTerrainSceneNode::loadHeightMap(io::IReadFile* file, video::SColor vertexColor, + s32 smoothFactor) + { + if (!file) + return false; + + Mesh->MeshBuffers.clear(); + const u32 startTime = os::Timer::getRealTime(); + video::IImage* heightMap = SceneManager->getVideoDriver()->createImageFromFile(file); + + if (!heightMap) + { + os::Printer::log("Unable to load heightmap."); + return false; + } + + HeightmapFile = file->getFileName(); + SmoothFactor = smoothFactor; + + // Get the dimension of the heightmap data + TerrainData.Size = heightMap->getDimension().Width; + + switch (TerrainData.PatchSize) + { + case ETPS_9: + if (TerrainData.MaxLOD > 3) + { + TerrainData.MaxLOD = 3; + } + break; + case ETPS_17: + if (TerrainData.MaxLOD > 4) + { + TerrainData.MaxLOD = 4; + } + break; + case ETPS_33: + if (TerrainData.MaxLOD > 5) + { + TerrainData.MaxLOD = 5; + } + break; + case ETPS_65: + if (TerrainData.MaxLOD > 6) + { + TerrainData.MaxLOD = 6; + } + break; + case ETPS_129: + if (TerrainData.MaxLOD > 7) + { + TerrainData.MaxLOD = 7; + } + break; + } + + // --- Generate vertex data from heightmap ---- + // resize the vertex array for the mesh buffer one time (makes loading faster) + scene::CDynamicMeshBuffer *mb=0; + + const u32 numVertices = TerrainData.Size * TerrainData.Size; + if (numVertices <= 65536) + { + //small enough for 16bit buffers + mb=new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT); + RenderBuffer->getIndexBuffer().setType(video::EIT_16BIT); + } + else + { + //we need 32bit buffers + mb=new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_32BIT); + RenderBuffer->getIndexBuffer().setType(video::EIT_32BIT); + } + + mb->getVertexBuffer().set_used(numVertices); + + // Read the heightmap to get the vertex data + // Apply positions changes, scaling changes + const f32 tdSize = 1.0f/(f32)(TerrainData.Size-1); + s32 index = 0; + float fx=0.f; + float fx2=0.f; + for (s32 x = 0; x < TerrainData.Size; ++x) + { + float fz=0.f; + float fz2=0.f; + 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-1,z).getLightness(); + vertex.Pos.Z = fz; + + vertex.TCoords.X = vertex.TCoords2.X = 1.f-fx2; + vertex.TCoords.Y = vertex.TCoords2.Y = fz2; + + ++fz; + fz2 += tdSize; + } + ++fx; + fx2 += tdSize; + } + + // drop heightMap, no longer needed + heightMap->drop(); + + smoothTerrain(mb, smoothFactor); + + // calculate smooth normals for the vertices + calculateNormals(mb); + + // add the MeshBuffer to the mesh + Mesh->addMeshBuffer(mb); + + // 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) + { + RenderBuffer->getVertexBuffer()[i] = mb->getVertexBuffer()[i]; + RenderBuffer->getVertexBuffer()[i].Pos *= TerrainData.Scale; + RenderBuffer->getVertexBuffer()[i].Pos += TerrainData.Position; + } + + // We no longer need the mb + mb->drop(); + + // calculate all the necessary data for the patches and the terrain + calculateDistanceThresholds(); + createPatches(); + calculatePatchData(); + + // set the default rotation pivot point to the terrain nodes center + TerrainData.RotationPivot = TerrainData.Center; + + // 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); + + // Pre-allocate memory for indices + + RenderBuffer->getIndexBuffer().set_used( + TerrainData.PatchCount * TerrainData.PatchCount * + TerrainData.CalcPatchSize * TerrainData.CalcPatchSize * 6); + + RenderBuffer->setDirty(); + + const u32 endTime = os::Timer::getRealTime(); + + c8 tmp[255]; + snprintf_irr(tmp, 255, "Generated terrain data (%dx%d) in %.4f seconds", + TerrainData.Size, TerrainData.Size, (endTime - startTime) / 1000.0f ); + os::Printer::log(tmp); + + return true; + } + + + //! 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) + { + if (!file) + return false; + if (floatVals && bitsPerPixel != 32) + return false; + + // start reading + const u32 startTime = os::Timer::getTime(); + + Mesh->MeshBuffers.clear(); + + const size_t bytesPerPixel = (size_t)bitsPerPixel / 8; + + // Get the dimension of the heightmap data + const long filesize = file->getSize(); + if (!width) + TerrainData.Size = core::floor32(sqrtf((f32)(filesize / bytesPerPixel))); + else + { + if ((filesize-file->getPos())/bytesPerPixel>(size_t)(width*width)) + { + os::Printer::log("Error reading heightmap RAW file", "File is too small."); + return false; + } + TerrainData.Size = width; + } + + switch (TerrainData.PatchSize) + { + case ETPS_9: + if (TerrainData.MaxLOD > 3) + { + TerrainData.MaxLOD = 3; + } + break; + case ETPS_17: + if (TerrainData.MaxLOD > 4) + { + TerrainData.MaxLOD = 4; + } + break; + case ETPS_33: + if (TerrainData.MaxLOD > 5) + { + TerrainData.MaxLOD = 5; + } + break; + case ETPS_65: + if (TerrainData.MaxLOD > 6) + { + TerrainData.MaxLOD = 6; + } + break; + case ETPS_129: + if (TerrainData.MaxLOD > 7) + { + TerrainData.MaxLOD = 7; + } + break; + } + + // --- Generate vertex data from heightmap ---- + // resize the vertex array for the mesh buffer one time (makes loading faster) + scene::CDynamicMeshBuffer *mb=0; + const u32 numVertices = TerrainData.Size * TerrainData.Size; + if (numVertices <= 65536) + { + //small enough for 16bit buffers + mb=new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT); + RenderBuffer->getIndexBuffer().setType(video::EIT_16BIT); + } + else + { + //we need 32bit buffers + mb=new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_32BIT); + RenderBuffer->getIndexBuffer().setType(video::EIT_32BIT); + } + + mb->getVertexBuffer().reallocate(numVertices); + + video::S3DVertex2TCoords vertex; + vertex.Normal.set(0.0f, 1.0f, 0.0f); + vertex.Color = vertexColor; + + // Read the heightmap to get the vertex data + // Apply positions changes, scaling changes + 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) + { + float fz=0.f; + float fz2=0.f; + 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) + failure=true; + } + else if (signedData) + { + switch (bytesPerPixel) + { + case 1: + { + s8 val; + if (file->read(&val, bytesPerPixel) != bytesPerPixel) + failure=true; + vertex.Pos.Y=val; + } + break; + case 2: + { + s16 val; + if (file->read(&val, bytesPerPixel) != bytesPerPixel) + failure=true; + vertex.Pos.Y=val/256.f; + } + break; + case 4: + { + s32 val; + if (file->read(&val, bytesPerPixel) != bytesPerPixel) + failure=true; + vertex.Pos.Y=val/16777216.f; + } + break; + } + } + else + { + switch (bytesPerPixel) + { + case 1: + { + u8 val; + if (file->read(&val, bytesPerPixel) != bytesPerPixel) + failure=true; + vertex.Pos.Y=val; + } + break; + case 2: + { + u16 val; + if (file->read(&val, bytesPerPixel) != bytesPerPixel) + failure=true; + vertex.Pos.Y=val/256.f; + } + break; + case 4: + { + u32 val; + if (file->read(&val, bytesPerPixel) != bytesPerPixel) + failure=true; + vertex.Pos.Y=val/16777216.f; + } + break; + } + } + if (failure) + { + os::Printer::log("Error reading heightmap RAW file."); + mb->drop(); + return false; + } + vertex.Pos.Z = fz; + + vertex.TCoords.X = vertex.TCoords2.X = 1.f-fx2; + vertex.TCoords.Y = vertex.TCoords2.Y = fz2; + + mb->getVertexBuffer().push_back(vertex); + ++fz; + fz2 += tdSize; + } + ++fx; + fx2 += tdSize; + } + + smoothTerrain(mb, smoothFactor); + + // calculate smooth normals for the vertices + calculateNormals(mb); + + // add the MeshBuffer to the mesh + 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); + + for (u32 i = 0; i < vertexCount; i++) + { + RenderBuffer->getVertexBuffer()[i] = mb->getVertexBuffer()[i]; + RenderBuffer->getVertexBuffer()[i].Pos *= TerrainData.Scale; + RenderBuffer->getVertexBuffer()[i].Pos += TerrainData.Position; + } + + // We no longer need the mb + mb->drop(); + + // calculate all the necessary data for the patches and the terrain + calculateDistanceThresholds(); + createPatches(); + calculatePatchData(); + + // set the default rotation pivot point to the terrain nodes center + TerrainData.RotationPivot = TerrainData.Center; + + // 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); + + // Pre-allocate memory for indices + RenderBuffer->getIndexBuffer().set_used( + TerrainData.PatchCount*TerrainData.PatchCount* + TerrainData.CalcPatchSize*TerrainData.CalcPatchSize*6); + + const u32 endTime = os::Timer::getTime(); + + c8 tmp[255]; + snprintf_irr(tmp, 255, "Generated terrain data (%dx%d) in %.4f seconds", + TerrainData.Size, TerrainData.Size, (endTime - startTime) / 1000.0f); + os::Printer::log(tmp); + + return true; + } + + + //! Returns the mesh + IMesh* CTerrainSceneNode::getMesh() { return Mesh; } + + + //! Returns the material based on the zero based index i. + video::SMaterial& CTerrainSceneNode::getMaterial(u32 i) + { + return Mesh->getMeshBuffer(i)->getMaterial(); + } + + + //! Returns amount of materials used by this scene node ( always 1 ) + u32 CTerrainSceneNode::getMaterialCount() const + { + return Mesh->getMeshBufferCount(); + } + + + //! Sets the scale of the scene node. + //! \param scale: New scale of the node + void CTerrainSceneNode::setScale(const core::vector3df& scale) + { + TerrainData.Scale = scale; + applyTransformation(); + calculateNormals(RenderBuffer); + ForceRecalculation = true; + } + + + //! Sets the rotation of the node. This only modifies + //! the relative rotation of the node. + //! \param rotation: New rotation of the node in degrees. + void CTerrainSceneNode::setRotation(const core::vector3df& rotation) + { + TerrainData.Rotation = rotation; + applyTransformation(); + ForceRecalculation = true; + } + + + //! 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) + { + UseDefaultRotationPivot = false; + TerrainData.RotationPivot = pivot; + } + + + //! Sets the position of the node. + //! \param newpos: New postition of the scene node. + void CTerrainSceneNode::setPosition(const core::vector3df& newpos) + { + TerrainData.Position = newpos; + applyTransformation(); + ForceRecalculation = true; + } + + + //! Apply transformation changes(scale, position, rotation) + void CTerrainSceneNode::applyTransformation() + { + if (!Mesh->getMeshBufferCount()) + return; + + core::matrix4 rotMatrix; + rotMatrix.setRotationDegrees(TerrainData.Rotation); + + const s32 vtxCount = Mesh->getMeshBuffer(0)->getVertexCount(); + for (s32 i = 0; i < vtxCount; ++i) + { + 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); + RenderBuffer->getVertexBuffer()[i].Pos += TerrainData.RotationPivot; + } + + calculateDistanceThresholds(true); + calculatePatchData(); + + RenderBuffer->setDirty(EBT_VERTEX); + } + + + //! Updates the scene nodes indices if the camera has moved or rotated by a certain + //! threshold, which can be changed using the SetCameraMovementDeltaThreshold and + //! SetCameraRotationDeltaThreshold functions. This also determines if a given patch + //! for the scene node is within the view frustum and if it's not the indices are not + //! generated for that patch. + void CTerrainSceneNode::OnRegisterSceneNode() + { + if (!IsVisible || !SceneManager->getActiveCamera()) + return; + + SceneManager->registerNodeForRendering(this); + + preRenderCalculationsIfNeeded(); + + // Do Not call ISceneNode::OnRegisterSceneNode(), this node should have no children (luke: is this comment still true, as ISceneNode::OnRegisterSceneNode() is called?) + + ISceneNode::OnRegisterSceneNode(); + ForceRecalculation = false; + } + + void CTerrainSceneNode::preRenderCalculationsIfNeeded() + { + scene::ICameraSceneNode * camera = SceneManager->getActiveCamera(); + if (!camera) + return; + + // Determine the camera rotation, based on the camera direction. + 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 ((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 && + cameraUp.dotProduct(OldCameraUp) > (1.f - (cos(core::DEGTORAD * CameraRotationDelta)))) + { + return; + } + } + } + } + + //we need to redo calculations... + + OldCameraPosition = cameraPosition; + OldCameraRotation = cameraRotation; + OldCameraUp = cameraUp; + OldCameraFOV = CameraFOV; + + preRenderLODCalculations(); + preRenderIndicesCalculations(); + } + + void CTerrainSceneNode::preRenderLODCalculations() + { + scene::ICameraSceneNode * camera = SceneManager->getActiveCamera(); + + if (!camera) + return; + + const core::vector3df cameraPosition = camera->getAbsolutePosition(); + + const SViewFrustum* frustum = camera->getViewFrustum(); + + // 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) + { + if (frustum->getBoundingBox().intersectsWithBox(TerrainData.Patches[j].BoundingBox)) + { + const f32 distance = cameraPosition.getDistanceFromSQ(TerrainData.Patches[j].Center); + + if ( FixedBorderLOD >= 0 ) + { + TerrainData.Patches[j].CurrentLOD = FixedBorderLOD; + if (j < TerrainData.PatchCount + || j >= (count - TerrainData.PatchCount) + || (j % TerrainData.PatchCount) == 0 + || (j % TerrainData.PatchCount) == TerrainData.PatchCount-1) + continue; + } + + TerrainData.Patches[j].CurrentLOD = 0; + + for (s32 i = TerrainData.MaxLOD - 1; i>0; --i) + { + if (distance >= TerrainData.LODDistanceThreshold[i]) + { + TerrainData.Patches[j].CurrentLOD = i; + break; + } + } + } + else + { + TerrainData.Patches[j].CurrentLOD = -1; + } + } + } + + + void CTerrainSceneNode::preRenderIndicesCalculations() + { + 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 j = 0; j < TerrainData.PatchCount; ++j) + { + if (TerrainData.Patches[index].CurrentLOD >= 0) + { + s32 x = 0; + s32 z = 0; + + // calculate the step we take this patch, based on the patches current LOD + const s32 step = 1 << TerrainData.Patches[index].CurrentLOD; + + // 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); + + 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; + + // we've hit an edge + if (x >= TerrainData.CalcPatchSize) + { + x = 0; + z += step; + } + } + } + ++index; + } + } + + RenderBuffer->setDirty(EBT_INDEX); + + if (DynamicSelectorUpdate && TriangleSelector) + { + CTerrainTriangleSelector* selector = (CTerrainTriangleSelector*)TriangleSelector; + selector->setTriangleData(this, -1); + } + } + + + //! Render the scene node + void CTerrainSceneNode::render() + { + if (!IsVisible || !SceneManager->getActiveCamera()) + return; + + if (!Mesh->getMeshBufferCount()) + return; + + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + + driver->setTransform (video::ETS_WORLD, core::IdentityMatrix); + driver->setMaterial(Mesh->getMeshBuffer(0)->getMaterial()); + + RenderBuffer->getIndexBuffer().set_used(IndicesToRender); + + // For use with geomorphing + driver->drawMeshBuffer(RenderBuffer); + + RenderBuffer->getIndexBuffer().set_used(RenderBuffer->getIndexBuffer().allocated_size()); + + // for debug purposes only: + if (DebugDataVisible) + { + video::SMaterial m; + m.Lighting = false; + driver->setMaterial(m); + if (DebugDataVisible & scene::EDS_BBOX) + 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) + { + driver->draw3DBox(TerrainData.Patches[j].BoundingBox, video::SColor(255,255,0,0)); + visible += (TerrainData.Patches[j].CurrentLOD >= 0); + } + } + + if (DebugDataVisible & scene::EDS_NORMALS) + { + // draw normals + const f32 debugNormalLength = SceneManager->getParameters()->getAttributeAsFloat(DEBUG_NORMAL_LENGTH); + const video::SColor debugNormalColor = SceneManager->getParameters()->getAttributeAsColor(DEBUG_NORMAL_COLOR); + driver->drawMeshBufferNormals(RenderBuffer, debugNormalLength, debugNormalColor); + } + + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + + static u32 lastTime = 0; + + const u32 now = os::Timer::getRealTime(); + if (now - lastTime > 1000) + { + char buf[64]; + snprintf_irr(buf, 64, "Count: %d, Visible: %d", count, visible); + os::Printer::log(buf); + + lastTime = now; + } + } + } + + + //! Return the bounding box of the entire terrain. + const core::aabbox3d& CTerrainSceneNode::getBoundingBox() const + { + return TerrainData.BoundingBox; + } + + + //! Return the bounding box of a patch + const core::aabbox3d& CTerrainSceneNode::getBoundingBox(s32 patchX, s32 patchZ) const + { + return TerrainData.Patches[patchX * TerrainData.PatchCount + patchZ].BoundingBox; + } + + + //! Gets the meshbuffer data based on a specified Level of Detail. + //! \param mb: A reference to an SMeshBuffer object + //! \param LOD: The Level Of Detail you want the indices from. + void CTerrainSceneNode::getMeshBufferForLOD(IDynamicMeshBuffer& mb, s32 LOD ) const + { + if (!Mesh->getMeshBufferCount()) + return; + + LOD = core::clamp(LOD, 0, TerrainData.MaxLOD - 1); + + const u32 numVertices = Mesh->getMeshBuffer(0)->getVertexCount(); + mb.getVertexBuffer().reallocate(numVertices); + video::S3DVertex2TCoords* vertices = (video::S3DVertex2TCoords*)Mesh->getMeshBuffer(0)->getVertices(); + + for (u32 n=0; ngetIndexBuffer().getType()); + + // calculate the step we take for all patches, since LOD is the same + const s32 step = 1 << LOD; + + // Generate the indices for all patches at the specified LOD + s32 index = 0; + for (s32 i=0; i= TerrainData.CalcPatchSize) // we've hit an edge + { + x = 0; + z += step; + } + } + ++index; + } + } + } + + + //! Gets the indices for a specified patch at a specified Level of Detail. + //! \param mb: A reference to an array of u32 indices. + //! \param patchX: Patch x coordinate. + //! \param patchZ: Patch z coordinate. + //! \param LOD: The level of detail to get for that patch. If -1, then get + //! the CurrentLOD. If the CurrentLOD is set to -1, meaning it's not shown, + //! then it will retrieve the triangles at the highest LOD (0). + //! \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) + return -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) + { + LOD = TerrainData.Patches[patchX * TerrainData.PatchCount + patchZ].CurrentLOD; + } + else + { + getCurrentLODOfPatches(cLODs); + setCurrentLODOfPatches(LOD); + setLODs = true; + } + + if (LOD < 0) + return -2; // Patch not visible, don't generate indices. + + // calculate the step we take for this LOD + const s32 step = 1 << LOD; + + // Generate the indices for the specified patch at the specified LOD + const s32 index = patchX * TerrainData.PatchCount + patchZ; + + s32 x = 0; + s32 z = 0; + + indices.set_used(TerrainData.PatchSize * TerrainData.PatchSize * 6); + + // Loop through patch and generate indices + s32 rv=0; + while (z= TerrainData.CalcPatchSize) // we've hit an edge + { + x = 0; + z += step; + } + } + + if (setLODs) + setCurrentLODOfPatches(cLODs); + + return rv; + } + + + //! Populates an array with the CurrentLOD of each patch. + //! \param LODs: A reference to a core::array to hold the values + //! \return Returns the number of elements in the array + s32 CTerrainSceneNode::getCurrentLODOfPatches(core::array& LODs) const + { + s32 numLODs; + LODs.clear(); + + const s32 count = TerrainData.PatchCount * TerrainData.PatchCount; + for (numLODs = 0; numLODs < count; numLODs++) + LODs.push_back(TerrainData.Patches[numLODs].CurrentLOD); + + return LODs.size(); + } + + + //! Manually sets the LOD of a patch + //! \param patchX: Patch x coordinate. + //! \param patchZ: Patch z coordinate. + //! \param LOD: The level of detail to set the patch to. + void CTerrainSceneNode::setLODOfPatch(s32 patchX, s32 patchZ, s32 LOD) + { + TerrainData.Patches[patchX * TerrainData.PatchCount + patchZ].CurrentLOD = LOD; + } + + + //! Override the default generation of distance thresholds for determining the LOD a patch + //! is rendered at. + bool CTerrainSceneNode::overrideLODDistance(s32 LOD, f64 newDistance) + { + OverrideDistanceThreshold = true; + + if (LOD < 0 || LOD > TerrainData.MaxLOD - 1) + return false; + + TerrainData.LODDistanceThreshold[LOD] = newDistance * newDistance; + + return true; + } + + + //! Creates a planar texture mapping on the terrain + //! \param resolution: resolution of the planar mapping. This is the value + //! specifying the relation between world space and texture coordinate space. + void CTerrainSceneNode::scaleTexture(f32 resolution, f32 resolution2) + { + TCoordScale1 = resolution; + TCoordScale2 = resolution2; + + const f32 resBySize = resolution / (f32)(TerrainData.Size-1); + const f32 res2BySize = resolution2 / (f32)(TerrainData.Size-1); + u32 index = 0; + f32 xval = 0.f; + f32 x2val = 0.f; + for (s32 x=0; xgetVertexBuffer()[index].TCoords.X = 1.f-xval; + RenderBuffer->getVertexBuffer()[index].TCoords.Y = zval; + + if (RenderBuffer->getVertexType()==video::EVT_2TCOORDS) + { + if (resolution2 == 0) + { + ((video::S3DVertex2TCoords&)RenderBuffer->getVertexBuffer()[index]).TCoords2 = RenderBuffer->getVertexBuffer()[index].TCoords; + } + else + { + ((video::S3DVertex2TCoords&)RenderBuffer->getVertexBuffer()[index]).TCoords2.X = 1.f-x2val; + ((video::S3DVertex2TCoords&)RenderBuffer->getVertexBuffer()[index]).TCoords2.Y = z2val; + } + } + + ++index; + zval += resBySize; + z2val += res2BySize; + } + xval += resBySize; + x2val += res2BySize; + } + + RenderBuffer->setDirty(EBT_VERTEX); + } + + + //! used to get the indices when generating index data for patches at varying levels of detail. + u32 CTerrainSceneNode::getIndex(const s32 PatchX, const s32 PatchZ, + const s32 PatchIndex, u32 vX, u32 vZ) const + { + // top border + if (vZ == 0) + { + if (TerrainData.Patches[PatchIndex].Top && + TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Top->CurrentLOD && + (vX % (1 << TerrainData.Patches[PatchIndex].Top->CurrentLOD)) != 0 ) + { + vX -= vX % (1 << TerrainData.Patches[PatchIndex].Top->CurrentLOD); + } + } + else + 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 -= vX % (1 << TerrainData.Patches[PatchIndex].Bottom->CurrentLOD); + } + } + + // left border + 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 -= vZ % (1 << TerrainData.Patches[PatchIndex].Left->CurrentLOD); + } + } + else + 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 -= vZ % (1 << TerrainData.Patches[PatchIndex].Right->CurrentLOD); + } + } + + if (vZ >= (u32)TerrainData.PatchSize) + vZ = TerrainData.CalcPatchSize; + + if (vX >= (u32)TerrainData.PatchSize) + vX = TerrainData.CalcPatchSize; + + return (vZ + ((TerrainData.CalcPatchSize) * PatchZ)) * TerrainData.Size + + (vX + ((TerrainData.CalcPatchSize) * PatchX)); + } + + + //! smooth the terrain + void CTerrainSceneNode::smoothTerrain(IDynamicMeshBuffer* mb, s32 smoothFactor) + { + for (s32 run = 0; run < smoothFactor; ++run) + { + s32 yd = TerrainData.Size; + for (s32 y = 1; y < TerrainData.Size - 1; ++y) + { + for (s32 x = 1; x < TerrainData.Size - 1; ++x) + { + mb->getVertexBuffer()[x + yd].Pos.Y = + (mb->getVertexBuffer()[x-1 + yd].Pos.Y + //left + mb->getVertexBuffer()[x+1 + yd].Pos.Y + //right + mb->getVertexBuffer()[x + yd - TerrainData.Size].Pos.Y + //above + mb->getVertexBuffer()[x + yd + TerrainData.Size].Pos.Y) * 0.25f; //below + } + yd += TerrainData.Size; + } + } + } + + + //! calculate smooth normals + void CTerrainSceneNode::calculateNormals(IDynamicMeshBuffer* mb) + { + s32 count; + core::vector3df a, b, c, t; + + for (s32 x=0; x0 && z>0) + { + a = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z-1].Pos; + b = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z].Pos; + c = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos; + b -= a; + c -= a; + t = b.crossProduct(c); + t.normalize(); + normal += t; + + a = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z-1].Pos; + b = mb->getVertexBuffer()[x*TerrainData.Size+z-1].Pos; + c = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos; + b -= a; + c -= a; + t = b.crossProduct(c); + t.normalize(); + normal += t; + + count += 2; + } + + // top right + if (x>0 && zgetVertexBuffer()[(x-1)*TerrainData.Size+z].Pos; + b = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z+1].Pos; + c = mb->getVertexBuffer()[x*TerrainData.Size+z+1].Pos; + b -= a; + c -= a; + t = b.crossProduct(c); + t.normalize(); + normal += t; + + a = mb->getVertexBuffer()[(x-1)*TerrainData.Size+z].Pos; + b = mb->getVertexBuffer()[x*TerrainData.Size+z+1].Pos; + c = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos; + b -= a; + c -= a; + t = b.crossProduct(c); + t.normalize(); + normal += t; + + count += 2; + } + + // bottom right + if (xgetVertexBuffer()[x*TerrainData.Size+z+1].Pos; + b = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos; + c = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z+1].Pos; + b -= a; + c -= a; + t = b.crossProduct(c); + t.normalize(); + normal += t; + + a = mb->getVertexBuffer()[x*TerrainData.Size+z+1].Pos; + b = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z+1].Pos; + c = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z].Pos; + b -= a; + c -= a; + t = b.crossProduct(c); + t.normalize(); + normal += t; + + count += 2; + } + + // bottom left + if (x0) + { + a = mb->getVertexBuffer()[x*TerrainData.Size+z-1].Pos; + b = mb->getVertexBuffer()[x*TerrainData.Size+z].Pos; + c = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z].Pos; + b -= a; + c -= a; + t = b.crossProduct(c); + t.normalize(); + normal += t; + + a = mb->getVertexBuffer()[x*TerrainData.Size+z-1].Pos; + b = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z].Pos; + c = mb->getVertexBuffer()[(x+1)*TerrainData.Size+z-1].Pos; + b -= a; + c -= a; + t = b.crossProduct(c); + t.normalize(); + normal += t; + + count += 2; + } + + if (count != 0) + { + normal.normalize(); + } + else + { + normal.set(0.0f, 1.0f, 0.0f); + } + + mb->getVertexBuffer()[x * TerrainData.Size + z].Normal = normal; + } + } + } + + + //! create patches, stuff that needs to be done only once for patches goes here. + void CTerrainSceneNode::createPatches() + { + TerrainData.PatchCount = (TerrainData.Size - 1) / (TerrainData.CalcPatchSize); + + if (TerrainData.Patches) + delete [] TerrainData.Patches; + + TerrainData.Patches = new SPatch[TerrainData.PatchCount * TerrainData.PatchCount]; + } + + + //! used to calculate the internal STerrainData structure both at creation and after scaling/position calls. + void CTerrainSceneNode::calculatePatchData() + { + // Reset the Terrains Bounding Box for re-calculation + TerrainData.BoundingBox.reset(RenderBuffer->getPosition(0)); + + for (s32 x = 0; x < TerrainData.PatchCount; ++x) + { + for (s32 z = 0; z < TerrainData.PatchCount; ++z) + { + const s32 index = x * TerrainData.PatchCount + z; + SPatch& patch = TerrainData.Patches[index]; + patch.CurrentLOD = 0; + + const s32 xstart = x*TerrainData.CalcPatchSize; + const s32 xend = xstart+TerrainData.CalcPatchSize; + const s32 zstart = z*TerrainData.CalcPatchSize; + const s32 zend = zstart+TerrainData.CalcPatchSize; + // For each patch, calculate the bounding box (mins and maxes) + patch.BoundingBox.reset(RenderBuffer->getPosition(xstart*TerrainData.Size + zstart)); + + for (s32 xx = xstart; xx <= xend; ++xx) + for (s32 zz = zstart; zz <= zend; ++zz) + patch.BoundingBox.addInternalPoint(RenderBuffer->getVertexBuffer()[xx * TerrainData.Size + zz].Pos); + + // Reconfigure the bounding box of the terrain as a whole + TerrainData.BoundingBox.addInternalBox(patch.BoundingBox); + + // get center of Patch + patch.Center = patch.BoundingBox.getCenter(); + + // Assign Neighbours + // Top + if (x > 0) + patch.Top = &TerrainData.Patches[(x-1) * TerrainData.PatchCount + z]; + else + patch.Top = 0; + + // Bottom + if (x < TerrainData.PatchCount - 1) + patch.Bottom = &TerrainData.Patches[(x+1) * TerrainData.PatchCount + z]; + else + patch.Bottom = 0; + + // Left + if (z > 0) + patch.Left = &TerrainData.Patches[x * TerrainData.PatchCount + z - 1]; + else + patch.Left = 0; + + // Right + if (z < TerrainData.PatchCount - 1) + patch.Right = &TerrainData.Patches[x * TerrainData.PatchCount + z + 1]; + else + patch.Right = 0; + } + } + + // get center of Terrain + TerrainData.Center = TerrainData.BoundingBox.getCenter(); + + // if the default rotation pivot is still being used, update it. + if (UseDefaultRotationPivot) + { + TerrainData.RotationPivot = TerrainData.Center; + } + } + + + //! used to calculate or recalculate the distance thresholds + void CTerrainSceneNode::calculateDistanceThresholds(bool scalechanged) + { + // Only update the LODDistanceThreshold if it's not manually changed + if (!OverrideDistanceThreshold) + { + TerrainData.LODDistanceThreshold.set_used(0); + // Determine new distance threshold for determining what LOD to draw patches at + TerrainData.LODDistanceThreshold.reallocate(TerrainData.MaxLOD); + + const f64 size = TerrainData.PatchSize * TerrainData.PatchSize * + TerrainData.Scale.X * TerrainData.Scale.Z; + for (s32 i=0; i& lodarray) + { + const s32 count = TerrainData.PatchCount * TerrainData.PatchCount; + for (s32 i=0; igetMeshBufferCount()) + return 0; + + core::matrix4 rotMatrix; + 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)); + + f32 height = -FLT_MAX; + 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; + + // offset from integer position + const f32 dx = pos.X - X; + const f32 dz = pos.Z - Z; + + 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; + + height *= TerrainData.Scale.Y; + height += TerrainData.Position.Y; + } + + return height; + } + + + //! Writes attributes of the scene node. + void CTerrainSceneNode::serializeAttributes(io::IAttributes* out, + io::SAttributeReadWriteOptions* options) const + { + ISceneNode::serializeAttributes(out, options); + + out->addString("Heightmap", HeightmapFile.c_str()); + out->addFloat("TextureScale1", TCoordScale1); + out->addFloat("TextureScale2", TCoordScale2); + out->addInt("SmoothFactor", SmoothFactor); + } + + + //! Reads attributes of the scene node. + void CTerrainSceneNode::deserializeAttributes(io::IAttributes* in, + io::SAttributeReadWriteOptions* options) + { + io::path newHeightmap = in->getAttributeAsString("Heightmap"); + f32 tcoordScale1 = in->getAttributeAsFloat("TextureScale1"); + f32 tcoordScale2 = in->getAttributeAsFloat("TextureScale2"); + s32 smoothFactor = in->getAttributeAsInt("SmoothFactor"); + + // set possible new heightmap + + if (newHeightmap.size() != 0 && newHeightmap != HeightmapFile) + { + io::IReadFile* file = FileSystem->createAndOpenFile(newHeightmap.c_str()); + if (file) + { + loadHeightMap(file, video::SColor(255,255,255,255), smoothFactor); + file->drop(); + } + else + os::Printer::log("could not open heightmap", newHeightmap.c_str()); + } + + // set possible new scale + + if (core::equals(tcoordScale1, 0.f)) + tcoordScale1 = 1.0f; + + if (core::equals(tcoordScale2, 0.f)) + tcoordScale2 = 1.0f; + + if (!core::equals(tcoordScale1, TCoordScale1) || + !core::equals(tcoordScale2, TCoordScale2)) + { + scaleTexture(tcoordScale1, tcoordScale2); + } + + ISceneNode::deserializeAttributes(in, options); + } + + + //! Creates a clone of this scene node and its children. + ISceneNode* CTerrainSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager) + { + if (!newParent) + newParent = Parent; + if (!newManager) + newManager = SceneManager; + + CTerrainSceneNode* nb = new CTerrainSceneNode( + newParent, newManager, FileSystem, ID, + 4, ETPS_17, getPosition(), getRotation(), getScale()); + + nb->cloneMembers(this, newManager); + + // instead of cloning the data structures, recreate the terrain. + // (temporary solution) + + // load file + + io::IReadFile* file = FileSystem->createAndOpenFile(HeightmapFile.c_str()); + if (file) + { + nb->loadHeightMap(file, video::SColor(255,255,255,255), 0); + file->drop(); + } + + // scale textures + + nb->scaleTexture(TCoordScale1, TCoordScale2); + + // copy materials + + for (unsigned int m = 0; mgetMeshBufferCount(); ++m) + { + if (nb->Mesh->getMeshBufferCount()>m && + nb->Mesh->getMeshBuffer(m) && + Mesh->getMeshBuffer(m)) + { + nb->Mesh->getMeshBuffer(m)->getMaterial() = + Mesh->getMeshBuffer(m)->getMaterial(); + } + } + + nb->RenderBuffer->getMaterial() = RenderBuffer->getMaterial(); + + // finish + + if ( newParent ) + nb->drop(); + return nb; + } + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_TERRAIN_SCENENODE_ diff --git a/source/Irrlicht/CTerrainSceneNode.h b/source/Irrlicht/CTerrainSceneNode.h new file mode 100644 index 00000000..3e22d69a --- /dev/null +++ b/source/Irrlicht/CTerrainSceneNode.h @@ -0,0 +1,336 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +// The code for the TerrainSceneNode is based on the GeoMipMapSceneNode +// developed by Spintz. He made it available for Irrlicht and allowed it to be +// distributed under this licence. I only modified some parts. A lot of thanks go to him. + +#ifndef __C_TERRAIN_SCENE_NODE_H__ +#define __C_TERRAIN_SCENE_NODE_H__ + +#include "ITerrainSceneNode.h" +#include "IDynamicMeshBuffer.h" +#include "path.h" + +namespace irr +{ +namespace io +{ + class IFileSystem; + class IReadFile; +} +namespace scene +{ + struct SMesh; + class ITextSceneNode; + + //! A scene node for displaying terrain using the geo mip map algorithm. + class CTerrainSceneNode : public ITerrainSceneNode + { + public: + + //! constructor + //! \param parent: The node which this node is a child of. Making this node a child of another node, or + //! making it a parent of another node is yet untested and most likely does not work properly. + //! \param mgr: Pointer to the scene manager. + //! \param id: The id of the node + //! \param maxLOD: The maximum LOD ( Level of Detail ) for the node. + //! \param patchSize: An E_GEOMIPMAP_PATCH_SIZE enumeration defining the size of each patch of the terrain. + //! \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 128x128 and would like + //! your terrain to be 12800x12800 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. + CTerrainSceneNode(ISceneNode* parent, ISceneManager* mgr, io::IFileSystem* fs, s32 id, + s32 maxLOD = 4, E_TERRAIN_PATCH_SIZE patchSize = ETPS_17, + const core::vector3df& position = core::vector3df(0.0f, 0.0f, 0.0f), + const core::vector3df& rotation = core::vector3df(0.0f, 0.0f, 0.0f), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)); + + virtual ~CTerrainSceneNode(); + + //! Initializes the terrain data. Loads the vertices from the heightMapFile. + virtual bool loadHeightMap(io::IReadFile* file, + video::SColor vertexColor = video::SColor ( 255, 255, 255, 255 ), s32 smoothFactor = 0 ) _IRR_OVERRIDE_; + + //! Initializes the terrain data. Loads the vertices from the heightMapFile. + virtual bool loadHeightMapRAW(io::IReadFile* file, s32 bitsPerPixel = 16, + bool signedData=true, bool floatVals=false, s32 width=0, + video::SColor vertexColor = video::SColor ( 255, 255, 255, 255 ), s32 smoothFactor = 0 ) _IRR_OVERRIDE_; + + //! Returns the material based on the zero based index i. This scene node only uses + //! 1 material. + //! \param i: Zero based index i. UNUSED, left in for virtual purposes. + //! \return Returns the single material this scene node uses. + virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_; + + //! Returns amount of materials used by this scene node ( always 1 ) + //! \return Returns current count of materials used by this scene node ( always 1 ) + virtual u32 getMaterialCount() const _IRR_OVERRIDE_; + + //! Gets the last scaling factor applied to the scene node. This value only represents the + //! last scaling factor presented to the node. For instance, if you make create the node + //! with a scale factor of ( 1.0f, 1.0f, 1.0f ) then call setScale ( 50.0f, 5.0f, 50.0f ), + //! then make another call to setScale with the values ( 2.0f, 2.0f, 2.0f ), this will return + //! core::vector3df ( 2.0f, 2.0f, 2.0f ), although the total scaling of the scene node is + //! core::vector3df ( 100.0f, 10.0f, 100.0f ). + //! \return Returns the last scaling factor passed to the scene node. + virtual const core::vector3df& getScale() const _IRR_OVERRIDE_ + { + return TerrainData.Scale; + } + + //! Scales the scene nodes vertices by the vector specified. + //! \param scale: Scaling factor to apply to the node. + virtual void setScale(const core::vector3df& scale) _IRR_OVERRIDE_; + + //! Gets the last rotation factor applied to the scene node. + //! \return Returns the last rotation factor applied to the scene node. + virtual const core::vector3df& getRotation() const _IRR_OVERRIDE_ + { + return TerrainData.Rotation; + } + + //! Rotates the node. This only modifies the relative rotation of the node. + //! \param rotation: New rotation of the node in degrees. + virtual void setRotation(const core::vector3df& rotation) _IRR_OVERRIDE_; + + //! Sets the pivot point for rotation of this node. + //! NOTE: The default for the RotationPivot will be the center of the individual tile. + virtual void setRotationPivot( const core::vector3df& pivot ); + + //! Gets the last positioning vector applied to the scene node. + //! \return Returns the last position vector applied to the scene node. + virtual const core::vector3df& getPosition() const _IRR_OVERRIDE_ + { + return TerrainData.Position; + } + + //! Moves the scene nodes vertices by the vector specified. + //! \param newpos: Vector specifying how much to move each vertex of the scene node. + virtual void setPosition(const core::vector3df& newpos) _IRR_OVERRIDE_; + + //! Updates the scene nodes indices if the camera has moved or rotated by a certain + //! threshold, which can be changed using the SetCameraMovementDeltaThreshold and + //! SetCameraRotationDeltaThreshold functions. This also determines if a given patch + //! for the scene node is within the view frustum and if it's not the indices are not + //! generated for that patch. + virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; + + //! Render the scene node + virtual void render() _IRR_OVERRIDE_; + + //! Return the bounding box of the entire terrain. + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + //! Return the bounding box of a patch + virtual const core::aabbox3d& getBoundingBox(s32 patchX, s32 patchZ) const _IRR_OVERRIDE_; + + //! Return the number of indices currently used to draw the scene node. + virtual u32 getIndexCount() const _IRR_OVERRIDE_ { return IndicesToRender; } + + //! Returns the mesh + virtual IMesh* getMesh() _IRR_OVERRIDE_; + + //! Returns a pointer to the buffer used by the terrain (most users will not need this) + virtual IMeshBuffer* getRenderBuffer() _IRR_OVERRIDE_ { return RenderBuffer; } + + //! Gets the meshbuffer data based on a specified Level of Detail. + //! \param mb: A reference to an IDynamicMeshBuffer object + //! \param LOD: The Level Of Detail you want the indices from. + virtual void getMeshBufferForLOD(IDynamicMeshBuffer& mb, s32 LOD=0) const _IRR_OVERRIDE_; + + //! Gets the indices for a specified patch at a specified Level of Detail. + //! \param indices: A reference to an array of u32 indices. + //! \param patchX: Patch x coordinate. + //! \param patchZ: Patch z coordinate. + //! \param LOD: The level of detail to get for that patch. If -1, then get + //! the CurrentLOD. If the CurrentLOD is set to -1, meaning it's not shown, + //! then it will retrieve the triangles at the highest LOD (0). + //! \return: Number of indices put into the buffer. + virtual s32 getIndicesForPatch(core::array& indices, + s32 patchX, s32 patchZ, s32 LOD=0) _IRR_OVERRIDE_; + + //! Populates an array with the CurrentLOD of each patch. + //! \param LODs: A reference to a core::array to hold the values + //! \return Returns the number of elements in the array + virtual s32 getCurrentLODOfPatches(core::array& LODs) const _IRR_OVERRIDE_; + + //! Manually sets the LOD of a patch + //! \param patchX: Patch x coordinate. + //! \param patchZ: Patch z coordinate. + //! \param LOD: The level of detail to set the patch to. + virtual void setLODOfPatch(s32 patchX, s32 patchZ, s32 LOD=0) _IRR_OVERRIDE_; + + //! Returns center of terrain. + virtual const core::vector3df& getTerrainCenter() const _IRR_OVERRIDE_ + { + return TerrainData.Center; + } + + //! Returns center of terrain. + virtual f32 getHeight( f32 x, f32 y ) const _IRR_OVERRIDE_; + + //! Sets the movement camera threshold which is used to determine when to recalculate + //! indices for the scene node. The default value is 10.0f. + virtual void setCameraMovementDelta(f32 delta) _IRR_OVERRIDE_ + { + CameraMovementDelta = delta; + } + + //! Sets the rotation camera threshold which is used to determine when to recalculate + //! indices for the scene node. The default value is 1.0f. + virtual void setCameraRotationDelta(f32 delta) _IRR_OVERRIDE_ + { + CameraRotationDelta = delta; + } + + //! Sets whether or not the node should dynamically update it its associated selector when + //! the geomipmap data changes. + //! param bVal: Boolean value representing whether or not to update selector dynamically. + //! NOTE: Temporarily disabled while working out issues with DynamicSelectorUpdate + virtual void setDynamicSelectorUpdate(bool bVal ) _IRR_OVERRIDE_ { DynamicSelectorUpdate = false; } + + //! Override the default generation of distance thresholds for determining the LOD a patch + //! is rendered at. If any LOD is overridden, then the scene node will no longer apply + //! scaling factors to these values. If you override these distances and then apply + //! a scale to the scene node, it is your responsibility to update the new distances to + //! work best with your new terrain size. + virtual bool overrideLODDistance( s32 LOD, f64 newDistance ) _IRR_OVERRIDE_; + + //! Scales the two textures + virtual void scaleTexture(f32 scale = 1.0f, f32 scale2 = 0.0f) _IRR_OVERRIDE_; + + //! Force node to use a fixed LOD level at the borders of the terrain. + virtual void setFixedBorderLOD(irr::s32 borderLOD) _IRR_OVERRIDE_ + { + FixedBorderLOD = borderLOD; + } + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ {return ESNT_TERRAIN;} + + //! Writes attributes of the scene node. + virtual void serializeAttributes(io::IAttributes* out, + io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node. + virtual void deserializeAttributes(io::IAttributes* in, + io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! Creates a clone of this scene node and its children. + virtual ISceneNode* clone(ISceneNode* newParent, + ISceneManager* newManager) _IRR_OVERRIDE_; + + private: + friend class CTerrainTriangleSelector; + + struct SPatch + { + SPatch() + : Top(0), Bottom(0), Right(0), Left(0), CurrentLOD(-1) + { + } + + SPatch* Top; + SPatch* Bottom; + SPatch* Right; + SPatch* Left; + s32 CurrentLOD; + core::aabbox3df BoundingBox; + core::vector3df Center; + }; + + struct STerrainData + { + STerrainData(s32 patchSize, s32 maxLOD, const core::vector3df& position, const core::vector3df& rotation, const core::vector3df& scale) + : Patches(0), Size(0), Position(position), Rotation(rotation), + Scale(scale), PatchSize(patchSize), CalcPatchSize(patchSize-1), + PatchCount(0), MaxLOD(maxLOD) + { + } + + SPatch* Patches; + s32 Size; + core::vector3df Position; + core::vector3df Rotation; + core::vector3df RotationPivot; + core::vector3df Scale; + core::vector3df Center; + s32 PatchSize; + s32 CalcPatchSize; + s32 PatchCount; + s32 MaxLOD; + core::aabbox3df BoundingBox; + core::array LODDistanceThreshold; + }; + + void preRenderCalculationsIfNeeded(); + void preRenderLODCalculations(); + void preRenderIndicesCalculations(); + + //! 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; + + //! smooth the terrain + void smoothTerrain(IDynamicMeshBuffer* mb, s32 smoothFactor); + + //! calculate smooth normals + void calculateNormals(IDynamicMeshBuffer* mb); + + //! create patches, stuff that needs to only be done once for patches goes here. + void createPatches(); + + //! calculate the internal STerrainData structure + void calculatePatchData(); + + //! calculate or recalculate the distance thresholds + void calculateDistanceThresholds(bool scalechanged = false); + + //! sets the CurrentLOD of all patches to the specified LOD + void setCurrentLODOfPatches(s32 i); + + //! sets the CurrentLOD of TerrainData patches to the LODs specified in the array + void setCurrentLODOfPatches(const core::array& lodarray); + + //! Apply transformation changes( scale, position, rotation ) + void applyTransformation(); + + STerrainData TerrainData; + SMesh* Mesh; + + IDynamicMeshBuffer *RenderBuffer; + + u32 VerticesToRender; + u32 IndicesToRender; + + bool DynamicSelectorUpdate; + bool OverrideDistanceThreshold; + bool UseDefaultRotationPivot; + bool ForceRecalculation; + s32 FixedBorderLOD; + + core::vector3df OldCameraPosition; + core::vector3df OldCameraRotation; + core::vector3df OldCameraUp; + f32 OldCameraFOV; + f32 CameraMovementDelta; + f32 CameraRotationDelta; + f32 CameraFOVDelta; + + // needed for (de)serialization + f32 TCoordScale1; + f32 TCoordScale2; + s32 SmoothFactor; + io::path HeightmapFile; + io::IFileSystem* FileSystem; + }; + + +} // end namespace scene +} // end namespace irr + +#endif // __C_TERRAIN_SCENE_NODE_H__ + + diff --git a/source/Irrlicht/CTerrainTriangleSelector.cpp b/source/Irrlicht/CTerrainTriangleSelector.cpp new file mode 100644 index 00000000..db544d40 --- /dev/null +++ b/source/Irrlicht/CTerrainTriangleSelector.cpp @@ -0,0 +1,271 @@ +// Copyright (C) 2002-2012 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" + +#ifdef _IRR_COMPILE_WITH_TERRAIN_SCENENODE_ + +#include "CTerrainTriangleSelector.h" +#include "CTerrainSceneNode.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + + +//! constructor +CTerrainTriangleSelector::CTerrainTriangleSelector ( ITerrainSceneNode* node, s32 LOD ) + : SceneNode(node) +{ + #ifdef _DEBUG + setDebugName ("CTerrainTriangleSelector"); + #endif + + setTriangleData(node, LOD); +} + + +//! destructor +CTerrainTriangleSelector::~CTerrainTriangleSelector() +{ + TrianglePatches.TrianglePatchArray.clear(); +} + + +//! Clears and sets triangle data +void CTerrainTriangleSelector::setTriangleData(ITerrainSceneNode* node, s32 LOD) +{ + // Get pointer to the GeoMipMaps vertices + const video::S3DVertex2TCoords* vertices = static_cast(node->getRenderBuffer()->getVertices()); + + // Clear current data + const s32 count = (static_cast(node))->TerrainData.PatchCount; + TrianglePatches.TotalTriangles = 0; + TrianglePatches.NumPatches = count*count; + + TrianglePatches.TrianglePatchArray.reallocate(TrianglePatches.NumPatches); + for (s32 o=0; o indices; + s32 tIndex = 0; + for(s32 x = 0; x < count; ++x ) + { + for(s32 z = 0; z < count; ++z ) + { + TrianglePatches.TrianglePatchArray[tIndex].NumTriangles = 0; + TrianglePatches.TrianglePatchArray[tIndex].Box = node->getBoundingBox( x, z ); + u32 indexCount = node->getIndicesForPatch( indices, x, z, LOD ); + + TrianglePatches.TrianglePatchArray[tIndex].Triangles.reallocate(indexCount/3); + for(u32 i = 0; i < indexCount; i += 3 ) + { + tri.pointA = vertices[indices[i+0]].Pos; + tri.pointB = vertices[indices[i+1]].Pos; + tri.pointC = vertices[indices[i+2]].Pos; + TrianglePatches.TrianglePatchArray[tIndex].Triangles.push_back(tri); + ++TrianglePatches.TrianglePatchArray[tIndex].NumTriangles; + } + + TrianglePatches.TotalTriangles += TrianglePatches.TrianglePatchArray[tIndex].NumTriangles; + ++tIndex; + } + } +} + + +//! Gets all triangles. +void CTerrainTriangleSelector::getTriangles(core::triangle3df* triangles, + s32 arraySize, s32& outTriangleCount, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const +{ + s32 count = TrianglePatches.TotalTriangles; + + if (count > arraySize) + count = arraySize; + + core::matrix4 mat; + + if (transform) + mat = (*transform); + + s32 tIndex = 0; + + for (s32 i=0; i(this); + triRange.SceneNode = SceneNode; + outTriangleInfo->push_back(triRange); + } + + outTriangleCount = tIndex; +} + + +//! Gets all triangles which lie within a specific bounding box. +void CTerrainTriangleSelector::getTriangles(core::triangle3df* triangles, + s32 arraySize, s32& outTriangleCount, + const core::aabbox3d& box, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const +{ + s32 count = TrianglePatches.TotalTriangles; + + if (count > arraySize) + count = arraySize; + + core::matrix4 mat; + + if (transform) + mat = (*transform); + + s32 tIndex = 0; + + for (s32 i=0; i(this); + triRange.SceneNode = SceneNode; + outTriangleInfo->push_back(triRange); + } + + outTriangleCount = tIndex; +} + + +//! Gets all triangles which have or may have contact with a 3d line. +void CTerrainTriangleSelector::getTriangles(core::triangle3df* triangles, + s32 arraySize, s32& outTriangleCount, const core::line3d& line, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const +{ + const s32 count = core::min_((s32)TrianglePatches.TotalTriangles, arraySize); + + core::matrix4 mat; + + if (transform) + mat = (*transform); + + s32 tIndex = 0; + + for (s32 i=0; i(this); + triRange.SceneNode = SceneNode; + outTriangleInfo->push_back(triRange); + } + + outTriangleCount = tIndex; +} + + +//! Returns amount of all available triangles in this selector +s32 CTerrainTriangleSelector::getTriangleCount() const +{ + return TrianglePatches.TotalTriangles; +} + + +ISceneNode* CTerrainTriangleSelector::getSceneNodeForTriangle( + u32 triangleIndex) const +{ + return SceneNode; +} + + +/* Get the number of TriangleSelectors that are part of this one. +Only useful for MetaTriangleSelector others return 1 +*/ +u32 CTerrainTriangleSelector::getSelectorCount() const +{ + return 1; +} + + +/* Get the TriangleSelector based on index based on getSelectorCount. +Only useful for MetaTriangleSelector others return 'this' or 0 +*/ +ITriangleSelector* CTerrainTriangleSelector::getSelector(u32 index) +{ + if (index) + return 0; + else + return this; +} + + +/* Get the TriangleSelector based on index based on getSelectorCount. +Only useful for MetaTriangleSelector others return 'this' or 0 +*/ +const ITriangleSelector* CTerrainTriangleSelector::getSelector(u32 index) const +{ + if (index) + return 0; + else + return this; +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_TERRAIN_SCENENODE_ diff --git a/source/Irrlicht/CTerrainTriangleSelector.h b/source/Irrlicht/CTerrainTriangleSelector.h new file mode 100644 index 00000000..eee29772 --- /dev/null +++ b/source/Irrlicht/CTerrainTriangleSelector.h @@ -0,0 +1,103 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +// The code for the TerrainTriangleSelector is based on the GeoMipMapSelector +// developed by Spintz. He made it available for Irrlicht and allowed it to be +// distributed under this licence. I only modified some parts. A lot of thanks go to him. + +#ifndef __C_TERRAIN_TRIANGLE_SELECTOR_H__ +#define __C_TERRAIN_TRIANGLE_SELECTOR_H__ + +#include "ITriangleSelector.h" +#include "irrArray.h" + +namespace irr +{ +namespace scene +{ + +class ITerrainSceneNode; + +//! Triangle Selector for the TerrainSceneNode +/** The code for the TerrainTriangleSelector is based on the GeoMipMapSelector +developed by Spintz. He made it available for Irrlicht and allowed it to be +distributed under this license. I only modified some parts. A lot of thanks go +to him. +*/ +class CTerrainTriangleSelector : public ITriangleSelector +{ +public: + + //! Constructs a selector based on an ITerrainSceneNode + CTerrainTriangleSelector(ITerrainSceneNode* node, s32 LOD); + + //! Destructor + virtual ~CTerrainTriangleSelector(); + + //! Clears and sets triangle data + virtual void setTriangleData(ITerrainSceneNode* node, s32 LOD); + + //! Gets all triangles. + void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; + + //! Gets all triangles which lie within a specific bounding box. + void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, + const core::aabbox3d& box, const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; + + //! Gets all triangles which have or may have contact with a 3d line. + virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, + s32& outTriangleCount, const core::line3d& line, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; + + //! Returns amount of all available triangles in this selector + virtual s32 getTriangleCount() const _IRR_OVERRIDE_; + + //! Return the scene node associated with a given triangle. + virtual ISceneNode* getSceneNodeForTriangle(u32 triangleIndex) const _IRR_OVERRIDE_; + + // Get the number of TriangleSelectors that are part of this one + virtual u32 getSelectorCount() const _IRR_OVERRIDE_; + + // Get the TriangleSelector based on index based on getSelectorCount + virtual ITriangleSelector* getSelector(u32 index) _IRR_OVERRIDE_; + + // Get the TriangleSelector based on index based on getSelectorCount + virtual const ITriangleSelector* getSelector(u32 index) const _IRR_OVERRIDE_; + +private: + + friend class CTerrainSceneNode; + + struct SGeoMipMapTrianglePatch + { + core::array Triangles; + s32 NumTriangles; + core::aabbox3df Box; + }; + + struct SGeoMipMapTrianglePatches + { + SGeoMipMapTrianglePatches() : + NumPatches(0), TotalTriangles(0) + { + } + + core::array TrianglePatchArray; + s32 NumPatches; + u32 TotalTriangles; + }; + + ITerrainSceneNode* SceneNode; + SGeoMipMapTrianglePatches TrianglePatches; +}; + +} // end namespace scene +} // end namespace irr + + +#endif // __C_TERRAIN_TRIANGLE_SELECTOR_H__ diff --git a/source/Irrlicht/CTextSceneNode.cpp b/source/Irrlicht/CTextSceneNode.cpp new file mode 100644 index 00000000..131c9184 --- /dev/null +++ b/source/Irrlicht/CTextSceneNode.cpp @@ -0,0 +1,521 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CTextSceneNode.h" +#include "ISceneManager.h" +#include "IVideoDriver.h" +#include "ICameraSceneNode.h" +#include "IGUISpriteBank.h" +#include "SMeshBuffer.h" +#include "os.h" + + +namespace irr +{ +namespace scene +{ + + +//! constructor +CTextSceneNode::CTextSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + gui::IGUIFont* font, scene::ISceneCollisionManager* coll, + const core::vector3df& position, const wchar_t* text, + video::SColor color) + : ITextSceneNode(parent, mgr, id, position), Text(text), Color(color), + Font(font), Coll(coll) + +{ + #ifdef _DEBUG + setDebugName("CTextSceneNode"); + #endif + + if (Font) + Font->grab(); + + setAutomaticCulling(scene::EAC_OFF); +} + +//! destructor +CTextSceneNode::~CTextSceneNode() +{ + if (Font) + Font->drop(); +} + +void CTextSceneNode::OnRegisterSceneNode() +{ + if (IsVisible) + SceneManager->registerNodeForRendering(this, ESNRP_TRANSPARENT); + + ISceneNode::OnRegisterSceneNode(); +} + +//! renders the node. +void CTextSceneNode::render() +{ + if (!Font || !Coll) + return; + + core::position2d pos = Coll->getScreenCoordinatesFrom3DPosition(getAbsolutePosition(), + SceneManager->getActiveCamera()); + + core::rect r(pos, core::dimension2d(1,1)); + Font->draw(Text, r, Color, true, true); +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CTextSceneNode::getBoundingBox() const +{ + return Box; +} + +//! sets the text string +void CTextSceneNode::setText(const wchar_t* text) +{ + Text = text; +} + +//! get the text string +const wchar_t* CTextSceneNode::getText() const +{ + return Text.c_str(); +} + +//! sets the color of the text +void CTextSceneNode::setTextColor(video::SColor color) +{ + Color = color; +} + +//! get the color of the text +video::SColor CTextSceneNode::getTextColor() const +{ + return Color; +} + +void CTextSceneNode::setFont(gui::IGUIFont* font) +{ + if ( font != Font ) + { + if ( font ) + font->grab(); + if ( Font ) + Font->drop(); + Font = font; + } +} + +//! Get the font used to draw the text +gui::IGUIFont* CTextSceneNode::getFont() const +{ + return Font; +} + + +//!--------------------------------- CBillboardTextSceneNode ---------------------------------------------- + + +//! constructor +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 ) +: IBillboardTextSceneNode(parent, mgr, id, position), + Font(0), ColorTop(colorTop), ColorBottom(shade_bottom), Mesh(0) +{ + #ifdef _DEBUG + setDebugName("CBillboardTextSceneNode"); + #endif + + Material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + Material.MaterialTypeParam = 1.f / 255.f; + Material.BackfaceCulling = false; + Material.Lighting = false; + Material.ZBuffer = video::ECFN_LESSEQUAL; + Material.ZWriteEnable = video::EZW_OFF; + + if (font) + { + // doesn't support other font types + if (font->getType() == gui::EGFT_BITMAP) + { + Font = (gui::IGUIFontBitmap*)font; + Font->grab(); + + // mesh with one buffer per texture + Mesh = new SMesh(); + for (u32 i=0; igetSpriteBank()->getTextureCount(); ++i) + { + SMeshBuffer *mb = new SMeshBuffer(); + mb->Material = Material; + mb->Material.setTexture(0, Font->getSpriteBank()->getTexture(i)); + Mesh->addMeshBuffer(mb); + mb->drop(); + } + } + else + { + os::Printer::log("Sorry, CBillboardTextSceneNode does not support this font type", ELL_INFORMATION); + } + } + + setText(text); + setSize(size); + + setAutomaticCulling ( scene::EAC_BOX ); +} + + + +CBillboardTextSceneNode::~CBillboardTextSceneNode() +{ + if (Font) + Font->drop(); + + if (Mesh) + Mesh->drop(); + +} + + +//! sets the text string +void CBillboardTextSceneNode::setText(const wchar_t* text) +{ + if ( !Mesh ) + return; + + Text = text; + + Symbol.clear(); + + // clear mesh + for (u32 j=0; j < Mesh->getMeshBufferCount(); ++j) + { + ((SMeshBuffer*)Mesh->getMeshBuffer(j))->Indices.clear(); + ((SMeshBuffer*)Mesh->getMeshBuffer(j))->Vertices.clear(); + } + + if (!Font) + return; + + const core::array< core::rect > &sourceRects = Font->getSpriteBank()->getPositions(); + const core::array< gui::SGUISprite > &sprites = Font->getSpriteBank()->getSprites(); + + f32 dim[2]; + f32 tex[4]; + + u32 i; + for ( i = 0; i != Text.size (); ++i ) + { + SSymbolInfo info; + + u32 spriteno = Font->getSpriteNoFromChar( &text[i] ); + u32 rectno = sprites[spriteno].Frames[0].rectNumber; + u32 texno = sprites[spriteno].Frames[0].textureNumber; + + dim[0] = core::reciprocal ( (f32) Font->getSpriteBank()->getTexture(texno)->getSize().Width ); + dim[1] = core::reciprocal ( (f32) Font->getSpriteBank()->getTexture(texno)->getSize().Height ); + + const core::rect& s = sourceRects[rectno]; + + // add space for letter to buffer + SMeshBuffer* buf = (SMeshBuffer*)Mesh->getMeshBuffer(texno); + u32 firstInd = buf->Indices.size(); + u32 firstVert = buf->Vertices.size(); + buf->Indices.set_used(firstInd + 6); + buf->Vertices.set_used(firstVert + 4); + + tex[0] = (s.LowerRightCorner.X * dim[0]) + 0.5f*dim[0]; // half pixel + 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]); + buf->Vertices[firstVert+3].TCoords.set(tex[3], tex[1]); + + buf->Vertices[firstVert+0].Color = ColorBottom; + buf->Vertices[firstVert+3].Color = ColorBottom; + buf->Vertices[firstVert+1].Color = ColorTop; + buf->Vertices[firstVert+2].Color = ColorTop; + + buf->Indices[firstInd+0] = (u16)firstVert+0; + buf->Indices[firstInd+1] = (u16)firstVert+2; + buf->Indices[firstInd+2] = (u16)firstVert+1; + buf->Indices[firstInd+3] = (u16)firstVert+0; + buf->Indices[firstInd+4] = (u16)firstVert+3; + buf->Indices[firstInd+5] = (u16)firstVert+2; + + wchar_t *tp = 0; + if (i>0) + tp = &Text[i-1]; + + info.Width = (f32)s.getWidth(); + info.bufNo = texno; + info.Kerning = (f32)Font->getKerningWidth(&Text[i], tp); + info.firstInd = firstInd; + info.firstVert = firstVert; + + Symbol.push_back(info); + } +} + +//! get the text string +const wchar_t* CBillboardTextSceneNode::getText() const +{ + return Text.c_str(); +} + +//! pre render event +void CBillboardTextSceneNode::OnAnimate(u32 timeMs) +{ + ISceneNode::OnAnimate(timeMs); + + if (!IsVisible || !Font || !Mesh) + return; + + ICameraSceneNode* camera = SceneManager->getActiveCamera(); + if (!camera) + return; + + // TODO: Risky - if camera is later in the scene-graph then it's not yet updated here + // CBillBoardSceneNode does it different, but maybe real solution would be to enforce cameras to update earlier? + // Maybe we can also unify the code by using a common base-class or having updateMesh functionality in an animator instead. + updateMesh(camera); + + // mesh uses vertices with absolute coordinates so to get a bbox for culling we have to get back to local ones. + BBox = Mesh->getBoundingBox(); + core::matrix4 mat( getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE ); + mat.transformBoxEx(BBox); +} + +const core::aabbox3d& CBillboardTextSceneNode::getTransformedBillboardBoundingBox(const irr::scene::ICameraSceneNode* camera) +{ + updateMesh(camera); + return Mesh->getBoundingBox(); +} + +void CBillboardTextSceneNode::updateMesh(const irr::scene::ICameraSceneNode* camera) +{ + // get text width + f32 textLength = 0.f; + u32 i; + for(i=0; i!=Symbol.size(); ++i) + { + SSymbolInfo &info = Symbol[i]; + textLength += info.Kerning + info.Width; + } + if (textLength<0.0f) + textLength=1.0f; + + //const core::matrix4 &m = camera->getViewFrustum()->Matrices[ video::ETS_VIEW ]; + + // make billboard look to camera + core::vector3df pos = getAbsolutePosition(); + + core::vector3df campos = camera->getAbsolutePosition(); + core::vector3df target = camera->getTarget(); + core::vector3df up = camera->getUpVector(); + core::vector3df view = target - campos; + view.normalize(); + + core::vector3df horizontal = up.crossProduct(view); + if ( horizontal.getLength() == 0 ) + { + horizontal.set(up.Y,up.X,up.Z); + } + + horizontal.normalize(); + core::vector3df space = horizontal; + + horizontal *= 0.5f * Size.Width; + + core::vector3df vertical = horizontal.crossProduct(view); + vertical.normalize(); + vertical *= 0.5f * Size.Height; + + view *= -1.0f; + + // center text + pos += space * (Size.Width * -0.5f); + + for ( i = 0; i!= Symbol.size(); ++i ) + { + SSymbolInfo &info = Symbol[i]; + f32 infw = info.Width / textLength; + f32 infk = info.Kerning / textLength; + f32 w = (Size.Width * infw * 0.5f); + pos += space * w; + + SMeshBuffer* buf = (SMeshBuffer*)Mesh->getMeshBuffer(info.bufNo); + + buf->Vertices[info.firstVert+0].Normal = view; + buf->Vertices[info.firstVert+1].Normal = view; + buf->Vertices[info.firstVert+2].Normal = view; + buf->Vertices[info.firstVert+3].Normal = view; + + buf->Vertices[info.firstVert+0].Pos = pos + (space * w) + vertical; + buf->Vertices[info.firstVert+1].Pos = pos + (space * w) - vertical; + buf->Vertices[info.firstVert+2].Pos = pos - (space * w) - vertical; + buf->Vertices[info.firstVert+3].Pos = pos - (space * w) + vertical; + + pos += space * (Size.Width*infk + w); + } + + // make bounding box + for (i=0; i< Mesh->getMeshBufferCount() ; ++i) + Mesh->getMeshBuffer(i)->recalculateBoundingBox(); + Mesh->recalculateBoundingBox(); +} + +void CBillboardTextSceneNode::OnRegisterSceneNode() +{ + if (IsVisible && Font && Mesh) + { + SceneManager->registerNodeForRendering(this, ESNRP_TRANSPARENT); + ISceneNode::OnRegisterSceneNode(); + } +} + + +//! render +void CBillboardTextSceneNode::render() +{ + if ( !Mesh ) + return; + + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + + // draw + core::matrix4 mat; + driver->setTransform(video::ETS_WORLD, mat); + + for (u32 i = 0; i < Mesh->getMeshBufferCount(); ++i) + { + driver->setMaterial(Mesh->getMeshBuffer(i)->getMaterial()); + driver->drawMeshBuffer(Mesh->getMeshBuffer(i)); + } + + if ( DebugDataVisible & scene::EDS_BBOX ) + { + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + video::SMaterial m; + m.Lighting = false; + driver->setMaterial(m); + driver->draw3DBox(BBox, video::SColor(0,208,195,152)); + } +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CBillboardTextSceneNode::getBoundingBox() const +{ + return BBox; +} + + +//! sets the size of the billboard +void CBillboardTextSceneNode::setSize(const core::dimension2d& size) +{ + Size = size; + + if (Size.Width == 0.0f) + Size.Width = 1.0f; + + if (Size.Height == 0.0f ) + Size.Height = 1.0f; + + //f32 avg = (size.Width + size.Height)/6; + //BBox.MinEdge.set(-avg,-avg,-avg); + //BBox.MaxEdge.set(avg,avg,avg); +} + + +video::SMaterial& CBillboardTextSceneNode::getMaterial(u32 i) +{ + if (Mesh && Mesh->getMeshBufferCount() > i ) + return Mesh->getMeshBuffer(i)->getMaterial(); + else + return Material; +} + + +//! returns amount of materials used by this scene node. +u32 CBillboardTextSceneNode::getMaterialCount() const +{ + if (Mesh) + return Mesh->getMeshBufferCount(); + else + return 0; +} + + +//! gets the size of the billboard +const core::dimension2d& CBillboardTextSceneNode::getSize() const +{ + return Size; +} + +//! Get the font used to draw the text +gui::IGUIFont* CBillboardTextSceneNode::getFont() const +{ + return Font; +} + +//! Set the color of all vertices of the billboard +//! \param overallColor: the color to set +void CBillboardTextSceneNode::setColor(const video::SColor & overallColor) +{ + if ( !Mesh ) + return; + + for ( u32 i = 0; i != Text.size (); ++i ) + { + const SSymbolInfo &info = Symbol[i]; + SMeshBuffer* buf = (SMeshBuffer*)Mesh->getMeshBuffer(info.bufNo); + buf->Vertices[info.firstVert+0].Color = overallColor; + buf->Vertices[info.firstVert+1].Color = overallColor; + buf->Vertices[info.firstVert+2].Color = overallColor; + buf->Vertices[info.firstVert+3].Color = overallColor; + } +} + + +//! Set the color of the top and bottom vertices of the billboard +//! \param topColor: the color to set the top vertices +//! \param bottomColor: the color to set the bottom vertices +void CBillboardTextSceneNode::setColor(const video::SColor & topColor, const video::SColor & bottomColor) +{ + if ( !Mesh ) + return; + + ColorBottom = bottomColor; + ColorTop = topColor; + for ( u32 i = 0; i != Text.size (); ++i ) + { + const SSymbolInfo &info = Symbol[i]; + SMeshBuffer* buf = (SMeshBuffer*)Mesh->getMeshBuffer(info.bufNo); + buf->Vertices[info.firstVert+0].Color = ColorBottom; + buf->Vertices[info.firstVert+3].Color = ColorBottom; + buf->Vertices[info.firstVert+1].Color = ColorTop; + buf->Vertices[info.firstVert+2].Color = ColorTop; + } +} + + +//! Gets the color of the top and bottom vertices of the billboard +//! \param topColor: stores the color of the top vertices +//! \param bottomColor: stores the color of the bottom vertices +void CBillboardTextSceneNode::getColor(video::SColor & topColor, video::SColor & bottomColor) const +{ + topColor = ColorTop; + bottomColor = ColorBottom; +} + + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CTextSceneNode.h b/source/Irrlicht/CTextSceneNode.h new file mode 100644 index 00000000..5b849110 --- /dev/null +++ b/source/Irrlicht/CTextSceneNode.h @@ -0,0 +1,180 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_TEXT_SCENE_NODE_H_INCLUDED__ +#define __C_TEXT_SCENE_NODE_H_INCLUDED__ + +#include "ITextSceneNode.h" +#include "IBillboardTextSceneNode.h" +#include "IGUIFont.h" +#include "IGUIFontBitmap.h" +#include "ISceneCollisionManager.h" +#include "SMesh.h" + +namespace irr +{ +namespace scene +{ + + class ICameraSceneNode; + + class CTextSceneNode : public ITextSceneNode + { + public: + + //! constructor + CTextSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + gui::IGUIFont* font, scene::ISceneCollisionManager* coll, + const core::vector3df& position = core::vector3df(0,0,0), const wchar_t* text=0, + video::SColor color=video::SColor(100,0,0,0)); + + //! destructor + virtual ~CTextSceneNode(); + + virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; + + //! renders the node. + virtual void render() _IRR_OVERRIDE_; + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + //! sets the text string + virtual void setText(const wchar_t* text) _IRR_OVERRIDE_; + + //! get the text string + virtual const wchar_t* getText() const _IRR_OVERRIDE_; + + //! sets the color of the text + virtual void setTextColor(video::SColor color) _IRR_OVERRIDE_; + + //! get the color of the text + virtual video::SColor getTextColor() const _IRR_OVERRIDE_; + + //! set the font used to draw the text + virtual void setFont(gui::IGUIFont* font) _IRR_OVERRIDE_; + + //! Get the font used to draw the text + virtual gui::IGUIFont* getFont() const _IRR_OVERRIDE_; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_TEXT; } + + private: + + core::stringw Text; + video::SColor Color; + gui::IGUIFont* Font; + scene::ISceneCollisionManager* Coll; + core::aabbox3d Box; + }; + + class CBillboardTextSceneNode : public IBillboardTextSceneNode + { + public: + + 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); + + //! destructor + virtual ~CBillboardTextSceneNode(); + + //! sets the vertex positions etc + virtual void OnAnimate(u32 timeMs) _IRR_OVERRIDE_; + + //! registers the node into the transparent pass + virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; + + //! renders the node. + virtual void render() _IRR_OVERRIDE_; + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + //! sets the text string + virtual void setText(const wchar_t* text) _IRR_OVERRIDE_; + + //! get the text string + virtual const wchar_t* getText() const _IRR_OVERRIDE_; + + //! Get the font used to draw the text + virtual gui::IGUIFont* getFont() const _IRR_OVERRIDE_; + + //! sets the size of the billboard + virtual void setSize(const core::dimension2d& size) _IRR_OVERRIDE_; + + //! gets the size of the billboard + virtual const core::dimension2d& getSize() const _IRR_OVERRIDE_; + + virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_; + + //! returns amount of materials used by this scene node. + virtual u32 getMaterialCount() const _IRR_OVERRIDE_; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_BILLBOARD_TEXT; } + + //! Set the color of all vertices of the billboard + //! \param overallColor: the color to set + virtual void setColor(const video::SColor & overallColor) _IRR_OVERRIDE_; + + //! Set the color of the top and bottom vertices of the billboard + //! \param topColor: the color to set the top vertices + //! \param bottomColor: the color to set the bottom vertices + virtual void setColor(const video::SColor & topColor, const video::SColor & bottomColor) _IRR_OVERRIDE_; + + //! Gets the color of the top and bottom vertices of the billboard + //! \param topColor: stores the color of the top vertices + //! \param bottomColor: stores the color of the bottom vertices + virtual void getColor(video::SColor & topColor, video::SColor & bottomColor) const _IRR_OVERRIDE_; + + virtual void setSize(f32 height, f32 bottomEdgeWidth, f32 topEdgeWidth) _IRR_OVERRIDE_ + { + setSize(core::dimension2df(bottomEdgeWidth, height)); + } + + virtual void getSize(f32& height, f32& bottomEdgeWidth, f32& topEdgeWidth) const _IRR_OVERRIDE_ + { + height = Size.Height; + bottomEdgeWidth = Size.Width; + topEdgeWidth = Size.Width; + } + + virtual const core::aabbox3d& getTransformedBillboardBoundingBox(const irr::scene::ICameraSceneNode* camera) _IRR_OVERRIDE_; + + protected: + void updateMesh(const irr::scene::ICameraSceneNode* camera); + + private: + + core::stringw Text; + gui::IGUIFontBitmap* Font; + + core::dimension2d Size; + core::aabbox3d BBox; + video::SMaterial Material; + + video::SColor ColorTop; + video::SColor ColorBottom; + struct SSymbolInfo + { + u32 bufNo; + f32 Width; + f32 Kerning; + u32 firstInd; + u32 firstVert; + }; + + core::array < SSymbolInfo > Symbol; + + SMesh *Mesh; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CTimer.h b/source/Irrlicht/CTimer.h new file mode 100644 index 00000000..caf2bf5f --- /dev/null +++ b/source/Irrlicht/CTimer.h @@ -0,0 +1,107 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_IRR_C_TIMER_H_INCLUDED__ +#define __C_IRR_C_TIMER_H_INCLUDED__ + +#include "ITimer.h" +#include "os.h" + +namespace irr +{ + //! Device independent implementation of the timer + class CTimer : public ITimer + { + public: + + CTimer(bool usePerformanceTimer=true) + { + os::Timer::initTimer(usePerformanceTimer); + } + + //! Returns current real time in milliseconds of the system. + /** This value does not start with 0 when the application starts. + For example in one implementation the value returned could be the + amount of milliseconds which have elapsed since the system was started. */ + virtual u32 getRealTime() const _IRR_OVERRIDE_ + { + return os::Timer::getRealTime(); + } + + //! Get current time and date in calendar form + virtual RealTimeDate getRealTimeAndDate() const _IRR_OVERRIDE_ + { + return os::Timer::getRealTimeAndDate(); + } + + //! Returns current virtual time in milliseconds. + /** This value starts with 0 and can be manipulated using setTime(), stopTimer(), + startTimer(), etc. This value depends on the set speed of the timer if the timer + is stopped, etc. If you need the system time, use getRealTime() */ + virtual u32 getTime() const _IRR_OVERRIDE_ + { + return os::Timer::getTime(); + } + + //! sets current virtual time + virtual void setTime(u32 time) _IRR_OVERRIDE_ + { + os::Timer::setTime(time); + } + + //! Stops the game timer. + /** The timer is reference counted, which means everything which calls + stopTimer() will also have to call startTimer(), otherwise the timer may not start/stop + corretly again. */ + virtual void stop() _IRR_OVERRIDE_ + { + os::Timer::stopTimer(); + } + + //! Starts the game timer. + /** The timer is reference counted, which means everything which calls + stopTimer() will also have to call startTimer(), otherwise the timer may not start/stop + corretly again. */ + virtual void start() _IRR_OVERRIDE_ + { + os::Timer::startTimer(); + } + + //! Sets the speed of the timer + /** The speed is the factor with which the time is running faster or slower then the + real system time. */ + virtual void setSpeed(f32 speed = 1.0f) _IRR_OVERRIDE_ + { + os::Timer::setSpeed(speed); + } + + //! Returns current speed of the timer + /** The speed is the factor with which the time is running faster or slower then the + real system time. */ + virtual f32 getSpeed() const _IRR_OVERRIDE_ + { + return os::Timer::getSpeed(); + } + + //! Returns if game timer is currently stopped + virtual bool isStopped() const _IRR_OVERRIDE_ + { + bool ret = os::Timer::isStopped(); + return ret; + } + + //! Advances the virtual time + /** Makes the virtual timer update the time value based on the real time. This is + called automatically when calling IrrlichtDevice::run(), but you can call it manually + if you don't use this method. */ + virtual void tick() _IRR_OVERRIDE_ + { + os::Timer::tick(); + } + }; + +} // end namespace + +#endif + diff --git a/source/Irrlicht/CTriangleBBSelector.cpp b/source/Irrlicht/CTriangleBBSelector.cpp new file mode 100644 index 00000000..b30f04e1 --- /dev/null +++ b/source/Irrlicht/CTriangleBBSelector.cpp @@ -0,0 +1,89 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CTriangleBBSelector.h" +#include "ISceneNode.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CTriangleBBSelector::CTriangleBBSelector(ISceneNode* node) +: CTriangleSelector(node) +{ + #ifdef _DEBUG + setDebugName("CTriangleBBSelector"); + #endif + + Triangles.set_used(12); // a box has 12 triangles. +} + +//! Gets all triangles. +void CTriangleBBSelector::getTriangles(core::triangle3df* triangles, + s32 arraySize, s32& outTriangleCount, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const +{ + fillTriangles(); + + // call parent + CTriangleSelector::getTriangles(triangles, arraySize, outTriangleCount, transform, useNodeTransform, outTriangleInfo); +} + +void CTriangleBBSelector::getTriangles(core::triangle3df* triangles, + s32 arraySize, s32& outTriangleCount, + const core::aabbox3d& box, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const +{ + fillTriangles(); + return CTriangleSelector::getTriangles(triangles, arraySize, outTriangleCount, box, transform, useNodeTransform, outTriangleInfo); +} + +void CTriangleBBSelector::getTriangles(core::triangle3df* triangles, + s32 arraySize, s32& outTriangleCount, + const core::line3d& line, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const +{ + fillTriangles(); + return CTriangleSelector::getTriangles(triangles, arraySize, outTriangleCount, line, transform, useNodeTransform, outTriangleInfo); +} + +void CTriangleBBSelector::fillTriangles() const +{ + if (SceneNode) + { + // construct triangles + const core::aabbox3d& box = SceneNode->getBoundingBox(); + BoundingBox = box; + core::vector3df edges[8]; + box.getEdges(edges); + + // yeah, not really const... Triangles are mutable + Triangles[0].set( edges[3], edges[0], edges[2]); + Triangles[1].set( edges[3], edges[1], edges[0]); + + Triangles[2].set( edges[3], edges[2], edges[7]); + Triangles[3].set( edges[7], edges[2], edges[6]); + + Triangles[4].set( edges[7], edges[6], edges[4]); + Triangles[5].set( edges[5], edges[7], edges[4]); + + Triangles[6].set( edges[5], edges[4], edges[0]); + Triangles[7].set( edges[5], edges[0], edges[1]); + + Triangles[8].set( edges[1], edges[3], edges[7]); + Triangles[9].set( edges[1], edges[7], edges[5]); + + Triangles[10].set(edges[0], edges[6], edges[2]); + Triangles[11].set(edges[0], edges[4], edges[6]); + } +} + + +} // end namespace scene +} // end namespace irr diff --git a/source/Irrlicht/CTriangleBBSelector.h b/source/Irrlicht/CTriangleBBSelector.h new file mode 100644 index 00000000..b4444a33 --- /dev/null +++ b/source/Irrlicht/CTriangleBBSelector.h @@ -0,0 +1,49 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_TRIANGLE_BB_SELECTOR_H_INCLUDED__ +#define __C_TRIANGLE_BB_SELECTOR_H_INCLUDED__ + +#include "CTriangleSelector.h" + +namespace irr +{ +namespace scene +{ + +//! Stupid triangle selector without optimization +class CTriangleBBSelector : public CTriangleSelector +{ +public: + + //! Constructs a selector based on a mesh + CTriangleBBSelector(ISceneNode* node); + + //! Gets all triangles. + virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; + + //! Gets all triangles which lie within a specific bounding box. + virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, + const core::aabbox3d& box, const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; + + //! Gets all triangles which have or may have contact with a 3d line. + virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, + s32& outTriangleCount, const core::line3d& line, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; + +protected: + void fillTriangles() const; + +}; + +} // end namespace scene +} // end namespace irr + + +#endif + diff --git a/source/Irrlicht/CTriangleSelector.cpp b/source/Irrlicht/CTriangleSelector.cpp new file mode 100644 index 00000000..0342b349 --- /dev/null +++ b/source/Irrlicht/CTriangleSelector.cpp @@ -0,0 +1,508 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CTriangleSelector.h" +#include "ISceneNode.h" +#include "IMeshBuffer.h" +#include "IAnimatedMeshSceneNode.h" +#include "SSkinMeshBuffer.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CTriangleSelector::CTriangleSelector(ISceneNode* node) +: SceneNode(node), MeshBuffer(0), MaterialIndex(0), AnimatedNode(0), LastMeshFrame(0) +{ + #ifdef _DEBUG + setDebugName("CTriangleSelector"); + #endif + + BoundingBox.reset(0.f, 0.f, 0.f); +} + + +//! constructor +CTriangleSelector::CTriangleSelector(const core::aabbox3d& box, ISceneNode* node) +: SceneNode(node), MeshBuffer(0), MaterialIndex(0), AnimatedNode(0), LastMeshFrame(0) +{ + #ifdef _DEBUG + setDebugName("CTriangleSelector"); + #endif + + BoundingBox=box; + // TODO +} + + +//! constructor +CTriangleSelector::CTriangleSelector(const IMesh* mesh, ISceneNode* node, bool separateMeshbuffers) +: SceneNode(node), MeshBuffer(0), MaterialIndex(0), AnimatedNode(0), LastMeshFrame(0) +{ + #ifdef _DEBUG + setDebugName("CTriangleSelector"); + #endif + + createFromMesh(mesh, separateMeshbuffers); +} + +CTriangleSelector::CTriangleSelector(const IMeshBuffer* meshBuffer, irr::u32 materialIndex, ISceneNode* node) + : SceneNode(node), MeshBuffer(meshBuffer), MaterialIndex(materialIndex), AnimatedNode(0), LastMeshFrame(0) +{ + #ifdef _DEBUG + setDebugName("CTriangleSelector"); + #endif + + createFromMeshBuffer(meshBuffer); +} + +CTriangleSelector::CTriangleSelector(IAnimatedMeshSceneNode* node, bool separateMeshbuffers) +: SceneNode(node), AnimatedNode(node), LastMeshFrame(0) +{ + #ifdef _DEBUG + setDebugName("CTriangleSelector"); + #endif + + if (!AnimatedNode) + return; + + IAnimatedMesh* animatedMesh = AnimatedNode->getMesh(); + if (!animatedMesh) + return; + + LastMeshFrame = (u32)AnimatedNode->getFrameNr(); + IMesh* mesh = animatedMesh->getMesh(LastMeshFrame); + + if (mesh) + createFromMesh(mesh, separateMeshbuffers); +} + + +void CTriangleSelector::createFromMesh(const IMesh* mesh, bool createBufferRanges) +{ + BufferRanges.clear(); + Triangles.clear(); + + const u32 cnt = mesh->getMeshBufferCount(); + u32 totalFaceCount = 0; + for (u32 j=0; jgetMeshBuffer(j); + range.MaterialIndex = j; + range.RangeSize = range.MeshBuffer->getIndexCount() / 3; + + if ( createBufferRanges ) + { + range.RangeStart = totalFaceCount; + + BufferRanges.push_back(range); + } + + totalFaceCount += range.RangeSize; + } + Triangles.set_used(totalFaceCount); + + updateFromMesh(mesh); +} + +void CTriangleSelector::createFromMeshBuffer(const IMeshBuffer* meshBuffer) +{ + BufferRanges.clear(); + Triangles.clear(); + + if ( meshBuffer ) + { + Triangles.set_used(meshBuffer->getIndexCount() / 3); + } + + updateFromMeshBuffer(meshBuffer); +} + +template +static void updateTriangles(u32& triangleCount, core::array& triangles, u32 idxCnt, const TIndex* indices, const u8* vertices, u32 vertexPitch, const core::matrix4* bufferTransform) +{ + if ( bufferTransform ) + { + for (u32 index = 0; index < idxCnt; index += 3) + { + core::triangle3df& tri = triangles[triangleCount++]; + bufferTransform->transformVect( tri.pointA, (*reinterpret_cast(&vertices[indices[index + 0]*vertexPitch])).Pos ); + bufferTransform->transformVect( tri.pointB, (*reinterpret_cast(&vertices[indices[index + 1]*vertexPitch])).Pos ); + bufferTransform->transformVect( tri.pointC, (*reinterpret_cast(&vertices[indices[index + 2]*vertexPitch])).Pos ); + } + } + else + { + for (u32 index = 0; index < idxCnt; index += 3) + { + core::triangle3df& tri = triangles[triangleCount++]; + tri.pointA = (*reinterpret_cast(&vertices[indices[index + 0]*vertexPitch])).Pos; + tri.pointB = (*reinterpret_cast(&vertices[indices[index + 1]*vertexPitch])).Pos; + tri.pointC = (*reinterpret_cast(&vertices[indices[index + 2]*vertexPitch])).Pos; + } + } +} + +void CTriangleSelector::updateFromMesh(const IMesh* mesh) const +{ + if (!mesh) + return; + + bool skinnnedMesh = mesh->getMeshType() == EAMT_SKINNED; + u32 meshBuffers = mesh->getMeshBufferCount(); + u32 triangleCount = 0; + + for (u32 i = 0; i < meshBuffers; ++i) + { + IMeshBuffer* buf = mesh->getMeshBuffer(i); + u32 idxCnt = buf->getIndexCount(); + u32 vertexPitch = getVertexPitchFromType(buf->getVertexType()); + u8* vertices = (u8*)buf->getVertices(); + + const core::matrix4* bufferTransform = 0; + if ( skinnnedMesh ) + { + bufferTransform = &(((scene::SSkinMeshBuffer*)buf)->Transformation); + if ( bufferTransform->isIdentity() ) + bufferTransform = 0; + } + + switch ( buf->getIndexType() ) + { + case video::EIT_16BIT: + { + const u16* indices = buf->getIndices(); + updateTriangles(triangleCount, Triangles, idxCnt, indices, vertices, vertexPitch, bufferTransform); + } + break; + case video::EIT_32BIT: + { + const u32* indices = (u32*)buf->getIndices(); + updateTriangles(triangleCount, Triangles, idxCnt, indices, vertices, vertexPitch, bufferTransform); + } + break; + } + } + + // Update bounding box + updateBoundingBox(); +} + +void CTriangleSelector::updateFromMeshBuffer(const IMeshBuffer* meshBuffer) const +{ + if ( !meshBuffer ) + return; + + u32 idxCnt = meshBuffer->getIndexCount(); + u32 vertexPitch = getVertexPitchFromType(meshBuffer->getVertexType()); + u8* vertices = (u8*)meshBuffer->getVertices(); + u32 triangleCount = 0; + switch ( meshBuffer->getIndexType() ) + { + case video::EIT_16BIT: + { + const u16* indices = meshBuffer->getIndices(); + updateTriangles(triangleCount, Triangles, idxCnt, indices, vertices, vertexPitch, 0); + } + break; + case video::EIT_32BIT: + { + const u32* indices = (u32*)meshBuffer->getIndices(); + updateTriangles(triangleCount, Triangles, idxCnt, indices, vertices, vertexPitch, 0); + } + break; + } +} + +void CTriangleSelector::updateBoundingBox() const +{ + if ( !Triangles.empty() ) + { + BoundingBox.reset( Triangles[0].pointA ); + for (u32 i=0; i < Triangles.size(); ++i) + { + const core::triangle3df& tri = Triangles[i]; + BoundingBox.addInternalPoint(tri.pointA); + BoundingBox.addInternalPoint(tri.pointB); + BoundingBox.addInternalPoint(tri.pointC); + } + } + else + { + BoundingBox.reset(0.f, 0.f, 0.f); + } +} + +void CTriangleSelector::update(void) const +{ + if (!AnimatedNode) + return; //< harmless no-op + + const u32 currentFrame = (u32)AnimatedNode->getFrameNr(); + if (currentFrame == LastMeshFrame) + return; //< Nothing to do + + LastMeshFrame = currentFrame; + IAnimatedMesh * animatedMesh = AnimatedNode->getMesh(); + + if (animatedMesh) + { + IMesh * mesh = animatedMesh->getMesh(LastMeshFrame); + + if (mesh) + updateFromMesh(mesh); + } +} + + +//! Gets all triangles. +void CTriangleSelector::getTriangles(core::triangle3df* triangles, + s32 arraySize, s32& outTriangleCount, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const +{ + // Update my triangles if necessary + update(); + + u32 cnt = Triangles.size(); + if (cnt > (u32)arraySize) + cnt = (u32)arraySize; + + core::matrix4 mat; + if (transform) + mat = *transform; + if (SceneNode&&useNodeTransform) + mat *= SceneNode->getAbsoluteTransformation(); + + for (u32 i=0; i(this); + triRange.SceneNode = SceneNode; + triRange.MeshBuffer = MeshBuffer; + triRange.MaterialIndex = MaterialIndex; + outTriangleInfo->push_back(triRange); + } + else + { + irr::u32 rangeIndex = 0; + for (u32 i=0; i= (BufferRanges[rangeIndex].RangeStart + BufferRanges[rangeIndex].RangeSize) ) + ++rangeIndex; + + SCollisionTriangleRange triRange; + + triRange.MaterialIndex = BufferRanges[rangeIndex].MaterialIndex; + triRange.MeshBuffer = BufferRanges[rangeIndex].MeshBuffer; + triRange.RangeStart = BufferRanges[rangeIndex].RangeStart; + triRange.RangeSize = core::min_( cnt-BufferRanges[rangeIndex].RangeStart, BufferRanges[rangeIndex].RangeSize); + triRange.Selector = const_cast(this); + triRange.SceneNode = SceneNode; + outTriangleInfo->push_back(triRange); + + i += triRange.RangeSize; + } + } + } + + outTriangleCount = cnt; +} + + +//! Gets all triangles which lie within a specific bounding box. +void CTriangleSelector::getTriangles(core::triangle3df* triangles, + s32 arraySize, s32& outTriangleCount, + const core::aabbox3d& box, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const +{ + // Update my triangles if necessary + update(); + + core::matrix4 mat(core::matrix4::EM4CONST_NOTHING); + core::aabbox3df tBox(box); + + if (SceneNode && useNodeTransform) + { + if ( SceneNode->getAbsoluteTransformation().getInverse(mat) ) + mat.transformBoxEx(tBox); + else + { + // TODO: else is not yet handled optimally. + // If a node has an axis scaled to 0 we return all triangles without any check + return getTriangles(triangles, arraySize, outTriangleCount, + transform, useNodeTransform, outTriangleInfo ); + } + } + if (transform) + mat = *transform; + else + mat.makeIdentity(); + if (SceneNode && useNodeTransform) + mat *= SceneNode->getAbsoluteTransformation(); + + outTriangleCount = 0; + + if (!tBox.intersectsWithBox(BoundingBox)) + return; + + s32 triangleCount = 0; + const u32 cnt = Triangles.size(); + + if ( outTriangleInfo && !BufferRanges.empty() ) + { + irr::u32 activeRange = 0; + SCollisionTriangleRange triRange; + triRange.Selector = const_cast(this); + triRange.SceneNode = SceneNode; + triRange.RangeStart = triangleCount; + triRange.MeshBuffer = BufferRanges[activeRange].MeshBuffer; + triRange.MaterialIndex = BufferRanges[activeRange].MaterialIndex; + + for (u32 i=0; i= BufferRanges[activeRange].RangeStart + BufferRanges[activeRange].RangeSize ) + { + triRange.RangeSize = triangleCount-triRange.RangeStart; + if ( triRange.RangeSize > 0 ) + outTriangleInfo->push_back(triRange); + + ++activeRange; + triRange.RangeStart = triangleCount; + triRange.MeshBuffer = BufferRanges[activeRange].MeshBuffer; + triRange.MaterialIndex = BufferRanges[activeRange].MaterialIndex; + } + + triangles[triangleCount] = Triangles[i]; + mat.transformVect(triangles[triangleCount].pointA); + mat.transformVect(triangles[triangleCount].pointB); + mat.transformVect(triangles[triangleCount].pointC); + + ++triangleCount; + + if (triangleCount == arraySize) + break; + } + triRange.RangeSize = triangleCount-triRange.RangeStart; + if ( triRange.RangeSize > 0 ) + outTriangleInfo->push_back(triRange); + } + else + { + for (u32 i=0; i(this); + triRange.SceneNode = SceneNode; + triRange.MeshBuffer = MeshBuffer; + triRange.MaterialIndex = MaterialIndex; + outTriangleInfo->push_back(triRange); + } + } + + outTriangleCount = triangleCount; +} + + +//! Gets all triangles which have or may have contact with a 3d line. +void CTriangleSelector::getTriangles(core::triangle3df* triangles, + s32 arraySize, s32& outTriangleCount, + const core::line3d& line, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const +{ + // Update my triangles if necessary + update(); + + core::aabbox3d box(line.start); + box.addInternalPoint(line.end); + + // TODO: Could be optimized for line a little bit more. + getTriangles(triangles, arraySize, outTriangleCount, + box, transform, useNodeTransform, outTriangleInfo); +} + + +//! Returns amount of all available triangles in this selector +s32 CTriangleSelector::getTriangleCount() const +{ + return Triangles.size(); +} + + +/* Get the number of TriangleSelectors that are part of this one. +Only useful for MetaTriangleSelector others return 1 +*/ +u32 CTriangleSelector::getSelectorCount() const +{ + return 1; +} + + +/* Get the TriangleSelector based on index based on getSelectorCount. +Only useful for MetaTriangleSelector others return 'this' or 0 +*/ +ITriangleSelector* CTriangleSelector::getSelector(u32 index) +{ + if (index) + return 0; + else + return this; +} + + +/* Get the TriangleSelector based on index based on getSelectorCount. +Only useful for MetaTriangleSelector others return 'this' or 0 +*/ +const ITriangleSelector* CTriangleSelector::getSelector(u32 index) const +{ + if (index) + return 0; + else + return this; +} + + +} // end namespace scene +} // end namespace irr diff --git a/source/Irrlicht/CTriangleSelector.h b/source/Irrlicht/CTriangleSelector.h new file mode 100644 index 00000000..01acacff --- /dev/null +++ b/source/Irrlicht/CTriangleSelector.h @@ -0,0 +1,109 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_TRIANGLE_SELECTOR_H_INCLUDED__ +#define __C_TRIANGLE_SELECTOR_H_INCLUDED__ + +#include "ITriangleSelector.h" +#include "IMesh.h" +#include "irrArray.h" +#include "aabbox3d.h" + +namespace irr +{ +namespace scene +{ + +class ISceneNode; +class IAnimatedMeshSceneNode; + +//! Stupid triangle selector without optimization +class CTriangleSelector : public ITriangleSelector +{ +public: + + //! Constructs a selector based on a mesh + CTriangleSelector(ISceneNode* node); + + //! Constructs a selector based on a mesh + CTriangleSelector(const IMesh* mesh, ISceneNode* node, bool separateMeshbuffers); + + //! Constructs a selector based on a meshbuffer + CTriangleSelector(const IMeshBuffer* meshBuffer, irr::u32 materialIndex, ISceneNode* node); + + //! Constructs a selector based on an animated mesh scene node + //!\param node An animated mesh scene node, which must have a valid mesh + CTriangleSelector(IAnimatedMeshSceneNode* node, bool separateMeshbuffers); + + //! Constructs a selector based on a bounding box + CTriangleSelector(const core::aabbox3d& box, ISceneNode* node); + + //! Gets all triangles. + virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; + + //! Gets all triangles which lie within a specific bounding box. + virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, + const core::aabbox3d& box, const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; + + //! Gets all triangles which have or may have contact with a 3d line. + virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, + s32& outTriangleCount, const core::line3d& line, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; + + //! Returns amount of all available triangles in this selector + virtual s32 getTriangleCount() const _IRR_OVERRIDE_; + + //! Return the scene node associated with a given triangle. + virtual ISceneNode* getSceneNodeForTriangle(u32 triangleIndex) const _IRR_OVERRIDE_ { return SceneNode; } + + // Get the number of TriangleSelectors that are part of this one + virtual u32 getSelectorCount() const _IRR_OVERRIDE_; + + // Get the TriangleSelector based on index based on getSelectorCount + virtual ITriangleSelector* getSelector(u32 index) _IRR_OVERRIDE_; + + // Get the TriangleSelector based on index based on getSelectorCount + virtual const ITriangleSelector* getSelector(u32 index) const _IRR_OVERRIDE_; + +protected: + //! Create from a mesh + virtual void createFromMesh(const IMesh* mesh, bool createBufferRanges); + + //! Create from a meshbuffer + virtual void createFromMeshBuffer(const IMeshBuffer* meshBuffer); + + //! Update when the mesh has changed + virtual void updateFromMesh(const IMesh* mesh) const; + + //! Update when the meshbuffer has changed + virtual void updateFromMeshBuffer(const IMeshBuffer* meshBuffer) const; + + //! Update bounding box from triangles + void updateBoundingBox() const; + + //! Update the triangle selector, which will only have an effect if it + //! was built from an animated mesh and that mesh's frame has changed + //! since the last time it was updated. + virtual void update(void) const; + + irr::core::array BufferRanges; + + ISceneNode* SceneNode; + mutable core::array Triangles; // (mutable for CTriangleBBSelector) + mutable core::aabbox3df BoundingBox; // Allows for trivial rejection + + const IMeshBuffer* MeshBuffer; // non-zero when the selector is for a single meshbuffer + irr::u32 MaterialIndex; // Only set when MeshBuffer is non-zero + IAnimatedMeshSceneNode* AnimatedNode; + mutable u32 LastMeshFrame; +}; + +} // end namespace scene +} // end namespace irr + +#endif diff --git a/source/Irrlicht/CVideoModeList.cpp b/source/Irrlicht/CVideoModeList.cpp new file mode 100644 index 00000000..9ae7fb27 --- /dev/null +++ b/source/Irrlicht/CVideoModeList.cpp @@ -0,0 +1,132 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CVideoModeList.h" +#include "irrMath.h" + +namespace irr +{ +namespace video +{ + +//! constructor +CVideoModeList::CVideoModeList() +{ + #ifdef _DEBUG + setDebugName("CVideoModeList"); + #endif + + Desktop.depth = 0; + Desktop.size = core::dimension2d(0,0); +} + + +void CVideoModeList::setDesktop(s32 desktopDepth, const core::dimension2d& desktopSize) +{ + Desktop.depth = desktopDepth; + Desktop.size = desktopSize; +} + + +//! Gets amount of video modes in the list. +s32 CVideoModeList::getVideoModeCount() const +{ + return (s32)VideoModes.size(); +} + + +//! Returns the screen size of a video mode in pixels. +core::dimension2d CVideoModeList::getVideoModeResolution(s32 modeNumber) const +{ + if (modeNumber < 0 || modeNumber > (s32)VideoModes.size()) + return core::dimension2d(0,0); + + return VideoModes[modeNumber].size; +} + + +core::dimension2d CVideoModeList::getVideoModeResolution( + const core::dimension2d& minSize, + const core::dimension2d& maxSize) const +{ + u32 best=VideoModes.size(); + // if only one or no mode + if (best<2) + return getVideoModeResolution(0); + + u32 i; + for (i=0; i=minSize.Width && + VideoModes[i].size.Height>=minSize.Height && + VideoModes[i].size.Width<=maxSize.Width && + VideoModes[i].size.Height<=maxSize.Height) + best=i; + } + // we take the last one found, the largest one fitting + if (best (s32)VideoModes.size()) + return 0; + + return VideoModes[modeNumber].depth; +} + + +//! Returns current desktop screen resolution. +const core::dimension2d& CVideoModeList::getDesktopResolution() const +{ + return Desktop.size; +} + + +//! Returns the pixel depth of a video mode in bits. +s32 CVideoModeList::getDesktopDepth() const +{ + return Desktop.depth; +} + + +//! adds a new mode to the list +void CVideoModeList::addMode(const core::dimension2d& size, s32 depth) +{ + SVideoMode m; + m.depth = depth; + m.size = size; + + for (u32 i=0; i getVideoModeResolution(s32 modeNumber) const _IRR_OVERRIDE_; + + //! Returns the screen size of an optimal video mode in pixels. + virtual core::dimension2d getVideoModeResolution(const core::dimension2d& minSize, const core::dimension2d& maxSize) const _IRR_OVERRIDE_; + + //! Returns the pixel depth of a video mode in bits. + virtual s32 getVideoModeDepth(s32 modeNumber) const _IRR_OVERRIDE_; + + //! Returns current desktop screen resolution. + virtual const core::dimension2d& getDesktopResolution() const _IRR_OVERRIDE_; + + //! Returns the pixel depth of a video mode in bits. + virtual s32 getDesktopDepth() const _IRR_OVERRIDE_; + + //! adds a new mode to the list + void addMode(const core::dimension2d& size, s32 depth); + + void setDesktop(s32 desktopDepth, const core::dimension2d& desktopSize); + + private: + + struct SVideoMode + { + core::dimension2d size; + s32 depth; + + bool operator==(const SVideoMode& other) const + { + return size == other.size && depth == other.depth; + } + + bool operator <(const SVideoMode& other) const + { + return (size.Width < other.size.Width || + (size.Width == other.size.Width && + size.Height < other.size.Height) || + (size.Width == other.size.Width && + size.Height == other.size.Height && + depth < other.depth)); + } + }; + + core::array VideoModes; + SVideoMode Desktop; + }; + +} // end namespace video +} // end namespace irr + + +#endif + diff --git a/source/Irrlicht/CVolumeLightSceneNode.cpp b/source/Irrlicht/CVolumeLightSceneNode.cpp new file mode 100644 index 00000000..720c3607 --- /dev/null +++ b/source/Irrlicht/CVolumeLightSceneNode.cpp @@ -0,0 +1,196 @@ +// Copyright (C) 2007-2012 Dean Wadsworth +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CVolumeLightSceneNode.h" +#include "IVideoDriver.h" +#include "ISceneManager.h" +#include "S3DVertex.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CVolumeLightSceneNode::CVolumeLightSceneNode(ISceneNode* parent, ISceneManager* mgr, + s32 id, const u32 subdivU, const u32 subdivV, + const video::SColor foot, + const video::SColor tail, + const core::vector3df& position, + const core::vector3df& rotation, const core::vector3df& scale) + : IVolumeLightSceneNode(parent, mgr, id, position, rotation, scale), + Mesh(0), LPDistance(8.0f), + SubdivideU(subdivU), SubdivideV(subdivV), + FootColor(foot), TailColor(tail), + LightDimensions(core::vector3df(1.0f, 1.2f, 1.0f)) +{ + #ifdef _DEBUG + setDebugName("CVolumeLightSceneNode"); + #endif + + constructLight(); +} + + +CVolumeLightSceneNode::~CVolumeLightSceneNode() +{ + if (Mesh) + Mesh->drop(); +} + + +void CVolumeLightSceneNode::constructLight() +{ + if (Mesh) + Mesh->drop(); + Mesh = SceneManager->getGeometryCreator()->createVolumeLightMesh(SubdivideU, SubdivideV, FootColor, TailColor, LPDistance, LightDimensions); +} + + +//! renders the node. +void CVolumeLightSceneNode::render() +{ + if (!Mesh) + return; + + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + + driver->setMaterial(Mesh->getMeshBuffer(0)->getMaterial()); + driver->drawMeshBuffer(Mesh->getMeshBuffer(0)); +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CVolumeLightSceneNode::getBoundingBox() const +{ + return Mesh->getBoundingBox(); +} + + +void CVolumeLightSceneNode::OnRegisterSceneNode() +{ + if (IsVisible) + { + SceneManager->registerNodeForRendering(this, ESNRP_TRANSPARENT); + } + ISceneNode::OnRegisterSceneNode(); +} + + +video::SMaterial& CVolumeLightSceneNode::getMaterial(u32 i) +{ + return Mesh->getMeshBuffer(i)->getMaterial(); +} + + +u32 CVolumeLightSceneNode::getMaterialCount() const +{ + return 1; +} + + +void CVolumeLightSceneNode::setSubDivideU (const u32 inU) +{ + if (inU != SubdivideU) + { + SubdivideU = inU; + constructLight(); + } +} + + +void CVolumeLightSceneNode::setSubDivideV (const u32 inV) +{ + if (inV != SubdivideV) + { + SubdivideV = inV; + constructLight(); + } +} + + +void CVolumeLightSceneNode::setFootColor(const video::SColor inColor) +{ + if (inColor != FootColor) + { + FootColor = inColor; + constructLight(); + } +} + + +void CVolumeLightSceneNode::setTailColor(const video::SColor inColor) +{ + if (inColor != TailColor) + { + TailColor = inColor; + constructLight(); + } +} + + +//! Writes attributes of the scene node. +void CVolumeLightSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + ISceneNode::serializeAttributes(out, options); + + out->addFloat("lpDistance", LPDistance); + out->addInt("subDivideU", SubdivideU); + out->addInt("subDivideV", SubdivideV); + + out->addColor("footColor", FootColor); + out->addColor("tailColor", TailColor); + + out->addVector3d("lightDimension", LightDimensions); +} + + +//! Reads attributes of the scene node. +void CVolumeLightSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + LPDistance = in->getAttributeAsFloat("lpDistance"); + LPDistance = core::max_(LPDistance, 8.0f); + + SubdivideU = in->getAttributeAsInt("subDivideU"); + SubdivideU = core::max_(SubdivideU, 1u); + + SubdivideV = in->getAttributeAsInt("subDivideV"); + SubdivideV = core::max_(SubdivideV, 1u); + + FootColor = in->getAttributeAsColor("footColor"); + TailColor = in->getAttributeAsColor("tailColor"); + + LightDimensions = in->getAttributeAsVector3d("lightDimension"); + + constructLight(); + + ISceneNode::deserializeAttributes(in, options); +} + + +//! Creates a clone of this scene node and its children. +ISceneNode* CVolumeLightSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager) +{ + if (!newParent) + newParent = Parent; + if (!newManager) + newManager = SceneManager; + + CVolumeLightSceneNode* nb = new CVolumeLightSceneNode(newParent, + newManager, ID, SubdivideU, SubdivideV, FootColor, TailColor, RelativeTranslation); + + nb->cloneMembers(this, newManager); + nb->getMaterial(0) = Mesh->getMeshBuffer(0)->getMaterial(); + + if ( newParent ) + nb->drop(); + return nb; +} + + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CVolumeLightSceneNode.h b/source/Irrlicht/CVolumeLightSceneNode.h new file mode 100644 index 00000000..13c0335a --- /dev/null +++ b/source/Irrlicht/CVolumeLightSceneNode.h @@ -0,0 +1,95 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +// +// created by Dean Wadsworth aka Varmint Dec 31 2007 + +#ifndef __VOLUME_LIGHT_SCENE_NODE_H_INCLUDED__ +#define __VOLUME_LIGHT_SCENE_NODE_H_INCLUDED__ + +#include "IVolumeLightSceneNode.h" +#include "IMesh.h" + +namespace irr +{ +namespace scene +{ + class CVolumeLightSceneNode : public IVolumeLightSceneNode + { + public: + + //! constructor + CVolumeLightSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + const u32 subdivU = 32, const u32 subdivV = 32, + const video::SColor foot = video::SColor(51, 0, 230, 180), + const video::SColor tail = video::SColor(0, 0, 0, 0), + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)); + + virtual ~CVolumeLightSceneNode(); + + virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; + + //! renders the node. + virtual void render() _IRR_OVERRIDE_; + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const _IRR_OVERRIDE_; + + //! returns the material based on the zero based index i. + virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_; + + //! returns amount of materials used by this scene node. + virtual u32 getMaterialCount() const _IRR_OVERRIDE_; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_VOLUME_LIGHT; } + + //! Writes attributes of the scene node. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_; + + //! Creates a clone of this scene node and its children. + virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_; + + virtual void setSubDivideU(const u32 inU) _IRR_OVERRIDE_; + virtual void setSubDivideV(const u32 inV) _IRR_OVERRIDE_; + + virtual u32 getSubDivideU() const _IRR_OVERRIDE_ { return SubdivideU; } + virtual u32 getSubDivideV() const _IRR_OVERRIDE_ { return SubdivideV; } + + virtual void setFootColor(const video::SColor inColor) _IRR_OVERRIDE_; + virtual void setTailColor(const video::SColor inColor) _IRR_OVERRIDE_; + + virtual video::SColor getFootColor() const _IRR_OVERRIDE_ { return FootColor; } + virtual video::SColor getTailColor() const _IRR_OVERRIDE_ { return TailColor; } + + private: + void constructLight(); + + IMesh* Mesh; + + f32 LPDistance; // Distance to hypothetical lightsource point -- affects fov angle + + u32 SubdivideU; // Number of subdivisions in U and V space. + u32 SubdivideV; // Controls the number of "slices" in the volume. + // NOTE : Total number of polygons = 2 + ((SubdivideU + 1) + (SubdivideV + 1)) * 2 + // Each slice being a quad plus the rectangular plane at the bottom. + + video::SColor FootColor; // Color at the source + video::SColor TailColor; // Color at the end. + + // LightDimensions.Y Distance of shooting -- Length of beams + // LightDimensions.X and LightDimensions.Z determine the + // size/dimension of the plane + core::vector3df LightDimensions; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CWADReader.cpp b/source/Irrlicht/CWADReader.cpp new file mode 100644 index 00000000..0d7b8f9e --- /dev/null +++ b/source/Irrlicht/CWADReader.cpp @@ -0,0 +1,263 @@ +// Copyright (C) 2002-2012 Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +// Code contributed by skreamz + +#include "IrrCompileConfig.h" + +#ifdef __IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_ + +#include "CWADReader.h" +#include "os.h" +#include "coreutil.h" + +namespace irr +{ +namespace io +{ + +//! Constructor +CArchiveLoaderWAD::CArchiveLoaderWAD( io::IFileSystem* fs) +: FileSystem(fs) +{ + #ifdef _DEBUG + setDebugName("CArchiveLoaderWAD"); + #endif +} + + +//! returns true if the file maybe is able to be loaded by this class +bool CArchiveLoaderWAD::isALoadableFileFormat(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "wad" ); +} + + +//! Creates an archive from the filename +/** \param file File handle to check. +\return Pointer to newly created archive, or 0 upon error. */ +IFileArchive* CArchiveLoaderWAD::createArchive(const io::path& filename, bool ignoreCase, bool ignorePaths) const +{ + IFileArchive *archive = 0; + io::IReadFile* file = FileSystem->createAndOpenFile(filename); + + if (file) + { + archive = createArchive ( file, ignoreCase, ignorePaths ); + file->drop (); + } + + return archive; +} + +//! creates/loads an archive from the file. +//! \return Pointer to the created archive. Returns 0 if loading failed. +IFileArchive* CArchiveLoaderWAD::createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const +{ + IFileArchive *archive = 0; + if ( file ) + { + file->seek ( 0 ); + archive = new CWADReader(file, ignoreCase, ignorePaths); + } + return archive; +} + + +//! Check if the file might be loaded by this class +/** Check might look into the file. +\param file File handle to check. +\return True if file seems to be loadable. */ +bool CArchiveLoaderWAD::isALoadableFileFormat(io::IReadFile* file) const +{ + SWADFileHeader header; + memset(&header, 0, sizeof(header)); + + file->read( &header.tag, 4 ); + + return !strncmp ( header.tag, "WAD2", 4 ) || !strncmp ( header.tag, "WAD3", 4 ); +} + +//! Check to see if the loader can create archives of this type. +bool CArchiveLoaderWAD::isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const +{ + return fileType == EFAT_WAD; +} + +void createDir ( const c8 *full ); + + +/*! + WAD Reader +*/ +CWADReader::CWADReader(IReadFile* file, bool ignoreCase, bool ignorePaths) +: CFileList((file ? file->getFileName() : io::path("")), ignoreCase, ignorePaths), File(file) +{ + #ifdef _DEBUG + setDebugName("CWADReader"); + #endif + + if (File) + { + File->grab(); + + Base = File->getFileName(); + Base.replace ( '\\', '/' ); + + // scan local headers + scanLocalHeader(); + + sort(); + } + +#if 0 + for ( u32 i = 0; i < FileList.size(); ++i ) + { + SWADFileEntry &e = FileList[i]; + char buf[128]; + snprintf_irr ( buf, 128, "c:\\h2\\%s", e.wadFileName.c_str() ); + + createDir ( buf ); + FILE * f = fopen ( buf, "wb" ); + if ( 0 == f ) + continue; + + u8 * mem = new u8 [ e.header.disksize ]; + File->seek ( e.header.filepos ); + File->read ( mem, e.header.disksize ); + fwrite ( mem, e.header.disksize, 1, f ); + delete [] mem; + fclose ( f ); + } +#endif + +} + + +CWADReader::~CWADReader() +{ + if (File) + File->drop(); +} + + +//! return the id of the file Archive +const io::path& CWADReader::getArchiveName () const +{ + return Base; +} + +const IFileList* CWADReader::getFileList() const +{ + return this; +} + + +//! scans for a local header, returns false if there is no more local file header. +bool CWADReader::scanLocalHeader() +{ + SWADFileEntryOriginal entry; + SWADFileEntry save; + + memset(&Header, 0, sizeof(SWADFileHeader)); + File->read(&Header, sizeof(SWADFileHeader)); + + if ( 0 == strncmp ( Header.tag, "WAD2", 4 ) ) + WadType = WAD_FORMAT_QUAKE2; + else + if ( 0 == strncmp ( Header.tag, "WAD3", 4 ) ) + WadType = WAD_FORMAT_HALFLIFE; + else + WadType = WAD_FORMAT_UNKNOWN; + + if ( WadType == WAD_FORMAT_UNKNOWN ) + return false; + +#ifdef __BIG_ENDIAN__ + Header.numlumps = os::Byteswap::byteswap(Header.numlumps); + Header.infotableofs = os::Byteswap::byteswap(Header.infotableofs); +#endif + + File->seek ( Header.infotableofs ); + + c8 buf[16]; + for ( u32 i = 0; i < Header.numlumps; ++i ) + { + // read entry + File->read(&entry, sizeof ( SWADFileEntryOriginal )); + entry.name[ sizeof ( entry.name ) - 1 ] = 0; + + save.header = entry; + save.wadFileName = "/"; + save.wadFileName += entry.name; + + if ( WadType == WAD_FORMAT_HALFLIFE ) + { + // don't know about the types! i'm guessing + switch ( entry.type ) + { + case WAD_TYP_MIPTEX_HALFLIFE: + save.wadFileName += ".wal2"; + break; + default: + snprintf_irr ( buf, 16, ".%02d", entry.type ); + save.wadFileName += buf; + break; + } + } + else + if ( WadType == WAD_FORMAT_QUAKE2 ) + { + switch ( entry.type ) + { + case WAD_TYP_MIPTEX: save.wadFileName += ".miptex"; break; + case WAD_TYP_SOUND: save.wadFileName += ".sound"; break; + case WAD_TYP_PALETTE: save.wadFileName += ".palette"; break; + case WAD_TYP_QTEX: save.wadFileName += ".qtex"; break; + case WAD_TYP_QPIC: save.wadFileName += ".qpic"; break; + case WAD_TYP_FONT: save.wadFileName += ".font"; break; + default: + snprintf_irr ( buf, 16, ".%02d", entry.type ); + save.wadFileName += buf; + break; + } + } + + // add file to list + addItem(save.wadFileName,save.header.filepos, save.header.disksize, false ); + //FileInfo.push_back(save); + } + return true; +} + + +//! opens a file by file name +IReadFile* CWADReader::createAndOpenFile(const io::path& filename) +{ + s32 index = findFile(filename, false); + + if (index != -1) + return createAndOpenFile(index); + + return 0; +} + + +//! opens a file by index +IReadFile* CWADReader::createAndOpenFile(u32 index) +{ + if (index >= Files.size() ) + return 0; + + const SFileListEntry &entry = Files[index]; + return createLimitReadFile( entry.FullName, File, entry.Offset, entry.Size ); +} + + + +} // end namespace io +} // end namespace irr + + +#endif // __IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_ + diff --git a/source/Irrlicht/CWADReader.h b/source/Irrlicht/CWADReader.h new file mode 100644 index 00000000..fe2acd1f --- /dev/null +++ b/source/Irrlicht/CWADReader.h @@ -0,0 +1,176 @@ +// Copyright (C) 2002-2012 Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_WAD_READER_H_INCLUDED__ +#define __C_WAD_READER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef __IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_ + +#include "IReferenceCounted.h" +#include "IReadFile.h" +#include "irrArray.h" +#include "irrString.h" +#include "IFileSystem.h" +#include "CFileList.h" + + +namespace irr +{ +namespace io +{ + + enum eWADFileTypes + { + WAD_FORMAT_UNKNOWN = 0, + WAD_FORMAT_QUAKE2 = 1, + WAD_FORMAT_HALFLIFE = 2, + + WAD_CMP_NONE = 0, + WAD_CMP_LZSS = 1, + + WAD_TYP_NONE = 0, + WAD_TYP_LABEL = 1, + + WAD_TYP_LUMPY = 64, // 64 + grab command number + WAD_TYP_PALETTE = 64, + WAD_TYP_QTEX = 65, + WAD_TYP_QPIC = 66, + WAD_TYP_SOUND = 67, + WAD_TYP_MIPTEX = 68, + WAD_TYP_MIPTEX_HALFLIFE = 67, + WAD_TYP_FONT = 70, + }; + +// byte-align structures +#include "irrpack.h" + + struct SWADFileHeader + { + c8 tag[4]; // type of WAD format WAD2 = quake2, WAD3 = halflife + u32 numlumps; + u32 infotableofs; + } PACK_STRUCT; + + struct SWADFileEntryOriginal + { + u32 filepos; + u32 disksize; + u32 size; // uncompressed + u8 type; + u8 compression; + u8 pad[2]; + u8 name[16]; // must be null terminated + } PACK_STRUCT; + +// Default alignment +#include "irrunpack.h" + + struct SWADFileEntry + { + io::path simpleFileName; + bool operator < (const SWADFileEntry& other) const + { + return simpleFileName < other.simpleFileName; + } + + io::path wadFileName; + SWADFileEntryOriginal header; + }; + + //! Archiveloader capable of loading WAD Archives + class CArchiveLoaderWAD : public IArchiveLoader + { + public: + + //! Constructor + CArchiveLoaderWAD(io::IFileSystem* fs); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".zip") + virtual bool isALoadableFileFormat(const io::path& filename) const _IRR_OVERRIDE_; + + //! Check if the file might be loaded by this class + /** Check might look into the file. + \param file File handle to check. + \return True if file seems to be loadable. */ + virtual bool isALoadableFileFormat(io::IReadFile* file) const _IRR_OVERRIDE_; + + //! Check to see if the loader can create archives of this type. + /** Check based on the archive type. + \param fileType The archive type to check. + \return True if the archile loader supports this type, false if not */ + virtual bool isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const _IRR_OVERRIDE_; + + //! Creates an archive from the filename + /** \param file File handle to check. + \return Pointer to newly created archive, or 0 upon error. */ + virtual IFileArchive* createArchive(const io::path& filename, bool ignoreCase, bool ignorePaths) const _IRR_OVERRIDE_; + + //! creates/loads an archive from the file. + //! \return Pointer to the created archive. Returns 0 if loading failed. + virtual io::IFileArchive* createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const _IRR_OVERRIDE_; + + private: + io::IFileSystem* FileSystem; + }; + + + //! reads from WAD + class CWADReader : public IFileArchive, virtual CFileList + { + public: + + CWADReader(IReadFile* file, bool ignoreCase, bool ignorePaths); + virtual ~CWADReader(); + + // file archive methods + + //! return the id of the file Archive + virtual const io::path& getArchiveName() const _IRR_OVERRIDE_; + + //! opens a file by file name + virtual IReadFile* createAndOpenFile(const io::path& filename) _IRR_OVERRIDE_; + + //! opens a file by index + virtual IReadFile* createAndOpenFile(u32 index) _IRR_OVERRIDE_; + + //! returns the list of files + virtual const IFileList* getFileList() const _IRR_OVERRIDE_; + + //! get the class Type + virtual E_FILE_ARCHIVE_TYPE getType() const _IRR_OVERRIDE_ { return EFAT_WAD; } + + + private: + + io::path Type; + + //! scans for a local header, returns false if there is no more local file header. + bool scanLocalHeader(); + + //! splits filename from zip file into useful filenames and paths + void extractFilename(SWADFileEntry* entry); + + io::path Base; + io::path MountPoint; + + IReadFile* File; + + eWADFileTypes WadType; + SWADFileHeader Header; + + //core::array FileInfo; + + io::IFileSystem* FileSystem; + }; + +} // end namespace io +} // end namespace irr + +#endif + + +#endif // #ifdef __IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_ + diff --git a/source/Irrlicht/CWGLManager.cpp b/source/Irrlicht/CWGLManager.cpp new file mode 100644 index 00000000..da9fb1a3 --- /dev/null +++ b/source/Irrlicht/CWGLManager.cpp @@ -0,0 +1,497 @@ +// Copyright (C) 2013 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#include "CWGLManager.h" + +#ifdef _IRR_COMPILE_WITH_WGL_MANAGER_ + +#include "os.h" + +#include +#include "wglext.h" + +#ifdef _MSC_VER + #pragma comment(lib, "OpenGL32.lib") +#endif + +namespace irr +{ +namespace video +{ + +CWGLManager::CWGLManager() + : PrimaryContext(SExposedVideoData(0)), PixelFormat(0) +{ + #ifdef _DEBUG + setDebugName("CWGLManager"); + #endif +} + +CWGLManager::~CWGLManager() +{ +} + +bool CWGLManager::initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& videodata) +{ + // store params, videoData is set later as it would be overwritten else + Params=params; + + // Create a window to test antialiasing support + const fschar_t* ClassName = __TEXT("CWGLManager"); + HINSTANCE lhInstance = GetModuleHandle(0); + + // Register Class + WNDCLASSEX wcex; + 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; + RegisterClassEx(&wcex); + + RECT clientSize; + clientSize.top = 0; + clientSize.left = 0; + clientSize.right = Params.WindowSize.Width; + clientSize.bottom = Params.WindowSize.Height; + + DWORD style = WS_POPUP; + if (!Params.Fullscreen) + style = WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + + AdjustWindowRect(&clientSize, style, FALSE); + + const s32 realWidth = clientSize.right - clientSize.left; + const s32 realHeight = clientSize.bottom - clientSize.top; + + const s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2; + const s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2; + + HWND temporary_wnd=CreateWindow(ClassName, __TEXT(""), style, windowLeft, + windowTop, realWidth, realHeight, NULL, NULL, lhInstance, NULL); + + if (!temporary_wnd) + { + os::Printer::log("Cannot create a temporary window.", ELL_ERROR); + UnregisterClass(ClassName, lhInstance); + return false; + } + + HDC HDc = GetDC(temporary_wnd); + + // Set up pixel format descriptor with desired parameters + PIXELFORMATDESCRIPTOR tmp_pfd = { + sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor + 1, // Version Number + (DWORD)(PFD_DRAW_TO_WINDOW | // Format Must Support Window + PFD_SUPPORT_OPENGL | // Format Must Support OpenGL + (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 + 0, // No Alpha Buffer + 0, // Shift Bit Ignored + 0, // No Accumulation Buffer + 0, 0, 0, 0, // Accumulation Bits Ignored + Params.ZBufferBits, // Z-Buffer (Depth Buffer) + BYTE(Params.Stencilbuffer ? 1 : 0), // Stencil Buffer Depth + 0, // No Auxiliary Buffer + PFD_MAIN_PLANE, // Main Drawing Layer + 0, // Reserved + 0, 0, 0 // Layer Masks Ignored + }; + pfd=tmp_pfd; + + for (u32 i=0; i<6; ++i) + { + if (i == 1) + { + if (Params.Stencilbuffer) + { + os::Printer::log("Cannot create a GL device with stencil buffer, disabling stencil shadows.", ELL_WARNING); + Params.Stencilbuffer = false; + pfd.cStencilBits = 0; + } + else + continue; + } + else + if (i == 2) + { + pfd.cDepthBits = 24; + } + else + if (i == 3) + { + if (Params.Bits!=16) + pfd.cDepthBits = 16; + else + continue; + } + 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); + DestroyWindow(temporary_wnd); + UnregisterClass(ClassName, lhInstance); + return false; + } + + // choose pixelformat + PixelFormat = ChoosePixelFormat(HDc, &pfd); + if (PixelFormat) + break; + } + + SetPixelFormat(HDc, PixelFormat, &pfd); + os::Printer::log("Create temporary GL rendering context", ELL_DEBUG); + HGLRC hrc=wglCreateContext(HDc); + if (!hrc) + { + os::Printer::log("Cannot create a temporary GL rendering context.", ELL_ERROR); + ReleaseDC(temporary_wnd, HDc); + DestroyWindow(temporary_wnd); + UnregisterClass(ClassName, lhInstance); + return false; + } + + CurrentContext.OpenGLWin32.HDc = HDc; + CurrentContext.OpenGLWin32.HRc = hrc; + CurrentContext.OpenGLWin32.HWnd = temporary_wnd; + + if (!activateContext(CurrentContext, false)) + { + os::Printer::log("Cannot activate a temporary GL rendering context.", ELL_ERROR); + wglDeleteContext(hrc); + ReleaseDC(temporary_wnd, HDc); + DestroyWindow(temporary_wnd); + UnregisterClass(ClassName, lhInstance); + return false; + } + + core::stringc wglExtensions; +#ifdef WGL_ARB_extensions_string + PFNWGLGETEXTENSIONSSTRINGARBPROC irrGetExtensionsString = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); + if (irrGetExtensionsString) + wglExtensions = irrGetExtensionsString(HDc); +#elif defined(WGL_EXT_extensions_string) + PFNWGLGETEXTENSIONSSTRINGEXTPROC irrGetExtensionsString = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT"); + if (irrGetExtensionsString) + wglExtensions = irrGetExtensionsString(HDc); +#endif + const bool pixel_format_supported = (wglExtensions.find("WGL_ARB_pixel_format") != -1); + const bool multi_sample_supported = ((wglExtensions.find("WGL_ARB_multisample") != -1) || + (wglExtensions.find("WGL_EXT_multisample") != -1) || (wglExtensions.find("WGL_3DFX_multisample") != -1) ); +#ifdef _DEBUG + os::Printer::log("WGL_extensions", wglExtensions); +#endif + +#ifdef WGL_ARB_pixel_format + PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormat_ARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); + if (pixel_format_supported && wglChoosePixelFormat_ARB) + { + // This value determines the number of samples used for antialiasing + // My experience is that 8 does not show a big + // improvement over 4, but 4 shows a big improvement + // over 2. + + if (Params.AntiAlias > 32) + Params.AntiAlias = 32; + + f32 fAttributes[] = {0.0, 0.0}; + s32 iAttributes[] = + { + WGL_DRAW_TO_WINDOW_ARB,1, + WGL_SUPPORT_OPENGL_ARB,1, + WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB, + WGL_COLOR_BITS_ARB,(Params.Bits==32) ? 24 : 15, + WGL_ALPHA_BITS_ARB,(Params.Bits==32) ? 8 : 1, + WGL_DEPTH_BITS_ARB,Params.ZBufferBits, // 10,11 + WGL_STENCIL_BITS_ARB,Params.Stencilbuffer ? 1 : 0, + WGL_DOUBLE_BUFFER_ARB,Params.Doublebuffer ? 1 : 0, + WGL_STEREO_ARB,Params.Stereobuffer ? 1 : 0, + WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, +#ifdef WGL_ARB_multisample + WGL_SAMPLES_ARB,Params.AntiAlias, // 20,21 + WGL_SAMPLE_BUFFERS_ARB, (Params.AntiAlias>0) ? 1 : 0, +#elif defined(WGL_EXT_multisample) + WGL_SAMPLES_EXT,AntiAlias, // 20,21 + WGL_SAMPLE_BUFFERS_EXT, (Params.AntiAlias>0) ? 1 : 0, +#elif defined(WGL_3DFX_multisample) + WGL_SAMPLES_3DFX,AntiAlias, // 20,21 + WGL_SAMPLE_BUFFERS_3DFX, (Params.AntiAlias>0) ? 1 : 0, +#endif +#ifdef WGL_ARB_framebuffer_sRGB + WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, Params.HandleSRGB ? 1:0, +#elif defined(WGL_EXT_framebuffer_sRGB) + WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT, Params.HandleSRGB ? 1:0, +#endif +// WGL_DEPTH_FLOAT_EXT, 1, + 0,0,0,0 + }; + int iAttrSize = sizeof(iAttributes)/sizeof(int); + const bool framebuffer_srgb_supported = ((wglExtensions.find("WGL_ARB_framebuffer_sRGB") != -1) || + (wglExtensions.find("WGL_EXT_framebuffer_sRGB") != -1)); + if (!framebuffer_srgb_supported) + { + memmove(&iAttributes[24],&iAttributes[26],sizeof(int)*(iAttrSize-26)); + iAttrSize -= 2; + } + if (!multi_sample_supported) + { + memmove(&iAttributes[20],&iAttributes[24],sizeof(int)*(iAttrSize-24)); + iAttrSize -= 4; + } + + s32 rv=0; + // Try to get an acceptable pixel format + do + { + int pixelFormat=0; + UINT numFormats=0; + const BOOL valid = wglChoosePixelFormat_ARB(HDc,iAttributes,fAttributes,1,&pixelFormat,&numFormats); + + if (valid && numFormats) + rv = pixelFormat; + else + iAttributes[21] -= 1; + } + while(rv==0 && iAttributes[21]>1); + if (rv) + { + PixelFormat=rv; + Params.AntiAlias=iAttributes[21]; + } + } + else +#endif + Params.AntiAlias=0; + + // this only terminates the temporary HRc + destroyContext(); + destroySurface(); + terminate(); + DestroyWindow(temporary_wnd); + UnregisterClass(ClassName, lhInstance); + + // now get new window + CurrentContext.OpenGLWin32.HWnd=videodata.OpenGLWin32.HWnd; + // get hdc + if (!(CurrentContext.OpenGLWin32.HDc=GetDC((HWND)videodata.OpenGLWin32.HWnd))) + { + os::Printer::log("Cannot create a GL device context.", ELL_ERROR); + return false; + } + if (!PrimaryContext.OpenGLWin32.HWnd) + { + PrimaryContext.OpenGLWin32.HWnd=CurrentContext.OpenGLWin32.HWnd; + PrimaryContext.OpenGLWin32.HDc=CurrentContext.OpenGLWin32.HDc; + } + + return true; +} + +void CWGLManager::terminate() +{ + if (CurrentContext.OpenGLWin32.HDc) + ReleaseDC((HWND)CurrentContext.OpenGLWin32.HWnd, (HDC)CurrentContext.OpenGLWin32.HDc); + if (PrimaryContext.OpenGLWin32.HDc && PrimaryContext.OpenGLWin32.HDc == CurrentContext.OpenGLWin32.HDc) + memset(&PrimaryContext, 0, sizeof(PrimaryContext)); + memset(&CurrentContext, 0, sizeof(CurrentContext)); +} + +bool CWGLManager::generateSurface() +{ + HDC HDc = (HDC)CurrentContext.OpenGLWin32.HDc; + // search for pixel format the simple way + if (PixelFormat==0 || (!SetPixelFormat(HDc, PixelFormat, &pfd))) + { + for (u32 i=0; i<5; ++i) + { + if (i == 1) + { + if (Params.Stencilbuffer) + { + os::Printer::log("Cannot create a GL device with stencil buffer, disabling stencil shadows.", ELL_WARNING); + Params.Stencilbuffer = false; + pfd.cStencilBits = 0; + } + else + continue; + } + else + if (i == 2) + { + pfd.cDepthBits = 24; + } + if (i == 3) + { + if (Params.Bits!=16) + pfd.cDepthBits = 16; + else + continue; + } + else + if (i == 4) + { + os::Printer::log("Cannot create a GL device context", "No suitable format.", ELL_ERROR); + return false; + } + + // choose pixelformat + PixelFormat = ChoosePixelFormat(HDc, &pfd); + if (PixelFormat) + break; + } + + // set pixel format + if (!SetPixelFormat(HDc, PixelFormat, &pfd)) + { + os::Printer::log("Cannot set the pixel format.", ELL_ERROR); + return false; + } + } + + if (pfd.cAlphaBits != 0) + { + if (pfd.cRedBits == 8) + ColorFormat = ECF_A8R8G8B8; + else + ColorFormat = ECF_A1R5G5B5; + } + else + { + if (pfd.cRedBits == 8) + ColorFormat = ECF_R8G8B8; + else + ColorFormat = ECF_R5G6B5; + } + os::Printer::log("Pixel Format", core::stringc(PixelFormat).c_str(), ELL_DEBUG); + return true; +} + +void CWGLManager::destroySurface() +{ +} + +bool CWGLManager::generateContext() +{ + HDC HDc=(HDC)CurrentContext.OpenGLWin32.HDc; + HGLRC hrc; + // create rendering context +#ifdef WGL_ARB_create_context + PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs_ARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); + if (wglCreateContextAttribs_ARB) + { + // with 3.0 all available profiles should be usable, higher versions impose restrictions + // we need at least 1.1 + const int iAttribs[] = + { + WGL_CONTEXT_MAJOR_VERSION_ARB, 1, + WGL_CONTEXT_MINOR_VERSION_ARB, 1, +// WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB, // enable to get a debug context (depends on driver if that does anything) + 0 + }; + hrc=wglCreateContextAttribs_ARB(HDc, 0, iAttribs); + } + else +#endif + hrc=wglCreateContext(HDc); + os::Printer::log("Irrlicht context"); + + if (!hrc) + { + os::Printer::log("Cannot create a GL rendering context.", ELL_ERROR); + return false; + } + + // set exposed data + CurrentContext.OpenGLWin32.HRc = hrc; + if (!PrimaryContext.OpenGLWin32.HRc) + PrimaryContext.OpenGLWin32.HRc=CurrentContext.OpenGLWin32.HRc; + + return true; +} + +const SExposedVideoData& CWGLManager::getContext() const +{ + return CurrentContext; +} + +bool CWGLManager::activateContext(const SExposedVideoData& videoData, bool restorePrimaryOnZero) +{ + if (videoData.OpenGLWin32.HWnd && videoData.OpenGLWin32.HDc && videoData.OpenGLWin32.HRc) + { + if (!wglMakeCurrent((HDC)videoData.OpenGLWin32.HDc, (HGLRC)videoData.OpenGLWin32.HRc)) + { + os::Printer::log("Render Context switch failed."); + return false; + } + CurrentContext=videoData; + } + else if (!restorePrimaryOnZero && !videoData.OpenGLWin32.HDc && !videoData.OpenGLWin32.HRc) + { + if (!wglMakeCurrent((HDC)0, (HGLRC)0)) + { + os::Printer::log("Render Context reset failed."); + return false; + } + CurrentContext = videoData; + } + // set back to main context + else if (!videoData.OpenGLWin32.HWnd && CurrentContext.OpenGLWin32.HDc != PrimaryContext.OpenGLWin32.HDc) + { + if (!wglMakeCurrent((HDC)PrimaryContext.OpenGLWin32.HDc, (HGLRC)PrimaryContext.OpenGLWin32.HRc)) + { + os::Printer::log("Render Context switch failed."); + return false; + } + CurrentContext=PrimaryContext; + } + return true; +} + +void CWGLManager::destroyContext() +{ + if (CurrentContext.OpenGLWin32.HRc) + { + if (!wglMakeCurrent((HDC)CurrentContext.OpenGLWin32.HDc, 0)) + os::Printer::log("Release of render context failed.", ELL_WARNING); + + if (!wglDeleteContext((HGLRC)CurrentContext.OpenGLWin32.HRc)) + os::Printer::log("Deletion of render context failed.", ELL_WARNING); + if (PrimaryContext.OpenGLWin32.HRc==CurrentContext.OpenGLWin32.HRc) + PrimaryContext.OpenGLWin32.HRc=0; + CurrentContext.OpenGLWin32.HRc=0; + } +} + +bool CWGLManager::swapBuffers() +{ + return SwapBuffers((HDC)CurrentContext.OpenGLWin32.HDc) == TRUE; +} + +} +} + +#endif diff --git a/source/Irrlicht/CWGLManager.h b/source/Irrlicht/CWGLManager.h new file mode 100644 index 00000000..4cfeb8f0 --- /dev/null +++ b/source/Irrlicht/CWGLManager.h @@ -0,0 +1,74 @@ +// Copyright (C) 2013 Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __C_WGL_MANAGER_H_INCLUDED__ +#define __C_WGL_MANAGER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_WGL_MANAGER_ + +#include "SIrrCreationParameters.h" +#include "SExposedVideoData.h" +#include "IContextManager.h" +#include "SColor.h" + +#define WIN32_LEAN_AND_MEAN +#include + +namespace irr +{ +namespace video +{ + // WGL manager. + class CWGLManager : public IContextManager + { + public: + //! Constructor. + CWGLManager(); + + //! Destructor + ~CWGLManager(); + + // Initialize + virtual bool initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& data) _IRR_OVERRIDE_; + + // Terminate + virtual void terminate() _IRR_OVERRIDE_; + + // Create surface. + virtual bool generateSurface() _IRR_OVERRIDE_; + + // Destroy surface. + virtual void destroySurface() _IRR_OVERRIDE_; + + // Create context. + virtual bool generateContext() _IRR_OVERRIDE_; + + // Destroy EGL context. + virtual void destroyContext() _IRR_OVERRIDE_; + + //! Get current context + virtual const SExposedVideoData& getContext() const _IRR_OVERRIDE_; + + //! Change render context, disable old and activate new defined by videoData + virtual bool activateContext(const SExposedVideoData& videoData, bool restorePrimaryOnZero) _IRR_OVERRIDE_; + + // Swap buffers. + virtual bool swapBuffers() _IRR_OVERRIDE_; + + private: + SIrrlichtCreationParameters Params; + SExposedVideoData PrimaryContext; + SExposedVideoData CurrentContext; + s32 PixelFormat; + PIXELFORMATDESCRIPTOR pfd; + ECOLOR_FORMAT ColorFormat; + }; +} +} + +#endif + +#endif diff --git a/source/Irrlicht/CWaterSurfaceSceneNode.cpp b/source/Irrlicht/CWaterSurfaceSceneNode.cpp new file mode 100644 index 00000000..0aee1012 --- /dev/null +++ b/source/Irrlicht/CWaterSurfaceSceneNode.cpp @@ -0,0 +1,140 @@ +// Copyright (C) 2002-2012 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" +#ifdef _IRR_COMPILE_WITH_WATER_SURFACE_SCENENODE_ +#include "CWaterSurfaceSceneNode.h" +#include "ISceneManager.h" +#include "IMeshManipulator.h" +#include "IMeshCache.h" +#include "S3DVertex.h" +#include "SMesh.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CWaterSurfaceSceneNode::CWaterSurfaceSceneNode(f32 waveHeight, f32 waveSpeed, f32 waveLength, + IMesh* mesh, ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position, const core::vector3df& rotation, + const core::vector3df& scale) + : CMeshSceneNode(mesh, parent, mgr, id, position, rotation, scale), + WaveLength(waveLength), WaveSpeed(waveSpeed), WaveHeight(waveHeight), + OriginalMesh(0) +{ + #ifdef _DEBUG + setDebugName("CWaterSurfaceSceneNode"); + #endif + + setMesh(mesh); +} + + +//! destructor +CWaterSurfaceSceneNode::~CWaterSurfaceSceneNode() +{ + // Mesh is dropped in CMeshSceneNode destructor + if (OriginalMesh) + OriginalMesh->drop(); +} + + +//! frame +void CWaterSurfaceSceneNode::OnRegisterSceneNode() +{ + CMeshSceneNode::OnRegisterSceneNode(); +} + + +void CWaterSurfaceSceneNode::OnAnimate(u32 timeMs) +{ + if (Mesh && IsVisible) + { + const u32 meshBufferCount = Mesh->getMeshBufferCount(); + const f32 time = timeMs / WaveSpeed; + + for (u32 b=0; bgetMeshBuffer(b)->getVertexCount(); + + for (u32 i=0; igetMeshBuffer(b)->getPosition(i).Y = addWave( + OriginalMesh->getMeshBuffer(b)->getPosition(i), + time); + }// end for all mesh buffers + Mesh->setDirty(scene::EBT_VERTEX); + + SceneManager->getMeshManipulator()->recalculateNormals(Mesh); + } + CMeshSceneNode::OnAnimate(timeMs); +} + + +void CWaterSurfaceSceneNode::setMesh(IMesh* mesh) +{ + CMeshSceneNode::setMesh(mesh); + if (!mesh) + return; + if (OriginalMesh) + OriginalMesh->drop(); + IMesh* clone = SceneManager->getMeshManipulator()->createMeshCopy(mesh); + OriginalMesh = mesh; + Mesh = clone; + Mesh->setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_INDEX); +// Mesh->setHardwareMappingHint(scene::EHM_STREAM, scene::EBT_VERTEX); +} + + +//! Writes attributes of the scene node. +void CWaterSurfaceSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + out->addFloat("WaveLength", WaveLength); + out->addFloat("WaveSpeed", WaveSpeed); + out->addFloat("WaveHeight", WaveHeight); + + CMeshSceneNode::serializeAttributes(out, options); + // serialize original mesh + out->setAttribute("Mesh", SceneManager->getMeshCache()->getMeshName(OriginalMesh).getPath().c_str()); +} + + +//! Reads attributes of the scene node. +void CWaterSurfaceSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + WaveLength = in->getAttributeAsFloat("WaveLength"); + WaveSpeed = in->getAttributeAsFloat("WaveSpeed"); + WaveHeight = in->getAttributeAsFloat("WaveHeight"); + + if (Mesh) + { + Mesh->drop(); + Mesh = OriginalMesh; + OriginalMesh = 0; + } + // deserialize original mesh + CMeshSceneNode::deserializeAttributes(in, options); + + if (Mesh) + { + IMesh* clone = SceneManager->getMeshManipulator()->createMeshCopy(Mesh); + OriginalMesh = Mesh; + Mesh = clone; + } +} + + +f32 CWaterSurfaceSceneNode::addWave(const core::vector3df &source, f32 time) const +{ + return source.Y + + (sinf(((source.X/WaveLength) + time)) * WaveHeight) + + (cosf(((source.Z/WaveLength) + time)) * WaveHeight); +} + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_WATER_SURFACE_SCENENODE_ diff --git a/source/Irrlicht/CWaterSurfaceSceneNode.h b/source/Irrlicht/CWaterSurfaceSceneNode.h new file mode 100644 index 00000000..7a588cd2 --- /dev/null +++ b/source/Irrlicht/CWaterSurfaceSceneNode.h @@ -0,0 +1,61 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_WATER_SURFACE_SCENE_NODE_H_INCLUDED__ +#define __C_WATER_SURFACE_SCENE_NODE_H_INCLUDED__ + +#include "CMeshSceneNode.h" + +namespace irr +{ +namespace scene +{ + + class CWaterSurfaceSceneNode : public CMeshSceneNode + { + public: + + //! constructor + CWaterSurfaceSceneNode(f32 waveHeight, f32 waveSpeed, f32 waveLength, + IMesh* mesh, ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)); + + //! destructor + virtual ~CWaterSurfaceSceneNode(); + + //! frame registration + virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; + + //! animated update + virtual void OnAnimate(u32 timeMs) _IRR_OVERRIDE_; + + //! Update mesh + virtual void setMesh(IMesh* mesh) _IRR_OVERRIDE_; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_WATER_SURFACE; } + + //! Writes attributes of the scene node. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_; + + //! Reads attributes of the scene node. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_; + + private: + + inline f32 addWave(const core::vector3df &source, f32 time) const; + + f32 WaveLength; + f32 WaveSpeed; + f32 WaveHeight; + IMesh* OriginalMesh; + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CWebGL1Driver.cpp b/source/Irrlicht/CWebGL1Driver.cpp new file mode 100644 index 00000000..1f0acb11 --- /dev/null +++ b/source/Irrlicht/CWebGL1Driver.cpp @@ -0,0 +1,1138 @@ +// Copyright (C) 2017 Michael Zeilfelder +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#include "CWebGL1Driver.h" + +#ifdef _IRR_COMPILE_WITH_WEBGL1_ + +#include "COpenGLCoreTexture.h" +#include "COpenGLCoreRenderTarget.h" +#include "COpenGLCoreCacheHandler.h" +#include "EVertexAttributes.h" + +namespace irr +{ +namespace video +{ + +CWebGL1Driver::CWebGL1Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager) : + COGLES2Driver(params, io, contextManager) + , MBTriangleFanSize4(0), MBLinesSize2(0), MBPointsSize1(0) +{ +#ifdef _DEBUG + setDebugName("CWebGL1Driver"); +#endif + + // NPOT are not allowed for WebGL in most cases. + // One can use them when: + // - The TEXTURE_MIN_FILTER is linear or nearest + // - no mipmapping is used + // - no texture wrapping is used (so all texture_wraps have to be CLAMP_TO_EDGE) + // So users could still enable them for specific cases (usually GUI), but in general better to have it off. + disableFeature(EVDF_TEXTURE_NPOT); + + MBLinesSize2 = createSimpleMeshBuffer(2, scene::EPT_LINES); + MBTriangleFanSize4 = createSimpleMeshBuffer(4, scene::EPT_TRIANGLE_FAN); + MBPointsSize1 = createSimpleMeshBuffer(1, scene::EPT_POINTS); +} + +CWebGL1Driver::~CWebGL1Driver() +{ + if ( MBTriangleFanSize4 ) + MBTriangleFanSize4->drop(); + if ( MBLinesSize2 ) + MBLinesSize2->drop(); + if ( MBPointsSize1 ) + MBPointsSize1->drop(); +} + +//! Returns type of video driver +E_DRIVER_TYPE CWebGL1Driver::getDriverType() const +{ + return EDT_WEBGL1; +} + +//! draws a vertex primitive list +void CWebGL1Driver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) +{ + if ( !vertices ) + { + COGLES2Driver::drawVertexPrimitiveList(vertices, vertexCount, indexList, primitiveCount, vType, pType, iType); + } + else + { + static bool first = true; + if ( first ) + { + first = false; + os::Printer::log("WebGL driver does not support drawVertexPrimitiveList calls without a VBO", ELL_WARNING); + os::Printer::log(__FILE__, irr::core::stringc(__LINE__).c_str(), ELL_WARNING); + } + } +} + +//! Draws a mesh buffer +void CWebGL1Driver::drawMeshBuffer(const scene::IMeshBuffer* mb) +{ + if ( mb ) + { + // OK - this is bad and I hope I can find a better solution. + // Basically casting away a const which shouldn't be cast away. + // Not a nice surprise for users to see their mesh changes I guess :-( + scene::IMeshBuffer* mbUglyHack = const_cast(mb); + + // We can't allow any buffers which are not bound to some VBO. + if ( mb->getHardwareMappingHint_Vertex() == scene::EHM_NEVER) + mbUglyHack->setHardwareMappingHint(scene::EHM_STREAM, scene::EBT_VERTEX); + if ( mb->getHardwareMappingHint_Index() == scene::EHM_NEVER) + mbUglyHack->setHardwareMappingHint(scene::EHM_STREAM, scene::EBT_INDEX); + + COGLES2Driver::drawMeshBuffer(mb); + } +} + +void CWebGL1Driver::draw2DImage(const video::ITexture* texture, + const core::position2d& destPos,const core::rect& sourceRect, + const core::rect* clipRect, SColor color, bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + if (!sourceRect.isValid()) + return; + + core::position2d targetPos(destPos); + core::position2d sourcePos(sourceRect.UpperLeftCorner); + core::dimension2d sourceSize(sourceRect.getSize()); + if (clipRect) + { + if (targetPos.X < clipRect->UpperLeftCorner.X) + { + sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X; + if (sourceSize.Width <= 0) + return; + + sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X; + targetPos.X = clipRect->UpperLeftCorner.X; + } + + if (targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X; + if (sourceSize.Width <= 0) + return; + } + + if (targetPos.Y < clipRect->UpperLeftCorner.Y) + { + sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y; + if (sourceSize.Height <= 0) + return; + + sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y; + targetPos.Y = clipRect->UpperLeftCorner.Y; + } + + if (targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y; + if (sourceSize.Height <= 0) + return; + } + } + + // clip these coordinates + + if (targetPos.X < 0) + { + sourceSize.Width += targetPos.X; + if (sourceSize.Width <= 0) + return; + + sourcePos.X -= targetPos.X; + targetPos.X = 0; + } + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width; + if (sourceSize.Width <= 0) + return; + } + + if (targetPos.Y < 0) + { + sourceSize.Height += targetPos.Y; + if (sourceSize.Height <= 0) + return; + + sourcePos.Y -= targetPos.Y; + targetPos.Y = 0; + } + + if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height; + if (sourceSize.Height <= 0) + return; + } + + // ok, we've clipped everything. + // now draw it. + + // texcoords need to be flipped horizontally for RTTs + const bool isRTT = texture->isRenderTarget(); + 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( + sourcePos.X * invW, + (isRTT ? (sourcePos.Y + sourceSize.Height) : sourcePos.Y) * invH, + (sourcePos.X + sourceSize.Width) * invW, + (isRTT ? sourcePos.Y : (sourcePos.Y + sourceSize.Height)) * invH); + + const core::rect poss(targetPos, sourceSize); + + chooseMaterial2D(); + if ( !setMaterialTexture(0, texture) ) + return; + + setRenderStates2DMode(color.getAlpha() < 255, true, useAlphaChannelOfTexture); + lockRenderStateMode(); + + f32 left = (f32)poss.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 right = (f32)poss.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 down = 2.f - (f32)poss.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + f32 top = 2.f - (f32)poss.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + + MBTriangleFanSize4->Vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, color, tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + MBTriangleFanSize4->Vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, color, tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + MBTriangleFanSize4->Vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, color, tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + MBTriangleFanSize4->Vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, color, tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + MBTriangleFanSize4->setDirty(scene::EBT_VERTEX); + + drawMeshBuffer(MBTriangleFanSize4); + + unlockRenderStateMode(); +} + +void CWebGL1Driver::draw2DImage(const video::ITexture* texture, const core::rect& destRect, + const core::rect& sourceRect, const core::rect* clipRect, + const video::SColor* const colors, bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + // texcoords need to be flipped horizontally for RTTs + const bool isRTT = texture->isRenderTarget(); + const core::dimension2du& 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( + sourceRect.UpperLeftCorner.X * invW, + (isRTT ? sourceRect.LowerRightCorner.Y : sourceRect.UpperLeftCorner.Y) * invH, + sourceRect.LowerRightCorner.X * invW, + (isRTT ? sourceRect.UpperLeftCorner.Y : sourceRect.LowerRightCorner.Y) *invH); + + const video::SColor temp[4] = + { + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF + }; + + const video::SColor* const useColor = colors ? colors : temp; + + chooseMaterial2D(); + if ( !setMaterialTexture(0, texture) ) + return; + + setRenderStates2DMode(useColor[0].getAlpha() < 255 || useColor[1].getAlpha() < 255 || + useColor[2].getAlpha() < 255 || useColor[3].getAlpha() < 255, + true, useAlphaChannelOfTexture); + lockRenderStateMode(); + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + bool useScissorTest = false; + if (clipRect && clipRect->isValid()) + { + useScissorTest = true; + glEnable(GL_SCISSOR_TEST); + glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height - clipRect->LowerRightCorner.Y, + clipRect->getWidth(), clipRect->getHeight()); + } + + f32 left = (f32)destRect.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 right = (f32)destRect.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 down = 2.f - (f32)destRect.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + f32 top = 2.f - (f32)destRect.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + + MBTriangleFanSize4->Vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, useColor[0], tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + MBTriangleFanSize4->Vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, useColor[3], tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + MBTriangleFanSize4->Vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, useColor[2], tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + MBTriangleFanSize4->Vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, useColor[1], tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + MBTriangleFanSize4->setDirty(scene::EBT_VERTEX); + + drawMeshBuffer(MBTriangleFanSize4); + + if (useScissorTest) + glDisable(GL_SCISSOR_TEST); + + unlockRenderStateMode(); + + testGLError(); +} + +void CWebGL1Driver::draw2DImage(const video::ITexture* texture, u32 layer, bool flip) +{ + if (!texture ) + return; + + chooseMaterial2D(); + if ( !setMaterialTexture(0, texture) ) + return; + + setRenderStates2DMode(false, true, true); + lockRenderStateMode(); + + MBTriangleFanSize4->Vertices[0].Pos = core::vector3df(-1.f, 1.f, 0.f); + MBTriangleFanSize4->Vertices[1].Pos = core::vector3df(1.f, 1.f, 0.f); + MBTriangleFanSize4->Vertices[2].Pos = core::vector3df(1.f, -1.f, 0.f); + MBTriangleFanSize4->Vertices[3].Pos = core::vector3df(-1.f, -1.f, 0.f); + + f32 modificator = (flip) ? 1.f : 0.f; + + MBTriangleFanSize4->Vertices[0].TCoords = core::vector2df(0.f, 0.f + modificator); + MBTriangleFanSize4->Vertices[1].TCoords = core::vector2df(1.f, 0.f + modificator); + MBTriangleFanSize4->Vertices[2].TCoords = core::vector2df(1.f, 1.f - modificator); + MBTriangleFanSize4->Vertices[3].TCoords = core::vector2df(0.f, 1.f - modificator); + + MBTriangleFanSize4->Vertices[0].Color = SColor(0xFFFFFFFF); + MBTriangleFanSize4->Vertices[1].Color = SColor(0xFFFFFFFF); + MBTriangleFanSize4->Vertices[2].Color = SColor(0xFFFFFFFF); + MBTriangleFanSize4->Vertices[3].Color = SColor(0xFFFFFFFF); + + MBTriangleFanSize4->setDirty(scene::EBT_VERTEX); + + drawMeshBuffer(MBTriangleFanSize4); + + unlockRenderStateMode(); +} + +void CWebGL1Driver::draw2DImageBatch(const video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, s32 kerningWidth, + const core::rect* clipRect, + SColor color, bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + chooseMaterial2D(); + if ( !setMaterialTexture(0, texture) ) + return; + + setRenderStates2DMode(color.getAlpha() < 255, true, useAlphaChannelOfTexture); + lockRenderStateMode(); + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + bool useScissorTest = false; + if (clipRect && clipRect->isValid()) + { + useScissorTest = true; + glEnable(GL_SCISSOR_TEST); + glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height - clipRect->LowerRightCorner.Y, + clipRect->getWidth(), clipRect->getHeight()); + } + + const core::dimension2du& ss = texture->getOriginalSize(); + core::position2d targetPos(pos); + // texcoords need to be flipped horizontally for RTTs + const bool isRTT = texture->isRenderTarget(); + const f32 invW = 1.f / static_cast(ss.Width); + const f32 invH = 1.f / static_cast(ss.Height); + + for (u32 i = 0; i < indices.size(); ++i) + { + const s32 currentIndex = indices[i]; + if (!sourceRects[currentIndex].isValid()) + break; + + const core::rect tcoords( + sourceRects[currentIndex].UpperLeftCorner.X * invW, + (isRTT ? sourceRects[currentIndex].LowerRightCorner.Y : sourceRects[currentIndex].UpperLeftCorner.Y) * invH, + sourceRects[currentIndex].LowerRightCorner.X * invW, + (isRTT ? sourceRects[currentIndex].UpperLeftCorner.Y : sourceRects[currentIndex].LowerRightCorner.Y) * invH); + + const core::rect poss(targetPos, sourceRects[currentIndex].getSize()); + + f32 left = (f32)poss.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 right = (f32)poss.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 down = 2.f - (f32)poss.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + f32 top = 2.f - (f32)poss.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + + MBTriangleFanSize4->Vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, color, tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + MBTriangleFanSize4->Vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, color, tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + MBTriangleFanSize4->Vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, color, tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + MBTriangleFanSize4->Vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, color, tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + MBTriangleFanSize4->setDirty(scene::EBT_VERTEX); + + drawMeshBuffer(MBTriangleFanSize4); + + targetPos.X += sourceRects[currentIndex].getWidth(); + } + + if (useScissorTest) + glDisable(GL_SCISSOR_TEST); + + unlockRenderStateMode(); + + testGLError(); +} + +void CWebGL1Driver::draw2DImageBatch(const video::ITexture* texture, + const core::array >& positions, + const core::array >& sourceRects, + const core::rect* clipRect, + SColor color, bool useAlphaChannelOfTexture) +{ + if (!texture) + return; + + const irr::u32 drawCount = core::min_(positions.size(), sourceRects.size()); + if ( !drawCount ) + return; + + chooseMaterial2D(); + if ( !setMaterialTexture(0, texture) ) + return; + + setRenderStates2DMode(color.getAlpha() < 255, true, useAlphaChannelOfTexture); + lockRenderStateMode(); + + for (u32 i = 0; i < drawCount; i++) + { + core::position2d targetPos = positions[i]; + core::position2d sourcePos = sourceRects[i].UpperLeftCorner; + // This needs to be signed as it may go negative. + core::dimension2d sourceSize(sourceRects[i].getSize()); + + if (clipRect) + { + if (targetPos.X < clipRect->UpperLeftCorner.X) + { + sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X; + if (sourceSize.Width <= 0) + continue; + + sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X; + targetPos.X = clipRect->UpperLeftCorner.X; + } + + if (targetPos.X + (s32)sourceSize.Width > clipRect->LowerRightCorner.X) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X; + if (sourceSize.Width <= 0) + continue; + } + + if (targetPos.Y < clipRect->UpperLeftCorner.Y) + { + sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y; + if (sourceSize.Height <= 0) + continue; + + sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y; + targetPos.Y = clipRect->UpperLeftCorner.Y; + } + + if (targetPos.Y + (s32)sourceSize.Height > clipRect->LowerRightCorner.Y) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y; + if (sourceSize.Height <= 0) + continue; + } + } + + // clip these coordinates + + if (targetPos.X < 0) + { + sourceSize.Width += targetPos.X; + if (sourceSize.Width <= 0) + continue; + + sourcePos.X -= targetPos.X; + targetPos.X = 0; + } + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width) + { + sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width; + if (sourceSize.Width <= 0) + continue; + } + + if (targetPos.Y < 0) + { + sourceSize.Height += targetPos.Y; + if (sourceSize.Height <= 0) + continue; + + sourcePos.Y -= targetPos.Y; + targetPos.Y = 0; + } + + if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height) + { + sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height; + if (sourceSize.Height <= 0) + continue; + } + + // ok, we've clipped everything. + // now draw it. + + core::rect tcoords; + tcoords.UpperLeftCorner.X = (((f32)sourcePos.X)) / texture->getOriginalSize().Width ; + tcoords.UpperLeftCorner.Y = (((f32)sourcePos.Y)) / texture->getOriginalSize().Height; + tcoords.LowerRightCorner.X = tcoords.UpperLeftCorner.X + ((f32)(sourceSize.Width) / texture->getOriginalSize().Width); + tcoords.LowerRightCorner.Y = tcoords.UpperLeftCorner.Y + ((f32)(sourceSize.Height) / texture->getOriginalSize().Height); + + const core::rect poss(targetPos, sourceSize); + + f32 left = (f32)poss.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 right = (f32)poss.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 down = 2.f - (f32)poss.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + f32 top = 2.f - (f32)poss.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + + MBTriangleFanSize4->Vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, color, tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y); + MBTriangleFanSize4->Vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, color, tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y); + MBTriangleFanSize4->Vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, color, tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y); + MBTriangleFanSize4->Vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, color, tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y); + MBTriangleFanSize4->setDirty(scene::EBT_VERTEX); + + drawMeshBuffer(MBTriangleFanSize4); + } + + unlockRenderStateMode(); +} + +//! draw a 2d rectangle +void CWebGL1Driver::draw2DRectangle(SColor color, + const core::rect& position, + const core::rect* clip) +{ + chooseMaterial2D(); + setMaterialTexture(0, 0); + + setRenderStates2DMode(color.getAlpha() < 255, false, false); + lockRenderStateMode(); + + core::rect pos = position; + + if (clip) + pos.clipAgainst(*clip); + + if (!pos.isValid()) + return; + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + f32 left = (f32)pos.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 right = (f32)pos.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 down = 2.f - (f32)pos.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + f32 top = 2.f - (f32)pos.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + + MBTriangleFanSize4->Vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, color, 0, 0); + MBTriangleFanSize4->Vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, color, 0, 0); + MBTriangleFanSize4->Vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, color, 0, 0); + MBTriangleFanSize4->Vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, color, 0, 0); + MBTriangleFanSize4->setDirty(scene::EBT_VERTEX); + + drawMeshBuffer(MBTriangleFanSize4); + + unlockRenderStateMode(); +} + +void CWebGL1Driver::draw2DRectangle(const core::rect& position, + SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, + const core::rect* clip) +{ + core::rect pos = position; + + if (clip) + pos.clipAgainst(*clip); + + if (!pos.isValid()) + return; + + chooseMaterial2D(); + setMaterialTexture(0, 0); + + setRenderStates2DMode(colorLeftUp.getAlpha() < 255 || + colorRightUp.getAlpha() < 255 || + colorLeftDown.getAlpha() < 255 || + colorRightDown.getAlpha() < 255, false, false); + lockRenderStateMode(); + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + f32 left = (f32)pos.UpperLeftCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 right = (f32)pos.LowerRightCorner.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 down = 2.f - (f32)pos.LowerRightCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + f32 top = 2.f - (f32)pos.UpperLeftCorner.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + + MBTriangleFanSize4->Vertices[0] = S3DVertex(left, top, 0, 0, 0, 1, colorLeftUp, 0, 0); + MBTriangleFanSize4->Vertices[1] = S3DVertex(right, top, 0, 0, 0, 1, colorRightUp, 0, 0); + MBTriangleFanSize4->Vertices[2] = S3DVertex(right, down, 0, 0, 0, 1, colorRightDown, 0, 0); + MBTriangleFanSize4->Vertices[3] = S3DVertex(left, down, 0, 0, 0, 1, colorLeftDown, 0, 0); + MBTriangleFanSize4->setDirty(scene::EBT_VERTEX); + + drawMeshBuffer(MBTriangleFanSize4); + + unlockRenderStateMode(); +} + + //! Draws a 2d line. +void CWebGL1Driver::draw2DLine(const core::position2d& start, const core::position2d& end, SColor color) +{ + if (start==end) + drawPixel(start.X, start.Y, color); + else + { + chooseMaterial2D(); + setMaterialTexture(0, 0); + + setRenderStates2DMode(color.getAlpha() < 255, false, false); + lockRenderStateMode(); + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + f32 startX = (f32)start.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 endX = (f32)end.X / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 startY = 2.f - (f32)start.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + f32 endY = 2.f - (f32)end.Y / (f32)renderTargetSize.Height * 2.f - 1.f; + + MBLinesSize2->Vertices[0] = S3DVertex(startX, startY, 0, 0, 0, 1, color, 0, 0); + MBLinesSize2->Vertices[1] = S3DVertex(endX, endY, 0, 0, 0, 1, color, 1, 1); + MBLinesSize2->setDirty(scene::EBT_VERTEX); + + drawMeshBuffer(MBLinesSize2); + + unlockRenderStateMode(); + } +} + +void CWebGL1Driver::drawPixel(u32 x, u32 y, const SColor & color) +{ + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + if (x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height) + return; + + chooseMaterial2D(); + setMaterialTexture(0, 0); + + setRenderStates2DMode(color.getAlpha() < 255, false, false); + lockRenderStateMode(); + + f32 X = (f32)x / (f32)renderTargetSize.Width * 2.f - 1.f; + f32 Y = 2.f - (f32)y / (f32)renderTargetSize.Height * 2.f - 1.f; + + MBPointsSize1->Vertices[0] = S3DVertex(X, Y, 0, 0, 0, 1, color, 0, 0); + MBPointsSize1->setDirty(scene::EBT_VERTEX); + + drawMeshBuffer(MBPointsSize1); + + unlockRenderStateMode(); +} + +void CWebGL1Driver::draw3DLine(const core::vector3df& start, const core::vector3df& end, SColor color) +{ + MBLinesSize2->Vertices[0] = S3DVertex(start.X, start.Y, start.Z, 0, 0, 1, color, 0, 0); + MBLinesSize2->Vertices[1] = S3DVertex(end.X, end.Y, end.Z, 0, 0, 1, color, 0, 0); + MBLinesSize2->setDirty(scene::EBT_VERTEX); + + drawMeshBuffer(MBLinesSize2); +} + +void CWebGL1Driver::drawStencilShadowVolume(const core::array& triangles, bool zfail, u32 debugDataVisible) +{ + static bool first = true; + if ( first ) + { + first = false; + os::Printer::log("WebGL1 driver does not yet support drawStencilShadowVolume", ELL_WARNING); + os::Printer::log(__FILE__, irr::core::stringc(__LINE__).c_str(), ELL_WARNING); + } +} + +void CWebGL1Driver::drawStencilShadow(bool clearStencilBuffer, + video::SColor leftUpEdge, + video::SColor rightUpEdge, + video::SColor leftDownEdge, + video::SColor rightDownEdge) +{ + // NOTE: Might work, but untested as drawStencilShadowVolume is not yet supported. + + if (!StencilBuffer) + return; + + chooseMaterial2D(); + setMaterialTexture(0, 0); + + setRenderStates2DMode(true, false, false); + lockRenderStateMode(); + + CacheHandler->setDepthMask(false); + CacheHandler->setColorMask(ECP_ALL); + + CacheHandler->setBlend(true); + CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_STENCIL_TEST); + glStencilFunc(GL_NOTEQUAL, 0, ~0); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + + MBTriangleFanSize4->Vertices[0] = S3DVertex(-1.f, 1.f, 0.9f, 0, 0, 1, leftDownEdge, 0, 0); + MBTriangleFanSize4->Vertices[1] = S3DVertex(1.f, 1.f, 0.9f, 0, 0, 1, leftUpEdge, 0, 0); + MBTriangleFanSize4->Vertices[2] = S3DVertex(1.f, -1.f, 0.9f, 0, 0, 1, rightUpEdge, 0, 0); + MBTriangleFanSize4->Vertices[3] = S3DVertex(-1.f, -1.f, 0.9f, 0, 0, 1, rightDownEdge, 0, 0); + MBTriangleFanSize4->setDirty(scene::EBT_VERTEX); + + drawMeshBuffer(MBTriangleFanSize4); + + unlockRenderStateMode(); + + if (clearStencilBuffer) + glClear(GL_STENCIL_BUFFER_BIT); + + glDisable(GL_STENCIL_TEST); +} + +GLenum CWebGL1Driver::getZBufferBits() const +{ + // TODO: Never used, so not sure what this was really about (zbuffer used by device? Or for RTT's?) + // If it's about device it might need a check like: GLint depthBits; glGetIntegerv(GL_DEPTH_BITS, &depthBits); + // If it's about textures it might need a check for IRR_WEBGL_depth_texture + + GLenum bits = 0; + + switch (Params.ZBufferBits) + { +#if defined(GL_OES_depth24) + case 24: + bits = GL_DEPTH_COMPONENT24_OES; + break; +#endif +#if defined(GL_OES_depth32) + case 32: + bits = GL_DEPTH_COMPONENT32_OES; + break; +#endif + default: + bits = GL_DEPTH_COMPONENT16_OES; + break; + } + + return bits; +} + +bool CWebGL1Driver::getColorFormatParameters(ECOLOR_FORMAT format, GLint& internalFormat, GLenum& pixelFormat, + GLenum& pixelType, void(**converter)(const void*, s32, void*)) const +{ + bool supported = false; + pixelFormat = GL_RGBA; + pixelType = GL_UNSIGNED_BYTE; + *converter = 0; + + switch (format) + { + case ECF_A1R5G5B5: + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_UNSIGNED_SHORT_5_5_5_1; + *converter = CColorConverter::convert_A1R5G5B5toR5G5B5A1; + break; + case ECF_R5G6B5: + supported = true; + pixelFormat = GL_RGB; + pixelType = GL_UNSIGNED_SHORT_5_6_5; + break; + case ECF_R8G8B8: + supported = true; + pixelFormat = GL_RGB; + pixelType = GL_UNSIGNED_BYTE; + break; + case ECF_A8R8G8B8: + // WebGL doesn't seem to support GL_BGRA so we always convert + supported = true; + pixelFormat = GL_RGBA; + *converter = CColorConverter::convert_A8R8G8B8toA8B8G8R8; + pixelType = GL_UNSIGNED_BYTE; + break; +#ifdef GL_EXT_texture_compression_dxt1 + case ECF_DXT1: + if ( WebGLExtensions.queryWebGLFeature(CWebGLExtensionHandler::IRR_WEBGL_compressed_texture_s3tc) ) + { + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + } + break; +#endif +#ifdef GL_EXT_texture_compression_s3tc + case ECF_DXT2: + case ECF_DXT3: + if ( WebGLExtensions.queryWebGLFeature(CWebGLExtensionHandler::IRR_WEBGL_compressed_texture_s3tc) ) + { + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + } + break; +#endif +#ifdef GL_EXT_texture_compression_s3tc + case ECF_DXT4: + case ECF_DXT5: + if ( WebGLExtensions.queryWebGLFeature(CWebGLExtensionHandler::IRR_WEBGL_compressed_texture_s3tc) ) + { + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + } + break; +#endif +#ifdef GL_IMG_texture_compression_pvrtc + case ECF_PVRTC_RGB2: + if ( WebGLExtensions.queryWebGLFeature(CWebGLExtensionHandler::IRR_WEBGL_compressed_texture_pvrtc) ) + { + supported = true; + pixelFormat = GL_RGB; + pixelType = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + } + break; +#endif +#ifdef GL_IMG_texture_compression_pvrtc + case ECF_PVRTC_ARGB2: + if ( WebGLExtensions.queryWebGLFeature(CWebGLExtensionHandler::IRR_WEBGL_compressed_texture_pvrtc) ) + { + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + } + break; +#endif +#ifdef GL_IMG_texture_compression_pvrtc + case ECF_PVRTC_RGB4: + if ( WebGLExtensions.queryWebGLFeature(CWebGLExtensionHandler::IRR_WEBGL_compressed_texture_pvrtc) ) + { + supported = true; + pixelFormat = GL_RGB; + pixelType = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + } + break; +#endif +#ifdef GL_IMG_texture_compression_pvrtc + case ECF_PVRTC_ARGB4: + if ( WebGLExtensions.queryWebGLFeature(CWebGLExtensionHandler::IRR_WEBGL_compressed_texture_pvrtc) ) + { + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + } + break; +#endif +#ifdef GL_IMG_texture_compression_pvrtc2 + case ECF_PVRTC2_ARGB2: + if ( WebGLExtensions.queryWebGLFeature(CWebGLExtensionHandler::IRR_WEBGL_compressed_texture_pvrtc) ) + { + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG; + } + break; +#endif +#ifdef GL_IMG_texture_compression_pvrtc2 + case ECF_PVRTC2_ARGB4: + if ( WebGLExtensions.queryWebGLFeature(CWebGLExtensionHandler::IRR_WEBGL_compressed_texture_pvrtc) ) + { + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG; + } + break; +#endif +#ifdef GL_OES_compressed_ETC1_RGB8_texture + case ECF_ETC1: + if ( WebGLExtensions.queryWebGLFeature(CWebGLExtensionHandler::IRR_WEBGL_compressed_texture_etc1) ) + { + supported = true; + pixelFormat = GL_RGB; + pixelType = GL_ETC1_RGB8_OES; + } + break; +#endif +#ifdef GL_ES_VERSION_3_0 // TO-DO - fix when extension name will be available + case ECF_ETC2_RGB: + supported = true; + pixelFormat = GL_RGB; + pixelType = GL_COMPRESSED_RGB8_ETC2; + break; +#endif +#ifdef GL_ES_VERSION_3_0 // TO-DO - fix when extension name will be available + case ECF_ETC2_ARGB: + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_COMPRESSED_RGBA8_ETC2_EAC; + break; +#endif + case ECF_D16: + if (WebGLExtensions.queryWebGLFeature(CWebGLExtensionHandler::IRR_WEBGL_depth_texture)) + { + supported = true; + pixelFormat = GL_DEPTH_COMPONENT; + pixelType = GL_UNSIGNED_SHORT; + } + break; + case ECF_D32: + if (WebGLExtensions.queryWebGLFeature(CWebGLExtensionHandler::IRR_WEBGL_depth_texture)) + { + // NOTE: There is still no guarantee it will return a 32 bit depth buffer. It might convert stuff internally to 16 bit :-( + supported = true; + pixelFormat = GL_DEPTH_COMPONENT; + pixelType = GL_UNSIGNED_INT; + } + break; + case ECF_D24S8: + if (WebGLExtensions.queryWebGLFeature(CWebGLExtensionHandler::IRR_WEBGL_depth_texture)) + { + supported = true; + pixelFormat = 0x84F9; // GL_DEPTH_STENCIL + pixelType = 0x84FA; // UNSIGNED_INT_24_8_WEBGL + } + break; + case ECF_R8: + // Does not seem to be supported in WebGL so far (missing GL_EXT_texture_rg) + break; + case ECF_R8G8: + // Does not seem to be supported in WebGL so far (missing GL_EXT_texture_rg) + break; + case ECF_R16: + // Does not seem to be supported in WebGL so far + break; + case ECF_R16G16: + // Does not seem to be supported in WebGL so far + break; + case ECF_R16F: + // Does not seem to be supported in WebGL so far (missing GL_EXT_texture_rg) + break; + case ECF_G16R16F: + // Does not seem to be supported in WebGL so far (missing GL_EXT_texture_rg) + break; + case ECF_A16B16G16R16F: +#if defined(GL_OES_texture_half_float) + if (WebGLExtensions.queryWebGLFeature(CWebGLExtensionHandler::IRR_OES_texture_half_float)) + { + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_HALF_FLOAT_OES ; + } +#endif + break; + case ECF_R32F: + // Does not seem to be supported in WebGL so far (missing GL_EXT_texture_rg) + break; + case ECF_G32R32F: + // Does not seem to be supported in WebGL so far (missing GL_EXT_texture_rg) + break; + case ECF_A32B32G32R32F: +#if defined(GL_OES_texture_float) + if (WebGLExtensions.queryWebGLFeature(CWebGLExtensionHandler::IRR_OES_texture_half_float)) + { + supported = true; + pixelFormat = GL_RGBA; + pixelType = GL_FLOAT ; + } +#endif + break; + default: + break; + } + + // ES 2.0 says internalFormat must match pixelFormat (chapter 3.7.1 in Spec). + // Doesn't mention if "match" means "equal" or some other way of matching, but + // some bug on Emscripten and browsing discussions by others lead me to believe + // it means they have to be equal. Note that this was different in OpenGL. + internalFormat = pixelFormat; + + return supported; +} + + +scene::SMeshBuffer* CWebGL1Driver::createSimpleMeshBuffer(irr::u32 numVertices, scene::E_PRIMITIVE_TYPE primitiveType, scene::E_HARDWARE_MAPPING vertexMappingHint, scene::E_HARDWARE_MAPPING indexMappingHint) const +{ + scene::SMeshBuffer* mbResult = new scene::SMeshBuffer(); + mbResult->Vertices.set_used(numVertices); + mbResult->Indices.set_used(numVertices); + for ( irr::u32 i=0; i < numVertices; ++i ) + mbResult->Indices[i] = i; + + mbResult->setPrimitiveType(primitiveType); + mbResult->setHardwareMappingHint(vertexMappingHint, scene::EBT_VERTEX); + mbResult->setHardwareMappingHint(indexMappingHint, scene::EBT_INDEX); + mbResult->setDirty(); + + return mbResult; +} + +bool CWebGL1Driver::genericDriverInit(const core::dimension2d& screenSize, bool stencilBuffer) +{ + Name = glGetString(GL_VERSION); + printVersion(); + + // print renderer information + VendorName = glGetString(GL_VENDOR); + os::Printer::log(VendorName.c_str(), ELL_INFORMATION); + + // load extensions + initWebGLExtensions(); + + // reset cache handler + delete CacheHandler; + CacheHandler = new COGLES2CacheHandler(this); + + StencilBuffer = stencilBuffer; + + DriverAttributes->setAttribute("MaxTextures", (s32)Feature.MaxTextureUnits); + DriverAttributes->setAttribute("MaxSupportedTextures", (s32)Feature.MaxTextureUnits); + DriverAttributes->setAttribute("MaxAnisotropy", MaxAnisotropy); + DriverAttributes->setAttribute("MaxIndices", (s32)MaxIndices); + DriverAttributes->setAttribute("MaxTextureSize", (s32)MaxTextureSize); + DriverAttributes->setAttribute("MaxTextureLODBias", MaxTextureLODBias); + DriverAttributes->setAttribute("Version", Version); + DriverAttributes->setAttribute("AntiAlias", AntiAlias); + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + UserClipPlane.reallocate(0); + + for (s32 i = 0; i < ETS_COUNT; ++i) + setTransform(static_cast(i), core::IdentityMatrix); + + setAmbientLight(SColorf(0.0f, 0.0f, 0.0f, 0.0f)); + glClearDepthf(1.0f); + + glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST); + glFrontFace(GL_CW); + + // create material renderers + createMaterialRenderers(); + + // set the renderstates + setRenderStates3DMode(); + + // set fog mode + setFog(FogColor, FogType, FogStart, FogEnd, FogDensity, PixelFog, RangeFog); + + // create matrix for flipping textures + TextureFlipMatrix.buildTextureTransform(0.0f, core::vector2df(0, 0), core::vector2df(0, 1.0f), core::vector2df(1.0f, -1.0f)); + + // We need to reset once more at the beginning of the first rendering. + // This fixes problems with intermediate changes to the material during texture load. + ResetRenderStates = true; + + testGLError(__LINE__); + + return true; +} + +void CWebGL1Driver::initWebGLExtensions() +{ + // Stuff still a little bit hacky as we derive from ES2Driver with it's own extensions. + // We only get the feature-strings from WebGLExtensions. + + getGLVersion(); + + WebGLExtensions.getGLExtensions(); + + // TODO: basically copied ES2 implementation, so not certain if 100% correct for WebGL + GLint val=0; + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &val); + Feature.MaxTextureUnits = static_cast(val); + +#ifdef GL_EXT_texture_filter_anisotropic + if ( WebGLExtensions.queryWebGLFeature(CWebGLExtensionHandler::IRR_EXT_texture_filter_anisotropic) ) + { + glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &val); + MaxAnisotropy = static_cast(val); + } +#endif + + if ( WebGLExtensions.queryWebGLFeature(CWebGLExtensionHandler::IRR_OES_element_index_uint) ) // note: WebGL2 won't need extension as that got default there + { + MaxIndices=0xffffffff; + } + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &val); + MaxTextureSize=static_cast(val); + +#ifdef GL_MAX_TEXTURE_LOD_BIAS_EXT + // TODO: Found no info about this anywhere. It's no extension in WebGL + // and GL_MAX_TEXTURE_LOD_BIAS_EXT doesn't seem to be part of gl2ext.h in emscripten + glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS_EXT, &MaxTextureLODBias); +#endif + + glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, DimAliasedLine); + glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, DimAliasedPoint); + Feature.MaxTextureUnits = core::min_(Feature.MaxTextureUnits, static_cast(MATERIAL_MAX_TEXTURES)); + Feature.MaxTextureUnits = core::min_(Feature.MaxTextureUnits, static_cast(MATERIAL_MAX_TEXTURES_USED)); + + Feature.ColorAttachment = 1; +} + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_WEBGL1_ + +namespace irr +{ +#ifndef _IRR_COMPILE_WITH_WEBGL1_ +namespace io +{ + class IFileSystem; +} +#endif +namespace video +{ + +#ifndef _IRR_COMPILE_WITH_WEBGL1_ +class IVideoDriver; +class IContextManager; +#endif + +IVideoDriver* createWebGL1Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager) +{ +#ifdef _IRR_COMPILE_WITH_WEBGL1_ + CWebGL1Driver* driver = new CWebGL1Driver(params, io, contextManager); + driver->genericDriverInit(params.WindowSize, params.Stencilbuffer); // don't call in constructor, it uses virtual function calls of driver + return driver; +#else + return 0; +#endif // _IRR_COMPILE_WITH_WEBGL1_ +} + +} // end namespace +} // end namespace diff --git a/source/Irrlicht/CWebGL1Driver.h b/source/Irrlicht/CWebGL1Driver.h new file mode 100644 index 00000000..dd1dad82 --- /dev/null +++ b/source/Irrlicht/CWebGL1Driver.h @@ -0,0 +1,146 @@ +// Copyright (C) 2017 Michael Zeilfelder +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __C_WEBGL1_DRIVER_H_INCLUDED__ +#define __C_WEBGL1_DRIVER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#include "SIrrCreationParameters.h" + +#ifdef _IRR_COMPILE_WITH_WEBGL1_ + +#include "COGLES2Driver.h" +#include "CWebGLExtensionHandler.h" +#include "CMeshBuffer.h" +#include "EHardwareBufferFlags.h" + +namespace irr +{ +namespace video +{ + //! WebGL friendly subset of OGL ES 2.0. + //! Written for use with emscripten + class CWebGL1Driver : public COGLES2Driver + { + friend class COpenGLCoreTexture; + friend IVideoDriver* createWebGL1Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager); + + protected: + //! constructor + CWebGL1Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager); + + public: + + //! destructor + virtual ~CWebGL1Driver(); + + //! Returns type of video driver + virtual E_DRIVER_TYPE getDriverType() const _IRR_OVERRIDE_; + + //! Is VBO recommended on this mesh? + virtual bool isHardwareBufferRecommend(const scene::IMeshBuffer* mb) _IRR_OVERRIDE_ + { + // All buffers must be bound, WebGL doesn't allow sending unbound buffers at all. + return true; + } + + //! draws a vertex primitive list + virtual void drawVertexPrimitiveList(const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) _IRR_OVERRIDE_; + + //! Draws a mesh buffer + virtual void drawMeshBuffer(const scene::IMeshBuffer* mb) _IRR_OVERRIDE_; + + 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) _IRR_OVERRIDE_; + + 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) _IRR_OVERRIDE_; + + // internally used + virtual void draw2DImage(const video::ITexture* texture, u32 layer, bool flip) _IRR_OVERRIDE_; + + //! draws a set of 2d images + virtual void draw2DImageBatch(const video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, s32 kerningWidth = 0, + const core::rect* clipRect = 0, + SColor color = SColor(255, 255, 255, 255), + bool useAlphaChannelOfTexture = false) _IRR_OVERRIDE_; + + void draw2DImageBatch(const video::ITexture* texture, + const core::array >& positions, + const core::array >& sourceRects, + const core::rect* clipRect, + SColor color, + bool useAlphaChannelOfTexture) _IRR_OVERRIDE_; + + //! draw an 2d rectangle + virtual void draw2DRectangle(SColor color, const core::rect& pos, + const core::rect* clip = 0) _IRR_OVERRIDE_; + + //!Draws an 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) _IRR_OVERRIDE_; + + //! Draws a 2d line. + virtual void draw2DLine(const core::position2d& start, + const core::position2d& end, + SColor color = SColor(255, 255, 255, 255)) _IRR_OVERRIDE_; + + //! Draws a single pixel + virtual void drawPixel(u32 x, u32 y, const SColor & color) _IRR_OVERRIDE_; + + //! Draws a 3d line. + virtual void draw3DLine(const core::vector3df& start, + const core::vector3df& end, + SColor color = SColor(255, 255, 255, 255)) _IRR_OVERRIDE_; + + //! Draws a shadow volume into the stencil buffer. + virtual void drawStencilShadowVolume(const core::array& triangles, bool zfail, u32 debugDataVisible=0) _IRR_OVERRIDE_; + + //! Fills the stencil shadow with color. + virtual void drawStencilShadow(bool clearStencilBuffer=false, + video::SColor leftUpEdge = video::SColor(0,0,0,0), + video::SColor rightUpEdge = video::SColor(0,0,0,0), + video::SColor leftDownEdge = video::SColor(0,0,0,0), + video::SColor rightDownEdge = video::SColor(0,0,0,0)) _IRR_OVERRIDE_; + + //! Get ZBuffer bits. + virtual GLenum getZBufferBits() const _IRR_OVERRIDE_; + + virtual bool getColorFormatParameters(ECOLOR_FORMAT format, GLint& internalFormat, GLenum& pixelFormat, + GLenum& pixelType, void(**converter)(const void*, s32, void*)) const _IRR_OVERRIDE_; + + protected: + // create a meshbuffer which has as many vertices as indices + scene::SMeshBuffer* createSimpleMeshBuffer(irr::u32 numVertices, scene::E_PRIMITIVE_TYPE primitiveType, scene::E_HARDWARE_MAPPING vertexMappingHint=scene::EHM_STREAM, scene::E_HARDWARE_MAPPING indexMappingHint=scene::EHM_STATIC) const; + + virtual bool genericDriverInit(const core::dimension2d& screenSize, bool stencilBuffer) _IRR_OVERRIDE_; + void initWebGLExtensions(); + + private: + // CWebGL1Driver is derived from COGLES2Driver so it already got an extension handler from that. + // But we shouldn't use other extensions most of the time as there are minor differences. + CWebGLExtensionHandler WebGLExtensions; + + // Because we can't have unbound buffers in webgl we give drawing functions bound buffers to use + scene::SMeshBuffer* MBTriangleFanSize4; + scene::SMeshBuffer* MBLinesSize2; + scene::SMeshBuffer* MBPointsSize1; + }; + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_WEBGL1_ + +#endif // __C_WEBGL1_DRIVER_H_INCLUDED__ diff --git a/source/Irrlicht/CWebGLExtensionHandler.h b/source/Irrlicht/CWebGLExtensionHandler.h new file mode 100644 index 00000000..67ffaf75 --- /dev/null +++ b/source/Irrlicht/CWebGLExtensionHandler.h @@ -0,0 +1,182 @@ +// Copyright (C) 2017 Michael Zeilfelder +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __E_WEGL_EXTENSION_HANDLER_H_INCLUDED__ +#define __E_WEGL_EXTENSION_HANDLER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#if defined(_IRR_COMPILE_WITH_WEBGL1_) // Note: should also work with WebGL2 once we add that to Irrlicht + +#include "COpenGLCoreFeature.h" + +namespace irr +{ +namespace video +{ + // Extension handling for WebGL. + class CWebGLExtensionHandler + { + public: + // Enums used internally to check for WebGL extensions quickly. + // We buffer all extensions on start once in an array. + enum EWebGLFeatures + { + // If you update this enum also update the corresponding WebGLFeatureStrings string-array + // Last updated was up to (including) extension number 35 (EXT_float_blend) + + // Khronos ratified WebGL Extensions + IRR_OES_texture_float, // 1 + IRR_OES_texture_half_float, // 2 + IRR_WEBGL_lose_context, // 3 + IRR_OES_standard_derivatives, // 4 + IRR_OES_vertex_array_object, // 5 + IRR_WEBGL_debug_renderer_info, // 6 + IRR_WEBGL_debug_shaders, // 7 + IRR_WEBGL_compressed_texture_s3tc, // 8 + IRR_WEBGL_depth_texture, // 9 + IRR_OES_element_index_uint, // 10 + IRR_EXT_texture_filter_anisotropic, // 11 + IRR_EXT_frag_depth, // 16 + IRR_WEBGL_draw_buffers, // 18 + IRR_ANGLE_instanced_arrays, // 19 + IRR_OES_texture_float_linear, // 20 + IRR_OES_texture_half_float_linear, // 21 + IRR_EXT_blend_minmax, // 25 + IRR_EXT_shader_texture_lod, // 27 + + // Community approved WebGL Extensions + IRR_WEBGL_compressed_texture_atc, // 12 + IRR_WEBGL_compressed_texture_pvrtc, // 13 + IRR_EXT_color_buffer_half_float, // 14 + IRR_WEBGL_color_buffer_float, // 15 + IRR_EXT_sRGB, // 17 + IRR_WEBGL_compressed_texture_etc1, // 24 + IRR_EXT_disjoint_timer_query, // 26 + IRR_WEBGL_compressed_texture_etc, // 29 + IRR_WEBGL_compressed_texture_astc, // 30 + IRR_EXT_color_buffer_float, // 31 + IRR_WEBGL_compressed_texture_s3tc_srgb, // 32 + IRR_EXT_disjoint_timer_query_webgl2, // 33 + + // Draft WebGL Extensions + IRR_WEBGL_shared_resources, // 22 + IRR_WEBGL_security_sensitive_resources, // 23 + IRR_OES_fbo_render_mipmap, // 28 + IRR_WEBGL_get_buffer_sub_data_async, // 34 + IRR_EXT_float_blend, // 35 + + IRR_WEBGL_Feature_Count + }; + + CWebGLExtensionHandler() + { + for (u32 i = 0; i < IRR_WEBGL_Feature_Count; ++i) + FeatureAvailable[i] = false; + } + + virtual ~CWebGLExtensionHandler() {} + + void dump() const + { + for (u32 i = 0; i < IRR_WEBGL_Feature_Count; ++i) + os::Printer::log(getFeatureString(i), FeatureAvailable[i] ? " true" : " false"); + } + + bool queryWebGLFeature(EWebGLFeatures feature) const + { + return FeatureAvailable[feature]; + } + + void getGLExtensions() + { + core::stringc extensions = glGetString(GL_EXTENSIONS); + os::Printer::log(extensions.c_str()); + + const u32 size = extensions.size() + 1; + c8* str = new c8[size]; + strncpy(str, extensions.c_str(), extensions.size()); + str[extensions.size()] = ' '; + c8* p = str; + + for (u32 i=0; i + +namespace irr +{ +namespace io +{ + + +CWriteFile::CWriteFile(const io::path& fileName, bool append) +: FileSize(0) +{ + #ifdef _DEBUG + setDebugName("CWriteFile"); + #endif + + Filename = fileName; + openFile(append); +} + + + +CWriteFile::~CWriteFile() +{ + if (File) + fclose(File); +} + + + +//! returns if file is open +inline bool CWriteFile::isOpen() const +{ + return File != 0; +} + + + +//! returns how much was read +size_t CWriteFile::write(const void* buffer, size_t sizeToWrite) +{ + if (!isOpen()) + return 0; + + return fwrite(buffer, 1, sizeToWrite, File); +} + + + +//! 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 CWriteFile::seek(long finalPos, bool relativeMovement) +{ + if (!isOpen()) + return false; + + return fseek(File, finalPos, relativeMovement ? SEEK_CUR : SEEK_SET) == 0; +} + + + +//! returns where in the file we are. +long CWriteFile::getPos() const +{ + return ftell(File); +} + + + +//! opens the file +void CWriteFile::openFile(bool append) +{ + if (Filename.size() == 0) + { + File = 0; + return; + } + +#if defined(_IRR_WCHAR_FILESYSTEM) + File = _wfopen(Filename.c_str(), append ? L"ab" : L"wb"); +#else + File = fopen(Filename.c_str(), append ? "ab" : "wb"); +#endif + + if (File) + { + // get FileSize + + fseek(File, 0, SEEK_END); + FileSize = ftell(File); + fseek(File, 0, SEEK_SET); + } +} + + + +//! returns name of file +const io::path& CWriteFile::getFileName() const +{ + return Filename; +} + +//! Flush the content of the buffer in the file +bool CWriteFile::flush() +{ + if (!isOpen()) + return false; + + return fflush(File) == 0; // 0 indicates success, otherwise EOF and errno is set +} + +IWriteFile* CWriteFile::createWriteFile(const io::path& fileName, bool append) +{ + CWriteFile* file = new CWriteFile(fileName, append); + if (file->isOpen()) + return file; + + file->drop(); + return 0; +} + + +} // end namespace io +} // end namespace irr + diff --git a/source/Irrlicht/CWriteFile.h b/source/Irrlicht/CWriteFile.h new file mode 100644 index 00000000..d0e2c804 --- /dev/null +++ b/source/Irrlicht/CWriteFile.h @@ -0,0 +1,64 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_WRITE_FILE_H_INCLUDED__ +#define __C_WRITE_FILE_H_INCLUDED__ + +#include +#include "IWriteFile.h" +#include "irrString.h" + +namespace irr +{ + +namespace io +{ + + /*! + Class for writing a real file to disk. + */ + class CWriteFile : public IWriteFile + { + public: + + CWriteFile(const io::path& fileName, bool append); + + virtual ~CWriteFile(); + + //! Reads an amount of bytes from the file. + virtual size_t write(const void* buffer, size_t sizeToWrite) _IRR_OVERRIDE_; + + //! Changes position in file, returns true if successful. + virtual bool seek(long finalPos, bool relativeMovement = false) _IRR_OVERRIDE_; + + //! Returns the current position in the file. + virtual long getPos() const _IRR_OVERRIDE_; + + //! Returns name of file. + virtual const io::path& getFileName() const _IRR_OVERRIDE_; + + //! Flush the content of the buffer in the file + virtual bool flush() _IRR_OVERRIDE_; + + //! returns if file is open + bool isOpen() const; + + //! creator method + static IWriteFile* createWriteFile(const io::path& fileName, bool append); + + private: + + //! opens the file + void openFile(bool append); + + io::path Filename; + FILE* File; + long FileSize; + }; + +} // end namespace io +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CXMLReader.cpp b/source/Irrlicht/CXMLReader.cpp new file mode 100644 index 00000000..db5a9443 --- /dev/null +++ b/source/Irrlicht/CXMLReader.cpp @@ -0,0 +1,84 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CXMLReader.h" + +#ifdef _IRR_COMPILE_WITH_XML_ +#include "CXMLReaderImpl.h" +#include "IReadFile.h" + +namespace irr +{ +namespace io +{ + //! Irrlicht implementation of the file read callback for the xml parser + class CIrrXMLFileReadCallBack : public IFileReadCallBack + { + public: + + //! construct from FILE pointer + CIrrXMLFileReadCallBack(IReadFile* file) + : ReadFile(file) + { + ReadFile->grab(); + } + + //! destructor + virtual ~CIrrXMLFileReadCallBack() + { + ReadFile->drop(); + } + + //! Reads an amount of bytes from the file. + virtual int read(void* buffer, int sizeToRead) _IRR_OVERRIDE_ + { + return (int)ReadFile->read(buffer, sizeToRead); + } + + //! Returns size of file in bytes + virtual long getSize() const _IRR_OVERRIDE_ + { + return ReadFile->getSize(); + } + + private: + + IReadFile* ReadFile; + }; // end class CMyXMLFileReadCallBack + + + // now create an implementation for IXMLReader using irrXML. + + //! Creates an instance of a wide character xml parser. + IXMLReader* createIXMLReader(IReadFile* file) + { + if (!file) + return 0; + + return new CXMLReaderImpl(new CIrrXMLFileReadCallBack(file)); + } + + //! Creates an instance of an UFT-8 or ASCII character xml parser. + IXMLReaderUTF8* createIXMLReaderUTF8(IReadFile* file) + { + if (!file) + return 0; + + return new CXMLReaderImpl(new CIrrXMLFileReadCallBack(file)); + } + +} // end namespace +} // end namespace +#else // not _IRR_COMPILE_WITH_XML_ +#include "os.h" +namespace irr +{ + +void noXML() +{ + irr::os::Printer::log("XML support disabled in IrrCompileConfig.", irr::ELL_ERROR); +} + +} // end namespace +#endif // _IRR_COMPILE_WITH_XML_ diff --git a/source/Irrlicht/CXMLReader.h b/source/Irrlicht/CXMLReader.h new file mode 100644 index 00000000..328b92a8 --- /dev/null +++ b/source/Irrlicht/CXMLReader.h @@ -0,0 +1,30 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_XML_READER_H_INCLUDED__ +#define __C_XML_READER_H_INCLUDED__ + +#include "IXMLReader.h" + +namespace irr +{ +#ifdef _IRR_COMPILE_WITH_XML_ +namespace io +{ + class IReadFile; + + //! creates an IXMLReader + IXMLReader* createIXMLReader(IReadFile* file); + + //! creates an IXMLReader + IXMLReaderUTF8* createIXMLReaderUTF8(IReadFile* file); +} // end namespace irr +#else // _IRR_COMPILE_WITH_XML_ + //! print a message that Irrlicht is compiled without _IRR_COMPILE_WITH_XML_ + void noXML(); +#endif // _IRR_COMPILE_WITH_XML_ +} // end namespace io + +#endif + diff --git a/source/Irrlicht/CXMLReaderImpl.h b/source/Irrlicht/CXMLReaderImpl.h new file mode 100644 index 00000000..6f1192c6 --- /dev/null +++ b/source/Irrlicht/CXMLReaderImpl.h @@ -0,0 +1,821 @@ +// Copyright (C) 2002-2012 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 + +#ifndef __ICXML_READER_IMPL_H_INCLUDED__ +#define __ICXML_READER_IMPL_H_INCLUDED__ + +#include "irrXML.h" +#include "irrString.h" +#include "irrArray.h" +#include "fast_atof.h" + +#ifdef _DEBUG +#define IRR_DEBUGPRINT(x) printf((x)); +#else // _DEBUG +#define IRR_DEBUGPRINT(x) +#endif // _DEBUG + + +namespace irr +{ +namespace io +{ + + +//! implementation of the IrrXMLReader +template +class CXMLReaderImpl : public IIrrXMLReader +{ +public: + + //! Constructor + CXMLReaderImpl(IFileReadCallBack* callback, bool deleteCallBack = true) + : IgnoreWhitespaceText(true), TextData(0), P(0), TextBegin(0), TextSize(0), CurrentNodeType(EXN_NONE), + SourceFormat(ETF_ASCII), TargetFormat(ETF_ASCII), IsEmptyElement(false) + { + if (!callback) + return; + + storeTargetFormat(); + + // read whole xml file + + readFile(callback); + + // clean up + + if (deleteCallBack) + delete callback; + + // create list with special characters + + createSpecialCharacterList(); + + // set pointer to text begin + P = TextBegin; + } + + + //! Destructor + virtual ~CXMLReaderImpl() + { + delete [] TextData; + } + + + //! Reads forward to the next xml node. + //! \return Returns false, if there was no further node. + virtual bool read() _IRR_OVERRIDE_ + { + // if not end reached, parse the node + if (P && ((unsigned int)(P - TextBegin) < TextSize - 1) && (*P != 0)) + { + return parseCurrentNode(); + } + + return false; + } + + + //! Returns the type of the current XML node. + virtual EXML_NODE getNodeType() const _IRR_OVERRIDE_ + { + return CurrentNodeType; + } + + + //! Returns attribute count of the current XML node. + virtual unsigned int getAttributeCount() const _IRR_OVERRIDE_ + { + return Attributes.size(); + } + + + //! Returns name of an attribute. + virtual const char_type* getAttributeName(int idx) const _IRR_OVERRIDE_ + { + if ((u32)idx >= Attributes.size()) + return 0; + + return Attributes[idx].Name.c_str(); + } + + + //! Returns the value of an attribute. + virtual const char_type* getAttributeValue(int idx) const _IRR_OVERRIDE_ + { + if ((unsigned int)idx >= Attributes.size()) + return 0; + + return Attributes[idx].Value.c_str(); + } + + + //! Returns the value of an attribute. + virtual const char_type* getAttributeValue(const char_type* name) const _IRR_OVERRIDE_ + { + const SAttribute* attr = getAttributeByName(name); + if (!attr) + return 0; + + return attr->Value.c_str(); + } + + + //! Returns the value of an attribute + virtual const char_type* getAttributeValueSafe(const char_type* name) const _IRR_OVERRIDE_ + { + const SAttribute* attr = getAttributeByName(name); + if (!attr) + return EmptyString.c_str(); + + return attr->Value.c_str(); + } + + + + //! Returns the value of an attribute as integer. + virtual int getAttributeValueAsInt(const char_type* name, int defaultNotFound) const _IRR_OVERRIDE_ + { + const SAttribute* attr = getAttributeByName(name); + if (!attr) + return defaultNotFound; + + core::stringc c(attr->Value.c_str()); + return core::strtol10(c.c_str()); + } + + + //! Returns the value of an attribute as integer. + virtual int getAttributeValueAsInt(int idx, int defaultNotFound) const _IRR_OVERRIDE_ + { + const char_type* attrvalue = getAttributeValue(idx); + if (!attrvalue) + return defaultNotFound; + + core::stringc c(attrvalue); + return core::strtol10(c.c_str()); + } + + + //! Returns the value of an attribute as float. + virtual float getAttributeValueAsFloat(const char_type* name, float defaultNotFound) const _IRR_OVERRIDE_ + { + const SAttribute* attr = getAttributeByName(name); + if (!attr) + return defaultNotFound; + + core::stringc c = attr->Value.c_str(); + return core::fast_atof(c.c_str()); + } + + + //! Returns the value of an attribute as float. + virtual float getAttributeValueAsFloat(int idx, float defaultNotFound) const _IRR_OVERRIDE_ + { + const char_type* attrvalue = getAttributeValue(idx); + if (!attrvalue) + return defaultNotFound; + + core::stringc c = attrvalue; + return core::fast_atof(c.c_str()); + } + + + //! Returns the name of the current node. + virtual const char_type* getNodeName() const _IRR_OVERRIDE_ + { + return NodeName.c_str(); + } + + + //! Returns data of the current node. + virtual const char_type* getNodeData() const _IRR_OVERRIDE_ + { + return NodeName.c_str(); + } + + + //! Returns if an element is an empty element, like + virtual bool isEmptyElement() const _IRR_OVERRIDE_ + { + return IsEmptyElement; + } + + //! Returns format of the source xml file. + virtual ETEXT_FORMAT getSourceFormat() const _IRR_OVERRIDE_ + { + return SourceFormat; + } + + //! Returns format of the strings returned by the parser. + virtual ETEXT_FORMAT getParserFormat() const _IRR_OVERRIDE_ + { + return TargetFormat; + } + +private: + + // Reads the current xml node + // return false if no further node is found + bool parseCurrentNode() + { + char_type* start = P; + + // more forward until '<' found + while(*P != L'<' && *P) + ++P; + + // not a node, so return false + if (!*P) + return false; + + if (P - start > 0) + { + // we found some text, store it + if (setText(start, P)) + return true; + } + + ++P; + + // based on current token, parse and report next element + switch(*P) + { + case L'/': + parseClosingXMLElement(); + break; + case L'?': + ignoreDefinition(); + break; + case L'!': + if (!parseCDATA()) + parseComment(); + break; + default: + parseOpeningXMLElement(); + break; + } + return true; + } + + + //! sets the state that text was found. Returns true if set should be set + bool setText(char_type* start, char_type* end) + { + // By default xml preserves all whitespace. But Irrlicht dropped some whitespace by default + // in the past which did lead to OS dependent behavior. We just ignore all whitespace for now + // as it's the closest to fixing behavior without breaking downward compatibility too much. + if ( IgnoreWhitespaceText ) + { + char_type* p = start; + for(; p != end; ++p) + if (!isWhiteSpace(*p)) + break; + + if (p == end) + return false; + } + + // set current text to the parsed text, and replace xml special characters + core::string s(start, (int)(end - start)); + NodeName = replaceSpecialCharacters(s); + + // current XML node type is text + CurrentNodeType = EXN_TEXT; + + return true; + } + + + + //! ignores an xml definition like + void ignoreDefinition() + { + CurrentNodeType = EXN_UNKNOWN; + + // move until end marked with '>' reached + while(*P != L'>') + ++P; + + ++P; + } + + + //! parses a comment + void parseComment() + { + CurrentNodeType = EXN_COMMENT; + P += 1; + + char_type *pCommentBegin = P; + + int count = 1; + + // move until end of comment reached + while(count) + { + if (*P == L'>') + --count; + else + if (*P == L'<') + ++count; + + ++P; + } + + P -= 3; + NodeName = core::string(pCommentBegin+2, (int)(P - pCommentBegin-2)); + P += 3; + } + + + //! parses an opening xml element and reads attributes + void parseOpeningXMLElement() + { + CurrentNodeType = EXN_ELEMENT; + IsEmptyElement = false; + Attributes.clear(); + + // find name + const char_type* startName = P; + + // find end of element + while(*P != L'>' && !isWhiteSpace(*P)) + ++P; + + const char_type* endName = P; + + // find Attributes + while(*P != L'>') + { + if (isWhiteSpace(*P)) + ++P; + else + { + if (*P != L'/') + { + // we've got an attribute + + // read the attribute names + const char_type* attributeNameBegin = P; + + while(!isWhiteSpace(*P) && *P != L'=') + ++P; + + const char_type* attributeNameEnd = P; + ++P; + + // read the attribute value + // check for quotes and single quotes, thx to murphy + while( (*P != L'\"') && (*P != L'\'') && *P) + ++P; + + if (!*P) // malformatted xml file + return; + + const char_type attributeQuoteChar = *P; + + ++P; + const char_type* attributeValueBegin = P; + + while(*P != attributeQuoteChar && *P) + ++P; + + if (!*P) // malformatted xml file + return; + + const char_type* attributeValueEnd = P; + ++P; + + SAttribute attr; + attr.Name = core::string(attributeNameBegin, + (int)(attributeNameEnd - attributeNameBegin)); + + core::string s(attributeValueBegin, + (int)(attributeValueEnd - attributeValueBegin)); + + attr.Value = replaceSpecialCharacters(s); + Attributes.push_back(attr); + } + else + { + // tag is closed directly + ++P; + IsEmptyElement = true; + break; + } + } + } + + // check if this tag is closing directly + if (endName > startName && *(endName-1) == L'/') + { + // directly closing tag + IsEmptyElement = true; + endName--; + } + + NodeName = core::string(startName, (int)(endName - startName)); + + ++P; + } + + + //! parses an closing xml tag + void parseClosingXMLElement() + { + CurrentNodeType = EXN_ELEMENT_END; + IsEmptyElement = false; + Attributes.clear(); + + ++P; + const char_type* pBeginClose = P; + + while(*P != L'>') + ++P; + + NodeName = core::string(pBeginClose, (int)(P - pBeginClose)); + ++P; + } + + //! parses a possible CDATA section, returns false if begin was not a CDATA section + bool parseCDATA() + { + if (*(P+1) != L'[') + return false; + + CurrentNodeType = EXN_CDATA; + + // skip '' && + (*(P-1) == L']') && + (*(P-2) == L']')) + { + cDataEnd = P - 2; + } + + ++P; + } + + if ( cDataEnd ) + NodeName = core::string(cDataBegin, (int)(cDataEnd - cDataBegin)); + else + NodeName = ""; + + return true; + } + + + // structure for storing attribute-name pairs + struct SAttribute + { + core::string Name; + core::string Value; + }; + + // finds a current attribute by name, returns 0 if not found + const SAttribute* getAttributeByName(const char_type* name) const + { + if (!name) + return 0; + + core::string n = name; + + for (int i=0; i<(int)Attributes.size(); ++i) + if (Attributes[i].Name == n) + return &Attributes[i]; + + return 0; + } + + // replaces xml special characters in a string and creates a new one + core::string replaceSpecialCharacters( + const core::string& origstr) + { + int pos = origstr.findFirst(L'&'); + int oldPos = 0; + + if (pos == -1) + return origstr; + + core::string newstr; + + while(pos != -1 && pos < (int)origstr.size()-2) + { + // check if it is one of the special characters + + int specialChar = -1; + for (int i=0; i<(int)SpecialCharacters.size(); ++i) + { + const char_type* p = &origstr.c_str()[pos]+1; + + if (equalsn(&SpecialCharacters[i][1], p, SpecialCharacters[i].size()-1)) + { + specialChar = i; + break; + } + } + + if (specialChar != -1) + { + newstr.append(origstr.subString(oldPos, pos - oldPos)); + newstr.append(SpecialCharacters[specialChar][0]); + pos += SpecialCharacters[specialChar].size(); + } + else + { + newstr.append(origstr.subString(oldPos, pos - oldPos + 1)); + pos += 1; + } + + // find next & + oldPos = pos; + pos = origstr.findNext(L'&', pos); + } + + if (oldPos < (int)origstr.size()-1) + newstr.append(origstr.subString(oldPos, origstr.size()-oldPos)); + + return newstr; + } + + + + //! reads the xml file and converts it into the wanted character format. + bool readFile(IFileReadCallBack* callback) + { + long size = callback->getSize(); + if (size<0) + return false; + // We need four terminating 0's at the end. + // For ASCII we need 1 0's, for UTF-16 2, for UTF-32 4. + size += 4; + + char* data8 = new char[size]; + + if (!callback->read(data8, size-4)) + { + delete [] data8; + return false; + } + + // add zeros at end + + memset(data8+size-4, 0, 4); + + char16* data16 = reinterpret_cast(data8); + char32* data32 = reinterpret_cast(data8); + + // now we need to convert the data to the desired target format + // based on the byte order mark. + + const unsigned char UTF8[] = {0xEF, 0xBB, 0xBF}; // 0xEFBBBF; + const u16 UTF16_BE = 0xFFFE; + const u16 UTF16_LE = 0xFEFF; + const u32 UTF32_BE = 0xFFFE0000; + const u32 UTF32_LE = 0x0000FEFF; + + // check source for all utf versions and convert to target data format + + if (size >= 4 && data32[0] + == static_cast(UTF32_BE)) + { + // UTF-32, big endian + SourceFormat = ETF_UTF32_BE; + convertTextData(data32+1, data8, (size/4)-1); // data32+1 because we need to skip the header + } + else + if (size >= 4 && data32[0] == static_cast(UTF32_LE)) + { + // UTF-32, little endian + SourceFormat = ETF_UTF32_LE; + convertTextData(data32+1, data8, (size/4)-1); // data32+1 because we need to skip the header + } + else + if (size >= 2 && data16[0] == UTF16_BE) + { + // UTF-16, big endian + SourceFormat = ETF_UTF16_BE; + convertTextData(data16+1, data8, (size/2)-1); // data16+1 because we need to skip the header + } + else + if (size >= 2 && data16[0] == UTF16_LE) + { + // UTF-16, little endian + SourceFormat = ETF_UTF16_LE; + convertTextData(data16+1, data8, (size/2)-1); // data16+1 because we need to skip the header + } + else + if (size >= 3 && memcmp(data8,UTF8,3)==0) + { + // UTF-8 + SourceFormat = ETF_UTF8; + convertTextData(data8+3, data8, size-3); // data8+3 because we need to skip the header + } + else + { + // ASCII + SourceFormat = ETF_ASCII; + convertTextData(data8, data8, size); + } + + return true; + } + + + //! converts the text file into the desired format. + /** \param source: begin of the text (without byte order mark) + \param pointerToStore: pointer to text data block which can be + stored or deleted based on the nesessary conversion. + \param sizeWithoutHeader: Text size in characters without header + */ + template + void convertTextData(src_char_type* source, char* pointerToStore, int sizeWithoutHeader) + { + // convert little to big endian if necessary + if (sizeof(src_char_type) > 1 && + isLittleEndian(TargetFormat) != isLittleEndian(SourceFormat)) + convertToLittleEndian(source); + + // check if conversion is necessary: + if (sizeof(src_char_type) == sizeof(char_type)) + { + // no need to convert + TextBegin = (char_type*)source; + TextData = (char_type*)pointerToStore; + TextSize = sizeWithoutHeader; + } + else + { + // convert source into target data format. + // TODO: implement a real conversion. This one just + // copies bytes. This is a problem when there are + // unicode symbols using more than one character. + + TextData = new char_type[sizeWithoutHeader]; + + if ( sizeof(src_char_type) == 1 ) + { + // we have to cast away negative numbers or results might add the sign instead of just doing a copy + for (int i=0; i(static_cast(source[i])); + } + } + else + { + for (int i=0; i(source[i]); + } + TextBegin = TextData; + TextSize = sizeWithoutHeader; + + // delete original data because no longer needed + delete [] pointerToStore; + } + } + + //! converts whole text buffer to little endian + template + void convertToLittleEndian(src_char_type* t) + { + if (sizeof(src_char_type) == 4) + { + // 32 bit + + while(*t) + { + *t = ((*t & 0xff000000) >> 24) | + ((*t & 0x00ff0000) >> 8) | + ((*t & 0x0000ff00) << 8) | + ((*t & 0x000000ff) << 24); + ++t; + } + } + else + { + // 16 bit + + while(*t) + { + *t = (*t >> 8) | (*t << 8); + ++t; + } + } + } + + //! returns if a format is little endian + inline bool isLittleEndian(ETEXT_FORMAT f) + { + return f == ETF_ASCII || + f == ETF_UTF8 || + f == ETF_UTF16_LE || + f == ETF_UTF32_LE; + } + + + //! returns true if a character is whitespace + inline bool isWhiteSpace(char_type c) + { + return (c==' ' || c=='\t' || c=='\n' || c=='\r'); + } + + + //! generates a list with xml special characters + void createSpecialCharacterList() + { + // list of strings containing special symbols, + // the first character is the special character, + // the following is the symbol string without trailing &. + + SpecialCharacters.push_back("&"); + SpecialCharacters.push_back("gt;"); + SpecialCharacters.push_back("\"quot;"); + SpecialCharacters.push_back("'apos;"); + + } + + + //! compares the first n characters of the strings + bool equalsn(const char_type* str1, const char_type* str2, int len) + { + int i; + for(i=0; str1[i] && str2[i] && i < len; ++i) + if (str1[i] != str2[i]) + return false; + + // if one (or both) of the strings was smaller then they + // are only equal if they have the same length + return (i == len) || (str1[i] == 0 && str2[i] == 0); + } + + + //! stores the target text format + void storeTargetFormat() + { + // get target format. We could have done this using template specialization, + // but VisualStudio 6 don't like it and we want to support it. + + switch(sizeof(char_type)) + { + case 1: + TargetFormat = ETF_UTF8; + break; + case 2: + TargetFormat = ETF_UTF16_LE; + break; + case 4: + TargetFormat = ETF_UTF32_LE; + break; + default: + TargetFormat = ETF_ASCII; // should never happen. + } + } + + + // instance variables: + bool IgnoreWhitespaceText; // do not return EXN_TEXT nodes for pure whitespace + char_type* TextData; // data block of the text file + char_type* P; // current point in text to parse + char_type* TextBegin; // start of text to parse + unsigned int TextSize; // size of text to parse in characters, not bytes + + EXML_NODE CurrentNodeType; // type of the currently parsed node + ETEXT_FORMAT SourceFormat; // source format of the xml file + ETEXT_FORMAT TargetFormat; // output format of this parser + + core::string NodeName; // name of the node currently in - also used for text + core::string EmptyString; // empty string to be returned by getSafe() methods + + bool IsEmptyElement; // is the currently parsed node empty? + + core::array< core::string > SpecialCharacters; // see createSpecialCharacterList() + + core::array Attributes; // attributes of current element + +}; // end CXMLReaderImpl + + +} // end namespace +} // end namespace + +#endif diff --git a/source/Irrlicht/CXMLWriter.cpp b/source/Irrlicht/CXMLWriter.cpp new file mode 100644 index 00000000..4e9d6900 --- /dev/null +++ b/source/Irrlicht/CXMLWriter.cpp @@ -0,0 +1,472 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CXMLWriter.h" + +#ifdef _IRR_COMPILE_WITH_XML_ + +#include +#include "irrString.h" +#include "IrrCompileConfig.h" + +namespace irr +{ +namespace io +{ + +//! creates an IXMLReader +IXMLWriter* createIXMLWriter(IWriteFile* file) +{ + return new CXMLWriter(file); +} + +//! creates an IXMLReader +IXMLWriterUTF8* createIXMLWriterUTF8(IWriteFile* file) +{ + return new CXMLWriterUTF8(file); +} + +//! Constructor +CXMLWriter::CXMLWriter(IWriteFile* file) +: CXMLWriterCommon(file) +{ + #ifdef _DEBUG + setDebugName("CXMLWriter"); + #endif +} + + +//! Writes a xml 1.0 header like +void CXMLWriter::writeXMLHeader() +{ + if (!File) + return; + + if (sizeof(wchar_t)==2) + { + const u16 h = 0xFEFF; + File->write(&h, 2); + } + else + { + const u32 h = 0x0000FEFF; + File->write(&h, sizeof(wchar_t)); + } + + const wchar_t* const p = L""; + File->write(p, wcslen(p)*sizeof(wchar_t)); + + writeLineBreak(); + TextWrittenLast = false; +} + + + +//! Writes an xml element with maximal 5 attributes +void CXMLWriter::writeElement(const wchar_t* name, bool empty, + const wchar_t* attr1Name, const wchar_t* attr1Value, + const wchar_t* attr2Name, const wchar_t* attr2Value, + const wchar_t* attr3Name, const wchar_t* attr3Value, + const wchar_t* attr4Name, const wchar_t* attr4Value, + const wchar_t* attr5Name, const wchar_t* attr5Value) +{ + if (!File || !name) + return; + + if (Tabs > 0) + { + for (int i=0; iwrite(L"\t", sizeof(wchar_t)); + } + + // write name + + File->write(L"<", sizeof(wchar_t)); + File->write(name, wcslen(name)*sizeof(wchar_t)); + + // write attributes + + writeAttribute(attr1Name, attr1Value); + writeAttribute(attr2Name, attr2Value); + writeAttribute(attr3Name, attr3Value); + writeAttribute(attr4Name, attr4Value); + writeAttribute(attr5Name, attr5Value); + + // write closing tag + if (empty) + File->write(L" />", 3*sizeof(wchar_t)); + else + { + File->write(L">", sizeof(wchar_t)); + ++Tabs; + } + + TextWrittenLast = false; +} + +//! Writes an xml element with any number of attributes +void CXMLWriter::writeElement(const wchar_t* name, bool empty, + core::array &names, + core::array &values) +{ + if (!File || !name) + return; + + if (Tabs > 0) + { + for (int i=0; iwrite(L"\t", sizeof(wchar_t)); + } + + // write name + + File->write(L"<", sizeof(wchar_t)); + File->write(name, wcslen(name)*sizeof(wchar_t)); + + // write attributes + u32 i=0; + for (; i < names.size() && i < values.size(); ++i) + writeAttribute(names[i].c_str(), values[i].c_str()); + + // write closing tag + if (empty) + File->write(L" />", 3*sizeof(wchar_t)); + else + { + File->write(L">", sizeof(wchar_t)); + ++Tabs; + } + + TextWrittenLast = false; +} + + +void CXMLWriter::writeAttribute(const wchar_t* name, const wchar_t* value) +{ + if (!name || !value) + return; + + File->write(L" ", sizeof(wchar_t)); + File->write(name, wcslen(name)*sizeof(wchar_t)); + File->write(L"=\"", 2*sizeof(wchar_t)); + writeText(value); + File->write(L"\"", sizeof(wchar_t)); +} + + +//! Writes a comment into the xml file +void CXMLWriter::writeComment(const wchar_t* comment) +{ + if (!File || !comment) + return; + + File->write(L"", 3*sizeof(wchar_t)); +} + + +//! Writes the closing tag for an element. Like +void CXMLWriter::writeClosingTag(const wchar_t* name) +{ + if (!File || !name) + return; + + --Tabs; + + if (Tabs > 0 && !TextWrittenLast) + { + for (int i=0; iwrite(L"\t", sizeof(wchar_t)); + } + + File->write(L"write(name, wcslen(name)*sizeof(wchar_t)); + File->write(L">", sizeof(wchar_t)); + TextWrittenLast = false; +} + +//! Writes a text into the file. All occurrences of special characters like +//! & (&), < (<), > (>), and " (") are automatically replaced. +void CXMLWriter::writeText(const wchar_t* text) +{ + if (!File || !text) + return; + + static const CXMLWriter::XMLSpecialCharacters XMLWSChar[] = + { + { L'&', L"&" }, + { L'<', L"<" }, + { L'>', L">" }, + { L'"', L""" }, + { L'\0', 0 } + }; + + // TODO: we have to get rid of that reserve call as well as it slows down xml-writing seriously. + // Making a member-variable would work, but a lot of memory would stay around after writing. + // So the correct solution is probably using fixed block here and always write when that is full. + core::stringw s; + s.reserve(wcslen(text)+1); + const wchar_t* p = text; + + while(*p) + { + // check if it is matching + bool found = false; + for (s32 i=0; XMLWSChar[i].Character != '\0'; ++i) + if (*p == XMLWSChar[i].Character) + { + s.append(XMLWSChar[i].Symbol); + found = true; + break; + } + + if (!found) + s.append(*p); + ++p; + } + + // write new string + File->write(s.c_str(), s.size()*sizeof(wchar_t)); + TextWrittenLast = true; +} + + +//! Writes a line break +void CXMLWriter::writeLineBreak() +{ + if (!File) + return; + +#if defined(_IRR_OSX_PLATFORM_) + File->write(L"\r", sizeof(wchar_t)); +#elif defined(_IRR_WINDOWS_API_) + File->write(L"\r\n", 2*sizeof(wchar_t)); +#else + File->write(L"\n", sizeof(wchar_t)); +#endif + +} + + + +//! Constructor +CXMLWriterUTF8::CXMLWriterUTF8(IWriteFile* file) +: CXMLWriterCommon(file) +{ + #ifdef _DEBUG + setDebugName("CXMLWriter"); + #endif +} + + +//! Writes a xml 1.0 header like +void CXMLWriterUTF8::writeXMLHeader() +{ + if (!File) + return; + + // No BOM as it's not necessarily utf8 + + const c8* const p = ""; + File->write(p, strlen(p) * sizeof(c8)); + + writeLineBreak(); + TextWrittenLast = false; +} + + + +//! Writes an xml element with maximal 5 attributes +void CXMLWriterUTF8::writeElement(const c8* name, bool empty, + const c8* attr1Name, const c8* attr1Value, + const c8* attr2Name, const c8* attr2Value, + const c8* attr3Name, const c8* attr3Value, + const c8* attr4Name, const c8* attr4Value, + const c8* attr5Name, const c8* attr5Value) +{ + if (!File || !name) + return; + + if (Tabs > 0) + { + for (int i=0; iwrite("\t", sizeof(c8)); + } + + // write name + + File->write("<", sizeof(c8)); + File->write(name, strlen(name)*sizeof(c8)); + + // write attributes + + writeAttribute(attr1Name, attr1Value); + writeAttribute(attr2Name, attr2Value); + writeAttribute(attr3Name, attr3Value); + writeAttribute(attr4Name, attr4Value); + writeAttribute(attr5Name, attr5Value); + + // write closing tag + if (empty) + File->write(" />", 3*sizeof(c8)); + else + { + File->write(">", sizeof(c8)); + ++Tabs; + } + + TextWrittenLast = false; +} + +//! Writes an xml element with any number of attributes +void CXMLWriterUTF8::writeElement(const c8* name, bool empty, + core::array &names, + core::array &values) +{ + if (!File || !name) + return; + + if (Tabs > 0) + { + for (int i=0; iwrite("\t", sizeof(c8)); + } + + // write name + + File->write("<", sizeof(c8)); + File->write(name, strlen(name)*sizeof(c8)); + + // write attributes + u32 i=0; + for (; i < names.size() && i < values.size(); ++i) + writeAttribute(names[i].c_str(), values[i].c_str()); + + // write closing tag + if (empty) + File->write(" />", 3*sizeof(c8)); + else + { + File->write(">", sizeof(c8)); + ++Tabs; + } + + TextWrittenLast = false; +} + + +void CXMLWriterUTF8::writeAttribute(const c8* name, const c8* value) +{ + if (!name || !value) + return; + + File->write(" ", sizeof(c8)); + File->write(name, strlen(name)*sizeof(c8)); + File->write("=\"", 2*sizeof(c8)); + writeText(value); + File->write("\"", sizeof(c8)); +} + + +//! Writes a comment into the xml file +void CXMLWriterUTF8::writeComment(const c8* comment) +{ + if (!File || !comment) + return; + + File->write("", 3*sizeof(c8)); +} + + +//! Writes the closing tag for an element. Like +void CXMLWriterUTF8::writeClosingTag(const c8* name) +{ + if (!File || !name) + return; + + --Tabs; + + if (Tabs > 0 && !TextWrittenLast) + { + for (int i=0; iwrite("\t", sizeof(c8)); + } + + File->write("write(name, strlen(name)*sizeof(c8)); + File->write(">", sizeof(c8)); + TextWrittenLast = false; +} + + + +//! Writes a text into the file. All occurrences of special characters like +//! & (&), < (<), > (>), and " (") are automatically replaced. +void CXMLWriterUTF8::writeText(const c8* text) +{ + if (!File || !text) + return; + + static const CXMLWriterUTF8::XMLSpecialCharacters XMLWSChar[] = + { + { '&', "&" }, + { '<', "<" }, + { '>', ">" }, + { '"', """ }, + { '\0', 0 } + }; + + // TODO: we have to get rid of that reserve call as well as it slows down xml-writing seriously. + // Making a member-variable would work, but a lot of memory would stay around after writing. + // So the correct solution is probably using fixed block here and always write when that is full. + core::stringc s; + s.reserve(strlen(text)+1); + const c8* p = text; + + while(*p) + { + // check if it is matching + bool found = false; + for (s32 i=0; XMLWSChar[i].Character != '\0'; ++i) + if (*p == XMLWSChar[i].Character) + { + s.append(XMLWSChar[i].Symbol); + found = true; + break; + } + + if (!found) + s.append(*p); + ++p; + } + + // write new string + File->write(s.c_str(), s.size()*sizeof(c8)); + TextWrittenLast = true; +} + + +//! Writes a line break +void CXMLWriterUTF8::writeLineBreak() +{ + if (!File) + return; + +#if defined(_IRR_OSX_PLATFORM_) + File->write("\r", sizeof(c8)); +#elif defined(_IRR_WINDOWS_API_) + File->write("\r\n", 2*sizeof(c8)); +#else + File->write("\n", sizeof(c8)); +#endif + +} + +} // end namespace irr +} // end namespace io + +#endif // _IRR_COMPILE_WITH_XML_ diff --git a/source/Irrlicht/CXMLWriter.h b/source/Irrlicht/CXMLWriter.h new file mode 100644 index 00000000..6febc66a --- /dev/null +++ b/source/Irrlicht/CXMLWriter.h @@ -0,0 +1,156 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_XML_WRITER_H_INCLUDED__ +#define __C_XML_WRITER_H_INCLUDED__ + +#include "IXMLWriter.h" + +#ifdef _IRR_COMPILE_WITH_XML_ + +#include +#include "IWriteFile.h" + +namespace irr +{ +namespace io +{ + + //! creates an IXMLReader + IXMLWriter* createIXMLWriter(IWriteFile* file); + + //! creates an IXMLReader + IXMLWriterUTF8* createIXMLWriterUTF8(IWriteFile* file); + + // Stuff needed by implementations for all character types + // TODO: With some more work it could maybe become a pure template based thing like CXMLReaderImpl + // and replace the type based writer implementations. Sorry, too lazy for now :-/ + template + class CXMLWriterCommon + { + public: + //! Constructor + CXMLWriterCommon(IWriteFile* file): File(file), Tabs(0), TextWrittenLast(false) + { + if (File) + File->grab(); + } + + //! Destructor + virtual ~CXMLWriterCommon() + { + if (File) + File->drop(); + } + + struct XMLSpecialCharacters + { + char_type Character; + const char_type* Symbol; + }; + + protected: + IWriteFile* File; + s32 Tabs; + + bool TextWrittenLast; + }; + + + //! Implementation providing methods for making it easier to write XML files. + class CXMLWriter : public IXMLWriter, public CXMLWriterCommon + { + public: + + //! Constructor + CXMLWriter(IWriteFile* file); + + //! Destructor + virtual ~CXMLWriter() {} + + //! Writes a xml 1.0 header like + virtual void writeXMLHeader() _IRR_OVERRIDE_; + + //! Writes an xml element with maximal 5 attributes + virtual void writeElement(const wchar_t* name, bool empty=false, + const wchar_t* attr1Name = 0, const wchar_t* attr1Value = 0, + const wchar_t* attr2Name = 0, const wchar_t* attr2Value = 0, + const wchar_t* attr3Name = 0, const wchar_t* attr3Value = 0, + const wchar_t* attr4Name = 0, const wchar_t* attr4Value = 0, + const wchar_t* attr5Name = 0, const wchar_t* attr5Value = 0) _IRR_OVERRIDE_; + + //! Writes an xml element with any number of attributes + virtual void writeElement(const wchar_t* name, bool empty, + core::array &names, core::array &values) _IRR_OVERRIDE_; + + //! Writes a comment into the xml file + virtual void writeComment(const wchar_t* comment) _IRR_OVERRIDE_; + + //! Writes the closing tag for an element. Like + virtual void writeClosingTag(const wchar_t* name) _IRR_OVERRIDE_; + + //! Writes a text into the file. All occurrences of special characters like + //! & (&), < (<), > (>), and " (") are automatically replaced. + virtual void writeText(const wchar_t* text) _IRR_OVERRIDE_; + + //! Writes a line break + virtual void writeLineBreak() _IRR_OVERRIDE_; + + private: + + void writeAttribute(const wchar_t* att, const wchar_t* name); + }; + + //! Implementation providing methods for making it easier to write XML files. + class CXMLWriterUTF8 : public IXMLWriterUTF8, public CXMLWriterCommon + { + public: + + //! Constructor + CXMLWriterUTF8(IWriteFile* file); + + //! Destructor + virtual ~CXMLWriterUTF8() {} + + //! Writes a xml 1.0 header like + virtual void writeXMLHeader() _IRR_OVERRIDE_; + + //! Writes an xml element with maximal 5 attributes + virtual void writeElement(const c8* name, bool empty=false, + const c8* attr1Name = 0, const c8* attr1Value = 0, + const c8* attr2Name = 0, const c8* attr2Value = 0, + const c8* attr3Name = 0, const c8* attr3Value = 0, + const c8* attr4Name = 0, const c8* attr4Value = 0, + const c8* attr5Name = 0, const c8* attr5Value = 0) _IRR_OVERRIDE_; + + //! Writes an xml element with any number of attributes + virtual void writeElement(const c8* name, bool empty, + core::array &names, core::array &values) _IRR_OVERRIDE_; + + //! Writes a comment into the xml file + virtual void writeComment(const c8* comment) _IRR_OVERRIDE_; + + //! Writes the closing tag for an element. Like + virtual void writeClosingTag(const c8* name) _IRR_OVERRIDE_; + + //! Writes a text into the file. All occurrences of special characters like + //! & (&), < (<), > (>), and " (") are automatically replaced. + virtual void writeText(const c8* text) _IRR_OVERRIDE_; + + //! Writes a line break + virtual void writeLineBreak() _IRR_OVERRIDE_; + + private: + + void writeAttribute(const c8* att, const c8* name); + }; + + +} // end namespace irr +} // end namespace io + +#endif // _IRR_COMPILE_WITH_XML_ + +#endif + diff --git a/source/Irrlicht/CXMeshFileLoader.cpp b/source/Irrlicht/CXMeshFileLoader.cpp new file mode 100644 index 00000000..89c2c77a --- /dev/null +++ b/source/Irrlicht/CXMeshFileLoader.cpp @@ -0,0 +1,2451 @@ +// Copyright (C) 2002-2012 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" + +#ifdef _IRR_COMPILE_WITH_X_LOADER_ + +#include "CXMeshFileLoader.h" +#include "CMeshTextureLoader.h" +#include "os.h" + +#include "fast_atof.h" +#include "coreutil.h" +#include "ISceneManager.h" +#include "IVideoDriver.h" +#include "IFileSystem.h" +#include "IReadFile.h" + +#ifdef _DEBUG +#define _XREADER_DEBUG +#endif +//#define BETTER_MESHBUFFER_SPLITTING_FOR_X + +namespace irr +{ +namespace scene +{ + +//! Constructor +CXMeshFileLoader::CXMeshFileLoader(scene::ISceneManager* smgr, io::IFileSystem* fs) +: SceneManager(smgr), FileSystem(fs), 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"); + #endif + + TextureLoader = new CMeshTextureLoader( FileSystem, SceneManager->getVideoDriver() ); +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool CXMeshFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "x" ); +} + + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IReferenceCounted::drop() for more information. +IAnimatedMesh* CXMeshFileLoader::createMesh(io::IReadFile* file) +{ + if (!file) + return 0; + + if ( getMeshTextureLoader() ) + getMeshTextureLoader()->setMeshFile(file); + +#ifdef _XREADER_DEBUG + u32 time = os::Timer::getRealTime(); +#endif + + AnimatedMesh = new CSkinnedMesh(); + + if (load(file)) + { + AnimatedMesh->finalize(); + } + else + { + AnimatedMesh->drop(); + AnimatedMesh = 0; + } +#ifdef _XREADER_DEBUG + time = os::Timer::getRealTime() - time; + core::stringc tmpString = "Time to load "; + tmpString += BinaryFormat ? "binary" : "ascii"; + tmpString += " X file: "; + tmpString += time; + tmpString += "ms"; + os::Printer::log(tmpString.c_str()); +#endif + //Clear up + + MajorVersion=0; + MinorVersion=0; + BinaryFormat=0; + BinaryNumCount=0; + FloatSize=0; + P=0; + End=0; + CurFrame=0; + TemplateMaterials.clear(); + + delete [] Buffer; + Buffer = 0; + + for (u32 i=0; iMaterials.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; + + mesh->Buffers.reallocate(mesh->Materials.size()); +#ifndef BETTER_MESHBUFFER_SPLITTING_FOR_X + const u32 bufferOffset = AnimatedMesh->getMeshBufferCount(); +#endif + for (i=0; iMaterials.size(); ++i) + { + mesh->Buffers.push_back( AnimatedMesh->addMeshBuffer() ); + mesh->Buffers.getLast()->Material = mesh->Materials[i]; + + if (!mesh->HasSkinning) + { + //Set up rigid animation + if (mesh->AttachedJointID!=-1) + { + AnimatedMesh->getAllJoints()[mesh->AttachedJointID]->AttachedMeshes.push_back( AnimatedMesh->getMeshBuffers().size()-1 ); + } + } + } + + 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) + { + for (u32 id=j*3+0;id<=j*3+2;++id) + { + mesh->Vertices[ mesh->Indices[id] ].Color = mesh->Buffers[mesh->FaceMaterialIndices[j]]->Material.DiffuseColor; + } + } + } + + #ifdef BETTER_MESHBUFFER_SPLITTING_FOR_X + { + //the same vertex can be used in many different meshbuffers, but it's slow to work out + + core::array< core::array< u32 > > verticesLinkIndex; + verticesLinkIndex.reallocate(mesh->Vertices.size()); + core::array< core::array< u16 > > verticesLinkBuffer; + verticesLinkBuffer.reallocate(mesh->Vertices.size()); + + for (i=0;iVertices.size();++i) + { + verticesLinkIndex.push_back( core::array< u32 >() ); + verticesLinkBuffer.push_back( core::array< u16 >() ); + } + + for (i=0;iFaceMaterialIndices.size();++i) + { + for (u32 id=i*3+0;id<=i*3+2;++id) + { + core::array< u16 > &Array=verticesLinkBuffer[ mesh->Indices[id] ]; + bool found=false; + + for (u32 j=0; j < Array.size(); ++j) + { + if (Array[j]==mesh->FaceMaterialIndices[i]) + { + found=true; + break; + } + } + + if (!found) + Array.push_back( mesh->FaceMaterialIndices[i] ); + } + } + + for (i=0;iVertices.size();++i) + { + core::array< u16 > &Array = verticesLinkBuffer[i]; + verticesLinkIndex[i].reallocate(Array.size()); + for (u32 j=0; j < Array.size(); ++j) + { + scene::SSkinMeshBuffer *buffer = mesh->Buffers[ Array[j] ]; + verticesLinkIndex[i].push_back( buffer->Vertices_Standard.size() ); + buffer->Vertices_Standard.push_back( mesh->Vertices[i] ); + } + } + + for (i=0;iFaceMaterialIndices.size();++i) + { + scene::SSkinMeshBuffer *buffer=mesh->Buffers[ mesh->FaceMaterialIndices[i] ]; + + for (u32 id=i*3+0;id<=i*3+2;++id) + { + core::array< u16 > &Array=verticesLinkBuffer[ mesh->Indices[id] ]; + + for (u32 j=0;j< Array.size() ;++j) + { + if ( Array[j]== mesh->FaceMaterialIndices[i] ) + buffer->Indices.push_back( verticesLinkIndex[ mesh->Indices[id] ][j] ); + } + } + } + + for (u32 j=0;jWeightJoint.size();++j) + { + ISkinnedMesh::SJoint* joint = AnimatedMesh->getAllJoints()[mesh->WeightJoint[j]]; + ISkinnedMesh::SWeight& weight = joint->Weights[mesh->WeightNum[j]]; + + u32 id = weight.vertex_id; + + if (id>=verticesLinkIndex.size()) + { + os::Printer::log("X loader: Weight id out of range", ELL_WARNING); + id=0; + weight.strength=0.f; + } + + if (verticesLinkBuffer[id].size()==1) + { + weight.vertex_id=verticesLinkIndex[id][0]; + weight.buffer_id=verticesLinkBuffer[id][0]; + } + else if (verticesLinkBuffer[id].size() != 0) + { + for (u32 k=1; k < verticesLinkBuffer[id].size(); ++k) + { + ISkinnedMesh::SWeight* WeightClone = AnimatedMesh->addWeight(joint); + WeightClone->strength = weight.strength; + WeightClone->vertex_id = verticesLinkIndex[id][k]; + WeightClone->buffer_id = verticesLinkBuffer[id][k]; + } + } + } + } + #else + { + core::array< u32 > verticesLinkIndex; + core::array< s16 > verticesLinkBuffer; + verticesLinkBuffer.set_used(mesh->Vertices.size()); + + // init with 0 + for (i=0;iVertices.size();++i) + { + // watch out for vertices which are not part of the mesh + // they will keep the -1 and can lead to out-of-bounds access + verticesLinkBuffer[i]=-1; + } + + bool warned = false; + // store meshbuffer number per vertex + for (i=0;iFaceMaterialIndices.size();++i) + { + for (u32 id=i*3+0;id<=i*3+2;++id) + { + if ((verticesLinkBuffer[mesh->Indices[id]] != -1) && (verticesLinkBuffer[mesh->Indices[id]] != (s16)mesh->FaceMaterialIndices[i])) + { + if (!warned) + { + os::Printer::log("X loader", "Duplicated vertex, animation might be corrupted.", ELL_WARNING); + warned=true; + } + const u32 tmp = mesh->Vertices.size(); + mesh->Vertices.push_back(mesh->Vertices[ mesh->Indices[id] ]); + mesh->Indices[id] = tmp; + verticesLinkBuffer.set_used(mesh->Vertices.size()); + } + verticesLinkBuffer[ mesh->Indices[id] ] = mesh->FaceMaterialIndices[i]; + } + } + + if (mesh->FaceMaterialIndices.size() != 0) + { + // store vertices in buffers and remember relation in verticesLinkIndex + u32* vCountArray = new u32[mesh->Buffers.size()]; + memset(vCountArray, 0, mesh->Buffers.size()*sizeof(u32)); + // count vertices in each buffer and reallocate + for (i=0; iVertices.size(); ++i) + { + if (verticesLinkBuffer[i] != -1) + ++vCountArray[verticesLinkBuffer[i]]; + } + if (mesh->TCoords2.size()) + { + for (i=0; i!=mesh->Buffers.size(); ++i) + { + mesh->Buffers[i]->Vertices_2TCoords.reallocate(vCountArray[i]); + mesh->Buffers[i]->VertexType=video::EVT_2TCOORDS; + } + } + else + { + for (i=0; i!=mesh->Buffers.size(); ++i) + mesh->Buffers[i]->Vertices_Standard.reallocate(vCountArray[i]); + } + + verticesLinkIndex.set_used(mesh->Vertices.size()); + // actually store vertices + for (i=0; iVertices.size(); ++i) + { + // if a vertex is missing for some reason, just skip it + if (verticesLinkBuffer[i]==-1) + continue; + scene::SSkinMeshBuffer *buffer = mesh->Buffers[ verticesLinkBuffer[i] ]; + + if (mesh->TCoords2.size()) + { + verticesLinkIndex[i] = buffer->Vertices_2TCoords.size(); + buffer->Vertices_2TCoords.push_back( mesh->Vertices[i] ); + // We have a problem with correct tcoord2 handling here + // crash fixed for now by checking the values + buffer->Vertices_2TCoords.getLast().TCoords2=(iTCoords2.size())?mesh->TCoords2[i]:mesh->Vertices[i].TCoords; + } + else + { + verticesLinkIndex[i] = buffer->Vertices_Standard.size(); + buffer->Vertices_Standard.push_back( mesh->Vertices[i] ); + } + } + + // count indices per buffer and reallocate + memset(vCountArray, 0, mesh->Buffers.size()*sizeof(u32)); + for (i=0; iFaceMaterialIndices.size(); ++i) + ++vCountArray[ mesh->FaceMaterialIndices[i] ]; + for (i=0; i!=mesh->Buffers.size(); ++i) + mesh->Buffers[i]->Indices.reallocate(vCountArray[i]); + delete [] vCountArray; + // create indices per buffer + for (i=0; iFaceMaterialIndices.size(); ++i) + { + scene::SSkinMeshBuffer *buffer = mesh->Buffers[ mesh->FaceMaterialIndices[i] ]; + for (u32 id=i*3+0; id!=i*3+3; ++id) + { + buffer->Indices.push_back( verticesLinkIndex[ mesh->Indices[id] ] ); + } + } + } + + for (u32 j=0; jWeightJoint.size(); ++j) + { + ISkinnedMesh::SWeight& weight = (AnimatedMesh->getAllJoints()[mesh->WeightJoint[j]]->Weights[mesh->WeightNum[j]]); + + u32 id = weight.vertex_id; + + if (id>=verticesLinkIndex.size()) + { + os::Printer::log("X loader: Weight id out of range", ELL_WARNING); + id=0; + weight.strength=0.f; + } + + weight.vertex_id=verticesLinkIndex[id]; + weight.buffer_id=verticesLinkBuffer[id] + bufferOffset; + } + } + #endif + + } + + return true; +} + + +//! Reads file into memory +bool CXMeshFileLoader::readFileIntoMemory(io::IReadFile* file) +{ + const long size = file->getSize(); + if (size < 12) + { + os::Printer::log("X File is too small.", ELL_WARNING); + return false; + } + + Buffer = new c8[size]; + + //! read all into memory + if (file->read(Buffer, size) != static_cast(size)) + { + os::Printer::log("Could not read from x file.", ELL_WARNING); + return false; + } + + Line = 1; + End = Buffer + size; + + //! check header "xof " + if (strncmp(Buffer, "xof ", 4)!=0) + { + os::Printer::log("Not an x file, wrong header.", ELL_WARNING); + return false; + } + + //! read minor and major version, e.g. 0302 or 0303 + c8 tmp[3]; + tmp[0] = Buffer[4]; + tmp[1] = Buffer[5]; + tmp[2] = 0x0; + MajorVersion = core::strtoul10(tmp); + + tmp[0] = Buffer[6]; + tmp[1] = Buffer[7]; + MinorVersion = core::strtoul10(tmp); + + //! read format + if (strncmp(&Buffer[8], "txt ", 4) ==0) + BinaryFormat = false; + else if (strncmp(&Buffer[8], "bin ", 4) ==0) + BinaryFormat = true; + else + { + os::Printer::log("Only uncompressed x files currently supported.", ELL_WARNING); + return false; + } + BinaryNumCount=0; + + //! read float size + if (strncmp(&Buffer[12], "0032", 4) ==0) + FloatSize = 4; + else if (strncmp(&Buffer[12], "0064", 4) ==0) + FloatSize = 8; + else + { + os::Printer::log("Float size not supported.", ELL_WARNING); + return false; + } + + P = &Buffer[16]; + + readUntilEndOfLine(); + + return true; +} + + +//! Parses the file +bool CXMeshFileLoader::parseFile() +{ + while(parseDataObject()) + { + // loop + } + + return true; +} + + +//! Parses the next Data object in the file +bool CXMeshFileLoader::parseDataObject() +{ + core::stringc objectName = getNextToken(); + + if (objectName.size() == 0) + return false; + + // parse specific object +#ifdef _XREADER_DEBUG + os::Printer::log("debug DataObject:", objectName.c_str(), ELL_DEBUG); +#endif + + if (objectName == "template") + return parseDataObjectTemplate(); + else + if (objectName == "Frame") + { + return parseDataObjectFrame( 0 ); + } + else + if (objectName == "Mesh") + { + // some meshes have no frames at all + //CurFrame = AnimatedMesh->addJoint(0); + + SXMesh *mesh=new SXMesh; + + //mesh->Buffer=AnimatedMesh->addMeshBuffer(); + Meshes.push_back(mesh); + + return parseDataObjectMesh(*mesh); + } + else + if (objectName == "AnimationSet") + { + return parseDataObjectAnimationSet(); + } + else + if (objectName == "AnimTicksPerSecond") + { + return parseDataObjectAnimationTicksPerSecond(); + } + else + if (objectName == "Material") + { + // template materials now available thanks to joeWright + TemplateMaterials.push_back(SXTemplateMaterial()); + TemplateMaterials.getLast().Name = getNextToken(); + return parseDataObjectMaterial(TemplateMaterials.getLast().Material); + } + else + if (objectName == "}") + { + os::Printer::log("} found in dataObject", ELL_WARNING); + return true; + } + + os::Printer::log("Unknown data object in animation of .x file", objectName.c_str(), ELL_WARNING); + + return parseUnknownDataObject(); +} + + +bool CXMeshFileLoader::parseDataObjectTemplate() +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading template", ELL_DEBUG); +#endif + + // parse a template data object. Currently not stored. + core::stringc name; + + if (!readHeadOfDataObject(&name)) + { + os::Printer::log("Left delimiter in template data object missing.", + name.c_str(), ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + // read GUID + getNextToken(); + + // read and ignore data members + while(true) + { + core::stringc s = getNextToken(); + + if (s == "}") + break; + + if (s.size() == 0) + return false; + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectFrame(CSkinnedMesh::SJoint *Parent) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading frame", ELL_DEBUG); +#endif + + // A coordinate frame, or "frame of reference." The Frame template + // is open and can contain any object. The Direct3D extensions (D3DX) + // mesh-loading functions recognize Mesh, FrameTransformMatrix, and + // Frame template instances as child objects when loading a Frame + // instance. + + u32 JointID=0; + + core::stringc name; + + if (!readHeadOfDataObject(&name)) + { + os::Printer::log("No opening brace in Frame found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + CSkinnedMesh::SJoint *joint=0; + + if (name.size()) + { + for (u32 n=0; n < AnimatedMesh->getAllJoints().size(); ++n) + { + if (AnimatedMesh->getAllJoints()[n]->Name==name) + { + joint=AnimatedMesh->getAllJoints()[n]; + JointID=n; + break; + } + } + } + + if (!joint) + { +#ifdef _XREADER_DEBUG + os::Printer::log("creating joint ", name.c_str(), ELL_DEBUG); +#endif + joint=AnimatedMesh->addJoint(Parent); + joint->Name=name; + JointID=AnimatedMesh->getAllJoints().size()-1; + } + else + { +#ifdef _XREADER_DEBUG + os::Printer::log("using joint ", name.c_str(), ELL_DEBUG); +#endif + if (Parent) + Parent->Children.push_back(joint); + } + + // Now inside a frame. + // read tokens until closing brace is reached. + + while(true) + { + core::stringc objectName = getNextToken(); + +#ifdef _XREADER_DEBUG + os::Printer::log("debug DataObject in frame:", objectName.c_str(), ELL_DEBUG); +#endif + + if (objectName.size() == 0) + { + os::Printer::log("Unexpected ending found in Frame in x file.", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + else + if (objectName == "}") + { + break; // frame finished + } + else + if (objectName == "Frame") + { + + if (!parseDataObjectFrame(joint)) + return false; + } + else + if (objectName == "FrameTransformMatrix") + { + if (!parseDataObjectTransformationMatrix(joint->LocalMatrix)) + return false; + + //joint->LocalAnimatedMatrix + //joint->LocalAnimatedMatrix.makeInverse(); + //joint->LocalMatrix=tmp*joint->LocalAnimatedMatrix; + } + else + if (objectName == "Mesh") + { + /* + frame.Meshes.push_back(SXMesh()); + if (!parseDataObjectMesh(frame.Meshes.getLast())) + return false; + */ + SXMesh *mesh=new SXMesh; + + mesh->AttachedJointID=JointID; + + Meshes.push_back(mesh); + + if (!parseDataObjectMesh(*mesh)) + return false; + } + else + { + os::Printer::log("Unknown data object in frame in x file", objectName.c_str(), ELL_WARNING); + if (!parseUnknownDataObject()) + return false; + } + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectTransformationMatrix(core::matrix4 &mat) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading Transformation Matrix", ELL_DEBUG); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Transformation Matrix found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + readMatrix(mat); + + if (!checkForOneFollowingSemicolons()) + { + os::Printer::log("No finishing semicolon in Transformation Matrix found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + } + + if (!checkForClosingBrace()) + { + os::Printer::log("No closing brace in Transformation Matrix found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectMesh(SXMesh &mesh) +{ + core::stringc name; + + if (!readHeadOfDataObject(&name)) + { +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading mesh", ELL_DEBUG); +#endif + os::Printer::log("No opening brace in Mesh found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading mesh", name.c_str(), ELL_DEBUG); +#endif + + // read vertex count + const u32 nVertices = readInt(); + + // read vertices + mesh.Vertices.set_used(nVertices); + for (u32 n=0; n polygonfaces; + u32 currentIndex = 0; + + for (u32 k=0; k>8)&0xf)*sizeof(core::vector2df); + for (u32 j=0; jgetAllJoints().size(); ++n) + { + if (AnimatedMesh->getAllJoints()[n]->Name==TransformNodeName) + { + joint=AnimatedMesh->getAllJoints()[n]; + break; + } + } + + if (!joint) + { +#ifdef _XREADER_DEBUG + os::Printer::log("creating joint for skinning ", TransformNodeName.c_str(), ELL_DEBUG); +#endif + n = AnimatedMesh->getAllJoints().size(); + joint=AnimatedMesh->addJoint(0); + joint->Name=TransformNodeName; + } + + // read vertex weights + const u32 nWeights = readInt(); + + // read vertex indices + u32 i; + + const u32 jointStart = joint->Weights.size(); + joint->Weights.reallocate(jointStart+nWeights); + + mesh.WeightJoint.reallocate( mesh.WeightJoint.size() + nWeights ); + mesh.WeightNum.reallocate( mesh.WeightNum.size() + nWeights ); + + for (i=0; iWeights.size()); + + CSkinnedMesh::SWeight *weight=AnimatedMesh->addWeight(joint); + + weight->buffer_id=0; + weight->vertex_id=readInt(); + } + + // read vertex weights + + for (i=jointStart; iWeights[i].strength = readFloat(); + + // read matrix offset + + // transforms the mesh vertices to the space of the bone + // When concatenated to the bone's transform, this provides the + // world space coordinates of the mesh as affected by the bone + core::matrix4& MatrixOffset = joint->GlobalInversedMatrix; + + readMatrix(MatrixOffset); + + if (!checkForOneFollowingSemicolons()) + { + os::Printer::log("No finishing semicolon in Skin Weights found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + } + + if (!checkForClosingBrace()) + { + os::Printer::log("No closing brace in Skin Weights found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectSkinMeshHeader(SXMesh& mesh) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading skin mesh header", ELL_DEBUG); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Skin Mesh header found in .x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + mesh.MaxSkinWeightsPerVertex = readInt(); + mesh.MaxSkinWeightsPerFace = readInt(); + mesh.BoneCount = readInt(); + + if (!BinaryFormat) + getNextToken(); // skip semicolon + + if (!checkForClosingBrace()) + { + os::Printer::log("No closing brace in skin mesh header in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectMeshNormals(SXMesh &mesh) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: reading mesh normals", ELL_DEBUG); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Mesh Normals found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + // read count + const u32 nNormals = readInt(); + core::array normals; + normals.set_used(nNormals); + + // read normals + for (u32 i=0; i normalIndices; + normalIndices.set_used(mesh.Indices.size()); + + // read face normal indices + const u32 nFNormals = readInt(); + + u32 normalidx = 0; + core::array polygonfaces; + for (u32 k=0; k=mesh.Vertices.size()) + { + os::Printer::log("index value in parseDataObjectMeshVertexColors out of bounds", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + readRGBA(mesh.Vertices[Index].Color); + checkForOneFollowingSemicolons(); + } + + if (!checkForOneFollowingSemicolons()) + { + os::Printer::log("No finishing semicolon in Mesh Vertex Colors Array found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + } + + if (!checkForClosingBrace()) + { + os::Printer::log("No closing brace in Mesh Texture Coordinates Array found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectMeshMaterialList(SXMesh &mesh) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading mesh material list", ELL_DEBUG); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Mesh Material List found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + // read material count + mesh.Materials.reallocate(readInt()); + + // read non triangulated face material index count + const u32 nFaceIndices = readInt(); + + // There seems to be a compact representation of "all faces the same material" + // being represented as 1;1;0;; which means 1 material, 1 face with first material + // all the other faces have to obey then, so check is disabled + //if (nFaceIndices != mesh.IndexCountPerFace.size()) + // os::Printer::log("Index count per face not equal to face material index count in x file.", ELL_WARNING); + + // read non triangulated face indices and create triangulated ones + mesh.FaceMaterialIndices.set_used( mesh.Indices.size() / 3); + u32 triangulatedindex = 0; + u32 ind = 0; + for (u32 tfi=0; tfigetTexture(TextureFileName) : NULL ); + + ++textureLayer; + if (textureLayer==2) + material.MaterialType=video::EMT_LIGHTMAP; + } + else + if (objectName.equals_ignore_case("NormalmapFilename")) + { + // some exporters write "NormalmapFileName" instead. + core::stringc TextureFileName; + if (!parseDataObjectTextureFilename(TextureFileName)) + return false; + + material.setTexture( 1, getMeshTextureLoader() ? getMeshTextureLoader()->getTexture(TextureFileName) : NULL ); + + if (textureLayer==1) + ++textureLayer; + } + else + { + os::Printer::log("Unknown data object in material in .x file", objectName.c_str(), ELL_WARNING); + if (!parseUnknownDataObject()) + return false; + } + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectAnimationSet() +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading animation set", ELL_DEBUG); +#endif + + core::stringc AnimationName; + + if (!readHeadOfDataObject(&AnimationName)) + { + os::Printer::log("No opening brace in Animation Set found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + os::Printer::log("Reading animationset ", AnimationName, ELL_DEBUG); + + while(true) + { + core::stringc objectName = getNextToken(); + + if (objectName.size() == 0) + { + os::Printer::log("Unexpected ending found in Animation set in x file.", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + else + if (objectName == "}") + { + break; // animation set finished + } + else + if (objectName == "Animation") + { + if (!parseDataObjectAnimation()) + return false; + } + else + { + os::Printer::log("Unknown data object in animation set in x file", objectName.c_str(), ELL_WARNING); + if (!parseUnknownDataObject()) + return false; + } + } + return true; +} + +bool CXMeshFileLoader::parseDataObjectAnimationTicksPerSecond() +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: reading AnimationTicksPerSecond", ELL_DEBUG); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Animation found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + const u32 ticks = readInt(); + + if (!checkForOneFollowingSemicolons()) + { + os::Printer::log("No closing semicolon in AnimationTicksPerSecond in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + if (!checkForClosingBrace()) + { + os::Printer::log("No closing brace in AnimationTicksPerSecond in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + AnimatedMesh->setAnimationSpeed(static_cast(ticks)); + + return true; +} + +bool CXMeshFileLoader::parseDataObjectAnimation() +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: reading animation", ELL_DEBUG); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Animation found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + //anim.closed = true; + //anim.linearPositionQuality = true; + CSkinnedMesh::SJoint animationDump; + + core::stringc FrameName; + + while(true) + { + core::stringc objectName = getNextToken(); + + if (objectName.size() == 0) + { + os::Printer::log("Unexpected ending found in Animation in x file.", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + else + if (objectName == "}") + { + break; // animation finished + } + else + if (objectName == "AnimationKey") + { + if (!parseDataObjectAnimationKey(&animationDump)) + return false; + } + else + if (objectName == "AnimationOptions") + { + //TODO: parse options. + if (!parseUnknownDataObject()) + return false; + } + else + if (objectName == "{") + { + // read frame name + FrameName = getNextToken(); + + if (!checkForClosingBrace()) + { + os::Printer::log("Unexpected ending found in Animation in x file.", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + } + else + { + os::Printer::log("Unknown data object in animation in x file", objectName.c_str(), ELL_WARNING); + if (!parseUnknownDataObject()) + return false; + } + } + + if (FrameName.size() != 0) + { +#ifdef _XREADER_DEBUG + os::Printer::log("frame name", FrameName.c_str(), ELL_DEBUG); +#endif + CSkinnedMesh::SJoint *joint=0; + + u32 n; + for (n=0; n < AnimatedMesh->getAllJoints().size(); ++n) + { + if (AnimatedMesh->getAllJoints()[n]->Name==FrameName) + { + joint=AnimatedMesh->getAllJoints()[n]; + break; + } + } + + if (!joint) + { +#ifdef _XREADER_DEBUG + os::Printer::log("creating joint for animation ", FrameName.c_str(), ELL_DEBUG); +#endif + joint=AnimatedMesh->addJoint(0); + joint->Name=FrameName; + } + + joint->PositionKeys.reallocate(joint->PositionKeys.size()+animationDump.PositionKeys.size()); + for (n=0; nPositionKeys.push_back(animationDump.PositionKeys[n]); + } + + joint->ScaleKeys.reallocate(joint->ScaleKeys.size()+animationDump.ScaleKeys.size()); + for (n=0; nScaleKeys.push_back(animationDump.ScaleKeys[n]); + } + + joint->RotationKeys.reallocate(joint->RotationKeys.size()+animationDump.RotationKeys.size()); + for (n=0; nRotationKeys.push_back(animationDump.RotationKeys[n]); + } + } + else + os::Printer::log("joint name was never given", ELL_WARNING); + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: reading animation key", ELL_DEBUG); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Animation Key found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + // read key type + + const u32 keyType = readInt(); + + if (keyType > 4) + { + os::Printer::log("Unknown key type found in Animation Key in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + // read number of keys + const u32 numberOfKeys = readInt(); + + // eat the semicolon after the "0". if there are keys present, readInt() + // does this for us. If there aren't, we need to do it explicitly + if (numberOfKeys == 0) + checkForOneFollowingSemicolons(); + + for (u32 i=0; iaddRotationKey(joint); + key->frame=time; + key->rotation.set(X,Y,Z,W); + key->rotation.normalize(); + } + break; + case 1: //scale + case 2: //position + { + // read vectors + + // read count + if (readInt() != 3) + { + os::Printer::log("Expected 3 numbers in animation key in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + core::vector3df vector; + readVector3(vector); + + if (!checkForTwoFollowingSemicolons()) + { + os::Printer::log("No finishing semicolon after vector animation key in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + } + + if (keyType==2) + { + ISkinnedMesh::SPositionKey *key=AnimatedMesh->addPositionKey(joint); + key->frame=time; + key->position=vector; + } + else + { + ISkinnedMesh::SScaleKey *key=AnimatedMesh->addScaleKey(joint); + key->frame=time; + key->scale=vector; + } + } + break; + case 3: + case 4: + { + // read matrix + + // read count + if (readInt() != 16) + { + os::Printer::log("Expected 16 numbers in animation key in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + // read matrix + core::matrix4 mat(core::matrix4::EM4CONST_NOTHING); + readMatrix(mat); + + //mat=joint->LocalMatrix*mat; + + if (!checkForOneFollowingSemicolons()) + { + os::Printer::log("No finishing semicolon after matrix animation key in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + } + + //core::vector3df rotation = mat.getRotationDegrees(); + + ISkinnedMesh::SRotationKey *keyR=AnimatedMesh->addRotationKey(joint); + keyR->frame=time; + + // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched from mat to mat.getTransposed() for downward compatibility. + // Not tested so far if this was correct or wrong before quaternion fix! + keyR->rotation= core::quaternion(mat.getTransposed()); + + ISkinnedMesh::SPositionKey *keyP=AnimatedMesh->addPositionKey(joint); + keyP->frame=time; + keyP->position=mat.getTranslation(); + +/* + core::vector3df scale=mat.getScale(); + + if (scale.X==0) + scale.X=1; + if (scale.Y==0) + scale.Y=1; + if (scale.Z==0) + scale.Z=1; + ISkinnedMesh::SScaleKey *keyS=AnimatedMesh->addScaleKey(joint); + keyS->frame=time; + keyS->scale=scale; +*/ + } + break; + } // end switch + } + + if (!checkForOneFollowingSemicolons()) + --P; + + if (!checkForClosingBrace()) + { + os::Printer::log("No closing brace in animation key in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectTextureFilename(core::stringc& texturename) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: reading texture filename", ELL_DEBUG); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Texture filename found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + if (!getNextTokenAsString(texturename)) + { + os::Printer::log("Unknown syntax while reading texture filename string in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + if (!checkForClosingBrace()) + { + os::Printer::log("No closing brace in Texture filename found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + return true; +} + + +bool CXMeshFileLoader::parseUnknownDataObject() +{ + // find opening delimiter + while(true) + { + core::stringc t = getNextToken(); + + if (t.size() == 0) + return false; + + if (t == "{") + break; + } + + u32 counter = 1; + + // parse until closing delimiter + + while(counter) + { + core::stringc t = getNextToken(); + + if (t.size() == 0) + return false; + + if (t == "{") + ++counter; + else + if (t == "}") + --counter; + } + + return true; +} + + +//! checks for closing curly brace, returns false if not there +bool CXMeshFileLoader::checkForClosingBrace() +{ + return (getNextToken() == "}"); +} + + +//! checks for one following semicolon, returns false if not there +bool CXMeshFileLoader::checkForOneFollowingSemicolons() +{ + if (BinaryFormat) + return true; + + if (getNextToken() == ";") + return true; + else + { + --P; + return false; + } +} + + +//! checks for two following semicolons, returns false if they are not there +bool CXMeshFileLoader::checkForTwoFollowingSemicolons() +{ + if (BinaryFormat) + return true; + + for (u32 k=0; k<2; ++k) + { + if (getNextToken() != ";") + { + --P; + return false; + } + } + + return true; +} + + +//! reads header of dataobject including the opening brace. +//! returns false if error happened, and writes name of object +//! if there is one +bool CXMeshFileLoader::readHeadOfDataObject(core::stringc* outname) +{ + core::stringc nameOrBrace = getNextToken(); + if (nameOrBrace != "{") + { + if (outname) + (*outname) = nameOrBrace; + + if (getNextToken() != "{") + return false; + } + + return true; +} + + +//! returns next parseable token. Returns empty string if no token there +core::stringc CXMeshFileLoader::getNextToken() +{ + core::stringc s; + + // process binary-formatted file + if (BinaryFormat) + { + // in binary mode it will only return NAME and STRING token + // and (correctly) skip over other tokens. + + s16 tok = readBinWord(); + u32 len; + + // standalone tokens + switch (tok) { + case 1: + // name token + len = readBinDWord(); + s = core::stringc(P, len); + P += len; + return s; + case 2: + // string token + len = readBinDWord(); + s = core::stringc(P, len); + P += (len + 2); + return s; + case 3: + // integer token + P += 4; + return ""; + case 5: + // GUID token + P += 16; + return ""; + case 6: + len = readBinDWord(); + P += (len * 4); + return ""; + case 7: + len = readBinDWord(); + P += (len * FloatSize); + return ""; + case 0x0a: + return "{"; + case 0x0b: + return "}"; + case 0x0c: + return "("; + case 0x0d: + return ")"; + case 0x0e: + return "["; + case 0x0f: + return "]"; + case 0x10: + return "<"; + case 0x11: + return ">"; + case 0x12: + return "."; + case 0x13: + return ","; + case 0x14: + return ";"; + case 0x1f: + return "template"; + case 0x28: + return "WORD"; + case 0x29: + return "DWORD"; + case 0x2a: + return "FLOAT"; + case 0x2b: + return "DOUBLE"; + case 0x2c: + return "CHAR"; + case 0x2d: + return "UCHAR"; + case 0x2e: + return "SWORD"; + case 0x2f: + return "SDWORD"; + case 0x30: + return "void"; + case 0x31: + return "string"; + case 0x32: + return "unicode"; + case 0x33: + return "cstring"; + case 0x34: + return "array"; + } + } + // process text-formatted file + else + { + findNextNoneWhiteSpace(); + + if (P >= End) + return s; + + while((P < End) && !core::isspace(P[0])) + { + // either keep token delimiters when already holding a token, or return if first valid char + if (P[0]==';' || P[0]=='}' || P[0]=='{' || P[0]==',') + { + if (!s.size()) + { + s.append(P[0]); + ++P; + } + break; // stop for delimiter + } + s.append(P[0]); + ++P; + } + } + return s; +} + + +//! places pointer to next begin of a token, which must be a number, +// and ignores comments +void CXMeshFileLoader::findNextNoneWhiteSpaceNumber() +{ + if (BinaryFormat) + return; + + while((P < End) && (P[0] != '-') && (P[0] != '.') && + !( core::isdigit(P[0]))) + { + // check if this is a comment + if ((P[0] == '/' && P[1] == '/') || P[0] == '#') + readUntilEndOfLine(); + else + ++P; + } +} + + +// places pointer to next begin of a token, and ignores comments +void CXMeshFileLoader::findNextNoneWhiteSpace() +{ + if (BinaryFormat) + return; + + while(true) + { + while((P < End) && core::isspace(P[0])) + { + if (*P=='\n') + ++Line; + ++P; + } + + if (P >= End) + return; + + // check if this is a comment + if ((P[0] == '/' && P[1] == '/') || + P[0] == '#') + readUntilEndOfLine(); + else + break; + } +} + + +//! reads a x file style string +bool CXMeshFileLoader::getNextTokenAsString(core::stringc& out) +{ + if (BinaryFormat) + { + out=getNextToken(); + return true; + } + findNextNoneWhiteSpace(); + + if (P >= End) + return false; + + if (P[0] != '"') + return false; + ++P; + + while(P < End && P[0]!='"') + { + out.append(P[0]); + ++P; + } + + if ( P[1] != ';' || P[0] != '"') + return false; + P+=2; + + return true; +} + + +void CXMeshFileLoader::readUntilEndOfLine() +{ + if (BinaryFormat) + return; + + while(P < End) + { + if (P[0] == '\n' || P[0] == '\r') + { + ++P; + ++Line; + return; + } + + ++P; + } +} + + +u16 CXMeshFileLoader::readBinWord() +{ + if (P>=End) + return 0; +#ifdef __BIG_ENDIAN__ + const u16 tmp = os::Byteswap::byteswap(*(u16 *)P); +#else + const u16 tmp = *(u16 *)P; +#endif + P += 2; + return tmp; +} + + +u32 CXMeshFileLoader::readBinDWord() +{ + if (P>=End) + return 0; +#ifdef __BIG_ENDIAN__ + const u32 tmp = os::Byteswap::byteswap(*(u32 *)P); +#else + const u32 tmp = *(u32 *)P; +#endif + P += 4; + return tmp; +} + + +u32 CXMeshFileLoader::readInt() +{ + if (BinaryFormat) + { + if (!BinaryNumCount) + { + const u16 tmp = readBinWord(); // 0x06 or 0x03 + if (tmp == 0x06) + BinaryNumCount = readBinDWord(); + else + BinaryNumCount = 1; // single int + } + --BinaryNumCount; + return readBinDWord(); + } + else + { + findNextNoneWhiteSpaceNumber(); + return core::strtoul10(P, &P); + } +} + + +f32 CXMeshFileLoader::readFloat() +{ + if (BinaryFormat) + { + if (!BinaryNumCount) + { + const u16 tmp = readBinWord(); // 0x07 or 0x42 + if (tmp == 0x07) + BinaryNumCount = readBinDWord(); + else + BinaryNumCount = 1; // single int + } + --BinaryNumCount; + if (FloatSize == 8) + { +#ifdef __BIG_ENDIAN__ + //TODO: Check if data is properly converted here + f32 ctmp[2]; + ctmp[1] = os::Byteswap::byteswap(*(f32*)P); + ctmp[0] = os::Byteswap::byteswap(*(f32*)P+4); + const f32 tmp = (f32)(*(f64*)(void*)ctmp); +#else + const f32 tmp = (f32)(*(f64 *)P); +#endif + P += 8; + return tmp; + } + else + { +#ifdef __BIG_ENDIAN__ + const f32 tmp = os::Byteswap::byteswap(*(f32 *)P); +#else + const f32 tmp = *(f32 *)P; +#endif + P += 4; + return tmp; + } + } + findNextNoneWhiteSpaceNumber(); + f32 ftmp; + P = core::fast_atof_move(P, ftmp); + return ftmp; +} + + +// read 2-dimensional vector. Stops at semicolon after second value for text file format +bool CXMeshFileLoader::readVector2(core::vector2df& vec) +{ + vec.X = readFloat(); + vec.Y = readFloat(); + return true; +} + + +// read 3-dimensional vector. Stops at semicolon after third value for text file format +bool CXMeshFileLoader::readVector3(core::vector3df& vec) +{ + vec.X = readFloat(); + vec.Y = readFloat(); + vec.Z = readFloat(); + return true; +} + + +// read color without alpha value. Stops after second semicolon after blue value +bool CXMeshFileLoader::readRGB(video::SColor& color) +{ + video::SColorf tmpColor; + tmpColor.r = readFloat(); + tmpColor.g = readFloat(); + tmpColor.b = readFloat(); + color = tmpColor.toSColor(); + return checkForOneFollowingSemicolons(); +} + + +// read color with alpha value. Stops after second semicolon after blue value +bool CXMeshFileLoader::readRGBA(video::SColor& color) +{ + video::SColorf tmpColor; + tmpColor.r = readFloat(); + tmpColor.g = readFloat(); + tmpColor.b = readFloat(); + tmpColor.a = readFloat(); + color = tmpColor.toSColor(); + return checkForOneFollowingSemicolons(); +} + + +// read matrix from list of floats +bool CXMeshFileLoader::readMatrix(core::matrix4& mat) +{ + for (u32 i=0; i<16; ++i) + mat[i] = readFloat(); + return checkForOneFollowingSemicolons(); +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_X_LOADER_ + diff --git a/source/Irrlicht/CXMeshFileLoader.h b/source/Irrlicht/CXMeshFileLoader.h new file mode 100644 index 00000000..a4806d7b --- /dev/null +++ b/source/Irrlicht/CXMeshFileLoader.h @@ -0,0 +1,198 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_X_MESH_FILE_LOADER_H_INCLUDED__ +#define __C_X_MESH_FILE_LOADER_H_INCLUDED__ + +#include "IMeshLoader.h" +#include "irrString.h" +#include "CSkinnedMesh.h" + + +namespace irr +{ +namespace io +{ + class IFileSystem; + class IReadFile; +} // end namespace io +namespace scene +{ +class IMeshManipulator; + +//! Meshloader capable of loading x meshes. +class CXMeshFileLoader : public IMeshLoader +{ +public: + + //! Constructor + CXMeshFileLoader(scene::ISceneManager* smgr, io::IFileSystem* fs); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".cob") + virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_; + + //! creates/loads an animated mesh from the file. + //! \return Pointer to the created mesh. Returns 0 if loading failed. + //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). + //! See IReferenceCounted::drop() for more information. + virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_; + + struct SXTemplateMaterial + { + core::stringc Name; // template name from Xfile + video::SMaterial Material; // material + }; + + struct SXMesh + { + SXMesh() : MaxSkinWeightsPerVertex(0), MaxSkinWeightsPerFace(0), BoneCount(0),AttachedJointID(-1),HasSkinning(false), HasVertexColors(false) {} + // this mesh contains triangulated texture data. + // because in an .x file, faces can be made of more than 3 + // vertices, the indices data structure is triangulated during the + // loading process. The IndexCountPerFace array is filled during + // this triangulation process and stores how much indices belong to + // every face. This data structure can be ignored, because all data + // in this structure is triangulated. + + core::stringc Name; + + u32 MaxSkinWeightsPerVertex; + u32 MaxSkinWeightsPerFace; + u32 BoneCount; + + core::array IndexCountPerFace; // default 3, but could be more + + core::array Buffers; + + core::array Vertices; + core::array TCoords2; + + core::array Indices; + + core::array FaceMaterialIndices; // index of material for each face + + core::array Materials; // material array + + core::array WeightJoint; + core::array WeightNum; + + s32 AttachedJointID; + + bool HasSkinning; + bool HasVertexColors; + }; + +private: + + bool load(io::IReadFile* file); + + bool readFileIntoMemory(io::IReadFile* file); + + bool parseFile(); + + bool parseDataObject(); + + bool parseDataObjectTemplate(); + + bool parseDataObjectFrame(CSkinnedMesh::SJoint *parent); + + bool parseDataObjectTransformationMatrix(core::matrix4 &mat); + + bool parseDataObjectMesh(SXMesh &mesh); + + bool parseDataObjectSkinWeights(SXMesh &mesh); + + bool parseDataObjectSkinMeshHeader(SXMesh &mesh); + + bool parseDataObjectMeshNormals(SXMesh &mesh); + + bool parseDataObjectMeshTextureCoords(SXMesh &mesh); + + bool parseDataObjectMeshVertexColors(SXMesh &mesh); + + bool parseDataObjectMeshMaterialList(SXMesh &mesh); + + bool parseDataObjectMaterial(video::SMaterial& material); + + bool parseDataObjectAnimationSet(); + + bool parseDataObjectAnimationTicksPerSecond(); + + bool parseDataObjectAnimation(); + + bool parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint); + + bool parseDataObjectTextureFilename(core::stringc& texturename); + + bool parseUnknownDataObject(); + + //! places pointer to next begin of a token, and ignores comments + void findNextNoneWhiteSpace(); + + //! places pointer to next begin of a token, which must be a number, + // and ignores comments + void findNextNoneWhiteSpaceNumber(); + + //! returns next parseable token. Returns empty string if no token there + core::stringc getNextToken(); + + //! reads header of dataobject including the opening brace. + //! returns false if error happened, and writes name of object + //! if there is one + bool readHeadOfDataObject(core::stringc* outname=0); + + //! checks for closing curly brace, returns false if not there + bool checkForClosingBrace(); + + //! checks for one following semicolons, returns false if not there + bool checkForOneFollowingSemicolons(); + + //! checks for two following semicolons, returns false if they are not there + bool checkForTwoFollowingSemicolons(); + + //! reads a x file style string + bool getNextTokenAsString(core::stringc& out); + + void readUntilEndOfLine(); + + u16 readBinWord(); + u32 readBinDWord(); + u32 readInt(); + f32 readFloat(); + bool readVector2(core::vector2df& vec); + bool readVector3(core::vector3df& vec); + bool readMatrix(core::matrix4& mat); + bool readRGB(video::SColor& color); + bool readRGBA(video::SColor& color); + + ISceneManager* SceneManager; + io::IFileSystem* FileSystem; + + CSkinnedMesh* AnimatedMesh; + + c8* Buffer; + const c8* P; + c8* End; + // counter for number arrays in binary format + u32 BinaryNumCount; + u32 Line; + io::path FilePath; + + CSkinnedMesh::SJoint *CurFrame; + + 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 new file mode 100644 index 00000000..23b515b0 --- /dev/null +++ b/source/Irrlicht/CZBuffer.cpp @@ -0,0 +1,109 @@ +// Copyright (C) 2002-2012 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" +#include "CZBuffer.h" +#include "irrString.h" + +#ifdef _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + + +//! constructor +CZBuffer::CZBuffer(const core::dimension2d& size) +: Buffer(0), BufferEnd(0), Size(0,0), TotalSize(0) +{ + #ifdef _DEBUG + setDebugName("CZBuffer"); + #endif + + setSize(size); +} + + + +//! destructor +CZBuffer::~CZBuffer() +{ + delete [] Buffer; +} + + + +//! clears the zbuffer +void CZBuffer::clear() +{ + memset(Buffer, 0, (BufferEnd-Buffer)*sizeof(TZBufferType)); +} + + + +//! sets the new size of the zbuffer +void CZBuffer::setSize(const core::dimension2d& size) +{ + if (size == Size) + return; + + Size = size; + + delete [] Buffer; + + TotalSize = size.Width * size.Height; + Buffer = new TZBufferType[TotalSize]; + BufferEnd = Buffer + TotalSize; +} + + + +//! returns the size of the zbuffer +const core::dimension2d& CZBuffer::getSize() const +{ + return Size; +} + + + +//! locks the zbuffer +TZBufferType* CZBuffer::lock() +{ + return Buffer; +} + + + +//! unlocks the zbuffer +void CZBuffer::unlock() +{ +} + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_SOFTWARE_ + +namespace irr +{ +namespace video +{ + +//! creates a ZBuffer +IZBuffer* createZBuffer(const core::dimension2d& size) +{ + #ifdef _IRR_COMPILE_WITH_SOFTWARE_ + return new CZBuffer(size); + #else + return 0; + #endif // _IRR_COMPILE_WITH_SOFTWARE_ +} + + +} // end namespace video +} // end namespace irr + + + diff --git a/source/Irrlicht/CZBuffer.h b/source/Irrlicht/CZBuffer.h new file mode 100644 index 00000000..ff517740 --- /dev/null +++ b/source/Irrlicht/CZBuffer.h @@ -0,0 +1,52 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_Z_BUFFER_H_INCLUDED__ +#define __C_Z_BUFFER_H_INCLUDED__ + +#include "IZBuffer.h" + +namespace irr +{ +namespace video +{ + + class CZBuffer : public IZBuffer + { + public: + + //! constructor + CZBuffer(const core::dimension2d& size); + + //! destructor + virtual ~CZBuffer(); + + //! clears the zbuffer + virtual void clear() _IRR_OVERRIDE_; + + //! sets the new size of the zbuffer + virtual void setSize(const core::dimension2d& size) _IRR_OVERRIDE_; + + //! returns the size of the zbuffer + virtual const core::dimension2d& getSize() const _IRR_OVERRIDE_; + + //! locks the zbuffer + virtual TZBufferType* lock() _IRR_OVERRIDE_; + + //! unlocks the zbuffer + virtual void unlock() _IRR_OVERRIDE_; + + private: + + TZBufferType* Buffer; + TZBufferType* BufferEnd; + core::dimension2d Size; + s32 TotalSize; + }; + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/CZipReader.cpp b/source/Irrlicht/CZipReader.cpp new file mode 100644 index 00000000..91574b5c --- /dev/null +++ b/source/Irrlicht/CZipReader.cpp @@ -0,0 +1,848 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CZipReader.h" + +#include "os.h" + +// This method is used for error output from bzip2. +extern "C" void bz_internal_error(int errorCode) +{ + irr::os::Printer::log("Error in bzip2 handling", irr::core::stringc(errorCode), irr::ELL_ERROR); +} + +#ifdef __IRR_COMPILE_WITH_ZIP_ARCHIVE_LOADER_ + +#include "CFileList.h" +#include "CReadFile.h" +#include "coreutil.h" + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_ZLIB_ + #ifndef _IRR_USE_NON_SYSTEM_ZLIB_ + #include // use system lib + #else + #include "zlib/zlib.h" + #endif + + #ifdef _IRR_COMPILE_WITH_ZIP_ENCRYPTION_ + #include "aesGladman/fileenc.h" + #endif + #ifdef _IRR_COMPILE_WITH_BZIP2_ + #ifndef _IRR_USE_NON_SYSTEM_BZLIB_ + #include + #else + #include "bzip2/bzlib.h" + #endif + #endif + #ifdef _IRR_COMPILE_WITH_LZMA_ + #include "lzma/LzmaDec.h" + #endif +#endif + +namespace irr +{ +namespace io +{ + + +// ----------------------------------------------------------------------------- +// zip loader +// ----------------------------------------------------------------------------- + +//! Constructor +CArchiveLoaderZIP::CArchiveLoaderZIP(io::IFileSystem* fs) +: FileSystem(fs) +{ + #ifdef _DEBUG + setDebugName("CArchiveLoaderZIP"); + #endif +} + +//! returns true if the file maybe is able to be loaded by this class +bool CArchiveLoaderZIP::isALoadableFileFormat(const io::path& filename) const +{ + return core::hasFileExtension(filename, "zip", "pk3") || + core::hasFileExtension(filename, "gz", "tgz"); +} + +//! Check to see if the loader can create archives of this type. +bool CArchiveLoaderZIP::isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const +{ + return (fileType == EFAT_ZIP || fileType == EFAT_GZIP); +} + + +//! Creates an archive from the filename +/** \param file File handle to check. +\return Pointer to newly created archive, or 0 upon error. */ +IFileArchive* CArchiveLoaderZIP::createArchive(const io::path& filename, bool ignoreCase, bool ignorePaths) const +{ + IFileArchive *archive = 0; + io::IReadFile* file = FileSystem->createAndOpenFile(filename); + + if (file) + { + archive = createArchive(file, ignoreCase, ignorePaths); + file->drop(); + } + + return archive; +} + +//! creates/loads an archive from the file. +//! \return Pointer to the created archive. Returns 0 if loading failed. +IFileArchive* CArchiveLoaderZIP::createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const +{ + IFileArchive *archive = 0; + if (file) + { + file->seek(0); + + u16 sig; + file->read(&sig, 2); + +#ifdef __BIG_ENDIAN__ + sig = os::Byteswap::byteswap(sig); +#endif + + file->seek(0); + + bool isGZip = (sig == 0x8b1f); + + archive = new CZipReader(FileSystem, file, ignoreCase, ignorePaths, isGZip); + } + return archive; +} + +//! Check if the file might be loaded by this class +/** Check might look into the file. +\param file File handle to check. +\return True if file seems to be loadable. */ +bool CArchiveLoaderZIP::isALoadableFileFormat(io::IReadFile* file) const +{ + SZIPFileHeader header; + + file->read( &header.Sig, 4 ); +#ifdef __BIG_ENDIAN__ + header.Sig = os::Byteswap::byteswap(header.Sig); +#endif + + return header.Sig == 0x04034b50 || // ZIP + (header.Sig&0xffff) == 0x8b1f; // gzip +} + +// ----------------------------------------------------------------------------- +// zip archive +// ----------------------------------------------------------------------------- + +CZipReader::CZipReader(IFileSystem* fs, IReadFile* file, bool ignoreCase, bool ignorePaths, bool isGZip) + : CFileList((file ? file->getFileName() : io::path("")), ignoreCase, ignorePaths), FileSystem(fs), File(file), IsGZip(isGZip) +{ + #ifdef _DEBUG + setDebugName("CZipReader"); + #endif + + if (File) + { + File->grab(); + + // load file entries + if (IsGZip) + while (scanGZipHeader()) { } + else + while (scanZipHeader()) { } + + sort(); + } +} + +CZipReader::~CZipReader() +{ + if (File) + File->drop(); +} + + +//! get the archive type +E_FILE_ARCHIVE_TYPE CZipReader::getType() const +{ + return IsGZip ? EFAT_GZIP : EFAT_ZIP; +} + +const IFileList* CZipReader::getFileList() const +{ + return this; +} + + +//! scans for a local header, returns false if there is no more local file header. +//! The gzip file format seems to think that there can be multiple files in a gzip file +//! but none +bool CZipReader::scanGZipHeader() +{ + SZipFileEntry entry; + entry.Offset = 0; + memset(&entry.header, 0, sizeof(SZIPFileHeader)); + + // read header + SGZIPMemberHeader header; + if (File->read(&header, sizeof(SGZIPMemberHeader)) == sizeof(SGZIPMemberHeader)) + { + +#ifdef __BIG_ENDIAN__ + header.sig = os::Byteswap::byteswap(header.sig); + header.time = os::Byteswap::byteswap(header.time); +#endif + + // check header value + if (header.sig != 0x8b1f) + return false; + + // now get the file info + if (header.flags & EGZF_EXTRA_FIELDS) + { + // read lenth of extra data + u16 dataLen; + + File->read(&dataLen, 2); + +#ifdef __BIG_ENDIAN__ + dataLen = os::Byteswap::byteswap(dataLen); +#endif + + // skip it + File->seek(dataLen, true); + } + + io::path ZipFileName = ""; + + if (header.flags & EGZF_FILE_NAME) + { + c8 c; + File->read(&c, 1); + while (c) + { + ZipFileName.append(c); + File->read(&c, 1); + } + } + else + { + // no file name? + ZipFileName = Path; + core::deletePathFromFilename(ZipFileName); + + // rename tgz to tar or remove gz extension + if (core::hasFileExtension(ZipFileName, "tgz")) + { + ZipFileName[ ZipFileName.size() - 2] = 'a'; + ZipFileName[ ZipFileName.size() - 1] = 'r'; + } + else if (core::hasFileExtension(ZipFileName, "gz")) + { + ZipFileName[ ZipFileName.size() - 3] = 0; + ZipFileName.validate(); + } + } + + if (header.flags & EGZF_COMMENT) + { + c8 c='a'; + while (c) + File->read(&c, 1); + } + + if (header.flags & EGZF_CRC16) + File->seek(2, true); + + // we are now at the start of the data blocks + entry.Offset = File->getPos(); + + entry.header.FilenameLength = ZipFileName.size(); + + entry.header.CompressionMethod = header.compressionMethod; + entry.header.DataDescriptor.CompressedSize = (File->getSize() - 8) - File->getPos(); + + // seek to file end + File->seek(entry.header.DataDescriptor.CompressedSize, true); + + // read CRC + File->read(&entry.header.DataDescriptor.CRC32, 4); + // read uncompressed size + File->read(&entry.header.DataDescriptor.UncompressedSize, 4); + +#ifdef __BIG_ENDIAN__ + entry.header.DataDescriptor.CRC32 = os::Byteswap::byteswap(entry.header.DataDescriptor.CRC32); + entry.header.DataDescriptor.UncompressedSize = os::Byteswap::byteswap(entry.header.DataDescriptor.UncompressedSize); +#endif + + // now we've filled all the fields, this is just a standard deflate block + addItem(ZipFileName, entry.Offset, entry.header.DataDescriptor.UncompressedSize, false, 0); + FileInfo.push_back(entry); + } + + // there's only one block of data in a gzip file + return false; +} + +//! scans for a local header, returns false if there is no more local file header. +bool CZipReader::scanZipHeader(bool ignoreGPBits) +{ + io::path ZipFileName = ""; + SZipFileEntry entry; + entry.Offset = 0; + memset(&entry.header, 0, sizeof(SZIPFileHeader)); + + File->read(&entry.header, sizeof(SZIPFileHeader)); + +#ifdef __BIG_ENDIAN__ + entry.header.Sig = os::Byteswap::byteswap(entry.header.Sig); + entry.header.VersionToExtract = os::Byteswap::byteswap(entry.header.VersionToExtract); + entry.header.GeneralBitFlag = os::Byteswap::byteswap(entry.header.GeneralBitFlag); + entry.header.CompressionMethod = os::Byteswap::byteswap(entry.header.CompressionMethod); + entry.header.LastModFileTime = os::Byteswap::byteswap(entry.header.LastModFileTime); + entry.header.LastModFileDate = os::Byteswap::byteswap(entry.header.LastModFileDate); + entry.header.DataDescriptor.CRC32 = os::Byteswap::byteswap(entry.header.DataDescriptor.CRC32); + entry.header.DataDescriptor.CompressedSize = os::Byteswap::byteswap(entry.header.DataDescriptor.CompressedSize); + entry.header.DataDescriptor.UncompressedSize = os::Byteswap::byteswap(entry.header.DataDescriptor.UncompressedSize); + entry.header.FilenameLength = os::Byteswap::byteswap(entry.header.FilenameLength); + entry.header.ExtraFieldLength = os::Byteswap::byteswap(entry.header.ExtraFieldLength); +#endif + + if (entry.header.Sig != 0x04034b50) + return false; // local file headers end here. + + // read filename + { + c8 *tmp = new c8 [ entry.header.FilenameLength + 2 ]; + File->read(tmp, entry.header.FilenameLength); + tmp[entry.header.FilenameLength] = 0; + ZipFileName = tmp; + delete [] tmp; + } + +#ifdef _IRR_COMPILE_WITH_ZIP_ENCRYPTION_ + // AES encryption + if ((entry.header.GeneralBitFlag & ZIP_FILE_ENCRYPTED) && (entry.header.CompressionMethod == 99)) + { + s16 restSize = entry.header.ExtraFieldLength; + SZipFileExtraHeader extraHeader; + while (restSize) + { + File->read(&extraHeader, sizeof(extraHeader)); +#ifdef __BIG_ENDIAN__ + extraHeader.ID = os::Byteswap::byteswap(extraHeader.ID); + extraHeader.Size = os::Byteswap::byteswap(extraHeader.Size); +#endif + restSize -= sizeof(extraHeader); + if (extraHeader.ID==(s16)0x9901) + { + SZipFileAESExtraData data; + File->read(&data, sizeof(data)); +#ifdef __BIG_ENDIAN__ + data.Version = os::Byteswap::byteswap(data.Version); + data.CompressionMode = os::Byteswap::byteswap(data.CompressionMode); +#endif + restSize -= sizeof(data); + if (data.Vendor[0]=='A' && data.Vendor[1]=='E') + { + // encode values into Sig + // AE-Version | Strength | ActualMode + entry.header.Sig = + ((data.Version & 0xff) << 24) | + (data.EncryptionStrength << 16) | + (data.CompressionMode); + File->seek(restSize, true); + break; + } + } + } + } + // move forward length of extra field. + else +#endif + if (entry.header.ExtraFieldLength) + File->seek(entry.header.ExtraFieldLength, true); + + // if bit 3 was set, use CentralDirectory for setup + if (!ignoreGPBits && entry.header.GeneralBitFlag & ZIP_INFO_IN_DATA_DESCRIPTOR) + { + SZIPFileCentralDirEnd dirEnd; + FileInfo.clear(); + Files.clear(); + // First place where the end record could be stored + File->seek(File->getSize()-22); + const char endID[] = {0x50, 0x4b, 0x05, 0x06, 0x0}; + char tmp[5]={'\0'}; + bool found=false; + // search for the end record ID + while (!found && File->getPos()>0) + { + int seek=8; + File->read(tmp, 4); + switch (tmp[0]) + { + case 0x50: + if (!strcmp(endID, tmp)) + { + seek=4; + found=true; + } + break; + case 0x4b: + seek=5; + break; + case 0x05: + seek=6; + break; + case 0x06: + seek=7; + break; + } + File->seek(-seek, true); + } + File->read(&dirEnd, sizeof(dirEnd)); +#ifdef __BIG_ENDIAN__ + dirEnd.NumberDisk = os::Byteswap::byteswap(dirEnd.NumberDisk); + dirEnd.NumberStart = os::Byteswap::byteswap(dirEnd.NumberStart); + dirEnd.TotalDisk = os::Byteswap::byteswap(dirEnd.TotalDisk); + dirEnd.TotalEntries = os::Byteswap::byteswap(dirEnd.TotalEntries); + dirEnd.Size = os::Byteswap::byteswap(dirEnd.Size); + dirEnd.Offset = os::Byteswap::byteswap(dirEnd.Offset); + dirEnd.CommentLength = os::Byteswap::byteswap(dirEnd.CommentLength); +#endif + FileInfo.reallocate(dirEnd.TotalEntries); + File->seek(dirEnd.Offset); + while (scanCentralDirectoryHeader()) { } + return false; + } + + // store position in file + entry.Offset = File->getPos(); + // move forward length of data + File->seek(entry.header.DataDescriptor.CompressedSize, true); + + #ifdef _DEBUG + //os::Debuginfo::print("added file from archive", ZipFileName.c_str()); + #endif + + addItem(ZipFileName, entry.Offset, entry.header.DataDescriptor.UncompressedSize, ZipFileName.lastChar()=='/', FileInfo.size()); + FileInfo.push_back(entry); + + return true; +} + + +//! scans for a local header, returns false if there is no more local file header. +bool CZipReader::scanCentralDirectoryHeader() +{ + io::path ZipFileName = ""; + SZIPFileCentralDirFileHeader entry; + File->read(&entry, sizeof(SZIPFileCentralDirFileHeader)); + +#ifdef __BIG_ENDIAN__ + entry.Sig = os::Byteswap::byteswap(entry.Sig); + entry.VersionMadeBy = os::Byteswap::byteswap(entry.VersionMadeBy); + entry.VersionToExtract = os::Byteswap::byteswap(entry.VersionToExtract); + entry.GeneralBitFlag = os::Byteswap::byteswap(entry.GeneralBitFlag); + entry.CompressionMethod = os::Byteswap::byteswap(entry.CompressionMethod); + entry.LastModFileTime = os::Byteswap::byteswap(entry.LastModFileTime); + entry.LastModFileDate = os::Byteswap::byteswap(entry.LastModFileDate); + entry.CRC32 = os::Byteswap::byteswap(entry.CRC32); + entry.CompressedSize = os::Byteswap::byteswap(entry.CompressedSize); + entry.UncompressedSize = os::Byteswap::byteswap(entry.UncompressedSize); + entry.FilenameLength = os::Byteswap::byteswap(entry.FilenameLength); + entry.ExtraFieldLength = os::Byteswap::byteswap(entry.ExtraFieldLength); + entry.FileCommentLength = os::Byteswap::byteswap(entry.FileCommentLength); + entry.DiskNumberStart = os::Byteswap::byteswap(entry.DiskNumberStart); + entry.InternalFileAttributes = os::Byteswap::byteswap(entry.InternalFileAttributes); + entry.ExternalFileAttributes = os::Byteswap::byteswap(entry.ExternalFileAttributes); + entry.RelativeOffsetOfLocalHeader = os::Byteswap::byteswap(entry.RelativeOffsetOfLocalHeader); +#endif + + if (entry.Sig != 0x02014b50) + return false; // central dir headers end here. + + const long pos = File->getPos(); + File->seek(entry.RelativeOffsetOfLocalHeader); + scanZipHeader(true); + File->seek(pos+entry.FilenameLength+entry.ExtraFieldLength+entry.FileCommentLength); + FileInfo.getLast().header.DataDescriptor.CompressedSize=entry.CompressedSize; + FileInfo.getLast().header.DataDescriptor.UncompressedSize=entry.UncompressedSize; + FileInfo.getLast().header.DataDescriptor.CRC32=entry.CRC32; + Files.getLast().Size=entry.UncompressedSize; + return true; +} + + +//! opens a file by file name +IReadFile* CZipReader::createAndOpenFile(const io::path& filename) +{ + s32 index = findFile(filename, false); + + if (index != -1) + return createAndOpenFile(index); + + return 0; +} + +#ifdef _IRR_COMPILE_WITH_LZMA_ +//! Used for LZMA decompression. The lib has no default memory management +namespace +{ + void *SzAlloc(void *p, size_t size) + { + (void)p; // disable unused variable warnings + return malloc(size); + } + void SzFree(void *p, void *address) + { + (void)p; // disable unused variable warnings + free(address); + } + ISzAlloc lzmaAlloc = { SzAlloc, SzFree }; +} +#endif + +//! opens a file by index +IReadFile* CZipReader::createAndOpenFile(u32 index) +{ + // Irrlicht supports 0, 8, 12, 14, 99 + //0 - The file is stored (no compression) + //1 - The file is Shrunk + //2 - The file is Reduced with compression factor 1 + //3 - The file is Reduced with compression factor 2 + //4 - The file is Reduced with compression factor 3 + //5 - The file is Reduced with compression factor 4 + //6 - The file is Imploded + //7 - Reserved for Tokenizing compression algorithm + //8 - The file is Deflated + //9 - Reserved for enhanced Deflating + //10 - PKWARE Date Compression Library Imploding + //12 - bzip2 - Compression Method from libbz2, WinZip 10 + //14 - LZMA - Compression Method, WinZip 12 + //96 - Jpeg compression - Compression Method, WinZip 12 + //97 - WavPack - Compression Method, WinZip 11 + //98 - PPMd - Compression Method, WinZip 10 + //99 - AES encryption, WinZip 9 + + const SZipFileEntry &e = FileInfo[Files[index].ID]; + wchar_t buf[64]; + s16 actualCompressionMethod=e.header.CompressionMethod; + IReadFile* decrypted=0; + u8* decryptedBuf=0; + u32 decryptedSize=e.header.DataDescriptor.CompressedSize; +#ifdef _IRR_COMPILE_WITH_ZIP_ENCRYPTION_ + if ((e.header.GeneralBitFlag & ZIP_FILE_ENCRYPTED) && (e.header.CompressionMethod == 99)) + { + os::Printer::log("Reading encrypted file."); + u8 salt[16]={0}; + const u16 saltSize = (((e.header.Sig & 0x00ff0000) >>16)+1)*4; + File->seek(e.Offset); + File->read(salt, saltSize); + char pwVerification[2]; + char pwVerificationFile[2]; + File->read(pwVerification, 2); + fcrypt_ctx zctx; // the encryption context + int rc = fcrypt_init( + (e.header.Sig & 0x00ff0000) >>16, + (const unsigned char*)Password.c_str(), // the password + Password.size(), // number of bytes in password + salt, // the salt + (unsigned char*)pwVerificationFile, // on return contains password verifier + &zctx); // encryption context + if (strncmp(pwVerificationFile, pwVerification, 2)) + { + os::Printer::log("Wrong password"); + return 0; + } + decryptedSize= e.header.DataDescriptor.CompressedSize-saltSize-12; + decryptedBuf= new u8[decryptedSize]; + u32 c = 0; + while ((c+32768)<=decryptedSize) + { + File->read(decryptedBuf+c, 32768); + fcrypt_decrypt( + decryptedBuf+c, // pointer to the data to decrypt + 32768, // how many bytes to decrypt + &zctx); // decryption context + c+=32768; + } + File->read(decryptedBuf+c, decryptedSize-c); + fcrypt_decrypt( + decryptedBuf+c, // pointer to the data to decrypt + decryptedSize-c, // how many bytes to decrypt + &zctx); // decryption context + + char fileMAC[10]; + char resMAC[10]; + rc = fcrypt_end( + (unsigned char*)resMAC, // on return contains the authentication code + &zctx); // encryption context + if (rc != 10) + { + os::Printer::log("Error on encryption closing"); + delete [] decryptedBuf; + return 0; + } + File->read(fileMAC, 10); + if (strncmp(fileMAC, resMAC, 10)) + { + os::Printer::log("Error on encryption check"); + delete [] decryptedBuf; + return 0; + } + decrypted = FileSystem->createMemoryReadFile(decryptedBuf, decryptedSize, Files[index].FullName, true); + actualCompressionMethod = (e.header.Sig & 0xffff); +#if 0 + if ((e.header.Sig & 0xff000000)==0x01000000) + { + } + else if ((e.header.Sig & 0xff000000)==0x02000000) + { + } + else + { + os::Printer::log("Unknown encryption method"); + return 0; + } +#endif + } +#endif + switch(actualCompressionMethod) + { + case 0: // no compression + { + if (decrypted) + return decrypted; + else + return createLimitReadFile(Files[index].FullName, File, e.Offset, decryptedSize); + } + case 8: + { + #ifdef _IRR_COMPILE_WITH_ZLIB_ + + const u32 uncompressedSize = e.header.DataDescriptor.UncompressedSize; + c8* pBuf = new c8[ uncompressedSize ]; + if (!pBuf) + { + swprintf_irr ( buf, 64, L"Not enough memory for decompressing %s", core::stringw(Files[index].FullName).c_str() ); + os::Printer::log( buf, ELL_ERROR); + if (decrypted) + decrypted->drop(); + return 0; + } + + u8 *pcData = decryptedBuf; + if (!pcData) + { + pcData = new u8[decryptedSize]; + if (!pcData) + { + swprintf_irr ( buf, 64, L"Not enough memory for decompressing %s", core::stringw(Files[index].FullName).c_str() ); + os::Printer::log( buf, ELL_ERROR); + delete [] pBuf; + return 0; + } + + //memset(pcData, 0, decryptedSize); + File->seek(e.Offset); + File->read(pcData, decryptedSize); + } + + // Setup the inflate stream. + z_stream stream; + s32 err; + + stream.next_in = (Bytef*)pcData; + stream.avail_in = (uInt)decryptedSize; + stream.next_out = (Bytef*)pBuf; + stream.avail_out = uncompressedSize; + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + // Perform inflation. wbits < 0 indicates no zlib header inside the data. + err = inflateInit2(&stream, -MAX_WBITS); + if (err == Z_OK) + { + err = inflate(&stream, Z_FINISH); + inflateEnd(&stream); + if (err == Z_STREAM_END) + err = Z_OK; + err = Z_OK; + inflateEnd(&stream); + } + + if (decrypted) + decrypted->drop(); + else + delete[] pcData; + + if (err != Z_OK) + { + swprintf_irr ( buf, 64, L"Error decompressing %s", core::stringw(Files[index].FullName).c_str() ); + os::Printer::log( buf, ELL_ERROR); + delete [] pBuf; + return 0; + } + else + return FileSystem->createMemoryReadFile(pBuf, uncompressedSize, Files[index].FullName, true); + + #else + return 0; // zlib not compiled, we cannot decompress the data. + #endif + } + case 12: + { + #ifdef _IRR_COMPILE_WITH_BZIP2_ + + const u32 uncompressedSize = e.header.DataDescriptor.UncompressedSize; + c8* pBuf = new c8[ uncompressedSize ]; + if (!pBuf) + { + swprintf_irr ( buf, 64, L"Not enough memory for decompressing %s", core::stringw(Files[index].FullName).c_str() ); + os::Printer::log( buf, ELL_ERROR); + if (decrypted) + decrypted->drop(); + return 0; + } + + u8 *pcData = decryptedBuf; + if (!pcData) + { + pcData = new u8[decryptedSize]; + if (!pcData) + { + swprintf_irr ( buf, 64, L"Not enough memory for decompressing %s", core::stringw(Files[index].FullName).c_str() ); + os::Printer::log( buf, ELL_ERROR); + delete [] pBuf; + return 0; + } + + //memset(pcData, 0, decryptedSize); + File->seek(e.Offset); + File->read(pcData, decryptedSize); + } + + bz_stream bz_ctx; + memset(&bz_ctx, 0, sizeof(bz_ctx)); + /* use BZIP2's default memory allocation + bz_ctx->bzalloc = NULL; + bz_ctx->bzfree = NULL; + bz_ctx->opaque = NULL; + */ + int err = BZ2_bzDecompressInit(&bz_ctx, 0, 0); /* decompression */ + if(err != BZ_OK) + { + os::Printer::log("bzip2 decompression failed. File cannot be read.", ELL_ERROR); + return 0; + } + bz_ctx.next_in = (char*)pcData; + bz_ctx.avail_in = decryptedSize; + /* pass all input to decompressor */ + bz_ctx.next_out = pBuf; + bz_ctx.avail_out = uncompressedSize; + err = BZ2_bzDecompress(&bz_ctx); + err = BZ2_bzDecompressEnd(&bz_ctx); + + if (decrypted) + decrypted->drop(); + else + delete[] pcData; + + if (err != BZ_OK) + { + swprintf_irr ( buf, 64, L"Error decompressing %s", core::stringw(Files[index].FullName).c_str() ); + os::Printer::log( buf, ELL_ERROR); + delete [] pBuf; + return 0; + } + else + return FileSystem->createMemoryReadFile(pBuf, uncompressedSize, Files[index].FullName, true); + + #else + os::Printer::log("bzip2 decompression not supported. File cannot be read.", ELL_ERROR); + return 0; + #endif + } + case 14: + { + #ifdef _IRR_COMPILE_WITH_LZMA_ + + u32 uncompressedSize = e.header.DataDescriptor.UncompressedSize; + c8* pBuf = new c8[ uncompressedSize ]; + if (!pBuf) + { + swprintf_irr ( buf, 64, L"Not enough memory for decompressing %s", core::stringw(Files[index].FullName).c_str() ); + os::Printer::log( buf, ELL_ERROR); + if (decrypted) + decrypted->drop(); + return 0; + } + + u8 *pcData = decryptedBuf; + if (!pcData) + { + pcData = new u8[decryptedSize]; + if (!pcData) + { + swprintf_irr ( buf, 64, L"Not enough memory for decompressing %s", core::stringw(Files[index].FullName).c_str() ); + os::Printer::log( buf, ELL_ERROR); + delete [] pBuf; + return 0; + } + + //memset(pcData, 0, decryptedSize); + File->seek(e.Offset); + File->read(pcData, decryptedSize); + } + + ELzmaStatus status; + SizeT tmpDstSize = uncompressedSize; + SizeT tmpSrcSize = decryptedSize; + + unsigned int propSize = (pcData[3]<<8)+pcData[2]; + int err = LzmaDecode((Byte*)pBuf, &tmpDstSize, + pcData+4+propSize, &tmpSrcSize, + pcData+4, propSize, + e.header.GeneralBitFlag&0x1?LZMA_FINISH_END:LZMA_FINISH_ANY, &status, + &lzmaAlloc); + uncompressedSize = tmpDstSize; // may be different to expected value + + if (decrypted) + decrypted->drop(); + else + delete[] pcData; + + if (err != SZ_OK) + { + os::Printer::log( "Error decompressing", Files[index].FullName, ELL_ERROR); + delete [] pBuf; + return 0; + } + else + return FileSystem->createMemoryReadFile(pBuf, uncompressedSize, Files[index].FullName, true); + + #else + os::Printer::log("lzma decompression not supported. File cannot be read.", ELL_ERROR); + return 0; + #endif + } + case 99: + // If we come here with an encrypted file, decryption support is missing + os::Printer::log("Decryption support not enabled. File cannot be read.", ELL_ERROR); + return 0; + default: + swprintf_irr ( buf, 64, L"file has unsupported compression method. %s", core::stringw(Files[index].FullName).c_str() ); + os::Printer::log( buf, ELL_ERROR); + return 0; + }; + +} + +} // end namespace io +} // end namespace irr + +#endif // __IRR_COMPILE_WITH_ZIP_ARCHIVE_LOADER_ diff --git a/source/Irrlicht/CZipReader.h b/source/Irrlicht/CZipReader.h new file mode 100644 index 00000000..286c4ebf --- /dev/null +++ b/source/Irrlicht/CZipReader.h @@ -0,0 +1,231 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_ZIP_READER_H_INCLUDED__ +#define __C_ZIP_READER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef __IRR_COMPILE_WITH_ZIP_ARCHIVE_LOADER_ + +#include "IReadFile.h" +#include "irrArray.h" +#include "irrString.h" +#include "IFileSystem.h" +#include "CFileList.h" + +namespace irr +{ +namespace io +{ + // set if the file is encrypted + const s16 ZIP_FILE_ENCRYPTED = 0x0001; + // the fields crc-32, compressed size and uncompressed size are set to + // zero in the local header + const s16 ZIP_INFO_IN_DATA_DESCRIPTOR = 0x0008; + +// byte-align structures +#include "irrpack.h" + + struct SZIPFileDataDescriptor + { + u32 CRC32; + u32 CompressedSize; + u32 UncompressedSize; + } PACK_STRUCT; + + struct SZIPFileHeader + { + u32 Sig; // 'PK0304' little endian (0x04034b50) + s16 VersionToExtract; + s16 GeneralBitFlag; + s16 CompressionMethod; + s16 LastModFileTime; + s16 LastModFileDate; + SZIPFileDataDescriptor DataDescriptor; + s16 FilenameLength; + s16 ExtraFieldLength; + // filename (variable size) + // extra field (variable size ) + } PACK_STRUCT; + + struct SZIPFileCentralDirFileHeader + { + u32 Sig; // 'PK0102' (0x02014b50) + u16 VersionMadeBy; + u16 VersionToExtract; + u16 GeneralBitFlag; + u16 CompressionMethod; + u16 LastModFileTime; + u16 LastModFileDate; + u32 CRC32; + u32 CompressedSize; + u32 UncompressedSize; + u16 FilenameLength; + u16 ExtraFieldLength; + u16 FileCommentLength; + u16 DiskNumberStart; + u16 InternalFileAttributes; + u32 ExternalFileAttributes; + u32 RelativeOffsetOfLocalHeader; + + // filename (variable size) + // extra field (variable size) + // file comment (variable size) + + } PACK_STRUCT; + + struct SZIPFileCentralDirEnd + { + u32 Sig; // 'PK0506' end_of central dir signature // (0x06054b50) + u16 NumberDisk; // number of this disk + u16 NumberStart; // number of the disk with the start of the central directory + u16 TotalDisk; // total number of entries in the central dir on this disk + u16 TotalEntries; // total number of entries in the central dir + u32 Size; // size of the central directory + u32 Offset; // offset of start of centraldirectory with respect to the starting disk number + u16 CommentLength; // zipfile comment length + // zipfile comment (variable size) + } PACK_STRUCT; + + struct SZipFileExtraHeader + { + s16 ID; + s16 Size; + } PACK_STRUCT; + + struct SZipFileAESExtraData + { + s16 Version; + u8 Vendor[2]; + u8 EncryptionStrength; + s16 CompressionMode; + } PACK_STRUCT; + + enum E_GZIP_FLAGS + { + EGZF_TEXT_DAT = 1, + EGZF_CRC16 = 2, + EGZF_EXTRA_FIELDS = 4, + EGZF_FILE_NAME = 8, + EGZF_COMMENT = 16 + }; + + struct SGZIPMemberHeader + { + u16 sig; // 0x8b1f + u8 compressionMethod; // 8 = deflate + u8 flags; + u32 time; + u8 extraFlags; // slow compress = 2, fast compress = 4 + u8 operatingSystem; + } PACK_STRUCT; + +// Default alignment +#include "irrunpack.h" + + //! Contains extended info about zip files in the archive + struct SZipFileEntry + { + //! Position of data in the archive file + s32 Offset; + + //! The header for this file containing compression info etc + SZIPFileHeader header; + }; + + //! Archiveloader capable of loading ZIP Archives + class CArchiveLoaderZIP : public IArchiveLoader + { + public: + + //! Constructor + CArchiveLoaderZIP(io::IFileSystem* fs); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".zip") + virtual bool isALoadableFileFormat(const io::path& filename) const _IRR_OVERRIDE_; + + //! Check if the file might be loaded by this class + /** Check might look into the file. + \param file File handle to check. + \return True if file seems to be loadable. */ + virtual bool isALoadableFileFormat(io::IReadFile* file) const _IRR_OVERRIDE_; + + //! Check to see if the loader can create archives of this type. + /** Check based on the archive type. + \param fileType The archive type to check. + \return True if the archile loader supports this type, false if not */ + virtual bool isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const _IRR_OVERRIDE_; + + //! Creates an archive from the filename + /** \param file File handle to check. + \return Pointer to newly created archive, or 0 upon error. */ + virtual IFileArchive* createArchive(const io::path& filename, bool ignoreCase, bool ignorePaths) const _IRR_OVERRIDE_; + + //! creates/loads an archive from the file. + //! \return Pointer to the created archive. Returns 0 if loading failed. + virtual io::IFileArchive* createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const _IRR_OVERRIDE_; + + private: + io::IFileSystem* FileSystem; + }; + +/*! + Zip file Reader written April 2002 by N.Gebhardt. +*/ + class CZipReader : public virtual IFileArchive, virtual CFileList + { + public: + + //! constructor + CZipReader(IFileSystem* fs, IReadFile* file, bool ignoreCase, bool ignorePaths, bool isGZip=false); + + //! destructor + virtual ~CZipReader(); + + //! opens a file by file name + virtual IReadFile* createAndOpenFile(const io::path& filename) _IRR_OVERRIDE_; + + //! opens a file by index + virtual IReadFile* createAndOpenFile(u32 index) _IRR_OVERRIDE_; + + //! returns the list of files + virtual const IFileList* getFileList() const _IRR_OVERRIDE_; + + //! get the archive type + virtual E_FILE_ARCHIVE_TYPE getType() const _IRR_OVERRIDE_; + + //! return the id of the file Archive + virtual const io::path& getArchiveName() const _IRR_OVERRIDE_ {return Path;} + + protected: + + //! reads the next file header from a ZIP file, returns false if there are no more headers. + /* if ignoreGPBits is set, the item will be read despite missing + file information. This is used when reading items from the central + directory. */ + bool scanZipHeader(bool ignoreGPBits=false); + + //! the same but for gzip files + bool scanGZipHeader(); + + bool scanCentralDirectoryHeader(); + + io::IFileSystem* FileSystem; + IReadFile* File; + + // holds extended info about files + core::array FileInfo; + + bool IsGZip; + }; + + +} // end namespace io +} // end namespace irr + +#endif // __IRR_COMPILE_WITH_ZIP_ARCHIVE_LOADER_ +#endif // __C_ZIP_READER_H_INCLUDED__ + diff --git a/source/Irrlicht/EProfileIDs.h b/source/Irrlicht/EProfileIDs.h new file mode 100644 index 00000000..b986e4f0 --- /dev/null +++ b/source/Irrlicht/EProfileIDs.h @@ -0,0 +1,54 @@ +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef E_PROFILE_IDS_H_INCLUDED__ +#define E_PROFILE_IDS_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#include "limits.h" + +namespace irr +{ +#ifdef _IRR_COMPILE_WITH_PROFILING_ + enum EPROFILE_ID + { + // We use negative ID's to avoid clashing with user application id's. + EPID_FIRST = -INT_MAX, // not used + + //! scenemanager. + EPID_SM_DRAW_ALL, + EPID_SM_ANIMATE, + EPID_SM_RENDER_CAMERAS, + EPID_SM_RENDER_LIGHTS, + EPID_SM_RENDER_SKYBOXES, + EPID_SM_RENDER_DEFAULT, + EPID_SM_RENDER_SHADOWS, + EPID_SM_RENDER_TRANSPARENT, + EPID_SM_RENDER_EFFECT, + EPID_SM_REGISTER, + + //! octrees + EPID_OC_RENDER, + EPID_OC_CALCPOLYS, + + //! es2 driver + EPID_ES2_END_SCENE, + EPID_ES2_BEGIN_SCENE, + EPID_ES2_UPDATE_VERTEX_HW_BUF, + EPID_ES2_UPDATE_INDEX_HW_BUF, + EPID_ES2_DRAW_PRIMITIVES, + EPID_ES2_DRAW_2DIMAGE, + EPID_ES2_DRAW_2DIMAGE_BATCH, + EPID_ES2_DRAW_2DRECTANGLE, + EPID_ES2_DRAW_2DLINE, + EPID_ES2_DRAW_3DLINE, + EPID_ES2_SET_RENDERSTATE_2D, + EPID_ES2_SET_RENDERSTATE_3D, + EPID_ES2_SET_RENDERSTATE_BASIC, + EPID_ES2_SET_RENDERSTATE_TEXTURE, + EPID_ES2_DRAW_SHADOW + }; +#endif +} // end namespace irr + +#endif // E_PROFILE_IDS_H_INCLUDED__ diff --git a/source/Irrlicht/IAttribute.h b/source/Irrlicht/IAttribute.h new file mode 100644 index 00000000..554ca951 --- /dev/null +++ b/source/Irrlicht/IAttribute.h @@ -0,0 +1,116 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_ATTRIBUTE_H_INCLUDED__ +#define __I_ATTRIBUTE_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "SColor.h" +#include "vector3d.h" +#include "vector2d.h" +#include "line2d.h" +#include "line3d.h" +#include "triangle3d.h" +#include "position2d.h" +#include "rect.h" +#include "dimension2d.h" +#include "matrix4.h" +#include "quaternion.h" +#include "plane3d.h" +#include "triangle3d.h" +#include "line2d.h" +#include "line3d.h" +#include "irrString.h" +#include "irrArray.h" +#include "EAttributes.h" + + +namespace irr +{ +namespace io +{ + +// All derived attribute types implement at least getter/setter for their own type (like CBoolAttribute will have setBool/getBool). +// Simple types will also implement getStringW and setString, but don't expect it to work for all types. +// String serialization makes no sense for some attribute-types (like stringw arrays or pointers), but is still useful for many types. +// (Note: I do _not_ know yet why the default string serialization is asymmetric with char* in set and wchar_t* in get). +// Additionally many attribute types will implement conversion functions like CBoolAttribute has p.E. getInt/setInt(). +// The reason for conversion functions is likely to make reading old formats easier which have changed in the meantime. For example +// an old xml can contain a bool attribute which is an int in a newer format. You can still call getInt() even thought the attribute has the wrong type. +// And please do _not_ confuse these attributes here with the ones used in the xml-reader (aka SAttribute which is just a key-value pair). + +class IAttribute : public virtual IReferenceCounted +{ +public: + + virtual ~IAttribute() {}; + + virtual s32 getInt() const { return 0; } + virtual f32 getFloat() const { return 0; } + virtual video::SColorf getColorf() const { return video::SColorf(1.0f,1.0f,1.0f,1.0f); } + virtual video::SColor getColor() const { return video::SColor(255,255,255,255); } + virtual core::stringc getString() const { return core::stringc(getStringW().c_str()); } + virtual core::stringw getStringW() const { return core::stringw(); } + virtual core::array getArray() const { return core::array(); }; + virtual bool getBool() const { return false; } + virtual void getBinary(void* outdata, s32 maxLength) const {}; + virtual core::vector3df getVector() const { return core::vector3df(); } + virtual core::position2di getPosition() const { return core::position2di(); } + virtual core::rect getRect() const { return core::rect(); } + virtual core::quaternion getQuaternion() const { return core::quaternion(); } + virtual core::matrix4 getMatrix() const { return core::matrix4(); } + virtual core::triangle3df getTriangle() const { return core::triangle3df(); } + virtual core::vector2df getVector2d() const { return core::vector2df(); } + virtual core::vector2di getVector2di() const { return core::vector2di(); } + virtual core::line2df getLine2d() const { return core::line2df(); } + virtual core::line2di getLine2di() const { return core::line2di(); } + virtual core::line3df getLine3d() const { return core::line3df(); } + virtual core::line3di getLine3di() const { return core::line3di(); } + virtual core::dimension2du getDimension2d() const { return core::dimension2du(); } + virtual core::aabbox3d getBBox() const { return core::aabbox3d(); } + virtual core::plane3df getPlane() const { return core::plane3df(); } + + virtual video::ITexture* getTexture() const { return 0; } + virtual const char* getEnum() const { return 0; } + virtual void* getUserPointer() const { return 0; } + + virtual void setInt(s32 intValue) {}; + virtual void setFloat(f32 floatValue) {}; + virtual void setString(const char* text) {}; + virtual void setString(const wchar_t* text){ setString(core::stringc(text).c_str()); }; + virtual void setArray(const core::array& arr ) {}; + virtual void setColor(video::SColorf color) {}; + virtual void setColor(video::SColor color) {}; + virtual void setBool(bool boolValue) {}; + virtual void setBinary(void* data, s32 maxLength) {}; + virtual void setVector(const core::vector3df& v) {}; + virtual void setPosition(const core::position2di& v) {}; + virtual void setRect(const core::rect& v) {}; + virtual void setQuaternion(const core::quaternion& v) {}; + virtual void setMatrix(const core::matrix4& v) {}; + virtual void setTriangle(const core::triangle3df& v) {}; + virtual void setVector2d(const core::vector2df& v) {}; + virtual void setVector2d(const core::vector2di& v) {}; + virtual void setLine2d(const core::line2df& v) {}; + virtual void setLine2d(const core::line2di& v) {}; + virtual void setLine3d(const core::line3df& v) {}; + virtual void setLine3d(const core::line3di& v) {}; + virtual void setDimension2d(const core::dimension2du& v) {}; + virtual void setBBox(const core::aabbox3d& v) {}; + virtual void setPlane(const core::plane3df& v) {}; + virtual void setUserPointer(void* v) {}; + + virtual void setEnum(const char* enumValue, const char* const* enumerationLiterals) {}; + virtual void setTexture(video::ITexture*, const path& filename) {}; + + core::stringc Name; + + virtual E_ATTRIBUTE_TYPE getType() const = 0; + virtual const wchar_t* getTypeString() const = 0; +}; + +} // end namespace io +} // end namespace irr + +#endif diff --git a/source/Irrlicht/IBurningShader.cpp b/source/Irrlicht/IBurningShader.cpp new file mode 100644 index 00000000..f11eac31 --- /dev/null +++ b/source/Irrlicht/IBurningShader.cpp @@ -0,0 +1,119 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +#include "SoftwareDriver2_compile_config.h" +#include "IBurningShader.h" +#include "CSoftwareDriver2.h" + +namespace irr +{ +namespace video +{ + + const tFixPointu IBurningShader::dithermask[] = + { + 0x00,0x80,0x20,0xa0, + 0xc0,0x40,0xe0,0x60, + 0x30,0xb0,0x10,0x90, + 0xf0,0x70,0xd0,0x50 + }; + + IBurningShader::IBurningShader(CBurningVideoDriver* driver) + { + #ifdef _DEBUG + setDebugName("IBurningShader"); + #endif + + for ( u32 i = 0; i != BURNING_MATERIAL_MAX_TEXTURES; ++i ) + { + IT[i].Texture = 0; + } + + Driver = driver; + RenderTarget = 0; + ColorMask = COLOR_BRIGHT_WHITE; + DepthBuffer = (CDepthBuffer*) driver->getDepthBuffer (); + if ( DepthBuffer ) + DepthBuffer->grab(); + + Stencil = (CStencilBuffer*) driver->getStencilBuffer (); + if ( Stencil ) + Stencil->grab(); + + } + + + //! destructor + IBurningShader::~IBurningShader() + { + if (RenderTarget) + RenderTarget->drop(); + + if (DepthBuffer) + DepthBuffer->drop(); + + if (Stencil) + Stencil->drop(); + + for ( u32 i = 0; i != BURNING_MATERIAL_MAX_TEXTURES; ++i ) + { + if ( IT[i].Texture ) + IT[i].Texture->drop(); + } + } + + //! sets a render target + void IBurningShader::setRenderTarget(video::IImage* surface, const core::rect& viewPort) + { + if (RenderTarget) + RenderTarget->drop(); + + RenderTarget = (video::CImage* ) surface; + + if (RenderTarget) + { + RenderTarget->grab(); + + //(fp24*) DepthBuffer->lock() = DepthBuffer->lock(); + } + } + + + //! sets the Texture + void IBurningShader::setTextureParam( u32 stage, video::CSoftwareTexture2* texture, s32 lodLevel) + { + sInternalTexture *it = &IT[stage]; + + if ( it->Texture) + it->Texture->drop(); + + it->Texture = texture; + + if ( it->Texture) + { + it->Texture->grab(); + + // select mignify and magnify ( lodLevel ) + //SOFTWARE_DRIVER_2_MIPMAPPING_LOD_BIAS + it->lodLevel = lodLevel; + it->data = (tVideoSample*) it->Texture->lock(ETLM_READ_ONLY, + core::s32_clamp ( lodLevel + SOFTWARE_DRIVER_2_MIPMAPPING_LOD_BIAS, 0, SOFTWARE_DRIVER_2_MIPMAPPING_MAX - 1 ), 0); + + // prepare for optimal fixpoint + it->pitchlog2 = s32_log2_s32 ( it->Texture->getPitch() ); + + 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; + } + } + + +} // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ diff --git a/source/Irrlicht/IBurningShader.h b/source/Irrlicht/IBurningShader.h new file mode 100644 index 00000000..0fffff7c --- /dev/null +++ b/source/Irrlicht/IBurningShader.h @@ -0,0 +1,202 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_BURNING_SHADER_H_INCLUDED__ +#define __I_BURNING_SHADER_H_INCLUDED__ + +#include "SoftwareDriver2_compile_config.h" +#include "IReferenceCounted.h" +#include "irrMath.h" +#include "irrMathFastCompat.h" +#include "IImage.h" +#include "S2DVertex.h" +#include "rect.h" +#include "CDepthBuffer.h" +#include "S4DVertex.h" +#include "irrArray.h" +#include "SLight.h" +#include "SMaterial.h" +#include "os.h" + + +namespace irr +{ + +namespace video +{ + + struct SBurningShaderLight + { + //SLight org; + bool LightIsOn; + + E_LIGHT_TYPE Type; + f32 radius; + f32 linearAttenuation; + f32 constantAttenuation; + f32 quadraticAttenuation; + sVec4 pos; + + sVec3 AmbientColor; + sVec3 DiffuseColor; + sVec3 SpecularColor; + sVec4 pos_objectspace; + }; + + enum eLightFlags + { + ENABLED = 0x01, + POINTLIGHT = 0x02, + SPECULAR = 0x04, + FOG = 0x08, + NORMALIZE = 0x10, + VERTEXTRANSFORM = 0x20, + }; + + struct SBurningShaderLightSpace + { + void reset () + { + Light.set_used ( 0 ); + Global_AmbientLight.set ( 0.f, 0.f, 0.f ); + Flags = 0; + } + core::array Light; + sVec3 Global_AmbientLight; + sVec4 FogColor; + sVec4 campos; + sVec4 vertex; + sVec4 normal; + u32 Flags; + }; + + struct SBurningShaderMaterial + { + SMaterial org; + + sVec3 AmbientColor; + sVec3 DiffuseColor; + sVec3 SpecularColor; + sVec3 EmissiveColor; + + }; + + enum EBurningFFShader + { + ETR_FLAT = 0, + ETR_FLAT_WIRE, + ETR_GOURAUD, + ETR_GOURAUD_WIRE, + ETR_TEXTURE_FLAT, + ETR_TEXTURE_FLAT_WIRE, + ETR_TEXTURE_GOURAUD, + ETR_TEXTURE_GOURAUD_WIRE, + ETR_TEXTURE_GOURAUD_NOZ, + ETR_TEXTURE_GOURAUD_ADD, + ETR_TEXTURE_GOURAUD_ADD_NO_Z, + + ETR_TEXTURE_GOURAUD_VERTEX_ALPHA, + + ETR_TEXTURE_GOURAUD_LIGHTMAP_M1, + ETR_TEXTURE_GOURAUD_LIGHTMAP_M2, + ETR_TEXTURE_GOURAUD_LIGHTMAP_M4, + ETR_TEXTURE_LIGHTMAP_M4, + + ETR_TEXTURE_GOURAUD_DETAIL_MAP, + ETR_TEXTURE_GOURAUD_LIGHTMAP_ADD, + + ETR_GOURAUD_ALPHA, + ETR_GOURAUD_ALPHA_NOZ, + + ETR_TEXTURE_GOURAUD_ALPHA, + ETR_TEXTURE_GOURAUD_ALPHA_NOZ, + + ETR_NORMAL_MAP_SOLID, + ETR_STENCIL_SHADOW, + + ETR_TEXTURE_BLEND, + ETR_REFERENCE, + ETR_INVALID, + + ETR2_COUNT + }; + + + class CBurningVideoDriver; + class IBurningShader : public virtual IReferenceCounted + { + public: + IBurningShader(CBurningVideoDriver* driver); + + //! destructor + virtual ~IBurningShader(); + + //! sets a render target + virtual void setRenderTarget(video::IImage* surface, const core::rect& viewPort); + + //! sets the Texture + virtual void setTextureParam( u32 stage, video::CSoftwareTexture2* texture, s32 lodLevel); + virtual void drawTriangle ( const s4DVertex *a,const s4DVertex *b,const s4DVertex *c ) = 0; + virtual void drawLine ( const s4DVertex *a,const s4DVertex *b) {}; + + virtual void setParam ( u32 index, f32 value) {}; + virtual void setZCompareFunc ( u32 func) {}; + + virtual void setMaterial ( const SBurningShaderMaterial &material ) {}; + + protected: + + CBurningVideoDriver *Driver; + + video::CImage* RenderTarget; + CDepthBuffer* DepthBuffer; + CStencilBuffer * Stencil; + tVideoSample ColorMask; + + sInternalTexture IT[ BURNING_MATERIAL_MAX_TEXTURES ]; + + static const tFixPointu dithermask[ 4 * 4]; + }; + + + IBurningShader* createTriangleRendererTextureGouraud2(CBurningVideoDriver* driver); + IBurningShader* createTriangleRendererTextureLightMap2_M1(CBurningVideoDriver* driver); + IBurningShader* createTriangleRendererTextureLightMap2_M2(CBurningVideoDriver* driver); + IBurningShader* createTriangleRendererTextureLightMap2_M4(CBurningVideoDriver* driver); + IBurningShader* createTriangleRendererGTextureLightMap2_M4(CBurningVideoDriver* driver); + IBurningShader* createTriangleRendererTextureLightMap2_Add(CBurningVideoDriver* driver); + IBurningShader* createTriangleRendererTextureDetailMap2(CBurningVideoDriver* driver); + IBurningShader* createTriangleRendererTextureVertexAlpha2(CBurningVideoDriver* driver); + + + IBurningShader* createTriangleRendererTextureGouraudWire2(CBurningVideoDriver* driver); + IBurningShader* createTriangleRendererGouraud2(CBurningVideoDriver* driver); + IBurningShader* createTriangleRendererGouraudAlpha2(CBurningVideoDriver* driver); + IBurningShader* createTRGouraudAlphaNoZ2(CBurningVideoDriver* driver); + IBurningShader* createTriangleRendererGouraudWire2(CBurningVideoDriver* driver); + IBurningShader* createTriangleRendererTextureFlat2(CBurningVideoDriver* driver); + IBurningShader* createTriangleRendererTextureFlatWire2(CBurningVideoDriver* driver); + IBurningShader* createTRFlat2(CBurningVideoDriver* driver); + IBurningShader* createTRFlatWire2(CBurningVideoDriver* driver); + IBurningShader* createTRTextureGouraudNoZ2(CBurningVideoDriver* driver); + IBurningShader* createTRTextureGouraudAdd2(CBurningVideoDriver* driver); + IBurningShader* createTRTextureGouraudAddNoZ2(CBurningVideoDriver* driver); + + IBurningShader* createTRTextureGouraudAlpha(CBurningVideoDriver* driver); + IBurningShader* createTRTextureGouraudAlphaNoZ(CBurningVideoDriver* driver); + IBurningShader* createTRTextureBlend(CBurningVideoDriver* driver); + IBurningShader* createTRTextureInverseAlphaBlend(CBurningVideoDriver* driver); + + IBurningShader* createTRNormalMap(CBurningVideoDriver* driver); + IBurningShader* createTRStencilShadow(CBurningVideoDriver* driver); + + IBurningShader* createTriangleRendererReference(CBurningVideoDriver* driver); + + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/IDepthBuffer.h b/source/Irrlicht/IDepthBuffer.h new file mode 100644 index 00000000..719d9f17 --- /dev/null +++ b/source/Irrlicht/IDepthBuffer.h @@ -0,0 +1,82 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_Z2_BUFFER_H_INCLUDED__ +#define __I_Z2_BUFFER_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "dimension2d.h" +#include "S4DVertex.h" + +namespace irr +{ +namespace video +{ + class IDepthBuffer : public virtual IReferenceCounted + { + public: + + //! destructor + virtual ~IDepthBuffer() {}; + + //! clears the zbuffer + virtual void clear() = 0; + + //! sets the new size of the zbuffer + virtual void setSize(const core::dimension2d& size) = 0; + + //! returns the size of the zbuffer + virtual const core::dimension2d& getSize() const = 0; + + //! locks the zbuffer + virtual void* lock() = 0; + + //! unlocks the zbuffer + virtual void unlock() = 0; + + //! returns pitch of depthbuffer (in bytes) + virtual u32 getPitch() const = 0; + + }; + + + //! creates a ZBuffer + IDepthBuffer* createDepthBuffer(const core::dimension2d& size); + + class IStencilBuffer : public virtual IReferenceCounted + { + public: + + //! destructor + virtual ~IStencilBuffer() {}; + + //! clears the zbuffer + virtual void clear() = 0; + + //! sets the new size of the zbuffer + virtual void setSize(const core::dimension2d& size) = 0; + + //! returns the size of the zbuffer + virtual const core::dimension2d& getSize() const = 0; + + //! locks the zbuffer + virtual void* lock() = 0; + + //! unlocks the zbuffer + virtual void unlock() = 0; + + //! returns pitch of depthbuffer (in bytes) + virtual u32 getPitch() const = 0; + + }; + + + //! creates a Stencil Buffer + IStencilBuffer* createStencilBuffer(const core::dimension2d& size); + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/IImagePresenter.h b/source/Irrlicht/IImagePresenter.h new file mode 100644 index 00000000..c93fc855 --- /dev/null +++ b/source/Irrlicht/IImagePresenter.h @@ -0,0 +1,36 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_IMAGE_PRESENTER_H_INCLUDED__ +#define __I_IMAGE_PRESENTER_H_INCLUDED__ + +#include "IImage.h" + +namespace irr +{ +namespace video +{ + +/*! + Interface for a class which is able to present an IImage + an the Screen. Usually only implemented by an IrrDevice for + presenting Software Device Rendered images. + + This class should be used only internally. +*/ + + class IImagePresenter + { + public: + + virtual ~IImagePresenter() {}; + //! presents a surface in the client area + virtual bool present(video::IImage* surface, void* windowId=0, core::rect* src=0 ) = 0; + }; + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/ISceneNodeAnimatorFinishing.h b/source/Irrlicht/ISceneNodeAnimatorFinishing.h new file mode 100644 index 00000000..a6425621 --- /dev/null +++ b/source/Irrlicht/ISceneNodeAnimatorFinishing.h @@ -0,0 +1,36 @@ +// Copyright (C) 2002-2012 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) { } + + virtual bool hasFinished(void) const _IRR_OVERRIDE_ { 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 new file mode 100644 index 00000000..954ce6de --- /dev/null +++ b/source/Irrlicht/ITriangleRenderer.h @@ -0,0 +1,68 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_TRIANGLE_RENDERER_H_INCLUDED__ +#define __I_TRIANGLE_RENDERER_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "S2DVertex.h" +#include "rect.h" +#include "IZBuffer.h" + +namespace irr +{ +namespace video +{ + class IImage; + + enum ETriangleRenderer + { + ETR_FLAT = 0, + ETR_FLAT_WIRE, + ETR_GOURAUD, + ETR_GOURAUD_WIRE, + ETR_TEXTURE_FLAT, + ETR_TEXTURE_FLAT_WIRE, + ETR_TEXTURE_GOURAUD, + ETR_TEXTURE_GOURAUD_WIRE, + ETR_TEXTURE_GOURAUD_NOZ, + ETR_TEXTURE_GOURAUD_ADD, + ETR_COUNT + }; + + class ITriangleRenderer : public virtual IReferenceCounted + { + public: + + //! sets a render target + virtual void setRenderTarget(video::IImage* surface, const core::rect& viewPort) = 0; + + //! en or disables the backface culling + virtual void setBackfaceCulling(bool enabled = true) = 0; + + //! sets the Texture + virtual void setTexture(video::IImage* texture) = 0; + + //! draws an indexed triangle list + virtual void drawIndexedTriangleList(S2DVertex* vertices, s32 vertexCount, const u16* indexList, s32 triangleCount) = 0; + }; + + + ITriangleRenderer* createTriangleRendererTextureGouraud(IZBuffer* zbuffer); + ITriangleRenderer* createTriangleRendererTextureGouraudWire(IZBuffer* zbuffer); + ITriangleRenderer* createTriangleRendererGouraud(IZBuffer* zbuffer); + ITriangleRenderer* createTriangleRendererGouraudWire(IZBuffer* zbuffer); + ITriangleRenderer* createTriangleRendererTextureFlat(IZBuffer* zbuffer); + ITriangleRenderer* createTriangleRendererTextureFlatWire(IZBuffer* zbuffer); + ITriangleRenderer* createTriangleRendererFlat(IZBuffer* zbuffer); + ITriangleRenderer* createTriangleRendererFlatWire(IZBuffer* zbuffer); + ITriangleRenderer* createTriangleRendererTextureGouraudNoZ(); + ITriangleRenderer* createTriangleRendererTextureGouraudAdd(IZBuffer* zbuffer); + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/IZBuffer.h b/source/Irrlicht/IZBuffer.h new file mode 100644 index 00000000..2c235a89 --- /dev/null +++ b/source/Irrlicht/IZBuffer.h @@ -0,0 +1,47 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_Z_BUFFER_H_INCLUDED__ +#define __I_Z_BUFFER_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "dimension2d.h" +#include "S2DVertex.h" + +namespace irr +{ +namespace video +{ + class IZBuffer : public virtual IReferenceCounted + { + public: + + //! destructor + virtual ~IZBuffer() {}; + + //! clears the zbuffer + virtual void clear() = 0; + + //! sets the new size of the zbuffer + virtual void setSize(const core::dimension2d& size) = 0; + + //! returns the size of the zbuffer + virtual const core::dimension2d& getSize() const = 0; + + //! locks the zbuffer + virtual TZBufferType* lock() = 0; + + //! unlocks the zbuffer + virtual void unlock() = 0; + }; + + + //! creates a ZBuffer + IZBuffer* createZBuffer(const core::dimension2d& size); + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/Irrlicht-gcc.cbp b/source/Irrlicht/Irrlicht-gcc.cbp new file mode 100644 index 00000000..3e8d0ad0 --- /dev/null +++ b/source/Irrlicht/Irrlicht-gcc.cbp @@ -0,0 +1,1348 @@ + + + + + + diff --git a/source/Irrlicht/Irrlicht.cpp b/source/Irrlicht/Irrlicht.cpp new file mode 100644 index 00000000..c816aaec --- /dev/null +++ b/source/Irrlicht/Irrlicht.cpp @@ -0,0 +1,166 @@ +// Copyright (C) 2002-2012 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-2017 Nikolaus Gebhardt"; // put string in binary + +#ifdef _IRR_WINDOWS_ + #include + #if defined(_DEBUG) && !defined(__GNUWIN32__) && !defined(_WIN32_WCE) + #include + #endif // _DEBUG +#endif + +#include "irrlicht.h" +#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ +#include "CIrrDeviceWin32.h" +#endif + +#ifdef _IRR_COMPILE_WITH_X11_DEVICE_ +#include "CIrrDeviceLinux.h" +#endif + +#ifdef _IRR_COMPILE_WITH_OSX_DEVICE_ +#include "CIrrDeviceOSX.h" +#endif + +#ifdef _IRR_COMPILE_WITH_FB_DEVICE_ +#include "CIrrDeviceFB.h" +#endif + +#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ +#include "CIrrDeviceSDL.h" +#endif + +#ifdef _IRR_COMPILE_WITH_CONSOLE_DEVICE_ +#include "CIrrDeviceConsole.h" +#endif + +#ifdef _IRR_COMPILE_WITH_IOS_DEVICE_ +#include "CIrrDeviceiOS.h" +#endif + +#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_ +#include "Android/CIrrDeviceAndroid.h" +#endif + +namespace irr +{ + //! stub for calling createDeviceEx + IRRLICHT_API IrrlichtDevice* IRRCALLCONV createDevice(video::E_DRIVER_TYPE driverType, + const core::dimension2d& windowSize, + u32 bits, bool fullscreen, + bool stencilbuffer, bool vsync, IEventReceiver* res) + { + (void)copyright; // prevent unused variable warning + + SIrrlichtCreationParameters p; + p.DriverType = driverType; + p.WindowSize = windowSize; + p.Bits = (u8)bits; + p.Fullscreen = fullscreen; + p.Stencilbuffer = stencilbuffer; + p.Vsync = vsync; + p.EventReceiver = res; + + return createDeviceEx(p); + } + + extern "C" IRRLICHT_API IrrlichtDevice* IRRCALLCONV createDeviceEx(const SIrrlichtCreationParameters& params) + { + + IrrlichtDevice* dev = 0; + +#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ + if (params.DeviceType == EIDT_WIN32 || (!dev && params.DeviceType == EIDT_BEST)) + dev = new CIrrDeviceWin32(params); +#endif + +#ifdef _IRR_COMPILE_WITH_OSX_DEVICE_ + if (params.DeviceType == EIDT_OSX || (!dev && params.DeviceType == EIDT_BEST)) + dev = new CIrrDeviceMacOSX(params); +#endif + +#ifdef _IRR_COMPILE_WITH_X11_DEVICE_ + if (params.DeviceType == EIDT_X11 || (!dev && params.DeviceType == EIDT_BEST)) + dev = new CIrrDeviceLinux(params); +#endif + +#ifdef _IRR_COMPILE_WITH_IOS_DEVICE_ + if (params.DeviceType == EIDT_IOS || (!dev && params.DeviceType == EIDT_BEST)) + dev = new CIrrDeviceiOS(params); +#endif + +#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_ + if (params.DeviceType == EIDT_ANDROID || (!dev && params.DeviceType == EIDT_BEST)) + dev = new CIrrDeviceAndroid(params); +#endif + +#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ + if (params.DeviceType == EIDT_SDL || (!dev && params.DeviceType == EIDT_BEST)) + dev = new CIrrDeviceSDL(params); +#endif + +#ifdef _IRR_COMPILE_WITH_FB_DEVICE_ + if (params.DeviceType == EIDT_FRAMEBUFFER || (!dev && params.DeviceType == EIDT_BEST)) + dev = new CIrrDeviceFB(params); +#endif + +#ifdef _IRR_COMPILE_WITH_CONSOLE_DEVICE_ + if (params.DeviceType == EIDT_CONSOLE || (!dev && params.DeviceType == EIDT_BEST)) + dev = new CIrrDeviceConsole(params); +#endif + + if (dev && !dev->getVideoDriver() && params.DriverType != video::EDT_NULL) + { + dev->closeDevice(); // destroy window + dev->run(); // consume quit message + dev->drop(); + dev = 0; + } + + return dev; + } + +namespace core +{ + const matrix4 IdentityMatrix(matrix4::EM4CONST_IDENTITY); + irr::core::stringc LOCALE_DECIMAL_POINTS("."); +} + +namespace video +{ + SMaterial IdentityMaterial; + u32 MATERIAL_MAX_TEXTURES_USED = MATERIAL_MAX_TEXTURES; +} + +} // end namespace irr + + +#if defined(_IRR_WINDOWS_API_) && !defined(_IRR_STATIC_LIB_) + +BOOL APIENTRY DllMain( HANDLE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved ) +{ + // _crtBreakAlloc = 139; + + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + #if defined(_DEBUG) && !defined(__GNUWIN32__) && !defined(__BORLANDC__) && !defined (_WIN32_WCE) && !defined (_IRR_XBOX_PLATFORM_) + _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF); + #endif + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + +#endif // defined(_IRR_WINDOWS_) + diff --git a/source/Irrlicht/Irrlicht.dev b/source/Irrlicht/Irrlicht.dev new file mode 100644 index 00000000..e69de29b diff --git a/source/Irrlicht/Irrlicht.rc b/source/Irrlicht/Irrlicht.rc new file mode 100644 index 00000000..cb79e56f Binary files /dev/null and b/source/Irrlicht/Irrlicht.rc differ diff --git a/source/Irrlicht/Irrlicht.ruleset b/source/Irrlicht/Irrlicht.ruleset new file mode 100644 index 00000000..8766033d --- /dev/null +++ b/source/Irrlicht/Irrlicht.ruleset @@ -0,0 +1,348 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Irrlicht/Irrlicht.xcodeproj/project.pbxproj b/source/Irrlicht/Irrlicht.xcodeproj/project.pbxproj new file mode 100644 index 00000000..983e3e95 --- /dev/null +++ b/source/Irrlicht/Irrlicht.xcodeproj/project.pbxproj @@ -0,0 +1,3389 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E1DF8E11E96BFE100FC3523 /* CIrrDeviceOSX.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8141B7F535C00F212E8 /* CIrrDeviceOSX.mm */; }; + 5E34C9F91B7F6EBF00F212E8 /* CDefaultGUIElementFactory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7E21B7F50DE00F212E8 /* CDefaultGUIElementFactory.cpp */; }; + 5E34C9FB1B7F6EBF00F212E8 /* CGUIButton.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7A91B7F50A900F212E8 /* CGUIButton.cpp */; }; + 5E34C9FD1B7F6EBF00F212E8 /* CGUICheckBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7AB1B7F50A900F212E8 /* CGUICheckBox.cpp */; }; + 5E34C9FF1B7F6EBF00F212E8 /* CGUIColorSelectDialog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7AD1B7F50A900F212E8 /* CGUIColorSelectDialog.cpp */; }; + 5E34CA011B7F6EBF00F212E8 /* CGUIComboBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7AF1B7F50A900F212E8 /* CGUIComboBox.cpp */; }; + 5E34CA031B7F6EBF00F212E8 /* CGUIContextMenu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7B11B7F50A900F212E8 /* CGUIContextMenu.cpp */; }; + 5E34CA051B7F6EBF00F212E8 /* CGUIEditBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7B31B7F50A900F212E8 /* CGUIEditBox.cpp */; }; + 5E34CA071B7F6EBF00F212E8 /* CGUIEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7B51B7F50A900F212E8 /* CGUIEnvironment.cpp */; }; + 5E34CA091B7F6EBF00F212E8 /* CGUIFileOpenDialog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7B71B7F50A900F212E8 /* CGUIFileOpenDialog.cpp */; }; + 5E34CA0B1B7F6EBF00F212E8 /* CGUIFont.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7B91B7F50A900F212E8 /* CGUIFont.cpp */; }; + 5E34CA0D1B7F6EBF00F212E8 /* CGUIImage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7BB1B7F50A900F212E8 /* CGUIImage.cpp */; }; + 5E34CA0F1B7F6EBF00F212E8 /* CGUIImageList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7BD1B7F50A900F212E8 /* CGUIImageList.cpp */; }; + 5E34CA111B7F6EBF00F212E8 /* CGUIInOutFader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7BF1B7F50A900F212E8 /* CGUIInOutFader.cpp */; }; + 5E34CA131B7F6EBF00F212E8 /* CGUIListBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7C11B7F50A900F212E8 /* CGUIListBox.cpp */; }; + 5E34CA151B7F6EBF00F212E8 /* CGUIMenu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7C31B7F50A900F212E8 /* CGUIMenu.cpp */; }; + 5E34CA171B7F6EBF00F212E8 /* CGUIMeshViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7C51B7F50A900F212E8 /* CGUIMeshViewer.cpp */; }; + 5E34CA191B7F6EBF00F212E8 /* CGUIMessageBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7C71B7F50A900F212E8 /* CGUIMessageBox.cpp */; }; + 5E34CA1B1B7F6EBF00F212E8 /* CGUIModalScreen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7C91B7F50A900F212E8 /* CGUIModalScreen.cpp */; }; + 5E34CA1D1B7F6EBF00F212E8 /* CGUIProfiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7CB1B7F50A900F212E8 /* CGUIProfiler.cpp */; }; + 5E34CA1F1B7F6EBF00F212E8 /* CGUIScrollBar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7CD1B7F50A900F212E8 /* CGUIScrollBar.cpp */; }; + 5E34CA211B7F6EBF00F212E8 /* CGUISkin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7CF1B7F50A900F212E8 /* CGUISkin.cpp */; }; + 5E34CA231B7F6EBF00F212E8 /* CGUISpinBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7D11B7F50A900F212E8 /* CGUISpinBox.cpp */; }; + 5E34CA251B7F6EBF00F212E8 /* CGUISpriteBank.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7D31B7F50A900F212E8 /* CGUISpriteBank.cpp */; }; + 5E34CA271B7F6EBF00F212E8 /* CGUIStaticText.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7D51B7F50A900F212E8 /* CGUIStaticText.cpp */; }; + 5E34CA291B7F6EBF00F212E8 /* CGUITabControl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7D71B7F50A900F212E8 /* CGUITabControl.cpp */; }; + 5E34CA2B1B7F6EBF00F212E8 /* CGUITable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7D91B7F50A900F212E8 /* CGUITable.cpp */; }; + 5E34CA2D1B7F6EBF00F212E8 /* CGUIToolBar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7DB1B7F50A900F212E8 /* CGUIToolBar.cpp */; }; + 5E34CA2F1B7F6EBF00F212E8 /* CGUITreeView.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7DD1B7F50A900F212E8 /* CGUITreeView.cpp */; }; + 5E34CA311B7F6EBF00F212E8 /* CGUIWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7DF1B7F50A900F212E8 /* CGUIWindow.cpp */; }; + 5E34CA341B7F6EBF00F212E8 /* CAttributes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7E51B7F517000F212E8 /* CAttributes.cpp */; }; + 5E34CA361B7F6EBF00F212E8 /* CFileList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7E71B7F517000F212E8 /* CFileList.cpp */; }; + 5E34CA381B7F6EBF00F212E8 /* CFileSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7E91B7F517000F212E8 /* CFileSystem.cpp */; }; + 5E34CA3A1B7F6EBF00F212E8 /* CLimitReadFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7EB1B7F517000F212E8 /* CLimitReadFile.cpp */; }; + 5E34CA3C1B7F6EBF00F212E8 /* CMemoryFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7ED1B7F517000F212E8 /* CMemoryFile.cpp */; }; + 5E34CA3E1B7F6EBF00F212E8 /* CMountPointReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7EF1B7F517000F212E8 /* CMountPointReader.cpp */; }; + 5E34CA401B7F6EBF00F212E8 /* CNPKReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7F11B7F517000F212E8 /* CNPKReader.cpp */; }; + 5E34CA421B7F6EBF00F212E8 /* CPakReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7F31B7F517000F212E8 /* CPakReader.cpp */; }; + 5E34CA441B7F6EBF00F212E8 /* CReadFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7F51B7F51D900F212E8 /* CReadFile.cpp */; }; + 5E34CA461B7F6EBF00F212E8 /* CTarReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7F71B7F51D900F212E8 /* CTarReader.cpp */; }; + 5E34CA481B7F6EBF00F212E8 /* CWADReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7F91B7F51D900F212E8 /* CWADReader.cpp */; }; + 5E34CA4A1B7F6EBF00F212E8 /* CWriteFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7FB1B7F51D900F212E8 /* CWriteFile.cpp */; }; + 5E34CA4C1B7F6EBF00F212E8 /* CXMLReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7FD1B7F51D900F212E8 /* CXMLReader.cpp */; }; + 5E34CA4F1B7F6EBF00F212E8 /* CXMLWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8001B7F51D900F212E8 /* CXMLWriter.cpp */; }; + 5E34CA511B7F6EBF00F212E8 /* CZipReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8021B7F51D900F212E8 /* CZipReader.cpp */; }; + 5E34CA541B7F6EBF00F212E8 /* irrXML.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8051B7F51D900F212E8 /* irrXML.cpp */; }; + 5E34CA591B7F6EBF00F212E8 /* CIrrDeviceStub.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C80D1B7F52AC00F212E8 /* CIrrDeviceStub.cpp */; }; + 5E34CA5C1B7F6EBF00F212E8 /* aescrypt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8161B7F540B00F212E8 /* aescrypt.cpp */; }; + 5E34CA5D1B7F6EBF00F212E8 /* aeskey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8171B7F540B00F212E8 /* aeskey.cpp */; }; + 5E34CA5F1B7F6EBF00F212E8 /* aestab.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8191B7F540B00F212E8 /* aestab.cpp */; }; + 5E34CA601B7F6EBF00F212E8 /* fileenc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C81A1B7F540B00F212E8 /* fileenc.cpp */; }; + 5E34CA621B7F6EBF00F212E8 /* hmac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C81C1B7F540B00F212E8 /* hmac.cpp */; }; + 5E34CA641B7F6EBF00F212E8 /* prng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C81E1B7F540B00F212E8 /* prng.cpp */; }; + 5E34CA661B7F6EBF00F212E8 /* pwd2key.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8201B7F540B00F212E8 /* pwd2key.cpp */; }; + 5E34CA681B7F6EBF00F212E8 /* sha1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8221B7F540B00F212E8 /* sha1.cpp */; }; + 5E34CA6A1B7F6EBF00F212E8 /* sha2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8241B7F540B00F212E8 /* sha2.cpp */; }; + 5E34CA6C1B7F6EBF00F212E8 /* blocksort.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8261B7F54FE00F212E8 /* blocksort.c */; }; + 5E34CA6D1B7F6EBF00F212E8 /* bzcompress.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8271B7F54FE00F212E8 /* bzcompress.c */; }; + 5E34CA6F1B7F6EBF00F212E8 /* bzlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8291B7F54FE00F212E8 /* bzlib.c */; }; + 5E34CA711B7F6EBF00F212E8 /* crctable.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C82B1B7F54FE00F212E8 /* crctable.c */; }; + 5E34CA721B7F6EBF00F212E8 /* decompress.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C82C1B7F54FE00F212E8 /* decompress.c */; }; + 5E34CA731B7F6EBF00F212E8 /* huffman.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C82D1B7F54FE00F212E8 /* huffman.c */; }; + 5E34CA741B7F6EBF00F212E8 /* randtable.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C82E1B7F54FE00F212E8 /* randtable.c */; }; + 5E34CA761B7F6EBF00F212E8 /* jaricom.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8321B7F561400F212E8 /* jaricom.c */; }; + 5E34CA771B7F6EBF00F212E8 /* jcapimin.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8331B7F561400F212E8 /* jcapimin.c */; }; + 5E34CA781B7F6EBF00F212E8 /* jcapistd.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8341B7F561400F212E8 /* jcapistd.c */; }; + 5E34CA791B7F6EBF00F212E8 /* jcarith.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8351B7F561400F212E8 /* jcarith.c */; }; + 5E34CA7A1B7F6EBF00F212E8 /* jccoefct.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8361B7F561400F212E8 /* jccoefct.c */; }; + 5E34CA7B1B7F6EBF00F212E8 /* jccolor.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8371B7F561400F212E8 /* jccolor.c */; }; + 5E34CA7C1B7F6EBF00F212E8 /* jcdctmgr.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8381B7F561400F212E8 /* jcdctmgr.c */; }; + 5E34CA7D1B7F6EBF00F212E8 /* jchuff.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8391B7F561400F212E8 /* jchuff.c */; }; + 5E34CA7E1B7F6EBF00F212E8 /* jcinit.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C83A1B7F561400F212E8 /* jcinit.c */; }; + 5E34CA7F1B7F6EBF00F212E8 /* jcmainct.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C83B1B7F561400F212E8 /* jcmainct.c */; }; + 5E34CA801B7F6EBF00F212E8 /* jcmarker.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C83C1B7F561400F212E8 /* jcmarker.c */; }; + 5E34CA811B7F6EBF00F212E8 /* jcmaster.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C83D1B7F561400F212E8 /* jcmaster.c */; }; + 5E34CA821B7F6EC000F212E8 /* jcomapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C83E1B7F561400F212E8 /* jcomapi.c */; }; + 5E34CA841B7F6EC000F212E8 /* jcparam.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8401B7F561400F212E8 /* jcparam.c */; }; + 5E34CA851B7F6EC000F212E8 /* jcprepct.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8411B7F561400F212E8 /* jcprepct.c */; }; + 5E34CA861B7F6EC000F212E8 /* jcsample.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8421B7F561400F212E8 /* jcsample.c */; }; + 5E34CA871B7F6EC000F212E8 /* jctrans.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8431B7F561400F212E8 /* jctrans.c */; }; + 5E34CA881B7F6EC000F212E8 /* jdapimin.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8441B7F561400F212E8 /* jdapimin.c */; }; + 5E34CA891B7F6EC000F212E8 /* jdapistd.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8451B7F561400F212E8 /* jdapistd.c */; }; + 5E34CA8A1B7F6EC000F212E8 /* jdarith.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8461B7F561400F212E8 /* jdarith.c */; }; + 5E34CA8B1B7F6EC000F212E8 /* jdatadst.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8471B7F561400F212E8 /* jdatadst.c */; }; + 5E34CA8C1B7F6EC000F212E8 /* jdatasrc.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8481B7F561400F212E8 /* jdatasrc.c */; }; + 5E34CA8D1B7F6EC000F212E8 /* jdcoefct.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8491B7F561400F212E8 /* jdcoefct.c */; }; + 5E34CA8E1B7F6EC000F212E8 /* jdcolor.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C84A1B7F561400F212E8 /* jdcolor.c */; }; + 5E34CA901B7F6EC000F212E8 /* jddctmgr.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C84C1B7F561400F212E8 /* jddctmgr.c */; }; + 5E34CA911B7F6EC000F212E8 /* jdhuff.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C84D1B7F561400F212E8 /* jdhuff.c */; }; + 5E34CA921B7F6EC000F212E8 /* jdinput.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C84E1B7F561400F212E8 /* jdinput.c */; }; + 5E34CA931B7F6EC000F212E8 /* jdmainct.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C84F1B7F561400F212E8 /* jdmainct.c */; }; + 5E34CA941B7F6EC000F212E8 /* jdmarker.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8501B7F561400F212E8 /* jdmarker.c */; }; + 5E34CA951B7F6EC000F212E8 /* jdmaster.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8511B7F561400F212E8 /* jdmaster.c */; }; + 5E34CA961B7F6EC000F212E8 /* jdmerge.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8521B7F561400F212E8 /* jdmerge.c */; }; + 5E34CA971B7F6EC000F212E8 /* jdpostct.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8531B7F561400F212E8 /* jdpostct.c */; }; + 5E34CA981B7F6EC000F212E8 /* jdsample.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8541B7F561400F212E8 /* jdsample.c */; }; + 5E34CA991B7F6EC000F212E8 /* jdtrans.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8551B7F561400F212E8 /* jdtrans.c */; }; + 5E34CA9A1B7F6EC000F212E8 /* jerror.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8561B7F561400F212E8 /* jerror.c */; }; + 5E34CA9C1B7F6EC000F212E8 /* jfdctflt.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8581B7F568200F212E8 /* jfdctflt.c */; }; + 5E34CA9D1B7F6EC000F212E8 /* jfdctfst.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8591B7F568200F212E8 /* jfdctfst.c */; }; + 5E34CA9E1B7F6EC000F212E8 /* jfdctint.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C85A1B7F568200F212E8 /* jfdctint.c */; }; + 5E34CA9F1B7F6EC000F212E8 /* jidctflt.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C85B1B7F568200F212E8 /* jidctflt.c */; }; + 5E34CAA01B7F6EC000F212E8 /* jidctfst.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C85C1B7F568200F212E8 /* jidctfst.c */; }; + 5E34CAA11B7F6EC000F212E8 /* jidctint.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C85D1B7F568200F212E8 /* jidctint.c */; }; + 5E34CAA31B7F6EC000F212E8 /* jmemmgr.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C85F1B7F568200F212E8 /* jmemmgr.c */; }; + 5E34CAA41B7F6EC000F212E8 /* jmemnobs.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8601B7F568200F212E8 /* jmemnobs.c */; }; + 5E34CAA91B7F6EC000F212E8 /* jquant1.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8651B7F568200F212E8 /* jquant1.c */; }; + 5E34CAAA1B7F6EC000F212E8 /* jquant2.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8661B7F568200F212E8 /* jquant2.c */; }; + 5E34CAAB1B7F6EC000F212E8 /* jutils.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8671B7F568200F212E8 /* jutils.c */; }; + 5E34CAAD1B7F6EC000F212E8 /* png.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8691B7F56E900F212E8 /* png.c */; }; + 5E34CAB01B7F6EC000F212E8 /* pngerror.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C86C1B7F56E900F212E8 /* pngerror.c */; }; + 5E34CAB11B7F6EC000F212E8 /* pngget.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C86D1B7F56E900F212E8 /* pngget.c */; }; + 5E34CAB21B7F6EC000F212E8 /* pngmem.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C86E1B7F56E900F212E8 /* pngmem.c */; }; + 5E34CAB31B7F6EC000F212E8 /* pngpread.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C86F1B7F56E900F212E8 /* pngpread.c */; }; + 5E34CAB41B7F6EC000F212E8 /* pngread.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8701B7F56E900F212E8 /* pngread.c */; }; + 5E34CAB51B7F6EC000F212E8 /* pngrio.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8711B7F56E900F212E8 /* pngrio.c */; }; + 5E34CAB61B7F6EC000F212E8 /* pngrtran.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8721B7F56E900F212E8 /* pngrtran.c */; }; + 5E34CAB71B7F6EC000F212E8 /* pngrutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8731B7F56E900F212E8 /* pngrutil.c */; }; + 5E34CAB81B7F6EC000F212E8 /* pngset.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8741B7F56E900F212E8 /* pngset.c */; }; + 5E34CAB91B7F6EC000F212E8 /* pngtrans.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8751B7F56E900F212E8 /* pngtrans.c */; }; + 5E34CABA1B7F6EC000F212E8 /* pngwio.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8761B7F56E900F212E8 /* pngwio.c */; }; + 5E34CABB1B7F6EC000F212E8 /* pngwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8771B7F56E900F212E8 /* pngwrite.c */; }; + 5E34CABC1B7F6EC000F212E8 /* pngwtran.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8781B7F56E900F212E8 /* pngwtran.c */; }; + 5E34CABD1B7F6EC000F212E8 /* pngwutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8791B7F56E900F212E8 /* pngwutil.c */; }; + 5E34CABE1B7F6EC000F212E8 /* LzmaDec.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C88F1B7F57B100F212E8 /* LzmaDec.c */; }; + 5E34CAC11B7F6EC000F212E8 /* adler32.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C87A1B7F577000F212E8 /* adler32.c */; }; + 5E34CAC21B7F6EC000F212E8 /* compress.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C87B1B7F577000F212E8 /* compress.c */; }; + 5E34CAC31B7F6EC000F212E8 /* crc32.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C87C1B7F577000F212E8 /* crc32.c */; }; + 5E34CAC51B7F6EC000F212E8 /* deflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C87E1B7F577000F212E8 /* deflate.c */; }; + 5E34CAC71B7F6EC000F212E8 /* inffast.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8801B7F577000F212E8 /* inffast.c */; }; + 5E34CACA1B7F6EC000F212E8 /* inflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8831B7F577000F212E8 /* inflate.c */; }; + 5E34CACC1B7F6EC000F212E8 /* inftrees.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8851B7F577000F212E8 /* inftrees.c */; }; + 5E34CACE1B7F6EC100F212E8 /* trees.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8871B7F577000F212E8 /* trees.c */; }; + 5E34CAD01B7F6EC100F212E8 /* uncompr.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8891B7F577000F212E8 /* uncompr.c */; }; + 5E34CAD31B7F6EC100F212E8 /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C88C1B7F577000F212E8 /* zutil.c */; }; + 5E34CAD51B7F6EC100F212E8 /* CLogger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8921B7F652600F212E8 /* CLogger.cpp */; }; + 5E34CAD71B7F6EC100F212E8 /* COSOperator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8941B7F652600F212E8 /* COSOperator.cpp */; }; + 5E34CAD91B7F6EC100F212E8 /* CProfiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8961B7F652600F212E8 /* CProfiler.cpp */; }; + 5E34CADD1B7F6EC100F212E8 /* Irrlicht.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C89A1B7F652600F212E8 /* Irrlicht.cpp */; }; + 5E34CADE1B7F6EC100F212E8 /* leakHunter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C89B1B7F652600F212E8 /* leakHunter.cpp */; }; + 5E34CADF1B7F6EC100F212E8 /* os.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C89C1B7F652600F212E8 /* os.cpp */; }; + 5E34CAE11B7F6EC100F212E8 /* utf8.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C89E1B7F652600F212E8 /* utf8.cpp */; }; + 5E34CAE21B7F6EC100F212E8 /* CSceneNodeAnimatorCameraFPS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8BA1B7F669200F212E8 /* CSceneNodeAnimatorCameraFPS.cpp */; }; + 5E34CAE41B7F6EC100F212E8 /* CSceneNodeAnimatorCameraMaya.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8BC1B7F669200F212E8 /* CSceneNodeAnimatorCameraMaya.cpp */; }; + 5E34CAE61B7F6EC100F212E8 /* CSceneNodeAnimatorCollisionResponse.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8BE1B7F669200F212E8 /* CSceneNodeAnimatorCollisionResponse.cpp */; }; + 5E34CAE81B7F6EC100F212E8 /* CSceneNodeAnimatorDelete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8C01B7F669200F212E8 /* CSceneNodeAnimatorDelete.cpp */; }; + 5E34CAEA1B7F6EC100F212E8 /* CSceneNodeAnimatorFlyCircle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8C21B7F669200F212E8 /* CSceneNodeAnimatorFlyCircle.cpp */; }; + 5E34CAEC1B7F6EC100F212E8 /* CSceneNodeAnimatorFlyStraight.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8C41B7F669200F212E8 /* CSceneNodeAnimatorFlyStraight.cpp */; }; + 5E34CAEE1B7F6EC100F212E8 /* CSceneNodeAnimatorFollowSpline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8C61B7F669200F212E8 /* CSceneNodeAnimatorFollowSpline.cpp */; }; + 5E34CAF01B7F6EC100F212E8 /* CSceneNodeAnimatorRotation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8C81B7F669200F212E8 /* CSceneNodeAnimatorRotation.cpp */; }; + 5E34CAF21B7F6EC100F212E8 /* CSceneNodeAnimatorTexture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8CA1B7F669200F212E8 /* CSceneNodeAnimatorTexture.cpp */; }; + 5E34CAF41B7F6EC100F212E8 /* CMetaTriangleSelector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8CC1B7F66E600F212E8 /* CMetaTriangleSelector.cpp */; }; + 5E34CAF61B7F6EC100F212E8 /* COctreeTriangleSelector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8CE1B7F66E600F212E8 /* COctreeTriangleSelector.cpp */; }; + 5E34CAF81B7F6EC100F212E8 /* CSceneCollisionManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8D01B7F66E600F212E8 /* CSceneCollisionManager.cpp */; }; + 5E34CAFA1B7F6EC100F212E8 /* CTerrainTriangleSelector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8D21B7F66E600F212E8 /* CTerrainTriangleSelector.cpp */; }; + 5E34CAFC1B7F6EC100F212E8 /* CTriangleBBSelector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8D41B7F66E600F212E8 /* CTriangleBBSelector.cpp */; }; + 5E34CAFE1B7F6EC100F212E8 /* CTriangleSelector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8D61B7F66E600F212E8 /* CTriangleSelector.cpp */; }; + 5E34CB001B7F6EC100F212E8 /* C3DSMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8D81B7F680200F212E8 /* C3DSMeshFileLoader.cpp */; }; + 5E34CB021B7F6EC100F212E8 /* CAnimatedMeshHalfLife.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8DA1B7F680200F212E8 /* CAnimatedMeshHalfLife.cpp */; }; + 5E34CB041B7F6EC100F212E8 /* CAnimatedMeshMD2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8DC1B7F680200F212E8 /* CAnimatedMeshMD2.cpp */; }; + 5E34CB061B7F6EC100F212E8 /* CAnimatedMeshMD3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8DE1B7F680200F212E8 /* CAnimatedMeshMD3.cpp */; }; + 5E34CB081B7F6EC200F212E8 /* CB3DMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8E01B7F680200F212E8 /* CB3DMeshFileLoader.cpp */; }; + 5E34CB0A1B7F6EC200F212E8 /* CBSPMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8E21B7F680200F212E8 /* CBSPMeshFileLoader.cpp */; }; + 5E34CB0C1B7F6EC200F212E8 /* CColladaFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8E41B7F680200F212E8 /* CColladaFileLoader.cpp */; }; + 5E34CB0E1B7F6EC200F212E8 /* CCSMLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8E61B7F680200F212E8 /* CCSMLoader.cpp */; }; + 5E34CB101B7F6EC200F212E8 /* CDMFLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8E81B7F680200F212E8 /* CDMFLoader.cpp */; }; + 5E34CB121B7F6EC200F212E8 /* CIrrMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8EA1B7F680200F212E8 /* CIrrMeshFileLoader.cpp */; }; + 5E34CB141B7F6EC200F212E8 /* CLMTSMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8EC1B7F680200F212E8 /* CLMTSMeshFileLoader.cpp */; }; + 5E34CB161B7F6EC200F212E8 /* CLWOMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8EE1B7F680200F212E8 /* CLWOMeshFileLoader.cpp */; }; + 5E34CB181B7F6EC200F212E8 /* CMD2MeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8F01B7F680200F212E8 /* CMD2MeshFileLoader.cpp */; }; + 5E34CB1A1B7F6EC200F212E8 /* CMD3MeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8F21B7F680200F212E8 /* CMD3MeshFileLoader.cpp */; }; + 5E34CB1C1B7F6EC200F212E8 /* CMeshTextureLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8F41B7F680200F212E8 /* CMeshTextureLoader.cpp */; }; + 5E34CB1E1B7F6EC200F212E8 /* CMS3DMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8F61B7F680200F212E8 /* CMS3DMeshFileLoader.cpp */; }; + 5E34CB211B7F6EC200F212E8 /* CMY3DMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8F91B7F680200F212E8 /* CMY3DMeshFileLoader.cpp */; }; + 5E34CB231B7F6EC200F212E8 /* COBJMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8FB1B7F680200F212E8 /* COBJMeshFileLoader.cpp */; }; + 5E34CB251B7F6EC200F212E8 /* COCTLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8FD1B7F680200F212E8 /* COCTLoader.cpp */; }; + 5E34CB271B7F6EC200F212E8 /* COgreMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8FF1B7F680200F212E8 /* COgreMeshFileLoader.cpp */; }; + 5E34CB291B7F6EC200F212E8 /* CPLYMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9011B7F680200F212E8 /* CPLYMeshFileLoader.cpp */; }; + 5E34CB2B1B7F6EC200F212E8 /* CQ3LevelMesh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9031B7F680200F212E8 /* CQ3LevelMesh.cpp */; }; + 5E34CB2D1B7F6EC200F212E8 /* CSceneLoaderIrr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9051B7F680200F212E8 /* CSceneLoaderIrr.cpp */; }; + 5E34CB2F1B7F6EC200F212E8 /* CSkinnedMesh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9071B7F680200F212E8 /* CSkinnedMesh.cpp */; }; + 5E34CB311B7F6EC200F212E8 /* CSMFMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9091B7F680200F212E8 /* CSMFMeshFileLoader.cpp */; }; + 5E34CB331B7F6EC200F212E8 /* CSTLMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C90B1B7F680200F212E8 /* CSTLMeshFileLoader.cpp */; }; + 5E34CB351B7F6EC200F212E8 /* CXMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C90D1B7F680200F212E8 /* CXMeshFileLoader.cpp */; }; + 5E34CB381B7F6EC200F212E8 /* CParticleAnimatedMeshSceneNodeEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9101B7F684000F212E8 /* CParticleAnimatedMeshSceneNodeEmitter.cpp */; }; + 5E34CB3A1B7F6EC200F212E8 /* CParticleAttractionAffector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9121B7F684000F212E8 /* CParticleAttractionAffector.cpp */; }; + 5E34CB3C1B7F6EC300F212E8 /* CParticleBoxEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9141B7F684000F212E8 /* CParticleBoxEmitter.cpp */; }; + 5E34CB3E1B7F6EC300F212E8 /* CParticleCylinderEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9161B7F684000F212E8 /* CParticleCylinderEmitter.cpp */; }; + 5E34CB401B7F6EC300F212E8 /* CParticleFadeOutAffector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9181B7F684000F212E8 /* CParticleFadeOutAffector.cpp */; }; + 5E34CB421B7F6EC300F212E8 /* CParticleGravityAffector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C91A1B7F684000F212E8 /* CParticleGravityAffector.cpp */; }; + 5E34CB441B7F6EC300F212E8 /* CParticleMeshEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C91C1B7F684000F212E8 /* CParticleMeshEmitter.cpp */; }; + 5E34CB461B7F6EC300F212E8 /* CParticlePointEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C91E1B7F684000F212E8 /* CParticlePointEmitter.cpp */; }; + 5E34CB481B7F6EC300F212E8 /* CParticleRingEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9201B7F684000F212E8 /* CParticleRingEmitter.cpp */; }; + 5E34CB4A1B7F6EC300F212E8 /* CParticleRotationAffector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9221B7F684000F212E8 /* CParticleRotationAffector.cpp */; }; + 5E34CB4C1B7F6EC300F212E8 /* CParticleScaleAffector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9241B7F684000F212E8 /* CParticleScaleAffector.cpp */; }; + 5E34CB4E1B7F6EC300F212E8 /* CParticleSphereEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9261B7F684000F212E8 /* CParticleSphereEmitter.cpp */; }; + 5E34CB501B7F6EC300F212E8 /* CParticleSystemSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9281B7F684000F212E8 /* CParticleSystemSceneNode.cpp */; }; + 5E34CB521B7F6EC300F212E8 /* CAnimatedMeshSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C92A1B7F68D600F212E8 /* CAnimatedMeshSceneNode.cpp */; }; + 5E34CB541B7F6EC300F212E8 /* CBillboardSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C92C1B7F68D600F212E8 /* CBillboardSceneNode.cpp */; }; + 5E34CB561B7F6EC300F212E8 /* CBoneSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C92E1B7F68D600F212E8 /* CBoneSceneNode.cpp */; }; + 5E34CB581B7F6EC300F212E8 /* CCameraSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9301B7F68D600F212E8 /* CCameraSceneNode.cpp */; }; + 5E34CB5A1B7F6EC300F212E8 /* CCubeSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9321B7F68D600F212E8 /* CCubeSceneNode.cpp */; }; + 5E34CB5C1B7F6EC300F212E8 /* CDummyTransformationSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9341B7F68D600F212E8 /* CDummyTransformationSceneNode.cpp */; }; + 5E34CB5E1B7F6EC300F212E8 /* CEmptySceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9361B7F68D600F212E8 /* CEmptySceneNode.cpp */; }; + 5E34CB601B7F6EC300F212E8 /* CLightSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9381B7F68D600F212E8 /* CLightSceneNode.cpp */; }; + 5E34CB621B7F6EC300F212E8 /* CMeshSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C93A1B7F68D600F212E8 /* CMeshSceneNode.cpp */; }; + 5E34CB641B7F6EC300F212E8 /* COctreeSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C93C1B7F68D600F212E8 /* COctreeSceneNode.cpp */; }; + 5E34CB661B7F6EC300F212E8 /* CQuake3ShaderSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C93E1B7F68D600F212E8 /* CQuake3ShaderSceneNode.cpp */; }; + 5E34CB681B7F6EC400F212E8 /* CShadowVolumeSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9401B7F68D600F212E8 /* CShadowVolumeSceneNode.cpp */; }; + 5E34CB6A1B7F6EC400F212E8 /* CSkyBoxSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9421B7F68D600F212E8 /* CSkyBoxSceneNode.cpp */; }; + 5E34CB6C1B7F6EC400F212E8 /* CSkyDomeSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9441B7F68D600F212E8 /* CSkyDomeSceneNode.cpp */; }; + 5E34CB6E1B7F6EC400F212E8 /* CSphereSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9461B7F68D600F212E8 /* CSphereSceneNode.cpp */; }; + 5E34CB701B7F6EC400F212E8 /* CTerrainSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9481B7F68D600F212E8 /* CTerrainSceneNode.cpp */; }; + 5E34CB721B7F6EC400F212E8 /* CTextSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C94A1B7F68D600F212E8 /* CTextSceneNode.cpp */; }; + 5E34CB741B7F6EC400F212E8 /* CVolumeLightSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C94C1B7F68D600F212E8 /* CVolumeLightSceneNode.cpp */; }; + 5E34CB761B7F6EC400F212E8 /* CWaterSurfaceSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C94E1B7F68D600F212E8 /* CWaterSurfaceSceneNode.cpp */; }; + 5E34CB781B7F6EC400F212E8 /* CColladaMeshWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9501B7F691500F212E8 /* CColladaMeshWriter.cpp */; }; + 5E34CB7A1B7F6EC400F212E8 /* CIrrMeshWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9521B7F691500F212E8 /* CIrrMeshWriter.cpp */; }; + 5E34CB7C1B7F6EC400F212E8 /* COBJMeshWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9541B7F691500F212E8 /* COBJMeshWriter.cpp */; }; + 5E34CB7E1B7F6EC400F212E8 /* CPLYMeshWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9561B7F691500F212E8 /* CPLYMeshWriter.cpp */; }; + 5E34CB801B7F6EC400F212E8 /* CSTLMeshWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9581B7F691500F212E8 /* CSTLMeshWriter.cpp */; }; + 5E34CB821B7F6EC400F212E8 /* CDefaultSceneNodeAnimatorFactory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8AD1B7F664100F212E8 /* CDefaultSceneNodeAnimatorFactory.cpp */; }; + 5E34CB841B7F6EC400F212E8 /* CDefaultSceneNodeFactory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8AF1B7F664100F212E8 /* CDefaultSceneNodeFactory.cpp */; }; + 5E34CB861B7F6EC400F212E8 /* CGeometryCreator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8B11B7F664100F212E8 /* CGeometryCreator.cpp */; }; + 5E34CB881B7F6EC400F212E8 /* CMeshCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8B31B7F664100F212E8 /* CMeshCache.cpp */; }; + 5E34CB8A1B7F6EC400F212E8 /* CMeshManipulator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8B51B7F664100F212E8 /* CMeshManipulator.cpp */; }; + 5E34CB8C1B7F6EC400F212E8 /* CSceneManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8B71B7F664100F212E8 /* CSceneManager.cpp */; }; + 5E34CB8F1B7F6EC400F212E8 /* CBurningShader_Raster_Reference.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9601B7F6A7600F212E8 /* CBurningShader_Raster_Reference.cpp */; }; + 5E34CB901B7F6EC500F212E8 /* CDepthBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9611B7F6A7600F212E8 /* CDepthBuffer.cpp */; }; + 5E34CB931B7F6EC500F212E8 /* CSoftwareDriver2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9641B7F6A7600F212E8 /* CSoftwareDriver2.cpp */; }; + 5E34CB951B7F6EC500F212E8 /* CSoftwareTexture2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9661B7F6A7600F212E8 /* CSoftwareTexture2.cpp */; }; + 5E34CB971B7F6EC500F212E8 /* CTRGouraud2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9681B7F6A7600F212E8 /* CTRGouraud2.cpp */; }; + 5E34CB981B7F6EC500F212E8 /* CTRGouraudAlpha2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9691B7F6A7600F212E8 /* CTRGouraudAlpha2.cpp */; }; + 5E34CB991B7F6EC500F212E8 /* CTRGouraudAlphaNoZ2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C96A1B7F6A7600F212E8 /* CTRGouraudAlphaNoZ2.cpp */; }; + 5E34CB9A1B7F6EC500F212E8 /* CTRNormalMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C96B1B7F6A7600F212E8 /* CTRNormalMap.cpp */; }; + 5E34CB9B1B7F6EC500F212E8 /* CTRStencilShadow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C96C1B7F6A7600F212E8 /* CTRStencilShadow.cpp */; }; + 5E34CB9C1B7F6EC500F212E8 /* CTRTextureBlend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C96D1B7F6A7600F212E8 /* CTRTextureBlend.cpp */; }; + 5E34CB9D1B7F6EC500F212E8 /* CTRTextureDetailMap2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C96E1B7F6A7600F212E8 /* CTRTextureDetailMap2.cpp */; }; + 5E34CB9E1B7F6EC500F212E8 /* CTRTextureGouraud2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C96F1B7F6A7600F212E8 /* CTRTextureGouraud2.cpp */; }; + 5E34CB9F1B7F6EC500F212E8 /* CTRTextureGouraudAdd2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9701B7F6A7600F212E8 /* CTRTextureGouraudAdd2.cpp */; }; + 5E34CBA01B7F6EC500F212E8 /* CTRTextureGouraudAddNoZ2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9711B7F6A7600F212E8 /* CTRTextureGouraudAddNoZ2.cpp */; }; + 5E34CBA11B7F6EC500F212E8 /* CTRTextureGouraudAlpha.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9721B7F6A7600F212E8 /* CTRTextureGouraudAlpha.cpp */; }; + 5E34CBA21B7F6EC500F212E8 /* CTRTextureGouraudAlphaNoZ.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9731B7F6A7600F212E8 /* CTRTextureGouraudAlphaNoZ.cpp */; }; + 5E34CBA31B7F6EC500F212E8 /* CTRTextureGouraudNoZ2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9741B7F6A7600F212E8 /* CTRTextureGouraudNoZ2.cpp */; }; + 5E34CBA41B7F6EC500F212E8 /* CTRTextureGouraudVertexAlpha2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9751B7F6A7600F212E8 /* CTRTextureGouraudVertexAlpha2.cpp */; }; + 5E34CBA51B7F6EC500F212E8 /* CTRTextureLightMap2_Add.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9761B7F6A7600F212E8 /* CTRTextureLightMap2_Add.cpp */; }; + 5E34CBA61B7F6EC500F212E8 /* CTRTextureLightMap2_M1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9771B7F6A7600F212E8 /* CTRTextureLightMap2_M1.cpp */; }; + 5E34CBA71B7F6EC500F212E8 /* CTRTextureLightMap2_M2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9781B7F6A7600F212E8 /* CTRTextureLightMap2_M2.cpp */; }; + 5E34CBA81B7F6EC500F212E8 /* CTRTextureLightMap2_M4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9791B7F6A7600F212E8 /* CTRTextureLightMap2_M4.cpp */; }; + 5E34CBA91B7F6EC500F212E8 /* CTRTextureLightMapGouraud2_M4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C97A1B7F6A7600F212E8 /* CTRTextureLightMapGouraud2_M4.cpp */; }; + 5E34CBAA1B7F6EC500F212E8 /* CTRTextureWire2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C97B1B7F6A7600F212E8 /* CTRTextureWire2.cpp */; }; + 5E34CBAB1B7F6EC500F212E8 /* IBurningShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C97C1B7F6A7600F212E8 /* IBurningShader.cpp */; }; + 5E34CBB11B7F6EC500F212E8 /* CImageLoaderBMP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9841B7F6AED00F212E8 /* CImageLoaderBMP.cpp */; }; + 5E34CBB31B7F6EC500F212E8 /* CImageLoaderDDS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9861B7F6AED00F212E8 /* CImageLoaderDDS.cpp */; }; + 5E34CBB51B7F6EC600F212E8 /* CImageLoaderJPG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9881B7F6AED00F212E8 /* CImageLoaderJPG.cpp */; }; + 5E34CBB71B7F6EC600F212E8 /* CImageLoaderPCX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C98A1B7F6AED00F212E8 /* CImageLoaderPCX.cpp */; }; + 5E34CBB91B7F6EC600F212E8 /* CImageLoaderPNG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C98C1B7F6AED00F212E8 /* CImageLoaderPNG.cpp */; }; + 5E34CBBB1B7F6EC600F212E8 /* CImageLoaderPPM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C98E1B7F6AED00F212E8 /* CImageLoaderPPM.cpp */; }; + 5E34CBBD1B7F6EC600F212E8 /* CImageLoaderPSD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9901B7F6AED00F212E8 /* CImageLoaderPSD.cpp */; }; + 5E34CBBF1B7F6EC600F212E8 /* CImageLoaderPVR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9921B7F6AED00F212E8 /* CImageLoaderPVR.cpp */; }; + 5E34CBC11B7F6EC600F212E8 /* CImageLoaderRGB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9941B7F6AED00F212E8 /* CImageLoaderRGB.cpp */; }; + 5E34CBC31B7F6EC600F212E8 /* CImageLoaderTGA.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9961B7F6AED00F212E8 /* CImageLoaderTGA.cpp */; }; + 5E34CBC51B7F6EC600F212E8 /* CImageLoaderWAL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9981B7F6AED00F212E8 /* CImageLoaderWAL.cpp */; }; + 5E34CBC71B7F6EC600F212E8 /* CImageWriterBMP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C99A1B7F6B0900F212E8 /* CImageWriterBMP.cpp */; }; + 5E34CBC91B7F6EC600F212E8 /* CImageWriterJPG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C99C1B7F6B0900F212E8 /* CImageWriterJPG.cpp */; }; + 5E34CBCB1B7F6EC600F212E8 /* CImageWriterPCX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C99E1B7F6B0900F212E8 /* CImageWriterPCX.cpp */; }; + 5E34CBCD1B7F6EC600F212E8 /* CImageWriterPNG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9A01B7F6B0900F212E8 /* CImageWriterPNG.cpp */; }; + 5E34CBCF1B7F6EC600F212E8 /* CImageWriterPPM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9A21B7F6B0900F212E8 /* CImageWriterPPM.cpp */; }; + 5E34CBD11B7F6EC600F212E8 /* CImageWriterPSD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9A41B7F6B0900F212E8 /* CImageWriterPSD.cpp */; }; + 5E34CBD31B7F6EC600F212E8 /* CImageWriterTGA.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9A61B7F6B0900F212E8 /* CImageWriterTGA.cpp */; }; + 5E34CBD51B7F6EC600F212E8 /* CColorConverter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9A81B7F6B6800F212E8 /* CColorConverter.cpp */; }; + 5E34CBD71B7F6EC700F212E8 /* CFPSCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9AA1B7F6B6800F212E8 /* CFPSCounter.cpp */; }; + 5E34CBD91B7F6EC700F212E8 /* CImage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9AC1B7F6B6800F212E8 /* CImage.cpp */; }; + 5E34CBDB1B7F6EC700F212E8 /* CNullDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9AE1B7F6B6800F212E8 /* CNullDriver.cpp */; }; + 5E34CBDE1B7F6EC700F212E8 /* COpenGLDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9B11B7F6BA700F212E8 /* COpenGLDriver.cpp */; }; + 5E34CBE01B7F6EC700F212E8 /* COpenGLExtensionHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9B31B7F6BA700F212E8 /* COpenGLExtensionHandler.cpp */; }; + 5E34CBE31B7F6EC700F212E8 /* COpenGLNormalMapRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9B61B7F6BA700F212E8 /* COpenGLNormalMapRenderer.cpp */; }; + 5E34CBE51B7F6EC700F212E8 /* COpenGLParallaxMapRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9B81B7F6BA700F212E8 /* COpenGLParallaxMapRenderer.cpp */; }; + 5E34CBE71B7F6EC700F212E8 /* COpenGLShaderMaterialRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9BA1B7F6BA700F212E8 /* COpenGLShaderMaterialRenderer.cpp */; }; + 5E34CBE91B7F6EC700F212E8 /* COpenGLSLMaterialRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9BC1B7F6BA700F212E8 /* COpenGLSLMaterialRenderer.cpp */; }; + 5E34CC041B7F6EC800F212E8 /* CSoftwareDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9D71B7F6C6100F212E8 /* CSoftwareDriver.cpp */; }; + 5E34CC061B7F6EC800F212E8 /* CSoftwareTexture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9D91B7F6C6100F212E8 /* CSoftwareTexture.cpp */; }; + 5E34CC081B7F6EC800F212E8 /* CTRFlat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9DB1B7F6C6100F212E8 /* CTRFlat.cpp */; }; + 5E34CC091B7F6EC800F212E8 /* CTRFlatWire.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9DC1B7F6C6100F212E8 /* CTRFlatWire.cpp */; }; + 5E34CC0A1B7F6EC800F212E8 /* CTRGouraud.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9DD1B7F6C6100F212E8 /* CTRGouraud.cpp */; }; + 5E34CC0B1B7F6EC800F212E8 /* CTRGouraudWire.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9DE1B7F6C6100F212E8 /* CTRGouraudWire.cpp */; }; + 5E34CC0C1B7F6EC800F212E8 /* CTRTextureFlat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9DF1B7F6C6100F212E8 /* CTRTextureFlat.cpp */; }; + 5E34CC0D1B7F6EC800F212E8 /* CTRTextureFlatWire.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9E01B7F6C6100F212E8 /* CTRTextureFlatWire.cpp */; }; + 5E34CC0E1B7F6EC800F212E8 /* CTRTextureGouraud.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9E11B7F6C6100F212E8 /* CTRTextureGouraud.cpp */; }; + 5E34CC101B7F6EC800F212E8 /* CTRTextureGouraudAdd.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9E31B7F6C6100F212E8 /* CTRTextureGouraudAdd.cpp */; }; + 5E34CC111B7F6EC800F212E8 /* CTRTextureGouraudNoZ.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9E41B7F6C6100F212E8 /* CTRTextureGouraudNoZ.cpp */; }; + 5E34CC121B7F6EC900F212E8 /* CTRTextureGouraudWire.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9E51B7F6C6100F212E8 /* CTRTextureGouraudWire.cpp */; }; + 5E34CC131B7F6EC900F212E8 /* CZBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9E61B7F6C6100F212E8 /* CZBuffer.cpp */; }; + 5E34CC191B7F6EC900F212E8 /* CNSOGLManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9EE1B7F6CCC00F212E8 /* CNSOGLManager.mm */; }; + 5E34CC1A1B7F6EC900F212E8 /* CVideoModeList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9EB1B7F6C8200F212E8 /* CVideoModeList.cpp */; }; + 5E5732B31C18E212003F664E /* CDefaultGUIElementFactory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7E21B7F50DE00F212E8 /* CDefaultGUIElementFactory.cpp */; }; + 5E5732B41C18E212003F664E /* CGUIButton.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7A91B7F50A900F212E8 /* CGUIButton.cpp */; }; + 5E5732B51C18E212003F664E /* CGUICheckBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7AB1B7F50A900F212E8 /* CGUICheckBox.cpp */; }; + 5E5732B61C18E212003F664E /* CGUIColorSelectDialog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7AD1B7F50A900F212E8 /* CGUIColorSelectDialog.cpp */; }; + 5E5732B71C18E212003F664E /* CGUIComboBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7AF1B7F50A900F212E8 /* CGUIComboBox.cpp */; }; + 5E5732B81C18E212003F664E /* CGUIContextMenu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7B11B7F50A900F212E8 /* CGUIContextMenu.cpp */; }; + 5E5732B91C18E212003F664E /* CGUIEditBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7B31B7F50A900F212E8 /* CGUIEditBox.cpp */; }; + 5E5732BA1C18E212003F664E /* CGUIEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7B51B7F50A900F212E8 /* CGUIEnvironment.cpp */; }; + 5E5732BB1C18E212003F664E /* CGUIFileOpenDialog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7B71B7F50A900F212E8 /* CGUIFileOpenDialog.cpp */; }; + 5E5732BC1C18E212003F664E /* CGUIFont.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7B91B7F50A900F212E8 /* CGUIFont.cpp */; }; + 5E5732BD1C18E212003F664E /* CGUIImage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7BB1B7F50A900F212E8 /* CGUIImage.cpp */; }; + 5E5732BE1C18E212003F664E /* CGUIImageList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7BD1B7F50A900F212E8 /* CGUIImageList.cpp */; }; + 5E5732BF1C18E212003F664E /* CGUIInOutFader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7BF1B7F50A900F212E8 /* CGUIInOutFader.cpp */; }; + 5E5732C01C18E212003F664E /* CGUIListBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7C11B7F50A900F212E8 /* CGUIListBox.cpp */; }; + 5E5732C11C18E212003F664E /* CGUIMenu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7C31B7F50A900F212E8 /* CGUIMenu.cpp */; }; + 5E5732C21C18E212003F664E /* CGUIMeshViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7C51B7F50A900F212E8 /* CGUIMeshViewer.cpp */; }; + 5E5732C31C18E212003F664E /* CGUIMessageBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7C71B7F50A900F212E8 /* CGUIMessageBox.cpp */; }; + 5E5732C41C18E212003F664E /* CGUIModalScreen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7C91B7F50A900F212E8 /* CGUIModalScreen.cpp */; }; + 5E5732C51C18E212003F664E /* CGUIProfiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7CB1B7F50A900F212E8 /* CGUIProfiler.cpp */; }; + 5E5732C61C18E212003F664E /* CGUIScrollBar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7CD1B7F50A900F212E8 /* CGUIScrollBar.cpp */; }; + 5E5732C71C18E212003F664E /* CGUISkin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7CF1B7F50A900F212E8 /* CGUISkin.cpp */; }; + 5E5732C81C18E212003F664E /* CGUISpinBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7D11B7F50A900F212E8 /* CGUISpinBox.cpp */; }; + 5E5732C91C18E212003F664E /* CGUISpriteBank.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7D31B7F50A900F212E8 /* CGUISpriteBank.cpp */; }; + 5E5732CA1C18E212003F664E /* CGUIStaticText.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7D51B7F50A900F212E8 /* CGUIStaticText.cpp */; }; + 5E5732CB1C18E212003F664E /* CGUITabControl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7D71B7F50A900F212E8 /* CGUITabControl.cpp */; }; + 5E5732CC1C18E212003F664E /* CGUITable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7D91B7F50A900F212E8 /* CGUITable.cpp */; }; + 5E5732CD1C18E212003F664E /* CGUIToolBar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7DB1B7F50A900F212E8 /* CGUIToolBar.cpp */; }; + 5E5732CE1C18E212003F664E /* CGUITreeView.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7DD1B7F50A900F212E8 /* CGUITreeView.cpp */; }; + 5E5732CF1C18E212003F664E /* CGUIWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7DF1B7F50A900F212E8 /* CGUIWindow.cpp */; }; + 5E5732D01C18E212003F664E /* CAttributes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7E51B7F517000F212E8 /* CAttributes.cpp */; }; + 5E5732D11C18E212003F664E /* CFileList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7E71B7F517000F212E8 /* CFileList.cpp */; }; + 5E5732D21C18E212003F664E /* CFileSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7E91B7F517000F212E8 /* CFileSystem.cpp */; }; + 5E5732D31C18E212003F664E /* CLimitReadFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7EB1B7F517000F212E8 /* CLimitReadFile.cpp */; }; + 5E5732D41C18E212003F664E /* CMemoryFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7ED1B7F517000F212E8 /* CMemoryFile.cpp */; }; + 5E5732D51C18E212003F664E /* CMountPointReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7EF1B7F517000F212E8 /* CMountPointReader.cpp */; }; + 5E5732D61C18E212003F664E /* CNPKReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7F11B7F517000F212E8 /* CNPKReader.cpp */; }; + 5E5732D71C18E212003F664E /* CPakReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7F31B7F517000F212E8 /* CPakReader.cpp */; }; + 5E5732D81C18E212003F664E /* CReadFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7F51B7F51D900F212E8 /* CReadFile.cpp */; }; + 5E5732D91C18E212003F664E /* CTarReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7F71B7F51D900F212E8 /* CTarReader.cpp */; }; + 5E5732DA1C18E212003F664E /* CWADReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7F91B7F51D900F212E8 /* CWADReader.cpp */; }; + 5E5732DB1C18E212003F664E /* CWriteFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7FB1B7F51D900F212E8 /* CWriteFile.cpp */; }; + 5E5732DC1C18E212003F664E /* CXMLReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C7FD1B7F51D900F212E8 /* CXMLReader.cpp */; }; + 5E5732DD1C18E212003F664E /* CXMLWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8001B7F51D900F212E8 /* CXMLWriter.cpp */; }; + 5E5732DE1C18E212003F664E /* CZipReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8021B7F51D900F212E8 /* CZipReader.cpp */; }; + 5E5732DF1C18E212003F664E /* irrXML.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8051B7F51D900F212E8 /* irrXML.cpp */; }; + 5E5732E11C18E212003F664E /* CIrrDeviceStub.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C80D1B7F52AC00F212E8 /* CIrrDeviceStub.cpp */; }; + 5E5732E21C18E212003F664E /* aescrypt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8161B7F540B00F212E8 /* aescrypt.cpp */; }; + 5E5732E31C18E212003F664E /* aeskey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8171B7F540B00F212E8 /* aeskey.cpp */; }; + 5E5732E41C18E212003F664E /* aestab.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8191B7F540B00F212E8 /* aestab.cpp */; }; + 5E5732E51C18E212003F664E /* fileenc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C81A1B7F540B00F212E8 /* fileenc.cpp */; }; + 5E5732E61C18E212003F664E /* hmac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C81C1B7F540B00F212E8 /* hmac.cpp */; }; + 5E5732E71C18E212003F664E /* prng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C81E1B7F540B00F212E8 /* prng.cpp */; }; + 5E5732E81C18E212003F664E /* pwd2key.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8201B7F540B00F212E8 /* pwd2key.cpp */; }; + 5E5732E91C18E212003F664E /* sha1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8221B7F540B00F212E8 /* sha1.cpp */; }; + 5E5732EA1C18E212003F664E /* sha2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8241B7F540B00F212E8 /* sha2.cpp */; }; + 5E5732EB1C18E212003F664E /* blocksort.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8261B7F54FE00F212E8 /* blocksort.c */; }; + 5E5732EC1C18E212003F664E /* bzcompress.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8271B7F54FE00F212E8 /* bzcompress.c */; }; + 5E5732ED1C18E212003F664E /* bzlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8291B7F54FE00F212E8 /* bzlib.c */; }; + 5E5732EE1C18E212003F664E /* crctable.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C82B1B7F54FE00F212E8 /* crctable.c */; }; + 5E5732EF1C18E212003F664E /* decompress.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C82C1B7F54FE00F212E8 /* decompress.c */; }; + 5E5732F01C18E212003F664E /* huffman.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C82D1B7F54FE00F212E8 /* huffman.c */; }; + 5E5732F11C18E212003F664E /* randtable.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C82E1B7F54FE00F212E8 /* randtable.c */; }; + 5E5732F21C18E212003F664E /* jaricom.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8321B7F561400F212E8 /* jaricom.c */; }; + 5E5732F31C18E212003F664E /* jcapimin.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8331B7F561400F212E8 /* jcapimin.c */; }; + 5E5732F41C18E212003F664E /* jcapistd.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8341B7F561400F212E8 /* jcapistd.c */; }; + 5E5732F51C18E212003F664E /* jcarith.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8351B7F561400F212E8 /* jcarith.c */; }; + 5E5732F61C18E212003F664E /* jccoefct.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8361B7F561400F212E8 /* jccoefct.c */; }; + 5E5732F71C18E212003F664E /* jccolor.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8371B7F561400F212E8 /* jccolor.c */; }; + 5E5732F81C18E212003F664E /* jcdctmgr.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8381B7F561400F212E8 /* jcdctmgr.c */; }; + 5E5732F91C18E212003F664E /* jchuff.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8391B7F561400F212E8 /* jchuff.c */; }; + 5E5732FA1C18E212003F664E /* jcinit.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C83A1B7F561400F212E8 /* jcinit.c */; }; + 5E5732FB1C18E212003F664E /* jcmainct.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C83B1B7F561400F212E8 /* jcmainct.c */; }; + 5E5732FC1C18E212003F664E /* jcmarker.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C83C1B7F561400F212E8 /* jcmarker.c */; }; + 5E5732FD1C18E212003F664E /* jcmaster.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C83D1B7F561400F212E8 /* jcmaster.c */; }; + 5E5732FE1C18E212003F664E /* jcomapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C83E1B7F561400F212E8 /* jcomapi.c */; }; + 5E5732FF1C18E212003F664E /* jcparam.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8401B7F561400F212E8 /* jcparam.c */; }; + 5E5733001C18E212003F664E /* jcprepct.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8411B7F561400F212E8 /* jcprepct.c */; }; + 5E5733011C18E212003F664E /* jcsample.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8421B7F561400F212E8 /* jcsample.c */; }; + 5E5733021C18E212003F664E /* jctrans.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8431B7F561400F212E8 /* jctrans.c */; }; + 5E5733031C18E212003F664E /* jdapimin.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8441B7F561400F212E8 /* jdapimin.c */; }; + 5E5733041C18E212003F664E /* jdapistd.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8451B7F561400F212E8 /* jdapistd.c */; }; + 5E5733051C18E212003F664E /* jdarith.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8461B7F561400F212E8 /* jdarith.c */; }; + 5E5733061C18E212003F664E /* jdatadst.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8471B7F561400F212E8 /* jdatadst.c */; }; + 5E5733071C18E212003F664E /* jdatasrc.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8481B7F561400F212E8 /* jdatasrc.c */; }; + 5E5733081C18E212003F664E /* jdcoefct.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8491B7F561400F212E8 /* jdcoefct.c */; }; + 5E5733091C18E212003F664E /* jdcolor.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C84A1B7F561400F212E8 /* jdcolor.c */; }; + 5E57330A1C18E212003F664E /* jddctmgr.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C84C1B7F561400F212E8 /* jddctmgr.c */; }; + 5E57330B1C18E212003F664E /* jdhuff.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C84D1B7F561400F212E8 /* jdhuff.c */; }; + 5E57330C1C18E212003F664E /* jdinput.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C84E1B7F561400F212E8 /* jdinput.c */; }; + 5E57330D1C18E212003F664E /* jdmainct.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C84F1B7F561400F212E8 /* jdmainct.c */; }; + 5E57330E1C18E212003F664E /* jdmarker.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8501B7F561400F212E8 /* jdmarker.c */; }; + 5E57330F1C18E212003F664E /* jdmaster.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8511B7F561400F212E8 /* jdmaster.c */; }; + 5E5733101C18E212003F664E /* jdmerge.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8521B7F561400F212E8 /* jdmerge.c */; }; + 5E5733111C18E212003F664E /* jdpostct.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8531B7F561400F212E8 /* jdpostct.c */; }; + 5E5733121C18E212003F664E /* jdsample.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8541B7F561400F212E8 /* jdsample.c */; }; + 5E5733131C18E212003F664E /* CIrrDeviceConsole.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E8570BA1B7F9AC400B267D2 /* CIrrDeviceConsole.cpp */; }; + 5E5733141C18E212003F664E /* jdtrans.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8551B7F561400F212E8 /* jdtrans.c */; }; + 5E5733151C18E212003F664E /* jerror.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8561B7F561400F212E8 /* jerror.c */; }; + 5E5733161C18E212003F664E /* jfdctflt.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8581B7F568200F212E8 /* jfdctflt.c */; }; + 5E5733171C18E212003F664E /* jfdctfst.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8591B7F568200F212E8 /* jfdctfst.c */; }; + 5E5733181C18E212003F664E /* jfdctint.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C85A1B7F568200F212E8 /* jfdctint.c */; }; + 5E5733191C18E212003F664E /* jidctflt.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C85B1B7F568200F212E8 /* jidctflt.c */; }; + 5E57331A1C18E212003F664E /* jidctfst.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C85C1B7F568200F212E8 /* jidctfst.c */; }; + 5E57331B1C18E212003F664E /* jidctint.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C85D1B7F568200F212E8 /* jidctint.c */; }; + 5E57331C1C18E212003F664E /* jmemmgr.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C85F1B7F568200F212E8 /* jmemmgr.c */; }; + 5E57331D1C18E212003F664E /* jmemnobs.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8601B7F568200F212E8 /* jmemnobs.c */; }; + 5E57331E1C18E212003F664E /* jquant1.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8651B7F568200F212E8 /* jquant1.c */; }; + 5E57331F1C18E212003F664E /* jquant2.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8661B7F568200F212E8 /* jquant2.c */; }; + 5E5733201C18E212003F664E /* jutils.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8671B7F568200F212E8 /* jutils.c */; }; + 5E5733211C18E212003F664E /* png.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8691B7F56E900F212E8 /* png.c */; }; + 5E5733221C18E212003F664E /* pngerror.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C86C1B7F56E900F212E8 /* pngerror.c */; }; + 5E5733231C18E212003F664E /* pngget.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C86D1B7F56E900F212E8 /* pngget.c */; }; + 5E5733241C18E212003F664E /* pngmem.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C86E1B7F56E900F212E8 /* pngmem.c */; }; + 5E5733251C18E212003F664E /* pngpread.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C86F1B7F56E900F212E8 /* pngpread.c */; }; + 5E5733261C18E212003F664E /* pngread.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8701B7F56E900F212E8 /* pngread.c */; }; + 5E5733271C18E212003F664E /* pngrio.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8711B7F56E900F212E8 /* pngrio.c */; }; + 5E5733281C18E212003F664E /* pngrtran.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8721B7F56E900F212E8 /* pngrtran.c */; }; + 5E5733291C18E212003F664E /* pngrutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8731B7F56E900F212E8 /* pngrutil.c */; }; + 5E57332A1C18E212003F664E /* pngset.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8741B7F56E900F212E8 /* pngset.c */; }; + 5E57332B1C18E212003F664E /* pngtrans.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8751B7F56E900F212E8 /* pngtrans.c */; }; + 5E57332C1C18E212003F664E /* pngwio.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8761B7F56E900F212E8 /* pngwio.c */; }; + 5E57332D1C18E212003F664E /* pngwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8771B7F56E900F212E8 /* pngwrite.c */; }; + 5E57332E1C18E212003F664E /* pngwtran.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8781B7F56E900F212E8 /* pngwtran.c */; }; + 5E57332F1C18E212003F664E /* pngwutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8791B7F56E900F212E8 /* pngwutil.c */; }; + 5E5733301C18E212003F664E /* LzmaDec.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C88F1B7F57B100F212E8 /* LzmaDec.c */; }; + 5E5733311C18E212003F664E /* adler32.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C87A1B7F577000F212E8 /* adler32.c */; }; + 5E5733321C18E212003F664E /* compress.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C87B1B7F577000F212E8 /* compress.c */; }; + 5E5733331C18E212003F664E /* crc32.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C87C1B7F577000F212E8 /* crc32.c */; }; + 5E5733341C18E212003F664E /* deflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C87E1B7F577000F212E8 /* deflate.c */; }; + 5E5733351C18E212003F664E /* inffast.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8801B7F577000F212E8 /* inffast.c */; }; + 5E5733361C18E212003F664E /* inflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8831B7F577000F212E8 /* inflate.c */; }; + 5E5733371C18E212003F664E /* inftrees.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8851B7F577000F212E8 /* inftrees.c */; }; + 5E5733381C18E212003F664E /* trees.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8871B7F577000F212E8 /* trees.c */; }; + 5E5733391C18E212003F664E /* uncompr.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8891B7F577000F212E8 /* uncompr.c */; }; + 5E57333A1C18E212003F664E /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C88C1B7F577000F212E8 /* zutil.c */; }; + 5E57333B1C18E212003F664E /* CLogger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8921B7F652600F212E8 /* CLogger.cpp */; }; + 5E57333C1C18E212003F664E /* COSOperator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8941B7F652600F212E8 /* COSOperator.cpp */; }; + 5E57333D1C18E212003F664E /* CProfiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8961B7F652600F212E8 /* CProfiler.cpp */; }; + 5E57333E1C18E212003F664E /* Irrlicht.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C89A1B7F652600F212E8 /* Irrlicht.cpp */; }; + 5E57333F1C18E212003F664E /* leakHunter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C89B1B7F652600F212E8 /* leakHunter.cpp */; }; + 5E5733401C18E212003F664E /* os.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C89C1B7F652600F212E8 /* os.cpp */; }; + 5E5733411C18E212003F664E /* utf8.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C89E1B7F652600F212E8 /* utf8.cpp */; }; + 5E5733421C18E212003F664E /* CSceneNodeAnimatorCameraFPS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8BA1B7F669200F212E8 /* CSceneNodeAnimatorCameraFPS.cpp */; }; + 5E5733431C18E212003F664E /* CSceneNodeAnimatorCameraMaya.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8BC1B7F669200F212E8 /* CSceneNodeAnimatorCameraMaya.cpp */; }; + 5E5733441C18E212003F664E /* CSceneNodeAnimatorCollisionResponse.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8BE1B7F669200F212E8 /* CSceneNodeAnimatorCollisionResponse.cpp */; }; + 5E5733451C18E212003F664E /* CSceneNodeAnimatorDelete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8C01B7F669200F212E8 /* CSceneNodeAnimatorDelete.cpp */; }; + 5E5733461C18E212003F664E /* CSceneNodeAnimatorFlyCircle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8C21B7F669200F212E8 /* CSceneNodeAnimatorFlyCircle.cpp */; }; + 5E5733471C18E212003F664E /* CSceneNodeAnimatorFlyStraight.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8C41B7F669200F212E8 /* CSceneNodeAnimatorFlyStraight.cpp */; }; + 5E5733481C18E212003F664E /* CSceneNodeAnimatorFollowSpline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8C61B7F669200F212E8 /* CSceneNodeAnimatorFollowSpline.cpp */; }; + 5E5733491C18E212003F664E /* CSceneNodeAnimatorRotation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8C81B7F669200F212E8 /* CSceneNodeAnimatorRotation.cpp */; }; + 5E57334A1C18E212003F664E /* CSceneNodeAnimatorTexture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8CA1B7F669200F212E8 /* CSceneNodeAnimatorTexture.cpp */; }; + 5E57334B1C18E212003F664E /* CMetaTriangleSelector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8CC1B7F66E600F212E8 /* CMetaTriangleSelector.cpp */; }; + 5E57334C1C18E212003F664E /* COctreeTriangleSelector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8CE1B7F66E600F212E8 /* COctreeTriangleSelector.cpp */; }; + 5E57334D1C18E212003F664E /* CSceneCollisionManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8D01B7F66E600F212E8 /* CSceneCollisionManager.cpp */; }; + 5E57334E1C18E212003F664E /* CTerrainTriangleSelector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8D21B7F66E600F212E8 /* CTerrainTriangleSelector.cpp */; }; + 5E57334F1C18E212003F664E /* CTriangleBBSelector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8D41B7F66E600F212E8 /* CTriangleBBSelector.cpp */; }; + 5E5733501C18E212003F664E /* CTriangleSelector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8D61B7F66E600F212E8 /* CTriangleSelector.cpp */; }; + 5E5733511C18E212003F664E /* C3DSMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8D81B7F680200F212E8 /* C3DSMeshFileLoader.cpp */; }; + 5E5733521C18E212003F664E /* CAnimatedMeshHalfLife.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8DA1B7F680200F212E8 /* CAnimatedMeshHalfLife.cpp */; }; + 5E5733531C18E212003F664E /* CAnimatedMeshMD2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8DC1B7F680200F212E8 /* CAnimatedMeshMD2.cpp */; }; + 5E5733541C18E212003F664E /* CAnimatedMeshMD3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8DE1B7F680200F212E8 /* CAnimatedMeshMD3.cpp */; }; + 5E5733551C18E212003F664E /* CB3DMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8E01B7F680200F212E8 /* CB3DMeshFileLoader.cpp */; }; + 5E5733561C18E212003F664E /* CBSPMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8E21B7F680200F212E8 /* CBSPMeshFileLoader.cpp */; }; + 5E5733571C18E212003F664E /* CColladaFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8E41B7F680200F212E8 /* CColladaFileLoader.cpp */; }; + 5E5733581C18E212003F664E /* CCSMLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8E61B7F680200F212E8 /* CCSMLoader.cpp */; }; + 5E5733591C18E212003F664E /* CDMFLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8E81B7F680200F212E8 /* CDMFLoader.cpp */; }; + 5E57335A1C18E212003F664E /* CIrrMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8EA1B7F680200F212E8 /* CIrrMeshFileLoader.cpp */; }; + 5E57335B1C18E212003F664E /* CLMTSMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8EC1B7F680200F212E8 /* CLMTSMeshFileLoader.cpp */; }; + 5E57335C1C18E212003F664E /* CLWOMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8EE1B7F680200F212E8 /* CLWOMeshFileLoader.cpp */; }; + 5E57335D1C18E212003F664E /* CMD2MeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8F01B7F680200F212E8 /* CMD2MeshFileLoader.cpp */; }; + 5E57335E1C18E212003F664E /* CMD3MeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8F21B7F680200F212E8 /* CMD3MeshFileLoader.cpp */; }; + 5E57335F1C18E212003F664E /* CMeshTextureLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8F41B7F680200F212E8 /* CMeshTextureLoader.cpp */; }; + 5E5733601C18E212003F664E /* CMS3DMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8F61B7F680200F212E8 /* CMS3DMeshFileLoader.cpp */; }; + 5E5733611C18E212003F664E /* CMY3DMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8F91B7F680200F212E8 /* CMY3DMeshFileLoader.cpp */; }; + 5E5733621C18E212003F664E /* COBJMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8FB1B7F680200F212E8 /* COBJMeshFileLoader.cpp */; }; + 5E5733631C18E212003F664E /* COCTLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8FD1B7F680200F212E8 /* COCTLoader.cpp */; }; + 5E5733641C18E212003F664E /* COgreMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8FF1B7F680200F212E8 /* COgreMeshFileLoader.cpp */; }; + 5E5733651C18E212003F664E /* CPLYMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9011B7F680200F212E8 /* CPLYMeshFileLoader.cpp */; }; + 5E5733661C18E212003F664E /* CQ3LevelMesh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9031B7F680200F212E8 /* CQ3LevelMesh.cpp */; }; + 5E5733671C18E212003F664E /* CSceneLoaderIrr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9051B7F680200F212E8 /* CSceneLoaderIrr.cpp */; }; + 5E5733681C18E212003F664E /* CSkinnedMesh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9071B7F680200F212E8 /* CSkinnedMesh.cpp */; }; + 5E5733691C18E212003F664E /* CSMFMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9091B7F680200F212E8 /* CSMFMeshFileLoader.cpp */; }; + 5E57336A1C18E212003F664E /* CSTLMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C90B1B7F680200F212E8 /* CSTLMeshFileLoader.cpp */; }; + 5E57336B1C18E212003F664E /* CXMeshFileLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C90D1B7F680200F212E8 /* CXMeshFileLoader.cpp */; }; + 5E57336C1C18E212003F664E /* CParticleAnimatedMeshSceneNodeEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9101B7F684000F212E8 /* CParticleAnimatedMeshSceneNodeEmitter.cpp */; }; + 5E57336D1C18E212003F664E /* CParticleAttractionAffector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9121B7F684000F212E8 /* CParticleAttractionAffector.cpp */; }; + 5E57336E1C18E212003F664E /* CParticleBoxEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9141B7F684000F212E8 /* CParticleBoxEmitter.cpp */; }; + 5E57336F1C18E212003F664E /* CParticleCylinderEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9161B7F684000F212E8 /* CParticleCylinderEmitter.cpp */; }; + 5E5733701C18E212003F664E /* CParticleFadeOutAffector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9181B7F684000F212E8 /* CParticleFadeOutAffector.cpp */; }; + 5E5733711C18E212003F664E /* CParticleGravityAffector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C91A1B7F684000F212E8 /* CParticleGravityAffector.cpp */; }; + 5E5733721C18E212003F664E /* CParticleMeshEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C91C1B7F684000F212E8 /* CParticleMeshEmitter.cpp */; }; + 5E5733731C18E212003F664E /* CParticlePointEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C91E1B7F684000F212E8 /* CParticlePointEmitter.cpp */; }; + 5E5733741C18E212003F664E /* CParticleRingEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9201B7F684000F212E8 /* CParticleRingEmitter.cpp */; }; + 5E5733751C18E212003F664E /* CParticleRotationAffector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9221B7F684000F212E8 /* CParticleRotationAffector.cpp */; }; + 5E5733761C18E212003F664E /* CParticleScaleAffector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9241B7F684000F212E8 /* CParticleScaleAffector.cpp */; }; + 5E5733771C18E212003F664E /* CParticleSphereEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9261B7F684000F212E8 /* CParticleSphereEmitter.cpp */; }; + 5E5733781C18E212003F664E /* CParticleSystemSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9281B7F684000F212E8 /* CParticleSystemSceneNode.cpp */; }; + 5E5733791C18E212003F664E /* CAnimatedMeshSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C92A1B7F68D600F212E8 /* CAnimatedMeshSceneNode.cpp */; }; + 5E57337A1C18E212003F664E /* CBillboardSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C92C1B7F68D600F212E8 /* CBillboardSceneNode.cpp */; }; + 5E57337B1C18E212003F664E /* CBoneSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C92E1B7F68D600F212E8 /* CBoneSceneNode.cpp */; }; + 5E57337C1C18E212003F664E /* CCameraSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9301B7F68D600F212E8 /* CCameraSceneNode.cpp */; }; + 5E57337D1C18E212003F664E /* CCubeSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9321B7F68D600F212E8 /* CCubeSceneNode.cpp */; }; + 5E57337E1C18E212003F664E /* CDummyTransformationSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9341B7F68D600F212E8 /* CDummyTransformationSceneNode.cpp */; }; + 5E57337F1C18E212003F664E /* CEmptySceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9361B7F68D600F212E8 /* CEmptySceneNode.cpp */; }; + 5E5733801C18E212003F664E /* CLightSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9381B7F68D600F212E8 /* CLightSceneNode.cpp */; }; + 5E5733811C18E212003F664E /* CMeshSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C93A1B7F68D600F212E8 /* CMeshSceneNode.cpp */; }; + 5E5733821C18E212003F664E /* COctreeSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C93C1B7F68D600F212E8 /* COctreeSceneNode.cpp */; }; + 5E5733831C18E212003F664E /* CQuake3ShaderSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C93E1B7F68D600F212E8 /* CQuake3ShaderSceneNode.cpp */; }; + 5E5733841C18E212003F664E /* CShadowVolumeSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9401B7F68D600F212E8 /* CShadowVolumeSceneNode.cpp */; }; + 5E5733851C18E212003F664E /* CSkyBoxSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9421B7F68D600F212E8 /* CSkyBoxSceneNode.cpp */; }; + 5E5733861C18E212003F664E /* CSkyDomeSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9441B7F68D600F212E8 /* CSkyDomeSceneNode.cpp */; }; + 5E5733871C18E212003F664E /* CSphereSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9461B7F68D600F212E8 /* CSphereSceneNode.cpp */; }; + 5E5733881C18E212003F664E /* CTerrainSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9481B7F68D600F212E8 /* CTerrainSceneNode.cpp */; }; + 5E5733891C18E212003F664E /* CTextSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C94A1B7F68D600F212E8 /* CTextSceneNode.cpp */; }; + 5E57338A1C18E212003F664E /* CVolumeLightSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C94C1B7F68D600F212E8 /* CVolumeLightSceneNode.cpp */; }; + 5E57338B1C18E212003F664E /* CWaterSurfaceSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C94E1B7F68D600F212E8 /* CWaterSurfaceSceneNode.cpp */; }; + 5E57338C1C18E212003F664E /* CB3DMeshWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E7908981C10FE4A00DFE7FE /* CB3DMeshWriter.cpp */; }; + 5E57338D1C18E212003F664E /* CColladaMeshWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9501B7F691500F212E8 /* CColladaMeshWriter.cpp */; }; + 5E57338E1C18E212003F664E /* CIrrMeshWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9521B7F691500F212E8 /* CIrrMeshWriter.cpp */; }; + 5E57338F1C18E212003F664E /* COBJMeshWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9541B7F691500F212E8 /* COBJMeshWriter.cpp */; }; + 5E5733901C18E212003F664E /* CPLYMeshWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9561B7F691500F212E8 /* CPLYMeshWriter.cpp */; }; + 5E5733911C18E212003F664E /* CSTLMeshWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9581B7F691500F212E8 /* CSTLMeshWriter.cpp */; }; + 5E5733921C18E212003F664E /* CDefaultSceneNodeAnimatorFactory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8AD1B7F664100F212E8 /* CDefaultSceneNodeAnimatorFactory.cpp */; }; + 5E5733931C18E212003F664E /* CDefaultSceneNodeFactory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8AF1B7F664100F212E8 /* CDefaultSceneNodeFactory.cpp */; }; + 5E5733941C18E212003F664E /* CGeometryCreator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8B11B7F664100F212E8 /* CGeometryCreator.cpp */; }; + 5E5733951C18E212003F664E /* CMeshCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8B31B7F664100F212E8 /* CMeshCache.cpp */; }; + 5E5733961C18E212003F664E /* CMeshManipulator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8B51B7F664100F212E8 /* CMeshManipulator.cpp */; }; + 5E5733971C18E212003F664E /* CSceneManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C8B71B7F664100F212E8 /* CSceneManager.cpp */; }; + 5E5733981C18E212003F664E /* CBurningShader_Raster_Reference.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9601B7F6A7600F212E8 /* CBurningShader_Raster_Reference.cpp */; }; + 5E5733991C18E212003F664E /* CDepthBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9611B7F6A7600F212E8 /* CDepthBuffer.cpp */; }; + 5E57339A1C18E212003F664E /* CSoftwareDriver2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9641B7F6A7600F212E8 /* CSoftwareDriver2.cpp */; }; + 5E57339B1C18E212003F664E /* CSoftwareTexture2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9661B7F6A7600F212E8 /* CSoftwareTexture2.cpp */; }; + 5E57339C1C18E212003F664E /* CTRGouraud2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9681B7F6A7600F212E8 /* CTRGouraud2.cpp */; }; + 5E57339D1C18E212003F664E /* CTRGouraudAlpha2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9691B7F6A7600F212E8 /* CTRGouraudAlpha2.cpp */; }; + 5E57339E1C18E212003F664E /* CTRGouraudAlphaNoZ2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C96A1B7F6A7600F212E8 /* CTRGouraudAlphaNoZ2.cpp */; }; + 5E57339F1C18E212003F664E /* CTRNormalMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C96B1B7F6A7600F212E8 /* CTRNormalMap.cpp */; }; + 5E5733A01C18E212003F664E /* CTRStencilShadow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C96C1B7F6A7600F212E8 /* CTRStencilShadow.cpp */; }; + 5E5733A11C18E212003F664E /* CTRTextureBlend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C96D1B7F6A7600F212E8 /* CTRTextureBlend.cpp */; }; + 5E5733A21C18E212003F664E /* CTRTextureDetailMap2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C96E1B7F6A7600F212E8 /* CTRTextureDetailMap2.cpp */; }; + 5E5733A31C18E212003F664E /* CTRTextureGouraud2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C96F1B7F6A7600F212E8 /* CTRTextureGouraud2.cpp */; }; + 5E5733A41C18E212003F664E /* CTRTextureGouraudAdd2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9701B7F6A7600F212E8 /* CTRTextureGouraudAdd2.cpp */; }; + 5E5733A51C18E212003F664E /* CTRTextureGouraudAddNoZ2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9711B7F6A7600F212E8 /* CTRTextureGouraudAddNoZ2.cpp */; }; + 5E5733A61C18E212003F664E /* CTRTextureGouraudAlpha.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9721B7F6A7600F212E8 /* CTRTextureGouraudAlpha.cpp */; }; + 5E5733A71C18E212003F664E /* CTRTextureGouraudAlphaNoZ.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9731B7F6A7600F212E8 /* CTRTextureGouraudAlphaNoZ.cpp */; }; + 5E5733A81C18E212003F664E /* CTRTextureGouraudNoZ2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9741B7F6A7600F212E8 /* CTRTextureGouraudNoZ2.cpp */; }; + 5E5733A91C18E212003F664E /* CTRTextureGouraudVertexAlpha2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9751B7F6A7600F212E8 /* CTRTextureGouraudVertexAlpha2.cpp */; }; + 5E5733AA1C18E212003F664E /* CTRTextureLightMap2_Add.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9761B7F6A7600F212E8 /* CTRTextureLightMap2_Add.cpp */; }; + 5E5733AB1C18E212003F664E /* CTRTextureLightMap2_M1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9771B7F6A7600F212E8 /* CTRTextureLightMap2_M1.cpp */; }; + 5E5733AC1C18E212003F664E /* CTRTextureLightMap2_M2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9781B7F6A7600F212E8 /* CTRTextureLightMap2_M2.cpp */; }; + 5E5733AD1C18E212003F664E /* CTRTextureLightMap2_M4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9791B7F6A7600F212E8 /* CTRTextureLightMap2_M4.cpp */; }; + 5E5733AE1C18E212003F664E /* CTRTextureLightMapGouraud2_M4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C97A1B7F6A7600F212E8 /* CTRTextureLightMapGouraud2_M4.cpp */; }; + 5E5733AF1C18E212003F664E /* CTRTextureWire2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C97B1B7F6A7600F212E8 /* CTRTextureWire2.cpp */; }; + 5E5733B01C18E212003F664E /* IBurningShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C97C1B7F6A7600F212E8 /* IBurningShader.cpp */; }; + 5E5733B11C18E212003F664E /* CImageLoaderBMP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9841B7F6AED00F212E8 /* CImageLoaderBMP.cpp */; }; + 5E5733B21C18E212003F664E /* CImageLoaderDDS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9861B7F6AED00F212E8 /* CImageLoaderDDS.cpp */; }; + 5E5733B31C18E212003F664E /* CImageLoaderJPG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9881B7F6AED00F212E8 /* CImageLoaderJPG.cpp */; }; + 5E5733B41C18E212003F664E /* CImageLoaderPCX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C98A1B7F6AED00F212E8 /* CImageLoaderPCX.cpp */; }; + 5E5733B51C18E212003F664E /* CImageLoaderPNG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C98C1B7F6AED00F212E8 /* CImageLoaderPNG.cpp */; }; + 5E5733B61C18E212003F664E /* CImageLoaderPPM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C98E1B7F6AED00F212E8 /* CImageLoaderPPM.cpp */; }; + 5E5733B71C18E212003F664E /* CImageLoaderPSD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9901B7F6AED00F212E8 /* CImageLoaderPSD.cpp */; }; + 5E5733B81C18E212003F664E /* CImageLoaderPVR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9921B7F6AED00F212E8 /* CImageLoaderPVR.cpp */; }; + 5E5733B91C18E212003F664E /* CImageLoaderRGB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9941B7F6AED00F212E8 /* CImageLoaderRGB.cpp */; }; + 5E5733BA1C18E212003F664E /* CImageLoaderTGA.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9961B7F6AED00F212E8 /* CImageLoaderTGA.cpp */; }; + 5E5733BB1C18E212003F664E /* CImageLoaderWAL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9981B7F6AED00F212E8 /* CImageLoaderWAL.cpp */; }; + 5E5733BC1C18E212003F664E /* CImageWriterBMP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C99A1B7F6B0900F212E8 /* CImageWriterBMP.cpp */; }; + 5E5733BD1C18E212003F664E /* CImageWriterJPG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C99C1B7F6B0900F212E8 /* CImageWriterJPG.cpp */; }; + 5E5733BE1C18E212003F664E /* CImageWriterPCX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C99E1B7F6B0900F212E8 /* CImageWriterPCX.cpp */; }; + 5E5733BF1C18E212003F664E /* CImageWriterPNG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9A01B7F6B0900F212E8 /* CImageWriterPNG.cpp */; }; + 5E5733C01C18E212003F664E /* CImageWriterPPM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9A21B7F6B0900F212E8 /* CImageWriterPPM.cpp */; }; + 5E5733C11C18E212003F664E /* CImageWriterPSD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9A41B7F6B0900F212E8 /* CImageWriterPSD.cpp */; }; + 5E5733C21C18E212003F664E /* CImageWriterTGA.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9A61B7F6B0900F212E8 /* CImageWriterTGA.cpp */; }; + 5E5733C31C18E212003F664E /* CColorConverter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9A81B7F6B6800F212E8 /* CColorConverter.cpp */; }; + 5E5733C41C18E212003F664E /* CFPSCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9AA1B7F6B6800F212E8 /* CFPSCounter.cpp */; }; + 5E5733C51C18E212003F664E /* CImage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9AC1B7F6B6800F212E8 /* CImage.cpp */; }; + 5E5733C61C18E212003F664E /* CNullDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9AE1B7F6B6800F212E8 /* CNullDriver.cpp */; }; + 5E5733C71C18E212003F664E /* COpenGLCacheHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E7908911C10EEC000DFE7FE /* COpenGLCacheHandler.cpp */; }; + 5E5733C81C18E212003F664E /* COpenGLDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9B11B7F6BA700F212E8 /* COpenGLDriver.cpp */; }; + 5E5733C91C18E212003F664E /* COpenGLExtensionHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9B31B7F6BA700F212E8 /* COpenGLExtensionHandler.cpp */; }; + 5E5733CA1C18E212003F664E /* COpenGLNormalMapRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9B61B7F6BA700F212E8 /* COpenGLNormalMapRenderer.cpp */; }; + 5E5733CB1C18E212003F664E /* COpenGLParallaxMapRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9B81B7F6BA700F212E8 /* COpenGLParallaxMapRenderer.cpp */; }; + 5E5733CC1C18E212003F664E /* COpenGLShaderMaterialRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9BA1B7F6BA700F212E8 /* COpenGLShaderMaterialRenderer.cpp */; }; + 5E5733CD1C18E212003F664E /* COpenGLSLMaterialRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9BC1B7F6BA700F212E8 /* COpenGLSLMaterialRenderer.cpp */; }; + 5E5733CE1C18E212003F664E /* CSoftwareDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9D71B7F6C6100F212E8 /* CSoftwareDriver.cpp */; }; + 5E5733CF1C18E212003F664E /* CSoftwareTexture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9D91B7F6C6100F212E8 /* CSoftwareTexture.cpp */; }; + 5E5733D01C18E212003F664E /* CTRFlat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9DB1B7F6C6100F212E8 /* CTRFlat.cpp */; }; + 5E5733D11C18E212003F664E /* CTRFlatWire.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9DC1B7F6C6100F212E8 /* CTRFlatWire.cpp */; }; + 5E5733D21C18E212003F664E /* CTRGouraud.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9DD1B7F6C6100F212E8 /* CTRGouraud.cpp */; }; + 5E5733D31C18E212003F664E /* CTRGouraudWire.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9DE1B7F6C6100F212E8 /* CTRGouraudWire.cpp */; }; + 5E5733D41C18E212003F664E /* CTRTextureFlat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9DF1B7F6C6100F212E8 /* CTRTextureFlat.cpp */; }; + 5E5733D51C18E212003F664E /* CTRTextureFlatWire.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9E01B7F6C6100F212E8 /* CTRTextureFlatWire.cpp */; }; + 5E5733D61C18E212003F664E /* CTRTextureGouraud.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9E11B7F6C6100F212E8 /* CTRTextureGouraud.cpp */; }; + 5E5733D71C18E212003F664E /* CTRTextureGouraudAdd.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9E31B7F6C6100F212E8 /* CTRTextureGouraudAdd.cpp */; }; + 5E5733D81C18E212003F664E /* CTRTextureGouraudNoZ.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9E41B7F6C6100F212E8 /* CTRTextureGouraudNoZ.cpp */; }; + 5E5733D91C18E212003F664E /* CTRTextureGouraudWire.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9E51B7F6C6100F212E8 /* CTRTextureGouraudWire.cpp */; }; + 5E5733DA1C18E212003F664E /* CZBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9E61B7F6C6100F212E8 /* CZBuffer.cpp */; }; + 5E5733DB1C18E212003F664E /* CNSOGLManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9EE1B7F6CCC00F212E8 /* CNSOGLManager.mm */; }; + 5E5733DC1C18E212003F664E /* CVideoModeList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E34C9EB1B7F6C8200F212E8 /* CVideoModeList.cpp */; }; + 5E5733E91C18E254003F664E /* CIrrDeviceiOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5E5733E71C18E254003F664E /* CIrrDeviceiOS.mm */; }; + 5E5733F31C18E2C0003F664E /* COGLESDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E5733ED1C18E2C0003F664E /* COGLESDriver.cpp */; }; + 5E5733F51C18E2C0003F664E /* COGLESExtensionHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E5733EF1C18E2C0003F664E /* COGLESExtensionHandler.cpp */; }; + 5E5734081C18E2E2003F664E /* COGLES2Driver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E5733F91C18E2E2003F664E /* COGLES2Driver.cpp */; }; + 5E57340A1C18E2E2003F664E /* COGLES2ExtensionHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E5733FB1C18E2E2003F664E /* COGLES2ExtensionHandler.cpp */; }; + 5E57340C1C18E2E2003F664E /* COGLES2FixedPipelineRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E5733FD1C18E2E2003F664E /* COGLES2FixedPipelineRenderer.cpp */; }; + 5E57340E1C18E2E2003F664E /* COGLES2MaterialRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E5733FF1C18E2E2003F664E /* COGLES2MaterialRenderer.cpp */; }; + 5E5734101C18E2E2003F664E /* COGLES2NormalMapRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E5734011C18E2E2003F664E /* COGLES2NormalMapRenderer.cpp */; }; + 5E5734121C18E2E2003F664E /* COGLES2ParallaxMapRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E5734031C18E2E2003F664E /* COGLES2ParallaxMapRenderer.cpp */; }; + 5E5734141C18E2E2003F664E /* COGLES2Renderer2D.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E5734051C18E2E2003F664E /* COGLES2Renderer2D.cpp */; }; + 5E7908971C10EF3F00DFE7FE /* COpenGLCacheHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E7908911C10EEC000DFE7FE /* COpenGLCacheHandler.cpp */; }; + 5E79089B1C10FEF900DFE7FE /* CB3DMeshWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E7908981C10FE4A00DFE7FE /* CB3DMeshWriter.cpp */; }; + 5E8570BC1B7F9AC400B267D2 /* CIrrDeviceConsole.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E8570BA1B7F9AC400B267D2 /* CIrrDeviceConsole.cpp */; }; + 5E9573D71C18E9E600C27989 /* CEAGLManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5E9573D61C18E9E600C27989 /* CEAGLManager.mm */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5E34C6E21B7F4AFB00F212E8 /* aabbox3d.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = aabbox3d.h; path = ../../include/aabbox3d.h; sourceTree = ""; }; + 5E34C6E31B7F4AFB00F212E8 /* CDynamicMeshBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CDynamicMeshBuffer.h; path = ../../include/CDynamicMeshBuffer.h; sourceTree = ""; }; + 5E34C6E41B7F4AFB00F212E8 /* CIndexBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CIndexBuffer.h; path = ../../include/CIndexBuffer.h; sourceTree = ""; }; + 5E34C6E51B7F4AFB00F212E8 /* CMeshBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CMeshBuffer.h; path = ../../include/CMeshBuffer.h; sourceTree = ""; }; + 5E34C6E61B7F4AFB00F212E8 /* coreutil.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = coreutil.h; path = ../../include/coreutil.h; sourceTree = ""; }; + 5E34C6E71B7F4AFB00F212E8 /* CVertexBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CVertexBuffer.h; path = ../../include/CVertexBuffer.h; sourceTree = ""; }; + 5E34C6E81B7F4AFB00F212E8 /* dimension2d.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dimension2d.h; path = ../../include/dimension2d.h; sourceTree = ""; }; + 5E34C6E91B7F4AFB00F212E8 /* driverChoice.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = driverChoice.h; path = ../../include/driverChoice.h; sourceTree = ""; }; + 5E34C6EA1B7F4AFB00F212E8 /* EAttributes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EAttributes.h; path = ../../include/EAttributes.h; sourceTree = ""; }; + 5E34C6EB1B7F4AFB00F212E8 /* ECullingTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ECullingTypes.h; path = ../../include/ECullingTypes.h; sourceTree = ""; }; + 5E34C6EC1B7F4AFB00F212E8 /* EDebugSceneTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EDebugSceneTypes.h; path = ../../include/EDebugSceneTypes.h; sourceTree = ""; }; + 5E34C6ED1B7F4AFB00F212E8 /* EDeviceTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EDeviceTypes.h; path = ../../include/EDeviceTypes.h; sourceTree = ""; }; + 5E34C6EE1B7F4AFB00F212E8 /* EDriverFeatures.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EDriverFeatures.h; path = ../../include/EDriverFeatures.h; sourceTree = ""; }; + 5E34C6EF1B7F4AFB00F212E8 /* EDriverTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EDriverTypes.h; path = ../../include/EDriverTypes.h; sourceTree = ""; }; + 5E34C6F01B7F4AFB00F212E8 /* EFocusFlags.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EFocusFlags.h; path = ../../include/EFocusFlags.h; sourceTree = ""; }; + 5E34C6F11B7F4AFB00F212E8 /* EGUIAlignment.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EGUIAlignment.h; path = ../../include/EGUIAlignment.h; sourceTree = ""; }; + 5E34C6F21B7F4AFB00F212E8 /* EGUIElementTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EGUIElementTypes.h; path = ../../include/EGUIElementTypes.h; sourceTree = ""; }; + 5E34C6F31B7F4AFB00F212E8 /* EHardwareBufferFlags.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EHardwareBufferFlags.h; path = ../../include/EHardwareBufferFlags.h; sourceTree = ""; }; + 5E34C6F41B7F4AFB00F212E8 /* EMaterialFlags.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EMaterialFlags.h; path = ../../include/EMaterialFlags.h; sourceTree = ""; }; + 5E34C6F51B7F4AFB00F212E8 /* EMaterialTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EMaterialTypes.h; path = ../../include/EMaterialTypes.h; sourceTree = ""; }; + 5E34C6F61B7F4AFB00F212E8 /* EMeshWriterEnums.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EMeshWriterEnums.h; path = ../../include/EMeshWriterEnums.h; sourceTree = ""; }; + 5E34C6F71B7F4AFB00F212E8 /* EMessageBoxFlags.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EMessageBoxFlags.h; path = ../../include/EMessageBoxFlags.h; sourceTree = ""; }; + 5E34C6F81B7F4AFB00F212E8 /* EPrimitiveTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EPrimitiveTypes.h; path = ../../include/EPrimitiveTypes.h; sourceTree = ""; }; + 5E34C6F91B7F4AFB00F212E8 /* ESceneNodeAnimatorTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ESceneNodeAnimatorTypes.h; path = ../../include/ESceneNodeAnimatorTypes.h; sourceTree = ""; }; + 5E34C6FA1B7F4AFC00F212E8 /* ESceneNodeTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ESceneNodeTypes.h; path = ../../include/ESceneNodeTypes.h; sourceTree = ""; }; + 5E34C6FB1B7F4AFC00F212E8 /* EShaderTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EShaderTypes.h; path = ../../include/EShaderTypes.h; sourceTree = ""; }; + 5E34C6FC1B7F4AFC00F212E8 /* ETerrainElements.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ETerrainElements.h; path = ../../include/ETerrainElements.h; sourceTree = ""; }; + 5E34C6FE1B7F4AFC00F212E8 /* fast_atof.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = fast_atof.h; path = ../../include/fast_atof.h; sourceTree = ""; }; + 5E34C6FF1B7F4AFC00F212E8 /* heapsort.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = heapsort.h; path = ../../include/heapsort.h; sourceTree = ""; }; + 5E34C7001B7F4AFC00F212E8 /* IAnimatedMesh.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IAnimatedMesh.h; path = ../../include/IAnimatedMesh.h; sourceTree = ""; }; + 5E34C7011B7F4AFC00F212E8 /* IAnimatedMeshMD2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IAnimatedMeshMD2.h; path = ../../include/IAnimatedMeshMD2.h; sourceTree = ""; }; + 5E34C7021B7F4AFC00F212E8 /* IAnimatedMeshMD3.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IAnimatedMeshMD3.h; path = ../../include/IAnimatedMeshMD3.h; sourceTree = ""; }; + 5E34C7031B7F4AFC00F212E8 /* IAnimatedMeshSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IAnimatedMeshSceneNode.h; path = ../../include/IAnimatedMeshSceneNode.h; sourceTree = ""; }; + 5E34C7041B7F4AFC00F212E8 /* IAttributeExchangingObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IAttributeExchangingObject.h; path = ../../include/IAttributeExchangingObject.h; sourceTree = ""; }; + 5E34C7051B7F4AFC00F212E8 /* IAttributes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IAttributes.h; path = ../../include/IAttributes.h; sourceTree = ""; }; + 5E34C7061B7F4AFC00F212E8 /* IBillboardSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IBillboardSceneNode.h; path = ../../include/IBillboardSceneNode.h; sourceTree = ""; }; + 5E34C7071B7F4AFC00F212E8 /* IBillboardTextSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IBillboardTextSceneNode.h; path = ../../include/IBillboardTextSceneNode.h; sourceTree = ""; }; + 5E34C7081B7F4AFC00F212E8 /* IBoneSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IBoneSceneNode.h; path = ../../include/IBoneSceneNode.h; sourceTree = ""; }; + 5E34C7091B7F4AFC00F212E8 /* ICameraSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ICameraSceneNode.h; path = ../../include/ICameraSceneNode.h; sourceTree = ""; }; + 5E34C70A1B7F4AFC00F212E8 /* IColladaMeshWriter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IColladaMeshWriter.h; path = ../../include/IColladaMeshWriter.h; sourceTree = ""; }; + 5E34C70B1B7F4AFC00F212E8 /* IContextManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IContextManager.h; path = ../../include/IContextManager.h; sourceTree = ""; }; + 5E34C70C1B7F4AFC00F212E8 /* ICursorControl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ICursorControl.h; path = ../../include/ICursorControl.h; sourceTree = ""; }; + 5E34C70D1B7F4AFC00F212E8 /* IDummyTransformationSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IDummyTransformationSceneNode.h; path = ../../include/IDummyTransformationSceneNode.h; sourceTree = ""; }; + 5E34C70E1B7F4AFC00F212E8 /* IDynamicMeshBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IDynamicMeshBuffer.h; path = ../../include/IDynamicMeshBuffer.h; sourceTree = ""; }; + 5E34C70F1B7F4AFC00F212E8 /* IEventReceiver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IEventReceiver.h; path = ../../include/IEventReceiver.h; sourceTree = ""; }; + 5E34C7101B7F4AFC00F212E8 /* IFileArchive.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IFileArchive.h; path = ../../include/IFileArchive.h; sourceTree = ""; }; + 5E34C7111B7F4AFC00F212E8 /* IFileList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IFileList.h; path = ../../include/IFileList.h; sourceTree = ""; }; + 5E34C7121B7F4AFC00F212E8 /* IFileSystem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IFileSystem.h; path = ../../include/IFileSystem.h; sourceTree = ""; }; + 5E34C7131B7F4AFC00F212E8 /* IGeometryCreator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGeometryCreator.h; path = ../../include/IGeometryCreator.h; sourceTree = ""; }; + 5E34C7141B7F4AFC00F212E8 /* IGPUProgrammingServices.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGPUProgrammingServices.h; path = ../../include/IGPUProgrammingServices.h; sourceTree = ""; }; + 5E34C7151B7F4AFC00F212E8 /* IGUIButton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIButton.h; path = ../../include/IGUIButton.h; sourceTree = ""; }; + 5E34C7161B7F4AFC00F212E8 /* IGUICheckBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUICheckBox.h; path = ../../include/IGUICheckBox.h; sourceTree = ""; }; + 5E34C7171B7F4AFC00F212E8 /* IGUIColorSelectDialog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIColorSelectDialog.h; path = ../../include/IGUIColorSelectDialog.h; sourceTree = ""; }; + 5E34C7181B7F4AFC00F212E8 /* IGUIComboBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIComboBox.h; path = ../../include/IGUIComboBox.h; sourceTree = ""; }; + 5E34C7191B7F4AFC00F212E8 /* IGUIContextMenu.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIContextMenu.h; path = ../../include/IGUIContextMenu.h; sourceTree = ""; }; + 5E34C71A1B7F4AFC00F212E8 /* IGUIEditBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIEditBox.h; path = ../../include/IGUIEditBox.h; sourceTree = ""; }; + 5E34C71B1B7F4AFC00F212E8 /* IGUIElement.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIElement.h; path = ../../include/IGUIElement.h; sourceTree = ""; }; + 5E34C71C1B7F4AFC00F212E8 /* IGUIElementFactory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIElementFactory.h; path = ../../include/IGUIElementFactory.h; sourceTree = ""; }; + 5E34C71D1B7F4AFC00F212E8 /* IGUIEnvironment.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIEnvironment.h; path = ../../include/IGUIEnvironment.h; sourceTree = ""; }; + 5E34C71E1B7F4AFC00F212E8 /* IGUIFileOpenDialog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIFileOpenDialog.h; path = ../../include/IGUIFileOpenDialog.h; sourceTree = ""; }; + 5E34C71F1B7F4AFC00F212E8 /* IGUIFont.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIFont.h; path = ../../include/IGUIFont.h; sourceTree = ""; }; + 5E34C7201B7F4AFC00F212E8 /* IGUIFontBitmap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIFontBitmap.h; path = ../../include/IGUIFontBitmap.h; sourceTree = ""; }; + 5E34C7211B7F4AFC00F212E8 /* IGUIImage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIImage.h; path = ../../include/IGUIImage.h; sourceTree = ""; }; + 5E34C7221B7F4AFC00F212E8 /* IGUIImageList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIImageList.h; path = ../../include/IGUIImageList.h; sourceTree = ""; }; + 5E34C7231B7F4AFC00F212E8 /* IGUIInOutFader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIInOutFader.h; path = ../../include/IGUIInOutFader.h; sourceTree = ""; }; + 5E34C7241B7F4AFC00F212E8 /* IGUIListBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIListBox.h; path = ../../include/IGUIListBox.h; sourceTree = ""; }; + 5E34C7251B7F4AFC00F212E8 /* IGUIMeshViewer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIMeshViewer.h; path = ../../include/IGUIMeshViewer.h; sourceTree = ""; }; + 5E34C7261B7F4AFC00F212E8 /* IGUIProfiler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIProfiler.h; path = ../../include/IGUIProfiler.h; sourceTree = ""; }; + 5E34C7271B7F4AFC00F212E8 /* IGUIScrollBar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIScrollBar.h; path = ../../include/IGUIScrollBar.h; sourceTree = ""; }; + 5E34C7281B7F4AFC00F212E8 /* IGUISkin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUISkin.h; path = ../../include/IGUISkin.h; sourceTree = ""; }; + 5E34C7291B7F4AFC00F212E8 /* IGUISpinBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUISpinBox.h; path = ../../include/IGUISpinBox.h; sourceTree = ""; }; + 5E34C72A1B7F4AFC00F212E8 /* IGUISpriteBank.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUISpriteBank.h; path = ../../include/IGUISpriteBank.h; sourceTree = ""; }; + 5E34C72B1B7F4AFC00F212E8 /* IGUIStaticText.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIStaticText.h; path = ../../include/IGUIStaticText.h; sourceTree = ""; }; + 5E34C72C1B7F4AFC00F212E8 /* IGUITabControl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUITabControl.h; path = ../../include/IGUITabControl.h; sourceTree = ""; }; + 5E34C72D1B7F4AFC00F212E8 /* IGUITable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUITable.h; path = ../../include/IGUITable.h; sourceTree = ""; }; + 5E34C72E1B7F4AFC00F212E8 /* IGUIToolbar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIToolbar.h; path = ../../include/IGUIToolbar.h; sourceTree = ""; }; + 5E34C72F1B7F4AFC00F212E8 /* IGUITreeView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUITreeView.h; path = ../../include/IGUITreeView.h; sourceTree = ""; }; + 5E34C7301B7F4AFC00F212E8 /* IGUIWindow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IGUIWindow.h; path = ../../include/IGUIWindow.h; sourceTree = ""; }; + 5E34C7311B7F4AFC00F212E8 /* IImage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IImage.h; path = ../../include/IImage.h; sourceTree = ""; }; + 5E34C7321B7F4AFC00F212E8 /* IImageLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IImageLoader.h; path = ../../include/IImageLoader.h; sourceTree = ""; }; + 5E34C7331B7F4AFC00F212E8 /* IImageWriter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IImageWriter.h; path = ../../include/IImageWriter.h; sourceTree = ""; }; + 5E34C7341B7F4AFC00F212E8 /* IIndexBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IIndexBuffer.h; path = ../../include/IIndexBuffer.h; sourceTree = ""; }; + 5E34C7351B7F4AFC00F212E8 /* ILightManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ILightManager.h; path = ../../include/ILightManager.h; sourceTree = ""; }; + 5E34C7361B7F4AFC00F212E8 /* ILightSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ILightSceneNode.h; path = ../../include/ILightSceneNode.h; sourceTree = ""; }; + 5E34C7371B7F4AFC00F212E8 /* ILogger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ILogger.h; path = ../../include/ILogger.h; sourceTree = ""; }; + 5E34C7381B7F4AFC00F212E8 /* IMaterialRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IMaterialRenderer.h; path = ../../include/IMaterialRenderer.h; sourceTree = ""; }; + 5E34C7391B7F4AFC00F212E8 /* IMaterialRendererServices.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IMaterialRendererServices.h; path = ../../include/IMaterialRendererServices.h; sourceTree = ""; }; + 5E34C73A1B7F4AFC00F212E8 /* IMesh.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IMesh.h; path = ../../include/IMesh.h; sourceTree = ""; }; + 5E34C73B1B7F4AFC00F212E8 /* IMeshBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IMeshBuffer.h; path = ../../include/IMeshBuffer.h; sourceTree = ""; }; + 5E34C73C1B7F4AFC00F212E8 /* IMeshCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IMeshCache.h; path = ../../include/IMeshCache.h; sourceTree = ""; }; + 5E34C73D1B7F4AFC00F212E8 /* IMeshLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IMeshLoader.h; path = ../../include/IMeshLoader.h; sourceTree = ""; }; + 5E34C73E1B7F4AFC00F212E8 /* IMeshManipulator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IMeshManipulator.h; path = ../../include/IMeshManipulator.h; sourceTree = ""; }; + 5E34C73F1B7F4AFC00F212E8 /* IMeshSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IMeshSceneNode.h; path = ../../include/IMeshSceneNode.h; sourceTree = ""; }; + 5E34C7401B7F4AFC00F212E8 /* IMeshTextureLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IMeshTextureLoader.h; path = ../../include/IMeshTextureLoader.h; sourceTree = ""; }; + 5E34C7411B7F4AFC00F212E8 /* IMeshWriter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IMeshWriter.h; path = ../../include/IMeshWriter.h; sourceTree = ""; }; + 5E34C7421B7F4AFC00F212E8 /* IMetaTriangleSelector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IMetaTriangleSelector.h; path = ../../include/IMetaTriangleSelector.h; sourceTree = ""; }; + 5E34C7431B7F4AFC00F212E8 /* IOSOperator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IOSOperator.h; path = ../../include/IOSOperator.h; sourceTree = ""; }; + 5E34C7441B7F4AFC00F212E8 /* IParticleAffector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IParticleAffector.h; path = ../../include/IParticleAffector.h; sourceTree = ""; }; + 5E34C7451B7F4AFC00F212E8 /* IParticleAnimatedMeshSceneNodeEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IParticleAnimatedMeshSceneNodeEmitter.h; path = ../../include/IParticleAnimatedMeshSceneNodeEmitter.h; sourceTree = ""; }; + 5E34C7461B7F4AFC00F212E8 /* IParticleAttractionAffector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IParticleAttractionAffector.h; path = ../../include/IParticleAttractionAffector.h; sourceTree = ""; }; + 5E34C7471B7F4AFC00F212E8 /* IParticleBoxEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IParticleBoxEmitter.h; path = ../../include/IParticleBoxEmitter.h; sourceTree = ""; }; + 5E34C7481B7F4AFC00F212E8 /* IParticleCylinderEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IParticleCylinderEmitter.h; path = ../../include/IParticleCylinderEmitter.h; sourceTree = ""; }; + 5E34C7491B7F4AFC00F212E8 /* IParticleEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IParticleEmitter.h; path = ../../include/IParticleEmitter.h; sourceTree = ""; }; + 5E34C74A1B7F4AFC00F212E8 /* IParticleFadeOutAffector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IParticleFadeOutAffector.h; path = ../../include/IParticleFadeOutAffector.h; sourceTree = ""; }; + 5E34C74B1B7F4AFC00F212E8 /* IParticleGravityAffector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IParticleGravityAffector.h; path = ../../include/IParticleGravityAffector.h; sourceTree = ""; }; + 5E34C74C1B7F4AFC00F212E8 /* IParticleMeshEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IParticleMeshEmitter.h; path = ../../include/IParticleMeshEmitter.h; sourceTree = ""; }; + 5E34C74D1B7F4AFC00F212E8 /* IParticleRingEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IParticleRingEmitter.h; path = ../../include/IParticleRingEmitter.h; sourceTree = ""; }; + 5E34C74E1B7F4AFC00F212E8 /* IParticleRotationAffector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IParticleRotationAffector.h; path = ../../include/IParticleRotationAffector.h; sourceTree = ""; }; + 5E34C74F1B7F4AFC00F212E8 /* IParticleSphereEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IParticleSphereEmitter.h; path = ../../include/IParticleSphereEmitter.h; sourceTree = ""; }; + 5E34C7501B7F4AFC00F212E8 /* IParticleSystemSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IParticleSystemSceneNode.h; path = ../../include/IParticleSystemSceneNode.h; sourceTree = ""; }; + 5E34C7511B7F4AFC00F212E8 /* IProfiler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IProfiler.h; path = ../../include/IProfiler.h; sourceTree = ""; }; + 5E34C7521B7F4AFC00F212E8 /* IQ3LevelMesh.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IQ3LevelMesh.h; path = ../../include/IQ3LevelMesh.h; sourceTree = ""; }; + 5E34C7531B7F4AFC00F212E8 /* IQ3Shader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IQ3Shader.h; path = ../../include/IQ3Shader.h; sourceTree = ""; }; + 5E34C7541B7F4AFC00F212E8 /* IRandomizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IRandomizer.h; path = ../../include/IRandomizer.h; sourceTree = ""; }; + 5E34C7551B7F4AFC00F212E8 /* IReadFile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IReadFile.h; path = ../../include/IReadFile.h; sourceTree = ""; }; + 5E34C7561B7F4AFC00F212E8 /* IReferenceCounted.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IReferenceCounted.h; path = ../../include/IReferenceCounted.h; sourceTree = ""; }; + 5E34C7571B7F4AFC00F212E8 /* irrAllocator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = irrAllocator.h; path = ../../include/irrAllocator.h; sourceTree = ""; }; + 5E34C7581B7F4AFC00F212E8 /* irrArray.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = irrArray.h; path = ../../include/irrArray.h; sourceTree = ""; }; + 5E34C7591B7F4AFC00F212E8 /* IrrCompileConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IrrCompileConfig.h; path = ../../include/IrrCompileConfig.h; sourceTree = ""; }; + 5E34C75A1B7F4AFC00F212E8 /* irrlicht.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = irrlicht.h; path = ../../include/irrlicht.h; sourceTree = ""; }; + 5E34C75B1B7F4AFC00F212E8 /* IrrlichtDevice.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IrrlichtDevice.h; path = ../../include/IrrlichtDevice.h; sourceTree = ""; }; + 5E34C75C1B7F4AFC00F212E8 /* irrList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = irrList.h; path = ../../include/irrList.h; sourceTree = ""; }; + 5E34C75D1B7F4AFC00F212E8 /* irrMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = irrMap.h; path = ../../include/irrMap.h; sourceTree = ""; }; + 5E34C75E1B7F4AFC00F212E8 /* irrMath.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = irrMath.h; path = ../../include/irrMath.h; sourceTree = ""; }; + 5E34C75F1B7F4AFC00F212E8 /* irrpack.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = irrpack.h; path = ../../include/irrpack.h; sourceTree = ""; }; + 5E34C7601B7F4AFC00F212E8 /* irrString.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = irrString.h; path = ../../include/irrString.h; sourceTree = ""; }; + 5E34C7611B7F4AFC00F212E8 /* irrTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = irrTypes.h; path = ../../include/irrTypes.h; sourceTree = ""; }; + 5E34C7621B7F4AFC00F212E8 /* irrunpack.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = irrunpack.h; path = ../../include/irrunpack.h; sourceTree = ""; }; + 5E34C7631B7F4AFC00F212E8 /* irrXML.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = irrXML.h; path = ../../include/irrXML.h; sourceTree = ""; }; + 5E34C7641B7F4AFC00F212E8 /* ISceneCollisionManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ISceneCollisionManager.h; path = ../../include/ISceneCollisionManager.h; sourceTree = ""; }; + 5E34C7651B7F4AFC00F212E8 /* ISceneLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ISceneLoader.h; path = ../../include/ISceneLoader.h; sourceTree = ""; }; + 5E34C7661B7F4AFC00F212E8 /* ISceneManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ISceneManager.h; path = ../../include/ISceneManager.h; sourceTree = ""; }; + 5E34C7671B7F4AFC00F212E8 /* ISceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ISceneNode.h; path = ../../include/ISceneNode.h; sourceTree = ""; }; + 5E34C7681B7F4AFC00F212E8 /* ISceneNodeAnimator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ISceneNodeAnimator.h; path = ../../include/ISceneNodeAnimator.h; sourceTree = ""; }; + 5E34C7691B7F4AFC00F212E8 /* ISceneNodeAnimatorCameraFPS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ISceneNodeAnimatorCameraFPS.h; path = ../../include/ISceneNodeAnimatorCameraFPS.h; sourceTree = ""; }; + 5E34C76A1B7F4AFC00F212E8 /* ISceneNodeAnimatorCameraMaya.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ISceneNodeAnimatorCameraMaya.h; path = ../../include/ISceneNodeAnimatorCameraMaya.h; sourceTree = ""; }; + 5E34C76B1B7F4AFC00F212E8 /* ISceneNodeAnimatorCollisionResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ISceneNodeAnimatorCollisionResponse.h; path = ../../include/ISceneNodeAnimatorCollisionResponse.h; sourceTree = ""; }; + 5E34C76C1B7F4AFC00F212E8 /* ISceneNodeAnimatorFactory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ISceneNodeAnimatorFactory.h; path = ../../include/ISceneNodeAnimatorFactory.h; sourceTree = ""; }; + 5E34C76D1B7F4AFC00F212E8 /* ISceneNodeFactory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ISceneNodeFactory.h; path = ../../include/ISceneNodeFactory.h; sourceTree = ""; }; + 5E34C76E1B7F4AFC00F212E8 /* ISceneUserDataSerializer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ISceneUserDataSerializer.h; path = ../../include/ISceneUserDataSerializer.h; sourceTree = ""; }; + 5E34C76F1B7F4AFC00F212E8 /* IShaderConstantSetCallBack.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IShaderConstantSetCallBack.h; path = ../../include/IShaderConstantSetCallBack.h; sourceTree = ""; }; + 5E34C7701B7F4AFC00F212E8 /* IShadowVolumeSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IShadowVolumeSceneNode.h; path = ../../include/IShadowVolumeSceneNode.h; sourceTree = ""; }; + 5E34C7711B7F4AFC00F212E8 /* ISkinnedMesh.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ISkinnedMesh.h; path = ../../include/ISkinnedMesh.h; sourceTree = ""; }; + 5E34C7721B7F4AFC00F212E8 /* ITerrainSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ITerrainSceneNode.h; path = ../../include/ITerrainSceneNode.h; sourceTree = ""; }; + 5E34C7731B7F4AFC00F212E8 /* ITextSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ITextSceneNode.h; path = ../../include/ITextSceneNode.h; sourceTree = ""; }; + 5E34C7741B7F4AFC00F212E8 /* ITexture.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ITexture.h; path = ../../include/ITexture.h; sourceTree = ""; }; + 5E34C7751B7F4AFC00F212E8 /* ITimer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ITimer.h; path = ../../include/ITimer.h; sourceTree = ""; }; + 5E34C7761B7F4AFC00F212E8 /* ITriangleSelector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ITriangleSelector.h; path = ../../include/ITriangleSelector.h; sourceTree = ""; }; + 5E34C7771B7F4AFC00F212E8 /* IVertexBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IVertexBuffer.h; path = ../../include/IVertexBuffer.h; sourceTree = ""; }; + 5E34C7781B7F4AFC00F212E8 /* IVideoDriver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IVideoDriver.h; path = ../../include/IVideoDriver.h; sourceTree = ""; }; + 5E34C7791B7F4AFC00F212E8 /* IVideoModeList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IVideoModeList.h; path = ../../include/IVideoModeList.h; sourceTree = ""; }; + 5E34C77A1B7F4AFC00F212E8 /* IVolumeLightSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IVolumeLightSceneNode.h; path = ../../include/IVolumeLightSceneNode.h; sourceTree = ""; }; + 5E34C77B1B7F4AFC00F212E8 /* IWriteFile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IWriteFile.h; path = ../../include/IWriteFile.h; sourceTree = ""; }; + 5E34C77C1B7F4AFC00F212E8 /* IXMLReader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IXMLReader.h; path = ../../include/IXMLReader.h; sourceTree = ""; }; + 5E34C77D1B7F4AFC00F212E8 /* IXMLWriter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IXMLWriter.h; path = ../../include/IXMLWriter.h; sourceTree = ""; }; + 5E34C77E1B7F4AFC00F212E8 /* Keycodes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Keycodes.h; path = ../../include/Keycodes.h; sourceTree = ""; }; + 5E34C77F1B7F4AFC00F212E8 /* leakHunter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = leakHunter.h; path = ../../include/leakHunter.h; sourceTree = ""; }; + 5E34C7801B7F4AFC00F212E8 /* line2d.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = line2d.h; path = ../../include/line2d.h; sourceTree = ""; }; + 5E34C7811B7F4AFC00F212E8 /* line3d.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = line3d.h; path = ../../include/line3d.h; sourceTree = ""; }; + 5E34C7821B7F4AFC00F212E8 /* matrix4.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = matrix4.h; path = ../../include/matrix4.h; sourceTree = ""; }; + 5E34C7831B7F4AFC00F212E8 /* path.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = path.h; path = ../../include/path.h; sourceTree = ""; }; + 5E34C7841B7F4AFC00F212E8 /* plane3d.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = plane3d.h; path = ../../include/plane3d.h; sourceTree = ""; }; + 5E34C7851B7F4AFC00F212E8 /* position2d.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = position2d.h; path = ../../include/position2d.h; sourceTree = ""; }; + 5E34C7861B7F4AFC00F212E8 /* quaternion.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = quaternion.h; path = ../../include/quaternion.h; sourceTree = ""; }; + 5E34C7871B7F4AFC00F212E8 /* rect.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = rect.h; path = ../../include/rect.h; sourceTree = ""; }; + 5E34C7881B7F4AFC00F212E8 /* S3DVertex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = S3DVertex.h; path = ../../include/S3DVertex.h; sourceTree = ""; }; + 5E34C7891B7F4AFC00F212E8 /* SAnimatedMesh.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SAnimatedMesh.h; path = ../../include/SAnimatedMesh.h; sourceTree = ""; }; + 5E34C78A1B7F4AFC00F212E8 /* SceneParameters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SceneParameters.h; path = ../../include/SceneParameters.h; sourceTree = ""; }; + 5E34C78B1B7F4AFC00F212E8 /* SColor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SColor.h; path = ../../include/SColor.h; sourceTree = ""; }; + 5E34C78C1B7F4AFC00F212E8 /* SExposedVideoData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SExposedVideoData.h; path = ../../include/SExposedVideoData.h; sourceTree = ""; }; + 5E34C78D1B7F4AFC00F212E8 /* SIrrCreationParameters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SIrrCreationParameters.h; path = ../../include/SIrrCreationParameters.h; sourceTree = ""; }; + 5E34C78E1B7F4AFC00F212E8 /* SKeyMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SKeyMap.h; path = ../../include/SKeyMap.h; sourceTree = ""; }; + 5E34C78F1B7F4AFC00F212E8 /* SLight.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SLight.h; path = ../../include/SLight.h; sourceTree = ""; }; + 5E34C7901B7F4AFC00F212E8 /* SMaterial.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SMaterial.h; path = ../../include/SMaterial.h; sourceTree = ""; }; + 5E34C7911B7F4AFC00F212E8 /* SMaterialLayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SMaterialLayer.h; path = ../../include/SMaterialLayer.h; sourceTree = ""; }; + 5E34C7921B7F4AFC00F212E8 /* SMesh.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SMesh.h; path = ../../include/SMesh.h; sourceTree = ""; }; + 5E34C7931B7F4AFC00F212E8 /* SMeshBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SMeshBuffer.h; path = ../../include/SMeshBuffer.h; sourceTree = ""; }; + 5E34C7941B7F4AFC00F212E8 /* SMeshBufferLightMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SMeshBufferLightMap.h; path = ../../include/SMeshBufferLightMap.h; sourceTree = ""; }; + 5E34C7951B7F4AFC00F212E8 /* SMeshBufferTangents.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SMeshBufferTangents.h; path = ../../include/SMeshBufferTangents.h; sourceTree = ""; }; + 5E34C7961B7F4AFC00F212E8 /* SParticle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SParticle.h; path = ../../include/SParticle.h; sourceTree = ""; }; + 5E34C7971B7F4AFC00F212E8 /* SSharedMeshBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SSharedMeshBuffer.h; path = ../../include/SSharedMeshBuffer.h; sourceTree = ""; }; + 5E34C7981B7F4AFC00F212E8 /* SSkinMeshBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SSkinMeshBuffer.h; path = ../../include/SSkinMeshBuffer.h; sourceTree = ""; }; + 5E34C7991B7F4AFC00F212E8 /* SVertexIndex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SVertexIndex.h; path = ../../include/SVertexIndex.h; sourceTree = ""; }; + 5E34C79A1B7F4AFC00F212E8 /* SVertexManipulator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SVertexManipulator.h; path = ../../include/SVertexManipulator.h; sourceTree = ""; }; + 5E34C79B1B7F4AFC00F212E8 /* SViewFrustum.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SViewFrustum.h; path = ../../include/SViewFrustum.h; sourceTree = ""; }; + 5E34C79C1B7F4AFC00F212E8 /* triangle3d.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = triangle3d.h; path = ../../include/triangle3d.h; sourceTree = ""; }; + 5E34C79D1B7F4AFC00F212E8 /* vector2d.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = vector2d.h; path = ../../include/vector2d.h; sourceTree = ""; }; + 5E34C79E1B7F4AFC00F212E8 /* vector3d.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = vector3d.h; path = ../../include/vector3d.h; sourceTree = ""; }; + 5E34C7A91B7F50A900F212E8 /* CGUIButton.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIButton.cpp; sourceTree = ""; }; + 5E34C7AA1B7F50A900F212E8 /* CGUIButton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIButton.h; sourceTree = ""; }; + 5E34C7AB1B7F50A900F212E8 /* CGUICheckBox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUICheckBox.cpp; sourceTree = ""; }; + 5E34C7AC1B7F50A900F212E8 /* CGUICheckBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUICheckBox.h; sourceTree = ""; }; + 5E34C7AD1B7F50A900F212E8 /* CGUIColorSelectDialog.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIColorSelectDialog.cpp; sourceTree = ""; }; + 5E34C7AE1B7F50A900F212E8 /* CGUIColorSelectDialog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIColorSelectDialog.h; sourceTree = ""; }; + 5E34C7AF1B7F50A900F212E8 /* CGUIComboBox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIComboBox.cpp; sourceTree = ""; }; + 5E34C7B01B7F50A900F212E8 /* CGUIComboBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIComboBox.h; sourceTree = ""; }; + 5E34C7B11B7F50A900F212E8 /* CGUIContextMenu.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIContextMenu.cpp; sourceTree = ""; }; + 5E34C7B21B7F50A900F212E8 /* CGUIContextMenu.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIContextMenu.h; sourceTree = ""; }; + 5E34C7B31B7F50A900F212E8 /* CGUIEditBox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIEditBox.cpp; sourceTree = ""; }; + 5E34C7B41B7F50A900F212E8 /* CGUIEditBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIEditBox.h; sourceTree = ""; }; + 5E34C7B51B7F50A900F212E8 /* CGUIEnvironment.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIEnvironment.cpp; sourceTree = ""; }; + 5E34C7B61B7F50A900F212E8 /* CGUIEnvironment.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIEnvironment.h; sourceTree = ""; }; + 5E34C7B71B7F50A900F212E8 /* CGUIFileOpenDialog.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIFileOpenDialog.cpp; sourceTree = ""; }; + 5E34C7B81B7F50A900F212E8 /* CGUIFileOpenDialog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIFileOpenDialog.h; sourceTree = ""; }; + 5E34C7B91B7F50A900F212E8 /* CGUIFont.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIFont.cpp; sourceTree = ""; }; + 5E34C7BA1B7F50A900F212E8 /* CGUIFont.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIFont.h; sourceTree = ""; }; + 5E34C7BB1B7F50A900F212E8 /* CGUIImage.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIImage.cpp; sourceTree = ""; }; + 5E34C7BC1B7F50A900F212E8 /* CGUIImage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIImage.h; sourceTree = ""; }; + 5E34C7BD1B7F50A900F212E8 /* CGUIImageList.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIImageList.cpp; sourceTree = ""; }; + 5E34C7BE1B7F50A900F212E8 /* CGUIImageList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIImageList.h; sourceTree = ""; }; + 5E34C7BF1B7F50A900F212E8 /* CGUIInOutFader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIInOutFader.cpp; sourceTree = ""; }; + 5E34C7C01B7F50A900F212E8 /* CGUIInOutFader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIInOutFader.h; sourceTree = ""; }; + 5E34C7C11B7F50A900F212E8 /* CGUIListBox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIListBox.cpp; sourceTree = ""; }; + 5E34C7C21B7F50A900F212E8 /* CGUIListBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIListBox.h; sourceTree = ""; }; + 5E34C7C31B7F50A900F212E8 /* CGUIMenu.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIMenu.cpp; sourceTree = ""; }; + 5E34C7C41B7F50A900F212E8 /* CGUIMenu.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIMenu.h; sourceTree = ""; }; + 5E34C7C51B7F50A900F212E8 /* CGUIMeshViewer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIMeshViewer.cpp; sourceTree = ""; }; + 5E34C7C61B7F50A900F212E8 /* CGUIMeshViewer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIMeshViewer.h; sourceTree = ""; }; + 5E34C7C71B7F50A900F212E8 /* CGUIMessageBox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIMessageBox.cpp; sourceTree = ""; }; + 5E34C7C81B7F50A900F212E8 /* CGUIMessageBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIMessageBox.h; sourceTree = ""; }; + 5E34C7C91B7F50A900F212E8 /* CGUIModalScreen.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIModalScreen.cpp; sourceTree = ""; }; + 5E34C7CA1B7F50A900F212E8 /* CGUIModalScreen.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIModalScreen.h; sourceTree = ""; }; + 5E34C7CB1B7F50A900F212E8 /* CGUIProfiler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIProfiler.cpp; sourceTree = ""; }; + 5E34C7CC1B7F50A900F212E8 /* CGUIProfiler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIProfiler.h; sourceTree = ""; }; + 5E34C7CD1B7F50A900F212E8 /* CGUIScrollBar.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIScrollBar.cpp; sourceTree = ""; }; + 5E34C7CE1B7F50A900F212E8 /* CGUIScrollBar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIScrollBar.h; sourceTree = ""; }; + 5E34C7CF1B7F50A900F212E8 /* CGUISkin.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUISkin.cpp; sourceTree = ""; }; + 5E34C7D01B7F50A900F212E8 /* CGUISkin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUISkin.h; sourceTree = ""; }; + 5E34C7D11B7F50A900F212E8 /* CGUISpinBox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUISpinBox.cpp; sourceTree = ""; }; + 5E34C7D21B7F50A900F212E8 /* CGUISpinBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUISpinBox.h; sourceTree = ""; }; + 5E34C7D31B7F50A900F212E8 /* CGUISpriteBank.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUISpriteBank.cpp; sourceTree = ""; }; + 5E34C7D41B7F50A900F212E8 /* CGUISpriteBank.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUISpriteBank.h; sourceTree = ""; }; + 5E34C7D51B7F50A900F212E8 /* CGUIStaticText.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIStaticText.cpp; sourceTree = ""; }; + 5E34C7D61B7F50A900F212E8 /* CGUIStaticText.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIStaticText.h; sourceTree = ""; }; + 5E34C7D71B7F50A900F212E8 /* CGUITabControl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUITabControl.cpp; sourceTree = ""; }; + 5E34C7D81B7F50A900F212E8 /* CGUITabControl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUITabControl.h; sourceTree = ""; }; + 5E34C7D91B7F50A900F212E8 /* CGUITable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUITable.cpp; sourceTree = ""; }; + 5E34C7DA1B7F50A900F212E8 /* CGUITable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUITable.h; sourceTree = ""; }; + 5E34C7DB1B7F50A900F212E8 /* CGUIToolBar.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIToolBar.cpp; sourceTree = ""; }; + 5E34C7DC1B7F50A900F212E8 /* CGUIToolBar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIToolBar.h; sourceTree = ""; }; + 5E34C7DD1B7F50A900F212E8 /* CGUITreeView.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUITreeView.cpp; sourceTree = ""; }; + 5E34C7DE1B7F50A900F212E8 /* CGUITreeView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUITreeView.h; sourceTree = ""; }; + 5E34C7DF1B7F50A900F212E8 /* CGUIWindow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGUIWindow.cpp; sourceTree = ""; }; + 5E34C7E01B7F50A900F212E8 /* CGUIWindow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGUIWindow.h; sourceTree = ""; }; + 5E34C7E11B7F50DE00F212E8 /* BuiltInFont.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BuiltInFont.h; sourceTree = ""; }; + 5E34C7E21B7F50DE00F212E8 /* CDefaultGUIElementFactory.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CDefaultGUIElementFactory.cpp; sourceTree = ""; }; + 5E34C7E31B7F50DE00F212E8 /* CDefaultGUIElementFactory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDefaultGUIElementFactory.h; sourceTree = ""; }; + 5E34C7E41B7F517000F212E8 /* CAttributeImpl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CAttributeImpl.h; sourceTree = ""; }; + 5E34C7E51B7F517000F212E8 /* CAttributes.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CAttributes.cpp; sourceTree = ""; }; + 5E34C7E61B7F517000F212E8 /* CAttributes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CAttributes.h; sourceTree = ""; }; + 5E34C7E71B7F517000F212E8 /* CFileList.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CFileList.cpp; sourceTree = ""; }; + 5E34C7E81B7F517000F212E8 /* CFileList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CFileList.h; sourceTree = ""; }; + 5E34C7E91B7F517000F212E8 /* CFileSystem.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CFileSystem.cpp; sourceTree = ""; }; + 5E34C7EA1B7F517000F212E8 /* CFileSystem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CFileSystem.h; sourceTree = ""; }; + 5E34C7EB1B7F517000F212E8 /* CLimitReadFile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CLimitReadFile.cpp; sourceTree = ""; }; + 5E34C7EC1B7F517000F212E8 /* CLimitReadFile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CLimitReadFile.h; sourceTree = ""; }; + 5E34C7ED1B7F517000F212E8 /* CMemoryFile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CMemoryFile.cpp; sourceTree = ""; }; + 5E34C7EE1B7F517000F212E8 /* CMemoryFile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CMemoryFile.h; sourceTree = ""; }; + 5E34C7EF1B7F517000F212E8 /* CMountPointReader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CMountPointReader.cpp; sourceTree = ""; }; + 5E34C7F01B7F517000F212E8 /* CMountPointReader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CMountPointReader.h; sourceTree = ""; }; + 5E34C7F11B7F517000F212E8 /* CNPKReader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CNPKReader.cpp; sourceTree = ""; }; + 5E34C7F21B7F517000F212E8 /* CNPKReader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CNPKReader.h; sourceTree = ""; }; + 5E34C7F31B7F517000F212E8 /* CPakReader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CPakReader.cpp; sourceTree = ""; }; + 5E34C7F41B7F517000F212E8 /* CPakReader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CPakReader.h; sourceTree = ""; }; + 5E34C7F51B7F51D900F212E8 /* CReadFile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CReadFile.cpp; sourceTree = ""; }; + 5E34C7F61B7F51D900F212E8 /* CReadFile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CReadFile.h; sourceTree = ""; }; + 5E34C7F71B7F51D900F212E8 /* CTarReader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTarReader.cpp; sourceTree = ""; }; + 5E34C7F81B7F51D900F212E8 /* CTarReader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CTarReader.h; sourceTree = ""; }; + 5E34C7F91B7F51D900F212E8 /* CWADReader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CWADReader.cpp; sourceTree = ""; }; + 5E34C7FA1B7F51D900F212E8 /* CWADReader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CWADReader.h; sourceTree = ""; }; + 5E34C7FB1B7F51D900F212E8 /* CWriteFile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CWriteFile.cpp; sourceTree = ""; }; + 5E34C7FC1B7F51D900F212E8 /* CWriteFile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CWriteFile.h; sourceTree = ""; }; + 5E34C7FD1B7F51D900F212E8 /* CXMLReader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CXMLReader.cpp; sourceTree = ""; }; + 5E34C7FE1B7F51D900F212E8 /* CXMLReader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CXMLReader.h; sourceTree = ""; }; + 5E34C7FF1B7F51D900F212E8 /* CXMLReaderImpl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CXMLReaderImpl.h; sourceTree = ""; }; + 5E34C8001B7F51D900F212E8 /* CXMLWriter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CXMLWriter.cpp; sourceTree = ""; }; + 5E34C8011B7F51D900F212E8 /* CXMLWriter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CXMLWriter.h; sourceTree = ""; }; + 5E34C8021B7F51D900F212E8 /* CZipReader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CZipReader.cpp; sourceTree = ""; }; + 5E34C8031B7F51D900F212E8 /* CZipReader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CZipReader.h; sourceTree = ""; }; + 5E34C8041B7F51D900F212E8 /* IAttribute.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IAttribute.h; sourceTree = ""; }; + 5E34C8051B7F51D900F212E8 /* irrXML.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = irrXML.cpp; sourceTree = ""; }; + 5E34C80D1B7F52AC00F212E8 /* CIrrDeviceStub.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CIrrDeviceStub.cpp; sourceTree = ""; }; + 5E34C80E1B7F52AC00F212E8 /* CIrrDeviceStub.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CIrrDeviceStub.h; sourceTree = ""; }; + 5E34C8131B7F535C00F212E8 /* CIrrDeviceOSX.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CIrrDeviceOSX.h; sourceTree = ""; }; + 5E34C8141B7F535C00F212E8 /* CIrrDeviceOSX.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CIrrDeviceOSX.mm; sourceTree = ""; }; + 5E34C8151B7F540B00F212E8 /* aes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = aes.h; path = aesGladman/aes.h; sourceTree = ""; }; + 5E34C8161B7F540B00F212E8 /* aescrypt.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = aescrypt.cpp; path = aesGladman/aescrypt.cpp; sourceTree = ""; }; + 5E34C8171B7F540B00F212E8 /* aeskey.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = aeskey.cpp; path = aesGladman/aeskey.cpp; sourceTree = ""; }; + 5E34C8181B7F540B00F212E8 /* aesopt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = aesopt.h; path = aesGladman/aesopt.h; sourceTree = ""; }; + 5E34C8191B7F540B00F212E8 /* aestab.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = aestab.cpp; path = aesGladman/aestab.cpp; sourceTree = ""; }; + 5E34C81A1B7F540B00F212E8 /* fileenc.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = fileenc.cpp; path = aesGladman/fileenc.cpp; sourceTree = ""; }; + 5E34C81B1B7F540B00F212E8 /* fileenc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = fileenc.h; path = aesGladman/fileenc.h; sourceTree = ""; }; + 5E34C81C1B7F540B00F212E8 /* hmac.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = hmac.cpp; path = aesGladman/hmac.cpp; sourceTree = ""; }; + 5E34C81D1B7F540B00F212E8 /* hmac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = hmac.h; path = aesGladman/hmac.h; sourceTree = ""; }; + 5E34C81E1B7F540B00F212E8 /* prng.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = prng.cpp; path = aesGladman/prng.cpp; sourceTree = ""; }; + 5E34C81F1B7F540B00F212E8 /* prng.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = prng.h; path = aesGladman/prng.h; sourceTree = ""; }; + 5E34C8201B7F540B00F212E8 /* pwd2key.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = pwd2key.cpp; path = aesGladman/pwd2key.cpp; sourceTree = ""; }; + 5E34C8211B7F540B00F212E8 /* pwd2key.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = pwd2key.h; path = aesGladman/pwd2key.h; sourceTree = ""; }; + 5E34C8221B7F540B00F212E8 /* sha1.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = sha1.cpp; path = aesGladman/sha1.cpp; sourceTree = ""; }; + 5E34C8231B7F540B00F212E8 /* sha1.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = sha1.h; path = aesGladman/sha1.h; sourceTree = ""; }; + 5E34C8241B7F540B00F212E8 /* sha2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = sha2.cpp; path = aesGladman/sha2.cpp; sourceTree = ""; }; + 5E34C8251B7F540B00F212E8 /* sha2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = sha2.h; path = aesGladman/sha2.h; sourceTree = ""; }; + 5E34C8261B7F54FE00F212E8 /* blocksort.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = blocksort.c; path = bzip2/blocksort.c; sourceTree = ""; }; + 5E34C8271B7F54FE00F212E8 /* bzcompress.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = bzcompress.c; path = bzip2/bzcompress.c; sourceTree = ""; }; + 5E34C8281B7F54FE00F212E8 /* bzlib_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = bzlib_private.h; path = bzip2/bzlib_private.h; sourceTree = ""; }; + 5E34C8291B7F54FE00F212E8 /* bzlib.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = bzlib.c; path = bzip2/bzlib.c; sourceTree = ""; }; + 5E34C82A1B7F54FE00F212E8 /* bzlib.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = bzlib.h; path = bzip2/bzlib.h; sourceTree = ""; }; + 5E34C82B1B7F54FE00F212E8 /* crctable.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = crctable.c; path = bzip2/crctable.c; sourceTree = ""; }; + 5E34C82C1B7F54FE00F212E8 /* decompress.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = decompress.c; path = bzip2/decompress.c; sourceTree = ""; }; + 5E34C82D1B7F54FE00F212E8 /* huffman.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = huffman.c; path = bzip2/huffman.c; sourceTree = ""; }; + 5E34C82E1B7F54FE00F212E8 /* randtable.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = randtable.c; path = bzip2/randtable.c; sourceTree = ""; }; + 5E34C8311B7F561400F212E8 /* cderror.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = cderror.h; path = jpeglib/cderror.h; sourceTree = ""; }; + 5E34C8321B7F561400F212E8 /* jaricom.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jaricom.c; path = jpeglib/jaricom.c; sourceTree = ""; }; + 5E34C8331B7F561400F212E8 /* jcapimin.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jcapimin.c; path = jpeglib/jcapimin.c; sourceTree = ""; }; + 5E34C8341B7F561400F212E8 /* jcapistd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jcapistd.c; path = jpeglib/jcapistd.c; sourceTree = ""; }; + 5E34C8351B7F561400F212E8 /* jcarith.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jcarith.c; path = jpeglib/jcarith.c; sourceTree = ""; }; + 5E34C8361B7F561400F212E8 /* jccoefct.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jccoefct.c; path = jpeglib/jccoefct.c; sourceTree = ""; }; + 5E34C8371B7F561400F212E8 /* jccolor.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jccolor.c; path = jpeglib/jccolor.c; sourceTree = ""; }; + 5E34C8381B7F561400F212E8 /* jcdctmgr.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jcdctmgr.c; path = jpeglib/jcdctmgr.c; sourceTree = ""; }; + 5E34C8391B7F561400F212E8 /* jchuff.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jchuff.c; path = jpeglib/jchuff.c; sourceTree = ""; }; + 5E34C83A1B7F561400F212E8 /* jcinit.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jcinit.c; path = jpeglib/jcinit.c; sourceTree = ""; }; + 5E34C83B1B7F561400F212E8 /* jcmainct.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jcmainct.c; path = jpeglib/jcmainct.c; sourceTree = ""; }; + 5E34C83C1B7F561400F212E8 /* jcmarker.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jcmarker.c; path = jpeglib/jcmarker.c; sourceTree = ""; }; + 5E34C83D1B7F561400F212E8 /* jcmaster.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jcmaster.c; path = jpeglib/jcmaster.c; sourceTree = ""; }; + 5E34C83E1B7F561400F212E8 /* jcomapi.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jcomapi.c; path = jpeglib/jcomapi.c; sourceTree = ""; }; + 5E34C83F1B7F561400F212E8 /* jconfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jconfig.h; path = jpeglib/jconfig.h; sourceTree = ""; }; + 5E34C8401B7F561400F212E8 /* jcparam.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jcparam.c; path = jpeglib/jcparam.c; sourceTree = ""; }; + 5E34C8411B7F561400F212E8 /* jcprepct.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jcprepct.c; path = jpeglib/jcprepct.c; sourceTree = ""; }; + 5E34C8421B7F561400F212E8 /* jcsample.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jcsample.c; path = jpeglib/jcsample.c; sourceTree = ""; }; + 5E34C8431B7F561400F212E8 /* jctrans.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jctrans.c; path = jpeglib/jctrans.c; sourceTree = ""; }; + 5E34C8441B7F561400F212E8 /* jdapimin.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jdapimin.c; path = jpeglib/jdapimin.c; sourceTree = ""; }; + 5E34C8451B7F561400F212E8 /* jdapistd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jdapistd.c; path = jpeglib/jdapistd.c; sourceTree = ""; }; + 5E34C8461B7F561400F212E8 /* jdarith.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jdarith.c; path = jpeglib/jdarith.c; sourceTree = ""; }; + 5E34C8471B7F561400F212E8 /* jdatadst.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jdatadst.c; path = jpeglib/jdatadst.c; sourceTree = ""; }; + 5E34C8481B7F561400F212E8 /* jdatasrc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jdatasrc.c; path = jpeglib/jdatasrc.c; sourceTree = ""; }; + 5E34C8491B7F561400F212E8 /* jdcoefct.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jdcoefct.c; path = jpeglib/jdcoefct.c; sourceTree = ""; }; + 5E34C84A1B7F561400F212E8 /* jdcolor.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jdcolor.c; path = jpeglib/jdcolor.c; sourceTree = ""; }; + 5E34C84B1B7F561400F212E8 /* jdct.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jdct.h; path = jpeglib/jdct.h; sourceTree = ""; }; + 5E34C84C1B7F561400F212E8 /* jddctmgr.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jddctmgr.c; path = jpeglib/jddctmgr.c; sourceTree = ""; }; + 5E34C84D1B7F561400F212E8 /* jdhuff.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jdhuff.c; path = jpeglib/jdhuff.c; sourceTree = ""; }; + 5E34C84E1B7F561400F212E8 /* jdinput.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jdinput.c; path = jpeglib/jdinput.c; sourceTree = ""; }; + 5E34C84F1B7F561400F212E8 /* jdmainct.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jdmainct.c; path = jpeglib/jdmainct.c; sourceTree = ""; }; + 5E34C8501B7F561400F212E8 /* jdmarker.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jdmarker.c; path = jpeglib/jdmarker.c; sourceTree = ""; }; + 5E34C8511B7F561400F212E8 /* jdmaster.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jdmaster.c; path = jpeglib/jdmaster.c; sourceTree = ""; }; + 5E34C8521B7F561400F212E8 /* jdmerge.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jdmerge.c; path = jpeglib/jdmerge.c; sourceTree = ""; }; + 5E34C8531B7F561400F212E8 /* jdpostct.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jdpostct.c; path = jpeglib/jdpostct.c; sourceTree = ""; }; + 5E34C8541B7F561400F212E8 /* jdsample.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jdsample.c; path = jpeglib/jdsample.c; sourceTree = ""; }; + 5E34C8551B7F561400F212E8 /* jdtrans.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jdtrans.c; path = jpeglib/jdtrans.c; sourceTree = ""; }; + 5E34C8561B7F561400F212E8 /* jerror.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jerror.c; path = jpeglib/jerror.c; sourceTree = ""; }; + 5E34C8571B7F561400F212E8 /* jerror.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jerror.h; path = jpeglib/jerror.h; sourceTree = ""; }; + 5E34C8581B7F568200F212E8 /* jfdctflt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jfdctflt.c; path = jpeglib/jfdctflt.c; sourceTree = ""; }; + 5E34C8591B7F568200F212E8 /* jfdctfst.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jfdctfst.c; path = jpeglib/jfdctfst.c; sourceTree = ""; }; + 5E34C85A1B7F568200F212E8 /* jfdctint.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jfdctint.c; path = jpeglib/jfdctint.c; sourceTree = ""; }; + 5E34C85B1B7F568200F212E8 /* jidctflt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jidctflt.c; path = jpeglib/jidctflt.c; sourceTree = ""; }; + 5E34C85C1B7F568200F212E8 /* jidctfst.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jidctfst.c; path = jpeglib/jidctfst.c; sourceTree = ""; }; + 5E34C85D1B7F568200F212E8 /* jidctint.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jidctint.c; path = jpeglib/jidctint.c; sourceTree = ""; }; + 5E34C85E1B7F568200F212E8 /* jinclude.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jinclude.h; path = jpeglib/jinclude.h; sourceTree = ""; }; + 5E34C85F1B7F568200F212E8 /* jmemmgr.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jmemmgr.c; path = jpeglib/jmemmgr.c; sourceTree = ""; }; + 5E34C8601B7F568200F212E8 /* jmemnobs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jmemnobs.c; path = jpeglib/jmemnobs.c; sourceTree = ""; }; + 5E34C8611B7F568200F212E8 /* jmemsys.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jmemsys.h; path = jpeglib/jmemsys.h; sourceTree = ""; }; + 5E34C8621B7F568200F212E8 /* jmorecfg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jmorecfg.h; path = jpeglib/jmorecfg.h; sourceTree = ""; }; + 5E34C8631B7F568200F212E8 /* jpegint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jpegint.h; path = jpeglib/jpegint.h; sourceTree = ""; }; + 5E34C8641B7F568200F212E8 /* jpeglib.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jpeglib.h; path = jpeglib/jpeglib.h; sourceTree = ""; }; + 5E34C8651B7F568200F212E8 /* jquant1.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jquant1.c; path = jpeglib/jquant1.c; sourceTree = ""; }; + 5E34C8661B7F568200F212E8 /* jquant2.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jquant2.c; path = jpeglib/jquant2.c; sourceTree = ""; }; + 5E34C8671B7F568200F212E8 /* jutils.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = jutils.c; path = jpeglib/jutils.c; sourceTree = ""; }; + 5E34C8681B7F568200F212E8 /* jversion.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jversion.h; path = jpeglib/jversion.h; sourceTree = ""; }; + 5E34C8691B7F56E900F212E8 /* png.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = png.c; path = libpng/png.c; sourceTree = ""; }; + 5E34C86A1B7F56E900F212E8 /* png.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = png.h; path = libpng/png.h; sourceTree = ""; }; + 5E34C86B1B7F56E900F212E8 /* pngconf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = pngconf.h; path = libpng/pngconf.h; sourceTree = ""; }; + 5E34C86C1B7F56E900F212E8 /* pngerror.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pngerror.c; path = libpng/pngerror.c; sourceTree = ""; }; + 5E34C86D1B7F56E900F212E8 /* pngget.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pngget.c; path = libpng/pngget.c; sourceTree = ""; }; + 5E34C86E1B7F56E900F212E8 /* pngmem.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pngmem.c; path = libpng/pngmem.c; sourceTree = ""; }; + 5E34C86F1B7F56E900F212E8 /* pngpread.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pngpread.c; path = libpng/pngpread.c; sourceTree = ""; }; + 5E34C8701B7F56E900F212E8 /* pngread.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pngread.c; path = libpng/pngread.c; sourceTree = ""; }; + 5E34C8711B7F56E900F212E8 /* pngrio.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pngrio.c; path = libpng/pngrio.c; sourceTree = ""; }; + 5E34C8721B7F56E900F212E8 /* pngrtran.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pngrtran.c; path = libpng/pngrtran.c; sourceTree = ""; }; + 5E34C8731B7F56E900F212E8 /* pngrutil.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pngrutil.c; path = libpng/pngrutil.c; sourceTree = ""; }; + 5E34C8741B7F56E900F212E8 /* pngset.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pngset.c; path = libpng/pngset.c; sourceTree = ""; }; + 5E34C8751B7F56E900F212E8 /* pngtrans.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pngtrans.c; path = libpng/pngtrans.c; sourceTree = ""; }; + 5E34C8761B7F56E900F212E8 /* pngwio.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pngwio.c; path = libpng/pngwio.c; sourceTree = ""; }; + 5E34C8771B7F56E900F212E8 /* pngwrite.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pngwrite.c; path = libpng/pngwrite.c; sourceTree = ""; }; + 5E34C8781B7F56E900F212E8 /* pngwtran.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pngwtran.c; path = libpng/pngwtran.c; sourceTree = ""; }; + 5E34C8791B7F56E900F212E8 /* pngwutil.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pngwutil.c; path = libpng/pngwutil.c; sourceTree = ""; }; + 5E34C87A1B7F577000F212E8 /* adler32.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = adler32.c; path = zlib/adler32.c; sourceTree = ""; }; + 5E34C87B1B7F577000F212E8 /* compress.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = compress.c; path = zlib/compress.c; sourceTree = ""; }; + 5E34C87C1B7F577000F212E8 /* crc32.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = crc32.c; path = zlib/crc32.c; sourceTree = ""; }; + 5E34C87D1B7F577000F212E8 /* crc32.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = crc32.h; path = zlib/crc32.h; sourceTree = ""; }; + 5E34C87E1B7F577000F212E8 /* deflate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = deflate.c; path = zlib/deflate.c; sourceTree = ""; }; + 5E34C87F1B7F577000F212E8 /* deflate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = deflate.h; path = zlib/deflate.h; sourceTree = ""; }; + 5E34C8801B7F577000F212E8 /* inffast.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = inffast.c; path = zlib/inffast.c; sourceTree = ""; }; + 5E34C8811B7F577000F212E8 /* inffast.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = inffast.h; path = zlib/inffast.h; sourceTree = ""; }; + 5E34C8821B7F577000F212E8 /* inffixed.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = inffixed.h; path = zlib/inffixed.h; sourceTree = ""; }; + 5E34C8831B7F577000F212E8 /* inflate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = inflate.c; path = zlib/inflate.c; sourceTree = ""; }; + 5E34C8841B7F577000F212E8 /* inflate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = inflate.h; path = zlib/inflate.h; sourceTree = ""; }; + 5E34C8851B7F577000F212E8 /* inftrees.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = inftrees.c; path = zlib/inftrees.c; sourceTree = ""; }; + 5E34C8861B7F577000F212E8 /* inftrees.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = inftrees.h; path = zlib/inftrees.h; sourceTree = ""; }; + 5E34C8871B7F577000F212E8 /* trees.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = trees.c; path = zlib/trees.c; sourceTree = ""; }; + 5E34C8881B7F577000F212E8 /* trees.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = trees.h; path = zlib/trees.h; sourceTree = ""; }; + 5E34C8891B7F577000F212E8 /* uncompr.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = uncompr.c; path = zlib/uncompr.c; sourceTree = ""; }; + 5E34C88A1B7F577000F212E8 /* zconf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = zconf.h; path = zlib/zconf.h; sourceTree = ""; }; + 5E34C88B1B7F577000F212E8 /* zlib.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = zlib.h; path = zlib/zlib.h; sourceTree = ""; }; + 5E34C88C1B7F577000F212E8 /* zutil.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = zutil.c; path = zlib/zutil.c; sourceTree = ""; }; + 5E34C88D1B7F577000F212E8 /* zutil.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = zutil.h; path = zlib/zutil.h; sourceTree = ""; }; + 5E34C88F1B7F57B100F212E8 /* LzmaDec.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = LzmaDec.c; path = lzma/LzmaDec.c; sourceTree = ""; }; + 5E34C8901B7F57B100F212E8 /* LzmaDec.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = LzmaDec.h; path = lzma/LzmaDec.h; sourceTree = ""; }; + 5E34C8911B7F57B100F212E8 /* Types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Types.h; path = lzma/Types.h; sourceTree = ""; }; + 5E34C8921B7F652600F212E8 /* CLogger.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CLogger.cpp; sourceTree = ""; }; + 5E34C8931B7F652600F212E8 /* CLogger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CLogger.h; sourceTree = ""; }; + 5E34C8941B7F652600F212E8 /* COSOperator.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; path = COSOperator.cpp; sourceTree = ""; }; + 5E34C8951B7F652600F212E8 /* COSOperator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = COSOperator.h; sourceTree = ""; }; + 5E34C8961B7F652600F212E8 /* CProfiler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CProfiler.cpp; sourceTree = ""; }; + 5E34C8971B7F652600F212E8 /* CProfiler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CProfiler.h; sourceTree = ""; }; + 5E34C8981B7F652600F212E8 /* CTimer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CTimer.h; sourceTree = ""; }; + 5E34C8991B7F652600F212E8 /* EProfileIDs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EProfileIDs.h; sourceTree = ""; }; + 5E34C89A1B7F652600F212E8 /* Irrlicht.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; path = Irrlicht.cpp; sourceTree = ""; }; + 5E34C89B1B7F652600F212E8 /* leakHunter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = leakHunter.cpp; sourceTree = ""; }; + 5E34C89C1B7F652600F212E8 /* os.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = os.cpp; sourceTree = ""; }; + 5E34C89D1B7F652600F212E8 /* os.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os.h; sourceTree = ""; }; + 5E34C89E1B7F652600F212E8 /* utf8.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = utf8.cpp; sourceTree = ""; }; + 5E34C8AD1B7F664100F212E8 /* CDefaultSceneNodeAnimatorFactory.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CDefaultSceneNodeAnimatorFactory.cpp; sourceTree = ""; }; + 5E34C8AE1B7F664100F212E8 /* CDefaultSceneNodeAnimatorFactory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDefaultSceneNodeAnimatorFactory.h; sourceTree = ""; }; + 5E34C8AF1B7F664100F212E8 /* CDefaultSceneNodeFactory.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CDefaultSceneNodeFactory.cpp; sourceTree = ""; }; + 5E34C8B01B7F664100F212E8 /* CDefaultSceneNodeFactory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDefaultSceneNodeFactory.h; sourceTree = ""; }; + 5E34C8B11B7F664100F212E8 /* CGeometryCreator.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CGeometryCreator.cpp; sourceTree = ""; }; + 5E34C8B21B7F664100F212E8 /* CGeometryCreator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CGeometryCreator.h; sourceTree = ""; }; + 5E34C8B31B7F664100F212E8 /* CMeshCache.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CMeshCache.cpp; sourceTree = ""; }; + 5E34C8B41B7F664100F212E8 /* CMeshCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CMeshCache.h; sourceTree = ""; }; + 5E34C8B51B7F664100F212E8 /* CMeshManipulator.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CMeshManipulator.cpp; sourceTree = ""; }; + 5E34C8B61B7F664100F212E8 /* CMeshManipulator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CMeshManipulator.h; sourceTree = ""; }; + 5E34C8B71B7F664100F212E8 /* CSceneManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSceneManager.cpp; sourceTree = ""; }; + 5E34C8B81B7F664100F212E8 /* CSceneManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSceneManager.h; sourceTree = ""; }; + 5E34C8B91B7F664100F212E8 /* Octree.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Octree.h; sourceTree = ""; }; + 5E34C8BA1B7F669200F212E8 /* CSceneNodeAnimatorCameraFPS.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSceneNodeAnimatorCameraFPS.cpp; sourceTree = ""; }; + 5E34C8BB1B7F669200F212E8 /* CSceneNodeAnimatorCameraFPS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSceneNodeAnimatorCameraFPS.h; sourceTree = ""; }; + 5E34C8BC1B7F669200F212E8 /* CSceneNodeAnimatorCameraMaya.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSceneNodeAnimatorCameraMaya.cpp; sourceTree = ""; }; + 5E34C8BD1B7F669200F212E8 /* CSceneNodeAnimatorCameraMaya.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSceneNodeAnimatorCameraMaya.h; sourceTree = ""; }; + 5E34C8BE1B7F669200F212E8 /* CSceneNodeAnimatorCollisionResponse.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSceneNodeAnimatorCollisionResponse.cpp; sourceTree = ""; }; + 5E34C8BF1B7F669200F212E8 /* CSceneNodeAnimatorCollisionResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSceneNodeAnimatorCollisionResponse.h; sourceTree = ""; }; + 5E34C8C01B7F669200F212E8 /* CSceneNodeAnimatorDelete.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSceneNodeAnimatorDelete.cpp; sourceTree = ""; }; + 5E34C8C11B7F669200F212E8 /* CSceneNodeAnimatorDelete.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSceneNodeAnimatorDelete.h; sourceTree = ""; }; + 5E34C8C21B7F669200F212E8 /* CSceneNodeAnimatorFlyCircle.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSceneNodeAnimatorFlyCircle.cpp; sourceTree = ""; }; + 5E34C8C31B7F669200F212E8 /* CSceneNodeAnimatorFlyCircle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSceneNodeAnimatorFlyCircle.h; sourceTree = ""; }; + 5E34C8C41B7F669200F212E8 /* CSceneNodeAnimatorFlyStraight.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSceneNodeAnimatorFlyStraight.cpp; sourceTree = ""; }; + 5E34C8C51B7F669200F212E8 /* CSceneNodeAnimatorFlyStraight.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSceneNodeAnimatorFlyStraight.h; sourceTree = ""; }; + 5E34C8C61B7F669200F212E8 /* CSceneNodeAnimatorFollowSpline.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSceneNodeAnimatorFollowSpline.cpp; sourceTree = ""; }; + 5E34C8C71B7F669200F212E8 /* CSceneNodeAnimatorFollowSpline.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSceneNodeAnimatorFollowSpline.h; sourceTree = ""; }; + 5E34C8C81B7F669200F212E8 /* CSceneNodeAnimatorRotation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSceneNodeAnimatorRotation.cpp; sourceTree = ""; }; + 5E34C8C91B7F669200F212E8 /* CSceneNodeAnimatorRotation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSceneNodeAnimatorRotation.h; sourceTree = ""; }; + 5E34C8CA1B7F669200F212E8 /* CSceneNodeAnimatorTexture.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSceneNodeAnimatorTexture.cpp; sourceTree = ""; }; + 5E34C8CB1B7F669200F212E8 /* CSceneNodeAnimatorTexture.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSceneNodeAnimatorTexture.h; sourceTree = ""; }; + 5E34C8CC1B7F66E600F212E8 /* CMetaTriangleSelector.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CMetaTriangleSelector.cpp; sourceTree = ""; }; + 5E34C8CD1B7F66E600F212E8 /* CMetaTriangleSelector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CMetaTriangleSelector.h; sourceTree = ""; }; + 5E34C8CE1B7F66E600F212E8 /* COctreeTriangleSelector.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = COctreeTriangleSelector.cpp; sourceTree = ""; }; + 5E34C8CF1B7F66E600F212E8 /* COctreeTriangleSelector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = COctreeTriangleSelector.h; sourceTree = ""; }; + 5E34C8D01B7F66E600F212E8 /* CSceneCollisionManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSceneCollisionManager.cpp; sourceTree = ""; }; + 5E34C8D11B7F66E600F212E8 /* CSceneCollisionManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSceneCollisionManager.h; sourceTree = ""; }; + 5E34C8D21B7F66E600F212E8 /* CTerrainTriangleSelector.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTerrainTriangleSelector.cpp; sourceTree = ""; }; + 5E34C8D31B7F66E600F212E8 /* CTerrainTriangleSelector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CTerrainTriangleSelector.h; sourceTree = ""; }; + 5E34C8D41B7F66E600F212E8 /* CTriangleBBSelector.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTriangleBBSelector.cpp; sourceTree = ""; }; + 5E34C8D51B7F66E600F212E8 /* CTriangleBBSelector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CTriangleBBSelector.h; sourceTree = ""; }; + 5E34C8D61B7F66E600F212E8 /* CTriangleSelector.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTriangleSelector.cpp; sourceTree = ""; }; + 5E34C8D71B7F66E600F212E8 /* CTriangleSelector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CTriangleSelector.h; sourceTree = ""; }; + 5E34C8D81B7F680200F212E8 /* C3DSMeshFileLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = C3DSMeshFileLoader.cpp; sourceTree = ""; }; + 5E34C8D91B7F680200F212E8 /* C3DSMeshFileLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = C3DSMeshFileLoader.h; sourceTree = ""; }; + 5E34C8DA1B7F680200F212E8 /* CAnimatedMeshHalfLife.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CAnimatedMeshHalfLife.cpp; sourceTree = ""; }; + 5E34C8DB1B7F680200F212E8 /* CAnimatedMeshHalfLife.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CAnimatedMeshHalfLife.h; sourceTree = ""; }; + 5E34C8DC1B7F680200F212E8 /* CAnimatedMeshMD2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CAnimatedMeshMD2.cpp; sourceTree = ""; }; + 5E34C8DD1B7F680200F212E8 /* CAnimatedMeshMD2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CAnimatedMeshMD2.h; sourceTree = ""; }; + 5E34C8DE1B7F680200F212E8 /* CAnimatedMeshMD3.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CAnimatedMeshMD3.cpp; sourceTree = ""; }; + 5E34C8DF1B7F680200F212E8 /* CAnimatedMeshMD3.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CAnimatedMeshMD3.h; sourceTree = ""; }; + 5E34C8E01B7F680200F212E8 /* CB3DMeshFileLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CB3DMeshFileLoader.cpp; sourceTree = ""; }; + 5E34C8E11B7F680200F212E8 /* CB3DMeshFileLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CB3DMeshFileLoader.h; sourceTree = ""; }; + 5E34C8E21B7F680200F212E8 /* CBSPMeshFileLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CBSPMeshFileLoader.cpp; sourceTree = ""; }; + 5E34C8E31B7F680200F212E8 /* CBSPMeshFileLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CBSPMeshFileLoader.h; sourceTree = ""; }; + 5E34C8E41B7F680200F212E8 /* CColladaFileLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CColladaFileLoader.cpp; sourceTree = ""; }; + 5E34C8E51B7F680200F212E8 /* CColladaFileLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CColladaFileLoader.h; sourceTree = ""; }; + 5E34C8E61B7F680200F212E8 /* CCSMLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CCSMLoader.cpp; sourceTree = ""; }; + 5E34C8E71B7F680200F212E8 /* CCSMLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CCSMLoader.h; sourceTree = ""; }; + 5E34C8E81B7F680200F212E8 /* CDMFLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CDMFLoader.cpp; sourceTree = ""; }; + 5E34C8E91B7F680200F212E8 /* CDMFLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDMFLoader.h; sourceTree = ""; }; + 5E34C8EA1B7F680200F212E8 /* CIrrMeshFileLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CIrrMeshFileLoader.cpp; sourceTree = ""; }; + 5E34C8EB1B7F680200F212E8 /* CIrrMeshFileLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CIrrMeshFileLoader.h; sourceTree = ""; }; + 5E34C8EC1B7F680200F212E8 /* CLMTSMeshFileLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CLMTSMeshFileLoader.cpp; sourceTree = ""; }; + 5E34C8ED1B7F680200F212E8 /* CLMTSMeshFileLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CLMTSMeshFileLoader.h; sourceTree = ""; }; + 5E34C8EE1B7F680200F212E8 /* CLWOMeshFileLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CLWOMeshFileLoader.cpp; sourceTree = ""; }; + 5E34C8EF1B7F680200F212E8 /* CLWOMeshFileLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CLWOMeshFileLoader.h; sourceTree = ""; }; + 5E34C8F01B7F680200F212E8 /* CMD2MeshFileLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CMD2MeshFileLoader.cpp; sourceTree = ""; }; + 5E34C8F11B7F680200F212E8 /* CMD2MeshFileLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CMD2MeshFileLoader.h; sourceTree = ""; }; + 5E34C8F21B7F680200F212E8 /* CMD3MeshFileLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CMD3MeshFileLoader.cpp; sourceTree = ""; }; + 5E34C8F31B7F680200F212E8 /* CMD3MeshFileLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CMD3MeshFileLoader.h; sourceTree = ""; }; + 5E34C8F41B7F680200F212E8 /* CMeshTextureLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CMeshTextureLoader.cpp; sourceTree = ""; }; + 5E34C8F51B7F680200F212E8 /* CMeshTextureLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CMeshTextureLoader.h; sourceTree = ""; }; + 5E34C8F61B7F680200F212E8 /* CMS3DMeshFileLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CMS3DMeshFileLoader.cpp; sourceTree = ""; }; + 5E34C8F71B7F680200F212E8 /* CMS3DMeshFileLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CMS3DMeshFileLoader.h; sourceTree = ""; }; + 5E34C8F81B7F680200F212E8 /* CMY3DHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CMY3DHelper.h; sourceTree = ""; }; + 5E34C8F91B7F680200F212E8 /* CMY3DMeshFileLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CMY3DMeshFileLoader.cpp; sourceTree = ""; }; + 5E34C8FA1B7F680200F212E8 /* CMY3DMeshFileLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CMY3DMeshFileLoader.h; sourceTree = ""; }; + 5E34C8FB1B7F680200F212E8 /* COBJMeshFileLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = COBJMeshFileLoader.cpp; sourceTree = ""; }; + 5E34C8FC1B7F680200F212E8 /* COBJMeshFileLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = COBJMeshFileLoader.h; sourceTree = ""; }; + 5E34C8FD1B7F680200F212E8 /* COCTLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = COCTLoader.cpp; sourceTree = ""; }; + 5E34C8FE1B7F680200F212E8 /* COCTLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = COCTLoader.h; sourceTree = ""; }; + 5E34C8FF1B7F680200F212E8 /* COgreMeshFileLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = COgreMeshFileLoader.cpp; sourceTree = ""; }; + 5E34C9001B7F680200F212E8 /* COgreMeshFileLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = COgreMeshFileLoader.h; sourceTree = ""; }; + 5E34C9011B7F680200F212E8 /* CPLYMeshFileLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CPLYMeshFileLoader.cpp; sourceTree = ""; }; + 5E34C9021B7F680200F212E8 /* CPLYMeshFileLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CPLYMeshFileLoader.h; sourceTree = ""; }; + 5E34C9031B7F680200F212E8 /* CQ3LevelMesh.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CQ3LevelMesh.cpp; sourceTree = ""; }; + 5E34C9041B7F680200F212E8 /* CQ3LevelMesh.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CQ3LevelMesh.h; sourceTree = ""; }; + 5E34C9051B7F680200F212E8 /* CSceneLoaderIrr.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSceneLoaderIrr.cpp; sourceTree = ""; }; + 5E34C9061B7F680200F212E8 /* CSceneLoaderIrr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSceneLoaderIrr.h; sourceTree = ""; }; + 5E34C9071B7F680200F212E8 /* CSkinnedMesh.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSkinnedMesh.cpp; sourceTree = ""; }; + 5E34C9081B7F680200F212E8 /* CSkinnedMesh.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSkinnedMesh.h; sourceTree = ""; }; + 5E34C9091B7F680200F212E8 /* CSMFMeshFileLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSMFMeshFileLoader.cpp; sourceTree = ""; }; + 5E34C90A1B7F680200F212E8 /* CSMFMeshFileLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSMFMeshFileLoader.h; sourceTree = ""; }; + 5E34C90B1B7F680200F212E8 /* CSTLMeshFileLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSTLMeshFileLoader.cpp; sourceTree = ""; }; + 5E34C90C1B7F680200F212E8 /* CSTLMeshFileLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSTLMeshFileLoader.h; sourceTree = ""; }; + 5E34C90D1B7F680200F212E8 /* CXMeshFileLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CXMeshFileLoader.cpp; sourceTree = ""; }; + 5E34C90E1B7F680200F212E8 /* CXMeshFileLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CXMeshFileLoader.h; sourceTree = ""; }; + 5E34C90F1B7F680200F212E8 /* dmfsupport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dmfsupport.h; sourceTree = ""; }; + 5E34C9101B7F684000F212E8 /* CParticleAnimatedMeshSceneNodeEmitter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CParticleAnimatedMeshSceneNodeEmitter.cpp; sourceTree = ""; }; + 5E34C9111B7F684000F212E8 /* CParticleAnimatedMeshSceneNodeEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CParticleAnimatedMeshSceneNodeEmitter.h; sourceTree = ""; }; + 5E34C9121B7F684000F212E8 /* CParticleAttractionAffector.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CParticleAttractionAffector.cpp; sourceTree = ""; }; + 5E34C9131B7F684000F212E8 /* CParticleAttractionAffector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CParticleAttractionAffector.h; sourceTree = ""; }; + 5E34C9141B7F684000F212E8 /* CParticleBoxEmitter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CParticleBoxEmitter.cpp; sourceTree = ""; }; + 5E34C9151B7F684000F212E8 /* CParticleBoxEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CParticleBoxEmitter.h; sourceTree = ""; }; + 5E34C9161B7F684000F212E8 /* CParticleCylinderEmitter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CParticleCylinderEmitter.cpp; sourceTree = ""; }; + 5E34C9171B7F684000F212E8 /* CParticleCylinderEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CParticleCylinderEmitter.h; sourceTree = ""; }; + 5E34C9181B7F684000F212E8 /* CParticleFadeOutAffector.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CParticleFadeOutAffector.cpp; sourceTree = ""; }; + 5E34C9191B7F684000F212E8 /* CParticleFadeOutAffector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CParticleFadeOutAffector.h; sourceTree = ""; }; + 5E34C91A1B7F684000F212E8 /* CParticleGravityAffector.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CParticleGravityAffector.cpp; sourceTree = ""; }; + 5E34C91B1B7F684000F212E8 /* CParticleGravityAffector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CParticleGravityAffector.h; sourceTree = ""; }; + 5E34C91C1B7F684000F212E8 /* CParticleMeshEmitter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CParticleMeshEmitter.cpp; sourceTree = ""; }; + 5E34C91D1B7F684000F212E8 /* CParticleMeshEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CParticleMeshEmitter.h; sourceTree = ""; }; + 5E34C91E1B7F684000F212E8 /* CParticlePointEmitter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CParticlePointEmitter.cpp; sourceTree = ""; }; + 5E34C91F1B7F684000F212E8 /* CParticlePointEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CParticlePointEmitter.h; sourceTree = ""; }; + 5E34C9201B7F684000F212E8 /* CParticleRingEmitter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CParticleRingEmitter.cpp; sourceTree = ""; }; + 5E34C9211B7F684000F212E8 /* CParticleRingEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CParticleRingEmitter.h; sourceTree = ""; }; + 5E34C9221B7F684000F212E8 /* CParticleRotationAffector.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CParticleRotationAffector.cpp; sourceTree = ""; }; + 5E34C9231B7F684000F212E8 /* CParticleRotationAffector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CParticleRotationAffector.h; sourceTree = ""; }; + 5E34C9241B7F684000F212E8 /* CParticleScaleAffector.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CParticleScaleAffector.cpp; sourceTree = ""; }; + 5E34C9251B7F684000F212E8 /* CParticleScaleAffector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CParticleScaleAffector.h; sourceTree = ""; }; + 5E34C9261B7F684000F212E8 /* CParticleSphereEmitter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CParticleSphereEmitter.cpp; sourceTree = ""; }; + 5E34C9271B7F684000F212E8 /* CParticleSphereEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CParticleSphereEmitter.h; sourceTree = ""; }; + 5E34C9281B7F684000F212E8 /* CParticleSystemSceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CParticleSystemSceneNode.cpp; sourceTree = ""; }; + 5E34C9291B7F684000F212E8 /* CParticleSystemSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CParticleSystemSceneNode.h; sourceTree = ""; }; + 5E34C92A1B7F68D600F212E8 /* CAnimatedMeshSceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CAnimatedMeshSceneNode.cpp; sourceTree = ""; }; + 5E34C92B1B7F68D600F212E8 /* CAnimatedMeshSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CAnimatedMeshSceneNode.h; sourceTree = ""; }; + 5E34C92C1B7F68D600F212E8 /* CBillboardSceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CBillboardSceneNode.cpp; sourceTree = ""; }; + 5E34C92D1B7F68D600F212E8 /* CBillboardSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CBillboardSceneNode.h; sourceTree = ""; }; + 5E34C92E1B7F68D600F212E8 /* CBoneSceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CBoneSceneNode.cpp; sourceTree = ""; }; + 5E34C92F1B7F68D600F212E8 /* CBoneSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CBoneSceneNode.h; sourceTree = ""; }; + 5E34C9301B7F68D600F212E8 /* CCameraSceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CCameraSceneNode.cpp; sourceTree = ""; }; + 5E34C9311B7F68D600F212E8 /* CCameraSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CCameraSceneNode.h; sourceTree = ""; }; + 5E34C9321B7F68D600F212E8 /* CCubeSceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CCubeSceneNode.cpp; sourceTree = ""; }; + 5E34C9331B7F68D600F212E8 /* CCubeSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CCubeSceneNode.h; sourceTree = ""; }; + 5E34C9341B7F68D600F212E8 /* CDummyTransformationSceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CDummyTransformationSceneNode.cpp; sourceTree = ""; }; + 5E34C9351B7F68D600F212E8 /* CDummyTransformationSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDummyTransformationSceneNode.h; sourceTree = ""; }; + 5E34C9361B7F68D600F212E8 /* CEmptySceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CEmptySceneNode.cpp; sourceTree = ""; }; + 5E34C9371B7F68D600F212E8 /* CEmptySceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CEmptySceneNode.h; sourceTree = ""; }; + 5E34C9381B7F68D600F212E8 /* CLightSceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CLightSceneNode.cpp; sourceTree = ""; }; + 5E34C9391B7F68D600F212E8 /* CLightSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CLightSceneNode.h; sourceTree = ""; }; + 5E34C93A1B7F68D600F212E8 /* CMeshSceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CMeshSceneNode.cpp; sourceTree = ""; }; + 5E34C93B1B7F68D600F212E8 /* CMeshSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CMeshSceneNode.h; sourceTree = ""; }; + 5E34C93C1B7F68D600F212E8 /* COctreeSceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = COctreeSceneNode.cpp; sourceTree = ""; }; + 5E34C93D1B7F68D600F212E8 /* COctreeSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = COctreeSceneNode.h; sourceTree = ""; }; + 5E34C93E1B7F68D600F212E8 /* CQuake3ShaderSceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CQuake3ShaderSceneNode.cpp; sourceTree = ""; }; + 5E34C93F1B7F68D600F212E8 /* CQuake3ShaderSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CQuake3ShaderSceneNode.h; sourceTree = ""; }; + 5E34C9401B7F68D600F212E8 /* CShadowVolumeSceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CShadowVolumeSceneNode.cpp; sourceTree = ""; }; + 5E34C9411B7F68D600F212E8 /* CShadowVolumeSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CShadowVolumeSceneNode.h; sourceTree = ""; }; + 5E34C9421B7F68D600F212E8 /* CSkyBoxSceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSkyBoxSceneNode.cpp; sourceTree = ""; }; + 5E34C9431B7F68D600F212E8 /* CSkyBoxSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSkyBoxSceneNode.h; sourceTree = ""; }; + 5E34C9441B7F68D600F212E8 /* CSkyDomeSceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSkyDomeSceneNode.cpp; sourceTree = ""; }; + 5E34C9451B7F68D600F212E8 /* CSkyDomeSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSkyDomeSceneNode.h; sourceTree = ""; }; + 5E34C9461B7F68D600F212E8 /* CSphereSceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSphereSceneNode.cpp; sourceTree = ""; }; + 5E34C9471B7F68D600F212E8 /* CSphereSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSphereSceneNode.h; sourceTree = ""; }; + 5E34C9481B7F68D600F212E8 /* CTerrainSceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTerrainSceneNode.cpp; sourceTree = ""; }; + 5E34C9491B7F68D600F212E8 /* CTerrainSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CTerrainSceneNode.h; sourceTree = ""; }; + 5E34C94A1B7F68D600F212E8 /* CTextSceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTextSceneNode.cpp; sourceTree = ""; }; + 5E34C94B1B7F68D600F212E8 /* CTextSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CTextSceneNode.h; sourceTree = ""; }; + 5E34C94C1B7F68D600F212E8 /* CVolumeLightSceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CVolumeLightSceneNode.cpp; sourceTree = ""; }; + 5E34C94D1B7F68D600F212E8 /* CVolumeLightSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CVolumeLightSceneNode.h; sourceTree = ""; }; + 5E34C94E1B7F68D600F212E8 /* CWaterSurfaceSceneNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CWaterSurfaceSceneNode.cpp; sourceTree = ""; }; + 5E34C94F1B7F68D600F212E8 /* CWaterSurfaceSceneNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CWaterSurfaceSceneNode.h; sourceTree = ""; }; + 5E34C9501B7F691500F212E8 /* CColladaMeshWriter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CColladaMeshWriter.cpp; sourceTree = ""; }; + 5E34C9511B7F691500F212E8 /* CColladaMeshWriter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CColladaMeshWriter.h; sourceTree = ""; }; + 5E34C9521B7F691500F212E8 /* CIrrMeshWriter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CIrrMeshWriter.cpp; sourceTree = ""; }; + 5E34C9531B7F691500F212E8 /* CIrrMeshWriter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CIrrMeshWriter.h; sourceTree = ""; }; + 5E34C9541B7F691500F212E8 /* COBJMeshWriter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = COBJMeshWriter.cpp; sourceTree = ""; }; + 5E34C9551B7F691500F212E8 /* COBJMeshWriter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = COBJMeshWriter.h; sourceTree = ""; }; + 5E34C9561B7F691500F212E8 /* CPLYMeshWriter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CPLYMeshWriter.cpp; sourceTree = ""; }; + 5E34C9571B7F691500F212E8 /* CPLYMeshWriter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CPLYMeshWriter.h; sourceTree = ""; }; + 5E34C9581B7F691500F212E8 /* CSTLMeshWriter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSTLMeshWriter.cpp; sourceTree = ""; }; + 5E34C9591B7F691500F212E8 /* CSTLMeshWriter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSTLMeshWriter.h; sourceTree = ""; }; + 5E34C9601B7F6A7600F212E8 /* CBurningShader_Raster_Reference.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CBurningShader_Raster_Reference.cpp; sourceTree = ""; }; + 5E34C9611B7F6A7600F212E8 /* CDepthBuffer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CDepthBuffer.cpp; sourceTree = ""; }; + 5E34C9621B7F6A7600F212E8 /* CDepthBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDepthBuffer.h; sourceTree = ""; }; + 5E34C9631B7F6A7600F212E8 /* CSoftware2MaterialRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSoftware2MaterialRenderer.h; sourceTree = ""; }; + 5E34C9641B7F6A7600F212E8 /* CSoftwareDriver2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSoftwareDriver2.cpp; sourceTree = ""; }; + 5E34C9651B7F6A7600F212E8 /* CSoftwareDriver2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSoftwareDriver2.h; sourceTree = ""; }; + 5E34C9661B7F6A7600F212E8 /* CSoftwareTexture2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSoftwareTexture2.cpp; sourceTree = ""; }; + 5E34C9671B7F6A7600F212E8 /* CSoftwareTexture2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSoftwareTexture2.h; sourceTree = ""; }; + 5E34C9681B7F6A7600F212E8 /* CTRGouraud2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRGouraud2.cpp; sourceTree = ""; }; + 5E34C9691B7F6A7600F212E8 /* CTRGouraudAlpha2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRGouraudAlpha2.cpp; sourceTree = ""; }; + 5E34C96A1B7F6A7600F212E8 /* CTRGouraudAlphaNoZ2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRGouraudAlphaNoZ2.cpp; sourceTree = ""; }; + 5E34C96B1B7F6A7600F212E8 /* CTRNormalMap.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRNormalMap.cpp; sourceTree = ""; }; + 5E34C96C1B7F6A7600F212E8 /* CTRStencilShadow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRStencilShadow.cpp; sourceTree = ""; }; + 5E34C96D1B7F6A7600F212E8 /* CTRTextureBlend.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureBlend.cpp; sourceTree = ""; }; + 5E34C96E1B7F6A7600F212E8 /* CTRTextureDetailMap2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureDetailMap2.cpp; sourceTree = ""; }; + 5E34C96F1B7F6A7600F212E8 /* CTRTextureGouraud2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureGouraud2.cpp; sourceTree = ""; }; + 5E34C9701B7F6A7600F212E8 /* CTRTextureGouraudAdd2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureGouraudAdd2.cpp; sourceTree = ""; }; + 5E34C9711B7F6A7600F212E8 /* CTRTextureGouraudAddNoZ2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureGouraudAddNoZ2.cpp; sourceTree = ""; }; + 5E34C9721B7F6A7600F212E8 /* CTRTextureGouraudAlpha.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureGouraudAlpha.cpp; sourceTree = ""; }; + 5E34C9731B7F6A7600F212E8 /* CTRTextureGouraudAlphaNoZ.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureGouraudAlphaNoZ.cpp; sourceTree = ""; }; + 5E34C9741B7F6A7600F212E8 /* CTRTextureGouraudNoZ2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureGouraudNoZ2.cpp; sourceTree = ""; }; + 5E34C9751B7F6A7600F212E8 /* CTRTextureGouraudVertexAlpha2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureGouraudVertexAlpha2.cpp; sourceTree = ""; }; + 5E34C9761B7F6A7600F212E8 /* CTRTextureLightMap2_Add.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureLightMap2_Add.cpp; sourceTree = ""; }; + 5E34C9771B7F6A7600F212E8 /* CTRTextureLightMap2_M1.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureLightMap2_M1.cpp; sourceTree = ""; }; + 5E34C9781B7F6A7600F212E8 /* CTRTextureLightMap2_M2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureLightMap2_M2.cpp; sourceTree = ""; }; + 5E34C9791B7F6A7600F212E8 /* CTRTextureLightMap2_M4.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureLightMap2_M4.cpp; sourceTree = ""; }; + 5E34C97A1B7F6A7600F212E8 /* CTRTextureLightMapGouraud2_M4.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureLightMapGouraud2_M4.cpp; sourceTree = ""; }; + 5E34C97B1B7F6A7600F212E8 /* CTRTextureWire2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureWire2.cpp; sourceTree = ""; }; + 5E34C97C1B7F6A7600F212E8 /* IBurningShader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = IBurningShader.cpp; sourceTree = ""; }; + 5E34C97D1B7F6A7600F212E8 /* IBurningShader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IBurningShader.h; sourceTree = ""; }; + 5E34C97E1B7F6A7600F212E8 /* IDepthBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IDepthBuffer.h; sourceTree = ""; }; + 5E34C97F1B7F6A7600F212E8 /* S4DVertex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = S4DVertex.h; sourceTree = ""; }; + 5E34C9801B7F6A7600F212E8 /* SoftwareDriver2_compile_config.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SoftwareDriver2_compile_config.h; sourceTree = ""; }; + 5E34C9811B7F6A7600F212E8 /* SoftwareDriver2_helper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SoftwareDriver2_helper.h; sourceTree = ""; }; + 5E34C9841B7F6AED00F212E8 /* CImageLoaderBMP.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CImageLoaderBMP.cpp; sourceTree = ""; }; + 5E34C9851B7F6AED00F212E8 /* CImageLoaderBMP.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CImageLoaderBMP.h; sourceTree = ""; }; + 5E34C9861B7F6AED00F212E8 /* CImageLoaderDDS.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CImageLoaderDDS.cpp; sourceTree = ""; }; + 5E34C9871B7F6AED00F212E8 /* CImageLoaderDDS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CImageLoaderDDS.h; sourceTree = ""; }; + 5E34C9881B7F6AED00F212E8 /* CImageLoaderJPG.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CImageLoaderJPG.cpp; sourceTree = ""; }; + 5E34C9891B7F6AED00F212E8 /* CImageLoaderJPG.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CImageLoaderJPG.h; sourceTree = ""; }; + 5E34C98A1B7F6AED00F212E8 /* CImageLoaderPCX.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CImageLoaderPCX.cpp; sourceTree = ""; }; + 5E34C98B1B7F6AED00F212E8 /* CImageLoaderPCX.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CImageLoaderPCX.h; sourceTree = ""; }; + 5E34C98C1B7F6AED00F212E8 /* CImageLoaderPNG.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CImageLoaderPNG.cpp; sourceTree = ""; }; + 5E34C98D1B7F6AED00F212E8 /* CImageLoaderPNG.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CImageLoaderPNG.h; sourceTree = ""; }; + 5E34C98E1B7F6AED00F212E8 /* CImageLoaderPPM.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CImageLoaderPPM.cpp; sourceTree = ""; }; + 5E34C98F1B7F6AED00F212E8 /* CImageLoaderPPM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CImageLoaderPPM.h; sourceTree = ""; }; + 5E34C9901B7F6AED00F212E8 /* CImageLoaderPSD.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CImageLoaderPSD.cpp; sourceTree = ""; }; + 5E34C9911B7F6AED00F212E8 /* CImageLoaderPSD.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CImageLoaderPSD.h; sourceTree = ""; }; + 5E34C9921B7F6AED00F212E8 /* CImageLoaderPVR.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CImageLoaderPVR.cpp; sourceTree = ""; }; + 5E34C9931B7F6AED00F212E8 /* CImageLoaderPVR.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CImageLoaderPVR.h; sourceTree = ""; }; + 5E34C9941B7F6AED00F212E8 /* CImageLoaderRGB.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CImageLoaderRGB.cpp; sourceTree = ""; }; + 5E34C9951B7F6AED00F212E8 /* CImageLoaderRGB.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CImageLoaderRGB.h; sourceTree = ""; }; + 5E34C9961B7F6AED00F212E8 /* CImageLoaderTGA.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CImageLoaderTGA.cpp; sourceTree = ""; }; + 5E34C9971B7F6AED00F212E8 /* CImageLoaderTGA.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CImageLoaderTGA.h; sourceTree = ""; }; + 5E34C9981B7F6AED00F212E8 /* CImageLoaderWAL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CImageLoaderWAL.cpp; sourceTree = ""; }; + 5E34C9991B7F6AED00F212E8 /* CImageLoaderWAL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CImageLoaderWAL.h; sourceTree = ""; }; + 5E34C99A1B7F6B0900F212E8 /* CImageWriterBMP.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CImageWriterBMP.cpp; sourceTree = ""; }; + 5E34C99B1B7F6B0900F212E8 /* CImageWriterBMP.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CImageWriterBMP.h; sourceTree = ""; }; + 5E34C99C1B7F6B0900F212E8 /* CImageWriterJPG.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CImageWriterJPG.cpp; sourceTree = ""; }; + 5E34C99D1B7F6B0900F212E8 /* CImageWriterJPG.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CImageWriterJPG.h; sourceTree = ""; }; + 5E34C99E1B7F6B0900F212E8 /* CImageWriterPCX.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CImageWriterPCX.cpp; sourceTree = ""; }; + 5E34C99F1B7F6B0900F212E8 /* CImageWriterPCX.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CImageWriterPCX.h; sourceTree = ""; }; + 5E34C9A01B7F6B0900F212E8 /* CImageWriterPNG.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CImageWriterPNG.cpp; sourceTree = ""; }; + 5E34C9A11B7F6B0900F212E8 /* CImageWriterPNG.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CImageWriterPNG.h; sourceTree = ""; }; + 5E34C9A21B7F6B0900F212E8 /* CImageWriterPPM.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CImageWriterPPM.cpp; sourceTree = ""; }; + 5E34C9A31B7F6B0900F212E8 /* CImageWriterPPM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CImageWriterPPM.h; sourceTree = ""; }; + 5E34C9A41B7F6B0900F212E8 /* CImageWriterPSD.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CImageWriterPSD.cpp; sourceTree = ""; }; + 5E34C9A51B7F6B0900F212E8 /* CImageWriterPSD.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CImageWriterPSD.h; sourceTree = ""; }; + 5E34C9A61B7F6B0900F212E8 /* CImageWriterTGA.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CImageWriterTGA.cpp; sourceTree = ""; }; + 5E34C9A71B7F6B0900F212E8 /* CImageWriterTGA.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CImageWriterTGA.h; sourceTree = ""; }; + 5E34C9A81B7F6B6800F212E8 /* CColorConverter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CColorConverter.cpp; sourceTree = ""; }; + 5E34C9A91B7F6B6800F212E8 /* CColorConverter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CColorConverter.h; sourceTree = ""; }; + 5E34C9AA1B7F6B6800F212E8 /* CFPSCounter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CFPSCounter.cpp; sourceTree = ""; }; + 5E34C9AB1B7F6B6800F212E8 /* CFPSCounter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CFPSCounter.h; sourceTree = ""; }; + 5E34C9AC1B7F6B6800F212E8 /* CImage.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CImage.cpp; sourceTree = ""; }; + 5E34C9AD1B7F6B6800F212E8 /* CImage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CImage.h; sourceTree = ""; }; + 5E34C9AE1B7F6B6800F212E8 /* CNullDriver.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CNullDriver.cpp; sourceTree = ""; }; + 5E34C9AF1B7F6B6800F212E8 /* CNullDriver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CNullDriver.h; sourceTree = ""; }; + 5E34C9B01B7F6B6800F212E8 /* IImagePresenter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IImagePresenter.h; sourceTree = ""; }; + 5E34C9B11B7F6BA700F212E8 /* COpenGLDriver.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = COpenGLDriver.cpp; sourceTree = ""; }; + 5E34C9B21B7F6BA700F212E8 /* COpenGLDriver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = COpenGLDriver.h; sourceTree = ""; }; + 5E34C9B31B7F6BA700F212E8 /* COpenGLExtensionHandler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = COpenGLExtensionHandler.cpp; sourceTree = ""; }; + 5E34C9B41B7F6BA700F212E8 /* COpenGLExtensionHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = COpenGLExtensionHandler.h; sourceTree = ""; }; + 5E34C9B51B7F6BA700F212E8 /* COpenGLMaterialRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = COpenGLMaterialRenderer.h; sourceTree = ""; }; + 5E34C9B61B7F6BA700F212E8 /* COpenGLNormalMapRenderer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = COpenGLNormalMapRenderer.cpp; sourceTree = ""; }; + 5E34C9B71B7F6BA700F212E8 /* COpenGLNormalMapRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = COpenGLNormalMapRenderer.h; sourceTree = ""; }; + 5E34C9B81B7F6BA700F212E8 /* COpenGLParallaxMapRenderer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = COpenGLParallaxMapRenderer.cpp; sourceTree = ""; }; + 5E34C9B91B7F6BA700F212E8 /* COpenGLParallaxMapRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = COpenGLParallaxMapRenderer.h; sourceTree = ""; }; + 5E34C9BA1B7F6BA700F212E8 /* COpenGLShaderMaterialRenderer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = COpenGLShaderMaterialRenderer.cpp; sourceTree = ""; }; + 5E34C9BB1B7F6BA700F212E8 /* COpenGLShaderMaterialRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = COpenGLShaderMaterialRenderer.h; sourceTree = ""; }; + 5E34C9BC1B7F6BA700F212E8 /* COpenGLSLMaterialRenderer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = COpenGLSLMaterialRenderer.cpp; sourceTree = ""; }; + 5E34C9BD1B7F6BA700F212E8 /* COpenGLSLMaterialRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = COpenGLSLMaterialRenderer.h; sourceTree = ""; }; + 5E34C9D71B7F6C6100F212E8 /* CSoftwareDriver.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSoftwareDriver.cpp; sourceTree = ""; }; + 5E34C9D81B7F6C6100F212E8 /* CSoftwareDriver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSoftwareDriver.h; sourceTree = ""; }; + 5E34C9D91B7F6C6100F212E8 /* CSoftwareTexture.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSoftwareTexture.cpp; sourceTree = ""; }; + 5E34C9DA1B7F6C6100F212E8 /* CSoftwareTexture.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSoftwareTexture.h; sourceTree = ""; }; + 5E34C9DB1B7F6C6100F212E8 /* CTRFlat.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRFlat.cpp; sourceTree = ""; }; + 5E34C9DC1B7F6C6100F212E8 /* CTRFlatWire.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRFlatWire.cpp; sourceTree = ""; }; + 5E34C9DD1B7F6C6100F212E8 /* CTRGouraud.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRGouraud.cpp; sourceTree = ""; }; + 5E34C9DE1B7F6C6100F212E8 /* CTRGouraudWire.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRGouraudWire.cpp; sourceTree = ""; }; + 5E34C9DF1B7F6C6100F212E8 /* CTRTextureFlat.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureFlat.cpp; sourceTree = ""; }; + 5E34C9E01B7F6C6100F212E8 /* CTRTextureFlatWire.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureFlatWire.cpp; sourceTree = ""; }; + 5E34C9E11B7F6C6100F212E8 /* CTRTextureGouraud.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureGouraud.cpp; sourceTree = ""; }; + 5E34C9E21B7F6C6100F212E8 /* CTRTextureGouraud.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CTRTextureGouraud.h; sourceTree = ""; }; + 5E34C9E31B7F6C6100F212E8 /* CTRTextureGouraudAdd.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureGouraudAdd.cpp; sourceTree = ""; }; + 5E34C9E41B7F6C6100F212E8 /* CTRTextureGouraudNoZ.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureGouraudNoZ.cpp; sourceTree = ""; }; + 5E34C9E51B7F6C6100F212E8 /* CTRTextureGouraudWire.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CTRTextureGouraudWire.cpp; sourceTree = ""; }; + 5E34C9E61B7F6C6100F212E8 /* CZBuffer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CZBuffer.cpp; sourceTree = ""; }; + 5E34C9E71B7F6C6100F212E8 /* CZBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CZBuffer.h; sourceTree = ""; }; + 5E34C9E81B7F6C6100F212E8 /* ITriangleRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ITriangleRenderer.h; sourceTree = ""; }; + 5E34C9E91B7F6C6100F212E8 /* IZBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IZBuffer.h; sourceTree = ""; }; + 5E34C9EA1B7F6C6100F212E8 /* S2DVertex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = S2DVertex.h; sourceTree = ""; }; + 5E34C9EB1B7F6C8200F212E8 /* CVideoModeList.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CVideoModeList.cpp; sourceTree = ""; }; + 5E34C9EC1B7F6C8200F212E8 /* CVideoModeList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CVideoModeList.h; sourceTree = ""; }; + 5E34C9ED1B7F6CCC00F212E8 /* CNSOGLManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CNSOGLManager.h; sourceTree = ""; }; + 5E34C9EE1B7F6CCC00F212E8 /* CNSOGLManager.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CNSOGLManager.mm; sourceTree = ""; }; + 5E34C9F31B7F6E3400F212E8 /* libIrrlicht.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libIrrlicht.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E5733E51C18E212003F664E /* libIrrlicht.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libIrrlicht.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E5733E61C18E254003F664E /* CIrrDeviceiOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CIrrDeviceiOS.h; sourceTree = ""; }; + 5E5733E71C18E254003F664E /* CIrrDeviceiOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CIrrDeviceiOS.mm; sourceTree = ""; }; + 5E5733EC1C18E2C0003F664E /* COGLESCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COGLESCommon.h; sourceTree = ""; }; + 5E5733ED1C18E2C0003F664E /* COGLESDriver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = COGLESDriver.cpp; sourceTree = ""; }; + 5E5733EE1C18E2C0003F664E /* COGLESDriver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COGLESDriver.h; sourceTree = ""; }; + 5E5733EF1C18E2C0003F664E /* COGLESExtensionHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = COGLESExtensionHandler.cpp; sourceTree = ""; }; + 5E5733F01C18E2C0003F664E /* COGLESExtensionHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COGLESExtensionHandler.h; sourceTree = ""; }; + 5E5733F11C18E2C0003F664E /* COGLESMaterialRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COGLESMaterialRenderer.h; sourceTree = ""; }; + 5E5733F81C18E2E2003F664E /* COGLES2Common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COGLES2Common.h; sourceTree = ""; }; + 5E5733F91C18E2E2003F664E /* COGLES2Driver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = COGLES2Driver.cpp; sourceTree = ""; }; + 5E5733FA1C18E2E2003F664E /* COGLES2Driver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COGLES2Driver.h; sourceTree = ""; }; + 5E5733FB1C18E2E2003F664E /* COGLES2ExtensionHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = COGLES2ExtensionHandler.cpp; sourceTree = ""; }; + 5E5733FC1C18E2E2003F664E /* COGLES2ExtensionHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COGLES2ExtensionHandler.h; sourceTree = ""; }; + 5E5733FD1C18E2E2003F664E /* COGLES2FixedPipelineRenderer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = COGLES2FixedPipelineRenderer.cpp; sourceTree = ""; }; + 5E5733FE1C18E2E2003F664E /* COGLES2FixedPipelineRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COGLES2FixedPipelineRenderer.h; sourceTree = ""; }; + 5E5733FF1C18E2E2003F664E /* COGLES2MaterialRenderer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = COGLES2MaterialRenderer.cpp; sourceTree = ""; }; + 5E5734001C18E2E2003F664E /* COGLES2MaterialRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COGLES2MaterialRenderer.h; sourceTree = ""; }; + 5E5734011C18E2E2003F664E /* COGLES2NormalMapRenderer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = COGLES2NormalMapRenderer.cpp; sourceTree = ""; }; + 5E5734021C18E2E2003F664E /* COGLES2NormalMapRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COGLES2NormalMapRenderer.h; sourceTree = ""; }; + 5E5734031C18E2E2003F664E /* COGLES2ParallaxMapRenderer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = COGLES2ParallaxMapRenderer.cpp; sourceTree = ""; }; + 5E5734041C18E2E2003F664E /* COGLES2ParallaxMapRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COGLES2ParallaxMapRenderer.h; sourceTree = ""; }; + 5E5734051C18E2E2003F664E /* COGLES2Renderer2D.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = COGLES2Renderer2D.cpp; sourceTree = ""; }; + 5E5734061C18E2E2003F664E /* COGLES2Renderer2D.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COGLES2Renderer2D.h; sourceTree = ""; }; + 5E79088A1C10EC6C00DFE7FE /* IRenderTarget.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IRenderTarget.h; path = ../../include/IRenderTarget.h; sourceTree = ""; }; + 5E79088D1C10EE6700DFE7FE /* COpenGLCoreCacheHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = COpenGLCoreCacheHandler.h; sourceTree = ""; }; + 5E79088E1C10EE6700DFE7FE /* COpenGLCoreFeature.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = COpenGLCoreFeature.h; sourceTree = ""; }; + 5E79088F1C10EE6700DFE7FE /* COpenGLCoreRenderTarget.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = COpenGLCoreRenderTarget.h; sourceTree = ""; }; + 5E7908901C10EE6700DFE7FE /* COpenGLCoreTexture.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = COpenGLCoreTexture.h; sourceTree = ""; }; + 5E7908911C10EEC000DFE7FE /* COpenGLCacheHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = COpenGLCacheHandler.cpp; sourceTree = ""; }; + 5E7908921C10EEC000DFE7FE /* COpenGLCacheHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COpenGLCacheHandler.h; sourceTree = ""; }; + 5E7908931C10EEC000DFE7FE /* COpenGLCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COpenGLCommon.h; sourceTree = ""; }; + 5E7908981C10FE4A00DFE7FE /* CB3DMeshWriter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CB3DMeshWriter.cpp; sourceTree = ""; }; + 5E7908991C10FE4A00DFE7FE /* CB3DMeshWriter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CB3DMeshWriter.h; sourceTree = ""; }; + 5E8570BA1B7F9AC400B267D2 /* CIrrDeviceConsole.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CIrrDeviceConsole.cpp; sourceTree = ""; }; + 5E8570BB1B7F9AC400B267D2 /* CIrrDeviceConsole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CIrrDeviceConsole.h; sourceTree = ""; }; + 5E9573D11C18E70000C27989 /* EVertexAttributes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EVertexAttributes.h; path = ../../include/EVertexAttributes.h; sourceTree = ""; }; + 5E9573D31C18E9B300C27989 /* CEAGLManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CEAGLManager.h; sourceTree = ""; }; + 5E9573D61C18E9E600C27989 /* CEAGLManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CEAGLManager.mm; sourceTree = ""; }; + 5EC24F5E1B8B861200DCA615 /* exampleHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = exampleHelper.h; path = ../../include/exampleHelper.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E34C9F01B7F6E3400F212E8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5E5733DD1C18E212003F664E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E34C6D81B7F4A0C00F212E8 = { + isa = PBXGroup; + children = ( + 5E34C6DF1B7F4AB500F212E8 /* include */, + 5E34C6E01B7F4ABD00F212E8 /* Irrlicht */, + 5E34C9F41B7F6E3400F212E8 /* Products */, + ); + sourceTree = ""; + }; + 5E34C6DF1B7F4AB500F212E8 /* include */ = { + isa = PBXGroup; + children = ( + 5E34C79F1B7F4B9400F212E8 /* core */, + 5E34C7A31B7F4C2100F212E8 /* gui */, + 5E34C7A11B7F4BF000F212E8 /* io */, + 5E34C7A01B7F4BC900F212E8 /* scene */, + 5E34C7A21B7F4C1900F212E8 /* video */, + 5E34C6E91B7F4AFB00F212E8 /* driverChoice.h */, + 5EC24F5E1B8B861200DCA615 /* exampleHelper.h */, + 5E34C6ED1B7F4AFB00F212E8 /* EDeviceTypes.h */, + 5E34C70F1B7F4AFC00F212E8 /* IEventReceiver.h */, + 5E34C7371B7F4AFC00F212E8 /* ILogger.h */, + 5E34C7431B7F4AFC00F212E8 /* IOSOperator.h */, + 5E34C7511B7F4AFC00F212E8 /* IProfiler.h */, + 5E34C7541B7F4AFC00F212E8 /* IRandomizer.h */, + 5E34C7561B7F4AFC00F212E8 /* IReferenceCounted.h */, + 5E34C7591B7F4AFC00F212E8 /* IrrCompileConfig.h */, + 5E34C75A1B7F4AFC00F212E8 /* irrlicht.h */, + 5E34C75B1B7F4AFC00F212E8 /* IrrlichtDevice.h */, + 5E34C75F1B7F4AFC00F212E8 /* irrpack.h */, + 5E34C7611B7F4AFC00F212E8 /* irrTypes.h */, + 5E34C7621B7F4AFC00F212E8 /* irrunpack.h */, + 5E34C7751B7F4AFC00F212E8 /* ITimer.h */, + 5E34C77E1B7F4AFC00F212E8 /* Keycodes.h */, + 5E34C77F1B7F4AFC00F212E8 /* leakHunter.h */, + 5E34C78D1B7F4AFC00F212E8 /* SIrrCreationParameters.h */, + 5E34C78E1B7F4AFC00F212E8 /* SKeyMap.h */, + ); + name = include; + sourceTree = ""; + }; + 5E34C6E01B7F4ABD00F212E8 /* Irrlicht */ = { + isa = PBXGroup; + children = ( + 5E34C7A41B7F503A00F212E8 /* gui */, + 5E34C7A51B7F504400F212E8 /* io */, + 5E34C7A81B7F506D00F212E8 /* irr */, + 5E34C7A61B7F505A00F212E8 /* scene */, + 5E34C7A71B7F506300F212E8 /* video */, + 5E34C9EB1B7F6C8200F212E8 /* CVideoModeList.cpp */, + 5E34C9EC1B7F6C8200F212E8 /* CVideoModeList.h */, + ); + name = Irrlicht; + sourceTree = ""; + }; + 5E34C79F1B7F4B9400F212E8 /* core */ = { + isa = PBXGroup; + children = ( + 5E34C6E21B7F4AFB00F212E8 /* aabbox3d.h */, + 5E34C6E61B7F4AFB00F212E8 /* coreutil.h */, + 5E34C6E81B7F4AFB00F212E8 /* dimension2d.h */, + 5E34C6FE1B7F4AFC00F212E8 /* fast_atof.h */, + 5E34C6FF1B7F4AFC00F212E8 /* heapsort.h */, + 5E34C7571B7F4AFC00F212E8 /* irrAllocator.h */, + 5E34C7581B7F4AFC00F212E8 /* irrArray.h */, + 5E34C75C1B7F4AFC00F212E8 /* irrList.h */, + 5E34C75D1B7F4AFC00F212E8 /* irrMap.h */, + 5E34C75E1B7F4AFC00F212E8 /* irrMath.h */, + 5E34C7601B7F4AFC00F212E8 /* irrString.h */, + 5E34C7801B7F4AFC00F212E8 /* line2d.h */, + 5E34C7811B7F4AFC00F212E8 /* line3d.h */, + 5E34C7821B7F4AFC00F212E8 /* matrix4.h */, + 5E34C7841B7F4AFC00F212E8 /* plane3d.h */, + 5E34C7851B7F4AFC00F212E8 /* position2d.h */, + 5E34C7861B7F4AFC00F212E8 /* quaternion.h */, + 5E34C7871B7F4AFC00F212E8 /* rect.h */, + 5E34C79C1B7F4AFC00F212E8 /* triangle3d.h */, + 5E34C79D1B7F4AFC00F212E8 /* vector2d.h */, + 5E34C79E1B7F4AFC00F212E8 /* vector3d.h */, + ); + name = core; + sourceTree = ""; + }; + 5E34C7A01B7F4BC900F212E8 /* scene */ = { + isa = PBXGroup; + children = ( + 5E34C6E31B7F4AFB00F212E8 /* CDynamicMeshBuffer.h */, + 5E34C6E41B7F4AFB00F212E8 /* CIndexBuffer.h */, + 5E34C6E51B7F4AFB00F212E8 /* CMeshBuffer.h */, + 5E34C6E71B7F4AFB00F212E8 /* CVertexBuffer.h */, + 5E34C6EB1B7F4AFB00F212E8 /* ECullingTypes.h */, + 5E34C6EC1B7F4AFB00F212E8 /* EDebugSceneTypes.h */, + 5E34C6F31B7F4AFB00F212E8 /* EHardwareBufferFlags.h */, + 5E34C6F61B7F4AFB00F212E8 /* EMeshWriterEnums.h */, + 5E34C6F81B7F4AFB00F212E8 /* EPrimitiveTypes.h */, + 5E34C6F91B7F4AFB00F212E8 /* ESceneNodeAnimatorTypes.h */, + 5E34C6FA1B7F4AFC00F212E8 /* ESceneNodeTypes.h */, + 5E34C6FC1B7F4AFC00F212E8 /* ETerrainElements.h */, + 5E34C7001B7F4AFC00F212E8 /* IAnimatedMesh.h */, + 5E34C7011B7F4AFC00F212E8 /* IAnimatedMeshMD2.h */, + 5E34C7021B7F4AFC00F212E8 /* IAnimatedMeshMD3.h */, + 5E34C7031B7F4AFC00F212E8 /* IAnimatedMeshSceneNode.h */, + 5E34C7061B7F4AFC00F212E8 /* IBillboardSceneNode.h */, + 5E34C7071B7F4AFC00F212E8 /* IBillboardTextSceneNode.h */, + 5E34C7081B7F4AFC00F212E8 /* IBoneSceneNode.h */, + 5E34C7091B7F4AFC00F212E8 /* ICameraSceneNode.h */, + 5E34C70A1B7F4AFC00F212E8 /* IColladaMeshWriter.h */, + 5E34C70D1B7F4AFC00F212E8 /* IDummyTransformationSceneNode.h */, + 5E34C70E1B7F4AFC00F212E8 /* IDynamicMeshBuffer.h */, + 5E34C7131B7F4AFC00F212E8 /* IGeometryCreator.h */, + 5E34C7341B7F4AFC00F212E8 /* IIndexBuffer.h */, + 5E34C7351B7F4AFC00F212E8 /* ILightManager.h */, + 5E34C7361B7F4AFC00F212E8 /* ILightSceneNode.h */, + 5E34C73A1B7F4AFC00F212E8 /* IMesh.h */, + 5E34C73B1B7F4AFC00F212E8 /* IMeshBuffer.h */, + 5E34C73C1B7F4AFC00F212E8 /* IMeshCache.h */, + 5E34C73D1B7F4AFC00F212E8 /* IMeshLoader.h */, + 5E34C73E1B7F4AFC00F212E8 /* IMeshManipulator.h */, + 5E34C73F1B7F4AFC00F212E8 /* IMeshSceneNode.h */, + 5E34C7401B7F4AFC00F212E8 /* IMeshTextureLoader.h */, + 5E34C7411B7F4AFC00F212E8 /* IMeshWriter.h */, + 5E34C7421B7F4AFC00F212E8 /* IMetaTriangleSelector.h */, + 5E34C7441B7F4AFC00F212E8 /* IParticleAffector.h */, + 5E34C7451B7F4AFC00F212E8 /* IParticleAnimatedMeshSceneNodeEmitter.h */, + 5E34C7461B7F4AFC00F212E8 /* IParticleAttractionAffector.h */, + 5E34C7471B7F4AFC00F212E8 /* IParticleBoxEmitter.h */, + 5E34C7481B7F4AFC00F212E8 /* IParticleCylinderEmitter.h */, + 5E34C7491B7F4AFC00F212E8 /* IParticleEmitter.h */, + 5E34C74A1B7F4AFC00F212E8 /* IParticleFadeOutAffector.h */, + 5E34C74B1B7F4AFC00F212E8 /* IParticleGravityAffector.h */, + 5E34C74C1B7F4AFC00F212E8 /* IParticleMeshEmitter.h */, + 5E34C74D1B7F4AFC00F212E8 /* IParticleRingEmitter.h */, + 5E34C74E1B7F4AFC00F212E8 /* IParticleRotationAffector.h */, + 5E34C74F1B7F4AFC00F212E8 /* IParticleSphereEmitter.h */, + 5E34C7501B7F4AFC00F212E8 /* IParticleSystemSceneNode.h */, + 5E34C7521B7F4AFC00F212E8 /* IQ3LevelMesh.h */, + 5E34C7531B7F4AFC00F212E8 /* IQ3Shader.h */, + 5E34C7641B7F4AFC00F212E8 /* ISceneCollisionManager.h */, + 5E34C7651B7F4AFC00F212E8 /* ISceneLoader.h */, + 5E34C7661B7F4AFC00F212E8 /* ISceneManager.h */, + 5E34C7671B7F4AFC00F212E8 /* ISceneNode.h */, + 5E34C7681B7F4AFC00F212E8 /* ISceneNodeAnimator.h */, + 5E34C7691B7F4AFC00F212E8 /* ISceneNodeAnimatorCameraFPS.h */, + 5E34C76A1B7F4AFC00F212E8 /* ISceneNodeAnimatorCameraMaya.h */, + 5E34C76B1B7F4AFC00F212E8 /* ISceneNodeAnimatorCollisionResponse.h */, + 5E34C76C1B7F4AFC00F212E8 /* ISceneNodeAnimatorFactory.h */, + 5E34C76D1B7F4AFC00F212E8 /* ISceneNodeFactory.h */, + 5E34C76E1B7F4AFC00F212E8 /* ISceneUserDataSerializer.h */, + 5E34C7701B7F4AFC00F212E8 /* IShadowVolumeSceneNode.h */, + 5E34C7711B7F4AFC00F212E8 /* ISkinnedMesh.h */, + 5E34C7721B7F4AFC00F212E8 /* ITerrainSceneNode.h */, + 5E34C7731B7F4AFC00F212E8 /* ITextSceneNode.h */, + 5E34C7761B7F4AFC00F212E8 /* ITriangleSelector.h */, + 5E34C7771B7F4AFC00F212E8 /* IVertexBuffer.h */, + 5E34C77A1B7F4AFC00F212E8 /* IVolumeLightSceneNode.h */, + 5E34C7891B7F4AFC00F212E8 /* SAnimatedMesh.h */, + 5E34C78A1B7F4AFC00F212E8 /* SceneParameters.h */, + 5E34C7921B7F4AFC00F212E8 /* SMesh.h */, + 5E34C7931B7F4AFC00F212E8 /* SMeshBuffer.h */, + 5E34C7941B7F4AFC00F212E8 /* SMeshBufferLightMap.h */, + 5E34C7951B7F4AFC00F212E8 /* SMeshBufferTangents.h */, + 5E34C7961B7F4AFC00F212E8 /* SParticle.h */, + 5E34C7971B7F4AFC00F212E8 /* SSharedMeshBuffer.h */, + 5E34C7981B7F4AFC00F212E8 /* SSkinMeshBuffer.h */, + 5E34C79A1B7F4AFC00F212E8 /* SVertexManipulator.h */, + 5E34C79B1B7F4AFC00F212E8 /* SViewFrustum.h */, + ); + name = scene; + sourceTree = ""; + }; + 5E34C7A11B7F4BF000F212E8 /* io */ = { + isa = PBXGroup; + children = ( + 5E34C6EA1B7F4AFB00F212E8 /* EAttributes.h */, + 5E34C7041B7F4AFC00F212E8 /* IAttributeExchangingObject.h */, + 5E34C7051B7F4AFC00F212E8 /* IAttributes.h */, + 5E34C7101B7F4AFC00F212E8 /* IFileArchive.h */, + 5E34C7111B7F4AFC00F212E8 /* IFileList.h */, + 5E34C7121B7F4AFC00F212E8 /* IFileSystem.h */, + 5E34C7551B7F4AFC00F212E8 /* IReadFile.h */, + 5E34C7631B7F4AFC00F212E8 /* irrXML.h */, + 5E34C77B1B7F4AFC00F212E8 /* IWriteFile.h */, + 5E34C77C1B7F4AFC00F212E8 /* IXMLReader.h */, + 5E34C77D1B7F4AFC00F212E8 /* IXMLWriter.h */, + 5E34C7831B7F4AFC00F212E8 /* path.h */, + ); + name = io; + sourceTree = ""; + }; + 5E34C7A21B7F4C1900F212E8 /* video */ = { + isa = PBXGroup; + children = ( + 5E34C6EE1B7F4AFB00F212E8 /* EDriverFeatures.h */, + 5E34C6EF1B7F4AFB00F212E8 /* EDriverTypes.h */, + 5E34C6F41B7F4AFB00F212E8 /* EMaterialFlags.h */, + 5E34C6F51B7F4AFB00F212E8 /* EMaterialTypes.h */, + 5E34C6FB1B7F4AFC00F212E8 /* EShaderTypes.h */, + 5E9573D11C18E70000C27989 /* EVertexAttributes.h */, + 5E34C70B1B7F4AFC00F212E8 /* IContextManager.h */, + 5E34C7141B7F4AFC00F212E8 /* IGPUProgrammingServices.h */, + 5E34C7311B7F4AFC00F212E8 /* IImage.h */, + 5E34C7321B7F4AFC00F212E8 /* IImageLoader.h */, + 5E34C7331B7F4AFC00F212E8 /* IImageWriter.h */, + 5E34C7381B7F4AFC00F212E8 /* IMaterialRenderer.h */, + 5E34C7391B7F4AFC00F212E8 /* IMaterialRendererServices.h */, + 5E79088A1C10EC6C00DFE7FE /* IRenderTarget.h */, + 5E34C76F1B7F4AFC00F212E8 /* IShaderConstantSetCallBack.h */, + 5E34C7741B7F4AFC00F212E8 /* ITexture.h */, + 5E34C7781B7F4AFC00F212E8 /* IVideoDriver.h */, + 5E34C7791B7F4AFC00F212E8 /* IVideoModeList.h */, + 5E34C7881B7F4AFC00F212E8 /* S3DVertex.h */, + 5E34C78B1B7F4AFC00F212E8 /* SColor.h */, + 5E34C78C1B7F4AFC00F212E8 /* SExposedVideoData.h */, + 5E34C78F1B7F4AFC00F212E8 /* SLight.h */, + 5E34C7901B7F4AFC00F212E8 /* SMaterial.h */, + 5E34C7911B7F4AFC00F212E8 /* SMaterialLayer.h */, + 5E34C7991B7F4AFC00F212E8 /* SVertexIndex.h */, + ); + name = video; + sourceTree = ""; + }; + 5E34C7A31B7F4C2100F212E8 /* gui */ = { + isa = PBXGroup; + children = ( + 5E34C6F01B7F4AFB00F212E8 /* EFocusFlags.h */, + 5E34C6F11B7F4AFB00F212E8 /* EGUIAlignment.h */, + 5E34C6F21B7F4AFB00F212E8 /* EGUIElementTypes.h */, + 5E34C6F71B7F4AFB00F212E8 /* EMessageBoxFlags.h */, + 5E34C70C1B7F4AFC00F212E8 /* ICursorControl.h */, + 5E34C7151B7F4AFC00F212E8 /* IGUIButton.h */, + 5E34C7161B7F4AFC00F212E8 /* IGUICheckBox.h */, + 5E34C7171B7F4AFC00F212E8 /* IGUIColorSelectDialog.h */, + 5E34C7181B7F4AFC00F212E8 /* IGUIComboBox.h */, + 5E34C7191B7F4AFC00F212E8 /* IGUIContextMenu.h */, + 5E34C71A1B7F4AFC00F212E8 /* IGUIEditBox.h */, + 5E34C71B1B7F4AFC00F212E8 /* IGUIElement.h */, + 5E34C71C1B7F4AFC00F212E8 /* IGUIElementFactory.h */, + 5E34C71D1B7F4AFC00F212E8 /* IGUIEnvironment.h */, + 5E34C71E1B7F4AFC00F212E8 /* IGUIFileOpenDialog.h */, + 5E34C71F1B7F4AFC00F212E8 /* IGUIFont.h */, + 5E34C7201B7F4AFC00F212E8 /* IGUIFontBitmap.h */, + 5E34C7211B7F4AFC00F212E8 /* IGUIImage.h */, + 5E34C7221B7F4AFC00F212E8 /* IGUIImageList.h */, + 5E34C7231B7F4AFC00F212E8 /* IGUIInOutFader.h */, + 5E34C7241B7F4AFC00F212E8 /* IGUIListBox.h */, + 5E34C7251B7F4AFC00F212E8 /* IGUIMeshViewer.h */, + 5E34C7261B7F4AFC00F212E8 /* IGUIProfiler.h */, + 5E34C7271B7F4AFC00F212E8 /* IGUIScrollBar.h */, + 5E34C7281B7F4AFC00F212E8 /* IGUISkin.h */, + 5E34C7291B7F4AFC00F212E8 /* IGUISpinBox.h */, + 5E34C72A1B7F4AFC00F212E8 /* IGUISpriteBank.h */, + 5E34C72B1B7F4AFC00F212E8 /* IGUIStaticText.h */, + 5E34C72C1B7F4AFC00F212E8 /* IGUITabControl.h */, + 5E34C72D1B7F4AFC00F212E8 /* IGUITable.h */, + 5E34C72E1B7F4AFC00F212E8 /* IGUIToolbar.h */, + 5E34C72F1B7F4AFC00F212E8 /* IGUITreeView.h */, + 5E34C7301B7F4AFC00F212E8 /* IGUIWindow.h */, + ); + name = gui; + sourceTree = ""; + }; + 5E34C7A41B7F503A00F212E8 /* gui */ = { + isa = PBXGroup; + children = ( + 5E34C7E11B7F50DE00F212E8 /* BuiltInFont.h */, + 5E34C7E21B7F50DE00F212E8 /* CDefaultGUIElementFactory.cpp */, + 5E34C7E31B7F50DE00F212E8 /* CDefaultGUIElementFactory.h */, + 5E34C7A91B7F50A900F212E8 /* CGUIButton.cpp */, + 5E34C7AA1B7F50A900F212E8 /* CGUIButton.h */, + 5E34C7AB1B7F50A900F212E8 /* CGUICheckBox.cpp */, + 5E34C7AC1B7F50A900F212E8 /* CGUICheckBox.h */, + 5E34C7AD1B7F50A900F212E8 /* CGUIColorSelectDialog.cpp */, + 5E34C7AE1B7F50A900F212E8 /* CGUIColorSelectDialog.h */, + 5E34C7AF1B7F50A900F212E8 /* CGUIComboBox.cpp */, + 5E34C7B01B7F50A900F212E8 /* CGUIComboBox.h */, + 5E34C7B11B7F50A900F212E8 /* CGUIContextMenu.cpp */, + 5E34C7B21B7F50A900F212E8 /* CGUIContextMenu.h */, + 5E34C7B31B7F50A900F212E8 /* CGUIEditBox.cpp */, + 5E34C7B41B7F50A900F212E8 /* CGUIEditBox.h */, + 5E34C7B51B7F50A900F212E8 /* CGUIEnvironment.cpp */, + 5E34C7B61B7F50A900F212E8 /* CGUIEnvironment.h */, + 5E34C7B71B7F50A900F212E8 /* CGUIFileOpenDialog.cpp */, + 5E34C7B81B7F50A900F212E8 /* CGUIFileOpenDialog.h */, + 5E34C7B91B7F50A900F212E8 /* CGUIFont.cpp */, + 5E34C7BA1B7F50A900F212E8 /* CGUIFont.h */, + 5E34C7BB1B7F50A900F212E8 /* CGUIImage.cpp */, + 5E34C7BC1B7F50A900F212E8 /* CGUIImage.h */, + 5E34C7BD1B7F50A900F212E8 /* CGUIImageList.cpp */, + 5E34C7BE1B7F50A900F212E8 /* CGUIImageList.h */, + 5E34C7BF1B7F50A900F212E8 /* CGUIInOutFader.cpp */, + 5E34C7C01B7F50A900F212E8 /* CGUIInOutFader.h */, + 5E34C7C11B7F50A900F212E8 /* CGUIListBox.cpp */, + 5E34C7C21B7F50A900F212E8 /* CGUIListBox.h */, + 5E34C7C31B7F50A900F212E8 /* CGUIMenu.cpp */, + 5E34C7C41B7F50A900F212E8 /* CGUIMenu.h */, + 5E34C7C51B7F50A900F212E8 /* CGUIMeshViewer.cpp */, + 5E34C7C61B7F50A900F212E8 /* CGUIMeshViewer.h */, + 5E34C7C71B7F50A900F212E8 /* CGUIMessageBox.cpp */, + 5E34C7C81B7F50A900F212E8 /* CGUIMessageBox.h */, + 5E34C7C91B7F50A900F212E8 /* CGUIModalScreen.cpp */, + 5E34C7CA1B7F50A900F212E8 /* CGUIModalScreen.h */, + 5E34C7CB1B7F50A900F212E8 /* CGUIProfiler.cpp */, + 5E34C7CC1B7F50A900F212E8 /* CGUIProfiler.h */, + 5E34C7CD1B7F50A900F212E8 /* CGUIScrollBar.cpp */, + 5E34C7CE1B7F50A900F212E8 /* CGUIScrollBar.h */, + 5E34C7CF1B7F50A900F212E8 /* CGUISkin.cpp */, + 5E34C7D01B7F50A900F212E8 /* CGUISkin.h */, + 5E34C7D11B7F50A900F212E8 /* CGUISpinBox.cpp */, + 5E34C7D21B7F50A900F212E8 /* CGUISpinBox.h */, + 5E34C7D31B7F50A900F212E8 /* CGUISpriteBank.cpp */, + 5E34C7D41B7F50A900F212E8 /* CGUISpriteBank.h */, + 5E34C7D51B7F50A900F212E8 /* CGUIStaticText.cpp */, + 5E34C7D61B7F50A900F212E8 /* CGUIStaticText.h */, + 5E34C7D71B7F50A900F212E8 /* CGUITabControl.cpp */, + 5E34C7D81B7F50A900F212E8 /* CGUITabControl.h */, + 5E34C7D91B7F50A900F212E8 /* CGUITable.cpp */, + 5E34C7DA1B7F50A900F212E8 /* CGUITable.h */, + 5E34C7DB1B7F50A900F212E8 /* CGUIToolBar.cpp */, + 5E34C7DC1B7F50A900F212E8 /* CGUIToolBar.h */, + 5E34C7DD1B7F50A900F212E8 /* CGUITreeView.cpp */, + 5E34C7DE1B7F50A900F212E8 /* CGUITreeView.h */, + 5E34C7DF1B7F50A900F212E8 /* CGUIWindow.cpp */, + 5E34C7E01B7F50A900F212E8 /* CGUIWindow.h */, + ); + name = gui; + sourceTree = ""; + }; + 5E34C7A51B7F504400F212E8 /* io */ = { + isa = PBXGroup; + children = ( + 5E34C7E41B7F517000F212E8 /* CAttributeImpl.h */, + 5E34C7E51B7F517000F212E8 /* CAttributes.cpp */, + 5E34C7E61B7F517000F212E8 /* CAttributes.h */, + 5E34C7E71B7F517000F212E8 /* CFileList.cpp */, + 5E34C7E81B7F517000F212E8 /* CFileList.h */, + 5E34C7E91B7F517000F212E8 /* CFileSystem.cpp */, + 5E34C7EA1B7F517000F212E8 /* CFileSystem.h */, + 5E34C7EB1B7F517000F212E8 /* CLimitReadFile.cpp */, + 5E34C7EC1B7F517000F212E8 /* CLimitReadFile.h */, + 5E34C7ED1B7F517000F212E8 /* CMemoryFile.cpp */, + 5E34C7EE1B7F517000F212E8 /* CMemoryFile.h */, + 5E34C7EF1B7F517000F212E8 /* CMountPointReader.cpp */, + 5E34C7F01B7F517000F212E8 /* CMountPointReader.h */, + 5E34C7F11B7F517000F212E8 /* CNPKReader.cpp */, + 5E34C7F21B7F517000F212E8 /* CNPKReader.h */, + 5E34C7F31B7F517000F212E8 /* CPakReader.cpp */, + 5E34C7F41B7F517000F212E8 /* CPakReader.h */, + 5E34C7F51B7F51D900F212E8 /* CReadFile.cpp */, + 5E34C7F61B7F51D900F212E8 /* CReadFile.h */, + 5E34C7F71B7F51D900F212E8 /* CTarReader.cpp */, + 5E34C7F81B7F51D900F212E8 /* CTarReader.h */, + 5E34C7F91B7F51D900F212E8 /* CWADReader.cpp */, + 5E34C7FA1B7F51D900F212E8 /* CWADReader.h */, + 5E34C7FB1B7F51D900F212E8 /* CWriteFile.cpp */, + 5E34C7FC1B7F51D900F212E8 /* CWriteFile.h */, + 5E34C7FD1B7F51D900F212E8 /* CXMLReader.cpp */, + 5E34C7FE1B7F51D900F212E8 /* CXMLReader.h */, + 5E34C7FF1B7F51D900F212E8 /* CXMLReaderImpl.h */, + 5E34C8001B7F51D900F212E8 /* CXMLWriter.cpp */, + 5E34C8011B7F51D900F212E8 /* CXMLWriter.h */, + 5E34C8021B7F51D900F212E8 /* CZipReader.cpp */, + 5E34C8031B7F51D900F212E8 /* CZipReader.h */, + 5E34C8041B7F51D900F212E8 /* IAttribute.h */, + 5E34C8051B7F51D900F212E8 /* irrXML.cpp */, + ); + name = io; + sourceTree = ""; + }; + 5E34C7A61B7F505A00F212E8 /* scene */ = { + isa = PBXGroup; + children = ( + 5E34C89F1B7F655200F212E8 /* animators */, + 5E34C8A01B7F655A00F212E8 /* collision */, + 5E34C8A11B7F656300F212E8 /* loaders */, + 5E34C8A21B7F656C00F212E8 /* particleSystem */, + 5E34C8A31B7F657A00F212E8 /* sceneNodes */, + 5E34C8A41B7F658300F212E8 /* writers */, + 5E34C8AD1B7F664100F212E8 /* CDefaultSceneNodeAnimatorFactory.cpp */, + 5E34C8AE1B7F664100F212E8 /* CDefaultSceneNodeAnimatorFactory.h */, + 5E34C8AF1B7F664100F212E8 /* CDefaultSceneNodeFactory.cpp */, + 5E34C8B01B7F664100F212E8 /* CDefaultSceneNodeFactory.h */, + 5E34C8B11B7F664100F212E8 /* CGeometryCreator.cpp */, + 5E34C8B21B7F664100F212E8 /* CGeometryCreator.h */, + 5E34C8B31B7F664100F212E8 /* CMeshCache.cpp */, + 5E34C8B41B7F664100F212E8 /* CMeshCache.h */, + 5E34C8B51B7F664100F212E8 /* CMeshManipulator.cpp */, + 5E34C8B61B7F664100F212E8 /* CMeshManipulator.h */, + 5E34C8B71B7F664100F212E8 /* CSceneManager.cpp */, + 5E34C8B81B7F664100F212E8 /* CSceneManager.h */, + 5E34C8B91B7F664100F212E8 /* Octree.h */, + ); + name = scene; + sourceTree = ""; + }; + 5E34C7A71B7F506300F212E8 /* video */ = { + isa = PBXGroup; + children = ( + 5E34C95A1B7F692C00F212E8 /* Burning Video */, + 5E34C95B1B7F693800F212E8 /* Null */, + 5E34C95C1B7F694500F212E8 /* OpenGL */, + 5E79088C1C10EDF000DFE7FE /* OpenGL Context */, + 5E5733EA1C18E27E003F664E /* OpenGL ES1.x */, + 5E5733EB1C18E29B003F664E /* OpenGL ES2.x */, + 5E79088B1C10ED5000DFE7FE /* OpenGL Core */, + 5E34C95F1B7F697B00F212E8 /* Software */, + ); + name = video; + sourceTree = ""; + }; + 5E34C7A81B7F506D00F212E8 /* irr */ = { + isa = PBXGroup; + children = ( + 5E34C8061B7F51F100F212E8 /* device */, + 5E34C8071B7F520000F212E8 /* extern */, + 5E34C8921B7F652600F212E8 /* CLogger.cpp */, + 5E34C8931B7F652600F212E8 /* CLogger.h */, + 5E34C8941B7F652600F212E8 /* COSOperator.cpp */, + 5E34C8951B7F652600F212E8 /* COSOperator.h */, + 5E34C8961B7F652600F212E8 /* CProfiler.cpp */, + 5E34C8971B7F652600F212E8 /* CProfiler.h */, + 5E34C8981B7F652600F212E8 /* CTimer.h */, + 5E34C8991B7F652600F212E8 /* EProfileIDs.h */, + 5E34C89A1B7F652600F212E8 /* Irrlicht.cpp */, + 5E34C89B1B7F652600F212E8 /* leakHunter.cpp */, + 5E34C89C1B7F652600F212E8 /* os.cpp */, + 5E34C89D1B7F652600F212E8 /* os.h */, + 5E34C89E1B7F652600F212E8 /* utf8.cpp */, + ); + name = irr; + sourceTree = ""; + }; + 5E34C8061B7F51F100F212E8 /* device */ = { + isa = PBXGroup; + children = ( + 5E8570BA1B7F9AC400B267D2 /* CIrrDeviceConsole.cpp */, + 5E8570BB1B7F9AC400B267D2 /* CIrrDeviceConsole.h */, + 5E5733E61C18E254003F664E /* CIrrDeviceiOS.h */, + 5E5733E71C18E254003F664E /* CIrrDeviceiOS.mm */, + 5E34C8131B7F535C00F212E8 /* CIrrDeviceOSX.h */, + 5E34C8141B7F535C00F212E8 /* CIrrDeviceOSX.mm */, + 5E34C80D1B7F52AC00F212E8 /* CIrrDeviceStub.cpp */, + 5E34C80E1B7F52AC00F212E8 /* CIrrDeviceStub.h */, + ); + name = device; + sourceTree = ""; + }; + 5E34C8071B7F520000F212E8 /* extern */ = { + isa = PBXGroup; + children = ( + 5E34C8081B7F521A00F212E8 /* aesGladman */, + 5E34C8091B7F522700F212E8 /* bzip2 */, + 5E34C80A1B7F522E00F212E8 /* jpeglib */, + 5E34C80B1B7F523B00F212E8 /* libpng */, + 5E34C88E1B7F579B00F212E8 /* lzma */, + 5E34C80C1B7F524400F212E8 /* zlib */, + ); + name = extern; + sourceTree = ""; + }; + 5E34C8081B7F521A00F212E8 /* aesGladman */ = { + isa = PBXGroup; + children = ( + 5E34C8151B7F540B00F212E8 /* aes.h */, + 5E34C8161B7F540B00F212E8 /* aescrypt.cpp */, + 5E34C8171B7F540B00F212E8 /* aeskey.cpp */, + 5E34C8181B7F540B00F212E8 /* aesopt.h */, + 5E34C8191B7F540B00F212E8 /* aestab.cpp */, + 5E34C81A1B7F540B00F212E8 /* fileenc.cpp */, + 5E34C81B1B7F540B00F212E8 /* fileenc.h */, + 5E34C81C1B7F540B00F212E8 /* hmac.cpp */, + 5E34C81D1B7F540B00F212E8 /* hmac.h */, + 5E34C81E1B7F540B00F212E8 /* prng.cpp */, + 5E34C81F1B7F540B00F212E8 /* prng.h */, + 5E34C8201B7F540B00F212E8 /* pwd2key.cpp */, + 5E34C8211B7F540B00F212E8 /* pwd2key.h */, + 5E34C8221B7F540B00F212E8 /* sha1.cpp */, + 5E34C8231B7F540B00F212E8 /* sha1.h */, + 5E34C8241B7F540B00F212E8 /* sha2.cpp */, + 5E34C8251B7F540B00F212E8 /* sha2.h */, + ); + name = aesGladman; + sourceTree = ""; + }; + 5E34C8091B7F522700F212E8 /* bzip2 */ = { + isa = PBXGroup; + children = ( + 5E34C8261B7F54FE00F212E8 /* blocksort.c */, + 5E34C8271B7F54FE00F212E8 /* bzcompress.c */, + 5E34C8281B7F54FE00F212E8 /* bzlib_private.h */, + 5E34C8291B7F54FE00F212E8 /* bzlib.c */, + 5E34C82A1B7F54FE00F212E8 /* bzlib.h */, + 5E34C82B1B7F54FE00F212E8 /* crctable.c */, + 5E34C82C1B7F54FE00F212E8 /* decompress.c */, + 5E34C82D1B7F54FE00F212E8 /* huffman.c */, + 5E34C82E1B7F54FE00F212E8 /* randtable.c */, + ); + name = bzip2; + sourceTree = ""; + }; + 5E34C80A1B7F522E00F212E8 /* jpeglib */ = { + isa = PBXGroup; + children = ( + 5E34C8311B7F561400F212E8 /* cderror.h */, + 5E34C8321B7F561400F212E8 /* jaricom.c */, + 5E34C8331B7F561400F212E8 /* jcapimin.c */, + 5E34C8341B7F561400F212E8 /* jcapistd.c */, + 5E34C8351B7F561400F212E8 /* jcarith.c */, + 5E34C8361B7F561400F212E8 /* jccoefct.c */, + 5E34C8371B7F561400F212E8 /* jccolor.c */, + 5E34C8381B7F561400F212E8 /* jcdctmgr.c */, + 5E34C8391B7F561400F212E8 /* jchuff.c */, + 5E34C83A1B7F561400F212E8 /* jcinit.c */, + 5E34C83B1B7F561400F212E8 /* jcmainct.c */, + 5E34C83C1B7F561400F212E8 /* jcmarker.c */, + 5E34C83D1B7F561400F212E8 /* jcmaster.c */, + 5E34C83E1B7F561400F212E8 /* jcomapi.c */, + 5E34C83F1B7F561400F212E8 /* jconfig.h */, + 5E34C8401B7F561400F212E8 /* jcparam.c */, + 5E34C8411B7F561400F212E8 /* jcprepct.c */, + 5E34C8421B7F561400F212E8 /* jcsample.c */, + 5E34C8431B7F561400F212E8 /* jctrans.c */, + 5E34C8441B7F561400F212E8 /* jdapimin.c */, + 5E34C8451B7F561400F212E8 /* jdapistd.c */, + 5E34C8461B7F561400F212E8 /* jdarith.c */, + 5E34C8471B7F561400F212E8 /* jdatadst.c */, + 5E34C8481B7F561400F212E8 /* jdatasrc.c */, + 5E34C8491B7F561400F212E8 /* jdcoefct.c */, + 5E34C84A1B7F561400F212E8 /* jdcolor.c */, + 5E34C84B1B7F561400F212E8 /* jdct.h */, + 5E34C84C1B7F561400F212E8 /* jddctmgr.c */, + 5E34C84D1B7F561400F212E8 /* jdhuff.c */, + 5E34C84E1B7F561400F212E8 /* jdinput.c */, + 5E34C84F1B7F561400F212E8 /* jdmainct.c */, + 5E34C8501B7F561400F212E8 /* jdmarker.c */, + 5E34C8511B7F561400F212E8 /* jdmaster.c */, + 5E34C8521B7F561400F212E8 /* jdmerge.c */, + 5E34C8531B7F561400F212E8 /* jdpostct.c */, + 5E34C8541B7F561400F212E8 /* jdsample.c */, + 5E34C8551B7F561400F212E8 /* jdtrans.c */, + 5E34C8561B7F561400F212E8 /* jerror.c */, + 5E34C8571B7F561400F212E8 /* jerror.h */, + 5E34C8581B7F568200F212E8 /* jfdctflt.c */, + 5E34C8591B7F568200F212E8 /* jfdctfst.c */, + 5E34C85A1B7F568200F212E8 /* jfdctint.c */, + 5E34C85B1B7F568200F212E8 /* jidctflt.c */, + 5E34C85C1B7F568200F212E8 /* jidctfst.c */, + 5E34C85D1B7F568200F212E8 /* jidctint.c */, + 5E34C85E1B7F568200F212E8 /* jinclude.h */, + 5E34C85F1B7F568200F212E8 /* jmemmgr.c */, + 5E34C8601B7F568200F212E8 /* jmemnobs.c */, + 5E34C8611B7F568200F212E8 /* jmemsys.h */, + 5E34C8621B7F568200F212E8 /* jmorecfg.h */, + 5E34C8631B7F568200F212E8 /* jpegint.h */, + 5E34C8641B7F568200F212E8 /* jpeglib.h */, + 5E34C8651B7F568200F212E8 /* jquant1.c */, + 5E34C8661B7F568200F212E8 /* jquant2.c */, + 5E34C8671B7F568200F212E8 /* jutils.c */, + 5E34C8681B7F568200F212E8 /* jversion.h */, + ); + name = jpeglib; + sourceTree = ""; + }; + 5E34C80B1B7F523B00F212E8 /* libpng */ = { + isa = PBXGroup; + children = ( + 5E34C8691B7F56E900F212E8 /* png.c */, + 5E34C86A1B7F56E900F212E8 /* png.h */, + 5E34C86B1B7F56E900F212E8 /* pngconf.h */, + 5E34C86C1B7F56E900F212E8 /* pngerror.c */, + 5E34C86D1B7F56E900F212E8 /* pngget.c */, + 5E34C86E1B7F56E900F212E8 /* pngmem.c */, + 5E34C86F1B7F56E900F212E8 /* pngpread.c */, + 5E34C8701B7F56E900F212E8 /* pngread.c */, + 5E34C8711B7F56E900F212E8 /* pngrio.c */, + 5E34C8721B7F56E900F212E8 /* pngrtran.c */, + 5E34C8731B7F56E900F212E8 /* pngrutil.c */, + 5E34C8741B7F56E900F212E8 /* pngset.c */, + 5E34C8751B7F56E900F212E8 /* pngtrans.c */, + 5E34C8761B7F56E900F212E8 /* pngwio.c */, + 5E34C8771B7F56E900F212E8 /* pngwrite.c */, + 5E34C8781B7F56E900F212E8 /* pngwtran.c */, + 5E34C8791B7F56E900F212E8 /* pngwutil.c */, + ); + name = libpng; + sourceTree = ""; + }; + 5E34C80C1B7F524400F212E8 /* zlib */ = { + isa = PBXGroup; + children = ( + 5E34C87A1B7F577000F212E8 /* adler32.c */, + 5E34C87B1B7F577000F212E8 /* compress.c */, + 5E34C87C1B7F577000F212E8 /* crc32.c */, + 5E34C87D1B7F577000F212E8 /* crc32.h */, + 5E34C87E1B7F577000F212E8 /* deflate.c */, + 5E34C87F1B7F577000F212E8 /* deflate.h */, + 5E34C8801B7F577000F212E8 /* inffast.c */, + 5E34C8811B7F577000F212E8 /* inffast.h */, + 5E34C8821B7F577000F212E8 /* inffixed.h */, + 5E34C8831B7F577000F212E8 /* inflate.c */, + 5E34C8841B7F577000F212E8 /* inflate.h */, + 5E34C8851B7F577000F212E8 /* inftrees.c */, + 5E34C8861B7F577000F212E8 /* inftrees.h */, + 5E34C8871B7F577000F212E8 /* trees.c */, + 5E34C8881B7F577000F212E8 /* trees.h */, + 5E34C8891B7F577000F212E8 /* uncompr.c */, + 5E34C88A1B7F577000F212E8 /* zconf.h */, + 5E34C88B1B7F577000F212E8 /* zlib.h */, + 5E34C88C1B7F577000F212E8 /* zutil.c */, + 5E34C88D1B7F577000F212E8 /* zutil.h */, + ); + name = zlib; + sourceTree = ""; + }; + 5E34C88E1B7F579B00F212E8 /* lzma */ = { + isa = PBXGroup; + children = ( + 5E34C88F1B7F57B100F212E8 /* LzmaDec.c */, + 5E34C8901B7F57B100F212E8 /* LzmaDec.h */, + 5E34C8911B7F57B100F212E8 /* Types.h */, + ); + name = lzma; + sourceTree = ""; + }; + 5E34C89F1B7F655200F212E8 /* animators */ = { + isa = PBXGroup; + children = ( + 5E34C8BA1B7F669200F212E8 /* CSceneNodeAnimatorCameraFPS.cpp */, + 5E34C8BB1B7F669200F212E8 /* CSceneNodeAnimatorCameraFPS.h */, + 5E34C8BC1B7F669200F212E8 /* CSceneNodeAnimatorCameraMaya.cpp */, + 5E34C8BD1B7F669200F212E8 /* CSceneNodeAnimatorCameraMaya.h */, + 5E34C8BE1B7F669200F212E8 /* CSceneNodeAnimatorCollisionResponse.cpp */, + 5E34C8BF1B7F669200F212E8 /* CSceneNodeAnimatorCollisionResponse.h */, + 5E34C8C01B7F669200F212E8 /* CSceneNodeAnimatorDelete.cpp */, + 5E34C8C11B7F669200F212E8 /* CSceneNodeAnimatorDelete.h */, + 5E34C8C21B7F669200F212E8 /* CSceneNodeAnimatorFlyCircle.cpp */, + 5E34C8C31B7F669200F212E8 /* CSceneNodeAnimatorFlyCircle.h */, + 5E34C8C41B7F669200F212E8 /* CSceneNodeAnimatorFlyStraight.cpp */, + 5E34C8C51B7F669200F212E8 /* CSceneNodeAnimatorFlyStraight.h */, + 5E34C8C61B7F669200F212E8 /* CSceneNodeAnimatorFollowSpline.cpp */, + 5E34C8C71B7F669200F212E8 /* CSceneNodeAnimatorFollowSpline.h */, + 5E34C8C81B7F669200F212E8 /* CSceneNodeAnimatorRotation.cpp */, + 5E34C8C91B7F669200F212E8 /* CSceneNodeAnimatorRotation.h */, + 5E34C8CA1B7F669200F212E8 /* CSceneNodeAnimatorTexture.cpp */, + 5E34C8CB1B7F669200F212E8 /* CSceneNodeAnimatorTexture.h */, + ); + name = animators; + sourceTree = ""; + }; + 5E34C8A01B7F655A00F212E8 /* collision */ = { + isa = PBXGroup; + children = ( + 5E34C8CC1B7F66E600F212E8 /* CMetaTriangleSelector.cpp */, + 5E34C8CD1B7F66E600F212E8 /* CMetaTriangleSelector.h */, + 5E34C8CE1B7F66E600F212E8 /* COctreeTriangleSelector.cpp */, + 5E34C8CF1B7F66E600F212E8 /* COctreeTriangleSelector.h */, + 5E34C8D01B7F66E600F212E8 /* CSceneCollisionManager.cpp */, + 5E34C8D11B7F66E600F212E8 /* CSceneCollisionManager.h */, + 5E34C8D21B7F66E600F212E8 /* CTerrainTriangleSelector.cpp */, + 5E34C8D31B7F66E600F212E8 /* CTerrainTriangleSelector.h */, + 5E34C8D41B7F66E600F212E8 /* CTriangleBBSelector.cpp */, + 5E34C8D51B7F66E600F212E8 /* CTriangleBBSelector.h */, + 5E34C8D61B7F66E600F212E8 /* CTriangleSelector.cpp */, + 5E34C8D71B7F66E600F212E8 /* CTriangleSelector.h */, + ); + name = collision; + sourceTree = ""; + }; + 5E34C8A11B7F656300F212E8 /* loaders */ = { + isa = PBXGroup; + children = ( + 5E34C8D81B7F680200F212E8 /* C3DSMeshFileLoader.cpp */, + 5E34C8D91B7F680200F212E8 /* C3DSMeshFileLoader.h */, + 5E34C8DA1B7F680200F212E8 /* CAnimatedMeshHalfLife.cpp */, + 5E34C8DB1B7F680200F212E8 /* CAnimatedMeshHalfLife.h */, + 5E34C8DC1B7F680200F212E8 /* CAnimatedMeshMD2.cpp */, + 5E34C8DD1B7F680200F212E8 /* CAnimatedMeshMD2.h */, + 5E34C8DE1B7F680200F212E8 /* CAnimatedMeshMD3.cpp */, + 5E34C8DF1B7F680200F212E8 /* CAnimatedMeshMD3.h */, + 5E34C8E01B7F680200F212E8 /* CB3DMeshFileLoader.cpp */, + 5E34C8E11B7F680200F212E8 /* CB3DMeshFileLoader.h */, + 5E34C8E21B7F680200F212E8 /* CBSPMeshFileLoader.cpp */, + 5E34C8E31B7F680200F212E8 /* CBSPMeshFileLoader.h */, + 5E34C8E41B7F680200F212E8 /* CColladaFileLoader.cpp */, + 5E34C8E51B7F680200F212E8 /* CColladaFileLoader.h */, + 5E34C8E61B7F680200F212E8 /* CCSMLoader.cpp */, + 5E34C8E71B7F680200F212E8 /* CCSMLoader.h */, + 5E34C8E81B7F680200F212E8 /* CDMFLoader.cpp */, + 5E34C8E91B7F680200F212E8 /* CDMFLoader.h */, + 5E34C8EA1B7F680200F212E8 /* CIrrMeshFileLoader.cpp */, + 5E34C8EB1B7F680200F212E8 /* CIrrMeshFileLoader.h */, + 5E34C8EC1B7F680200F212E8 /* CLMTSMeshFileLoader.cpp */, + 5E34C8ED1B7F680200F212E8 /* CLMTSMeshFileLoader.h */, + 5E34C8EE1B7F680200F212E8 /* CLWOMeshFileLoader.cpp */, + 5E34C8EF1B7F680200F212E8 /* CLWOMeshFileLoader.h */, + 5E34C8F01B7F680200F212E8 /* CMD2MeshFileLoader.cpp */, + 5E34C8F11B7F680200F212E8 /* CMD2MeshFileLoader.h */, + 5E34C8F21B7F680200F212E8 /* CMD3MeshFileLoader.cpp */, + 5E34C8F31B7F680200F212E8 /* CMD3MeshFileLoader.h */, + 5E34C8F41B7F680200F212E8 /* CMeshTextureLoader.cpp */, + 5E34C8F51B7F680200F212E8 /* CMeshTextureLoader.h */, + 5E34C8F61B7F680200F212E8 /* CMS3DMeshFileLoader.cpp */, + 5E34C8F71B7F680200F212E8 /* CMS3DMeshFileLoader.h */, + 5E34C8F81B7F680200F212E8 /* CMY3DHelper.h */, + 5E34C8F91B7F680200F212E8 /* CMY3DMeshFileLoader.cpp */, + 5E34C8FA1B7F680200F212E8 /* CMY3DMeshFileLoader.h */, + 5E34C8FB1B7F680200F212E8 /* COBJMeshFileLoader.cpp */, + 5E34C8FC1B7F680200F212E8 /* COBJMeshFileLoader.h */, + 5E34C8FD1B7F680200F212E8 /* COCTLoader.cpp */, + 5E34C8FE1B7F680200F212E8 /* COCTLoader.h */, + 5E34C8FF1B7F680200F212E8 /* COgreMeshFileLoader.cpp */, + 5E34C9001B7F680200F212E8 /* COgreMeshFileLoader.h */, + 5E34C9011B7F680200F212E8 /* CPLYMeshFileLoader.cpp */, + 5E34C9021B7F680200F212E8 /* CPLYMeshFileLoader.h */, + 5E34C9031B7F680200F212E8 /* CQ3LevelMesh.cpp */, + 5E34C9041B7F680200F212E8 /* CQ3LevelMesh.h */, + 5E34C9051B7F680200F212E8 /* CSceneLoaderIrr.cpp */, + 5E34C9061B7F680200F212E8 /* CSceneLoaderIrr.h */, + 5E34C9071B7F680200F212E8 /* CSkinnedMesh.cpp */, + 5E34C9081B7F680200F212E8 /* CSkinnedMesh.h */, + 5E34C9091B7F680200F212E8 /* CSMFMeshFileLoader.cpp */, + 5E34C90A1B7F680200F212E8 /* CSMFMeshFileLoader.h */, + 5E34C90B1B7F680200F212E8 /* CSTLMeshFileLoader.cpp */, + 5E34C90C1B7F680200F212E8 /* CSTLMeshFileLoader.h */, + 5E34C90D1B7F680200F212E8 /* CXMeshFileLoader.cpp */, + 5E34C90E1B7F680200F212E8 /* CXMeshFileLoader.h */, + 5E34C90F1B7F680200F212E8 /* dmfsupport.h */, + ); + name = loaders; + sourceTree = ""; + }; + 5E34C8A21B7F656C00F212E8 /* particleSystem */ = { + isa = PBXGroup; + children = ( + 5E34C9101B7F684000F212E8 /* CParticleAnimatedMeshSceneNodeEmitter.cpp */, + 5E34C9111B7F684000F212E8 /* CParticleAnimatedMeshSceneNodeEmitter.h */, + 5E34C9121B7F684000F212E8 /* CParticleAttractionAffector.cpp */, + 5E34C9131B7F684000F212E8 /* CParticleAttractionAffector.h */, + 5E34C9141B7F684000F212E8 /* CParticleBoxEmitter.cpp */, + 5E34C9151B7F684000F212E8 /* CParticleBoxEmitter.h */, + 5E34C9161B7F684000F212E8 /* CParticleCylinderEmitter.cpp */, + 5E34C9171B7F684000F212E8 /* CParticleCylinderEmitter.h */, + 5E34C9181B7F684000F212E8 /* CParticleFadeOutAffector.cpp */, + 5E34C9191B7F684000F212E8 /* CParticleFadeOutAffector.h */, + 5E34C91A1B7F684000F212E8 /* CParticleGravityAffector.cpp */, + 5E34C91B1B7F684000F212E8 /* CParticleGravityAffector.h */, + 5E34C91C1B7F684000F212E8 /* CParticleMeshEmitter.cpp */, + 5E34C91D1B7F684000F212E8 /* CParticleMeshEmitter.h */, + 5E34C91E1B7F684000F212E8 /* CParticlePointEmitter.cpp */, + 5E34C91F1B7F684000F212E8 /* CParticlePointEmitter.h */, + 5E34C9201B7F684000F212E8 /* CParticleRingEmitter.cpp */, + 5E34C9211B7F684000F212E8 /* CParticleRingEmitter.h */, + 5E34C9221B7F684000F212E8 /* CParticleRotationAffector.cpp */, + 5E34C9231B7F684000F212E8 /* CParticleRotationAffector.h */, + 5E34C9241B7F684000F212E8 /* CParticleScaleAffector.cpp */, + 5E34C9251B7F684000F212E8 /* CParticleScaleAffector.h */, + 5E34C9261B7F684000F212E8 /* CParticleSphereEmitter.cpp */, + 5E34C9271B7F684000F212E8 /* CParticleSphereEmitter.h */, + 5E34C9281B7F684000F212E8 /* CParticleSystemSceneNode.cpp */, + 5E34C9291B7F684000F212E8 /* CParticleSystemSceneNode.h */, + ); + name = particleSystem; + sourceTree = ""; + }; + 5E34C8A31B7F657A00F212E8 /* sceneNodes */ = { + isa = PBXGroup; + children = ( + 5E34C92A1B7F68D600F212E8 /* CAnimatedMeshSceneNode.cpp */, + 5E34C92B1B7F68D600F212E8 /* CAnimatedMeshSceneNode.h */, + 5E34C92C1B7F68D600F212E8 /* CBillboardSceneNode.cpp */, + 5E34C92D1B7F68D600F212E8 /* CBillboardSceneNode.h */, + 5E34C92E1B7F68D600F212E8 /* CBoneSceneNode.cpp */, + 5E34C92F1B7F68D600F212E8 /* CBoneSceneNode.h */, + 5E34C9301B7F68D600F212E8 /* CCameraSceneNode.cpp */, + 5E34C9311B7F68D600F212E8 /* CCameraSceneNode.h */, + 5E34C9321B7F68D600F212E8 /* CCubeSceneNode.cpp */, + 5E34C9331B7F68D600F212E8 /* CCubeSceneNode.h */, + 5E34C9341B7F68D600F212E8 /* CDummyTransformationSceneNode.cpp */, + 5E34C9351B7F68D600F212E8 /* CDummyTransformationSceneNode.h */, + 5E34C9361B7F68D600F212E8 /* CEmptySceneNode.cpp */, + 5E34C9371B7F68D600F212E8 /* CEmptySceneNode.h */, + 5E34C9381B7F68D600F212E8 /* CLightSceneNode.cpp */, + 5E34C9391B7F68D600F212E8 /* CLightSceneNode.h */, + 5E34C93A1B7F68D600F212E8 /* CMeshSceneNode.cpp */, + 5E34C93B1B7F68D600F212E8 /* CMeshSceneNode.h */, + 5E34C93C1B7F68D600F212E8 /* COctreeSceneNode.cpp */, + 5E34C93D1B7F68D600F212E8 /* COctreeSceneNode.h */, + 5E34C93E1B7F68D600F212E8 /* CQuake3ShaderSceneNode.cpp */, + 5E34C93F1B7F68D600F212E8 /* CQuake3ShaderSceneNode.h */, + 5E34C9401B7F68D600F212E8 /* CShadowVolumeSceneNode.cpp */, + 5E34C9411B7F68D600F212E8 /* CShadowVolumeSceneNode.h */, + 5E34C9421B7F68D600F212E8 /* CSkyBoxSceneNode.cpp */, + 5E34C9431B7F68D600F212E8 /* CSkyBoxSceneNode.h */, + 5E34C9441B7F68D600F212E8 /* CSkyDomeSceneNode.cpp */, + 5E34C9451B7F68D600F212E8 /* CSkyDomeSceneNode.h */, + 5E34C9461B7F68D600F212E8 /* CSphereSceneNode.cpp */, + 5E34C9471B7F68D600F212E8 /* CSphereSceneNode.h */, + 5E34C9481B7F68D600F212E8 /* CTerrainSceneNode.cpp */, + 5E34C9491B7F68D600F212E8 /* CTerrainSceneNode.h */, + 5E34C94A1B7F68D600F212E8 /* CTextSceneNode.cpp */, + 5E34C94B1B7F68D600F212E8 /* CTextSceneNode.h */, + 5E34C94C1B7F68D600F212E8 /* CVolumeLightSceneNode.cpp */, + 5E34C94D1B7F68D600F212E8 /* CVolumeLightSceneNode.h */, + 5E34C94E1B7F68D600F212E8 /* CWaterSurfaceSceneNode.cpp */, + 5E34C94F1B7F68D600F212E8 /* CWaterSurfaceSceneNode.h */, + ); + name = sceneNodes; + sourceTree = ""; + }; + 5E34C8A41B7F658300F212E8 /* writers */ = { + isa = PBXGroup; + children = ( + 5E7908981C10FE4A00DFE7FE /* CB3DMeshWriter.cpp */, + 5E7908991C10FE4A00DFE7FE /* CB3DMeshWriter.h */, + 5E34C9501B7F691500F212E8 /* CColladaMeshWriter.cpp */, + 5E34C9511B7F691500F212E8 /* CColladaMeshWriter.h */, + 5E34C9521B7F691500F212E8 /* CIrrMeshWriter.cpp */, + 5E34C9531B7F691500F212E8 /* CIrrMeshWriter.h */, + 5E34C9541B7F691500F212E8 /* COBJMeshWriter.cpp */, + 5E34C9551B7F691500F212E8 /* COBJMeshWriter.h */, + 5E34C9561B7F691500F212E8 /* CPLYMeshWriter.cpp */, + 5E34C9571B7F691500F212E8 /* CPLYMeshWriter.h */, + 5E34C9581B7F691500F212E8 /* CSTLMeshWriter.cpp */, + 5E34C9591B7F691500F212E8 /* CSTLMeshWriter.h */, + ); + name = writers; + sourceTree = ""; + }; + 5E34C95A1B7F692C00F212E8 /* Burning Video */ = { + isa = PBXGroup; + children = ( + 5E34C9601B7F6A7600F212E8 /* CBurningShader_Raster_Reference.cpp */, + 5E34C9611B7F6A7600F212E8 /* CDepthBuffer.cpp */, + 5E34C9621B7F6A7600F212E8 /* CDepthBuffer.h */, + 5E34C9631B7F6A7600F212E8 /* CSoftware2MaterialRenderer.h */, + 5E34C9641B7F6A7600F212E8 /* CSoftwareDriver2.cpp */, + 5E34C9651B7F6A7600F212E8 /* CSoftwareDriver2.h */, + 5E34C9661B7F6A7600F212E8 /* CSoftwareTexture2.cpp */, + 5E34C9671B7F6A7600F212E8 /* CSoftwareTexture2.h */, + 5E34C9681B7F6A7600F212E8 /* CTRGouraud2.cpp */, + 5E34C9691B7F6A7600F212E8 /* CTRGouraudAlpha2.cpp */, + 5E34C96A1B7F6A7600F212E8 /* CTRGouraudAlphaNoZ2.cpp */, + 5E34C96B1B7F6A7600F212E8 /* CTRNormalMap.cpp */, + 5E34C96C1B7F6A7600F212E8 /* CTRStencilShadow.cpp */, + 5E34C96D1B7F6A7600F212E8 /* CTRTextureBlend.cpp */, + 5E34C96E1B7F6A7600F212E8 /* CTRTextureDetailMap2.cpp */, + 5E34C96F1B7F6A7600F212E8 /* CTRTextureGouraud2.cpp */, + 5E34C9701B7F6A7600F212E8 /* CTRTextureGouraudAdd2.cpp */, + 5E34C9711B7F6A7600F212E8 /* CTRTextureGouraudAddNoZ2.cpp */, + 5E34C9721B7F6A7600F212E8 /* CTRTextureGouraudAlpha.cpp */, + 5E34C9731B7F6A7600F212E8 /* CTRTextureGouraudAlphaNoZ.cpp */, + 5E34C9741B7F6A7600F212E8 /* CTRTextureGouraudNoZ2.cpp */, + 5E34C9751B7F6A7600F212E8 /* CTRTextureGouraudVertexAlpha2.cpp */, + 5E34C9761B7F6A7600F212E8 /* CTRTextureLightMap2_Add.cpp */, + 5E34C9771B7F6A7600F212E8 /* CTRTextureLightMap2_M1.cpp */, + 5E34C9781B7F6A7600F212E8 /* CTRTextureLightMap2_M2.cpp */, + 5E34C9791B7F6A7600F212E8 /* CTRTextureLightMap2_M4.cpp */, + 5E34C97A1B7F6A7600F212E8 /* CTRTextureLightMapGouraud2_M4.cpp */, + 5E34C97B1B7F6A7600F212E8 /* CTRTextureWire2.cpp */, + 5E34C97C1B7F6A7600F212E8 /* IBurningShader.cpp */, + 5E34C97D1B7F6A7600F212E8 /* IBurningShader.h */, + 5E34C97E1B7F6A7600F212E8 /* IDepthBuffer.h */, + 5E34C97F1B7F6A7600F212E8 /* S4DVertex.h */, + 5E34C9801B7F6A7600F212E8 /* SoftwareDriver2_compile_config.h */, + 5E34C9811B7F6A7600F212E8 /* SoftwareDriver2_helper.h */, + ); + name = "Burning Video"; + sourceTree = ""; + }; + 5E34C95B1B7F693800F212E8 /* Null */ = { + isa = PBXGroup; + children = ( + 5E34C9821B7F6A9700F212E8 /* loaders */, + 5E34C9831B7F6ABA00F212E8 /* writers */, + 5E34C9A81B7F6B6800F212E8 /* CColorConverter.cpp */, + 5E34C9A91B7F6B6800F212E8 /* CColorConverter.h */, + 5E34C9AA1B7F6B6800F212E8 /* CFPSCounter.cpp */, + 5E34C9AB1B7F6B6800F212E8 /* CFPSCounter.h */, + 5E34C9AC1B7F6B6800F212E8 /* CImage.cpp */, + 5E34C9AD1B7F6B6800F212E8 /* CImage.h */, + 5E34C9AE1B7F6B6800F212E8 /* CNullDriver.cpp */, + 5E34C9AF1B7F6B6800F212E8 /* CNullDriver.h */, + 5E34C9B01B7F6B6800F212E8 /* IImagePresenter.h */, + ); + name = Null; + sourceTree = ""; + }; + 5E34C95C1B7F694500F212E8 /* OpenGL */ = { + isa = PBXGroup; + children = ( + 5E7908911C10EEC000DFE7FE /* COpenGLCacheHandler.cpp */, + 5E7908921C10EEC000DFE7FE /* COpenGLCacheHandler.h */, + 5E7908931C10EEC000DFE7FE /* COpenGLCommon.h */, + 5E34C9B11B7F6BA700F212E8 /* COpenGLDriver.cpp */, + 5E34C9B21B7F6BA700F212E8 /* COpenGLDriver.h */, + 5E34C9B31B7F6BA700F212E8 /* COpenGLExtensionHandler.cpp */, + 5E34C9B41B7F6BA700F212E8 /* COpenGLExtensionHandler.h */, + 5E34C9B51B7F6BA700F212E8 /* COpenGLMaterialRenderer.h */, + 5E34C9B61B7F6BA700F212E8 /* COpenGLNormalMapRenderer.cpp */, + 5E34C9B71B7F6BA700F212E8 /* COpenGLNormalMapRenderer.h */, + 5E34C9B81B7F6BA700F212E8 /* COpenGLParallaxMapRenderer.cpp */, + 5E34C9B91B7F6BA700F212E8 /* COpenGLParallaxMapRenderer.h */, + 5E34C9BA1B7F6BA700F212E8 /* COpenGLShaderMaterialRenderer.cpp */, + 5E34C9BB1B7F6BA700F212E8 /* COpenGLShaderMaterialRenderer.h */, + 5E34C9BC1B7F6BA700F212E8 /* COpenGLSLMaterialRenderer.cpp */, + 5E34C9BD1B7F6BA700F212E8 /* COpenGLSLMaterialRenderer.h */, + ); + name = OpenGL; + sourceTree = ""; + }; + 5E34C95F1B7F697B00F212E8 /* Software */ = { + isa = PBXGroup; + children = ( + 5E34C9D71B7F6C6100F212E8 /* CSoftwareDriver.cpp */, + 5E34C9D81B7F6C6100F212E8 /* CSoftwareDriver.h */, + 5E34C9D91B7F6C6100F212E8 /* CSoftwareTexture.cpp */, + 5E34C9DA1B7F6C6100F212E8 /* CSoftwareTexture.h */, + 5E34C9DB1B7F6C6100F212E8 /* CTRFlat.cpp */, + 5E34C9DC1B7F6C6100F212E8 /* CTRFlatWire.cpp */, + 5E34C9DD1B7F6C6100F212E8 /* CTRGouraud.cpp */, + 5E34C9DE1B7F6C6100F212E8 /* CTRGouraudWire.cpp */, + 5E34C9DF1B7F6C6100F212E8 /* CTRTextureFlat.cpp */, + 5E34C9E01B7F6C6100F212E8 /* CTRTextureFlatWire.cpp */, + 5E34C9E11B7F6C6100F212E8 /* CTRTextureGouraud.cpp */, + 5E34C9E21B7F6C6100F212E8 /* CTRTextureGouraud.h */, + 5E34C9E31B7F6C6100F212E8 /* CTRTextureGouraudAdd.cpp */, + 5E34C9E41B7F6C6100F212E8 /* CTRTextureGouraudNoZ.cpp */, + 5E34C9E51B7F6C6100F212E8 /* CTRTextureGouraudWire.cpp */, + 5E34C9E61B7F6C6100F212E8 /* CZBuffer.cpp */, + 5E34C9E71B7F6C6100F212E8 /* CZBuffer.h */, + 5E34C9E81B7F6C6100F212E8 /* ITriangleRenderer.h */, + 5E34C9E91B7F6C6100F212E8 /* IZBuffer.h */, + 5E34C9EA1B7F6C6100F212E8 /* S2DVertex.h */, + ); + name = Software; + sourceTree = ""; + }; + 5E34C9821B7F6A9700F212E8 /* loaders */ = { + isa = PBXGroup; + children = ( + 5E34C9841B7F6AED00F212E8 /* CImageLoaderBMP.cpp */, + 5E34C9851B7F6AED00F212E8 /* CImageLoaderBMP.h */, + 5E34C9861B7F6AED00F212E8 /* CImageLoaderDDS.cpp */, + 5E34C9871B7F6AED00F212E8 /* CImageLoaderDDS.h */, + 5E34C9881B7F6AED00F212E8 /* CImageLoaderJPG.cpp */, + 5E34C9891B7F6AED00F212E8 /* CImageLoaderJPG.h */, + 5E34C98A1B7F6AED00F212E8 /* CImageLoaderPCX.cpp */, + 5E34C98B1B7F6AED00F212E8 /* CImageLoaderPCX.h */, + 5E34C98C1B7F6AED00F212E8 /* CImageLoaderPNG.cpp */, + 5E34C98D1B7F6AED00F212E8 /* CImageLoaderPNG.h */, + 5E34C98E1B7F6AED00F212E8 /* CImageLoaderPPM.cpp */, + 5E34C98F1B7F6AED00F212E8 /* CImageLoaderPPM.h */, + 5E34C9901B7F6AED00F212E8 /* CImageLoaderPSD.cpp */, + 5E34C9911B7F6AED00F212E8 /* CImageLoaderPSD.h */, + 5E34C9921B7F6AED00F212E8 /* CImageLoaderPVR.cpp */, + 5E34C9931B7F6AED00F212E8 /* CImageLoaderPVR.h */, + 5E34C9941B7F6AED00F212E8 /* CImageLoaderRGB.cpp */, + 5E34C9951B7F6AED00F212E8 /* CImageLoaderRGB.h */, + 5E34C9961B7F6AED00F212E8 /* CImageLoaderTGA.cpp */, + 5E34C9971B7F6AED00F212E8 /* CImageLoaderTGA.h */, + 5E34C9981B7F6AED00F212E8 /* CImageLoaderWAL.cpp */, + 5E34C9991B7F6AED00F212E8 /* CImageLoaderWAL.h */, + ); + name = loaders; + sourceTree = ""; + }; + 5E34C9831B7F6ABA00F212E8 /* writers */ = { + isa = PBXGroup; + children = ( + 5E34C99A1B7F6B0900F212E8 /* CImageWriterBMP.cpp */, + 5E34C99B1B7F6B0900F212E8 /* CImageWriterBMP.h */, + 5E34C99C1B7F6B0900F212E8 /* CImageWriterJPG.cpp */, + 5E34C99D1B7F6B0900F212E8 /* CImageWriterJPG.h */, + 5E34C99E1B7F6B0900F212E8 /* CImageWriterPCX.cpp */, + 5E34C99F1B7F6B0900F212E8 /* CImageWriterPCX.h */, + 5E34C9A01B7F6B0900F212E8 /* CImageWriterPNG.cpp */, + 5E34C9A11B7F6B0900F212E8 /* CImageWriterPNG.h */, + 5E34C9A21B7F6B0900F212E8 /* CImageWriterPPM.cpp */, + 5E34C9A31B7F6B0900F212E8 /* CImageWriterPPM.h */, + 5E34C9A41B7F6B0900F212E8 /* CImageWriterPSD.cpp */, + 5E34C9A51B7F6B0900F212E8 /* CImageWriterPSD.h */, + 5E34C9A61B7F6B0900F212E8 /* CImageWriterTGA.cpp */, + 5E34C9A71B7F6B0900F212E8 /* CImageWriterTGA.h */, + ); + name = writers; + sourceTree = ""; + }; + 5E34C9F41B7F6E3400F212E8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E34C9F31B7F6E3400F212E8 /* libIrrlicht.a */, + 5E5733E51C18E212003F664E /* libIrrlicht.a */, + ); + name = Products; + sourceTree = ""; + }; + 5E5733EA1C18E27E003F664E /* OpenGL ES1.x */ = { + isa = PBXGroup; + children = ( + 5E5733EC1C18E2C0003F664E /* COGLESCommon.h */, + 5E5733ED1C18E2C0003F664E /* COGLESDriver.cpp */, + 5E5733EE1C18E2C0003F664E /* COGLESDriver.h */, + 5E5733EF1C18E2C0003F664E /* COGLESExtensionHandler.cpp */, + 5E5733F01C18E2C0003F664E /* COGLESExtensionHandler.h */, + 5E5733F11C18E2C0003F664E /* COGLESMaterialRenderer.h */, + ); + name = "OpenGL ES1.x"; + sourceTree = ""; + }; + 5E5733EB1C18E29B003F664E /* OpenGL ES2.x */ = { + isa = PBXGroup; + children = ( + 5E5733F81C18E2E2003F664E /* COGLES2Common.h */, + 5E5733F91C18E2E2003F664E /* COGLES2Driver.cpp */, + 5E5733FA1C18E2E2003F664E /* COGLES2Driver.h */, + 5E5733FB1C18E2E2003F664E /* COGLES2ExtensionHandler.cpp */, + 5E5733FC1C18E2E2003F664E /* COGLES2ExtensionHandler.h */, + 5E5733FD1C18E2E2003F664E /* COGLES2FixedPipelineRenderer.cpp */, + 5E5733FE1C18E2E2003F664E /* COGLES2FixedPipelineRenderer.h */, + 5E5733FF1C18E2E2003F664E /* COGLES2MaterialRenderer.cpp */, + 5E5734001C18E2E2003F664E /* COGLES2MaterialRenderer.h */, + 5E5734011C18E2E2003F664E /* COGLES2NormalMapRenderer.cpp */, + 5E5734021C18E2E2003F664E /* COGLES2NormalMapRenderer.h */, + 5E5734031C18E2E2003F664E /* COGLES2ParallaxMapRenderer.cpp */, + 5E5734041C18E2E2003F664E /* COGLES2ParallaxMapRenderer.h */, + 5E5734051C18E2E2003F664E /* COGLES2Renderer2D.cpp */, + 5E5734061C18E2E2003F664E /* COGLES2Renderer2D.h */, + ); + name = "OpenGL ES2.x"; + sourceTree = ""; + }; + 5E79088B1C10ED5000DFE7FE /* OpenGL Core */ = { + isa = PBXGroup; + children = ( + 5E79088D1C10EE6700DFE7FE /* COpenGLCoreCacheHandler.h */, + 5E79088E1C10EE6700DFE7FE /* COpenGLCoreFeature.h */, + 5E79088F1C10EE6700DFE7FE /* COpenGLCoreRenderTarget.h */, + 5E7908901C10EE6700DFE7FE /* COpenGLCoreTexture.h */, + ); + name = "OpenGL Core"; + sourceTree = ""; + }; + 5E79088C1C10EDF000DFE7FE /* OpenGL Context */ = { + isa = PBXGroup; + children = ( + 5E9573D61C18E9E600C27989 /* CEAGLManager.mm */, + 5E9573D31C18E9B300C27989 /* CEAGLManager.h */, + 5E34C9ED1B7F6CCC00F212E8 /* CNSOGLManager.h */, + 5E34C9EE1B7F6CCC00F212E8 /* CNSOGLManager.mm */, + ); + name = "OpenGL Context"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 5E34C9F11B7F6E3400F212E8 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5E5733DE1C18E212003F664E /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 5E34C9F21B7F6E3400F212E8 /* Irrlicht_OSX */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E34C9F51B7F6E3400F212E8 /* Build configuration list for PBXNativeTarget "Irrlicht_OSX" */; + buildPhases = ( + 5E34C9EF1B7F6E3400F212E8 /* Sources */, + 5E34C9F01B7F6E3400F212E8 /* Frameworks */, + 5E34C9F11B7F6E3400F212E8 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Irrlicht_OSX; + productName = Irrlicht; + productReference = 5E34C9F31B7F6E3400F212E8 /* libIrrlicht.a */; + productType = "com.apple.product-type.library.static"; + }; + 5E5732B11C18E212003F664E /* Irrlicht_iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E5733E21C18E212003F664E /* Build configuration list for PBXNativeTarget "Irrlicht_iOS" */; + buildPhases = ( + 5E5732B21C18E212003F664E /* Sources */, + 5E5733DD1C18E212003F664E /* Frameworks */, + 5E5733DE1C18E212003F664E /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Irrlicht_iOS; + productName = Irrlicht; + productReference = 5E5733E51C18E212003F664E /* libIrrlicht.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E34C6D91B7F4A0C00F212E8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0830; + TargetAttributes = { + 5E34C9F21B7F6E3400F212E8 = { + CreatedOnToolsVersion = 6.1; + }; + }; + }; + buildConfigurationList = 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Irrlicht" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 5E34C6D81B7F4A0C00F212E8; + productRefGroup = 5E34C9F41B7F6E3400F212E8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E34C9F21B7F6E3400F212E8 /* Irrlicht_OSX */, + 5E5732B11C18E212003F664E /* Irrlicht_iOS */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E34C9EF1B7F6E3400F212E8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E1DF8E11E96BFE100FC3523 /* CIrrDeviceOSX.mm in Sources */, + 5E34C9F91B7F6EBF00F212E8 /* CDefaultGUIElementFactory.cpp in Sources */, + 5E34C9FB1B7F6EBF00F212E8 /* CGUIButton.cpp in Sources */, + 5E34C9FD1B7F6EBF00F212E8 /* CGUICheckBox.cpp in Sources */, + 5E34C9FF1B7F6EBF00F212E8 /* CGUIColorSelectDialog.cpp in Sources */, + 5E34CA011B7F6EBF00F212E8 /* CGUIComboBox.cpp in Sources */, + 5E34CA031B7F6EBF00F212E8 /* CGUIContextMenu.cpp in Sources */, + 5E34CA051B7F6EBF00F212E8 /* CGUIEditBox.cpp in Sources */, + 5E34CA071B7F6EBF00F212E8 /* CGUIEnvironment.cpp in Sources */, + 5E34CA091B7F6EBF00F212E8 /* CGUIFileOpenDialog.cpp in Sources */, + 5E34CA0B1B7F6EBF00F212E8 /* CGUIFont.cpp in Sources */, + 5E34CA0D1B7F6EBF00F212E8 /* CGUIImage.cpp in Sources */, + 5E34CA0F1B7F6EBF00F212E8 /* CGUIImageList.cpp in Sources */, + 5E34CA111B7F6EBF00F212E8 /* CGUIInOutFader.cpp in Sources */, + 5E34CA131B7F6EBF00F212E8 /* CGUIListBox.cpp in Sources */, + 5E34CA151B7F6EBF00F212E8 /* CGUIMenu.cpp in Sources */, + 5E34CA171B7F6EBF00F212E8 /* CGUIMeshViewer.cpp in Sources */, + 5E34CA191B7F6EBF00F212E8 /* CGUIMessageBox.cpp in Sources */, + 5E34CA1B1B7F6EBF00F212E8 /* CGUIModalScreen.cpp in Sources */, + 5E34CA1D1B7F6EBF00F212E8 /* CGUIProfiler.cpp in Sources */, + 5E34CA1F1B7F6EBF00F212E8 /* CGUIScrollBar.cpp in Sources */, + 5E34CA211B7F6EBF00F212E8 /* CGUISkin.cpp in Sources */, + 5E34CA231B7F6EBF00F212E8 /* CGUISpinBox.cpp in Sources */, + 5E34CA251B7F6EBF00F212E8 /* CGUISpriteBank.cpp in Sources */, + 5E34CA271B7F6EBF00F212E8 /* CGUIStaticText.cpp in Sources */, + 5E34CA291B7F6EBF00F212E8 /* CGUITabControl.cpp in Sources */, + 5E34CA2B1B7F6EBF00F212E8 /* CGUITable.cpp in Sources */, + 5E34CA2D1B7F6EBF00F212E8 /* CGUIToolBar.cpp in Sources */, + 5E34CA2F1B7F6EBF00F212E8 /* CGUITreeView.cpp in Sources */, + 5E34CA311B7F6EBF00F212E8 /* CGUIWindow.cpp in Sources */, + 5E34CA341B7F6EBF00F212E8 /* CAttributes.cpp in Sources */, + 5E34CA361B7F6EBF00F212E8 /* CFileList.cpp in Sources */, + 5E34CA381B7F6EBF00F212E8 /* CFileSystem.cpp in Sources */, + 5E34CA3A1B7F6EBF00F212E8 /* CLimitReadFile.cpp in Sources */, + 5E34CA3C1B7F6EBF00F212E8 /* CMemoryFile.cpp in Sources */, + 5E34CA3E1B7F6EBF00F212E8 /* CMountPointReader.cpp in Sources */, + 5E34CA401B7F6EBF00F212E8 /* CNPKReader.cpp in Sources */, + 5E34CA421B7F6EBF00F212E8 /* CPakReader.cpp in Sources */, + 5E34CA441B7F6EBF00F212E8 /* CReadFile.cpp in Sources */, + 5E34CA461B7F6EBF00F212E8 /* CTarReader.cpp in Sources */, + 5E34CA481B7F6EBF00F212E8 /* CWADReader.cpp in Sources */, + 5E34CA4A1B7F6EBF00F212E8 /* CWriteFile.cpp in Sources */, + 5E34CA4C1B7F6EBF00F212E8 /* CXMLReader.cpp in Sources */, + 5E34CA4F1B7F6EBF00F212E8 /* CXMLWriter.cpp in Sources */, + 5E34CA511B7F6EBF00F212E8 /* CZipReader.cpp in Sources */, + 5E34CA541B7F6EBF00F212E8 /* irrXML.cpp in Sources */, + 5E34CA591B7F6EBF00F212E8 /* CIrrDeviceStub.cpp in Sources */, + 5E34CA5C1B7F6EBF00F212E8 /* aescrypt.cpp in Sources */, + 5E34CA5D1B7F6EBF00F212E8 /* aeskey.cpp in Sources */, + 5E34CA5F1B7F6EBF00F212E8 /* aestab.cpp in Sources */, + 5E34CA601B7F6EBF00F212E8 /* fileenc.cpp in Sources */, + 5E34CA621B7F6EBF00F212E8 /* hmac.cpp in Sources */, + 5E34CA641B7F6EBF00F212E8 /* prng.cpp in Sources */, + 5E34CA661B7F6EBF00F212E8 /* pwd2key.cpp in Sources */, + 5E34CA681B7F6EBF00F212E8 /* sha1.cpp in Sources */, + 5E34CA6A1B7F6EBF00F212E8 /* sha2.cpp in Sources */, + 5E34CA6C1B7F6EBF00F212E8 /* blocksort.c in Sources */, + 5E34CA6D1B7F6EBF00F212E8 /* bzcompress.c in Sources */, + 5E34CA6F1B7F6EBF00F212E8 /* bzlib.c in Sources */, + 5E34CA711B7F6EBF00F212E8 /* crctable.c in Sources */, + 5E34CA721B7F6EBF00F212E8 /* decompress.c in Sources */, + 5E34CA731B7F6EBF00F212E8 /* huffman.c in Sources */, + 5E34CA741B7F6EBF00F212E8 /* randtable.c in Sources */, + 5E34CA761B7F6EBF00F212E8 /* jaricom.c in Sources */, + 5E34CA771B7F6EBF00F212E8 /* jcapimin.c in Sources */, + 5E34CA781B7F6EBF00F212E8 /* jcapistd.c in Sources */, + 5E34CA791B7F6EBF00F212E8 /* jcarith.c in Sources */, + 5E34CA7A1B7F6EBF00F212E8 /* jccoefct.c in Sources */, + 5E34CA7B1B7F6EBF00F212E8 /* jccolor.c in Sources */, + 5E34CA7C1B7F6EBF00F212E8 /* jcdctmgr.c in Sources */, + 5E34CA7D1B7F6EBF00F212E8 /* jchuff.c in Sources */, + 5E34CA7E1B7F6EBF00F212E8 /* jcinit.c in Sources */, + 5E34CA7F1B7F6EBF00F212E8 /* jcmainct.c in Sources */, + 5E34CA801B7F6EBF00F212E8 /* jcmarker.c in Sources */, + 5E34CA811B7F6EBF00F212E8 /* jcmaster.c in Sources */, + 5E34CA821B7F6EC000F212E8 /* jcomapi.c in Sources */, + 5E34CA841B7F6EC000F212E8 /* jcparam.c in Sources */, + 5E34CA851B7F6EC000F212E8 /* jcprepct.c in Sources */, + 5E34CA861B7F6EC000F212E8 /* jcsample.c in Sources */, + 5E34CA871B7F6EC000F212E8 /* jctrans.c in Sources */, + 5E34CA881B7F6EC000F212E8 /* jdapimin.c in Sources */, + 5E34CA891B7F6EC000F212E8 /* jdapistd.c in Sources */, + 5E34CA8A1B7F6EC000F212E8 /* jdarith.c in Sources */, + 5E34CA8B1B7F6EC000F212E8 /* jdatadst.c in Sources */, + 5E34CA8C1B7F6EC000F212E8 /* jdatasrc.c in Sources */, + 5E34CA8D1B7F6EC000F212E8 /* jdcoefct.c in Sources */, + 5E34CA8E1B7F6EC000F212E8 /* jdcolor.c in Sources */, + 5E34CA901B7F6EC000F212E8 /* jddctmgr.c in Sources */, + 5E34CA911B7F6EC000F212E8 /* jdhuff.c in Sources */, + 5E34CA921B7F6EC000F212E8 /* jdinput.c in Sources */, + 5E34CA931B7F6EC000F212E8 /* jdmainct.c in Sources */, + 5E34CA941B7F6EC000F212E8 /* jdmarker.c in Sources */, + 5E34CA951B7F6EC000F212E8 /* jdmaster.c in Sources */, + 5E34CA961B7F6EC000F212E8 /* jdmerge.c in Sources */, + 5E34CA971B7F6EC000F212E8 /* jdpostct.c in Sources */, + 5E34CA981B7F6EC000F212E8 /* jdsample.c in Sources */, + 5E8570BC1B7F9AC400B267D2 /* CIrrDeviceConsole.cpp in Sources */, + 5E34CA991B7F6EC000F212E8 /* jdtrans.c in Sources */, + 5E34CA9A1B7F6EC000F212E8 /* jerror.c in Sources */, + 5E34CA9C1B7F6EC000F212E8 /* jfdctflt.c in Sources */, + 5E34CA9D1B7F6EC000F212E8 /* jfdctfst.c in Sources */, + 5E34CA9E1B7F6EC000F212E8 /* jfdctint.c in Sources */, + 5E34CA9F1B7F6EC000F212E8 /* jidctflt.c in Sources */, + 5E34CAA01B7F6EC000F212E8 /* jidctfst.c in Sources */, + 5E34CAA11B7F6EC000F212E8 /* jidctint.c in Sources */, + 5E34CAA31B7F6EC000F212E8 /* jmemmgr.c in Sources */, + 5E34CAA41B7F6EC000F212E8 /* jmemnobs.c in Sources */, + 5E34CAA91B7F6EC000F212E8 /* jquant1.c in Sources */, + 5E34CAAA1B7F6EC000F212E8 /* jquant2.c in Sources */, + 5E34CAAB1B7F6EC000F212E8 /* jutils.c in Sources */, + 5E34CAAD1B7F6EC000F212E8 /* png.c in Sources */, + 5E34CAB01B7F6EC000F212E8 /* pngerror.c in Sources */, + 5E34CAB11B7F6EC000F212E8 /* pngget.c in Sources */, + 5E34CAB21B7F6EC000F212E8 /* pngmem.c in Sources */, + 5E34CAB31B7F6EC000F212E8 /* pngpread.c in Sources */, + 5E34CAB41B7F6EC000F212E8 /* pngread.c in Sources */, + 5E34CAB51B7F6EC000F212E8 /* pngrio.c in Sources */, + 5E34CAB61B7F6EC000F212E8 /* pngrtran.c in Sources */, + 5E34CAB71B7F6EC000F212E8 /* pngrutil.c in Sources */, + 5E34CAB81B7F6EC000F212E8 /* pngset.c in Sources */, + 5E34CAB91B7F6EC000F212E8 /* pngtrans.c in Sources */, + 5E34CABA1B7F6EC000F212E8 /* pngwio.c in Sources */, + 5E34CABB1B7F6EC000F212E8 /* pngwrite.c in Sources */, + 5E34CABC1B7F6EC000F212E8 /* pngwtran.c in Sources */, + 5E34CABD1B7F6EC000F212E8 /* pngwutil.c in Sources */, + 5E34CABE1B7F6EC000F212E8 /* LzmaDec.c in Sources */, + 5E34CAC11B7F6EC000F212E8 /* adler32.c in Sources */, + 5E34CAC21B7F6EC000F212E8 /* compress.c in Sources */, + 5E34CAC31B7F6EC000F212E8 /* crc32.c in Sources */, + 5E34CAC51B7F6EC000F212E8 /* deflate.c in Sources */, + 5E34CAC71B7F6EC000F212E8 /* inffast.c in Sources */, + 5E34CACA1B7F6EC000F212E8 /* inflate.c in Sources */, + 5E34CACC1B7F6EC000F212E8 /* inftrees.c in Sources */, + 5E34CACE1B7F6EC100F212E8 /* trees.c in Sources */, + 5E34CAD01B7F6EC100F212E8 /* uncompr.c in Sources */, + 5E34CAD31B7F6EC100F212E8 /* zutil.c in Sources */, + 5E34CAD51B7F6EC100F212E8 /* CLogger.cpp in Sources */, + 5E34CAD71B7F6EC100F212E8 /* COSOperator.cpp in Sources */, + 5E34CAD91B7F6EC100F212E8 /* CProfiler.cpp in Sources */, + 5E34CADD1B7F6EC100F212E8 /* Irrlicht.cpp in Sources */, + 5E34CADE1B7F6EC100F212E8 /* leakHunter.cpp in Sources */, + 5E34CADF1B7F6EC100F212E8 /* os.cpp in Sources */, + 5E34CAE11B7F6EC100F212E8 /* utf8.cpp in Sources */, + 5E34CAE21B7F6EC100F212E8 /* CSceneNodeAnimatorCameraFPS.cpp in Sources */, + 5E34CAE41B7F6EC100F212E8 /* CSceneNodeAnimatorCameraMaya.cpp in Sources */, + 5E34CAE61B7F6EC100F212E8 /* CSceneNodeAnimatorCollisionResponse.cpp in Sources */, + 5E34CAE81B7F6EC100F212E8 /* CSceneNodeAnimatorDelete.cpp in Sources */, + 5E34CAEA1B7F6EC100F212E8 /* CSceneNodeAnimatorFlyCircle.cpp in Sources */, + 5E34CAEC1B7F6EC100F212E8 /* CSceneNodeAnimatorFlyStraight.cpp in Sources */, + 5E34CAEE1B7F6EC100F212E8 /* CSceneNodeAnimatorFollowSpline.cpp in Sources */, + 5E34CAF01B7F6EC100F212E8 /* CSceneNodeAnimatorRotation.cpp in Sources */, + 5E34CAF21B7F6EC100F212E8 /* CSceneNodeAnimatorTexture.cpp in Sources */, + 5E34CAF41B7F6EC100F212E8 /* CMetaTriangleSelector.cpp in Sources */, + 5E34CAF61B7F6EC100F212E8 /* COctreeTriangleSelector.cpp in Sources */, + 5E34CAF81B7F6EC100F212E8 /* CSceneCollisionManager.cpp in Sources */, + 5E34CAFA1B7F6EC100F212E8 /* CTerrainTriangleSelector.cpp in Sources */, + 5E34CAFC1B7F6EC100F212E8 /* CTriangleBBSelector.cpp in Sources */, + 5E34CAFE1B7F6EC100F212E8 /* CTriangleSelector.cpp in Sources */, + 5E34CB001B7F6EC100F212E8 /* C3DSMeshFileLoader.cpp in Sources */, + 5E34CB021B7F6EC100F212E8 /* CAnimatedMeshHalfLife.cpp in Sources */, + 5E34CB041B7F6EC100F212E8 /* CAnimatedMeshMD2.cpp in Sources */, + 5E34CB061B7F6EC100F212E8 /* CAnimatedMeshMD3.cpp in Sources */, + 5E34CB081B7F6EC200F212E8 /* CB3DMeshFileLoader.cpp in Sources */, + 5E34CB0A1B7F6EC200F212E8 /* CBSPMeshFileLoader.cpp in Sources */, + 5E34CB0C1B7F6EC200F212E8 /* CColladaFileLoader.cpp in Sources */, + 5E34CB0E1B7F6EC200F212E8 /* CCSMLoader.cpp in Sources */, + 5E34CB101B7F6EC200F212E8 /* CDMFLoader.cpp in Sources */, + 5E34CB121B7F6EC200F212E8 /* CIrrMeshFileLoader.cpp in Sources */, + 5E34CB141B7F6EC200F212E8 /* CLMTSMeshFileLoader.cpp in Sources */, + 5E34CB161B7F6EC200F212E8 /* CLWOMeshFileLoader.cpp in Sources */, + 5E34CB181B7F6EC200F212E8 /* CMD2MeshFileLoader.cpp in Sources */, + 5E34CB1A1B7F6EC200F212E8 /* CMD3MeshFileLoader.cpp in Sources */, + 5E34CB1C1B7F6EC200F212E8 /* CMeshTextureLoader.cpp in Sources */, + 5E34CB1E1B7F6EC200F212E8 /* CMS3DMeshFileLoader.cpp in Sources */, + 5E34CB211B7F6EC200F212E8 /* CMY3DMeshFileLoader.cpp in Sources */, + 5E34CB231B7F6EC200F212E8 /* COBJMeshFileLoader.cpp in Sources */, + 5E34CB251B7F6EC200F212E8 /* COCTLoader.cpp in Sources */, + 5E34CB271B7F6EC200F212E8 /* COgreMeshFileLoader.cpp in Sources */, + 5E34CB291B7F6EC200F212E8 /* CPLYMeshFileLoader.cpp in Sources */, + 5E34CB2B1B7F6EC200F212E8 /* CQ3LevelMesh.cpp in Sources */, + 5E34CB2D1B7F6EC200F212E8 /* CSceneLoaderIrr.cpp in Sources */, + 5E34CB2F1B7F6EC200F212E8 /* CSkinnedMesh.cpp in Sources */, + 5E34CB311B7F6EC200F212E8 /* CSMFMeshFileLoader.cpp in Sources */, + 5E34CB331B7F6EC200F212E8 /* CSTLMeshFileLoader.cpp in Sources */, + 5E34CB351B7F6EC200F212E8 /* CXMeshFileLoader.cpp in Sources */, + 5E34CB381B7F6EC200F212E8 /* CParticleAnimatedMeshSceneNodeEmitter.cpp in Sources */, + 5E34CB3A1B7F6EC200F212E8 /* CParticleAttractionAffector.cpp in Sources */, + 5E34CB3C1B7F6EC300F212E8 /* CParticleBoxEmitter.cpp in Sources */, + 5E34CB3E1B7F6EC300F212E8 /* CParticleCylinderEmitter.cpp in Sources */, + 5E34CB401B7F6EC300F212E8 /* CParticleFadeOutAffector.cpp in Sources */, + 5E34CB421B7F6EC300F212E8 /* CParticleGravityAffector.cpp in Sources */, + 5E34CB441B7F6EC300F212E8 /* CParticleMeshEmitter.cpp in Sources */, + 5E34CB461B7F6EC300F212E8 /* CParticlePointEmitter.cpp in Sources */, + 5E34CB481B7F6EC300F212E8 /* CParticleRingEmitter.cpp in Sources */, + 5E34CB4A1B7F6EC300F212E8 /* CParticleRotationAffector.cpp in Sources */, + 5E34CB4C1B7F6EC300F212E8 /* CParticleScaleAffector.cpp in Sources */, + 5E34CB4E1B7F6EC300F212E8 /* CParticleSphereEmitter.cpp in Sources */, + 5E34CB501B7F6EC300F212E8 /* CParticleSystemSceneNode.cpp in Sources */, + 5E34CB521B7F6EC300F212E8 /* CAnimatedMeshSceneNode.cpp in Sources */, + 5E34CB541B7F6EC300F212E8 /* CBillboardSceneNode.cpp in Sources */, + 5E34CB561B7F6EC300F212E8 /* CBoneSceneNode.cpp in Sources */, + 5E34CB581B7F6EC300F212E8 /* CCameraSceneNode.cpp in Sources */, + 5E34CB5A1B7F6EC300F212E8 /* CCubeSceneNode.cpp in Sources */, + 5E34CB5C1B7F6EC300F212E8 /* CDummyTransformationSceneNode.cpp in Sources */, + 5E34CB5E1B7F6EC300F212E8 /* CEmptySceneNode.cpp in Sources */, + 5E34CB601B7F6EC300F212E8 /* CLightSceneNode.cpp in Sources */, + 5E34CB621B7F6EC300F212E8 /* CMeshSceneNode.cpp in Sources */, + 5E34CB641B7F6EC300F212E8 /* COctreeSceneNode.cpp in Sources */, + 5E34CB661B7F6EC300F212E8 /* CQuake3ShaderSceneNode.cpp in Sources */, + 5E34CB681B7F6EC400F212E8 /* CShadowVolumeSceneNode.cpp in Sources */, + 5E34CB6A1B7F6EC400F212E8 /* CSkyBoxSceneNode.cpp in Sources */, + 5E34CB6C1B7F6EC400F212E8 /* CSkyDomeSceneNode.cpp in Sources */, + 5E34CB6E1B7F6EC400F212E8 /* CSphereSceneNode.cpp in Sources */, + 5E34CB701B7F6EC400F212E8 /* CTerrainSceneNode.cpp in Sources */, + 5E34CB721B7F6EC400F212E8 /* CTextSceneNode.cpp in Sources */, + 5E34CB741B7F6EC400F212E8 /* CVolumeLightSceneNode.cpp in Sources */, + 5E34CB761B7F6EC400F212E8 /* CWaterSurfaceSceneNode.cpp in Sources */, + 5E79089B1C10FEF900DFE7FE /* CB3DMeshWriter.cpp in Sources */, + 5E34CB781B7F6EC400F212E8 /* CColladaMeshWriter.cpp in Sources */, + 5E34CB7A1B7F6EC400F212E8 /* CIrrMeshWriter.cpp in Sources */, + 5E34CB7C1B7F6EC400F212E8 /* COBJMeshWriter.cpp in Sources */, + 5E34CB7E1B7F6EC400F212E8 /* CPLYMeshWriter.cpp in Sources */, + 5E34CB801B7F6EC400F212E8 /* CSTLMeshWriter.cpp in Sources */, + 5E34CB821B7F6EC400F212E8 /* CDefaultSceneNodeAnimatorFactory.cpp in Sources */, + 5E34CB841B7F6EC400F212E8 /* CDefaultSceneNodeFactory.cpp in Sources */, + 5E34CB861B7F6EC400F212E8 /* CGeometryCreator.cpp in Sources */, + 5E34CB881B7F6EC400F212E8 /* CMeshCache.cpp in Sources */, + 5E34CB8A1B7F6EC400F212E8 /* CMeshManipulator.cpp in Sources */, + 5E34CB8C1B7F6EC400F212E8 /* CSceneManager.cpp in Sources */, + 5E34CB8F1B7F6EC400F212E8 /* CBurningShader_Raster_Reference.cpp in Sources */, + 5E34CB901B7F6EC500F212E8 /* CDepthBuffer.cpp in Sources */, + 5E34CB931B7F6EC500F212E8 /* CSoftwareDriver2.cpp in Sources */, + 5E34CB951B7F6EC500F212E8 /* CSoftwareTexture2.cpp in Sources */, + 5E34CB971B7F6EC500F212E8 /* CTRGouraud2.cpp in Sources */, + 5E34CB981B7F6EC500F212E8 /* CTRGouraudAlpha2.cpp in Sources */, + 5E34CB991B7F6EC500F212E8 /* CTRGouraudAlphaNoZ2.cpp in Sources */, + 5E34CB9A1B7F6EC500F212E8 /* CTRNormalMap.cpp in Sources */, + 5E34CB9B1B7F6EC500F212E8 /* CTRStencilShadow.cpp in Sources */, + 5E34CB9C1B7F6EC500F212E8 /* CTRTextureBlend.cpp in Sources */, + 5E34CB9D1B7F6EC500F212E8 /* CTRTextureDetailMap2.cpp in Sources */, + 5E34CB9E1B7F6EC500F212E8 /* CTRTextureGouraud2.cpp in Sources */, + 5E34CB9F1B7F6EC500F212E8 /* CTRTextureGouraudAdd2.cpp in Sources */, + 5E34CBA01B7F6EC500F212E8 /* CTRTextureGouraudAddNoZ2.cpp in Sources */, + 5E34CBA11B7F6EC500F212E8 /* CTRTextureGouraudAlpha.cpp in Sources */, + 5E34CBA21B7F6EC500F212E8 /* CTRTextureGouraudAlphaNoZ.cpp in Sources */, + 5E34CBA31B7F6EC500F212E8 /* CTRTextureGouraudNoZ2.cpp in Sources */, + 5E34CBA41B7F6EC500F212E8 /* CTRTextureGouraudVertexAlpha2.cpp in Sources */, + 5E34CBA51B7F6EC500F212E8 /* CTRTextureLightMap2_Add.cpp in Sources */, + 5E34CBA61B7F6EC500F212E8 /* CTRTextureLightMap2_M1.cpp in Sources */, + 5E34CBA71B7F6EC500F212E8 /* CTRTextureLightMap2_M2.cpp in Sources */, + 5E34CBA81B7F6EC500F212E8 /* CTRTextureLightMap2_M4.cpp in Sources */, + 5E34CBA91B7F6EC500F212E8 /* CTRTextureLightMapGouraud2_M4.cpp in Sources */, + 5E34CBAA1B7F6EC500F212E8 /* CTRTextureWire2.cpp in Sources */, + 5E34CBAB1B7F6EC500F212E8 /* IBurningShader.cpp in Sources */, + 5E34CBB11B7F6EC500F212E8 /* CImageLoaderBMP.cpp in Sources */, + 5E34CBB31B7F6EC500F212E8 /* CImageLoaderDDS.cpp in Sources */, + 5E34CBB51B7F6EC600F212E8 /* CImageLoaderJPG.cpp in Sources */, + 5E34CBB71B7F6EC600F212E8 /* CImageLoaderPCX.cpp in Sources */, + 5E34CBB91B7F6EC600F212E8 /* CImageLoaderPNG.cpp in Sources */, + 5E34CBBB1B7F6EC600F212E8 /* CImageLoaderPPM.cpp in Sources */, + 5E34CBBD1B7F6EC600F212E8 /* CImageLoaderPSD.cpp in Sources */, + 5E34CBBF1B7F6EC600F212E8 /* CImageLoaderPVR.cpp in Sources */, + 5E34CBC11B7F6EC600F212E8 /* CImageLoaderRGB.cpp in Sources */, + 5E34CBC31B7F6EC600F212E8 /* CImageLoaderTGA.cpp in Sources */, + 5E34CBC51B7F6EC600F212E8 /* CImageLoaderWAL.cpp in Sources */, + 5E34CBC71B7F6EC600F212E8 /* CImageWriterBMP.cpp in Sources */, + 5E34CBC91B7F6EC600F212E8 /* CImageWriterJPG.cpp in Sources */, + 5E34CBCB1B7F6EC600F212E8 /* CImageWriterPCX.cpp in Sources */, + 5E34CBCD1B7F6EC600F212E8 /* CImageWriterPNG.cpp in Sources */, + 5E34CBCF1B7F6EC600F212E8 /* CImageWriterPPM.cpp in Sources */, + 5E34CBD11B7F6EC600F212E8 /* CImageWriterPSD.cpp in Sources */, + 5E34CBD31B7F6EC600F212E8 /* CImageWriterTGA.cpp in Sources */, + 5E34CBD51B7F6EC600F212E8 /* CColorConverter.cpp in Sources */, + 5E34CBD71B7F6EC700F212E8 /* CFPSCounter.cpp in Sources */, + 5E34CBD91B7F6EC700F212E8 /* CImage.cpp in Sources */, + 5E34CBDB1B7F6EC700F212E8 /* CNullDriver.cpp in Sources */, + 5E7908971C10EF3F00DFE7FE /* COpenGLCacheHandler.cpp in Sources */, + 5E34CBDE1B7F6EC700F212E8 /* COpenGLDriver.cpp in Sources */, + 5E34CBE01B7F6EC700F212E8 /* COpenGLExtensionHandler.cpp in Sources */, + 5E34CBE31B7F6EC700F212E8 /* COpenGLNormalMapRenderer.cpp in Sources */, + 5E34CBE51B7F6EC700F212E8 /* COpenGLParallaxMapRenderer.cpp in Sources */, + 5E34CBE71B7F6EC700F212E8 /* COpenGLShaderMaterialRenderer.cpp in Sources */, + 5E34CBE91B7F6EC700F212E8 /* COpenGLSLMaterialRenderer.cpp in Sources */, + 5E34CC041B7F6EC800F212E8 /* CSoftwareDriver.cpp in Sources */, + 5E34CC061B7F6EC800F212E8 /* CSoftwareTexture.cpp in Sources */, + 5E34CC081B7F6EC800F212E8 /* CTRFlat.cpp in Sources */, + 5E34CC091B7F6EC800F212E8 /* CTRFlatWire.cpp in Sources */, + 5E34CC0A1B7F6EC800F212E8 /* CTRGouraud.cpp in Sources */, + 5E34CC0B1B7F6EC800F212E8 /* CTRGouraudWire.cpp in Sources */, + 5E34CC0C1B7F6EC800F212E8 /* CTRTextureFlat.cpp in Sources */, + 5E34CC0D1B7F6EC800F212E8 /* CTRTextureFlatWire.cpp in Sources */, + 5E34CC0E1B7F6EC800F212E8 /* CTRTextureGouraud.cpp in Sources */, + 5E34CC101B7F6EC800F212E8 /* CTRTextureGouraudAdd.cpp in Sources */, + 5E34CC111B7F6EC800F212E8 /* CTRTextureGouraudNoZ.cpp in Sources */, + 5E34CC121B7F6EC900F212E8 /* CTRTextureGouraudWire.cpp in Sources */, + 5E34CC131B7F6EC900F212E8 /* CZBuffer.cpp in Sources */, + 5E34CC191B7F6EC900F212E8 /* CNSOGLManager.mm in Sources */, + 5E34CC1A1B7F6EC900F212E8 /* CVideoModeList.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5E5732B21C18E212003F664E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E57340E1C18E2E2003F664E /* COGLES2MaterialRenderer.cpp in Sources */, + 5E5732B31C18E212003F664E /* CDefaultGUIElementFactory.cpp in Sources */, + 5E5732B41C18E212003F664E /* CGUIButton.cpp in Sources */, + 5E5732B51C18E212003F664E /* CGUICheckBox.cpp in Sources */, + 5E5732B61C18E212003F664E /* CGUIColorSelectDialog.cpp in Sources */, + 5E5732B71C18E212003F664E /* CGUIComboBox.cpp in Sources */, + 5E5732B81C18E212003F664E /* CGUIContextMenu.cpp in Sources */, + 5E5732B91C18E212003F664E /* CGUIEditBox.cpp in Sources */, + 5E5732BA1C18E212003F664E /* CGUIEnvironment.cpp in Sources */, + 5E5732BB1C18E212003F664E /* CGUIFileOpenDialog.cpp in Sources */, + 5E5732BC1C18E212003F664E /* CGUIFont.cpp in Sources */, + 5E5732BD1C18E212003F664E /* CGUIImage.cpp in Sources */, + 5E5732BE1C18E212003F664E /* CGUIImageList.cpp in Sources */, + 5E5732BF1C18E212003F664E /* CGUIInOutFader.cpp in Sources */, + 5E5732C01C18E212003F664E /* CGUIListBox.cpp in Sources */, + 5E5732C11C18E212003F664E /* CGUIMenu.cpp in Sources */, + 5E5732C21C18E212003F664E /* CGUIMeshViewer.cpp in Sources */, + 5E5732C31C18E212003F664E /* CGUIMessageBox.cpp in Sources */, + 5E5732C41C18E212003F664E /* CGUIModalScreen.cpp in Sources */, + 5E5732C51C18E212003F664E /* CGUIProfiler.cpp in Sources */, + 5E5732C61C18E212003F664E /* CGUIScrollBar.cpp in Sources */, + 5E5732C71C18E212003F664E /* CGUISkin.cpp in Sources */, + 5E5732C81C18E212003F664E /* CGUISpinBox.cpp in Sources */, + 5E5732C91C18E212003F664E /* CGUISpriteBank.cpp in Sources */, + 5E5732CA1C18E212003F664E /* CGUIStaticText.cpp in Sources */, + 5E5732CB1C18E212003F664E /* CGUITabControl.cpp in Sources */, + 5E5732CC1C18E212003F664E /* CGUITable.cpp in Sources */, + 5E5732CD1C18E212003F664E /* CGUIToolBar.cpp in Sources */, + 5E5732CE1C18E212003F664E /* CGUITreeView.cpp in Sources */, + 5E5732CF1C18E212003F664E /* CGUIWindow.cpp in Sources */, + 5E5732D01C18E212003F664E /* CAttributes.cpp in Sources */, + 5E5732D11C18E212003F664E /* CFileList.cpp in Sources */, + 5E5732D21C18E212003F664E /* CFileSystem.cpp in Sources */, + 5E5732D31C18E212003F664E /* CLimitReadFile.cpp in Sources */, + 5E5732D41C18E212003F664E /* CMemoryFile.cpp in Sources */, + 5E5732D51C18E212003F664E /* CMountPointReader.cpp in Sources */, + 5E5732D61C18E212003F664E /* CNPKReader.cpp in Sources */, + 5E5732D71C18E212003F664E /* CPakReader.cpp in Sources */, + 5E5732D81C18E212003F664E /* CReadFile.cpp in Sources */, + 5E5732D91C18E212003F664E /* CTarReader.cpp in Sources */, + 5E5732DA1C18E212003F664E /* CWADReader.cpp in Sources */, + 5E5732DB1C18E212003F664E /* CWriteFile.cpp in Sources */, + 5E5732DC1C18E212003F664E /* CXMLReader.cpp in Sources */, + 5E5732DD1C18E212003F664E /* CXMLWriter.cpp in Sources */, + 5E5732DE1C18E212003F664E /* CZipReader.cpp in Sources */, + 5E5732DF1C18E212003F664E /* irrXML.cpp in Sources */, + 5E5732E11C18E212003F664E /* CIrrDeviceStub.cpp in Sources */, + 5E5732E21C18E212003F664E /* aescrypt.cpp in Sources */, + 5E5732E31C18E212003F664E /* aeskey.cpp in Sources */, + 5E5732E41C18E212003F664E /* aestab.cpp in Sources */, + 5E5732E51C18E212003F664E /* fileenc.cpp in Sources */, + 5E5732E61C18E212003F664E /* hmac.cpp in Sources */, + 5E5732E71C18E212003F664E /* prng.cpp in Sources */, + 5E5732E81C18E212003F664E /* pwd2key.cpp in Sources */, + 5E5732E91C18E212003F664E /* sha1.cpp in Sources */, + 5E5732EA1C18E212003F664E /* sha2.cpp in Sources */, + 5E5732EB1C18E212003F664E /* blocksort.c in Sources */, + 5E5732EC1C18E212003F664E /* bzcompress.c in Sources */, + 5E5732ED1C18E212003F664E /* bzlib.c in Sources */, + 5E5732EE1C18E212003F664E /* crctable.c in Sources */, + 5E5732EF1C18E212003F664E /* decompress.c in Sources */, + 5E5732F01C18E212003F664E /* huffman.c in Sources */, + 5E5732F11C18E212003F664E /* randtable.c in Sources */, + 5E5732F21C18E212003F664E /* jaricom.c in Sources */, + 5E5732F31C18E212003F664E /* jcapimin.c in Sources */, + 5E5732F41C18E212003F664E /* jcapistd.c in Sources */, + 5E5732F51C18E212003F664E /* jcarith.c in Sources */, + 5E5732F61C18E212003F664E /* jccoefct.c in Sources */, + 5E5732F71C18E212003F664E /* jccolor.c in Sources */, + 5E5734081C18E2E2003F664E /* COGLES2Driver.cpp in Sources */, + 5E5732F81C18E212003F664E /* jcdctmgr.c in Sources */, + 5E5732F91C18E212003F664E /* jchuff.c in Sources */, + 5E5732FA1C18E212003F664E /* jcinit.c in Sources */, + 5E5732FB1C18E212003F664E /* jcmainct.c in Sources */, + 5E5732FC1C18E212003F664E /* jcmarker.c in Sources */, + 5E5732FD1C18E212003F664E /* jcmaster.c in Sources */, + 5E5732FE1C18E212003F664E /* jcomapi.c in Sources */, + 5E5732FF1C18E212003F664E /* jcparam.c in Sources */, + 5E5733001C18E212003F664E /* jcprepct.c in Sources */, + 5E5733011C18E212003F664E /* jcsample.c in Sources */, + 5E5733021C18E212003F664E /* jctrans.c in Sources */, + 5E5733031C18E212003F664E /* jdapimin.c in Sources */, + 5E5733041C18E212003F664E /* jdapistd.c in Sources */, + 5E5733051C18E212003F664E /* jdarith.c in Sources */, + 5E5733061C18E212003F664E /* jdatadst.c in Sources */, + 5E5733071C18E212003F664E /* jdatasrc.c in Sources */, + 5E5733081C18E212003F664E /* jdcoefct.c in Sources */, + 5E5733091C18E212003F664E /* jdcolor.c in Sources */, + 5E57330A1C18E212003F664E /* jddctmgr.c in Sources */, + 5E57330B1C18E212003F664E /* jdhuff.c in Sources */, + 5E57340C1C18E2E2003F664E /* COGLES2FixedPipelineRenderer.cpp in Sources */, + 5E57330C1C18E212003F664E /* jdinput.c in Sources */, + 5E57330D1C18E212003F664E /* jdmainct.c in Sources */, + 5E57330E1C18E212003F664E /* jdmarker.c in Sources */, + 5E57330F1C18E212003F664E /* jdmaster.c in Sources */, + 5E5733101C18E212003F664E /* jdmerge.c in Sources */, + 5E5733111C18E212003F664E /* jdpostct.c in Sources */, + 5E5733121C18E212003F664E /* jdsample.c in Sources */, + 5E5733131C18E212003F664E /* CIrrDeviceConsole.cpp in Sources */, + 5E5733141C18E212003F664E /* jdtrans.c in Sources */, + 5E5733151C18E212003F664E /* jerror.c in Sources */, + 5E5733161C18E212003F664E /* jfdctflt.c in Sources */, + 5E5733171C18E212003F664E /* jfdctfst.c in Sources */, + 5E5733181C18E212003F664E /* jfdctint.c in Sources */, + 5E5733191C18E212003F664E /* jidctflt.c in Sources */, + 5E57331A1C18E212003F664E /* jidctfst.c in Sources */, + 5E57331B1C18E212003F664E /* jidctint.c in Sources */, + 5E57331C1C18E212003F664E /* jmemmgr.c in Sources */, + 5E57331D1C18E212003F664E /* jmemnobs.c in Sources */, + 5E57331E1C18E212003F664E /* jquant1.c in Sources */, + 5E57331F1C18E212003F664E /* jquant2.c in Sources */, + 5E5733201C18E212003F664E /* jutils.c in Sources */, + 5E5733211C18E212003F664E /* png.c in Sources */, + 5E5733221C18E212003F664E /* pngerror.c in Sources */, + 5E5733231C18E212003F664E /* pngget.c in Sources */, + 5E5733241C18E212003F664E /* pngmem.c in Sources */, + 5E5733251C18E212003F664E /* pngpread.c in Sources */, + 5E5733261C18E212003F664E /* pngread.c in Sources */, + 5E5733271C18E212003F664E /* pngrio.c in Sources */, + 5E5733281C18E212003F664E /* pngrtran.c in Sources */, + 5E5733291C18E212003F664E /* pngrutil.c in Sources */, + 5E9573D71C18E9E600C27989 /* CEAGLManager.mm in Sources */, + 5E57332A1C18E212003F664E /* pngset.c in Sources */, + 5E57332B1C18E212003F664E /* pngtrans.c in Sources */, + 5E57332C1C18E212003F664E /* pngwio.c in Sources */, + 5E57332D1C18E212003F664E /* pngwrite.c in Sources */, + 5E57332E1C18E212003F664E /* pngwtran.c in Sources */, + 5E57332F1C18E212003F664E /* pngwutil.c in Sources */, + 5E5733301C18E212003F664E /* LzmaDec.c in Sources */, + 5E5733311C18E212003F664E /* adler32.c in Sources */, + 5E5733321C18E212003F664E /* compress.c in Sources */, + 5E5733331C18E212003F664E /* crc32.c in Sources */, + 5E5733341C18E212003F664E /* deflate.c in Sources */, + 5E5733351C18E212003F664E /* inffast.c in Sources */, + 5E5733361C18E212003F664E /* inflate.c in Sources */, + 5E5733371C18E212003F664E /* inftrees.c in Sources */, + 5E5733381C18E212003F664E /* trees.c in Sources */, + 5E5733391C18E212003F664E /* uncompr.c in Sources */, + 5E57333A1C18E212003F664E /* zutil.c in Sources */, + 5E57333B1C18E212003F664E /* CLogger.cpp in Sources */, + 5E57333C1C18E212003F664E /* COSOperator.cpp in Sources */, + 5E57333D1C18E212003F664E /* CProfiler.cpp in Sources */, + 5E57333E1C18E212003F664E /* Irrlicht.cpp in Sources */, + 5E57333F1C18E212003F664E /* leakHunter.cpp in Sources */, + 5E5733401C18E212003F664E /* os.cpp in Sources */, + 5E5733411C18E212003F664E /* utf8.cpp in Sources */, + 5E5733421C18E212003F664E /* CSceneNodeAnimatorCameraFPS.cpp in Sources */, + 5E5733431C18E212003F664E /* CSceneNodeAnimatorCameraMaya.cpp in Sources */, + 5E5733441C18E212003F664E /* CSceneNodeAnimatorCollisionResponse.cpp in Sources */, + 5E5733451C18E212003F664E /* CSceneNodeAnimatorDelete.cpp in Sources */, + 5E5733461C18E212003F664E /* CSceneNodeAnimatorFlyCircle.cpp in Sources */, + 5E5733471C18E212003F664E /* CSceneNodeAnimatorFlyStraight.cpp in Sources */, + 5E5733481C18E212003F664E /* CSceneNodeAnimatorFollowSpline.cpp in Sources */, + 5E5733491C18E212003F664E /* CSceneNodeAnimatorRotation.cpp in Sources */, + 5E57334A1C18E212003F664E /* CSceneNodeAnimatorTexture.cpp in Sources */, + 5E57334B1C18E212003F664E /* CMetaTriangleSelector.cpp in Sources */, + 5E57334C1C18E212003F664E /* COctreeTriangleSelector.cpp in Sources */, + 5E57334D1C18E212003F664E /* CSceneCollisionManager.cpp in Sources */, + 5E57334E1C18E212003F664E /* CTerrainTriangleSelector.cpp in Sources */, + 5E57334F1C18E212003F664E /* CTriangleBBSelector.cpp in Sources */, + 5E5733501C18E212003F664E /* CTriangleSelector.cpp in Sources */, + 5E5733511C18E212003F664E /* C3DSMeshFileLoader.cpp in Sources */, + 5E5733521C18E212003F664E /* CAnimatedMeshHalfLife.cpp in Sources */, + 5E5733531C18E212003F664E /* CAnimatedMeshMD2.cpp in Sources */, + 5E5733541C18E212003F664E /* CAnimatedMeshMD3.cpp in Sources */, + 5E5733551C18E212003F664E /* CB3DMeshFileLoader.cpp in Sources */, + 5E5733561C18E212003F664E /* CBSPMeshFileLoader.cpp in Sources */, + 5E5733571C18E212003F664E /* CColladaFileLoader.cpp in Sources */, + 5E5733581C18E212003F664E /* CCSMLoader.cpp in Sources */, + 5E5733591C18E212003F664E /* CDMFLoader.cpp in Sources */, + 5E57335A1C18E212003F664E /* CIrrMeshFileLoader.cpp in Sources */, + 5E57335B1C18E212003F664E /* CLMTSMeshFileLoader.cpp in Sources */, + 5E57335C1C18E212003F664E /* CLWOMeshFileLoader.cpp in Sources */, + 5E57335D1C18E212003F664E /* CMD2MeshFileLoader.cpp in Sources */, + 5E57335E1C18E212003F664E /* CMD3MeshFileLoader.cpp in Sources */, + 5E57335F1C18E212003F664E /* CMeshTextureLoader.cpp in Sources */, + 5E5733601C18E212003F664E /* CMS3DMeshFileLoader.cpp in Sources */, + 5E5733611C18E212003F664E /* CMY3DMeshFileLoader.cpp in Sources */, + 5E5733621C18E212003F664E /* COBJMeshFileLoader.cpp in Sources */, + 5E5733631C18E212003F664E /* COCTLoader.cpp in Sources */, + 5E5733641C18E212003F664E /* COgreMeshFileLoader.cpp in Sources */, + 5E5733651C18E212003F664E /* CPLYMeshFileLoader.cpp in Sources */, + 5E5733661C18E212003F664E /* CQ3LevelMesh.cpp in Sources */, + 5E5733671C18E212003F664E /* CSceneLoaderIrr.cpp in Sources */, + 5E5733681C18E212003F664E /* CSkinnedMesh.cpp in Sources */, + 5E5733691C18E212003F664E /* CSMFMeshFileLoader.cpp in Sources */, + 5E57336A1C18E212003F664E /* CSTLMeshFileLoader.cpp in Sources */, + 5E57336B1C18E212003F664E /* CXMeshFileLoader.cpp in Sources */, + 5E57336C1C18E212003F664E /* CParticleAnimatedMeshSceneNodeEmitter.cpp in Sources */, + 5E57336D1C18E212003F664E /* CParticleAttractionAffector.cpp in Sources */, + 5E57336E1C18E212003F664E /* CParticleBoxEmitter.cpp in Sources */, + 5E57336F1C18E212003F664E /* CParticleCylinderEmitter.cpp in Sources */, + 5E5733701C18E212003F664E /* CParticleFadeOutAffector.cpp in Sources */, + 5E5733711C18E212003F664E /* CParticleGravityAffector.cpp in Sources */, + 5E5733721C18E212003F664E /* CParticleMeshEmitter.cpp in Sources */, + 5E5733731C18E212003F664E /* CParticlePointEmitter.cpp in Sources */, + 5E5733741C18E212003F664E /* CParticleRingEmitter.cpp in Sources */, + 5E5733751C18E212003F664E /* CParticleRotationAffector.cpp in Sources */, + 5E5733761C18E212003F664E /* CParticleScaleAffector.cpp in Sources */, + 5E5733771C18E212003F664E /* CParticleSphereEmitter.cpp in Sources */, + 5E5733781C18E212003F664E /* CParticleSystemSceneNode.cpp in Sources */, + 5E5733791C18E212003F664E /* CAnimatedMeshSceneNode.cpp in Sources */, + 5E5734141C18E2E2003F664E /* COGLES2Renderer2D.cpp in Sources */, + 5E57337A1C18E212003F664E /* CBillboardSceneNode.cpp in Sources */, + 5E57337B1C18E212003F664E /* CBoneSceneNode.cpp in Sources */, + 5E57337C1C18E212003F664E /* CCameraSceneNode.cpp in Sources */, + 5E57337D1C18E212003F664E /* CCubeSceneNode.cpp in Sources */, + 5E5734101C18E2E2003F664E /* COGLES2NormalMapRenderer.cpp in Sources */, + 5E57337E1C18E212003F664E /* CDummyTransformationSceneNode.cpp in Sources */, + 5E57337F1C18E212003F664E /* CEmptySceneNode.cpp in Sources */, + 5E5733801C18E212003F664E /* CLightSceneNode.cpp in Sources */, + 5E5733811C18E212003F664E /* CMeshSceneNode.cpp in Sources */, + 5E5733821C18E212003F664E /* COctreeSceneNode.cpp in Sources */, + 5E5733831C18E212003F664E /* CQuake3ShaderSceneNode.cpp in Sources */, + 5E5733841C18E212003F664E /* CShadowVolumeSceneNode.cpp in Sources */, + 5E5733851C18E212003F664E /* CSkyBoxSceneNode.cpp in Sources */, + 5E5733861C18E212003F664E /* CSkyDomeSceneNode.cpp in Sources */, + 5E5733871C18E212003F664E /* CSphereSceneNode.cpp in Sources */, + 5E5733881C18E212003F664E /* CTerrainSceneNode.cpp in Sources */, + 5E5733F31C18E2C0003F664E /* COGLESDriver.cpp in Sources */, + 5E5733891C18E212003F664E /* CTextSceneNode.cpp in Sources */, + 5E57338A1C18E212003F664E /* CVolumeLightSceneNode.cpp in Sources */, + 5E57338B1C18E212003F664E /* CWaterSurfaceSceneNode.cpp in Sources */, + 5E57338C1C18E212003F664E /* CB3DMeshWriter.cpp in Sources */, + 5E57338D1C18E212003F664E /* CColladaMeshWriter.cpp in Sources */, + 5E57338E1C18E212003F664E /* CIrrMeshWriter.cpp in Sources */, + 5E57338F1C18E212003F664E /* COBJMeshWriter.cpp in Sources */, + 5E5733901C18E212003F664E /* CPLYMeshWriter.cpp in Sources */, + 5E57340A1C18E2E2003F664E /* COGLES2ExtensionHandler.cpp in Sources */, + 5E5733911C18E212003F664E /* CSTLMeshWriter.cpp in Sources */, + 5E5733921C18E212003F664E /* CDefaultSceneNodeAnimatorFactory.cpp in Sources */, + 5E5733931C18E212003F664E /* CDefaultSceneNodeFactory.cpp in Sources */, + 5E5733941C18E212003F664E /* CGeometryCreator.cpp in Sources */, + 5E5733951C18E212003F664E /* CMeshCache.cpp in Sources */, + 5E5733961C18E212003F664E /* CMeshManipulator.cpp in Sources */, + 5E5733971C18E212003F664E /* CSceneManager.cpp in Sources */, + 5E5733981C18E212003F664E /* CBurningShader_Raster_Reference.cpp in Sources */, + 5E5734121C18E2E2003F664E /* COGLES2ParallaxMapRenderer.cpp in Sources */, + 5E5733991C18E212003F664E /* CDepthBuffer.cpp in Sources */, + 5E57339A1C18E212003F664E /* CSoftwareDriver2.cpp in Sources */, + 5E57339B1C18E212003F664E /* CSoftwareTexture2.cpp in Sources */, + 5E57339C1C18E212003F664E /* CTRGouraud2.cpp in Sources */, + 5E57339D1C18E212003F664E /* CTRGouraudAlpha2.cpp in Sources */, + 5E57339E1C18E212003F664E /* CTRGouraudAlphaNoZ2.cpp in Sources */, + 5E57339F1C18E212003F664E /* CTRNormalMap.cpp in Sources */, + 5E5733A01C18E212003F664E /* CTRStencilShadow.cpp in Sources */, + 5E5733A11C18E212003F664E /* CTRTextureBlend.cpp in Sources */, + 5E5733A21C18E212003F664E /* CTRTextureDetailMap2.cpp in Sources */, + 5E5733A31C18E212003F664E /* CTRTextureGouraud2.cpp in Sources */, + 5E5733A41C18E212003F664E /* CTRTextureGouraudAdd2.cpp in Sources */, + 5E5733A51C18E212003F664E /* CTRTextureGouraudAddNoZ2.cpp in Sources */, + 5E5733A61C18E212003F664E /* CTRTextureGouraudAlpha.cpp in Sources */, + 5E5733A71C18E212003F664E /* CTRTextureGouraudAlphaNoZ.cpp in Sources */, + 5E5733A81C18E212003F664E /* CTRTextureGouraudNoZ2.cpp in Sources */, + 5E5733A91C18E212003F664E /* CTRTextureGouraudVertexAlpha2.cpp in Sources */, + 5E5733AA1C18E212003F664E /* CTRTextureLightMap2_Add.cpp in Sources */, + 5E5733F51C18E2C0003F664E /* COGLESExtensionHandler.cpp in Sources */, + 5E5733AB1C18E212003F664E /* CTRTextureLightMap2_M1.cpp in Sources */, + 5E5733AC1C18E212003F664E /* CTRTextureLightMap2_M2.cpp in Sources */, + 5E5733AD1C18E212003F664E /* CTRTextureLightMap2_M4.cpp in Sources */, + 5E5733AE1C18E212003F664E /* CTRTextureLightMapGouraud2_M4.cpp in Sources */, + 5E5733AF1C18E212003F664E /* CTRTextureWire2.cpp in Sources */, + 5E5733B01C18E212003F664E /* IBurningShader.cpp in Sources */, + 5E5733B11C18E212003F664E /* CImageLoaderBMP.cpp in Sources */, + 5E5733B21C18E212003F664E /* CImageLoaderDDS.cpp in Sources */, + 5E5733B31C18E212003F664E /* CImageLoaderJPG.cpp in Sources */, + 5E5733B41C18E212003F664E /* CImageLoaderPCX.cpp in Sources */, + 5E5733B51C18E212003F664E /* CImageLoaderPNG.cpp in Sources */, + 5E5733B61C18E212003F664E /* CImageLoaderPPM.cpp in Sources */, + 5E5733B71C18E212003F664E /* CImageLoaderPSD.cpp in Sources */, + 5E5733B81C18E212003F664E /* CImageLoaderPVR.cpp in Sources */, + 5E5733B91C18E212003F664E /* CImageLoaderRGB.cpp in Sources */, + 5E5733BA1C18E212003F664E /* CImageLoaderTGA.cpp in Sources */, + 5E5733BB1C18E212003F664E /* CImageLoaderWAL.cpp in Sources */, + 5E5733BC1C18E212003F664E /* CImageWriterBMP.cpp in Sources */, + 5E5733BD1C18E212003F664E /* CImageWriterJPG.cpp in Sources */, + 5E5733BE1C18E212003F664E /* CImageWriterPCX.cpp in Sources */, + 5E5733BF1C18E212003F664E /* CImageWriterPNG.cpp in Sources */, + 5E5733C01C18E212003F664E /* CImageWriterPPM.cpp in Sources */, + 5E5733C11C18E212003F664E /* CImageWriterPSD.cpp in Sources */, + 5E5733C21C18E212003F664E /* CImageWriterTGA.cpp in Sources */, + 5E5733C31C18E212003F664E /* CColorConverter.cpp in Sources */, + 5E5733C41C18E212003F664E /* CFPSCounter.cpp in Sources */, + 5E5733C51C18E212003F664E /* CImage.cpp in Sources */, + 5E5733C61C18E212003F664E /* CNullDriver.cpp in Sources */, + 5E5733C71C18E212003F664E /* COpenGLCacheHandler.cpp in Sources */, + 5E5733C81C18E212003F664E /* COpenGLDriver.cpp in Sources */, + 5E5733C91C18E212003F664E /* COpenGLExtensionHandler.cpp in Sources */, + 5E5733CA1C18E212003F664E /* COpenGLNormalMapRenderer.cpp in Sources */, + 5E5733CB1C18E212003F664E /* COpenGLParallaxMapRenderer.cpp in Sources */, + 5E5733CC1C18E212003F664E /* COpenGLShaderMaterialRenderer.cpp in Sources */, + 5E5733CD1C18E212003F664E /* COpenGLSLMaterialRenderer.cpp in Sources */, + 5E5733CE1C18E212003F664E /* CSoftwareDriver.cpp in Sources */, + 5E5733CF1C18E212003F664E /* CSoftwareTexture.cpp in Sources */, + 5E5733D01C18E212003F664E /* CTRFlat.cpp in Sources */, + 5E5733D11C18E212003F664E /* CTRFlatWire.cpp in Sources */, + 5E5733D21C18E212003F664E /* CTRGouraud.cpp in Sources */, + 5E5733D31C18E212003F664E /* CTRGouraudWire.cpp in Sources */, + 5E5733D41C18E212003F664E /* CTRTextureFlat.cpp in Sources */, + 5E5733D51C18E212003F664E /* CTRTextureFlatWire.cpp in Sources */, + 5E5733D61C18E212003F664E /* CTRTextureGouraud.cpp in Sources */, + 5E5733D71C18E212003F664E /* CTRTextureGouraudAdd.cpp in Sources */, + 5E5733D81C18E212003F664E /* CTRTextureGouraudNoZ.cpp in Sources */, + 5E5733D91C18E212003F664E /* CTRTextureGouraudWire.cpp in Sources */, + 5E5733DA1C18E212003F664E /* CZBuffer.cpp in Sources */, + 5E5733DB1C18E212003F664E /* CNSOGLManager.mm in Sources */, + 5E5733DC1C18E212003F664E /* CVideoModeList.cpp in Sources */, + 5E5733E91C18E254003F664E /* CIrrDeviceiOS.mm in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5E34C6DD1B7F4A0C00F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + DEPLOYMENT_LOCATION = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = "DEBUG=1"; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INSTALL_PATH = /; + ONLY_ACTIVE_ARCH = YES; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-U__STRICT_ANSI__", + ); + }; + name = Debug; + }; + 5E34C6DE1B7F4A0C00F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + DEPLOYMENT_LOCATION = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c11; + GCC_NO_COMMON_BLOCKS = YES; + "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = "NDEBUG=1"; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INSTALL_PATH = /; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-U__STRICT_ANSI__", + ); + }; + name = Release; + }; + 5E34C9F61B7F6E3400F212E8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_OBJC_ARC = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DSTROOT = "$(SRCROOT)/../../lib/OSX"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + EXECUTABLE_PREFIX = lib; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = Irrlicht; + SDKROOT = macosx; + }; + name = Debug; + }; + 5E34C9F71B7F6E3400F212E8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_OBJC_ARC = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DSTROOT = "$(SRCROOT)/../../lib/OSX"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + EXECUTABLE_PREFIX = lib; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.9; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = Irrlicht; + SDKROOT = macosx; + }; + name = Release; + }; + 5E5733E31C18E212003F664E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DSTROOT = "$(SRCROOT)/../../lib/iOS"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + EXECUTABLE_PREFIX = lib; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_MODULE_NAME = Irrlicht; + PRODUCT_NAME = Irrlicht; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 5E5733E41C18E212003F664E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DSTROOT = "$(SRCROOT)/../../lib/iOS"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + EXECUTABLE_PREFIX = lib; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_MODULE_NAME = Irrlicht; + PRODUCT_NAME = Irrlicht; + SDKROOT = iphoneos; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E34C6DC1B7F4A0C00F212E8 /* Build configuration list for PBXProject "Irrlicht" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C6DD1B7F4A0C00F212E8 /* Debug */, + 5E34C6DE1B7F4A0C00F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E34C9F51B7F6E3400F212E8 /* Build configuration list for PBXNativeTarget "Irrlicht_OSX" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E34C9F61B7F6E3400F212E8 /* Debug */, + 5E34C9F71B7F6E3400F212E8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E5733E21C18E212003F664E /* Build configuration list for PBXNativeTarget "Irrlicht_iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E5733E31C18E212003F664E /* Debug */, + 5E5733E41C18E212003F664E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E34C6D91B7F4A0C00F212E8 /* Project object */; +} diff --git a/source/Irrlicht/Irrlicht.xcodeproj/xcshareddata/xcschemes/Irrlicht_OSX.xcscheme b/source/Irrlicht/Irrlicht.xcodeproj/xcshareddata/xcschemes/Irrlicht_OSX.xcscheme new file mode 100644 index 00000000..9448ffc3 --- /dev/null +++ b/source/Irrlicht/Irrlicht.xcodeproj/xcshareddata/xcschemes/Irrlicht_OSX.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/Irrlicht/Irrlicht.xcodeproj/xcshareddata/xcschemes/Irrlicht_iOS.xcscheme b/source/Irrlicht/Irrlicht.xcodeproj/xcshareddata/xcschemes/Irrlicht_iOS.xcscheme new file mode 100644 index 00000000..2fbdaf6b --- /dev/null +++ b/source/Irrlicht/Irrlicht.xcodeproj/xcshareddata/xcschemes/Irrlicht_iOS.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/Irrlicht/Irrlicht10.0.sln b/source/Irrlicht/Irrlicht10.0.sln new file mode 100644 index 00000000..f3dcbb4e --- /dev/null +++ b/source/Irrlicht/Irrlicht10.0.sln @@ -0,0 +1,50 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Irrlicht", "Irrlicht10.0.vcxproj", "{E08E042A-6C45-411B-92BE-3CC31331019F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release - Fast FPU|Win32 = Release - Fast FPU|Win32 + Release - Fast FPU|x64 = Release - Fast FPU|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + Static lib - Debug|Win32 = Static lib - Debug|Win32 + Static lib - Debug|x64 = Static lib - Debug|x64 + Static lib - Release - Fast FPU|Win32 = Static lib - Release - Fast FPU|Win32 + Static lib - Release - Fast FPU|x64 = Static lib - Release - Fast FPU|x64 + Static lib - Release|Win32 = Static lib - Release|Win32 + Static lib - Release|x64 = Static lib - Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.ActiveCfg = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.Build.0 = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.ActiveCfg = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.Build.0 = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.ActiveCfg = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.Build.0 = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.ActiveCfg = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.Build.0 = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.ActiveCfg = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.Build.0 = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.ActiveCfg = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.Build.0 = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.ActiveCfg = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.Build.0 = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.ActiveCfg = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.Build.0 = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.Build.0 = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.ActiveCfg = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.Build.0 = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.ActiveCfg = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.Build.0 = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.ActiveCfg = Static lib - Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.Build.0 = Static lib - Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/source/Irrlicht/Irrlicht10.0.vcxproj b/source/Irrlicht/Irrlicht10.0.vcxproj new file mode 100644 index 00000000..78c279ca --- /dev/null +++ b/source/Irrlicht/Irrlicht10.0.vcxproj @@ -0,0 +1,1600 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release - Fast FPU + Win32 + + + Release - Fast FPU + x64 + + + Release + Win32 + + + Release + x64 + + + SDL-Debug + Win32 + + + SDL-Debug + x64 + + + Static lib - Debug + Win32 + + + Static lib - Debug + x64 + + + Static lib - Release - Fast FPU + Win32 + + + Static lib - Release - Fast FPU + x64 + + + Static lib - Release + Win32 + + + Static lib - Release + x64 + + + + Irrlicht + {E08E042A-6C45-411B-92BE-3CC31331019F} + Irrlicht + + + + DynamicLibrary + NotSet + Windows7.1SDK + + + DynamicLibrary + NotSet + Windows7.1SDK + + + StaticLibrary + MultiByte + true + Windows7.1SDK + + + StaticLibrary + MultiByte + true + Windows7.1SDK + + + StaticLibrary + MultiByte + true + Windows7.1SDK + + + StaticLibrary + MultiByte + true + Windows7.1SDK + + + StaticLibrary + NotSet + Windows7.1SDK + + + StaticLibrary + NotSet + Windows7.1SDK + + + DynamicLibrary + MultiByte + true + Windows7.1SDK + + + DynamicLibrary + MultiByte + true + Windows7.1SDK + + + DynamicLibrary + MultiByte + true + Windows7.1SDK + + + DynamicLibrary + MultiByte + true + Windows7.1SDK + + + DynamicLibrary + NotSet + Windows7.1SDK + + + DynamicLibrary + NotSet + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + false + false + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + false + false + ..\..\lib\Win32-VisualStudio\ + ..\..\lib\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + ..\..\lib\Win32-VisualStudio\ + ..\..\lib\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + ..\..\lib\Win32-VisualStudio\ + ..\..\lib\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + true + true + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + obj\$(Configuration)\ + obj\$(Configuration)64\ + true + true + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Debug/Irrlicht.tlb + + + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions); _ITERATOR_DEBUG_LEVEL=0 + + + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + Disabled + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + 1.9 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\..\Debug/Irrlicht.tlb + + + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions); _ITERATOR_DEBUG_LEVEL=0 + + + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + Disabled + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Level3 + + + Default + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + false + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + 1.9 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Level3 + + + Default + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + kernel32.lib;user32.lib;gdi32.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + $(TargetDir)$(TargetName).pdb + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + Default + false + false + StreamingSIMDExtensions2 + Fast + false + Level3 + + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + false + true + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + Windows + 1.9 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + Default + false + false + StreamingSIMDExtensions2 + Fast + false + Level3 + + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + false + true + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + Windows + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions); _ITERATOR_DEBUG_LEVEL=0 + + + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win32-visualstudio\Irrlicht.lib + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions); _ITERATOR_DEBUG_LEVEL=0 + + + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win64-visualstudio\Irrlicht.lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + false + false + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Level3 + + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win32-visualstudio\Irrlicht.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + false + false + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Level3 + + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win64-visualstudio\Irrlicht.lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Fast + false + Level3 + + + Cdecl + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win32-visualstudio\Irrlicht.lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Fast + false + Level3 + + + FastCall + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win64-visualstudio\Irrlicht.lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_IRR_USE_SDL_DEVICE_=1;%(PreprocessorDefinitions) + + + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + 1.9 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_IRR_USE_SDL_DEVICE_=1;%(PreprocessorDefinitions) + + + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Irrlicht/Irrlicht10.0.vcxproj.filters b/source/Irrlicht/Irrlicht10.0.vcxproj.filters new file mode 100644 index 00000000..6269a9c5 --- /dev/null +++ b/source/Irrlicht/Irrlicht10.0.vcxproj.filters @@ -0,0 +1,2364 @@ + + + + + {b5bde5d3-f9e4-4036-8c28-2f4e8cd03846} + + + {0b0937fb-2270-4e3e-a94f-f92bc0fa74ae} + + + {67300400-93d5-4a7e-8b59-7c0d7b1f6d75} + + + {feb206b9-81b6-45c0-b4e5-9e637fe060e7} + + + {af459bf5-2849-4a0e-9a21-91acbbf1c6b5} + + + {aa649d49-922d-4118-8574-f05c13d67706} + + + {a72cb2e5-a5c3-41bc-9c86-fdbdae8f7866} + + + {72c30315-bbc0-4109-9ccd-fb7107ba316a} + + + {1fcdc900-911d-4b7a-9328-afce5bbe44fa} + + + {41e16cbf-c3cb-4d74-8aef-c0416b6b9d7f} + + + {b84f01e5-ae3c-457b-8d96-b3e271800162} + + + {eca36d94-d8fb-477d-a0dc-b5498c9686d7} + + + {67826246-df05-4523-9191-5286f9157963} + + + {659a61d5-7ab3-4aa3-95ca-879780810b4e} + + + {f65e8d89-c715-4794-8c2d-22f2b57cffb0} + + + {3cb7865d-a5e9-4b22-8f54-dde759b88c51} + + + {919fcfa4-4277-4c88-8bfc-4bfcfcbb1b65} + + + {834213c7-9515-49de-aa27-8d3ed9c0c87a} + + + {a9ca9d4d-7678-4687-b78b-15236c0dcf53} + + + {d694e7b0-0fb0-4685-ace7-56d9ec65a3d0} + + + {e2571a61-945c-4509-b47c-daea464916ab} + + + {1354e9fa-cea6-461e-af7f-9940bb5f0a2f} + + + {ac7af7ba-0e6b-4da4-a695-a0070a4da974} + + + {1173499e-79e8-4c34-8046-abc325e2f2a9} + + + {ca095ff3-25e4-4852-ab55-af28c602cd8a} + + + {1c8bd90a-8361-4478-8942-a062450ef209} + + + {128cac28-b6f8-49e7-87f5-ee15951d0396} + + + {6f10ce97-ed8b-47bc-a189-f2262eb467e4} + + + {5d58bc55-284e-4880-9226-85083e65d660} + + + {064ee182-9f07-4026-ac22-c141ae2c7281} + + + {6e842906-e193-451d-8716-12eaafabd0d8} + + + {799f220e-3a58-4788-876b-88c175b69871} + + + {da421793-4674-481c-be46-f7a44e78aee5} + + + {2c9c6ef7-5662-4f11-83cd-921c717d3ab0} + + + {8fc81fd6-acd6-46be-adf7-31d8413fa51d} + + + {6372c29c-b69e-41e5-bee2-27ad7cf3872f} + + + {397439c6-ad86-45a8-b692-f3606794a075} + + + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\video + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr\extern + + + Irrlicht\irr\extern + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + include\scene + + + + Irrlicht\scene\loaders + + + include\scene + + + Irrlicht\scene\loaders + + + include\video + + + include + + + include\video + + + include\scene + + + include + + + Irrlicht\irr + + + include\video + + + Irrlicht\video\Direct3D9 + + + Irrlicht\scene\writers + + + Irrlicht\scene + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL Context + + + Irrlicht\video\OpenGL Context + + + Irrlicht\video\OpenGL Context + + + include\video + + + include\scene + + + + + doc + + + doc + + + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\video + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr\extern + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\irr + + + Irrlicht\video\Direct3D9 + + + Irrlicht\scene\writers + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL Context + + + Irrlicht\video\OpenGL Context + + + Irrlicht\video\OpenGL Context + + + + + + \ No newline at end of file diff --git a/source/Irrlicht/Irrlicht11.0.sln b/source/Irrlicht/Irrlicht11.0.sln new file mode 100644 index 00000000..3a289183 --- /dev/null +++ b/source/Irrlicht/Irrlicht11.0.sln @@ -0,0 +1,50 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Irrlicht", "Irrlicht11.0.vcxproj", "{E08E042A-6C45-411B-92BE-3CC31331019F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release - Fast FPU|Win32 = Release - Fast FPU|Win32 + Release - Fast FPU|x64 = Release - Fast FPU|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + Static lib - Debug|Win32 = Static lib - Debug|Win32 + Static lib - Debug|x64 = Static lib - Debug|x64 + Static lib - Release - Fast FPU|Win32 = Static lib - Release - Fast FPU|Win32 + Static lib - Release - Fast FPU|x64 = Static lib - Release - Fast FPU|x64 + Static lib - Release|Win32 = Static lib - Release|Win32 + Static lib - Release|x64 = Static lib - Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.ActiveCfg = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.Build.0 = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.ActiveCfg = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.Build.0 = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.ActiveCfg = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.Build.0 = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.ActiveCfg = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.Build.0 = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.ActiveCfg = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.Build.0 = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.ActiveCfg = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.Build.0 = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.ActiveCfg = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.Build.0 = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.ActiveCfg = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.Build.0 = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.Build.0 = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.ActiveCfg = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.Build.0 = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.ActiveCfg = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.Build.0 = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.ActiveCfg = Static lib - Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.Build.0 = Static lib - Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/source/Irrlicht/Irrlicht11.0.vcxproj b/source/Irrlicht/Irrlicht11.0.vcxproj new file mode 100644 index 00000000..791a36a0 --- /dev/null +++ b/source/Irrlicht/Irrlicht11.0.vcxproj @@ -0,0 +1,1599 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release - Fast FPU + Win32 + + + Release - Fast FPU + x64 + + + Release + Win32 + + + Release + x64 + + + SDL-Debug + Win32 + + + SDL-Debug + x64 + + + Static lib - Debug + Win32 + + + Static lib - Debug + x64 + + + Static lib - Release - Fast FPU + Win32 + + + Static lib - Release - Fast FPU + x64 + + + Static lib - Release + Win32 + + + Static lib - Release + x64 + + + + Irrlicht + {E08E042A-6C45-411B-92BE-3CC31331019F} + Irrlicht + + + + DynamicLibrary + NotSet + Windows7.1SDK + + + DynamicLibrary + NotSet + Windows7.1SDK + + + StaticLibrary + MultiByte + true + Windows7.1SDK + + + StaticLibrary + MultiByte + true + Windows7.1SDK + + + StaticLibrary + MultiByte + true + Windows7.1SDK + + + StaticLibrary + MultiByte + true + Windows7.1SDK + + + StaticLibrary + NotSet + Windows7.1SDK + + + StaticLibrary + NotSet + Windows7.1SDK + + + DynamicLibrary + MultiByte + true + Windows7.1SDK + + + DynamicLibrary + MultiByte + true + Windows7.1SDK + + + DynamicLibrary + MultiByte + true + Windows7.1SDK + + + DynamicLibrary + MultiByte + true + Windows7.1SDK + + + DynamicLibrary + NotSet + Windows7.1SDK + + + DynamicLibrary + NotSet + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + false + false + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + false + false + ..\..\lib\Win32-VisualStudio\ + ..\..\lib\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + ..\..\lib\Win32-VisualStudio\ + ..\..\lib\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + ..\..\lib\Win32-VisualStudio\ + ..\..\lib\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + true + true + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + obj\$(Configuration)\ + obj\$(Configuration)64\ + true + true + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Debug/Irrlicht.tlb + + + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions); _ITERATOR_DEBUG_LEVEL=0 + + + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + Disabled + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + 1.9 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\..\Debug/Irrlicht.tlb + + + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions); _ITERATOR_DEBUG_LEVEL=0 + + + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + Disabled + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Level3 + + + Default + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + false + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + 1.9 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Level3 + + + Default + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + kernel32.lib;user32.lib;gdi32.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + false + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + Default + false + false + StreamingSIMDExtensions2 + Fast + false + Level3 + + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + false + true + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + Windows + 1.9 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + Default + false + false + StreamingSIMDExtensions2 + Fast + false + Level3 + + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + false + true + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + Windows + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions); _ITERATOR_DEBUG_LEVEL=0 + + + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win32-visualstudio\Irrlicht.lib + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions); _ITERATOR_DEBUG_LEVEL=0 + + + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win64-visualstudio\Irrlicht.lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + false + false + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Level3 + + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win32-visualstudio\Irrlicht.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + false + false + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Level3 + + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win64-visualstudio\Irrlicht.lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Fast + false + Level3 + + + FastCall + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win32-visualstudio\Irrlicht.lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Fast + false + Level3 + + + FastCall + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win64-visualstudio\Irrlicht.lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_IRR_USE_SDL_DEVICE_=1;%(PreprocessorDefinitions) + + + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + 1.9 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_IRR_USE_SDL_DEVICE_=1;%(PreprocessorDefinitions) + + + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Irrlicht/Irrlicht11.0.vcxproj.filters b/source/Irrlicht/Irrlicht11.0.vcxproj.filters new file mode 100644 index 00000000..f61a3f95 --- /dev/null +++ b/source/Irrlicht/Irrlicht11.0.vcxproj.filters @@ -0,0 +1,2364 @@ + + + + + {b5bde5d3-f9e4-4036-8c28-2f4e8cd03846} + + + {0b0937fb-2270-4e3e-a94f-f92bc0fa74ae} + + + {67300400-93d5-4a7e-8b59-7c0d7b1f6d75} + + + {feb206b9-81b6-45c0-b4e5-9e637fe060e7} + + + {af459bf5-2849-4a0e-9a21-91acbbf1c6b5} + + + {aa649d49-922d-4118-8574-f05c13d67706} + + + {a72cb2e5-a5c3-41bc-9c86-fdbdae8f7866} + + + {72c30315-bbc0-4109-9ccd-fb7107ba316a} + + + {1fcdc900-911d-4b7a-9328-afce5bbe44fa} + + + {41e16cbf-c3cb-4d74-8aef-c0416b6b9d7f} + + + {b84f01e5-ae3c-457b-8d96-b3e271800162} + + + {eca36d94-d8fb-477d-a0dc-b5498c9686d7} + + + {67826246-df05-4523-9191-5286f9157963} + + + {659a61d5-7ab3-4aa3-95ca-879780810b4e} + + + {f65e8d89-c715-4794-8c2d-22f2b57cffb0} + + + {3cb7865d-a5e9-4b22-8f54-dde759b88c51} + + + {919fcfa4-4277-4c88-8bfc-4bfcfcbb1b65} + + + {834213c7-9515-49de-aa27-8d3ed9c0c87a} + + + {a9ca9d4d-7678-4687-b78b-15236c0dcf53} + + + {d694e7b0-0fb0-4685-ace7-56d9ec65a3d0} + + + {e2571a61-945c-4509-b47c-daea464916ab} + + + {1354e9fa-cea6-461e-af7f-9940bb5f0a2f} + + + {ac7af7ba-0e6b-4da4-a695-a0070a4da974} + + + {1173499e-79e8-4c34-8046-abc325e2f2a9} + + + {ca095ff3-25e4-4852-ab55-af28c602cd8a} + + + {1c8bd90a-8361-4478-8942-a062450ef209} + + + {128cac28-b6f8-49e7-87f5-ee15951d0396} + + + {6f10ce97-ed8b-47bc-a189-f2262eb467e4} + + + {5d58bc55-284e-4880-9226-85083e65d660} + + + {064ee182-9f07-4026-ac22-c141ae2c7281} + + + {6e842906-e193-451d-8716-12eaafabd0d8} + + + {799f220e-3a58-4788-876b-88c175b69871} + + + {da421793-4674-481c-be46-f7a44e78aee5} + + + {bc1d03a2-7534-4b2f-857f-be5e0ab41dde} + + + {7c6393e3-ff28-4ef8-9a82-6a1dc7e9b1fc} + + + {9386255e-8324-4ce1-864a-225390cee09e} + + + {d16493e0-554f-49e0-b228-0e4047839dba} + + + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\video + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr\extern + + + Irrlicht\irr\extern + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + include\scene + + + + Irrlicht\scene\loaders + + + include\scene + + + Irrlicht\scene\loaders + + + include\video + + + include + + + include\video + + + include\video + + + Irrlicht\video\Direct3D9 + + + Irrlicht\scene\writers + + + Irrlicht\scene + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL Context + + + Irrlicht\video\OpenGL Context + + + Irrlicht\video\OpenGL Context + + + include\video + + + include\scene + + + + + doc + + + doc + + + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\video + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr\extern + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\video\Direct3D9 + + + Irrlicht\scene\writers + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL Context + + + Irrlicht\video\OpenGL Context + + + Irrlicht\video\OpenGL Context + + + + + + \ No newline at end of file diff --git a/source/Irrlicht/Irrlicht12.0.sln b/source/Irrlicht/Irrlicht12.0.sln new file mode 100644 index 00000000..8a6714b4 --- /dev/null +++ b/source/Irrlicht/Irrlicht12.0.sln @@ -0,0 +1,58 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2013 for Windows Desktop +VisualStudioVersion = 12.0.30501.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Irrlicht", "Irrlicht12.0.vcxproj", "{E08E042A-6C45-411B-92BE-3CC31331019F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release - Fast FPU|Win32 = Release - Fast FPU|Win32 + Release - Fast FPU|x64 = Release - Fast FPU|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + SDL-Debug|Win32 = SDL-Debug|Win32 + SDL-Debug|x64 = SDL-Debug|x64 + Static lib - Debug|Win32 = Static lib - Debug|Win32 + Static lib - Debug|x64 = Static lib - Debug|x64 + Static lib - Release - Fast FPU|Win32 = Static lib - Release - Fast FPU|Win32 + Static lib - Release - Fast FPU|x64 = Static lib - Release - Fast FPU|x64 + Static lib - Release|Win32 = Static lib - Release|Win32 + Static lib - Release|x64 = Static lib - Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.ActiveCfg = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.Build.0 = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.ActiveCfg = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.Build.0 = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.ActiveCfg = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.Build.0 = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.ActiveCfg = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.Build.0 = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.ActiveCfg = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.Build.0 = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.ActiveCfg = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.Build.0 = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|Win32.ActiveCfg = SDL-Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|Win32.Build.0 = SDL-Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|x64.ActiveCfg = SDL-Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|x64.Build.0 = SDL-Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.ActiveCfg = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.Build.0 = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.ActiveCfg = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.Build.0 = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.Build.0 = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.ActiveCfg = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.Build.0 = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.ActiveCfg = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.Build.0 = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.ActiveCfg = Static lib - Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.Build.0 = Static lib - Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/source/Irrlicht/Irrlicht12.0.vcxproj b/source/Irrlicht/Irrlicht12.0.vcxproj new file mode 100644 index 00000000..7b01c746 --- /dev/null +++ b/source/Irrlicht/Irrlicht12.0.vcxproj @@ -0,0 +1,1599 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release - Fast FPU + Win32 + + + Release - Fast FPU + x64 + + + Release + Win32 + + + Release + x64 + + + SDL-Debug + Win32 + + + SDL-Debug + x64 + + + Static lib - Debug + Win32 + + + Static lib - Debug + x64 + + + Static lib - Release - Fast FPU + Win32 + + + Static lib - Release - Fast FPU + x64 + + + Static lib - Release + Win32 + + + Static lib - Release + x64 + + + + Irrlicht + {E08E042A-6C45-411B-92BE-3CC31331019F} + Irrlicht + + + + DynamicLibrary + NotSet + Windows7.1SDK + + + DynamicLibrary + NotSet + Windows7.1SDK + + + StaticLibrary + MultiByte + true + Windows7.1SDK + + + StaticLibrary + MultiByte + true + Windows7.1SDK + + + StaticLibrary + MultiByte + true + Windows7.1SDK + + + StaticLibrary + MultiByte + true + Windows7.1SDK + + + StaticLibrary + NotSet + Windows7.1SDK + + + StaticLibrary + NotSet + Windows7.1SDK + + + DynamicLibrary + MultiByte + true + Windows7.1SDK + + + DynamicLibrary + MultiByte + true + Windows7.1SDK + + + DynamicLibrary + MultiByte + true + Windows7.1SDK + + + DynamicLibrary + MultiByte + true + Windows7.1SDK + + + DynamicLibrary + NotSet + Windows7.1SDK + + + DynamicLibrary + NotSet + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + false + false + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + false + false + ..\..\lib\Win32-VisualStudio\ + ..\..\lib\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + ..\..\lib\Win32-VisualStudio\ + ..\..\lib\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + ..\..\lib\Win32-VisualStudio\ + ..\..\lib\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + true + true + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + obj\$(Configuration)\ + obj\$(Configuration)64\ + true + true + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Debug/Irrlicht.tlb + + + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions); _ITERATOR_DEBUG_LEVEL=0 + + + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + Disabled + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + 1.9 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\..\Debug/Irrlicht.tlb + + + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions); _ITERATOR_DEBUG_LEVEL=0 + + + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + Disabled + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Level3 + + + Default + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + false + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + 1.9 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Level3 + + + Default + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + kernel32.lib;user32.lib;gdi32.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + false + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + Default + false + false + StreamingSIMDExtensions2 + Fast + false + Level3 + + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + false + true + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + Windows + 1.9 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + Default + false + false + StreamingSIMDExtensions2 + Fast + false + Level3 + + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + false + true + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + Windows + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions); _ITERATOR_DEBUG_LEVEL=0 + + + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win32-visualstudio\Irrlicht.lib + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions); _ITERATOR_DEBUG_LEVEL=0 + + + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win64-visualstudio\Irrlicht.lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + false + false + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Level3 + + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win32-visualstudio\Irrlicht.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + false + false + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Level3 + + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win64-visualstudio\Irrlicht.lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Fast + false + Level3 + + + FastCall + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win32-visualstudio\Irrlicht.lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Fast + false + Level3 + + + FastCall + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win64-visualstudio\Irrlicht.lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_IRR_USE_SDL_DEVICE_=1;%(PreprocessorDefinitions) + + + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + 1.9 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_IRR_USE_SDL_DEVICE_=1;%(PreprocessorDefinitions) + + + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Irrlicht/Irrlicht12.0.vcxproj.filters b/source/Irrlicht/Irrlicht12.0.vcxproj.filters new file mode 100644 index 00000000..7e94d188 --- /dev/null +++ b/source/Irrlicht/Irrlicht12.0.vcxproj.filters @@ -0,0 +1,2364 @@ + + + + + {b5bde5d3-f9e4-4036-8c28-2f4e8cd03846} + + + {0b0937fb-2270-4e3e-a94f-f92bc0fa74ae} + + + {67300400-93d5-4a7e-8b59-7c0d7b1f6d75} + + + {feb206b9-81b6-45c0-b4e5-9e637fe060e7} + + + {af459bf5-2849-4a0e-9a21-91acbbf1c6b5} + + + {aa649d49-922d-4118-8574-f05c13d67706} + + + {a72cb2e5-a5c3-41bc-9c86-fdbdae8f7866} + + + {72c30315-bbc0-4109-9ccd-fb7107ba316a} + + + {1fcdc900-911d-4b7a-9328-afce5bbe44fa} + + + {41e16cbf-c3cb-4d74-8aef-c0416b6b9d7f} + + + {b84f01e5-ae3c-457b-8d96-b3e271800162} + + + {eca36d94-d8fb-477d-a0dc-b5498c9686d7} + + + {67826246-df05-4523-9191-5286f9157963} + + + {659a61d5-7ab3-4aa3-95ca-879780810b4e} + + + {f65e8d89-c715-4794-8c2d-22f2b57cffb0} + + + {3cb7865d-a5e9-4b22-8f54-dde759b88c51} + + + {919fcfa4-4277-4c88-8bfc-4bfcfcbb1b65} + + + {834213c7-9515-49de-aa27-8d3ed9c0c87a} + + + {a9ca9d4d-7678-4687-b78b-15236c0dcf53} + + + {d694e7b0-0fb0-4685-ace7-56d9ec65a3d0} + + + {e2571a61-945c-4509-b47c-daea464916ab} + + + {1354e9fa-cea6-461e-af7f-9940bb5f0a2f} + + + {ac7af7ba-0e6b-4da4-a695-a0070a4da974} + + + {1173499e-79e8-4c34-8046-abc325e2f2a9} + + + {ca095ff3-25e4-4852-ab55-af28c602cd8a} + + + {1c8bd90a-8361-4478-8942-a062450ef209} + + + {128cac28-b6f8-49e7-87f5-ee15951d0396} + + + {6f10ce97-ed8b-47bc-a189-f2262eb467e4} + + + {5d58bc55-284e-4880-9226-85083e65d660} + + + {064ee182-9f07-4026-ac22-c141ae2c7281} + + + {6e842906-e193-451d-8716-12eaafabd0d8} + + + {799f220e-3a58-4788-876b-88c175b69871} + + + {da421793-4674-481c-be46-f7a44e78aee5} + + + {d6b83fe4-204d-4a95-aeb7-5b8ebdec7e5d} + + + {27e98892-9346-44d4-87f7-ec6dac7b613f} + + + {8868062c-90fe-48c1-863f-daddd86dca3c} + + + {f1f5ce52-0b36-4934-8c51-8e73026f94cc} + + + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\video + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr\extern + + + Irrlicht\irr\extern + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + include\scene + + + + Irrlicht\scene\loaders + + + include\scene + + + Irrlicht\scene\loaders + + + include\video + + + include + + + include\video + + + include\video + + + Irrlicht\video\Direct3D9 + + + Irrlicht\scene\writers + + + Irrlicht\scene + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL Context + + + Irrlicht\video\OpenGL Context + + + Irrlicht\video\OpenGL Context + + + include\video + + + include\scene + + + + + doc + + + doc + + + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\video + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr\extern + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\video\Direct3D9 + + + Irrlicht\scene\writers + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL Context + + + Irrlicht\video\OpenGL Context + + + Irrlicht\video\OpenGL Context + + + + + + \ No newline at end of file diff --git a/source/Irrlicht/Irrlicht14.0.sln b/source/Irrlicht/Irrlicht14.0.sln new file mode 100644 index 00000000..84f8862a --- /dev/null +++ b/source/Irrlicht/Irrlicht14.0.sln @@ -0,0 +1,58 @@ + +Microsoft Visual Studio Solution File, Format Version 14.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Irrlicht", "Irrlicht14.0.vcxproj", "{E08E042A-6C45-411B-92BE-3CC31331019F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release - Fast FPU|Win32 = Release - Fast FPU|Win32 + Release - Fast FPU|x64 = Release - Fast FPU|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + SDL-Debug|Win32 = SDL-Debug|Win32 + SDL-Debug|x64 = SDL-Debug|x64 + Static lib - Debug|Win32 = Static lib - Debug|Win32 + Static lib - Debug|x64 = Static lib - Debug|x64 + Static lib - Release - Fast FPU|Win32 = Static lib - Release - Fast FPU|Win32 + Static lib - Release - Fast FPU|x64 = Static lib - Release - Fast FPU|x64 + Static lib - Release|Win32 = Static lib - Release|Win32 + Static lib - Release|x64 = Static lib - Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.ActiveCfg = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.Build.0 = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.ActiveCfg = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.Build.0 = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.ActiveCfg = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.Build.0 = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.ActiveCfg = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.Build.0 = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.ActiveCfg = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.Build.0 = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.ActiveCfg = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.Build.0 = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|Win32.ActiveCfg = SDL-Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|Win32.Build.0 = SDL-Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|x64.ActiveCfg = SDL-Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|x64.Build.0 = SDL-Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.ActiveCfg = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.Build.0 = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.ActiveCfg = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.Build.0 = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.Build.0 = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.ActiveCfg = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.Build.0 = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.ActiveCfg = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.Build.0 = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.ActiveCfg = Static lib - Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.Build.0 = Static lib - Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/source/Irrlicht/Irrlicht14.0.vcxproj b/source/Irrlicht/Irrlicht14.0.vcxproj new file mode 100644 index 00000000..22385f15 --- /dev/null +++ b/source/Irrlicht/Irrlicht14.0.vcxproj @@ -0,0 +1,1610 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release - Fast FPU + Win32 + + + Release - Fast FPU + x64 + + + Release + Win32 + + + Release + x64 + + + SDL-Debug + Win32 + + + SDL-Debug + x64 + + + Static lib - Debug + Win32 + + + Static lib - Debug + x64 + + + Static lib - Release - Fast FPU + Win32 + + + Static lib - Release - Fast FPU + x64 + + + Static lib - Release + Win32 + + + Static lib - Release + x64 + + + + Irrlicht + {E08E042A-6C45-411B-92BE-3CC31331019F} + Irrlicht + 8.1 + + + + DynamicLibrary + NotSet + v140 + + + DynamicLibrary + NotSet + v140 + + + StaticLibrary + MultiByte + true + v140 + + + StaticLibrary + MultiByte + true + v140 + + + StaticLibrary + MultiByte + true + v140 + + + StaticLibrary + MultiByte + true + v140 + + + StaticLibrary + NotSet + v140 + + + StaticLibrary + NotSet + v140 + + + DynamicLibrary + MultiByte + true + v140 + + + DynamicLibrary + MultiByte + true + v140 + + + DynamicLibrary + MultiByte + true + v140 + + + DynamicLibrary + MultiByte + true + v140 + + + DynamicLibrary + NotSet + v140 + + + DynamicLibrary + NotSet + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + false + false + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + false + false + ..\..\lib\Win32-VisualStudio\ + ..\..\lib\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + ..\..\lib\Win32-VisualStudio\ + ..\..\lib\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + ..\..\lib\Win32-VisualStudio\ + ..\..\lib\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + true + true + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + obj\$(Configuration)\ + obj\$(Configuration)64\ + true + true + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)include;$(DXSDK_DIR)include;$(IncludePath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x86;$(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(OGLES_SDK)lib\x64;$(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Debug/Irrlicht.tlb + + + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions); _ITERATOR_DEBUG_LEVEL=0 + false + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + Disabled + 4577 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + 1.9 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\..\Debug/Irrlicht.tlb + + + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions); _ITERATOR_DEBUG_LEVEL=0 + false + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + Disabled + 4577 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + false + true + Level3 + + + Default + false + 4577 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + false + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + 1.9 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + false + true + Level3 + + + Default + false + 4577 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + kernel32.lib;user32.lib;gdi32.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + false + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + Default + false + false + StreamingSIMDExtensions2 + Fast + false + Level3 + + + false + 4577 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + false + true + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + Windows + 1.9 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + Default + false + false + StreamingSIMDExtensions2 + Fast + false + Level3 + + + false + 4577 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + false + true + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + Windows + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions); _ITERATOR_DEBUG_LEVEL=0 + false + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + 4577 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win32-visualstudio\Irrlicht.lib + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions); _ITERATOR_DEBUG_LEVEL=0 + false + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + 4577 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win64-visualstudio\Irrlicht.lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + false + false + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + false + true + Level3 + + + false + 4577 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win32-visualstudio\Irrlicht.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + false + false + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + false + true + Level3 + + + false + 4577 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win64-visualstudio\Irrlicht.lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + false + true + Fast + false + Level3 + + + FastCall + false + 4577 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win32-visualstudio\Irrlicht.lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + false + true + Fast + false + Level3 + + + FastCall + false + 4577 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win64-visualstudio\Irrlicht.lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_IRR_USE_SDL_DEVICE_=1;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + 4577 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + 1.9 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_IRR_USE_SDL_DEVICE_=1;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + 4577 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Irrlicht/Irrlicht14.0.vcxproj.filters b/source/Irrlicht/Irrlicht14.0.vcxproj.filters new file mode 100644 index 00000000..ed8c285b --- /dev/null +++ b/source/Irrlicht/Irrlicht14.0.vcxproj.filters @@ -0,0 +1,2364 @@ + + + + + {b5bde5d3-f9e4-4036-8c28-2f4e8cd03846} + + + {0b0937fb-2270-4e3e-a94f-f92bc0fa74ae} + + + {67300400-93d5-4a7e-8b59-7c0d7b1f6d75} + + + {feb206b9-81b6-45c0-b4e5-9e637fe060e7} + + + {af459bf5-2849-4a0e-9a21-91acbbf1c6b5} + + + {aa649d49-922d-4118-8574-f05c13d67706} + + + {a72cb2e5-a5c3-41bc-9c86-fdbdae8f7866} + + + {72c30315-bbc0-4109-9ccd-fb7107ba316a} + + + {1fcdc900-911d-4b7a-9328-afce5bbe44fa} + + + {41e16cbf-c3cb-4d74-8aef-c0416b6b9d7f} + + + {b84f01e5-ae3c-457b-8d96-b3e271800162} + + + {eca36d94-d8fb-477d-a0dc-b5498c9686d7} + + + {67826246-df05-4523-9191-5286f9157963} + + + {659a61d5-7ab3-4aa3-95ca-879780810b4e} + + + {f65e8d89-c715-4794-8c2d-22f2b57cffb0} + + + {3cb7865d-a5e9-4b22-8f54-dde759b88c51} + + + {919fcfa4-4277-4c88-8bfc-4bfcfcbb1b65} + + + {834213c7-9515-49de-aa27-8d3ed9c0c87a} + + + {a9ca9d4d-7678-4687-b78b-15236c0dcf53} + + + {d694e7b0-0fb0-4685-ace7-56d9ec65a3d0} + + + {e2571a61-945c-4509-b47c-daea464916ab} + + + {1354e9fa-cea6-461e-af7f-9940bb5f0a2f} + + + {ac7af7ba-0e6b-4da4-a695-a0070a4da974} + + + {1173499e-79e8-4c34-8046-abc325e2f2a9} + + + {ca095ff3-25e4-4852-ab55-af28c602cd8a} + + + {1c8bd90a-8361-4478-8942-a062450ef209} + + + {128cac28-b6f8-49e7-87f5-ee15951d0396} + + + {6f10ce97-ed8b-47bc-a189-f2262eb467e4} + + + {5d58bc55-284e-4880-9226-85083e65d660} + + + {064ee182-9f07-4026-ac22-c141ae2c7281} + + + {6e842906-e193-451d-8716-12eaafabd0d8} + + + {799f220e-3a58-4788-876b-88c175b69871} + + + {da421793-4674-481c-be46-f7a44e78aee5} + + + {628de03e-6872-4682-b1f6-d3cc453c9d55} + + + {224208f8-92b4-4fee-8825-3313e2819e8c} + + + {fbd95ddd-9178-412e-942b-f1c94ab68240} + + + {2512a519-e6c0-4b48-aae4-ded2d2500b95} + + + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\video + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr\extern + + + Irrlicht\irr\extern + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + include\scene + + + + Irrlicht\scene\loaders + + + include\scene + + + Irrlicht\scene\loaders + + + include\video + + + include + + + include\video + + + include\video + + + Irrlicht\video\Direct3D9 + + + Irrlicht\scene\writers + + + Irrlicht\scene + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL Context + + + Irrlicht\video\OpenGL Context + + + Irrlicht\video\OpenGL Context + + + include\video + + + include\scene + + + + + doc + + + doc + + + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\video + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr\extern + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\video\Direct3D9 + + + Irrlicht\scene\writers + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES2.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL ES1.x + + + Irrlicht\video\OpenGL Context + + + Irrlicht\video\OpenGL Context + + + Irrlicht\video\OpenGL Context + + + + + + \ No newline at end of file diff --git a/source/Irrlicht/Irrlicht15.0.sln b/source/Irrlicht/Irrlicht15.0.sln new file mode 100644 index 00000000..590f4d93 --- /dev/null +++ b/source/Irrlicht/Irrlicht15.0.sln @@ -0,0 +1,61 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27004.2008 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Irrlicht", "Irrlicht15.0.vcxproj", "{DD5C43CB-34A8-409B-9010-5A5A52787552}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release - Fast FPU|Win32 = Release - Fast FPU|Win32 + Release - Fast FPU|x64 = Release - Fast FPU|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + SDL-Debug|Win32 = SDL-Debug|Win32 + SDL-Debug|x64 = SDL-Debug|x64 + Static lib - Debug|Win32 = Static lib - Debug|Win32 + Static lib - Debug|x64 = Static lib - Debug|x64 + Static lib - Release - Fast FPU|Win32 = Static lib - Release - Fast FPU|Win32 + Static lib - Release - Fast FPU|x64 = Static lib - Release - Fast FPU|x64 + Static lib - Release|Win32 = Static lib - Release|Win32 + Static lib - Release|x64 = Static lib - Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Debug|Win32.ActiveCfg = Debug|Win32 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Debug|Win32.Build.0 = Debug|Win32 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Debug|x64.ActiveCfg = Debug|x64 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Debug|x64.Build.0 = Debug|x64 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Release - Fast FPU|Win32.ActiveCfg = Release - Fast FPU|Win32 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Release - Fast FPU|Win32.Build.0 = Release - Fast FPU|Win32 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Release - Fast FPU|x64.ActiveCfg = Release - Fast FPU|x64 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Release - Fast FPU|x64.Build.0 = Release - Fast FPU|x64 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Release|Win32.ActiveCfg = Release|Win32 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Release|Win32.Build.0 = Release|Win32 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Release|x64.ActiveCfg = Release|x64 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Release|x64.Build.0 = Release|x64 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.SDL-Debug|Win32.ActiveCfg = SDL-Debug|Win32 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.SDL-Debug|Win32.Build.0 = SDL-Debug|Win32 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.SDL-Debug|x64.ActiveCfg = SDL-Debug|x64 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.SDL-Debug|x64.Build.0 = SDL-Debug|x64 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Static lib - Debug|Win32.ActiveCfg = Static lib - Debug|Win32 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Static lib - Debug|Win32.Build.0 = Static lib - Debug|Win32 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Static lib - Debug|x64.ActiveCfg = Static lib - Debug|x64 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Static lib - Debug|x64.Build.0 = Static lib - Debug|x64 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Static lib - Release - Fast FPU|Win32 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Static lib - Release - Fast FPU|Win32.Build.0 = Static lib - Release - Fast FPU|Win32 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Static lib - Release - Fast FPU|x64.ActiveCfg = Static lib - Release - Fast FPU|x64 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Static lib - Release - Fast FPU|x64.Build.0 = Static lib - Release - Fast FPU|x64 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Static lib - Release|Win32.ActiveCfg = Static lib - Release|Win32 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Static lib - Release|Win32.Build.0 = Static lib - Release|Win32 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Static lib - Release|x64.ActiveCfg = Static lib - Release|x64 + {DD5C43CB-34A8-409B-9010-5A5A52787552}.Static lib - Release|x64.Build.0 = Static lib - Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DF9BEF31-A6F9-42FD-9573-28F994828B0B} + EndGlobalSection +EndGlobal diff --git a/source/Irrlicht/Irrlicht15.0.vcxproj b/source/Irrlicht/Irrlicht15.0.vcxproj new file mode 100644 index 00000000..3e766078 --- /dev/null +++ b/source/Irrlicht/Irrlicht15.0.vcxproj @@ -0,0 +1,1587 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release - Fast FPU + Win32 + + + Release - Fast FPU + x64 + + + Release + Win32 + + + Release + x64 + + + SDL-Debug + Win32 + + + SDL-Debug + x64 + + + Static lib - Debug + Win32 + + + Static lib - Debug + x64 + + + Static lib - Release - Fast FPU + Win32 + + + Static lib - Release - Fast FPU + x64 + + + Static lib - Release + Win32 + + + Static lib - Release + x64 + + + + Irrlicht + {DD5C43CB-34A8-409B-9010-5A5A52787552} + Irrlicht + 8.1 + + + + DynamicLibrary + NotSet + v141 + + + DynamicLibrary + NotSet + v141 + + + StaticLibrary + MultiByte + true + v141 + + + StaticLibrary + MultiByte + true + v141 + + + StaticLibrary + MultiByte + true + v141 + + + StaticLibrary + MultiByte + true + v141 + + + StaticLibrary + NotSet + v141 + + + StaticLibrary + NotSet + v141 + + + DynamicLibrary + MultiByte + true + v141 + + + DynamicLibrary + MultiByte + true + v141 + + + DynamicLibrary + MultiByte + true + v141 + + + DynamicLibrary + MultiByte + true + v141 + + + DynamicLibrary + NotSet + v141 + + + DynamicLibrary + NotSet + v141 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + false + false + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + false + false + ..\..\lib\Win32-VisualStudio\ + ..\..\lib\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + ..\..\lib\Win32-VisualStudio\ + ..\..\lib\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + ..\..\lib\Win32-VisualStudio\ + ..\..\lib\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + obj\$(Configuration)\ + obj\$(Configuration)64\ + true + true + Irrlicht.ruleset + Irrlicht.ruleset + + + + + Irrlicht.ruleset + Irrlicht.ruleset + + + + + Irrlicht.ruleset + Irrlicht.ruleset + + + + + Irrlicht.ruleset + Irrlicht.ruleset + + + + + Irrlicht.ruleset + Irrlicht.ruleset + + + + + Irrlicht.ruleset + Irrlicht.ruleset + + + + + Irrlicht.ruleset + Irrlicht.ruleset + + + + + $(DXSDK_DIR)include;$(IncludePath) + $(DXSDK_DIR)include;$(IncludePath) + obj\$(Configuration)\ + obj\$(Configuration)64\ + true + true + $(DXSDK_DIR)include;$(IncludePath) + $(DXSDK_DIR)include;$(IncludePath) + $(DXSDK_DIR)include;$(IncludePath) + $(DXSDK_DIR)include;$(IncludePath) + $(DXSDK_DIR)include;$(IncludePath) + $(DXSDK_DIR)include;$(IncludePath) + $(DXSDK_DIR)include;$(IncludePath) + $(DXSDK_DIR)include;$(IncludePath) + $(DXSDK_DIR)include;$(IncludePath) + $(DXSDK_DIR)include;$(IncludePath) + $(DXSDK_DIR)include;$(IncludePath) + $(DXSDK_DIR)include;$(IncludePath) + $(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(DXSDK_DIR)Lib\x86;$(LibraryPath) + $(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + $(DXSDK_DIR)Lib\x64;$(LibraryPath);$(VSInstallDir);$(VSInstallDir)lib\amd64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Debug/Irrlicht.tlb + + + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + Disabled + 4577 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + 1.9 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\..\Debug/Irrlicht.tlb + + + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + Disabled + 4577 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + false + true + Level3 + + + Default + false + 4577 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + false + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + 1.9 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + false + true + Level3 + + + Default + false + 4577 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + kernel32.lib;user32.lib;gdi32.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + false + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + Default + false + false + StreamingSIMDExtensions2 + Fast + false + Level3 + + + false + 4577 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + false + true + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + Windows + 1.9 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + Default + false + false + StreamingSIMDExtensions2 + Fast + false + Level3 + + + false + 4577 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + libci.lib;%(IgnoreSpecificDefaultLibraries) + false + true + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + Windows + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + 4577 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win32-visualstudio\Irrlicht.lib + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + 4577 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win64-visualstudio\Irrlicht.lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + false + false + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + false + true + Level3 + + + false + 4577 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win32-visualstudio\Irrlicht.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + MaxSpeed + OnlyExplicitInline + false + false + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + false + true + Level3 + + + false + 4577 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win64-visualstudio\Irrlicht.lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + false + true + Fast + false + Level3 + + + FastCall + false + 4577 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win32-visualstudio\Irrlicht.lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\..\Release/Irrlicht.tlb + + + Full + AnySuitable + true + Speed + true + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;_IRR_STATIC_LIB_;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + false + MultiThreaded + false + true + Fast + false + Level3 + + + FastCall + false + 4577 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + winmm.lib;%(AdditionalDependencies) + ..\..\lib\Win64-visualstudio\Irrlicht.lib + MachineX64 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_IRR_USE_SDL_DEVICE_=1;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + 4577 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + /MACHINE:I386 %(AdditionalOptions) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;%(AdditionalDependencies) + ..\..\bin\Win32-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win32-visualstudio\Irrlicht.lib + 1.9 + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\..\Debug/Irrlicht.tlb + + + Disabled + ..\..\include;zlib;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_WINDOWS;_USRDLL;IRRLICHT_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_IRR_USE_SDL_DEVICE_=1;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + false + false + Level3 + 4577 + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + true + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;opengl32.lib;winmm.lib;%(AdditionalDependencies) + ..\..\bin\Win64-visualstudio\Irrlicht.dll + %(AdditionalLibraryDirectories) + libci.lib;%(IgnoreSpecificDefaultLibraries) + true + + + ..\..\lib\Win64-visualstudio\Irrlicht.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Irrlicht/Irrlicht15.0.vcxproj.filters b/source/Irrlicht/Irrlicht15.0.vcxproj.filters new file mode 100644 index 00000000..7230ff84 --- /dev/null +++ b/source/Irrlicht/Irrlicht15.0.vcxproj.filters @@ -0,0 +1,2287 @@ + + + + + {b5bde5d3-f9e4-4036-8c28-2f4e8cd03846} + + + {0b0937fb-2270-4e3e-a94f-f92bc0fa74ae} + + + {67300400-93d5-4a7e-8b59-7c0d7b1f6d75} + + + {feb206b9-81b6-45c0-b4e5-9e637fe060e7} + + + {af459bf5-2849-4a0e-9a21-91acbbf1c6b5} + + + {aa649d49-922d-4118-8574-f05c13d67706} + + + {a72cb2e5-a5c3-41bc-9c86-fdbdae8f7866} + + + {72c30315-bbc0-4109-9ccd-fb7107ba316a} + + + {1fcdc900-911d-4b7a-9328-afce5bbe44fa} + + + {41e16cbf-c3cb-4d74-8aef-c0416b6b9d7f} + + + {b84f01e5-ae3c-457b-8d96-b3e271800162} + + + {eca36d94-d8fb-477d-a0dc-b5498c9686d7} + + + {67826246-df05-4523-9191-5286f9157963} + + + {659a61d5-7ab3-4aa3-95ca-879780810b4e} + + + {f65e8d89-c715-4794-8c2d-22f2b57cffb0} + + + {3cb7865d-a5e9-4b22-8f54-dde759b88c51} + + + {919fcfa4-4277-4c88-8bfc-4bfcfcbb1b65} + + + {834213c7-9515-49de-aa27-8d3ed9c0c87a} + + + {a9ca9d4d-7678-4687-b78b-15236c0dcf53} + + + {d694e7b0-0fb0-4685-ace7-56d9ec65a3d0} + + + {e2571a61-945c-4509-b47c-daea464916ab} + + + {1354e9fa-cea6-461e-af7f-9940bb5f0a2f} + + + {ac7af7ba-0e6b-4da4-a695-a0070a4da974} + + + {1173499e-79e8-4c34-8046-abc325e2f2a9} + + + {ca095ff3-25e4-4852-ab55-af28c602cd8a} + + + {1c8bd90a-8361-4478-8942-a062450ef209} + + + {128cac28-b6f8-49e7-87f5-ee15951d0396} + + + {6f10ce97-ed8b-47bc-a189-f2262eb467e4} + + + {5d58bc55-284e-4880-9226-85083e65d660} + + + {064ee182-9f07-4026-ac22-c141ae2c7281} + + + {6e842906-e193-451d-8716-12eaafabd0d8} + + + {799f220e-3a58-4788-876b-88c175b69871} + + + {da421793-4674-481c-be46-f7a44e78aee5} + + + {628de03e-6872-4682-b1f6-d3cc453c9d55} + + + {2512a519-e6c0-4b48-aae4-ded2d2500b95} + + + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\video + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\core + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\io + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\scene + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + include\gui + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\video + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr\extern + + + Irrlicht\irr\extern + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + include\scene + + + + Irrlicht\scene\loaders + + + include\scene + + + Irrlicht\scene\loaders + + + include\video + + + include + + + include\video + + + include\video + + + Irrlicht\video\Direct3D9 + + + Irrlicht\scene\writers + + + Irrlicht\scene + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL Core + + + Irrlicht\video\OpenGL Context + + + Irrlicht\video\OpenGL Context + + + include\video + + + + + doc + + + doc + + + + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\sceneNodes + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\particleSystem + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\collision + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\animators + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\scene\writers + + + Irrlicht\video + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Software + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Writer + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Null\Loader + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Direct3D9 + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\video\Burning Video + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr + + + Irrlicht\irr\extern + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\zlib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\jpeglib + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\libpng + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\aesGladman + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\extern\bzip2 + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\irr\device + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\io + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\gui + + + Irrlicht\scene\loaders + + + Irrlicht\scene\loaders + + + Irrlicht\video\Direct3D9 + + + Irrlicht\scene\writers + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL + + + Irrlicht\video\OpenGL Context + + + Irrlicht\video\OpenGL Context + + + + + + \ No newline at end of file diff --git a/source/Irrlicht/KHR/khrplatform.h b/source/Irrlicht/KHR/khrplatform.h new file mode 100644 index 00000000..1b3fc929 --- /dev/null +++ b/source/Irrlicht/KHR/khrplatform.h @@ -0,0 +1,290 @@ +#ifndef __khrplatform_h_ +#define __khrplatform_h_ + +/* +** Copyright (c) 2008-2018 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Khronos platform-specific types and definitions. + * + * The master copy of khrplatform.h is maintained in the Khronos EGL + * Registry repository at https://github.com/KhronosGroup/EGL-Registry + * The last semantic modification to khrplatform.h was at commit ID: + * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 + * + * Adopters may modify this file to suit their platform. Adopters are + * encouraged to submit platform specific modifications to the Khronos + * group so that they can be included in future versions of this file. + * Please submit changes by filing pull requests or issues on + * the EGL Registry repository linked above. + * + * + * See the Implementer's Guidelines for information about where this file + * should be located on your system and for more details of its use: + * http://www.khronos.org/registry/implementers_guide.pdf + * + * This file should be included as + * #include + * by Khronos client API header files that use its types and defines. + * + * The types in khrplatform.h should only be used to define API-specific types. + * + * Types defined in khrplatform.h: + * khronos_int8_t signed 8 bit + * khronos_uint8_t unsigned 8 bit + * khronos_int16_t signed 16 bit + * khronos_uint16_t unsigned 16 bit + * khronos_int32_t signed 32 bit + * khronos_uint32_t unsigned 32 bit + * khronos_int64_t signed 64 bit + * khronos_uint64_t unsigned 64 bit + * khronos_intptr_t signed same number of bits as a pointer + * khronos_uintptr_t unsigned same number of bits as a pointer + * khronos_ssize_t signed size + * khronos_usize_t unsigned size + * khronos_float_t signed 32 bit floating point + * khronos_time_ns_t unsigned 64 bit time in nanoseconds + * khronos_utime_nanoseconds_t unsigned time interval or absolute time in + * nanoseconds + * khronos_stime_nanoseconds_t signed time interval in nanoseconds + * khronos_boolean_enum_t enumerated boolean type. This should + * only be used as a base type when a client API's boolean type is + * an enum. Client APIs which use an integer or other type for + * booleans cannot use this as the base type for their boolean. + * + * Tokens defined in khrplatform.h: + * + * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. + * + * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. + * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. + * + * Calling convention macros defined in this file: + * KHRONOS_APICALL + * KHRONOS_APIENTRY + * KHRONOS_APIATTRIBUTES + * + * These may be used in function prototypes as: + * + * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( + * int arg1, + * int arg2) KHRONOS_APIATTRIBUTES; + */ + +#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC) +# define KHRONOS_STATIC 1 +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APICALL + *------------------------------------------------------------------------- + * This precedes the return type of the function in the function prototype. + */ +#if defined(KHRONOS_STATIC) + /* If the preprocessor constant KHRONOS_STATIC is defined, make the + * header compatible with static linking. */ +# define KHRONOS_APICALL +#elif defined(_WIN32) +# define KHRONOS_APICALL __declspec(dllimport) +#elif defined (__SYMBIAN32__) +# define KHRONOS_APICALL IMPORT_C +#elif defined(__ANDROID__) +# define KHRONOS_APICALL __attribute__((visibility("default"))) +#else +# define KHRONOS_APICALL +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIENTRY + *------------------------------------------------------------------------- + * This follows the return type of the function and precedes the function + * name in the function prototype. + */ +#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(KHRONOS_STATIC) + /* Win32 but not WinCE */ +# define KHRONOS_APIENTRY __stdcall +#else +# define KHRONOS_APIENTRY +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIATTRIBUTES + *------------------------------------------------------------------------- + * This follows the closing parenthesis of the function prototype arguments. + */ +#if defined (__ARMCC_2__) +#define KHRONOS_APIATTRIBUTES __softfp +#else +#define KHRONOS_APIATTRIBUTES +#endif + +/*------------------------------------------------------------------------- + * basic type definitions + *-----------------------------------------------------------------------*/ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) + + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__VMS ) || defined(__sgi) + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) + +/* + * Win32 + */ +typedef __int32 khronos_int32_t; +typedef unsigned __int32 khronos_uint32_t; +typedef __int64 khronos_int64_t; +typedef unsigned __int64 khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__sun__) || defined(__digital__) + +/* + * Sun or Digital + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#if defined(__arch64__) || defined(_LP64) +typedef long int khronos_int64_t; +typedef unsigned long int khronos_uint64_t; +#else +typedef long long int khronos_int64_t; +typedef unsigned long long int khronos_uint64_t; +#endif /* __arch64__ */ +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif 0 + +/* + * Hypothetical platform with no float or int64 support + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#define KHRONOS_SUPPORT_INT64 0 +#define KHRONOS_SUPPORT_FLOAT 0 + +#else + +/* + * Generic fallback + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#endif + + +/* + * Types that are (so far) the same on all platforms + */ +typedef signed char khronos_int8_t; +typedef unsigned char khronos_uint8_t; +typedef signed short int khronos_int16_t; +typedef unsigned short int khronos_uint16_t; + +/* + * Types that differ between LLP64 and LP64 architectures - in LLP64, + * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears + * to be the only LLP64 architecture in current use. + */ +#ifdef _WIN64 +typedef signed long long int khronos_intptr_t; +typedef unsigned long long int khronos_uintptr_t; +typedef signed long long int khronos_ssize_t; +typedef unsigned long long int khronos_usize_t; +#else +typedef signed long int khronos_intptr_t; +typedef unsigned long int khronos_uintptr_t; +typedef signed long int khronos_ssize_t; +typedef unsigned long int khronos_usize_t; +#endif + +#if KHRONOS_SUPPORT_FLOAT +/* + * Float type + */ +typedef float khronos_float_t; +#endif + +#if KHRONOS_SUPPORT_INT64 +/* Time types + * + * These types can be used to represent a time interval in nanoseconds or + * an absolute Unadjusted System Time. Unadjusted System Time is the number + * of nanoseconds since some arbitrary system event (e.g. since the last + * time the system booted). The Unadjusted System Time is an unsigned + * 64 bit value that wraps back to 0 every 584 years. Time intervals + * may be either signed or unsigned. + */ +typedef khronos_uint64_t khronos_utime_nanoseconds_t; +typedef khronos_int64_t khronos_stime_nanoseconds_t; +#endif + +/* + * Dummy value used to pad enum types to 32 bits. + */ +#ifndef KHRONOS_MAX_ENUM +#define KHRONOS_MAX_ENUM 0x7FFFFFFF +#endif + +/* + * Enumerated boolean type + * + * Values other than zero should be considered to be true. Therefore + * comparisons should not be made against KHRONOS_TRUE. + */ +typedef enum { + KHRONOS_FALSE = 0, + KHRONOS_TRUE = 1, + KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM +} khronos_boolean_enum_t; + +#endif /* __khrplatform_h_ */ diff --git a/source/Irrlicht/Makefile b/source/Irrlicht/Makefile new file mode 100644 index 00000000..37b14fb3 --- /dev/null +++ b/source/Irrlicht/Makefile @@ -0,0 +1,246 @@ +VERSION_MAJOR = 1 +VERSION_MINOR = 9 +VERSION_RELEASE = 0 +# Irrlicht Engine 1.9.0 +# Makefile for Linux +# +# To use, just run: +# +# make +# +# This will compile Irrlicht, create a static lib (libIrrlicht.a), and copy it +# into the subdirectory lib/Linux. That's all. +# +# If you want Irrlicht to be compiled as shared lib (libIrrlicht.so.versionnumber), then run: +# +# make sharedlib +# make install +# +# If you want to compile in release mode run: +# +# make NDEBUG=1 +# +# For cross-compilation for Win32 under Linux, just use the win32 targets. You have to set +# at least CXX, CC, and AR to the proper binaries. +# +# For compiling on MinGW you can run it with: +# +# make win32 +# +# Or as MinGW by default has CC set to cc - but has no compiler by that name - you might have to do: +# make CC=gcc win32 + +#List of object files, separated based on engine architecture +IRRMESHLOADER = CBSPMeshFileLoader.o CMD2MeshFileLoader.o CMD3MeshFileLoader.o CMS3DMeshFileLoader.o CB3DMeshFileLoader.o C3DSMeshFileLoader.o COgreMeshFileLoader.o COBJMeshFileLoader.o CColladaFileLoader.o CCSMLoader.o CDMFLoader.o CLMTSMeshFileLoader.o CMY3DMeshFileLoader.o COCTLoader.o CXMeshFileLoader.o CIrrMeshFileLoader.o CSTLMeshFileLoader.o CLWOMeshFileLoader.o CPLYMeshFileLoader.o CSMFMeshFileLoader.o CMeshTextureLoader.o +IRRMESHWRITER = CColladaMeshWriter.o CIrrMeshWriter.o CSTLMeshWriter.o COBJMeshWriter.o CPLYMeshWriter.o CB3DMeshWriter.o +IRRMESHOBJ = $(IRRMESHLOADER) $(IRRMESHWRITER) \ + CSkinnedMesh.o CBoneSceneNode.o CMeshSceneNode.o \ + CAnimatedMeshSceneNode.o CAnimatedMeshMD2.o CAnimatedMeshMD3.o \ + CQ3LevelMesh.o CQuake3ShaderSceneNode.o CAnimatedMeshHalfLife.o +IRROBJ = CBillboardSceneNode.o CCameraSceneNode.o CDummyTransformationSceneNode.o CEmptySceneNode.o CGeometryCreator.o CLightSceneNode.o CMeshManipulator.o CMetaTriangleSelector.o COctreeSceneNode.o COctreeTriangleSelector.o CSceneCollisionManager.o CSceneManager.o CShadowVolumeSceneNode.o CSkyBoxSceneNode.o CSkyDomeSceneNode.o CTerrainSceneNode.o CTerrainTriangleSelector.o CVolumeLightSceneNode.o CCubeSceneNode.o CSphereSceneNode.o CTextSceneNode.o CTriangleBBSelector.o CTriangleSelector.o CWaterSurfaceSceneNode.o CMeshCache.o CDefaultSceneNodeAnimatorFactory.o CDefaultSceneNodeFactory.o CSceneLoaderIrr.o +IRRPARTICLEOBJ = CParticleAnimatedMeshSceneNodeEmitter.o CParticleBoxEmitter.o CParticleCylinderEmitter.o CParticleMeshEmitter.o CParticlePointEmitter.o CParticleRingEmitter.o CParticleSphereEmitter.o CParticleAttractionAffector.o CParticleFadeOutAffector.o CParticleGravityAffector.o CParticleRotationAffector.o CParticleSystemSceneNode.o CParticleScaleAffector.o +IRRANIMOBJ = CSceneNodeAnimatorCameraFPS.o CSceneNodeAnimatorCameraMaya.o CSceneNodeAnimatorCollisionResponse.o CSceneNodeAnimatorDelete.o CSceneNodeAnimatorFlyCircle.o CSceneNodeAnimatorFlyStraight.o CSceneNodeAnimatorFollowSpline.o CSceneNodeAnimatorRotation.o CSceneNodeAnimatorTexture.o +IRRDRVROBJ = CNullDriver.o COpenGLCacheHandler.o COpenGLDriver.o COpenGLNormalMapRenderer.o COpenGLParallaxMapRenderer.o COpenGLShaderMaterialRenderer.o COpenGLSLMaterialRenderer.o COpenGLExtensionHandler.o \ + CD3D9Driver.o CD3D9HLSLMaterialRenderer.o CD3D9NormalMapRenderer.o CD3D9ParallaxMapRenderer.o CD3D9ShaderMaterialRenderer.o CD3D9Texture.o \ + COGLESDriver.o COGLESExtensionHandler.o COGLES2Driver.o COGLES2ExtensionHandler.o COGLES2FixedPipelineRenderer.o COGLES2MaterialRenderer.o COGLES2NormalMapRenderer.o COGLES2ParallaxMapRenderer.o COGLES2Renderer2D.o CWebGL1Driver.o \ + CGLXManager.o CWGLManager.o CEGLManager.o +IRRIMAGEOBJ = CColorConverter.o CImage.o CImageLoaderBMP.o CImageLoaderDDS.o CImageLoaderJPG.o CImageLoaderPCX.o CImageLoaderPNG.o CImageLoaderPSD.o CImageLoaderPVR.o CImageLoaderTGA.o CImageLoaderPPM.o CImageLoaderWAL.o CImageLoaderRGB.o \ + 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 CTRNormalMap.o CTRStencilShadow.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 CMemoryFile.o CReadFile.o CWriteFile.o CXMLReader.o CXMLWriter.o CWADReader.o CZipReader.o CPakReader.o CNPKReader.o CTarReader.o CMountPointReader.o irrXML.o CAttributes.o lzma/LzmaDec.o +IRROTHEROBJ = CIrrDeviceSDL.o CIrrDeviceLinux.o CIrrDeviceConsole.o CIrrDeviceStub.o CIrrDeviceWin32.o CIrrDeviceFB.o CLogger.o COSOperator.o Irrlicht.o os.o leakHunter.o CProfiler.o utf8.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 CGUIImageList.o CGUITreeView.o CGUIProfiler.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 +JPEGLIBOBJ = jpeglib/jcapimin.o jpeglib/jcapistd.o jpeglib/jccoefct.o jpeglib/jccolor.o jpeglib/jcdctmgr.o jpeglib/jchuff.o jpeglib/jcinit.o jpeglib/jcmainct.o jpeglib/jcmarker.o jpeglib/jcmaster.o jpeglib/jcomapi.o jpeglib/jcparam.o jpeglib/jcprepct.o jpeglib/jcsample.o jpeglib/jctrans.o jpeglib/jdapimin.o jpeglib/jdapistd.o jpeglib/jdatadst.o jpeglib/jdatasrc.o jpeglib/jdcoefct.o jpeglib/jdcolor.o jpeglib/jddctmgr.o jpeglib/jdhuff.o jpeglib/jdinput.o jpeglib/jdmainct.o jpeglib/jdmarker.o jpeglib/jdmaster.o jpeglib/jdmerge.o jpeglib/jdpostct.o jpeglib/jdsample.o jpeglib/jdtrans.o jpeglib/jerror.o jpeglib/jfdctflt.o jpeglib/jfdctfst.o jpeglib/jfdctint.o jpeglib/jidctflt.o jpeglib/jidctfst.o jpeglib/jidctint.o jpeglib/jmemmgr.o jpeglib/jmemnobs.o jpeglib/jquant1.o jpeglib/jquant2.o jpeglib/jutils.o jpeglib/jcarith.o jpeglib/jdarith.o jpeglib/jaricom.o +LIBPNGOBJ = libpng/png.o libpng/pngerror.o libpng/pngget.o libpng/pngmem.o libpng/pngpread.o libpng/pngread.o libpng/pngrio.o libpng/pngrtran.o libpng/pngrutil.o libpng/pngset.o libpng/pngtrans.o libpng/pngwio.o libpng/pngwrite.o libpng/pngwtran.o libpng/pngwutil.o +LIBAESGM = aesGladman/aescrypt.o aesGladman/aeskey.o aesGladman/aestab.o aesGladman/fileenc.o aesGladman/hmac.o aesGladman/prng.o aesGladman/pwd2key.o aesGladman/sha1.o aesGladman/sha2.o +BZIP2OBJ = bzip2/blocksort.o bzip2/huffman.o bzip2/crctable.o bzip2/randtable.o bzip2/bzcompress.o bzip2/decompress.o bzip2/bzlib.o + +# Next variable is for additional scene nodes etc. of customized Irrlicht versions +EXTRAOBJ = +LINKOBJ = $(IRRMESHOBJ) $(IRROBJ) $(IRRPARTICLEOBJ) $(IRRANIMOBJ) \ + $(IRRVIDEOOBJ) $(IRRSWRENDEROBJ) $(IRRIOOBJ) $(IRROTHEROBJ) \ + $(IRRGUIOBJ) $(ZLIBOBJ) $(JPEGLIBOBJ) $(LIBPNGOBJ) $(LIBAESGM) \ + $(BZIP2OBJ) $(EXTRAOBJ) + +emscripten: EMSCRIPTEN=1 + +############### +#Compiler flags + +CXXINCS = -I../../include -Izlib -Ijpeglib -Ilibpng +CPPFLAGS += $(CXXINCS) -DIRRLICHT_EXPORTS=1 +CXXFLAGS += -Wall -pipe -fno-exceptions -fno-rtti -fstrict-aliasing +#CXXFLAGS += -std=gnu++11 -U__STRICT_ANSI__ +ifndef NDEBUG + CXXFLAGS += -g -D_DEBUG +else + ifndef EMSCRIPTEN + CXXFLAGS += -fexpensive-optimizations -O3 + else + CXXFLAGS += -O3 + endif +endif +ifdef PROFILE + CXXFLAGS += -pg +endif +ifdef EMSCRIPTEN + CXXFLAGS += -std=gnu++11 -U__STRICT_ANSI__ + ifndef NDEBUG + CFLAGS := -DPNG_THREAD_UNSAFE_OK -DPNG_NO_MMX_CODE -DPNG_NO_MNG_FEATURES + else + CFLAGS := -O3 -DPNG_THREAD_UNSAFE_OK -DPNG_NO_MMX_CODE -DPNG_NO_MNG_FEATURES + endif + ifdef WASM + CXXFLAGS += -s WASM=1 + endif +else + CFLAGS := -O3 -fexpensive-optimizations -DPNG_THREAD_UNSAFE_OK -DPNG_NO_MMX_CODE -DPNG_NO_MNG_FEATURES +endif + +sharedlib sharedlib_osx: CXXFLAGS += -fPIC +sharedlib sharedlib_osx: CFLAGS += -fPIC + +#multilib handling +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif + +#Linux specific options +staticlib sharedlib install: SYSTEM = Linux +sharedlib install: SHARED_LIB = libIrrlicht.so +sharedlib: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lXxf86vm +staticlib sharedlib: CXXINCS += -I/usr/X11R6/include + +#OSX specific options +staticlib_osx sharedlib_osx install_osx: SYSTEM = MacOSX +staticlib_osx sharedlib_osx: IRROTHEROBJ += MacOSX/CIrrDeviceMacOSX.o MacOSX/OSXClipboard.o MacOSX/AppDelegate.o +staticlib_osx sharedlib_osx: CXXINCS += -IMacOSX -I/usr/X11R6/include +sharedlib_osx install_osx: SHARED_LIB = libIrrlicht.dylib +staticlib_osx sharedlib_osx: LDFLAGS += --no-export-all-symbols --add-stdcall-alias +sharedlib_osx: LDFLAGS += -L/usr/X11R6/lib$(LIBSELECT) -lGL -lXxf86vm +# for non-X11 app +#sharedlib_osx: LDFLAGS += -framework cocoa -framework carbon -framework opengl -framework IOKit + +#Windows specific options +IRRLICHT_DLL := ../../bin/Win32-gcc/Irrlicht.dll +sharedlib_win32 staticlib_win32: SYSTEM = Win32-gcc +sharedlib_win32: LDFLAGS += -lgdi32 -lopengl32 -ld3dx9d -lwinmm -Wl,--add-stdcall-alias +#sharedlib_win32: LDFLAGS += -lSDL +#choose either -DIRR_COMPILE_WITH_DX9_DEV_PACK or -DNO_IRR_COMPILE_WITH_DIRECT3D_9_ depending if you need dx9 +#sharedlib_win32 staticlib_win32: CPPFLAGS += -DIRR_COMPILE_WITH_DX9_DEV_PACK +sharedlib_win32 staticlib_win32: CPPFLAGS += -DNO_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ -DNO_IRR_COMPILE_WITH_DIRECT3D_9_ +staticlib_win32: CPPFLAGS += -D_IRR_STATIC_LIB_ + +#emscripten specific options +staticlib_emscripten: SYSTEM = emscripten + + +# You might want to disable features you don't need in Irrlicht here to reduce Irrlicht library. +# This can also help to reduce the .js size when compiling for emscripten. +# Note you can also disable the same features by modifying IrrCompileConfig.h which is slightly +# safer as you have then the same setting when compiling Irrlicht and your project (but needs +# modifying source-code while you can simply copy the Makefile and create your own settings) + +# xml - use a lot, but also takes a lot of space. Check if you have any formats using it.s +#CXXFLAGS += -DNO_IRR_COMPILE_WITH_XML_ +# Get rid of encrypted zip files or bzip encrypted zip's or lzma encrypte zip's - or even all zip-file support. +#CXXFLAGS += -DNO_IRR_COMPILE_WITH_ZIP_ENCRYPTION_ -DNO_IRR_COMPILE_WITH_BZIP2_ -DNO_IRR_COMPILE_WITH_LZMA_ -DNO_IRR_COMPILE_WITH_ZLIB_ +# Disable mesh writers +#CXXFLAGS += -DNO_IRR_COMPILE_WITH_IRR_WRITER_ -DNO_IRR_COMPILE_WITH_COLLADA_WRITER_ -DNO_IRR_COMPILE_WITH_STL_WRITER_ +#CXXFLAGS += -DNO_IRR_COMPILE_WITH_OBJ_WRITER_ -DNO_IRR_COMPILE_WITH_PLY_WRITER_ -DNO_IRR_COMPILE_WITH_B3D_WRITER_ +# Disable image writers +#CXXFLAGS += -DNO_IRR_COMPILE_WITH_BMP_WRITER_ -DNO_IRR_COMPILE_WITH_JPG_WRITER_ -DNO_IRR_COMPILE_WITH_PCX_WRITER_ +#CXXFLAGS += -DNO_IRR_COMPILE_WITH_PNG_WRITER_ -DNO_IRR_COMPILE_WITH_PPM_WRITER_ -DNO_IRR_COMPILE_WITH_TGA_WRITER_ + + +STATIC_LIB = libIrrlicht.a +LIB_PATH = ../../lib/$(SYSTEM) +INSTALL_DIR = /usr/local/lib + +VERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE) +SHARED_FULLNAME = $(SHARED_LIB).$(VERSION) +SONAME = $(SHARED_LIB).$(VERSION_MAJOR).$(VERSION_MINOR) + +#################### +# All target, builds Irrlicht as static lib (libIrrlicht.a) and copies it into lib/Linux +all linux : staticlib + +emscripten: staticlib_emscripten + +# Builds Irrlicht as shared lib (libIrrlicht.so.versionNumber) and copies it into lib/Linux +sharedlib: $(LINKOBJ) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -shared -Wl,-soname,$(SONAME) -o $(SHARED_FULLNAME) $^ $(LDFLAGS) + mkdir -p $(LIB_PATH) + cp $(SHARED_FULLNAME) $(LIB_PATH) + +# Builds Irrlicht as static lib (libIrrlicht.a) +$(STATIC_LIB): $(LINKOBJ) + $(AR) rs $@ $^ + +# Copies static lib into ../../lib/($SYSTEM) +staticlib staticlib_osx staticlib_emscripten: $(STATIC_LIB) + mkdir -p $(LIB_PATH) + cp $^ $(LIB_PATH) + +# Builds Irrlicht as dll (Irrlicht.dll) into ../../bin/Win32-gcc +all_win32 win32: sharedlib_win32 +sharedlib_win32: $(IRRLICHT_DLL) +../../bin/Win32-gcc/Irrlicht.dll: $(LINKOBJ) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -shared -o $@ $^ $(LDFLAGS) -Wl,--out-implib,../../lib/Win32-gcc/$(STATIC_LIB) +# Copies static lib into /lib/Win32-gcc +staticlib_win32: $(STATIC_LIB) + cp $^ $(LIB_PATH) + +# Builds Irrlicht as shared lib (libIrrlicht.so.versionNumber) and copies it into /lib/MacOSX +sharedlib_osx: $(LINKOBJ) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -dynamiclib -Wl,-install_name,$(SONAME) -o $(SHARED_FULLNAME) $^ $(LDFLAGS) + cp $(SHARED_FULLNAME) $(LIB_PATH) + +# Installs Irrlicht if it was created as shared lib +install install_osx: + $(RM) -r $(INSTALL_DIR)/../include/irrlicht + mkdir -p $(INSTALL_DIR)/../include/irrlicht + cp ../../include/*.h $(INSTALL_DIR)/../include/irrlicht/ + cp $(LIB_PATH)/$(SHARED_FULLNAME) $(INSTALL_DIR) + cd $(INSTALL_DIR) && ln -s -f $(SHARED_FULLNAME) $(SONAME) + cd $(INSTALL_DIR) && ln -s -f $(SONAME) $(SHARED_LIB) +# ldconfig -n $(INSTALL_DIR) + +TAGS: + ctags *.cpp ../../include/*.h *.h + +# Create dependency files for automatic recompilation +%.d:%.cpp + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -MM -MF $@ $< + +# Create dependency files for automatic recompilation +%.d:%.c + $(CC) $(CPPFLAGS) $(CFLAGS) -MM -MF $@ $< + +# Create object files from objective-c code +%.o:%.mm + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $< + +ifneq ($(MAKECMDGOALS),clean) +-include $(LINKOBJ:.o=.d) +endif + +help: + @echo "Available targets for Irrlicht" + @echo " sharedlib: Build shared library Irrlicht.so for Linux" + @echo " staticlib: Build static library Irrlicht.a for Linux" + @echo " emscripten: Build static emscripen library on Linux" + @echo " install: Copy shared library to /usr/local/lib" + @echo "" + @echo " sharedlib_win32: Build shared library Irrlicht.dll for Windows" + @echo " staticlib_win32: Build static library Irrlicht.a for Windows" + @echo "" + @echo " clean: Clean up directory" + +# Cleans all temporary files and compilation results. +clean: + $(RM) $(LINKOBJ) $(SHARED_FULLNAME) $(STATIC_LIB) $(LINKOBJ:.o=.d) + +.PHONY: all sharedlib staticlib sharedlib_win32 staticlib_win32 emscripten staticlib_emscripten help install clean diff --git a/source/Irrlicht/Octree.h b/source/Irrlicht/Octree.h new file mode 100644 index 00000000..e9c092b8 --- /dev/null +++ b/source/Irrlicht/Octree.h @@ -0,0 +1,389 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_OCTREE_H_INCLUDED__ +#define __C_OCTREE_H_INCLUDED__ + +#include "SViewFrustum.h" +#include "S3DVertex.h" +#include "aabbox3d.h" +#include "irrArray.h" +#include "CMeshBuffer.h" + +/** + Flags for Octree +*/ +//! bypass full invisible/visible test +#define OCTREE_PARENTTEST + +namespace irr +{ + +//! template octree. +/** T must be a vertex type which has a member +called .Pos, which is a core::vertex3df position. */ +template +class Octree +{ +public: + + // TODO: Using reference counted class on the stack. + // Reason is likely that it really costs speed here otherwise. + // But doing so prevents using VBO's with octrees. + // Also it's just a bad idea, for example this is the reason + // we can't make the copy-constructor private for IReferenceCounted. + // So would be nice to figure out how to put this on heap (and check + // if it's maybe cheap enough) or maybe stop using CMeshBuffer here. + struct SMeshChunk : public scene::CMeshBuffer + { + SMeshChunk () + : scene::CMeshBuffer(), MaterialId(0) + { + scene::CMeshBuffer::grab(); + } + + virtual ~SMeshChunk () + { + //removeAllHardwareBuffers + } + + s32 MaterialId; + }; + + struct SIndexChunk + { + core::array Indices; + s32 MaterialId; + }; + + struct SIndexData + { + u16* Indices; + s32 CurrentSize; + s32 MaxSize; + }; + + + //! Constructor + Octree(const core::array& meshes, s32 minimalPolysPerNode=128) : + IndexData(0), IndexDataCount(meshes.size()), NodeCount(0) + { + IndexData = new SIndexData[IndexDataCount]; + + // construct array of all indices + + core::array* indexChunks = new core::array; + indexChunks->reallocate(meshes.size()); + for (u32 i=0; i!=meshes.size(); ++i) + { + IndexData[i].CurrentSize = 0; + IndexData[i].MaxSize = meshes[i].Indices.size(); + IndexData[i].Indices = new u16[IndexData[i].MaxSize]; + + indexChunks->push_back(SIndexChunk()); + SIndexChunk& tic = indexChunks->getLast(); + + tic.MaterialId = meshes[i].MaterialId; + tic.Indices = meshes[i].Indices; + } + + // create tree + Root = new OctreeNode(NodeCount, 0, meshes, indexChunks, minimalPolysPerNode); + } + + //! returns all ids of polygons partially or fully enclosed + //! by this bounding box. + void calculatePolys(const core::aabbox3d& box) + { + for (u32 i=0; i!=IndexDataCount; ++i) + IndexData[i].CurrentSize = 0; + + Root->getPolys(box, IndexData, 0); + } + + //! returns all ids of polygons partially or fully enclosed + //! by a view frustum. + void calculatePolys(const scene::SViewFrustum& frustum) + { + for (u32 i=0; i!=IndexDataCount; ++i) + IndexData[i].CurrentSize = 0; + + Root->getPolys(frustum, IndexData, 0); + } + + const SIndexData* getIndexData() const + { + return IndexData; + } + + u32 getIndexDataCount() const + { + return IndexDataCount; + } + + u32 getNodeCount() const + { + return NodeCount; + } + + //! for debug purposes only, collects the bounding boxes of the tree + void getBoundingBoxes(const core::aabbox3d& box, + core::array< const core::aabbox3d* >&outBoxes) const + { + Root->getBoundingBoxes(box, outBoxes); + } + + //! destructor + ~Octree() + { + for (u32 i=0; i& allmeshdata, + core::array* indices, + s32 minimalPolysPerNode) : IndexData(0), + Depth(currentdepth+1) + { + ++nodeCount; + + u32 i; // new ISO for scoping problem with different compilers + + for (i=0; i!=8; ++i) + Children[i] = 0; + + if (indices->empty()) + { + delete indices; + return; + } + + bool found = false; + + // find first point for bounding box + + for (i=0; isize(); ++i) + { + if (!(*indices)[i].Indices.empty()) + { + Box.reset(allmeshdata[i].Vertices[(*indices)[i].Indices[0]].Pos); + found = true; + break; + } + } + + if (!found) + { + delete indices; + return; + } + + s32 totalPrimitives = 0; + + // now lets calculate our bounding box + for (i=0; isize(); ++i) + { + totalPrimitives += (*indices)[i].Indices.size(); + for (u32 j=0; j<(*indices)[i].Indices.size(); ++j) + Box.addInternalPoint(allmeshdata[i].Vertices[(*indices)[i].Indices[j]].Pos); + } + + core::vector3df middle = Box.getCenter(); + core::vector3df edges[8]; + Box.getEdges(edges); + + // calculate all children + core::aabbox3d box; + core::array keepIndices; + + if (totalPrimitives > minimalPolysPerNode && !Box.isEmpty()) + for (u32 ch=0; ch!=8; ++ch) + { + box.reset(middle); + box.addInternalPoint(edges[ch]); + + // create indices for child + bool added = false; + core::array* cindexChunks = new core::array; + cindexChunks->reallocate(allmeshdata.size()); + for (i=0; ipush_back(SIndexChunk()); + SIndexChunk& tic = cindexChunks->getLast(); + tic.MaterialId = allmeshdata[i].MaterialId; + + for (u32 t=0; t<(*indices)[i].Indices.size(); t+=3) + { + if (box.isPointInside(allmeshdata[i].Vertices[(*indices)[i].Indices[t]].Pos) && + box.isPointInside(allmeshdata[i].Vertices[(*indices)[i].Indices[t+1]].Pos) && + box.isPointInside(allmeshdata[i].Vertices[(*indices)[i].Indices[t+2]].Pos)) + { + tic.Indices.push_back((*indices)[i].Indices[t]); + tic.Indices.push_back((*indices)[i].Indices[t+1]); + tic.Indices.push_back((*indices)[i].Indices[t+2]); + + added = true; + } + else + { + keepIndices.push_back((*indices)[i].Indices[t]); + keepIndices.push_back((*indices)[i].Indices[t+1]); + keepIndices.push_back((*indices)[i].Indices[t+2]); + } + } + + (*indices)[i].Indices.set_used(keepIndices.size()); + memcpy( (*indices)[i].Indices.pointer(), keepIndices.pointer(), keepIndices.size()*sizeof(u16)); + keepIndices.set_used(0); + } + + if (added) + Children[ch] = new OctreeNode(nodeCount, Depth, + allmeshdata, cindexChunks, minimalPolysPerNode); + else + delete cindexChunks; + + } // end for all possible children + + IndexData = indices; + } + + // destructor + ~OctreeNode() + { + delete IndexData; + + for (u32 i=0; i<8; ++i) + delete Children[i]; + } + + // returns all ids of polygons partially or full enclosed + // by this bounding box. + void getPolys(const core::aabbox3d& box, SIndexData* idxdata, u32 parentTest ) const + { +#if defined (OCTREE_PARENTTEST ) + // if not full inside + if ( parentTest != 2 ) + { + // partially inside ? + if (!Box.intersectsWithBox(box)) + return; + + // fully inside ? + parentTest = Box.isFullInside(box)?2:1; + } +#else + if (Box.intersectsWithBox(box)) +#endif + { + const u32 cnt = IndexData->size(); + u32 i; // new ISO for scoping problem in some compilers + + for (i=0; igetPolys(box, idxdata,parentTest); + } + } + + // returns all ids of polygons partially or full enclosed + // by the view frustum. + void getPolys(const scene::SViewFrustum& frustum, SIndexData* idxdata,u32 parentTest) const + { + u32 i; // new ISO for scoping problem in some compilers + + // if parent is fully inside, no further check for the children is needed +#if defined (OCTREE_PARENTTEST ) + if ( parentTest != 2 ) +#endif + { +#if defined (OCTREE_PARENTTEST ) + parentTest = 2; +#endif + for (i=0; i!=scene::SViewFrustum::VF_PLANE_COUNT; ++i) + { + core::EIntersectionRelation3D r = Box.classifyPlaneRelation(frustum.planes[i]); + if ( r == core::ISREL3D_FRONT ) + return; +#if defined (OCTREE_PARENTTEST ) + if ( r == core::ISREL3D_CLIPPED ) + parentTest = 1; // must still check children +#endif + } + } + + + const u32 cnt = IndexData->size(); + + for (i=0; i!=cnt; ++i) + { + s32 idxcnt = (*IndexData)[i].Indices.size(); + + if (idxcnt) + { + memcpy(&idxdata[i].Indices[idxdata[i].CurrentSize], + &(*IndexData)[i].Indices[0], idxcnt * sizeof(s16)); + idxdata[i].CurrentSize += idxcnt; + } + } + + for (i=0; i!=8; ++i) + if (Children[i]) + Children[i]->getPolys(frustum, idxdata,parentTest); + } + + //! for debug purposes only, collects the bounding boxes of the node + void getBoundingBoxes(const core::aabbox3d& box, + core::array< const core::aabbox3d* >&outBoxes) const + { + if (Box.intersectsWithBox(box)) + { + outBoxes.push_back(&Box); + + for (u32 i=0; i!=8; ++i) + if (Children[i]) + Children[i]->getBoundingBoxes(box, outBoxes); + } + } + + private: + + core::aabbox3df Box; + core::array* IndexData; + OctreeNode* Children[8]; + u32 Depth; + }; + + OctreeNode* Root; + SIndexData* IndexData; + u32 IndexDataCount; + u32 NodeCount; +}; + +} // end namespace + +#endif + diff --git a/source/Irrlicht/S2DVertex.h b/source/Irrlicht/S2DVertex.h new file mode 100644 index 00000000..f6f6a885 --- /dev/null +++ b/source/Irrlicht/S2DVertex.h @@ -0,0 +1,30 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __S_K_2D_VERTEX_H_INCLUDED__ +#define __S_K_2D_VERTEX_H_INCLUDED__ + +#include "vector2d.h" + +typedef signed short TZBufferType; + +namespace irr +{ +namespace video +{ + + struct S2DVertex + { + core::vector2d Pos; // position + core::vector2d TCoords; // texture coordinates + TZBufferType ZValue; // zvalue + u16 Color; + }; + + +} // end namespace video +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/S4DVertex.h b/source/Irrlicht/S4DVertex.h new file mode 100644 index 00000000..7ad6b83d --- /dev/null +++ b/source/Irrlicht/S4DVertex.h @@ -0,0 +1,693 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + + +#ifndef __S_4D_VERTEX_H_INCLUDED__ +#define __S_4D_VERTEX_H_INCLUDED__ + +#include "SoftwareDriver2_compile_config.h" +#include "SoftwareDriver2_helper.h" +#include "irrAllocator.h" + +namespace irr +{ + +namespace video +{ + +struct sVec2 +{ + f32 x; + f32 y; + + sVec2 () {} + + sVec2 ( f32 s) : x ( s ), y ( s ) {} + sVec2 ( f32 _x, f32 _y ) + : x ( _x ), y ( _y ) {} + + void set ( f32 _x, f32 _y ) + { + x = _x; + y = _y; + } + + // f = a * t + b * ( 1 - t ) + void interpolate(const sVec2& a, const sVec2& b, const f32 t) + { + x = b.x + ( ( a.x - b.x ) * t ); + y = b.y + ( ( a.y - b.y ) * t ); + } + + sVec2 operator-(const sVec2& other) const + { + return sVec2(x - other.x, y - other.y); + } + + sVec2 operator+(const sVec2& other) const + { + return sVec2(x + other.x, y + other.y); + } + + void operator+=(const sVec2& other) + { + x += other.x; + y += other.y; + } + + sVec2 operator*(const f32 s) const + { + return sVec2(x * s , y * s); + } + + void operator*=( const f32 s) + { + x *= s; + y *= s; + } + + void operator=(const sVec2& other) + { + x = other.x; + y = other.y; + } + +}; + +// A8R8G8B8 +struct sVec4; +struct sCompressedVec4 +{ + u32 argb; + + void setA8R8G8B8 ( u32 value ) + { + argb = value; + } + + void setColorf ( const video::SColorf & color ) + { + argb = core::floor32_fast( color.a * 255.f ) << 24 | + core::floor32_fast( color.r * 255.f ) << 16 | + core::floor32_fast( color.g * 255.f ) << 8 | + core::floor32_fast( color.b * 255.f ); + } + + void setVec4 ( const sVec4 & v ); + + // f = a * t + b * ( 1 - t ) + void interpolate(const sCompressedVec4& a, const sCompressedVec4& b, const f32 t) + { + argb = PixelBlend32 ( b.argb, a.argb, core::floor32_fast( t * 256.f ) ); + } + + +}; + + +struct sVec4 +{ + union + { + struct { f32 x, y, z, w; }; + struct { f32 a, r, g, b; }; +// struct { sVec2 xy, zw; }; // sorry, this does not compile with gcc + }; + + + + sVec4 () {} + + sVec4 ( f32 s) : x ( s ), y ( s ), z ( s ), w ( s ) {} + + sVec4 ( f32 _x, f32 _y, f32 _z, f32 _w ) + : x ( _x ), y ( _y ), z( _z ), w ( _w ){} + + void set ( f32 _x, f32 _y, f32 _z, f32 _w ) + { + x = _x; + y = _y; + z = _z; + w = _w; + } + + void setA8R8G8B8 ( u32 argb ) + { + x = ( ( argb & 0xFF000000 ) >> 24 ) * ( 1.f / 255.f ); + y = ( ( argb & 0x00FF0000 ) >> 16 ) * ( 1.f / 255.f ); + z = ( ( argb & 0x0000FF00 ) >> 8 ) * ( 1.f / 255.f ); + w = ( ( argb & 0x000000FF ) ) * ( 1.f / 255.f ); + } + + + void setColorf ( const video::SColorf & color ) + { + x = color.a; + y = color.r; + z = color.g; + w = color.b; + } + + + // f = a * t + b * ( 1 - t ) + void interpolate(const sVec4& a, const sVec4& b, const f32 t) + { + x = b.x + ( ( a.x - b.x ) * t ); + y = b.y + ( ( a.y - b.y ) * t ); + z = b.z + ( ( a.z - b.z ) * t ); + w = b.w + ( ( a.w - b.w ) * t ); + } + + + f32 dotProduct(const sVec4& other) const + { + return x*other.x + y*other.y + z*other.z + w*other.w; + } + + f32 dot_xyz( const sVec4& other) const + { + return x*other.x + y*other.y + z*other.z; + } + + f32 get_length_xyz_square () const + { + return x * x + y * y + z * z; + } + + f32 get_length_xyz () const + { + return core::squareroot ( x * x + y * y + z * z ); + } + + void normalize_xyz () + { + const f32 l = core::reciprocal_squareroot ( x * x + y * y + z * z ); + + x *= l; + y *= l; + z *= l; + } + + void project_xyz () + { + w = core::reciprocal ( w ); + x *= w; + y *= w; + z *= w; + } + + sVec4 operator-(const sVec4& other) const + { + return sVec4(x - other.x, y - other.y, z - other.z,w - other.w); + } + + sVec4 operator+(const sVec4& other) const + { + return sVec4(x + other.x, y + other.y, z + other.z,w + other.w); + } + + void operator+=(const sVec4& other) + { + x += other.x; + y += other.y; + z += other.z; + w += other.w; + } + + sVec4 operator*(const f32 s) const + { + return sVec4(x * s , y * s, z * s,w * s); + } + + sVec4 operator*(const sVec4 &other) const + { + return sVec4(x * other.x , y * other.y, z * other.z,w * other.w); + } + + void mulReciprocal ( f32 s ) + { + const f32 i = core::reciprocal ( s ); + x = (f32) ( x * i ); + y = (f32) ( y * i ); + z = (f32) ( z * i ); + w = (f32) ( w * i ); + } + + void mul ( const f32 s ) + { + x *= s; + y *= s; + z *= s; + w *= s; + } + +/* + void operator*=(f32 s) + { + x *= s; + y *= s; + z *= s; + w *= s; + } +*/ + void operator*=(const sVec4 &other) + { + x *= other.x; + y *= other.y; + z *= other.z; + w *= other.w; + } + + void operator=(const sVec4& other) + { + x = other.x; + y = other.y; + z = other.z; + w = other.w; + } +}; + +struct sVec3 +{ + union + { + struct { f32 r, g, b; }; + struct { f32 x, y, z; }; + }; + + + sVec3 () {} + sVec3 ( f32 _x, f32 _y, f32 _z ) + : r ( _x ), g ( _y ), b( _z ) {} + + sVec3 ( const sVec4 &v ) + : r ( v.x ), g ( v.y ), b( v.z ) {} + + void set ( f32 _r, f32 _g, f32 _b ) + { + r = _r; + g = _g; + b = _b; + } + + void setR8G8B8 ( u32 argb ) + { + r = ( ( argb & 0x00FF0000 ) >> 16 ) * ( 1.f / 255.f ); + g = ( ( argb & 0x0000FF00 ) >> 8 ) * ( 1.f / 255.f ); + b = ( ( argb & 0x000000FF ) ) * ( 1.f / 255.f ); + } + + void setColorf ( const video::SColorf & color ) + { + r = color.r; + g = color.g; + b = color.b; + } + + void add (const sVec3& other) + { + r += other.r; + g += other.g; + b += other.b; + } + + void mulAdd(const sVec3& other, const f32 v) + { + r += other.r * v; + g += other.g * v; + b += other.b * v; + } + + void mulAdd(const sVec3& v0, const sVec3& v1) + { + r += v0.r * v1.r; + g += v0.g * v1.g; + b += v0.b * v1.b; + } + + void saturate ( sVec4 &dest, u32 argb ) + { + dest.x = ( ( argb & 0xFF000000 ) >> 24 ) * ( 1.f / 255.f ); + dest.y = core::min_ ( r, 1.f ); + dest.z = core::min_ ( g, 1.f ); + dest.w = core::min_ ( b, 1.f ); + } + + // f = a * t + b * ( 1 - t ) + void interpolate(const sVec3& v0, const sVec3& v1, const f32 t) + { + r = v1.r + ( ( v0.r - v1.r ) * t ); + g = v1.g + ( ( v0.g - v1.g ) * t ); + b = v1.b + ( ( v0.b - v1.b ) * t ); + } + + sVec3 operator-(const sVec3& other) const + { + return sVec3(r - other.r, b - other.b, g - other.g); + } + + sVec3 operator+(const sVec3& other) const + { + return sVec3(r + other.r, g + other.g, b + other.b); + } + + sVec3 operator*(const f32 s) const + { + return sVec3(r * s , g * s, b * s); + } + + sVec3 operator/(const f32 s) const + { + f32 inv = 1.f / s; + return sVec3(r * inv , g * inv, b * inv); + } + + sVec3 operator*(const sVec3 &other) const + { + return sVec3(r * other.r , b * other.b, g * other.g); + } + + void operator+=(const sVec3& other) + { + r += other.r; + g += other.g; + b += other.b; + } + + void setLength ( f32 len ) + { + const f32 l = len * core::reciprocal_squareroot ( r * r + g * g + b * b ); + + r *= l; + g *= l; + b *= l; + } + +}; + + + +inline void sCompressedVec4::setVec4 ( const sVec4 & v ) +{ + argb = core::floor32_fast( v.x * 255.f ) << 24 | + core::floor32_fast( v.y * 255.f ) << 16 | + core::floor32_fast( v.z * 255.f ) << 8 | + core::floor32_fast( v.w * 255.f ); +} + + +enum e4DVertexFlag +{ + VERTEX4D_INSIDE = 0x0000003F, + VERTEX4D_CLIPMASK = 0x0000003F, + VERTEX4D_PROJECTED = 0x00000100, + + VERTEX4D_FORMAT_MASK = 0xFFFF0000, + + VERTEX4D_FORMAT_MASK_TEXTURE = 0x000F0000, + VERTEX4D_FORMAT_TEXTURE_1 = 0x00010000, + VERTEX4D_FORMAT_TEXTURE_2 = 0x00020000, + VERTEX4D_FORMAT_TEXTURE_3 = 0x00030000, + VERTEX4D_FORMAT_TEXTURE_4 = 0x00040000, + + VERTEX4D_FORMAT_MASK_COLOR = 0x00F00000, + VERTEX4D_FORMAT_COLOR_1 = 0x00100000, + VERTEX4D_FORMAT_COLOR_2 = 0x00200000, + + VERTEX4D_FORMAT_MASK_BUMP = 0x0F000000, + VERTEX4D_FORMAT_BUMP_DOT3 = 0x01000000, + +}; + +const u32 MATERIAL_MAX_COLORS = 1; +const u32 BURNING_MATERIAL_MAX_TEXTURES = 2; +const u32 BURNING_MATERIAL_MAX_TANGENT = 1; + +// dummy Vertex. used for calculation vertex memory size +struct s4DVertex_proxy +{ + u32 flag; + sVec4 Pos; + sVec2 Tex[BURNING_MATERIAL_MAX_TEXTURES]; + +#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + sVec4 Color[MATERIAL_MAX_COLORS]; +#endif + + sVec3 LightTangent[BURNING_MATERIAL_MAX_TANGENT]; + +}; + +#define SIZEOF_SVERTEX 64 +#define SIZEOF_SVERTEX_LOG2 6 + +/*! + Internal BurningVideo Vertex +*/ +struct s4DVertex +{ + u32 flag; + + sVec4 Pos; + sVec2 Tex[ BURNING_MATERIAL_MAX_TEXTURES ]; + +#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + sVec4 Color[ MATERIAL_MAX_COLORS ]; +#endif + + sVec3 LightTangent[BURNING_MATERIAL_MAX_TANGENT]; + + //u8 fill [ SIZEOF_SVERTEX - sizeof (s4DVertex_proxy) ]; + + // f = a * t + b * ( 1 - t ) + void interpolate(const s4DVertex& b, const s4DVertex& a, const f32 t) + { + u32 i; + u32 size; + + Pos.interpolate ( a.Pos, b.Pos, t ); + +#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + size = (flag & VERTEX4D_FORMAT_MASK_COLOR) >> 20; + for ( i = 0; i!= size; ++i ) + { + Color[i].interpolate ( a.Color[i], b.Color[i], t ); + } +#endif + + size = (flag & VERTEX4D_FORMAT_MASK_TEXTURE) >> 16; + for ( i = 0; i!= size; ++i ) + { + Tex[i].interpolate ( a.Tex[i], b.Tex[i], t ); + } + + size = (flag & VERTEX4D_FORMAT_MASK_BUMP) >> 24; + for ( i = 0; i!= size; ++i ) + { + LightTangent[i].interpolate ( a.LightTangent[i], b.LightTangent[i], t ); + } + + } +}; + +// ----------------- Vertex Cache --------------------------- + +struct SAlignedVertex +{ + SAlignedVertex ( u32 element, u32 aligned ) + : ElementSize ( element ) + { + u32 byteSize = (ElementSize << SIZEOF_SVERTEX_LOG2 ) + aligned; + mem = new u8 [ byteSize ]; + data = (s4DVertex*) mem; + } + + virtual ~SAlignedVertex () + { + delete [] mem; + } + + s4DVertex *data; + u8 *mem; + u32 ElementSize; +}; + + +// hold info for different Vertex Types +struct SVSize +{ + u32 Format; + u32 Pitch; + u32 TexSize; +}; + + +// a cache info +struct SCacheInfo +{ + u32 index; + u32 hit; +}; + +#define VERTEXCACHE_ELEMENT 16 +#define VERTEXCACHE_MISS 0xFFFFFFFF +struct SVertexCache +{ + SVertexCache (): mem ( VERTEXCACHE_ELEMENT * 2, 128 ) {} + + SCacheInfo info[VERTEXCACHE_ELEMENT]; + + + // Transformed and lite, clipping state + // + Clipped, Projected + SAlignedVertex mem; + + // source + const void* vertices; + u32 vertexCount; + + const void* indices; + u32 indexCount; + u32 indicesIndex; + + u32 indicesRun; + + // primitives consist of x vertices + u32 primitivePitch; + + u32 vType; //E_VERTEX_TYPE + u32 pType; //scene::E_PRIMITIVE_TYPE + u32 iType; //E_INDEX_TYPE iType + +}; + + +// swap 2 pointer +REALINLINE void swapVertexPointer(const s4DVertex** v1, const s4DVertex** v2) +{ + const s4DVertex* b = *v1; + *v1 = *v2; + *v2 = b; +} + + +// ------------------------ Internal Scanline Rasterizer ----------------------------- + + + +// internal scan convert +struct sScanConvertData +{ + u8 left; // major edge left/right + u8 right; // !left + + f32 invDeltaY[3]; // inverse edge delta y + + f32 x[2]; // x coordinate + f32 slopeX[2]; // x slope along edges + +#if defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) || defined ( SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT ) + f32 w[2]; // w coordinate + fp24 slopeW[2]; // w slope along edges +#else + f32 z[2]; // z coordinate + f32 slopeZ[2]; // z slope along edges +#endif + + sVec4 c[MATERIAL_MAX_COLORS][2]; // color + sVec4 slopeC[MATERIAL_MAX_COLORS][2]; // color slope along edges + + sVec2 t[BURNING_MATERIAL_MAX_TEXTURES][2]; // texture + sVec2 slopeT[BURNING_MATERIAL_MAX_TEXTURES][2]; // texture slope along edges + + sVec3 l[BURNING_MATERIAL_MAX_TANGENT][2]; // Light Tangent + sVec3 slopeL[BURNING_MATERIAL_MAX_TEXTURES][2]; // tanget slope along edges +}; + +// passed to scan Line +struct sScanLineData +{ + s32 y; // y position of scanline + f32 x[2]; // x start, x end of scanline + +#if defined ( SOFTWARE_DRIVER_2_USE_WBUFFER ) || defined ( SOFTWARE_DRIVER_2_PERSPECTIVE_CORRECT ) + f32 w[2]; // w start, w end of scanline +#else + f32 z[2]; // z start, z end of scanline +#endif + +#ifdef SOFTWARE_DRIVER_2_USE_VERTEX_COLOR + sVec4 c[MATERIAL_MAX_COLORS][2]; // color start, color end of scanline +#endif + + sVec2 t[BURNING_MATERIAL_MAX_TEXTURES][2]; // texture start, texture end of scanline + sVec3 l[BURNING_MATERIAL_MAX_TANGENT][2]; // Light Tangent start, end +}; + +// passed to pixel Shader +struct sPixelShaderData +{ + tVideoSample *dst; + fp24 *z; + + s32 xStart; + s32 xEnd; + s32 dx; + s32 i; +}; + +/* + load a color value +*/ +inline void getTexel_plain2 ( tFixPoint &r, tFixPoint &g, tFixPoint &b, + const sVec4 &v + ) +{ + r = tofix(v.y, FIX_POINT_F32_MUL); + g = tofix(v.z, FIX_POINT_F32_MUL); + b = tofix(v.w, FIX_POINT_F32_MUL); +} + +/* + load a color value +*/ +inline void getSample_color ( tFixPoint &a, tFixPoint &r, tFixPoint &g, tFixPoint &b, + const sVec4 &v + ) +{ + a = tofix(v.x, FIX_POINT_F32_MUL); + r = tofix ( v.y, COLOR_MAX * FIX_POINT_F32_MUL); + g = tofix ( v.z, COLOR_MAX * FIX_POINT_F32_MUL); + b = tofix ( v.w, COLOR_MAX * FIX_POINT_F32_MUL); +} + +/* + load a color value +*/ +inline void getSample_color ( tFixPoint &r, tFixPoint &g, tFixPoint &b,const sVec4 &v ) +{ + r = tofix ( v.y, COLOR_MAX * FIX_POINT_F32_MUL); + g = tofix ( v.z, COLOR_MAX * FIX_POINT_F32_MUL); + b = tofix ( v.w, COLOR_MAX * FIX_POINT_F32_MUL); +} + +/* + load a color value +*/ +inline void getSample_color ( tFixPoint &r, tFixPoint &g, tFixPoint &b, + const sVec4 &v, const f32 mulby ) +{ + r = tofix ( v.y, mulby); + g = tofix ( v.z, mulby); + b = tofix ( v.w, mulby); +} + + + +} + +} + +#endif + diff --git a/source/Irrlicht/SB3DStructs.h b/source/Irrlicht/SB3DStructs.h new file mode 100644 index 00000000..8f88a850 --- /dev/null +++ b/source/Irrlicht/SB3DStructs.h @@ -0,0 +1,71 @@ +// Copyright (C) 2006-2012 Luke Hoschke +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +// B3D Mesh loader +// File format designed by Mark Sibly for the Blitz3D engine and has been +// declared public domain + +#include "IrrCompileConfig.h" + +#ifndef SB3DSTRUCTS_H +#define SB3DSTRUCTS_H + +#include "SMaterial.h" + +namespace irr { +namespace scene { + +struct SB3dChunkHeader +{ + c8 name[4]; + s32 size; +}; + +struct SB3dChunk +{ + SB3dChunk(const SB3dChunkHeader& header, long sp) + : length(header.size+8), startposition(sp) + { + name[0]=header.name[0]; + name[1]=header.name[1]; + name[2]=header.name[2]; + name[3]=header.name[3]; + } + c8 name[4]; + s32 length; + long startposition; +}; + +struct SB3dTexture +{ + core::stringc TextureName; + s32 Flags; + s32 Blend; + f32 Xpos; + f32 Ypos; + f32 Xscale; + f32 Yscale; + f32 Angle; +}; + +struct SB3dMaterial +{ + SB3dMaterial() : red(1.0f), green(1.0f), + blue(1.0f), alpha(1.0f), shininess(0.0f), blend(1), + fx(0) + { + for (u32 i=0; i> (2 + 3); + while (i) + { + d[0] = value; + d[1] = value; + d[2] = value; + d[3] = value; + + d[4] = value; + d[5] = value; + d[6] = value; + d[7] = value; + + d += 8; + i -= 1; + } + + i = (bytesize >> 2 ) & 7; + while (i) + { + d[0] = value; + d += 1; + i -= 1; + } +} + +//! a more useful memset for pixel +// (standard memset only works with 8-bit values) +inline void memset16(void * dest, const u16 value, u32 bytesize) +{ + u16 * d = (u16*) dest; + + u32 i; + + // loops unrolled to reduce the number of increments by factor ~8. + i = bytesize >> (1 + 3); + while (i) + { + d[0] = value; + d[1] = value; + d[2] = value; + d[3] = value; + + d[4] = value; + d[5] = value; + d[6] = value; + d[7] = value; + + d += 8; + --i; + } + + i = (bytesize >> 1 ) & 7; + while (i) + { + d[0] = value; + ++d; + --i; + } +} + +/* + use biased loop counter + --> 0 byte copy is forbidden +*/ +REALINLINE void memcpy32_small ( void * dest, const void *source, u32 bytesize ) +{ + u32 c = bytesize >> 2; + + do + { + ((u32*) dest ) [ c-1 ] = ((u32*) source) [ c-1 ]; + } while ( --c ); + +} + + + +// integer log2 of a float ieee 754. TODO: non ieee floating point +static inline s32 s32_log2_f32( f32 f) +{ + u32 x = IR ( f ); + return ((x & 0x7F800000) >> 23) - 127; +} + +static inline s32 s32_log2_s32(u32 x) +{ + return s32_log2_f32( (f32) x); +} + +static inline s32 s32_abs(s32 x) +{ + s32 b = x >> 31; + return (x ^ b ) - b; +} + + +//! conditional set based on mask and arithmetic shift +REALINLINE u32 if_mask_a_else_b ( const u32 mask, const u32 a, const u32 b ) +{ + return ( mask & ( a ^ b ) ) ^ b; +} + +// ------------------ Video--------------------------------------- +/*! + Pixel = dest * ( 1 - alpha ) + source * alpha + alpha [0;256] +*/ +REALINLINE u32 PixelBlend32 ( const u32 c2, const u32 c1, u32 alpha ) +{ + u32 srcRB = c1 & 0x00FF00FF; + u32 srcXG = c1 & 0x0000FF00; + + u32 dstRB = c2 & 0x00FF00FF; + u32 dstXG = c2 & 0x0000FF00; + + + u32 rb = srcRB - dstRB; + u32 xg = srcXG - dstXG; + + rb *= alpha; + xg *= alpha; + rb >>= 8; + xg >>= 8; + + rb += dstRB; + xg += dstXG; + + rb &= 0x00FF00FF; + xg &= 0x0000FF00; + + return rb | xg; +} + +/*! + Pixel = dest * ( 1 - alpha ) + source * alpha + alpha [0;32] +*/ +inline u16 PixelBlend16 ( const u16 c2, const u32 c1, const u16 alpha ) +{ + const u16 srcRB = c1 & 0x7C1F; + const u16 srcXG = c1 & 0x03E0; + + const u16 dstRB = c2 & 0x7C1F; + const u16 dstXG = c2 & 0x03E0; + + u32 rb = srcRB - dstRB; + u32 xg = srcXG - dstXG; + + rb *= alpha; + xg *= alpha; + rb >>= 5; + xg >>= 5; + + rb += dstRB; + xg += dstXG; + + rb &= 0x7C1F; + xg &= 0x03E0; + + return (u16)(rb | xg); +} + +/* + Pixel = c0 * (c1/31). c0 Alpha retain +*/ +inline u16 PixelMul16 ( const u16 c0, const u16 c1) +{ + return (u16)((( ( (c0 & 0x7C00) * (c1 & 0x7C00) ) & 0x3E000000 ) >> 15 ) | + (( ( (c0 & 0x03E0) * (c1 & 0x03E0) ) & 0x000F8000 ) >> 10 ) | + (( ( (c0 & 0x001F) * (c1 & 0x001F) ) & 0x000003E0 ) >> 5 ) | + (c0 & 0x8000)); +} + +/* + Pixel = c0 * (c1/31). +*/ +inline u16 PixelMul16_2 ( u16 c0, u16 c1) +{ + return (u16)(( ( (c0 & 0x7C00) * (c1 & 0x7C00) ) & 0x3E000000 ) >> 15 | + ( ( (c0 & 0x03E0) * (c1 & 0x03E0) ) & 0x000F8000 ) >> 10 | + ( ( (c0 & 0x001F) * (c1 & 0x001F) ) & 0x000003E0 ) >> 5 | + ( c0 & c1 & 0x8000)); +} + +/* + Pixel = c0 * (c1/255). c0 Alpha Retain +*/ +REALINLINE u32 PixelMul32 ( const u32 c0, const u32 c1) +{ + return (c0 & 0xFF000000) | + (( ( (c0 & 0x00FF0000) >> 12 ) * ( (c1 & 0x00FF0000) >> 12 ) ) & 0x00FF0000 ) | + (( ( (c0 & 0x0000FF00) * (c1 & 0x0000FF00) ) >> 16 ) & 0x0000FF00 ) | + (( ( (c0 & 0x000000FF) * (c1 & 0x000000FF) ) >> 8 ) & 0x000000FF); +} + +/* + Pixel = c0 * (c1/255). +*/ +REALINLINE u32 PixelMul32_2 ( const u32 c0, const u32 c1) +{ + return (( ( (c0 & 0xFF000000) >> 16 ) * ( (c1 & 0xFF000000) >> 16 ) ) & 0xFF000000 ) | + (( ( (c0 & 0x00FF0000) >> 12 ) * ( (c1 & 0x00FF0000) >> 12 ) ) & 0x00FF0000 ) | + (( ( (c0 & 0x0000FF00) * (c1 & 0x0000FF00) ) >> 16 ) & 0x0000FF00 ) | + (( ( (c0 & 0x000000FF) * (c1 & 0x000000FF) ) >> 8 ) & 0x000000FF); +} + +/* + Pixel = clamp ( c0 + c1, 0, 255 ) +*/ +REALINLINE u32 PixelAdd32 ( const u32 c2, const u32 c1) +{ + u32 sum = ( c2 & 0x00FFFFFF ) + ( c1 & 0x00FFFFFF ); + u32 low_bits = ( c2 ^ c1 ) & 0x00010101; + s32 carries = ( sum - low_bits ) & 0x01010100; + u32 modulo = sum - carries; + u32 clamp = carries - ( carries >> 8 ); + return modulo | clamp; +} + +#if 0 + +// 1 - Bit Alpha Blending +inline u16 PixelBlend16 ( const u16 destination, const u16 source ) +{ + 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 destination, const u32 source ) +{ + 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; + } +} +#else + +// 1 - Bit Alpha Blending +inline u16 PixelBlend16 ( const u16 c2, const u16 c1 ) +{ + u16 mask = ((c1 & 0x8000) >> 15 ) + 0x7fff; + return (c2 & mask ) | ( c1 & ~mask ); +} + +// 1 - Bit Alpha Blending 16Bit SIMD +inline u32 PixelBlend16_simd ( const u32 c2, const u32 c1 ) +{ + u32 mask = ((c1 & 0x80008000) >> 15 ) + 0x7fff7fff; + return (c2 & mask ) | ( c1 & ~mask ); +} + +#endif + +/*! + Pixel = dest * ( 1 - SourceAlpha ) + source * SourceAlpha (OpenGL blending) +*/ +inline u32 PixelBlend32 ( const u32 c2, const u32 c1 ) +{ + // alpha test + u32 alpha = c1 & 0xFF000000; + + if ( 0 == alpha ) + return c2; + if ( 0xFF000000 == alpha ) + { + return c1; + } + + alpha >>= 24; + + // add highbit alpha, if ( alpha > 127 ) alpha += 1; + alpha += ( alpha >> 7); + + u32 srcRB = c1 & 0x00FF00FF; + u32 srcXG = c1 & 0x0000FF00; + + u32 dstRB = c2 & 0x00FF00FF; + u32 dstXG = c2 & 0x0000FF00; + + + u32 rb = srcRB - dstRB; + u32 xg = srcXG - dstXG; + + rb *= alpha; + xg *= alpha; + rb >>= 8; + xg >>= 8; + + rb += dstRB; + xg += dstXG; + + rb &= 0x00FF00FF; + xg &= 0x0000FF00; + + return (c1 & 0xFF000000) | rb | xg; +} + +/*! + Pixel => + color = sourceAlpha > 0 ? source, else dest + alpha = max(destAlpha, sourceAlpha) +*/ +inline u16 PixelCombine16 ( const u16 c2, const u16 c1 ) +{ + if ( video::getAlpha(c1) > 0 ) + return c1; + else + return c2; +} + +/*! + Pixel => + color = dest * ( 1 - SourceAlpha ) + source * SourceAlpha, + alpha = destAlpha * ( 1 - SourceAlpha ) + sourceAlpha + + where "1" means "full scale" (255) +*/ +inline u32 PixelCombine32 ( const u32 c2, const u32 c1 ) +{ + // alpha test + u32 alpha = c1 & 0xFF000000; + + if ( 0 == alpha ) + return c2; + if ( 0xFF000000 == alpha ) + { + return c1; + } + + alpha >>= 24; + + // add highbit alpha, if ( alpha > 127 ) alpha += 1; + // stretches [0;255] to [0;256] to avoid division by 255. use division 256 == shr 8 + alpha += ( alpha >> 7); + + u32 srcRB = c1 & 0x00FF00FF; + u32 srcXG = c1 & 0x0000FF00; + + u32 dstRB = c2 & 0x00FF00FF; + u32 dstXG = c2 & 0x0000FF00; + + + u32 rb = srcRB - dstRB; + u32 xg = srcXG - dstXG; + + rb *= alpha; + xg *= alpha; + rb >>= 8; + xg >>= 8; + + rb += dstRB; + xg += dstXG; + + rb &= 0x00FF00FF; + xg &= 0x0000FF00; + + u32 sa = c1 >> 24; + u32 da = c2 >> 24; + u32 blendAlpha_fix8 = (sa*256 + da*(256-alpha))>>8; + return blendAlpha_fix8 << 24 | rb | xg; +} + + + +// ------------------ Fix Point ---------------------------------- + +typedef s32 tFixPoint; +typedef u32 tFixPointu; + +// Fix Point 12 +#if 0 + #define FIX_POINT_PRE 12 + #define FIX_POINT_FRACT_MASK 0xFFF + #define FIX_POINT_SIGNED_MASK 0xFFFFF000 + #define FIX_POINT_UNSIGNED_MASK 0x7FFFF000 + #define FIX_POINT_ONE 0x1000 + #define FIX_POINT_ZERO_DOT_FIVE 0x0800 + #define FIX_POINT_F32_MUL 4096.f +#endif + +// Fix Point 10 +#if 1 + #define FIX_POINT_PRE 10 + #define FIX_POINT_FRACT_MASK 0x3FF + #define FIX_POINT_SIGNED_MASK 0xFFFFFC00 + #define FIX_POINT_UNSIGNED_MASK 0x7FFFFE00 + #define FIX_POINT_ONE 0x400 + #define FIX_POINT_ZERO_DOT_FIVE 0x200 + #define FIX_POINT_F32_MUL 1024.f +#endif + +// Fix Point 9 +#if 0 + #define FIX_POINT_PRE 9 + #define FIX_POINT_FRACT_MASK 0x1FF + #define FIX_POINT_SIGNED_MASK 0xFFFFFE00 + #define FIX_POINT_UNSIGNED_MASK 0x7FFFFE00 + #define FIX_POINT_ONE 0x200 + #define FIX_POINT_ZERO_DOT_FIVE 0x100 + #define FIX_POINT_F32_MUL 512.f +#endif + +// Fix Point 7 +#if 0 + #define FIX_POINT_PRE 7 + #define FIX_POINT_FRACT_MASK 0x7F + #define FIX_POINT_SIGNED_MASK 0xFFFFFF80 + #define FIX_POINT_UNSIGNED_MASK 0x7FFFFF80 + #define FIX_POINT_ONE 0x80 + #define FIX_POINT_ZERO_DOT_FIVE 0x40 + #define FIX_POINT_F32_MUL 128.f +#endif + +#define FIXPOINT_COLOR_MAX ( COLOR_MAX << FIX_POINT_PRE ) +#define FIX_POINT_HALF_COLOR ( (tFixPoint) ( ((f32) COLOR_MAX / 2.f * FIX_POINT_F32_MUL ) ) ) + + +/* + convert signed integer to fixpoint +*/ +inline tFixPoint s32_to_fixPoint (const s32 x) +{ + return x << FIX_POINT_PRE; +} + +inline tFixPointu u32_to_fixPoint (const u32 x) +{ + return x << FIX_POINT_PRE; +} + +inline u32 fixPointu_to_u32 (const tFixPointu x) +{ + return x >> FIX_POINT_PRE; +} + + +// 1/x * FIX_POINT +#define fix_inverse32(x) (FIX_POINT_F32_MUL / (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.. +*/ +static inline int f_round2(f32 f) +{ + f += (3<<22); + return IR(f) - 0x4b400000; +} + +/* + convert f32 to Fix Point. + multiply is needed anyway, so scale mulby +*/ +REALINLINE tFixPoint tofix0 (const f32 x, const f32 mulby = FIX_POINT_F32_MUL ) +{ + return (tFixPoint) (x * mulby); +} +#define tofix(x,y) (tFixPoint)(x * y) + +/* + Fix Point , Fix Point Multiply +*/ +REALINLINE tFixPointu imulFixu(const tFixPointu x, const tFixPointu y) +{ + return (x * y) >> (tFixPointu) FIX_POINT_PRE; +} + +/* + Fix Point , Fix Point Multiply +*/ +REALINLINE tFixPoint imulFix(const tFixPoint x, const tFixPoint y) +{ + return ( x * y) >> ( FIX_POINT_PRE ); +} + +/* + Fix Point , Fix Point Multiply x * y * 2 +*/ +REALINLINE tFixPoint imulFix2(const tFixPoint x, const tFixPoint y) +{ + return ( x * y) >> ( FIX_POINT_PRE -1 ); +} + + +/* + Multiply x * y * 1 +*/ +REALINLINE tFixPoint imulFix_tex1(const tFixPoint x, const tFixPoint y) +{ + return ( ( (tFixPointu) x >> 2 ) * ( (tFixPointu) y >> 2 ) ) >> (tFixPointu) ( FIX_POINT_PRE + 4 ); +} + +/* + Multiply x * y * 2 +*/ +REALINLINE tFixPoint imulFix_tex2(const tFixPoint x, const tFixPoint y) +{ + return ( ( (tFixPointu) x >> 2 ) * ( (tFixPointu) y >> 2 ) ) >> (tFixPointu) ( FIX_POINT_PRE + 3 ); +} + +/* + Multiply x * y * 4 +*/ +REALINLINE tFixPoint imulFix_tex4(const tFixPoint x, const tFixPoint y) +{ +#ifdef SOFTWARE_DRIVER_2_32BIT + return ( ( (tFixPointu) x >> 2 ) * ( (tFixPointu) y >> 2 ) ) >> (tFixPointu) ( FIX_POINT_PRE + 2 ); +#else + return ( x * y) >> ( FIX_POINT_PRE + ( VIDEO_SAMPLE_GRANULARITY * 3 ) ); +#endif +} + +/*! + clamp FixPoint to maxcolor in FixPoint, min(a,31) +*/ +REALINLINE tFixPoint clampfix_maxcolor ( const tFixPoint a) +{ + tFixPoint c = (a - FIXPOINT_COLOR_MAX) >> 31; + return (a & c) | ( FIXPOINT_COLOR_MAX & ~c); +} + +/*! + clamp FixPoint to 0 in FixPoint, max(a,0) +*/ +REALINLINE tFixPoint clampfix_mincolor ( const tFixPoint a) +{ + return a - ( a & ( a >> 31 ) ); +} + +REALINLINE tFixPoint saturateFix ( const tFixPoint a) +{ + return clampfix_mincolor ( clampfix_maxcolor ( a ) ); +} + + +// rount fixpoint to int +inline s32 roundFix ( const tFixPoint x ) +{ + return ( x + FIX_POINT_ZERO_DOT_FIVE ) >> FIX_POINT_PRE; +} + + + +// x in [0;1[ +inline s32 f32_to_23Bits(const f32 x) +{ + f32 y = x + 1.f; + return IR(y) & 0x7FFFFF; // last 23 bits +} + +/*! + return VideoSample from fixpoint +*/ +REALINLINE tVideoSample fix_to_color ( const tFixPoint r, const tFixPoint g, const tFixPoint b ) +{ + return ( FIXPOINT_COLOR_MAX & FIXPOINT_COLOR_MAX) << ( SHIFT_A - FIX_POINT_PRE ) | + ( r & FIXPOINT_COLOR_MAX) << ( SHIFT_R - FIX_POINT_PRE ) | + ( g & FIXPOINT_COLOR_MAX) >> ( FIX_POINT_PRE - SHIFT_G ) | + ( b & FIXPOINT_COLOR_MAX) >> ( FIX_POINT_PRE - SHIFT_B ); +} + + +/*! + return VideoSample from fixpoint +*/ +REALINLINE tVideoSample fix4_to_color ( const tFixPoint a, const tFixPoint r, const tFixPoint g, const tFixPoint b ) +{ + return ( a & (FIX_POINT_FRACT_MASK - 1 )) << ( SHIFT_A - 1 ) | + ( r & FIXPOINT_COLOR_MAX) << ( SHIFT_R - FIX_POINT_PRE ) | + ( g & FIXPOINT_COLOR_MAX) >> ( FIX_POINT_PRE - SHIFT_G ) | + ( b & FIXPOINT_COLOR_MAX) >> ( FIX_POINT_PRE - SHIFT_B ); +} + +/*! + return fixpoint from VideoSample granularity COLOR_MAX +*/ +inline void color_to_fix ( tFixPoint &r, tFixPoint &g, tFixPoint &b, const tVideoSample t00 ) +{ + (tFixPointu&) r = (t00 & MASK_R) >> ( SHIFT_R - FIX_POINT_PRE ); + (tFixPointu&) g = (t00 & MASK_G) << ( FIX_POINT_PRE - SHIFT_G ); + (tFixPointu&) b = (t00 & MASK_B) << ( FIX_POINT_PRE - SHIFT_B ); +} + +/*! + return fixpoint from VideoSample granularity COLOR_MAX +*/ +inline void color_to_fix ( tFixPoint &a, tFixPoint &r, tFixPoint &g, tFixPoint &b, const tVideoSample t00 ) +{ + (tFixPointu&) a = (t00 & MASK_A) >> ( SHIFT_A - FIX_POINT_PRE ); + (tFixPointu&) r = (t00 & MASK_R) >> ( SHIFT_R - FIX_POINT_PRE ); + (tFixPointu&) g = (t00 & MASK_G) << ( FIX_POINT_PRE - SHIFT_G ); + (tFixPointu&) b = (t00 & MASK_B) << ( FIX_POINT_PRE - SHIFT_B ); +} + +/*! + return fixpoint from VideoSample granularity 0..FIX_POINT_ONE +*/ +inline void color_to_fix1 ( tFixPoint &r, tFixPoint &g, tFixPoint &b, const tVideoSample t00 ) +{ + (tFixPointu&) r = (t00 & MASK_R) >> ( SHIFT_R + COLOR_MAX_LOG2 - FIX_POINT_PRE ); + (tFixPointu&) g = (t00 & MASK_G) >> ( SHIFT_G + COLOR_MAX_LOG2 - FIX_POINT_PRE ); + (tFixPointu&) b = (t00 & MASK_B) << ( FIX_POINT_PRE - COLOR_MAX_LOG2 ); +} + +/*! + return fixpoint from VideoSample granularity 0..FIX_POINT_ONE +*/ +inline void color_to_fix1 ( tFixPoint &a, tFixPoint &r, tFixPoint &g, tFixPoint &b, const tVideoSample t00 ) +{ + (tFixPointu&) a = (t00 & MASK_A) >> ( SHIFT_A + COLOR_MAX_LOG2 - FIX_POINT_PRE ); + (tFixPointu&) r = (t00 & MASK_R) >> ( SHIFT_R + COLOR_MAX_LOG2 - FIX_POINT_PRE ); + (tFixPointu&) g = (t00 & MASK_G) >> ( SHIFT_G + COLOR_MAX_LOG2 - FIX_POINT_PRE ); + (tFixPointu&) b = (t00 & MASK_B) << ( FIX_POINT_PRE - COLOR_MAX_LOG2 ); +} + + + +// ----- FP24 ---- floating point z-buffer + +#if 1 +typedef f32 fp24; +#else +struct fp24 +{ + u32 v; + + fp24() {} + + fp24 ( const f32 f ) + { + f32 y = f + 1.f; + v = ((u32&)y) & 0x7FFFFF; // last 23 bits + } + + void operator=(const f32 f ) + { + f32 y = f + 1.f; + v = ((u32&)y) & 0x7FFFFF; // last 23 bits + } + + void operator+=(const fp24 &other ) + { + v += other.v; + } + + operator f32 () const + { + f32 r = FR ( v ); + return r + 1.f; + } + +}; +#endif + + +// ------------------------ Internal Texture ----------------------------- + +struct sInternalTexture +{ + u32 textureXMask; + u32 textureYMask; + + u32 pitchlog2; + void *data; + + video::CSoftwareTexture2 *Texture; + s32 lodLevel; +}; + + + +// get video sample plain +inline tVideoSample getTexel_plain ( const sInternalTexture * t, const tFixPointu tx, const tFixPointu ty ) +{ + u32 ofs; + + ofs = ( ( ty & t->textureYMask ) >> FIX_POINT_PRE ) << t->pitchlog2; + ofs |= ( tx & t->textureXMask ) >> ( FIX_POINT_PRE - VIDEO_SAMPLE_GRANULARITY ); + + // texel + return *((tVideoSample*)( (u8*) t->data + ofs )); +} + +// get video sample to fix +inline void getTexel_fix ( tFixPoint &r, tFixPoint &g, tFixPoint &b, + const sInternalTexture * t, const tFixPointu tx, const tFixPointu ty + ) +{ + u32 ofs; + + ofs = ( ( ty & t->textureYMask ) >> FIX_POINT_PRE ) << t->pitchlog2; + ofs |= ( tx & t->textureXMask ) >> ( FIX_POINT_PRE - VIDEO_SAMPLE_GRANULARITY ); + + // texel + tVideoSample t00; + t00 = *((tVideoSample*)( (u8*) t->data + ofs )); + + r = (t00 & MASK_R) >> ( SHIFT_R - FIX_POINT_PRE); + g = (t00 & MASK_G) << ( FIX_POINT_PRE - SHIFT_G ); + b = (t00 & MASK_B) << ( FIX_POINT_PRE - SHIFT_B ); + +} + +// get video sample to fixpoint +REALINLINE void getTexel_fix ( tFixPoint &a, + const sInternalTexture * t, const tFixPointu tx, const tFixPointu ty) +{ + u32 ofs; + + ofs = ( ( ty & t->textureYMask ) >> FIX_POINT_PRE ) << t->pitchlog2; + ofs |= ( tx & t->textureXMask ) >> ( FIX_POINT_PRE - VIDEO_SAMPLE_GRANULARITY ); + + // texel + tVideoSample t00; + t00 = *((tVideoSample*)( (u8*) t->data + ofs )); + + a = (t00 & MASK_A) >> ( SHIFT_A - FIX_POINT_PRE); +} + + +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 + ) +{ + static const tFixPointu dithermask[] = + { + 0x00,0x80,0x20,0xa0, + 0xc0,0x40,0xe0,0x60, + 0x30,0xb0,0x10,0x90, + 0xf0,0x70,0xd0,0x50 + }; + + const u32 index = (y & 3 ) << 2 | (x & 3); + + const tFixPointu _ntx = (tx + dithermask [ index ] ) & t->textureXMask; + const tFixPointu _nty = (ty + dithermask [ index ] ) & t->textureYMask; + + u32 ofs; + ofs = ( ( _nty ) >> FIX_POINT_PRE ) << t->pitchlog2; + ofs |= ( _ntx ) >> ( FIX_POINT_PRE - VIDEO_SAMPLE_GRANULARITY ); + + // texel + const tVideoSample t00 = *((tVideoSample*)( (u8*) t->data + ofs )); + + (tFixPointu &) r = (t00 & MASK_R) >> ( SHIFT_R - FIX_POINT_PRE); + (tFixPointu &) g = (t00 & MASK_G) << ( FIX_POINT_PRE - SHIFT_G ); + (tFixPointu &) b = (t00 & MASK_B) << ( FIX_POINT_PRE - SHIFT_B ); + +} + +/* + load a sample from internal texture at position tx,ty to fixpoint +*/ +#ifndef SOFTWARE_DRIVER_2_BILINEAR + +// get Sample linear == getSample_fixpoint + +inline void getSample_texture ( tFixPoint &r, tFixPoint &g, tFixPoint &b, + const sInternalTexture * t, const tFixPointu tx, const tFixPointu ty + ) +{ + u32 ofs; + + ofs = ( ( ty & t->textureYMask ) >> FIX_POINT_PRE ) << t->pitchlog2; + ofs |= ( tx & t->textureXMask ) >> ( FIX_POINT_PRE - VIDEO_SAMPLE_GRANULARITY ); + + // texel + const tVideoSample t00 = *((tVideoSample*)( (u8*) t->data + ofs )); + + (tFixPointu &) r = (t00 & MASK_R) >> ( SHIFT_R - FIX_POINT_PRE); + (tFixPointu &) g = (t00 & MASK_G) << ( FIX_POINT_PRE - SHIFT_G ); + (tFixPointu &) b = (t00 & MASK_B) << ( FIX_POINT_PRE - SHIFT_B ); +} + +inline void getSample_texture ( tFixPoint &a, tFixPoint &r, tFixPoint &g, tFixPoint &b, + const sInternalTexture * t, const tFixPointu tx, const tFixPointu ty + ) +{ + u32 ofs; + + ofs = ( ( ty & t->textureYMask ) >> FIX_POINT_PRE ) << t->pitchlog2; + ofs |= ( tx & t->textureXMask ) >> ( FIX_POINT_PRE - VIDEO_SAMPLE_GRANULARITY ); + + // texel + const tVideoSample t00 = *((tVideoSample*)( (u8*) t->data + ofs )); + + (tFixPointu &)a = (t00 & MASK_A) >> ( SHIFT_A - FIX_POINT_PRE); + (tFixPointu &)r = (t00 & MASK_R) >> ( SHIFT_R - FIX_POINT_PRE); + (tFixPointu &)g = (t00 & MASK_G) << ( FIX_POINT_PRE - SHIFT_G ); + (tFixPointu &)b = (t00 & MASK_B) << ( FIX_POINT_PRE - SHIFT_B ); +} + + +#else + + +// get sample linear +REALINLINE void getSample_linear ( tFixPointu &r, tFixPointu &g, tFixPointu &b, + const sInternalTexture * t, const tFixPointu tx, const tFixPointu ty + ) +{ + u32 ofs; + + ofs = ( ( ty & t->textureYMask ) >> FIX_POINT_PRE ) << t->pitchlog2; + ofs |= ( tx & t->textureXMask ) >> ( FIX_POINT_PRE - VIDEO_SAMPLE_GRANULARITY ); + + // texel + tVideoSample t00; + t00 = *((tVideoSample*)( (u8*) t->data + ofs )); + + r = (t00 & MASK_R) >> SHIFT_R; + g = (t00 & MASK_G) >> SHIFT_G; + b = (t00 & MASK_B); +} + +// get Sample bilinear +REALINLINE void getSample_texture ( tFixPoint &r, tFixPoint &g, tFixPoint &b, + const sInternalTexture * t, const tFixPointu tx, const tFixPointu ty + ) +{ + + tFixPointu r00,g00,b00; + tFixPointu r01,g01,b01; + tFixPointu r10,g10,b10; + tFixPointu r11,g11,b11; + +#if 0 + getSample_linear ( r00, g00, b00, t, tx,ty ); + getSample_linear ( r10, g10, b10, t, tx + FIX_POINT_ONE,ty ); + getSample_linear ( r01, g01, b01, t, tx,ty + FIX_POINT_ONE ); + getSample_linear ( r11, g11, b11, t, tx + FIX_POINT_ONE,ty + FIX_POINT_ONE ); +#else + u32 o0, o1,o2,o3; + tVideoSample t00; + + o0 = ( ( (ty) & t->textureYMask ) >> FIX_POINT_PRE ) << t->pitchlog2; + o1 = ( ( (ty+FIX_POINT_ONE) & t->textureYMask ) >> FIX_POINT_PRE ) << t->pitchlog2; + o2 = ( (tx) & t->textureXMask ) >> ( FIX_POINT_PRE - VIDEO_SAMPLE_GRANULARITY ); + o3 = ( (tx+FIX_POINT_ONE) & t->textureXMask ) >> ( FIX_POINT_PRE - VIDEO_SAMPLE_GRANULARITY ); + + t00 = *((tVideoSample*)( (u8*) t->data + (o0 | o2 ) )); + r00 = (t00 & MASK_R) >> SHIFT_R; + g00 = (t00 & MASK_G) >> SHIFT_G; + b00 = (t00 & MASK_B); + + t00 = *((tVideoSample*)( (u8*) t->data + (o0 | o3 ) )); + r10 = (t00 & MASK_R) >> SHIFT_R; + g10 = (t00 & MASK_G) >> SHIFT_G; + b10 = (t00 & MASK_B); + + t00 = *((tVideoSample*)( (u8*) t->data + (o1 | o2 ) )); + r01 = (t00 & MASK_R) >> SHIFT_R; + g01 = (t00 & MASK_G) >> SHIFT_G; + b01 = (t00 & MASK_B); + + t00 = *((tVideoSample*)( (u8*) t->data + (o1 | o3 ) )); + r11 = (t00 & MASK_R) >> SHIFT_R; + g11 = (t00 & MASK_G) >> SHIFT_G; + b11 = (t00 & MASK_B); + +#endif + + const tFixPointu txFract = tx & FIX_POINT_FRACT_MASK; + const tFixPointu txFractInv = FIX_POINT_ONE - txFract; + + const tFixPointu tyFract = ty & FIX_POINT_FRACT_MASK; + const tFixPointu tyFractInv = FIX_POINT_ONE - tyFract; + + const tFixPointu w00 = imulFixu ( txFractInv, tyFractInv ); + const tFixPointu w10 = imulFixu ( txFract , tyFractInv ); + const tFixPointu w01 = imulFixu ( txFractInv, tyFract ); + const tFixPointu w11 = imulFixu ( txFract , tyFract ); + + r = (r00 * w00 ) + + (r01 * w01 ) + + (r10 * w10 ) + + (r11 * w11 ); + + g = (g00 * w00 ) + + (g01 * w01 ) + + (g10 * w10 ) + + (g11 * w11 ); + + b = (b00 * w00 ) + + (b01 * w01 ) + + (b10 * w10 ) + + (b11 * w11 ); + +} + + +// get sample linear +REALINLINE void getSample_linear ( tFixPointu &a, tFixPointu &r, tFixPointu &g, tFixPointu &b, + const sInternalTexture * t, const tFixPointu tx, const tFixPointu ty + ) +{ + u32 ofs; + + ofs = ( ( ty & t->textureYMask ) >> FIX_POINT_PRE ) << t->pitchlog2; + ofs |= ( tx & t->textureXMask ) >> ( FIX_POINT_PRE - VIDEO_SAMPLE_GRANULARITY ); + + // texel + tVideoSample t00; + t00 = *((tVideoSample*)( (u8*) t->data + ofs )); + + a = (t00 & MASK_A) >> SHIFT_A; + r = (t00 & MASK_R) >> SHIFT_R; + g = (t00 & MASK_G) >> SHIFT_G; + b = (t00 & MASK_B); +} + +// get Sample bilinear +REALINLINE void getSample_texture ( tFixPoint &a, tFixPoint &r, tFixPoint &g, tFixPoint &b, + const sInternalTexture * t, const tFixPointu tx, const tFixPointu ty + ) +{ + + tFixPointu a00, r00,g00,b00; + tFixPointu a01, r01,g01,b01; + tFixPointu a10, r10,g10,b10; + tFixPointu a11, r11,g11,b11; + + getSample_linear ( a00, r00, g00, b00, t, tx,ty ); + getSample_linear ( a10, r10, g10, b10, t, tx + FIX_POINT_ONE,ty ); + getSample_linear ( a01, r01, g01, b01, t, tx,ty + FIX_POINT_ONE ); + getSample_linear ( a11, r11, g11, b11, t, tx + FIX_POINT_ONE,ty + FIX_POINT_ONE ); + + const tFixPointu txFract = tx & FIX_POINT_FRACT_MASK; + const tFixPointu txFractInv = FIX_POINT_ONE - txFract; + + const tFixPointu tyFract = ty & FIX_POINT_FRACT_MASK; + const tFixPointu tyFractInv = FIX_POINT_ONE - tyFract; + + const tFixPointu w00 = imulFixu ( txFractInv, tyFractInv ); + const tFixPointu w10 = imulFixu ( txFract , tyFractInv ); + const tFixPointu w01 = imulFixu ( txFractInv, tyFract ); + const tFixPointu w11 = imulFixu ( txFract , tyFract ); + + a = (a00 * w00 ) + + (a01 * w01 ) + + (a10 * w10 ) + + (a11 * w11 ); + + r = (r00 * w00 ) + + (r01 * w01 ) + + (r10 * w10 ) + + (r11 * w11 ); + + g = (g00 * w00 ) + + (g01 * w01 ) + + (g10 * w10 ) + + (g11 * w11 ); + + b = (b00 * w00 ) + + (b01 * w01 ) + + (b10 * w10 ) + + (b11 * w11 ); + +} + + +#endif + +// some 2D Defines +struct AbsRectangle +{ + s32 x0; + s32 y0; + s32 x1; + s32 y1; +}; + +//! 2D Intersection test +inline bool intersect ( AbsRectangle &dest, const AbsRectangle& a, const AbsRectangle& b) +{ + dest.x0 = core::s32_max( a.x0, b.x0 ); + dest.y0 = core::s32_max( a.y0, b.y0 ); + dest.x1 = core::s32_min( a.x1, b.x1 ); + dest.y1 = core::s32_min( a.y1, b.y1 ); + return dest.x0 < dest.x1 && dest.y0 < dest.y1; +} + +// some 1D defines +struct sIntervall +{ + s32 start; + s32 end; +}; + +// returning intersection width +inline s32 intervall_intersect_test( const sIntervall& a, const sIntervall& b) +{ + return core::s32_min( a.end, b.end ) - core::s32_max( a.start, b.start ); +} + + +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/aesGladman/Readme.txt b/source/Irrlicht/aesGladman/Readme.txt new file mode 100644 index 00000000..86842c28 --- /dev/null +++ b/source/Irrlicht/aesGladman/Readme.txt @@ -0,0 +1,25 @@ +A File Encryption Utility - VC++ 7.1 project Instructions + +1. Unzip the enclosed files into a suitable VC++ project directory. +2. Obtain the bzip2 source code from http://sources.redhat.com/bzip2/ + and unzip the files into the bzip2 sub-directory. +3. Compile the bzip2 project to give a static library +4. Compile the encfile project. +5. The executable encfile.exe is now ready for use: + + enfile password filename + + If the filename does not have the extension 'enc', it is assumed to + be a normal file that will then be encrypted to a file with the same + name but with an added extension 'enc'. + + If the filename has the extension 'enc' its is assumed to be an + encrypted file that will be decrypted to a file with the same name + but without the 'enc' extension. + +The default HASH function is SHA1, which is set up by defining USE_SHA1 in +compiling the project. If USE_SHA256 is defined instead then SHA256 is used. + +Brian Gladman + + diff --git a/source/Irrlicht/aesGladman/aes.h b/source/Irrlicht/aesGladman/aes.h new file mode 100644 index 00000000..127c886c --- /dev/null +++ b/source/Irrlicht/aesGladman/aes.h @@ -0,0 +1,137 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2003, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 26/08/2003 + + This file contains the definitions required to use AES in C. See aesopt.h + for optimisation details. +*/ + +#ifndef _AES_H +#define _AES_H + +#include "irrMath.h" + +#define AES_128 /* define if AES with 128 bit keys is needed */ +#define AES_192 /* define if AES with 192 bit keys is needed */ +#define AES_256 /* define if AES with 256 bit keys is needed */ +#define AES_VAR /* define if a variable key size is needed */ + +/* The following must also be set in assembler files if being used */ + +#define AES_ENCRYPT /* if support for encryption is needed */ +#define AES_DECRYPT /* if support for decryption is needed */ +#define AES_ERR_CHK /* for parameter checks & error return codes */ + +typedef irr::u8 aes_08t; +typedef irr::u32 aes_32t; + +#define AES_BLOCK_SIZE 16 /* the AES block size in bytes */ +#define N_COLS 4 /* the number of columns in the state */ + +/* a maximum of 60 32-bit words are needed for the key schedule */ +#define KS_LENGTH 64 + +#ifdef AES_ERR_CHK +#define aes_ret int +#define aes_good 0 +#define aes_error -1 +#else +#define aes_ret void +#endif + +#ifndef AES_DLL /* implement normal/DLL functions */ +#define aes_rval aes_ret +#else +#define aes_rval aes_ret __declspec(dllexport) _stdcall +#endif + +/* This routine must be called before first use if non-static */ +/* tables are being used */ + +void gen_tabs(void); + +/* The key length (klen) is input in bytes when it is in the range */ +/* 16 <= klen <= 32 or in bits when in the range 128 <= klen <= 256 */ + +#ifdef AES_ENCRYPT + +typedef struct +{ + aes_32t ks[KS_LENGTH]; +} aes_encrypt_ctx; + +#if defined(AES_128) || defined(AES_VAR) +aes_rval aes_encrypt_key128(const void *in_key, aes_encrypt_ctx cx[1]); +#endif + +#if defined(AES_192) || defined(AES_VAR) +aes_rval aes_encrypt_key192(const void *in_key, aes_encrypt_ctx cx[1]); +#endif + +#if defined(AES_256) || defined(AES_VAR) +aes_rval aes_encrypt_key256(const void *in_key, aes_encrypt_ctx cx[1]); +#endif + +#if defined(AES_VAR) +aes_rval aes_encrypt_key(const void *in_key, int key_len, aes_encrypt_ctx cx[1]); +#endif + +aes_rval aes_encrypt(const void *in_blk, void *out_blk, const aes_encrypt_ctx cx[1]); +#endif + +#ifdef AES_DECRYPT + +typedef struct +{ + aes_32t ks[KS_LENGTH]; +} aes_decrypt_ctx; + +#if defined(AES_128) || defined(AES_VAR) +aes_rval aes_decrypt_key128(const void *in_key, aes_decrypt_ctx cx[1]); +#endif + +#if defined(AES_192) || defined(AES_VAR) +aes_rval aes_decrypt_key192(const void *in_key, aes_decrypt_ctx cx[1]); +#endif + +#if defined(AES_256) || defined(AES_VAR) +aes_rval aes_decrypt_key256(const void *in_key, aes_decrypt_ctx cx[1]); +#endif + +#if defined(AES_VAR) +aes_rval aes_decrypt_key(const void *in_key, int key_len, aes_decrypt_ctx cx[1]); +#endif + +aes_rval aes_decrypt(const void *in_blk, void *out_blk, const aes_decrypt_ctx cx[1]); +#endif + +#endif + diff --git a/source/Irrlicht/aesGladman/aescrypt.cpp b/source/Irrlicht/aesGladman/aescrypt.cpp new file mode 100644 index 00000000..8d1feee6 --- /dev/null +++ b/source/Irrlicht/aesGladman/aescrypt.cpp @@ -0,0 +1,303 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2003, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 26/08/2003 + + This file contains the code for implementing encryption and decryption + for AES (Rijndael) for block and key sizes of 16, 24 and 32 bytes. It + can optionally be replaced by code written in assembler using NASM. For + further details see the file aesopt.h +*/ + +#include "aesopt.h" + +#define si(y,x,k,c) (s(y,c) = word_in(x, c) ^ (k)[c]) +#define so(y,x,c) word_out(y, c, s(x,c)) + +#if defined(ARRAYS) +#define locals(y,x) x[4],y[4] +#else +#define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3 +#endif + +#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ + s(y,2) = s(x,2); s(y,3) = s(x,3); +#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3) +#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3) +#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3) + +#if defined(ENCRYPTION) && !defined(AES_ASM) + +/* Visual C++ .Net v7.1 provides the fastest encryption code when using + Pentium optimization with small code but this is poor for decryption + so we need to control this with the following VC++ pragmas +*/ + +#if defined(_MSC_VER) +#pragma optimize( "s", on ) +#endif + +/* Given the column (c) of the output state variable, the following + macros give the input state variables which are needed in its + computation for each row (r) of the state. All the alternative + macros give the same end values but expand into different ways + of calculating these values. In particular the complex macro + used for dynamically variable block sizes is designed to expand + to a compile time constant whenever possible but will expand to + conditional clauses on some branches (I am grateful to Frank + Yellin for this construction) +*/ + +#define fwd_var(x,r,c)\ + ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ + : r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\ + : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ + : ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))) + +#if defined(FT4_SET) +#undef dec_fmvars +#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c)) +#elif defined(FT1_SET) +#undef dec_fmvars +#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(f,n),fwd_var,rf1,c)) +#else +#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ fwd_mcol(no_table(x,t_use(s,box),fwd_var,rf1,c))) +#endif + +#if defined(FL4_SET) +#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,l),fwd_var,rf1,c)) +#elif defined(FL1_SET) +#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(f,l),fwd_var,rf1,c)) +#else +#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(s,box),fwd_var,rf1,c)) +#endif + +aes_rval aes_encrypt(const void *in_blk, void *out_blk, const aes_encrypt_ctx cx[1]) +{ aes_32t locals(b0, b1); + const aes_32t *kp = cx->ks; +#ifdef dec_fmvars + dec_fmvars; /* declare variables for fwd_mcol() if needed */ +#endif + + aes_32t nr = (kp[45] ^ kp[52] ^ kp[53] ? kp[52] : 14); + +#ifdef AES_ERR_CHK + if( (nr != 10 || !(kp[0] | kp[3] | kp[4])) + && (nr != 12 || !(kp[0] | kp[5] | kp[6])) + && (nr != 14 || !(kp[0] | kp[7] | kp[8])) ) + return aes_error; +#endif + + state_in(b0, in_blk, kp); + +#if (ENC_UNROLL == FULL) + + switch(nr) + { + case 14: + round(fwd_rnd, b1, b0, kp + 1 * N_COLS); + round(fwd_rnd, b0, b1, kp + 2 * N_COLS); + kp += 2 * N_COLS; + case 12: + round(fwd_rnd, b1, b0, kp + 1 * N_COLS); + round(fwd_rnd, b0, b1, kp + 2 * N_COLS); + kp += 2 * N_COLS; + case 10: + round(fwd_rnd, b1, b0, kp + 1 * N_COLS); + round(fwd_rnd, b0, b1, kp + 2 * N_COLS); + round(fwd_rnd, b1, b0, kp + 3 * N_COLS); + round(fwd_rnd, b0, b1, kp + 4 * N_COLS); + round(fwd_rnd, b1, b0, kp + 5 * N_COLS); + round(fwd_rnd, b0, b1, kp + 6 * N_COLS); + round(fwd_rnd, b1, b0, kp + 7 * N_COLS); + round(fwd_rnd, b0, b1, kp + 8 * N_COLS); + round(fwd_rnd, b1, b0, kp + 9 * N_COLS); + round(fwd_lrnd, b0, b1, kp +10 * N_COLS); + } + +#else + +#if (ENC_UNROLL == PARTIAL) + { aes_32t rnd; + for(rnd = 0; rnd < (nr >> 1) - 1; ++rnd) + { + kp += N_COLS; + round(fwd_rnd, b1, b0, kp); + kp += N_COLS; + round(fwd_rnd, b0, b1, kp); + } + kp += N_COLS; + round(fwd_rnd, b1, b0, kp); +#else + { aes_32t rnd; + for(rnd = 0; rnd < nr - 1; ++rnd) + { + kp += N_COLS; + round(fwd_rnd, b1, b0, kp); + l_copy(b0, b1); + } +#endif + kp += N_COLS; + round(fwd_lrnd, b0, b1, kp); + } +#endif + + state_out(out_blk, b0); +#ifdef AES_ERR_CHK + return aes_good; +#endif +} + +#endif + +#if defined(DECRYPTION) && !defined(AES_ASM) + +/* Visual C++ .Net v7.1 provides the fastest encryption code when using + Pentium optimization with small code but this is poor for decryption + so we need to control this with the following VC++ pragmas +*/ + +#if defined(_MSC_VER) +#pragma optimize( "t", on ) +#endif + +/* Given the column (c) of the output state variable, the following + macros give the input state variables which are needed in its + computation for each row (r) of the state. All the alternative + macros give the same end values but expand into different ways + of calculating these values. In particular the complex macro + used for dynamically variable block sizes is designed to expand + to a compile time constant whenever possible but will expand to + conditional clauses on some branches (I am grateful to Frank + Yellin for this construction) +*/ + +#define inv_var(x,r,c)\ + ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ + : r == 1 ? ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))\ + : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ + : ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))) + +#if defined(IT4_SET) +#undef dec_imvars +#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,n),inv_var,rf1,c)) +#elif defined(IT1_SET) +#undef dec_imvars +#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(i,n),inv_var,rf1,c)) +#else +#define inv_rnd(y,x,k,c) (s(y,c) = inv_mcol((k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c))) +#endif + +#if defined(IL4_SET) +#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,l),inv_var,rf1,c)) +#elif defined(IL1_SET) +#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(i,l),inv_var,rf1,c)) +#else +#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c)) +#endif + +aes_rval aes_decrypt(const void *in_blk, void *out_blk, const aes_decrypt_ctx cx[1]) +{ aes_32t locals(b0, b1); +#ifdef dec_imvars + dec_imvars; /* declare variables for inv_mcol() if needed */ +#endif + + aes_32t nr = (cx->ks[45] ^ cx->ks[52] ^ cx->ks[53] ? cx->ks[52] : 14); + const aes_32t *kp = cx->ks + nr * N_COLS; + +#ifdef AES_ERR_CHK + if( (nr != 10 || !(cx->ks[0] | cx->ks[3] | cx->ks[4])) + && (nr != 12 || !(cx->ks[0] | cx->ks[5] | cx->ks[6])) + && (nr != 14 || !(cx->ks[0] | cx->ks[7] | cx->ks[8])) ) + return aes_error; +#endif + + state_in(b0, in_blk, kp); + +#if (DEC_UNROLL == FULL) + + switch(nr) + { + case 14: + round(inv_rnd, b1, b0, kp - 1 * N_COLS); + round(inv_rnd, b0, b1, kp - 2 * N_COLS); + kp -= 2 * N_COLS; + case 12: + round(inv_rnd, b1, b0, kp - 1 * N_COLS); + round(inv_rnd, b0, b1, kp - 2 * N_COLS); + kp -= 2 * N_COLS; + case 10: + round(inv_rnd, b1, b0, kp - 1 * N_COLS); + round(inv_rnd, b0, b1, kp - 2 * N_COLS); + round(inv_rnd, b1, b0, kp - 3 * N_COLS); + round(inv_rnd, b0, b1, kp - 4 * N_COLS); + round(inv_rnd, b1, b0, kp - 5 * N_COLS); + round(inv_rnd, b0, b1, kp - 6 * N_COLS); + round(inv_rnd, b1, b0, kp - 7 * N_COLS); + round(inv_rnd, b0, b1, kp - 8 * N_COLS); + round(inv_rnd, b1, b0, kp - 9 * N_COLS); + round(inv_lrnd, b0, b1, kp - 10 * N_COLS); + } + +#else + +#if (DEC_UNROLL == PARTIAL) + { aes_32t rnd; + for(rnd = 0; rnd < (nr >> 1) - 1; ++rnd) + { + kp -= N_COLS; + round(inv_rnd, b1, b0, kp); + kp -= N_COLS; + round(inv_rnd, b0, b1, kp); + } + kp -= N_COLS; + round(inv_rnd, b1, b0, kp); +#else + { aes_32t rnd; + for(rnd = 0; rnd < nr - 1; ++rnd) + { + kp -= N_COLS; + round(inv_rnd, b1, b0, kp); + l_copy(b0, b1); + } +#endif + kp -= N_COLS; + round(inv_lrnd, b0, b1, kp); + } +#endif + + state_out(out_blk, b0); +#ifdef AES_ERR_CHK + return aes_good; +#endif +} + +#endif + diff --git a/source/Irrlicht/aesGladman/aeskey.cpp b/source/Irrlicht/aesGladman/aeskey.cpp new file mode 100644 index 00000000..47d1aac9 --- /dev/null +++ b/source/Irrlicht/aesGladman/aeskey.cpp @@ -0,0 +1,461 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2003, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 26/08/2003 + + This file contains the code for implementing the key schedule for AES + (Rijndael) for block and key sizes of 16, 24, and 32 bytes. See aesopt.h + for further details including optimisation. +*/ + +#include "aesopt.h" + +/* Initialise the key schedule from the user supplied key. The key + length can be specified in bytes, with legal values of 16, 24 + and 32, or in bits, with legal values of 128, 192 and 256. These + values correspond with Nk values of 4, 6 and 8 respectively. + + The following macros implement a single cycle in the key + schedule generation process. The number of cycles needed + for each cx->n_col and nk value is: + + nk = 4 5 6 7 8 + ------------------------------ + cx->n_col = 4 10 9 8 7 7 + cx->n_col = 5 14 11 10 9 9 + cx->n_col = 6 19 15 12 11 11 + cx->n_col = 7 21 19 16 13 14 + cx->n_col = 8 29 23 19 17 14 +*/ + +#define ke4(k,i) \ +{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[4*(i)+5] = ss[1] ^= ss[0]; \ + k[4*(i)+6] = ss[2] ^= ss[1]; k[4*(i)+7] = ss[3] ^= ss[2]; \ +} +#define kel4(k,i) \ +{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[4*(i)+5] = ss[1] ^= ss[0]; \ + k[4*(i)+6] = ss[2] ^= ss[1]; k[4*(i)+7] = ss[3] ^= ss[2]; \ +} + +#define ke6(k,i) \ +{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[6*(i)+ 7] = ss[1] ^= ss[0]; \ + k[6*(i)+ 8] = ss[2] ^= ss[1]; k[6*(i)+ 9] = ss[3] ^= ss[2]; \ + k[6*(i)+10] = ss[4] ^= ss[3]; k[6*(i)+11] = ss[5] ^= ss[4]; \ +} +#define kel6(k,i) \ +{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[6*(i)+ 7] = ss[1] ^= ss[0]; \ + k[6*(i)+ 8] = ss[2] ^= ss[1]; k[6*(i)+ 9] = ss[3] ^= ss[2]; \ +} + +#define ke8(k,i) \ +{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[8*(i)+ 9] = ss[1] ^= ss[0]; \ + k[8*(i)+10] = ss[2] ^= ss[1]; k[8*(i)+11] = ss[3] ^= ss[2]; \ + k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); k[8*(i)+13] = ss[5] ^= ss[4]; \ + k[8*(i)+14] = ss[6] ^= ss[5]; k[8*(i)+15] = ss[7] ^= ss[6]; \ +} +#define kel8(k,i) \ +{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[8*(i)+ 9] = ss[1] ^= ss[0]; \ + k[8*(i)+10] = ss[2] ^= ss[1]; k[8*(i)+11] = ss[3] ^= ss[2]; \ +} + +#if defined(ENCRYPTION_KEY_SCHEDULE) + +#if defined(AES_128) || defined(AES_VAR) + +aes_rval aes_encrypt_key128(const void *in_key, aes_encrypt_ctx cx[1]) +{ aes_32t ss[4]; + + cx->ks[0] = ss[0] = word_in(in_key, 0); + cx->ks[1] = ss[1] = word_in(in_key, 1); + cx->ks[2] = ss[2] = word_in(in_key, 2); + cx->ks[3] = ss[3] = word_in(in_key, 3); + +#if ENC_UNROLL == NONE + { aes_32t i; + + for(i = 0; i < ((11 * N_COLS - 1) / 4); ++i) + ke4(cx->ks, i); + } +#else + ke4(cx->ks, 0); ke4(cx->ks, 1); + ke4(cx->ks, 2); ke4(cx->ks, 3); + ke4(cx->ks, 4); ke4(cx->ks, 5); + ke4(cx->ks, 6); ke4(cx->ks, 7); + ke4(cx->ks, 8); kel4(cx->ks, 9); +#endif + + /* cx->ks[45] ^ cx->ks[52] ^ cx->ks[53] is zero for a 256 bit */ + /* key and must be non-zero for 128 and 192 bits keys */ + cx->ks[53] = cx->ks[45] = 0; + cx->ks[52] = 10; +#ifdef AES_ERR_CHK + return aes_good; +#endif +} + +#endif + +#if defined(AES_192) || defined(AES_VAR) + +aes_rval aes_encrypt_key192(const void *in_key, aes_encrypt_ctx cx[1]) +{ aes_32t ss[6]; + + cx->ks[0] = ss[0] = word_in(in_key, 0); + cx->ks[1] = ss[1] = word_in(in_key, 1); + cx->ks[2] = ss[2] = word_in(in_key, 2); + cx->ks[3] = ss[3] = word_in(in_key, 3); + cx->ks[4] = ss[4] = word_in(in_key, 4); + cx->ks[5] = ss[5] = word_in(in_key, 5); + +#if ENC_UNROLL == NONE + { aes_32t i; + + for(i = 0; i < (13 * N_COLS - 1) / 6; ++i) + ke6(cx->ks, i); + } +#else + ke6(cx->ks, 0); ke6(cx->ks, 1); + ke6(cx->ks, 2); ke6(cx->ks, 3); + ke6(cx->ks, 4); ke6(cx->ks, 5); + ke6(cx->ks, 6); kel6(cx->ks, 7); +#endif + + /* cx->ks[45] ^ cx->ks[52] ^ cx->ks[53] is zero for a 256 bit */ + /* key and must be non-zero for 128 and 192 bits keys */ + cx->ks[53] = cx->ks[45]; + cx->ks[52] = 12; +#ifdef AES_ERR_CHK + return aes_good; +#endif +} + +#endif + +#if defined(AES_256) || defined(AES_VAR) + +aes_rval aes_encrypt_key256(const void *in_key, aes_encrypt_ctx cx[1]) +{ aes_32t ss[8]; + + cx->ks[0] = ss[0] = word_in(in_key, 0); + cx->ks[1] = ss[1] = word_in(in_key, 1); + cx->ks[2] = ss[2] = word_in(in_key, 2); + cx->ks[3] = ss[3] = word_in(in_key, 3); + cx->ks[4] = ss[4] = word_in(in_key, 4); + cx->ks[5] = ss[5] = word_in(in_key, 5); + cx->ks[6] = ss[6] = word_in(in_key, 6); + cx->ks[7] = ss[7] = word_in(in_key, 7); + +#if ENC_UNROLL == NONE + { aes_32t i; + + for(i = 0; i < (15 * N_COLS - 1) / 8; ++i) + ke8(cx->ks, i); + } +#else + ke8(cx->ks, 0); ke8(cx->ks, 1); + ke8(cx->ks, 2); ke8(cx->ks, 3); + ke8(cx->ks, 4); ke8(cx->ks, 5); + kel8(cx->ks, 6); +#endif +#ifdef AES_ERR_CHK + return aes_good; +#endif +} + +#endif + +#if defined(AES_VAR) + +aes_rval aes_encrypt_key(const void *in_key, int key_len, aes_encrypt_ctx cx[1]) +{ + switch(key_len) + { +#ifdef AES_ERR_CHK + case 16: case 128: return aes_encrypt_key128(in_key, cx); + case 24: case 192: return aes_encrypt_key192(in_key, cx); + case 32: case 256: return aes_encrypt_key256(in_key, cx); + default: return aes_error; +#else + case 16: case 128: aes_encrypt_key128(in_key, cx); return; + case 24: case 192: aes_encrypt_key192(in_key, cx); return; + case 32: case 256: aes_encrypt_key256(in_key, cx); return; +#endif + } +} + +#endif + +#endif + +#if defined(DECRYPTION_KEY_SCHEDULE) + +#if DEC_ROUND == NO_TABLES +#define ff(x) (x) +#else +#define ff(x) inv_mcol(x) +#ifdef dec_imvars +#define d_vars dec_imvars +#endif +#endif + +#if 1 +#define kdf4(k,i) \ +{ ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; ss[1] = ss[1] ^ ss[3]; ss[2] = ss[2] ^ ss[3]; ss[3] = ss[3]; \ + ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; \ + ss[4] ^= k[4*(i)]; k[4*(i)+4] = ff(ss[4]); ss[4] ^= k[4*(i)+1]; k[4*(i)+5] = ff(ss[4]); \ + ss[4] ^= k[4*(i)+2]; k[4*(i)+6] = ff(ss[4]); ss[4] ^= k[4*(i)+3]; k[4*(i)+7] = ff(ss[4]); \ +} +#define kd4(k,i) \ +{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \ + k[4*(i)+4] = ss[4] ^= k[4*(i)]; k[4*(i)+5] = ss[4] ^= k[4*(i)+1]; \ + k[4*(i)+6] = ss[4] ^= k[4*(i)+2]; k[4*(i)+7] = ss[4] ^= k[4*(i)+3]; \ +} +#define kdl4(k,i) \ +{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; \ + k[4*(i)+4] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; k[4*(i)+5] = ss[1] ^ ss[3]; \ + k[4*(i)+6] = ss[0]; k[4*(i)+7] = ss[1]; \ +} +#else +#define kdf4(k,i) \ +{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[4*(i)+ 4] = ff(ss[0]); ss[1] ^= ss[0]; k[4*(i)+ 5] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[4*(i)+ 6] = ff(ss[2]); ss[3] ^= ss[2]; k[4*(i)+ 7] = ff(ss[3]); \ +} +#define kd4(k,i) \ +{ ss[4] = ls_box(ss[3],3) ^ t_use(r,c)[i]; \ + ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[4*(i)+ 4] = ss[4] ^= k[4*(i)]; \ + ss[1] ^= ss[0]; k[4*(i)+ 5] = ss[4] ^= k[4*(i)+ 1]; \ + ss[2] ^= ss[1]; k[4*(i)+ 6] = ss[4] ^= k[4*(i)+ 2]; \ + ss[3] ^= ss[2]; k[4*(i)+ 7] = ss[4] ^= k[4*(i)+ 3]; \ +} +#define kdl4(k,i) \ +{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[4*(i)+ 4] = ss[0]; ss[1] ^= ss[0]; k[4*(i)+ 5] = ss[1]; \ + ss[2] ^= ss[1]; k[4*(i)+ 6] = ss[2]; ss[3] ^= ss[2]; k[4*(i)+ 7] = ss[3]; \ +} +#endif + +#define kdf6(k,i) \ +{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[6*(i)+ 6] = ff(ss[0]); ss[1] ^= ss[0]; k[6*(i)+ 7] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[6*(i)+ 8] = ff(ss[2]); ss[3] ^= ss[2]; k[6*(i)+ 9] = ff(ss[3]); \ + ss[4] ^= ss[3]; k[6*(i)+10] = ff(ss[4]); ss[5] ^= ss[4]; k[6*(i)+11] = ff(ss[5]); \ +} +#define kd6(k,i) \ +{ ss[6] = ls_box(ss[5],3) ^ t_use(r,c)[i]; \ + ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[6*(i)+ 6] = ss[6] ^= k[6*(i)]; \ + ss[1] ^= ss[0]; k[6*(i)+ 7] = ss[6] ^= k[6*(i)+ 1]; \ + ss[2] ^= ss[1]; k[6*(i)+ 8] = ss[6] ^= k[6*(i)+ 2]; \ + ss[3] ^= ss[2]; k[6*(i)+ 9] = ss[6] ^= k[6*(i)+ 3]; \ + ss[4] ^= ss[3]; k[6*(i)+10] = ss[6] ^= k[6*(i)+ 4]; \ + ss[5] ^= ss[4]; k[6*(i)+11] = ss[6] ^= k[6*(i)+ 5]; \ +} +#define kdl6(k,i) \ +{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[6*(i)+ 6] = ss[0]; ss[1] ^= ss[0]; k[6*(i)+ 7] = ss[1]; \ + ss[2] ^= ss[1]; k[6*(i)+ 8] = ss[2]; ss[3] ^= ss[2]; k[6*(i)+ 9] = ss[3]; \ +} + +#define kdf8(k,i) \ +{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[8*(i)+ 8] = ff(ss[0]); ss[1] ^= ss[0]; k[8*(i)+ 9] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[8*(i)+10] = ff(ss[2]); ss[3] ^= ss[2]; k[8*(i)+11] = ff(ss[3]); \ + ss[4] ^= ls_box(ss[3],0); k[8*(i)+12] = ff(ss[4]); ss[5] ^= ss[4]; k[8*(i)+13] = ff(ss[5]); \ + ss[6] ^= ss[5]; k[8*(i)+14] = ff(ss[6]); ss[7] ^= ss[6]; k[8*(i)+15] = ff(ss[7]); \ +} +#define kd8(k,i) \ +{ aes_32t g = ls_box(ss[7],3) ^ t_use(r,c)[i]; \ + ss[0] ^= g; g = ff(g); k[8*(i)+ 8] = g ^= k[8*(i)]; \ + ss[1] ^= ss[0]; k[8*(i)+ 9] = g ^= k[8*(i)+ 1]; \ + ss[2] ^= ss[1]; k[8*(i)+10] = g ^= k[8*(i)+ 2]; \ + ss[3] ^= ss[2]; k[8*(i)+11] = g ^= k[8*(i)+ 3]; \ + g = ls_box(ss[3],0); \ + ss[4] ^= g; g = ff(g); k[8*(i)+12] = g ^= k[8*(i)+ 4]; \ + ss[5] ^= ss[4]; k[8*(i)+13] = g ^= k[8*(i)+ 5]; \ + ss[6] ^= ss[5]; k[8*(i)+14] = g ^= k[8*(i)+ 6]; \ + ss[7] ^= ss[6]; k[8*(i)+15] = g ^= k[8*(i)+ 7]; \ +} +#define kdl8(k,i) \ +{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[8*(i)+ 8] = ss[0]; ss[1] ^= ss[0]; k[8*(i)+ 9] = ss[1]; \ + ss[2] ^= ss[1]; k[8*(i)+10] = ss[2]; ss[3] ^= ss[2]; k[8*(i)+11] = ss[3]; \ +} + +#if defined(AES_128) || defined(AES_VAR) + +aes_rval aes_decrypt_key128(const void *in_key, aes_decrypt_ctx cx[1]) +{ aes_32t ss[5]; +#ifdef d_vars + d_vars; +#endif + cx->ks[0] = ss[0] = word_in(in_key, 0); + cx->ks[1] = ss[1] = word_in(in_key, 1); + cx->ks[2] = ss[2] = word_in(in_key, 2); + cx->ks[3] = ss[3] = word_in(in_key, 3); + +#if DEC_UNROLL == NONE + { aes_32t i; + + for(i = 0; i < (11 * N_COLS - 1) / 4; ++i) + ke4(cx->ks, i); +#if !(DEC_ROUND == NO_TABLES) + for(i = N_COLS; i < 10 * N_COLS; ++i) + cx->ks[i] = inv_mcol(cx->ks[i]); +#endif + } +#else + kdf4(cx->ks, 0); kd4(cx->ks, 1); + kd4(cx->ks, 2); kd4(cx->ks, 3); + kd4(cx->ks, 4); kd4(cx->ks, 5); + kd4(cx->ks, 6); kd4(cx->ks, 7); + kd4(cx->ks, 8); kdl4(cx->ks, 9); +#endif + + /* cx->ks[45] ^ cx->ks[52] ^ cx->ks[53] is zero for a 256 bit */ + /* key and must be non-zero for 128 and 192 bits keys */ + cx->ks[53] = cx->ks[45] = 0; + cx->ks[52] = 10; +#ifdef AES_ERR_CHK + return aes_good; +#endif +} + +#endif + +#if defined(AES_192) || defined(AES_VAR) + +aes_rval aes_decrypt_key192(const void *in_key, aes_decrypt_ctx cx[1]) +{ aes_32t ss[7]; +#ifdef d_vars + d_vars; +#endif + cx->ks[0] = ss[0] = word_in(in_key, 0); + cx->ks[1] = ss[1] = word_in(in_key, 1); + cx->ks[2] = ss[2] = word_in(in_key, 2); + cx->ks[3] = ss[3] = word_in(in_key, 3); + +#if DEC_UNROLL == NONE + cx->ks[4] = ss[4] = word_in(in_key, 4); + cx->ks[5] = ss[5] = word_in(in_key, 5); + { aes_32t i; + + for(i = 0; i < (13 * N_COLS - 1) / 6; ++i) + ke6(cx->ks, i); +#if !(DEC_ROUND == NO_TABLES) + for(i = N_COLS; i < 12 * N_COLS; ++i) + cx->ks[i] = inv_mcol(cx->ks[i]); +#endif + } +#else + ss[4] = word_in(in_key, 4); + cx->ks[4] = ff(ss[4]); + ss[5] = word_in(in_key, 5); + cx->ks[5] = ff(ss[5]); + kdf6(cx->ks, 0); kd6(cx->ks, 1); + kd6(cx->ks, 2); kd6(cx->ks, 3); + kd6(cx->ks, 4); kd6(cx->ks, 5); + kd6(cx->ks, 6); kdl6(cx->ks, 7); +#endif + + /* cx->ks[45] ^ cx->ks[52] ^ cx->ks[53] is zero for a 256 bit */ + /* key and must be non-zero for 128 and 192 bits keys */ + cx->ks[53] = cx->ks[45]; + cx->ks[52] = 12; +#ifdef AES_ERR_CHK + return aes_good; +#endif +} + +#endif + +#if defined(AES_256) || defined(AES_VAR) + +aes_rval aes_decrypt_key256(const void *in_key, aes_decrypt_ctx cx[1]) +{ aes_32t ss[8]; +#ifdef d_vars + d_vars; +#endif + cx->ks[0] = ss[0] = word_in(in_key, 0); + cx->ks[1] = ss[1] = word_in(in_key, 1); + cx->ks[2] = ss[2] = word_in(in_key, 2); + cx->ks[3] = ss[3] = word_in(in_key, 3); + +#if DEC_UNROLL == NONE + cx->ks[4] = ss[4] = word_in(in_key, 4); + cx->ks[5] = ss[5] = word_in(in_key, 5); + cx->ks[6] = ss[6] = word_in(in_key, 6); + cx->ks[7] = ss[7] = word_in(in_key, 7); + { aes_32t i; + + for(i = 0; i < (15 * N_COLS - 1) / 8; ++i) + ke8(cx->ks, i); +#if !(DEC_ROUND == NO_TABLES) + for(i = N_COLS; i < 14 * N_COLS; ++i) + cx->ks[i] = inv_mcol(cx->ks[i]); +#endif + } +#else + ss[4] = word_in(in_key, 4); + cx->ks[4] = ff(ss[4]); + ss[5] = word_in(in_key, 5); + cx->ks[5] = ff(ss[5]); + ss[6] = word_in(in_key, 6); + cx->ks[6] = ff(ss[6]); + ss[7] = word_in(in_key, 7); + cx->ks[7] = ff(ss[7]); + kdf8(cx->ks, 0); kd8(cx->ks, 1); + kd8(cx->ks, 2); kd8(cx->ks, 3); + kd8(cx->ks, 4); kd8(cx->ks, 5); + kdl8(cx->ks, 6); +#endif +#ifdef AES_ERR_CHK + return aes_good; +#endif +} + +#endif + +#if defined(AES_VAR) + +aes_rval aes_decrypt_key(const void *in_key, int key_len, aes_decrypt_ctx cx[1]) +{ + switch(key_len) + { +#ifdef AES_ERR_CHK + case 16: case 128: return aes_decrypt_key128(in_key, cx); + case 24: case 192: return aes_decrypt_key192(in_key, cx); + case 32: case 256: return aes_decrypt_key256(in_key, cx); + default: return aes_error; +#else + case 16: case 128: aes_decrypt_key128(in_key, cx); return; + case 24: case 192: aes_decrypt_key192(in_key, cx); return; + case 32: case 256: aes_decrypt_key256(in_key, cx); return; +#endif + } +} + +#endif + +#endif + diff --git a/source/Irrlicht/aesGladman/aesopt.h b/source/Irrlicht/aesGladman/aesopt.h new file mode 100644 index 00000000..9c0d842d --- /dev/null +++ b/source/Irrlicht/aesGladman/aesopt.h @@ -0,0 +1,955 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2003, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 26/08/2003 + + My thanks go to Dag Arne Osvik for devising the schemes used here for key + length derivation from the form of the key schedule + + This file contains the compilation options for AES (Rijndael) and code + that is common across encryption, key scheduling and table generation. + + OPERATION + + These source code files implement the AES algorithm Rijndael designed by + Joan Daemen and Vincent Rijmen. This version is designed for the standard + block size of 16 bytes and for key sizes of 128, 192 and 256 bits (16, 24 + and 32 bytes). + + This version is designed for flexibility and speed using operations on + 32-bit words rather than operations on bytes. It can be compiled with + either big or little endian internal byte order but is faster when the + native byte order for the processor is used. + + THE CIPHER INTERFACE + + The cipher interface is implemented as an array of bytes in which lower + AES bit sequence indexes map to higher numeric significance within bytes. + + aes_08t (an unsigned 8-bit type) + aes_32t (an unsigned 32-bit type) + struct aes_encrypt_ctx (structure for the cipher encryption context) + struct aes_decrypt_ctx (structure for the cipher decryption context) + aes_rval the function return type + + C subroutine calls: + + aes_rval aes_encrypt_key128(const void *in_key, aes_encrypt_ctx cx[1]); + aes_rval aes_encrypt_key192(const void *in_key, aes_encrypt_ctx cx[1]); + aes_rval aes_encrypt_key256(const void *in_key, aes_encrypt_ctx cx[1]); + aes_rval aes_encrypt(const void *in_blk, + void *out_blk, const aes_encrypt_ctx cx[1]); + + aes_rval aes_decrypt_key128(const void *in_key, aes_decrypt_ctx cx[1]); + aes_rval aes_decrypt_key192(const void *in_key, aes_decrypt_ctx cx[1]); + aes_rval aes_decrypt_key256(const void *in_key, aes_decrypt_ctx cx[1]); + aes_rval aes_decrypt(const void *in_blk, + void *out_blk, const aes_decrypt_ctx cx[1]); + + IMPORTANT NOTE: If you are using this C interface with dynamic tables make sure that + you call genTabs() before AES is used so that the tables are initialised. + + C++ aes class subroutines: + + Class AESencrypt for encryption + + Construtors: + AESencrypt(void) + AESencrypt(const void *in_key) - 128 bit key + Members: + void key128(const void *in_key) + void key192(const void *in_key) + void key256(const void *in_key) + void encrypt(const void *in_blk, void *out_blk) const + + Class AESdecrypt for encryption + Construtors: + AESdecrypt(void) + AESdecrypt(const void *in_key) - 128 bit key + Members: + void key128(const void *in_key) + void key192(const void *in_key) + void key256(const void *in_key) + void decrypt(const void *in_blk, void *out_blk) const + + COMPILATION + + The files used to provide AES (Rijndael) are + + a. aes.h for the definitions needed for use in C. + b. aescpp.h for the definitions needed for use in C++. + c. aesopt.h for setting compilation options (also includes common code). + d. aescrypt.c for encryption and decrytpion, or + e. aeskey.c for key scheduling. + f. aestab.c for table loading or generation. + g. aescrypt.asm for encryption and decryption using assembler code. + h. aescrypt.mmx.asm for encryption and decryption using MMX assembler. + + To compile AES (Rijndael) for use in C code use aes.h and set the + defines here for the facilities you need (key lengths, encryption + and/or decryption). Do not define AES_DLL or AES_CPP. Set the options + for optimisations and table sizes here. + + To compile AES (Rijndael) for use in in C++ code use aescpp.h but do + not define AES_DLL + + To compile AES (Rijndael) in C as a Dynamic Link Library DLL) use + aes.h and include the AES_DLL define. + + CONFIGURATION OPTIONS (here and in aes.h) + + a. set AES_DLL in aes.h if AES (Rijndael) is to be compiled as a DLL + b. You may need to set PLATFORM_BYTE_ORDER to define the byte order. + c. If you want the code to run in a specific internal byte order, then + ALGORITHM_BYTE_ORDER must be set accordingly. + d. set other configuration options decribed below. +*/ + +#ifndef _AESOPT_H +#define _AESOPT_H + +#include "aes.h" + +/* CONFIGURATION - USE OF DEFINES + + Later in this section there are a number of defines that control the + operation of the code. In each section, the purpose of each define is + explained so that the relevant form can be included or excluded by + setting either 1's or 0's respectively on the branches of the related + #if clauses. +*/ + +/* BYTE ORDER IN 32-BIT WORDS + + To obtain the highest speed on processors with 32-bit words, this code + needs to determine the byte order of the target machine. The following + block of code is an attempt to capture the most obvious ways in which + various environemnts define byte order. It may well fail, in which case + the definitions will need to be set by editing at the points marked + **** EDIT HERE IF NECESSARY **** below. My thanks to Peter Gutmann for + some of these defines (from cryptlib). +*/ + +#define BRG_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ +#define BRG_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ + +#ifdef __BIG_ENDIAN__ +#define PLATFORM_BYTE_ORDER BRG_BIG_ENDIAN +#else +#define PLATFORM_BYTE_ORDER BRG_LITTLE_ENDIAN +#endif + +/* SOME LOCAL DEFINITIONS */ + +#define NO_TABLES 0 +#define ONE_TABLE 1 +#define FOUR_TABLES 4 +#define NONE 0 +#define PARTIAL 1 +#define FULL 2 + +#define aes_sw32 Byteswap::byteswap + +/* 1. FUNCTIONS REQUIRED + + This implementation provides subroutines for encryption, decryption + and for setting the three key lengths (separately) for encryption + and decryption. When the assembler code is not being used the following + definition blocks allow the selection of the routines that are to be + included in the compilation. +*/ +#ifdef AES_ENCRYPT +#define ENCRYPTION +#define ENCRYPTION_KEY_SCHEDULE +#endif + +#ifdef AES_DECRYPT +#define DECRYPTION +#define DECRYPTION_KEY_SCHEDULE +#endif + +/* 2. ASSEMBLER SUPPORT + + This define (which can be on the command line) enables the use of the + assembler code routines for encryption and decryption with the C code + only providing key scheduling +*/ +#if 0 +#define AES_ASM +#endif + +/* 3. BYTE ORDER WITHIN 32 BIT WORDS + + The fundamental data processing units in Rijndael are 8-bit bytes. The + input, output and key input are all enumerated arrays of bytes in which + bytes are numbered starting at zero and increasing to one less than the + number of bytes in the array in question. This enumeration is only used + for naming bytes and does not imply any adjacency or order relationship + from one byte to another. When these inputs and outputs are considered + as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to + byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte. + In this implementation bits are numbered from 0 to 7 starting at the + numerically least significant end of each byte (bit n represents 2^n). + + However, Rijndael can be implemented more efficiently using 32-bit + words by packing bytes into words so that bytes 4*n to 4*n+3 are placed + into word[n]. While in principle these bytes can be assembled into words + in any positions, this implementation only supports the two formats in + which bytes in adjacent positions within words also have adjacent byte + numbers. This order is called big-endian if the lowest numbered bytes + in words have the highest numeric significance and little-endian if the + opposite applies. + + This code can work in either order irrespective of the order used by the + machine on which it runs. Normally the internal byte order will be set + to the order of the processor on which the code is to be run but this + define can be used to reverse this in special situations + + NOTE: Assembler code versions rely on PLATFORM_BYTE_ORDER being set +*/ +#if 1 || defined(AES_ASM) +#define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER +#elif 0 +#define ALGORITHM_BYTE_ORDER BRG_LITTLE_ENDIAN +#elif 0 +#define ALGORITHM_BYTE_ORDER BRG_BIG_ENDIAN +#else +#error The algorithm byte order is not defined +#endif + +/* 4. FAST INPUT/OUTPUT OPERATIONS. + + On some machines it is possible to improve speed by transferring the + bytes in the input and output arrays to and from the internal 32-bit + variables by addressing these arrays as if they are arrays of 32-bit + words. On some machines this will always be possible but there may + be a large performance penalty if the byte arrays are not aligned on + the normal word boundaries. On other machines this technique will + lead to memory access errors when such 32-bit word accesses are not + properly aligned. The option SAFE_IO avoids such problems but will + often be slower on those machines that support misaligned access + (especially so if care is taken to align the input and output byte + arrays on 32-bit word boundaries). If SAFE_IO is not defined it is + assumed that access to byte arrays as if they are arrays of 32-bit + words will not cause problems when such accesses are misaligned. +*/ +#if 1 && !defined(_MSC_VER) +#define SAFE_IO +#endif + +/* 5. LOOP UNROLLING + + The code for encryption and decrytpion cycles through a number of rounds + that can be implemented either in a loop or by expanding the code into a + long sequence of instructions, the latter producing a larger program but + one that will often be much faster. The latter is called loop unrolling. + There are also potential speed advantages in expanding two iterations in + a loop with half the number of iterations, which is called partial loop + unrolling. The following options allow partial or full loop unrolling + to be set independently for encryption and decryption +*/ +#if 1 +#define ENC_UNROLL FULL +#elif 0 +#define ENC_UNROLL PARTIAL +#else +#define ENC_UNROLL NONE +#endif + +#if 1 +#define DEC_UNROLL FULL +#elif 0 +#define DEC_UNROLL PARTIAL +#else +#define DEC_UNROLL NONE +#endif + +/* 6. FAST FINITE FIELD OPERATIONS + + If this section is included, tables are used to provide faster finite + field arithmetic (this has no effect if FIXED_TABLES is defined). +*/ +#if 0 +#define FF_TABLES +#endif + +/* 7. INTERNAL STATE VARIABLE FORMAT + + The internal state of Rijndael is stored in a number of local 32-bit + word varaibles which can be defined either as an array or as individual + names variables. Include this section if you want to store these local + varaibles in arrays. Otherwise individual local variables will be used. +*/ +#if 1 +#define ARRAYS +#endif + +/* In this implementation the columns of the state array are each held in + 32-bit words. The state array can be held in various ways: in an array + of words, in a number of individual word variables or in a number of + processor registers. The following define maps a variable name x and + a column number c to the way the state array variable is to be held. + The first define below maps the state into an array x[c] whereas the + second form maps the state into a number of individual variables x0, + x1, etc. Another form could map individual state colums to machine + register names. +*/ + +#if defined(ARRAYS) +#define s(x,c) x[c] +#else +#define s(x,c) x##c +#endif + +/* 8. FIXED OR DYNAMIC TABLES + + When this section is included the tables used by the code are compiled + statically into the binary file. Otherwise the subroutine gen_tabs() + must be called to compute them before the code is first used. +*/ +#if 1 +#define FIXED_TABLES +#define DO_TABLES +#endif + +/* 9. TABLE ALIGNMENT + + On some systems speed will be improved by aligning the AES large lookup + tables on particular boundaries. This define should be set to a power of + two giving the desired alignment. It can be left undefined if alignment + is not needed. This option is specific to the Microsft VC++ compiler - + it seems to sometimes cause trouble for the VC++ version 6 compiler. +*/ + +#if 0 && defined(_MSC_VER) && (_MSC_VER >= 1300) +#define TABLE_ALIGN 64 +#endif + +/* 10. INTERNAL TABLE CONFIGURATION + + This cipher proceeds by repeating in a number of cycles known as 'rounds' + which are implemented by a round function which can optionally be speeded + up using tables. The basic tables are each 256 32-bit words, with either + one or four tables being required for each round function depending on + how much speed is required. The encryption and decryption round functions + are different and the last encryption and decrytpion round functions are + different again making four different round functions in all. + + This means that: + 1. Normal encryption and decryption rounds can each use either 0, 1 + or 4 tables and table spaces of 0, 1024 or 4096 bytes each. + 2. The last encryption and decryption rounds can also use either 0, 1 + or 4 tables and table spaces of 0, 1024 or 4096 bytes each. + + Include or exclude the appropriate definitions below to set the number + of tables used by this implementation. +*/ + +#if 1 /* set tables for the normal encryption round */ +#define ENC_ROUND FOUR_TABLES +#elif 0 +#define ENC_ROUND ONE_TABLE +#else +#define ENC_ROUND NO_TABLES +#endif + +#if 1 /* set tables for the last encryption round */ +#define LAST_ENC_ROUND FOUR_TABLES +#elif 0 +#define LAST_ENC_ROUND ONE_TABLE +#else +#define LAST_ENC_ROUND NO_TABLES +#endif + +#if 1 /* set tables for the normal decryption round */ +#define DEC_ROUND FOUR_TABLES +#elif 0 +#define DEC_ROUND ONE_TABLE +#else +#define DEC_ROUND NO_TABLES +#endif + +#if 1 /* set tables for the last decryption round */ +#define LAST_DEC_ROUND FOUR_TABLES +#elif 0 +#define LAST_DEC_ROUND ONE_TABLE +#else +#define LAST_DEC_ROUND NO_TABLES +#endif + +/* The decryption key schedule can be speeded up with tables in the same + way that the round functions can. Include or exclude the following + defines to set this requirement. +*/ +#if 1 +#define KEY_SCHED FOUR_TABLES +#elif 0 +#define KEY_SCHED ONE_TABLE +#else +#define KEY_SCHED NO_TABLES +#endif + +/* END OF CONFIGURATION OPTIONS */ + +#define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2)) + +/* Disable or report errors on some combinations of options */ + +#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES +#undef LAST_ENC_ROUND +#define LAST_ENC_ROUND NO_TABLES +#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES +#undef LAST_ENC_ROUND +#define LAST_ENC_ROUND ONE_TABLE +#endif + +#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE +#undef ENC_UNROLL +#define ENC_UNROLL NONE +#endif + +#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES +#undef LAST_DEC_ROUND +#define LAST_DEC_ROUND NO_TABLES +#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES +#undef LAST_DEC_ROUND +#define LAST_DEC_ROUND ONE_TABLE +#endif + +#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE +#undef DEC_UNROLL +#define DEC_UNROLL NONE +#endif + +/* upr(x,n): rotates bytes within words by n positions, moving bytes to + higher index positions with wrap around into low positions + ups(x,n): moves bytes by n positions to higher index positions in + words but without wrap around + bval(x,n): extracts a byte from a word + + NOTE: The definitions given here are intended only for use with + unsigned variables and with shift counts that are compile + time constants +*/ + +#if (ALGORITHM_BYTE_ORDER == BRG_LITTLE_ENDIAN) +#define upr(x,n) (((aes_32t)(x) << (8 * (n))) | ((aes_32t)(x) >> (32 - 8 * (n)))) +#define ups(x,n) ((aes_32t) (x) << (8 * (n))) +#define bval(x,n) ((aes_08t)((x) >> (8 * (n)))) +#define bytes2word(b0, b1, b2, b3) \ + (((aes_32t)(b3) << 24) | ((aes_32t)(b2) << 16) | ((aes_32t)(b1) << 8) | (b0)) +#endif + +#if (ALGORITHM_BYTE_ORDER == BRG_BIG_ENDIAN) +#define upr(x,n) (((aes_32t)(x) >> (8 * (n))) | ((aes_32t)(x) << (32 - 8 * (n)))) +#define ups(x,n) ((aes_32t) (x) >> (8 * (n)))) +#define bval(x,n) ((aes_08t)((x) >> (24 - 8 * (n)))) +#define bytes2word(b0, b1, b2, b3) \ + (((aes_32t)(b0) << 24) | ((aes_32t)(b1) << 16) | ((aes_32t)(b2) << 8) | (b3)) +#endif + +#if defined(SAFE_IO) + +#define word_in(x,c) bytes2word(((aes_08t*)(x)+4*c)[0], ((aes_08t*)(x)+4*c)[1], \ + ((aes_08t*)(x)+4*c)[2], ((aes_08t*)(x)+4*c)[3]) +#define word_out(x,c,v) { ((aes_08t*)(x)+4*c)[0] = bval(v,0); ((aes_08t*)(x)+4*c)[1] = bval(v,1); \ + ((aes_08t*)(x)+4*c)[2] = bval(v,2); ((aes_08t*)(x)+4*c)[3] = bval(v,3); } + +#elif (ALGORITHM_BYTE_ORDER == PLATFORM_BYTE_ORDER) + +#define word_in(x,c) (*((aes_32t*)(x)+(c))) +#define word_out(x,c,v) (*((aes_32t*)(x)+(c)) = (v)) + +#else + +#define word_in(x,c) aes_sw32(*((aes_32t*)(x)+(c))) +#define word_out(x,c,v) (*((aes_32t*)(x)+(c)) = aes_sw32(v)) + +#endif + +/* the finite field modular polynomial and elements */ + +#define WPOLY 0x011b +#define BPOLY 0x1b + +/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ + +#define m1 0x80808080 +#define m2 0x7f7f7f7f +#define gf_mulx(x) ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * BPOLY)) + +/* The following defines provide alternative definitions of gf_mulx that might + give improved performance if a fast 32-bit multiply is not available. Note + that a temporary variable u needs to be defined where gf_mulx is used. + +#define gf_mulx(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ ((u >> 3) | (u >> 6)) +#define m4 (0x01010101 * BPOLY) +#define gf_mulx(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) & m4) +*/ + +/* Work out which tables are needed for the different options */ + +#ifdef AES_ASM +#ifdef ENC_ROUND +#undef ENC_ROUND +#endif +#define ENC_ROUND FOUR_TABLES +#ifdef LAST_ENC_ROUND +#undef LAST_ENC_ROUND +#endif +#define LAST_ENC_ROUND FOUR_TABLES +#ifdef DEC_ROUND +#undef DEC_ROUND +#endif +#define DEC_ROUND FOUR_TABLES +#ifdef LAST_DEC_ROUND +#undef LAST_DEC_ROUND +#endif +#define LAST_DEC_ROUND FOUR_TABLES +#ifdef KEY_SCHED +#undef KEY_SCHED +#define KEY_SCHED FOUR_TABLES +#endif +#endif + +#if defined(ENCRYPTION) || defined(AES_ASM) +#if ENC_ROUND == ONE_TABLE +#define FT1_SET +#elif ENC_ROUND == FOUR_TABLES +#define FT4_SET +#else +#define SBX_SET +#endif +#if LAST_ENC_ROUND == ONE_TABLE +#define FL1_SET +#elif LAST_ENC_ROUND == FOUR_TABLES +#define FL4_SET +#elif !defined(SBX_SET) +#define SBX_SET +#endif +#endif + +#if defined(DECRYPTION) || defined(AES_ASM) +#if DEC_ROUND == ONE_TABLE +#define IT1_SET +#elif DEC_ROUND == FOUR_TABLES +#define IT4_SET +#else +#define ISB_SET +#endif +#if LAST_DEC_ROUND == ONE_TABLE +#define IL1_SET +#elif LAST_DEC_ROUND == FOUR_TABLES +#define IL4_SET +#elif !defined(ISB_SET) +#define ISB_SET +#endif +#endif + +#if defined(ENCRYPTION_KEY_SCHEDULE) || defined(DECRYPTION_KEY_SCHEDULE) +#if KEY_SCHED == ONE_TABLE +#define LS1_SET +#define IM1_SET +#elif KEY_SCHED == FOUR_TABLES +#define LS4_SET +#define IM4_SET +#elif !defined(SBX_SET) +#define SBX_SET +#endif +#endif + +/* generic definitions of Rijndael macros that use tables */ + +#define no_table(x,box,vf,rf,c) bytes2word( \ + box[bval(vf(x,0,c),rf(0,c))], \ + box[bval(vf(x,1,c),rf(1,c))], \ + box[bval(vf(x,2,c),rf(2,c))], \ + box[bval(vf(x,3,c),rf(3,c))]) + +#define one_table(x,op,tab,vf,rf,c) \ + ( tab[bval(vf(x,0,c),rf(0,c))] \ + ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \ + ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \ + ^ op(tab[bval(vf(x,3,c),rf(3,c))],3)) + +#define four_tables(x,tab,vf,rf,c) \ + ( tab[0][bval(vf(x,0,c),rf(0,c))] \ + ^ tab[1][bval(vf(x,1,c),rf(1,c))] \ + ^ tab[2][bval(vf(x,2,c),rf(2,c))] \ + ^ tab[3][bval(vf(x,3,c),rf(3,c))]) + +#define vf1(x,r,c) (x) +#define rf1(r,c) (r) +#define rf2(r,c) ((8+r-c)&3) + +/* perform forward and inverse column mix operation on four bytes in long word x in */ +/* parallel. NOTE: x must be a simple variable, NOT an expression in these macros. */ + +#if defined(FM4_SET) /* not currently used */ +#define fwd_mcol(x) four_tables(x,t_use(f,m),vf1,rf1,0) +#elif defined(FM1_SET) /* not currently used */ +#define fwd_mcol(x) one_table(x,upr,t_use(f,m),vf1,rf1,0) +#else +#define dec_fmvars aes_32t g2 +#define fwd_mcol(x) (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ upr((x), 2) ^ upr((x), 1)) +#endif + +#if defined(IM4_SET) +#define inv_mcol(x) four_tables(x,t_use(i,m),vf1,rf1,0) +#elif defined(IM1_SET) +#define inv_mcol(x) one_table(x,upr,t_use(i,m),vf1,rf1,0) +#else +#define dec_imvars aes_32t g2, g4, g9 +#define inv_mcol(x) (g2 = gf_mulx(x), g4 = gf_mulx(g2), g9 = (x) ^ gf_mulx(g4), g4 ^= g9, \ + (x) ^ g2 ^ g4 ^ upr(g2 ^ g9, 3) ^ upr(g4, 2) ^ upr(g9, 1)) +#endif + +#if defined(FL4_SET) +#define ls_box(x,c) four_tables(x,t_use(f,l),vf1,rf2,c) +#elif defined(LS4_SET) +#define ls_box(x,c) four_tables(x,t_use(l,s),vf1,rf2,c) +#elif defined(FL1_SET) +#define ls_box(x,c) one_table(x,upr,t_use(f,l),vf1,rf2,c) +#elif defined(LS1_SET) +#define ls_box(x,c) one_table(x,upr,t_use(l,s),vf1,rf2,c) +#else +#define ls_box(x,c) no_table(x,t_use(s,box),vf1,rf2,c) +#endif + +/* If there are no global variables, the definitions here can be + used to put the AES tables in a structure so that a pointer + can then be added to the AES context to pass them to the AES + routines that need them. If this facility is used, the calling + program has to ensure that this pointer is managed appropriately. + In particular, the value of the t_dec(in,it) item in the table + structure must be set to zero in order to ensure that the tables + are initialised. In practice the three code sequences in aeskey.c + that control the calls to gen_tabs() and the gen_tabs() routine + itself will have to be changed for a specific implementation. If + global variables are available it will generally be preferable to + use them with the precomputed FIXED_TABLES option that uses static + global tables. + + The following defines can be used to control the way the tables + are defined, initialised and used in embedded environments that + require special features for these purposes + + the 't_dec' construction is used to declare fixed table arrays + the 't_set' construction is used to set fixed table values + the 't_use' construction is used to access fixed table values + + 256 byte tables: + + t_xxx(s,box) => forward S box + t_xxx(i,box) => inverse S box + + 256 32-bit word OR 4 x 256 32-bit word tables: + + t_xxx(f,n) => forward normal round + t_xxx(f,l) => forward last round + t_xxx(i,n) => inverse normal round + t_xxx(i,l) => inverse last round + t_xxx(l,s) => key schedule table + t_xxx(i,m) => key schedule table + + Other variables and tables: + + t_xxx(r,c) => the rcon table +*/ + +#define t_dec(m,n) t_##m##n +#define t_set(m,n) t_##m##n +#define t_use(m,n) t_##m##n + +#if defined(DO_TABLES) /* declare and instantiate tables */ + +/* finite field arithmetic operations for table generation */ + +#if defined(FIXED_TABLES) || !defined(FF_TABLES) + +#define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY)) +#define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY)) +#define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \ + ^ (((x>>5) & 4) * WPOLY)) +#define f3(x) (f2(x) ^ x) +#define f9(x) (f8(x) ^ x) +#define fb(x) (f8(x) ^ f2(x) ^ x) +#define fd(x) (f8(x) ^ f4(x) ^ x) +#define fe(x) (f8(x) ^ f4(x) ^ f2(x)) + +#else + +#define f2(x) ((x) ? pow[log[x] + 0x19] : 0) +#define f3(x) ((x) ? pow[log[x] + 0x01] : 0) +#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0) +#define fb(x) ((x) ? pow[log[x] + 0x68] : 0) +#define fd(x) ((x) ? pow[log[x] + 0xee] : 0) +#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0) +#define fi(x) ((x) ? pow[ 255 - log[x]] : 0) + +#endif + +#if defined(FIXED_TABLES) /* declare and set values for static tables */ + +#define sb_data(w) \ + w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\ + w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\ + w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\ + w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\ + w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\ + w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\ + w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\ + w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\ + w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\ + w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\ + w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\ + w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\ + w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\ + w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\ + w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\ + w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\ + w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\ + w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\ + w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\ + w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\ + w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\ + w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\ + w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\ + w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\ + w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\ + w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\ + w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\ + w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\ + w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\ + w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\ + w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\ + w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) + +#define isb_data(w) \ + w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\ + w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\ + w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\ + w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\ + w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\ + w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\ + w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\ + w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\ + w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\ + w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\ + w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\ + w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\ + w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\ + w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\ + w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\ + w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\ + w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\ + w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\ + w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\ + w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\ + w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\ + w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\ + w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\ + w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\ + w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\ + w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\ + w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\ + w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\ + w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\ + w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\ + w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\ + w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d), + +#define mm_data(w) \ + w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\ + w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\ + w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\ + w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\ + w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\ + w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\ + w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\ + w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\ + w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\ + w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\ + w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\ + w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\ + w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\ + w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\ + w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\ + w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\ + w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\ + w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\ + w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\ + w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\ + w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\ + w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\ + w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\ + w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\ + w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\ + w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\ + w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\ + w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\ + w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\ + w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\ + w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\ + w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) + +#define h0(x) (x) + +/* These defines are used to ensure tables are generated in the + right format depending on the internal byte order required +*/ + +#define w0(p) bytes2word(p, 0, 0, 0) +#define w1(p) bytes2word(0, p, 0, 0) +#define w2(p) bytes2word(0, 0, p, 0) +#define w3(p) bytes2word(0, 0, 0, p) + +#define u0(p) bytes2word(f2(p), p, p, f3(p)) +#define u1(p) bytes2word(f3(p), f2(p), p, p) +#define u2(p) bytes2word(p, f3(p), f2(p), p) +#define u3(p) bytes2word(p, p, f3(p), f2(p)) + +#define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p)) +#define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p)) +#define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p)) +#define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p)) + +const aes_32t t_dec(r,c)[RC_LENGTH] = +{ + w0(0x01), w0(0x02), w0(0x04), w0(0x08), w0(0x10), + w0(0x20), w0(0x40), w0(0x80), w0(0x1b), w0(0x36) +}; + +#if defined(__BORLANDC__) + #define concat(s1, s2) s1##s2 + #define d_1(t,n,b,v) const t n[256] = { b(concat(v,0)) } + #define d_4(t,n,b,v) const t n[4][256] = { { b(concat(v,0)) }, { b(concat(v,1)) }, { b(concat(v,2)) }, { b(concat(v,3)) } } +#else + #define d_1(t,n,b,v) const t n[256] = { b(v##0) } + #define d_4(t,n,b,v) const t n[4][256] = { { b(v##0) }, { b(v##1) }, { b(v##2) }, { b(v##3) } } +#endif + +#else /* declare and instantiate tables for dynamic value generation in in tab.c */ + +aes_32t t_dec(r,c)[RC_LENGTH]; + +#define d_1(t,n,b,v) t n[256] +#define d_4(t,n,b,v) t n[4][256] + +#endif + +#else /* declare tables without instantiation */ + +#if defined(FIXED_TABLES) + +extern const aes_32t t_dec(r,c)[RC_LENGTH]; + +#if defined(_MSC_VER) && defined(TABLE_ALIGN) +#define d_1(t,n,b,v) extern __declspec(align(TABLE_ALIGN)) const t n[256] +#define d_4(t,n,b,v) extern __declspec(align(TABLE_ALIGN)) const t n[4][256] +#else +#define d_1(t,n,b,v) extern const t n[256] +#define d_4(t,n,b,v) extern const t n[4][256] +#endif +#else + +extern aes_32t t_dec(r,c)[RC_LENGTH]; + +#if defined(_MSC_VER) && defined(TABLE_ALIGN) +#define d_1(t,n,b,v) extern __declspec(align(TABLE_ALIGN)) t n[256] +#define d_4(t,n,b,v) extern __declspec(align(TABLE_ALIGN)) t n[4][256] +#else +#define d_1(t,n,b,v) extern t n[256] +#define d_4(t,n,b,v) extern t n[4][256] +#endif +#endif + +#endif + +#ifdef SBX_SET + d_1(aes_08t, t_dec(s,box), sb_data, h); +#endif +#ifdef ISB_SET + d_1(aes_08t, t_dec(i,box), isb_data, h); +#endif + +#ifdef FT1_SET + d_1(aes_32t, t_dec(f,n), sb_data, u); +#endif +#ifdef FT4_SET + d_4(aes_32t, t_dec(f,n), sb_data, u); +#endif + +#ifdef FL1_SET + d_1(aes_32t, t_dec(f,l), sb_data, w); +#endif +#ifdef FL4_SET + d_4(aes_32t, t_dec(f,l), sb_data, w); +#endif + +#ifdef IT1_SET + d_1(aes_32t, t_dec(i,n), isb_data, v); +#endif +#ifdef IT4_SET + d_4(aes_32t, t_dec(i,n), isb_data, v); +#endif + +#ifdef IL1_SET + d_1(aes_32t, t_dec(i,l), isb_data, w); +#endif +#ifdef IL4_SET + d_4(aes_32t, t_dec(i,l), isb_data, w); +#endif + +#ifdef LS1_SET +#ifdef FL1_SET +#undef LS1_SET +#else + d_1(aes_32t, t_dec(l,s), sb_data, w); +#endif +#endif + +#ifdef LS4_SET +#ifdef FL4_SET +#undef LS4_SET +#else + d_4(aes_32t, t_dec(l,s), sb_data, w); +#endif +#endif + +#ifdef IM1_SET + d_1(aes_32t, t_dec(i,m), mm_data, v); +#endif +#ifdef IM4_SET + d_4(aes_32t, t_dec(i,m), mm_data, v); +#endif + +#endif + diff --git a/source/Irrlicht/aesGladman/aestab.cpp b/source/Irrlicht/aesGladman/aestab.cpp new file mode 100644 index 00000000..e94aa76b --- /dev/null +++ b/source/Irrlicht/aesGladman/aestab.cpp @@ -0,0 +1,223 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2003, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 26/08/2003 + +*/ + +#define DO_TABLES + +#include "aesopt.h" + +#if defined(FIXED_TABLES) + +/* implemented in case of wrong call for fixed tables */ + +void gen_tabs(void) +{ +} + +#else /* dynamic table generation */ + +#if !defined(FF_TABLES) + +/* Generate the tables for the dynamic table option + + It will generally be sensible to use tables to compute finite + field multiplies and inverses but where memory is scarse this + code might sometimes be better. But it only has effect during + initialisation so its pretty unimportant in overall terms. +*/ + +/* return 2 ^ (n - 1) where n is the bit number of the highest bit + set in x with x in the range 1 < x < 0x00000200. This form is + used so that locals within fi can be bytes rather than words +*/ + +static aes_08t hibit(const aes_32t x) +{ aes_08t r = (aes_08t)((x >> 1) | (x >> 2)); + + r |= (r >> 2); + r |= (r >> 4); + return (r + 1) >> 1; +} + +/* return the inverse of the finite field element x */ + +static aes_08t fi(const aes_08t x) +{ aes_08t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; + + if(x < 2) return x; + + for(;;) + { + if(!n1) return v1; + + while(n2 >= n1) + { + n2 /= n1; p2 ^= p1 * n2; v2 ^= v1 * n2; n2 = hibit(p2); + } + + if(!n2) return v2; + + while(n1 >= n2) + { + n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1); + } + } +} + +#endif + +/* The forward and inverse affine transformations used in the S-box */ + +#define fwd_affine(x) \ + (w = (aes_32t)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(aes_08t)(w^(w>>8))) + +#define inv_affine(x) \ + (w = (aes_32t)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(aes_08t)(w^(w>>8))) + +static int init = 0; + +void gen_tabs(void) +{ aes_32t i, w; + +#if defined(FF_TABLES) + + aes_08t pow[512], log[256]; + + if(init) return; + /* log and power tables for GF(2^8) finite field with + WPOLY as modular polynomial - the simplest primitive + root is 0x03, used here to generate the tables + */ + + i = 0; w = 1; + do + { + pow[i] = (aes_08t)w; + pow[i + 255] = (aes_08t)w; + log[w] = (aes_08t)i++; + w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0); + } + while (w != 1); + +#else + if(init) return; +#endif + + for(i = 0, w = 1; i < RC_LENGTH; ++i) + { + t_set(r,c)[i] = bytes2word(w, 0, 0, 0); + w = f2(w); + } + + for(i = 0; i < 256; ++i) + { aes_08t b; + + b = fwd_affine(fi((aes_08t)i)); + w = bytes2word(f2(b), b, b, f3(b)); + +#ifdef SBX_SET + t_set(s,box)[i] = b; +#endif + +#ifdef FT1_SET /* tables for a normal encryption round */ + t_set(f,n)[i] = w; +#endif +#ifdef FT4_SET + t_set(f,n)[0][i] = w; + t_set(f,n)[1][i] = upr(w,1); + t_set(f,n)[2][i] = upr(w,2); + t_set(f,n)[3][i] = upr(w,3); +#endif + w = bytes2word(b, 0, 0, 0); + +#ifdef FL1_SET /* tables for last encryption round (may also */ + t_set(f,l)[i] = w; /* be used in the key schedule) */ +#endif +#ifdef FL4_SET + t_set(f,l)[0][i] = w; + t_set(f,l)[1][i] = upr(w,1); + t_set(f,l)[2][i] = upr(w,2); + t_set(f,l)[3][i] = upr(w,3); +#endif + +#ifdef LS1_SET /* table for key schedule if t_set(f,l) above is */ + t_set(l,s)[i] = w; /* not of the required form */ +#endif +#ifdef LS4_SET + t_set(l,s)[0][i] = w; + t_set(l,s)[1][i] = upr(w,1); + t_set(l,s)[2][i] = upr(w,2); + t_set(l,s)[3][i] = upr(w,3); +#endif + + b = fi(inv_affine((aes_08t)i)); + w = bytes2word(fe(b), f9(b), fd(b), fb(b)); + +#ifdef IM1_SET /* tables for the inverse mix column operation */ + t_set(i,m)[b] = w; +#endif +#ifdef IM4_SET + t_set(i,m)[0][b] = w; + t_set(i,m)[1][b] = upr(w,1); + t_set(i,m)[2][b] = upr(w,2); + t_set(i,m)[3][b] = upr(w,3); +#endif + +#ifdef ISB_SET + t_set(i,box)[i] = b; +#endif +#ifdef IT1_SET /* tables for a normal decryption round */ + t_set(i,n)[i] = w; +#endif +#ifdef IT4_SET + t_set(i,n)[0][i] = w; + t_set(i,n)[1][i] = upr(w,1); + t_set(i,n)[2][i] = upr(w,2); + t_set(i,n)[3][i] = upr(w,3); +#endif + w = bytes2word(b, 0, 0, 0); +#ifdef IL1_SET /* tables for last decryption round */ + t_set(i,l)[i] = w; +#endif +#ifdef IL4_SET + t_set(i,l)[0][i] = w; + t_set(i,l)[1][i] = upr(w,1); + t_set(i,l)[2][i] = upr(w,2); + t_set(i,l)[3][i] = upr(w,3); +#endif + } + init = 1; +} + +#endif + diff --git a/source/Irrlicht/aesGladman/fileenc.cpp b/source/Irrlicht/aesGladman/fileenc.cpp new file mode 100644 index 00000000..982d9c4e --- /dev/null +++ b/source/Irrlicht/aesGladman/fileenc.cpp @@ -0,0 +1,138 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + ------------------------------------------------------------------------- + Issue Date: 26/08/2003 + + This file implements password based file encryption and authentication + using AES in CTR mode, HMAC-SHA1 authentication and RFC2898 password + based key derivation. + +*/ + +#include + +#include "fileenc.h" + +/* subroutine for data encryption/decryption */ +/* this could be speeded up a lot by aligning */ +/* buffers and using 32 bit operations */ + +static void encr_data(unsigned char data[], unsigned long d_len, fcrypt_ctx cx[1]) +{ + unsigned long i = 0, pos = cx->encr_pos; + + while(i < d_len) + { + if(pos == BLOCK_SIZE) + { unsigned int j = 0; + /* increment encryption nonce */ + while(j < 8 && !++cx->nonce[j]) + ++j; + /* encrypt the nonce to form next xor buffer */ + aes_encrypt(cx->nonce, cx->encr_bfr, cx->encr_ctx); + pos = 0; + } + + data[i++] ^= cx->encr_bfr[pos++]; + } + + cx->encr_pos = pos; +} + +int fcrypt_init( + int mode, /* the mode to be used (input) */ + const unsigned char pwd[], /* the user specified password (input) */ + unsigned int pwd_len, /* the length of the password (input) */ + const unsigned char salt[], /* the salt (input) */ +#ifdef PASSWORD_VERIFIER + unsigned char pwd_ver[PWD_VER_LENGTH], /* 2 byte password verifier (output) */ +#endif + fcrypt_ctx cx[1]) /* the file encryption context (output) */ +{ + unsigned char kbuf[2 * MAX_KEY_LENGTH + PWD_VER_LENGTH]; + + if(pwd_len > MAX_PWD_LENGTH) + return PASSWORD_TOO_LONG; + + if(mode < 1 || mode > 3) + return BAD_MODE; + + cx->mode = mode; + cx->pwd_len = pwd_len; + /* initialise the encryption nonce and buffer pos */ + cx->encr_pos = BLOCK_SIZE; + + /* if we need a random component in the encryption */ + /* nonce, this is where it would have to be set */ + memset(cx->nonce, 0, BLOCK_SIZE * sizeof(unsigned char)); + /* initialise for authentication */ + hmac_sha_begin(cx->auth_ctx); + + /* derive the encryption and authetication keys and the password verifier */ + derive_key(pwd, pwd_len, salt, SALT_LENGTH(mode), KEYING_ITERATIONS, + kbuf, 2 * KEY_LENGTH(mode) + PWD_VER_LENGTH); + /* set the encryption key */ + aes_encrypt_key(kbuf, KEY_LENGTH(mode), cx->encr_ctx); + /* set the authentication key */ + hmac_sha_key(kbuf + KEY_LENGTH(mode), KEY_LENGTH(mode), cx->auth_ctx); +#ifdef PASSWORD_VERIFIER + memcpy(pwd_ver, kbuf + 2 * KEY_LENGTH(mode), PWD_VER_LENGTH); +#endif + /* clear the buffer holding the derived key values */ + memset(kbuf, 0, 2 * KEY_LENGTH(mode) + PWD_VER_LENGTH); + + return GOOD_RETURN; +} + +/* perform 'in place' encryption and authentication */ + +void fcrypt_encrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1]) +{ + encr_data(data, data_len, cx); + hmac_sha_data(data, data_len, cx->auth_ctx); +} + +/* perform 'in place' authentication and decryption */ + +void fcrypt_decrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1]) +{ + hmac_sha_data(data, data_len, cx->auth_ctx); + encr_data(data, data_len, cx); +} + +/* close encryption/decryption and return the MAC value */ + +int fcrypt_end(unsigned char mac[], fcrypt_ctx cx[1]) +{ + hmac_sha_end(mac, MAC_LENGTH(cx->mode), cx->auth_ctx); + memset(cx, 0, sizeof(fcrypt_ctx)); /* clear the encryption context */ + return MAC_LENGTH(cx->mode); /* return MAC length in bytes */ +} + diff --git a/source/Irrlicht/aesGladman/fileenc.h b/source/Irrlicht/aesGladman/fileenc.h new file mode 100644 index 00000000..ba5cabcc --- /dev/null +++ b/source/Irrlicht/aesGladman/fileenc.h @@ -0,0 +1,114 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 24/01/2003 + + This file contains the header file for fileenc.c, which implements password + based file encryption and authentication using AES in CTR mode, HMAC-SHA1 + authentication and RFC2898 password based key derivation. +*/ + +#ifndef _FENC_H +#define _FENC_H + +#include "aes.h" +#include "hmac.h" +#include "pwd2key.h" + +#define BLOCK_SIZE AES_BLOCK_SIZE +#define PASSWORD_VERIFIER + +#define MAX_KEY_LENGTH 32 +#define MAX_PWD_LENGTH 128 +#define MAX_SALT_LENGTH 16 +#define KEYING_ITERATIONS 1000 + +#ifdef PASSWORD_VERIFIER +#define PWD_VER_LENGTH 2 +#else +#define PWD_VER_LENGTH 0 +#endif + +#define GOOD_RETURN 0 +#define PASSWORD_TOO_LONG -100 +#define BAD_MODE -101 + +/* + Field lengths (in bytes) versus File Encryption Mode (0 < mode < 4) + + Mode Key Salt MAC Overhead + 1 16 8 10 18 + 2 24 12 10 22 + 3 32 16 10 26 + + The following macros assume that the mode value is correct. +*/ + +#define KEY_LENGTH(mode) (8 * (mode & 3) + 8) +#define SALT_LENGTH(mode) (4 * (mode & 3) + 4) +#define MAC_LENGTH(mode) (10) + +/* the context for file encryption */ + +typedef struct +{ unsigned char nonce[BLOCK_SIZE]; /* the CTR nonce */ + unsigned char encr_bfr[BLOCK_SIZE]; /* encrypt buffer */ + aes_encrypt_ctx encr_ctx[1]; /* encryption context */ + hmac_ctx auth_ctx[1]; /* authentication context */ + unsigned int encr_pos; /* block position (enc) */ + unsigned int pwd_len; /* password length */ + unsigned int mode; /* File encryption mode */ +} fcrypt_ctx; + +/* initialise file encryption or decryption */ + +int fcrypt_init( + int mode, /* the mode to be used (input) */ + const unsigned char pwd[], /* the user specified password (input) */ + unsigned int pwd_len, /* the length of the password (input) */ + const unsigned char salt[], /* the salt (input) */ +#ifdef PASSWORD_VERIFIER + unsigned char pwd_ver[PWD_VER_LENGTH], /* 2 byte password verifier (output) */ +#endif + fcrypt_ctx cx[1]); /* the file encryption context (output) */ + +/* perform 'in place' encryption or decryption and authentication */ + +void fcrypt_encrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1]); +void fcrypt_decrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1]); + +/* close encryption/decryption and return the MAC value */ +/* the return value is the length of the MAC */ + +int fcrypt_end(unsigned char mac[], /* the MAC value (output) */ + fcrypt_ctx cx[1]); /* the context (input) */ + +#endif + diff --git a/source/Irrlicht/aesGladman/hmac.cpp b/source/Irrlicht/aesGladman/hmac.cpp new file mode 100644 index 00000000..e6b322ef --- /dev/null +++ b/source/Irrlicht/aesGladman/hmac.cpp @@ -0,0 +1,142 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 26/08/2003 + Includes a bugfix from Dr Brian Gladman made on 16/04/2012 for compiling on 64-bit + + This is an implementation of HMAC, the FIPS standard keyed hash function +*/ + +#include +#include "hmac.h" + +#define HMAC_IPAD (0x36 * (((unsigned long)-1) / 0xff)) +#define HMAC_OPAD (0x5c * (((unsigned long)-1) / 0xff)) + +/* initialise the HMAC context to zero */ +void hmac_sha_begin(hmac_ctx cx[1]) +{ + memset(cx, 0, sizeof(hmac_ctx)); +} + +/* input the HMAC key (can be called multiple times) */ +int hmac_sha_key(const unsigned char key[], unsigned long key_len, hmac_ctx cx[1]) +{ + if(cx->klen == HMAC_IN_DATA) /* error if further key input */ + return HMAC_BAD_MODE; /* is attempted in data mode */ + + if(cx->klen + key_len > HMAC_HASH_INPUT_SIZE) /* if the key has to be hashed */ + { + if(cx->klen <= HMAC_HASH_INPUT_SIZE) /* if the hash has not yet been */ + { /* started, initialise it and */ + sha_begin(cx->ctx); /* hash stored key characters */ + sha_hash(cx->key, cx->klen, cx->ctx); + } + + sha_hash(key, key_len, cx->ctx); /* hash long key data into hash */ + } + else /* otherwise store key data */ + memcpy(cx->key + cx->klen, key, key_len); + + cx->klen += key_len; /* update the key length count */ + return HMAC_OK; +} + +/* input the HMAC data (can be called multiple times) - */ +/* note that this call terminates the key input phase */ +void hmac_sha_data(const unsigned char data[], unsigned long data_len, hmac_ctx cx[1]) +{ unsigned int i; + + if(cx->klen != HMAC_IN_DATA) /* if not yet in data phase */ + { + if(cx->klen > HMAC_HASH_INPUT_SIZE) /* if key is being hashed */ + { /* complete the hash and */ + sha_end(cx->key, cx->ctx); /* store the result as the */ + cx->klen = HMAC_HASH_OUTPUT_SIZE; /* key and set new length */ + } + + /* pad the key if necessary */ + memset(cx->key + cx->klen, 0, HMAC_HASH_INPUT_SIZE - cx->klen); + + /* xor ipad into key value */ + for(i = 0; i < HMAC_HASH_INPUT_SIZE / sizeof(unsigned long); ++i) + ((unsigned long*)cx->key)[i] ^= HMAC_IPAD; + + /* and start hash operation */ + sha_begin(cx->ctx); + sha_hash(cx->key, HMAC_HASH_INPUT_SIZE, cx->ctx); + + /* mark as now in data mode */ + cx->klen = HMAC_IN_DATA; + } + + /* hash the data (if any) */ + if(data_len) + sha_hash(data, data_len, cx->ctx); +} + +/* compute and output the MAC value */ +void hmac_sha_end(unsigned char mac[], unsigned long mac_len, hmac_ctx cx[1]) +{ unsigned char dig[HMAC_HASH_OUTPUT_SIZE]; + unsigned int i; + + /* if no data has been entered perform a null data phase */ + if(cx->klen != HMAC_IN_DATA) + hmac_sha_data((const unsigned char*)0, 0, cx); + + sha_end(dig, cx->ctx); /* complete the inner hash */ + + /* set outer key value using opad and removing ipad */ + for(i = 0; i < HMAC_HASH_INPUT_SIZE / sizeof(unsigned long); ++i) + ((unsigned long*)cx->key)[i] ^= HMAC_OPAD ^ HMAC_IPAD; + + /* perform the outer hash operation */ + sha_begin(cx->ctx); + sha_hash(cx->key, HMAC_HASH_INPUT_SIZE, cx->ctx); + sha_hash(dig, HMAC_HASH_OUTPUT_SIZE, cx->ctx); + sha_end(dig, cx->ctx); + + /* output the hash value */ + for(i = 0; i < mac_len; ++i) + mac[i] = dig[i]; +} + +/* 'do it all in one go' subroutine */ +void hmac_sha(const unsigned char key[], unsigned long key_len, + const unsigned char data[], unsigned long data_len, + unsigned char mac[], unsigned long mac_len) +{ hmac_ctx cx[1]; + + hmac_sha_begin(cx); + hmac_sha_key(key, key_len, cx); + hmac_sha_data(data, data_len, cx); + hmac_sha_end(mac, mac_len, cx); +} + diff --git a/source/Irrlicht/aesGladman/hmac.h b/source/Irrlicht/aesGladman/hmac.h new file mode 100644 index 00000000..284c50f7 --- /dev/null +++ b/source/Irrlicht/aesGladman/hmac.h @@ -0,0 +1,95 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 26/08/2003 + Includes a bugfix from Dr Brian Gladman made on 16/04/2012 for compiling on 64-bit + + This is an implementation of HMAC, the FIPS standard keyed hash function +*/ + +#ifndef _HMAC_H +#define _HMAC_H + +#include + +#define USE_SHA1 // Irrlicht only cares about SHA1 for now +#if !defined(USE_SHA1) && !defined(USE_SHA256) +#error define USE_SHA1 or USE_SHA256 to set the HMAC hash algorithm +#endif + +#ifdef USE_SHA1 + +#include "sha1.h" + +#define HMAC_HASH_INPUT_SIZE SHA1_BLOCK_SIZE +#define HMAC_HASH_OUTPUT_SIZE SHA1_DIGEST_SIZE +#define sha_ctx sha1_ctx +#define sha_begin sha1_begin +#define sha_hash sha1_hash +#define sha_end sha1_end + +#endif + +#ifdef USE_SHA256 + +#include "sha2.h" + +#define HMAC_HASH_INPUT_SIZE SHA256_BLOCK_SIZE +#define HMAC_HASH_OUTPUT_SIZE SHA256_DIGEST_SIZE +#define sha_ctx sha256_ctx +#define sha_begin sha256_begin +#define sha_hash sha256_hash +#define sha_end sha256_end + +#endif + +#define HMAC_OK 0 +#define HMAC_BAD_MODE -1 +#define HMAC_IN_DATA 0xffffffff + +typedef struct +{ unsigned char key[HMAC_HASH_INPUT_SIZE]; + sha_ctx ctx[1]; + unsigned long klen; +} hmac_ctx; + +void hmac_sha_begin(hmac_ctx cx[1]); + +int hmac_sha_key(const unsigned char key[], unsigned long key_len, hmac_ctx cx[1]); + +void hmac_sha_data(const unsigned char data[], unsigned long data_len, hmac_ctx cx[1]); + +void hmac_sha_end(unsigned char mac[], unsigned long mac_len, hmac_ctx cx[1]); + +void hmac_sha(const unsigned char key[], unsigned long key_len, + const unsigned char data[], unsigned long data_len, + unsigned char mac[], unsigned long mac_len); + +#endif diff --git a/source/Irrlicht/aesGladman/prng.cpp b/source/Irrlicht/aesGladman/prng.cpp new file mode 100644 index 00000000..b38d858d --- /dev/null +++ b/source/Irrlicht/aesGladman/prng.cpp @@ -0,0 +1,147 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 24/01/2003 + + This file implements a random data pool based on the use of an external + entropy function. It is based on the ideas advocated by Peter Gutmann in + his work on pseudo random sequence generators. It is not a 'paranoid' + random sequence generator and no attempt is made to protect the pool + from prying eyes either by memory locking or by techniques to obscure + its location in memory. +*/ + +#include +#include +#include "prng.h" + +/* mix a random data pool using the SHA1 compression function (as */ +/* suggested by Peter Gutmann in his paper on random pools) */ + +static void prng_mix(unsigned char buf[]) +{ unsigned int i, len; + sha1_ctx ctx[1]; + + /*lint -e{663} unusual array to pointer conversion */ + for(i = 0; i < PRNG_POOL_SIZE; i += SHA1_DIGEST_SIZE) + { + /* copy digest size pool block into SHA1 hash block */ + memcpy(ctx->hash, buf + (i ? i : PRNG_POOL_SIZE) + - SHA1_DIGEST_SIZE, SHA1_DIGEST_SIZE); + + /* copy data from pool into the SHA1 data buffer */ + len = PRNG_POOL_SIZE - i; + memcpy(ctx->wbuf, buf + i, (len > SHA1_BLOCK_SIZE ? SHA1_BLOCK_SIZE : len)); + + if(len < SHA1_BLOCK_SIZE) + memcpy(((char*)ctx->wbuf) + len, buf, SHA1_BLOCK_SIZE - len); + + /* compress using the SHA1 compression function */ + sha1_compile(ctx); + + /* put digest size block back into the random pool */ + memcpy(buf + i, ctx->hash, SHA1_DIGEST_SIZE); + } +} + +/* refresh the output buffer and update the random pool by adding */ +/* entropy and remixing */ + +static void update_pool(prng_ctx ctx[1]) +{ unsigned int i = 0; + + /* transfer random pool data to the output buffer */ + memcpy(ctx->obuf, ctx->rbuf, PRNG_POOL_SIZE); + + /* enter entropy data into the pool */ + while(i < PRNG_POOL_SIZE) + i += ctx->entropy(ctx->rbuf + i, PRNG_POOL_SIZE - i); + + /* invert and xor the original pool data into the pool */ + for(i = 0; i < PRNG_POOL_SIZE; ++i) + ctx->rbuf[i] ^= ~ctx->obuf[i]; + + /* mix the pool and the output buffer */ + prng_mix(ctx->rbuf); + prng_mix(ctx->obuf); +} + +void prng_init(prng_entropy_fn fun, prng_ctx ctx[1]) +{ int i; + + /* clear the buffers and the counter in the context */ + memset(ctx, 0, sizeof(prng_ctx)); + + /* set the pointer to the entropy collection function */ + ctx->entropy = fun; + + /* initialise the random data pool */ + update_pool(ctx); + + /* mix the pool a minimum number of times */ + for(i = 0; i < PRNG_MIN_MIX; ++i) + prng_mix(ctx->rbuf); + + /* update the pool to prime the pool output buffer */ + update_pool(ctx); +} + +/* provide random bytes from the random data pool */ + +void prng_rand(unsigned char data[], unsigned int data_len, prng_ctx ctx[1]) +{ unsigned char *rp = data; + unsigned int len, pos = ctx->pos; + + while(data_len) + { + /* transfer 'data_len' bytes (or the number of bytes remaining */ + /* the pool output buffer if less) into the output */ + len = (data_len < PRNG_POOL_SIZE - pos ? data_len : PRNG_POOL_SIZE - pos); + memcpy(rp, ctx->obuf + pos, len); + rp += len; /* update ouput buffer position pointer */ + pos += len; /* update pool output buffer pointer */ + data_len -= len; /* update the remaining data count */ + + /* refresh the random pool if necessary */ + if(pos == PRNG_POOL_SIZE) + { + update_pool(ctx); pos = 0; + } + } + + ctx->pos = pos; +} + +void prng_end(prng_ctx ctx[1]) +{ + /* ensure the data in the context is destroyed */ + memset(ctx, 0, sizeof(prng_ctx)); +} + diff --git a/source/Irrlicht/aesGladman/prng.h b/source/Irrlicht/aesGladman/prng.h new file mode 100644 index 00000000..a81ed8e4 --- /dev/null +++ b/source/Irrlicht/aesGladman/prng.h @@ -0,0 +1,74 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 24/01/2003 + + This is the header file for an implementation of a random data pool based on + the use of an external entropy function (inspired by Peter Gutmann's work). +*/ + +#ifndef _PRNG_H +#define _PRNG_H + +#include "sha1.h" + +#define PRNG_POOL_LEN 256 /* minimum random pool size */ +#define PRNG_MIN_MIX 20 /* min initial pool mixing iterations */ + +/* ensure that pool length is a multiple of the SHA1 digest size */ + +#define PRNG_POOL_SIZE (SHA1_DIGEST_SIZE * (1 + (PRNG_POOL_LEN - 1) / SHA1_DIGEST_SIZE)) + +/* A function for providing entropy is a parameter in the prng_init() */ +/* call. This function has the following form and returns a maximum */ +/* of 'len' bytes of pseudo random data in the buffer 'buf'. It can */ +/* return less than 'len' bytes but will be repeatedly called for more */ +/* data in this case. */ + +typedef int (*prng_entropy_fn)(unsigned char buf[], unsigned int len); + +typedef struct +{ unsigned char rbuf[PRNG_POOL_SIZE]; /* the random pool */ + unsigned char obuf[PRNG_POOL_SIZE]; /* pool output buffer */ + unsigned int pos; /* output buffer position */ + prng_entropy_fn entropy; /* entropy function pointer */ +} prng_ctx; + +/* initialise the random stream generator */ +void prng_init(prng_entropy_fn fun, prng_ctx ctx[1]); + +/* obtain random bytes from the generator */ +void prng_rand(unsigned char data[], unsigned int data_len, prng_ctx ctx[1]); + +/* close the random stream generator */ +void prng_end(prng_ctx ctx[1]); + +#endif + diff --git a/source/Irrlicht/aesGladman/pwd2key.cpp b/source/Irrlicht/aesGladman/pwd2key.cpp new file mode 100644 index 00000000..cb9281d1 --- /dev/null +++ b/source/Irrlicht/aesGladman/pwd2key.cpp @@ -0,0 +1,187 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 26/08/2003 + + This is an implementation of RFC2898, which specifies key derivation from + a password and a salt value. +*/ + +#include +#include +#include "hmac.h" + +void derive_key(const unsigned char pwd[], /* the PASSWORD */ + unsigned int pwd_len, /* and its length */ + const unsigned char salt[], /* the SALT and its */ + unsigned int salt_len, /* length */ + unsigned int iter, /* the number of iterations */ + unsigned char key[], /* space for the output key */ + unsigned int key_len)/* and its required length */ +{ + unsigned int i, j, k, n_blk; + unsigned char uu[HMAC_HASH_OUTPUT_SIZE], ux[HMAC_HASH_OUTPUT_SIZE]; + hmac_ctx c1[1], c2[1], c3[1]; + + /* set HMAC context (c1) for password */ + hmac_sha_begin(c1); + hmac_sha_key(pwd, pwd_len, c1); + + /* set HMAC context (c2) for password and salt */ + memcpy(c2, c1, sizeof(hmac_ctx)); + hmac_sha_data(salt, salt_len, c2); + + /* find the number of SHA blocks in the key */ + n_blk = 1 + (key_len - 1) / HMAC_HASH_OUTPUT_SIZE; + + for(i = 0; i < n_blk; ++i) /* for each block in key */ + { + /* ux[] holds the running xor value */ + memset(ux, 0, HMAC_HASH_OUTPUT_SIZE); + + /* set HMAC context (c3) for password and salt */ + memcpy(c3, c2, sizeof(hmac_ctx)); + + /* enter additional data for 1st block into uu */ + uu[0] = (unsigned char)((i + 1) >> 24); + uu[1] = (unsigned char)((i + 1) >> 16); + uu[2] = (unsigned char)((i + 1) >> 8); + uu[3] = (unsigned char)(i + 1); + + /* this is the key mixing iteration */ + for(j = 0, k = 4; j < iter; ++j) + { + /* add previous round data to HMAC */ + hmac_sha_data(uu, k, c3); + + /* obtain HMAC for uu[] */ + hmac_sha_end(uu, HMAC_HASH_OUTPUT_SIZE, c3); + + /* xor into the running xor block */ + for(k = 0; k < HMAC_HASH_OUTPUT_SIZE; ++k) + ux[k] ^= uu[k]; + + /* set HMAC context (c3) for password */ + memcpy(c3, c1, sizeof(hmac_ctx)); + } + + /* compile key blocks into the key output */ + j = 0; k = i * HMAC_HASH_OUTPUT_SIZE; + while(j < HMAC_HASH_OUTPUT_SIZE && k < key_len) + key[k++] = ux[j++]; + } +} + +#ifdef TEST + +#include + +struct +{ unsigned int pwd_len; + unsigned int salt_len; + unsigned int it_count; + unsigned char *pwd; + unsigned char salt[32]; + unsigned char key[32]; +} tests[] = +{ + { 8, 4, 5, (unsigned char*)"password", + { + 0x12, 0x34, 0x56, 0x78 + }, + { + 0x5c, 0x75, 0xce, 0xf0, 0x1a, 0x96, 0x0d, 0xf7, + 0x4c, 0xb6, 0xb4, 0x9b, 0x9e, 0x38, 0xe6, 0xb5 + } + }, + { 8, 8, 5, (unsigned char*)"password", + { + 0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0x12 + }, + { + 0xd1, 0xda, 0xa7, 0x86, 0x15, 0xf2, 0x87, 0xe6, + 0xa1, 0xc8, 0xb1, 0x20, 0xd7, 0x06, 0x2a, 0x49 + } + }, + { 8, 21, 1, (unsigned char*)"password", + { + "ATHENA.MIT.EDUraeburn" + }, + { + 0xcd, 0xed, 0xb5, 0x28, 0x1b, 0xb2, 0xf8, 0x01, + 0x56, 0x5a, 0x11, 0x22, 0xb2, 0x56, 0x35, 0x15 + } + }, + { 8, 21, 2, (unsigned char*)"password", + { + "ATHENA.MIT.EDUraeburn" + }, + { + 0x01, 0xdb, 0xee, 0x7f, 0x4a, 0x9e, 0x24, 0x3e, + 0x98, 0x8b, 0x62, 0xc7, 0x3c, 0xda, 0x93, 0x5d + } + }, + { 8, 21, 1200, (unsigned char*)"password", + { + "ATHENA.MIT.EDUraeburn" + }, + { + 0x5c, 0x08, 0xeb, 0x61, 0xfd, 0xf7, 0x1e, 0x4e, + 0x4e, 0xc3, 0xcf, 0x6b, 0xa1, 0xf5, 0x51, 0x2b + } + } +}; + +int main() +{ unsigned int i, j, key_len = 256; + unsigned char key[256]; + + printf("\nTest of RFC2898 Password Based Key Derivation"); + for(i = 0; i < 5; ++i) + { + derive_key(tests[i].pwd, tests[i].pwd_len, tests[i].salt, + tests[i].salt_len, tests[i].it_count, key, key_len); + + printf("\ntest %i: ", i + 1); + printf("key %s", memcmp(tests[i].key, key, 16) ? "is bad" : "is good"); + for(j = 0; j < key_len && j < 64; j += 4) + { + if(j % 16 == 0) + printf("\n"); + printf("0x%02x%02x%02x%02x ", key[j], key[j + 1], key[j + 2], key[j + 3]); + } + printf(j < key_len ? " ... \n" : "\n"); + } + printf("\n"); + return 0; +} + +#endif + diff --git a/source/Irrlicht/aesGladman/pwd2key.h b/source/Irrlicht/aesGladman/pwd2key.h new file mode 100644 index 00000000..f5248ad6 --- /dev/null +++ b/source/Irrlicht/aesGladman/pwd2key.h @@ -0,0 +1,50 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 26/08/2003 + + This is an implementation of RFC2898, which specifies key derivation from + a password and a salt value. +*/ + +#ifndef PWD2KEY_H +#define PWD2KEY_H + +void derive_key( + const unsigned char pwd[], /* the PASSWORD, and */ + unsigned int pwd_len, /* its length */ + const unsigned char salt[], /* the SALT and its */ + unsigned int salt_len, /* length */ + unsigned int iter, /* the number of iterations */ + unsigned char key[], /* space for the output key */ + unsigned int key_len); /* and its required length */ + +#endif + diff --git a/source/Irrlicht/aesGladman/sha1.cpp b/source/Irrlicht/aesGladman/sha1.cpp new file mode 100644 index 00000000..8a917685 --- /dev/null +++ b/source/Irrlicht/aesGladman/sha1.cpp @@ -0,0 +1,237 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 26/08/2003 + + This is a byte oriented version of SHA1 that operates on arrays of bytes + stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor +*/ + +#include /* for memcpy() etc. */ +#include /* for _lrotl with VC++ */ + +#include "sha1.h" +#include "../os.h" + +/* + To obtain the highest speed on processors with 32-bit words, this code + needs to determine the order in which bytes are packed into such words. + The following block of code is an attempt to capture the most obvious + ways in which various environemnts specify their endian definitions. + It may well fail, in which case the definitions will need to be set by + editing at the points marked **** EDIT HERE IF NECESSARY **** below. +*/ + +/* BYTE ORDER IN 32-BIT WORDS + + To obtain the highest speed on processors with 32-bit words, this code + needs to determine the byte order of the target machine. The following + block of code is an attempt to capture the most obvious ways in which + various environemnts define byte order. It may well fail, in which case + the definitions will need to be set by editing at the points marked + **** EDIT HERE IF NECESSARY **** below. My thanks to Peter Gutmann for + some of these defines (from cryptlib). +*/ + +#define BRG_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ +#define BRG_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ + +#ifdef __BIG_ENDIAN__ +#define PLATFORM_BYTE_ORDER BRG_BIG_ENDIAN +#else +#define PLATFORM_BYTE_ORDER BRG_LITTLE_ENDIAN +#endif + +#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n))) + +#if (PLATFORM_BYTE_ORDER == BRG_BIG_ENDIAN) +#define swap_b32(x) (x) +#else +#define swap_b32(x) irr::os::Byteswap::byteswap(x) +#endif + +#define SHA1_MASK (SHA1_BLOCK_SIZE - 1) + +#if 1 + +#define ch(x,y,z) (((x) & (y)) ^ (~(x) & (z))) +#define parity(x,y,z) ((x) ^ (y) ^ (z)) +#define maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +#else /* Discovered Rich Schroeppel and Colin Plumb */ + +#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) +#define parity(x,y,z) ((x) ^ (y) ^ (z)) +#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y)))) + +#endif + +/* A normal version as set out in the FIPS */ + +#define rnd(f,k) \ + t = a; a = rotl32(a,5) + f(b,c,d) + e + k + w[i]; \ + e = d; d = c; c = rotl32(b, 30); b = t + +void sha1_compile(sha1_ctx ctx[1]) +{ sha1_32t w[80], i, a, b, c, d, e, t; + + /* note that words are compiled from the buffer into 32-bit */ + /* words in big-endian order so an order reversal is needed */ + /* here on little endian machines */ + for(i = 0; i < SHA1_BLOCK_SIZE / 4; ++i) + w[i] = swap_b32(ctx->wbuf[i]); + + for(i = SHA1_BLOCK_SIZE / 4; i < 80; ++i) + w[i] = rotl32(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1); + + a = ctx->hash[0]; + b = ctx->hash[1]; + c = ctx->hash[2]; + d = ctx->hash[3]; + e = ctx->hash[4]; + + for(i = 0; i < 20; ++i) + { + rnd(ch, 0x5a827999); + } + + for(i = 20; i < 40; ++i) + { + rnd(parity, 0x6ed9eba1); + } + + for(i = 40; i < 60; ++i) + { + rnd(maj, 0x8f1bbcdc); + } + + for(i = 60; i < 80; ++i) + { + rnd(parity, 0xca62c1d6); + } + + ctx->hash[0] += a; + ctx->hash[1] += b; + ctx->hash[2] += c; + ctx->hash[3] += d; + ctx->hash[4] += e; +} + +void sha1_begin(sha1_ctx ctx[1]) +{ + ctx->count[0] = ctx->count[1] = 0; + ctx->hash[0] = 0x67452301; + ctx->hash[1] = 0xefcdab89; + ctx->hash[2] = 0x98badcfe; + ctx->hash[3] = 0x10325476; + ctx->hash[4] = 0xc3d2e1f0; +} + +/* SHA1 hash data in an array of bytes into hash buffer and */ +/* call the hash_compile function as required. */ + +void sha1_hash(const unsigned char data[], unsigned long len, sha1_ctx ctx[1]) +{ sha1_32t pos = (sha1_32t)(ctx->count[0] & SHA1_MASK), + space = SHA1_BLOCK_SIZE - pos; + const unsigned char *sp = data; + + if((ctx->count[0] += len) < len) + ++(ctx->count[1]); + + while(len >= space) /* tranfer whole blocks if possible */ + { + memcpy(((unsigned char*)ctx->wbuf) + pos, sp, space); + sp += space; len -= space; space = SHA1_BLOCK_SIZE; pos = 0; + sha1_compile(ctx); + } + + /*lint -e{803} conceivable data overrun */ + memcpy(((unsigned char*)ctx->wbuf) + pos, sp, len); +} + +/* SHA1 final padding and digest calculation */ + +#if (PLATFORM_BYTE_ORDER == BRG_LITTLE_ENDIAN) +static sha1_32t mask[4] = + { 0x00000000, 0x000000ff, 0x0000ffff, 0x00ffffff }; +static sha1_32t bits[4] = + { 0x00000080, 0x00008000, 0x00800000, 0x80000000 }; +#else +static sha1_32t mask[4] = + { 0x00000000, 0xff000000, 0xffff0000, 0xffffff00 }; +static sha1_32t bits[4] = + { 0x80000000, 0x00800000, 0x00008000, 0x00000080 }; +#endif + +void sha1_end(unsigned char hval[], sha1_ctx ctx[1]) +{ sha1_32t i = (sha1_32t)(ctx->count[0] & SHA1_MASK); + + /* mask out the rest of any partial 32-bit word and then set */ + /* the next byte to 0x80. On big-endian machines any bytes in */ + /* the buffer will be at the top end of 32 bit words, on little */ + /* endian machines they will be at the bottom. Hence the AND */ + /* and OR masks above are reversed for little endian systems */ + /* Note that we can always add the first padding byte at this */ + /* point because the buffer always has at least one empty slot */ + ctx->wbuf[i >> 2] = (ctx->wbuf[i >> 2] & mask[i & 3]) | bits[i & 3]; + + /* we need 9 or more empty positions, one for the padding byte */ + /* (above) and eight for the length count. If there is not */ + /* enough space pad and empty the buffer */ + if(i > SHA1_BLOCK_SIZE - 9) + { + if(i < 60) ctx->wbuf[15] = 0; + sha1_compile(ctx); + i = 0; + } + else /* compute a word index for the empty buffer positions */ + i = (i >> 2) + 1; + + while(i < 14) /* and zero pad all but last two positions */ + ctx->wbuf[i++] = 0; + + /* assemble the eight byte counter in in big-endian format */ + ctx->wbuf[14] = swap_b32((ctx->count[1] << 3) | (ctx->count[0] >> 29)); + ctx->wbuf[15] = swap_b32(ctx->count[0] << 3); + + sha1_compile(ctx); + + /* extract the hash value as bytes in case the hash buffer is */ + /* misaligned for 32-bit words */ + for(i = 0; i < SHA1_DIGEST_SIZE; ++i) + hval[i] = (unsigned char)(ctx->hash[i >> 2] >> (8 * (~i & 3))); +} + +void sha1(unsigned char hval[], const unsigned char data[], unsigned long len) +{ sha1_ctx cx[1]; + + sha1_begin(cx); sha1_hash(data, len, cx); sha1_end(hval, cx); +} + diff --git a/source/Irrlicht/aesGladman/sha1.h b/source/Irrlicht/aesGladman/sha1.h new file mode 100644 index 00000000..0b39f5c8 --- /dev/null +++ b/source/Irrlicht/aesGladman/sha1.h @@ -0,0 +1,68 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 26/08/2003 +*/ + +#ifndef _SHA1_H +#define _SHA1_H + +#include + +#define SHA1_BLOCK_SIZE 64 +#define SHA1_DIGEST_SIZE 20 + +/* define an unsigned 32-bit type */ + +#if UINT_MAX == 0xffffffff + typedef unsigned int sha1_32t; +#elif ULONG_MAX == 0xffffffff + typedef unsigned long sha1_32t; +#else +#error Please define sha1_32t as an unsigned 32 bit type in sha2.h +#endif + +/* type to hold the SHA256 context */ + +typedef struct +{ sha1_32t count[2]; + sha1_32t hash[5]; + sha1_32t wbuf[16]; +} sha1_ctx; + +void sha1_compile(sha1_ctx ctx[1]); + +void sha1_begin(sha1_ctx ctx[1]); +void sha1_hash(const unsigned char data[], unsigned long len, sha1_ctx ctx[1]); +void sha1_end(unsigned char hval[], sha1_ctx ctx[1]); +void sha1(unsigned char hval[], const unsigned char data[], unsigned long len); + +#endif + diff --git a/source/Irrlicht/aesGladman/sha2.cpp b/source/Irrlicht/aesGladman/sha2.cpp new file mode 100644 index 00000000..5be1bbf4 --- /dev/null +++ b/source/Irrlicht/aesGladman/sha2.cpp @@ -0,0 +1,626 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 26/08/2003 + + This is a byte oriented version of SHA2 that operates on arrays of bytes + stored in memory. This code implements sha256, sha384 and sha512 but the + latter two functions rely on efficient 64-bit integer operations that + may not be very efficient on 32-bit machines + + The sha256 functions use a type 'sha256_ctx' to hold details of the + current hash state and uses the following three calls: + + void sha256_begin(sha256_ctx ctx[1]) + void sha256_hash(const unsigned char data[], + unsigned long len, sha256_ctx ctx[1]) + void sha256_end(unsigned char hval[], sha256_ctx ctx[1]) + + The first subroutine initialises a hash computation by setting up the + context in the sha256_ctx context. The second subroutine hashes 8-bit + bytes from array data[] into the hash state withinh sha256_ctx context, + the number of bytes to be hashed being given by the the unsigned long + integer len. The third subroutine completes the hash calculation and + places the resulting digest value in the array of 8-bit bytes hval[]. + + The sha384 and sha512 functions are similar and use the interfaces: + + void sha384_begin(sha384_ctx ctx[1]); + void sha384_hash(const unsigned char data[], + unsigned long len, sha384_ctx ctx[1]); + void sha384_end(unsigned char hval[], sha384_ctx ctx[1]); + + void sha512_begin(sha512_ctx ctx[1]); + void sha512_hash(const unsigned char data[], + unsigned long len, sha512_ctx ctx[1]); + void sha512_end(unsigned char hval[], sha512_ctx ctx[1]); + + In addition there is a function sha2 that can be used to call all these + functions using a call with a hash length parameter as follows: + + int sha2_begin(unsigned long len, sha2_ctx ctx[1]); + void sha2_hash(const unsigned char data[], + unsigned long len, sha2_ctx ctx[1]); + void sha2_end(unsigned char hval[], sha2_ctx ctx[1]); + + My thanks to Erik Andersen for testing this code + on big-endian systems and for his assistance with corrections +*/ + +/* define the hash functions that you need */ + +#define SHA_2 /* for dynamic hash length */ +#define SHA_256 +#define SHA_384 +#define SHA_512 + +#include /* for memcpy() etc. */ +#include /* for _lrotr with VC++ */ + +#include "sha2.h" +#include "../os.h" + +/* BYTE ORDER IN 32-BIT WORDS + + To obtain the highest speed on processors with 32-bit words, this code + needs to determine the byte order of the target machine. The following + block of code is an attempt to capture the most obvious ways in which + various environemnts define byte order. It may well fail, in which case + the definitions will need to be set by editing at the points marked + **** EDIT HERE IF NECESSARY **** below. My thanks to Peter Gutmann for + some of these defines (from cryptlib). +*/ + +#define BRG_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ +#define BRG_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ + +#ifdef __BIG_ENDIAN__ +#define PLATFORM_BYTE_ORDER BRG_BIG_ENDIAN +#else +#define PLATFORM_BYTE_ORDER BRG_LITTLE_ENDIAN +#endif + +#ifdef _MSC_VER +#pragma intrinsic(memcpy) +#endif + +#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n))) + +#if !defined(bswap_32) +#define bswap_32(x) irr::os::Byteswap::byteswap(x) +#endif + +#if (PLATFORM_BYTE_ORDER == BRG_LITTLE_ENDIAN) +#define SWAP_BYTES +#else +#undef SWAP_BYTES +#endif + +#if defined(SHA_2) || defined(SHA_256) + +#define SHA256_MASK (SHA256_BLOCK_SIZE - 1) + +#if defined(SWAP_BYTES) +#define bsw_32(p,n) { int _i = (n); while(_i--) p[_i] = bswap_32(p[_i]); } +#else +#define bsw_32(p,n) +#endif + +/* SHA256 mixing function definitions */ + +#if 0 + +#define ch(x,y,z) (((x) & (y)) ^ (~(x) & (z))) +#define maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +#else /* Thanks to Rich Schroeppel and Colin Plumb for the following */ + +#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) +#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y)))) + +#endif + +#define s256_0(x) (rotr32((x), 2) ^ rotr32((x), 13) ^ rotr32((x), 22)) +#define s256_1(x) (rotr32((x), 6) ^ rotr32((x), 11) ^ rotr32((x), 25)) +#define g256_0(x) (rotr32((x), 7) ^ rotr32((x), 18) ^ ((x) >> 3)) +#define g256_1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10)) + +/* rotated SHA256 round definition. Rather than swapping variables as in */ +/* FIPS-180, different variables are 'rotated' on each round, returning */ +/* to their starting positions every eight rounds */ + +#define h2(i) p[i & 15] += \ + g256_1(p[(i + 14) & 15]) + p[(i + 9) & 15] + g256_0(p[(i + 1) & 15]) + +#define h2_cycle(i,j) \ + v[(7 - i) & 7] += (j ? h2(i) : p[i & 15]) + k256[i + j] \ + + s256_1(v[(4 - i) & 7]) + ch(v[(4 - i) & 7], v[(5 - i) & 7], v[(6 - i) & 7]); \ + v[(3 - i) & 7] += v[(7 - i) & 7]; \ + v[(7 - i) & 7] += s256_0(v[(0 - i) & 7]) + maj(v[(0 - i) & 7], v[(1 - i) & 7], v[(2 - i) & 7]) + +/* SHA256 mixing data */ + +const sha2_32t k256[64] = +{ n_u32(428a2f98), n_u32(71374491), n_u32(b5c0fbcf), n_u32(e9b5dba5), + n_u32(3956c25b), n_u32(59f111f1), n_u32(923f82a4), n_u32(ab1c5ed5), + n_u32(d807aa98), n_u32(12835b01), n_u32(243185be), n_u32(550c7dc3), + n_u32(72be5d74), n_u32(80deb1fe), n_u32(9bdc06a7), n_u32(c19bf174), + n_u32(e49b69c1), n_u32(efbe4786), n_u32(0fc19dc6), n_u32(240ca1cc), + n_u32(2de92c6f), n_u32(4a7484aa), n_u32(5cb0a9dc), n_u32(76f988da), + n_u32(983e5152), n_u32(a831c66d), n_u32(b00327c8), n_u32(bf597fc7), + n_u32(c6e00bf3), n_u32(d5a79147), n_u32(06ca6351), n_u32(14292967), + n_u32(27b70a85), n_u32(2e1b2138), n_u32(4d2c6dfc), n_u32(53380d13), + n_u32(650a7354), n_u32(766a0abb), n_u32(81c2c92e), n_u32(92722c85), + n_u32(a2bfe8a1), n_u32(a81a664b), n_u32(c24b8b70), n_u32(c76c51a3), + n_u32(d192e819), n_u32(d6990624), n_u32(f40e3585), n_u32(106aa070), + n_u32(19a4c116), n_u32(1e376c08), n_u32(2748774c), n_u32(34b0bcb5), + n_u32(391c0cb3), n_u32(4ed8aa4a), n_u32(5b9cca4f), n_u32(682e6ff3), + n_u32(748f82ee), n_u32(78a5636f), n_u32(84c87814), n_u32(8cc70208), + n_u32(90befffa), n_u32(a4506ceb), n_u32(bef9a3f7), n_u32(c67178f2), +}; + +/* SHA256 initialisation data */ + +const sha2_32t i256[8] = +{ + n_u32(6a09e667), n_u32(bb67ae85), n_u32(3c6ef372), n_u32(a54ff53a), + n_u32(510e527f), n_u32(9b05688c), n_u32(1f83d9ab), n_u32(5be0cd19) +}; + +sha2_void sha256_begin(sha256_ctx ctx[1]) +{ + ctx->count[0] = ctx->count[1] = 0; + memcpy(ctx->hash, i256, 8 * sizeof(sha2_32t)); +} + +/* Compile 64 bytes of hash data into SHA256 digest value */ +/* NOTE: this routine assumes that the byte order in the */ +/* ctx->wbuf[] at this point is in such an order that low */ +/* address bytes in the ORIGINAL byte stream placed in this */ +/* buffer will now go to the high end of words on BOTH big */ +/* and little endian systems */ + +sha2_void sha256_compile(sha256_ctx ctx[1]) +{ sha2_32t v[8], j, *p = ctx->wbuf; + + memcpy(v, ctx->hash, 8 * sizeof(sha2_32t)); + + for(j = 0; j < 64; j += 16) + { + h2_cycle( 0, j); h2_cycle( 1, j); h2_cycle( 2, j); h2_cycle( 3, j); + h2_cycle( 4, j); h2_cycle( 5, j); h2_cycle( 6, j); h2_cycle( 7, j); + h2_cycle( 8, j); h2_cycle( 9, j); h2_cycle(10, j); h2_cycle(11, j); + h2_cycle(12, j); h2_cycle(13, j); h2_cycle(14, j); h2_cycle(15, j); + } + + ctx->hash[0] += v[0]; ctx->hash[1] += v[1]; ctx->hash[2] += v[2]; ctx->hash[3] += v[3]; + ctx->hash[4] += v[4]; ctx->hash[5] += v[5]; ctx->hash[6] += v[6]; ctx->hash[7] += v[7]; +} + +/* SHA256 hash data in an array of bytes into hash buffer */ +/* and call the hash_compile function as required. */ + +sha2_void sha256_hash(const unsigned char data[], unsigned long len, sha256_ctx ctx[1]) +{ sha2_32t pos = (sha2_32t)(ctx->count[0] & SHA256_MASK), + space = SHA256_BLOCK_SIZE - pos; + const unsigned char *sp = data; + + if((ctx->count[0] += len) < len) + ++(ctx->count[1]); + + while(len >= space) /* tranfer whole blocks while possible */ + { + memcpy(((unsigned char*)ctx->wbuf) + pos, sp, space); + sp += space; len -= space; space = SHA256_BLOCK_SIZE; pos = 0; + bsw_32(ctx->wbuf, SHA256_BLOCK_SIZE >> 2) + sha256_compile(ctx); + } + + memcpy(((unsigned char*)ctx->wbuf) + pos, sp, len); +} + +/* SHA256 Final padding and digest calculation */ + +static sha2_32t m1[4] = +{ + n_u32(00000000), n_u32(ff000000), n_u32(ffff0000), n_u32(ffffff00) +}; + +static sha2_32t b1[4] = +{ + n_u32(80000000), n_u32(00800000), n_u32(00008000), n_u32(00000080) +}; + +sha2_void sha256_end(unsigned char hval[], sha256_ctx ctx[1]) +{ sha2_32t i = (sha2_32t)(ctx->count[0] & SHA256_MASK); + + bsw_32(ctx->wbuf, (i + 3) >> 2) + /* bytes in the buffer are now in an order in which references */ + /* to 32-bit words will put bytes with lower addresses into the */ + /* top of 32 bit words on BOTH big and little endian machines */ + + /* we now need to mask valid bytes and add the padding which is */ + /* a single 1 bit and as many zero bits as necessary. */ + ctx->wbuf[i >> 2] = (ctx->wbuf[i >> 2] & m1[i & 3]) | b1[i & 3]; + + /* we need 9 or more empty positions, one for the padding byte */ + /* (above) and eight for the length count. If there is not */ + /* enough space pad and empty the buffer */ + if(i > SHA256_BLOCK_SIZE - 9) + { + if(i < 60) ctx->wbuf[15] = 0; + sha256_compile(ctx); + i = 0; + } + else /* compute a word index for the empty buffer positions */ + i = (i >> 2) + 1; + + while(i < 14) /* and zero pad all but last two positions */ + ctx->wbuf[i++] = 0; + + /* the following 32-bit length fields are assembled in the */ + /* wrong byte order on little endian machines but this is */ + /* corrected later since they are only ever used as 32-bit */ + /* word values. */ + + ctx->wbuf[14] = (ctx->count[1] << 3) | (ctx->count[0] >> 29); + ctx->wbuf[15] = ctx->count[0] << 3; + + sha256_compile(ctx); + + /* extract the hash value as bytes in case the hash buffer is */ + /* mislaigned for 32-bit words */ + for(i = 0; i < SHA256_DIGEST_SIZE; ++i) + hval[i] = (unsigned char)(ctx->hash[i >> 2] >> (8 * (~i & 3))); +} + +sha2_void sha256(unsigned char hval[], const unsigned char data[], unsigned long len) +{ sha256_ctx cx[1]; + + sha256_begin(cx); sha256_hash(data, len, cx); sha256_end(hval, cx); +} + +#endif + +#if defined(SHA_2) || defined(SHA_384) || defined(SHA_512) + +#define SHA512_MASK (SHA512_BLOCK_SIZE - 1) + +#define rotr64(x,n) (((x) >> n) | ((x) << (64 - n))) + +#if !defined(bswap_64) +#define bswap_64(x) ((((sha2_64t)(bswap_32((sha2_32t)(x)))) << 32) | (bswap_32((sha2_32t)((x) >> 32)))) +#endif + +#if defined(SWAP_BYTES) +#define bsw_64(p,n) { int _i = (n); while(_i--) p[_i] = bswap_64(p[_i]); } +#else +#define bsw_64(p,n) +#endif + +/* SHA512 mixing function definitions */ + +#define s512_0(x) (rotr64((x), 28) ^ rotr64((x), 34) ^ rotr64((x), 39)) +#define s512_1(x) (rotr64((x), 14) ^ rotr64((x), 18) ^ rotr64((x), 41)) +#define g512_0(x) (rotr64((x), 1) ^ rotr64((x), 8) ^ ((x) >> 7)) +#define g512_1(x) (rotr64((x), 19) ^ rotr64((x), 61) ^ ((x) >> 6)) + +/* rotated SHA512 round definition. Rather than swapping variables as in */ +/* FIPS-180, different variables are 'rotated' on each round, returning */ +/* to their starting positions every eight rounds */ + +#define h5(i) ctx->wbuf[i & 15] += \ + g512_1(ctx->wbuf[(i + 14) & 15]) + ctx->wbuf[(i + 9) & 15] + g512_0(ctx->wbuf[(i + 1) & 15]) + +#define h5_cycle(i,j) \ + v[(7 - i) & 7] += (j ? h5(i) : ctx->wbuf[i & 15]) + k512[i + j] \ + + s512_1(v[(4 - i) & 7]) + ch(v[(4 - i) & 7], v[(5 - i) & 7], v[(6 - i) & 7]); \ + v[(3 - i) & 7] += v[(7 - i) & 7]; \ + v[(7 - i) & 7] += s512_0(v[(0 - i) & 7]) + maj(v[(0 - i) & 7], v[(1 - i) & 7], v[(2 - i) & 7]) + +/* SHA384/SHA512 mixing data */ + +const sha2_64t k512[80] = +{ + n_u64(428a2f98d728ae22), n_u64(7137449123ef65cd), + n_u64(b5c0fbcfec4d3b2f), n_u64(e9b5dba58189dbbc), + n_u64(3956c25bf348b538), n_u64(59f111f1b605d019), + n_u64(923f82a4af194f9b), n_u64(ab1c5ed5da6d8118), + n_u64(d807aa98a3030242), n_u64(12835b0145706fbe), + n_u64(243185be4ee4b28c), n_u64(550c7dc3d5ffb4e2), + n_u64(72be5d74f27b896f), n_u64(80deb1fe3b1696b1), + n_u64(9bdc06a725c71235), n_u64(c19bf174cf692694), + n_u64(e49b69c19ef14ad2), n_u64(efbe4786384f25e3), + n_u64(0fc19dc68b8cd5b5), n_u64(240ca1cc77ac9c65), + n_u64(2de92c6f592b0275), n_u64(4a7484aa6ea6e483), + n_u64(5cb0a9dcbd41fbd4), n_u64(76f988da831153b5), + n_u64(983e5152ee66dfab), n_u64(a831c66d2db43210), + n_u64(b00327c898fb213f), n_u64(bf597fc7beef0ee4), + n_u64(c6e00bf33da88fc2), n_u64(d5a79147930aa725), + n_u64(06ca6351e003826f), n_u64(142929670a0e6e70), + n_u64(27b70a8546d22ffc), n_u64(2e1b21385c26c926), + n_u64(4d2c6dfc5ac42aed), n_u64(53380d139d95b3df), + n_u64(650a73548baf63de), n_u64(766a0abb3c77b2a8), + n_u64(81c2c92e47edaee6), n_u64(92722c851482353b), + n_u64(a2bfe8a14cf10364), n_u64(a81a664bbc423001), + n_u64(c24b8b70d0f89791), n_u64(c76c51a30654be30), + n_u64(d192e819d6ef5218), n_u64(d69906245565a910), + n_u64(f40e35855771202a), n_u64(106aa07032bbd1b8), + n_u64(19a4c116b8d2d0c8), n_u64(1e376c085141ab53), + n_u64(2748774cdf8eeb99), n_u64(34b0bcb5e19b48a8), + n_u64(391c0cb3c5c95a63), n_u64(4ed8aa4ae3418acb), + n_u64(5b9cca4f7763e373), n_u64(682e6ff3d6b2b8a3), + n_u64(748f82ee5defb2fc), n_u64(78a5636f43172f60), + n_u64(84c87814a1f0ab72), n_u64(8cc702081a6439ec), + n_u64(90befffa23631e28), n_u64(a4506cebde82bde9), + n_u64(bef9a3f7b2c67915), n_u64(c67178f2e372532b), + n_u64(ca273eceea26619c), n_u64(d186b8c721c0c207), + n_u64(eada7dd6cde0eb1e), n_u64(f57d4f7fee6ed178), + n_u64(06f067aa72176fba), n_u64(0a637dc5a2c898a6), + n_u64(113f9804bef90dae), n_u64(1b710b35131c471b), + n_u64(28db77f523047d84), n_u64(32caab7b40c72493), + n_u64(3c9ebe0a15c9bebc), n_u64(431d67c49c100d4c), + n_u64(4cc5d4becb3e42b6), n_u64(597f299cfc657e2a), + n_u64(5fcb6fab3ad6faec), n_u64(6c44198c4a475817) +}; + +/* Compile 64 bytes of hash data into SHA384/SHA512 digest value */ + +sha2_void sha512_compile(sha512_ctx ctx[1]) +{ sha2_64t v[8]; + sha2_32t j; + + memcpy(v, ctx->hash, 8 * sizeof(sha2_64t)); + + for(j = 0; j < 80; j += 16) + { + h5_cycle( 0, j); h5_cycle( 1, j); h5_cycle( 2, j); h5_cycle( 3, j); + h5_cycle( 4, j); h5_cycle( 5, j); h5_cycle( 6, j); h5_cycle( 7, j); + h5_cycle( 8, j); h5_cycle( 9, j); h5_cycle(10, j); h5_cycle(11, j); + h5_cycle(12, j); h5_cycle(13, j); h5_cycle(14, j); h5_cycle(15, j); + } + + ctx->hash[0] += v[0]; ctx->hash[1] += v[1]; ctx->hash[2] += v[2]; ctx->hash[3] += v[3]; + ctx->hash[4] += v[4]; ctx->hash[5] += v[5]; ctx->hash[6] += v[6]; ctx->hash[7] += v[7]; +} + +/* Compile 128 bytes of hash data into SHA256 digest value */ +/* NOTE: this routine assumes that the byte order in the */ +/* ctx->wbuf[] at this point is in such an order that low */ +/* address bytes in the ORIGINAL byte stream placed in this */ +/* buffer will now go to the high end of words on BOTH big */ +/* and little endian systems */ + +sha2_void sha512_hash(const unsigned char data[], unsigned long len, sha512_ctx ctx[1]) +{ sha2_32t pos = (sha2_32t)(ctx->count[0] & SHA512_MASK), + space = SHA512_BLOCK_SIZE - pos; + const unsigned char *sp = data; + + if((ctx->count[0] += len) < len) + ++(ctx->count[1]); + + while(len >= space) /* tranfer whole blocks while possible */ + { + memcpy(((unsigned char*)ctx->wbuf) + pos, sp, space); + sp += space; len -= space; space = SHA512_BLOCK_SIZE; pos = 0; + bsw_64(ctx->wbuf, SHA512_BLOCK_SIZE >> 3); + sha512_compile(ctx); + } + + memcpy(((unsigned char*)ctx->wbuf) + pos, sp, len); +} + +/* SHA384/512 Final padding and digest calculation */ + +static sha2_64t m2[8] = +{ + n_u64(0000000000000000), n_u64(ff00000000000000), + n_u64(ffff000000000000), n_u64(ffffff0000000000), + n_u64(ffffffff00000000), n_u64(ffffffffff000000), + n_u64(ffffffffffff0000), n_u64(ffffffffffffff00) +}; + +static sha2_64t b2[8] = +{ + n_u64(8000000000000000), n_u64(0080000000000000), + n_u64(0000800000000000), n_u64(0000008000000000), + n_u64(0000000080000000), n_u64(0000000000800000), + n_u64(0000000000008000), n_u64(0000000000000080) +}; + +static void sha_end(unsigned char hval[], sha512_ctx ctx[1], const unsigned int hlen) +{ sha2_32t i = (sha2_32t)(ctx->count[0] & SHA512_MASK); + + bsw_64(ctx->wbuf, (i + 7) >> 3); + + /* bytes in the buffer are now in an order in which references */ + /* to 64-bit words will put bytes with lower addresses into the */ + /* top of 64 bit words on BOTH big and little endian machines */ + + /* we now need to mask valid bytes and add the padding which is */ + /* a single 1 bit and as many zero bits as necessary. */ + ctx->wbuf[i >> 3] = (ctx->wbuf[i >> 3] & m2[i & 7]) | b2[i & 7]; + + /* we need 17 or more empty byte positions, one for the padding */ + /* byte (above) and sixteen for the length count. If there is */ + /* not enough space pad and empty the buffer */ + if(i > SHA512_BLOCK_SIZE - 17) + { + if(i < 120) ctx->wbuf[15] = 0; + sha512_compile(ctx); + i = 0; + } + else + i = (i >> 3) + 1; + + while(i < 14) + ctx->wbuf[i++] = 0; + + /* the following 64-bit length fields are assembled in the */ + /* wrong byte order on little endian machines but this is */ + /* corrected later since they are only ever used as 64-bit */ + /* word values. */ + + ctx->wbuf[14] = (ctx->count[1] << 3) | (ctx->count[0] >> 61); + ctx->wbuf[15] = ctx->count[0] << 3; + + sha512_compile(ctx); + + /* extract the hash value as bytes in case the hash buffer is */ + /* misaligned for 32-bit words */ + for(i = 0; i < hlen; ++i) + hval[i] = (unsigned char)(ctx->hash[i >> 3] >> (8 * (~i & 7))); +} + +#endif + +#if defined(SHA_2) || defined(SHA_384) + +/* SHA384 initialisation data */ + +const sha2_64t i384[80] = +{ + n_u64(cbbb9d5dc1059ed8), n_u64(629a292a367cd507), + n_u64(9159015a3070dd17), n_u64(152fecd8f70e5939), + n_u64(67332667ffc00b31), n_u64(8eb44a8768581511), + n_u64(db0c2e0d64f98fa7), n_u64(47b5481dbefa4fa4) +}; + +sha2_void sha384_begin(sha384_ctx ctx[1]) +{ + ctx->count[0] = ctx->count[1] = 0; + memcpy(ctx->hash, i384, 8 * sizeof(sha2_64t)); +} + +sha2_void sha384_end(unsigned char hval[], sha384_ctx ctx[1]) +{ + sha_end(hval, ctx, SHA384_DIGEST_SIZE); +} + +sha2_void sha384(unsigned char hval[], const unsigned char data[], unsigned long len) +{ sha384_ctx cx[1]; + + sha384_begin(cx); sha384_hash(data, len, cx); sha384_end(hval, cx); +} + +#endif + +#if defined(SHA_2) || defined(SHA_512) + +/* SHA512 initialisation data */ + +const sha2_64t i512[80] = +{ + n_u64(6a09e667f3bcc908), n_u64(bb67ae8584caa73b), + n_u64(3c6ef372fe94f82b), n_u64(a54ff53a5f1d36f1), + n_u64(510e527fade682d1), n_u64(9b05688c2b3e6c1f), + n_u64(1f83d9abfb41bd6b), n_u64(5be0cd19137e2179) +}; + +sha2_void sha512_begin(sha512_ctx ctx[1]) +{ + ctx->count[0] = ctx->count[1] = 0; + memcpy(ctx->hash, i512, 8 * sizeof(sha2_64t)); +} + +sha2_void sha512_end(unsigned char hval[], sha512_ctx ctx[1]) +{ + sha_end(hval, ctx, SHA512_DIGEST_SIZE); +} + +sha2_void sha512(unsigned char hval[], const unsigned char data[], unsigned long len) +{ sha512_ctx cx[1]; + + sha512_begin(cx); sha512_hash(data, len, cx); sha512_end(hval, cx); +} + +#endif + +#if defined(SHA_2) + +#define CTX_256(x) ((x)->uu->ctx256) +#define CTX_384(x) ((x)->uu->ctx512) +#define CTX_512(x) ((x)->uu->ctx512) + +/* SHA2 initialisation */ + +sha2_int sha2_begin(unsigned long len, sha2_ctx ctx[1]) +{ unsigned long l = len; + switch(len) + { + case 256: l = len >> 3; + case 32: CTX_256(ctx)->count[0] = CTX_256(ctx)->count[1] = 0; + memcpy(CTX_256(ctx)->hash, i256, 32); break; + case 384: l = len >> 3; + case 48: CTX_384(ctx)->count[0] = CTX_384(ctx)->count[1] = 0; + memcpy(CTX_384(ctx)->hash, i384, 64); break; + case 512: l = len >> 3; + case 64: CTX_512(ctx)->count[0] = CTX_512(ctx)->count[1] = 0; + memcpy(CTX_512(ctx)->hash, i512, 64); break; + default: return SHA2_BAD; + } + + ctx->sha2_len = l; return SHA2_GOOD; +} + +sha2_void sha2_hash(const unsigned char data[], unsigned long len, sha2_ctx ctx[1]) +{ + switch(ctx->sha2_len) + { + case 32: sha256_hash(data, len, CTX_256(ctx)); return; + case 48: sha384_hash(data, len, CTX_384(ctx)); return; + case 64: sha512_hash(data, len, CTX_512(ctx)); return; + } +} + +sha2_void sha2_end(unsigned char hval[], sha2_ctx ctx[1]) +{ + switch(ctx->sha2_len) + { + case 32: sha256_end(hval, CTX_256(ctx)); return; + case 48: sha_end(hval, CTX_384(ctx), SHA384_DIGEST_SIZE); return; + case 64: sha_end(hval, CTX_512(ctx), SHA512_DIGEST_SIZE); return; + } +} + +sha2_int sha2(unsigned char hval[], unsigned long size, + const unsigned char data[], unsigned long len) +{ sha2_ctx cx[1]; + + if(sha2_begin(size, cx) == SHA2_GOOD) + { + sha2_hash(data, len, cx); sha2_end(hval, cx); return SHA2_GOOD; + } + else + return SHA2_BAD; +} + +#endif + diff --git a/source/Irrlicht/aesGladman/sha2.h b/source/Irrlicht/aesGladman/sha2.h new file mode 100644 index 00000000..f95b614a --- /dev/null +++ b/source/Irrlicht/aesGladman/sha2.h @@ -0,0 +1,160 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 26/08/2003 +*/ + +#ifndef _SHA2_H +#define _SHA2_H + +#include "irrMath.h" + +/* Defines for suffixes to 32 and 64 bit unsigned numeric values */ + +#define sfx_lo(x,y) x##y +#define sfx_hi(x,y) sfx_lo(x,y) +#define n_u32(p) sfx_hi(0x##p,s_u32) +#define n_u64(p) sfx_hi(0x##p,s_u64) + +/* define an unsigned 32-bit type */ + +#if UINT_MAX == 0xffffffff + typedef unsigned int sha2_32t; + #define s_u32 u +#elif ULONG_MAX == 0xffffffff + typedef unsigned long sha2_32t; + #define s_u32 ul +#else +#error Please define sha2_32t as an unsigned 32 bit type in sha2.h +#endif + +/* define an unsigned 64-bit type */ + +#if defined(_MSC_VER) || defined(__BORLANDC__) +#if (_MSC_VER < 1300) || (__BORLANDC__ < 0x582) + typedef unsigned __int64 sha2_64t; + #define s_u64 ui64 +#elif ULONG_MAX == 0xffffffffffffffff + typedef unsigned long sha2_64t; + #define s_u64 ul +#elif ULONG_MAX == 0xffffffff + typedef unsigned long long sha2_64t; /* a somewhat dangerous guess */ + #define s_u64 ull +#else +#error Please define sha2_64t as an unsigned 64 bit type in sha2.h +#endif +#else +#ifdef _IRR_SOLARIS_PLATFORM_ +#include +#else +#include +#endif + typedef uint64_t sha2_64t; +#if __WORDSIZE==64 +#define s_u64 ul +#else +#define s_u64 ull +#endif +#endif + +#define SHA256_DIGEST_SIZE 32 +#define SHA384_DIGEST_SIZE 48 +#define SHA512_DIGEST_SIZE 64 + +#define SHA256_BLOCK_SIZE 64 +#define SHA384_BLOCK_SIZE 128 +#define SHA512_BLOCK_SIZE 128 + +#define SHA2_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE + +#define SHA2_GOOD 0 +#define SHA2_BAD 1 + +/* type to hold the SHA256 context */ + +typedef struct +{ sha2_32t count[2]; + sha2_32t hash[8]; + sha2_32t wbuf[16]; +} sha256_ctx; + +/* type to hold the SHA384/512 context */ + +typedef struct +{ sha2_64t count[2]; + sha2_64t hash[8]; + sha2_64t wbuf[16]; +} sha512_ctx; + +typedef sha512_ctx sha384_ctx; + +/* type to hold a SHA2 context (256/384/512) */ + +typedef struct +{ union + { sha256_ctx ctx256[1]; + sha512_ctx ctx512[1]; + } uu[1]; + sha2_32t sha2_len; +} sha2_ctx; + +#ifndef SHA2_DLL /* implement normal or DLL functions */ +#define sha2_void void +#define sha2_int int +#else +#define sha2_void void __declspec(dllexport) _stdcall +#define sha2_int int __declspec(dllexport) _stdcall +#endif + +sha2_void sha256_compile(sha256_ctx ctx[1]); +sha2_void sha512_compile(sha512_ctx ctx[1]); + +sha2_void sha256_begin(sha256_ctx ctx[1]); +sha2_void sha256_hash(const unsigned char data[], unsigned long len, sha256_ctx ctx[1]); +sha2_void sha256_end(unsigned char hval[], sha256_ctx ctx[1]); +sha2_void sha256(unsigned char hval[], const unsigned char data[], unsigned long len); + +sha2_void sha384_begin(sha384_ctx ctx[1]); +#define sha384_hash sha512_hash +sha2_void sha384_end(unsigned char hval[], sha384_ctx ctx[1]); +sha2_void sha384(unsigned char hval[], const unsigned char data[], unsigned long len); + +sha2_void sha512_begin(sha512_ctx ctx[1]); +sha2_void sha512_hash(const unsigned char data[], unsigned long len, sha512_ctx ctx[1]); +sha2_void sha512_end(unsigned char hval[], sha512_ctx ctx[1]); +sha2_void sha512(unsigned char hval[], const unsigned char data[], unsigned long len); + +sha2_int sha2_begin(unsigned long size, sha2_ctx ctx[1]); +sha2_void sha2_hash(const unsigned char data[], unsigned long len, sha2_ctx ctx[1]); +sha2_void sha2_end(unsigned char hval[], sha2_ctx ctx[1]); +sha2_int sha2(unsigned char hval[], unsigned long size, const unsigned char data[], unsigned long len); + +#endif + diff --git a/source/Irrlicht/builtInFont.bmp b/source/Irrlicht/builtInFont.bmp new file mode 100644 index 00000000..7001c123 Binary files /dev/null and b/source/Irrlicht/builtInFont.bmp differ diff --git a/source/Irrlicht/bzip2/CHANGES b/source/Irrlicht/bzip2/CHANGES new file mode 100644 index 00000000..81e97ca6 --- /dev/null +++ b/source/Irrlicht/bzip2/CHANGES @@ -0,0 +1,327 @@ + ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ + + +0.9.0 +~~~~~ +First version. + + +0.9.0a +~~~~~~ +Removed 'ranlib' from Makefile, since most modern Unix-es +don't need it, or even know about it. + + +0.9.0b +~~~~~~ +Fixed a problem with error reporting in bzip2.c. This does not effect +the library in any way. Problem is: versions 0.9.0 and 0.9.0a (of the +program proper) compress and decompress correctly, but give misleading +error messages (internal panics) when an I/O error occurs, instead of +reporting the problem correctly. This shouldn't give any data loss +(as far as I can see), but is confusing. + +Made the inline declarations disappear for non-GCC compilers. + + +0.9.0c +~~~~~~ +Fixed some problems in the library pertaining to some boundary cases. +This makes the library behave more correctly in those situations. The +fixes apply only to features (calls and parameters) not used by +bzip2.c, so the non-fixedness of them in previous versions has no +effect on reliability of bzip2.c. + +In bzlib.c: + * made zero-length BZ_FLUSH work correctly in bzCompress(). + * fixed bzWrite/bzRead to ignore zero-length requests. + * fixed bzread to correctly handle read requests after EOF. + * wrong parameter order in call to bzDecompressInit in + bzBuffToBuffDecompress. Fixed. + +In compress.c: + * changed setting of nGroups in sendMTFValues() so as to + do a bit better on small files. This _does_ effect + bzip2.c. + + +0.9.5a +~~~~~~ +Major change: add a fallback sorting algorithm (blocksort.c) +to give reasonable behaviour even for very repetitive inputs. +Nuked --repetitive-best and --repetitive-fast since they are +no longer useful. + +Minor changes: mostly a whole bunch of small changes/ +bugfixes in the driver (bzip2.c). Changes pertaining to the +user interface are: + + allow decompression of symlink'd files to stdout + decompress/test files even without .bz2 extension + give more accurate error messages for I/O errors + when compressing/decompressing to stdout, don't catch control-C + read flags from BZIP2 and BZIP environment variables + decline to break hard links to a file unless forced with -f + allow -c flag even with no filenames + preserve file ownerships as far as possible + make -s -1 give the expected block size (100k) + add a flag -q --quiet to suppress nonessential warnings + stop decoding flags after --, so files beginning in - can be handled + resolved inconsistent naming: bzcat or bz2cat ? + bzip2 --help now returns 0 + +Programming-level changes are: + + fixed syntax error in GET_LL4 for Borland C++ 5.02 + let bzBuffToBuffDecompress return BZ_DATA_ERROR{_MAGIC} + fix overshoot of mode-string end in bzopen_or_bzdopen + wrapped bzlib.h in #ifdef __cplusplus ... extern "C" { ... } + close file handles under all error conditions + added minor mods so it compiles with DJGPP out of the box + fixed Makefile so it doesn't give problems with BSD make + fix uninitialised memory reads in dlltest.c + +0.9.5b +~~~~~~ +Open stdin/stdout in binary mode for DJGPP. + +0.9.5c +~~~~~~ +Changed BZ_N_OVERSHOOT to be ... + 2 instead of ... + 1. The + 1 +version could cause the sorted order to be wrong in some extremely +obscure cases. Also changed setting of quadrant in blocksort.c. + +0.9.5d +~~~~~~ +The only functional change is to make bzlibVersion() in the library +return the correct string. This has no effect whatsoever on the +functioning of the bzip2 program or library. Added a couple of casts +so the library compiles without warnings at level 3 in MS Visual +Studio 6.0. Included a Y2K statement in the file Y2K_INFO. All other +changes are minor documentation changes. + +1.0 +~~~ +Several minor bugfixes and enhancements: + +* Large file support. The library uses 64-bit counters to + count the volume of data passing through it. bzip2.c + is now compiled with -D_FILE_OFFSET_BITS=64 to get large + file support from the C library. -v correctly prints out + file sizes greater than 4 gigabytes. All these changes have + been made without assuming a 64-bit platform or a C compiler + which supports 64-bit ints, so, except for the C library + aspect, they are fully portable. + +* Decompression robustness. The library/program should be + robust to any corruption of compressed data, detecting and + handling _all_ corruption, instead of merely relying on + the CRCs. What this means is that the program should + never crash, given corrupted data, and the library should + always return BZ_DATA_ERROR. + +* Fixed an obscure race-condition bug only ever observed on + Solaris, in which, if you were very unlucky and issued + control-C at exactly the wrong time, both input and output + files would be deleted. + +* Don't run out of file handles on test/decompression when + large numbers of files have invalid magic numbers. + +* Avoid library namespace pollution. Prefix all exported + symbols with BZ2_. + +* Minor sorting enhancements from my DCC2000 paper. + +* Advance the version number to 1.0, so as to counteract the + (false-in-this-case) impression some people have that programs + with version numbers less than 1.0 are in some way, experimental, + pre-release versions. + +* Create an initial Makefile-libbz2_so to build a shared library. + Yes, I know I should really use libtool et al ... + +* Make the program exit with 2 instead of 0 when decompression + fails due to a bad magic number (ie, an invalid bzip2 header). + Also exit with 1 (as the manual claims :-) whenever a diagnostic + message would have been printed AND the corresponding operation + is aborted, for example + bzip2: Output file xx already exists. + When a diagnostic message is printed but the operation is not + aborted, for example + bzip2: Can't guess original name for wurble -- using wurble.out + then the exit value 0 is returned, unless some other problem is + also detected. + + I think it corresponds more closely to what the manual claims now. + + +1.0.1 +~~~~~ +* Modified dlltest.c so it uses the new BZ2_ naming scheme. +* Modified makefile-msc to fix minor build probs on Win2k. +* Updated README.COMPILATION.PROBLEMS. + +There are no functionality changes or bug fixes relative to version +1.0.0. This is just a documentation update + a fix for minor Win32 +build problems. For almost everyone, upgrading from 1.0.0 to 1.0.1 is +utterly pointless. Don't bother. + + +1.0.2 +~~~~~ +A bug fix release, addressing various minor issues which have appeared +in the 18 or so months since 1.0.1 was released. Most of the fixes +are to do with file-handling or documentation bugs. To the best of my +knowledge, there have been no data-loss-causing bugs reported in the +compression/decompression engine of 1.0.0 or 1.0.1. + +Note that this release does not improve the rather crude build system +for Unix platforms. The general plan here is to autoconfiscate/ +libtoolise 1.0.2 soon after release, and release the result as 1.1.0 +or perhaps 1.2.0. That, however, is still just a plan at this point. + +Here are the changes in 1.0.2. Bug-reporters and/or patch-senders in +parentheses. + +* Fix an infinite segfault loop in 1.0.1 when a directory is + encountered in -f (force) mode. + (Trond Eivind Glomsrod, Nicholas Nethercote, Volker Schmidt) + +* Avoid double fclose() of output file on certain I/O error paths. + (Solar Designer) + +* Don't fail with internal error 1007 when fed a long stream (> 48MB) + of byte 251. Also print useful message suggesting that 1007s may be + caused by bad memory. + (noticed by Juan Pedro Vallejo, fixed by me) + +* Fix uninitialised variable silly bug in demo prog dlltest.c. + (Jorj Bauer) + +* Remove 512-MB limitation on recovered file size for bzip2recover + on selected platforms which support 64-bit ints. At the moment + all GCC supported platforms, and Win32. + (me, Alson van der Meulen) + +* Hard-code header byte values, to give correct operation on platforms + using EBCDIC as their native character set (IBM's OS/390). + (Leland Lucius) + +* Copy file access times correctly. + (Marty Leisner) + +* Add distclean and check targets to Makefile. + (Michael Carmack) + +* Parameterise use of ar and ranlib in Makefile. Also add $(LDFLAGS). + (Rich Ireland, Bo Thorsen) + +* Pass -p (create parent dirs as needed) to mkdir during make install. + (Jeremy Fusco) + +* Dereference symlinks when copying file permissions in -f mode. + (Volker Schmidt) + +* Majorly simplify implementation of uInt64_qrm10. + (Bo Lindbergh) + +* Check the input file still exists before deleting the output one, + when aborting in cleanUpAndFail(). + (Joerg Prante, Robert Linden, Matthias Krings) + +Also a bunch of patches courtesy of Philippe Troin, the Debian maintainer +of bzip2: + +* Wrapper scripts (with manpages): bzdiff, bzgrep, bzmore. + +* Spelling changes and minor enhancements in bzip2.1. + +* Avoid race condition between creating the output file and setting its + interim permissions safely, by using fopen_output_safely(). + No changes to bzip2recover since there is no issue with file + permissions there. + +* do not print senseless report with -v when compressing an empty + file. + +* bzcat -f works on non-bzip2 files. + +* do not try to escape shell meta-characters on unix (the shell takes + care of these). + +* added --fast and --best aliases for -1 -9 for gzip compatibility. + + +1.0.3 (15 Feb 05) +~~~~~~~~~~~~~~~~~ +Fixes some minor bugs since the last version, 1.0.2. + +* Further robustification against corrupted compressed data. + There are currently no known bitstreams which can cause the + decompressor to crash, loop or access memory which does not + belong to it. If you are using bzip2 or the library to + decompress bitstreams from untrusted sources, an upgrade + to 1.0.3 is recommended. This fixes CAN-2005-1260. + +* The documentation has been converted to XML, from which html + and pdf can be derived. + +* Various minor bugs in the documentation have been fixed. + +* Fixes for various compilation warnings with newer versions of + gcc, and on 64-bit platforms. + +* The BZ_NO_STDIO cpp symbol was not properly observed in 1.0.2. + This has been fixed. + + +1.0.4 (20 Dec 06) +~~~~~~~~~~~~~~~~~ +Fixes some minor bugs since the last version, 1.0.3. + +* Fix file permissions race problem (CAN-2005-0953). + +* Avoid possible segfault in BZ2_bzclose. From Coverity's NetBSD + scan. + +* 'const'/prototype cleanups in the C code. + +* Change default install location to /usr/local, and handle multiple + 'make install's without error. + +* Sanitise file names more carefully in bzgrep. Fixes CAN-2005-0758 + to the extent that applies to bzgrep. + +* Use 'mktemp' rather than 'tempfile' in bzdiff. + +* Tighten up a couple of assertions in blocksort.c following automated + analysis. + +* Fix minor doc/comment bugs. + + +1.0.5 (10 Dec 07) +~~~~~~~~~~~~~~~~~ +Security fix only. Fixes CERT-FI 20469 as it applies to bzip2. + + +1.0.6 (6 Sept 10) +~~~~~~~~~~~~~~~~~ + +* Security fix for CVE-2010-0405. This was reported by Mikolaj + Izdebski. + +* Make the documentation build on Ubuntu 10.04 diff --git a/source/Irrlicht/bzip2/LICENSE b/source/Irrlicht/bzip2/LICENSE new file mode 100644 index 00000000..cc614178 --- /dev/null +++ b/source/Irrlicht/bzip2/LICENSE @@ -0,0 +1,42 @@ + +-------------------------------------------------------------------------- + +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2010 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Julian Seward, jseward@bzip.org +bzip2/libbzip2 version 1.0.6 of 6 September 2010 + +-------------------------------------------------------------------------- diff --git a/source/Irrlicht/bzip2/Makefile b/source/Irrlicht/bzip2/Makefile new file mode 100644 index 00000000..9754ddf2 --- /dev/null +++ b/source/Irrlicht/bzip2/Makefile @@ -0,0 +1,217 @@ +# ------------------------------------------------------------------ +# This file is part of bzip2/libbzip2, a program and library for +# lossless, block-sorting data compression. +# +# bzip2/libbzip2 version 1.0.6 of 6 September 2010 +# Copyright (C) 1996-2010 Julian Seward +# +# Please read the WARNING, DISCLAIMER and PATENTS sections in the +# README file. +# +# This program is released under the terms of the license contained +# in the file LICENSE. +# ------------------------------------------------------------------ + +SHELL=/bin/sh + +# To assist in cross-compiling +CC=gcc +AR=ar +RANLIB=ranlib +LDFLAGS= + +BIGFILES=-D_FILE_OFFSET_BITS=64 +CFLAGS=-Wall -Winline -O2 -g $(BIGFILES) + +# Where you want it installed when you do 'make install' +PREFIX=/usr/local + + +OBJS= blocksort.o \ + huffman.o \ + crctable.o \ + randtable.o \ + compress.o \ + decompress.o \ + bzlib.o + +all: libbz2.a bzip2 bzip2recover test + +bzip2: libbz2.a bzip2.o + $(CC) $(CFLAGS) $(LDFLAGS) -o bzip2 bzip2.o -L. -lbz2 + +bzip2recover: bzip2recover.o + $(CC) $(CFLAGS) $(LDFLAGS) -o bzip2recover bzip2recover.o + +libbz2.a: $(OBJS) + rm -f libbz2.a + $(AR) cq libbz2.a $(OBJS) + @if ( test -f $(RANLIB) -o -f /usr/bin/ranlib -o \ + -f /bin/ranlib -o -f /usr/ccs/bin/ranlib ) ; then \ + echo $(RANLIB) libbz2.a ; \ + $(RANLIB) libbz2.a ; \ + fi + +check: test +test: bzip2 + @cat words1 + ./bzip2 -1 < sample1.ref > sample1.rb2 + ./bzip2 -2 < sample2.ref > sample2.rb2 + ./bzip2 -3 < sample3.ref > sample3.rb2 + ./bzip2 -d < sample1.bz2 > sample1.tst + ./bzip2 -d < sample2.bz2 > sample2.tst + ./bzip2 -ds < sample3.bz2 > sample3.tst + cmp sample1.bz2 sample1.rb2 + cmp sample2.bz2 sample2.rb2 + cmp sample3.bz2 sample3.rb2 + cmp sample1.tst sample1.ref + cmp sample2.tst sample2.ref + cmp sample3.tst sample3.ref + @cat words3 + +install: bzip2 bzip2recover + if ( test ! -d $(PREFIX)/bin ) ; then mkdir -p $(PREFIX)/bin ; fi + if ( test ! -d $(PREFIX)/lib ) ; then mkdir -p $(PREFIX)/lib ; fi + if ( test ! -d $(PREFIX)/man ) ; then mkdir -p $(PREFIX)/man ; fi + if ( test ! -d $(PREFIX)/man/man1 ) ; then mkdir -p $(PREFIX)/man/man1 ; fi + if ( test ! -d $(PREFIX)/include ) ; then mkdir -p $(PREFIX)/include ; fi + cp -f bzip2 $(PREFIX)/bin/bzip2 + cp -f bzip2 $(PREFIX)/bin/bunzip2 + cp -f bzip2 $(PREFIX)/bin/bzcat + cp -f bzip2recover $(PREFIX)/bin/bzip2recover + chmod a+x $(PREFIX)/bin/bzip2 + chmod a+x $(PREFIX)/bin/bunzip2 + chmod a+x $(PREFIX)/bin/bzcat + chmod a+x $(PREFIX)/bin/bzip2recover + cp -f bzip2.1 $(PREFIX)/man/man1 + chmod a+r $(PREFIX)/man/man1/bzip2.1 + cp -f bzlib.h $(PREFIX)/include + chmod a+r $(PREFIX)/include/bzlib.h + cp -f libbz2.a $(PREFIX)/lib + chmod a+r $(PREFIX)/lib/libbz2.a + cp -f bzgrep $(PREFIX)/bin/bzgrep + ln -s -f $(PREFIX)/bin/bzgrep $(PREFIX)/bin/bzegrep + ln -s -f $(PREFIX)/bin/bzgrep $(PREFIX)/bin/bzfgrep + chmod a+x $(PREFIX)/bin/bzgrep + cp -f bzmore $(PREFIX)/bin/bzmore + ln -s -f $(PREFIX)/bin/bzmore $(PREFIX)/bin/bzless + chmod a+x $(PREFIX)/bin/bzmore + cp -f bzdiff $(PREFIX)/bin/bzdiff + ln -s -f $(PREFIX)/bin/bzdiff $(PREFIX)/bin/bzcmp + chmod a+x $(PREFIX)/bin/bzdiff + cp -f bzgrep.1 bzmore.1 bzdiff.1 $(PREFIX)/man/man1 + chmod a+r $(PREFIX)/man/man1/bzgrep.1 + chmod a+r $(PREFIX)/man/man1/bzmore.1 + chmod a+r $(PREFIX)/man/man1/bzdiff.1 + echo ".so man1/bzgrep.1" > $(PREFIX)/man/man1/bzegrep.1 + echo ".so man1/bzgrep.1" > $(PREFIX)/man/man1/bzfgrep.1 + echo ".so man1/bzmore.1" > $(PREFIX)/man/man1/bzless.1 + echo ".so man1/bzdiff.1" > $(PREFIX)/man/man1/bzcmp.1 + +clean: + rm -f *.o libbz2.a bzip2 bzip2recover \ + sample1.rb2 sample2.rb2 sample3.rb2 \ + sample1.tst sample2.tst sample3.tst + +blocksort.o: blocksort.c + @cat words0 + $(CC) $(CFLAGS) -c blocksort.c +huffman.o: huffman.c + $(CC) $(CFLAGS) -c huffman.c +crctable.o: crctable.c + $(CC) $(CFLAGS) -c crctable.c +randtable.o: randtable.c + $(CC) $(CFLAGS) -c randtable.c +compress.o: compress.c + $(CC) $(CFLAGS) -c compress.c +decompress.o: decompress.c + $(CC) $(CFLAGS) -c decompress.c +bzlib.o: bzlib.c + $(CC) $(CFLAGS) -c bzlib.c +bzip2.o: bzip2.c + $(CC) $(CFLAGS) -c bzip2.c +bzip2recover.o: bzip2recover.c + $(CC) $(CFLAGS) -c bzip2recover.c + + +distclean: clean + rm -f manual.ps manual.html manual.pdf + +DISTNAME=bzip2-1.0.6 +dist: check manual + rm -f $(DISTNAME) + ln -s -f . $(DISTNAME) + tar cvf $(DISTNAME).tar \ + $(DISTNAME)/blocksort.c \ + $(DISTNAME)/huffman.c \ + $(DISTNAME)/crctable.c \ + $(DISTNAME)/randtable.c \ + $(DISTNAME)/compress.c \ + $(DISTNAME)/decompress.c \ + $(DISTNAME)/bzlib.c \ + $(DISTNAME)/bzip2.c \ + $(DISTNAME)/bzip2recover.c \ + $(DISTNAME)/bzlib.h \ + $(DISTNAME)/bzlib_private.h \ + $(DISTNAME)/Makefile \ + $(DISTNAME)/LICENSE \ + $(DISTNAME)/bzip2.1 \ + $(DISTNAME)/bzip2.1.preformatted \ + $(DISTNAME)/bzip2.txt \ + $(DISTNAME)/words0 \ + $(DISTNAME)/words1 \ + $(DISTNAME)/words2 \ + $(DISTNAME)/words3 \ + $(DISTNAME)/sample1.ref \ + $(DISTNAME)/sample2.ref \ + $(DISTNAME)/sample3.ref \ + $(DISTNAME)/sample1.bz2 \ + $(DISTNAME)/sample2.bz2 \ + $(DISTNAME)/sample3.bz2 \ + $(DISTNAME)/dlltest.c \ + $(DISTNAME)/manual.html \ + $(DISTNAME)/manual.pdf \ + $(DISTNAME)/manual.ps \ + $(DISTNAME)/README \ + $(DISTNAME)/README.COMPILATION.PROBLEMS \ + $(DISTNAME)/README.XML.STUFF \ + $(DISTNAME)/CHANGES \ + $(DISTNAME)/libbz2.def \ + $(DISTNAME)/libbz2.dsp \ + $(DISTNAME)/dlltest.dsp \ + $(DISTNAME)/makefile.msc \ + $(DISTNAME)/unzcrash.c \ + $(DISTNAME)/spewG.c \ + $(DISTNAME)/mk251.c \ + $(DISTNAME)/bzdiff \ + $(DISTNAME)/bzdiff.1 \ + $(DISTNAME)/bzmore \ + $(DISTNAME)/bzmore.1 \ + $(DISTNAME)/bzgrep \ + $(DISTNAME)/bzgrep.1 \ + $(DISTNAME)/Makefile-libbz2_so \ + $(DISTNAME)/bz-common.xsl \ + $(DISTNAME)/bz-fo.xsl \ + $(DISTNAME)/bz-html.xsl \ + $(DISTNAME)/bzip.css \ + $(DISTNAME)/entities.xml \ + $(DISTNAME)/manual.xml \ + $(DISTNAME)/format.pl \ + $(DISTNAME)/xmlproc.sh + gzip -v $(DISTNAME).tar + +# For rebuilding the manual from sources on my SuSE 9.1 box + +MANUAL_SRCS= bz-common.xsl bz-fo.xsl bz-html.xsl bzip.css \ + entities.xml manual.xml + +manual: manual.html manual.ps manual.pdf + +manual.ps: $(MANUAL_SRCS) + ./xmlproc.sh -ps manual.xml + +manual.pdf: $(MANUAL_SRCS) + ./xmlproc.sh -pdf manual.xml + +manual.html: $(MANUAL_SRCS) + ./xmlproc.sh -html manual.xml diff --git a/source/Irrlicht/bzip2/Makefile-libbz2_so b/source/Irrlicht/bzip2/Makefile-libbz2_so new file mode 100644 index 00000000..e58791b3 --- /dev/null +++ b/source/Irrlicht/bzip2/Makefile-libbz2_so @@ -0,0 +1,59 @@ + +# This Makefile builds a shared version of the library, +# libbz2.so.1.0.6, with soname libbz2.so.1.0, +# at least on x86-Linux (RedHat 7.2), +# with gcc-2.96 20000731 (Red Hat Linux 7.1 2.96-98). +# Please see the README file for some important info +# about building the library like this. + +# ------------------------------------------------------------------ +# This file is part of bzip2/libbzip2, a program and library for +# lossless, block-sorting data compression. +# +# bzip2/libbzip2 version 1.0.6 of 6 September 2010 +# Copyright (C) 1996-2010 Julian Seward +# +# Please read the WARNING, DISCLAIMER and PATENTS sections in the +# README file. +# +# This program is released under the terms of the license contained +# in the file LICENSE. +# ------------------------------------------------------------------ + + +SHELL=/bin/sh +CC=gcc +BIGFILES=-D_FILE_OFFSET_BITS=64 +CFLAGS=-fpic -fPIC -Wall -Winline -O2 -g $(BIGFILES) + +OBJS= blocksort.o \ + huffman.o \ + crctable.o \ + randtable.o \ + compress.o \ + decompress.o \ + bzlib.o + +all: $(OBJS) + $(CC) -shared -Wl,-soname -Wl,libbz2.so.1.0 -o libbz2.so.1.0.6 $(OBJS) + $(CC) $(CFLAGS) -o bzip2-shared bzip2.c libbz2.so.1.0.6 + rm -f libbz2.so.1.0 + ln -s libbz2.so.1.0.6 libbz2.so.1.0 + +clean: + rm -f $(OBJS) bzip2.o libbz2.so.1.0.6 libbz2.so.1.0 bzip2-shared + +blocksort.o: blocksort.c + $(CC) $(CFLAGS) -c blocksort.c +huffman.o: huffman.c + $(CC) $(CFLAGS) -c huffman.c +crctable.o: crctable.c + $(CC) $(CFLAGS) -c crctable.c +randtable.o: randtable.c + $(CC) $(CFLAGS) -c randtable.c +compress.o: compress.c + $(CC) $(CFLAGS) -c compress.c +decompress.o: decompress.c + $(CC) $(CFLAGS) -c decompress.c +bzlib.o: bzlib.c + $(CC) $(CFLAGS) -c bzlib.c diff --git a/source/Irrlicht/bzip2/README b/source/Irrlicht/bzip2/README new file mode 100644 index 00000000..9fb0f636 --- /dev/null +++ b/source/Irrlicht/bzip2/README @@ -0,0 +1,215 @@ + +This is the README for bzip2/libzip2. +This version is fully compatible with the previous public releases. + +------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.6 of 6 September 2010 +Copyright (C) 1996-2010 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in this file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ + +Complete documentation is available in Postscript form (manual.ps), +PDF (manual.pdf) or html (manual.html). A plain-text version of the +manual page is available as bzip2.txt. + + +HOW TO BUILD -- UNIX + +Type 'make'. This builds the library libbz2.a and then the programs +bzip2 and bzip2recover. Six self-tests are run. If the self-tests +complete ok, carry on to installation: + +To install in /usr/local/bin, /usr/local/lib, /usr/local/man and +/usr/local/include, type + + make install + +To install somewhere else, eg, /xxx/yyy/{bin,lib,man,include}, type + + make install PREFIX=/xxx/yyy + +If you are (justifiably) paranoid and want to see what 'make install' +is going to do, you can first do + + make -n install or + make -n install PREFIX=/xxx/yyy respectively. + +The -n instructs make to show the commands it would execute, but not +actually execute them. + + +HOW TO BUILD -- UNIX, shared library libbz2.so. + +Do 'make -f Makefile-libbz2_so'. This Makefile seems to work for +Linux-ELF (RedHat 7.2 on an x86 box), with gcc. I make no claims +that it works for any other platform, though I suspect it probably +will work for most platforms employing both ELF and gcc. + +bzip2-shared, a client of the shared library, is also built, but not +self-tested. So I suggest you also build using the normal Makefile, +since that conducts a self-test. A second reason to prefer the +version statically linked to the library is that, on x86 platforms, +building shared objects makes a valuable register (%ebx) unavailable +to gcc, resulting in a slowdown of 10%-20%, at least for bzip2. + +Important note for people upgrading .so's from 0.9.0/0.9.5 to version +1.0.X. All the functions in the library have been renamed, from (eg) +bzCompress to BZ2_bzCompress, to avoid namespace pollution. +Unfortunately this means that the libbz2.so created by +Makefile-libbz2_so will not work with any program which used an older +version of the library. I do encourage library clients to make the +effort to upgrade to use version 1.0, since it is both faster and more +robust than previous versions. + + +HOW TO BUILD -- Windows 95, NT, DOS, Mac, etc. + +It's difficult for me to support compilation on all these platforms. +My approach is to collect binaries for these platforms, and put them +on the master web site (http://www.bzip.org). Look there. However +(FWIW), bzip2-1.0.X is very standard ANSI C and should compile +unmodified with MS Visual C. If you have difficulties building, you +might want to read README.COMPILATION.PROBLEMS. + +At least using MS Visual C++ 6, you can build from the unmodified +sources by issuing, in a command shell: + + nmake -f makefile.msc + +(you may need to first run the MSVC-provided script VCVARS32.BAT + so as to set up paths to the MSVC tools correctly). + + +VALIDATION + +Correct operation, in the sense that a compressed file can always be +decompressed to reproduce the original, is obviously of paramount +importance. To validate bzip2, I used a modified version of Mark +Nelson's churn program. Churn is an automated test driver which +recursively traverses a directory structure, using bzip2 to compress +and then decompress each file it encounters, and checking that the +decompressed data is the same as the original. + + + +Please read and be aware of the following: + +WARNING: + + This program and library (attempts to) compress data by + performing several non-trivial transformations on it. + Unless you are 100% familiar with *all* the algorithms + contained herein, and with the consequences of modifying them, + you should NOT meddle with the compression or decompression + machinery. Incorrect changes can and very likely *will* + lead to disastrous loss of data. + + +DISCLAIMER: + + I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE + USE OF THIS PROGRAM/LIBRARY, HOWSOEVER CAUSED. + + Every compression of a file implies an assumption that the + compressed file can be decompressed to reproduce the original. + Great efforts in design, coding and testing have been made to + ensure that this program works correctly. However, the complexity + of the algorithms, and, in particular, the presence of various + special cases in the code which occur with very low but non-zero + probability make it impossible to rule out the possibility of bugs + remaining in the program. DO NOT COMPRESS ANY DATA WITH THIS + PROGRAM UNLESS YOU ARE PREPARED TO ACCEPT THE POSSIBILITY, HOWEVER + SMALL, THAT THE DATA WILL NOT BE RECOVERABLE. + + That is not to say this program is inherently unreliable. + Indeed, I very much hope the opposite is true. bzip2/libbzip2 + has been carefully constructed and extensively tested. + + +PATENTS: + + To the best of my knowledge, bzip2/libbzip2 does not use any + patented algorithms. However, I do not have the resources + to carry out a patent search. Therefore I cannot give any + guarantee of the above statement. + + + +WHAT'S NEW IN 0.9.0 (as compared to 0.1pl2) ? + + * Approx 10% faster compression, 30% faster decompression + * -t (test mode) is a lot quicker + * Can decompress concatenated compressed files + * Programming interface, so programs can directly read/write .bz2 files + * Less restrictive (BSD-style) licensing + * Flag handling more compatible with GNU gzip + * Much more documentation, i.e., a proper user manual + * Hopefully, improved portability (at least of the library) + +WHAT'S NEW IN 0.9.5 ? + + * Compression speed is much less sensitive to the input + data than in previous versions. Specifically, the very + slow performance caused by repetitive data is fixed. + * Many small improvements in file and flag handling. + * A Y2K statement. + +WHAT'S NEW IN 1.0.0 ? + + See the CHANGES file. + +WHAT'S NEW IN 1.0.2 ? + + See the CHANGES file. + +WHAT'S NEW IN 1.0.3 ? + + See the CHANGES file. + +WHAT'S NEW IN 1.0.4 ? + + See the CHANGES file. + +WHAT'S NEW IN 1.0.5 ? + + See the CHANGES file. + +WHAT'S NEW IN 1.0.6 ? + + See the CHANGES file. + + +I hope you find bzip2 useful. Feel free to contact me at + jseward@bzip.org +if you have any suggestions or queries. Many people mailed me with +comments, suggestions and patches after the releases of bzip-0.15, +bzip-0.21, and bzip2 versions 0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1, +1.0.2 and 1.0.3, and the changes in bzip2 are largely a result of this +feedback. I thank you for your comments. + +bzip2's "home" is http://www.bzip.org/ + +Julian Seward +jseward@bzip.org +Cambridge, UK. + +18 July 1996 (version 0.15) +25 August 1996 (version 0.21) + 7 August 1997 (bzip2, version 0.1) +29 August 1997 (bzip2, version 0.1pl2) +23 August 1998 (bzip2, version 0.9.0) + 8 June 1999 (bzip2, version 0.9.5) + 4 Sept 1999 (bzip2, version 0.9.5d) + 5 May 2000 (bzip2, version 1.0pre8) +30 December 2001 (bzip2, version 1.0.2pre1) +15 February 2005 (bzip2, version 1.0.3) +20 December 2006 (bzip2, version 1.0.4) +10 December 2007 (bzip2, version 1.0.5) + 6 Sept 2010 (bzip2, version 1.0.6) diff --git a/source/Irrlicht/bzip2/README.COMPILATION.PROBLEMS b/source/Irrlicht/bzip2/README.COMPILATION.PROBLEMS new file mode 100644 index 00000000..667d0d6d --- /dev/null +++ b/source/Irrlicht/bzip2/README.COMPILATION.PROBLEMS @@ -0,0 +1,58 @@ +------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.6 of 6 September 2010 +Copyright (C) 1996-2010 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in the +README file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ + +bzip2-1.0.6 should compile without problems on the vast majority of +platforms. Using the supplied Makefile, I've built and tested it +myself for x86-linux and amd64-linux. With makefile.msc, Visual C++ +6.0 and nmake, you can build a native Win32 version too. Large file +support seems to work correctly on at least on amd64-linux. + +When I say "large file" I mean a file of size 2,147,483,648 (2^31) +bytes or above. Many older OSs can't handle files above this size, +but many newer ones can. Large files are pretty huge -- most files +you'll encounter are not Large Files. + +Early versions of bzip2 (0.1, 0.9.0, 0.9.5) compiled on a wide variety +of platforms without difficulty, and I hope this version will continue +in that tradition. However, in order to support large files, I've had +to include the define -D_FILE_OFFSET_BITS=64 in the Makefile. This +can cause problems. + +The technique of adding -D_FILE_OFFSET_BITS=64 to get large file +support is, as far as I know, the Recommended Way to get correct large +file support. For more details, see the Large File Support +Specification, published by the Large File Summit, at + + http://ftp.sas.com/standards/large.file + +As a general comment, if you get compilation errors which you think +are related to large file support, try removing the above define from +the Makefile, ie, delete the line + + BIGFILES=-D_FILE_OFFSET_BITS=64 + +from the Makefile, and do 'make clean ; make'. This will give you a +version of bzip2 without large file support, which, for most +applications, is probably not a problem. + +Alternatively, try some of the platform-specific hints listed below. + +You can use the spewG.c program to generate huge files to test bzip2's +large file support, if you are feeling paranoid. Be aware though that +any compilation problems which affect bzip2 will also affect spewG.c, +alas. + +AIX: I have reports that for large file support, you need to specify +-D_LARGE_FILES rather than -D_FILE_OFFSET_BITS=64. I have not tested +this myself. diff --git a/source/Irrlicht/bzip2/README.XML.STUFF b/source/Irrlicht/bzip2/README.XML.STUFF new file mode 100644 index 00000000..3a57f3fa --- /dev/null +++ b/source/Irrlicht/bzip2/README.XML.STUFF @@ -0,0 +1,45 @@ + ---------------------------------------------------------------- + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ---------------------------------------------------------------- + +The script xmlproc.sh takes an xml file as input, +and processes it to create .pdf, .html or .ps output. +It uses format.pl, a perl script to format
 blocks nicely,
+ and add CDATA tags so writers do not have to use eg. < 
+
+The file "entities.xml" must be edited to reflect current
+version, year, etc.
+
+
+Usage:
+
+  ./xmlproc.sh -v manual.xml
+  Validates an xml file to ensure no dtd-compliance errors
+
+  ./xmlproc.sh -html manual.xml
+  Output: manual.html
+
+  ./xmlproc.sh -pdf manual.xml
+  Output: manual.pdf
+
+  ./xmlproc.sh -ps manual.xml
+  Output: manual.ps
+
+
+Notum bene: 
+- pdfxmltex barfs if given a filename with an underscore in it
+
+- xmltex won't work yet - there's a bug in passivetex
+    which we are all waiting for Sebastian to fix.
+  So we are going the xml -> pdf -> ps route for the time being,
+    using pdfxmltex.
diff --git a/source/Irrlicht/bzip2/blocksort.c b/source/Irrlicht/bzip2/blocksort.c
new file mode 100644
index 00000000..d0d662cd
--- /dev/null
+++ b/source/Irrlicht/bzip2/blocksort.c
@@ -0,0 +1,1094 @@
+
+/*-------------------------------------------------------------*/
+/*--- Block sorting machinery                               ---*/
+/*---                                           blocksort.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+/*---------------------------------------------*/
+/*--- Fallback O(N log(N)^2) sorting        ---*/
+/*--- algorithm, for repetitive blocks      ---*/
+/*---------------------------------------------*/
+
+/*---------------------------------------------*/
+static 
+__inline__
+void fallbackSimpleSort ( UInt32* fmap, 
+                          UInt32* eclass, 
+                          Int32   lo, 
+                          Int32   hi )
+{
+   Int32 i, j, tmp;
+   UInt32 ec_tmp;
+
+   if (lo == hi) return;
+
+   if (hi - lo > 3) {
+      for ( i = hi-4; i >= lo; i-- ) {
+         tmp = fmap[i];
+         ec_tmp = eclass[tmp];
+         for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 )
+            fmap[j-4] = fmap[j];
+         fmap[j-4] = tmp;
+      }
+   }
+
+   for ( i = hi-1; i >= lo; i-- ) {
+      tmp = fmap[i];
+      ec_tmp = eclass[tmp];
+      for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ )
+         fmap[j-1] = fmap[j];
+      fmap[j-1] = tmp;
+   }
+}
+
+
+/*---------------------------------------------*/
+#define fswap(zz1, zz2) \
+   { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; }
+
+#define fvswap(zzp1, zzp2, zzn)       \
+{                                     \
+   Int32 yyp1 = (zzp1);               \
+   Int32 yyp2 = (zzp2);               \
+   Int32 yyn  = (zzn);                \
+   while (yyn > 0) {                  \
+      fswap(fmap[yyp1], fmap[yyp2]);  \
+      yyp1++; yyp2++; yyn--;          \
+   }                                  \
+}
+
+
+#define fmin(a,b) ((a) < (b)) ? (a) : (b)
+
+#define fpush(lz,hz) { stackLo[sp] = lz; \
+                       stackHi[sp] = hz; \
+                       sp++; }
+
+#define fpop(lz,hz) { sp--;              \
+                      lz = stackLo[sp];  \
+                      hz = stackHi[sp]; }
+
+#define FALLBACK_QSORT_SMALL_THRESH 10
+#define FALLBACK_QSORT_STACK_SIZE   100
+
+
+static
+void fallbackQSort3 ( UInt32* fmap, 
+                      UInt32* eclass,
+                      Int32   loSt, 
+                      Int32   hiSt )
+{
+   Int32 unLo, unHi, ltLo, gtHi, n, m;
+   Int32 sp, lo, hi;
+   UInt32 med, r, r3;
+   Int32 stackLo[FALLBACK_QSORT_STACK_SIZE];
+   Int32 stackHi[FALLBACK_QSORT_STACK_SIZE];
+
+   r = 0;
+
+   sp = 0;
+   fpush ( loSt, hiSt );
+
+   while (sp > 0) {
+
+      AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 );
+
+      fpop ( lo, hi );
+      if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) {
+         fallbackSimpleSort ( fmap, eclass, lo, hi );
+         continue;
+      }
+
+      /* Random partitioning.  Median of 3 sometimes fails to
+         avoid bad cases.  Median of 9 seems to help but 
+         looks rather expensive.  This too seems to work but
+         is cheaper.  Guidance for the magic constants 
+         7621 and 32768 is taken from Sedgewick's algorithms
+         book, chapter 35.
+      */
+      r = ((r * 7621) + 1) % 32768;
+      r3 = r % 3;
+      if (r3 == 0) med = eclass[fmap[lo]]; else
+      if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else
+                   med = eclass[fmap[hi]];
+
+      unLo = ltLo = lo;
+      unHi = gtHi = hi;
+
+      while (1) {
+         while (1) {
+            if (unLo > unHi) break;
+            n = (Int32)eclass[fmap[unLo]] - (Int32)med;
+            if (n == 0) { 
+               fswap(fmap[unLo], fmap[ltLo]); 
+               ltLo++; unLo++; 
+               continue; 
+            };
+            if (n > 0) break;
+            unLo++;
+         }
+         while (1) {
+            if (unLo > unHi) break;
+            n = (Int32)eclass[fmap[unHi]] - (Int32)med;
+            if (n == 0) { 
+               fswap(fmap[unHi], fmap[gtHi]); 
+               gtHi--; unHi--; 
+               continue; 
+            };
+            if (n < 0) break;
+            unHi--;
+         }
+         if (unLo > unHi) break;
+         fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--;
+      }
+
+      AssertD ( unHi == unLo-1, "fallbackQSort3(2)" );
+
+      if (gtHi < ltLo) continue;
+
+      n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n);
+      m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m);
+
+      n = lo + unLo - ltLo - 1;
+      m = hi - (gtHi - unHi) + 1;
+
+      if (n - lo > hi - m) {
+         fpush ( lo, n );
+         fpush ( m, hi );
+      } else {
+         fpush ( m, hi );
+         fpush ( lo, n );
+      }
+   }
+}
+
+#undef fmin
+#undef fpush
+#undef fpop
+#undef fswap
+#undef fvswap
+#undef FALLBACK_QSORT_SMALL_THRESH
+#undef FALLBACK_QSORT_STACK_SIZE
+
+
+/*---------------------------------------------*/
+/* Pre:
+      nblock > 0
+      eclass exists for [0 .. nblock-1]
+      ((UChar*)eclass) [0 .. nblock-1] holds block
+      ptr exists for [0 .. nblock-1]
+
+   Post:
+      ((UChar*)eclass) [0 .. nblock-1] holds block
+      All other areas of eclass destroyed
+      fmap [0 .. nblock-1] holds sorted order
+      bhtab [ 0 .. 2+(nblock/32) ] destroyed
+*/
+
+#define       SET_BH(zz)  bhtab[(zz) >> 5] |= (1 << ((zz) & 31))
+#define     CLEAR_BH(zz)  bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31))
+#define     ISSET_BH(zz)  (bhtab[(zz) >> 5] & (1 << ((zz) & 31)))
+#define      WORD_BH(zz)  bhtab[(zz) >> 5]
+#define UNALIGNED_BH(zz)  ((zz) & 0x01f)
+
+static
+void fallbackSort ( UInt32* fmap, 
+                    UInt32* eclass, 
+                    UInt32* bhtab,
+                    Int32   nblock,
+                    Int32   verb )
+{
+   Int32 ftab[257];
+   Int32 ftabCopy[256];
+   Int32 H, i, j, k, l, r, cc, cc1;
+   Int32 nNotDone;
+   Int32 nBhtab;
+   UChar* eclass8 = (UChar*)eclass;
+
+   /*--
+      Initial 1-char radix sort to generate
+      initial fmap and initial BH bits.
+   --*/
+   if (verb >= 4)
+      VPrintf0 ( "        bucket sorting ...\n" );
+   for (i = 0; i < 257;    i++) ftab[i] = 0;
+   for (i = 0; i < nblock; i++) ftab[eclass8[i]]++;
+   for (i = 0; i < 256;    i++) ftabCopy[i] = ftab[i];
+   for (i = 1; i < 257;    i++) ftab[i] += ftab[i-1];
+
+   for (i = 0; i < nblock; i++) {
+      j = eclass8[i];
+      k = ftab[j] - 1;
+      ftab[j] = k;
+      fmap[k] = i;
+   }
+
+   nBhtab = 2 + (nblock / 32);
+   for (i = 0; i < nBhtab; i++) bhtab[i] = 0;
+   for (i = 0; i < 256; i++) SET_BH(ftab[i]);
+
+   /*--
+      Inductively refine the buckets.  Kind-of an
+      "exponential radix sort" (!), inspired by the
+      Manber-Myers suffix array construction algorithm.
+   --*/
+
+   /*-- set sentinel bits for block-end detection --*/
+   for (i = 0; i < 32; i++) { 
+      SET_BH(nblock + 2*i);
+      CLEAR_BH(nblock + 2*i + 1);
+   }
+
+   /*-- the log(N) loop --*/
+   H = 1;
+   while (1) {
+
+      if (verb >= 4) 
+         VPrintf1 ( "        depth %6d has ", H );
+
+      j = 0;
+      for (i = 0; i < nblock; i++) {
+         if (ISSET_BH(i)) j = i;
+         k = fmap[i] - H; if (k < 0) k += nblock;
+         eclass[k] = j;
+      }
+
+      nNotDone = 0;
+      r = -1;
+      while (1) {
+
+	 /*-- find the next non-singleton bucket --*/
+         k = r + 1;
+         while (ISSET_BH(k) && UNALIGNED_BH(k)) k++;
+         if (ISSET_BH(k)) {
+            while (WORD_BH(k) == 0xffffffff) k += 32;
+            while (ISSET_BH(k)) k++;
+         }
+         l = k - 1;
+         if (l >= nblock) break;
+         while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++;
+         if (!ISSET_BH(k)) {
+            while (WORD_BH(k) == 0x00000000) k += 32;
+            while (!ISSET_BH(k)) k++;
+         }
+         r = k - 1;
+         if (r >= nblock) break;
+
+         /*-- now [l, r] bracket current bucket --*/
+         if (r > l) {
+            nNotDone += (r - l + 1);
+            fallbackQSort3 ( fmap, eclass, l, r );
+
+            /*-- scan bucket and generate header bits-- */
+            cc = -1;
+            for (i = l; i <= r; i++) {
+               cc1 = eclass[fmap[i]];
+               if (cc != cc1) { SET_BH(i); cc = cc1; };
+            }
+         }
+      }
+
+      if (verb >= 4) 
+         VPrintf1 ( "%6d unresolved strings\n", nNotDone );
+
+      H *= 2;
+      if (H > nblock || nNotDone == 0) break;
+   }
+
+   /*-- 
+      Reconstruct the original block in
+      eclass8 [0 .. nblock-1], since the
+      previous phase destroyed it.
+   --*/
+   if (verb >= 4)
+      VPrintf0 ( "        reconstructing block ...\n" );
+   j = 0;
+   for (i = 0; i < nblock; i++) {
+      while (ftabCopy[j] == 0) j++;
+      ftabCopy[j]--;
+      eclass8[fmap[i]] = (UChar)j;
+   }
+   AssertH ( j < 256, 1005 );
+}
+
+#undef       SET_BH
+#undef     CLEAR_BH
+#undef     ISSET_BH
+#undef      WORD_BH
+#undef UNALIGNED_BH
+
+
+/*---------------------------------------------*/
+/*--- The main, O(N^2 log(N)) sorting       ---*/
+/*--- algorithm.  Faster for "normal"       ---*/
+/*--- non-repetitive blocks.                ---*/
+/*---------------------------------------------*/
+
+/*---------------------------------------------*/
+static
+__inline__
+Bool mainGtU ( UInt32  i1, 
+               UInt32  i2,
+               UChar*  block, 
+               UInt16* quadrant,
+               UInt32  nblock,
+               Int32*  budget )
+{
+   Int32  k;
+   UChar  c1, c2;
+   UInt16 s1, s2;
+
+   AssertD ( i1 != i2, "mainGtU" );
+   /* 1 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 2 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 3 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 4 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 5 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 6 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 7 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 8 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 9 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 10 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 11 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 12 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+
+   k = nblock + 8;
+
+   do {
+      /* 1 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 2 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 3 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 4 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 5 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 6 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 7 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 8 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+
+      if (i1 >= nblock) i1 -= nblock;
+      if (i2 >= nblock) i2 -= nblock;
+
+      k -= 8;
+      (*budget)--;
+   }
+      while (k >= 0);
+
+   return False;
+}
+
+
+/*---------------------------------------------*/
+/*--
+   Knuth's increments seem to work better
+   than Incerpi-Sedgewick here.  Possibly
+   because the number of elems to sort is
+   usually small, typically <= 20.
+--*/
+static
+Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280,
+                   9841, 29524, 88573, 265720,
+                   797161, 2391484 };
+
+static
+void mainSimpleSort ( UInt32* ptr,
+                      UChar*  block,
+                      UInt16* quadrant,
+                      Int32   nblock,
+                      Int32   lo, 
+                      Int32   hi, 
+                      Int32   d,
+                      Int32*  budget )
+{
+   Int32 i, j, h, bigN, hp;
+   UInt32 v;
+
+   bigN = hi - lo + 1;
+   if (bigN < 2) return;
+
+   hp = 0;
+   while (incs[hp] < bigN) hp++;
+   hp--;
+
+   for (; hp >= 0; hp--) {
+      h = incs[hp];
+
+      i = lo + h;
+      while (True) {
+
+         /*-- copy 1 --*/
+         if (i > hi) break;
+         v = ptr[i];
+         j = i;
+         while ( mainGtU ( 
+                    ptr[j-h]+d, v+d, block, quadrant, nblock, budget 
+                 ) ) {
+            ptr[j] = ptr[j-h];
+            j = j - h;
+            if (j <= (lo + h - 1)) break;
+         }
+         ptr[j] = v;
+         i++;
+
+         /*-- copy 2 --*/
+         if (i > hi) break;
+         v = ptr[i];
+         j = i;
+         while ( mainGtU ( 
+                    ptr[j-h]+d, v+d, block, quadrant, nblock, budget 
+                 ) ) {
+            ptr[j] = ptr[j-h];
+            j = j - h;
+            if (j <= (lo + h - 1)) break;
+         }
+         ptr[j] = v;
+         i++;
+
+         /*-- copy 3 --*/
+         if (i > hi) break;
+         v = ptr[i];
+         j = i;
+         while ( mainGtU ( 
+                    ptr[j-h]+d, v+d, block, quadrant, nblock, budget 
+                 ) ) {
+            ptr[j] = ptr[j-h];
+            j = j - h;
+            if (j <= (lo + h - 1)) break;
+         }
+         ptr[j] = v;
+         i++;
+
+         if (*budget < 0) return;
+      }
+   }
+}
+
+
+/*---------------------------------------------*/
+/*--
+   The following is an implementation of
+   an elegant 3-way quicksort for strings,
+   described in a paper "Fast Algorithms for
+   Sorting and Searching Strings", by Robert
+   Sedgewick and Jon L. Bentley.
+--*/
+
+#define mswap(zz1, zz2) \
+   { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; }
+
+#define mvswap(zzp1, zzp2, zzn)       \
+{                                     \
+   Int32 yyp1 = (zzp1);               \
+   Int32 yyp2 = (zzp2);               \
+   Int32 yyn  = (zzn);                \
+   while (yyn > 0) {                  \
+      mswap(ptr[yyp1], ptr[yyp2]);    \
+      yyp1++; yyp2++; yyn--;          \
+   }                                  \
+}
+
+static 
+__inline__
+UChar mmed3 ( UChar a, UChar b, UChar c )
+{
+   UChar t;
+   if (a > b) { t = a; a = b; b = t; };
+   if (b > c) { 
+      b = c;
+      if (a > b) b = a;
+   }
+   return b;
+}
+
+#define mmin(a,b) ((a) < (b)) ? (a) : (b)
+
+#define mpush(lz,hz,dz) { stackLo[sp] = lz; \
+                          stackHi[sp] = hz; \
+                          stackD [sp] = dz; \
+                          sp++; }
+
+#define mpop(lz,hz,dz) { sp--;             \
+                         lz = stackLo[sp]; \
+                         hz = stackHi[sp]; \
+                         dz = stackD [sp]; }
+
+
+#define mnextsize(az) (nextHi[az]-nextLo[az])
+
+#define mnextswap(az,bz)                                        \
+   { Int32 tz;                                                  \
+     tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \
+     tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \
+     tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; }
+
+
+#define MAIN_QSORT_SMALL_THRESH 20
+#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT)
+#define MAIN_QSORT_STACK_SIZE 100
+
+static
+void mainQSort3 ( UInt32* ptr,
+                  UChar*  block,
+                  UInt16* quadrant,
+                  Int32   nblock,
+                  Int32   loSt, 
+                  Int32   hiSt, 
+                  Int32   dSt,
+                  Int32*  budget )
+{
+   Int32 unLo, unHi, ltLo, gtHi, n, m, med;
+   Int32 sp, lo, hi, d;
+
+   Int32 stackLo[MAIN_QSORT_STACK_SIZE];
+   Int32 stackHi[MAIN_QSORT_STACK_SIZE];
+   Int32 stackD [MAIN_QSORT_STACK_SIZE];
+
+   Int32 nextLo[3];
+   Int32 nextHi[3];
+   Int32 nextD [3];
+
+   sp = 0;
+   mpush ( loSt, hiSt, dSt );
+
+   while (sp > 0) {
+
+      AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 );
+
+      mpop ( lo, hi, d );
+      if (hi - lo < MAIN_QSORT_SMALL_THRESH || 
+          d > MAIN_QSORT_DEPTH_THRESH) {
+         mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget );
+         if (*budget < 0) return;
+         continue;
+      }
+
+      med = (Int32) 
+            mmed3 ( block[ptr[ lo         ]+d],
+                    block[ptr[ hi         ]+d],
+                    block[ptr[ (lo+hi)>>1 ]+d] );
+
+      unLo = ltLo = lo;
+      unHi = gtHi = hi;
+
+      while (True) {
+         while (True) {
+            if (unLo > unHi) break;
+            n = ((Int32)block[ptr[unLo]+d]) - med;
+            if (n == 0) { 
+               mswap(ptr[unLo], ptr[ltLo]); 
+               ltLo++; unLo++; continue; 
+            };
+            if (n >  0) break;
+            unLo++;
+         }
+         while (True) {
+            if (unLo > unHi) break;
+            n = ((Int32)block[ptr[unHi]+d]) - med;
+            if (n == 0) { 
+               mswap(ptr[unHi], ptr[gtHi]); 
+               gtHi--; unHi--; continue; 
+            };
+            if (n <  0) break;
+            unHi--;
+         }
+         if (unLo > unHi) break;
+         mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--;
+      }
+
+      AssertD ( unHi == unLo-1, "mainQSort3(2)" );
+
+      if (gtHi < ltLo) {
+         mpush(lo, hi, d+1 );
+         continue;
+      }
+
+      n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n);
+      m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m);
+
+      n = lo + unLo - ltLo - 1;
+      m = hi - (gtHi - unHi) + 1;
+
+      nextLo[0] = lo;  nextHi[0] = n;   nextD[0] = d;
+      nextLo[1] = m;   nextHi[1] = hi;  nextD[1] = d;
+      nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1;
+
+      if (mnextsize(0) < mnextsize(1)) mnextswap(0,1);
+      if (mnextsize(1) < mnextsize(2)) mnextswap(1,2);
+      if (mnextsize(0) < mnextsize(1)) mnextswap(0,1);
+
+      AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" );
+      AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" );
+
+      mpush (nextLo[0], nextHi[0], nextD[0]);
+      mpush (nextLo[1], nextHi[1], nextD[1]);
+      mpush (nextLo[2], nextHi[2], nextD[2]);
+   }
+}
+
+#undef mswap
+#undef mvswap
+#undef mpush
+#undef mpop
+#undef mmin
+#undef mnextsize
+#undef mnextswap
+#undef MAIN_QSORT_SMALL_THRESH
+#undef MAIN_QSORT_DEPTH_THRESH
+#undef MAIN_QSORT_STACK_SIZE
+
+
+/*---------------------------------------------*/
+/* Pre:
+      nblock > N_OVERSHOOT
+      block32 exists for [0 .. nblock-1 +N_OVERSHOOT]
+      ((UChar*)block32) [0 .. nblock-1] holds block
+      ptr exists for [0 .. nblock-1]
+
+   Post:
+      ((UChar*)block32) [0 .. nblock-1] holds block
+      All other areas of block32 destroyed
+      ftab [0 .. 65536 ] destroyed
+      ptr [0 .. nblock-1] holds sorted order
+      if (*budget < 0), sorting was abandoned
+*/
+
+#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8])
+#define SETMASK (1 << 21)
+#define CLEARMASK (~(SETMASK))
+
+static
+void mainSort ( UInt32* ptr, 
+                UChar*  block,
+                UInt16* quadrant, 
+                UInt32* ftab,
+                Int32   nblock,
+                Int32   verb,
+                Int32*  budget )
+{
+   Int32  i, j, k, ss, sb;
+   Int32  runningOrder[256];
+   Bool   bigDone[256];
+   Int32  copyStart[256];
+   Int32  copyEnd  [256];
+   UChar  c1;
+   Int32  numQSorted;
+   UInt16 s;
+   if (verb >= 4) VPrintf0 ( "        main sort initialise ...\n" );
+
+   /*-- set up the 2-byte frequency table --*/
+   for (i = 65536; i >= 0; i--) ftab[i] = 0;
+
+   j = block[0] << 8;
+   i = nblock-1;
+   for (; i >= 3; i -= 4) {
+      quadrant[i] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i]) << 8);
+      ftab[j]++;
+      quadrant[i-1] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i-1]) << 8);
+      ftab[j]++;
+      quadrant[i-2] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i-2]) << 8);
+      ftab[j]++;
+      quadrant[i-3] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i-3]) << 8);
+      ftab[j]++;
+   }
+   for (; i >= 0; i--) {
+      quadrant[i] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i]) << 8);
+      ftab[j]++;
+   }
+
+   /*-- (emphasises close relationship of block & quadrant) --*/
+   for (i = 0; i < BZ_N_OVERSHOOT; i++) {
+      block   [nblock+i] = block[i];
+      quadrant[nblock+i] = 0;
+   }
+
+   if (verb >= 4) VPrintf0 ( "        bucket sorting ...\n" );
+
+   /*-- Complete the initial radix sort --*/
+   for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1];
+
+   s = block[0] << 8;
+   i = nblock-1;
+   for (; i >= 3; i -= 4) {
+      s = (s >> 8) | (block[i] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i;
+      s = (s >> 8) | (block[i-1] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i-1;
+      s = (s >> 8) | (block[i-2] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i-2;
+      s = (s >> 8) | (block[i-3] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i-3;
+   }
+   for (; i >= 0; i--) {
+      s = (s >> 8) | (block[i] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i;
+   }
+
+   /*--
+      Now ftab contains the first loc of every small bucket.
+      Calculate the running order, from smallest to largest
+      big bucket.
+   --*/
+   for (i = 0; i <= 255; i++) {
+      bigDone     [i] = False;
+      runningOrder[i] = i;
+   }
+
+   {
+      Int32 vv;
+      Int32 h = 1;
+      do h = 3 * h + 1; while (h <= 256);
+      do {
+         h = h / 3;
+         for (i = h; i <= 255; i++) {
+            vv = runningOrder[i];
+            j = i;
+            while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) {
+               runningOrder[j] = runningOrder[j-h];
+               j = j - h;
+               if (j <= (h - 1)) goto zero;
+            }
+            zero:
+            runningOrder[j] = vv;
+         }
+      } while (h != 1);
+   }
+
+   /*--
+      The main sorting loop.
+   --*/
+
+   numQSorted = 0;
+
+   for (i = 0; i <= 255; i++) {
+
+      /*--
+         Process big buckets, starting with the least full.
+         Basically this is a 3-step process in which we call
+         mainQSort3 to sort the small buckets [ss, j], but
+         also make a big effort to avoid the calls if we can.
+      --*/
+      ss = runningOrder[i];
+
+      /*--
+         Step 1:
+         Complete the big bucket [ss] by quicksorting
+         any unsorted small buckets [ss, j], for j != ss.  
+         Hopefully previous pointer-scanning phases have already
+         completed many of the small buckets [ss, j], so
+         we don't have to sort them at all.
+      --*/
+      for (j = 0; j <= 255; j++) {
+         if (j != ss) {
+            sb = (ss << 8) + j;
+            if ( ! (ftab[sb] & SETMASK) ) {
+               Int32 lo = ftab[sb]   & CLEARMASK;
+               Int32 hi = (ftab[sb+1] & CLEARMASK) - 1;
+               if (hi > lo) {
+                  if (verb >= 4)
+                     VPrintf4 ( "        qsort [0x%x, 0x%x]   "
+                                "done %d   this %d\n",
+                                ss, j, numQSorted, hi - lo + 1 );
+                  mainQSort3 ( 
+                     ptr, block, quadrant, nblock, 
+                     lo, hi, BZ_N_RADIX, budget 
+                  );   
+                  numQSorted += (hi - lo + 1);
+                  if (*budget < 0) return;
+               }
+            }
+            ftab[sb] |= SETMASK;
+         }
+      }
+
+      AssertH ( !bigDone[ss], 1006 );
+
+      /*--
+         Step 2:
+         Now scan this big bucket [ss] so as to synthesise the
+         sorted order for small buckets [t, ss] for all t,
+         including, magically, the bucket [ss,ss] too.
+         This will avoid doing Real Work in subsequent Step 1's.
+      --*/
+      {
+         for (j = 0; j <= 255; j++) {
+            copyStart[j] =  ftab[(j << 8) + ss]     & CLEARMASK;
+            copyEnd  [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1;
+         }
+         for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) {
+            k = ptr[j]-1; if (k < 0) k += nblock;
+            c1 = block[k];
+            if (!bigDone[c1])
+               ptr[ copyStart[c1]++ ] = k;
+         }
+         for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) {
+            k = ptr[j]-1; if (k < 0) k += nblock;
+            c1 = block[k];
+            if (!bigDone[c1]) 
+               ptr[ copyEnd[c1]-- ] = k;
+         }
+      }
+
+      AssertH ( (copyStart[ss]-1 == copyEnd[ss])
+                || 
+                /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1.
+                   Necessity for this case is demonstrated by compressing 
+                   a sequence of approximately 48.5 million of character 
+                   251; 1.0.0/1.0.1 will then die here. */
+                (copyStart[ss] == 0 && copyEnd[ss] == nblock-1),
+                1007 )
+
+      for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK;
+
+      /*--
+         Step 3:
+         The [ss] big bucket is now done.  Record this fact,
+         and update the quadrant descriptors.  Remember to
+         update quadrants in the overshoot area too, if
+         necessary.  The "if (i < 255)" test merely skips
+         this updating for the last bucket processed, since
+         updating for the last bucket is pointless.
+
+         The quadrant array provides a way to incrementally
+         cache sort orderings, as they appear, so as to 
+         make subsequent comparisons in fullGtU() complete
+         faster.  For repetitive blocks this makes a big
+         difference (but not big enough to be able to avoid
+         the fallback sorting mechanism, exponential radix sort).
+
+         The precise meaning is: at all times:
+
+            for 0 <= i < nblock and 0 <= j <= nblock
+
+            if block[i] != block[j], 
+
+               then the relative values of quadrant[i] and 
+                    quadrant[j] are meaningless.
+
+               else {
+                  if quadrant[i] < quadrant[j]
+                     then the string starting at i lexicographically
+                     precedes the string starting at j
+
+                  else if quadrant[i] > quadrant[j]
+                     then the string starting at j lexicographically
+                     precedes the string starting at i
+
+                  else
+                     the relative ordering of the strings starting
+                     at i and j has not yet been determined.
+               }
+      --*/
+      bigDone[ss] = True;
+
+      if (i < 255) {
+         Int32 bbStart  = ftab[ss << 8] & CLEARMASK;
+         Int32 bbSize   = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart;
+         Int32 shifts   = 0;
+
+         while ((bbSize >> shifts) > 65534) shifts++;
+
+         for (j = bbSize-1; j >= 0; j--) {
+            Int32 a2update     = ptr[bbStart + j];
+            UInt16 qVal        = (UInt16)(j >> shifts);
+            quadrant[a2update] = qVal;
+            if (a2update < BZ_N_OVERSHOOT)
+               quadrant[a2update + nblock] = qVal;
+         }
+         AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 );
+      }
+
+   }
+
+   if (verb >= 4)
+      VPrintf3 ( "        %d pointers, %d sorted, %d scanned\n",
+                 nblock, numQSorted, nblock - numQSorted );
+}
+
+#undef BIGFREQ
+#undef SETMASK
+#undef CLEARMASK
+
+
+/*---------------------------------------------*/
+/* Pre:
+      nblock > 0
+      arr2 exists for [0 .. nblock-1 +N_OVERSHOOT]
+      ((UChar*)arr2)  [0 .. nblock-1] holds block
+      arr1 exists for [0 .. nblock-1]
+
+   Post:
+      ((UChar*)arr2) [0 .. nblock-1] holds block
+      All other areas of block destroyed
+      ftab [ 0 .. 65536 ] destroyed
+      arr1 [0 .. nblock-1] holds sorted order
+*/
+void BZ2_blockSort ( EState* s )
+{
+   UInt32* ptr    = s->ptr; 
+   UChar*  block  = s->block;
+   UInt32* ftab   = s->ftab;
+   Int32   nblock = s->nblock;
+   Int32   verb   = s->verbosity;
+   Int32   wfact  = s->workFactor;
+   UInt16* quadrant;
+   Int32   budget;
+   Int32   budgetInit;
+   Int32   i;
+
+   if (nblock < 10000) {
+      fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb );
+   } else {
+      /* Calculate the location for quadrant, remembering to get
+         the alignment right.  Assumes that &(block[0]) is at least
+         2-byte aligned -- this should be ok since block is really
+         the first section of arr2.
+      */
+      i = nblock+BZ_N_OVERSHOOT;
+      if (i & 1) i++;
+      quadrant = (UInt16*)(&(block[i]));
+
+      /* (wfact-1) / 3 puts the default-factor-30
+         transition point at very roughly the same place as 
+         with v0.1 and v0.9.0.  
+         Not that it particularly matters any more, since the
+         resulting compressed stream is now the same regardless
+         of whether or not we use the main sort or fallback sort.
+      */
+      if (wfact < 1  ) wfact = 1;
+      if (wfact > 100) wfact = 100;
+      budgetInit = nblock * ((wfact-1) / 3);
+      budget = budgetInit;
+
+      mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget );
+      if (verb >= 3) 
+         VPrintf3 ( "      %d work, %d block, ratio %5.2f\n",
+                    budgetInit - budget,
+                    nblock, 
+                    (float)(budgetInit - budget) /
+                    (float)(nblock==0 ? 1 : nblock) ); 
+      if (budget < 0) {
+         if (verb >= 2) 
+            VPrintf0 ( "    too repetitive; using fallback"
+                       " sorting algorithm\n" );
+         fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb );
+      }
+   }
+
+   s->origPtr = -1;
+   for (i = 0; i < s->nblock; i++)
+      if (ptr[i] == 0)
+         { s->origPtr = i; break; };
+
+   AssertH( s->origPtr != -1, 1003 );
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                       blocksort.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/source/Irrlicht/bzip2/bz-common.xsl b/source/Irrlicht/bzip2/bz-common.xsl
new file mode 100644
index 00000000..66fcd6fe
--- /dev/null
+++ b/source/Irrlicht/bzip2/bz-common.xsl
@@ -0,0 +1,39 @@
+ 
+
+
+
+ 
+
+
+
+ 
+ 
+   
+    
+      
+     
+  
+
+
+
+
+set       toc,title
+book      toc,title,figure,table,example,equation
+chapter   toc,title
+section   toc
+sect1     toc
+sect2     toc
+sect3     toc
+sect4     nop
+sect5     nop
+qandaset  toc
+qandadiv  nop
+appendix  toc,title
+article/appendix  nop
+article   toc,title
+preface   toc,title
+reference toc,title
+
+
+
diff --git a/source/Irrlicht/bzip2/bz-fo.xsl b/source/Irrlicht/bzip2/bz-fo.xsl
new file mode 100644
index 00000000..ba3e3012
--- /dev/null
+++ b/source/Irrlicht/bzip2/bz-fo.xsl
@@ -0,0 +1,276 @@
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+      
+     
+   
+
+
+
+
+ 
+
+
+
+
+
+
+  
+
+
+
+
+  blue
+
+
+
+
+  
+    
+  
+
+
+
+  
+    
+  
+
+
+
+
+  
+  
+  
+    
+      
+    
+  
+  
+    
+      
+        
+          
+          
+          
+        
+      
+    
+    
+          
+    
+  
+  
+    
+      
+        
+      
+    
+    
+      
+        
+      
+    
+  
+
+
+
+
+  
+  
+  
+    
+      
+        
+      
+    
+    
+          
+    
+  
+  
+    
+      
+        
+      
+    
+    
+      
+        
+      
+    
+  
+
+
+
+
+
+  
+    
+  
+    
+  
+  
+    
+      
+    
+  
+
+
+
+
+
+  
+  
+  
+  
+    
+      0pt
+    
+  
+  
+    
+      
+      
+      
+        
+          
+            baseline
+             
+               
+            
+          
+          
+            baseline
+            
+              
+                
+                
+                
+                
+              
+            
+          
+        
+      
+    
+  
+  
+  
+    
+      
+    
+    
+      
+    
+    
+      
+    
+  
+
+
+
+
+
+  
+  
+  
+  
+    
+      0pt
+    
+  
+  
+    
+      
+        
+        
+        
+      
+      
+      
+      
+        
+          
+            baseline
+            
+               
+            
+          
+          
+            baseline
+            
+              
+                
+                
+                
+                
+              
+            
+          
+        
+      
+    
+  
+  
+  
+    
+      
+    
+    
+      
+    
+    
+      
+    
+  
+
+
+
+
+
+
+  always
+  
+    
+  
+  
+    
+    pt
+  
+  
+    
+    pt
+  
+  false
+
+
+
+
diff --git a/source/Irrlicht/bzip2/bz-html.xsl b/source/Irrlicht/bzip2/bz-html.xsl
new file mode 100644
index 00000000..1785fffb
--- /dev/null
+++ b/source/Irrlicht/bzip2/bz-html.xsl
@@ -0,0 +1,20 @@
+ 
+ ]>
+
+
+
+
+
+
+
+
+
+
+  
+  
+
+
+
diff --git a/source/Irrlicht/bzip2/bzcompress.c b/source/Irrlicht/bzip2/bzcompress.c
new file mode 100644
index 00000000..caf76960
--- /dev/null
+++ b/source/Irrlicht/bzip2/bzcompress.c
@@ -0,0 +1,672 @@
+
+/*-------------------------------------------------------------*/
+/*--- Compression machinery (not incl block sorting)        ---*/
+/*---                                            compress.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+/* CHANGES
+    0.9.0    -- original version.
+    0.9.0a/b -- no changes in this file.
+    0.9.0c   -- changed setting of nGroups in sendMTFValues() 
+                so as to do a bit better on small files
+*/
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------------*/
+/*--- Bit stream I/O                              ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+void BZ2_bsInitWrite ( EState* s )
+{
+   s->bsLive = 0;
+   s->bsBuff = 0;
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsFinishWrite ( EState* s )
+{
+   while (s->bsLive > 0) {
+      s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24);
+      s->numZ++;
+      s->bsBuff <<= 8;
+      s->bsLive -= 8;
+   }
+}
+
+
+/*---------------------------------------------------*/
+#define bsNEEDW(nz)                           \
+{                                             \
+   while (s->bsLive >= 8) {                   \
+      s->zbits[s->numZ]                       \
+         = (UChar)(s->bsBuff >> 24);          \
+      s->numZ++;                              \
+      s->bsBuff <<= 8;                        \
+      s->bsLive -= 8;                         \
+   }                                          \
+}
+
+
+/*---------------------------------------------------*/
+static
+__inline__
+void bsW ( EState* s, Int32 n, UInt32 v )
+{
+   bsNEEDW ( n );
+   s->bsBuff |= (v << (32 - s->bsLive - n));
+   s->bsLive += n;
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsPutUInt32 ( EState* s, UInt32 u )
+{
+   bsW ( s, 8, (u >> 24) & 0xffL );
+   bsW ( s, 8, (u >> 16) & 0xffL );
+   bsW ( s, 8, (u >>  8) & 0xffL );
+   bsW ( s, 8,  u        & 0xffL );
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsPutUChar ( EState* s, UChar c )
+{
+   bsW( s, 8, (UInt32)c );
+}
+
+
+/*---------------------------------------------------*/
+/*--- The back end proper                         ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+static
+void makeMaps_e ( EState* s )
+{
+   Int32 i;
+   s->nInUse = 0;
+   for (i = 0; i < 256; i++)
+      if (s->inUse[i]) {
+         s->unseqToSeq[i] = s->nInUse;
+         s->nInUse++;
+      }
+}
+
+
+/*---------------------------------------------------*/
+static
+void generateMTFValues ( EState* s )
+{
+   UChar   yy[256];
+   Int32   i, j;
+   Int32   zPend;
+   Int32   wr;
+   Int32   EOB;
+
+   /* 
+      After sorting (eg, here),
+         s->arr1 [ 0 .. s->nblock-1 ] holds sorted order,
+         and
+         ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] 
+         holds the original block data.
+
+      The first thing to do is generate the MTF values,
+      and put them in
+         ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ].
+      Because there are strictly fewer or equal MTF values
+      than block values, ptr values in this area are overwritten
+      with MTF values only when they are no longer needed.
+
+      The final compressed bitstream is generated into the
+      area starting at
+         (UChar*) (&((UChar*)s->arr2)[s->nblock])
+
+      These storage aliases are set up in bzCompressInit(),
+      except for the last one, which is arranged in 
+      compressBlock().
+   */
+   UInt32* ptr   = s->ptr;
+   UChar* block  = s->block;
+   UInt16* mtfv  = s->mtfv;
+
+   makeMaps_e ( s );
+   EOB = s->nInUse+1;
+
+   for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0;
+
+   wr = 0;
+   zPend = 0;
+   for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i;
+
+   for (i = 0; i < s->nblock; i++) {
+      UChar ll_i;
+      AssertD ( wr <= i, "generateMTFValues(1)" );
+      j = ptr[i]-1; if (j < 0) j += s->nblock;
+      ll_i = s->unseqToSeq[block[j]];
+      AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" );
+
+      if (yy[0] == ll_i) { 
+         zPend++;
+      } else {
+
+         if (zPend > 0) {
+            zPend--;
+            while (True) {
+               if (zPend & 1) {
+                  mtfv[wr] = BZ_RUNB; wr++; 
+                  s->mtfFreq[BZ_RUNB]++; 
+               } else {
+                  mtfv[wr] = BZ_RUNA; wr++; 
+                  s->mtfFreq[BZ_RUNA]++; 
+               }
+               if (zPend < 2) break;
+               zPend = (zPend - 2) / 2;
+            };
+            zPend = 0;
+         }
+         {
+            register UChar  rtmp;
+            register UChar* ryy_j;
+            register UChar  rll_i;
+            rtmp  = yy[1];
+            yy[1] = yy[0];
+            ryy_j = &(yy[1]);
+            rll_i = ll_i;
+            while ( rll_i != rtmp ) {
+               register UChar rtmp2;
+               ryy_j++;
+               rtmp2  = rtmp;
+               rtmp   = *ryy_j;
+               *ryy_j = rtmp2;
+            };
+            yy[0] = rtmp;
+            j = ryy_j - &(yy[0]);
+            mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++;
+         }
+
+      }
+   }
+
+   if (zPend > 0) {
+      zPend--;
+      while (True) {
+         if (zPend & 1) {
+            mtfv[wr] = BZ_RUNB; wr++; 
+            s->mtfFreq[BZ_RUNB]++; 
+         } else {
+            mtfv[wr] = BZ_RUNA; wr++; 
+            s->mtfFreq[BZ_RUNA]++; 
+         }
+         if (zPend < 2) break;
+         zPend = (zPend - 2) / 2;
+      };
+      zPend = 0;
+   }
+
+   mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++;
+
+   s->nMTF = wr;
+}
+
+
+/*---------------------------------------------------*/
+#define BZ_LESSER_ICOST  0
+#define BZ_GREATER_ICOST 15
+
+static
+void sendMTFValues ( EState* s )
+{
+   Int32 v, t, i, j, gs, ge, totc, bt, bc, iter;
+   Int32 nSelectors, alphaSize, minLen, maxLen, selCtr;
+   Int32 nGroups, nBytes;
+
+   /*--
+   UChar  len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+   is a global since the decoder also needs it.
+
+   Int32  code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+   Int32  rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+   are also globals only used in this proc.
+   Made global to keep stack frame size small.
+   --*/
+
+
+   UInt16 cost[BZ_N_GROUPS];
+   Int32  fave[BZ_N_GROUPS];
+
+   UInt16* mtfv = s->mtfv;
+
+   if (s->verbosity >= 3)
+      VPrintf3( "      %d in block, %d after MTF & 1-2 coding, "
+                "%d+2 syms in use\n", 
+                s->nblock, s->nMTF, s->nInUse );
+
+   alphaSize = s->nInUse+2;
+   for (t = 0; t < BZ_N_GROUPS; t++)
+      for (v = 0; v < alphaSize; v++)
+         s->len[t][v] = BZ_GREATER_ICOST;
+
+   /*--- Decide how many coding tables to use ---*/
+   AssertH ( s->nMTF > 0, 3001 );
+   if (s->nMTF < 200)  nGroups = 2; else
+   if (s->nMTF < 600)  nGroups = 3; else
+   if (s->nMTF < 1200) nGroups = 4; else
+   if (s->nMTF < 2400) nGroups = 5; else
+                       nGroups = 6;
+
+   /*--- Generate an initial set of coding tables ---*/
+   { 
+      Int32 nPart, remF, tFreq, aFreq;
+
+      nPart = nGroups;
+      remF  = s->nMTF;
+      gs = 0;
+      while (nPart > 0) {
+         tFreq = remF / nPart;
+         ge = gs-1;
+         aFreq = 0;
+         while (aFreq < tFreq && ge < alphaSize-1) {
+            ge++;
+            aFreq += s->mtfFreq[ge];
+         }
+
+         if (ge > gs 
+             && nPart != nGroups && nPart != 1 
+             && ((nGroups-nPart) % 2 == 1)) {
+            aFreq -= s->mtfFreq[ge];
+            ge--;
+         }
+
+         if (s->verbosity >= 3)
+            VPrintf5( "      initial group %d, [%d .. %d], "
+                      "has %d syms (%4.1f%%)\n",
+                      nPart, gs, ge, aFreq, 
+                      (100.0 * (float)aFreq) / (float)(s->nMTF) );
+ 
+         for (v = 0; v < alphaSize; v++)
+            if (v >= gs && v <= ge) 
+               s->len[nPart-1][v] = BZ_LESSER_ICOST; else
+               s->len[nPart-1][v] = BZ_GREATER_ICOST;
+ 
+         nPart--;
+         gs = ge+1;
+         remF -= aFreq;
+      }
+   }
+
+   /*--- 
+      Iterate up to BZ_N_ITERS times to improve the tables.
+   ---*/
+   for (iter = 0; iter < BZ_N_ITERS; iter++) {
+
+      for (t = 0; t < nGroups; t++) fave[t] = 0;
+
+      for (t = 0; t < nGroups; t++)
+         for (v = 0; v < alphaSize; v++)
+            s->rfreq[t][v] = 0;
+
+      /*---
+        Set up an auxiliary length table which is used to fast-track
+	the common case (nGroups == 6). 
+      ---*/
+      if (nGroups == 6) {
+         for (v = 0; v < alphaSize; v++) {
+            s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v];
+            s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v];
+            s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v];
+	 }
+      }
+
+      nSelectors = 0;
+      totc = 0;
+      gs = 0;
+      while (True) {
+
+         /*--- Set group start & end marks. --*/
+         if (gs >= s->nMTF) break;
+         ge = gs + BZ_G_SIZE - 1; 
+         if (ge >= s->nMTF) ge = s->nMTF-1;
+
+         /*-- 
+            Calculate the cost of this group as coded
+            by each of the coding tables.
+         --*/
+         for (t = 0; t < nGroups; t++) cost[t] = 0;
+
+         if (nGroups == 6 && 50 == ge-gs+1) {
+            /*--- fast track the common case ---*/
+            register UInt32 cost01, cost23, cost45;
+            register UInt16 icv;
+            cost01 = cost23 = cost45 = 0;
+
+#           define BZ_ITER(nn)                \
+               icv = mtfv[gs+(nn)];           \
+               cost01 += s->len_pack[icv][0]; \
+               cost23 += s->len_pack[icv][1]; \
+               cost45 += s->len_pack[icv][2]; \
+
+            BZ_ITER(0);  BZ_ITER(1);  BZ_ITER(2);  BZ_ITER(3);  BZ_ITER(4);
+            BZ_ITER(5);  BZ_ITER(6);  BZ_ITER(7);  BZ_ITER(8);  BZ_ITER(9);
+            BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14);
+            BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19);
+            BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24);
+            BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29);
+            BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34);
+            BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39);
+            BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44);
+            BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49);
+
+#           undef BZ_ITER
+
+            cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16;
+            cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16;
+            cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16;
+
+         } else {
+	    /*--- slow version which correctly handles all situations ---*/
+            for (i = gs; i <= ge; i++) { 
+               UInt16 icv = mtfv[i];
+               for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv];
+            }
+         }
+ 
+         /*-- 
+            Find the coding table which is best for this group,
+            and record its identity in the selector table.
+         --*/
+         bc = 999999999; bt = -1;
+         for (t = 0; t < nGroups; t++)
+            if (cost[t] < bc) { bc = cost[t]; bt = t; };
+         totc += bc;
+         fave[bt]++;
+         s->selector[nSelectors] = bt;
+         nSelectors++;
+
+         /*-- 
+            Increment the symbol frequencies for the selected table.
+          --*/
+         if (nGroups == 6 && 50 == ge-gs+1) {
+            /*--- fast track the common case ---*/
+
+#           define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++
+
+            BZ_ITUR(0);  BZ_ITUR(1);  BZ_ITUR(2);  BZ_ITUR(3);  BZ_ITUR(4);
+            BZ_ITUR(5);  BZ_ITUR(6);  BZ_ITUR(7);  BZ_ITUR(8);  BZ_ITUR(9);
+            BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14);
+            BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19);
+            BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24);
+            BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29);
+            BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34);
+            BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39);
+            BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44);
+            BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49);
+
+#           undef BZ_ITUR
+
+         } else {
+	    /*--- slow version which correctly handles all situations ---*/
+            for (i = gs; i <= ge; i++)
+               s->rfreq[bt][ mtfv[i] ]++;
+         }
+
+         gs = ge+1;
+      }
+      if (s->verbosity >= 3) {
+         VPrintf2 ( "      pass %d: size is %d, grp uses are ", 
+                   iter+1, totc/8 );
+         for (t = 0; t < nGroups; t++)
+            VPrintf1 ( "%d ", fave[t] );
+         VPrintf0 ( "\n" );
+      }
+
+      /*--
+        Recompute the tables based on the accumulated frequencies.
+      --*/
+      /* maxLen was changed from 20 to 17 in bzip2-1.0.3.  See 
+         comment in huffman.c for details. */
+      for (t = 0; t < nGroups; t++)
+         BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), 
+                                 alphaSize, 17 /*20*/ );
+   }
+
+
+   AssertH( nGroups < 8, 3002 );
+   AssertH( nSelectors < 32768 &&
+            nSelectors <= (2 + (900000 / BZ_G_SIZE)),
+            3003 );
+
+
+   /*--- Compute MTF values for the selectors. ---*/
+   {
+      UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp;
+      for (i = 0; i < nGroups; i++) pos[i] = i;
+      for (i = 0; i < nSelectors; i++) {
+         ll_i = s->selector[i];
+         j = 0;
+         tmp = pos[j];
+         while ( ll_i != tmp ) {
+            j++;
+            tmp2 = tmp;
+            tmp = pos[j];
+            pos[j] = tmp2;
+         };
+         pos[0] = tmp;
+         s->selectorMtf[i] = j;
+      }
+   };
+
+   /*--- Assign actual codes for the tables. --*/
+   for (t = 0; t < nGroups; t++) {
+      minLen = 32;
+      maxLen = 0;
+      for (i = 0; i < alphaSize; i++) {
+         if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
+         if (s->len[t][i] < minLen) minLen = s->len[t][i];
+      }
+      AssertH ( !(maxLen > 17 /*20*/ ), 3004 );
+      AssertH ( !(minLen < 1),  3005 );
+      BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), 
+                          minLen, maxLen, alphaSize );
+   }
+
+   /*--- Transmit the mapping table. ---*/
+   { 
+      Bool inUse16[16];
+      for (i = 0; i < 16; i++) {
+          inUse16[i] = False;
+          for (j = 0; j < 16; j++)
+             if (s->inUse[i * 16 + j]) inUse16[i] = True;
+      }
+     
+      nBytes = s->numZ;
+      for (i = 0; i < 16; i++)
+         if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0);
+
+      for (i = 0; i < 16; i++)
+         if (inUse16[i])
+            for (j = 0; j < 16; j++) {
+               if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0);
+            }
+
+      if (s->verbosity >= 3) 
+         VPrintf1( "      bytes: mapping %d, ", s->numZ-nBytes );
+   }
+
+   /*--- Now the selectors. ---*/
+   nBytes = s->numZ;
+   bsW ( s, 3, nGroups );
+   bsW ( s, 15, nSelectors );
+   for (i = 0; i < nSelectors; i++) { 
+      for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1);
+      bsW(s,1,0);
+   }
+   if (s->verbosity >= 3)
+      VPrintf1( "selectors %d, ", s->numZ-nBytes );
+
+   /*--- Now the coding tables. ---*/
+   nBytes = s->numZ;
+
+   for (t = 0; t < nGroups; t++) {
+      Int32 curr = s->len[t][0];
+      bsW ( s, 5, curr );
+      for (i = 0; i < alphaSize; i++) {
+         while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ };
+         while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ };
+         bsW ( s, 1, 0 );
+      }
+   }
+
+   if (s->verbosity >= 3)
+      VPrintf1 ( "code lengths %d, ", s->numZ-nBytes );
+
+   /*--- And finally, the block data proper ---*/
+   nBytes = s->numZ;
+   selCtr = 0;
+   gs = 0;
+   while (True) {
+      if (gs >= s->nMTF) break;
+      ge = gs + BZ_G_SIZE - 1; 
+      if (ge >= s->nMTF) ge = s->nMTF-1;
+      AssertH ( s->selector[selCtr] < nGroups, 3006 );
+
+      if (nGroups == 6 && 50 == ge-gs+1) {
+            /*--- fast track the common case ---*/
+            UInt16 mtfv_i;
+            UChar* s_len_sel_selCtr 
+               = &(s->len[s->selector[selCtr]][0]);
+            Int32* s_code_sel_selCtr
+               = &(s->code[s->selector[selCtr]][0]);
+
+#           define BZ_ITAH(nn)                      \
+               mtfv_i = mtfv[gs+(nn)];              \
+               bsW ( s,                             \
+                     s_len_sel_selCtr[mtfv_i],      \
+                     s_code_sel_selCtr[mtfv_i] )
+
+            BZ_ITAH(0);  BZ_ITAH(1);  BZ_ITAH(2);  BZ_ITAH(3);  BZ_ITAH(4);
+            BZ_ITAH(5);  BZ_ITAH(6);  BZ_ITAH(7);  BZ_ITAH(8);  BZ_ITAH(9);
+            BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14);
+            BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19);
+            BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24);
+            BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29);
+            BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34);
+            BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39);
+            BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44);
+            BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49);
+
+#           undef BZ_ITAH
+
+      } else {
+	 /*--- slow version which correctly handles all situations ---*/
+         for (i = gs; i <= ge; i++) {
+            bsW ( s, 
+                  s->len  [s->selector[selCtr]] [mtfv[i]],
+                  s->code [s->selector[selCtr]] [mtfv[i]] );
+         }
+      }
+
+
+      gs = ge+1;
+      selCtr++;
+   }
+   AssertH( selCtr == nSelectors, 3007 );
+
+   if (s->verbosity >= 3)
+      VPrintf1( "codes %d\n", s->numZ-nBytes );
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_compressBlock ( EState* s, Bool is_last_block )
+{
+   if (s->nblock > 0) {
+
+      BZ_FINALISE_CRC ( s->blockCRC );
+      s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31);
+      s->combinedCRC ^= s->blockCRC;
+      if (s->blockNo > 1) s->numZ = 0;
+
+      if (s->verbosity >= 2)
+         VPrintf4( "    block %d: crc = 0x%08x, "
+                   "combined CRC = 0x%08x, size = %d\n",
+                   s->blockNo, s->blockCRC, s->combinedCRC, s->nblock );
+
+      BZ2_blockSort ( s );
+   }
+
+   s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]);
+
+   /*-- If this is the first block, create the stream header. --*/
+   if (s->blockNo == 1) {
+      BZ2_bsInitWrite ( s );
+      bsPutUChar ( s, BZ_HDR_B );
+      bsPutUChar ( s, BZ_HDR_Z );
+      bsPutUChar ( s, BZ_HDR_h );
+      bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) );
+   }
+
+   if (s->nblock > 0) {
+
+      bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 );
+      bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 );
+      bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 );
+
+      /*-- Now the block's CRC, so it is in a known place. --*/
+      bsPutUInt32 ( s, s->blockCRC );
+
+      /*-- 
+         Now a single bit indicating (non-)randomisation. 
+         As of version 0.9.5, we use a better sorting algorithm
+         which makes randomisation unnecessary.  So always set
+         the randomised bit to 'no'.  Of course, the decoder
+         still needs to be able to handle randomised blocks
+         so as to maintain backwards compatibility with
+         older versions of bzip2.
+      --*/
+      bsW(s,1,0);
+
+      bsW ( s, 24, s->origPtr );
+      generateMTFValues ( s );
+      sendMTFValues ( s );
+   }
+
+
+   /*-- If this is the last block, add the stream trailer. --*/
+   if (is_last_block) {
+
+      bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 );
+      bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 );
+      bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 );
+      bsPutUInt32 ( s, s->combinedCRC );
+      if (s->verbosity >= 2)
+         VPrintf1( "    final combined CRC = 0x%08x\n   ", s->combinedCRC );
+      bsFinishWrite ( s );
+   }
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                        compress.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/source/Irrlicht/bzip2/bzdiff b/source/Irrlicht/bzip2/bzdiff
new file mode 100644
index 00000000..6fc38f92
--- /dev/null
+++ b/source/Irrlicht/bzip2/bzdiff
@@ -0,0 +1,76 @@
+#!/bin/sh
+# sh is buggy on RS/6000 AIX 3.2. Replace above line with #!/bin/ksh
+
+# Bzcmp/diff wrapped for bzip2, 
+# adapted from zdiff by Philippe Troin  for Debian GNU/Linux.
+
+# Bzcmp and bzdiff are used to invoke the cmp or the  diff  pro-
+# gram  on compressed files.  All options specified are passed
+# directly to cmp or diff.  If only 1 file is specified,  then
+# the  files  compared  are file1 and an uncompressed file1.gz.
+# If two files are specified, then they are  uncompressed  (if
+# necessary) and fed to cmp or diff.  The exit status from cmp
+# or diff is preserved.
+
+PATH="/usr/bin:/bin:$PATH"; export PATH
+prog=`echo $0 | sed 's|.*/||'`
+case "$prog" in
+  *cmp) comp=${CMP-cmp}   ;;
+  *)    comp=${DIFF-diff} ;;
+esac
+
+OPTIONS=
+FILES=
+for ARG
+do
+    case "$ARG" in
+    -*)	OPTIONS="$OPTIONS $ARG";;
+     *)	if test -f "$ARG"; then
+            FILES="$FILES $ARG"
+        else
+            echo "${prog}: $ARG not found or not a regular file"
+	    exit 1
+        fi ;;
+    esac
+done
+if test -z "$FILES"; then
+	echo "Usage: $prog [${comp}_options] file [file]"
+	exit 1
+fi
+tmp=`mktemp ${TMPDIR:-/tmp}/bzdiff.XXXXXXXXXX` || {
+      echo 'cannot create a temporary file' >&2
+      exit 1
+}
+set $FILES
+if test $# -eq 1; then
+	FILE=`echo "$1" | sed 's/.bz2$//'`
+	bzip2 -cd "$FILE.bz2" | $comp $OPTIONS - "$FILE"
+	STAT="$?"
+
+elif test $# -eq 2; then
+	case "$1" in
+        *.bz2)
+                case "$2" in
+	        *.bz2)
+			F=`echo "$2" | sed 's|.*/||;s|.bz2$||'`
+                        bzip2 -cdfq "$2" > $tmp
+                        bzip2 -cdfq "$1" | $comp $OPTIONS - $tmp
+                        STAT="$?"
+			/bin/rm -f $tmp;;
+
+                *)      bzip2 -cdfq "$1" | $comp $OPTIONS - "$2"
+                        STAT="$?";;
+                esac;;
+        *)      case "$2" in
+	        *.bz2)
+                        bzip2 -cdfq "$2" | $comp $OPTIONS "$1" -
+                        STAT="$?";;
+                *)      $comp $OPTIONS "$1" "$2"
+                        STAT="$?";;
+                esac;;
+	esac
+        exit "$STAT"
+else
+	echo "Usage: $prog [${comp}_options] file [file]"
+	exit 1
+fi
diff --git a/source/Irrlicht/bzip2/bzdiff.1 b/source/Irrlicht/bzip2/bzdiff.1
new file mode 100644
index 00000000..adb7a8e7
--- /dev/null
+++ b/source/Irrlicht/bzip2/bzdiff.1
@@ -0,0 +1,47 @@
+\"Shamelessly copied from zmore.1 by Philippe Troin 
+\"for Debian GNU/Linux
+.TH BZDIFF 1
+.SH NAME
+bzcmp, bzdiff \- compare bzip2 compressed files
+.SH SYNOPSIS
+.B bzcmp
+[ cmp_options ] file1
+[ file2 ]
+.br
+.B bzdiff
+[ diff_options ] file1
+[ file2 ]
+.SH DESCRIPTION
+.I  Bzcmp
+and 
+.I bzdiff
+are used to invoke the
+.I cmp
+or the
+.I diff
+program on bzip2 compressed files.  All options specified are passed
+directly to
+.I cmp
+or
+.IR diff "."
+If only 1 file is specified, then the files compared are
+.I file1
+and an uncompressed
+.IR file1 ".bz2."
+If two files are specified, then they are uncompressed if necessary and fed to
+.I cmp
+or
+.IR diff "."
+The exit status from 
+.I cmp
+or
+.I diff
+is preserved.
+.SH "SEE ALSO"
+cmp(1), diff(1), bzmore(1), bzless(1), bzgrep(1), bzip2(1)
+.SH BUGS
+Messages from the
+.I cmp
+or
+.I diff
+programs refer to temporary filenames instead of those specified.
diff --git a/source/Irrlicht/bzip2/bzgrep b/source/Irrlicht/bzip2/bzgrep
new file mode 100644
index 00000000..9a04b833
--- /dev/null
+++ b/source/Irrlicht/bzip2/bzgrep
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+# Bzgrep wrapped for bzip2, 
+# adapted from zgrep by Philippe Troin  for Debian GNU/Linux.
+## zgrep notice:
+## zgrep -- a wrapper around a grep program that decompresses files as needed
+## Adapted from a version sent by Charles Levert 
+
+PATH="/usr/bin:$PATH"; export PATH
+
+prog=`echo $0 | sed 's|.*/||'`
+case "$prog" in
+	*egrep)	grep=${EGREP-egrep}	;;
+	*fgrep)	grep=${FGREP-fgrep}	;;
+	*)	grep=${GREP-grep}	;;
+esac
+pat=""
+while test $# -ne 0; do
+  case "$1" in
+  -e | -f) opt="$opt $1"; shift; pat="$1"
+           if test "$grep" = grep; then  # grep is buggy with -e on SVR4
+             grep=egrep
+           fi;;
+  -A | -B) opt="$opt $1 $2"; shift;;
+  -*)	   opt="$opt $1";;
+   *)      if test -z "$pat"; then
+	     pat="$1"
+	   else
+	     break;
+           fi;;
+  esac
+  shift
+done
+
+if test -z "$pat"; then
+  echo "grep through bzip2 files"
+  echo "usage: $prog [grep_options] pattern [files]"
+  exit 1
+fi
+
+list=0
+silent=0
+op=`echo "$opt" | sed -e 's/ //g' -e 's/-//g'`
+case "$op" in
+  *l*) list=1
+esac
+case "$op" in
+  *h*) silent=1
+esac
+
+if test $# -eq 0; then
+  bzip2 -cdfq | $grep $opt "$pat"
+  exit $?
+fi
+
+res=0
+for i do
+  if test -f "$i"; then :; else if test -f "$i.bz2"; then i="$i.bz2"; fi; fi
+  if test $list -eq 1; then
+    bzip2 -cdfq "$i" | $grep $opt "$pat" 2>&1 > /dev/null && echo $i
+    r=$?
+  elif test $# -eq 1 -o $silent -eq 1; then
+    bzip2 -cdfq "$i" | $grep $opt "$pat"
+    r=$?
+  else
+    j=${i//\\/\\\\}
+    j=${j//|/\\|}
+    j=${j//&/\\&}
+    j=`printf "%s" "$j" | tr '\n' ' '`
+    bzip2 -cdfq "$i" | $grep $opt "$pat" | sed "s|^|${j}:|"
+    r=$?
+  fi
+  test "$r" -ne 0 && res="$r"
+done
+exit $res
diff --git a/source/Irrlicht/bzip2/bzgrep.1 b/source/Irrlicht/bzip2/bzgrep.1
new file mode 100644
index 00000000..930af8c7
--- /dev/null
+++ b/source/Irrlicht/bzip2/bzgrep.1
@@ -0,0 +1,56 @@
+\"Shamelessly copied from zmore.1 by Philippe Troin 
+\"for Debian GNU/Linux
+.TH BZGREP 1
+.SH NAME
+bzgrep, bzfgrep, bzegrep \- search possibly bzip2 compressed files for a regular expression
+.SH SYNOPSIS
+.B bzgrep
+[ grep_options ]
+.BI  [\ -e\ ] " pattern"
+.IR filename ".\|.\|."
+.br
+.B bzegrep
+[ egrep_options ]
+.BI  [\ -e\ ] " pattern"
+.IR filename ".\|.\|."
+.br
+.B bzfgrep
+[ fgrep_options ]
+.BI  [\ -e\ ] " pattern"
+.IR filename ".\|.\|."
+.SH DESCRIPTION
+.IR  Bzgrep
+is used to invoke the
+.I grep
+on bzip2-compressed files. All options specified are passed directly to
+.I grep.
+If no file is specified, then the standard input is decompressed
+if necessary and fed to grep.
+Otherwise the given files are uncompressed if necessary and fed to
+.I grep.
+.PP
+If
+.I bzgrep
+is invoked as
+.I bzegrep
+or
+.I bzfgrep
+then
+.I egrep
+or
+.I fgrep
+is used instead of
+.I grep.
+If the GREP environment variable is set,
+.I bzgrep
+uses it as the
+.I grep
+program to be invoked. For example:
+
+    for sh:  GREP=fgrep  bzgrep string files
+    for csh: (setenv GREP fgrep; bzgrep string files)
+.SH AUTHOR
+Charles Levert (charles@comm.polymtl.ca). Adapted to bzip2 by Philippe
+Troin  for Debian GNU/Linux.
+.SH "SEE ALSO"
+grep(1), egrep(1), fgrep(1), bzdiff(1), bzmore(1), bzless(1), bzip2(1)
diff --git a/source/Irrlicht/bzip2/bzip.css b/source/Irrlicht/bzip2/bzip.css
new file mode 100644
index 00000000..43193d8d
--- /dev/null
+++ b/source/Irrlicht/bzip2/bzip.css
@@ -0,0 +1,74 @@
+/* Colours:
+#74240f  dark brown      h1, h2, h3, h4
+#336699  medium blue     links
+#339999  turquoise       link hover colour
+#202020  almost black    general text
+#761596  purple          md5sum text
+#626262  dark gray       pre border
+#eeeeee  very light gray pre background
+#f2f2f9  very light blue nav table background
+#3366cc  medium blue     nav table border
+*/
+
+a, a:link, a:visited, a:active { color: #336699; }
+a:hover { color: #339999; }
+
+body { font: 80%/126% sans-serif; }
+h1, h2, h3, h4 { color: #74240f; }
+
+dt { color: #336699; font-weight: bold }
+dd { 
+ margin-left: 1.5em; 
+ padding-bottom: 0.8em;
+}
+
+/* -- ruler -- */
+div.hr_blue { 
+  height:  3px; 
+  background:#ffffff url("/images/hr_blue.png") repeat-x; }
+div.hr_blue hr { display:none; }
+
+/* release styles */
+#release p { margin-top: 0.4em; }
+#release .md5sum { color: #761596; }
+
+
+/* ------ styles for docs|manuals|howto ------ */
+/* -- lists -- */
+ul  { 
+ margin:     0px 4px 16px 16px;
+ padding:    0px;
+ list-style: url("/images/li-blue.png"); 
+}
+ul li { 
+ margin-bottom: 10px;
+}
+ul ul	{ 
+ list-style-type:  none; 
+ list-style-image: none; 
+ margin-left:      0px; 
+}
+
+/* header / footer nav tables */
+table.nav {
+ border:     solid 1px #3366cc;
+ background: #f2f2f9;
+ background-color: #f2f2f9;
+ margin-bottom: 0.5em;
+}
+/* don't have underlined links in chunked nav menus */
+table.nav a { text-decoration: none; }
+table.nav a:hover { text-decoration: underline; }
+table.nav td { font-size: 85%; }
+
+code, tt, pre { font-size: 120%; }
+code, tt { color: #761596; }
+
+div.literallayout, pre.programlisting, pre.screen {
+ color:      #000000;
+ padding:    0.5em;
+ background: #eeeeee;
+ border:     1px solid #626262;
+ background-color: #eeeeee;
+ margin: 4px 0px 4px 0px; 
+}
diff --git a/source/Irrlicht/bzip2/bzip2.1 b/source/Irrlicht/bzip2/bzip2.1
new file mode 100644
index 00000000..ce3a78e6
--- /dev/null
+++ b/source/Irrlicht/bzip2/bzip2.1
@@ -0,0 +1,454 @@
+.PU
+.TH bzip2 1
+.SH NAME
+bzip2, bunzip2 \- a block-sorting file compressor, v1.0.6
+.br
+bzcat \- decompresses files to stdout
+.br
+bzip2recover \- recovers data from damaged bzip2 files
+
+.SH SYNOPSIS
+.ll +8
+.B bzip2
+.RB [ " \-cdfkqstvzVL123456789 " ]
+[
+.I "filenames \&..."
+]
+.ll -8
+.br
+.B bunzip2
+.RB [ " \-fkvsVL " ]
+[ 
+.I "filenames \&..."
+]
+.br
+.B bzcat
+.RB [ " \-s " ]
+[ 
+.I "filenames \&..."
+]
+.br
+.B bzip2recover
+.I "filename"
+
+.SH DESCRIPTION
+.I bzip2
+compresses files using the Burrows-Wheeler block sorting
+text compression algorithm, and Huffman coding.  Compression is
+generally considerably better than that achieved by more conventional
+LZ77/LZ78-based compressors, and approaches the performance of the PPM
+family of statistical compressors.
+
+The command-line options are deliberately very similar to 
+those of 
+.I GNU gzip, 
+but they are not identical.
+
+.I bzip2
+expects a list of file names to accompany the
+command-line flags.  Each file is replaced by a compressed version of
+itself, with the name "original_name.bz2".  
+Each compressed file
+has the same modification date, permissions, and, when possible,
+ownership as the corresponding original, so that these properties can
+be correctly restored at decompression time.  File name handling is
+naive in the sense that there is no mechanism for preserving original
+file names, permissions, ownerships or dates in filesystems which lack
+these concepts, or have serious file name length restrictions, such as
+MS-DOS.
+
+.I bzip2
+and
+.I bunzip2
+will by default not overwrite existing
+files.  If you want this to happen, specify the \-f flag.
+
+If no file names are specified,
+.I bzip2
+compresses from standard
+input to standard output.  In this case,
+.I bzip2
+will decline to
+write compressed output to a terminal, as this would be entirely
+incomprehensible and therefore pointless.
+
+.I bunzip2
+(or
+.I bzip2 \-d) 
+decompresses all
+specified files.  Files which were not created by 
+.I bzip2
+will be detected and ignored, and a warning issued.  
+.I bzip2
+attempts to guess the filename for the decompressed file 
+from that of the compressed file as follows:
+
+       filename.bz2    becomes   filename
+       filename.bz     becomes   filename
+       filename.tbz2   becomes   filename.tar
+       filename.tbz    becomes   filename.tar
+       anyothername    becomes   anyothername.out
+
+If the file does not end in one of the recognised endings, 
+.I .bz2, 
+.I .bz, 
+.I .tbz2
+or
+.I .tbz, 
+.I bzip2 
+complains that it cannot
+guess the name of the original file, and uses the original name
+with
+.I .out
+appended.
+
+As with compression, supplying no
+filenames causes decompression from 
+standard input to standard output.
+
+.I bunzip2 
+will correctly decompress a file which is the
+concatenation of two or more compressed files.  The result is the
+concatenation of the corresponding uncompressed files.  Integrity
+testing (\-t) 
+of concatenated 
+compressed files is also supported.
+
+You can also compress or decompress files to the standard output by
+giving the \-c flag.  Multiple files may be compressed and
+decompressed like this.  The resulting outputs are fed sequentially to
+stdout.  Compression of multiple files 
+in this manner generates a stream
+containing multiple compressed file representations.  Such a stream
+can be decompressed correctly only by
+.I bzip2 
+version 0.9.0 or
+later.  Earlier versions of
+.I bzip2
+will stop after decompressing
+the first file in the stream.
+
+.I bzcat
+(or
+.I bzip2 -dc) 
+decompresses all specified files to
+the standard output.
+
+.I bzip2
+will read arguments from the environment variables
+.I BZIP2
+and
+.I BZIP,
+in that order, and will process them
+before any arguments read from the command line.  This gives a 
+convenient way to supply default arguments.
+
+Compression is always performed, even if the compressed 
+file is slightly
+larger than the original.  Files of less than about one hundred bytes
+tend to get larger, since the compression mechanism has a constant
+overhead in the region of 50 bytes.  Random data (including the output
+of most file compressors) is coded at about 8.05 bits per byte, giving
+an expansion of around 0.5%.
+
+As a self-check for your protection, 
+.I 
+bzip2
+uses 32-bit CRCs to
+make sure that the decompressed version of a file is identical to the
+original.  This guards against corruption of the compressed data, and
+against undetected bugs in
+.I bzip2
+(hopefully very unlikely).  The
+chances of data corruption going undetected is microscopic, about one
+chance in four billion for each file processed.  Be aware, though, that
+the check occurs upon decompression, so it can only tell you that
+something is wrong.  It can't help you 
+recover the original uncompressed
+data.  You can use 
+.I bzip2recover
+to try to recover data from
+damaged files.
+
+Return values: 0 for a normal exit, 1 for environmental problems (file
+not found, invalid flags, I/O errors, &c), 2 to indicate a corrupt
+compressed file, 3 for an internal consistency error (eg, bug) which
+caused
+.I bzip2
+to panic.
+
+.SH OPTIONS
+.TP
+.B \-c --stdout
+Compress or decompress to standard output.
+.TP
+.B \-d --decompress
+Force decompression.  
+.I bzip2, 
+.I bunzip2 
+and
+.I bzcat 
+are
+really the same program, and the decision about what actions to take is
+done on the basis of which name is used.  This flag overrides that
+mechanism, and forces 
+.I bzip2
+to decompress.
+.TP
+.B \-z --compress
+The complement to \-d: forces compression, regardless of the
+invocation name.
+.TP
+.B \-t --test
+Check integrity of the specified file(s), but don't decompress them.
+This really performs a trial decompression and throws away the result.
+.TP
+.B \-f --force
+Force overwrite of output files.  Normally,
+.I bzip2 
+will not overwrite
+existing output files.  Also forces 
+.I bzip2 
+to break hard links
+to files, which it otherwise wouldn't do.
+
+bzip2 normally declines to decompress files which don't have the
+correct magic header bytes.  If forced (-f), however, it will pass
+such files through unmodified.  This is how GNU gzip behaves.
+.TP
+.B \-k --keep
+Keep (don't delete) input files during compression
+or decompression.
+.TP
+.B \-s --small
+Reduce memory usage, for compression, decompression and testing.  Files
+are decompressed and tested using a modified algorithm which only
+requires 2.5 bytes per block byte.  This means any file can be
+decompressed in 2300k of memory, albeit at about half the normal speed.
+
+During compression, \-s selects a block size of 200k, which limits
+memory use to around the same figure, at the expense of your compression
+ratio.  In short, if your machine is low on memory (8 megabytes or
+less), use \-s for everything.  See MEMORY MANAGEMENT below.
+.TP
+.B \-q --quiet
+Suppress non-essential warning messages.  Messages pertaining to
+I/O errors and other critical events will not be suppressed.
+.TP
+.B \-v --verbose
+Verbose mode -- show the compression ratio for each file processed.
+Further \-v's increase the verbosity level, spewing out lots of
+information which is primarily of interest for diagnostic purposes.
+.TP
+.B \-L --license -V --version
+Display the software version, license terms and conditions.
+.TP
+.B \-1 (or \-\-fast) to \-9 (or \-\-best)
+Set the block size to 100 k, 200 k ..  900 k when compressing.  Has no
+effect when decompressing.  See MEMORY MANAGEMENT below.
+The \-\-fast and \-\-best aliases are primarily for GNU gzip 
+compatibility.  In particular, \-\-fast doesn't make things
+significantly faster.  
+And \-\-best merely selects the default behaviour.
+.TP
+.B \--
+Treats all subsequent arguments as file names, even if they start
+with a dash.  This is so you can handle files with names beginning
+with a dash, for example: bzip2 \-- \-myfilename.
+.TP
+.B \--repetitive-fast --repetitive-best
+These flags are redundant in versions 0.9.5 and above.  They provided
+some coarse control over the behaviour of the sorting algorithm in
+earlier versions, which was sometimes useful.  0.9.5 and above have an
+improved algorithm which renders these flags irrelevant.
+
+.SH MEMORY MANAGEMENT
+.I bzip2 
+compresses large files in blocks.  The block size affects
+both the compression ratio achieved, and the amount of memory needed for
+compression and decompression.  The flags \-1 through \-9
+specify the block size to be 100,000 bytes through 900,000 bytes (the
+default) respectively.  At decompression time, the block size used for
+compression is read from the header of the compressed file, and
+.I bunzip2
+then allocates itself just enough memory to decompress
+the file.  Since block sizes are stored in compressed files, it follows
+that the flags \-1 to \-9 are irrelevant to and so ignored
+during decompression.
+
+Compression and decompression requirements, 
+in bytes, can be estimated as:
+
+       Compression:   400k + ( 8 x block size )
+
+       Decompression: 100k + ( 4 x block size ), or
+                      100k + ( 2.5 x block size )
+
+Larger block sizes give rapidly diminishing marginal returns.  Most of
+the compression comes from the first two or three hundred k of block
+size, a fact worth bearing in mind when using
+.I bzip2
+on small machines.
+It is also important to appreciate that the decompression memory
+requirement is set at compression time by the choice of block size.
+
+For files compressed with the default 900k block size,
+.I bunzip2
+will require about 3700 kbytes to decompress.  To support decompression
+of any file on a 4 megabyte machine, 
+.I bunzip2
+has an option to
+decompress using approximately half this amount of memory, about 2300
+kbytes.  Decompression speed is also halved, so you should use this
+option only where necessary.  The relevant flag is -s.
+
+In general, try and use the largest block size memory constraints allow,
+since that maximises the compression achieved.  Compression and
+decompression speed are virtually unaffected by block size.
+
+Another significant point applies to files which fit in a single block
+-- that means most files you'd encounter using a large block size.  The
+amount of real memory touched is proportional to the size of the file,
+since the file is smaller than a block.  For example, compressing a file
+20,000 bytes long with the flag -9 will cause the compressor to
+allocate around 7600k of memory, but only touch 400k + 20000 * 8 = 560
+kbytes of it.  Similarly, the decompressor will allocate 3700k but only
+touch 100k + 20000 * 4 = 180 kbytes.
+
+Here is a table which summarises the maximum memory usage for different
+block sizes.  Also recorded is the total compressed size for 14 files of
+the Calgary Text Compression Corpus totalling 3,141,622 bytes.  This
+column gives some feel for how compression varies with block size.
+These figures tend to understate the advantage of larger block sizes for
+larger files, since the Corpus is dominated by smaller files.
+
+           Compress   Decompress   Decompress   Corpus
+    Flag     usage      usage       -s usage     Size
+
+     -1      1200k       500k         350k      914704
+     -2      2000k       900k         600k      877703
+     -3      2800k      1300k         850k      860338
+     -4      3600k      1700k        1100k      846899
+     -5      4400k      2100k        1350k      845160
+     -6      5200k      2500k        1600k      838626
+     -7      6100k      2900k        1850k      834096
+     -8      6800k      3300k        2100k      828642
+     -9      7600k      3700k        2350k      828642
+
+.SH RECOVERING DATA FROM DAMAGED FILES
+.I bzip2
+compresses files in blocks, usually 900kbytes long.  Each
+block is handled independently.  If a media or transmission error causes
+a multi-block .bz2
+file to become damaged, it may be possible to
+recover data from the undamaged blocks in the file.
+
+The compressed representation of each block is delimited by a 48-bit
+pattern, which makes it possible to find the block boundaries with
+reasonable certainty.  Each block also carries its own 32-bit CRC, so
+damaged blocks can be distinguished from undamaged ones.
+
+.I bzip2recover
+is a simple program whose purpose is to search for
+blocks in .bz2 files, and write each block out into its own .bz2 
+file.  You can then use
+.I bzip2 
+\-t
+to test the
+integrity of the resulting files, and decompress those which are
+undamaged.
+
+.I bzip2recover
+takes a single argument, the name of the damaged file, 
+and writes a number of files "rec00001file.bz2",
+"rec00002file.bz2", etc, containing the  extracted  blocks.
+The  output  filenames  are  designed  so  that the use of
+wildcards in subsequent processing -- for example,  
+"bzip2 -dc  rec*file.bz2 > recovered_data" -- processes the files in
+the correct order.
+
+.I bzip2recover
+should be of most use dealing with large .bz2
+files,  as  these will contain many blocks.  It is clearly
+futile to use it on damaged single-block  files,  since  a
+damaged  block  cannot  be recovered.  If you wish to minimise 
+any potential data loss through media  or  transmission errors, 
+you might consider compressing with a smaller
+block size.
+
+.SH PERFORMANCE NOTES
+The sorting phase of compression gathers together similar strings in the
+file.  Because of this, files containing very long runs of repeated
+symbols, like "aabaabaabaab ..."  (repeated several hundred times) may
+compress more slowly than normal.  Versions 0.9.5 and above fare much
+better than previous versions in this respect.  The ratio between
+worst-case and average-case compression time is in the region of 10:1.
+For previous versions, this figure was more like 100:1.  You can use the
+\-vvvv option to monitor progress in great detail, if you want.
+
+Decompression speed is unaffected by these phenomena.
+
+.I bzip2
+usually allocates several megabytes of memory to operate
+in, and then charges all over it in a fairly random fashion.  This means
+that performance, both for compressing and decompressing, is largely
+determined by the speed at which your machine can service cache misses.
+Because of this, small changes to the code to reduce the miss rate have
+been observed to give disproportionately large performance improvements.
+I imagine 
+.I bzip2
+will perform best on machines with very large caches.
+
+.SH CAVEATS
+I/O error messages are not as helpful as they could be.
+.I bzip2
+tries hard to detect I/O errors and exit cleanly, but the details of
+what the problem is sometimes seem rather misleading.
+
+This manual page pertains to version 1.0.6 of
+.I bzip2.  
+Compressed data created by this version is entirely forwards and
+backwards compatible with the previous public releases, versions
+0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1, 1.0.2 and above, but with the following
+exception: 0.9.0 and above can correctly decompress multiple
+concatenated compressed files.  0.1pl2 cannot do this; it will stop
+after decompressing just the first file in the stream.
+
+.I bzip2recover
+versions prior to 1.0.2 used 32-bit integers to represent
+bit positions in compressed files, so they could not handle compressed
+files more than 512 megabytes long.  Versions 1.0.2 and above use
+64-bit ints on some platforms which support them (GNU supported
+targets, and Windows).  To establish whether or not bzip2recover was
+built with such a limitation, run it without arguments.  In any event
+you can build yourself an unlimited version if you can recompile it
+with MaybeUInt64 set to be an unsigned 64-bit integer.
+
+
+
+.SH AUTHOR
+Julian Seward, jsewardbzip.org.
+
+http://www.bzip.org
+
+The ideas embodied in
+.I bzip2
+are due to (at least) the following
+people: Michael Burrows and David Wheeler (for the block sorting
+transformation), David Wheeler (again, for the Huffman coder), Peter
+Fenwick (for the structured coding model in the original
+.I bzip,
+and many refinements), and Alistair Moffat, Radford Neal and Ian Witten
+(for the arithmetic coder in the original
+.I bzip).  
+I am much
+indebted for their help, support and advice.  See the manual in the
+source distribution for pointers to sources of documentation.  Christian
+von Roques encouraged me to look for faster sorting algorithms, so as to
+speed up compression.  Bela Lubkin encouraged me to improve the
+worst-case compression performance.  
+Donna Robinson XMLised the documentation.
+The bz* scripts are derived from those of GNU gzip.
+Many people sent patches, helped
+with portability problems, lent machines, gave advice and were generally
+helpful.
diff --git a/source/Irrlicht/bzip2/bzip2.1.preformatted b/source/Irrlicht/bzip2/bzip2.1.preformatted
new file mode 100644
index 00000000..63c33be9
--- /dev/null
+++ b/source/Irrlicht/bzip2/bzip2.1.preformatted
@@ -0,0 +1,399 @@
+bzip2(1)                                                 bzip2(1)
+
+
+
+NNAAMMEE
+       bzip2, bunzip2 − a block‐sorting file compressor, v1.0.6
+       bzcat − decompresses files to stdout
+       bzip2recover − recovers data from damaged bzip2 files
+
+
+SSYYNNOOPPSSIISS
+       bbzziipp22 [ −−ccddffkkqqssttvvzzVVLL112233445566778899 ] [ _f_i_l_e_n_a_m_e_s _._._.  ]
+       bbuunnzziipp22 [ −−ffkkvvssVVLL ] [ _f_i_l_e_n_a_m_e_s _._._.  ]
+       bbzzccaatt [ −−ss ] [ _f_i_l_e_n_a_m_e_s _._._.  ]
+       bbzziipp22rreeccoovveerr _f_i_l_e_n_a_m_e
+
+
+DDEESSCCRRIIPPTTIIOONN
+       _b_z_i_p_2  compresses  files  using  the Burrows‐Wheeler block
+       sorting text compression algorithm,  and  Huffman  coding.
+       Compression  is  generally  considerably  better than that
+       achieved by more conventional LZ77/LZ78‐based compressors,
+       and  approaches  the performance of the PPM family of sta­
+       tistical compressors.
+
+       The command‐line options are deliberately very similar  to
+       those of _G_N_U _g_z_i_p_, but they are not identical.
+
+       _b_z_i_p_2  expects  a list of file names to accompany the com­
+       mand‐line flags.  Each file is replaced  by  a  compressed
+       version  of  itself,  with  the  name "original_name.bz2".
+       Each compressed file has the same modification date,  per­
+       missions, and, when possible, ownership as the correspond­
+       ing original, so that these properties  can  be  correctly
+       restored  at  decompression  time.   File name handling is
+       naive in the sense that there is no mechanism for preserv­
+       ing  original file names, permissions, ownerships or dates
+       in filesystems which lack these concepts, or have  serious
+       file name length restrictions, such as MS‐DOS.
+
+       _b_z_i_p_2  and  _b_u_n_z_i_p_2 will by default not overwrite existing
+       files.  If you want this to happen, specify the −f flag.
+
+       If no file names  are  specified,  _b_z_i_p_2  compresses  from
+       standard  input  to  standard output.  In this case, _b_z_i_p_2
+       will decline to write compressed output to a terminal,  as
+       this  would  be  entirely  incomprehensible  and therefore
+       pointless.
+
+       _b_u_n_z_i_p_2 (or _b_z_i_p_2 _−_d_) decompresses  all  specified  files.
+       Files which were not created by _b_z_i_p_2 will be detected and
+       ignored, and a warning issued.  _b_z_i_p_2  attempts  to  guess
+       the  filename  for  the decompressed file from that of the
+       compressed file as follows:
+
+              filename.bz2    becomes   filename
+              filename.bz     becomes   filename
+              filename.tbz2   becomes   filename.tar
+              filename.tbz    becomes   filename.tar
+              anyothername    becomes   anyothername.out
+
+       If the file does not end in one of the recognised endings,
+       _._b_z_2_,  _._b_z_,  _._t_b_z_2 or _._t_b_z_, _b_z_i_p_2 complains that it cannot
+       guess the name of the original file, and uses the original
+       name with _._o_u_t appended.
+
+       As  with compression, supplying no filenames causes decom­
+       pression from standard input to standard output.
+
+       _b_u_n_z_i_p_2 will correctly decompress a file which is the con­
+       catenation of two or more compressed files.  The result is
+       the concatenation of the corresponding uncompressed files.
+       Integrity testing (−t) of concatenated compressed files is
+       also supported.
+
+       You can also compress or decompress files to the  standard
+       output  by giving the −c flag.  Multiple files may be com­
+       pressed and decompressed like this.  The resulting outputs
+       are  fed  sequentially to stdout.  Compression of multiple
+       files in this manner generates a stream containing  multi­
+       ple compressed file representations.  Such a stream can be
+       decompressed correctly only  by  _b_z_i_p_2  version  0.9.0  or
+       later.   Earlier  versions of _b_z_i_p_2 will stop after decom­
+       pressing the first file in the stream.
+
+       _b_z_c_a_t (or _b_z_i_p_2 _‐_d_c_) decompresses all specified  files  to
+       the standard output.
+
+       _b_z_i_p_2  will  read arguments from the environment variables
+       _B_Z_I_P_2 and _B_Z_I_P_, in  that  order,  and  will  process  them
+       before  any  arguments  read  from the command line.  This
+       gives a convenient way to supply default arguments.
+
+       Compression is always performed, even  if  the  compressed
+       file  is slightly larger than the original.  Files of less
+       than about one hundred bytes tend to get larger, since the
+       compression  mechanism  has  a  constant  overhead  in the
+       region of 50 bytes.  Random data (including the output  of
+       most  file  compressors)  is  coded at about 8.05 bits per
+       byte, giving an expansion of around 0.5%.
+
+       As a self‐check for your  protection,  _b_z_i_p_2  uses  32‐bit
+       CRCs  to make sure that the decompressed version of a file
+       is identical to the original.  This guards against corrup­
+       tion  of  the compressed data, and against undetected bugs
+       in _b_z_i_p_2 (hopefully very unlikely).  The chances  of  data
+       corruption  going  undetected  is  microscopic,  about one
+       chance in four billion for each file processed.  Be aware,
+       though,  that  the  check occurs upon decompression, so it
+       can only tell you that something is wrong.  It can’t  help
+       you  recover  the original uncompressed data.  You can use
+       _b_z_i_p_2_r_e_c_o_v_e_r to try to recover data from damaged files.
+
+       Return values: 0 for a normal exit,  1  for  environmental
+       problems  (file not found, invalid flags, I/O errors, &c),
+       2 to indicate a corrupt compressed file, 3 for an internal
+       consistency error (eg, bug) which caused _b_z_i_p_2 to panic.
+
+
+OOPPTTIIOONNSS
+       −−cc ‐‐‐‐ssttddoouutt
+              Compress or decompress to standard output.
+
+       −−dd ‐‐‐‐ddeeccoommpprreessss
+              Force  decompression.  _b_z_i_p_2_, _b_u_n_z_i_p_2 and _b_z_c_a_t are
+              really the same program,  and  the  decision  about
+              what  actions to take is done on the basis of which
+              name is used.  This flag overrides that  mechanism,
+              and forces _b_z_i_p_2 to decompress.
+
+       −−zz ‐‐‐‐ccoommpprreessss
+              The   complement   to   −d:   forces   compression,
+              regardless of the invocation name.
+
+       −−tt ‐‐‐‐tteesstt
+              Check integrity of the specified file(s), but don’t
+              decompress  them.   This  really  performs  a trial
+              decompression and throws away the result.
+
+       −−ff ‐‐‐‐ffoorrccee
+              Force overwrite of output files.   Normally,  _b_z_i_p_2
+              will  not  overwrite  existing  output files.  Also
+              forces _b_z_i_p_2 to break hard links to files, which it
+              otherwise wouldn’t do.
+
+              bzip2  normally  declines to decompress files which
+              don’t have the  correct  magic  header  bytes.   If
+              forced  (‐f),  however,  it  will  pass  such files
+              through unmodified.  This is how GNU gzip  behaves.
+
+       −−kk ‐‐‐‐kkeeeepp
+              Keep  (don’t delete) input files during compression
+              or decompression.
+
+       −−ss ‐‐‐‐ssmmaallll
+              Reduce memory usage, for compression, decompression
+              and  testing.   Files  are  decompressed and tested
+              using a modified algorithm which only requires  2.5
+              bytes  per  block byte.  This means any file can be
+              decompressed in 2300k of memory,  albeit  at  about
+              half the normal speed.
+
+              During  compression,  −s  selects  a  block size of
+              200k, which limits memory use to  around  the  same
+              figure,  at  the expense of your compression ratio.
+              In short, if your  machine  is  low  on  memory  (8
+              megabytes  or  less),  use  −s for everything.  See
+              MEMORY MANAGEMENT below.
+
+       −−qq ‐‐‐‐qquuiieett
+              Suppress non‐essential warning messages.   Messages
+              pertaining  to I/O errors and other critical events
+              will not be suppressed.
+
+       −−vv ‐‐‐‐vveerrbboossee
+              Verbose mode ‐‐ show the compression ratio for each
+              file  processed.   Further  −v’s  increase the ver­
+              bosity level, spewing out lots of information which
+              is primarily of interest for diagnostic purposes.
+
+       −−LL ‐‐‐‐lliicceennssee ‐‐VV ‐‐‐‐vveerrssiioonn
+              Display  the  software  version,  license terms and
+              conditions.
+
+       −−11 ((oorr −−−−ffaasstt)) ttoo −−99 ((oorr −−−−bbeesstt))
+              Set the block size to 100 k, 200 k ..  900  k  when
+              compressing.   Has  no  effect  when decompressing.
+              See MEMORY MANAGEMENT below.  The −−fast and −−best
+              aliases  are  primarily for GNU gzip compatibility.
+              In particular, −−fast doesn’t make things  signifi­
+              cantly  faster.   And  −−best  merely  selects  the
+              default behaviour.
+
+       −−‐‐     Treats all subsequent arguments as file names, even
+              if they start with a dash.  This is so you can han­
+              dle files with names beginning  with  a  dash,  for
+              example: bzip2 −‐ −myfilename.
+
+       −−‐‐rreeppeettiittiivvee‐‐ffaasstt ‐‐‐‐rreeppeettiittiivvee‐‐bbeesstt
+              These  flags  are  redundant  in versions 0.9.5 and
+              above.  They provided some coarse control over  the
+              behaviour  of the sorting algorithm in earlier ver­
+              sions, which was sometimes useful.  0.9.5 and above
+              have  an  improved  algorithm  which  renders these
+              flags irrelevant.
+
+
+MMEEMMOORRYY MMAANNAAGGEEMMEENNTT
+       _b_z_i_p_2 compresses large files in blocks.   The  block  size
+       affects  both  the  compression  ratio  achieved,  and the
+       amount of memory needed for compression and decompression.
+       The  flags  −1  through  −9  specify  the block size to be
+       100,000 bytes through 900,000 bytes (the default)  respec­
+       tively.   At  decompression  time, the block size used for
+       compression is read from  the  header  of  the  compressed
+       file, and _b_u_n_z_i_p_2 then allocates itself just enough memory
+       to decompress the file.  Since block sizes are  stored  in
+       compressed  files,  it follows that the flags −1 to −9 are
+       irrelevant to and so ignored during decompression.
+
+       Compression and decompression requirements, in bytes,  can
+       be estimated as:
+
+              Compression:   400k + ( 8 x block size )
+
+              Decompression: 100k + ( 4 x block size ), or
+                             100k + ( 2.5 x block size )
+
+       Larger  block  sizes  give  rapidly  diminishing  marginal
+       returns.  Most of the compression comes from the first two
+       or  three hundred k of block size, a fact worth bearing in
+       mind when using _b_z_i_p_2  on  small  machines.   It  is  also
+       important  to  appreciate  that  the  decompression memory
+       requirement is set at compression time by  the  choice  of
+       block size.
+
+       For  files  compressed  with  the default 900k block size,
+       _b_u_n_z_i_p_2 will require about 3700 kbytes to decompress.   To
+       support decompression of any file on a 4 megabyte machine,
+       _b_u_n_z_i_p_2 has an option to  decompress  using  approximately
+       half this amount of memory, about 2300 kbytes.  Decompres­
+       sion speed is also halved, so you should use  this  option
+       only where necessary.  The relevant flag is ‐s.
+
+       In general, try and use the largest block size memory con­
+       straints  allow,  since  that  maximises  the  compression
+       achieved.   Compression and decompression speed are virtu­
+       ally unaffected by block size.
+
+       Another significant point applies to files which fit in  a
+       single  block  ‐‐  that  means  most files you’d encounter
+       using a large block  size.   The  amount  of  real  memory
+       touched is proportional to the size of the file, since the
+       file is smaller than a block.  For example, compressing  a
+       file  20,000  bytes  long  with the flag ‐9 will cause the
+       compressor to allocate around 7600k of  memory,  but  only
+       touch 400k + 20000 * 8 = 560 kbytes of it.  Similarly, the
+       decompressor will allocate 3700k but  only  touch  100k  +
+       20000 * 4 = 180 kbytes.
+
+       Here  is a table which summarises the maximum memory usage
+       for different block sizes.  Also  recorded  is  the  total
+       compressed  size for 14 files of the Calgary Text Compres­
+       sion Corpus totalling 3,141,622 bytes.  This column  gives
+       some  feel  for  how  compression  varies with block size.
+       These figures tend to understate the advantage  of  larger
+       block  sizes  for  larger files, since the Corpus is domi­
+       nated by smaller files.
+
+                  Compress   Decompress   Decompress   Corpus
+           Flag     usage      usage       ‐s usage     Size
+
+            ‐1      1200k       500k         350k      914704
+            ‐2      2000k       900k         600k      877703
+            ‐3      2800k      1300k         850k      860338
+            ‐4      3600k      1700k        1100k      846899
+            ‐5      4400k      2100k        1350k      845160
+            ‐6      5200k      2500k        1600k      838626
+            ‐7      6100k      2900k        1850k      834096
+            ‐8      6800k      3300k        2100k      828642
+            ‐9      7600k      3700k        2350k      828642
+
+
+RREECCOOVVEERRIINNGG DDAATTAA FFRROOMM DDAAMMAAGGEEDD FFIILLEESS
+       _b_z_i_p_2 compresses files in blocks, usually 900kbytes  long.
+       Each block is handled independently.  If a media or trans­
+       mission error causes a multi‐block  .bz2  file  to  become
+       damaged,  it  may  be  possible  to  recover data from the
+       undamaged blocks in the file.
+
+       The compressed representation of each block  is  delimited
+       by  a  48‐bit pattern, which makes it possible to find the
+       block boundaries with reasonable  certainty.   Each  block
+       also  carries its own 32‐bit CRC, so damaged blocks can be
+       distinguished from undamaged ones.
+
+       _b_z_i_p_2_r_e_c_o_v_e_r is a  simple  program  whose  purpose  is  to
+       search  for blocks in .bz2 files, and write each block out
+       into its own .bz2 file.  You can then use _b_z_i_p_2 −t to test
+       the integrity of the resulting files, and decompress those
+       which are undamaged.
+
+       _b_z_i_p_2_r_e_c_o_v_e_r takes a single argument, the name of the dam­
+       aged    file,    and    writes    a    number   of   files
+       "rec00001file.bz2",  "rec00002file.bz2",  etc,  containing
+       the   extracted   blocks.   The   output   filenames   are
+       designed  so  that the use of wildcards in subsequent pro­
+       cessing  ‐‐ for example, "bzip2 ‐dc  rec*file.bz2 > recov­
+       ered_data" ‐‐ processes the files in the correct order.
+
+       _b_z_i_p_2_r_e_c_o_v_e_r should be of most use dealing with large .bz2
+       files,  as  these will contain many blocks.  It is clearly
+       futile to use it on damaged single‐block  files,  since  a
+       damaged  block  cannot  be recovered.  If you wish to min­
+       imise any potential data loss through media  or  transmis­
+       sion errors, you might consider compressing with a smaller
+       block size.
+
+
+PPEERRFFOORRMMAANNCCEE NNOOTTEESS
+       The sorting phase of compression gathers together  similar
+       strings  in  the  file.  Because of this, files containing
+       very long runs of  repeated  symbols,  like  "aabaabaabaab
+       ..."   (repeated  several hundred times) may compress more
+       slowly than normal.  Versions 0.9.5 and  above  fare  much
+       better  than previous versions in this respect.  The ratio
+       between worst‐case and average‐case compression time is in
+       the  region  of  10:1.  For previous versions, this figure
+       was more like 100:1.  You can use the −vvvv option to mon­
+       itor progress in great detail, if you want.
+
+       Decompression speed is unaffected by these phenomena.
+
+       _b_z_i_p_2  usually  allocates  several  megabytes of memory to
+       operate in, and then charges all over it in a fairly  ran­
+       dom  fashion.   This means that performance, both for com­
+       pressing and decompressing, is largely determined  by  the
+       speed  at  which  your  machine  can service cache misses.
+       Because of this, small changes to the code to  reduce  the
+       miss  rate  have  been observed to give disproportionately
+       large performance improvements.  I imagine _b_z_i_p_2 will per­
+       form best on machines with very large caches.
+
+
+CCAAVVEEAATTSS
+       I/O  error  messages  are not as helpful as they could be.
+       _b_z_i_p_2 tries hard to detect I/O errors  and  exit  cleanly,
+       but  the  details  of  what  the problem is sometimes seem
+       rather misleading.
+
+       This manual page pertains to version 1.0.6 of _b_z_i_p_2_.  Com­
+       pressed  data created by this version is entirely forwards
+       and  backwards  compatible  with   the   previous   public
+       releases,  versions  0.1pl2,  0.9.0,  0.9.5, 1.0.0, 1.0.1, 
+       1.0.2 and above, but with the  following  exception: 0.9.0
+       and above can  correctly decompress  multiple concatenated
+       compressed files.  0.1pl2  cannot do this;  it  will  stop 
+       after  decompressing just the first file in the stream.
+
+       _b_z_i_p_2_r_e_c_o_v_e_r  versions prior to 1.0.2 used 32‐bit integers
+       to represent bit positions in compressed  files,  so  they
+       could  not handle compressed files more than 512 megabytes
+       long.  Versions 1.0.2 and above use 64‐bit  ints  on  some
+       platforms  which  support them (GNU supported targets, and
+       Windows).  To establish whether or  not  bzip2recover  was
+       built  with  such  a limitation, run it without arguments.
+       In any event you can build yourself an  unlimited  version
+       if  you  can  recompile  it  with MaybeUInt64 set to be an
+       unsigned 64‐bit integer.
+
+
+
+
+AAUUTTHHOORR
+       Julian Seward, jsewardbzip.org.
+
+       http://www.bzip.org
+
+       The ideas embodied in _b_z_i_p_2 are due to (at least) the fol­
+       lowing  people: Michael Burrows and David Wheeler (for the
+       block sorting transformation), David Wheeler  (again,  for
+       the Huffman coder), Peter Fenwick (for the structured cod­
+       ing model in the original _b_z_i_p_, and many refinements), and
+       Alistair  Moffat,  Radford  Neal  and  Ian Witten (for the
+       arithmetic  coder  in  the  original  _b_z_i_p_)_.   I  am  much
+       indebted for their help, support and advice.  See the man­
+       ual in the source distribution for pointers to sources  of
+       documentation.  Christian von Roques encouraged me to look
+       for faster sorting algorithms, so as to speed up  compres­
+       sion.  Bela Lubkin encouraged me to improve the worst‐case
+       compression performance.  Donna Robinson XMLised the docu­
+       mentation.   The bz* scripts are derived from those of GNU
+       gzip.  Many people sent patches, helped  with  portability
+       problems,  lent  machines,  gave advice and were generally
+       helpful.
+
+
+
+                                                         bzip2(1)
diff --git a/source/Irrlicht/bzip2/bzip2.c b/source/Irrlicht/bzip2/bzip2.c
new file mode 100644
index 00000000..6de9d1d1
--- /dev/null
+++ b/source/Irrlicht/bzip2/bzip2.c
@@ -0,0 +1,2034 @@
+
+/*-----------------------------------------------------------*/
+/*--- A block-sorting, lossless compressor        bzip2.c ---*/
+/*-----------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+/* Place a 1 beside your platform, and 0 elsewhere.
+   Generic 32-bit Unix.
+   Also works on 64-bit Unix boxes.
+   This is the default.
+*/
+#define BZ_UNIX      1
+
+/*--
+  Win32, as seen by Jacob Navia's excellent
+  port of (Chris Fraser & David Hanson)'s excellent
+  lcc compiler.  Or with MS Visual C.
+  This is selected automatically if compiled by a compiler which
+  defines _WIN32, not including the Cygwin GCC.
+--*/
+#define BZ_LCCWIN32  0
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#undef  BZ_LCCWIN32
+#define BZ_LCCWIN32 1
+#undef  BZ_UNIX
+#define BZ_UNIX 0
+#endif
+
+
+/*---------------------------------------------*/
+/*--
+  Some stuff for all platforms.
+--*/
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "bzlib.h"
+
+#define ERROR_IF_EOF(i)       { if ((i) == EOF)  ioError(); }
+#define ERROR_IF_NOT_ZERO(i)  { if ((i) != 0)    ioError(); }
+#define ERROR_IF_MINUS_ONE(i) { if ((i) == (-1)) ioError(); }
+
+
+/*---------------------------------------------*/
+/*--
+   Platform-specific stuff.
+--*/
+
+#if BZ_UNIX
+#   include 
+#   include 
+#   include 
+#   include 
+#   include 
+#   include 
+
+#   define PATH_SEP    '/'
+#   define MY_LSTAT    lstat
+#   define MY_STAT     stat
+#   define MY_S_ISREG  S_ISREG
+#   define MY_S_ISDIR  S_ISDIR
+
+#   define APPEND_FILESPEC(root, name) \
+      root=snocString((root), (name))
+
+#   define APPEND_FLAG(root, name) \
+      root=snocString((root), (name))
+
+#   define SET_BINARY_MODE(fd) /**/
+
+#   ifdef __GNUC__
+#      define NORETURN __attribute__ ((noreturn))
+#   else
+#      define NORETURN /**/
+#   endif
+
+#   ifdef __DJGPP__
+#     include 
+#     include 
+#     undef MY_LSTAT
+#     undef MY_STAT
+#     define MY_LSTAT stat
+#     define MY_STAT stat
+#     undef SET_BINARY_MODE
+#     define SET_BINARY_MODE(fd)                        \
+        do {                                            \
+           int retVal = setmode ( fileno ( fd ),        \
+                                  O_BINARY );           \
+           ERROR_IF_MINUS_ONE ( retVal );               \
+        } while ( 0 )
+#   endif
+
+#   ifdef __CYGWIN__
+#     include 
+#     include 
+#     undef SET_BINARY_MODE
+#     define SET_BINARY_MODE(fd)                        \
+        do {                                            \
+           int retVal = setmode ( fileno ( fd ),        \
+                                  O_BINARY );           \
+           ERROR_IF_MINUS_ONE ( retVal );               \
+        } while ( 0 )
+#   endif
+#endif /* BZ_UNIX */
+
+
+
+#if BZ_LCCWIN32
+#   include 
+#   include 
+#   include 
+
+#   define NORETURN       /**/
+#   define PATH_SEP       '\\'
+#   define MY_LSTAT       _stat
+#   define MY_STAT        _stat
+#   define MY_S_ISREG(x)  ((x) & _S_IFREG)
+#   define MY_S_ISDIR(x)  ((x) & _S_IFDIR)
+
+#   define APPEND_FLAG(root, name) \
+      root=snocString((root), (name))
+
+#   define APPEND_FILESPEC(root, name)                \
+      root = snocString ((root), (name))
+
+#   define SET_BINARY_MODE(fd)                        \
+      do {                                            \
+         int retVal = setmode ( fileno ( fd ),        \
+                                O_BINARY );           \
+         ERROR_IF_MINUS_ONE ( retVal );               \
+      } while ( 0 )
+
+#endif /* BZ_LCCWIN32 */
+
+
+/*---------------------------------------------*/
+/*--
+  Some more stuff for all platforms :-)
+--*/
+
+typedef char            Char;
+typedef unsigned char   Bool;
+typedef unsigned char   UChar;
+typedef int             Int32;
+typedef unsigned int    UInt32;
+typedef short           Int16;
+typedef unsigned short  UInt16;
+                                       
+#define True  ((Bool)1)
+#define False ((Bool)0)
+
+/*--
+  IntNative is your platform's `native' int size.
+  Only here to avoid probs with 64-bit platforms.
+--*/
+typedef int IntNative;
+
+
+/*---------------------------------------------------*/
+/*--- Misc (file handling) data decls             ---*/
+/*---------------------------------------------------*/
+
+Int32   verbosity;
+Bool    keepInputFiles, smallMode, deleteOutputOnInterrupt;
+Bool    forceOverwrite, testFailsExist, unzFailsExist, noisy;
+Int32   numFileNames, numFilesProcessed, blockSize100k;
+Int32   exitValue;
+
+/*-- source modes; F==file, I==stdin, O==stdout --*/
+#define SM_I2O           1
+#define SM_F2O           2
+#define SM_F2F           3
+
+/*-- operation modes --*/
+#define OM_Z             1
+#define OM_UNZ           2
+#define OM_TEST          3
+
+Int32   opMode;
+Int32   srcMode;
+
+#define FILE_NAME_LEN 1034
+
+Int32   longestFileName;
+Char    inName [FILE_NAME_LEN];
+Char    outName[FILE_NAME_LEN];
+Char    tmpName[FILE_NAME_LEN];
+Char    *progName;
+Char    progNameReally[FILE_NAME_LEN];
+FILE    *outputHandleJustInCase;
+Int32   workFactor;
+
+static void    panic                 ( const Char* ) NORETURN;
+static void    ioError               ( void )        NORETURN;
+static void    outOfMemory           ( void )        NORETURN;
+static void    configError           ( void )        NORETURN;
+static void    crcError              ( void )        NORETURN;
+static void    cleanUpAndFail        ( Int32 )       NORETURN;
+static void    compressedStreamEOF   ( void )        NORETURN;
+
+static void    copyFileName ( Char*, Char* );
+static void*   myMalloc     ( Int32 );
+static void    applySavedFileAttrToOutputFile ( IntNative fd );
+
+
+
+/*---------------------------------------------------*/
+/*--- An implementation of 64-bit ints.  Sigh.    ---*/
+/*--- Roll on widespread deployment of ANSI C9X ! ---*/
+/*---------------------------------------------------*/
+
+typedef
+   struct { UChar b[8]; } 
+   UInt64;
+
+
+static
+void uInt64_from_UInt32s ( UInt64* n, UInt32 lo32, UInt32 hi32 )
+{
+   n->b[7] = (UChar)((hi32 >> 24) & 0xFF);
+   n->b[6] = (UChar)((hi32 >> 16) & 0xFF);
+   n->b[5] = (UChar)((hi32 >> 8)  & 0xFF);
+   n->b[4] = (UChar) (hi32        & 0xFF);
+   n->b[3] = (UChar)((lo32 >> 24) & 0xFF);
+   n->b[2] = (UChar)((lo32 >> 16) & 0xFF);
+   n->b[1] = (UChar)((lo32 >> 8)  & 0xFF);
+   n->b[0] = (UChar) (lo32        & 0xFF);
+}
+
+
+static
+double uInt64_to_double ( UInt64* n )
+{
+   Int32  i;
+   double base = 1.0;
+   double sum  = 0.0;
+   for (i = 0; i < 8; i++) {
+      sum  += base * (double)(n->b[i]);
+      base *= 256.0;
+   }
+   return sum;
+}
+
+
+static
+Bool uInt64_isZero ( UInt64* n )
+{
+   Int32 i;
+   for (i = 0; i < 8; i++)
+      if (n->b[i] != 0) return 0;
+   return 1;
+}
+
+
+/* Divide *n by 10, and return the remainder.  */
+static 
+Int32 uInt64_qrm10 ( UInt64* n )
+{
+   UInt32 rem, tmp;
+   Int32  i;
+   rem = 0;
+   for (i = 7; i >= 0; i--) {
+      tmp = rem * 256 + n->b[i];
+      n->b[i] = tmp / 10;
+      rem = tmp % 10;
+   }
+   return rem;
+}
+
+
+/* ... and the Whole Entire Point of all this UInt64 stuff is
+   so that we can supply the following function.
+*/
+static
+void uInt64_toAscii ( char* outbuf, UInt64* n )
+{
+   Int32  i, q;
+   UChar  buf[32];
+   Int32  nBuf   = 0;
+   UInt64 n_copy = *n;
+   do {
+      q = uInt64_qrm10 ( &n_copy );
+      buf[nBuf] = q + '0';
+      nBuf++;
+   } while (!uInt64_isZero(&n_copy));
+   outbuf[nBuf] = 0;
+   for (i = 0; i < nBuf; i++) 
+      outbuf[i] = buf[nBuf-i-1];
+}
+
+
+/*---------------------------------------------------*/
+/*--- Processing of complete files and streams    ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------*/
+static 
+Bool myfeof ( FILE* f )
+{
+   Int32 c = fgetc ( f );
+   if (c == EOF) return True;
+   ungetc ( c, f );
+   return False;
+}
+
+
+/*---------------------------------------------*/
+static 
+void compressStream ( FILE *stream, FILE *zStream )
+{
+   BZFILE* bzf = NULL;
+   UChar   ibuf[5000];
+   Int32   nIbuf;
+   UInt32  nbytes_in_lo32, nbytes_in_hi32;
+   UInt32  nbytes_out_lo32, nbytes_out_hi32;
+   Int32   bzerr, bzerr_dummy, ret;
+
+   SET_BINARY_MODE(stream);
+   SET_BINARY_MODE(zStream);
+
+   if (ferror(stream)) goto errhandler_io;
+   if (ferror(zStream)) goto errhandler_io;
+
+   bzf = BZ2_bzWriteOpen ( &bzerr, zStream, 
+                           blockSize100k, verbosity, workFactor );   
+   if (bzerr != BZ_OK) goto errhandler;
+
+   if (verbosity >= 2) fprintf ( stderr, "\n" );
+
+   while (True) {
+
+      if (myfeof(stream)) break;
+      nIbuf = fread ( ibuf, sizeof(UChar), 5000, stream );
+      if (ferror(stream)) goto errhandler_io;
+      if (nIbuf > 0) BZ2_bzWrite ( &bzerr, bzf, (void*)ibuf, nIbuf );
+      if (bzerr != BZ_OK) goto errhandler;
+
+   }
+
+   BZ2_bzWriteClose64 ( &bzerr, bzf, 0, 
+                        &nbytes_in_lo32, &nbytes_in_hi32,
+                        &nbytes_out_lo32, &nbytes_out_hi32 );
+   if (bzerr != BZ_OK) goto errhandler;
+
+   if (ferror(zStream)) goto errhandler_io;
+   ret = fflush ( zStream );
+   if (ret == EOF) goto errhandler_io;
+   if (zStream != stdout) {
+      Int32 fd = fileno ( zStream );
+      if (fd < 0) goto errhandler_io;
+      applySavedFileAttrToOutputFile ( fd );
+      ret = fclose ( zStream );
+      outputHandleJustInCase = NULL;
+      if (ret == EOF) goto errhandler_io;
+   }
+   outputHandleJustInCase = NULL;
+   if (ferror(stream)) goto errhandler_io;
+   ret = fclose ( stream );
+   if (ret == EOF) goto errhandler_io;
+
+   if (verbosity >= 1) {
+      if (nbytes_in_lo32 == 0 && nbytes_in_hi32 == 0) {
+	 fprintf ( stderr, " no data compressed.\n");
+      } else {
+	 Char   buf_nin[32], buf_nout[32];
+	 UInt64 nbytes_in,   nbytes_out;
+	 double nbytes_in_d, nbytes_out_d;
+	 uInt64_from_UInt32s ( &nbytes_in, 
+			       nbytes_in_lo32, nbytes_in_hi32 );
+	 uInt64_from_UInt32s ( &nbytes_out, 
+			       nbytes_out_lo32, nbytes_out_hi32 );
+	 nbytes_in_d  = uInt64_to_double ( &nbytes_in );
+	 nbytes_out_d = uInt64_to_double ( &nbytes_out );
+	 uInt64_toAscii ( buf_nin, &nbytes_in );
+	 uInt64_toAscii ( buf_nout, &nbytes_out );
+	 fprintf ( stderr, "%6.3f:1, %6.3f bits/byte, "
+		   "%5.2f%% saved, %s in, %s out.\n",
+		   nbytes_in_d / nbytes_out_d,
+		   (8.0 * nbytes_out_d) / nbytes_in_d,
+		   100.0 * (1.0 - nbytes_out_d / nbytes_in_d),
+		   buf_nin,
+		   buf_nout
+		 );
+      }
+   }
+
+   return;
+
+   errhandler:
+   BZ2_bzWriteClose64 ( &bzerr_dummy, bzf, 1, 
+                        &nbytes_in_lo32, &nbytes_in_hi32,
+                        &nbytes_out_lo32, &nbytes_out_hi32 );
+   switch (bzerr) {
+      case BZ_CONFIG_ERROR:
+         configError(); break;
+      case BZ_MEM_ERROR:
+         outOfMemory (); break;
+      case BZ_IO_ERROR:
+         errhandler_io:
+         ioError(); break;
+      default:
+         panic ( "compress:unexpected error" );
+   }
+
+   panic ( "compress:end" );
+   /*notreached*/
+}
+
+
+
+/*---------------------------------------------*/
+static 
+Bool uncompressStream ( FILE *zStream, FILE *stream )
+{
+   BZFILE* bzf = NULL;
+   Int32   bzerr, bzerr_dummy, ret, nread, streamNo, i;
+   UChar   obuf[5000];
+   UChar   unused[BZ_MAX_UNUSED];
+   Int32   nUnused;
+   void*   unusedTmpV;
+   UChar*  unusedTmp;
+
+   nUnused = 0;
+   streamNo = 0;
+
+   SET_BINARY_MODE(stream);
+   SET_BINARY_MODE(zStream);
+
+   if (ferror(stream)) goto errhandler_io;
+   if (ferror(zStream)) goto errhandler_io;
+
+   while (True) {
+
+      bzf = BZ2_bzReadOpen ( 
+               &bzerr, zStream, verbosity, 
+               (int)smallMode, unused, nUnused
+            );
+      if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
+      streamNo++;
+
+      while (bzerr == BZ_OK) {
+         nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 );
+         if (bzerr == BZ_DATA_ERROR_MAGIC) goto trycat;
+         if ((bzerr == BZ_OK || bzerr == BZ_STREAM_END) && nread > 0)
+            fwrite ( obuf, sizeof(UChar), nread, stream );
+         if (ferror(stream)) goto errhandler_io;
+      }
+      if (bzerr != BZ_STREAM_END) goto errhandler;
+
+      BZ2_bzReadGetUnused ( &bzerr, bzf, &unusedTmpV, &nUnused );
+      if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
+
+      unusedTmp = (UChar*)unusedTmpV;
+      for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
+
+      BZ2_bzReadClose ( &bzerr, bzf );
+      if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
+
+      if (nUnused == 0 && myfeof(zStream)) break;
+   }
+
+   closeok:
+   if (ferror(zStream)) goto errhandler_io;
+   if (stream != stdout) {
+      Int32 fd = fileno ( stream );
+      if (fd < 0) goto errhandler_io;
+      applySavedFileAttrToOutputFile ( fd );
+   }
+   ret = fclose ( zStream );
+   if (ret == EOF) goto errhandler_io;
+
+   if (ferror(stream)) goto errhandler_io;
+   ret = fflush ( stream );
+   if (ret != 0) goto errhandler_io;
+   if (stream != stdout) {
+      ret = fclose ( stream );
+      outputHandleJustInCase = NULL;
+      if (ret == EOF) goto errhandler_io;
+   }
+   outputHandleJustInCase = NULL;
+   if (verbosity >= 2) fprintf ( stderr, "\n    " );
+   return True;
+
+   trycat: 
+   if (forceOverwrite) {
+      rewind(zStream);
+      while (True) {
+      	 if (myfeof(zStream)) break;
+      	 nread = fread ( obuf, sizeof(UChar), 5000, zStream );
+      	 if (ferror(zStream)) goto errhandler_io;
+      	 if (nread > 0) fwrite ( obuf, sizeof(UChar), nread, stream );
+      	 if (ferror(stream)) goto errhandler_io;
+      }
+      goto closeok;
+   }
+  
+   errhandler:
+   BZ2_bzReadClose ( &bzerr_dummy, bzf );
+   switch (bzerr) {
+      case BZ_CONFIG_ERROR:
+         configError(); break;
+      case BZ_IO_ERROR:
+         errhandler_io:
+         ioError(); break;
+      case BZ_DATA_ERROR:
+         crcError();
+      case BZ_MEM_ERROR:
+         outOfMemory();
+      case BZ_UNEXPECTED_EOF:
+         compressedStreamEOF();
+      case BZ_DATA_ERROR_MAGIC:
+         if (zStream != stdin) fclose(zStream);
+         if (stream != stdout) fclose(stream);
+         if (streamNo == 1) {
+            return False;
+         } else {
+            if (noisy)
+            fprintf ( stderr, 
+                      "\n%s: %s: trailing garbage after EOF ignored\n",
+                      progName, inName );
+            return True;       
+         }
+      default:
+         panic ( "decompress:unexpected error" );
+   }
+
+   panic ( "decompress:end" );
+   return True; /*notreached*/
+}
+
+
+/*---------------------------------------------*/
+static 
+Bool testStream ( FILE *zStream )
+{
+   BZFILE* bzf = NULL;
+   Int32   bzerr, bzerr_dummy, ret, nread, streamNo, i;
+   UChar   obuf[5000];
+   UChar   unused[BZ_MAX_UNUSED];
+   Int32   nUnused;
+   void*   unusedTmpV;
+   UChar*  unusedTmp;
+
+   nUnused = 0;
+   streamNo = 0;
+
+   SET_BINARY_MODE(zStream);
+   if (ferror(zStream)) goto errhandler_io;
+
+   while (True) {
+
+      bzf = BZ2_bzReadOpen ( 
+               &bzerr, zStream, verbosity, 
+               (int)smallMode, unused, nUnused
+            );
+      if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
+      streamNo++;
+
+      while (bzerr == BZ_OK) {
+         nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 );
+         if (bzerr == BZ_DATA_ERROR_MAGIC) goto errhandler;
+      }
+      if (bzerr != BZ_STREAM_END) goto errhandler;
+
+      BZ2_bzReadGetUnused ( &bzerr, bzf, &unusedTmpV, &nUnused );
+      if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
+
+      unusedTmp = (UChar*)unusedTmpV;
+      for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
+
+      BZ2_bzReadClose ( &bzerr, bzf );
+      if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
+      if (nUnused == 0 && myfeof(zStream)) break;
+
+   }
+
+   if (ferror(zStream)) goto errhandler_io;
+   ret = fclose ( zStream );
+   if (ret == EOF) goto errhandler_io;
+
+   if (verbosity >= 2) fprintf ( stderr, "\n    " );
+   return True;
+
+   errhandler:
+   BZ2_bzReadClose ( &bzerr_dummy, bzf );
+   if (verbosity == 0) 
+      fprintf ( stderr, "%s: %s: ", progName, inName );
+   switch (bzerr) {
+      case BZ_CONFIG_ERROR:
+         configError(); break;
+      case BZ_IO_ERROR:
+         errhandler_io:
+         ioError(); break;
+      case BZ_DATA_ERROR:
+         fprintf ( stderr,
+                   "data integrity (CRC) error in data\n" );
+         return False;
+      case BZ_MEM_ERROR:
+         outOfMemory();
+      case BZ_UNEXPECTED_EOF:
+         fprintf ( stderr,
+                   "file ends unexpectedly\n" );
+         return False;
+      case BZ_DATA_ERROR_MAGIC:
+         if (zStream != stdin) fclose(zStream);
+         if (streamNo == 1) {
+          fprintf ( stderr, 
+                    "bad magic number (file not created by bzip2)\n" );
+            return False;
+         } else {
+            if (noisy)
+            fprintf ( stderr, 
+                      "trailing garbage after EOF ignored\n" );
+            return True;       
+         }
+      default:
+         panic ( "test:unexpected error" );
+   }
+
+   panic ( "test:end" );
+   return True; /*notreached*/
+}
+
+
+/*---------------------------------------------------*/
+/*--- Error [non-] handling grunge                ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------*/
+static
+void setExit ( Int32 v )
+{
+   if (v > exitValue) exitValue = v;
+}
+
+
+/*---------------------------------------------*/
+static 
+void cadvise ( void )
+{
+   if (noisy)
+   fprintf (
+      stderr,
+      "\nIt is possible that the compressed file(s) have become corrupted.\n"
+        "You can use the -tvv option to test integrity of such files.\n\n"
+        "You can use the `bzip2recover' program to attempt to recover\n"
+        "data from undamaged sections of corrupted files.\n\n"
+    );
+}
+
+
+/*---------------------------------------------*/
+static 
+void showFileNames ( void )
+{
+   if (noisy)
+   fprintf (
+      stderr,
+      "\tInput file = %s, output file = %s\n",
+      inName, outName 
+   );
+}
+
+
+/*---------------------------------------------*/
+static 
+void cleanUpAndFail ( Int32 ec )
+{
+   IntNative      retVal;
+   struct MY_STAT statBuf;
+
+   if ( srcMode == SM_F2F 
+        && opMode != OM_TEST
+        && deleteOutputOnInterrupt ) {
+
+      /* Check whether input file still exists.  Delete output file
+         only if input exists to avoid loss of data.  Joerg Prante, 5
+         January 2002.  (JRS 06-Jan-2002: other changes in 1.0.2 mean
+         this is less likely to happen.  But to be ultra-paranoid, we
+         do the check anyway.)  */
+      retVal = MY_STAT ( inName, &statBuf );
+      if (retVal == 0) {
+         if (noisy)
+            fprintf ( stderr, 
+                      "%s: Deleting output file %s, if it exists.\n",
+                      progName, outName );
+         if (outputHandleJustInCase != NULL)
+            fclose ( outputHandleJustInCase );
+         retVal = remove ( outName );
+         if (retVal != 0)
+            fprintf ( stderr,
+                      "%s: WARNING: deletion of output file "
+                      "(apparently) failed.\n",
+                      progName );
+      } else {
+         fprintf ( stderr,
+                   "%s: WARNING: deletion of output file suppressed\n",
+                    progName );
+         fprintf ( stderr,
+                   "%s:    since input file no longer exists.  Output file\n",
+                   progName );
+         fprintf ( stderr,
+                   "%s:    `%s' may be incomplete.\n",
+                   progName, outName );
+         fprintf ( stderr, 
+                   "%s:    I suggest doing an integrity test (bzip2 -tv)"
+                   " of it.\n",
+                   progName );
+      }
+   }
+
+   if (noisy && numFileNames > 0 && numFilesProcessed < numFileNames) {
+      fprintf ( stderr, 
+                "%s: WARNING: some files have not been processed:\n"
+                "%s:    %d specified on command line, %d not processed yet.\n\n",
+                progName, progName,
+                numFileNames, numFileNames - numFilesProcessed );
+   }
+   setExit(ec);
+   exit(exitValue);
+}
+
+
+/*---------------------------------------------*/
+static 
+void panic ( const Char* s )
+{
+   fprintf ( stderr,
+             "\n%s: PANIC -- internal consistency error:\n"
+             "\t%s\n"
+             "\tThis is a BUG.  Please report it to me at:\n"
+             "\tjseward@bzip.org\n",
+             progName, s );
+   showFileNames();
+   cleanUpAndFail( 3 );
+}
+
+
+/*---------------------------------------------*/
+static 
+void crcError ( void )
+{
+   fprintf ( stderr,
+             "\n%s: Data integrity error when decompressing.\n",
+             progName );
+   showFileNames();
+   cadvise();
+   cleanUpAndFail( 2 );
+}
+
+
+/*---------------------------------------------*/
+static 
+void compressedStreamEOF ( void )
+{
+  if (noisy) {
+    fprintf ( stderr,
+	      "\n%s: Compressed file ends unexpectedly;\n\t"
+	      "perhaps it is corrupted?  *Possible* reason follows.\n",
+	      progName );
+    perror ( progName );
+    showFileNames();
+    cadvise();
+  }
+  cleanUpAndFail( 2 );
+}
+
+
+/*---------------------------------------------*/
+static 
+void ioError ( void )
+{
+   fprintf ( stderr,
+             "\n%s: I/O or other error, bailing out.  "
+             "Possible reason follows.\n",
+             progName );
+   perror ( progName );
+   showFileNames();
+   cleanUpAndFail( 1 );
+}
+
+
+/*---------------------------------------------*/
+static 
+void mySignalCatcher ( IntNative n )
+{
+   fprintf ( stderr,
+             "\n%s: Control-C or similar caught, quitting.\n",
+             progName );
+   cleanUpAndFail(1);
+}
+
+
+/*---------------------------------------------*/
+static 
+void mySIGSEGVorSIGBUScatcher ( IntNative n )
+{
+   if (opMode == OM_Z)
+      fprintf ( 
+      stderr,
+      "\n%s: Caught a SIGSEGV or SIGBUS whilst compressing.\n"
+      "\n"
+      "   Possible causes are (most likely first):\n"
+      "   (1) This computer has unreliable memory or cache hardware\n"
+      "       (a surprisingly common problem; try a different machine.)\n"
+      "   (2) A bug in the compiler used to create this executable\n"
+      "       (unlikely, if you didn't compile bzip2 yourself.)\n"
+      "   (3) A real bug in bzip2 -- I hope this should never be the case.\n"
+      "   The user's manual, Section 4.3, has more info on (1) and (2).\n"
+      "   \n"
+      "   If you suspect this is a bug in bzip2, or are unsure about (1)\n"
+      "   or (2), feel free to report it to me at: jseward@bzip.org.\n"
+      "   Section 4.3 of the user's manual describes the info a useful\n"
+      "   bug report should have.  If the manual is available on your\n"
+      "   system, please try and read it before mailing me.  If you don't\n"
+      "   have the manual or can't be bothered to read it, mail me anyway.\n"
+      "\n",
+      progName );
+      else
+      fprintf ( 
+      stderr,
+      "\n%s: Caught a SIGSEGV or SIGBUS whilst decompressing.\n"
+      "\n"
+      "   Possible causes are (most likely first):\n"
+      "   (1) The compressed data is corrupted, and bzip2's usual checks\n"
+      "       failed to detect this.  Try bzip2 -tvv my_file.bz2.\n"
+      "   (2) This computer has unreliable memory or cache hardware\n"
+      "       (a surprisingly common problem; try a different machine.)\n"
+      "   (3) A bug in the compiler used to create this executable\n"
+      "       (unlikely, if you didn't compile bzip2 yourself.)\n"
+      "   (4) A real bug in bzip2 -- I hope this should never be the case.\n"
+      "   The user's manual, Section 4.3, has more info on (2) and (3).\n"
+      "   \n"
+      "   If you suspect this is a bug in bzip2, or are unsure about (2)\n"
+      "   or (3), feel free to report it to me at: jseward@bzip.org.\n"
+      "   Section 4.3 of the user's manual describes the info a useful\n"
+      "   bug report should have.  If the manual is available on your\n"
+      "   system, please try and read it before mailing me.  If you don't\n"
+      "   have the manual or can't be bothered to read it, mail me anyway.\n"
+      "\n",
+      progName );
+
+   showFileNames();
+   if (opMode == OM_Z)
+      cleanUpAndFail( 3 ); else
+      { cadvise(); cleanUpAndFail( 2 ); }
+}
+
+
+/*---------------------------------------------*/
+static 
+void outOfMemory ( void )
+{
+   fprintf ( stderr,
+             "\n%s: couldn't allocate enough memory\n",
+             progName );
+   showFileNames();
+   cleanUpAndFail(1);
+}
+
+
+/*---------------------------------------------*/
+static 
+void configError ( void )
+{
+   fprintf ( stderr,
+             "bzip2: I'm not configured correctly for this platform!\n"
+             "\tI require Int32, Int16 and Char to have sizes\n"
+             "\tof 4, 2 and 1 bytes to run properly, and they don't.\n"
+             "\tProbably you can fix this by defining them correctly,\n"
+             "\tand recompiling.  Bye!\n" );
+   setExit(3);
+   exit(exitValue);
+}
+
+
+/*---------------------------------------------------*/
+/*--- The main driver machinery                   ---*/
+/*---------------------------------------------------*/
+
+/* All rather crufty.  The main problem is that input files
+   are stat()d multiple times before use.  This should be
+   cleaned up. 
+*/
+
+/*---------------------------------------------*/
+static 
+void pad ( Char *s )
+{
+   Int32 i;
+   if ( (Int32)strlen(s) >= longestFileName ) return;
+   for (i = 1; i <= longestFileName - (Int32)strlen(s); i++)
+      fprintf ( stderr, " " );
+}
+
+
+/*---------------------------------------------*/
+static 
+void copyFileName ( Char* to, Char* from ) 
+{
+   if ( strlen(from) > FILE_NAME_LEN-10 )  {
+      fprintf (
+         stderr,
+         "bzip2: file name\n`%s'\n"
+         "is suspiciously (more than %d chars) long.\n"
+         "Try using a reasonable file name instead.  Sorry! :-)\n",
+         from, FILE_NAME_LEN-10
+      );
+      setExit(1);
+      exit(exitValue);
+   }
+
+  strncpy(to,from,FILE_NAME_LEN-10);
+  to[FILE_NAME_LEN-10]='\0';
+}
+
+
+/*---------------------------------------------*/
+static 
+Bool fileExists ( Char* name )
+{
+   FILE *tmp   = fopen ( name, "rb" );
+   Bool exists = (tmp != NULL);
+   if (tmp != NULL) fclose ( tmp );
+   return exists;
+}
+
+
+/*---------------------------------------------*/
+/* Open an output file safely with O_EXCL and good permissions.
+   This avoids a race condition in versions < 1.0.2, in which
+   the file was first opened and then had its interim permissions
+   set safely.  We instead use open() to create the file with
+   the interim permissions required. (--- --- rw-).
+
+   For non-Unix platforms, if we are not worrying about
+   security issues, simple this simply behaves like fopen.
+*/
+static
+FILE* fopen_output_safely ( Char* name, const char* mode )
+{
+#  if BZ_UNIX
+   FILE*     fp;
+   IntNative fh;
+   fh = open(name, O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR);
+   if (fh == -1) return NULL;
+   fp = fdopen(fh, mode);
+   if (fp == NULL) close(fh);
+   return fp;
+#  else
+   return fopen(name, mode);
+#  endif
+}
+
+
+/*---------------------------------------------*/
+/*--
+  if in doubt, return True
+--*/
+static 
+Bool notAStandardFile ( Char* name )
+{
+   IntNative      i;
+   struct MY_STAT statBuf;
+
+   i = MY_LSTAT ( name, &statBuf );
+   if (i != 0) return True;
+   if (MY_S_ISREG(statBuf.st_mode)) return False;
+   return True;
+}
+
+
+/*---------------------------------------------*/
+/*--
+  rac 11/21/98 see if file has hard links to it
+--*/
+static 
+Int32 countHardLinks ( Char* name )
+{  
+   IntNative      i;
+   struct MY_STAT statBuf;
+
+   i = MY_LSTAT ( name, &statBuf );
+   if (i != 0) return 0;
+   return (statBuf.st_nlink - 1);
+}
+
+
+/*---------------------------------------------*/
+/* Copy modification date, access date, permissions and owner from the
+   source to destination file.  We have to copy this meta-info off
+   into fileMetaInfo before starting to compress / decompress it,
+   because doing it afterwards means we get the wrong access time.
+
+   To complicate matters, in compress() and decompress() below, the
+   sequence of tests preceding the call to saveInputFileMetaInfo()
+   involves calling fileExists(), which in turn establishes its result
+   by attempting to fopen() the file, and if successful, immediately
+   fclose()ing it again.  So we have to assume that the fopen() call
+   does not cause the access time field to be updated.
+
+   Reading of the man page for stat() (man 2 stat) on RedHat 7.2 seems
+   to imply that merely doing open() will not affect the access time.
+   Therefore we merely need to hope that the C library only does
+   open() as a result of fopen(), and not any kind of read()-ahead
+   cleverness.
+
+   It sounds pretty fragile to me.  Whether this carries across
+   robustly to arbitrary Unix-like platforms (or even works robustly
+   on this one, RedHat 7.2) is unknown to me.  Nevertheless ...  
+*/
+#if BZ_UNIX
+static 
+struct MY_STAT fileMetaInfo;
+#endif
+
+static 
+void saveInputFileMetaInfo ( Char *srcName )
+{
+#  if BZ_UNIX
+   IntNative retVal;
+   /* Note use of stat here, not lstat. */
+   retVal = MY_STAT( srcName, &fileMetaInfo );
+   ERROR_IF_NOT_ZERO ( retVal );
+#  endif
+}
+
+
+static 
+void applySavedTimeInfoToOutputFile ( Char *dstName )
+{
+#  if BZ_UNIX
+   IntNative      retVal;
+   struct utimbuf uTimBuf;
+
+   uTimBuf.actime = fileMetaInfo.st_atime;
+   uTimBuf.modtime = fileMetaInfo.st_mtime;
+
+   retVal = utime ( dstName, &uTimBuf );
+   ERROR_IF_NOT_ZERO ( retVal );
+#  endif
+}
+
+static 
+void applySavedFileAttrToOutputFile ( IntNative fd )
+{
+#  if BZ_UNIX
+   IntNative retVal;
+
+   retVal = fchmod ( fd, fileMetaInfo.st_mode );
+   ERROR_IF_NOT_ZERO ( retVal );
+
+   (void) fchown ( fd, fileMetaInfo.st_uid, fileMetaInfo.st_gid );
+   /* chown() will in many cases return with EPERM, which can
+      be safely ignored.
+   */
+#  endif
+}
+
+
+/*---------------------------------------------*/
+static 
+Bool containsDubiousChars ( Char* name )
+{
+#  if BZ_UNIX
+   /* On unix, files can contain any characters and the file expansion
+    * is performed by the shell.
+    */
+   return False;
+#  else /* ! BZ_UNIX */
+   /* On non-unix (Win* platforms), wildcard characters are not allowed in 
+    * filenames.
+    */
+   for (; *name != '\0'; name++)
+      if (*name == '?' || *name == '*') return True;
+   return False;
+#  endif /* BZ_UNIX */
+}
+
+
+/*---------------------------------------------*/
+#define BZ_N_SUFFIX_PAIRS 4
+
+const Char* zSuffix[BZ_N_SUFFIX_PAIRS] 
+   = { ".bz2", ".bz", ".tbz2", ".tbz" };
+const Char* unzSuffix[BZ_N_SUFFIX_PAIRS] 
+   = { "", "", ".tar", ".tar" };
+
+static 
+Bool hasSuffix ( Char* s, const Char* suffix )
+{
+   Int32 ns = strlen(s);
+   Int32 nx = strlen(suffix);
+   if (ns < nx) return False;
+   if (strcmp(s + ns - nx, suffix) == 0) return True;
+   return False;
+}
+
+static 
+Bool mapSuffix ( Char* name, 
+                 const Char* oldSuffix, 
+                 const Char* newSuffix )
+{
+   if (!hasSuffix(name,oldSuffix)) return False;
+   name[strlen(name)-strlen(oldSuffix)] = 0;
+   strcat ( name, newSuffix );
+   return True;
+}
+
+
+/*---------------------------------------------*/
+static 
+void compress ( Char *name )
+{
+   FILE  *inStr;
+   FILE  *outStr;
+   Int32 n, i;
+   struct MY_STAT statBuf;
+
+   deleteOutputOnInterrupt = False;
+
+   if (name == NULL && srcMode != SM_I2O)
+      panic ( "compress: bad modes\n" );
+
+   switch (srcMode) {
+      case SM_I2O: 
+         copyFileName ( inName, (Char*)"(stdin)" );
+         copyFileName ( outName, (Char*)"(stdout)" ); 
+         break;
+      case SM_F2F: 
+         copyFileName ( inName, name );
+         copyFileName ( outName, name );
+         strcat ( outName, ".bz2" ); 
+         break;
+      case SM_F2O: 
+         copyFileName ( inName, name );
+         copyFileName ( outName, (Char*)"(stdout)" ); 
+         break;
+   }
+
+   if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
+      if (noisy)
+      fprintf ( stderr, "%s: There are no files matching `%s'.\n",
+                progName, inName );
+      setExit(1);
+      return;
+   }
+   if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
+      fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
+                progName, inName, strerror(errno) );
+      setExit(1);
+      return;
+   }
+   for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++) {
+      if (hasSuffix(inName, zSuffix[i])) {
+         if (noisy)
+         fprintf ( stderr, 
+                   "%s: Input file %s already has %s suffix.\n",
+                   progName, inName, zSuffix[i] );
+         setExit(1);
+         return;
+      }
+   }
+   if ( srcMode == SM_F2F || srcMode == SM_F2O ) {
+      MY_STAT(inName, &statBuf);
+      if ( MY_S_ISDIR(statBuf.st_mode) ) {
+         fprintf( stderr,
+                  "%s: Input file %s is a directory.\n",
+                  progName,inName);
+         setExit(1);
+         return;
+      }
+   }
+   if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
+      if (noisy)
+      fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
+                progName, inName );
+      setExit(1);
+      return;
+   }
+   if ( srcMode == SM_F2F && fileExists ( outName ) ) {
+      if (forceOverwrite) {
+	 remove(outName);
+      } else {
+	 fprintf ( stderr, "%s: Output file %s already exists.\n",
+		   progName, outName );
+	 setExit(1);
+	 return;
+      }
+   }
+   if ( srcMode == SM_F2F && !forceOverwrite &&
+        (n=countHardLinks ( inName )) > 0) {
+      fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
+                progName, inName, n, n > 1 ? "s" : "" );
+      setExit(1);
+      return;
+   }
+
+   if ( srcMode == SM_F2F ) {
+      /* Save the file's meta-info before we open it.  Doing it later
+         means we mess up the access times. */
+      saveInputFileMetaInfo ( inName );
+   }
+
+   switch ( srcMode ) {
+
+      case SM_I2O:
+         inStr = stdin;
+         outStr = stdout;
+         if ( isatty ( fileno ( stdout ) ) ) {
+            fprintf ( stderr,
+                      "%s: I won't write compressed data to a terminal.\n",
+                      progName );
+            fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
+                              progName, progName );
+            setExit(1);
+            return;
+         };
+         break;
+
+      case SM_F2O:
+         inStr = fopen ( inName, "rb" );
+         outStr = stdout;
+         if ( isatty ( fileno ( stdout ) ) ) {
+            fprintf ( stderr,
+                      "%s: I won't write compressed data to a terminal.\n",
+                      progName );
+            fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
+                              progName, progName );
+            if ( inStr != NULL ) fclose ( inStr );
+            setExit(1);
+            return;
+         };
+         if ( inStr == NULL ) {
+            fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
+                      progName, inName, strerror(errno) );
+            setExit(1);
+            return;
+         };
+         break;
+
+      case SM_F2F:
+         inStr = fopen ( inName, "rb" );
+         outStr = fopen_output_safely ( outName, "wb" );
+         if ( outStr == NULL) {
+            fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
+                      progName, outName, strerror(errno) );
+            if ( inStr != NULL ) fclose ( inStr );
+            setExit(1);
+            return;
+         }
+         if ( inStr == NULL ) {
+            fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
+                      progName, inName, strerror(errno) );
+            if ( outStr != NULL ) fclose ( outStr );
+            setExit(1);
+            return;
+         };
+         break;
+
+      default:
+         panic ( "compress: bad srcMode" );
+         break;
+   }
+
+   if (verbosity >= 1) {
+      fprintf ( stderr,  "  %s: ", inName );
+      pad ( inName );
+      fflush ( stderr );
+   }
+
+   /*--- Now the input and output handles are sane.  Do the Biz. ---*/
+   outputHandleJustInCase = outStr;
+   deleteOutputOnInterrupt = True;
+   compressStream ( inStr, outStr );
+   outputHandleJustInCase = NULL;
+
+   /*--- If there was an I/O error, we won't get here. ---*/
+   if ( srcMode == SM_F2F ) {
+      applySavedTimeInfoToOutputFile ( outName );
+      deleteOutputOnInterrupt = False;
+      if ( !keepInputFiles ) {
+         IntNative retVal = remove ( inName );
+         ERROR_IF_NOT_ZERO ( retVal );
+      }
+   }
+
+   deleteOutputOnInterrupt = False;
+}
+
+
+/*---------------------------------------------*/
+static 
+void uncompress ( Char *name )
+{
+   FILE  *inStr;
+   FILE  *outStr;
+   Int32 n, i;
+   Bool  magicNumberOK;
+   Bool  cantGuess;
+   struct MY_STAT statBuf;
+
+   deleteOutputOnInterrupt = False;
+
+   if (name == NULL && srcMode != SM_I2O)
+      panic ( "uncompress: bad modes\n" );
+
+   cantGuess = False;
+   switch (srcMode) {
+      case SM_I2O: 
+         copyFileName ( inName, (Char*)"(stdin)" );
+         copyFileName ( outName, (Char*)"(stdout)" ); 
+         break;
+      case SM_F2F: 
+         copyFileName ( inName, name );
+         copyFileName ( outName, name );
+         for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++)
+            if (mapSuffix(outName,zSuffix[i],unzSuffix[i]))
+               goto zzz; 
+         cantGuess = True;
+         strcat ( outName, ".out" );
+         break;
+      case SM_F2O: 
+         copyFileName ( inName, name );
+         copyFileName ( outName, (Char*)"(stdout)" ); 
+         break;
+   }
+
+   zzz:
+   if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
+      if (noisy)
+      fprintf ( stderr, "%s: There are no files matching `%s'.\n",
+                progName, inName );
+      setExit(1);
+      return;
+   }
+   if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
+      fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
+                progName, inName, strerror(errno) );
+      setExit(1);
+      return;
+   }
+   if ( srcMode == SM_F2F || srcMode == SM_F2O ) {
+      MY_STAT(inName, &statBuf);
+      if ( MY_S_ISDIR(statBuf.st_mode) ) {
+         fprintf( stderr,
+                  "%s: Input file %s is a directory.\n",
+                  progName,inName);
+         setExit(1);
+         return;
+      }
+   }
+   if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
+      if (noisy)
+      fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
+                progName, inName );
+      setExit(1);
+      return;
+   }
+   if ( /* srcMode == SM_F2F implied && */ cantGuess ) {
+      if (noisy)
+      fprintf ( stderr, 
+                "%s: Can't guess original name for %s -- using %s\n",
+                progName, inName, outName );
+      /* just a warning, no return */
+   }   
+   if ( srcMode == SM_F2F && fileExists ( outName ) ) {
+      if (forceOverwrite) {
+	remove(outName);
+      } else {
+        fprintf ( stderr, "%s: Output file %s already exists.\n",
+                  progName, outName );
+        setExit(1);
+        return;
+      }
+   }
+   if ( srcMode == SM_F2F && !forceOverwrite &&
+        (n=countHardLinks ( inName ) ) > 0) {
+      fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
+                progName, inName, n, n > 1 ? "s" : "" );
+      setExit(1);
+      return;
+   }
+
+   if ( srcMode == SM_F2F ) {
+      /* Save the file's meta-info before we open it.  Doing it later
+         means we mess up the access times. */
+      saveInputFileMetaInfo ( inName );
+   }
+
+   switch ( srcMode ) {
+
+      case SM_I2O:
+         inStr = stdin;
+         outStr = stdout;
+         if ( isatty ( fileno ( stdin ) ) ) {
+            fprintf ( stderr,
+                      "%s: I won't read compressed data from a terminal.\n",
+                      progName );
+            fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
+                              progName, progName );
+            setExit(1);
+            return;
+         };
+         break;
+
+      case SM_F2O:
+         inStr = fopen ( inName, "rb" );
+         outStr = stdout;
+         if ( inStr == NULL ) {
+            fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
+                      progName, inName, strerror(errno) );
+            if ( inStr != NULL ) fclose ( inStr );
+            setExit(1);
+            return;
+         };
+         break;
+
+      case SM_F2F:
+         inStr = fopen ( inName, "rb" );
+         outStr = fopen_output_safely ( outName, "wb" );
+         if ( outStr == NULL) {
+            fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
+                      progName, outName, strerror(errno) );
+            if ( inStr != NULL ) fclose ( inStr );
+            setExit(1);
+            return;
+         }
+         if ( inStr == NULL ) {
+            fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
+                      progName, inName, strerror(errno) );
+            if ( outStr != NULL ) fclose ( outStr );
+            setExit(1);
+            return;
+         };
+         break;
+
+      default:
+         panic ( "uncompress: bad srcMode" );
+         break;
+   }
+
+   if (verbosity >= 1) {
+      fprintf ( stderr, "  %s: ", inName );
+      pad ( inName );
+      fflush ( stderr );
+   }
+
+   /*--- Now the input and output handles are sane.  Do the Biz. ---*/
+   outputHandleJustInCase = outStr;
+   deleteOutputOnInterrupt = True;
+   magicNumberOK = uncompressStream ( inStr, outStr );
+   outputHandleJustInCase = NULL;
+
+   /*--- If there was an I/O error, we won't get here. ---*/
+   if ( magicNumberOK ) {
+      if ( srcMode == SM_F2F ) {
+         applySavedTimeInfoToOutputFile ( outName );
+         deleteOutputOnInterrupt = False;
+         if ( !keepInputFiles ) {
+            IntNative retVal = remove ( inName );
+            ERROR_IF_NOT_ZERO ( retVal );
+         }
+      }
+   } else {
+      unzFailsExist = True;
+      deleteOutputOnInterrupt = False;
+      if ( srcMode == SM_F2F ) {
+         IntNative retVal = remove ( outName );
+         ERROR_IF_NOT_ZERO ( retVal );
+      }
+   }
+   deleteOutputOnInterrupt = False;
+
+   if ( magicNumberOK ) {
+      if (verbosity >= 1)
+         fprintf ( stderr, "done\n" );
+   } else {
+      setExit(2);
+      if (verbosity >= 1)
+         fprintf ( stderr, "not a bzip2 file.\n" ); else
+         fprintf ( stderr,
+                   "%s: %s is not a bzip2 file.\n",
+                   progName, inName );
+   }
+
+}
+
+
+/*---------------------------------------------*/
+static 
+void testf ( Char *name )
+{
+   FILE *inStr;
+   Bool allOK;
+   struct MY_STAT statBuf;
+
+   deleteOutputOnInterrupt = False;
+
+   if (name == NULL && srcMode != SM_I2O)
+      panic ( "testf: bad modes\n" );
+
+   copyFileName ( outName, (Char*)"(none)" );
+   switch (srcMode) {
+      case SM_I2O: copyFileName ( inName, (Char*)"(stdin)" ); break;
+      case SM_F2F: copyFileName ( inName, name ); break;
+      case SM_F2O: copyFileName ( inName, name ); break;
+   }
+
+   if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
+      if (noisy)
+      fprintf ( stderr, "%s: There are no files matching `%s'.\n",
+                progName, inName );
+      setExit(1);
+      return;
+   }
+   if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
+      fprintf ( stderr, "%s: Can't open input %s: %s.\n",
+                progName, inName, strerror(errno) );
+      setExit(1);
+      return;
+   }
+   if ( srcMode != SM_I2O ) {
+      MY_STAT(inName, &statBuf);
+      if ( MY_S_ISDIR(statBuf.st_mode) ) {
+         fprintf( stderr,
+                  "%s: Input file %s is a directory.\n",
+                  progName,inName);
+         setExit(1);
+         return;
+      }
+   }
+
+   switch ( srcMode ) {
+
+      case SM_I2O:
+         if ( isatty ( fileno ( stdin ) ) ) {
+            fprintf ( stderr,
+                      "%s: I won't read compressed data from a terminal.\n",
+                      progName );
+            fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
+                              progName, progName );
+            setExit(1);
+            return;
+         };
+         inStr = stdin;
+         break;
+
+      case SM_F2O: case SM_F2F:
+         inStr = fopen ( inName, "rb" );
+         if ( inStr == NULL ) {
+            fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
+                      progName, inName, strerror(errno) );
+            setExit(1);
+            return;
+         };
+         break;
+
+      default:
+         panic ( "testf: bad srcMode" );
+         break;
+   }
+
+   if (verbosity >= 1) {
+      fprintf ( stderr, "  %s: ", inName );
+      pad ( inName );
+      fflush ( stderr );
+   }
+
+   /*--- Now the input handle is sane.  Do the Biz. ---*/
+   outputHandleJustInCase = NULL;
+   allOK = testStream ( inStr );
+
+   if (allOK && verbosity >= 1) fprintf ( stderr, "ok\n" );
+   if (!allOK) testFailsExist = True;
+}
+
+
+/*---------------------------------------------*/
+static 
+void license ( void )
+{
+   fprintf ( stderr,
+
+    "bzip2, a block-sorting file compressor.  "
+    "Version %s.\n"
+    "   \n"
+    "   Copyright (C) 1996-2010 by Julian Seward.\n"
+    "   \n"
+    "   This program is free software; you can redistribute it and/or modify\n"
+    "   it under the terms set out in the LICENSE file, which is included\n"
+    "   in the bzip2-1.0.6 source distribution.\n"
+    "   \n"
+    "   This program is distributed in the hope that it will be useful,\n"
+    "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+    "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
+    "   LICENSE file for more details.\n"
+    "   \n",
+    BZ2_bzlibVersion()
+   );
+}
+
+
+/*---------------------------------------------*/
+static 
+void usage ( Char *fullProgName )
+{
+   fprintf (
+      stderr,
+      "bzip2, a block-sorting file compressor.  "
+      "Version %s.\n"
+      "\n   usage: %s [flags and input files in any order]\n"
+      "\n"
+      "   -h --help           print this message\n"
+      "   -d --decompress     force decompression\n"
+      "   -z --compress       force compression\n"
+      "   -k --keep           keep (don't delete) input files\n"
+      "   -f --force          overwrite existing output files\n"
+      "   -t --test           test compressed file integrity\n"
+      "   -c --stdout         output to standard out\n"
+      "   -q --quiet          suppress noncritical error messages\n"
+      "   -v --verbose        be verbose (a 2nd -v gives more)\n"
+      "   -L --license        display software version & license\n"
+      "   -V --version        display software version & license\n"
+      "   -s --small          use less memory (at most 2500k)\n"
+      "   -1 .. -9            set block size to 100k .. 900k\n"
+      "   --fast              alias for -1\n"
+      "   --best              alias for -9\n"
+      "\n"
+      "   If invoked as `bzip2', default action is to compress.\n"
+      "              as `bunzip2',  default action is to decompress.\n"
+      "              as `bzcat', default action is to decompress to stdout.\n"
+      "\n"
+      "   If no file names are given, bzip2 compresses or decompresses\n"
+      "   from standard input to standard output.  You can combine\n"
+      "   short flags, so `-v -4' means the same as -v4 or -4v, &c.\n"
+#     if BZ_UNIX
+      "\n"
+#     endif
+      ,
+
+      BZ2_bzlibVersion(),
+      fullProgName
+   );
+}
+
+
+/*---------------------------------------------*/
+static 
+void redundant ( Char* flag )
+{
+   fprintf ( 
+      stderr, 
+      "%s: %s is redundant in versions 0.9.5 and above\n",
+      progName, flag );
+}
+
+
+/*---------------------------------------------*/
+/*--
+  All the garbage from here to main() is purely to
+  implement a linked list of command-line arguments,
+  into which main() copies argv[1 .. argc-1].
+
+  The purpose of this exercise is to facilitate 
+  the expansion of wildcard characters * and ? in 
+  filenames for OSs which don't know how to do it
+  themselves, like MSDOS, Windows 95 and NT.
+
+  The actual Dirty Work is done by the platform-
+  specific macro APPEND_FILESPEC.
+--*/
+
+typedef
+   struct zzzz {
+      Char        *name;
+      struct zzzz *link;
+   }
+   Cell;
+
+
+/*---------------------------------------------*/
+static 
+void *myMalloc ( Int32 n )
+{
+   void* p;
+
+   p = malloc ( (size_t)n );
+   if (p == NULL) outOfMemory ();
+   return p;
+}
+
+
+/*---------------------------------------------*/
+static 
+Cell *mkCell ( void )
+{
+   Cell *c;
+
+   c = (Cell*) myMalloc ( sizeof ( Cell ) );
+   c->name = NULL;
+   c->link = NULL;
+   return c;
+}
+
+
+/*---------------------------------------------*/
+static 
+Cell *snocString ( Cell *root, Char *name )
+{
+   if (root == NULL) {
+      Cell *tmp = mkCell();
+      tmp->name = (Char*) myMalloc ( 5 + strlen(name) );
+      strcpy ( tmp->name, name );
+      return tmp;
+   } else {
+      Cell *tmp = root;
+      while (tmp->link != NULL) tmp = tmp->link;
+      tmp->link = snocString ( tmp->link, name );
+      return root;
+   }
+}
+
+
+/*---------------------------------------------*/
+static 
+void addFlagsFromEnvVar ( Cell** argList, Char* varName ) 
+{
+   Int32 i, j, k;
+   Char *envbase, *p;
+
+   envbase = getenv(varName);
+   if (envbase != NULL) {
+      p = envbase;
+      i = 0;
+      while (True) {
+         if (p[i] == 0) break;
+         p += i;
+         i = 0;
+         while (isspace((Int32)(p[0]))) p++;
+         while (p[i] != 0 && !isspace((Int32)(p[i]))) i++;
+         if (i > 0) {
+            k = i; if (k > FILE_NAME_LEN-10) k = FILE_NAME_LEN-10;
+            for (j = 0; j < k; j++) tmpName[j] = p[j];
+            tmpName[k] = 0;
+            APPEND_FLAG(*argList, tmpName);
+         }
+      }
+   }
+}
+
+
+/*---------------------------------------------*/
+#define ISFLAG(s) (strcmp(aa->name, (s))==0)
+
+IntNative main ( IntNative argc, Char *argv[] )
+{
+   Int32  i, j;
+   Char   *tmp;
+   Cell   *argList;
+   Cell   *aa;
+   Bool   decode;
+
+   /*-- Be really really really paranoid :-) --*/
+   if (sizeof(Int32) != 4 || sizeof(UInt32) != 4  ||
+       sizeof(Int16) != 2 || sizeof(UInt16) != 2  ||
+       sizeof(Char)  != 1 || sizeof(UChar)  != 1)
+      configError();
+
+   /*-- Initialise --*/
+   outputHandleJustInCase  = NULL;
+   smallMode               = False;
+   keepInputFiles          = False;
+   forceOverwrite          = False;
+   noisy                   = True;
+   verbosity               = 0;
+   blockSize100k           = 9;
+   testFailsExist          = False;
+   unzFailsExist           = False;
+   numFileNames            = 0;
+   numFilesProcessed       = 0;
+   workFactor              = 30;
+   deleteOutputOnInterrupt = False;
+   exitValue               = 0;
+   i = j = 0; /* avoid bogus warning from egcs-1.1.X */
+
+   /*-- Set up signal handlers for mem access errors --*/
+   signal (SIGSEGV, mySIGSEGVorSIGBUScatcher);
+#  if BZ_UNIX
+#  ifndef __DJGPP__
+   signal (SIGBUS,  mySIGSEGVorSIGBUScatcher);
+#  endif
+#  endif
+
+   copyFileName ( inName,  (Char*)"(none)" );
+   copyFileName ( outName, (Char*)"(none)" );
+
+   copyFileName ( progNameReally, argv[0] );
+   progName = &progNameReally[0];
+   for (tmp = &progNameReally[0]; *tmp != '\0'; tmp++)
+      if (*tmp == PATH_SEP) progName = tmp + 1;
+
+
+   /*-- Copy flags from env var BZIP2, and 
+        expand filename wildcards in arg list.
+   --*/
+   argList = NULL;
+   addFlagsFromEnvVar ( &argList,  (Char*)"BZIP2" );
+   addFlagsFromEnvVar ( &argList,  (Char*)"BZIP" );
+   for (i = 1; i <= argc-1; i++)
+      APPEND_FILESPEC(argList, argv[i]);
+
+
+   /*-- Find the length of the longest filename --*/
+   longestFileName = 7;
+   numFileNames    = 0;
+   decode          = True;
+   for (aa = argList; aa != NULL; aa = aa->link) {
+      if (ISFLAG("--")) { decode = False; continue; }
+      if (aa->name[0] == '-' && decode) continue;
+      numFileNames++;
+      if (longestFileName < (Int32)strlen(aa->name) )
+         longestFileName = (Int32)strlen(aa->name);
+   }
+
+
+   /*-- Determine source modes; flag handling may change this too. --*/
+   if (numFileNames == 0)
+      srcMode = SM_I2O; else srcMode = SM_F2F;
+
+
+   /*-- Determine what to do (compress/uncompress/test/cat). --*/
+   /*-- Note that subsequent flag handling may change this. --*/
+   opMode = OM_Z;
+
+   if ( (strstr ( progName, "unzip" ) != 0) ||
+        (strstr ( progName, "UNZIP" ) != 0) )
+      opMode = OM_UNZ;
+
+   if ( (strstr ( progName, "z2cat" ) != 0) ||
+        (strstr ( progName, "Z2CAT" ) != 0) ||
+        (strstr ( progName, "zcat" ) != 0)  ||
+        (strstr ( progName, "ZCAT" ) != 0) )  {
+      opMode = OM_UNZ;
+      srcMode = (numFileNames == 0) ? SM_I2O : SM_F2O;
+   }
+
+
+   /*-- Look at the flags. --*/
+   for (aa = argList; aa != NULL; aa = aa->link) {
+      if (ISFLAG("--")) break;
+      if (aa->name[0] == '-' && aa->name[1] != '-') {
+         for (j = 1; aa->name[j] != '\0'; j++) {
+            switch (aa->name[j]) {
+               case 'c': srcMode          = SM_F2O; break;
+               case 'd': opMode           = OM_UNZ; break;
+               case 'z': opMode           = OM_Z; break;
+               case 'f': forceOverwrite   = True; break;
+               case 't': opMode           = OM_TEST; break;
+               case 'k': keepInputFiles   = True; break;
+               case 's': smallMode        = True; break;
+               case 'q': noisy            = False; break;
+               case '1': blockSize100k    = 1; break;
+               case '2': blockSize100k    = 2; break;
+               case '3': blockSize100k    = 3; break;
+               case '4': blockSize100k    = 4; break;
+               case '5': blockSize100k    = 5; break;
+               case '6': blockSize100k    = 6; break;
+               case '7': blockSize100k    = 7; break;
+               case '8': blockSize100k    = 8; break;
+               case '9': blockSize100k    = 9; break;
+               case 'V':
+               case 'L': license();            break;
+               case 'v': verbosity++; break;
+               case 'h': usage ( progName );
+                         exit ( 0 );
+                         break;
+               default:  fprintf ( stderr, "%s: Bad flag `%s'\n",
+                                   progName, aa->name );
+                         usage ( progName );
+                         exit ( 1 );
+                         break;
+            }
+         }
+      }
+   }
+   
+   /*-- And again ... --*/
+   for (aa = argList; aa != NULL; aa = aa->link) {
+      if (ISFLAG("--")) break;
+      if (ISFLAG("--stdout"))            srcMode          = SM_F2O;  else
+      if (ISFLAG("--decompress"))        opMode           = OM_UNZ;  else
+      if (ISFLAG("--compress"))          opMode           = OM_Z;    else
+      if (ISFLAG("--force"))             forceOverwrite   = True;    else
+      if (ISFLAG("--test"))              opMode           = OM_TEST; else
+      if (ISFLAG("--keep"))              keepInputFiles   = True;    else
+      if (ISFLAG("--small"))             smallMode        = True;    else
+      if (ISFLAG("--quiet"))             noisy            = False;   else
+      if (ISFLAG("--version"))           license();                  else
+      if (ISFLAG("--license"))           license();                  else
+      if (ISFLAG("--exponential"))       workFactor = 1;             else 
+      if (ISFLAG("--repetitive-best"))   redundant(aa->name);        else
+      if (ISFLAG("--repetitive-fast"))   redundant(aa->name);        else
+      if (ISFLAG("--fast"))              blockSize100k = 1;          else
+      if (ISFLAG("--best"))              blockSize100k = 9;          else
+      if (ISFLAG("--verbose"))           verbosity++;                else
+      if (ISFLAG("--help"))              { usage ( progName ); exit ( 0 ); }
+         else
+         if (strncmp ( aa->name, "--", 2) == 0) {
+            fprintf ( stderr, "%s: Bad flag `%s'\n", progName, aa->name );
+            usage ( progName );
+            exit ( 1 );
+         }
+   }
+
+   if (verbosity > 4) verbosity = 4;
+   if (opMode == OM_Z && smallMode && blockSize100k > 2) 
+      blockSize100k = 2;
+
+   if (opMode == OM_TEST && srcMode == SM_F2O) {
+      fprintf ( stderr, "%s: -c and -t cannot be used together.\n",
+                progName );
+      exit ( 1 );
+   }
+
+   if (srcMode == SM_F2O && numFileNames == 0)
+      srcMode = SM_I2O;
+
+   if (opMode != OM_Z) blockSize100k = 0;
+
+   if (srcMode == SM_F2F) {
+      signal (SIGINT,  mySignalCatcher);
+      signal (SIGTERM, mySignalCatcher);
+#     if BZ_UNIX
+      signal (SIGHUP,  mySignalCatcher);
+#     endif
+   }
+
+   if (opMode == OM_Z) {
+     if (srcMode == SM_I2O) {
+        compress ( NULL );
+     } else {
+        decode = True;
+        for (aa = argList; aa != NULL; aa = aa->link) {
+           if (ISFLAG("--")) { decode = False; continue; }
+           if (aa->name[0] == '-' && decode) continue;
+           numFilesProcessed++;
+           compress ( aa->name );
+        }
+     }
+   } 
+   else
+
+   if (opMode == OM_UNZ) {
+      unzFailsExist = False;
+      if (srcMode == SM_I2O) {
+         uncompress ( NULL );
+      } else {
+         decode = True;
+         for (aa = argList; aa != NULL; aa = aa->link) {
+            if (ISFLAG("--")) { decode = False; continue; }
+            if (aa->name[0] == '-' && decode) continue;
+            numFilesProcessed++;
+            uncompress ( aa->name );
+         }      
+      }
+      if (unzFailsExist) { 
+         setExit(2); 
+         exit(exitValue);
+      }
+   } 
+
+   else {
+      testFailsExist = False;
+      if (srcMode == SM_I2O) {
+         testf ( NULL );
+      } else {
+         decode = True;
+         for (aa = argList; aa != NULL; aa = aa->link) {
+	    if (ISFLAG("--")) { decode = False; continue; }
+            if (aa->name[0] == '-' && decode) continue;
+            numFilesProcessed++;
+            testf ( aa->name );
+	 }
+      }
+      if (testFailsExist && noisy) {
+         fprintf ( stderr,
+           "\n"
+           "You can use the `bzip2recover' program to attempt to recover\n"
+           "data from undamaged sections of corrupted files.\n\n"
+         );
+         setExit(2);
+         exit(exitValue);
+      }
+   }
+
+   /* Free the argument list memory to mollify leak detectors 
+      (eg) Purify, Checker.  Serves no other useful purpose.
+   */
+   aa = argList;
+   while (aa != NULL) {
+      Cell* aa2 = aa->link;
+      if (aa->name != NULL) free(aa->name);
+      free(aa);
+      aa = aa2;
+   }
+
+   return exitValue;
+}
+
+
+/*-----------------------------------------------------------*/
+/*--- end                                         bzip2.c ---*/
+/*-----------------------------------------------------------*/
diff --git a/source/Irrlicht/bzip2/bzip2.txt b/source/Irrlicht/bzip2/bzip2.txt
new file mode 100644
index 00000000..d2deb394
--- /dev/null
+++ b/source/Irrlicht/bzip2/bzip2.txt
@@ -0,0 +1,391 @@
+
+NAME
+       bzip2, bunzip2 - a block-sorting file compressor, v1.0.6
+       bzcat - decompresses files to stdout
+       bzip2recover - recovers data from damaged bzip2 files
+
+
+SYNOPSIS
+       bzip2 [ -cdfkqstvzVL123456789 ] [ filenames ...  ]
+       bunzip2 [ -fkvsVL ] [ filenames ...  ]
+       bzcat [ -s ] [ filenames ...  ]
+       bzip2recover filename
+
+
+DESCRIPTION
+       bzip2  compresses  files  using  the Burrows-Wheeler block
+       sorting text compression algorithm,  and  Huffman  coding.
+       Compression  is  generally  considerably  better than that
+       achieved by more conventional LZ77/LZ78-based compressors,
+       and  approaches  the performance of the PPM family of sta-
+       tistical compressors.
+
+       The command-line options are deliberately very similar  to
+       those of GNU gzip, but they are not identical.
+
+       bzip2  expects  a list of file names to accompany the com-
+       mand-line flags.  Each file is replaced  by  a  compressed
+       version  of  itself,  with  the  name "original_name.bz2".
+       Each compressed file has the same modification date,  per-
+       missions, and, when possible, ownership as the correspond-
+       ing original, so that these properties  can  be  correctly
+       restored  at  decompression  time.   File name handling is
+       naive in the sense that there is no mechanism for preserv-
+       ing  original file names, permissions, ownerships or dates
+       in filesystems which lack these concepts, or have  serious
+       file name length restrictions, such as MS-DOS.
+
+       bzip2  and  bunzip2 will by default not overwrite existing
+       files.  If you want this to happen, specify the -f flag.
+
+       If no file names  are  specified,  bzip2  compresses  from
+       standard  input  to  standard output.  In this case, bzip2
+       will decline to write compressed output to a terminal,  as
+       this  would  be  entirely  incomprehensible  and therefore
+       pointless.
+
+       bunzip2 (or bzip2 -d) decompresses  all  specified  files.
+       Files which were not created by bzip2 will be detected and
+       ignored, and a warning issued.  bzip2  attempts  to  guess
+       the  filename  for  the decompressed file from that of the
+       compressed file as follows:
+
+              filename.bz2    becomes   filename
+              filename.bz     becomes   filename
+              filename.tbz2   becomes   filename.tar
+              filename.tbz    becomes   filename.tar
+              anyothername    becomes   anyothername.out
+
+       If the file does not end in one of the recognised endings,
+       .bz2,  .bz,  .tbz2 or .tbz, bzip2 complains that it cannot
+       guess the name of the original file, and uses the original
+       name with .out appended.
+
+       As  with compression, supplying no filenames causes decom-
+       pression from standard input to standard output.
+
+       bunzip2 will correctly decompress a file which is the con-
+       catenation of two or more compressed files.  The result is
+       the concatenation of the corresponding uncompressed files.
+       Integrity testing (-t) of concatenated compressed files is
+       also supported.
+
+       You can also compress or decompress files to the  standard
+       output  by giving the -c flag.  Multiple files may be com-
+       pressed and decompressed like this.  The resulting outputs
+       are  fed  sequentially to stdout.  Compression of multiple
+       files in this manner generates a stream containing  multi-
+       ple compressed file representations.  Such a stream can be
+       decompressed correctly only  by  bzip2  version  0.9.0  or
+       later.   Earlier  versions of bzip2 will stop after decom-
+       pressing the first file in the stream.
+
+       bzcat (or bzip2 -dc) decompresses all specified  files  to
+       the standard output.
+
+       bzip2  will  read arguments from the environment variables
+       BZIP2 and BZIP, in  that  order,  and  will  process  them
+       before  any  arguments  read  from the command line.  This
+       gives a convenient way to supply default arguments.
+
+       Compression is always performed, even  if  the  compressed
+       file  is slightly larger than the original.  Files of less
+       than about one hundred bytes tend to get larger, since the
+       compression  mechanism  has  a  constant  overhead  in the
+       region of 50 bytes.  Random data (including the output  of
+       most  file  compressors)  is  coded at about 8.05 bits per
+       byte, giving an expansion of around 0.5%.
+
+       As a self-check for your  protection,  bzip2  uses  32-bit
+       CRCs  to make sure that the decompressed version of a file
+       is identical to the original.  This guards against corrup-
+       tion  of  the compressed data, and against undetected bugs
+       in bzip2 (hopefully very unlikely).  The chances  of  data
+       corruption  going  undetected  is  microscopic,  about one
+       chance in four billion for each file processed.  Be aware,
+       though,  that  the  check occurs upon decompression, so it
+       can only tell you that something is wrong.  It can't  help
+       you  recover  the original uncompressed data.  You can use
+       bzip2recover to try to recover data from damaged files.
+
+       Return values: 0 for a normal exit,  1  for  environmental
+       problems  (file not found, invalid flags, I/O errors, &c),
+       2 to indicate a corrupt compressed file, 3 for an internal
+       consistency error (eg, bug) which caused bzip2 to panic.
+
+
+OPTIONS
+       -c --stdout
+              Compress or decompress to standard output.
+
+       -d --decompress
+              Force  decompression.  bzip2, bunzip2 and bzcat are
+              really the same program,  and  the  decision  about
+              what  actions to take is done on the basis of which
+              name is used.  This flag overrides that  mechanism,
+              and forces bzip2 to decompress.
+
+       -z --compress
+              The   complement   to   -d:   forces   compression,
+              regardless of the invocation name.
+
+       -t --test
+              Check integrity of the specified file(s), but don't
+              decompress  them.   This  really  performs  a trial
+              decompression and throws away the result.
+
+       -f --force
+              Force overwrite of output files.   Normally,  bzip2
+              will  not  overwrite  existing  output files.  Also
+              forces bzip2 to break hard links to files, which it
+              otherwise wouldn't do.
+
+              bzip2  normally  declines to decompress files which
+              don't have the  correct  magic  header  bytes.   If
+              forced  (-f),  however,  it  will  pass  such files
+              through unmodified.  This is how GNU gzip  behaves.
+
+       -k --keep
+              Keep  (don't delete) input files during compression
+              or decompression.
+
+       -s --small
+              Reduce memory usage, for compression, decompression
+              and  testing.   Files  are  decompressed and tested
+              using a modified algorithm which only requires  2.5
+              bytes  per  block byte.  This means any file can be
+              decompressed in 2300k of memory,  albeit  at  about
+              half the normal speed.
+
+              During  compression,  -s  selects  a  block size of
+              200k, which limits memory use to  around  the  same
+              figure,  at  the expense of your compression ratio.
+              In short, if your  machine  is  low  on  memory  (8
+              megabytes  or  less),  use  -s for everything.  See
+              MEMORY MANAGEMENT below.
+
+       -q --quiet
+              Suppress non-essential warning messages.   Messages
+              pertaining  to I/O errors and other critical events
+              will not be suppressed.
+
+       -v --verbose
+              Verbose mode -- show the compression ratio for each
+              file  processed.   Further  -v's  increase the ver-
+              bosity level, spewing out lots of information which
+              is primarily of interest for diagnostic purposes.
+
+       -L --license -V --version
+              Display  the  software  version,  license terms and
+              conditions.
+
+       -1 (or --fast) to -9 (or --best)
+              Set the block size to 100 k, 200 k ..  900  k  when
+              compressing.   Has  no  effect  when decompressing.
+              See MEMORY MANAGEMENT below.  The --fast and --best
+              aliases  are  primarily for GNU gzip compatibility.
+              In particular, --fast doesn't make things  signifi-
+              cantly  faster.   And  --best  merely  selects  the
+              default behaviour.
+
+       --     Treats all subsequent arguments as file names, even
+              if they start with a dash.  This is so you can han-
+              dle files with names beginning  with  a  dash,  for
+              example: bzip2 -- -myfilename.
+
+       --repetitive-fast --repetitive-best
+              These  flags  are  redundant  in versions 0.9.5 and
+              above.  They provided some coarse control over  the
+              behaviour  of the sorting algorithm in earlier ver-
+              sions, which was sometimes useful.  0.9.5 and above
+              have  an  improved  algorithm  which  renders these
+              flags irrelevant.
+
+
+MEMORY MANAGEMENT
+       bzip2 compresses large files in blocks.   The  block  size
+       affects  both  the  compression  ratio  achieved,  and the
+       amount of memory needed for compression and decompression.
+       The  flags  -1  through  -9  specify  the block size to be
+       100,000 bytes through 900,000 bytes (the default)  respec-
+       tively.   At  decompression  time, the block size used for
+       compression is read from  the  header  of  the  compressed
+       file, and bunzip2 then allocates itself just enough memory
+       to decompress the file.  Since block sizes are  stored  in
+       compressed  files,  it follows that the flags -1 to -9 are
+       irrelevant to and so ignored during decompression.
+
+       Compression and decompression requirements, in bytes,  can
+       be estimated as:
+
+              Compression:   400k + ( 8 x block size )
+
+              Decompression: 100k + ( 4 x block size ), or
+                             100k + ( 2.5 x block size )
+
+       Larger  block  sizes  give  rapidly  diminishing  marginal
+       returns.  Most of the compression comes from the first two
+       or  three hundred k of block size, a fact worth bearing in
+       mind when using bzip2  on  small  machines.   It  is  also
+       important  to  appreciate  that  the  decompression memory
+       requirement is set at compression time by  the  choice  of
+       block size.
+
+       For  files  compressed  with  the default 900k block size,
+       bunzip2 will require about 3700 kbytes to decompress.   To
+       support decompression of any file on a 4 megabyte machine,
+       bunzip2 has an option to  decompress  using  approximately
+       half this amount of memory, about 2300 kbytes.  Decompres-
+       sion speed is also halved, so you should use  this  option
+       only where necessary.  The relevant flag is -s.
+
+       In general, try and use the largest block size memory con-
+       straints  allow,  since  that  maximises  the  compression
+       achieved.   Compression and decompression speed are virtu-
+       ally unaffected by block size.
+
+       Another significant point applies to files which fit in  a
+       single  block  --  that  means  most files you'd encounter
+       using a large block  size.   The  amount  of  real  memory
+       touched is proportional to the size of the file, since the
+       file is smaller than a block.  For example, compressing  a
+       file  20,000  bytes  long  with the flag -9 will cause the
+       compressor to allocate around 7600k of  memory,  but  only
+       touch 400k + 20000 * 8 = 560 kbytes of it.  Similarly, the
+       decompressor will allocate 3700k but  only  touch  100k  +
+       20000 * 4 = 180 kbytes.
+
+       Here  is a table which summarises the maximum memory usage
+       for different block sizes.  Also  recorded  is  the  total
+       compressed  size for 14 files of the Calgary Text Compres-
+       sion Corpus totalling 3,141,622 bytes.  This column  gives
+       some  feel  for  how  compression  varies with block size.
+       These figures tend to understate the advantage  of  larger
+       block  sizes  for  larger files, since the Corpus is domi-
+       nated by smaller files.
+
+                  Compress   Decompress   Decompress   Corpus
+           Flag     usage      usage       -s usage     Size
+
+            -1      1200k       500k         350k      914704
+            -2      2000k       900k         600k      877703
+            -3      2800k      1300k         850k      860338
+            -4      3600k      1700k        1100k      846899
+            -5      4400k      2100k        1350k      845160
+            -6      5200k      2500k        1600k      838626
+            -7      6100k      2900k        1850k      834096
+            -8      6800k      3300k        2100k      828642
+            -9      7600k      3700k        2350k      828642
+
+
+RECOVERING DATA FROM DAMAGED FILES
+       bzip2 compresses files in blocks, usually 900kbytes  long.
+       Each block is handled independently.  If a media or trans-
+       mission error causes a multi-block  .bz2  file  to  become
+       damaged,  it  may  be  possible  to  recover data from the
+       undamaged blocks in the file.
+
+       The compressed representation of each block  is  delimited
+       by  a  48-bit pattern, which makes it possible to find the
+       block boundaries with reasonable  certainty.   Each  block
+       also  carries its own 32-bit CRC, so damaged blocks can be
+       distinguished from undamaged ones.
+
+       bzip2recover is a  simple  program  whose  purpose  is  to
+       search  for blocks in .bz2 files, and write each block out
+       into its own .bz2 file.  You can then use bzip2 -t to test
+       the integrity of the resulting files, and decompress those
+       which are undamaged.
+
+       bzip2recover takes a single argument, the name of the dam-
+       aged    file,    and    writes    a    number   of   files
+       "rec00001file.bz2",  "rec00002file.bz2",  etc,  containing
+       the   extracted   blocks.   The   output   filenames   are
+       designed  so  that the use of wildcards in subsequent pro-
+       cessing  -- for example, "bzip2 -dc  rec*file.bz2 > recov-
+       ered_data" -- processes the files in the correct order.
+
+       bzip2recover should be of most use dealing with large .bz2
+       files,  as  these will contain many blocks.  It is clearly
+       futile to use it on damaged single-block  files,  since  a
+       damaged  block  cannot  be recovered.  If you wish to min-
+       imise any potential data loss through media  or  transmis-
+       sion errors, you might consider compressing with a smaller
+       block size.
+
+
+PERFORMANCE NOTES
+       The sorting phase of compression gathers together  similar
+       strings  in  the  file.  Because of this, files containing
+       very long runs of  repeated  symbols,  like  "aabaabaabaab
+       ..."   (repeated  several hundred times) may compress more
+       slowly than normal.  Versions 0.9.5 and  above  fare  much
+       better  than previous versions in this respect.  The ratio
+       between worst-case and average-case compression time is in
+       the  region  of  10:1.  For previous versions, this figure
+       was more like 100:1.  You can use the -vvvv option to mon-
+       itor progress in great detail, if you want.
+
+       Decompression speed is unaffected by these phenomena.
+
+       bzip2  usually  allocates  several  megabytes of memory to
+       operate in, and then charges all over it in a fairly  ran-
+       dom  fashion.   This means that performance, both for com-
+       pressing and decompressing, is largely determined  by  the
+       speed  at  which  your  machine  can service cache misses.
+       Because of this, small changes to the code to  reduce  the
+       miss  rate  have  been observed to give disproportionately
+       large performance improvements.  I imagine bzip2 will per-
+       form best on machines with very large caches.
+
+
+CAVEATS
+       I/O  error  messages  are not as helpful as they could be.
+       bzip2 tries hard to detect I/O errors  and  exit  cleanly,
+       but  the  details  of  what  the problem is sometimes seem
+       rather misleading.
+
+       This manual page pertains to version 1.0.6 of bzip2.  Com-
+       pressed  data created by this version is entirely forwards
+       and  backwards  compatible  with   the   previous   public
+       releases,  versions  0.1pl2,  0.9.0,  0.9.5, 1.0.0, 1.0.1,
+       1.0.2 and above, but with the  following  exception: 0.9.0
+       and above can  correctly decompress  multiple concatenated
+       compressed files.  0.1pl2  cannot do this;  it  will  stop
+       after  decompressing just the first file in the stream.
+
+       bzip2recover  versions prior to 1.0.2 used 32-bit integers
+       to represent bit positions in compressed  files,  so  they
+       could  not handle compressed files more than 512 megabytes
+       long.  Versions 1.0.2 and above use 64-bit  ints  on  some
+       platforms  which  support them (GNU supported targets, and
+       Windows).  To establish whether or  not  bzip2recover  was
+       built  with  such  a limitation, run it without arguments.
+       In any event you can build yourself an  unlimited  version
+       if  you  can  recompile  it  with MaybeUInt64 set to be an
+       unsigned 64-bit integer.
+
+
+AUTHOR
+       Julian Seward, jsewardbzip.org.
+
+       http://www.bzip.org
+
+       The ideas embodied in bzip2 are due to (at least) the fol-
+       lowing  people: Michael Burrows and David Wheeler (for the
+       block sorting transformation), David Wheeler  (again,  for
+       the Huffman coder), Peter Fenwick (for the structured cod-
+       ing model in the original bzip, and many refinements), and
+       Alistair  Moffat,  Radford  Neal  and  Ian Witten (for the
+       arithmetic  coder  in  the  original  bzip).   I  am  much
+       indebted for their help, support and advice.  See the man-
+       ual in the source distribution for pointers to sources  of
+       documentation.  Christian von Roques encouraged me to look
+       for faster sorting algorithms, so as to speed up  compres-
+       sion.  Bela Lubkin encouraged me to improve the worst-case
+       compression performance.  Donna Robinson XMLised the docu-
+       mentation.   The bz* scripts are derived from those of GNU
+       gzip.  Many people sent patches, helped  with  portability
+       problems,  lent  machines,  gave advice and were generally
+       helpful.
+
diff --git a/source/Irrlicht/bzip2/bzip2recover.c b/source/Irrlicht/bzip2/bzip2recover.c
new file mode 100644
index 00000000..f9de0496
--- /dev/null
+++ b/source/Irrlicht/bzip2/bzip2recover.c
@@ -0,0 +1,514 @@
+/*-----------------------------------------------------------*/
+/*--- Block recoverer program for bzip2                   ---*/
+/*---                                      bzip2recover.c ---*/
+/*-----------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+/* This program is a complete hack and should be rewritten properly.
+	 It isn't very complicated. */
+
+#include 
+#include 
+#include 
+#include 
+
+
+/* This program records bit locations in the file to be recovered.
+   That means that if 64-bit ints are not supported, we will not
+   be able to recover .bz2 files over 512MB (2^32 bits) long.
+   On GNU supported platforms, we take advantage of the 64-bit
+   int support to circumvent this problem.  Ditto MSVC.
+
+   This change occurred in version 1.0.2; all prior versions have
+   the 512MB limitation.
+*/
+#ifdef __GNUC__
+   typedef  unsigned long long int  MaybeUInt64;
+#  define MaybeUInt64_FMT "%Lu"
+#else
+#ifdef _MSC_VER
+   typedef  unsigned __int64  MaybeUInt64;
+#  define MaybeUInt64_FMT "%I64u"
+#else
+   typedef  unsigned int   MaybeUInt64;
+#  define MaybeUInt64_FMT "%u"
+#endif
+#endif
+
+typedef  unsigned int   UInt32;
+typedef  int            Int32;
+typedef  unsigned char  UChar;
+typedef  char           Char;
+typedef  unsigned char  Bool;
+#define True    ((Bool)1)
+#define False   ((Bool)0)
+
+
+#define BZ_MAX_FILENAME 2000
+
+Char inFileName[BZ_MAX_FILENAME];
+Char outFileName[BZ_MAX_FILENAME];
+Char progName[BZ_MAX_FILENAME];
+
+MaybeUInt64 bytesOut = 0;
+MaybeUInt64 bytesIn  = 0;
+
+
+/*---------------------------------------------------*/
+/*--- Header bytes                                ---*/
+/*---------------------------------------------------*/
+
+#define BZ_HDR_B 0x42                         /* 'B' */
+#define BZ_HDR_Z 0x5a                         /* 'Z' */
+#define BZ_HDR_h 0x68                         /* 'h' */
+#define BZ_HDR_0 0x30                         /* '0' */
+ 
+
+/*---------------------------------------------------*/
+/*--- I/O errors                                  ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------*/
+static void readError ( void )
+{
+   fprintf ( stderr,
+             "%s: I/O error reading `%s', possible reason follows.\n",
+            progName, inFileName );
+   perror ( progName );
+   fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
+             progName );
+   exit ( 1 );
+}
+
+
+/*---------------------------------------------*/
+static void writeError ( void )
+{
+   fprintf ( stderr,
+             "%s: I/O error reading `%s', possible reason follows.\n",
+            progName, inFileName );
+   perror ( progName );
+   fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
+             progName );
+   exit ( 1 );
+}
+
+
+/*---------------------------------------------*/
+static void mallocFail ( Int32 n )
+{
+   fprintf ( stderr,
+             "%s: malloc failed on request for %d bytes.\n",
+            progName, n );
+   fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
+             progName );
+   exit ( 1 );
+}
+
+
+/*---------------------------------------------*/
+static void tooManyBlocks ( Int32 max_handled_blocks )
+{
+   fprintf ( stderr,
+             "%s: `%s' appears to contain more than %d blocks\n",
+            progName, inFileName, max_handled_blocks );
+   fprintf ( stderr,
+             "%s: and cannot be handled.  To fix, increase\n",
+             progName );
+   fprintf ( stderr, 
+             "%s: BZ_MAX_HANDLED_BLOCKS in bzip2recover.c, and recompile.\n",
+             progName );
+   exit ( 1 );
+}
+
+
+
+/*---------------------------------------------------*/
+/*--- Bit stream I/O                              ---*/
+/*---------------------------------------------------*/
+
+typedef
+   struct {
+      FILE*  handle;
+      Int32  buffer;
+      Int32  buffLive;
+      Char   mode;
+   }
+   BitStream;
+
+
+/*---------------------------------------------*/
+static BitStream* bsOpenReadStream ( FILE* stream )
+{
+   BitStream *bs = malloc ( sizeof(BitStream) );
+   if (bs == NULL) mallocFail ( sizeof(BitStream) );
+   bs->handle = stream;
+   bs->buffer = 0;
+   bs->buffLive = 0;
+   bs->mode = 'r';
+   return bs;
+}
+
+
+/*---------------------------------------------*/
+static BitStream* bsOpenWriteStream ( FILE* stream )
+{
+   BitStream *bs = malloc ( sizeof(BitStream) );
+   if (bs == NULL) mallocFail ( sizeof(BitStream) );
+   bs->handle = stream;
+   bs->buffer = 0;
+   bs->buffLive = 0;
+   bs->mode = 'w';
+   return bs;
+}
+
+
+/*---------------------------------------------*/
+static void bsPutBit ( BitStream* bs, Int32 bit )
+{
+   if (bs->buffLive == 8) {
+      Int32 retVal = putc ( (UChar) bs->buffer, bs->handle );
+      if (retVal == EOF) writeError();
+      bytesOut++;
+      bs->buffLive = 1;
+      bs->buffer = bit & 0x1;
+   } else {
+      bs->buffer = ( (bs->buffer << 1) | (bit & 0x1) );
+      bs->buffLive++;
+   };
+}
+
+
+/*---------------------------------------------*/
+/*--
+   Returns 0 or 1, or 2 to indicate EOF.
+--*/
+static Int32 bsGetBit ( BitStream* bs )
+{
+   if (bs->buffLive > 0) {
+      bs->buffLive --;
+      return ( ((bs->buffer) >> (bs->buffLive)) & 0x1 );
+   } else {
+      Int32 retVal = getc ( bs->handle );
+      if ( retVal == EOF ) {
+         if (errno != 0) readError();
+         return 2;
+      }
+      bs->buffLive = 7;
+      bs->buffer = retVal;
+      return ( ((bs->buffer) >> 7) & 0x1 );
+   }
+}
+
+
+/*---------------------------------------------*/
+static void bsClose ( BitStream* bs )
+{
+   Int32 retVal;
+
+   if ( bs->mode == 'w' ) {
+      while ( bs->buffLive < 8 ) {
+         bs->buffLive++;
+         bs->buffer <<= 1;
+      };
+      retVal = putc ( (UChar) (bs->buffer), bs->handle );
+      if (retVal == EOF) writeError();
+      bytesOut++;
+      retVal = fflush ( bs->handle );
+      if (retVal == EOF) writeError();
+   }
+   retVal = fclose ( bs->handle );
+   if (retVal == EOF) {
+      if (bs->mode == 'w') writeError(); else readError();
+   }
+   free ( bs );
+}
+
+
+/*---------------------------------------------*/
+static void bsPutUChar ( BitStream* bs, UChar c )
+{
+   Int32 i;
+   for (i = 7; i >= 0; i--)
+      bsPutBit ( bs, (((UInt32) c) >> i) & 0x1 );
+}
+
+
+/*---------------------------------------------*/
+static void bsPutUInt32 ( BitStream* bs, UInt32 c )
+{
+   Int32 i;
+
+   for (i = 31; i >= 0; i--)
+      bsPutBit ( bs, (c >> i) & 0x1 );
+}
+
+
+/*---------------------------------------------*/
+static Bool endsInBz2 ( Char* name )
+{
+   Int32 n = strlen ( name );
+   if (n <= 4) return False;
+   return
+      (name[n-4] == '.' &&
+       name[n-3] == 'b' &&
+       name[n-2] == 'z' &&
+       name[n-1] == '2');
+}
+
+
+/*---------------------------------------------------*/
+/*---                                             ---*/
+/*---------------------------------------------------*/
+
+/* This logic isn't really right when it comes to Cygwin. */
+#ifdef _WIN32
+#  define  BZ_SPLIT_SYM  '\\'  /* path splitter on Windows platform */
+#else
+#  define  BZ_SPLIT_SYM  '/'   /* path splitter on Unix platform */
+#endif
+
+#define BLOCK_HEADER_HI  0x00003141UL
+#define BLOCK_HEADER_LO  0x59265359UL
+
+#define BLOCK_ENDMARK_HI 0x00001772UL
+#define BLOCK_ENDMARK_LO 0x45385090UL
+
+/* Increase if necessary.  However, a .bz2 file with > 50000 blocks
+   would have an uncompressed size of at least 40GB, so the chances
+   are low you'll need to up this.
+*/
+#define BZ_MAX_HANDLED_BLOCKS 50000
+
+MaybeUInt64 bStart [BZ_MAX_HANDLED_BLOCKS];
+MaybeUInt64 bEnd   [BZ_MAX_HANDLED_BLOCKS];
+MaybeUInt64 rbStart[BZ_MAX_HANDLED_BLOCKS];
+MaybeUInt64 rbEnd  [BZ_MAX_HANDLED_BLOCKS];
+
+Int32 main ( Int32 argc, Char** argv )
+{
+   FILE*       inFile;
+   FILE*       outFile;
+   BitStream*  bsIn, *bsWr;
+   Int32       b, wrBlock, currBlock, rbCtr;
+   MaybeUInt64 bitsRead;
+
+   UInt32      buffHi, buffLo, blockCRC;
+   Char*       p;
+
+   strcpy ( progName, argv[0] );
+   inFileName[0] = outFileName[0] = 0;
+
+   fprintf ( stderr, 
+             "bzip2recover 1.0.6: extracts blocks from damaged .bz2 files.\n" );
+
+   if (argc != 2) {
+      fprintf ( stderr, "%s: usage is `%s damaged_file_name'.\n",
+                        progName, progName );
+      switch (sizeof(MaybeUInt64)) {
+         case 8:
+            fprintf(stderr, 
+                    "\trestrictions on size of recovered file: None\n");
+            break;
+         case 4:
+            fprintf(stderr, 
+                    "\trestrictions on size of recovered file: 512 MB\n");
+            fprintf(stderr, 
+                    "\tto circumvent, recompile with MaybeUInt64 as an\n"
+                    "\tunsigned 64-bit int.\n");
+            break;
+         default:
+            fprintf(stderr, 
+                    "\tsizeof(MaybeUInt64) is not 4 or 8 -- "
+                    "configuration error.\n");
+            break;
+      }
+      exit(1);
+   }
+
+   if (strlen(argv[1]) >= BZ_MAX_FILENAME-20) {
+      fprintf ( stderr, 
+                "%s: supplied filename is suspiciously (>= %d chars) long.  Bye!\n",
+                progName, (int)strlen(argv[1]) );
+      exit(1);
+   }
+
+   strcpy ( inFileName, argv[1] );
+
+   inFile = fopen ( inFileName, "rb" );
+   if (inFile == NULL) {
+      fprintf ( stderr, "%s: can't read `%s'\n", progName, inFileName );
+      exit(1);
+   }
+
+   bsIn = bsOpenReadStream ( inFile );
+   fprintf ( stderr, "%s: searching for block boundaries ...\n", progName );
+
+   bitsRead = 0;
+   buffHi = buffLo = 0;
+   currBlock = 0;
+   bStart[currBlock] = 0;
+
+   rbCtr = 0;
+
+   while (True) {
+      b = bsGetBit ( bsIn );
+      bitsRead++;
+      if (b == 2) {
+         if (bitsRead >= bStart[currBlock] &&
+            (bitsRead - bStart[currBlock]) >= 40) {
+            bEnd[currBlock] = bitsRead-1;
+            if (currBlock > 0)
+               fprintf ( stderr, "   block %d runs from " MaybeUInt64_FMT 
+                                 " to " MaybeUInt64_FMT " (incomplete)\n",
+                         currBlock,  bStart[currBlock], bEnd[currBlock] );
+         } else
+            currBlock--;
+         break;
+      }
+      buffHi = (buffHi << 1) | (buffLo >> 31);
+      buffLo = (buffLo << 1) | (b & 1);
+      if ( ( (buffHi & 0x0000ffff) == BLOCK_HEADER_HI 
+             && buffLo == BLOCK_HEADER_LO)
+           || 
+           ( (buffHi & 0x0000ffff) == BLOCK_ENDMARK_HI 
+             && buffLo == BLOCK_ENDMARK_LO)
+         ) {
+         if (bitsRead > 49) {
+            bEnd[currBlock] = bitsRead-49;
+         } else {
+            bEnd[currBlock] = 0;
+         }
+         if (currBlock > 0 &&
+	     (bEnd[currBlock] - bStart[currBlock]) >= 130) {
+            fprintf ( stderr, "   block %d runs from " MaybeUInt64_FMT 
+                              " to " MaybeUInt64_FMT "\n",
+                      rbCtr+1,  bStart[currBlock], bEnd[currBlock] );
+            rbStart[rbCtr] = bStart[currBlock];
+            rbEnd[rbCtr] = bEnd[currBlock];
+            rbCtr++;
+         }
+         if (currBlock >= BZ_MAX_HANDLED_BLOCKS)
+            tooManyBlocks(BZ_MAX_HANDLED_BLOCKS);
+         currBlock++;
+
+         bStart[currBlock] = bitsRead;
+      }
+   }
+
+   bsClose ( bsIn );
+
+   /*-- identified blocks run from 1 to rbCtr inclusive. --*/
+
+   if (rbCtr < 1) {
+      fprintf ( stderr,
+                "%s: sorry, I couldn't find any block boundaries.\n",
+                progName );
+      exit(1);
+   };
+
+   fprintf ( stderr, "%s: splitting into blocks\n", progName );
+
+   inFile = fopen ( inFileName, "rb" );
+   if (inFile == NULL) {
+      fprintf ( stderr, "%s: can't open `%s'\n", progName, inFileName );
+      exit(1);
+   }
+   bsIn = bsOpenReadStream ( inFile );
+
+   /*-- placate gcc's dataflow analyser --*/
+   blockCRC = 0; bsWr = 0;
+
+   bitsRead = 0;
+   outFile = NULL;
+   wrBlock = 0;
+   while (True) {
+      b = bsGetBit(bsIn);
+      if (b == 2) break;
+      buffHi = (buffHi << 1) | (buffLo >> 31);
+      buffLo = (buffLo << 1) | (b & 1);
+      if (bitsRead == 47+rbStart[wrBlock]) 
+         blockCRC = (buffHi << 16) | (buffLo >> 16);
+
+      if (outFile != NULL && bitsRead >= rbStart[wrBlock]
+                          && bitsRead <= rbEnd[wrBlock]) {
+         bsPutBit ( bsWr, b );
+      }
+
+      bitsRead++;
+
+      if (bitsRead == rbEnd[wrBlock]+1) {
+         if (outFile != NULL) {
+            bsPutUChar ( bsWr, 0x17 ); bsPutUChar ( bsWr, 0x72 );
+            bsPutUChar ( bsWr, 0x45 ); bsPutUChar ( bsWr, 0x38 );
+            bsPutUChar ( bsWr, 0x50 ); bsPutUChar ( bsWr, 0x90 );
+            bsPutUInt32 ( bsWr, blockCRC );
+            bsClose ( bsWr );
+         }
+         if (wrBlock >= rbCtr) break;
+         wrBlock++;
+      } else
+      if (bitsRead == rbStart[wrBlock]) {
+         /* Create the output file name, correctly handling leading paths. 
+            (31.10.2001 by Sergey E. Kusikov) */
+         Char* split;
+         Int32 ofs, k;
+         for (k = 0; k < BZ_MAX_FILENAME; k++) 
+            outFileName[k] = 0;
+         strcpy (outFileName, inFileName);
+         split = strrchr (outFileName, BZ_SPLIT_SYM);
+         if (split == NULL) {
+            split = outFileName;
+         } else {
+            ++split;
+	 }
+	 /* Now split points to the start of the basename. */
+         ofs  = split - outFileName;
+         sprintf (split, "rec%5d", wrBlock+1);
+         for (p = split; *p != 0; p++) if (*p == ' ') *p = '0';
+         strcat (outFileName, inFileName + ofs);
+
+         if ( !endsInBz2(outFileName)) strcat ( outFileName, ".bz2" );
+
+         fprintf ( stderr, "   writing block %d to `%s' ...\n",
+                           wrBlock+1, outFileName );
+
+         outFile = fopen ( outFileName, "wb" );
+         if (outFile == NULL) {
+            fprintf ( stderr, "%s: can't write `%s'\n",
+                      progName, outFileName );
+            exit(1);
+         }
+         bsWr = bsOpenWriteStream ( outFile );
+         bsPutUChar ( bsWr, BZ_HDR_B );    
+         bsPutUChar ( bsWr, BZ_HDR_Z );    
+         bsPutUChar ( bsWr, BZ_HDR_h );    
+         bsPutUChar ( bsWr, BZ_HDR_0 + 9 );
+         bsPutUChar ( bsWr, 0x31 ); bsPutUChar ( bsWr, 0x41 );
+         bsPutUChar ( bsWr, 0x59 ); bsPutUChar ( bsWr, 0x26 );
+         bsPutUChar ( bsWr, 0x53 ); bsPutUChar ( bsWr, 0x59 );
+      }
+   }
+
+   fprintf ( stderr, "%s: finished\n", progName );
+   return 0;
+}
+
+
+
+/*-----------------------------------------------------------*/
+/*--- end                                  bzip2recover.c ---*/
+/*-----------------------------------------------------------*/
diff --git a/source/Irrlicht/bzip2/bzlib.c b/source/Irrlicht/bzip2/bzlib.c
new file mode 100644
index 00000000..d85e734e
--- /dev/null
+++ b/source/Irrlicht/bzip2/bzlib.c
@@ -0,0 +1,1580 @@
+
+/*-------------------------------------------------------------*/
+/*--- Library top-level functions.                          ---*/
+/*---                                               bzlib.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+/* CHANGES
+   0.9.0    -- original version.
+   0.9.0a/b -- no changes in this file.
+   0.9.0c   -- made zero-length BZ_FLUSH work correctly in bzCompress().
+     fixed bzWrite/bzRead to ignore zero-length requests.
+     fixed bzread to correctly handle read requests after EOF.
+     wrong parameter order in call to bzDecompressInit in
+     bzBuffToBuffDecompress.  Fixed.
+*/
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------------*/
+/*--- Compression stuff                           ---*/
+/*---------------------------------------------------*/
+
+
+/*---------------------------------------------------*/
+#ifndef BZ_NO_STDIO
+void BZ2_bz__AssertH__fail ( int errcode )
+{
+   fprintf(stderr, 
+      "\n\nbzip2/libbzip2: internal error number %d.\n"
+      "This is a bug in bzip2/libbzip2, %s.\n"
+      "Please report it to me at: jseward@bzip.org.  If this happened\n"
+      "when you were using some program which uses libbzip2 as a\n"
+      "component, you should also report this bug to the author(s)\n"
+      "of that program.  Please make an effort to report this bug;\n"
+      "timely and accurate bug reports eventually lead to higher\n"
+      "quality software.  Thanks.  Julian Seward, 10 December 2007.\n\n",
+      errcode,
+      BZ2_bzlibVersion()
+   );
+
+   if (errcode == 1007) {
+   fprintf(stderr,
+      "\n*** A special note about internal error number 1007 ***\n"
+      "\n"
+      "Experience suggests that a common cause of i.e. 1007\n"
+      "is unreliable memory or other hardware.  The 1007 assertion\n"
+      "just happens to cross-check the results of huge numbers of\n"
+      "memory reads/writes, and so acts (unintendedly) as a stress\n"
+      "test of your memory system.\n"
+      "\n"
+      "I suggest the following: try compressing the file again,\n"
+      "possibly monitoring progress in detail with the -vv flag.\n"
+      "\n"
+      "* If the error cannot be reproduced, and/or happens at different\n"
+      "  points in compression, you may have a flaky memory system.\n"
+      "  Try a memory-test program.  I have used Memtest86\n"
+      "  (www.memtest86.com).  At the time of writing it is free (GPLd).\n"
+      "  Memtest86 tests memory much more thorougly than your BIOSs\n"
+      "  power-on test, and may find failures that the BIOS doesn't.\n"
+      "\n"
+      "* If the error can be repeatably reproduced, this is a bug in\n"
+      "  bzip2, and I would very much like to hear about it.  Please\n"
+      "  let me know, and, ideally, save a copy of the file causing the\n"
+      "  problem -- without which I will be unable to investigate it.\n"
+      "\n"
+   );
+   }
+
+   exit(3);
+}
+#endif
+
+
+/*---------------------------------------------------*/
+static
+int bz_config_ok ( void )
+{
+   if (sizeof(int)   != 4) return 0;
+   if (sizeof(short) != 2) return 0;
+   if (sizeof(char)  != 1) return 0;
+   return 1;
+}
+
+
+/*---------------------------------------------------*/
+static
+void* default_bzalloc ( void* opaque, Int32 items, Int32 size )
+{
+   void* v = malloc ( items * size );
+   return v;
+}
+
+static
+void default_bzfree ( void* opaque, void* addr )
+{
+   if (addr != NULL) free ( addr );
+}
+
+
+/*---------------------------------------------------*/
+static
+void prepare_new_block ( EState* s )
+{
+   Int32 i;
+   s->nblock = 0;
+   s->numZ = 0;
+   s->state_out_pos = 0;
+   BZ_INITIALISE_CRC ( s->blockCRC );
+   for (i = 0; i < 256; i++) s->inUse[i] = False;
+   s->blockNo++;
+}
+
+
+/*---------------------------------------------------*/
+static
+void init_RL ( EState* s )
+{
+   s->state_in_ch  = 256;
+   s->state_in_len = 0;
+}
+
+
+static
+Bool isempty_RL ( EState* s )
+{
+   if (s->state_in_ch < 256 && s->state_in_len > 0)
+      return False; else
+      return True;
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzCompressInit) 
+                    ( bz_stream* strm, 
+                     int        blockSize100k,
+                     int        verbosity,
+                     int        workFactor )
+{
+   Int32   n;
+   EState* s;
+
+   if (!bz_config_ok()) return BZ_CONFIG_ERROR;
+
+   if (strm == NULL || 
+       blockSize100k < 1 || blockSize100k > 9 ||
+       workFactor < 0 || workFactor > 250)
+     return BZ_PARAM_ERROR;
+
+   if (workFactor == 0) workFactor = 30;
+   if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
+   if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
+
+   s = BZALLOC( sizeof(EState) );
+   if (s == NULL) return BZ_MEM_ERROR;
+   s->strm = strm;
+
+   s->arr1 = NULL;
+   s->arr2 = NULL;
+   s->ftab = NULL;
+
+   n       = 100000 * blockSize100k;
+   s->arr1 = BZALLOC( n                  * sizeof(UInt32) );
+   s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) );
+   s->ftab = BZALLOC( 65537              * sizeof(UInt32) );
+
+   if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) {
+      if (s->arr1 != NULL) BZFREE(s->arr1);
+      if (s->arr2 != NULL) BZFREE(s->arr2);
+      if (s->ftab != NULL) BZFREE(s->ftab);
+      if (s       != NULL) BZFREE(s);
+      return BZ_MEM_ERROR;
+   }
+
+   s->blockNo           = 0;
+   s->state             = BZ_S_INPUT;
+   s->mode              = BZ_M_RUNNING;
+   s->combinedCRC       = 0;
+   s->blockSize100k     = blockSize100k;
+   s->nblockMAX         = 100000 * blockSize100k - 19;
+   s->verbosity         = verbosity;
+   s->workFactor        = workFactor;
+
+   s->block             = (UChar*)s->arr2;
+   s->mtfv              = (UInt16*)s->arr1;
+   s->zbits             = NULL;
+   s->ptr               = (UInt32*)s->arr1;
+
+   strm->state          = s;
+   strm->total_in_lo32  = 0;
+   strm->total_in_hi32  = 0;
+   strm->total_out_lo32 = 0;
+   strm->total_out_hi32 = 0;
+   init_RL ( s );
+   prepare_new_block ( s );
+   return BZ_OK;
+}
+
+
+/*---------------------------------------------------*/
+static
+void add_pair_to_block ( EState* s )
+{
+   Int32 i;
+   UChar ch = (UChar)(s->state_in_ch);
+   for (i = 0; i < s->state_in_len; i++) {
+      BZ_UPDATE_CRC( s->blockCRC, ch );
+   }
+   s->inUse[s->state_in_ch] = True;
+   switch (s->state_in_len) {
+      case 1:
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         break;
+      case 2:
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         break;
+      case 3:
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         break;
+      default:
+         s->inUse[s->state_in_len-4] = True;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = ((UChar)(s->state_in_len-4));
+         s->nblock++;
+         break;
+   }
+}
+
+
+/*---------------------------------------------------*/
+static
+void flush_RL ( EState* s )
+{
+   if (s->state_in_ch < 256) add_pair_to_block ( s );
+   init_RL ( s );
+}
+
+
+/*---------------------------------------------------*/
+#define ADD_CHAR_TO_BLOCK(zs,zchh0)               \
+{                                                 \
+   UInt32 zchh = (UInt32)(zchh0);                 \
+   /*-- fast track the common case --*/           \
+   if (zchh != zs->state_in_ch &&                 \
+       zs->state_in_len == 1) {                   \
+      UChar ch = (UChar)(zs->state_in_ch);        \
+      BZ_UPDATE_CRC( zs->blockCRC, ch );          \
+      zs->inUse[zs->state_in_ch] = True;          \
+      zs->block[zs->nblock] = (UChar)ch;          \
+      zs->nblock++;                               \
+      zs->state_in_ch = zchh;                     \
+   }                                              \
+   else                                           \
+   /*-- general, uncommon cases --*/              \
+   if (zchh != zs->state_in_ch ||                 \
+      zs->state_in_len == 255) {                  \
+      if (zs->state_in_ch < 256)                  \
+         add_pair_to_block ( zs );                \
+      zs->state_in_ch = zchh;                     \
+      zs->state_in_len = 1;                       \
+   } else {                                       \
+      zs->state_in_len++;                         \
+   }                                              \
+}
+
+
+/*---------------------------------------------------*/
+static
+Bool copy_input_until_stop ( EState* s )
+{
+   Bool progress_in = False;
+
+   if (s->mode == BZ_M_RUNNING) {
+
+      /*-- fast track the common case --*/
+      while (True) {
+         /*-- block full? --*/
+         if (s->nblock >= s->nblockMAX) break;
+         /*-- no input? --*/
+         if (s->strm->avail_in == 0) break;
+         progress_in = True;
+         ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); 
+         s->strm->next_in++;
+         s->strm->avail_in--;
+         s->strm->total_in_lo32++;
+         if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
+      }
+
+   } else {
+
+      /*-- general, uncommon case --*/
+      while (True) {
+         /*-- block full? --*/
+         if (s->nblock >= s->nblockMAX) break;
+         /*-- no input? --*/
+         if (s->strm->avail_in == 0) break;
+         /*-- flush/finish end? --*/
+         if (s->avail_in_expect == 0) break;
+         progress_in = True;
+         ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); 
+         s->strm->next_in++;
+         s->strm->avail_in--;
+         s->strm->total_in_lo32++;
+         if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
+         s->avail_in_expect--;
+      }
+   }
+   return progress_in;
+}
+
+
+/*---------------------------------------------------*/
+static
+Bool copy_output_until_stop ( EState* s )
+{
+   Bool progress_out = False;
+
+   while (True) {
+
+      /*-- no output space? --*/
+      if (s->strm->avail_out == 0) break;
+
+      /*-- block done? --*/
+      if (s->state_out_pos >= s->numZ) break;
+
+      progress_out = True;
+      *(s->strm->next_out) = s->zbits[s->state_out_pos];
+      s->state_out_pos++;
+      s->strm->avail_out--;
+      s->strm->next_out++;
+      s->strm->total_out_lo32++;
+      if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+   }
+
+   return progress_out;
+}
+
+
+/*---------------------------------------------------*/
+static
+Bool handle_compress ( bz_stream* strm )
+{
+   Bool progress_in  = False;
+   Bool progress_out = False;
+   EState* s = strm->state;
+   
+   while (True) {
+
+      if (s->state == BZ_S_OUTPUT) {
+         progress_out |= copy_output_until_stop ( s );
+         if (s->state_out_pos < s->numZ) break;
+         if (s->mode == BZ_M_FINISHING && 
+             s->avail_in_expect == 0 &&
+             isempty_RL(s)) break;
+         prepare_new_block ( s );
+         s->state = BZ_S_INPUT;
+         if (s->mode == BZ_M_FLUSHING && 
+             s->avail_in_expect == 0 &&
+             isempty_RL(s)) break;
+      }
+
+      if (s->state == BZ_S_INPUT) {
+         progress_in |= copy_input_until_stop ( s );
+         if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) {
+            flush_RL ( s );
+            BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) );
+            s->state = BZ_S_OUTPUT;
+         }
+         else
+         if (s->nblock >= s->nblockMAX) {
+            BZ2_compressBlock ( s, False );
+            s->state = BZ_S_OUTPUT;
+         }
+         else
+         if (s->strm->avail_in == 0) {
+            break;
+         }
+      }
+
+   }
+
+   return progress_in || progress_out;
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action )
+{
+   Bool progress;
+   EState* s;
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   s = strm->state;
+   if (s == NULL) return BZ_PARAM_ERROR;
+   if (s->strm != strm) return BZ_PARAM_ERROR;
+
+   preswitch:
+   switch (s->mode) {
+
+      case BZ_M_IDLE:
+         return BZ_SEQUENCE_ERROR;
+
+      case BZ_M_RUNNING:
+         if (action == BZ_RUN) {
+            progress = handle_compress ( strm );
+            return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;
+         } 
+         else
+	 if (action == BZ_FLUSH) {
+            s->avail_in_expect = strm->avail_in;
+            s->mode = BZ_M_FLUSHING;
+            goto preswitch;
+         }
+         else
+         if (action == BZ_FINISH) {
+            s->avail_in_expect = strm->avail_in;
+            s->mode = BZ_M_FINISHING;
+            goto preswitch;
+         }
+         else 
+            return BZ_PARAM_ERROR;
+
+      case BZ_M_FLUSHING:
+         if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR;
+         if (s->avail_in_expect != s->strm->avail_in) 
+            return BZ_SEQUENCE_ERROR;
+         progress = handle_compress ( strm );
+         if (s->avail_in_expect > 0 || !isempty_RL(s) ||
+             s->state_out_pos < s->numZ) return BZ_FLUSH_OK;
+         s->mode = BZ_M_RUNNING;
+         return BZ_RUN_OK;
+
+      case BZ_M_FINISHING:
+         if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR;
+         if (s->avail_in_expect != s->strm->avail_in) 
+            return BZ_SEQUENCE_ERROR;
+         progress = handle_compress ( strm );
+         if (!progress) return BZ_SEQUENCE_ERROR;
+         if (s->avail_in_expect > 0 || !isempty_RL(s) ||
+             s->state_out_pos < s->numZ) return BZ_FINISH_OK;
+         s->mode = BZ_M_IDLE;
+         return BZ_STREAM_END;
+   }
+   return BZ_OK; /*--not reached--*/
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzCompressEnd)  ( bz_stream *strm )
+{
+   EState* s;
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   s = strm->state;
+   if (s == NULL) return BZ_PARAM_ERROR;
+   if (s->strm != strm) return BZ_PARAM_ERROR;
+
+   if (s->arr1 != NULL) BZFREE(s->arr1);
+   if (s->arr2 != NULL) BZFREE(s->arr2);
+   if (s->ftab != NULL) BZFREE(s->ftab);
+   BZFREE(strm->state);
+
+   strm->state = NULL;   
+
+   return BZ_OK;
+}
+
+
+/*---------------------------------------------------*/
+/*--- Decompression stuff                         ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzDecompressInit) 
+                     ( bz_stream* strm, 
+                       int        verbosity,
+                       int        small )
+{
+   DState* s;
+
+   if (!bz_config_ok()) return BZ_CONFIG_ERROR;
+
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   if (small != 0 && small != 1) return BZ_PARAM_ERROR;
+   if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR;
+
+   if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
+   if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
+
+   s = BZALLOC( sizeof(DState) );
+   if (s == NULL) return BZ_MEM_ERROR;
+   s->strm                  = strm;
+   strm->state              = s;
+   s->state                 = BZ_X_MAGIC_1;
+   s->bsLive                = 0;
+   s->bsBuff                = 0;
+   s->calculatedCombinedCRC = 0;
+   strm->total_in_lo32      = 0;
+   strm->total_in_hi32      = 0;
+   strm->total_out_lo32     = 0;
+   strm->total_out_hi32     = 0;
+   s->smallDecompress       = (Bool)small;
+   s->ll4                   = NULL;
+   s->ll16                  = NULL;
+   s->tt                    = NULL;
+   s->currBlockNo           = 0;
+   s->verbosity             = verbosity;
+
+   return BZ_OK;
+}
+
+
+/*---------------------------------------------------*/
+/* Return  True iff data corruption is discovered.
+   Returns False if there is no problem.
+*/
+static
+Bool unRLE_obuf_to_output_FAST ( DState* s )
+{
+   UChar k1;
+
+   if (s->blockRandomised) {
+
+      while (True) {
+         /* try to finish existing run */
+         while (True) {
+            if (s->strm->avail_out == 0) return False;
+            if (s->state_out_len == 0) break;
+            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
+            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
+            s->state_out_len--;
+            s->strm->next_out++;
+            s->strm->avail_out--;
+            s->strm->total_out_lo32++;
+            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+         }
+
+         /* can a new run be started? */
+         if (s->nblock_used == s->save_nblock+1) return False;
+               
+         /* Only caused by corrupt data stream? */
+         if (s->nblock_used > s->save_nblock+1)
+            return True;
+   
+         s->state_out_len = 1;
+         s->state_out_ch = s->k0;
+         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 2;
+         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 3;
+         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         s->state_out_len = ((Int32)k1) + 4;
+         BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; 
+         s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
+      }
+
+   } else {
+
+      /* restore */
+      UInt32        c_calculatedBlockCRC = s->calculatedBlockCRC;
+      UChar         c_state_out_ch       = s->state_out_ch;
+      Int32         c_state_out_len      = s->state_out_len;
+      Int32         c_nblock_used        = s->nblock_used;
+      Int32         c_k0                 = s->k0;
+      UInt32*       c_tt                 = s->tt;
+      UInt32        c_tPos               = s->tPos;
+      char*         cs_next_out          = s->strm->next_out;
+      unsigned int  cs_avail_out         = s->strm->avail_out;
+      Int32         ro_blockSize100k     = s->blockSize100k;
+      /* end restore */
+
+      UInt32       avail_out_INIT = cs_avail_out;
+      Int32        s_save_nblockPP = s->save_nblock+1;
+      unsigned int total_out_lo32_old;
+
+      while (True) {
+
+         /* try to finish existing run */
+         if (c_state_out_len > 0) {
+            while (True) {
+               if (cs_avail_out == 0) goto return_notr;
+               if (c_state_out_len == 1) break;
+               *( (UChar*)(cs_next_out) ) = c_state_out_ch;
+               BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
+               c_state_out_len--;
+               cs_next_out++;
+               cs_avail_out--;
+            }
+            s_state_out_len_eq_one:
+            {
+               if (cs_avail_out == 0) { 
+                  c_state_out_len = 1; goto return_notr;
+               };
+               *( (UChar*)(cs_next_out) ) = c_state_out_ch;
+               BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
+               cs_next_out++;
+               cs_avail_out--;
+            }
+         }   
+         /* Only caused by corrupt data stream? */
+         if (c_nblock_used > s_save_nblockPP)
+            return True;
+
+         /* can a new run be started? */
+         if (c_nblock_used == s_save_nblockPP) {
+            c_state_out_len = 0; goto return_notr;
+         };   
+         c_state_out_ch = c_k0;
+         BZ_GET_FAST_C(k1); c_nblock_used++;
+         if (k1 != c_k0) { 
+            c_k0 = k1; goto s_state_out_len_eq_one; 
+         };
+         if (c_nblock_used == s_save_nblockPP) 
+            goto s_state_out_len_eq_one;
+   
+         c_state_out_len = 2;
+         BZ_GET_FAST_C(k1); c_nblock_used++;
+         if (c_nblock_used == s_save_nblockPP) continue;
+         if (k1 != c_k0) { c_k0 = k1; continue; };
+   
+         c_state_out_len = 3;
+         BZ_GET_FAST_C(k1); c_nblock_used++;
+         if (c_nblock_used == s_save_nblockPP) continue;
+         if (k1 != c_k0) { c_k0 = k1; continue; };
+   
+         BZ_GET_FAST_C(k1); c_nblock_used++;
+         c_state_out_len = ((Int32)k1) + 4;
+         BZ_GET_FAST_C(c_k0); c_nblock_used++;
+      }
+
+      return_notr:
+      total_out_lo32_old = s->strm->total_out_lo32;
+      s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out);
+      if (s->strm->total_out_lo32 < total_out_lo32_old)
+         s->strm->total_out_hi32++;
+
+      /* save */
+      s->calculatedBlockCRC = c_calculatedBlockCRC;
+      s->state_out_ch       = c_state_out_ch;
+      s->state_out_len      = c_state_out_len;
+      s->nblock_used        = c_nblock_used;
+      s->k0                 = c_k0;
+      s->tt                 = c_tt;
+      s->tPos               = c_tPos;
+      s->strm->next_out     = cs_next_out;
+      s->strm->avail_out    = cs_avail_out;
+      /* end save */
+   }
+   return False;
+}
+
+
+
+/*---------------------------------------------------*/
+__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab )
+{
+   Int32 nb, na, mid;
+   nb = 0;
+   na = 256;
+   do {
+      mid = (nb + na) >> 1;
+      if (indx >= cftab[mid]) nb = mid; else na = mid;
+   }
+   while (na - nb != 1);
+   return nb;
+}
+
+
+/*---------------------------------------------------*/
+/* Return  True iff data corruption is discovered.
+   Returns False if there is no problem.
+*/
+static
+Bool unRLE_obuf_to_output_SMALL ( DState* s )
+{
+   UChar k1;
+
+   if (s->blockRandomised) {
+
+      while (True) {
+         /* try to finish existing run */
+         while (True) {
+            if (s->strm->avail_out == 0) return False;
+            if (s->state_out_len == 0) break;
+            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
+            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
+            s->state_out_len--;
+            s->strm->next_out++;
+            s->strm->avail_out--;
+            s->strm->total_out_lo32++;
+            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+         }
+   
+         /* can a new run be started? */
+         if (s->nblock_used == s->save_nblock+1) return False;
+
+         /* Only caused by corrupt data stream? */
+         if (s->nblock_used > s->save_nblock+1)
+            return True;
+   
+         s->state_out_len = 1;
+         s->state_out_ch = s->k0;
+         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 2;
+         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 3;
+         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         s->state_out_len = ((Int32)k1) + 4;
+         BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; 
+         s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
+      }
+
+   } else {
+
+      while (True) {
+         /* try to finish existing run */
+         while (True) {
+            if (s->strm->avail_out == 0) return False;
+            if (s->state_out_len == 0) break;
+            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
+            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
+            s->state_out_len--;
+            s->strm->next_out++;
+            s->strm->avail_out--;
+            s->strm->total_out_lo32++;
+            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+         }
+   
+         /* can a new run be started? */
+         if (s->nblock_used == s->save_nblock+1) return False;
+
+         /* Only caused by corrupt data stream? */
+         if (s->nblock_used > s->save_nblock+1)
+            return True;
+   
+         s->state_out_len = 1;
+         s->state_out_ch = s->k0;
+         BZ_GET_SMALL(k1); s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 2;
+         BZ_GET_SMALL(k1); s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 3;
+         BZ_GET_SMALL(k1); s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         BZ_GET_SMALL(k1); s->nblock_used++;
+         s->state_out_len = ((Int32)k1) + 4;
+         BZ_GET_SMALL(s->k0); s->nblock_used++;
+      }
+
+   }
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzDecompress) ( bz_stream *strm )
+{
+   Bool    corrupt;
+   DState* s;
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   s = strm->state;
+   if (s == NULL) return BZ_PARAM_ERROR;
+   if (s->strm != strm) return BZ_PARAM_ERROR;
+
+   while (True) {
+      if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR;
+      if (s->state == BZ_X_OUTPUT) {
+         if (s->smallDecompress)
+            corrupt = unRLE_obuf_to_output_SMALL ( s ); else
+            corrupt = unRLE_obuf_to_output_FAST  ( s );
+         if (corrupt) return BZ_DATA_ERROR;
+         if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
+            BZ_FINALISE_CRC ( s->calculatedBlockCRC );
+            if (s->verbosity >= 3) 
+               VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, 
+                          s->calculatedBlockCRC );
+            if (s->verbosity >= 2) VPrintf0 ( "]" );
+            if (s->calculatedBlockCRC != s->storedBlockCRC)
+               return BZ_DATA_ERROR;
+            s->calculatedCombinedCRC 
+               = (s->calculatedCombinedCRC << 1) | 
+                    (s->calculatedCombinedCRC >> 31);
+            s->calculatedCombinedCRC ^= s->calculatedBlockCRC;
+            s->state = BZ_X_BLKHDR_1;
+         } else {
+            return BZ_OK;
+         }
+      }
+      if (s->state >= BZ_X_MAGIC_1) {
+         Int32 r = BZ2_decompress ( s );
+         if (r == BZ_STREAM_END) {
+            if (s->verbosity >= 3)
+               VPrintf2 ( "\n    combined CRCs: stored = 0x%08x, computed = 0x%08x", 
+                          s->storedCombinedCRC, s->calculatedCombinedCRC );
+            if (s->calculatedCombinedCRC != s->storedCombinedCRC)
+               return BZ_DATA_ERROR;
+            return r;
+         }
+         if (s->state != BZ_X_OUTPUT) return r;
+      }
+   }
+
+   AssertH ( 0, 6001 );
+
+   return 0;  /*NOTREACHED*/
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzDecompressEnd)  ( bz_stream *strm )
+{
+   DState* s;
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   s = strm->state;
+   if (s == NULL) return BZ_PARAM_ERROR;
+   if (s->strm != strm) return BZ_PARAM_ERROR;
+
+   if (s->tt   != NULL) BZFREE(s->tt);
+   if (s->ll16 != NULL) BZFREE(s->ll16);
+   if (s->ll4  != NULL) BZFREE(s->ll4);
+
+   BZFREE(strm->state);
+   strm->state = NULL;
+
+   return BZ_OK;
+}
+
+
+#ifndef BZ_NO_STDIO
+/*---------------------------------------------------*/
+/*--- File I/O stuff                              ---*/
+/*---------------------------------------------------*/
+
+#define BZ_SETERR(eee)                    \
+{                                         \
+   if (bzerror != NULL) *bzerror = eee;   \
+   if (bzf != NULL) bzf->lastErr = eee;   \
+}
+
+typedef 
+   struct {
+      FILE*     handle;
+      Char      buf[BZ_MAX_UNUSED];
+      Int32     bufN;
+      Bool      writing;
+      bz_stream strm;
+      Int32     lastErr;
+      Bool      initialisedOk;
+   }
+   bzFile;
+
+
+/*---------------------------------------------*/
+static Bool myfeof ( FILE* f )
+{
+   Int32 c = fgetc ( f );
+   if (c == EOF) return True;
+   ungetc ( c, f );
+   return False;
+}
+
+
+/*---------------------------------------------------*/
+BZFILE* BZ_API(BZ2_bzWriteOpen) 
+                    ( int*  bzerror,      
+                      FILE* f, 
+                      int   blockSize100k, 
+                      int   verbosity,
+                      int   workFactor )
+{
+   Int32   ret;
+   bzFile* bzf = NULL;
+
+   BZ_SETERR(BZ_OK);
+
+   if (f == NULL ||
+       (blockSize100k < 1 || blockSize100k > 9) ||
+       (workFactor < 0 || workFactor > 250) ||
+       (verbosity < 0 || verbosity > 4))
+      { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
+
+   if (ferror(f))
+      { BZ_SETERR(BZ_IO_ERROR); return NULL; };
+
+   bzf = malloc ( sizeof(bzFile) );
+   if (bzf == NULL)
+      { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
+
+   BZ_SETERR(BZ_OK);
+   bzf->initialisedOk = False;
+   bzf->bufN          = 0;
+   bzf->handle        = f;
+   bzf->writing       = True;
+   bzf->strm.bzalloc  = NULL;
+   bzf->strm.bzfree   = NULL;
+   bzf->strm.opaque   = NULL;
+
+   if (workFactor == 0) workFactor = 30;
+   ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, 
+                              verbosity, workFactor );
+   if (ret != BZ_OK)
+      { BZ_SETERR(ret); free(bzf); return NULL; };
+
+   bzf->strm.avail_in = 0;
+   bzf->initialisedOk = True;
+   return bzf;   
+}
+
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzWrite)
+             ( int*    bzerror, 
+               BZFILE* b, 
+               void*   buf, 
+               int     len )
+{
+   Int32 n, n2, ret;
+   bzFile* bzf = (bzFile*)b;
+
+   BZ_SETERR(BZ_OK);
+   if (bzf == NULL || buf == NULL || len < 0)
+      { BZ_SETERR(BZ_PARAM_ERROR); return; };
+   if (!(bzf->writing))
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+   if (ferror(bzf->handle))
+      { BZ_SETERR(BZ_IO_ERROR); return; };
+
+   if (len == 0)
+      { BZ_SETERR(BZ_OK); return; };
+
+   bzf->strm.avail_in = len;
+   bzf->strm.next_in  = buf;
+
+   while (True) {
+      bzf->strm.avail_out = BZ_MAX_UNUSED;
+      bzf->strm.next_out = bzf->buf;
+      ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN );
+      if (ret != BZ_RUN_OK)
+         { BZ_SETERR(ret); return; };
+
+      if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
+         n = BZ_MAX_UNUSED - bzf->strm.avail_out;
+         n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), 
+                       n, bzf->handle );
+         if (n != n2 || ferror(bzf->handle))
+            { BZ_SETERR(BZ_IO_ERROR); return; };
+      }
+
+      if (bzf->strm.avail_in == 0)
+         { BZ_SETERR(BZ_OK); return; };
+   }
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzWriteClose)
+                  ( int*          bzerror, 
+                    BZFILE*       b, 
+                    int           abandon,
+                    unsigned int* nbytes_in,
+                    unsigned int* nbytes_out )
+{
+   BZ2_bzWriteClose64 ( bzerror, b, abandon, 
+                        nbytes_in, NULL, nbytes_out, NULL );
+}
+
+
+void BZ_API(BZ2_bzWriteClose64)
+                  ( int*          bzerror, 
+                    BZFILE*       b, 
+                    int           abandon,
+                    unsigned int* nbytes_in_lo32,
+                    unsigned int* nbytes_in_hi32,
+                    unsigned int* nbytes_out_lo32,
+                    unsigned int* nbytes_out_hi32 )
+{
+   Int32   n, n2, ret;
+   bzFile* bzf = (bzFile*)b;
+
+   if (bzf == NULL)
+      { BZ_SETERR(BZ_OK); return; };
+   if (!(bzf->writing))
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+   if (ferror(bzf->handle))
+      { BZ_SETERR(BZ_IO_ERROR); return; };
+
+   if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0;
+   if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0;
+   if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0;
+   if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0;
+
+   if ((!abandon) && bzf->lastErr == BZ_OK) {
+      while (True) {
+         bzf->strm.avail_out = BZ_MAX_UNUSED;
+         bzf->strm.next_out = bzf->buf;
+         ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH );
+         if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END)
+            { BZ_SETERR(ret); return; };
+
+         if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
+            n = BZ_MAX_UNUSED - bzf->strm.avail_out;
+            n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), 
+                          n, bzf->handle );
+            if (n != n2 || ferror(bzf->handle))
+               { BZ_SETERR(BZ_IO_ERROR); return; };
+         }
+
+         if (ret == BZ_STREAM_END) break;
+      }
+   }
+
+   if ( !abandon && !ferror ( bzf->handle ) ) {
+      fflush ( bzf->handle );
+      if (ferror(bzf->handle))
+         { BZ_SETERR(BZ_IO_ERROR); return; };
+   }
+
+   if (nbytes_in_lo32 != NULL)
+      *nbytes_in_lo32 = bzf->strm.total_in_lo32;
+   if (nbytes_in_hi32 != NULL)
+      *nbytes_in_hi32 = bzf->strm.total_in_hi32;
+   if (nbytes_out_lo32 != NULL)
+      *nbytes_out_lo32 = bzf->strm.total_out_lo32;
+   if (nbytes_out_hi32 != NULL)
+      *nbytes_out_hi32 = bzf->strm.total_out_hi32;
+
+   BZ_SETERR(BZ_OK);
+   BZ2_bzCompressEnd ( &(bzf->strm) );
+   free ( bzf );
+}
+
+
+/*---------------------------------------------------*/
+BZFILE* BZ_API(BZ2_bzReadOpen) 
+                   ( int*  bzerror, 
+                     FILE* f, 
+                     int   verbosity,
+                     int   small,
+                     void* unused,
+                     int   nUnused )
+{
+   bzFile* bzf = NULL;
+   int     ret;
+
+   BZ_SETERR(BZ_OK);
+
+   if (f == NULL || 
+       (small != 0 && small != 1) ||
+       (verbosity < 0 || verbosity > 4) ||
+       (unused == NULL && nUnused != 0) ||
+       (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED)))
+      { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
+
+   if (ferror(f))
+      { BZ_SETERR(BZ_IO_ERROR); return NULL; };
+
+   bzf = malloc ( sizeof(bzFile) );
+   if (bzf == NULL) 
+      { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
+
+   BZ_SETERR(BZ_OK);
+
+   bzf->initialisedOk = False;
+   bzf->handle        = f;
+   bzf->bufN          = 0;
+   bzf->writing       = False;
+   bzf->strm.bzalloc  = NULL;
+   bzf->strm.bzfree   = NULL;
+   bzf->strm.opaque   = NULL;
+   
+   while (nUnused > 0) {
+      bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++;
+      unused = ((void*)( 1 + ((UChar*)(unused))  ));
+      nUnused--;
+   }
+
+   ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small );
+   if (ret != BZ_OK)
+      { BZ_SETERR(ret); free(bzf); return NULL; };
+
+   bzf->strm.avail_in = bzf->bufN;
+   bzf->strm.next_in  = bzf->buf;
+
+   bzf->initialisedOk = True;
+   return bzf;   
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b )
+{
+   bzFile* bzf = (bzFile*)b;
+
+   BZ_SETERR(BZ_OK);
+   if (bzf == NULL)
+      { BZ_SETERR(BZ_OK); return; };
+
+   if (bzf->writing)
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+
+   if (bzf->initialisedOk)
+      (void)BZ2_bzDecompressEnd ( &(bzf->strm) );
+   free ( bzf );
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzRead) 
+           ( int*    bzerror, 
+             BZFILE* b, 
+             void*   buf, 
+             int     len )
+{
+   Int32   n, ret;
+   bzFile* bzf = (bzFile*)b;
+
+   BZ_SETERR(BZ_OK);
+
+   if (bzf == NULL || buf == NULL || len < 0)
+      { BZ_SETERR(BZ_PARAM_ERROR); return 0; };
+
+   if (bzf->writing)
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; };
+
+   if (len == 0)
+      { BZ_SETERR(BZ_OK); return 0; };
+
+   bzf->strm.avail_out = len;
+   bzf->strm.next_out = buf;
+
+   while (True) {
+
+      if (ferror(bzf->handle)) 
+         { BZ_SETERR(BZ_IO_ERROR); return 0; };
+
+      if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) {
+         n = fread ( bzf->buf, sizeof(UChar), 
+                     BZ_MAX_UNUSED, bzf->handle );
+         if (ferror(bzf->handle))
+            { BZ_SETERR(BZ_IO_ERROR); return 0; };
+         bzf->bufN = n;
+         bzf->strm.avail_in = bzf->bufN;
+         bzf->strm.next_in = bzf->buf;
+      }
+
+      ret = BZ2_bzDecompress ( &(bzf->strm) );
+
+      if (ret != BZ_OK && ret != BZ_STREAM_END)
+         { BZ_SETERR(ret); return 0; };
+
+      if (ret == BZ_OK && myfeof(bzf->handle) && 
+          bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0)
+         { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; };
+
+      if (ret == BZ_STREAM_END)
+         { BZ_SETERR(BZ_STREAM_END);
+           return len - bzf->strm.avail_out; };
+      if (bzf->strm.avail_out == 0)
+         { BZ_SETERR(BZ_OK); return len; };
+      
+   }
+
+   return 0; /*not reached*/
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzReadGetUnused) 
+                     ( int*    bzerror, 
+                       BZFILE* b, 
+                       void**  unused, 
+                       int*    nUnused )
+{
+   bzFile* bzf = (bzFile*)b;
+   if (bzf == NULL)
+      { BZ_SETERR(BZ_PARAM_ERROR); return; };
+   if (bzf->lastErr != BZ_STREAM_END)
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+   if (unused == NULL || nUnused == NULL)
+      { BZ_SETERR(BZ_PARAM_ERROR); return; };
+
+   BZ_SETERR(BZ_OK);
+   *nUnused = bzf->strm.avail_in;
+   *unused = bzf->strm.next_in;
+}
+#endif
+
+
+/*---------------------------------------------------*/
+/*--- Misc convenience stuff                      ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzBuffToBuffCompress) 
+                         ( char*         dest, 
+                           unsigned int* destLen,
+                           char*         source, 
+                           unsigned int  sourceLen,
+                           int           blockSize100k, 
+                           int           verbosity, 
+                           int           workFactor )
+{
+   bz_stream strm;
+   int ret;
+
+   if (dest == NULL || destLen == NULL || 
+       source == NULL ||
+       blockSize100k < 1 || blockSize100k > 9 ||
+       verbosity < 0 || verbosity > 4 ||
+       workFactor < 0 || workFactor > 250) 
+      return BZ_PARAM_ERROR;
+
+   if (workFactor == 0) workFactor = 30;
+   strm.bzalloc = NULL;
+   strm.bzfree = NULL;
+   strm.opaque = NULL;
+   ret = BZ2_bzCompressInit ( &strm, blockSize100k, 
+                              verbosity, workFactor );
+   if (ret != BZ_OK) return ret;
+
+   strm.next_in = source;
+   strm.next_out = dest;
+   strm.avail_in = sourceLen;
+   strm.avail_out = *destLen;
+
+   ret = BZ2_bzCompress ( &strm, BZ_FINISH );
+   if (ret == BZ_FINISH_OK) goto output_overflow;
+   if (ret != BZ_STREAM_END) goto errhandler;
+
+   /* normal termination */
+   *destLen -= strm.avail_out;   
+   BZ2_bzCompressEnd ( &strm );
+   return BZ_OK;
+
+   output_overflow:
+   BZ2_bzCompressEnd ( &strm );
+   return BZ_OUTBUFF_FULL;
+
+   errhandler:
+   BZ2_bzCompressEnd ( &strm );
+   return ret;
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzBuffToBuffDecompress) 
+                           ( char*         dest, 
+                             unsigned int* destLen,
+                             char*         source, 
+                             unsigned int  sourceLen,
+                             int           small,
+                             int           verbosity )
+{
+   bz_stream strm;
+   int ret;
+
+   if (dest == NULL || destLen == NULL || 
+       source == NULL ||
+       (small != 0 && small != 1) ||
+       verbosity < 0 || verbosity > 4) 
+          return BZ_PARAM_ERROR;
+
+   strm.bzalloc = NULL;
+   strm.bzfree = NULL;
+   strm.opaque = NULL;
+   ret = BZ2_bzDecompressInit ( &strm, verbosity, small );
+   if (ret != BZ_OK) return ret;
+
+   strm.next_in = source;
+   strm.next_out = dest;
+   strm.avail_in = sourceLen;
+   strm.avail_out = *destLen;
+
+   ret = BZ2_bzDecompress ( &strm );
+   if (ret == BZ_OK) goto output_overflow_or_eof;
+   if (ret != BZ_STREAM_END) goto errhandler;
+
+   /* normal termination */
+   *destLen -= strm.avail_out;
+   BZ2_bzDecompressEnd ( &strm );
+   return BZ_OK;
+
+   output_overflow_or_eof:
+   if (strm.avail_out > 0) {
+      BZ2_bzDecompressEnd ( &strm );
+      return BZ_UNEXPECTED_EOF;
+   } else {
+      BZ2_bzDecompressEnd ( &strm );
+      return BZ_OUTBUFF_FULL;
+   };      
+
+   errhandler:
+   BZ2_bzDecompressEnd ( &strm );
+   return ret; 
+}
+
+
+/*---------------------------------------------------*/
+/*--
+   Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
+   to support better zlib compatibility.
+   This code is not _officially_ part of libbzip2 (yet);
+   I haven't tested it, documented it, or considered the
+   threading-safeness of it.
+   If this code breaks, please contact both Yoshioka and me.
+--*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+/*--
+   return version like "0.9.5d, 4-Sept-1999".
+--*/
+const char * BZ_API(BZ2_bzlibVersion)(void)
+{
+   return BZ_VERSION;
+}
+
+
+#ifndef BZ_NO_STDIO
+/*---------------------------------------------------*/
+
+#if defined(_WIN32) || defined(OS2) || defined(MSDOS)
+#   include 
+#   include 
+#if _MSC_VER > 1410
+#   define SET_BINARY_MODE(file) _setmode(_fileno(file),O_BINARY)
+#else
+#   define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY)
+#endif
+#else
+#   define SET_BINARY_MODE(file)
+#endif
+static
+BZFILE * bzopen_or_bzdopen
+               ( const char *path,   /* no use when bzdopen */
+                 int fd,             /* no use when bzdopen */
+                 const char *mode,
+                 int open_mode)      /* bzopen: 0, bzdopen:1 */
+{
+   int    bzerr;
+   char   unused[BZ_MAX_UNUSED];
+   int    blockSize100k = 9;
+   int    writing       = 0;
+   char   mode2[10]     = "";
+   FILE   *fp           = NULL;
+   BZFILE *bzfp         = NULL;
+   int    verbosity     = 0;
+   int    workFactor    = 30;
+   int    smallMode     = 0;
+   int    nUnused       = 0; 
+
+   if (mode == NULL) return NULL;
+   while (*mode) {
+      switch (*mode) {
+      case 'r':
+         writing = 0; break;
+      case 'w':
+         writing = 1; break;
+      case 's':
+         smallMode = 1; break;
+      default:
+         if (isdigit((int)(*mode))) {
+            blockSize100k = *mode-BZ_HDR_0;
+         }
+      }
+      mode++;
+   }
+   strcat(mode2, writing ? "w" : "r" );
+   strcat(mode2,"b");   /* binary mode */
+
+   if (open_mode==0) {
+      if (path==NULL || strcmp(path,"")==0) {
+        fp = (writing ? stdout : stdin);
+        SET_BINARY_MODE(fp);
+      } else {
+        fp = fopen(path,mode2);
+      }
+   } else {
+#ifdef BZ_STRICT_ANSI
+      fp = NULL;
+#else
+#if _MSC_VER > 1410
+      fp = _fdopen(fd,mode2);
+#else
+	   fp = fdopen(fd,mode2);
+#endif
+#endif
+   }
+   if (fp == NULL) return NULL;
+
+   if (writing) {
+      /* Guard against total chaos and anarchy -- JRS */
+      if (blockSize100k < 1) blockSize100k = 1;
+      if (blockSize100k > 9) blockSize100k = 9; 
+      bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k,
+                             verbosity,workFactor);
+   } else {
+      bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode,
+                            unused,nUnused);
+   }
+   if (bzfp == NULL) {
+      if (fp != stdin && fp != stdout) fclose(fp);
+      return NULL;
+   }
+   return bzfp;
+}
+
+
+/*---------------------------------------------------*/
+/*--
+   open file for read or write.
+      ex) bzopen("file","w9")
+      case path="" or NULL => use stdin or stdout.
+--*/
+BZFILE * BZ_API(BZ2_bzopen)
+               ( const char *path,
+                 const char *mode )
+{
+   return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0);
+}
+
+
+/*---------------------------------------------------*/
+BZFILE * BZ_API(BZ2_bzdopen)
+               ( int fd,
+                 const char *mode )
+{
+   return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1);
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len )
+{
+   int bzerr, nread;
+   if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0;
+   nread = BZ2_bzRead(&bzerr,b,buf,len);
+   if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) {
+      return nread;
+   } else {
+      return -1;
+   }
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len )
+{
+   int bzerr;
+
+   BZ2_bzWrite(&bzerr,b,buf,len);
+   if(bzerr == BZ_OK){
+      return len;
+   }else{
+      return -1;
+   }
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzflush) (BZFILE *b)
+{
+   /* do nothing now... */
+   return 0;
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzclose) (BZFILE* b)
+{
+   int bzerr;
+   FILE *fp;
+   
+   if (b==NULL) {return;}
+   fp = ((bzFile *)b)->handle;
+   if(((bzFile*)b)->writing){
+      BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL);
+      if(bzerr != BZ_OK){
+         BZ2_bzWriteClose(NULL,b,1,NULL,NULL);
+      }
+   }else{
+      BZ2_bzReadClose(&bzerr,b);
+   }
+   if(fp!=stdin && fp!=stdout){
+      fclose(fp);
+   }
+}
+
+
+/*---------------------------------------------------*/
+/*--
+   return last error code 
+--*/
+static const char *bzerrorstrings[] = {
+       "OK"
+      ,"SEQUENCE_ERROR"
+      ,"PARAM_ERROR"
+      ,"MEM_ERROR"
+      ,"DATA_ERROR"
+      ,"DATA_ERROR_MAGIC"
+      ,"IO_ERROR"
+      ,"UNEXPECTED_EOF"
+      ,"OUTBUFF_FULL"
+      ,"CONFIG_ERROR"
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+};
+
+
+const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum)
+{
+   int err = ((bzFile *)b)->lastErr;
+
+   if(err>0) err = 0;
+   *errnum = err;
+   return bzerrorstrings[err*-1];
+}
+#endif
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                           bzlib.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/source/Irrlicht/bzip2/bzlib.h b/source/Irrlicht/bzip2/bzlib.h
new file mode 100644
index 00000000..acb1935e
--- /dev/null
+++ b/source/Irrlicht/bzip2/bzlib.h
@@ -0,0 +1,285 @@
+
+/*-------------------------------------------------------------*/
+/*--- Public header file for the library.                   ---*/
+/*---                                               bzlib.h ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#ifndef _BZLIB_H
+#define _BZLIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// we don't need the FILE* interface
+#define BZ_NO_STDIO
+
+#define BZ_RUN               0
+#define BZ_FLUSH             1
+#define BZ_FINISH            2
+
+#define BZ_OK                0
+#define BZ_RUN_OK            1
+#define BZ_FLUSH_OK          2
+#define BZ_FINISH_OK         3
+#define BZ_STREAM_END        4
+#define BZ_SEQUENCE_ERROR    (-1)
+#define BZ_PARAM_ERROR       (-2)
+#define BZ_MEM_ERROR         (-3)
+#define BZ_DATA_ERROR        (-4)
+#define BZ_DATA_ERROR_MAGIC  (-5)
+#define BZ_IO_ERROR          (-6)
+#define BZ_UNEXPECTED_EOF    (-7)
+#define BZ_OUTBUFF_FULL      (-8)
+#define BZ_CONFIG_ERROR      (-9)
+
+typedef 
+   struct {
+      char *next_in;
+      unsigned int avail_in;
+      unsigned int total_in_lo32;
+      unsigned int total_in_hi32;
+
+      char *next_out;
+      unsigned int avail_out;
+      unsigned int total_out_lo32;
+      unsigned int total_out_hi32;
+
+      void *state;
+
+      void *(*bzalloc)(void *,int,int);
+      void (*bzfree)(void *,void *);
+      void *opaque;
+   } 
+   bz_stream;
+
+
+#ifndef BZ_IMPORT
+#define BZ_EXPORT
+#endif
+
+#ifndef BZ_NO_STDIO
+/* Need a definitition for FILE */
+#include 
+#endif
+
+#ifdef _WIN32
+#   include 
+#   ifdef small
+      /* windows.h define small to char */
+#      undef small
+#   endif
+#   ifdef BZ_EXPORT
+#   define BZ_API(func) WINAPI func
+#   define BZ_EXTERN extern
+#   else
+   /* import windows dll dynamically */
+#   define BZ_API(func) (WINAPI * func)
+#   define BZ_EXTERN
+#   endif
+#else
+#   define BZ_API(func) func
+#   define BZ_EXTERN extern
+#endif
+
+
+/*-- Core (low-level) library functions --*/
+
+BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( 
+      bz_stream* strm, 
+      int        blockSize100k, 
+      int        verbosity, 
+      int        workFactor 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzCompress) ( 
+      bz_stream* strm, 
+      int action 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( 
+      bz_stream* strm 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( 
+      bz_stream *strm, 
+      int       verbosity, 
+      int       small
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( 
+      bz_stream* strm 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( 
+      bz_stream *strm 
+   );
+
+
+
+/*-- High(er) level library functions --*/
+
+#ifndef BZ_NO_STDIO
+#define BZ_MAX_UNUSED 5000
+
+typedef void BZFILE;
+
+BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( 
+      int*  bzerror,   
+      FILE* f, 
+      int   verbosity, 
+      int   small,
+      void* unused,    
+      int   nUnused 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( 
+      int*    bzerror, 
+      BZFILE* b 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( 
+      int*    bzerror, 
+      BZFILE* b, 
+      void**  unused,  
+      int*    nUnused 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzRead) ( 
+      int*    bzerror, 
+      BZFILE* b, 
+      void*   buf, 
+      int     len 
+   );
+
+BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( 
+      int*  bzerror,      
+      FILE* f, 
+      int   blockSize100k, 
+      int   verbosity, 
+      int   workFactor 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzWrite) ( 
+      int*    bzerror, 
+      BZFILE* b, 
+      void*   buf, 
+      int     len 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( 
+      int*          bzerror, 
+      BZFILE*       b, 
+      int           abandon, 
+      unsigned int* nbytes_in, 
+      unsigned int* nbytes_out 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( 
+      int*          bzerror, 
+      BZFILE*       b, 
+      int           abandon, 
+      unsigned int* nbytes_in_lo32, 
+      unsigned int* nbytes_in_hi32, 
+      unsigned int* nbytes_out_lo32, 
+      unsigned int* nbytes_out_hi32
+   );
+#endif
+
+
+/*-- Utility functions --*/
+
+BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( 
+      char*         dest, 
+      unsigned int* destLen,
+      char*         source, 
+      unsigned int  sourceLen,
+      int           blockSize100k, 
+      int           verbosity, 
+      int           workFactor 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( 
+      char*         dest, 
+      unsigned int* destLen,
+      char*         source, 
+      unsigned int  sourceLen,
+      int           small, 
+      int           verbosity 
+   );
+
+
+/*--
+   Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
+   to support better zlib compatibility.
+   This code is not _officially_ part of libbzip2 (yet);
+   I haven't tested it, documented it, or considered the
+   threading-safeness of it.
+   If this code breaks, please contact both Yoshioka and me.
+--*/
+
+BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) (
+      void
+   );
+
+#ifndef BZ_NO_STDIO
+BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) (
+      const char *path,
+      const char *mode
+   );
+
+BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) (
+      int        fd,
+      const char *mode
+   );
+         
+BZ_EXTERN int BZ_API(BZ2_bzread) (
+      BZFILE* b, 
+      void* buf, 
+      int len 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzwrite) (
+      BZFILE* b, 
+      void*   buf, 
+      int     len 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzflush) (
+      BZFILE* b
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzclose) (
+      BZFILE* b
+   );
+
+BZ_EXTERN const char * BZ_API(BZ2_bzerror) (
+      BZFILE *b, 
+      int    *errnum
+   );
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/*-------------------------------------------------------------*/
+/*--- end                                           bzlib.h ---*/
+/*-------------------------------------------------------------*/
diff --git a/source/Irrlicht/bzip2/bzlib_private.h b/source/Irrlicht/bzip2/bzlib_private.h
new file mode 100644
index 00000000..5d0217f4
--- /dev/null
+++ b/source/Irrlicht/bzip2/bzlib_private.h
@@ -0,0 +1,509 @@
+
+/*-------------------------------------------------------------*/
+/*--- Private header file for the library.                  ---*/
+/*---                                       bzlib_private.h ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#ifndef _BZLIB_PRIVATE_H
+#define _BZLIB_PRIVATE_H
+
+#include 
+
+#ifndef BZ_NO_STDIO
+#include 
+#include 
+#include 
+#endif
+
+#include "bzlib.h"
+
+
+
+/*-- General stuff. --*/
+
+#define BZ_VERSION  "1.0.6, 6-Sept-2010"
+
+typedef char            Char;
+typedef unsigned char   Bool;
+typedef unsigned char   UChar;
+typedef int             Int32;
+typedef unsigned int    UInt32;
+typedef short           Int16;
+typedef unsigned short  UInt16;
+
+#define True  ((Bool)1)
+#define False ((Bool)0)
+
+#ifndef __GNUC__
+#define __inline__  /* */
+#endif 
+
+#ifndef BZ_NO_STDIO
+
+extern void BZ2_bz__AssertH__fail ( int errcode );
+#define AssertH(cond,errcode) \
+   { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); }
+
+#if BZ_DEBUG
+#define AssertD(cond,msg) \
+   { if (!(cond)) {       \
+      fprintf ( stderr,   \
+        "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\
+      exit(1); \
+   }}
+#else
+#define AssertD(cond,msg) /* */
+#endif
+
+#define VPrintf0(zf) \
+   fprintf(stderr,zf)
+#define VPrintf1(zf,za1) \
+   fprintf(stderr,zf,za1)
+#define VPrintf2(zf,za1,za2) \
+   fprintf(stderr,zf,za1,za2)
+#define VPrintf3(zf,za1,za2,za3) \
+   fprintf(stderr,zf,za1,za2,za3)
+#define VPrintf4(zf,za1,za2,za3,za4) \
+   fprintf(stderr,zf,za1,za2,za3,za4)
+#define VPrintf5(zf,za1,za2,za3,za4,za5) \
+   fprintf(stderr,zf,za1,za2,za3,za4,za5)
+
+#else
+
+extern void bz_internal_error ( int errcode );
+#define AssertH(cond,errcode) \
+   { if (!(cond)) bz_internal_error ( errcode ); }
+#define AssertD(cond,msg)                do { } while (0)
+#define VPrintf0(zf)                     do { } while (0)
+#define VPrintf1(zf,za1)                 do { } while (0)
+#define VPrintf2(zf,za1,za2)             do { } while (0)
+#define VPrintf3(zf,za1,za2,za3)         do { } while (0)
+#define VPrintf4(zf,za1,za2,za3,za4)     do { } while (0)
+#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0)
+
+#endif
+
+
+#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1)
+#define BZFREE(ppp)  (strm->bzfree)(strm->opaque,(ppp))
+
+
+/*-- Header bytes. --*/
+
+#define BZ_HDR_B 0x42   /* 'B' */
+#define BZ_HDR_Z 0x5a   /* 'Z' */
+#define BZ_HDR_h 0x68   /* 'h' */
+#define BZ_HDR_0 0x30   /* '0' */
+  
+/*-- Constants for the back end. --*/
+
+#define BZ_MAX_ALPHA_SIZE 258
+#define BZ_MAX_CODE_LEN    23
+
+#define BZ_RUNA 0
+#define BZ_RUNB 1
+
+#define BZ_N_GROUPS 6
+#define BZ_G_SIZE   50
+#define BZ_N_ITERS  4
+
+#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE))
+
+
+
+/*-- Stuff for randomising repetitive blocks. --*/
+
+extern Int32 BZ2_rNums[512];
+
+#define BZ_RAND_DECLS                          \
+   Int32 rNToGo;                               \
+   Int32 rTPos                                 \
+
+#define BZ_RAND_INIT_MASK                      \
+   s->rNToGo = 0;                              \
+   s->rTPos  = 0                               \
+
+#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0)
+
+#define BZ_RAND_UPD_MASK                       \
+   if (s->rNToGo == 0) {                       \
+      s->rNToGo = BZ2_rNums[s->rTPos];         \
+      s->rTPos++;                              \
+      if (s->rTPos == 512) s->rTPos = 0;       \
+   }                                           \
+   s->rNToGo--;
+
+
+
+/*-- Stuff for doing CRCs. --*/
+
+extern UInt32 BZ2_crc32Table[256];
+
+#define BZ_INITIALISE_CRC(crcVar)              \
+{                                              \
+   crcVar = 0xffffffffL;                       \
+}
+
+#define BZ_FINALISE_CRC(crcVar)                \
+{                                              \
+   crcVar = ~(crcVar);                         \
+}
+
+#define BZ_UPDATE_CRC(crcVar,cha)              \
+{                                              \
+   crcVar = (crcVar << 8) ^                    \
+            BZ2_crc32Table[(crcVar >> 24) ^    \
+                           ((UChar)cha)];      \
+}
+
+
+
+/*-- States and modes for compression. --*/
+
+#define BZ_M_IDLE      1
+#define BZ_M_RUNNING   2
+#define BZ_M_FLUSHING  3
+#define BZ_M_FINISHING 4
+
+#define BZ_S_OUTPUT    1
+#define BZ_S_INPUT     2
+
+#define BZ_N_RADIX 2
+#define BZ_N_QSORT 12
+#define BZ_N_SHELL 18
+#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2)
+
+
+
+
+/*-- Structure holding all the compression-side stuff. --*/
+
+typedef
+   struct {
+      /* pointer back to the struct bz_stream */
+      bz_stream* strm;
+
+      /* mode this stream is in, and whether inputting */
+      /* or outputting data */
+      Int32    mode;
+      Int32    state;
+
+      /* remembers avail_in when flush/finish requested */
+      UInt32   avail_in_expect;
+
+      /* for doing the block sorting */
+      UInt32*  arr1;
+      UInt32*  arr2;
+      UInt32*  ftab;
+      Int32    origPtr;
+
+      /* aliases for arr1 and arr2 */
+      UInt32*  ptr;
+      UChar*   block;
+      UInt16*  mtfv;
+      UChar*   zbits;
+
+      /* for deciding when to use the fallback sorting algorithm */
+      Int32    workFactor;
+
+      /* run-length-encoding of the input */
+      UInt32   state_in_ch;
+      Int32    state_in_len;
+      BZ_RAND_DECLS;
+
+      /* input and output limits and current posns */
+      Int32    nblock;
+      Int32    nblockMAX;
+      Int32    numZ;
+      Int32    state_out_pos;
+
+      /* map of bytes used in block */
+      Int32    nInUse;
+      Bool     inUse[256];
+      UChar    unseqToSeq[256];
+
+      /* the buffer for bit stream creation */
+      UInt32   bsBuff;
+      Int32    bsLive;
+
+      /* block and combined CRCs */
+      UInt32   blockCRC;
+      UInt32   combinedCRC;
+
+      /* misc administratium */
+      Int32    verbosity;
+      Int32    blockNo;
+      Int32    blockSize100k;
+
+      /* stuff for coding the MTF values */
+      Int32    nMTF;
+      Int32    mtfFreq    [BZ_MAX_ALPHA_SIZE];
+      UChar    selector   [BZ_MAX_SELECTORS];
+      UChar    selectorMtf[BZ_MAX_SELECTORS];
+
+      UChar    len     [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    code    [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    rfreq   [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      /* second dimension: only 3 needed; 4 makes index calculations faster */
+      UInt32   len_pack[BZ_MAX_ALPHA_SIZE][4];
+
+   }
+   EState;
+
+
+
+/*-- externs for compression. --*/
+
+extern void 
+BZ2_blockSort ( EState* );
+
+extern void 
+BZ2_compressBlock ( EState*, Bool );
+
+extern void 
+BZ2_bsInitWrite ( EState* );
+
+extern void 
+BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 );
+
+extern void 
+BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 );
+
+
+
+/*-- states for decompression. --*/
+
+#define BZ_X_IDLE        1
+#define BZ_X_OUTPUT      2
+
+#define BZ_X_MAGIC_1     10
+#define BZ_X_MAGIC_2     11
+#define BZ_X_MAGIC_3     12
+#define BZ_X_MAGIC_4     13
+#define BZ_X_BLKHDR_1    14
+#define BZ_X_BLKHDR_2    15
+#define BZ_X_BLKHDR_3    16
+#define BZ_X_BLKHDR_4    17
+#define BZ_X_BLKHDR_5    18
+#define BZ_X_BLKHDR_6    19
+#define BZ_X_BCRC_1      20
+#define BZ_X_BCRC_2      21
+#define BZ_X_BCRC_3      22
+#define BZ_X_BCRC_4      23
+#define BZ_X_RANDBIT     24
+#define BZ_X_ORIGPTR_1   25
+#define BZ_X_ORIGPTR_2   26
+#define BZ_X_ORIGPTR_3   27
+#define BZ_X_MAPPING_1   28
+#define BZ_X_MAPPING_2   29
+#define BZ_X_SELECTOR_1  30
+#define BZ_X_SELECTOR_2  31
+#define BZ_X_SELECTOR_3  32
+#define BZ_X_CODING_1    33
+#define BZ_X_CODING_2    34
+#define BZ_X_CODING_3    35
+#define BZ_X_MTF_1       36
+#define BZ_X_MTF_2       37
+#define BZ_X_MTF_3       38
+#define BZ_X_MTF_4       39
+#define BZ_X_MTF_5       40
+#define BZ_X_MTF_6       41
+#define BZ_X_ENDHDR_2    42
+#define BZ_X_ENDHDR_3    43
+#define BZ_X_ENDHDR_4    44
+#define BZ_X_ENDHDR_5    45
+#define BZ_X_ENDHDR_6    46
+#define BZ_X_CCRC_1      47
+#define BZ_X_CCRC_2      48
+#define BZ_X_CCRC_3      49
+#define BZ_X_CCRC_4      50
+
+
+
+/*-- Constants for the fast MTF decoder. --*/
+
+#define MTFA_SIZE 4096
+#define MTFL_SIZE 16
+
+
+
+/*-- Structure holding all the decompression-side stuff. --*/
+
+typedef
+   struct {
+      /* pointer back to the struct bz_stream */
+      bz_stream* strm;
+
+      /* state indicator for this stream */
+      Int32    state;
+
+      /* for doing the final run-length decoding */
+      UChar    state_out_ch;
+      Int32    state_out_len;
+      Bool     blockRandomised;
+      BZ_RAND_DECLS;
+
+      /* the buffer for bit stream reading */
+      UInt32   bsBuff;
+      Int32    bsLive;
+
+      /* misc administratium */
+      Int32    blockSize100k;
+      Bool     smallDecompress;
+      Int32    currBlockNo;
+      Int32    verbosity;
+
+      /* for undoing the Burrows-Wheeler transform */
+      Int32    origPtr;
+      UInt32   tPos;
+      Int32    k0;
+      Int32    unzftab[256];
+      Int32    nblock_used;
+      Int32    cftab[257];
+      Int32    cftabCopy[257];
+
+      /* for undoing the Burrows-Wheeler transform (FAST) */
+      UInt32   *tt;
+
+      /* for undoing the Burrows-Wheeler transform (SMALL) */
+      UInt16   *ll16;
+      UChar    *ll4;
+
+      /* stored and calculated CRCs */
+      UInt32   storedBlockCRC;
+      UInt32   storedCombinedCRC;
+      UInt32   calculatedBlockCRC;
+      UInt32   calculatedCombinedCRC;
+
+      /* map of bytes used in block */
+      Int32    nInUse;
+      Bool     inUse[256];
+      Bool     inUse16[16];
+      UChar    seqToUnseq[256];
+
+      /* for decoding the MTF values */
+      UChar    mtfa   [MTFA_SIZE];
+      Int32    mtfbase[256 / MTFL_SIZE];
+      UChar    selector   [BZ_MAX_SELECTORS];
+      UChar    selectorMtf[BZ_MAX_SELECTORS];
+      UChar    len  [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+
+      Int32    limit  [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    base   [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    perm   [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    minLens[BZ_N_GROUPS];
+
+      /* save area for scalars in the main decompress code */
+      Int32    save_i;
+      Int32    save_j;
+      Int32    save_t;
+      Int32    save_alphaSize;
+      Int32    save_nGroups;
+      Int32    save_nSelectors;
+      Int32    save_EOB;
+      Int32    save_groupNo;
+      Int32    save_groupPos;
+      Int32    save_nextSym;
+      Int32    save_nblockMAX;
+      Int32    save_nblock;
+      Int32    save_es;
+      Int32    save_N;
+      Int32    save_curr;
+      Int32    save_zt;
+      Int32    save_zn; 
+      Int32    save_zvec;
+      Int32    save_zj;
+      Int32    save_gSel;
+      Int32    save_gMinlen;
+      Int32*   save_gLimit;
+      Int32*   save_gBase;
+      Int32*   save_gPerm;
+
+   }
+   DState;
+
+
+
+/*-- Macros for decompression. --*/
+
+#define BZ_GET_FAST(cccc)                     \
+    /* c_tPos is unsigned, hence test < 0 is pointless. */ \
+    if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
+    s->tPos = s->tt[s->tPos];                 \
+    cccc = (UChar)(s->tPos & 0xff);           \
+    s->tPos >>= 8;
+
+#define BZ_GET_FAST_C(cccc)                   \
+    /* c_tPos is unsigned, hence test < 0 is pointless. */ \
+    if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \
+    c_tPos = c_tt[c_tPos];                    \
+    cccc = (UChar)(c_tPos & 0xff);            \
+    c_tPos >>= 8;
+
+#define SET_LL4(i,n)                                          \
+   { if (((i) & 0x1) == 0)                                    \
+        s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else    \
+        s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4);  \
+   }
+
+#define GET_LL4(i)                             \
+   ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF)
+
+#define SET_LL(i,n)                          \
+   { s->ll16[i] = (UInt16)(n & 0x0000ffff);  \
+     SET_LL4(i, n >> 16);                    \
+   }
+
+#define GET_LL(i) \
+   (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16))
+
+#define BZ_GET_SMALL(cccc)                            \
+    /* c_tPos is unsigned, hence test < 0 is pointless. */ \
+    if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
+    cccc = BZ2_indexIntoF ( s->tPos, s->cftab );    \
+    s->tPos = GET_LL(s->tPos);
+
+
+/*-- externs for decompression. --*/
+
+extern Int32 
+BZ2_indexIntoF ( Int32, Int32* );
+
+extern Int32 
+BZ2_decompress ( DState* );
+
+extern void 
+BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*,
+                           Int32,  Int32, Int32 );
+
+
+#endif
+
+
+/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/
+
+#ifdef BZ_NO_STDIO
+#ifndef NULL
+#define NULL 0
+#endif
+#endif
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                   bzlib_private.h ---*/
+/*-------------------------------------------------------------*/
diff --git a/source/Irrlicht/bzip2/bzmore b/source/Irrlicht/bzip2/bzmore
new file mode 100644
index 00000000..d3140434
--- /dev/null
+++ b/source/Irrlicht/bzip2/bzmore
@@ -0,0 +1,61 @@
+#!/bin/sh
+
+# Bzmore wrapped for bzip2, 
+# adapted from zmore by Philippe Troin  for Debian GNU/Linux.
+
+PATH="/usr/bin:$PATH"; export PATH
+
+prog=`echo $0 | sed 's|.*/||'`
+case "$prog" in
+	*less)	more=less	;;
+	*)	more=more       ;;
+esac
+
+if test "`echo -n a`" = "-n a"; then
+  # looks like a SysV system:
+  n1=''; n2='\c'
+else
+  n1='-n'; n2=''
+fi
+oldtty=`stty -g 2>/dev/null`
+if stty -cbreak 2>/dev/null; then
+  cb='cbreak'; ncb='-cbreak'
+else
+  # 'stty min 1' resets eof to ^a on both SunOS and SysV!
+  cb='min 1 -icanon'; ncb='icanon eof ^d'
+fi
+if test $? -eq 0 -a -n "$oldtty"; then
+   trap 'stty $oldtty 2>/dev/null; exit' 0 2 3 5 10 13 15
+else
+   trap 'stty $ncb echo 2>/dev/null; exit' 0 2 3 5 10 13 15
+fi
+
+if test $# = 0; then
+    if test -t 0; then
+	echo usage: $prog files...
+    else
+	bzip2 -cdfq | eval $more
+    fi
+else
+    FIRST=1
+    for FILE
+    do
+	if test $FIRST -eq 0; then
+		echo $n1 "--More--(Next file: $FILE)$n2"
+		stty $cb -echo 2>/dev/null
+		ANS=`dd bs=1 count=1 2>/dev/null` 
+		stty $ncb echo 2>/dev/null
+		echo " "
+		if test "$ANS" = 'e' -o "$ANS" = 'q'; then
+			exit
+		fi
+	fi
+	if test "$ANS" != 's'; then
+		echo "------> $FILE <------"
+		bzip2 -cdfq "$FILE" | eval $more
+	fi
+	if test -t; then
+		FIRST=0
+	fi
+    done
+fi
diff --git a/source/Irrlicht/bzip2/bzmore.1 b/source/Irrlicht/bzip2/bzmore.1
new file mode 100644
index 00000000..b437d3b0
--- /dev/null
+++ b/source/Irrlicht/bzip2/bzmore.1
@@ -0,0 +1,152 @@
+.\"Shamelessly copied from zmore.1 by Philippe Troin 
+.\"for Debian GNU/Linux
+.TH BZMORE 1
+.SH NAME
+bzmore, bzless \- file perusal filter for crt viewing of bzip2 compressed text
+.SH SYNOPSIS
+.B bzmore
+[ name ...  ]
+.br
+.B bzless
+[ name ...  ]
+.SH NOTE
+In the following description,
+.I bzless
+and
+.I less
+can be used interchangeably with
+.I bzmore
+and
+.I more.
+.SH DESCRIPTION
+.I  Bzmore
+is a filter which allows examination of compressed or plain text files
+one screenful at a time on a soft-copy terminal.
+.I bzmore
+works on files compressed with
+.I bzip2
+and also on uncompressed files.
+If a file does not exist,
+.I bzmore
+looks for a file of the same name with the addition of a .bz2 suffix.
+.PP
+.I Bzmore
+normally pauses after each screenful, printing --More--
+at the bottom of the screen.
+If the user then types a carriage return, one more line is displayed.
+If the user hits a space,
+another screenful is displayed.  Other possibilities are enumerated later.
+.PP
+.I Bzmore
+looks in the file
+.I /etc/termcap
+to determine terminal characteristics,
+and to determine the default window size.
+On a terminal capable of displaying 24 lines,
+the default window size is 22 lines.
+Other sequences which may be typed when
+.I bzmore
+pauses, and their effects, are as follows (\fIi\fP is an optional integer
+argument, defaulting to 1) :
+.PP
+.IP \fIi\|\fP
+display
+.I i
+more lines, (or another screenful if no argument is given)
+.PP
+.IP ^D
+display 11 more lines (a ``scroll'').
+If
+.I i
+is given, then the scroll size is set to \fIi\|\fP.
+.PP
+.IP d
+same as ^D (control-D)
+.PP
+.IP \fIi\|\fPz
+same as typing a space except that \fIi\|\fP, if present, becomes the new
+window size.  Note that the window size reverts back to the default at the
+end of the current file.
+.PP
+.IP \fIi\|\fPs
+skip \fIi\|\fP lines and print a screenful of lines
+.PP
+.IP \fIi\|\fPf
+skip \fIi\fP screenfuls and print a screenful of lines
+.PP
+.IP "q or Q"
+quit reading the current file; go on to the next (if any)
+.PP
+.IP "e or q"
+When the prompt --More--(Next file: 
+.IR file )
+is printed, this command causes bzmore to exit.
+.PP
+.IP s
+When the prompt --More--(Next file: 
+.IR file )
+is printed, this command causes bzmore to skip the next file and continue.
+.PP 
+.IP =
+Display the current line number.
+.PP
+.IP \fIi\|\fP/expr
+search for the \fIi\|\fP-th occurrence of the regular expression \fIexpr.\fP
+If the pattern is not found,
+.I bzmore
+goes on to the next file (if any).
+Otherwise, a screenful is displayed, starting two lines before the place
+where the expression was found.
+The user's erase and kill characters may be used to edit the regular
+expression.
+Erasing back past the first column cancels the search command.
+.PP
+.IP \fIi\|\fPn
+search for the \fIi\|\fP-th occurrence of the last regular expression entered.
+.PP
+.IP !command
+invoke a shell with \fIcommand\|\fP. 
+The character `!' in "command" are replaced with the
+previous shell command.  The sequence "\\!" is replaced by "!".
+.PP
+.IP ":q or :Q"
+quit reading the current file; go on to the next (if any)
+(same as q or Q).
+.PP
+.IP .
+(dot) repeat the previous command.
+.PP
+The commands take effect immediately, i.e., it is not necessary to
+type a carriage return.
+Up to the time when the command character itself is given,
+the user may hit the line kill character to cancel the numerical
+argument being formed.
+In addition, the user may hit the erase character to redisplay the
+--More-- message.
+.PP
+At any time when output is being sent to the terminal, the user can
+hit the quit key (normally control\-\\).
+.I Bzmore
+will stop sending output, and will display the usual --More--
+prompt.
+The user may then enter one of the above commands in the normal manner.
+Unfortunately, some output is lost when this is done, due to the
+fact that any characters waiting in the terminal's output queue
+are flushed when the quit signal occurs.
+.PP
+The terminal is set to
+.I noecho
+mode by this program so that the output can be continuous.
+What you type will thus not show on your terminal, except for the / and !
+commands.
+.PP
+If the standard output is not a teletype, then
+.I bzmore
+acts just like
+.I bzcat,
+except that a header is printed before each file.
+.SH FILES
+.DT
+/etc/termcap		Terminal data base
+.SH "SEE ALSO"
+more(1), less(1), bzip2(1), bzdiff(1), bzgrep(1)
diff --git a/source/Irrlicht/bzip2/crctable.c b/source/Irrlicht/bzip2/crctable.c
new file mode 100644
index 00000000..1fea7e94
--- /dev/null
+++ b/source/Irrlicht/bzip2/crctable.c
@@ -0,0 +1,104 @@
+
+/*-------------------------------------------------------------*/
+/*--- Table for doing CRCs                                  ---*/
+/*---                                            crctable.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+/*--
+  I think this is an implementation of the AUTODIN-II,
+  Ethernet & FDDI 32-bit CRC standard.  Vaguely derived
+  from code by Rob Warnock, in Section 51 of the
+  comp.compression FAQ.
+--*/
+
+UInt32 BZ2_crc32Table[256] = {
+
+   /*-- Ugly, innit? --*/
+
+   0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L,
+   0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L,
+   0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L,
+   0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL,
+   0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L,
+   0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L,
+   0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L,
+   0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL,
+   0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L,
+   0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L,
+   0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L,
+   0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL,
+   0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L,
+   0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L,
+   0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L,
+   0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL,
+   0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL,
+   0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L,
+   0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L,
+   0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL,
+   0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL,
+   0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L,
+   0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L,
+   0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL,
+   0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL,
+   0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L,
+   0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L,
+   0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL,
+   0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL,
+   0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L,
+   0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L,
+   0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL,
+   0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L,
+   0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL,
+   0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL,
+   0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L,
+   0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L,
+   0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL,
+   0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL,
+   0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L,
+   0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L,
+   0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL,
+   0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL,
+   0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L,
+   0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L,
+   0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL,
+   0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL,
+   0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L,
+   0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L,
+   0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL,
+   0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L,
+   0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L,
+   0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L,
+   0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL,
+   0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L,
+   0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L,
+   0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L,
+   0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL,
+   0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L,
+   0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L,
+   0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L,
+   0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL,
+   0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L,
+   0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L
+};
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                        crctable.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/source/Irrlicht/bzip2/decompress.c b/source/Irrlicht/bzip2/decompress.c
new file mode 100644
index 00000000..311f5668
--- /dev/null
+++ b/source/Irrlicht/bzip2/decompress.c
@@ -0,0 +1,646 @@
+
+/*-------------------------------------------------------------*/
+/*--- Decompression machinery                               ---*/
+/*---                                          decompress.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------------*/
+static
+void makeMaps_d ( DState* s )
+{
+   Int32 i;
+   s->nInUse = 0;
+   for (i = 0; i < 256; i++)
+      if (s->inUse[i]) {
+         s->seqToUnseq[s->nInUse] = i;
+         s->nInUse++;
+      }
+}
+
+
+/*---------------------------------------------------*/
+#define RETURN(rrr)                               \
+   { retVal = rrr; goto save_state_and_return; };
+
+#define GET_BITS(lll,vvv,nnn)                     \
+   case lll: s->state = lll;                      \
+   while (True) {                                 \
+      if (s->bsLive >= nnn) {                     \
+         UInt32 v;                                \
+         v = (s->bsBuff >>                        \
+             (s->bsLive-nnn)) & ((1 << nnn)-1);   \
+         s->bsLive -= nnn;                        \
+         vvv = v;                                 \
+         break;                                   \
+      }                                           \
+      if (s->strm->avail_in == 0) RETURN(BZ_OK);  \
+      s->bsBuff                                   \
+         = (s->bsBuff << 8) |                     \
+           ((UInt32)                              \
+              (*((UChar*)(s->strm->next_in))));   \
+      s->bsLive += 8;                             \
+      s->strm->next_in++;                         \
+      s->strm->avail_in--;                        \
+      s->strm->total_in_lo32++;                   \
+      if (s->strm->total_in_lo32 == 0)            \
+         s->strm->total_in_hi32++;                \
+   }
+
+#define GET_UCHAR(lll,uuu)                        \
+   GET_BITS(lll,uuu,8)
+
+#define GET_BIT(lll,uuu)                          \
+   GET_BITS(lll,uuu,1)
+
+/*---------------------------------------------------*/
+#define GET_MTF_VAL(label1,label2,lval)           \
+{                                                 \
+   if (groupPos == 0) {                           \
+      groupNo++;                                  \
+      if (groupNo >= nSelectors)                  \
+         RETURN(BZ_DATA_ERROR);                   \
+      groupPos = BZ_G_SIZE;                       \
+      gSel = s->selector[groupNo];                \
+      gMinlen = s->minLens[gSel];                 \
+      gLimit = &(s->limit[gSel][0]);              \
+      gPerm = &(s->perm[gSel][0]);                \
+      gBase = &(s->base[gSel][0]);                \
+   }                                              \
+   groupPos--;                                    \
+   zn = gMinlen;                                  \
+   GET_BITS(label1, zvec, zn);                    \
+   while (1) {                                    \
+      if (zn > 20 /* the longest code */)         \
+         RETURN(BZ_DATA_ERROR);                   \
+      if (zvec <= gLimit[zn]) break;              \
+      zn++;                                       \
+      GET_BIT(label2, zj);                        \
+      zvec = (zvec << 1) | zj;                    \
+   };                                             \
+   if (zvec - gBase[zn] < 0                       \
+       || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE)  \
+      RETURN(BZ_DATA_ERROR);                      \
+   lval = gPerm[zvec - gBase[zn]];                \
+}
+
+
+/*---------------------------------------------------*/
+Int32 BZ2_decompress ( DState* s )
+{
+   UChar      uc;
+   Int32      retVal;
+   Int32      minLen, maxLen;
+   bz_stream* strm = s->strm;
+
+   /* stuff that needs to be saved/restored */
+   Int32  i;
+   Int32  j;
+   Int32  t;
+   Int32  alphaSize;
+   Int32  nGroups;
+   Int32  nSelectors;
+   Int32  EOB;
+   Int32  groupNo;
+   Int32  groupPos;
+   Int32  nextSym;
+   Int32  nblockMAX;
+   Int32  nblock;
+   Int32  es;
+   Int32  N;
+   Int32  curr;
+   Int32  zt;
+   Int32  zn; 
+   Int32  zvec;
+   Int32  zj;
+   Int32  gSel;
+   Int32  gMinlen;
+   Int32* gLimit;
+   Int32* gBase;
+   Int32* gPerm;
+
+   if (s->state == BZ_X_MAGIC_1) {
+      /*initialise the save area*/
+      s->save_i           = 0;
+      s->save_j           = 0;
+      s->save_t           = 0;
+      s->save_alphaSize   = 0;
+      s->save_nGroups     = 0;
+      s->save_nSelectors  = 0;
+      s->save_EOB         = 0;
+      s->save_groupNo     = 0;
+      s->save_groupPos    = 0;
+      s->save_nextSym     = 0;
+      s->save_nblockMAX   = 0;
+      s->save_nblock      = 0;
+      s->save_es          = 0;
+      s->save_N           = 0;
+      s->save_curr        = 0;
+      s->save_zt          = 0;
+      s->save_zn          = 0;
+      s->save_zvec        = 0;
+      s->save_zj          = 0;
+      s->save_gSel        = 0;
+      s->save_gMinlen     = 0;
+      s->save_gLimit      = NULL;
+      s->save_gBase       = NULL;
+      s->save_gPerm       = NULL;
+   }
+
+   /*restore from the save area*/
+   i           = s->save_i;
+   j           = s->save_j;
+   t           = s->save_t;
+   alphaSize   = s->save_alphaSize;
+   nGroups     = s->save_nGroups;
+   nSelectors  = s->save_nSelectors;
+   EOB         = s->save_EOB;
+   groupNo     = s->save_groupNo;
+   groupPos    = s->save_groupPos;
+   nextSym     = s->save_nextSym;
+   nblockMAX   = s->save_nblockMAX;
+   nblock      = s->save_nblock;
+   es          = s->save_es;
+   N           = s->save_N;
+   curr        = s->save_curr;
+   zt          = s->save_zt;
+   zn          = s->save_zn; 
+   zvec        = s->save_zvec;
+   zj          = s->save_zj;
+   gSel        = s->save_gSel;
+   gMinlen     = s->save_gMinlen;
+   gLimit      = s->save_gLimit;
+   gBase       = s->save_gBase;
+   gPerm       = s->save_gPerm;
+
+   retVal = BZ_OK;
+
+   switch (s->state) {
+
+      GET_UCHAR(BZ_X_MAGIC_1, uc);
+      if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC);
+
+      GET_UCHAR(BZ_X_MAGIC_2, uc);
+      if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC);
+
+      GET_UCHAR(BZ_X_MAGIC_3, uc)
+      if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC);
+
+      GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8)
+      if (s->blockSize100k < (BZ_HDR_0 + 1) || 
+          s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC);
+      s->blockSize100k -= BZ_HDR_0;
+
+      if (s->smallDecompress) {
+         s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) );
+         s->ll4  = BZALLOC( 
+                      ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) 
+                   );
+         if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR);
+      } else {
+         s->tt  = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) );
+         if (s->tt == NULL) RETURN(BZ_MEM_ERROR);
+      }
+
+      GET_UCHAR(BZ_X_BLKHDR_1, uc);
+
+      if (uc == 0x17) goto endhdr_2;
+      if (uc != 0x31) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_2, uc);
+      if (uc != 0x41) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_3, uc);
+      if (uc != 0x59) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_4, uc);
+      if (uc != 0x26) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_5, uc);
+      if (uc != 0x53) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_6, uc);
+      if (uc != 0x59) RETURN(BZ_DATA_ERROR);
+
+      s->currBlockNo++;
+      if (s->verbosity >= 2)
+         VPrintf1 ( "\n    [%d: huff+mtf ", s->currBlockNo );
+ 
+      s->storedBlockCRC = 0;
+      GET_UCHAR(BZ_X_BCRC_1, uc);
+      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_BCRC_2, uc);
+      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_BCRC_3, uc);
+      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_BCRC_4, uc);
+      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+
+      GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1);
+
+      s->origPtr = 0;
+      GET_UCHAR(BZ_X_ORIGPTR_1, uc);
+      s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+      GET_UCHAR(BZ_X_ORIGPTR_2, uc);
+      s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+      GET_UCHAR(BZ_X_ORIGPTR_3, uc);
+      s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+
+      if (s->origPtr < 0)
+         RETURN(BZ_DATA_ERROR);
+      if (s->origPtr > 10 + 100000*s->blockSize100k) 
+         RETURN(BZ_DATA_ERROR);
+
+      /*--- Receive the mapping table ---*/
+      for (i = 0; i < 16; i++) {
+         GET_BIT(BZ_X_MAPPING_1, uc);
+         if (uc == 1) 
+            s->inUse16[i] = True; else 
+            s->inUse16[i] = False;
+      }
+
+      for (i = 0; i < 256; i++) s->inUse[i] = False;
+
+      for (i = 0; i < 16; i++)
+         if (s->inUse16[i])
+            for (j = 0; j < 16; j++) {
+               GET_BIT(BZ_X_MAPPING_2, uc);
+               if (uc == 1) s->inUse[i * 16 + j] = True;
+            }
+      makeMaps_d ( s );
+      if (s->nInUse == 0) RETURN(BZ_DATA_ERROR);
+      alphaSize = s->nInUse+2;
+
+      /*--- Now the selectors ---*/
+      GET_BITS(BZ_X_SELECTOR_1, nGroups, 3);
+      if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR);
+      GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15);
+      if (nSelectors < 1) RETURN(BZ_DATA_ERROR);
+      for (i = 0; i < nSelectors; i++) {
+         j = 0;
+         while (True) {
+            GET_BIT(BZ_X_SELECTOR_3, uc);
+            if (uc == 0) break;
+            j++;
+            if (j >= nGroups) RETURN(BZ_DATA_ERROR);
+         }
+         s->selectorMtf[i] = j;
+      }
+
+      /*--- Undo the MTF values for the selectors. ---*/
+      {
+         UChar pos[BZ_N_GROUPS], tmp, v;
+         for (v = 0; v < nGroups; v++) pos[v] = v;
+   
+         for (i = 0; i < nSelectors; i++) {
+            v = s->selectorMtf[i];
+            tmp = pos[v];
+            while (v > 0) { pos[v] = pos[v-1]; v--; }
+            pos[0] = tmp;
+            s->selector[i] = tmp;
+         }
+      }
+
+      /*--- Now the coding tables ---*/
+      for (t = 0; t < nGroups; t++) {
+         GET_BITS(BZ_X_CODING_1, curr, 5);
+         for (i = 0; i < alphaSize; i++) {
+            while (True) {
+               if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR);
+               GET_BIT(BZ_X_CODING_2, uc);
+               if (uc == 0) break;
+               GET_BIT(BZ_X_CODING_3, uc);
+               if (uc == 0) curr++; else curr--;
+            }
+            s->len[t][i] = curr;
+         }
+      }
+
+      /*--- Create the Huffman decoding tables ---*/
+      for (t = 0; t < nGroups; t++) {
+         minLen = 32;
+         maxLen = 0;
+         for (i = 0; i < alphaSize; i++) {
+            if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
+            if (s->len[t][i] < minLen) minLen = s->len[t][i];
+         }
+         BZ2_hbCreateDecodeTables ( 
+            &(s->limit[t][0]), 
+            &(s->base[t][0]), 
+            &(s->perm[t][0]), 
+            &(s->len[t][0]),
+            minLen, maxLen, alphaSize
+         );
+         s->minLens[t] = minLen;
+      }
+
+      /*--- Now the MTF values ---*/
+
+      EOB      = s->nInUse+1;
+      nblockMAX = 100000 * s->blockSize100k;
+      groupNo  = -1;
+      groupPos = 0;
+
+      for (i = 0; i <= 255; i++) s->unzftab[i] = 0;
+
+      /*-- MTF init --*/
+      {
+         Int32 ii, jj, kk;
+         kk = MTFA_SIZE-1;
+         for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) {
+            for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
+               s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj);
+               kk--;
+            }
+            s->mtfbase[ii] = kk + 1;
+         }
+      }
+      /*-- end MTF init --*/
+
+      nblock = 0;
+      GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym);
+
+      while (True) {
+
+         if (nextSym == EOB) break;
+
+         if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) {
+
+            es = -1;
+            N = 1;
+            do {
+               /* Check that N doesn't get too big, so that es doesn't
+                  go negative.  The maximum value that can be
+                  RUNA/RUNB encoded is equal to the block size (post
+                  the initial RLE), viz, 900k, so bounding N at 2
+                  million should guard against overflow without
+                  rejecting any legitimate inputs. */
+               if (N >= 2*1024*1024) RETURN(BZ_DATA_ERROR);
+               if (nextSym == BZ_RUNA) es = es + (0+1) * N; else
+               if (nextSym == BZ_RUNB) es = es + (1+1) * N;
+               N = N * 2;
+               GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym);
+            }
+               while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
+
+            es++;
+            uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ];
+            s->unzftab[uc] += es;
+
+            if (s->smallDecompress)
+               while (es > 0) {
+                  if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+                  s->ll16[nblock] = (UInt16)uc;
+                  nblock++;
+                  es--;
+               }
+            else
+               while (es > 0) {
+                  if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+                  s->tt[nblock] = (UInt32)uc;
+                  nblock++;
+                  es--;
+               };
+
+            continue;
+
+         } else {
+
+            if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+
+            /*-- uc = MTF ( nextSym-1 ) --*/
+            {
+               Int32 ii, jj, kk, pp, lno, off;
+               UInt32 nn;
+               nn = (UInt32)(nextSym - 1);
+
+               if (nn < MTFL_SIZE) {
+                  /* avoid general-case expense */
+                  pp = s->mtfbase[0];
+                  uc = s->mtfa[pp+nn];
+                  while (nn > 3) {
+                     Int32 z = pp+nn;
+                     s->mtfa[(z)  ] = s->mtfa[(z)-1];
+                     s->mtfa[(z)-1] = s->mtfa[(z)-2];
+                     s->mtfa[(z)-2] = s->mtfa[(z)-3];
+                     s->mtfa[(z)-3] = s->mtfa[(z)-4];
+                     nn -= 4;
+                  }
+                  while (nn > 0) { 
+                     s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; 
+                  };
+                  s->mtfa[pp] = uc;
+               } else { 
+                  /* general case */
+                  lno = nn / MTFL_SIZE;
+                  off = nn % MTFL_SIZE;
+                  pp = s->mtfbase[lno] + off;
+                  uc = s->mtfa[pp];
+                  while (pp > s->mtfbase[lno]) { 
+                     s->mtfa[pp] = s->mtfa[pp-1]; pp--; 
+                  };
+                  s->mtfbase[lno]++;
+                  while (lno > 0) {
+                     s->mtfbase[lno]--;
+                     s->mtfa[s->mtfbase[lno]] 
+                        = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1];
+                     lno--;
+                  }
+                  s->mtfbase[0]--;
+                  s->mtfa[s->mtfbase[0]] = uc;
+                  if (s->mtfbase[0] == 0) {
+                     kk = MTFA_SIZE-1;
+                     for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) {
+                        for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
+                           s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj];
+                           kk--;
+                        }
+                        s->mtfbase[ii] = kk + 1;
+                     }
+                  }
+               }
+            }
+            /*-- end uc = MTF ( nextSym-1 ) --*/
+
+            s->unzftab[s->seqToUnseq[uc]]++;
+            if (s->smallDecompress)
+               s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else
+               s->tt[nblock]   = (UInt32)(s->seqToUnseq[uc]);
+            nblock++;
+
+            GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym);
+            continue;
+         }
+      }
+
+      /* Now we know what nblock is, we can do a better sanity
+         check on s->origPtr.
+      */
+      if (s->origPtr < 0 || s->origPtr >= nblock)
+         RETURN(BZ_DATA_ERROR);
+
+      /*-- Set up cftab to facilitate generation of T^(-1) --*/
+      /* Check: unzftab entries in range. */
+      for (i = 0; i <= 255; i++) {
+         if (s->unzftab[i] < 0 || s->unzftab[i] > nblock)
+            RETURN(BZ_DATA_ERROR);
+      }
+      /* Actually generate cftab. */
+      s->cftab[0] = 0;
+      for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
+      for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
+      /* Check: cftab entries in range. */
+      for (i = 0; i <= 256; i++) {
+         if (s->cftab[i] < 0 || s->cftab[i] > nblock) {
+            /* s->cftab[i] can legitimately be == nblock */
+            RETURN(BZ_DATA_ERROR);
+         }
+      }
+      /* Check: cftab entries non-descending. */
+      for (i = 1; i <= 256; i++) {
+         if (s->cftab[i-1] > s->cftab[i]) {
+            RETURN(BZ_DATA_ERROR);
+         }
+      }
+
+      s->state_out_len = 0;
+      s->state_out_ch  = 0;
+      BZ_INITIALISE_CRC ( s->calculatedBlockCRC );
+      s->state = BZ_X_OUTPUT;
+      if (s->verbosity >= 2) VPrintf0 ( "rt+rld" );
+
+      if (s->smallDecompress) {
+
+         /*-- Make a copy of cftab, used in generation of T --*/
+         for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i];
+
+         /*-- compute the T vector --*/
+         for (i = 0; i < nblock; i++) {
+            uc = (UChar)(s->ll16[i]);
+            SET_LL(i, s->cftabCopy[uc]);
+            s->cftabCopy[uc]++;
+         }
+
+         /*-- Compute T^(-1) by pointer reversal on T --*/
+         i = s->origPtr;
+         j = GET_LL(i);
+         do {
+            Int32 tmp = GET_LL(j);
+            SET_LL(j, i);
+            i = j;
+            j = tmp;
+         }
+            while (i != s->origPtr);
+
+         s->tPos = s->origPtr;
+         s->nblock_used = 0;
+         if (s->blockRandomised) {
+            BZ_RAND_INIT_MASK;
+            BZ_GET_SMALL(s->k0); s->nblock_used++;
+            BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; 
+         } else {
+            BZ_GET_SMALL(s->k0); s->nblock_used++;
+         }
+
+      } else {
+
+         /*-- compute the T^(-1) vector --*/
+         for (i = 0; i < nblock; i++) {
+            uc = (UChar)(s->tt[i] & 0xff);
+            s->tt[s->cftab[uc]] |= (i << 8);
+            s->cftab[uc]++;
+         }
+
+         s->tPos = s->tt[s->origPtr] >> 8;
+         s->nblock_used = 0;
+         if (s->blockRandomised) {
+            BZ_RAND_INIT_MASK;
+            BZ_GET_FAST(s->k0); s->nblock_used++;
+            BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; 
+         } else {
+            BZ_GET_FAST(s->k0); s->nblock_used++;
+         }
+
+      }
+
+      RETURN(BZ_OK);
+
+
+
+    endhdr_2:
+
+      GET_UCHAR(BZ_X_ENDHDR_2, uc);
+      if (uc != 0x72) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_ENDHDR_3, uc);
+      if (uc != 0x45) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_ENDHDR_4, uc);
+      if (uc != 0x38) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_ENDHDR_5, uc);
+      if (uc != 0x50) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_ENDHDR_6, uc);
+      if (uc != 0x90) RETURN(BZ_DATA_ERROR);
+
+      s->storedCombinedCRC = 0;
+      GET_UCHAR(BZ_X_CCRC_1, uc);
+      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_CCRC_2, uc);
+      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_CCRC_3, uc);
+      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_CCRC_4, uc);
+      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+
+      s->state = BZ_X_IDLE;
+      RETURN(BZ_STREAM_END);
+
+      default: AssertH ( False, 4001 );
+   }
+
+   AssertH ( False, 4002 );
+
+   save_state_and_return:
+
+   s->save_i           = i;
+   s->save_j           = j;
+   s->save_t           = t;
+   s->save_alphaSize   = alphaSize;
+   s->save_nGroups     = nGroups;
+   s->save_nSelectors  = nSelectors;
+   s->save_EOB         = EOB;
+   s->save_groupNo     = groupNo;
+   s->save_groupPos    = groupPos;
+   s->save_nextSym     = nextSym;
+   s->save_nblockMAX   = nblockMAX;
+   s->save_nblock      = nblock;
+   s->save_es          = es;
+   s->save_N           = N;
+   s->save_curr        = curr;
+   s->save_zt          = zt;
+   s->save_zn          = zn;
+   s->save_zvec        = zvec;
+   s->save_zj          = zj;
+   s->save_gSel        = gSel;
+   s->save_gMinlen     = gMinlen;
+   s->save_gLimit      = gLimit;
+   s->save_gBase       = gBase;
+   s->save_gPerm       = gPerm;
+
+   return retVal;   
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                      decompress.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/source/Irrlicht/bzip2/dlltest.c b/source/Irrlicht/bzip2/dlltest.c
new file mode 100644
index 00000000..03fa1462
--- /dev/null
+++ b/source/Irrlicht/bzip2/dlltest.c
@@ -0,0 +1,175 @@
+/*
+   minibz2
+      libbz2.dll test program.
+      by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
+      This file is Public Domain.  Welcome any email to me.
+
+   usage: minibz2 [-d] [-{1,2,..9}] [[srcfilename] destfilename]
+*/
+
+#define BZ_IMPORT
+#include 
+#include 
+#include "bzlib.h"
+#ifdef _WIN32
+#include 
+#endif
+
+
+#ifdef _WIN32
+
+#define BZ2_LIBNAME "libbz2-1.0.2.DLL" 
+
+#include 
+static int BZ2DLLLoaded = 0;
+static HINSTANCE BZ2DLLhLib;
+int BZ2DLLLoadLibrary(void)
+{
+   HINSTANCE hLib;
+
+   if(BZ2DLLLoaded==1){return 0;}
+   hLib=LoadLibrary(BZ2_LIBNAME);
+   if(hLib == NULL){
+      fprintf(stderr,"Can't load %s\n",BZ2_LIBNAME);
+      return -1;
+   }
+   BZ2_bzlibVersion=GetProcAddress(hLib,"BZ2_bzlibVersion");
+   BZ2_bzopen=GetProcAddress(hLib,"BZ2_bzopen");
+   BZ2_bzdopen=GetProcAddress(hLib,"BZ2_bzdopen");
+   BZ2_bzread=GetProcAddress(hLib,"BZ2_bzread");
+   BZ2_bzwrite=GetProcAddress(hLib,"BZ2_bzwrite");
+   BZ2_bzflush=GetProcAddress(hLib,"BZ2_bzflush");
+   BZ2_bzclose=GetProcAddress(hLib,"BZ2_bzclose");
+   BZ2_bzerror=GetProcAddress(hLib,"BZ2_bzerror");
+
+   if (!BZ2_bzlibVersion || !BZ2_bzopen || !BZ2_bzdopen
+       || !BZ2_bzread || !BZ2_bzwrite || !BZ2_bzflush
+       || !BZ2_bzclose || !BZ2_bzerror) {
+      fprintf(stderr,"GetProcAddress failed.\n");
+      return -1;
+   }
+   BZ2DLLLoaded=1;
+   BZ2DLLhLib=hLib;
+   return 0;
+
+}
+int BZ2DLLFreeLibrary(void)
+{
+   if(BZ2DLLLoaded==0){return 0;}
+   FreeLibrary(BZ2DLLhLib);
+   BZ2DLLLoaded=0;
+}
+#endif /* WIN32 */
+
+void usage(void)
+{
+   puts("usage: minibz2 [-d] [-{1,2,..9}] [[srcfilename] destfilename]");
+}
+
+int main(int argc,char *argv[])
+{
+   int decompress = 0;
+   int level = 9;
+   char *fn_r = NULL;
+   char *fn_w = NULL;
+
+#ifdef _WIN32
+   if(BZ2DLLLoadLibrary()<0){
+      fprintf(stderr,"Loading of %s failed.  Giving up.\n", BZ2_LIBNAME);
+      exit(1);
+   }
+   printf("Loading of %s succeeded.  Library version is %s.\n",
+          BZ2_LIBNAME, BZ2_bzlibVersion() );
+#endif
+   while(++argv,--argc){
+      if(**argv =='-' || **argv=='/'){
+         char *p;
+
+         for(p=*argv+1;*p;p++){
+            if(*p=='d'){
+               decompress = 1;
+            }else if('1'<=*p && *p<='9'){
+               level = *p - '0';
+            }else{
+               usage();
+               exit(1);
+            }
+         }
+      }else{
+         break;
+      }
+   }
+   if(argc>=1){
+      fn_r = *argv;
+      argc--;argv++;
+   }else{
+      fn_r = NULL;
+   }
+   if(argc>=1){
+      fn_w = *argv;
+      argc--;argv++;
+   }else{
+      fn_w = NULL;
+   }
+   {
+      int len;
+      char buff[0x1000];
+      char mode[10];
+
+      if(decompress){
+         BZFILE *BZ2fp_r = NULL;
+         FILE *fp_w = NULL;
+
+         if(fn_w){
+            if((fp_w = fopen(fn_w,"wb"))==NULL){
+               printf("can't open [%s]\n",fn_w);
+               perror("reason:");
+               exit(1);
+            }
+         }else{
+            fp_w = stdout;
+         }
+         if((fn_r == NULL && (BZ2fp_r = BZ2_bzdopen(fileno(stdin),"rb"))==NULL)
+            || (fn_r != NULL && (BZ2fp_r = BZ2_bzopen(fn_r,"rb"))==NULL)){
+            printf("can't bz2openstream\n");
+            exit(1);
+         }
+         while((len=BZ2_bzread(BZ2fp_r,buff,0x1000))>0){
+            fwrite(buff,1,len,fp_w);
+         }
+         BZ2_bzclose(BZ2fp_r);
+         if(fp_w != stdout) fclose(fp_w);
+      }else{
+         BZFILE *BZ2fp_w = NULL;
+         FILE *fp_r = NULL;
+
+         if(fn_r){
+            if((fp_r = fopen(fn_r,"rb"))==NULL){
+               printf("can't open [%s]\n",fn_r);
+               perror("reason:");
+               exit(1);
+            }
+         }else{
+            fp_r = stdin;
+         }
+         mode[0]='w';
+         mode[1] = '0' + level;
+         mode[2] = '\0';
+
+         if((fn_w == NULL && (BZ2fp_w = BZ2_bzdopen(fileno(stdout),mode))==NULL)
+            || (fn_w !=NULL && (BZ2fp_w = BZ2_bzopen(fn_w,mode))==NULL)){
+            printf("can't bz2openstream\n");
+            exit(1);
+         }
+         while((len=fread(buff,1,0x1000,fp_r))>0){
+            BZ2_bzwrite(BZ2fp_w,buff,len);
+         }
+         BZ2_bzclose(BZ2fp_w);
+         if(fp_r!=stdin)fclose(fp_r);
+      }
+   }
+#ifdef _WIN32
+   BZ2DLLFreeLibrary();
+#endif
+   return 0;
+}
diff --git a/source/Irrlicht/bzip2/dlltest.dsp b/source/Irrlicht/bzip2/dlltest.dsp
new file mode 100644
index 00000000..4b1615ed
--- /dev/null
+++ b/source/Irrlicht/bzip2/dlltest.dsp
@@ -0,0 +1,93 @@
+# Microsoft Developer Studio Project File - Name="dlltest" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** ҏWȂł **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=dlltest - Win32 Debug
+!MESSAGE ͗LҲ̧قł͂܂B ۼުĂނ邽߂ɂ NMAKE gpĂB
+!MESSAGE [Ҳ̧ق̴߰] ނgpĎsĂ
+!MESSAGE 
+!MESSAGE NMAKE /f "dlltest.mak".
+!MESSAGE 
+!MESSAGE NMAKE ̎sɍ\wł܂
+!MESSAGE  ײݏϸۂ̐ݒ`܂B:
+!MESSAGE 
+!MESSAGE NMAKE /f "dlltest.mak" CFG="dlltest - Win32 Debug"
+!MESSAGE 
+!MESSAGE I”\ Ӱ:
+!MESSAGE 
+!MESSAGE "dlltest - Win32 Release" ("Win32 (x86) Console Application" p)
+!MESSAGE "dlltest - Win32 Debug" ("Win32 (x86) Console Application" p)
+!MESSAGE 
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "dlltest - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x411 /d "NDEBUG"
+# ADD RSC /l 0x411 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"minibz2.exe"
+
+!ELSEIF  "$(CFG)" == "dlltest - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "dlltest_"
+# PROP BASE Intermediate_Dir "dlltest_"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "dlltest_"
+# PROP Intermediate_Dir "dlltest_"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x411 /d "_DEBUG"
+# ADD RSC /l 0x411 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"minibz2.exe" /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "dlltest - Win32 Release"
+# Name "dlltest - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\bzlib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\dlltest.c
+# End Source File
+# End Target
+# End Project
diff --git a/source/Irrlicht/bzip2/entities.xml b/source/Irrlicht/bzip2/entities.xml
new file mode 100644
index 00000000..4b28f346
--- /dev/null
+++ b/source/Irrlicht/bzip2/entities.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/source/Irrlicht/bzip2/format.pl b/source/Irrlicht/bzip2/format.pl
new file mode 100755
index 00000000..f169fd9d
--- /dev/null
+++ b/source/Irrlicht/bzip2/format.pl
@@ -0,0 +1,68 @@
+#!/usr/bin/perl -w
+#
+# ------------------------------------------------------------------
+# This file is part of bzip2/libbzip2, a program and library for
+# lossless, block-sorting data compression.
+#
+# bzip2/libbzip2 version 1.0.6 of 6 September 2010
+# Copyright (C) 1996-2010 Julian Seward 
+#
+# Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+# README file.
+#
+# This program is released under the terms of the license contained
+# in the file LICENSE.
+# ------------------------------------------------------------------
+#
+use strict;
+
+# get command line values:
+if ( $#ARGV !=1 ) {
+    die "Usage:  $0 xml_infile xml_outfile\n";
+}
+
+my $infile = shift;
+# check infile exists
+die "Can't find file \"$infile\""
+  unless -f $infile;
+# check we can read infile
+if (! -r $infile) {
+    die "Can't read input $infile\n";
+}
+# check we can open infile
+open( INFILE,"<$infile" ) or 
+    die "Can't input $infile $!";
+
+#my $outfile = 'fmt-manual.xml';
+my $outfile = shift;
+#print "Infile: $infile, Outfile: $outfile\n";
+# check we can write to outfile
+open( OUTFILE,">$outfile" ) or 
+    die "Can't output $outfile $! for writing";
+
+my ($prev, $curr, $str);
+$prev = ''; $curr = '';
+while (  ) {
+
+		print OUTFILE $prev;
+    $prev = $curr;
+    $curr = $_;
+    $str = '';
+
+    if ( $prev =~ /$|$/ ) {
+        chomp $prev;
+        $curr = join( '', $prev, "|<\/screen>/ ) {
+        chomp $prev;
+        $curr = join( '', $prev, "]]>", $curr );
+				$prev = '';
+        next;
+    }
+}
+print OUTFILE $curr;
+close INFILE;
+close OUTFILE;
+exit;
diff --git a/source/Irrlicht/bzip2/huffman.c b/source/Irrlicht/bzip2/huffman.c
new file mode 100644
index 00000000..2283fdbc
--- /dev/null
+++ b/source/Irrlicht/bzip2/huffman.c
@@ -0,0 +1,205 @@
+
+/*-------------------------------------------------------------*/
+/*--- Huffman coding low-level stuff                        ---*/
+/*---                                             huffman.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+/*---------------------------------------------------*/
+#define WEIGHTOF(zz0)  ((zz0) & 0xffffff00)
+#define DEPTHOF(zz1)   ((zz1) & 0x000000ff)
+#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3))
+
+#define ADDWEIGHTS(zw1,zw2)                           \
+   (WEIGHTOF(zw1)+WEIGHTOF(zw2)) |                    \
+   (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2)))
+
+#define UPHEAP(z)                                     \
+{                                                     \
+   Int32 zz, tmp;                                     \
+   zz = z; tmp = heap[zz];                            \
+   while (weight[tmp] < weight[heap[zz >> 1]]) {      \
+      heap[zz] = heap[zz >> 1];                       \
+      zz >>= 1;                                       \
+   }                                                  \
+   heap[zz] = tmp;                                    \
+}
+
+#define DOWNHEAP(z)                                   \
+{                                                     \
+   Int32 zz, yy, tmp;                                 \
+   zz = z; tmp = heap[zz];                            \
+   while (True) {                                     \
+      yy = zz << 1;                                   \
+      if (yy > nHeap) break;                          \
+      if (yy < nHeap &&                               \
+          weight[heap[yy+1]] < weight[heap[yy]])      \
+         yy++;                                        \
+      if (weight[tmp] < weight[heap[yy]]) break;      \
+      heap[zz] = heap[yy];                            \
+      zz = yy;                                        \
+   }                                                  \
+   heap[zz] = tmp;                                    \
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_hbMakeCodeLengths ( UChar *len, 
+                             Int32 *freq,
+                             Int32 alphaSize,
+                             Int32 maxLen )
+{
+   /*--
+      Nodes and heap entries run from 1.  Entry 0
+      for both the heap and nodes is a sentinel.
+   --*/
+   Int32 nNodes, nHeap, n1, n2, i, j, k;
+   Bool  tooLong;
+
+   Int32 heap   [ BZ_MAX_ALPHA_SIZE + 2 ];
+   Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ];
+   Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; 
+
+   for (i = 0; i < alphaSize; i++)
+      weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
+
+   while (True) {
+
+      nNodes = alphaSize;
+      nHeap = 0;
+
+      heap[0] = 0;
+      weight[0] = 0;
+      parent[0] = -2;
+
+      for (i = 1; i <= alphaSize; i++) {
+         parent[i] = -1;
+         nHeap++;
+         heap[nHeap] = i;
+         UPHEAP(nHeap);
+      }
+
+      AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 );
+   
+      while (nHeap > 1) {
+         n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
+         n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
+         nNodes++;
+         parent[n1] = parent[n2] = nNodes;
+         weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]);
+         parent[nNodes] = -1;
+         nHeap++;
+         heap[nHeap] = nNodes;
+         UPHEAP(nHeap);
+      }
+
+      AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 );
+
+      tooLong = False;
+      for (i = 1; i <= alphaSize; i++) {
+         j = 0;
+         k = i;
+         while (parent[k] >= 0) { k = parent[k]; j++; }
+         len[i-1] = j;
+         if (j > maxLen) tooLong = True;
+      }
+      
+      if (! tooLong) break;
+
+      /* 17 Oct 04: keep-going condition for the following loop used
+         to be 'i < alphaSize', which missed the last element,
+         theoretically leading to the possibility of the compressor
+         looping.  However, this count-scaling step is only needed if
+         one of the generated Huffman code words is longer than
+         maxLen, which up to and including version 1.0.2 was 20 bits,
+         which is extremely unlikely.  In version 1.0.3 maxLen was
+         changed to 17 bits, which has minimal effect on compression
+         ratio, but does mean this scaling step is used from time to
+         time, enough to verify that it works.
+
+         This means that bzip2-1.0.3 and later will only produce
+         Huffman codes with a maximum length of 17 bits.  However, in
+         order to preserve backwards compatibility with bitstreams
+         produced by versions pre-1.0.3, the decompressor must still
+         handle lengths of up to 20. */
+
+      for (i = 1; i <= alphaSize; i++) {
+         j = weight[i] >> 8;
+         j = 1 + (j / 2);
+         weight[i] = j << 8;
+      }
+   }
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_hbAssignCodes ( Int32 *code,
+                         UChar *length,
+                         Int32 minLen,
+                         Int32 maxLen,
+                         Int32 alphaSize )
+{
+   Int32 n, vec, i;
+
+   vec = 0;
+   for (n = minLen; n <= maxLen; n++) {
+      for (i = 0; i < alphaSize; i++)
+         if (length[i] == n) { code[i] = vec; vec++; };
+      vec <<= 1;
+   }
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_hbCreateDecodeTables ( Int32 *limit,
+                                Int32 *base,
+                                Int32 *perm,
+                                UChar *length,
+                                Int32 minLen,
+                                Int32 maxLen,
+                                Int32 alphaSize )
+{
+   Int32 pp, i, j, vec;
+
+   pp = 0;
+   for (i = minLen; i <= maxLen; i++)
+      for (j = 0; j < alphaSize; j++)
+         if (length[j] == i) { perm[pp] = j; pp++; };
+
+   for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0;
+   for (i = 0; i < alphaSize; i++) base[length[i]+1]++;
+
+   for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1];
+
+   for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0;
+   vec = 0;
+
+   for (i = minLen; i <= maxLen; i++) {
+      vec += (base[i+1] - base[i]);
+      limit[i] = vec-1;
+      vec <<= 1;
+   }
+   for (i = minLen + 1; i <= maxLen; i++)
+      base[i] = ((limit[i-1] + 1) << 1) - base[i];
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                         huffman.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/source/Irrlicht/bzip2/libbz2.def b/source/Irrlicht/bzip2/libbz2.def
new file mode 100644
index 00000000..2dc0dd89
--- /dev/null
+++ b/source/Irrlicht/bzip2/libbz2.def
@@ -0,0 +1,27 @@
+LIBRARY			LIBBZ2
+DESCRIPTION		"libbzip2: library for data compression"
+EXPORTS
+	BZ2_bzCompressInit
+	BZ2_bzCompress
+	BZ2_bzCompressEnd
+	BZ2_bzDecompressInit
+	BZ2_bzDecompress
+	BZ2_bzDecompressEnd
+	BZ2_bzReadOpen
+	BZ2_bzReadClose
+	BZ2_bzReadGetUnused
+	BZ2_bzRead
+	BZ2_bzWriteOpen
+	BZ2_bzWrite
+	BZ2_bzWriteClose
+	BZ2_bzWriteClose64
+	BZ2_bzBuffToBuffCompress
+	BZ2_bzBuffToBuffDecompress
+	BZ2_bzlibVersion
+	BZ2_bzopen
+	BZ2_bzdopen
+	BZ2_bzread
+	BZ2_bzwrite
+	BZ2_bzflush
+	BZ2_bzclose
+	BZ2_bzerror
diff --git a/source/Irrlicht/bzip2/libbz2.dsp b/source/Irrlicht/bzip2/libbz2.dsp
new file mode 100644
index 00000000..a21a20f7
--- /dev/null
+++ b/source/Irrlicht/bzip2/libbz2.dsp
@@ -0,0 +1,130 @@
+# Microsoft Developer Studio Project File - Name="libbz2" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** ҏWȂł **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=libbz2 - Win32 Debug
+!MESSAGE ͗LҲ̧قł͂܂B ۼުĂނ邽߂ɂ NMAKE gpĂB
+!MESSAGE [Ҳ̧ق̴߰] ނgpĎsĂ
+!MESSAGE 
+!MESSAGE NMAKE /f "libbz2.mak".
+!MESSAGE 
+!MESSAGE NMAKE ̎sɍ\wł܂
+!MESSAGE  ײݏϸۂ̐ݒ`܂B:
+!MESSAGE 
+!MESSAGE NMAKE /f "libbz2.mak" CFG="libbz2 - Win32 Debug"
+!MESSAGE 
+!MESSAGE I”\ Ӱ:
+!MESSAGE 
+!MESSAGE "libbz2 - Win32 Release" ("Win32 (x86) Dynamic-Link Library" p)
+!MESSAGE "libbz2 - Win32 Debug" ("Win32 (x86) Dynamic-Link Library" p)
+!MESSAGE 
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "libbz2 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+# ADD BASE RSC /l 0x411 /d "NDEBUG"
+# ADD RSC /l 0x411 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 /out:"libbz2.dll"
+
+!ELSEIF  "$(CFG)" == "libbz2 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+# ADD BASE RSC /l 0x411 /d "_DEBUG"
+# ADD RSC /l 0x411 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"libbz2.dll" /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "libbz2 - Win32 Release"
+# Name "libbz2 - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\blocksort.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\bzlib.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\bzlib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\bzlib_private.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\compress.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\crctable.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\decompress.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\huffman.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\libbz2.def
+# End Source File
+# Begin Source File
+
+SOURCE=.\randtable.c
+# End Source File
+# End Target
+# End Project
diff --git a/source/Irrlicht/bzip2/makefile.msc b/source/Irrlicht/bzip2/makefile.msc
new file mode 100644
index 00000000..799a18a5
--- /dev/null
+++ b/source/Irrlicht/bzip2/makefile.msc
@@ -0,0 +1,63 @@
+# Makefile for Microsoft Visual C++ 6.0
+# usage: nmake -f makefile.msc
+# K.M. Syring (syring@gsf.de)
+# Fixed up by JRS for bzip2-0.9.5d release.
+
+CC=cl
+CFLAGS= -DWIN32 -MD -Ox -D_FILE_OFFSET_BITS=64 -nologo
+
+OBJS= blocksort.obj  \
+      huffman.obj    \
+      crctable.obj   \
+      randtable.obj  \
+      compress.obj   \
+      decompress.obj \
+      bzlib.obj
+
+all: lib bzip2 test
+
+bzip2: lib
+	$(CC) $(CFLAGS) -o bzip2 bzip2.c libbz2.lib setargv.obj
+	$(CC) $(CFLAGS) -o bzip2recover bzip2recover.c
+
+lib: $(OBJS)
+	lib /out:libbz2.lib $(OBJS)
+
+test: bzip2
+	type words1
+	.\\bzip2 -1  < sample1.ref > sample1.rb2
+	.\\bzip2 -2  < sample2.ref > sample2.rb2
+	.\\bzip2 -3  < sample3.ref > sample3.rb2
+	.\\bzip2 -d  < sample1.bz2 > sample1.tst
+	.\\bzip2 -d  < sample2.bz2 > sample2.tst
+	.\\bzip2 -ds < sample3.bz2 > sample3.tst
+	@echo All six of the fc's should find no differences.
+	@echo If fc finds an error on sample3.bz2, this could be
+	@echo because WinZip's 'TAR file smart CR/LF conversion'
+	@echo is too clever for its own good.  Disable this option.
+	@echo The correct size for sample3.ref is 120,244.  If it
+	@echo is 150,251, WinZip has messed it up.
+	fc sample1.bz2 sample1.rb2 
+	fc sample2.bz2 sample2.rb2
+	fc sample3.bz2 sample3.rb2
+	fc sample1.tst sample1.ref
+	fc sample2.tst sample2.ref
+	fc sample3.tst sample3.ref
+
+
+
+clean: 
+	del *.obj
+	del libbz2.lib 
+	del bzip2.exe
+	del bzip2recover.exe
+	del sample1.rb2 
+	del sample2.rb2 
+	del sample3.rb2
+	del sample1.tst 
+	del sample2.tst
+	del sample3.tst
+
+.c.obj: 
+	$(CC) $(CFLAGS) -c $*.c -o $*.obj
+
diff --git a/source/Irrlicht/bzip2/mk251.c b/source/Irrlicht/bzip2/mk251.c
new file mode 100644
index 00000000..c9c36f6c
--- /dev/null
+++ b/source/Irrlicht/bzip2/mk251.c
@@ -0,0 +1,31 @@
+
+/* Spew out a long sequence of the byte 251.  When fed to bzip2
+   versions 1.0.0 or 1.0.1, causes it to die with internal error
+   1007 in blocksort.c.  This assertion misses an extremely rare
+   case, which is fixed in this version (1.0.2) and above.
+*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include 
+
+int main ()
+{
+   int i;
+   for (i = 0; i < 48500000 ; i++)
+     putchar(251);
+   return 0;
+}
diff --git a/source/Irrlicht/bzip2/randtable.c b/source/Irrlicht/bzip2/randtable.c
new file mode 100644
index 00000000..6d624599
--- /dev/null
+++ b/source/Irrlicht/bzip2/randtable.c
@@ -0,0 +1,84 @@
+
+/*-------------------------------------------------------------*/
+/*--- Table for randomising repetitive blocks               ---*/
+/*---                                           randtable.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------*/
+Int32 BZ2_rNums[512] = { 
+   619, 720, 127, 481, 931, 816, 813, 233, 566, 247, 
+   985, 724, 205, 454, 863, 491, 741, 242, 949, 214, 
+   733, 859, 335, 708, 621, 574, 73, 654, 730, 472, 
+   419, 436, 278, 496, 867, 210, 399, 680, 480, 51, 
+   878, 465, 811, 169, 869, 675, 611, 697, 867, 561, 
+   862, 687, 507, 283, 482, 129, 807, 591, 733, 623, 
+   150, 238, 59, 379, 684, 877, 625, 169, 643, 105, 
+   170, 607, 520, 932, 727, 476, 693, 425, 174, 647, 
+   73, 122, 335, 530, 442, 853, 695, 249, 445, 515, 
+   909, 545, 703, 919, 874, 474, 882, 500, 594, 612, 
+   641, 801, 220, 162, 819, 984, 589, 513, 495, 799, 
+   161, 604, 958, 533, 221, 400, 386, 867, 600, 782, 
+   382, 596, 414, 171, 516, 375, 682, 485, 911, 276, 
+   98, 553, 163, 354, 666, 933, 424, 341, 533, 870, 
+   227, 730, 475, 186, 263, 647, 537, 686, 600, 224, 
+   469, 68, 770, 919, 190, 373, 294, 822, 808, 206, 
+   184, 943, 795, 384, 383, 461, 404, 758, 839, 887, 
+   715, 67, 618, 276, 204, 918, 873, 777, 604, 560, 
+   951, 160, 578, 722, 79, 804, 96, 409, 713, 940, 
+   652, 934, 970, 447, 318, 353, 859, 672, 112, 785, 
+   645, 863, 803, 350, 139, 93, 354, 99, 820, 908, 
+   609, 772, 154, 274, 580, 184, 79, 626, 630, 742, 
+   653, 282, 762, 623, 680, 81, 927, 626, 789, 125, 
+   411, 521, 938, 300, 821, 78, 343, 175, 128, 250, 
+   170, 774, 972, 275, 999, 639, 495, 78, 352, 126, 
+   857, 956, 358, 619, 580, 124, 737, 594, 701, 612, 
+   669, 112, 134, 694, 363, 992, 809, 743, 168, 974, 
+   944, 375, 748, 52, 600, 747, 642, 182, 862, 81, 
+   344, 805, 988, 739, 511, 655, 814, 334, 249, 515, 
+   897, 955, 664, 981, 649, 113, 974, 459, 893, 228, 
+   433, 837, 553, 268, 926, 240, 102, 654, 459, 51, 
+   686, 754, 806, 760, 493, 403, 415, 394, 687, 700, 
+   946, 670, 656, 610, 738, 392, 760, 799, 887, 653, 
+   978, 321, 576, 617, 626, 502, 894, 679, 243, 440, 
+   680, 879, 194, 572, 640, 724, 926, 56, 204, 700, 
+   707, 151, 457, 449, 797, 195, 791, 558, 945, 679, 
+   297, 59, 87, 824, 713, 663, 412, 693, 342, 606, 
+   134, 108, 571, 364, 631, 212, 174, 643, 304, 329, 
+   343, 97, 430, 751, 497, 314, 983, 374, 822, 928, 
+   140, 206, 73, 263, 980, 736, 876, 478, 430, 305, 
+   170, 514, 364, 692, 829, 82, 855, 953, 676, 246, 
+   369, 970, 294, 750, 807, 827, 150, 790, 288, 923, 
+   804, 378, 215, 828, 592, 281, 565, 555, 710, 82, 
+   896, 831, 547, 261, 524, 462, 293, 465, 502, 56, 
+   661, 821, 976, 991, 658, 869, 905, 758, 745, 193, 
+   768, 550, 608, 933, 378, 286, 215, 979, 792, 961, 
+   61, 688, 793, 644, 986, 403, 106, 366, 905, 644, 
+   372, 567, 466, 434, 645, 210, 389, 550, 919, 135, 
+   780, 773, 635, 389, 707, 100, 626, 958, 165, 504, 
+   920, 176, 193, 713, 857, 265, 203, 50, 668, 108, 
+   645, 990, 626, 197, 510, 357, 358, 850, 858, 364, 
+   936, 638
+};
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                       randtable.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/source/Irrlicht/bzip2/spewG.c b/source/Irrlicht/bzip2/spewG.c
new file mode 100644
index 00000000..14a36493
--- /dev/null
+++ b/source/Irrlicht/bzip2/spewG.c
@@ -0,0 +1,54 @@
+
+/* spew out a thoroughly gigantic file designed so that bzip2
+   can compress it reasonably rapidly.  This is to help test
+   support for large files (> 2GB) in a reasonable amount of time.
+   I suggest you use the undocumented --exponential option to
+   bzip2 when compressing the resulting file; this saves a bit of
+   time.  Note: *don't* bother with --exponential when compressing 
+   Real Files; it'll just waste a lot of CPU time :-)
+   (but is otherwise harmless).
+*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+	 ------------------------------------------------------------------ */
+
+
+#define _FILE_OFFSET_BITS 64
+
+#include 
+#include 
+
+/* The number of megabytes of junk to spew out (roughly) */
+#define MEGABYTES 5000
+
+#define N_BUF 1000000
+char buf[N_BUF];
+
+int main ( int argc, char** argv )
+{
+   int ii, kk, p;
+   srandom(1);
+   setbuffer ( stdout, buf, N_BUF );
+   for (kk = 0; kk < MEGABYTES * 515; kk+=3) {
+      p = 25+random()%50;
+      for (ii = 0; ii < p; ii++)
+         printf ( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" );
+      for (ii = 0; ii < p-1; ii++)
+         printf ( "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" );
+      for (ii = 0; ii < p+1; ii++)
+         printf ( "ccccccccccccccccccccccccccccccccccccc" );
+   }
+   fflush(stdout);
+   return 0;
+}
diff --git a/source/Irrlicht/bzip2/unzcrash.c b/source/Irrlicht/bzip2/unzcrash.c
new file mode 100644
index 00000000..7041da51
--- /dev/null
+++ b/source/Irrlicht/bzip2/unzcrash.c
@@ -0,0 +1,141 @@
+
+/* A test program written to test robustness to decompression of
+   corrupted data.  Usage is 
+       unzcrash filename
+   and the program will read the specified file, compress it (in memory),
+   and then repeatedly decompress it, each time with a different bit of
+   the compressed data inverted, so as to test all possible one-bit errors.
+   This should not cause any invalid memory accesses.  If it does, 
+   I want to know about it!
+
+   PS.  As you can see from the above description, the process is
+   incredibly slow.  A file of size eg 5KB will cause it to run for
+   many hours.
+*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include 
+#include 
+#include "bzlib.h"
+
+#define M_BLOCK 1000000
+
+typedef unsigned char uchar;
+
+#define M_BLOCK_OUT (M_BLOCK + 1000000)
+uchar inbuf[M_BLOCK];
+uchar outbuf[M_BLOCK_OUT];
+uchar zbuf[M_BLOCK + 600 + (M_BLOCK / 100)];
+
+int nIn, nOut, nZ;
+
+static char *bzerrorstrings[] = {
+       "OK"
+      ,"SEQUENCE_ERROR"
+      ,"PARAM_ERROR"
+      ,"MEM_ERROR"
+      ,"DATA_ERROR"
+      ,"DATA_ERROR_MAGIC"
+      ,"IO_ERROR"
+      ,"UNEXPECTED_EOF"
+      ,"OUTBUFF_FULL"
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+};
+
+void flip_bit ( int bit )
+{
+   int byteno = bit / 8;
+   int bitno  = bit % 8;
+   uchar mask = 1 << bitno;
+   //fprintf ( stderr, "(byte %d  bit %d  mask %d)",
+   //          byteno, bitno, (int)mask );
+   zbuf[byteno] ^= mask;
+}
+
+int main ( int argc, char** argv )
+{
+   FILE* f;
+   int   r;
+   int   bit;
+   int   i;
+
+   if (argc != 2) {
+      fprintf ( stderr, "usage: unzcrash filename\n" );
+      return 1;
+   }
+
+   f = fopen ( argv[1], "r" );
+   if (!f) {
+      fprintf ( stderr, "unzcrash: can't open %s\n", argv[1] );
+      return 1;
+   }
+
+   nIn = fread ( inbuf, 1, M_BLOCK, f );
+   fprintf ( stderr, "%d bytes read\n", nIn );
+
+   nZ = M_BLOCK;
+   r = BZ2_bzBuffToBuffCompress (
+         zbuf, &nZ, inbuf, nIn, 9, 0, 30 );
+
+   assert (r == BZ_OK);
+   fprintf ( stderr, "%d after compression\n", nZ );
+
+   for (bit = 0; bit < nZ*8; bit++) {
+      fprintf ( stderr, "bit %d  ", bit );
+      flip_bit ( bit );
+      nOut = M_BLOCK_OUT;
+      r = BZ2_bzBuffToBuffDecompress (
+            outbuf, &nOut, zbuf, nZ, 0, 0 );
+      fprintf ( stderr, " %d  %s ", r, bzerrorstrings[-r] );
+
+      if (r != BZ_OK) {
+         fprintf ( stderr, "\n" );
+      } else {
+         if (nOut != nIn) {
+           fprintf(stderr, "nIn/nOut mismatch %d %d\n", nIn, nOut );
+           return 1;
+         } else {
+           for (i = 0; i < nOut; i++)
+             if (inbuf[i] != outbuf[i]) { 
+                fprintf(stderr, "mismatch at %d\n", i ); 
+                return 1; 
+           }
+           if (i == nOut) fprintf(stderr, "really ok!\n" );
+         }
+      }
+
+      flip_bit ( bit );
+   }
+
+#if 0
+   assert (nOut == nIn);
+   for (i = 0; i < nOut; i++) {
+     if (inbuf[i] != outbuf[i]) {
+        fprintf ( stderr, "difference at %d !\n", i );
+        return 1;
+     }
+   }
+#endif
+
+   fprintf ( stderr, "all ok\n" );
+   return 0;
+}
diff --git a/source/Irrlicht/bzip2/words0 b/source/Irrlicht/bzip2/words0
new file mode 100644
index 00000000..fbf442ad
--- /dev/null
+++ b/source/Irrlicht/bzip2/words0
@@ -0,0 +1,9 @@
+
+If compilation produces errors, or a large number of warnings,
+please read README.COMPILATION.PROBLEMS -- you might be able to
+adjust the flags in this Makefile to improve matters.
+
+Also in README.COMPILATION.PROBLEMS are some hints that may help
+if your build produces an executable which is unable to correctly
+handle so-called 'large files' -- files of size 2GB or more.
+
diff --git a/source/Irrlicht/bzip2/words1 b/source/Irrlicht/bzip2/words1
new file mode 100644
index 00000000..2e83de9f
--- /dev/null
+++ b/source/Irrlicht/bzip2/words1
@@ -0,0 +1,4 @@
+
+Doing 6 tests (3 compress, 3 uncompress) ...
+If there's a problem, things might stop at this point.
+ 
diff --git a/source/Irrlicht/bzip2/words2 b/source/Irrlicht/bzip2/words2
new file mode 100644
index 00000000..caddcf42
--- /dev/null
+++ b/source/Irrlicht/bzip2/words2
@@ -0,0 +1,5 @@
+
+Checking test results.  If any of the four "cmp"s which follow
+report any differences, something is wrong.  If you can't easily
+figure out what, please let me know (jseward@bzip.org).
+
diff --git a/source/Irrlicht/bzip2/words3 b/source/Irrlicht/bzip2/words3
new file mode 100644
index 00000000..69726699
--- /dev/null
+++ b/source/Irrlicht/bzip2/words3
@@ -0,0 +1,30 @@
+
+If you got this far and the 'cmp's didn't complain, it looks
+like you're in business.  
+
+To install in /usr/local/bin, /usr/local/lib, /usr/local/man and 
+/usr/local/include, type
+
+   make install
+
+To install somewhere else, eg, /xxx/yyy/{bin,lib,man,include}, type 
+
+   make install PREFIX=/xxx/yyy
+
+If you are (justifiably) paranoid and want to see what 'make install'
+is going to do, you can first do
+
+   make -n install                      or
+   make -n install PREFIX=/xxx/yyy      respectively.
+
+The -n instructs make to show the commands it would execute, but
+not actually execute them.
+
+Instructions for use are in the preformatted manual page, in the file
+bzip2.txt.  For more detailed documentation, read the full manual.  
+It is available in Postscript form (manual.ps), PDF form (manual.pdf),
+and HTML form (manual.html).
+
+You can also do "bzip2 --help" to see some helpful information. 
+"bzip2 -L" displays the software license.
+
diff --git a/source/Irrlicht/bzip2/xmlproc.sh b/source/Irrlicht/bzip2/xmlproc.sh
new file mode 100755
index 00000000..ca284ea9
--- /dev/null
+++ b/source/Irrlicht/bzip2/xmlproc.sh
@@ -0,0 +1,114 @@
+#!/bin/bash
+# see the README file for usage etc.
+#
+# ------------------------------------------------------------------
+#  This file is part of bzip2/libbzip2, a program and library for
+#  lossless, block-sorting data compression.
+#
+#  bzip2/libbzip2 version 1.0.6 of 6 September 2010
+#  Copyright (C) 1996-2010 Julian Seward 
+#
+#  Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+#  README file.
+#
+#  This program is released under the terms of the license contained
+#  in the file LICENSE.
+# ----------------------------------------------------------------
+
+
+usage() {
+  echo '';
+  echo 'Usage: xmlproc.sh -[option] ';
+  echo 'Specify a target from:';
+  echo '-v      verify xml file conforms to dtd';
+  echo '-html   output in html format (single file)';
+  echo '-ps     output in postscript format';
+  echo '-pdf    output in pdf format';
+  exit;
+}
+
+if test $# -ne 2; then
+  usage
+fi
+# assign the variable for the output type
+action=$1; shift
+# assign the output filename
+xmlfile=$1; shift
+# and check user input it correct
+if !(test -f $xmlfile); then
+  echo "No such file: $xmlfile";
+  exit;
+fi
+# some other stuff we will use
+OUT=output
+xsl_fo=bz-fo.xsl
+xsl_html=bz-html.xsl
+
+basename=$xmlfile
+basename=${basename//'.xml'/''}
+
+fofile="${basename}.fo"
+htmlfile="${basename}.html"
+pdffile="${basename}.pdf"
+psfile="${basename}.ps"
+xmlfmtfile="${basename}.fmt"
+
+# first process the xmlfile with CDATA tags
+./format.pl $xmlfile $xmlfmtfile
+# so the shell knows where the catalogs live
+export XML_CATALOG_FILES=/etc/xml/catalog
+
+# post-processing tidy up
+cleanup() {
+  echo "Cleaning up: $@" 
+  while [ $# != 0 ]
+  do
+    arg=$1; shift;
+    echo "  deleting $arg";
+    rm $arg
+  done
+}
+
+case $action in
+  -v)
+   flags='--noout --xinclude --noblanks --postvalid'
+   dtd='--dtdvalid http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd'
+   xmllint $flags $dtd $xmlfmtfile 2> $OUT 
+   egrep 'error' $OUT 
+   rm $OUT
+  ;;
+
+  -html)
+   echo "Creating $htmlfile ..."
+   xsltproc --nonet --xinclude  -o $htmlfile $xsl_html $xmlfmtfile
+   cleanup $xmlfmtfile
+  ;;
+
+  -pdf)
+   echo "Creating $pdffile ..."
+   xsltproc --nonet --xinclude -o $fofile $xsl_fo $xmlfmtfile
+   pdfxmltex $fofile >$OUT $OUT $OUT $OUT $OUT $OUT $OUT $OUT $OUT  tileNum;//! StringList;
+
+//Loads a stringlist from a file
+//note that each String added to StringList
+//is separated by a \\n character and it's present
+//at the end of line.
+/** Loads a StringList from a file.
+This function loads a StringList from a file where each string is divided by a \\n char.*/
+void LoadFromFile(io::IReadFile* file, StringList& strlist)
+{
+	const long sz = file->getSize();
+	char* buf = new char[sz+1];
+	file->read(buf, sz);
+	buf[sz] = 0;
+	char* p = buf;
+	char* start = p;
+
+	while(*p)
+	{
+		if (*p == '\n')
+		{
+			core::stringc str(start, (u32)(p - start - 1));
+			str.trim();
+			strlist.push_back(str);
+			start = p+1;
+		}
+
+		++p;
+	}
+
+	if (p - start > 1)
+	{
+		core::stringc str(start, (u32)(p - start - 1));
+		str.trim();
+		strlist.push_back(str);
+	}
+
+	delete [] buf;
+};
+
+//This function subdivides a string in a list of strings
+/** This function subdivides strings divided by divider in a list of strings.
+\return A StringList made of all strings divided by divider.*/
+StringList SubdivideString(const core::stringc& str, const core::stringc& divider)
+{
+	StringList strings; //returned StringList
+	strings.clear();    //clear returned stringlist
+
+	int c=0;
+	int l=str.size();
+
+	//process entire string
+	while(c& materials,
+			int num_material)
+{
+	// offset for already handled lines
+	const int offs=4;
+
+	StringList temp;
+	StringList temp1;
+
+	// The number of materials is predetermined
+	materials.reallocate(num_material);
+	for(int i=0; i=9)
+		{
+			temp1=SubdivideString(temp[temp.size() - 1],",");
+			materials[i].lightmapFlag=atoi(temp1[0].c_str());
+			materials[i].lightmapName=temp1[1];
+			materials[i].lightmapName.replace('\\','/');
+			materials[i].lightmapBlend = atoi(temp1[2].c_str());
+		}
+		else
+		{
+			materials[i].lightmapFlag=1;
+			materials[i].lightmapName="";
+		}
+	}
+	return true;
+}
+
+
+/**This function extract an array of dmfMaterial from a DMF file considering 1st an 2nd layer for water plains.
+You must give in input a StringList representing a DMF file loaded with LoadFromFile.
+\return true if function succeed or false on fail.*/
+bool GetDMFWaterMaterials(const StringList& RawFile /**& materials/**= 0.91
+	temp=SubdivideString(RawFile[0],";");//file info
+
+	if ( temp[0] != "DeleD Map File" )
+		return false;//not a deled file
+
+	temp.clear();
+	temp=SubdivideString(RawFile[1]," ");//get version
+	temp1=SubdivideString(temp[1],";");
+
+	if (atof(temp1[0].c_str()) < 0.91)
+		return false;//not correct version
+
+	//end checking
+	temp.clear();
+	temp1.clear();
+
+	for(int i=0;i pos;
+		const u32 posCount = core::strtoul10(RawFile[offs].c_str());
+		++offs;
+		pos.reallocate(posCount);
+		for (u32 i=0; i= 0.91
+	temp=SubdivideString(RawFile[0],";");//file info
+
+	if ( temp[0] != "DeleD Map File" )
+		return false;//not a deled file
+
+	temp.clear();
+	temp=SubdivideString(RawFile[1]," ");//get version
+	temp1=SubdivideString(temp[1],";");
+
+	if (atof(temp1[0].c_str()) < 0.91)
+		return false;//not correct version
+
+	//end checking
+
+	temp.clear();
+	temp1.clear();
+	offs=offs + atoi(RawFile[offs].c_str());
+	offs++;
+	s32 objs = atoi(RawFile[offs].c_str());
+	s32 lit=0;
+	s32 d_lit=0;
+	offs++;
+
+	//let's get position of lights in file
+	int i;
+	for(i=0;i= 0.91
+	temp=SubdivideString(RawFile[0],";");//file info
+
+	if ( temp[0] != "DeleD Map File" )
+		return false;//not a deled file
+
+	temp.clear();
+	temp=SubdivideString(RawFile[1]," ");//get version
+	temp1=SubdivideString(temp[1],";");
+
+	if (atof(temp1[0].c_str()) < 0.91)
+		return false;//not correct version
+
+	//end checking
+
+	temp.clear();
+	temp1.clear();
+	offs=offs+atoi(RawFile[offs].c_str());
+	offs++;
+	s32 objs=atoi(RawFile[offs].c_str());
+	s32 fac=0,vert=0,tmp_sz=0,vert_cnt=0,face_cnt=0,wat_id=0;
+	core::dimension2d tilenum(40,40);
+	f32 waveheight=3.0f;
+	f32 wavespeed=300.0f;
+	f32 wavelength=80.0f;
+	offs++;
+
+	for(int i=0;i
+#endif
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+#ifndef APIENTRYP
+#define APIENTRYP APIENTRY *
+#endif
+#ifndef GLAPI
+#define GLAPI extern
+#endif
+
+#define GL_GLEXT_VERSION 20190515
+
+// NOTE: Modified this for Irrlicht from an include with <> to an include with "". 
+//       Otherwise have to add include paths to many project files.
+#include "KHR/khrplatform.h"
+
+/* Generated C header for:
+ * API: gl
+ * Profile: compatibility
+ * Versions considered: .*
+ * Versions emitted: 1\.[2-9]|[234]\.[0-9]
+ * Default extensions included: gl
+ * Additional extensions included: _nomatch_^
+ * Extensions removed: _nomatch_^
+ */
+
+#ifndef GL_VERSION_1_2
+#define GL_VERSION_1_2 1
+#define GL_UNSIGNED_BYTE_3_3_2            0x8032
+#define GL_UNSIGNED_SHORT_4_4_4_4         0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1         0x8034
+#define GL_UNSIGNED_INT_8_8_8_8           0x8035
+#define GL_UNSIGNED_INT_10_10_10_2        0x8036
+#define GL_TEXTURE_BINDING_3D             0x806A
+#define GL_PACK_SKIP_IMAGES               0x806B
+#define GL_PACK_IMAGE_HEIGHT              0x806C
+#define GL_UNPACK_SKIP_IMAGES             0x806D
+#define GL_UNPACK_IMAGE_HEIGHT            0x806E
+#define GL_TEXTURE_3D                     0x806F
+#define GL_PROXY_TEXTURE_3D               0x8070
+#define GL_TEXTURE_DEPTH                  0x8071
+#define GL_TEXTURE_WRAP_R                 0x8072
+#define GL_MAX_3D_TEXTURE_SIZE            0x8073
+#define GL_UNSIGNED_BYTE_2_3_3_REV        0x8362
+#define GL_UNSIGNED_SHORT_5_6_5           0x8363
+#define GL_UNSIGNED_SHORT_5_6_5_REV       0x8364
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV     0x8365
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV     0x8366
+#define GL_UNSIGNED_INT_8_8_8_8_REV       0x8367
+#define GL_UNSIGNED_INT_2_10_10_10_REV    0x8368
+#define GL_BGR                            0x80E0
+#define GL_BGRA                           0x80E1
+#define GL_MAX_ELEMENTS_VERTICES          0x80E8
+#define GL_MAX_ELEMENTS_INDICES           0x80E9
+#define GL_CLAMP_TO_EDGE                  0x812F
+#define GL_TEXTURE_MIN_LOD                0x813A
+#define GL_TEXTURE_MAX_LOD                0x813B
+#define GL_TEXTURE_BASE_LEVEL             0x813C
+#define GL_TEXTURE_MAX_LEVEL              0x813D
+#define GL_SMOOTH_POINT_SIZE_RANGE        0x0B12
+#define GL_SMOOTH_POINT_SIZE_GRANULARITY  0x0B13
+#define GL_SMOOTH_LINE_WIDTH_RANGE        0x0B22
+#define GL_SMOOTH_LINE_WIDTH_GRANULARITY  0x0B23
+#define GL_ALIASED_LINE_WIDTH_RANGE       0x846E
+#define GL_RESCALE_NORMAL                 0x803A
+#define GL_LIGHT_MODEL_COLOR_CONTROL      0x81F8
+#define GL_SINGLE_COLOR                   0x81F9
+#define GL_SEPARATE_SPECULAR_COLOR        0x81FA
+#define GL_ALIASED_POINT_SIZE_RANGE       0x846D
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
+typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
+GLAPI void APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+#endif
+#endif /* GL_VERSION_1_2 */
+
+#ifndef GL_VERSION_1_3
+#define GL_VERSION_1_3 1
+#define GL_TEXTURE0                       0x84C0
+#define GL_TEXTURE1                       0x84C1
+#define GL_TEXTURE2                       0x84C2
+#define GL_TEXTURE3                       0x84C3
+#define GL_TEXTURE4                       0x84C4
+#define GL_TEXTURE5                       0x84C5
+#define GL_TEXTURE6                       0x84C6
+#define GL_TEXTURE7                       0x84C7
+#define GL_TEXTURE8                       0x84C8
+#define GL_TEXTURE9                       0x84C9
+#define GL_TEXTURE10                      0x84CA
+#define GL_TEXTURE11                      0x84CB
+#define GL_TEXTURE12                      0x84CC
+#define GL_TEXTURE13                      0x84CD
+#define GL_TEXTURE14                      0x84CE
+#define GL_TEXTURE15                      0x84CF
+#define GL_TEXTURE16                      0x84D0
+#define GL_TEXTURE17                      0x84D1
+#define GL_TEXTURE18                      0x84D2
+#define GL_TEXTURE19                      0x84D3
+#define GL_TEXTURE20                      0x84D4
+#define GL_TEXTURE21                      0x84D5
+#define GL_TEXTURE22                      0x84D6
+#define GL_TEXTURE23                      0x84D7
+#define GL_TEXTURE24                      0x84D8
+#define GL_TEXTURE25                      0x84D9
+#define GL_TEXTURE26                      0x84DA
+#define GL_TEXTURE27                      0x84DB
+#define GL_TEXTURE28                      0x84DC
+#define GL_TEXTURE29                      0x84DD
+#define GL_TEXTURE30                      0x84DE
+#define GL_TEXTURE31                      0x84DF
+#define GL_ACTIVE_TEXTURE                 0x84E0
+#define GL_MULTISAMPLE                    0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE       0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE            0x809F
+#define GL_SAMPLE_COVERAGE                0x80A0
+#define GL_SAMPLE_BUFFERS                 0x80A8
+#define GL_SAMPLES                        0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE          0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT         0x80AB
+#define GL_TEXTURE_CUBE_MAP               0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP       0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X    0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X    0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y    0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y    0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z    0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z    0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP         0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE      0x851C
+#define GL_COMPRESSED_RGB                 0x84ED
+#define GL_COMPRESSED_RGBA                0x84EE
+#define GL_TEXTURE_COMPRESSION_HINT       0x84EF
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE  0x86A0
+#define GL_TEXTURE_COMPRESSED             0x86A1
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS     0x86A3
+#define GL_CLAMP_TO_BORDER                0x812D
+#define GL_CLIENT_ACTIVE_TEXTURE          0x84E1
+#define GL_MAX_TEXTURE_UNITS              0x84E2
+#define GL_TRANSPOSE_MODELVIEW_MATRIX     0x84E3
+#define GL_TRANSPOSE_PROJECTION_MATRIX    0x84E4
+#define GL_TRANSPOSE_TEXTURE_MATRIX       0x84E5
+#define GL_TRANSPOSE_COLOR_MATRIX         0x84E6
+#define GL_MULTISAMPLE_BIT                0x20000000
+#define GL_NORMAL_MAP                     0x8511
+#define GL_REFLECTION_MAP                 0x8512
+#define GL_COMPRESSED_ALPHA               0x84E9
+#define GL_COMPRESSED_LUMINANCE           0x84EA
+#define GL_COMPRESSED_LUMINANCE_ALPHA     0x84EB
+#define GL_COMPRESSED_INTENSITY           0x84EC
+#define GL_COMBINE                        0x8570
+#define GL_COMBINE_RGB                    0x8571
+#define GL_COMBINE_ALPHA                  0x8572
+#define GL_SOURCE0_RGB                    0x8580
+#define GL_SOURCE1_RGB                    0x8581
+#define GL_SOURCE2_RGB                    0x8582
+#define GL_SOURCE0_ALPHA                  0x8588
+#define GL_SOURCE1_ALPHA                  0x8589
+#define GL_SOURCE2_ALPHA                  0x858A
+#define GL_OPERAND0_RGB                   0x8590
+#define GL_OPERAND1_RGB                   0x8591
+#define GL_OPERAND2_RGB                   0x8592
+#define GL_OPERAND0_ALPHA                 0x8598
+#define GL_OPERAND1_ALPHA                 0x8599
+#define GL_OPERAND2_ALPHA                 0x859A
+#define GL_RGB_SCALE                      0x8573
+#define GL_ADD_SIGNED                     0x8574
+#define GL_INTERPOLATE                    0x8575
+#define GL_SUBTRACT                       0x84E7
+#define GL_CONSTANT                       0x8576
+#define GL_PRIMARY_COLOR                  0x8577
+#define GL_PREVIOUS                       0x8578
+#define GL_DOT3_RGB                       0x86AE
+#define GL_DOT3_RGBA                      0x86AF
+typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, void *img);
+typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glActiveTexture (GLenum texture);
+GLAPI void APIENTRY glSampleCoverage (GLfloat value, GLboolean invert);
+GLAPI void APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glGetCompressedTexImage (GLenum target, GLint level, void *img);
+GLAPI void APIENTRY glClientActiveTexture (GLenum texture);
+GLAPI void APIENTRY glMultiTexCoord1d (GLenum target, GLdouble s);
+GLAPI void APIENTRY glMultiTexCoord1dv (GLenum target, const GLdouble *v);
+GLAPI void APIENTRY glMultiTexCoord1f (GLenum target, GLfloat s);
+GLAPI void APIENTRY glMultiTexCoord1fv (GLenum target, const GLfloat *v);
+GLAPI void APIENTRY glMultiTexCoord1i (GLenum target, GLint s);
+GLAPI void APIENTRY glMultiTexCoord1iv (GLenum target, const GLint *v);
+GLAPI void APIENTRY glMultiTexCoord1s (GLenum target, GLshort s);
+GLAPI void APIENTRY glMultiTexCoord1sv (GLenum target, const GLshort *v);
+GLAPI void APIENTRY glMultiTexCoord2d (GLenum target, GLdouble s, GLdouble t);
+GLAPI void APIENTRY glMultiTexCoord2dv (GLenum target, const GLdouble *v);
+GLAPI void APIENTRY glMultiTexCoord2f (GLenum target, GLfloat s, GLfloat t);
+GLAPI void APIENTRY glMultiTexCoord2fv (GLenum target, const GLfloat *v);
+GLAPI void APIENTRY glMultiTexCoord2i (GLenum target, GLint s, GLint t);
+GLAPI void APIENTRY glMultiTexCoord2iv (GLenum target, const GLint *v);
+GLAPI void APIENTRY glMultiTexCoord2s (GLenum target, GLshort s, GLshort t);
+GLAPI void APIENTRY glMultiTexCoord2sv (GLenum target, const GLshort *v);
+GLAPI void APIENTRY glMultiTexCoord3d (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+GLAPI void APIENTRY glMultiTexCoord3dv (GLenum target, const GLdouble *v);
+GLAPI void APIENTRY glMultiTexCoord3f (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+GLAPI void APIENTRY glMultiTexCoord3fv (GLenum target, const GLfloat *v);
+GLAPI void APIENTRY glMultiTexCoord3i (GLenum target, GLint s, GLint t, GLint r);
+GLAPI void APIENTRY glMultiTexCoord3iv (GLenum target, const GLint *v);
+GLAPI void APIENTRY glMultiTexCoord3s (GLenum target, GLshort s, GLshort t, GLshort r);
+GLAPI void APIENTRY glMultiTexCoord3sv (GLenum target, const GLshort *v);
+GLAPI void APIENTRY glMultiTexCoord4d (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+GLAPI void APIENTRY glMultiTexCoord4dv (GLenum target, const GLdouble *v);
+GLAPI void APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+GLAPI void APIENTRY glMultiTexCoord4fv (GLenum target, const GLfloat *v);
+GLAPI void APIENTRY glMultiTexCoord4i (GLenum target, GLint s, GLint t, GLint r, GLint q);
+GLAPI void APIENTRY glMultiTexCoord4iv (GLenum target, const GLint *v);
+GLAPI void APIENTRY glMultiTexCoord4s (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+GLAPI void APIENTRY glMultiTexCoord4sv (GLenum target, const GLshort *v);
+GLAPI void APIENTRY glLoadTransposeMatrixf (const GLfloat *m);
+GLAPI void APIENTRY glLoadTransposeMatrixd (const GLdouble *m);
+GLAPI void APIENTRY glMultTransposeMatrixf (const GLfloat *m);
+GLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *m);
+#endif
+#endif /* GL_VERSION_1_3 */
+
+#ifndef GL_VERSION_1_4
+#define GL_VERSION_1_4 1
+#define GL_BLEND_DST_RGB                  0x80C8
+#define GL_BLEND_SRC_RGB                  0x80C9
+#define GL_BLEND_DST_ALPHA                0x80CA
+#define GL_BLEND_SRC_ALPHA                0x80CB
+#define GL_POINT_FADE_THRESHOLD_SIZE      0x8128
+#define GL_DEPTH_COMPONENT16              0x81A5
+#define GL_DEPTH_COMPONENT24              0x81A6
+#define GL_DEPTH_COMPONENT32              0x81A7
+#define GL_MIRRORED_REPEAT                0x8370
+#define GL_MAX_TEXTURE_LOD_BIAS           0x84FD
+#define GL_TEXTURE_LOD_BIAS               0x8501
+#define GL_INCR_WRAP                      0x8507
+#define GL_DECR_WRAP                      0x8508
+#define GL_TEXTURE_DEPTH_SIZE             0x884A
+#define GL_TEXTURE_COMPARE_MODE           0x884C
+#define GL_TEXTURE_COMPARE_FUNC           0x884D
+#define GL_POINT_SIZE_MIN                 0x8126
+#define GL_POINT_SIZE_MAX                 0x8127
+#define GL_POINT_DISTANCE_ATTENUATION     0x8129
+#define GL_GENERATE_MIPMAP                0x8191
+#define GL_GENERATE_MIPMAP_HINT           0x8192
+#define GL_FOG_COORDINATE_SOURCE          0x8450
+#define GL_FOG_COORDINATE                 0x8451
+#define GL_FRAGMENT_DEPTH                 0x8452
+#define GL_CURRENT_FOG_COORDINATE         0x8453
+#define GL_FOG_COORDINATE_ARRAY_TYPE      0x8454
+#define GL_FOG_COORDINATE_ARRAY_STRIDE    0x8455
+#define GL_FOG_COORDINATE_ARRAY_POINTER   0x8456
+#define GL_FOG_COORDINATE_ARRAY           0x8457
+#define GL_COLOR_SUM                      0x8458
+#define GL_CURRENT_SECONDARY_COLOR        0x8459
+#define GL_SECONDARY_COLOR_ARRAY_SIZE     0x845A
+#define GL_SECONDARY_COLOR_ARRAY_TYPE     0x845B
+#define GL_SECONDARY_COLOR_ARRAY_STRIDE   0x845C
+#define GL_SECONDARY_COLOR_ARRAY_POINTER  0x845D
+#define GL_SECONDARY_COLOR_ARRAY          0x845E
+#define GL_TEXTURE_FILTER_CONTROL         0x8500
+#define GL_DEPTH_TEXTURE_MODE             0x884B
+#define GL_COMPARE_R_TO_TEXTURE           0x884E
+#define GL_BLEND_COLOR                    0x8005
+#define GL_BLEND_EQUATION                 0x8009
+#define GL_CONSTANT_COLOR                 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR       0x8002
+#define GL_CONSTANT_ALPHA                 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA       0x8004
+#define GL_FUNC_ADD                       0x8006
+#define GL_FUNC_REVERSE_SUBTRACT          0x800B
+#define GL_FUNC_SUBTRACT                  0x800A
+#define GL_MIN                            0x8007
+#define GL_MAX                            0x8008
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord);
+typedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC) (GLint x, GLint y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+GLAPI void APIENTRY glMultiDrawArrays (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount);
+GLAPI void APIENTRY glMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount);
+GLAPI void APIENTRY glPointParameterf (GLenum pname, GLfloat param);
+GLAPI void APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glPointParameteri (GLenum pname, GLint param);
+GLAPI void APIENTRY glPointParameteriv (GLenum pname, const GLint *params);
+GLAPI void APIENTRY glFogCoordf (GLfloat coord);
+GLAPI void APIENTRY glFogCoordfv (const GLfloat *coord);
+GLAPI void APIENTRY glFogCoordd (GLdouble coord);
+GLAPI void APIENTRY glFogCoorddv (const GLdouble *coord);
+GLAPI void APIENTRY glFogCoordPointer (GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glSecondaryColor3b (GLbyte red, GLbyte green, GLbyte blue);
+GLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *v);
+GLAPI void APIENTRY glSecondaryColor3d (GLdouble red, GLdouble green, GLdouble blue);
+GLAPI void APIENTRY glSecondaryColor3dv (const GLdouble *v);
+GLAPI void APIENTRY glSecondaryColor3f (GLfloat red, GLfloat green, GLfloat blue);
+GLAPI void APIENTRY glSecondaryColor3fv (const GLfloat *v);
+GLAPI void APIENTRY glSecondaryColor3i (GLint red, GLint green, GLint blue);
+GLAPI void APIENTRY glSecondaryColor3iv (const GLint *v);
+GLAPI void APIENTRY glSecondaryColor3s (GLshort red, GLshort green, GLshort blue);
+GLAPI void APIENTRY glSecondaryColor3sv (const GLshort *v);
+GLAPI void APIENTRY glSecondaryColor3ub (GLubyte red, GLubyte green, GLubyte blue);
+GLAPI void APIENTRY glSecondaryColor3ubv (const GLubyte *v);
+GLAPI void APIENTRY glSecondaryColor3ui (GLuint red, GLuint green, GLuint blue);
+GLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *v);
+GLAPI void APIENTRY glSecondaryColor3us (GLushort red, GLushort green, GLushort blue);
+GLAPI void APIENTRY glSecondaryColor3usv (const GLushort *v);
+GLAPI void APIENTRY glSecondaryColorPointer (GLint size, GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glWindowPos2d (GLdouble x, GLdouble y);
+GLAPI void APIENTRY glWindowPos2dv (const GLdouble *v);
+GLAPI void APIENTRY glWindowPos2f (GLfloat x, GLfloat y);
+GLAPI void APIENTRY glWindowPos2fv (const GLfloat *v);
+GLAPI void APIENTRY glWindowPos2i (GLint x, GLint y);
+GLAPI void APIENTRY glWindowPos2iv (const GLint *v);
+GLAPI void APIENTRY glWindowPos2s (GLshort x, GLshort y);
+GLAPI void APIENTRY glWindowPos2sv (const GLshort *v);
+GLAPI void APIENTRY glWindowPos3d (GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glWindowPos3dv (const GLdouble *v);
+GLAPI void APIENTRY glWindowPos3f (GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glWindowPos3fv (const GLfloat *v);
+GLAPI void APIENTRY glWindowPos3i (GLint x, GLint y, GLint z);
+GLAPI void APIENTRY glWindowPos3iv (const GLint *v);
+GLAPI void APIENTRY glWindowPos3s (GLshort x, GLshort y, GLshort z);
+GLAPI void APIENTRY glWindowPos3sv (const GLshort *v);
+GLAPI void APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+GLAPI void APIENTRY glBlendEquation (GLenum mode);
+#endif
+#endif /* GL_VERSION_1_4 */
+
+#ifndef GL_VERSION_1_5
+#define GL_VERSION_1_5 1
+typedef khronos_ssize_t GLsizeiptr;
+typedef khronos_intptr_t GLintptr;
+#define GL_BUFFER_SIZE                    0x8764
+#define GL_BUFFER_USAGE                   0x8765
+#define GL_QUERY_COUNTER_BITS             0x8864
+#define GL_CURRENT_QUERY                  0x8865
+#define GL_QUERY_RESULT                   0x8866
+#define GL_QUERY_RESULT_AVAILABLE         0x8867
+#define GL_ARRAY_BUFFER                   0x8892
+#define GL_ELEMENT_ARRAY_BUFFER           0x8893
+#define GL_ARRAY_BUFFER_BINDING           0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING   0x8895
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+#define GL_READ_ONLY                      0x88B8
+#define GL_WRITE_ONLY                     0x88B9
+#define GL_READ_WRITE                     0x88BA
+#define GL_BUFFER_ACCESS                  0x88BB
+#define GL_BUFFER_MAPPED                  0x88BC
+#define GL_BUFFER_MAP_POINTER             0x88BD
+#define GL_STREAM_DRAW                    0x88E0
+#define GL_STREAM_READ                    0x88E1
+#define GL_STREAM_COPY                    0x88E2
+#define GL_STATIC_DRAW                    0x88E4
+#define GL_STATIC_READ                    0x88E5
+#define GL_STATIC_COPY                    0x88E6
+#define GL_DYNAMIC_DRAW                   0x88E8
+#define GL_DYNAMIC_READ                   0x88E9
+#define GL_DYNAMIC_COPY                   0x88EA
+#define GL_SAMPLES_PASSED                 0x8914
+#define GL_SRC1_ALPHA                     0x8589
+#define GL_VERTEX_ARRAY_BUFFER_BINDING    0x8896
+#define GL_NORMAL_ARRAY_BUFFER_BINDING    0x8897
+#define GL_COLOR_ARRAY_BUFFER_BINDING     0x8898
+#define GL_INDEX_ARRAY_BUFFER_BINDING     0x8899
+#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A
+#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B
+#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C
+#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D
+#define GL_WEIGHT_ARRAY_BUFFER_BINDING    0x889E
+#define GL_FOG_COORD_SRC                  0x8450
+#define GL_FOG_COORD                      0x8451
+#define GL_CURRENT_FOG_COORD              0x8453
+#define GL_FOG_COORD_ARRAY_TYPE           0x8454
+#define GL_FOG_COORD_ARRAY_STRIDE         0x8455
+#define GL_FOG_COORD_ARRAY_POINTER        0x8456
+#define GL_FOG_COORD_ARRAY                0x8457
+#define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D
+#define GL_SRC0_RGB                       0x8580
+#define GL_SRC1_RGB                       0x8581
+#define GL_SRC2_RGB                       0x8582
+#define GL_SRC0_ALPHA                     0x8588
+#define GL_SRC2_ALPHA                     0x858A
+typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
+typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
+typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
+typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
+typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
+typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, void *data);
+typedef void *(APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access);
+typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void **params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenQueries (GLsizei n, GLuint *ids);
+GLAPI void APIENTRY glDeleteQueries (GLsizei n, const GLuint *ids);
+GLAPI GLboolean APIENTRY glIsQuery (GLuint id);
+GLAPI void APIENTRY glBeginQuery (GLenum target, GLuint id);
+GLAPI void APIENTRY glEndQuery (GLenum target);
+GLAPI void APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetQueryObjectiv (GLuint id, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params);
+GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer);
+GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers);
+GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers);
+GLAPI GLboolean APIENTRY glIsBuffer (GLuint buffer);
+GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
+GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
+GLAPI void APIENTRY glGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, void *data);
+GLAPI void *APIENTRY glMapBuffer (GLenum target, GLenum access);
+GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum target);
+GLAPI void APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, void **params);
+#endif
+#endif /* GL_VERSION_1_5 */
+
+#ifndef GL_VERSION_2_0
+#define GL_VERSION_2_0 1
+typedef char GLchar;
+#define GL_BLEND_EQUATION_RGB             0x8009
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED    0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE       0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE     0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE       0x8625
+#define GL_CURRENT_VERTEX_ATTRIB          0x8626
+#define GL_VERTEX_PROGRAM_POINT_SIZE      0x8642
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER    0x8645
+#define GL_STENCIL_BACK_FUNC              0x8800
+#define GL_STENCIL_BACK_FAIL              0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL   0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS   0x8803
+#define GL_MAX_DRAW_BUFFERS               0x8824
+#define GL_DRAW_BUFFER0                   0x8825
+#define GL_DRAW_BUFFER1                   0x8826
+#define GL_DRAW_BUFFER2                   0x8827
+#define GL_DRAW_BUFFER3                   0x8828
+#define GL_DRAW_BUFFER4                   0x8829
+#define GL_DRAW_BUFFER5                   0x882A
+#define GL_DRAW_BUFFER6                   0x882B
+#define GL_DRAW_BUFFER7                   0x882C
+#define GL_DRAW_BUFFER8                   0x882D
+#define GL_DRAW_BUFFER9                   0x882E
+#define GL_DRAW_BUFFER10                  0x882F
+#define GL_DRAW_BUFFER11                  0x8830
+#define GL_DRAW_BUFFER12                  0x8831
+#define GL_DRAW_BUFFER13                  0x8832
+#define GL_DRAW_BUFFER14                  0x8833
+#define GL_DRAW_BUFFER15                  0x8834
+#define GL_BLEND_EQUATION_ALPHA           0x883D
+#define GL_MAX_VERTEX_ATTRIBS             0x8869
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_MAX_TEXTURE_IMAGE_UNITS        0x8872
+#define GL_FRAGMENT_SHADER                0x8B30
+#define GL_VERTEX_SHADER                  0x8B31
+#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49
+#define GL_MAX_VERTEX_UNIFORM_COMPONENTS  0x8B4A
+#define GL_MAX_VARYING_FLOATS             0x8B4B
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_SHADER_TYPE                    0x8B4F
+#define GL_FLOAT_VEC2                     0x8B50
+#define GL_FLOAT_VEC3                     0x8B51
+#define GL_FLOAT_VEC4                     0x8B52
+#define GL_INT_VEC2                       0x8B53
+#define GL_INT_VEC3                       0x8B54
+#define GL_INT_VEC4                       0x8B55
+#define GL_BOOL                           0x8B56
+#define GL_BOOL_VEC2                      0x8B57
+#define GL_BOOL_VEC3                      0x8B58
+#define GL_BOOL_VEC4                      0x8B59
+#define GL_FLOAT_MAT2                     0x8B5A
+#define GL_FLOAT_MAT3                     0x8B5B
+#define GL_FLOAT_MAT4                     0x8B5C
+#define GL_SAMPLER_1D                     0x8B5D
+#define GL_SAMPLER_2D                     0x8B5E
+#define GL_SAMPLER_3D                     0x8B5F
+#define GL_SAMPLER_CUBE                   0x8B60
+#define GL_SAMPLER_1D_SHADOW              0x8B61
+#define GL_SAMPLER_2D_SHADOW              0x8B62
+#define GL_DELETE_STATUS                  0x8B80
+#define GL_COMPILE_STATUS                 0x8B81
+#define GL_LINK_STATUS                    0x8B82
+#define GL_VALIDATE_STATUS                0x8B83
+#define GL_INFO_LOG_LENGTH                0x8B84
+#define GL_ATTACHED_SHADERS               0x8B85
+#define GL_ACTIVE_UNIFORMS                0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH      0x8B87
+#define GL_SHADER_SOURCE_LENGTH           0x8B88
+#define GL_ACTIVE_ATTRIBUTES              0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH    0x8B8A
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B
+#define GL_SHADING_LANGUAGE_VERSION       0x8B8C
+#define GL_CURRENT_PROGRAM                0x8B8D
+#define GL_POINT_SPRITE_COORD_ORIGIN      0x8CA0
+#define GL_LOWER_LEFT                     0x8CA1
+#define GL_UPPER_LEFT                     0x8CA2
+#define GL_STENCIL_BACK_REF               0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK        0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK         0x8CA5
+#define GL_VERTEX_PROGRAM_TWO_SIDE        0x8643
+#define GL_POINT_SPRITE                   0x8861
+#define GL_COORD_REPLACE                  0x8862
+#define GL_MAX_TEXTURE_COORDS             0x8871
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
+typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs);
+typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask);
+typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask);
+typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
+typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name);
+typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);
+typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
+typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);
+typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders);
+typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source);
+typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program);
+typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader);
+typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
+typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0);
+typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
+typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1);
+typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
+GLAPI void APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs);
+GLAPI void APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+GLAPI void APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask);
+GLAPI void APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask);
+GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader);
+GLAPI void APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name);
+GLAPI void APIENTRY glCompileShader (GLuint shader);
+GLAPI GLuint APIENTRY glCreateProgram (void);
+GLAPI GLuint APIENTRY glCreateShader (GLenum type);
+GLAPI void APIENTRY glDeleteProgram (GLuint program);
+GLAPI void APIENTRY glDeleteShader (GLuint shader);
+GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader);
+GLAPI void APIENTRY glDisableVertexAttribArray (GLuint index);
+GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index);
+GLAPI void APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+GLAPI void APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+GLAPI void APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders);
+GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name);
+GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+GLAPI void APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source);
+GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name);
+GLAPI void APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params);
+GLAPI void APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params);
+GLAPI void APIENTRY glGetVertexAttribdv (GLuint index, GLenum pname, GLdouble *params);
+GLAPI void APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer);
+GLAPI GLboolean APIENTRY glIsProgram (GLuint program);
+GLAPI GLboolean APIENTRY glIsShader (GLuint shader);
+GLAPI void APIENTRY glLinkProgram (GLuint program);
+GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
+GLAPI void APIENTRY glUseProgram (GLuint program);
+GLAPI void APIENTRY glUniform1f (GLint location, GLfloat v0);
+GLAPI void APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1);
+GLAPI void APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+GLAPI void APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+GLAPI void APIENTRY glUniform1i (GLint location, GLint v0);
+GLAPI void APIENTRY glUniform2i (GLint location, GLint v0, GLint v1);
+GLAPI void APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2);
+GLAPI void APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+GLAPI void APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glValidateProgram (GLuint program);
+GLAPI void APIENTRY glVertexAttrib1d (GLuint index, GLdouble x);
+GLAPI void APIENTRY glVertexAttrib1dv (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib1f (GLuint index, GLfloat x);
+GLAPI void APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib1s (GLuint index, GLshort x);
+GLAPI void APIENTRY glVertexAttrib1sv (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib2d (GLuint index, GLdouble x, GLdouble y);
+GLAPI void APIENTRY glVertexAttrib2dv (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y);
+GLAPI void APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib2s (GLuint index, GLshort x, GLshort y);
+GLAPI void APIENTRY glVertexAttrib2sv (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib3d (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glVertexAttrib3dv (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib3s (GLuint index, GLshort x, GLshort y, GLshort z);
+GLAPI void APIENTRY glVertexAttrib3sv (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint index, const GLbyte *v);
+GLAPI void APIENTRY glVertexAttrib4Niv (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib4Nub (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint index, const GLubyte *v);
+GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint index, const GLushort *v);
+GLAPI void APIENTRY glVertexAttrib4bv (GLuint index, const GLbyte *v);
+GLAPI void APIENTRY glVertexAttrib4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glVertexAttrib4dv (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib4iv (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttrib4s (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+GLAPI void APIENTRY glVertexAttrib4sv (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib4ubv (GLuint index, const GLubyte *v);
+GLAPI void APIENTRY glVertexAttrib4uiv (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttrib4usv (GLuint index, const GLushort *v);
+GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
+#endif
+#endif /* GL_VERSION_2_0 */
+
+#ifndef GL_VERSION_2_1
+#define GL_VERSION_2_1 1
+#define GL_PIXEL_PACK_BUFFER              0x88EB
+#define GL_PIXEL_UNPACK_BUFFER            0x88EC
+#define GL_PIXEL_PACK_BUFFER_BINDING      0x88ED
+#define GL_PIXEL_UNPACK_BUFFER_BINDING    0x88EF
+#define GL_FLOAT_MAT2x3                   0x8B65
+#define GL_FLOAT_MAT2x4                   0x8B66
+#define GL_FLOAT_MAT3x2                   0x8B67
+#define GL_FLOAT_MAT3x4                   0x8B68
+#define GL_FLOAT_MAT4x2                   0x8B69
+#define GL_FLOAT_MAT4x3                   0x8B6A
+#define GL_SRGB                           0x8C40
+#define GL_SRGB8                          0x8C41
+#define GL_SRGB_ALPHA                     0x8C42
+#define GL_SRGB8_ALPHA8                   0x8C43
+#define GL_COMPRESSED_SRGB                0x8C48
+#define GL_COMPRESSED_SRGB_ALPHA          0x8C49
+#define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F
+#define GL_SLUMINANCE_ALPHA               0x8C44
+#define GL_SLUMINANCE8_ALPHA8             0x8C45
+#define GL_SLUMINANCE                     0x8C46
+#define GL_SLUMINANCE8                    0x8C47
+#define GL_COMPRESSED_SLUMINANCE          0x8C4A
+#define GL_COMPRESSED_SLUMINANCE_ALPHA    0x8C4B
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+#endif
+#endif /* GL_VERSION_2_1 */
+
+#ifndef GL_VERSION_3_0
+#define GL_VERSION_3_0 1
+typedef khronos_uint16_t GLhalf;
+#define GL_COMPARE_REF_TO_TEXTURE         0x884E
+#define GL_CLIP_DISTANCE0                 0x3000
+#define GL_CLIP_DISTANCE1                 0x3001
+#define GL_CLIP_DISTANCE2                 0x3002
+#define GL_CLIP_DISTANCE3                 0x3003
+#define GL_CLIP_DISTANCE4                 0x3004
+#define GL_CLIP_DISTANCE5                 0x3005
+#define GL_CLIP_DISTANCE6                 0x3006
+#define GL_CLIP_DISTANCE7                 0x3007
+#define GL_MAX_CLIP_DISTANCES             0x0D32
+#define GL_MAJOR_VERSION                  0x821B
+#define GL_MINOR_VERSION                  0x821C
+#define GL_NUM_EXTENSIONS                 0x821D
+#define GL_CONTEXT_FLAGS                  0x821E
+#define GL_COMPRESSED_RED                 0x8225
+#define GL_COMPRESSED_RG                  0x8226
+#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001
+#define GL_RGBA32F                        0x8814
+#define GL_RGB32F                         0x8815
+#define GL_RGBA16F                        0x881A
+#define GL_RGB16F                         0x881B
+#define GL_VERTEX_ATTRIB_ARRAY_INTEGER    0x88FD
+#define GL_MAX_ARRAY_TEXTURE_LAYERS       0x88FF
+#define GL_MIN_PROGRAM_TEXEL_OFFSET       0x8904
+#define GL_MAX_PROGRAM_TEXEL_OFFSET       0x8905
+#define GL_CLAMP_READ_COLOR               0x891C
+#define GL_FIXED_ONLY                     0x891D
+#define GL_MAX_VARYING_COMPONENTS         0x8B4B
+#define GL_TEXTURE_1D_ARRAY               0x8C18
+#define GL_PROXY_TEXTURE_1D_ARRAY         0x8C19
+#define GL_TEXTURE_2D_ARRAY               0x8C1A
+#define GL_PROXY_TEXTURE_2D_ARRAY         0x8C1B
+#define GL_TEXTURE_BINDING_1D_ARRAY       0x8C1C
+#define GL_TEXTURE_BINDING_2D_ARRAY       0x8C1D
+#define GL_R11F_G11F_B10F                 0x8C3A
+#define GL_UNSIGNED_INT_10F_11F_11F_REV   0x8C3B
+#define GL_RGB9_E5                        0x8C3D
+#define GL_UNSIGNED_INT_5_9_9_9_REV       0x8C3E
+#define GL_TEXTURE_SHARED_SIZE            0x8C3F
+#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76
+#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80
+#define GL_TRANSFORM_FEEDBACK_VARYINGS    0x8C83
+#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84
+#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85
+#define GL_PRIMITIVES_GENERATED           0x8C87
+#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88
+#define GL_RASTERIZER_DISCARD             0x8C89
+#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B
+#define GL_INTERLEAVED_ATTRIBS            0x8C8C
+#define GL_SEPARATE_ATTRIBS               0x8C8D
+#define GL_TRANSFORM_FEEDBACK_BUFFER      0x8C8E
+#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F
+#define GL_RGBA32UI                       0x8D70
+#define GL_RGB32UI                        0x8D71
+#define GL_RGBA16UI                       0x8D76
+#define GL_RGB16UI                        0x8D77
+#define GL_RGBA8UI                        0x8D7C
+#define GL_RGB8UI                         0x8D7D
+#define GL_RGBA32I                        0x8D82
+#define GL_RGB32I                         0x8D83
+#define GL_RGBA16I                        0x8D88
+#define GL_RGB16I                         0x8D89
+#define GL_RGBA8I                         0x8D8E
+#define GL_RGB8I                          0x8D8F
+#define GL_RED_INTEGER                    0x8D94
+#define GL_GREEN_INTEGER                  0x8D95
+#define GL_BLUE_INTEGER                   0x8D96
+#define GL_RGB_INTEGER                    0x8D98
+#define GL_RGBA_INTEGER                   0x8D99
+#define GL_BGR_INTEGER                    0x8D9A
+#define GL_BGRA_INTEGER                   0x8D9B
+#define GL_SAMPLER_1D_ARRAY               0x8DC0
+#define GL_SAMPLER_2D_ARRAY               0x8DC1
+#define GL_SAMPLER_1D_ARRAY_SHADOW        0x8DC3
+#define GL_SAMPLER_2D_ARRAY_SHADOW        0x8DC4
+#define GL_SAMPLER_CUBE_SHADOW            0x8DC5
+#define GL_UNSIGNED_INT_VEC2              0x8DC6
+#define GL_UNSIGNED_INT_VEC3              0x8DC7
+#define GL_UNSIGNED_INT_VEC4              0x8DC8
+#define GL_INT_SAMPLER_1D                 0x8DC9
+#define GL_INT_SAMPLER_2D                 0x8DCA
+#define GL_INT_SAMPLER_3D                 0x8DCB
+#define GL_INT_SAMPLER_CUBE               0x8DCC
+#define GL_INT_SAMPLER_1D_ARRAY           0x8DCE
+#define GL_INT_SAMPLER_2D_ARRAY           0x8DCF
+#define GL_UNSIGNED_INT_SAMPLER_1D        0x8DD1
+#define GL_UNSIGNED_INT_SAMPLER_2D        0x8DD2
+#define GL_UNSIGNED_INT_SAMPLER_3D        0x8DD3
+#define GL_UNSIGNED_INT_SAMPLER_CUBE      0x8DD4
+#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY  0x8DD6
+#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY  0x8DD7
+#define GL_QUERY_WAIT                     0x8E13
+#define GL_QUERY_NO_WAIT                  0x8E14
+#define GL_QUERY_BY_REGION_WAIT           0x8E15
+#define GL_QUERY_BY_REGION_NO_WAIT        0x8E16
+#define GL_BUFFER_ACCESS_FLAGS            0x911F
+#define GL_BUFFER_MAP_LENGTH              0x9120
+#define GL_BUFFER_MAP_OFFSET              0x9121
+#define GL_DEPTH_COMPONENT32F             0x8CAC
+#define GL_DEPTH32F_STENCIL8              0x8CAD
+#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD
+#define GL_INVALID_FRAMEBUFFER_OPERATION  0x0506
+#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210
+#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211
+#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212
+#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213
+#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214
+#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215
+#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216
+#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217
+#define GL_FRAMEBUFFER_DEFAULT            0x8218
+#define GL_FRAMEBUFFER_UNDEFINED          0x8219
+#define GL_DEPTH_STENCIL_ATTACHMENT       0x821A
+#define GL_MAX_RENDERBUFFER_SIZE          0x84E8
+#define GL_DEPTH_STENCIL                  0x84F9
+#define GL_UNSIGNED_INT_24_8              0x84FA
+#define GL_DEPTH24_STENCIL8               0x88F0
+#define GL_TEXTURE_STENCIL_SIZE           0x88F1
+#define GL_TEXTURE_RED_TYPE               0x8C10
+#define GL_TEXTURE_GREEN_TYPE             0x8C11
+#define GL_TEXTURE_BLUE_TYPE              0x8C12
+#define GL_TEXTURE_ALPHA_TYPE             0x8C13
+#define GL_TEXTURE_DEPTH_TYPE             0x8C16
+#define GL_UNSIGNED_NORMALIZED            0x8C17
+#define GL_FRAMEBUFFER_BINDING            0x8CA6
+#define GL_DRAW_FRAMEBUFFER_BINDING       0x8CA6
+#define GL_RENDERBUFFER_BINDING           0x8CA7
+#define GL_READ_FRAMEBUFFER               0x8CA8
+#define GL_DRAW_FRAMEBUFFER               0x8CA9
+#define GL_READ_FRAMEBUFFER_BINDING       0x8CAA
+#define GL_RENDERBUFFER_SAMPLES           0x8CAB
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4
+#define GL_FRAMEBUFFER_COMPLETE           0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB
+#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC
+#define GL_FRAMEBUFFER_UNSUPPORTED        0x8CDD
+#define GL_MAX_COLOR_ATTACHMENTS          0x8CDF
+#define GL_COLOR_ATTACHMENT0              0x8CE0
+#define GL_COLOR_ATTACHMENT1              0x8CE1
+#define GL_COLOR_ATTACHMENT2              0x8CE2
+#define GL_COLOR_ATTACHMENT3              0x8CE3
+#define GL_COLOR_ATTACHMENT4              0x8CE4
+#define GL_COLOR_ATTACHMENT5              0x8CE5
+#define GL_COLOR_ATTACHMENT6              0x8CE6
+#define GL_COLOR_ATTACHMENT7              0x8CE7
+#define GL_COLOR_ATTACHMENT8              0x8CE8
+#define GL_COLOR_ATTACHMENT9              0x8CE9
+#define GL_COLOR_ATTACHMENT10             0x8CEA
+#define GL_COLOR_ATTACHMENT11             0x8CEB
+#define GL_COLOR_ATTACHMENT12             0x8CEC
+#define GL_COLOR_ATTACHMENT13             0x8CED
+#define GL_COLOR_ATTACHMENT14             0x8CEE
+#define GL_COLOR_ATTACHMENT15             0x8CEF
+#define GL_COLOR_ATTACHMENT16             0x8CF0
+#define GL_COLOR_ATTACHMENT17             0x8CF1
+#define GL_COLOR_ATTACHMENT18             0x8CF2
+#define GL_COLOR_ATTACHMENT19             0x8CF3
+#define GL_COLOR_ATTACHMENT20             0x8CF4
+#define GL_COLOR_ATTACHMENT21             0x8CF5
+#define GL_COLOR_ATTACHMENT22             0x8CF6
+#define GL_COLOR_ATTACHMENT23             0x8CF7
+#define GL_COLOR_ATTACHMENT24             0x8CF8
+#define GL_COLOR_ATTACHMENT25             0x8CF9
+#define GL_COLOR_ATTACHMENT26             0x8CFA
+#define GL_COLOR_ATTACHMENT27             0x8CFB
+#define GL_COLOR_ATTACHMENT28             0x8CFC
+#define GL_COLOR_ATTACHMENT29             0x8CFD
+#define GL_COLOR_ATTACHMENT30             0x8CFE
+#define GL_COLOR_ATTACHMENT31             0x8CFF
+#define GL_DEPTH_ATTACHMENT               0x8D00
+#define GL_STENCIL_ATTACHMENT             0x8D20
+#define GL_FRAMEBUFFER                    0x8D40
+#define GL_RENDERBUFFER                   0x8D41
+#define GL_RENDERBUFFER_WIDTH             0x8D42
+#define GL_RENDERBUFFER_HEIGHT            0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT   0x8D44
+#define GL_STENCIL_INDEX1                 0x8D46
+#define GL_STENCIL_INDEX4                 0x8D47
+#define GL_STENCIL_INDEX8                 0x8D48
+#define GL_STENCIL_INDEX16                0x8D49
+#define GL_RENDERBUFFER_RED_SIZE          0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE        0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE         0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE        0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE        0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE      0x8D55
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
+#define GL_MAX_SAMPLES                    0x8D57
+#define GL_INDEX                          0x8222
+#define GL_TEXTURE_LUMINANCE_TYPE         0x8C14
+#define GL_TEXTURE_INTENSITY_TYPE         0x8C15
+#define GL_FRAMEBUFFER_SRGB               0x8DB9
+#define GL_HALF_FLOAT                     0x140B
+#define GL_MAP_READ_BIT                   0x0001
+#define GL_MAP_WRITE_BIT                  0x0002
+#define GL_MAP_INVALIDATE_RANGE_BIT       0x0004
+#define GL_MAP_INVALIDATE_BUFFER_BIT      0x0008
+#define GL_MAP_FLUSH_EXPLICIT_BIT         0x0010
+#define GL_MAP_UNSYNCHRONIZED_BIT         0x0020
+#define GL_COMPRESSED_RED_RGTC1           0x8DBB
+#define GL_COMPRESSED_SIGNED_RED_RGTC1    0x8DBC
+#define GL_COMPRESSED_RG_RGTC2            0x8DBD
+#define GL_COMPRESSED_SIGNED_RG_RGTC2     0x8DBE
+#define GL_RG                             0x8227
+#define GL_RG_INTEGER                     0x8228
+#define GL_R8                             0x8229
+#define GL_R16                            0x822A
+#define GL_RG8                            0x822B
+#define GL_RG16                           0x822C
+#define GL_R16F                           0x822D
+#define GL_R32F                           0x822E
+#define GL_RG16F                          0x822F
+#define GL_RG32F                          0x8230
+#define GL_R8I                            0x8231
+#define GL_R8UI                           0x8232
+#define GL_R16I                           0x8233
+#define GL_R16UI                          0x8234
+#define GL_R32I                           0x8235
+#define GL_R32UI                          0x8236
+#define GL_RG8I                           0x8237
+#define GL_RG8UI                          0x8238
+#define GL_RG16I                          0x8239
+#define GL_RG16UI                         0x823A
+#define GL_RG32I                          0x823B
+#define GL_RG32UI                         0x823C
+#define GL_VERTEX_ARRAY_BINDING           0x85B5
+#define GL_CLAMP_VERTEX_COLOR             0x891A
+#define GL_CLAMP_FRAGMENT_COLOR           0x891B
+#define GL_ALPHA_INTEGER                  0x8D97
+typedef void (APIENTRYP PFNGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data);
+typedef void (APIENTRYP PFNGLENABLEIPROC) (GLenum target, GLuint index);
+typedef void (APIENTRYP PFNGLDISABLEIPROC) (GLenum target, GLuint index);
+typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC) (GLenum target, GLuint index);
+typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode);
+typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC) (void);
+typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer);
+typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);
+typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP PFNGLCLAMPCOLORPROC) (GLenum target, GLenum clamp);
+typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode);
+typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC) (void);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params);
+typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name);
+typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0);
+typedef void (APIENTRYP PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1);
+typedef void (APIENTRYP PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2);
+typedef void (APIENTRYP PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params);
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value);
+typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value);
+typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value);
+typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
+typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index);
+typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers);
+typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers);
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer);
+typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer);
+typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers);
+typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers);
+typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+typedef void *(APIENTRYP PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length);
+typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array);
+typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays);
+typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
+typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC) (GLuint array);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorMaski (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+GLAPI void APIENTRY glGetBooleani_v (GLenum target, GLuint index, GLboolean *data);
+GLAPI void APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint *data);
+GLAPI void APIENTRY glEnablei (GLenum target, GLuint index);
+GLAPI void APIENTRY glDisablei (GLenum target, GLuint index);
+GLAPI GLboolean APIENTRY glIsEnabledi (GLenum target, GLuint index);
+GLAPI void APIENTRY glBeginTransformFeedback (GLenum primitiveMode);
+GLAPI void APIENTRY glEndTransformFeedback (void);
+GLAPI void APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+GLAPI void APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer);
+GLAPI void APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);
+GLAPI void APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);
+GLAPI void APIENTRY glClampColor (GLenum target, GLenum clamp);
+GLAPI void APIENTRY glBeginConditionalRender (GLuint id, GLenum mode);
+GLAPI void APIENTRY glEndConditionalRender (void);
+GLAPI void APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params);
+GLAPI void APIENTRY glVertexAttribI1i (GLuint index, GLint x);
+GLAPI void APIENTRY glVertexAttribI2i (GLuint index, GLint x, GLint y);
+GLAPI void APIENTRY glVertexAttribI3i (GLuint index, GLint x, GLint y, GLint z);
+GLAPI void APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w);
+GLAPI void APIENTRY glVertexAttribI1ui (GLuint index, GLuint x);
+GLAPI void APIENTRY glVertexAttribI2ui (GLuint index, GLuint x, GLuint y);
+GLAPI void APIENTRY glVertexAttribI3ui (GLuint index, GLuint x, GLuint y, GLuint z);
+GLAPI void APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+GLAPI void APIENTRY glVertexAttribI1iv (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttribI2iv (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttribI3iv (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttribI4iv (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttribI1uiv (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttribI2uiv (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttribI3uiv (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttribI4bv (GLuint index, const GLbyte *v);
+GLAPI void APIENTRY glVertexAttribI4sv (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttribI4ubv (GLuint index, const GLubyte *v);
+GLAPI void APIENTRY glVertexAttribI4usv (GLuint index, const GLushort *v);
+GLAPI void APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint *params);
+GLAPI void APIENTRY glBindFragDataLocation (GLuint program, GLuint color, const GLchar *name);
+GLAPI GLint APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name);
+GLAPI void APIENTRY glUniform1ui (GLint location, GLuint v0);
+GLAPI void APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1);
+GLAPI void APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2);
+GLAPI void APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+GLAPI void APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glTexParameterIiv (GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glTexParameterIuiv (GLenum target, GLenum pname, const GLuint *params);
+GLAPI void APIENTRY glGetTexParameterIiv (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetTexParameterIuiv (GLenum target, GLenum pname, GLuint *params);
+GLAPI void APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint *value);
+GLAPI void APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint *value);
+GLAPI void APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat *value);
+GLAPI void APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
+GLAPI const GLubyte *APIENTRY glGetStringi (GLenum name, GLuint index);
+GLAPI GLboolean APIENTRY glIsRenderbuffer (GLuint renderbuffer);
+GLAPI void APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer);
+GLAPI void APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers);
+GLAPI void APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers);
+GLAPI void APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params);
+GLAPI GLboolean APIENTRY glIsFramebuffer (GLuint framebuffer);
+GLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
+GLAPI void APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers);
+GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers);
+GLAPI GLenum APIENTRY glCheckFramebufferStatus (GLenum target);
+GLAPI void APIENTRY glFramebufferTexture1D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLAPI void APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLAPI void APIENTRY glFramebufferTexture3D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+GLAPI void APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GLAPI void APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGenerateMipmap (GLenum target);
+GLAPI void APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+GLAPI void APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+GLAPI void *APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+GLAPI void APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length);
+GLAPI void APIENTRY glBindVertexArray (GLuint array);
+GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays);
+GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays);
+GLAPI GLboolean APIENTRY glIsVertexArray (GLuint array);
+#endif
+#endif /* GL_VERSION_3_0 */
+
+#ifndef GL_VERSION_3_1
+#define GL_VERSION_3_1 1
+#define GL_SAMPLER_2D_RECT                0x8B63
+#define GL_SAMPLER_2D_RECT_SHADOW         0x8B64
+#define GL_SAMPLER_BUFFER                 0x8DC2
+#define GL_INT_SAMPLER_2D_RECT            0x8DCD
+#define GL_INT_SAMPLER_BUFFER             0x8DD0
+#define GL_UNSIGNED_INT_SAMPLER_2D_RECT   0x8DD5
+#define GL_UNSIGNED_INT_SAMPLER_BUFFER    0x8DD8
+#define GL_TEXTURE_BUFFER                 0x8C2A
+#define GL_MAX_TEXTURE_BUFFER_SIZE        0x8C2B
+#define GL_TEXTURE_BINDING_BUFFER         0x8C2C
+#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D
+#define GL_TEXTURE_RECTANGLE              0x84F5
+#define GL_TEXTURE_BINDING_RECTANGLE      0x84F6
+#define GL_PROXY_TEXTURE_RECTANGLE        0x84F7
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE     0x84F8
+#define GL_R8_SNORM                       0x8F94
+#define GL_RG8_SNORM                      0x8F95
+#define GL_RGB8_SNORM                     0x8F96
+#define GL_RGBA8_SNORM                    0x8F97
+#define GL_R16_SNORM                      0x8F98
+#define GL_RG16_SNORM                     0x8F99
+#define GL_RGB16_SNORM                    0x8F9A
+#define GL_RGBA16_SNORM                   0x8F9B
+#define GL_SIGNED_NORMALIZED              0x8F9C
+#define GL_PRIMITIVE_RESTART              0x8F9D
+#define GL_PRIMITIVE_RESTART_INDEX        0x8F9E
+#define GL_COPY_READ_BUFFER               0x8F36
+#define GL_COPY_WRITE_BUFFER              0x8F37
+#define GL_UNIFORM_BUFFER                 0x8A11
+#define GL_UNIFORM_BUFFER_BINDING         0x8A28
+#define GL_UNIFORM_BUFFER_START           0x8A29
+#define GL_UNIFORM_BUFFER_SIZE            0x8A2A
+#define GL_MAX_VERTEX_UNIFORM_BLOCKS      0x8A2B
+#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS    0x8A2C
+#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS    0x8A2D
+#define GL_MAX_COMBINED_UNIFORM_BLOCKS    0x8A2E
+#define GL_MAX_UNIFORM_BUFFER_BINDINGS    0x8A2F
+#define GL_MAX_UNIFORM_BLOCK_SIZE         0x8A30
+#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31
+#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32
+#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33
+#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34
+#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35
+#define GL_ACTIVE_UNIFORM_BLOCKS          0x8A36
+#define GL_UNIFORM_TYPE                   0x8A37
+#define GL_UNIFORM_SIZE                   0x8A38
+#define GL_UNIFORM_NAME_LENGTH            0x8A39
+#define GL_UNIFORM_BLOCK_INDEX            0x8A3A
+#define GL_UNIFORM_OFFSET                 0x8A3B
+#define GL_UNIFORM_ARRAY_STRIDE           0x8A3C
+#define GL_UNIFORM_MATRIX_STRIDE          0x8A3D
+#define GL_UNIFORM_IS_ROW_MAJOR           0x8A3E
+#define GL_UNIFORM_BLOCK_BINDING          0x8A3F
+#define GL_UNIFORM_BLOCK_DATA_SIZE        0x8A40
+#define GL_UNIFORM_BLOCK_NAME_LENGTH      0x8A41
+#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS  0x8A42
+#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46
+#define GL_INVALID_INDEX                  0xFFFFFFFFu
+typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount);
+typedef void (APIENTRYP PFNGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer);
+typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName);
+typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName);
+typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
+GLAPI void APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount);
+GLAPI void APIENTRY glTexBuffer (GLenum target, GLenum internalformat, GLuint buffer);
+GLAPI void APIENTRY glPrimitiveRestartIndex (GLuint index);
+GLAPI void APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+GLAPI void APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices);
+GLAPI void APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetActiveUniformName (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName);
+GLAPI GLuint APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar *uniformBlockName);
+GLAPI void APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName);
+GLAPI void APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
+#endif
+#endif /* GL_VERSION_3_1 */
+
+#ifndef GL_VERSION_3_2
+#define GL_VERSION_3_2 1
+typedef struct __GLsync *GLsync;
+typedef khronos_uint64_t GLuint64;
+typedef khronos_int64_t GLint64;
+#define GL_CONTEXT_CORE_PROFILE_BIT       0x00000001
+#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
+#define GL_LINES_ADJACENCY                0x000A
+#define GL_LINE_STRIP_ADJACENCY           0x000B
+#define GL_TRIANGLES_ADJACENCY            0x000C
+#define GL_TRIANGLE_STRIP_ADJACENCY       0x000D
+#define GL_PROGRAM_POINT_SIZE             0x8642
+#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29
+#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7
+#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8
+#define GL_GEOMETRY_SHADER                0x8DD9
+#define GL_GEOMETRY_VERTICES_OUT          0x8916
+#define GL_GEOMETRY_INPUT_TYPE            0x8917
+#define GL_GEOMETRY_OUTPUT_TYPE           0x8918
+#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF
+#define GL_MAX_GEOMETRY_OUTPUT_VERTICES   0x8DE0
+#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1
+#define GL_MAX_VERTEX_OUTPUT_COMPONENTS   0x9122
+#define GL_MAX_GEOMETRY_INPUT_COMPONENTS  0x9123
+#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124
+#define GL_MAX_FRAGMENT_INPUT_COMPONENTS  0x9125
+#define GL_CONTEXT_PROFILE_MASK           0x9126
+#define GL_DEPTH_CLAMP                    0x864F
+#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C
+#define GL_FIRST_VERTEX_CONVENTION        0x8E4D
+#define GL_LAST_VERTEX_CONVENTION         0x8E4E
+#define GL_PROVOKING_VERTEX               0x8E4F
+#define GL_TEXTURE_CUBE_MAP_SEAMLESS      0x884F
+#define GL_MAX_SERVER_WAIT_TIMEOUT        0x9111
+#define GL_OBJECT_TYPE                    0x9112
+#define GL_SYNC_CONDITION                 0x9113
+#define GL_SYNC_STATUS                    0x9114
+#define GL_SYNC_FLAGS                     0x9115
+#define GL_SYNC_FENCE                     0x9116
+#define GL_SYNC_GPU_COMMANDS_COMPLETE     0x9117
+#define GL_UNSIGNALED                     0x9118
+#define GL_SIGNALED                       0x9119
+#define GL_ALREADY_SIGNALED               0x911A
+#define GL_TIMEOUT_EXPIRED                0x911B
+#define GL_CONDITION_SATISFIED            0x911C
+#define GL_WAIT_FAILED                    0x911D
+#define GL_TIMEOUT_IGNORED                0xFFFFFFFFFFFFFFFFull
+#define GL_SYNC_FLUSH_COMMANDS_BIT        0x00000001
+#define GL_SAMPLE_POSITION                0x8E50
+#define GL_SAMPLE_MASK                    0x8E51
+#define GL_SAMPLE_MASK_VALUE              0x8E52
+#define GL_MAX_SAMPLE_MASK_WORDS          0x8E59
+#define GL_TEXTURE_2D_MULTISAMPLE         0x9100
+#define GL_PROXY_TEXTURE_2D_MULTISAMPLE   0x9101
+#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY   0x9102
+#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103
+#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104
+#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105
+#define GL_TEXTURE_SAMPLES                0x9106
+#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107
+#define GL_SAMPLER_2D_MULTISAMPLE         0x9108
+#define GL_INT_SAMPLER_2D_MULTISAMPLE     0x9109
+#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A
+#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY   0x910B
+#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C
+#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D
+#define GL_MAX_COLOR_TEXTURE_SAMPLES      0x910E
+#define GL_MAX_DEPTH_TEXTURE_SAMPLES      0x910F
+#define GL_MAX_INTEGER_SAMPLES            0x9110
+typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex);
+typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC) (GLenum mode);
+typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC) (GLenum condition, GLbitfield flags);
+typedef GLboolean (APIENTRYP PFNGLISSYNCPROC) (GLsync sync);
+typedef void (APIENTRYP PFNGLDELETESYNCPROC) (GLsync sync);
+typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
+typedef void (APIENTRYP PFNGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
+typedef void (APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *data);
+typedef void (APIENTRYP PFNGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
+typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data);
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val);
+typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC) (GLuint maskNumber, GLbitfield mask);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+GLAPI void APIENTRY glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+GLAPI void APIENTRY glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
+GLAPI void APIENTRY glMultiDrawElementsBaseVertex (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex);
+GLAPI void APIENTRY glProvokingVertex (GLenum mode);
+GLAPI GLsync APIENTRY glFenceSync (GLenum condition, GLbitfield flags);
+GLAPI GLboolean APIENTRY glIsSync (GLsync sync);
+GLAPI void APIENTRY glDeleteSync (GLsync sync);
+GLAPI GLenum APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout);
+GLAPI void APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout);
+GLAPI void APIENTRY glGetInteger64v (GLenum pname, GLint64 *data);
+GLAPI void APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
+GLAPI void APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64 *data);
+GLAPI void APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64 *params);
+GLAPI void APIENTRY glFramebufferTexture (GLenum target, GLenum attachment, GLuint texture, GLint level);
+GLAPI void APIENTRY glTexImage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+GLAPI void APIENTRY glTexImage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+GLAPI void APIENTRY glGetMultisamplefv (GLenum pname, GLuint index, GLfloat *val);
+GLAPI void APIENTRY glSampleMaski (GLuint maskNumber, GLbitfield mask);
+#endif
+#endif /* GL_VERSION_3_2 */
+
+#ifndef GL_VERSION_3_3
+#define GL_VERSION_3_3 1
+#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR    0x88FE
+#define GL_SRC1_COLOR                     0x88F9
+#define GL_ONE_MINUS_SRC1_COLOR           0x88FA
+#define GL_ONE_MINUS_SRC1_ALPHA           0x88FB
+#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS   0x88FC
+#define GL_ANY_SAMPLES_PASSED             0x8C2F
+#define GL_SAMPLER_BINDING                0x8919
+#define GL_RGB10_A2UI                     0x906F
+#define GL_TEXTURE_SWIZZLE_R              0x8E42
+#define GL_TEXTURE_SWIZZLE_G              0x8E43
+#define GL_TEXTURE_SWIZZLE_B              0x8E44
+#define GL_TEXTURE_SWIZZLE_A              0x8E45
+#define GL_TEXTURE_SWIZZLE_RGBA           0x8E46
+#define GL_TIME_ELAPSED                   0x88BF
+#define GL_TIMESTAMP                      0x8E28
+#define GL_INT_2_10_10_10_REV             0x8D9F
+typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);
+typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers);
+typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers);
+typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC) (GLuint sampler);
+typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler);
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param);
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param);
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param);
+typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param);
+typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC) (GLuint id, GLenum target);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64 *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64 *params);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+typedef void (APIENTRYP PFNGLVERTEXP2UIPROC) (GLenum type, GLuint value);
+typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC) (GLenum type, const GLuint *value);
+typedef void (APIENTRYP PFNGLVERTEXP3UIPROC) (GLenum type, GLuint value);
+typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC) (GLenum type, const GLuint *value);
+typedef void (APIENTRYP PFNGLVERTEXP4UIPROC) (GLenum type, GLuint value);
+typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC) (GLenum type, const GLuint *value);
+typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC) (GLenum type, GLuint coords);
+typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC) (GLenum type, const GLuint *coords);
+typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC) (GLenum type, GLuint coords);
+typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC) (GLenum type, const GLuint *coords);
+typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC) (GLenum type, GLuint coords);
+typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC) (GLenum type, const GLuint *coords);
+typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC) (GLenum type, GLuint coords);
+typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC) (GLenum type, const GLuint *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC) (GLenum texture, GLenum type, GLuint coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC) (GLenum texture, GLenum type, GLuint coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC) (GLenum texture, GLenum type, GLuint coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC) (GLenum texture, GLenum type, GLuint coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
+typedef void (APIENTRYP PFNGLNORMALP3UIPROC) (GLenum type, GLuint coords);
+typedef void (APIENTRYP PFNGLNORMALP3UIVPROC) (GLenum type, const GLuint *coords);
+typedef void (APIENTRYP PFNGLCOLORP3UIPROC) (GLenum type, GLuint color);
+typedef void (APIENTRYP PFNGLCOLORP3UIVPROC) (GLenum type, const GLuint *color);
+typedef void (APIENTRYP PFNGLCOLORP4UIPROC) (GLenum type, GLuint color);
+typedef void (APIENTRYP PFNGLCOLORP4UIVPROC) (GLenum type, const GLuint *color);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC) (GLenum type, GLuint color);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC) (GLenum type, const GLuint *color);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindFragDataLocationIndexed (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);
+GLAPI GLint APIENTRY glGetFragDataIndex (GLuint program, const GLchar *name);
+GLAPI void APIENTRY glGenSamplers (GLsizei count, GLuint *samplers);
+GLAPI void APIENTRY glDeleteSamplers (GLsizei count, const GLuint *samplers);
+GLAPI GLboolean APIENTRY glIsSampler (GLuint sampler);
+GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler);
+GLAPI void APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param);
+GLAPI void APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint *param);
+GLAPI void APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat *param);
+GLAPI void APIENTRY glSamplerParameterIiv (GLuint sampler, GLenum pname, const GLint *param);
+GLAPI void APIENTRY glSamplerParameterIuiv (GLuint sampler, GLenum pname, const GLuint *param);
+GLAPI void APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetSamplerParameterIiv (GLuint sampler, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetSamplerParameterIuiv (GLuint sampler, GLenum pname, GLuint *params);
+GLAPI void APIENTRY glQueryCounter (GLuint id, GLenum target);
+GLAPI void APIENTRY glGetQueryObjecti64v (GLuint id, GLenum pname, GLint64 *params);
+GLAPI void APIENTRY glGetQueryObjectui64v (GLuint id, GLenum pname, GLuint64 *params);
+GLAPI void APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor);
+GLAPI void APIENTRY glVertexAttribP1ui (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+GLAPI void APIENTRY glVertexAttribP1uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+GLAPI void APIENTRY glVertexAttribP2ui (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+GLAPI void APIENTRY glVertexAttribP2uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+GLAPI void APIENTRY glVertexAttribP3ui (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+GLAPI void APIENTRY glVertexAttribP3uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+GLAPI void APIENTRY glVertexAttribP4ui (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+GLAPI void APIENTRY glVertexAttribP4uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+GLAPI void APIENTRY glVertexP2ui (GLenum type, GLuint value);
+GLAPI void APIENTRY glVertexP2uiv (GLenum type, const GLuint *value);
+GLAPI void APIENTRY glVertexP3ui (GLenum type, GLuint value);
+GLAPI void APIENTRY glVertexP3uiv (GLenum type, const GLuint *value);
+GLAPI void APIENTRY glVertexP4ui (GLenum type, GLuint value);
+GLAPI void APIENTRY glVertexP4uiv (GLenum type, const GLuint *value);
+GLAPI void APIENTRY glTexCoordP1ui (GLenum type, GLuint coords);
+GLAPI void APIENTRY glTexCoordP1uiv (GLenum type, const GLuint *coords);
+GLAPI void APIENTRY glTexCoordP2ui (GLenum type, GLuint coords);
+GLAPI void APIENTRY glTexCoordP2uiv (GLenum type, const GLuint *coords);
+GLAPI void APIENTRY glTexCoordP3ui (GLenum type, GLuint coords);
+GLAPI void APIENTRY glTexCoordP3uiv (GLenum type, const GLuint *coords);
+GLAPI void APIENTRY glTexCoordP4ui (GLenum type, GLuint coords);
+GLAPI void APIENTRY glTexCoordP4uiv (GLenum type, const GLuint *coords);
+GLAPI void APIENTRY glMultiTexCoordP1ui (GLenum texture, GLenum type, GLuint coords);
+GLAPI void APIENTRY glMultiTexCoordP1uiv (GLenum texture, GLenum type, const GLuint *coords);
+GLAPI void APIENTRY glMultiTexCoordP2ui (GLenum texture, GLenum type, GLuint coords);
+GLAPI void APIENTRY glMultiTexCoordP2uiv (GLenum texture, GLenum type, const GLuint *coords);
+GLAPI void APIENTRY glMultiTexCoordP3ui (GLenum texture, GLenum type, GLuint coords);
+GLAPI void APIENTRY glMultiTexCoordP3uiv (GLenum texture, GLenum type, const GLuint *coords);
+GLAPI void APIENTRY glMultiTexCoordP4ui (GLenum texture, GLenum type, GLuint coords);
+GLAPI void APIENTRY glMultiTexCoordP4uiv (GLenum texture, GLenum type, const GLuint *coords);
+GLAPI void APIENTRY glNormalP3ui (GLenum type, GLuint coords);
+GLAPI void APIENTRY glNormalP3uiv (GLenum type, const GLuint *coords);
+GLAPI void APIENTRY glColorP3ui (GLenum type, GLuint color);
+GLAPI void APIENTRY glColorP3uiv (GLenum type, const GLuint *color);
+GLAPI void APIENTRY glColorP4ui (GLenum type, GLuint color);
+GLAPI void APIENTRY glColorP4uiv (GLenum type, const GLuint *color);
+GLAPI void APIENTRY glSecondaryColorP3ui (GLenum type, GLuint color);
+GLAPI void APIENTRY glSecondaryColorP3uiv (GLenum type, const GLuint *color);
+#endif
+#endif /* GL_VERSION_3_3 */
+
+#ifndef GL_VERSION_4_0
+#define GL_VERSION_4_0 1
+#define GL_SAMPLE_SHADING                 0x8C36
+#define GL_MIN_SAMPLE_SHADING_VALUE       0x8C37
+#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E
+#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F
+#define GL_TEXTURE_CUBE_MAP_ARRAY         0x9009
+#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A
+#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY   0x900B
+#define GL_SAMPLER_CUBE_MAP_ARRAY         0x900C
+#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW  0x900D
+#define GL_INT_SAMPLER_CUBE_MAP_ARRAY     0x900E
+#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F
+#define GL_DRAW_INDIRECT_BUFFER           0x8F3F
+#define GL_DRAW_INDIRECT_BUFFER_BINDING   0x8F43
+#define GL_GEOMETRY_SHADER_INVOCATIONS    0x887F
+#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A
+#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B
+#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C
+#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D
+#define GL_MAX_VERTEX_STREAMS             0x8E71
+#define GL_DOUBLE_VEC2                    0x8FFC
+#define GL_DOUBLE_VEC3                    0x8FFD
+#define GL_DOUBLE_VEC4                    0x8FFE
+#define GL_DOUBLE_MAT2                    0x8F46
+#define GL_DOUBLE_MAT3                    0x8F47
+#define GL_DOUBLE_MAT4                    0x8F48
+#define GL_DOUBLE_MAT2x3                  0x8F49
+#define GL_DOUBLE_MAT2x4                  0x8F4A
+#define GL_DOUBLE_MAT3x2                  0x8F4B
+#define GL_DOUBLE_MAT3x4                  0x8F4C
+#define GL_DOUBLE_MAT4x2                  0x8F4D
+#define GL_DOUBLE_MAT4x3                  0x8F4E
+#define GL_ACTIVE_SUBROUTINES             0x8DE5
+#define GL_ACTIVE_SUBROUTINE_UNIFORMS     0x8DE6
+#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47
+#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH   0x8E48
+#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49
+#define GL_MAX_SUBROUTINES                0x8DE7
+#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8
+#define GL_NUM_COMPATIBLE_SUBROUTINES     0x8E4A
+#define GL_COMPATIBLE_SUBROUTINES         0x8E4B
+#define GL_PATCHES                        0x000E
+#define GL_PATCH_VERTICES                 0x8E72
+#define GL_PATCH_DEFAULT_INNER_LEVEL      0x8E73
+#define GL_PATCH_DEFAULT_OUTER_LEVEL      0x8E74
+#define GL_TESS_CONTROL_OUTPUT_VERTICES   0x8E75
+#define GL_TESS_GEN_MODE                  0x8E76
+#define GL_TESS_GEN_SPACING               0x8E77
+#define GL_TESS_GEN_VERTEX_ORDER          0x8E78
+#define GL_TESS_GEN_POINT_MODE            0x8E79
+#define GL_ISOLINES                       0x8E7A
+#define GL_FRACTIONAL_ODD                 0x8E7B
+#define GL_FRACTIONAL_EVEN                0x8E7C
+#define GL_MAX_PATCH_VERTICES             0x8E7D
+#define GL_MAX_TESS_GEN_LEVEL             0x8E7E
+#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F
+#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80
+#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81
+#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82
+#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83
+#define GL_MAX_TESS_PATCH_COMPONENTS      0x8E84
+#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85
+#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86
+#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89
+#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A
+#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C
+#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D
+#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E
+#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1
+#define GL_TESS_EVALUATION_SHADER         0x8E87
+#define GL_TESS_CONTROL_SHADER            0x8E88
+#define GL_TRANSFORM_FEEDBACK             0x8E22
+#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23
+#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24
+#define GL_TRANSFORM_FEEDBACK_BINDING     0x8E25
+#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70
+typedef void (APIENTRYP PFNGLMINSAMPLESHADINGPROC) (GLfloat value);
+typedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode);
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+typedef void (APIENTRYP PFNGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst);
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect);
+typedef void (APIENTRYP PFNGLUNIFORM1DPROC) (GLint location, GLdouble x);
+typedef void (APIENTRYP PFNGLUNIFORM2DPROC) (GLint location, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLUNIFORM3DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLUNIFORM4DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLUNIFORM1DVPROC) (GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORM2DVPROC) (GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORM3DVPROC) (GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORM4DVPROC) (GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLGETUNIFORMDVPROC) (GLuint program, GLint location, GLdouble *params);
+typedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC) (GLuint program, GLenum shadertype, const GLchar *name);
+typedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC) (GLuint program, GLenum shadertype, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC) (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values);
+typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);
+typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);
+typedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, GLsizei count, const GLuint *indices);
+typedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC) (GLenum shadertype, GLint location, GLuint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC) (GLuint program, GLenum shadertype, GLenum pname, GLint *values);
+typedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC) (GLenum pname, GLint value);
+typedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC) (GLenum pname, const GLfloat *values);
+typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids);
+typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC) (void);
+typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC) (void);
+typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC) (GLenum mode, GLuint id);
+typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC) (GLenum mode, GLuint id, GLuint stream);
+typedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC) (GLenum target, GLuint index, GLuint id);
+typedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC) (GLenum target, GLuint index);
+typedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMinSampleShading (GLfloat value);
+GLAPI void APIENTRY glBlendEquationi (GLuint buf, GLenum mode);
+GLAPI void APIENTRY glBlendEquationSeparatei (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+GLAPI void APIENTRY glBlendFunci (GLuint buf, GLenum src, GLenum dst);
+GLAPI void APIENTRY glBlendFuncSeparatei (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+GLAPI void APIENTRY glDrawArraysIndirect (GLenum mode, const void *indirect);
+GLAPI void APIENTRY glDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect);
+GLAPI void APIENTRY glUniform1d (GLint location, GLdouble x);
+GLAPI void APIENTRY glUniform2d (GLint location, GLdouble x, GLdouble y);
+GLAPI void APIENTRY glUniform3d (GLint location, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glUniform4d (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glUniform1dv (GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glUniform2dv (GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glUniform3dv (GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glUniform4dv (GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glUniformMatrix2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glUniformMatrix3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glUniformMatrix4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glUniformMatrix2x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glUniformMatrix2x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glUniformMatrix3x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glUniformMatrix3x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glUniformMatrix4x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glUniformMatrix4x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glGetUniformdv (GLuint program, GLint location, GLdouble *params);
+GLAPI GLint APIENTRY glGetSubroutineUniformLocation (GLuint program, GLenum shadertype, const GLchar *name);
+GLAPI GLuint APIENTRY glGetSubroutineIndex (GLuint program, GLenum shadertype, const GLchar *name);
+GLAPI void APIENTRY glGetActiveSubroutineUniformiv (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values);
+GLAPI void APIENTRY glGetActiveSubroutineUniformName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);
+GLAPI void APIENTRY glGetActiveSubroutineName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);
+GLAPI void APIENTRY glUniformSubroutinesuiv (GLenum shadertype, GLsizei count, const GLuint *indices);
+GLAPI void APIENTRY glGetUniformSubroutineuiv (GLenum shadertype, GLint location, GLuint *params);
+GLAPI void APIENTRY glGetProgramStageiv (GLuint program, GLenum shadertype, GLenum pname, GLint *values);
+GLAPI void APIENTRY glPatchParameteri (GLenum pname, GLint value);
+GLAPI void APIENTRY glPatchParameterfv (GLenum pname, const GLfloat *values);
+GLAPI void APIENTRY glBindTransformFeedback (GLenum target, GLuint id);
+GLAPI void APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint *ids);
+GLAPI void APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint *ids);
+GLAPI GLboolean APIENTRY glIsTransformFeedback (GLuint id);
+GLAPI void APIENTRY glPauseTransformFeedback (void);
+GLAPI void APIENTRY glResumeTransformFeedback (void);
+GLAPI void APIENTRY glDrawTransformFeedback (GLenum mode, GLuint id);
+GLAPI void APIENTRY glDrawTransformFeedbackStream (GLenum mode, GLuint id, GLuint stream);
+GLAPI void APIENTRY glBeginQueryIndexed (GLenum target, GLuint index, GLuint id);
+GLAPI void APIENTRY glEndQueryIndexed (GLenum target, GLuint index);
+GLAPI void APIENTRY glGetQueryIndexediv (GLenum target, GLuint index, GLenum pname, GLint *params);
+#endif
+#endif /* GL_VERSION_4_0 */
+
+#ifndef GL_VERSION_4_1
+#define GL_VERSION_4_1 1
+#define GL_FIXED                          0x140C
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
+#define GL_LOW_FLOAT                      0x8DF0
+#define GL_MEDIUM_FLOAT                   0x8DF1
+#define GL_HIGH_FLOAT                     0x8DF2
+#define GL_LOW_INT                        0x8DF3
+#define GL_MEDIUM_INT                     0x8DF4
+#define GL_HIGH_INT                       0x8DF5
+#define GL_SHADER_COMPILER                0x8DFA
+#define GL_SHADER_BINARY_FORMATS          0x8DF8
+#define GL_NUM_SHADER_BINARY_FORMATS      0x8DF9
+#define GL_MAX_VERTEX_UNIFORM_VECTORS     0x8DFB
+#define GL_MAX_VARYING_VECTORS            0x8DFC
+#define GL_MAX_FRAGMENT_UNIFORM_VECTORS   0x8DFD
+#define GL_RGB565                         0x8D62
+#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257
+#define GL_PROGRAM_BINARY_LENGTH          0x8741
+#define GL_NUM_PROGRAM_BINARY_FORMATS     0x87FE
+#define GL_PROGRAM_BINARY_FORMATS         0x87FF
+#define GL_VERTEX_SHADER_BIT              0x00000001
+#define GL_FRAGMENT_SHADER_BIT            0x00000002
+#define GL_GEOMETRY_SHADER_BIT            0x00000004
+#define GL_TESS_CONTROL_SHADER_BIT        0x00000008
+#define GL_TESS_EVALUATION_SHADER_BIT     0x00000010
+#define GL_ALL_SHADER_BITS                0xFFFFFFFF
+#define GL_PROGRAM_SEPARABLE              0x8258
+#define GL_ACTIVE_PROGRAM                 0x8259
+#define GL_PROGRAM_PIPELINE_BINDING       0x825A
+#define GL_MAX_VIEWPORTS                  0x825B
+#define GL_VIEWPORT_SUBPIXEL_BITS         0x825C
+#define GL_VIEWPORT_BOUNDS_RANGE          0x825D
+#define GL_LAYER_PROVOKING_VERTEX         0x825E
+#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F
+#define GL_UNDEFINED_VERTEX               0x8260
+typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void);
+typedef void (APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length);
+typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision);
+typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f);
+typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC) (GLfloat d);
+typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
+typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value);
+typedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program);
+typedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program);
+typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar *const*strings);
+typedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines);
+typedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC) (GLuint pipeline);
+typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC) (GLuint program, GLint location, GLdouble v0);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline);
+typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);
+typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLSCISSORARRAYVPROC) (GLuint first, GLsizei count, const GLint *v);
+typedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC) (GLuint first, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC) (GLuint index, GLdouble n, GLdouble f);
+typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data);
+typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glReleaseShaderCompiler (void);
+GLAPI void APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length);
+GLAPI void APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision);
+GLAPI void APIENTRY glDepthRangef (GLfloat n, GLfloat f);
+GLAPI void APIENTRY glClearDepthf (GLfloat d);
+GLAPI void APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
+GLAPI void APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length);
+GLAPI void APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value);
+GLAPI void APIENTRY glUseProgramStages (GLuint pipeline, GLbitfield stages, GLuint program);
+GLAPI void APIENTRY glActiveShaderProgram (GLuint pipeline, GLuint program);
+GLAPI GLuint APIENTRY glCreateShaderProgramv (GLenum type, GLsizei count, const GLchar *const*strings);
+GLAPI void APIENTRY glBindProgramPipeline (GLuint pipeline);
+GLAPI void APIENTRY glDeleteProgramPipelines (GLsizei n, const GLuint *pipelines);
+GLAPI void APIENTRY glGenProgramPipelines (GLsizei n, GLuint *pipelines);
+GLAPI GLboolean APIENTRY glIsProgramPipeline (GLuint pipeline);
+GLAPI void APIENTRY glGetProgramPipelineiv (GLuint pipeline, GLenum pname, GLint *params);
+GLAPI void APIENTRY glProgramUniform1i (GLuint program, GLint location, GLint v0);
+GLAPI void APIENTRY glProgramUniform1iv (GLuint program, GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glProgramUniform1f (GLuint program, GLint location, GLfloat v0);
+GLAPI void APIENTRY glProgramUniform1fv (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniform1d (GLuint program, GLint location, GLdouble v0);
+GLAPI void APIENTRY glProgramUniform1dv (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniform1ui (GLuint program, GLint location, GLuint v0);
+GLAPI void APIENTRY glProgramUniform1uiv (GLuint program, GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glProgramUniform2i (GLuint program, GLint location, GLint v0, GLint v1);
+GLAPI void APIENTRY glProgramUniform2iv (GLuint program, GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glProgramUniform2f (GLuint program, GLint location, GLfloat v0, GLfloat v1);
+GLAPI void APIENTRY glProgramUniform2fv (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniform2d (GLuint program, GLint location, GLdouble v0, GLdouble v1);
+GLAPI void APIENTRY glProgramUniform2dv (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniform2ui (GLuint program, GLint location, GLuint v0, GLuint v1);
+GLAPI void APIENTRY glProgramUniform2uiv (GLuint program, GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glProgramUniform3i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
+GLAPI void APIENTRY glProgramUniform3iv (GLuint program, GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glProgramUniform3f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+GLAPI void APIENTRY glProgramUniform3fv (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniform3d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2);
+GLAPI void APIENTRY glProgramUniform3dv (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniform3ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
+GLAPI void APIENTRY glProgramUniform3uiv (GLuint program, GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glProgramUniform4i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+GLAPI void APIENTRY glProgramUniform4iv (GLuint program, GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glProgramUniform4f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+GLAPI void APIENTRY glProgramUniform4fv (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniform4d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3);
+GLAPI void APIENTRY glProgramUniform4dv (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniform4ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+GLAPI void APIENTRY glProgramUniform4uiv (GLuint program, GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glProgramUniformMatrix2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix2x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix3x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix2x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix4x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix3x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix4x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix2x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix3x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix2x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix4x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix3x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix4x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glValidateProgramPipeline (GLuint pipeline);
+GLAPI void APIENTRY glGetProgramPipelineInfoLog (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+GLAPI void APIENTRY glVertexAttribL1d (GLuint index, GLdouble x);
+GLAPI void APIENTRY glVertexAttribL2d (GLuint index, GLdouble x, GLdouble y);
+GLAPI void APIENTRY glVertexAttribL3d (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glVertexAttribL4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glVertexAttribL1dv (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribL2dv (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribL3dv (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribL4dv (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribLPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glGetVertexAttribLdv (GLuint index, GLenum pname, GLdouble *params);
+GLAPI void APIENTRY glViewportArrayv (GLuint first, GLsizei count, const GLfloat *v);
+GLAPI void APIENTRY glViewportIndexedf (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);
+GLAPI void APIENTRY glViewportIndexedfv (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glScissorArrayv (GLuint first, GLsizei count, const GLint *v);
+GLAPI void APIENTRY glScissorIndexed (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glScissorIndexedv (GLuint index, const GLint *v);
+GLAPI void APIENTRY glDepthRangeArrayv (GLuint first, GLsizei count, const GLdouble *v);
+GLAPI void APIENTRY glDepthRangeIndexed (GLuint index, GLdouble n, GLdouble f);
+GLAPI void APIENTRY glGetFloati_v (GLenum target, GLuint index, GLfloat *data);
+GLAPI void APIENTRY glGetDoublei_v (GLenum target, GLuint index, GLdouble *data);
+#endif
+#endif /* GL_VERSION_4_1 */
+
+#ifndef GL_VERSION_4_2
+#define GL_VERSION_4_2 1
+#define GL_COPY_READ_BUFFER_BINDING       0x8F36
+#define GL_COPY_WRITE_BUFFER_BINDING      0x8F37
+#define GL_TRANSFORM_FEEDBACK_ACTIVE      0x8E24
+#define GL_TRANSFORM_FEEDBACK_PAUSED      0x8E23
+#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH  0x9127
+#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128
+#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH  0x9129
+#define GL_UNPACK_COMPRESSED_BLOCK_SIZE   0x912A
+#define GL_PACK_COMPRESSED_BLOCK_WIDTH    0x912B
+#define GL_PACK_COMPRESSED_BLOCK_HEIGHT   0x912C
+#define GL_PACK_COMPRESSED_BLOCK_DEPTH    0x912D
+#define GL_PACK_COMPRESSED_BLOCK_SIZE     0x912E
+#define GL_NUM_SAMPLE_COUNTS              0x9380
+#define GL_MIN_MAP_BUFFER_ALIGNMENT       0x90BC
+#define GL_ATOMIC_COUNTER_BUFFER          0x92C0
+#define GL_ATOMIC_COUNTER_BUFFER_BINDING  0x92C1
+#define GL_ATOMIC_COUNTER_BUFFER_START    0x92C2
+#define GL_ATOMIC_COUNTER_BUFFER_SIZE     0x92C3
+#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4
+#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5
+#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB
+#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC
+#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD
+#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE
+#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF
+#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0
+#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1
+#define GL_MAX_VERTEX_ATOMIC_COUNTERS     0x92D2
+#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3
+#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4
+#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS   0x92D5
+#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS   0x92D6
+#define GL_MAX_COMBINED_ATOMIC_COUNTERS   0x92D7
+#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8
+#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC
+#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS  0x92D9
+#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA
+#define GL_UNSIGNED_INT_ATOMIC_COUNTER    0x92DB
+#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001
+#define GL_ELEMENT_ARRAY_BARRIER_BIT      0x00000002
+#define GL_UNIFORM_BARRIER_BIT            0x00000004
+#define GL_TEXTURE_FETCH_BARRIER_BIT      0x00000008
+#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
+#define GL_COMMAND_BARRIER_BIT            0x00000040
+#define GL_PIXEL_BUFFER_BARRIER_BIT       0x00000080
+#define GL_TEXTURE_UPDATE_BARRIER_BIT     0x00000100
+#define GL_BUFFER_UPDATE_BARRIER_BIT      0x00000200
+#define GL_FRAMEBUFFER_BARRIER_BIT        0x00000400
+#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800
+#define GL_ATOMIC_COUNTER_BARRIER_BIT     0x00001000
+#define GL_ALL_BARRIER_BITS               0xFFFFFFFF
+#define GL_MAX_IMAGE_UNITS                0x8F38
+#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39
+#define GL_IMAGE_BINDING_NAME             0x8F3A
+#define GL_IMAGE_BINDING_LEVEL            0x8F3B
+#define GL_IMAGE_BINDING_LAYERED          0x8F3C
+#define GL_IMAGE_BINDING_LAYER            0x8F3D
+#define GL_IMAGE_BINDING_ACCESS           0x8F3E
+#define GL_IMAGE_1D                       0x904C
+#define GL_IMAGE_2D                       0x904D
+#define GL_IMAGE_3D                       0x904E
+#define GL_IMAGE_2D_RECT                  0x904F
+#define GL_IMAGE_CUBE                     0x9050
+#define GL_IMAGE_BUFFER                   0x9051
+#define GL_IMAGE_1D_ARRAY                 0x9052
+#define GL_IMAGE_2D_ARRAY                 0x9053
+#define GL_IMAGE_CUBE_MAP_ARRAY           0x9054
+#define GL_IMAGE_2D_MULTISAMPLE           0x9055
+#define GL_IMAGE_2D_MULTISAMPLE_ARRAY     0x9056
+#define GL_INT_IMAGE_1D                   0x9057
+#define GL_INT_IMAGE_2D                   0x9058
+#define GL_INT_IMAGE_3D                   0x9059
+#define GL_INT_IMAGE_2D_RECT              0x905A
+#define GL_INT_IMAGE_CUBE                 0x905B
+#define GL_INT_IMAGE_BUFFER               0x905C
+#define GL_INT_IMAGE_1D_ARRAY             0x905D
+#define GL_INT_IMAGE_2D_ARRAY             0x905E
+#define GL_INT_IMAGE_CUBE_MAP_ARRAY       0x905F
+#define GL_INT_IMAGE_2D_MULTISAMPLE       0x9060
+#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061
+#define GL_UNSIGNED_INT_IMAGE_1D          0x9062
+#define GL_UNSIGNED_INT_IMAGE_2D          0x9063
+#define GL_UNSIGNED_INT_IMAGE_3D          0x9064
+#define GL_UNSIGNED_INT_IMAGE_2D_RECT     0x9065
+#define GL_UNSIGNED_INT_IMAGE_CUBE        0x9066
+#define GL_UNSIGNED_INT_IMAGE_BUFFER      0x9067
+#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY    0x9068
+#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY    0x9069
+#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A
+#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B
+#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C
+#define GL_MAX_IMAGE_SAMPLES              0x906D
+#define GL_IMAGE_BINDING_FORMAT           0x906E
+#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7
+#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8
+#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9
+#define GL_MAX_VERTEX_IMAGE_UNIFORMS      0x90CA
+#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB
+#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC
+#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS    0x90CD
+#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS    0x90CE
+#define GL_MAX_COMBINED_IMAGE_UNIFORMS    0x90CF
+#define GL_COMPRESSED_RGBA_BPTC_UNORM     0x8E8C
+#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D
+#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E
+#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F
+#define GL_TEXTURE_IMMUTABLE_FORMAT       0x912F
+typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);
+typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);
+typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
+typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers);
+typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei instancecount);
+typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);
+GLAPI void APIENTRY glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);
+GLAPI void APIENTRY glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);
+GLAPI void APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);
+GLAPI void APIENTRY glGetActiveAtomicCounterBufferiv (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params);
+GLAPI void APIENTRY glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
+GLAPI void APIENTRY glMemoryBarrier (GLbitfield barriers);
+GLAPI void APIENTRY glTexStorage1D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GLAPI void APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+GLAPI void APIENTRY glDrawTransformFeedbackInstanced (GLenum mode, GLuint id, GLsizei instancecount);
+GLAPI void APIENTRY glDrawTransformFeedbackStreamInstanced (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount);
+#endif
+#endif /* GL_VERSION_4_2 */
+
+#ifndef GL_VERSION_4_3
+#define GL_VERSION_4_3 1
+typedef void (APIENTRY  *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+#define GL_NUM_SHADING_LANGUAGE_VERSIONS  0x82E9
+#define GL_VERTEX_ATTRIB_ARRAY_LONG       0x874E
+#define GL_COMPRESSED_RGB8_ETC2           0x9274
+#define GL_COMPRESSED_SRGB8_ETC2          0x9275
+#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
+#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
+#define GL_COMPRESSED_RGBA8_ETC2_EAC      0x9278
+#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279
+#define GL_COMPRESSED_R11_EAC             0x9270
+#define GL_COMPRESSED_SIGNED_R11_EAC      0x9271
+#define GL_COMPRESSED_RG11_EAC            0x9272
+#define GL_COMPRESSED_SIGNED_RG11_EAC     0x9273
+#define GL_PRIMITIVE_RESTART_FIXED_INDEX  0x8D69
+#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A
+#define GL_MAX_ELEMENT_INDEX              0x8D6B
+#define GL_COMPUTE_SHADER                 0x91B9
+#define GL_MAX_COMPUTE_UNIFORM_BLOCKS     0x91BB
+#define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC
+#define GL_MAX_COMPUTE_IMAGE_UNIFORMS     0x91BD
+#define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262
+#define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263
+#define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264
+#define GL_MAX_COMPUTE_ATOMIC_COUNTERS    0x8265
+#define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266
+#define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB
+#define GL_MAX_COMPUTE_WORK_GROUP_COUNT   0x91BE
+#define GL_MAX_COMPUTE_WORK_GROUP_SIZE    0x91BF
+#define GL_COMPUTE_WORK_GROUP_SIZE        0x8267
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED
+#define GL_DISPATCH_INDIRECT_BUFFER       0x90EE
+#define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF
+#define GL_COMPUTE_SHADER_BIT             0x00000020
+#define GL_DEBUG_OUTPUT_SYNCHRONOUS       0x8242
+#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243
+#define GL_DEBUG_CALLBACK_FUNCTION        0x8244
+#define GL_DEBUG_CALLBACK_USER_PARAM      0x8245
+#define GL_DEBUG_SOURCE_API               0x8246
+#define GL_DEBUG_SOURCE_WINDOW_SYSTEM     0x8247
+#define GL_DEBUG_SOURCE_SHADER_COMPILER   0x8248
+#define GL_DEBUG_SOURCE_THIRD_PARTY       0x8249
+#define GL_DEBUG_SOURCE_APPLICATION       0x824A
+#define GL_DEBUG_SOURCE_OTHER             0x824B
+#define GL_DEBUG_TYPE_ERROR               0x824C
+#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D
+#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR  0x824E
+#define GL_DEBUG_TYPE_PORTABILITY         0x824F
+#define GL_DEBUG_TYPE_PERFORMANCE         0x8250
+#define GL_DEBUG_TYPE_OTHER               0x8251
+#define GL_MAX_DEBUG_MESSAGE_LENGTH       0x9143
+#define GL_MAX_DEBUG_LOGGED_MESSAGES      0x9144
+#define GL_DEBUG_LOGGED_MESSAGES          0x9145
+#define GL_DEBUG_SEVERITY_HIGH            0x9146
+#define GL_DEBUG_SEVERITY_MEDIUM          0x9147
+#define GL_DEBUG_SEVERITY_LOW             0x9148
+#define GL_DEBUG_TYPE_MARKER              0x8268
+#define GL_DEBUG_TYPE_PUSH_GROUP          0x8269
+#define GL_DEBUG_TYPE_POP_GROUP           0x826A
+#define GL_DEBUG_SEVERITY_NOTIFICATION    0x826B
+#define GL_MAX_DEBUG_GROUP_STACK_DEPTH    0x826C
+#define GL_DEBUG_GROUP_STACK_DEPTH        0x826D
+#define GL_BUFFER                         0x82E0
+#define GL_SHADER                         0x82E1
+#define GL_PROGRAM                        0x82E2
+#define GL_QUERY                          0x82E3
+#define GL_PROGRAM_PIPELINE               0x82E4
+#define GL_SAMPLER                        0x82E6
+#define GL_MAX_LABEL_LENGTH               0x82E8
+#define GL_DEBUG_OUTPUT                   0x92E0
+#define GL_CONTEXT_FLAG_DEBUG_BIT         0x00000002
+#define GL_MAX_UNIFORM_LOCATIONS          0x826E
+#define GL_FRAMEBUFFER_DEFAULT_WIDTH      0x9310
+#define GL_FRAMEBUFFER_DEFAULT_HEIGHT     0x9311
+#define GL_FRAMEBUFFER_DEFAULT_LAYERS     0x9312
+#define GL_FRAMEBUFFER_DEFAULT_SAMPLES    0x9313
+#define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314
+#define GL_MAX_FRAMEBUFFER_WIDTH          0x9315
+#define GL_MAX_FRAMEBUFFER_HEIGHT         0x9316
+#define GL_MAX_FRAMEBUFFER_LAYERS         0x9317
+#define GL_MAX_FRAMEBUFFER_SAMPLES        0x9318
+#define GL_INTERNALFORMAT_SUPPORTED       0x826F
+#define GL_INTERNALFORMAT_PREFERRED       0x8270
+#define GL_INTERNALFORMAT_RED_SIZE        0x8271
+#define GL_INTERNALFORMAT_GREEN_SIZE      0x8272
+#define GL_INTERNALFORMAT_BLUE_SIZE       0x8273
+#define GL_INTERNALFORMAT_ALPHA_SIZE      0x8274
+#define GL_INTERNALFORMAT_DEPTH_SIZE      0x8275
+#define GL_INTERNALFORMAT_STENCIL_SIZE    0x8276
+#define GL_INTERNALFORMAT_SHARED_SIZE     0x8277
+#define GL_INTERNALFORMAT_RED_TYPE        0x8278
+#define GL_INTERNALFORMAT_GREEN_TYPE      0x8279
+#define GL_INTERNALFORMAT_BLUE_TYPE       0x827A
+#define GL_INTERNALFORMAT_ALPHA_TYPE      0x827B
+#define GL_INTERNALFORMAT_DEPTH_TYPE      0x827C
+#define GL_INTERNALFORMAT_STENCIL_TYPE    0x827D
+#define GL_MAX_WIDTH                      0x827E
+#define GL_MAX_HEIGHT                     0x827F
+#define GL_MAX_DEPTH                      0x8280
+#define GL_MAX_LAYERS                     0x8281
+#define GL_MAX_COMBINED_DIMENSIONS        0x8282
+#define GL_COLOR_COMPONENTS               0x8283
+#define GL_DEPTH_COMPONENTS               0x8284
+#define GL_STENCIL_COMPONENTS             0x8285
+#define GL_COLOR_RENDERABLE               0x8286
+#define GL_DEPTH_RENDERABLE               0x8287
+#define GL_STENCIL_RENDERABLE             0x8288
+#define GL_FRAMEBUFFER_RENDERABLE         0x8289
+#define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A
+#define GL_FRAMEBUFFER_BLEND              0x828B
+#define GL_READ_PIXELS                    0x828C
+#define GL_READ_PIXELS_FORMAT             0x828D
+#define GL_READ_PIXELS_TYPE               0x828E
+#define GL_TEXTURE_IMAGE_FORMAT           0x828F
+#define GL_TEXTURE_IMAGE_TYPE             0x8290
+#define GL_GET_TEXTURE_IMAGE_FORMAT       0x8291
+#define GL_GET_TEXTURE_IMAGE_TYPE         0x8292
+#define GL_MIPMAP                         0x8293
+#define GL_MANUAL_GENERATE_MIPMAP         0x8294
+#define GL_AUTO_GENERATE_MIPMAP           0x8295
+#define GL_COLOR_ENCODING                 0x8296
+#define GL_SRGB_READ                      0x8297
+#define GL_SRGB_WRITE                     0x8298
+#define GL_FILTER                         0x829A
+#define GL_VERTEX_TEXTURE                 0x829B
+#define GL_TESS_CONTROL_TEXTURE           0x829C
+#define GL_TESS_EVALUATION_TEXTURE        0x829D
+#define GL_GEOMETRY_TEXTURE               0x829E
+#define GL_FRAGMENT_TEXTURE               0x829F
+#define GL_COMPUTE_TEXTURE                0x82A0
+#define GL_TEXTURE_SHADOW                 0x82A1
+#define GL_TEXTURE_GATHER                 0x82A2
+#define GL_TEXTURE_GATHER_SHADOW          0x82A3
+#define GL_SHADER_IMAGE_LOAD              0x82A4
+#define GL_SHADER_IMAGE_STORE             0x82A5
+#define GL_SHADER_IMAGE_ATOMIC            0x82A6
+#define GL_IMAGE_TEXEL_SIZE               0x82A7
+#define GL_IMAGE_COMPATIBILITY_CLASS      0x82A8
+#define GL_IMAGE_PIXEL_FORMAT             0x82A9
+#define GL_IMAGE_PIXEL_TYPE               0x82AA
+#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC
+#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD
+#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE
+#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF
+#define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1
+#define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2
+#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE  0x82B3
+#define GL_CLEAR_BUFFER                   0x82B4
+#define GL_TEXTURE_VIEW                   0x82B5
+#define GL_VIEW_COMPATIBILITY_CLASS       0x82B6
+#define GL_FULL_SUPPORT                   0x82B7
+#define GL_CAVEAT_SUPPORT                 0x82B8
+#define GL_IMAGE_CLASS_4_X_32             0x82B9
+#define GL_IMAGE_CLASS_2_X_32             0x82BA
+#define GL_IMAGE_CLASS_1_X_32             0x82BB
+#define GL_IMAGE_CLASS_4_X_16             0x82BC
+#define GL_IMAGE_CLASS_2_X_16             0x82BD
+#define GL_IMAGE_CLASS_1_X_16             0x82BE
+#define GL_IMAGE_CLASS_4_X_8              0x82BF
+#define GL_IMAGE_CLASS_2_X_8              0x82C0
+#define GL_IMAGE_CLASS_1_X_8              0x82C1
+#define GL_IMAGE_CLASS_11_11_10           0x82C2
+#define GL_IMAGE_CLASS_10_10_10_2         0x82C3
+#define GL_VIEW_CLASS_128_BITS            0x82C4
+#define GL_VIEW_CLASS_96_BITS             0x82C5
+#define GL_VIEW_CLASS_64_BITS             0x82C6
+#define GL_VIEW_CLASS_48_BITS             0x82C7
+#define GL_VIEW_CLASS_32_BITS             0x82C8
+#define GL_VIEW_CLASS_24_BITS             0x82C9
+#define GL_VIEW_CLASS_16_BITS             0x82CA
+#define GL_VIEW_CLASS_8_BITS              0x82CB
+#define GL_VIEW_CLASS_S3TC_DXT1_RGB       0x82CC
+#define GL_VIEW_CLASS_S3TC_DXT1_RGBA      0x82CD
+#define GL_VIEW_CLASS_S3TC_DXT3_RGBA      0x82CE
+#define GL_VIEW_CLASS_S3TC_DXT5_RGBA      0x82CF
+#define GL_VIEW_CLASS_RGTC1_RED           0x82D0
+#define GL_VIEW_CLASS_RGTC2_RG            0x82D1
+#define GL_VIEW_CLASS_BPTC_UNORM          0x82D2
+#define GL_VIEW_CLASS_BPTC_FLOAT          0x82D3
+#define GL_UNIFORM                        0x92E1
+#define GL_UNIFORM_BLOCK                  0x92E2
+#define GL_PROGRAM_INPUT                  0x92E3
+#define GL_PROGRAM_OUTPUT                 0x92E4
+#define GL_BUFFER_VARIABLE                0x92E5
+#define GL_SHADER_STORAGE_BLOCK           0x92E6
+#define GL_VERTEX_SUBROUTINE              0x92E8
+#define GL_TESS_CONTROL_SUBROUTINE        0x92E9
+#define GL_TESS_EVALUATION_SUBROUTINE     0x92EA
+#define GL_GEOMETRY_SUBROUTINE            0x92EB
+#define GL_FRAGMENT_SUBROUTINE            0x92EC
+#define GL_COMPUTE_SUBROUTINE             0x92ED
+#define GL_VERTEX_SUBROUTINE_UNIFORM      0x92EE
+#define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF
+#define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0
+#define GL_GEOMETRY_SUBROUTINE_UNIFORM    0x92F1
+#define GL_FRAGMENT_SUBROUTINE_UNIFORM    0x92F2
+#define GL_COMPUTE_SUBROUTINE_UNIFORM     0x92F3
+#define GL_TRANSFORM_FEEDBACK_VARYING     0x92F4
+#define GL_ACTIVE_RESOURCES               0x92F5
+#define GL_MAX_NAME_LENGTH                0x92F6
+#define GL_MAX_NUM_ACTIVE_VARIABLES       0x92F7
+#define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8
+#define GL_NAME_LENGTH                    0x92F9
+#define GL_TYPE                           0x92FA
+#define GL_ARRAY_SIZE                     0x92FB
+#define GL_OFFSET                         0x92FC
+#define GL_BLOCK_INDEX                    0x92FD
+#define GL_ARRAY_STRIDE                   0x92FE
+#define GL_MATRIX_STRIDE                  0x92FF
+#define GL_IS_ROW_MAJOR                   0x9300
+#define GL_ATOMIC_COUNTER_BUFFER_INDEX    0x9301
+#define GL_BUFFER_BINDING                 0x9302
+#define GL_BUFFER_DATA_SIZE               0x9303
+#define GL_NUM_ACTIVE_VARIABLES           0x9304
+#define GL_ACTIVE_VARIABLES               0x9305
+#define GL_REFERENCED_BY_VERTEX_SHADER    0x9306
+#define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307
+#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308
+#define GL_REFERENCED_BY_GEOMETRY_SHADER  0x9309
+#define GL_REFERENCED_BY_FRAGMENT_SHADER  0x930A
+#define GL_REFERENCED_BY_COMPUTE_SHADER   0x930B
+#define GL_TOP_LEVEL_ARRAY_SIZE           0x930C
+#define GL_TOP_LEVEL_ARRAY_STRIDE         0x930D
+#define GL_LOCATION                       0x930E
+#define GL_LOCATION_INDEX                 0x930F
+#define GL_IS_PER_PATCH                   0x92E7
+#define GL_SHADER_STORAGE_BUFFER          0x90D2
+#define GL_SHADER_STORAGE_BUFFER_BINDING  0x90D3
+#define GL_SHADER_STORAGE_BUFFER_START    0x90D4
+#define GL_SHADER_STORAGE_BUFFER_SIZE     0x90D5
+#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6
+#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7
+#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8
+#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9
+#define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA
+#define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB
+#define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC
+#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD
+#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE  0x90DE
+#define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF
+#define GL_SHADER_STORAGE_BARRIER_BIT     0x00002000
+#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39
+#define GL_DEPTH_STENCIL_TEXTURE_MODE     0x90EA
+#define GL_TEXTURE_BUFFER_OFFSET          0x919D
+#define GL_TEXTURE_BUFFER_SIZE            0x919E
+#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F
+#define GL_TEXTURE_VIEW_MIN_LEVEL         0x82DB
+#define GL_TEXTURE_VIEW_NUM_LEVELS        0x82DC
+#define GL_TEXTURE_VIEW_MIN_LAYER         0x82DD
+#define GL_TEXTURE_VIEW_NUM_LAYERS        0x82DE
+#define GL_TEXTURE_IMMUTABLE_LEVELS       0x82DF
+#define GL_VERTEX_ATTRIB_BINDING          0x82D4
+#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET  0x82D5
+#define GL_VERTEX_BINDING_DIVISOR         0x82D6
+#define GL_VERTEX_BINDING_OFFSET          0x82D7
+#define GL_VERTEX_BINDING_STRIDE          0x82D8
+#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9
+#define GL_MAX_VERTEX_ATTRIB_BINDINGS     0x82DA
+#define GL_VERTEX_BINDING_BUFFER          0x8F4F
+#define GL_DISPLAY_LIST                   0x82E7
+typedef void (APIENTRYP PFNGLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP PFNGLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);
+typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect);
+typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params);
+typedef void (APIENTRYP PFNGLINVALIDATETEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (APIENTRYP PFNGLINVALIDATETEXIMAGEPROC) (GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLINVALIDATEBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length);
+typedef void (APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+typedef void (APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);
+typedef void (APIENTRYP PFNGLGETPROGRAMINTERFACEIVPROC) (GLuint program, GLenum programInterface, GLenum pname, GLint *params);
+typedef GLuint (APIENTRYP PFNGLGETPROGRAMRESOURCEINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);
+typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params);
+typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name);
+typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name);
+typedef void (APIENTRYP PFNGLSHADERSTORAGEBLOCKBINDINGPROC) (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
+typedef void (APIENTRYP PFNGLTEXBUFFERRANGEPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+typedef void (APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+typedef void (APIENTRYP PFNGLTEXTUREVIEWPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
+typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex);
+typedef void (APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor);
+typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
+typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam);
+typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
+typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);
+typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC) (void);
+typedef void (APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
+typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
+typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label);
+typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glClearBufferData (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data);
+GLAPI void APIENTRY glClearBufferSubData (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
+GLAPI void APIENTRY glDispatchCompute (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);
+GLAPI void APIENTRY glDispatchComputeIndirect (GLintptr indirect);
+GLAPI void APIENTRY glCopyImageSubData (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
+GLAPI void APIENTRY glFramebufferParameteri (GLenum target, GLenum pname, GLint param);
+GLAPI void APIENTRY glGetFramebufferParameteriv (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetInternalformati64v (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params);
+GLAPI void APIENTRY glInvalidateTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth);
+GLAPI void APIENTRY glInvalidateTexImage (GLuint texture, GLint level);
+GLAPI void APIENTRY glInvalidateBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr length);
+GLAPI void APIENTRY glInvalidateBufferData (GLuint buffer);
+GLAPI void APIENTRY glInvalidateFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+GLAPI void APIENTRY glInvalidateSubFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glMultiDrawArraysIndirect (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);
+GLAPI void APIENTRY glMultiDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);
+GLAPI void APIENTRY glGetProgramInterfaceiv (GLuint program, GLenum programInterface, GLenum pname, GLint *params);
+GLAPI GLuint APIENTRY glGetProgramResourceIndex (GLuint program, GLenum programInterface, const GLchar *name);
+GLAPI void APIENTRY glGetProgramResourceName (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);
+GLAPI void APIENTRY glGetProgramResourceiv (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params);
+GLAPI GLint APIENTRY glGetProgramResourceLocation (GLuint program, GLenum programInterface, const GLchar *name);
+GLAPI GLint APIENTRY glGetProgramResourceLocationIndex (GLuint program, GLenum programInterface, const GLchar *name);
+GLAPI void APIENTRY glShaderStorageBlockBinding (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
+GLAPI void APIENTRY glTexBufferRange (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
+GLAPI void APIENTRY glTexStorage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+GLAPI void APIENTRY glTexStorage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+GLAPI void APIENTRY glTextureView (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
+GLAPI void APIENTRY glBindVertexBuffer (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
+GLAPI void APIENTRY glVertexAttribFormat (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
+GLAPI void APIENTRY glVertexAttribIFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+GLAPI void APIENTRY glVertexAttribLFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+GLAPI void APIENTRY glVertexAttribBinding (GLuint attribindex, GLuint bindingindex);
+GLAPI void APIENTRY glVertexBindingDivisor (GLuint bindingindex, GLuint divisor);
+GLAPI void APIENTRY glDebugMessageControl (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+GLAPI void APIENTRY glDebugMessageInsert (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
+GLAPI void APIENTRY glDebugMessageCallback (GLDEBUGPROC callback, const void *userParam);
+GLAPI GLuint APIENTRY glGetDebugMessageLog (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
+GLAPI void APIENTRY glPushDebugGroup (GLenum source, GLuint id, GLsizei length, const GLchar *message);
+GLAPI void APIENTRY glPopDebugGroup (void);
+GLAPI void APIENTRY glObjectLabel (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
+GLAPI void APIENTRY glGetObjectLabel (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
+GLAPI void APIENTRY glObjectPtrLabel (const void *ptr, GLsizei length, const GLchar *label);
+GLAPI void APIENTRY glGetObjectPtrLabel (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
+#endif
+#endif /* GL_VERSION_4_3 */
+
+#ifndef GL_VERSION_4_4
+#define GL_VERSION_4_4 1
+#define GL_MAX_VERTEX_ATTRIB_STRIDE       0x82E5
+#define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221
+#define GL_TEXTURE_BUFFER_BINDING         0x8C2A
+#define GL_MAP_PERSISTENT_BIT             0x0040
+#define GL_MAP_COHERENT_BIT               0x0080
+#define GL_DYNAMIC_STORAGE_BIT            0x0100
+#define GL_CLIENT_STORAGE_BIT             0x0200
+#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000
+#define GL_BUFFER_IMMUTABLE_STORAGE       0x821F
+#define GL_BUFFER_STORAGE_FLAGS           0x8220
+#define GL_CLEAR_TEXTURE                  0x9365
+#define GL_LOCATION_COMPONENT             0x934A
+#define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B
+#define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C
+#define GL_QUERY_BUFFER                   0x9192
+#define GL_QUERY_BUFFER_BARRIER_BIT       0x00008000
+#define GL_QUERY_BUFFER_BINDING           0x9193
+#define GL_QUERY_RESULT_NO_WAIT           0x9194
+#define GL_MIRROR_CLAMP_TO_EDGE           0x8743
+typedef void (APIENTRYP PFNGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
+typedef void (APIENTRYP PFNGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP PFNGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP PFNGLBINDBUFFERSBASEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers);
+typedef void (APIENTRYP PFNGLBINDBUFFERSRANGEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes);
+typedef void (APIENTRYP PFNGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
+typedef void (APIENTRYP PFNGLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint *samplers);
+typedef void (APIENTRYP PFNGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
+typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERSPROC) (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBufferStorage (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
+GLAPI void APIENTRY glClearTexImage (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
+GLAPI void APIENTRY glClearTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
+GLAPI void APIENTRY glBindBuffersBase (GLenum target, GLuint first, GLsizei count, const GLuint *buffers);
+GLAPI void APIENTRY glBindBuffersRange (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes);
+GLAPI void APIENTRY glBindTextures (GLuint first, GLsizei count, const GLuint *textures);
+GLAPI void APIENTRY glBindSamplers (GLuint first, GLsizei count, const GLuint *samplers);
+GLAPI void APIENTRY glBindImageTextures (GLuint first, GLsizei count, const GLuint *textures);
+GLAPI void APIENTRY glBindVertexBuffers (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides);
+#endif
+#endif /* GL_VERSION_4_4 */
+
+#ifndef GL_VERSION_4_5
+#define GL_VERSION_4_5 1
+#define GL_CONTEXT_LOST                   0x0507
+#define GL_NEGATIVE_ONE_TO_ONE            0x935E
+#define GL_ZERO_TO_ONE                    0x935F
+#define GL_CLIP_ORIGIN                    0x935C
+#define GL_CLIP_DEPTH_MODE                0x935D
+#define GL_QUERY_WAIT_INVERTED            0x8E17
+#define GL_QUERY_NO_WAIT_INVERTED         0x8E18
+#define GL_QUERY_BY_REGION_WAIT_INVERTED  0x8E19
+#define GL_QUERY_BY_REGION_NO_WAIT_INVERTED 0x8E1A
+#define GL_MAX_CULL_DISTANCES             0x82F9
+#define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES 0x82FA
+#define GL_TEXTURE_TARGET                 0x1006
+#define GL_QUERY_TARGET                   0x82EA
+#define GL_GUILTY_CONTEXT_RESET           0x8253
+#define GL_INNOCENT_CONTEXT_RESET         0x8254
+#define GL_UNKNOWN_CONTEXT_RESET          0x8255
+#define GL_RESET_NOTIFICATION_STRATEGY    0x8256
+#define GL_LOSE_CONTEXT_ON_RESET          0x8252
+#define GL_NO_RESET_NOTIFICATION          0x8261
+#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT 0x00000004
+#define GL_CONTEXT_RELEASE_BEHAVIOR       0x82FB
+#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC
+typedef void (APIENTRYP PFNGLCLIPCONTROLPROC) (GLenum origin, GLenum depth);
+typedef void (APIENTRYP PFNGLCREATETRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC) (GLuint xfb, GLuint index, GLuint buffer);
+typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC) (GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKIVPROC) (GLuint xfb, GLenum pname, GLint *param);
+typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint *param);
+typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI64_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint64 *param);
+typedef void (APIENTRYP PFNGLCREATEBUFFERSPROC) (GLsizei n, GLuint *buffers);
+typedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags);
+typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage);
+typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);
+typedef void (APIENTRYP PFNGLCOPYNAMEDBUFFERSUBDATAPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
+typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERPROC) (GLuint buffer, GLenum access);
+typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERRANGEPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);
+typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFERPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length);
+typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVPROC) (GLuint buffer, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERI64VPROC) (GLuint buffer, GLenum pname, GLint64 *params);
+typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVPROC) (GLuint buffer, GLenum pname, void **params);
+typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data);
+typedef void (APIENTRYP PFNGLCREATEFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC) (GLuint framebuffer, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC) (GLuint framebuffer, GLenum buf);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC) (GLuint framebuffer, GLenum src);
+typedef void (APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC) (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments);
+typedef void (APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC) (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint *value);
+typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint *value);
+typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value);
+typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFIPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
+typedef void (APIENTRYP PFNGLBLITNAMEDFRAMEBUFFERPROC) (GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC) (GLuint framebuffer, GLenum target);
+typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC) (GLuint framebuffer, GLenum pname, GLint *param);
+typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLCREATERENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers);
+typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC) (GLuint renderbuffer, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLCREATETEXTURESPROC) (GLenum target, GLsizei n, GLuint *textures);
+typedef void (APIENTRYP PFNGLTEXTUREBUFFERPROC) (GLuint texture, GLenum internalformat, GLuint buffer);
+typedef void (APIENTRYP PFNGLTEXTUREBUFFERRANGEPROC) (GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC) (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC) (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFPROC) (GLuint texture, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVPROC) (GLuint texture, GLenum pname, const GLfloat *param);
+typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIPROC) (GLuint texture, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVPROC) (GLuint texture, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVPROC) (GLuint texture, GLenum pname, const GLuint *params);
+typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVPROC) (GLuint texture, GLenum pname, const GLint *param);
+typedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPPROC) (GLuint texture);
+typedef void (APIENTRYP PFNGLBINDTEXTUREUNITPROC) (GLuint unit, GLuint texture);
+typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC) (GLuint texture, GLint level, GLsizei bufSize, void *pixels);
+typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVPROC) (GLuint texture, GLint level, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVPROC) (GLuint texture, GLint level, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVPROC) (GLuint texture, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVPROC) (GLuint texture, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVPROC) (GLuint texture, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVPROC) (GLuint texture, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLCREATEVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBPROC) (GLuint vaobj, GLuint index);
+typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBPROC) (GLuint vaobj, GLuint index);
+typedef void (APIENTRYP PFNGLVERTEXARRAYELEMENTBUFFERPROC) (GLuint vaobj, GLuint buffer);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERSPROC) (GLuint vaobj, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides);
+typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBBINDINGPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex);
+typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBIFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBLFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYBINDINGDIVISORPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor);
+typedef void (APIENTRYP PFNGLGETVERTEXARRAYIVPROC) (GLuint vaobj, GLenum pname, GLint *param);
+typedef void (APIENTRYP PFNGLGETVERTEXARRAYINDEXEDIVPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param);
+typedef void (APIENTRYP PFNGLGETVERTEXARRAYINDEXED64IVPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint64 *param);
+typedef void (APIENTRYP PFNGLCREATESAMPLERSPROC) (GLsizei n, GLuint *samplers);
+typedef void (APIENTRYP PFNGLCREATEPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines);
+typedef void (APIENTRYP PFNGLCREATEQUERIESPROC) (GLenum target, GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTI64VPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset);
+typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTIVPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset);
+typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTUI64VPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset);
+typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTUIVPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset);
+typedef void (APIENTRYP PFNGLMEMORYBARRIERBYREGIONPROC) (GLbitfield barriers);
+typedef void (APIENTRYP PFNGLGETTEXTURESUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void *pixels);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void *pixels);
+typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSPROC) (void);
+typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint lod, GLsizei bufSize, void *pixels);
+typedef void (APIENTRYP PFNGLGETNTEXIMAGEPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels);
+typedef void (APIENTRYP PFNGLGETNUNIFORMDVPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETNUNIFORMFVPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETNUNIFORMIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+typedef void (APIENTRYP PFNGLGETNUNIFORMUIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params);
+typedef void (APIENTRYP PFNGLREADNPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+typedef void (APIENTRYP PFNGLGETNMAPDVPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v);
+typedef void (APIENTRYP PFNGLGETNMAPFVPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v);
+typedef void (APIENTRYP PFNGLGETNMAPIVPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v);
+typedef void (APIENTRYP PFNGLGETNPIXELMAPFVPROC) (GLenum map, GLsizei bufSize, GLfloat *values);
+typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVPROC) (GLenum map, GLsizei bufSize, GLuint *values);
+typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVPROC) (GLenum map, GLsizei bufSize, GLushort *values);
+typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEPROC) (GLsizei bufSize, GLubyte *pattern);
+typedef void (APIENTRYP PFNGLGETNCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table);
+typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image);
+typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span);
+typedef void (APIENTRYP PFNGLGETNHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
+typedef void (APIENTRYP PFNGLGETNMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
+typedef void (APIENTRYP PFNGLTEXTUREBARRIERPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glClipControl (GLenum origin, GLenum depth);
+GLAPI void APIENTRY glCreateTransformFeedbacks (GLsizei n, GLuint *ids);
+GLAPI void APIENTRY glTransformFeedbackBufferBase (GLuint xfb, GLuint index, GLuint buffer);
+GLAPI void APIENTRY glTransformFeedbackBufferRange (GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+GLAPI void APIENTRY glGetTransformFeedbackiv (GLuint xfb, GLenum pname, GLint *param);
+GLAPI void APIENTRY glGetTransformFeedbacki_v (GLuint xfb, GLenum pname, GLuint index, GLint *param);
+GLAPI void APIENTRY glGetTransformFeedbacki64_v (GLuint xfb, GLenum pname, GLuint index, GLint64 *param);
+GLAPI void APIENTRY glCreateBuffers (GLsizei n, GLuint *buffers);
+GLAPI void APIENTRY glNamedBufferStorage (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags);
+GLAPI void APIENTRY glNamedBufferData (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage);
+GLAPI void APIENTRY glNamedBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);
+GLAPI void APIENTRY glCopyNamedBufferSubData (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+GLAPI void APIENTRY glClearNamedBufferData (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data);
+GLAPI void APIENTRY glClearNamedBufferSubData (GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
+GLAPI void *APIENTRY glMapNamedBuffer (GLuint buffer, GLenum access);
+GLAPI void *APIENTRY glMapNamedBufferRange (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);
+GLAPI GLboolean APIENTRY glUnmapNamedBuffer (GLuint buffer);
+GLAPI void APIENTRY glFlushMappedNamedBufferRange (GLuint buffer, GLintptr offset, GLsizeiptr length);
+GLAPI void APIENTRY glGetNamedBufferParameteriv (GLuint buffer, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetNamedBufferParameteri64v (GLuint buffer, GLenum pname, GLint64 *params);
+GLAPI void APIENTRY glGetNamedBufferPointerv (GLuint buffer, GLenum pname, void **params);
+GLAPI void APIENTRY glGetNamedBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data);
+GLAPI void APIENTRY glCreateFramebuffers (GLsizei n, GLuint *framebuffers);
+GLAPI void APIENTRY glNamedFramebufferRenderbuffer (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GLAPI void APIENTRY glNamedFramebufferParameteri (GLuint framebuffer, GLenum pname, GLint param);
+GLAPI void APIENTRY glNamedFramebufferTexture (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level);
+GLAPI void APIENTRY glNamedFramebufferTextureLayer (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer);
+GLAPI void APIENTRY glNamedFramebufferDrawBuffer (GLuint framebuffer, GLenum buf);
+GLAPI void APIENTRY glNamedFramebufferDrawBuffers (GLuint framebuffer, GLsizei n, const GLenum *bufs);
+GLAPI void APIENTRY glNamedFramebufferReadBuffer (GLuint framebuffer, GLenum src);
+GLAPI void APIENTRY glInvalidateNamedFramebufferData (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments);
+GLAPI void APIENTRY glInvalidateNamedFramebufferSubData (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glClearNamedFramebufferiv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint *value);
+GLAPI void APIENTRY glClearNamedFramebufferuiv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint *value);
+GLAPI void APIENTRY glClearNamedFramebufferfv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value);
+GLAPI void APIENTRY glClearNamedFramebufferfi (GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
+GLAPI void APIENTRY glBlitNamedFramebuffer (GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+GLAPI GLenum APIENTRY glCheckNamedFramebufferStatus (GLuint framebuffer, GLenum target);
+GLAPI void APIENTRY glGetNamedFramebufferParameteriv (GLuint framebuffer, GLenum pname, GLint *param);
+GLAPI void APIENTRY glGetNamedFramebufferAttachmentParameteriv (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params);
+GLAPI void APIENTRY glCreateRenderbuffers (GLsizei n, GLuint *renderbuffers);
+GLAPI void APIENTRY glNamedRenderbufferStorage (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glNamedRenderbufferStorageMultisample (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glGetNamedRenderbufferParameteriv (GLuint renderbuffer, GLenum pname, GLint *params);
+GLAPI void APIENTRY glCreateTextures (GLenum target, GLsizei n, GLuint *textures);
+GLAPI void APIENTRY glTextureBuffer (GLuint texture, GLenum internalformat, GLuint buffer);
+GLAPI void APIENTRY glTextureBufferRange (GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
+GLAPI void APIENTRY glTextureStorage1D (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width);
+GLAPI void APIENTRY glTextureStorage2D (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glTextureStorage3D (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+GLAPI void APIENTRY glTextureStorage2DMultisample (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+GLAPI void APIENTRY glTextureStorage3DMultisample (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+GLAPI void APIENTRY glTextureSubImage1D (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glTextureSubImage2D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glTextureSubImage3D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glCompressedTextureSubImage1D (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTextureSubImage2D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTextureSubImage3D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCopyTextureSubImage1D (GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+GLAPI void APIENTRY glCopyTextureSubImage2D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glCopyTextureSubImage3D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glTextureParameterf (GLuint texture, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glTextureParameterfv (GLuint texture, GLenum pname, const GLfloat *param);
+GLAPI void APIENTRY glTextureParameteri (GLuint texture, GLenum pname, GLint param);
+GLAPI void APIENTRY glTextureParameterIiv (GLuint texture, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glTextureParameterIuiv (GLuint texture, GLenum pname, const GLuint *params);
+GLAPI void APIENTRY glTextureParameteriv (GLuint texture, GLenum pname, const GLint *param);
+GLAPI void APIENTRY glGenerateTextureMipmap (GLuint texture);
+GLAPI void APIENTRY glBindTextureUnit (GLuint unit, GLuint texture);
+GLAPI void APIENTRY glGetTextureImage (GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels);
+GLAPI void APIENTRY glGetCompressedTextureImage (GLuint texture, GLint level, GLsizei bufSize, void *pixels);
+GLAPI void APIENTRY glGetTextureLevelParameterfv (GLuint texture, GLint level, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetTextureLevelParameteriv (GLuint texture, GLint level, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetTextureParameterfv (GLuint texture, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetTextureParameterIiv (GLuint texture, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetTextureParameterIuiv (GLuint texture, GLenum pname, GLuint *params);
+GLAPI void APIENTRY glGetTextureParameteriv (GLuint texture, GLenum pname, GLint *params);
+GLAPI void APIENTRY glCreateVertexArrays (GLsizei n, GLuint *arrays);
+GLAPI void APIENTRY glDisableVertexArrayAttrib (GLuint vaobj, GLuint index);
+GLAPI void APIENTRY glEnableVertexArrayAttrib (GLuint vaobj, GLuint index);
+GLAPI void APIENTRY glVertexArrayElementBuffer (GLuint vaobj, GLuint buffer);
+GLAPI void APIENTRY glVertexArrayVertexBuffer (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
+GLAPI void APIENTRY glVertexArrayVertexBuffers (GLuint vaobj, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides);
+GLAPI void APIENTRY glVertexArrayAttribBinding (GLuint vaobj, GLuint attribindex, GLuint bindingindex);
+GLAPI void APIENTRY glVertexArrayAttribFormat (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
+GLAPI void APIENTRY glVertexArrayAttribIFormat (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+GLAPI void APIENTRY glVertexArrayAttribLFormat (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+GLAPI void APIENTRY glVertexArrayBindingDivisor (GLuint vaobj, GLuint bindingindex, GLuint divisor);
+GLAPI void APIENTRY glGetVertexArrayiv (GLuint vaobj, GLenum pname, GLint *param);
+GLAPI void APIENTRY glGetVertexArrayIndexediv (GLuint vaobj, GLuint index, GLenum pname, GLint *param);
+GLAPI void APIENTRY glGetVertexArrayIndexed64iv (GLuint vaobj, GLuint index, GLenum pname, GLint64 *param);
+GLAPI void APIENTRY glCreateSamplers (GLsizei n, GLuint *samplers);
+GLAPI void APIENTRY glCreateProgramPipelines (GLsizei n, GLuint *pipelines);
+GLAPI void APIENTRY glCreateQueries (GLenum target, GLsizei n, GLuint *ids);
+GLAPI void APIENTRY glGetQueryBufferObjecti64v (GLuint id, GLuint buffer, GLenum pname, GLintptr offset);
+GLAPI void APIENTRY glGetQueryBufferObjectiv (GLuint id, GLuint buffer, GLenum pname, GLintptr offset);
+GLAPI void APIENTRY glGetQueryBufferObjectui64v (GLuint id, GLuint buffer, GLenum pname, GLintptr offset);
+GLAPI void APIENTRY glGetQueryBufferObjectuiv (GLuint id, GLuint buffer, GLenum pname, GLintptr offset);
+GLAPI void APIENTRY glMemoryBarrierByRegion (GLbitfield barriers);
+GLAPI void APIENTRY glGetTextureSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void *pixels);
+GLAPI void APIENTRY glGetCompressedTextureSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void *pixels);
+GLAPI GLenum APIENTRY glGetGraphicsResetStatus (void);
+GLAPI void APIENTRY glGetnCompressedTexImage (GLenum target, GLint lod, GLsizei bufSize, void *pixels);
+GLAPI void APIENTRY glGetnTexImage (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels);
+GLAPI void APIENTRY glGetnUniformdv (GLuint program, GLint location, GLsizei bufSize, GLdouble *params);
+GLAPI void APIENTRY glGetnUniformfv (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
+GLAPI void APIENTRY glGetnUniformiv (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+GLAPI void APIENTRY glGetnUniformuiv (GLuint program, GLint location, GLsizei bufSize, GLuint *params);
+GLAPI void APIENTRY glReadnPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+GLAPI void APIENTRY glGetnMapdv (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v);
+GLAPI void APIENTRY glGetnMapfv (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v);
+GLAPI void APIENTRY glGetnMapiv (GLenum target, GLenum query, GLsizei bufSize, GLint *v);
+GLAPI void APIENTRY glGetnPixelMapfv (GLenum map, GLsizei bufSize, GLfloat *values);
+GLAPI void APIENTRY glGetnPixelMapuiv (GLenum map, GLsizei bufSize, GLuint *values);
+GLAPI void APIENTRY glGetnPixelMapusv (GLenum map, GLsizei bufSize, GLushort *values);
+GLAPI void APIENTRY glGetnPolygonStipple (GLsizei bufSize, GLubyte *pattern);
+GLAPI void APIENTRY glGetnColorTable (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table);
+GLAPI void APIENTRY glGetnConvolutionFilter (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image);
+GLAPI void APIENTRY glGetnSeparableFilter (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span);
+GLAPI void APIENTRY glGetnHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
+GLAPI void APIENTRY glGetnMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
+GLAPI void APIENTRY glTextureBarrier (void);
+#endif
+#endif /* GL_VERSION_4_5 */
+
+#ifndef GL_VERSION_4_6
+#define GL_VERSION_4_6 1
+#define GL_SHADER_BINARY_FORMAT_SPIR_V    0x9551
+#define GL_SPIR_V_BINARY                  0x9552
+#define GL_PARAMETER_BUFFER               0x80EE
+#define GL_PARAMETER_BUFFER_BINDING       0x80EF
+#define GL_CONTEXT_FLAG_NO_ERROR_BIT      0x00000008
+#define GL_VERTICES_SUBMITTED             0x82EE
+#define GL_PRIMITIVES_SUBMITTED           0x82EF
+#define GL_VERTEX_SHADER_INVOCATIONS      0x82F0
+#define GL_TESS_CONTROL_SHADER_PATCHES    0x82F1
+#define GL_TESS_EVALUATION_SHADER_INVOCATIONS 0x82F2
+#define GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED 0x82F3
+#define GL_FRAGMENT_SHADER_INVOCATIONS    0x82F4
+#define GL_COMPUTE_SHADER_INVOCATIONS     0x82F5
+#define GL_CLIPPING_INPUT_PRIMITIVES      0x82F6
+#define GL_CLIPPING_OUTPUT_PRIMITIVES     0x82F7
+#define GL_POLYGON_OFFSET_CLAMP           0x8E1B
+#define GL_SPIR_V_EXTENSIONS              0x9553
+#define GL_NUM_SPIR_V_EXTENSIONS          0x9554
+#define GL_TEXTURE_MAX_ANISOTROPY         0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY     0x84FF
+#define GL_TRANSFORM_FEEDBACK_OVERFLOW    0x82EC
+#define GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW 0x82ED
+typedef void (APIENTRYP PFNGLSPECIALIZESHADERPROC) (GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue);
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC) (GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC) (GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
+typedef void (APIENTRYP PFNGLPOLYGONOFFSETCLAMPPROC) (GLfloat factor, GLfloat units, GLfloat clamp);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSpecializeShader (GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue);
+GLAPI void APIENTRY glMultiDrawArraysIndirectCount (GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
+GLAPI void APIENTRY glMultiDrawElementsIndirectCount (GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
+GLAPI void APIENTRY glPolygonOffsetClamp (GLfloat factor, GLfloat units, GLfloat clamp);
+#endif
+#endif /* GL_VERSION_4_6 */
+
+#ifndef GL_ARB_ES2_compatibility
+#define GL_ARB_ES2_compatibility 1
+#endif /* GL_ARB_ES2_compatibility */
+
+#ifndef GL_ARB_ES3_1_compatibility
+#define GL_ARB_ES3_1_compatibility 1
+#endif /* GL_ARB_ES3_1_compatibility */
+
+#ifndef GL_ARB_ES3_2_compatibility
+#define GL_ARB_ES3_2_compatibility 1
+#define GL_PRIMITIVE_BOUNDING_BOX_ARB     0x92BE
+#define GL_MULTISAMPLE_LINE_WIDTH_RANGE_ARB 0x9381
+#define GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY_ARB 0x9382
+typedef void (APIENTRYP PFNGLPRIMITIVEBOUNDINGBOXARBPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPrimitiveBoundingBoxARB (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
+#endif
+#endif /* GL_ARB_ES3_2_compatibility */
+
+#ifndef GL_ARB_ES3_compatibility
+#define GL_ARB_ES3_compatibility 1
+#endif /* GL_ARB_ES3_compatibility */
+
+#ifndef GL_ARB_arrays_of_arrays
+#define GL_ARB_arrays_of_arrays 1
+#endif /* GL_ARB_arrays_of_arrays */
+
+#ifndef GL_ARB_base_instance
+#define GL_ARB_base_instance 1
+#endif /* GL_ARB_base_instance */
+
+#ifndef GL_ARB_bindless_texture
+#define GL_ARB_bindless_texture 1
+typedef khronos_uint64_t GLuint64EXT;
+#define GL_UNSIGNED_INT64_ARB             0x140F
+typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLEARBPROC) (GLuint texture);
+typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLEARBPROC) (GLuint texture, GLuint sampler);
+typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle);
+typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC) (GLuint64 handle);
+typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLEARBPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format);
+typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle, GLenum access);
+typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC) (GLuint64 handle);
+typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64ARBPROC) (GLint location, GLuint64 value);
+typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC) (GLuint program, GLint location, GLuint64 value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values);
+typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle);
+typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64ARBPROC) (GLuint index, GLuint64EXT x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VARBPROC) (GLuint index, const GLuint64EXT *v);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VARBPROC) (GLuint index, GLenum pname, GLuint64EXT *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLuint64 APIENTRY glGetTextureHandleARB (GLuint texture);
+GLAPI GLuint64 APIENTRY glGetTextureSamplerHandleARB (GLuint texture, GLuint sampler);
+GLAPI void APIENTRY glMakeTextureHandleResidentARB (GLuint64 handle);
+GLAPI void APIENTRY glMakeTextureHandleNonResidentARB (GLuint64 handle);
+GLAPI GLuint64 APIENTRY glGetImageHandleARB (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format);
+GLAPI void APIENTRY glMakeImageHandleResidentARB (GLuint64 handle, GLenum access);
+GLAPI void APIENTRY glMakeImageHandleNonResidentARB (GLuint64 handle);
+GLAPI void APIENTRY glUniformHandleui64ARB (GLint location, GLuint64 value);
+GLAPI void APIENTRY glUniformHandleui64vARB (GLint location, GLsizei count, const GLuint64 *value);
+GLAPI void APIENTRY glProgramUniformHandleui64ARB (GLuint program, GLint location, GLuint64 value);
+GLAPI void APIENTRY glProgramUniformHandleui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *values);
+GLAPI GLboolean APIENTRY glIsTextureHandleResidentARB (GLuint64 handle);
+GLAPI GLboolean APIENTRY glIsImageHandleResidentARB (GLuint64 handle);
+GLAPI void APIENTRY glVertexAttribL1ui64ARB (GLuint index, GLuint64EXT x);
+GLAPI void APIENTRY glVertexAttribL1ui64vARB (GLuint index, const GLuint64EXT *v);
+GLAPI void APIENTRY glGetVertexAttribLui64vARB (GLuint index, GLenum pname, GLuint64EXT *params);
+#endif
+#endif /* GL_ARB_bindless_texture */
+
+#ifndef GL_ARB_blend_func_extended
+#define GL_ARB_blend_func_extended 1
+#endif /* GL_ARB_blend_func_extended */
+
+#ifndef GL_ARB_buffer_storage
+#define GL_ARB_buffer_storage 1
+#endif /* GL_ARB_buffer_storage */
+
+#ifndef GL_ARB_cl_event
+#define GL_ARB_cl_event 1
+struct _cl_context;
+struct _cl_event;
+#define GL_SYNC_CL_EVENT_ARB              0x8240
+#define GL_SYNC_CL_EVENT_COMPLETE_ARB     0x8241
+typedef GLsync (APIENTRYP PFNGLCREATESYNCFROMCLEVENTARBPROC) (struct _cl_context *context, struct _cl_event *event, GLbitfield flags);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLsync APIENTRY glCreateSyncFromCLeventARB (struct _cl_context *context, struct _cl_event *event, GLbitfield flags);
+#endif
+#endif /* GL_ARB_cl_event */
+
+#ifndef GL_ARB_clear_buffer_object
+#define GL_ARB_clear_buffer_object 1
+#endif /* GL_ARB_clear_buffer_object */
+
+#ifndef GL_ARB_clear_texture
+#define GL_ARB_clear_texture 1
+#endif /* GL_ARB_clear_texture */
+
+#ifndef GL_ARB_clip_control
+#define GL_ARB_clip_control 1
+#endif /* GL_ARB_clip_control */
+
+#ifndef GL_ARB_color_buffer_float
+#define GL_ARB_color_buffer_float 1
+#define GL_RGBA_FLOAT_MODE_ARB            0x8820
+#define GL_CLAMP_VERTEX_COLOR_ARB         0x891A
+#define GL_CLAMP_FRAGMENT_COLOR_ARB       0x891B
+#define GL_CLAMP_READ_COLOR_ARB           0x891C
+#define GL_FIXED_ONLY_ARB                 0x891D
+typedef void (APIENTRYP PFNGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glClampColorARB (GLenum target, GLenum clamp);
+#endif
+#endif /* GL_ARB_color_buffer_float */
+
+#ifndef GL_ARB_compatibility
+#define GL_ARB_compatibility 1
+#endif /* GL_ARB_compatibility */
+
+#ifndef GL_ARB_compressed_texture_pixel_storage
+#define GL_ARB_compressed_texture_pixel_storage 1
+#endif /* GL_ARB_compressed_texture_pixel_storage */
+
+#ifndef GL_ARB_compute_shader
+#define GL_ARB_compute_shader 1
+#endif /* GL_ARB_compute_shader */
+
+#ifndef GL_ARB_compute_variable_group_size
+#define GL_ARB_compute_variable_group_size 1
+#define GL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB 0x9344
+#define GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB 0x90EB
+#define GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB 0x9345
+#define GL_MAX_COMPUTE_FIXED_GROUP_SIZE_ARB 0x91BF
+typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDispatchComputeGroupSizeARB (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z);
+#endif
+#endif /* GL_ARB_compute_variable_group_size */
+
+#ifndef GL_ARB_conditional_render_inverted
+#define GL_ARB_conditional_render_inverted 1
+#endif /* GL_ARB_conditional_render_inverted */
+
+#ifndef GL_ARB_conservative_depth
+#define GL_ARB_conservative_depth 1
+#endif /* GL_ARB_conservative_depth */
+
+#ifndef GL_ARB_copy_buffer
+#define GL_ARB_copy_buffer 1
+#endif /* GL_ARB_copy_buffer */
+
+#ifndef GL_ARB_copy_image
+#define GL_ARB_copy_image 1
+#endif /* GL_ARB_copy_image */
+
+#ifndef GL_ARB_cull_distance
+#define GL_ARB_cull_distance 1
+#endif /* GL_ARB_cull_distance */
+
+#ifndef GL_ARB_debug_output
+#define GL_ARB_debug_output 1
+typedef void (APIENTRY  *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB   0x8242
+#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243
+#define GL_DEBUG_CALLBACK_FUNCTION_ARB    0x8244
+#define GL_DEBUG_CALLBACK_USER_PARAM_ARB  0x8245
+#define GL_DEBUG_SOURCE_API_ARB           0x8246
+#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247
+#define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248
+#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB   0x8249
+#define GL_DEBUG_SOURCE_APPLICATION_ARB   0x824A
+#define GL_DEBUG_SOURCE_OTHER_ARB         0x824B
+#define GL_DEBUG_TYPE_ERROR_ARB           0x824C
+#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D
+#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E
+#define GL_DEBUG_TYPE_PORTABILITY_ARB     0x824F
+#define GL_DEBUG_TYPE_PERFORMANCE_ARB     0x8250
+#define GL_DEBUG_TYPE_OTHER_ARB           0x8251
+#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB   0x9143
+#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB  0x9144
+#define GL_DEBUG_LOGGED_MESSAGES_ARB      0x9145
+#define GL_DEBUG_SEVERITY_HIGH_ARB        0x9146
+#define GL_DEBUG_SEVERITY_MEDIUM_ARB      0x9147
+#define GL_DEBUG_SEVERITY_LOW_ARB         0x9148
+typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
+typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const void *userParam);
+typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDebugMessageControlARB (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+GLAPI void APIENTRY glDebugMessageInsertARB (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
+GLAPI void APIENTRY glDebugMessageCallbackARB (GLDEBUGPROCARB callback, const void *userParam);
+GLAPI GLuint APIENTRY glGetDebugMessageLogARB (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
+#endif
+#endif /* GL_ARB_debug_output */
+
+#ifndef GL_ARB_depth_buffer_float
+#define GL_ARB_depth_buffer_float 1
+#endif /* GL_ARB_depth_buffer_float */
+
+#ifndef GL_ARB_depth_clamp
+#define GL_ARB_depth_clamp 1
+#endif /* GL_ARB_depth_clamp */
+
+#ifndef GL_ARB_depth_texture
+#define GL_ARB_depth_texture 1
+#define GL_DEPTH_COMPONENT16_ARB          0x81A5
+#define GL_DEPTH_COMPONENT24_ARB          0x81A6
+#define GL_DEPTH_COMPONENT32_ARB          0x81A7
+#define GL_TEXTURE_DEPTH_SIZE_ARB         0x884A
+#define GL_DEPTH_TEXTURE_MODE_ARB         0x884B
+#endif /* GL_ARB_depth_texture */
+
+#ifndef GL_ARB_derivative_control
+#define GL_ARB_derivative_control 1
+#endif /* GL_ARB_derivative_control */
+
+#ifndef GL_ARB_direct_state_access
+#define GL_ARB_direct_state_access 1
+#endif /* GL_ARB_direct_state_access */
+
+#ifndef GL_ARB_draw_buffers
+#define GL_ARB_draw_buffers 1
+#define GL_MAX_DRAW_BUFFERS_ARB           0x8824
+#define GL_DRAW_BUFFER0_ARB               0x8825
+#define GL_DRAW_BUFFER1_ARB               0x8826
+#define GL_DRAW_BUFFER2_ARB               0x8827
+#define GL_DRAW_BUFFER3_ARB               0x8828
+#define GL_DRAW_BUFFER4_ARB               0x8829
+#define GL_DRAW_BUFFER5_ARB               0x882A
+#define GL_DRAW_BUFFER6_ARB               0x882B
+#define GL_DRAW_BUFFER7_ARB               0x882C
+#define GL_DRAW_BUFFER8_ARB               0x882D
+#define GL_DRAW_BUFFER9_ARB               0x882E
+#define GL_DRAW_BUFFER10_ARB              0x882F
+#define GL_DRAW_BUFFER11_ARB              0x8830
+#define GL_DRAW_BUFFER12_ARB              0x8831
+#define GL_DRAW_BUFFER13_ARB              0x8832
+#define GL_DRAW_BUFFER14_ARB              0x8833
+#define GL_DRAW_BUFFER15_ARB              0x8834
+typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawBuffersARB (GLsizei n, const GLenum *bufs);
+#endif
+#endif /* GL_ARB_draw_buffers */
+
+#ifndef GL_ARB_draw_buffers_blend
+#define GL_ARB_draw_buffers_blend 1
+typedef void (APIENTRYP PFNGLBLENDEQUATIONIARBPROC) (GLuint buf, GLenum mode);
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIARBPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+typedef void (APIENTRYP PFNGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLenum dst);
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIARBPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationiARB (GLuint buf, GLenum mode);
+GLAPI void APIENTRY glBlendEquationSeparateiARB (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+GLAPI void APIENTRY glBlendFunciARB (GLuint buf, GLenum src, GLenum dst);
+GLAPI void APIENTRY glBlendFuncSeparateiARB (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+#endif
+#endif /* GL_ARB_draw_buffers_blend */
+
+#ifndef GL_ARB_draw_elements_base_vertex
+#define GL_ARB_draw_elements_base_vertex 1
+#endif /* GL_ARB_draw_elements_base_vertex */
+
+#ifndef GL_ARB_draw_indirect
+#define GL_ARB_draw_indirect 1
+#endif /* GL_ARB_draw_indirect */
+
+#ifndef GL_ARB_draw_instanced
+#define GL_ARB_draw_instanced 1
+typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDARBPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDARBPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawArraysInstancedARB (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+GLAPI void APIENTRY glDrawElementsInstancedARB (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+#endif
+#endif /* GL_ARB_draw_instanced */
+
+#ifndef GL_ARB_enhanced_layouts
+#define GL_ARB_enhanced_layouts 1
+#endif /* GL_ARB_enhanced_layouts */
+
+#ifndef GL_ARB_explicit_attrib_location
+#define GL_ARB_explicit_attrib_location 1
+#endif /* GL_ARB_explicit_attrib_location */
+
+#ifndef GL_ARB_explicit_uniform_location
+#define GL_ARB_explicit_uniform_location 1
+#endif /* GL_ARB_explicit_uniform_location */
+
+#ifndef GL_ARB_fragment_coord_conventions
+#define GL_ARB_fragment_coord_conventions 1
+#endif /* GL_ARB_fragment_coord_conventions */
+
+#ifndef GL_ARB_fragment_layer_viewport
+#define GL_ARB_fragment_layer_viewport 1
+#endif /* GL_ARB_fragment_layer_viewport */
+
+#ifndef GL_ARB_fragment_program
+#define GL_ARB_fragment_program 1
+#define GL_FRAGMENT_PROGRAM_ARB           0x8804
+#define GL_PROGRAM_FORMAT_ASCII_ARB       0x8875
+#define GL_PROGRAM_LENGTH_ARB             0x8627
+#define GL_PROGRAM_FORMAT_ARB             0x8876
+#define GL_PROGRAM_BINDING_ARB            0x8677
+#define GL_PROGRAM_INSTRUCTIONS_ARB       0x88A0
+#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB   0x88A1
+#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2
+#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3
+#define GL_PROGRAM_TEMPORARIES_ARB        0x88A4
+#define GL_MAX_PROGRAM_TEMPORARIES_ARB    0x88A5
+#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6
+#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7
+#define GL_PROGRAM_PARAMETERS_ARB         0x88A8
+#define GL_MAX_PROGRAM_PARAMETERS_ARB     0x88A9
+#define GL_PROGRAM_NATIVE_PARAMETERS_ARB  0x88AA
+#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB
+#define GL_PROGRAM_ATTRIBS_ARB            0x88AC
+#define GL_MAX_PROGRAM_ATTRIBS_ARB        0x88AD
+#define GL_PROGRAM_NATIVE_ATTRIBS_ARB     0x88AE
+#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF
+#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4
+#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5
+#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6
+#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB   0x8805
+#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB   0x8806
+#define GL_PROGRAM_TEX_INDIRECTIONS_ARB   0x8807
+#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808
+#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809
+#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A
+#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B
+#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C
+#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D
+#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E
+#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F
+#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810
+#define GL_PROGRAM_STRING_ARB             0x8628
+#define GL_PROGRAM_ERROR_POSITION_ARB     0x864B
+#define GL_CURRENT_MATRIX_ARB             0x8641
+#define GL_TRANSPOSE_CURRENT_MATRIX_ARB   0x88B7
+#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640
+#define GL_MAX_PROGRAM_MATRICES_ARB       0x862F
+#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E
+#define GL_MAX_TEXTURE_COORDS_ARB         0x8871
+#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB    0x8872
+#define GL_PROGRAM_ERROR_STRING_ARB       0x8874
+#define GL_MATRIX0_ARB                    0x88C0
+#define GL_MATRIX1_ARB                    0x88C1
+#define GL_MATRIX2_ARB                    0x88C2
+#define GL_MATRIX3_ARB                    0x88C3
+#define GL_MATRIX4_ARB                    0x88C4
+#define GL_MATRIX5_ARB                    0x88C5
+#define GL_MATRIX6_ARB                    0x88C6
+#define GL_MATRIX7_ARB                    0x88C7
+#define GL_MATRIX8_ARB                    0x88C8
+#define GL_MATRIX9_ARB                    0x88C9
+#define GL_MATRIX10_ARB                   0x88CA
+#define GL_MATRIX11_ARB                   0x88CB
+#define GL_MATRIX12_ARB                   0x88CC
+#define GL_MATRIX13_ARB                   0x88CD
+#define GL_MATRIX14_ARB                   0x88CE
+#define GL_MATRIX15_ARB                   0x88CF
+#define GL_MATRIX16_ARB                   0x88D0
+#define GL_MATRIX17_ARB                   0x88D1
+#define GL_MATRIX18_ARB                   0x88D2
+#define GL_MATRIX19_ARB                   0x88D3
+#define GL_MATRIX20_ARB                   0x88D4
+#define GL_MATRIX21_ARB                   0x88D5
+#define GL_MATRIX22_ARB                   0x88D6
+#define GL_MATRIX23_ARB                   0x88D7
+#define GL_MATRIX24_ARB                   0x88D8
+#define GL_MATRIX25_ARB                   0x88D9
+#define GL_MATRIX26_ARB                   0x88DA
+#define GL_MATRIX27_ARB                   0x88DB
+#define GL_MATRIX28_ARB                   0x88DC
+#define GL_MATRIX29_ARB                   0x88DD
+#define GL_MATRIX30_ARB                   0x88DE
+#define GL_MATRIX31_ARB                   0x88DF
+typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const void *string);
+typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, void *string);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramStringARB (GLenum target, GLenum format, GLsizei len, const void *string);
+GLAPI void APIENTRY glBindProgramARB (GLenum target, GLuint program);
+GLAPI void APIENTRY glDeleteProgramsARB (GLsizei n, const GLuint *programs);
+GLAPI void APIENTRY glGenProgramsARB (GLsizei n, GLuint *programs);
+GLAPI void APIENTRY glProgramEnvParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glProgramEnvParameter4dvARB (GLenum target, GLuint index, const GLdouble *params);
+GLAPI void APIENTRY glProgramEnvParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glProgramEnvParameter4fvARB (GLenum target, GLuint index, const GLfloat *params);
+GLAPI void APIENTRY glProgramLocalParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glProgramLocalParameter4dvARB (GLenum target, GLuint index, const GLdouble *params);
+GLAPI void APIENTRY glProgramLocalParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum target, GLuint index, const GLfloat *params);
+GLAPI void APIENTRY glGetProgramEnvParameterdvARB (GLenum target, GLuint index, GLdouble *params);
+GLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum target, GLuint index, GLfloat *params);
+GLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum target, GLuint index, GLdouble *params);
+GLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum target, GLuint index, GLfloat *params);
+GLAPI void APIENTRY glGetProgramivARB (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetProgramStringARB (GLenum target, GLenum pname, void *string);
+GLAPI GLboolean APIENTRY glIsProgramARB (GLuint program);
+#endif
+#endif /* GL_ARB_fragment_program */
+
+#ifndef GL_ARB_fragment_program_shadow
+#define GL_ARB_fragment_program_shadow 1
+#endif /* GL_ARB_fragment_program_shadow */
+
+#ifndef GL_ARB_fragment_shader
+#define GL_ARB_fragment_shader 1
+#define GL_FRAGMENT_SHADER_ARB            0x8B30
+#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B
+#endif /* GL_ARB_fragment_shader */
+
+#ifndef GL_ARB_fragment_shader_interlock
+#define GL_ARB_fragment_shader_interlock 1
+#endif /* GL_ARB_fragment_shader_interlock */
+
+#ifndef GL_ARB_framebuffer_no_attachments
+#define GL_ARB_framebuffer_no_attachments 1
+#endif /* GL_ARB_framebuffer_no_attachments */
+
+#ifndef GL_ARB_framebuffer_object
+#define GL_ARB_framebuffer_object 1
+#endif /* GL_ARB_framebuffer_object */
+
+#ifndef GL_ARB_framebuffer_sRGB
+#define GL_ARB_framebuffer_sRGB 1
+#endif /* GL_ARB_framebuffer_sRGB */
+
+#ifndef GL_ARB_geometry_shader4
+#define GL_ARB_geometry_shader4 1
+#define GL_LINES_ADJACENCY_ARB            0x000A
+#define GL_LINE_STRIP_ADJACENCY_ARB       0x000B
+#define GL_TRIANGLES_ADJACENCY_ARB        0x000C
+#define GL_TRIANGLE_STRIP_ADJACENCY_ARB   0x000D
+#define GL_PROGRAM_POINT_SIZE_ARB         0x8642
+#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29
+#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7
+#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8
+#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9
+#define GL_GEOMETRY_SHADER_ARB            0x8DD9
+#define GL_GEOMETRY_VERTICES_OUT_ARB      0x8DDA
+#define GL_GEOMETRY_INPUT_TYPE_ARB        0x8DDB
+#define GL_GEOMETRY_OUTPUT_TYPE_ARB       0x8DDC
+#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD
+#define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE
+#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF
+#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0
+#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIARBPROC) (GLuint program, GLenum pname, GLint value);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramParameteriARB (GLuint program, GLenum pname, GLint value);
+GLAPI void APIENTRY glFramebufferTextureARB (GLenum target, GLenum attachment, GLuint texture, GLint level);
+GLAPI void APIENTRY glFramebufferTextureLayerARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+GLAPI void APIENTRY glFramebufferTextureFaceARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face);
+#endif
+#endif /* GL_ARB_geometry_shader4 */
+
+#ifndef GL_ARB_get_program_binary
+#define GL_ARB_get_program_binary 1
+#endif /* GL_ARB_get_program_binary */
+
+#ifndef GL_ARB_get_texture_sub_image
+#define GL_ARB_get_texture_sub_image 1
+#endif /* GL_ARB_get_texture_sub_image */
+
+#ifndef GL_ARB_gl_spirv
+#define GL_ARB_gl_spirv 1
+#define GL_SHADER_BINARY_FORMAT_SPIR_V_ARB 0x9551
+#define GL_SPIR_V_BINARY_ARB              0x9552
+typedef void (APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSpecializeShaderARB (GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue);
+#endif
+#endif /* GL_ARB_gl_spirv */
+
+#ifndef GL_ARB_gpu_shader5
+#define GL_ARB_gpu_shader5 1
+#endif /* GL_ARB_gpu_shader5 */
+
+#ifndef GL_ARB_gpu_shader_fp64
+#define GL_ARB_gpu_shader_fp64 1
+#endif /* GL_ARB_gpu_shader_fp64 */
+
+#ifndef GL_ARB_gpu_shader_int64
+#define GL_ARB_gpu_shader_int64 1
+#define GL_INT64_ARB                      0x140E
+#define GL_INT64_VEC2_ARB                 0x8FE9
+#define GL_INT64_VEC3_ARB                 0x8FEA
+#define GL_INT64_VEC4_ARB                 0x8FEB
+#define GL_UNSIGNED_INT64_VEC2_ARB        0x8FF5
+#define GL_UNSIGNED_INT64_VEC3_ARB        0x8FF6
+#define GL_UNSIGNED_INT64_VEC4_ARB        0x8FF7
+typedef void (APIENTRYP PFNGLUNIFORM1I64ARBPROC) (GLint location, GLint64 x);
+typedef void (APIENTRYP PFNGLUNIFORM2I64ARBPROC) (GLint location, GLint64 x, GLint64 y);
+typedef void (APIENTRYP PFNGLUNIFORM3I64ARBPROC) (GLint location, GLint64 x, GLint64 y, GLint64 z);
+typedef void (APIENTRYP PFNGLUNIFORM4I64ARBPROC) (GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w);
+typedef void (APIENTRYP PFNGLUNIFORM1I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value);
+typedef void (APIENTRYP PFNGLUNIFORM2I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value);
+typedef void (APIENTRYP PFNGLUNIFORM3I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value);
+typedef void (APIENTRYP PFNGLUNIFORM4I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value);
+typedef void (APIENTRYP PFNGLUNIFORM1UI64ARBPROC) (GLint location, GLuint64 x);
+typedef void (APIENTRYP PFNGLUNIFORM2UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y);
+typedef void (APIENTRYP PFNGLUNIFORM3UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y, GLuint64 z);
+typedef void (APIENTRYP PFNGLUNIFORM4UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w);
+typedef void (APIENTRYP PFNGLUNIFORM1UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value);
+typedef void (APIENTRYP PFNGLUNIFORM2UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value);
+typedef void (APIENTRYP PFNGLUNIFORM3UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value);
+typedef void (APIENTRYP PFNGLUNIFORM4UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value);
+typedef void (APIENTRYP PFNGLGETUNIFORMI64VARBPROC) (GLuint program, GLint location, GLint64 *params);
+typedef void (APIENTRYP PFNGLGETUNIFORMUI64VARBPROC) (GLuint program, GLint location, GLuint64 *params);
+typedef void (APIENTRYP PFNGLGETNUNIFORMI64VARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint64 *params);
+typedef void (APIENTRYP PFNGLGETNUNIFORMUI64VARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint64 *params);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64ARBPROC) (GLuint program, GLint location, GLint64 x);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64ARBPROC) (GLuint program, GLint location, GLuint64 x);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glUniform1i64ARB (GLint location, GLint64 x);
+GLAPI void APIENTRY glUniform2i64ARB (GLint location, GLint64 x, GLint64 y);
+GLAPI void APIENTRY glUniform3i64ARB (GLint location, GLint64 x, GLint64 y, GLint64 z);
+GLAPI void APIENTRY glUniform4i64ARB (GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w);
+GLAPI void APIENTRY glUniform1i64vARB (GLint location, GLsizei count, const GLint64 *value);
+GLAPI void APIENTRY glUniform2i64vARB (GLint location, GLsizei count, const GLint64 *value);
+GLAPI void APIENTRY glUniform3i64vARB (GLint location, GLsizei count, const GLint64 *value);
+GLAPI void APIENTRY glUniform4i64vARB (GLint location, GLsizei count, const GLint64 *value);
+GLAPI void APIENTRY glUniform1ui64ARB (GLint location, GLuint64 x);
+GLAPI void APIENTRY glUniform2ui64ARB (GLint location, GLuint64 x, GLuint64 y);
+GLAPI void APIENTRY glUniform3ui64ARB (GLint location, GLuint64 x, GLuint64 y, GLuint64 z);
+GLAPI void APIENTRY glUniform4ui64ARB (GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w);
+GLAPI void APIENTRY glUniform1ui64vARB (GLint location, GLsizei count, const GLuint64 *value);
+GLAPI void APIENTRY glUniform2ui64vARB (GLint location, GLsizei count, const GLuint64 *value);
+GLAPI void APIENTRY glUniform3ui64vARB (GLint location, GLsizei count, const GLuint64 *value);
+GLAPI void APIENTRY glUniform4ui64vARB (GLint location, GLsizei count, const GLuint64 *value);
+GLAPI void APIENTRY glGetUniformi64vARB (GLuint program, GLint location, GLint64 *params);
+GLAPI void APIENTRY glGetUniformui64vARB (GLuint program, GLint location, GLuint64 *params);
+GLAPI void APIENTRY glGetnUniformi64vARB (GLuint program, GLint location, GLsizei bufSize, GLint64 *params);
+GLAPI void APIENTRY glGetnUniformui64vARB (GLuint program, GLint location, GLsizei bufSize, GLuint64 *params);
+GLAPI void APIENTRY glProgramUniform1i64ARB (GLuint program, GLint location, GLint64 x);
+GLAPI void APIENTRY glProgramUniform2i64ARB (GLuint program, GLint location, GLint64 x, GLint64 y);
+GLAPI void APIENTRY glProgramUniform3i64ARB (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z);
+GLAPI void APIENTRY glProgramUniform4i64ARB (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w);
+GLAPI void APIENTRY glProgramUniform1i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value);
+GLAPI void APIENTRY glProgramUniform2i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value);
+GLAPI void APIENTRY glProgramUniform3i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value);
+GLAPI void APIENTRY glProgramUniform4i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value);
+GLAPI void APIENTRY glProgramUniform1ui64ARB (GLuint program, GLint location, GLuint64 x);
+GLAPI void APIENTRY glProgramUniform2ui64ARB (GLuint program, GLint location, GLuint64 x, GLuint64 y);
+GLAPI void APIENTRY glProgramUniform3ui64ARB (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z);
+GLAPI void APIENTRY glProgramUniform4ui64ARB (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w);
+GLAPI void APIENTRY glProgramUniform1ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value);
+GLAPI void APIENTRY glProgramUniform2ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value);
+GLAPI void APIENTRY glProgramUniform3ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value);
+GLAPI void APIENTRY glProgramUniform4ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value);
+#endif
+#endif /* GL_ARB_gpu_shader_int64 */
+
+#ifndef GL_ARB_half_float_pixel
+#define GL_ARB_half_float_pixel 1
+typedef khronos_uint16_t GLhalfARB;
+#define GL_HALF_FLOAT_ARB                 0x140B
+#endif /* GL_ARB_half_float_pixel */
+
+#ifndef GL_ARB_half_float_vertex
+#define GL_ARB_half_float_vertex 1
+#endif /* GL_ARB_half_float_vertex */
+
+#ifndef GL_ARB_imaging
+#define GL_ARB_imaging 1
+#define GL_CONVOLUTION_1D                 0x8010
+#define GL_CONVOLUTION_2D                 0x8011
+#define GL_SEPARABLE_2D                   0x8012
+#define GL_CONVOLUTION_BORDER_MODE        0x8013
+#define GL_CONVOLUTION_FILTER_SCALE       0x8014
+#define GL_CONVOLUTION_FILTER_BIAS        0x8015
+#define GL_REDUCE                         0x8016
+#define GL_CONVOLUTION_FORMAT             0x8017
+#define GL_CONVOLUTION_WIDTH              0x8018
+#define GL_CONVOLUTION_HEIGHT             0x8019
+#define GL_MAX_CONVOLUTION_WIDTH          0x801A
+#define GL_MAX_CONVOLUTION_HEIGHT         0x801B
+#define GL_POST_CONVOLUTION_RED_SCALE     0x801C
+#define GL_POST_CONVOLUTION_GREEN_SCALE   0x801D
+#define GL_POST_CONVOLUTION_BLUE_SCALE    0x801E
+#define GL_POST_CONVOLUTION_ALPHA_SCALE   0x801F
+#define GL_POST_CONVOLUTION_RED_BIAS      0x8020
+#define GL_POST_CONVOLUTION_GREEN_BIAS    0x8021
+#define GL_POST_CONVOLUTION_BLUE_BIAS     0x8022
+#define GL_POST_CONVOLUTION_ALPHA_BIAS    0x8023
+#define GL_HISTOGRAM                      0x8024
+#define GL_PROXY_HISTOGRAM                0x8025
+#define GL_HISTOGRAM_WIDTH                0x8026
+#define GL_HISTOGRAM_FORMAT               0x8027
+#define GL_HISTOGRAM_RED_SIZE             0x8028
+#define GL_HISTOGRAM_GREEN_SIZE           0x8029
+#define GL_HISTOGRAM_BLUE_SIZE            0x802A
+#define GL_HISTOGRAM_ALPHA_SIZE           0x802B
+#define GL_HISTOGRAM_LUMINANCE_SIZE       0x802C
+#define GL_HISTOGRAM_SINK                 0x802D
+#define GL_MINMAX                         0x802E
+#define GL_MINMAX_FORMAT                  0x802F
+#define GL_MINMAX_SINK                    0x8030
+#define GL_TABLE_TOO_LARGE                0x8031
+#define GL_COLOR_MATRIX                   0x80B1
+#define GL_COLOR_MATRIX_STACK_DEPTH       0x80B2
+#define GL_MAX_COLOR_MATRIX_STACK_DEPTH   0x80B3
+#define GL_POST_COLOR_MATRIX_RED_SCALE    0x80B4
+#define GL_POST_COLOR_MATRIX_GREEN_SCALE  0x80B5
+#define GL_POST_COLOR_MATRIX_BLUE_SCALE   0x80B6
+#define GL_POST_COLOR_MATRIX_ALPHA_SCALE  0x80B7
+#define GL_POST_COLOR_MATRIX_RED_BIAS     0x80B8
+#define GL_POST_COLOR_MATRIX_GREEN_BIAS   0x80B9
+#define GL_POST_COLOR_MATRIX_BLUE_BIAS    0x80BA
+#define GL_POST_COLOR_MATRIX_ALPHA_BIAS   0x80BB
+#define GL_COLOR_TABLE                    0x80D0
+#define GL_POST_CONVOLUTION_COLOR_TABLE   0x80D1
+#define GL_POST_COLOR_MATRIX_COLOR_TABLE  0x80D2
+#define GL_PROXY_COLOR_TABLE              0x80D3
+#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4
+#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5
+#define GL_COLOR_TABLE_SCALE              0x80D6
+#define GL_COLOR_TABLE_BIAS               0x80D7
+#define GL_COLOR_TABLE_FORMAT             0x80D8
+#define GL_COLOR_TABLE_WIDTH              0x80D9
+#define GL_COLOR_TABLE_RED_SIZE           0x80DA
+#define GL_COLOR_TABLE_GREEN_SIZE         0x80DB
+#define GL_COLOR_TABLE_BLUE_SIZE          0x80DC
+#define GL_COLOR_TABLE_ALPHA_SIZE         0x80DD
+#define GL_COLOR_TABLE_LUMINANCE_SIZE     0x80DE
+#define GL_COLOR_TABLE_INTENSITY_SIZE     0x80DF
+#define GL_CONSTANT_BORDER                0x8151
+#define GL_REPLICATE_BORDER               0x8153
+#define GL_CONVOLUTION_BORDER_COLOR       0x8154
+typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, void *table);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, void *image);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span);
+typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorTable (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table);
+GLAPI void APIENTRY glColorTableParameterfv (GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glColorTableParameteriv (GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glCopyColorTable (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+GLAPI void APIENTRY glGetColorTable (GLenum target, GLenum format, GLenum type, void *table);
+GLAPI void APIENTRY glGetColorTableParameterfv (GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetColorTableParameteriv (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data);
+GLAPI void APIENTRY glCopyColorSubTable (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+GLAPI void APIENTRY glConvolutionFilter1D (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image);
+GLAPI void APIENTRY glConvolutionFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image);
+GLAPI void APIENTRY glConvolutionParameterf (GLenum target, GLenum pname, GLfloat params);
+GLAPI void APIENTRY glConvolutionParameterfv (GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glConvolutionParameteri (GLenum target, GLenum pname, GLint params);
+GLAPI void APIENTRY glConvolutionParameteriv (GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+GLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glGetConvolutionFilter (GLenum target, GLenum format, GLenum type, void *image);
+GLAPI void APIENTRY glGetConvolutionParameterfv (GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetConvolutionParameteriv (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetSeparableFilter (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span);
+GLAPI void APIENTRY glSeparableFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column);
+GLAPI void APIENTRY glGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
+GLAPI void APIENTRY glGetHistogramParameterfv (GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetHistogramParameteriv (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
+GLAPI void APIENTRY glGetMinmaxParameterfv (GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetMinmaxParameteriv (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glHistogram (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+GLAPI void APIENTRY glMinmax (GLenum target, GLenum internalformat, GLboolean sink);
+GLAPI void APIENTRY glResetHistogram (GLenum target);
+GLAPI void APIENTRY glResetMinmax (GLenum target);
+#endif
+#endif /* GL_ARB_imaging */
+
+#ifndef GL_ARB_indirect_parameters
+#define GL_ARB_indirect_parameters 1
+#define GL_PARAMETER_BUFFER_ARB           0x80EE
+#define GL_PARAMETER_BUFFER_BINDING_ARB   0x80EF
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC) (GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC) (GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiDrawArraysIndirectCountARB (GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
+GLAPI void APIENTRY glMultiDrawElementsIndirectCountARB (GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
+#endif
+#endif /* GL_ARB_indirect_parameters */
+
+#ifndef GL_ARB_instanced_arrays
+#define GL_ARB_instanced_arrays 1
+#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB 0x88FE
+typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORARBPROC) (GLuint index, GLuint divisor);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttribDivisorARB (GLuint index, GLuint divisor);
+#endif
+#endif /* GL_ARB_instanced_arrays */
+
+#ifndef GL_ARB_internalformat_query
+#define GL_ARB_internalformat_query 1
+#endif /* GL_ARB_internalformat_query */
+
+#ifndef GL_ARB_internalformat_query2
+#define GL_ARB_internalformat_query2 1
+#define GL_SRGB_DECODE_ARB                0x8299
+#define GL_VIEW_CLASS_EAC_R11             0x9383
+#define GL_VIEW_CLASS_EAC_RG11            0x9384
+#define GL_VIEW_CLASS_ETC2_RGB            0x9385
+#define GL_VIEW_CLASS_ETC2_RGBA           0x9386
+#define GL_VIEW_CLASS_ETC2_EAC_RGBA       0x9387
+#define GL_VIEW_CLASS_ASTC_4x4_RGBA       0x9388
+#define GL_VIEW_CLASS_ASTC_5x4_RGBA       0x9389
+#define GL_VIEW_CLASS_ASTC_5x5_RGBA       0x938A
+#define GL_VIEW_CLASS_ASTC_6x5_RGBA       0x938B
+#define GL_VIEW_CLASS_ASTC_6x6_RGBA       0x938C
+#define GL_VIEW_CLASS_ASTC_8x5_RGBA       0x938D
+#define GL_VIEW_CLASS_ASTC_8x6_RGBA       0x938E
+#define GL_VIEW_CLASS_ASTC_8x8_RGBA       0x938F
+#define GL_VIEW_CLASS_ASTC_10x5_RGBA      0x9390
+#define GL_VIEW_CLASS_ASTC_10x6_RGBA      0x9391
+#define GL_VIEW_CLASS_ASTC_10x8_RGBA      0x9392
+#define GL_VIEW_CLASS_ASTC_10x10_RGBA     0x9393
+#define GL_VIEW_CLASS_ASTC_12x10_RGBA     0x9394
+#define GL_VIEW_CLASS_ASTC_12x12_RGBA     0x9395
+#endif /* GL_ARB_internalformat_query2 */
+
+#ifndef GL_ARB_invalidate_subdata
+#define GL_ARB_invalidate_subdata 1
+#endif /* GL_ARB_invalidate_subdata */
+
+#ifndef GL_ARB_map_buffer_alignment
+#define GL_ARB_map_buffer_alignment 1
+#endif /* GL_ARB_map_buffer_alignment */
+
+#ifndef GL_ARB_map_buffer_range
+#define GL_ARB_map_buffer_range 1
+#endif /* GL_ARB_map_buffer_range */
+
+#ifndef GL_ARB_matrix_palette
+#define GL_ARB_matrix_palette 1
+#define GL_MATRIX_PALETTE_ARB             0x8840
+#define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841
+#define GL_MAX_PALETTE_MATRICES_ARB       0x8842
+#define GL_CURRENT_PALETTE_MATRIX_ARB     0x8843
+#define GL_MATRIX_INDEX_ARRAY_ARB         0x8844
+#define GL_CURRENT_MATRIX_INDEX_ARB       0x8845
+#define GL_MATRIX_INDEX_ARRAY_SIZE_ARB    0x8846
+#define GL_MATRIX_INDEX_ARRAY_TYPE_ARB    0x8847
+#define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB  0x8848
+#define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849
+typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index);
+typedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices);
+typedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices);
+typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices);
+typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint index);
+GLAPI void APIENTRY glMatrixIndexubvARB (GLint size, const GLubyte *indices);
+GLAPI void APIENTRY glMatrixIndexusvARB (GLint size, const GLushort *indices);
+GLAPI void APIENTRY glMatrixIndexuivARB (GLint size, const GLuint *indices);
+GLAPI void APIENTRY glMatrixIndexPointerARB (GLint size, GLenum type, GLsizei stride, const void *pointer);
+#endif
+#endif /* GL_ARB_matrix_palette */
+
+#ifndef GL_ARB_multi_bind
+#define GL_ARB_multi_bind 1
+#endif /* GL_ARB_multi_bind */
+
+#ifndef GL_ARB_multi_draw_indirect
+#define GL_ARB_multi_draw_indirect 1
+#endif /* GL_ARB_multi_draw_indirect */
+
+#ifndef GL_ARB_multisample
+#define GL_ARB_multisample 1
+#define GL_MULTISAMPLE_ARB                0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB   0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_ARB        0x809F
+#define GL_SAMPLE_COVERAGE_ARB            0x80A0
+#define GL_SAMPLE_BUFFERS_ARB             0x80A8
+#define GL_SAMPLES_ARB                    0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE_ARB      0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT_ARB     0x80AB
+#define GL_MULTISAMPLE_BIT_ARB            0x20000000
+typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC) (GLfloat value, GLboolean invert);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSampleCoverageARB (GLfloat value, GLboolean invert);
+#endif
+#endif /* GL_ARB_multisample */
+
+#ifndef GL_ARB_multitexture
+#define GL_ARB_multitexture 1
+#define GL_TEXTURE0_ARB                   0x84C0
+#define GL_TEXTURE1_ARB                   0x84C1
+#define GL_TEXTURE2_ARB                   0x84C2
+#define GL_TEXTURE3_ARB                   0x84C3
+#define GL_TEXTURE4_ARB                   0x84C4
+#define GL_TEXTURE5_ARB                   0x84C5
+#define GL_TEXTURE6_ARB                   0x84C6
+#define GL_TEXTURE7_ARB                   0x84C7
+#define GL_TEXTURE8_ARB                   0x84C8
+#define GL_TEXTURE9_ARB                   0x84C9
+#define GL_TEXTURE10_ARB                  0x84CA
+#define GL_TEXTURE11_ARB                  0x84CB
+#define GL_TEXTURE12_ARB                  0x84CC
+#define GL_TEXTURE13_ARB                  0x84CD
+#define GL_TEXTURE14_ARB                  0x84CE
+#define GL_TEXTURE15_ARB                  0x84CF
+#define GL_TEXTURE16_ARB                  0x84D0
+#define GL_TEXTURE17_ARB                  0x84D1
+#define GL_TEXTURE18_ARB                  0x84D2
+#define GL_TEXTURE19_ARB                  0x84D3
+#define GL_TEXTURE20_ARB                  0x84D4
+#define GL_TEXTURE21_ARB                  0x84D5
+#define GL_TEXTURE22_ARB                  0x84D6
+#define GL_TEXTURE23_ARB                  0x84D7
+#define GL_TEXTURE24_ARB                  0x84D8
+#define GL_TEXTURE25_ARB                  0x84D9
+#define GL_TEXTURE26_ARB                  0x84DA
+#define GL_TEXTURE27_ARB                  0x84DB
+#define GL_TEXTURE28_ARB                  0x84DC
+#define GL_TEXTURE29_ARB                  0x84DD
+#define GL_TEXTURE30_ARB                  0x84DE
+#define GL_TEXTURE31_ARB                  0x84DF
+#define GL_ACTIVE_TEXTURE_ARB             0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE_ARB      0x84E1
+#define GL_MAX_TEXTURE_UNITS_ARB          0x84E2
+typedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glActiveTextureARB (GLenum texture);
+GLAPI void APIENTRY glClientActiveTextureARB (GLenum texture);
+GLAPI void APIENTRY glMultiTexCoord1dARB (GLenum target, GLdouble s);
+GLAPI void APIENTRY glMultiTexCoord1dvARB (GLenum target, const GLdouble *v);
+GLAPI void APIENTRY glMultiTexCoord1fARB (GLenum target, GLfloat s);
+GLAPI void APIENTRY glMultiTexCoord1fvARB (GLenum target, const GLfloat *v);
+GLAPI void APIENTRY glMultiTexCoord1iARB (GLenum target, GLint s);
+GLAPI void APIENTRY glMultiTexCoord1ivARB (GLenum target, const GLint *v);
+GLAPI void APIENTRY glMultiTexCoord1sARB (GLenum target, GLshort s);
+GLAPI void APIENTRY glMultiTexCoord1svARB (GLenum target, const GLshort *v);
+GLAPI void APIENTRY glMultiTexCoord2dARB (GLenum target, GLdouble s, GLdouble t);
+GLAPI void APIENTRY glMultiTexCoord2dvARB (GLenum target, const GLdouble *v);
+GLAPI void APIENTRY glMultiTexCoord2fARB (GLenum target, GLfloat s, GLfloat t);
+GLAPI void APIENTRY glMultiTexCoord2fvARB (GLenum target, const GLfloat *v);
+GLAPI void APIENTRY glMultiTexCoord2iARB (GLenum target, GLint s, GLint t);
+GLAPI void APIENTRY glMultiTexCoord2ivARB (GLenum target, const GLint *v);
+GLAPI void APIENTRY glMultiTexCoord2sARB (GLenum target, GLshort s, GLshort t);
+GLAPI void APIENTRY glMultiTexCoord2svARB (GLenum target, const GLshort *v);
+GLAPI void APIENTRY glMultiTexCoord3dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+GLAPI void APIENTRY glMultiTexCoord3dvARB (GLenum target, const GLdouble *v);
+GLAPI void APIENTRY glMultiTexCoord3fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+GLAPI void APIENTRY glMultiTexCoord3fvARB (GLenum target, const GLfloat *v);
+GLAPI void APIENTRY glMultiTexCoord3iARB (GLenum target, GLint s, GLint t, GLint r);
+GLAPI void APIENTRY glMultiTexCoord3ivARB (GLenum target, const GLint *v);
+GLAPI void APIENTRY glMultiTexCoord3sARB (GLenum target, GLshort s, GLshort t, GLshort r);
+GLAPI void APIENTRY glMultiTexCoord3svARB (GLenum target, const GLshort *v);
+GLAPI void APIENTRY glMultiTexCoord4dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+GLAPI void APIENTRY glMultiTexCoord4dvARB (GLenum target, const GLdouble *v);
+GLAPI void APIENTRY glMultiTexCoord4fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+GLAPI void APIENTRY glMultiTexCoord4fvARB (GLenum target, const GLfloat *v);
+GLAPI void APIENTRY glMultiTexCoord4iARB (GLenum target, GLint s, GLint t, GLint r, GLint q);
+GLAPI void APIENTRY glMultiTexCoord4ivARB (GLenum target, const GLint *v);
+GLAPI void APIENTRY glMultiTexCoord4sARB (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+GLAPI void APIENTRY glMultiTexCoord4svARB (GLenum target, const GLshort *v);
+#endif
+#endif /* GL_ARB_multitexture */
+
+#ifndef GL_ARB_occlusion_query
+#define GL_ARB_occlusion_query 1
+#define GL_QUERY_COUNTER_BITS_ARB         0x8864
+#define GL_CURRENT_QUERY_ARB              0x8865
+#define GL_QUERY_RESULT_ARB               0x8866
+#define GL_QUERY_RESULT_AVAILABLE_ARB     0x8867
+#define GL_SAMPLES_PASSED_ARB             0x8914
+typedef void (APIENTRYP PFNGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISQUERYARBPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINQUERYARBPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLENDQUERYARBPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenQueriesARB (GLsizei n, GLuint *ids);
+GLAPI void APIENTRY glDeleteQueriesARB (GLsizei n, const GLuint *ids);
+GLAPI GLboolean APIENTRY glIsQueryARB (GLuint id);
+GLAPI void APIENTRY glBeginQueryARB (GLenum target, GLuint id);
+GLAPI void APIENTRY glEndQueryARB (GLenum target);
+GLAPI void APIENTRY glGetQueryivARB (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetQueryObjectivARB (GLuint id, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetQueryObjectuivARB (GLuint id, GLenum pname, GLuint *params);
+#endif
+#endif /* GL_ARB_occlusion_query */
+
+#ifndef GL_ARB_occlusion_query2
+#define GL_ARB_occlusion_query2 1
+#endif /* GL_ARB_occlusion_query2 */
+
+#ifndef GL_ARB_parallel_shader_compile
+#define GL_ARB_parallel_shader_compile 1
+#define GL_MAX_SHADER_COMPILER_THREADS_ARB 0x91B0
+#define GL_COMPLETION_STATUS_ARB          0x91B1
+typedef void (APIENTRYP PFNGLMAXSHADERCOMPILERTHREADSARBPROC) (GLuint count);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMaxShaderCompilerThreadsARB (GLuint count);
+#endif
+#endif /* GL_ARB_parallel_shader_compile */
+
+#ifndef GL_ARB_pipeline_statistics_query
+#define GL_ARB_pipeline_statistics_query 1
+#define GL_VERTICES_SUBMITTED_ARB         0x82EE
+#define GL_PRIMITIVES_SUBMITTED_ARB       0x82EF
+#define GL_VERTEX_SHADER_INVOCATIONS_ARB  0x82F0
+#define GL_TESS_CONTROL_SHADER_PATCHES_ARB 0x82F1
+#define GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB 0x82F2
+#define GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB 0x82F3
+#define GL_FRAGMENT_SHADER_INVOCATIONS_ARB 0x82F4
+#define GL_COMPUTE_SHADER_INVOCATIONS_ARB 0x82F5
+#define GL_CLIPPING_INPUT_PRIMITIVES_ARB  0x82F6
+#define GL_CLIPPING_OUTPUT_PRIMITIVES_ARB 0x82F7
+#endif /* GL_ARB_pipeline_statistics_query */
+
+#ifndef GL_ARB_pixel_buffer_object
+#define GL_ARB_pixel_buffer_object 1
+#define GL_PIXEL_PACK_BUFFER_ARB          0x88EB
+#define GL_PIXEL_UNPACK_BUFFER_ARB        0x88EC
+#define GL_PIXEL_PACK_BUFFER_BINDING_ARB  0x88ED
+#define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF
+#endif /* GL_ARB_pixel_buffer_object */
+
+#ifndef GL_ARB_point_parameters
+#define GL_ARB_point_parameters 1
+#define GL_POINT_SIZE_MIN_ARB             0x8126
+#define GL_POINT_SIZE_MAX_ARB             0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE_ARB  0x8128
+#define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameterfARB (GLenum pname, GLfloat param);
+GLAPI void APIENTRY glPointParameterfvARB (GLenum pname, const GLfloat *params);
+#endif
+#endif /* GL_ARB_point_parameters */
+
+#ifndef GL_ARB_point_sprite
+#define GL_ARB_point_sprite 1
+#define GL_POINT_SPRITE_ARB               0x8861
+#define GL_COORD_REPLACE_ARB              0x8862
+#endif /* GL_ARB_point_sprite */
+
+#ifndef GL_ARB_polygon_offset_clamp
+#define GL_ARB_polygon_offset_clamp 1
+#endif /* GL_ARB_polygon_offset_clamp */
+
+#ifndef GL_ARB_post_depth_coverage
+#define GL_ARB_post_depth_coverage 1
+#endif /* GL_ARB_post_depth_coverage */
+
+#ifndef GL_ARB_program_interface_query
+#define GL_ARB_program_interface_query 1
+#endif /* GL_ARB_program_interface_query */
+
+#ifndef GL_ARB_provoking_vertex
+#define GL_ARB_provoking_vertex 1
+#endif /* GL_ARB_provoking_vertex */
+
+#ifndef GL_ARB_query_buffer_object
+#define GL_ARB_query_buffer_object 1
+#endif /* GL_ARB_query_buffer_object */
+
+#ifndef GL_ARB_robust_buffer_access_behavior
+#define GL_ARB_robust_buffer_access_behavior 1
+#endif /* GL_ARB_robust_buffer_access_behavior */
+
+#ifndef GL_ARB_robustness
+#define GL_ARB_robustness 1
+#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004
+#define GL_LOSE_CONTEXT_ON_RESET_ARB      0x8252
+#define GL_GUILTY_CONTEXT_RESET_ARB       0x8253
+#define GL_INNOCENT_CONTEXT_RESET_ARB     0x8254
+#define GL_UNKNOWN_CONTEXT_RESET_ARB      0x8255
+#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
+#define GL_NO_RESET_NOTIFICATION_ARB      0x8261
+typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSARBPROC) (void);
+typedef void (APIENTRYP PFNGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img);
+typedef void (APIENTRYP PFNGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, void *img);
+typedef void (APIENTRYP PFNGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETNUNIFORMIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+typedef void (APIENTRYP PFNGLGETNUNIFORMUIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params);
+typedef void (APIENTRYP PFNGLGETNUNIFORMDVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETNMAPDVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v);
+typedef void (APIENTRYP PFNGLGETNMAPFVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v);
+typedef void (APIENTRYP PFNGLGETNMAPIVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v);
+typedef void (APIENTRYP PFNGLGETNPIXELMAPFVARBPROC) (GLenum map, GLsizei bufSize, GLfloat *values);
+typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVARBPROC) (GLenum map, GLsizei bufSize, GLuint *values);
+typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVARBPROC) (GLenum map, GLsizei bufSize, GLushort *values);
+typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEARBPROC) (GLsizei bufSize, GLubyte *pattern);
+typedef void (APIENTRYP PFNGLGETNCOLORTABLEARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table);
+typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image);
+typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span);
+typedef void (APIENTRYP PFNGLGETNHISTOGRAMARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
+typedef void (APIENTRYP PFNGLGETNMINMAXARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLenum APIENTRY glGetGraphicsResetStatusARB (void);
+GLAPI void APIENTRY glGetnTexImageARB (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img);
+GLAPI void APIENTRY glReadnPixelsARB (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+GLAPI void APIENTRY glGetnCompressedTexImageARB (GLenum target, GLint lod, GLsizei bufSize, void *img);
+GLAPI void APIENTRY glGetnUniformfvARB (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
+GLAPI void APIENTRY glGetnUniformivARB (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+GLAPI void APIENTRY glGetnUniformuivARB (GLuint program, GLint location, GLsizei bufSize, GLuint *params);
+GLAPI void APIENTRY glGetnUniformdvARB (GLuint program, GLint location, GLsizei bufSize, GLdouble *params);
+GLAPI void APIENTRY glGetnMapdvARB (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v);
+GLAPI void APIENTRY glGetnMapfvARB (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v);
+GLAPI void APIENTRY glGetnMapivARB (GLenum target, GLenum query, GLsizei bufSize, GLint *v);
+GLAPI void APIENTRY glGetnPixelMapfvARB (GLenum map, GLsizei bufSize, GLfloat *values);
+GLAPI void APIENTRY glGetnPixelMapuivARB (GLenum map, GLsizei bufSize, GLuint *values);
+GLAPI void APIENTRY glGetnPixelMapusvARB (GLenum map, GLsizei bufSize, GLushort *values);
+GLAPI void APIENTRY glGetnPolygonStippleARB (GLsizei bufSize, GLubyte *pattern);
+GLAPI void APIENTRY glGetnColorTableARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table);
+GLAPI void APIENTRY glGetnConvolutionFilterARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image);
+GLAPI void APIENTRY glGetnSeparableFilterARB (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span);
+GLAPI void APIENTRY glGetnHistogramARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
+GLAPI void APIENTRY glGetnMinmaxARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
+#endif
+#endif /* GL_ARB_robustness */
+
+#ifndef GL_ARB_robustness_isolation
+#define GL_ARB_robustness_isolation 1
+#endif /* GL_ARB_robustness_isolation */
+
+#ifndef GL_ARB_sample_locations
+#define GL_ARB_sample_locations 1
+#define GL_SAMPLE_LOCATION_SUBPIXEL_BITS_ARB 0x933D
+#define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_ARB 0x933E
+#define GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_ARB 0x933F
+#define GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_ARB 0x9340
+#define GL_SAMPLE_LOCATION_ARB            0x8E50
+#define GL_PROGRAMMABLE_SAMPLE_LOCATION_ARB 0x9341
+#define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB 0x9342
+#define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB 0x9343
+typedef void (APIENTRYP PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC) (GLenum target, GLuint start, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC) (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLEVALUATEDEPTHVALUESARBPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFramebufferSampleLocationsfvARB (GLenum target, GLuint start, GLsizei count, const GLfloat *v);
+GLAPI void APIENTRY glNamedFramebufferSampleLocationsfvARB (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v);
+GLAPI void APIENTRY glEvaluateDepthValuesARB (void);
+#endif
+#endif /* GL_ARB_sample_locations */
+
+#ifndef GL_ARB_sample_shading
+#define GL_ARB_sample_shading 1
+#define GL_SAMPLE_SHADING_ARB             0x8C36
+#define GL_MIN_SAMPLE_SHADING_VALUE_ARB   0x8C37
+typedef void (APIENTRYP PFNGLMINSAMPLESHADINGARBPROC) (GLfloat value);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMinSampleShadingARB (GLfloat value);
+#endif
+#endif /* GL_ARB_sample_shading */
+
+#ifndef GL_ARB_sampler_objects
+#define GL_ARB_sampler_objects 1
+#endif /* GL_ARB_sampler_objects */
+
+#ifndef GL_ARB_seamless_cube_map
+#define GL_ARB_seamless_cube_map 1
+#endif /* GL_ARB_seamless_cube_map */
+
+#ifndef GL_ARB_seamless_cubemap_per_texture
+#define GL_ARB_seamless_cubemap_per_texture 1
+#endif /* GL_ARB_seamless_cubemap_per_texture */
+
+#ifndef GL_ARB_separate_shader_objects
+#define GL_ARB_separate_shader_objects 1
+#endif /* GL_ARB_separate_shader_objects */
+
+#ifndef GL_ARB_shader_atomic_counter_ops
+#define GL_ARB_shader_atomic_counter_ops 1
+#endif /* GL_ARB_shader_atomic_counter_ops */
+
+#ifndef GL_ARB_shader_atomic_counters
+#define GL_ARB_shader_atomic_counters 1
+#endif /* GL_ARB_shader_atomic_counters */
+
+#ifndef GL_ARB_shader_ballot
+#define GL_ARB_shader_ballot 1
+#endif /* GL_ARB_shader_ballot */
+
+#ifndef GL_ARB_shader_bit_encoding
+#define GL_ARB_shader_bit_encoding 1
+#endif /* GL_ARB_shader_bit_encoding */
+
+#ifndef GL_ARB_shader_clock
+#define GL_ARB_shader_clock 1
+#endif /* GL_ARB_shader_clock */
+
+#ifndef GL_ARB_shader_draw_parameters
+#define GL_ARB_shader_draw_parameters 1
+#endif /* GL_ARB_shader_draw_parameters */
+
+#ifndef GL_ARB_shader_group_vote
+#define GL_ARB_shader_group_vote 1
+#endif /* GL_ARB_shader_group_vote */
+
+#ifndef GL_ARB_shader_image_load_store
+#define GL_ARB_shader_image_load_store 1
+#endif /* GL_ARB_shader_image_load_store */
+
+#ifndef GL_ARB_shader_image_size
+#define GL_ARB_shader_image_size 1
+#endif /* GL_ARB_shader_image_size */
+
+#ifndef GL_ARB_shader_objects
+#define GL_ARB_shader_objects 1
+#ifdef __APPLE__
+typedef void *GLhandleARB;
+#else
+typedef unsigned int GLhandleARB;
+#endif
+typedef char GLcharARB;
+#define GL_PROGRAM_OBJECT_ARB             0x8B40
+#define GL_SHADER_OBJECT_ARB              0x8B48
+#define GL_OBJECT_TYPE_ARB                0x8B4E
+#define GL_OBJECT_SUBTYPE_ARB             0x8B4F
+#define GL_FLOAT_VEC2_ARB                 0x8B50
+#define GL_FLOAT_VEC3_ARB                 0x8B51
+#define GL_FLOAT_VEC4_ARB                 0x8B52
+#define GL_INT_VEC2_ARB                   0x8B53
+#define GL_INT_VEC3_ARB                   0x8B54
+#define GL_INT_VEC4_ARB                   0x8B55
+#define GL_BOOL_ARB                       0x8B56
+#define GL_BOOL_VEC2_ARB                  0x8B57
+#define GL_BOOL_VEC3_ARB                  0x8B58
+#define GL_BOOL_VEC4_ARB                  0x8B59
+#define GL_FLOAT_MAT2_ARB                 0x8B5A
+#define GL_FLOAT_MAT3_ARB                 0x8B5B
+#define GL_FLOAT_MAT4_ARB                 0x8B5C
+#define GL_SAMPLER_1D_ARB                 0x8B5D
+#define GL_SAMPLER_2D_ARB                 0x8B5E
+#define GL_SAMPLER_3D_ARB                 0x8B5F
+#define GL_SAMPLER_CUBE_ARB               0x8B60
+#define GL_SAMPLER_1D_SHADOW_ARB          0x8B61
+#define GL_SAMPLER_2D_SHADOW_ARB          0x8B62
+#define GL_SAMPLER_2D_RECT_ARB            0x8B63
+#define GL_SAMPLER_2D_RECT_SHADOW_ARB     0x8B64
+#define GL_OBJECT_DELETE_STATUS_ARB       0x8B80
+#define GL_OBJECT_COMPILE_STATUS_ARB      0x8B81
+#define GL_OBJECT_LINK_STATUS_ARB         0x8B82
+#define GL_OBJECT_VALIDATE_STATUS_ARB     0x8B83
+#define GL_OBJECT_INFO_LOG_LENGTH_ARB     0x8B84
+#define GL_OBJECT_ATTACHED_OBJECTS_ARB    0x8B85
+#define GL_OBJECT_ACTIVE_UNIFORMS_ARB     0x8B86
+#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87
+#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88
+typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj);
+typedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname);
+typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj);
+typedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType);
+typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length);
+typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj);
+typedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void);
+typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj);
+typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0);
+typedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (APIENTRYP PFNGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRYP PFNGLUNIFORM1IARBPROC) (GLint location, GLint v0);
+typedef void (APIENTRYP PFNGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1);
+typedef void (APIENTRYP PFNGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (APIENTRYP PFNGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);
+typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj);
+typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
+typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params);
+typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDeleteObjectARB (GLhandleARB obj);
+GLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum pname);
+GLAPI void APIENTRY glDetachObjectARB (GLhandleARB containerObj, GLhandleARB attachedObj);
+GLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum shaderType);
+GLAPI void APIENTRY glShaderSourceARB (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length);
+GLAPI void APIENTRY glCompileShaderARB (GLhandleARB shaderObj);
+GLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void);
+GLAPI void APIENTRY glAttachObjectARB (GLhandleARB containerObj, GLhandleARB obj);
+GLAPI void APIENTRY glLinkProgramARB (GLhandleARB programObj);
+GLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB programObj);
+GLAPI void APIENTRY glValidateProgramARB (GLhandleARB programObj);
+GLAPI void APIENTRY glUniform1fARB (GLint location, GLfloat v0);
+GLAPI void APIENTRY glUniform2fARB (GLint location, GLfloat v0, GLfloat v1);
+GLAPI void APIENTRY glUniform3fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+GLAPI void APIENTRY glUniform4fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+GLAPI void APIENTRY glUniform1iARB (GLint location, GLint v0);
+GLAPI void APIENTRY glUniform2iARB (GLint location, GLint v0, GLint v1);
+GLAPI void APIENTRY glUniform3iARB (GLint location, GLint v0, GLint v1, GLint v2);
+GLAPI void APIENTRY glUniform4iARB (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+GLAPI void APIENTRY glUniform1fvARB (GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glUniform2fvARB (GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glUniform3fvARB (GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glUniform4fvARB (GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glUniform1ivARB (GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glUniform2ivARB (GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glUniform3ivARB (GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glUniform4ivARB (GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glUniformMatrix2fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glUniformMatrix3fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glUniformMatrix4fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB obj, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB obj, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetInfoLogARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);
+GLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj);
+GLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB programObj, const GLcharARB *name);
+GLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
+GLAPI void APIENTRY glGetUniformfvARB (GLhandleARB programObj, GLint location, GLfloat *params);
+GLAPI void APIENTRY glGetUniformivARB (GLhandleARB programObj, GLint location, GLint *params);
+GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source);
+#endif
+#endif /* GL_ARB_shader_objects */
+
+#ifndef GL_ARB_shader_precision
+#define GL_ARB_shader_precision 1
+#endif /* GL_ARB_shader_precision */
+
+#ifndef GL_ARB_shader_stencil_export
+#define GL_ARB_shader_stencil_export 1
+#endif /* GL_ARB_shader_stencil_export */
+
+#ifndef GL_ARB_shader_storage_buffer_object
+#define GL_ARB_shader_storage_buffer_object 1
+#endif /* GL_ARB_shader_storage_buffer_object */
+
+#ifndef GL_ARB_shader_subroutine
+#define GL_ARB_shader_subroutine 1
+#endif /* GL_ARB_shader_subroutine */
+
+#ifndef GL_ARB_shader_texture_image_samples
+#define GL_ARB_shader_texture_image_samples 1
+#endif /* GL_ARB_shader_texture_image_samples */
+
+#ifndef GL_ARB_shader_texture_lod
+#define GL_ARB_shader_texture_lod 1
+#endif /* GL_ARB_shader_texture_lod */
+
+#ifndef GL_ARB_shader_viewport_layer_array
+#define GL_ARB_shader_viewport_layer_array 1
+#endif /* GL_ARB_shader_viewport_layer_array */
+
+#ifndef GL_ARB_shading_language_100
+#define GL_ARB_shading_language_100 1
+#define GL_SHADING_LANGUAGE_VERSION_ARB   0x8B8C
+#endif /* GL_ARB_shading_language_100 */
+
+#ifndef GL_ARB_shading_language_420pack
+#define GL_ARB_shading_language_420pack 1
+#endif /* GL_ARB_shading_language_420pack */
+
+#ifndef GL_ARB_shading_language_include
+#define GL_ARB_shading_language_include 1
+#define GL_SHADER_INCLUDE_ARB             0x8DAE
+#define GL_NAMED_STRING_LENGTH_ARB        0x8DE9
+#define GL_NAMED_STRING_TYPE_ARB          0x8DEA
+typedef void (APIENTRYP PFNGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string);
+typedef void (APIENTRYP PFNGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name);
+typedef void (APIENTRYP PFNGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length);
+typedef GLboolean (APIENTRYP PFNGLISNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string);
+typedef void (APIENTRYP PFNGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar *name, GLenum pname, GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glNamedStringARB (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string);
+GLAPI void APIENTRY glDeleteNamedStringARB (GLint namelen, const GLchar *name);
+GLAPI void APIENTRY glCompileShaderIncludeARB (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length);
+GLAPI GLboolean APIENTRY glIsNamedStringARB (GLint namelen, const GLchar *name);
+GLAPI void APIENTRY glGetNamedStringARB (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string);
+GLAPI void APIENTRY glGetNamedStringivARB (GLint namelen, const GLchar *name, GLenum pname, GLint *params);
+#endif
+#endif /* GL_ARB_shading_language_include */
+
+#ifndef GL_ARB_shading_language_packing
+#define GL_ARB_shading_language_packing 1
+#endif /* GL_ARB_shading_language_packing */
+
+#ifndef GL_ARB_shadow
+#define GL_ARB_shadow 1
+#define GL_TEXTURE_COMPARE_MODE_ARB       0x884C
+#define GL_TEXTURE_COMPARE_FUNC_ARB       0x884D
+#define GL_COMPARE_R_TO_TEXTURE_ARB       0x884E
+#endif /* GL_ARB_shadow */
+
+#ifndef GL_ARB_shadow_ambient
+#define GL_ARB_shadow_ambient 1
+#define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF
+#endif /* GL_ARB_shadow_ambient */
+
+#ifndef GL_ARB_sparse_buffer
+#define GL_ARB_sparse_buffer 1
+#define GL_SPARSE_STORAGE_BIT_ARB         0x0400
+#define GL_SPARSE_BUFFER_PAGE_SIZE_ARB    0x82F8
+typedef void (APIENTRYP PFNGLBUFFERPAGECOMMITMENTARBPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLboolean commit);
+typedef void (APIENTRYP PFNGLNAMEDBUFFERPAGECOMMITMENTEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit);
+typedef void (APIENTRYP PFNGLNAMEDBUFFERPAGECOMMITMENTARBPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBufferPageCommitmentARB (GLenum target, GLintptr offset, GLsizeiptr size, GLboolean commit);
+GLAPI void APIENTRY glNamedBufferPageCommitmentEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit);
+GLAPI void APIENTRY glNamedBufferPageCommitmentARB (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit);
+#endif
+#endif /* GL_ARB_sparse_buffer */
+
+#ifndef GL_ARB_sparse_texture
+#define GL_ARB_sparse_texture 1
+#define GL_TEXTURE_SPARSE_ARB             0x91A6
+#define GL_VIRTUAL_PAGE_SIZE_INDEX_ARB    0x91A7
+#define GL_NUM_SPARSE_LEVELS_ARB          0x91AA
+#define GL_NUM_VIRTUAL_PAGE_SIZES_ARB     0x91A8
+#define GL_VIRTUAL_PAGE_SIZE_X_ARB        0x9195
+#define GL_VIRTUAL_PAGE_SIZE_Y_ARB        0x9196
+#define GL_VIRTUAL_PAGE_SIZE_Z_ARB        0x9197
+#define GL_MAX_SPARSE_TEXTURE_SIZE_ARB    0x9198
+#define GL_MAX_SPARSE_3D_TEXTURE_SIZE_ARB 0x9199
+#define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_ARB 0x919A
+#define GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_ARB 0x91A9
+typedef void (APIENTRYP PFNGLTEXPAGECOMMITMENTARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexPageCommitmentARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);
+#endif
+#endif /* GL_ARB_sparse_texture */
+
+#ifndef GL_ARB_sparse_texture2
+#define GL_ARB_sparse_texture2 1
+#endif /* GL_ARB_sparse_texture2 */
+
+#ifndef GL_ARB_sparse_texture_clamp
+#define GL_ARB_sparse_texture_clamp 1
+#endif /* GL_ARB_sparse_texture_clamp */
+
+#ifndef GL_ARB_spirv_extensions
+#define GL_ARB_spirv_extensions 1
+#endif /* GL_ARB_spirv_extensions */
+
+#ifndef GL_ARB_stencil_texturing
+#define GL_ARB_stencil_texturing 1
+#endif /* GL_ARB_stencil_texturing */
+
+#ifndef GL_ARB_sync
+#define GL_ARB_sync 1
+#endif /* GL_ARB_sync */
+
+#ifndef GL_ARB_tessellation_shader
+#define GL_ARB_tessellation_shader 1
+#endif /* GL_ARB_tessellation_shader */
+
+#ifndef GL_ARB_texture_barrier
+#define GL_ARB_texture_barrier 1
+#endif /* GL_ARB_texture_barrier */
+
+#ifndef GL_ARB_texture_border_clamp
+#define GL_ARB_texture_border_clamp 1
+#define GL_CLAMP_TO_BORDER_ARB            0x812D
+#endif /* GL_ARB_texture_border_clamp */
+
+#ifndef GL_ARB_texture_buffer_object
+#define GL_ARB_texture_buffer_object 1
+#define GL_TEXTURE_BUFFER_ARB             0x8C2A
+#define GL_MAX_TEXTURE_BUFFER_SIZE_ARB    0x8C2B
+#define GL_TEXTURE_BINDING_BUFFER_ARB     0x8C2C
+#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB 0x8C2D
+#define GL_TEXTURE_BUFFER_FORMAT_ARB      0x8C2E
+typedef void (APIENTRYP PFNGLTEXBUFFERARBPROC) (GLenum target, GLenum internalformat, GLuint buffer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexBufferARB (GLenum target, GLenum internalformat, GLuint buffer);
+#endif
+#endif /* GL_ARB_texture_buffer_object */
+
+#ifndef GL_ARB_texture_buffer_object_rgb32
+#define GL_ARB_texture_buffer_object_rgb32 1
+#endif /* GL_ARB_texture_buffer_object_rgb32 */
+
+#ifndef GL_ARB_texture_buffer_range
+#define GL_ARB_texture_buffer_range 1
+#endif /* GL_ARB_texture_buffer_range */
+
+#ifndef GL_ARB_texture_compression
+#define GL_ARB_texture_compression 1
+#define GL_COMPRESSED_ALPHA_ARB           0x84E9
+#define GL_COMPRESSED_LUMINANCE_ARB       0x84EA
+#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB
+#define GL_COMPRESSED_INTENSITY_ARB       0x84EC
+#define GL_COMPRESSED_RGB_ARB             0x84ED
+#define GL_COMPRESSED_RGBA_ARB            0x84EE
+#define GL_TEXTURE_COMPRESSION_HINT_ARB   0x84EF
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0
+#define GL_TEXTURE_COMPRESSED_ARB         0x86A1
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, void *img);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexImage1DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
+GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum target, GLint level, void *img);
+#endif
+#endif /* GL_ARB_texture_compression */
+
+#ifndef GL_ARB_texture_compression_bptc
+#define GL_ARB_texture_compression_bptc 1
+#define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C
+#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D
+#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E
+#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F
+#endif /* GL_ARB_texture_compression_bptc */
+
+#ifndef GL_ARB_texture_compression_rgtc
+#define GL_ARB_texture_compression_rgtc 1
+#endif /* GL_ARB_texture_compression_rgtc */
+
+#ifndef GL_ARB_texture_cube_map
+#define GL_ARB_texture_cube_map 1
+#define GL_NORMAL_MAP_ARB                 0x8511
+#define GL_REFLECTION_MAP_ARB             0x8512
+#define GL_TEXTURE_CUBE_MAP_ARB           0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP_ARB   0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP_ARB     0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB  0x851C
+#endif /* GL_ARB_texture_cube_map */
+
+#ifndef GL_ARB_texture_cube_map_array
+#define GL_ARB_texture_cube_map_array 1
+#define GL_TEXTURE_CUBE_MAP_ARRAY_ARB     0x9009
+#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB 0x900A
+#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB 0x900B
+#define GL_SAMPLER_CUBE_MAP_ARRAY_ARB     0x900C
+#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D
+#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900E
+#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900F
+#endif /* GL_ARB_texture_cube_map_array */
+
+#ifndef GL_ARB_texture_env_add
+#define GL_ARB_texture_env_add 1
+#endif /* GL_ARB_texture_env_add */
+
+#ifndef GL_ARB_texture_env_combine
+#define GL_ARB_texture_env_combine 1
+#define GL_COMBINE_ARB                    0x8570
+#define GL_COMBINE_RGB_ARB                0x8571
+#define GL_COMBINE_ALPHA_ARB              0x8572
+#define GL_SOURCE0_RGB_ARB                0x8580
+#define GL_SOURCE1_RGB_ARB                0x8581
+#define GL_SOURCE2_RGB_ARB                0x8582
+#define GL_SOURCE0_ALPHA_ARB              0x8588
+#define GL_SOURCE1_ALPHA_ARB              0x8589
+#define GL_SOURCE2_ALPHA_ARB              0x858A
+#define GL_OPERAND0_RGB_ARB               0x8590
+#define GL_OPERAND1_RGB_ARB               0x8591
+#define GL_OPERAND2_RGB_ARB               0x8592
+#define GL_OPERAND0_ALPHA_ARB             0x8598
+#define GL_OPERAND1_ALPHA_ARB             0x8599
+#define GL_OPERAND2_ALPHA_ARB             0x859A
+#define GL_RGB_SCALE_ARB                  0x8573
+#define GL_ADD_SIGNED_ARB                 0x8574
+#define GL_INTERPOLATE_ARB                0x8575
+#define GL_SUBTRACT_ARB                   0x84E7
+#define GL_CONSTANT_ARB                   0x8576
+#define GL_PRIMARY_COLOR_ARB              0x8577
+#define GL_PREVIOUS_ARB                   0x8578
+#endif /* GL_ARB_texture_env_combine */
+
+#ifndef GL_ARB_texture_env_crossbar
+#define GL_ARB_texture_env_crossbar 1
+#endif /* GL_ARB_texture_env_crossbar */
+
+#ifndef GL_ARB_texture_env_dot3
+#define GL_ARB_texture_env_dot3 1
+#define GL_DOT3_RGB_ARB                   0x86AE
+#define GL_DOT3_RGBA_ARB                  0x86AF
+#endif /* GL_ARB_texture_env_dot3 */
+
+#ifndef GL_ARB_texture_filter_anisotropic
+#define GL_ARB_texture_filter_anisotropic 1
+#endif /* GL_ARB_texture_filter_anisotropic */
+
+#ifndef GL_ARB_texture_filter_minmax
+#define GL_ARB_texture_filter_minmax 1
+#define GL_TEXTURE_REDUCTION_MODE_ARB     0x9366
+#define GL_WEIGHTED_AVERAGE_ARB           0x9367
+#endif /* GL_ARB_texture_filter_minmax */
+
+#ifndef GL_ARB_texture_float
+#define GL_ARB_texture_float 1
+#define GL_TEXTURE_RED_TYPE_ARB           0x8C10
+#define GL_TEXTURE_GREEN_TYPE_ARB         0x8C11
+#define GL_TEXTURE_BLUE_TYPE_ARB          0x8C12
+#define GL_TEXTURE_ALPHA_TYPE_ARB         0x8C13
+#define GL_TEXTURE_LUMINANCE_TYPE_ARB     0x8C14
+#define GL_TEXTURE_INTENSITY_TYPE_ARB     0x8C15
+#define GL_TEXTURE_DEPTH_TYPE_ARB         0x8C16
+#define GL_UNSIGNED_NORMALIZED_ARB        0x8C17
+#define GL_RGBA32F_ARB                    0x8814
+#define GL_RGB32F_ARB                     0x8815
+#define GL_ALPHA32F_ARB                   0x8816
+#define GL_INTENSITY32F_ARB               0x8817
+#define GL_LUMINANCE32F_ARB               0x8818
+#define GL_LUMINANCE_ALPHA32F_ARB         0x8819
+#define GL_RGBA16F_ARB                    0x881A
+#define GL_RGB16F_ARB                     0x881B
+#define GL_ALPHA16F_ARB                   0x881C
+#define GL_INTENSITY16F_ARB               0x881D
+#define GL_LUMINANCE16F_ARB               0x881E
+#define GL_LUMINANCE_ALPHA16F_ARB         0x881F
+#endif /* GL_ARB_texture_float */
+
+#ifndef GL_ARB_texture_gather
+#define GL_ARB_texture_gather 1
+#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5E
+#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5F
+#define GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB 0x8F9F
+#endif /* GL_ARB_texture_gather */
+
+#ifndef GL_ARB_texture_mirror_clamp_to_edge
+#define GL_ARB_texture_mirror_clamp_to_edge 1
+#endif /* GL_ARB_texture_mirror_clamp_to_edge */
+
+#ifndef GL_ARB_texture_mirrored_repeat
+#define GL_ARB_texture_mirrored_repeat 1
+#define GL_MIRRORED_REPEAT_ARB            0x8370
+#endif /* GL_ARB_texture_mirrored_repeat */
+
+#ifndef GL_ARB_texture_multisample
+#define GL_ARB_texture_multisample 1
+#endif /* GL_ARB_texture_multisample */
+
+#ifndef GL_ARB_texture_non_power_of_two
+#define GL_ARB_texture_non_power_of_two 1
+#endif /* GL_ARB_texture_non_power_of_two */
+
+#ifndef GL_ARB_texture_query_levels
+#define GL_ARB_texture_query_levels 1
+#endif /* GL_ARB_texture_query_levels */
+
+#ifndef GL_ARB_texture_query_lod
+#define GL_ARB_texture_query_lod 1
+#endif /* GL_ARB_texture_query_lod */
+
+#ifndef GL_ARB_texture_rectangle
+#define GL_ARB_texture_rectangle 1
+#define GL_TEXTURE_RECTANGLE_ARB          0x84F5
+#define GL_TEXTURE_BINDING_RECTANGLE_ARB  0x84F6
+#define GL_PROXY_TEXTURE_RECTANGLE_ARB    0x84F7
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
+#endif /* GL_ARB_texture_rectangle */
+
+#ifndef GL_ARB_texture_rg
+#define GL_ARB_texture_rg 1
+#endif /* GL_ARB_texture_rg */
+
+#ifndef GL_ARB_texture_rgb10_a2ui
+#define GL_ARB_texture_rgb10_a2ui 1
+#endif /* GL_ARB_texture_rgb10_a2ui */
+
+#ifndef GL_ARB_texture_stencil8
+#define GL_ARB_texture_stencil8 1
+#endif /* GL_ARB_texture_stencil8 */
+
+#ifndef GL_ARB_texture_storage
+#define GL_ARB_texture_storage 1
+#endif /* GL_ARB_texture_storage */
+
+#ifndef GL_ARB_texture_storage_multisample
+#define GL_ARB_texture_storage_multisample 1
+#endif /* GL_ARB_texture_storage_multisample */
+
+#ifndef GL_ARB_texture_swizzle
+#define GL_ARB_texture_swizzle 1
+#endif /* GL_ARB_texture_swizzle */
+
+#ifndef GL_ARB_texture_view
+#define GL_ARB_texture_view 1
+#endif /* GL_ARB_texture_view */
+
+#ifndef GL_ARB_timer_query
+#define GL_ARB_timer_query 1
+#endif /* GL_ARB_timer_query */
+
+#ifndef GL_ARB_transform_feedback2
+#define GL_ARB_transform_feedback2 1
+#endif /* GL_ARB_transform_feedback2 */
+
+#ifndef GL_ARB_transform_feedback3
+#define GL_ARB_transform_feedback3 1
+#endif /* GL_ARB_transform_feedback3 */
+
+#ifndef GL_ARB_transform_feedback_instanced
+#define GL_ARB_transform_feedback_instanced 1
+#endif /* GL_ARB_transform_feedback_instanced */
+
+#ifndef GL_ARB_transform_feedback_overflow_query
+#define GL_ARB_transform_feedback_overflow_query 1
+#define GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB 0x82EC
+#define GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB 0x82ED
+#endif /* GL_ARB_transform_feedback_overflow_query */
+
+#ifndef GL_ARB_transpose_matrix
+#define GL_ARB_transpose_matrix 1
+#define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3
+#define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4
+#define GL_TRANSPOSE_TEXTURE_MATRIX_ARB   0x84E5
+#define GL_TRANSPOSE_COLOR_MATRIX_ARB     0x84E6
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glLoadTransposeMatrixfARB (const GLfloat *m);
+GLAPI void APIENTRY glLoadTransposeMatrixdARB (const GLdouble *m);
+GLAPI void APIENTRY glMultTransposeMatrixfARB (const GLfloat *m);
+GLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *m);
+#endif
+#endif /* GL_ARB_transpose_matrix */
+
+#ifndef GL_ARB_uniform_buffer_object
+#define GL_ARB_uniform_buffer_object 1
+#endif /* GL_ARB_uniform_buffer_object */
+
+#ifndef GL_ARB_vertex_array_bgra
+#define GL_ARB_vertex_array_bgra 1
+#endif /* GL_ARB_vertex_array_bgra */
+
+#ifndef GL_ARB_vertex_array_object
+#define GL_ARB_vertex_array_object 1
+#endif /* GL_ARB_vertex_array_object */
+
+#ifndef GL_ARB_vertex_attrib_64bit
+#define GL_ARB_vertex_attrib_64bit 1
+#endif /* GL_ARB_vertex_attrib_64bit */
+
+#ifndef GL_ARB_vertex_attrib_binding
+#define GL_ARB_vertex_attrib_binding 1
+#endif /* GL_ARB_vertex_attrib_binding */
+
+#ifndef GL_ARB_vertex_blend
+#define GL_ARB_vertex_blend 1
+#define GL_MAX_VERTEX_UNITS_ARB           0x86A4
+#define GL_ACTIVE_VERTEX_UNITS_ARB        0x86A5
+#define GL_WEIGHT_SUM_UNITY_ARB           0x86A6
+#define GL_VERTEX_BLEND_ARB               0x86A7
+#define GL_CURRENT_WEIGHT_ARB             0x86A8
+#define GL_WEIGHT_ARRAY_TYPE_ARB          0x86A9
+#define GL_WEIGHT_ARRAY_STRIDE_ARB        0x86AA
+#define GL_WEIGHT_ARRAY_SIZE_ARB          0x86AB
+#define GL_WEIGHT_ARRAY_POINTER_ARB       0x86AC
+#define GL_WEIGHT_ARRAY_ARB               0x86AD
+#define GL_MODELVIEW0_ARB                 0x1700
+#define GL_MODELVIEW1_ARB                 0x850A
+#define GL_MODELVIEW2_ARB                 0x8722
+#define GL_MODELVIEW3_ARB                 0x8723
+#define GL_MODELVIEW4_ARB                 0x8724
+#define GL_MODELVIEW5_ARB                 0x8725
+#define GL_MODELVIEW6_ARB                 0x8726
+#define GL_MODELVIEW7_ARB                 0x8727
+#define GL_MODELVIEW8_ARB                 0x8728
+#define GL_MODELVIEW9_ARB                 0x8729
+#define GL_MODELVIEW10_ARB                0x872A
+#define GL_MODELVIEW11_ARB                0x872B
+#define GL_MODELVIEW12_ARB                0x872C
+#define GL_MODELVIEW13_ARB                0x872D
+#define GL_MODELVIEW14_ARB                0x872E
+#define GL_MODELVIEW15_ARB                0x872F
+#define GL_MODELVIEW16_ARB                0x8730
+#define GL_MODELVIEW17_ARB                0x8731
+#define GL_MODELVIEW18_ARB                0x8732
+#define GL_MODELVIEW19_ARB                0x8733
+#define GL_MODELVIEW20_ARB                0x8734
+#define GL_MODELVIEW21_ARB                0x8735
+#define GL_MODELVIEW22_ARB                0x8736
+#define GL_MODELVIEW23_ARB                0x8737
+#define GL_MODELVIEW24_ARB                0x8738
+#define GL_MODELVIEW25_ARB                0x8739
+#define GL_MODELVIEW26_ARB                0x873A
+#define GL_MODELVIEW27_ARB                0x873B
+#define GL_MODELVIEW28_ARB                0x873C
+#define GL_MODELVIEW29_ARB                0x873D
+#define GL_MODELVIEW30_ARB                0x873E
+#define GL_MODELVIEW31_ARB                0x873F
+typedef void (APIENTRYP PFNGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights);
+typedef void (APIENTRYP PFNGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights);
+typedef void (APIENTRYP PFNGLWEIGHTIVARBPROC) (GLint size, const GLint *weights);
+typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights);
+typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights);
+typedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights);
+typedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights);
+typedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights);
+typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glWeightbvARB (GLint size, const GLbyte *weights);
+GLAPI void APIENTRY glWeightsvARB (GLint size, const GLshort *weights);
+GLAPI void APIENTRY glWeightivARB (GLint size, const GLint *weights);
+GLAPI void APIENTRY glWeightfvARB (GLint size, const GLfloat *weights);
+GLAPI void APIENTRY glWeightdvARB (GLint size, const GLdouble *weights);
+GLAPI void APIENTRY glWeightubvARB (GLint size, const GLubyte *weights);
+GLAPI void APIENTRY glWeightusvARB (GLint size, const GLushort *weights);
+GLAPI void APIENTRY glWeightuivARB (GLint size, const GLuint *weights);
+GLAPI void APIENTRY glWeightPointerARB (GLint size, GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glVertexBlendARB (GLint count);
+#endif
+#endif /* GL_ARB_vertex_blend */
+
+#ifndef GL_ARB_vertex_buffer_object
+#define GL_ARB_vertex_buffer_object 1
+typedef khronos_ssize_t GLsizeiptrARB;
+typedef khronos_intptr_t GLintptrARB;
+#define GL_BUFFER_SIZE_ARB                0x8764
+#define GL_BUFFER_USAGE_ARB               0x8765
+#define GL_ARRAY_BUFFER_ARB               0x8892
+#define GL_ELEMENT_ARRAY_BUFFER_ARB       0x8893
+#define GL_ARRAY_BUFFER_BINDING_ARB       0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895
+#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896
+#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897
+#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898
+#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899
+#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A
+#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B
+#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C
+#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D
+#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F
+#define GL_READ_ONLY_ARB                  0x88B8
+#define GL_WRITE_ONLY_ARB                 0x88B9
+#define GL_READ_WRITE_ARB                 0x88BA
+#define GL_BUFFER_ACCESS_ARB              0x88BB
+#define GL_BUFFER_MAPPED_ARB              0x88BC
+#define GL_BUFFER_MAP_POINTER_ARB         0x88BD
+#define GL_STREAM_DRAW_ARB                0x88E0
+#define GL_STREAM_READ_ARB                0x88E1
+#define GL_STREAM_COPY_ARB                0x88E2
+#define GL_STATIC_DRAW_ARB                0x88E4
+#define GL_STATIC_READ_ARB                0x88E5
+#define GL_STATIC_COPY_ARB                0x88E6
+#define GL_DYNAMIC_DRAW_ARB               0x88E8
+#define GL_DYNAMIC_READ_ARB               0x88E9
+#define GL_DYNAMIC_COPY_ARB               0x88EA
+typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);
+typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers);
+typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers);
+typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage);
+typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data);
+typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data);
+typedef void *(APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access);
+typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, void **params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindBufferARB (GLenum target, GLuint buffer);
+GLAPI void APIENTRY glDeleteBuffersARB (GLsizei n, const GLuint *buffers);
+GLAPI void APIENTRY glGenBuffersARB (GLsizei n, GLuint *buffers);
+GLAPI GLboolean APIENTRY glIsBufferARB (GLuint buffer);
+GLAPI void APIENTRY glBufferDataARB (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage);
+GLAPI void APIENTRY glBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data);
+GLAPI void APIENTRY glGetBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data);
+GLAPI void *APIENTRY glMapBufferARB (GLenum target, GLenum access);
+GLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum target);
+GLAPI void APIENTRY glGetBufferParameterivARB (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetBufferPointervARB (GLenum target, GLenum pname, void **params);
+#endif
+#endif /* GL_ARB_vertex_buffer_object */
+
+#ifndef GL_ARB_vertex_program
+#define GL_ARB_vertex_program 1
+#define GL_COLOR_SUM_ARB                  0x8458
+#define GL_VERTEX_PROGRAM_ARB             0x8620
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB   0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB   0x8625
+#define GL_CURRENT_VERTEX_ATTRIB_ARB      0x8626
+#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB  0x8642
+#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB    0x8643
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645
+#define GL_MAX_VERTEX_ATTRIBS_ARB         0x8869
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A
+#define GL_PROGRAM_ADDRESS_REGISTERS_ARB  0x88B0
+#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1
+#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2
+#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, void **pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttrib1dARB (GLuint index, GLdouble x);
+GLAPI void APIENTRY glVertexAttrib1dvARB (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib1fARB (GLuint index, GLfloat x);
+GLAPI void APIENTRY glVertexAttrib1fvARB (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib1sARB (GLuint index, GLshort x);
+GLAPI void APIENTRY glVertexAttrib1svARB (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib2dARB (GLuint index, GLdouble x, GLdouble y);
+GLAPI void APIENTRY glVertexAttrib2dvARB (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib2fARB (GLuint index, GLfloat x, GLfloat y);
+GLAPI void APIENTRY glVertexAttrib2fvARB (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib2sARB (GLuint index, GLshort x, GLshort y);
+GLAPI void APIENTRY glVertexAttrib2svARB (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib3dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glVertexAttrib3dvARB (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib3fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glVertexAttrib3fvARB (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib3sARB (GLuint index, GLshort x, GLshort y, GLshort z);
+GLAPI void APIENTRY glVertexAttrib3svARB (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib4NbvARB (GLuint index, const GLbyte *v);
+GLAPI void APIENTRY glVertexAttrib4NivARB (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttrib4NsvARB (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib4NubARB (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+GLAPI void APIENTRY glVertexAttrib4NubvARB (GLuint index, const GLubyte *v);
+GLAPI void APIENTRY glVertexAttrib4NuivARB (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttrib4NusvARB (GLuint index, const GLushort *v);
+GLAPI void APIENTRY glVertexAttrib4bvARB (GLuint index, const GLbyte *v);
+GLAPI void APIENTRY glVertexAttrib4dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glVertexAttrib4dvARB (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib4fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glVertexAttrib4fvARB (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib4ivARB (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttrib4sARB (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+GLAPI void APIENTRY glVertexAttrib4svARB (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint index, const GLubyte *v);
+GLAPI void APIENTRY glVertexAttrib4uivARB (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttrib4usvARB (GLuint index, const GLushort *v);
+GLAPI void APIENTRY glVertexAttribPointerARB (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint index);
+GLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint index);
+GLAPI void APIENTRY glGetVertexAttribdvARB (GLuint index, GLenum pname, GLdouble *params);
+GLAPI void APIENTRY glGetVertexAttribfvARB (GLuint index, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetVertexAttribivARB (GLuint index, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint index, GLenum pname, void **pointer);
+#endif
+#endif /* GL_ARB_vertex_program */
+
+#ifndef GL_ARB_vertex_shader
+#define GL_ARB_vertex_shader 1
+#define GL_VERTEX_SHADER_ARB              0x8B31
+#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A
+#define GL_MAX_VARYING_FLOATS_ARB         0x8B4B
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D
+#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB   0x8B89
+#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A
+typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name);
+typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
+typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB programObj, GLuint index, const GLcharARB *name);
+GLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
+GLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB programObj, const GLcharARB *name);
+#endif
+#endif /* GL_ARB_vertex_shader */
+
+#ifndef GL_ARB_vertex_type_10f_11f_11f_rev
+#define GL_ARB_vertex_type_10f_11f_11f_rev 1
+#endif /* GL_ARB_vertex_type_10f_11f_11f_rev */
+
+#ifndef GL_ARB_vertex_type_2_10_10_10_rev
+#define GL_ARB_vertex_type_2_10_10_10_rev 1
+#endif /* GL_ARB_vertex_type_2_10_10_10_rev */
+
+#ifndef GL_ARB_viewport_array
+#define GL_ARB_viewport_array 1
+#endif /* GL_ARB_viewport_array */
+
+#ifndef GL_ARB_window_pos
+#define GL_ARB_window_pos 1
+typedef void (APIENTRYP PFNGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DVARBPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FVARBPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IARBPROC) (GLint x, GLint y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IVARBPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SVARBPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DVARBPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FVARBPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IVARBPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SVARBPROC) (const GLshort *v);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glWindowPos2dARB (GLdouble x, GLdouble y);
+GLAPI void APIENTRY glWindowPos2dvARB (const GLdouble *v);
+GLAPI void APIENTRY glWindowPos2fARB (GLfloat x, GLfloat y);
+GLAPI void APIENTRY glWindowPos2fvARB (const GLfloat *v);
+GLAPI void APIENTRY glWindowPos2iARB (GLint x, GLint y);
+GLAPI void APIENTRY glWindowPos2ivARB (const GLint *v);
+GLAPI void APIENTRY glWindowPos2sARB (GLshort x, GLshort y);
+GLAPI void APIENTRY glWindowPos2svARB (const GLshort *v);
+GLAPI void APIENTRY glWindowPos3dARB (GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glWindowPos3dvARB (const GLdouble *v);
+GLAPI void APIENTRY glWindowPos3fARB (GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glWindowPos3fvARB (const GLfloat *v);
+GLAPI void APIENTRY glWindowPos3iARB (GLint x, GLint y, GLint z);
+GLAPI void APIENTRY glWindowPos3ivARB (const GLint *v);
+GLAPI void APIENTRY glWindowPos3sARB (GLshort x, GLshort y, GLshort z);
+GLAPI void APIENTRY glWindowPos3svARB (const GLshort *v);
+#endif
+#endif /* GL_ARB_window_pos */
+
+#ifndef GL_KHR_blend_equation_advanced
+#define GL_KHR_blend_equation_advanced 1
+#define GL_MULTIPLY_KHR                   0x9294
+#define GL_SCREEN_KHR                     0x9295
+#define GL_OVERLAY_KHR                    0x9296
+#define GL_DARKEN_KHR                     0x9297
+#define GL_LIGHTEN_KHR                    0x9298
+#define GL_COLORDODGE_KHR                 0x9299
+#define GL_COLORBURN_KHR                  0x929A
+#define GL_HARDLIGHT_KHR                  0x929B
+#define GL_SOFTLIGHT_KHR                  0x929C
+#define GL_DIFFERENCE_KHR                 0x929E
+#define GL_EXCLUSION_KHR                  0x92A0
+#define GL_HSL_HUE_KHR                    0x92AD
+#define GL_HSL_SATURATION_KHR             0x92AE
+#define GL_HSL_COLOR_KHR                  0x92AF
+#define GL_HSL_LUMINOSITY_KHR             0x92B0
+typedef void (APIENTRYP PFNGLBLENDBARRIERKHRPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendBarrierKHR (void);
+#endif
+#endif /* GL_KHR_blend_equation_advanced */
+
+#ifndef GL_KHR_blend_equation_advanced_coherent
+#define GL_KHR_blend_equation_advanced_coherent 1
+#define GL_BLEND_ADVANCED_COHERENT_KHR    0x9285
+#endif /* GL_KHR_blend_equation_advanced_coherent */
+
+#ifndef GL_KHR_context_flush_control
+#define GL_KHR_context_flush_control 1
+#endif /* GL_KHR_context_flush_control */
+
+#ifndef GL_KHR_debug
+#define GL_KHR_debug 1
+#endif /* GL_KHR_debug */
+
+#ifndef GL_KHR_no_error
+#define GL_KHR_no_error 1
+#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR  0x00000008
+#endif /* GL_KHR_no_error */
+
+#ifndef GL_KHR_parallel_shader_compile
+#define GL_KHR_parallel_shader_compile 1
+#define GL_MAX_SHADER_COMPILER_THREADS_KHR 0x91B0
+#define GL_COMPLETION_STATUS_KHR          0x91B1
+typedef void (APIENTRYP PFNGLMAXSHADERCOMPILERTHREADSKHRPROC) (GLuint count);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMaxShaderCompilerThreadsKHR (GLuint count);
+#endif
+#endif /* GL_KHR_parallel_shader_compile */
+
+#ifndef GL_KHR_robust_buffer_access_behavior
+#define GL_KHR_robust_buffer_access_behavior 1
+#endif /* GL_KHR_robust_buffer_access_behavior */
+
+#ifndef GL_KHR_robustness
+#define GL_KHR_robustness 1
+#define GL_CONTEXT_ROBUST_ACCESS          0x90F3
+#endif /* GL_KHR_robustness */
+
+#ifndef GL_KHR_texture_compression_astc_hdr
+#define GL_KHR_texture_compression_astc_hdr 1
+#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR   0x93B0
+#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR   0x93B1
+#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR   0x93B2
+#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR   0x93B3
+#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR   0x93B4
+#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR   0x93B5
+#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR   0x93B6
+#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR   0x93B7
+#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR  0x93B8
+#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR  0x93B9
+#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR  0x93BA
+#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB
+#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC
+#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD
+#endif /* GL_KHR_texture_compression_astc_hdr */
+
+#ifndef GL_KHR_texture_compression_astc_ldr
+#define GL_KHR_texture_compression_astc_ldr 1
+#endif /* GL_KHR_texture_compression_astc_ldr */
+
+#ifndef GL_KHR_texture_compression_astc_sliced_3d
+#define GL_KHR_texture_compression_astc_sliced_3d 1
+#endif /* GL_KHR_texture_compression_astc_sliced_3d */
+
+#ifndef GL_OES_byte_coordinates
+#define GL_OES_byte_coordinates 1
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1BOESPROC) (GLenum texture, GLbyte s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1BVOESPROC) (GLenum texture, const GLbyte *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2BOESPROC) (GLenum texture, GLbyte s, GLbyte t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2BVOESPROC) (GLenum texture, const GLbyte *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3BVOESPROC) (GLenum texture, const GLbyte *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4BVOESPROC) (GLenum texture, const GLbyte *coords);
+typedef void (APIENTRYP PFNGLTEXCOORD1BOESPROC) (GLbyte s);
+typedef void (APIENTRYP PFNGLTEXCOORD1BVOESPROC) (const GLbyte *coords);
+typedef void (APIENTRYP PFNGLTEXCOORD2BOESPROC) (GLbyte s, GLbyte t);
+typedef void (APIENTRYP PFNGLTEXCOORD2BVOESPROC) (const GLbyte *coords);
+typedef void (APIENTRYP PFNGLTEXCOORD3BOESPROC) (GLbyte s, GLbyte t, GLbyte r);
+typedef void (APIENTRYP PFNGLTEXCOORD3BVOESPROC) (const GLbyte *coords);
+typedef void (APIENTRYP PFNGLTEXCOORD4BOESPROC) (GLbyte s, GLbyte t, GLbyte r, GLbyte q);
+typedef void (APIENTRYP PFNGLTEXCOORD4BVOESPROC) (const GLbyte *coords);
+typedef void (APIENTRYP PFNGLVERTEX2BOESPROC) (GLbyte x, GLbyte y);
+typedef void (APIENTRYP PFNGLVERTEX2BVOESPROC) (const GLbyte *coords);
+typedef void (APIENTRYP PFNGLVERTEX3BOESPROC) (GLbyte x, GLbyte y, GLbyte z);
+typedef void (APIENTRYP PFNGLVERTEX3BVOESPROC) (const GLbyte *coords);
+typedef void (APIENTRYP PFNGLVERTEX4BOESPROC) (GLbyte x, GLbyte y, GLbyte z, GLbyte w);
+typedef void (APIENTRYP PFNGLVERTEX4BVOESPROC) (const GLbyte *coords);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiTexCoord1bOES (GLenum texture, GLbyte s);
+GLAPI void APIENTRY glMultiTexCoord1bvOES (GLenum texture, const GLbyte *coords);
+GLAPI void APIENTRY glMultiTexCoord2bOES (GLenum texture, GLbyte s, GLbyte t);
+GLAPI void APIENTRY glMultiTexCoord2bvOES (GLenum texture, const GLbyte *coords);
+GLAPI void APIENTRY glMultiTexCoord3bOES (GLenum texture, GLbyte s, GLbyte t, GLbyte r);
+GLAPI void APIENTRY glMultiTexCoord3bvOES (GLenum texture, const GLbyte *coords);
+GLAPI void APIENTRY glMultiTexCoord4bOES (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q);
+GLAPI void APIENTRY glMultiTexCoord4bvOES (GLenum texture, const GLbyte *coords);
+GLAPI void APIENTRY glTexCoord1bOES (GLbyte s);
+GLAPI void APIENTRY glTexCoord1bvOES (const GLbyte *coords);
+GLAPI void APIENTRY glTexCoord2bOES (GLbyte s, GLbyte t);
+GLAPI void APIENTRY glTexCoord2bvOES (const GLbyte *coords);
+GLAPI void APIENTRY glTexCoord3bOES (GLbyte s, GLbyte t, GLbyte r);
+GLAPI void APIENTRY glTexCoord3bvOES (const GLbyte *coords);
+GLAPI void APIENTRY glTexCoord4bOES (GLbyte s, GLbyte t, GLbyte r, GLbyte q);
+GLAPI void APIENTRY glTexCoord4bvOES (const GLbyte *coords);
+GLAPI void APIENTRY glVertex2bOES (GLbyte x, GLbyte y);
+GLAPI void APIENTRY glVertex2bvOES (const GLbyte *coords);
+GLAPI void APIENTRY glVertex3bOES (GLbyte x, GLbyte y, GLbyte z);
+GLAPI void APIENTRY glVertex3bvOES (const GLbyte *coords);
+GLAPI void APIENTRY glVertex4bOES (GLbyte x, GLbyte y, GLbyte z, GLbyte w);
+GLAPI void APIENTRY glVertex4bvOES (const GLbyte *coords);
+#endif
+#endif /* GL_OES_byte_coordinates */
+
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_OES_compressed_paletted_texture 1
+#define GL_PALETTE4_RGB8_OES              0x8B90
+#define GL_PALETTE4_RGBA8_OES             0x8B91
+#define GL_PALETTE4_R5_G6_B5_OES          0x8B92
+#define GL_PALETTE4_RGBA4_OES             0x8B93
+#define GL_PALETTE4_RGB5_A1_OES           0x8B94
+#define GL_PALETTE8_RGB8_OES              0x8B95
+#define GL_PALETTE8_RGBA8_OES             0x8B96
+#define GL_PALETTE8_R5_G6_B5_OES          0x8B97
+#define GL_PALETTE8_RGBA4_OES             0x8B98
+#define GL_PALETTE8_RGB5_A1_OES           0x8B99
+#endif /* GL_OES_compressed_paletted_texture */
+
+#ifndef GL_OES_fixed_point
+#define GL_OES_fixed_point 1
+typedef khronos_int32_t GLfixed;
+#define GL_FIXED_OES                      0x140C
+typedef void (APIENTRYP PFNGLALPHAFUNCXOESPROC) (GLenum func, GLfixed ref);
+typedef void (APIENTRYP PFNGLCLEARCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+typedef void (APIENTRYP PFNGLCLEARDEPTHXOESPROC) (GLfixed depth);
+typedef void (APIENTRYP PFNGLCLIPPLANEXOESPROC) (GLenum plane, const GLfixed *equation);
+typedef void (APIENTRYP PFNGLCOLOR4XOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+typedef void (APIENTRYP PFNGLDEPTHRANGEXOESPROC) (GLfixed n, GLfixed f);
+typedef void (APIENTRYP PFNGLFOGXOESPROC) (GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLFOGXVOESPROC) (GLenum pname, const GLfixed *param);
+typedef void (APIENTRYP PFNGLFRUSTUMXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
+typedef void (APIENTRYP PFNGLGETCLIPPLANEXOESPROC) (GLenum plane, GLfixed *equation);
+typedef void (APIENTRYP PFNGLGETFIXEDVOESPROC) (GLenum pname, GLfixed *params);
+typedef void (APIENTRYP PFNGLGETTEXENVXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP PFNGLLIGHTMODELXOESPROC) (GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLLIGHTMODELXVOESPROC) (GLenum pname, const GLfixed *param);
+typedef void (APIENTRYP PFNGLLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLLIGHTXVOESPROC) (GLenum light, GLenum pname, const GLfixed *params);
+typedef void (APIENTRYP PFNGLLINEWIDTHXOESPROC) (GLfixed width);
+typedef void (APIENTRYP PFNGLLOADMATRIXXOESPROC) (const GLfixed *m);
+typedef void (APIENTRYP PFNGLMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLMATERIALXVOESPROC) (GLenum face, GLenum pname, const GLfixed *param);
+typedef void (APIENTRYP PFNGLMULTMATRIXXOESPROC) (const GLfixed *m);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+typedef void (APIENTRYP PFNGLNORMAL3XOESPROC) (GLfixed nx, GLfixed ny, GLfixed nz);
+typedef void (APIENTRYP PFNGLORTHOXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERXVOESPROC) (GLenum pname, const GLfixed *params);
+typedef void (APIENTRYP PFNGLPOINTSIZEXOESPROC) (GLfixed size);
+typedef void (APIENTRYP PFNGLPOLYGONOFFSETXOESPROC) (GLfixed factor, GLfixed units);
+typedef void (APIENTRYP PFNGLROTATEXOESPROC) (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
+typedef void (APIENTRYP PFNGLSCALEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);
+typedef void (APIENTRYP PFNGLTEXENVXOESPROC) (GLenum target, GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLTEXENVXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
+typedef void (APIENTRYP PFNGLTEXPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
+typedef void (APIENTRYP PFNGLTRANSLATEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);
+typedef void (APIENTRYP PFNGLACCUMXOESPROC) (GLenum op, GLfixed value);
+typedef void (APIENTRYP PFNGLBITMAPXOESPROC) (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap);
+typedef void (APIENTRYP PFNGLBLENDCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+typedef void (APIENTRYP PFNGLCLEARACCUMXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+typedef void (APIENTRYP PFNGLCOLOR3XOESPROC) (GLfixed red, GLfixed green, GLfixed blue);
+typedef void (APIENTRYP PFNGLCOLOR3XVOESPROC) (const GLfixed *components);
+typedef void (APIENTRYP PFNGLCOLOR4XVOESPROC) (const GLfixed *components);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
+typedef void (APIENTRYP PFNGLEVALCOORD1XOESPROC) (GLfixed u);
+typedef void (APIENTRYP PFNGLEVALCOORD1XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLEVALCOORD2XOESPROC) (GLfixed u, GLfixed v);
+typedef void (APIENTRYP PFNGLEVALCOORD2XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLFEEDBACKBUFFERXOESPROC) (GLsizei n, GLenum type, const GLfixed *buffer);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP PFNGLGETLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP PFNGLGETMAPXVOESPROC) (GLenum target, GLenum query, GLfixed *v);
+typedef void (APIENTRYP PFNGLGETMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLGETPIXELMAPXVPROC) (GLenum map, GLint size, GLfixed *values);
+typedef void (APIENTRYP PFNGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERXVOESPROC) (GLenum target, GLint level, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP PFNGLINDEXXOESPROC) (GLfixed component);
+typedef void (APIENTRYP PFNGLINDEXXVOESPROC) (const GLfixed *component);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXXOESPROC) (const GLfixed *m);
+typedef void (APIENTRYP PFNGLMAP1XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points);
+typedef void (APIENTRYP PFNGLMAP2XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points);
+typedef void (APIENTRYP PFNGLMAPGRID1XOESPROC) (GLint n, GLfixed u1, GLfixed u2);
+typedef void (APIENTRYP PFNGLMAPGRID2XOESPROC) (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXXOESPROC) (const GLfixed *m);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1XOESPROC) (GLenum texture, GLfixed s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1XVOESPROC) (GLenum texture, const GLfixed *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2XOESPROC) (GLenum texture, GLfixed s, GLfixed t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2XVOESPROC) (GLenum texture, const GLfixed *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3XVOESPROC) (GLenum texture, const GLfixed *coords);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4XVOESPROC) (GLenum texture, const GLfixed *coords);
+typedef void (APIENTRYP PFNGLNORMAL3XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLPASSTHROUGHXOESPROC) (GLfixed token);
+typedef void (APIENTRYP PFNGLPIXELMAPXPROC) (GLenum map, GLint size, const GLfixed *values);
+typedef void (APIENTRYP PFNGLPIXELSTOREXPROC) (GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLPIXELTRANSFERXOESPROC) (GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLPIXELZOOMXOESPROC) (GLfixed xfactor, GLfixed yfactor);
+typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESXOESPROC) (GLsizei n, const GLuint *textures, const GLfixed *priorities);
+typedef void (APIENTRYP PFNGLRASTERPOS2XOESPROC) (GLfixed x, GLfixed y);
+typedef void (APIENTRYP PFNGLRASTERPOS2XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLRASTERPOS3XOESPROC) (GLfixed x, GLfixed y, GLfixed z);
+typedef void (APIENTRYP PFNGLRASTERPOS3XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLRASTERPOS4XOESPROC) (GLfixed x, GLfixed y, GLfixed z, GLfixed w);
+typedef void (APIENTRYP PFNGLRASTERPOS4XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLRECTXOESPROC) (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2);
+typedef void (APIENTRYP PFNGLRECTXVOESPROC) (const GLfixed *v1, const GLfixed *v2);
+typedef void (APIENTRYP PFNGLTEXCOORD1XOESPROC) (GLfixed s);
+typedef void (APIENTRYP PFNGLTEXCOORD1XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLTEXCOORD2XOESPROC) (GLfixed s, GLfixed t);
+typedef void (APIENTRYP PFNGLTEXCOORD2XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLTEXCOORD3XOESPROC) (GLfixed s, GLfixed t, GLfixed r);
+typedef void (APIENTRYP PFNGLTEXCOORD3XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLTEXCOORD4XOESPROC) (GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+typedef void (APIENTRYP PFNGLTEXCOORD4XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLTEXGENXOESPROC) (GLenum coord, GLenum pname, GLfixed param);
+typedef void (APIENTRYP PFNGLTEXGENXVOESPROC) (GLenum coord, GLenum pname, const GLfixed *params);
+typedef void (APIENTRYP PFNGLVERTEX2XOESPROC) (GLfixed x);
+typedef void (APIENTRYP PFNGLVERTEX2XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLVERTEX3XOESPROC) (GLfixed x, GLfixed y);
+typedef void (APIENTRYP PFNGLVERTEX3XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP PFNGLVERTEX4XOESPROC) (GLfixed x, GLfixed y, GLfixed z);
+typedef void (APIENTRYP PFNGLVERTEX4XVOESPROC) (const GLfixed *coords);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glAlphaFuncxOES (GLenum func, GLfixed ref);
+GLAPI void APIENTRY glClearColorxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+GLAPI void APIENTRY glClearDepthxOES (GLfixed depth);
+GLAPI void APIENTRY glClipPlanexOES (GLenum plane, const GLfixed *equation);
+GLAPI void APIENTRY glColor4xOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+GLAPI void APIENTRY glDepthRangexOES (GLfixed n, GLfixed f);
+GLAPI void APIENTRY glFogxOES (GLenum pname, GLfixed param);
+GLAPI void APIENTRY glFogxvOES (GLenum pname, const GLfixed *param);
+GLAPI void APIENTRY glFrustumxOES (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
+GLAPI void APIENTRY glGetClipPlanexOES (GLenum plane, GLfixed *equation);
+GLAPI void APIENTRY glGetFixedvOES (GLenum pname, GLfixed *params);
+GLAPI void APIENTRY glGetTexEnvxvOES (GLenum target, GLenum pname, GLfixed *params);
+GLAPI void APIENTRY glGetTexParameterxvOES (GLenum target, GLenum pname, GLfixed *params);
+GLAPI void APIENTRY glLightModelxOES (GLenum pname, GLfixed param);
+GLAPI void APIENTRY glLightModelxvOES (GLenum pname, const GLfixed *param);
+GLAPI void APIENTRY glLightxOES (GLenum light, GLenum pname, GLfixed param);
+GLAPI void APIENTRY glLightxvOES (GLenum light, GLenum pname, const GLfixed *params);
+GLAPI void APIENTRY glLineWidthxOES (GLfixed width);
+GLAPI void APIENTRY glLoadMatrixxOES (const GLfixed *m);
+GLAPI void APIENTRY glMaterialxOES (GLenum face, GLenum pname, GLfixed param);
+GLAPI void APIENTRY glMaterialxvOES (GLenum face, GLenum pname, const GLfixed *param);
+GLAPI void APIENTRY glMultMatrixxOES (const GLfixed *m);
+GLAPI void APIENTRY glMultiTexCoord4xOES (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+GLAPI void APIENTRY glNormal3xOES (GLfixed nx, GLfixed ny, GLfixed nz);
+GLAPI void APIENTRY glOrthoxOES (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
+GLAPI void APIENTRY glPointParameterxvOES (GLenum pname, const GLfixed *params);
+GLAPI void APIENTRY glPointSizexOES (GLfixed size);
+GLAPI void APIENTRY glPolygonOffsetxOES (GLfixed factor, GLfixed units);
+GLAPI void APIENTRY glRotatexOES (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
+GLAPI void APIENTRY glScalexOES (GLfixed x, GLfixed y, GLfixed z);
+GLAPI void APIENTRY glTexEnvxOES (GLenum target, GLenum pname, GLfixed param);
+GLAPI void APIENTRY glTexEnvxvOES (GLenum target, GLenum pname, const GLfixed *params);
+GLAPI void APIENTRY glTexParameterxOES (GLenum target, GLenum pname, GLfixed param);
+GLAPI void APIENTRY glTexParameterxvOES (GLenum target, GLenum pname, const GLfixed *params);
+GLAPI void APIENTRY glTranslatexOES (GLfixed x, GLfixed y, GLfixed z);
+GLAPI void APIENTRY glAccumxOES (GLenum op, GLfixed value);
+GLAPI void APIENTRY glBitmapxOES (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap);
+GLAPI void APIENTRY glBlendColorxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+GLAPI void APIENTRY glClearAccumxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+GLAPI void APIENTRY glColor3xOES (GLfixed red, GLfixed green, GLfixed blue);
+GLAPI void APIENTRY glColor3xvOES (const GLfixed *components);
+GLAPI void APIENTRY glColor4xvOES (const GLfixed *components);
+GLAPI void APIENTRY glConvolutionParameterxOES (GLenum target, GLenum pname, GLfixed param);
+GLAPI void APIENTRY glConvolutionParameterxvOES (GLenum target, GLenum pname, const GLfixed *params);
+GLAPI void APIENTRY glEvalCoord1xOES (GLfixed u);
+GLAPI void APIENTRY glEvalCoord1xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glEvalCoord2xOES (GLfixed u, GLfixed v);
+GLAPI void APIENTRY glEvalCoord2xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glFeedbackBufferxOES (GLsizei n, GLenum type, const GLfixed *buffer);
+GLAPI void APIENTRY glGetConvolutionParameterxvOES (GLenum target, GLenum pname, GLfixed *params);
+GLAPI void APIENTRY glGetHistogramParameterxvOES (GLenum target, GLenum pname, GLfixed *params);
+GLAPI void APIENTRY glGetLightxOES (GLenum light, GLenum pname, GLfixed *params);
+GLAPI void APIENTRY glGetMapxvOES (GLenum target, GLenum query, GLfixed *v);
+GLAPI void APIENTRY glGetMaterialxOES (GLenum face, GLenum pname, GLfixed param);
+GLAPI void APIENTRY glGetPixelMapxv (GLenum map, GLint size, GLfixed *values);
+GLAPI void APIENTRY glGetTexGenxvOES (GLenum coord, GLenum pname, GLfixed *params);
+GLAPI void APIENTRY glGetTexLevelParameterxvOES (GLenum target, GLint level, GLenum pname, GLfixed *params);
+GLAPI void APIENTRY glIndexxOES (GLfixed component);
+GLAPI void APIENTRY glIndexxvOES (const GLfixed *component);
+GLAPI void APIENTRY glLoadTransposeMatrixxOES (const GLfixed *m);
+GLAPI void APIENTRY glMap1xOES (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points);
+GLAPI void APIENTRY glMap2xOES (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points);
+GLAPI void APIENTRY glMapGrid1xOES (GLint n, GLfixed u1, GLfixed u2);
+GLAPI void APIENTRY glMapGrid2xOES (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2);
+GLAPI void APIENTRY glMultTransposeMatrixxOES (const GLfixed *m);
+GLAPI void APIENTRY glMultiTexCoord1xOES (GLenum texture, GLfixed s);
+GLAPI void APIENTRY glMultiTexCoord1xvOES (GLenum texture, const GLfixed *coords);
+GLAPI void APIENTRY glMultiTexCoord2xOES (GLenum texture, GLfixed s, GLfixed t);
+GLAPI void APIENTRY glMultiTexCoord2xvOES (GLenum texture, const GLfixed *coords);
+GLAPI void APIENTRY glMultiTexCoord3xOES (GLenum texture, GLfixed s, GLfixed t, GLfixed r);
+GLAPI void APIENTRY glMultiTexCoord3xvOES (GLenum texture, const GLfixed *coords);
+GLAPI void APIENTRY glMultiTexCoord4xvOES (GLenum texture, const GLfixed *coords);
+GLAPI void APIENTRY glNormal3xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glPassThroughxOES (GLfixed token);
+GLAPI void APIENTRY glPixelMapx (GLenum map, GLint size, const GLfixed *values);
+GLAPI void APIENTRY glPixelStorex (GLenum pname, GLfixed param);
+GLAPI void APIENTRY glPixelTransferxOES (GLenum pname, GLfixed param);
+GLAPI void APIENTRY glPixelZoomxOES (GLfixed xfactor, GLfixed yfactor);
+GLAPI void APIENTRY glPrioritizeTexturesxOES (GLsizei n, const GLuint *textures, const GLfixed *priorities);
+GLAPI void APIENTRY glRasterPos2xOES (GLfixed x, GLfixed y);
+GLAPI void APIENTRY glRasterPos2xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glRasterPos3xOES (GLfixed x, GLfixed y, GLfixed z);
+GLAPI void APIENTRY glRasterPos3xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glRasterPos4xOES (GLfixed x, GLfixed y, GLfixed z, GLfixed w);
+GLAPI void APIENTRY glRasterPos4xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glRectxOES (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2);
+GLAPI void APIENTRY glRectxvOES (const GLfixed *v1, const GLfixed *v2);
+GLAPI void APIENTRY glTexCoord1xOES (GLfixed s);
+GLAPI void APIENTRY glTexCoord1xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glTexCoord2xOES (GLfixed s, GLfixed t);
+GLAPI void APIENTRY glTexCoord2xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glTexCoord3xOES (GLfixed s, GLfixed t, GLfixed r);
+GLAPI void APIENTRY glTexCoord3xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glTexCoord4xOES (GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+GLAPI void APIENTRY glTexCoord4xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glTexGenxOES (GLenum coord, GLenum pname, GLfixed param);
+GLAPI void APIENTRY glTexGenxvOES (GLenum coord, GLenum pname, const GLfixed *params);
+GLAPI void APIENTRY glVertex2xOES (GLfixed x);
+GLAPI void APIENTRY glVertex2xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glVertex3xOES (GLfixed x, GLfixed y);
+GLAPI void APIENTRY glVertex3xvOES (const GLfixed *coords);
+GLAPI void APIENTRY glVertex4xOES (GLfixed x, GLfixed y, GLfixed z);
+GLAPI void APIENTRY glVertex4xvOES (const GLfixed *coords);
+#endif
+#endif /* GL_OES_fixed_point */
+
+#ifndef GL_OES_query_matrix
+#define GL_OES_query_matrix 1
+typedef GLbitfield (APIENTRYP PFNGLQUERYMATRIXXOESPROC) (GLfixed *mantissa, GLint *exponent);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLbitfield APIENTRY glQueryMatrixxOES (GLfixed *mantissa, GLint *exponent);
+#endif
+#endif /* GL_OES_query_matrix */
+
+#ifndef GL_OES_read_format
+#define GL_OES_read_format 1
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B
+#endif /* GL_OES_read_format */
+
+#ifndef GL_OES_single_precision
+#define GL_OES_single_precision 1
+typedef void (APIENTRYP PFNGLCLEARDEPTHFOESPROC) (GLclampf depth);
+typedef void (APIENTRYP PFNGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat *equation);
+typedef void (APIENTRYP PFNGLDEPTHRANGEFOESPROC) (GLclampf n, GLclampf f);
+typedef void (APIENTRYP PFNGLFRUSTUMFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
+typedef void (APIENTRYP PFNGLGETCLIPPLANEFOESPROC) (GLenum plane, GLfloat *equation);
+typedef void (APIENTRYP PFNGLORTHOFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glClearDepthfOES (GLclampf depth);
+GLAPI void APIENTRY glClipPlanefOES (GLenum plane, const GLfloat *equation);
+GLAPI void APIENTRY glDepthRangefOES (GLclampf n, GLclampf f);
+GLAPI void APIENTRY glFrustumfOES (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
+GLAPI void APIENTRY glGetClipPlanefOES (GLenum plane, GLfloat *equation);
+GLAPI void APIENTRY glOrthofOES (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
+#endif
+#endif /* GL_OES_single_precision */
+
+#ifndef GL_3DFX_multisample
+#define GL_3DFX_multisample 1
+#define GL_MULTISAMPLE_3DFX               0x86B2
+#define GL_SAMPLE_BUFFERS_3DFX            0x86B3
+#define GL_SAMPLES_3DFX                   0x86B4
+#define GL_MULTISAMPLE_BIT_3DFX           0x20000000
+#endif /* GL_3DFX_multisample */
+
+#ifndef GL_3DFX_tbuffer
+#define GL_3DFX_tbuffer 1
+typedef void (APIENTRYP PFNGLTBUFFERMASK3DFXPROC) (GLuint mask);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTbufferMask3DFX (GLuint mask);
+#endif
+#endif /* GL_3DFX_tbuffer */
+
+#ifndef GL_3DFX_texture_compression_FXT1
+#define GL_3DFX_texture_compression_FXT1 1
+#define GL_COMPRESSED_RGB_FXT1_3DFX       0x86B0
+#define GL_COMPRESSED_RGBA_FXT1_3DFX      0x86B1
+#endif /* GL_3DFX_texture_compression_FXT1 */
+
+#ifndef GL_AMD_blend_minmax_factor
+#define GL_AMD_blend_minmax_factor 1
+#define GL_FACTOR_MIN_AMD                 0x901C
+#define GL_FACTOR_MAX_AMD                 0x901D
+#endif /* GL_AMD_blend_minmax_factor */
+
+#ifndef GL_AMD_conservative_depth
+#define GL_AMD_conservative_depth 1
+#endif /* GL_AMD_conservative_depth */
+
+#ifndef GL_AMD_debug_output
+#define GL_AMD_debug_output 1
+typedef void (APIENTRY  *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam);
+#define GL_MAX_DEBUG_MESSAGE_LENGTH_AMD   0x9143
+#define GL_MAX_DEBUG_LOGGED_MESSAGES_AMD  0x9144
+#define GL_DEBUG_LOGGED_MESSAGES_AMD      0x9145
+#define GL_DEBUG_SEVERITY_HIGH_AMD        0x9146
+#define GL_DEBUG_SEVERITY_MEDIUM_AMD      0x9147
+#define GL_DEBUG_SEVERITY_LOW_AMD         0x9148
+#define GL_DEBUG_CATEGORY_API_ERROR_AMD   0x9149
+#define GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD 0x914A
+#define GL_DEBUG_CATEGORY_DEPRECATION_AMD 0x914B
+#define GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD 0x914C
+#define GL_DEBUG_CATEGORY_PERFORMANCE_AMD 0x914D
+#define GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD 0x914E
+#define GL_DEBUG_CATEGORY_APPLICATION_AMD 0x914F
+#define GL_DEBUG_CATEGORY_OTHER_AMD       0x9150
+typedef void (APIENTRYP PFNGLDEBUGMESSAGEENABLEAMDPROC) (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTAMDPROC) (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf);
+typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKAMDPROC) (GLDEBUGPROCAMD callback, void *userParam);
+typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGAMDPROC) (GLuint count, GLsizei bufsize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDebugMessageEnableAMD (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+GLAPI void APIENTRY glDebugMessageInsertAMD (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf);
+GLAPI void APIENTRY glDebugMessageCallbackAMD (GLDEBUGPROCAMD callback, void *userParam);
+GLAPI GLuint APIENTRY glGetDebugMessageLogAMD (GLuint count, GLsizei bufsize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message);
+#endif
+#endif /* GL_AMD_debug_output */
+
+#ifndef GL_AMD_depth_clamp_separate
+#define GL_AMD_depth_clamp_separate 1
+#define GL_DEPTH_CLAMP_NEAR_AMD           0x901E
+#define GL_DEPTH_CLAMP_FAR_AMD            0x901F
+#endif /* GL_AMD_depth_clamp_separate */
+
+#ifndef GL_AMD_draw_buffers_blend
+#define GL_AMD_draw_buffers_blend 1
+typedef void (APIENTRYP PFNGLBLENDFUNCINDEXEDAMDPROC) (GLuint buf, GLenum src, GLenum dst);
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+typedef void (APIENTRYP PFNGLBLENDEQUATIONINDEXEDAMDPROC) (GLuint buf, GLenum mode);
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncIndexedAMD (GLuint buf, GLenum src, GLenum dst);
+GLAPI void APIENTRY glBlendFuncSeparateIndexedAMD (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+GLAPI void APIENTRY glBlendEquationIndexedAMD (GLuint buf, GLenum mode);
+GLAPI void APIENTRY glBlendEquationSeparateIndexedAMD (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+#endif
+#endif /* GL_AMD_draw_buffers_blend */
+
+#ifndef GL_AMD_framebuffer_multisample_advanced
+#define GL_AMD_framebuffer_multisample_advanced 1
+#define GL_RENDERBUFFER_STORAGE_SAMPLES_AMD 0x91B2
+#define GL_MAX_COLOR_FRAMEBUFFER_SAMPLES_AMD 0x91B3
+#define GL_MAX_COLOR_FRAMEBUFFER_STORAGE_SAMPLES_AMD 0x91B4
+#define GL_MAX_DEPTH_STENCIL_FRAMEBUFFER_SAMPLES_AMD 0x91B5
+#define GL_NUM_SUPPORTED_MULTISAMPLE_MODES_AMD 0x91B6
+#define GL_SUPPORTED_MULTISAMPLE_MODES_AMD 0x91B7
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEADVANCEDAMDPROC) (GLenum target, GLsizei samples, GLsizei storageSamples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEADVANCEDAMDPROC) (GLuint renderbuffer, GLsizei samples, GLsizei storageSamples, GLenum internalformat, GLsizei width, GLsizei height);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glRenderbufferStorageMultisampleAdvancedAMD (GLenum target, GLsizei samples, GLsizei storageSamples, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleAdvancedAMD (GLuint renderbuffer, GLsizei samples, GLsizei storageSamples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+#endif /* GL_AMD_framebuffer_multisample_advanced */
+
+#ifndef GL_AMD_framebuffer_sample_positions
+#define GL_AMD_framebuffer_sample_positions 1
+#define GL_SUBSAMPLE_DISTANCE_AMD         0x883F
+#define GL_PIXELS_PER_SAMPLE_PATTERN_X_AMD 0x91AE
+#define GL_PIXELS_PER_SAMPLE_PATTERN_Y_AMD 0x91AF
+#define GL_ALL_PIXELS_AMD                 0xFFFFFFFF
+typedef void (APIENTRYP PFNGLFRAMEBUFFERSAMPLEPOSITIONSFVAMDPROC) (GLenum target, GLuint numsamples, GLuint pixelindex, const GLfloat *values);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERSAMPLEPOSITIONSFVAMDPROC) (GLuint framebuffer, GLuint numsamples, GLuint pixelindex, const GLfloat *values);
+typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERFVAMDPROC) (GLenum target, GLenum pname, GLuint numsamples, GLuint pixelindex, GLsizei size, GLfloat *values);
+typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERFVAMDPROC) (GLuint framebuffer, GLenum pname, GLuint numsamples, GLuint pixelindex, GLsizei size, GLfloat *values);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFramebufferSamplePositionsfvAMD (GLenum target, GLuint numsamples, GLuint pixelindex, const GLfloat *values);
+GLAPI void APIENTRY glNamedFramebufferSamplePositionsfvAMD (GLuint framebuffer, GLuint numsamples, GLuint pixelindex, const GLfloat *values);
+GLAPI void APIENTRY glGetFramebufferParameterfvAMD (GLenum target, GLenum pname, GLuint numsamples, GLuint pixelindex, GLsizei size, GLfloat *values);
+GLAPI void APIENTRY glGetNamedFramebufferParameterfvAMD (GLuint framebuffer, GLenum pname, GLuint numsamples, GLuint pixelindex, GLsizei size, GLfloat *values);
+#endif
+#endif /* GL_AMD_framebuffer_sample_positions */
+
+#ifndef GL_AMD_gcn_shader
+#define GL_AMD_gcn_shader 1
+#endif /* GL_AMD_gcn_shader */
+
+#ifndef GL_AMD_gpu_shader_half_float
+#define GL_AMD_gpu_shader_half_float 1
+#define GL_FLOAT16_NV                     0x8FF8
+#define GL_FLOAT16_VEC2_NV                0x8FF9
+#define GL_FLOAT16_VEC3_NV                0x8FFA
+#define GL_FLOAT16_VEC4_NV                0x8FFB
+#define GL_FLOAT16_MAT2_AMD               0x91C5
+#define GL_FLOAT16_MAT3_AMD               0x91C6
+#define GL_FLOAT16_MAT4_AMD               0x91C7
+#define GL_FLOAT16_MAT2x3_AMD             0x91C8
+#define GL_FLOAT16_MAT2x4_AMD             0x91C9
+#define GL_FLOAT16_MAT3x2_AMD             0x91CA
+#define GL_FLOAT16_MAT3x4_AMD             0x91CB
+#define GL_FLOAT16_MAT4x2_AMD             0x91CC
+#define GL_FLOAT16_MAT4x3_AMD             0x91CD
+#endif /* GL_AMD_gpu_shader_half_float */
+
+#ifndef GL_AMD_gpu_shader_int16
+#define GL_AMD_gpu_shader_int16 1
+#endif /* GL_AMD_gpu_shader_int16 */
+
+#ifndef GL_AMD_gpu_shader_int64
+#define GL_AMD_gpu_shader_int64 1
+typedef khronos_int64_t GLint64EXT;
+#define GL_INT64_NV                       0x140E
+#define GL_UNSIGNED_INT64_NV              0x140F
+#define GL_INT8_NV                        0x8FE0
+#define GL_INT8_VEC2_NV                   0x8FE1
+#define GL_INT8_VEC3_NV                   0x8FE2
+#define GL_INT8_VEC4_NV                   0x8FE3
+#define GL_INT16_NV                       0x8FE4
+#define GL_INT16_VEC2_NV                  0x8FE5
+#define GL_INT16_VEC3_NV                  0x8FE6
+#define GL_INT16_VEC4_NV                  0x8FE7
+#define GL_INT64_VEC2_NV                  0x8FE9
+#define GL_INT64_VEC3_NV                  0x8FEA
+#define GL_INT64_VEC4_NV                  0x8FEB
+#define GL_UNSIGNED_INT8_NV               0x8FEC
+#define GL_UNSIGNED_INT8_VEC2_NV          0x8FED
+#define GL_UNSIGNED_INT8_VEC3_NV          0x8FEE
+#define GL_UNSIGNED_INT8_VEC4_NV          0x8FEF
+#define GL_UNSIGNED_INT16_NV              0x8FF0
+#define GL_UNSIGNED_INT16_VEC2_NV         0x8FF1
+#define GL_UNSIGNED_INT16_VEC3_NV         0x8FF2
+#define GL_UNSIGNED_INT16_VEC4_NV         0x8FF3
+#define GL_UNSIGNED_INT64_VEC2_NV         0x8FF5
+#define GL_UNSIGNED_INT64_VEC3_NV         0x8FF6
+#define GL_UNSIGNED_INT64_VEC4_NV         0x8FF7
+typedef void (APIENTRYP PFNGLUNIFORM1I64NVPROC) (GLint location, GLint64EXT x);
+typedef void (APIENTRYP PFNGLUNIFORM2I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y);
+typedef void (APIENTRYP PFNGLUNIFORM3I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z);
+typedef void (APIENTRYP PFNGLUNIFORM4I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);
+typedef void (APIENTRYP PFNGLUNIFORM1I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (APIENTRYP PFNGLUNIFORM2I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (APIENTRYP PFNGLUNIFORM3I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (APIENTRYP PFNGLUNIFORM4I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (APIENTRYP PFNGLUNIFORM1UI64NVPROC) (GLint location, GLuint64EXT x);
+typedef void (APIENTRYP PFNGLUNIFORM2UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y);
+typedef void (APIENTRYP PFNGLUNIFORM3UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);
+typedef void (APIENTRYP PFNGLUNIFORM4UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);
+typedef void (APIENTRYP PFNGLUNIFORM1UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (APIENTRYP PFNGLUNIFORM2UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (APIENTRYP PFNGLUNIFORM3UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (APIENTRYP PFNGLUNIFORM4UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (APIENTRYP PFNGLGETUNIFORMI64VNVPROC) (GLuint program, GLint location, GLint64EXT *params);
+typedef void (APIENTRYP PFNGLGETUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLuint64EXT *params);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64NVPROC) (GLuint program, GLint location, GLint64EXT x);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glUniform1i64NV (GLint location, GLint64EXT x);
+GLAPI void APIENTRY glUniform2i64NV (GLint location, GLint64EXT x, GLint64EXT y);
+GLAPI void APIENTRY glUniform3i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z);
+GLAPI void APIENTRY glUniform4i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);
+GLAPI void APIENTRY glUniform1i64vNV (GLint location, GLsizei count, const GLint64EXT *value);
+GLAPI void APIENTRY glUniform2i64vNV (GLint location, GLsizei count, const GLint64EXT *value);
+GLAPI void APIENTRY glUniform3i64vNV (GLint location, GLsizei count, const GLint64EXT *value);
+GLAPI void APIENTRY glUniform4i64vNV (GLint location, GLsizei count, const GLint64EXT *value);
+GLAPI void APIENTRY glUniform1ui64NV (GLint location, GLuint64EXT x);
+GLAPI void APIENTRY glUniform2ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y);
+GLAPI void APIENTRY glUniform3ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);
+GLAPI void APIENTRY glUniform4ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);
+GLAPI void APIENTRY glUniform1ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value);
+GLAPI void APIENTRY glUniform2ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value);
+GLAPI void APIENTRY glUniform3ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value);
+GLAPI void APIENTRY glUniform4ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value);
+GLAPI void APIENTRY glGetUniformi64vNV (GLuint program, GLint location, GLint64EXT *params);
+GLAPI void APIENTRY glGetUniformui64vNV (GLuint program, GLint location, GLuint64EXT *params);
+GLAPI void APIENTRY glProgramUniform1i64NV (GLuint program, GLint location, GLint64EXT x);
+GLAPI void APIENTRY glProgramUniform2i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y);
+GLAPI void APIENTRY glProgramUniform3i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z);
+GLAPI void APIENTRY glProgramUniform4i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);
+GLAPI void APIENTRY glProgramUniform1i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+GLAPI void APIENTRY glProgramUniform2i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+GLAPI void APIENTRY glProgramUniform3i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+GLAPI void APIENTRY glProgramUniform4i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);
+GLAPI void APIENTRY glProgramUniform1ui64NV (GLuint program, GLint location, GLuint64EXT x);
+GLAPI void APIENTRY glProgramUniform2ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y);
+GLAPI void APIENTRY glProgramUniform3ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);
+GLAPI void APIENTRY glProgramUniform4ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);
+GLAPI void APIENTRY glProgramUniform1ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+GLAPI void APIENTRY glProgramUniform2ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+GLAPI void APIENTRY glProgramUniform3ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+GLAPI void APIENTRY glProgramUniform4ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+#endif
+#endif /* GL_AMD_gpu_shader_int64 */
+
+#ifndef GL_AMD_interleaved_elements
+#define GL_AMD_interleaved_elements 1
+#define GL_VERTEX_ELEMENT_SWIZZLE_AMD     0x91A4
+#define GL_VERTEX_ID_SWIZZLE_AMD          0x91A5
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPARAMETERIAMDPROC) (GLuint index, GLenum pname, GLint param);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttribParameteriAMD (GLuint index, GLenum pname, GLint param);
+#endif
+#endif /* GL_AMD_interleaved_elements */
+
+#ifndef GL_AMD_multi_draw_indirect
+#define GL_AMD_multi_draw_indirect 1
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC) (GLenum mode, const void *indirect, GLsizei primcount, GLsizei stride);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei primcount, GLsizei stride);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiDrawArraysIndirectAMD (GLenum mode, const void *indirect, GLsizei primcount, GLsizei stride);
+GLAPI void APIENTRY glMultiDrawElementsIndirectAMD (GLenum mode, GLenum type, const void *indirect, GLsizei primcount, GLsizei stride);
+#endif
+#endif /* GL_AMD_multi_draw_indirect */
+
+#ifndef GL_AMD_name_gen_delete
+#define GL_AMD_name_gen_delete 1
+#define GL_DATA_BUFFER_AMD                0x9151
+#define GL_PERFORMANCE_MONITOR_AMD        0x9152
+#define GL_QUERY_OBJECT_AMD               0x9153
+#define GL_VERTEX_ARRAY_OBJECT_AMD        0x9154
+#define GL_SAMPLER_OBJECT_AMD             0x9155
+typedef void (APIENTRYP PFNGLGENNAMESAMDPROC) (GLenum identifier, GLuint num, GLuint *names);
+typedef void (APIENTRYP PFNGLDELETENAMESAMDPROC) (GLenum identifier, GLuint num, const GLuint *names);
+typedef GLboolean (APIENTRYP PFNGLISNAMEAMDPROC) (GLenum identifier, GLuint name);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenNamesAMD (GLenum identifier, GLuint num, GLuint *names);
+GLAPI void APIENTRY glDeleteNamesAMD (GLenum identifier, GLuint num, const GLuint *names);
+GLAPI GLboolean APIENTRY glIsNameAMD (GLenum identifier, GLuint name);
+#endif
+#endif /* GL_AMD_name_gen_delete */
+
+#ifndef GL_AMD_occlusion_query_event
+#define GL_AMD_occlusion_query_event 1
+#define GL_OCCLUSION_QUERY_EVENT_MASK_AMD 0x874F
+#define GL_QUERY_DEPTH_PASS_EVENT_BIT_AMD 0x00000001
+#define GL_QUERY_DEPTH_FAIL_EVENT_BIT_AMD 0x00000002
+#define GL_QUERY_STENCIL_FAIL_EVENT_BIT_AMD 0x00000004
+#define GL_QUERY_DEPTH_BOUNDS_FAIL_EVENT_BIT_AMD 0x00000008
+#define GL_QUERY_ALL_EVENT_BITS_AMD       0xFFFFFFFF
+typedef void (APIENTRYP PFNGLQUERYOBJECTPARAMETERUIAMDPROC) (GLenum target, GLuint id, GLenum pname, GLuint param);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glQueryObjectParameteruiAMD (GLenum target, GLuint id, GLenum pname, GLuint param);
+#endif
+#endif /* GL_AMD_occlusion_query_event */
+
+#ifndef GL_AMD_performance_monitor
+#define GL_AMD_performance_monitor 1
+#define GL_COUNTER_TYPE_AMD               0x8BC0
+#define GL_COUNTER_RANGE_AMD              0x8BC1
+#define GL_UNSIGNED_INT64_AMD             0x8BC2
+#define GL_PERCENTAGE_AMD                 0x8BC3
+#define GL_PERFMON_RESULT_AVAILABLE_AMD   0x8BC4
+#define GL_PERFMON_RESULT_SIZE_AMD        0x8BC5
+#define GL_PERFMON_RESULT_AMD             0x8BC6
+typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);
+typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);
+typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, void *data);
+typedef void (APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList);
+typedef void (APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+GLAPI void APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+GLAPI void APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);
+GLAPI void APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);
+GLAPI void APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, void *data);
+GLAPI void APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GLAPI void APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GLAPI void APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList);
+GLAPI void APIENTRY glBeginPerfMonitorAMD (GLuint monitor);
+GLAPI void APIENTRY glEndPerfMonitorAMD (GLuint monitor);
+GLAPI void APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+#endif /* GL_AMD_performance_monitor */
+
+#ifndef GL_AMD_pinned_memory
+#define GL_AMD_pinned_memory 1
+#define GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD 0x9160
+#endif /* GL_AMD_pinned_memory */
+
+#ifndef GL_AMD_query_buffer_object
+#define GL_AMD_query_buffer_object 1
+#define GL_QUERY_BUFFER_AMD               0x9192
+#define GL_QUERY_BUFFER_BINDING_AMD       0x9193
+#define GL_QUERY_RESULT_NO_WAIT_AMD       0x9194
+#endif /* GL_AMD_query_buffer_object */
+
+#ifndef GL_AMD_sample_positions
+#define GL_AMD_sample_positions 1
+typedef void (APIENTRYP PFNGLSETMULTISAMPLEFVAMDPROC) (GLenum pname, GLuint index, const GLfloat *val);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSetMultisamplefvAMD (GLenum pname, GLuint index, const GLfloat *val);
+#endif
+#endif /* GL_AMD_sample_positions */
+
+#ifndef GL_AMD_seamless_cubemap_per_texture
+#define GL_AMD_seamless_cubemap_per_texture 1
+#endif /* GL_AMD_seamless_cubemap_per_texture */
+
+#ifndef GL_AMD_shader_atomic_counter_ops
+#define GL_AMD_shader_atomic_counter_ops 1
+#endif /* GL_AMD_shader_atomic_counter_ops */
+
+#ifndef GL_AMD_shader_ballot
+#define GL_AMD_shader_ballot 1
+#endif /* GL_AMD_shader_ballot */
+
+#ifndef GL_AMD_shader_explicit_vertex_parameter
+#define GL_AMD_shader_explicit_vertex_parameter 1
+#endif /* GL_AMD_shader_explicit_vertex_parameter */
+
+#ifndef GL_AMD_shader_gpu_shader_half_float_fetch
+#define GL_AMD_shader_gpu_shader_half_float_fetch 1
+#endif /* GL_AMD_shader_gpu_shader_half_float_fetch */
+
+#ifndef GL_AMD_shader_image_load_store_lod
+#define GL_AMD_shader_image_load_store_lod 1
+#endif /* GL_AMD_shader_image_load_store_lod */
+
+#ifndef GL_AMD_shader_stencil_export
+#define GL_AMD_shader_stencil_export 1
+#endif /* GL_AMD_shader_stencil_export */
+
+#ifndef GL_AMD_shader_trinary_minmax
+#define GL_AMD_shader_trinary_minmax 1
+#endif /* GL_AMD_shader_trinary_minmax */
+
+#ifndef GL_AMD_sparse_texture
+#define GL_AMD_sparse_texture 1
+#define GL_VIRTUAL_PAGE_SIZE_X_AMD        0x9195
+#define GL_VIRTUAL_PAGE_SIZE_Y_AMD        0x9196
+#define GL_VIRTUAL_PAGE_SIZE_Z_AMD        0x9197
+#define GL_MAX_SPARSE_TEXTURE_SIZE_AMD    0x9198
+#define GL_MAX_SPARSE_3D_TEXTURE_SIZE_AMD 0x9199
+#define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS 0x919A
+#define GL_MIN_SPARSE_LEVEL_AMD           0x919B
+#define GL_MIN_LOD_WARNING_AMD            0x919C
+#define GL_TEXTURE_STORAGE_SPARSE_BIT_AMD 0x00000001
+typedef void (APIENTRYP PFNGLTEXSTORAGESPARSEAMDPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGESPARSEAMDPROC) (GLuint texture, GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexStorageSparseAMD (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags);
+GLAPI void APIENTRY glTextureStorageSparseAMD (GLuint texture, GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags);
+#endif
+#endif /* GL_AMD_sparse_texture */
+
+#ifndef GL_AMD_stencil_operation_extended
+#define GL_AMD_stencil_operation_extended 1
+#define GL_SET_AMD                        0x874A
+#define GL_REPLACE_VALUE_AMD              0x874B
+#define GL_STENCIL_OP_VALUE_AMD           0x874C
+#define GL_STENCIL_BACK_OP_VALUE_AMD      0x874D
+typedef void (APIENTRYP PFNGLSTENCILOPVALUEAMDPROC) (GLenum face, GLuint value);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glStencilOpValueAMD (GLenum face, GLuint value);
+#endif
+#endif /* GL_AMD_stencil_operation_extended */
+
+#ifndef GL_AMD_texture_gather_bias_lod
+#define GL_AMD_texture_gather_bias_lod 1
+#endif /* GL_AMD_texture_gather_bias_lod */
+
+#ifndef GL_AMD_texture_texture4
+#define GL_AMD_texture_texture4 1
+#endif /* GL_AMD_texture_texture4 */
+
+#ifndef GL_AMD_transform_feedback3_lines_triangles
+#define GL_AMD_transform_feedback3_lines_triangles 1
+#endif /* GL_AMD_transform_feedback3_lines_triangles */
+
+#ifndef GL_AMD_transform_feedback4
+#define GL_AMD_transform_feedback4 1
+#define GL_STREAM_RASTERIZATION_AMD       0x91A0
+#endif /* GL_AMD_transform_feedback4 */
+
+#ifndef GL_AMD_vertex_shader_layer
+#define GL_AMD_vertex_shader_layer 1
+#endif /* GL_AMD_vertex_shader_layer */
+
+#ifndef GL_AMD_vertex_shader_tessellator
+#define GL_AMD_vertex_shader_tessellator 1
+#define GL_SAMPLER_BUFFER_AMD             0x9001
+#define GL_INT_SAMPLER_BUFFER_AMD         0x9002
+#define GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD 0x9003
+#define GL_TESSELLATION_MODE_AMD          0x9004
+#define GL_TESSELLATION_FACTOR_AMD        0x9005
+#define GL_DISCRETE_AMD                   0x9006
+#define GL_CONTINUOUS_AMD                 0x9007
+typedef void (APIENTRYP PFNGLTESSELLATIONFACTORAMDPROC) (GLfloat factor);
+typedef void (APIENTRYP PFNGLTESSELLATIONMODEAMDPROC) (GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTessellationFactorAMD (GLfloat factor);
+GLAPI void APIENTRY glTessellationModeAMD (GLenum mode);
+#endif
+#endif /* GL_AMD_vertex_shader_tessellator */
+
+#ifndef GL_AMD_vertex_shader_viewport_index
+#define GL_AMD_vertex_shader_viewport_index 1
+#endif /* GL_AMD_vertex_shader_viewport_index */
+
+#ifndef GL_APPLE_aux_depth_stencil
+#define GL_APPLE_aux_depth_stencil 1
+#define GL_AUX_DEPTH_STENCIL_APPLE        0x8A14
+#endif /* GL_APPLE_aux_depth_stencil */
+
+#ifndef GL_APPLE_client_storage
+#define GL_APPLE_client_storage 1
+#define GL_UNPACK_CLIENT_STORAGE_APPLE    0x85B2
+#endif /* GL_APPLE_client_storage */
+
+#ifndef GL_APPLE_element_array
+#define GL_APPLE_element_array 1
+#define GL_ELEMENT_ARRAY_APPLE            0x8A0C
+#define GL_ELEMENT_ARRAY_TYPE_APPLE       0x8A0D
+#define GL_ELEMENT_ARRAY_POINTER_APPLE    0x8A0E
+typedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const void *pointer);
+typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glElementPointerAPPLE (GLenum type, const void *pointer);
+GLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum mode, GLint first, GLsizei count);
+GLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count);
+GLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
+GLAPI void APIENTRY glMultiDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount);
+#endif
+#endif /* GL_APPLE_element_array */
+
+#ifndef GL_APPLE_fence
+#define GL_APPLE_fence 1
+#define GL_DRAW_PIXELS_APPLE              0x8A0A
+#define GL_FENCE_APPLE                    0x8A0B
+typedef void (APIENTRYP PFNGLGENFENCESAPPLEPROC) (GLsizei n, GLuint *fences);
+typedef void (APIENTRYP PFNGLDELETEFENCESAPPLEPROC) (GLsizei n, const GLuint *fences);
+typedef void (APIENTRYP PFNGLSETFENCEAPPLEPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLISFENCEAPPLEPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLTESTFENCEAPPLEPROC) (GLuint fence);
+typedef void (APIENTRYP PFNGLFINISHFENCEAPPLEPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLTESTOBJECTAPPLEPROC) (GLenum object, GLuint name);
+typedef void (APIENTRYP PFNGLFINISHOBJECTAPPLEPROC) (GLenum object, GLint name);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenFencesAPPLE (GLsizei n, GLuint *fences);
+GLAPI void APIENTRY glDeleteFencesAPPLE (GLsizei n, const GLuint *fences);
+GLAPI void APIENTRY glSetFenceAPPLE (GLuint fence);
+GLAPI GLboolean APIENTRY glIsFenceAPPLE (GLuint fence);
+GLAPI GLboolean APIENTRY glTestFenceAPPLE (GLuint fence);
+GLAPI void APIENTRY glFinishFenceAPPLE (GLuint fence);
+GLAPI GLboolean APIENTRY glTestObjectAPPLE (GLenum object, GLuint name);
+GLAPI void APIENTRY glFinishObjectAPPLE (GLenum object, GLint name);
+#endif
+#endif /* GL_APPLE_fence */
+
+#ifndef GL_APPLE_float_pixels
+#define GL_APPLE_float_pixels 1
+#define GL_HALF_APPLE                     0x140B
+#define GL_RGBA_FLOAT32_APPLE             0x8814
+#define GL_RGB_FLOAT32_APPLE              0x8815
+#define GL_ALPHA_FLOAT32_APPLE            0x8816
+#define GL_INTENSITY_FLOAT32_APPLE        0x8817
+#define GL_LUMINANCE_FLOAT32_APPLE        0x8818
+#define GL_LUMINANCE_ALPHA_FLOAT32_APPLE  0x8819
+#define GL_RGBA_FLOAT16_APPLE             0x881A
+#define GL_RGB_FLOAT16_APPLE              0x881B
+#define GL_ALPHA_FLOAT16_APPLE            0x881C
+#define GL_INTENSITY_FLOAT16_APPLE        0x881D
+#define GL_LUMINANCE_FLOAT16_APPLE        0x881E
+#define GL_LUMINANCE_ALPHA_FLOAT16_APPLE  0x881F
+#define GL_COLOR_FLOAT_APPLE              0x8A0F
+#endif /* GL_APPLE_float_pixels */
+
+#ifndef GL_APPLE_flush_buffer_range
+#define GL_APPLE_flush_buffer_range 1
+#define GL_BUFFER_SERIALIZED_MODIFY_APPLE 0x8A12
+#define GL_BUFFER_FLUSHING_UNMAP_APPLE    0x8A13
+typedef void (APIENTRYP PFNGLBUFFERPARAMETERIAPPLEPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC) (GLenum target, GLintptr offset, GLsizeiptr size);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBufferParameteriAPPLE (GLenum target, GLenum pname, GLint param);
+GLAPI void APIENTRY glFlushMappedBufferRangeAPPLE (GLenum target, GLintptr offset, GLsizeiptr size);
+#endif
+#endif /* GL_APPLE_flush_buffer_range */
+
+#ifndef GL_APPLE_object_purgeable
+#define GL_APPLE_object_purgeable 1
+#define GL_BUFFER_OBJECT_APPLE            0x85B3
+#define GL_RELEASED_APPLE                 0x8A19
+#define GL_VOLATILE_APPLE                 0x8A1A
+#define GL_RETAINED_APPLE                 0x8A1B
+#define GL_UNDEFINED_APPLE                0x8A1C
+#define GL_PURGEABLE_APPLE                0x8A1D
+typedef GLenum (APIENTRYP PFNGLOBJECTPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option);
+typedef GLenum (APIENTRYP PFNGLOBJECTUNPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option);
+typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVAPPLEPROC) (GLenum objectType, GLuint name, GLenum pname, GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLenum APIENTRY glObjectPurgeableAPPLE (GLenum objectType, GLuint name, GLenum option);
+GLAPI GLenum APIENTRY glObjectUnpurgeableAPPLE (GLenum objectType, GLuint name, GLenum option);
+GLAPI void APIENTRY glGetObjectParameterivAPPLE (GLenum objectType, GLuint name, GLenum pname, GLint *params);
+#endif
+#endif /* GL_APPLE_object_purgeable */
+
+#ifndef GL_APPLE_rgb_422
+#define GL_APPLE_rgb_422 1
+#define GL_RGB_422_APPLE                  0x8A1F
+#define GL_UNSIGNED_SHORT_8_8_APPLE       0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_APPLE   0x85BB
+#define GL_RGB_RAW_422_APPLE              0x8A51
+#endif /* GL_APPLE_rgb_422 */
+
+#ifndef GL_APPLE_row_bytes
+#define GL_APPLE_row_bytes 1
+#define GL_PACK_ROW_BYTES_APPLE           0x8A15
+#define GL_UNPACK_ROW_BYTES_APPLE         0x8A16
+#endif /* GL_APPLE_row_bytes */
+
+#ifndef GL_APPLE_specular_vector
+#define GL_APPLE_specular_vector 1
+#define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0
+#endif /* GL_APPLE_specular_vector */
+
+#ifndef GL_APPLE_texture_range
+#define GL_APPLE_texture_range 1
+#define GL_TEXTURE_RANGE_LENGTH_APPLE     0x85B7
+#define GL_TEXTURE_RANGE_POINTER_APPLE    0x85B8
+#define GL_TEXTURE_STORAGE_HINT_APPLE     0x85BC
+#define GL_STORAGE_PRIVATE_APPLE          0x85BD
+#define GL_STORAGE_CACHED_APPLE           0x85BE
+#define GL_STORAGE_SHARED_APPLE           0x85BF
+typedef void (APIENTRYP PFNGLTEXTURERANGEAPPLEPROC) (GLenum target, GLsizei length, const void *pointer);
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERPOINTERVAPPLEPROC) (GLenum target, GLenum pname, void **params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTextureRangeAPPLE (GLenum target, GLsizei length, const void *pointer);
+GLAPI void APIENTRY glGetTexParameterPointervAPPLE (GLenum target, GLenum pname, void **params);
+#endif
+#endif /* GL_APPLE_texture_range */
+
+#ifndef GL_APPLE_transform_hint
+#define GL_APPLE_transform_hint 1
+#define GL_TRANSFORM_HINT_APPLE           0x85B1
+#endif /* GL_APPLE_transform_hint */
+
+#ifndef GL_APPLE_vertex_array_object
+#define GL_APPLE_vertex_array_object 1
+#define GL_VERTEX_ARRAY_BINDING_APPLE     0x85B5
+typedef void (APIENTRYP PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array);
+typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays);
+typedef void (APIENTRYP PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, GLuint *arrays);
+typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindVertexArrayAPPLE (GLuint array);
+GLAPI void APIENTRY glDeleteVertexArraysAPPLE (GLsizei n, const GLuint *arrays);
+GLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei n, GLuint *arrays);
+GLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint array);
+#endif
+#endif /* GL_APPLE_vertex_array_object */
+
+#ifndef GL_APPLE_vertex_array_range
+#define GL_APPLE_vertex_array_range 1
+#define GL_VERTEX_ARRAY_RANGE_APPLE       0x851D
+#define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E
+#define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F
+#define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521
+#define GL_STORAGE_CLIENT_APPLE           0x85B4
+typedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void *pointer);
+typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void *pointer);
+typedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei length, void *pointer);
+GLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei length, void *pointer);
+GLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum pname, GLint param);
+#endif
+#endif /* GL_APPLE_vertex_array_range */
+
+#ifndef GL_APPLE_vertex_program_evaluators
+#define GL_APPLE_vertex_program_evaluators 1
+#define GL_VERTEX_ATTRIB_MAP1_APPLE       0x8A00
+#define GL_VERTEX_ATTRIB_MAP2_APPLE       0x8A01
+#define GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE  0x8A02
+#define GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE 0x8A03
+#define GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE 0x8A04
+#define GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE 0x8A05
+#define GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE  0x8A06
+#define GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE 0x8A07
+#define GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE 0x8A08
+#define GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE 0x8A09
+typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname);
+typedef GLboolean (APIENTRYP PFNGLISVERTEXATTRIBENABLEDAPPLEPROC) (GLuint index, GLenum pname);
+typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points);
+typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points);
+typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points);
+typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glEnableVertexAttribAPPLE (GLuint index, GLenum pname);
+GLAPI void APIENTRY glDisableVertexAttribAPPLE (GLuint index, GLenum pname);
+GLAPI GLboolean APIENTRY glIsVertexAttribEnabledAPPLE (GLuint index, GLenum pname);
+GLAPI void APIENTRY glMapVertexAttrib1dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points);
+GLAPI void APIENTRY glMapVertexAttrib1fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points);
+GLAPI void APIENTRY glMapVertexAttrib2dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points);
+GLAPI void APIENTRY glMapVertexAttrib2fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points);
+#endif
+#endif /* GL_APPLE_vertex_program_evaluators */
+
+#ifndef GL_APPLE_ycbcr_422
+#define GL_APPLE_ycbcr_422 1
+#define GL_YCBCR_422_APPLE                0x85B9
+#endif /* GL_APPLE_ycbcr_422 */
+
+#ifndef GL_ATI_draw_buffers
+#define GL_ATI_draw_buffers 1
+#define GL_MAX_DRAW_BUFFERS_ATI           0x8824
+#define GL_DRAW_BUFFER0_ATI               0x8825
+#define GL_DRAW_BUFFER1_ATI               0x8826
+#define GL_DRAW_BUFFER2_ATI               0x8827
+#define GL_DRAW_BUFFER3_ATI               0x8828
+#define GL_DRAW_BUFFER4_ATI               0x8829
+#define GL_DRAW_BUFFER5_ATI               0x882A
+#define GL_DRAW_BUFFER6_ATI               0x882B
+#define GL_DRAW_BUFFER7_ATI               0x882C
+#define GL_DRAW_BUFFER8_ATI               0x882D
+#define GL_DRAW_BUFFER9_ATI               0x882E
+#define GL_DRAW_BUFFER10_ATI              0x882F
+#define GL_DRAW_BUFFER11_ATI              0x8830
+#define GL_DRAW_BUFFER12_ATI              0x8831
+#define GL_DRAW_BUFFER13_ATI              0x8832
+#define GL_DRAW_BUFFER14_ATI              0x8833
+#define GL_DRAW_BUFFER15_ATI              0x8834
+typedef void (APIENTRYP PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum *bufs);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawBuffersATI (GLsizei n, const GLenum *bufs);
+#endif
+#endif /* GL_ATI_draw_buffers */
+
+#ifndef GL_ATI_element_array
+#define GL_ATI_element_array 1
+#define GL_ELEMENT_ARRAY_ATI              0x8768
+#define GL_ELEMENT_ARRAY_TYPE_ATI         0x8769
+#define GL_ELEMENT_ARRAY_POINTER_ATI      0x876A
+typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const void *pointer);
+typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count);
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glElementPointerATI (GLenum type, const void *pointer);
+GLAPI void APIENTRY glDrawElementArrayATI (GLenum mode, GLsizei count);
+GLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum mode, GLuint start, GLuint end, GLsizei count);
+#endif
+#endif /* GL_ATI_element_array */
+
+#ifndef GL_ATI_envmap_bumpmap
+#define GL_ATI_envmap_bumpmap 1
+#define GL_BUMP_ROT_MATRIX_ATI            0x8775
+#define GL_BUMP_ROT_MATRIX_SIZE_ATI       0x8776
+#define GL_BUMP_NUM_TEX_UNITS_ATI         0x8777
+#define GL_BUMP_TEX_UNITS_ATI             0x8778
+#define GL_DUDV_ATI                       0x8779
+#define GL_DU8DV8_ATI                     0x877A
+#define GL_BUMP_ENVMAP_ATI                0x877B
+#define GL_BUMP_TARGET_ATI                0x877C
+typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, const GLint *param);
+typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERFVATIPROC) (GLenum pname, const GLfloat *param);
+typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint *param);
+typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERFVATIPROC) (GLenum pname, GLfloat *param);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexBumpParameterivATI (GLenum pname, const GLint *param);
+GLAPI void APIENTRY glTexBumpParameterfvATI (GLenum pname, const GLfloat *param);
+GLAPI void APIENTRY glGetTexBumpParameterivATI (GLenum pname, GLint *param);
+GLAPI void APIENTRY glGetTexBumpParameterfvATI (GLenum pname, GLfloat *param);
+#endif
+#endif /* GL_ATI_envmap_bumpmap */
+
+#ifndef GL_ATI_fragment_shader
+#define GL_ATI_fragment_shader 1
+#define GL_FRAGMENT_SHADER_ATI            0x8920
+#define GL_REG_0_ATI                      0x8921
+#define GL_REG_1_ATI                      0x8922
+#define GL_REG_2_ATI                      0x8923
+#define GL_REG_3_ATI                      0x8924
+#define GL_REG_4_ATI                      0x8925
+#define GL_REG_5_ATI                      0x8926
+#define GL_REG_6_ATI                      0x8927
+#define GL_REG_7_ATI                      0x8928
+#define GL_REG_8_ATI                      0x8929
+#define GL_REG_9_ATI                      0x892A
+#define GL_REG_10_ATI                     0x892B
+#define GL_REG_11_ATI                     0x892C
+#define GL_REG_12_ATI                     0x892D
+#define GL_REG_13_ATI                     0x892E
+#define GL_REG_14_ATI                     0x892F
+#define GL_REG_15_ATI                     0x8930
+#define GL_REG_16_ATI                     0x8931
+#define GL_REG_17_ATI                     0x8932
+#define GL_REG_18_ATI                     0x8933
+#define GL_REG_19_ATI                     0x8934
+#define GL_REG_20_ATI                     0x8935
+#define GL_REG_21_ATI                     0x8936
+#define GL_REG_22_ATI                     0x8937
+#define GL_REG_23_ATI                     0x8938
+#define GL_REG_24_ATI                     0x8939
+#define GL_REG_25_ATI                     0x893A
+#define GL_REG_26_ATI                     0x893B
+#define GL_REG_27_ATI                     0x893C
+#define GL_REG_28_ATI                     0x893D
+#define GL_REG_29_ATI                     0x893E
+#define GL_REG_30_ATI                     0x893F
+#define GL_REG_31_ATI                     0x8940
+#define GL_CON_0_ATI                      0x8941
+#define GL_CON_1_ATI                      0x8942
+#define GL_CON_2_ATI                      0x8943
+#define GL_CON_3_ATI                      0x8944
+#define GL_CON_4_ATI                      0x8945
+#define GL_CON_5_ATI                      0x8946
+#define GL_CON_6_ATI                      0x8947
+#define GL_CON_7_ATI                      0x8948
+#define GL_CON_8_ATI                      0x8949
+#define GL_CON_9_ATI                      0x894A
+#define GL_CON_10_ATI                     0x894B
+#define GL_CON_11_ATI                     0x894C
+#define GL_CON_12_ATI                     0x894D
+#define GL_CON_13_ATI                     0x894E
+#define GL_CON_14_ATI                     0x894F
+#define GL_CON_15_ATI                     0x8950
+#define GL_CON_16_ATI                     0x8951
+#define GL_CON_17_ATI                     0x8952
+#define GL_CON_18_ATI                     0x8953
+#define GL_CON_19_ATI                     0x8954
+#define GL_CON_20_ATI                     0x8955
+#define GL_CON_21_ATI                     0x8956
+#define GL_CON_22_ATI                     0x8957
+#define GL_CON_23_ATI                     0x8958
+#define GL_CON_24_ATI                     0x8959
+#define GL_CON_25_ATI                     0x895A
+#define GL_CON_26_ATI                     0x895B
+#define GL_CON_27_ATI                     0x895C
+#define GL_CON_28_ATI                     0x895D
+#define GL_CON_29_ATI                     0x895E
+#define GL_CON_30_ATI                     0x895F
+#define GL_CON_31_ATI                     0x8960
+#define GL_MOV_ATI                        0x8961
+#define GL_ADD_ATI                        0x8963
+#define GL_MUL_ATI                        0x8964
+#define GL_SUB_ATI                        0x8965
+#define GL_DOT3_ATI                       0x8966
+#define GL_DOT4_ATI                       0x8967
+#define GL_MAD_ATI                        0x8968
+#define GL_LERP_ATI                       0x8969
+#define GL_CND_ATI                        0x896A
+#define GL_CND0_ATI                       0x896B
+#define GL_DOT2_ADD_ATI                   0x896C
+#define GL_SECONDARY_INTERPOLATOR_ATI     0x896D
+#define GL_NUM_FRAGMENT_REGISTERS_ATI     0x896E
+#define GL_NUM_FRAGMENT_CONSTANTS_ATI     0x896F
+#define GL_NUM_PASSES_ATI                 0x8970
+#define GL_NUM_INSTRUCTIONS_PER_PASS_ATI  0x8971
+#define GL_NUM_INSTRUCTIONS_TOTAL_ATI     0x8972
+#define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973
+#define GL_NUM_LOOPBACK_COMPONENTS_ATI    0x8974
+#define GL_COLOR_ALPHA_PAIRING_ATI        0x8975
+#define GL_SWIZZLE_STR_ATI                0x8976
+#define GL_SWIZZLE_STQ_ATI                0x8977
+#define GL_SWIZZLE_STR_DR_ATI             0x8978
+#define GL_SWIZZLE_STQ_DQ_ATI             0x8979
+#define GL_SWIZZLE_STRQ_ATI               0x897A
+#define GL_SWIZZLE_STRQ_DQ_ATI            0x897B
+#define GL_RED_BIT_ATI                    0x00000001
+#define GL_GREEN_BIT_ATI                  0x00000002
+#define GL_BLUE_BIT_ATI                   0x00000004
+#define GL_2X_BIT_ATI                     0x00000001
+#define GL_4X_BIT_ATI                     0x00000002
+#define GL_8X_BIT_ATI                     0x00000004
+#define GL_HALF_BIT_ATI                   0x00000008
+#define GL_QUARTER_BIT_ATI                0x00000010
+#define GL_EIGHTH_BIT_ATI                 0x00000020
+#define GL_SATURATE_BIT_ATI               0x00000040
+#define GL_COMP_BIT_ATI                   0x00000002
+#define GL_NEGATE_BIT_ATI                 0x00000004
+#define GL_BIAS_BIT_ATI                   0x00000008
+typedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC) (GLuint range);
+typedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC) (void);
+typedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC) (void);
+typedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC) (GLuint dst, GLuint coord, GLenum swizzle);
+typedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC) (GLuint dst, GLuint interp, GLenum swizzle);
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);
+typedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, const GLfloat *value);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLuint APIENTRY glGenFragmentShadersATI (GLuint range);
+GLAPI void APIENTRY glBindFragmentShaderATI (GLuint id);
+GLAPI void APIENTRY glDeleteFragmentShaderATI (GLuint id);
+GLAPI void APIENTRY glBeginFragmentShaderATI (void);
+GLAPI void APIENTRY glEndFragmentShaderATI (void);
+GLAPI void APIENTRY glPassTexCoordATI (GLuint dst, GLuint coord, GLenum swizzle);
+GLAPI void APIENTRY glSampleMapATI (GLuint dst, GLuint interp, GLenum swizzle);
+GLAPI void APIENTRY glColorFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);
+GLAPI void APIENTRY glColorFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);
+GLAPI void APIENTRY glColorFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);
+GLAPI void APIENTRY glAlphaFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);
+GLAPI void APIENTRY glAlphaFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);
+GLAPI void APIENTRY glAlphaFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);
+GLAPI void APIENTRY glSetFragmentShaderConstantATI (GLuint dst, const GLfloat *value);
+#endif
+#endif /* GL_ATI_fragment_shader */
+
+#ifndef GL_ATI_map_object_buffer
+#define GL_ATI_map_object_buffer 1
+typedef void *(APIENTRYP PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void *APIENTRY glMapObjectBufferATI (GLuint buffer);
+GLAPI void APIENTRY glUnmapObjectBufferATI (GLuint buffer);
+#endif
+#endif /* GL_ATI_map_object_buffer */
+
+#ifndef GL_ATI_meminfo
+#define GL_ATI_meminfo 1
+#define GL_VBO_FREE_MEMORY_ATI            0x87FB
+#define GL_TEXTURE_FREE_MEMORY_ATI        0x87FC
+#define GL_RENDERBUFFER_FREE_MEMORY_ATI   0x87FD
+#endif /* GL_ATI_meminfo */
+
+#ifndef GL_ATI_pixel_format_float
+#define GL_ATI_pixel_format_float 1
+#define GL_RGBA_FLOAT_MODE_ATI            0x8820
+#define GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835
+#endif /* GL_ATI_pixel_format_float */
+
+#ifndef GL_ATI_pn_triangles
+#define GL_ATI_pn_triangles 1
+#define GL_PN_TRIANGLES_ATI               0x87F0
+#define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1
+#define GL_PN_TRIANGLES_POINT_MODE_ATI    0x87F2
+#define GL_PN_TRIANGLES_NORMAL_MODE_ATI   0x87F3
+#define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4
+#define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5
+#define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6
+#define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7
+#define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8
+typedef void (APIENTRYP PFNGLPNTRIANGLESIATIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPNTRIANGLESFATIPROC) (GLenum pname, GLfloat param);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPNTrianglesiATI (GLenum pname, GLint param);
+GLAPI void APIENTRY glPNTrianglesfATI (GLenum pname, GLfloat param);
+#endif
+#endif /* GL_ATI_pn_triangles */
+
+#ifndef GL_ATI_separate_stencil
+#define GL_ATI_separate_stencil 1
+#define GL_STENCIL_BACK_FUNC_ATI          0x8800
+#define GL_STENCIL_BACK_FAIL_ATI          0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803
+typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEATIPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEATIPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glStencilOpSeparateATI (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+GLAPI void APIENTRY glStencilFuncSeparateATI (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask);
+#endif
+#endif /* GL_ATI_separate_stencil */
+
+#ifndef GL_ATI_text_fragment_shader
+#define GL_ATI_text_fragment_shader 1
+#define GL_TEXT_FRAGMENT_SHADER_ATI       0x8200
+#endif /* GL_ATI_text_fragment_shader */
+
+#ifndef GL_ATI_texture_env_combine3
+#define GL_ATI_texture_env_combine3 1
+#define GL_MODULATE_ADD_ATI               0x8744
+#define GL_MODULATE_SIGNED_ADD_ATI        0x8745
+#define GL_MODULATE_SUBTRACT_ATI          0x8746
+#endif /* GL_ATI_texture_env_combine3 */
+
+#ifndef GL_ATI_texture_float
+#define GL_ATI_texture_float 1
+#define GL_RGBA_FLOAT32_ATI               0x8814
+#define GL_RGB_FLOAT32_ATI                0x8815
+#define GL_ALPHA_FLOAT32_ATI              0x8816
+#define GL_INTENSITY_FLOAT32_ATI          0x8817
+#define GL_LUMINANCE_FLOAT32_ATI          0x8818
+#define GL_LUMINANCE_ALPHA_FLOAT32_ATI    0x8819
+#define GL_RGBA_FLOAT16_ATI               0x881A
+#define GL_RGB_FLOAT16_ATI                0x881B
+#define GL_ALPHA_FLOAT16_ATI              0x881C
+#define GL_INTENSITY_FLOAT16_ATI          0x881D
+#define GL_LUMINANCE_FLOAT16_ATI          0x881E
+#define GL_LUMINANCE_ALPHA_FLOAT16_ATI    0x881F
+#endif /* GL_ATI_texture_float */
+
+#ifndef GL_ATI_texture_mirror_once
+#define GL_ATI_texture_mirror_once 1
+#define GL_MIRROR_CLAMP_ATI               0x8742
+#define GL_MIRROR_CLAMP_TO_EDGE_ATI       0x8743
+#endif /* GL_ATI_texture_mirror_once */
+
+#ifndef GL_ATI_vertex_array_object
+#define GL_ATI_vertex_array_object 1
+#define GL_STATIC_ATI                     0x8760
+#define GL_DYNAMIC_ATI                    0x8761
+#define GL_PRESERVE_ATI                   0x8762
+#define GL_DISCARD_ATI                    0x8763
+#define GL_OBJECT_BUFFER_SIZE_ATI         0x8764
+#define GL_OBJECT_BUFFER_USAGE_ATI        0x8765
+#define GL_ARRAY_OBJECT_BUFFER_ATI        0x8766
+#define GL_ARRAY_OBJECT_OFFSET_ATI        0x8767
+typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const void *pointer, GLenum usage);
+typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const void *pointer, GLenum preserve);
+typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);
+typedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC) (GLenum array, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC) (GLenum array, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);
+typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei size, const void *pointer, GLenum usage);
+GLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint buffer);
+GLAPI void APIENTRY glUpdateObjectBufferATI (GLuint buffer, GLuint offset, GLsizei size, const void *pointer, GLenum preserve);
+GLAPI void APIENTRY glGetObjectBufferfvATI (GLuint buffer, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetObjectBufferivATI (GLuint buffer, GLenum pname, GLint *params);
+GLAPI void APIENTRY glFreeObjectBufferATI (GLuint buffer);
+GLAPI void APIENTRY glArrayObjectATI (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);
+GLAPI void APIENTRY glGetArrayObjectfvATI (GLenum array, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetArrayObjectivATI (GLenum array, GLenum pname, GLint *params);
+GLAPI void APIENTRY glVariantArrayObjectATI (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);
+GLAPI void APIENTRY glGetVariantArrayObjectfvATI (GLuint id, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetVariantArrayObjectivATI (GLuint id, GLenum pname, GLint *params);
+#endif
+#endif /* GL_ATI_vertex_array_object */
+
+#ifndef GL_ATI_vertex_attrib_array_object
+#define GL_ATI_vertex_attrib_array_object 1
+typedef void (APIENTRYP PFNGLVERTEXATTRIBARRAYOBJECTATIPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC) (GLuint index, GLenum pname, GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttribArrayObjectATI (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset);
+GLAPI void APIENTRY glGetVertexAttribArrayObjectfvATI (GLuint index, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetVertexAttribArrayObjectivATI (GLuint index, GLenum pname, GLint *params);
+#endif
+#endif /* GL_ATI_vertex_attrib_array_object */
+
+#ifndef GL_ATI_vertex_streams
+#define GL_ATI_vertex_streams 1
+#define GL_MAX_VERTEX_STREAMS_ATI         0x876B
+#define GL_VERTEX_STREAM0_ATI             0x876C
+#define GL_VERTEX_STREAM1_ATI             0x876D
+#define GL_VERTEX_STREAM2_ATI             0x876E
+#define GL_VERTEX_STREAM3_ATI             0x876F
+#define GL_VERTEX_STREAM4_ATI             0x8770
+#define GL_VERTEX_STREAM5_ATI             0x8771
+#define GL_VERTEX_STREAM6_ATI             0x8772
+#define GL_VERTEX_STREAM7_ATI             0x8773
+#define GL_VERTEX_SOURCE_ATI              0x8774
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1SATIPROC) (GLenum stream, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1IATIPROC) (GLenum stream, GLint x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1FATIPROC) (GLenum stream, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1DATIPROC) (GLenum stream, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2SATIPROC) (GLenum stream, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2IATIPROC) (GLenum stream, GLint x, GLint y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2FATIPROC) (GLenum stream, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2DATIPROC) (GLenum stream, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3IATIPROC) (GLenum stream, GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4IATIPROC) (GLenum stream, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3BATIPROC) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3BVATIPROC) (GLenum stream, const GLbyte *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3SATIPROC) (GLenum stream, GLshort nx, GLshort ny, GLshort nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3IATIPROC) (GLenum stream, GLint nx, GLint ny, GLint nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3FATIPROC) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3DATIPROC) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC) (GLenum stream);
+typedef void (APIENTRYP PFNGLVERTEXBLENDENVIATIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLVERTEXBLENDENVFATIPROC) (GLenum pname, GLfloat param);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexStream1sATI (GLenum stream, GLshort x);
+GLAPI void APIENTRY glVertexStream1svATI (GLenum stream, const GLshort *coords);
+GLAPI void APIENTRY glVertexStream1iATI (GLenum stream, GLint x);
+GLAPI void APIENTRY glVertexStream1ivATI (GLenum stream, const GLint *coords);
+GLAPI void APIENTRY glVertexStream1fATI (GLenum stream, GLfloat x);
+GLAPI void APIENTRY glVertexStream1fvATI (GLenum stream, const GLfloat *coords);
+GLAPI void APIENTRY glVertexStream1dATI (GLenum stream, GLdouble x);
+GLAPI void APIENTRY glVertexStream1dvATI (GLenum stream, const GLdouble *coords);
+GLAPI void APIENTRY glVertexStream2sATI (GLenum stream, GLshort x, GLshort y);
+GLAPI void APIENTRY glVertexStream2svATI (GLenum stream, const GLshort *coords);
+GLAPI void APIENTRY glVertexStream2iATI (GLenum stream, GLint x, GLint y);
+GLAPI void APIENTRY glVertexStream2ivATI (GLenum stream, const GLint *coords);
+GLAPI void APIENTRY glVertexStream2fATI (GLenum stream, GLfloat x, GLfloat y);
+GLAPI void APIENTRY glVertexStream2fvATI (GLenum stream, const GLfloat *coords);
+GLAPI void APIENTRY glVertexStream2dATI (GLenum stream, GLdouble x, GLdouble y);
+GLAPI void APIENTRY glVertexStream2dvATI (GLenum stream, const GLdouble *coords);
+GLAPI void APIENTRY glVertexStream3sATI (GLenum stream, GLshort x, GLshort y, GLshort z);
+GLAPI void APIENTRY glVertexStream3svATI (GLenum stream, const GLshort *coords);
+GLAPI void APIENTRY glVertexStream3iATI (GLenum stream, GLint x, GLint y, GLint z);
+GLAPI void APIENTRY glVertexStream3ivATI (GLenum stream, const GLint *coords);
+GLAPI void APIENTRY glVertexStream3fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glVertexStream3fvATI (GLenum stream, const GLfloat *coords);
+GLAPI void APIENTRY glVertexStream3dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glVertexStream3dvATI (GLenum stream, const GLdouble *coords);
+GLAPI void APIENTRY glVertexStream4sATI (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w);
+GLAPI void APIENTRY glVertexStream4svATI (GLenum stream, const GLshort *coords);
+GLAPI void APIENTRY glVertexStream4iATI (GLenum stream, GLint x, GLint y, GLint z, GLint w);
+GLAPI void APIENTRY glVertexStream4ivATI (GLenum stream, const GLint *coords);
+GLAPI void APIENTRY glVertexStream4fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glVertexStream4fvATI (GLenum stream, const GLfloat *coords);
+GLAPI void APIENTRY glVertexStream4dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glVertexStream4dvATI (GLenum stream, const GLdouble *coords);
+GLAPI void APIENTRY glNormalStream3bATI (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz);
+GLAPI void APIENTRY glNormalStream3bvATI (GLenum stream, const GLbyte *coords);
+GLAPI void APIENTRY glNormalStream3sATI (GLenum stream, GLshort nx, GLshort ny, GLshort nz);
+GLAPI void APIENTRY glNormalStream3svATI (GLenum stream, const GLshort *coords);
+GLAPI void APIENTRY glNormalStream3iATI (GLenum stream, GLint nx, GLint ny, GLint nz);
+GLAPI void APIENTRY glNormalStream3ivATI (GLenum stream, const GLint *coords);
+GLAPI void APIENTRY glNormalStream3fATI (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz);
+GLAPI void APIENTRY glNormalStream3fvATI (GLenum stream, const GLfloat *coords);
+GLAPI void APIENTRY glNormalStream3dATI (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz);
+GLAPI void APIENTRY glNormalStream3dvATI (GLenum stream, const GLdouble *coords);
+GLAPI void APIENTRY glClientActiveVertexStreamATI (GLenum stream);
+GLAPI void APIENTRY glVertexBlendEnviATI (GLenum pname, GLint param);
+GLAPI void APIENTRY glVertexBlendEnvfATI (GLenum pname, GLfloat param);
+#endif
+#endif /* GL_ATI_vertex_streams */
+
+#ifndef GL_EXT_422_pixels
+#define GL_EXT_422_pixels 1
+#define GL_422_EXT                        0x80CC
+#define GL_422_REV_EXT                    0x80CD
+#define GL_422_AVERAGE_EXT                0x80CE
+#define GL_422_REV_AVERAGE_EXT            0x80CF
+#endif /* GL_EXT_422_pixels */
+
+#ifndef GL_EXT_EGL_image_storage
+#define GL_EXT_EGL_image_storage 1
+typedef void *GLeglImageOES;
+typedef void (APIENTRYP PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC) (GLenum target, GLeglImageOES image, const GLint* attrib_list);
+typedef void (APIENTRYP PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC) (GLuint texture, GLeglImageOES image, const GLint* attrib_list);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glEGLImageTargetTexStorageEXT (GLenum target, GLeglImageOES image, const GLint* attrib_list);
+GLAPI void APIENTRY glEGLImageTargetTextureStorageEXT (GLuint texture, GLeglImageOES image, const GLint* attrib_list);
+#endif
+#endif /* GL_EXT_EGL_image_storage */
+
+#ifndef GL_EXT_abgr
+#define GL_EXT_abgr 1
+#define GL_ABGR_EXT                       0x8000
+#endif /* GL_EXT_abgr */
+
+#ifndef GL_EXT_bgra
+#define GL_EXT_bgra 1
+#define GL_BGR_EXT                        0x80E0
+#define GL_BGRA_EXT                       0x80E1
+#endif /* GL_EXT_bgra */
+
+#ifndef GL_EXT_bindable_uniform
+#define GL_EXT_bindable_uniform 1
+#define GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT 0x8DE2
+#define GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT 0x8DE3
+#define GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT 0x8DE4
+#define GL_MAX_BINDABLE_UNIFORM_SIZE_EXT  0x8DED
+#define GL_UNIFORM_BUFFER_EXT             0x8DEE
+#define GL_UNIFORM_BUFFER_BINDING_EXT     0x8DEF
+typedef void (APIENTRYP PFNGLUNIFORMBUFFEREXTPROC) (GLuint program, GLint location, GLuint buffer);
+typedef GLint (APIENTRYP PFNGLGETUNIFORMBUFFERSIZEEXTPROC) (GLuint program, GLint location);
+typedef GLintptr (APIENTRYP PFNGLGETUNIFORMOFFSETEXTPROC) (GLuint program, GLint location);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glUniformBufferEXT (GLuint program, GLint location, GLuint buffer);
+GLAPI GLint APIENTRY glGetUniformBufferSizeEXT (GLuint program, GLint location);
+GLAPI GLintptr APIENTRY glGetUniformOffsetEXT (GLuint program, GLint location);
+#endif
+#endif /* GL_EXT_bindable_uniform */
+
+#ifndef GL_EXT_blend_color
+#define GL_EXT_blend_color 1
+#define GL_CONSTANT_COLOR_EXT             0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR_EXT   0x8002
+#define GL_CONSTANT_ALPHA_EXT             0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA_EXT   0x8004
+#define GL_BLEND_COLOR_EXT                0x8005
+typedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendColorEXT (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+#endif
+#endif /* GL_EXT_blend_color */
+
+#ifndef GL_EXT_blend_equation_separate
+#define GL_EXT_blend_equation_separate 1
+#define GL_BLEND_EQUATION_RGB_EXT         0x8009
+#define GL_BLEND_EQUATION_ALPHA_EXT       0x883D
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationSeparateEXT (GLenum modeRGB, GLenum modeAlpha);
+#endif
+#endif /* GL_EXT_blend_equation_separate */
+
+#ifndef GL_EXT_blend_func_separate
+#define GL_EXT_blend_func_separate 1
+#define GL_BLEND_DST_RGB_EXT              0x80C8
+#define GL_BLEND_SRC_RGB_EXT              0x80C9
+#define GL_BLEND_DST_ALPHA_EXT            0x80CA
+#define GL_BLEND_SRC_ALPHA_EXT            0x80CB
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncSeparateEXT (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+#endif
+#endif /* GL_EXT_blend_func_separate */
+
+#ifndef GL_EXT_blend_logic_op
+#define GL_EXT_blend_logic_op 1
+#endif /* GL_EXT_blend_logic_op */
+
+#ifndef GL_EXT_blend_minmax
+#define GL_EXT_blend_minmax 1
+#define GL_MIN_EXT                        0x8007
+#define GL_MAX_EXT                        0x8008
+#define GL_FUNC_ADD_EXT                   0x8006
+#define GL_BLEND_EQUATION_EXT             0x8009
+typedef void (APIENTRYP PFNGLBLENDEQUATIONEXTPROC) (GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationEXT (GLenum mode);
+#endif
+#endif /* GL_EXT_blend_minmax */
+
+#ifndef GL_EXT_blend_subtract
+#define GL_EXT_blend_subtract 1
+#define GL_FUNC_SUBTRACT_EXT              0x800A
+#define GL_FUNC_REVERSE_SUBTRACT_EXT      0x800B
+#endif /* GL_EXT_blend_subtract */
+
+#ifndef GL_EXT_clip_volume_hint
+#define GL_EXT_clip_volume_hint 1
+#define GL_CLIP_VOLUME_CLIPPING_HINT_EXT  0x80F0
+#endif /* GL_EXT_clip_volume_hint */
+
+#ifndef GL_EXT_cmyka
+#define GL_EXT_cmyka 1
+#define GL_CMYK_EXT                       0x800C
+#define GL_CMYKA_EXT                      0x800D
+#define GL_PACK_CMYK_HINT_EXT             0x800E
+#define GL_UNPACK_CMYK_HINT_EXT           0x800F
+#endif /* GL_EXT_cmyka */
+
+#ifndef GL_EXT_color_subtable
+#define GL_EXT_color_subtable 1
+typedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorSubTableEXT (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data);
+GLAPI void APIENTRY glCopyColorSubTableEXT (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+#endif
+#endif /* GL_EXT_color_subtable */
+
+#ifndef GL_EXT_compiled_vertex_array
+#define GL_EXT_compiled_vertex_array 1
+#define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT   0x81A8
+#define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT   0x81A9
+typedef void (APIENTRYP PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLUNLOCKARRAYSEXTPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glLockArraysEXT (GLint first, GLsizei count);
+GLAPI void APIENTRY glUnlockArraysEXT (void);
+#endif
+#endif /* GL_EXT_compiled_vertex_array */
+
+#ifndef GL_EXT_convolution
+#define GL_EXT_convolution 1
+#define GL_CONVOLUTION_1D_EXT             0x8010
+#define GL_CONVOLUTION_2D_EXT             0x8011
+#define GL_SEPARABLE_2D_EXT               0x8012
+#define GL_CONVOLUTION_BORDER_MODE_EXT    0x8013
+#define GL_CONVOLUTION_FILTER_SCALE_EXT   0x8014
+#define GL_CONVOLUTION_FILTER_BIAS_EXT    0x8015
+#define GL_REDUCE_EXT                     0x8016
+#define GL_CONVOLUTION_FORMAT_EXT         0x8017
+#define GL_CONVOLUTION_WIDTH_EXT          0x8018
+#define GL_CONVOLUTION_HEIGHT_EXT         0x8019
+#define GL_MAX_CONVOLUTION_WIDTH_EXT      0x801A
+#define GL_MAX_CONVOLUTION_HEIGHT_EXT     0x801B
+#define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C
+#define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D
+#define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E
+#define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F
+#define GL_POST_CONVOLUTION_RED_BIAS_EXT  0x8020
+#define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021
+#define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022
+#define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void *image);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span);
+typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image);
+GLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image);
+GLAPI void APIENTRY glConvolutionParameterfEXT (GLenum target, GLenum pname, GLfloat params);
+GLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glConvolutionParameteriEXT (GLenum target, GLenum pname, GLint params);
+GLAPI void APIENTRY glConvolutionParameterivEXT (GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+GLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum target, GLenum format, GLenum type, void *image);
+GLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetSeparableFilterEXT (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span);
+GLAPI void APIENTRY glSeparableFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column);
+#endif
+#endif /* GL_EXT_convolution */
+
+#ifndef GL_EXT_coordinate_frame
+#define GL_EXT_coordinate_frame 1
+#define GL_TANGENT_ARRAY_EXT              0x8439
+#define GL_BINORMAL_ARRAY_EXT             0x843A
+#define GL_CURRENT_TANGENT_EXT            0x843B
+#define GL_CURRENT_BINORMAL_EXT           0x843C
+#define GL_TANGENT_ARRAY_TYPE_EXT         0x843E
+#define GL_TANGENT_ARRAY_STRIDE_EXT       0x843F
+#define GL_BINORMAL_ARRAY_TYPE_EXT        0x8440
+#define GL_BINORMAL_ARRAY_STRIDE_EXT      0x8441
+#define GL_TANGENT_ARRAY_POINTER_EXT      0x8442
+#define GL_BINORMAL_ARRAY_POINTER_EXT     0x8443
+#define GL_MAP1_TANGENT_EXT               0x8444
+#define GL_MAP2_TANGENT_EXT               0x8445
+#define GL_MAP1_BINORMAL_EXT              0x8446
+#define GL_MAP2_BINORMAL_EXT              0x8447
+typedef void (APIENTRYP PFNGLTANGENT3BEXTPROC) (GLbyte tx, GLbyte ty, GLbyte tz);
+typedef void (APIENTRYP PFNGLTANGENT3BVEXTPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLTANGENT3DEXTPROC) (GLdouble tx, GLdouble ty, GLdouble tz);
+typedef void (APIENTRYP PFNGLTANGENT3DVEXTPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLTANGENT3FEXTPROC) (GLfloat tx, GLfloat ty, GLfloat tz);
+typedef void (APIENTRYP PFNGLTANGENT3FVEXTPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLTANGENT3IEXTPROC) (GLint tx, GLint ty, GLint tz);
+typedef void (APIENTRYP PFNGLTANGENT3IVEXTPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLTANGENT3SEXTPROC) (GLshort tx, GLshort ty, GLshort tz);
+typedef void (APIENTRYP PFNGLTANGENT3SVEXTPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLBINORMAL3BEXTPROC) (GLbyte bx, GLbyte by, GLbyte bz);
+typedef void (APIENTRYP PFNGLBINORMAL3BVEXTPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLBINORMAL3DEXTPROC) (GLdouble bx, GLdouble by, GLdouble bz);
+typedef void (APIENTRYP PFNGLBINORMAL3DVEXTPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLBINORMAL3FEXTPROC) (GLfloat bx, GLfloat by, GLfloat bz);
+typedef void (APIENTRYP PFNGLBINORMAL3FVEXTPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz);
+typedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz);
+typedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTangent3bEXT (GLbyte tx, GLbyte ty, GLbyte tz);
+GLAPI void APIENTRY glTangent3bvEXT (const GLbyte *v);
+GLAPI void APIENTRY glTangent3dEXT (GLdouble tx, GLdouble ty, GLdouble tz);
+GLAPI void APIENTRY glTangent3dvEXT (const GLdouble *v);
+GLAPI void APIENTRY glTangent3fEXT (GLfloat tx, GLfloat ty, GLfloat tz);
+GLAPI void APIENTRY glTangent3fvEXT (const GLfloat *v);
+GLAPI void APIENTRY glTangent3iEXT (GLint tx, GLint ty, GLint tz);
+GLAPI void APIENTRY glTangent3ivEXT (const GLint *v);
+GLAPI void APIENTRY glTangent3sEXT (GLshort tx, GLshort ty, GLshort tz);
+GLAPI void APIENTRY glTangent3svEXT (const GLshort *v);
+GLAPI void APIENTRY glBinormal3bEXT (GLbyte bx, GLbyte by, GLbyte bz);
+GLAPI void APIENTRY glBinormal3bvEXT (const GLbyte *v);
+GLAPI void APIENTRY glBinormal3dEXT (GLdouble bx, GLdouble by, GLdouble bz);
+GLAPI void APIENTRY glBinormal3dvEXT (const GLdouble *v);
+GLAPI void APIENTRY glBinormal3fEXT (GLfloat bx, GLfloat by, GLfloat bz);
+GLAPI void APIENTRY glBinormal3fvEXT (const GLfloat *v);
+GLAPI void APIENTRY glBinormal3iEXT (GLint bx, GLint by, GLint bz);
+GLAPI void APIENTRY glBinormal3ivEXT (const GLint *v);
+GLAPI void APIENTRY glBinormal3sEXT (GLshort bx, GLshort by, GLshort bz);
+GLAPI void APIENTRY glBinormal3svEXT (const GLshort *v);
+GLAPI void APIENTRY glTangentPointerEXT (GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glBinormalPointerEXT (GLenum type, GLsizei stride, const void *pointer);
+#endif
+#endif /* GL_EXT_coordinate_frame */
+
+#ifndef GL_EXT_copy_texture
+#define GL_EXT_copy_texture 1
+typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCopyTexImage1DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+GLAPI void APIENTRY glCopyTexImage2DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GLAPI void APIENTRY glCopyTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+GLAPI void APIENTRY glCopyTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glCopyTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+#endif
+#endif /* GL_EXT_copy_texture */
+
+#ifndef GL_EXT_cull_vertex
+#define GL_EXT_cull_vertex 1
+#define GL_CULL_VERTEX_EXT                0x81AA
+#define GL_CULL_VERTEX_EYE_POSITION_EXT   0x81AB
+#define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC
+typedef void (APIENTRYP PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCullParameterdvEXT (GLenum pname, GLdouble *params);
+GLAPI void APIENTRY glCullParameterfvEXT (GLenum pname, GLfloat *params);
+#endif
+#endif /* GL_EXT_cull_vertex */
+
+#ifndef GL_EXT_debug_label
+#define GL_EXT_debug_label 1
+#define GL_PROGRAM_PIPELINE_OBJECT_EXT    0x8A4F
+#define GL_PROGRAM_OBJECT_EXT             0x8B40
+#define GL_SHADER_OBJECT_EXT              0x8B48
+#define GL_BUFFER_OBJECT_EXT              0x9151
+#define GL_QUERY_OBJECT_EXT               0x9153
+#define GL_VERTEX_ARRAY_OBJECT_EXT        0x9154
+typedef void (APIENTRYP PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label);
+typedef void (APIENTRYP PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glLabelObjectEXT (GLenum type, GLuint object, GLsizei length, const GLchar *label);
+GLAPI void APIENTRY glGetObjectLabelEXT (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+#endif
+#endif /* GL_EXT_debug_label */
+
+#ifndef GL_EXT_debug_marker
+#define GL_EXT_debug_marker 1
+typedef void (APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker);
+GLAPI void APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker);
+GLAPI void APIENTRY glPopGroupMarkerEXT (void);
+#endif
+#endif /* GL_EXT_debug_marker */
+
+#ifndef GL_EXT_depth_bounds_test
+#define GL_EXT_depth_bounds_test 1
+#define GL_DEPTH_BOUNDS_TEST_EXT          0x8890
+#define GL_DEPTH_BOUNDS_EXT               0x8891
+typedef void (APIENTRYP PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zmax);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDepthBoundsEXT (GLclampd zmin, GLclampd zmax);
+#endif
+#endif /* GL_EXT_depth_bounds_test */
+
+#ifndef GL_EXT_direct_state_access
+#define GL_EXT_direct_state_access 1
+#define GL_PROGRAM_MATRIX_EXT             0x8E2D
+#define GL_TRANSPOSE_PROGRAM_MATRIX_EXT   0x8E2E
+#define GL_PROGRAM_MATRIX_STACK_DEPTH_EXT 0x8E2F
+typedef void (APIENTRYP PFNGLMATRIXLOADFEXTPROC) (GLenum mode, const GLfloat *m);
+typedef void (APIENTRYP PFNGLMATRIXLOADDEXTPROC) (GLenum mode, const GLdouble *m);
+typedef void (APIENTRYP PFNGLMATRIXMULTFEXTPROC) (GLenum mode, const GLfloat *m);
+typedef void (APIENTRYP PFNGLMATRIXMULTDEXTPROC) (GLenum mode, const GLdouble *m);
+typedef void (APIENTRYP PFNGLMATRIXLOADIDENTITYEXTPROC) (GLenum mode);
+typedef void (APIENTRYP PFNGLMATRIXROTATEFEXTPROC) (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLMATRIXROTATEDEXTPROC) (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLMATRIXSCALEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLMATRIXSCALEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLMATRIXTRANSLATEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLMATRIXTRANSLATEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLMATRIXFRUSTUMEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+typedef void (APIENTRYP PFNGLMATRIXORTHOEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+typedef void (APIENTRYP PFNGLMATRIXPOPEXTPROC) (GLenum mode);
+typedef void (APIENTRYP PFNGLMATRIXPUSHEXTPROC) (GLenum mode);
+typedef void (APIENTRYP PFNGLCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask);
+typedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask);
+typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void *pixels);
+typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLBINDMULTITEXTUREEXTPROC) (GLenum texunit, GLenum target, GLuint texture);
+typedef void (APIENTRYP PFNGLMULTITEXCOORDPOINTEREXTPROC) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLMULTITEXENVFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLMULTITEXENVIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLMULTITEXGENDEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble param);
+typedef void (APIENTRYP PFNGLMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params);
+typedef void (APIENTRYP PFNGLMULTITEXGENFEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLMULTITEXGENIEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void *pixels);
+typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLENABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index);
+typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index);
+typedef void (APIENTRYP PFNGLGETFLOATINDEXEDVEXTPROC) (GLenum target, GLuint index, GLfloat *data);
+typedef void (APIENTRYP PFNGLGETDOUBLEINDEXEDVEXTPROC) (GLenum target, GLuint index, GLdouble *data);
+typedef void (APIENTRYP PFNGLGETPOINTERINDEXEDVEXTPROC) (GLenum target, GLuint index, void **data);
+typedef void (APIENTRYP PFNGLENABLEINDEXEDEXTPROC) (GLenum target, GLuint index);
+typedef void (APIENTRYP PFNGLDISABLEINDEXEDEXTPROC) (GLenum target, GLuint index);
+typedef GLboolean (APIENTRYP PFNGLISENABLEDINDEXEDEXTPROC) (GLenum target, GLuint index);
+typedef void (APIENTRYP PFNGLGETINTEGERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLint *data);
+typedef void (APIENTRYP PFNGLGETBOOLEANINDEXEDVEXTPROC) (GLenum target, GLuint index, GLboolean *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint lod, void *img);
+typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint lod, void *img);
+typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m);
+typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m);
+typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m);
+typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m);
+typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage);
+typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);
+typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFEREXTPROC) (GLuint buffer, GLenum access);
+typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFEREXTPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC) (GLuint buffer, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVEXTPROC) (GLuint buffer, GLenum pname, void **params);
+typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLTEXTUREBUFFEREXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer);
+typedef void (APIENTRYP PFNGLMULTITEXBUFFEREXTPROC) (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer);
+typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLuint *params);
+typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLuint *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IEXTPROC) (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLint *params);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLuint *params);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params);
+typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLint *params);
+typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint *params);
+typedef void (APIENTRYP PFNGLENABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint index);
+typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint index);
+typedef void (APIENTRYP PFNGLGETFLOATI_VEXTPROC) (GLenum pname, GLuint index, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, void **params);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum format, GLsizei len, const void *string);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLdouble *params);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMIVEXTPROC) (GLuint program, GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum pname, void *string);
+typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC) (GLuint renderbuffer, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC) (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC) (GLuint framebuffer, GLenum target);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE2DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE3DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPEXTPROC) (GLuint texture, GLenum target);
+typedef void (APIENTRYP PFNGLGENERATEMULTITEXMIPMAPEXTPROC) (GLenum texunit, GLenum target);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFEREXTPROC) (GLuint framebuffer, GLenum mode);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERREADBUFFEREXTPROC) (GLuint framebuffer, GLenum mode);
+typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLNAMEDCOPYBUFFERSUBDATAEXTPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYEREXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREFACEEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face);
+typedef void (APIENTRYP PFNGLTEXTURERENDERBUFFEREXTPROC) (GLuint texture, GLenum target, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLMULTITEXRENDERBUFFEREXTPROC) (GLenum texunit, GLenum target, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYEDGEFLAGOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYINDEXOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYNORMALOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYTEXCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYMULTITEXCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYFOGCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYSECONDARYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYEXTPROC) (GLuint vaobj, GLenum array);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYEXTPROC) (GLuint vaobj, GLenum array);
+typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index);
+typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERVEXTPROC) (GLuint vaobj, GLenum pname, GLint *param);
+typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERVEXTPROC) (GLuint vaobj, GLenum pname, void **param);
+typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param);
+typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, void **param);
+typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);
+typedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length);
+typedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags);
+typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIEXTPROC) (GLuint framebuffer, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DEXTPROC) (GLuint program, GLint location, GLdouble x);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP PFNGLTEXTUREBUFFERRANGEEXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+typedef void (APIENTRYP PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (APIENTRYP PFNGLTEXTUREPAGECOMMITMENTEXTPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);
+typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBDIVISOREXTPROC) (GLuint vaobj, GLuint index, GLuint divisor);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMatrixLoadfEXT (GLenum mode, const GLfloat *m);
+GLAPI void APIENTRY glMatrixLoaddEXT (GLenum mode, const GLdouble *m);
+GLAPI void APIENTRY glMatrixMultfEXT (GLenum mode, const GLfloat *m);
+GLAPI void APIENTRY glMatrixMultdEXT (GLenum mode, const GLdouble *m);
+GLAPI void APIENTRY glMatrixLoadIdentityEXT (GLenum mode);
+GLAPI void APIENTRY glMatrixRotatefEXT (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glMatrixRotatedEXT (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glMatrixScalefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glMatrixScaledEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glMatrixTranslatefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glMatrixTranslatedEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glMatrixFrustumEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+GLAPI void APIENTRY glMatrixOrthoEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
+GLAPI void APIENTRY glMatrixPopEXT (GLenum mode);
+GLAPI void APIENTRY glMatrixPushEXT (GLenum mode);
+GLAPI void APIENTRY glClientAttribDefaultEXT (GLbitfield mask);
+GLAPI void APIENTRY glPushClientAttribDefaultEXT (GLbitfield mask);
+GLAPI void APIENTRY glTextureParameterfEXT (GLuint texture, GLenum target, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glTextureParameteriEXT (GLuint texture, GLenum target, GLenum pname, GLint param);
+GLAPI void APIENTRY glTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glCopyTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+GLAPI void APIENTRY glCopyTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GLAPI void APIENTRY glCopyTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+GLAPI void APIENTRY glCopyTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glGetTextureImageEXT (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void *pixels);
+GLAPI void APIENTRY glGetTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetTextureLevelParameterfvEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetTextureLevelParameterivEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params);
+GLAPI void APIENTRY glTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glCopyTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glBindMultiTextureEXT (GLenum texunit, GLenum target, GLuint texture);
+GLAPI void APIENTRY glMultiTexCoordPointerEXT (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glMultiTexEnvfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glMultiTexEnviEXT (GLenum texunit, GLenum target, GLenum pname, GLint param);
+GLAPI void APIENTRY glMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glMultiTexGendEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble param);
+GLAPI void APIENTRY glMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params);
+GLAPI void APIENTRY glMultiTexGenfEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glMultiTexGeniEXT (GLenum texunit, GLenum coord, GLenum pname, GLint param);
+GLAPI void APIENTRY glMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glGetMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params);
+GLAPI void APIENTRY glGetMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, GLint *params);
+GLAPI void APIENTRY glMultiTexParameteriEXT (GLenum texunit, GLenum target, GLenum pname, GLint param);
+GLAPI void APIENTRY glMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glMultiTexParameterfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glCopyMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+GLAPI void APIENTRY glCopyMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GLAPI void APIENTRY glCopyMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+GLAPI void APIENTRY glCopyMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glGetMultiTexImageEXT (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void *pixels);
+GLAPI void APIENTRY glGetMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetMultiTexLevelParameterfvEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetMultiTexLevelParameterivEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params);
+GLAPI void APIENTRY glMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glCopyMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glEnableClientStateIndexedEXT (GLenum array, GLuint index);
+GLAPI void APIENTRY glDisableClientStateIndexedEXT (GLenum array, GLuint index);
+GLAPI void APIENTRY glGetFloatIndexedvEXT (GLenum target, GLuint index, GLfloat *data);
+GLAPI void APIENTRY glGetDoubleIndexedvEXT (GLenum target, GLuint index, GLdouble *data);
+GLAPI void APIENTRY glGetPointerIndexedvEXT (GLenum target, GLuint index, void **data);
+GLAPI void APIENTRY glEnableIndexedEXT (GLenum target, GLuint index);
+GLAPI void APIENTRY glDisableIndexedEXT (GLenum target, GLuint index);
+GLAPI GLboolean APIENTRY glIsEnabledIndexedEXT (GLenum target, GLuint index);
+GLAPI void APIENTRY glGetIntegerIndexedvEXT (GLenum target, GLuint index, GLint *data);
+GLAPI void APIENTRY glGetBooleanIndexedvEXT (GLenum target, GLuint index, GLboolean *data);
+GLAPI void APIENTRY glCompressedTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glGetCompressedTextureImageEXT (GLuint texture, GLenum target, GLint lod, void *img);
+GLAPI void APIENTRY glCompressedMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glCompressedMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits);
+GLAPI void APIENTRY glGetCompressedMultiTexImageEXT (GLenum texunit, GLenum target, GLint lod, void *img);
+GLAPI void APIENTRY glMatrixLoadTransposefEXT (GLenum mode, const GLfloat *m);
+GLAPI void APIENTRY glMatrixLoadTransposedEXT (GLenum mode, const GLdouble *m);
+GLAPI void APIENTRY glMatrixMultTransposefEXT (GLenum mode, const GLfloat *m);
+GLAPI void APIENTRY glMatrixMultTransposedEXT (GLenum mode, const GLdouble *m);
+GLAPI void APIENTRY glNamedBufferDataEXT (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage);
+GLAPI void APIENTRY glNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);
+GLAPI void *APIENTRY glMapNamedBufferEXT (GLuint buffer, GLenum access);
+GLAPI GLboolean APIENTRY glUnmapNamedBufferEXT (GLuint buffer);
+GLAPI void APIENTRY glGetNamedBufferParameterivEXT (GLuint buffer, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetNamedBufferPointervEXT (GLuint buffer, GLenum pname, void **params);
+GLAPI void APIENTRY glGetNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data);
+GLAPI void APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat v0);
+GLAPI void APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1);
+GLAPI void APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+GLAPI void APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+GLAPI void APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint v0);
+GLAPI void APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint v0, GLint v1);
+GLAPI void APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
+GLAPI void APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+GLAPI void APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GLAPI void APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix2x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix3x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix2x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix4x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix3x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glProgramUniformMatrix4x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GLAPI void APIENTRY glTextureBufferEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer);
+GLAPI void APIENTRY glMultiTexBufferEXT (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer);
+GLAPI void APIENTRY glTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, const GLuint *params);
+GLAPI void APIENTRY glGetTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, GLuint *params);
+GLAPI void APIENTRY glMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, const GLuint *params);
+GLAPI void APIENTRY glGetMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, GLuint *params);
+GLAPI void APIENTRY glProgramUniform1uiEXT (GLuint program, GLint location, GLuint v0);
+GLAPI void APIENTRY glProgramUniform2uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1);
+GLAPI void APIENTRY glProgramUniform3uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
+GLAPI void APIENTRY glProgramUniform4uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+GLAPI void APIENTRY glProgramUniform1uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glProgramUniform2uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glProgramUniform3uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glProgramUniform4uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glNamedProgramLocalParameters4fvEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params);
+GLAPI void APIENTRY glNamedProgramLocalParameterI4iEXT (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);
+GLAPI void APIENTRY glNamedProgramLocalParameterI4ivEXT (GLuint program, GLenum target, GLuint index, const GLint *params);
+GLAPI void APIENTRY glNamedProgramLocalParametersI4ivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params);
+GLAPI void APIENTRY glNamedProgramLocalParameterI4uiEXT (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+GLAPI void APIENTRY glNamedProgramLocalParameterI4uivEXT (GLuint program, GLenum target, GLuint index, const GLuint *params);
+GLAPI void APIENTRY glNamedProgramLocalParametersI4uivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params);
+GLAPI void APIENTRY glGetNamedProgramLocalParameterIivEXT (GLuint program, GLenum target, GLuint index, GLint *params);
+GLAPI void APIENTRY glGetNamedProgramLocalParameterIuivEXT (GLuint program, GLenum target, GLuint index, GLuint *params);
+GLAPI void APIENTRY glEnableClientStateiEXT (GLenum array, GLuint index);
+GLAPI void APIENTRY glDisableClientStateiEXT (GLenum array, GLuint index);
+GLAPI void APIENTRY glGetFloati_vEXT (GLenum pname, GLuint index, GLfloat *params);
+GLAPI void APIENTRY glGetDoublei_vEXT (GLenum pname, GLuint index, GLdouble *params);
+GLAPI void APIENTRY glGetPointeri_vEXT (GLenum pname, GLuint index, void **params);
+GLAPI void APIENTRY glNamedProgramStringEXT (GLuint program, GLenum target, GLenum format, GLsizei len, const void *string);
+GLAPI void APIENTRY glNamedProgramLocalParameter4dEXT (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glNamedProgramLocalParameter4dvEXT (GLuint program, GLenum target, GLuint index, const GLdouble *params);
+GLAPI void APIENTRY glNamedProgramLocalParameter4fEXT (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glNamedProgramLocalParameter4fvEXT (GLuint program, GLenum target, GLuint index, const GLfloat *params);
+GLAPI void APIENTRY glGetNamedProgramLocalParameterdvEXT (GLuint program, GLenum target, GLuint index, GLdouble *params);
+GLAPI void APIENTRY glGetNamedProgramLocalParameterfvEXT (GLuint program, GLenum target, GLuint index, GLfloat *params);
+GLAPI void APIENTRY glGetNamedProgramivEXT (GLuint program, GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetNamedProgramStringEXT (GLuint program, GLenum target, GLenum pname, void *string);
+GLAPI void APIENTRY glNamedRenderbufferStorageEXT (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glGetNamedRenderbufferParameterivEXT (GLuint renderbuffer, GLenum pname, GLint *params);
+GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleEXT (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleCoverageEXT (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI GLenum APIENTRY glCheckNamedFramebufferStatusEXT (GLuint framebuffer, GLenum target);
+GLAPI void APIENTRY glNamedFramebufferTexture1DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLAPI void APIENTRY glNamedFramebufferTexture2DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLAPI void APIENTRY glNamedFramebufferTexture3DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+GLAPI void APIENTRY glNamedFramebufferRenderbufferEXT (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GLAPI void APIENTRY glGetNamedFramebufferAttachmentParameterivEXT (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGenerateTextureMipmapEXT (GLuint texture, GLenum target);
+GLAPI void APIENTRY glGenerateMultiTexMipmapEXT (GLenum texunit, GLenum target);
+GLAPI void APIENTRY glFramebufferDrawBufferEXT (GLuint framebuffer, GLenum mode);
+GLAPI void APIENTRY glFramebufferDrawBuffersEXT (GLuint framebuffer, GLsizei n, const GLenum *bufs);
+GLAPI void APIENTRY glFramebufferReadBufferEXT (GLuint framebuffer, GLenum mode);
+GLAPI void APIENTRY glGetFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params);
+GLAPI void APIENTRY glNamedCopyBufferSubDataEXT (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+GLAPI void APIENTRY glNamedFramebufferTextureEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level);
+GLAPI void APIENTRY glNamedFramebufferTextureLayerEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer);
+GLAPI void APIENTRY glNamedFramebufferTextureFaceEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face);
+GLAPI void APIENTRY glTextureRenderbufferEXT (GLuint texture, GLenum target, GLuint renderbuffer);
+GLAPI void APIENTRY glMultiTexRenderbufferEXT (GLenum texunit, GLenum target, GLuint renderbuffer);
+GLAPI void APIENTRY glVertexArrayVertexOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArrayColorOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArrayEdgeFlagOffsetEXT (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArrayIndexOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArrayNormalOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArrayTexCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArrayMultiTexCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArrayFogCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArraySecondaryColorOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArrayVertexAttribOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glVertexArrayVertexAttribIOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glEnableVertexArrayEXT (GLuint vaobj, GLenum array);
+GLAPI void APIENTRY glDisableVertexArrayEXT (GLuint vaobj, GLenum array);
+GLAPI void APIENTRY glEnableVertexArrayAttribEXT (GLuint vaobj, GLuint index);
+GLAPI void APIENTRY glDisableVertexArrayAttribEXT (GLuint vaobj, GLuint index);
+GLAPI void APIENTRY glGetVertexArrayIntegervEXT (GLuint vaobj, GLenum pname, GLint *param);
+GLAPI void APIENTRY glGetVertexArrayPointervEXT (GLuint vaobj, GLenum pname, void **param);
+GLAPI void APIENTRY glGetVertexArrayIntegeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, GLint *param);
+GLAPI void APIENTRY glGetVertexArrayPointeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, void **param);
+GLAPI void *APIENTRY glMapNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);
+GLAPI void APIENTRY glFlushMappedNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length);
+GLAPI void APIENTRY glNamedBufferStorageEXT (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags);
+GLAPI void APIENTRY glClearNamedBufferDataEXT (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data);
+GLAPI void APIENTRY glClearNamedBufferSubDataEXT (GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
+GLAPI void APIENTRY glNamedFramebufferParameteriEXT (GLuint framebuffer, GLenum pname, GLint param);
+GLAPI void APIENTRY glGetNamedFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params);
+GLAPI void APIENTRY glProgramUniform1dEXT (GLuint program, GLint location, GLdouble x);
+GLAPI void APIENTRY glProgramUniform2dEXT (GLuint program, GLint location, GLdouble x, GLdouble y);
+GLAPI void APIENTRY glProgramUniform3dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glProgramUniform4dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glProgramUniform1dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniform2dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniform3dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniform4dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix2x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix2x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix3x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix3x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix4x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glProgramUniformMatrix4x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+GLAPI void APIENTRY glTextureBufferRangeEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
+GLAPI void APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GLAPI void APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+GLAPI void APIENTRY glTextureStorage2DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+GLAPI void APIENTRY glTextureStorage3DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+GLAPI void APIENTRY glVertexArrayBindVertexBufferEXT (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
+GLAPI void APIENTRY glVertexArrayVertexAttribFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
+GLAPI void APIENTRY glVertexArrayVertexAttribIFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+GLAPI void APIENTRY glVertexArrayVertexAttribLFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+GLAPI void APIENTRY glVertexArrayVertexAttribBindingEXT (GLuint vaobj, GLuint attribindex, GLuint bindingindex);
+GLAPI void APIENTRY glVertexArrayVertexBindingDivisorEXT (GLuint vaobj, GLuint bindingindex, GLuint divisor);
+GLAPI void APIENTRY glVertexArrayVertexAttribLOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+GLAPI void APIENTRY glTexturePageCommitmentEXT (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);
+GLAPI void APIENTRY glVertexArrayVertexAttribDivisorEXT (GLuint vaobj, GLuint index, GLuint divisor);
+#endif
+#endif /* GL_EXT_direct_state_access */
+
+#ifndef GL_EXT_draw_buffers2
+#define GL_EXT_draw_buffers2 1
+typedef void (APIENTRYP PFNGLCOLORMASKINDEXEDEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorMaskIndexedEXT (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+#endif
+#endif /* GL_EXT_draw_buffers2 */
+
+#ifndef GL_EXT_draw_instanced
+#define GL_EXT_draw_instanced 1
+typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawArraysInstancedEXT (GLenum mode, GLint start, GLsizei count, GLsizei primcount);
+GLAPI void APIENTRY glDrawElementsInstancedEXT (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+#endif
+#endif /* GL_EXT_draw_instanced */
+
+#ifndef GL_EXT_draw_range_elements
+#define GL_EXT_draw_range_elements 1
+#define GL_MAX_ELEMENTS_VERTICES_EXT      0x80E8
+#define GL_MAX_ELEMENTS_INDICES_EXT       0x80E9
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawRangeElementsEXT (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
+#endif
+#endif /* GL_EXT_draw_range_elements */
+
+#ifndef GL_EXT_external_buffer
+#define GL_EXT_external_buffer 1
+typedef void *GLeglClientBufferEXT;
+typedef void (APIENTRYP PFNGLBUFFERSTORAGEEXTERNALEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags);
+typedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBufferStorageExternalEXT (GLenum target, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags);
+GLAPI void APIENTRY glNamedBufferStorageExternalEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags);
+#endif
+#endif /* GL_EXT_external_buffer */
+
+#ifndef GL_EXT_fog_coord
+#define GL_EXT_fog_coord 1
+#define GL_FOG_COORDINATE_SOURCE_EXT      0x8450
+#define GL_FOG_COORDINATE_EXT             0x8451
+#define GL_FRAGMENT_DEPTH_EXT             0x8452
+#define GL_CURRENT_FOG_COORDINATE_EXT     0x8453
+#define GL_FOG_COORDINATE_ARRAY_TYPE_EXT  0x8454
+#define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455
+#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456
+#define GL_FOG_COORDINATE_ARRAY_EXT       0x8457
+typedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord);
+typedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFogCoordfEXT (GLfloat coord);
+GLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *coord);
+GLAPI void APIENTRY glFogCoorddEXT (GLdouble coord);
+GLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *coord);
+GLAPI void APIENTRY glFogCoordPointerEXT (GLenum type, GLsizei stride, const void *pointer);
+#endif
+#endif /* GL_EXT_fog_coord */
+
+#ifndef GL_EXT_framebuffer_blit
+#define GL_EXT_framebuffer_blit 1
+#define GL_READ_FRAMEBUFFER_EXT           0x8CA8
+#define GL_DRAW_FRAMEBUFFER_EXT           0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_EXT   0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_EXT   0x8CAA
+typedef void (APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlitFramebufferEXT (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+#endif /* GL_EXT_framebuffer_blit */
+
+#ifndef GL_EXT_framebuffer_multisample
+#define GL_EXT_framebuffer_multisample 1
+#define GL_RENDERBUFFER_SAMPLES_EXT       0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56
+#define GL_MAX_SAMPLES_EXT                0x8D57
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glRenderbufferStorageMultisampleEXT (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+#endif /* GL_EXT_framebuffer_multisample */
+
+#ifndef GL_EXT_framebuffer_multisample_blit_scaled
+#define GL_EXT_framebuffer_multisample_blit_scaled 1
+#define GL_SCALED_RESOLVE_FASTEST_EXT     0x90BA
+#define GL_SCALED_RESOLVE_NICEST_EXT      0x90BB
+#endif /* GL_EXT_framebuffer_multisample_blit_scaled */
+
+#ifndef GL_EXT_framebuffer_object
+#define GL_EXT_framebuffer_object 1
+#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506
+#define GL_MAX_RENDERBUFFER_SIZE_EXT      0x84E8
+#define GL_FRAMEBUFFER_BINDING_EXT        0x8CA6
+#define GL_RENDERBUFFER_BINDING_EXT       0x8CA7
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4
+#define GL_FRAMEBUFFER_COMPLETE_EXT       0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9
+#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA
+#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB
+#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC
+#define GL_FRAMEBUFFER_UNSUPPORTED_EXT    0x8CDD
+#define GL_MAX_COLOR_ATTACHMENTS_EXT      0x8CDF
+#define GL_COLOR_ATTACHMENT0_EXT          0x8CE0
+#define GL_COLOR_ATTACHMENT1_EXT          0x8CE1
+#define GL_COLOR_ATTACHMENT2_EXT          0x8CE2
+#define GL_COLOR_ATTACHMENT3_EXT          0x8CE3
+#define GL_COLOR_ATTACHMENT4_EXT          0x8CE4
+#define GL_COLOR_ATTACHMENT5_EXT          0x8CE5
+#define GL_COLOR_ATTACHMENT6_EXT          0x8CE6
+#define GL_COLOR_ATTACHMENT7_EXT          0x8CE7
+#define GL_COLOR_ATTACHMENT8_EXT          0x8CE8
+#define GL_COLOR_ATTACHMENT9_EXT          0x8CE9
+#define GL_COLOR_ATTACHMENT10_EXT         0x8CEA
+#define GL_COLOR_ATTACHMENT11_EXT         0x8CEB
+#define GL_COLOR_ATTACHMENT12_EXT         0x8CEC
+#define GL_COLOR_ATTACHMENT13_EXT         0x8CED
+#define GL_COLOR_ATTACHMENT14_EXT         0x8CEE
+#define GL_COLOR_ATTACHMENT15_EXT         0x8CEF
+#define GL_DEPTH_ATTACHMENT_EXT           0x8D00
+#define GL_STENCIL_ATTACHMENT_EXT         0x8D20
+#define GL_FRAMEBUFFER_EXT                0x8D40
+#define GL_RENDERBUFFER_EXT               0x8D41
+#define GL_RENDERBUFFER_WIDTH_EXT         0x8D42
+#define GL_RENDERBUFFER_HEIGHT_EXT        0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44
+#define GL_STENCIL_INDEX1_EXT             0x8D46
+#define GL_STENCIL_INDEX4_EXT             0x8D47
+#define GL_STENCIL_INDEX8_EXT             0x8D48
+#define GL_STENCIL_INDEX16_EXT            0x8D49
+#define GL_RENDERBUFFER_RED_SIZE_EXT      0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE_EXT    0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE_EXT     0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE_EXT    0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE_EXT    0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE_EXT  0x8D55
+typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers);
+typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers);
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer);
+typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer);
+typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers);
+typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers);
+typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLboolean APIENTRY glIsRenderbufferEXT (GLuint renderbuffer);
+GLAPI void APIENTRY glBindRenderbufferEXT (GLenum target, GLuint renderbuffer);
+GLAPI void APIENTRY glDeleteRenderbuffersEXT (GLsizei n, const GLuint *renderbuffers);
+GLAPI void APIENTRY glGenRenderbuffersEXT (GLsizei n, GLuint *renderbuffers);
+GLAPI void APIENTRY glRenderbufferStorageEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glGetRenderbufferParameterivEXT (GLenum target, GLenum pname, GLint *params);
+GLAPI GLboolean APIENTRY glIsFramebufferEXT (GLuint framebuffer);
+GLAPI void APIENTRY glBindFramebufferEXT (GLenum target, GLuint framebuffer);
+GLAPI void APIENTRY glDeleteFramebuffersEXT (GLsizei n, const GLuint *framebuffers);
+GLAPI void APIENTRY glGenFramebuffersEXT (GLsizei n, GLuint *framebuffers);
+GLAPI GLenum APIENTRY glCheckFramebufferStatusEXT (GLenum target);
+GLAPI void APIENTRY glFramebufferTexture1DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLAPI void APIENTRY glFramebufferTexture3DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+GLAPI void APIENTRY glFramebufferRenderbufferEXT (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GLAPI void APIENTRY glGetFramebufferAttachmentParameterivEXT (GLenum target, GLenum attachment, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGenerateMipmapEXT (GLenum target);
+#endif
+#endif /* GL_EXT_framebuffer_object */
+
+#ifndef GL_EXT_framebuffer_sRGB
+#define GL_EXT_framebuffer_sRGB 1
+#define GL_FRAMEBUFFER_SRGB_EXT           0x8DB9
+#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT   0x8DBA
+#endif /* GL_EXT_framebuffer_sRGB */
+
+#ifndef GL_EXT_geometry_shader4
+#define GL_EXT_geometry_shader4 1
+#define GL_GEOMETRY_SHADER_EXT            0x8DD9
+#define GL_GEOMETRY_VERTICES_OUT_EXT      0x8DDA
+#define GL_GEOMETRY_INPUT_TYPE_EXT        0x8DDB
+#define GL_GEOMETRY_OUTPUT_TYPE_EXT       0x8DDC
+#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29
+#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT 0x8DDD
+#define GL_MAX_VERTEX_VARYING_COMPONENTS_EXT 0x8DDE
+#define GL_MAX_VARYING_COMPONENTS_EXT     0x8B4B
+#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF
+#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0
+#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1
+#define GL_LINES_ADJACENCY_EXT            0x000A
+#define GL_LINE_STRIP_ADJACENCY_EXT       0x000B
+#define GL_TRIANGLES_ADJACENCY_EXT        0x000C
+#define GL_TRIANGLE_STRIP_ADJACENCY_EXT   0x000D
+#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8
+#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT 0x8DA9
+#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4
+#define GL_PROGRAM_POINT_SIZE_EXT         0x8642
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value);
+#endif
+#endif /* GL_EXT_geometry_shader4 */
+
+#ifndef GL_EXT_gpu_program_parameters
+#define GL_EXT_gpu_program_parameters 1
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramEnvParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params);
+GLAPI void APIENTRY glProgramLocalParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params);
+#endif
+#endif /* GL_EXT_gpu_program_parameters */
+
+#ifndef GL_EXT_gpu_shader4
+#define GL_EXT_gpu_shader4 1
+#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT 0x88FD
+#define GL_SAMPLER_1D_ARRAY_EXT           0x8DC0
+#define GL_SAMPLER_2D_ARRAY_EXT           0x8DC1
+#define GL_SAMPLER_BUFFER_EXT             0x8DC2
+#define GL_SAMPLER_1D_ARRAY_SHADOW_EXT    0x8DC3
+#define GL_SAMPLER_2D_ARRAY_SHADOW_EXT    0x8DC4
+#define GL_SAMPLER_CUBE_SHADOW_EXT        0x8DC5
+#define GL_UNSIGNED_INT_VEC2_EXT          0x8DC6
+#define GL_UNSIGNED_INT_VEC3_EXT          0x8DC7
+#define GL_UNSIGNED_INT_VEC4_EXT          0x8DC8
+#define GL_INT_SAMPLER_1D_EXT             0x8DC9
+#define GL_INT_SAMPLER_2D_EXT             0x8DCA
+#define GL_INT_SAMPLER_3D_EXT             0x8DCB
+#define GL_INT_SAMPLER_CUBE_EXT           0x8DCC
+#define GL_INT_SAMPLER_2D_RECT_EXT        0x8DCD
+#define GL_INT_SAMPLER_1D_ARRAY_EXT       0x8DCE
+#define GL_INT_SAMPLER_2D_ARRAY_EXT       0x8DCF
+#define GL_INT_SAMPLER_BUFFER_EXT         0x8DD0
+#define GL_UNSIGNED_INT_SAMPLER_1D_EXT    0x8DD1
+#define GL_UNSIGNED_INT_SAMPLER_2D_EXT    0x8DD2
+#define GL_UNSIGNED_INT_SAMPLER_3D_EXT    0x8DD3
+#define GL_UNSIGNED_INT_SAMPLER_CUBE_EXT  0x8DD4
+#define GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT 0x8DD5
+#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT 0x8DD6
+#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT 0x8DD7
+#define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8
+#define GL_MIN_PROGRAM_TEXEL_OFFSET_EXT   0x8904
+#define GL_MAX_PROGRAM_TEXEL_OFFSET_EXT   0x8905
+typedef void (APIENTRYP PFNGLGETUNIFORMUIVEXTPROC) (GLuint program, GLint location, GLuint *params);
+typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name);
+typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONEXTPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLUNIFORM1UIEXTPROC) (GLint location, GLuint v0);
+typedef void (APIENTRYP PFNGLUNIFORM2UIEXTPROC) (GLint location, GLuint v0, GLuint v1);
+typedef void (APIENTRYP PFNGLUNIFORM3UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2);
+typedef void (APIENTRYP PFNGLUNIFORM4UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+typedef void (APIENTRYP PFNGLUNIFORM1UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM2UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM3UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP PFNGLUNIFORM4UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetUniformuivEXT (GLuint program, GLint location, GLuint *params);
+GLAPI void APIENTRY glBindFragDataLocationEXT (GLuint program, GLuint color, const GLchar *name);
+GLAPI GLint APIENTRY glGetFragDataLocationEXT (GLuint program, const GLchar *name);
+GLAPI void APIENTRY glUniform1uiEXT (GLint location, GLuint v0);
+GLAPI void APIENTRY glUniform2uiEXT (GLint location, GLuint v0, GLuint v1);
+GLAPI void APIENTRY glUniform3uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2);
+GLAPI void APIENTRY glUniform4uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+GLAPI void APIENTRY glUniform1uivEXT (GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glUniform2uivEXT (GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glUniform3uivEXT (GLint location, GLsizei count, const GLuint *value);
+GLAPI void APIENTRY glUniform4uivEXT (GLint location, GLsizei count, const GLuint *value);
+#endif
+#endif /* GL_EXT_gpu_shader4 */
+
+#ifndef GL_EXT_histogram
+#define GL_EXT_histogram 1
+#define GL_HISTOGRAM_EXT                  0x8024
+#define GL_PROXY_HISTOGRAM_EXT            0x8025
+#define GL_HISTOGRAM_WIDTH_EXT            0x8026
+#define GL_HISTOGRAM_FORMAT_EXT           0x8027
+#define GL_HISTOGRAM_RED_SIZE_EXT         0x8028
+#define GL_HISTOGRAM_GREEN_SIZE_EXT       0x8029
+#define GL_HISTOGRAM_BLUE_SIZE_EXT        0x802A
+#define GL_HISTOGRAM_ALPHA_SIZE_EXT       0x802B
+#define GL_HISTOGRAM_LUMINANCE_SIZE_EXT   0x802C
+#define GL_HISTOGRAM_SINK_EXT             0x802D
+#define GL_MINMAX_EXT                     0x802E
+#define GL_MINMAX_FORMAT_EXT              0x802F
+#define GL_MINMAX_SINK_EXT                0x8030
+#define GL_TABLE_TOO_LARGE_EXT            0x8031
+typedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetHistogramEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
+GLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetMinmaxEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
+GLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glHistogramEXT (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+GLAPI void APIENTRY glMinmaxEXT (GLenum target, GLenum internalformat, GLboolean sink);
+GLAPI void APIENTRY glResetHistogramEXT (GLenum target);
+GLAPI void APIENTRY glResetMinmaxEXT (GLenum target);
+#endif
+#endif /* GL_EXT_histogram */
+
+#ifndef GL_EXT_index_array_formats
+#define GL_EXT_index_array_formats 1
+#define GL_IUI_V2F_EXT                    0x81AD
+#define GL_IUI_V3F_EXT                    0x81AE
+#define GL_IUI_N3F_V2F_EXT                0x81AF
+#define GL_IUI_N3F_V3F_EXT                0x81B0
+#define GL_T2F_IUI_V2F_EXT                0x81B1
+#define GL_T2F_IUI_V3F_EXT                0x81B2
+#define GL_T2F_IUI_N3F_V2F_EXT            0x81B3
+#define GL_T2F_IUI_N3F_V3F_EXT            0x81B4
+#endif /* GL_EXT_index_array_formats */
+
+#ifndef GL_EXT_index_func
+#define GL_EXT_index_func 1
+#define GL_INDEX_TEST_EXT                 0x81B5
+#define GL_INDEX_TEST_FUNC_EXT            0x81B6
+#define GL_INDEX_TEST_REF_EXT             0x81B7
+typedef void (APIENTRYP PFNGLINDEXFUNCEXTPROC) (GLenum func, GLclampf ref);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glIndexFuncEXT (GLenum func, GLclampf ref);
+#endif
+#endif /* GL_EXT_index_func */
+
+#ifndef GL_EXT_index_material
+#define GL_EXT_index_material 1
+#define GL_INDEX_MATERIAL_EXT             0x81B8
+#define GL_INDEX_MATERIAL_PARAMETER_EXT   0x81B9
+#define GL_INDEX_MATERIAL_FACE_EXT        0x81BA
+typedef void (APIENTRYP PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glIndexMaterialEXT (GLenum face, GLenum mode);
+#endif
+#endif /* GL_EXT_index_material */
+
+#ifndef GL_EXT_index_texture
+#define GL_EXT_index_texture 1
+#endif /* GL_EXT_index_texture */
+
+#ifndef GL_EXT_light_texture
+#define GL_EXT_light_texture 1
+#define GL_FRAGMENT_MATERIAL_EXT          0x8349
+#define GL_FRAGMENT_NORMAL_EXT            0x834A
+#define GL_FRAGMENT_COLOR_EXT             0x834C
+#define GL_ATTENUATION_EXT                0x834D
+#define GL_SHADOW_ATTENUATION_EXT         0x834E
+#define GL_TEXTURE_APPLICATION_MODE_EXT   0x834F
+#define GL_TEXTURE_LIGHT_EXT              0x8350
+#define GL_TEXTURE_MATERIAL_FACE_EXT      0x8351
+#define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352
+typedef void (APIENTRYP PFNGLAPPLYTEXTUREEXTPROC) (GLenum mode);
+typedef void (APIENTRYP PFNGLTEXTURELIGHTEXTPROC) (GLenum pname);
+typedef void (APIENTRYP PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glApplyTextureEXT (GLenum mode);
+GLAPI void APIENTRY glTextureLightEXT (GLenum pname);
+GLAPI void APIENTRY glTextureMaterialEXT (GLenum face, GLenum mode);
+#endif
+#endif /* GL_EXT_light_texture */
+
+#ifndef GL_EXT_memory_object
+#define GL_EXT_memory_object 1
+#define GL_TEXTURE_TILING_EXT             0x9580
+#define GL_DEDICATED_MEMORY_OBJECT_EXT    0x9581
+#define GL_PROTECTED_MEMORY_OBJECT_EXT    0x959B
+#define GL_NUM_TILING_TYPES_EXT           0x9582
+#define GL_TILING_TYPES_EXT               0x9583
+#define GL_OPTIMAL_TILING_EXT             0x9584
+#define GL_LINEAR_TILING_EXT              0x9585
+#define GL_NUM_DEVICE_UUIDS_EXT           0x9596
+#define GL_DEVICE_UUID_EXT                0x9597
+#define GL_DRIVER_UUID_EXT                0x9598
+#define GL_UUID_SIZE_EXT                  16
+typedef void (APIENTRYP PFNGLGETUNSIGNEDBYTEVEXTPROC) (GLenum pname, GLubyte *data);
+typedef void (APIENTRYP PFNGLGETUNSIGNEDBYTEI_VEXTPROC) (GLenum target, GLuint index, GLubyte *data);
+typedef void (APIENTRYP PFNGLDELETEMEMORYOBJECTSEXTPROC) (GLsizei n, const GLuint *memoryObjects);
+typedef GLboolean (APIENTRYP PFNGLISMEMORYOBJECTEXTPROC) (GLuint memoryObject);
+typedef void (APIENTRYP PFNGLCREATEMEMORYOBJECTSEXTPROC) (GLsizei n, GLuint *memoryObjects);
+typedef void (APIENTRYP PFNGLMEMORYOBJECTPARAMETERIVEXTPROC) (GLuint memoryObject, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC) (GLuint memoryObject, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLTEXSTORAGEMEM2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset);
+typedef void (APIENTRYP PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);
+typedef void (APIENTRYP PFNGLTEXSTORAGEMEM3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset);
+typedef void (APIENTRYP PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);
+typedef void (APIENTRYP PFNGLBUFFERSTORAGEMEMEXTPROC) (GLenum target, GLsizeiptr size, GLuint memory, GLuint64 offset);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGEMEM2DEXTPROC) (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC) (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGEMEM3DEXTPROC) (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC) (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);
+typedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC) (GLuint buffer, GLsizeiptr size, GLuint memory, GLuint64 offset);
+typedef void (APIENTRYP PFNGLTEXSTORAGEMEM1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLuint memory, GLuint64 offset);
+typedef void (APIENTRYP PFNGLTEXTURESTORAGEMEM1DEXTPROC) (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLuint memory, GLuint64 offset);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetUnsignedBytevEXT (GLenum pname, GLubyte *data);
+GLAPI void APIENTRY glGetUnsignedBytei_vEXT (GLenum target, GLuint index, GLubyte *data);
+GLAPI void APIENTRY glDeleteMemoryObjectsEXT (GLsizei n, const GLuint *memoryObjects);
+GLAPI GLboolean APIENTRY glIsMemoryObjectEXT (GLuint memoryObject);
+GLAPI void APIENTRY glCreateMemoryObjectsEXT (GLsizei n, GLuint *memoryObjects);
+GLAPI void APIENTRY glMemoryObjectParameterivEXT (GLuint memoryObject, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glGetMemoryObjectParameterivEXT (GLuint memoryObject, GLenum pname, GLint *params);
+GLAPI void APIENTRY glTexStorageMem2DEXT (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset);
+GLAPI void APIENTRY glTexStorageMem2DMultisampleEXT (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);
+GLAPI void APIENTRY glTexStorageMem3DEXT (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset);
+GLAPI void APIENTRY glTexStorageMem3DMultisampleEXT (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);
+GLAPI void APIENTRY glBufferStorageMemEXT (GLenum target, GLsizeiptr size, GLuint memory, GLuint64 offset);
+GLAPI void APIENTRY glTextureStorageMem2DEXT (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset);
+GLAPI void APIENTRY glTextureStorageMem2DMultisampleEXT (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);
+GLAPI void APIENTRY glTextureStorageMem3DEXT (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset);
+GLAPI void APIENTRY glTextureStorageMem3DMultisampleEXT (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);
+GLAPI void APIENTRY glNamedBufferStorageMemEXT (GLuint buffer, GLsizeiptr size, GLuint memory, GLuint64 offset);
+GLAPI void APIENTRY glTexStorageMem1DEXT (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLuint memory, GLuint64 offset);
+GLAPI void APIENTRY glTextureStorageMem1DEXT (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLuint memory, GLuint64 offset);
+#endif
+#endif /* GL_EXT_memory_object */
+
+#ifndef GL_EXT_memory_object_fd
+#define GL_EXT_memory_object_fd 1
+#define GL_HANDLE_TYPE_OPAQUE_FD_EXT      0x9586
+typedef void (APIENTRYP PFNGLIMPORTMEMORYFDEXTPROC) (GLuint memory, GLuint64 size, GLenum handleType, GLint fd);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glImportMemoryFdEXT (GLuint memory, GLuint64 size, GLenum handleType, GLint fd);
+#endif
+#endif /* GL_EXT_memory_object_fd */
+
+#ifndef GL_EXT_memory_object_win32
+#define GL_EXT_memory_object_win32 1
+#define GL_HANDLE_TYPE_OPAQUE_WIN32_EXT   0x9587
+#define GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT 0x9588
+#define GL_DEVICE_LUID_EXT                0x9599
+#define GL_DEVICE_NODE_MASK_EXT           0x959A
+#define GL_LUID_SIZE_EXT                  8
+#define GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT 0x9589
+#define GL_HANDLE_TYPE_D3D12_RESOURCE_EXT 0x958A
+#define GL_HANDLE_TYPE_D3D11_IMAGE_EXT    0x958B
+#define GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT 0x958C
+typedef void (APIENTRYP PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC) (GLuint memory, GLuint64 size, GLenum handleType, void *handle);
+typedef void (APIENTRYP PFNGLIMPORTMEMORYWIN32NAMEEXTPROC) (GLuint memory, GLuint64 size, GLenum handleType, const void *name);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glImportMemoryWin32HandleEXT (GLuint memory, GLuint64 size, GLenum handleType, void *handle);
+GLAPI void APIENTRY glImportMemoryWin32NameEXT (GLuint memory, GLuint64 size, GLenum handleType, const void *name);
+#endif
+#endif /* GL_EXT_memory_object_win32 */
+
+#ifndef GL_EXT_misc_attribute
+#define GL_EXT_misc_attribute 1
+#endif /* GL_EXT_misc_attribute */
+
+#ifndef GL_EXT_multi_draw_arrays
+#define GL_EXT_multi_draw_arrays 1
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiDrawArraysEXT (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
+GLAPI void APIENTRY glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount);
+#endif
+#endif /* GL_EXT_multi_draw_arrays */
+
+#ifndef GL_EXT_multisample
+#define GL_EXT_multisample 1
+#define GL_MULTISAMPLE_EXT                0x809D
+#define GL_SAMPLE_ALPHA_TO_MASK_EXT       0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_EXT        0x809F
+#define GL_SAMPLE_MASK_EXT                0x80A0
+#define GL_1PASS_EXT                      0x80A1
+#define GL_2PASS_0_EXT                    0x80A2
+#define GL_2PASS_1_EXT                    0x80A3
+#define GL_4PASS_0_EXT                    0x80A4
+#define GL_4PASS_1_EXT                    0x80A5
+#define GL_4PASS_2_EXT                    0x80A6
+#define GL_4PASS_3_EXT                    0x80A7
+#define GL_SAMPLE_BUFFERS_EXT             0x80A8
+#define GL_SAMPLES_EXT                    0x80A9
+#define GL_SAMPLE_MASK_VALUE_EXT          0x80AA
+#define GL_SAMPLE_MASK_INVERT_EXT         0x80AB
+#define GL_SAMPLE_PATTERN_EXT             0x80AC
+#define GL_MULTISAMPLE_BIT_EXT            0x20000000
+typedef void (APIENTRYP PFNGLSAMPLEMASKEXTPROC) (GLclampf value, GLboolean invert);
+typedef void (APIENTRYP PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSampleMaskEXT (GLclampf value, GLboolean invert);
+GLAPI void APIENTRY glSamplePatternEXT (GLenum pattern);
+#endif
+#endif /* GL_EXT_multisample */
+
+#ifndef GL_EXT_multiview_tessellation_geometry_shader
+#define GL_EXT_multiview_tessellation_geometry_shader 1
+#endif /* GL_EXT_multiview_tessellation_geometry_shader */
+
+#ifndef GL_EXT_multiview_texture_multisample
+#define GL_EXT_multiview_texture_multisample 1
+#endif /* GL_EXT_multiview_texture_multisample */
+
+#ifndef GL_EXT_multiview_timer_query
+#define GL_EXT_multiview_timer_query 1
+#endif /* GL_EXT_multiview_timer_query */
+
+#ifndef GL_EXT_packed_depth_stencil
+#define GL_EXT_packed_depth_stencil 1
+#define GL_DEPTH_STENCIL_EXT              0x84F9
+#define GL_UNSIGNED_INT_24_8_EXT          0x84FA
+#define GL_DEPTH24_STENCIL8_EXT           0x88F0
+#define GL_TEXTURE_STENCIL_SIZE_EXT       0x88F1
+#endif /* GL_EXT_packed_depth_stencil */
+
+#ifndef GL_EXT_packed_float
+#define GL_EXT_packed_float 1
+#define GL_R11F_G11F_B10F_EXT             0x8C3A
+#define GL_UNSIGNED_INT_10F_11F_11F_REV_EXT 0x8C3B
+#define GL_RGBA_SIGNED_COMPONENTS_EXT     0x8C3C
+#endif /* GL_EXT_packed_float */
+
+#ifndef GL_EXT_packed_pixels
+#define GL_EXT_packed_pixels 1
+#define GL_UNSIGNED_BYTE_3_3_2_EXT        0x8032
+#define GL_UNSIGNED_SHORT_4_4_4_4_EXT     0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1_EXT     0x8034
+#define GL_UNSIGNED_INT_8_8_8_8_EXT       0x8035
+#define GL_UNSIGNED_INT_10_10_10_2_EXT    0x8036
+#endif /* GL_EXT_packed_pixels */
+
+#ifndef GL_EXT_paletted_texture
+#define GL_EXT_paletted_texture 1
+#define GL_COLOR_INDEX1_EXT               0x80E2
+#define GL_COLOR_INDEX2_EXT               0x80E3
+#define GL_COLOR_INDEX4_EXT               0x80E4
+#define GL_COLOR_INDEX8_EXT               0x80E5
+#define GL_COLOR_INDEX12_EXT              0x80E6
+#define GL_COLOR_INDEX16_EXT              0x80E7
+#define GL_TEXTURE_INDEX_SIZE_EXT         0x80ED
+typedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const void *table);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, void *data);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorTableEXT (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const void *table);
+GLAPI void APIENTRY glGetColorTableEXT (GLenum target, GLenum format, GLenum type, void *data);
+GLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum target, GLenum pname, GLfloat *params);
+#endif
+#endif /* GL_EXT_paletted_texture */
+
+#ifndef GL_EXT_pixel_buffer_object
+#define GL_EXT_pixel_buffer_object 1
+#define GL_PIXEL_PACK_BUFFER_EXT          0x88EB
+#define GL_PIXEL_UNPACK_BUFFER_EXT        0x88EC
+#define GL_PIXEL_PACK_BUFFER_BINDING_EXT  0x88ED
+#define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF
+#endif /* GL_EXT_pixel_buffer_object */
+
+#ifndef GL_EXT_pixel_transform
+#define GL_EXT_pixel_transform 1
+#define GL_PIXEL_TRANSFORM_2D_EXT         0x8330
+#define GL_PIXEL_MAG_FILTER_EXT           0x8331
+#define GL_PIXEL_MIN_FILTER_EXT           0x8332
+#define GL_PIXEL_CUBIC_WEIGHT_EXT         0x8333
+#define GL_CUBIC_EXT                      0x8334
+#define GL_AVERAGE_EXT                    0x8335
+#define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336
+#define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337
+#define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT  0x8338
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelTransformParameteriEXT (GLenum target, GLenum pname, GLint param);
+GLAPI void APIENTRY glPixelTransformParameterfEXT (GLenum target, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glPixelTransformParameterivEXT (GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glPixelTransformParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glGetPixelTransformParameterivEXT (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetPixelTransformParameterfvEXT (GLenum target, GLenum pname, GLfloat *params);
+#endif
+#endif /* GL_EXT_pixel_transform */
+
+#ifndef GL_EXT_pixel_transform_color_table
+#define GL_EXT_pixel_transform_color_table 1
+#endif /* GL_EXT_pixel_transform_color_table */
+
+#ifndef GL_EXT_point_parameters
+#define GL_EXT_point_parameters 1
+#define GL_POINT_SIZE_MIN_EXT             0x8126
+#define GL_POINT_SIZE_MAX_EXT             0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE_EXT  0x8128
+#define GL_DISTANCE_ATTENUATION_EXT       0x8129
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameterfEXT (GLenum pname, GLfloat param);
+GLAPI void APIENTRY glPointParameterfvEXT (GLenum pname, const GLfloat *params);
+#endif
+#endif /* GL_EXT_point_parameters */
+
+#ifndef GL_EXT_polygon_offset
+#define GL_EXT_polygon_offset 1
+#define GL_POLYGON_OFFSET_EXT             0x8037
+#define GL_POLYGON_OFFSET_FACTOR_EXT      0x8038
+#define GL_POLYGON_OFFSET_BIAS_EXT        0x8039
+typedef void (APIENTRYP PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPolygonOffsetEXT (GLfloat factor, GLfloat bias);
+#endif
+#endif /* GL_EXT_polygon_offset */
+
+#ifndef GL_EXT_polygon_offset_clamp
+#define GL_EXT_polygon_offset_clamp 1
+#define GL_POLYGON_OFFSET_CLAMP_EXT       0x8E1B
+typedef void (APIENTRYP PFNGLPOLYGONOFFSETCLAMPEXTPROC) (GLfloat factor, GLfloat units, GLfloat clamp);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPolygonOffsetClampEXT (GLfloat factor, GLfloat units, GLfloat clamp);
+#endif
+#endif /* GL_EXT_polygon_offset_clamp */
+
+#ifndef GL_EXT_post_depth_coverage
+#define GL_EXT_post_depth_coverage 1
+#endif /* GL_EXT_post_depth_coverage */
+
+#ifndef GL_EXT_provoking_vertex
+#define GL_EXT_provoking_vertex 1
+#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT 0x8E4C
+#define GL_FIRST_VERTEX_CONVENTION_EXT    0x8E4D
+#define GL_LAST_VERTEX_CONVENTION_EXT     0x8E4E
+#define GL_PROVOKING_VERTEX_EXT           0x8E4F
+typedef void (APIENTRYP PFNGLPROVOKINGVERTEXEXTPROC) (GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProvokingVertexEXT (GLenum mode);
+#endif
+#endif /* GL_EXT_provoking_vertex */
+
+#ifndef GL_EXT_raster_multisample
+#define GL_EXT_raster_multisample 1
+#define GL_RASTER_MULTISAMPLE_EXT         0x9327
+#define GL_RASTER_SAMPLES_EXT             0x9328
+#define GL_MAX_RASTER_SAMPLES_EXT         0x9329
+#define GL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT 0x932A
+#define GL_MULTISAMPLE_RASTERIZATION_ALLOWED_EXT 0x932B
+#define GL_EFFECTIVE_RASTER_SAMPLES_EXT   0x932C
+typedef void (APIENTRYP PFNGLRASTERSAMPLESEXTPROC) (GLuint samples, GLboolean fixedsamplelocations);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glRasterSamplesEXT (GLuint samples, GLboolean fixedsamplelocations);
+#endif
+#endif /* GL_EXT_raster_multisample */
+
+#ifndef GL_EXT_rescale_normal
+#define GL_EXT_rescale_normal 1
+#define GL_RESCALE_NORMAL_EXT             0x803A
+#endif /* GL_EXT_rescale_normal */
+
+#ifndef GL_EXT_secondary_color
+#define GL_EXT_secondary_color 1
+#define GL_COLOR_SUM_EXT                  0x8458
+#define GL_CURRENT_SECONDARY_COLOR_EXT    0x8459
+#define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A
+#define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B
+#define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C
+#define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D
+#define GL_SECONDARY_COLOR_ARRAY_EXT      0x845E
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BEXTPROC) (GLbyte red, GLbyte green, GLbyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVEXTPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DEXTPROC) (GLdouble red, GLdouble green, GLdouble blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVEXTPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FEXTPROC) (GLfloat red, GLfloat green, GLfloat blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVEXTPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IEXTPROC) (GLint red, GLint green, GLint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVEXTPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SEXTPROC) (GLshort red, GLshort green, GLshort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVEXTPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBEXTPROC) (GLubyte red, GLubyte green, GLubyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVEXTPROC) (const GLubyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green, GLuint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte red, GLbyte green, GLbyte blue);
+GLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *v);
+GLAPI void APIENTRY glSecondaryColor3dEXT (GLdouble red, GLdouble green, GLdouble blue);
+GLAPI void APIENTRY glSecondaryColor3dvEXT (const GLdouble *v);
+GLAPI void APIENTRY glSecondaryColor3fEXT (GLfloat red, GLfloat green, GLfloat blue);
+GLAPI void APIENTRY glSecondaryColor3fvEXT (const GLfloat *v);
+GLAPI void APIENTRY glSecondaryColor3iEXT (GLint red, GLint green, GLint blue);
+GLAPI void APIENTRY glSecondaryColor3ivEXT (const GLint *v);
+GLAPI void APIENTRY glSecondaryColor3sEXT (GLshort red, GLshort green, GLshort blue);
+GLAPI void APIENTRY glSecondaryColor3svEXT (const GLshort *v);
+GLAPI void APIENTRY glSecondaryColor3ubEXT (GLubyte red, GLubyte green, GLubyte blue);
+GLAPI void APIENTRY glSecondaryColor3ubvEXT (const GLubyte *v);
+GLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint red, GLuint green, GLuint blue);
+GLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *v);
+GLAPI void APIENTRY glSecondaryColor3usEXT (GLushort red, GLushort green, GLushort blue);
+GLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *v);
+GLAPI void APIENTRY glSecondaryColorPointerEXT (GLint size, GLenum type, GLsizei stride, const void *pointer);
+#endif
+#endif /* GL_EXT_secondary_color */
+
+#ifndef GL_EXT_semaphore
+#define GL_EXT_semaphore 1
+#define GL_LAYOUT_GENERAL_EXT             0x958D
+#define GL_LAYOUT_COLOR_ATTACHMENT_EXT    0x958E
+#define GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT 0x958F
+#define GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT 0x9590
+#define GL_LAYOUT_SHADER_READ_ONLY_EXT    0x9591
+#define GL_LAYOUT_TRANSFER_SRC_EXT        0x9592
+#define GL_LAYOUT_TRANSFER_DST_EXT        0x9593
+#define GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT 0x9530
+#define GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT 0x9531
+typedef void (APIENTRYP PFNGLGENSEMAPHORESEXTPROC) (GLsizei n, GLuint *semaphores);
+typedef void (APIENTRYP PFNGLDELETESEMAPHORESEXTPROC) (GLsizei n, const GLuint *semaphores);
+typedef GLboolean (APIENTRYP PFNGLISSEMAPHOREEXTPROC) (GLuint semaphore);
+typedef void (APIENTRYP PFNGLSEMAPHOREPARAMETERUI64VEXTPROC) (GLuint semaphore, GLenum pname, const GLuint64 *params);
+typedef void (APIENTRYP PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC) (GLuint semaphore, GLenum pname, GLuint64 *params);
+typedef void (APIENTRYP PFNGLWAITSEMAPHOREEXTPROC) (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *srcLayouts);
+typedef void (APIENTRYP PFNGLSIGNALSEMAPHOREEXTPROC) (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *dstLayouts);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenSemaphoresEXT (GLsizei n, GLuint *semaphores);
+GLAPI void APIENTRY glDeleteSemaphoresEXT (GLsizei n, const GLuint *semaphores);
+GLAPI GLboolean APIENTRY glIsSemaphoreEXT (GLuint semaphore);
+GLAPI void APIENTRY glSemaphoreParameterui64vEXT (GLuint semaphore, GLenum pname, const GLuint64 *params);
+GLAPI void APIENTRY glGetSemaphoreParameterui64vEXT (GLuint semaphore, GLenum pname, GLuint64 *params);
+GLAPI void APIENTRY glWaitSemaphoreEXT (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *srcLayouts);
+GLAPI void APIENTRY glSignalSemaphoreEXT (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *dstLayouts);
+#endif
+#endif /* GL_EXT_semaphore */
+
+#ifndef GL_EXT_semaphore_fd
+#define GL_EXT_semaphore_fd 1
+typedef void (APIENTRYP PFNGLIMPORTSEMAPHOREFDEXTPROC) (GLuint semaphore, GLenum handleType, GLint fd);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glImportSemaphoreFdEXT (GLuint semaphore, GLenum handleType, GLint fd);
+#endif
+#endif /* GL_EXT_semaphore_fd */
+
+#ifndef GL_EXT_semaphore_win32
+#define GL_EXT_semaphore_win32 1
+#define GL_HANDLE_TYPE_D3D12_FENCE_EXT    0x9594
+#define GL_D3D12_FENCE_VALUE_EXT          0x9595
+typedef void (APIENTRYP PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC) (GLuint semaphore, GLenum handleType, void *handle);
+typedef void (APIENTRYP PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC) (GLuint semaphore, GLenum handleType, const void *name);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glImportSemaphoreWin32HandleEXT (GLuint semaphore, GLenum handleType, void *handle);
+GLAPI void APIENTRY glImportSemaphoreWin32NameEXT (GLuint semaphore, GLenum handleType, const void *name);
+#endif
+#endif /* GL_EXT_semaphore_win32 */
+
+#ifndef GL_EXT_separate_shader_objects
+#define GL_EXT_separate_shader_objects 1
+#define GL_ACTIVE_PROGRAM_EXT             0x8B8D
+typedef void (APIENTRYP PFNGLUSESHADERPROGRAMEXTPROC) (GLenum type, GLuint program);
+typedef void (APIENTRYP PFNGLACTIVEPROGRAMEXTPROC) (GLuint program);
+typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMEXTPROC) (GLenum type, const GLchar *string);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glUseShaderProgramEXT (GLenum type, GLuint program);
+GLAPI void APIENTRY glActiveProgramEXT (GLuint program);
+GLAPI GLuint APIENTRY glCreateShaderProgramEXT (GLenum type, const GLchar *string);
+#endif
+#endif /* GL_EXT_separate_shader_objects */
+
+#ifndef GL_EXT_separate_specular_color
+#define GL_EXT_separate_specular_color 1
+#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT  0x81F8
+#define GL_SINGLE_COLOR_EXT               0x81F9
+#define GL_SEPARATE_SPECULAR_COLOR_EXT    0x81FA
+#endif /* GL_EXT_separate_specular_color */
+
+#ifndef GL_EXT_shader_framebuffer_fetch
+#define GL_EXT_shader_framebuffer_fetch 1
+#define GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT 0x8A52
+#endif /* GL_EXT_shader_framebuffer_fetch */
+
+#ifndef GL_EXT_shader_framebuffer_fetch_non_coherent
+#define GL_EXT_shader_framebuffer_fetch_non_coherent 1
+typedef void (APIENTRYP PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFramebufferFetchBarrierEXT (void);
+#endif
+#endif /* GL_EXT_shader_framebuffer_fetch_non_coherent */
+
+#ifndef GL_EXT_shader_image_load_formatted
+#define GL_EXT_shader_image_load_formatted 1
+#endif /* GL_EXT_shader_image_load_formatted */
+
+#ifndef GL_EXT_shader_image_load_store
+#define GL_EXT_shader_image_load_store 1
+#define GL_MAX_IMAGE_UNITS_EXT            0x8F38
+#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT 0x8F39
+#define GL_IMAGE_BINDING_NAME_EXT         0x8F3A
+#define GL_IMAGE_BINDING_LEVEL_EXT        0x8F3B
+#define GL_IMAGE_BINDING_LAYERED_EXT      0x8F3C
+#define GL_IMAGE_BINDING_LAYER_EXT        0x8F3D
+#define GL_IMAGE_BINDING_ACCESS_EXT       0x8F3E
+#define GL_IMAGE_1D_EXT                   0x904C
+#define GL_IMAGE_2D_EXT                   0x904D
+#define GL_IMAGE_3D_EXT                   0x904E
+#define GL_IMAGE_2D_RECT_EXT              0x904F
+#define GL_IMAGE_CUBE_EXT                 0x9050
+#define GL_IMAGE_BUFFER_EXT               0x9051
+#define GL_IMAGE_1D_ARRAY_EXT             0x9052
+#define GL_IMAGE_2D_ARRAY_EXT             0x9053
+#define GL_IMAGE_CUBE_MAP_ARRAY_EXT       0x9054
+#define GL_IMAGE_2D_MULTISAMPLE_EXT       0x9055
+#define GL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9056
+#define GL_INT_IMAGE_1D_EXT               0x9057
+#define GL_INT_IMAGE_2D_EXT               0x9058
+#define GL_INT_IMAGE_3D_EXT               0x9059
+#define GL_INT_IMAGE_2D_RECT_EXT          0x905A
+#define GL_INT_IMAGE_CUBE_EXT             0x905B
+#define GL_INT_IMAGE_BUFFER_EXT           0x905C
+#define GL_INT_IMAGE_1D_ARRAY_EXT         0x905D
+#define GL_INT_IMAGE_2D_ARRAY_EXT         0x905E
+#define GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT   0x905F
+#define GL_INT_IMAGE_2D_MULTISAMPLE_EXT   0x9060
+#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9061
+#define GL_UNSIGNED_INT_IMAGE_1D_EXT      0x9062
+#define GL_UNSIGNED_INT_IMAGE_2D_EXT      0x9063
+#define GL_UNSIGNED_INT_IMAGE_3D_EXT      0x9064
+#define GL_UNSIGNED_INT_IMAGE_2D_RECT_EXT 0x9065
+#define GL_UNSIGNED_INT_IMAGE_CUBE_EXT    0x9066
+#define GL_UNSIGNED_INT_IMAGE_BUFFER_EXT  0x9067
+#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT 0x9068
+#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT 0x9069
+#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x906A
+#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT 0x906B
+#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x906C
+#define GL_MAX_IMAGE_SAMPLES_EXT          0x906D
+#define GL_IMAGE_BINDING_FORMAT_EXT       0x906E
+#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT 0x00000001
+#define GL_ELEMENT_ARRAY_BARRIER_BIT_EXT  0x00000002
+#define GL_UNIFORM_BARRIER_BIT_EXT        0x00000004
+#define GL_TEXTURE_FETCH_BARRIER_BIT_EXT  0x00000008
+#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT 0x00000020
+#define GL_COMMAND_BARRIER_BIT_EXT        0x00000040
+#define GL_PIXEL_BUFFER_BARRIER_BIT_EXT   0x00000080
+#define GL_TEXTURE_UPDATE_BARRIER_BIT_EXT 0x00000100
+#define GL_BUFFER_UPDATE_BARRIER_BIT_EXT  0x00000200
+#define GL_FRAMEBUFFER_BARRIER_BIT_EXT    0x00000400
+#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT 0x00000800
+#define GL_ATOMIC_COUNTER_BARRIER_BIT_EXT 0x00001000
+#define GL_ALL_BARRIER_BITS_EXT           0xFFFFFFFF
+typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREEXTPROC) (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format);
+typedef void (APIENTRYP PFNGLMEMORYBARRIEREXTPROC) (GLbitfield barriers);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindImageTextureEXT (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format);
+GLAPI void APIENTRY glMemoryBarrierEXT (GLbitfield barriers);
+#endif
+#endif /* GL_EXT_shader_image_load_store */
+
+#ifndef GL_EXT_shader_integer_mix
+#define GL_EXT_shader_integer_mix 1
+#endif /* GL_EXT_shader_integer_mix */
+
+#ifndef GL_EXT_shadow_funcs
+#define GL_EXT_shadow_funcs 1
+#endif /* GL_EXT_shadow_funcs */
+
+#ifndef GL_EXT_shared_texture_palette
+#define GL_EXT_shared_texture_palette 1
+#define GL_SHARED_TEXTURE_PALETTE_EXT     0x81FB
+#endif /* GL_EXT_shared_texture_palette */
+
+#ifndef GL_EXT_sparse_texture2
+#define GL_EXT_sparse_texture2 1
+#endif /* GL_EXT_sparse_texture2 */
+
+#ifndef GL_EXT_stencil_clear_tag
+#define GL_EXT_stencil_clear_tag 1
+#define GL_STENCIL_TAG_BITS_EXT           0x88F2
+#define GL_STENCIL_CLEAR_TAG_VALUE_EXT    0x88F3
+typedef void (APIENTRYP PFNGLSTENCILCLEARTAGEXTPROC) (GLsizei stencilTagBits, GLuint stencilClearTag);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glStencilClearTagEXT (GLsizei stencilTagBits, GLuint stencilClearTag);
+#endif
+#endif /* GL_EXT_stencil_clear_tag */
+
+#ifndef GL_EXT_stencil_two_side
+#define GL_EXT_stencil_two_side 1
+#define GL_STENCIL_TEST_TWO_SIDE_EXT      0x8910
+#define GL_ACTIVE_STENCIL_FACE_EXT        0x8911
+typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glActiveStencilFaceEXT (GLenum face);
+#endif
+#endif /* GL_EXT_stencil_two_side */
+
+#ifndef GL_EXT_stencil_wrap
+#define GL_EXT_stencil_wrap 1
+#define GL_INCR_WRAP_EXT                  0x8507
+#define GL_DECR_WRAP_EXT                  0x8508
+#endif /* GL_EXT_stencil_wrap */
+
+#ifndef GL_EXT_subtexture
+#define GL_EXT_subtexture 1
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+#endif
+#endif /* GL_EXT_subtexture */
+
+#ifndef GL_EXT_texture
+#define GL_EXT_texture 1
+#define GL_ALPHA4_EXT                     0x803B
+#define GL_ALPHA8_EXT                     0x803C
+#define GL_ALPHA12_EXT                    0x803D
+#define GL_ALPHA16_EXT                    0x803E
+#define GL_LUMINANCE4_EXT                 0x803F
+#define GL_LUMINANCE8_EXT                 0x8040
+#define GL_LUMINANCE12_EXT                0x8041
+#define GL_LUMINANCE16_EXT                0x8042
+#define GL_LUMINANCE4_ALPHA4_EXT          0x8043
+#define GL_LUMINANCE6_ALPHA2_EXT          0x8044
+#define GL_LUMINANCE8_ALPHA8_EXT          0x8045
+#define GL_LUMINANCE12_ALPHA4_EXT         0x8046
+#define GL_LUMINANCE12_ALPHA12_EXT        0x8047
+#define GL_LUMINANCE16_ALPHA16_EXT        0x8048
+#define GL_INTENSITY_EXT                  0x8049
+#define GL_INTENSITY4_EXT                 0x804A
+#define GL_INTENSITY8_EXT                 0x804B
+#define GL_INTENSITY12_EXT                0x804C
+#define GL_INTENSITY16_EXT                0x804D
+#define GL_RGB2_EXT                       0x804E
+#define GL_RGB4_EXT                       0x804F
+#define GL_RGB5_EXT                       0x8050
+#define GL_RGB8_EXT                       0x8051
+#define GL_RGB10_EXT                      0x8052
+#define GL_RGB12_EXT                      0x8053
+#define GL_RGB16_EXT                      0x8054
+#define GL_RGBA2_EXT                      0x8055
+#define GL_RGBA4_EXT                      0x8056
+#define GL_RGB5_A1_EXT                    0x8057
+#define GL_RGBA8_EXT                      0x8058
+#define GL_RGB10_A2_EXT                   0x8059
+#define GL_RGBA12_EXT                     0x805A
+#define GL_RGBA16_EXT                     0x805B
+#define GL_TEXTURE_RED_SIZE_EXT           0x805C
+#define GL_TEXTURE_GREEN_SIZE_EXT         0x805D
+#define GL_TEXTURE_BLUE_SIZE_EXT          0x805E
+#define GL_TEXTURE_ALPHA_SIZE_EXT         0x805F
+#define GL_TEXTURE_LUMINANCE_SIZE_EXT     0x8060
+#define GL_TEXTURE_INTENSITY_SIZE_EXT     0x8061
+#define GL_REPLACE_EXT                    0x8062
+#define GL_PROXY_TEXTURE_1D_EXT           0x8063
+#define GL_PROXY_TEXTURE_2D_EXT           0x8064
+#define GL_TEXTURE_TOO_LARGE_EXT          0x8065
+#endif /* GL_EXT_texture */
+
+#ifndef GL_EXT_texture3D
+#define GL_EXT_texture3D 1
+#define GL_PACK_SKIP_IMAGES_EXT           0x806B
+#define GL_PACK_IMAGE_HEIGHT_EXT          0x806C
+#define GL_UNPACK_SKIP_IMAGES_EXT         0x806D
+#define GL_UNPACK_IMAGE_HEIGHT_EXT        0x806E
+#define GL_TEXTURE_3D_EXT                 0x806F
+#define GL_PROXY_TEXTURE_3D_EXT           0x8070
+#define GL_TEXTURE_DEPTH_EXT              0x8071
+#define GL_TEXTURE_WRAP_R_EXT             0x8072
+#define GL_MAX_3D_TEXTURE_SIZE_EXT        0x8073
+typedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexImage3DEXT (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+#endif
+#endif /* GL_EXT_texture3D */
+
+#ifndef GL_EXT_texture_array
+#define GL_EXT_texture_array 1
+#define GL_TEXTURE_1D_ARRAY_EXT           0x8C18
+#define GL_PROXY_TEXTURE_1D_ARRAY_EXT     0x8C19
+#define GL_TEXTURE_2D_ARRAY_EXT           0x8C1A
+#define GL_PROXY_TEXTURE_2D_ARRAY_EXT     0x8C1B
+#define GL_TEXTURE_BINDING_1D_ARRAY_EXT   0x8C1C
+#define GL_TEXTURE_BINDING_2D_ARRAY_EXT   0x8C1D
+#define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT   0x88FF
+#define GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFramebufferTextureLayerEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+#endif
+#endif /* GL_EXT_texture_array */
+
+#ifndef GL_EXT_texture_buffer_object
+#define GL_EXT_texture_buffer_object 1
+#define GL_TEXTURE_BUFFER_EXT             0x8C2A
+#define GL_MAX_TEXTURE_BUFFER_SIZE_EXT    0x8C2B
+#define GL_TEXTURE_BINDING_BUFFER_EXT     0x8C2C
+#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D
+#define GL_TEXTURE_BUFFER_FORMAT_EXT      0x8C2E
+typedef void (APIENTRYP PFNGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexBufferEXT (GLenum target, GLenum internalformat, GLuint buffer);
+#endif
+#endif /* GL_EXT_texture_buffer_object */
+
+#ifndef GL_EXT_texture_compression_latc
+#define GL_EXT_texture_compression_latc 1
+#define GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70
+#define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71
+#define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72
+#define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73
+#endif /* GL_EXT_texture_compression_latc */
+
+#ifndef GL_EXT_texture_compression_rgtc
+#define GL_EXT_texture_compression_rgtc 1
+#define GL_COMPRESSED_RED_RGTC1_EXT       0x8DBB
+#define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC
+#define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD
+#define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE
+#endif /* GL_EXT_texture_compression_rgtc */
+
+#ifndef GL_EXT_texture_compression_s3tc
+#define GL_EXT_texture_compression_s3tc 1
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT   0x83F0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT  0x83F1
+#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT  0x83F2
+#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT  0x83F3
+#endif /* GL_EXT_texture_compression_s3tc */
+
+#ifndef GL_EXT_texture_cube_map
+#define GL_EXT_texture_cube_map 1
+#define GL_NORMAL_MAP_EXT                 0x8511
+#define GL_REFLECTION_MAP_EXT             0x8512
+#define GL_TEXTURE_CUBE_MAP_EXT           0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP_EXT   0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP_EXT     0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT  0x851C
+#endif /* GL_EXT_texture_cube_map */
+
+#ifndef GL_EXT_texture_env_add
+#define GL_EXT_texture_env_add 1
+#endif /* GL_EXT_texture_env_add */
+
+#ifndef GL_EXT_texture_env_combine
+#define GL_EXT_texture_env_combine 1
+#define GL_COMBINE_EXT                    0x8570
+#define GL_COMBINE_RGB_EXT                0x8571
+#define GL_COMBINE_ALPHA_EXT              0x8572
+#define GL_RGB_SCALE_EXT                  0x8573
+#define GL_ADD_SIGNED_EXT                 0x8574
+#define GL_INTERPOLATE_EXT                0x8575
+#define GL_CONSTANT_EXT                   0x8576
+#define GL_PRIMARY_COLOR_EXT              0x8577
+#define GL_PREVIOUS_EXT                   0x8578
+#define GL_SOURCE0_RGB_EXT                0x8580
+#define GL_SOURCE1_RGB_EXT                0x8581
+#define GL_SOURCE2_RGB_EXT                0x8582
+#define GL_SOURCE0_ALPHA_EXT              0x8588
+#define GL_SOURCE1_ALPHA_EXT              0x8589
+#define GL_SOURCE2_ALPHA_EXT              0x858A
+#define GL_OPERAND0_RGB_EXT               0x8590
+#define GL_OPERAND1_RGB_EXT               0x8591
+#define GL_OPERAND2_RGB_EXT               0x8592
+#define GL_OPERAND0_ALPHA_EXT             0x8598
+#define GL_OPERAND1_ALPHA_EXT             0x8599
+#define GL_OPERAND2_ALPHA_EXT             0x859A
+#endif /* GL_EXT_texture_env_combine */
+
+#ifndef GL_EXT_texture_env_dot3
+#define GL_EXT_texture_env_dot3 1
+#define GL_DOT3_RGB_EXT                   0x8740
+#define GL_DOT3_RGBA_EXT                  0x8741
+#endif /* GL_EXT_texture_env_dot3 */
+
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_EXT_texture_filter_anisotropic 1
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT     0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+#endif /* GL_EXT_texture_filter_anisotropic */
+
+#ifndef GL_EXT_texture_filter_minmax
+#define GL_EXT_texture_filter_minmax 1
+#define GL_TEXTURE_REDUCTION_MODE_EXT     0x9366
+#define GL_WEIGHTED_AVERAGE_EXT           0x9367
+#endif /* GL_EXT_texture_filter_minmax */
+
+#ifndef GL_EXT_texture_integer
+#define GL_EXT_texture_integer 1
+#define GL_RGBA32UI_EXT                   0x8D70
+#define GL_RGB32UI_EXT                    0x8D71
+#define GL_ALPHA32UI_EXT                  0x8D72
+#define GL_INTENSITY32UI_EXT              0x8D73
+#define GL_LUMINANCE32UI_EXT              0x8D74
+#define GL_LUMINANCE_ALPHA32UI_EXT        0x8D75
+#define GL_RGBA16UI_EXT                   0x8D76
+#define GL_RGB16UI_EXT                    0x8D77
+#define GL_ALPHA16UI_EXT                  0x8D78
+#define GL_INTENSITY16UI_EXT              0x8D79
+#define GL_LUMINANCE16UI_EXT              0x8D7A
+#define GL_LUMINANCE_ALPHA16UI_EXT        0x8D7B
+#define GL_RGBA8UI_EXT                    0x8D7C
+#define GL_RGB8UI_EXT                     0x8D7D
+#define GL_ALPHA8UI_EXT                   0x8D7E
+#define GL_INTENSITY8UI_EXT               0x8D7F
+#define GL_LUMINANCE8UI_EXT               0x8D80
+#define GL_LUMINANCE_ALPHA8UI_EXT         0x8D81
+#define GL_RGBA32I_EXT                    0x8D82
+#define GL_RGB32I_EXT                     0x8D83
+#define GL_ALPHA32I_EXT                   0x8D84
+#define GL_INTENSITY32I_EXT               0x8D85
+#define GL_LUMINANCE32I_EXT               0x8D86
+#define GL_LUMINANCE_ALPHA32I_EXT         0x8D87
+#define GL_RGBA16I_EXT                    0x8D88
+#define GL_RGB16I_EXT                     0x8D89
+#define GL_ALPHA16I_EXT                   0x8D8A
+#define GL_INTENSITY16I_EXT               0x8D8B
+#define GL_LUMINANCE16I_EXT               0x8D8C
+#define GL_LUMINANCE_ALPHA16I_EXT         0x8D8D
+#define GL_RGBA8I_EXT                     0x8D8E
+#define GL_RGB8I_EXT                      0x8D8F
+#define GL_ALPHA8I_EXT                    0x8D90
+#define GL_INTENSITY8I_EXT                0x8D91
+#define GL_LUMINANCE8I_EXT                0x8D92
+#define GL_LUMINANCE_ALPHA8I_EXT          0x8D93
+#define GL_RED_INTEGER_EXT                0x8D94
+#define GL_GREEN_INTEGER_EXT              0x8D95
+#define GL_BLUE_INTEGER_EXT               0x8D96
+#define GL_ALPHA_INTEGER_EXT              0x8D97
+#define GL_RGB_INTEGER_EXT                0x8D98
+#define GL_RGBA_INTEGER_EXT               0x8D99
+#define GL_BGR_INTEGER_EXT                0x8D9A
+#define GL_BGRA_INTEGER_EXT               0x8D9B
+#define GL_LUMINANCE_INTEGER_EXT          0x8D9C
+#define GL_LUMINANCE_ALPHA_INTEGER_EXT    0x8D9D
+#define GL_RGBA_INTEGER_MODE_EXT          0x8D9E
+typedef void (APIENTRYP PFNGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params);
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLCLEARCOLORIIEXTPROC) (GLint red, GLint green, GLint blue, GLint alpha);
+typedef void (APIENTRYP PFNGLCLEARCOLORIUIEXTPROC) (GLuint red, GLuint green, GLuint blue, GLuint alpha);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexParameterIivEXT (GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glTexParameterIuivEXT (GLenum target, GLenum pname, const GLuint *params);
+GLAPI void APIENTRY glGetTexParameterIivEXT (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetTexParameterIuivEXT (GLenum target, GLenum pname, GLuint *params);
+GLAPI void APIENTRY glClearColorIiEXT (GLint red, GLint green, GLint blue, GLint alpha);
+GLAPI void APIENTRY glClearColorIuiEXT (GLuint red, GLuint green, GLuint blue, GLuint alpha);
+#endif
+#endif /* GL_EXT_texture_integer */
+
+#ifndef GL_EXT_texture_lod_bias
+#define GL_EXT_texture_lod_bias 1
+#define GL_MAX_TEXTURE_LOD_BIAS_EXT       0x84FD
+#define GL_TEXTURE_FILTER_CONTROL_EXT     0x8500
+#define GL_TEXTURE_LOD_BIAS_EXT           0x8501
+#endif /* GL_EXT_texture_lod_bias */
+
+#ifndef GL_EXT_texture_mirror_clamp
+#define GL_EXT_texture_mirror_clamp 1
+#define GL_MIRROR_CLAMP_EXT               0x8742
+#define GL_MIRROR_CLAMP_TO_EDGE_EXT       0x8743
+#define GL_MIRROR_CLAMP_TO_BORDER_EXT     0x8912
+#endif /* GL_EXT_texture_mirror_clamp */
+
+#ifndef GL_EXT_texture_object
+#define GL_EXT_texture_object 1
+#define GL_TEXTURE_PRIORITY_EXT           0x8066
+#define GL_TEXTURE_RESIDENT_EXT           0x8067
+#define GL_TEXTURE_1D_BINDING_EXT         0x8068
+#define GL_TEXTURE_2D_BINDING_EXT         0x8069
+#define GL_TEXTURE_3D_BINDING_EXT         0x806A
+typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences);
+typedef void (APIENTRYP PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture);
+typedef void (APIENTRYP PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures);
+typedef void (APIENTRYP PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures);
+typedef GLboolean (APIENTRYP PFNGLISTEXTUREEXTPROC) (GLuint texture);
+typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLboolean APIENTRY glAreTexturesResidentEXT (GLsizei n, const GLuint *textures, GLboolean *residences);
+GLAPI void APIENTRY glBindTextureEXT (GLenum target, GLuint texture);
+GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei n, const GLuint *textures);
+GLAPI void APIENTRY glGenTexturesEXT (GLsizei n, GLuint *textures);
+GLAPI GLboolean APIENTRY glIsTextureEXT (GLuint texture);
+GLAPI void APIENTRY glPrioritizeTexturesEXT (GLsizei n, const GLuint *textures, const GLclampf *priorities);
+#endif
+#endif /* GL_EXT_texture_object */
+
+#ifndef GL_EXT_texture_perturb_normal
+#define GL_EXT_texture_perturb_normal 1
+#define GL_PERTURB_EXT                    0x85AE
+#define GL_TEXTURE_NORMAL_EXT             0x85AF
+typedef void (APIENTRYP PFNGLTEXTURENORMALEXTPROC) (GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTextureNormalEXT (GLenum mode);
+#endif
+#endif /* GL_EXT_texture_perturb_normal */
+
+#ifndef GL_EXT_texture_sRGB
+#define GL_EXT_texture_sRGB 1
+#define GL_SRGB_EXT                       0x8C40
+#define GL_SRGB8_EXT                      0x8C41
+#define GL_SRGB_ALPHA_EXT                 0x8C42
+#define GL_SRGB8_ALPHA8_EXT               0x8C43
+#define GL_SLUMINANCE_ALPHA_EXT           0x8C44
+#define GL_SLUMINANCE8_ALPHA8_EXT         0x8C45
+#define GL_SLUMINANCE_EXT                 0x8C46
+#define GL_SLUMINANCE8_EXT                0x8C47
+#define GL_COMPRESSED_SRGB_EXT            0x8C48
+#define GL_COMPRESSED_SRGB_ALPHA_EXT      0x8C49
+#define GL_COMPRESSED_SLUMINANCE_EXT      0x8C4A
+#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B
+#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT  0x8C4C
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F
+#endif /* GL_EXT_texture_sRGB */
+
+#ifndef GL_EXT_texture_sRGB_R8
+#define GL_EXT_texture_sRGB_R8 1
+#define GL_SR8_EXT                        0x8FBD
+#endif /* GL_EXT_texture_sRGB_R8 */
+
+#ifndef GL_EXT_texture_sRGB_decode
+#define GL_EXT_texture_sRGB_decode 1
+#define GL_TEXTURE_SRGB_DECODE_EXT        0x8A48
+#define GL_DECODE_EXT                     0x8A49
+#define GL_SKIP_DECODE_EXT                0x8A4A
+#endif /* GL_EXT_texture_sRGB_decode */
+
+#ifndef GL_EXT_texture_shared_exponent
+#define GL_EXT_texture_shared_exponent 1
+#define GL_RGB9_E5_EXT                    0x8C3D
+#define GL_UNSIGNED_INT_5_9_9_9_REV_EXT   0x8C3E
+#define GL_TEXTURE_SHARED_SIZE_EXT        0x8C3F
+#endif /* GL_EXT_texture_shared_exponent */
+
+#ifndef GL_EXT_texture_snorm
+#define GL_EXT_texture_snorm 1
+#define GL_ALPHA_SNORM                    0x9010
+#define GL_LUMINANCE_SNORM                0x9011
+#define GL_LUMINANCE_ALPHA_SNORM          0x9012
+#define GL_INTENSITY_SNORM                0x9013
+#define GL_ALPHA8_SNORM                   0x9014
+#define GL_LUMINANCE8_SNORM               0x9015
+#define GL_LUMINANCE8_ALPHA8_SNORM        0x9016
+#define GL_INTENSITY8_SNORM               0x9017
+#define GL_ALPHA16_SNORM                  0x9018
+#define GL_LUMINANCE16_SNORM              0x9019
+#define GL_LUMINANCE16_ALPHA16_SNORM      0x901A
+#define GL_INTENSITY16_SNORM              0x901B
+#define GL_RED_SNORM                      0x8F90
+#define GL_RG_SNORM                       0x8F91
+#define GL_RGB_SNORM                      0x8F92
+#define GL_RGBA_SNORM                     0x8F93
+#endif /* GL_EXT_texture_snorm */
+
+#ifndef GL_EXT_texture_swizzle
+#define GL_EXT_texture_swizzle 1
+#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 /* GL_EXT_texture_swizzle */
+
+#ifndef GL_EXT_timer_query
+#define GL_EXT_timer_query 1
+#define GL_TIME_ELAPSED_EXT               0x88BF
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64 *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64 *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetQueryObjecti64vEXT (GLuint id, GLenum pname, GLint64 *params);
+GLAPI void APIENTRY glGetQueryObjectui64vEXT (GLuint id, GLenum pname, GLuint64 *params);
+#endif
+#endif /* GL_EXT_timer_query */
+
+#ifndef GL_EXT_transform_feedback
+#define GL_EXT_transform_feedback 1
+#define GL_TRANSFORM_FEEDBACK_BUFFER_EXT  0x8C8E
+#define GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT 0x8C84
+#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT 0x8C85
+#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT 0x8C8F
+#define GL_INTERLEAVED_ATTRIBS_EXT        0x8C8C
+#define GL_SEPARATE_ATTRIBS_EXT           0x8C8D
+#define GL_PRIMITIVES_GENERATED_EXT       0x8C87
+#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT 0x8C88
+#define GL_RASTERIZER_DISCARD_EXT         0x8C89
+#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT 0x8C8A
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT 0x8C8B
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT 0x8C80
+#define GL_TRANSFORM_FEEDBACK_VARYINGS_EXT 0x8C83
+#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT 0x8C7F
+#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT 0x8C76
+typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKEXTPROC) (GLenum primitiveMode);
+typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKEXTPROC) (void);
+typedef void (APIENTRYP PFNGLBINDBUFFERRANGEEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset);
+typedef void (APIENTRYP PFNGLBINDBUFFERBASEEXTPROC) (GLenum target, GLuint index, GLuint buffer);
+typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);
+typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBeginTransformFeedbackEXT (GLenum primitiveMode);
+GLAPI void APIENTRY glEndTransformFeedbackEXT (void);
+GLAPI void APIENTRY glBindBufferRangeEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+GLAPI void APIENTRY glBindBufferOffsetEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset);
+GLAPI void APIENTRY glBindBufferBaseEXT (GLenum target, GLuint index, GLuint buffer);
+GLAPI void APIENTRY glTransformFeedbackVaryingsEXT (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);
+GLAPI void APIENTRY glGetTransformFeedbackVaryingEXT (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);
+#endif
+#endif /* GL_EXT_transform_feedback */
+
+#ifndef GL_EXT_vertex_array
+#define GL_EXT_vertex_array 1
+#define GL_VERTEX_ARRAY_EXT               0x8074
+#define GL_NORMAL_ARRAY_EXT               0x8075
+#define GL_COLOR_ARRAY_EXT                0x8076
+#define GL_INDEX_ARRAY_EXT                0x8077
+#define GL_TEXTURE_COORD_ARRAY_EXT        0x8078
+#define GL_EDGE_FLAG_ARRAY_EXT            0x8079
+#define GL_VERTEX_ARRAY_SIZE_EXT          0x807A
+#define GL_VERTEX_ARRAY_TYPE_EXT          0x807B
+#define GL_VERTEX_ARRAY_STRIDE_EXT        0x807C
+#define GL_VERTEX_ARRAY_COUNT_EXT         0x807D
+#define GL_NORMAL_ARRAY_TYPE_EXT          0x807E
+#define GL_NORMAL_ARRAY_STRIDE_EXT        0x807F
+#define GL_NORMAL_ARRAY_COUNT_EXT         0x8080
+#define GL_COLOR_ARRAY_SIZE_EXT           0x8081
+#define GL_COLOR_ARRAY_TYPE_EXT           0x8082
+#define GL_COLOR_ARRAY_STRIDE_EXT         0x8083
+#define GL_COLOR_ARRAY_COUNT_EXT          0x8084
+#define GL_INDEX_ARRAY_TYPE_EXT           0x8085
+#define GL_INDEX_ARRAY_STRIDE_EXT         0x8086
+#define GL_INDEX_ARRAY_COUNT_EXT          0x8087
+#define GL_TEXTURE_COORD_ARRAY_SIZE_EXT   0x8088
+#define GL_TEXTURE_COORD_ARRAY_TYPE_EXT   0x8089
+#define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A
+#define GL_TEXTURE_COORD_ARRAY_COUNT_EXT  0x808B
+#define GL_EDGE_FLAG_ARRAY_STRIDE_EXT     0x808C
+#define GL_EDGE_FLAG_ARRAY_COUNT_EXT      0x808D
+#define GL_VERTEX_ARRAY_POINTER_EXT       0x808E
+#define GL_NORMAL_ARRAY_POINTER_EXT       0x808F
+#define GL_COLOR_ARRAY_POINTER_EXT        0x8090
+#define GL_INDEX_ARRAY_POINTER_EXT        0x8091
+#define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092
+#define GL_EDGE_FLAG_ARRAY_POINTER_EXT    0x8093
+typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i);
+typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer);
+typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, void **params);
+typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glArrayElementEXT (GLint i);
+GLAPI void APIENTRY glColorPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+GLAPI void APIENTRY glDrawArraysEXT (GLenum mode, GLint first, GLsizei count);
+GLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei stride, GLsizei count, const GLboolean *pointer);
+GLAPI void APIENTRY glGetPointervEXT (GLenum pname, void **params);
+GLAPI void APIENTRY glIndexPointerEXT (GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+GLAPI void APIENTRY glNormalPointerEXT (GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+GLAPI void APIENTRY glTexCoordPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+GLAPI void APIENTRY glVertexPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+#endif
+#endif /* GL_EXT_vertex_array */
+
+#ifndef GL_EXT_vertex_array_bgra
+#define GL_EXT_vertex_array_bgra 1
+#endif /* GL_EXT_vertex_array_bgra */
+
+#ifndef GL_EXT_vertex_attrib_64bit
+#define GL_EXT_vertex_attrib_64bit 1
+#define GL_DOUBLE_VEC2_EXT                0x8FFC
+#define GL_DOUBLE_VEC3_EXT                0x8FFD
+#define GL_DOUBLE_VEC4_EXT                0x8FFE
+#define GL_DOUBLE_MAT2_EXT                0x8F46
+#define GL_DOUBLE_MAT3_EXT                0x8F47
+#define GL_DOUBLE_MAT4_EXT                0x8F48
+#define GL_DOUBLE_MAT2x3_EXT              0x8F49
+#define GL_DOUBLE_MAT2x4_EXT              0x8F4A
+#define GL_DOUBLE_MAT3x2_EXT              0x8F4B
+#define GL_DOUBLE_MAT3x4_EXT              0x8F4C
+#define GL_DOUBLE_MAT4x2_EXT              0x8F4D
+#define GL_DOUBLE_MAT4x3_EXT              0x8F4E
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DEXTPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DEXTPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVEXTPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVEXTPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVEXTPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVEXTPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVEXTPROC) (GLuint index, GLenum pname, GLdouble *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttribL1dEXT (GLuint index, GLdouble x);
+GLAPI void APIENTRY glVertexAttribL2dEXT (GLuint index, GLdouble x, GLdouble y);
+GLAPI void APIENTRY glVertexAttribL3dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glVertexAttribL4dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glVertexAttribL1dvEXT (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribL2dvEXT (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribL3dvEXT (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribL4dvEXT (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribLPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glGetVertexAttribLdvEXT (GLuint index, GLenum pname, GLdouble *params);
+#endif
+#endif /* GL_EXT_vertex_attrib_64bit */
+
+#ifndef GL_EXT_vertex_shader
+#define GL_EXT_vertex_shader 1
+#define GL_VERTEX_SHADER_EXT              0x8780
+#define GL_VERTEX_SHADER_BINDING_EXT      0x8781
+#define GL_OP_INDEX_EXT                   0x8782
+#define GL_OP_NEGATE_EXT                  0x8783
+#define GL_OP_DOT3_EXT                    0x8784
+#define GL_OP_DOT4_EXT                    0x8785
+#define GL_OP_MUL_EXT                     0x8786
+#define GL_OP_ADD_EXT                     0x8787
+#define GL_OP_MADD_EXT                    0x8788
+#define GL_OP_FRAC_EXT                    0x8789
+#define GL_OP_MAX_EXT                     0x878A
+#define GL_OP_MIN_EXT                     0x878B
+#define GL_OP_SET_GE_EXT                  0x878C
+#define GL_OP_SET_LT_EXT                  0x878D
+#define GL_OP_CLAMP_EXT                   0x878E
+#define GL_OP_FLOOR_EXT                   0x878F
+#define GL_OP_ROUND_EXT                   0x8790
+#define GL_OP_EXP_BASE_2_EXT              0x8791
+#define GL_OP_LOG_BASE_2_EXT              0x8792
+#define GL_OP_POWER_EXT                   0x8793
+#define GL_OP_RECIP_EXT                   0x8794
+#define GL_OP_RECIP_SQRT_EXT              0x8795
+#define GL_OP_SUB_EXT                     0x8796
+#define GL_OP_CROSS_PRODUCT_EXT           0x8797
+#define GL_OP_MULTIPLY_MATRIX_EXT         0x8798
+#define GL_OP_MOV_EXT                     0x8799
+#define GL_OUTPUT_VERTEX_EXT              0x879A
+#define GL_OUTPUT_COLOR0_EXT              0x879B
+#define GL_OUTPUT_COLOR1_EXT              0x879C
+#define GL_OUTPUT_TEXTURE_COORD0_EXT      0x879D
+#define GL_OUTPUT_TEXTURE_COORD1_EXT      0x879E
+#define GL_OUTPUT_TEXTURE_COORD2_EXT      0x879F
+#define GL_OUTPUT_TEXTURE_COORD3_EXT      0x87A0
+#define GL_OUTPUT_TEXTURE_COORD4_EXT      0x87A1
+#define GL_OUTPUT_TEXTURE_COORD5_EXT      0x87A2
+#define GL_OUTPUT_TEXTURE_COORD6_EXT      0x87A3
+#define GL_OUTPUT_TEXTURE_COORD7_EXT      0x87A4
+#define GL_OUTPUT_TEXTURE_COORD8_EXT      0x87A5
+#define GL_OUTPUT_TEXTURE_COORD9_EXT      0x87A6
+#define GL_OUTPUT_TEXTURE_COORD10_EXT     0x87A7
+#define GL_OUTPUT_TEXTURE_COORD11_EXT     0x87A8
+#define GL_OUTPUT_TEXTURE_COORD12_EXT     0x87A9
+#define GL_OUTPUT_TEXTURE_COORD13_EXT     0x87AA
+#define GL_OUTPUT_TEXTURE_COORD14_EXT     0x87AB
+#define GL_OUTPUT_TEXTURE_COORD15_EXT     0x87AC
+#define GL_OUTPUT_TEXTURE_COORD16_EXT     0x87AD
+#define GL_OUTPUT_TEXTURE_COORD17_EXT     0x87AE
+#define GL_OUTPUT_TEXTURE_COORD18_EXT     0x87AF
+#define GL_OUTPUT_TEXTURE_COORD19_EXT     0x87B0
+#define GL_OUTPUT_TEXTURE_COORD20_EXT     0x87B1
+#define GL_OUTPUT_TEXTURE_COORD21_EXT     0x87B2
+#define GL_OUTPUT_TEXTURE_COORD22_EXT     0x87B3
+#define GL_OUTPUT_TEXTURE_COORD23_EXT     0x87B4
+#define GL_OUTPUT_TEXTURE_COORD24_EXT     0x87B5
+#define GL_OUTPUT_TEXTURE_COORD25_EXT     0x87B6
+#define GL_OUTPUT_TEXTURE_COORD26_EXT     0x87B7
+#define GL_OUTPUT_TEXTURE_COORD27_EXT     0x87B8
+#define GL_OUTPUT_TEXTURE_COORD28_EXT     0x87B9
+#define GL_OUTPUT_TEXTURE_COORD29_EXT     0x87BA
+#define GL_OUTPUT_TEXTURE_COORD30_EXT     0x87BB
+#define GL_OUTPUT_TEXTURE_COORD31_EXT     0x87BC
+#define GL_OUTPUT_FOG_EXT                 0x87BD
+#define GL_SCALAR_EXT                     0x87BE
+#define GL_VECTOR_EXT                     0x87BF
+#define GL_MATRIX_EXT                     0x87C0
+#define GL_VARIANT_EXT                    0x87C1
+#define GL_INVARIANT_EXT                  0x87C2
+#define GL_LOCAL_CONSTANT_EXT             0x87C3
+#define GL_LOCAL_EXT                      0x87C4
+#define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5
+#define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6
+#define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7
+#define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8
+#define GL_MAX_VERTEX_SHADER_LOCALS_EXT   0x87C9
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE
+#define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF
+#define GL_VERTEX_SHADER_VARIANTS_EXT     0x87D0
+#define GL_VERTEX_SHADER_INVARIANTS_EXT   0x87D1
+#define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2
+#define GL_VERTEX_SHADER_LOCALS_EXT       0x87D3
+#define GL_VERTEX_SHADER_OPTIMIZED_EXT    0x87D4
+#define GL_X_EXT                          0x87D5
+#define GL_Y_EXT                          0x87D6
+#define GL_Z_EXT                          0x87D7
+#define GL_W_EXT                          0x87D8
+#define GL_NEGATIVE_X_EXT                 0x87D9
+#define GL_NEGATIVE_Y_EXT                 0x87DA
+#define GL_NEGATIVE_Z_EXT                 0x87DB
+#define GL_NEGATIVE_W_EXT                 0x87DC
+#define GL_ZERO_EXT                       0x87DD
+#define GL_ONE_EXT                        0x87DE
+#define GL_NEGATIVE_ONE_EXT               0x87DF
+#define GL_NORMALIZED_RANGE_EXT           0x87E0
+#define GL_FULL_RANGE_EXT                 0x87E1
+#define GL_CURRENT_VERTEX_EXT             0x87E2
+#define GL_MVP_MATRIX_EXT                 0x87E3
+#define GL_VARIANT_VALUE_EXT              0x87E4
+#define GL_VARIANT_DATATYPE_EXT           0x87E5
+#define GL_VARIANT_ARRAY_STRIDE_EXT       0x87E6
+#define GL_VARIANT_ARRAY_TYPE_EXT         0x87E7
+#define GL_VARIANT_ARRAY_EXT              0x87E8
+#define GL_VARIANT_ARRAY_POINTER_EXT      0x87E9
+#define GL_INVARIANT_VALUE_EXT            0x87EA
+#define GL_INVARIANT_DATATYPE_EXT         0x87EB
+#define GL_LOCAL_CONSTANT_VALUE_EXT       0x87EC
+#define GL_LOCAL_CONSTANT_DATATYPE_EXT    0x87ED
+typedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC) (void);
+typedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC) (void);
+typedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC) (GLuint id);
+typedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC) (GLuint range);
+typedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1);
+typedef void (APIENTRYP PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2);
+typedef void (APIENTRYP PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3);
+typedef void (APIENTRYP PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);
+typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);
+typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num);
+typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num);
+typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components);
+typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const void *addr);
+typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const void *addr);
+typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr);
+typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr);
+typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr);
+typedef void (APIENTRYP PFNGLVARIANTFVEXTPROC) (GLuint id, const GLfloat *addr);
+typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr);
+typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr);
+typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr);
+typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr);
+typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const void *addr);
+typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id);
+typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC) (GLenum face, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC) (GLenum unit, GLenum coord, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC) (GLenum unit, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC) (GLenum value);
+typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap);
+typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);
+typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);
+typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, void **data);
+typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);
+typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBeginVertexShaderEXT (void);
+GLAPI void APIENTRY glEndVertexShaderEXT (void);
+GLAPI void APIENTRY glBindVertexShaderEXT (GLuint id);
+GLAPI GLuint APIENTRY glGenVertexShadersEXT (GLuint range);
+GLAPI void APIENTRY glDeleteVertexShaderEXT (GLuint id);
+GLAPI void APIENTRY glShaderOp1EXT (GLenum op, GLuint res, GLuint arg1);
+GLAPI void APIENTRY glShaderOp2EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2);
+GLAPI void APIENTRY glShaderOp3EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3);
+GLAPI void APIENTRY glSwizzleEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);
+GLAPI void APIENTRY glWriteMaskEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);
+GLAPI void APIENTRY glInsertComponentEXT (GLuint res, GLuint src, GLuint num);
+GLAPI void APIENTRY glExtractComponentEXT (GLuint res, GLuint src, GLuint num);
+GLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum datatype, GLenum storagetype, GLenum range, GLuint components);
+GLAPI void APIENTRY glSetInvariantEXT (GLuint id, GLenum type, const void *addr);
+GLAPI void APIENTRY glSetLocalConstantEXT (GLuint id, GLenum type, const void *addr);
+GLAPI void APIENTRY glVariantbvEXT (GLuint id, const GLbyte *addr);
+GLAPI void APIENTRY glVariantsvEXT (GLuint id, const GLshort *addr);
+GLAPI void APIENTRY glVariantivEXT (GLuint id, const GLint *addr);
+GLAPI void APIENTRY glVariantfvEXT (GLuint id, const GLfloat *addr);
+GLAPI void APIENTRY glVariantdvEXT (GLuint id, const GLdouble *addr);
+GLAPI void APIENTRY glVariantubvEXT (GLuint id, const GLubyte *addr);
+GLAPI void APIENTRY glVariantusvEXT (GLuint id, const GLushort *addr);
+GLAPI void APIENTRY glVariantuivEXT (GLuint id, const GLuint *addr);
+GLAPI void APIENTRY glVariantPointerEXT (GLuint id, GLenum type, GLuint stride, const void *addr);
+GLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint id);
+GLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint id);
+GLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum light, GLenum value);
+GLAPI GLuint APIENTRY glBindMaterialParameterEXT (GLenum face, GLenum value);
+GLAPI GLuint APIENTRY glBindTexGenParameterEXT (GLenum unit, GLenum coord, GLenum value);
+GLAPI GLuint APIENTRY glBindTextureUnitParameterEXT (GLenum unit, GLenum value);
+GLAPI GLuint APIENTRY glBindParameterEXT (GLenum value);
+GLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint id, GLenum cap);
+GLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data);
+GLAPI void APIENTRY glGetVariantIntegervEXT (GLuint id, GLenum value, GLint *data);
+GLAPI void APIENTRY glGetVariantFloatvEXT (GLuint id, GLenum value, GLfloat *data);
+GLAPI void APIENTRY glGetVariantPointervEXT (GLuint id, GLenum value, void **data);
+GLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data);
+GLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint id, GLenum value, GLint *data);
+GLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint id, GLenum value, GLfloat *data);
+GLAPI void APIENTRY glGetLocalConstantBooleanvEXT (GLuint id, GLenum value, GLboolean *data);
+GLAPI void APIENTRY glGetLocalConstantIntegervEXT (GLuint id, GLenum value, GLint *data);
+GLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint id, GLenum value, GLfloat *data);
+#endif
+#endif /* GL_EXT_vertex_shader */
+
+#ifndef GL_EXT_vertex_weighting
+#define GL_EXT_vertex_weighting 1
+#define GL_MODELVIEW0_STACK_DEPTH_EXT     0x0BA3
+#define GL_MODELVIEW1_STACK_DEPTH_EXT     0x8502
+#define GL_MODELVIEW0_MATRIX_EXT          0x0BA6
+#define GL_MODELVIEW1_MATRIX_EXT          0x8506
+#define GL_VERTEX_WEIGHTING_EXT           0x8509
+#define GL_MODELVIEW0_EXT                 0x1700
+#define GL_MODELVIEW1_EXT                 0x850A
+#define GL_CURRENT_VERTEX_WEIGHT_EXT      0x850B
+#define GL_VERTEX_WEIGHT_ARRAY_EXT        0x850C
+#define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT   0x850D
+#define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT   0x850E
+#define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F
+#define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexWeightfEXT (GLfloat weight);
+GLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *weight);
+GLAPI void APIENTRY glVertexWeightPointerEXT (GLint size, GLenum type, GLsizei stride, const void *pointer);
+#endif
+#endif /* GL_EXT_vertex_weighting */
+
+#ifndef GL_EXT_win32_keyed_mutex
+#define GL_EXT_win32_keyed_mutex 1
+typedef GLboolean (APIENTRYP PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC) (GLuint memory, GLuint64 key, GLuint timeout);
+typedef GLboolean (APIENTRYP PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC) (GLuint memory, GLuint64 key);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLboolean APIENTRY glAcquireKeyedMutexWin32EXT (GLuint memory, GLuint64 key, GLuint timeout);
+GLAPI GLboolean APIENTRY glReleaseKeyedMutexWin32EXT (GLuint memory, GLuint64 key);
+#endif
+#endif /* GL_EXT_win32_keyed_mutex */
+
+#ifndef GL_EXT_window_rectangles
+#define GL_EXT_window_rectangles 1
+#define GL_INCLUSIVE_EXT                  0x8F10
+#define GL_EXCLUSIVE_EXT                  0x8F11
+#define GL_WINDOW_RECTANGLE_EXT           0x8F12
+#define GL_WINDOW_RECTANGLE_MODE_EXT      0x8F13
+#define GL_MAX_WINDOW_RECTANGLES_EXT      0x8F14
+#define GL_NUM_WINDOW_RECTANGLES_EXT      0x8F15
+typedef void (APIENTRYP PFNGLWINDOWRECTANGLESEXTPROC) (GLenum mode, GLsizei count, const GLint *box);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glWindowRectanglesEXT (GLenum mode, GLsizei count, const GLint *box);
+#endif
+#endif /* GL_EXT_window_rectangles */
+
+#ifndef GL_EXT_x11_sync_object
+#define GL_EXT_x11_sync_object 1
+#define GL_SYNC_X11_FENCE_EXT             0x90E1
+typedef GLsync (APIENTRYP PFNGLIMPORTSYNCEXTPROC) (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLsync APIENTRY glImportSyncEXT (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags);
+#endif
+#endif /* GL_EXT_x11_sync_object */
+
+#ifndef GL_GREMEDY_frame_terminator
+#define GL_GREMEDY_frame_terminator 1
+typedef void (APIENTRYP PFNGLFRAMETERMINATORGREMEDYPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFrameTerminatorGREMEDY (void);
+#endif
+#endif /* GL_GREMEDY_frame_terminator */
+
+#ifndef GL_GREMEDY_string_marker
+#define GL_GREMEDY_string_marker 1
+typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const void *string);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei len, const void *string);
+#endif
+#endif /* GL_GREMEDY_string_marker */
+
+#ifndef GL_HP_convolution_border_modes
+#define GL_HP_convolution_border_modes 1
+#define GL_IGNORE_BORDER_HP               0x8150
+#define GL_CONSTANT_BORDER_HP             0x8151
+#define GL_REPLICATE_BORDER_HP            0x8153
+#define GL_CONVOLUTION_BORDER_COLOR_HP    0x8154
+#endif /* GL_HP_convolution_border_modes */
+
+#ifndef GL_HP_image_transform
+#define GL_HP_image_transform 1
+#define GL_IMAGE_SCALE_X_HP               0x8155
+#define GL_IMAGE_SCALE_Y_HP               0x8156
+#define GL_IMAGE_TRANSLATE_X_HP           0x8157
+#define GL_IMAGE_TRANSLATE_Y_HP           0x8158
+#define GL_IMAGE_ROTATE_ANGLE_HP          0x8159
+#define GL_IMAGE_ROTATE_ORIGIN_X_HP       0x815A
+#define GL_IMAGE_ROTATE_ORIGIN_Y_HP       0x815B
+#define GL_IMAGE_MAG_FILTER_HP            0x815C
+#define GL_IMAGE_MIN_FILTER_HP            0x815D
+#define GL_IMAGE_CUBIC_WEIGHT_HP          0x815E
+#define GL_CUBIC_HP                       0x815F
+#define GL_AVERAGE_HP                     0x8160
+#define GL_IMAGE_TRANSFORM_2D_HP          0x8161
+#define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162
+#define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glImageTransformParameteriHP (GLenum target, GLenum pname, GLint param);
+GLAPI void APIENTRY glImageTransformParameterfHP (GLenum target, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glImageTransformParameterivHP (GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glImageTransformParameterfvHP (GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glGetImageTransformParameterivHP (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum target, GLenum pname, GLfloat *params);
+#endif
+#endif /* GL_HP_image_transform */
+
+#ifndef GL_HP_occlusion_test
+#define GL_HP_occlusion_test 1
+#define GL_OCCLUSION_TEST_HP              0x8165
+#define GL_OCCLUSION_TEST_RESULT_HP       0x8166
+#endif /* GL_HP_occlusion_test */
+
+#ifndef GL_HP_texture_lighting
+#define GL_HP_texture_lighting 1
+#define GL_TEXTURE_LIGHTING_MODE_HP       0x8167
+#define GL_TEXTURE_POST_SPECULAR_HP       0x8168
+#define GL_TEXTURE_PRE_SPECULAR_HP        0x8169
+#endif /* GL_HP_texture_lighting */
+
+#ifndef GL_IBM_cull_vertex
+#define GL_IBM_cull_vertex 1
+#define GL_CULL_VERTEX_IBM                103050
+#endif /* GL_IBM_cull_vertex */
+
+#ifndef GL_IBM_multimode_draw_arrays
+#define GL_IBM_multimode_draw_arrays 1
+typedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride);
+typedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, GLint modestride);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride);
+GLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, GLint modestride);
+#endif
+#endif /* GL_IBM_multimode_draw_arrays */
+
+#ifndef GL_IBM_rasterpos_clip
+#define GL_IBM_rasterpos_clip 1
+#define GL_RASTER_POSITION_UNCLIPPED_IBM  0x19262
+#endif /* GL_IBM_rasterpos_clip */
+
+#ifndef GL_IBM_static_data
+#define GL_IBM_static_data 1
+#define GL_ALL_STATIC_DATA_IBM            103060
+#define GL_STATIC_VERTEX_ARRAY_IBM        103061
+typedef void (APIENTRYP PFNGLFLUSHSTATICDATAIBMPROC) (GLenum target);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFlushStaticDataIBM (GLenum target);
+#endif
+#endif /* GL_IBM_static_data */
+
+#ifndef GL_IBM_texture_mirrored_repeat
+#define GL_IBM_texture_mirrored_repeat 1
+#define GL_MIRRORED_REPEAT_IBM            0x8370
+#endif /* GL_IBM_texture_mirrored_repeat */
+
+#ifndef GL_IBM_vertex_array_lists
+#define GL_IBM_vertex_array_lists 1
+#define GL_VERTEX_ARRAY_LIST_IBM          103070
+#define GL_NORMAL_ARRAY_LIST_IBM          103071
+#define GL_COLOR_ARRAY_LIST_IBM           103072
+#define GL_INDEX_ARRAY_LIST_IBM           103073
+#define GL_TEXTURE_COORD_ARRAY_LIST_IBM   103074
+#define GL_EDGE_FLAG_ARRAY_LIST_IBM       103075
+#define GL_FOG_COORDINATE_ARRAY_LIST_IBM  103076
+#define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077
+#define GL_VERTEX_ARRAY_LIST_STRIDE_IBM   103080
+#define GL_NORMAL_ARRAY_LIST_STRIDE_IBM   103081
+#define GL_COLOR_ARRAY_LIST_STRIDE_IBM    103082
+#define GL_INDEX_ARRAY_LIST_STRIDE_IBM    103083
+#define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084
+#define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085
+#define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086
+#define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087
+typedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean **pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+GLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+GLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint stride, const GLboolean **pointer, GLint ptrstride);
+GLAPI void APIENTRY glFogCoordPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+GLAPI void APIENTRY glIndexPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+GLAPI void APIENTRY glNormalPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+GLAPI void APIENTRY glTexCoordPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+GLAPI void APIENTRY glVertexPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);
+#endif
+#endif /* GL_IBM_vertex_array_lists */
+
+#ifndef GL_INGR_blend_func_separate
+#define GL_INGR_blend_func_separate 1
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+#endif
+#endif /* GL_INGR_blend_func_separate */
+
+#ifndef GL_INGR_color_clamp
+#define GL_INGR_color_clamp 1
+#define GL_RED_MIN_CLAMP_INGR             0x8560
+#define GL_GREEN_MIN_CLAMP_INGR           0x8561
+#define GL_BLUE_MIN_CLAMP_INGR            0x8562
+#define GL_ALPHA_MIN_CLAMP_INGR           0x8563
+#define GL_RED_MAX_CLAMP_INGR             0x8564
+#define GL_GREEN_MAX_CLAMP_INGR           0x8565
+#define GL_BLUE_MAX_CLAMP_INGR            0x8566
+#define GL_ALPHA_MAX_CLAMP_INGR           0x8567
+#endif /* GL_INGR_color_clamp */
+
+#ifndef GL_INGR_interlace_read
+#define GL_INGR_interlace_read 1
+#define GL_INTERLACE_READ_INGR            0x8568
+#endif /* GL_INGR_interlace_read */
+
+#ifndef GL_INTEL_blackhole_render
+#define GL_INTEL_blackhole_render 1
+#define GL_BLACKHOLE_RENDER_INTEL         0x83FC
+#endif /* GL_INTEL_blackhole_render */
+
+#ifndef GL_INTEL_conservative_rasterization
+#define GL_INTEL_conservative_rasterization 1
+#define GL_CONSERVATIVE_RASTERIZATION_INTEL 0x83FE
+#endif /* GL_INTEL_conservative_rasterization */
+
+#ifndef GL_INTEL_fragment_shader_ordering
+#define GL_INTEL_fragment_shader_ordering 1
+#endif /* GL_INTEL_fragment_shader_ordering */
+
+#ifndef GL_INTEL_framebuffer_CMAA
+#define GL_INTEL_framebuffer_CMAA 1
+typedef void (APIENTRYP PFNGLAPPLYFRAMEBUFFERATTACHMENTCMAAINTELPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glApplyFramebufferAttachmentCMAAINTEL (void);
+#endif
+#endif /* GL_INTEL_framebuffer_CMAA */
+
+#ifndef GL_INTEL_map_texture
+#define GL_INTEL_map_texture 1
+#define GL_TEXTURE_MEMORY_LAYOUT_INTEL    0x83FF
+#define GL_LAYOUT_DEFAULT_INTEL           0
+#define GL_LAYOUT_LINEAR_INTEL            1
+#define GL_LAYOUT_LINEAR_CPU_CACHED_INTEL 2
+typedef void (APIENTRYP PFNGLSYNCTEXTUREINTELPROC) (GLuint texture);
+typedef void (APIENTRYP PFNGLUNMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level);
+typedef void *(APIENTRYP PFNGLMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level, GLbitfield access, GLint *stride, GLenum *layout);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSyncTextureINTEL (GLuint texture);
+GLAPI void APIENTRY glUnmapTexture2DINTEL (GLuint texture, GLint level);
+GLAPI void *APIENTRY glMapTexture2DINTEL (GLuint texture, GLint level, GLbitfield access, GLint *stride, GLenum *layout);
+#endif
+#endif /* GL_INTEL_map_texture */
+
+#ifndef GL_INTEL_parallel_arrays
+#define GL_INTEL_parallel_arrays 1
+#define GL_PARALLEL_ARRAYS_INTEL          0x83F4
+#define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5
+#define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6
+#define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7
+#define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8
+typedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer);
+typedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const void **pointer);
+typedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer);
+typedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexPointervINTEL (GLint size, GLenum type, const void **pointer);
+GLAPI void APIENTRY glNormalPointervINTEL (GLenum type, const void **pointer);
+GLAPI void APIENTRY glColorPointervINTEL (GLint size, GLenum type, const void **pointer);
+GLAPI void APIENTRY glTexCoordPointervINTEL (GLint size, GLenum type, const void **pointer);
+#endif
+#endif /* GL_INTEL_parallel_arrays */
+
+#ifndef GL_INTEL_performance_query
+#define GL_INTEL_performance_query 1
+#define GL_PERFQUERY_SINGLE_CONTEXT_INTEL 0x00000000
+#define GL_PERFQUERY_GLOBAL_CONTEXT_INTEL 0x00000001
+#define GL_PERFQUERY_WAIT_INTEL           0x83FB
+#define GL_PERFQUERY_FLUSH_INTEL          0x83FA
+#define GL_PERFQUERY_DONOT_FLUSH_INTEL    0x83F9
+#define GL_PERFQUERY_COUNTER_EVENT_INTEL  0x94F0
+#define GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL 0x94F1
+#define GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL 0x94F2
+#define GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL 0x94F3
+#define GL_PERFQUERY_COUNTER_RAW_INTEL    0x94F4
+#define GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL 0x94F5
+#define GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL 0x94F8
+#define GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL 0x94F9
+#define GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL 0x94FA
+#define GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL 0x94FB
+#define GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL 0x94FC
+#define GL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL 0x94FD
+#define GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL 0x94FE
+#define GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL 0x94FF
+#define GL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL 0x9500
+typedef void (APIENTRYP PFNGLBEGINPERFQUERYINTELPROC) (GLuint queryHandle);
+typedef void (APIENTRYP PFNGLCREATEPERFQUERYINTELPROC) (GLuint queryId, GLuint *queryHandle);
+typedef void (APIENTRYP PFNGLDELETEPERFQUERYINTELPROC) (GLuint queryHandle);
+typedef void (APIENTRYP PFNGLENDPERFQUERYINTELPROC) (GLuint queryHandle);
+typedef void (APIENTRYP PFNGLGETFIRSTPERFQUERYIDINTELPROC) (GLuint *queryId);
+typedef void (APIENTRYP PFNGLGETNEXTPERFQUERYIDINTELPROC) (GLuint queryId, GLuint *nextQueryId);
+typedef void (APIENTRYP PFNGLGETPERFCOUNTERINFOINTELPROC) (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue);
+typedef void (APIENTRYP PFNGLGETPERFQUERYDATAINTELPROC) (GLuint queryHandle, GLuint flags, GLsizei dataSize, void *data, GLuint *bytesWritten);
+typedef void (APIENTRYP PFNGLGETPERFQUERYIDBYNAMEINTELPROC) (GLchar *queryName, GLuint *queryId);
+typedef void (APIENTRYP PFNGLGETPERFQUERYINFOINTELPROC) (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBeginPerfQueryINTEL (GLuint queryHandle);
+GLAPI void APIENTRY glCreatePerfQueryINTEL (GLuint queryId, GLuint *queryHandle);
+GLAPI void APIENTRY glDeletePerfQueryINTEL (GLuint queryHandle);
+GLAPI void APIENTRY glEndPerfQueryINTEL (GLuint queryHandle);
+GLAPI void APIENTRY glGetFirstPerfQueryIdINTEL (GLuint *queryId);
+GLAPI void APIENTRY glGetNextPerfQueryIdINTEL (GLuint queryId, GLuint *nextQueryId);
+GLAPI void APIENTRY glGetPerfCounterInfoINTEL (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue);
+GLAPI void APIENTRY glGetPerfQueryDataINTEL (GLuint queryHandle, GLuint flags, GLsizei dataSize, void *data, GLuint *bytesWritten);
+GLAPI void APIENTRY glGetPerfQueryIdByNameINTEL (GLchar *queryName, GLuint *queryId);
+GLAPI void APIENTRY glGetPerfQueryInfoINTEL (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask);
+#endif
+#endif /* GL_INTEL_performance_query */
+
+#ifndef GL_MESAX_texture_stack
+#define GL_MESAX_texture_stack 1
+#define GL_TEXTURE_1D_STACK_MESAX         0x8759
+#define GL_TEXTURE_2D_STACK_MESAX         0x875A
+#define GL_PROXY_TEXTURE_1D_STACK_MESAX   0x875B
+#define GL_PROXY_TEXTURE_2D_STACK_MESAX   0x875C
+#define GL_TEXTURE_1D_STACK_BINDING_MESAX 0x875D
+#define GL_TEXTURE_2D_STACK_BINDING_MESAX 0x875E
+#endif /* GL_MESAX_texture_stack */
+
+#ifndef GL_MESA_pack_invert
+#define GL_MESA_pack_invert 1
+#define GL_PACK_INVERT_MESA               0x8758
+#endif /* GL_MESA_pack_invert */
+
+#ifndef GL_MESA_program_binary_formats
+#define GL_MESA_program_binary_formats 1
+#define GL_PROGRAM_BINARY_FORMAT_MESA     0x875F
+#endif /* GL_MESA_program_binary_formats */
+
+#ifndef GL_MESA_resize_buffers
+#define GL_MESA_resize_buffers 1
+typedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glResizeBuffersMESA (void);
+#endif
+#endif /* GL_MESA_resize_buffers */
+
+#ifndef GL_MESA_shader_integer_functions
+#define GL_MESA_shader_integer_functions 1
+#endif /* GL_MESA_shader_integer_functions */
+
+#ifndef GL_MESA_tile_raster_order
+#define GL_MESA_tile_raster_order 1
+#define GL_TILE_RASTER_ORDER_FIXED_MESA   0x8BB8
+#define GL_TILE_RASTER_ORDER_INCREASING_X_MESA 0x8BB9
+#define GL_TILE_RASTER_ORDER_INCREASING_Y_MESA 0x8BBA
+#endif /* GL_MESA_tile_raster_order */
+
+#ifndef GL_MESA_window_pos
+#define GL_MESA_window_pos 1
+typedef void (APIENTRYP PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IVMESAPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IVMESAPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4IMESAPROC) (GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4IVMESAPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *v);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glWindowPos2dMESA (GLdouble x, GLdouble y);
+GLAPI void APIENTRY glWindowPos2dvMESA (const GLdouble *v);
+GLAPI void APIENTRY glWindowPos2fMESA (GLfloat x, GLfloat y);
+GLAPI void APIENTRY glWindowPos2fvMESA (const GLfloat *v);
+GLAPI void APIENTRY glWindowPos2iMESA (GLint x, GLint y);
+GLAPI void APIENTRY glWindowPos2ivMESA (const GLint *v);
+GLAPI void APIENTRY glWindowPos2sMESA (GLshort x, GLshort y);
+GLAPI void APIENTRY glWindowPos2svMESA (const GLshort *v);
+GLAPI void APIENTRY glWindowPos3dMESA (GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glWindowPos3dvMESA (const GLdouble *v);
+GLAPI void APIENTRY glWindowPos3fMESA (GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glWindowPos3fvMESA (const GLfloat *v);
+GLAPI void APIENTRY glWindowPos3iMESA (GLint x, GLint y, GLint z);
+GLAPI void APIENTRY glWindowPos3ivMESA (const GLint *v);
+GLAPI void APIENTRY glWindowPos3sMESA (GLshort x, GLshort y, GLshort z);
+GLAPI void APIENTRY glWindowPos3svMESA (const GLshort *v);
+GLAPI void APIENTRY glWindowPos4dMESA (GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glWindowPos4dvMESA (const GLdouble *v);
+GLAPI void APIENTRY glWindowPos4fMESA (GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glWindowPos4fvMESA (const GLfloat *v);
+GLAPI void APIENTRY glWindowPos4iMESA (GLint x, GLint y, GLint z, GLint w);
+GLAPI void APIENTRY glWindowPos4ivMESA (const GLint *v);
+GLAPI void APIENTRY glWindowPos4sMESA (GLshort x, GLshort y, GLshort z, GLshort w);
+GLAPI void APIENTRY glWindowPos4svMESA (const GLshort *v);
+#endif
+#endif /* GL_MESA_window_pos */
+
+#ifndef GL_MESA_ycbcr_texture
+#define GL_MESA_ycbcr_texture 1
+#define GL_UNSIGNED_SHORT_8_8_MESA        0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_MESA    0x85BB
+#define GL_YCBCR_MESA                     0x8757
+#endif /* GL_MESA_ycbcr_texture */
+
+#ifndef GL_NVX_blend_equation_advanced_multi_draw_buffers
+#define GL_NVX_blend_equation_advanced_multi_draw_buffers 1
+#endif /* GL_NVX_blend_equation_advanced_multi_draw_buffers */
+
+#ifndef GL_NVX_conditional_render
+#define GL_NVX_conditional_render 1
+typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVXPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVXPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBeginConditionalRenderNVX (GLuint id);
+GLAPI void APIENTRY glEndConditionalRenderNVX (void);
+#endif
+#endif /* GL_NVX_conditional_render */
+
+#ifndef GL_NVX_gpu_memory_info
+#define GL_NVX_gpu_memory_info 1
+#define GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX 0x9047
+#define GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX 0x9048
+#define GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049
+#define GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX 0x904A
+#define GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX 0x904B
+#endif /* GL_NVX_gpu_memory_info */
+
+#ifndef GL_NVX_linked_gpu_multicast
+#define GL_NVX_linked_gpu_multicast 1
+#define GL_LGPU_SEPARATE_STORAGE_BIT_NVX  0x0800
+#define GL_MAX_LGPU_GPUS_NVX              0x92BA
+typedef void (APIENTRYP PFNGLLGPUNAMEDBUFFERSUBDATANVXPROC) (GLbitfield gpuMask, GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);
+typedef void (APIENTRYP PFNGLLGPUCOPYIMAGESUBDATANVXPROC) (GLuint sourceGpu, GLbitfield destinationGpuMask, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srxY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (APIENTRYP PFNGLLGPUINTERLOCKNVXPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glLGPUNamedBufferSubDataNVX (GLbitfield gpuMask, GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);
+GLAPI void APIENTRY glLGPUCopyImageSubDataNVX (GLuint sourceGpu, GLbitfield destinationGpuMask, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srxY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);
+GLAPI void APIENTRY glLGPUInterlockNVX (void);
+#endif
+#endif /* GL_NVX_linked_gpu_multicast */
+
+#ifndef GL_NV_alpha_to_coverage_dither_control
+#define GL_NV_alpha_to_coverage_dither_control 1
+#define GL_ALPHA_TO_COVERAGE_DITHER_DEFAULT_NV 0x934D
+#define GL_ALPHA_TO_COVERAGE_DITHER_ENABLE_NV 0x934E
+#define GL_ALPHA_TO_COVERAGE_DITHER_DISABLE_NV 0x934F
+#define GL_ALPHA_TO_COVERAGE_DITHER_MODE_NV 0x92BF
+typedef void (APIENTRYP PFNGLALPHATOCOVERAGEDITHERCONTROLNVPROC) (GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glAlphaToCoverageDitherControlNV (GLenum mode);
+#endif
+#endif /* GL_NV_alpha_to_coverage_dither_control */
+
+#ifndef GL_NV_bindless_multi_draw_indirect
+#define GL_NV_bindless_multi_draw_indirect 1
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC) (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiDrawArraysIndirectBindlessNV (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount);
+GLAPI void APIENTRY glMultiDrawElementsIndirectBindlessNV (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount);
+#endif
+#endif /* GL_NV_bindless_multi_draw_indirect */
+
+#ifndef GL_NV_bindless_multi_draw_indirect_count
+#define GL_NV_bindless_multi_draw_indirect_count 1
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSCOUNTNVPROC) (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSCOUNTNVPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiDrawArraysIndirectBindlessCountNV (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount);
+GLAPI void APIENTRY glMultiDrawElementsIndirectBindlessCountNV (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount);
+#endif
+#endif /* GL_NV_bindless_multi_draw_indirect_count */
+
+#ifndef GL_NV_bindless_texture
+#define GL_NV_bindless_texture 1
+typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLENVPROC) (GLuint texture);
+typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLENVPROC) (GLuint texture, GLuint sampler);
+typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle);
+typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTNVPROC) (GLuint64 handle);
+typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLENVPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format);
+typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle, GLenum access);
+typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTNVPROC) (GLuint64 handle);
+typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64NVPROC) (GLint location, GLuint64 value);
+typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VNVPROC) (GLint location, GLsizei count, const GLuint64 *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64NVPROC) (GLuint program, GLint location, GLuint64 value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values);
+typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle);
+typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLuint64 APIENTRY glGetTextureHandleNV (GLuint texture);
+GLAPI GLuint64 APIENTRY glGetTextureSamplerHandleNV (GLuint texture, GLuint sampler);
+GLAPI void APIENTRY glMakeTextureHandleResidentNV (GLuint64 handle);
+GLAPI void APIENTRY glMakeTextureHandleNonResidentNV (GLuint64 handle);
+GLAPI GLuint64 APIENTRY glGetImageHandleNV (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format);
+GLAPI void APIENTRY glMakeImageHandleResidentNV (GLuint64 handle, GLenum access);
+GLAPI void APIENTRY glMakeImageHandleNonResidentNV (GLuint64 handle);
+GLAPI void APIENTRY glUniformHandleui64NV (GLint location, GLuint64 value);
+GLAPI void APIENTRY glUniformHandleui64vNV (GLint location, GLsizei count, const GLuint64 *value);
+GLAPI void APIENTRY glProgramUniformHandleui64NV (GLuint program, GLint location, GLuint64 value);
+GLAPI void APIENTRY glProgramUniformHandleui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64 *values);
+GLAPI GLboolean APIENTRY glIsTextureHandleResidentNV (GLuint64 handle);
+GLAPI GLboolean APIENTRY glIsImageHandleResidentNV (GLuint64 handle);
+#endif
+#endif /* GL_NV_bindless_texture */
+
+#ifndef GL_NV_blend_equation_advanced
+#define GL_NV_blend_equation_advanced 1
+#define GL_BLEND_OVERLAP_NV               0x9281
+#define GL_BLEND_PREMULTIPLIED_SRC_NV     0x9280
+#define GL_BLUE_NV                        0x1905
+#define GL_COLORBURN_NV                   0x929A
+#define GL_COLORDODGE_NV                  0x9299
+#define GL_CONJOINT_NV                    0x9284
+#define GL_CONTRAST_NV                    0x92A1
+#define GL_DARKEN_NV                      0x9297
+#define GL_DIFFERENCE_NV                  0x929E
+#define GL_DISJOINT_NV                    0x9283
+#define GL_DST_ATOP_NV                    0x928F
+#define GL_DST_IN_NV                      0x928B
+#define GL_DST_NV                         0x9287
+#define GL_DST_OUT_NV                     0x928D
+#define GL_DST_OVER_NV                    0x9289
+#define GL_EXCLUSION_NV                   0x92A0
+#define GL_GREEN_NV                       0x1904
+#define GL_HARDLIGHT_NV                   0x929B
+#define GL_HARDMIX_NV                     0x92A9
+#define GL_HSL_COLOR_NV                   0x92AF
+#define GL_HSL_HUE_NV                     0x92AD
+#define GL_HSL_LUMINOSITY_NV              0x92B0
+#define GL_HSL_SATURATION_NV              0x92AE
+#define GL_INVERT_OVG_NV                  0x92B4
+#define GL_INVERT_RGB_NV                  0x92A3
+#define GL_LIGHTEN_NV                     0x9298
+#define GL_LINEARBURN_NV                  0x92A5
+#define GL_LINEARDODGE_NV                 0x92A4
+#define GL_LINEARLIGHT_NV                 0x92A7
+#define GL_MINUS_CLAMPED_NV               0x92B3
+#define GL_MINUS_NV                       0x929F
+#define GL_MULTIPLY_NV                    0x9294
+#define GL_OVERLAY_NV                     0x9296
+#define GL_PINLIGHT_NV                    0x92A8
+#define GL_PLUS_CLAMPED_ALPHA_NV          0x92B2
+#define GL_PLUS_CLAMPED_NV                0x92B1
+#define GL_PLUS_DARKER_NV                 0x9292
+#define GL_PLUS_NV                        0x9291
+#define GL_RED_NV                         0x1903
+#define GL_SCREEN_NV                      0x9295
+#define GL_SOFTLIGHT_NV                   0x929C
+#define GL_SRC_ATOP_NV                    0x928E
+#define GL_SRC_IN_NV                      0x928A
+#define GL_SRC_NV                         0x9286
+#define GL_SRC_OUT_NV                     0x928C
+#define GL_SRC_OVER_NV                    0x9288
+#define GL_UNCORRELATED_NV                0x9282
+#define GL_VIVIDLIGHT_NV                  0x92A6
+#define GL_XOR_NV                         0x1506
+typedef void (APIENTRYP PFNGLBLENDPARAMETERINVPROC) (GLenum pname, GLint value);
+typedef void (APIENTRYP PFNGLBLENDBARRIERNVPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendParameteriNV (GLenum pname, GLint value);
+GLAPI void APIENTRY glBlendBarrierNV (void);
+#endif
+#endif /* GL_NV_blend_equation_advanced */
+
+#ifndef GL_NV_blend_equation_advanced_coherent
+#define GL_NV_blend_equation_advanced_coherent 1
+#define GL_BLEND_ADVANCED_COHERENT_NV     0x9285
+#endif /* GL_NV_blend_equation_advanced_coherent */
+
+#ifndef GL_NV_blend_minmax_factor
+#define GL_NV_blend_minmax_factor 1
+#endif /* GL_NV_blend_minmax_factor */
+
+#ifndef GL_NV_blend_square
+#define GL_NV_blend_square 1
+#endif /* GL_NV_blend_square */
+
+#ifndef GL_NV_clip_space_w_scaling
+#define GL_NV_clip_space_w_scaling 1
+#define GL_VIEWPORT_POSITION_W_SCALE_NV   0x937C
+#define GL_VIEWPORT_POSITION_W_SCALE_X_COEFF_NV 0x937D
+#define GL_VIEWPORT_POSITION_W_SCALE_Y_COEFF_NV 0x937E
+typedef void (APIENTRYP PFNGLVIEWPORTPOSITIONWSCALENVPROC) (GLuint index, GLfloat xcoeff, GLfloat ycoeff);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glViewportPositionWScaleNV (GLuint index, GLfloat xcoeff, GLfloat ycoeff);
+#endif
+#endif /* GL_NV_clip_space_w_scaling */
+
+#ifndef GL_NV_command_list
+#define GL_NV_command_list 1
+#define GL_TERMINATE_SEQUENCE_COMMAND_NV  0x0000
+#define GL_NOP_COMMAND_NV                 0x0001
+#define GL_DRAW_ELEMENTS_COMMAND_NV       0x0002
+#define GL_DRAW_ARRAYS_COMMAND_NV         0x0003
+#define GL_DRAW_ELEMENTS_STRIP_COMMAND_NV 0x0004
+#define GL_DRAW_ARRAYS_STRIP_COMMAND_NV   0x0005
+#define GL_DRAW_ELEMENTS_INSTANCED_COMMAND_NV 0x0006
+#define GL_DRAW_ARRAYS_INSTANCED_COMMAND_NV 0x0007
+#define GL_ELEMENT_ADDRESS_COMMAND_NV     0x0008
+#define GL_ATTRIBUTE_ADDRESS_COMMAND_NV   0x0009
+#define GL_UNIFORM_ADDRESS_COMMAND_NV     0x000A
+#define GL_BLEND_COLOR_COMMAND_NV         0x000B
+#define GL_STENCIL_REF_COMMAND_NV         0x000C
+#define GL_LINE_WIDTH_COMMAND_NV          0x000D
+#define GL_POLYGON_OFFSET_COMMAND_NV      0x000E
+#define GL_ALPHA_REF_COMMAND_NV           0x000F
+#define GL_VIEWPORT_COMMAND_NV            0x0010
+#define GL_SCISSOR_COMMAND_NV             0x0011
+#define GL_FRONT_FACE_COMMAND_NV          0x0012
+typedef void (APIENTRYP PFNGLCREATESTATESNVPROC) (GLsizei n, GLuint *states);
+typedef void (APIENTRYP PFNGLDELETESTATESNVPROC) (GLsizei n, const GLuint *states);
+typedef GLboolean (APIENTRYP PFNGLISSTATENVPROC) (GLuint state);
+typedef void (APIENTRYP PFNGLSTATECAPTURENVPROC) (GLuint state, GLenum mode);
+typedef GLuint (APIENTRYP PFNGLGETCOMMANDHEADERNVPROC) (GLenum tokenID, GLuint size);
+typedef GLushort (APIENTRYP PFNGLGETSTAGEINDEXNVPROC) (GLenum shadertype);
+typedef void (APIENTRYP PFNGLDRAWCOMMANDSNVPROC) (GLenum primitiveMode, GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, GLuint count);
+typedef void (APIENTRYP PFNGLDRAWCOMMANDSADDRESSNVPROC) (GLenum primitiveMode, const GLuint64 *indirects, const GLsizei *sizes, GLuint count);
+typedef void (APIENTRYP PFNGLDRAWCOMMANDSSTATESNVPROC) (GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count);
+typedef void (APIENTRYP PFNGLDRAWCOMMANDSSTATESADDRESSNVPROC) (const GLuint64 *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count);
+typedef void (APIENTRYP PFNGLCREATECOMMANDLISTSNVPROC) (GLsizei n, GLuint *lists);
+typedef void (APIENTRYP PFNGLDELETECOMMANDLISTSNVPROC) (GLsizei n, const GLuint *lists);
+typedef GLboolean (APIENTRYP PFNGLISCOMMANDLISTNVPROC) (GLuint list);
+typedef void (APIENTRYP PFNGLLISTDRAWCOMMANDSSTATESCLIENTNVPROC) (GLuint list, GLuint segment, const void **indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count);
+typedef void (APIENTRYP PFNGLCOMMANDLISTSEGMENTSNVPROC) (GLuint list, GLuint segments);
+typedef void (APIENTRYP PFNGLCOMPILECOMMANDLISTNVPROC) (GLuint list);
+typedef void (APIENTRYP PFNGLCALLCOMMANDLISTNVPROC) (GLuint list);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCreateStatesNV (GLsizei n, GLuint *states);
+GLAPI void APIENTRY glDeleteStatesNV (GLsizei n, const GLuint *states);
+GLAPI GLboolean APIENTRY glIsStateNV (GLuint state);
+GLAPI void APIENTRY glStateCaptureNV (GLuint state, GLenum mode);
+GLAPI GLuint APIENTRY glGetCommandHeaderNV (GLenum tokenID, GLuint size);
+GLAPI GLushort APIENTRY glGetStageIndexNV (GLenum shadertype);
+GLAPI void APIENTRY glDrawCommandsNV (GLenum primitiveMode, GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, GLuint count);
+GLAPI void APIENTRY glDrawCommandsAddressNV (GLenum primitiveMode, const GLuint64 *indirects, const GLsizei *sizes, GLuint count);
+GLAPI void APIENTRY glDrawCommandsStatesNV (GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count);
+GLAPI void APIENTRY glDrawCommandsStatesAddressNV (const GLuint64 *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count);
+GLAPI void APIENTRY glCreateCommandListsNV (GLsizei n, GLuint *lists);
+GLAPI void APIENTRY glDeleteCommandListsNV (GLsizei n, const GLuint *lists);
+GLAPI GLboolean APIENTRY glIsCommandListNV (GLuint list);
+GLAPI void APIENTRY glListDrawCommandsStatesClientNV (GLuint list, GLuint segment, const void **indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count);
+GLAPI void APIENTRY glCommandListSegmentsNV (GLuint list, GLuint segments);
+GLAPI void APIENTRY glCompileCommandListNV (GLuint list);
+GLAPI void APIENTRY glCallCommandListNV (GLuint list);
+#endif
+#endif /* GL_NV_command_list */
+
+#ifndef GL_NV_compute_program5
+#define GL_NV_compute_program5 1
+#define GL_COMPUTE_PROGRAM_NV             0x90FB
+#define GL_COMPUTE_PROGRAM_PARAMETER_BUFFER_NV 0x90FC
+#endif /* GL_NV_compute_program5 */
+
+#ifndef GL_NV_compute_shader_derivatives
+#define GL_NV_compute_shader_derivatives 1
+#endif /* GL_NV_compute_shader_derivatives */
+
+#ifndef GL_NV_conditional_render
+#define GL_NV_conditional_render 1
+#define GL_QUERY_WAIT_NV                  0x8E13
+#define GL_QUERY_NO_WAIT_NV               0x8E14
+#define GL_QUERY_BY_REGION_WAIT_NV        0x8E15
+#define GL_QUERY_BY_REGION_NO_WAIT_NV     0x8E16
+typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVPROC) (GLuint id, GLenum mode);
+typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBeginConditionalRenderNV (GLuint id, GLenum mode);
+GLAPI void APIENTRY glEndConditionalRenderNV (void);
+#endif
+#endif /* GL_NV_conditional_render */
+
+#ifndef GL_NV_conservative_raster
+#define GL_NV_conservative_raster 1
+#define GL_CONSERVATIVE_RASTERIZATION_NV  0x9346
+#define GL_SUBPIXEL_PRECISION_BIAS_X_BITS_NV 0x9347
+#define GL_SUBPIXEL_PRECISION_BIAS_Y_BITS_NV 0x9348
+#define GL_MAX_SUBPIXEL_PRECISION_BIAS_BITS_NV 0x9349
+typedef void (APIENTRYP PFNGLSUBPIXELPRECISIONBIASNVPROC) (GLuint xbits, GLuint ybits);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSubpixelPrecisionBiasNV (GLuint xbits, GLuint ybits);
+#endif
+#endif /* GL_NV_conservative_raster */
+
+#ifndef GL_NV_conservative_raster_dilate
+#define GL_NV_conservative_raster_dilate 1
+#define GL_CONSERVATIVE_RASTER_DILATE_NV  0x9379
+#define GL_CONSERVATIVE_RASTER_DILATE_RANGE_NV 0x937A
+#define GL_CONSERVATIVE_RASTER_DILATE_GRANULARITY_NV 0x937B
+typedef void (APIENTRYP PFNGLCONSERVATIVERASTERPARAMETERFNVPROC) (GLenum pname, GLfloat value);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glConservativeRasterParameterfNV (GLenum pname, GLfloat value);
+#endif
+#endif /* GL_NV_conservative_raster_dilate */
+
+#ifndef GL_NV_conservative_raster_pre_snap
+#define GL_NV_conservative_raster_pre_snap 1
+#define GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_NV 0x9550
+#endif /* GL_NV_conservative_raster_pre_snap */
+
+#ifndef GL_NV_conservative_raster_pre_snap_triangles
+#define GL_NV_conservative_raster_pre_snap_triangles 1
+#define GL_CONSERVATIVE_RASTER_MODE_NV    0x954D
+#define GL_CONSERVATIVE_RASTER_MODE_POST_SNAP_NV 0x954E
+#define GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_TRIANGLES_NV 0x954F
+typedef void (APIENTRYP PFNGLCONSERVATIVERASTERPARAMETERINVPROC) (GLenum pname, GLint param);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glConservativeRasterParameteriNV (GLenum pname, GLint param);
+#endif
+#endif /* GL_NV_conservative_raster_pre_snap_triangles */
+
+#ifndef GL_NV_conservative_raster_underestimation
+#define GL_NV_conservative_raster_underestimation 1
+#endif /* GL_NV_conservative_raster_underestimation */
+
+#ifndef GL_NV_copy_depth_to_color
+#define GL_NV_copy_depth_to_color 1
+#define GL_DEPTH_STENCIL_TO_RGBA_NV       0x886E
+#define GL_DEPTH_STENCIL_TO_BGRA_NV       0x886F
+#endif /* GL_NV_copy_depth_to_color */
+
+#ifndef GL_NV_copy_image
+#define GL_NV_copy_image 1
+typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATANVPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCopyImageSubDataNV (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+#endif /* GL_NV_copy_image */
+
+#ifndef GL_NV_deep_texture3D
+#define GL_NV_deep_texture3D 1
+#define GL_MAX_DEEP_3D_TEXTURE_WIDTH_HEIGHT_NV 0x90D0
+#define GL_MAX_DEEP_3D_TEXTURE_DEPTH_NV   0x90D1
+#endif /* GL_NV_deep_texture3D */
+
+#ifndef GL_NV_depth_buffer_float
+#define GL_NV_depth_buffer_float 1
+#define GL_DEPTH_COMPONENT32F_NV          0x8DAB
+#define GL_DEPTH32F_STENCIL8_NV           0x8DAC
+#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV 0x8DAD
+#define GL_DEPTH_BUFFER_FLOAT_MODE_NV     0x8DAF
+typedef void (APIENTRYP PFNGLDEPTHRANGEDNVPROC) (GLdouble zNear, GLdouble zFar);
+typedef void (APIENTRYP PFNGLCLEARDEPTHDNVPROC) (GLdouble depth);
+typedef void (APIENTRYP PFNGLDEPTHBOUNDSDNVPROC) (GLdouble zmin, GLdouble zmax);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDepthRangedNV (GLdouble zNear, GLdouble zFar);
+GLAPI void APIENTRY glClearDepthdNV (GLdouble depth);
+GLAPI void APIENTRY glDepthBoundsdNV (GLdouble zmin, GLdouble zmax);
+#endif
+#endif /* GL_NV_depth_buffer_float */
+
+#ifndef GL_NV_depth_clamp
+#define GL_NV_depth_clamp 1
+#define GL_DEPTH_CLAMP_NV                 0x864F
+#endif /* GL_NV_depth_clamp */
+
+#ifndef GL_NV_draw_texture
+#define GL_NV_draw_texture 1
+typedef void (APIENTRYP PFNGLDRAWTEXTURENVPROC) (GLuint texture, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawTextureNV (GLuint texture, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1);
+#endif
+#endif /* GL_NV_draw_texture */
+
+#ifndef GL_NV_draw_vulkan_image
+#define GL_NV_draw_vulkan_image 1
+typedef void (APIENTRY  *GLVULKANPROCNV)(void);
+typedef void (APIENTRYP PFNGLDRAWVKIMAGENVPROC) (GLuint64 vkImage, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1);
+typedef GLVULKANPROCNV (APIENTRYP PFNGLGETVKPROCADDRNVPROC) (const GLchar *name);
+typedef void (APIENTRYP PFNGLWAITVKSEMAPHORENVPROC) (GLuint64 vkSemaphore);
+typedef void (APIENTRYP PFNGLSIGNALVKSEMAPHORENVPROC) (GLuint64 vkSemaphore);
+typedef void (APIENTRYP PFNGLSIGNALVKFENCENVPROC) (GLuint64 vkFence);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawVkImageNV (GLuint64 vkImage, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1);
+GLAPI GLVULKANPROCNV APIENTRY glGetVkProcAddrNV (const GLchar *name);
+GLAPI void APIENTRY glWaitVkSemaphoreNV (GLuint64 vkSemaphore);
+GLAPI void APIENTRY glSignalVkSemaphoreNV (GLuint64 vkSemaphore);
+GLAPI void APIENTRY glSignalVkFenceNV (GLuint64 vkFence);
+#endif
+#endif /* GL_NV_draw_vulkan_image */
+
+#ifndef GL_NV_evaluators
+#define GL_NV_evaluators 1
+#define GL_EVAL_2D_NV                     0x86C0
+#define GL_EVAL_TRIANGULAR_2D_NV          0x86C1
+#define GL_MAP_TESSELLATION_NV            0x86C2
+#define GL_MAP_ATTRIB_U_ORDER_NV          0x86C3
+#define GL_MAP_ATTRIB_V_ORDER_NV          0x86C4
+#define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5
+#define GL_EVAL_VERTEX_ATTRIB0_NV         0x86C6
+#define GL_EVAL_VERTEX_ATTRIB1_NV         0x86C7
+#define GL_EVAL_VERTEX_ATTRIB2_NV         0x86C8
+#define GL_EVAL_VERTEX_ATTRIB3_NV         0x86C9
+#define GL_EVAL_VERTEX_ATTRIB4_NV         0x86CA
+#define GL_EVAL_VERTEX_ATTRIB5_NV         0x86CB
+#define GL_EVAL_VERTEX_ATTRIB6_NV         0x86CC
+#define GL_EVAL_VERTEX_ATTRIB7_NV         0x86CD
+#define GL_EVAL_VERTEX_ATTRIB8_NV         0x86CE
+#define GL_EVAL_VERTEX_ATTRIB9_NV         0x86CF
+#define GL_EVAL_VERTEX_ATTRIB10_NV        0x86D0
+#define GL_EVAL_VERTEX_ATTRIB11_NV        0x86D1
+#define GL_EVAL_VERTEX_ATTRIB12_NV        0x86D2
+#define GL_EVAL_VERTEX_ATTRIB13_NV        0x86D3
+#define GL_EVAL_VERTEX_ATTRIB14_NV        0x86D4
+#define GL_EVAL_VERTEX_ATTRIB15_NV        0x86D5
+#define GL_MAX_MAP_TESSELLATION_NV        0x86D6
+#define GL_MAX_RATIONAL_EVAL_ORDER_NV     0x86D7
+typedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const void *points);
+typedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, void *points);
+typedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const void *points);
+GLAPI void APIENTRY glMapParameterivNV (GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glMapParameterfvNV (GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glGetMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, void *points);
+GLAPI void APIENTRY glGetMapParameterivNV (GLenum target, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetMapParameterfvNV (GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum target, GLuint index, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetMapAttribParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glEvalMapsNV (GLenum target, GLenum mode);
+#endif
+#endif /* GL_NV_evaluators */
+
+#ifndef GL_NV_explicit_multisample
+#define GL_NV_explicit_multisample 1
+#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_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
+#define GL_MAX_SAMPLE_MASK_WORDS_NV       0x8E59
+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);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetMultisamplefvNV (GLenum pname, GLuint index, GLfloat *val);
+GLAPI void APIENTRY glSampleMaskIndexedNV (GLuint index, GLbitfield mask);
+GLAPI void APIENTRY glTexRenderbufferNV (GLenum target, GLuint renderbuffer);
+#endif
+#endif /* GL_NV_explicit_multisample */
+
+#ifndef GL_NV_fence
+#define GL_NV_fence 1
+#define GL_ALL_COMPLETED_NV               0x84F2
+#define GL_FENCE_STATUS_NV                0x84F3
+#define GL_FENCE_CONDITION_NV             0x84F4
+typedef void (APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);
+typedef void (APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);
+typedef GLboolean (APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence);
+typedef void (APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);
+typedef void (APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDeleteFencesNV (GLsizei n, const GLuint *fences);
+GLAPI void APIENTRY glGenFencesNV (GLsizei n, GLuint *fences);
+GLAPI GLboolean APIENTRY glIsFenceNV (GLuint fence);
+GLAPI GLboolean APIENTRY glTestFenceNV (GLuint fence);
+GLAPI void APIENTRY glGetFenceivNV (GLuint fence, GLenum pname, GLint *params);
+GLAPI void APIENTRY glFinishFenceNV (GLuint fence);
+GLAPI void APIENTRY glSetFenceNV (GLuint fence, GLenum condition);
+#endif
+#endif /* GL_NV_fence */
+
+#ifndef GL_NV_fill_rectangle
+#define GL_NV_fill_rectangle 1
+#define GL_FILL_RECTANGLE_NV              0x933C
+#endif /* GL_NV_fill_rectangle */
+
+#ifndef GL_NV_float_buffer
+#define GL_NV_float_buffer 1
+#define GL_FLOAT_R_NV                     0x8880
+#define GL_FLOAT_RG_NV                    0x8881
+#define GL_FLOAT_RGB_NV                   0x8882
+#define GL_FLOAT_RGBA_NV                  0x8883
+#define GL_FLOAT_R16_NV                   0x8884
+#define GL_FLOAT_R32_NV                   0x8885
+#define GL_FLOAT_RG16_NV                  0x8886
+#define GL_FLOAT_RG32_NV                  0x8887
+#define GL_FLOAT_RGB16_NV                 0x8888
+#define GL_FLOAT_RGB32_NV                 0x8889
+#define GL_FLOAT_RGBA16_NV                0x888A
+#define GL_FLOAT_RGBA32_NV                0x888B
+#define GL_TEXTURE_FLOAT_COMPONENTS_NV    0x888C
+#define GL_FLOAT_CLEAR_COLOR_VALUE_NV     0x888D
+#define GL_FLOAT_RGBA_MODE_NV             0x888E
+#endif /* GL_NV_float_buffer */
+
+#ifndef GL_NV_fog_distance
+#define GL_NV_fog_distance 1
+#define GL_FOG_DISTANCE_MODE_NV           0x855A
+#define GL_EYE_RADIAL_NV                  0x855B
+#define GL_EYE_PLANE_ABSOLUTE_NV          0x855C
+#endif /* GL_NV_fog_distance */
+
+#ifndef GL_NV_fragment_coverage_to_color
+#define GL_NV_fragment_coverage_to_color 1
+#define GL_FRAGMENT_COVERAGE_TO_COLOR_NV  0x92DD
+#define GL_FRAGMENT_COVERAGE_COLOR_NV     0x92DE
+typedef void (APIENTRYP PFNGLFRAGMENTCOVERAGECOLORNVPROC) (GLuint color);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFragmentCoverageColorNV (GLuint color);
+#endif
+#endif /* GL_NV_fragment_coverage_to_color */
+
+#ifndef GL_NV_fragment_program
+#define GL_NV_fragment_program 1
+#define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868
+#define GL_FRAGMENT_PROGRAM_NV            0x8870
+#define GL_MAX_TEXTURE_COORDS_NV          0x8871
+#define GL_MAX_TEXTURE_IMAGE_UNITS_NV     0x8872
+#define GL_FRAGMENT_PROGRAM_BINDING_NV    0x8873
+#define GL_PROGRAM_ERROR_STRING_NV        0x8874
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v);
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v);
+typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramNamedParameter4fNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glProgramNamedParameter4fvNV (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v);
+GLAPI void APIENTRY glProgramNamedParameter4dNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glProgramNamedParameter4dvNV (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v);
+GLAPI void APIENTRY glGetProgramNamedParameterfvNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params);
+GLAPI void APIENTRY glGetProgramNamedParameterdvNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params);
+#endif
+#endif /* GL_NV_fragment_program */
+
+#ifndef GL_NV_fragment_program2
+#define GL_NV_fragment_program2 1
+#define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4
+#define GL_MAX_PROGRAM_CALL_DEPTH_NV      0x88F5
+#define GL_MAX_PROGRAM_IF_DEPTH_NV        0x88F6
+#define GL_MAX_PROGRAM_LOOP_DEPTH_NV      0x88F7
+#define GL_MAX_PROGRAM_LOOP_COUNT_NV      0x88F8
+#endif /* GL_NV_fragment_program2 */
+
+#ifndef GL_NV_fragment_program4
+#define GL_NV_fragment_program4 1
+#endif /* GL_NV_fragment_program4 */
+
+#ifndef GL_NV_fragment_program_option
+#define GL_NV_fragment_program_option 1
+#endif /* GL_NV_fragment_program_option */
+
+#ifndef GL_NV_fragment_shader_barycentric
+#define GL_NV_fragment_shader_barycentric 1
+#endif /* GL_NV_fragment_shader_barycentric */
+
+#ifndef GL_NV_fragment_shader_interlock
+#define GL_NV_fragment_shader_interlock 1
+#endif /* GL_NV_fragment_shader_interlock */
+
+#ifndef GL_NV_framebuffer_mixed_samples
+#define GL_NV_framebuffer_mixed_samples 1
+#define GL_COVERAGE_MODULATION_TABLE_NV   0x9331
+#define GL_COLOR_SAMPLES_NV               0x8E20
+#define GL_DEPTH_SAMPLES_NV               0x932D
+#define GL_STENCIL_SAMPLES_NV             0x932E
+#define GL_MIXED_DEPTH_SAMPLES_SUPPORTED_NV 0x932F
+#define GL_MIXED_STENCIL_SAMPLES_SUPPORTED_NV 0x9330
+#define GL_COVERAGE_MODULATION_NV         0x9332
+#define GL_COVERAGE_MODULATION_TABLE_SIZE_NV 0x9333
+typedef void (APIENTRYP PFNGLCOVERAGEMODULATIONTABLENVPROC) (GLsizei n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLGETCOVERAGEMODULATIONTABLENVPROC) (GLsizei bufsize, GLfloat *v);
+typedef void (APIENTRYP PFNGLCOVERAGEMODULATIONNVPROC) (GLenum components);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCoverageModulationTableNV (GLsizei n, const GLfloat *v);
+GLAPI void APIENTRY glGetCoverageModulationTableNV (GLsizei bufsize, GLfloat *v);
+GLAPI void APIENTRY glCoverageModulationNV (GLenum components);
+#endif
+#endif /* GL_NV_framebuffer_mixed_samples */
+
+#ifndef GL_NV_framebuffer_multisample_coverage
+#define GL_NV_framebuffer_multisample_coverage 1
+#define GL_RENDERBUFFER_COVERAGE_SAMPLES_NV 0x8CAB
+#define GL_RENDERBUFFER_COLOR_SAMPLES_NV  0x8E10
+#define GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV 0x8E11
+#define GL_MULTISAMPLE_COVERAGE_MODES_NV  0x8E12
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glRenderbufferStorageMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+#endif /* GL_NV_framebuffer_multisample_coverage */
+
+#ifndef GL_NV_geometry_program4
+#define GL_NV_geometry_program4 1
+#define GL_GEOMETRY_PROGRAM_NV            0x8C26
+#define GL_MAX_PROGRAM_OUTPUT_VERTICES_NV 0x8C27
+#define GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV 0x8C28
+typedef void (APIENTRYP PFNGLPROGRAMVERTEXLIMITNVPROC) (GLenum target, GLint limit);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramVertexLimitNV (GLenum target, GLint limit);
+GLAPI void APIENTRY glFramebufferTextureEXT (GLenum target, GLenum attachment, GLuint texture, GLint level);
+GLAPI void APIENTRY glFramebufferTextureFaceEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face);
+#endif
+#endif /* GL_NV_geometry_program4 */
+
+#ifndef GL_NV_geometry_shader4
+#define GL_NV_geometry_shader4 1
+#endif /* GL_NV_geometry_shader4 */
+
+#ifndef GL_NV_geometry_shader_passthrough
+#define GL_NV_geometry_shader_passthrough 1
+#endif /* GL_NV_geometry_shader_passthrough */
+
+#ifndef GL_NV_gpu_multicast
+#define GL_NV_gpu_multicast 1
+#define GL_PER_GPU_STORAGE_BIT_NV         0x0800
+#define GL_MULTICAST_GPUS_NV              0x92BA
+#define GL_RENDER_GPU_MASK_NV             0x9558
+#define GL_PER_GPU_STORAGE_NV             0x9548
+#define GL_MULTICAST_PROGRAMMABLE_SAMPLE_LOCATION_NV 0x9549
+typedef void (APIENTRYP PFNGLRENDERGPUMASKNVPROC) (GLbitfield mask);
+typedef void (APIENTRYP PFNGLMULTICASTBUFFERSUBDATANVPROC) (GLbitfield gpuMask, GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);
+typedef void (APIENTRYP PFNGLMULTICASTCOPYBUFFERSUBDATANVPROC) (GLuint readGpu, GLbitfield writeGpuMask, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+typedef void (APIENTRYP PFNGLMULTICASTCOPYIMAGESUBDATANVPROC) (GLuint srcGpu, GLbitfield dstGpuMask, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
+typedef void (APIENTRYP PFNGLMULTICASTBLITFRAMEBUFFERNVPROC) (GLuint srcGpu, GLuint dstGpu, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+typedef void (APIENTRYP PFNGLMULTICASTFRAMEBUFFERSAMPLELOCATIONSFVNVPROC) (GLuint gpu, GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTICASTBARRIERNVPROC) (void);
+typedef void (APIENTRYP PFNGLMULTICASTWAITSYNCNVPROC) (GLuint signalGpu, GLbitfield waitGpuMask);
+typedef void (APIENTRYP PFNGLMULTICASTGETQUERYOBJECTIVNVPROC) (GLuint gpu, GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLMULTICASTGETQUERYOBJECTUIVNVPROC) (GLuint gpu, GLuint id, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLMULTICASTGETQUERYOBJECTI64VNVPROC) (GLuint gpu, GLuint id, GLenum pname, GLint64 *params);
+typedef void (APIENTRYP PFNGLMULTICASTGETQUERYOBJECTUI64VNVPROC) (GLuint gpu, GLuint id, GLenum pname, GLuint64 *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glRenderGpuMaskNV (GLbitfield mask);
+GLAPI void APIENTRY glMulticastBufferSubDataNV (GLbitfield gpuMask, GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);
+GLAPI void APIENTRY glMulticastCopyBufferSubDataNV (GLuint readGpu, GLbitfield writeGpuMask, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+GLAPI void APIENTRY glMulticastCopyImageSubDataNV (GLuint srcGpu, GLbitfield dstGpuMask, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
+GLAPI void APIENTRY glMulticastBlitFramebufferNV (GLuint srcGpu, GLuint dstGpu, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+GLAPI void APIENTRY glMulticastFramebufferSampleLocationsfvNV (GLuint gpu, GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v);
+GLAPI void APIENTRY glMulticastBarrierNV (void);
+GLAPI void APIENTRY glMulticastWaitSyncNV (GLuint signalGpu, GLbitfield waitGpuMask);
+GLAPI void APIENTRY glMulticastGetQueryObjectivNV (GLuint gpu, GLuint id, GLenum pname, GLint *params);
+GLAPI void APIENTRY glMulticastGetQueryObjectuivNV (GLuint gpu, GLuint id, GLenum pname, GLuint *params);
+GLAPI void APIENTRY glMulticastGetQueryObjecti64vNV (GLuint gpu, GLuint id, GLenum pname, GLint64 *params);
+GLAPI void APIENTRY glMulticastGetQueryObjectui64vNV (GLuint gpu, GLuint id, GLenum pname, GLuint64 *params);
+#endif
+#endif /* GL_NV_gpu_multicast */
+
+#ifndef GL_NV_gpu_program4
+#define GL_NV_gpu_program4 1
+#define GL_MIN_PROGRAM_TEXEL_OFFSET_NV    0x8904
+#define GL_MAX_PROGRAM_TEXEL_OFFSET_NV    0x8905
+#define GL_PROGRAM_ATTRIB_COMPONENTS_NV   0x8906
+#define GL_PROGRAM_RESULT_COMPONENTS_NV   0x8907
+#define GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV 0x8908
+#define GL_MAX_PROGRAM_RESULT_COMPONENTS_NV 0x8909
+#define GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV 0x8DA5
+#define GL_MAX_PROGRAM_GENERIC_RESULTS_NV 0x8DA6
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramLocalParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);
+GLAPI void APIENTRY glProgramLocalParameterI4ivNV (GLenum target, GLuint index, const GLint *params);
+GLAPI void APIENTRY glProgramLocalParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params);
+GLAPI void APIENTRY glProgramLocalParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+GLAPI void APIENTRY glProgramLocalParameterI4uivNV (GLenum target, GLuint index, const GLuint *params);
+GLAPI void APIENTRY glProgramLocalParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params);
+GLAPI void APIENTRY glProgramEnvParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);
+GLAPI void APIENTRY glProgramEnvParameterI4ivNV (GLenum target, GLuint index, const GLint *params);
+GLAPI void APIENTRY glProgramEnvParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params);
+GLAPI void APIENTRY glProgramEnvParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+GLAPI void APIENTRY glProgramEnvParameterI4uivNV (GLenum target, GLuint index, const GLuint *params);
+GLAPI void APIENTRY glProgramEnvParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params);
+GLAPI void APIENTRY glGetProgramLocalParameterIivNV (GLenum target, GLuint index, GLint *params);
+GLAPI void APIENTRY glGetProgramLocalParameterIuivNV (GLenum target, GLuint index, GLuint *params);
+GLAPI void APIENTRY glGetProgramEnvParameterIivNV (GLenum target, GLuint index, GLint *params);
+GLAPI void APIENTRY glGetProgramEnvParameterIuivNV (GLenum target, GLuint index, GLuint *params);
+#endif
+#endif /* GL_NV_gpu_program4 */
+
+#ifndef GL_NV_gpu_program5
+#define GL_NV_gpu_program5 1
+#define GL_MAX_GEOMETRY_PROGRAM_INVOCATIONS_NV 0x8E5A
+#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5B
+#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5C
+#define GL_FRAGMENT_PROGRAM_INTERPOLATION_OFFSET_BITS_NV 0x8E5D
+#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5E
+#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5F
+#define GL_MAX_PROGRAM_SUBROUTINE_PARAMETERS_NV 0x8F44
+#define GL_MAX_PROGRAM_SUBROUTINE_NUM_NV  0x8F45
+typedef void (APIENTRYP PFNGLPROGRAMSUBROUTINEPARAMETERSUIVNVPROC) (GLenum target, GLsizei count, const GLuint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMSUBROUTINEPARAMETERUIVNVPROC) (GLenum target, GLuint index, GLuint *param);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramSubroutineParametersuivNV (GLenum target, GLsizei count, const GLuint *params);
+GLAPI void APIENTRY glGetProgramSubroutineParameteruivNV (GLenum target, GLuint index, GLuint *param);
+#endif
+#endif /* GL_NV_gpu_program5 */
+
+#ifndef GL_NV_gpu_program5_mem_extended
+#define GL_NV_gpu_program5_mem_extended 1
+#endif /* GL_NV_gpu_program5_mem_extended */
+
+#ifndef GL_NV_gpu_shader5
+#define GL_NV_gpu_shader5 1
+#endif /* GL_NV_gpu_shader5 */
+
+#ifndef GL_NV_half_float
+#define GL_NV_half_float 1
+typedef unsigned short GLhalfNV;
+#define GL_HALF_FLOAT_NV                  0x140B
+typedef void (APIENTRYP PFNGLVERTEX2HNVPROC) (GLhalfNV x, GLhalfNV y);
+typedef void (APIENTRYP PFNGLVERTEX2HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEX3HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z);
+typedef void (APIENTRYP PFNGLVERTEX3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEX4HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);
+typedef void (APIENTRYP PFNGLVERTEX4HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLNORMAL3HNVPROC) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz);
+typedef void (APIENTRYP PFNGLNORMAL3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
+typedef void (APIENTRYP PFNGLCOLOR3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLCOLOR4HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha);
+typedef void (APIENTRYP PFNGLCOLOR4HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD1HNVPROC) (GLhalfNV s);
+typedef void (APIENTRYP PFNGLTEXCOORD1HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2HNVPROC) (GLhalfNV s, GLhalfNV t);
+typedef void (APIENTRYP PFNGLTEXCOORD2HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD3HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r);
+typedef void (APIENTRYP PFNGLTEXCOORD3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD4HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
+typedef void (APIENTRYP PFNGLTEXCOORD4HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1HNVPROC) (GLenum target, GLhalfNV s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog);
+typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertex2hNV (GLhalfNV x, GLhalfNV y);
+GLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glVertex3hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z);
+GLAPI void APIENTRY glVertex3hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glVertex4hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);
+GLAPI void APIENTRY glVertex4hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glNormal3hNV (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz);
+GLAPI void APIENTRY glNormal3hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
+GLAPI void APIENTRY glColor3hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glColor4hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha);
+GLAPI void APIENTRY glColor4hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glTexCoord1hNV (GLhalfNV s);
+GLAPI void APIENTRY glTexCoord1hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glTexCoord2hNV (GLhalfNV s, GLhalfNV t);
+GLAPI void APIENTRY glTexCoord2hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glTexCoord3hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r);
+GLAPI void APIENTRY glTexCoord3hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glTexCoord4hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
+GLAPI void APIENTRY glTexCoord4hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glMultiTexCoord1hNV (GLenum target, GLhalfNV s);
+GLAPI void APIENTRY glMultiTexCoord1hvNV (GLenum target, const GLhalfNV *v);
+GLAPI void APIENTRY glMultiTexCoord2hNV (GLenum target, GLhalfNV s, GLhalfNV t);
+GLAPI void APIENTRY glMultiTexCoord2hvNV (GLenum target, const GLhalfNV *v);
+GLAPI void APIENTRY glMultiTexCoord3hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r);
+GLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum target, const GLhalfNV *v);
+GLAPI void APIENTRY glMultiTexCoord4hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
+GLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum target, const GLhalfNV *v);
+GLAPI void APIENTRY glFogCoordhNV (GLhalfNV fog);
+GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *fog);
+GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
+GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *v);
+GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV weight);
+GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *weight);
+GLAPI void APIENTRY glVertexAttrib1hNV (GLuint index, GLhalfNV x);
+GLAPI void APIENTRY glVertexAttrib1hvNV (GLuint index, const GLhalfNV *v);
+GLAPI void APIENTRY glVertexAttrib2hNV (GLuint index, GLhalfNV x, GLhalfNV y);
+GLAPI void APIENTRY glVertexAttrib2hvNV (GLuint index, const GLhalfNV *v);
+GLAPI void APIENTRY glVertexAttrib3hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z);
+GLAPI void APIENTRY glVertexAttrib3hvNV (GLuint index, const GLhalfNV *v);
+GLAPI void APIENTRY glVertexAttrib4hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);
+GLAPI void APIENTRY glVertexAttrib4hvNV (GLuint index, const GLhalfNV *v);
+GLAPI void APIENTRY glVertexAttribs1hvNV (GLuint index, GLsizei n, const GLhalfNV *v);
+GLAPI void APIENTRY glVertexAttribs2hvNV (GLuint index, GLsizei n, const GLhalfNV *v);
+GLAPI void APIENTRY glVertexAttribs3hvNV (GLuint index, GLsizei n, const GLhalfNV *v);
+GLAPI void APIENTRY glVertexAttribs4hvNV (GLuint index, GLsizei n, const GLhalfNV *v);
+#endif
+#endif /* GL_NV_half_float */
+
+#ifndef GL_NV_internalformat_sample_query
+#define GL_NV_internalformat_sample_query 1
+#define GL_MULTISAMPLES_NV                0x9371
+#define GL_SUPERSAMPLE_SCALE_X_NV         0x9372
+#define GL_SUPERSAMPLE_SCALE_Y_NV         0x9373
+#define GL_CONFORMANT_NV                  0x9374
+typedef void (APIENTRYP PFNGLGETINTERNALFORMATSAMPLEIVNVPROC) (GLenum target, GLenum internalformat, GLsizei samples, GLenum pname, GLsizei bufSize, GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetInternalformatSampleivNV (GLenum target, GLenum internalformat, GLsizei samples, GLenum pname, GLsizei bufSize, GLint *params);
+#endif
+#endif /* GL_NV_internalformat_sample_query */
+
+#ifndef GL_NV_light_max_exponent
+#define GL_NV_light_max_exponent 1
+#define GL_MAX_SHININESS_NV               0x8504
+#define GL_MAX_SPOT_EXPONENT_NV           0x8505
+#endif /* GL_NV_light_max_exponent */
+
+#ifndef GL_NV_memory_attachment
+#define GL_NV_memory_attachment 1
+#define GL_ATTACHED_MEMORY_OBJECT_NV      0x95A4
+#define GL_ATTACHED_MEMORY_OFFSET_NV      0x95A5
+#define GL_MEMORY_ATTACHABLE_ALIGNMENT_NV 0x95A6
+#define GL_MEMORY_ATTACHABLE_SIZE_NV      0x95A7
+#define GL_MEMORY_ATTACHABLE_NV           0x95A8
+#define GL_DETACHED_MEMORY_INCARNATION_NV 0x95A9
+#define GL_DETACHED_TEXTURES_NV           0x95AA
+#define GL_DETACHED_BUFFERS_NV            0x95AB
+#define GL_MAX_DETACHED_TEXTURES_NV       0x95AC
+#define GL_MAX_DETACHED_BUFFERS_NV        0x95AD
+typedef void (APIENTRYP PFNGLGETMEMORYOBJECTDETACHEDRESOURCESUIVNVPROC) (GLuint memory, GLenum pname, GLint first, GLsizei count, GLuint *params);
+typedef void (APIENTRYP PFNGLRESETMEMORYOBJECTPARAMETERNVPROC) (GLuint memory, GLenum pname);
+typedef void (APIENTRYP PFNGLTEXATTACHMEMORYNVPROC) (GLenum target, GLuint memory, GLuint64 offset);
+typedef void (APIENTRYP PFNGLBUFFERATTACHMEMORYNVPROC) (GLenum target, GLuint memory, GLuint64 offset);
+typedef void (APIENTRYP PFNGLTEXTUREATTACHMEMORYNVPROC) (GLuint texture, GLuint memory, GLuint64 offset);
+typedef void (APIENTRYP PFNGLNAMEDBUFFERATTACHMEMORYNVPROC) (GLuint buffer, GLuint memory, GLuint64 offset);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetMemoryObjectDetachedResourcesuivNV (GLuint memory, GLenum pname, GLint first, GLsizei count, GLuint *params);
+GLAPI void APIENTRY glResetMemoryObjectParameterNV (GLuint memory, GLenum pname);
+GLAPI void APIENTRY glTexAttachMemoryNV (GLenum target, GLuint memory, GLuint64 offset);
+GLAPI void APIENTRY glBufferAttachMemoryNV (GLenum target, GLuint memory, GLuint64 offset);
+GLAPI void APIENTRY glTextureAttachMemoryNV (GLuint texture, GLuint memory, GLuint64 offset);
+GLAPI void APIENTRY glNamedBufferAttachMemoryNV (GLuint buffer, GLuint memory, GLuint64 offset);
+#endif
+#endif /* GL_NV_memory_attachment */
+
+#ifndef GL_NV_mesh_shader
+#define GL_NV_mesh_shader 1
+#define GL_MESH_SHADER_NV                 0x9559
+#define GL_TASK_SHADER_NV                 0x955A
+#define GL_MAX_MESH_UNIFORM_BLOCKS_NV     0x8E60
+#define GL_MAX_MESH_TEXTURE_IMAGE_UNITS_NV 0x8E61
+#define GL_MAX_MESH_IMAGE_UNIFORMS_NV     0x8E62
+#define GL_MAX_MESH_UNIFORM_COMPONENTS_NV 0x8E63
+#define GL_MAX_MESH_ATOMIC_COUNTER_BUFFERS_NV 0x8E64
+#define GL_MAX_MESH_ATOMIC_COUNTERS_NV    0x8E65
+#define GL_MAX_MESH_SHADER_STORAGE_BLOCKS_NV 0x8E66
+#define GL_MAX_COMBINED_MESH_UNIFORM_COMPONENTS_NV 0x8E67
+#define GL_MAX_TASK_UNIFORM_BLOCKS_NV     0x8E68
+#define GL_MAX_TASK_TEXTURE_IMAGE_UNITS_NV 0x8E69
+#define GL_MAX_TASK_IMAGE_UNIFORMS_NV     0x8E6A
+#define GL_MAX_TASK_UNIFORM_COMPONENTS_NV 0x8E6B
+#define GL_MAX_TASK_ATOMIC_COUNTER_BUFFERS_NV 0x8E6C
+#define GL_MAX_TASK_ATOMIC_COUNTERS_NV    0x8E6D
+#define GL_MAX_TASK_SHADER_STORAGE_BLOCKS_NV 0x8E6E
+#define GL_MAX_COMBINED_TASK_UNIFORM_COMPONENTS_NV 0x8E6F
+#define GL_MAX_MESH_WORK_GROUP_INVOCATIONS_NV 0x95A2
+#define GL_MAX_TASK_WORK_GROUP_INVOCATIONS_NV 0x95A3
+#define GL_MAX_MESH_TOTAL_MEMORY_SIZE_NV  0x9536
+#define GL_MAX_TASK_TOTAL_MEMORY_SIZE_NV  0x9537
+#define GL_MAX_MESH_OUTPUT_VERTICES_NV    0x9538
+#define GL_MAX_MESH_OUTPUT_PRIMITIVES_NV  0x9539
+#define GL_MAX_TASK_OUTPUT_COUNT_NV       0x953A
+#define GL_MAX_DRAW_MESH_TASKS_COUNT_NV   0x953D
+#define GL_MAX_MESH_VIEWS_NV              0x9557
+#define GL_MESH_OUTPUT_PER_VERTEX_GRANULARITY_NV 0x92DF
+#define GL_MESH_OUTPUT_PER_PRIMITIVE_GRANULARITY_NV 0x9543
+#define GL_MAX_MESH_WORK_GROUP_SIZE_NV    0x953B
+#define GL_MAX_TASK_WORK_GROUP_SIZE_NV    0x953C
+#define GL_MESH_WORK_GROUP_SIZE_NV        0x953E
+#define GL_TASK_WORK_GROUP_SIZE_NV        0x953F
+#define GL_MESH_VERTICES_OUT_NV           0x9579
+#define GL_MESH_PRIMITIVES_OUT_NV         0x957A
+#define GL_MESH_OUTPUT_TYPE_NV            0x957B
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_MESH_SHADER_NV 0x959C
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_TASK_SHADER_NV 0x959D
+#define GL_REFERENCED_BY_MESH_SHADER_NV   0x95A0
+#define GL_REFERENCED_BY_TASK_SHADER_NV   0x95A1
+#define GL_MESH_SHADER_BIT_NV             0x00000040
+#define GL_TASK_SHADER_BIT_NV             0x00000080
+#define GL_MESH_SUBROUTINE_NV             0x957C
+#define GL_TASK_SUBROUTINE_NV             0x957D
+#define GL_MESH_SUBROUTINE_UNIFORM_NV     0x957E
+#define GL_TASK_SUBROUTINE_UNIFORM_NV     0x957F
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_MESH_SHADER_NV 0x959E
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TASK_SHADER_NV 0x959F
+typedef void (APIENTRYP PFNGLDRAWMESHTASKSNVPROC) (GLuint first, GLuint count);
+typedef void (APIENTRYP PFNGLDRAWMESHTASKSINDIRECTNVPROC) (GLintptr indirect);
+typedef void (APIENTRYP PFNGLMULTIDRAWMESHTASKSINDIRECTNVPROC) (GLintptr indirect, GLsizei drawcount, GLsizei stride);
+typedef void (APIENTRYP PFNGLMULTIDRAWMESHTASKSINDIRECTCOUNTNVPROC) (GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawMeshTasksNV (GLuint first, GLuint count);
+GLAPI void APIENTRY glDrawMeshTasksIndirectNV (GLintptr indirect);
+GLAPI void APIENTRY glMultiDrawMeshTasksIndirectNV (GLintptr indirect, GLsizei drawcount, GLsizei stride);
+GLAPI void APIENTRY glMultiDrawMeshTasksIndirectCountNV (GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
+#endif
+#endif /* GL_NV_mesh_shader */
+
+#ifndef GL_NV_multisample_coverage
+#define GL_NV_multisample_coverage 1
+#endif /* GL_NV_multisample_coverage */
+
+#ifndef GL_NV_multisample_filter_hint
+#define GL_NV_multisample_filter_hint 1
+#define GL_MULTISAMPLE_FILTER_HINT_NV     0x8534
+#endif /* GL_NV_multisample_filter_hint */
+
+#ifndef GL_NV_occlusion_query
+#define GL_NV_occlusion_query 1
+#define GL_PIXEL_COUNTER_BITS_NV          0x8864
+#define GL_CURRENT_OCCLUSION_QUERY_ID_NV  0x8865
+#define GL_PIXEL_COUNT_NV                 0x8866
+#define GL_PIXEL_COUNT_AVAILABLE_NV       0x8867
+typedef void (APIENTRYP PFNGLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISOCCLUSIONQUERYNVPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINOCCLUSIONQUERYNVPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLENDOCCLUSIONQUERYNVPROC) (void);
+typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenOcclusionQueriesNV (GLsizei n, GLuint *ids);
+GLAPI void APIENTRY glDeleteOcclusionQueriesNV (GLsizei n, const GLuint *ids);
+GLAPI GLboolean APIENTRY glIsOcclusionQueryNV (GLuint id);
+GLAPI void APIENTRY glBeginOcclusionQueryNV (GLuint id);
+GLAPI void APIENTRY glEndOcclusionQueryNV (void);
+GLAPI void APIENTRY glGetOcclusionQueryivNV (GLuint id, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetOcclusionQueryuivNV (GLuint id, GLenum pname, GLuint *params);
+#endif
+#endif /* GL_NV_occlusion_query */
+
+#ifndef GL_NV_packed_depth_stencil
+#define GL_NV_packed_depth_stencil 1
+#define GL_DEPTH_STENCIL_NV               0x84F9
+#define GL_UNSIGNED_INT_24_8_NV           0x84FA
+#endif /* GL_NV_packed_depth_stencil */
+
+#ifndef GL_NV_parameter_buffer_object
+#define GL_NV_parameter_buffer_object 1
+#define GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV 0x8DA0
+#define GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV 0x8DA1
+#define GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV 0x8DA2
+#define GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV 0x8DA3
+#define GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV 0x8DA4
+typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLfloat *params);
+typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIIVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLint *params);
+typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIUIVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLuint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramBufferParametersfvNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLfloat *params);
+GLAPI void APIENTRY glProgramBufferParametersIivNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLint *params);
+GLAPI void APIENTRY glProgramBufferParametersIuivNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLuint *params);
+#endif
+#endif /* GL_NV_parameter_buffer_object */
+
+#ifndef GL_NV_parameter_buffer_object2
+#define GL_NV_parameter_buffer_object2 1
+#endif /* GL_NV_parameter_buffer_object2 */
+
+#ifndef GL_NV_path_rendering
+#define GL_NV_path_rendering 1
+#define GL_PATH_FORMAT_SVG_NV             0x9070
+#define GL_PATH_FORMAT_PS_NV              0x9071
+#define GL_STANDARD_FONT_NAME_NV          0x9072
+#define GL_SYSTEM_FONT_NAME_NV            0x9073
+#define GL_FILE_NAME_NV                   0x9074
+#define GL_PATH_STROKE_WIDTH_NV           0x9075
+#define GL_PATH_END_CAPS_NV               0x9076
+#define GL_PATH_INITIAL_END_CAP_NV        0x9077
+#define GL_PATH_TERMINAL_END_CAP_NV       0x9078
+#define GL_PATH_JOIN_STYLE_NV             0x9079
+#define GL_PATH_MITER_LIMIT_NV            0x907A
+#define GL_PATH_DASH_CAPS_NV              0x907B
+#define GL_PATH_INITIAL_DASH_CAP_NV       0x907C
+#define GL_PATH_TERMINAL_DASH_CAP_NV      0x907D
+#define GL_PATH_DASH_OFFSET_NV            0x907E
+#define GL_PATH_CLIENT_LENGTH_NV          0x907F
+#define GL_PATH_FILL_MODE_NV              0x9080
+#define GL_PATH_FILL_MASK_NV              0x9081
+#define GL_PATH_FILL_COVER_MODE_NV        0x9082
+#define GL_PATH_STROKE_COVER_MODE_NV      0x9083
+#define GL_PATH_STROKE_MASK_NV            0x9084
+#define GL_COUNT_UP_NV                    0x9088
+#define GL_COUNT_DOWN_NV                  0x9089
+#define GL_PATH_OBJECT_BOUNDING_BOX_NV    0x908A
+#define GL_CONVEX_HULL_NV                 0x908B
+#define GL_BOUNDING_BOX_NV                0x908D
+#define GL_TRANSLATE_X_NV                 0x908E
+#define GL_TRANSLATE_Y_NV                 0x908F
+#define GL_TRANSLATE_2D_NV                0x9090
+#define GL_TRANSLATE_3D_NV                0x9091
+#define GL_AFFINE_2D_NV                   0x9092
+#define GL_AFFINE_3D_NV                   0x9094
+#define GL_TRANSPOSE_AFFINE_2D_NV         0x9096
+#define GL_TRANSPOSE_AFFINE_3D_NV         0x9098
+#define GL_UTF8_NV                        0x909A
+#define GL_UTF16_NV                       0x909B
+#define GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV 0x909C
+#define GL_PATH_COMMAND_COUNT_NV          0x909D
+#define GL_PATH_COORD_COUNT_NV            0x909E
+#define GL_PATH_DASH_ARRAY_COUNT_NV       0x909F
+#define GL_PATH_COMPUTED_LENGTH_NV        0x90A0
+#define GL_PATH_FILL_BOUNDING_BOX_NV      0x90A1
+#define GL_PATH_STROKE_BOUNDING_BOX_NV    0x90A2
+#define GL_SQUARE_NV                      0x90A3
+#define GL_ROUND_NV                       0x90A4
+#define GL_TRIANGULAR_NV                  0x90A5
+#define GL_BEVEL_NV                       0x90A6
+#define GL_MITER_REVERT_NV                0x90A7
+#define GL_MITER_TRUNCATE_NV              0x90A8
+#define GL_SKIP_MISSING_GLYPH_NV          0x90A9
+#define GL_USE_MISSING_GLYPH_NV           0x90AA
+#define GL_PATH_ERROR_POSITION_NV         0x90AB
+#define GL_ACCUM_ADJACENT_PAIRS_NV        0x90AD
+#define GL_ADJACENT_PAIRS_NV              0x90AE
+#define GL_FIRST_TO_REST_NV               0x90AF
+#define GL_PATH_GEN_MODE_NV               0x90B0
+#define GL_PATH_GEN_COEFF_NV              0x90B1
+#define GL_PATH_GEN_COMPONENTS_NV         0x90B3
+#define GL_PATH_STENCIL_FUNC_NV           0x90B7
+#define GL_PATH_STENCIL_REF_NV            0x90B8
+#define GL_PATH_STENCIL_VALUE_MASK_NV     0x90B9
+#define GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV 0x90BD
+#define GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV 0x90BE
+#define GL_PATH_COVER_DEPTH_FUNC_NV       0x90BF
+#define GL_PATH_DASH_OFFSET_RESET_NV      0x90B4
+#define GL_MOVE_TO_RESETS_NV              0x90B5
+#define GL_MOVE_TO_CONTINUES_NV           0x90B6
+#define GL_CLOSE_PATH_NV                  0x00
+#define GL_MOVE_TO_NV                     0x02
+#define GL_RELATIVE_MOVE_TO_NV            0x03
+#define GL_LINE_TO_NV                     0x04
+#define GL_RELATIVE_LINE_TO_NV            0x05
+#define GL_HORIZONTAL_LINE_TO_NV          0x06
+#define GL_RELATIVE_HORIZONTAL_LINE_TO_NV 0x07
+#define GL_VERTICAL_LINE_TO_NV            0x08
+#define GL_RELATIVE_VERTICAL_LINE_TO_NV   0x09
+#define GL_QUADRATIC_CURVE_TO_NV          0x0A
+#define GL_RELATIVE_QUADRATIC_CURVE_TO_NV 0x0B
+#define GL_CUBIC_CURVE_TO_NV              0x0C
+#define GL_RELATIVE_CUBIC_CURVE_TO_NV     0x0D
+#define GL_SMOOTH_QUADRATIC_CURVE_TO_NV   0x0E
+#define GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0F
+#define GL_SMOOTH_CUBIC_CURVE_TO_NV       0x10
+#define GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV 0x11
+#define GL_SMALL_CCW_ARC_TO_NV            0x12
+#define GL_RELATIVE_SMALL_CCW_ARC_TO_NV   0x13
+#define GL_SMALL_CW_ARC_TO_NV             0x14
+#define GL_RELATIVE_SMALL_CW_ARC_TO_NV    0x15
+#define GL_LARGE_CCW_ARC_TO_NV            0x16
+#define GL_RELATIVE_LARGE_CCW_ARC_TO_NV   0x17
+#define GL_LARGE_CW_ARC_TO_NV             0x18
+#define GL_RELATIVE_LARGE_CW_ARC_TO_NV    0x19
+#define GL_RESTART_PATH_NV                0xF0
+#define GL_DUP_FIRST_CUBIC_CURVE_TO_NV    0xF2
+#define GL_DUP_LAST_CUBIC_CURVE_TO_NV     0xF4
+#define GL_RECT_NV                        0xF6
+#define GL_CIRCULAR_CCW_ARC_TO_NV         0xF8
+#define GL_CIRCULAR_CW_ARC_TO_NV          0xFA
+#define GL_CIRCULAR_TANGENT_ARC_TO_NV     0xFC
+#define GL_ARC_TO_NV                      0xFE
+#define GL_RELATIVE_ARC_TO_NV             0xFF
+#define GL_BOLD_BIT_NV                    0x01
+#define GL_ITALIC_BIT_NV                  0x02
+#define GL_GLYPH_WIDTH_BIT_NV             0x01
+#define GL_GLYPH_HEIGHT_BIT_NV            0x02
+#define GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV 0x04
+#define GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV 0x08
+#define GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV 0x10
+#define GL_GLYPH_VERTICAL_BEARING_X_BIT_NV 0x20
+#define GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV 0x40
+#define GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV 0x80
+#define GL_GLYPH_HAS_KERNING_BIT_NV       0x100
+#define GL_FONT_X_MIN_BOUNDS_BIT_NV       0x00010000
+#define GL_FONT_Y_MIN_BOUNDS_BIT_NV       0x00020000
+#define GL_FONT_X_MAX_BOUNDS_BIT_NV       0x00040000
+#define GL_FONT_Y_MAX_BOUNDS_BIT_NV       0x00080000
+#define GL_FONT_UNITS_PER_EM_BIT_NV       0x00100000
+#define GL_FONT_ASCENDER_BIT_NV           0x00200000
+#define GL_FONT_DESCENDER_BIT_NV          0x00400000
+#define GL_FONT_HEIGHT_BIT_NV             0x00800000
+#define GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV  0x01000000
+#define GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV 0x02000000
+#define GL_FONT_UNDERLINE_POSITION_BIT_NV 0x04000000
+#define GL_FONT_UNDERLINE_THICKNESS_BIT_NV 0x08000000
+#define GL_FONT_HAS_KERNING_BIT_NV        0x10000000
+#define GL_ROUNDED_RECT_NV                0xE8
+#define GL_RELATIVE_ROUNDED_RECT_NV       0xE9
+#define GL_ROUNDED_RECT2_NV               0xEA
+#define GL_RELATIVE_ROUNDED_RECT2_NV      0xEB
+#define GL_ROUNDED_RECT4_NV               0xEC
+#define GL_RELATIVE_ROUNDED_RECT4_NV      0xED
+#define GL_ROUNDED_RECT8_NV               0xEE
+#define GL_RELATIVE_ROUNDED_RECT8_NV      0xEF
+#define GL_RELATIVE_RECT_NV               0xF7
+#define GL_FONT_GLYPHS_AVAILABLE_NV       0x9368
+#define GL_FONT_TARGET_UNAVAILABLE_NV     0x9369
+#define GL_FONT_UNAVAILABLE_NV            0x936A
+#define GL_FONT_UNINTELLIGIBLE_NV         0x936B
+#define GL_CONIC_CURVE_TO_NV              0x1A
+#define GL_RELATIVE_CONIC_CURVE_TO_NV     0x1B
+#define GL_FONT_NUM_GLYPH_INDICES_BIT_NV  0x20000000
+#define GL_STANDARD_FONT_FORMAT_NV        0x936C
+#define GL_2_BYTES_NV                     0x1407
+#define GL_3_BYTES_NV                     0x1408
+#define GL_4_BYTES_NV                     0x1409
+#define GL_EYE_LINEAR_NV                  0x2400
+#define GL_OBJECT_LINEAR_NV               0x2401
+#define GL_CONSTANT_NV                    0x8576
+#define GL_PATH_FOG_GEN_MODE_NV           0x90AC
+#define GL_PRIMARY_COLOR_NV               0x852C
+#define GL_SECONDARY_COLOR_NV             0x852D
+#define GL_PATH_GEN_COLOR_FORMAT_NV       0x90B2
+#define GL_PATH_PROJECTION_NV             0x1701
+#define GL_PATH_MODELVIEW_NV              0x1700
+#define GL_PATH_MODELVIEW_STACK_DEPTH_NV  0x0BA3
+#define GL_PATH_MODELVIEW_MATRIX_NV       0x0BA6
+#define GL_PATH_MAX_MODELVIEW_STACK_DEPTH_NV 0x0D36
+#define GL_PATH_TRANSPOSE_MODELVIEW_MATRIX_NV 0x84E3
+#define GL_PATH_PROJECTION_STACK_DEPTH_NV 0x0BA4
+#define GL_PATH_PROJECTION_MATRIX_NV      0x0BA7
+#define GL_PATH_MAX_PROJECTION_STACK_DEPTH_NV 0x0D38
+#define GL_PATH_TRANSPOSE_PROJECTION_MATRIX_NV 0x84E4
+#define GL_FRAGMENT_INPUT_NV              0x936D
+typedef GLuint (APIENTRYP PFNGLGENPATHSNVPROC) (GLsizei range);
+typedef void (APIENTRYP PFNGLDELETEPATHSNVPROC) (GLuint path, GLsizei range);
+typedef GLboolean (APIENTRYP PFNGLISPATHNVPROC) (GLuint path);
+typedef void (APIENTRYP PFNGLPATHCOMMANDSNVPROC) (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords);
+typedef void (APIENTRYP PFNGLPATHCOORDSNVPROC) (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords);
+typedef void (APIENTRYP PFNGLPATHSUBCOMMANDSNVPROC) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords);
+typedef void (APIENTRYP PFNGLPATHSUBCOORDSNVPROC) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords);
+typedef void (APIENTRYP PFNGLPATHSTRINGNVPROC) (GLuint path, GLenum format, GLsizei length, const void *pathString);
+typedef void (APIENTRYP PFNGLPATHGLYPHSNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+typedef void (APIENTRYP PFNGLPATHGLYPHRANGENVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+typedef void (APIENTRYP PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights);
+typedef void (APIENTRYP PFNGLCOPYPATHNVPROC) (GLuint resultPath, GLuint srcPath);
+typedef void (APIENTRYP PFNGLINTERPOLATEPATHSNVPROC) (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight);
+typedef void (APIENTRYP PFNGLTRANSFORMPATHNVPROC) (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues);
+typedef void (APIENTRYP PFNGLPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, const GLint *value);
+typedef void (APIENTRYP PFNGLPATHPARAMETERINVPROC) (GLuint path, GLenum pname, GLint value);
+typedef void (APIENTRYP PFNGLPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, const GLfloat *value);
+typedef void (APIENTRYP PFNGLPATHPARAMETERFNVPROC) (GLuint path, GLenum pname, GLfloat value);
+typedef void (APIENTRYP PFNGLPATHDASHARRAYNVPROC) (GLuint path, GLsizei dashCount, const GLfloat *dashArray);
+typedef void (APIENTRYP PFNGLPATHSTENCILFUNCNVPROC) (GLenum func, GLint ref, GLuint mask);
+typedef void (APIENTRYP PFNGLPATHSTENCILDEPTHOFFSETNVPROC) (GLfloat factor, GLfloat units);
+typedef void (APIENTRYP PFNGLSTENCILFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask);
+typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask);
+typedef void (APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues);
+typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues);
+typedef void (APIENTRYP PFNGLPATHCOVERDEPTHFUNCNVPROC) (GLenum func);
+typedef void (APIENTRYP PFNGLCOVERFILLPATHNVPROC) (GLuint path, GLenum coverMode);
+typedef void (APIENTRYP PFNGLCOVERSTROKEPATHNVPROC) (GLuint path, GLenum coverMode);
+typedef void (APIENTRYP PFNGLCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+typedef void (APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+typedef void (APIENTRYP PFNGLGETPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, GLint *value);
+typedef void (APIENTRYP PFNGLGETPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, GLfloat *value);
+typedef void (APIENTRYP PFNGLGETPATHCOMMANDSNVPROC) (GLuint path, GLubyte *commands);
+typedef void (APIENTRYP PFNGLGETPATHCOORDSNVPROC) (GLuint path, GLfloat *coords);
+typedef void (APIENTRYP PFNGLGETPATHDASHARRAYNVPROC) (GLuint path, GLfloat *dashArray);
+typedef void (APIENTRYP PFNGLGETPATHMETRICSNVPROC) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics);
+typedef void (APIENTRYP PFNGLGETPATHMETRICRANGENVPROC) (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics);
+typedef void (APIENTRYP PFNGLGETPATHSPACINGNVPROC) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing);
+typedef GLboolean (APIENTRYP PFNGLISPOINTINFILLPATHNVPROC) (GLuint path, GLuint mask, GLfloat x, GLfloat y);
+typedef GLboolean (APIENTRYP PFNGLISPOINTINSTROKEPATHNVPROC) (GLuint path, GLfloat x, GLfloat y);
+typedef GLfloat (APIENTRYP PFNGLGETPATHLENGTHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments);
+typedef GLboolean (APIENTRYP PFNGLPOINTALONGPATHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY);
+typedef void (APIENTRYP PFNGLMATRIXLOAD3X2FNVPROC) (GLenum matrixMode, const GLfloat *m);
+typedef void (APIENTRYP PFNGLMATRIXLOAD3X3FNVPROC) (GLenum matrixMode, const GLfloat *m);
+typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m);
+typedef void (APIENTRYP PFNGLMATRIXMULT3X2FNVPROC) (GLenum matrixMode, const GLfloat *m);
+typedef void (APIENTRYP PFNGLMATRIXMULT3X3FNVPROC) (GLenum matrixMode, const GLfloat *m);
+typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m);
+typedef void (APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode);
+typedef void (APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask, GLenum coverMode);
+typedef void (APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+typedef void (APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+typedef GLenum (APIENTRYP PFNGLPATHGLYPHINDEXRANGENVPROC) (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]);
+typedef GLenum (APIENTRYP PFNGLPATHGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+typedef GLenum (APIENTRYP PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+typedef void (APIENTRYP PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC) (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs);
+typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEFVNVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLfloat *params);
+typedef void (APIENTRYP PFNGLPATHCOLORGENNVPROC) (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs);
+typedef void (APIENTRYP PFNGLPATHTEXGENNVPROC) (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs);
+typedef void (APIENTRYP PFNGLPATHFOGGENNVPROC) (GLenum genMode);
+typedef void (APIENTRYP PFNGLGETPATHCOLORGENIVNVPROC) (GLenum color, GLenum pname, GLint *value);
+typedef void (APIENTRYP PFNGLGETPATHCOLORGENFVNVPROC) (GLenum color, GLenum pname, GLfloat *value);
+typedef void (APIENTRYP PFNGLGETPATHTEXGENIVNVPROC) (GLenum texCoordSet, GLenum pname, GLint *value);
+typedef void (APIENTRYP PFNGLGETPATHTEXGENFVNVPROC) (GLenum texCoordSet, GLenum pname, GLfloat *value);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLuint APIENTRY glGenPathsNV (GLsizei range);
+GLAPI void APIENTRY glDeletePathsNV (GLuint path, GLsizei range);
+GLAPI GLboolean APIENTRY glIsPathNV (GLuint path);
+GLAPI void APIENTRY glPathCommandsNV (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords);
+GLAPI void APIENTRY glPathCoordsNV (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords);
+GLAPI void APIENTRY glPathSubCommandsNV (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords);
+GLAPI void APIENTRY glPathSubCoordsNV (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords);
+GLAPI void APIENTRY glPathStringNV (GLuint path, GLenum format, GLsizei length, const void *pathString);
+GLAPI void APIENTRY glPathGlyphsNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+GLAPI void APIENTRY glPathGlyphRangeNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+GLAPI void APIENTRY glWeightPathsNV (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights);
+GLAPI void APIENTRY glCopyPathNV (GLuint resultPath, GLuint srcPath);
+GLAPI void APIENTRY glInterpolatePathsNV (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight);
+GLAPI void APIENTRY glTransformPathNV (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues);
+GLAPI void APIENTRY glPathParameterivNV (GLuint path, GLenum pname, const GLint *value);
+GLAPI void APIENTRY glPathParameteriNV (GLuint path, GLenum pname, GLint value);
+GLAPI void APIENTRY glPathParameterfvNV (GLuint path, GLenum pname, const GLfloat *value);
+GLAPI void APIENTRY glPathParameterfNV (GLuint path, GLenum pname, GLfloat value);
+GLAPI void APIENTRY glPathDashArrayNV (GLuint path, GLsizei dashCount, const GLfloat *dashArray);
+GLAPI void APIENTRY glPathStencilFuncNV (GLenum func, GLint ref, GLuint mask);
+GLAPI void APIENTRY glPathStencilDepthOffsetNV (GLfloat factor, GLfloat units);
+GLAPI void APIENTRY glStencilFillPathNV (GLuint path, GLenum fillMode, GLuint mask);
+GLAPI void APIENTRY glStencilStrokePathNV (GLuint path, GLint reference, GLuint mask);
+GLAPI void APIENTRY glStencilFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues);
+GLAPI void APIENTRY glStencilStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues);
+GLAPI void APIENTRY glPathCoverDepthFuncNV (GLenum func);
+GLAPI void APIENTRY glCoverFillPathNV (GLuint path, GLenum coverMode);
+GLAPI void APIENTRY glCoverStrokePathNV (GLuint path, GLenum coverMode);
+GLAPI void APIENTRY glCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+GLAPI void APIENTRY glCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+GLAPI void APIENTRY glGetPathParameterivNV (GLuint path, GLenum pname, GLint *value);
+GLAPI void APIENTRY glGetPathParameterfvNV (GLuint path, GLenum pname, GLfloat *value);
+GLAPI void APIENTRY glGetPathCommandsNV (GLuint path, GLubyte *commands);
+GLAPI void APIENTRY glGetPathCoordsNV (GLuint path, GLfloat *coords);
+GLAPI void APIENTRY glGetPathDashArrayNV (GLuint path, GLfloat *dashArray);
+GLAPI void APIENTRY glGetPathMetricsNV (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics);
+GLAPI void APIENTRY glGetPathMetricRangeNV (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics);
+GLAPI void APIENTRY glGetPathSpacingNV (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing);
+GLAPI GLboolean APIENTRY glIsPointInFillPathNV (GLuint path, GLuint mask, GLfloat x, GLfloat y);
+GLAPI GLboolean APIENTRY glIsPointInStrokePathNV (GLuint path, GLfloat x, GLfloat y);
+GLAPI GLfloat APIENTRY glGetPathLengthNV (GLuint path, GLsizei startSegment, GLsizei numSegments);
+GLAPI GLboolean APIENTRY glPointAlongPathNV (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY);
+GLAPI void APIENTRY glMatrixLoad3x2fNV (GLenum matrixMode, const GLfloat *m);
+GLAPI void APIENTRY glMatrixLoad3x3fNV (GLenum matrixMode, const GLfloat *m);
+GLAPI void APIENTRY glMatrixLoadTranspose3x3fNV (GLenum matrixMode, const GLfloat *m);
+GLAPI void APIENTRY glMatrixMult3x2fNV (GLenum matrixMode, const GLfloat *m);
+GLAPI void APIENTRY glMatrixMult3x3fNV (GLenum matrixMode, const GLfloat *m);
+GLAPI void APIENTRY glMatrixMultTranspose3x3fNV (GLenum matrixMode, const GLfloat *m);
+GLAPI void APIENTRY glStencilThenCoverFillPathNV (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode);
+GLAPI void APIENTRY glStencilThenCoverStrokePathNV (GLuint path, GLint reference, GLuint mask, GLenum coverMode);
+GLAPI void APIENTRY glStencilThenCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+GLAPI void APIENTRY glStencilThenCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+GLAPI GLenum APIENTRY glPathGlyphIndexRangeNV (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]);
+GLAPI GLenum APIENTRY glPathGlyphIndexArrayNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+GLAPI GLenum APIENTRY glPathMemoryGlyphIndexArrayNV (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+GLAPI void APIENTRY glProgramPathFragmentInputGenNV (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs);
+GLAPI void APIENTRY glGetProgramResourcefvNV (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLfloat *params);
+GLAPI void APIENTRY glPathColorGenNV (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs);
+GLAPI void APIENTRY glPathTexGenNV (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs);
+GLAPI void APIENTRY glPathFogGenNV (GLenum genMode);
+GLAPI void APIENTRY glGetPathColorGenivNV (GLenum color, GLenum pname, GLint *value);
+GLAPI void APIENTRY glGetPathColorGenfvNV (GLenum color, GLenum pname, GLfloat *value);
+GLAPI void APIENTRY glGetPathTexGenivNV (GLenum texCoordSet, GLenum pname, GLint *value);
+GLAPI void APIENTRY glGetPathTexGenfvNV (GLenum texCoordSet, GLenum pname, GLfloat *value);
+#endif
+#endif /* GL_NV_path_rendering */
+
+#ifndef GL_NV_path_rendering_shared_edge
+#define GL_NV_path_rendering_shared_edge 1
+#define GL_SHARED_EDGE_NV                 0xC0
+#endif /* GL_NV_path_rendering_shared_edge */
+
+#ifndef GL_NV_pixel_data_range
+#define GL_NV_pixel_data_range 1
+#define GL_WRITE_PIXEL_DATA_RANGE_NV      0x8878
+#define GL_READ_PIXEL_DATA_RANGE_NV       0x8879
+#define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A
+#define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B
+#define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C
+#define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D
+typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, const void *pointer);
+typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelDataRangeNV (GLenum target, GLsizei length, const void *pointer);
+GLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum target);
+#endif
+#endif /* GL_NV_pixel_data_range */
+
+#ifndef GL_NV_point_sprite
+#define GL_NV_point_sprite 1
+#define GL_POINT_SPRITE_NV                0x8861
+#define GL_COORD_REPLACE_NV               0x8862
+#define GL_POINT_SPRITE_R_MODE_NV         0x8863
+typedef void (APIENTRYP PFNGLPOINTPARAMETERINVPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIVNVPROC) (GLenum pname, const GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameteriNV (GLenum pname, GLint param);
+GLAPI void APIENTRY glPointParameterivNV (GLenum pname, const GLint *params);
+#endif
+#endif /* GL_NV_point_sprite */
+
+#ifndef GL_NV_present_video
+#define GL_NV_present_video 1
+#define GL_FRAME_NV                       0x8E26
+#define GL_FIELDS_NV                      0x8E27
+#define GL_CURRENT_TIME_NV                0x8E28
+#define GL_NUM_FILL_STREAMS_NV            0x8E29
+#define GL_PRESENT_TIME_NV                0x8E2A
+#define GL_PRESENT_DURATION_NV            0x8E2B
+typedef void (APIENTRYP PFNGLPRESENTFRAMEKEYEDNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1);
+typedef void (APIENTRYP PFNGLPRESENTFRAMEDUALFILLNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3);
+typedef void (APIENTRYP PFNGLGETVIDEOIVNVPROC) (GLuint video_slot, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVIDEOUIVNVPROC) (GLuint video_slot, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLGETVIDEOI64VNVPROC) (GLuint video_slot, GLenum pname, GLint64EXT *params);
+typedef void (APIENTRYP PFNGLGETVIDEOUI64VNVPROC) (GLuint video_slot, GLenum pname, GLuint64EXT *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPresentFrameKeyedNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1);
+GLAPI void APIENTRY glPresentFrameDualFillNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3);
+GLAPI void APIENTRY glGetVideoivNV (GLuint video_slot, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetVideouivNV (GLuint video_slot, GLenum pname, GLuint *params);
+GLAPI void APIENTRY glGetVideoi64vNV (GLuint video_slot, GLenum pname, GLint64EXT *params);
+GLAPI void APIENTRY glGetVideoui64vNV (GLuint video_slot, GLenum pname, GLuint64EXT *params);
+#endif
+#endif /* GL_NV_present_video */
+
+#ifndef GL_NV_primitive_restart
+#define GL_NV_primitive_restart 1
+#define GL_PRIMITIVE_RESTART_NV           0x8558
+#define GL_PRIMITIVE_RESTART_INDEX_NV     0x8559
+typedef void (APIENTRYP PFNGLPRIMITIVERESTARTNVPROC) (void);
+typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXNVPROC) (GLuint index);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPrimitiveRestartNV (void);
+GLAPI void APIENTRY glPrimitiveRestartIndexNV (GLuint index);
+#endif
+#endif /* GL_NV_primitive_restart */
+
+#ifndef GL_NV_query_resource
+#define GL_NV_query_resource 1
+#define GL_QUERY_RESOURCE_TYPE_VIDMEM_ALLOC_NV 0x9540
+#define GL_QUERY_RESOURCE_MEMTYPE_VIDMEM_NV 0x9542
+#define GL_QUERY_RESOURCE_SYS_RESERVED_NV 0x9544
+#define GL_QUERY_RESOURCE_TEXTURE_NV      0x9545
+#define GL_QUERY_RESOURCE_RENDERBUFFER_NV 0x9546
+#define GL_QUERY_RESOURCE_BUFFEROBJECT_NV 0x9547
+typedef GLint (APIENTRYP PFNGLQUERYRESOURCENVPROC) (GLenum queryType, GLint tagId, GLuint bufSize, GLint *buffer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLint APIENTRY glQueryResourceNV (GLenum queryType, GLint tagId, GLuint bufSize, GLint *buffer);
+#endif
+#endif /* GL_NV_query_resource */
+
+#ifndef GL_NV_query_resource_tag
+#define GL_NV_query_resource_tag 1
+typedef void (APIENTRYP PFNGLGENQUERYRESOURCETAGNVPROC) (GLsizei n, GLint *tagIds);
+typedef void (APIENTRYP PFNGLDELETEQUERYRESOURCETAGNVPROC) (GLsizei n, const GLint *tagIds);
+typedef void (APIENTRYP PFNGLQUERYRESOURCETAGNVPROC) (GLint tagId, const GLchar *tagString);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenQueryResourceTagNV (GLsizei n, GLint *tagIds);
+GLAPI void APIENTRY glDeleteQueryResourceTagNV (GLsizei n, const GLint *tagIds);
+GLAPI void APIENTRY glQueryResourceTagNV (GLint tagId, const GLchar *tagString);
+#endif
+#endif /* GL_NV_query_resource_tag */
+
+#ifndef GL_NV_register_combiners
+#define GL_NV_register_combiners 1
+#define GL_REGISTER_COMBINERS_NV          0x8522
+#define GL_VARIABLE_A_NV                  0x8523
+#define GL_VARIABLE_B_NV                  0x8524
+#define GL_VARIABLE_C_NV                  0x8525
+#define GL_VARIABLE_D_NV                  0x8526
+#define GL_VARIABLE_E_NV                  0x8527
+#define GL_VARIABLE_F_NV                  0x8528
+#define GL_VARIABLE_G_NV                  0x8529
+#define GL_CONSTANT_COLOR0_NV             0x852A
+#define GL_CONSTANT_COLOR1_NV             0x852B
+#define GL_SPARE0_NV                      0x852E
+#define GL_SPARE1_NV                      0x852F
+#define GL_DISCARD_NV                     0x8530
+#define GL_E_TIMES_F_NV                   0x8531
+#define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532
+#define GL_UNSIGNED_IDENTITY_NV           0x8536
+#define GL_UNSIGNED_INVERT_NV             0x8537
+#define GL_EXPAND_NORMAL_NV               0x8538
+#define GL_EXPAND_NEGATE_NV               0x8539
+#define GL_HALF_BIAS_NORMAL_NV            0x853A
+#define GL_HALF_BIAS_NEGATE_NV            0x853B
+#define GL_SIGNED_IDENTITY_NV             0x853C
+#define GL_SIGNED_NEGATE_NV               0x853D
+#define GL_SCALE_BY_TWO_NV                0x853E
+#define GL_SCALE_BY_FOUR_NV               0x853F
+#define GL_SCALE_BY_ONE_HALF_NV           0x8540
+#define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV   0x8541
+#define GL_COMBINER_INPUT_NV              0x8542
+#define GL_COMBINER_MAPPING_NV            0x8543
+#define GL_COMBINER_COMPONENT_USAGE_NV    0x8544
+#define GL_COMBINER_AB_DOT_PRODUCT_NV     0x8545
+#define GL_COMBINER_CD_DOT_PRODUCT_NV     0x8546
+#define GL_COMBINER_MUX_SUM_NV            0x8547
+#define GL_COMBINER_SCALE_NV              0x8548
+#define GL_COMBINER_BIAS_NV               0x8549
+#define GL_COMBINER_AB_OUTPUT_NV          0x854A
+#define GL_COMBINER_CD_OUTPUT_NV          0x854B
+#define GL_COMBINER_SUM_OUTPUT_NV         0x854C
+#define GL_MAX_GENERAL_COMBINERS_NV       0x854D
+#define GL_NUM_GENERAL_COMBINERS_NV       0x854E
+#define GL_COLOR_SUM_CLAMP_NV             0x854F
+#define GL_COMBINER0_NV                   0x8550
+#define GL_COMBINER1_NV                   0x8551
+#define GL_COMBINER2_NV                   0x8552
+#define GL_COMBINER3_NV                   0x8553
+#define GL_COMBINER4_NV                   0x8554
+#define GL_COMBINER5_NV                   0x8555
+#define GL_COMBINER6_NV                   0x8556
+#define GL_COMBINER7_NV                   0x8557
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);
+typedef void (APIENTRYP PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum);
+typedef void (APIENTRYP PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);
+typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCombinerParameterfvNV (GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glCombinerParameterfNV (GLenum pname, GLfloat param);
+GLAPI void APIENTRY glCombinerParameterivNV (GLenum pname, const GLint *params);
+GLAPI void APIENTRY glCombinerParameteriNV (GLenum pname, GLint param);
+GLAPI void APIENTRY glCombinerInputNV (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);
+GLAPI void APIENTRY glCombinerOutputNV (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum);
+GLAPI void APIENTRY glFinalCombinerInputNV (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);
+GLAPI void APIENTRY glGetCombinerInputParameterfvNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetCombinerInputParameterivNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetCombinerOutputParameterfvNV (GLenum stage, GLenum portion, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetCombinerOutputParameterivNV (GLenum stage, GLenum portion, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetFinalCombinerInputParameterfvNV (GLenum variable, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetFinalCombinerInputParameterivNV (GLenum variable, GLenum pname, GLint *params);
+#endif
+#endif /* GL_NV_register_combiners */
+
+#ifndef GL_NV_register_combiners2
+#define GL_NV_register_combiners2 1
+#define GL_PER_STAGE_CONSTANTS_NV         0x8535
+typedef void (APIENTRYP PFNGLCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCombinerStageParameterfvNV (GLenum stage, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum stage, GLenum pname, GLfloat *params);
+#endif
+#endif /* GL_NV_register_combiners2 */
+
+#ifndef GL_NV_representative_fragment_test
+#define GL_NV_representative_fragment_test 1
+#define GL_REPRESENTATIVE_FRAGMENT_TEST_NV 0x937F
+#endif /* GL_NV_representative_fragment_test */
+
+#ifndef GL_NV_robustness_video_memory_purge
+#define GL_NV_robustness_video_memory_purge 1
+#define GL_PURGED_CONTEXT_RESET_NV        0x92BB
+#endif /* GL_NV_robustness_video_memory_purge */
+
+#ifndef GL_NV_sample_locations
+#define GL_NV_sample_locations 1
+#define GL_SAMPLE_LOCATION_SUBPIXEL_BITS_NV 0x933D
+#define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_NV 0x933E
+#define GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_NV 0x933F
+#define GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_NV 0x9340
+#define GL_SAMPLE_LOCATION_NV             0x8E50
+#define GL_PROGRAMMABLE_SAMPLE_LOCATION_NV 0x9341
+#define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_NV 0x9342
+#define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_NV 0x9343
+typedef void (APIENTRYP PFNGLFRAMEBUFFERSAMPLELOCATIONSFVNVPROC) (GLenum target, GLuint start, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC) (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLRESOLVEDEPTHVALUESNVPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFramebufferSampleLocationsfvNV (GLenum target, GLuint start, GLsizei count, const GLfloat *v);
+GLAPI void APIENTRY glNamedFramebufferSampleLocationsfvNV (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v);
+GLAPI void APIENTRY glResolveDepthValuesNV (void);
+#endif
+#endif /* GL_NV_sample_locations */
+
+#ifndef GL_NV_sample_mask_override_coverage
+#define GL_NV_sample_mask_override_coverage 1
+#endif /* GL_NV_sample_mask_override_coverage */
+
+#ifndef GL_NV_scissor_exclusive
+#define GL_NV_scissor_exclusive 1
+#define GL_SCISSOR_TEST_EXCLUSIVE_NV      0x9555
+#define GL_SCISSOR_BOX_EXCLUSIVE_NV       0x9556
+typedef void (APIENTRYP PFNGLSCISSOREXCLUSIVENVPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLSCISSOREXCLUSIVEARRAYVNVPROC) (GLuint first, GLsizei count, const GLint *v);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glScissorExclusiveNV (GLint x, GLint y, GLsizei width, GLsizei height);
+GLAPI void APIENTRY glScissorExclusiveArrayvNV (GLuint first, GLsizei count, const GLint *v);
+#endif
+#endif /* GL_NV_scissor_exclusive */
+
+#ifndef GL_NV_shader_atomic_counters
+#define GL_NV_shader_atomic_counters 1
+#endif /* GL_NV_shader_atomic_counters */
+
+#ifndef GL_NV_shader_atomic_float
+#define GL_NV_shader_atomic_float 1
+#endif /* GL_NV_shader_atomic_float */
+
+#ifndef GL_NV_shader_atomic_float64
+#define GL_NV_shader_atomic_float64 1
+#endif /* GL_NV_shader_atomic_float64 */
+
+#ifndef GL_NV_shader_atomic_fp16_vector
+#define GL_NV_shader_atomic_fp16_vector 1
+#endif /* GL_NV_shader_atomic_fp16_vector */
+
+#ifndef GL_NV_shader_atomic_int64
+#define GL_NV_shader_atomic_int64 1
+#endif /* GL_NV_shader_atomic_int64 */
+
+#ifndef GL_NV_shader_buffer_load
+#define GL_NV_shader_buffer_load 1
+#define GL_BUFFER_GPU_ADDRESS_NV          0x8F1D
+#define GL_GPU_ADDRESS_NV                 0x8F34
+#define GL_MAX_SHADER_BUFFER_ADDRESS_NV   0x8F35
+typedef void (APIENTRYP PFNGLMAKEBUFFERRESIDENTNVPROC) (GLenum target, GLenum access);
+typedef void (APIENTRYP PFNGLMAKEBUFFERNONRESIDENTNVPROC) (GLenum target);
+typedef GLboolean (APIENTRYP PFNGLISBUFFERRESIDENTNVPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERRESIDENTNVPROC) (GLuint buffer, GLenum access);
+typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERNONRESIDENTNVPROC) (GLuint buffer);
+typedef GLboolean (APIENTRYP PFNGLISNAMEDBUFFERRESIDENTNVPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERUI64VNVPROC) (GLenum target, GLenum pname, GLuint64EXT *params);
+typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC) (GLuint buffer, GLenum pname, GLuint64EXT *params);
+typedef void (APIENTRYP PFNGLGETINTEGERUI64VNVPROC) (GLenum value, GLuint64EXT *result);
+typedef void (APIENTRYP PFNGLUNIFORMUI64NVPROC) (GLint location, GLuint64EXT value);
+typedef void (APIENTRYP PFNGLUNIFORMUI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64NVPROC) (GLuint program, GLint location, GLuint64EXT value);
+typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMakeBufferResidentNV (GLenum target, GLenum access);
+GLAPI void APIENTRY glMakeBufferNonResidentNV (GLenum target);
+GLAPI GLboolean APIENTRY glIsBufferResidentNV (GLenum target);
+GLAPI void APIENTRY glMakeNamedBufferResidentNV (GLuint buffer, GLenum access);
+GLAPI void APIENTRY glMakeNamedBufferNonResidentNV (GLuint buffer);
+GLAPI GLboolean APIENTRY glIsNamedBufferResidentNV (GLuint buffer);
+GLAPI void APIENTRY glGetBufferParameterui64vNV (GLenum target, GLenum pname, GLuint64EXT *params);
+GLAPI void APIENTRY glGetNamedBufferParameterui64vNV (GLuint buffer, GLenum pname, GLuint64EXT *params);
+GLAPI void APIENTRY glGetIntegerui64vNV (GLenum value, GLuint64EXT *result);
+GLAPI void APIENTRY glUniformui64NV (GLint location, GLuint64EXT value);
+GLAPI void APIENTRY glUniformui64vNV (GLint location, GLsizei count, const GLuint64EXT *value);
+GLAPI void APIENTRY glProgramUniformui64NV (GLuint program, GLint location, GLuint64EXT value);
+GLAPI void APIENTRY glProgramUniformui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);
+#endif
+#endif /* GL_NV_shader_buffer_load */
+
+#ifndef GL_NV_shader_buffer_store
+#define GL_NV_shader_buffer_store 1
+#define GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV 0x00000010
+#endif /* GL_NV_shader_buffer_store */
+
+#ifndef GL_NV_shader_storage_buffer_object
+#define GL_NV_shader_storage_buffer_object 1
+#endif /* GL_NV_shader_storage_buffer_object */
+
+#ifndef GL_NV_shader_texture_footprint
+#define GL_NV_shader_texture_footprint 1
+#endif /* GL_NV_shader_texture_footprint */
+
+#ifndef GL_NV_shader_thread_group
+#define GL_NV_shader_thread_group 1
+#define GL_WARP_SIZE_NV                   0x9339
+#define GL_WARPS_PER_SM_NV                0x933A
+#define GL_SM_COUNT_NV                    0x933B
+#endif /* GL_NV_shader_thread_group */
+
+#ifndef GL_NV_shader_thread_shuffle
+#define GL_NV_shader_thread_shuffle 1
+#endif /* GL_NV_shader_thread_shuffle */
+
+#ifndef GL_NV_shading_rate_image
+#define GL_NV_shading_rate_image 1
+#define GL_SHADING_RATE_IMAGE_NV          0x9563
+#define GL_SHADING_RATE_NO_INVOCATIONS_NV 0x9564
+#define GL_SHADING_RATE_1_INVOCATION_PER_PIXEL_NV 0x9565
+#define GL_SHADING_RATE_1_INVOCATION_PER_1X2_PIXELS_NV 0x9566
+#define GL_SHADING_RATE_1_INVOCATION_PER_2X1_PIXELS_NV 0x9567
+#define GL_SHADING_RATE_1_INVOCATION_PER_2X2_PIXELS_NV 0x9568
+#define GL_SHADING_RATE_1_INVOCATION_PER_2X4_PIXELS_NV 0x9569
+#define GL_SHADING_RATE_1_INVOCATION_PER_4X2_PIXELS_NV 0x956A
+#define GL_SHADING_RATE_1_INVOCATION_PER_4X4_PIXELS_NV 0x956B
+#define GL_SHADING_RATE_2_INVOCATIONS_PER_PIXEL_NV 0x956C
+#define GL_SHADING_RATE_4_INVOCATIONS_PER_PIXEL_NV 0x956D
+#define GL_SHADING_RATE_8_INVOCATIONS_PER_PIXEL_NV 0x956E
+#define GL_SHADING_RATE_16_INVOCATIONS_PER_PIXEL_NV 0x956F
+#define GL_SHADING_RATE_IMAGE_BINDING_NV  0x955B
+#define GL_SHADING_RATE_IMAGE_TEXEL_WIDTH_NV 0x955C
+#define GL_SHADING_RATE_IMAGE_TEXEL_HEIGHT_NV 0x955D
+#define GL_SHADING_RATE_IMAGE_PALETTE_SIZE_NV 0x955E
+#define GL_MAX_COARSE_FRAGMENT_SAMPLES_NV 0x955F
+#define GL_SHADING_RATE_SAMPLE_ORDER_DEFAULT_NV 0x95AE
+#define GL_SHADING_RATE_SAMPLE_ORDER_PIXEL_MAJOR_NV 0x95AF
+#define GL_SHADING_RATE_SAMPLE_ORDER_SAMPLE_MAJOR_NV 0x95B0
+typedef void (APIENTRYP PFNGLBINDSHADINGRATEIMAGENVPROC) (GLuint texture);
+typedef void (APIENTRYP PFNGLGETSHADINGRATEIMAGEPALETTENVPROC) (GLuint viewport, GLuint entry, GLenum *rate);
+typedef void (APIENTRYP PFNGLGETSHADINGRATESAMPLELOCATIONIVNVPROC) (GLenum rate, GLuint samples, GLuint index, GLint *location);
+typedef void (APIENTRYP PFNGLSHADINGRATEIMAGEBARRIERNVPROC) (GLboolean synchronize);
+typedef void (APIENTRYP PFNGLSHADINGRATEIMAGEPALETTENVPROC) (GLuint viewport, GLuint first, GLsizei count, const GLenum *rates);
+typedef void (APIENTRYP PFNGLSHADINGRATESAMPLEORDERNVPROC) (GLenum order);
+typedef void (APIENTRYP PFNGLSHADINGRATESAMPLEORDERCUSTOMNVPROC) (GLenum rate, GLuint samples, const GLint *locations);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindShadingRateImageNV (GLuint texture);
+GLAPI void APIENTRY glGetShadingRateImagePaletteNV (GLuint viewport, GLuint entry, GLenum *rate);
+GLAPI void APIENTRY glGetShadingRateSampleLocationivNV (GLenum rate, GLuint samples, GLuint index, GLint *location);
+GLAPI void APIENTRY glShadingRateImageBarrierNV (GLboolean synchronize);
+GLAPI void APIENTRY glShadingRateImagePaletteNV (GLuint viewport, GLuint first, GLsizei count, const GLenum *rates);
+GLAPI void APIENTRY glShadingRateSampleOrderNV (GLenum order);
+GLAPI void APIENTRY glShadingRateSampleOrderCustomNV (GLenum rate, GLuint samples, const GLint *locations);
+#endif
+#endif /* GL_NV_shading_rate_image */
+
+#ifndef GL_NV_stereo_view_rendering
+#define GL_NV_stereo_view_rendering 1
+#endif /* GL_NV_stereo_view_rendering */
+
+#ifndef GL_NV_tessellation_program5
+#define GL_NV_tessellation_program5 1
+#define GL_MAX_PROGRAM_PATCH_ATTRIBS_NV   0x86D8
+#define GL_TESS_CONTROL_PROGRAM_NV        0x891E
+#define GL_TESS_EVALUATION_PROGRAM_NV     0x891F
+#define GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV 0x8C74
+#define GL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV 0x8C75
+#endif /* GL_NV_tessellation_program5 */
+
+#ifndef GL_NV_texgen_emboss
+#define GL_NV_texgen_emboss 1
+#define GL_EMBOSS_LIGHT_NV                0x855D
+#define GL_EMBOSS_CONSTANT_NV             0x855E
+#define GL_EMBOSS_MAP_NV                  0x855F
+#endif /* GL_NV_texgen_emboss */
+
+#ifndef GL_NV_texgen_reflection
+#define GL_NV_texgen_reflection 1
+#define GL_NORMAL_MAP_NV                  0x8511
+#define GL_REFLECTION_MAP_NV              0x8512
+#endif /* GL_NV_texgen_reflection */
+
+#ifndef GL_NV_texture_barrier
+#define GL_NV_texture_barrier 1
+typedef void (APIENTRYP PFNGLTEXTUREBARRIERNVPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTextureBarrierNV (void);
+#endif
+#endif /* GL_NV_texture_barrier */
+
+#ifndef GL_NV_texture_compression_vtc
+#define GL_NV_texture_compression_vtc 1
+#endif /* GL_NV_texture_compression_vtc */
+
+#ifndef GL_NV_texture_env_combine4
+#define GL_NV_texture_env_combine4 1
+#define GL_COMBINE4_NV                    0x8503
+#define GL_SOURCE3_RGB_NV                 0x8583
+#define GL_SOURCE3_ALPHA_NV               0x858B
+#define GL_OPERAND3_RGB_NV                0x8593
+#define GL_OPERAND3_ALPHA_NV              0x859B
+#endif /* GL_NV_texture_env_combine4 */
+
+#ifndef GL_NV_texture_expand_normal
+#define GL_NV_texture_expand_normal 1
+#define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F
+#endif /* GL_NV_texture_expand_normal */
+
+#ifndef GL_NV_texture_multisample
+#define GL_NV_texture_multisample 1
+#define GL_TEXTURE_COVERAGE_SAMPLES_NV    0x9045
+#define GL_TEXTURE_COLOR_SAMPLES_NV       0x9046
+typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations);
+typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations);
+typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations);
+typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations);
+typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations);
+typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexImage2DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations);
+GLAPI void APIENTRY glTexImage3DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations);
+GLAPI void APIENTRY glTextureImage2DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations);
+GLAPI void APIENTRY glTextureImage3DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations);
+GLAPI void APIENTRY glTextureImage2DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations);
+GLAPI void APIENTRY glTextureImage3DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations);
+#endif
+#endif /* GL_NV_texture_multisample */
+
+#ifndef GL_NV_texture_rectangle
+#define GL_NV_texture_rectangle 1
+#define GL_TEXTURE_RECTANGLE_NV           0x84F5
+#define GL_TEXTURE_BINDING_RECTANGLE_NV   0x84F6
+#define GL_PROXY_TEXTURE_RECTANGLE_NV     0x84F7
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV  0x84F8
+#endif /* GL_NV_texture_rectangle */
+
+#ifndef GL_NV_texture_rectangle_compressed
+#define GL_NV_texture_rectangle_compressed 1
+#endif /* GL_NV_texture_rectangle_compressed */
+
+#ifndef GL_NV_texture_shader
+#define GL_NV_texture_shader 1
+#define GL_OFFSET_TEXTURE_RECTANGLE_NV    0x864C
+#define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D
+#define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E
+#define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9
+#define GL_UNSIGNED_INT_S8_S8_8_8_NV      0x86DA
+#define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV  0x86DB
+#define GL_DSDT_MAG_INTENSITY_NV          0x86DC
+#define GL_SHADER_CONSISTENT_NV           0x86DD
+#define GL_TEXTURE_SHADER_NV              0x86DE
+#define GL_SHADER_OPERATION_NV            0x86DF
+#define GL_CULL_MODES_NV                  0x86E0
+#define GL_OFFSET_TEXTURE_MATRIX_NV       0x86E1
+#define GL_OFFSET_TEXTURE_SCALE_NV        0x86E2
+#define GL_OFFSET_TEXTURE_BIAS_NV         0x86E3
+#define GL_OFFSET_TEXTURE_2D_MATRIX_NV    0x86E1
+#define GL_OFFSET_TEXTURE_2D_SCALE_NV     0x86E2
+#define GL_OFFSET_TEXTURE_2D_BIAS_NV      0x86E3
+#define GL_PREVIOUS_TEXTURE_INPUT_NV      0x86E4
+#define GL_CONST_EYE_NV                   0x86E5
+#define GL_PASS_THROUGH_NV                0x86E6
+#define GL_CULL_FRAGMENT_NV               0x86E7
+#define GL_OFFSET_TEXTURE_2D_NV           0x86E8
+#define GL_DEPENDENT_AR_TEXTURE_2D_NV     0x86E9
+#define GL_DEPENDENT_GB_TEXTURE_2D_NV     0x86EA
+#define GL_DOT_PRODUCT_NV                 0x86EC
+#define GL_DOT_PRODUCT_DEPTH_REPLACE_NV   0x86ED
+#define GL_DOT_PRODUCT_TEXTURE_2D_NV      0x86EE
+#define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0
+#define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1
+#define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2
+#define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3
+#define GL_HILO_NV                        0x86F4
+#define GL_DSDT_NV                        0x86F5
+#define GL_DSDT_MAG_NV                    0x86F6
+#define GL_DSDT_MAG_VIB_NV                0x86F7
+#define GL_HILO16_NV                      0x86F8
+#define GL_SIGNED_HILO_NV                 0x86F9
+#define GL_SIGNED_HILO16_NV               0x86FA
+#define GL_SIGNED_RGBA_NV                 0x86FB
+#define GL_SIGNED_RGBA8_NV                0x86FC
+#define GL_SIGNED_RGB_NV                  0x86FE
+#define GL_SIGNED_RGB8_NV                 0x86FF
+#define GL_SIGNED_LUMINANCE_NV            0x8701
+#define GL_SIGNED_LUMINANCE8_NV           0x8702
+#define GL_SIGNED_LUMINANCE_ALPHA_NV      0x8703
+#define GL_SIGNED_LUMINANCE8_ALPHA8_NV    0x8704
+#define GL_SIGNED_ALPHA_NV                0x8705
+#define GL_SIGNED_ALPHA8_NV               0x8706
+#define GL_SIGNED_INTENSITY_NV            0x8707
+#define GL_SIGNED_INTENSITY8_NV           0x8708
+#define GL_DSDT8_NV                       0x8709
+#define GL_DSDT8_MAG8_NV                  0x870A
+#define GL_DSDT8_MAG8_INTENSITY8_NV       0x870B
+#define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV   0x870C
+#define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D
+#define GL_HI_SCALE_NV                    0x870E
+#define GL_LO_SCALE_NV                    0x870F
+#define GL_DS_SCALE_NV                    0x8710
+#define GL_DT_SCALE_NV                    0x8711
+#define GL_MAGNITUDE_SCALE_NV             0x8712
+#define GL_VIBRANCE_SCALE_NV              0x8713
+#define GL_HI_BIAS_NV                     0x8714
+#define GL_LO_BIAS_NV                     0x8715
+#define GL_DS_BIAS_NV                     0x8716
+#define GL_DT_BIAS_NV                     0x8717
+#define GL_MAGNITUDE_BIAS_NV              0x8718
+#define GL_VIBRANCE_BIAS_NV               0x8719
+#define GL_TEXTURE_BORDER_VALUES_NV       0x871A
+#define GL_TEXTURE_HI_SIZE_NV             0x871B
+#define GL_TEXTURE_LO_SIZE_NV             0x871C
+#define GL_TEXTURE_DS_SIZE_NV             0x871D
+#define GL_TEXTURE_DT_SIZE_NV             0x871E
+#define GL_TEXTURE_MAG_SIZE_NV            0x871F
+#endif /* GL_NV_texture_shader */
+
+#ifndef GL_NV_texture_shader2
+#define GL_NV_texture_shader2 1
+#define GL_DOT_PRODUCT_TEXTURE_3D_NV      0x86EF
+#endif /* GL_NV_texture_shader2 */
+
+#ifndef GL_NV_texture_shader3
+#define GL_NV_texture_shader3 1
+#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850
+#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851
+#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852
+#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853
+#define GL_OFFSET_HILO_TEXTURE_2D_NV      0x8854
+#define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855
+#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856
+#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857
+#define GL_DEPENDENT_HILO_TEXTURE_2D_NV   0x8858
+#define GL_DEPENDENT_RGB_TEXTURE_3D_NV    0x8859
+#define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A
+#define GL_DOT_PRODUCT_PASS_THROUGH_NV    0x885B
+#define GL_DOT_PRODUCT_TEXTURE_1D_NV      0x885C
+#define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D
+#define GL_HILO8_NV                       0x885E
+#define GL_SIGNED_HILO8_NV                0x885F
+#define GL_FORCE_BLUE_TO_ONE_NV           0x8860
+#endif /* GL_NV_texture_shader3 */
+
+#ifndef GL_NV_transform_feedback
+#define GL_NV_transform_feedback 1
+#define GL_BACK_PRIMARY_COLOR_NV          0x8C77
+#define GL_BACK_SECONDARY_COLOR_NV        0x8C78
+#define GL_TEXTURE_COORD_NV               0x8C79
+#define GL_CLIP_DISTANCE_NV               0x8C7A
+#define GL_VERTEX_ID_NV                   0x8C7B
+#define GL_PRIMITIVE_ID_NV                0x8C7C
+#define GL_GENERIC_ATTRIB_NV              0x8C7D
+#define GL_TRANSFORM_FEEDBACK_ATTRIBS_NV  0x8C7E
+#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV 0x8C7F
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV 0x8C80
+#define GL_ACTIVE_VARYINGS_NV             0x8C81
+#define GL_ACTIVE_VARYING_MAX_LENGTH_NV   0x8C82
+#define GL_TRANSFORM_FEEDBACK_VARYINGS_NV 0x8C83
+#define GL_TRANSFORM_FEEDBACK_BUFFER_START_NV 0x8C84
+#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV 0x8C85
+#define GL_TRANSFORM_FEEDBACK_RECORD_NV   0x8C86
+#define GL_PRIMITIVES_GENERATED_NV        0x8C87
+#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV 0x8C88
+#define GL_RASTERIZER_DISCARD_NV          0x8C89
+#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_NV 0x8C8A
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV 0x8C8B
+#define GL_INTERLEAVED_ATTRIBS_NV         0x8C8C
+#define GL_SEPARATE_ATTRIBS_NV            0x8C8D
+#define GL_TRANSFORM_FEEDBACK_BUFFER_NV   0x8C8E
+#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV 0x8C8F
+#define GL_LAYER_NV                       0x8DAA
+#define GL_NEXT_BUFFER_NV                 -2
+#define GL_SKIP_COMPONENTS4_NV            -3
+#define GL_SKIP_COMPONENTS3_NV            -4
+#define GL_SKIP_COMPONENTS2_NV            -5
+#define GL_SKIP_COMPONENTS1_NV            -6
+typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKNVPROC) (GLenum primitiveMode);
+typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKNVPROC) (void);
+typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC) (GLsizei count, const GLint *attribs, GLenum bufferMode);
+typedef void (APIENTRYP PFNGLBINDBUFFERRANGENVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETNVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset);
+typedef void (APIENTRYP PFNGLBINDBUFFERBASENVPROC) (GLenum target, GLuint index, GLuint buffer);
+typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSNVPROC) (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode);
+typedef void (APIENTRYP PFNGLACTIVEVARYINGNVPROC) (GLuint program, const GLchar *name);
+typedef GLint (APIENTRYP PFNGLGETVARYINGLOCATIONNVPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETACTIVEVARYINGNVPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGNVPROC) (GLuint program, GLuint index, GLint *location);
+typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKSTREAMATTRIBSNVPROC) (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBeginTransformFeedbackNV (GLenum primitiveMode);
+GLAPI void APIENTRY glEndTransformFeedbackNV (void);
+GLAPI void APIENTRY glTransformFeedbackAttribsNV (GLsizei count, const GLint *attribs, GLenum bufferMode);
+GLAPI void APIENTRY glBindBufferRangeNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+GLAPI void APIENTRY glBindBufferOffsetNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset);
+GLAPI void APIENTRY glBindBufferBaseNV (GLenum target, GLuint index, GLuint buffer);
+GLAPI void APIENTRY glTransformFeedbackVaryingsNV (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode);
+GLAPI void APIENTRY glActiveVaryingNV (GLuint program, const GLchar *name);
+GLAPI GLint APIENTRY glGetVaryingLocationNV (GLuint program, const GLchar *name);
+GLAPI void APIENTRY glGetActiveVaryingNV (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);
+GLAPI void APIENTRY glGetTransformFeedbackVaryingNV (GLuint program, GLuint index, GLint *location);
+GLAPI void APIENTRY glTransformFeedbackStreamAttribsNV (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode);
+#endif
+#endif /* GL_NV_transform_feedback */
+
+#ifndef GL_NV_transform_feedback2
+#define GL_NV_transform_feedback2 1
+#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
+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);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindTransformFeedbackNV (GLenum target, GLuint id);
+GLAPI void APIENTRY glDeleteTransformFeedbacksNV (GLsizei n, const GLuint *ids);
+GLAPI void APIENTRY glGenTransformFeedbacksNV (GLsizei n, GLuint *ids);
+GLAPI GLboolean APIENTRY glIsTransformFeedbackNV (GLuint id);
+GLAPI void APIENTRY glPauseTransformFeedbackNV (void);
+GLAPI void APIENTRY glResumeTransformFeedbackNV (void);
+GLAPI void APIENTRY glDrawTransformFeedbackNV (GLenum mode, GLuint id);
+#endif
+#endif /* GL_NV_transform_feedback2 */
+
+#ifndef GL_NV_uniform_buffer_unified_memory
+#define GL_NV_uniform_buffer_unified_memory 1
+#define GL_UNIFORM_BUFFER_UNIFIED_NV      0x936E
+#define GL_UNIFORM_BUFFER_ADDRESS_NV      0x936F
+#define GL_UNIFORM_BUFFER_LENGTH_NV       0x9370
+#endif /* GL_NV_uniform_buffer_unified_memory */
+
+#ifndef GL_NV_vdpau_interop
+#define GL_NV_vdpau_interop 1
+typedef GLintptr GLvdpauSurfaceNV;
+#define GL_SURFACE_STATE_NV               0x86EB
+#define GL_SURFACE_REGISTERED_NV          0x86FD
+#define GL_SURFACE_MAPPED_NV              0x8700
+#define GL_WRITE_DISCARD_NV               0x88BE
+typedef void (APIENTRYP PFNGLVDPAUINITNVPROC) (const void *vdpDevice, const void *getProcAddress);
+typedef void (APIENTRYP PFNGLVDPAUFININVPROC) (void);
+typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTERVIDEOSURFACENVPROC) (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames);
+typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC) (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames);
+typedef GLboolean (APIENTRYP PFNGLVDPAUISSURFACENVPROC) (GLvdpauSurfaceNV surface);
+typedef void (APIENTRYP PFNGLVDPAUUNREGISTERSURFACENVPROC) (GLvdpauSurfaceNV surface);
+typedef void (APIENTRYP PFNGLVDPAUGETSURFACEIVNVPROC) (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
+typedef void (APIENTRYP PFNGLVDPAUSURFACEACCESSNVPROC) (GLvdpauSurfaceNV surface, GLenum access);
+typedef void (APIENTRYP PFNGLVDPAUMAPSURFACESNVPROC) (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces);
+typedef void (APIENTRYP PFNGLVDPAUUNMAPSURFACESNVPROC) (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVDPAUInitNV (const void *vdpDevice, const void *getProcAddress);
+GLAPI void APIENTRY glVDPAUFiniNV (void);
+GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterVideoSurfaceNV (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames);
+GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterOutputSurfaceNV (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames);
+GLAPI GLboolean APIENTRY glVDPAUIsSurfaceNV (GLvdpauSurfaceNV surface);
+GLAPI void APIENTRY glVDPAUUnregisterSurfaceNV (GLvdpauSurfaceNV surface);
+GLAPI void APIENTRY glVDPAUGetSurfaceivNV (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
+GLAPI void APIENTRY glVDPAUSurfaceAccessNV (GLvdpauSurfaceNV surface, GLenum access);
+GLAPI void APIENTRY glVDPAUMapSurfacesNV (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces);
+GLAPI void APIENTRY glVDPAUUnmapSurfacesNV (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces);
+#endif
+#endif /* GL_NV_vdpau_interop */
+
+#ifndef GL_NV_vdpau_interop2
+#define GL_NV_vdpau_interop2 1
+typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTERVIDEOSURFACEWITHPICTURESTRUCTURENVPROC) (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames, GLboolean isFrameStructure);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterVideoSurfaceWithPictureStructureNV (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames, GLboolean isFrameStructure);
+#endif
+#endif /* GL_NV_vdpau_interop2 */
+
+#ifndef GL_NV_vertex_array_range
+#define GL_NV_vertex_array_range 1
+#define GL_VERTEX_ARRAY_RANGE_NV          0x851D
+#define GL_VERTEX_ARRAY_RANGE_LENGTH_NV   0x851E
+#define GL_VERTEX_ARRAY_RANGE_VALID_NV    0x851F
+#define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520
+#define GL_VERTEX_ARRAY_RANGE_POINTER_NV  0x8521
+typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void);
+typedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const void *pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFlushVertexArrayRangeNV (void);
+GLAPI void APIENTRY glVertexArrayRangeNV (GLsizei length, const void *pointer);
+#endif
+#endif /* GL_NV_vertex_array_range */
+
+#ifndef GL_NV_vertex_array_range2
+#define GL_NV_vertex_array_range2 1
+#define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533
+#endif /* GL_NV_vertex_array_range2 */
+
+#ifndef GL_NV_vertex_attrib_integer_64bit
+#define GL_NV_vertex_attrib_integer_64bit 1
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64NVPROC) (GLuint index, GLint64EXT x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64VNVPROC) (GLuint index, const GLint64EXT *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64VNVPROC) (GLuint index, const GLint64EXT *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64VNVPROC) (GLuint index, const GLint64EXT *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64VNVPROC) (GLuint index, const GLint64EXT *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64NVPROC) (GLuint index, GLuint64EXT x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VNVPROC) (GLuint index, const GLuint64EXT *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64VNVPROC) (GLuint index, const GLuint64EXT *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64VNVPROC) (GLuint index, const GLuint64EXT *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64VNVPROC) (GLuint index, const GLuint64EXT *v);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLI64VNVPROC) (GLuint index, GLenum pname, GLint64EXT *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VNVPROC) (GLuint index, GLenum pname, GLuint64EXT *params);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttribL1i64NV (GLuint index, GLint64EXT x);
+GLAPI void APIENTRY glVertexAttribL2i64NV (GLuint index, GLint64EXT x, GLint64EXT y);
+GLAPI void APIENTRY glVertexAttribL3i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z);
+GLAPI void APIENTRY glVertexAttribL4i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);
+GLAPI void APIENTRY glVertexAttribL1i64vNV (GLuint index, const GLint64EXT *v);
+GLAPI void APIENTRY glVertexAttribL2i64vNV (GLuint index, const GLint64EXT *v);
+GLAPI void APIENTRY glVertexAttribL3i64vNV (GLuint index, const GLint64EXT *v);
+GLAPI void APIENTRY glVertexAttribL4i64vNV (GLuint index, const GLint64EXT *v);
+GLAPI void APIENTRY glVertexAttribL1ui64NV (GLuint index, GLuint64EXT x);
+GLAPI void APIENTRY glVertexAttribL2ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y);
+GLAPI void APIENTRY glVertexAttribL3ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);
+GLAPI void APIENTRY glVertexAttribL4ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);
+GLAPI void APIENTRY glVertexAttribL1ui64vNV (GLuint index, const GLuint64EXT *v);
+GLAPI void APIENTRY glVertexAttribL2ui64vNV (GLuint index, const GLuint64EXT *v);
+GLAPI void APIENTRY glVertexAttribL3ui64vNV (GLuint index, const GLuint64EXT *v);
+GLAPI void APIENTRY glVertexAttribL4ui64vNV (GLuint index, const GLuint64EXT *v);
+GLAPI void APIENTRY glGetVertexAttribLi64vNV (GLuint index, GLenum pname, GLint64EXT *params);
+GLAPI void APIENTRY glGetVertexAttribLui64vNV (GLuint index, GLenum pname, GLuint64EXT *params);
+GLAPI void APIENTRY glVertexAttribLFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride);
+#endif
+#endif /* GL_NV_vertex_attrib_integer_64bit */
+
+#ifndef GL_NV_vertex_buffer_unified_memory
+#define GL_NV_vertex_buffer_unified_memory 1
+#define GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV 0x8F1E
+#define GL_ELEMENT_ARRAY_UNIFIED_NV       0x8F1F
+#define GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV 0x8F20
+#define GL_VERTEX_ARRAY_ADDRESS_NV        0x8F21
+#define GL_NORMAL_ARRAY_ADDRESS_NV        0x8F22
+#define GL_COLOR_ARRAY_ADDRESS_NV         0x8F23
+#define GL_INDEX_ARRAY_ADDRESS_NV         0x8F24
+#define GL_TEXTURE_COORD_ARRAY_ADDRESS_NV 0x8F25
+#define GL_EDGE_FLAG_ARRAY_ADDRESS_NV     0x8F26
+#define GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV 0x8F27
+#define GL_FOG_COORD_ARRAY_ADDRESS_NV     0x8F28
+#define GL_ELEMENT_ARRAY_ADDRESS_NV       0x8F29
+#define GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV  0x8F2A
+#define GL_VERTEX_ARRAY_LENGTH_NV         0x8F2B
+#define GL_NORMAL_ARRAY_LENGTH_NV         0x8F2C
+#define GL_COLOR_ARRAY_LENGTH_NV          0x8F2D
+#define GL_INDEX_ARRAY_LENGTH_NV          0x8F2E
+#define GL_TEXTURE_COORD_ARRAY_LENGTH_NV  0x8F2F
+#define GL_EDGE_FLAG_ARRAY_LENGTH_NV      0x8F30
+#define GL_SECONDARY_COLOR_ARRAY_LENGTH_NV 0x8F31
+#define GL_FOG_COORD_ARRAY_LENGTH_NV      0x8F32
+#define GL_ELEMENT_ARRAY_LENGTH_NV        0x8F33
+#define GL_DRAW_INDIRECT_UNIFIED_NV       0x8F40
+#define GL_DRAW_INDIRECT_ADDRESS_NV       0x8F41
+#define GL_DRAW_INDIRECT_LENGTH_NV        0x8F42
+typedef void (APIENTRYP PFNGLBUFFERADDRESSRANGENVPROC) (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length);
+typedef void (APIENTRYP PFNGLVERTEXFORMATNVPROC) (GLint size, GLenum type, GLsizei stride);
+typedef void (APIENTRYP PFNGLNORMALFORMATNVPROC) (GLenum type, GLsizei stride);
+typedef void (APIENTRYP PFNGLCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride);
+typedef void (APIENTRYP PFNGLINDEXFORMATNVPROC) (GLenum type, GLsizei stride);
+typedef void (APIENTRYP PFNGLTEXCOORDFORMATNVPROC) (GLint size, GLenum type, GLsizei stride);
+typedef void (APIENTRYP PFNGLEDGEFLAGFORMATNVPROC) (GLsizei stride);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride);
+typedef void (APIENTRYP PFNGLFOGCOORDFORMATNVPROC) (GLenum type, GLsizei stride);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride);
+typedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBufferAddressRangeNV (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length);
+GLAPI void APIENTRY glVertexFormatNV (GLint size, GLenum type, GLsizei stride);
+GLAPI void APIENTRY glNormalFormatNV (GLenum type, GLsizei stride);
+GLAPI void APIENTRY glColorFormatNV (GLint size, GLenum type, GLsizei stride);
+GLAPI void APIENTRY glIndexFormatNV (GLenum type, GLsizei stride);
+GLAPI void APIENTRY glTexCoordFormatNV (GLint size, GLenum type, GLsizei stride);
+GLAPI void APIENTRY glEdgeFlagFormatNV (GLsizei stride);
+GLAPI void APIENTRY glSecondaryColorFormatNV (GLint size, GLenum type, GLsizei stride);
+GLAPI void APIENTRY glFogCoordFormatNV (GLenum type, GLsizei stride);
+GLAPI void APIENTRY glVertexAttribFormatNV (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride);
+GLAPI void APIENTRY glVertexAttribIFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride);
+GLAPI void APIENTRY glGetIntegerui64i_vNV (GLenum value, GLuint index, GLuint64EXT *result);
+#endif
+#endif /* GL_NV_vertex_buffer_unified_memory */
+
+#ifndef GL_NV_vertex_program
+#define GL_NV_vertex_program 1
+#define GL_VERTEX_PROGRAM_NV              0x8620
+#define GL_VERTEX_STATE_PROGRAM_NV        0x8621
+#define GL_ATTRIB_ARRAY_SIZE_NV           0x8623
+#define GL_ATTRIB_ARRAY_STRIDE_NV         0x8624
+#define GL_ATTRIB_ARRAY_TYPE_NV           0x8625
+#define GL_CURRENT_ATTRIB_NV              0x8626
+#define GL_PROGRAM_LENGTH_NV              0x8627
+#define GL_PROGRAM_STRING_NV              0x8628
+#define GL_MODELVIEW_PROJECTION_NV        0x8629
+#define GL_IDENTITY_NV                    0x862A
+#define GL_INVERSE_NV                     0x862B
+#define GL_TRANSPOSE_NV                   0x862C
+#define GL_INVERSE_TRANSPOSE_NV           0x862D
+#define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E
+#define GL_MAX_TRACK_MATRICES_NV          0x862F
+#define GL_MATRIX0_NV                     0x8630
+#define GL_MATRIX1_NV                     0x8631
+#define GL_MATRIX2_NV                     0x8632
+#define GL_MATRIX3_NV                     0x8633
+#define GL_MATRIX4_NV                     0x8634
+#define GL_MATRIX5_NV                     0x8635
+#define GL_MATRIX6_NV                     0x8636
+#define GL_MATRIX7_NV                     0x8637
+#define GL_CURRENT_MATRIX_STACK_DEPTH_NV  0x8640
+#define GL_CURRENT_MATRIX_NV              0x8641
+#define GL_VERTEX_PROGRAM_POINT_SIZE_NV   0x8642
+#define GL_VERTEX_PROGRAM_TWO_SIDE_NV     0x8643
+#define GL_PROGRAM_PARAMETER_NV           0x8644
+#define GL_ATTRIB_ARRAY_POINTER_NV        0x8645
+#define GL_PROGRAM_TARGET_NV              0x8646
+#define GL_PROGRAM_RESIDENT_NV            0x8647
+#define GL_TRACK_MATRIX_NV                0x8648
+#define GL_TRACK_MATRIX_TRANSFORM_NV      0x8649
+#define GL_VERTEX_PROGRAM_BINDING_NV      0x864A
+#define GL_PROGRAM_ERROR_POSITION_NV      0x864B
+#define GL_VERTEX_ATTRIB_ARRAY0_NV        0x8650
+#define GL_VERTEX_ATTRIB_ARRAY1_NV        0x8651
+#define GL_VERTEX_ATTRIB_ARRAY2_NV        0x8652
+#define GL_VERTEX_ATTRIB_ARRAY3_NV        0x8653
+#define GL_VERTEX_ATTRIB_ARRAY4_NV        0x8654
+#define GL_VERTEX_ATTRIB_ARRAY5_NV        0x8655
+#define GL_VERTEX_ATTRIB_ARRAY6_NV        0x8656
+#define GL_VERTEX_ATTRIB_ARRAY7_NV        0x8657
+#define GL_VERTEX_ATTRIB_ARRAY8_NV        0x8658
+#define GL_VERTEX_ATTRIB_ARRAY9_NV        0x8659
+#define GL_VERTEX_ATTRIB_ARRAY10_NV       0x865A
+#define GL_VERTEX_ATTRIB_ARRAY11_NV       0x865B
+#define GL_VERTEX_ATTRIB_ARRAY12_NV       0x865C
+#define GL_VERTEX_ATTRIB_ARRAY13_NV       0x865D
+#define GL_VERTEX_ATTRIB_ARRAY14_NV       0x865E
+#define GL_VERTEX_ATTRIB_ARRAY15_NV       0x865F
+#define GL_MAP1_VERTEX_ATTRIB0_4_NV       0x8660
+#define GL_MAP1_VERTEX_ATTRIB1_4_NV       0x8661
+#define GL_MAP1_VERTEX_ATTRIB2_4_NV       0x8662
+#define GL_MAP1_VERTEX_ATTRIB3_4_NV       0x8663
+#define GL_MAP1_VERTEX_ATTRIB4_4_NV       0x8664
+#define GL_MAP1_VERTEX_ATTRIB5_4_NV       0x8665
+#define GL_MAP1_VERTEX_ATTRIB6_4_NV       0x8666
+#define GL_MAP1_VERTEX_ATTRIB7_4_NV       0x8667
+#define GL_MAP1_VERTEX_ATTRIB8_4_NV       0x8668
+#define GL_MAP1_VERTEX_ATTRIB9_4_NV       0x8669
+#define GL_MAP1_VERTEX_ATTRIB10_4_NV      0x866A
+#define GL_MAP1_VERTEX_ATTRIB11_4_NV      0x866B
+#define GL_MAP1_VERTEX_ATTRIB12_4_NV      0x866C
+#define GL_MAP1_VERTEX_ATTRIB13_4_NV      0x866D
+#define GL_MAP1_VERTEX_ATTRIB14_4_NV      0x866E
+#define GL_MAP1_VERTEX_ATTRIB15_4_NV      0x866F
+#define GL_MAP2_VERTEX_ATTRIB0_4_NV       0x8670
+#define GL_MAP2_VERTEX_ATTRIB1_4_NV       0x8671
+#define GL_MAP2_VERTEX_ATTRIB2_4_NV       0x8672
+#define GL_MAP2_VERTEX_ATTRIB3_4_NV       0x8673
+#define GL_MAP2_VERTEX_ATTRIB4_4_NV       0x8674
+#define GL_MAP2_VERTEX_ATTRIB5_4_NV       0x8675
+#define GL_MAP2_VERTEX_ATTRIB6_4_NV       0x8676
+#define GL_MAP2_VERTEX_ATTRIB7_4_NV       0x8677
+#define GL_MAP2_VERTEX_ATTRIB8_4_NV       0x8678
+#define GL_MAP2_VERTEX_ATTRIB9_4_NV       0x8679
+#define GL_MAP2_VERTEX_ATTRIB10_4_NV      0x867A
+#define GL_MAP2_VERTEX_ATTRIB11_4_NV      0x867B
+#define GL_MAP2_VERTEX_ATTRIB12_4_NV      0x867C
+#define GL_MAP2_VERTEX_ATTRIB13_4_NV      0x867D
+#define GL_MAP2_VERTEX_ATTRIB14_4_NV      0x867E
+#define GL_MAP2_VERTEX_ATTRIB15_4_NV      0x867F
+typedef GLboolean (APIENTRYP PFNGLAREPROGRAMSRESIDENTNVPROC) (GLsizei n, const GLuint *programs, GLboolean *residences);
+typedef void (APIENTRYP PFNGLBINDPROGRAMNVPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMSNVPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP PFNGLEXECUTEPROGRAMNVPROC) (GLenum target, GLuint id, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGENPROGRAMSNVPROC) (GLsizei n, GLuint *programs);
+typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERDVNVPROC) (GLenum target, GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte *program);
+typedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, void **pointer);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DVNVPROC) (GLenum target, GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FNVPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FVNVPROC) (GLenum target, GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SNVPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DNVPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FNVPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SNVPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4UBVNVPROC) (GLuint index, GLsizei count, const GLubyte *v);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLboolean APIENTRY glAreProgramsResidentNV (GLsizei n, const GLuint *programs, GLboolean *residences);
+GLAPI void APIENTRY glBindProgramNV (GLenum target, GLuint id);
+GLAPI void APIENTRY glDeleteProgramsNV (GLsizei n, const GLuint *programs);
+GLAPI void APIENTRY glExecuteProgramNV (GLenum target, GLuint id, const GLfloat *params);
+GLAPI void APIENTRY glGenProgramsNV (GLsizei n, GLuint *programs);
+GLAPI void APIENTRY glGetProgramParameterdvNV (GLenum target, GLuint index, GLenum pname, GLdouble *params);
+GLAPI void APIENTRY glGetProgramParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetProgramivNV (GLuint id, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetProgramStringNV (GLuint id, GLenum pname, GLubyte *program);
+GLAPI void APIENTRY glGetTrackMatrixivNV (GLenum target, GLuint address, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetVertexAttribdvNV (GLuint index, GLenum pname, GLdouble *params);
+GLAPI void APIENTRY glGetVertexAttribfvNV (GLuint index, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetVertexAttribivNV (GLuint index, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint index, GLenum pname, void **pointer);
+GLAPI GLboolean APIENTRY glIsProgramNV (GLuint id);
+GLAPI void APIENTRY glLoadProgramNV (GLenum target, GLuint id, GLsizei len, const GLubyte *program);
+GLAPI void APIENTRY glProgramParameter4dNV (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glProgramParameter4dvNV (GLenum target, GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glProgramParameter4fNV (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glProgramParameter4fvNV (GLenum target, GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glProgramParameters4dvNV (GLenum target, GLuint index, GLsizei count, const GLdouble *v);
+GLAPI void APIENTRY glProgramParameters4fvNV (GLenum target, GLuint index, GLsizei count, const GLfloat *v);
+GLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei n, const GLuint *programs);
+GLAPI void APIENTRY glTrackMatrixNV (GLenum target, GLuint address, GLenum matrix, GLenum transform);
+GLAPI void APIENTRY glVertexAttribPointerNV (GLuint index, GLint fsize, GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glVertexAttrib1dNV (GLuint index, GLdouble x);
+GLAPI void APIENTRY glVertexAttrib1dvNV (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib1fNV (GLuint index, GLfloat x);
+GLAPI void APIENTRY glVertexAttrib1fvNV (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib1sNV (GLuint index, GLshort x);
+GLAPI void APIENTRY glVertexAttrib1svNV (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib2dNV (GLuint index, GLdouble x, GLdouble y);
+GLAPI void APIENTRY glVertexAttrib2dvNV (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib2fNV (GLuint index, GLfloat x, GLfloat y);
+GLAPI void APIENTRY glVertexAttrib2fvNV (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib2sNV (GLuint index, GLshort x, GLshort y);
+GLAPI void APIENTRY glVertexAttrib2svNV (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib3dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+GLAPI void APIENTRY glVertexAttrib3dvNV (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib3fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glVertexAttrib3fvNV (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib3sNV (GLuint index, GLshort x, GLshort y, GLshort z);
+GLAPI void APIENTRY glVertexAttrib3svNV (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib4dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+GLAPI void APIENTRY glVertexAttrib4dvNV (GLuint index, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttrib4fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glVertexAttrib4fvNV (GLuint index, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttrib4sNV (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+GLAPI void APIENTRY glVertexAttrib4svNV (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttrib4ubNV (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+GLAPI void APIENTRY glVertexAttrib4ubvNV (GLuint index, const GLubyte *v);
+GLAPI void APIENTRY glVertexAttribs1dvNV (GLuint index, GLsizei count, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribs1fvNV (GLuint index, GLsizei count, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttribs1svNV (GLuint index, GLsizei count, const GLshort *v);
+GLAPI void APIENTRY glVertexAttribs2dvNV (GLuint index, GLsizei count, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribs2fvNV (GLuint index, GLsizei count, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttribs2svNV (GLuint index, GLsizei count, const GLshort *v);
+GLAPI void APIENTRY glVertexAttribs3dvNV (GLuint index, GLsizei count, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribs3fvNV (GLuint index, GLsizei count, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttribs3svNV (GLuint index, GLsizei count, const GLshort *v);
+GLAPI void APIENTRY glVertexAttribs4dvNV (GLuint index, GLsizei count, const GLdouble *v);
+GLAPI void APIENTRY glVertexAttribs4fvNV (GLuint index, GLsizei count, const GLfloat *v);
+GLAPI void APIENTRY glVertexAttribs4svNV (GLuint index, GLsizei count, const GLshort *v);
+GLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint index, GLsizei count, const GLubyte *v);
+#endif
+#endif /* GL_NV_vertex_program */
+
+#ifndef GL_NV_vertex_program1_1
+#define GL_NV_vertex_program1_1 1
+#endif /* GL_NV_vertex_program1_1 */
+
+#ifndef GL_NV_vertex_program2
+#define GL_NV_vertex_program2 1
+#endif /* GL_NV_vertex_program2 */
+
+#ifndef GL_NV_vertex_program2_option
+#define GL_NV_vertex_program2_option 1
+#endif /* GL_NV_vertex_program2_option */
+
+#ifndef GL_NV_vertex_program3
+#define GL_NV_vertex_program3 1
+#endif /* GL_NV_vertex_program3 */
+
+#ifndef GL_NV_vertex_program4
+#define GL_NV_vertex_program4 1
+#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV 0x88FD
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IEXTPROC) (GLuint index, GLint x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IEXTPROC) (GLuint index, GLint x, GLint y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IEXTPROC) (GLuint index, GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IEXTPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIEXTPROC) (GLuint index, GLuint x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIEXTPROC) (GLuint index, GLuint x, GLuint y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVEXTPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVEXTPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVEXTPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVEXTPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVEXTPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVEXTPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVEXTPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVEXTPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVEXTPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVEXTPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVEXTPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVEXTPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVEXTPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVEXTPROC) (GLuint index, GLenum pname, GLuint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttribI1iEXT (GLuint index, GLint x);
+GLAPI void APIENTRY glVertexAttribI2iEXT (GLuint index, GLint x, GLint y);
+GLAPI void APIENTRY glVertexAttribI3iEXT (GLuint index, GLint x, GLint y, GLint z);
+GLAPI void APIENTRY glVertexAttribI4iEXT (GLuint index, GLint x, GLint y, GLint z, GLint w);
+GLAPI void APIENTRY glVertexAttribI1uiEXT (GLuint index, GLuint x);
+GLAPI void APIENTRY glVertexAttribI2uiEXT (GLuint index, GLuint x, GLuint y);
+GLAPI void APIENTRY glVertexAttribI3uiEXT (GLuint index, GLuint x, GLuint y, GLuint z);
+GLAPI void APIENTRY glVertexAttribI4uiEXT (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+GLAPI void APIENTRY glVertexAttribI1ivEXT (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttribI2ivEXT (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttribI3ivEXT (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttribI4ivEXT (GLuint index, const GLint *v);
+GLAPI void APIENTRY glVertexAttribI1uivEXT (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttribI2uivEXT (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttribI3uivEXT (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttribI4uivEXT (GLuint index, const GLuint *v);
+GLAPI void APIENTRY glVertexAttribI4bvEXT (GLuint index, const GLbyte *v);
+GLAPI void APIENTRY glVertexAttribI4svEXT (GLuint index, const GLshort *v);
+GLAPI void APIENTRY glVertexAttribI4ubvEXT (GLuint index, const GLubyte *v);
+GLAPI void APIENTRY glVertexAttribI4usvEXT (GLuint index, const GLushort *v);
+GLAPI void APIENTRY glVertexAttribIPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+GLAPI void APIENTRY glGetVertexAttribIivEXT (GLuint index, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetVertexAttribIuivEXT (GLuint index, GLenum pname, GLuint *params);
+#endif
+#endif /* GL_NV_vertex_program4 */
+
+#ifndef GL_NV_video_capture
+#define GL_NV_video_capture 1
+#define GL_VIDEO_BUFFER_NV                0x9020
+#define GL_VIDEO_BUFFER_BINDING_NV        0x9021
+#define GL_FIELD_UPPER_NV                 0x9022
+#define GL_FIELD_LOWER_NV                 0x9023
+#define GL_NUM_VIDEO_CAPTURE_STREAMS_NV   0x9024
+#define GL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV 0x9025
+#define GL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV 0x9026
+#define GL_LAST_VIDEO_CAPTURE_STATUS_NV   0x9027
+#define GL_VIDEO_BUFFER_PITCH_NV          0x9028
+#define GL_VIDEO_COLOR_CONVERSION_MATRIX_NV 0x9029
+#define GL_VIDEO_COLOR_CONVERSION_MAX_NV  0x902A
+#define GL_VIDEO_COLOR_CONVERSION_MIN_NV  0x902B
+#define GL_VIDEO_COLOR_CONVERSION_OFFSET_NV 0x902C
+#define GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV 0x902D
+#define GL_PARTIAL_SUCCESS_NV             0x902E
+#define GL_SUCCESS_NV                     0x902F
+#define GL_FAILURE_NV                     0x9030
+#define GL_YCBYCR8_422_NV                 0x9031
+#define GL_YCBAYCR8A_4224_NV              0x9032
+#define GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV  0x9033
+#define GL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV 0x9034
+#define GL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV  0x9035
+#define GL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV 0x9036
+#define GL_Z4Y12Z4CB12Z4CR12_444_NV       0x9037
+#define GL_VIDEO_CAPTURE_FRAME_WIDTH_NV   0x9038
+#define GL_VIDEO_CAPTURE_FRAME_HEIGHT_NV  0x9039
+#define GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV 0x903A
+#define GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV 0x903B
+#define GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV 0x903C
+typedef void (APIENTRYP PFNGLBEGINVIDEOCAPTURENVPROC) (GLuint video_capture_slot);
+typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMBUFFERNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset);
+typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMTEXTURENVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture);
+typedef void (APIENTRYP PFNGLENDVIDEOCAPTURENVPROC) (GLuint video_capture_slot);
+typedef void (APIENTRYP PFNGLGETVIDEOCAPTUREIVNVPROC) (GLuint video_capture_slot, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params);
+typedef GLenum (APIENTRYP PFNGLVIDEOCAPTURENVPROC) (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time);
+typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBeginVideoCaptureNV (GLuint video_capture_slot);
+GLAPI void APIENTRY glBindVideoCaptureStreamBufferNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset);
+GLAPI void APIENTRY glBindVideoCaptureStreamTextureNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture);
+GLAPI void APIENTRY glEndVideoCaptureNV (GLuint video_capture_slot);
+GLAPI void APIENTRY glGetVideoCaptureivNV (GLuint video_capture_slot, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetVideoCaptureStreamivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetVideoCaptureStreamfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetVideoCaptureStreamdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params);
+GLAPI GLenum APIENTRY glVideoCaptureNV (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time);
+GLAPI void APIENTRY glVideoCaptureStreamParameterivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glVideoCaptureStreamParameterfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glVideoCaptureStreamParameterdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params);
+#endif
+#endif /* GL_NV_video_capture */
+
+#ifndef GL_NV_viewport_array2
+#define GL_NV_viewport_array2 1
+#endif /* GL_NV_viewport_array2 */
+
+#ifndef GL_NV_viewport_swizzle
+#define GL_NV_viewport_swizzle 1
+#define GL_VIEWPORT_SWIZZLE_POSITIVE_X_NV 0x9350
+#define GL_VIEWPORT_SWIZZLE_NEGATIVE_X_NV 0x9351
+#define GL_VIEWPORT_SWIZZLE_POSITIVE_Y_NV 0x9352
+#define GL_VIEWPORT_SWIZZLE_NEGATIVE_Y_NV 0x9353
+#define GL_VIEWPORT_SWIZZLE_POSITIVE_Z_NV 0x9354
+#define GL_VIEWPORT_SWIZZLE_NEGATIVE_Z_NV 0x9355
+#define GL_VIEWPORT_SWIZZLE_POSITIVE_W_NV 0x9356
+#define GL_VIEWPORT_SWIZZLE_NEGATIVE_W_NV 0x9357
+#define GL_VIEWPORT_SWIZZLE_X_NV          0x9358
+#define GL_VIEWPORT_SWIZZLE_Y_NV          0x9359
+#define GL_VIEWPORT_SWIZZLE_Z_NV          0x935A
+#define GL_VIEWPORT_SWIZZLE_W_NV          0x935B
+typedef void (APIENTRYP PFNGLVIEWPORTSWIZZLENVPROC) (GLuint index, GLenum swizzlex, GLenum swizzley, GLenum swizzlez, GLenum swizzlew);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glViewportSwizzleNV (GLuint index, GLenum swizzlex, GLenum swizzley, GLenum swizzlez, GLenum swizzlew);
+#endif
+#endif /* GL_NV_viewport_swizzle */
+
+#ifndef GL_OML_interlace
+#define GL_OML_interlace 1
+#define GL_INTERLACE_OML                  0x8980
+#define GL_INTERLACE_READ_OML             0x8981
+#endif /* GL_OML_interlace */
+
+#ifndef GL_OML_resample
+#define GL_OML_resample 1
+#define GL_PACK_RESAMPLE_OML              0x8984
+#define GL_UNPACK_RESAMPLE_OML            0x8985
+#define GL_RESAMPLE_REPLICATE_OML         0x8986
+#define GL_RESAMPLE_ZERO_FILL_OML         0x8987
+#define GL_RESAMPLE_AVERAGE_OML           0x8988
+#define GL_RESAMPLE_DECIMATE_OML          0x8989
+#endif /* GL_OML_resample */
+
+#ifndef GL_OML_subsample
+#define GL_OML_subsample 1
+#define GL_FORMAT_SUBSAMPLE_24_24_OML     0x8982
+#define GL_FORMAT_SUBSAMPLE_244_244_OML   0x8983
+#endif /* GL_OML_subsample */
+
+#ifndef GL_OVR_multiview
+#define GL_OVR_multiview 1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632
+#define GL_MAX_VIEWS_OVR                  0x9631
+#define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR 0x9633
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFramebufferTextureMultiviewOVR (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
+#endif
+#endif /* GL_OVR_multiview */
+
+#ifndef GL_OVR_multiview2
+#define GL_OVR_multiview2 1
+#endif /* GL_OVR_multiview2 */
+
+#ifndef GL_PGI_misc_hints
+#define GL_PGI_misc_hints 1
+#define GL_PREFER_DOUBLEBUFFER_HINT_PGI   0x1A1F8
+#define GL_CONSERVE_MEMORY_HINT_PGI       0x1A1FD
+#define GL_RECLAIM_MEMORY_HINT_PGI        0x1A1FE
+#define GL_NATIVE_GRAPHICS_HANDLE_PGI     0x1A202
+#define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203
+#define GL_NATIVE_GRAPHICS_END_HINT_PGI   0x1A204
+#define GL_ALWAYS_FAST_HINT_PGI           0x1A20C
+#define GL_ALWAYS_SOFT_HINT_PGI           0x1A20D
+#define GL_ALLOW_DRAW_OBJ_HINT_PGI        0x1A20E
+#define GL_ALLOW_DRAW_WIN_HINT_PGI        0x1A20F
+#define GL_ALLOW_DRAW_FRG_HINT_PGI        0x1A210
+#define GL_ALLOW_DRAW_MEM_HINT_PGI        0x1A211
+#define GL_STRICT_DEPTHFUNC_HINT_PGI      0x1A216
+#define GL_STRICT_LIGHTING_HINT_PGI       0x1A217
+#define GL_STRICT_SCISSOR_HINT_PGI        0x1A218
+#define GL_FULL_STIPPLE_HINT_PGI          0x1A219
+#define GL_CLIP_NEAR_HINT_PGI             0x1A220
+#define GL_CLIP_FAR_HINT_PGI              0x1A221
+#define GL_WIDE_LINE_HINT_PGI             0x1A222
+#define GL_BACK_NORMALS_HINT_PGI          0x1A223
+typedef void (APIENTRYP PFNGLHINTPGIPROC) (GLenum target, GLint mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glHintPGI (GLenum target, GLint mode);
+#endif
+#endif /* GL_PGI_misc_hints */
+
+#ifndef GL_PGI_vertex_hints
+#define GL_PGI_vertex_hints 1
+#define GL_VERTEX_DATA_HINT_PGI           0x1A22A
+#define GL_VERTEX_CONSISTENT_HINT_PGI     0x1A22B
+#define GL_MATERIAL_SIDE_HINT_PGI         0x1A22C
+#define GL_MAX_VERTEX_HINT_PGI            0x1A22D
+#define GL_COLOR3_BIT_PGI                 0x00010000
+#define GL_COLOR4_BIT_PGI                 0x00020000
+#define GL_EDGEFLAG_BIT_PGI               0x00040000
+#define GL_INDEX_BIT_PGI                  0x00080000
+#define GL_MAT_AMBIENT_BIT_PGI            0x00100000
+#define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000
+#define GL_MAT_DIFFUSE_BIT_PGI            0x00400000
+#define GL_MAT_EMISSION_BIT_PGI           0x00800000
+#define GL_MAT_COLOR_INDEXES_BIT_PGI      0x01000000
+#define GL_MAT_SHININESS_BIT_PGI          0x02000000
+#define GL_MAT_SPECULAR_BIT_PGI           0x04000000
+#define GL_NORMAL_BIT_PGI                 0x08000000
+#define GL_TEXCOORD1_BIT_PGI              0x10000000
+#define GL_TEXCOORD2_BIT_PGI              0x20000000
+#define GL_TEXCOORD3_BIT_PGI              0x40000000
+#define GL_TEXCOORD4_BIT_PGI              0x80000000
+#define GL_VERTEX23_BIT_PGI               0x00000004
+#define GL_VERTEX4_BIT_PGI                0x00000008
+#endif /* GL_PGI_vertex_hints */
+
+#ifndef GL_REND_screen_coordinates
+#define GL_REND_screen_coordinates 1
+#define GL_SCREEN_COORDINATES_REND        0x8490
+#define GL_INVERTED_SCREEN_W_REND         0x8491
+#endif /* GL_REND_screen_coordinates */
+
+#ifndef GL_S3_s3tc
+#define GL_S3_s3tc 1
+#define GL_RGB_S3TC                       0x83A0
+#define GL_RGB4_S3TC                      0x83A1
+#define GL_RGBA_S3TC                      0x83A2
+#define GL_RGBA4_S3TC                     0x83A3
+#define GL_RGBA_DXT5_S3TC                 0x83A4
+#define GL_RGBA4_DXT5_S3TC                0x83A5
+#endif /* GL_S3_s3tc */
+
+#ifndef GL_SGIS_detail_texture
+#define GL_SGIS_detail_texture 1
+#define GL_DETAIL_TEXTURE_2D_SGIS         0x8095
+#define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096
+#define GL_LINEAR_DETAIL_SGIS             0x8097
+#define GL_LINEAR_DETAIL_ALPHA_SGIS       0x8098
+#define GL_LINEAR_DETAIL_COLOR_SGIS       0x8099
+#define GL_DETAIL_TEXTURE_LEVEL_SGIS      0x809A
+#define GL_DETAIL_TEXTURE_MODE_SGIS       0x809B
+#define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C
+typedef void (APIENTRYP PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points);
+typedef void (APIENTRYP PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDetailTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points);
+GLAPI void APIENTRY glGetDetailTexFuncSGIS (GLenum target, GLfloat *points);
+#endif
+#endif /* GL_SGIS_detail_texture */
+
+#ifndef GL_SGIS_fog_function
+#define GL_SGIS_fog_function 1
+#define GL_FOG_FUNC_SGIS                  0x812A
+#define GL_FOG_FUNC_POINTS_SGIS           0x812B
+#define GL_MAX_FOG_FUNC_POINTS_SGIS       0x812C
+typedef void (APIENTRYP PFNGLFOGFUNCSGISPROC) (GLsizei n, const GLfloat *points);
+typedef void (APIENTRYP PFNGLGETFOGFUNCSGISPROC) (GLfloat *points);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFogFuncSGIS (GLsizei n, const GLfloat *points);
+GLAPI void APIENTRY glGetFogFuncSGIS (GLfloat *points);
+#endif
+#endif /* GL_SGIS_fog_function */
+
+#ifndef GL_SGIS_generate_mipmap
+#define GL_SGIS_generate_mipmap 1
+#define GL_GENERATE_MIPMAP_SGIS           0x8191
+#define GL_GENERATE_MIPMAP_HINT_SGIS      0x8192
+#endif /* GL_SGIS_generate_mipmap */
+
+#ifndef GL_SGIS_multisample
+#define GL_SGIS_multisample 1
+#define GL_MULTISAMPLE_SGIS               0x809D
+#define GL_SAMPLE_ALPHA_TO_MASK_SGIS      0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_SGIS       0x809F
+#define GL_SAMPLE_MASK_SGIS               0x80A0
+#define GL_1PASS_SGIS                     0x80A1
+#define GL_2PASS_0_SGIS                   0x80A2
+#define GL_2PASS_1_SGIS                   0x80A3
+#define GL_4PASS_0_SGIS                   0x80A4
+#define GL_4PASS_1_SGIS                   0x80A5
+#define GL_4PASS_2_SGIS                   0x80A6
+#define GL_4PASS_3_SGIS                   0x80A7
+#define GL_SAMPLE_BUFFERS_SGIS            0x80A8
+#define GL_SAMPLES_SGIS                   0x80A9
+#define GL_SAMPLE_MASK_VALUE_SGIS         0x80AA
+#define GL_SAMPLE_MASK_INVERT_SGIS        0x80AB
+#define GL_SAMPLE_PATTERN_SGIS            0x80AC
+typedef void (APIENTRYP PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert);
+typedef void (APIENTRYP PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSampleMaskSGIS (GLclampf value, GLboolean invert);
+GLAPI void APIENTRY glSamplePatternSGIS (GLenum pattern);
+#endif
+#endif /* GL_SGIS_multisample */
+
+#ifndef GL_SGIS_pixel_texture
+#define GL_SGIS_pixel_texture 1
+#define GL_PIXEL_TEXTURE_SGIS             0x8353
+#define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354
+#define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355
+#define GL_PIXEL_GROUP_COLOR_SGIS         0x8356
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelTexGenParameteriSGIS (GLenum pname, GLint param);
+GLAPI void APIENTRY glPixelTexGenParameterivSGIS (GLenum pname, const GLint *params);
+GLAPI void APIENTRY glPixelTexGenParameterfSGIS (GLenum pname, GLfloat param);
+GLAPI void APIENTRY glPixelTexGenParameterfvSGIS (GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glGetPixelTexGenParameterivSGIS (GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetPixelTexGenParameterfvSGIS (GLenum pname, GLfloat *params);
+#endif
+#endif /* GL_SGIS_pixel_texture */
+
+#ifndef GL_SGIS_point_line_texgen
+#define GL_SGIS_point_line_texgen 1
+#define GL_EYE_DISTANCE_TO_POINT_SGIS     0x81F0
+#define GL_OBJECT_DISTANCE_TO_POINT_SGIS  0x81F1
+#define GL_EYE_DISTANCE_TO_LINE_SGIS      0x81F2
+#define GL_OBJECT_DISTANCE_TO_LINE_SGIS   0x81F3
+#define GL_EYE_POINT_SGIS                 0x81F4
+#define GL_OBJECT_POINT_SGIS              0x81F5
+#define GL_EYE_LINE_SGIS                  0x81F6
+#define GL_OBJECT_LINE_SGIS               0x81F7
+#endif /* GL_SGIS_point_line_texgen */
+
+#ifndef GL_SGIS_point_parameters
+#define GL_SGIS_point_parameters 1
+#define GL_POINT_SIZE_MIN_SGIS            0x8126
+#define GL_POINT_SIZE_MAX_SGIS            0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128
+#define GL_DISTANCE_ATTENUATION_SGIS      0x8129
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFSGISPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameterfSGIS (GLenum pname, GLfloat param);
+GLAPI void APIENTRY glPointParameterfvSGIS (GLenum pname, const GLfloat *params);
+#endif
+#endif /* GL_SGIS_point_parameters */
+
+#ifndef GL_SGIS_sharpen_texture
+#define GL_SGIS_sharpen_texture 1
+#define GL_LINEAR_SHARPEN_SGIS            0x80AD
+#define GL_LINEAR_SHARPEN_ALPHA_SGIS      0x80AE
+#define GL_LINEAR_SHARPEN_COLOR_SGIS      0x80AF
+#define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0
+typedef void (APIENTRYP PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points);
+typedef void (APIENTRYP PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSharpenTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points);
+GLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum target, GLfloat *points);
+#endif
+#endif /* GL_SGIS_sharpen_texture */
+
+#ifndef GL_SGIS_texture4D
+#define GL_SGIS_texture4D 1
+#define GL_PACK_SKIP_VOLUMES_SGIS         0x8130
+#define GL_PACK_IMAGE_DEPTH_SGIS          0x8131
+#define GL_UNPACK_SKIP_VOLUMES_SGIS       0x8132
+#define GL_UNPACK_IMAGE_DEPTH_SGIS        0x8133
+#define GL_TEXTURE_4D_SGIS                0x8134
+#define GL_PROXY_TEXTURE_4D_SGIS          0x8135
+#define GL_TEXTURE_4DSIZE_SGIS            0x8136
+#define GL_TEXTURE_WRAP_Q_SGIS            0x8137
+#define GL_MAX_4D_TEXTURE_SIZE_SGIS       0x8138
+#define GL_TEXTURE_4D_BINDING_SGIS        0x814F
+typedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const void *pixels);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexImage4DSGIS (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void APIENTRY glTexSubImage4DSGIS (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const void *pixels);
+#endif
+#endif /* GL_SGIS_texture4D */
+
+#ifndef GL_SGIS_texture_border_clamp
+#define GL_SGIS_texture_border_clamp 1
+#define GL_CLAMP_TO_BORDER_SGIS           0x812D
+#endif /* GL_SGIS_texture_border_clamp */
+
+#ifndef GL_SGIS_texture_color_mask
+#define GL_SGIS_texture_color_mask 1
+#define GL_TEXTURE_COLOR_WRITEMASK_SGIS   0x81EF
+typedef void (APIENTRYP PFNGLTEXTURECOLORMASKSGISPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTextureColorMaskSGIS (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+#endif
+#endif /* GL_SGIS_texture_color_mask */
+
+#ifndef GL_SGIS_texture_edge_clamp
+#define GL_SGIS_texture_edge_clamp 1
+#define GL_CLAMP_TO_EDGE_SGIS             0x812F
+#endif /* GL_SGIS_texture_edge_clamp */
+
+#ifndef GL_SGIS_texture_filter4
+#define GL_SGIS_texture_filter4 1
+#define GL_FILTER4_SGIS                   0x8146
+#define GL_TEXTURE_FILTER4_SIZE_SGIS      0x8147
+typedef void (APIENTRYP PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights);
+typedef void (APIENTRYP PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetTexFilterFuncSGIS (GLenum target, GLenum filter, GLfloat *weights);
+GLAPI void APIENTRY glTexFilterFuncSGIS (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights);
+#endif
+#endif /* GL_SGIS_texture_filter4 */
+
+#ifndef GL_SGIS_texture_lod
+#define GL_SGIS_texture_lod 1
+#define GL_TEXTURE_MIN_LOD_SGIS           0x813A
+#define GL_TEXTURE_MAX_LOD_SGIS           0x813B
+#define GL_TEXTURE_BASE_LEVEL_SGIS        0x813C
+#define GL_TEXTURE_MAX_LEVEL_SGIS         0x813D
+#endif /* GL_SGIS_texture_lod */
+
+#ifndef GL_SGIS_texture_select
+#define GL_SGIS_texture_select 1
+#define GL_DUAL_ALPHA4_SGIS               0x8110
+#define GL_DUAL_ALPHA8_SGIS               0x8111
+#define GL_DUAL_ALPHA12_SGIS              0x8112
+#define GL_DUAL_ALPHA16_SGIS              0x8113
+#define GL_DUAL_LUMINANCE4_SGIS           0x8114
+#define GL_DUAL_LUMINANCE8_SGIS           0x8115
+#define GL_DUAL_LUMINANCE12_SGIS          0x8116
+#define GL_DUAL_LUMINANCE16_SGIS          0x8117
+#define GL_DUAL_INTENSITY4_SGIS           0x8118
+#define GL_DUAL_INTENSITY8_SGIS           0x8119
+#define GL_DUAL_INTENSITY12_SGIS          0x811A
+#define GL_DUAL_INTENSITY16_SGIS          0x811B
+#define GL_DUAL_LUMINANCE_ALPHA4_SGIS     0x811C
+#define GL_DUAL_LUMINANCE_ALPHA8_SGIS     0x811D
+#define GL_QUAD_ALPHA4_SGIS               0x811E
+#define GL_QUAD_ALPHA8_SGIS               0x811F
+#define GL_QUAD_LUMINANCE4_SGIS           0x8120
+#define GL_QUAD_LUMINANCE8_SGIS           0x8121
+#define GL_QUAD_INTENSITY4_SGIS           0x8122
+#define GL_QUAD_INTENSITY8_SGIS           0x8123
+#define GL_DUAL_TEXTURE_SELECT_SGIS       0x8124
+#define GL_QUAD_TEXTURE_SELECT_SGIS       0x8125
+#endif /* GL_SGIS_texture_select */
+
+#ifndef GL_SGIX_async
+#define GL_SGIX_async 1
+#define GL_ASYNC_MARKER_SGIX              0x8329
+typedef void (APIENTRYP PFNGLASYNCMARKERSGIXPROC) (GLuint marker);
+typedef GLint (APIENTRYP PFNGLFINISHASYNCSGIXPROC) (GLuint *markerp);
+typedef GLint (APIENTRYP PFNGLPOLLASYNCSGIXPROC) (GLuint *markerp);
+typedef GLuint (APIENTRYP PFNGLGENASYNCMARKERSSGIXPROC) (GLsizei range);
+typedef void (APIENTRYP PFNGLDELETEASYNCMARKERSSGIXPROC) (GLuint marker, GLsizei range);
+typedef GLboolean (APIENTRYP PFNGLISASYNCMARKERSGIXPROC) (GLuint marker);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glAsyncMarkerSGIX (GLuint marker);
+GLAPI GLint APIENTRY glFinishAsyncSGIX (GLuint *markerp);
+GLAPI GLint APIENTRY glPollAsyncSGIX (GLuint *markerp);
+GLAPI GLuint APIENTRY glGenAsyncMarkersSGIX (GLsizei range);
+GLAPI void APIENTRY glDeleteAsyncMarkersSGIX (GLuint marker, GLsizei range);
+GLAPI GLboolean APIENTRY glIsAsyncMarkerSGIX (GLuint marker);
+#endif
+#endif /* GL_SGIX_async */
+
+#ifndef GL_SGIX_async_histogram
+#define GL_SGIX_async_histogram 1
+#define GL_ASYNC_HISTOGRAM_SGIX           0x832C
+#define GL_MAX_ASYNC_HISTOGRAM_SGIX       0x832D
+#endif /* GL_SGIX_async_histogram */
+
+#ifndef GL_SGIX_async_pixel
+#define GL_SGIX_async_pixel 1
+#define GL_ASYNC_TEX_IMAGE_SGIX           0x835C
+#define GL_ASYNC_DRAW_PIXELS_SGIX         0x835D
+#define GL_ASYNC_READ_PIXELS_SGIX         0x835E
+#define GL_MAX_ASYNC_TEX_IMAGE_SGIX       0x835F
+#define GL_MAX_ASYNC_DRAW_PIXELS_SGIX     0x8360
+#define GL_MAX_ASYNC_READ_PIXELS_SGIX     0x8361
+#endif /* GL_SGIX_async_pixel */
+
+#ifndef GL_SGIX_blend_alpha_minmax
+#define GL_SGIX_blend_alpha_minmax 1
+#define GL_ALPHA_MIN_SGIX                 0x8320
+#define GL_ALPHA_MAX_SGIX                 0x8321
+#endif /* GL_SGIX_blend_alpha_minmax */
+
+#ifndef GL_SGIX_calligraphic_fragment
+#define GL_SGIX_calligraphic_fragment 1
+#define GL_CALLIGRAPHIC_FRAGMENT_SGIX     0x8183
+#endif /* GL_SGIX_calligraphic_fragment */
+
+#ifndef GL_SGIX_clipmap
+#define GL_SGIX_clipmap 1
+#define GL_LINEAR_CLIPMAP_LINEAR_SGIX     0x8170
+#define GL_TEXTURE_CLIPMAP_CENTER_SGIX    0x8171
+#define GL_TEXTURE_CLIPMAP_FRAME_SGIX     0x8172
+#define GL_TEXTURE_CLIPMAP_OFFSET_SGIX    0x8173
+#define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174
+#define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175
+#define GL_TEXTURE_CLIPMAP_DEPTH_SGIX     0x8176
+#define GL_MAX_CLIPMAP_DEPTH_SGIX         0x8177
+#define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178
+#define GL_NEAREST_CLIPMAP_NEAREST_SGIX   0x844D
+#define GL_NEAREST_CLIPMAP_LINEAR_SGIX    0x844E
+#define GL_LINEAR_CLIPMAP_NEAREST_SGIX    0x844F
+#endif /* GL_SGIX_clipmap */
+
+#ifndef GL_SGIX_convolution_accuracy
+#define GL_SGIX_convolution_accuracy 1
+#define GL_CONVOLUTION_HINT_SGIX          0x8316
+#endif /* GL_SGIX_convolution_accuracy */
+
+#ifndef GL_SGIX_depth_pass_instrument
+#define GL_SGIX_depth_pass_instrument 1
+#endif /* GL_SGIX_depth_pass_instrument */
+
+#ifndef GL_SGIX_depth_texture
+#define GL_SGIX_depth_texture 1
+#define GL_DEPTH_COMPONENT16_SGIX         0x81A5
+#define GL_DEPTH_COMPONENT24_SGIX         0x81A6
+#define GL_DEPTH_COMPONENT32_SGIX         0x81A7
+#endif /* GL_SGIX_depth_texture */
+
+#ifndef GL_SGIX_flush_raster
+#define GL_SGIX_flush_raster 1
+typedef void (APIENTRYP PFNGLFLUSHRASTERSGIXPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFlushRasterSGIX (void);
+#endif
+#endif /* GL_SGIX_flush_raster */
+
+#ifndef GL_SGIX_fog_offset
+#define GL_SGIX_fog_offset 1
+#define GL_FOG_OFFSET_SGIX                0x8198
+#define GL_FOG_OFFSET_VALUE_SGIX          0x8199
+#endif /* GL_SGIX_fog_offset */
+
+#ifndef GL_SGIX_fragment_lighting
+#define GL_SGIX_fragment_lighting 1
+#define GL_FRAGMENT_LIGHTING_SGIX         0x8400
+#define GL_FRAGMENT_COLOR_MATERIAL_SGIX   0x8401
+#define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402
+#define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403
+#define GL_MAX_FRAGMENT_LIGHTS_SGIX       0x8404
+#define GL_MAX_ACTIVE_LIGHTS_SGIX         0x8405
+#define GL_CURRENT_RASTER_NORMAL_SGIX     0x8406
+#define GL_LIGHT_ENV_MODE_SGIX            0x8407
+#define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408
+#define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409
+#define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A
+#define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B
+#define GL_FRAGMENT_LIGHT0_SGIX           0x840C
+#define GL_FRAGMENT_LIGHT1_SGIX           0x840D
+#define GL_FRAGMENT_LIGHT2_SGIX           0x840E
+#define GL_FRAGMENT_LIGHT3_SGIX           0x840F
+#define GL_FRAGMENT_LIGHT4_SGIX           0x8410
+#define GL_FRAGMENT_LIGHT5_SGIX           0x8411
+#define GL_FRAGMENT_LIGHT6_SGIX           0x8412
+#define GL_FRAGMENT_LIGHT7_SGIX           0x8413
+typedef void (APIENTRYP PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFragmentColorMaterialSGIX (GLenum face, GLenum mode);
+GLAPI void APIENTRY glFragmentLightfSGIX (GLenum light, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glFragmentLightfvSGIX (GLenum light, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glFragmentLightiSGIX (GLenum light, GLenum pname, GLint param);
+GLAPI void APIENTRY glFragmentLightivSGIX (GLenum light, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glFragmentLightModelfSGIX (GLenum pname, GLfloat param);
+GLAPI void APIENTRY glFragmentLightModelfvSGIX (GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glFragmentLightModeliSGIX (GLenum pname, GLint param);
+GLAPI void APIENTRY glFragmentLightModelivSGIX (GLenum pname, const GLint *params);
+GLAPI void APIENTRY glFragmentMaterialfSGIX (GLenum face, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glFragmentMaterialfvSGIX (GLenum face, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glFragmentMaterialiSGIX (GLenum face, GLenum pname, GLint param);
+GLAPI void APIENTRY glFragmentMaterialivSGIX (GLenum face, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glGetFragmentLightfvSGIX (GLenum light, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetFragmentLightivSGIX (GLenum light, GLenum pname, GLint *params);
+GLAPI void APIENTRY glGetFragmentMaterialfvSGIX (GLenum face, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetFragmentMaterialivSGIX (GLenum face, GLenum pname, GLint *params);
+GLAPI void APIENTRY glLightEnviSGIX (GLenum pname, GLint param);
+#endif
+#endif /* GL_SGIX_fragment_lighting */
+
+#ifndef GL_SGIX_framezoom
+#define GL_SGIX_framezoom 1
+#define GL_FRAMEZOOM_SGIX                 0x818B
+#define GL_FRAMEZOOM_FACTOR_SGIX          0x818C
+#define GL_MAX_FRAMEZOOM_FACTOR_SGIX      0x818D
+typedef void (APIENTRYP PFNGLFRAMEZOOMSGIXPROC) (GLint factor);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFrameZoomSGIX (GLint factor);
+#endif
+#endif /* GL_SGIX_framezoom */
+
+#ifndef GL_SGIX_igloo_interface
+#define GL_SGIX_igloo_interface 1
+typedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const void *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glIglooInterfaceSGIX (GLenum pname, const void *params);
+#endif
+#endif /* GL_SGIX_igloo_interface */
+
+#ifndef GL_SGIX_instruments
+#define GL_SGIX_instruments 1
+#define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180
+#define GL_INSTRUMENT_MEASUREMENTS_SGIX   0x8181
+typedef GLint (APIENTRYP PFNGLGETINSTRUMENTSSGIXPROC) (void);
+typedef void (APIENTRYP PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buffer);
+typedef GLint (APIENTRYP PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *marker_p);
+typedef void (APIENTRYP PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker);
+typedef void (APIENTRYP PFNGLSTARTINSTRUMENTSSGIXPROC) (void);
+typedef void (APIENTRYP PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLint APIENTRY glGetInstrumentsSGIX (void);
+GLAPI void APIENTRY glInstrumentsBufferSGIX (GLsizei size, GLint *buffer);
+GLAPI GLint APIENTRY glPollInstrumentsSGIX (GLint *marker_p);
+GLAPI void APIENTRY glReadInstrumentsSGIX (GLint marker);
+GLAPI void APIENTRY glStartInstrumentsSGIX (void);
+GLAPI void APIENTRY glStopInstrumentsSGIX (GLint marker);
+#endif
+#endif /* GL_SGIX_instruments */
+
+#ifndef GL_SGIX_interlace
+#define GL_SGIX_interlace 1
+#define GL_INTERLACE_SGIX                 0x8094
+#endif /* GL_SGIX_interlace */
+
+#ifndef GL_SGIX_ir_instrument1
+#define GL_SGIX_ir_instrument1 1
+#define GL_IR_INSTRUMENT1_SGIX            0x817F
+#endif /* GL_SGIX_ir_instrument1 */
+
+#ifndef GL_SGIX_list_priority
+#define GL_SGIX_list_priority 1
+#define GL_LIST_PRIORITY_SGIX             0x8182
+typedef void (APIENTRYP PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, const GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetListParameterfvSGIX (GLuint list, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetListParameterivSGIX (GLuint list, GLenum pname, GLint *params);
+GLAPI void APIENTRY glListParameterfSGIX (GLuint list, GLenum pname, GLfloat param);
+GLAPI void APIENTRY glListParameterfvSGIX (GLuint list, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glListParameteriSGIX (GLuint list, GLenum pname, GLint param);
+GLAPI void APIENTRY glListParameterivSGIX (GLuint list, GLenum pname, const GLint *params);
+#endif
+#endif /* GL_SGIX_list_priority */
+
+#ifndef GL_SGIX_pixel_texture
+#define GL_SGIX_pixel_texture 1
+#define GL_PIXEL_TEX_GEN_SGIX             0x8139
+#define GL_PIXEL_TEX_GEN_MODE_SGIX        0x832B
+typedef void (APIENTRYP PFNGLPIXELTEXGENSGIXPROC) (GLenum mode);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelTexGenSGIX (GLenum mode);
+#endif
+#endif /* GL_SGIX_pixel_texture */
+
+#ifndef GL_SGIX_pixel_tiles
+#define GL_SGIX_pixel_tiles 1
+#define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E
+#define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F
+#define GL_PIXEL_TILE_WIDTH_SGIX          0x8140
+#define GL_PIXEL_TILE_HEIGHT_SGIX         0x8141
+#define GL_PIXEL_TILE_GRID_WIDTH_SGIX     0x8142
+#define GL_PIXEL_TILE_GRID_HEIGHT_SGIX    0x8143
+#define GL_PIXEL_TILE_GRID_DEPTH_SGIX     0x8144
+#define GL_PIXEL_TILE_CACHE_SIZE_SGIX     0x8145
+#endif /* GL_SGIX_pixel_tiles */
+
+#ifndef GL_SGIX_polynomial_ffd
+#define GL_SGIX_polynomial_ffd 1
+#define GL_TEXTURE_DEFORMATION_BIT_SGIX   0x00000001
+#define GL_GEOMETRY_DEFORMATION_BIT_SGIX  0x00000002
+#define GL_GEOMETRY_DEFORMATION_SGIX      0x8194
+#define GL_TEXTURE_DEFORMATION_SGIX       0x8195
+#define GL_DEFORMATIONS_MASK_SGIX         0x8196
+#define GL_MAX_DEFORMATION_ORDER_SGIX     0x8197
+typedef void (APIENTRYP PFNGLDEFORMATIONMAP3DSGIXPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points);
+typedef void (APIENTRYP PFNGLDEFORMATIONMAP3FSGIXPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points);
+typedef void (APIENTRYP PFNGLDEFORMSGIXPROC) (GLbitfield mask);
+typedef void (APIENTRYP PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC) (GLbitfield mask);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDeformationMap3dSGIX (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points);
+GLAPI void APIENTRY glDeformationMap3fSGIX (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points);
+GLAPI void APIENTRY glDeformSGIX (GLbitfield mask);
+GLAPI void APIENTRY glLoadIdentityDeformationMapSGIX (GLbitfield mask);
+#endif
+#endif /* GL_SGIX_polynomial_ffd */
+
+#ifndef GL_SGIX_reference_plane
+#define GL_SGIX_reference_plane 1
+#define GL_REFERENCE_PLANE_SGIX           0x817D
+#define GL_REFERENCE_PLANE_EQUATION_SGIX  0x817E
+typedef void (APIENTRYP PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *equation);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glReferencePlaneSGIX (const GLdouble *equation);
+#endif
+#endif /* GL_SGIX_reference_plane */
+
+#ifndef GL_SGIX_resample
+#define GL_SGIX_resample 1
+#define GL_PACK_RESAMPLE_SGIX             0x842E
+#define GL_UNPACK_RESAMPLE_SGIX           0x842F
+#define GL_RESAMPLE_REPLICATE_SGIX        0x8433
+#define GL_RESAMPLE_ZERO_FILL_SGIX        0x8434
+#define GL_RESAMPLE_DECIMATE_SGIX         0x8430
+#endif /* GL_SGIX_resample */
+
+#ifndef GL_SGIX_scalebias_hint
+#define GL_SGIX_scalebias_hint 1
+#define GL_SCALEBIAS_HINT_SGIX            0x8322
+#endif /* GL_SGIX_scalebias_hint */
+
+#ifndef GL_SGIX_shadow
+#define GL_SGIX_shadow 1
+#define GL_TEXTURE_COMPARE_SGIX           0x819A
+#define GL_TEXTURE_COMPARE_OPERATOR_SGIX  0x819B
+#define GL_TEXTURE_LEQUAL_R_SGIX          0x819C
+#define GL_TEXTURE_GEQUAL_R_SGIX          0x819D
+#endif /* GL_SGIX_shadow */
+
+#ifndef GL_SGIX_shadow_ambient
+#define GL_SGIX_shadow_ambient 1
+#define GL_SHADOW_AMBIENT_SGIX            0x80BF
+#endif /* GL_SGIX_shadow_ambient */
+
+#ifndef GL_SGIX_sprite
+#define GL_SGIX_sprite 1
+#define GL_SPRITE_SGIX                    0x8148
+#define GL_SPRITE_MODE_SGIX               0x8149
+#define GL_SPRITE_AXIS_SGIX               0x814A
+#define GL_SPRITE_TRANSLATION_SGIX        0x814B
+#define GL_SPRITE_AXIAL_SGIX              0x814C
+#define GL_SPRITE_OBJECT_ALIGNED_SGIX     0x814D
+#define GL_SPRITE_EYE_ALIGNED_SGIX        0x814E
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSpriteParameterfSGIX (GLenum pname, GLfloat param);
+GLAPI void APIENTRY glSpriteParameterfvSGIX (GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glSpriteParameteriSGIX (GLenum pname, GLint param);
+GLAPI void APIENTRY glSpriteParameterivSGIX (GLenum pname, const GLint *params);
+#endif
+#endif /* GL_SGIX_sprite */
+
+#ifndef GL_SGIX_subsample
+#define GL_SGIX_subsample 1
+#define GL_PACK_SUBSAMPLE_RATE_SGIX       0x85A0
+#define GL_UNPACK_SUBSAMPLE_RATE_SGIX     0x85A1
+#define GL_PIXEL_SUBSAMPLE_4444_SGIX      0x85A2
+#define GL_PIXEL_SUBSAMPLE_2424_SGIX      0x85A3
+#define GL_PIXEL_SUBSAMPLE_4242_SGIX      0x85A4
+#endif /* GL_SGIX_subsample */
+
+#ifndef GL_SGIX_tag_sample_buffer
+#define GL_SGIX_tag_sample_buffer 1
+typedef void (APIENTRYP PFNGLTAGSAMPLEBUFFERSGIXPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTagSampleBufferSGIX (void);
+#endif
+#endif /* GL_SGIX_tag_sample_buffer */
+
+#ifndef GL_SGIX_texture_add_env
+#define GL_SGIX_texture_add_env 1
+#define GL_TEXTURE_ENV_BIAS_SGIX          0x80BE
+#endif /* GL_SGIX_texture_add_env */
+
+#ifndef GL_SGIX_texture_coordinate_clamp
+#define GL_SGIX_texture_coordinate_clamp 1
+#define GL_TEXTURE_MAX_CLAMP_S_SGIX       0x8369
+#define GL_TEXTURE_MAX_CLAMP_T_SGIX       0x836A
+#define GL_TEXTURE_MAX_CLAMP_R_SGIX       0x836B
+#endif /* GL_SGIX_texture_coordinate_clamp */
+
+#ifndef GL_SGIX_texture_lod_bias
+#define GL_SGIX_texture_lod_bias 1
+#define GL_TEXTURE_LOD_BIAS_S_SGIX        0x818E
+#define GL_TEXTURE_LOD_BIAS_T_SGIX        0x818F
+#define GL_TEXTURE_LOD_BIAS_R_SGIX        0x8190
+#endif /* GL_SGIX_texture_lod_bias */
+
+#ifndef GL_SGIX_texture_multi_buffer
+#define GL_SGIX_texture_multi_buffer 1
+#define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E
+#endif /* GL_SGIX_texture_multi_buffer */
+
+#ifndef GL_SGIX_texture_scale_bias
+#define GL_SGIX_texture_scale_bias 1
+#define GL_POST_TEXTURE_FILTER_BIAS_SGIX  0x8179
+#define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A
+#define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B
+#define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C
+#endif /* GL_SGIX_texture_scale_bias */
+
+#ifndef GL_SGIX_vertex_preclip
+#define GL_SGIX_vertex_preclip 1
+#define GL_VERTEX_PRECLIP_SGIX            0x83EE
+#define GL_VERTEX_PRECLIP_HINT_SGIX       0x83EF
+#endif /* GL_SGIX_vertex_preclip */
+
+#ifndef GL_SGIX_ycrcb
+#define GL_SGIX_ycrcb 1
+#define GL_YCRCB_422_SGIX                 0x81BB
+#define GL_YCRCB_444_SGIX                 0x81BC
+#endif /* GL_SGIX_ycrcb */
+
+#ifndef GL_SGIX_ycrcb_subsample
+#define GL_SGIX_ycrcb_subsample 1
+#endif /* GL_SGIX_ycrcb_subsample */
+
+#ifndef GL_SGIX_ycrcba
+#define GL_SGIX_ycrcba 1
+#define GL_YCRCB_SGIX                     0x8318
+#define GL_YCRCBA_SGIX                    0x8319
+#endif /* GL_SGIX_ycrcba */
+
+#ifndef GL_SGI_color_matrix
+#define GL_SGI_color_matrix 1
+#define GL_COLOR_MATRIX_SGI               0x80B1
+#define GL_COLOR_MATRIX_STACK_DEPTH_SGI   0x80B2
+#define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3
+#define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4
+#define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5
+#define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6
+#define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7
+#define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8
+#define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9
+#define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA
+#define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB
+#endif /* GL_SGI_color_matrix */
+
+#ifndef GL_SGI_color_table
+#define GL_SGI_color_table 1
+#define GL_COLOR_TABLE_SGI                0x80D0
+#define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1
+#define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2
+#define GL_PROXY_COLOR_TABLE_SGI          0x80D3
+#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4
+#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5
+#define GL_COLOR_TABLE_SCALE_SGI          0x80D6
+#define GL_COLOR_TABLE_BIAS_SGI           0x80D7
+#define GL_COLOR_TABLE_FORMAT_SGI         0x80D8
+#define GL_COLOR_TABLE_WIDTH_SGI          0x80D9
+#define GL_COLOR_TABLE_RED_SIZE_SGI       0x80DA
+#define GL_COLOR_TABLE_GREEN_SIZE_SGI     0x80DB
+#define GL_COLOR_TABLE_BLUE_SIZE_SGI      0x80DC
+#define GL_COLOR_TABLE_ALPHA_SIZE_SGI     0x80DD
+#define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE
+#define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF
+typedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, void *table);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorTableSGI (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table);
+GLAPI void APIENTRY glColorTableParameterfvSGI (GLenum target, GLenum pname, const GLfloat *params);
+GLAPI void APIENTRY glColorTableParameterivSGI (GLenum target, GLenum pname, const GLint *params);
+GLAPI void APIENTRY glCopyColorTableSGI (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+GLAPI void APIENTRY glGetColorTableSGI (GLenum target, GLenum format, GLenum type, void *table);
+GLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum target, GLenum pname, GLfloat *params);
+GLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum target, GLenum pname, GLint *params);
+#endif
+#endif /* GL_SGI_color_table */
+
+#ifndef GL_SGI_texture_color_table
+#define GL_SGI_texture_color_table 1
+#define GL_TEXTURE_COLOR_TABLE_SGI        0x80BC
+#define GL_PROXY_TEXTURE_COLOR_TABLE_SGI  0x80BD
+#endif /* GL_SGI_texture_color_table */
+
+#ifndef GL_SUNX_constant_data
+#define GL_SUNX_constant_data 1
+#define GL_UNPACK_CONSTANT_DATA_SUNX      0x81D5
+#define GL_TEXTURE_CONSTANT_DATA_SUNX     0x81D6
+typedef void (APIENTRYP PFNGLFINISHTEXTURESUNXPROC) (void);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFinishTextureSUNX (void);
+#endif
+#endif /* GL_SUNX_constant_data */
+
+#ifndef GL_SUN_convolution_border_modes
+#define GL_SUN_convolution_border_modes 1
+#define GL_WRAP_BORDER_SUN                0x81D4
+#endif /* GL_SUN_convolution_border_modes */
+
+#ifndef GL_SUN_global_alpha
+#define GL_SUN_global_alpha 1
+#define GL_GLOBAL_ALPHA_SUN               0x81D9
+#define GL_GLOBAL_ALPHA_FACTOR_SUN        0x81DA
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORBSUNPROC) (GLbyte factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORSSUNPROC) (GLshort factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORISUNPROC) (GLint factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORDSUNPROC) (GLdouble factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUBSUNPROC) (GLubyte factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUISUNPROC) (GLuint factor);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGlobalAlphaFactorbSUN (GLbyte factor);
+GLAPI void APIENTRY glGlobalAlphaFactorsSUN (GLshort factor);
+GLAPI void APIENTRY glGlobalAlphaFactoriSUN (GLint factor);
+GLAPI void APIENTRY glGlobalAlphaFactorfSUN (GLfloat factor);
+GLAPI void APIENTRY glGlobalAlphaFactordSUN (GLdouble factor);
+GLAPI void APIENTRY glGlobalAlphaFactorubSUN (GLubyte factor);
+GLAPI void APIENTRY glGlobalAlphaFactorusSUN (GLushort factor);
+GLAPI void APIENTRY glGlobalAlphaFactoruiSUN (GLuint factor);
+#endif
+#endif /* GL_SUN_global_alpha */
+
+#ifndef GL_SUN_mesh_array
+#define GL_SUN_mesh_array 1
+#define GL_QUAD_MESH_SUN                  0x8614
+#define GL_TRIANGLE_MESH_SUN              0x8615
+typedef void (APIENTRYP PFNGLDRAWMESHARRAYSSUNPROC) (GLenum mode, GLint first, GLsizei count, GLsizei width);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawMeshArraysSUN (GLenum mode, GLint first, GLsizei count, GLsizei width);
+#endif
+#endif /* GL_SUN_mesh_array */
+
+#ifndef GL_SUN_slice_accum
+#define GL_SUN_slice_accum 1
+#define GL_SLICE_ACCUM_SUN                0x85CC
+#endif /* GL_SUN_slice_accum */
+
+#ifndef GL_SUN_triangle_list
+#define GL_SUN_triangle_list 1
+#define GL_RESTART_SUN                    0x0001
+#define GL_REPLACE_MIDDLE_SUN             0x0002
+#define GL_REPLACE_OLDEST_SUN             0x0003
+#define GL_TRIANGLE_LIST_SUN              0x81D7
+#define GL_REPLACEMENT_CODE_SUN           0x81D8
+#define GL_REPLACEMENT_CODE_ARRAY_SUN     0x85C0
+#define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1
+#define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2
+#define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3
+#define GL_R1UI_V3F_SUN                   0x85C4
+#define GL_R1UI_C4UB_V3F_SUN              0x85C5
+#define GL_R1UI_C3F_V3F_SUN               0x85C6
+#define GL_R1UI_N3F_V3F_SUN               0x85C7
+#define GL_R1UI_C4F_N3F_V3F_SUN           0x85C8
+#define GL_R1UI_T2F_V3F_SUN               0x85C9
+#define GL_R1UI_T2F_N3F_V3F_SUN           0x85CA
+#define GL_R1UI_T2F_C4F_N3F_V3F_SUN       0x85CB
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSSUNPROC) (GLushort code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const void **pointer);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glReplacementCodeuiSUN (GLuint code);
+GLAPI void APIENTRY glReplacementCodeusSUN (GLushort code);
+GLAPI void APIENTRY glReplacementCodeubSUN (GLubyte code);
+GLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *code);
+GLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *code);
+GLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *code);
+GLAPI void APIENTRY glReplacementCodePointerSUN (GLenum type, GLsizei stride, const void **pointer);
+#endif
+#endif /* GL_SUN_triangle_list */
+
+#ifndef GL_SUN_vertex
+#define GL_SUN_vertex 1
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FVSUNPROC) (const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FVSUNPROC) (const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FSUNPROC) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC) (const GLfloat *tc, const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC) (GLuint rc, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC) (const GLuint *rc, const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColor4ubVertex2fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y);
+GLAPI void APIENTRY glColor4ubVertex2fvSUN (const GLubyte *c, const GLfloat *v);
+GLAPI void APIENTRY glColor4ubVertex3fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glColor4ubVertex3fvSUN (const GLubyte *c, const GLfloat *v);
+GLAPI void APIENTRY glColor3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glColor3fVertex3fvSUN (const GLfloat *c, const GLfloat *v);
+GLAPI void APIENTRY glNormal3fVertex3fSUN (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glNormal3fVertex3fvSUN (const GLfloat *n, const GLfloat *v);
+GLAPI void APIENTRY glColor4fNormal3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glColor4fNormal3fVertex3fvSUN (const GLfloat *c, const GLfloat *n, const GLfloat *v);
+GLAPI void APIENTRY glTexCoord2fVertex3fSUN (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glTexCoord2fVertex3fvSUN (const GLfloat *tc, const GLfloat *v);
+GLAPI void APIENTRY glTexCoord4fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glTexCoord4fVertex4fvSUN (const GLfloat *tc, const GLfloat *v);
+GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fSUN (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fvSUN (const GLfloat *tc, const GLubyte *c, const GLfloat *v);
+GLAPI void APIENTRY glTexCoord2fColor3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glTexCoord2fColor3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *v);
+GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *n, const GLfloat *v);
+GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+GLAPI void APIENTRY glReplacementCodeuiVertex3fSUN (GLuint rc, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glReplacementCodeuiVertex3fvSUN (const GLuint *rc, const GLfloat *v);
+GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fSUN (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *rc, const GLubyte *c, const GLfloat *v);
+GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *v);
+GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fSUN (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *n, const GLfloat *v);
+GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *v);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+#endif
+#endif /* GL_SUN_vertex */
+
+#ifndef GL_WIN_phong_shading
+#define GL_WIN_phong_shading 1
+#define GL_PHONG_WIN                      0x80EA
+#define GL_PHONG_HINT_WIN                 0x80EB
+#endif /* GL_WIN_phong_shading */
+
+#ifndef GL_WIN_specular_fog
+#define GL_WIN_specular_fog 1
+#define GL_FOG_SPECULAR_TEXTURE_WIN       0x80EC
+#endif /* GL_WIN_specular_fog */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/Irrlicht/glxext.h b/source/Irrlicht/glxext.h
new file mode 100644
index 00000000..30fcd73a
--- /dev/null
+++ b/source/Irrlicht/glxext.h
@@ -0,0 +1,960 @@
+#ifndef __glx_glxext_h_
+#define __glx_glxext_h_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright (c) 2013-2018 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+/*
+** This header is generated from the Khronos OpenGL / OpenGL ES XML
+** API Registry. The current version of the Registry, generator scripts
+** used to make the header, and the header can be found at
+**   https://github.com/KhronosGroup/OpenGL-Registry
+*/
+
+#define GLX_GLXEXT_VERSION 20190515
+
+/* Generated C header for:
+ * API: glx
+ * Versions considered: .*
+ * Versions emitted: 1\.[3-9]
+ * Default extensions included: glx
+ * Additional extensions included: _nomatch_^
+ * Extensions removed: _nomatch_^
+ */
+
+#ifndef GLX_VERSION_1_3
+#define GLX_VERSION_1_3 1
+typedef XID GLXContextID;
+typedef struct __GLXFBConfigRec *GLXFBConfig;
+typedef XID GLXWindow;
+typedef XID GLXPbuffer;
+#define GLX_WINDOW_BIT                    0x00000001
+#define GLX_PIXMAP_BIT                    0x00000002
+#define GLX_PBUFFER_BIT                   0x00000004
+#define GLX_RGBA_BIT                      0x00000001
+#define GLX_COLOR_INDEX_BIT               0x00000002
+#define GLX_PBUFFER_CLOBBER_MASK          0x08000000
+#define GLX_FRONT_LEFT_BUFFER_BIT         0x00000001
+#define GLX_FRONT_RIGHT_BUFFER_BIT        0x00000002
+#define GLX_BACK_LEFT_BUFFER_BIT          0x00000004
+#define GLX_BACK_RIGHT_BUFFER_BIT         0x00000008
+#define GLX_AUX_BUFFERS_BIT               0x00000010
+#define GLX_DEPTH_BUFFER_BIT              0x00000020
+#define GLX_STENCIL_BUFFER_BIT            0x00000040
+#define GLX_ACCUM_BUFFER_BIT              0x00000080
+#define GLX_CONFIG_CAVEAT                 0x20
+#define GLX_X_VISUAL_TYPE                 0x22
+#define GLX_TRANSPARENT_TYPE              0x23
+#define GLX_TRANSPARENT_INDEX_VALUE       0x24
+#define GLX_TRANSPARENT_RED_VALUE         0x25
+#define GLX_TRANSPARENT_GREEN_VALUE       0x26
+#define GLX_TRANSPARENT_BLUE_VALUE        0x27
+#define GLX_TRANSPARENT_ALPHA_VALUE       0x28
+#define GLX_DONT_CARE                     0xFFFFFFFF
+#define GLX_NONE                          0x8000
+#define GLX_SLOW_CONFIG                   0x8001
+#define GLX_TRUE_COLOR                    0x8002
+#define GLX_DIRECT_COLOR                  0x8003
+#define GLX_PSEUDO_COLOR                  0x8004
+#define GLX_STATIC_COLOR                  0x8005
+#define GLX_GRAY_SCALE                    0x8006
+#define GLX_STATIC_GRAY                   0x8007
+#define GLX_TRANSPARENT_RGB               0x8008
+#define GLX_TRANSPARENT_INDEX             0x8009
+#define GLX_VISUAL_ID                     0x800B
+#define GLX_SCREEN                        0x800C
+#define GLX_NON_CONFORMANT_CONFIG         0x800D
+#define GLX_DRAWABLE_TYPE                 0x8010
+#define GLX_RENDER_TYPE                   0x8011
+#define GLX_X_RENDERABLE                  0x8012
+#define GLX_FBCONFIG_ID                   0x8013
+#define GLX_RGBA_TYPE                     0x8014
+#define GLX_COLOR_INDEX_TYPE              0x8015
+#define GLX_MAX_PBUFFER_WIDTH             0x8016
+#define GLX_MAX_PBUFFER_HEIGHT            0x8017
+#define GLX_MAX_PBUFFER_PIXELS            0x8018
+#define GLX_PRESERVED_CONTENTS            0x801B
+#define GLX_LARGEST_PBUFFER               0x801C
+#define GLX_WIDTH                         0x801D
+#define GLX_HEIGHT                        0x801E
+#define GLX_EVENT_MASK                    0x801F
+#define GLX_DAMAGED                       0x8020
+#define GLX_SAVED                         0x8021
+#define GLX_WINDOW                        0x8022
+#define GLX_PBUFFER                       0x8023
+#define GLX_PBUFFER_HEIGHT                0x8040
+#define GLX_PBUFFER_WIDTH                 0x8041
+typedef GLXFBConfig *( *PFNGLXGETFBCONFIGSPROC) (Display *dpy, int screen, int *nelements);
+typedef GLXFBConfig *( *PFNGLXCHOOSEFBCONFIGPROC) (Display *dpy, int screen, const int *attrib_list, int *nelements);
+typedef int ( *PFNGLXGETFBCONFIGATTRIBPROC) (Display *dpy, GLXFBConfig config, int attribute, int *value);
+typedef XVisualInfo *( *PFNGLXGETVISUALFROMFBCONFIGPROC) (Display *dpy, GLXFBConfig config);
+typedef GLXWindow ( *PFNGLXCREATEWINDOWPROC) (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list);
+typedef void ( *PFNGLXDESTROYWINDOWPROC) (Display *dpy, GLXWindow win);
+typedef GLXPixmap ( *PFNGLXCREATEPIXMAPPROC) (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list);
+typedef void ( *PFNGLXDESTROYPIXMAPPROC) (Display *dpy, GLXPixmap pixmap);
+typedef GLXPbuffer ( *PFNGLXCREATEPBUFFERPROC) (Display *dpy, GLXFBConfig config, const int *attrib_list);
+typedef void ( *PFNGLXDESTROYPBUFFERPROC) (Display *dpy, GLXPbuffer pbuf);
+typedef void ( *PFNGLXQUERYDRAWABLEPROC) (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value);
+typedef GLXContext ( *PFNGLXCREATENEWCONTEXTPROC) (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct);
+typedef Bool ( *PFNGLXMAKECONTEXTCURRENTPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
+typedef GLXDrawable ( *PFNGLXGETCURRENTREADDRAWABLEPROC) (void);
+typedef int ( *PFNGLXQUERYCONTEXTPROC) (Display *dpy, GLXContext ctx, int attribute, int *value);
+typedef void ( *PFNGLXSELECTEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long event_mask);
+typedef void ( *PFNGLXGETSELECTEDEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long *event_mask);
+#ifdef GLX_GLXEXT_PROTOTYPES
+GLXFBConfig *glXGetFBConfigs (Display *dpy, int screen, int *nelements);
+GLXFBConfig *glXChooseFBConfig (Display *dpy, int screen, const int *attrib_list, int *nelements);
+int glXGetFBConfigAttrib (Display *dpy, GLXFBConfig config, int attribute, int *value);
+XVisualInfo *glXGetVisualFromFBConfig (Display *dpy, GLXFBConfig config);
+GLXWindow glXCreateWindow (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list);
+void glXDestroyWindow (Display *dpy, GLXWindow win);
+GLXPixmap glXCreatePixmap (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list);
+void glXDestroyPixmap (Display *dpy, GLXPixmap pixmap);
+GLXPbuffer glXCreatePbuffer (Display *dpy, GLXFBConfig config, const int *attrib_list);
+void glXDestroyPbuffer (Display *dpy, GLXPbuffer pbuf);
+void glXQueryDrawable (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value);
+GLXContext glXCreateNewContext (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct);
+Bool glXMakeContextCurrent (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
+GLXDrawable glXGetCurrentReadDrawable (void);
+int glXQueryContext (Display *dpy, GLXContext ctx, int attribute, int *value);
+void glXSelectEvent (Display *dpy, GLXDrawable draw, unsigned long event_mask);
+void glXGetSelectedEvent (Display *dpy, GLXDrawable draw, unsigned long *event_mask);
+#endif
+#endif /* GLX_VERSION_1_3 */
+
+#ifndef GLX_VERSION_1_4
+#define GLX_VERSION_1_4 1
+typedef void ( *__GLXextFuncPtr)(void);
+#define GLX_SAMPLE_BUFFERS                100000
+#define GLX_SAMPLES                       100001
+typedef __GLXextFuncPtr ( *PFNGLXGETPROCADDRESSPROC) (const GLubyte *procName);
+#ifdef GLX_GLXEXT_PROTOTYPES
+__GLXextFuncPtr glXGetProcAddress (const GLubyte *procName);
+#endif
+#endif /* GLX_VERSION_1_4 */
+
+#ifndef GLX_ARB_context_flush_control
+#define GLX_ARB_context_flush_control 1
+#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB  0x2097
+#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
+#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
+#endif /* GLX_ARB_context_flush_control */
+
+#ifndef GLX_ARB_create_context
+#define GLX_ARB_create_context 1
+#define GLX_CONTEXT_DEBUG_BIT_ARB         0x00000001
+#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
+#define GLX_CONTEXT_MAJOR_VERSION_ARB     0x2091
+#define GLX_CONTEXT_MINOR_VERSION_ARB     0x2092
+#define GLX_CONTEXT_FLAGS_ARB             0x2094
+typedef GLXContext ( *PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
+#ifdef GLX_GLXEXT_PROTOTYPES
+GLXContext glXCreateContextAttribsARB (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
+#endif
+#endif /* GLX_ARB_create_context */
+
+#ifndef GLX_ARB_create_context_no_error
+#define GLX_ARB_create_context_no_error 1
+#define GLX_CONTEXT_OPENGL_NO_ERROR_ARB   0x31B3
+#endif /* GLX_ARB_create_context_no_error */
+
+#ifndef GLX_ARB_create_context_profile
+#define GLX_ARB_create_context_profile 1
+#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB  0x00000001
+#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
+#define GLX_CONTEXT_PROFILE_MASK_ARB      0x9126
+#endif /* GLX_ARB_create_context_profile */
+
+#ifndef GLX_ARB_create_context_robustness
+#define GLX_ARB_create_context_robustness 1
+#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
+#define GLX_LOSE_CONTEXT_ON_RESET_ARB     0x8252
+#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
+#define GLX_NO_RESET_NOTIFICATION_ARB     0x8261
+#endif /* GLX_ARB_create_context_robustness */
+
+#ifndef GLX_ARB_fbconfig_float
+#define GLX_ARB_fbconfig_float 1
+#define GLX_RGBA_FLOAT_TYPE_ARB           0x20B9
+#define GLX_RGBA_FLOAT_BIT_ARB            0x00000004
+#endif /* GLX_ARB_fbconfig_float */
+
+#ifndef GLX_ARB_framebuffer_sRGB
+#define GLX_ARB_framebuffer_sRGB 1
+#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB  0x20B2
+#endif /* GLX_ARB_framebuffer_sRGB */
+
+#ifndef GLX_ARB_get_proc_address
+#define GLX_ARB_get_proc_address 1
+typedef __GLXextFuncPtr ( *PFNGLXGETPROCADDRESSARBPROC) (const GLubyte *procName);
+#ifdef GLX_GLXEXT_PROTOTYPES
+__GLXextFuncPtr glXGetProcAddressARB (const GLubyte *procName);
+#endif
+#endif /* GLX_ARB_get_proc_address */
+
+#ifndef GLX_ARB_multisample
+#define GLX_ARB_multisample 1
+#define GLX_SAMPLE_BUFFERS_ARB            100000
+#define GLX_SAMPLES_ARB                   100001
+#endif /* GLX_ARB_multisample */
+
+#ifndef GLX_ARB_robustness_application_isolation
+#define GLX_ARB_robustness_application_isolation 1
+#define GLX_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008
+#endif /* GLX_ARB_robustness_application_isolation */
+
+#ifndef GLX_ARB_robustness_share_group_isolation
+#define GLX_ARB_robustness_share_group_isolation 1
+#endif /* GLX_ARB_robustness_share_group_isolation */
+
+#ifndef GLX_ARB_vertex_buffer_object
+#define GLX_ARB_vertex_buffer_object 1
+#define GLX_CONTEXT_ALLOW_BUFFER_BYTE_ORDER_MISMATCH_ARB 0x2095
+#endif /* GLX_ARB_vertex_buffer_object */
+
+#ifndef GLX_3DFX_multisample
+#define GLX_3DFX_multisample 1
+#define GLX_SAMPLE_BUFFERS_3DFX           0x8050
+#define GLX_SAMPLES_3DFX                  0x8051
+#endif /* GLX_3DFX_multisample */
+
+#ifndef GLX_AMD_gpu_association
+#define GLX_AMD_gpu_association 1
+#define GLX_GPU_VENDOR_AMD                0x1F00
+#define GLX_GPU_RENDERER_STRING_AMD       0x1F01
+#define GLX_GPU_OPENGL_VERSION_STRING_AMD 0x1F02
+#define GLX_GPU_FASTEST_TARGET_GPUS_AMD   0x21A2
+#define GLX_GPU_RAM_AMD                   0x21A3
+#define GLX_GPU_CLOCK_AMD                 0x21A4
+#define GLX_GPU_NUM_PIPES_AMD             0x21A5
+#define GLX_GPU_NUM_SIMD_AMD              0x21A6
+#define GLX_GPU_NUM_RB_AMD                0x21A7
+#define GLX_GPU_NUM_SPI_AMD               0x21A8
+typedef unsigned int ( *PFNGLXGETGPUIDSAMDPROC) (unsigned int maxCount, unsigned int *ids);
+typedef int ( *PFNGLXGETGPUINFOAMDPROC) (unsigned int id, int property, GLenum dataType, unsigned int size, void *data);
+typedef unsigned int ( *PFNGLXGETCONTEXTGPUIDAMDPROC) (GLXContext ctx);
+typedef GLXContext ( *PFNGLXCREATEASSOCIATEDCONTEXTAMDPROC) (unsigned int id, GLXContext share_list);
+typedef GLXContext ( *PFNGLXCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC) (unsigned int id, GLXContext share_context, const int *attribList);
+typedef Bool ( *PFNGLXDELETEASSOCIATEDCONTEXTAMDPROC) (GLXContext ctx);
+typedef Bool ( *PFNGLXMAKEASSOCIATEDCONTEXTCURRENTAMDPROC) (GLXContext ctx);
+typedef GLXContext ( *PFNGLXGETCURRENTASSOCIATEDCONTEXTAMDPROC) (void);
+typedef void ( *PFNGLXBLITCONTEXTFRAMEBUFFERAMDPROC) (GLXContext dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#ifdef GLX_GLXEXT_PROTOTYPES
+unsigned int glXGetGPUIDsAMD (unsigned int maxCount, unsigned int *ids);
+int glXGetGPUInfoAMD (unsigned int id, int property, GLenum dataType, unsigned int size, void *data);
+unsigned int glXGetContextGPUIDAMD (GLXContext ctx);
+GLXContext glXCreateAssociatedContextAMD (unsigned int id, GLXContext share_list);
+GLXContext glXCreateAssociatedContextAttribsAMD (unsigned int id, GLXContext share_context, const int *attribList);
+Bool glXDeleteAssociatedContextAMD (GLXContext ctx);
+Bool glXMakeAssociatedContextCurrentAMD (GLXContext ctx);
+GLXContext glXGetCurrentAssociatedContextAMD (void);
+void glXBlitContextFramebufferAMD (GLXContext dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+#endif /* GLX_AMD_gpu_association */
+
+#ifndef GLX_EXT_buffer_age
+#define GLX_EXT_buffer_age 1
+#define GLX_BACK_BUFFER_AGE_EXT           0x20F4
+#endif /* GLX_EXT_buffer_age */
+
+#ifndef GLX_EXT_context_priority
+#define GLX_EXT_context_priority 1
+#define GLX_CONTEXT_PRIORITY_LEVEL_EXT    0x3100
+#define GLX_CONTEXT_PRIORITY_HIGH_EXT     0x3101
+#define GLX_CONTEXT_PRIORITY_MEDIUM_EXT   0x3102
+#define GLX_CONTEXT_PRIORITY_LOW_EXT      0x3103
+#endif /* GLX_EXT_context_priority */
+
+#ifndef GLX_EXT_create_context_es2_profile
+#define GLX_EXT_create_context_es2_profile 1
+#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT   0x00000004
+#endif /* GLX_EXT_create_context_es2_profile */
+
+#ifndef GLX_EXT_create_context_es_profile
+#define GLX_EXT_create_context_es_profile 1
+#define GLX_CONTEXT_ES_PROFILE_BIT_EXT    0x00000004
+#endif /* GLX_EXT_create_context_es_profile */
+
+#ifndef GLX_EXT_fbconfig_packed_float
+#define GLX_EXT_fbconfig_packed_float 1
+#define GLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT  0x20B1
+#define GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT   0x00000008
+#endif /* GLX_EXT_fbconfig_packed_float */
+
+#ifndef GLX_EXT_framebuffer_sRGB
+#define GLX_EXT_framebuffer_sRGB 1
+#define GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT  0x20B2
+#endif /* GLX_EXT_framebuffer_sRGB */
+
+#ifndef GLX_EXT_import_context
+#define GLX_EXT_import_context 1
+#define GLX_SHARE_CONTEXT_EXT             0x800A
+#define GLX_VISUAL_ID_EXT                 0x800B
+#define GLX_SCREEN_EXT                    0x800C
+typedef Display *( *PFNGLXGETCURRENTDISPLAYEXTPROC) (void);
+typedef int ( *PFNGLXQUERYCONTEXTINFOEXTPROC) (Display *dpy, GLXContext context, int attribute, int *value);
+typedef GLXContextID ( *PFNGLXGETCONTEXTIDEXTPROC) (const GLXContext context);
+typedef GLXContext ( *PFNGLXIMPORTCONTEXTEXTPROC) (Display *dpy, GLXContextID contextID);
+typedef void ( *PFNGLXFREECONTEXTEXTPROC) (Display *dpy, GLXContext context);
+#ifdef GLX_GLXEXT_PROTOTYPES
+Display *glXGetCurrentDisplayEXT (void);
+int glXQueryContextInfoEXT (Display *dpy, GLXContext context, int attribute, int *value);
+GLXContextID glXGetContextIDEXT (const GLXContext context);
+GLXContext glXImportContextEXT (Display *dpy, GLXContextID contextID);
+void glXFreeContextEXT (Display *dpy, GLXContext context);
+#endif
+#endif /* GLX_EXT_import_context */
+
+#ifndef GLX_EXT_libglvnd
+#define GLX_EXT_libglvnd 1
+#define GLX_VENDOR_NAMES_EXT              0x20F6
+#endif /* GLX_EXT_libglvnd */
+
+#ifndef GLX_EXT_no_config_context
+#define GLX_EXT_no_config_context 1
+#endif /* GLX_EXT_no_config_context */
+
+#ifndef GLX_EXT_stereo_tree
+#define GLX_EXT_stereo_tree 1
+typedef struct {
+    int type;
+    unsigned long serial;
+    Bool send_event;
+    Display *display;
+    int extension;
+    int evtype;
+    GLXDrawable window;
+    Bool stereo_tree;
+} GLXStereoNotifyEventEXT;
+#define GLX_STEREO_TREE_EXT               0x20F5
+#define GLX_STEREO_NOTIFY_MASK_EXT        0x00000001
+#define GLX_STEREO_NOTIFY_EXT             0x00000000
+#endif /* GLX_EXT_stereo_tree */
+
+#ifndef GLX_EXT_swap_control
+#define GLX_EXT_swap_control 1
+#define GLX_SWAP_INTERVAL_EXT             0x20F1
+#define GLX_MAX_SWAP_INTERVAL_EXT         0x20F2
+typedef void ( *PFNGLXSWAPINTERVALEXTPROC) (Display *dpy, GLXDrawable drawable, int interval);
+#ifdef GLX_GLXEXT_PROTOTYPES
+void glXSwapIntervalEXT (Display *dpy, GLXDrawable drawable, int interval);
+#endif
+#endif /* GLX_EXT_swap_control */
+
+#ifndef GLX_EXT_swap_control_tear
+#define GLX_EXT_swap_control_tear 1
+#define GLX_LATE_SWAPS_TEAR_EXT           0x20F3
+#endif /* GLX_EXT_swap_control_tear */
+
+#ifndef GLX_EXT_texture_from_pixmap
+#define GLX_EXT_texture_from_pixmap 1
+#define GLX_TEXTURE_1D_BIT_EXT            0x00000001
+#define GLX_TEXTURE_2D_BIT_EXT            0x00000002
+#define GLX_TEXTURE_RECTANGLE_BIT_EXT     0x00000004
+#define GLX_BIND_TO_TEXTURE_RGB_EXT       0x20D0
+#define GLX_BIND_TO_TEXTURE_RGBA_EXT      0x20D1
+#define GLX_BIND_TO_MIPMAP_TEXTURE_EXT    0x20D2
+#define GLX_BIND_TO_TEXTURE_TARGETS_EXT   0x20D3
+#define GLX_Y_INVERTED_EXT                0x20D4
+#define GLX_TEXTURE_FORMAT_EXT            0x20D5
+#define GLX_TEXTURE_TARGET_EXT            0x20D6
+#define GLX_MIPMAP_TEXTURE_EXT            0x20D7
+#define GLX_TEXTURE_FORMAT_NONE_EXT       0x20D8
+#define GLX_TEXTURE_FORMAT_RGB_EXT        0x20D9
+#define GLX_TEXTURE_FORMAT_RGBA_EXT       0x20DA
+#define GLX_TEXTURE_1D_EXT                0x20DB
+#define GLX_TEXTURE_2D_EXT                0x20DC
+#define GLX_TEXTURE_RECTANGLE_EXT         0x20DD
+#define GLX_FRONT_LEFT_EXT                0x20DE
+#define GLX_FRONT_RIGHT_EXT               0x20DF
+#define GLX_BACK_LEFT_EXT                 0x20E0
+#define GLX_BACK_RIGHT_EXT                0x20E1
+#define GLX_FRONT_EXT                     0x20DE
+#define GLX_BACK_EXT                      0x20E0
+#define GLX_AUX0_EXT                      0x20E2
+#define GLX_AUX1_EXT                      0x20E3
+#define GLX_AUX2_EXT                      0x20E4
+#define GLX_AUX3_EXT                      0x20E5
+#define GLX_AUX4_EXT                      0x20E6
+#define GLX_AUX5_EXT                      0x20E7
+#define GLX_AUX6_EXT                      0x20E8
+#define GLX_AUX7_EXT                      0x20E9
+#define GLX_AUX8_EXT                      0x20EA
+#define GLX_AUX9_EXT                      0x20EB
+typedef void ( *PFNGLXBINDTEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list);
+typedef void ( *PFNGLXRELEASETEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer);
+#ifdef GLX_GLXEXT_PROTOTYPES
+void glXBindTexImageEXT (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list);
+void glXReleaseTexImageEXT (Display *dpy, GLXDrawable drawable, int buffer);
+#endif
+#endif /* GLX_EXT_texture_from_pixmap */
+
+#ifndef GLX_EXT_visual_info
+#define GLX_EXT_visual_info 1
+#define GLX_X_VISUAL_TYPE_EXT             0x22
+#define GLX_TRANSPARENT_TYPE_EXT          0x23
+#define GLX_TRANSPARENT_INDEX_VALUE_EXT   0x24
+#define GLX_TRANSPARENT_RED_VALUE_EXT     0x25
+#define GLX_TRANSPARENT_GREEN_VALUE_EXT   0x26
+#define GLX_TRANSPARENT_BLUE_VALUE_EXT    0x27
+#define GLX_TRANSPARENT_ALPHA_VALUE_EXT   0x28
+#define GLX_NONE_EXT                      0x8000
+#define GLX_TRUE_COLOR_EXT                0x8002
+#define GLX_DIRECT_COLOR_EXT              0x8003
+#define GLX_PSEUDO_COLOR_EXT              0x8004
+#define GLX_STATIC_COLOR_EXT              0x8005
+#define GLX_GRAY_SCALE_EXT                0x8006
+#define GLX_STATIC_GRAY_EXT               0x8007
+#define GLX_TRANSPARENT_RGB_EXT           0x8008
+#define GLX_TRANSPARENT_INDEX_EXT         0x8009
+#endif /* GLX_EXT_visual_info */
+
+#ifndef GLX_EXT_visual_rating
+#define GLX_EXT_visual_rating 1
+#define GLX_VISUAL_CAVEAT_EXT             0x20
+#define GLX_SLOW_VISUAL_EXT               0x8001
+#define GLX_NON_CONFORMANT_VISUAL_EXT     0x800D
+#endif /* GLX_EXT_visual_rating */
+
+#ifndef GLX_INTEL_swap_event
+#define GLX_INTEL_swap_event 1
+#define GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK 0x04000000
+#define GLX_EXCHANGE_COMPLETE_INTEL       0x8180
+#define GLX_COPY_COMPLETE_INTEL           0x8181
+#define GLX_FLIP_COMPLETE_INTEL           0x8182
+#endif /* GLX_INTEL_swap_event */
+
+#ifndef GLX_MESA_agp_offset
+#define GLX_MESA_agp_offset 1
+typedef unsigned int ( *PFNGLXGETAGPOFFSETMESAPROC) (const void *pointer);
+#ifdef GLX_GLXEXT_PROTOTYPES
+unsigned int glXGetAGPOffsetMESA (const void *pointer);
+#endif
+#endif /* GLX_MESA_agp_offset */
+
+#ifndef GLX_MESA_copy_sub_buffer
+#define GLX_MESA_copy_sub_buffer 1
+typedef void ( *PFNGLXCOPYSUBBUFFERMESAPROC) (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height);
+#ifdef GLX_GLXEXT_PROTOTYPES
+void glXCopySubBufferMESA (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height);
+#endif
+#endif /* GLX_MESA_copy_sub_buffer */
+
+#ifndef GLX_MESA_pixmap_colormap
+#define GLX_MESA_pixmap_colormap 1
+typedef GLXPixmap ( *PFNGLXCREATEGLXPIXMAPMESAPROC) (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap);
+#ifdef GLX_GLXEXT_PROTOTYPES
+GLXPixmap glXCreateGLXPixmapMESA (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap);
+#endif
+#endif /* GLX_MESA_pixmap_colormap */
+
+#ifndef GLX_MESA_query_renderer
+#define GLX_MESA_query_renderer 1
+#define GLX_RENDERER_VENDOR_ID_MESA       0x8183
+#define GLX_RENDERER_DEVICE_ID_MESA       0x8184
+#define GLX_RENDERER_VERSION_MESA         0x8185
+#define GLX_RENDERER_ACCELERATED_MESA     0x8186
+#define GLX_RENDERER_VIDEO_MEMORY_MESA    0x8187
+#define GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA 0x8188
+#define GLX_RENDERER_PREFERRED_PROFILE_MESA 0x8189
+#define GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA 0x818A
+#define GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA 0x818B
+#define GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA 0x818C
+#define GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA 0x818D
+typedef Bool ( *PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC) (int attribute, unsigned int *value);
+typedef const char *( *PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC) (int attribute);
+typedef Bool ( *PFNGLXQUERYRENDERERINTEGERMESAPROC) (Display *dpy, int screen, int renderer, int attribute, unsigned int *value);
+typedef const char *( *PFNGLXQUERYRENDERERSTRINGMESAPROC) (Display *dpy, int screen, int renderer, int attribute);
+#ifdef GLX_GLXEXT_PROTOTYPES
+Bool glXQueryCurrentRendererIntegerMESA (int attribute, unsigned int *value);
+const char *glXQueryCurrentRendererStringMESA (int attribute);
+Bool glXQueryRendererIntegerMESA (Display *dpy, int screen, int renderer, int attribute, unsigned int *value);
+const char *glXQueryRendererStringMESA (Display *dpy, int screen, int renderer, int attribute);
+#endif
+#endif /* GLX_MESA_query_renderer */
+
+#ifndef GLX_MESA_release_buffers
+#define GLX_MESA_release_buffers 1
+typedef Bool ( *PFNGLXRELEASEBUFFERSMESAPROC) (Display *dpy, GLXDrawable drawable);
+#ifdef GLX_GLXEXT_PROTOTYPES
+Bool glXReleaseBuffersMESA (Display *dpy, GLXDrawable drawable);
+#endif
+#endif /* GLX_MESA_release_buffers */
+
+#ifndef GLX_MESA_set_3dfx_mode
+#define GLX_MESA_set_3dfx_mode 1
+#define GLX_3DFX_WINDOW_MODE_MESA         0x1
+#define GLX_3DFX_FULLSCREEN_MODE_MESA     0x2
+typedef GLboolean ( *PFNGLXSET3DFXMODEMESAPROC) (GLint mode);
+#ifdef GLX_GLXEXT_PROTOTYPES
+GLboolean glXSet3DfxModeMESA (GLint mode);
+#endif
+#endif /* GLX_MESA_set_3dfx_mode */
+
+#ifndef GLX_MESA_swap_control
+#define GLX_MESA_swap_control 1
+typedef int ( *PFNGLXGETSWAPINTERVALMESAPROC) (void);
+typedef int ( *PFNGLXSWAPINTERVALMESAPROC) (unsigned int interval);
+#ifdef GLX_GLXEXT_PROTOTYPES
+int glXGetSwapIntervalMESA (void);
+int glXSwapIntervalMESA (unsigned int interval);
+#endif
+#endif /* GLX_MESA_swap_control */
+
+#ifndef GLX_NV_copy_buffer
+#define GLX_NV_copy_buffer 1
+typedef void ( *PFNGLXCOPYBUFFERSUBDATANVPROC) (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+typedef void ( *PFNGLXNAMEDCOPYBUFFERSUBDATANVPROC) (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+#ifdef GLX_GLXEXT_PROTOTYPES
+void glXCopyBufferSubDataNV (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+void glXNamedCopyBufferSubDataNV (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+#endif
+#endif /* GLX_NV_copy_buffer */
+
+#ifndef GLX_NV_copy_image
+#define GLX_NV_copy_image 1
+typedef void ( *PFNGLXCOPYIMAGESUBDATANVPROC) (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);
+#ifdef GLX_GLXEXT_PROTOTYPES
+void glXCopyImageSubDataNV (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+#endif /* GLX_NV_copy_image */
+
+#ifndef GLX_NV_delay_before_swap
+#define GLX_NV_delay_before_swap 1
+typedef Bool ( *PFNGLXDELAYBEFORESWAPNVPROC) (Display *dpy, GLXDrawable drawable, GLfloat seconds);
+#ifdef GLX_GLXEXT_PROTOTYPES
+Bool glXDelayBeforeSwapNV (Display *dpy, GLXDrawable drawable, GLfloat seconds);
+#endif
+#endif /* GLX_NV_delay_before_swap */
+
+#ifndef GLX_NV_float_buffer
+#define GLX_NV_float_buffer 1
+#define GLX_FLOAT_COMPONENTS_NV           0x20B0
+#endif /* GLX_NV_float_buffer */
+
+#ifndef GLX_NV_multisample_coverage
+#define GLX_NV_multisample_coverage 1
+#define GLX_COVERAGE_SAMPLES_NV           100001
+#define GLX_COLOR_SAMPLES_NV              0x20B3
+#endif /* GLX_NV_multisample_coverage */
+
+#ifndef GLX_NV_present_video
+#define GLX_NV_present_video 1
+#define GLX_NUM_VIDEO_SLOTS_NV            0x20F0
+typedef unsigned int *( *PFNGLXENUMERATEVIDEODEVICESNVPROC) (Display *dpy, int screen, int *nelements);
+typedef int ( *PFNGLXBINDVIDEODEVICENVPROC) (Display *dpy, unsigned int video_slot, unsigned int video_device, const int *attrib_list);
+#ifdef GLX_GLXEXT_PROTOTYPES
+unsigned int *glXEnumerateVideoDevicesNV (Display *dpy, int screen, int *nelements);
+int glXBindVideoDeviceNV (Display *dpy, unsigned int video_slot, unsigned int video_device, const int *attrib_list);
+#endif
+#endif /* GLX_NV_present_video */
+
+#ifndef GLX_NV_robustness_video_memory_purge
+#define GLX_NV_robustness_video_memory_purge 1
+#define GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x20F7
+#endif /* GLX_NV_robustness_video_memory_purge */
+
+#ifndef GLX_NV_swap_group
+#define GLX_NV_swap_group 1
+typedef Bool ( *PFNGLXJOINSWAPGROUPNVPROC) (Display *dpy, GLXDrawable drawable, GLuint group);
+typedef Bool ( *PFNGLXBINDSWAPBARRIERNVPROC) (Display *dpy, GLuint group, GLuint barrier);
+typedef Bool ( *PFNGLXQUERYSWAPGROUPNVPROC) (Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier);
+typedef Bool ( *PFNGLXQUERYMAXSWAPGROUPSNVPROC) (Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers);
+typedef Bool ( *PFNGLXQUERYFRAMECOUNTNVPROC) (Display *dpy, int screen, GLuint *count);
+typedef Bool ( *PFNGLXRESETFRAMECOUNTNVPROC) (Display *dpy, int screen);
+#ifdef GLX_GLXEXT_PROTOTYPES
+Bool glXJoinSwapGroupNV (Display *dpy, GLXDrawable drawable, GLuint group);
+Bool glXBindSwapBarrierNV (Display *dpy, GLuint group, GLuint barrier);
+Bool glXQuerySwapGroupNV (Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier);
+Bool glXQueryMaxSwapGroupsNV (Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers);
+Bool glXQueryFrameCountNV (Display *dpy, int screen, GLuint *count);
+Bool glXResetFrameCountNV (Display *dpy, int screen);
+#endif
+#endif /* GLX_NV_swap_group */
+
+#ifndef GLX_NV_video_capture
+#define GLX_NV_video_capture 1
+typedef XID GLXVideoCaptureDeviceNV;
+#define GLX_DEVICE_ID_NV                  0x20CD
+#define GLX_UNIQUE_ID_NV                  0x20CE
+#define GLX_NUM_VIDEO_CAPTURE_SLOTS_NV    0x20CF
+typedef int ( *PFNGLXBINDVIDEOCAPTUREDEVICENVPROC) (Display *dpy, unsigned int video_capture_slot, GLXVideoCaptureDeviceNV device);
+typedef GLXVideoCaptureDeviceNV *( *PFNGLXENUMERATEVIDEOCAPTUREDEVICESNVPROC) (Display *dpy, int screen, int *nelements);
+typedef void ( *PFNGLXLOCKVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device);
+typedef int ( *PFNGLXQUERYVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device, int attribute, int *value);
+typedef void ( *PFNGLXRELEASEVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device);
+#ifdef GLX_GLXEXT_PROTOTYPES
+int glXBindVideoCaptureDeviceNV (Display *dpy, unsigned int video_capture_slot, GLXVideoCaptureDeviceNV device);
+GLXVideoCaptureDeviceNV *glXEnumerateVideoCaptureDevicesNV (Display *dpy, int screen, int *nelements);
+void glXLockVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device);
+int glXQueryVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device, int attribute, int *value);
+void glXReleaseVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device);
+#endif
+#endif /* GLX_NV_video_capture */
+
+#ifndef GLX_NV_video_out
+#define GLX_NV_video_out 1
+typedef unsigned int GLXVideoDeviceNV;
+#define GLX_VIDEO_OUT_COLOR_NV            0x20C3
+#define GLX_VIDEO_OUT_ALPHA_NV            0x20C4
+#define GLX_VIDEO_OUT_DEPTH_NV            0x20C5
+#define GLX_VIDEO_OUT_COLOR_AND_ALPHA_NV  0x20C6
+#define GLX_VIDEO_OUT_COLOR_AND_DEPTH_NV  0x20C7
+#define GLX_VIDEO_OUT_FRAME_NV            0x20C8
+#define GLX_VIDEO_OUT_FIELD_1_NV          0x20C9
+#define GLX_VIDEO_OUT_FIELD_2_NV          0x20CA
+#define GLX_VIDEO_OUT_STACKED_FIELDS_1_2_NV 0x20CB
+#define GLX_VIDEO_OUT_STACKED_FIELDS_2_1_NV 0x20CC
+typedef int ( *PFNGLXGETVIDEODEVICENVPROC) (Display *dpy, int screen, int numVideoDevices, GLXVideoDeviceNV *pVideoDevice);
+typedef int ( *PFNGLXRELEASEVIDEODEVICENVPROC) (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice);
+typedef int ( *PFNGLXBINDVIDEOIMAGENVPROC) (Display *dpy, GLXVideoDeviceNV VideoDevice, GLXPbuffer pbuf, int iVideoBuffer);
+typedef int ( *PFNGLXRELEASEVIDEOIMAGENVPROC) (Display *dpy, GLXPbuffer pbuf);
+typedef int ( *PFNGLXSENDPBUFFERTOVIDEONVPROC) (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock);
+typedef int ( *PFNGLXGETVIDEOINFONVPROC) (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo);
+#ifdef GLX_GLXEXT_PROTOTYPES
+int glXGetVideoDeviceNV (Display *dpy, int screen, int numVideoDevices, GLXVideoDeviceNV *pVideoDevice);
+int glXReleaseVideoDeviceNV (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice);
+int glXBindVideoImageNV (Display *dpy, GLXVideoDeviceNV VideoDevice, GLXPbuffer pbuf, int iVideoBuffer);
+int glXReleaseVideoImageNV (Display *dpy, GLXPbuffer pbuf);
+int glXSendPbufferToVideoNV (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock);
+int glXGetVideoInfoNV (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo);
+#endif
+#endif /* GLX_NV_video_out */
+
+#ifndef GLX_OML_swap_method
+#define GLX_OML_swap_method 1
+#define GLX_SWAP_METHOD_OML               0x8060
+#define GLX_SWAP_EXCHANGE_OML             0x8061
+#define GLX_SWAP_COPY_OML                 0x8062
+#define GLX_SWAP_UNDEFINED_OML            0x8063
+#endif /* GLX_OML_swap_method */
+
+#ifndef GLX_OML_sync_control
+#define GLX_OML_sync_control 1
+#ifndef GLEXT_64_TYPES_DEFINED
+/* This code block is duplicated in glext.h, so must be protected */
+#define GLEXT_64_TYPES_DEFINED
+/* Define int32_t, int64_t, and uint64_t types for UST/MSC */
+/* (as used in the GLX_OML_sync_control extension). */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#include 
+#elif defined(__sun__) || defined(__digital__)
+#include 
+#if defined(__STDC__)
+#if defined(__arch64__) || defined(_LP64)
+typedef long int int64_t;
+typedef unsigned long int uint64_t;
+#else
+typedef long long int int64_t;
+typedef unsigned long long int uint64_t;
+#endif /* __arch64__ */
+#endif /* __STDC__ */
+#elif defined( __VMS ) || defined(__sgi)
+#include 
+#elif defined(__SCO__) || defined(__USLC__)
+#include 
+#elif defined(__UNIXOS2__) || defined(__SOL64__)
+typedef long int int32_t;
+typedef long long int int64_t;
+typedef unsigned long long int uint64_t;
+#elif defined(_WIN32) && defined(__GNUC__)
+#include 
+#elif defined(_WIN32)
+typedef __int32 int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+/* Fallback if nothing above works */
+#include 
+#endif
+#endif
+typedef Bool ( *PFNGLXGETSYNCVALUESOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc);
+typedef Bool ( *PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator);
+typedef int64_t ( *PFNGLXSWAPBUFFERSMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder);
+typedef Bool ( *PFNGLXWAITFORMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc);
+typedef Bool ( *PFNGLXWAITFORSBCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc);
+#ifdef GLX_GLXEXT_PROTOTYPES
+Bool glXGetSyncValuesOML (Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc);
+Bool glXGetMscRateOML (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator);
+int64_t glXSwapBuffersMscOML (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder);
+Bool glXWaitForMscOML (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc);
+Bool glXWaitForSbcOML (Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc);
+#endif
+#endif /* GLX_OML_sync_control */
+
+#ifndef GLX_SGIS_blended_overlay
+#define GLX_SGIS_blended_overlay 1
+#define GLX_BLENDED_RGBA_SGIS             0x8025
+#endif /* GLX_SGIS_blended_overlay */
+
+#ifndef GLX_SGIS_multisample
+#define GLX_SGIS_multisample 1
+#define GLX_SAMPLE_BUFFERS_SGIS           100000
+#define GLX_SAMPLES_SGIS                  100001
+#endif /* GLX_SGIS_multisample */
+
+#ifndef GLX_SGIS_shared_multisample
+#define GLX_SGIS_shared_multisample 1
+#define GLX_MULTISAMPLE_SUB_RECT_WIDTH_SGIS 0x8026
+#define GLX_MULTISAMPLE_SUB_RECT_HEIGHT_SGIS 0x8027
+#endif /* GLX_SGIS_shared_multisample */
+
+#ifndef GLX_SGIX_dmbuffer
+#define GLX_SGIX_dmbuffer 1
+typedef XID GLXPbufferSGIX;
+#ifdef _DM_BUFFER_H_
+#define GLX_DIGITAL_MEDIA_PBUFFER_SGIX    0x8024
+typedef Bool ( *PFNGLXASSOCIATEDMPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer);
+#ifdef GLX_GLXEXT_PROTOTYPES
+Bool glXAssociateDMPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer);
+#endif
+#endif /* _DM_BUFFER_H_ */
+#endif /* GLX_SGIX_dmbuffer */
+
+#ifndef GLX_SGIX_fbconfig
+#define GLX_SGIX_fbconfig 1
+typedef struct __GLXFBConfigRec *GLXFBConfigSGIX;
+#define GLX_WINDOW_BIT_SGIX               0x00000001
+#define GLX_PIXMAP_BIT_SGIX               0x00000002
+#define GLX_RGBA_BIT_SGIX                 0x00000001
+#define GLX_COLOR_INDEX_BIT_SGIX          0x00000002
+#define GLX_DRAWABLE_TYPE_SGIX            0x8010
+#define GLX_RENDER_TYPE_SGIX              0x8011
+#define GLX_X_RENDERABLE_SGIX             0x8012
+#define GLX_FBCONFIG_ID_SGIX              0x8013
+#define GLX_RGBA_TYPE_SGIX                0x8014
+#define GLX_COLOR_INDEX_TYPE_SGIX         0x8015
+typedef int ( *PFNGLXGETFBCONFIGATTRIBSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value);
+typedef GLXFBConfigSGIX *( *PFNGLXCHOOSEFBCONFIGSGIXPROC) (Display *dpy, int screen, int *attrib_list, int *nelements);
+typedef GLXPixmap ( *PFNGLXCREATEGLXPIXMAPWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap);
+typedef GLXContext ( *PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct);
+typedef XVisualInfo *( *PFNGLXGETVISUALFROMFBCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config);
+typedef GLXFBConfigSGIX ( *PFNGLXGETFBCONFIGFROMVISUALSGIXPROC) (Display *dpy, XVisualInfo *vis);
+#ifdef GLX_GLXEXT_PROTOTYPES
+int glXGetFBConfigAttribSGIX (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value);
+GLXFBConfigSGIX *glXChooseFBConfigSGIX (Display *dpy, int screen, int *attrib_list, int *nelements);
+GLXPixmap glXCreateGLXPixmapWithConfigSGIX (Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap);
+GLXContext glXCreateContextWithConfigSGIX (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct);
+XVisualInfo *glXGetVisualFromFBConfigSGIX (Display *dpy, GLXFBConfigSGIX config);
+GLXFBConfigSGIX glXGetFBConfigFromVisualSGIX (Display *dpy, XVisualInfo *vis);
+#endif
+#endif /* GLX_SGIX_fbconfig */
+
+#ifndef GLX_SGIX_hyperpipe
+#define GLX_SGIX_hyperpipe 1
+typedef struct {
+    char    pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */
+    int     networkId;
+} GLXHyperpipeNetworkSGIX;
+typedef struct {
+    char    pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */
+    int     channel;
+    unsigned int participationType;
+    int     timeSlice;
+} GLXHyperpipeConfigSGIX;
+typedef struct {
+    char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */
+    int srcXOrigin, srcYOrigin, srcWidth, srcHeight;
+    int destXOrigin, destYOrigin, destWidth, destHeight;
+} GLXPipeRect;
+typedef struct {
+    char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */
+    int XOrigin, YOrigin, maxHeight, maxWidth;
+} GLXPipeRectLimits;
+#define GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX 80
+#define GLX_BAD_HYPERPIPE_CONFIG_SGIX     91
+#define GLX_BAD_HYPERPIPE_SGIX            92
+#define GLX_HYPERPIPE_DISPLAY_PIPE_SGIX   0x00000001
+#define GLX_HYPERPIPE_RENDER_PIPE_SGIX    0x00000002
+#define GLX_PIPE_RECT_SGIX                0x00000001
+#define GLX_PIPE_RECT_LIMITS_SGIX         0x00000002
+#define GLX_HYPERPIPE_STEREO_SGIX         0x00000003
+#define GLX_HYPERPIPE_PIXEL_AVERAGE_SGIX  0x00000004
+#define GLX_HYPERPIPE_ID_SGIX             0x8030
+typedef GLXHyperpipeNetworkSGIX *( *PFNGLXQUERYHYPERPIPENETWORKSGIXPROC) (Display *dpy, int *npipes);
+typedef int ( *PFNGLXHYPERPIPECONFIGSGIXPROC) (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId);
+typedef GLXHyperpipeConfigSGIX *( *PFNGLXQUERYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId, int *npipes);
+typedef int ( *PFNGLXDESTROYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId);
+typedef int ( *PFNGLXBINDHYPERPIPESGIXPROC) (Display *dpy, int hpId);
+typedef int ( *PFNGLXQUERYHYPERPIPEBESTATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList);
+typedef int ( *PFNGLXHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList);
+typedef int ( *PFNGLXQUERYHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList);
+#ifdef GLX_GLXEXT_PROTOTYPES
+GLXHyperpipeNetworkSGIX *glXQueryHyperpipeNetworkSGIX (Display *dpy, int *npipes);
+int glXHyperpipeConfigSGIX (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId);
+GLXHyperpipeConfigSGIX *glXQueryHyperpipeConfigSGIX (Display *dpy, int hpId, int *npipes);
+int glXDestroyHyperpipeConfigSGIX (Display *dpy, int hpId);
+int glXBindHyperpipeSGIX (Display *dpy, int hpId);
+int glXQueryHyperpipeBestAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList);
+int glXHyperpipeAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *attribList);
+int glXQueryHyperpipeAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList);
+#endif
+#endif /* GLX_SGIX_hyperpipe */
+
+#ifndef GLX_SGIX_pbuffer
+#define GLX_SGIX_pbuffer 1
+#define GLX_PBUFFER_BIT_SGIX              0x00000004
+#define GLX_BUFFER_CLOBBER_MASK_SGIX      0x08000000
+#define GLX_FRONT_LEFT_BUFFER_BIT_SGIX    0x00000001
+#define GLX_FRONT_RIGHT_BUFFER_BIT_SGIX   0x00000002
+#define GLX_BACK_LEFT_BUFFER_BIT_SGIX     0x00000004
+#define GLX_BACK_RIGHT_BUFFER_BIT_SGIX    0x00000008
+#define GLX_AUX_BUFFERS_BIT_SGIX          0x00000010
+#define GLX_DEPTH_BUFFER_BIT_SGIX         0x00000020
+#define GLX_STENCIL_BUFFER_BIT_SGIX       0x00000040
+#define GLX_ACCUM_BUFFER_BIT_SGIX         0x00000080
+#define GLX_SAMPLE_BUFFERS_BIT_SGIX       0x00000100
+#define GLX_MAX_PBUFFER_WIDTH_SGIX        0x8016
+#define GLX_MAX_PBUFFER_HEIGHT_SGIX       0x8017
+#define GLX_MAX_PBUFFER_PIXELS_SGIX       0x8018
+#define GLX_OPTIMAL_PBUFFER_WIDTH_SGIX    0x8019
+#define GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX   0x801A
+#define GLX_PRESERVED_CONTENTS_SGIX       0x801B
+#define GLX_LARGEST_PBUFFER_SGIX          0x801C
+#define GLX_WIDTH_SGIX                    0x801D
+#define GLX_HEIGHT_SGIX                   0x801E
+#define GLX_EVENT_MASK_SGIX               0x801F
+#define GLX_DAMAGED_SGIX                  0x8020
+#define GLX_SAVED_SGIX                    0x8021
+#define GLX_WINDOW_SGIX                   0x8022
+#define GLX_PBUFFER_SGIX                  0x8023
+typedef GLXPbufferSGIX ( *PFNGLXCREATEGLXPBUFFERSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list);
+typedef void ( *PFNGLXDESTROYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf);
+typedef void ( *PFNGLXQUERYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value);
+typedef void ( *PFNGLXSELECTEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long mask);
+typedef void ( *PFNGLXGETSELECTEDEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long *mask);
+#ifdef GLX_GLXEXT_PROTOTYPES
+GLXPbufferSGIX glXCreateGLXPbufferSGIX (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list);
+void glXDestroyGLXPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuf);
+void glXQueryGLXPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value);
+void glXSelectEventSGIX (Display *dpy, GLXDrawable drawable, unsigned long mask);
+void glXGetSelectedEventSGIX (Display *dpy, GLXDrawable drawable, unsigned long *mask);
+#endif
+#endif /* GLX_SGIX_pbuffer */
+
+#ifndef GLX_SGIX_swap_barrier
+#define GLX_SGIX_swap_barrier 1
+typedef void ( *PFNGLXBINDSWAPBARRIERSGIXPROC) (Display *dpy, GLXDrawable drawable, int barrier);
+typedef Bool ( *PFNGLXQUERYMAXSWAPBARRIERSSGIXPROC) (Display *dpy, int screen, int *max);
+#ifdef GLX_GLXEXT_PROTOTYPES
+void glXBindSwapBarrierSGIX (Display *dpy, GLXDrawable drawable, int barrier);
+Bool glXQueryMaxSwapBarriersSGIX (Display *dpy, int screen, int *max);
+#endif
+#endif /* GLX_SGIX_swap_barrier */
+
+#ifndef GLX_SGIX_swap_group
+#define GLX_SGIX_swap_group 1
+typedef void ( *PFNGLXJOINSWAPGROUPSGIXPROC) (Display *dpy, GLXDrawable drawable, GLXDrawable member);
+#ifdef GLX_GLXEXT_PROTOTYPES
+void glXJoinSwapGroupSGIX (Display *dpy, GLXDrawable drawable, GLXDrawable member);
+#endif
+#endif /* GLX_SGIX_swap_group */
+
+#ifndef GLX_SGIX_video_resize
+#define GLX_SGIX_video_resize 1
+#define GLX_SYNC_FRAME_SGIX               0x00000000
+#define GLX_SYNC_SWAP_SGIX                0x00000001
+typedef int ( *PFNGLXBINDCHANNELTOWINDOWSGIXPROC) (Display *display, int screen, int channel, Window window);
+typedef int ( *PFNGLXCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int x, int y, int w, int h);
+typedef int ( *PFNGLXQUERYCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int *dx, int *dy, int *dw, int *dh);
+typedef int ( *PFNGLXQUERYCHANNELDELTASSGIXPROC) (Display *display, int screen, int channel, int *x, int *y, int *w, int *h);
+typedef int ( *PFNGLXCHANNELRECTSYNCSGIXPROC) (Display *display, int screen, int channel, GLenum synctype);
+#ifdef GLX_GLXEXT_PROTOTYPES
+int glXBindChannelToWindowSGIX (Display *display, int screen, int channel, Window window);
+int glXChannelRectSGIX (Display *display, int screen, int channel, int x, int y, int w, int h);
+int glXQueryChannelRectSGIX (Display *display, int screen, int channel, int *dx, int *dy, int *dw, int *dh);
+int glXQueryChannelDeltasSGIX (Display *display, int screen, int channel, int *x, int *y, int *w, int *h);
+int glXChannelRectSyncSGIX (Display *display, int screen, int channel, GLenum synctype);
+#endif
+#endif /* GLX_SGIX_video_resize */
+
+#ifndef GLX_SGIX_video_source
+#define GLX_SGIX_video_source 1
+typedef XID GLXVideoSourceSGIX;
+#ifdef _VL_H
+typedef GLXVideoSourceSGIX ( *PFNGLXCREATEGLXVIDEOSOURCESGIXPROC) (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode);
+typedef void ( *PFNGLXDESTROYGLXVIDEOSOURCESGIXPROC) (Display *dpy, GLXVideoSourceSGIX glxvideosource);
+#ifdef GLX_GLXEXT_PROTOTYPES
+GLXVideoSourceSGIX glXCreateGLXVideoSourceSGIX (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode);
+void glXDestroyGLXVideoSourceSGIX (Display *dpy, GLXVideoSourceSGIX glxvideosource);
+#endif
+#endif /* _VL_H */
+#endif /* GLX_SGIX_video_source */
+
+#ifndef GLX_SGIX_visual_select_group
+#define GLX_SGIX_visual_select_group 1
+#define GLX_VISUAL_SELECT_GROUP_SGIX      0x8028
+#endif /* GLX_SGIX_visual_select_group */
+
+#ifndef GLX_SGI_cushion
+#define GLX_SGI_cushion 1
+typedef void ( *PFNGLXCUSHIONSGIPROC) (Display *dpy, Window window, float cushion);
+#ifdef GLX_GLXEXT_PROTOTYPES
+void glXCushionSGI (Display *dpy, Window window, float cushion);
+#endif
+#endif /* GLX_SGI_cushion */
+
+#ifndef GLX_SGI_make_current_read
+#define GLX_SGI_make_current_read 1
+typedef Bool ( *PFNGLXMAKECURRENTREADSGIPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
+typedef GLXDrawable ( *PFNGLXGETCURRENTREADDRAWABLESGIPROC) (void);
+#ifdef GLX_GLXEXT_PROTOTYPES
+Bool glXMakeCurrentReadSGI (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
+GLXDrawable glXGetCurrentReadDrawableSGI (void);
+#endif
+#endif /* GLX_SGI_make_current_read */
+
+#ifndef GLX_SGI_swap_control
+#define GLX_SGI_swap_control 1
+typedef int ( *PFNGLXSWAPINTERVALSGIPROC) (int interval);
+#ifdef GLX_GLXEXT_PROTOTYPES
+int glXSwapIntervalSGI (int interval);
+#endif
+#endif /* GLX_SGI_swap_control */
+
+#ifndef GLX_SGI_video_sync
+#define GLX_SGI_video_sync 1
+typedef int ( *PFNGLXGETVIDEOSYNCSGIPROC) (unsigned int *count);
+typedef int ( *PFNGLXWAITVIDEOSYNCSGIPROC) (int divisor, int remainder, unsigned int *count);
+#ifdef GLX_GLXEXT_PROTOTYPES
+int glXGetVideoSyncSGI (unsigned int *count);
+int glXWaitVideoSyncSGI (int divisor, int remainder, unsigned int *count);
+#endif
+#endif /* GLX_SGI_video_sync */
+
+#ifndef GLX_SUN_get_transparent_index
+#define GLX_SUN_get_transparent_index 1
+typedef Status ( *PFNGLXGETTRANSPARENTINDEXSUNPROC) (Display *dpy, Window overlay, Window underlay, unsigned long *pTransparentIndex);
+#ifdef GLX_GLXEXT_PROTOTYPES
+Status glXGetTransparentIndexSUN (Display *dpy, Window overlay, Window underlay, unsigned long *pTransparentIndex);
+#endif
+#endif /* GLX_SUN_get_transparent_index */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/Irrlicht/irrMathFastCompat.h b/source/Irrlicht/irrMathFastCompat.h
new file mode 100644
index 00000000..19ce1ed6
--- /dev/null
+++ b/source/Irrlicht/irrMathFastCompat.h
@@ -0,0 +1,126 @@
+// This file is part of the "Irrlicht Engine".
+// For conditions of distribution and use, see copyright notice in irrlicht.h
+
+#ifndef __IRR_FAST_MATH_COMPAT_H_INCLUDED__
+#define __IRR_FAST_MATH_COMPAT_H_INCLUDED__
+
+#include "irrMath.h"
+
+namespace irr
+{
+namespace core
+{
+
+
+// IRRLICHT_FAST_MATH functions which I wanted to kick out because they return
+// wrong results. But last time I proposed that I've been asked to keep them for 
+// Burnings software renderer. So to avoid changing that accidentally or messing up
+// it's speed I'll keep them around, but only as internal header.
+// They should not be used otherwise any longer.
+
+	// Some examples for unexpected results when using this with IRRLICHT_FAST_MATH:
+	// Input 1, expected 1, got 0
+	// Input 3, expected 3, got 2
+	// Input -1.40129846e-45, expected -1, got 0
+	REALINLINE s32 floor32_fast(f32 x)
+	{
+#ifdef IRRLICHT_FAST_MATH
+		const f32 h = 0.5f;
+
+		s32 t;
+
+#if defined(_MSC_VER) && !defined(_WIN64)
+		__asm
+		{
+			fld	x
+			fsub	h
+			fistp	t
+		}
+#elif defined(__GNUC__)
+		__asm__ __volatile__ (
+			"fsub %2 \n\t"
+			"fistpl %0"
+			: "=m" (t)
+			: "t" (x), "f" (h)
+			: "st"
+			);
+#else
+		return (s32) floorf ( x );
+#endif
+		return t;
+#else // no fast math
+		return (s32) floorf ( x );
+#endif
+	}
+	
+	// Some examples for unexpected results when using this with IRRLICHT_FAST_MATH:
+	// Input 1.40129846e-45, expected 1, got 0
+	// Input -1, expected -1, got 0
+	// Input -3, expected -3, got -2
+	REALINLINE s32 ceil32_fast ( f32 x )
+	{
+#ifdef IRRLICHT_FAST_MATH
+		const f32 h = 0.5f;
+
+		s32 t;
+
+#if defined(_MSC_VER) && !defined(_WIN64)
+		__asm
+		{
+			fld	x
+			fadd	h
+			fistp	t
+		}
+#elif defined(__GNUC__)
+		__asm__ __volatile__ (
+			"fadd %2 \n\t"
+			"fistpl %0 \n\t"
+			: "=m"(t)
+			: "t"(x), "f"(h)
+			: "st"
+			);
+#else
+		return (s32) ceilf ( x );
+#endif
+		return t;
+#else // not fast math
+		return (s32) ceilf ( x );
+#endif
+	}	
+	
+	// Some examples for unexpected results when using this with IRRLICHT_FAST_MATH:
+	// Input 0.5, expected 1, got 0
+	// Input 2.5, expected 3, got 2
+	// Input -1.40129846e-45, expected -nan(ind), got -inf
+	// Input -2.80259693e-45, expected -nan(ind), got -inf	
+	REALINLINE s32 round32_fast(f32 x)
+	{
+#if defined(IRRLICHT_FAST_MATH)
+		s32 t;
+
+#if defined(_MSC_VER) && !defined(_WIN64)
+		__asm
+		{
+			fld   x
+			fistp t
+		}
+#elif defined(__GNUC__)
+		__asm__ __volatile__ (
+			"fistpl %0 \n\t"
+			: "=m"(t)
+			: "t"(x)
+			: "st"
+			);
+#else
+		return (s32) round_(x);
+#endif
+		return t;
+#else // no fast math
+		return (s32) round_(x);
+#endif
+	}	
+	
+} // end namespace core
+} // end namespace irr	
+
+#endif // __IRR_FAST_MATH_COMPAT_H_INCLUDED__
diff --git a/source/Irrlicht/irrXML.cpp b/source/Irrlicht/irrXML.cpp
new file mode 100644
index 00000000..96f0ec79
--- /dev/null
+++ b/source/Irrlicht/irrXML.cpp
@@ -0,0 +1,185 @@
+// Copyright (C) 2002-2012 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
+
+#include "irrXML.h"
+
+#ifdef _IRR_COMPILE_WITH_XML_
+
+#include "irrString.h"
+#include "irrArray.h"
+#include "fast_atof.h"
+#include "CXMLReaderImpl.h"
+
+namespace irr
+{
+namespace io
+{
+
+//! Implementation of the file read callback for ordinary files
+class CFileReadCallBack : public IFileReadCallBack
+{
+public:
+
+	//! construct from filename
+	CFileReadCallBack(const char* filename)
+		: File(0), Size(-1), Close(true)
+	{
+		// open file
+		File = fopen(filename, "rb");
+
+		if (File)
+			getFileSize();
+	}
+
+	//! construct from FILE pointer
+	CFileReadCallBack(FILE* file)
+		: File(file), Size(-1), Close(false)
+	{
+		if (File)
+			getFileSize();
+	}
+
+	//! destructor
+	virtual ~CFileReadCallBack()
+	{
+		if (Close && File)
+			fclose(File);
+	}
+
+	//! Reads an amount of bytes from the file.
+	virtual int read(void* buffer, int sizeToRead) _IRR_OVERRIDE_
+	{
+		if (!File)
+			return 0;
+
+		return (int)fread(buffer, 1, sizeToRead, File);
+	}
+
+	//! Returns size of file in bytes
+	virtual long getSize() const _IRR_OVERRIDE_
+	{
+		return Size;
+	}
+
+private:
+
+	//! retrieves the file size of the open file
+	void getFileSize()
+	{
+		fseek(File, 0, SEEK_END);
+		Size = ftell(File);
+		fseek(File, 0, SEEK_SET);
+	}
+
+	FILE* File;
+	long Size;
+	bool Close;
+
+}; // end class CFileReadCallBack
+
+
+
+// FACTORY FUNCTIONS:
+
+
+//! Creates an instance of an UFT-8 or ASCII character xml parser.
+IRRLICHT_API IrrXMLReader* IRRCALLCONV createIrrXMLReader(const char* filename)
+{
+	return createIrrXMLReader(new CFileReadCallBack(filename), true);
+}
+
+
+//! Creates an instance of an UFT-8 or ASCII character xml parser.
+IRRLICHT_API IrrXMLReader* IRRCALLCONV createIrrXMLReader(FILE* file)
+{
+	return createIrrXMLReader(new CFileReadCallBack(file), true);
+}
+
+
+//! Creates an instance of an UFT-8 or ASCII character xml parser.
+IRRLICHT_API IrrXMLReader* IRRCALLCONV createIrrXMLReader(IFileReadCallBack* callback,
+														  bool deleteCallback)
+{
+	if (callback && (callback->getSize() >= 0))
+	{
+		return new CXMLReaderImpl(callback, deleteCallback);
+	}
+	else
+	{
+		if(callback && deleteCallback)
+			delete callback;
+
+		return 0;
+	}
+}
+
+
+//! Creates an instance of an UTF-16 xml parser.
+IRRLICHT_API IrrXMLReaderUTF16* IRRCALLCONV createIrrXMLReaderUTF16(const char* filename)
+{
+	return createIrrXMLReaderUTF16(new CFileReadCallBack(filename), true);
+}
+
+
+//! Creates an instance of an UTF-16 xml parser.
+IRRLICHT_API IrrXMLReaderUTF16* IRRCALLCONV createIrrXMLReaderUTF16(FILE* file)
+{
+	return createIrrXMLReaderUTF16(new CFileReadCallBack(file), true);
+}
+
+
+//! Creates an instance of an UTF-16 xml parser.
+IRRLICHT_API IrrXMLReaderUTF16* IRRCALLCONV createIrrXMLReaderUTF16(IFileReadCallBack* callback,
+																	bool deleteCallback)
+{
+	if (callback && (callback->getSize() >= 0))
+	{
+		return new CXMLReaderImpl(callback, deleteCallback);
+	}
+	else
+	{
+		if(callback && deleteCallback)
+			delete callback;
+
+		return 0;
+	}
+}
+
+
+//! Creates an instance of an UTF-32 xml parser.
+IRRLICHT_API IrrXMLReaderUTF32* IRRCALLCONV createIrrXMLReaderUTF32(const char* filename)
+{
+	return createIrrXMLReaderUTF32(new CFileReadCallBack(filename), true);
+}
+
+
+//! Creates an instance of an UTF-32 xml parser.
+IRRLICHT_API IrrXMLReaderUTF32* IRRCALLCONV createIrrXMLReaderUTF32(FILE* file)
+{
+	return createIrrXMLReaderUTF32(new CFileReadCallBack(file), true);
+}
+
+
+//! Creates an instance of an UTF-32 xml parser.
+IRRLICHT_API IrrXMLReaderUTF32* IRRCALLCONV createIrrXMLReaderUTF32(
+		IFileReadCallBack* callback, bool deleteCallback)
+{
+	if (callback && (callback->getSize() >= 0))
+	{
+		return new CXMLReaderImpl(callback, deleteCallback);
+	}
+	else
+	{
+		if(callback && deleteCallback)
+			delete callback;
+
+		return 0;
+	}
+}
+
+
+} // end namespace io
+} // end namespace irr
+
+#endif // _IRR_COMPILE_WITH_XML_
diff --git a/source/Irrlicht/jpeglib/Makefile.am b/source/Irrlicht/jpeglib/Makefile.am
new file mode 100644
index 00000000..86895a1e
--- /dev/null
+++ b/source/Irrlicht/jpeglib/Makefile.am
@@ -0,0 +1,134 @@
+## Process this file with automake to produce Makefile.in
+#
+#  Automake Makefile for the JPEG library
+#
+#  This file is written by Bob Friesenhahn, Guido Vollbeding
+#
+
+# Sources to build library
+LIBSOURCES = jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+        jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+        jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+        jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+        jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+        jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+        jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+        jquant2.c jutils.c jmemmgr.c @MEMORYMGR@.c
+
+# System dependent sources
+SYSDEPSOURCES = jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+
+# Headers which are installed to support the library
+INSTINCLUDES  = jerror.h jmorecfg.h jpeglib.h
+
+# Headers which are not installed
+OTHERINCLUDES = cderror.h cdjpeg.h jdct.h jinclude.h jmemsys.h jpegint.h \
+        jversion.h transupp.h
+
+# Manual pages (Automake uses 'MANS' for itself)
+DISTMANS= cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 wrjpgcom.1
+
+# Other documentation files
+DOCS= README install.txt usage.txt wizard.txt example.c libjpeg.txt \
+        structure.txt coderules.txt filelist.txt change.log
+
+# Makefiles for various systems
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+        makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+        makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+        makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+        maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+        makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+        makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+        makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+        makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+        makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+        makefile.mms makefile.vms makvms.opt
+
+# Configuration files
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+        jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+        jconfig.vms
+
+# Support scripts for configure
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp \
+        missing ar-lib
+
+# Miscellaneous support files
+OTHERFILES= jconfig.txt ckconfig.c jmemdosa.asm libjpeg.map
+
+# Test support files
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+        testimgp.jpg
+
+# libtool libraries to build
+lib_LTLIBRARIES = libjpeg.la
+
+# Library sources for libjpeg.la
+libjpeg_la_SOURCES = $(LIBSOURCES)
+
+# LDFLAGS for libjpeg.la
+libjpeg_la_LDFLAGS = -no-undefined \
+        -version-info $(JPEG_LIB_VERSION)
+
+if HAVE_LD_VERSION_SCRIPT
+  libjpeg_la_LDFLAGS += -Wl,--version-script=$(srcdir)/libjpeg.map
+endif
+
+# Executables to build
+bin_PROGRAMS = cjpeg djpeg jpegtran rdjpgcom wrjpgcom
+
+# Executable sources & libs
+cjpeg_SOURCES    = cjpeg.c rdppm.c rdgif.c rdtarga.c rdrle.c rdbmp.c \
+        rdswitch.c cdjpeg.c
+cjpeg_LDADD      = libjpeg.la
+djpeg_SOURCES    = djpeg.c wrppm.c wrgif.c wrtarga.c wrrle.c wrbmp.c \
+        rdcolmap.c cdjpeg.c
+djpeg_LDADD      = libjpeg.la
+jpegtran_SOURCES = jpegtran.c rdswitch.c cdjpeg.c transupp.c
+jpegtran_LDADD   = libjpeg.la
+rdjpgcom_SOURCES = rdjpgcom.c
+wrjpgcom_SOURCES = wrjpgcom.c
+
+# Manual pages to install
+man_MANS = $(DISTMANS)
+
+# Headers to install
+include_HEADERS = $(INSTINCLUDES)
+
+# Other distributed headers
+noinst_HEADERS = $(OTHERINCLUDES)
+
+# Other distributed files
+EXTRA_DIST =  $(DOCS) $(DISTMANS) $(MKFILES) $(CONFIGFILES) $(SYSDEPSOURCES) \
+        $(OTHERFILES) $(TESTFILES)
+
+# Files to be cleaned
+CLEANFILES = testout.ppm testout.bmp testout.jpg testoutp.ppm testoutp.jpg \
+        testoutt.jpg
+
+# Install jconfig.h
+install-data-local:
+	$(mkinstalldirs) $(DESTDIR)$(includedir)
+	$(INSTALL_HEADER) jconfig.h $(DESTDIR)$(includedir)/jconfig.h
+
+# Uninstall jconfig.h
+uninstall-local:
+	rm -f $(DESTDIR)$(includedir)/jconfig.h
+
+# Run tests
+test: check-local
+check-local:
+	rm -f testout*
+	./djpeg -dct int -ppm -outfile testout.ppm  $(srcdir)/testorig.jpg
+	./djpeg -dct int -bmp -colors 256 -outfile testout.bmp  $(srcdir)/testorig.jpg
+	./cjpeg -dct int -outfile testout.jpg  $(srcdir)/testimg.ppm
+	./djpeg -dct int -ppm -outfile testoutp.ppm $(srcdir)/testprog.jpg
+	./cjpeg -dct int -progressive -opt -outfile testoutp.jpg $(srcdir)/testimg.ppm
+	./jpegtran -outfile testoutt.jpg $(srcdir)/testprog.jpg
+	cmp $(srcdir)/testimg.ppm testout.ppm
+	cmp $(srcdir)/testimg.bmp testout.bmp
+	cmp $(srcdir)/testimg.jpg testout.jpg
+	cmp $(srcdir)/testimg.ppm testoutp.ppm
+	cmp $(srcdir)/testimgp.jpg testoutp.jpg
+	cmp $(srcdir)/testorig.jpg testoutt.jpg
diff --git a/source/Irrlicht/jpeglib/Makefile.in b/source/Irrlicht/jpeglib/Makefile.in
new file mode 100644
index 00000000..5654c785
--- /dev/null
+++ b/source/Irrlicht/jpeglib/Makefile.in
@@ -0,0 +1,1029 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+#  Automake Makefile for the JPEG library
+#
+#  This file is written by Bob Friesenhahn, Guido Vollbeding
+#
+
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+@HAVE_LD_VERSION_SCRIPT_TRUE@am__append_1 = -Wl,--version-script=$(srcdir)/libjpeg.map
+bin_PROGRAMS = cjpeg$(EXEEXT) djpeg$(EXEEXT) jpegtran$(EXEEXT) \
+	rdjpgcom$(EXEEXT) wrjpgcom$(EXEEXT)
+subdir = .
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+	$(top_srcdir)/configure $(am__configure_deps) \
+	$(srcdir)/jconfig.cfg depcomp $(include_HEADERS) \
+	$(noinst_HEADERS)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = jconfig.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
+	"$(DESTDIR)$(man1dir)" "$(DESTDIR)$(includedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libjpeg_la_LIBADD =
+am__objects_1 = jaricom.lo jcapimin.lo jcapistd.lo jcarith.lo \
+	jccoefct.lo jccolor.lo jcdctmgr.lo jchuff.lo jcinit.lo \
+	jcmainct.lo jcmarker.lo jcmaster.lo jcomapi.lo jcparam.lo \
+	jcprepct.lo jcsample.lo jctrans.lo jdapimin.lo jdapistd.lo \
+	jdarith.lo jdatadst.lo jdatasrc.lo jdcoefct.lo jdcolor.lo \
+	jddctmgr.lo jdhuff.lo jdinput.lo jdmainct.lo jdmarker.lo \
+	jdmaster.lo jdmerge.lo jdpostct.lo jdsample.lo jdtrans.lo \
+	jerror.lo jfdctflt.lo jfdctfst.lo jfdctint.lo jidctflt.lo \
+	jidctfst.lo jidctint.lo jquant1.lo jquant2.lo jutils.lo \
+	jmemmgr.lo @MEMORYMGR@.lo
+am_libjpeg_la_OBJECTS = $(am__objects_1)
+libjpeg_la_OBJECTS = $(am_libjpeg_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+libjpeg_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(libjpeg_la_LDFLAGS) $(LDFLAGS) -o $@
+PROGRAMS = $(bin_PROGRAMS)
+am_cjpeg_OBJECTS = cjpeg.$(OBJEXT) rdppm.$(OBJEXT) rdgif.$(OBJEXT) \
+	rdtarga.$(OBJEXT) rdrle.$(OBJEXT) rdbmp.$(OBJEXT) \
+	rdswitch.$(OBJEXT) cdjpeg.$(OBJEXT)
+cjpeg_OBJECTS = $(am_cjpeg_OBJECTS)
+cjpeg_DEPENDENCIES = libjpeg.la
+am_djpeg_OBJECTS = djpeg.$(OBJEXT) wrppm.$(OBJEXT) wrgif.$(OBJEXT) \
+	wrtarga.$(OBJEXT) wrrle.$(OBJEXT) wrbmp.$(OBJEXT) \
+	rdcolmap.$(OBJEXT) cdjpeg.$(OBJEXT)
+djpeg_OBJECTS = $(am_djpeg_OBJECTS)
+djpeg_DEPENDENCIES = libjpeg.la
+am_jpegtran_OBJECTS = jpegtran.$(OBJEXT) rdswitch.$(OBJEXT) \
+	cdjpeg.$(OBJEXT) transupp.$(OBJEXT)
+jpegtran_OBJECTS = $(am_jpegtran_OBJECTS)
+jpegtran_DEPENDENCIES = libjpeg.la
+am_rdjpgcom_OBJECTS = rdjpgcom.$(OBJEXT)
+rdjpgcom_OBJECTS = $(am_rdjpgcom_OBJECTS)
+rdjpgcom_LDADD = $(LDADD)
+am_wrjpgcom_OBJECTS = wrjpgcom.$(OBJEXT)
+wrjpgcom_OBJECTS = $(am_wrjpgcom_OBJECTS)
+wrjpgcom_LDADD = $(LDADD)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libjpeg_la_SOURCES) $(cjpeg_SOURCES) $(djpeg_SOURCES) \
+	$(jpegtran_SOURCES) $(rdjpgcom_SOURCES) $(wrjpgcom_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+man1dir = $(mandir)/man1
+NROFF = nroff
+MANS = $(man_MANS)
+HEADERS = $(include_HEADERS) $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
+	$(LISP)jconfig.cfg
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+CSCOPE = cscope
+AM_RECURSIVE_TARGETS = cscope
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JPEG_LIB_VERSION = @JPEG_LIB_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MEMORYMGR = @MEMORYMGR@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# Sources to build library
+LIBSOURCES = jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+        jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+        jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+        jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+        jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+        jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+        jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+        jquant2.c jutils.c jmemmgr.c @MEMORYMGR@.c
+
+
+# System dependent sources
+SYSDEPSOURCES = jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+
+# Headers which are installed to support the library
+INSTINCLUDES = jerror.h jmorecfg.h jpeglib.h
+
+# Headers which are not installed
+OTHERINCLUDES = cderror.h cdjpeg.h jdct.h jinclude.h jmemsys.h jpegint.h \
+        jversion.h transupp.h
+
+
+# Manual pages (Automake uses 'MANS' for itself)
+DISTMANS = cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 wrjpgcom.1
+
+# Other documentation files
+DOCS = README install.txt usage.txt wizard.txt example.c libjpeg.txt \
+        structure.txt coderules.txt filelist.txt change.log
+
+
+# Makefiles for various systems
+MKFILES = configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+        makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+        makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+        makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+        maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+        makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+        makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+        makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+        makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+        makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+        makefile.mms makefile.vms makvms.opt
+
+
+# Configuration files
+CONFIGFILES = jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+        jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+        jconfig.vms
+
+
+# Support scripts for configure
+CONFIGUREFILES = config.guess config.sub install-sh ltmain.sh depcomp \
+        missing ar-lib
+
+
+# Miscellaneous support files
+OTHERFILES = jconfig.txt ckconfig.c jmemdosa.asm libjpeg.map
+
+# Test support files
+TESTFILES = testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+        testimgp.jpg
+
+
+# libtool libraries to build
+lib_LTLIBRARIES = libjpeg.la
+
+# Library sources for libjpeg.la
+libjpeg_la_SOURCES = $(LIBSOURCES)
+
+# LDFLAGS for libjpeg.la
+libjpeg_la_LDFLAGS = -no-undefined -version-info $(JPEG_LIB_VERSION) \
+	$(am__append_1)
+
+# Executable sources & libs
+cjpeg_SOURCES = cjpeg.c rdppm.c rdgif.c rdtarga.c rdrle.c rdbmp.c \
+        rdswitch.c cdjpeg.c
+
+cjpeg_LDADD = libjpeg.la
+djpeg_SOURCES = djpeg.c wrppm.c wrgif.c wrtarga.c wrrle.c wrbmp.c \
+        rdcolmap.c cdjpeg.c
+
+djpeg_LDADD = libjpeg.la
+jpegtran_SOURCES = jpegtran.c rdswitch.c cdjpeg.c transupp.c
+jpegtran_LDADD = libjpeg.la
+rdjpgcom_SOURCES = rdjpgcom.c
+wrjpgcom_SOURCES = wrjpgcom.c
+
+# Manual pages to install
+man_MANS = $(DISTMANS)
+
+# Headers to install
+include_HEADERS = $(INSTINCLUDES)
+
+# Other distributed headers
+noinst_HEADERS = $(OTHERINCLUDES)
+
+# Other distributed files
+EXTRA_DIST = $(DOCS) $(DISTMANS) $(MKFILES) $(CONFIGFILES) $(SYSDEPSOURCES) \
+        $(OTHERFILES) $(TESTFILES)
+
+
+# Files to be cleaned
+CLEANFILES = testout.ppm testout.bmp testout.jpg testoutp.ppm testoutp.jpg \
+        testoutt.jpg
+
+all: jconfig.h
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+am--refresh: Makefile
+	@:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+	      $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    echo ' $(SHELL) ./config.status'; \
+	    $(SHELL) ./config.status;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	$(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	$(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+jconfig.h: stamp-h1
+	@test -f $@ || rm -f stamp-h1
+	@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/jconfig.cfg $(top_builddir)/config.status
+	@rm -f stamp-h1
+	cd $(top_builddir) && $(SHELL) ./config.status jconfig.h
+$(srcdir)/jconfig.cfg: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) 
+	($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+	rm -f stamp-h1
+	touch $@
+
+distclean-hdr:
+	-rm -f jconfig.h stamp-h1
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+	}
+
+uninstall-libLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+	done
+
+clean-libLTLIBRARIES:
+	-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+	@list='$(lib_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+libjpeg.la: $(libjpeg_la_OBJECTS) $(libjpeg_la_DEPENDENCIES) $(EXTRA_libjpeg_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libjpeg_la_LINK) -rpath $(libdir) $(libjpeg_la_OBJECTS) $(libjpeg_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+	fi; \
+	for p in $$list; do echo "$$p $$p"; done | \
+	sed 's/$(EXEEXT)$$//' | \
+	while read p p1; do if test -f $$p \
+	 || test -f $$p1 \
+	  ; then echo "$$p"; echo "$$p"; else :; fi; \
+	done | \
+	sed -e 'p;s,.*/,,;n;h' \
+	    -e 's|.*|.|' \
+	    -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+	sed 'N;N;N;s,\n, ,g' | \
+	$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+	  { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+	    if ($$2 == $$4) files[d] = files[d] " " $$1; \
+	    else { print "f", $$3 "/" $$4, $$1; } } \
+	  END { for (d in files) print "f", d, files[d] }' | \
+	while read type dir files; do \
+	    if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+	    test -z "$$files" || { \
+	    echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+	    $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+	    } \
+	; done
+
+uninstall-binPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+	files=`for p in $$list; do echo "$$p"; done | \
+	  sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+	      -e 's/$$/$(EXEEXT)/' \
+	`; \
+	test -n "$$list" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+	@list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+cjpeg$(EXEEXT): $(cjpeg_OBJECTS) $(cjpeg_DEPENDENCIES) $(EXTRA_cjpeg_DEPENDENCIES) 
+	@rm -f cjpeg$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(cjpeg_OBJECTS) $(cjpeg_LDADD) $(LIBS)
+
+djpeg$(EXEEXT): $(djpeg_OBJECTS) $(djpeg_DEPENDENCIES) $(EXTRA_djpeg_DEPENDENCIES) 
+	@rm -f djpeg$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(djpeg_OBJECTS) $(djpeg_LDADD) $(LIBS)
+
+jpegtran$(EXEEXT): $(jpegtran_OBJECTS) $(jpegtran_DEPENDENCIES) $(EXTRA_jpegtran_DEPENDENCIES) 
+	@rm -f jpegtran$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(jpegtran_OBJECTS) $(jpegtran_LDADD) $(LIBS)
+
+rdjpgcom$(EXEEXT): $(rdjpgcom_OBJECTS) $(rdjpgcom_DEPENDENCIES) $(EXTRA_rdjpgcom_DEPENDENCIES) 
+	@rm -f rdjpgcom$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(rdjpgcom_OBJECTS) $(rdjpgcom_LDADD) $(LIBS)
+
+wrjpgcom$(EXEEXT): $(wrjpgcom_OBJECTS) $(wrjpgcom_DEPENDENCIES) $(EXTRA_wrjpgcom_DEPENDENCIES) 
+	@rm -f wrjpgcom$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(wrjpgcom_OBJECTS) $(wrjpgcom_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/@MEMORYMGR@.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdjpeg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cjpeg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/djpeg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jaricom.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcapimin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcapistd.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcarith.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jccoefct.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jccolor.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcdctmgr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jchuff.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcinit.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcmainct.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcmarker.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcmaster.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcomapi.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcparam.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcprepct.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcsample.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jctrans.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdapimin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdapistd.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdarith.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdatadst.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdatasrc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdcoefct.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdcolor.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jddctmgr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdhuff.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdinput.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdmainct.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdmarker.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdmaster.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdmerge.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdpostct.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdsample.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdtrans.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jerror.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jfdctflt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jfdctfst.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jfdctint.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jidctflt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jidctfst.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jidctint.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jmemmgr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jpegtran.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jquant1.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jquant2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jutils.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdbmp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdcolmap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdgif.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdjpgcom.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdppm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdrle.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdswitch.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdtarga.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transupp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrbmp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrgif.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrjpgcom.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrppm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrrle.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrtarga.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool config.lt
+install-man1: $(man_MANS)
+	@$(NORMAL_INSTALL)
+	@list1=''; \
+	list2='$(man_MANS)'; \
+	test -n "$(man1dir)" \
+	  && test -n "`echo $$list1$$list2`" \
+	  || exit 0; \
+	echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \
+	$(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \
+	{ for i in $$list1; do echo "$$i"; done;  \
+	if test -n "$$list2"; then \
+	  for i in $$list2; do echo "$$i"; done \
+	    | sed -n '/\.1[a-z]*$$/p'; \
+	fi; \
+	} | while read p; do \
+	  if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; echo "$$p"; \
+	done | \
+	sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+	      -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+	sed 'N;N;s,\n, ,g' | { \
+	list=; while read file base inst; do \
+	  if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+	    echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+	    $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \
+	  fi; \
+	done; \
+	for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+	while read files; do \
+	  test -z "$$files" || { \
+	    echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \
+	    $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \
+	done; }
+
+uninstall-man1:
+	@$(NORMAL_UNINSTALL)
+	@list=''; test -n "$(man1dir)" || exit 0; \
+	files=`{ for i in $$list; do echo "$$i"; done; \
+	l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+	  sed -n '/\.1[a-z]*$$/p'; \
+	} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+	      -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+	dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir)
+install-includeHEADERS: $(include_HEADERS)
+	@$(NORMAL_INSTALL)
+	@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \
+	done
+
+uninstall-includeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscope: cscope.files
+	test ! -s cscope.files \
+	  || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
+clean-cscope:
+	-rm -f cscope.files
+cscope.files: clean-cscope cscopelist
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+	-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) check-local
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(MANS) $(HEADERS) \
+		jconfig.h
+install-binPROGRAMS: install-libLTLIBRARIES
+
+installdirs:
+	for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(includedir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
+	clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-hdr distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-data-local install-includeHEADERS install-man
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man: install-man1
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf $(top_srcdir)/autom4te.cache
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-includeHEADERS \
+	uninstall-libLTLIBRARIES uninstall-local uninstall-man
+
+uninstall-man: uninstall-man1
+
+.MAKE: all check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-am \
+	check-local clean clean-binPROGRAMS clean-cscope clean-generic \
+	clean-libLTLIBRARIES clean-libtool cscope cscopelist-am ctags \
+	ctags-am distclean distclean-compile distclean-generic \
+	distclean-hdr distclean-libtool distclean-tags dvi dvi-am html \
+	html-am info info-am install install-am install-binPROGRAMS \
+	install-data install-data-am install-data-local install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-includeHEADERS install-info \
+	install-info-am install-libLTLIBRARIES install-man \
+	install-man1 install-pdf install-pdf-am install-ps \
+	install-ps-am install-strip installcheck installcheck-am \
+	installdirs maintainer-clean maintainer-clean-generic \
+	mostlyclean mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+	uninstall-am uninstall-binPROGRAMS uninstall-includeHEADERS \
+	uninstall-libLTLIBRARIES uninstall-local uninstall-man \
+	uninstall-man1
+
+
+# Install jconfig.h
+install-data-local:
+	$(mkinstalldirs) $(DESTDIR)$(includedir)
+	$(INSTALL_HEADER) jconfig.h $(DESTDIR)$(includedir)/jconfig.h
+
+# Uninstall jconfig.h
+uninstall-local:
+	rm -f $(DESTDIR)$(includedir)/jconfig.h
+
+# Run tests
+test: check-local
+check-local:
+	rm -f testout*
+	./djpeg -dct int -ppm -outfile testout.ppm  $(srcdir)/testorig.jpg
+	./djpeg -dct int -bmp -colors 256 -outfile testout.bmp  $(srcdir)/testorig.jpg
+	./cjpeg -dct int -outfile testout.jpg  $(srcdir)/testimg.ppm
+	./djpeg -dct int -ppm -outfile testoutp.ppm $(srcdir)/testprog.jpg
+	./cjpeg -dct int -progressive -opt -outfile testoutp.jpg $(srcdir)/testimg.ppm
+	./jpegtran -outfile testoutt.jpg $(srcdir)/testprog.jpg
+	cmp $(srcdir)/testimg.ppm testout.ppm
+	cmp $(srcdir)/testimg.bmp testout.bmp
+	cmp $(srcdir)/testimg.jpg testout.jpg
+	cmp $(srcdir)/testimg.ppm testoutp.ppm
+	cmp $(srcdir)/testimgp.jpg testoutp.jpg
+	cmp $(srcdir)/testorig.jpg testoutt.jpg
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/source/Irrlicht/jpeglib/README b/source/Irrlicht/jpeglib/README
new file mode 100644
index 00000000..014ad301
--- /dev/null
+++ b/source/Irrlicht/jpeglib/README
@@ -0,0 +1,381 @@
+The Independent JPEG Group's JPEG software
+==========================================
+
+README for release 9a of 19-Jan-2014
+====================================
+
+This distribution contains the ninth public release of the Independent JPEG
+Group's free JPEG software.  You are welcome to redistribute this software and
+to use it for any purpose, subject to the conditions under LEGAL ISSUES, below.
+
+This software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone,
+Bill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson,
+Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, Ge' Weijers,
+and other members of the Independent JPEG Group.
+
+IJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee
+(previously known as JPEG, together with ITU-T SG16).
+
+
+DOCUMENTATION ROADMAP
+=====================
+
+This file contains the following sections:
+
+OVERVIEW            General description of JPEG and the IJG software.
+LEGAL ISSUES        Copyright, lack of warranty, terms of distribution.
+REFERENCES          Where to learn more about JPEG.
+ARCHIVE LOCATIONS   Where to find newer versions of this software.
+ACKNOWLEDGMENTS     Special thanks.
+FILE FORMAT WARS    Software *not* to get.
+TO DO               Plans for future IJG releases.
+
+Other documentation files in the distribution are:
+
+User documentation:
+  install.txt       How to configure and install the IJG software.
+  usage.txt         Usage instructions for cjpeg, djpeg, jpegtran,
+                    rdjpgcom, and wrjpgcom.
+  *.1               Unix-style man pages for programs (same info as usage.txt).
+  wizard.txt        Advanced usage instructions for JPEG wizards only.
+  change.log        Version-to-version change highlights.
+Programmer and internal documentation:
+  libjpeg.txt       How to use the JPEG library in your own programs.
+  example.c         Sample code for calling the JPEG library.
+  structure.txt     Overview of the JPEG library's internal structure.
+  filelist.txt      Road map of IJG files.
+  coderules.txt     Coding style rules --- please read if you contribute code.
+
+Please read at least the files install.txt and usage.txt.  Some information
+can also be found in the JPEG FAQ (Frequently Asked Questions) article.  See
+ARCHIVE LOCATIONS below to find out where to obtain the FAQ article.
+
+If you want to understand how the JPEG code works, we suggest reading one or
+more of the REFERENCES, then looking at the documentation files (in roughly
+the order listed) before diving into the code.
+
+
+OVERVIEW
+========
+
+This package contains C software to implement JPEG image encoding, decoding,
+and transcoding.  JPEG (pronounced "jay-peg") is a standardized compression
+method for full-color and gray-scale images.
+
+This software implements JPEG baseline, extended-sequential, and progressive
+compression processes.  Provision is made for supporting all variants of these
+processes, although some uncommon parameter settings aren't implemented yet.
+We have made no provision for supporting the hierarchical or lossless
+processes defined in the standard.
+
+We provide a set of library routines for reading and writing JPEG image files,
+plus two sample applications "cjpeg" and "djpeg", which use the library to
+perform conversion between JPEG and some other popular image file formats.
+The library is intended to be reused in other applications.
+
+In order to support file conversion and viewing software, we have included
+considerable functionality beyond the bare JPEG coding/decoding capability;
+for example, the color quantization modules are not strictly part of JPEG
+decoding, but they are essential for output to colormapped file formats or
+colormapped displays.  These extra functions can be compiled out of the
+library if not required for a particular application.
+
+We have also included "jpegtran", a utility for lossless transcoding between
+different JPEG processes, and "rdjpgcom" and "wrjpgcom", two simple
+applications for inserting and extracting textual comments in JFIF files.
+
+The emphasis in designing this software has been on achieving portability and
+flexibility, while also making it fast enough to be useful.  In particular,
+the software is not intended to be read as a tutorial on JPEG.  (See the
+REFERENCES section for introductory material.)  Rather, it is intended to
+be reliable, portable, industrial-strength code.  We do not claim to have
+achieved that goal in every aspect of the software, but we strive for it.
+
+We welcome the use of this software as a component of commercial products.
+No royalty is required, but we do ask for an acknowledgement in product
+documentation, as described under LEGAL ISSUES.
+
+
+LEGAL ISSUES
+============
+
+In plain English:
+
+1. We don't promise that this software works.  (But if you find any bugs,
+   please let us know!)
+2. You can use this software for whatever you want.  You don't have to pay us.
+3. You may not pretend that you wrote this software.  If you use it in a
+   program, you must acknowledge somewhere in your documentation that
+   you've used the IJG code.
+
+In legalese:
+
+The authors make NO WARRANTY or representation, either express or implied,
+with respect to this software, its quality, accuracy, merchantability, or
+fitness for a particular purpose.  This software is provided "AS IS", and you,
+its user, assume the entire risk as to its quality and accuracy.
+
+This software is copyright (C) 1991-2014, Thomas G. Lane, Guido Vollbeding.
+All Rights Reserved except as specified below.
+
+Permission is hereby granted to use, copy, modify, and distribute this
+software (or portions thereof) for any purpose, without fee, subject to these
+conditions:
+(1) If any part of the source code for this software is distributed, then this
+README file must be included, with this copyright and no-warranty notice
+unaltered; and any additions, deletions, or changes to the original files
+must be clearly indicated in accompanying documentation.
+(2) If only executable code is distributed, then the accompanying
+documentation must state that "this software is based in part on the work of
+the Independent JPEG Group".
+(3) Permission for use of this software is granted only if the user accepts
+full responsibility for any undesirable consequences; the authors accept
+NO LIABILITY for damages of any kind.
+
+These conditions apply to any software derived from or based on the IJG code,
+not just to the unmodified library.  If you use our work, you ought to
+acknowledge us.
+
+Permission is NOT granted for the use of any IJG author's name or company name
+in advertising or publicity relating to this software or products derived from
+it.  This software may be referred to only as "the Independent JPEG Group's
+software".
+
+We specifically permit and encourage the use of this software as the basis of
+commercial products, provided that all warranty or liability claims are
+assumed by the product vendor.
+
+
+The Unix configuration script "configure" was produced with GNU Autoconf.
+It is copyright by the Free Software Foundation but is freely distributable.
+The same holds for its supporting scripts (config.guess, config.sub,
+ltmain.sh).  Another support script, install-sh, is copyright by X Consortium
+but is also freely distributable.
+
+The IJG distribution formerly included code to read and write GIF files.
+To avoid entanglement with the Unisys LZW patent (now expired), GIF reading
+support has been removed altogether, and the GIF writer has been simplified
+to produce "uncompressed GIFs".  This technique does not use the LZW
+algorithm; the resulting GIF files are larger than usual, but are readable
+by all standard GIF decoders.
+
+We are required to state that
+    "The Graphics Interchange Format(c) is the Copyright property of
+    CompuServe Incorporated.  GIF(sm) is a Service Mark property of
+    CompuServe Incorporated."
+
+
+REFERENCES
+==========
+
+We recommend reading one or more of these references before trying to
+understand the innards of the JPEG software.
+
+The best short technical introduction to the JPEG compression algorithm is
+	Wallace, Gregory K.  "The JPEG Still Picture Compression Standard",
+	Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.
+(Adjacent articles in that issue discuss MPEG motion picture compression,
+applications of JPEG, and related topics.)  If you don't have the CACM issue
+handy, a PostScript file containing a revised version of Wallace's article is
+available at http://www.ijg.org/files/wallace.ps.gz.  The file (actually
+a preprint for an article that appeared in IEEE Trans. Consumer Electronics)
+omits the sample images that appeared in CACM, but it includes corrections
+and some added material.  Note: the Wallace article is copyright ACM and IEEE,
+and it may not be used for commercial purposes.
+
+A somewhat less technical, more leisurely introduction to JPEG can be found in
+"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by
+M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1.  This book provides
+good explanations and example C code for a multitude of compression methods
+including JPEG.  It is an excellent source if you are comfortable reading C
+code but don't know much about data compression in general.  The book's JPEG
+sample code is far from industrial-strength, but when you are ready to look
+at a full implementation, you've got one here...
+
+The best currently available description of JPEG is the textbook "JPEG Still
+Image Data Compression Standard" by William B. Pennebaker and Joan L.
+Mitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1.
+Price US$59.95, 638 pp.  The book includes the complete text of the ISO JPEG
+standards (DIS 10918-1 and draft DIS 10918-2).
+Although this is by far the most detailed and comprehensive exposition of
+JPEG publicly available, we point out that it is still missing an explanation
+of the most essential properties and algorithms of the underlying DCT
+technology.
+If you think that you know about DCT-based JPEG after reading this book,
+then you are in delusion.  The real fundamentals and corresponding potential
+of DCT-based JPEG are not publicly known so far, and that is the reason for
+all the mistaken developments taking place in the image coding domain.
+
+The original JPEG standard is divided into two parts, Part 1 being the actual
+specification, while Part 2 covers compliance testing methods.  Part 1 is
+titled "Digital Compression and Coding of Continuous-tone Still Images,
+Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS
+10918-1, ITU-T T.81.  Part 2 is titled "Digital Compression and Coding of
+Continuous-tone Still Images, Part 2: Compliance testing" and has document
+numbers ISO/IEC IS 10918-2, ITU-T T.83.
+IJG JPEG 8 introduced an implementation of the JPEG SmartScale extension
+which is specified in two documents:  A contributed document at ITU and ISO
+with title "ITU-T JPEG-Plus Proposal for Extending ITU-T T.81 for Advanced
+Image Coding", April 2006, Geneva, Switzerland.  The latest version of this
+document is Revision 3.  And a contributed document ISO/IEC JTC1/SC29/WG1 N
+5799 with title "Evolution of JPEG", June/July 2011, Berlin, Germany.
+IJG JPEG 9 introduces a reversible color transform for improved lossless
+compression which is described in a contributed document ISO/IEC JTC1/SC29/
+WG1 N 6080 with title "JPEG 9 Lossless Coding", June/July 2012, Paris,
+France.
+
+The JPEG standard does not specify all details of an interchangeable file
+format.  For the omitted details we follow the "JFIF" conventions, revision
+1.02.  JFIF 1.02 has been adopted as an Ecma International Technical Report
+and thus received a formal publication status.  It is available as a free
+download in PDF format from
+http://www.ecma-international.org/publications/techreports/E-TR-098.htm.
+A PostScript version of the JFIF document is available at
+http://www.ijg.org/files/jfif.ps.gz.  There is also a plain text version at
+http://www.ijg.org/files/jfif.txt.gz, but it is missing the figures.
+
+The TIFF 6.0 file format specification can be obtained by FTP from
+ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz.  The JPEG incorporation scheme
+found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems.
+IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6).
+Instead, we recommend the JPEG design proposed by TIFF Technical Note #2
+(Compression tag 7).  Copies of this Note can be obtained from
+http://www.ijg.org/files/.  It is expected that the next revision
+of the TIFF spec will replace the 6.0 JPEG design with the Note's design.
+Although IJG's own code does not support TIFF/JPEG, the free libtiff library
+uses our library to implement TIFF/JPEG per the Note.
+
+
+ARCHIVE LOCATIONS
+=================
+
+The "official" archive site for this software is www.ijg.org.
+The most recent released version can always be found there in
+directory "files".  This particular version will be archived as
+http://www.ijg.org/files/jpegsrc.v9a.tar.gz, and in Windows-compatible
+"zip" archive format as http://www.ijg.org/files/jpegsr9a.zip.
+
+The JPEG FAQ (Frequently Asked Questions) article is a source of some
+general information about JPEG.
+It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/
+and other news.answers archive sites, including the official news.answers
+archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/.
+If you don't have Web or FTP access, send e-mail to mail-server@rtfm.mit.edu
+with body
+	send usenet/news.answers/jpeg-faq/part1
+	send usenet/news.answers/jpeg-faq/part2
+
+
+ACKNOWLEDGMENTS
+===============
+
+Thank to Juergen Bruder for providing me with a copy of the common DCT
+algorithm article, only to find out that I had come to the same result
+in a more direct and comprehensible way with a more generative approach.
+
+Thank to Istvan Sebestyen and Joan L. Mitchell for inviting me to the
+ITU JPEG (Study Group 16) meeting in Geneva, Switzerland.
+
+Thank to Thomas Wiegand and Gary Sullivan for inviting me to the
+Joint Video Team (MPEG & ITU) meeting in Geneva, Switzerland.
+
+Thank to Thomas Richter and Daniel Lee for inviting me to the
+ISO/IEC JTC1/SC29/WG1 (previously known as JPEG, together with ITU-T SG16)
+meeting in Berlin, Germany.
+
+Thank to John Korejwa and Massimo Ballerini for inviting me to
+fruitful consultations in Boston, MA and Milan, Italy.
+
+Thank to Hendrik Elstner, Roland Fassauer, Simone Zuck, Guenther
+Maier-Gerber, Walter Stoeber, Fred Schmitz, and Norbert Braunagel
+for corresponding business development.
+
+Thank to Nico Zschach and Dirk Stelling of the technical support team
+at the Digital Images company in Halle for providing me with extra
+equipment for configuration tests.
+
+Thank to Richard F. Lyon (then of Foveon Inc.) for fruitful
+communication about JPEG configuration in Sigma Photo Pro software.
+
+Thank to Andrew Finkenstadt for hosting the ijg.org site.
+
+Last but not least special thank to Thomas G. Lane for the original
+design and development of this singular software package.
+
+
+FILE FORMAT WARS
+================
+
+The ISO/IEC JTC1/SC29/WG1 standards committee (previously known as JPEG,
+together with ITU-T SG16) currently promotes different formats containing
+the name "JPEG" which is misleading because these formats are incompatible
+with original DCT-based JPEG and are based on faulty technologies.
+IJG therefore does not and will not support such momentary mistakes
+(see REFERENCES).
+There exist also distributions under the name "OpenJPEG" promoting such
+kind of formats which is misleading because they don't support original
+JPEG images.
+We have no sympathy for the promotion of inferior formats.  Indeed, one of
+the original reasons for developing this free software was to help force
+convergence on common, interoperable format standards for JPEG files.
+Don't use an incompatible file format!
+(In any case, our decoder will remain capable of reading existing JPEG
+image files indefinitely.)
+
+The ISO committee pretends to be "responsible for the popular JPEG" in their
+public reports which is not true because they don't respond to actual
+requirements for the maintenance of the original JPEG specification.
+Furthermore, the ISO committee pretends to "ensure interoperability" with
+their standards which is not true because their "standards" support only
+application-specific and proprietary use cases and contain mathematically
+incorrect code.
+
+There are currently different distributions in circulation containing the
+name "libjpeg" which is misleading because they don't have the features and
+are incompatible with formats supported by actual IJG libjpeg distributions.
+One of those fakes is released by members of the ISO committee and just uses
+the name of libjpeg for misdirection of people, similar to the abuse of the
+name JPEG as described above, while having nothing in common with actual IJG
+libjpeg distributions and containing mathematically incorrect code.
+The other one claims to be a "derivative" or "fork" of the original libjpeg,
+but violates the license conditions as described under LEGAL ISSUES above
+and violates basic C programming properties.
+We have no sympathy for the release of misleading, incorrect and illegal
+distributions derived from obsolete code bases.
+Don't use an obsolete code base!
+
+According to the UCC (Uniform Commercial Code) law, IJG has the lawful and
+legal right to foreclose on certain standardization bodies and other
+institutions or corporations that knowingly perform substantial and
+systematic deceptive acts and practices, fraud, theft, and damaging of the
+value of the people of this planet without their knowing, willing and
+intentional consent.
+The titles, ownership, and rights of these institutions and all their assets
+are now duly secured and held in trust for the free people of this planet.
+People of the planet, on every country, may have a financial interest in
+the assets of these former principals, agents, and beneficiaries of the
+foreclosed institutions and corporations.
+IJG asserts what is: that each man, woman, and child has unalienable value
+and rights granted and deposited in them by the Creator and not any one of
+the people is subordinate to any artificial principality, corporate fiction
+or the special interest of another without their appropriate knowing,
+willing and intentional consent made by contract or accommodation agreement.
+IJG expresses that which already was.
+The people have already determined and demanded that public administration
+entities, national governments, and their supporting judicial systems must
+be fully transparent, accountable, and liable.
+IJG has secured the value for all concerned free people of the planet.
+
+A partial list of foreclosed institutions and corporations ("Hall of Shame")
+is currently prepared and will be published later.
+
+
+TO DO
+=====
+
+Version 9 is the second release of a new generation JPEG standard
+to overcome the limitations of the original JPEG specification,
+and is the first true source reference JPEG codec.
+More features are being prepared for coming releases...
+
+Please send bug reports, offers of help, etc. to jpeg-info@jpegclub.org.
diff --git a/source/Irrlicht/jpeglib/aclocal.m4 b/source/Irrlicht/jpeglib/aclocal.m4
new file mode 100644
index 00000000..9e947ab4
--- /dev/null
+++ b/source/Irrlicht/jpeglib/aclocal.m4
@@ -0,0 +1,9832 @@
+# generated automatically by aclocal 1.14.1 -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
+You have another version of autoconf.  It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically 'autoreconf'.])])
+
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+#                 Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+#                 Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+#   This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+])
+
+# serial 57 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+       [m4_default([$3],
+		   [m4_fatal([Libtool version $1 or higher is required],
+		             63)])],
+       [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+  *\ * | *\	*)
+    AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
+AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+m4_defun([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+  case $cc_temp in
+    compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+    distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+
+_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
+dnl
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_WITH_SYSROOT])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    _LT_PATH_MAGIC
+  fi
+  ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PREPARE_SED_QUOTE_VARS
+# --------------------------
+# Define a few sed substitution that help us do robust quoting.
+m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
+[# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+])
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from `configure', and `config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool.  Notably,
+# `config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain="$ac_aux_dir/ltmain.sh"
+])# _LT_PROG_LTMAIN
+
+
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the `libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+              [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME.  Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+    [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+	[m4_ifval([$1], [$1], [$2])])
+    lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+    m4_ifval([$4],
+	[lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+    lt_dict_add_subkey([lt_decl_dict], [$2],
+	[tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+  [0], [m4_fatal([$0: too few arguments: $#])],
+  [1], [m4_fatal([$0: too few arguments: $#: $1])],
+  [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+  [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+  [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+    m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+    m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+     m4_if([$2], [],
+	   m4_quote(lt_decl_varnames),
+	m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+			lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to `config.status' so that its
+# declaration there will have the same value as in `configure'.  VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly.  In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+#    ='`$ECHO "$" | $SED "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+    [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags="_LT_TAGS"dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+#    # Some comment about what VAR is for.
+#    visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+					   [description])))[]dnl
+m4_pushdef([_libtool_name],
+    m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+    [0], [_libtool_name=[$]$1],
+    [1], [_libtool_name=$lt_[]$1],
+    [2], [_libtool_name=$lt_[]$1],
+    [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
+# script.  Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+    m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS.  Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into `config.status', and then the shell code to quote escape them in
+# for loops in `config.status'.  Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+	dnl If the libtool generation code has been placed in $CONFIG_LT,
+	dnl instead of duplicating it all over again into config.status,
+	dnl then we will have config.status run $CONFIG_LT later, so it
+	dnl needs to know what name is stored there:
+        [AC_CONFIG_COMMANDS([libtool],
+            [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+    dnl If the libtool generation code is destined for config.status,
+    dnl expand the accumulated commands and init code now:
+    [AC_CONFIG_COMMANDS([libtool],
+        [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
+# ------------------------------------
+# Generate a child script FILE with all initialization necessary to
+# reuse the environment learned by the parent script, and make the
+# file executable.  If COMMENT is supplied, it is inserted after the
+# `#!' sequence but before initialization text begins.  After this
+# macro, additional text can be appended to FILE to form the body of
+# the child script.  The macro ends with non-zero status if the
+# file could not be fully written (such as if the disk is full).
+m4_ifdef([AS_INIT_GENERATED],
+[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
+[m4_defun([_LT_GENERATED_FILE_INIT],
+[m4_require([AS_PREPARE])]dnl
+[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
+[lt_write_fail=0
+cat >$1 <<_ASEOF || lt_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+$2
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$1 <<\_ASEOF || lt_write_fail=1
+AS_SHELL_SANITIZE
+_AS_PREPARE
+exec AS_MESSAGE_FD>&1
+_ASEOF
+test $lt_write_fail = 0 && chmod +x $1[]dnl
+m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
+[# Run this file to recreate a libtool stub with the current configuration.])
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+lt_cl_silent=false
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+  echo
+  AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+\`$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+  -h, --help      print this help, then exit
+  -V, --version   print version number, then exit
+  -q, --quiet     do not print progress messages
+  -d, --debug     don't remove temporary files
+
+Report bugs to ."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2011 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test $[#] != 0
+do
+  case $[1] in
+    --version | --v* | -V )
+      echo "$lt_cl_version"; exit 0 ;;
+    --help | --h* | -h )
+      echo "$lt_cl_help"; exit 0 ;;
+    --debug | --d* | -d )
+      debug=: ;;
+    --quiet | --q* | --silent | --s* | -q )
+      lt_cl_silent=: ;;
+
+    -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try \`$[0] --help' for more information.]) ;;
+
+    *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try \`$[0] --help' for more information.]) ;;
+  esac
+  shift
+done
+
+if $lt_cl_silent; then
+  exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure.  Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+lt_cl_success=:
+test "$silent" = yes &&
+  lt_config_lt_args="$lt_config_lt_args --quiet"
+exec AS_MESSAGE_LOG_FD>/dev/null
+$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+exec AS_MESSAGE_LOG_FD>>config.log
+$lt_cl_success || AS_EXIT(1)
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars.  Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+  m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+  m4_if(_LT_TAG, [C], [
+    # See if we are running on zsh, and set the options which allow our
+    # commands through without removal of \ escapes.
+    if test -n "${ZSH_VERSION+set}" ; then
+      setopt NO_GLOB_SUBST
+    fi
+
+    cfgfile="${ofile}T"
+    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+    $RM "$cfgfile"
+
+    cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+  case $host_os in
+  aix3*)
+    cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+_LT_EOF
+    ;;
+  esac
+
+  _LT_PROG_LTMAIN
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" \
+     || (rm -f "$cfgfile"; exit 1)
+
+  _LT_PROG_REPLACE_SHELLFNS
+
+   mv -f "$cfgfile" "$ofile" ||
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+    PACKAGE='$PACKAGE'
+    VERSION='$VERSION'
+    TIMESTAMP='$TIMESTAMP'
+    RM='$RM'
+    ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+#    autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+  [C],			[_LT_LANG(C)],
+  [C++],		[_LT_LANG(CXX)],
+  [Go],			[_LT_LANG(GO)],
+  [Java],		[_LT_LANG(GCJ)],
+  [Fortran 77],		[_LT_LANG(F77)],
+  [Fortran],		[_LT_LANG(FC)],
+  [Windows Resource],	[_LT_LANG(RC)],
+  [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+    [_LT_LANG($1)],
+    [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+  [LT_SUPPORTED_TAG([$1])dnl
+  m4_append([_LT_TAGS], [$1 ])dnl
+  m4_define([_LT_LANG_]$1[_enabled], [])dnl
+  _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+m4_ifndef([AC_PROG_GO], [
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_GO.  When it is available in    #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+m4_defun([AC_PROG_GO],
+[AC_LANG_PUSH(Go)dnl
+AC_ARG_VAR([GOC],     [Go compiler command])dnl
+AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
+_AC_ARG_VAR_LDFLAGS()dnl
+AC_CHECK_TOOL(GOC, gccgo)
+if test -z "$GOC"; then
+  if test -n "$ac_tool_prefix"; then
+    AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
+  fi
+fi
+if test -z "$GOC"; then
+  AC_CHECK_PROG(GOC, gccgo, gccgo, false)
+fi
+])#m4_defun
+])#m4_ifndef
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+  [LT_LANG(CXX)],
+  [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+  [LT_LANG(F77)],
+  [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+  [LT_LANG(FC)],
+  [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+  [LT_LANG(GCJ)],
+  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+    [LT_LANG(GCJ)],
+    [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+      [LT_LANG(GCJ)],
+      [m4_ifdef([AC_PROG_GCJ],
+	[m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([A][M_PROG_GCJ],
+	[m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([LT_PROG_GCJ],
+	[m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([AC_PROG_GO],
+  [LT_LANG(GO)],
+  [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+  [LT_LANG(RC)],
+  [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+dnl AC_DEFUN([AC_LIBTOOL_RC], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+  case $host_os in
+    rhapsody* | darwin*)
+    AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+    AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+    AC_CHECK_TOOL([LIPO], [lipo], [:])
+    AC_CHECK_TOOL([OTOOL], [otool], [:])
+    AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+    _LT_DECL([], [DSYMUTIL], [1],
+      [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+    _LT_DECL([], [NMEDIT], [1],
+      [Tool to change global to local symbols on Mac OS X])
+    _LT_DECL([], [LIPO], [1],
+      [Tool to manipulate fat objects and archives on Mac OS X])
+    _LT_DECL([], [OTOOL], [1],
+      [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+    _LT_DECL([], [OTOOL64], [1],
+      [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+    AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+      [lt_cv_apple_cc_single_mod=no
+      if test -z "${LT_MULTI_MODULE}"; then
+	# By default we will add the -single_module flag. You can override
+	# by either setting the environment variable LT_MULTI_MODULE
+	# non-empty at configure time, or by adding -multi_module to the
+	# link flags.
+	rm -rf libconftest.dylib*
+	echo "int foo(void){return 1;}" > conftest.c
+	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+	# If there is a non-empty error log, and "single_module"
+	# appears in it, assume the flag caused a linker warning
+        if test -s conftest.err && $GREP single_module conftest.err; then
+	  cat conftest.err >&AS_MESSAGE_LOG_FD
+	# Otherwise, if the output was created with a 0 exit code from
+	# the compiler, it worked.
+	elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+	  lt_cv_apple_cc_single_mod=yes
+	else
+	  cat conftest.err >&AS_MESSAGE_LOG_FD
+	fi
+	rm -rf libconftest.dylib*
+	rm -f conftest.*
+      fi])
+
+    AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+      [lt_cv_ld_exported_symbols_list],
+      [lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+	[lt_cv_ld_exported_symbols_list=yes],
+	[lt_cv_ld_exported_symbols_list=no])
+	LDFLAGS="$save_LDFLAGS"
+    ])
+
+    AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
+      [lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
+      echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+      $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+      echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
+      $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -s conftest.err && $GREP force_load conftest.err; then
+	cat conftest.err >&AS_MESSAGE_LOG_FD
+      elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+	lt_cv_ld_force_load=yes
+      else
+	cat conftest.err >&AS_MESSAGE_LOG_FD
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+    ])
+    case $host_os in
+    rhapsody* | darwin1.[[012]])
+      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+	10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+	10.[[012]]*)
+	  _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+	10.*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    fi
+    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES([TAG])
+# ---------------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+  m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_automatic, $1)=yes
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+    m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
+                  [FC],  [_LT_TAGVAR(compiler_needs_object, $1)=yes])
+  else
+    _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+  fi
+  _LT_TAGVAR(link_all_deplibs, $1)=yes
+  _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+  case $cc_basename in
+     ifort*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test "$_lt_dar_can_shared" = "yes"; then
+    output_verbose_link_cmd=func_echo_all
+    _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+    _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+    _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+    _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+    m4_if([$1], [CXX],
+[   if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+      _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+      _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+    fi
+],[])
+  else
+  _LT_TAGVAR(ld_shlibs, $1)=no
+  fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
+# ----------------------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+# Store the results from the different compilers for each TAGNAME.
+# Allow to override them for all tags through lt_cv_aix_libpath.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
+  [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
+  lt_aix_libpath_sed='[
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }]'
+  _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi],[])
+  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib"
+  fi
+  ])
+  aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
+fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[m4_divert_text([M4SH-INIT], [$1
+])])# _LT_SHELL_INIT
+
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script which will find a shell with a builtin
+# printf (which we can use as an echo command).
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+AC_MSG_CHECKING([how to print strings])
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*" 
+}
+
+case "$ECHO" in
+  printf*) AC_MSG_RESULT([printf]) ;;
+  print*) AC_MSG_RESULT([print -r]) ;;
+  *) AC_MSG_RESULT([cat]) ;;
+esac
+
+m4_ifdef([_AS_DETECT_SUGGESTED],
+[_AS_DETECT_SUGGESTED([
+  test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test "X`printf %s $ECHO`" = "X$ECHO" \
+      || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
+
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_WITH_SYSROOT
+# ----------------
+AC_DEFUN([_LT_WITH_SYSROOT],
+[AC_MSG_CHECKING([for sysroot])
+AC_ARG_WITH([sysroot],
+[  --with-sysroot[=DIR] Search for dependent libraries within DIR
+                        (or the compiler's sysroot if not specified).],
+[], [with_sysroot=no])
+
+dnl lt_sysroot will always be passed unquoted.  We quote it here
+dnl in case the user passed a directory name.
+lt_sysroot=
+case ${with_sysroot} in #(
+ yes)
+   if test "$GCC" = yes; then
+     lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+   fi
+   ;; #(
+ /*)
+   lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+   ;; #(
+ no|'')
+   ;; #(
+ *)
+   AC_MSG_RESULT([${with_sysroot}])
+   AC_MSG_ERROR([The sysroot must be an absolute path.])
+   ;;
+esac
+
+ AC_MSG_RESULT([${lt_sysroot:-no}])
+_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
+[dependent libraries, and in which our libraries should be installed.])])
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+  [AS_HELP_STRING([--disable-libtool-lock],
+    [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.$ac_objext` in
+      *ELF-32*)
+	HPUX_IA64_MODE="32"
+	;;
+      *ELF-64*)
+	HPUX_IA64_MODE="64"
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    if test "$lt_cv_prog_gnu_ld" = yes; then
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -melf32bsmip"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -melf32bmipn32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -melf64bmip"
+	;;
+      esac
+    else
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -32"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -n32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -64"
+	  ;;
+      esac
+    fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+      *32-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_i386_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_i386"
+	    ;;
+	  ppc64-*linux*|powerpc64-*linux*)
+	    LD="${LD-ld} -m elf32ppclinux"
+	    ;;
+	  s390x-*linux*)
+	    LD="${LD-ld} -m elf_s390"
+	    ;;
+	  sparc64-*linux*)
+	    LD="${LD-ld} -m elf32_sparc"
+	    ;;
+	esac
+	;;
+      *64-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_x86_64_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_x86_64"
+	    ;;
+	  ppc*-*linux*|powerpc*-*linux*)
+	    LD="${LD-ld} -m elf64ppc"
+	    ;;
+	  s390*-*linux*|s390*-*tpf*)
+	    LD="${LD-ld} -m elf64_s390"
+	    ;;
+	  sparc*-*linux*)
+	    LD="${LD-ld} -m elf64_sparc"
+	    ;;
+	esac
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+    [AC_LANG_PUSH(C)
+     AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+     AC_LANG_POP])
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+*-*solaris*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*)
+        case $host in
+        i?86-*-solaris*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        sparc*-*-solaris*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+        esac
+        # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
+        if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+          LD="${LD-ld}_sol2"
+        fi
+        ;;
+      *)
+	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+	  LD="${LD-ld} -64"
+	fi
+	;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
+need_locks="$enable_libtool_lock"
+])# _LT_ENABLE_LOCK
+
+
+# _LT_PROG_AR
+# -----------
+m4_defun([_LT_PROG_AR],
+[AC_CHECK_TOOLS(AR, [ar], false)
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
+
+AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
+  [lt_cv_ar_at_file=no
+   AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
+     [echo conftest.$ac_objext > conftest.lst
+      lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
+      AC_TRY_EVAL([lt_ar_try])
+      if test "$ac_status" -eq 0; then
+	# Ensure the archiver fails upon bogus file names.
+	rm -f conftest.$ac_objext libconftest.a
+	AC_TRY_EVAL([lt_ar_try])
+	if test "$ac_status" -ne 0; then
+          lt_cv_ar_at_file=@
+        fi
+      fi
+      rm -f conftest.* libconftest.a
+     ])
+  ])
+
+if test "x$lt_cv_ar_at_file" = xno; then
+  archiver_list_spec=
+else
+  archiver_list_spec=$lt_cv_ar_at_file
+fi
+_LT_DECL([], [archiver_list_spec], [1],
+  [How to feed a file listing to the archiver])
+])# _LT_PROG_AR
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[_LT_PROG_AR
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+    [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+    [Commands used to build an old-style archive])
+_LT_DECL([], [lock_old_archive_extraction], [0],
+    [Whether to use a lock for old archive extraction])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#		[OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$3"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       $2=yes
+     fi
+   fi
+   $RM conftest*
+])
+
+if test x"[$]$2" = xyes; then
+    m4_if([$5], , :, [$5])
+else
+    m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#                  [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $3"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&AS_MESSAGE_LOG_FD
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         $2=yes
+       fi
+     else
+       $2=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+    m4_if([$4], , :, [$4])
+else
+    m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+  i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw* | cegcc*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  os2*)
+    # The test takes a long time on OS/2.
+    lt_cv_sys_max_cmd_len=8192
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[	 ]]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      # Make teststring a little bigger before we do anything with it.
+      # a 1K string should be a reasonable start.
+      for i in 1 2 3 4 5 6 7 8 ; do
+        teststring=$teststring$teststring
+      done
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      # If test is not a shell built-in, we'll probably end up computing a
+      # maximum length that is only half of the actual maximum length, but
+      # we can't tell.
+      while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+	         = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+	      test $i != 17 # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      # Only check the string length outside the loop.
+      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on
+      # massive amounts of additional arguments before passing them to the
+      # linker.  It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+  AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+    [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+#                      ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+  [$4]
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+[#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include 
+#endif
+
+#include 
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}]
+_LT_EOF
+  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) $1 ;;
+      x$lt_dlneed_uscore) $2 ;;
+      x$lt_dlunknown|x*) $3 ;;
+    esac
+  else :
+    # compilation failed
+    $3
+  fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32* | cegcc*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+    ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+    ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ])
+    ;;
+
+  *)
+    AC_CHECK_FUNC([shl_load],
+	  [lt_cv_dlopen="shl_load"],
+      [AC_CHECK_LIB([dld], [shl_load],
+	    [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
+	[AC_CHECK_FUNC([dlopen],
+	      [lt_cv_dlopen="dlopen"],
+	  [AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+	    [AC_CHECK_LIB([svld], [dlopen],
+		  [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+	      [AC_CHECK_LIB([dld], [dld_link],
+		    [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
+	      ])
+	    ])
+	  ])
+	])
+      ])
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    AC_CACHE_CHECK([whether a program can dlopen itself],
+	  lt_cv_dlopen_self, [dnl
+	  _LT_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+	    lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+    ])
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+	  lt_cv_dlopen_self_static, [dnl
+	  _LT_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+	    lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
+      ])
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+	 [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+	 [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+	 [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+     fi
+   fi
+   chmod u+w . 2>&AS_MESSAGE_LOG_FD
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+	[Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links="nottested"
+if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  AC_MSG_CHECKING([if we can lock with hard links])
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  AC_MSG_RESULT([$hard_links])
+  if test "$hard_links" = no; then
+    AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+         [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
+  [Define to the sub-directory in which libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+   test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+   test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+     test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
+    # Linking always hardcodes the temporary library directory.
+    _LT_TAGVAR(hardcode_action, $1)=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    _LT_TAGVAR(hardcode_action, $1)=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
+   test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+    [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP" ; then
+      striplib="$STRIP -x"
+      old_striplib="$STRIP -S"
+      AC_MSG_RESULT([yes])
+    else
+      AC_MSG_RESULT([no])
+    fi
+    ;;
+  *)
+    AC_MSG_RESULT([no])
+    ;;
+  esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+	[], [
+if test "$GCC" = yes; then
+  case $host_os in
+    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+    *) lt_awk_arg="/^libraries:/" ;;
+  esac
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
+    *) lt_sed_strip_eq="s,=/,/,g" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary.
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+    else
+      test -d "$lt_sys_path" && \
+	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+  lt_foo="";
+  lt_count=0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo="/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+  if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix[[4-9]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[[01]] | aix4.[[01]].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib.so
+      # instead of lib.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[[45]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$cc_basename in
+  yes,*)
+    # gcc
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+m4_if([$1], [],[
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    dynamic_linker='Win32 ld.exe'
+    ;;
+
+  *,cl*)
+    # Native MSVC
+    libname_spec='$name'
+    soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+    library_names_spec='${libname}.dll.lib'
+
+    case $build_os in
+    mingw*)
+      sys_lib_search_path_spec=
+      lt_save_ifs=$IFS
+      IFS=';'
+      for lt_path in $LIB
+      do
+        IFS=$lt_save_ifs
+        # Let DOS variable expansion print the short 8.3 style file name.
+        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+      done
+      IFS=$lt_save_ifs
+      # Convert to MSYS style.
+      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
+      ;;
+    cygwin*)
+      # Convert to unix form, then to dos form, then back to unix form
+      # but this time dos style (no spaces!) so that the unix form looks
+      # like /cygdrive/c/PROGRA~1:/cygdr...
+      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      ;;
+    *)
+      sys_lib_search_path_spec="$LIB"
+      if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
+        # It is most probably a Windows format PATH.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      # FIXME: find the short name or the path components, as spaces are
+      # common. (e.g. "Program Files" -> "PROGRA~1")
+      ;;
+    esac
+
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+    dynamic_linker='Win32 link.exe'
+    ;;
+
+  *)
+    # Assume MSVC wrapper
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    dynamic_linker='Win32 ld.exe'
+    ;;
+  esac
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[[23]].*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2.*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+haiku*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[[3-9]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux # correct to gnu/linux during the next big refactor
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
+    [lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+	 LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+      [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+	 [lt_cv_shlibpath_overrides_runpath=yes])])
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+    ])
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
+    *)				need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[[89]] | openbsd2.[[89]].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux # correct to gnu/linux during the next big refactor
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+    [Variables whose values should be saved in libtool wrapper scripts and
+    restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+    [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0],  [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+    [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+    [[List of archive names.  First name is the real one, the rest are links.
+    The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+    [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [install_override_mode], [1],
+    [Permission mode override for installation of shared libraries])
+_LT_DECL([], [postinstall_cmds], [2],
+    [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+    [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+    [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+    [[As "finish_cmds", except a single script fragment to be evaled but
+    not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+    [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+    [Compile-time system search path for libraries])
+_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
+    [Run-time system search path for libraries])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program which can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] |  ?:[\\/]*])
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word.  This closes a longstanding sh security hole.
+  ac_dummy="m4_if([$2], , $PATH, [$2])"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$1; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  AC_MSG_RESULT($MAGIC_CMD)
+else
+  AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+	 [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program which can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+  else
+    MAGIC_CMD=:
+  fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
+
+AC_ARG_WITH([gnu-ld],
+    [AS_HELP_STRING([--with-gnu-ld],
+	[assume the C compiler uses GNU ld @<:@default=no@:>@])],
+    [test "$withval" = no || with_gnu_ld=yes],
+    [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by $CC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]]* | ?:[[\\/]]*)
+      re_direlt='/[[^/]][[^/]]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    # Keep this pattern in sync with the one in func_win32_libid.
+    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+cegcc*)
+  # use the weaker test based on 'objdump'. See mingw*.
+  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+haiku*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[[3-9]]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+*nto* | *qnx*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+openbsd*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+tpf*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+])
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+  case $host_os in
+  mingw* | pw32*)
+    if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+      want_nocaseglob=yes
+    else
+      file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
+    fi
+    ;;
+  esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+    [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+    [Command to use when deplibs_check_method = "file_magic"])
+_LT_DECL([], [file_magic_glob], [1],
+    [How to find potential files when deplibs_check_method = "file_magic"])
+_LT_DECL([], [want_nocaseglob], [1],
+    [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_nm_to_check="${ac_tool_prefix}nm"
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS="$lt_save_ifs"
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm="$ac_dir/$lt_tmp_nm"
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+	# Check to see if the nm accepts a BSD-compat flag.
+	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
+	#   nm: unknown option "B" ignored
+	# Tru64's nm complains that /dev/null is an invalid object file
+	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+	*/dev/null* | *'Invalid file or object type'*)
+	  lt_cv_path_NM="$tmp_nm -B"
+	  break
+	  ;;
+	*)
+	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	  */dev/null*)
+	    lt_cv_path_NM="$tmp_nm -p"
+	    break
+	    ;;
+	  *)
+	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	    continue # so that we can try to find one that supports BSD flags
+	    ;;
+	  esac
+	  ;;
+	esac
+      fi
+    done
+    IFS="$lt_save_ifs"
+  done
+  : ${lt_cv_path_NM=no}
+fi])
+if test "$lt_cv_path_NM" != "no"; then
+  NM="$lt_cv_path_NM"
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
+    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+  AC_SUBST([DUMPBIN])
+  if test "$DUMPBIN" != ":"; then
+    NM="$DUMPBIN"
+  fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+  [lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
+  cat conftest.out >&AS_MESSAGE_LOG_FD
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+# --------------------------------
+# how to determine the name of the shared library
+# associated with a specific link library.
+#  -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+m4_require([_LT_DECL_DLLTOOL])
+AC_CACHE_CHECK([how to associate runtime and link libraries],
+lt_cv_sharedlib_from_linklib_cmd,
+[lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+  # two different shell functions defined in ltmain.sh
+  # decide which to use based on capabilities of $DLLTOOL
+  case `$DLLTOOL --help 2>&1` in
+  *--identify-strict*)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+    ;;
+  *)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+    ;;
+  esac
+  ;;
+*)
+  # fallback: assume linklib IS sharedlib
+  lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+  ;;
+esac
+])
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
+    [Command to associate shared and link libraries])
+])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+
+
+# _LT_PATH_MANIFEST_TOOL
+# ----------------------
+# locate the manifest tool
+m4_defun([_LT_PATH_MANIFEST_TOOL],
+[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
+  [lt_cv_path_mainfest_tool=no
+  echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
+  $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+    lt_cv_path_mainfest_tool=yes
+  fi
+  rm -f conftest*])
+if test "x$lt_cv_path_mainfest_tool" != xyes; then
+  MANIFEST_TOOL=:
+fi
+_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
+])# _LT_PATH_MANIFEST_TOOL
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
+  # These system don't have libm, or don't need it
+  ;;
+*-ncr-sysv4.3*)
+  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+  ;;
+*)
+  AC_CHECK_LIB(m, cos, LIBM="-lm")
+  ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+  case $cc_basename in
+  nvcc*)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
+  esac
+
+  _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+    lt_cv_prog_compiler_rtti_exceptions,
+    [-fno-rtti -fno-exceptions], [],
+    [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+	[Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[[BCDT]]'
+  ;;
+cygwin* | mingw* | pw32* | cegcc*)
+  symcode='[[ABCDGISTW]]'
+  ;;
+hpux*)
+  if test "$host_cpu" = ia64; then
+    symcode='[[ABCDEGRST]]'
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[[BCDEGRST]]'
+  ;;
+osf*)
+  symcode='[[BCDEGQRST]]'
+  ;;
+solaris*)
+  symcode='[[BDRT]]'
+  ;;
+sco3.2v5*)
+  symcode='[[DT]]'
+  ;;
+sysv4.2uw2*)
+  symcode='[[DT]]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[[ABDT]]'
+  ;;
+sysv4)
+  symcode='[[DFNSTU]]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+    # Fake it for dumpbin and say T for any non-static function
+    # and D for any global variable.
+    # Also find C++ and __fastcall symbols from MSVC++,
+    # which start with @ or ?.
+    lt_cv_sys_global_symbol_pipe="$AWK ['"\
+"     {last_section=section; section=\$ 3};"\
+"     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     \$ 0!~/External *\|/{next};"\
+"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+"     {if(hide[section]) next};"\
+"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+"     ' prfx=^$ac_symprfx]"
+  else
+    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[	 ]]\($symcode$symcode*\)[[	 ]][[	 ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+  fi
+  lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+  if AC_TRY_EVAL(ac_compile); then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+	mv -f "$nlist"T "$nlist"
+      else
+	rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+	  cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT@&t@_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data.  */
+# define LT@&t@_DLSYM_CONST
+#else
+# define LT@&t@_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+	  # Now generate the symbol file.
+	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+	  cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols.  */
+LT@&t@_DLSYM_CONST struct {
+  const char *name;
+  void       *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+  { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+	  cat <<\_LT_EOF >> conftest.$ac_ext
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+	  # Now try linking the two files.
+	  mv conftest.$ac_objext conftstm.$ac_objext
+	  lt_globsym_save_LIBS=$LIBS
+	  lt_globsym_save_CFLAGS=$CFLAGS
+	  LIBS="conftstm.$ac_objext"
+	  CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+	  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+	    pipe_works=yes
+	  fi
+	  LIBS=$lt_globsym_save_LIBS
+	  CFLAGS=$lt_globsym_save_CFLAGS
+	else
+	  echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+	fi
+      else
+	echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+    fi
+  else
+    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  AC_MSG_RESULT(failed)
+else
+  AC_MSG_RESULT(ok)
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
+  nm_file_list_spec='@'
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+    [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+    [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_c_name_address],
+    [lt_cv_sys_global_symbol_to_c_name_address], [1],
+    [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+    [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+    [Transform the output of nm in a C name address pair when lib prefix is needed])
+_LT_DECL([], [nm_file_list_spec], [1],
+    [Specify filename containing input files for $NM])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+m4_if([$1], [CXX], [
+  # C++ specific cases for pic, static, wl, etc.
+  if test "$GXX" = yes; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | cygwin* | os2* | pw32* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+      ;;
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+    *qnx* | *nto*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix[[4-9]]*)
+	# All AIX code is PIC.
+	if test "$host_cpu" = ia64; then
+	  # AIX 5 now supports IA64 processor
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	else
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+	fi
+	;;
+      chorus*)
+	case $cc_basename in
+	cxch68*)
+	  # Green Hills C++ Compiler
+	  # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+	  ;;
+	esac
+	;;
+      mingw* | cygwin* | os2* | pw32* | cegcc*)
+	# This hack is so that the source file can tell whether it is being
+	# built for inclusion in a dll (and should export symbols for example).
+	m4_if([$1], [GCJ], [],
+	  [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+	;;
+      dgux*)
+	case $cc_basename in
+	  ec++*)
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  ghcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      freebsd* | dragonfly*)
+	# FreeBSD uses GNU C++
+	;;
+      hpux9* | hpux10* | hpux11*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+	    if test "$host_cpu" != ia64; then
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	    fi
+	    ;;
+	  aCC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+	    case $host_cpu in
+	    hppa*64*|ia64*)
+	      # +Z the default
+	      ;;
+	    *)
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	      ;;
+	    esac
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      interix*)
+	# This is c89, which is MS Visual C++ (no shared libs)
+	# Anyone wants to do a port?
+	;;
+      irix5* | irix6* | nonstopux*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    # CC pic flag -KPIC is the default.
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      linux* | k*bsd*-gnu | kopensolaris*-gnu)
+	case $cc_basename in
+	  KCC*)
+	    # KAI C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	    ;;
+	  ecpc* )
+	    # old Intel C++ for x86_64 which still supported -KPIC.
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	    ;;
+	  icpc* )
+	    # Intel C++, used to be incompatible with GCC.
+	    # ICC 10 doesn't accept -KPIC any more.
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	    ;;
+	  pgCC* | pgcpp*)
+	    # Portland Group C++ compiler
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	  cxx*)
+	    # Compaq C++
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
+	    # IBM XL 8.0, 9.0 on PPC and BlueGene
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+      lynxos*)
+	;;
+      m88k*)
+	;;
+      mvs*)
+	case $cc_basename in
+	  cxx*)
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      netbsd*)
+	;;
+      *qnx* | *nto*)
+        # QNX uses GNU C++, but need to define -shared option too, otherwise
+        # it will coredump.
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+        ;;
+      osf3* | osf4* | osf5*)
+	case $cc_basename in
+	  KCC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    ;;
+	  RCC*)
+	    # Rational C++ 2.4.1
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  cxx*)
+	    # Digital/Compaq C++
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      psos*)
+	;;
+      solaris*)
+	case $cc_basename in
+	  CC* | sunCC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	    ;;
+	  gcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sunos4*)
+	case $cc_basename in
+	  CC*)
+	    # Sun C++ 4.x
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	  lcc*)
+	    # Lucid
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	esac
+	;;
+      tandem*)
+	case $cc_basename in
+	  NCC*)
+	    # NonStop-UX NCC 3.20
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      vxworks*)
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+	;;
+    esac
+  fi
+],
+[
+  if test "$GCC" = yes; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	# +Z the default
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
+      if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
+      fi
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      else
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC (with -KPIC) is the default.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu | kopensolaris*-gnu)
+      case $cc_basename in
+      # old Intel for x86_64 which still supported -KPIC.
+      ecc*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+	;;
+      nagfor*)
+	# NAG Fortran compiler
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	;;
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+	# which looks to be a dead project)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+        ;;
+      ccc*)
+        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+        # All Alpha code is PIC.
+        _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+        ;;
+      xl* | bgxl* | bgf* | mpixl*)
+	# IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+	;;
+      *)
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
+	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+	  ;;
+	*Sun\ F* | *Sun*Fortran*)
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	  ;;
+	*Sun\ C*)
+	  # Sun C 5.9
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  ;;
+        *Intel*\ [[CF]]*Compiler*)
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	  ;;
+	*Portland\ Group*)
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  ;;
+	esac
+	;;
+      esac
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # All OSF/1 code is PIC.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    rdos*)
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    unicos*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+    esac
+  fi
+])
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+    ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+    ;;
+esac
+
+AC_CACHE_CHECK([for $compiler option to produce PIC],
+  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
+  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+  _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+    [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+    [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+    [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+     "" | " "*) ;;
+     *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+     esac],
+    [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+     _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+	[Additional compiler flags for building library objects])
+
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+	[How to pass a linker flag through the compiler])
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+  _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+  $lt_tmp_static_flag,
+  [],
+  [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+	[Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  case $host_os in
+  aix[[4-9]]*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to AIX nm, but means don't demangle with GNU nm
+    # Also, AIX nm treats weak defined symbols like other global defined
+    # symbols, whereas GNU nm marks them as "W".
+    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    else
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+    ;;
+  cygwin* | mingw* | cegcc*)
+    case $cc_basename in
+    cl*)
+      _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+      ;;
+    *)
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+      ;;
+    esac
+    ;;
+  *)
+    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+    ;;
+  esac
+], [
+  runpath_var=
+  _LT_TAGVAR(allow_undefined_flag, $1)=
+  _LT_TAGVAR(always_export_symbols, $1)=no
+  _LT_TAGVAR(archive_cmds, $1)=
+  _LT_TAGVAR(archive_expsym_cmds, $1)=
+  _LT_TAGVAR(compiler_needs_object, $1)=no
+  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+  _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  _LT_TAGVAR(hardcode_automatic, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+  _LT_TAGVAR(hardcode_libdir_separator, $1)=
+  _LT_TAGVAR(hardcode_minus_L, $1)=no
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  _LT_TAGVAR(inherit_rpath, $1)=no
+  _LT_TAGVAR(link_all_deplibs, $1)=unknown
+  _LT_TAGVAR(module_cmds, $1)=
+  _LT_TAGVAR(module_expsym_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+  _LT_TAGVAR(thread_safe_flag_spec, $1)=
+  _LT_TAGVAR(whole_archive_flag_spec, $1)=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  _LT_TAGVAR(include_expsyms, $1)=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  _LT_TAGVAR(ld_shlibs, $1)=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test "$with_gnu_ld" = yes; then
+    case $host_os in
+      aix*)
+	# The AIX port of GNU ld has always aspired to compatibility
+	# with the native linker.  However, as the warning in the GNU ld
+	# block says, versions before 2.19.5* couldn't really create working
+	# shared libraries, regardless of the interface used.
+	case `$LD -v 2>&1` in
+	  *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+	  *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
+	  *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
+	  *)
+	    lt_use_gnu_ld_interface=yes
+	    ;;
+	esac
+	;;
+      *)
+	lt_use_gnu_ld_interface=yes
+	;;
+    esac
+  fi
+
+  if test "$lt_use_gnu_ld_interface" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[[3-9]]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	# Joseph Beckenbach  says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	_LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+      # as there is no search path for DLLs.
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=no
+      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file (1st line
+	# is EXPORTS), use it as is; otherwise, prepend...
+	_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	  cp $export_symbols $output_objdir/$soname.def;
+	else
+	  echo EXPORTS > $output_objdir/$soname.def;
+	  cat $export_symbols >> $output_objdir/$soname.def;
+	fi~
+	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    haiku*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    interix[[3-9]]*)
+      _LT_TAGVAR(hardcode_direct, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+      tmp_diet=no
+      if test "$host_os" = linux-dietlibc; then
+	case $cc_basename in
+	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
+	esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+	 && test "$tmp_diet" = no
+      then
+	tmp_addflag=' $pic_flag'
+	tmp_sharedflag='-shared'
+	case $cc_basename,$host_cpu in
+        pgcc*)				# Portland Group C compiler
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag'
+	  ;;
+	pgf77* | pgf90* | pgf95* | pgfortran*)
+					# Portland Group f77 and f90 compilers
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag -Mnomain' ;;
+	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
+	  tmp_addflag=' -i_dynamic' ;;
+	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+	ifc* | ifort*)			# Intel Fortran compiler
+	  tmp_addflag=' -nofor_main' ;;
+	lf95*)				# Lahey Fortran 8.1
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)=
+	  tmp_sharedflag='--shared' ;;
+	xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+	  tmp_sharedflag='-qmkshrobj'
+	  tmp_addflag= ;;
+	nvcc*)	# Cuda Compiler Driver 2.2
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  _LT_TAGVAR(compiler_needs_object, $1)=yes
+	  ;;
+	esac
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)			# Sun C 5.9
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  _LT_TAGVAR(compiler_needs_object, $1)=yes
+	  tmp_sharedflag='-G' ;;
+	*Sun\ F*)			# Sun Fortran 8.3
+	  tmp_sharedflag='-G' ;;
+	esac
+	_LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+        if test "x$supports_anon_versioning" = xyes; then
+          _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+	    cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	    echo "local: *; };" >> $output_objdir/$libname.ver~
+	    $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+        fi
+
+	case $cc_basename in
+	xlf* | bgf* | bgxlf* | mpixlf*)
+	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+	  if test "x$supports_anon_versioning" = xyes; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+	      cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	      echo "local: *; };" >> $output_objdir/$libname.ver~
+	      $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+	  fi
+	  ;;
+	esac
+      else
+        _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+	;;
+	*)
+	  # For security reasons, it is highly recommended that you always
+	  # use absolute paths for naming shared libraries, and exclude the
+	  # DT_RUNPATH tag from executables and libraries.  But doing so
+	  # requires that you compile everything twice, which is a pain.
+	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	  else
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	  fi
+	;;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
+
+    if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
+      runpath_var=
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	_LT_TAGVAR(hardcode_direct, $1)=unsupported
+      fi
+      ;;
+
+    aix[[4-9]]*)
+      if test "$host_cpu" = ia64; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=""
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+	# Also, AIX nm treats weak defined symbols like other global
+	# defined symbols, whereas GNU nm marks them as "W".
+	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	else
+	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# need to do runtime linking.
+	case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+	  for ld_flag in $LDFLAGS; do
+	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+	    aix_use_runtimelinking=yes
+	    break
+	  fi
+	  done
+	  ;;
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      _LT_TAGVAR(archive_cmds, $1)=''
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+      if test "$GCC" = yes; then
+	case $host_os in aix4.[[012]]|aix4.[[012]].*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	  # We have reworked collect2
+	  :
+	  else
+	  # We have old collect2
+	  _LT_TAGVAR(hardcode_direct, $1)=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	  _LT_TAGVAR(hardcode_libdir_separator, $1)=
+	  fi
+	  ;;
+	esac
+	shared_flag='-shared'
+	if test "$aix_use_runtimelinking" = yes; then
+	  shared_flag="$shared_flag "'${wl}-G'
+	fi
+      else
+	# not using gcc
+	if test "$host_cpu" = ia64; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag='${wl}-G'
+	  else
+	    shared_flag='${wl}-bM:SRE'
+	  fi
+	fi
+      fi
+
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      if test "$aix_use_runtimelinking" = yes; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	_LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        _LT_SYS_MODULE_PATH_AIX([$1])
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+      else
+	if test "$host_cpu" = ia64; then
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+	  _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an
+	 # empty executable.
+	 _LT_SYS_MODULE_PATH_AIX([$1])
+	 _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+	  _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+	  if test "$with_gnu_ld" = yes; then
+	    # We only use this code for GNU lds that support --whole-archive.
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	  else
+	    # Exported symbols can be pulled into shared objects from archives
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+	  fi
+	  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	  # This is similar to how AIX traditionally builds its shared libraries.
+	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[[45]]*)
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      case $cc_basename in
+      cl*)
+	# Native MSVC
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	_LT_TAGVAR(always_export_symbols, $1)=yes
+	_LT_TAGVAR(file_list_spec, $1)='@'
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=".dll"
+	# FIXME: Setting linknames here is a bad hack.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+	_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	    sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+	  else
+	    sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+	  fi~
+	  $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+	  linknames='
+	# The linker will not automatically build a static lib if we build a DLL.
+	# _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+	_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	_LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+	_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+	# Don't use ranlib
+	_LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+	_LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+	  lt_tool_outputfile="@TOOL_OUTPUT@"~
+	  case $lt_outputfile in
+	    *.exe|*.EXE) ;;
+	    *)
+	      lt_outputfile="$lt_outputfile.exe"
+	      lt_tool_outputfile="$lt_tool_outputfile.exe"
+	      ;;
+	  esac~
+	  if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+	    $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+	    $RM "$lt_outputfile.manifest";
+	  fi'
+	;;
+      *)
+	# Assume MSVC wrapper
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=".dll"
+	# FIXME: Setting linknames here is a bad hack.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+	# The linker will automatically build a .lib file if we build a DLL.
+	_LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+	# FIXME: Should let the user specify the lib program.
+	_LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+	_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+      _LT_DARWIN_LINKER_FEATURES($1)
+      ;;
+
+    dgux*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2.*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      ;;
+
+    hpux10*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test "$with_gnu_ld" = no; then
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
+	_LT_TAGVAR(hardcode_direct, $1)=yes
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	# hardcode_minus_L: Not really in the search PATH,
+	# but as the default location of the library.
+	_LT_TAGVAR(hardcode_minus_L, $1)=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	case $host_cpu in
+	hppa*64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case $host_cpu in
+	hppa*64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	m4_if($1, [], [
+	  # Older versions of the 11.00 compiler do not understand -b yet
+	  # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+	  _LT_LINKER_OPTION([if $CC understands -b],
+	    _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
+	    [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+	    [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
+	  [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+	  ;;
+	esac
+      fi
+      if test "$with_gnu_ld" = no; then
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	case $host_cpu in
+	hppa*64*|ia64*)
+	  _LT_TAGVAR(hardcode_direct, $1)=no
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	  ;;
+	*)
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	# Try to use the -exported_symbol ld option, if it does not
+	# work, assume that -exports_file does not work either and
+	# implicitly export all symbols.
+	# This should be the same for all languages, so no per-tag cache variable.
+	AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
+	  [lt_cv_irix_exported_symbol],
+	  [save_LDFLAGS="$LDFLAGS"
+	   LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+	   AC_LINK_IFELSE(
+	     [AC_LANG_SOURCE(
+	        [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
+			      [C++], [[int foo (void) { return 0; }]],
+			      [Fortran 77], [[
+      subroutine foo
+      end]],
+			      [Fortran], [[
+      subroutine foo
+      end]])])],
+	      [lt_cv_irix_exported_symbol=yes],
+	      [lt_cv_irix_exported_symbol=no])
+           LDFLAGS="$save_LDFLAGS"])
+	if test "$lt_cv_irix_exported_symbol" = yes; then
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+	fi
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(inherit_rpath, $1)=yes
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+	_LT_TAGVAR(hardcode_direct, $1)=yes
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	else
+	  case $host_os in
+	   openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+	     _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	     ;;
+	   *)
+	     _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	     ;;
+	  esac
+	fi
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    os2*)
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      else
+	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+	$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+      if test "$GCC" = yes; then
+	wlarc='${wl}'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+	case `$CC -V 2>&1` in
+	*"Compilers 5.0"*)
+	  wlarc=''
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+	  ;;
+	*)
+	  wlarc='${wl}'
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+	  ;;
+	esac
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      case $host_os in
+      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+      *)
+	# The compiler driver will combine and reorder linker options,
+	# but understands `-z linker_flag'.  GCC discards it without `$wl',
+	# but is careful enough not to reorder.
+	# Supported since Solaris 2.6 (maybe 2.5.1?)
+	if test "$GCC" = yes; then
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+	else
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+	fi
+	;;
+      esac
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+	  _LT_TAGVAR(hardcode_direct, $1)=no
+        ;;
+	motorola)
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4.3*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	_LT_TAGVAR(ld_shlibs, $1)=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We can NOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      _LT_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    esac
+
+    if test x$host_vendor = xsni; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
+	;;
+      esac
+    fi
+  fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+    [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+  # Assume -lc should be added
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $_LT_TAGVAR(archive_cmds, $1) in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      AC_CACHE_CHECK([whether -lc should be explicitly linked in],
+	[lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
+	[$RM conftest*
+	echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+	if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+	  soname=conftest
+	  lib=conftest
+	  libobjs=conftest.$ac_objext
+	  deplibs=
+	  wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+	  pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+	  compiler_flags=-v
+	  linker_flags=-v
+	  verstring=
+	  output_objdir=.
+	  libname=conftest
+	  lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+	  _LT_TAGVAR(allow_undefined_flag, $1)=
+	  if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+	  then
+	    lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	  else
+	    lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	  fi
+	  _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+	else
+	  cat conftest.err 1>&5
+	fi
+	$RM conftest*
+	])
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+    [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+    [enable_shared_with_static_runtimes], [0],
+    [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+    [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+    [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+    [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+    [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+    [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+    [Commands used to build a loadable module if different from building
+    a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+    [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+    [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+    [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+    [Flag to hardcode $libdir into a binary during linking.
+    This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+    [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+    DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+    DIR into the resulting binary and the resulting library dependency is
+    "absolute", i.e impossible to change by setting ${shlibpath_var} if the
+    library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+    [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+    [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+    [Set to "yes" if building a shared library automatically hardcodes DIR
+    into the library and all subsequent libraries and executables linked
+    against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+    [Set to yes if linker adds runtime paths of dependent libraries
+    to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+    [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [always_export_symbols], [0],
+    [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+    [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+    [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+    [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+    [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [postlink_cmds], [2],
+    [Commands necessary for finishing linking programs])
+_LT_TAGDECL([], [file_list_spec], [1],
+    [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl    [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_SYS_DYNAMIC_LINKER($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+  LT_SYS_DLOPEN_SELF
+  _LT_CMD_STRIPLIB
+
+  # Report which library types will actually be built
+  AC_MSG_CHECKING([if libtool supports shared libraries])
+  AC_MSG_RESULT([$can_build_shared])
+
+  AC_MSG_CHECKING([whether to build shared libraries])
+  test "$can_build_shared" = "no" && enable_shared=no
+
+  # On AIX, shared libraries and static libraries use the same namespace, and
+  # are all built from PIC.
+  case $host_os in
+  aix3*)
+    test "$enable_shared" = yes && enable_static=no
+    if test -n "$RANLIB"; then
+      archive_cmds="$archive_cmds~\$RANLIB \$lib"
+      postinstall_cmds='$RANLIB $lib'
+    fi
+    ;;
+
+  aix[[4-9]]*)
+    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+      test "$enable_shared" = yes && enable_static=no
+    fi
+    ;;
+  esac
+  AC_MSG_RESULT([$enable_shared])
+
+  AC_MSG_CHECKING([whether to build static libraries])
+  # Make sure either enable_shared or enable_static is yes.
+  test "$enable_shared" = yes || enable_static=yes
+  AC_MSG_RESULT([$enable_static])
+
+  _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC="$lt_save_CC"
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+    (test "X$CXX" != "Xg++"))) ; then
+  AC_PROG_CXXCPP
+else
+  _lt_caught_CXX_error=yes
+fi
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="int some_variable = 0;"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC=$CC
+  lt_save_CFLAGS=$CFLAGS
+  lt_save_LD=$LD
+  lt_save_GCC=$GCC
+  GCC=$GXX
+  lt_save_with_gnu_ld=$with_gnu_ld
+  lt_save_path_LD=$lt_cv_path_LD
+  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+  else
+    $as_unset lt_cv_prog_gnu_ld
+  fi
+  if test -n "${lt_cv_path_LDCXX+set}"; then
+    lt_cv_path_LD=$lt_cv_path_LDCXX
+  else
+    $as_unset lt_cv_path_LD
+  fi
+  test -z "${LDCXX+set}" || LD=$LDCXX
+  CC=${CXX-"c++"}
+  CFLAGS=$CXXFLAGS
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    # We don't want -fno-exception when compiling C++ code, so set the
+    # no_builtin_flag separately
+    if test "$GXX" = yes; then
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+    else
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+    fi
+
+    if test "$GXX" = yes; then
+      # Set up default GNU C++ configuration
+
+      LT_PATH_LD
+
+      # Check if GNU C++ uses GNU ld as the underlying linker, since the
+      # archiving commands below assume that GNU ld is being used.
+      if test "$with_gnu_ld" = yes; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+        # If archive_cmds runs LD, not CC, wlarc should be empty
+        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+        #     investigate it a little bit more. (MM)
+        wlarc='${wl}'
+
+        # ancient GNU ld didn't support --whole-archive et. al.
+        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+	  $GREP 'no-whole-archive' > /dev/null; then
+          _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+        else
+          _LT_TAGVAR(whole_archive_flag_spec, $1)=
+        fi
+      else
+        with_gnu_ld=no
+        wlarc=
+
+        # A generic and very simple default shared library creation
+        # command for GNU C++ for the case where it uses the native
+        # linker, instead of GNU ld.  If possible, this setting should
+        # overridden to take advantage of the native linker features on
+        # the platform it is being used on.
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+      fi
+
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+    else
+      GXX=no
+      with_gnu_ld=no
+      wlarc=
+    fi
+
+    # PORTME: fill in a description of your system's C++ link characteristics
+    AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+    _LT_TAGVAR(ld_shlibs, $1)=yes
+    case $host_os in
+      aix3*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+      aix[[4-9]]*)
+        if test "$host_cpu" = ia64; then
+          # On IA64, the linker does run time linking by default, so we don't
+          # have to do anything special.
+          aix_use_runtimelinking=no
+          exp_sym_flag='-Bexport'
+          no_entry_flag=""
+        else
+          aix_use_runtimelinking=no
+
+          # Test if we are trying to use run time linking or normal
+          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+          # need to do runtime linking.
+          case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+	    for ld_flag in $LDFLAGS; do
+	      case $ld_flag in
+	      *-brtl*)
+	        aix_use_runtimelinking=yes
+	        break
+	        ;;
+	      esac
+	    done
+	    ;;
+          esac
+
+          exp_sym_flag='-bexport'
+          no_entry_flag='-bnoentry'
+        fi
+
+        # When large executables or shared objects are built, AIX ld can
+        # have problems creating the table of contents.  If linking a library
+        # or program results in "error TOC overflow" add -mminimal-toc to
+        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+        _LT_TAGVAR(archive_cmds, $1)=''
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+        if test "$GXX" = yes; then
+          case $host_os in aix4.[[012]]|aix4.[[012]].*)
+          # We only want to do this on AIX 4.2 and lower, the check
+          # below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	     strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	    # We have reworked collect2
+	    :
+	  else
+	    # We have old collect2
+	    _LT_TAGVAR(hardcode_direct, $1)=unsupported
+	    # It fails to find uninstalled libraries when the uninstalled
+	    # path is not listed in the libpath.  Setting hardcode_minus_L
+	    # to unsupported forces relinking
+	    _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=
+	  fi
+          esac
+          shared_flag='-shared'
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag="$shared_flag "'${wl}-G'
+	  fi
+        else
+          # not using gcc
+          if test "$host_cpu" = ia64; then
+	  # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	  # chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+          else
+	    if test "$aix_use_runtimelinking" = yes; then
+	      shared_flag='${wl}-G'
+	    else
+	      shared_flag='${wl}-bM:SRE'
+	    fi
+          fi
+        fi
+
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+        # It seems that -bexpall does not export symbols beginning with
+        # underscore (_), so it is better to generate a list of symbols to
+	# export.
+        _LT_TAGVAR(always_export_symbols, $1)=yes
+        if test "$aix_use_runtimelinking" = yes; then
+          # Warning - without using the other runtime loading flags (-brtl),
+          # -berok will link without error, but may produce a broken library.
+          _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+          # Determine the default libpath from the value encoded in an empty
+          # executable.
+          _LT_SYS_MODULE_PATH_AIX([$1])
+          _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+        else
+          if test "$host_cpu" = ia64; then
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+	    _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+          else
+	    # Determine the default libpath from the value encoded in an
+	    # empty executable.
+	    _LT_SYS_MODULE_PATH_AIX([$1])
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	    # Warning - without using the other run time loading flags,
+	    # -berok will link without error, but may produce a broken library.
+	    _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+	    _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+	    if test "$with_gnu_ld" = yes; then
+	      # We only use this code for GNU lds that support --whole-archive.
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	    else
+	      # Exported symbols can be pulled into shared objects from archives
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+	    fi
+	    _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	    # This is similar to how AIX traditionally builds its shared
+	    # libraries.
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+          fi
+        fi
+        ;;
+
+      beos*)
+	if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  # Joseph Beckenbach  says some releases of gcc
+	  # support --undefined.  This deserves some investigation.  FIXME
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	else
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+
+      chorus*)
+        case $cc_basename in
+          *)
+	  # FIXME: insert proper C++ library support
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	  ;;
+        esac
+        ;;
+
+      cygwin* | mingw* | pw32* | cegcc*)
+	case $GXX,$cc_basename in
+	,cl* | no,cl*)
+	  # Native MSVC
+	  # hardcode_libdir_flag_spec is actually meaningless, as there is
+	  # no search path for DLLs.
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  _LT_TAGVAR(always_export_symbols, $1)=yes
+	  _LT_TAGVAR(file_list_spec, $1)='@'
+	  # Tell ltmain to make .lib files, not .a files.
+	  libext=lib
+	  # Tell ltmain to make .dll files, not .so files.
+	  shrext_cmds=".dll"
+	  # FIXME: Setting linknames here is a bad hack.
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	      $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+	    else
+	      $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+	    fi~
+	    $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+	    linknames='
+	  # The linker will not automatically build a static lib if we build a DLL.
+	  # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+	  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	  # Don't use ranlib
+	  _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+	  _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+	    lt_tool_outputfile="@TOOL_OUTPUT@"~
+	    case $lt_outputfile in
+	      *.exe|*.EXE) ;;
+	      *)
+		lt_outputfile="$lt_outputfile.exe"
+		lt_tool_outputfile="$lt_tool_outputfile.exe"
+		;;
+	    esac~
+	    func_to_tool_file "$lt_outputfile"~
+	    if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+	      $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+	      $RM "$lt_outputfile.manifest";
+	    fi'
+	  ;;
+	*)
+	  # g++
+	  # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+	  # as there is no search path for DLLs.
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  _LT_TAGVAR(always_export_symbols, $1)=no
+	  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+	  if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	    # If the export-symbols file already is a .def file (1st line
+	    # is EXPORTS), use it as is; otherwise, prepend...
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	      cp $export_symbols $output_objdir/$soname.def;
+	    else
+	      echo EXPORTS > $output_objdir/$soname.def;
+	      cat $export_symbols >> $output_objdir/$soname.def;
+	    fi~
+	    $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	  else
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	  fi
+	  ;;
+	esac
+	;;
+      darwin* | rhapsody*)
+        _LT_DARWIN_LINKER_FEATURES($1)
+	;;
+
+      dgux*)
+        case $cc_basename in
+          ec++*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          ghcx*)
+	    # Green Hills C++ Compiler
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      freebsd2.*)
+        # C++ shared libraries reported to be fairly broken before
+	# switch to ELF
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      freebsd-elf*)
+        _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+        ;;
+
+      freebsd* | dragonfly*)
+        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+        # conventions
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+        ;;
+
+      gnu*)
+        ;;
+
+      haiku*)
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        ;;
+
+      hpux9*)
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+				             # but as the default
+				             # location of the library.
+
+        case $cc_basename in
+          CC*)
+            # FIXME: insert proper C++ library support
+            _LT_TAGVAR(ld_shlibs, $1)=no
+            ;;
+          aCC*)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            # Commands to make compiler produce verbose output that lists
+            # what "hidden" libraries, object files and flags are used when
+            # linking a shared library.
+            #
+            # There doesn't appear to be a way to prevent this compiler from
+            # explicitly linking system object files so we need to strip them
+            # from the output so that they don't get included in the library
+            # dependencies.
+            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+            ;;
+          *)
+            if test "$GXX" = yes; then
+              _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            else
+              # FIXME: insert proper C++ library support
+              _LT_TAGVAR(ld_shlibs, $1)=no
+            fi
+            ;;
+        esac
+        ;;
+
+      hpux10*|hpux11*)
+        if test $with_gnu_ld = no; then
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	  _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+          case $host_cpu in
+            hppa*64*|ia64*)
+              ;;
+            *)
+	      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+              ;;
+          esac
+        fi
+        case $host_cpu in
+          hppa*64*|ia64*)
+            _LT_TAGVAR(hardcode_direct, $1)=no
+            _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+            ;;
+          *)
+            _LT_TAGVAR(hardcode_direct, $1)=yes
+            _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+					         # but as the default
+					         # location of the library.
+            ;;
+        esac
+
+        case $cc_basename in
+          CC*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          aCC*)
+	    case $host_cpu in
+	      hppa*64*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      ia64*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      *)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	    esac
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+          *)
+	    if test "$GXX" = yes; then
+	      if test $with_gnu_ld = no; then
+	        case $host_cpu in
+	          hppa*64*)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          ia64*)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          *)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	        esac
+	      fi
+	    else
+	      # FIXME: insert proper C++ library support
+	      _LT_TAGVAR(ld_shlibs, $1)=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      interix[[3-9]]*)
+	_LT_TAGVAR(hardcode_direct, $1)=no
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+	# Instead, shared libraries are loaded at an image base (0x10000000 by
+	# default) and relocated if they conflict, which is a slow very memory
+	# consuming and fragmenting process.  To avoid this, we pick a random,
+	# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+	# time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	;;
+      irix5* | irix6*)
+        case $cc_basename in
+          CC*)
+	    # SGI C++
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    if test "$GXX" = yes; then
+	      if test "$with_gnu_ld" = no; then
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	      else
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+	      fi
+	    fi
+	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+	    ;;
+        esac
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(inherit_rpath, $1)=yes
+        ;;
+
+      linux* | k*bsd*-gnu | kopensolaris*-gnu)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+	    ;;
+	  icpc* | ecpc* )
+	    # Intel C++
+	    with_gnu_ld=yes
+	    # version 8.0 and above of icpc choke on multiply defined symbols
+	    # if we add $predep_objects and $postdep_objects, however 7.1 and
+	    # earlier do not add the objects themselves.
+	    case `$CC -V 2>&1` in
+	      *"Version 7."*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	      *)  # Version 8.0 or newer
+	        tmp_idyn=
+	        case $host_cpu in
+		  ia64*) tmp_idyn=' -i_dynamic';;
+		esac
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	    esac
+	    _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	    ;;
+          pgCC* | pgcpp*)
+            # Portland Group C++ compiler
+	    case `$CC -V` in
+	    *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
+	      _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+		compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+	      _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+		$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+		$RANLIB $oldlib'
+	      _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+	      ;;
+	    *) # Version 6 and above use weak symbols
+	      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+	      ;;
+	    esac
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+            ;;
+	  cxx*)
+	    # Compaq C++
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+	    runpath_var=LD_RUN_PATH
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+	    ;;
+	  xl* | mpixl* | bgxl*)
+	    # IBM XL 8.0 on PPC, with GNU ld
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    if test "x$supports_anon_versioning" = xyes; then
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+		cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+		echo "local: *; };" >> $output_objdir/$libname.ver~
+		$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+	    fi
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+	      _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	      _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+	      # Not sure whether something based on
+	      # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+	      # would be better.
+	      output_verbose_link_cmd='func_echo_all'
+
+	      # Archives containing C++ object files must be created using
+	      # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	      # necessary to make sure instantiated templates are included
+	      # in the archive.
+	      _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+
+      lynxos*)
+        # FIXME: insert proper C++ library support
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      m88k*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      mvs*)
+        case $cc_basename in
+          cxx*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+	  *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+	esac
+	;;
+
+      netbsd*)
+        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+	  wlarc=
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	fi
+	# Workaround some broken pre-1.5 toolchains
+	output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+	;;
+
+      *nto* | *qnx*)
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+	;;
+
+      openbsd2*)
+        # C++ shared libraries are fairly broken
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      openbsd*)
+	if test -f /usr/libexec/ld.so; then
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+	  fi
+	  output_verbose_link_cmd=func_echo_all
+	else
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+
+      osf3* | osf4* | osf5*)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Archives containing C++ object files must be created using
+	    # the KAI C++ compiler.
+	    case $host in
+	      osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+	      *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+	    esac
+	    ;;
+          RCC*)
+	    # Rational C++ 2.4.1
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          cxx*)
+	    case $host in
+	      osf3*)
+	        _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+		;;
+	      *)
+	        _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+	          echo "-hidden">> $lib.exp~
+	          $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
+	          $RM $lib.exp'
+	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+		;;
+	    esac
+
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+	  *)
+	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	      _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	      case $host in
+	        osf3*)
+	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+		  ;;
+	        *)
+	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+		  ;;
+	      esac
+
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	      # Commands to make compiler produce verbose output that lists
+	      # what "hidden" libraries, object files and flags are used when
+	      # linking a shared library.
+	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+	    else
+	      # FIXME: insert proper C++ library support
+	      _LT_TAGVAR(ld_shlibs, $1)=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      psos*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      sunos4*)
+        case $cc_basename in
+          CC*)
+	    # Sun C++ 4.x
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          lcc*)
+	    # Lucid
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      solaris*)
+        case $cc_basename in
+          CC* | sunCC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+            _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+	    _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	      $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	    _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	    case $host_os in
+	      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+	      *)
+		# The compiler driver will combine and reorder linker options,
+		# but understands `-z linker_flag'.
+	        # Supported since Solaris 2.6 (maybe 2.5.1?)
+		_LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+	        ;;
+	    esac
+	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+	    output_verbose_link_cmd='func_echo_all'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+	    ;;
+          gcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+	    # The C++ compiler must be used to create the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    # GNU C++ compiler with Solaris linker
+	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	      _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+	      if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+		  $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      else
+	        # g++ 2.7 appears to require `-G' NOT `-shared' on this
+	        # platform.
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+		  $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      fi
+
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+	      case $host_os in
+		solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+		*)
+		  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+		  ;;
+	      esac
+	    fi
+	    ;;
+        esac
+        ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      case $cc_basename in
+        CC*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+      esac
+      ;;
+
+      sysv5* | sco3.2v5* | sco5v6*)
+	# Note: We can NOT use -z defs as we might desire, because we do not
+	# link with -lc, and that would cause any symbols used from libc to
+	# always be unresolved, which means just about no library would
+	# ever link correctly.  If we're not using GNU ld we use -z text
+	# though, which does catch some bad symbols but isn't as heavy-handed
+	# as -z defs.
+	_LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+	_LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+	_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+	_LT_TAGVAR(link_all_deplibs, $1)=yes
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+	runpath_var='LD_RUN_PATH'
+
+	case $cc_basename in
+          CC*)
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
+	      '"$_LT_TAGVAR(old_archive_cmds, $1)"
+	    _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
+	      '"$_LT_TAGVAR(reload_cmds, $1)"
+	    ;;
+	  *)
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    ;;
+	esac
+      ;;
+
+      tandem*)
+        case $cc_basename in
+          NCC*)
+	    # NonStop-UX NCC 3.20
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      vxworks*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      *)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+    esac
+
+    AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+    test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+    _LT_TAGVAR(GCC, $1)="$GXX"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+  LDCXX=$LD
+  LD=$lt_save_LD
+  GCC=$lt_save_GCC
+  with_gnu_ld=$lt_save_with_gnu_ld
+  lt_cv_path_LDCXX=$lt_cv_path_LD
+  lt_cv_path_LD=$lt_save_path_LD
+  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_FUNC_STRIPNAME_CNF
+# ----------------------
+# func_stripname_cnf prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+#
+# This function is identical to the (non-XSI) version of func_stripname,
+# except this one can be used by m4 code that may be executed by configure,
+# rather than the libtool script.
+m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
+AC_REQUIRE([_LT_DECL_SED])
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
+func_stripname_cnf ()
+{
+  case ${2} in
+  .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+  *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+  esac
+} # func_stripname_cnf
+])# _LT_FUNC_STRIPNAME_CNF
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library.  It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer*4 a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+  private int a;
+  public void bar (void) {
+    a = 0;
+  }
+};
+_LT_EOF
+], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
+package foo
+func foo() {
+}
+_LT_EOF
+])
+
+_lt_libdeps_save_CFLAGS=$CFLAGS
+case "$CC $CFLAGS " in #(
+*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
+*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
+*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
+esac
+
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  for p in `eval "$output_verbose_link_cmd"`; do
+    case ${prev}${p} in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test $p = "-L" ||
+          test $p = "-R"; then
+	 prev=$p
+	 continue
+       fi
+
+       # Expand the sysroot to ease extracting the directories later.
+       if test -z "$prev"; then
+         case $p in
+         -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
+         -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
+         -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
+         esac
+       fi
+       case $p in
+       =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
+       esac
+       if test "$pre_test_object_deps_done" = no; then
+	 case ${prev} in
+	 -L | -R)
+	   # Internal compiler library paths should come after those
+	   # provided the user.  The postdeps already come after the
+	   # user supplied libs so there is no need to process them.
+	   if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+	     _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+	   else
+	     _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+	   fi
+	   ;;
+	 # The "-l" case would never come before the object being
+	 # linked, so don't bother handling this case.
+	 esac
+       else
+	 if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+	   _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+	 else
+	   _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+	 fi
+       fi
+       prev=
+       ;;
+
+    *.lto.$objext) ;; # Ignore GCC LTO objects
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+	 pre_test_object_deps_done=yes
+	 continue
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+	 if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+	   _LT_TAGVAR(predep_objects, $1)="$p"
+	 else
+	   _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+	 fi
+       else
+	 if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+	   _LT_TAGVAR(postdep_objects, $1)="$p"
+	 else
+	   _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+	 fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
+
+    esac
+  done
+
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+CFLAGS=$_lt_libdeps_save_CFLAGS
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+  # Interix 3.5 installs completely hosed .la files for C++, so rather than
+  # hack all around it, let's just trust "g++" to DTRT.
+  _LT_TAGVAR(predep_objects,$1)=
+  _LT_TAGVAR(postdep_objects,$1)=
+  _LT_TAGVAR(postdeps,$1)=
+  ;;
+
+linux*)
+  case `$CC -V 2>&1 | sed 5q` in
+  *Sun\ C*)
+    # Sun C++ 5.9
+
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    if test "$solaris_use_stlport4" != yes; then
+      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+
+solaris*)
+  case $cc_basename in
+  CC* | sunCC*)
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    # Adding this requires a known-good setup of shared libraries for
+    # Sun compiler versions before 5.6, else PIC objects from an old
+    # archive will be linked into the output, leading to subtle bugs.
+    if test "$solaris_use_stlport4" != yes; then
+      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+    [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+    [Dependencies to place before and after the objects being linked to
+    create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+    [The library search path used internally by the compiler when linking
+    a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_LANG_PUSH(Fortran 77)
+if test -z "$F77" || test "X$F77" = "Xno"; then
+  _lt_disable_F77=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_F77" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC="$CC"
+  lt_save_GCC=$GCC
+  lt_save_CFLAGS=$CFLAGS
+  CC=${F77-"f77"}
+  CFLAGS=$FFLAGS
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+  GCC=$G77
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test "$can_build_shared" = "no" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test "$enable_shared" = yes && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+	  test "$enable_shared" = yes && enable_static=no
+	fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test "$enable_shared" = yes || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)="$G77"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC="$lt_save_CC"
+  CFLAGS="$lt_save_CFLAGS"
+fi # test "$_lt_disable_F77" != yes
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_LANG_PUSH(Fortran)
+
+if test -z "$FC" || test "X$FC" = "Xno"; then
+  _lt_disable_FC=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_FC" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC="$CC"
+  lt_save_GCC=$GCC
+  lt_save_CFLAGS=$CFLAGS
+  CC=${FC-"f95"}
+  CFLAGS=$FCFLAGS
+  compiler=$CC
+  GCC=$ac_cv_fc_compiler_gnu
+
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test "$can_build_shared" = "no" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test "$enable_shared" = yes && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+	  test "$enable_shared" = yes && enable_static=no
+	fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test "$enable_shared" = yes || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+fi # test "$_lt_disable_FC" != yes
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+CFLAGS=$GCJFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+
+  _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GCJ_CONFIG
+
+
+# _LT_LANG_GO_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Go compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GO_CONFIG],
+[AC_REQUIRE([LT_PROG_GO])dnl
+AC_LANG_SAVE
+
+# Source file extension for Go test sources.
+ac_ext=go
+
+# Object file extension for compiled Go test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="package main; func main() { }"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='package main; func main() { }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GOC-"gccgo"}
+CFLAGS=$GOFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# Go did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+
+  _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GO_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+CFLAGS=
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+  :
+  _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+  [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+    [AC_CHECK_TOOL(GCJ, gcj,)
+      test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+      AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+
+# LT_PROG_GO
+# ----------
+AC_DEFUN([LT_PROG_GO],
+[AC_CHECK_TOOL(GOC, gccgo,)
+])
+
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+# _LT_DECL_DLLTOOL
+# ----------------
+# Ensure DLLTOOL variable is set.
+m4_defun([_LT_DECL_DLLTOOL],
+[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
+AC_SUBST([DLLTOOL])
+])
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible.  Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+    [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_SED.  When it is available in   #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for lt_ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+        lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+      fi
+    done
+  done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+  test ! -f $lt_ac_sed && continue
+  cat /dev/null > conftest.in
+  lt_ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+  # Check for GNU sed and select it if it is found.
+  if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+    lt_cv_path_SED=$lt_ac_sed
+    break
+  fi
+  while true; do
+    cat conftest.in conftest.in >conftest.tmp
+    mv conftest.tmp conftest.in
+    cp conftest.in conftest.nl
+    echo >>conftest.nl
+    $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+    cmp -s conftest.out conftest.nl || break
+    # 10000 chars as input seems more than enough
+    test $lt_ac_count -gt 10 && break
+    lt_ac_count=`expr $lt_ac_count + 1`
+    if test $lt_ac_count -gt $lt_ac_max; then
+      lt_ac_max=$lt_ac_count
+      lt_cv_path_SED=$lt_ac_sed
+    fi
+  done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+  test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
+      = c,a/b,b/c, \
+    && eval 'test $(( 1 + 1 )) -eq 2 \
+    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+  && xsi_shell=yes
+AC_MSG_RESULT([$xsi_shell])
+_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
+
+AC_MSG_CHECKING([whether the shell understands "+="])
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
+    >/dev/null 2>&1 \
+  && lt_shell_append=yes
+AC_MSG_RESULT([$lt_shell_append])
+_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  lt_unset=unset
+else
+  lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  lt_SP2NL='tr \040 \012'
+  lt_NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  lt_SP2NL='tr \100 \n'
+  lt_NL2SP='tr \r\n \100\100'
+  ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY)
+# ------------------------------------------------------
+# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and
+# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY.
+m4_defun([_LT_PROG_FUNCTION_REPLACE],
+[dnl {
+sed -e '/^$1 ()$/,/^} # $1 /c\
+$1 ()\
+{\
+m4_bpatsubsts([$2], [$], [\\], [^\([	 ]\)], [\\\1])
+} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+])
+
+
+# _LT_PROG_REPLACE_SHELLFNS
+# -------------------------
+# Replace existing portable implementations of several shell functions with
+# equivalent extended shell implementations where those features are available..
+m4_defun([_LT_PROG_REPLACE_SHELLFNS],
+[if test x"$xsi_shell" = xyes; then
+  _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl
+    case ${1} in
+      */*) func_dirname_result="${1%/*}${2}" ;;
+      *  ) func_dirname_result="${3}" ;;
+    esac])
+
+  _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl
+    func_basename_result="${1##*/}"])
+
+  _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl
+    case ${1} in
+      */*) func_dirname_result="${1%/*}${2}" ;;
+      *  ) func_dirname_result="${3}" ;;
+    esac
+    func_basename_result="${1##*/}"])
+
+  _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl
+    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+    # positional parameters, so assign one to ordinary parameter first.
+    func_stripname_result=${3}
+    func_stripname_result=${func_stripname_result#"${1}"}
+    func_stripname_result=${func_stripname_result%"${2}"}])
+
+  _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl
+    func_split_long_opt_name=${1%%=*}
+    func_split_long_opt_arg=${1#*=}])
+
+  _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl
+    func_split_short_opt_arg=${1#??}
+    func_split_short_opt_name=${1%"$func_split_short_opt_arg"}])
+
+  _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl
+    case ${1} in
+      *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+      *)    func_lo2o_result=${1} ;;
+    esac])
+
+  _LT_PROG_FUNCTION_REPLACE([func_xform], [    func_xform_result=${1%.*}.lo])
+
+  _LT_PROG_FUNCTION_REPLACE([func_arith], [    func_arith_result=$(( $[*] ))])
+
+  _LT_PROG_FUNCTION_REPLACE([func_len], [    func_len_result=${#1}])
+fi
+
+if test x"$lt_shell_append" = xyes; then
+  _LT_PROG_FUNCTION_REPLACE([func_append], [    eval "${1}+=\\${2}"])
+
+  _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl
+    func_quote_for_eval "${2}"
+dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \
+    eval "${1}+=\\\\ \\$func_quote_for_eval_result"])
+
+  # Save a `func_append' function call where possible by direct use of '+='
+  sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+else
+  # Save a `func_append' function call even when '+=' is not available
+  sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+fi
+
+if test x"$_lt_function_replace_fail" = x":"; then
+  AC_MSG_WARN([Unable to substitute extended shell functions in $ofile])
+fi
+])
+
+# _LT_PATH_CONVERSION_FUNCTIONS
+# -----------------------------
+# Determine which file name conversion functions should be used by
+# func_to_host_file (and, implicitly, by func_to_host_path).  These are needed
+# for certain cross-compile configurations and native mingw.
+m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_MSG_CHECKING([how to convert $build file names to $host format])
+AC_CACHE_VAL(lt_cv_to_host_file_cmd,
+[case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+        ;;
+    esac
+    ;;
+  *-*-cygwin* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_noop
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+        ;;
+    esac
+    ;;
+  * ) # unhandled hosts (and "normal" native builds)
+    lt_cv_to_host_file_cmd=func_convert_file_noop
+    ;;
+esac
+])
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
+_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
+         [0], [convert $build file names to $host format])dnl
+
+AC_MSG_CHECKING([how to convert $build file names to toolchain format])
+AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
+[#assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+        ;;
+    esac
+    ;;
+esac
+])
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
+_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
+         [0], [convert $build files to toolchain format])dnl
+])# _LT_PATH_CONVERSION_FUNCTIONS
+
+# Helper functions for option handling.                    -*- Autoconf -*-
+#
+#   Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
+#   Inc.
+#   Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 7 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it.  Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+        _LT_MANGLE_DEFUN([$1], [$2]),
+    [m4_warning([Unknown $1 option `$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+	    [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+		      [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME.  If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+    [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+  dnl
+  dnl Simply set some default values (i.e off) if boolean options were not
+  dnl specified:
+  _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+  ])
+  _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+  ])
+  dnl
+  dnl If no reference was made to various pairs of opposing options, then
+  dnl we run the default mode handler for the pair.  For example, if neither
+  dnl `shared' nor `disable-shared' was passed, we enable building of shared
+  dnl archives by default:
+  _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+  _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+  		   [_LT_ENABLE_FAST_INSTALL])
+  ])
+])# _LT_SET_OPTIONS
+
+
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+  AC_CHECK_TOOL(AS, as, false)
+  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+  AC_CHECK_TOOL(OBJDUMP, objdump, false)
+  ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS],      [1], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the `shared' and
+# `disable-shared' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+    [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+	[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+    _LT_DECL([build_libtool_libs], [enable_shared], [0],
+	[Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the `static' and
+# `disable-static' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+    [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+	[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+    _LT_DECL([build_old_libs], [enable_static], [0],
+	[Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the `fast-install'
+# and `disable-fast-install' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+    [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+    [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_fast_install=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+	 [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the `pic-only' and `no-pic'
+# LT_INIT options.
+# MODE is either `yes' or `no'.  If omitted, it defaults to `both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+    [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
+	[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+    [lt_p=${PACKAGE-default}
+    case $withval in
+    yes|no) pic_mode=$withval ;;
+    *)
+      pic_mode=default
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for lt_pkg in $withval; do
+	IFS="$lt_save_ifs"
+	if test "X$lt_pkg" = "X$lt_p"; then
+	  pic_mode=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [pic_mode=default])
+
+test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+		 [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+		 [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+		 [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+		 [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+		 [m4_define([_LTDL_TYPE], [convenience])])
+
+# ltsugar.m4 -- libtool m4 base layer.                         -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+       [$#], [2], [[$2]],
+       [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+       [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59 which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+       [$#], 1, [],
+       [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+	   m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn.  Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+       [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+	     [m4_foreach([_Lt_suffix],
+		]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+	[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+	  [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+		 [lt_append([$1], [$2], [$3])$4],
+		 [$5])],
+	  [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+	m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+    m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+	[$5],
+    [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+  [lt_join(m4_quote(m4_default([$4], [[, ]])),
+           lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+		      [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
+
+# ltversion.m4 -- version numbers			-*- Autoconf -*-
+#
+#   Copyright (C) 2004 Free Software Foundation, Inc.
+#   Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# @configure_input@
+
+# serial 3337 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.4.2])
+m4_define([LT_PACKAGE_REVISION], [1.3337])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.4.2'
+macro_revision='1.3337'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
+
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions.    -*-Autoconf-*-
+#
+#   Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
+#   Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 5 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick.  It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else.  This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. 
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION],	[AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP],		[AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH],	[AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT],		[AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX],	[AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN],		[AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR],		[AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL],	[AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN],		[AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER],	[AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK],		[AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE],	[AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF],	[AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O],	[AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR],		[AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR],		[AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP],	[AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC],		[AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU],		[AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG],	[AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD],	[AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS],	[AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP],	[AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP],		[AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED],		[AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME],		[AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE],	[AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE],	[AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL],		[AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP],		[AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN],		[AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER],	[AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG],		[AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL],	[AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX],		[AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77],		[AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ],		[AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG],	[AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG],	[AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG],	[AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG],	[AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG],	[AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG],		[AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C],	[AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
+m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS],	[AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
+m4_ifndef([_LT_AC_PROG_CXXCPP],		[AC_DEFUN([_LT_AC_PROG_CXXCPP])])
+m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS],	[AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
+m4_ifndef([_LT_PROG_ECHO_BACKSLASH],	[AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_PROG_F77],		[AC_DEFUN([_LT_PROG_F77])])
+m4_ifndef([_LT_PROG_FC],		[AC_DEFUN([_LT_PROG_FC])])
+m4_ifndef([_LT_PROG_CXX],		[AC_DEFUN([_LT_PROG_CXX])])
+
+# Copyright (C) 2002-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.14'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version.  Point them to the right macro.
+m4_if([$1], [1.14.1], [],
+      [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too.  Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.14.1])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# Copyright (C) 2011-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_AR([ACT-IF-FAIL])
+# -------------------------
+# Try to determine the archiver interface, and trigger the ar-lib wrapper
+# if it is needed.  If the detection of archiver interface fails, run
+# ACT-IF-FAIL (default is to abort configure with a proper error message).
+AC_DEFUN([AM_PROG_AR],
+[AC_BEFORE([$0], [LT_INIT])dnl
+AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl
+AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([ar-lib])dnl
+AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false])
+: ${AR=ar}
+
+AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface],
+  [AC_LANG_PUSH([C])
+   am_cv_ar_interface=ar
+   AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])],
+     [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
+      AC_TRY_EVAL([am_ar_try])
+      if test "$ac_status" -eq 0; then
+        am_cv_ar_interface=ar
+      else
+        am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
+        AC_TRY_EVAL([am_ar_try])
+        if test "$ac_status" -eq 0; then
+          am_cv_ar_interface=lib
+        else
+          am_cv_ar_interface=unknown
+        fi
+      fi
+      rm -f conftest.lib libconftest.a
+     ])
+   AC_LANG_POP([C])])
+
+case $am_cv_ar_interface in
+ar)
+  ;;
+lib)
+  # Microsoft lib, so override with the ar-lib wrapper script.
+  # FIXME: It is wrong to rewrite AR.
+  # But if we don't then we get into trouble of one sort or another.
+  # A longer-term fix would be to have automake use am__AR in this case,
+  # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something
+  # similar.
+  AR="$am_aux_dir/ar-lib $AR"
+  ;;
+unknown)
+  m4_default([$1],
+             [AC_MSG_ERROR([could not determine $AR interface])])
+  ;;
+esac
+AC_SUBST([AR])dnl
+])
+
+# AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to '$srcdir/foo'.  In other projects, it is set to
+# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory.  The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run.  This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+#    fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+#    fails if $ac_aux_dir is absolute,
+#    fails when called from a subdirectory in a VPATH build with
+#          a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir.  In an in-source build this is usually
+# harmless because $srcdir is '.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir.  That would be:
+#   am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+#   MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH.  The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL                                            -*- Autoconf -*-
+
+# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ([2.52])dnl
+ m4_if([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],
+       [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+  AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery.  Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+m4_if([$1], [CC],   [depcc="$CC"   am_compiler_list=],
+      [$1], [CXX],  [depcc="$CXX"  am_compiler_list=],
+      [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+      [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'],
+      [$1], [UPC],  [depcc="$UPC"  am_compiler_list=],
+      [$1], [GCJ],  [depcc="$GCJ"  am_compiler_list='gcc3 gcc'],
+                    [depcc="$$1"   am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+               [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named 'D' -- because '-MD' means "put the output
+  # in D".
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_$1_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+  fi
+  am__universal=false
+  m4_case([$1], [CC],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac],
+    [CXX],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac])
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+      # Solaris 10 /bin/sh.
+      echo '/* dummy */' > sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with '-c' and '-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle '-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs.
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # After this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested.
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok '-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_$1_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES.
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE([dependency-tracking], [dnl
+AS_HELP_STRING(
+  [--enable-dependency-tracking],
+  [do not reject slow dependency extractors])
+AS_HELP_STRING(
+  [--disable-dependency-tracking],
+  [speeds up one-time build])])
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+  am__nodep='_no'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+AC_SUBST([am__nodep])dnl
+_AM_SUBST_NOTMAKE([am__nodep])dnl
+])
+
+# Generate code to set up dependency tracking.              -*- Autoconf -*-
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+  # Older Autoconf quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named 'Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`AS_DIRNAME("$mf")`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running 'make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "$am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+	 sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`AS_DIRNAME(["$file"])`
+      AS_MKDIR_P([$dirpart/$fdir])
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled.  FIXME.  This creates each '.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+     [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+     [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake.                             -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This macro actually does too much.  Some checks are only needed if
+# your package does certain things.  But this isn't really a big deal.
+
+dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
+m4_define([AC_PROG_CC],
+m4_defn([AC_PROG_CC])
+[_AM_PROG_CC_C_O
+])
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out.  PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition.  After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.65])dnl
+dnl Autoconf wants to disallow AM_ names.  We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[AC_DIAGNOSE([obsolete],
+             [$0: two- and three-arguments forms are deprecated.])
+m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(
+  m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
+  [ok:ok],,
+  [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
+ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
+AM_MISSING_PROG([AUTOCONF], [autoconf])
+AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
+AM_MISSING_PROG([AUTOHEADER], [autoheader])
+AM_MISSING_PROG([MAKEINFO], [makeinfo])
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+# For better backward compatibility.  To be removed once Automake 1.9.x
+# dies out for good.  For more background, see:
+# 
+# 
+AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
+# We need awk for the "check" target.  The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+	      [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+			     [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+		  [_AM_DEPENDENCIES([CC])],
+		  [m4_define([AC_PROG_CC],
+			     m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+		  [_AM_DEPENDENCIES([CXX])],
+		  [m4_define([AC_PROG_CXX],
+			     m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+		  [_AM_DEPENDENCIES([OBJC])],
+		  [m4_define([AC_PROG_OBJC],
+			     m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
+		  [_AM_DEPENDENCIES([OBJCXX])],
+		  [m4_define([AC_PROG_OBJCXX],
+			     m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
+])
+AC_REQUIRE([AM_SILENT_RULES])dnl
+dnl The testsuite driver may need to know about EXEEXT, so add the
+dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen.  This
+dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+  [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes.  So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+  cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present.  This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: 
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message.  This
+can help us improve future automake versions.
+
+END
+  if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+    echo 'Configuration will proceed anyway, since you have set the' >&2
+    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+    echo >&2
+  else
+    cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: .
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+    AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
+  fi
+fi])
+
+dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated.  The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+AC_SUBST([install_sh])])
+
+# Copyright (C) 2003-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot.  For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Add --enable-maintainer-mode option to configure.         -*- Autoconf -*-
+# From Jim Meyering
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAINTAINER_MODE([DEFAULT-MODE])
+# ----------------------------------
+# Control maintainer-specific portions of Makefiles.
+# Default is to disable them, unless 'enable' is passed literally.
+# For symmetry, 'disable' may be passed as well.  Anyway, the user
+# can override the default with the --enable/--disable switch.
+AC_DEFUN([AM_MAINTAINER_MODE],
+[m4_case(m4_default([$1], [disable]),
+       [enable], [m4_define([am_maintainer_other], [disable])],
+       [disable], [m4_define([am_maintainer_other], [enable])],
+       [m4_define([am_maintainer_other], [enable])
+        m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
+AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+  dnl maintainer-mode's default is 'disable' unless 'enable' is passed
+  AC_ARG_ENABLE([maintainer-mode],
+    [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode],
+      am_maintainer_other[ make rules and dependencies not useful
+      (and sometimes confusing) to the casual installer])],
+    [USE_MAINTAINER_MODE=$enableval],
+    [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
+  AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+  AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
+  MAINT=$MAINTAINER_MODE_TRUE
+  AC_SUBST([MAINT])dnl
+]
+)
+
+# Check to see how 'make' treats includes.	            -*- Autoconf -*-
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
+
+# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it is modern enough.
+# If it is, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
+else
+  am_missing_run=
+  AC_MSG_WARN(['missing' script is too old or missing])
+fi
+])
+
+# Helper functions for option handling.                     -*- Autoconf -*-
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# --------------------
+# Set option NAME.  Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_CC_C_O
+# ---------------
+# Like AC_PROG_CC_C_O, but changed for automake.  We rewrite AC_PROG_CC
+# to automatically call this.
+AC_DEFUN([_AM_PROG_CC_C_O],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+AC_LANG_PUSH([C])dnl
+AC_CACHE_CHECK(
+  [whether $CC understands -c and -o together],
+  [am_cv_prog_cc_c_o],
+  [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])])
+  # Make sure it works both with $CC and with simple cc.
+  # Following AC_PROG_CC_C_O, we do the test twice because some
+  # compilers refuse to overwrite an existing .o file with -o,
+  # though they will create one.
+  am_cv_prog_cc_c_o=yes
+  for am_i in 1 2; do
+    if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \
+         && test -f conftest2.$ac_objext; then
+      : OK
+    else
+      am_cv_prog_cc_c_o=no
+      break
+    fi
+  done
+  rm -f core conftest*
+  unset am_i])
+if test "$am_cv_prog_cc_c_o" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+AC_LANG_POP([C])])
+
+# For backward compatibility.
+AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_RUN_LOG(COMMAND)
+# -------------------
+# Run COMMAND, save the exit status in ac_status, and log it.
+# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
+AC_DEFUN([AM_RUN_LOG],
+[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
+   ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   (exit $ac_status); }])
+
+# Check to make sure that the build environment is sane.    -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[[\\\"\#\$\&\'\`$am_lf]]*)
+    AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+  *[[\\\"\#\$\&\'\`$am_lf\ \	]]*)
+    AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   am_has_slept=no
+   for am_try in 1 2; do
+     echo "timestamp, slept: $am_has_slept" > conftest.file
+     set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+     if test "$[*]" = "X"; then
+	# -L didn't work.
+	set X `ls -t "$srcdir/configure" conftest.file`
+     fi
+     if test "$[*]" != "X $srcdir/configure conftest.file" \
+	&& test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+	# If neither matched, then we have a broken ls.  This can happen
+	# if, for instance, CONFIG_SHELL is bash and it inherits a
+	# broken ls alias from the environment.  This has actually
+	# happened.  Such a system could not be considered "sane".
+	AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+  alias in your environment])
+     fi
+     if test "$[2]" = conftest.file || test $am_try -eq 2; then
+       break
+     fi
+     # Just in case.
+     sleep 1
+     am_has_slept=yes
+   done
+   test "$[2]" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT([yes])
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+  ( sleep 1 ) &
+  am_sleep_pid=$!
+fi
+AC_CONFIG_COMMANDS_PRE(
+  [AC_MSG_CHECKING([that generated files are newer than configure])
+   if test -n "$am_sleep_pid"; then
+     # Hide warnings about reused PIDs.
+     wait $am_sleep_pid 2>/dev/null
+   fi
+   AC_MSG_RESULT([done])])
+rm -f conftest.file
+])
+
+# Copyright (C) 2009-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# ("yes" being less verbose, "no" or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules], [dnl
+AS_HELP_STRING(
+  [--enable-silent-rules],
+  [less verbose build output (undo: "make V=1")])
+AS_HELP_STRING(
+  [--disable-silent-rules],
+  [verbose build output (undo: "make V=0")])dnl
+])
+case $enable_silent_rules in @%:@ (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+dnl
+dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
+dnl do not support nested variable expansions.
+dnl See automake bug#9928 and bug#10237.
+am_make=${MAKE-make}
+AC_CACHE_CHECK([whether $am_make supports nested variables],
+   [am_cv_make_support_nested_variables],
+   [if AS_ECHO([['TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi])
+if test $am_cv_make_support_nested_variables = yes; then
+  dnl Using '$V' instead of '$(V)' breaks IRIX make.
+  AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AC_SUBST([AM_V])dnl
+AM_SUBST_NOTMAKE([AM_V])dnl
+AC_SUBST([AM_DEFAULT_V])dnl
+AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor 'install' (even GNU) is that you can't
+# specify the program used to strip binaries.  This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in "make install-strip", and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip".  However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
+if test "$cross_compiling" != no; then
+  AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# --------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball.                            -*- Autoconf -*-
+
+# Copyright (C) 2004-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of 'v7', 'ustar', or 'pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+#     tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+#     $(am__untar) < result.tar
+#
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.  Yes, it's still used
+# in the wild :-(  We should find a proper way to deprecate it ...
+AC_SUBST([AMTAR], ['$${TAR-tar}'])
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+
+m4_if([$1], [v7],
+  [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+
+  [m4_case([$1],
+    [ustar],
+     [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+      # There is notably a 21 bits limit for the UID and the GID.  In fact,
+      # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+      # and bug#13588).
+      am_max_uid=2097151 # 2^21 - 1
+      am_max_gid=$am_max_uid
+      # The $UID and $GID variables are not portable, so we need to resort
+      # to the POSIX-mandated id(1) utility.  Errors in the 'id' calls
+      # below are definitely unexpected, so allow the users to see them
+      # (that is, avoid stderr redirection).
+      am_uid=`id -u || echo unknown`
+      am_gid=`id -g || echo unknown`
+      AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
+      if test $am_uid -le $am_max_uid; then
+         AC_MSG_RESULT([yes])
+      else
+         AC_MSG_RESULT([no])
+         _am_tools=none
+      fi
+      AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
+      if test $am_gid -le $am_max_gid; then
+         AC_MSG_RESULT([yes])
+      else
+        AC_MSG_RESULT([no])
+        _am_tools=none
+      fi],
+
+  [pax],
+    [],
+
+  [m4_fatal([Unknown tar format])])
+
+  AC_MSG_CHECKING([how to create a $1 tar archive])
+
+  # Go ahead even if we have the value already cached.  We do so because we
+  # need to set the values for the 'am__tar' and 'am__untar' variables.
+  _am_tools=${am_cv_prog_tar_$1-$_am_tools}
+
+  for _am_tool in $_am_tools; do
+    case $_am_tool in
+    gnutar)
+      for _am_tar in tar gnutar gtar; do
+        AM_RUN_LOG([$_am_tar --version]) && break
+      done
+      am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+      am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+      am__untar="$_am_tar -xf -"
+      ;;
+    plaintar)
+      # Must skip GNU tar: if it does not support --format= it doesn't create
+      # ustar tarball either.
+      (tar --version) >/dev/null 2>&1 && continue
+      am__tar='tar chf - "$$tardir"'
+      am__tar_='tar chf - "$tardir"'
+      am__untar='tar xf -'
+      ;;
+    pax)
+      am__tar='pax -L -x $1 -w "$$tardir"'
+      am__tar_='pax -L -x $1 -w "$tardir"'
+      am__untar='pax -r'
+      ;;
+    cpio)
+      am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+      am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+      am__untar='cpio -i -H $1 -d'
+      ;;
+    none)
+      am__tar=false
+      am__tar_=false
+      am__untar=false
+      ;;
+    esac
+
+    # If the value was cached, stop now.  We just wanted to have am__tar
+    # and am__untar set.
+    test -n "${am_cv_prog_tar_$1}" && break
+
+    # tar/untar a dummy directory, and stop if the command works.
+    rm -rf conftest.dir
+    mkdir conftest.dir
+    echo GrepMe > conftest.dir/file
+    AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+    rm -rf conftest.dir
+    if test -s conftest.tar; then
+      AM_RUN_LOG([$am__untar /dev/null 2>&1 && break
+    fi
+  done
+  rm -rf conftest.dir
+
+  AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+  AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
diff --git a/source/Irrlicht/jpeglib/ansi2knr.1 b/source/Irrlicht/jpeglib/ansi2knr.1
new file mode 100644
index 00000000..e69de29b
diff --git a/source/Irrlicht/jpeglib/ansi2knr.c b/source/Irrlicht/jpeglib/ansi2knr.c
new file mode 100644
index 00000000..e69de29b
diff --git a/source/Irrlicht/jpeglib/cderror.h b/source/Irrlicht/jpeglib/cderror.h
new file mode 100644
index 00000000..fb72a51f
--- /dev/null
+++ b/source/Irrlicht/jpeglib/cderror.h
@@ -0,0 +1,134 @@
+/*
+ * cderror.h
+ *
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * Modified 2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file defines the error and message codes for the cjpeg/djpeg
+ * applications.  These strings are not needed as part of the JPEG library
+ * proper.
+ * Edit this file to add new codes, or to translate the message strings to
+ * some other language.
+ */
+
+/*
+ * To define the enum list of message codes, include this file without
+ * defining macro JMESSAGE.  To create a message string table, include it
+ * again with a suitable JMESSAGE definition (see jerror.c for an example).
+ */
+#ifndef JMESSAGE
+#ifndef CDERROR_H
+#define CDERROR_H
+/* First time through, define the enum list */
+#define JMAKE_ENUM_LIST
+#else
+/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */
+#define JMESSAGE(code,string)
+#endif /* CDERROR_H */
+#endif /* JMESSAGE */
+
+#ifdef JMAKE_ENUM_LIST
+
+typedef enum {
+
+#define JMESSAGE(code,string)	code ,
+
+#endif /* JMAKE_ENUM_LIST */
+
+JMESSAGE(JMSG_FIRSTADDONCODE=1000, NULL) /* Must be first entry! */
+
+#ifdef BMP_SUPPORTED
+JMESSAGE(JERR_BMP_BADCMAP, "Unsupported BMP colormap format")
+JMESSAGE(JERR_BMP_BADDEPTH, "Only 8- and 24-bit BMP files are supported")
+JMESSAGE(JERR_BMP_BADHEADER, "Invalid BMP file: bad header length")
+JMESSAGE(JERR_BMP_BADPLANES, "Invalid BMP file: biPlanes not equal to 1")
+JMESSAGE(JERR_BMP_COLORSPACE, "BMP output must be grayscale or RGB")
+JMESSAGE(JERR_BMP_COMPRESSED, "Sorry, compressed BMPs not yet supported")
+JMESSAGE(JERR_BMP_EMPTY, "Empty BMP image")
+JMESSAGE(JERR_BMP_NOT, "Not a BMP file - does not start with BM")
+JMESSAGE(JTRC_BMP, "%ux%u 24-bit BMP image")
+JMESSAGE(JTRC_BMP_MAPPED, "%ux%u 8-bit colormapped BMP image")
+JMESSAGE(JTRC_BMP_OS2, "%ux%u 24-bit OS2 BMP image")
+JMESSAGE(JTRC_BMP_OS2_MAPPED, "%ux%u 8-bit colormapped OS2 BMP image")
+#endif /* BMP_SUPPORTED */
+
+#ifdef GIF_SUPPORTED
+JMESSAGE(JERR_GIF_BUG, "GIF output got confused")
+JMESSAGE(JERR_GIF_CODESIZE, "Bogus GIF codesize %d")
+JMESSAGE(JERR_GIF_COLORSPACE, "GIF output must be grayscale or RGB")
+JMESSAGE(JERR_GIF_IMAGENOTFOUND, "Too few images in GIF file")
+JMESSAGE(JERR_GIF_NOT, "Not a GIF file")
+JMESSAGE(JTRC_GIF, "%ux%ux%d GIF image")
+JMESSAGE(JTRC_GIF_BADVERSION,
+	 "Warning: unexpected GIF version number '%c%c%c'")
+JMESSAGE(JTRC_GIF_EXTENSION, "Ignoring GIF extension block of type 0x%02x")
+JMESSAGE(JTRC_GIF_NONSQUARE, "Caution: nonsquare pixels in input")
+JMESSAGE(JWRN_GIF_BADDATA, "Corrupt data in GIF file")
+JMESSAGE(JWRN_GIF_CHAR, "Bogus char 0x%02x in GIF file, ignoring")
+JMESSAGE(JWRN_GIF_ENDCODE, "Premature end of GIF image")
+JMESSAGE(JWRN_GIF_NOMOREDATA, "Ran out of GIF bits")
+#endif /* GIF_SUPPORTED */
+
+#ifdef PPM_SUPPORTED
+JMESSAGE(JERR_PPM_COLORSPACE, "PPM output must be grayscale or RGB")
+JMESSAGE(JERR_PPM_NONNUMERIC, "Nonnumeric data in PPM file")
+JMESSAGE(JERR_PPM_NOT, "Not a PPM/PGM file")
+JMESSAGE(JTRC_PGM, "%ux%u PGM image")
+JMESSAGE(JTRC_PGM_TEXT, "%ux%u text PGM image")
+JMESSAGE(JTRC_PPM, "%ux%u PPM image")
+JMESSAGE(JTRC_PPM_TEXT, "%ux%u text PPM image")
+#endif /* PPM_SUPPORTED */
+
+#ifdef RLE_SUPPORTED
+JMESSAGE(JERR_RLE_BADERROR, "Bogus error code from RLE library")
+JMESSAGE(JERR_RLE_COLORSPACE, "RLE output must be grayscale or RGB")
+JMESSAGE(JERR_RLE_DIMENSIONS, "Image dimensions (%ux%u) too large for RLE")
+JMESSAGE(JERR_RLE_EMPTY, "Empty RLE file")
+JMESSAGE(JERR_RLE_EOF, "Premature EOF in RLE header")
+JMESSAGE(JERR_RLE_MEM, "Insufficient memory for RLE header")
+JMESSAGE(JERR_RLE_NOT, "Not an RLE file")
+JMESSAGE(JERR_RLE_TOOMANYCHANNELS, "Cannot handle %d output channels for RLE")
+JMESSAGE(JERR_RLE_UNSUPPORTED, "Cannot handle this RLE setup")
+JMESSAGE(JTRC_RLE, "%ux%u full-color RLE file")
+JMESSAGE(JTRC_RLE_FULLMAP, "%ux%u full-color RLE file with map of length %d")
+JMESSAGE(JTRC_RLE_GRAY, "%ux%u grayscale RLE file")
+JMESSAGE(JTRC_RLE_MAPGRAY, "%ux%u grayscale RLE file with map of length %d")
+JMESSAGE(JTRC_RLE_MAPPED, "%ux%u colormapped RLE file with map of length %d")
+#endif /* RLE_SUPPORTED */
+
+#ifdef TARGA_SUPPORTED
+JMESSAGE(JERR_TGA_BADCMAP, "Unsupported Targa colormap format")
+JMESSAGE(JERR_TGA_BADPARMS, "Invalid or unsupported Targa file")
+JMESSAGE(JERR_TGA_COLORSPACE, "Targa output must be grayscale or RGB")
+JMESSAGE(JTRC_TGA, "%ux%u RGB Targa image")
+JMESSAGE(JTRC_TGA_GRAY, "%ux%u grayscale Targa image")
+JMESSAGE(JTRC_TGA_MAPPED, "%ux%u colormapped Targa image")
+#else
+JMESSAGE(JERR_TGA_NOTCOMP, "Targa support was not compiled")
+#endif /* TARGA_SUPPORTED */
+
+JMESSAGE(JERR_BAD_CMAP_FILE,
+	 "Color map file is invalid or of unsupported format")
+JMESSAGE(JERR_TOO_MANY_COLORS,
+	 "Output file format cannot handle %d colormap entries")
+JMESSAGE(JERR_UNGETC_FAILED, "ungetc failed")
+#ifdef TARGA_SUPPORTED
+JMESSAGE(JERR_UNKNOWN_FORMAT,
+	 "Unrecognized input file format --- perhaps you need -targa")
+#else
+JMESSAGE(JERR_UNKNOWN_FORMAT, "Unrecognized input file format")
+#endif
+JMESSAGE(JERR_UNSUPPORTED_FORMAT, "Unsupported output file format")
+
+#ifdef JMAKE_ENUM_LIST
+
+  JMSG_LASTADDONCODE
+} ADDON_MESSAGE_CODE;
+
+#undef JMAKE_ENUM_LIST
+#endif /* JMAKE_ENUM_LIST */
+
+/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */
+#undef JMESSAGE
diff --git a/source/Irrlicht/jpeglib/cdjpeg.c b/source/Irrlicht/jpeglib/cdjpeg.c
new file mode 100644
index 00000000..89fe6337
--- /dev/null
+++ b/source/Irrlicht/jpeglib/cdjpeg.c
@@ -0,0 +1,181 @@
+/*
+ * cdjpeg.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains common support routines used by the IJG application
+ * programs (cjpeg, djpeg, jpegtran).
+ */
+
+#include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
+#include 		/* to declare isupper(), tolower() */
+#ifdef NEED_SIGNAL_CATCHER
+#include 		/* to declare signal() */
+#endif
+#ifdef USE_SETMODE
+#include 		/* to declare setmode()'s parameter macros */
+/* If you have setmode() but not , just delete this line: */
+#include 			/* to declare setmode() */
+#endif
+
+
+/*
+ * Signal catcher to ensure that temporary files are removed before aborting.
+ * NB: for Amiga Manx C this is actually a global routine named _abort();
+ * we put "#define signal_catcher _abort" in jconfig.h.  Talk about bogus...
+ */
+
+#ifdef NEED_SIGNAL_CATCHER
+
+static j_common_ptr sig_cinfo;
+
+void				/* must be global for Manx C */
+signal_catcher (int signum)
+{
+  if (sig_cinfo != NULL) {
+    if (sig_cinfo->err != NULL) /* turn off trace output */
+      sig_cinfo->err->trace_level = 0;
+    jpeg_destroy(sig_cinfo);	/* clean up memory allocation & temp files */
+  }
+  exit(EXIT_FAILURE);
+}
+
+
+GLOBAL(void)
+enable_signal_catcher (j_common_ptr cinfo)
+{
+  sig_cinfo = cinfo;
+#ifdef SIGINT			/* not all systems have SIGINT */
+  signal(SIGINT, signal_catcher);
+#endif
+#ifdef SIGTERM			/* not all systems have SIGTERM */
+  signal(SIGTERM, signal_catcher);
+#endif
+}
+
+#endif
+
+
+/*
+ * Optional progress monitor: display a percent-done figure on stderr.
+ */
+
+#ifdef PROGRESS_REPORT
+
+METHODDEF(void)
+progress_monitor (j_common_ptr cinfo)
+{
+  cd_progress_ptr prog = (cd_progress_ptr) cinfo->progress;
+  int total_passes = prog->pub.total_passes + prog->total_extra_passes;
+  int percent_done = (int) (prog->pub.pass_counter*100L/prog->pub.pass_limit);
+
+  if (percent_done != prog->percent_done) {
+    prog->percent_done = percent_done;
+    if (total_passes > 1) {
+      fprintf(stderr, "\rPass %d/%d: %3d%% ",
+	      prog->pub.completed_passes + prog->completed_extra_passes + 1,
+	      total_passes, percent_done);
+    } else {
+      fprintf(stderr, "\r %3d%% ", percent_done);
+    }
+    fflush(stderr);
+  }
+}
+
+
+GLOBAL(void)
+start_progress_monitor (j_common_ptr cinfo, cd_progress_ptr progress)
+{
+  /* Enable progress display, unless trace output is on */
+  if (cinfo->err->trace_level == 0) {
+    progress->pub.progress_monitor = progress_monitor;
+    progress->completed_extra_passes = 0;
+    progress->total_extra_passes = 0;
+    progress->percent_done = -1;
+    cinfo->progress = &progress->pub;
+  }
+}
+
+
+GLOBAL(void)
+end_progress_monitor (j_common_ptr cinfo)
+{
+  /* Clear away progress display */
+  if (cinfo->err->trace_level == 0) {
+    fprintf(stderr, "\r                \r");
+    fflush(stderr);
+  }
+}
+
+#endif
+
+
+/*
+ * Case-insensitive matching of possibly-abbreviated keyword switches.
+ * keyword is the constant keyword (must be lower case already),
+ * minchars is length of minimum legal abbreviation.
+ */
+
+GLOBAL(boolean)
+keymatch (char * arg, const char * keyword, int minchars)
+{
+  register int ca, ck;
+  register int nmatched = 0;
+
+  while ((ca = *arg++) != '\0') {
+    if ((ck = *keyword++) == '\0')
+      return FALSE;		/* arg longer than keyword, no good */
+    if (isupper(ca))		/* force arg to lcase (assume ck is already) */
+      ca = tolower(ca);
+    if (ca != ck)
+      return FALSE;		/* no good */
+    nmatched++;			/* count matched characters */
+  }
+  /* reached end of argument; fail if it's too short for unique abbrev */
+  if (nmatched < minchars)
+    return FALSE;
+  return TRUE;			/* A-OK */
+}
+
+
+/*
+ * Routines to establish binary I/O mode for stdin and stdout.
+ * Non-Unix systems often require some hacking to get out of text mode.
+ */
+
+GLOBAL(FILE *)
+read_stdin (void)
+{
+  FILE * input_file = stdin;
+
+#ifdef USE_SETMODE		/* need to hack file mode? */
+  setmode(fileno(stdin), O_BINARY);
+#endif
+#ifdef USE_FDOPEN		/* need to re-open in binary mode? */
+  if ((input_file = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
+    fprintf(stderr, "Cannot reopen stdin\n");
+    exit(EXIT_FAILURE);
+  }
+#endif
+  return input_file;
+}
+
+
+GLOBAL(FILE *)
+write_stdout (void)
+{
+  FILE * output_file = stdout;
+
+#ifdef USE_SETMODE		/* need to hack file mode? */
+  setmode(fileno(stdout), O_BINARY);
+#endif
+#ifdef USE_FDOPEN		/* need to re-open in binary mode? */
+  if ((output_file = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) {
+    fprintf(stderr, "Cannot reopen stdout\n");
+    exit(EXIT_FAILURE);
+  }
+#endif
+  return output_file;
+}
diff --git a/source/Irrlicht/jpeglib/cdjpeg.h b/source/Irrlicht/jpeglib/cdjpeg.h
new file mode 100644
index 00000000..c0d064cc
--- /dev/null
+++ b/source/Irrlicht/jpeglib/cdjpeg.h
@@ -0,0 +1,187 @@
+/*
+ * cdjpeg.h
+ *
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains common declarations for the sample applications
+ * cjpeg and djpeg.  It is NOT used by the core JPEG library.
+ */
+
+#define JPEG_CJPEG_DJPEG	/* define proper options in jconfig.h */
+#define JPEG_INTERNAL_OPTIONS	/* cjpeg.c,djpeg.c need to see xxx_SUPPORTED */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jerror.h"		/* get library error codes too */
+#include "cderror.h"		/* get application-specific error codes */
+
+
+/*
+ * Object interface for cjpeg's source file decoding modules
+ */
+
+typedef struct cjpeg_source_struct * cjpeg_source_ptr;
+
+struct cjpeg_source_struct {
+  JMETHOD(void, start_input, (j_compress_ptr cinfo,
+			      cjpeg_source_ptr sinfo));
+  JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo,
+				       cjpeg_source_ptr sinfo));
+  JMETHOD(void, finish_input, (j_compress_ptr cinfo,
+			       cjpeg_source_ptr sinfo));
+
+  FILE *input_file;
+
+  JSAMPARRAY buffer;
+  JDIMENSION buffer_height;
+};
+
+
+/*
+ * Object interface for djpeg's output file encoding modules
+ */
+
+typedef struct djpeg_dest_struct * djpeg_dest_ptr;
+
+struct djpeg_dest_struct {
+  /* start_output is called after jpeg_start_decompress finishes.
+   * The color map will be ready at this time, if one is needed.
+   */
+  JMETHOD(void, start_output, (j_decompress_ptr cinfo,
+			       djpeg_dest_ptr dinfo));
+  /* Emit the specified number of pixel rows from the buffer. */
+  JMETHOD(void, put_pixel_rows, (j_decompress_ptr cinfo,
+				 djpeg_dest_ptr dinfo,
+				 JDIMENSION rows_supplied));
+  /* Finish up at the end of the image. */
+  JMETHOD(void, finish_output, (j_decompress_ptr cinfo,
+				djpeg_dest_ptr dinfo));
+
+  /* Target file spec; filled in by djpeg.c after object is created. */
+  FILE * output_file;
+
+  /* Output pixel-row buffer.  Created by module init or start_output.
+   * Width is cinfo->output_width * cinfo->output_components;
+   * height is buffer_height.
+   */
+  JSAMPARRAY buffer;
+  JDIMENSION buffer_height;
+};
+
+
+/*
+ * cjpeg/djpeg may need to perform extra passes to convert to or from
+ * the source/destination file format.  The JPEG library does not know
+ * about these passes, but we'd like them to be counted by the progress
+ * monitor.  We use an expanded progress monitor object to hold the
+ * additional pass count.
+ */
+
+struct cdjpeg_progress_mgr {
+  struct jpeg_progress_mgr pub;	/* fields known to JPEG library */
+  int completed_extra_passes;	/* extra passes completed */
+  int total_extra_passes;	/* total extra */
+  /* last printed percentage stored here to avoid multiple printouts */
+  int percent_done;
+};
+
+typedef struct cdjpeg_progress_mgr * cd_progress_ptr;
+
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jinit_read_bmp		jIRdBMP
+#define jinit_write_bmp		jIWrBMP
+#define jinit_read_gif		jIRdGIF
+#define jinit_write_gif		jIWrGIF
+#define jinit_read_ppm		jIRdPPM
+#define jinit_write_ppm		jIWrPPM
+#define jinit_read_rle		jIRdRLE
+#define jinit_write_rle		jIWrRLE
+#define jinit_read_targa	jIRdTarga
+#define jinit_write_targa	jIWrTarga
+#define read_quant_tables	RdQTables
+#define read_scan_script	RdScnScript
+#define set_quality_ratings     SetQRates
+#define set_quant_slots		SetQSlots
+#define set_sample_factors	SetSFacts
+#define read_color_map		RdCMap
+#define enable_signal_catcher	EnSigCatcher
+#define start_progress_monitor	StProgMon
+#define end_progress_monitor	EnProgMon
+#define read_stdin		RdStdin
+#define write_stdout		WrStdout
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+/* Module selection routines for I/O modules. */
+
+EXTERN(cjpeg_source_ptr) jinit_read_bmp JPP((j_compress_ptr cinfo));
+EXTERN(djpeg_dest_ptr) jinit_write_bmp JPP((j_decompress_ptr cinfo,
+					    boolean is_os2));
+EXTERN(cjpeg_source_ptr) jinit_read_gif JPP((j_compress_ptr cinfo));
+EXTERN(djpeg_dest_ptr) jinit_write_gif JPP((j_decompress_ptr cinfo));
+EXTERN(cjpeg_source_ptr) jinit_read_ppm JPP((j_compress_ptr cinfo));
+EXTERN(djpeg_dest_ptr) jinit_write_ppm JPP((j_decompress_ptr cinfo));
+EXTERN(cjpeg_source_ptr) jinit_read_rle JPP((j_compress_ptr cinfo));
+EXTERN(djpeg_dest_ptr) jinit_write_rle JPP((j_decompress_ptr cinfo));
+EXTERN(cjpeg_source_ptr) jinit_read_targa JPP((j_compress_ptr cinfo));
+EXTERN(djpeg_dest_ptr) jinit_write_targa JPP((j_decompress_ptr cinfo));
+
+/* cjpeg support routines (in rdswitch.c) */
+
+EXTERN(boolean) read_quant_tables JPP((j_compress_ptr cinfo, char * filename,
+				       boolean force_baseline));
+EXTERN(boolean) read_scan_script JPP((j_compress_ptr cinfo, char * filename));
+EXTERN(boolean) set_quality_ratings JPP((j_compress_ptr cinfo, char *arg,
+					 boolean force_baseline));
+EXTERN(boolean) set_quant_slots JPP((j_compress_ptr cinfo, char *arg));
+EXTERN(boolean) set_sample_factors JPP((j_compress_ptr cinfo, char *arg));
+
+/* djpeg support routines (in rdcolmap.c) */
+
+EXTERN(void) read_color_map JPP((j_decompress_ptr cinfo, FILE * infile));
+
+/* common support routines (in cdjpeg.c) */
+
+EXTERN(void) enable_signal_catcher JPP((j_common_ptr cinfo));
+EXTERN(void) start_progress_monitor JPP((j_common_ptr cinfo,
+					 cd_progress_ptr progress));
+EXTERN(void) end_progress_monitor JPP((j_common_ptr cinfo));
+EXTERN(boolean) keymatch JPP((char * arg, const char * keyword, int minchars));
+EXTERN(FILE *) read_stdin JPP((void));
+EXTERN(FILE *) write_stdout JPP((void));
+
+/* miscellaneous useful macros */
+
+#ifdef DONT_USE_B_MODE		/* define mode parameters for fopen() */
+#define READ_BINARY	"r"
+#define WRITE_BINARY	"w"
+#else
+#ifdef VMS			/* VMS is very nonstandard */
+#define READ_BINARY	"rb", "ctx=stm"
+#define WRITE_BINARY	"wb", "ctx=stm"
+#else				/* standard ANSI-compliant case */
+#define READ_BINARY	"rb"
+#define WRITE_BINARY	"wb"
+#endif
+#endif
+
+#ifndef EXIT_FAILURE		/* define exit() codes if not provided */
+#define EXIT_FAILURE  1
+#endif
+#ifndef EXIT_SUCCESS
+#ifdef VMS
+#define EXIT_SUCCESS  1		/* VMS is very nonstandard */
+#else
+#define EXIT_SUCCESS  0
+#endif
+#endif
+#ifndef EXIT_WARNING
+#ifdef VMS
+#define EXIT_WARNING  1		/* VMS is very nonstandard */
+#else
+#define EXIT_WARNING  2
+#endif
+#endif
diff --git a/source/Irrlicht/jpeglib/change.log b/source/Irrlicht/jpeglib/change.log
new file mode 100644
index 00000000..97cde1d4
--- /dev/null
+++ b/source/Irrlicht/jpeglib/change.log
@@ -0,0 +1,409 @@
+CHANGE LOG for Independent JPEG Group's JPEG software
+
+
+Version 9a  19-Jan-2014
+-----------------------
+
+Add support for wide gamut color spaces (JFIF version 2).
+Improve clarity and accuracy in color conversion modules.
+Note: Requires rebuild of test images.
+
+Extend the bit depth support to all values from 8 to 12
+(BITS_IN_JSAMPLE configuration option in jmorecfg.h).
+jpegtran now supports N bits sample data precision with all N from 8 to 12
+in a single instance.  Thank to Roland Fassauer for inspiration.
+
+Try to resolve issues with new boolean type definition.
+Thank also to v4hn for suggestion.
+
+Enable option to use default Huffman tables for lossless compression
+(for hardware solution), and in this case improve lossless RGB compression
+with reversible color transform.  Thank to Benny Alexandar for hint.
+
+Extend the entropy decoding structure, so that extraneous bytes between
+compressed scan data and following marker can be reported correctly.
+Thank to Nigel Tao for hint.
+
+Add jpegtran -wipe option and extension for -crop.
+Thank to Andrew Senior, David Clunie, and Josef Schmid for suggestion.
+
+
+Version 9  13-Jan-2013
+----------------------
+
+Add cjpeg -rgb1 option to create an RGB JPEG file, and insert
+a simple reversible color transform into the processing which
+significantly improves the compression.
+The recommended command for lossless coding of RGB images is now
+cjpeg -rgb1 -block 1 -arithmetic.
+As said, this option improves the compression significantly, but
+the files are not compatible with JPEG decoders prior to IJG v9
+due to the included color transform.
+The used color transform and marker signaling is compatible with
+other JPEG standards (e.g., JPEG-LS part 2).
+
+Remove the automatic de-ANSI-fication support (Automake 1.12).
+Thank also to Nitin A Kamble for suggestion.
+
+Add remark for jpeg_mem_dest() in jdatadst.c.
+Thank to Elie-Gregoire Khoury for the hint.
+
+Support files with invalid component identifiers (created
+by Adobe PDF).  Thank to Robin Watts for the suggestion.
+
+Adapt full buffer case in jcmainct.c for use with scaled DCT.
+Thank to Sergii Biloshytskyi for the suggestion.
+
+Add type identifier for declaration of noreturn functions.
+Thank to Brett L. Moore for the suggestion.
+
+Correct argument type in format string, avoid compiler warnings.
+Thank to Vincent Torri for hint.
+
+Add missing #include directives in configuration checks, avoid
+configuration errors.  Thank to John Spencer for the hint.
+
+
+Version 8d  15-Jan-2012
+-----------------------
+
+Add cjpeg -rgb option to create RGB JPEG files.
+Using this switch suppresses the conversion from RGB
+colorspace input to the default YCbCr JPEG colorspace.
+This feature allows true lossless JPEG coding of RGB color images.
+The recommended command for this purpose is currently
+cjpeg -rgb -block 1 -arithmetic.
+SmartScale capable decoder (introduced with IJG JPEG 8) required.
+Thank to Michael Koch for the initial suggestion.
+
+Add option to disable the region adjustment in the transupp crop code.
+Thank to Jeffrey Friedl for the suggestion.
+
+Thank to Richard Jones and Edd Dawson for various minor corrections.
+
+Thank to Akim Demaille for configure.ac cleanup.
+
+
+Version 8c  16-Jan-2011
+-----------------------
+
+Add option to compression library and cjpeg (-block N) to use
+different DCT block size.
+All N from 1 to 16 are possible.  Default is 8 (baseline format).
+Larger values produce higher compression,
+smaller values produce higher quality.
+SmartScale capable decoder (introduced with IJG JPEG 8) required.
+
+
+Version 8b  16-May-2010
+-----------------------
+
+Repair problem in new memory source manager with corrupt JPEG data.
+Thank to Ted Campbell and Samuel Chun for the report.
+
+Repair problem in Makefile.am test target.
+Thank to anonymous user for the report.
+
+Support MinGW installation with automatic configure.
+Thank to Volker Grabsch for the suggestion.
+
+
+Version 8a  28-Feb-2010
+-----------------------
+
+Writing tables-only datastreams via jpeg_write_tables works again.
+
+Support 32-bit BMPs (RGB image with Alpha channel) for read in cjpeg.
+Thank to Brett Blackham for the suggestion.
+
+Improve accuracy in floating point IDCT calculation.
+Thank to Robert Hooke for the hint.
+
+
+Version 8  10-Jan-2010
+----------------------
+
+jpegtran now supports the same -scale option as djpeg for "lossless" resize.
+An implementation of the JPEG SmartScale extension is required for this
+feature.  A (draft) specification of the JPEG SmartScale extension is
+available as a contributed document at ITU and ISO.  Revision 2 or later
+of the document is required (latest document version is Revision 3).
+The SmartScale extension will enable more features beside lossless resize
+in future implementations, as described in the document (new compression
+options).
+
+Add sanity check in BMP reader module to avoid cjpeg crash for empty input
+image (thank to Isaev Ildar of ISP RAS, Moscow, RU for reporting this error).
+
+Add data source and destination managers for read from and write to
+memory buffers.  New API functions jpeg_mem_src and jpeg_mem_dest.
+Thank to Roberto Boni from Italy for the suggestion.
+
+
+Version 7  27-Jun-2009
+----------------------
+
+New scaled DCTs implemented.
+djpeg now supports scalings N/8 with all N from 1 to 16.
+cjpeg now supports scalings 8/N with all N from 1 to 16.
+Scaled DCTs with size larger than 8 are now also used for resolving the
+common 2x2 chroma subsampling case without additional spatial resampling.
+Separate spatial resampling for those kind of files is now only necessary
+for N>8 scaling cases.
+Furthermore, separate scaled DCT functions are provided for direct resolving
+of the common asymmetric subsampling cases (2x1 and 1x2) without additional
+spatial resampling.
+
+cjpeg -quality option has been extended for support of separate quality
+settings for luminance and chrominance (or in general, for every provided
+quantization table slot).
+New API function jpeg_default_qtables() and q_scale_factor array in library.
+
+Added -nosmooth option to cjpeg, complementary to djpeg.
+New variable "do_fancy_downsampling" in library, complement to fancy
+upsampling.  Fancy upsampling now uses direct DCT scaling with sizes
+larger than 8.  The old method is not reversible and has been removed.
+
+Support arithmetic entropy encoding and decoding.
+Added files jaricom.c, jcarith.c, jdarith.c.
+
+Straighten the file structure:
+Removed files jidctred.c, jcphuff.c, jchuff.h, jdphuff.c, jdhuff.h.
+
+jpegtran has a new "lossless" cropping feature.
+
+Implement -perfect option in jpegtran, new API function
+jtransform_perfect_transform() in transupp. (DP 204_perfect.dpatch)
+
+Better error messages for jpegtran fopen failure.
+(DP 203_jpegtran_errmsg.dpatch)
+
+Fix byte order issue with 16bit PPM/PGM files in rdppm.c/wrppm.c:
+according to Netpbm, the de facto standard implementation of the PNM formats,
+the most significant byte is first. (DP 203_rdppm.dpatch)
+
+Add -raw option to rdjpgcom not to mangle the output.
+(DP 205_rdjpgcom_raw.dpatch)
+
+Make rdjpgcom locale aware. (DP 201_rdjpgcom_locale.dpatch)
+
+Add extern "C" to jpeglib.h.
+This avoids the need to put extern "C" { ... } around #include "jpeglib.h"
+in your C++ application.  Defining the symbol DONT_USE_EXTERN_C in the
+configuration prevents this. (DP 202_jpeglib.h_c++.dpatch)
+
+
+Version 6b  27-Mar-1998
+-----------------------
+
+jpegtran has new features for lossless image transformations (rotation
+and flipping) as well as "lossless" reduction to grayscale.
+
+jpegtran now copies comments by default; it has a -copy switch to enable
+copying all APPn blocks as well, or to suppress comments.  (Formerly it
+always suppressed comments and APPn blocks.)  jpegtran now also preserves
+JFIF version and resolution information.
+
+New decompressor library feature: COM and APPn markers found in the input
+file can be saved in memory for later use by the application.  (Before,
+you had to code this up yourself with a custom marker processor.)
+
+There is an unused field "void * client_data" now in compress and decompress
+parameter structs; this may be useful in some applications.
+
+JFIF version number information is now saved by the decoder and accepted by
+the encoder.  jpegtran uses this to copy the source file's version number,
+to ensure "jpegtran -copy all" won't create bogus files that contain JFXX
+extensions but claim to be version 1.01.  Applications that generate their
+own JFXX extension markers also (finally) have a supported way to cause the
+encoder to emit JFIF version number 1.02.
+
+djpeg's trace mode reports JFIF 1.02 thumbnail images as such, rather
+than as unknown APP0 markers.
+
+In -verbose mode, djpeg and rdjpgcom will try to print the contents of
+APP12 markers as text.  Some digital cameras store useful text information
+in APP12 markers.
+
+Handling of truncated data streams is more robust: blocks beyond the one in
+which the error occurs will be output as uniform gray, or left unchanged
+if decoding a progressive JPEG.  The appearance no longer depends on the
+Huffman tables being used.
+
+Huffman tables are checked for validity much more carefully than before.
+
+To avoid the Unisys LZW patent, djpeg's GIF output capability has been
+changed to produce "uncompressed GIFs", and cjpeg's GIF input capability
+has been removed altogether.  We're not happy about it either, but there
+seems to be no good alternative.
+
+The configure script now supports building libjpeg as a shared library
+on many flavors of Unix (all the ones that GNU libtool knows how to
+build shared libraries for).  Use "./configure --enable-shared" to
+try this out.
+
+New jconfig file and makefiles for Microsoft Visual C++ and Developer Studio.
+Also, a jconfig file and a build script for Metrowerks CodeWarrior
+on Apple Macintosh.  makefile.dj has been updated for DJGPP v2, and there
+are miscellaneous other minor improvements in the makefiles.
+
+jmemmac.c now knows how to create temporary files following Mac System 7
+conventions.
+
+djpeg's -map switch is now able to read raw-format PPM files reliably.
+
+cjpeg -progressive -restart no longer generates any unnecessary DRI markers.
+
+Multiple calls to jpeg_simple_progression for a single JPEG object
+no longer leak memory.
+
+
+Version 6a  7-Feb-96
+--------------------
+
+Library initialization sequence modified to detect version mismatches
+and struct field packing mismatches between library and calling application.
+This change requires applications to be recompiled, but does not require
+any application source code change.
+
+All routine declarations changed to the style "GLOBAL(type) name ...",
+that is, GLOBAL, LOCAL, METHODDEF, EXTERN are now macros taking the
+routine's return type as an argument.  This makes it possible to add
+Microsoft-style linkage keywords to all the routines by changing just
+these macros.  Note that any application code that was using these macros
+will have to be changed.
+
+DCT coefficient quantization tables are now stored in normal array order
+rather than zigzag order.  Application code that calls jpeg_add_quant_table,
+or otherwise manipulates quantization tables directly, will need to be
+changed.  If you need to make such code work with either older or newer
+versions of the library, a test like "#if JPEG_LIB_VERSION >= 61" is
+recommended.
+
+djpeg's trace capability now dumps DQT tables in natural order, not zigzag
+order.  This allows the trace output to be made into a "-qtables" file
+more easily.
+
+New system-dependent memory manager module for use on Apple Macintosh.
+
+Fix bug in cjpeg's -smooth option: last one or two scanlines would be
+duplicates of the prior line unless the image height mod 16 was 1 or 2.
+
+Repair minor problems in VMS, BCC, MC6 makefiles.
+
+New configure script based on latest GNU Autoconf.
+
+Correct the list of include files needed by MetroWerks C for ccommand().
+
+Numerous small documentation updates.
+
+
+Version 6  2-Aug-95
+-------------------
+
+Progressive JPEG support: library can read and write full progressive JPEG
+files.  A "buffered image" mode supports incremental decoding for on-the-fly
+display of progressive images.  Simply recompiling an existing IJG-v5-based
+decoder with v6 should allow it to read progressive files, though of course
+without any special progressive display.
+
+New "jpegtran" application performs lossless transcoding between different
+JPEG formats; primarily, it can be used to convert baseline to progressive
+JPEG and vice versa.  In support of jpegtran, the library now allows lossless
+reading and writing of JPEG files as DCT coefficient arrays.  This ability
+may be of use in other applications.
+
+Notes for programmers:
+* We changed jpeg_start_decompress() to be able to suspend; this makes all
+decoding modes available to suspending-input applications.  However,
+existing applications that use suspending input will need to be changed
+to check the return value from jpeg_start_decompress().  You don't need to
+do anything if you don't use a suspending data source.
+* We changed the interface to the virtual array routines: access_virt_array
+routines now take a count of the number of rows to access this time.  The
+last parameter to request_virt_array routines is now interpreted as the
+maximum number of rows that may be accessed at once, but not necessarily
+the height of every access.
+
+
+Version 5b  15-Mar-95
+---------------------
+
+Correct bugs with grayscale images having v_samp_factor > 1.
+
+jpeg_write_raw_data() now supports output suspension.
+
+Correct bugs in "configure" script for case of compiling in
+a directory other than the one containing the source files.
+
+Repair bug in jquant1.c: sometimes didn't use as many colors as it could.
+
+Borland C makefile and jconfig file work under either MS-DOS or OS/2.
+
+Miscellaneous improvements to documentation.
+
+
+Version 5a  7-Dec-94
+--------------------
+
+Changed color conversion roundoff behavior so that grayscale values are
+represented exactly.  (This causes test image files to change.)
+
+Make ordered dither use 16x16 instead of 4x4 pattern for a small quality
+improvement.
+
+New configure script based on latest GNU Autoconf.
+Fix configure script to handle CFLAGS correctly.
+Rename *.auto files to *.cfg, so that configure script still works if
+file names have been truncated for DOS.
+
+Fix bug in rdbmp.c: didn't allow for extra data between header and image.
+
+Modify rdppm.c/wrppm.c to handle 2-byte raw PPM/PGM formats for 12-bit data.
+
+Fix several bugs in rdrle.c.
+
+NEED_SHORT_EXTERNAL_NAMES option was broken.
+
+Revise jerror.h/jerror.c for more flexibility in message table.
+
+Repair oversight in jmemname.c NO_MKTEMP case: file could be there
+but unreadable.
+
+
+Version 5  24-Sep-94
+--------------------
+
+Version 5 represents a nearly complete redesign and rewrite of the IJG
+software.  Major user-visible changes include:
+  * Automatic configuration simplifies installation for most Unix systems.
+  * A range of speed vs. image quality tradeoffs are supported.
+    This includes resizing of an image during decompression: scaling down
+    by a factor of 1/2, 1/4, or 1/8 is handled very efficiently.
+  * New programs rdjpgcom and wrjpgcom allow insertion and extraction
+    of text comments in a JPEG file.
+
+The application programmer's interface to the library has changed completely.
+Notable improvements include:
+  * We have eliminated the use of callback routines for handling the
+    uncompressed image data.  The application now sees the library as a
+    set of routines that it calls to read or write image data on a
+    scanline-by-scanline basis.
+  * The application image data is represented in a conventional interleaved-
+    pixel format, rather than as a separate array for each color channel.
+    This can save a copying step in many programs.
+  * The handling of compressed data has been cleaned up: the application can
+    supply routines to source or sink the compressed data.  It is possible to
+    suspend processing on source/sink buffer overrun, although this is not
+    supported in all operating modes.
+  * All static state has been eliminated from the library, so that multiple
+    instances of compression or decompression can be active concurrently.
+  * JPEG abbreviated datastream formats are supported, ie, quantization and
+    Huffman tables can be stored separately from the image data.
+  * And not only that, but the documentation of the library has improved
+    considerably!
+
+
+The last widely used release before the version 5 rewrite was version 4A of
+18-Feb-93.  Change logs before that point have been discarded, since they
+are not of much interest after the rewrite.
diff --git a/source/Irrlicht/jpeglib/cjpeg.1 b/source/Irrlicht/jpeglib/cjpeg.1
new file mode 100644
index 00000000..8684331e
--- /dev/null
+++ b/source/Irrlicht/jpeglib/cjpeg.1
@@ -0,0 +1,387 @@
+.TH CJPEG 1 "23 November 2013"
+.SH NAME
+cjpeg \- compress an image file to a JPEG file
+.SH SYNOPSIS
+.B cjpeg
+[
+.I options
+]
+[
+.I filename
+]
+.LP
+.SH DESCRIPTION
+.LP
+.B cjpeg
+compresses the named image file, or the standard input if no file is
+named, and produces a JPEG/JFIF file on the standard output.
+The currently supported input file formats are: PPM (PBMPLUS color
+format), PGM (PBMPLUS gray-scale format), BMP, Targa, and RLE (Utah Raster
+Toolkit format).  (RLE is supported only if the URT library is available.)
+.SH OPTIONS
+All switch names may be abbreviated; for example,
+.B \-grayscale
+may be written
+.B \-gray
+or
+.BR \-gr .
+Most of the "basic" switches can be abbreviated to as little as one letter.
+Upper and lower case are equivalent (thus
+.B \-BMP
+is the same as
+.BR \-bmp ).
+British spellings are also accepted (e.g.,
+.BR \-greyscale ),
+though for brevity these are not mentioned below.
+.PP
+The basic switches are:
+.TP
+.BI \-quality " N[,...]"
+Scale quantization tables to adjust image quality.  Quality is 0 (worst) to
+100 (best); default is 75.  (See below for more info.)
+.TP
+.B \-grayscale
+Create monochrome JPEG file from color input.  Be sure to use this switch when
+compressing a grayscale BMP file, because
+.B cjpeg
+isn't bright enough to notice whether a BMP file uses only shades of gray.
+By saying
+.BR \-grayscale ,
+you'll get a smaller JPEG file that takes less time to process.
+.TP
+.B \-rgb
+Create RGB JPEG file.
+Using this switch suppresses the conversion from RGB
+colorspace input to the default YCbCr JPEG colorspace.
+You can use this switch in combination with the
+.BI \-block " N"
+switch (see below) for lossless JPEG coding.
+See also the
+.B \-rgb1
+switch below.
+.TP
+.B \-optimize
+Perform optimization of entropy encoding parameters.  Without this, default
+encoding parameters are used.
+.B \-optimize
+usually makes the JPEG file a little smaller, but
+.B cjpeg
+runs somewhat slower and needs much more memory.  Image quality and speed of
+decompression are unaffected by
+.BR \-optimize .
+.TP
+.B \-progressive
+Create progressive JPEG file (see below).
+.TP
+.BI \-scale " M/N"
+Scale the output image by a factor M/N.  Currently supported scale factors are
+M/N with all N from 1 to 16, where M is the destination DCT size, which is 8
+by default (see
+.BI \-block " N"
+switch below).
+.TP
+.B \-targa
+Input file is Targa format.  Targa files that contain an "identification"
+field will not be automatically recognized by
+.BR cjpeg ;
+for such files you must specify
+.B \-targa
+to make
+.B cjpeg
+treat the input as Targa format.
+For most Targa files, you won't need this switch.
+.PP
+The
+.B \-quality
+switch lets you trade off compressed file size against quality of the
+reconstructed image: the higher the quality setting, the larger the JPEG file,
+and the closer the output image will be to the original input.  Normally you
+want to use the lowest quality setting (smallest file) that decompresses into
+something visually indistinguishable from the original image.  For this
+purpose the quality setting should be between 50 and 95; the default of 75 is
+often about right.  If you see defects at
+.B \-quality
+75, then go up 5 or 10 counts at a time until you are happy with the output
+image.  (The optimal setting will vary from one image to another.)
+.PP
+.B \-quality
+100 will generate a quantization table of all 1's, minimizing loss in the
+quantization step (but there is still information loss in subsampling, as well
+as roundoff error).  This setting is mainly of interest for experimental
+purposes.  Quality values above about 95 are
+.B not
+recommended for normal use; the compressed file size goes up dramatically for
+hardly any gain in output image quality.
+.PP
+In the other direction, quality values below 50 will produce very small files
+of low image quality.  Settings around 5 to 10 might be useful in preparing an
+index of a large image library, for example.  Try
+.B \-quality
+2 (or so) for some amusing Cubist effects.  (Note: quality
+values below about 25 generate 2-byte quantization tables, which are
+considered optional in the JPEG standard.
+.B cjpeg
+emits a warning message when you give such a quality value, because some
+other JPEG programs may be unable to decode the resulting file.  Use
+.B \-baseline
+if you need to ensure compatibility at low quality values.)
+.PP
+The
+.B \-quality
+option has been extended in IJG version 7 for support of separate quality
+settings for luminance and chrominance (or in general, for every provided
+quantization table slot).  This feature is useful for high-quality
+applications which cannot accept the damage of color data by coarse
+subsampling settings.  You can now easily reduce the color data amount more
+smoothly with finer control without separate subsampling.  The resulting file
+is fully compliant with standard JPEG decoders.
+Note that the
+.B \-quality
+ratings refer to the quantization table slots, and that the last value is
+replicated if there are more q-table slots than parameters.  The default
+q-table slots are 0 for luminance and 1 for chrominance with default tables as
+given in the JPEG standard.  This is compatible with the old behaviour in case
+that only one parameter is given, which is then used for both luminance and
+chrominance (slots 0 and 1).  More or custom quantization tables can be set
+with
+.B \-qtables
+and assigned to components with
+.B \-qslots
+parameter (see the "wizard" switches below).
+.B Caution:
+You must explicitly add
+.BI \-sample " 1x1"
+for efficient separate color
+quality selection, since the default value used by library is 2x2!
+.PP
+The
+.B \-progressive
+switch creates a "progressive JPEG" file.  In this type of JPEG file, the data
+is stored in multiple scans of increasing quality.  If the file is being
+transmitted over a slow communications link, the decoder can use the first
+scan to display a low-quality image very quickly, and can then improve the
+display with each subsequent scan.  The final image is exactly equivalent to a
+standard JPEG file of the same quality setting, and the total file size is
+about the same --- often a little smaller.
+.PP
+Switches for advanced users:
+.TP
+.B \-arithmetic
+Use arithmetic coding.
+.B Caution:
+arithmetic coded JPEG is not yet widely implemented, so many decoders will
+be unable to view an arithmetic coded JPEG file at all.
+.TP
+.BI \-block " N"
+Set DCT block size.  All N from 1 to 16 are possible.
+Default is 8 (baseline format).
+Larger values produce higher compression,
+smaller values produce higher quality
+(exact DCT stage possible with 1 or 2; with the default quality of 75 and
+default Luminance qtable the DCT+Quantization stage is lossless for N=1).
+.B Caution:
+An implementation of the JPEG SmartScale extension is required for this
+feature.  SmartScale enabled JPEG is not yet widely implemented, so many
+decoders will be unable to view a SmartScale extended JPEG file at all.
+.TP
+.B \-rgb1
+Create RGB JPEG file with reversible color transform.
+Works like the
+.B \-rgb
+switch (see above) and inserts a simple reversible color transform
+into the processing which significantly improves the compression.
+Use this switch in combination with the
+.BI \-block " N"
+switch (see above) for lossless JPEG coding.
+.B Caution:
+A decoder with inverse color transform support is required for
+this feature.  Reversible color transform support is not yet
+widely implemented, so many decoders will be unable to view
+a reversible color transformed JPEG file at all.
+.TP
+.B \-bgycc
+Create big gamut YCC JPEG file.
+In this type of encoding the color difference components are quantized
+further by a factor of 2 compared to the normal Cb/Cr values, thus creating
+space to allow larger color values with higher saturation than the normal
+gamut limits to be encoded.  In order to compensate for the loss of color
+fidelity compared to a normal YCC encoded file, the color quantization
+tables can be adjusted accordingly.  For example,
+.B cjpeg \-bgycc \-quality
+80,90 will give similar results as
+.B cjpeg \-quality
+80.
+.B Caution:
+For correct decompression a decoder with big gamut YCC support (JFIF
+version 2) is required.  An old decoder may or may not display a big
+gamut YCC encoded JPEG file, depending on JFIF version check and
+corresponding warning/error configuration.  In case of a granted
+decompression the old decoder will display the image with half
+saturated colors.
+.TP
+.B \-dct int
+Use integer DCT method (default).
+.TP
+.B \-dct fast
+Use fast integer DCT (less accurate).
+.TP
+.B \-dct float
+Use floating-point DCT method.
+The float method is very slightly more accurate than the int method, but is
+much slower unless your machine has very fast floating-point hardware.  Also
+note that results of the floating-point method may vary slightly across
+machines, while the integer methods should give the same results everywhere.
+The fast integer method is much less accurate than the other two.
+.TP
+.B \-nosmooth
+Don't use high-quality downsampling.
+.TP
+.BI \-restart " N"
+Emit a JPEG restart marker every N MCU rows, or every N MCU blocks if "B" is
+attached to the number.
+.B \-restart 0
+(the default) means no restart markers.
+.TP
+.BI \-smooth " N"
+Smooth the input image to eliminate dithering noise.  N, ranging from 1 to
+100, indicates the strength of smoothing.  0 (the default) means no smoothing.
+.TP
+.BI \-maxmemory " N"
+Set limit for amount of memory to use in processing large images.  Value is
+in thousands of bytes, or millions of bytes if "M" is attached to the
+number.  For example,
+.B \-max 4m
+selects 4000000 bytes.  If more space is needed, temporary files will be used.
+.TP
+.BI \-outfile " name"
+Send output image to the named file, not to standard output.
+.TP
+.B \-verbose
+Enable debug printout.  More
+.BR \-v 's
+give more output.  Also, version information is printed at startup.
+.TP
+.B \-debug
+Same as
+.BR \-verbose .
+.PP
+The
+.B \-restart
+option inserts extra markers that allow a JPEG decoder to resynchronize after
+a transmission error.  Without restart markers, any damage to a compressed
+file will usually ruin the image from the point of the error to the end of the
+image; with restart markers, the damage is usually confined to the portion of
+the image up to the next restart marker.  Of course, the restart markers
+occupy extra space.  We recommend
+.B \-restart 1
+for images that will be transmitted across unreliable networks such as Usenet.
+.PP
+The
+.B \-smooth
+option filters the input to eliminate fine-scale noise.  This is often useful
+when converting dithered images to JPEG: a moderate smoothing factor of 10 to
+50 gets rid of dithering patterns in the input file, resulting in a smaller
+JPEG file and a better-looking image.  Too large a smoothing factor will
+visibly blur the image, however.
+.PP
+Switches for wizards:
+.TP
+.B \-baseline
+Force baseline-compatible quantization tables to be generated.  This clamps
+quantization values to 8 bits even at low quality settings.  (This switch is
+poorly named, since it does not ensure that the output is actually baseline
+JPEG.  For example, you can use
+.B \-baseline
+and
+.B \-progressive
+together.)
+.TP
+.BI \-qtables " file"
+Use the quantization tables given in the specified text file.
+.TP
+.BI \-qslots " N[,...]"
+Select which quantization table to use for each color component.
+.TP
+.BI \-sample " HxV[,...]"
+Set JPEG sampling factors for each color component.
+.TP
+.BI \-scans " file"
+Use the scan script given in the specified text file.
+.PP
+The "wizard" switches are intended for experimentation with JPEG.  If you
+don't know what you are doing, \fBdon't use them\fR.  These switches are
+documented further in the file wizard.txt.
+.SH EXAMPLES
+.LP
+This example compresses the PPM file foo.ppm with a quality factor of
+60 and saves the output as foo.jpg:
+.IP
+.B cjpeg \-quality
+.I 60 foo.ppm
+.B >
+.I foo.jpg
+.SH HINTS
+Color GIF files are not the ideal input for JPEG; JPEG is really intended for
+compressing full-color (24-bit) images.  In particular, don't try to convert
+cartoons, line drawings, and other images that have only a few distinct
+colors.  GIF works great on these, JPEG does not.  If you want to convert a
+GIF to JPEG, you should experiment with
+.BR cjpeg 's
+.B \-quality
+and
+.B \-smooth
+options to get a satisfactory conversion.
+.B \-smooth 10
+or so is often helpful.
+.PP
+Avoid running an image through a series of JPEG compression/decompression
+cycles.  Image quality loss will accumulate; after ten or so cycles the image
+may be noticeably worse than it was after one cycle.  It's best to use a
+lossless format while manipulating an image, then convert to JPEG format when
+you are ready to file the image away.
+.PP
+The
+.B \-optimize
+option to
+.B cjpeg
+is worth using when you are making a "final" version for posting or archiving.
+It's also a win when you are using low quality settings to make very small
+JPEG files; the percentage improvement is often a lot more than it is on
+larger files.  (At present,
+.B \-optimize
+mode is always selected when generating progressive JPEG files.)
+.SH ENVIRONMENT
+.TP
+.B JPEGMEM
+If this environment variable is set, its value is the default memory limit.
+The value is specified as described for the
+.B \-maxmemory
+switch.
+.B JPEGMEM
+overrides the default value specified when the program was compiled, and
+itself is overridden by an explicit
+.BR \-maxmemory .
+.SH SEE ALSO
+.BR djpeg (1),
+.BR jpegtran (1),
+.BR rdjpgcom (1),
+.BR wrjpgcom (1)
+.br
+.BR ppm (5),
+.BR pgm (5)
+.br
+Wallace, Gregory K.  "The JPEG Still Picture Compression Standard",
+Communications of the ACM, April 1991 (vol. 34, no. 4), pp. 30-44.
+.SH AUTHOR
+Independent JPEG Group
+.SH BUGS
+GIF input files are no longer supported, to avoid the Unisys LZW patent
+(now expired).
+(Conversion of GIF files to JPEG is usually a bad idea anyway.)
+.PP
+Not all variants of BMP and Targa file formats are supported.
+.PP
+The
+.B \-targa
+switch is not a bug, it's a feature.  (It would be a bug if the Targa format
+designers had not been clueless.)
diff --git a/source/Irrlicht/jpeglib/cjpeg.c b/source/Irrlicht/jpeglib/cjpeg.c
new file mode 100644
index 00000000..b9b65b88
--- /dev/null
+++ b/source/Irrlicht/jpeglib/cjpeg.c
@@ -0,0 +1,664 @@
+/*
+ * cjpeg.c
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Modified 2003-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a command-line user interface for the JPEG compressor.
+ * It should work on any system with Unix- or MS-DOS-style command lines.
+ *
+ * Two different command line styles are permitted, depending on the
+ * compile-time switch TWO_FILE_COMMANDLINE:
+ *	cjpeg [options]  inputfile outputfile
+ *	cjpeg [options]  [inputfile]
+ * In the second style, output is always to standard output, which you'd
+ * normally redirect to a file or pipe to some other program.  Input is
+ * either from a named file or from standard input (typically redirected).
+ * The second style is convenient on Unix but is unhelpful on systems that
+ * don't support pipes.  Also, you MUST use the first style if your system
+ * doesn't do binary I/O to stdin/stdout.
+ * To simplify script writing, the "-outfile" switch is provided.  The syntax
+ *	cjpeg [options]  -outfile outputfile  inputfile
+ * works regardless of which command line style is used.
+ */
+
+#include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
+#include "jversion.h"		/* for version message */
+
+#ifdef USE_CCOMMAND		/* command-line reader for Macintosh */
+#ifdef __MWERKS__
+#include               /* Metrowerks needs this */
+#include 		/* ... and this */
+#endif
+#ifdef THINK_C
+#include 		/* Think declares it here */
+#endif
+#endif
+
+
+/* Create the add-on message string table. */
+
+#define JMESSAGE(code,string)	string ,
+
+static const char * const cdjpeg_message_table[] = {
+#include "cderror.h"
+  NULL
+};
+
+
+/*
+ * This routine determines what format the input file is,
+ * and selects the appropriate input-reading module.
+ *
+ * To determine which family of input formats the file belongs to,
+ * we may look only at the first byte of the file, since C does not
+ * guarantee that more than one character can be pushed back with ungetc.
+ * Looking at additional bytes would require one of these approaches:
+ *     1) assume we can fseek() the input file (fails for piped input);
+ *     2) assume we can push back more than one character (works in
+ *        some C implementations, but unportable);
+ *     3) provide our own buffering (breaks input readers that want to use
+ *        stdio directly, such as the RLE library);
+ * or  4) don't put back the data, and modify the input_init methods to assume
+ *        they start reading after the start of file (also breaks RLE library).
+ * #1 is attractive for MS-DOS but is untenable on Unix.
+ *
+ * The most portable solution for file types that can't be identified by their
+ * first byte is to make the user tell us what they are.  This is also the
+ * only approach for "raw" file types that contain only arbitrary values.
+ * We presently apply this method for Targa files.  Most of the time Targa
+ * files start with 0x00, so we recognize that case.  Potentially, however,
+ * a Targa file could start with any byte value (byte 0 is the length of the
+ * seldom-used ID field), so we provide a switch to force Targa input mode.
+ */
+
+static boolean is_targa;	/* records user -targa switch */
+
+
+LOCAL(cjpeg_source_ptr)
+select_file_type (j_compress_ptr cinfo, FILE * infile)
+{
+  int c;
+
+  if (is_targa) {
+#ifdef TARGA_SUPPORTED
+    return jinit_read_targa(cinfo);
+#else
+    ERREXIT(cinfo, JERR_TGA_NOTCOMP);
+#endif
+  }
+
+  if ((c = getc(infile)) == EOF)
+    ERREXIT(cinfo, JERR_INPUT_EMPTY);
+  if (ungetc(c, infile) == EOF)
+    ERREXIT(cinfo, JERR_UNGETC_FAILED);
+
+  switch (c) {
+#ifdef BMP_SUPPORTED
+  case 'B':
+    return jinit_read_bmp(cinfo);
+#endif
+#ifdef GIF_SUPPORTED
+  case 'G':
+    return jinit_read_gif(cinfo);
+#endif
+#ifdef PPM_SUPPORTED
+  case 'P':
+    return jinit_read_ppm(cinfo);
+#endif
+#ifdef RLE_SUPPORTED
+  case 'R':
+    return jinit_read_rle(cinfo);
+#endif
+#ifdef TARGA_SUPPORTED
+  case 0x00:
+    return jinit_read_targa(cinfo);
+#endif
+  default:
+    ERREXIT(cinfo, JERR_UNKNOWN_FORMAT);
+    break;
+  }
+
+  return NULL;			/* suppress compiler warnings */
+}
+
+
+/*
+ * Argument-parsing code.
+ * The switch parser is designed to be useful with DOS-style command line
+ * syntax, ie, intermixed switches and file names, where only the switches
+ * to the left of a given file name affect processing of that file.
+ * The main program in this file doesn't actually use this capability...
+ */
+
+
+static const char * progname;	/* program name for error messages */
+static char * outfilename;	/* for -outfile switch */
+
+
+LOCAL(void)
+usage (void)
+/* complain about bad command line */
+{
+  fprintf(stderr, "usage: %s [switches] ", progname);
+#ifdef TWO_FILE_COMMANDLINE
+  fprintf(stderr, "inputfile outputfile\n");
+#else
+  fprintf(stderr, "[inputfile]\n");
+#endif
+
+  fprintf(stderr, "Switches (names may be abbreviated):\n");
+  fprintf(stderr, "  -quality N[,...]   Compression quality (0..100; 5-95 is useful range)\n");
+  fprintf(stderr, "  -grayscale     Create monochrome JPEG file\n");
+  fprintf(stderr, "  -rgb           Create RGB JPEG file\n");
+#ifdef ENTROPY_OPT_SUPPORTED
+  fprintf(stderr, "  -optimize      Optimize Huffman table (smaller file, but slow compression)\n");
+#endif
+#ifdef C_PROGRESSIVE_SUPPORTED
+  fprintf(stderr, "  -progressive   Create progressive JPEG file\n");
+#endif
+#ifdef DCT_SCALING_SUPPORTED
+  fprintf(stderr, "  -scale M/N     Scale image by fraction M/N, eg, 1/2\n");
+#endif
+#ifdef TARGA_SUPPORTED
+  fprintf(stderr, "  -targa         Input file is Targa format (usually not needed)\n");
+#endif
+  fprintf(stderr, "Switches for advanced users:\n");
+#ifdef C_ARITH_CODING_SUPPORTED
+  fprintf(stderr, "  -arithmetic    Use arithmetic coding\n");
+#endif
+#ifdef DCT_SCALING_SUPPORTED
+  fprintf(stderr, "  -block N       DCT block size (1..16; default is 8)\n");
+#endif
+#if JPEG_LIB_VERSION_MAJOR >= 9
+  fprintf(stderr, "  -rgb1          Create RGB JPEG file with reversible color transform\n");
+  fprintf(stderr, "  -bgycc         Create big gamut YCC JPEG file\n");
+#endif
+#ifdef DCT_ISLOW_SUPPORTED
+  fprintf(stderr, "  -dct int       Use integer DCT method%s\n",
+	  (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : ""));
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+  fprintf(stderr, "  -dct fast      Use fast integer DCT (less accurate)%s\n",
+	  (JDCT_DEFAULT == JDCT_IFAST ? " (default)" : ""));
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+  fprintf(stderr, "  -dct float     Use floating-point DCT method%s\n",
+	  (JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : ""));
+#endif
+  fprintf(stderr, "  -nosmooth      Don't use high-quality downsampling\n");
+  fprintf(stderr, "  -restart N     Set restart interval in rows, or in blocks with B\n");
+#ifdef INPUT_SMOOTHING_SUPPORTED
+  fprintf(stderr, "  -smooth N      Smooth dithered input (N=1..100 is strength)\n");
+#endif
+  fprintf(stderr, "  -maxmemory N   Maximum memory to use (in kbytes)\n");
+  fprintf(stderr, "  -outfile name  Specify name for output file\n");
+  fprintf(stderr, "  -verbose  or  -debug   Emit debug output\n");
+  fprintf(stderr, "Switches for wizards:\n");
+  fprintf(stderr, "  -baseline      Force baseline quantization tables\n");
+  fprintf(stderr, "  -qtables file  Use quantization tables given in file\n");
+  fprintf(stderr, "  -qslots N[,...]    Set component quantization tables\n");
+  fprintf(stderr, "  -sample HxV[,...]  Set component sampling factors\n");
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+  fprintf(stderr, "  -scans file    Create multi-scan JPEG per script file\n");
+#endif
+  exit(EXIT_FAILURE);
+}
+
+
+LOCAL(int)
+parse_switches (j_compress_ptr cinfo, int argc, char **argv,
+		int last_file_arg_seen, boolean for_real)
+/* Parse optional switches.
+ * Returns argv[] index of first file-name argument (== argc if none).
+ * Any file names with indexes <= last_file_arg_seen are ignored;
+ * they have presumably been processed in a previous iteration.
+ * (Pass 0 for last_file_arg_seen on the first or only iteration.)
+ * for_real is FALSE on the first (dummy) pass; we may skip any expensive
+ * processing.
+ */
+{
+  int argn;
+  char * arg;
+  boolean force_baseline;
+  boolean simple_progressive;
+  char * qualityarg = NULL;	/* saves -quality parm if any */
+  char * qtablefile = NULL;	/* saves -qtables filename if any */
+  char * qslotsarg = NULL;	/* saves -qslots parm if any */
+  char * samplearg = NULL;	/* saves -sample parm if any */
+  char * scansarg = NULL;	/* saves -scans parm if any */
+
+  /* Set up default JPEG parameters. */
+
+  force_baseline = FALSE;	/* by default, allow 16-bit quantizers */
+  simple_progressive = FALSE;
+  is_targa = FALSE;
+  outfilename = NULL;
+  cinfo->err->trace_level = 0;
+
+  /* Scan command line options, adjust parameters */
+
+  for (argn = 1; argn < argc; argn++) {
+    arg = argv[argn];
+    if (*arg != '-') {
+      /* Not a switch, must be a file name argument */
+      if (argn <= last_file_arg_seen) {
+	outfilename = NULL;	/* -outfile applies to just one input file */
+	continue;		/* ignore this name if previously processed */
+      }
+      break;			/* else done parsing switches */
+    }
+    arg++;			/* advance past switch marker character */
+
+    if (keymatch(arg, "arithmetic", 1)) {
+      /* Use arithmetic coding. */
+#ifdef C_ARITH_CODING_SUPPORTED
+      cinfo->arith_code = TRUE;
+#else
+      fprintf(stderr, "%s: sorry, arithmetic coding not supported\n",
+	      progname);
+      exit(EXIT_FAILURE);
+#endif
+
+    } else if (keymatch(arg, "baseline", 2)) {
+      /* Force baseline-compatible output (8-bit quantizer values). */
+      force_baseline = TRUE;
+
+    } else if (keymatch(arg, "block", 2)) {
+      /* Set DCT block size. */
+#if defined DCT_SCALING_SUPPORTED && JPEG_LIB_VERSION_MAJOR >= 8 && \
+      (JPEG_LIB_VERSION_MAJOR > 8 || JPEG_LIB_VERSION_MINOR >= 3)
+      int val;
+
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (sscanf(argv[argn], "%d", &val) != 1)
+	usage();
+      if (val < 1 || val > 16)
+	usage();
+      cinfo->block_size = val;
+#else
+      fprintf(stderr, "%s: sorry, block size setting not supported\n",
+	      progname);
+      exit(EXIT_FAILURE);
+#endif
+
+    } else if (keymatch(arg, "dct", 2)) {
+      /* Select DCT algorithm. */
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (keymatch(argv[argn], "int", 1)) {
+	cinfo->dct_method = JDCT_ISLOW;
+      } else if (keymatch(argv[argn], "fast", 2)) {
+	cinfo->dct_method = JDCT_IFAST;
+      } else if (keymatch(argv[argn], "float", 2)) {
+	cinfo->dct_method = JDCT_FLOAT;
+      } else
+	usage();
+
+    } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
+      /* Enable debug printouts. */
+      /* On first -d, print version identification */
+      static boolean printed_version = FALSE;
+
+      if (! printed_version) {
+	fprintf(stderr, "Independent JPEG Group's CJPEG, version %s\n%s\n",
+		JVERSION, JCOPYRIGHT);
+	printed_version = TRUE;
+      }
+      cinfo->err->trace_level++;
+
+    } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) {
+      /* Force a monochrome JPEG file to be generated. */
+      jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
+
+    } else if (keymatch(arg, "rgb", 3) || keymatch(arg, "rgb1", 4)) {
+      /* Force an RGB JPEG file to be generated. */
+#if JPEG_LIB_VERSION_MAJOR >= 9
+      /* Note: Entropy table assignment in jpeg_set_colorspace depends
+       * on color_transform.
+       */
+      cinfo->color_transform = arg[3] ? JCT_SUBTRACT_GREEN : JCT_NONE;
+#endif
+      jpeg_set_colorspace(cinfo, JCS_RGB);
+
+    } else if (keymatch(arg, "bgycc", 5)) {
+      /* Force a big gamut YCC JPEG file to be generated. */
+#if JPEG_LIB_VERSION_MAJOR >= 9 && \
+      (JPEG_LIB_VERSION_MAJOR > 9 || JPEG_LIB_VERSION_MINOR >= 1)
+      jpeg_set_colorspace(cinfo, JCS_BG_YCC);
+#else
+      fprintf(stderr, "%s: sorry, BG_YCC colorspace not supported\n",
+	      progname);
+      exit(EXIT_FAILURE);
+#endif
+
+    } else if (keymatch(arg, "maxmemory", 3)) {
+      /* Maximum memory in Kb (or Mb with 'm'). */
+      long lval;
+      char ch = 'x';
+
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
+	usage();
+      if (ch == 'm' || ch == 'M')
+	lval *= 1000L;
+      cinfo->mem->max_memory_to_use = lval * 1000L;
+
+    } else if (keymatch(arg, "nosmooth", 3)) {
+      /* Suppress fancy downsampling. */
+      cinfo->do_fancy_downsampling = FALSE;
+
+    } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) {
+      /* Enable entropy parm optimization. */
+#ifdef ENTROPY_OPT_SUPPORTED
+      cinfo->optimize_coding = TRUE;
+#else
+      fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n",
+	      progname);
+      exit(EXIT_FAILURE);
+#endif
+
+    } else if (keymatch(arg, "outfile", 4)) {
+      /* Set output file name. */
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      outfilename = argv[argn];	/* save it away for later use */
+
+    } else if (keymatch(arg, "progressive", 1)) {
+      /* Select simple progressive mode. */
+#ifdef C_PROGRESSIVE_SUPPORTED
+      simple_progressive = TRUE;
+      /* We must postpone execution until num_components is known. */
+#else
+      fprintf(stderr, "%s: sorry, progressive output was not compiled\n",
+	      progname);
+      exit(EXIT_FAILURE);
+#endif
+
+    } else if (keymatch(arg, "quality", 1)) {
+      /* Quality ratings (quantization table scaling factors). */
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      qualityarg = argv[argn];
+
+    } else if (keymatch(arg, "qslots", 2)) {
+      /* Quantization table slot numbers. */
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      qslotsarg = argv[argn];
+      /* Must delay setting qslots until after we have processed any
+       * colorspace-determining switches, since jpeg_set_colorspace sets
+       * default quant table numbers.
+       */
+
+    } else if (keymatch(arg, "qtables", 2)) {
+      /* Quantization tables fetched from file. */
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      qtablefile = argv[argn];
+      /* We postpone actually reading the file in case -quality comes later. */
+
+    } else if (keymatch(arg, "restart", 1)) {
+      /* Restart interval in MCU rows (or in MCUs with 'b'). */
+      long lval;
+      char ch = 'x';
+
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
+	usage();
+      if (lval < 0 || lval > 65535L)
+	usage();
+      if (ch == 'b' || ch == 'B') {
+	cinfo->restart_interval = (unsigned int) lval;
+	cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */
+      } else {
+	cinfo->restart_in_rows = (int) lval;
+	/* restart_interval will be computed during startup */
+      }
+
+    } else if (keymatch(arg, "sample", 2)) {
+      /* Set sampling factors. */
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      samplearg = argv[argn];
+      /* Must delay setting sample factors until after we have processed any
+       * colorspace-determining switches, since jpeg_set_colorspace sets
+       * default sampling factors.
+       */
+
+    } else if (keymatch(arg, "scale", 4)) {
+      /* Scale the image by a fraction M/N. */
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (sscanf(argv[argn], "%u/%u",
+		 &cinfo->scale_num, &cinfo->scale_denom) != 2)
+	usage();
+
+    } else if (keymatch(arg, "scans", 4)) {
+      /* Set scan script. */
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      scansarg = argv[argn];
+      /* We must postpone reading the file in case -progressive appears. */
+#else
+      fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n",
+	      progname);
+      exit(EXIT_FAILURE);
+#endif
+
+    } else if (keymatch(arg, "smooth", 2)) {
+      /* Set input smoothing factor. */
+      int val;
+
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (sscanf(argv[argn], "%d", &val) != 1)
+	usage();
+      if (val < 0 || val > 100)
+	usage();
+      cinfo->smoothing_factor = val;
+
+    } else if (keymatch(arg, "targa", 1)) {
+      /* Input file is Targa format. */
+      is_targa = TRUE;
+
+    } else {
+      usage();			/* bogus switch */
+    }
+  }
+
+  /* Post-switch-scanning cleanup */
+
+  if (for_real) {
+
+    /* Set quantization tables for selected quality. */
+    /* Some or all may be overridden if -qtables is present. */
+    if (qualityarg != NULL)	/* process -quality if it was present */
+      if (! set_quality_ratings(cinfo, qualityarg, force_baseline))
+	usage();
+
+    if (qtablefile != NULL)	/* process -qtables if it was present */
+      if (! read_quant_tables(cinfo, qtablefile, force_baseline))
+	usage();
+
+    if (qslotsarg != NULL)	/* process -qslots if it was present */
+      if (! set_quant_slots(cinfo, qslotsarg))
+	usage();
+
+    if (samplearg != NULL)	/* process -sample if it was present */
+      if (! set_sample_factors(cinfo, samplearg))
+	usage();
+
+#ifdef C_PROGRESSIVE_SUPPORTED
+    if (simple_progressive)	/* process -progressive; -scans can override */
+      jpeg_simple_progression(cinfo);
+#endif
+
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+    if (scansarg != NULL)	/* process -scans if it was present */
+      if (! read_scan_script(cinfo, scansarg))
+	usage();
+#endif
+  }
+
+  return argn;			/* return index of next arg (file name) */
+}
+
+
+/*
+ * The main program.
+ */
+
+int
+main (int argc, char **argv)
+{
+  struct jpeg_compress_struct cinfo;
+  struct jpeg_error_mgr jerr;
+#ifdef PROGRESS_REPORT
+  struct cdjpeg_progress_mgr progress;
+#endif
+  int file_index;
+  cjpeg_source_ptr src_mgr;
+  FILE * input_file;
+  FILE * output_file;
+  JDIMENSION num_scanlines;
+
+  /* On Mac, fetch a command line. */
+#ifdef USE_CCOMMAND
+  argc = ccommand(&argv);
+#endif
+
+  progname = argv[0];
+  if (progname == NULL || progname[0] == 0)
+    progname = "cjpeg";		/* in case C library doesn't provide it */
+
+  /* Initialize the JPEG compression object with default error handling. */
+  cinfo.err = jpeg_std_error(&jerr);
+  jpeg_create_compress(&cinfo);
+  /* Add some application-specific error messages (from cderror.h) */
+  jerr.addon_message_table = cdjpeg_message_table;
+  jerr.first_addon_message = JMSG_FIRSTADDONCODE;
+  jerr.last_addon_message = JMSG_LASTADDONCODE;
+
+  /* Now safe to enable signal catcher. */
+#ifdef NEED_SIGNAL_CATCHER
+  enable_signal_catcher((j_common_ptr) &cinfo);
+#endif
+
+  /* Initialize JPEG parameters.
+   * Much of this may be overridden later.
+   * In particular, we don't yet know the input file's color space,
+   * but we need to provide some value for jpeg_set_defaults() to work.
+   */
+
+  cinfo.in_color_space = JCS_RGB; /* arbitrary guess */
+  jpeg_set_defaults(&cinfo);
+
+  /* Scan command line to find file names.
+   * It is convenient to use just one switch-parsing routine, but the switch
+   * values read here are ignored; we will rescan the switches after opening
+   * the input file.
+   */
+
+  file_index = parse_switches(&cinfo, argc, argv, 0, FALSE);
+
+#ifdef TWO_FILE_COMMANDLINE
+  /* Must have either -outfile switch or explicit output file name */
+  if (outfilename == NULL) {
+    if (file_index != argc-2) {
+      fprintf(stderr, "%s: must name one input and one output file\n",
+	      progname);
+      usage();
+    }
+    outfilename = argv[file_index+1];
+  } else {
+    if (file_index != argc-1) {
+      fprintf(stderr, "%s: must name one input and one output file\n",
+	      progname);
+      usage();
+    }
+  }
+#else
+  /* Unix style: expect zero or one file name */
+  if (file_index < argc-1) {
+    fprintf(stderr, "%s: only one input file\n", progname);
+    usage();
+  }
+#endif /* TWO_FILE_COMMANDLINE */
+
+  /* Open the input file. */
+  if (file_index < argc) {
+    if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
+      fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
+      exit(EXIT_FAILURE);
+    }
+  } else {
+    /* default input file is stdin */
+    input_file = read_stdin();
+  }
+
+  /* Open the output file. */
+  if (outfilename != NULL) {
+    if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
+      fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
+      exit(EXIT_FAILURE);
+    }
+  } else {
+    /* default output file is stdout */
+    output_file = write_stdout();
+  }
+
+#ifdef PROGRESS_REPORT
+  start_progress_monitor((j_common_ptr) &cinfo, &progress);
+#endif
+
+  /* Figure out the input file format, and set up to read it. */
+  src_mgr = select_file_type(&cinfo, input_file);
+  src_mgr->input_file = input_file;
+
+  /* Read the input file header to obtain file size & colorspace. */
+  (*src_mgr->start_input) (&cinfo, src_mgr);
+
+  /* Now that we know input colorspace, fix colorspace-dependent defaults */
+  jpeg_default_colorspace(&cinfo);
+
+  /* Adjust default compression parameters by re-parsing the options */
+  file_index = parse_switches(&cinfo, argc, argv, 0, TRUE);
+
+  /* Specify data destination for compression */
+  jpeg_stdio_dest(&cinfo, output_file);
+
+  /* Start compressor */
+  jpeg_start_compress(&cinfo, TRUE);
+
+  /* Process data */
+  while (cinfo.next_scanline < cinfo.image_height) {
+    num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr);
+    (void) jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines);
+  }
+
+  /* Finish compression and release memory */
+  (*src_mgr->finish_input) (&cinfo, src_mgr);
+  jpeg_finish_compress(&cinfo);
+  jpeg_destroy_compress(&cinfo);
+
+  /* Close files, if we opened them */
+  if (input_file != stdin)
+    fclose(input_file);
+  if (output_file != stdout)
+    fclose(output_file);
+
+#ifdef PROGRESS_REPORT
+  end_progress_monitor((j_common_ptr) &cinfo);
+#endif
+
+  /* All done. */
+  exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);
+  return 0;			/* suppress no-return-value warnings */
+}
diff --git a/source/Irrlicht/jpeglib/ckconfig.c b/source/Irrlicht/jpeglib/ckconfig.c
new file mode 100644
index 00000000..fb9429af
--- /dev/null
+++ b/source/Irrlicht/jpeglib/ckconfig.c
@@ -0,0 +1,402 @@
+/*
+ * ckconfig.c
+ *
+ * Copyright (C) 1991-1994, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ */
+
+/*
+ * This program is intended to help you determine how to configure the JPEG
+ * software for installation on a particular system.  The idea is to try to
+ * compile and execute this program.  If your compiler fails to compile the
+ * program, make changes as indicated in the comments below.  Once you can
+ * compile the program, run it, and it will produce a "jconfig.h" file for
+ * your system.
+ *
+ * As a general rule, each time you try to compile this program,
+ * pay attention only to the *first* error message you get from the compiler.
+ * Many C compilers will issue lots of spurious error messages once they
+ * have gotten confused.  Go to the line indicated in the first error message,
+ * and read the comments preceding that line to see what to change.
+ *
+ * Almost all of the edits you may need to make to this program consist of
+ * changing a line that reads "#define SOME_SYMBOL" to "#undef SOME_SYMBOL",
+ * or vice versa.  This is called defining or undefining that symbol.
+ */
+
+
+/* First we must see if your system has the include files we need.
+ * We start out with the assumption that your system has all the ANSI-standard
+ * include files.  If you get any error trying to include one of these files,
+ * undefine the corresponding HAVE_xxx symbol.
+ */
+
+#define HAVE_STDDEF_H		/* replace 'define' by 'undef' if error here */
+#ifdef HAVE_STDDEF_H		/* next line will be skipped if you undef... */
+#include 
+#endif
+
+#define HAVE_STDLIB_H		/* same thing for stdlib.h */
+#ifdef HAVE_STDLIB_H
+#include 
+#endif
+
+#include 		/* If you ain't got this, you ain't got C. */
+
+/* We have to see if your string functions are defined by
+ * strings.h (old BSD convention) or string.h (everybody else).
+ * We try the non-BSD convention first; define NEED_BSD_STRINGS
+ * if the compiler says it can't find string.h.
+ */
+
+#undef NEED_BSD_STRINGS
+
+#ifdef NEED_BSD_STRINGS
+#include 
+#else
+#include 
+#endif
+
+/* On some systems (especially older Unix machines), type size_t is
+ * defined only in the include file .  If you get a failure
+ * on the size_t test below, try defining NEED_SYS_TYPES_H.
+ */
+
+#undef NEED_SYS_TYPES_H		/* start by assuming we don't need it */
+#ifdef NEED_SYS_TYPES_H
+#include 
+#endif
+
+
+/* Usually type size_t is defined in one of the include files we've included
+ * above.  If not, you'll get an error on the "typedef size_t my_size_t;" line.
+ * In that case, first try defining NEED_SYS_TYPES_H just above.
+ * If that doesn't work, you'll have to search through your system library
+ * to figure out which include file defines "size_t".  Look for a line that
+ * says "typedef something-or-other size_t;".  Then, change the line below
+ * that says "#include " to instead include the file
+ * you found size_t in, and define NEED_SPECIAL_INCLUDE.  If you can't find
+ * type size_t anywhere, try replacing "#include " with
+ * "typedef unsigned int size_t;".
+ */
+
+#undef NEED_SPECIAL_INCLUDE	/* assume we DON'T need it, for starters */
+
+#ifdef NEED_SPECIAL_INCLUDE
+#include 
+#endif
+
+typedef size_t my_size_t;	/* The payoff: do we have size_t now? */
+
+
+/* The next question is whether your compiler supports ANSI-style function
+ * prototypes.  You need to know this in order to choose between using
+ * makefile.ansi and using makefile.unix.
+ * The #define line below is set to assume you have ANSI function prototypes.
+ * If you get an error in this group of lines, undefine HAVE_PROTOTYPES.
+ */
+
+#define HAVE_PROTOTYPES
+
+#ifdef HAVE_PROTOTYPES
+int testfunction (int arg1, int * arg2); /* check prototypes */
+
+struct methods_struct {		/* check method-pointer declarations */
+  int (*error_exit) (char *msgtext);
+  int (*trace_message) (char *msgtext);
+  int (*another_method) (void);
+};
+
+int testfunction (int arg1, int * arg2) /* check definitions */
+{
+  return arg2[arg1];
+}
+
+int test2function (void)	/* check void arg list */
+{
+  return 0;
+}
+#endif
+
+
+/* Now we want to find out if your compiler knows what "unsigned char" means.
+ * If you get an error on the "unsigned char un_char;" line,
+ * then undefine HAVE_UNSIGNED_CHAR.
+ */
+
+#define HAVE_UNSIGNED_CHAR
+
+#ifdef HAVE_UNSIGNED_CHAR
+unsigned char un_char;
+#endif
+
+
+/* Now we want to find out if your compiler knows what "unsigned short" means.
+ * If you get an error on the "unsigned short un_short;" line,
+ * then undefine HAVE_UNSIGNED_SHORT.
+ */
+
+#define HAVE_UNSIGNED_SHORT
+
+#ifdef HAVE_UNSIGNED_SHORT
+unsigned short un_short;
+#endif
+
+
+/* Now we want to find out if your compiler understands type "void".
+ * If you get an error anywhere in here, undefine HAVE_VOID.
+ */
+
+#define HAVE_VOID
+
+#ifdef HAVE_VOID
+/* Caution: a C++ compiler will insist on complete prototypes */
+typedef void * void_ptr;	/* check void * */
+#ifdef HAVE_PROTOTYPES		/* check ptr to function returning void */
+typedef void (*void_func) (int a, int b);
+#else
+typedef void (*void_func) ();
+#endif
+
+#ifdef HAVE_PROTOTYPES		/* check void function result */
+void test3function (void_ptr arg1, void_func arg2)
+#else
+void test3function (arg1, arg2)
+     void_ptr arg1;
+     void_func arg2;
+#endif
+{
+  char * locptr = (char *) arg1; /* check casting to and from void * */
+  arg1 = (void *) locptr;
+  (*arg2) (1, 2);		/* check call of fcn returning void */
+}
+#endif
+
+
+/* Now we want to find out if your compiler knows what "const" means.
+ * If you get an error here, undefine HAVE_CONST.
+ */
+
+#define HAVE_CONST
+
+#ifdef HAVE_CONST
+static const int carray[3] = {1, 2, 3};
+
+#ifdef HAVE_PROTOTYPES
+int test4function (const int arg1)
+#else
+int test4function (arg1)
+     const int arg1;
+#endif
+{
+  return carray[arg1];
+}
+#endif
+
+
+/* If you get an error or warning about this structure definition,
+ * define INCOMPLETE_TYPES_BROKEN.
+ */
+
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifndef INCOMPLETE_TYPES_BROKEN
+typedef struct undefined_structure * undef_struct_ptr;
+#endif
+
+
+/* If you get an error about duplicate names,
+ * define NEED_SHORT_EXTERNAL_NAMES.
+ */
+
+#undef NEED_SHORT_EXTERNAL_NAMES
+
+#ifndef NEED_SHORT_EXTERNAL_NAMES
+
+int possibly_duplicate_function ()
+{
+  return 0;
+}
+
+int possibly_dupli_function ()
+{
+  return 1;
+}
+
+#endif
+
+
+
+/************************************************************************
+ *  OK, that's it.  You should not have to change anything beyond this
+ *  point in order to compile and execute this program.  (You might get
+ *  some warnings, but you can ignore them.)
+ *  When you run the program, it will make a couple more tests that it
+ *  can do automatically, and then it will create jconfig.h and print out
+ *  any additional suggestions it has.
+ ************************************************************************
+ */
+
+
+#ifdef HAVE_PROTOTYPES
+int is_char_signed (int arg)
+#else
+int is_char_signed (arg)
+     int arg;
+#endif
+{
+  if (arg == 189) {		/* expected result for unsigned char */
+    return 0;			/* type char is unsigned */
+  }
+  else if (arg != -67) {	/* expected result for signed char */
+    printf("Hmm, it seems 'char' is not eight bits wide on your machine.\n");
+    printf("I fear the JPEG software will not work at all.\n\n");
+  }
+  return 1;			/* assume char is signed otherwise */
+}
+
+
+#ifdef HAVE_PROTOTYPES
+int is_shifting_signed (long arg)
+#else
+int is_shifting_signed (arg)
+     long arg;
+#endif
+/* See whether right-shift on a long is signed or not. */
+{
+  long res = arg >> 4;
+
+  if (res == -0x7F7E80CL) {	/* expected result for signed shift */
+    return 1;			/* right shift is signed */
+  }
+  /* see if unsigned-shift hack will fix it. */
+  /* we can't just test exact value since it depends on width of long... */
+  res |= (~0L) << (32-4);
+  if (res == -0x7F7E80CL) {	/* expected result now? */
+    return 0;			/* right shift is unsigned */
+  }
+  printf("Right shift isn't acting as I expect it to.\n");
+  printf("I fear the JPEG software will not work at all.\n\n");
+  return 0;			/* try it with unsigned anyway */
+}
+
+
+#ifdef HAVE_PROTOTYPES
+int main (int argc, char ** argv)
+#else
+int main (argc, argv)
+     int argc;
+     char ** argv;
+#endif
+{
+  char signed_char_check = (char) (-67);
+  FILE *outfile;
+
+  /* Attempt to write jconfig.h */
+  if ((outfile = fopen("jconfig.h", "w")) == NULL) {
+    printf("Failed to write jconfig.h\n");
+    return 1;
+  }
+
+  /* Write out all the info */
+  fprintf(outfile, "/* jconfig.h --- generated by ckconfig.c */\n");
+  fprintf(outfile, "/* see jconfig.txt for explanations */\n\n");
+#ifdef HAVE_PROTOTYPES
+  fprintf(outfile, "#define HAVE_PROTOTYPES\n");
+#else
+  fprintf(outfile, "#undef HAVE_PROTOTYPES\n");
+#endif
+#ifdef HAVE_UNSIGNED_CHAR
+  fprintf(outfile, "#define HAVE_UNSIGNED_CHAR\n");
+#else
+  fprintf(outfile, "#undef HAVE_UNSIGNED_CHAR\n");
+#endif
+#ifdef HAVE_UNSIGNED_SHORT
+  fprintf(outfile, "#define HAVE_UNSIGNED_SHORT\n");
+#else
+  fprintf(outfile, "#undef HAVE_UNSIGNED_SHORT\n");
+#endif
+#ifdef HAVE_VOID
+  fprintf(outfile, "/* #define void char */\n");
+#else
+  fprintf(outfile, "#define void char\n");
+#endif
+#ifdef HAVE_CONST
+  fprintf(outfile, "/* #define const */\n");
+#else
+  fprintf(outfile, "#define const\n");
+#endif
+  if (is_char_signed((int) signed_char_check))
+    fprintf(outfile, "#undef CHAR_IS_UNSIGNED\n");
+  else
+    fprintf(outfile, "#define CHAR_IS_UNSIGNED\n");
+#ifdef HAVE_STDDEF_H
+  fprintf(outfile, "#define HAVE_STDDEF_H\n");
+#else
+  fprintf(outfile, "#undef HAVE_STDDEF_H\n");
+#endif
+#ifdef HAVE_STDLIB_H
+  fprintf(outfile, "#define HAVE_STDLIB_H\n");
+#else
+  fprintf(outfile, "#undef HAVE_STDLIB_H\n");
+#endif
+#ifdef NEED_BSD_STRINGS
+  fprintf(outfile, "#define NEED_BSD_STRINGS\n");
+#else
+  fprintf(outfile, "#undef NEED_BSD_STRINGS\n");
+#endif
+#ifdef NEED_SYS_TYPES_H
+  fprintf(outfile, "#define NEED_SYS_TYPES_H\n");
+#else
+  fprintf(outfile, "#undef NEED_SYS_TYPES_H\n");
+#endif
+  fprintf(outfile, "#undef NEED_FAR_POINTERS\n");
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+  fprintf(outfile, "#define NEED_SHORT_EXTERNAL_NAMES\n");
+#else
+  fprintf(outfile, "#undef NEED_SHORT_EXTERNAL_NAMES\n");
+#endif
+#ifdef INCOMPLETE_TYPES_BROKEN
+  fprintf(outfile, "#define INCOMPLETE_TYPES_BROKEN\n");
+#else
+  fprintf(outfile, "#undef INCOMPLETE_TYPES_BROKEN\n");
+#endif
+  fprintf(outfile, "\n#ifdef JPEG_INTERNALS\n\n");
+  if (is_shifting_signed(-0x7F7E80B1L))
+    fprintf(outfile, "#undef RIGHT_SHIFT_IS_UNSIGNED\n");
+  else
+    fprintf(outfile, "#define RIGHT_SHIFT_IS_UNSIGNED\n");
+  fprintf(outfile, "\n#endif /* JPEG_INTERNALS */\n");
+  fprintf(outfile, "\n#ifdef JPEG_CJPEG_DJPEG\n\n");
+  fprintf(outfile, "#define BMP_SUPPORTED		/* BMP image file format */\n");
+  fprintf(outfile, "#define GIF_SUPPORTED		/* GIF image file format */\n");
+  fprintf(outfile, "#define PPM_SUPPORTED		/* PBMPLUS PPM/PGM image file format */\n");
+  fprintf(outfile, "#undef RLE_SUPPORTED		/* Utah RLE image file format */\n");
+  fprintf(outfile, "#define TARGA_SUPPORTED		/* Targa image file format */\n\n");
+  fprintf(outfile, "#undef TWO_FILE_COMMANDLINE	/* You may need this on non-Unix systems */\n");
+  fprintf(outfile, "#undef NEED_SIGNAL_CATCHER	/* Define this if you use jmemname.c */\n");
+  fprintf(outfile, "#undef DONT_USE_B_MODE\n");
+  fprintf(outfile, "/* #define PROGRESS_REPORT */	/* optional */\n");
+  fprintf(outfile, "\n#endif /* JPEG_CJPEG_DJPEG */\n");
+
+  /* Close the jconfig.h file */
+  fclose(outfile);
+
+  /* User report */
+  printf("Configuration check for Independent JPEG Group's software done.\n");
+  printf("\nI have written the jconfig.h file for you.\n\n");
+#ifdef HAVE_PROTOTYPES
+  printf("You should use makefile.ansi as the starting point for your Makefile.\n");
+#else
+  printf("You should use makefile.unix as the starting point for your Makefile.\n");
+#endif
+
+#ifdef NEED_SPECIAL_INCLUDE
+  printf("\nYou'll need to change jconfig.h to include the system include file\n");
+  printf("that you found type size_t in, or add a direct definition of type\n");
+  printf("size_t if that's what you used.  Just add it to the end.\n");
+#endif
+
+  return 0;
+}
diff --git a/source/Irrlicht/jpeglib/coderules.txt b/source/Irrlicht/jpeglib/coderules.txt
new file mode 100644
index 00000000..357929fb
--- /dev/null
+++ b/source/Irrlicht/jpeglib/coderules.txt
@@ -0,0 +1,118 @@
+IJG JPEG LIBRARY:  CODING RULES
+
+Copyright (C) 1991-1996, Thomas G. Lane.
+This file is part of the Independent JPEG Group's software.
+For conditions of distribution and use, see the accompanying README file.
+
+
+Since numerous people will be contributing code and bug fixes, it's important
+to establish a common coding style.  The goal of using similar coding styles
+is much more important than the details of just what that style is.
+
+In general we follow the recommendations of "Recommended C Style and Coding
+Standards" revision 6.1 (Cannon et al. as modified by Spencer, Keppel and
+Brader).  This document is available in the IJG FTP archive (see
+jpeg/doc/cstyle.ms.tbl.Z, or cstyle.txt.Z for those without nroff/tbl).
+
+Block comments should be laid out thusly:
+
+/*
+ *  Block comments in this style.
+ */
+
+We indent statements in K&R style, e.g.,
+	if (test) {
+	  then-part;
+	} else {
+	  else-part;
+	}
+with two spaces per indentation level.  (This indentation convention is
+handled automatically by GNU Emacs and many other text editors.)
+
+Multi-word names should be written in lower case with underscores, e.g.,
+multi_word_name (not multiWordName).  Preprocessor symbols and enum constants
+are similar but upper case (MULTI_WORD_NAME).  Names should be unique within
+the first fifteen characters.  (On some older systems, global names must be
+unique within six characters.  We accommodate this without cluttering the
+source code by using macros to substitute shorter names.)
+
+We use function prototypes everywhere; we rely on automatic source code
+transformation to feed prototype-less C compilers.  Transformation is done
+by the simple and portable tool 'ansi2knr.c' (courtesy of Ghostscript).
+ansi2knr is not very bright, so it imposes a format requirement on function
+declarations: the function name MUST BEGIN IN COLUMN 1.  Thus all functions
+should be written in the following style:
+
+LOCAL(int *)
+function_name (int a, char *b)
+{
+    code...
+}
+
+Note that each function definition must begin with GLOBAL(type), LOCAL(type),
+or METHODDEF(type).  These macros expand to "static type" or just "type" as
+appropriate.  They provide a readable indication of the routine's usage and
+can readily be changed for special needs.  (For instance, special linkage
+keywords can be inserted for use in Windows DLLs.)
+
+ansi2knr does not transform method declarations (function pointers in
+structs).  We handle these with a macro JMETHOD, defined as
+	#ifdef HAVE_PROTOTYPES
+	#define JMETHOD(type,methodname,arglist)  type (*methodname) arglist
+	#else
+	#define JMETHOD(type,methodname,arglist)  type (*methodname) ()
+	#endif
+which is used like this:
+	struct function_pointers {
+	  JMETHOD(void, init_entropy_encoder, (int somearg, jparms *jp));
+	  JMETHOD(void, term_entropy_encoder, (void));
+	};
+Note the set of parentheses surrounding the parameter list.
+
+A similar solution is used for forward and external function declarations
+(see the EXTERN and JPP macros).
+
+If the code is to work on non-ANSI compilers, we cannot rely on a prototype
+declaration to coerce actual parameters into the right types.  Therefore, use
+explicit casts on actual parameters whenever the actual parameter type is not
+identical to the formal parameter.  Beware of implicit conversions to "int".
+
+It seems there are some non-ANSI compilers in which the sizeof() operator
+is defined to return int, yet size_t is defined as long.  Needless to say,
+this is brain-damaged.  Always use the SIZEOF() macro in place of sizeof(),
+so that the result is guaranteed to be of type size_t.
+
+
+The JPEG library is intended to be used within larger programs.  Furthermore,
+we want it to be reentrant so that it can be used by applications that process
+multiple images concurrently.  The following rules support these requirements:
+
+1. Avoid direct use of file I/O, "malloc", error report printouts, etc;
+pass these through the common routines provided.
+
+2. Minimize global namespace pollution.  Functions should be declared static
+wherever possible.  (Note that our method-based calling conventions help this
+a lot: in many modules only the initialization function will ever need to be
+called directly, so only that function need be externally visible.)  All
+global function names should begin with "jpeg_", and should have an
+abbreviated name (unique in the first six characters) substituted by macro
+when NEED_SHORT_EXTERNAL_NAMES is set.
+
+3. Don't use global variables; anything that must be used in another module
+should be in the common data structures.
+
+4. Don't use static variables except for read-only constant tables.  Variables
+that should be private to a module can be placed into private structures (see
+the system architecture document, structure.txt).
+
+5. Source file names should begin with "j" for files that are part of the
+library proper; source files that are not part of the library, such as cjpeg.c
+and djpeg.c, do not begin with "j".  Keep source file names to eight
+characters (plus ".c" or ".h", etc) to make life easy for MS-DOSers.  Keep
+compression and decompression code in separate source files --- some
+applications may want only one half of the library.
+
+Note: these rules (particularly #4) are not followed religiously in the
+modules that are used in cjpeg/djpeg but are not part of the JPEG library
+proper.  Those modules are not really intended to be used in other
+applications.
diff --git a/source/Irrlicht/jpeglib/compile b/source/Irrlicht/jpeglib/compile
new file mode 100644
index 00000000..531136b0
--- /dev/null
+++ b/source/Irrlicht/jpeglib/compile
@@ -0,0 +1,347 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand '-c -o'.
+
+scriptversion=2012-10-14.11; # UTC
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Written by Tom Tromey .
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see .
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to  or send patches to
+# .
+
+nl='
+'
+
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent tools from complaining about whitespace usage.
+IFS=" ""	$nl"
+
+file_conv=
+
+# func_file_conv build_file lazy
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts. If the determined conversion
+# type is listed in (the comma separated) LAZY, no conversion will
+# take place.
+func_file_conv ()
+{
+  file=$1
+  case $file in
+    / | /[!/]*) # absolute file, and not a UNC file
+      if test -z "$file_conv"; then
+	# lazily determine how to convert abs files
+	case `uname -s` in
+	  MINGW*)
+	    file_conv=mingw
+	    ;;
+	  CYGWIN*)
+	    file_conv=cygwin
+	    ;;
+	  *)
+	    file_conv=wine
+	    ;;
+	esac
+      fi
+      case $file_conv/,$2, in
+	*,$file_conv,*)
+	  ;;
+	mingw/*)
+	  file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+	  ;;
+	cygwin/*)
+	  file=`cygpath -m "$file" || echo "$file"`
+	  ;;
+	wine/*)
+	  file=`winepath -w "$file" || echo "$file"`
+	  ;;
+      esac
+      ;;
+  esac
+}
+
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+  func_file_conv "$1"
+  if test -z "$lib_path"; then
+    lib_path=$file
+  else
+    lib_path="$lib_path;$file"
+  fi
+  linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+  lib=$1
+  found=no
+  save_IFS=$IFS
+  IFS=';'
+  for dir in $lib_path $LIB
+  do
+    IFS=$save_IFS
+    if $shared && test -f "$dir/$lib.dll.lib"; then
+      found=yes
+      lib=$dir/$lib.dll.lib
+      break
+    fi
+    if test -f "$dir/$lib.lib"; then
+      found=yes
+      lib=$dir/$lib.lib
+      break
+    fi
+    if test -f "$dir/lib$lib.a"; then
+      found=yes
+      lib=$dir/lib$lib.a
+      break
+    fi
+  done
+  IFS=$save_IFS
+
+  if test "$found" != yes; then
+    lib=$lib.lib
+  fi
+}
+
+# func_cl_wrapper cl arg...
+# Adjust compile command to suit cl
+func_cl_wrapper ()
+{
+  # Assume a capable shell
+  lib_path=
+  shared=:
+  linker_opts=
+  for arg
+  do
+    if test -n "$eat"; then
+      eat=
+    else
+      case $1 in
+	-o)
+	  # configure might choose to run compile as 'compile cc -o foo foo.c'.
+	  eat=1
+	  case $2 in
+	    *.o | *.[oO][bB][jJ])
+	      func_file_conv "$2"
+	      set x "$@" -Fo"$file"
+	      shift
+	      ;;
+	    *)
+	      func_file_conv "$2"
+	      set x "$@" -Fe"$file"
+	      shift
+	      ;;
+	  esac
+	  ;;
+	-I)
+	  eat=1
+	  func_file_conv "$2" mingw
+	  set x "$@" -I"$file"
+	  shift
+	  ;;
+	-I*)
+	  func_file_conv "${1#-I}" mingw
+	  set x "$@" -I"$file"
+	  shift
+	  ;;
+	-l)
+	  eat=1
+	  func_cl_dashl "$2"
+	  set x "$@" "$lib"
+	  shift
+	  ;;
+	-l*)
+	  func_cl_dashl "${1#-l}"
+	  set x "$@" "$lib"
+	  shift
+	  ;;
+	-L)
+	  eat=1
+	  func_cl_dashL "$2"
+	  ;;
+	-L*)
+	  func_cl_dashL "${1#-L}"
+	  ;;
+	-static)
+	  shared=false
+	  ;;
+	-Wl,*)
+	  arg=${1#-Wl,}
+	  save_ifs="$IFS"; IFS=','
+	  for flag in $arg; do
+	    IFS="$save_ifs"
+	    linker_opts="$linker_opts $flag"
+	  done
+	  IFS="$save_ifs"
+	  ;;
+	-Xlinker)
+	  eat=1
+	  linker_opts="$linker_opts $2"
+	  ;;
+	-*)
+	  set x "$@" "$1"
+	  shift
+	  ;;
+	*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
+	  func_file_conv "$1"
+	  set x "$@" -Tp"$file"
+	  shift
+	  ;;
+	*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
+	  func_file_conv "$1" mingw
+	  set x "$@" "$file"
+	  shift
+	  ;;
+	*)
+	  set x "$@" "$1"
+	  shift
+	  ;;
+      esac
+    fi
+    shift
+  done
+  if test -n "$linker_opts"; then
+    linker_opts="-link$linker_opts"
+  fi
+  exec "$@" $linker_opts
+  exit 1
+}
+
+eat=
+
+case $1 in
+  '')
+     echo "$0: No command.  Try '$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand '-c -o'.
+Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file 'INSTALL'.
+
+Report bugs to .
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "compile $scriptversion"
+    exit $?
+    ;;
+  cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
+    func_cl_wrapper "$@"      # Doesn't return...
+    ;;
+esac
+
+ofile=
+cfile=
+
+for arg
+do
+  if test -n "$eat"; then
+    eat=
+  else
+    case $1 in
+      -o)
+	# configure might choose to run compile as 'compile cc -o foo foo.c'.
+	# So we strip '-o arg' only if arg is an object.
+	eat=1
+	case $2 in
+	  *.o | *.obj)
+	    ofile=$2
+	    ;;
+	  *)
+	    set x "$@" -o "$2"
+	    shift
+	    ;;
+	esac
+	;;
+      *.c)
+	cfile=$1
+	set x "$@" "$1"
+	shift
+	;;
+      *)
+	set x "$@" "$1"
+	shift
+	;;
+    esac
+  fi
+  shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+  # If no '-o' option was seen then we might have been invoked from a
+  # pattern rule where we don't need one.  That is ok -- this is a
+  # normal compilation that the losing compiler can handle.  If no
+  # '.c' file was seen then we are probably linking.  That is also
+  # ok.
+  exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use '[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file.  Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+  if mkdir "$lockdir" >/dev/null 2>&1; then
+    break
+  fi
+  sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+  test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+  test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/source/Irrlicht/jpeglib/config.guess b/source/Irrlicht/jpeglib/config.guess
new file mode 100644
index 00000000..9afd6762
--- /dev/null
+++ b/source/Irrlicht/jpeglib/config.guess
@@ -0,0 +1,1568 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright 1992-2013 Free Software Foundation, Inc.
+
+timestamp='2013-11-29'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see .
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+#
+# Please send patches with a ChangeLog entry to config-patches@gnu.org.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to ."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2013 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "${UNAME_SYSTEM}" in
+Linux|GNU|GNU/*)
+	# If the system lacks a compiler, then just pick glibc.
+	# We could probably try harder.
+	LIBC=gnu
+
+	eval $set_cc_for_build
+	cat <<-EOF > $dummy.c
+	#include 
+	#if defined(__UCLIBC__)
+	LIBC=uclibc
+	#elif defined(__dietlibc__)
+	LIBC=dietlibc
+	#else
+	LIBC=gnu
+	#endif
+	EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+	;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep -q __ELF__
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+		os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit ;;
+    *:Bitrig:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	exit ;;
+    *:SolidBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:MirBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+	exitcode=$?
+	trap '' 0
+	exit $exitcode ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+	echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit ;;
+    arm*:riscos:*:*|arm*:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    s390x:SunOS:*:*)
+	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+	echo i386-pc-auroraux${UNAME_RELEASE}
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	eval $set_cc_for_build
+	SUN_ARCH="i386"
+	# If there is a compiler, see if it is configured for 64-bit objects.
+	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+	# This test works for both compilers.
+	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		SUN_ARCH="x86_64"
+	    fi
+	fi
+	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+	echo m68k-milan-mint${UNAME_RELEASE}
+	exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+	echo m68k-hades-mint${UNAME_RELEASE}
+	exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+	echo m68k-unknown-mint${UNAME_RELEASE}
+	exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten${UNAME_RELEASE}
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include   /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c &&
+	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+	# DG/UX returns AViiON for all architectures
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include 
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[4567])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+		    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+		    case "${sc_cpu_version}" in
+		      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+		      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+		      532)                      # CPU_PA_RISC2_0
+			case "${sc_kernel_bits}" in
+			  32) HP_ARCH="hppa2.0n" ;;
+			  64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+			esac ;;
+		    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^		//' << EOF >$dummy.c
+
+		#define _HPUX_SOURCE
+		#include 
+		#include 
+
+		int main ()
+		{
+		#if defined(_SC_KERNEL_BITS)
+		    long bits = sysconf(_SC_KERNEL_BITS);
+		#endif
+		    long cpu  = sysconf (_SC_CPU_VERSION);
+
+		    switch (cpu)
+			{
+			case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+			case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+			case CPU_PA_RISC2_0:
+		#if defined(_SC_KERNEL_BITS)
+			    switch (bits)
+				{
+				case 64: puts ("hppa2.0w"); break;
+				case 32: puts ("hppa2.0n"); break;
+				default: puts ("hppa2.0"); break;
+				} break;
+		#else  /* !defined(_SC_KERNEL_BITS) */
+			    puts ("hppa2.0"); break;
+		#endif
+			default: puts ("hppa1.0"); break;
+			}
+		    exit (0);
+		}
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    eval $set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep -q __LP64__
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include 
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+	exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+	exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+	exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+	exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+	FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+	echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    5000:UNIX_System_V:4.*:*)
+	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+	FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+	echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:FreeBSD:*:*)
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	case ${UNAME_PROCESSOR} in
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW64*:*)
+	echo ${UNAME_MACHINE}-pc-mingw64
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    i*:MSYS*:*)
+	echo ${UNAME_MACHINE}-pc-msys
+	exit ;;
+    i*:windows32*:*)
+	# uname -m includes "-pc" on this system.
+	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:*)
+	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    authenticamd | genuineintel | EM64T)
+		echo x86_64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	    IA64)
+		echo ia64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit ;;
+    8664:Windows_NT:*)
+	echo x86_64-pc-mks
+	exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-unknown-cygwin
+	exit ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    aarch64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    aarch64_be:Linux:*:*)
+	UNAME_MACHINE=aarch64_be
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+	esac
+	objdump --private-headers /bin/sh | grep -q ld.so.1
+	if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    arc:Linux:*:* | arceb:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    arm*:Linux:*:*)
+	eval $set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	else
+	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+		| grep -q __ARM_PCS_VFP
+	    then
+		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+	    else
+		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+	    fi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    cris:Linux:*:*)
+	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+	exit ;;
+    crisv32:Linux:*:*)
+	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+	exit ;;
+    frv:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    hexagon:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    i*86:Linux:*:*)
+	echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef ${UNAME_MACHINE}
+	#undef ${UNAME_MACHINE}el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=${UNAME_MACHINE}el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=${UNAME_MACHINE}
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+	;;
+    or1k:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    or32:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-${LIBC}
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-${LIBC}
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
+	  PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
+	  *)    echo hppa-unknown-linux-${LIBC} ;;
+	esac
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-${LIBC}
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-${LIBC}
+	exit ;;
+    ppc64le:Linux:*:*)
+	echo powerpc64le-unknown-linux-${LIBC}
+	exit ;;
+    ppcle:Linux:*:*)
+	echo powerpcle-unknown-linux-${LIBC}
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+	exit ;;
+    sh64*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    tile*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+	exit ;;
+    x86_64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    xtensa*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+	# Unixware is an offshoot of SVR4, but it has its own version
+	# number series starting with 2...
+	# I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+	# Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo ${UNAME_MACHINE}-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+	# uname -m prints for DJGPP always 'pc', but it prints nothing about
+	# the processor, so we play safe by assuming i586.
+	# Note: whatever this is, it MUST be the same as what config.sub
+	# prints for the "djgpp" host, or else GDB configury will decide that
+	# this is a cross-build.
+	echo i586-pc-msdosdjgpp
+	exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+	OS_REL='.3'
+	test -r /etc/.relid \
+	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*)	# Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+			# says 
+	echo i586-unisys-sysv4
+	exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes .
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf@swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo ${UNAME_MACHINE}-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+		echo mips-nec-sysv${UNAME_RELEASE}
+	else
+		echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+	exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
+    x86_64:Haiku:*:*)
+	echo x86_64-unknown-haiku
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux${UNAME_RELEASE}
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+	eval $set_cc_for_build
+	if test "$UNAME_PROCESSOR" = unknown ; then
+	    UNAME_PROCESSOR=powerpc
+	fi
+	if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
+	    if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+		if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		    (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		    grep IS_64BIT_ARCH >/dev/null
+		then
+		    case $UNAME_PROCESSOR in
+			i386) UNAME_PROCESSOR=x86_64 ;;
+			powerpc) UNAME_PROCESSOR=powerpc64 ;;
+		    esac
+		fi
+	    fi
+	elif test "$UNAME_PROCESSOR" = i386 ; then
+	    # Avoid executing cc on OS X 10.9, as it ships with a stub
+	    # that puts up a graphical alert prompting to install
+	    # developer tools.  Any system running Mac OS X 10.7 or
+	    # later (Darwin 11 and later) is required to have a 64-bit
+	    # processor. This is not true of the ARM version of Darwin
+	    # that Apple uses in portable devices.
+	    UNAME_PROCESSOR=x86_64
+	fi
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NEO-?:NONSTOP_KERNEL:*:*)
+	echo neo-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSE-*:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+	echo mips-sei-seiux${UNAME_RELEASE}
+	exit ;;
+    *:DragonFly:*:*)
+	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit ;;
+    *:*VMS:*:*)
+	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "${UNAME_MACHINE}" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	exit ;;
+    i*86:rdos:*:*)
+	echo ${UNAME_MACHINE}-pc-rdos
+	exit ;;
+    i*86:AROS:*:*)
+	echo ${UNAME_MACHINE}-pc-aros
+	exit ;;
+    x86_64:VMkernel:*:*)
+	echo ${UNAME_MACHINE}-unknown-esx
+	exit ;;
+esac
+
+eval $set_cc_for_build
+cat >$dummy.c <
+# include 
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include 
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+	"4"
+#else
+	""
+#endif
+	); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include 
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+	{ echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    c34*)
+	echo c34-convex-bsd
+	exit ;;
+    c38*)
+	echo c38-convex-bsd
+	exit ;;
+    c4*)
+	echo c4-convex-bsd
+	exit ;;
+    esac
+fi
+
+cat >&2 < in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/source/Irrlicht/jpeglib/config.sub b/source/Irrlicht/jpeglib/config.sub
new file mode 100644
index 00000000..61cb4bc2
--- /dev/null
+++ b/source/Irrlicht/jpeglib/config.sub
@@ -0,0 +1,1793 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright 1992-2013 Free Software Foundation, Inc.
+
+timestamp='2013-10-01'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see .
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches with a ChangeLog entry to config-patches@gnu.org.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to ."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2013 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+  linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+  knetbsd*-gnu* | netbsd*-gnu* | \
+  kopensolaris*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  android-linux)
+    os=-linux-android
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis | -knuth | -cray | -microblaze*)
+		os=
+		basic_machine=$1
+		;;
+	-bluegene*)
+		os=-cnk
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+	-chorusrdb)
+		os=-chorusrdb
+		basic_machine=$1
+		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco6)
+		os=-sco5v6
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*178)
+		os=-lynxos178
+		;;
+	-lynx*5)
+		os=-lynxos5
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| aarch64 | aarch64_be \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arceb \
+	| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
+	| avr | avr32 \
+	| be32 | be64 \
+	| bfin \
+	| c4x | c8051 | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| epiphany \
+	| fido | fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| hexagon \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| k1om \
+	| le32 | le64 \
+	| lm32 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | microblazeel | mcore | mep | metag \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64octeon | mips64octeonel \
+	| mips64orion | mips64orionel \
+	| mips64r5900 | mips64r5900el \
+	| mips64vr | mips64vrel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipsr5900 | mipsr5900el \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| moxie \
+	| mt \
+	| msp430 \
+	| nds32 | nds32le | nds32be \
+	| nios | nios2 | nios2eb | nios2el \
+	| ns16k | ns32k \
+	| open8 \
+	| or1k | or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle \
+	| pyramid \
+	| rl78 | rx \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu \
+	| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+	| ubicom32 \
+	| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+	| we32k \
+	| x86 | xc16x | xstormy16 | xtensa \
+	| z8k | z80)
+		basic_machine=$basic_machine-unknown
+		;;
+	c54x)
+		basic_machine=tic54x-unknown
+		;;
+	c55x)
+		basic_machine=tic55x-unknown
+		;;
+	c6x)
+		basic_machine=tic6x-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
+	strongarm | thumb | xscale)
+		basic_machine=arm-unknown
+		;;
+	xgate)
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	xscaleeb)
+		basic_machine=armeb-unknown
+		;;
+
+	xscaleel)
+		basic_machine=armel-unknown
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| aarch64-* | aarch64_be-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| be32-* | be64-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* \
+	| c8051-* | clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| hexagon-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| k1om-* \
+	| le32-* | le64-* \
+	| lm32-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+	| microblaze-* | microblazeel-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64octeon-* | mips64octeonel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64r5900-* | mips64r5900el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipsr5900-* | mipsr5900el-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nds32-* | nds32le-* | nds32be-* \
+	| nios-* | nios2-* | nios2eb-* | nios2el-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| open8-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+	| pyramid-* \
+	| rl78-* | romp-* | rs6000-* | rx-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+	| sparclite-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
+	| tahoe-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+	| tile*-* \
+	| tron-* \
+	| ubicom32-* \
+	| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+	| vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-* | z80-*)
+		;;
+	# Recognize the basic CPU types without company name, with glob match.
+	xtensa*)
+		basic_machine=$basic_machine-unknown
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	abacus)
+		basic_machine=abacus-unknown
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amd64-*)
+		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aros)
+		basic_machine=i386-pc
+		os=-aros
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	blackfin)
+		basic_machine=bfin-unknown
+		os=-linux
+		;;
+	blackfin-*)
+		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	bluegene*)
+		basic_machine=powerpc-ibm
+		os=-cnk
+		;;
+	c54x-*)
+		basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c55x-*)
+		basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c6x-*)
+		basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+	cegcc)
+		basic_machine=arm-unknown
+		os=-cegcc
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	craynv)
+		basic_machine=craynv-cray
+		os=-unicosmp
+		;;
+	cr16 | cr16-*)
+		basic_machine=cr16-unknown
+		os=-elf
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	crisv32 | crisv32-* | etraxfs*)
+		basic_machine=crisv32-axis
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	crx)
+		basic_machine=crx-unknown
+		os=-elf
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dicos)
+		basic_machine=i686-pc
+		os=-dicos
+		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m68knommu)
+		basic_machine=m68k-unknown
+		os=-linux
+		;;
+	m68knommu-*)
+		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	microblaze*)
+		basic_machine=microblaze-xilinx
+		;;
+	mingw64)
+		basic_machine=x86_64-pc
+		os=-mingw64
+		;;
+	mingw32)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	mingw32ce)
+		basic_machine=arm-unknown
+		os=-mingw32ce
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	msys)
+		basic_machine=i686-pc
+		os=-msys
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	nacl)
+		basic_machine=le32-unknown
+		os=-nacl
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	neo-tandem)
+		basic_machine=neo-tandem
+		;;
+	nse-tandem)
+		basic_machine=nse-tandem
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	openrisc | openrisc-*)
+		basic_machine=or32-unknown
+		;;
+	os400)
+		basic_machine=powerpc-ibm
+		os=-os400
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	parisc)
+		basic_machine=hppa-unknown
+		os=-linux
+		;;
+	parisc-*)
+		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pc98)
+		basic_machine=i386-pc
+		;;
+	pc98-*)
+		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc | ppcbe)	basic_machine=powerpc-unknown
+		;;
+	ppc-* | ppcbe-*)
+		basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rdos | rdos64)
+		basic_machine=x86_64-pc
+		os=-rdos
+		;;
+	rdos32)
+		basic_machine=i386-pc
+		os=-rdos
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sde)
+		basic_machine=mipsisa32-sde
+		os=-elf
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh5el)
+		basic_machine=sh5le-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	strongarm-* | thumb-*)
+		basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tile*)
+		basic_machine=$basic_machine-unknown
+		os=-linux-gnu
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	tpf)
+		basic_machine=s390x-ibm
+		os=-tpf
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xbox)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	xscale-* | xscalee[bl]-*)
+		basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	z80-*-coff)
+		basic_machine=z80-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	mmix)
+		basic_machine=mmix-knuth
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+	# First match some system type aliases
+	# that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+	-auroraux)
+		os=-auroraux
+		;;
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+	      | -sym* | -kopensolaris* | -plan9* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* | -aros* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -bitrig* | -openbsd* | -solidbsd* \
+	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* | -cegcc* \
+	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+	      | -linux-newlib* | -linux-musl* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+	-os400*)
+		os=-os400
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-syllable*)
+		os=-syllable
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+	-tpf*)
+		os=-tpf
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-dicos*)
+		os=-dicos
+		;;
+	-nacl*)
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+	score-*)
+		os=-elf
+		;;
+	spu-*)
+		os=-elf
+		;;
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+	c4x-* | tic4x-*)
+		os=-coff
+		;;
+	c8051-*)
+		os=-elf
+		;;
+	hexagon-*)
+		os=-elf
+		;;
+	tic54x-*)
+		os=-coff
+		;;
+	tic55x-*)
+		os=-coff
+		;;
+	tic6x-*)
+		os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+	mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or1k-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-haiku)
+		os=-haiku
+		;;
+	*-ibm)
+		os=-aix
+		;;
+	*-knuth)
+		os=-mmixware
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-cnk*|-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-os400*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-tpf*)
+				vendor=ibm
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/source/Irrlicht/jpeglib/configure b/source/Irrlicht/jpeglib/configure
new file mode 100644
index 00000000..77a5df32
--- /dev/null
+++ b/source/Irrlicht/jpeglib/configure
@@ -0,0 +1,15462 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for libjpeg 9.1.0.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1
+
+  test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
+      || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     # Try only shells that exist, to save several forks.
+	     as_shell=$as_dir/$as_base
+	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+	   done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+
+test -n "$DJDIR" || exec 7<&0 &1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='libjpeg'
+PACKAGE_TARNAME='libjpeg'
+PACKAGE_VERSION='9.1.0'
+PACKAGE_STRING='libjpeg 9.1.0'
+PACKAGE_BUGREPORT=''
+PACKAGE_URL=''
+
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include 
+#ifdef HAVE_SYS_TYPES_H
+# include 
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include 
+#endif
+#ifdef STDC_HEADERS
+# include 
+# include 
+#else
+# ifdef HAVE_STDLIB_H
+#  include 
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include 
+# endif
+# include 
+#endif
+#ifdef HAVE_STRINGS_H
+# include 
+#endif
+#ifdef HAVE_INTTYPES_H
+# include 
+#endif
+#ifdef HAVE_STDINT_H
+# include 
+#endif
+#ifdef HAVE_UNISTD_H
+# include 
+#endif"
+
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+JPEG_LIB_VERSION
+MEMORYMGR
+OTOOL64
+OTOOL
+LIPO
+NMEDIT
+DSYMUTIL
+MANIFEST_TOOL
+RANLIB
+NM
+ac_ct_DUMPBIN
+DUMPBIN
+LD
+FGREP
+SED
+LIBTOOL
+OBJDUMP
+DLLTOOL
+AS
+EGREP
+GREP
+HAVE_LD_VERSION_SCRIPT_FALSE
+HAVE_LD_VERSION_SCRIPT_TRUE
+ac_ct_AR
+AR
+LN_S
+CPP
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+am__nodep
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__quote
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+MAINT
+MAINTAINER_MODE_FALSE
+MAINTAINER_MODE_TRUE
+AM_BACKSLASH
+AM_DEFAULT_VERBOSITY
+AM_DEFAULT_V
+AM_V
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_os
+target_vendor
+target_cpu
+target
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_silent_rules
+enable_maintainer_mode
+enable_dependency_tracking
+enable_ld_version_script
+enable_shared
+enable_static
+with_pic
+enable_fast_install
+with_gnu_ld
+with_sysroot
+enable_libtool_lock
+enable_maxmem
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
+		datadir sysconfdir sharedstatedir localstatedir includedir \
+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+		libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_myself" : 'X\(//\)[^/]' \| \
+	 X"$as_myself" : 'X\(//\)$' \| \
+	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+	pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures libjpeg 9.1.0 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking ...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/libjpeg]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+Program names:
+  --program-prefix=PREFIX            prepend PREFIX to installed program names
+  --program-suffix=SUFFIX            append SUFFIX to installed program names
+  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+  --target=TARGET   configure for building compilers for TARGET [HOST]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of libjpeg 9.1.0:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-silent-rules   less verbose build output (undo: "make V=1")
+  --disable-silent-rules  verbose build output (undo: "make V=0")
+  --enable-maintainer-mode
+                          enable make rules and dependencies not useful (and
+                          sometimes confusing) to the casual installer
+  --enable-dependency-tracking
+                          do not reject slow dependency extractors
+  --disable-dependency-tracking
+                          speeds up one-time build
+  --enable-ld-version-script
+                          enable linker version script (default is enabled
+                          when possible)
+  --enable-shared[=PKGS]  build shared libraries [default=yes]
+  --enable-static[=PKGS]  build static libraries [default=yes]
+  --enable-fast-install[=PKGS]
+                          optimize for fast installation [default=yes]
+  --disable-libtool-lock  avoid locking (might break parallel builds)
+  --enable-maxmem=N     enable use of temp files, set max mem usage to N MB
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-pic[=PKGS]       try to use only PIC/non-PIC objects [default=use
+                          both]
+  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-sysroot=DIR Search for dependent libraries within DIR
+                        (or the compiler's sysroot if not specified).
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L if you have libraries in a
+              nonstandard directory 
+  LIBS        libraries to pass to the linker, e.g. -l
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I if
+              you have headers in a nonstandard directory 
+  CPP         C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+libjpeg configure 9.1.0
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 test -x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval \${$3+:} false; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case  declares $2.
+   For example, HP-UX 11i  declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer  to  if __STDC__ is defined, since
+     exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include 
+#else
+# include 
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by libjpeg $as_me 9.1.0, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+	"s/'\''/'\''\\\\'\'''\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	$as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	# differences in whitespace do not lead to failure.
+	ac_old_val_w=`echo x $ac_old_val`
+	ac_new_val_w=`echo x $ac_new_val`
+	if test "$ac_old_val_w" != "$ac_new_val_w"; then
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	  ac_cache_corrupted=:
+	else
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+	  eval $ac_var=\$ac_old_val
+	fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+# Directory where autotools helper scripts lives.
+ac_aux_dir=
+for ac_dir in . "$srcdir"/.; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  as_fn_error $? "cannot find install-sh, install.sh, or shtool in . \"$srcdir\"/." "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+
+# Generate configuration headers.
+ac_config_headers="$ac_config_headers jconfig.h:jconfig.cfg"
+
+
+# Hack: disable autoheader so that it doesn't overwrite our cfg template.
+AUTOHEADER="echo autoheader ignored"
+
+# Check system type
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5
+$as_echo_n "checking target system type... " >&6; }
+if ${ac_cv_target+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$target_alias" = x; then
+  ac_cv_target=$ac_cv_host
+else
+  ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5
+$as_echo "$ac_cv_target" >&6; }
+case $ac_cv_target in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;;
+esac
+target=$ac_cv_target
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_target
+shift
+target_cpu=$1
+target_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+target_os=$*
+IFS=$ac_save_IFS
+case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+  test "$program_prefix$program_suffix$program_transform_name" = \
+    NONENONEs,x,x, &&
+  program_prefix=${target_alias}-
+
+# Initialize Automake
+# Don't require all the GNU mandated files
+am__api_version='1.14'
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+  ./ | .// | /[cC]/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+	if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+	  if test $ac_prog = install &&
+	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    rm -rf conftest.one conftest.two conftest.dir
+	    echo one > conftest.one
+	    echo two > conftest.two
+	    mkdir conftest.dir
+	    if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+	      test -s conftest.one && test -s conftest.two &&
+	      test -s conftest.dir/conftest.one &&
+	      test -s conftest.dir/conftest.two
+	    then
+	      ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+	      break 3
+	    fi
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+
+  done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[\\\"\#\$\&\'\`$am_lf]*)
+    as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+  *[\\\"\#\$\&\'\`$am_lf\ \	]*)
+    as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   am_has_slept=no
+   for am_try in 1 2; do
+     echo "timestamp, slept: $am_has_slept" > conftest.file
+     set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+     if test "$*" = "X"; then
+	# -L didn't work.
+	set X `ls -t "$srcdir/configure" conftest.file`
+     fi
+     if test "$*" != "X $srcdir/configure conftest.file" \
+	&& test "$*" != "X conftest.file $srcdir/configure"; then
+
+	# If neither matched, then we have a broken ls.  This can happen
+	# if, for instance, CONFIG_SHELL is bash and it inherits a
+	# broken ls alias from the environment.  This has actually
+	# happened.  Such a system could not be considered "sane".
+	as_fn_error $? "ls -t appears to fail.  Make sure there is not a broken
+  alias in your environment" "$LINENO" 5
+     fi
+     if test "$2" = conftest.file || test $am_try -eq 2; then
+       break
+     fi
+     # Just in case.
+     sleep 1
+     am_has_slept=yes
+   done
+   test "$2" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   as_fn_error $? "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+  ( sleep 1 ) &
+  am_sleep_pid=$!
+fi
+
+rm -f conftest.file
+
+test "$program_prefix" != NONE &&
+  program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
+else
+  am_missing_run=
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip".  However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+  if ${ac_cv_path_mkdir+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in mkdir gmkdir; do
+	 for ac_exec_ext in '' $ac_executable_extensions; do
+	   as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
+	   case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+	     'mkdir (GNU coreutils) '* | \
+	     'mkdir (coreutils) '* | \
+	     'mkdir (fileutils) '4.1*)
+	       ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+	       break 3;;
+	   esac
+	 done
+       done
+  done
+IFS=$as_save_IFS
+
+fi
+
+  test -d ./--version && rmdir ./--version
+  if test "${ac_cv_path_mkdir+set}" = set; then
+    MKDIR_P="$ac_cv_path_mkdir -p"
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for MKDIR_P within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    MKDIR_P="$ac_install_sh -d"
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+for ac_prog in gawk mawk nawk awk
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AWK+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AWK="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+	@echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  SET_MAKE=
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+  enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in # (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=1;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+    AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  am__isrc=' -I$(srcdir)'
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='libjpeg'
+ VERSION='9.1.0'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# For better backward compatibility.  To be removed once Automake 1.9.x
+# dies out for good.  For more background, see:
+# 
+# 
+mkdir_p='$(MKDIR_P)'
+
+# We need awk for the "check" target.  The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility.  Yes, it's still used
+# in the wild :-(  We should find a proper way to deprecate it ...
+AMTAR='$${TAR-tar}'
+
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar  pax cpio none'
+
+am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
+
+
+
+
+
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes.  So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+  cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present.  This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: 
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message.  This
+can help us improve future automake versions.
+
+END
+  if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+    echo 'Configuration will proceed anyway, since you have set the' >&2
+    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+    echo >&2
+  else
+    cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: .
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+    as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
+  fi
+fi
+
+# Make --enable-silent-rules the default.
+# To get verbose build output you may configure
+# with --disable-silent-rules or use "make V=1".
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+  enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in # (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=0;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+    AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+
+# Add configure option --enable-maintainer-mode which enables
+# dependency checking and generation useful to package maintainers.
+# This is made an option to avoid confusing end users.
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5
+$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; }
+    # Check whether --enable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then :
+  enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval
+else
+  USE_MAINTAINER_MODE=no
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5
+$as_echo "$USE_MAINTAINER_MODE" >&6; }
+   if test $USE_MAINTAINER_MODE = yes; then
+  MAINTAINER_MODE_TRUE=
+  MAINTAINER_MODE_FALSE='#'
+else
+  MAINTAINER_MODE_TRUE='#'
+  MAINTAINER_MODE_FALSE=
+fi
+
+  MAINT=$MAINTAINER_MODE_TRUE
+
+
+
+# Check for programs
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+	;;
+    [ab].out )
+	# We found the default executable, but exeext='' is most
+	# certainly right.
+	break;;
+    *.* )
+	if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+	then :; else
+	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	fi
+	# We set ac_cv_exeext here because the later test for it is not
+	# safe: cross compilers may not add the suffix if given an `-o'
+	# argument, so we may need to know it at that point already.
+	# Even if this section looks crufty: it has the advantage of
+	# actually working.
+	break;;
+    * )
+	break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include 
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include 
+#include 
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
+$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
+if ${am_cv_prog_cc_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+  # Make sure it works both with $CC and with simple cc.
+  # Following AC_PROG_CC_C_O, we do the test twice because some
+  # compilers refuse to overwrite an existing .o file with -o,
+  # though they will create one.
+  am_cv_prog_cc_c_o=yes
+  for am_i in 1 2; do
+    if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
+   ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   (exit $ac_status); } \
+         && test -f conftest2.$ac_objext; then
+      : OK
+    else
+      am_cv_prog_cc_c_o=no
+      break
+    fi
+  done
+  rm -f core conftest*
+  unset am_i
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
+$as_echo "$am_cv_prog_cc_c_o" >&6; }
+if test "$am_cv_prog_cc_c_o" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+  enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+  am__nodep='_no'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+  AMDEP_TRUE=
+  AMDEP_FALSE='#'
+else
+  AMDEP_TRUE='#'
+  AMDEP_FALSE=
+fi
+
+
+
+depcc="$CC"   am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named 'D' -- because '-MD' means "put the output
+  # in D".
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_CC_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+  fi
+  am__universal=false
+  case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+      # Solaris 10 /bin/sh.
+      echo '/* dummy */' > sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with '-c' and '-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle '-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs.
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # After this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested.
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok '-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_CC_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+  am__fastdepCC_TRUE=
+  am__fastdepCC_FALSE='#'
+else
+  am__fastdepCC_TRUE='#'
+  am__fastdepCC_FALSE=
+fi
+
+
+   case $ac_cv_prog_cc_stdc in #(
+  no) :
+    ac_cv_prog_cc_c99=no; ac_cv_prog_cc_c89=no ;; #(
+  *) :
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5
+$as_echo_n "checking for $CC option to accept ISO C99... " >&6; }
+if ${ac_cv_prog_cc_c99+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c99=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include 
+#include 
+#include 
+#include 
+#include 
+
+// Check varargs macros.  These examples are taken from C99 6.10.3.5.
+#define debug(...) fprintf (stderr, __VA_ARGS__)
+#define showlist(...) puts (#__VA_ARGS__)
+#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
+static void
+test_varargs_macros (void)
+{
+  int x = 1234;
+  int y = 5678;
+  debug ("Flag");
+  debug ("X = %d\n", x);
+  showlist (The first, second, and third items.);
+  report (x>y, "x is %d but y is %d", x, y);
+}
+
+// Check long long types.
+#define BIG64 18446744073709551615ull
+#define BIG32 4294967295ul
+#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
+#if !BIG_OK
+  your preprocessor is broken;
+#endif
+#if BIG_OK
+#else
+  your preprocessor is broken;
+#endif
+static long long int bignum = -9223372036854775807LL;
+static unsigned long long int ubignum = BIG64;
+
+struct incomplete_array
+{
+  int datasize;
+  double data[];
+};
+
+struct named_init {
+  int number;
+  const wchar_t *name;
+  double average;
+};
+
+typedef const char *ccp;
+
+static inline int
+test_restrict (ccp restrict text)
+{
+  // See if C++-style comments work.
+  // Iterate through items via the restricted pointer.
+  // Also check for declarations in for loops.
+  for (unsigned int i = 0; *(text+i) != '\0'; ++i)
+    continue;
+  return 0;
+}
+
+// Check varargs and va_copy.
+static void
+test_varargs (const char *format, ...)
+{
+  va_list args;
+  va_start (args, format);
+  va_list args_copy;
+  va_copy (args_copy, args);
+
+  const char *str;
+  int number;
+  float fnumber;
+
+  while (*format)
+    {
+      switch (*format++)
+	{
+	case 's': // string
+	  str = va_arg (args_copy, const char *);
+	  break;
+	case 'd': // int
+	  number = va_arg (args_copy, int);
+	  break;
+	case 'f': // float
+	  fnumber = va_arg (args_copy, double);
+	  break;
+	default:
+	  break;
+	}
+    }
+  va_end (args_copy);
+  va_end (args);
+}
+
+int
+main ()
+{
+
+  // Check bool.
+  _Bool success = false;
+
+  // Check restrict.
+  if (test_restrict ("String literal") == 0)
+    success = true;
+  char *restrict newvar = "Another string";
+
+  // Check varargs.
+  test_varargs ("s, d' f .", "string", 65, 34.234);
+  test_varargs_macros ();
+
+  // Check flexible array members.
+  struct incomplete_array *ia =
+    malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
+  ia->datasize = 10;
+  for (int i = 0; i < ia->datasize; ++i)
+    ia->data[i] = i * 1.234;
+
+  // Check named initializers.
+  struct named_init ni = {
+    .number = 34,
+    .name = L"Test wide string",
+    .average = 543.34343,
+  };
+
+  ni.number = 58;
+
+  int dynamic_array[ni.number];
+  dynamic_array[ni.number - 1] = 543;
+
+  // work around unused variable warnings
+  return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x'
+	  || dynamic_array[ni.number - 1] != 543);
+
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c99=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c99" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c99" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c99"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
+$as_echo "$ac_cv_prog_cc_c99" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c99" != xno; then :
+  ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include 
+#include 
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+  ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89
+else
+  ac_cv_prog_cc_stdc=no
+fi
+
+fi
+ ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO Standard C" >&5
+$as_echo_n "checking for $CC option to accept ISO Standard C... " >&6; }
+  if ${ac_cv_prog_cc_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+fi
+
+  case $ac_cv_prog_cc_stdc in #(
+  no) :
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;; #(
+  '') :
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;; #(
+  *) :
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_stdc" >&5
+$as_echo "$ac_cv_prog_cc_stdc" >&6; } ;;
+esac
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if ${ac_cv_prog_CPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer  to  if __STDC__ is defined, since
+  #  exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include 
+#else
+# include 
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include 
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer  to  if __STDC__ is defined, since
+  #  exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include 
+#else
+# include 
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include 
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+	@echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  SET_MAKE=
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+
+if test -n "$ac_tool_prefix"; then
+  for ac_prog in ar lib "link -lib"
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$AR" && break
+  done
+fi
+if test -z "$AR"; then
+  ac_ct_AR=$AR
+  for ac_prog in ar lib "link -lib"
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_AR"; then
+  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_AR="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_AR" && break
+done
+
+  if test "x$ac_ct_AR" = x; then
+    AR="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    AR=$ac_ct_AR
+  fi
+fi
+
+: ${AR=ar}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5
+$as_echo_n "checking the archiver ($AR) interface... " >&6; }
+if ${am_cv_ar_interface+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+   am_cv_ar_interface=ar
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int some_variable = 0;
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5'
+      { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5
+  (eval $am_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+      if test "$ac_status" -eq 0; then
+        am_cv_ar_interface=ar
+      else
+        am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5'
+        { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5
+  (eval $am_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+        if test "$ac_status" -eq 0; then
+          am_cv_ar_interface=lib
+        else
+          am_cv_ar_interface=unknown
+        fi
+      fi
+      rm -f conftest.lib libconftest.a
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5
+$as_echo "$am_cv_ar_interface" >&6; }
+
+case $am_cv_ar_interface in
+ar)
+  ;;
+lib)
+  # Microsoft lib, so override with the ar-lib wrapper script.
+  # FIXME: It is wrong to rewrite AR.
+  # But if we don't then we get into trouble of one sort or another.
+  # A longer-term fix would be to have automake use am__AR in this case,
+  # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something
+  # similar.
+  AR="$am_aux_dir/ar-lib $AR"
+  ;;
+unknown)
+  as_fn_error $? "could not determine $AR interface" "$LINENO" 5
+  ;;
+esac
+
+
+# Check if LD supports linker scripts,
+# and define automake conditional HAVE_LD_VERSION_SCRIPT if so.
+# Check whether --enable-ld-version-script was given.
+if test "${enable_ld_version_script+set}" = set; then :
+  enableval=$enable_ld_version_script; have_ld_version_script=$enableval
+fi
+
+if test -z "$have_ld_version_script"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if LD -Wl,--version-script works" >&5
+$as_echo_n "checking if LD -Wl,--version-script works... " >&6; }
+  save_LDFLAGS="$LDFLAGS"
+  LDFLAGS="$LDFLAGS -Wl,--version-script=conftest.map"
+  cat > conftest.map <conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  have_ld_version_script=yes
+else
+  have_ld_version_script=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  rm -f conftest.map
+  LDFLAGS="$save_LDFLAGS"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_ld_version_script" >&5
+$as_echo "$have_ld_version_script" >&6; }
+fi
+ if test "$have_ld_version_script" = "yes"; then
+  HAVE_LD_VERSION_SCRIPT_TRUE=
+  HAVE_LD_VERSION_SCRIPT_FALSE='#'
+else
+  HAVE_LD_VERSION_SCRIPT_TRUE='#'
+  HAVE_LD_VERSION_SCRIPT_FALSE=
+fi
+
+
+# See if compiler supports prototypes.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for function prototypes" >&5
+$as_echo_n "checking for function prototypes... " >&6; }
+if ${ijg_cv_have_prototypes+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int testfunction (int arg1, int * arg2); /* check prototypes */
+struct methods_struct {		/* check method-pointer declarations */
+  int (*error_exit) (char *msgtext);
+  int (*trace_message) (char *msgtext);
+  int (*another_method) (void);
+};
+int testfunction (int arg1, int * arg2) /* check definitions */
+{ return arg2[arg1]; }
+int test2function (void)	/* check void arg list */
+{ return 0; }
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ijg_cv_have_prototypes=yes
+else
+  ijg_cv_have_prototypes=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ijg_cv_have_prototypes" >&5
+$as_echo "$ijg_cv_have_prototypes" >&6; }
+if test $ijg_cv_have_prototypes = yes; then
+
+$as_echo "#define HAVE_PROTOTYPES 1" >>confdefs.h
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Your compiler does not seem to know about function prototypes.
+    Perhaps it needs a special switch to enable ANSI C mode.
+    If so, we recommend running configure like this:
+       ./configure  CC='cc -switch'
+    where -switch is the proper switch." >&5
+$as_echo "$as_me: WARNING: Your compiler does not seem to know about function prototypes.
+    Perhaps it needs a special switch to enable ANSI C mode.
+    If so, we recommend running configure like this:
+       ./configure  CC='cc -switch'
+    where -switch is the proper switch." >&2;}
+fi
+
+# Check header files
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include 
+#include 
+#include 
+#include 
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include 
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include 
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include 
+#include 
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in stddef.h stdlib.h locale.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+ac_fn_c_check_header_mongrel "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default"
+if test "x$ac_cv_header_string_h" = xyes; then :
+
+else
+
+$as_echo "#define NEED_BSD_STRINGS 1" >>confdefs.h
+
+fi
+
+
+
+# See whether type size_t is defined in any ANSI-standard places;
+# if not, perhaps it is defined in .
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for size_t" >&5
+$as_echo_n "checking for size_t... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#ifdef HAVE_STDDEF_H
+#include 
+#endif
+#ifdef HAVE_STDLIB_H
+#include 
+#endif
+#include 
+#ifdef NEED_BSD_STRINGS
+#include 
+#else
+#include 
+#endif
+typedef size_t my_size_t;
+
+int
+main ()
+{
+ my_size_t foovar;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ijg_size_t_ok=yes
+else
+  ijg_size_t_ok="not ANSI, perhaps it is in sys/types.h"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ijg_size_t_ok" >&5
+$as_echo "$ijg_size_t_ok" >&6; }
+if test "$ijg_size_t_ok" != yes; then
+  ac_fn_c_check_header_mongrel "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_types_h" = xyes; then :
+
+$as_echo "#define NEED_SYS_TYPES_H 1" >>confdefs.h
+
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include 
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "size_t" >/dev/null 2>&1; then :
+  ijg_size_t_ok="size_t is in sys/types.h"
+else
+  ijg_size_t_ok=no
+fi
+rm -f conftest*
+
+else
+  ijg_size_t_ok=no
+fi
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ijg_size_t_ok" >&5
+$as_echo "$ijg_size_t_ok" >&6; }
+  if test "$ijg_size_t_ok" = no; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Type size_t is not defined in any of the usual places.
+      Try putting '\"typedef unsigned int size_t;\"' in jconfig.h." >&5
+$as_echo "$as_me: WARNING: Type size_t is not defined in any of the usual places.
+      Try putting '\"typedef unsigned int size_t;\"' in jconfig.h." >&2;}
+  fi
+fi
+
+# Check compiler characteristics
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for type unsigned char" >&5
+$as_echo_n "checking for type unsigned char... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+ unsigned char un_char;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_UNSIGNED_CHAR 1" >>confdefs.h
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for type unsigned short" >&5
+$as_echo_n "checking for type unsigned short... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+ unsigned short un_short;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_UNSIGNED_SHORT 1" >>confdefs.h
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for type void" >&5
+$as_echo_n "checking for type void... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Caution: a C++ compiler will insist on valid prototypes */
+typedef void * void_ptr;	/* check void * */
+#ifdef HAVE_PROTOTYPES		/* check ptr to function returning void */
+typedef void (*void_func) (int a, int b);
+#else
+typedef void (*void_func) ();
+#endif
+
+#ifdef HAVE_PROTOTYPES		/* check void function result */
+void test3function (void_ptr arg1, void_func arg2)
+#else
+void test3function (arg1, arg2)
+     void_ptr arg1;
+     void_func arg2;
+#endif
+{
+  char * locptr = (char *) arg1; /* check casting to and from void * */
+  arg1 = (void *) locptr;
+  (*arg2) (1, 2);		/* check call of fcn returning void */
+}
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+$as_echo "#define void char" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
+$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
+if ${ac_cv_c_const+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+#ifndef __cplusplus
+  /* Ultrix mips cc rejects this sort of thing.  */
+  typedef int charset[2];
+  const charset cs = { 0, 0 };
+  /* SunOS 4.1.1 cc rejects this.  */
+  char const *const *pcpcc;
+  char **ppc;
+  /* NEC SVR4.0.2 mips cc rejects this.  */
+  struct point {int x, y;};
+  static struct point const zero = {0,0};
+  /* AIX XL C 1.02.0.0 rejects this.
+     It does not let you subtract one const X* pointer from another in
+     an arm of an if-expression whose if-part is not a constant
+     expression */
+  const char *g = "string";
+  pcpcc = &g + (g ? g-g : 0);
+  /* HPUX 7.0 cc rejects these. */
+  ++pcpcc;
+  ppc = (char**) pcpcc;
+  pcpcc = (char const *const *) ppc;
+  { /* SCO 3.2v4 cc rejects this sort of thing.  */
+    char tx;
+    char *t = &tx;
+    char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+    *t++ = 0;
+    if (s) return 0;
+  }
+  { /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+    int x[] = {25, 17};
+    const int *foo = &x[0];
+    ++foo;
+  }
+  { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+    typedef const int *iptr;
+    iptr p = 0;
+    ++p;
+  }
+  { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying
+       "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+    struct s { int j; const int *ap[3]; } bx;
+    struct s *b = &bx; b->j = 5;
+  }
+  { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+    const int foo = 10;
+    if (!foo) return 0;
+  }
+  return !cs[0] && !zero.x;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_const=yes
+else
+  ac_cv_c_const=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5
+$as_echo "$ac_cv_c_const" >&6; }
+if test $ac_cv_c_const = no; then
+
+$as_echo "#define const /**/" >>confdefs.h
+
+fi
+
+
+# Check for non-broken inline under various spellings
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
+$as_echo_n "checking for inline... " >&6; }
+ijg_cv_inline=""
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+} __inline__ int foo() { return 0; }
+int bar() { return foo();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ijg_cv_inline="__inline__"
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+} __inline int foo() { return 0; }
+int bar() { return foo();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ijg_cv_inline="__inline"
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+} inline int foo() { return 0; }
+int bar() { return foo();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ijg_cv_inline="inline"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ijg_cv_inline" >&5
+$as_echo "$ijg_cv_inline" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define INLINE $ijg_cv_inline
+_ACEOF
+
+
+# We cannot check for bogus warnings, but at least we can check for errors
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken incomplete types" >&5
+$as_echo_n "checking for broken incomplete types... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+ typedef struct undefined_structure * undef_struct_ptr;
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: broken" >&5
+$as_echo "broken" >&6; }
+
+$as_echo "#define INCOMPLETE_TYPES_BROKEN 1" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+# Test whether global names are unique to at least 15 chars
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for short external names" >&5
+$as_echo_n "checking for short external names... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int possibly_duplicate_function () { return 0; }
+int possibly_dupli_function () { return 1; }
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: short" >&5
+$as_echo "short" >&6; }
+
+$as_echo "#define NEED_SHORT_EXTERNAL_NAMES 1" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+
+# Run-time checks
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking to see if char is signed" >&5
+$as_echo_n "checking to see if char is signed... " >&6; }
+if test "$cross_compiling" = yes; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Assuming that char is signed on target machine.
+    If it is unsigned, this will be a little bit inefficient." >&5
+$as_echo "$as_me: WARNING: Assuming that char is signed on target machine.
+    If it is unsigned, this will be a little bit inefficient." >&2;}
+
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#ifdef HAVE_STDLIB_H
+#include 
+#endif
+#include 
+#ifdef HAVE_PROTOTYPES
+int is_char_signed (int arg)
+#else
+int is_char_signed (arg)
+     int arg;
+#endif
+{
+  if (arg == 189) {		/* expected result for unsigned char */
+    return 0;			/* type char is unsigned */
+  }
+  else if (arg != -67) {	/* expected result for signed char */
+    printf("Hmm, it seems 'char' is not eight bits wide on your machine.\n");
+    printf("I fear the JPEG software will not work at all.\n\n");
+  }
+  return 1;			/* assume char is signed otherwise */
+}
+char signed_char_check = (char) (-67);
+int main() {
+  exit(is_char_signed((int) signed_char_check));
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+$as_echo "#define CHAR_IS_UNSIGNED 1" >>confdefs.h
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking to see if right shift is signed" >&5
+$as_echo_n "checking to see if right shift is signed... " >&6; }
+if test "$cross_compiling" = yes; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: Assuming that right shift is signed on target machine." >&5
+$as_echo "Assuming that right shift is signed on target machine." >&6; }
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#ifdef HAVE_STDLIB_H
+#include 
+#endif
+#include 
+#ifdef HAVE_PROTOTYPES
+int is_shifting_signed (long arg)
+#else
+int is_shifting_signed (arg)
+     long arg;
+#endif
+/* See whether right-shift on a long is signed or not. */
+{
+  long res = arg >> 4;
+
+  if (res == -0x7F7E80CL) {	/* expected result for signed shift */
+    return 1;			/* right shift is signed */
+  }
+  /* see if unsigned-shift hack will fix it. */
+  /* we can't just test exact value since it depends on width of long... */
+  res |= (~0L) << (32-4);
+  if (res == -0x7F7E80CL) {	/* expected result now? */
+    return 0;			/* right shift is unsigned */
+  }
+  printf("Right shift isn't acting as I expect it to.\n");
+  printf("I fear the JPEG software will not work at all.\n\n");
+  return 0;			/* try it with unsigned anyway */
+}
+int main() {
+  exit(is_shifting_signed(-0x7F7E80B1L));
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+$as_echo "#define RIGHT_SHIFT_IS_UNSIGNED 1" >>confdefs.h
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking to see if fopen accepts b spec" >&5
+$as_echo_n "checking to see if fopen accepts b spec... " >&6; }
+if test "$cross_compiling" = yes; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: Assuming that it does." >&5
+$as_echo "Assuming that it does." >&6; }
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#ifdef HAVE_STDLIB_H
+#include 
+#endif
+#include 
+int main() {
+  if (fopen("conftestdata", "wb") != NULL)
+    exit(0);
+  exit(1);
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+$as_echo "#define DONT_USE_B_MODE 1" >>confdefs.h
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+# Configure libtool
+enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args.
+set dummy ${ac_tool_prefix}as; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AS+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AS"; then
+  ac_cv_prog_AS="$AS" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AS="${ac_tool_prefix}as"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AS=$ac_cv_prog_AS
+if test -n "$AS"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5
+$as_echo "$AS" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_AS"; then
+  ac_ct_AS=$AS
+  # Extract the first word of "as", so it can be a program name with args.
+set dummy as; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AS+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_AS"; then
+  ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_AS="as"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AS=$ac_cv_prog_ac_ct_AS
+if test -n "$ac_ct_AS"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AS" >&5
+$as_echo "$ac_ct_AS" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_AS" = x; then
+    AS="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    AS=$ac_ct_AS
+  fi
+else
+  AS="$ac_cv_prog_AS"
+fi
+
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DLLTOOL"; then
+  ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DLLTOOL=$ac_cv_prog_DLLTOOL
+if test -n "$DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+$as_echo "$DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DLLTOOL"; then
+  ac_ct_DLLTOOL=$DLLTOOL
+  # Extract the first word of "dlltool", so it can be a program name with args.
+set dummy dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DLLTOOL"; then
+  ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
+if test -n "$ac_ct_DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+$as_echo "$ac_ct_DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DLLTOOL" = x; then
+    DLLTOOL="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DLLTOOL=$ac_ct_DLLTOOL
+  fi
+else
+  DLLTOOL="$ac_cv_prog_DLLTOOL"
+fi
+
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OBJDUMP"; then
+  ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+  ac_ct_OBJDUMP=$OBJDUMP
+  # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OBJDUMP"; then
+  ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OBJDUMP="objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OBJDUMP" = x; then
+    OBJDUMP="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OBJDUMP=$ac_ct_OBJDUMP
+  fi
+else
+  OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+  ;;
+esac
+
+test -z "$AS" && AS=as
+
+
+
+
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+
+
+
+
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+
+case `pwd` in
+  *\ * | *\	*)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.4.2'
+macro_revision='1.3337'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO ""
+}
+
+case "$ECHO" in
+  printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+  print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+  *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+            ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+     for ac_i in 1 2 3 4 5 6 7; do
+       ac_script="$ac_script$as_nl$ac_script"
+     done
+     echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+     { ac_script=; unset ac_script;}
+     if test -z "$SED"; then
+  ac_path_SED_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+  # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+  ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo '' >> "conftest.nl"
+    "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_SED_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_SED="$ac_path_SED"
+      ac_path_SED_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_SED_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_SED"; then
+    as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+  fi
+else
+  ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+  rm -f conftest.sed
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if ${ac_cv_path_FGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+   then ac_cv_path_FGREP="$GREP -F"
+   else
+     if test -z "$FGREP"; then
+  ac_path_FGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in fgrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_FGREP" || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+  # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'FGREP' >> "conftest.nl"
+    "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_FGREP="$ac_path_FGREP"
+      ac_path_FGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_FGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_FGREP"; then
+    as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_FGREP=$FGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+  withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [\\/]* | ?:[\\/]*)
+      re_direlt='/[^/][^/]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 &5
+$as_echo "$LD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 &5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if ${lt_cv_path_NM+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_nm_to_check="${ac_tool_prefix}nm"
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS="$lt_save_ifs"
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm="$ac_dir/$lt_tmp_nm"
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+	# Check to see if the nm accepts a BSD-compat flag.
+	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
+	#   nm: unknown option "B" ignored
+	# Tru64's nm complains that /dev/null is an invalid object file
+	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+	*/dev/null* | *'Invalid file or object type'*)
+	  lt_cv_path_NM="$tmp_nm -B"
+	  break
+	  ;;
+	*)
+	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	  */dev/null*)
+	    lt_cv_path_NM="$tmp_nm -p"
+	    break
+	    ;;
+	  *)
+	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	    continue # so that we can try to find one that supports BSD flags
+	    ;;
+	  esac
+	  ;;
+	esac
+      fi
+    done
+    IFS="$lt_save_ifs"
+  done
+  : ${lt_cv_path_NM=no}
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test "$lt_cv_path_NM" != "no"; then
+  NM="$lt_cv_path_NM"
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in dumpbin "link -dump"
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DUMPBIN+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DUMPBIN"; then
+  ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$DUMPBIN" && break
+  done
+fi
+if test -z "$DUMPBIN"; then
+  ac_ct_DUMPBIN=$DUMPBIN
+  for ac_prog in dumpbin "link -dump"
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DUMPBIN"; then
+  ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_DUMPBIN" && break
+done
+
+  if test "x$ac_ct_DUMPBIN" = x; then
+    DUMPBIN=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DUMPBIN=$ac_ct_DUMPBIN
+  fi
+fi
+
+    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+
+  if test "$DUMPBIN" != ":"; then
+    NM="$DUMPBIN"
+  fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
+$as_echo_n "checking the name lister ($NM) interface... " >&6; }
+if ${lt_cv_nm_interface+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: output\"" >&5)
+  cat conftest.out >&5
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
+$as_echo "$lt_cv_nm_interface" >&6; }
+
+# find the maximum length of command line arguments
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
+$as_echo_n "checking the maximum length of command line arguments... " >&6; }
+if ${lt_cv_sys_max_cmd_len+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+    i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw* | cegcc*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  os2*)
+    # The test takes a long time on OS/2.
+    lt_cv_sys_max_cmd_len=8192
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[	 ]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      # Make teststring a little bigger before we do anything with it.
+      # a 1K string should be a reasonable start.
+      for i in 1 2 3 4 5 6 7 8 ; do
+        teststring=$teststring$teststring
+      done
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      # If test is not a shell built-in, we'll probably end up computing a
+      # maximum length that is only half of the actual maximum length, but
+      # we can't tell.
+      while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+	         = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+	      test $i != 17 # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      # Only check the string length outside the loop.
+      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on
+      # massive amounts of additional arguments before passing them to the
+      # linker.  It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+
+fi
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
+$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+
+
+
+
+
+: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5
+$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; }
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+  test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
+      = c,a/b,b/c, \
+    && eval 'test $(( 1 + 1 )) -eq 2 \
+    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+  && xsi_shell=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5
+$as_echo "$xsi_shell" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5
+$as_echo_n "checking whether the shell understands \"+=\"... " >&6; }
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \
+    >/dev/null 2>&1 \
+  && lt_shell_append=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5
+$as_echo "$lt_shell_append" >&6; }
+
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  lt_unset=unset
+else
+  lt_unset=false
+fi
+
+
+
+
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  lt_SP2NL='tr \040 \012'
+  lt_NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  lt_SP2NL='tr \100 \n'
+  lt_NL2SP='tr \r\n \100\100'
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5
+$as_echo_n "checking how to convert $build file names to $host format... " >&6; }
+if ${lt_cv_to_host_file_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+        ;;
+    esac
+    ;;
+  *-*-cygwin* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_noop
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+        ;;
+    esac
+    ;;
+  * ) # unhandled hosts (and "normal" native builds)
+    lt_cv_to_host_file_cmd=func_convert_file_noop
+    ;;
+esac
+
+fi
+
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5
+$as_echo "$lt_cv_to_host_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5
+$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; }
+if ${lt_cv_to_tool_file_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  #assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+        ;;
+    esac
+    ;;
+esac
+
+fi
+
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5
+$as_echo "$lt_cv_to_tool_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
+$as_echo_n "checking for $LD option to reload object files... " >&6; }
+if ${lt_cv_ld_reload_flag+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_reload_flag='-r'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
+$as_echo "$lt_cv_ld_reload_flag" >&6; }
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    if test "$GCC" != yes; then
+      reload_cmds=false
+    fi
+    ;;
+  darwin*)
+    if test "$GCC" = yes; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OBJDUMP"; then
+  ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+  ac_ct_OBJDUMP=$OBJDUMP
+  # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OBJDUMP"; then
+  ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OBJDUMP="objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OBJDUMP" = x; then
+    OBJDUMP="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OBJDUMP=$ac_ct_OBJDUMP
+  fi
+else
+  OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
+$as_echo_n "checking how to recognize dependent libraries... " >&6; }
+if ${lt_cv_deplibs_check_method+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[4-9]*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[45]*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump',
+  # unless we find 'file', for example because we are cross-compiling.
+  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+  if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    # Keep this pattern in sync with the one in func_win32_libid.
+    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+cegcc*)
+  # use the weaker test based on 'objdump'. See mingw*.
+  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+haiku*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[3-9]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+*nto* | *qnx*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+openbsd*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+tpf*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
+$as_echo "$lt_cv_deplibs_check_method" >&6; }
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+  case $host_os in
+  mingw* | pw32*)
+    if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+      want_nocaseglob=yes
+    else
+      file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"`
+    fi
+    ;;
+  esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DLLTOOL"; then
+  ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DLLTOOL=$ac_cv_prog_DLLTOOL
+if test -n "$DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+$as_echo "$DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DLLTOOL"; then
+  ac_ct_DLLTOOL=$DLLTOOL
+  # Extract the first word of "dlltool", so it can be a program name with args.
+set dummy dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DLLTOOL"; then
+  ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
+if test -n "$ac_ct_DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+$as_echo "$ac_ct_DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DLLTOOL" = x; then
+    DLLTOOL="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DLLTOOL=$ac_ct_DLLTOOL
+  fi
+else
+  DLLTOOL="$ac_cv_prog_DLLTOOL"
+fi
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5
+$as_echo_n "checking how to associate runtime and link libraries... " >&6; }
+if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+  # two different shell functions defined in ltmain.sh
+  # decide which to use based on capabilities of $DLLTOOL
+  case `$DLLTOOL --help 2>&1` in
+  *--identify-strict*)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+    ;;
+  *)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+    ;;
+  esac
+  ;;
+*)
+  # fallback: assume linklib IS sharedlib
+  lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+  ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5
+$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; }
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  for ac_prog in ar
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$AR" && break
+  done
+fi
+if test -z "$AR"; then
+  ac_ct_AR=$AR
+  for ac_prog in ar
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_AR"; then
+  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_AR="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_AR" && break
+done
+
+  if test "x$ac_ct_AR" = x; then
+    AR="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    AR=$ac_ct_AR
+  fi
+fi
+
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5
+$as_echo_n "checking for archiver @FILE support... " >&6; }
+if ${lt_cv_ar_at_file+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ar_at_file=no
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  echo conftest.$ac_objext > conftest.lst
+      lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5'
+      { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+  (eval $lt_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+      if test "$ac_status" -eq 0; then
+	# Ensure the archiver fails upon bogus file names.
+	rm -f conftest.$ac_objext libconftest.a
+	{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+  (eval $lt_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+	if test "$ac_status" -ne 0; then
+          lt_cv_ar_at_file=@
+        fi
+      fi
+      rm -f conftest.* libconftest.a
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
+$as_echo "$lt_cv_ar_at_file" >&6; }
+
+if test "x$lt_cv_ar_at_file" = xno; then
+  archiver_list_spec=
+else
+  archiver_list_spec=$lt_cv_ar_at_file
+fi
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+test -z "$STRIP" && STRIP=:
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_RANLIB="ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_RANLIB" = x; then
+    RANLIB=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    RANLIB=$ac_ct_RANLIB
+  fi
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+test -z "$RANLIB" && RANLIB=:
+
+
+
+
+
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
+$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
+if ${lt_cv_sys_global_symbol_pipe+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[BCDT]'
+  ;;
+cygwin* | mingw* | pw32* | cegcc*)
+  symcode='[ABCDGISTW]'
+  ;;
+hpux*)
+  if test "$host_cpu" = ia64; then
+    symcode='[ABCDEGRST]'
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[BCDEGRST]'
+  ;;
+osf*)
+  symcode='[BCDEGQRST]'
+  ;;
+solaris*)
+  symcode='[BDRT]'
+  ;;
+sco3.2v5*)
+  symcode='[DT]'
+  ;;
+sysv4.2uw2*)
+  symcode='[DT]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[ABDT]'
+  ;;
+sysv4)
+  symcode='[DFNSTU]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[ABCDGIRSTW]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/  {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+    # Fake it for dumpbin and say T for any non-static function
+    # and D for any global variable.
+    # Also find C++ and __fastcall symbols from MSVC++,
+    # which start with @ or ?.
+    lt_cv_sys_global_symbol_pipe="$AWK '"\
+"     {last_section=section; section=\$ 3};"\
+"     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     \$ 0!~/External *\|/{next};"\
+"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+"     {if(hide[section]) next};"\
+"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+"     ' prfx=^$ac_symprfx"
+  else
+    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[	 ]\($symcode$symcode*\)[	 ][	 ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+  fi
+  lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5
+  (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+	mv -f "$nlist"T "$nlist"
+      else
+	rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+	  cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data.  */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+	  # Now generate the symbol file.
+	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+	  cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols.  */
+LT_DLSYM_CONST struct {
+  const char *name;
+  void       *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[] =
+{
+  { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+	  cat <<\_LT_EOF >> conftest.$ac_ext
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+	  # Now try linking the two files.
+	  mv conftest.$ac_objext conftstm.$ac_objext
+	  lt_globsym_save_LIBS=$LIBS
+	  lt_globsym_save_CFLAGS=$CFLAGS
+	  LIBS="conftstm.$ac_objext"
+	  CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext}; then
+	    pipe_works=yes
+	  fi
+	  LIBS=$lt_globsym_save_LIBS
+	  CFLAGS=$lt_globsym_save_CFLAGS
+	else
+	  echo "cannot find nm_test_func in $nlist" >&5
+	fi
+      else
+	echo "cannot find nm_test_var in $nlist" >&5
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+    fi
+  else
+    echo "$progname: failed program was:" >&5
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then
+  nm_file_list_spec='@'
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
+$as_echo_n "checking for sysroot... " >&6; }
+
+# Check whether --with-sysroot was given.
+if test "${with_sysroot+set}" = set; then :
+  withval=$with_sysroot;
+else
+  with_sysroot=no
+fi
+
+
+lt_sysroot=
+case ${with_sysroot} in #(
+ yes)
+   if test "$GCC" = yes; then
+     lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+   fi
+   ;; #(
+ /*)
+   lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+   ;; #(
+ no|'')
+   ;; #(
+ *)
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5
+$as_echo "${with_sysroot}" >&6; }
+   as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5
+   ;;
+esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5
+$as_echo "${lt_sysroot:-no}" >&6; }
+
+
+
+
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then :
+  enableval=$enable_libtool_lock;
+fi
+
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.$ac_objext` in
+      *ELF-32*)
+	HPUX_IA64_MODE="32"
+	;;
+      *ELF-64*)
+	HPUX_IA64_MODE="64"
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    if test "$lt_cv_prog_gnu_ld" = yes; then
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -melf32bsmip"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -melf32bmipn32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -melf64bmip"
+	;;
+      esac
+    else
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -32"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -n32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -64"
+	  ;;
+      esac
+    fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.o` in
+      *32-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_i386_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_i386"
+	    ;;
+	  ppc64-*linux*|powerpc64-*linux*)
+	    LD="${LD-ld} -m elf32ppclinux"
+	    ;;
+	  s390x-*linux*)
+	    LD="${LD-ld} -m elf_s390"
+	    ;;
+	  sparc64-*linux*)
+	    LD="${LD-ld} -m elf32_sparc"
+	    ;;
+	esac
+	;;
+      *64-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_x86_64_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_x86_64"
+	    ;;
+	  ppc*-*linux*|powerpc*-*linux*)
+	    LD="${LD-ld} -m elf64ppc"
+	    ;;
+	  s390*-*linux*|s390*-*tpf*)
+	    LD="${LD-ld} -m elf64_s390"
+	    ;;
+	  sparc*-*linux*)
+	    LD="${LD-ld} -m elf64_sparc"
+	    ;;
+	esac
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
+$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
+if ${lt_cv_cc_needs_belf+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_cc_needs_belf=yes
+else
+  lt_cv_cc_needs_belf=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+     ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
+$as_echo "$lt_cv_cc_needs_belf" >&6; }
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+*-*solaris*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*)
+        case $host in
+        i?86-*-solaris*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        sparc*-*-solaris*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+        esac
+        # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
+        if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+          LD="${LD-ld}_sol2"
+        fi
+        ;;
+      *)
+	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+	  LD="${LD-ld} -64"
+	fi
+	;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
+need_locks="$enable_libtool_lock"
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args.
+set dummy ${ac_tool_prefix}mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_MANIFEST_TOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$MANIFEST_TOOL"; then
+  ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL
+if test -n "$MANIFEST_TOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5
+$as_echo "$MANIFEST_TOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_MANIFEST_TOOL"; then
+  ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL
+  # Extract the first word of "mt", so it can be a program name with args.
+set dummy mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_MANIFEST_TOOL"; then
+  ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_MANIFEST_TOOL="mt"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL
+if test -n "$ac_ct_MANIFEST_TOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5
+$as_echo "$ac_ct_MANIFEST_TOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_MANIFEST_TOOL" = x; then
+    MANIFEST_TOOL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL
+  fi
+else
+  MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL"
+fi
+
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5
+$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; }
+if ${lt_cv_path_mainfest_tool+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_path_mainfest_tool=no
+  echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5
+  $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+  cat conftest.err >&5
+  if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+    lt_cv_path_mainfest_tool=yes
+  fi
+  rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
+$as_echo "$lt_cv_path_mainfest_tool" >&6; }
+if test "x$lt_cv_path_mainfest_tool" != xyes; then
+  MANIFEST_TOOL=:
+fi
+
+
+
+
+
+
+  case $host_os in
+    rhapsody* | darwin*)
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DSYMUTIL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DSYMUTIL"; then
+  ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DSYMUTIL=$ac_cv_prog_DSYMUTIL
+if test -n "$DSYMUTIL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
+$as_echo "$DSYMUTIL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DSYMUTIL"; then
+  ac_ct_DSYMUTIL=$DSYMUTIL
+  # Extract the first word of "dsymutil", so it can be a program name with args.
+set dummy dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DSYMUTIL"; then
+  ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
+if test -n "$ac_ct_DSYMUTIL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
+$as_echo "$ac_ct_DSYMUTIL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DSYMUTIL" = x; then
+    DSYMUTIL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DSYMUTIL=$ac_ct_DSYMUTIL
+  fi
+else
+  DSYMUTIL="$ac_cv_prog_DSYMUTIL"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_NMEDIT+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NMEDIT"; then
+  ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+NMEDIT=$ac_cv_prog_NMEDIT
+if test -n "$NMEDIT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
+$as_echo "$NMEDIT" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_NMEDIT"; then
+  ac_ct_NMEDIT=$NMEDIT
+  # Extract the first word of "nmedit", so it can be a program name with args.
+set dummy nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_NMEDIT"; then
+  ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_NMEDIT="nmedit"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
+if test -n "$ac_ct_NMEDIT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
+$as_echo "$ac_ct_NMEDIT" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_NMEDIT" = x; then
+    NMEDIT=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    NMEDIT=$ac_ct_NMEDIT
+  fi
+else
+  NMEDIT="$ac_cv_prog_NMEDIT"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_LIPO+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$LIPO"; then
+  ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+LIPO=$ac_cv_prog_LIPO
+if test -n "$LIPO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
+$as_echo "$LIPO" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LIPO"; then
+  ac_ct_LIPO=$LIPO
+  # Extract the first word of "lipo", so it can be a program name with args.
+set dummy lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_LIPO+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_LIPO"; then
+  ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_LIPO="lipo"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
+if test -n "$ac_ct_LIPO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
+$as_echo "$ac_ct_LIPO" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_LIPO" = x; then
+    LIPO=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    LIPO=$ac_ct_LIPO
+  fi
+else
+  LIPO="$ac_cv_prog_LIPO"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OTOOL"; then
+  ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL=$ac_cv_prog_OTOOL
+if test -n "$OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL"; then
+  ac_ct_OTOOL=$OTOOL
+  # Extract the first word of "otool", so it can be a program name with args.
+set dummy otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OTOOL"; then
+  ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OTOOL="otool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
+if test -n "$ac_ct_OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
+$as_echo "$ac_ct_OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OTOOL" = x; then
+    OTOOL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL=$ac_ct_OTOOL
+  fi
+else
+  OTOOL="$ac_cv_prog_OTOOL"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL64+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OTOOL64"; then
+  ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL64=$ac_cv_prog_OTOOL64
+if test -n "$OTOOL64"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
+$as_echo "$OTOOL64" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL64"; then
+  ac_ct_OTOOL64=$OTOOL64
+  # Extract the first word of "otool64", so it can be a program name with args.
+set dummy otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OTOOL64"; then
+  ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OTOOL64="otool64"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
+if test -n "$ac_ct_OTOOL64"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
+$as_echo "$ac_ct_OTOOL64" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OTOOL64" = x; then
+    OTOOL64=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL64=$ac_ct_OTOOL64
+  fi
+else
+  OTOOL64="$ac_cv_prog_OTOOL64"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
+$as_echo_n "checking for -single_module linker flag... " >&6; }
+if ${lt_cv_apple_cc_single_mod+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_apple_cc_single_mod=no
+      if test -z "${LT_MULTI_MODULE}"; then
+	# By default we will add the -single_module flag. You can override
+	# by either setting the environment variable LT_MULTI_MODULE
+	# non-empty at configure time, or by adding -multi_module to the
+	# link flags.
+	rm -rf libconftest.dylib*
+	echo "int foo(void){return 1;}" > conftest.c
+	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&5
+	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+	# If there is a non-empty error log, and "single_module"
+	# appears in it, assume the flag caused a linker warning
+        if test -s conftest.err && $GREP single_module conftest.err; then
+	  cat conftest.err >&5
+	# Otherwise, if the output was created with a 0 exit code from
+	# the compiler, it worked.
+	elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+	  lt_cv_apple_cc_single_mod=yes
+	else
+	  cat conftest.err >&5
+	fi
+	rm -rf libconftest.dylib*
+	rm -f conftest.*
+      fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
+$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
+$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
+if ${lt_cv_ld_exported_symbols_list+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_ld_exported_symbols_list=yes
+else
+  lt_cv_ld_exported_symbols_list=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+	LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
+$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+$as_echo_n "checking for -force_load linker flag... " >&6; }
+if ${lt_cv_ld_force_load+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
+      echo "$AR cru libconftest.a conftest.o" >&5
+      $AR cru libconftest.a conftest.o 2>&5
+      echo "$RANLIB libconftest.a" >&5
+      $RANLIB libconftest.a 2>&5
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -s conftest.err && $GREP force_load conftest.err; then
+	cat conftest.err >&5
+      elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+	lt_cv_ld_force_load=yes
+      else
+	cat conftest.err >&5
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+$as_echo "$lt_cv_ld_force_load" >&6; }
+    case $host_os in
+    rhapsody* | darwin1.[012])
+      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+	10.0,*86*-darwin8*|10.0,*-darwin[91]*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+	10.[012]*)
+	  _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+	10.*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    fi
+    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+
+for ac_header in dlfcn.h
+do :
+  ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
+"
+if test "x$ac_cv_header_dlfcn_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+# Set options
+
+
+
+        enable_dlopen=no
+
+
+
+            # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+  enableval=$enable_shared; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_shared=yes
+fi
+
+
+
+
+
+
+
+
+
+  # Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+  enableval=$enable_static; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_static=yes
+fi
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-pic was given.
+if test "${with_pic+set}" = set; then :
+  withval=$with_pic; lt_p=${PACKAGE-default}
+    case $withval in
+    yes|no) pic_mode=$withval ;;
+    *)
+      pic_mode=default
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for lt_pkg in $withval; do
+	IFS="$lt_save_ifs"
+	if test "X$lt_pkg" = "X$lt_p"; then
+	  pic_mode=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  pic_mode=default
+fi
+
+
+test -z "$pic_mode" && pic_mode=default
+
+
+
+
+
+
+
+  # Check whether --enable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then :
+  enableval=$enable_fast_install; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_fast_install=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_fast_install=yes
+fi
+
+
+
+
+
+
+
+
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test -z "$LN_S" && LN_S="ln -s"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
+$as_echo_n "checking for objdir... " >&6; }
+if ${lt_cv_objdir+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
+$as_echo "$lt_cv_objdir" >&6; }
+objdir=$lt_cv_objdir
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define LT_OBJDIR "$lt_cv_objdir/"
+_ACEOF
+
+
+
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+for cc_temp in $compiler""; do
+  case $cc_temp in
+    compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+    distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
+$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/${ac_tool_prefix}file; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
+$as_echo_n "checking for file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/file; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/file"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  else
+    MAGIC_CMD=:
+  fi
+fi
+
+  fi
+  ;;
+esac
+
+# Use C for the default configuration in the libtool script
+
+lt_save_CC="$CC"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+  case $cc_basename in
+  nvcc*)
+    lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
+  *)
+    lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
+  esac
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_rtti_exceptions=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="-fno-rtti -fno-exceptions"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_rtti_exceptions=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+    lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+    :
+fi
+
+fi
+
+
+
+
+
+
+  lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+
+  if test "$GCC" = yes; then
+    lt_prog_compiler_wl='-Wl,'
+    lt_prog_compiler_static='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            lt_prog_compiler_pic='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic='-fno-common'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      lt_prog_compiler_static=
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic='-fPIC'
+	;;
+      esac
+      ;;
+
+    interix[3-9]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      lt_prog_compiler_can_build_shared=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	lt_prog_compiler_pic=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      lt_prog_compiler_pic='-fPIC'
+      ;;
+    esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      lt_prog_compiler_wl='-Xlinker '
+      if test -n "$lt_prog_compiler_pic"; then
+        lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic"
+      fi
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      lt_prog_compiler_wl='-Wl,'
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static='-Bstatic'
+      else
+	lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      lt_prog_compiler_static='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC (with -KPIC) is the default.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu | kopensolaris*-gnu)
+      case $cc_basename in
+      # old Intel for x86_64 which still supported -KPIC.
+      ecc*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-KPIC'
+	lt_prog_compiler_static='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fPIC'
+	lt_prog_compiler_static='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='--shared'
+	lt_prog_compiler_static='--static'
+	;;
+      nagfor*)
+	# NAG Fortran compiler
+	lt_prog_compiler_wl='-Wl,-Wl,,'
+	lt_prog_compiler_pic='-PIC'
+	lt_prog_compiler_static='-Bstatic'
+	;;
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+	# which looks to be a dead project)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fpic'
+	lt_prog_compiler_static='-Bstatic'
+        ;;
+      ccc*)
+        lt_prog_compiler_wl='-Wl,'
+        # All Alpha code is PIC.
+        lt_prog_compiler_static='-non_shared'
+        ;;
+      xl* | bgxl* | bgf* | mpixl*)
+	# IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-qpic'
+	lt_prog_compiler_static='-qstaticlink'
+	;;
+      *)
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*)
+	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl=''
+	  ;;
+	*Sun\ F* | *Sun*Fortran*)
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl='-Qoption ld '
+	  ;;
+	*Sun\ C*)
+	  # Sun C 5.9
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl='-Wl,'
+	  ;;
+        *Intel*\ [CF]*Compiler*)
+	  lt_prog_compiler_wl='-Wl,'
+	  lt_prog_compiler_pic='-fPIC'
+	  lt_prog_compiler_static='-static'
+	  ;;
+	*Portland\ Group*)
+	  lt_prog_compiler_wl='-Wl,'
+	  lt_prog_compiler_pic='-fpic'
+	  lt_prog_compiler_static='-Bstatic'
+	  ;;
+	esac
+	;;
+      esac
+      ;;
+
+    newsos6)
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      lt_prog_compiler_wl='-Wl,'
+      # All OSF/1 code is PIC.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    rdos*)
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    solaris*)
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+	lt_prog_compiler_wl='-Qoption ld ';;
+      *)
+	lt_prog_compiler_wl='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      lt_prog_compiler_wl='-Qoption ld '
+      lt_prog_compiler_pic='-PIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+	lt_prog_compiler_pic='-Kconform_pic'
+	lt_prog_compiler_static='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    unicos*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_can_build_shared=no
+      ;;
+
+    uts4*)
+      lt_prog_compiler_pic='-pic'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    *)
+      lt_prog_compiler_can_build_shared=no
+      ;;
+    esac
+  fi
+
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    lt_prog_compiler_pic=
+    ;;
+  *)
+    lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+    ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+if ${lt_cv_prog_compiler_pic+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic=$lt_prog_compiler_pic
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5
+$as_echo "$lt_cv_prog_compiler_pic" >&6; }
+lt_prog_compiler_pic=$lt_cv_prog_compiler_pic
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
+if ${lt_cv_prog_compiler_pic_works+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic_works=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_pic_works=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works" = xyes; then
+    case $lt_prog_compiler_pic in
+     "" | " "*) ;;
+     *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+     esac
+else
+    lt_prog_compiler_pic=
+     lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if ${lt_cv_prog_compiler_static_works+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_static_works=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler_static_works=yes
+       fi
+     else
+       lt_cv_prog_compiler_static_works=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
+$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works" = xyes; then
+    :
+else
+    lt_prog_compiler_static=
+fi
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+  if test "$hard_links" = no; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+  runpath_var=
+  allow_undefined_flag=
+  always_export_symbols=no
+  archive_cmds=
+  archive_expsym_cmds=
+  compiler_needs_object=no
+  enable_shared_with_static_runtimes=no
+  export_dynamic_flag_spec=
+  export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  hardcode_automatic=no
+  hardcode_direct=no
+  hardcode_direct_absolute=no
+  hardcode_libdir_flag_spec=
+  hardcode_libdir_separator=
+  hardcode_minus_L=no
+  hardcode_shlibpath_var=unsupported
+  inherit_rpath=no
+  link_all_deplibs=unknown
+  module_cmds=
+  module_expsym_cmds=
+  old_archive_from_new_cmds=
+  old_archive_from_expsyms_cmds=
+  thread_safe_flag_spec=
+  whole_archive_flag_spec=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  include_expsyms=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  ld_shlibs=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test "$with_gnu_ld" = yes; then
+    case $host_os in
+      aix*)
+	# The AIX port of GNU ld has always aspired to compatibility
+	# with the native linker.  However, as the warning in the GNU ld
+	# block says, versions before 2.19.5* couldn't really create working
+	# shared libraries, regardless of the interface used.
+	case `$LD -v 2>&1` in
+	  *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+	  *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+	  *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+	  *)
+	    lt_use_gnu_ld_interface=yes
+	    ;;
+	esac
+	;;
+      *)
+	lt_use_gnu_ld_interface=yes
+	;;
+    esac
+  fi
+
+  if test "$lt_use_gnu_ld_interface" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+    export_dynamic_flag_spec='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      whole_archive_flag_spec=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[3-9]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_expsym_cmds=''
+        ;;
+      m68k)
+            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_minus_L=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	allow_undefined_flag=unsupported
+	# Joseph Beckenbach  says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+      # as there is no search path for DLLs.
+      hardcode_libdir_flag_spec='-L$libdir'
+      export_dynamic_flag_spec='${wl}--export-all-symbols'
+      allow_undefined_flag=unsupported
+      always_export_symbols=no
+      enable_shared_with_static_runtimes=yes
+      export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+      exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file (1st line
+	# is EXPORTS), use it as is; otherwise, prepend...
+	archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	  cp $export_symbols $output_objdir/$soname.def;
+	else
+	  echo EXPORTS > $output_objdir/$soname.def;
+	  cat $export_symbols >> $output_objdir/$soname.def;
+	fi~
+	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    haiku*)
+      archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      link_all_deplibs=yes
+      ;;
+
+    interix[3-9]*)
+      hardcode_direct=no
+      hardcode_shlibpath_var=no
+      hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+      export_dynamic_flag_spec='${wl}-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+      tmp_diet=no
+      if test "$host_os" = linux-dietlibc; then
+	case $cc_basename in
+	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
+	esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+	 && test "$tmp_diet" = no
+      then
+	tmp_addflag=' $pic_flag'
+	tmp_sharedflag='-shared'
+	case $cc_basename,$host_cpu in
+        pgcc*)				# Portland Group C compiler
+	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag'
+	  ;;
+	pgf77* | pgf90* | pgf95* | pgfortran*)
+					# Portland Group f77 and f90 compilers
+	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag -Mnomain' ;;
+	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
+	  tmp_addflag=' -i_dynamic' ;;
+	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+	ifc* | ifort*)			# Intel Fortran compiler
+	  tmp_addflag=' -nofor_main' ;;
+	lf95*)				# Lahey Fortran 8.1
+	  whole_archive_flag_spec=
+	  tmp_sharedflag='--shared' ;;
+	xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+	  tmp_sharedflag='-qmkshrobj'
+	  tmp_addflag= ;;
+	nvcc*)	# Cuda Compiler Driver 2.2
+	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  compiler_needs_object=yes
+	  ;;
+	esac
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)			# Sun C 5.9
+	  whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  compiler_needs_object=yes
+	  tmp_sharedflag='-G' ;;
+	*Sun\ F*)			# Sun Fortran 8.3
+	  tmp_sharedflag='-G' ;;
+	esac
+	archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+        if test "x$supports_anon_versioning" = xyes; then
+          archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+	    cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	    echo "local: *; };" >> $output_objdir/$libname.ver~
+	    $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+        fi
+
+	case $cc_basename in
+	xlf* | bgf* | bgxlf* | mpixlf*)
+	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+	  whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
+	  hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+	  archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+	  if test "x$supports_anon_versioning" = xyes; then
+	    archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+	      cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	      echo "local: *; };" >> $output_objdir/$libname.ver~
+	      $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+	  fi
+	  ;;
+	esac
+      else
+        ld_shlibs=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+	;;
+	*)
+	  # For security reasons, it is highly recommended that you always
+	  # use absolute paths for naming shared libraries, and exclude the
+	  # DT_RUNPATH tag from executables and libraries.  But doing so
+	  # requires that you compile everything twice, which is a pain.
+	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+	    archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	  else
+	    ld_shlibs=no
+	  fi
+	;;
+      esac
+      ;;
+
+    sunos4*)
+      archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+    esac
+
+    if test "$ld_shlibs" = no; then
+      runpath_var=
+      hardcode_libdir_flag_spec=
+      export_dynamic_flag_spec=
+      whole_archive_flag_spec=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      allow_undefined_flag=unsupported
+      always_export_symbols=yes
+      archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      hardcode_minus_L=yes
+      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	hardcode_direct=unsupported
+      fi
+      ;;
+
+    aix[4-9]*)
+      if test "$host_cpu" = ia64; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=""
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+	# Also, AIX nm treats weak defined symbols like other global
+	# defined symbols, whereas GNU nm marks them as "W".
+	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	else
+	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# need to do runtime linking.
+	case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+	  for ld_flag in $LDFLAGS; do
+	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+	    aix_use_runtimelinking=yes
+	    break
+	  fi
+	  done
+	  ;;
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      archive_cmds=''
+      hardcode_direct=yes
+      hardcode_direct_absolute=yes
+      hardcode_libdir_separator=':'
+      link_all_deplibs=yes
+      file_list_spec='${wl}-f,'
+
+      if test "$GCC" = yes; then
+	case $host_os in aix4.[012]|aix4.[012].*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	  # We have reworked collect2
+	  :
+	  else
+	  # We have old collect2
+	  hardcode_direct=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  hardcode_minus_L=yes
+	  hardcode_libdir_flag_spec='-L$libdir'
+	  hardcode_libdir_separator=
+	  fi
+	  ;;
+	esac
+	shared_flag='-shared'
+	if test "$aix_use_runtimelinking" = yes; then
+	  shared_flag="$shared_flag "'${wl}-G'
+	fi
+      else
+	# not using gcc
+	if test "$host_cpu" = ia64; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag='${wl}-G'
+	  else
+	    shared_flag='${wl}-bM:SRE'
+	  fi
+	fi
+      fi
+
+      export_dynamic_flag_spec='${wl}-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      always_export_symbols=yes
+      if test "$aix_use_runtimelinking" = yes; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	allow_undefined_flag='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_="/usr/lib:/lib"
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath_
+fi
+
+        hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+        archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+      else
+	if test "$host_cpu" = ia64; then
+	  hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+	  allow_undefined_flag="-z nodefs"
+	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an
+	 # empty executable.
+	 if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_="/usr/lib:/lib"
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath_
+fi
+
+	 hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  no_undefined_flag=' ${wl}-bernotok'
+	  allow_undefined_flag=' ${wl}-berok'
+	  if test "$with_gnu_ld" = yes; then
+	    # We only use this code for GNU lds that support --whole-archive.
+	    whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	  else
+	    # Exported symbols can be pulled into shared objects from archives
+	    whole_archive_flag_spec='$convenience'
+	  fi
+	  archive_cmds_need_lc=yes
+	  # This is similar to how AIX traditionally builds its shared libraries.
+	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_expsym_cmds=''
+        ;;
+      m68k)
+            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_minus_L=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[45]*)
+      export_dynamic_flag_spec=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      case $cc_basename in
+      cl*)
+	# Native MSVC
+	hardcode_libdir_flag_spec=' '
+	allow_undefined_flag=unsupported
+	always_export_symbols=yes
+	file_list_spec='@'
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=".dll"
+	# FIXME: Setting linknames here is a bad hack.
+	archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+	archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	    sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+	  else
+	    sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+	  fi~
+	  $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+	  linknames='
+	# The linker will not automatically build a static lib if we build a DLL.
+	# _LT_TAGVAR(old_archive_from_new_cmds, )='true'
+	enable_shared_with_static_runtimes=yes
+	exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+	export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+	# Don't use ranlib
+	old_postinstall_cmds='chmod 644 $oldlib'
+	postlink_cmds='lt_outputfile="@OUTPUT@"~
+	  lt_tool_outputfile="@TOOL_OUTPUT@"~
+	  case $lt_outputfile in
+	    *.exe|*.EXE) ;;
+	    *)
+	      lt_outputfile="$lt_outputfile.exe"
+	      lt_tool_outputfile="$lt_tool_outputfile.exe"
+	      ;;
+	  esac~
+	  if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+	    $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+	    $RM "$lt_outputfile.manifest";
+	  fi'
+	;;
+      *)
+	# Assume MSVC wrapper
+	hardcode_libdir_flag_spec=' '
+	allow_undefined_flag=unsupported
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=".dll"
+	# FIXME: Setting linknames here is a bad hack.
+	archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+	# The linker will automatically build a .lib file if we build a DLL.
+	old_archive_from_new_cmds='true'
+	# FIXME: Should let the user specify the lib program.
+	old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+	enable_shared_with_static_runtimes=yes
+	;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+
+
+  archive_cmds_need_lc=no
+  hardcode_direct=no
+  hardcode_automatic=yes
+  hardcode_shlibpath_var=unsupported
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    whole_archive_flag_spec='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+
+  else
+    whole_archive_flag_spec=''
+  fi
+  link_all_deplibs=yes
+  allow_undefined_flag="$_lt_dar_allow_undefined"
+  case $cc_basename in
+     ifort*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test "$_lt_dar_can_shared" = "yes"; then
+    output_verbose_link_cmd=func_echo_all
+    archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+    module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+    archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+    module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+
+  else
+  ld_shlibs=no
+  fi
+
+      ;;
+
+    dgux*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2.*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+	archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+	archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+      hardcode_libdir_separator=:
+      hardcode_direct=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      hardcode_minus_L=yes
+      export_dynamic_flag_spec='${wl}-E'
+      ;;
+
+    hpux10*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test "$with_gnu_ld" = no; then
+	hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+	hardcode_libdir_separator=:
+	hardcode_direct=yes
+	hardcode_direct_absolute=yes
+	export_dynamic_flag_spec='${wl}-E'
+	# hardcode_minus_L: Not really in the search PATH,
+	# but as the default location of the library.
+	hardcode_minus_L=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	case $host_cpu in
+	hppa*64*)
+	  archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case $host_cpu in
+	hppa*64*)
+	  archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+
+	  # Older versions of the 11.00 compiler do not understand -b yet
+	  # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
+$as_echo_n "checking if $CC understands -b... " >&6; }
+if ${lt_cv_prog_compiler__b+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler__b=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS -b"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler__b=yes
+       fi
+     else
+       lt_cv_prog_compiler__b=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
+$as_echo "$lt_cv_prog_compiler__b" >&6; }
+
+if test x"$lt_cv_prog_compiler__b" = xyes; then
+    archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+else
+    archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+fi
+
+	  ;;
+	esac
+      fi
+      if test "$with_gnu_ld" = no; then
+	hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+	hardcode_libdir_separator=:
+
+	case $host_cpu in
+	hppa*64*|ia64*)
+	  hardcode_direct=no
+	  hardcode_shlibpath_var=no
+	  ;;
+	*)
+	  hardcode_direct=yes
+	  hardcode_direct_absolute=yes
+	  export_dynamic_flag_spec='${wl}-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  hardcode_minus_L=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	# Try to use the -exported_symbol ld option, if it does not
+	# work, assume that -exports_file does not work either and
+	# implicitly export all symbols.
+	# This should be the same for all languages, so no per-tag cache variable.
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5
+$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; }
+if ${lt_cv_irix_exported_symbol+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  save_LDFLAGS="$LDFLAGS"
+	   LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+	   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int foo (void) { return 0; }
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_irix_exported_symbol=yes
+else
+  lt_cv_irix_exported_symbol=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+           LDFLAGS="$save_LDFLAGS"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
+$as_echo "$lt_cv_irix_exported_symbol" >&6; }
+	if test "$lt_cv_irix_exported_symbol" = yes; then
+          archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+	fi
+      else
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      inherit_rpath=yes
+      link_all_deplibs=yes
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    newsos6)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      hardcode_shlibpath_var=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+	hardcode_direct=yes
+	hardcode_shlibpath_var=no
+	hardcode_direct_absolute=yes
+	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	  archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+	  hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+	  export_dynamic_flag_spec='${wl}-E'
+	else
+	  case $host_os in
+	   openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+	     archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+	     hardcode_libdir_flag_spec='-R$libdir'
+	     ;;
+	   *)
+	     archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	     hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+	     ;;
+	  esac
+	fi
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    os2*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      allow_undefined_flag=unsupported
+      archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+	allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	allow_undefined_flag=' -expect_unresolved \*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+	allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      else
+	allow_undefined_flag=' -expect_unresolved \*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+	$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	hardcode_libdir_flag_spec='-rpath $libdir'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_separator=:
+      ;;
+
+    solaris*)
+      no_undefined_flag=' -z defs'
+      if test "$GCC" = yes; then
+	wlarc='${wl}'
+	archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+	case `$CC -V 2>&1` in
+	*"Compilers 5.0"*)
+	  wlarc=''
+	  archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+	  ;;
+	*)
+	  wlarc='${wl}'
+	  archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+	  ;;
+	esac
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_shlibpath_var=no
+      case $host_os in
+      solaris2.[0-5] | solaris2.[0-5].*) ;;
+      *)
+	# The compiler driver will combine and reorder linker options,
+	# but understands `-z linker_flag'.  GCC discards it without `$wl',
+	# but is careful enough not to reorder.
+	# Supported since Solaris 2.6 (maybe 2.5.1?)
+	if test "$GCC" = yes; then
+	  whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+	else
+	  whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+	fi
+	;;
+      esac
+      link_all_deplibs=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  reload_cmds='$CC -r -o $output$reload_objs'
+	  hardcode_direct=no
+        ;;
+	motorola)
+	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4.3*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_shlibpath_var=no
+      export_dynamic_flag_spec='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	hardcode_shlibpath_var=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	ld_shlibs=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+      no_undefined_flag='${wl}-z,text'
+      archive_cmds_need_lc=no
+      hardcode_shlibpath_var=no
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We can NOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      no_undefined_flag='${wl}-z,text'
+      allow_undefined_flag='${wl}-z,nodefs'
+      archive_cmds_need_lc=no
+      hardcode_shlibpath_var=no
+      hardcode_libdir_flag_spec='${wl}-R,$libdir'
+      hardcode_libdir_separator=':'
+      link_all_deplibs=yes
+      export_dynamic_flag_spec='${wl}-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    *)
+      ld_shlibs=no
+      ;;
+    esac
+
+    if test x$host_vendor = xsni; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+	export_dynamic_flag_spec='${wl}-Blargedynsym'
+	;;
+      esac
+    fi
+  fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
+$as_echo "$ld_shlibs" >&6; }
+test "$ld_shlibs" = no && can_build_shared=no
+
+with_gnu_ld=$with_gnu_ld
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+  # Assume -lc should be added
+  archive_cmds_need_lc=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $archive_cmds in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if ${lt_cv_archive_cmds_need_lc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  $RM conftest*
+	echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+	if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } 2>conftest.err; then
+	  soname=conftest
+	  lib=conftest
+	  libobjs=conftest.$ac_objext
+	  deplibs=
+	  wl=$lt_prog_compiler_wl
+	  pic_flag=$lt_prog_compiler_pic
+	  compiler_flags=-v
+	  linker_flags=-v
+	  verstring=
+	  output_objdir=.
+	  libname=conftest
+	  lt_save_allow_undefined_flag=$allow_undefined_flag
+	  allow_undefined_flag=
+	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+  (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+	  then
+	    lt_cv_archive_cmds_need_lc=no
+	  else
+	    lt_cv_archive_cmds_need_lc=yes
+	  fi
+	  allow_undefined_flag=$lt_save_allow_undefined_flag
+	else
+	  cat conftest.err 1>&5
+	fi
+	$RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
+      archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+if test "$GCC" = yes; then
+  case $host_os in
+    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+    *) lt_awk_arg="/^libraries:/" ;;
+  esac
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;;
+    *) lt_sed_strip_eq="s,=/,/,g" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary.
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+    else
+      test -d "$lt_sys_path" && \
+	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+  lt_foo="";
+  lt_count=0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo="/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[lt_foo]++; }
+  if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's,/\([A-Za-z]:\),\1,g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix[4-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[01] | aix4.[01].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib.so
+      # instead of lib.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[45]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$cc_basename in
+  yes,*)
+    # gcc
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    dynamic_linker='Win32 ld.exe'
+    ;;
+
+  *,cl*)
+    # Native MSVC
+    libname_spec='$name'
+    soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+    library_names_spec='${libname}.dll.lib'
+
+    case $build_os in
+    mingw*)
+      sys_lib_search_path_spec=
+      lt_save_ifs=$IFS
+      IFS=';'
+      for lt_path in $LIB
+      do
+        IFS=$lt_save_ifs
+        # Let DOS variable expansion print the short 8.3 style file name.
+        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+      done
+      IFS=$lt_save_ifs
+      # Convert to MSYS style.
+      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
+      ;;
+    cygwin*)
+      # Convert to unix form, then to dos form, then back to unix form
+      # but this time dos style (no spaces!) so that the unix form looks
+      # like /cygdrive/c/PROGRA~1:/cygdr...
+      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      ;;
+    *)
+      sys_lib_search_path_spec="$LIB"
+      if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+        # It is most probably a Windows format PATH.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      # FIXME: find the short name or the path components, as spaces are
+      # common. (e.g. "Program Files" -> "PROGRA~1")
+      ;;
+    esac
+
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+    dynamic_linker='Win32 link.exe'
+    ;;
+
+  *)
+    # Assume MSVC wrapper
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    dynamic_linker='Win32 ld.exe'
+    ;;
+  esac
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[23].*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2.*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[01]* | freebsdelf3.[01]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+  freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+haiku*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[3-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux # correct to gnu/linux during the next big refactor
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+	 LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  if  ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+  lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+
+fi
+
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
+    *)				need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[89] | openbsd2.[89].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux # correct to gnu/linux during the next big refactor
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" ||
+   test -n "$runpath_var" ||
+   test "X$hardcode_automatic" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$hardcode_direct" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no &&
+     test "$hardcode_minus_L" != no; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
+$as_echo "$hardcode_action" >&6; }
+
+if test "$hardcode_action" = relink ||
+   test "$inherit_rpath" = yes; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+
+
+
+
+
+
+  if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32* | cegcc*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+    ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+    ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dl_dlopen=yes
+else
+  ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+
+fi
+
+    ;;
+
+  *)
+    ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
+if test "x$ac_cv_func_shl_load" = xyes; then :
+  lt_cv_dlopen="shl_load"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
+$as_echo_n "checking for shl_load in -ldld... " >&6; }
+if ${ac_cv_lib_dld_shl_load+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dld_shl_load=yes
+else
+  ac_cv_lib_dld_shl_load=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
+$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
+if test "x$ac_cv_lib_dld_shl_load" = xyes; then :
+  lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
+else
+  ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dl_dlopen=yes
+else
+  ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
+$as_echo_n "checking for dlopen in -lsvld... " >&6; }
+if ${ac_cv_lib_svld_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_svld_dlopen=yes
+else
+  ac_cv_lib_svld_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
+$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
+if test "x$ac_cv_lib_svld_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
+$as_echo_n "checking for dld_link in -ldld... " >&6; }
+if ${ac_cv_lib_dld_dld_link+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link ();
+int
+main ()
+{
+return dld_link ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dld_dld_link=yes
+else
+  ac_cv_lib_dld_dld_link=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
+$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
+if test "x$ac_cv_lib_dld_dld_link" = xyes; then :
+  lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
+$as_echo_n "checking whether a program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  	  if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include 
+#endif
+
+#include 
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}
+_LT_EOF
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&5 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
+$as_echo "$lt_cv_dlopen_self" >&6; }
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
+$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self_static+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  	  if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self_static=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include 
+#endif
+
+#include 
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}
+_LT_EOF
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&5 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self_static=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
+$as_echo "$lt_cv_dlopen_self_static" >&6; }
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+striplib=
+old_striplib=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
+$as_echo_n "checking whether stripping libraries is possible... " >&6; }
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP" ; then
+      striplib="$STRIP -x"
+      old_striplib="$STRIP -S"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    fi
+    ;;
+  *)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    ;;
+  esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+  # Report which library types will actually be built
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
+$as_echo_n "checking if libtool supports shared libraries... " >&6; }
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
+$as_echo "$can_build_shared" >&6; }
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+  test "$can_build_shared" = "no" && enable_shared=no
+
+  # On AIX, shared libraries and static libraries use the same namespace, and
+  # are all built from PIC.
+  case $host_os in
+  aix3*)
+    test "$enable_shared" = yes && enable_static=no
+    if test -n "$RANLIB"; then
+      archive_cmds="$archive_cmds~\$RANLIB \$lib"
+      postinstall_cmds='$RANLIB $lib'
+    fi
+    ;;
+
+  aix[4-9]*)
+    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+      test "$enable_shared" = yes && enable_static=no
+    fi
+    ;;
+  esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
+$as_echo "$enable_shared" >&6; }
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+  # Make sure either enable_shared or enable_static is yes.
+  test "$enable_shared" = yes || enable_static=yes
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
+$as_echo "$enable_static" >&6; }
+
+
+
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+
+# Select memory manager depending on user input.
+# If no "-enable-maxmem", use jmemnobs
+MEMORYMGR='jmemnobs'
+MAXMEM="no"
+# Check whether --enable-maxmem was given.
+if test "${enable_maxmem+set}" = set; then :
+  enableval=$enable_maxmem; MAXMEM="$enableval"
+fi
+
+if test "x$MAXMEM" = xyes; then
+  MAXMEM=1
+fi
+if test "x$MAXMEM" != xno; then
+  if test -n "`echo $MAXMEM | sed 's/[0-9]//g'`"; then
+    as_fn_error $? "non-numeric argument to --enable-maxmem" "$LINENO" 5
+  fi
+  DEFAULTMAXMEM=`expr $MAXMEM \* 1048576`
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_MAX_MEM ${DEFAULTMAXMEM}
+_ACEOF
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 'tmpfile()'" >&5
+$as_echo_n "checking for 'tmpfile()'... " >&6; }
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include 
+int
+main ()
+{
+ FILE * tfile = tmpfile();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+    MEMORYMGR='jmemansi'
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+        MEMORYMGR='jmemname'
+
+    # Test for the need to remove temporary files using a signal handler
+    # (for cjpeg/djpeg)
+
+$as_echo "#define NEED_SIGNAL_CATCHER 1" >>confdefs.h
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 'mktemp()'" >&5
+$as_echo_n "checking for 'mktemp()'... " >&6; }
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+ char fname[80]; mktemp(fname);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+$as_echo "#define NO_MKTEMP 1" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+
+
+# Extract the library version IDs from jpeglib.h.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking libjpeg version number" >&5
+$as_echo_n "checking libjpeg version number... " >&6; }
+major=`sed -ne 's/^#define JPEG_LIB_VERSION_MAJOR *\([0-9][0-9]*\).*$/\1/p' $srcdir/jpeglib.h`
+minor=`sed -ne 's/^#define JPEG_LIB_VERSION_MINOR *\([0-9][0-9]*\).*$/\1/p' $srcdir/jpeglib.h`
+JPEG_LIB_VERSION=`expr $major + $minor`:0:$minor
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $JPEG_LIB_VERSION" >&5
+$as_echo "$JPEG_LIB_VERSION" >&6; }
+
+ac_config_files="$ac_config_files Makefile"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    if test "x$cache_file" != "x/dev/null"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+      if test ! -f "$cache_file" || test -h "$cache_file"; then
+	cat confcache >"$cache_file"
+      else
+        case $cache_file in #(
+        */* | ?:*)
+	  mv -f confcache "$cache_file"$$ &&
+	  mv -f "$cache_file"$$ "$cache_file" ;; #(
+        *)
+	  mv -f confcache "$cache_file" ;;
+	esac
+      fi
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
+$as_echo_n "checking that generated files are newer than configure... " >&6; }
+   if test -n "$am_sleep_pid"; then
+     # Hide warnings about reused PIDs.
+     wait $am_sleep_pid 2>/dev/null
+   fi
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
+$as_echo "done" >&6; }
+ if test -n "$EXEEXT"; then
+  am__EXEEXT_TRUE=
+  am__EXEEXT_FALSE='#'
+else
+  am__EXEEXT_TRUE='#'
+  am__EXEEXT_FALSE=
+fi
+
+if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
+  as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+  as_fn_error $? "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+  as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_LD_VERSION_SCRIPT_TRUE}" && test -z "${HAVE_LD_VERSION_SCRIPT_FALSE}"; then
+  as_fn_error $? "conditional \"HAVE_LD_VERSION_SCRIPT\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by libjpeg $as_me 9.1.0, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+      --header=FILE[:TEMPLATE]
+                   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+libjpeg config.status 9.1.0
+configured by $0, generated by GNU Autoconf 2.69,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+AS='`$ECHO "$AS" | $SED "$delay_single_quote_subst"`'
+DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
+enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
+ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
+PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`'
+host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
+host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
+host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
+build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
+build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
+build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
+SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
+Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
+GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
+EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
+FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
+LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
+NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
+LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
+exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
+file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`'
+want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`'
+sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`'
+AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
+archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`'
+STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
+lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
+CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
+compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
+GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`'
+lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`'
+objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
+need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
+MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
+LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
+libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
+postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
+need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
+version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
+install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
+sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
+striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in AS \
+DLLTOOL \
+OBJDUMP \
+SHELL \
+ECHO \
+PATH_SEPARATOR \
+SED \
+GREP \
+EGREP \
+FGREP \
+LD \
+NM \
+LN_S \
+lt_SP2NL \
+lt_NL2SP \
+reload_flag \
+deplibs_check_method \
+file_magic_cmd \
+file_magic_glob \
+want_nocaseglob \
+sharedlib_from_linklib_cmd \
+AR \
+AR_FLAGS \
+archiver_list_spec \
+STRIP \
+RANLIB \
+CC \
+CFLAGS \
+compiler \
+lt_cv_sys_global_symbol_pipe \
+lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_c_name_address \
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+nm_file_list_spec \
+lt_prog_compiler_no_builtin_flag \
+lt_prog_compiler_pic \
+lt_prog_compiler_wl \
+lt_prog_compiler_static \
+lt_cv_prog_compiler_c_o \
+need_locks \
+MANIFEST_TOOL \
+DSYMUTIL \
+NMEDIT \
+LIPO \
+OTOOL \
+OTOOL64 \
+shrext_cmds \
+export_dynamic_flag_spec \
+whole_archive_flag_spec \
+compiler_needs_object \
+with_gnu_ld \
+allow_undefined_flag \
+no_undefined_flag \
+hardcode_libdir_flag_spec \
+hardcode_libdir_separator \
+exclude_expsyms \
+include_expsyms \
+file_list_spec \
+variables_saved_for_relink \
+libname_spec \
+library_names_spec \
+soname_spec \
+install_override_mode \
+finish_eval \
+old_striplib \
+striplib; do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds \
+old_postinstall_cmds \
+old_postuninstall_cmds \
+old_archive_cmds \
+extract_expsyms_cmds \
+old_archive_from_new_cmds \
+old_archive_from_expsyms_cmds \
+archive_cmds \
+archive_expsym_cmds \
+module_cmds \
+module_expsym_cmds \
+export_symbols_cmds \
+prelink_cmds \
+postlink_cmds \
+postinstall_cmds \
+postuninstall_cmds \
+finish_cmds \
+sys_lib_search_path_spec \
+sys_lib_dlsearch_path_spec; do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+ac_aux_dir='$ac_aux_dir'
+xsi_shell='$xsi_shell'
+lt_shell_append='$lt_shell_append'
+
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+
+    PACKAGE='$PACKAGE'
+    VERSION='$VERSION'
+    TIMESTAMP='$TIMESTAMP'
+    RM='$RM'
+    ofile='$ofile'
+
+
+
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "jconfig.h") CONFIG_HEADERS="$CONFIG_HEADERS jconfig.h:jconfig.cfg" ;;
+    "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+    "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' >$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = ""
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{
+h
+s///
+s/^/:/
+s/[	 ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[	 ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+  ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_tt"; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any.  Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[	 ]*#[	 ]*define[	 ][	 ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' >$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  for (key in D) D_is_set[key] = 1
+  FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+  line = \$ 0
+  split(line, arg, " ")
+  if (arg[1] == "#") {
+    defundef = arg[2]
+    mac1 = arg[3]
+  } else {
+    defundef = substr(arg[1], 2)
+    mac1 = arg[2]
+  }
+  split(mac1, mac2, "(") #)
+  macro = mac2[1]
+  prefix = substr(line, 1, index(line, defundef) - 1)
+  if (D_is_set[macro]) {
+    # Preserve the white space surrounding the "#".
+    print prefix "define", macro P[macro] D[macro]
+    next
+  } else {
+    # Replace #undef with comments.  This is necessary, for example,
+    # in the case of _POSIX_SOURCE, which is predefined and required
+    # on some systems where configure will not decide to define it.
+    if (defundef == "undef") {
+      print "/*", prefix defundef, macro, "*/"
+      next
+    }
+  }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+  as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$ac_tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+	`' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+  ac_MKDIR_P=$MKDIR_P
+  case $MKDIR_P in
+  [\\/$]* | ?:[\\/]* ) ;;
+  */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+    } >"$ac_tmp/config.h" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$ac_tmp/config.h" "$ac_file" \
+	|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+      || as_fn_error $? "could not create -" "$LINENO" 5
+  fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$_am_arg" : 'X\(//\)[^/]' \| \
+	 X"$_am_arg" : 'X\(//\)$' \| \
+	 X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+  :C)  { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+  esac
+
+
+  case $ac_file$ac_mode in
+    "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+  # Older Autoconf quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named 'Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$mf" : 'X\(//\)[^/]' \| \
+	 X"$mf" : 'X\(//\)$' \| \
+	 X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running 'make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "$am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+	 sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$file" : 'X\(//\)[^/]' \| \
+	 X"$file" : 'X\(//\)$' \| \
+	 X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      as_dir=$dirpart/$fdir; as_fn_mkdir_p
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+ ;;
+    "libtool":C)
+
+    # See if we are running on zsh, and set the options which allow our
+    # commands through without removal of \ escapes.
+    if test -n "${ZSH_VERSION+set}" ; then
+      setopt NO_GLOB_SUBST
+    fi
+
+    cfgfile="${ofile}T"
+    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+    $RM "$cfgfile"
+
+    cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+#                 Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+#   This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags=""
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Assembler program.
+AS=$lt_AS
+
+# DLL creation program.
+DLLTOOL=$lt_DLLTOOL
+
+# Object dumper program.
+OBJDUMP=$lt_OBJDUMP
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that protects backslashes.
+ECHO=$lt_ECHO
+
+# The PATH separator for the build system.
+PATH_SEPARATOR=$lt_PATH_SEPARATOR
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# convert \$build file names to \$host format.
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+
+# convert \$build files to toolchain format.
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method = "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# How to find potential files when deplibs_check_method = "file_magic".
+file_magic_glob=$lt_file_magic_glob
+
+# Find potential files using nocaseglob when deplibs_check_method = "file_magic".
+want_nocaseglob=$lt_want_nocaseglob
+
+# Command to associate shared and link libraries.
+sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd
+
+# The archiver.
+AR=$lt_AR
+
+# Flags to create an archive.
+AR_FLAGS=$lt_AR_FLAGS
+
+# How to feed a file listing to the archiver.
+archiver_list_spec=$lt_archiver_list_spec
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Whether to use a lock for old archive extraction.
+lock_old_archive_extraction=$lock_old_archive_extraction
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# Transform the output of nm in a C name address pair when lib prefix is needed.
+global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+
+# Specify filename containing input files for \$NM.
+nm_file_list_spec=$lt_nm_file_list_spec
+
+# The root where to search for dependent libraries,and in which our libraries should be installed.
+lt_sysroot=$lt_sysroot
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Manifest tool.
+MANIFEST_TOOL=$lt_MANIFEST_TOOL
+
+# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
+DSYMUTIL=$lt_DSYMUTIL
+
+# Tool to change global to local symbols on Mac OS X.
+NMEDIT=$lt_NMEDIT
+
+# Tool to manipulate fat objects and archives on Mac OS X.
+LIPO=$lt_LIPO
+
+# ldd/readelf like tool for Mach-O binaries on Mac OS X.
+OTOOL=$lt_OTOOL
+
+# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
+OTOOL64=$lt_OTOOL64
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Permission mode override for installation of shared libraries.
+install_override_mode=$lt_install_override_mode
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Commands necessary for finishing linking programs.
+postlink_cmds=$lt_postlink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+  case $host_os in
+  aix3*)
+    cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+_LT_EOF
+    ;;
+  esac
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" \
+     || (rm -f "$cfgfile"; exit 1)
+
+  if test x"$xsi_shell" = xyes; then
+  sed -e '/^func_dirname ()$/,/^} # func_dirname /c\
+func_dirname ()\
+{\
+\    case ${1} in\
+\      */*) func_dirname_result="${1%/*}${2}" ;;\
+\      *  ) func_dirname_result="${3}" ;;\
+\    esac\
+} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_basename ()$/,/^} # func_basename /c\
+func_basename ()\
+{\
+\    func_basename_result="${1##*/}"\
+} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\
+func_dirname_and_basename ()\
+{\
+\    case ${1} in\
+\      */*) func_dirname_result="${1%/*}${2}" ;;\
+\      *  ) func_dirname_result="${3}" ;;\
+\    esac\
+\    func_basename_result="${1##*/}"\
+} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_stripname ()$/,/^} # func_stripname /c\
+func_stripname ()\
+{\
+\    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\
+\    # positional parameters, so assign one to ordinary parameter first.\
+\    func_stripname_result=${3}\
+\    func_stripname_result=${func_stripname_result#"${1}"}\
+\    func_stripname_result=${func_stripname_result%"${2}"}\
+} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\
+func_split_long_opt ()\
+{\
+\    func_split_long_opt_name=${1%%=*}\
+\    func_split_long_opt_arg=${1#*=}\
+} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\
+func_split_short_opt ()\
+{\
+\    func_split_short_opt_arg=${1#??}\
+\    func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\
+} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\
+func_lo2o ()\
+{\
+\    case ${1} in\
+\      *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\
+\      *)    func_lo2o_result=${1} ;;\
+\    esac\
+} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_xform ()$/,/^} # func_xform /c\
+func_xform ()\
+{\
+    func_xform_result=${1%.*}.lo\
+} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_arith ()$/,/^} # func_arith /c\
+func_arith ()\
+{\
+    func_arith_result=$(( $* ))\
+} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_len ()$/,/^} # func_len /c\
+func_len ()\
+{\
+    func_len_result=${#1}\
+} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+fi
+
+if test x"$lt_shell_append" = xyes; then
+  sed -e '/^func_append ()$/,/^} # func_append /c\
+func_append ()\
+{\
+    eval "${1}+=\\${2}"\
+} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\
+func_append_quoted ()\
+{\
+\    func_quote_for_eval "${2}"\
+\    eval "${1}+=\\\\ \\$func_quote_for_eval_result"\
+} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  # Save a `func_append' function call where possible by direct use of '+='
+  sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+else
+  # Save a `func_append' function call even when '+=' is not available
+  sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+fi
+
+if test x"$_lt_function_replace_fail" = x":"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5
+$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;}
+fi
+
+
+   mv -f "$cfgfile" "$ofile" ||
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+
+ ;;
+
+  esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/source/Irrlicht/jpeglib/configure.ac b/source/Irrlicht/jpeglib/configure.ac
new file mode 100644
index 00000000..934d07e9
--- /dev/null
+++ b/source/Irrlicht/jpeglib/configure.ac
@@ -0,0 +1,365 @@
+# IJG auto-configuration source file.
+# Process this file with autoconf to produce a configure script.
+
+#
+# Configure script for IJG libjpeg
+#
+
+AC_INIT([libjpeg], [9.1.0])
+
+# Directory where autotools helper scripts lives.
+AC_CONFIG_AUX_DIR([.])
+
+# Generate configuration headers.
+AC_CONFIG_HEADERS([jconfig.h:jconfig.cfg])
+
+# Hack: disable autoheader so that it doesn't overwrite our cfg template.
+AUTOHEADER="echo autoheader ignored"
+
+# Check system type
+AC_CANONICAL_TARGET
+
+# Initialize Automake
+# Don't require all the GNU mandated files
+AM_INIT_AUTOMAKE([-Wall -Werror no-dist foreign])
+
+# Make --enable-silent-rules the default.
+# To get verbose build output you may configure
+# with --disable-silent-rules or use "make V=1".
+AM_SILENT_RULES([yes])
+
+# Add configure option --enable-maintainer-mode which enables
+# dependency checking and generation useful to package maintainers.
+# This is made an option to avoid confusing end users.
+AM_MAINTAINER_MODE
+
+# Check for programs
+AC_PROG_CC
+AC_PROG_CC_STDC
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+AC_PROG_LN_S
+AM_PROG_AR
+
+# Check if LD supports linker scripts,
+# and define automake conditional HAVE_LD_VERSION_SCRIPT if so.
+AC_ARG_ENABLE([ld-version-script],
+  AS_HELP_STRING([--enable-ld-version-script],
+    [enable linker version script (default is enabled when possible)]),
+    [have_ld_version_script=$enableval], [])
+if test -z "$have_ld_version_script"; then
+  AC_MSG_CHECKING([if LD -Wl,--version-script works])
+  save_LDFLAGS="$LDFLAGS"
+  LDFLAGS="$LDFLAGS -Wl,--version-script=conftest.map"
+  cat > conftest.map < rather than standard .])])
+
+# See whether type size_t is defined in any ANSI-standard places;
+# if not, perhaps it is defined in .
+AC_MSG_CHECKING([for size_t])
+AC_TRY_COMPILE([
+#ifdef HAVE_STDDEF_H
+#include 
+#endif
+#ifdef HAVE_STDLIB_H
+#include 
+#endif
+#include 
+#ifdef NEED_BSD_STRINGS
+#include 
+#else
+#include 
+#endif
+typedef size_t my_size_t;
+],
+      [ my_size_t foovar; ],
+      [ijg_size_t_ok=yes],
+      [ijg_size_t_ok="not ANSI, perhaps it is in sys/types.h"])
+AC_MSG_RESULT([$ijg_size_t_ok])
+if test "$ijg_size_t_ok" != yes; then
+  AC_CHECK_HEADER([sys/types.h],
+     [AC_DEFINE([NEED_SYS_TYPES_H], [1],
+                [Need to include  in order to obtain size_t.])
+      AC_EGREP_CPP([size_t], [#include ],
+                   [ijg_size_t_ok="size_t is in sys/types.h"],
+                   [ijg_size_t_ok=no])],
+     [ijg_size_t_ok=no])
+  AC_MSG_RESULT([$ijg_size_t_ok])
+  if test "$ijg_size_t_ok" = no; then
+    AC_MSG_WARN([Type size_t is not defined in any of the usual places.
+      Try putting '"typedef unsigned int size_t;"' in jconfig.h.])
+  fi
+fi
+
+# Check compiler characteristics
+AC_MSG_CHECKING([for type unsigned char])
+AC_TRY_COMPILE([], [ unsigned char un_char; ],
+ [AC_MSG_RESULT(yes)
+  AC_DEFINE([HAVE_UNSIGNED_CHAR], [1],
+            [Compiler supports 'unsigned char'.])],
+ [AC_MSG_RESULT(no)])
+
+AC_MSG_CHECKING([for type unsigned short])
+AC_TRY_COMPILE([], [ unsigned short un_short; ],
+  [AC_MSG_RESULT(yes)
+   AC_DEFINE([HAVE_UNSIGNED_SHORT], [1],
+             [Compiler supports 'unsigned short'.])],
+  [AC_MSG_RESULT(no)])
+
+AC_MSG_CHECKING([for type void])
+AC_TRY_COMPILE([
+/* Caution: a C++ compiler will insist on valid prototypes */
+typedef void * void_ptr;	/* check void * */
+#ifdef HAVE_PROTOTYPES		/* check ptr to function returning void */
+typedef void (*void_func) (int a, int b);
+#else
+typedef void (*void_func) ();
+#endif
+
+#ifdef HAVE_PROTOTYPES		/* check void function result */
+void test3function (void_ptr arg1, void_func arg2)
+#else
+void test3function (arg1, arg2)
+     void_ptr arg1;
+     void_func arg2;
+#endif
+{
+  char * locptr = (char *) arg1; /* check casting to and from void * */
+  arg1 = (void *) locptr;
+  (*arg2) (1, 2);		/* check call of fcn returning void */
+}
+], [ ],
+        [AC_MSG_RESULT(yes)],
+        [AC_MSG_RESULT(no)
+         AC_DEFINE([void], [char],
+                   [Define 'void' as 'char' for archaic compilers
+                    that don't understand it.])])
+AC_C_CONST
+
+# Check for non-broken inline under various spellings
+AC_MSG_CHECKING([for inline])
+ijg_cv_inline=""
+AC_TRY_COMPILE([], [} __inline__ int foo() { return 0; }
+int bar() { return foo();], ijg_cv_inline="__inline__",
+[AC_TRY_COMPILE(, [} __inline int foo() { return 0; }
+int bar() { return foo();], ijg_cv_inline="__inline",
+[AC_TRY_COMPILE(, [} inline int foo() { return 0; }
+int bar() { return foo();], ijg_cv_inline="inline")])])
+AC_MSG_RESULT($ijg_cv_inline)
+AC_DEFINE_UNQUOTED([INLINE], [$ijg_cv_inline],
+                   [How to obtain function inlining.])
+
+# We cannot check for bogus warnings, but at least we can check for errors
+AC_MSG_CHECKING([for broken incomplete types])
+AC_TRY_COMPILE([ typedef struct undefined_structure * undef_struct_ptr; ],
+               [],
+               [AC_MSG_RESULT(ok)],
+               [AC_MSG_RESULT(broken)
+                AC_DEFINE([INCOMPLETE_TYPES_BROKEN], [1],
+                          [Compiler does not support pointers to unspecified
+                           structures.])])
+
+# Test whether global names are unique to at least 15 chars
+AC_MSG_CHECKING([for short external names])
+AC_TRY_LINK([
+int possibly_duplicate_function () { return 0; }
+int possibly_dupli_function () { return 1; }
+], [],
+            [AC_MSG_RESULT(ok)],
+            [AC_MSG_RESULT(short)
+             AC_DEFINE([NEED_SHORT_EXTERNAL_NAMES], [1],
+                       [Linker requires that global names be unique in
+                        first 15 characters.])])
+
+# Run-time checks
+AC_MSG_CHECKING([to see if char is signed])
+AC_TRY_RUN([
+#ifdef HAVE_STDLIB_H
+#include 
+#endif
+#include 
+#ifdef HAVE_PROTOTYPES
+int is_char_signed (int arg)
+#else
+int is_char_signed (arg)
+     int arg;
+#endif
+{
+  if (arg == 189) {		/* expected result for unsigned char */
+    return 0;			/* type char is unsigned */
+  }
+  else if (arg != -67) {	/* expected result for signed char */
+    printf("Hmm, it seems 'char' is not eight bits wide on your machine.\n");
+    printf("I fear the JPEG software will not work at all.\n\n");
+  }
+  return 1;			/* assume char is signed otherwise */
+}
+char signed_char_check = (char) (-67);
+int main() {
+  exit(is_char_signed((int) signed_char_check));
+}], [AC_MSG_RESULT(no)
+     AC_DEFINE([CHAR_IS_UNSIGNED], [1],
+               [Characters are unsigned])],
+               [AC_MSG_RESULT(yes)],
+[AC_MSG_WARN([Assuming that char is signed on target machine.
+    If it is unsigned, this will be a little bit inefficient.])
+])
+
+AC_MSG_CHECKING([to see if right shift is signed])
+AC_TRY_RUN([
+#ifdef HAVE_STDLIB_H
+#include 
+#endif
+#include 
+#ifdef HAVE_PROTOTYPES
+int is_shifting_signed (long arg)
+#else
+int is_shifting_signed (arg)
+     long arg;
+#endif
+/* See whether right-shift on a long is signed or not. */
+{
+  long res = arg >> 4;
+
+  if (res == -0x7F7E80CL) {	/* expected result for signed shift */
+    return 1;			/* right shift is signed */
+  }
+  /* see if unsigned-shift hack will fix it. */
+  /* we can't just test exact value since it depends on width of long... */
+  res |= (~0L) << (32-4);
+  if (res == -0x7F7E80CL) {	/* expected result now? */
+    return 0;			/* right shift is unsigned */
+  }
+  printf("Right shift isn't acting as I expect it to.\n");
+  printf("I fear the JPEG software will not work at all.\n\n");
+  return 0;			/* try it with unsigned anyway */
+}
+int main() {
+  exit(is_shifting_signed(-0x7F7E80B1L));
+}],
+      [AC_MSG_RESULT(no)
+       AC_DEFINE([RIGHT_SHIFT_IS_UNSIGNED], [1],
+                 [Broken compiler shifts signed values as an unsigned shift.])],
+       [AC_MSG_RESULT(yes)],
+       [AC_MSG_RESULT(Assuming that right shift is signed on target machine.)])
+
+AC_MSG_CHECKING([to see if fopen accepts b spec])
+AC_TRY_RUN([
+#ifdef HAVE_STDLIB_H
+#include 
+#endif
+#include 
+int main() {
+  if (fopen("conftestdata", "wb") != NULL)
+    exit(0);
+  exit(1);
+}],
+          [AC_MSG_RESULT(yes)],
+          [AC_MSG_RESULT(no)
+           AC_DEFINE([DONT_USE_B_MODE], [1],
+                     [Don't open files in binary mode.])],
+          [AC_MSG_RESULT(Assuming that it does.)])
+
+# Configure libtool
+AC_LIBTOOL_WIN32_DLL
+AC_PROG_LIBTOOL
+
+# Select memory manager depending on user input.
+# If no "-enable-maxmem", use jmemnobs
+MEMORYMGR='jmemnobs'
+MAXMEM="no"
+AC_ARG_ENABLE([maxmem],
+[  --enable-maxmem[=N]     enable use of temp files, set max mem usage to N MB],
+[MAXMEM="$enableval"])
+dnl [# support --with-maxmem for backwards compatibility with IJG V5.]
+dnl AC_ARG_WITH(maxmem, , MAXMEM="$withval")
+if test "x$MAXMEM" = xyes; then
+  MAXMEM=1
+fi
+if test "x$MAXMEM" != xno; then
+  if test -n "`echo $MAXMEM | sed 's/[[0-9]]//g'`"; then
+    AC_MSG_ERROR(non-numeric argument to --enable-maxmem)
+  fi
+  DEFAULTMAXMEM=`expr $MAXMEM \* 1048576`
+  AC_DEFINE_UNQUOTED([DEFAULT_MAX_MEM], [${DEFAULTMAXMEM}],
+                     [Maximum data space library will allocate.])
+  AC_MSG_CHECKING([for 'tmpfile()'])
+  AC_TRY_LINK([#include ], [ FILE * tfile = tmpfile(); ],
+    [AC_MSG_RESULT(yes)
+    MEMORYMGR='jmemansi'],
+    [AC_MSG_RESULT(no)
+    dnl if tmpfile is not present, must use jmemname.
+    MEMORYMGR='jmemname'
+
+    # Test for the need to remove temporary files using a signal handler
+    # (for cjpeg/djpeg)
+    AC_DEFINE([NEED_SIGNAL_CATCHER], [1],
+              [Need signal handler to clean up temporary files.])
+    AC_MSG_CHECKING([for 'mktemp()'])
+    AC_TRY_LINK([], [ char fname[80]; mktemp(fname); ],
+                [AC_MSG_RESULT(yes)],
+                [AC_MSG_RESULT(no)
+                 AC_DEFINE([NO_MKTEMP], [1],
+                           [The mktemp() function is not available.])])])
+fi
+AC_SUBST([MEMORYMGR])
+
+# Extract the library version IDs from jpeglib.h.
+AC_MSG_CHECKING([libjpeg version number])
+[major=`sed -ne 's/^#define JPEG_LIB_VERSION_MAJOR *\([0-9][0-9]*\).*$/\1/p' $srcdir/jpeglib.h`
+minor=`sed -ne 's/^#define JPEG_LIB_VERSION_MINOR *\([0-9][0-9]*\).*$/\1/p' $srcdir/jpeglib.h`]
+AC_SUBST([JPEG_LIB_VERSION],
+         [`expr $major + $minor`:0:$minor])
+AC_MSG_RESULT([$JPEG_LIB_VERSION])
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
diff --git a/source/Irrlicht/jpeglib/depcomp b/source/Irrlicht/jpeglib/depcomp
new file mode 100644
index 00000000..4ebd5b3a
--- /dev/null
+++ b/source/Irrlicht/jpeglib/depcomp
@@ -0,0 +1,791 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2013-05-30.07; # UTC
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see .
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva .
+
+case $1 in
+  '')
+    echo "$0: No command.  Try '$0 --help' for more information." 1>&2
+    exit 1;
+    ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+  depmode     Dependency tracking mode.
+  source      Source file read by 'PROGRAMS ARGS'.
+  object      Object file output by 'PROGRAMS ARGS'.
+  DEPDIR      directory where to store dependencies.
+  depfile     Dependency file to output.
+  tmpdepfile  Temporary file to use when outputting dependencies.
+  libtool     Whether libtool is used (yes/no).
+
+Report bugs to .
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "depcomp $scriptversion"
+    exit $?
+    ;;
+esac
+
+# Get the directory component of the given path, and save it in the
+# global variables '$dir'.  Note that this directory component will
+# be either empty or ending with a '/' character.  This is deliberate.
+set_dir_from ()
+{
+  case $1 in
+    */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
+      *) dir=;;
+  esac
+}
+
+# Get the suffix-stripped basename of the given path, and save it the
+# global variable '$base'.
+set_base_from ()
+{
+  base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
+}
+
+# If no dependency file was actually created by the compiler invocation,
+# we still have to create a dummy depfile, to avoid errors with the
+# Makefile "include basename.Plo" scheme.
+make_dummy_depfile ()
+{
+  echo "#dummy" > "$depfile"
+}
+
+# Factor out some common post-processing of the generated depfile.
+# Requires the auxiliary global variable '$tmpdepfile' to be set.
+aix_post_process_depfile ()
+{
+  # If the compiler actually managed to produce a dependency file,
+  # post-process it.
+  if test -f "$tmpdepfile"; then
+    # Each line is of the form 'foo.o: dependency.h'.
+    # Do two passes, one to just change these to
+    #   $object: dependency.h
+    # and one to simply output
+    #   dependency.h:
+    # which is needed to avoid the deleted-header problem.
+    { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
+      sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
+    } > "$depfile"
+    rm -f "$tmpdepfile"
+  else
+    make_dummy_depfile
+  fi
+}
+
+# A tabulation character.
+tab='	'
+# A newline character.
+nl='
+'
+# Character ranges might be problematic outside the C locale.
+# These definitions help.
+upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
+lower=abcdefghijklmnopqrstuvwxyz
+digits=0123456789
+alpha=${upper}${lower}
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+  echo "depcomp: Variables source, object and depmode must be set" 1>&2
+  exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+  sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Avoid interferences from the environment.
+gccflag= dashmflag=
+
+# Some modes work just like other modes, but use different flags.  We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write.  Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+  # HP compiler uses -M and no extra arg.
+  gccflag=-M
+  depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+  # This is just like dashmstdout with a different argument.
+  dashmflag=-xM
+  depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+  # This is just like msvisualcpp but w/o cygpath translation.
+  # Just convert the backslash-escaped backslashes to single forward
+  # slashes to satisfy depend.m4
+  cygpath_u='sed s,\\\\,/,g'
+  depmode=msvisualcpp
+fi
+
+if test "$depmode" = msvc7msys; then
+  # This is just like msvc7 but w/o cygpath translation.
+  # Just convert the backslash-escaped backslashes to single forward
+  # slashes to satisfy depend.m4
+  cygpath_u='sed s,\\\\,/,g'
+  depmode=msvc7
+fi
+
+if test "$depmode" = xlc; then
+  # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
+  gccflag=-qmakedep=gcc,-MF
+  depmode=gcc
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want.  Yay!  Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff.  Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am.  Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+  for arg
+  do
+    case $arg in
+    -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+    *)  set fnord "$@" "$arg" ;;
+    esac
+    shift # fnord
+    shift # $arg
+  done
+  "$@"
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  mv "$tmpdepfile" "$depfile"
+  ;;
+
+gcc)
+## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
+## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
+## (see the conditional assignment to $gccflag above).
+## There are various ways to get dependency output from gcc.  Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+##   up in a subdir.  Having to rename by hand is ugly.
+##   (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+##   -MM, not -M (despite what the docs say).  Also, it might not be
+##   supported by the other compilers which use the 'gcc' depmode.
+## - Using -M directly means running the compiler twice (even worse
+##   than renaming).
+  if test -z "$gccflag"; then
+    gccflag=-MD,
+  fi
+  "$@" -Wp,"$gccflag$tmpdepfile"
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  # The second -e expression handles DOS-style file names with drive
+  # letters.
+  sed -e 's/^[^:]*: / /' \
+      -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the "deleted header file" problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header).  We avoid this by adding
+## dummy dependencies for each header file.  Too bad gcc doesn't do
+## this for us directly.
+## Some versions of gcc put a space before the ':'.  On the theory
+## that the space means something, we add a space to the output as
+## well.  hp depmode also adds that space, but also prefixes the VPATH
+## to the object.  Take care to not repeat it in the output.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+  tr ' ' "$nl" < "$tmpdepfile" \
+    | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+sgi)
+  if test "$libtool" = yes; then
+    "$@" "-Wp,-MDupdate,$tmpdepfile"
+  else
+    "$@" -MDupdate "$tmpdepfile"
+  fi
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+
+  if test -f "$tmpdepfile"; then  # yes, the sourcefile depend on other files
+    echo "$object : \\" > "$depfile"
+    # Clip off the initial element (the dependent).  Don't try to be
+    # clever and replace this with sed code, as IRIX sed won't handle
+    # lines with more than a fixed number of characters (4096 in
+    # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;
+    # the IRIX cc adds comments like '#:fec' to the end of the
+    # dependency line.
+    tr ' ' "$nl" < "$tmpdepfile" \
+      | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
+      | tr "$nl" ' ' >> "$depfile"
+    echo >> "$depfile"
+    # The second pass generates a dummy entry for each header file.
+    tr ' ' "$nl" < "$tmpdepfile" \
+      | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+      >> "$depfile"
+  else
+    make_dummy_depfile
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+xlc)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+aix)
+  # The C for AIX Compiler uses -M and outputs the dependencies
+  # in a .u file.  In older versions, this file always lives in the
+  # current directory.  Also, the AIX compiler puts '$object:' at the
+  # start of each line; $object doesn't have directory information.
+  # Version 6 uses the directory in both cases.
+  set_dir_from "$object"
+  set_base_from "$object"
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$base.u
+    tmpdepfile3=$dir.libs/$base.u
+    "$@" -Wc,-M
+  else
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$dir$base.u
+    tmpdepfile3=$dir$base.u
+    "$@" -M
+  fi
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+    exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  aix_post_process_depfile
+  ;;
+
+tcc)
+  # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
+  # FIXME: That version still under development at the moment of writing.
+  #        Make that this statement remains true also for stable, released
+  #        versions.
+  # It will wrap lines (doesn't matter whether long or short) with a
+  # trailing '\', as in:
+  #
+  #   foo.o : \
+  #    foo.c \
+  #    foo.h \
+  #
+  # It will put a trailing '\' even on the last line, and will use leading
+  # spaces rather than leading tabs (at least since its commit 0394caf7
+  # "Emit spaces for -MD").
+  "$@" -MD -MF "$tmpdepfile"
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
+  # We have to change lines of the first kind to '$object: \'.
+  sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
+  # And for each line of the second kind, we have to emit a 'dep.h:'
+  # dummy dependency, to avoid the deleted-header problem.
+  sed -n -e 's|^  *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+## The order of this option in the case statement is important, since the
+## shell code in configure will try each of these formats in the order
+## listed in this file.  A plain '-MD' option would be understood by many
+## compilers, so we must ensure this comes after the gcc and icc options.
+pgcc)
+  # Portland's C compiler understands '-MD'.
+  # Will always output deps to 'file.d' where file is the root name of the
+  # source file under compilation, even if file resides in a subdirectory.
+  # The object file name does not affect the name of the '.d' file.
+  # pgcc 10.2 will output
+  #    foo.o: sub/foo.c sub/foo.h
+  # and will wrap long lines using '\' :
+  #    foo.o: sub/foo.c ... \
+  #     sub/foo.h ... \
+  #     ...
+  set_dir_from "$object"
+  # Use the source, not the object, to determine the base name, since
+  # that's sadly what pgcc will do too.
+  set_base_from "$source"
+  tmpdepfile=$base.d
+
+  # For projects that build the same source file twice into different object
+  # files, the pgcc approach of using the *source* file root name can cause
+  # problems in parallel builds.  Use a locking strategy to avoid stomping on
+  # the same $tmpdepfile.
+  lockdir=$base.d-lock
+  trap "
+    echo '$0: caught signal, cleaning up...' >&2
+    rmdir '$lockdir'
+    exit 1
+  " 1 2 13 15
+  numtries=100
+  i=$numtries
+  while test $i -gt 0; do
+    # mkdir is a portable test-and-set.
+    if mkdir "$lockdir" 2>/dev/null; then
+      # This process acquired the lock.
+      "$@" -MD
+      stat=$?
+      # Release the lock.
+      rmdir "$lockdir"
+      break
+    else
+      # If the lock is being held by a different process, wait
+      # until the winning process is done or we timeout.
+      while test -d "$lockdir" && test $i -gt 0; do
+        sleep 1
+        i=`expr $i - 1`
+      done
+    fi
+    i=`expr $i - 1`
+  done
+  trap - 1 2 13 15
+  if test $i -le 0; then
+    echo "$0: failed to acquire lock after $numtries attempts" >&2
+    echo "$0: check lockdir '$lockdir'" >&2
+    exit 1
+  fi
+
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  # Each line is of the form `foo.o: dependent.h',
+  # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+  # Do two passes, one to just change these to
+  # `$object: dependent.h' and one to simply `dependent.h:'.
+  sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process this invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp2)
+  # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+  # compilers, which have integrated preprocessors.  The correct option
+  # to use with these is +Maked; it writes dependencies to a file named
+  # 'foo.d', which lands next to the object file, wherever that
+  # happens to be.
+  # Much of this is similar to the tru64 case; see comments there.
+  set_dir_from  "$object"
+  set_base_from "$object"
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir.libs/$base.d
+    "$@" -Wc,+Maked
+  else
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir$base.d
+    "$@" +Maked
+  fi
+  stat=$?
+  if test $stat -ne 0; then
+     rm -f "$tmpdepfile1" "$tmpdepfile2"
+     exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  if test -f "$tmpdepfile"; then
+    sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
+    # Add 'dependent.h:' lines.
+    sed -ne '2,${
+               s/^ *//
+               s/ \\*$//
+               s/$/:/
+               p
+             }' "$tmpdepfile" >> "$depfile"
+  else
+    make_dummy_depfile
+  fi
+  rm -f "$tmpdepfile" "$tmpdepfile2"
+  ;;
+
+tru64)
+  # The Tru64 compiler uses -MD to generate dependencies as a side
+  # effect.  'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
+  # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+  # dependencies in 'foo.d' instead, so we check for that too.
+  # Subdirectories are respected.
+  set_dir_from  "$object"
+  set_base_from "$object"
+
+  if test "$libtool" = yes; then
+    # Libtool generates 2 separate objects for the 2 libraries.  These
+    # two compilations output dependencies in $dir.libs/$base.o.d and
+    # in $dir$base.o.d.  We have to check for both files, because
+    # one of the two compilations can be disabled.  We should prefer
+    # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+    # automatically cleaned when .libs/ is deleted, while ignoring
+    # the former would cause a distcleancheck panic.
+    tmpdepfile1=$dir$base.o.d          # libtool 1.5
+    tmpdepfile2=$dir.libs/$base.o.d    # Likewise.
+    tmpdepfile3=$dir.libs/$base.d      # Compaq CCC V6.2-504
+    "$@" -Wc,-MD
+  else
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir$base.d
+    tmpdepfile3=$dir$base.d
+    "$@" -MD
+  fi
+
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+    exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  # Same post-processing that is required for AIX mode.
+  aix_post_process_depfile
+  ;;
+
+msvc7)
+  if test "$libtool" = yes; then
+    showIncludes=-Wc,-showIncludes
+  else
+    showIncludes=-showIncludes
+  fi
+  "$@" $showIncludes > "$tmpdepfile"
+  stat=$?
+  grep -v '^Note: including file: ' "$tmpdepfile"
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  # The first sed program below extracts the file names and escapes
+  # backslashes for cygpath.  The second sed program outputs the file
+  # name when reading, but also accumulates all include files in the
+  # hold buffer in order to output them again at the end.  This only
+  # works with sed implementations that can handle large buffers.
+  sed < "$tmpdepfile" -n '
+/^Note: including file:  *\(.*\)/ {
+  s//\1/
+  s/\\/\\\\/g
+  p
+}' | $cygpath_u | sort -u | sed -n '
+s/ /\\ /g
+s/\(.*\)/'"$tab"'\1 \\/p
+s/.\(.*\) \\/\1:/
+H
+$ {
+  s/.*/'"$tab"'/
+  G
+  p
+}' >> "$depfile"
+  echo >> "$depfile" # make sure the fragment doesn't end with a backslash
+  rm -f "$tmpdepfile"
+  ;;
+
+msvc7msys)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+#nosideeffect)
+  # This comment above is used by automake to tell side-effect
+  # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout, regardless of -o.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove '-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  test -z "$dashmflag" && dashmflag=-M
+  # Require at least two characters before searching for ':'
+  # in the target name.  This is to cope with DOS-style filenames:
+  # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
+  "$@" $dashmflag |
+    sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process this sed invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  tr ' ' "$nl" < "$tmpdepfile" \
+    | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+dashXmstdout)
+  # This case only exists to satisfy depend.m4.  It is never actually
+  # run, as this mode is specially recognized in the preamble.
+  exit 1
+  ;;
+
+makedepend)
+  "$@" || exit $?
+  # Remove any Libtool call
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+  # X makedepend
+  shift
+  cleared=no eat=no
+  for arg
+  do
+    case $cleared in
+    no)
+      set ""; shift
+      cleared=yes ;;
+    esac
+    if test $eat = yes; then
+      eat=no
+      continue
+    fi
+    case "$arg" in
+    -D*|-I*)
+      set fnord "$@" "$arg"; shift ;;
+    # Strip any option that makedepend may not understand.  Remove
+    # the object too, otherwise makedepend will parse it as a source file.
+    -arch)
+      eat=yes ;;
+    -*|$object)
+      ;;
+    *)
+      set fnord "$@" "$arg"; shift ;;
+    esac
+  done
+  obj_suffix=`echo "$object" | sed 's/^.*\././'`
+  touch "$tmpdepfile"
+  ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+  rm -f "$depfile"
+  # makedepend may prepend the VPATH from the source file name to the object.
+  # No need to regex-escape $object, excess matching of '.' is harmless.
+  sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process the last invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  sed '1,2d' "$tmpdepfile" \
+    | tr ' ' "$nl" \
+    | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile" "$tmpdepfile".bak
+  ;;
+
+cpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove '-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  "$@" -E \
+    | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+             -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+    | sed '$ s: \\$::' > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  cat < "$tmpdepfile" >> "$depfile"
+  sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvisualcpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  IFS=" "
+  for arg
+  do
+    case "$arg" in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+        set fnord "$@"
+        shift
+        shift
+        ;;
+    *)
+        set fnord "$@" "$arg"
+        shift
+        shift
+        ;;
+    esac
+  done
+  "$@" -E 2>/dev/null |
+  sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+  echo "$tab" >> "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvcmsys)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+none)
+  exec "$@"
+  ;;
+
+*)
+  echo "Unknown depmode $depmode" 1>&2
+  exit 1
+  ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/source/Irrlicht/jpeglib/djpeg.1 b/source/Irrlicht/jpeglib/djpeg.1
new file mode 100644
index 00000000..67ee5cba
--- /dev/null
+++ b/source/Irrlicht/jpeglib/djpeg.1
@@ -0,0 +1,252 @@
+.TH DJPEG 1 "23 November 2013"
+.SH NAME
+djpeg \- decompress a JPEG file to an image file
+.SH SYNOPSIS
+.B djpeg
+[
+.I options
+]
+[
+.I filename
+]
+.LP
+.SH DESCRIPTION
+.LP
+.B djpeg
+decompresses the named JPEG file, or the standard input if no file is named,
+and produces an image file on the standard output.  PBMPLUS (PPM/PGM), BMP,
+GIF, Targa, or RLE (Utah Raster Toolkit) output format can be selected.
+(RLE is supported only if the URT library is available.)
+.SH OPTIONS
+All switch names may be abbreviated; for example,
+.B \-grayscale
+may be written
+.B \-gray
+or
+.BR \-gr .
+Most of the "basic" switches can be abbreviated to as little as one letter.
+Upper and lower case are equivalent (thus
+.B \-BMP
+is the same as
+.BR \-bmp ).
+British spellings are also accepted (e.g.,
+.BR \-greyscale ),
+though for brevity these are not mentioned below.
+.PP
+The basic switches are:
+.TP
+.BI \-colors " N"
+Reduce image to at most N colors.  This reduces the number of colors used in
+the output image, so that it can be displayed on a colormapped display or
+stored in a colormapped file format.  For example, if you have an 8-bit
+display, you'd need to reduce to 256 or fewer colors.
+.TP
+.BI \-quantize " N"
+Same as
+.BR \-colors .
+.B \-colors
+is the recommended name,
+.B \-quantize
+is provided only for backwards compatibility.
+.TP
+.B \-fast
+Select recommended processing options for fast, low quality output.  (The
+default options are chosen for highest quality output.)  Currently, this is
+equivalent to \fB\-dct fast \-nosmooth \-onepass \-dither ordered\fR.
+.TP
+.B \-grayscale
+Force gray-scale output even if JPEG file is color.  Useful for viewing on
+monochrome displays; also,
+.B djpeg
+runs noticeably faster in this mode.
+.TP
+.BI \-scale " M/N"
+Scale the output image by a factor M/N.  Currently supported scale factors are
+M/N with all M from 1 to 16, where N is the source DCT size, which is 8 for
+baseline JPEG.  If the /N part is omitted, then M specifies the DCT scaled
+size to be applied on the given input.  For baseline JPEG this is equivalent
+to M/8 scaling, since the source DCT size for baseline JPEG is 8.
+Scaling is handy if the image is larger than your screen; also,
+.B djpeg
+runs much faster when scaling down the output.
+.TP
+.B \-bmp
+Select BMP output format (Windows flavor).  8-bit colormapped format is
+emitted if
+.B \-colors
+or
+.B \-grayscale
+is specified, or if the JPEG file is gray-scale; otherwise, 24-bit full-color
+format is emitted.
+.TP
+.B \-gif
+Select GIF output format.  Since GIF does not support more than 256 colors,
+.B \-colors 256
+is assumed (unless you specify a smaller number of colors).
+.TP
+.B \-os2
+Select BMP output format (OS/2 1.x flavor).  8-bit colormapped format is
+emitted if
+.B \-colors
+or
+.B \-grayscale
+is specified, or if the JPEG file is gray-scale; otherwise, 24-bit full-color
+format is emitted.
+.TP
+.B \-pnm
+Select PBMPLUS (PPM/PGM) output format (this is the default format).
+PGM is emitted if the JPEG file is gray-scale or if
+.B \-grayscale
+is specified; otherwise PPM is emitted.
+.TP
+.B \-rle
+Select RLE output format.  (Requires URT library.)
+.TP
+.B \-targa
+Select Targa output format.  Gray-scale format is emitted if the JPEG file is
+gray-scale or if
+.B \-grayscale
+is specified; otherwise, colormapped format is emitted if
+.B \-colors
+is specified; otherwise, 24-bit full-color format is emitted.
+.PP
+Switches for advanced users:
+.TP
+.B \-dct int
+Use integer DCT method (default).
+.TP
+.B \-dct fast
+Use fast integer DCT (less accurate).
+.TP
+.B \-dct float
+Use floating-point DCT method.
+The float method is very slightly more accurate than the int method, but is
+much slower unless your machine has very fast floating-point hardware.  Also
+note that results of the floating-point method may vary slightly across
+machines, while the integer methods should give the same results everywhere.
+The fast integer method is much less accurate than the other two.
+.TP
+.B \-dither fs
+Use Floyd-Steinberg dithering in color quantization.
+.TP
+.B \-dither ordered
+Use ordered dithering in color quantization.
+.TP
+.B \-dither none
+Do not use dithering in color quantization.
+By default, Floyd-Steinberg dithering is applied when quantizing colors; this
+is slow but usually produces the best results.  Ordered dither is a compromise
+between speed and quality; no dithering is fast but usually looks awful.  Note
+that these switches have no effect unless color quantization is being done.
+Ordered dither is only available in
+.B \-onepass
+mode.
+.TP
+.BI \-map " file"
+Quantize to the colors used in the specified image file.  This is useful for
+producing multiple files with identical color maps, or for forcing a
+predefined set of colors to be used.  The
+.I file
+must be a GIF or PPM file. This option overrides
+.B \-colors
+and
+.BR \-onepass .
+.TP
+.B \-nosmooth
+Don't use high-quality upsampling.
+.TP
+.B \-onepass
+Use one-pass instead of two-pass color quantization.  The one-pass method is
+faster and needs less memory, but it produces a lower-quality image.
+.B \-onepass
+is ignored unless you also say
+.B \-colors
+.IR N .
+Also, the one-pass method is always used for gray-scale output (the two-pass
+method is no improvement then).
+.TP
+.BI \-maxmemory " N"
+Set limit for amount of memory to use in processing large images.  Value is
+in thousands of bytes, or millions of bytes if "M" is attached to the
+number.  For example,
+.B \-max 4m
+selects 4000000 bytes.  If more space is needed, temporary files will be used.
+.TP
+.BI \-outfile " name"
+Send output image to the named file, not to standard output.
+.TP
+.B \-verbose
+Enable debug printout.  More
+.BR \-v 's
+give more output.  Also, version information is printed at startup.
+.TP
+.B \-debug
+Same as
+.BR \-verbose .
+.SH EXAMPLES
+.LP
+This example decompresses the JPEG file foo.jpg, quantizes it to
+256 colors, and saves the output in 8-bit BMP format in foo.bmp:
+.IP
+.B djpeg \-colors 256 \-bmp
+.I foo.jpg
+.B >
+.I foo.bmp
+.SH HINTS
+To get a quick preview of an image, use the
+.B \-grayscale
+and/or
+.B \-scale
+switches.
+.B \-grayscale \-scale 1/8
+is the fastest case.
+.PP
+Several options are available that trade off image quality to gain speed.
+.B \-fast
+turns on the recommended settings.
+.PP
+.B \-dct fast
+and/or
+.B \-nosmooth
+gain speed at a small sacrifice in quality.
+When producing a color-quantized image,
+.B \-onepass \-dither ordered
+is fast but much lower quality than the default behavior.
+.B \-dither none
+may give acceptable results in two-pass mode, but is seldom tolerable in
+one-pass mode.
+.PP
+If you are fortunate enough to have very fast floating point hardware,
+\fB\-dct float\fR may be even faster than \fB\-dct fast\fR.  But on most
+machines \fB\-dct float\fR is slower than \fB\-dct int\fR; in this case it is
+not worth using, because its theoretical accuracy advantage is too small to be
+significant in practice.
+.SH ENVIRONMENT
+.TP
+.B JPEGMEM
+If this environment variable is set, its value is the default memory limit.
+The value is specified as described for the
+.B \-maxmemory
+switch.
+.B JPEGMEM
+overrides the default value specified when the program was compiled, and
+itself is overridden by an explicit
+.BR \-maxmemory .
+.SH SEE ALSO
+.BR cjpeg (1),
+.BR jpegtran (1),
+.BR rdjpgcom (1),
+.BR wrjpgcom (1)
+.br
+.BR ppm (5),
+.BR pgm (5)
+.br
+Wallace, Gregory K.  "The JPEG Still Picture Compression Standard",
+Communications of the ACM, April 1991 (vol. 34, no. 4), pp. 30-44.
+.SH AUTHOR
+Independent JPEG Group
+.SH BUGS
+To avoid the Unisys LZW patent (now expired),
+.B djpeg
+produces uncompressed GIF files.  These are larger than they should be, but
+are readable by standard GIF decoders.
diff --git a/source/Irrlicht/jpeglib/djpeg.c b/source/Irrlicht/jpeglib/djpeg.c
new file mode 100644
index 00000000..77718cef
--- /dev/null
+++ b/source/Irrlicht/jpeglib/djpeg.c
@@ -0,0 +1,617 @@
+/*
+ * djpeg.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2009-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a command-line user interface for the JPEG decompressor.
+ * It should work on any system with Unix- or MS-DOS-style command lines.
+ *
+ * Two different command line styles are permitted, depending on the
+ * compile-time switch TWO_FILE_COMMANDLINE:
+ *	djpeg [options]  inputfile outputfile
+ *	djpeg [options]  [inputfile]
+ * In the second style, output is always to standard output, which you'd
+ * normally redirect to a file or pipe to some other program.  Input is
+ * either from a named file or from standard input (typically redirected).
+ * The second style is convenient on Unix but is unhelpful on systems that
+ * don't support pipes.  Also, you MUST use the first style if your system
+ * doesn't do binary I/O to stdin/stdout.
+ * To simplify script writing, the "-outfile" switch is provided.  The syntax
+ *	djpeg [options]  -outfile outputfile  inputfile
+ * works regardless of which command line style is used.
+ */
+
+#include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
+#include "jversion.h"		/* for version message */
+
+#include 		/* to declare isprint() */
+
+#ifdef USE_CCOMMAND		/* command-line reader for Macintosh */
+#ifdef __MWERKS__
+#include               /* Metrowerks needs this */
+#include 		/* ... and this */
+#endif
+#ifdef THINK_C
+#include 		/* Think declares it here */
+#endif
+#endif
+
+
+/* Create the add-on message string table. */
+
+#define JMESSAGE(code,string)	string ,
+
+static const char * const cdjpeg_message_table[] = {
+#include "cderror.h"
+  NULL
+};
+
+
+/*
+ * This list defines the known output image formats
+ * (not all of which need be supported by a given version).
+ * You can change the default output format by defining DEFAULT_FMT;
+ * indeed, you had better do so if you undefine PPM_SUPPORTED.
+ */
+
+typedef enum {
+	FMT_BMP,		/* BMP format (Windows flavor) */
+	FMT_GIF,		/* GIF format */
+	FMT_OS2,		/* BMP format (OS/2 flavor) */
+	FMT_PPM,		/* PPM/PGM (PBMPLUS formats) */
+	FMT_RLE,		/* RLE format */
+	FMT_TARGA,		/* Targa format */
+	FMT_TIFF		/* TIFF format */
+} IMAGE_FORMATS;
+
+#ifndef DEFAULT_FMT		/* so can override from CFLAGS in Makefile */
+#define DEFAULT_FMT	FMT_PPM
+#endif
+
+static IMAGE_FORMATS requested_fmt;
+
+
+/*
+ * Argument-parsing code.
+ * The switch parser is designed to be useful with DOS-style command line
+ * syntax, ie, intermixed switches and file names, where only the switches
+ * to the left of a given file name affect processing of that file.
+ * The main program in this file doesn't actually use this capability...
+ */
+
+
+static const char * progname;	/* program name for error messages */
+static char * outfilename;	/* for -outfile switch */
+
+
+LOCAL(void)
+usage (void)
+/* complain about bad command line */
+{
+  fprintf(stderr, "usage: %s [switches] ", progname);
+#ifdef TWO_FILE_COMMANDLINE
+  fprintf(stderr, "inputfile outputfile\n");
+#else
+  fprintf(stderr, "[inputfile]\n");
+#endif
+
+  fprintf(stderr, "Switches (names may be abbreviated):\n");
+  fprintf(stderr, "  -colors N      Reduce image to no more than N colors\n");
+  fprintf(stderr, "  -fast          Fast, low-quality processing\n");
+  fprintf(stderr, "  -grayscale     Force grayscale output\n");
+#ifdef IDCT_SCALING_SUPPORTED
+  fprintf(stderr, "  -scale M/N     Scale output image by fraction M/N, eg, 1/8\n");
+#endif
+#ifdef BMP_SUPPORTED
+  fprintf(stderr, "  -bmp           Select BMP output format (Windows style)%s\n",
+	  (DEFAULT_FMT == FMT_BMP ? " (default)" : ""));
+#endif
+#ifdef GIF_SUPPORTED
+  fprintf(stderr, "  -gif           Select GIF output format%s\n",
+	  (DEFAULT_FMT == FMT_GIF ? " (default)" : ""));
+#endif
+#ifdef BMP_SUPPORTED
+  fprintf(stderr, "  -os2           Select BMP output format (OS/2 style)%s\n",
+	  (DEFAULT_FMT == FMT_OS2 ? " (default)" : ""));
+#endif
+#ifdef PPM_SUPPORTED
+  fprintf(stderr, "  -pnm           Select PBMPLUS (PPM/PGM) output format%s\n",
+	  (DEFAULT_FMT == FMT_PPM ? " (default)" : ""));
+#endif
+#ifdef RLE_SUPPORTED
+  fprintf(stderr, "  -rle           Select Utah RLE output format%s\n",
+	  (DEFAULT_FMT == FMT_RLE ? " (default)" : ""));
+#endif
+#ifdef TARGA_SUPPORTED
+  fprintf(stderr, "  -targa         Select Targa output format%s\n",
+	  (DEFAULT_FMT == FMT_TARGA ? " (default)" : ""));
+#endif
+  fprintf(stderr, "Switches for advanced users:\n");
+#ifdef DCT_ISLOW_SUPPORTED
+  fprintf(stderr, "  -dct int       Use integer DCT method%s\n",
+	  (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : ""));
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+  fprintf(stderr, "  -dct fast      Use fast integer DCT (less accurate)%s\n",
+	  (JDCT_DEFAULT == JDCT_IFAST ? " (default)" : ""));
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+  fprintf(stderr, "  -dct float     Use floating-point DCT method%s\n",
+	  (JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : ""));
+#endif
+  fprintf(stderr, "  -dither fs     Use F-S dithering (default)\n");
+  fprintf(stderr, "  -dither none   Don't use dithering in quantization\n");
+  fprintf(stderr, "  -dither ordered  Use ordered dither (medium speed, quality)\n");
+#ifdef QUANT_2PASS_SUPPORTED
+  fprintf(stderr, "  -map FILE      Map to colors used in named image file\n");
+#endif
+  fprintf(stderr, "  -nosmooth      Don't use high-quality upsampling\n");
+#ifdef QUANT_1PASS_SUPPORTED
+  fprintf(stderr, "  -onepass       Use 1-pass quantization (fast, low quality)\n");
+#endif
+  fprintf(stderr, "  -maxmemory N   Maximum memory to use (in kbytes)\n");
+  fprintf(stderr, "  -outfile name  Specify name for output file\n");
+  fprintf(stderr, "  -verbose  or  -debug   Emit debug output\n");
+  exit(EXIT_FAILURE);
+}
+
+
+LOCAL(int)
+parse_switches (j_decompress_ptr cinfo, int argc, char **argv,
+		int last_file_arg_seen, boolean for_real)
+/* Parse optional switches.
+ * Returns argv[] index of first file-name argument (== argc if none).
+ * Any file names with indexes <= last_file_arg_seen are ignored;
+ * they have presumably been processed in a previous iteration.
+ * (Pass 0 for last_file_arg_seen on the first or only iteration.)
+ * for_real is FALSE on the first (dummy) pass; we may skip any expensive
+ * processing.
+ */
+{
+  int argn;
+  char * arg;
+
+  /* Set up default JPEG parameters. */
+  requested_fmt = DEFAULT_FMT;	/* set default output file format */
+  outfilename = NULL;
+  cinfo->err->trace_level = 0;
+
+  /* Scan command line options, adjust parameters */
+
+  for (argn = 1; argn < argc; argn++) {
+    arg = argv[argn];
+    if (*arg != '-') {
+      /* Not a switch, must be a file name argument */
+      if (argn <= last_file_arg_seen) {
+	outfilename = NULL;	/* -outfile applies to just one input file */
+	continue;		/* ignore this name if previously processed */
+      }
+      break;			/* else done parsing switches */
+    }
+    arg++;			/* advance past switch marker character */
+
+    if (keymatch(arg, "bmp", 1)) {
+      /* BMP output format. */
+      requested_fmt = FMT_BMP;
+
+    } else if (keymatch(arg, "colors", 1) || keymatch(arg, "colours", 1) ||
+	       keymatch(arg, "quantize", 1) || keymatch(arg, "quantise", 1)) {
+      /* Do color quantization. */
+      int val;
+
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (sscanf(argv[argn], "%d", &val) != 1)
+	usage();
+      cinfo->desired_number_of_colors = val;
+      cinfo->quantize_colors = TRUE;
+
+    } else if (keymatch(arg, "dct", 2)) {
+      /* Select IDCT algorithm. */
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (keymatch(argv[argn], "int", 1)) {
+	cinfo->dct_method = JDCT_ISLOW;
+      } else if (keymatch(argv[argn], "fast", 2)) {
+	cinfo->dct_method = JDCT_IFAST;
+      } else if (keymatch(argv[argn], "float", 2)) {
+	cinfo->dct_method = JDCT_FLOAT;
+      } else
+	usage();
+
+    } else if (keymatch(arg, "dither", 2)) {
+      /* Select dithering algorithm. */
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (keymatch(argv[argn], "fs", 2)) {
+	cinfo->dither_mode = JDITHER_FS;
+      } else if (keymatch(argv[argn], "none", 2)) {
+	cinfo->dither_mode = JDITHER_NONE;
+      } else if (keymatch(argv[argn], "ordered", 2)) {
+	cinfo->dither_mode = JDITHER_ORDERED;
+      } else
+	usage();
+
+    } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
+      /* Enable debug printouts. */
+      /* On first -d, print version identification */
+      static boolean printed_version = FALSE;
+
+      if (! printed_version) {
+	fprintf(stderr, "Independent JPEG Group's DJPEG, version %s\n%s\n",
+		JVERSION, JCOPYRIGHT);
+	printed_version = TRUE;
+      }
+      cinfo->err->trace_level++;
+
+    } else if (keymatch(arg, "fast", 1)) {
+      /* Select recommended processing options for quick-and-dirty output. */
+      cinfo->two_pass_quantize = FALSE;
+      cinfo->dither_mode = JDITHER_ORDERED;
+      if (! cinfo->quantize_colors) /* don't override an earlier -colors */
+	cinfo->desired_number_of_colors = 216;
+      cinfo->dct_method = JDCT_FASTEST;
+      cinfo->do_fancy_upsampling = FALSE;
+
+    } else if (keymatch(arg, "gif", 1)) {
+      /* GIF output format. */
+      requested_fmt = FMT_GIF;
+
+    } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) {
+      /* Force monochrome output. */
+      cinfo->out_color_space = JCS_GRAYSCALE;
+
+    } else if (keymatch(arg, "map", 3)) {
+      /* Quantize to a color map taken from an input file. */
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (for_real) {		/* too expensive to do twice! */
+#ifdef QUANT_2PASS_SUPPORTED	/* otherwise can't quantize to supplied map */
+	FILE * mapfile;
+
+	if ((mapfile = fopen(argv[argn], READ_BINARY)) == NULL) {
+	  fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
+	  exit(EXIT_FAILURE);
+	}
+	read_color_map(cinfo, mapfile);
+	fclose(mapfile);
+	cinfo->quantize_colors = TRUE;
+#else
+	ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+      }
+
+    } else if (keymatch(arg, "maxmemory", 3)) {
+      /* Maximum memory in Kb (or Mb with 'm'). */
+      long lval;
+      char ch = 'x';
+
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
+	usage();
+      if (ch == 'm' || ch == 'M')
+	lval *= 1000L;
+      cinfo->mem->max_memory_to_use = lval * 1000L;
+
+    } else if (keymatch(arg, "nosmooth", 3)) {
+      /* Suppress fancy upsampling. */
+      cinfo->do_fancy_upsampling = FALSE;
+
+    } else if (keymatch(arg, "onepass", 3)) {
+      /* Use fast one-pass quantization. */
+      cinfo->two_pass_quantize = FALSE;
+
+    } else if (keymatch(arg, "os2", 3)) {
+      /* BMP output format (OS/2 flavor). */
+      requested_fmt = FMT_OS2;
+
+    } else if (keymatch(arg, "outfile", 4)) {
+      /* Set output file name. */
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      outfilename = argv[argn];	/* save it away for later use */
+
+    } else if (keymatch(arg, "pnm", 1) || keymatch(arg, "ppm", 1)) {
+      /* PPM/PGM output format. */
+      requested_fmt = FMT_PPM;
+
+    } else if (keymatch(arg, "rle", 1)) {
+      /* RLE output format. */
+      requested_fmt = FMT_RLE;
+
+    } else if (keymatch(arg, "scale", 1)) {
+      /* Scale the output image by a fraction M/N. */
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (sscanf(argv[argn], "%u/%u",
+		 &cinfo->scale_num, &cinfo->scale_denom) < 1)
+	usage();
+
+    } else if (keymatch(arg, "targa", 1)) {
+      /* Targa output format. */
+      requested_fmt = FMT_TARGA;
+
+    } else {
+      usage();			/* bogus switch */
+    }
+  }
+
+  return argn;			/* return index of next arg (file name) */
+}
+
+
+/*
+ * Marker processor for COM and interesting APPn markers.
+ * This replaces the library's built-in processor, which just skips the marker.
+ * We want to print out the marker as text, to the extent possible.
+ * Note this code relies on a non-suspending data source.
+ */
+
+LOCAL(unsigned int)
+jpeg_getc (j_decompress_ptr cinfo)
+/* Read next byte */
+{
+  struct jpeg_source_mgr * datasrc = cinfo->src;
+
+  if (datasrc->bytes_in_buffer == 0) {
+    if (! (*datasrc->fill_input_buffer) (cinfo))
+      ERREXIT(cinfo, JERR_CANT_SUSPEND);
+  }
+  datasrc->bytes_in_buffer--;
+  return GETJOCTET(*datasrc->next_input_byte++);
+}
+
+
+METHODDEF(boolean)
+print_text_marker (j_decompress_ptr cinfo)
+{
+  boolean traceit = (cinfo->err->trace_level >= 1);
+  INT32 length;
+  unsigned int ch;
+  unsigned int lastch = 0;
+
+  length = jpeg_getc(cinfo) << 8;
+  length += jpeg_getc(cinfo);
+  length -= 2;			/* discount the length word itself */
+
+  if (traceit) {
+    if (cinfo->unread_marker == JPEG_COM)
+      fprintf(stderr, "Comment, length %ld:\n", (long) length);
+    else			/* assume it is an APPn otherwise */
+      fprintf(stderr, "APP%d, length %ld:\n",
+	      cinfo->unread_marker - JPEG_APP0, (long) length);
+  }
+
+  while (--length >= 0) {
+    ch = jpeg_getc(cinfo);
+    if (traceit) {
+      /* Emit the character in a readable form.
+       * Nonprintables are converted to \nnn form,
+       * while \ is converted to \\.
+       * Newlines in CR, CR/LF, or LF form will be printed as one newline.
+       */
+      if (ch == '\r') {
+	fprintf(stderr, "\n");
+      } else if (ch == '\n') {
+	if (lastch != '\r')
+	  fprintf(stderr, "\n");
+      } else if (ch == '\\') {
+	fprintf(stderr, "\\\\");
+      } else if (isprint(ch)) {
+	putc(ch, stderr);
+      } else {
+	fprintf(stderr, "\\%03o", ch);
+      }
+      lastch = ch;
+    }
+  }
+
+  if (traceit)
+    fprintf(stderr, "\n");
+
+  return TRUE;
+}
+
+
+/*
+ * The main program.
+ */
+
+int
+main (int argc, char **argv)
+{
+  struct jpeg_decompress_struct cinfo;
+  struct jpeg_error_mgr jerr;
+#ifdef PROGRESS_REPORT
+  struct cdjpeg_progress_mgr progress;
+#endif
+  int file_index;
+  djpeg_dest_ptr dest_mgr = NULL;
+  FILE * input_file;
+  FILE * output_file;
+  JDIMENSION num_scanlines;
+
+  /* On Mac, fetch a command line. */
+#ifdef USE_CCOMMAND
+  argc = ccommand(&argv);
+#endif
+
+  progname = argv[0];
+  if (progname == NULL || progname[0] == 0)
+    progname = "djpeg";		/* in case C library doesn't provide it */
+
+  /* Initialize the JPEG decompression object with default error handling. */
+  cinfo.err = jpeg_std_error(&jerr);
+  jpeg_create_decompress(&cinfo);
+  /* Add some application-specific error messages (from cderror.h) */
+  jerr.addon_message_table = cdjpeg_message_table;
+  jerr.first_addon_message = JMSG_FIRSTADDONCODE;
+  jerr.last_addon_message = JMSG_LASTADDONCODE;
+
+  /* Insert custom marker processor for COM and APP12.
+   * APP12 is used by some digital camera makers for textual info,
+   * so we provide the ability to display it as text.
+   * If you like, additional APPn marker types can be selected for display,
+   * but don't try to override APP0 or APP14 this way (see libjpeg.doc).
+   */
+  jpeg_set_marker_processor(&cinfo, JPEG_COM, print_text_marker);
+  jpeg_set_marker_processor(&cinfo, JPEG_APP0+12, print_text_marker);
+
+  /* Now safe to enable signal catcher. */
+#ifdef NEED_SIGNAL_CATCHER
+  enable_signal_catcher((j_common_ptr) &cinfo);
+#endif
+
+  /* Scan command line to find file names. */
+  /* It is convenient to use just one switch-parsing routine, but the switch
+   * values read here are ignored; we will rescan the switches after opening
+   * the input file.
+   * (Exception: tracing level set here controls verbosity for COM markers
+   * found during jpeg_read_header...)
+   */
+
+  file_index = parse_switches(&cinfo, argc, argv, 0, FALSE);
+
+#ifdef TWO_FILE_COMMANDLINE
+  /* Must have either -outfile switch or explicit output file name */
+  if (outfilename == NULL) {
+    if (file_index != argc-2) {
+      fprintf(stderr, "%s: must name one input and one output file\n",
+	      progname);
+      usage();
+    }
+    outfilename = argv[file_index+1];
+  } else {
+    if (file_index != argc-1) {
+      fprintf(stderr, "%s: must name one input and one output file\n",
+	      progname);
+      usage();
+    }
+  }
+#else
+  /* Unix style: expect zero or one file name */
+  if (file_index < argc-1) {
+    fprintf(stderr, "%s: only one input file\n", progname);
+    usage();
+  }
+#endif /* TWO_FILE_COMMANDLINE */
+
+  /* Open the input file. */
+  if (file_index < argc) {
+    if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
+      fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
+      exit(EXIT_FAILURE);
+    }
+  } else {
+    /* default input file is stdin */
+    input_file = read_stdin();
+  }
+
+  /* Open the output file. */
+  if (outfilename != NULL) {
+    if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
+      fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
+      exit(EXIT_FAILURE);
+    }
+  } else {
+    /* default output file is stdout */
+    output_file = write_stdout();
+  }
+
+#ifdef PROGRESS_REPORT
+  start_progress_monitor((j_common_ptr) &cinfo, &progress);
+#endif
+
+  /* Specify data source for decompression */
+  jpeg_stdio_src(&cinfo, input_file);
+
+  /* Read file header, set default decompression parameters */
+  (void) jpeg_read_header(&cinfo, TRUE);
+
+  /* Adjust default decompression parameters by re-parsing the options */
+  file_index = parse_switches(&cinfo, argc, argv, 0, TRUE);
+
+  /* Initialize the output module now to let it override any crucial
+   * option settings (for instance, GIF wants to force color quantization).
+   */
+  switch (requested_fmt) {
+#ifdef BMP_SUPPORTED
+  case FMT_BMP:
+    dest_mgr = jinit_write_bmp(&cinfo, FALSE);
+    break;
+  case FMT_OS2:
+    dest_mgr = jinit_write_bmp(&cinfo, TRUE);
+    break;
+#endif
+#ifdef GIF_SUPPORTED
+  case FMT_GIF:
+    dest_mgr = jinit_write_gif(&cinfo);
+    break;
+#endif
+#ifdef PPM_SUPPORTED
+  case FMT_PPM:
+    dest_mgr = jinit_write_ppm(&cinfo);
+    break;
+#endif
+#ifdef RLE_SUPPORTED
+  case FMT_RLE:
+    dest_mgr = jinit_write_rle(&cinfo);
+    break;
+#endif
+#ifdef TARGA_SUPPORTED
+  case FMT_TARGA:
+    dest_mgr = jinit_write_targa(&cinfo);
+    break;
+#endif
+  default:
+    ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT);
+    break;
+  }
+  dest_mgr->output_file = output_file;
+
+  /* Start decompressor */
+  (void) jpeg_start_decompress(&cinfo);
+
+  /* Write output file header */
+  (*dest_mgr->start_output) (&cinfo, dest_mgr);
+
+  /* Process data */
+  while (cinfo.output_scanline < cinfo.output_height) {
+    num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
+					dest_mgr->buffer_height);
+    (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
+  }
+
+#ifdef PROGRESS_REPORT
+  /* Hack: count final pass as done in case finish_output does an extra pass.
+   * The library won't have updated completed_passes.
+   */
+  progress.pub.completed_passes = progress.pub.total_passes;
+#endif
+
+  /* Finish decompression and release memory.
+   * I must do it in this order because output module has allocated memory
+   * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory.
+   */
+  (*dest_mgr->finish_output) (&cinfo, dest_mgr);
+  (void) jpeg_finish_decompress(&cinfo);
+  jpeg_destroy_decompress(&cinfo);
+
+  /* Close files, if we opened them */
+  if (input_file != stdin)
+    fclose(input_file);
+  if (output_file != stdout)
+    fclose(output_file);
+
+#ifdef PROGRESS_REPORT
+  end_progress_monitor((j_common_ptr) &cinfo);
+#endif
+
+  /* All done. */
+  exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);
+  return 0;			/* suppress no-return-value warnings */
+}
diff --git a/source/Irrlicht/jpeglib/example.c b/source/Irrlicht/jpeglib/example.c
new file mode 100644
index 00000000..e21cf121
--- /dev/null
+++ b/source/Irrlicht/jpeglib/example.c
@@ -0,0 +1,433 @@
+/*
+ * example.c
+ *
+ * This file illustrates how to use the IJG code as a subroutine library
+ * to read or write JPEG image files.  You should look at this code in
+ * conjunction with the documentation file libjpeg.txt.
+ *
+ * This code will not do anything useful as-is, but it may be helpful as a
+ * skeleton for constructing routines that call the JPEG library.  
+ *
+ * We present these routines in the same coding style used in the JPEG code
+ * (ANSI function definitions, etc); but you are of course free to code your
+ * routines in a different style if you prefer.
+ */
+
+#include 
+
+/*
+ * Include file for users of JPEG library.
+ * You will need to have included system headers that define at least
+ * the typedefs FILE and size_t before you can include jpeglib.h.
+ * (stdio.h is sufficient on ANSI-conforming systems.)
+ * You may also wish to include "jerror.h".
+ */
+
+#include "jpeglib.h"
+
+/*
+ *  is used for the optional error recovery mechanism shown in
+ * the second part of the example.
+ */
+
+#include 
+
+
+
+/******************** JPEG COMPRESSION SAMPLE INTERFACE *******************/
+
+/* This half of the example shows how to feed data into the JPEG compressor.
+ * We present a minimal version that does not worry about refinements such
+ * as error recovery (the JPEG code will just exit() if it gets an error).
+ */
+
+
+/*
+ * IMAGE DATA FORMATS:
+ *
+ * The standard input image format is a rectangular array of pixels, with
+ * each pixel having the same number of "component" values (color channels).
+ * Each pixel row is an array of JSAMPLEs (which typically are unsigned chars).
+ * If you are working with color data, then the color values for each pixel
+ * must be adjacent in the row; for example, R,G,B,R,G,B,R,G,B,... for 24-bit
+ * RGB color.
+ *
+ * For this example, we'll assume that this data structure matches the way
+ * our application has stored the image in memory, so we can just pass a
+ * pointer to our image buffer.  In particular, let's say that the image is
+ * RGB color and is described by:
+ */
+
+extern JSAMPLE * image_buffer;	/* Points to large array of R,G,B-order data */
+extern int image_height;	/* Number of rows in image */
+extern int image_width;		/* Number of columns in image */
+
+
+/*
+ * Sample routine for JPEG compression.  We assume that the target file name
+ * and a compression quality factor are passed in.
+ */
+
+GLOBAL(void)
+write_JPEG_file (char * filename, int quality)
+{
+  /* This struct contains the JPEG compression parameters and pointers to
+   * working space (which is allocated as needed by the JPEG library).
+   * It is possible to have several such structures, representing multiple
+   * compression/decompression processes, in existence at once.  We refer
+   * to any one struct (and its associated working data) as a "JPEG object".
+   */
+  struct jpeg_compress_struct cinfo;
+  /* This struct represents a JPEG error handler.  It is declared separately
+   * because applications often want to supply a specialized error handler
+   * (see the second half of this file for an example).  But here we just
+   * take the easy way out and use the standard error handler, which will
+   * print a message on stderr and call exit() if compression fails.
+   * Note that this struct must live as long as the main JPEG parameter
+   * struct, to avoid dangling-pointer problems.
+   */
+  struct jpeg_error_mgr jerr;
+  /* More stuff */
+  FILE * outfile;		/* target file */
+  JSAMPROW row_pointer[1];	/* pointer to JSAMPLE row[s] */
+  int row_stride;		/* physical row width in image buffer */
+
+  /* Step 1: allocate and initialize JPEG compression object */
+
+  /* We have to set up the error handler first, in case the initialization
+   * step fails.  (Unlikely, but it could happen if you are out of memory.)
+   * This routine fills in the contents of struct jerr, and returns jerr's
+   * address which we place into the link field in cinfo.
+   */
+  cinfo.err = jpeg_std_error(&jerr);
+  /* Now we can initialize the JPEG compression object. */
+  jpeg_create_compress(&cinfo);
+
+  /* Step 2: specify data destination (eg, a file) */
+  /* Note: steps 2 and 3 can be done in either order. */
+
+  /* Here we use the library-supplied code to send compressed data to a
+   * stdio stream.  You can also write your own code to do something else.
+   * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
+   * requires it in order to write binary files.
+   */
+  if ((outfile = fopen(filename, "wb")) == NULL) {
+    fprintf(stderr, "can't open %s\n", filename);
+    exit(1);
+  }
+  jpeg_stdio_dest(&cinfo, outfile);
+
+  /* Step 3: set parameters for compression */
+
+  /* First we supply a description of the input image.
+   * Four fields of the cinfo struct must be filled in:
+   */
+  cinfo.image_width = image_width; 	/* image width and height, in pixels */
+  cinfo.image_height = image_height;
+  cinfo.input_components = 3;		/* # of color components per pixel */
+  cinfo.in_color_space = JCS_RGB; 	/* colorspace of input image */
+  /* Now use the library's routine to set default compression parameters.
+   * (You must set at least cinfo.in_color_space before calling this,
+   * since the defaults depend on the source color space.)
+   */
+  jpeg_set_defaults(&cinfo);
+  /* Now you can set any non-default parameters you wish to.
+   * Here we just illustrate the use of quality (quantization table) scaling:
+   */
+  jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
+
+  /* Step 4: Start compressor */
+
+  /* TRUE ensures that we will write a complete interchange-JPEG file.
+   * Pass TRUE unless you are very sure of what you're doing.
+   */
+  jpeg_start_compress(&cinfo, TRUE);
+
+  /* Step 5: while (scan lines remain to be written) */
+  /*           jpeg_write_scanlines(...); */
+
+  /* Here we use the library's state variable cinfo.next_scanline as the
+   * loop counter, so that we don't have to keep track ourselves.
+   * To keep things simple, we pass one scanline per call; you can pass
+   * more if you wish, though.
+   */
+  row_stride = image_width * 3;	/* JSAMPLEs per row in image_buffer */
+
+  while (cinfo.next_scanline < cinfo.image_height) {
+    /* jpeg_write_scanlines expects an array of pointers to scanlines.
+     * Here the array is only one element long, but you could pass
+     * more than one scanline at a time if that's more convenient.
+     */
+    row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
+    (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
+  }
+
+  /* Step 6: Finish compression */
+
+  jpeg_finish_compress(&cinfo);
+  /* After finish_compress, we can close the output file. */
+  fclose(outfile);
+
+  /* Step 7: release JPEG compression object */
+
+  /* This is an important step since it will release a good deal of memory. */
+  jpeg_destroy_compress(&cinfo);
+
+  /* And we're done! */
+}
+
+
+/*
+ * SOME FINE POINTS:
+ *
+ * In the above loop, we ignored the return value of jpeg_write_scanlines,
+ * which is the number of scanlines actually written.  We could get away
+ * with this because we were only relying on the value of cinfo.next_scanline,
+ * which will be incremented correctly.  If you maintain additional loop
+ * variables then you should be careful to increment them properly.
+ * Actually, for output to a stdio stream you needn't worry, because
+ * then jpeg_write_scanlines will write all the lines passed (or else exit
+ * with a fatal error).  Partial writes can only occur if you use a data
+ * destination module that can demand suspension of the compressor.
+ * (If you don't know what that's for, you don't need it.)
+ *
+ * If the compressor requires full-image buffers (for entropy-coding
+ * optimization or a multi-scan JPEG file), it will create temporary
+ * files for anything that doesn't fit within the maximum-memory setting.
+ * (Note that temp files are NOT needed if you use the default parameters.)
+ * On some systems you may need to set up a signal handler to ensure that
+ * temporary files are deleted if the program is interrupted.  See libjpeg.txt.
+ *
+ * Scanlines MUST be supplied in top-to-bottom order if you want your JPEG
+ * files to be compatible with everyone else's.  If you cannot readily read
+ * your data in that order, you'll need an intermediate array to hold the
+ * image.  See rdtarga.c or rdbmp.c for examples of handling bottom-to-top
+ * source data using the JPEG code's internal virtual-array mechanisms.
+ */
+
+
+
+/******************** JPEG DECOMPRESSION SAMPLE INTERFACE *******************/
+
+/* This half of the example shows how to read data from the JPEG decompressor.
+ * It's a bit more refined than the above, in that we show:
+ *   (a) how to modify the JPEG library's standard error-reporting behavior;
+ *   (b) how to allocate workspace using the library's memory manager.
+ *
+ * Just to make this example a little different from the first one, we'll
+ * assume that we do not intend to put the whole image into an in-memory
+ * buffer, but to send it line-by-line someplace else.  We need a one-
+ * scanline-high JSAMPLE array as a work buffer, and we will let the JPEG
+ * memory manager allocate it for us.  This approach is actually quite useful
+ * because we don't need to remember to deallocate the buffer separately: it
+ * will go away automatically when the JPEG object is cleaned up.
+ */
+
+
+/*
+ * ERROR HANDLING:
+ *
+ * The JPEG library's standard error handler (jerror.c) is divided into
+ * several "methods" which you can override individually.  This lets you
+ * adjust the behavior without duplicating a lot of code, which you might
+ * have to update with each future release.
+ *
+ * Our example here shows how to override the "error_exit" method so that
+ * control is returned to the library's caller when a fatal error occurs,
+ * rather than calling exit() as the standard error_exit method does.
+ *
+ * We use C's setjmp/longjmp facility to return control.  This means that the
+ * routine which calls the JPEG library must first execute a setjmp() call to
+ * establish the return point.  We want the replacement error_exit to do a
+ * longjmp().  But we need to make the setjmp buffer accessible to the
+ * error_exit routine.  To do this, we make a private extension of the
+ * standard JPEG error handler object.  (If we were using C++, we'd say we
+ * were making a subclass of the regular error handler.)
+ *
+ * Here's the extended error handler struct:
+ */
+
+struct my_error_mgr {
+  struct jpeg_error_mgr pub;	/* "public" fields */
+
+  jmp_buf setjmp_buffer;	/* for return to caller */
+};
+
+typedef struct my_error_mgr * my_error_ptr;
+
+/*
+ * Here's the routine that will replace the standard error_exit method:
+ */
+
+METHODDEF(void)
+my_error_exit (j_common_ptr cinfo)
+{
+  /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
+  my_error_ptr myerr = (my_error_ptr) cinfo->err;
+
+  /* Always display the message. */
+  /* We could postpone this until after returning, if we chose. */
+  (*cinfo->err->output_message) (cinfo);
+
+  /* Return control to the setjmp point */
+  longjmp(myerr->setjmp_buffer, 1);
+}
+
+
+/*
+ * Sample routine for JPEG decompression.  We assume that the source file name
+ * is passed in.  We want to return 1 on success, 0 on error.
+ */
+
+
+GLOBAL(int)
+read_JPEG_file (char * filename)
+{
+  /* This struct contains the JPEG decompression parameters and pointers to
+   * working space (which is allocated as needed by the JPEG library).
+   */
+  struct jpeg_decompress_struct cinfo;
+  /* We use our private extension JPEG error handler.
+   * Note that this struct must live as long as the main JPEG parameter
+   * struct, to avoid dangling-pointer problems.
+   */
+  struct my_error_mgr jerr;
+  /* More stuff */
+  FILE * infile;		/* source file */
+  JSAMPARRAY buffer;		/* Output row buffer */
+  int row_stride;		/* physical row width in output buffer */
+
+  /* In this example we want to open the input file before doing anything else,
+   * so that the setjmp() error recovery below can assume the file is open.
+   * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
+   * requires it in order to read binary files.
+   */
+
+  if ((infile = fopen(filename, "rb")) == NULL) {
+    fprintf(stderr, "can't open %s\n", filename);
+    return 0;
+  }
+
+  /* Step 1: allocate and initialize JPEG decompression object */
+
+  /* We set up the normal JPEG error routines, then override error_exit. */
+  cinfo.err = jpeg_std_error(&jerr.pub);
+  jerr.pub.error_exit = my_error_exit;
+  /* Establish the setjmp return context for my_error_exit to use. */
+  if (setjmp(jerr.setjmp_buffer)) {
+    /* If we get here, the JPEG code has signaled an error.
+     * We need to clean up the JPEG object, close the input file, and return.
+     */
+    jpeg_destroy_decompress(&cinfo);
+    fclose(infile);
+    return 0;
+  }
+  /* Now we can initialize the JPEG decompression object. */
+  jpeg_create_decompress(&cinfo);
+
+  /* Step 2: specify data source (eg, a file) */
+
+  jpeg_stdio_src(&cinfo, infile);
+
+  /* Step 3: read file parameters with jpeg_read_header() */
+
+  (void) jpeg_read_header(&cinfo, TRUE);
+  /* We can ignore the return value from jpeg_read_header since
+   *   (a) suspension is not possible with the stdio data source, and
+   *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
+   * See libjpeg.txt for more info.
+   */
+
+  /* Step 4: set parameters for decompression */
+
+  /* In this example, we don't need to change any of the defaults set by
+   * jpeg_read_header(), so we do nothing here.
+   */
+
+  /* Step 5: Start decompressor */
+
+  (void) jpeg_start_decompress(&cinfo);
+  /* We can ignore the return value since suspension is not possible
+   * with the stdio data source.
+   */
+
+  /* We may need to do some setup of our own at this point before reading
+   * the data.  After jpeg_start_decompress() we have the correct scaled
+   * output image dimensions available, as well as the output colormap
+   * if we asked for color quantization.
+   * In this example, we need to make an output work buffer of the right size.
+   */ 
+  /* JSAMPLEs per row in output buffer */
+  row_stride = cinfo.output_width * cinfo.output_components;
+  /* Make a one-row-high sample array that will go away when done with image */
+  buffer = (*cinfo.mem->alloc_sarray)
+		((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
+
+  /* Step 6: while (scan lines remain to be read) */
+  /*           jpeg_read_scanlines(...); */
+
+  /* Here we use the library's state variable cinfo.output_scanline as the
+   * loop counter, so that we don't have to keep track ourselves.
+   */
+  while (cinfo.output_scanline < cinfo.output_height) {
+    /* jpeg_read_scanlines expects an array of pointers to scanlines.
+     * Here the array is only one element long, but you could ask for
+     * more than one scanline at a time if that's more convenient.
+     */
+    (void) jpeg_read_scanlines(&cinfo, buffer, 1);
+    /* Assume put_scanline_someplace wants a pointer and sample count. */
+    put_scanline_someplace(buffer[0], row_stride);
+  }
+
+  /* Step 7: Finish decompression */
+
+  (void) jpeg_finish_decompress(&cinfo);
+  /* We can ignore the return value since suspension is not possible
+   * with the stdio data source.
+   */
+
+  /* Step 8: Release JPEG decompression object */
+
+  /* This is an important step since it will release a good deal of memory. */
+  jpeg_destroy_decompress(&cinfo);
+
+  /* After finish_decompress, we can close the input file.
+   * Here we postpone it until after no more JPEG errors are possible,
+   * so as to simplify the setjmp error logic above.  (Actually, I don't
+   * think that jpeg_destroy can do an error exit, but why assume anything...)
+   */
+  fclose(infile);
+
+  /* At this point you may want to check to see whether any corrupt-data
+   * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
+   */
+
+  /* And we're done! */
+  return 1;
+}
+
+
+/*
+ * SOME FINE POINTS:
+ *
+ * In the above code, we ignored the return value of jpeg_read_scanlines,
+ * which is the number of scanlines actually read.  We could get away with
+ * this because we asked for only one line at a time and we weren't using
+ * a suspending data source.  See libjpeg.txt for more info.
+ *
+ * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress();
+ * we should have done it beforehand to ensure that the space would be
+ * counted against the JPEG max_memory setting.  In some systems the above
+ * code would risk an out-of-memory error.  However, in general we don't
+ * know the output image dimensions before jpeg_start_decompress(), unless we
+ * call jpeg_calc_output_dimensions().  See libjpeg.txt for more about this.
+ *
+ * Scanlines are returned in the same order as they appear in the JPEG file,
+ * which is standardly top-to-bottom.  If you must emit data bottom-to-top,
+ * you can use one of the virtual arrays provided by the JPEG memory manager
+ * to invert the data.  See wrbmp.c for an example.
+ *
+ * As with compression, some operating modes may require temporary files.
+ * On some systems you may need to set up a signal handler to ensure that
+ * temporary files are deleted if the program is interrupted.  See libjpeg.txt.
+ */
diff --git a/source/Irrlicht/jpeglib/filelist.txt b/source/Irrlicht/jpeglib/filelist.txt
new file mode 100644
index 00000000..adfd14f3
--- /dev/null
+++ b/source/Irrlicht/jpeglib/filelist.txt
@@ -0,0 +1,215 @@
+IJG JPEG LIBRARY:  FILE LIST
+
+Copyright (C) 1994-2013, Thomas G. Lane, Guido Vollbeding.
+This file is part of the Independent JPEG Group's software.
+For conditions of distribution and use, see the accompanying README file.
+
+
+Here is a road map to the files in the IJG JPEG distribution.  The
+distribution includes the JPEG library proper, plus two application
+programs ("cjpeg" and "djpeg") which use the library to convert JPEG
+files to and from some other popular image formats.  A third application
+"jpegtran" uses the library to do lossless conversion between different
+variants of JPEG.  There are also two stand-alone applications,
+"rdjpgcom" and "wrjpgcom".
+
+
+THE JPEG LIBRARY
+================
+
+Include files:
+
+jpeglib.h	JPEG library's exported data and function declarations.
+jconfig.h	Configuration declarations.  Note: this file is not present
+		in the distribution; it is generated during installation.
+jmorecfg.h	Additional configuration declarations; need not be changed
+		for a standard installation.
+jerror.h	Declares JPEG library's error and trace message codes.
+jinclude.h	Central include file used by all IJG .c files to reference
+		system include files.
+jpegint.h	JPEG library's internal data structures.
+jdct.h		Private declarations for forward & reverse DCT subsystems.
+jmemsys.h	Private declarations for memory management subsystem.
+jversion.h	Version information.
+
+Applications using the library should include jpeglib.h (which in turn
+includes jconfig.h and jmorecfg.h).  Optionally, jerror.h may be included
+if the application needs to reference individual JPEG error codes.  The
+other include files are intended for internal use and would not normally
+be included by an application program.  (cjpeg/djpeg/etc do use jinclude.h,
+since its function is to improve portability of the whole IJG distribution.
+Most other applications will directly include the system include files they
+want, and hence won't need jinclude.h.)
+
+
+C source code files:
+
+These files contain most of the functions intended to be called directly by
+an application program:
+
+jcapimin.c	Application program interface: core routines for compression.
+jcapistd.c	Application program interface: standard compression.
+jdapimin.c	Application program interface: core routines for decompression.
+jdapistd.c	Application program interface: standard decompression.
+jcomapi.c	Application program interface routines common to compression
+		and decompression.
+jcparam.c	Compression parameter setting helper routines.
+jctrans.c	API and library routines for transcoding compression.
+jdtrans.c	API and library routines for transcoding decompression.
+
+Compression side of the library:
+
+jcinit.c	Initialization: determines which other modules to use.
+jcmaster.c	Master control: setup and inter-pass sequencing logic.
+jcmainct.c	Main buffer controller (preprocessor => JPEG compressor).
+jcprepct.c	Preprocessor buffer controller.
+jccoefct.c	Buffer controller for DCT coefficient buffer.
+jccolor.c	Color space conversion.
+jcsample.c	Downsampling.
+jcdctmgr.c	DCT manager (DCT implementation selection & control).
+jfdctint.c	Forward DCT using slow-but-accurate integer method.
+jfdctfst.c	Forward DCT using faster, less accurate integer method.
+jfdctflt.c	Forward DCT using floating-point arithmetic.
+jchuff.c	Huffman entropy coding.
+jcarith.c	Arithmetic entropy coding.
+jcmarker.c	JPEG marker writing.
+jdatadst.c	Data destination managers for memory and stdio output.
+
+Decompression side of the library:
+
+jdmaster.c	Master control: determines which other modules to use.
+jdinput.c	Input controller: controls input processing modules.
+jdmainct.c	Main buffer controller (JPEG decompressor => postprocessor).
+jdcoefct.c	Buffer controller for DCT coefficient buffer.
+jdpostct.c	Postprocessor buffer controller.
+jdmarker.c	JPEG marker reading.
+jdhuff.c	Huffman entropy decoding.
+jdarith.c	Arithmetic entropy decoding.
+jddctmgr.c	IDCT manager (IDCT implementation selection & control).
+jidctint.c	Inverse DCT using slow-but-accurate integer method.
+jidctfst.c	Inverse DCT using faster, less accurate integer method.
+jidctflt.c	Inverse DCT using floating-point arithmetic.
+jdsample.c	Upsampling.
+jdcolor.c	Color space conversion.
+jdmerge.c	Merged upsampling/color conversion (faster, lower quality).
+jquant1.c	One-pass color quantization using a fixed-spacing colormap.
+jquant2.c	Two-pass color quantization using a custom-generated colormap.
+		Also handles one-pass quantization to an externally given map.
+jdatasrc.c	Data source managers for memory and stdio input.
+
+Support files for both compression and decompression:
+
+jaricom.c	Tables for common use in arithmetic entropy encoding and
+		decoding routines.
+jerror.c	Standard error handling routines (application replaceable).
+jmemmgr.c	System-independent (more or less) memory management code.
+jutils.c	Miscellaneous utility routines.
+
+jmemmgr.c relies on a system-dependent memory management module.  The IJG
+distribution includes the following implementations of the system-dependent
+module:
+
+jmemnobs.c	"No backing store": assumes adequate virtual memory exists.
+jmemansi.c	Makes temporary files with ANSI-standard routine tmpfile().
+jmemname.c	Makes temporary files with program-generated file names.
+jmemdos.c	Custom implementation for MS-DOS (16-bit environment only):
+		can use extended and expanded memory as well as temp files.
+jmemmac.c	Custom implementation for Apple Macintosh.
+
+Exactly one of the system-dependent modules should be configured into an
+installed JPEG library (see install.txt for hints about which one to use).
+On unusual systems you may find it worthwhile to make a special
+system-dependent memory manager.
+
+
+Non-C source code files:
+
+jmemdosa.asm	80x86 assembly code support for jmemdos.c; used only in
+		MS-DOS-specific configurations of the JPEG library.
+
+
+CJPEG/DJPEG/JPEGTRAN
+====================
+
+Include files:
+
+cdjpeg.h	Declarations shared by cjpeg/djpeg/jpegtran modules.
+cderror.h	Additional error and trace message codes for cjpeg et al.
+transupp.h	Declarations for jpegtran support routines in transupp.c.
+
+C source code files:
+
+cjpeg.c		Main program for cjpeg.
+djpeg.c		Main program for djpeg.
+jpegtran.c	Main program for jpegtran.
+cdjpeg.c	Utility routines used by all three programs.
+rdcolmap.c	Code to read a colormap file for djpeg's "-map" switch.
+rdswitch.c	Code to process some of cjpeg's more complex switches.
+		Also used by jpegtran.
+transupp.c	Support code for jpegtran: lossless image manipulations.
+
+Image file reader modules for cjpeg:
+
+rdbmp.c		BMP file input.
+rdgif.c		GIF file input (now just a stub).
+rdppm.c		PPM/PGM file input.
+rdrle.c		Utah RLE file input.
+rdtarga.c	Targa file input.
+
+Image file writer modules for djpeg:
+
+wrbmp.c		BMP file output.
+wrgif.c		GIF file output (a mere shadow of its former self).
+wrppm.c		PPM/PGM file output.
+wrrle.c		Utah RLE file output.
+wrtarga.c	Targa file output.
+
+
+RDJPGCOM/WRJPGCOM
+=================
+
+C source code files:
+
+rdjpgcom.c	Stand-alone rdjpgcom application.
+wrjpgcom.c	Stand-alone wrjpgcom application.
+
+These programs do not depend on the IJG library.  They do use
+jconfig.h and jinclude.h, only to improve portability.
+
+
+ADDITIONAL FILES
+================
+
+Documentation (see README for a guide to the documentation files):
+
+README		Master documentation file.
+*.txt		Other documentation files.
+*.1		Documentation in Unix man page format.
+change.log	Version-to-version change highlights.
+example.c	Sample code for calling JPEG library.
+
+Configuration/installation files and programs (see install.txt for more info):
+
+configure	Unix shell script to perform automatic configuration.
+configure.ac	Source file for use with Autoconf to generate configure.
+ltmain.sh	Support scripts for configure (from GNU libtool).
+config.guess
+config.sub
+depcomp
+missing
+ar-lib
+compile
+install-sh	Install shell script for those Unix systems lacking one.
+Makefile.in	Makefile input for configure.
+Makefile.am	Source file for use with Automake to generate Makefile.in.
+ckconfig.c	Program to generate jconfig.h on non-Unix systems.
+jconfig.txt	Template for making jconfig.h by hand.
+mak*.*		Sample makefiles for particular systems.
+jconfig.*	Sample jconfig.h for particular systems.
+libjpeg.map	Script to generate shared library with versioned symbols.
+aclocal.m4	M4 macro definitions for use with Autoconf.
+
+Test files (see install.txt for test procedure):
+
+test*.*		Source and comparison files for confidence test.
+		These are binary image files, NOT text files.
diff --git a/source/Irrlicht/jpeglib/install-sh b/source/Irrlicht/jpeglib/install-sh
new file mode 100644
index 00000000..377bb868
--- /dev/null
+++ b/source/Irrlicht/jpeglib/install-sh
@@ -0,0 +1,527 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2011-11-20.07; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# 'make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" ""	$nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit=${DOITPROG-}
+if test -z "$doit"; then
+  doit_exec=exec
+else
+  doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_glob='?'
+initialize_posix_glob='
+  test "$posix_glob" != "?" || {
+    if (set -f) 2>/dev/null; then
+      posix_glob=
+    else
+      posix_glob=:
+    fi
+  }
+'
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+no_target_directory=
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+   or: $0 [OPTION]... SRCFILES... DIRECTORY
+   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+   or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+     --help     display this help and exit.
+     --version  display version info and exit.
+
+  -c            (ignored)
+  -C            install only if different (preserve the last data modification time)
+  -d            create directories instead of installing files.
+  -g GROUP      $chgrpprog installed files to GROUP.
+  -m MODE       $chmodprog installed files to MODE.
+  -o USER       $chownprog installed files to USER.
+  -s            $stripprog installed files.
+  -t DIRECTORY  install into DIRECTORY.
+  -T            report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+  RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+  case $1 in
+    -c) ;;
+
+    -C) copy_on_change=true;;
+
+    -d) dir_arg=true;;
+
+    -g) chgrpcmd="$chgrpprog $2"
+	shift;;
+
+    --help) echo "$usage"; exit $?;;
+
+    -m) mode=$2
+	case $mode in
+	  *' '* | *'	'* | *'
+'*	  | *'*'* | *'?'* | *'['*)
+	    echo "$0: invalid mode: $mode" >&2
+	    exit 1;;
+	esac
+	shift;;
+
+    -o) chowncmd="$chownprog $2"
+	shift;;
+
+    -s) stripcmd=$stripprog;;
+
+    -t) dst_arg=$2
+	# Protect names problematic for 'test' and other utilities.
+	case $dst_arg in
+	  -* | [=\(\)!]) dst_arg=./$dst_arg;;
+	esac
+	shift;;
+
+    -T) no_target_directory=true;;
+
+    --version) echo "$0 $scriptversion"; exit $?;;
+
+    --)	shift
+	break;;
+
+    -*)	echo "$0: invalid option: $1" >&2
+	exit 1;;
+
+    *)  break;;
+  esac
+  shift
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+  # When -d is used, all remaining arguments are directories to create.
+  # When -t is used, the destination is already specified.
+  # Otherwise, the last argument is the destination.  Remove it from $@.
+  for arg
+  do
+    if test -n "$dst_arg"; then
+      # $@ is not empty: it contains at least $arg.
+      set fnord "$@" "$dst_arg"
+      shift # fnord
+    fi
+    shift # arg
+    dst_arg=$arg
+    # Protect names problematic for 'test' and other utilities.
+    case $dst_arg in
+      -* | [=\(\)!]) dst_arg=./$dst_arg;;
+    esac
+  done
+fi
+
+if test $# -eq 0; then
+  if test -z "$dir_arg"; then
+    echo "$0: no input file specified." >&2
+    exit 1
+  fi
+  # It's OK to call 'install-sh -d' without argument.
+  # This can happen when creating conditional directories.
+  exit 0
+fi
+
+if test -z "$dir_arg"; then
+  do_exit='(exit $ret); exit $ret'
+  trap "ret=129; $do_exit" 1
+  trap "ret=130; $do_exit" 2
+  trap "ret=141; $do_exit" 13
+  trap "ret=143; $do_exit" 15
+
+  # Set umask so as not to create temps with too-generous modes.
+  # However, 'strip' requires both read and write access to temps.
+  case $mode in
+    # Optimize common cases.
+    *644) cp_umask=133;;
+    *755) cp_umask=22;;
+
+    *[0-7])
+      if test -z "$stripcmd"; then
+	u_plus_rw=
+      else
+	u_plus_rw='% 200'
+      fi
+      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+    *)
+      if test -z "$stripcmd"; then
+	u_plus_rw=
+      else
+	u_plus_rw=,u+rw
+      fi
+      cp_umask=$mode$u_plus_rw;;
+  esac
+fi
+
+for src
+do
+  # Protect names problematic for 'test' and other utilities.
+  case $src in
+    -* | [=\(\)!]) src=./$src;;
+  esac
+
+  if test -n "$dir_arg"; then
+    dst=$src
+    dstdir=$dst
+    test -d "$dstdir"
+    dstdir_status=$?
+  else
+
+    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+    # might cause directories to be created, which would be especially bad
+    # if $src (and thus $dsttmp) contains '*'.
+    if test ! -f "$src" && test ! -d "$src"; then
+      echo "$0: $src does not exist." >&2
+      exit 1
+    fi
+
+    if test -z "$dst_arg"; then
+      echo "$0: no destination specified." >&2
+      exit 1
+    fi
+    dst=$dst_arg
+
+    # If destination is a directory, append the input filename; won't work
+    # if double slashes aren't ignored.
+    if test -d "$dst"; then
+      if test -n "$no_target_directory"; then
+	echo "$0: $dst_arg: Is a directory" >&2
+	exit 1
+      fi
+      dstdir=$dst
+      dst=$dstdir/`basename "$src"`
+      dstdir_status=0
+    else
+      # Prefer dirname, but fall back on a substitute if dirname fails.
+      dstdir=`
+	(dirname "$dst") 2>/dev/null ||
+	expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	     X"$dst" : 'X\(//\)[^/]' \| \
+	     X"$dst" : 'X\(//\)$' \| \
+	     X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+	echo X"$dst" |
+	    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\/\)[^/].*/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\/\)$/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\).*/{
+		   s//\1/
+		   q
+		 }
+		 s/.*/./; q'
+      `
+
+      test -d "$dstdir"
+      dstdir_status=$?
+    fi
+  fi
+
+  obsolete_mkdir_used=false
+
+  if test $dstdir_status != 0; then
+    case $posix_mkdir in
+      '')
+	# Create intermediate dirs using mode 755 as modified by the umask.
+	# This is like FreeBSD 'install' as of 1997-10-28.
+	umask=`umask`
+	case $stripcmd.$umask in
+	  # Optimize common cases.
+	  *[2367][2367]) mkdir_umask=$umask;;
+	  .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+	  *[0-7])
+	    mkdir_umask=`expr $umask + 22 \
+	      - $umask % 100 % 40 + $umask % 20 \
+	      - $umask % 10 % 4 + $umask % 2
+	    `;;
+	  *) mkdir_umask=$umask,go-w;;
+	esac
+
+	# With -d, create the new directory with the user-specified mode.
+	# Otherwise, rely on $mkdir_umask.
+	if test -n "$dir_arg"; then
+	  mkdir_mode=-m$mode
+	else
+	  mkdir_mode=
+	fi
+
+	posix_mkdir=false
+	case $umask in
+	  *[123567][0-7][0-7])
+	    # POSIX mkdir -p sets u+wx bits regardless of umask, which
+	    # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+	    ;;
+	  *)
+	    tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+	    trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+	    if (umask $mkdir_umask &&
+		exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+	    then
+	      if test -z "$dir_arg" || {
+		   # Check for POSIX incompatibilities with -m.
+		   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+		   # other-writable bit of parent directory when it shouldn't.
+		   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+		   ls_ld_tmpdir=`ls -ld "$tmpdir"`
+		   case $ls_ld_tmpdir in
+		     d????-?r-*) different_mode=700;;
+		     d????-?--*) different_mode=755;;
+		     *) false;;
+		   esac &&
+		   $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+		     ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+		     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+		   }
+		 }
+	      then posix_mkdir=:
+	      fi
+	      rmdir "$tmpdir/d" "$tmpdir"
+	    else
+	      # Remove any dirs left behind by ancient mkdir implementations.
+	      rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+	    fi
+	    trap '' 0;;
+	esac;;
+    esac
+
+    if
+      $posix_mkdir && (
+	umask $mkdir_umask &&
+	$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+      )
+    then :
+    else
+
+      # The umask is ridiculous, or mkdir does not conform to POSIX,
+      # or it failed possibly due to a race condition.  Create the
+      # directory the slow way, step by step, checking for races as we go.
+
+      case $dstdir in
+	/*) prefix='/';;
+	[-=\(\)!]*) prefix='./';;
+	*)  prefix='';;
+      esac
+
+      eval "$initialize_posix_glob"
+
+      oIFS=$IFS
+      IFS=/
+      $posix_glob set -f
+      set fnord $dstdir
+      shift
+      $posix_glob set +f
+      IFS=$oIFS
+
+      prefixes=
+
+      for d
+      do
+	test X"$d" = X && continue
+
+	prefix=$prefix$d
+	if test -d "$prefix"; then
+	  prefixes=
+	else
+	  if $posix_mkdir; then
+	    (umask=$mkdir_umask &&
+	     $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+	    # Don't fail if two instances are running concurrently.
+	    test -d "$prefix" || exit 1
+	  else
+	    case $prefix in
+	      *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+	      *) qprefix=$prefix;;
+	    esac
+	    prefixes="$prefixes '$qprefix'"
+	  fi
+	fi
+	prefix=$prefix/
+      done
+
+      if test -n "$prefixes"; then
+	# Don't fail if two instances are running concurrently.
+	(umask $mkdir_umask &&
+	 eval "\$doit_exec \$mkdirprog $prefixes") ||
+	  test -d "$dstdir" || exit 1
+	obsolete_mkdir_used=true
+      fi
+    fi
+  fi
+
+  if test -n "$dir_arg"; then
+    { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+    { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+      test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+  else
+
+    # Make a couple of temp file names in the proper directory.
+    dsttmp=$dstdir/_inst.$$_
+    rmtmp=$dstdir/_rm.$$_
+
+    # Trap to clean up those temp files at exit.
+    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+    # Copy the file name to the temp name.
+    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+    # and set any options; do chmod last to preserve setuid bits.
+    #
+    # If any of these fail, we abort the whole thing.  If we want to
+    # ignore errors from any of these, just make sure not to ignore
+    # errors from the above "$doit $cpprog $src $dsttmp" command.
+    #
+    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+    { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+    { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+    # If -C, don't bother to copy if it wouldn't change the file.
+    if $copy_on_change &&
+       old=`LC_ALL=C ls -dlL "$dst"	2>/dev/null` &&
+       new=`LC_ALL=C ls -dlL "$dsttmp"	2>/dev/null` &&
+
+       eval "$initialize_posix_glob" &&
+       $posix_glob set -f &&
+       set X $old && old=:$2:$4:$5:$6 &&
+       set X $new && new=:$2:$4:$5:$6 &&
+       $posix_glob set +f &&
+
+       test "$old" = "$new" &&
+       $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+    then
+      rm -f "$dsttmp"
+    else
+      # Rename the file to the real destination.
+      $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+      # The rename failed, perhaps because mv can't rename something else
+      # to itself, or perhaps because mv is so ancient that it does not
+      # support -f.
+      {
+	# Now remove or move aside any old file at destination location.
+	# We try this two ways since rm can't unlink itself on some
+	# systems and the destination file might be busy for other
+	# reasons.  In this case, the final cleanup might fail but the new
+	# file should still install successfully.
+	{
+	  test ! -f "$dst" ||
+	  $doit $rmcmd -f "$dst" 2>/dev/null ||
+	  { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+	    { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+	  } ||
+	  { echo "$0: cannot unlink or rename $dst" >&2
+	    (exit 1); exit 1
+	  }
+	} &&
+
+	# Now rename the file to the real destination.
+	$doit $mvcmd "$dsttmp" "$dst"
+      }
+    fi || exit 1
+
+    trap '' 0
+  fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/source/Irrlicht/jpeglib/install.txt b/source/Irrlicht/jpeglib/install.txt
new file mode 100644
index 00000000..04053068
--- /dev/null
+++ b/source/Irrlicht/jpeglib/install.txt
@@ -0,0 +1,1106 @@
+INSTALLATION INSTRUCTIONS for the Independent JPEG Group's JPEG software
+
+Copyright (C) 1991-2013, Thomas G. Lane, Guido Vollbeding.
+This file is part of the Independent JPEG Group's software.
+For conditions of distribution and use, see the accompanying README file.
+
+
+This file explains how to configure and install the IJG software.  We have
+tried to make this software extremely portable and flexible, so that it can be
+adapted to almost any environment.  The downside of this decision is that the
+installation process is complicated.  We have provided shortcuts to simplify
+the task on common systems.  But in any case, you will need at least a little
+familiarity with C programming and program build procedures for your system.
+
+If you are only using this software as part of a larger program, the larger
+program's installation procedure may take care of configuring the IJG code.
+For example, Ghostscript's installation script will configure the IJG code.
+You don't need to read this file if you just want to compile Ghostscript.
+
+If you are on a Unix machine, you may not need to read this file at all.
+Try doing
+	./configure
+	make
+	make test
+If that doesn't complain, do
+	make install
+(better do "make -n install" first to see if the makefile will put the files
+where you want them).  Read further if you run into snags or want to customize
+the code for your system.
+
+
+TABLE OF CONTENTS
+-----------------
+
+Before you start
+Configuring the software:
+	using the automatic "configure" script
+	using one of the supplied jconfig and makefile files
+	by hand
+Building the software
+Testing the software
+Installing the software
+Optional stuff
+Optimization
+Hints for specific systems
+
+
+BEFORE YOU START
+================
+
+Before installing the software you must unpack the distributed source code.
+Since you are reading this file, you have probably already succeeded in this
+task.  However, there is a potential for error if you needed to convert the
+files to the local standard text file format (for example, if you are on
+MS-DOS you may have converted LF end-of-line to CR/LF).  You must apply
+such conversion to all the files EXCEPT those whose names begin with "test".
+The test files contain binary data; if you change them in any way then the
+self-test will give bad results.
+
+Please check the last section of this file to see if there are hints for the
+specific machine or compiler you are using.
+
+
+CONFIGURING THE SOFTWARE
+========================
+
+To configure the IJG code for your system, you need to create two files:
+  * jconfig.h: contains values for system-dependent #define symbols.
+  * Makefile: controls the compilation process.
+(On a non-Unix machine, you may create "project files" or some other
+substitute for a Makefile.  jconfig.h is needed in any environment.)
+
+We provide three different ways to generate these files:
+  * On a Unix system, you can just run the "configure" script.
+  * We provide sample jconfig files and makefiles for popular machines;
+    if your machine matches one of the samples, just copy the right sample
+    files to jconfig.h and Makefile.
+  * If all else fails, read the instructions below and make your own files.
+
+
+Configuring the software using the automatic "configure" script
+---------------------------------------------------------------
+
+If you are on a Unix machine, you can just type
+	./configure
+and let the configure script construct appropriate configuration files.
+If you're using "csh" on an old version of System V, you might need to type
+	sh configure
+instead to prevent csh from trying to execute configure itself.
+Expect configure to run for a few minutes, particularly on slower machines;
+it works by compiling a series of test programs.
+
+Configure was created with GNU Autoconf and it follows the usual conventions
+for GNU configure scripts.  It makes a few assumptions that you may want to
+override.  You can do this by providing optional switches to configure:
+
+* Configure will build both static and shared libraries, if possible.
+If you want to build libjpeg only as a static library, say
+	./configure --disable-shared
+If you want to build libjpeg only as a shared library, say
+	./configure --disable-static
+Configure uses GNU libtool to take care of system-dependent shared library
+building methods.
+
+* Configure will use gcc (GNU C compiler) if it's available, otherwise cc.
+To force a particular compiler to be selected, use the CC option, for example
+	./configure CC='cc'
+The same method can be used to include any unusual compiler switches.
+For example, on HP-UX you probably want to say
+	./configure CC='cc -Aa'
+to get HP's compiler to run in ANSI mode.
+
+* The default CFLAGS setting is "-g" for non-gcc compilers, "-g -O2" for gcc.
+You can override this by saying, for example,
+	./configure CFLAGS='-O2'
+if you want to compile without debugging support.
+
+* Configure will set up the makefile so that "make install" will install files
+into /usr/local/bin, /usr/local/man, etc.  You can specify an installation
+prefix other than "/usr/local" by giving configure the option "--prefix=PATH".
+
+* If you don't have a lot of swap space, you may need to enable the IJG
+software's internal virtual memory mechanism.  To do this, give the option
+"--enable-maxmem=N" where N is the default maxmemory limit in megabytes.
+This is discussed in more detail under "Selecting a memory manager", below.
+You probably don't need to worry about this on reasonably-sized Unix machines,
+unless you plan to process very large images.
+
+Configure has some other features that are useful if you are cross-compiling
+or working in a network of multiple machine types; but if you need those
+features, you probably already know how to use them.
+
+
+Configuring the software using one of the supplied jconfig and makefile files
+-----------------------------------------------------------------------------
+
+If you have one of these systems, you can just use the provided configuration
+files:
+
+Makefile	jconfig file	System and/or compiler
+
+makefile.manx	jconfig.manx	Amiga, Manx Aztec C
+makefile.sas	jconfig.sas	Amiga, SAS C
+makeproj.mac	jconfig.mac	Apple Macintosh, Metrowerks CodeWarrior
+mak*jpeg.st	jconfig.st	Atari ST/STE/TT, Pure C or Turbo C
+makefile.bcc	jconfig.bcc	MS-DOS or OS/2, Borland C
+makefile.dj	jconfig.dj	MS-DOS, DJGPP (Delorie's port of GNU C)
+makefile.mc6	jconfig.mc6	MS-DOS, Microsoft C (16-bit only)
+makefile.wat	jconfig.wat	MS-DOS, OS/2, or Windows NT, Watcom C
+makefile.vc	jconfig.vc	Windows NT/95, MS Visual C++
+make*.vc6	jconfig.vc	Windows NT/95, MS Visual C++ 6
+make*.v10	jconfig.vc	Windows NT/95, MS Visual C++ 2010 (v10)
+makefile.mms	jconfig.vms	Digital VMS, with MMS software
+makefile.vms	jconfig.vms	Digital VMS, without MMS software
+
+Copy the proper jconfig file to jconfig.h and the makefile to Makefile (or
+whatever your system uses as the standard makefile name).  For more info see
+the appropriate system-specific hints section near the end of this file.
+
+
+Configuring the software by hand
+--------------------------------
+
+First, generate a jconfig.h file.  If you are moderately familiar with C,
+the comments in jconfig.txt should be enough information to do this; just
+copy jconfig.txt to jconfig.h and edit it appropriately.  Otherwise, you may
+prefer to use the ckconfig.c program.  You will need to compile and execute
+ckconfig.c by hand --- we hope you know at least enough to do that.
+ckconfig.c may not compile the first try (in fact, the whole idea is for it
+to fail if anything is going to).  If you get compile errors, fix them by
+editing ckconfig.c according to the directions given in ckconfig.c.  Once
+you get it to run, it will write a suitable jconfig.h file, and will also
+print out some advice about which makefile to use.
+
+You may also want to look at the canned jconfig files, if there is one for a
+system similar to yours.
+
+Second, select a makefile and copy it to Makefile (or whatever your system
+uses as the standard makefile name).  The most generic makefiles we provide
+are
+	makefile.ansi:	if your C compiler supports function prototypes
+	makefile.unix:	if not.
+(You have function prototypes if ckconfig.c put "#define HAVE_PROTOTYPES"
+in jconfig.h.)  You may want to start from one of the other makefiles if
+there is one for a system similar to yours.
+
+Look over the selected Makefile and adjust options as needed.  In particular
+you may want to change the CC and CFLAGS definitions.  For instance, if you
+are using GCC, set CC=gcc.  If you had to use any compiler switches to get
+ckconfig.c to work, make sure the same switches are in CFLAGS.
+
+If you are on a system that doesn't use makefiles, you'll need to set up
+project files (or whatever you do use) to compile all the source files and
+link them into executable files cjpeg, djpeg, jpegtran, rdjpgcom, and wrjpgcom.
+See the file lists in any of the makefiles to find out which files go into
+each program.  Note that the provided makefiles all make a "library" file
+libjpeg first, but you don't have to do that if you don't want to; the file
+lists identify which source files are actually needed for compression,
+decompression, or both.  As a last resort, you can make a batch script that
+just compiles everything and links it all together; makefile.vms is an example
+of this (it's for VMS systems that have no make-like utility).
+
+Here are comments about some specific configuration decisions you'll
+need to make:
+
+Command line style
+------------------
+
+These programs can use a Unix-like command line style which supports
+redirection and piping, like this:
+	cjpeg inputfile >outputfile
+	cjpeg outputfile
+	source program | cjpeg >outputfile
+The simpler "two file" command line style is just
+	cjpeg inputfile outputfile
+You may prefer the two-file style, particularly if you don't have pipes.
+
+You MUST use two-file style on any system that doesn't cope well with binary
+data fed through stdin/stdout; this is true for some MS-DOS compilers, for
+example.  If you're not on a Unix system, it's safest to assume you need
+two-file style.  (But if your compiler provides either the Posix-standard
+fdopen() library routine or a Microsoft-compatible setmode() routine, you
+can safely use the Unix command line style, by defining USE_FDOPEN or
+USE_SETMODE respectively.)
+
+To use the two-file style, make jconfig.h say "#define TWO_FILE_COMMANDLINE".
+
+Selecting a memory manager
+--------------------------
+
+The IJG code is capable of working on images that are too big to fit in main
+memory; data is swapped out to temporary files as necessary.  However, the
+code to do this is rather system-dependent.  We provide five different
+memory managers:
+
+* jmemansi.c	This version uses the ANSI-standard library routine tmpfile(),
+		which not all non-ANSI systems have.  On some systems
+		tmpfile() may put the temporary file in a non-optimal
+		location; if you don't like what it does, use jmemname.c.
+
+* jmemname.c	This version creates named temporary files.  For anything
+		except a Unix machine, you'll need to configure the
+		select_file_name() routine appropriately; see the comments
+		near the head of jmemname.c.  If you use this version, define
+		NEED_SIGNAL_CATCHER in jconfig.h to make sure the temp files
+		are removed if the program is aborted.
+
+* jmemnobs.c	(That stands for No Backing Store :-).)  This will compile on
+		almost any system, but it assumes you have enough main memory
+		or virtual memory to hold the biggest images you work with.
+
+* jmemdos.c	This should be used with most 16-bit MS-DOS compilers.
+		See the system-specific notes about MS-DOS for more info.
+		IMPORTANT: if you use this, define USE_MSDOS_MEMMGR in
+		jconfig.h, and include the assembly file jmemdosa.asm in the
+		programs.  The supplied makefiles and jconfig files for
+		16-bit MS-DOS compilers already do both.
+
+* jmemmac.c	Custom version for Apple Macintosh; see the system-specific
+		notes for Macintosh for more info.
+
+To use a particular memory manager, change the SYSDEPMEM variable in your
+makefile to equal the corresponding object file name (for example, jmemansi.o
+or jmemansi.obj for jmemansi.c).
+
+If you have plenty of (real or virtual) main memory, just use jmemnobs.c.
+"Plenty" means about ten bytes for every pixel in the largest images
+you plan to process, so a lot of systems don't meet this criterion.
+If yours doesn't, try jmemansi.c first.  If that doesn't compile, you'll have
+to use jmemname.c; be sure to adjust select_file_name() for local conditions.
+You may also need to change unlink() to remove() in close_backing_store().
+
+Except with jmemnobs.c or jmemmac.c, you need to adjust the DEFAULT_MAX_MEM
+setting to a reasonable value for your system (either by adding a #define for
+DEFAULT_MAX_MEM to jconfig.h, or by adding a -D switch to the Makefile).
+This value limits the amount of data space the program will attempt to
+allocate.  Code and static data space isn't counted, so the actual memory
+needs for cjpeg or djpeg are typically 100 to 150Kb more than the max-memory
+setting.  Larger max-memory settings reduce the amount of I/O needed to
+process a large image, but too large a value can result in "insufficient
+memory" failures.  On most Unix machines (and other systems with virtual
+memory), just set DEFAULT_MAX_MEM to several million and forget it.  At the
+other end of the spectrum, for MS-DOS machines you probably can't go much
+above 300K to 400K.  (On MS-DOS the value refers to conventional memory only.
+Extended/expanded memory is handled separately by jmemdos.c.)
+
+
+BUILDING THE SOFTWARE
+=====================
+
+Now you should be able to compile the software.  Just say "make" (or
+whatever's necessary to start the compilation).  Have a cup of coffee.
+
+Here are some things that could go wrong:
+
+If your compiler complains about undefined structures, you should be able to
+shut it up by putting "#define INCOMPLETE_TYPES_BROKEN" in jconfig.h.
+
+If you have trouble with missing system include files or inclusion of the
+wrong ones, read jinclude.h.  This shouldn't happen if you used configure
+or ckconfig.c to set up jconfig.h.
+
+There are a fair number of routines that do not use all of their parameters;
+some compilers will issue warnings about this, which you can ignore.  There
+are also a few configuration checks that may give "unreachable code" warnings.
+Any other warning deserves investigation.
+
+If you don't have a getenv() library routine, define NO_GETENV.
+
+Also see the system-specific hints, below.
+
+
+TESTING THE SOFTWARE
+====================
+
+As a quick test of functionality we've included a small sample image in
+several forms:
+	testorig.jpg	Starting point for the djpeg tests.
+	testimg.ppm	The output of djpeg testorig.jpg
+	testimg.bmp	The output of djpeg -bmp -colors 256 testorig.jpg
+	testimg.jpg	The output of cjpeg testimg.ppm
+	testprog.jpg	Progressive-mode equivalent of testorig.jpg.
+	testimgp.jpg	The output of cjpeg -progressive -optimize testimg.ppm
+(The first- and second-generation .jpg files aren't identical since the
+default compression parameters are lossy.)  If you can generate duplicates
+of the testimg* files then you probably have working programs.
+
+With most of the makefiles, "make test" will perform the necessary
+comparisons.
+
+If you're using a makefile that doesn't provide the test option, run djpeg
+and cjpeg by hand and compare the output files to testimg* with whatever
+binary file comparison tool you have.  The files should be bit-for-bit
+identical.
+
+If the programs complain "MAX_ALLOC_CHUNK is wrong, please fix", then you
+need to reduce MAX_ALLOC_CHUNK to a value that fits in type size_t.
+Try adding "#define MAX_ALLOC_CHUNK 65520L" to jconfig.h.  A less likely
+configuration error is "ALIGN_TYPE is wrong, please fix": defining ALIGN_TYPE
+as long should take care of that one.
+
+If the cjpeg test run fails with "Missing Huffman code table entry", it's a
+good bet that you needed to define RIGHT_SHIFT_IS_UNSIGNED.  Go back to the
+configuration step and run ckconfig.c.  (This is a good plan for any other
+test failure, too.)
+
+If you are using Unix (one-file) command line style on a non-Unix system,
+it's a good idea to check that binary I/O through stdin/stdout actually
+works.  You should get the same results from "djpeg out.ppm"
+as from "djpeg -outfile out.ppm testorig.jpg".  Note that the makefiles all
+use the latter style and therefore do not exercise stdin/stdout!  If this
+check fails, try recompiling with USE_SETMODE or USE_FDOPEN defined.
+If it still doesn't work, better use two-file style.
+
+If you chose a memory manager other than jmemnobs.c, you should test that
+temporary-file usage works.  Try "djpeg -bmp -colors 256 -max 0 testorig.jpg"
+and make sure its output matches testimg.bmp.  If you have any really large
+images handy, try compressing them with -optimize and/or decompressing with
+-colors 256 to make sure your DEFAULT_MAX_MEM setting is not too large.
+
+NOTE: this is far from an exhaustive test of the JPEG software; some modules,
+such as 1-pass color quantization, are not exercised at all.  It's just a
+quick test to give you some confidence that you haven't missed something
+major.
+
+
+INSTALLING THE SOFTWARE
+=======================
+
+Once you're done with the above steps, you can install the software by
+copying the executable files (cjpeg, djpeg, jpegtran, rdjpgcom, and wrjpgcom)
+to wherever you normally install programs.  On Unix systems, you'll also want
+to put the man pages (cjpeg.1, djpeg.1, jpegtran.1, rdjpgcom.1, wrjpgcom.1)
+in the man-page directory.  The pre-fab makefiles don't support this step
+since there's such a wide variety of installation procedures on different
+systems.
+
+If you generated a Makefile with the "configure" script, you can just say
+	make install
+to install the programs and their man pages into the standard places.
+(You'll probably need to be root to do this.)  We recommend first saying
+	make -n install
+to see where configure thought the files should go.  You may need to edit
+the Makefile, particularly if your system's conventions for man page
+filenames don't match what configure expects.
+
+If you want to install the IJG library itself, for use in compiling other
+programs besides ours, then you need to put the four include files
+	jpeglib.h jerror.h jconfig.h jmorecfg.h
+into your include-file directory, and put the library file libjpeg.a
+(extension may vary depending on system) wherever library files go.
+If you generated a Makefile with "configure", it will do what it thinks
+is the right thing if you say
+	make install-lib
+
+
+OPTIONAL STUFF
+==============
+
+Progress monitor:
+
+If you like, you can #define PROGRESS_REPORT (in jconfig.h) to enable display
+of percent-done progress reports.  The routine provided in cdjpeg.c merely
+prints percentages to stderr, but you can customize it to do something
+fancier.
+
+Utah RLE file format support:
+
+We distribute the software with support for RLE image files (Utah Raster
+Toolkit format) disabled, because the RLE support won't compile without the
+Utah library.  If you have URT version 3.1 or later, you can enable RLE
+support as follows:
+	1.  #define RLE_SUPPORTED in jconfig.h.
+	2.  Add a -I option to CFLAGS in the Makefile for the directory
+	    containing the URT .h files (typically the "include"
+	    subdirectory of the URT distribution).
+	3.  Add -L... -lrle to LDLIBS in the Makefile, where ... specifies
+	    the directory containing the URT "librle.a" file (typically the
+	    "lib" subdirectory of the URT distribution).
+
+Support for 9-bit to 12-bit deep pixel data:
+
+The IJG code currently allows 8, 9, 10, 11, or 12 bits sample data precision.
+(For color, this means 8 to 12 bits per channel, of course.)  If you need to
+work with deeper than 8-bit data, you can compile the IJG code for 9-bit to
+12-bit operation.
+To do so:
+  1. In jmorecfg.h, define BITS_IN_JSAMPLE as 9, 10, 11, or 12 rather than 8.
+  2. In jconfig.h, undefine BMP_SUPPORTED, RLE_SUPPORTED, and TARGA_SUPPORTED,
+     because the code for those formats doesn't handle deeper than 8-bit data
+     and won't even compile.  (The PPM code does work, as explained below.
+     The GIF code works too; it scales 8-bit GIF data to and from 12-bit
+     depth automatically.)
+  3. Compile.  Don't expect "make test" to pass, since the supplied test
+     files are for 8-bit data.
+
+Currently, 9-bit to 12-bit support does not work on 16-bit-int machines.
+
+Run-time selection and conversion of data precision are currently not
+supported and may be added later.
+Exception:  The transcoding part (jpegtran) supports all settings in a
+single instance, since it operates on the level of DCT coefficients and
+not sample values.
+
+The PPM reader (rdppm.c) can read deeper than 8-bit data from either
+text-format or binary-format PPM and PGM files.  Binary-format PPM/PGM files
+which have a maxval greater than 255 are assumed to use 2 bytes per sample,
+MSB first (big-endian order).  As of early 1995, 2-byte binary format is not
+officially supported by the PBMPLUS library, but it is expected that a
+future release of PBMPLUS will support it.  Note that the PPM reader will
+read files of any maxval regardless of the BITS_IN_JSAMPLE setting; incoming
+data is automatically rescaled to maxval=MAXJSAMPLE as appropriate for the
+cjpeg bit depth.
+
+The PPM writer (wrppm.c) will normally write 2-byte binary PPM or PGM
+format, maxval=MAXJSAMPLE, when compiled with BITS_IN_JSAMPLE>8.  Since this
+format is not yet widely supported, you can disable it by compiling wrppm.c
+with PPM_NORAWWORD defined; then the data is scaled down to 8 bits to make a
+standard 1-byte/sample PPM or PGM file.  (Yes, this means still another copy
+of djpeg to keep around.  But hopefully you won't need it for very long.
+Poskanzer's supposed to get that new PBMPLUS release out Real Soon Now.)
+
+Of course, if you are working with 9-bit to 12-bit data, you probably have
+it stored in some other, nonstandard format.  In that case you'll probably
+want to write your own I/O modules to read and write your format.
+
+Note:
+The standard Huffman tables are only valid for 8-bit data precision.  If
+you selected more than 8-bit data precision, cjpeg uses arithmetic coding
+by default.  The Huffman encoder normally uses entropy optimization to
+compute usable tables for higher precision.  Otherwise, you'll have to
+supply different default Huffman tables.
+
+Removing code:
+
+If you need to make a smaller version of the JPEG software, some optional
+functions can be removed at compile time.  See the xxx_SUPPORTED #defines in
+jconfig.h and jmorecfg.h.  If at all possible, we recommend that you leave in
+decoder support for all valid JPEG files, to ensure that you can read anyone's
+output.  Taking out support for image file formats that you don't use is the
+most painless way to make the programs smaller.  Another possibility is to
+remove some of the DCT methods: in particular, the "IFAST" method may not be
+enough faster than the others to be worth keeping on your machine.  (If you
+do remove ISLOW or IFAST, be sure to redefine JDCT_DEFAULT or JDCT_FASTEST
+to a supported method, by adding a #define in jconfig.h.)
+
+
+OPTIMIZATION
+============
+
+Unless you own a Cray, you'll probably be interested in making the JPEG
+software go as fast as possible.  This section covers some machine-dependent
+optimizations you may want to try.  We suggest that before trying any of
+this, you first get the basic installation to pass the self-test step.
+Repeat the self-test after any optimization to make sure that you haven't
+broken anything.
+
+The integer DCT routines perform a lot of multiplications.  These
+multiplications must yield 32-bit results, but none of their input values
+are more than 16 bits wide.  On many machines, notably the 680x0 and 80x86
+CPUs, a 16x16=>32 bit multiply instruction is faster than a full 32x32=>32
+bit multiply.  Unfortunately there is no portable way to specify such a
+multiplication in C, but some compilers can generate one when you use the
+right combination of casts.  See the MULTIPLYxxx macro definitions in
+jdct.h.  If your compiler makes "int" be 32 bits and "short" be 16 bits,
+defining SHORTxSHORT_32 is fairly likely to work.  When experimenting with
+alternate definitions, be sure to test not only whether the code still works
+(use the self-test), but also whether it is actually faster --- on some
+compilers, alternate definitions may compute the right answer, yet be slower
+than the default.  Timing cjpeg on a large PGM (grayscale) input file is the
+best way to check this, as the DCT will be the largest fraction of the runtime
+in that mode.  (Note: some of the distributed compiler-specific jconfig files
+already contain #define switches to select appropriate MULTIPLYxxx
+definitions.)
+
+If your machine has sufficiently fast floating point hardware, you may find
+that the float DCT method is faster than the integer DCT methods, even
+after tweaking the integer multiply macros.  In that case you may want to
+make the float DCT be the default method.  (The only objection to this is
+that float DCT results may vary slightly across machines.)  To do that, add
+"#define JDCT_DEFAULT JDCT_FLOAT" to jconfig.h.  Even if you don't change
+the default, you should redefine JDCT_FASTEST, which is the method selected
+by djpeg's -fast switch.  Don't forget to update the documentation files
+(usage.txt and/or cjpeg.1, djpeg.1) to agree with what you've done.
+
+If access to "short" arrays is slow on your machine, it may be a win to
+define type JCOEF as int rather than short.  This will cost a good deal of
+memory though, particularly in some multi-pass modes, so don't do it unless
+you have memory to burn and short is REALLY slow.
+
+If your compiler can compile function calls in-line, make sure the INLINE
+macro in jmorecfg.h is defined as the keyword that marks a function
+inline-able.  Some compilers have a switch that tells the compiler to inline
+any function it thinks is profitable (e.g., -finline-functions for gcc).
+Enabling such a switch is likely to make the compiled code bigger but faster.
+
+In general, it's worth trying the maximum optimization level of your compiler,
+and experimenting with any optional optimizations such as loop unrolling.
+(Unfortunately, far too many compilers have optimizer bugs ... be prepared to
+back off if the code fails self-test.)  If you do any experimentation along
+these lines, please report the optimal settings to jpeg-info@jpegclub.org so
+we can mention them in future releases.  Be sure to specify your machine and
+compiler version.
+
+
+HINTS FOR SPECIFIC SYSTEMS
+==========================
+
+We welcome reports on changes needed for systems not mentioned here.  Submit
+'em to jpeg-info@jpegclub.org.  Also, if configure or ckconfig.c is wrong
+about how to configure the JPEG software for your system, please let us know.
+
+
+Acorn RISC OS:
+
+(Thanks to Simon Middleton for these hints on compiling with Desktop C.)
+After renaming the files according to Acorn conventions, take a copy of
+makefile.ansi, change all occurrences of 'libjpeg.a' to 'libjpeg.o' and
+change these definitions as indicated:
+
+CFLAGS= -throwback -IC: -Wn
+LDLIBS=C:o.Stubs
+SYSDEPMEM=jmemansi.o
+LN=Link
+AR=LibFile -c -o
+
+Also add a new line '.c.o:; $(cc) $< $(cflags) -c -o $@'.  Remove the
+lines '$(RM) libjpeg.o' and '$(AR2) libjpeg.o' and the 'jconfig.h'
+dependency section.
+
+Copy jconfig.txt to jconfig.h.  Edit jconfig.h to define TWO_FILE_COMMANDLINE
+and CHAR_IS_UNSIGNED.
+
+Run the makefile using !AMU not !Make.  If you want to use the 'clean' and
+'test' makefile entries then you will have to fiddle with the syntax a bit
+and rename the test files.
+
+
+Amiga:
+
+SAS C 6.50 reportedly is too buggy to compile the IJG code properly.
+A patch to update to 6.51 is available from SAS or AmiNet FTP sites.
+
+The supplied config files are set up to use jmemname.c as the memory
+manager, with temporary files being created on the device named by
+"JPEGTMP:".
+
+
+Atari ST/STE/TT:
+
+Copy the project files makcjpeg.st, makdjpeg.st, maktjpeg.st, and makljpeg.st
+to cjpeg.prj, djpeg.prj, jpegtran.prj, and libjpeg.prj respectively.  The
+project files should work as-is with Pure C.  For Turbo C, change library
+filenames "pc..." to "tc..." in each project file.  Note that libjpeg.prj
+selects jmemansi.c as the recommended memory manager.  You'll probably want to
+adjust the DEFAULT_MAX_MEM setting --- you want it to be a couple hundred K
+less than your normal free memory.  Put "#define DEFAULT_MAX_MEM nnnn" into
+jconfig.h to do this.
+
+To use the 68881/68882 coprocessor for the floating point DCT, add the
+compiler option "-8" to the project files and replace pcfltlib.lib with
+pc881lib.lib in cjpeg.prj and djpeg.prj.  Or if you don't have a
+coprocessor, you may prefer to remove the float DCT code by undefining
+DCT_FLOAT_SUPPORTED in jmorecfg.h (since without a coprocessor, the float
+code will be too slow to be useful).  In that case, you can delete
+pcfltlib.lib from the project files.
+
+Note that you must make libjpeg.lib before making cjpeg.ttp, djpeg.ttp,
+or jpegtran.ttp.  You'll have to perform the self-test by hand.
+
+We haven't bothered to include project files for rdjpgcom and wrjpgcom.
+Those source files should just be compiled by themselves; they don't
+depend on the JPEG library.  You can use the default.prj project file
+of the Pure C distribution to make the programs.
+
+There is a bug in some older versions of the Turbo C library which causes the
+space used by temporary files created with "tmpfile()" not to be freed after
+an abnormal program exit.  If you check your disk afterwards, you will find
+cluster chains that are allocated but not used by a file.  This should not
+happen in cjpeg/djpeg/jpegtran, since we enable a signal catcher to explicitly
+close temp files before exiting.  But if you use the JPEG library with your
+own code, be sure to supply a signal catcher, or else use a different
+system-dependent memory manager.
+
+
+Cray:
+
+Should you be so fortunate as to be running JPEG on a Cray YMP, there is a
+compiler bug in old versions of Cray's Standard C (prior to 3.1).  If you
+still have an old compiler, you'll need to insert a line reading
+"#pragma novector" just before the loop	
+    for (i = 1; i <= (int) htbl->bits[l]; i++)
+      huffsize[p++] = (char) l;
+in fix_huff_tbl (in V5beta1, line 204 of jchuff.c and line 176 of jdhuff.c).
+[This bug may or may not still occur with the current IJG code, but it's
+probably a dead issue anyway...]
+
+
+HP-UX:
+
+If you have HP-UX 7.05 or later with the "software development" C compiler,
+you should run the compiler in ANSI mode.  If using the configure script,
+say
+	./configure CC='cc -Aa'
+(or -Ae if you prefer).  If configuring by hand, use makefile.ansi and add
+"-Aa" to the CFLAGS line in the makefile.
+
+If you have a pre-7.05 system, or if you are using the non-ANSI C compiler
+delivered with a minimum HP-UX system, then you must use makefile.unix
+(and do NOT add -Aa); or just run configure without the CC option.
+
+On HP 9000 series 800 machines, the HP C compiler is buggy in revisions prior
+to A.08.07.  If you get complaints about "not a typedef name", you'll have to
+use makefile.unix, or run configure without the CC option.
+
+
+Macintosh, generic comments:
+
+The supplied user-interface files (cjpeg.c, djpeg.c, etc) are set up to
+provide a Unix-style command line interface.  You can use this interface on
+the Mac by means of the ccommand() library routine provided by Metrowerks
+CodeWarrior or Think C.  This is only appropriate for testing the library,
+however; to make a user-friendly equivalent of cjpeg/djpeg you'd really want
+to develop a Mac-style user interface.  There isn't a complete example
+available at the moment, but there are some helpful starting points:
+1. Sam Bushell's free "To JPEG" applet provides drag-and-drop conversion to
+JPEG under System 7 and later.  This only illustrates how to use the
+compression half of the library, but it does a very nice job of that part.
+The CodeWarrior source code is available from http://www.pobox.com/~jsam.
+2. Jim Brunner prepared a Mac-style user interface for both compression and
+decompression.  Unfortunately, it hasn't been updated since IJG v4, and
+the library's API has changed considerably since then.  Still it may be of
+some help, particularly as a guide to compiling the IJG code under Think C.
+Jim's code is available from the Info-Mac archives, at sumex-aim.stanford.edu
+or mirrors thereof; see file /info-mac/dev/src/jpeg-convert-c.hqx.
+
+jmemmac.c is the recommended memory manager back end for Macintosh.  It uses
+NewPtr/DisposePtr instead of malloc/free, and has a Mac-specific
+implementation of jpeg_mem_available().  It also creates temporary files that
+follow Mac conventions.  (That part of the code relies on System-7-or-later OS
+functions.  See the comments in jmemmac.c if you need to run it on System 6.)
+NOTE that USE_MAC_MEMMGR must be defined in jconfig.h to use jmemmac.c.
+
+You can also use jmemnobs.c, if you don't care about handling images larger
+than available memory.  If you use any memory manager back end other than
+jmemmac.c, we recommend replacing "malloc" and "free" by "NewPtr" and
+"DisposePtr", because Mac C libraries often have peculiar implementations of
+malloc/free.  (For instance, free() may not return the freed space to the
+Mac Memory Manager.  This is undesirable for the IJG code because jmemmgr.c
+already clumps space requests.)
+
+
+Macintosh, Metrowerks CodeWarrior:
+
+The Unix-command-line-style interface can be used by defining USE_CCOMMAND.
+You'll also need to define TWO_FILE_COMMANDLINE to avoid stdin/stdout.
+This means that when using the cjpeg/djpeg programs, you'll have to type the
+input and output file names in the "Arguments" text-edit box, rather than
+using the file radio buttons.  (Perhaps USE_FDOPEN or USE_SETMODE would
+eliminate the problem, but I haven't heard from anyone who's tried it.)
+
+On 680x0 Macs, Metrowerks defines type "double" as a 10-byte IEEE extended
+float.  jmemmgr.c won't like this: it wants sizeof(ALIGN_TYPE) to be a power
+of 2.  Add "#define ALIGN_TYPE long" to jconfig.h to eliminate the complaint.
+
+The supplied configuration file jconfig.mac can be used for your jconfig.h;
+it includes all the recommended symbol definitions.  If you have AppleScript
+installed, you can run the supplied script makeproj.mac to create CodeWarrior
+project files for the library and the testbed applications, then build the
+library and applications.  (Thanks to Dan Sears and Don Agro for this nifty
+hack, which saves us from trying to maintain CodeWarrior project files as part
+of the IJG distribution...)
+
+
+Macintosh, Think C:
+
+The documentation in Jim Brunner's "JPEG Convert" source code (see above)
+includes detailed build instructions for Think C; it's probably somewhat
+out of date for the current release, but may be helpful.
+
+If you want to build the minimal command line version, proceed as follows.
+You'll have to prepare project files for the programs; we don't include any
+in the distribution since they are not text files.  Use the file lists in
+any of the supplied makefiles as a guide.  Also add the ANSI and Unix C
+libraries in a separate segment.  You may need to divide the JPEG files into
+more than one segment; we recommend dividing compression and decompression
+modules.  Define USE_CCOMMAND in jconfig.h so that the ccommand() routine is
+called.  You must also define TWO_FILE_COMMANDLINE because stdin/stdout
+don't handle binary data correctly.
+
+On 680x0 Macs, Think C defines type "double" as a 12-byte IEEE extended float.
+jmemmgr.c won't like this: it wants sizeof(ALIGN_TYPE) to be a power of 2.
+Add "#define ALIGN_TYPE long" to jconfig.h to eliminate the complaint.
+
+jconfig.mac should work as a jconfig.h configuration file for Think C,
+but the makeproj.mac AppleScript script is specific to CodeWarrior.  Sorry.
+
+
+MIPS R3000:
+
+MIPS's cc version 1.31 has a rather nasty optimization bug.  Don't use -O
+if you have that compiler version.  (Use "cc -V" to check the version.)
+Note that the R3000 chip is found in workstations from DEC and others.
+
+
+MS-DOS, generic comments for 16-bit compilers:
+
+The IJG code is designed to work well in 80x86 "small" or "medium" memory
+models (i.e., data pointers are 16 bits unless explicitly declared "far";
+code pointers can be either size).  You may be able to use small model to
+compile cjpeg or djpeg by itself, but you will probably have to use medium
+model for any larger application.  This won't make much difference in
+performance.  You *will* take a noticeable performance hit if you use a
+large-data memory model, and you should avoid "huge" model if at all
+possible.  Be sure that NEED_FAR_POINTERS is defined in jconfig.h if you use
+a small-data memory model; be sure it is NOT defined if you use a large-data
+model.  (The supplied makefiles and jconfig files for Borland and Microsoft C
+compile in medium model and define NEED_FAR_POINTERS.)
+
+The DOS-specific memory manager, jmemdos.c, should be used if possible.
+It needs some assembly-code routines which are in jmemdosa.asm; make sure
+your makefile assembles that file and includes it in the library.  If you
+don't have a suitable assembler, you can get pre-assembled object files for
+jmemdosa by FTP from ftp.uu.net:/graphics/jpeg/jdosaobj.zip.  (DOS-oriented
+distributions of the IJG source code often include these object files.)
+
+When using jmemdos.c, jconfig.h must define USE_MSDOS_MEMMGR and must set
+MAX_ALLOC_CHUNK to less than 64K (65520L is a typical value).  If your
+C library's far-heap malloc() can't allocate blocks that large, reduce
+MAX_ALLOC_CHUNK to whatever it can handle.
+
+If you can't use jmemdos.c for some reason --- for example, because you
+don't have an assembler to assemble jmemdosa.asm --- you'll have to fall
+back to jmemansi.c or jmemname.c.  You'll probably still need to set
+MAX_ALLOC_CHUNK in jconfig.h, because most DOS C libraries won't malloc()
+more than 64K at a time.  IMPORTANT: if you use jmemansi.c or jmemname.c,
+you will have to compile in a large-data memory model in order to get the
+right stdio library.  Too bad.
+
+wrjpgcom needs to be compiled in large model, because it malloc()s a 64KB
+work area to hold the comment text.  If your C library's malloc can't
+handle that, reduce MAX_COM_LENGTH as necessary in wrjpgcom.c.
+
+Most MS-DOS compilers treat stdin/stdout as text files, so you must use
+two-file command line style.  But if your compiler has either fdopen() or
+setmode(), you can use one-file style if you like.  To do this, define
+USE_SETMODE or USE_FDOPEN so that stdin/stdout will be set to binary mode.
+(USE_SETMODE seems to work with more DOS compilers than USE_FDOPEN.)  You
+should test that I/O through stdin/stdout produces the same results as I/O
+to explicitly named files... the "make test" procedures in the supplied
+makefiles do NOT use stdin/stdout.
+
+
+MS-DOS, generic comments for 32-bit compilers:
+
+None of the above comments about memory models apply if you are using a
+32-bit flat-memory-space environment, such as DJGPP or Watcom C.  (And you
+should use one if you have it, as performance will be much better than
+8086-compatible code!)  For flat-memory-space compilers, do NOT define
+NEED_FAR_POINTERS, and do NOT use jmemdos.c.  Use jmemnobs.c if the
+environment supplies adequate virtual memory, otherwise use jmemansi.c or
+jmemname.c.
+
+You'll still need to be careful about binary I/O through stdin/stdout.
+See the last paragraph of the previous section.
+
+
+MS-DOS, Borland C:
+
+Be sure to convert all the source files to DOS text format (CR/LF newlines).
+Although Borland C will often work OK with unmodified Unix (LF newlines)
+source files, sometimes it will give bogus compile errors.
+"Illegal character '#'" is the most common such error.  (This is true with
+Borland C 3.1, but perhaps is fixed in newer releases.)
+
+If you want one-file command line style, just undefine TWO_FILE_COMMANDLINE.
+jconfig.bcc already includes #define USE_SETMODE to make this work.
+(fdopen does not work correctly.)
+
+
+MS-DOS, Microsoft C:
+
+makefile.mc6 works with Microsoft C, DOS Visual C++, etc.  It should only
+be used if you want to build a 16-bit (small or medium memory model) program.
+
+If you want one-file command line style, just undefine TWO_FILE_COMMANDLINE.
+jconfig.mc6 already includes #define USE_SETMODE to make this work.
+(fdopen does not work correctly.)
+
+Note that this makefile assumes that the working copy of itself is called
+"makefile".  If you want to call it something else, say "makefile.mak",
+be sure to adjust the dependency line that reads "$(RFILE) : makefile".
+Otherwise the make will fail because it doesn't know how to create "makefile".
+Worse, some releases of Microsoft's make utilities give an incorrect error
+message in this situation.
+
+Old versions of MS C fail with an "out of macro expansion space" error
+because they can't cope with the macro TRACEMS8 (defined in jerror.h).
+If this happens to you, the easiest solution is to change TRACEMS8 to
+expand to nothing.  You'll lose the ability to dump out JPEG coefficient
+tables with djpeg -debug -debug, but at least you can compile.
+
+Original MS C 6.0 is very buggy; it compiles incorrect code unless you turn
+off optimization entirely (remove -O from CFLAGS).  6.00A is better, but it
+still generates bad code if you enable loop optimizations (-Ol or -Ox).
+
+MS C 8.0 crashes when compiling jquant1.c with optimization switch /Oo ...
+which is on by default.  To work around this bug, compile that one file
+with /Oo-.
+
+
+Microsoft Windows (all versions), generic comments:
+
+Some Windows system include files define typedef boolean as "unsigned char".
+The IJG code also defines typedef boolean, but we make it an "enum" by default.
+This doesn't affect the IJG programs because we don't import those Windows
+include files.  But if you use the JPEG library in your own program, and some
+of your program's files import one definition of boolean while some import the
+other, you can get all sorts of mysterious problems.  A good preventive step
+is to make the IJG library use "unsigned char" for boolean.  To do that,
+add something like this to your jconfig.h file:
+	/* Define "boolean" as unsigned char, not enum, per Windows custom */
+	#ifndef __RPCNDR_H__	/* don't conflict if rpcndr.h already read */
+	typedef unsigned char boolean;
+	#endif
+	#ifndef FALSE		/* in case these macros already exist */
+	#define FALSE	0	/* values of boolean */
+	#endif
+	#ifndef TRUE
+	#define TRUE	1
+	#endif
+	#define HAVE_BOOLEAN	/* prevent jmorecfg.h from redefining it */
+(This is already in jconfig.vc, by the way.)
+
+windef.h contains the declarations
+	#define far
+	#define FAR far
+Since jmorecfg.h tries to define FAR as empty, you may get a compiler
+warning if you include both jpeglib.h and windef.h (which windows.h
+includes).  To suppress the warning, you can put "#ifndef FAR"/"#endif"
+around the line "#define FAR" in jmorecfg.h.
+(Something like this is already in jmorecfg.h, by the way.)
+
+When using the library in a Windows application, you will almost certainly
+want to modify or replace the error handler module jerror.c, since our
+default error handler does a couple of inappropriate things:
+  1. it tries to write error and warning messages on stderr;
+  2. in event of a fatal error, it exits by calling exit().
+
+A simple stopgap solution for problem 1 is to replace the line
+	fprintf(stderr, "%s\n", buffer);
+(in output_message in jerror.c) with
+	MessageBox(GetActiveWindow(),buffer,"JPEG Error",MB_OK|MB_ICONERROR);
+It's highly recommended that you at least do that much, since otherwise
+error messages will disappear into nowhere.  (Beginning with IJG v6b, this
+code is already present in jerror.c; just define USE_WINDOWS_MESSAGEBOX in
+jconfig.h to enable it.)
+
+The proper solution for problem 2 is to return control to your calling
+application after a library error.  This can be done with the setjmp/longjmp
+technique discussed in libjpeg.txt and illustrated in example.c.  (NOTE:
+some older Windows C compilers provide versions of setjmp/longjmp that
+don't actually work under Windows.  You may need to use the Windows system
+functions Catch and Throw instead.)
+
+The recommended memory manager under Windows is jmemnobs.c; in other words,
+let Windows do any virtual memory management needed.  You should NOT use
+jmemdos.c nor jmemdosa.asm under Windows.
+
+For Windows 3.1, we recommend compiling in medium or large memory model;
+for newer Windows versions, use a 32-bit flat memory model.  (See the MS-DOS
+sections above for more info about memory models.)  In the 16-bit memory
+models only, you'll need to put
+	#define MAX_ALLOC_CHUNK 65520L	/* Maximum request to malloc() */
+into jconfig.h to limit allocation chunks to 64Kb.  (Without that, you'd
+have to use huge memory model, which slows things down unnecessarily.)
+jmemnobs.c works without modification in large or flat memory models, but to
+use medium model, you need to modify its jpeg_get_large and jpeg_free_large
+routines to allocate far memory.  In any case, you might like to replace
+its calls to malloc and free with direct calls on Windows memory allocation
+functions.
+
+You may also want to modify jdatasrc.c and jdatadst.c to use Windows file
+operations rather than fread/fwrite.  This is only necessary if your C
+compiler doesn't provide a competent implementation of C stdio functions.
+
+You might want to tweak the RGB_xxx macros in jmorecfg.h so that the library
+will accept or deliver color pixels in BGR sample order, not RGB; BGR order
+is usually more convenient under Windows.  Note that this change will break
+the sample applications cjpeg/djpeg, but the library itself works fine.
+
+
+Many people want to convert the IJG library into a DLL.  This is reasonably
+straightforward, but watch out for the following:
+
+  1. Don't try to compile as a DLL in small or medium memory model; use
+large model, or even better, 32-bit flat model.  Many places in the IJG code
+assume the address of a local variable is an ordinary (not FAR) pointer;
+that isn't true in a medium-model DLL.
+
+  2. Microsoft C cannot pass file pointers between applications and DLLs.
+(See Microsoft Knowledge Base, PSS ID Number Q50336.)  So jdatasrc.c and
+jdatadst.c don't work if you open a file in your application and then pass
+the pointer to the DLL.  One workaround is to make jdatasrc.c/jdatadst.c
+part of your main application rather than part of the DLL.
+
+  3. You'll probably need to modify the macros GLOBAL() and EXTERN() to
+attach suitable linkage keywords to the exported routine names.  Similarly,
+you'll want to modify METHODDEF() and JMETHOD() to ensure function pointers
+are declared in a way that lets application routines be called back through
+the function pointers.  These macros are in jmorecfg.h.  Typical definitions
+for a 16-bit DLL are:
+	#define GLOBAL(type)		type _far _pascal _loadds _export
+	#define EXTERN(type)		extern type _far _pascal _loadds
+	#define METHODDEF(type)		static type _far _pascal
+	#define JMETHOD(type,methodname,arglist)  \
+		type (_far _pascal *methodname) arglist
+For a 32-bit DLL you may want something like
+	#define GLOBAL(type)		__declspec(dllexport) type
+	#define EXTERN(type)		extern __declspec(dllexport) type
+Although not all the GLOBAL routines are actually intended to be called by
+the application, the performance cost of making them all DLL entry points is
+negligible.
+
+The unmodified IJG library presents a very C-specific application interface,
+so the resulting DLL is only usable from C or C++ applications.  There has
+been some talk of writing wrapper code that would present a simpler interface
+usable from other languages, such as Visual Basic.  This is on our to-do list
+but hasn't been very high priority --- any volunteers out there?
+
+
+Microsoft Windows, Borland C:
+
+The provided jconfig.bcc should work OK in a 32-bit Windows environment,
+but you'll need to tweak it in a 16-bit environment (you'd need to define
+NEED_FAR_POINTERS and MAX_ALLOC_CHUNK).  Beware that makefile.bcc will need
+alteration if you want to use it for Windows --- in particular, you should
+use jmemnobs.c not jmemdos.c under Windows.
+
+Borland C++ 4.5 fails with an internal compiler error when trying to compile
+jdmerge.c in 32-bit mode.  If enough people complain, perhaps Borland will fix
+it.  In the meantime, the simplest known workaround is to add a redundant
+definition of the variable range_limit in h2v1_merged_upsample(), at the head
+of the block that handles odd image width (about line 268 in v6 jdmerge.c):
+  /* If image width is odd, do the last output column separately */
+  if (cinfo->output_width & 1) {
+    register JSAMPLE * range_limit = cinfo->sample_range_limit; /* ADD THIS */
+    cb = GETJSAMPLE(*inptr1);
+Pretty bizarre, especially since the very similar routine h2v2_merged_upsample
+doesn't trigger the bug.
+Recent reports suggest that this bug does not occur with "bcc32a" (the
+Pentium-optimized version of the compiler).
+
+Another report from a user of Borland C 4.5 was that incorrect code (leading
+to a color shift in processed images) was produced if any of the following
+optimization switch combinations were used: 
+	-Ot -Og
+	-Ot -Op
+	-Ot -Om
+So try backing off on optimization if you see such a problem.  (Are there
+several different releases all numbered "4.5"??)
+
+
+Microsoft Windows, Microsoft Visual C++:
+
+jconfig.vc should work OK with any Microsoft compiler for a 32-bit memory
+model.  makefile.vc is intended for command-line use.  (If you are using
+the Developer Studio environment, you may prefer the DevStudio project
+files; see below.)
+
+IJG JPEG 7 adds extern "C" to jpeglib.h.  This avoids the need to put
+extern "C" { ... } around #include "jpeglib.h" in your C++ application.
+You can also force VC++ to treat the library as C++ code by renaming
+all the *.c files to *.cpp (and adjusting the makefile to match).
+In this case you also need to define the symbol DONT_USE_EXTERN_C in
+the configuration to prevent jpeglib.h from using extern "C".
+
+
+Microsoft Windows, Microsoft Visual C++ 6 Developer Studio:
+
+We include makefiles that should work as project files in DevStudio 6.0 or
+later.  There is a library makefile that builds the IJG library as a static
+Win32 library, and application makefiles that build the sample applications
+as Win32 console applications.  (Even if you only want the library, we
+recommend building the applications so that you can run the self-test.)
+
+To use:
+1. Open the command prompt, change to the main directory and execute the
+   command line
+	NMAKE /f makefile.vc  setup-vc6
+   This will move jconfig.vc to jconfig.h and makefiles to project files.
+   (Note that the renaming is critical!)
+2. Open the workspace file jpeg.dsw, build the library project.
+   (If you are using DevStudio more recent than 6.0, you'll probably
+   get a message saying that the project files are being updated.)
+3. Open the workspace file apps.dsw, build the application projects.
+4. To perform the self-test, execute the command line
+	NMAKE /f makefile.vc  test-build
+5. Move the application .exe files from `app`\Release to an
+   appropriate location on your path.
+
+
+Microsoft Windows, Microsoft Visual C++ 2010 Developer Studio (v10):
+
+We include makefiles that should work as project files in Visual Studio
+2010 or later.  There is a library makefile that builds the IJG library
+as a static Win32 library, and application makefiles that build the sample
+applications as Win32 console applications.  (Even if you only want the
+library, we recommend building the applications so that you can run the
+self-test.)
+
+To use:
+1. Open the command prompt, change to the main directory and execute the
+   command line
+	NMAKE /f makefile.vc  setup-v10
+   This will move jconfig.vc to jconfig.h and makefiles to project files.
+   (Note that the renaming is critical!)
+2. Open the solution file jpeg.sln, build the library project.
+   (If you are using Visual Studio more recent than 2010 (v10), you'll
+   probably get a message saying that the project files are being updated.)
+3. Open the solution file apps.sln, build the application projects.
+4. To perform the self-test, execute the command line
+	NMAKE /f makefile.vc  test-build
+5. Move the application .exe files from `app`\Release to an
+   appropriate location on your path.
+
+Note:
+There seems to be an optimization bug in the compiler which causes the
+self-test to fail with the color quantization option.
+We have disabled optimization for the file jquant2.c in the library
+project file which causes the self-test to pass properly.
+
+
+OS/2, Borland C++:
+
+Watch out for optimization bugs in older Borland compilers; you may need
+to back off the optimization switch settings.  See the comments in
+makefile.bcc.
+
+
+SGI:
+
+On some SGI systems, you may need to set "AR2= ar -ts" in the Makefile.
+If you are using configure, you can do this by saying
+	./configure RANLIB='ar -ts'
+This change is not needed on all SGIs.  Use it only if the make fails at the
+stage of linking the completed programs.
+
+On the MIPS R4000 architecture (Indy, etc.), the compiler option "-mips2"
+reportedly speeds up the float DCT method substantially, enough to make it
+faster than the default int method (but still slower than the fast int
+method).  If you use -mips2, you may want to alter the default DCT method to
+be float.  To do this, put "#define JDCT_DEFAULT JDCT_FLOAT" in jconfig.h.
+
+
+VMS:
+
+On an Alpha/VMS system with MMS, be sure to use the "/Marco=Alpha=1"
+qualifier with MMS when building the JPEG package.
+
+VAX/VMS v5.5-1 may have problems with the test step of the build procedure
+reporting differences when it compares the original and test images.  If the
+error points to the last block of the files, it is most likely bogus and may
+be safely ignored.  It seems to be because the files are Stream_LF and
+Backup/Compare has difficulty with the (presumably) null padded files.
+This problem was not observed on VAX/VMS v6.1 or AXP/VMS v6.1.
diff --git a/source/Irrlicht/jpeglib/jaricom.c b/source/Irrlicht/jpeglib/jaricom.c
new file mode 100644
index 00000000..69006886
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jaricom.c
@@ -0,0 +1,153 @@
+/*
+ * jaricom.c
+ *
+ * Developed 1997-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains probability estimation tables for common use in
+ * arithmetic entropy encoding and decoding routines.
+ *
+ * This data represents Table D.3 in the JPEG spec (D.2 in the draft),
+ * ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81, and Table 24
+ * in the JBIG spec, ISO/IEC IS 11544 and CCITT Recommendation ITU-T T.82.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+/* The following #define specifies the packing of the four components
+ * into the compact INT32 representation.
+ * Note that this formula must match the actual arithmetic encoder
+ * and decoder implementation.  The implementation has to be changed
+ * if this formula is changed.
+ * The current organization is leaned on Markus Kuhn's JBIG
+ * implementation (jbig_tab.c).
+ */
+
+#define V(i,a,b,c,d) (((INT32)a << 16) | ((INT32)c << 8) | ((INT32)d << 7) | b)
+
+const INT32 jpeg_aritab[113+1] = {
+/*
+ * Index, Qe_Value, Next_Index_LPS, Next_Index_MPS, Switch_MPS
+ */
+  V(   0, 0x5a1d,   1,   1, 1 ),
+  V(   1, 0x2586,  14,   2, 0 ),
+  V(   2, 0x1114,  16,   3, 0 ),
+  V(   3, 0x080b,  18,   4, 0 ),
+  V(   4, 0x03d8,  20,   5, 0 ),
+  V(   5, 0x01da,  23,   6, 0 ),
+  V(   6, 0x00e5,  25,   7, 0 ),
+  V(   7, 0x006f,  28,   8, 0 ),
+  V(   8, 0x0036,  30,   9, 0 ),
+  V(   9, 0x001a,  33,  10, 0 ),
+  V(  10, 0x000d,  35,  11, 0 ),
+  V(  11, 0x0006,   9,  12, 0 ),
+  V(  12, 0x0003,  10,  13, 0 ),
+  V(  13, 0x0001,  12,  13, 0 ),
+  V(  14, 0x5a7f,  15,  15, 1 ),
+  V(  15, 0x3f25,  36,  16, 0 ),
+  V(  16, 0x2cf2,  38,  17, 0 ),
+  V(  17, 0x207c,  39,  18, 0 ),
+  V(  18, 0x17b9,  40,  19, 0 ),
+  V(  19, 0x1182,  42,  20, 0 ),
+  V(  20, 0x0cef,  43,  21, 0 ),
+  V(  21, 0x09a1,  45,  22, 0 ),
+  V(  22, 0x072f,  46,  23, 0 ),
+  V(  23, 0x055c,  48,  24, 0 ),
+  V(  24, 0x0406,  49,  25, 0 ),
+  V(  25, 0x0303,  51,  26, 0 ),
+  V(  26, 0x0240,  52,  27, 0 ),
+  V(  27, 0x01b1,  54,  28, 0 ),
+  V(  28, 0x0144,  56,  29, 0 ),
+  V(  29, 0x00f5,  57,  30, 0 ),
+  V(  30, 0x00b7,  59,  31, 0 ),
+  V(  31, 0x008a,  60,  32, 0 ),
+  V(  32, 0x0068,  62,  33, 0 ),
+  V(  33, 0x004e,  63,  34, 0 ),
+  V(  34, 0x003b,  32,  35, 0 ),
+  V(  35, 0x002c,  33,   9, 0 ),
+  V(  36, 0x5ae1,  37,  37, 1 ),
+  V(  37, 0x484c,  64,  38, 0 ),
+  V(  38, 0x3a0d,  65,  39, 0 ),
+  V(  39, 0x2ef1,  67,  40, 0 ),
+  V(  40, 0x261f,  68,  41, 0 ),
+  V(  41, 0x1f33,  69,  42, 0 ),
+  V(  42, 0x19a8,  70,  43, 0 ),
+  V(  43, 0x1518,  72,  44, 0 ),
+  V(  44, 0x1177,  73,  45, 0 ),
+  V(  45, 0x0e74,  74,  46, 0 ),
+  V(  46, 0x0bfb,  75,  47, 0 ),
+  V(  47, 0x09f8,  77,  48, 0 ),
+  V(  48, 0x0861,  78,  49, 0 ),
+  V(  49, 0x0706,  79,  50, 0 ),
+  V(  50, 0x05cd,  48,  51, 0 ),
+  V(  51, 0x04de,  50,  52, 0 ),
+  V(  52, 0x040f,  50,  53, 0 ),
+  V(  53, 0x0363,  51,  54, 0 ),
+  V(  54, 0x02d4,  52,  55, 0 ),
+  V(  55, 0x025c,  53,  56, 0 ),
+  V(  56, 0x01f8,  54,  57, 0 ),
+  V(  57, 0x01a4,  55,  58, 0 ),
+  V(  58, 0x0160,  56,  59, 0 ),
+  V(  59, 0x0125,  57,  60, 0 ),
+  V(  60, 0x00f6,  58,  61, 0 ),
+  V(  61, 0x00cb,  59,  62, 0 ),
+  V(  62, 0x00ab,  61,  63, 0 ),
+  V(  63, 0x008f,  61,  32, 0 ),
+  V(  64, 0x5b12,  65,  65, 1 ),
+  V(  65, 0x4d04,  80,  66, 0 ),
+  V(  66, 0x412c,  81,  67, 0 ),
+  V(  67, 0x37d8,  82,  68, 0 ),
+  V(  68, 0x2fe8,  83,  69, 0 ),
+  V(  69, 0x293c,  84,  70, 0 ),
+  V(  70, 0x2379,  86,  71, 0 ),
+  V(  71, 0x1edf,  87,  72, 0 ),
+  V(  72, 0x1aa9,  87,  73, 0 ),
+  V(  73, 0x174e,  72,  74, 0 ),
+  V(  74, 0x1424,  72,  75, 0 ),
+  V(  75, 0x119c,  74,  76, 0 ),
+  V(  76, 0x0f6b,  74,  77, 0 ),
+  V(  77, 0x0d51,  75,  78, 0 ),
+  V(  78, 0x0bb6,  77,  79, 0 ),
+  V(  79, 0x0a40,  77,  48, 0 ),
+  V(  80, 0x5832,  80,  81, 1 ),
+  V(  81, 0x4d1c,  88,  82, 0 ),
+  V(  82, 0x438e,  89,  83, 0 ),
+  V(  83, 0x3bdd,  90,  84, 0 ),
+  V(  84, 0x34ee,  91,  85, 0 ),
+  V(  85, 0x2eae,  92,  86, 0 ),
+  V(  86, 0x299a,  93,  87, 0 ),
+  V(  87, 0x2516,  86,  71, 0 ),
+  V(  88, 0x5570,  88,  89, 1 ),
+  V(  89, 0x4ca9,  95,  90, 0 ),
+  V(  90, 0x44d9,  96,  91, 0 ),
+  V(  91, 0x3e22,  97,  92, 0 ),
+  V(  92, 0x3824,  99,  93, 0 ),
+  V(  93, 0x32b4,  99,  94, 0 ),
+  V(  94, 0x2e17,  93,  86, 0 ),
+  V(  95, 0x56a8,  95,  96, 1 ),
+  V(  96, 0x4f46, 101,  97, 0 ),
+  V(  97, 0x47e5, 102,  98, 0 ),
+  V(  98, 0x41cf, 103,  99, 0 ),
+  V(  99, 0x3c3d, 104, 100, 0 ),
+  V( 100, 0x375e,  99,  93, 0 ),
+  V( 101, 0x5231, 105, 102, 0 ),
+  V( 102, 0x4c0f, 106, 103, 0 ),
+  V( 103, 0x4639, 107, 104, 0 ),
+  V( 104, 0x415e, 103,  99, 0 ),
+  V( 105, 0x5627, 105, 106, 1 ),
+  V( 106, 0x50e7, 108, 107, 0 ),
+  V( 107, 0x4b85, 109, 103, 0 ),
+  V( 108, 0x5597, 110, 109, 0 ),
+  V( 109, 0x504f, 111, 107, 0 ),
+  V( 110, 0x5a10, 110, 111, 1 ),
+  V( 111, 0x5522, 112, 109, 0 ),
+  V( 112, 0x59eb, 112, 111, 1 ),
+/*
+ * This last entry is used for fixed probability estimate of 0.5
+ * as suggested in Section 10.3 Table 5 of ITU-T Rec. T.851.
+ */
+  V( 113, 0x5a1d, 113, 113, 0 )
+};
diff --git a/source/Irrlicht/jpeglib/jcapimin.c b/source/Irrlicht/jpeglib/jcapimin.c
new file mode 100644
index 00000000..3382d915
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jcapimin.c
@@ -0,0 +1,288 @@
+/*
+ * jcapimin.c
+ *
+ * Copyright (C) 1994-1998, Thomas G. Lane.
+ * Modified 2003-2010 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface code for the compression half
+ * of the JPEG library.  These are the "minimum" API routines that may be
+ * needed in either the normal full-compression case or the transcoding-only
+ * case.
+ *
+ * Most of the routines intended to be called directly by an application
+ * are in this file or in jcapistd.c.  But also see jcparam.c for
+ * parameter-setup helper routines, jcomapi.c for routines shared by
+ * compression and decompression, and jctrans.c for the transcoding case.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Initialization of a JPEG compression object.
+ * The error manager must already be set up (in case memory manager fails).
+ */
+
+GLOBAL(void)
+jpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize)
+{
+  int i;
+
+  /* Guard against version mismatches between library and caller. */
+  cinfo->mem = NULL;		/* so jpeg_destroy knows mem mgr not called */
+  if (version != JPEG_LIB_VERSION)
+    ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version);
+  if (structsize != SIZEOF(struct jpeg_compress_struct))
+    ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, 
+	     (int) SIZEOF(struct jpeg_compress_struct), (int) structsize);
+
+  /* For debugging purposes, we zero the whole master structure.
+   * But the application has already set the err pointer, and may have set
+   * client_data, so we have to save and restore those fields.
+   * Note: if application hasn't set client_data, tools like Purify may
+   * complain here.
+   */
+  {
+    struct jpeg_error_mgr * err = cinfo->err;
+    void * client_data = cinfo->client_data; /* ignore Purify complaint here */
+    MEMZERO(cinfo, SIZEOF(struct jpeg_compress_struct));
+    cinfo->err = err;
+    cinfo->client_data = client_data;
+  }
+  cinfo->is_decompressor = FALSE;
+
+  /* Initialize a memory manager instance for this object */
+  jinit_memory_mgr((j_common_ptr) cinfo);
+
+  /* Zero out pointers to permanent structures. */
+  cinfo->progress = NULL;
+  cinfo->dest = NULL;
+
+  cinfo->comp_info = NULL;
+
+  for (i = 0; i < NUM_QUANT_TBLS; i++) {
+    cinfo->quant_tbl_ptrs[i] = NULL;
+    cinfo->q_scale_factor[i] = 100;
+  }
+
+  for (i = 0; i < NUM_HUFF_TBLS; i++) {
+    cinfo->dc_huff_tbl_ptrs[i] = NULL;
+    cinfo->ac_huff_tbl_ptrs[i] = NULL;
+  }
+
+  /* Must do it here for emit_dqt in case jpeg_write_tables is used */
+  cinfo->block_size = DCTSIZE;
+  cinfo->natural_order = jpeg_natural_order;
+  cinfo->lim_Se = DCTSIZE2-1;
+
+  cinfo->script_space = NULL;
+
+  cinfo->input_gamma = 1.0;	/* in case application forgets */
+
+  /* OK, I'm ready */
+  cinfo->global_state = CSTATE_START;
+}
+
+
+/*
+ * Destruction of a JPEG compression object
+ */
+
+GLOBAL(void)
+jpeg_destroy_compress (j_compress_ptr cinfo)
+{
+  jpeg_destroy((j_common_ptr) cinfo); /* use common routine */
+}
+
+
+/*
+ * Abort processing of a JPEG compression operation,
+ * but don't destroy the object itself.
+ */
+
+GLOBAL(void)
+jpeg_abort_compress (j_compress_ptr cinfo)
+{
+  jpeg_abort((j_common_ptr) cinfo); /* use common routine */
+}
+
+
+/*
+ * Forcibly suppress or un-suppress all quantization and Huffman tables.
+ * Marks all currently defined tables as already written (if suppress)
+ * or not written (if !suppress).  This will control whether they get emitted
+ * by a subsequent jpeg_start_compress call.
+ *
+ * This routine is exported for use by applications that want to produce
+ * abbreviated JPEG datastreams.  It logically belongs in jcparam.c, but
+ * since it is called by jpeg_start_compress, we put it here --- otherwise
+ * jcparam.o would be linked whether the application used it or not.
+ */
+
+GLOBAL(void)
+jpeg_suppress_tables (j_compress_ptr cinfo, boolean suppress)
+{
+  int i;
+  JQUANT_TBL * qtbl;
+  JHUFF_TBL * htbl;
+
+  for (i = 0; i < NUM_QUANT_TBLS; i++) {
+    if ((qtbl = cinfo->quant_tbl_ptrs[i]) != NULL)
+      qtbl->sent_table = suppress;
+  }
+
+  for (i = 0; i < NUM_HUFF_TBLS; i++) {
+    if ((htbl = cinfo->dc_huff_tbl_ptrs[i]) != NULL)
+      htbl->sent_table = suppress;
+    if ((htbl = cinfo->ac_huff_tbl_ptrs[i]) != NULL)
+      htbl->sent_table = suppress;
+  }
+}
+
+
+/*
+ * Finish JPEG compression.
+ *
+ * If a multipass operating mode was selected, this may do a great deal of
+ * work including most of the actual output.
+ */
+
+GLOBAL(void)
+jpeg_finish_compress (j_compress_ptr cinfo)
+{
+  JDIMENSION iMCU_row;
+
+  if (cinfo->global_state == CSTATE_SCANNING ||
+      cinfo->global_state == CSTATE_RAW_OK) {
+    /* Terminate first pass */
+    if (cinfo->next_scanline < cinfo->image_height)
+      ERREXIT(cinfo, JERR_TOO_LITTLE_DATA);
+    (*cinfo->master->finish_pass) (cinfo);
+  } else if (cinfo->global_state != CSTATE_WRCOEFS)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+  /* Perform any remaining passes */
+  while (! cinfo->master->is_last_pass) {
+    (*cinfo->master->prepare_for_pass) (cinfo);
+    for (iMCU_row = 0; iMCU_row < cinfo->total_iMCU_rows; iMCU_row++) {
+      if (cinfo->progress != NULL) {
+	cinfo->progress->pass_counter = (long) iMCU_row;
+	cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows;
+	(*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+      }
+      /* We bypass the main controller and invoke coef controller directly;
+       * all work is being done from the coefficient buffer.
+       */
+      if (! (*cinfo->coef->compress_data) (cinfo, (JSAMPIMAGE) NULL))
+	ERREXIT(cinfo, JERR_CANT_SUSPEND);
+    }
+    (*cinfo->master->finish_pass) (cinfo);
+  }
+  /* Write EOI, do final cleanup */
+  (*cinfo->marker->write_file_trailer) (cinfo);
+  (*cinfo->dest->term_destination) (cinfo);
+  /* We can use jpeg_abort to release memory and reset global_state */
+  jpeg_abort((j_common_ptr) cinfo);
+}
+
+
+/*
+ * Write a special marker.
+ * This is only recommended for writing COM or APPn markers.
+ * Must be called after jpeg_start_compress() and before
+ * first call to jpeg_write_scanlines() or jpeg_write_raw_data().
+ */
+
+GLOBAL(void)
+jpeg_write_marker (j_compress_ptr cinfo, int marker,
+		   const JOCTET *dataptr, unsigned int datalen)
+{
+  JMETHOD(void, write_marker_byte, (j_compress_ptr info, int val));
+
+  if (cinfo->next_scanline != 0 ||
+      (cinfo->global_state != CSTATE_SCANNING &&
+       cinfo->global_state != CSTATE_RAW_OK &&
+       cinfo->global_state != CSTATE_WRCOEFS))
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+  (*cinfo->marker->write_marker_header) (cinfo, marker, datalen);
+  write_marker_byte = cinfo->marker->write_marker_byte;	/* copy for speed */
+  while (datalen--) {
+    (*write_marker_byte) (cinfo, *dataptr);
+    dataptr++;
+  }
+}
+
+/* Same, but piecemeal. */
+
+GLOBAL(void)
+jpeg_write_m_header (j_compress_ptr cinfo, int marker, unsigned int datalen)
+{
+  if (cinfo->next_scanline != 0 ||
+      (cinfo->global_state != CSTATE_SCANNING &&
+       cinfo->global_state != CSTATE_RAW_OK &&
+       cinfo->global_state != CSTATE_WRCOEFS))
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+  (*cinfo->marker->write_marker_header) (cinfo, marker, datalen);
+}
+
+GLOBAL(void)
+jpeg_write_m_byte (j_compress_ptr cinfo, int val)
+{
+  (*cinfo->marker->write_marker_byte) (cinfo, val);
+}
+
+
+/*
+ * Alternate compression function: just write an abbreviated table file.
+ * Before calling this, all parameters and a data destination must be set up.
+ *
+ * To produce a pair of files containing abbreviated tables and abbreviated
+ * image data, one would proceed as follows:
+ *
+ *		initialize JPEG object
+ *		set JPEG parameters
+ *		set destination to table file
+ *		jpeg_write_tables(cinfo);
+ *		set destination to image file
+ *		jpeg_start_compress(cinfo, FALSE);
+ *		write data...
+ *		jpeg_finish_compress(cinfo);
+ *
+ * jpeg_write_tables has the side effect of marking all tables written
+ * (same as jpeg_suppress_tables(..., TRUE)).  Thus a subsequent start_compress
+ * will not re-emit the tables unless it is passed write_all_tables=TRUE.
+ */
+
+GLOBAL(void)
+jpeg_write_tables (j_compress_ptr cinfo)
+{
+  if (cinfo->global_state != CSTATE_START)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+  /* (Re)initialize error mgr and destination modules */
+  (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
+  (*cinfo->dest->init_destination) (cinfo);
+  /* Initialize the marker writer ... bit of a crock to do it here. */
+  jinit_marker_writer(cinfo);
+  /* Write them tables! */
+  (*cinfo->marker->write_tables_only) (cinfo);
+  /* And clean up. */
+  (*cinfo->dest->term_destination) (cinfo);
+  /*
+   * In library releases up through v6a, we called jpeg_abort() here to free
+   * any working memory allocated by the destination manager and marker
+   * writer.  Some applications had a problem with that: they allocated space
+   * of their own from the library memory manager, and didn't want it to go
+   * away during write_tables.  So now we do nothing.  This will cause a
+   * memory leak if an app calls write_tables repeatedly without doing a full
+   * compression cycle or otherwise resetting the JPEG object.  However, that
+   * seems less bad than unexpectedly freeing memory in the normal case.
+   * An app that prefers the old behavior can call jpeg_abort for itself after
+   * each call to jpeg_write_tables().
+   */
+}
diff --git a/source/Irrlicht/jpeglib/jcapistd.c b/source/Irrlicht/jpeglib/jcapistd.c
new file mode 100644
index 00000000..8892bfaa
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jcapistd.c
@@ -0,0 +1,162 @@
+/*
+ * jcapistd.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface code for the compression half
+ * of the JPEG library.  These are the "standard" API routines that are
+ * used in the normal full-compression case.  They are not used by a
+ * transcoding-only application.  Note that if an application links in
+ * jpeg_start_compress, it will end up linking in the entire compressor.
+ * We thus must separate this file from jcapimin.c to avoid linking the
+ * whole compression library into a transcoder.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Compression initialization.
+ * Before calling this, all parameters and a data destination must be set up.
+ *
+ * We require a write_all_tables parameter as a failsafe check when writing
+ * multiple datastreams from the same compression object.  Since prior runs
+ * will have left all the tables marked sent_table=TRUE, a subsequent run
+ * would emit an abbreviated stream (no tables) by default.  This may be what
+ * is wanted, but for safety's sake it should not be the default behavior:
+ * programmers should have to make a deliberate choice to emit abbreviated
+ * images.  Therefore the documentation and examples should encourage people
+ * to pass write_all_tables=TRUE; then it will take active thought to do the
+ * wrong thing.
+ */
+
+GLOBAL(void)
+jpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables)
+{
+  if (cinfo->global_state != CSTATE_START)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+  if (write_all_tables)
+    jpeg_suppress_tables(cinfo, FALSE);	/* mark all tables to be written */
+
+  /* (Re)initialize error mgr and destination modules */
+  (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
+  (*cinfo->dest->init_destination) (cinfo);
+  /* Perform master selection of active modules */
+  jinit_compress_master(cinfo);
+  /* Set up for the first pass */
+  (*cinfo->master->prepare_for_pass) (cinfo);
+  /* Ready for application to drive first pass through jpeg_write_scanlines
+   * or jpeg_write_raw_data.
+   */
+  cinfo->next_scanline = 0;
+  cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING);
+}
+
+
+/*
+ * Write some scanlines of data to the JPEG compressor.
+ *
+ * The return value will be the number of lines actually written.
+ * This should be less than the supplied num_lines only in case that
+ * the data destination module has requested suspension of the compressor,
+ * or if more than image_height scanlines are passed in.
+ *
+ * Note: we warn about excess calls to jpeg_write_scanlines() since
+ * this likely signals an application programmer error.  However,
+ * excess scanlines passed in the last valid call are *silently* ignored,
+ * so that the application need not adjust num_lines for end-of-image
+ * when using a multiple-scanline buffer.
+ */
+
+GLOBAL(JDIMENSION)
+jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines,
+		      JDIMENSION num_lines)
+{
+  JDIMENSION row_ctr, rows_left;
+
+  if (cinfo->global_state != CSTATE_SCANNING)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+  if (cinfo->next_scanline >= cinfo->image_height)
+    WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+
+  /* Call progress monitor hook if present */
+  if (cinfo->progress != NULL) {
+    cinfo->progress->pass_counter = (long) cinfo->next_scanline;
+    cinfo->progress->pass_limit = (long) cinfo->image_height;
+    (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+  }
+
+  /* Give master control module another chance if this is first call to
+   * jpeg_write_scanlines.  This lets output of the frame/scan headers be
+   * delayed so that application can write COM, etc, markers between
+   * jpeg_start_compress and jpeg_write_scanlines.
+   */
+  if (cinfo->master->call_pass_startup)
+    (*cinfo->master->pass_startup) (cinfo);
+
+  /* Ignore any extra scanlines at bottom of image. */
+  rows_left = cinfo->image_height - cinfo->next_scanline;
+  if (num_lines > rows_left)
+    num_lines = rows_left;
+
+  row_ctr = 0;
+  (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines);
+  cinfo->next_scanline += row_ctr;
+  return row_ctr;
+}
+
+
+/*
+ * Alternate entry point to write raw data.
+ * Processes exactly one iMCU row per call, unless suspended.
+ */
+
+GLOBAL(JDIMENSION)
+jpeg_write_raw_data (j_compress_ptr cinfo, JSAMPIMAGE data,
+		     JDIMENSION num_lines)
+{
+  JDIMENSION lines_per_iMCU_row;
+
+  if (cinfo->global_state != CSTATE_RAW_OK)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+  if (cinfo->next_scanline >= cinfo->image_height) {
+    WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+    return 0;
+  }
+
+  /* Call progress monitor hook if present */
+  if (cinfo->progress != NULL) {
+    cinfo->progress->pass_counter = (long) cinfo->next_scanline;
+    cinfo->progress->pass_limit = (long) cinfo->image_height;
+    (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+  }
+
+  /* Give master control module another chance if this is first call to
+   * jpeg_write_raw_data.  This lets output of the frame/scan headers be
+   * delayed so that application can write COM, etc, markers between
+   * jpeg_start_compress and jpeg_write_raw_data.
+   */
+  if (cinfo->master->call_pass_startup)
+    (*cinfo->master->pass_startup) (cinfo);
+
+  /* Verify that at least one iMCU row has been passed. */
+  lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_v_scaled_size;
+  if (num_lines < lines_per_iMCU_row)
+    ERREXIT(cinfo, JERR_BUFFER_SIZE);
+
+  /* Directly compress the row. */
+  if (! (*cinfo->coef->compress_data) (cinfo, data)) {
+    /* If compressor did not consume the whole row, suspend processing. */
+    return 0;
+  }
+
+  /* OK, we processed one iMCU row. */
+  cinfo->next_scanline += lines_per_iMCU_row;
+  return lines_per_iMCU_row;
+}
diff --git a/source/Irrlicht/jpeglib/jcarith.c b/source/Irrlicht/jpeglib/jcarith.c
new file mode 100644
index 00000000..a64190e7
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jcarith.c
@@ -0,0 +1,944 @@
+/*
+ * jcarith.c
+ *
+ * Developed 1997-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains portable arithmetic entropy encoding routines for JPEG
+ * (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81).
+ *
+ * Both sequential and progressive modes are supported in this single module.
+ *
+ * Suspension is not currently supported in this module.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Expanded entropy encoder object for arithmetic encoding. */
+
+typedef struct {
+  struct jpeg_entropy_encoder pub; /* public fields */
+
+  INT32 c; /* C register, base of coding interval, layout as in sec. D.1.3 */
+  INT32 a;               /* A register, normalized size of coding interval */
+  INT32 sc;        /* counter for stacked 0xFF values which might overflow */
+  INT32 zc;          /* counter for pending 0x00 output values which might *
+                          * be discarded at the end ("Pacman" termination) */
+  int ct;  /* bit shift counter, determines when next byte will be written */
+  int buffer;                /* buffer for most recent output byte != 0xFF */
+
+  int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
+  int dc_context[MAX_COMPS_IN_SCAN]; /* context index for DC conditioning */
+
+  unsigned int restarts_to_go;	/* MCUs left in this restart interval */
+  int next_restart_num;		/* next restart number to write (0-7) */
+
+  /* Pointers to statistics areas (these workspaces have image lifespan) */
+  unsigned char * dc_stats[NUM_ARITH_TBLS];
+  unsigned char * ac_stats[NUM_ARITH_TBLS];
+
+  /* Statistics bin for coding with fixed probability 0.5 */
+  unsigned char fixed_bin[4];
+} arith_entropy_encoder;
+
+typedef arith_entropy_encoder * arith_entropy_ptr;
+
+/* The following two definitions specify the allocation chunk size
+ * for the statistics area.
+ * According to sections F.1.4.4.1.3 and F.1.4.4.2, we need at least
+ * 49 statistics bins for DC, and 245 statistics bins for AC coding.
+ *
+ * We use a compact representation with 1 byte per statistics bin,
+ * thus the numbers directly represent byte sizes.
+ * This 1 byte per statistics bin contains the meaning of the MPS
+ * (more probable symbol) in the highest bit (mask 0x80), and the
+ * index into the probability estimation state machine table
+ * in the lower bits (mask 0x7F).
+ */
+
+#define DC_STAT_BINS 64
+#define AC_STAT_BINS 256
+
+/* NOTE: Uncomment the following #define if you want to use the
+ * given formula for calculating the AC conditioning parameter Kx
+ * for spectral selection progressive coding in section G.1.3.2
+ * of the spec (Kx = Kmin + SRL (8 + Se - Kmin) 4).
+ * Although the spec and P&M authors claim that this "has proven
+ * to give good results for 8 bit precision samples", I'm not
+ * convinced yet that this is really beneficial.
+ * Early tests gave only very marginal compression enhancements
+ * (a few - around 5 or so - bytes even for very large files),
+ * which would turn out rather negative if we'd suppress the
+ * DAC (Define Arithmetic Conditioning) marker segments for
+ * the default parameters in the future.
+ * Note that currently the marker writing module emits 12-byte
+ * DAC segments for a full-component scan in a color image.
+ * This is not worth worrying about IMHO. However, since the
+ * spec defines the default values to be used if the tables
+ * are omitted (unlike Huffman tables, which are required
+ * anyway), one might optimize this behaviour in the future,
+ * and then it would be disadvantageous to use custom tables if
+ * they don't provide sufficient gain to exceed the DAC size.
+ *
+ * On the other hand, I'd consider it as a reasonable result
+ * that the conditioning has no significant influence on the
+ * compression performance. This means that the basic
+ * statistical model is already rather stable.
+ *
+ * Thus, at the moment, we use the default conditioning values
+ * anyway, and do not use the custom formula.
+ *
+#define CALCULATE_SPECTRAL_CONDITIONING
+ */
+
+/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32.
+ * We assume that int right shift is unsigned if INT32 right shift is,
+ * which should be safe.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define ISHIFT_TEMPS	int ishift_temp;
+#define IRIGHT_SHIFT(x,shft)  \
+	((ishift_temp = (x)) < 0 ? \
+	 (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \
+	 (ishift_temp >> (shft)))
+#else
+#define ISHIFT_TEMPS
+#define IRIGHT_SHIFT(x,shft)	((x) >> (shft))
+#endif
+
+
+LOCAL(void)
+emit_byte (int val, j_compress_ptr cinfo)
+/* Write next output byte; we do not support suspension in this module. */
+{
+  struct jpeg_destination_mgr * dest = cinfo->dest;
+
+  *dest->next_output_byte++ = (JOCTET) val;
+  if (--dest->free_in_buffer == 0)
+    if (! (*dest->empty_output_buffer) (cinfo))
+      ERREXIT(cinfo, JERR_CANT_SUSPEND);
+}
+
+
+/*
+ * Finish up at the end of an arithmetic-compressed scan.
+ */
+
+METHODDEF(void)
+finish_pass (j_compress_ptr cinfo)
+{
+  arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
+  INT32 temp;
+
+  /* Section D.1.8: Termination of encoding */
+
+  /* Find the e->c in the coding interval with the largest
+   * number of trailing zero bits */
+  if ((temp = (e->a - 1 + e->c) & 0xFFFF0000L) < e->c)
+    e->c = temp + 0x8000L;
+  else
+    e->c = temp;
+  /* Send remaining bytes to output */
+  e->c <<= e->ct;
+  if (e->c & 0xF8000000L) {
+    /* One final overflow has to be handled */
+    if (e->buffer >= 0) {
+      if (e->zc)
+	do emit_byte(0x00, cinfo);
+	while (--e->zc);
+      emit_byte(e->buffer + 1, cinfo);
+      if (e->buffer + 1 == 0xFF)
+	emit_byte(0x00, cinfo);
+    }
+    e->zc += e->sc;  /* carry-over converts stacked 0xFF bytes to 0x00 */
+    e->sc = 0;
+  } else {
+    if (e->buffer == 0)
+      ++e->zc;
+    else if (e->buffer >= 0) {
+      if (e->zc)
+	do emit_byte(0x00, cinfo);
+	while (--e->zc);
+      emit_byte(e->buffer, cinfo);
+    }
+    if (e->sc) {
+      if (e->zc)
+	do emit_byte(0x00, cinfo);
+	while (--e->zc);
+      do {
+	emit_byte(0xFF, cinfo);
+	emit_byte(0x00, cinfo);
+      } while (--e->sc);
+    }
+  }
+  /* Output final bytes only if they are not 0x00 */
+  if (e->c & 0x7FFF800L) {
+    if (e->zc)  /* output final pending zero bytes */
+      do emit_byte(0x00, cinfo);
+      while (--e->zc);
+    emit_byte((e->c >> 19) & 0xFF, cinfo);
+    if (((e->c >> 19) & 0xFF) == 0xFF)
+      emit_byte(0x00, cinfo);
+    if (e->c & 0x7F800L) {
+      emit_byte((e->c >> 11) & 0xFF, cinfo);
+      if (((e->c >> 11) & 0xFF) == 0xFF)
+	emit_byte(0x00, cinfo);
+    }
+  }
+}
+
+
+/*
+ * The core arithmetic encoding routine (common in JPEG and JBIG).
+ * This needs to go as fast as possible.
+ * Machine-dependent optimization facilities
+ * are not utilized in this portable implementation.
+ * However, this code should be fairly efficient and
+ * may be a good base for further optimizations anyway.
+ *
+ * Parameter 'val' to be encoded may be 0 or 1 (binary decision).
+ *
+ * Note: I've added full "Pacman" termination support to the
+ * byte output routines, which is equivalent to the optional
+ * Discard_final_zeros procedure (Figure D.15) in the spec.
+ * Thus, we always produce the shortest possible output
+ * stream compliant to the spec (no trailing zero bytes,
+ * except for FF stuffing).
+ *
+ * I've also introduced a new scheme for accessing
+ * the probability estimation state machine table,
+ * derived from Markus Kuhn's JBIG implementation.
+ */
+
+LOCAL(void)
+arith_encode (j_compress_ptr cinfo, unsigned char *st, int val) 
+{
+  register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
+  register unsigned char nl, nm;
+  register INT32 qe, temp;
+  register int sv;
+
+  /* Fetch values from our compact representation of Table D.3(D.2):
+   * Qe values and probability estimation state machine
+   */
+  sv = *st;
+  qe = jpeg_aritab[sv & 0x7F];	/* => Qe_Value */
+  nl = qe & 0xFF; qe >>= 8;	/* Next_Index_LPS + Switch_MPS */
+  nm = qe & 0xFF; qe >>= 8;	/* Next_Index_MPS */
+
+  /* Encode & estimation procedures per sections D.1.4 & D.1.5 */
+  e->a -= qe;
+  if (val != (sv >> 7)) {
+    /* Encode the less probable symbol */
+    if (e->a >= qe) {
+      /* If the interval size (qe) for the less probable symbol (LPS)
+       * is larger than the interval size for the MPS, then exchange
+       * the two symbols for coding efficiency, otherwise code the LPS
+       * as usual: */
+      e->c += e->a;
+      e->a = qe;
+    }
+    *st = (sv & 0x80) ^ nl;	/* Estimate_after_LPS */
+  } else {
+    /* Encode the more probable symbol */
+    if (e->a >= 0x8000L)
+      return;  /* A >= 0x8000 -> ready, no renormalization required */
+    if (e->a < qe) {
+      /* If the interval size (qe) for the less probable symbol (LPS)
+       * is larger than the interval size for the MPS, then exchange
+       * the two symbols for coding efficiency: */
+      e->c += e->a;
+      e->a = qe;
+    }
+    *st = (sv & 0x80) ^ nm;	/* Estimate_after_MPS */
+  }
+
+  /* Renormalization & data output per section D.1.6 */
+  do {
+    e->a <<= 1;
+    e->c <<= 1;
+    if (--e->ct == 0) {
+      /* Another byte is ready for output */
+      temp = e->c >> 19;
+      if (temp > 0xFF) {
+	/* Handle overflow over all stacked 0xFF bytes */
+	if (e->buffer >= 0) {
+	  if (e->zc)
+	    do emit_byte(0x00, cinfo);
+	    while (--e->zc);
+	  emit_byte(e->buffer + 1, cinfo);
+	  if (e->buffer + 1 == 0xFF)
+	    emit_byte(0x00, cinfo);
+	}
+	e->zc += e->sc;  /* carry-over converts stacked 0xFF bytes to 0x00 */
+	e->sc = 0;
+	/* Note: The 3 spacer bits in the C register guarantee
+	 * that the new buffer byte can't be 0xFF here
+	 * (see page 160 in the P&M JPEG book). */
+	e->buffer = temp & 0xFF;  /* new output byte, might overflow later */
+      } else if (temp == 0xFF) {
+	++e->sc;  /* stack 0xFF byte (which might overflow later) */
+      } else {
+	/* Output all stacked 0xFF bytes, they will not overflow any more */
+	if (e->buffer == 0)
+	  ++e->zc;
+	else if (e->buffer >= 0) {
+	  if (e->zc)
+	    do emit_byte(0x00, cinfo);
+	    while (--e->zc);
+	  emit_byte(e->buffer, cinfo);
+	}
+	if (e->sc) {
+	  if (e->zc)
+	    do emit_byte(0x00, cinfo);
+	    while (--e->zc);
+	  do {
+	    emit_byte(0xFF, cinfo);
+	    emit_byte(0x00, cinfo);
+	  } while (--e->sc);
+	}
+	e->buffer = temp & 0xFF;  /* new output byte (can still overflow) */
+      }
+      e->c &= 0x7FFFFL;
+      e->ct += 8;
+    }
+  } while (e->a < 0x8000L);
+}
+
+
+/*
+ * Emit a restart marker & resynchronize predictions.
+ */
+
+LOCAL(void)
+emit_restart (j_compress_ptr cinfo, int restart_num)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  int ci;
+  jpeg_component_info * compptr;
+
+  finish_pass(cinfo);
+
+  emit_byte(0xFF, cinfo);
+  emit_byte(JPEG_RST0 + restart_num, cinfo);
+
+  /* Re-initialize statistics areas */
+  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+    compptr = cinfo->cur_comp_info[ci];
+    /* DC needs no table for refinement scan */
+    if (cinfo->Ss == 0 && cinfo->Ah == 0) {
+      MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS);
+      /* Reset DC predictions to 0 */
+      entropy->last_dc_val[ci] = 0;
+      entropy->dc_context[ci] = 0;
+    }
+    /* AC needs no table when not present */
+    if (cinfo->Se) {
+      MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS);
+    }
+  }
+
+  /* Reset arithmetic encoding variables */
+  entropy->c = 0;
+  entropy->a = 0x10000L;
+  entropy->sc = 0;
+  entropy->zc = 0;
+  entropy->ct = 11;
+  entropy->buffer = -1;  /* empty */
+}
+
+
+/*
+ * MCU encoding for DC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  unsigned char *st;
+  int blkn, ci, tbl;
+  int v, v2, m;
+  ISHIFT_TEMPS
+
+  /* Emit restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0) {
+      emit_restart(cinfo, entropy->next_restart_num);
+      entropy->restarts_to_go = cinfo->restart_interval;
+      entropy->next_restart_num++;
+      entropy->next_restart_num &= 7;
+    }
+    entropy->restarts_to_go--;
+  }
+
+  /* Encode the MCU data blocks */
+  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+    ci = cinfo->MCU_membership[blkn];
+    tbl = cinfo->cur_comp_info[ci]->dc_tbl_no;
+
+    /* Compute the DC value after the required point transform by Al.
+     * This is simply an arithmetic right shift.
+     */
+    m = IRIGHT_SHIFT((int) (MCU_data[blkn][0][0]), cinfo->Al);
+
+    /* Sections F.1.4.1 & F.1.4.4.1: Encoding of DC coefficients */
+
+    /* Table F.4: Point to statistics bin S0 for DC coefficient coding */
+    st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
+
+    /* Figure F.4: Encode_DC_DIFF */
+    if ((v = m - entropy->last_dc_val[ci]) == 0) {
+      arith_encode(cinfo, st, 0);
+      entropy->dc_context[ci] = 0;	/* zero diff category */
+    } else {
+      entropy->last_dc_val[ci] = m;
+      arith_encode(cinfo, st, 1);
+      /* Figure F.6: Encoding nonzero value v */
+      /* Figure F.7: Encoding the sign of v */
+      if (v > 0) {
+	arith_encode(cinfo, st + 1, 0);	/* Table F.4: SS = S0 + 1 */
+	st += 2;			/* Table F.4: SP = S0 + 2 */
+	entropy->dc_context[ci] = 4;	/* small positive diff category */
+      } else {
+	v = -v;
+	arith_encode(cinfo, st + 1, 1);	/* Table F.4: SS = S0 + 1 */
+	st += 3;			/* Table F.4: SN = S0 + 3 */
+	entropy->dc_context[ci] = 8;	/* small negative diff category */
+      }
+      /* Figure F.8: Encoding the magnitude category of v */
+      m = 0;
+      if (v -= 1) {
+	arith_encode(cinfo, st, 1);
+	m = 1;
+	v2 = v;
+	st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */
+	while (v2 >>= 1) {
+	  arith_encode(cinfo, st, 1);
+	  m <<= 1;
+	  st += 1;
+	}
+      }
+      arith_encode(cinfo, st, 0);
+      /* Section F.1.4.4.1.2: Establish dc_context conditioning category */
+      if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
+	entropy->dc_context[ci] = 0;	/* zero diff category */
+      else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
+	entropy->dc_context[ci] += 8;	/* large diff category */
+      /* Figure F.9: Encoding the magnitude bit pattern of v */
+      st += 14;
+      while (m >>= 1)
+	arith_encode(cinfo, st, (m & v) ? 1 : 0);
+    }
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * MCU encoding for AC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  const int * natural_order;
+  JBLOCKROW block;
+  unsigned char *st;
+  int tbl, k, ke;
+  int v, v2, m;
+
+  /* Emit restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0) {
+      emit_restart(cinfo, entropy->next_restart_num);
+      entropy->restarts_to_go = cinfo->restart_interval;
+      entropy->next_restart_num++;
+      entropy->next_restart_num &= 7;
+    }
+    entropy->restarts_to_go--;
+  }
+
+  natural_order = cinfo->natural_order;
+
+  /* Encode the MCU data block */
+  block = MCU_data[0];
+  tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
+
+  /* Sections F.1.4.2 & F.1.4.4.2: Encoding of AC coefficients */
+
+  /* Establish EOB (end-of-block) index */
+  ke = cinfo->Se;
+  do {
+    /* We must apply the point transform by Al.  For AC coefficients this
+     * is an integer division with rounding towards 0.  To do this portably
+     * in C, we shift after obtaining the absolute value.
+     */
+    if ((v = (*block)[natural_order[ke]]) >= 0) {
+      if (v >>= cinfo->Al) break;
+    } else {
+      v = -v;
+      if (v >>= cinfo->Al) break;
+    }
+  } while (--ke);
+
+  /* Figure F.5: Encode_AC_Coefficients */
+  for (k = cinfo->Ss - 1; k < ke;) {
+    st = entropy->ac_stats[tbl] + 3 * k;
+    arith_encode(cinfo, st, 0);		/* EOB decision */
+    for (;;) {
+      if ((v = (*block)[natural_order[++k]]) >= 0) {
+	if (v >>= cinfo->Al) {
+	  arith_encode(cinfo, st + 1, 1);
+	  arith_encode(cinfo, entropy->fixed_bin, 0);
+	  break;
+	}
+      } else {
+	v = -v;
+	if (v >>= cinfo->Al) {
+	  arith_encode(cinfo, st + 1, 1);
+	  arith_encode(cinfo, entropy->fixed_bin, 1);
+	  break;
+	}
+      }
+      arith_encode(cinfo, st + 1, 0);
+      st += 3;
+    }
+    st += 2;
+    /* Figure F.8: Encoding the magnitude category of v */
+    m = 0;
+    if (v -= 1) {
+      arith_encode(cinfo, st, 1);
+      m = 1;
+      v2 = v;
+      if (v2 >>= 1) {
+	arith_encode(cinfo, st, 1);
+	m <<= 1;
+	st = entropy->ac_stats[tbl] +
+	     (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
+	while (v2 >>= 1) {
+	  arith_encode(cinfo, st, 1);
+	  m <<= 1;
+	  st += 1;
+	}
+      }
+    }
+    arith_encode(cinfo, st, 0);
+    /* Figure F.9: Encoding the magnitude bit pattern of v */
+    st += 14;
+    while (m >>= 1)
+      arith_encode(cinfo, st, (m & v) ? 1 : 0);
+  }
+  /* Encode EOB decision only if k < cinfo->Se */
+  if (k < cinfo->Se) {
+    st = entropy->ac_stats[tbl] + 3 * k;
+    arith_encode(cinfo, st, 1);
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * MCU encoding for DC successive approximation refinement scan.
+ * Note: we assume such scans can be multi-component,
+ * although the spec is not very clear on the point.
+ */
+
+METHODDEF(boolean)
+encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  unsigned char *st;
+  int Al, blkn;
+
+  /* Emit restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0) {
+      emit_restart(cinfo, entropy->next_restart_num);
+      entropy->restarts_to_go = cinfo->restart_interval;
+      entropy->next_restart_num++;
+      entropy->next_restart_num &= 7;
+    }
+    entropy->restarts_to_go--;
+  }
+
+  st = entropy->fixed_bin;	/* use fixed probability estimation */
+  Al = cinfo->Al;
+
+  /* Encode the MCU data blocks */
+  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+    /* We simply emit the Al'th bit of the DC coefficient value. */
+    arith_encode(cinfo, st, (MCU_data[blkn][0][0] >> Al) & 1);
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * MCU encoding for AC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  const int * natural_order;
+  JBLOCKROW block;
+  unsigned char *st;
+  int tbl, k, ke, kex;
+  int v;
+
+  /* Emit restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0) {
+      emit_restart(cinfo, entropy->next_restart_num);
+      entropy->restarts_to_go = cinfo->restart_interval;
+      entropy->next_restart_num++;
+      entropy->next_restart_num &= 7;
+    }
+    entropy->restarts_to_go--;
+  }
+
+  natural_order = cinfo->natural_order;
+
+  /* Encode the MCU data block */
+  block = MCU_data[0];
+  tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
+
+  /* Section G.1.3.3: Encoding of AC coefficients */
+
+  /* Establish EOB (end-of-block) index */
+  ke = cinfo->Se;
+  do {
+    /* We must apply the point transform by Al.  For AC coefficients this
+     * is an integer division with rounding towards 0.  To do this portably
+     * in C, we shift after obtaining the absolute value.
+     */
+    if ((v = (*block)[natural_order[ke]]) >= 0) {
+      if (v >>= cinfo->Al) break;
+    } else {
+      v = -v;
+      if (v >>= cinfo->Al) break;
+    }
+  } while (--ke);
+
+  /* Establish EOBx (previous stage end-of-block) index */
+  for (kex = ke; kex > 0; kex--)
+    if ((v = (*block)[natural_order[kex]]) >= 0) {
+      if (v >>= cinfo->Ah) break;
+    } else {
+      v = -v;
+      if (v >>= cinfo->Ah) break;
+    }
+
+  /* Figure G.10: Encode_AC_Coefficients_SA */
+  for (k = cinfo->Ss - 1; k < ke;) {
+    st = entropy->ac_stats[tbl] + 3 * k;
+    if (k >= kex)
+      arith_encode(cinfo, st, 0);	/* EOB decision */
+    for (;;) {
+      if ((v = (*block)[natural_order[++k]]) >= 0) {
+	if (v >>= cinfo->Al) {
+	  if (v >> 1)			/* previously nonzero coef */
+	    arith_encode(cinfo, st + 2, (v & 1));
+	  else {			/* newly nonzero coef */
+	    arith_encode(cinfo, st + 1, 1);
+	    arith_encode(cinfo, entropy->fixed_bin, 0);
+	  }
+	  break;
+	}
+      } else {
+	v = -v;
+	if (v >>= cinfo->Al) {
+	  if (v >> 1)			/* previously nonzero coef */
+	    arith_encode(cinfo, st + 2, (v & 1));
+	  else {			/* newly nonzero coef */
+	    arith_encode(cinfo, st + 1, 1);
+	    arith_encode(cinfo, entropy->fixed_bin, 1);
+	  }
+	  break;
+	}
+      }
+      arith_encode(cinfo, st + 1, 0);
+      st += 3;
+    }
+  }
+  /* Encode EOB decision only if k < cinfo->Se */
+  if (k < cinfo->Se) {
+    st = entropy->ac_stats[tbl] + 3 * k;
+    arith_encode(cinfo, st, 1);
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * Encode and output one MCU's worth of arithmetic-compressed coefficients.
+ */
+
+METHODDEF(boolean)
+encode_mcu (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  const int * natural_order;
+  JBLOCKROW block;
+  unsigned char *st;
+  int tbl, k, ke;
+  int v, v2, m;
+  int blkn, ci;
+  jpeg_component_info * compptr;
+
+  /* Emit restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0) {
+      emit_restart(cinfo, entropy->next_restart_num);
+      entropy->restarts_to_go = cinfo->restart_interval;
+      entropy->next_restart_num++;
+      entropy->next_restart_num &= 7;
+    }
+    entropy->restarts_to_go--;
+  }
+
+  natural_order = cinfo->natural_order;
+
+  /* Encode the MCU data blocks */
+  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+    block = MCU_data[blkn];
+    ci = cinfo->MCU_membership[blkn];
+    compptr = cinfo->cur_comp_info[ci];
+
+    /* Sections F.1.4.1 & F.1.4.4.1: Encoding of DC coefficients */
+
+    tbl = compptr->dc_tbl_no;
+
+    /* Table F.4: Point to statistics bin S0 for DC coefficient coding */
+    st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
+
+    /* Figure F.4: Encode_DC_DIFF */
+    if ((v = (*block)[0] - entropy->last_dc_val[ci]) == 0) {
+      arith_encode(cinfo, st, 0);
+      entropy->dc_context[ci] = 0;	/* zero diff category */
+    } else {
+      entropy->last_dc_val[ci] = (*block)[0];
+      arith_encode(cinfo, st, 1);
+      /* Figure F.6: Encoding nonzero value v */
+      /* Figure F.7: Encoding the sign of v */
+      if (v > 0) {
+	arith_encode(cinfo, st + 1, 0);	/* Table F.4: SS = S0 + 1 */
+	st += 2;			/* Table F.4: SP = S0 + 2 */
+	entropy->dc_context[ci] = 4;	/* small positive diff category */
+      } else {
+	v = -v;
+	arith_encode(cinfo, st + 1, 1);	/* Table F.4: SS = S0 + 1 */
+	st += 3;			/* Table F.4: SN = S0 + 3 */
+	entropy->dc_context[ci] = 8;	/* small negative diff category */
+      }
+      /* Figure F.8: Encoding the magnitude category of v */
+      m = 0;
+      if (v -= 1) {
+	arith_encode(cinfo, st, 1);
+	m = 1;
+	v2 = v;
+	st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */
+	while (v2 >>= 1) {
+	  arith_encode(cinfo, st, 1);
+	  m <<= 1;
+	  st += 1;
+	}
+      }
+      arith_encode(cinfo, st, 0);
+      /* Section F.1.4.4.1.2: Establish dc_context conditioning category */
+      if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
+	entropy->dc_context[ci] = 0;	/* zero diff category */
+      else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
+	entropy->dc_context[ci] += 8;	/* large diff category */
+      /* Figure F.9: Encoding the magnitude bit pattern of v */
+      st += 14;
+      while (m >>= 1)
+	arith_encode(cinfo, st, (m & v) ? 1 : 0);
+    }
+
+    /* Sections F.1.4.2 & F.1.4.4.2: Encoding of AC coefficients */
+
+    if ((ke = cinfo->lim_Se) == 0) continue;
+    tbl = compptr->ac_tbl_no;
+
+    /* Establish EOB (end-of-block) index */
+    do {
+      if ((*block)[natural_order[ke]]) break;
+    } while (--ke);
+
+    /* Figure F.5: Encode_AC_Coefficients */
+    for (k = 0; k < ke;) {
+      st = entropy->ac_stats[tbl] + 3 * k;
+      arith_encode(cinfo, st, 0);	/* EOB decision */
+      while ((v = (*block)[natural_order[++k]]) == 0) {
+	arith_encode(cinfo, st + 1, 0);
+	st += 3;
+      }
+      arith_encode(cinfo, st + 1, 1);
+      /* Figure F.6: Encoding nonzero value v */
+      /* Figure F.7: Encoding the sign of v */
+      if (v > 0) {
+	arith_encode(cinfo, entropy->fixed_bin, 0);
+      } else {
+	v = -v;
+	arith_encode(cinfo, entropy->fixed_bin, 1);
+      }
+      st += 2;
+      /* Figure F.8: Encoding the magnitude category of v */
+      m = 0;
+      if (v -= 1) {
+	arith_encode(cinfo, st, 1);
+	m = 1;
+	v2 = v;
+	if (v2 >>= 1) {
+	  arith_encode(cinfo, st, 1);
+	  m <<= 1;
+	  st = entropy->ac_stats[tbl] +
+	       (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
+	  while (v2 >>= 1) {
+	    arith_encode(cinfo, st, 1);
+	    m <<= 1;
+	    st += 1;
+	  }
+	}
+      }
+      arith_encode(cinfo, st, 0);
+      /* Figure F.9: Encoding the magnitude bit pattern of v */
+      st += 14;
+      while (m >>= 1)
+	arith_encode(cinfo, st, (m & v) ? 1 : 0);
+    }
+    /* Encode EOB decision only if k < cinfo->lim_Se */
+    if (k < cinfo->lim_Se) {
+      st = entropy->ac_stats[tbl] + 3 * k;
+      arith_encode(cinfo, st, 1);
+    }
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * Initialize for an arithmetic-compressed scan.
+ */
+
+METHODDEF(void)
+start_pass (j_compress_ptr cinfo, boolean gather_statistics)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  int ci, tbl;
+  jpeg_component_info * compptr;
+
+  if (gather_statistics)
+    /* Make sure to avoid that in the master control logic!
+     * We are fully adaptive here and need no extra
+     * statistics gathering pass!
+     */
+    ERREXIT(cinfo, JERR_NOT_COMPILED);
+
+  /* We assume jcmaster.c already validated the progressive scan parameters. */
+
+  /* Select execution routines */
+  if (cinfo->progressive_mode) {
+    if (cinfo->Ah == 0) {
+      if (cinfo->Ss == 0)
+	entropy->pub.encode_mcu = encode_mcu_DC_first;
+      else
+	entropy->pub.encode_mcu = encode_mcu_AC_first;
+    } else {
+      if (cinfo->Ss == 0)
+	entropy->pub.encode_mcu = encode_mcu_DC_refine;
+      else
+	entropy->pub.encode_mcu = encode_mcu_AC_refine;
+    }
+  } else
+    entropy->pub.encode_mcu = encode_mcu;
+
+  /* Allocate & initialize requested statistics areas */
+  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+    compptr = cinfo->cur_comp_info[ci];
+    /* DC needs no table for refinement scan */
+    if (cinfo->Ss == 0 && cinfo->Ah == 0) {
+      tbl = compptr->dc_tbl_no;
+      if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
+	ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
+      if (entropy->dc_stats[tbl] == NULL)
+	entropy->dc_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
+	  ((j_common_ptr) cinfo, JPOOL_IMAGE, DC_STAT_BINS);
+      MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS);
+      /* Initialize DC predictions to 0 */
+      entropy->last_dc_val[ci] = 0;
+      entropy->dc_context[ci] = 0;
+    }
+    /* AC needs no table when not present */
+    if (cinfo->Se) {
+      tbl = compptr->ac_tbl_no;
+      if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
+	ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
+      if (entropy->ac_stats[tbl] == NULL)
+	entropy->ac_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
+	  ((j_common_ptr) cinfo, JPOOL_IMAGE, AC_STAT_BINS);
+      MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS);
+#ifdef CALCULATE_SPECTRAL_CONDITIONING
+      if (cinfo->progressive_mode)
+	/* Section G.1.3.2: Set appropriate arithmetic conditioning value Kx */
+	cinfo->arith_ac_K[tbl] = cinfo->Ss + ((8 + cinfo->Se - cinfo->Ss) >> 4);
+#endif
+    }
+  }
+
+  /* Initialize arithmetic encoding variables */
+  entropy->c = 0;
+  entropy->a = 0x10000L;
+  entropy->sc = 0;
+  entropy->zc = 0;
+  entropy->ct = 11;
+  entropy->buffer = -1;  /* empty */
+
+  /* Initialize restart stuff */
+  entropy->restarts_to_go = cinfo->restart_interval;
+  entropy->next_restart_num = 0;
+}
+
+
+/*
+ * Module initialization routine for arithmetic entropy encoding.
+ */
+
+GLOBAL(void)
+jinit_arith_encoder (j_compress_ptr cinfo)
+{
+  arith_entropy_ptr entropy;
+  int i;
+
+  entropy = (arith_entropy_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(arith_entropy_encoder));
+  cinfo->entropy = &entropy->pub;
+  entropy->pub.start_pass = start_pass;
+  entropy->pub.finish_pass = finish_pass;
+
+  /* Mark tables unallocated */
+  for (i = 0; i < NUM_ARITH_TBLS; i++) {
+    entropy->dc_stats[i] = NULL;
+    entropy->ac_stats[i] = NULL;
+  }
+
+  /* Initialize index for fixed probability estimation */
+  entropy->fixed_bin[0] = 113;
+}
diff --git a/source/Irrlicht/jpeglib/jccoefct.c b/source/Irrlicht/jpeglib/jccoefct.c
new file mode 100644
index 00000000..b64b46e7
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jccoefct.c
@@ -0,0 +1,454 @@
+/*
+ * jccoefct.c
+ *
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * Modified 2003-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the coefficient buffer controller for compression.
+ * This controller is the top level of the JPEG compressor proper.
+ * The coefficient buffer lies between forward-DCT and entropy encoding steps.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* We use a full-image coefficient buffer when doing Huffman optimization,
+ * and also for writing multiple-scan JPEG files.  In all cases, the DCT
+ * step is run during the first pass, and subsequent passes need only read
+ * the buffered coefficients.
+ */
+#ifdef ENTROPY_OPT_SUPPORTED
+#define FULL_COEF_BUFFER_SUPPORTED
+#else
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+#define FULL_COEF_BUFFER_SUPPORTED
+#endif
+#endif
+
+
+/* Private buffer controller object */
+
+typedef struct {
+  struct jpeg_c_coef_controller pub; /* public fields */
+
+  JDIMENSION iMCU_row_num;	/* iMCU row # within image */
+  JDIMENSION mcu_ctr;		/* counts MCUs processed in current row */
+  int MCU_vert_offset;		/* counts MCU rows within iMCU row */
+  int MCU_rows_per_iMCU_row;	/* number of such rows needed */
+
+  /* For single-pass compression, it's sufficient to buffer just one MCU
+   * (although this may prove a bit slow in practice).  We allocate a
+   * workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, and reuse it for each
+   * MCU constructed and sent.  (On 80x86, the workspace is FAR even though
+   * it's not really very big; this is to keep the module interfaces unchanged
+   * when a large coefficient buffer is necessary.)
+   * In multi-pass modes, this array points to the current MCU's blocks
+   * within the virtual arrays.
+   */
+  JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU];
+
+  /* In multi-pass modes, we need a virtual block array for each component. */
+  jvirt_barray_ptr whole_image[MAX_COMPONENTS];
+} my_coef_controller;
+
+typedef my_coef_controller * my_coef_ptr;
+
+
+/* Forward declarations */
+METHODDEF(boolean) compress_data
+    JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
+#ifdef FULL_COEF_BUFFER_SUPPORTED
+METHODDEF(boolean) compress_first_pass
+    JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
+METHODDEF(boolean) compress_output
+    JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
+#endif
+
+
+LOCAL(void)
+start_iMCU_row (j_compress_ptr cinfo)
+/* Reset within-iMCU-row counters for a new row */
+{
+  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+  /* In an interleaved scan, an MCU row is the same as an iMCU row.
+   * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
+   * But at the bottom of the image, process only what's left.
+   */
+  if (cinfo->comps_in_scan > 1) {
+    coef->MCU_rows_per_iMCU_row = 1;
+  } else {
+    if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1))
+      coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
+    else
+      coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
+  }
+
+  coef->mcu_ctr = 0;
+  coef->MCU_vert_offset = 0;
+}
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+  coef->iMCU_row_num = 0;
+  start_iMCU_row(cinfo);
+
+  switch (pass_mode) {
+  case JBUF_PASS_THRU:
+    if (coef->whole_image[0] != NULL)
+      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+    coef->pub.compress_data = compress_data;
+    break;
+#ifdef FULL_COEF_BUFFER_SUPPORTED
+  case JBUF_SAVE_AND_PASS:
+    if (coef->whole_image[0] == NULL)
+      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+    coef->pub.compress_data = compress_first_pass;
+    break;
+  case JBUF_CRANK_DEST:
+    if (coef->whole_image[0] == NULL)
+      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+    coef->pub.compress_data = compress_output;
+    break;
+#endif
+  default:
+    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+    break;
+  }
+}
+
+
+/*
+ * Process some data in the single-pass case.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor block rows for each component in the image.
+ * Returns TRUE if the iMCU row is completed, FALSE if suspended.
+ *
+ * NB: input_buf contains a plane for each component in image,
+ * which we index according to the component's SOF position.
+ */
+
+METHODDEF(boolean)
+compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+{
+  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+  JDIMENSION MCU_col_num;	/* index of current MCU within row */
+  JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
+  JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+  int blkn, bi, ci, yindex, yoffset, blockcnt;
+  JDIMENSION ypos, xpos;
+  jpeg_component_info *compptr;
+  forward_DCT_ptr forward_DCT;
+
+  /* Loop to write as much as one whole iMCU row */
+  for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+       yoffset++) {
+    for (MCU_col_num = coef->mcu_ctr; MCU_col_num <= last_MCU_col;
+	 MCU_col_num++) {
+      /* Determine where data comes from in input_buf and do the DCT thing.
+       * Each call on forward_DCT processes a horizontal row of DCT blocks
+       * as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks
+       * sequentially.  Dummy blocks at the right or bottom edge are filled in
+       * specially.  The data in them does not matter for image reconstruction,
+       * so we fill them with values that will encode to the smallest amount of
+       * data, viz: all zeroes in the AC entries, DC entries equal to previous
+       * block's DC value.  (Thanks to Thomas Kinsman for this idea.)
+       */
+      blkn = 0;
+      for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+	compptr = cinfo->cur_comp_info[ci];
+	forward_DCT = cinfo->fdct->forward_DCT[compptr->component_index];
+	blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
+						: compptr->last_col_width;
+	xpos = MCU_col_num * compptr->MCU_sample_width;
+	ypos = yoffset * compptr->DCT_v_scaled_size;
+	/* ypos == (yoffset+yindex) * DCTSIZE */
+	for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+	  if (coef->iMCU_row_num < last_iMCU_row ||
+	      yoffset+yindex < compptr->last_row_height) {
+	    (*forward_DCT) (cinfo, compptr,
+			    input_buf[compptr->component_index],
+			    coef->MCU_buffer[blkn],
+			    ypos, xpos, (JDIMENSION) blockcnt);
+	    if (blockcnt < compptr->MCU_width) {
+	      /* Create some dummy blocks at the right edge of the image. */
+	      FMEMZERO((void FAR *) coef->MCU_buffer[blkn + blockcnt],
+		       (compptr->MCU_width - blockcnt) * SIZEOF(JBLOCK));
+	      for (bi = blockcnt; bi < compptr->MCU_width; bi++) {
+		coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn+bi-1][0][0];
+	      }
+	    }
+	  } else {
+	    /* Create a row of dummy blocks at the bottom of the image. */
+	    FMEMZERO((void FAR *) coef->MCU_buffer[blkn],
+		     compptr->MCU_width * SIZEOF(JBLOCK));
+	    for (bi = 0; bi < compptr->MCU_width; bi++) {
+	      coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn-1][0][0];
+	    }
+	  }
+	  blkn += compptr->MCU_width;
+	  ypos += compptr->DCT_v_scaled_size;
+	}
+      }
+      /* Try to write the MCU.  In event of a suspension failure, we will
+       * re-DCT the MCU on restart (a bit inefficient, could be fixed...)
+       */
+      if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) {
+	/* Suspension forced; update state counters and exit */
+	coef->MCU_vert_offset = yoffset;
+	coef->mcu_ctr = MCU_col_num;
+	return FALSE;
+      }
+    }
+    /* Completed an MCU row, but perhaps not an iMCU row */
+    coef->mcu_ctr = 0;
+  }
+  /* Completed the iMCU row, advance counters for next one */
+  coef->iMCU_row_num++;
+  start_iMCU_row(cinfo);
+  return TRUE;
+}
+
+
+#ifdef FULL_COEF_BUFFER_SUPPORTED
+
+/*
+ * Process some data in the first pass of a multi-pass case.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor block rows for each component in the image.
+ * This amount of data is read from the source buffer, DCT'd and quantized,
+ * and saved into the virtual arrays.  We also generate suitable dummy blocks
+ * as needed at the right and lower edges.  (The dummy blocks are constructed
+ * in the virtual arrays, which have been padded appropriately.)  This makes
+ * it possible for subsequent passes not to worry about real vs. dummy blocks.
+ *
+ * We must also emit the data to the entropy encoder.  This is conveniently
+ * done by calling compress_output() after we've loaded the current strip
+ * of the virtual arrays.
+ *
+ * NB: input_buf contains a plane for each component in image.  All
+ * components are DCT'd and loaded into the virtual arrays in this pass.
+ * However, it may be that only a subset of the components are emitted to
+ * the entropy encoder during this first pass; be careful about looking
+ * at the scan-dependent variables (MCU dimensions, etc).
+ */
+
+METHODDEF(boolean)
+compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+{
+  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+  JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+  JDIMENSION blocks_across, MCUs_across, MCUindex;
+  int bi, ci, h_samp_factor, block_row, block_rows, ndummy;
+  JCOEF lastDC;
+  jpeg_component_info *compptr;
+  JBLOCKARRAY buffer;
+  JBLOCKROW thisblockrow, lastblockrow;
+  forward_DCT_ptr forward_DCT;
+
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    /* Align the virtual buffer for this component. */
+    buffer = (*cinfo->mem->access_virt_barray)
+      ((j_common_ptr) cinfo, coef->whole_image[ci],
+       coef->iMCU_row_num * compptr->v_samp_factor,
+       (JDIMENSION) compptr->v_samp_factor, TRUE);
+    /* Count non-dummy DCT block rows in this iMCU row. */
+    if (coef->iMCU_row_num < last_iMCU_row)
+      block_rows = compptr->v_samp_factor;
+    else {
+      /* NB: can't use last_row_height here, since may not be set! */
+      block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+      if (block_rows == 0) block_rows = compptr->v_samp_factor;
+    }
+    blocks_across = compptr->width_in_blocks;
+    h_samp_factor = compptr->h_samp_factor;
+    /* Count number of dummy blocks to be added at the right margin. */
+    ndummy = (int) (blocks_across % h_samp_factor);
+    if (ndummy > 0)
+      ndummy = h_samp_factor - ndummy;
+    forward_DCT = cinfo->fdct->forward_DCT[ci];
+    /* Perform DCT for all non-dummy blocks in this iMCU row.  Each call
+     * on forward_DCT processes a complete horizontal row of DCT blocks.
+     */
+    for (block_row = 0; block_row < block_rows; block_row++) {
+      thisblockrow = buffer[block_row];
+      (*forward_DCT) (cinfo, compptr, input_buf[ci], thisblockrow,
+		      (JDIMENSION) (block_row * compptr->DCT_v_scaled_size),
+		      (JDIMENSION) 0, blocks_across);
+      if (ndummy > 0) {
+	/* Create dummy blocks at the right edge of the image. */
+	thisblockrow += blocks_across; /* => first dummy block */
+	FMEMZERO((void FAR *) thisblockrow, ndummy * SIZEOF(JBLOCK));
+	lastDC = thisblockrow[-1][0];
+	for (bi = 0; bi < ndummy; bi++) {
+	  thisblockrow[bi][0] = lastDC;
+	}
+      }
+    }
+    /* If at end of image, create dummy block rows as needed.
+     * The tricky part here is that within each MCU, we want the DC values
+     * of the dummy blocks to match the last real block's DC value.
+     * This squeezes a few more bytes out of the resulting file...
+     */
+    if (coef->iMCU_row_num == last_iMCU_row) {
+      blocks_across += ndummy;	/* include lower right corner */
+      MCUs_across = blocks_across / h_samp_factor;
+      for (block_row = block_rows; block_row < compptr->v_samp_factor;
+	   block_row++) {
+	thisblockrow = buffer[block_row];
+	lastblockrow = buffer[block_row-1];
+	FMEMZERO((void FAR *) thisblockrow,
+		 (size_t) (blocks_across * SIZEOF(JBLOCK)));
+	for (MCUindex = 0; MCUindex < MCUs_across; MCUindex++) {
+	  lastDC = lastblockrow[h_samp_factor-1][0];
+	  for (bi = 0; bi < h_samp_factor; bi++) {
+	    thisblockrow[bi][0] = lastDC;
+	  }
+	  thisblockrow += h_samp_factor; /* advance to next MCU in row */
+	  lastblockrow += h_samp_factor;
+	}
+      }
+    }
+  }
+  /* NB: compress_output will increment iMCU_row_num if successful.
+   * A suspension return will result in redoing all the work above next time.
+   */
+
+  /* Emit data to the entropy encoder, sharing code with subsequent passes */
+  return compress_output(cinfo, input_buf);
+}
+
+
+/*
+ * Process some data in subsequent passes of a multi-pass case.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor block rows for each component in the scan.
+ * The data is obtained from the virtual arrays and fed to the entropy coder.
+ * Returns TRUE if the iMCU row is completed, FALSE if suspended.
+ *
+ * NB: input_buf is ignored; it is likely to be a NULL pointer.
+ */
+
+METHODDEF(boolean)
+compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+{
+  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+  JDIMENSION MCU_col_num;	/* index of current MCU within row */
+  int blkn, ci, xindex, yindex, yoffset;
+  JDIMENSION start_col;
+  JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];
+  JBLOCKROW buffer_ptr;
+  jpeg_component_info *compptr;
+
+  /* Align the virtual buffers for the components used in this scan.
+   * NB: during first pass, this is safe only because the buffers will
+   * already be aligned properly, so jmemmgr.c won't need to do any I/O.
+   */
+  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+    compptr = cinfo->cur_comp_info[ci];
+    buffer[ci] = (*cinfo->mem->access_virt_barray)
+      ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],
+       coef->iMCU_row_num * compptr->v_samp_factor,
+       (JDIMENSION) compptr->v_samp_factor, FALSE);
+  }
+
+  /* Loop to process one whole iMCU row */
+  for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+       yoffset++) {
+    for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row;
+	 MCU_col_num++) {
+      /* Construct list of pointers to DCT blocks belonging to this MCU */
+      blkn = 0;			/* index of current DCT block within MCU */
+      for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+	compptr = cinfo->cur_comp_info[ci];
+	start_col = MCU_col_num * compptr->MCU_width;
+	for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+	  buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
+	  for (xindex = 0; xindex < compptr->MCU_width; xindex++) {
+	    coef->MCU_buffer[blkn++] = buffer_ptr++;
+	  }
+	}
+      }
+      /* Try to write the MCU. */
+      if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) {
+	/* Suspension forced; update state counters and exit */
+	coef->MCU_vert_offset = yoffset;
+	coef->mcu_ctr = MCU_col_num;
+	return FALSE;
+      }
+    }
+    /* Completed an MCU row, but perhaps not an iMCU row */
+    coef->mcu_ctr = 0;
+  }
+  /* Completed the iMCU row, advance counters for next one */
+  coef->iMCU_row_num++;
+  start_iMCU_row(cinfo);
+  return TRUE;
+}
+
+#endif /* FULL_COEF_BUFFER_SUPPORTED */
+
+
+/*
+ * Initialize coefficient buffer controller.
+ */
+
+GLOBAL(void)
+jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer)
+{
+  my_coef_ptr coef;
+
+  coef = (my_coef_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(my_coef_controller));
+  cinfo->coef = (struct jpeg_c_coef_controller *) coef;
+  coef->pub.start_pass = start_pass_coef;
+
+  /* Create the coefficient buffer. */
+  if (need_full_buffer) {
+#ifdef FULL_COEF_BUFFER_SUPPORTED
+    /* Allocate a full-image virtual array for each component, */
+    /* padded to a multiple of samp_factor DCT blocks in each direction. */
+    int ci;
+    jpeg_component_info *compptr;
+
+    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+	 ci++, compptr++) {
+      coef->whole_image[ci] = (*cinfo->mem->request_virt_barray)
+	((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+	 (JDIMENSION) jround_up((long) compptr->width_in_blocks,
+				(long) compptr->h_samp_factor),
+	 (JDIMENSION) jround_up((long) compptr->height_in_blocks,
+				(long) compptr->v_samp_factor),
+	 (JDIMENSION) compptr->v_samp_factor);
+    }
+#else
+    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+#endif
+  } else {
+    /* We only need a single-MCU buffer. */
+    JBLOCKROW buffer;
+    int i;
+
+    buffer = (JBLOCKROW)
+      (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
+    for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) {
+      coef->MCU_buffer[i] = buffer + i;
+    }
+    coef->whole_image[0] = NULL; /* flag for no virtual arrays */
+  }
+}
diff --git a/source/Irrlicht/jpeglib/jccolor.c b/source/Irrlicht/jpeglib/jccolor.c
new file mode 100644
index 00000000..aac5802e
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jccolor.c
@@ -0,0 +1,604 @@
+/*
+ * jccolor.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * Modified 2011-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains input colorspace conversion routines.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private subobject */
+
+typedef struct {
+  struct jpeg_color_converter pub; /* public fields */
+
+  /* Private state for RGB->YCC conversion */
+  INT32 * rgb_ycc_tab;		/* => table for RGB to YCbCr conversion */
+} my_color_converter;
+
+typedef my_color_converter * my_cconvert_ptr;
+
+
+/**************** RGB -> YCbCr conversion: most common case **************/
+
+/*
+ * YCbCr is defined per Recommendation ITU-R BT.601-7 (03/2011),
+ * previously known as Recommendation CCIR 601-1, except that Cb and Cr
+ * are normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
+ * sRGB (standard RGB color space) is defined per IEC 61966-2-1:1999.
+ * sYCC (standard luma-chroma-chroma color space with extended gamut)
+ * is defined per IEC 61966-2-1:1999 Amendment A1:2003 Annex F.
+ * bg-sRGB and bg-sYCC (big gamut standard color spaces)
+ * are defined per IEC 61966-2-1:1999 Amendment A1:2003 Annex G.
+ * Note that the derived conversion coefficients given in some of these
+ * documents are imprecise.  The general conversion equations are
+ *	Y  = Kr * R + (1 - Kr - Kb) * G + Kb * B
+ *	Cb = 0.5 * (B - Y) / (1 - Kb)
+ *	Cr = 0.5 * (R - Y) / (1 - Kr)
+ * With Kr = 0.299 and Kb = 0.114 (derived according to SMPTE RP 177-1993
+ * from the 1953 FCC NTSC primaries and CIE Illuminant C),
+ * the conversion equations to be implemented are therefore
+ *	Y  =  0.299 * R + 0.587 * G + 0.114 * B
+ *	Cb = -0.168735892 * R - 0.331264108 * G + 0.5 * B + CENTERJSAMPLE
+ *	Cr =  0.5 * R - 0.418687589 * G - 0.081312411 * B + CENTERJSAMPLE
+ * Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2,
+ * rather than CENTERJSAMPLE, for Cb and Cr.  This gave equal positive and
+ * negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0)
+ * were not represented exactly.  Now we sacrifice exact representation of
+ * maximum red and maximum blue in order to get exact grayscales.
+ *
+ * To avoid floating-point arithmetic, we represent the fractional constants
+ * as integers scaled up by 2^16 (about 4 digits precision); we have to divide
+ * the products by 2^16, with appropriate rounding, to get the correct answer.
+ *
+ * For even more speed, we avoid doing any multiplications in the inner loop
+ * by precalculating the constants times R,G,B for all possible values.
+ * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
+ * for 9-bit to 12-bit samples it is still acceptable.  It's not very
+ * reasonable for 16-bit samples, but if you want lossless storage you
+ * shouldn't be changing colorspace anyway.
+ * The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included
+ * in the tables to save adding them separately in the inner loop.
+ */
+
+#define SCALEBITS	16	/* speediest right-shift on some machines */
+#define CBCR_OFFSET	((INT32) CENTERJSAMPLE << SCALEBITS)
+#define ONE_HALF	((INT32) 1 << (SCALEBITS-1))
+#define FIX(x)		((INT32) ((x) * (1L< Y section */
+#define G_Y_OFF		(1*(MAXJSAMPLE+1))	/* offset to G => Y section */
+#define B_Y_OFF		(2*(MAXJSAMPLE+1))	/* etc. */
+#define R_CB_OFF	(3*(MAXJSAMPLE+1))
+#define G_CB_OFF	(4*(MAXJSAMPLE+1))
+#define B_CB_OFF	(5*(MAXJSAMPLE+1))
+#define R_CR_OFF	B_CB_OFF		/* B=>Cb, R=>Cr are the same */
+#define G_CR_OFF	(6*(MAXJSAMPLE+1))
+#define B_CR_OFF	(7*(MAXJSAMPLE+1))
+#define TABLE_SIZE	(8*(MAXJSAMPLE+1))
+
+
+/*
+ * Initialize for RGB->YCC colorspace conversion.
+ */
+
+METHODDEF(void)
+rgb_ycc_start (j_compress_ptr cinfo)
+{
+  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+  INT32 * rgb_ycc_tab;
+  INT32 i;
+
+  /* Allocate and fill in the conversion tables. */
+  cconvert->rgb_ycc_tab = rgb_ycc_tab = (INT32 *)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				(TABLE_SIZE * SIZEOF(INT32)));
+
+  for (i = 0; i <= MAXJSAMPLE; i++) {
+    rgb_ycc_tab[i+R_Y_OFF] = FIX(0.299) * i;
+    rgb_ycc_tab[i+G_Y_OFF] = FIX(0.587) * i;
+    rgb_ycc_tab[i+B_Y_OFF] = FIX(0.114) * i   + ONE_HALF;
+    rgb_ycc_tab[i+R_CB_OFF] = (-FIX(0.168735892)) * i;
+    rgb_ycc_tab[i+G_CB_OFF] = (-FIX(0.331264108)) * i;
+    /* We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr.
+     * This ensures that the maximum output will round to MAXJSAMPLE
+     * not MAXJSAMPLE+1, and thus that we don't have to range-limit.
+     */
+    rgb_ycc_tab[i+B_CB_OFF] = FIX(0.5) * i    + CBCR_OFFSET + ONE_HALF-1;
+/*  B=>Cb and R=>Cr tables are the same
+    rgb_ycc_tab[i+R_CR_OFF] = FIX(0.5) * i    + CBCR_OFFSET + ONE_HALF-1;
+*/
+    rgb_ycc_tab[i+G_CR_OFF] = (-FIX(0.418687589)) * i;
+    rgb_ycc_tab[i+B_CR_OFF] = (-FIX(0.081312411)) * i;
+  }
+}
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ *
+ * Note that we change from the application's interleaved-pixel format
+ * to our internal noninterleaved, one-plane-per-component format.
+ * The input buffer is therefore three times as wide as the output buffer.
+ *
+ * A starting row offset is provided only for the output buffer.  The caller
+ * can easily adjust the passed input_buf value to accommodate any row
+ * offset required on that side.
+ */
+
+METHODDEF(void)
+rgb_ycc_convert (j_compress_ptr cinfo,
+		 JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+		 JDIMENSION output_row, int num_rows)
+{
+  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+  register INT32 * ctab = cconvert->rgb_ycc_tab;
+  register int r, g, b;
+  register JSAMPROW inptr;
+  register JSAMPROW outptr0, outptr1, outptr2;
+  register JDIMENSION col;
+  JDIMENSION num_cols = cinfo->image_width;
+
+  while (--num_rows >= 0) {
+    inptr = *input_buf++;
+    outptr0 = output_buf[0][output_row];
+    outptr1 = output_buf[1][output_row];
+    outptr2 = output_buf[2][output_row];
+    output_row++;
+    for (col = 0; col < num_cols; col++) {
+      r = GETJSAMPLE(inptr[RGB_RED]);
+      g = GETJSAMPLE(inptr[RGB_GREEN]);
+      b = GETJSAMPLE(inptr[RGB_BLUE]);
+      /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
+       * must be too; we do not need an explicit range-limiting operation.
+       * Hence the value being shifted is never negative, and we don't
+       * need the general RIGHT_SHIFT macro.
+       */
+      /* Y */
+      outptr0[col] = (JSAMPLE)
+		((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
+		 >> SCALEBITS);
+      /* Cb */
+      outptr1[col] = (JSAMPLE)
+		((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF])
+		 >> SCALEBITS);
+      /* Cr */
+      outptr2[col] = (JSAMPLE)
+		((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF])
+		 >> SCALEBITS);
+      inptr += RGB_PIXELSIZE;
+    }
+  }
+}
+
+
+/**************** Cases other than RGB -> YCbCr **************/
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ * This version handles RGB->grayscale conversion, which is the same
+ * as the RGB->Y portion of RGB->YCbCr.
+ * We assume rgb_ycc_start has been called (we only use the Y tables).
+ */
+
+METHODDEF(void)
+rgb_gray_convert (j_compress_ptr cinfo,
+		  JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+		  JDIMENSION output_row, int num_rows)
+{
+  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+  register INT32 * ctab = cconvert->rgb_ycc_tab;
+  register int r, g, b;
+  register JSAMPROW inptr;
+  register JSAMPROW outptr;
+  register JDIMENSION col;
+  JDIMENSION num_cols = cinfo->image_width;
+
+  while (--num_rows >= 0) {
+    inptr = *input_buf++;
+    outptr = output_buf[0][output_row++];
+    for (col = 0; col < num_cols; col++) {
+      r = GETJSAMPLE(inptr[RGB_RED]);
+      g = GETJSAMPLE(inptr[RGB_GREEN]);
+      b = GETJSAMPLE(inptr[RGB_BLUE]);
+      /* Y */
+      outptr[col] = (JSAMPLE)
+		((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
+		 >> SCALEBITS);
+      inptr += RGB_PIXELSIZE;
+    }
+  }
+}
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ * This version handles Adobe-style CMYK->YCCK conversion,
+ * where we convert R=1-C, G=1-M, and B=1-Y to YCbCr using the same
+ * conversion as above, while passing K (black) unchanged.
+ * We assume rgb_ycc_start has been called.
+ */
+
+METHODDEF(void)
+cmyk_ycck_convert (j_compress_ptr cinfo,
+		   JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+		   JDIMENSION output_row, int num_rows)
+{
+  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+  register INT32 * ctab = cconvert->rgb_ycc_tab;
+  register int r, g, b;
+  register JSAMPROW inptr;
+  register JSAMPROW outptr0, outptr1, outptr2, outptr3;
+  register JDIMENSION col;
+  JDIMENSION num_cols = cinfo->image_width;
+
+  while (--num_rows >= 0) {
+    inptr = *input_buf++;
+    outptr0 = output_buf[0][output_row];
+    outptr1 = output_buf[1][output_row];
+    outptr2 = output_buf[2][output_row];
+    outptr3 = output_buf[3][output_row];
+    output_row++;
+    for (col = 0; col < num_cols; col++) {
+      r = MAXJSAMPLE - GETJSAMPLE(inptr[0]);
+      g = MAXJSAMPLE - GETJSAMPLE(inptr[1]);
+      b = MAXJSAMPLE - GETJSAMPLE(inptr[2]);
+      /* K passes through as-is */
+      outptr3[col] = inptr[3];	/* don't need GETJSAMPLE here */
+      /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
+       * must be too; we do not need an explicit range-limiting operation.
+       * Hence the value being shifted is never negative, and we don't
+       * need the general RIGHT_SHIFT macro.
+       */
+      /* Y */
+      outptr0[col] = (JSAMPLE)
+		((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
+		 >> SCALEBITS);
+      /* Cb */
+      outptr1[col] = (JSAMPLE)
+		((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF])
+		 >> SCALEBITS);
+      /* Cr */
+      outptr2[col] = (JSAMPLE)
+		((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF])
+		 >> SCALEBITS);
+      inptr += 4;
+    }
+  }
+}
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ * [R,G,B] to [R-G,G,B-G] conversion with modulo calculation
+ * (forward reversible color transform).
+ * This can be seen as an adaption of the general RGB->YCbCr
+ * conversion equation with Kr = Kb = 0, while replacing the
+ * normalization by modulo calculation.
+ */
+
+METHODDEF(void)
+rgb_rgb1_convert (j_compress_ptr cinfo,
+		  JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+		  JDIMENSION output_row, int num_rows)
+{
+  register int r, g, b;
+  register JSAMPROW inptr;
+  register JSAMPROW outptr0, outptr1, outptr2;
+  register JDIMENSION col;
+  JDIMENSION num_cols = cinfo->image_width;
+
+  while (--num_rows >= 0) {
+    inptr = *input_buf++;
+    outptr0 = output_buf[0][output_row];
+    outptr1 = output_buf[1][output_row];
+    outptr2 = output_buf[2][output_row];
+    output_row++;
+    for (col = 0; col < num_cols; col++) {
+      r = GETJSAMPLE(inptr[RGB_RED]);
+      g = GETJSAMPLE(inptr[RGB_GREEN]);
+      b = GETJSAMPLE(inptr[RGB_BLUE]);
+      /* Assume that MAXJSAMPLE+1 is a power of 2, so that the MOD
+       * (modulo) operator is equivalent to the bitmask operator AND.
+       */
+      outptr0[col] = (JSAMPLE) ((r - g + CENTERJSAMPLE) & MAXJSAMPLE);
+      outptr1[col] = (JSAMPLE) g;
+      outptr2[col] = (JSAMPLE) ((b - g + CENTERJSAMPLE) & MAXJSAMPLE);
+      inptr += RGB_PIXELSIZE;
+    }
+  }
+}
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ * This version handles grayscale output with no conversion.
+ * The source can be either plain grayscale or YCC (since Y == gray).
+ */
+
+METHODDEF(void)
+grayscale_convert (j_compress_ptr cinfo,
+		   JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+		   JDIMENSION output_row, int num_rows)
+{
+  int instride = cinfo->input_components;
+  register JSAMPROW inptr;
+  register JSAMPROW outptr;
+  register JDIMENSION col;
+  JDIMENSION num_cols = cinfo->image_width;
+
+  while (--num_rows >= 0) {
+    inptr = *input_buf++;
+    outptr = output_buf[0][output_row++];
+    for (col = 0; col < num_cols; col++) {
+      outptr[col] = inptr[0];	/* don't need GETJSAMPLE() here */
+      inptr += instride;
+    }
+  }
+}
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ * No colorspace conversion, but change from interleaved
+ * to separate-planes representation.
+ */
+
+METHODDEF(void)
+rgb_convert (j_compress_ptr cinfo,
+	     JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+	     JDIMENSION output_row, int num_rows)
+{
+  register JSAMPROW inptr;
+  register JSAMPROW outptr0, outptr1, outptr2;
+  register JDIMENSION col;
+  JDIMENSION num_cols = cinfo->image_width;
+
+  while (--num_rows >= 0) {
+    inptr = *input_buf++;
+    outptr0 = output_buf[0][output_row];
+    outptr1 = output_buf[1][output_row];
+    outptr2 = output_buf[2][output_row];
+    output_row++;
+    for (col = 0; col < num_cols; col++) {
+      /* We can dispense with GETJSAMPLE() here */
+      outptr0[col] = inptr[RGB_RED];
+      outptr1[col] = inptr[RGB_GREEN];
+      outptr2[col] = inptr[RGB_BLUE];
+      inptr += RGB_PIXELSIZE;
+    }
+  }
+}
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ * This version handles multi-component colorspaces without conversion.
+ * We assume input_components == num_components.
+ */
+
+METHODDEF(void)
+null_convert (j_compress_ptr cinfo,
+	      JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+	      JDIMENSION output_row, int num_rows)
+{
+  int ci;
+  register int nc = cinfo->num_components;
+  register JSAMPROW inptr;
+  register JSAMPROW outptr;
+  register JDIMENSION col;
+  JDIMENSION num_cols = cinfo->image_width;
+
+  while (--num_rows >= 0) {
+    /* It seems fastest to make a separate pass for each component. */
+    for (ci = 0; ci < nc; ci++) {
+      inptr = input_buf[0] + ci;
+      outptr = output_buf[ci][output_row];
+      for (col = 0; col < num_cols; col++) {
+	*outptr++ = *inptr;	/* don't need GETJSAMPLE() here */
+	inptr += nc;
+      }
+    }
+    input_buf++;
+    output_row++;
+  }
+}
+
+
+/*
+ * Empty method for start_pass.
+ */
+
+METHODDEF(void)
+null_method (j_compress_ptr cinfo)
+{
+  /* no work needed */
+}
+
+
+/*
+ * Module initialization routine for input colorspace conversion.
+ */
+
+GLOBAL(void)
+jinit_color_converter (j_compress_ptr cinfo)
+{
+  my_cconvert_ptr cconvert;
+
+  cconvert = (my_cconvert_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(my_color_converter));
+  cinfo->cconvert = &cconvert->pub;
+  /* set start_pass to null method until we find out differently */
+  cconvert->pub.start_pass = null_method;
+
+  /* Make sure input_components agrees with in_color_space */
+  switch (cinfo->in_color_space) {
+  case JCS_GRAYSCALE:
+    if (cinfo->input_components != 1)
+      ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+    break;
+
+  case JCS_RGB:
+  case JCS_BG_RGB:
+    if (cinfo->input_components != RGB_PIXELSIZE)
+      ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+    break;
+
+  case JCS_YCbCr:
+  case JCS_BG_YCC:
+    if (cinfo->input_components != 3)
+      ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+    break;
+
+  case JCS_CMYK:
+  case JCS_YCCK:
+    if (cinfo->input_components != 4)
+      ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+    break;
+
+  default:			/* JCS_UNKNOWN can be anything */
+    if (cinfo->input_components < 1)
+      ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+    break;
+  }
+
+  /* Support color transform only for RGB colorspaces */
+  if (cinfo->color_transform &&
+      cinfo->jpeg_color_space != JCS_RGB &&
+      cinfo->jpeg_color_space != JCS_BG_RGB)
+    ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+
+  /* Check num_components, set conversion method based on requested space */
+  switch (cinfo->jpeg_color_space) {
+  case JCS_GRAYSCALE:
+    if (cinfo->num_components != 1)
+      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+    switch (cinfo->in_color_space) {
+    case JCS_GRAYSCALE:
+    case JCS_YCbCr:
+    case JCS_BG_YCC:
+      cconvert->pub.color_convert = grayscale_convert;
+      break;
+    case JCS_RGB:
+      cconvert->pub.start_pass = rgb_ycc_start;
+      cconvert->pub.color_convert = rgb_gray_convert;
+      break;
+    default:
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+    }
+    break;
+
+  case JCS_RGB:
+  case JCS_BG_RGB:
+    if (cinfo->num_components != 3)
+      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+    if (cinfo->in_color_space == cinfo->jpeg_color_space) {
+      switch (cinfo->color_transform) {
+      case JCT_NONE:
+	cconvert->pub.color_convert = rgb_convert;
+	break;
+      case JCT_SUBTRACT_GREEN:
+	cconvert->pub.color_convert = rgb_rgb1_convert;
+	break;
+      default:
+	ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+      }
+    } else
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+    break;
+
+  case JCS_YCbCr:
+    if (cinfo->num_components != 3)
+      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+    switch (cinfo->in_color_space) {
+    case JCS_RGB:
+      cconvert->pub.start_pass = rgb_ycc_start;
+      cconvert->pub.color_convert = rgb_ycc_convert;
+      break;
+    case JCS_YCbCr:
+      cconvert->pub.color_convert = null_convert;
+      break;
+    default:
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+    }
+    break;
+
+  case JCS_BG_YCC:
+    if (cinfo->num_components != 3)
+      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+    switch (cinfo->in_color_space) {
+    case JCS_RGB:
+      /* For conversion from normal RGB input to BG_YCC representation,
+       * the Cb/Cr values are first computed as usual, and then
+       * quantized further after DCT processing by a factor of
+       * 2 in reference to the nominal quantization factor.
+       */
+      /* need quantization scale by factor of 2 after DCT */
+      cinfo->comp_info[1].component_needed = TRUE;
+      cinfo->comp_info[2].component_needed = TRUE;
+      /* compute normal YCC first */
+      cconvert->pub.start_pass = rgb_ycc_start;
+      cconvert->pub.color_convert = rgb_ycc_convert;
+      break;
+    case JCS_YCbCr:
+      /* need quantization scale by factor of 2 after DCT */
+      cinfo->comp_info[1].component_needed = TRUE;
+      cinfo->comp_info[2].component_needed = TRUE;
+      /*FALLTHROUGH*/
+    case JCS_BG_YCC:
+      /* Pass through for BG_YCC input */
+      cconvert->pub.color_convert = null_convert;
+      break;
+    default:
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+    }
+    break;
+
+  case JCS_CMYK:
+    if (cinfo->num_components != 4)
+      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+    if (cinfo->in_color_space == JCS_CMYK)
+      cconvert->pub.color_convert = null_convert;
+    else
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+    break;
+
+  case JCS_YCCK:
+    if (cinfo->num_components != 4)
+      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+    switch (cinfo->in_color_space) {
+    case JCS_CMYK:
+      cconvert->pub.start_pass = rgb_ycc_start;
+      cconvert->pub.color_convert = cmyk_ycck_convert;
+      break;
+    case JCS_YCCK:
+      cconvert->pub.color_convert = null_convert;
+      break;
+    default:
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+    }
+    break;
+
+  default:			/* allow null conversion of JCS_UNKNOWN */
+    if (cinfo->jpeg_color_space != cinfo->in_color_space ||
+	cinfo->num_components != cinfo->input_components)
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+    cconvert->pub.color_convert = null_convert;
+    break;
+  }
+}
diff --git a/source/Irrlicht/jpeglib/jcdctmgr.c b/source/Irrlicht/jpeglib/jcdctmgr.c
new file mode 100644
index 00000000..9daea85f
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jcdctmgr.c
@@ -0,0 +1,477 @@
+/*
+ * jcdctmgr.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2003-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the forward-DCT management logic.
+ * This code selects a particular DCT implementation to be used,
+ * and it performs related housekeeping chores including coefficient
+ * quantization.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h"		/* Private declarations for DCT subsystem */
+
+
+/* Private subobject for this module */
+
+typedef struct {
+  struct jpeg_forward_dct pub;	/* public fields */
+
+  /* Pointer to the DCT routine actually in use */
+  forward_DCT_method_ptr do_dct[MAX_COMPONENTS];
+
+#ifdef DCT_FLOAT_SUPPORTED
+  /* Same as above for the floating-point case. */
+  float_DCT_method_ptr do_float_dct[MAX_COMPONENTS];
+#endif
+} my_fdct_controller;
+
+typedef my_fdct_controller * my_fdct_ptr;
+
+
+/* The allocated post-DCT divisor tables -- big enough for any
+ * supported variant and not identical to the quant table entries,
+ * because of scaling (especially for an unnormalized DCT) --
+ * are pointed to by dct_table in the per-component comp_info
+ * structures.  Each table is given in normal array order.
+ */
+
+typedef union {
+  DCTELEM int_array[DCTSIZE2];
+#ifdef DCT_FLOAT_SUPPORTED
+  FAST_FLOAT float_array[DCTSIZE2];
+#endif
+} divisor_table;
+
+
+/* The current scaled-DCT routines require ISLOW-style divisor tables,
+ * so be sure to compile that code if either ISLOW or SCALING is requested.
+ */
+#ifdef DCT_ISLOW_SUPPORTED
+#define PROVIDE_ISLOW_TABLES
+#else
+#ifdef DCT_SCALING_SUPPORTED
+#define PROVIDE_ISLOW_TABLES
+#endif
+#endif
+
+
+/*
+ * Perform forward DCT on one or more blocks of a component.
+ *
+ * The input samples are taken from the sample_data[] array starting at
+ * position start_row/start_col, and moving to the right for any additional
+ * blocks. The quantized coefficients are returned in coef_blocks[].
+ */
+
+METHODDEF(void)
+forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr,
+	     JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
+	     JDIMENSION start_row, JDIMENSION start_col,
+	     JDIMENSION num_blocks)
+/* This version is used for integer DCT implementations. */
+{
+  /* This routine is heavily used, so it's worth coding it tightly. */
+  my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
+  forward_DCT_method_ptr do_dct = fdct->do_dct[compptr->component_index];
+  DCTELEM * divisors = (DCTELEM *) compptr->dct_table;
+  DCTELEM workspace[DCTSIZE2];	/* work area for FDCT subroutine */
+  JDIMENSION bi;
+
+  sample_data += start_row;	/* fold in the vertical offset once */
+
+  for (bi = 0; bi < num_blocks; bi++, start_col += compptr->DCT_h_scaled_size) {
+    /* Perform the DCT */
+    (*do_dct) (workspace, sample_data, start_col);
+
+    /* Quantize/descale the coefficients, and store into coef_blocks[] */
+    { register DCTELEM temp, qval;
+      register int i;
+      register JCOEFPTR output_ptr = coef_blocks[bi];
+
+      for (i = 0; i < DCTSIZE2; i++) {
+	qval = divisors[i];
+	temp = workspace[i];
+	/* Divide the coefficient value by qval, ensuring proper rounding.
+	 * Since C does not specify the direction of rounding for negative
+	 * quotients, we have to force the dividend positive for portability.
+	 *
+	 * In most files, at least half of the output values will be zero
+	 * (at default quantization settings, more like three-quarters...)
+	 * so we should ensure that this case is fast.  On many machines,
+	 * a comparison is enough cheaper than a divide to make a special test
+	 * a win.  Since both inputs will be nonnegative, we need only test
+	 * for a < b to discover whether a/b is 0.
+	 * If your machine's division is fast enough, define FAST_DIVIDE.
+	 */
+#ifdef FAST_DIVIDE
+#define DIVIDE_BY(a,b)	a /= b
+#else
+#define DIVIDE_BY(a,b)	if (a >= b) a /= b; else a = 0
+#endif
+	if (temp < 0) {
+	  temp = -temp;
+	  temp += qval>>1;	/* for rounding */
+	  DIVIDE_BY(temp, qval);
+	  temp = -temp;
+	} else {
+	  temp += qval>>1;	/* for rounding */
+	  DIVIDE_BY(temp, qval);
+	}
+	output_ptr[i] = (JCOEF) temp;
+      }
+    }
+  }
+}
+
+
+#ifdef DCT_FLOAT_SUPPORTED
+
+METHODDEF(void)
+forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr,
+		   JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
+		   JDIMENSION start_row, JDIMENSION start_col,
+		   JDIMENSION num_blocks)
+/* This version is used for floating-point DCT implementations. */
+{
+  /* This routine is heavily used, so it's worth coding it tightly. */
+  my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
+  float_DCT_method_ptr do_dct = fdct->do_float_dct[compptr->component_index];
+  FAST_FLOAT * divisors = (FAST_FLOAT *) compptr->dct_table;
+  FAST_FLOAT workspace[DCTSIZE2]; /* work area for FDCT subroutine */
+  JDIMENSION bi;
+
+  sample_data += start_row;	/* fold in the vertical offset once */
+
+  for (bi = 0; bi < num_blocks; bi++, start_col += compptr->DCT_h_scaled_size) {
+    /* Perform the DCT */
+    (*do_dct) (workspace, sample_data, start_col);
+
+    /* Quantize/descale the coefficients, and store into coef_blocks[] */
+    { register FAST_FLOAT temp;
+      register int i;
+      register JCOEFPTR output_ptr = coef_blocks[bi];
+
+      for (i = 0; i < DCTSIZE2; i++) {
+	/* Apply the quantization and scaling factor */
+	temp = workspace[i] * divisors[i];
+	/* Round to nearest integer.
+	 * Since C does not specify the direction of rounding for negative
+	 * quotients, we have to force the dividend positive for portability.
+	 * The maximum coefficient size is +-16K (for 12-bit data), so this
+	 * code should work for either 16-bit or 32-bit ints.
+	 */
+	output_ptr[i] = (JCOEF) ((int) (temp + (FAST_FLOAT) 16384.5) - 16384);
+      }
+    }
+  }
+}
+
+#endif /* DCT_FLOAT_SUPPORTED */
+
+
+/*
+ * Initialize for a processing pass.
+ * Verify that all referenced Q-tables are present, and set up
+ * the divisor table for each one.
+ * In the current implementation, DCT of all components is done during
+ * the first pass, even if only some components will be output in the
+ * first scan.  Hence all components should be examined here.
+ */
+
+METHODDEF(void)
+start_pass_fdctmgr (j_compress_ptr cinfo)
+{
+  my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
+  int ci, qtblno, i;
+  jpeg_component_info *compptr;
+  int method = 0;
+  JQUANT_TBL * qtbl;
+  DCTELEM * dtbl;
+
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    /* Select the proper DCT routine for this component's scaling */
+    switch ((compptr->DCT_h_scaled_size << 8) + compptr->DCT_v_scaled_size) {
+#ifdef DCT_SCALING_SUPPORTED
+    case ((1 << 8) + 1):
+      fdct->do_dct[ci] = jpeg_fdct_1x1;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((2 << 8) + 2):
+      fdct->do_dct[ci] = jpeg_fdct_2x2;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((3 << 8) + 3):
+      fdct->do_dct[ci] = jpeg_fdct_3x3;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((4 << 8) + 4):
+      fdct->do_dct[ci] = jpeg_fdct_4x4;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((5 << 8) + 5):
+      fdct->do_dct[ci] = jpeg_fdct_5x5;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((6 << 8) + 6):
+      fdct->do_dct[ci] = jpeg_fdct_6x6;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((7 << 8) + 7):
+      fdct->do_dct[ci] = jpeg_fdct_7x7;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((9 << 8) + 9):
+      fdct->do_dct[ci] = jpeg_fdct_9x9;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((10 << 8) + 10):
+      fdct->do_dct[ci] = jpeg_fdct_10x10;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((11 << 8) + 11):
+      fdct->do_dct[ci] = jpeg_fdct_11x11;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((12 << 8) + 12):
+      fdct->do_dct[ci] = jpeg_fdct_12x12;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((13 << 8) + 13):
+      fdct->do_dct[ci] = jpeg_fdct_13x13;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((14 << 8) + 14):
+      fdct->do_dct[ci] = jpeg_fdct_14x14;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((15 << 8) + 15):
+      fdct->do_dct[ci] = jpeg_fdct_15x15;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((16 << 8) + 16):
+      fdct->do_dct[ci] = jpeg_fdct_16x16;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((16 << 8) + 8):
+      fdct->do_dct[ci] = jpeg_fdct_16x8;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((14 << 8) + 7):
+      fdct->do_dct[ci] = jpeg_fdct_14x7;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((12 << 8) + 6):
+      fdct->do_dct[ci] = jpeg_fdct_12x6;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((10 << 8) + 5):
+      fdct->do_dct[ci] = jpeg_fdct_10x5;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((8 << 8) + 4):
+      fdct->do_dct[ci] = jpeg_fdct_8x4;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((6 << 8) + 3):
+      fdct->do_dct[ci] = jpeg_fdct_6x3;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((4 << 8) + 2):
+      fdct->do_dct[ci] = jpeg_fdct_4x2;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((2 << 8) + 1):
+      fdct->do_dct[ci] = jpeg_fdct_2x1;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((8 << 8) + 16):
+      fdct->do_dct[ci] = jpeg_fdct_8x16;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((7 << 8) + 14):
+      fdct->do_dct[ci] = jpeg_fdct_7x14;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((6 << 8) + 12):
+      fdct->do_dct[ci] = jpeg_fdct_6x12;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((5 << 8) + 10):
+      fdct->do_dct[ci] = jpeg_fdct_5x10;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((4 << 8) + 8):
+      fdct->do_dct[ci] = jpeg_fdct_4x8;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((3 << 8) + 6):
+      fdct->do_dct[ci] = jpeg_fdct_3x6;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((2 << 8) + 4):
+      fdct->do_dct[ci] = jpeg_fdct_2x4;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+    case ((1 << 8) + 2):
+      fdct->do_dct[ci] = jpeg_fdct_1x2;
+      method = JDCT_ISLOW;	/* jfdctint uses islow-style table */
+      break;
+#endif
+    case ((DCTSIZE << 8) + DCTSIZE):
+      switch (cinfo->dct_method) {
+#ifdef DCT_ISLOW_SUPPORTED
+      case JDCT_ISLOW:
+	fdct->do_dct[ci] = jpeg_fdct_islow;
+	method = JDCT_ISLOW;
+	break;
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+      case JDCT_IFAST:
+	fdct->do_dct[ci] = jpeg_fdct_ifast;
+	method = JDCT_IFAST;
+	break;
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+      case JDCT_FLOAT:
+	fdct->do_float_dct[ci] = jpeg_fdct_float;
+	method = JDCT_FLOAT;
+	break;
+#endif
+      default:
+	ERREXIT(cinfo, JERR_NOT_COMPILED);
+	break;
+      }
+      break;
+    default:
+      ERREXIT2(cinfo, JERR_BAD_DCTSIZE,
+	       compptr->DCT_h_scaled_size, compptr->DCT_v_scaled_size);
+      break;
+    }
+    qtblno = compptr->quant_tbl_no;
+    /* Make sure specified quantization table is present */
+    if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS ||
+	cinfo->quant_tbl_ptrs[qtblno] == NULL)
+      ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno);
+    qtbl = cinfo->quant_tbl_ptrs[qtblno];
+    /* Create divisor table from quant table */
+    switch (method) {
+#ifdef PROVIDE_ISLOW_TABLES
+    case JDCT_ISLOW:
+      /* For LL&M IDCT method, divisors are equal to raw quantization
+       * coefficients multiplied by 8 (to counteract scaling).
+       */
+      dtbl = (DCTELEM *) compptr->dct_table;
+      for (i = 0; i < DCTSIZE2; i++) {
+	dtbl[i] =
+	  ((DCTELEM) qtbl->quantval[i]) << (compptr->component_needed ? 4 : 3);
+      }
+      fdct->pub.forward_DCT[ci] = forward_DCT;
+      break;
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+    case JDCT_IFAST:
+      {
+	/* For AA&N IDCT method, divisors are equal to quantization
+	 * coefficients scaled by scalefactor[row]*scalefactor[col], where
+	 *   scalefactor[0] = 1
+	 *   scalefactor[k] = cos(k*PI/16) * sqrt(2)    for k=1..7
+	 * We apply a further scale factor of 8.
+	 */
+#define CONST_BITS 14
+	static const INT16 aanscales[DCTSIZE2] = {
+	  /* precomputed values scaled up by 14 bits */
+	  16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,
+	  22725, 31521, 29692, 26722, 22725, 17855, 12299,  6270,
+	  21407, 29692, 27969, 25172, 21407, 16819, 11585,  5906,
+	  19266, 26722, 25172, 22654, 19266, 15137, 10426,  5315,
+	  16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,
+	  12873, 17855, 16819, 15137, 12873, 10114,  6967,  3552,
+	   8867, 12299, 11585, 10426,  8867,  6967,  4799,  2446,
+	   4520,  6270,  5906,  5315,  4520,  3552,  2446,  1247
+	};
+	SHIFT_TEMPS
+
+	dtbl = (DCTELEM *) compptr->dct_table;
+	for (i = 0; i < DCTSIZE2; i++) {
+	  dtbl[i] = (DCTELEM)
+	    DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],
+				  (INT32) aanscales[i]),
+		    compptr->component_needed ? CONST_BITS-4 : CONST_BITS-3);
+	}
+      }
+      fdct->pub.forward_DCT[ci] = forward_DCT;
+      break;
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+    case JDCT_FLOAT:
+      {
+	/* For float AA&N IDCT method, divisors are equal to quantization
+	 * coefficients scaled by scalefactor[row]*scalefactor[col], where
+	 *   scalefactor[0] = 1
+	 *   scalefactor[k] = cos(k*PI/16) * sqrt(2)    for k=1..7
+	 * We apply a further scale factor of 8.
+	 * What's actually stored is 1/divisor so that the inner loop can
+	 * use a multiplication rather than a division.
+	 */
+	FAST_FLOAT * fdtbl = (FAST_FLOAT *) compptr->dct_table;
+	int row, col;
+	static const double aanscalefactor[DCTSIZE] = {
+	  1.0, 1.387039845, 1.306562965, 1.175875602,
+	  1.0, 0.785694958, 0.541196100, 0.275899379
+	};
+
+	i = 0;
+	for (row = 0; row < DCTSIZE; row++) {
+	  for (col = 0; col < DCTSIZE; col++) {
+	    fdtbl[i] = (FAST_FLOAT)
+	      (1.0 / ((double) qtbl->quantval[i] *
+		      aanscalefactor[row] * aanscalefactor[col] *
+		      (compptr->component_needed ? 16.0 : 8.0)));
+	    i++;
+	  }
+	}
+      }
+      fdct->pub.forward_DCT[ci] = forward_DCT_float;
+      break;
+#endif
+    default:
+      ERREXIT(cinfo, JERR_NOT_COMPILED);
+      break;
+    }
+  }
+}
+
+
+/*
+ * Initialize FDCT manager.
+ */
+
+GLOBAL(void)
+jinit_forward_dct (j_compress_ptr cinfo)
+{
+  my_fdct_ptr fdct;
+  int ci;
+  jpeg_component_info *compptr;
+
+  fdct = (my_fdct_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(my_fdct_controller));
+  cinfo->fdct = &fdct->pub;
+  fdct->pub.start_pass = start_pass_fdctmgr;
+
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    /* Allocate a divisor table for each component */
+    compptr->dct_table =
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  SIZEOF(divisor_table));
+  }
+}
diff --git a/source/Irrlicht/jpeglib/jchuff.c b/source/Irrlicht/jpeglib/jchuff.c
new file mode 100644
index 00000000..92fd974c
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jchuff.c
@@ -0,0 +1,1573 @@
+/*
+ * jchuff.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2006-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains Huffman entropy encoding routines.
+ * Both sequential and progressive modes are supported in this single module.
+ *
+ * Much of the complexity here has to do with supporting output suspension.
+ * If the data destination module demands suspension, we want to be able to
+ * back up to the start of the current MCU.  To do this, we copy state
+ * variables into local working storage, and update them back to the
+ * permanent JPEG objects only upon successful completion of an MCU.
+ *
+ * We do not support output suspension for the progressive JPEG mode, since
+ * the library currently does not allow multiple-scan files to be written
+ * with output suspension.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* The legal range of a DCT coefficient is
+ *  -1024 .. +1023  for 8-bit data;
+ * -16384 .. +16383 for 12-bit data.
+ * Hence the magnitude should always fit in 10 or 14 bits respectively.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define MAX_COEF_BITS 10
+#else
+#define MAX_COEF_BITS 14
+#endif
+
+/* Derived data constructed for each Huffman table */
+
+typedef struct {
+  unsigned int ehufco[256];	/* code for each symbol */
+  char ehufsi[256];		/* length of code for each symbol */
+  /* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */
+} c_derived_tbl;
+
+
+/* Expanded entropy encoder object for Huffman encoding.
+ *
+ * The savable_state subrecord contains fields that change within an MCU,
+ * but must not be updated permanently until we complete the MCU.
+ */
+
+typedef struct {
+  INT32 put_buffer;		/* current bit-accumulation buffer */
+  int put_bits;			/* # of bits now in it */
+  int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
+} savable_state;
+
+/* This macro is to work around compilers with missing or broken
+ * structure assignment.  You'll need to fix this code if you have
+ * such a compiler and you change MAX_COMPS_IN_SCAN.
+ */
+
+#ifndef NO_STRUCT_ASSIGN
+#define ASSIGN_STATE(dest,src)  ((dest) = (src))
+#else
+#if MAX_COMPS_IN_SCAN == 4
+#define ASSIGN_STATE(dest,src)  \
+	((dest).put_buffer = (src).put_buffer, \
+	 (dest).put_bits = (src).put_bits, \
+	 (dest).last_dc_val[0] = (src).last_dc_val[0], \
+	 (dest).last_dc_val[1] = (src).last_dc_val[1], \
+	 (dest).last_dc_val[2] = (src).last_dc_val[2], \
+	 (dest).last_dc_val[3] = (src).last_dc_val[3])
+#endif
+#endif
+
+
+typedef struct {
+  struct jpeg_entropy_encoder pub; /* public fields */
+
+  savable_state saved;		/* Bit buffer & DC state at start of MCU */
+
+  /* These fields are NOT loaded into local working state. */
+  unsigned int restarts_to_go;	/* MCUs left in this restart interval */
+  int next_restart_num;		/* next restart number to write (0-7) */
+
+  /* Pointers to derived tables (these workspaces have image lifespan) */
+  c_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];
+  c_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];
+
+  /* Statistics tables for optimization */
+  long * dc_count_ptrs[NUM_HUFF_TBLS];
+  long * ac_count_ptrs[NUM_HUFF_TBLS];
+
+  /* Following fields used only in progressive mode */
+
+  /* Mode flag: TRUE for optimization, FALSE for actual data output */
+  boolean gather_statistics;
+
+  /* next_output_byte/free_in_buffer are local copies of cinfo->dest fields.
+   */
+  JOCTET * next_output_byte;	/* => next byte to write in buffer */
+  size_t free_in_buffer;	/* # of byte spaces remaining in buffer */
+  j_compress_ptr cinfo;		/* link to cinfo (needed for dump_buffer) */
+
+  /* Coding status for AC components */
+  int ac_tbl_no;		/* the table number of the single component */
+  unsigned int EOBRUN;		/* run length of EOBs */
+  unsigned int BE;		/* # of buffered correction bits before MCU */
+  char * bit_buffer;		/* buffer for correction bits (1 per char) */
+  /* packing correction bits tightly would save some space but cost time... */
+} huff_entropy_encoder;
+
+typedef huff_entropy_encoder * huff_entropy_ptr;
+
+/* Working state while writing an MCU (sequential mode).
+ * This struct contains all the fields that are needed by subroutines.
+ */
+
+typedef struct {
+  JOCTET * next_output_byte;	/* => next byte to write in buffer */
+  size_t free_in_buffer;	/* # of byte spaces remaining in buffer */
+  savable_state cur;		/* Current bit buffer & DC state */
+  j_compress_ptr cinfo;		/* dump_buffer needs access to this */
+} working_state;
+
+/* MAX_CORR_BITS is the number of bits the AC refinement correction-bit
+ * buffer can hold.  Larger sizes may slightly improve compression, but
+ * 1000 is already well into the realm of overkill.
+ * The minimum safe size is 64 bits.
+ */
+
+#define MAX_CORR_BITS  1000	/* Max # of correction bits I can buffer */
+
+/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32.
+ * We assume that int right shift is unsigned if INT32 right shift is,
+ * which should be safe.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define ISHIFT_TEMPS	int ishift_temp;
+#define IRIGHT_SHIFT(x,shft)  \
+	((ishift_temp = (x)) < 0 ? \
+	 (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \
+	 (ishift_temp >> (shft)))
+#else
+#define ISHIFT_TEMPS
+#define IRIGHT_SHIFT(x,shft)	((x) >> (shft))
+#endif
+
+
+/*
+ * Compute the derived values for a Huffman table.
+ * This routine also performs some validation checks on the table.
+ */
+
+LOCAL(void)
+jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno,
+			 c_derived_tbl ** pdtbl)
+{
+  JHUFF_TBL *htbl;
+  c_derived_tbl *dtbl;
+  int p, i, l, lastp, si, maxsymbol;
+  char huffsize[257];
+  unsigned int huffcode[257];
+  unsigned int code;
+
+  /* Note that huffsize[] and huffcode[] are filled in code-length order,
+   * paralleling the order of the symbols themselves in htbl->huffval[].
+   */
+
+  /* Find the input Huffman table */
+  if (tblno < 0 || tblno >= NUM_HUFF_TBLS)
+    ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);
+  htbl =
+    isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno];
+  if (htbl == NULL)
+    ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);
+
+  /* Allocate a workspace if we haven't already done so. */
+  if (*pdtbl == NULL)
+    *pdtbl = (c_derived_tbl *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  SIZEOF(c_derived_tbl));
+  dtbl = *pdtbl;
+  
+  /* Figure C.1: make table of Huffman code length for each symbol */
+
+  p = 0;
+  for (l = 1; l <= 16; l++) {
+    i = (int) htbl->bits[l];
+    if (i < 0 || p + i > 256)	/* protect against table overrun */
+      ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+    while (i--)
+      huffsize[p++] = (char) l;
+  }
+  huffsize[p] = 0;
+  lastp = p;
+  
+  /* Figure C.2: generate the codes themselves */
+  /* We also validate that the counts represent a legal Huffman code tree. */
+
+  code = 0;
+  si = huffsize[0];
+  p = 0;
+  while (huffsize[p]) {
+    while (((int) huffsize[p]) == si) {
+      huffcode[p++] = code;
+      code++;
+    }
+    /* code is now 1 more than the last code used for codelength si; but
+     * it must still fit in si bits, since no code is allowed to be all ones.
+     */
+    if (((INT32) code) >= (((INT32) 1) << si))
+      ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+    code <<= 1;
+    si++;
+  }
+  
+  /* Figure C.3: generate encoding tables */
+  /* These are code and size indexed by symbol value */
+
+  /* Set all codeless symbols to have code length 0;
+   * this lets us detect duplicate VAL entries here, and later
+   * allows emit_bits to detect any attempt to emit such symbols.
+   */
+  MEMZERO(dtbl->ehufsi, SIZEOF(dtbl->ehufsi));
+
+  /* This is also a convenient place to check for out-of-range
+   * and duplicated VAL entries.  We allow 0..255 for AC symbols
+   * but only 0..15 for DC.  (We could constrain them further
+   * based on data depth and mode, but this seems enough.)
+   */
+  maxsymbol = isDC ? 15 : 255;
+
+  for (p = 0; p < lastp; p++) {
+    i = htbl->huffval[p];
+    if (i < 0 || i > maxsymbol || dtbl->ehufsi[i])
+      ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+    dtbl->ehufco[i] = huffcode[p];
+    dtbl->ehufsi[i] = huffsize[p];
+  }
+}
+
+
+/* Outputting bytes to the file.
+ * NB: these must be called only when actually outputting,
+ * that is, entropy->gather_statistics == FALSE.
+ */
+
+/* Emit a byte, taking 'action' if must suspend. */
+#define emit_byte_s(state,val,action)  \
+	{ *(state)->next_output_byte++ = (JOCTET) (val);  \
+	  if (--(state)->free_in_buffer == 0)  \
+	    if (! dump_buffer_s(state))  \
+	      { action; } }
+
+/* Emit a byte */
+#define emit_byte_e(entropy,val)  \
+	{ *(entropy)->next_output_byte++ = (JOCTET) (val);  \
+	  if (--(entropy)->free_in_buffer == 0)  \
+	    dump_buffer_e(entropy); }
+
+
+LOCAL(boolean)
+dump_buffer_s (working_state * state)
+/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */
+{
+  struct jpeg_destination_mgr * dest = state->cinfo->dest;
+
+  if (! (*dest->empty_output_buffer) (state->cinfo))
+    return FALSE;
+  /* After a successful buffer dump, must reset buffer pointers */
+  state->next_output_byte = dest->next_output_byte;
+  state->free_in_buffer = dest->free_in_buffer;
+  return TRUE;
+}
+
+
+LOCAL(void)
+dump_buffer_e (huff_entropy_ptr entropy)
+/* Empty the output buffer; we do not support suspension in this case. */
+{
+  struct jpeg_destination_mgr * dest = entropy->cinfo->dest;
+
+  if (! (*dest->empty_output_buffer) (entropy->cinfo))
+    ERREXIT(entropy->cinfo, JERR_CANT_SUSPEND);
+  /* After a successful buffer dump, must reset buffer pointers */
+  entropy->next_output_byte = dest->next_output_byte;
+  entropy->free_in_buffer = dest->free_in_buffer;
+}
+
+
+/* Outputting bits to the file */
+
+/* Only the right 24 bits of put_buffer are used; the valid bits are
+ * left-justified in this part.  At most 16 bits can be passed to emit_bits
+ * in one call, and we never retain more than 7 bits in put_buffer
+ * between calls, so 24 bits are sufficient.
+ */
+
+INLINE
+LOCAL(boolean)
+emit_bits_s (working_state * state, unsigned int code, int size)
+/* Emit some bits; return TRUE if successful, FALSE if must suspend */
+{
+  /* This routine is heavily used, so it's worth coding tightly. */
+  register INT32 put_buffer;
+  register int put_bits;
+
+  /* if size is 0, caller used an invalid Huffman table entry */
+  if (size == 0)
+    ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE);
+
+  /* mask off any extra bits in code */
+  put_buffer = ((INT32) code) & ((((INT32) 1) << size) - 1);
+
+  /* new number of bits in buffer */
+  put_bits = size + state->cur.put_bits;
+
+  put_buffer <<= 24 - put_bits; /* align incoming bits */
+
+  /* and merge with old buffer contents */
+  put_buffer |= state->cur.put_buffer;
+
+  while (put_bits >= 8) {
+    int c = (int) ((put_buffer >> 16) & 0xFF);
+
+    emit_byte_s(state, c, return FALSE);
+    if (c == 0xFF) {		/* need to stuff a zero byte? */
+      emit_byte_s(state, 0, return FALSE);
+    }
+    put_buffer <<= 8;
+    put_bits -= 8;
+  }
+
+  state->cur.put_buffer = put_buffer; /* update state variables */
+  state->cur.put_bits = put_bits;
+
+  return TRUE;
+}
+
+
+INLINE
+LOCAL(void)
+emit_bits_e (huff_entropy_ptr entropy, unsigned int code, int size)
+/* Emit some bits, unless we are in gather mode */
+{
+  /* This routine is heavily used, so it's worth coding tightly. */
+  register INT32 put_buffer;
+  register int put_bits;
+
+  /* if size is 0, caller used an invalid Huffman table entry */
+  if (size == 0)
+    ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE);
+
+  if (entropy->gather_statistics)
+    return;			/* do nothing if we're only getting stats */
+
+  /* mask off any extra bits in code */
+  put_buffer = ((INT32) code) & ((((INT32) 1) << size) - 1);
+
+  /* new number of bits in buffer */
+  put_bits = size + entropy->saved.put_bits;
+
+  put_buffer <<= 24 - put_bits; /* align incoming bits */
+
+  /* and merge with old buffer contents */
+  put_buffer |= entropy->saved.put_buffer;
+
+  while (put_bits >= 8) {
+    int c = (int) ((put_buffer >> 16) & 0xFF);
+
+    emit_byte_e(entropy, c);
+    if (c == 0xFF) {		/* need to stuff a zero byte? */
+      emit_byte_e(entropy, 0);
+    }
+    put_buffer <<= 8;
+    put_bits -= 8;
+  }
+
+  entropy->saved.put_buffer = put_buffer; /* update variables */
+  entropy->saved.put_bits = put_bits;
+}
+
+
+LOCAL(boolean)
+flush_bits_s (working_state * state)
+{
+  if (! emit_bits_s(state, 0x7F, 7)) /* fill any partial byte with ones */
+    return FALSE;
+  state->cur.put_buffer = 0;	     /* and reset bit-buffer to empty */
+  state->cur.put_bits = 0;
+  return TRUE;
+}
+
+
+LOCAL(void)
+flush_bits_e (huff_entropy_ptr entropy)
+{
+  emit_bits_e(entropy, 0x7F, 7); /* fill any partial byte with ones */
+  entropy->saved.put_buffer = 0; /* and reset bit-buffer to empty */
+  entropy->saved.put_bits = 0;
+}
+
+
+/*
+ * Emit (or just count) a Huffman symbol.
+ */
+
+INLINE
+LOCAL(void)
+emit_dc_symbol (huff_entropy_ptr entropy, int tbl_no, int symbol)
+{
+  if (entropy->gather_statistics)
+    entropy->dc_count_ptrs[tbl_no][symbol]++;
+  else {
+    c_derived_tbl * tbl = entropy->dc_derived_tbls[tbl_no];
+    emit_bits_e(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]);
+  }
+}
+
+
+INLINE
+LOCAL(void)
+emit_ac_symbol (huff_entropy_ptr entropy, int tbl_no, int symbol)
+{
+  if (entropy->gather_statistics)
+    entropy->ac_count_ptrs[tbl_no][symbol]++;
+  else {
+    c_derived_tbl * tbl = entropy->ac_derived_tbls[tbl_no];
+    emit_bits_e(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]);
+  }
+}
+
+
+/*
+ * Emit bits from a correction bit buffer.
+ */
+
+LOCAL(void)
+emit_buffered_bits (huff_entropy_ptr entropy, char * bufstart,
+		    unsigned int nbits)
+{
+  if (entropy->gather_statistics)
+    return;			/* no real work */
+
+  while (nbits > 0) {
+    emit_bits_e(entropy, (unsigned int) (*bufstart), 1);
+    bufstart++;
+    nbits--;
+  }
+}
+
+
+/*
+ * Emit any pending EOBRUN symbol.
+ */
+
+LOCAL(void)
+emit_eobrun (huff_entropy_ptr entropy)
+{
+  register int temp, nbits;
+
+  if (entropy->EOBRUN > 0) {	/* if there is any pending EOBRUN */
+    temp = entropy->EOBRUN;
+    nbits = 0;
+    while ((temp >>= 1))
+      nbits++;
+    /* safety check: shouldn't happen given limited correction-bit buffer */
+    if (nbits > 14)
+      ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE);
+
+    emit_ac_symbol(entropy, entropy->ac_tbl_no, nbits << 4);
+    if (nbits)
+      emit_bits_e(entropy, entropy->EOBRUN, nbits);
+
+    entropy->EOBRUN = 0;
+
+    /* Emit any buffered correction bits */
+    emit_buffered_bits(entropy, entropy->bit_buffer, entropy->BE);
+    entropy->BE = 0;
+  }
+}
+
+
+/*
+ * Emit a restart marker & resynchronize predictions.
+ */
+
+LOCAL(boolean)
+emit_restart_s (working_state * state, int restart_num)
+{
+  int ci;
+
+  if (! flush_bits_s(state))
+    return FALSE;
+
+  emit_byte_s(state, 0xFF, return FALSE);
+  emit_byte_s(state, JPEG_RST0 + restart_num, return FALSE);
+
+  /* Re-initialize DC predictions to 0 */
+  for (ci = 0; ci < state->cinfo->comps_in_scan; ci++)
+    state->cur.last_dc_val[ci] = 0;
+
+  /* The restart counter is not updated until we successfully write the MCU. */
+
+  return TRUE;
+}
+
+
+LOCAL(void)
+emit_restart_e (huff_entropy_ptr entropy, int restart_num)
+{
+  int ci;
+
+  emit_eobrun(entropy);
+
+  if (! entropy->gather_statistics) {
+    flush_bits_e(entropy);
+    emit_byte_e(entropy, 0xFF);
+    emit_byte_e(entropy, JPEG_RST0 + restart_num);
+  }
+
+  if (entropy->cinfo->Ss == 0) {
+    /* Re-initialize DC predictions to 0 */
+    for (ci = 0; ci < entropy->cinfo->comps_in_scan; ci++)
+      entropy->saved.last_dc_val[ci] = 0;
+  } else {
+    /* Re-initialize all AC-related fields to 0 */
+    entropy->EOBRUN = 0;
+    entropy->BE = 0;
+  }
+}
+
+
+/*
+ * MCU encoding for DC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+  register int temp, temp2;
+  register int nbits;
+  int blkn, ci, tbl;
+  ISHIFT_TEMPS
+
+  entropy->next_output_byte = cinfo->dest->next_output_byte;
+  entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+  /* Emit restart marker if needed */
+  if (cinfo->restart_interval)
+    if (entropy->restarts_to_go == 0)
+      emit_restart_e(entropy, entropy->next_restart_num);
+
+  /* Encode the MCU data blocks */
+  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+    ci = cinfo->MCU_membership[blkn];
+    tbl = cinfo->cur_comp_info[ci]->dc_tbl_no;
+
+    /* Compute the DC value after the required point transform by Al.
+     * This is simply an arithmetic right shift.
+     */
+    temp = IRIGHT_SHIFT((int) (MCU_data[blkn][0][0]), cinfo->Al);
+
+    /* DC differences are figured on the point-transformed values. */
+    temp2 = temp - entropy->saved.last_dc_val[ci];
+    entropy->saved.last_dc_val[ci] = temp;
+
+    /* Encode the DC coefficient difference per section G.1.2.1 */
+    temp = temp2;
+    if (temp < 0) {
+      temp = -temp;		/* temp is abs value of input */
+      /* For a negative input, want temp2 = bitwise complement of abs(input) */
+      /* This code assumes we are on a two's complement machine */
+      temp2--;
+    }
+
+    /* Find the number of bits needed for the magnitude of the coefficient */
+    nbits = 0;
+    while (temp) {
+      nbits++;
+      temp >>= 1;
+    }
+    /* Check for out-of-range coefficient values.
+     * Since we're encoding a difference, the range limit is twice as much.
+     */
+    if (nbits > MAX_COEF_BITS+1)
+      ERREXIT(cinfo, JERR_BAD_DCT_COEF);
+
+    /* Count/emit the Huffman-coded symbol for the number of bits */
+    emit_dc_symbol(entropy, tbl, nbits);
+
+    /* Emit that number of bits of the value, if positive, */
+    /* or the complement of its magnitude, if negative. */
+    if (nbits)			/* emit_bits rejects calls with size 0 */
+      emit_bits_e(entropy, (unsigned int) temp2, nbits);
+  }
+
+  cinfo->dest->next_output_byte = entropy->next_output_byte;
+  cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+
+  /* Update restart-interval state too */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0) {
+      entropy->restarts_to_go = cinfo->restart_interval;
+      entropy->next_restart_num++;
+      entropy->next_restart_num &= 7;
+    }
+    entropy->restarts_to_go--;
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * MCU encoding for AC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+  const int * natural_order;
+  JBLOCKROW block;
+  register int temp, temp2;
+  register int nbits;
+  register int r, k;
+  int Se, Al;
+
+  entropy->next_output_byte = cinfo->dest->next_output_byte;
+  entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+  /* Emit restart marker if needed */
+  if (cinfo->restart_interval)
+    if (entropy->restarts_to_go == 0)
+      emit_restart_e(entropy, entropy->next_restart_num);
+
+  Se = cinfo->Se;
+  Al = cinfo->Al;
+  natural_order = cinfo->natural_order;
+
+  /* Encode the MCU data block */
+  block = MCU_data[0];
+
+  /* Encode the AC coefficients per section G.1.2.2, fig. G.3 */
+  
+  r = 0;			/* r = run length of zeros */
+   
+  for (k = cinfo->Ss; k <= Se; k++) {
+    if ((temp = (*block)[natural_order[k]]) == 0) {
+      r++;
+      continue;
+    }
+    /* We must apply the point transform by Al.  For AC coefficients this
+     * is an integer division with rounding towards 0.  To do this portably
+     * in C, we shift after obtaining the absolute value; so the code is
+     * interwoven with finding the abs value (temp) and output bits (temp2).
+     */
+    if (temp < 0) {
+      temp = -temp;		/* temp is abs value of input */
+      temp >>= Al;		/* apply the point transform */
+      /* For a negative coef, want temp2 = bitwise complement of abs(coef) */
+      temp2 = ~temp;
+    } else {
+      temp >>= Al;		/* apply the point transform */
+      temp2 = temp;
+    }
+    /* Watch out for case that nonzero coef is zero after point transform */
+    if (temp == 0) {
+      r++;
+      continue;
+    }
+
+    /* Emit any pending EOBRUN */
+    if (entropy->EOBRUN > 0)
+      emit_eobrun(entropy);
+    /* if run length > 15, must emit special run-length-16 codes (0xF0) */
+    while (r > 15) {
+      emit_ac_symbol(entropy, entropy->ac_tbl_no, 0xF0);
+      r -= 16;
+    }
+
+    /* Find the number of bits needed for the magnitude of the coefficient */
+    nbits = 1;			/* there must be at least one 1 bit */
+    while ((temp >>= 1))
+      nbits++;
+    /* Check for out-of-range coefficient values */
+    if (nbits > MAX_COEF_BITS)
+      ERREXIT(cinfo, JERR_BAD_DCT_COEF);
+
+    /* Count/emit Huffman symbol for run length / number of bits */
+    emit_ac_symbol(entropy, entropy->ac_tbl_no, (r << 4) + nbits);
+
+    /* Emit that number of bits of the value, if positive, */
+    /* or the complement of its magnitude, if negative. */
+    emit_bits_e(entropy, (unsigned int) temp2, nbits);
+
+    r = 0;			/* reset zero run length */
+  }
+
+  if (r > 0) {			/* If there are trailing zeroes, */
+    entropy->EOBRUN++;		/* count an EOB */
+    if (entropy->EOBRUN == 0x7FFF)
+      emit_eobrun(entropy);	/* force it out to avoid overflow */
+  }
+
+  cinfo->dest->next_output_byte = entropy->next_output_byte;
+  cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+
+  /* Update restart-interval state too */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0) {
+      entropy->restarts_to_go = cinfo->restart_interval;
+      entropy->next_restart_num++;
+      entropy->next_restart_num &= 7;
+    }
+    entropy->restarts_to_go--;
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * MCU encoding for DC successive approximation refinement scan.
+ * Note: we assume such scans can be multi-component,
+ * although the spec is not very clear on the point.
+ */
+
+METHODDEF(boolean)
+encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+  int Al, blkn;
+
+  entropy->next_output_byte = cinfo->dest->next_output_byte;
+  entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+  /* Emit restart marker if needed */
+  if (cinfo->restart_interval)
+    if (entropy->restarts_to_go == 0)
+      emit_restart_e(entropy, entropy->next_restart_num);
+
+  Al = cinfo->Al;
+
+  /* Encode the MCU data blocks */
+  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+    /* We simply emit the Al'th bit of the DC coefficient value. */
+    emit_bits_e(entropy, (unsigned int) (MCU_data[blkn][0][0] >> Al), 1);
+  }
+
+  cinfo->dest->next_output_byte = entropy->next_output_byte;
+  cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+
+  /* Update restart-interval state too */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0) {
+      entropy->restarts_to_go = cinfo->restart_interval;
+      entropy->next_restart_num++;
+      entropy->next_restart_num &= 7;
+    }
+    entropy->restarts_to_go--;
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * MCU encoding for AC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+  const int * natural_order;
+  JBLOCKROW block;
+  register int temp;
+  register int r, k;
+  int Se, Al;
+  int EOB;
+  char *BR_buffer;
+  unsigned int BR;
+  int absvalues[DCTSIZE2];
+
+  entropy->next_output_byte = cinfo->dest->next_output_byte;
+  entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+  /* Emit restart marker if needed */
+  if (cinfo->restart_interval)
+    if (entropy->restarts_to_go == 0)
+      emit_restart_e(entropy, entropy->next_restart_num);
+
+  Se = cinfo->Se;
+  Al = cinfo->Al;
+  natural_order = cinfo->natural_order;
+
+  /* Encode the MCU data block */
+  block = MCU_data[0];
+
+  /* It is convenient to make a pre-pass to determine the transformed
+   * coefficients' absolute values and the EOB position.
+   */
+  EOB = 0;
+  for (k = cinfo->Ss; k <= Se; k++) {
+    temp = (*block)[natural_order[k]];
+    /* We must apply the point transform by Al.  For AC coefficients this
+     * is an integer division with rounding towards 0.  To do this portably
+     * in C, we shift after obtaining the absolute value.
+     */
+    if (temp < 0)
+      temp = -temp;		/* temp is abs value of input */
+    temp >>= Al;		/* apply the point transform */
+    absvalues[k] = temp;	/* save abs value for main pass */
+    if (temp == 1)
+      EOB = k;			/* EOB = index of last newly-nonzero coef */
+  }
+
+  /* Encode the AC coefficients per section G.1.2.3, fig. G.7 */
+  
+  r = 0;			/* r = run length of zeros */
+  BR = 0;			/* BR = count of buffered bits added now */
+  BR_buffer = entropy->bit_buffer + entropy->BE; /* Append bits to buffer */
+
+  for (k = cinfo->Ss; k <= Se; k++) {
+    if ((temp = absvalues[k]) == 0) {
+      r++;
+      continue;
+    }
+
+    /* Emit any required ZRLs, but not if they can be folded into EOB */
+    while (r > 15 && k <= EOB) {
+      /* emit any pending EOBRUN and the BE correction bits */
+      emit_eobrun(entropy);
+      /* Emit ZRL */
+      emit_ac_symbol(entropy, entropy->ac_tbl_no, 0xF0);
+      r -= 16;
+      /* Emit buffered correction bits that must be associated with ZRL */
+      emit_buffered_bits(entropy, BR_buffer, BR);
+      BR_buffer = entropy->bit_buffer; /* BE bits are gone now */
+      BR = 0;
+    }
+
+    /* If the coef was previously nonzero, it only needs a correction bit.
+     * NOTE: a straight translation of the spec's figure G.7 would suggest
+     * that we also need to test r > 15.  But if r > 15, we can only get here
+     * if k > EOB, which implies that this coefficient is not 1.
+     */
+    if (temp > 1) {
+      /* The correction bit is the next bit of the absolute value. */
+      BR_buffer[BR++] = (char) (temp & 1);
+      continue;
+    }
+
+    /* Emit any pending EOBRUN and the BE correction bits */
+    emit_eobrun(entropy);
+
+    /* Count/emit Huffman symbol for run length / number of bits */
+    emit_ac_symbol(entropy, entropy->ac_tbl_no, (r << 4) + 1);
+
+    /* Emit output bit for newly-nonzero coef */
+    temp = ((*block)[natural_order[k]] < 0) ? 0 : 1;
+    emit_bits_e(entropy, (unsigned int) temp, 1);
+
+    /* Emit buffered correction bits that must be associated with this code */
+    emit_buffered_bits(entropy, BR_buffer, BR);
+    BR_buffer = entropy->bit_buffer; /* BE bits are gone now */
+    BR = 0;
+    r = 0;			/* reset zero run length */
+  }
+
+  if (r > 0 || BR > 0) {	/* If there are trailing zeroes, */
+    entropy->EOBRUN++;		/* count an EOB */
+    entropy->BE += BR;		/* concat my correction bits to older ones */
+    /* We force out the EOB if we risk either:
+     * 1. overflow of the EOB counter;
+     * 2. overflow of the correction bit buffer during the next MCU.
+     */
+    if (entropy->EOBRUN == 0x7FFF || entropy->BE > (MAX_CORR_BITS-DCTSIZE2+1))
+      emit_eobrun(entropy);
+  }
+
+  cinfo->dest->next_output_byte = entropy->next_output_byte;
+  cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+
+  /* Update restart-interval state too */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0) {
+      entropy->restarts_to_go = cinfo->restart_interval;
+      entropy->next_restart_num++;
+      entropy->next_restart_num &= 7;
+    }
+    entropy->restarts_to_go--;
+  }
+
+  return TRUE;
+}
+
+
+/* Encode a single block's worth of coefficients */
+
+LOCAL(boolean)
+encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val,
+		  c_derived_tbl *dctbl, c_derived_tbl *actbl)
+{
+  register int temp, temp2;
+  register int nbits;
+  register int r, k;
+  int Se = state->cinfo->lim_Se;
+  const int * natural_order = state->cinfo->natural_order;
+
+  /* Encode the DC coefficient difference per section F.1.2.1 */
+
+  temp = temp2 = block[0] - last_dc_val;
+
+  if (temp < 0) {
+    temp = -temp;		/* temp is abs value of input */
+    /* For a negative input, want temp2 = bitwise complement of abs(input) */
+    /* This code assumes we are on a two's complement machine */
+    temp2--;
+  }
+
+  /* Find the number of bits needed for the magnitude of the coefficient */
+  nbits = 0;
+  while (temp) {
+    nbits++;
+    temp >>= 1;
+  }
+  /* Check for out-of-range coefficient values.
+   * Since we're encoding a difference, the range limit is twice as much.
+   */
+  if (nbits > MAX_COEF_BITS+1)
+    ERREXIT(state->cinfo, JERR_BAD_DCT_COEF);
+
+  /* Emit the Huffman-coded symbol for the number of bits */
+  if (! emit_bits_s(state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits]))
+    return FALSE;
+
+  /* Emit that number of bits of the value, if positive, */
+  /* or the complement of its magnitude, if negative. */
+  if (nbits)			/* emit_bits rejects calls with size 0 */
+    if (! emit_bits_s(state, (unsigned int) temp2, nbits))
+      return FALSE;
+
+  /* Encode the AC coefficients per section F.1.2.2 */
+
+  r = 0;			/* r = run length of zeros */
+
+  for (k = 1; k <= Se; k++) {
+    if ((temp2 = block[natural_order[k]]) == 0) {
+      r++;
+    } else {
+      /* if run length > 15, must emit special run-length-16 codes (0xF0) */
+      while (r > 15) {
+	if (! emit_bits_s(state, actbl->ehufco[0xF0], actbl->ehufsi[0xF0]))
+	  return FALSE;
+	r -= 16;
+      }
+
+      temp = temp2;
+      if (temp < 0) {
+	temp = -temp;		/* temp is abs value of input */
+	/* This code assumes we are on a two's complement machine */
+	temp2--;
+      }
+
+      /* Find the number of bits needed for the magnitude of the coefficient */
+      nbits = 1;		/* there must be at least one 1 bit */
+      while ((temp >>= 1))
+	nbits++;
+      /* Check for out-of-range coefficient values */
+      if (nbits > MAX_COEF_BITS)
+	ERREXIT(state->cinfo, JERR_BAD_DCT_COEF);
+
+      /* Emit Huffman symbol for run length / number of bits */
+      temp = (r << 4) + nbits;
+      if (! emit_bits_s(state, actbl->ehufco[temp], actbl->ehufsi[temp]))
+	return FALSE;
+
+      /* Emit that number of bits of the value, if positive, */
+      /* or the complement of its magnitude, if negative. */
+      if (! emit_bits_s(state, (unsigned int) temp2, nbits))
+	return FALSE;
+
+      r = 0;
+    }
+  }
+
+  /* If the last coef(s) were zero, emit an end-of-block code */
+  if (r > 0)
+    if (! emit_bits_s(state, actbl->ehufco[0], actbl->ehufsi[0]))
+      return FALSE;
+
+  return TRUE;
+}
+
+
+/*
+ * Encode and output one MCU's worth of Huffman-compressed coefficients.
+ */
+
+METHODDEF(boolean)
+encode_mcu_huff (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+  working_state state;
+  int blkn, ci;
+  jpeg_component_info * compptr;
+
+  /* Load up working state */
+  state.next_output_byte = cinfo->dest->next_output_byte;
+  state.free_in_buffer = cinfo->dest->free_in_buffer;
+  ASSIGN_STATE(state.cur, entropy->saved);
+  state.cinfo = cinfo;
+
+  /* Emit restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0)
+      if (! emit_restart_s(&state, entropy->next_restart_num))
+	return FALSE;
+  }
+
+  /* Encode the MCU data blocks */
+  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+    ci = cinfo->MCU_membership[blkn];
+    compptr = cinfo->cur_comp_info[ci];
+    if (! encode_one_block(&state,
+			   MCU_data[blkn][0], state.cur.last_dc_val[ci],
+			   entropy->dc_derived_tbls[compptr->dc_tbl_no],
+			   entropy->ac_derived_tbls[compptr->ac_tbl_no]))
+      return FALSE;
+    /* Update last_dc_val */
+    state.cur.last_dc_val[ci] = MCU_data[blkn][0][0];
+  }
+
+  /* Completed MCU, so update state */
+  cinfo->dest->next_output_byte = state.next_output_byte;
+  cinfo->dest->free_in_buffer = state.free_in_buffer;
+  ASSIGN_STATE(entropy->saved, state.cur);
+
+  /* Update restart-interval state too */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0) {
+      entropy->restarts_to_go = cinfo->restart_interval;
+      entropy->next_restart_num++;
+      entropy->next_restart_num &= 7;
+    }
+    entropy->restarts_to_go--;
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * Finish up at the end of a Huffman-compressed scan.
+ */
+
+METHODDEF(void)
+finish_pass_huff (j_compress_ptr cinfo)
+{
+  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+  working_state state;
+
+  if (cinfo->progressive_mode) {
+    entropy->next_output_byte = cinfo->dest->next_output_byte;
+    entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+    /* Flush out any buffered data */
+    emit_eobrun(entropy);
+    flush_bits_e(entropy);
+
+    cinfo->dest->next_output_byte = entropy->next_output_byte;
+    cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+  } else {
+    /* Load up working state ... flush_bits needs it */
+    state.next_output_byte = cinfo->dest->next_output_byte;
+    state.free_in_buffer = cinfo->dest->free_in_buffer;
+    ASSIGN_STATE(state.cur, entropy->saved);
+    state.cinfo = cinfo;
+
+    /* Flush out the last data */
+    if (! flush_bits_s(&state))
+      ERREXIT(cinfo, JERR_CANT_SUSPEND);
+
+    /* Update state */
+    cinfo->dest->next_output_byte = state.next_output_byte;
+    cinfo->dest->free_in_buffer = state.free_in_buffer;
+    ASSIGN_STATE(entropy->saved, state.cur);
+  }
+}
+
+
+/*
+ * Huffman coding optimization.
+ *
+ * We first scan the supplied data and count the number of uses of each symbol
+ * that is to be Huffman-coded. (This process MUST agree with the code above.)
+ * Then we build a Huffman coding tree for the observed counts.
+ * Symbols which are not needed at all for the particular image are not
+ * assigned any code, which saves space in the DHT marker as well as in
+ * the compressed data.
+ */
+
+
+/* Process a single block's worth of coefficients */
+
+LOCAL(void)
+htest_one_block (j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val,
+		 long dc_counts[], long ac_counts[])
+{
+  register int temp;
+  register int nbits;
+  register int r, k;
+  int Se = cinfo->lim_Se;
+  const int * natural_order = cinfo->natural_order;
+
+  /* Encode the DC coefficient difference per section F.1.2.1 */
+
+  temp = block[0] - last_dc_val;
+  if (temp < 0)
+    temp = -temp;
+
+  /* Find the number of bits needed for the magnitude of the coefficient */
+  nbits = 0;
+  while (temp) {
+    nbits++;
+    temp >>= 1;
+  }
+  /* Check for out-of-range coefficient values.
+   * Since we're encoding a difference, the range limit is twice as much.
+   */
+  if (nbits > MAX_COEF_BITS+1)
+    ERREXIT(cinfo, JERR_BAD_DCT_COEF);
+
+  /* Count the Huffman symbol for the number of bits */
+  dc_counts[nbits]++;
+
+  /* Encode the AC coefficients per section F.1.2.2 */
+
+  r = 0;			/* r = run length of zeros */
+
+  for (k = 1; k <= Se; k++) {
+    if ((temp = block[natural_order[k]]) == 0) {
+      r++;
+    } else {
+      /* if run length > 15, must emit special run-length-16 codes (0xF0) */
+      while (r > 15) {
+	ac_counts[0xF0]++;
+	r -= 16;
+      }
+
+      /* Find the number of bits needed for the magnitude of the coefficient */
+      if (temp < 0)
+	temp = -temp;
+
+      /* Find the number of bits needed for the magnitude of the coefficient */
+      nbits = 1;		/* there must be at least one 1 bit */
+      while ((temp >>= 1))
+	nbits++;
+      /* Check for out-of-range coefficient values */
+      if (nbits > MAX_COEF_BITS)
+	ERREXIT(cinfo, JERR_BAD_DCT_COEF);
+
+      /* Count Huffman symbol for run length / number of bits */
+      ac_counts[(r << 4) + nbits]++;
+
+      r = 0;
+    }
+  }
+
+  /* If the last coef(s) were zero, emit an end-of-block code */
+  if (r > 0)
+    ac_counts[0]++;
+}
+
+
+/*
+ * Trial-encode one MCU's worth of Huffman-compressed coefficients.
+ * No data is actually output, so no suspension return is possible.
+ */
+
+METHODDEF(boolean)
+encode_mcu_gather (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+  int blkn, ci;
+  jpeg_component_info * compptr;
+
+  /* Take care of restart intervals if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0) {
+      /* Re-initialize DC predictions to 0 */
+      for (ci = 0; ci < cinfo->comps_in_scan; ci++)
+	entropy->saved.last_dc_val[ci] = 0;
+      /* Update restart state */
+      entropy->restarts_to_go = cinfo->restart_interval;
+    }
+    entropy->restarts_to_go--;
+  }
+
+  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+    ci = cinfo->MCU_membership[blkn];
+    compptr = cinfo->cur_comp_info[ci];
+    htest_one_block(cinfo, MCU_data[blkn][0], entropy->saved.last_dc_val[ci],
+		    entropy->dc_count_ptrs[compptr->dc_tbl_no],
+		    entropy->ac_count_ptrs[compptr->ac_tbl_no]);
+    entropy->saved.last_dc_val[ci] = MCU_data[blkn][0][0];
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * Generate the best Huffman code table for the given counts, fill htbl.
+ *
+ * The JPEG standard requires that no symbol be assigned a codeword of all
+ * one bits (so that padding bits added at the end of a compressed segment
+ * can't look like a valid code).  Because of the canonical ordering of
+ * codewords, this just means that there must be an unused slot in the
+ * longest codeword length category.  Section K.2 of the JPEG spec suggests
+ * reserving such a slot by pretending that symbol 256 is a valid symbol
+ * with count 1.  In theory that's not optimal; giving it count zero but
+ * including it in the symbol set anyway should give a better Huffman code.
+ * But the theoretically better code actually seems to come out worse in
+ * practice, because it produces more all-ones bytes (which incur stuffed
+ * zero bytes in the final file).  In any case the difference is tiny.
+ *
+ * The JPEG standard requires Huffman codes to be no more than 16 bits long.
+ * If some symbols have a very small but nonzero probability, the Huffman tree
+ * must be adjusted to meet the code length restriction.  We currently use
+ * the adjustment method suggested in JPEG section K.2.  This method is *not*
+ * optimal; it may not choose the best possible limited-length code.  But
+ * typically only very-low-frequency symbols will be given less-than-optimal
+ * lengths, so the code is almost optimal.  Experimental comparisons against
+ * an optimal limited-length-code algorithm indicate that the difference is
+ * microscopic --- usually less than a hundredth of a percent of total size.
+ * So the extra complexity of an optimal algorithm doesn't seem worthwhile.
+ */
+
+LOCAL(void)
+jpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])
+{
+#define MAX_CLEN 32		/* assumed maximum initial code length */
+  UINT8 bits[MAX_CLEN+1];	/* bits[k] = # of symbols with code length k */
+  int codesize[257];		/* codesize[k] = code length of symbol k */
+  int others[257];		/* next symbol in current branch of tree */
+  int c1, c2;
+  int p, i, j;
+  long v;
+
+  /* This algorithm is explained in section K.2 of the JPEG standard */
+
+  MEMZERO(bits, SIZEOF(bits));
+  MEMZERO(codesize, SIZEOF(codesize));
+  for (i = 0; i < 257; i++)
+    others[i] = -1;		/* init links to empty */
+  
+  freq[256] = 1;		/* make sure 256 has a nonzero count */
+  /* Including the pseudo-symbol 256 in the Huffman procedure guarantees
+   * that no real symbol is given code-value of all ones, because 256
+   * will be placed last in the largest codeword category.
+   */
+
+  /* Huffman's basic algorithm to assign optimal code lengths to symbols */
+
+  for (;;) {
+    /* Find the smallest nonzero frequency, set c1 = its symbol */
+    /* In case of ties, take the larger symbol number */
+    c1 = -1;
+    v = 1000000000L;
+    for (i = 0; i <= 256; i++) {
+      if (freq[i] && freq[i] <= v) {
+	v = freq[i];
+	c1 = i;
+      }
+    }
+
+    /* Find the next smallest nonzero frequency, set c2 = its symbol */
+    /* In case of ties, take the larger symbol number */
+    c2 = -1;
+    v = 1000000000L;
+    for (i = 0; i <= 256; i++) {
+      if (freq[i] && freq[i] <= v && i != c1) {
+	v = freq[i];
+	c2 = i;
+      }
+    }
+
+    /* Done if we've merged everything into one frequency */
+    if (c2 < 0)
+      break;
+    
+    /* Else merge the two counts/trees */
+    freq[c1] += freq[c2];
+    freq[c2] = 0;
+
+    /* Increment the codesize of everything in c1's tree branch */
+    codesize[c1]++;
+    while (others[c1] >= 0) {
+      c1 = others[c1];
+      codesize[c1]++;
+    }
+    
+    others[c1] = c2;		/* chain c2 onto c1's tree branch */
+    
+    /* Increment the codesize of everything in c2's tree branch */
+    codesize[c2]++;
+    while (others[c2] >= 0) {
+      c2 = others[c2];
+      codesize[c2]++;
+    }
+  }
+
+  /* Now count the number of symbols of each code length */
+  for (i = 0; i <= 256; i++) {
+    if (codesize[i]) {
+      /* The JPEG standard seems to think that this can't happen, */
+      /* but I'm paranoid... */
+      if (codesize[i] > MAX_CLEN)
+	ERREXIT(cinfo, JERR_HUFF_CLEN_OVERFLOW);
+
+      bits[codesize[i]]++;
+    }
+  }
+
+  /* JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure
+   * Huffman procedure assigned any such lengths, we must adjust the coding.
+   * Here is what the JPEG spec says about how this next bit works:
+   * Since symbols are paired for the longest Huffman code, the symbols are
+   * removed from this length category two at a time.  The prefix for the pair
+   * (which is one bit shorter) is allocated to one of the pair; then,
+   * skipping the BITS entry for that prefix length, a code word from the next
+   * shortest nonzero BITS entry is converted into a prefix for two code words
+   * one bit longer.
+   */
+  
+  for (i = MAX_CLEN; i > 16; i--) {
+    while (bits[i] > 0) {
+      j = i - 2;		/* find length of new prefix to be used */
+      while (bits[j] == 0)
+	j--;
+      
+      bits[i] -= 2;		/* remove two symbols */
+      bits[i-1]++;		/* one goes in this length */
+      bits[j+1] += 2;		/* two new symbols in this length */
+      bits[j]--;		/* symbol of this length is now a prefix */
+    }
+  }
+
+  /* Remove the count for the pseudo-symbol 256 from the largest codelength */
+  while (bits[i] == 0)		/* find largest codelength still in use */
+    i--;
+  bits[i]--;
+  
+  /* Return final symbol counts (only for lengths 0..16) */
+  MEMCOPY(htbl->bits, bits, SIZEOF(htbl->bits));
+  
+  /* Return a list of the symbols sorted by code length */
+  /* It's not real clear to me why we don't need to consider the codelength
+   * changes made above, but the JPEG spec seems to think this works.
+   */
+  p = 0;
+  for (i = 1; i <= MAX_CLEN; i++) {
+    for (j = 0; j <= 255; j++) {
+      if (codesize[j] == i) {
+	htbl->huffval[p] = (UINT8) j;
+	p++;
+      }
+    }
+  }
+
+  /* Set sent_table FALSE so updated table will be written to JPEG file. */
+  htbl->sent_table = FALSE;
+}
+
+
+/*
+ * Finish up a statistics-gathering pass and create the new Huffman tables.
+ */
+
+METHODDEF(void)
+finish_pass_gather (j_compress_ptr cinfo)
+{
+  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+  int ci, tbl;
+  jpeg_component_info * compptr;
+  JHUFF_TBL **htblptr;
+  boolean did_dc[NUM_HUFF_TBLS];
+  boolean did_ac[NUM_HUFF_TBLS];
+
+  /* It's important not to apply jpeg_gen_optimal_table more than once
+   * per table, because it clobbers the input frequency counts!
+   */
+  if (cinfo->progressive_mode)
+    /* Flush out buffered data (all we care about is counting the EOB symbol) */
+    emit_eobrun(entropy);
+
+  MEMZERO(did_dc, SIZEOF(did_dc));
+  MEMZERO(did_ac, SIZEOF(did_ac));
+
+  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+    compptr = cinfo->cur_comp_info[ci];
+    /* DC needs no table for refinement scan */
+    if (cinfo->Ss == 0 && cinfo->Ah == 0) {
+      tbl = compptr->dc_tbl_no;
+      if (! did_dc[tbl]) {
+	htblptr = & cinfo->dc_huff_tbl_ptrs[tbl];
+	if (*htblptr == NULL)
+	  *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
+	jpeg_gen_optimal_table(cinfo, *htblptr, entropy->dc_count_ptrs[tbl]);
+	did_dc[tbl] = TRUE;
+      }
+    }
+    /* AC needs no table when not present */
+    if (cinfo->Se) {
+      tbl = compptr->ac_tbl_no;
+      if (! did_ac[tbl]) {
+	htblptr = & cinfo->ac_huff_tbl_ptrs[tbl];
+	if (*htblptr == NULL)
+	  *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
+	jpeg_gen_optimal_table(cinfo, *htblptr, entropy->ac_count_ptrs[tbl]);
+	did_ac[tbl] = TRUE;
+      }
+    }
+  }
+}
+
+
+/*
+ * Initialize for a Huffman-compressed scan.
+ * If gather_statistics is TRUE, we do not output anything during the scan,
+ * just count the Huffman symbols used and generate Huffman code tables.
+ */
+
+METHODDEF(void)
+start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics)
+{
+  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+  int ci, tbl;
+  jpeg_component_info * compptr;
+
+  if (gather_statistics)
+    entropy->pub.finish_pass = finish_pass_gather;
+  else
+    entropy->pub.finish_pass = finish_pass_huff;
+
+  if (cinfo->progressive_mode) {
+    entropy->cinfo = cinfo;
+    entropy->gather_statistics = gather_statistics;
+
+    /* We assume jcmaster.c already validated the scan parameters. */
+
+    /* Select execution routine */
+    if (cinfo->Ah == 0) {
+      if (cinfo->Ss == 0)
+	entropy->pub.encode_mcu = encode_mcu_DC_first;
+      else
+	entropy->pub.encode_mcu = encode_mcu_AC_first;
+    } else {
+      if (cinfo->Ss == 0)
+	entropy->pub.encode_mcu = encode_mcu_DC_refine;
+      else {
+	entropy->pub.encode_mcu = encode_mcu_AC_refine;
+	/* AC refinement needs a correction bit buffer */
+	if (entropy->bit_buffer == NULL)
+	  entropy->bit_buffer = (char *)
+	    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+					MAX_CORR_BITS * SIZEOF(char));
+      }
+    }
+
+    /* Initialize AC stuff */
+    entropy->ac_tbl_no = cinfo->cur_comp_info[0]->ac_tbl_no;
+    entropy->EOBRUN = 0;
+    entropy->BE = 0;
+  } else {
+    if (gather_statistics)
+      entropy->pub.encode_mcu = encode_mcu_gather;
+    else
+      entropy->pub.encode_mcu = encode_mcu_huff;
+  }
+
+  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+    compptr = cinfo->cur_comp_info[ci];
+    /* DC needs no table for refinement scan */
+    if (cinfo->Ss == 0 && cinfo->Ah == 0) {
+      tbl = compptr->dc_tbl_no;
+      if (gather_statistics) {
+	/* Check for invalid table index */
+	/* (make_c_derived_tbl does this in the other path) */
+	if (tbl < 0 || tbl >= NUM_HUFF_TBLS)
+	  ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl);
+	/* Allocate and zero the statistics tables */
+	/* Note that jpeg_gen_optimal_table expects 257 entries in each table! */
+	if (entropy->dc_count_ptrs[tbl] == NULL)
+	  entropy->dc_count_ptrs[tbl] = (long *)
+	    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+					257 * SIZEOF(long));
+	MEMZERO(entropy->dc_count_ptrs[tbl], 257 * SIZEOF(long));
+      } else {
+	/* Compute derived values for Huffman tables */
+	/* We may do this more than once for a table, but it's not expensive */
+	jpeg_make_c_derived_tbl(cinfo, TRUE, tbl,
+				& entropy->dc_derived_tbls[tbl]);
+      }
+      /* Initialize DC predictions to 0 */
+      entropy->saved.last_dc_val[ci] = 0;
+    }
+    /* AC needs no table when not present */
+    if (cinfo->Se) {
+      tbl = compptr->ac_tbl_no;
+      if (gather_statistics) {
+	if (tbl < 0 || tbl >= NUM_HUFF_TBLS)
+	  ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl);
+	if (entropy->ac_count_ptrs[tbl] == NULL)
+	  entropy->ac_count_ptrs[tbl] = (long *)
+	    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+					257 * SIZEOF(long));
+	MEMZERO(entropy->ac_count_ptrs[tbl], 257 * SIZEOF(long));
+      } else {
+	jpeg_make_c_derived_tbl(cinfo, FALSE, tbl,
+				& entropy->ac_derived_tbls[tbl]);
+      }
+    }
+  }
+
+  /* Initialize bit buffer to empty */
+  entropy->saved.put_buffer = 0;
+  entropy->saved.put_bits = 0;
+
+  /* Initialize restart stuff */
+  entropy->restarts_to_go = cinfo->restart_interval;
+  entropy->next_restart_num = 0;
+}
+
+
+/*
+ * Module initialization routine for Huffman entropy encoding.
+ */
+
+GLOBAL(void)
+jinit_huff_encoder (j_compress_ptr cinfo)
+{
+  huff_entropy_ptr entropy;
+  int i;
+
+  entropy = (huff_entropy_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(huff_entropy_encoder));
+  cinfo->entropy = &entropy->pub;
+  entropy->pub.start_pass = start_pass_huff;
+
+  /* Mark tables unallocated */
+  for (i = 0; i < NUM_HUFF_TBLS; i++) {
+    entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL;
+    entropy->dc_count_ptrs[i] = entropy->ac_count_ptrs[i] = NULL;
+  }
+
+  if (cinfo->progressive_mode)
+    entropy->bit_buffer = NULL;	/* needed only in AC refinement scan */
+}
diff --git a/source/Irrlicht/jpeglib/jcinit.c b/source/Irrlicht/jpeglib/jcinit.c
new file mode 100644
index 00000000..397b488a
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jcinit.c
@@ -0,0 +1,84 @@
+/*
+ * jcinit.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2003-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains initialization logic for the JPEG compressor.
+ * This routine is in charge of selecting the modules to be executed and
+ * making an initialization call to each one.
+ *
+ * Logically, this code belongs in jcmaster.c.  It's split out because
+ * linking this routine implies linking the entire compression library.
+ * For a transcoding-only application, we want to be able to use jcmaster.c
+ * without linking in the whole library.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Master selection of compression modules.
+ * This is done once at the start of processing an image.  We determine
+ * which modules will be used and give them appropriate initialization calls.
+ */
+
+GLOBAL(void)
+jinit_compress_master (j_compress_ptr cinfo)
+{
+  long samplesperrow;
+  JDIMENSION jd_samplesperrow;
+
+  /* For now, precision must match compiled-in value... */
+  if (cinfo->data_precision != BITS_IN_JSAMPLE)
+    ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+  /* Sanity check on image dimensions */
+  if (cinfo->image_height <= 0 || cinfo->image_width <= 0 ||
+      cinfo->input_components <= 0)
+    ERREXIT(cinfo, JERR_EMPTY_IMAGE);
+
+  /* Width of an input scanline must be representable as JDIMENSION. */
+  samplesperrow = (long) cinfo->image_width * (long) cinfo->input_components;
+  jd_samplesperrow = (JDIMENSION) samplesperrow;
+  if ((long) jd_samplesperrow != samplesperrow)
+    ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+
+  /* Initialize master control (includes parameter checking/processing) */
+  jinit_c_master_control(cinfo, FALSE /* full compression */);
+
+  /* Preprocessing */
+  if (! cinfo->raw_data_in) {
+    jinit_color_converter(cinfo);
+    jinit_downsampler(cinfo);
+    jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */);
+  }
+  /* Forward DCT */
+  jinit_forward_dct(cinfo);
+  /* Entropy encoding: either Huffman or arithmetic coding. */
+  if (cinfo->arith_code)
+    jinit_arith_encoder(cinfo);
+  else {
+    jinit_huff_encoder(cinfo);
+  }
+
+  /* Need a full-image coefficient buffer in any multi-pass mode. */
+  jinit_c_coef_controller(cinfo,
+		(boolean) (cinfo->num_scans > 1 || cinfo->optimize_coding));
+  jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */);
+
+  jinit_marker_writer(cinfo);
+
+  /* We can now tell the memory manager to allocate virtual arrays. */
+  (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
+
+  /* Write the datastream header (SOI) immediately.
+   * Frame and scan headers are postponed till later.
+   * This lets application insert special markers after the SOI.
+   */
+  (*cinfo->marker->write_file_header) (cinfo);
+}
diff --git a/source/Irrlicht/jpeglib/jcmainct.c b/source/Irrlicht/jpeglib/jcmainct.c
new file mode 100644
index 00000000..29d53a22
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jcmainct.c
@@ -0,0 +1,297 @@
+/*
+ * jcmainct.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2003-2012 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the main buffer controller for compression.
+ * The main buffer lies between the pre-processor and the JPEG
+ * compressor proper; it holds downsampled data in the JPEG colorspace.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Note: currently, there is no operating mode in which a full-image buffer
+ * is needed at this step.  If there were, that mode could not be used with
+ * "raw data" input, since this module is bypassed in that case.  However,
+ * we've left the code here for possible use in special applications.
+ */
+#undef FULL_MAIN_BUFFER_SUPPORTED
+
+
+/* Private buffer controller object */
+
+typedef struct {
+  struct jpeg_c_main_controller pub; /* public fields */
+
+  JDIMENSION cur_iMCU_row;	/* number of current iMCU row */
+  JDIMENSION rowgroup_ctr;	/* counts row groups received in iMCU row */
+  boolean suspended;		/* remember if we suspended output */
+  J_BUF_MODE pass_mode;		/* current operating mode */
+
+  /* If using just a strip buffer, this points to the entire set of buffers
+   * (we allocate one for each component).  In the full-image case, this
+   * points to the currently accessible strips of the virtual arrays.
+   */
+  JSAMPARRAY buffer[MAX_COMPONENTS];
+
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+  /* If using full-image storage, this array holds pointers to virtual-array
+   * control blocks for each component.  Unused if not full-image storage.
+   */
+  jvirt_sarray_ptr whole_image[MAX_COMPONENTS];
+#endif
+} my_main_controller;
+
+typedef my_main_controller * my_main_ptr;
+
+
+/* Forward declarations */
+METHODDEF(void) process_data_simple_main
+	JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf,
+	     JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail));
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+METHODDEF(void) process_data_buffer_main
+	JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf,
+	     JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail));
+#endif
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+  my_main_ptr mainp = (my_main_ptr) cinfo->main;
+
+  /* Do nothing in raw-data mode. */
+  if (cinfo->raw_data_in)
+    return;
+
+  mainp->cur_iMCU_row = 0;	/* initialize counters */
+  mainp->rowgroup_ctr = 0;
+  mainp->suspended = FALSE;
+  mainp->pass_mode = pass_mode;	/* save mode for use by process_data */
+
+  switch (pass_mode) {
+  case JBUF_PASS_THRU:
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+    if (mainp->whole_image[0] != NULL)
+      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+#endif
+    mainp->pub.process_data = process_data_simple_main;
+    break;
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+  case JBUF_SAVE_SOURCE:
+  case JBUF_CRANK_DEST:
+  case JBUF_SAVE_AND_PASS:
+    if (mainp->whole_image[0] == NULL)
+      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+    mainp->pub.process_data = process_data_buffer_main;
+    break;
+#endif
+  default:
+    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+    break;
+  }
+}
+
+
+/*
+ * Process some data.
+ * This routine handles the simple pass-through mode,
+ * where we have only a strip buffer.
+ */
+
+METHODDEF(void)
+process_data_simple_main (j_compress_ptr cinfo,
+			  JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+			  JDIMENSION in_rows_avail)
+{
+  my_main_ptr mainp = (my_main_ptr) cinfo->main;
+
+  while (mainp->cur_iMCU_row < cinfo->total_iMCU_rows) {
+    /* Read input data if we haven't filled the main buffer yet */
+    if (mainp->rowgroup_ctr < (JDIMENSION) cinfo->min_DCT_v_scaled_size)
+      (*cinfo->prep->pre_process_data) (cinfo,
+					input_buf, in_row_ctr, in_rows_avail,
+					mainp->buffer, &mainp->rowgroup_ctr,
+					(JDIMENSION) cinfo->min_DCT_v_scaled_size);
+
+    /* If we don't have a full iMCU row buffered, return to application for
+     * more data.  Note that preprocessor will always pad to fill the iMCU row
+     * at the bottom of the image.
+     */
+    if (mainp->rowgroup_ctr != (JDIMENSION) cinfo->min_DCT_v_scaled_size)
+      return;
+
+    /* Send the completed row to the compressor */
+    if (! (*cinfo->coef->compress_data) (cinfo, mainp->buffer)) {
+      /* If compressor did not consume the whole row, then we must need to
+       * suspend processing and return to the application.  In this situation
+       * we pretend we didn't yet consume the last input row; otherwise, if
+       * it happened to be the last row of the image, the application would
+       * think we were done.
+       */
+      if (! mainp->suspended) {
+	(*in_row_ctr)--;
+	mainp->suspended = TRUE;
+      }
+      return;
+    }
+    /* We did finish the row.  Undo our little suspension hack if a previous
+     * call suspended; then mark the main buffer empty.
+     */
+    if (mainp->suspended) {
+      (*in_row_ctr)++;
+      mainp->suspended = FALSE;
+    }
+    mainp->rowgroup_ctr = 0;
+    mainp->cur_iMCU_row++;
+  }
+}
+
+
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+
+/*
+ * Process some data.
+ * This routine handles all of the modes that use a full-size buffer.
+ */
+
+METHODDEF(void)
+process_data_buffer_main (j_compress_ptr cinfo,
+			  JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+			  JDIMENSION in_rows_avail)
+{
+  my_main_ptr mainp = (my_main_ptr) cinfo->main;
+  int ci;
+  jpeg_component_info *compptr;
+  boolean writing = (mainp->pass_mode != JBUF_CRANK_DEST);
+
+  while (mainp->cur_iMCU_row < cinfo->total_iMCU_rows) {
+    /* Realign the virtual buffers if at the start of an iMCU row. */
+    if (mainp->rowgroup_ctr == 0) {
+      for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+	   ci++, compptr++) {
+	mainp->buffer[ci] = (*cinfo->mem->access_virt_sarray)
+	  ((j_common_ptr) cinfo, mainp->whole_image[ci], mainp->cur_iMCU_row *
+	   ((JDIMENSION) (compptr->v_samp_factor * cinfo->min_DCT_v_scaled_size)),
+	   (JDIMENSION) (compptr->v_samp_factor * cinfo->min_DCT_v_scaled_size),
+	   writing);
+      }
+      /* In a read pass, pretend we just read some source data. */
+      if (! writing) {
+	*in_row_ctr += (JDIMENSION)
+	  (cinfo->max_v_samp_factor * cinfo->min_DCT_v_scaled_size);
+	mainp->rowgroup_ctr = (JDIMENSION) cinfo->min_DCT_v_scaled_size;
+      }
+    }
+
+    /* If a write pass, read input data until the current iMCU row is full. */
+    /* Note: preprocessor will pad if necessary to fill the last iMCU row. */
+    if (writing) {
+      (*cinfo->prep->pre_process_data) (cinfo,
+					input_buf, in_row_ctr, in_rows_avail,
+					mainp->buffer, &mainp->rowgroup_ctr,
+					(JDIMENSION) cinfo->min_DCT_v_scaled_size);
+      /* Return to application if we need more data to fill the iMCU row. */
+      if (mainp->rowgroup_ctr < (JDIMENSION) cinfo->min_DCT_v_scaled_size)
+	return;
+    }
+
+    /* Emit data, unless this is a sink-only pass. */
+    if (mainp->pass_mode != JBUF_SAVE_SOURCE) {
+      if (! (*cinfo->coef->compress_data) (cinfo, mainp->buffer)) {
+	/* If compressor did not consume the whole row, then we must need to
+	 * suspend processing and return to the application.  In this situation
+	 * we pretend we didn't yet consume the last input row; otherwise, if
+	 * it happened to be the last row of the image, the application would
+	 * think we were done.
+	 */
+	if (! mainp->suspended) {
+	  (*in_row_ctr)--;
+	  mainp->suspended = TRUE;
+	}
+	return;
+      }
+      /* We did finish the row.  Undo our little suspension hack if a previous
+       * call suspended; then mark the main buffer empty.
+       */
+      if (mainp->suspended) {
+	(*in_row_ctr)++;
+	mainp->suspended = FALSE;
+      }
+    }
+
+    /* If get here, we are done with this iMCU row.  Mark buffer empty. */
+    mainp->rowgroup_ctr = 0;
+    mainp->cur_iMCU_row++;
+  }
+}
+
+#endif /* FULL_MAIN_BUFFER_SUPPORTED */
+
+
+/*
+ * Initialize main buffer controller.
+ */
+
+GLOBAL(void)
+jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer)
+{
+  my_main_ptr mainp;
+  int ci;
+  jpeg_component_info *compptr;
+
+  mainp = (my_main_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(my_main_controller));
+  cinfo->main = &mainp->pub;
+  mainp->pub.start_pass = start_pass_main;
+
+  /* We don't need to create a buffer in raw-data mode. */
+  if (cinfo->raw_data_in)
+    return;
+
+  /* Create the buffer.  It holds downsampled data, so each component
+   * may be of a different size.
+   */
+  if (need_full_buffer) {
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+    /* Allocate a full-image virtual array for each component */
+    /* Note we pad the bottom to a multiple of the iMCU height */
+    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+	 ci++, compptr++) {
+      mainp->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
+	((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+	 compptr->width_in_blocks * ((JDIMENSION) compptr->DCT_h_scaled_size),
+	 ((JDIMENSION) jround_up((long) compptr->height_in_blocks,
+				 (long) compptr->v_samp_factor)) *
+	 ((JDIMENSION) cinfo->min_DCT_v_scaled_size),
+	 (JDIMENSION) (compptr->v_samp_factor * compptr->DCT_v_scaled_size));
+    }
+#else
+    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+#endif
+  } else {
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+    mainp->whole_image[0] = NULL; /* flag for no virtual arrays */
+#endif
+    /* Allocate a strip buffer for each component */
+    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+	 ci++, compptr++) {
+      mainp->buffer[ci] = (*cinfo->mem->alloc_sarray)
+	((j_common_ptr) cinfo, JPOOL_IMAGE,
+	 compptr->width_in_blocks * ((JDIMENSION) compptr->DCT_h_scaled_size),
+	 (JDIMENSION) (compptr->v_samp_factor * compptr->DCT_v_scaled_size));
+    }
+  }
+}
diff --git a/source/Irrlicht/jpeglib/jcmarker.c b/source/Irrlicht/jpeglib/jcmarker.c
new file mode 100644
index 00000000..f2cd7a39
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jcmarker.c
@@ -0,0 +1,719 @@
+/*
+ * jcmarker.c
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Modified 2003-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to write JPEG datastream markers.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+typedef enum {			/* JPEG marker codes */
+  M_SOF0  = 0xc0,
+  M_SOF1  = 0xc1,
+  M_SOF2  = 0xc2,
+  M_SOF3  = 0xc3,
+
+  M_SOF5  = 0xc5,
+  M_SOF6  = 0xc6,
+  M_SOF7  = 0xc7,
+
+  M_JPG   = 0xc8,
+  M_SOF9  = 0xc9,
+  M_SOF10 = 0xca,
+  M_SOF11 = 0xcb,
+
+  M_SOF13 = 0xcd,
+  M_SOF14 = 0xce,
+  M_SOF15 = 0xcf,
+
+  M_DHT   = 0xc4,
+
+  M_DAC   = 0xcc,
+
+  M_RST0  = 0xd0,
+  M_RST1  = 0xd1,
+  M_RST2  = 0xd2,
+  M_RST3  = 0xd3,
+  M_RST4  = 0xd4,
+  M_RST5  = 0xd5,
+  M_RST6  = 0xd6,
+  M_RST7  = 0xd7,
+
+  M_SOI   = 0xd8,
+  M_EOI   = 0xd9,
+  M_SOS   = 0xda,
+  M_DQT   = 0xdb,
+  M_DNL   = 0xdc,
+  M_DRI   = 0xdd,
+  M_DHP   = 0xde,
+  M_EXP   = 0xdf,
+
+  M_APP0  = 0xe0,
+  M_APP1  = 0xe1,
+  M_APP2  = 0xe2,
+  M_APP3  = 0xe3,
+  M_APP4  = 0xe4,
+  M_APP5  = 0xe5,
+  M_APP6  = 0xe6,
+  M_APP7  = 0xe7,
+  M_APP8  = 0xe8,
+  M_APP9  = 0xe9,
+  M_APP10 = 0xea,
+  M_APP11 = 0xeb,
+  M_APP12 = 0xec,
+  M_APP13 = 0xed,
+  M_APP14 = 0xee,
+  M_APP15 = 0xef,
+
+  M_JPG0  = 0xf0,
+  M_JPG8  = 0xf8,
+  M_JPG13 = 0xfd,
+  M_COM   = 0xfe,
+
+  M_TEM   = 0x01,
+
+  M_ERROR = 0x100
+} JPEG_MARKER;
+
+
+/* Private state */
+
+typedef struct {
+  struct jpeg_marker_writer pub; /* public fields */
+
+  unsigned int last_restart_interval; /* last DRI value emitted; 0 after SOI */
+} my_marker_writer;
+
+typedef my_marker_writer * my_marker_ptr;
+
+
+/*
+ * Basic output routines.
+ *
+ * Note that we do not support suspension while writing a marker.
+ * Therefore, an application using suspension must ensure that there is
+ * enough buffer space for the initial markers (typ. 600-700 bytes) before
+ * calling jpeg_start_compress, and enough space to write the trailing EOI
+ * (a few bytes) before calling jpeg_finish_compress.  Multipass compression
+ * modes are not supported at all with suspension, so those two are the only
+ * points where markers will be written.
+ */
+
+LOCAL(void)
+emit_byte (j_compress_ptr cinfo, int val)
+/* Emit a byte */
+{
+  struct jpeg_destination_mgr * dest = cinfo->dest;
+
+  *(dest->next_output_byte)++ = (JOCTET) val;
+  if (--dest->free_in_buffer == 0) {
+    if (! (*dest->empty_output_buffer) (cinfo))
+      ERREXIT(cinfo, JERR_CANT_SUSPEND);
+  }
+}
+
+
+LOCAL(void)
+emit_marker (j_compress_ptr cinfo, JPEG_MARKER mark)
+/* Emit a marker code */
+{
+  emit_byte(cinfo, 0xFF);
+  emit_byte(cinfo, (int) mark);
+}
+
+
+LOCAL(void)
+emit_2bytes (j_compress_ptr cinfo, int value)
+/* Emit a 2-byte integer; these are always MSB first in JPEG files */
+{
+  emit_byte(cinfo, (value >> 8) & 0xFF);
+  emit_byte(cinfo, value & 0xFF);
+}
+
+
+/*
+ * Routines to write specific marker types.
+ */
+
+LOCAL(int)
+emit_dqt (j_compress_ptr cinfo, int index)
+/* Emit a DQT marker */
+/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */
+{
+  JQUANT_TBL * qtbl = cinfo->quant_tbl_ptrs[index];
+  int prec;
+  int i;
+
+  if (qtbl == NULL)
+    ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, index);
+
+  prec = 0;
+  for (i = 0; i <= cinfo->lim_Se; i++) {
+    if (qtbl->quantval[cinfo->natural_order[i]] > 255)
+      prec = 1;
+  }
+
+  if (! qtbl->sent_table) {
+    emit_marker(cinfo, M_DQT);
+
+    emit_2bytes(cinfo,
+      prec ? cinfo->lim_Se * 2 + 2 + 1 + 2 : cinfo->lim_Se + 1 + 1 + 2);
+
+    emit_byte(cinfo, index + (prec<<4));
+
+    for (i = 0; i <= cinfo->lim_Se; i++) {
+      /* The table entries must be emitted in zigzag order. */
+      unsigned int qval = qtbl->quantval[cinfo->natural_order[i]];
+      if (prec)
+	emit_byte(cinfo, (int) (qval >> 8));
+      emit_byte(cinfo, (int) (qval & 0xFF));
+    }
+
+    qtbl->sent_table = TRUE;
+  }
+
+  return prec;
+}
+
+
+LOCAL(void)
+emit_dht (j_compress_ptr cinfo, int index, boolean is_ac)
+/* Emit a DHT marker */
+{
+  JHUFF_TBL * htbl;
+  int length, i;
+  
+  if (is_ac) {
+    htbl = cinfo->ac_huff_tbl_ptrs[index];
+    index += 0x10;		/* output index has AC bit set */
+  } else {
+    htbl = cinfo->dc_huff_tbl_ptrs[index];
+  }
+
+  if (htbl == NULL)
+    ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, index);
+  
+  if (! htbl->sent_table) {
+    emit_marker(cinfo, M_DHT);
+    
+    length = 0;
+    for (i = 1; i <= 16; i++)
+      length += htbl->bits[i];
+    
+    emit_2bytes(cinfo, length + 2 + 1 + 16);
+    emit_byte(cinfo, index);
+    
+    for (i = 1; i <= 16; i++)
+      emit_byte(cinfo, htbl->bits[i]);
+    
+    for (i = 0; i < length; i++)
+      emit_byte(cinfo, htbl->huffval[i]);
+    
+    htbl->sent_table = TRUE;
+  }
+}
+
+
+LOCAL(void)
+emit_dac (j_compress_ptr cinfo)
+/* Emit a DAC marker */
+/* Since the useful info is so small, we want to emit all the tables in */
+/* one DAC marker.  Therefore this routine does its own scan of the table. */
+{
+#ifdef C_ARITH_CODING_SUPPORTED
+  char dc_in_use[NUM_ARITH_TBLS];
+  char ac_in_use[NUM_ARITH_TBLS];
+  int length, i;
+  jpeg_component_info *compptr;
+
+  for (i = 0; i < NUM_ARITH_TBLS; i++)
+    dc_in_use[i] = ac_in_use[i] = 0;
+
+  for (i = 0; i < cinfo->comps_in_scan; i++) {
+    compptr = cinfo->cur_comp_info[i];
+    /* DC needs no table for refinement scan */
+    if (cinfo->Ss == 0 && cinfo->Ah == 0)
+      dc_in_use[compptr->dc_tbl_no] = 1;
+    /* AC needs no table when not present */
+    if (cinfo->Se)
+      ac_in_use[compptr->ac_tbl_no] = 1;
+  }
+
+  length = 0;
+  for (i = 0; i < NUM_ARITH_TBLS; i++)
+    length += dc_in_use[i] + ac_in_use[i];
+
+  if (length) {
+    emit_marker(cinfo, M_DAC);
+
+    emit_2bytes(cinfo, length*2 + 2);
+
+    for (i = 0; i < NUM_ARITH_TBLS; i++) {
+      if (dc_in_use[i]) {
+	emit_byte(cinfo, i);
+	emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4));
+      }
+      if (ac_in_use[i]) {
+	emit_byte(cinfo, i + 0x10);
+	emit_byte(cinfo, cinfo->arith_ac_K[i]);
+      }
+    }
+  }
+#endif /* C_ARITH_CODING_SUPPORTED */
+}
+
+
+LOCAL(void)
+emit_dri (j_compress_ptr cinfo)
+/* Emit a DRI marker */
+{
+  emit_marker(cinfo, M_DRI);
+  
+  emit_2bytes(cinfo, 4);	/* fixed length */
+
+  emit_2bytes(cinfo, (int) cinfo->restart_interval);
+}
+
+
+LOCAL(void)
+emit_lse_ict (j_compress_ptr cinfo)
+/* Emit an LSE inverse color transform specification marker */
+{
+  /* Support only 1 transform */
+  if (cinfo->color_transform != JCT_SUBTRACT_GREEN ||
+      cinfo->num_components < 3)
+    ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+
+  emit_marker(cinfo, M_JPG8);
+  
+  emit_2bytes(cinfo, 24);	/* fixed length */
+
+  emit_byte(cinfo, 0x0D);	/* ID inverse transform specification */
+  emit_2bytes(cinfo, MAXJSAMPLE);	/* MAXTRANS */
+  emit_byte(cinfo, 3);		/* Nt=3 */
+  emit_byte(cinfo, cinfo->comp_info[1].component_id);
+  emit_byte(cinfo, cinfo->comp_info[0].component_id);
+  emit_byte(cinfo, cinfo->comp_info[2].component_id);
+  emit_byte(cinfo, 0x80);	/* F1: CENTER1=1, NORM1=0 */
+  emit_2bytes(cinfo, 0);	/* A(1,1)=0 */
+  emit_2bytes(cinfo, 0);	/* A(1,2)=0 */
+  emit_byte(cinfo, 0);		/* F2: CENTER2=0, NORM2=0 */
+  emit_2bytes(cinfo, 1);	/* A(2,1)=1 */
+  emit_2bytes(cinfo, 0);	/* A(2,2)=0 */
+  emit_byte(cinfo, 0);		/* F3: CENTER3=0, NORM3=0 */
+  emit_2bytes(cinfo, 1);	/* A(3,1)=1 */
+  emit_2bytes(cinfo, 0);	/* A(3,2)=0 */
+}
+
+
+LOCAL(void)
+emit_sof (j_compress_ptr cinfo, JPEG_MARKER code)
+/* Emit a SOF marker */
+{
+  int ci;
+  jpeg_component_info *compptr;
+  
+  emit_marker(cinfo, code);
+  
+  emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */
+
+  /* Make sure image isn't bigger than SOF field can handle */
+  if ((long) cinfo->jpeg_height > 65535L ||
+      (long) cinfo->jpeg_width > 65535L)
+    ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535);
+
+  emit_byte(cinfo, cinfo->data_precision);
+  emit_2bytes(cinfo, (int) cinfo->jpeg_height);
+  emit_2bytes(cinfo, (int) cinfo->jpeg_width);
+
+  emit_byte(cinfo, cinfo->num_components);
+
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    emit_byte(cinfo, compptr->component_id);
+    emit_byte(cinfo, (compptr->h_samp_factor << 4) + compptr->v_samp_factor);
+    emit_byte(cinfo, compptr->quant_tbl_no);
+  }
+}
+
+
+LOCAL(void)
+emit_sos (j_compress_ptr cinfo)
+/* Emit a SOS marker */
+{
+  int i, td, ta;
+  jpeg_component_info *compptr;
+  
+  emit_marker(cinfo, M_SOS);
+  
+  emit_2bytes(cinfo, 2 * cinfo->comps_in_scan + 2 + 1 + 3); /* length */
+  
+  emit_byte(cinfo, cinfo->comps_in_scan);
+  
+  for (i = 0; i < cinfo->comps_in_scan; i++) {
+    compptr = cinfo->cur_comp_info[i];
+    emit_byte(cinfo, compptr->component_id);
+
+    /* We emit 0 for unused field(s); this is recommended by the P&M text
+     * but does not seem to be specified in the standard.
+     */
+
+    /* DC needs no table for refinement scan */
+    td = cinfo->Ss == 0 && cinfo->Ah == 0 ? compptr->dc_tbl_no : 0;
+    /* AC needs no table when not present */
+    ta = cinfo->Se ? compptr->ac_tbl_no : 0;
+
+    emit_byte(cinfo, (td << 4) + ta);
+  }
+
+  emit_byte(cinfo, cinfo->Ss);
+  emit_byte(cinfo, cinfo->Se);
+  emit_byte(cinfo, (cinfo->Ah << 4) + cinfo->Al);
+}
+
+
+LOCAL(void)
+emit_pseudo_sos (j_compress_ptr cinfo)
+/* Emit a pseudo SOS marker */
+{
+  emit_marker(cinfo, M_SOS);
+  
+  emit_2bytes(cinfo, 2 + 1 + 3); /* length */
+  
+  emit_byte(cinfo, 0); /* Ns */
+
+  emit_byte(cinfo, 0); /* Ss */
+  emit_byte(cinfo, cinfo->block_size * cinfo->block_size - 1); /* Se */
+  emit_byte(cinfo, 0); /* Ah/Al */
+}
+
+
+LOCAL(void)
+emit_jfif_app0 (j_compress_ptr cinfo)
+/* Emit a JFIF-compliant APP0 marker */
+{
+  /*
+   * Length of APP0 block	(2 bytes)
+   * Block ID			(4 bytes - ASCII "JFIF")
+   * Zero byte			(1 byte to terminate the ID string)
+   * Version Major, Minor	(2 bytes - major first)
+   * Units			(1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm)
+   * Xdpu			(2 bytes - dots per unit horizontal)
+   * Ydpu			(2 bytes - dots per unit vertical)
+   * Thumbnail X size		(1 byte)
+   * Thumbnail Y size		(1 byte)
+   */
+  
+  emit_marker(cinfo, M_APP0);
+  
+  emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */
+
+  emit_byte(cinfo, 0x4A);	/* Identifier: ASCII "JFIF" */
+  emit_byte(cinfo, 0x46);
+  emit_byte(cinfo, 0x49);
+  emit_byte(cinfo, 0x46);
+  emit_byte(cinfo, 0);
+  emit_byte(cinfo, cinfo->JFIF_major_version); /* Version fields */
+  emit_byte(cinfo, cinfo->JFIF_minor_version);
+  emit_byte(cinfo, cinfo->density_unit); /* Pixel size information */
+  emit_2bytes(cinfo, (int) cinfo->X_density);
+  emit_2bytes(cinfo, (int) cinfo->Y_density);
+  emit_byte(cinfo, 0);		/* No thumbnail image */
+  emit_byte(cinfo, 0);
+}
+
+
+LOCAL(void)
+emit_adobe_app14 (j_compress_ptr cinfo)
+/* Emit an Adobe APP14 marker */
+{
+  /*
+   * Length of APP14 block	(2 bytes)
+   * Block ID			(5 bytes - ASCII "Adobe")
+   * Version Number		(2 bytes - currently 100)
+   * Flags0			(2 bytes - currently 0)
+   * Flags1			(2 bytes - currently 0)
+   * Color transform		(1 byte)
+   *
+   * Although Adobe TN 5116 mentions Version = 101, all the Adobe files
+   * now in circulation seem to use Version = 100, so that's what we write.
+   *
+   * We write the color transform byte as 1 if the JPEG color space is
+   * YCbCr, 2 if it's YCCK, 0 otherwise.  Adobe's definition has to do with
+   * whether the encoder performed a transformation, which is pretty useless.
+   */
+  
+  emit_marker(cinfo, M_APP14);
+  
+  emit_2bytes(cinfo, 2 + 5 + 2 + 2 + 2 + 1); /* length */
+
+  emit_byte(cinfo, 0x41);	/* Identifier: ASCII "Adobe" */
+  emit_byte(cinfo, 0x64);
+  emit_byte(cinfo, 0x6F);
+  emit_byte(cinfo, 0x62);
+  emit_byte(cinfo, 0x65);
+  emit_2bytes(cinfo, 100);	/* Version */
+  emit_2bytes(cinfo, 0);	/* Flags0 */
+  emit_2bytes(cinfo, 0);	/* Flags1 */
+  switch (cinfo->jpeg_color_space) {
+  case JCS_YCbCr:
+    emit_byte(cinfo, 1);	/* Color transform = 1 */
+    break;
+  case JCS_YCCK:
+    emit_byte(cinfo, 2);	/* Color transform = 2 */
+    break;
+  default:
+    emit_byte(cinfo, 0);	/* Color transform = 0 */
+    break;
+  }
+}
+
+
+/*
+ * These routines allow writing an arbitrary marker with parameters.
+ * The only intended use is to emit COM or APPn markers after calling
+ * write_file_header and before calling write_frame_header.
+ * Other uses are not guaranteed to produce desirable results.
+ * Counting the parameter bytes properly is the caller's responsibility.
+ */
+
+METHODDEF(void)
+write_marker_header (j_compress_ptr cinfo, int marker, unsigned int datalen)
+/* Emit an arbitrary marker header */
+{
+  if (datalen > (unsigned int) 65533)		/* safety check */
+    ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+  emit_marker(cinfo, (JPEG_MARKER) marker);
+
+  emit_2bytes(cinfo, (int) (datalen + 2));	/* total length */
+}
+
+METHODDEF(void)
+write_marker_byte (j_compress_ptr cinfo, int val)
+/* Emit one byte of marker parameters following write_marker_header */
+{
+  emit_byte(cinfo, val);
+}
+
+
+/*
+ * Write datastream header.
+ * This consists of an SOI and optional APPn markers.
+ * We recommend use of the JFIF marker, but not the Adobe marker,
+ * when using YCbCr or grayscale data.  The JFIF marker is also used
+ * for other standard JPEG colorspaces.  The Adobe marker is helpful
+ * to distinguish RGB, CMYK, and YCCK colorspaces.
+ * Note that an application can write additional header markers after
+ * jpeg_start_compress returns.
+ */
+
+METHODDEF(void)
+write_file_header (j_compress_ptr cinfo)
+{
+  my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
+
+  emit_marker(cinfo, M_SOI);	/* first the SOI */
+
+  /* SOI is defined to reset restart interval to 0 */
+  marker->last_restart_interval = 0;
+
+  if (cinfo->write_JFIF_header)	/* next an optional JFIF APP0 */
+    emit_jfif_app0(cinfo);
+  if (cinfo->write_Adobe_marker) /* next an optional Adobe APP14 */
+    emit_adobe_app14(cinfo);
+}
+
+
+/*
+ * Write frame header.
+ * This consists of DQT and SOFn markers,
+ * a conditional LSE marker and a conditional pseudo SOS marker.
+ * Note that we do not emit the SOF until we have emitted the DQT(s).
+ * This avoids compatibility problems with incorrect implementations that
+ * try to error-check the quant table numbers as soon as they see the SOF.
+ */
+
+METHODDEF(void)
+write_frame_header (j_compress_ptr cinfo)
+{
+  int ci, prec;
+  boolean is_baseline;
+  jpeg_component_info *compptr;
+  
+  /* Emit DQT for each quantization table.
+   * Note that emit_dqt() suppresses any duplicate tables.
+   */
+  prec = 0;
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    prec += emit_dqt(cinfo, compptr->quant_tbl_no);
+  }
+  /* now prec is nonzero iff there are any 16-bit quant tables. */
+
+  /* Check for a non-baseline specification.
+   * Note we assume that Huffman table numbers won't be changed later.
+   */
+  if (cinfo->arith_code || cinfo->progressive_mode ||
+      cinfo->data_precision != 8 || cinfo->block_size != DCTSIZE) {
+    is_baseline = FALSE;
+  } else {
+    is_baseline = TRUE;
+    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+	 ci++, compptr++) {
+      if (compptr->dc_tbl_no > 1 || compptr->ac_tbl_no > 1)
+	is_baseline = FALSE;
+    }
+    if (prec && is_baseline) {
+      is_baseline = FALSE;
+      /* If it's baseline except for quantizer size, warn the user */
+      TRACEMS(cinfo, 0, JTRC_16BIT_TABLES);
+    }
+  }
+
+  /* Emit the proper SOF marker */
+  if (cinfo->arith_code) {
+    if (cinfo->progressive_mode)
+      emit_sof(cinfo, M_SOF10); /* SOF code for progressive arithmetic */
+    else
+      emit_sof(cinfo, M_SOF9);  /* SOF code for sequential arithmetic */
+  } else {
+    if (cinfo->progressive_mode)
+      emit_sof(cinfo, M_SOF2);	/* SOF code for progressive Huffman */
+    else if (is_baseline)
+      emit_sof(cinfo, M_SOF0);	/* SOF code for baseline implementation */
+    else
+      emit_sof(cinfo, M_SOF1);	/* SOF code for non-baseline Huffman file */
+  }
+
+  /* Check to emit LSE inverse color transform specification marker */
+  if (cinfo->color_transform)
+    emit_lse_ict(cinfo);
+
+  /* Check to emit pseudo SOS marker */
+  if (cinfo->progressive_mode && cinfo->block_size != DCTSIZE)
+    emit_pseudo_sos(cinfo);
+}
+
+
+/*
+ * Write scan header.
+ * This consists of DHT or DAC markers, optional DRI, and SOS.
+ * Compressed data will be written following the SOS.
+ */
+
+METHODDEF(void)
+write_scan_header (j_compress_ptr cinfo)
+{
+  my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
+  int i;
+  jpeg_component_info *compptr;
+
+  if (cinfo->arith_code) {
+    /* Emit arith conditioning info.  We may have some duplication
+     * if the file has multiple scans, but it's so small it's hardly
+     * worth worrying about.
+     */
+    emit_dac(cinfo);
+  } else {
+    /* Emit Huffman tables.
+     * Note that emit_dht() suppresses any duplicate tables.
+     */
+    for (i = 0; i < cinfo->comps_in_scan; i++) {
+      compptr = cinfo->cur_comp_info[i];
+      /* DC needs no table for refinement scan */
+      if (cinfo->Ss == 0 && cinfo->Ah == 0)
+	emit_dht(cinfo, compptr->dc_tbl_no, FALSE);
+      /* AC needs no table when not present */
+      if (cinfo->Se)
+	emit_dht(cinfo, compptr->ac_tbl_no, TRUE);
+    }
+  }
+
+  /* Emit DRI if required --- note that DRI value could change for each scan.
+   * We avoid wasting space with unnecessary DRIs, however.
+   */
+  if (cinfo->restart_interval != marker->last_restart_interval) {
+    emit_dri(cinfo);
+    marker->last_restart_interval = cinfo->restart_interval;
+  }
+
+  emit_sos(cinfo);
+}
+
+
+/*
+ * Write datastream trailer.
+ */
+
+METHODDEF(void)
+write_file_trailer (j_compress_ptr cinfo)
+{
+  emit_marker(cinfo, M_EOI);
+}
+
+
+/*
+ * Write an abbreviated table-specification datastream.
+ * This consists of SOI, DQT and DHT tables, and EOI.
+ * Any table that is defined and not marked sent_table = TRUE will be
+ * emitted.  Note that all tables will be marked sent_table = TRUE at exit.
+ */
+
+METHODDEF(void)
+write_tables_only (j_compress_ptr cinfo)
+{
+  int i;
+
+  emit_marker(cinfo, M_SOI);
+
+  for (i = 0; i < NUM_QUANT_TBLS; i++) {
+    if (cinfo->quant_tbl_ptrs[i] != NULL)
+      (void) emit_dqt(cinfo, i);
+  }
+
+  if (! cinfo->arith_code) {
+    for (i = 0; i < NUM_HUFF_TBLS; i++) {
+      if (cinfo->dc_huff_tbl_ptrs[i] != NULL)
+	emit_dht(cinfo, i, FALSE);
+      if (cinfo->ac_huff_tbl_ptrs[i] != NULL)
+	emit_dht(cinfo, i, TRUE);
+    }
+  }
+
+  emit_marker(cinfo, M_EOI);
+}
+
+
+/*
+ * Initialize the marker writer module.
+ */
+
+GLOBAL(void)
+jinit_marker_writer (j_compress_ptr cinfo)
+{
+  my_marker_ptr marker;
+
+  /* Create the subobject */
+  marker = (my_marker_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(my_marker_writer));
+  cinfo->marker = &marker->pub;
+  /* Initialize method pointers */
+  marker->pub.write_file_header = write_file_header;
+  marker->pub.write_frame_header = write_frame_header;
+  marker->pub.write_scan_header = write_scan_header;
+  marker->pub.write_file_trailer = write_file_trailer;
+  marker->pub.write_tables_only = write_tables_only;
+  marker->pub.write_marker_header = write_marker_header;
+  marker->pub.write_marker_byte = write_marker_byte;
+  /* Initialize private state */
+  marker->last_restart_interval = 0;
+}
diff --git a/source/Irrlicht/jpeglib/jcmaster.c b/source/Irrlicht/jpeglib/jcmaster.c
new file mode 100644
index 00000000..431744eb
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jcmaster.c
@@ -0,0 +1,856 @@
+/*
+ * jcmaster.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2003-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains master control logic for the JPEG compressor.
+ * These routines are concerned with parameter validation, initial setup,
+ * and inter-pass control (determining the number of passes and the work 
+ * to be done in each pass).
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private state */
+
+typedef enum {
+	main_pass,		/* input data, also do first output step */
+	huff_opt_pass,		/* Huffman code optimization pass */
+	output_pass		/* data output pass */
+} c_pass_type;
+
+typedef struct {
+  struct jpeg_comp_master pub;	/* public fields */
+
+  c_pass_type pass_type;	/* the type of the current pass */
+
+  int pass_number;		/* # of passes completed */
+  int total_passes;		/* total # of passes needed */
+
+  int scan_number;		/* current index in scan_info[] */
+} my_comp_master;
+
+typedef my_comp_master * my_master_ptr;
+
+
+/*
+ * Support routines that do various essential calculations.
+ */
+
+/*
+ * Compute JPEG image dimensions and related values.
+ * NOTE: this is exported for possible use by application.
+ * Hence it mustn't do anything that can't be done twice.
+ */
+
+GLOBAL(void)
+jpeg_calc_jpeg_dimensions (j_compress_ptr cinfo)
+/* Do computations that are needed before master selection phase */
+{
+#ifdef DCT_SCALING_SUPPORTED
+
+  /* Sanity check on input image dimensions to prevent overflow in
+   * following calculation.
+   * We do check jpeg_width and jpeg_height in initial_setup below,
+   * but image_width and image_height can come from arbitrary data,
+   * and we need some space for multiplication by block_size.
+   */
+  if (((long) cinfo->image_width >> 24) || ((long) cinfo->image_height >> 24))
+    ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
+
+  /* Compute actual JPEG image dimensions and DCT scaling choices. */
+  if (cinfo->scale_num >= cinfo->scale_denom * cinfo->block_size) {
+    /* Provide block_size/1 scaling */
+    cinfo->jpeg_width = cinfo->image_width * cinfo->block_size;
+    cinfo->jpeg_height = cinfo->image_height * cinfo->block_size;
+    cinfo->min_DCT_h_scaled_size = 1;
+    cinfo->min_DCT_v_scaled_size = 1;
+  } else if (cinfo->scale_num * 2 >= cinfo->scale_denom * cinfo->block_size) {
+    /* Provide block_size/2 scaling */
+    cinfo->jpeg_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 2L);
+    cinfo->jpeg_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 2L);
+    cinfo->min_DCT_h_scaled_size = 2;
+    cinfo->min_DCT_v_scaled_size = 2;
+  } else if (cinfo->scale_num * 3 >= cinfo->scale_denom * cinfo->block_size) {
+    /* Provide block_size/3 scaling */
+    cinfo->jpeg_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 3L);
+    cinfo->jpeg_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 3L);
+    cinfo->min_DCT_h_scaled_size = 3;
+    cinfo->min_DCT_v_scaled_size = 3;
+  } else if (cinfo->scale_num * 4 >= cinfo->scale_denom * cinfo->block_size) {
+    /* Provide block_size/4 scaling */
+    cinfo->jpeg_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 4L);
+    cinfo->jpeg_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 4L);
+    cinfo->min_DCT_h_scaled_size = 4;
+    cinfo->min_DCT_v_scaled_size = 4;
+  } else if (cinfo->scale_num * 5 >= cinfo->scale_denom * cinfo->block_size) {
+    /* Provide block_size/5 scaling */
+    cinfo->jpeg_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 5L);
+    cinfo->jpeg_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 5L);
+    cinfo->min_DCT_h_scaled_size = 5;
+    cinfo->min_DCT_v_scaled_size = 5;
+  } else if (cinfo->scale_num * 6 >= cinfo->scale_denom * cinfo->block_size) {
+    /* Provide block_size/6 scaling */
+    cinfo->jpeg_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 6L);
+    cinfo->jpeg_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 6L);
+    cinfo->min_DCT_h_scaled_size = 6;
+    cinfo->min_DCT_v_scaled_size = 6;
+  } else if (cinfo->scale_num * 7 >= cinfo->scale_denom * cinfo->block_size) {
+    /* Provide block_size/7 scaling */
+    cinfo->jpeg_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 7L);
+    cinfo->jpeg_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 7L);
+    cinfo->min_DCT_h_scaled_size = 7;
+    cinfo->min_DCT_v_scaled_size = 7;
+  } else if (cinfo->scale_num * 8 >= cinfo->scale_denom * cinfo->block_size) {
+    /* Provide block_size/8 scaling */
+    cinfo->jpeg_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 8L);
+    cinfo->jpeg_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 8L);
+    cinfo->min_DCT_h_scaled_size = 8;
+    cinfo->min_DCT_v_scaled_size = 8;
+  } else if (cinfo->scale_num * 9 >= cinfo->scale_denom * cinfo->block_size) {
+    /* Provide block_size/9 scaling */
+    cinfo->jpeg_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 9L);
+    cinfo->jpeg_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 9L);
+    cinfo->min_DCT_h_scaled_size = 9;
+    cinfo->min_DCT_v_scaled_size = 9;
+  } else if (cinfo->scale_num * 10 >= cinfo->scale_denom * cinfo->block_size) {
+    /* Provide block_size/10 scaling */
+    cinfo->jpeg_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 10L);
+    cinfo->jpeg_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 10L);
+    cinfo->min_DCT_h_scaled_size = 10;
+    cinfo->min_DCT_v_scaled_size = 10;
+  } else if (cinfo->scale_num * 11 >= cinfo->scale_denom * cinfo->block_size) {
+    /* Provide block_size/11 scaling */
+    cinfo->jpeg_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 11L);
+    cinfo->jpeg_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 11L);
+    cinfo->min_DCT_h_scaled_size = 11;
+    cinfo->min_DCT_v_scaled_size = 11;
+  } else if (cinfo->scale_num * 12 >= cinfo->scale_denom * cinfo->block_size) {
+    /* Provide block_size/12 scaling */
+    cinfo->jpeg_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 12L);
+    cinfo->jpeg_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 12L);
+    cinfo->min_DCT_h_scaled_size = 12;
+    cinfo->min_DCT_v_scaled_size = 12;
+  } else if (cinfo->scale_num * 13 >= cinfo->scale_denom * cinfo->block_size) {
+    /* Provide block_size/13 scaling */
+    cinfo->jpeg_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 13L);
+    cinfo->jpeg_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 13L);
+    cinfo->min_DCT_h_scaled_size = 13;
+    cinfo->min_DCT_v_scaled_size = 13;
+  } else if (cinfo->scale_num * 14 >= cinfo->scale_denom * cinfo->block_size) {
+    /* Provide block_size/14 scaling */
+    cinfo->jpeg_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 14L);
+    cinfo->jpeg_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 14L);
+    cinfo->min_DCT_h_scaled_size = 14;
+    cinfo->min_DCT_v_scaled_size = 14;
+  } else if (cinfo->scale_num * 15 >= cinfo->scale_denom * cinfo->block_size) {
+    /* Provide block_size/15 scaling */
+    cinfo->jpeg_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 15L);
+    cinfo->jpeg_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 15L);
+    cinfo->min_DCT_h_scaled_size = 15;
+    cinfo->min_DCT_v_scaled_size = 15;
+  } else {
+    /* Provide block_size/16 scaling */
+    cinfo->jpeg_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 16L);
+    cinfo->jpeg_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 16L);
+    cinfo->min_DCT_h_scaled_size = 16;
+    cinfo->min_DCT_v_scaled_size = 16;
+  }
+
+#else /* !DCT_SCALING_SUPPORTED */
+
+  /* Hardwire it to "no scaling" */
+  cinfo->jpeg_width = cinfo->image_width;
+  cinfo->jpeg_height = cinfo->image_height;
+  cinfo->min_DCT_h_scaled_size = DCTSIZE;
+  cinfo->min_DCT_v_scaled_size = DCTSIZE;
+
+#endif /* DCT_SCALING_SUPPORTED */
+}
+
+
+LOCAL(void)
+jpeg_calc_trans_dimensions (j_compress_ptr cinfo)
+{
+  if (cinfo->min_DCT_h_scaled_size != cinfo->min_DCT_v_scaled_size)
+    ERREXIT2(cinfo, JERR_BAD_DCTSIZE,
+	     cinfo->min_DCT_h_scaled_size, cinfo->min_DCT_v_scaled_size);
+
+  cinfo->block_size = cinfo->min_DCT_h_scaled_size;
+}
+
+
+LOCAL(void)
+initial_setup (j_compress_ptr cinfo, boolean transcode_only)
+/* Do computations that are needed before master selection phase */
+{
+  int ci, ssize;
+  jpeg_component_info *compptr;
+
+  if (transcode_only)
+    jpeg_calc_trans_dimensions(cinfo);
+  else
+    jpeg_calc_jpeg_dimensions(cinfo);
+
+  /* Sanity check on block_size */
+  if (cinfo->block_size < 1 || cinfo->block_size > 16)
+    ERREXIT2(cinfo, JERR_BAD_DCTSIZE, cinfo->block_size, cinfo->block_size);
+
+  /* Derive natural_order from block_size */
+  switch (cinfo->block_size) {
+  case 2: cinfo->natural_order = jpeg_natural_order2; break;
+  case 3: cinfo->natural_order = jpeg_natural_order3; break;
+  case 4: cinfo->natural_order = jpeg_natural_order4; break;
+  case 5: cinfo->natural_order = jpeg_natural_order5; break;
+  case 6: cinfo->natural_order = jpeg_natural_order6; break;
+  case 7: cinfo->natural_order = jpeg_natural_order7; break;
+  default: cinfo->natural_order = jpeg_natural_order; break;
+  }
+
+  /* Derive lim_Se from block_size */
+  cinfo->lim_Se = cinfo->block_size < DCTSIZE ?
+    cinfo->block_size * cinfo->block_size - 1 : DCTSIZE2-1;
+
+  /* Sanity check on image dimensions */
+  if (cinfo->jpeg_height <= 0 || cinfo->jpeg_width <= 0 ||
+      cinfo->num_components <= 0)
+    ERREXIT(cinfo, JERR_EMPTY_IMAGE);
+
+  /* Make sure image isn't bigger than I can handle */
+  if ((long) cinfo->jpeg_height > (long) JPEG_MAX_DIMENSION ||
+      (long) cinfo->jpeg_width > (long) JPEG_MAX_DIMENSION)
+    ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
+
+  /* Only 8 to 12 bits data precision are supported for DCT based JPEG */
+  if (cinfo->data_precision < 8 || cinfo->data_precision > 12)
+    ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+  /* Check that number of components won't exceed internal array sizes */
+  if (cinfo->num_components > MAX_COMPONENTS)
+    ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
+	     MAX_COMPONENTS);
+
+  /* Compute maximum sampling factors; check factor validity */
+  cinfo->max_h_samp_factor = 1;
+  cinfo->max_v_samp_factor = 1;
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR ||
+	compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR)
+      ERREXIT(cinfo, JERR_BAD_SAMPLING);
+    cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor,
+				   compptr->h_samp_factor);
+    cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor,
+				   compptr->v_samp_factor);
+  }
+
+  /* Compute dimensions of components */
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    /* Fill in the correct component_index value; don't rely on application */
+    compptr->component_index = ci;
+    /* In selecting the actual DCT scaling for each component, we try to
+     * scale down the chroma components via DCT scaling rather than downsampling.
+     * This saves time if the downsampler gets to use 1:1 scaling.
+     * Note this code adapts subsampling ratios which are powers of 2.
+     */
+    ssize = 1;
+#ifdef DCT_SCALING_SUPPORTED
+    while (cinfo->min_DCT_h_scaled_size * ssize <=
+	   (cinfo->do_fancy_downsampling ? DCTSIZE : DCTSIZE / 2) &&
+	   (cinfo->max_h_samp_factor % (compptr->h_samp_factor * ssize * 2)) == 0) {
+      ssize = ssize * 2;
+    }
+#endif
+    compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size * ssize;
+    ssize = 1;
+#ifdef DCT_SCALING_SUPPORTED
+    while (cinfo->min_DCT_v_scaled_size * ssize <=
+	   (cinfo->do_fancy_downsampling ? DCTSIZE : DCTSIZE / 2) &&
+	   (cinfo->max_v_samp_factor % (compptr->v_samp_factor * ssize * 2)) == 0) {
+      ssize = ssize * 2;
+    }
+#endif
+    compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size * ssize;
+
+    /* We don't support DCT ratios larger than 2. */
+    if (compptr->DCT_h_scaled_size > compptr->DCT_v_scaled_size * 2)
+	compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size * 2;
+    else if (compptr->DCT_v_scaled_size > compptr->DCT_h_scaled_size * 2)
+	compptr->DCT_v_scaled_size = compptr->DCT_h_scaled_size * 2;
+
+    /* Size in DCT blocks */
+    compptr->width_in_blocks = (JDIMENSION)
+      jdiv_round_up((long) cinfo->jpeg_width * (long) compptr->h_samp_factor,
+		    (long) (cinfo->max_h_samp_factor * cinfo->block_size));
+    compptr->height_in_blocks = (JDIMENSION)
+      jdiv_round_up((long) cinfo->jpeg_height * (long) compptr->v_samp_factor,
+		    (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+    /* Size in samples */
+    compptr->downsampled_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->jpeg_width *
+		    (long) (compptr->h_samp_factor * compptr->DCT_h_scaled_size),
+		    (long) (cinfo->max_h_samp_factor * cinfo->block_size));
+    compptr->downsampled_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->jpeg_height *
+		    (long) (compptr->v_samp_factor * compptr->DCT_v_scaled_size),
+		    (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+    /* Don't need quantization scale after DCT,
+     * until color conversion says otherwise.
+     */
+    compptr->component_needed = FALSE;
+  }
+
+  /* Compute number of fully interleaved MCU rows (number of times that
+   * main controller will call coefficient controller).
+   */
+  cinfo->total_iMCU_rows = (JDIMENSION)
+    jdiv_round_up((long) cinfo->jpeg_height,
+		  (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+}
+
+
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+
+LOCAL(void)
+validate_script (j_compress_ptr cinfo)
+/* Verify that the scan script in cinfo->scan_info[] is valid; also
+ * determine whether it uses progressive JPEG, and set cinfo->progressive_mode.
+ */
+{
+  const jpeg_scan_info * scanptr;
+  int scanno, ncomps, ci, coefi, thisi;
+  int Ss, Se, Ah, Al;
+  boolean component_sent[MAX_COMPONENTS];
+#ifdef C_PROGRESSIVE_SUPPORTED
+  int * last_bitpos_ptr;
+  int last_bitpos[MAX_COMPONENTS][DCTSIZE2];
+  /* -1 until that coefficient has been seen; then last Al for it */
+#endif
+
+  if (cinfo->num_scans <= 0)
+    ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, 0);
+
+  /* For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1;
+   * for progressive JPEG, no scan can have this.
+   */
+  scanptr = cinfo->scan_info;
+  if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2-1) {
+#ifdef C_PROGRESSIVE_SUPPORTED
+    cinfo->progressive_mode = TRUE;
+    last_bitpos_ptr = & last_bitpos[0][0];
+    for (ci = 0; ci < cinfo->num_components; ci++) 
+      for (coefi = 0; coefi < DCTSIZE2; coefi++)
+	*last_bitpos_ptr++ = -1;
+#else
+    ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+  } else {
+    cinfo->progressive_mode = FALSE;
+    for (ci = 0; ci < cinfo->num_components; ci++) 
+      component_sent[ci] = FALSE;
+  }
+
+  for (scanno = 1; scanno <= cinfo->num_scans; scanptr++, scanno++) {
+    /* Validate component indexes */
+    ncomps = scanptr->comps_in_scan;
+    if (ncomps <= 0 || ncomps > MAX_COMPS_IN_SCAN)
+      ERREXIT2(cinfo, JERR_COMPONENT_COUNT, ncomps, MAX_COMPS_IN_SCAN);
+    for (ci = 0; ci < ncomps; ci++) {
+      thisi = scanptr->component_index[ci];
+      if (thisi < 0 || thisi >= cinfo->num_components)
+	ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
+      /* Components must appear in SOF order within each scan */
+      if (ci > 0 && thisi <= scanptr->component_index[ci-1])
+	ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
+    }
+    /* Validate progression parameters */
+    Ss = scanptr->Ss;
+    Se = scanptr->Se;
+    Ah = scanptr->Ah;
+    Al = scanptr->Al;
+    if (cinfo->progressive_mode) {
+#ifdef C_PROGRESSIVE_SUPPORTED
+      /* The JPEG spec simply gives the ranges 0..13 for Ah and Al, but that
+       * seems wrong: the upper bound ought to depend on data precision.
+       * Perhaps they really meant 0..N+1 for N-bit precision.
+       * Here we allow 0..10 for 8-bit data; Al larger than 10 results in
+       * out-of-range reconstructed DC values during the first DC scan,
+       * which might cause problems for some decoders.
+       */
+#if BITS_IN_JSAMPLE == 8
+#define MAX_AH_AL 10
+#else
+#define MAX_AH_AL 13
+#endif
+      if (Ss < 0 || Ss >= DCTSIZE2 || Se < Ss || Se >= DCTSIZE2 ||
+	  Ah < 0 || Ah > MAX_AH_AL || Al < 0 || Al > MAX_AH_AL)
+	ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+      if (Ss == 0) {
+	if (Se != 0)		/* DC and AC together not OK */
+	  ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+      } else {
+	if (ncomps != 1)	/* AC scans must be for only one component */
+	  ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+      }
+      for (ci = 0; ci < ncomps; ci++) {
+	last_bitpos_ptr = & last_bitpos[scanptr->component_index[ci]][0];
+	if (Ss != 0 && last_bitpos_ptr[0] < 0) /* AC without prior DC scan */
+	  ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+	for (coefi = Ss; coefi <= Se; coefi++) {
+	  if (last_bitpos_ptr[coefi] < 0) {
+	    /* first scan of this coefficient */
+	    if (Ah != 0)
+	      ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+	  } else {
+	    /* not first scan */
+	    if (Ah != last_bitpos_ptr[coefi] || Al != Ah-1)
+	      ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+	  }
+	  last_bitpos_ptr[coefi] = Al;
+	}
+      }
+#endif
+    } else {
+      /* For sequential JPEG, all progression parameters must be these: */
+      if (Ss != 0 || Se != DCTSIZE2-1 || Ah != 0 || Al != 0)
+	ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+      /* Make sure components are not sent twice */
+      for (ci = 0; ci < ncomps; ci++) {
+	thisi = scanptr->component_index[ci];
+	if (component_sent[thisi])
+	  ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
+	component_sent[thisi] = TRUE;
+      }
+    }
+  }
+
+  /* Now verify that everything got sent. */
+  if (cinfo->progressive_mode) {
+#ifdef C_PROGRESSIVE_SUPPORTED
+    /* For progressive mode, we only check that at least some DC data
+     * got sent for each component; the spec does not require that all bits
+     * of all coefficients be transmitted.  Would it be wiser to enforce
+     * transmission of all coefficient bits??
+     */
+    for (ci = 0; ci < cinfo->num_components; ci++) {
+      if (last_bitpos[ci][0] < 0)
+	ERREXIT(cinfo, JERR_MISSING_DATA);
+    }
+#endif
+  } else {
+    for (ci = 0; ci < cinfo->num_components; ci++) {
+      if (! component_sent[ci])
+	ERREXIT(cinfo, JERR_MISSING_DATA);
+    }
+  }
+}
+
+
+LOCAL(void)
+reduce_script (j_compress_ptr cinfo)
+/* Adapt scan script for use with reduced block size;
+ * assume that script has been validated before.
+ */
+{
+  jpeg_scan_info * scanptr;
+  int idxout, idxin;
+
+  /* Circumvent const declaration for this function */
+  scanptr = (jpeg_scan_info *) cinfo->scan_info;
+  idxout = 0;
+
+  for (idxin = 0; idxin < cinfo->num_scans; idxin++) {
+    /* After skipping, idxout becomes smaller than idxin */
+    if (idxin != idxout)
+      /* Copy rest of data;
+       * note we stay in given chunk of allocated memory.
+       */
+      scanptr[idxout] = scanptr[idxin];
+    if (scanptr[idxout].Ss > cinfo->lim_Se)
+      /* Entire scan out of range - skip this entry */
+      continue;
+    if (scanptr[idxout].Se > cinfo->lim_Se)
+      /* Limit scan to end of block */
+      scanptr[idxout].Se = cinfo->lim_Se;
+    idxout++;
+  }
+
+  cinfo->num_scans = idxout;
+}
+
+#endif /* C_MULTISCAN_FILES_SUPPORTED */
+
+
+LOCAL(void)
+select_scan_parameters (j_compress_ptr cinfo)
+/* Set up the scan parameters for the current scan */
+{
+  int ci;
+
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+  if (cinfo->scan_info != NULL) {
+    /* Prepare for current scan --- the script is already validated */
+    my_master_ptr master = (my_master_ptr) cinfo->master;
+    const jpeg_scan_info * scanptr = cinfo->scan_info + master->scan_number;
+
+    cinfo->comps_in_scan = scanptr->comps_in_scan;
+    for (ci = 0; ci < scanptr->comps_in_scan; ci++) {
+      cinfo->cur_comp_info[ci] =
+	&cinfo->comp_info[scanptr->component_index[ci]];
+    }
+    if (cinfo->progressive_mode) {
+      cinfo->Ss = scanptr->Ss;
+      cinfo->Se = scanptr->Se;
+      cinfo->Ah = scanptr->Ah;
+      cinfo->Al = scanptr->Al;
+      return;
+    }
+  }
+  else
+#endif
+  {
+    /* Prepare for single sequential-JPEG scan containing all components */
+    if (cinfo->num_components > MAX_COMPS_IN_SCAN)
+      ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
+	       MAX_COMPS_IN_SCAN);
+    cinfo->comps_in_scan = cinfo->num_components;
+    for (ci = 0; ci < cinfo->num_components; ci++) {
+      cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci];
+    }
+  }
+  cinfo->Ss = 0;
+  cinfo->Se = cinfo->block_size * cinfo->block_size - 1;
+  cinfo->Ah = 0;
+  cinfo->Al = 0;
+}
+
+
+LOCAL(void)
+per_scan_setup (j_compress_ptr cinfo)
+/* Do computations that are needed before processing a JPEG scan */
+/* cinfo->comps_in_scan and cinfo->cur_comp_info[] are already set */
+{
+  int ci, mcublks, tmp;
+  jpeg_component_info *compptr;
+  
+  if (cinfo->comps_in_scan == 1) {
+    
+    /* Noninterleaved (single-component) scan */
+    compptr = cinfo->cur_comp_info[0];
+    
+    /* Overall image size in MCUs */
+    cinfo->MCUs_per_row = compptr->width_in_blocks;
+    cinfo->MCU_rows_in_scan = compptr->height_in_blocks;
+    
+    /* For noninterleaved scan, always one block per MCU */
+    compptr->MCU_width = 1;
+    compptr->MCU_height = 1;
+    compptr->MCU_blocks = 1;
+    compptr->MCU_sample_width = compptr->DCT_h_scaled_size;
+    compptr->last_col_width = 1;
+    /* For noninterleaved scans, it is convenient to define last_row_height
+     * as the number of block rows present in the last iMCU row.
+     */
+    tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+    if (tmp == 0) tmp = compptr->v_samp_factor;
+    compptr->last_row_height = tmp;
+    
+    /* Prepare array describing MCU composition */
+    cinfo->blocks_in_MCU = 1;
+    cinfo->MCU_membership[0] = 0;
+    
+  } else {
+    
+    /* Interleaved (multi-component) scan */
+    if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN)
+      ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan,
+	       MAX_COMPS_IN_SCAN);
+    
+    /* Overall image size in MCUs */
+    cinfo->MCUs_per_row = (JDIMENSION)
+      jdiv_round_up((long) cinfo->jpeg_width,
+		    (long) (cinfo->max_h_samp_factor * cinfo->block_size));
+    cinfo->MCU_rows_in_scan = (JDIMENSION)
+      jdiv_round_up((long) cinfo->jpeg_height,
+		    (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+    
+    cinfo->blocks_in_MCU = 0;
+    
+    for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+      compptr = cinfo->cur_comp_info[ci];
+      /* Sampling factors give # of blocks of component in each MCU */
+      compptr->MCU_width = compptr->h_samp_factor;
+      compptr->MCU_height = compptr->v_samp_factor;
+      compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
+      compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_h_scaled_size;
+      /* Figure number of non-dummy blocks in last MCU column & row */
+      tmp = (int) (compptr->width_in_blocks % compptr->MCU_width);
+      if (tmp == 0) tmp = compptr->MCU_width;
+      compptr->last_col_width = tmp;
+      tmp = (int) (compptr->height_in_blocks % compptr->MCU_height);
+      if (tmp == 0) tmp = compptr->MCU_height;
+      compptr->last_row_height = tmp;
+      /* Prepare array describing MCU composition */
+      mcublks = compptr->MCU_blocks;
+      if (cinfo->blocks_in_MCU + mcublks > C_MAX_BLOCKS_IN_MCU)
+	ERREXIT(cinfo, JERR_BAD_MCU_SIZE);
+      while (mcublks-- > 0) {
+	cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci;
+      }
+    }
+    
+  }
+
+  /* Convert restart specified in rows to actual MCU count. */
+  /* Note that count must fit in 16 bits, so we provide limiting. */
+  if (cinfo->restart_in_rows > 0) {
+    long nominal = (long) cinfo->restart_in_rows * (long) cinfo->MCUs_per_row;
+    cinfo->restart_interval = (unsigned int) MIN(nominal, 65535L);
+  }
+}
+
+
+/*
+ * Per-pass setup.
+ * This is called at the beginning of each pass.  We determine which modules
+ * will be active during this pass and give them appropriate start_pass calls.
+ * We also set is_last_pass to indicate whether any more passes will be
+ * required.
+ */
+
+METHODDEF(void)
+prepare_for_pass (j_compress_ptr cinfo)
+{
+  my_master_ptr master = (my_master_ptr) cinfo->master;
+
+  switch (master->pass_type) {
+  case main_pass:
+    /* Initial pass: will collect input data, and do either Huffman
+     * optimization or data output for the first scan.
+     */
+    select_scan_parameters(cinfo);
+    per_scan_setup(cinfo);
+    if (! cinfo->raw_data_in) {
+      (*cinfo->cconvert->start_pass) (cinfo);
+      (*cinfo->downsample->start_pass) (cinfo);
+      (*cinfo->prep->start_pass) (cinfo, JBUF_PASS_THRU);
+    }
+    (*cinfo->fdct->start_pass) (cinfo);
+    (*cinfo->entropy->start_pass) (cinfo, cinfo->optimize_coding);
+    (*cinfo->coef->start_pass) (cinfo,
+				(master->total_passes > 1 ?
+				 JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));
+    (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU);
+    if (cinfo->optimize_coding) {
+      /* No immediate data output; postpone writing frame/scan headers */
+      master->pub.call_pass_startup = FALSE;
+    } else {
+      /* Will write frame/scan headers at first jpeg_write_scanlines call */
+      master->pub.call_pass_startup = TRUE;
+    }
+    break;
+#ifdef ENTROPY_OPT_SUPPORTED
+  case huff_opt_pass:
+    /* Do Huffman optimization for a scan after the first one. */
+    select_scan_parameters(cinfo);
+    per_scan_setup(cinfo);
+    if (cinfo->Ss != 0 || cinfo->Ah == 0) {
+      (*cinfo->entropy->start_pass) (cinfo, TRUE);
+      (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST);
+      master->pub.call_pass_startup = FALSE;
+      break;
+    }
+    /* Special case: Huffman DC refinement scans need no Huffman table
+     * and therefore we can skip the optimization pass for them.
+     */
+    master->pass_type = output_pass;
+    master->pass_number++;
+    /*FALLTHROUGH*/
+#endif
+  case output_pass:
+    /* Do a data-output pass. */
+    /* We need not repeat per-scan setup if prior optimization pass did it. */
+    if (! cinfo->optimize_coding) {
+      select_scan_parameters(cinfo);
+      per_scan_setup(cinfo);
+    }
+    (*cinfo->entropy->start_pass) (cinfo, FALSE);
+    (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST);
+    /* We emit frame/scan headers now */
+    if (master->scan_number == 0)
+      (*cinfo->marker->write_frame_header) (cinfo);
+    (*cinfo->marker->write_scan_header) (cinfo);
+    master->pub.call_pass_startup = FALSE;
+    break;
+  default:
+    ERREXIT(cinfo, JERR_NOT_COMPILED);
+  }
+
+  master->pub.is_last_pass = (master->pass_number == master->total_passes-1);
+
+  /* Set up progress monitor's pass info if present */
+  if (cinfo->progress != NULL) {
+    cinfo->progress->completed_passes = master->pass_number;
+    cinfo->progress->total_passes = master->total_passes;
+  }
+}
+
+
+/*
+ * Special start-of-pass hook.
+ * This is called by jpeg_write_scanlines if call_pass_startup is TRUE.
+ * In single-pass processing, we need this hook because we don't want to
+ * write frame/scan headers during jpeg_start_compress; we want to let the
+ * application write COM markers etc. between jpeg_start_compress and the
+ * jpeg_write_scanlines loop.
+ * In multi-pass processing, this routine is not used.
+ */
+
+METHODDEF(void)
+pass_startup (j_compress_ptr cinfo)
+{
+  cinfo->master->call_pass_startup = FALSE; /* reset flag so call only once */
+
+  (*cinfo->marker->write_frame_header) (cinfo);
+  (*cinfo->marker->write_scan_header) (cinfo);
+}
+
+
+/*
+ * Finish up at end of pass.
+ */
+
+METHODDEF(void)
+finish_pass_master (j_compress_ptr cinfo)
+{
+  my_master_ptr master = (my_master_ptr) cinfo->master;
+
+  /* The entropy coder always needs an end-of-pass call,
+   * either to analyze statistics or to flush its output buffer.
+   */
+  (*cinfo->entropy->finish_pass) (cinfo);
+
+  /* Update state for next pass */
+  switch (master->pass_type) {
+  case main_pass:
+    /* next pass is either output of scan 0 (after optimization)
+     * or output of scan 1 (if no optimization).
+     */
+    master->pass_type = output_pass;
+    if (! cinfo->optimize_coding)
+      master->scan_number++;
+    break;
+  case huff_opt_pass:
+    /* next pass is always output of current scan */
+    master->pass_type = output_pass;
+    break;
+  case output_pass:
+    /* next pass is either optimization or output of next scan */
+    if (cinfo->optimize_coding)
+      master->pass_type = huff_opt_pass;
+    master->scan_number++;
+    break;
+  }
+
+  master->pass_number++;
+}
+
+
+/*
+ * Initialize master compression control.
+ */
+
+GLOBAL(void)
+jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only)
+{
+  my_master_ptr master;
+
+  master = (my_master_ptr)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  SIZEOF(my_comp_master));
+  cinfo->master = &master->pub;
+  master->pub.prepare_for_pass = prepare_for_pass;
+  master->pub.pass_startup = pass_startup;
+  master->pub.finish_pass = finish_pass_master;
+  master->pub.is_last_pass = FALSE;
+
+  /* Validate parameters, determine derived values */
+  initial_setup(cinfo, transcode_only);
+
+  if (cinfo->scan_info != NULL) {
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+    validate_script(cinfo);
+    if (cinfo->block_size < DCTSIZE)
+      reduce_script(cinfo);
+#else
+    ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+  } else {
+    cinfo->progressive_mode = FALSE;
+    cinfo->num_scans = 1;
+  }
+
+  if (cinfo->optimize_coding)
+    cinfo->arith_code = FALSE; /* disable arithmetic coding */
+  else if (! cinfo->arith_code &&
+	   (cinfo->progressive_mode ||
+	    (cinfo->block_size > 1 && cinfo->block_size < DCTSIZE)))
+    /* TEMPORARY HACK ??? */
+    /* assume default tables no good for progressive or reduced AC mode */
+    cinfo->optimize_coding = TRUE; /* force Huffman optimization */
+
+  /* Initialize my private state */
+  if (transcode_only) {
+    /* no main pass in transcoding */
+    if (cinfo->optimize_coding)
+      master->pass_type = huff_opt_pass;
+    else
+      master->pass_type = output_pass;
+  } else {
+    /* for normal compression, first pass is always this type: */
+    master->pass_type = main_pass;
+  }
+  master->scan_number = 0;
+  master->pass_number = 0;
+  if (cinfo->optimize_coding)
+    master->total_passes = cinfo->num_scans * 2;
+  else
+    master->total_passes = cinfo->num_scans;
+}
diff --git a/source/Irrlicht/jpeglib/jcomapi.c b/source/Irrlicht/jpeglib/jcomapi.c
new file mode 100644
index 00000000..1b1a340c
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jcomapi.c
@@ -0,0 +1,106 @@
+/*
+ * jcomapi.c
+ *
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface routines that are used for both
+ * compression and decompression.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Abort processing of a JPEG compression or decompression operation,
+ * but don't destroy the object itself.
+ *
+ * For this, we merely clean up all the nonpermanent memory pools.
+ * Note that temp files (virtual arrays) are not allowed to belong to
+ * the permanent pool, so we will be able to close all temp files here.
+ * Closing a data source or destination, if necessary, is the application's
+ * responsibility.
+ */
+
+GLOBAL(void)
+jpeg_abort (j_common_ptr cinfo)
+{
+  int pool;
+
+  /* Do nothing if called on a not-initialized or destroyed JPEG object. */
+  if (cinfo->mem == NULL)
+    return;
+
+  /* Releasing pools in reverse order might help avoid fragmentation
+   * with some (brain-damaged) malloc libraries.
+   */
+  for (pool = JPOOL_NUMPOOLS-1; pool > JPOOL_PERMANENT; pool--) {
+    (*cinfo->mem->free_pool) (cinfo, pool);
+  }
+
+  /* Reset overall state for possible reuse of object */
+  if (cinfo->is_decompressor) {
+    cinfo->global_state = DSTATE_START;
+    /* Try to keep application from accessing now-deleted marker list.
+     * A bit kludgy to do it here, but this is the most central place.
+     */
+    ((j_decompress_ptr) cinfo)->marker_list = NULL;
+  } else {
+    cinfo->global_state = CSTATE_START;
+  }
+}
+
+
+/*
+ * Destruction of a JPEG object.
+ *
+ * Everything gets deallocated except the master jpeg_compress_struct itself
+ * and the error manager struct.  Both of these are supplied by the application
+ * and must be freed, if necessary, by the application.  (Often they are on
+ * the stack and so don't need to be freed anyway.)
+ * Closing a data source or destination, if necessary, is the application's
+ * responsibility.
+ */
+
+GLOBAL(void)
+jpeg_destroy (j_common_ptr cinfo)
+{
+  /* We need only tell the memory manager to release everything. */
+  /* NB: mem pointer is NULL if memory mgr failed to initialize. */
+  if (cinfo->mem != NULL)
+    (*cinfo->mem->self_destruct) (cinfo);
+  cinfo->mem = NULL;		/* be safe if jpeg_destroy is called twice */
+  cinfo->global_state = 0;	/* mark it destroyed */
+}
+
+
+/*
+ * Convenience routines for allocating quantization and Huffman tables.
+ * (Would jutils.c be a more reasonable place to put these?)
+ */
+
+GLOBAL(JQUANT_TBL *)
+jpeg_alloc_quant_table (j_common_ptr cinfo)
+{
+  JQUANT_TBL *tbl;
+
+  tbl = (JQUANT_TBL *)
+    (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JQUANT_TBL));
+  tbl->sent_table = FALSE;	/* make sure this is false in any new table */
+  return tbl;
+}
+
+
+GLOBAL(JHUFF_TBL *)
+jpeg_alloc_huff_table (j_common_ptr cinfo)
+{
+  JHUFF_TBL *tbl;
+
+  tbl = (JHUFF_TBL *)
+    (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JHUFF_TBL));
+  tbl->sent_table = FALSE;	/* make sure this is false in any new table */
+  return tbl;
+}
diff --git a/source/Irrlicht/jpeglib/jconfig.bcc b/source/Irrlicht/jpeglib/jconfig.bcc
new file mode 100644
index 00000000..e4da3d72
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jconfig.bcc
@@ -0,0 +1,48 @@
+/* jconfig.bcc --- jconfig.h for Borland C (Turbo C) on MS-DOS or OS/2. */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#ifdef __MSDOS__
+#define NEED_FAR_POINTERS	/* for small or medium memory model */
+#endif
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN	/* this assumes you have -w-stu in CFLAGS */
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#ifdef __MSDOS__
+#define USE_MSDOS_MEMMGR	/* Define this if you use jmemdos.c */
+#define MAX_ALLOC_CHUNK 65520L	/* Maximum request to malloc() */
+#define USE_FMEM		/* Borland has _fmemcpy() and _fmemset() */
+#endif
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED		/* BMP image file format */
+#define GIF_SUPPORTED		/* GIF image file format */
+#define PPM_SUPPORTED		/* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED		/* Utah RLE image file format */
+#define TARGA_SUPPORTED		/* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE
+#define USE_SETMODE		/* Borland has setmode() */
+#ifdef __MSDOS__
+#define NEED_SIGNAL_CATCHER	/* Define this if you use jmemdos.c */
+#endif
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT		/* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/source/Irrlicht/jpeglib/jconfig.cfg b/source/Irrlicht/jpeglib/jconfig.cfg
new file mode 100644
index 00000000..c4548fc2
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jconfig.cfg
@@ -0,0 +1,59 @@
+/* jconfig.cfg --- source file edited by configure script */
+/* see jconfig.txt for explanations */
+
+#undef HAVE_PROTOTYPES
+#undef HAVE_UNSIGNED_CHAR
+#undef HAVE_UNSIGNED_SHORT
+#undef void
+#undef const
+#undef CHAR_IS_UNSIGNED
+#undef HAVE_STDDEF_H
+#undef HAVE_STDLIB_H
+#undef HAVE_LOCALE_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+/* Define this if you get warnings about undefined structures. */
+#undef INCOMPLETE_TYPES_BROKEN
+
+/* Define "boolean" as unsigned char, not enum, on Windows systems. */
+#ifdef _WIN32
+#ifndef __RPCNDR_H__		/* don't conflict if rpcndr.h already read */
+typedef unsigned char boolean;
+#endif
+#ifndef FALSE			/* in case these macros already exist */
+#define FALSE	0		/* values of boolean */
+#endif
+#ifndef TRUE
+#define TRUE	1
+#endif
+#define HAVE_BOOLEAN		/* prevent jmorecfg.h from redefining it */
+#endif
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+#undef INLINE
+/* These are for configuring the JPEG memory manager. */
+#undef DEFAULT_MAX_MEM
+#undef NO_MKTEMP
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED		/* BMP image file format */
+#define GIF_SUPPORTED		/* GIF image file format */
+#define PPM_SUPPORTED		/* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED		/* Utah RLE image file format */
+#define TARGA_SUPPORTED		/* Targa image file format */
+
+#undef TWO_FILE_COMMANDLINE
+#undef NEED_SIGNAL_CATCHER
+#undef DONT_USE_B_MODE
+
+/* Define this if you want percent-done progress reports from cjpeg/djpeg. */
+#undef PROGRESS_REPORT
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/source/Irrlicht/jpeglib/jconfig.dj b/source/Irrlicht/jpeglib/jconfig.dj
new file mode 100644
index 00000000..a0d4092f
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jconfig.dj
@@ -0,0 +1,38 @@
+/* jconfig.dj --- jconfig.h for DJGPP (Delorie's GNU C port) on MS-DOS. */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS	/* DJGPP uses flat 32-bit addressing */
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED		/* BMP image file format */
+#define GIF_SUPPORTED		/* GIF image file format */
+#define PPM_SUPPORTED		/* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED		/* Utah RLE image file format */
+#define TARGA_SUPPORTED		/* Targa image file format */
+
+#undef TWO_FILE_COMMANDLINE	/* optional */
+#define USE_SETMODE		/* Needed to make one-file style work in DJGPP */
+#undef NEED_SIGNAL_CATCHER	/* Define this if you use jmemname.c */
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT		/* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/source/Irrlicht/jpeglib/jconfig.h b/source/Irrlicht/jpeglib/jconfig.h
new file mode 100644
index 00000000..3744691b
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jconfig.h
@@ -0,0 +1,38 @@
+/* jconfig.vc --- jconfig.h for Microsoft Visual C++ on Windows 95 or NT. */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS	/* we presume a 32-bit flat memory model */
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED		/* BMP image file format */
+#define GIF_SUPPORTED		/* GIF image file format */
+#define PPM_SUPPORTED		/* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED		/* Utah RLE image file format */
+#define TARGA_SUPPORTED		/* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE	/* optional */
+#define USE_SETMODE		/* Microsoft has setmode() */
+#undef NEED_SIGNAL_CATCHER
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT		/* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/source/Irrlicht/jpeglib/jconfig.mac b/source/Irrlicht/jpeglib/jconfig.mac
new file mode 100644
index 00000000..70ed66c1
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jconfig.mac
@@ -0,0 +1,43 @@
+/* jconfig.mac --- jconfig.h for CodeWarrior on Apple Macintosh */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#define USE_MAC_MEMMGR		/* Define this if you use jmemmac.c */
+
+#define ALIGN_TYPE long		/* Needed for 680x0 Macs */
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED		/* BMP image file format */
+#define GIF_SUPPORTED		/* GIF image file format */
+#define PPM_SUPPORTED		/* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED		/* Utah RLE image file format */
+#define TARGA_SUPPORTED		/* Targa image file format */
+
+#define USE_CCOMMAND		/* Command line reader for Macintosh */
+#define TWO_FILE_COMMANDLINE	/* Binary I/O thru stdin/stdout doesn't work */
+
+#undef NEED_SIGNAL_CATCHER
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT		/* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/source/Irrlicht/jpeglib/jconfig.manx b/source/Irrlicht/jpeglib/jconfig.manx
new file mode 100644
index 00000000..cd529d7d
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jconfig.manx
@@ -0,0 +1,43 @@
+/* jconfig.manx --- jconfig.h for Amiga systems using Manx Aztec C ver 5.x. */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#define TEMP_DIRECTORY "JPEGTMP:"	/* recommended setting for Amiga */
+
+#define SHORTxSHORT_32		/* produces better DCT code with Aztec C */
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED		/* BMP image file format */
+#define GIF_SUPPORTED		/* GIF image file format */
+#define PPM_SUPPORTED		/* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED		/* Utah RLE image file format */
+#define TARGA_SUPPORTED		/* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE
+#define NEED_SIGNAL_CATCHER
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT		/* optional */
+
+#define signal_catcher _abort	/* hack for Aztec C naming requirements */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/source/Irrlicht/jpeglib/jconfig.mc6 b/source/Irrlicht/jpeglib/jconfig.mc6
new file mode 100644
index 00000000..6b05e81b
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jconfig.mc6
@@ -0,0 +1,52 @@
+/* jconfig.mc6 --- jconfig.h for Microsoft C on MS-DOS, version 6.00A & up. */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#define NEED_FAR_POINTERS	/* for small or medium memory model */
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#define USE_MSDOS_MEMMGR	/* Define this if you use jmemdos.c */
+
+#define MAX_ALLOC_CHUNK 65520L	/* Maximum request to malloc() */
+
+#define USE_FMEM		/* Microsoft has _fmemcpy() and _fmemset() */
+
+#define NEED_FHEAPMIN		/* far heap management routines are broken */
+
+#define SHORTxLCONST_32		/* enable compiler-specific DCT optimization */
+/* Note: the above define is known to improve the code with Microsoft C 6.00A.
+ * I do not know whether it is good for later compiler versions.
+ * Please report any info on this point to jpeg-info@jpegclub.org.
+ */
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED		/* BMP image file format */
+#define GIF_SUPPORTED		/* GIF image file format */
+#define PPM_SUPPORTED		/* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED		/* Utah RLE image file format */
+#define TARGA_SUPPORTED		/* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE
+#define USE_SETMODE		/* Microsoft has setmode() */
+#define NEED_SIGNAL_CATCHER	/* Define this if you use jmemdos.c */
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT		/* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/source/Irrlicht/jpeglib/jconfig.sas b/source/Irrlicht/jpeglib/jconfig.sas
new file mode 100644
index 00000000..b8a18192
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jconfig.sas
@@ -0,0 +1,43 @@
+/* jconfig.sas --- jconfig.h for Amiga systems using SAS C 6.0 and up. */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#define TEMP_DIRECTORY "JPEGTMP:"	/* recommended setting for Amiga */
+
+#define NO_MKTEMP		/* SAS C doesn't have mktemp() */
+
+#define SHORTxSHORT_32		/* produces better DCT code with SAS C */
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED		/* BMP image file format */
+#define GIF_SUPPORTED		/* GIF image file format */
+#define PPM_SUPPORTED		/* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED		/* Utah RLE image file format */
+#define TARGA_SUPPORTED		/* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE
+#define NEED_SIGNAL_CATCHER
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT		/* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/source/Irrlicht/jpeglib/jconfig.st b/source/Irrlicht/jpeglib/jconfig.st
new file mode 100644
index 00000000..5afa0b6c
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jconfig.st
@@ -0,0 +1,42 @@
+/* jconfig.st --- jconfig.h for Atari ST/STE/TT using Pure C or Turbo C. */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+#define INCOMPLETE_TYPES_BROKEN	/* suppress undefined-structure warnings */
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#define ALIGN_TYPE  long	/* apparently double is a weird size? */
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED		/* BMP image file format */
+#define GIF_SUPPORTED		/* GIF image file format */
+#define PPM_SUPPORTED		/* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED		/* Utah RLE image file format */
+#define TARGA_SUPPORTED		/* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE	/* optional -- undef if you like Unix style */
+/* Note: if you undef TWO_FILE_COMMANDLINE, you may need to define
+ * USE_SETMODE.  Some Atari compilers require it, some do not.
+ */
+#define NEED_SIGNAL_CATCHER	/* needed if you use jmemname.c */
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT		/* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/source/Irrlicht/jpeglib/jconfig.txt b/source/Irrlicht/jpeglib/jconfig.txt
new file mode 100644
index 00000000..d1710ae7
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jconfig.txt
@@ -0,0 +1,171 @@
+/*
+ * jconfig.txt
+ *
+ * Copyright (C) 1991-1994, Thomas G. Lane.
+ * Modified 2009-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file documents the configuration options that are required to
+ * customize the JPEG software for a particular system.
+ *
+ * The actual configuration options for a particular installation are stored
+ * in jconfig.h.  On many machines, jconfig.h can be generated automatically
+ * or copied from one of the "canned" jconfig files that we supply.  But if
+ * you need to generate a jconfig.h file by hand, this file tells you how.
+ *
+ * DO NOT EDIT THIS FILE --- IT WON'T ACCOMPLISH ANYTHING.
+ * EDIT A COPY NAMED JCONFIG.H.
+ */
+
+
+/*
+ * These symbols indicate the properties of your machine or compiler.
+ * #define the symbol if yes, #undef it if no.
+ */
+
+/* Does your compiler support function prototypes?
+ * (If not, you also need to use ansi2knr, see install.txt)
+ */
+#define HAVE_PROTOTYPES
+
+/* Does your compiler support the declaration "unsigned char" ?
+ * How about "unsigned short" ?
+ */
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+
+/* Define "void" as "char" if your compiler doesn't know about type void.
+ * NOTE: be sure to define void such that "void *" represents the most general
+ * pointer type, e.g., that returned by malloc().
+ */
+/* #define void char */
+
+/* Define "const" as empty if your compiler doesn't know the "const" keyword.
+ */
+/* #define const */
+
+/* Define this if an ordinary "char" type is unsigned.
+ * If you're not sure, leaving it undefined will work at some cost in speed.
+ * If you defined HAVE_UNSIGNED_CHAR then the speed difference is minimal.
+ */
+#undef CHAR_IS_UNSIGNED
+
+/* Define this if your system has an ANSI-conforming  file.
+ */
+#define HAVE_STDDEF_H
+
+/* Define this if your system has an ANSI-conforming  file.
+ */
+#define HAVE_STDLIB_H
+
+/* Define this if your system does not have an ANSI/SysV ,
+ * but does have a BSD-style .
+ */
+#undef NEED_BSD_STRINGS
+
+/* Define this if your system does not provide typedef size_t in any of the
+ * ANSI-standard places (stddef.h, stdlib.h, or stdio.h), but places it in
+ *  instead.
+ */
+#undef NEED_SYS_TYPES_H
+
+/* For 80x86 machines, you need to define NEED_FAR_POINTERS,
+ * unless you are using a large-data memory model or 80386 flat-memory mode.
+ * On less brain-damaged CPUs this symbol must not be defined.
+ * (Defining this symbol causes large data structures to be referenced through
+ * "far" pointers and to be allocated with a special version of malloc.)
+ */
+#undef NEED_FAR_POINTERS
+
+/* Define this if your linker needs global names to be unique in less
+ * than the first 15 characters.
+ */
+#undef NEED_SHORT_EXTERNAL_NAMES
+
+/* Although a real ANSI C compiler can deal perfectly well with pointers to
+ * unspecified structures (see "incomplete types" in the spec), a few pre-ANSI
+ * and pseudo-ANSI compilers get confused.  To keep one of these bozos happy,
+ * define INCOMPLETE_TYPES_BROKEN.  This is not recommended unless you
+ * actually get "missing structure definition" warnings or errors while
+ * compiling the JPEG code.
+ */
+#undef INCOMPLETE_TYPES_BROKEN
+
+/* Define "boolean" as unsigned char, not enum, on Windows systems.
+ */
+#ifdef _WIN32
+#ifndef __RPCNDR_H__		/* don't conflict if rpcndr.h already read */
+typedef unsigned char boolean;
+#endif
+#ifndef FALSE			/* in case these macros already exist */
+#define FALSE	0		/* values of boolean */
+#endif
+#ifndef TRUE
+#define TRUE	1
+#endif
+#define HAVE_BOOLEAN		/* prevent jmorecfg.h from redefining it */
+#endif
+
+
+/*
+ * The following options affect code selection within the JPEG library,
+ * but they don't need to be visible to applications using the library.
+ * To minimize application namespace pollution, the symbols won't be
+ * defined unless JPEG_INTERNALS has been defined.
+ */
+
+#ifdef JPEG_INTERNALS
+
+/* Define this if your compiler implements ">>" on signed values as a logical
+ * (unsigned) shift; leave it undefined if ">>" is a signed (arithmetic) shift,
+ * which is the normal and rational definition.
+ */
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+
+#endif /* JPEG_INTERNALS */
+
+
+/*
+ * The remaining options do not affect the JPEG library proper,
+ * but only the sample applications cjpeg/djpeg (see cjpeg.c, djpeg.c).
+ * Other applications can ignore these.
+ */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+/* These defines indicate which image (non-JPEG) file formats are allowed. */
+
+#define BMP_SUPPORTED		/* BMP image file format */
+#define GIF_SUPPORTED		/* GIF image file format */
+#define PPM_SUPPORTED		/* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED		/* Utah RLE image file format */
+#define TARGA_SUPPORTED		/* Targa image file format */
+
+/* Define this if you want to name both input and output files on the command
+ * line, rather than using stdout and optionally stdin.  You MUST do this if
+ * your system can't cope with binary I/O to stdin/stdout.  See comments at
+ * head of cjpeg.c or djpeg.c.
+ */
+#undef TWO_FILE_COMMANDLINE
+
+/* Define this if your system needs explicit cleanup of temporary files.
+ * This is crucial under MS-DOS, where the temporary "files" may be areas
+ * of extended memory; on most other systems it's not as important.
+ */
+#undef NEED_SIGNAL_CATCHER
+
+/* By default, we open image files with fopen(...,"rb") or fopen(...,"wb").
+ * This is necessary on systems that distinguish text files from binary files,
+ * and is harmless on most systems that don't.  If you have one of the rare
+ * systems that complains about the "b" spec, define this symbol.
+ */
+#undef DONT_USE_B_MODE
+
+/* Define this if you want percent-done progress reports from cjpeg/djpeg.
+ */
+#undef PROGRESS_REPORT
+
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/source/Irrlicht/jpeglib/jconfig.vc b/source/Irrlicht/jpeglib/jconfig.vc
new file mode 100644
index 00000000..7d88482f
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jconfig.vc
@@ -0,0 +1,51 @@
+/* jconfig.vc --- jconfig.h for Microsoft Visual C++ on Windows 95 or NT. */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS	/* we presume a 32-bit flat memory model */
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+/* Define "boolean" as unsigned char, not enum, per Windows custom */
+#ifndef __RPCNDR_H__		/* don't conflict if rpcndr.h already read */
+typedef unsigned char boolean;
+#endif
+#ifndef FALSE			/* in case these macros already exist */
+#define FALSE	0		/* values of boolean */
+#endif
+#ifndef TRUE
+#define TRUE	1
+#endif
+#define HAVE_BOOLEAN		/* prevent jmorecfg.h from redefining it */
+
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED		/* BMP image file format */
+#define GIF_SUPPORTED		/* GIF image file format */
+#define PPM_SUPPORTED		/* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED		/* Utah RLE image file format */
+#define TARGA_SUPPORTED		/* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE	/* optional */
+#define USE_SETMODE		/* Microsoft has setmode() */
+#undef NEED_SIGNAL_CATCHER
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT		/* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/source/Irrlicht/jpeglib/jconfig.vms b/source/Irrlicht/jpeglib/jconfig.vms
new file mode 100644
index 00000000..8337b0b6
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jconfig.vms
@@ -0,0 +1,37 @@
+/* jconfig.vms --- jconfig.h for use on Digital VMS. */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED		/* BMP image file format */
+#define GIF_SUPPORTED		/* GIF image file format */
+#define PPM_SUPPORTED		/* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED		/* Utah RLE image file format */
+#define TARGA_SUPPORTED		/* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE	/* Needed on VMS */
+#undef NEED_SIGNAL_CATCHER
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT		/* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/source/Irrlicht/jpeglib/jconfig.wat b/source/Irrlicht/jpeglib/jconfig.wat
new file mode 100644
index 00000000..190cc75f
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jconfig.wat
@@ -0,0 +1,38 @@
+/* jconfig.wat --- jconfig.h for Watcom C/C++ on MS-DOS or OS/2. */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#define CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS	/* Watcom uses flat 32-bit addressing */
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED		/* BMP image file format */
+#define GIF_SUPPORTED		/* GIF image file format */
+#define PPM_SUPPORTED		/* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED		/* Utah RLE image file format */
+#define TARGA_SUPPORTED		/* Targa image file format */
+
+#undef TWO_FILE_COMMANDLINE	/* optional */
+#define USE_SETMODE		/* Needed to make one-file style work in Watcom */
+#undef NEED_SIGNAL_CATCHER	/* Define this if you use jmemname.c */
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT		/* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/source/Irrlicht/jpeglib/jcparam.c b/source/Irrlicht/jpeglib/jcparam.c
new file mode 100644
index 00000000..1680e392
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jcparam.c
@@ -0,0 +1,675 @@
+/*
+ * jcparam.c
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Modified 2003-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains optional default-setting code for the JPEG compressor.
+ * Applications do not have to use this file, but those that don't use it
+ * must know a lot more about the innards of the JPEG code.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Quantization table setup routines
+ */
+
+GLOBAL(void)
+jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl,
+		      const unsigned int *basic_table,
+		      int scale_factor, boolean force_baseline)
+/* Define a quantization table equal to the basic_table times
+ * a scale factor (given as a percentage).
+ * If force_baseline is TRUE, the computed quantization table entries
+ * are limited to 1..255 for JPEG baseline compatibility.
+ */
+{
+  JQUANT_TBL ** qtblptr;
+  int i;
+  long temp;
+
+  /* Safety check to ensure start_compress not called yet. */
+  if (cinfo->global_state != CSTATE_START)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+  if (which_tbl < 0 || which_tbl >= NUM_QUANT_TBLS)
+    ERREXIT1(cinfo, JERR_DQT_INDEX, which_tbl);
+
+  qtblptr = & cinfo->quant_tbl_ptrs[which_tbl];
+
+  if (*qtblptr == NULL)
+    *qtblptr = jpeg_alloc_quant_table((j_common_ptr) cinfo);
+
+  for (i = 0; i < DCTSIZE2; i++) {
+    temp = ((long) basic_table[i] * scale_factor + 50L) / 100L;
+    /* limit the values to the valid range */
+    if (temp <= 0L) temp = 1L;
+    if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */
+    if (force_baseline && temp > 255L)
+      temp = 255L;		/* limit to baseline range if requested */
+    (*qtblptr)->quantval[i] = (UINT16) temp;
+  }
+
+  /* Initialize sent_table FALSE so table will be written to JPEG file. */
+  (*qtblptr)->sent_table = FALSE;
+}
+
+
+/* These are the sample quantization tables given in JPEG spec section K.1.
+ * The spec says that the values given produce "good" quality, and
+ * when divided by 2, "very good" quality.
+ */
+static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = {
+  16,  11,  10,  16,  24,  40,  51,  61,
+  12,  12,  14,  19,  26,  58,  60,  55,
+  14,  13,  16,  24,  40,  57,  69,  56,
+  14,  17,  22,  29,  51,  87,  80,  62,
+  18,  22,  37,  56,  68, 109, 103,  77,
+  24,  35,  55,  64,  81, 104, 113,  92,
+  49,  64,  78,  87, 103, 121, 120, 101,
+  72,  92,  95,  98, 112, 100, 103,  99
+};
+static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = {
+  17,  18,  24,  47,  99,  99,  99,  99,
+  18,  21,  26,  66,  99,  99,  99,  99,
+  24,  26,  56,  99,  99,  99,  99,  99,
+  47,  66,  99,  99,  99,  99,  99,  99,
+  99,  99,  99,  99,  99,  99,  99,  99,
+  99,  99,  99,  99,  99,  99,  99,  99,
+  99,  99,  99,  99,  99,  99,  99,  99,
+  99,  99,  99,  99,  99,  99,  99,  99
+};
+
+
+GLOBAL(void)
+jpeg_default_qtables (j_compress_ptr cinfo, boolean force_baseline)
+/* Set or change the 'quality' (quantization) setting, using default tables
+ * and straight percentage-scaling quality scales.
+ * This entry point allows different scalings for luminance and chrominance.
+ */
+{
+  /* Set up two quantization tables using the specified scaling */
+  jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,
+		       cinfo->q_scale_factor[0], force_baseline);
+  jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,
+		       cinfo->q_scale_factor[1], force_baseline);
+}
+
+
+GLOBAL(void)
+jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor,
+			 boolean force_baseline)
+/* Set or change the 'quality' (quantization) setting, using default tables
+ * and a straight percentage-scaling quality scale.  In most cases it's better
+ * to use jpeg_set_quality (below); this entry point is provided for
+ * applications that insist on a linear percentage scaling.
+ */
+{
+  /* Set up two quantization tables using the specified scaling */
+  jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,
+		       scale_factor, force_baseline);
+  jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,
+		       scale_factor, force_baseline);
+}
+
+
+GLOBAL(int)
+jpeg_quality_scaling (int quality)
+/* Convert a user-specified quality rating to a percentage scaling factor
+ * for an underlying quantization table, using our recommended scaling curve.
+ * The input 'quality' factor should be 0 (terrible) to 100 (very good).
+ */
+{
+  /* Safety limit on quality factor.  Convert 0 to 1 to avoid zero divide. */
+  if (quality <= 0) quality = 1;
+  if (quality > 100) quality = 100;
+
+  /* The basic table is used as-is (scaling 100) for a quality of 50.
+   * Qualities 50..100 are converted to scaling percentage 200 - 2*Q;
+   * note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table
+   * to make all the table entries 1 (hence, minimum quantization loss).
+   * Qualities 1..50 are converted to scaling percentage 5000/Q.
+   */
+  if (quality < 50)
+    quality = 5000 / quality;
+  else
+    quality = 200 - quality*2;
+
+  return quality;
+}
+
+
+GLOBAL(void)
+jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline)
+/* Set or change the 'quality' (quantization) setting, using default tables.
+ * This is the standard quality-adjusting entry point for typical user
+ * interfaces; only those who want detailed control over quantization tables
+ * would use the preceding routines directly.
+ */
+{
+  /* Convert user 0-100 rating to percentage scaling */
+  quality = jpeg_quality_scaling(quality);
+
+  /* Set up standard quality tables */
+  jpeg_set_linear_quality(cinfo, quality, force_baseline);
+}
+
+
+/*
+ * Huffman table setup routines
+ */
+
+LOCAL(void)
+add_huff_table (j_compress_ptr cinfo,
+		JHUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val)
+/* Define a Huffman table */
+{
+  int nsymbols, len;
+
+  if (*htblptr == NULL)
+    *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
+
+  /* Copy the number-of-symbols-of-each-code-length counts */
+  MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits));
+
+  /* Validate the counts.  We do this here mainly so we can copy the right
+   * number of symbols from the val[] array, without risking marching off
+   * the end of memory.  jchuff.c will do a more thorough test later.
+   */
+  nsymbols = 0;
+  for (len = 1; len <= 16; len++)
+    nsymbols += bits[len];
+  if (nsymbols < 1 || nsymbols > 256)
+    ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+
+  MEMCOPY((*htblptr)->huffval, val, nsymbols * SIZEOF(UINT8));
+
+  /* Initialize sent_table FALSE so table will be written to JPEG file. */
+  (*htblptr)->sent_table = FALSE;
+}
+
+
+LOCAL(void)
+std_huff_tables (j_compress_ptr cinfo)
+/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
+/* IMPORTANT: these are only valid for 8-bit data precision! */
+{
+  static const UINT8 bits_dc_luminance[17] =
+    { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
+  static const UINT8 val_dc_luminance[] =
+    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+  
+  static const UINT8 bits_dc_chrominance[17] =
+    { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
+  static const UINT8 val_dc_chrominance[] =
+    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+  
+  static const UINT8 bits_ac_luminance[17] =
+    { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
+  static const UINT8 val_ac_luminance[] =
+    { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+      0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+      0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+      0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+      0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+      0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+      0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+      0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+      0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+      0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+      0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+      0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+      0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+      0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+      0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+      0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+      0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+      0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+      0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+      0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+      0xf9, 0xfa };
+  
+  static const UINT8 bits_ac_chrominance[17] =
+    { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
+  static const UINT8 val_ac_chrominance[] =
+    { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+      0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+      0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+      0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+      0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+      0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+      0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+      0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+      0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+      0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+      0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+      0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+      0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+      0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+      0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+      0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+      0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+      0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+      0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+      0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+      0xf9, 0xfa };
+  
+  add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[0],
+		 bits_dc_luminance, val_dc_luminance);
+  add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[0],
+		 bits_ac_luminance, val_ac_luminance);
+  add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[1],
+		 bits_dc_chrominance, val_dc_chrominance);
+  add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[1],
+		 bits_ac_chrominance, val_ac_chrominance);
+}
+
+
+/*
+ * Default parameter setup for compression.
+ *
+ * Applications that don't choose to use this routine must do their
+ * own setup of all these parameters.  Alternately, you can call this
+ * to establish defaults and then alter parameters selectively.  This
+ * is the recommended approach since, if we add any new parameters,
+ * your code will still work (they'll be set to reasonable defaults).
+ */
+
+GLOBAL(void)
+jpeg_set_defaults (j_compress_ptr cinfo)
+{
+  int i;
+
+  /* Safety check to ensure start_compress not called yet. */
+  if (cinfo->global_state != CSTATE_START)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+  /* Allocate comp_info array large enough for maximum component count.
+   * Array is made permanent in case application wants to compress
+   * multiple images at same param settings.
+   */
+  if (cinfo->comp_info == NULL)
+    cinfo->comp_info = (jpeg_component_info *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+				  MAX_COMPONENTS * SIZEOF(jpeg_component_info));
+
+  /* Initialize everything not dependent on the color space */
+
+  cinfo->scale_num = 1;		/* 1:1 scaling */
+  cinfo->scale_denom = 1;
+  cinfo->data_precision = BITS_IN_JSAMPLE;
+  /* Set up two quantization tables using default quality of 75 */
+  jpeg_set_quality(cinfo, 75, TRUE);
+  /* Set up two Huffman tables */
+  std_huff_tables(cinfo);
+
+  /* Initialize default arithmetic coding conditioning */
+  for (i = 0; i < NUM_ARITH_TBLS; i++) {
+    cinfo->arith_dc_L[i] = 0;
+    cinfo->arith_dc_U[i] = 1;
+    cinfo->arith_ac_K[i] = 5;
+  }
+
+  /* Default is no multiple-scan output */
+  cinfo->scan_info = NULL;
+  cinfo->num_scans = 0;
+
+  /* Expect normal source image, not raw downsampled data */
+  cinfo->raw_data_in = FALSE;
+
+  /* The standard Huffman tables are only valid for 8-bit data precision.
+   * If the precision is higher, use arithmetic coding.
+   * (Alternatively, using Huffman coding would be possible with forcing
+   * optimization on so that usable tables will be computed, or by
+   * supplying default tables that are valid for the desired precision.)
+   * Otherwise, use Huffman coding by default.
+   */
+  cinfo->arith_code = cinfo->data_precision > 8 ? TRUE : FALSE;
+
+  /* By default, don't do extra passes to optimize entropy coding */
+  cinfo->optimize_coding = FALSE;
+
+  /* By default, use the simpler non-cosited sampling alignment */
+  cinfo->CCIR601_sampling = FALSE;
+
+  /* By default, apply fancy downsampling */
+  cinfo->do_fancy_downsampling = TRUE;
+
+  /* No input smoothing */
+  cinfo->smoothing_factor = 0;
+
+  /* DCT algorithm preference */
+  cinfo->dct_method = JDCT_DEFAULT;
+
+  /* No restart markers */
+  cinfo->restart_interval = 0;
+  cinfo->restart_in_rows = 0;
+
+  /* Fill in default JFIF marker parameters.  Note that whether the marker
+   * will actually be written is determined by jpeg_set_colorspace.
+   *
+   * By default, the library emits JFIF version code 1.01.
+   * An application that wants to emit JFIF 1.02 extension markers should set
+   * JFIF_minor_version to 2.  We could probably get away with just defaulting
+   * to 1.02, but there may still be some decoders in use that will complain
+   * about that; saying 1.01 should minimize compatibility problems.
+   *
+   * For wide gamut colorspaces (BG_RGB and BG_YCC), the major version will be
+   * overridden by jpeg_set_colorspace and set to 2.
+   */
+  cinfo->JFIF_major_version = 1; /* Default JFIF version = 1.01 */
+  cinfo->JFIF_minor_version = 1;
+  cinfo->density_unit = 0;	/* Pixel size is unknown by default */
+  cinfo->X_density = 1;		/* Pixel aspect ratio is square by default */
+  cinfo->Y_density = 1;
+
+  /* No color transform */
+  cinfo->color_transform = JCT_NONE;
+
+  /* Choose JPEG colorspace based on input space, set defaults accordingly */
+
+  jpeg_default_colorspace(cinfo);
+}
+
+
+/*
+ * Select an appropriate JPEG colorspace for in_color_space.
+ */
+
+GLOBAL(void)
+jpeg_default_colorspace (j_compress_ptr cinfo)
+{
+  switch (cinfo->in_color_space) {
+  case JCS_UNKNOWN:
+    jpeg_set_colorspace(cinfo, JCS_UNKNOWN);
+    break;
+  case JCS_GRAYSCALE:
+    jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
+    break;
+  case JCS_RGB:
+    jpeg_set_colorspace(cinfo, JCS_YCbCr);
+    break;
+  case JCS_YCbCr:
+    jpeg_set_colorspace(cinfo, JCS_YCbCr);
+    break;
+  case JCS_CMYK:
+    jpeg_set_colorspace(cinfo, JCS_CMYK); /* By default, no translation */
+    break;
+  case JCS_YCCK:
+    jpeg_set_colorspace(cinfo, JCS_YCCK);
+    break;
+  case JCS_BG_RGB:
+    /* No translation for now -- conversion to BG_YCC not yet supportet */
+    jpeg_set_colorspace(cinfo, JCS_BG_RGB);
+    break;
+  case JCS_BG_YCC:
+    jpeg_set_colorspace(cinfo, JCS_BG_YCC);
+    break;
+  default:
+    ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+  }
+}
+
+
+/*
+ * Set the JPEG colorspace, and choose colorspace-dependent default values.
+ */
+
+GLOBAL(void)
+jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
+{
+  jpeg_component_info * compptr;
+  int ci;
+
+#define SET_COMP(index,id,hsamp,vsamp,quant,dctbl,actbl)  \
+  (compptr = &cinfo->comp_info[index], \
+   compptr->component_id = (id), \
+   compptr->h_samp_factor = (hsamp), \
+   compptr->v_samp_factor = (vsamp), \
+   compptr->quant_tbl_no = (quant), \
+   compptr->dc_tbl_no = (dctbl), \
+   compptr->ac_tbl_no = (actbl) )
+
+  /* Safety check to ensure start_compress not called yet. */
+  if (cinfo->global_state != CSTATE_START)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+  /* For all colorspaces, we use Q and Huff tables 0 for luminance components,
+   * tables 1 for chrominance components.
+   */
+
+  cinfo->jpeg_color_space = colorspace;
+
+  cinfo->write_JFIF_header = FALSE; /* No marker for non-JFIF colorspaces */
+  cinfo->write_Adobe_marker = FALSE; /* write no Adobe marker by default */
+
+  switch (colorspace) {
+  case JCS_UNKNOWN:
+    cinfo->num_components = cinfo->input_components;
+    if (cinfo->num_components < 1 || cinfo->num_components > MAX_COMPONENTS)
+      ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
+	       MAX_COMPONENTS);
+    for (ci = 0; ci < cinfo->num_components; ci++) {
+      SET_COMP(ci, ci, 1,1, 0, 0,0);
+    }
+    break;
+  case JCS_GRAYSCALE:
+    cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */
+    cinfo->num_components = 1;
+    /* JFIF specifies component ID 1 */
+    SET_COMP(0, 0x01, 1,1, 0, 0,0);
+    break;
+  case JCS_RGB:
+    cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag RGB */
+    cinfo->num_components = 3;
+    SET_COMP(0, 0x52 /* 'R' */, 1,1, 0,
+		cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0,
+		cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0);
+    SET_COMP(1, 0x47 /* 'G' */, 1,1, 0, 0,0);
+    SET_COMP(2, 0x42 /* 'B' */, 1,1, 0,
+		cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0,
+		cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0);
+    break;
+  case JCS_YCbCr:
+    cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */
+    cinfo->num_components = 3;
+    /* JFIF specifies component IDs 1,2,3 */
+    /* We default to 2x2 subsamples of chrominance */
+    SET_COMP(0, 0x01, 2,2, 0, 0,0);
+    SET_COMP(1, 0x02, 1,1, 1, 1,1);
+    SET_COMP(2, 0x03, 1,1, 1, 1,1);
+    break;
+  case JCS_CMYK:
+    cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag CMYK */
+    cinfo->num_components = 4;
+    SET_COMP(0, 0x43 /* 'C' */, 1,1, 0, 0,0);
+    SET_COMP(1, 0x4D /* 'M' */, 1,1, 0, 0,0);
+    SET_COMP(2, 0x59 /* 'Y' */, 1,1, 0, 0,0);
+    SET_COMP(3, 0x4B /* 'K' */, 1,1, 0, 0,0);
+    break;
+  case JCS_YCCK:
+    cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag YCCK */
+    cinfo->num_components = 4;
+    SET_COMP(0, 0x01, 2,2, 0, 0,0);
+    SET_COMP(1, 0x02, 1,1, 1, 1,1);
+    SET_COMP(2, 0x03, 1,1, 1, 1,1);
+    SET_COMP(3, 0x04, 2,2, 0, 0,0);
+    break;
+  case JCS_BG_RGB:
+    cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */
+    cinfo->JFIF_major_version = 2;   /* Set JFIF major version = 2 */
+    cinfo->num_components = 3;
+    /* Add offset 0x20 to the normal R/G/B component IDs */
+    SET_COMP(0, 0x72 /* 'r' */, 1,1, 0,
+		cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0,
+		cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0);
+    SET_COMP(1, 0x67 /* 'g' */, 1,1, 0, 0,0);
+    SET_COMP(2, 0x62 /* 'b' */, 1,1, 0,
+		cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0,
+		cinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0);
+    break;
+  case JCS_BG_YCC:
+    cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */
+    cinfo->JFIF_major_version = 2;   /* Set JFIF major version = 2 */
+    cinfo->num_components = 3;
+    /* Add offset 0x20 to the normal Cb/Cr component IDs */
+    /* We default to 2x2 subsamples of chrominance */
+    SET_COMP(0, 0x01, 2,2, 0, 0,0);
+    SET_COMP(1, 0x22, 1,1, 1, 1,1);
+    SET_COMP(2, 0x23, 1,1, 1, 1,1);
+    break;
+  default:
+    ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+  }
+}
+
+
+#ifdef C_PROGRESSIVE_SUPPORTED
+
+LOCAL(jpeg_scan_info *)
+fill_a_scan (jpeg_scan_info * scanptr, int ci,
+	     int Ss, int Se, int Ah, int Al)
+/* Support routine: generate one scan for specified component */
+{
+  scanptr->comps_in_scan = 1;
+  scanptr->component_index[0] = ci;
+  scanptr->Ss = Ss;
+  scanptr->Se = Se;
+  scanptr->Ah = Ah;
+  scanptr->Al = Al;
+  scanptr++;
+  return scanptr;
+}
+
+LOCAL(jpeg_scan_info *)
+fill_scans (jpeg_scan_info * scanptr, int ncomps,
+	    int Ss, int Se, int Ah, int Al)
+/* Support routine: generate one scan for each component */
+{
+  int ci;
+
+  for (ci = 0; ci < ncomps; ci++) {
+    scanptr->comps_in_scan = 1;
+    scanptr->component_index[0] = ci;
+    scanptr->Ss = Ss;
+    scanptr->Se = Se;
+    scanptr->Ah = Ah;
+    scanptr->Al = Al;
+    scanptr++;
+  }
+  return scanptr;
+}
+
+LOCAL(jpeg_scan_info *)
+fill_dc_scans (jpeg_scan_info * scanptr, int ncomps, int Ah, int Al)
+/* Support routine: generate interleaved DC scan if possible, else N scans */
+{
+  int ci;
+
+  if (ncomps <= MAX_COMPS_IN_SCAN) {
+    /* Single interleaved DC scan */
+    scanptr->comps_in_scan = ncomps;
+    for (ci = 0; ci < ncomps; ci++)
+      scanptr->component_index[ci] = ci;
+    scanptr->Ss = scanptr->Se = 0;
+    scanptr->Ah = Ah;
+    scanptr->Al = Al;
+    scanptr++;
+  } else {
+    /* Noninterleaved DC scan for each component */
+    scanptr = fill_scans(scanptr, ncomps, 0, 0, Ah, Al);
+  }
+  return scanptr;
+}
+
+
+/*
+ * Create a recommended progressive-JPEG script.
+ * cinfo->num_components and cinfo->jpeg_color_space must be correct.
+ */
+
+GLOBAL(void)
+jpeg_simple_progression (j_compress_ptr cinfo)
+{
+  int ncomps = cinfo->num_components;
+  int nscans;
+  jpeg_scan_info * scanptr;
+
+  /* Safety check to ensure start_compress not called yet. */
+  if (cinfo->global_state != CSTATE_START)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+  /* Figure space needed for script.  Calculation must match code below! */
+  if (ncomps == 3 &&
+      (cinfo->jpeg_color_space == JCS_YCbCr ||
+       cinfo->jpeg_color_space == JCS_BG_YCC)) {
+    /* Custom script for YCC color images. */
+    nscans = 10;
+  } else {
+    /* All-purpose script for other color spaces. */
+    if (ncomps > MAX_COMPS_IN_SCAN)
+      nscans = 6 * ncomps;	/* 2 DC + 4 AC scans per component */
+    else
+      nscans = 2 + 4 * ncomps;	/* 2 DC scans; 4 AC scans per component */
+  }
+
+  /* Allocate space for script.
+   * We need to put it in the permanent pool in case the application performs
+   * multiple compressions without changing the settings.  To avoid a memory
+   * leak if jpeg_simple_progression is called repeatedly for the same JPEG
+   * object, we try to re-use previously allocated space, and we allocate
+   * enough space to handle YCC even if initially asked for grayscale.
+   */
+  if (cinfo->script_space == NULL || cinfo->script_space_size < nscans) {
+    cinfo->script_space_size = MAX(nscans, 10);
+    cinfo->script_space = (jpeg_scan_info *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+			cinfo->script_space_size * SIZEOF(jpeg_scan_info));
+  }
+  scanptr = cinfo->script_space;
+  cinfo->scan_info = scanptr;
+  cinfo->num_scans = nscans;
+
+  if (ncomps == 3 &&
+      (cinfo->jpeg_color_space == JCS_YCbCr ||
+       cinfo->jpeg_color_space == JCS_BG_YCC)) {
+    /* Custom script for YCC color images. */
+    /* Initial DC scan */
+    scanptr = fill_dc_scans(scanptr, ncomps, 0, 1);
+    /* Initial AC scan: get some luma data out in a hurry */
+    scanptr = fill_a_scan(scanptr, 0, 1, 5, 0, 2);
+    /* Chroma data is too small to be worth expending many scans on */
+    scanptr = fill_a_scan(scanptr, 2, 1, 63, 0, 1);
+    scanptr = fill_a_scan(scanptr, 1, 1, 63, 0, 1);
+    /* Complete spectral selection for luma AC */
+    scanptr = fill_a_scan(scanptr, 0, 6, 63, 0, 2);
+    /* Refine next bit of luma AC */
+    scanptr = fill_a_scan(scanptr, 0, 1, 63, 2, 1);
+    /* Finish DC successive approximation */
+    scanptr = fill_dc_scans(scanptr, ncomps, 1, 0);
+    /* Finish AC successive approximation */
+    scanptr = fill_a_scan(scanptr, 2, 1, 63, 1, 0);
+    scanptr = fill_a_scan(scanptr, 1, 1, 63, 1, 0);
+    /* Luma bottom bit comes last since it's usually largest scan */
+    scanptr = fill_a_scan(scanptr, 0, 1, 63, 1, 0);
+  } else {
+    /* All-purpose script for other color spaces. */
+    /* Successive approximation first pass */
+    scanptr = fill_dc_scans(scanptr, ncomps, 0, 1);
+    scanptr = fill_scans(scanptr, ncomps, 1, 5, 0, 2);
+    scanptr = fill_scans(scanptr, ncomps, 6, 63, 0, 2);
+    /* Successive approximation second pass */
+    scanptr = fill_scans(scanptr, ncomps, 1, 63, 2, 1);
+    /* Successive approximation final pass */
+    scanptr = fill_dc_scans(scanptr, ncomps, 1, 0);
+    scanptr = fill_scans(scanptr, ncomps, 1, 63, 1, 0);
+  }
+}
+
+#endif /* C_PROGRESSIVE_SUPPORTED */
diff --git a/source/Irrlicht/jpeglib/jcprepct.c b/source/Irrlicht/jpeglib/jcprepct.c
new file mode 100644
index 00000000..00101e0b
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jcprepct.c
@@ -0,0 +1,358 @@
+/*
+ * jcprepct.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the compression preprocessing controller.
+ * This controller manages the color conversion, downsampling,
+ * and edge expansion steps.
+ *
+ * Most of the complexity here is associated with buffering input rows
+ * as required by the downsampler.  See the comments at the head of
+ * jcsample.c for the downsampler's needs.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* At present, jcsample.c can request context rows only for smoothing.
+ * In the future, we might also need context rows for CCIR601 sampling
+ * or other more-complex downsampling procedures.  The code to support
+ * context rows should be compiled only if needed.
+ */
+#ifdef INPUT_SMOOTHING_SUPPORTED
+#define CONTEXT_ROWS_SUPPORTED
+#endif
+
+
+/*
+ * For the simple (no-context-row) case, we just need to buffer one
+ * row group's worth of pixels for the downsampling step.  At the bottom of
+ * the image, we pad to a full row group by replicating the last pixel row.
+ * The downsampler's last output row is then replicated if needed to pad
+ * out to a full iMCU row.
+ *
+ * When providing context rows, we must buffer three row groups' worth of
+ * pixels.  Three row groups are physically allocated, but the row pointer
+ * arrays are made five row groups high, with the extra pointers above and
+ * below "wrapping around" to point to the last and first real row groups.
+ * This allows the downsampler to access the proper context rows.
+ * At the top and bottom of the image, we create dummy context rows by
+ * copying the first or last real pixel row.  This copying could be avoided
+ * by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the
+ * trouble on the compression side.
+ */
+
+
+/* Private buffer controller object */
+
+typedef struct {
+  struct jpeg_c_prep_controller pub; /* public fields */
+
+  /* Downsampling input buffer.  This buffer holds color-converted data
+   * until we have enough to do a downsample step.
+   */
+  JSAMPARRAY color_buf[MAX_COMPONENTS];
+
+  JDIMENSION rows_to_go;	/* counts rows remaining in source image */
+  int next_buf_row;		/* index of next row to store in color_buf */
+
+#ifdef CONTEXT_ROWS_SUPPORTED	/* only needed for context case */
+  int this_row_group;		/* starting row index of group to process */
+  int next_buf_stop;		/* downsample when we reach this index */
+#endif
+} my_prep_controller;
+
+typedef my_prep_controller * my_prep_ptr;
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_prep (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+  my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
+
+  if (pass_mode != JBUF_PASS_THRU)
+    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+
+  /* Initialize total-height counter for detecting bottom of image */
+  prep->rows_to_go = cinfo->image_height;
+  /* Mark the conversion buffer empty */
+  prep->next_buf_row = 0;
+#ifdef CONTEXT_ROWS_SUPPORTED
+  /* Preset additional state variables for context mode.
+   * These aren't used in non-context mode, so we needn't test which mode.
+   */
+  prep->this_row_group = 0;
+  /* Set next_buf_stop to stop after two row groups have been read in. */
+  prep->next_buf_stop = 2 * cinfo->max_v_samp_factor;
+#endif
+}
+
+
+/*
+ * Expand an image vertically from height input_rows to height output_rows,
+ * by duplicating the bottom row.
+ */
+
+LOCAL(void)
+expand_bottom_edge (JSAMPARRAY image_data, JDIMENSION num_cols,
+		    int input_rows, int output_rows)
+{
+  register int row;
+
+  for (row = input_rows; row < output_rows; row++) {
+    jcopy_sample_rows(image_data, input_rows-1, image_data, row,
+		      1, num_cols);
+  }
+}
+
+
+/*
+ * Process some data in the simple no-context case.
+ *
+ * Preprocessor output data is counted in "row groups".  A row group
+ * is defined to be v_samp_factor sample rows of each component.
+ * Downsampling will produce this much data from each max_v_samp_factor
+ * input rows.
+ */
+
+METHODDEF(void)
+pre_process_data (j_compress_ptr cinfo,
+		  JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+		  JDIMENSION in_rows_avail,
+		  JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
+		  JDIMENSION out_row_groups_avail)
+{
+  my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
+  int numrows, ci;
+  JDIMENSION inrows;
+  jpeg_component_info * compptr;
+
+  while (*in_row_ctr < in_rows_avail &&
+	 *out_row_group_ctr < out_row_groups_avail) {
+    /* Do color conversion to fill the conversion buffer. */
+    inrows = in_rows_avail - *in_row_ctr;
+    numrows = cinfo->max_v_samp_factor - prep->next_buf_row;
+    numrows = (int) MIN((JDIMENSION) numrows, inrows);
+    (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr,
+				       prep->color_buf,
+				       (JDIMENSION) prep->next_buf_row,
+				       numrows);
+    *in_row_ctr += numrows;
+    prep->next_buf_row += numrows;
+    prep->rows_to_go -= numrows;
+    /* If at bottom of image, pad to fill the conversion buffer. */
+    if (prep->rows_to_go == 0 &&
+	prep->next_buf_row < cinfo->max_v_samp_factor) {
+      for (ci = 0; ci < cinfo->num_components; ci++) {
+	expand_bottom_edge(prep->color_buf[ci], cinfo->image_width,
+			   prep->next_buf_row, cinfo->max_v_samp_factor);
+      }
+      prep->next_buf_row = cinfo->max_v_samp_factor;
+    }
+    /* If we've filled the conversion buffer, empty it. */
+    if (prep->next_buf_row == cinfo->max_v_samp_factor) {
+      (*cinfo->downsample->downsample) (cinfo,
+					prep->color_buf, (JDIMENSION) 0,
+					output_buf, *out_row_group_ctr);
+      prep->next_buf_row = 0;
+      (*out_row_group_ctr)++;
+    }
+    /* If at bottom of image, pad the output to a full iMCU height.
+     * Note we assume the caller is providing a one-iMCU-height output buffer!
+     */
+    if (prep->rows_to_go == 0 &&
+	*out_row_group_ctr < out_row_groups_avail) {
+      for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+	   ci++, compptr++) {
+	numrows = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+		  cinfo->min_DCT_v_scaled_size;
+	expand_bottom_edge(output_buf[ci],
+			   compptr->width_in_blocks * compptr->DCT_h_scaled_size,
+			   (int) (*out_row_group_ctr * numrows),
+			   (int) (out_row_groups_avail * numrows));
+      }
+      *out_row_group_ctr = out_row_groups_avail;
+      break;			/* can exit outer loop without test */
+    }
+  }
+}
+
+
+#ifdef CONTEXT_ROWS_SUPPORTED
+
+/*
+ * Process some data in the context case.
+ */
+
+METHODDEF(void)
+pre_process_context (j_compress_ptr cinfo,
+		     JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+		     JDIMENSION in_rows_avail,
+		     JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
+		     JDIMENSION out_row_groups_avail)
+{
+  my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
+  int numrows, ci;
+  int buf_height = cinfo->max_v_samp_factor * 3;
+  JDIMENSION inrows;
+
+  while (*out_row_group_ctr < out_row_groups_avail) {
+    if (*in_row_ctr < in_rows_avail) {
+      /* Do color conversion to fill the conversion buffer. */
+      inrows = in_rows_avail - *in_row_ctr;
+      numrows = prep->next_buf_stop - prep->next_buf_row;
+      numrows = (int) MIN((JDIMENSION) numrows, inrows);
+      (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr,
+					 prep->color_buf,
+					 (JDIMENSION) prep->next_buf_row,
+					 numrows);
+      /* Pad at top of image, if first time through */
+      if (prep->rows_to_go == cinfo->image_height) {
+	for (ci = 0; ci < cinfo->num_components; ci++) {
+	  int row;
+	  for (row = 1; row <= cinfo->max_v_samp_factor; row++) {
+	    jcopy_sample_rows(prep->color_buf[ci], 0,
+			      prep->color_buf[ci], -row,
+			      1, cinfo->image_width);
+	  }
+	}
+      }
+      *in_row_ctr += numrows;
+      prep->next_buf_row += numrows;
+      prep->rows_to_go -= numrows;
+    } else {
+      /* Return for more data, unless we are at the bottom of the image. */
+      if (prep->rows_to_go != 0)
+	break;
+      /* When at bottom of image, pad to fill the conversion buffer. */
+      if (prep->next_buf_row < prep->next_buf_stop) {
+	for (ci = 0; ci < cinfo->num_components; ci++) {
+	  expand_bottom_edge(prep->color_buf[ci], cinfo->image_width,
+			     prep->next_buf_row, prep->next_buf_stop);
+	}
+	prep->next_buf_row = prep->next_buf_stop;
+      }
+    }
+    /* If we've gotten enough data, downsample a row group. */
+    if (prep->next_buf_row == prep->next_buf_stop) {
+      (*cinfo->downsample->downsample) (cinfo,
+					prep->color_buf,
+					(JDIMENSION) prep->this_row_group,
+					output_buf, *out_row_group_ctr);
+      (*out_row_group_ctr)++;
+      /* Advance pointers with wraparound as necessary. */
+      prep->this_row_group += cinfo->max_v_samp_factor;
+      if (prep->this_row_group >= buf_height)
+	prep->this_row_group = 0;
+      if (prep->next_buf_row >= buf_height)
+	prep->next_buf_row = 0;
+      prep->next_buf_stop = prep->next_buf_row + cinfo->max_v_samp_factor;
+    }
+  }
+}
+
+
+/*
+ * Create the wrapped-around downsampling input buffer needed for context mode.
+ */
+
+LOCAL(void)
+create_context_buffer (j_compress_ptr cinfo)
+{
+  my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
+  int rgroup_height = cinfo->max_v_samp_factor;
+  int ci, i;
+  jpeg_component_info * compptr;
+  JSAMPARRAY true_buffer, fake_buffer;
+
+  /* Grab enough space for fake row pointers for all the components;
+   * we need five row groups' worth of pointers for each component.
+   */
+  fake_buffer = (JSAMPARRAY)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				(cinfo->num_components * 5 * rgroup_height) *
+				SIZEOF(JSAMPROW));
+
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    /* Allocate the actual buffer space (3 row groups) for this component.
+     * We make the buffer wide enough to allow the downsampler to edge-expand
+     * horizontally within the buffer, if it so chooses.
+     */
+    true_buffer = (*cinfo->mem->alloc_sarray)
+      ((j_common_ptr) cinfo, JPOOL_IMAGE,
+       (JDIMENSION) (((long) compptr->width_in_blocks *
+		      cinfo->min_DCT_h_scaled_size *
+		      cinfo->max_h_samp_factor) / compptr->h_samp_factor),
+       (JDIMENSION) (3 * rgroup_height));
+    /* Copy true buffer row pointers into the middle of the fake row array */
+    MEMCOPY(fake_buffer + rgroup_height, true_buffer,
+	    3 * rgroup_height * SIZEOF(JSAMPROW));
+    /* Fill in the above and below wraparound pointers */
+    for (i = 0; i < rgroup_height; i++) {
+      fake_buffer[i] = true_buffer[2 * rgroup_height + i];
+      fake_buffer[4 * rgroup_height + i] = true_buffer[i];
+    }
+    prep->color_buf[ci] = fake_buffer + rgroup_height;
+    fake_buffer += 5 * rgroup_height; /* point to space for next component */
+  }
+}
+
+#endif /* CONTEXT_ROWS_SUPPORTED */
+
+
+/*
+ * Initialize preprocessing controller.
+ */
+
+GLOBAL(void)
+jinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer)
+{
+  my_prep_ptr prep;
+  int ci;
+  jpeg_component_info * compptr;
+
+  if (need_full_buffer)		/* safety check */
+    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+
+  prep = (my_prep_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(my_prep_controller));
+  cinfo->prep = (struct jpeg_c_prep_controller *) prep;
+  prep->pub.start_pass = start_pass_prep;
+
+  /* Allocate the color conversion buffer.
+   * We make the buffer wide enough to allow the downsampler to edge-expand
+   * horizontally within the buffer, if it so chooses.
+   */
+  if (cinfo->downsample->need_context_rows) {
+    /* Set up to provide context rows */
+#ifdef CONTEXT_ROWS_SUPPORTED
+    prep->pub.pre_process_data = pre_process_context;
+    create_context_buffer(cinfo);
+#else
+    ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+  } else {
+    /* No context, just make it tall enough for one row group */
+    prep->pub.pre_process_data = pre_process_data;
+    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+	 ci++, compptr++) {
+      prep->color_buf[ci] = (*cinfo->mem->alloc_sarray)
+	((j_common_ptr) cinfo, JPOOL_IMAGE,
+	 (JDIMENSION) (((long) compptr->width_in_blocks *
+			cinfo->min_DCT_h_scaled_size *
+			cinfo->max_h_samp_factor) / compptr->h_samp_factor),
+	 (JDIMENSION) cinfo->max_v_samp_factor);
+    }
+  }
+}
diff --git a/source/Irrlicht/jpeglib/jcsample.c b/source/Irrlicht/jpeglib/jcsample.c
new file mode 100644
index 00000000..1aef8a6f
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jcsample.c
@@ -0,0 +1,545 @@
+/*
+ * jcsample.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains downsampling routines.
+ *
+ * Downsampling input data is counted in "row groups".  A row group
+ * is defined to be max_v_samp_factor pixel rows of each component,
+ * from which the downsampler produces v_samp_factor sample rows.
+ * A single row group is processed in each call to the downsampler module.
+ *
+ * The downsampler is responsible for edge-expansion of its output data
+ * to fill an integral number of DCT blocks horizontally.  The source buffer
+ * may be modified if it is helpful for this purpose (the source buffer is
+ * allocated wide enough to correspond to the desired output width).
+ * The caller (the prep controller) is responsible for vertical padding.
+ *
+ * The downsampler may request "context rows" by setting need_context_rows
+ * during startup.  In this case, the input arrays will contain at least
+ * one row group's worth of pixels above and below the passed-in data;
+ * the caller will create dummy rows at image top and bottom by replicating
+ * the first or last real pixel row.
+ *
+ * An excellent reference for image resampling is
+ *   Digital Image Warping, George Wolberg, 1990.
+ *   Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.
+ *
+ * The downsampling algorithm used here is a simple average of the source
+ * pixels covered by the output pixel.  The hi-falutin sampling literature
+ * refers to this as a "box filter".  In general the characteristics of a box
+ * filter are not very good, but for the specific cases we normally use (1:1
+ * and 2:1 ratios) the box is equivalent to a "triangle filter" which is not
+ * nearly so bad.  If you intend to use other sampling ratios, you'd be well
+ * advised to improve this code.
+ *
+ * A simple input-smoothing capability is provided.  This is mainly intended
+ * for cleaning up color-dithered GIF input files (if you find it inadequate,
+ * we suggest using an external filtering program such as pnmconvol).  When
+ * enabled, each input pixel P is replaced by a weighted sum of itself and its
+ * eight neighbors.  P's weight is 1-8*SF and each neighbor's weight is SF,
+ * where SF = (smoothing_factor / 1024).
+ * Currently, smoothing is only supported for 2h2v sampling factors.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Pointer to routine to downsample a single component */
+typedef JMETHOD(void, downsample1_ptr,
+		(j_compress_ptr cinfo, jpeg_component_info * compptr,
+		 JSAMPARRAY input_data, JSAMPARRAY output_data));
+
+/* Private subobject */
+
+typedef struct {
+  struct jpeg_downsampler pub;	/* public fields */
+
+  /* Downsampling method pointers, one per component */
+  downsample1_ptr methods[MAX_COMPONENTS];
+
+  /* Height of an output row group for each component. */
+  int rowgroup_height[MAX_COMPONENTS];
+
+  /* These arrays save pixel expansion factors so that int_downsample need not
+   * recompute them each time.  They are unused for other downsampling methods.
+   */
+  UINT8 h_expand[MAX_COMPONENTS];
+  UINT8 v_expand[MAX_COMPONENTS];
+} my_downsampler;
+
+typedef my_downsampler * my_downsample_ptr;
+
+
+/*
+ * Initialize for a downsampling pass.
+ */
+
+METHODDEF(void)
+start_pass_downsample (j_compress_ptr cinfo)
+{
+  /* no work for now */
+}
+
+
+/*
+ * Expand a component horizontally from width input_cols to width output_cols,
+ * by duplicating the rightmost samples.
+ */
+
+LOCAL(void)
+expand_right_edge (JSAMPARRAY image_data, int num_rows,
+		   JDIMENSION input_cols, JDIMENSION output_cols)
+{
+  register JSAMPROW ptr;
+  register JSAMPLE pixval;
+  register int count;
+  int row;
+  int numcols = (int) (output_cols - input_cols);
+
+  if (numcols > 0) {
+    for (row = 0; row < num_rows; row++) {
+      ptr = image_data[row] + input_cols;
+      pixval = ptr[-1];		/* don't need GETJSAMPLE() here */
+      for (count = numcols; count > 0; count--)
+	*ptr++ = pixval;
+    }
+  }
+}
+
+
+/*
+ * Do downsampling for a whole row group (all components).
+ *
+ * In this version we simply downsample each component independently.
+ */
+
+METHODDEF(void)
+sep_downsample (j_compress_ptr cinfo,
+		JSAMPIMAGE input_buf, JDIMENSION in_row_index,
+		JSAMPIMAGE output_buf, JDIMENSION out_row_group_index)
+{
+  my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample;
+  int ci;
+  jpeg_component_info * compptr;
+  JSAMPARRAY in_ptr, out_ptr;
+
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    in_ptr = input_buf[ci] + in_row_index;
+    out_ptr = output_buf[ci] +
+	      (out_row_group_index * downsample->rowgroup_height[ci]);
+    (*downsample->methods[ci]) (cinfo, compptr, in_ptr, out_ptr);
+  }
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * One row group is processed per call.
+ * This version handles arbitrary integral sampling ratios, without smoothing.
+ * Note that this version is not actually used for customary sampling ratios.
+ */
+
+METHODDEF(void)
+int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+		JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+  my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample;
+  int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v;
+  JDIMENSION outcol, outcol_h;	/* outcol_h == outcol*h_expand */
+  JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
+  JSAMPROW inptr, outptr;
+  INT32 outvalue;
+
+  h_expand = downsample->h_expand[compptr->component_index];
+  v_expand = downsample->v_expand[compptr->component_index];
+  numpix = h_expand * v_expand;
+  numpix2 = numpix/2;
+
+  /* Expand input data enough to let all the output samples be generated
+   * by the standard loop.  Special-casing padded output would be more
+   * efficient.
+   */
+  expand_right_edge(input_data, cinfo->max_v_samp_factor,
+		    cinfo->image_width, output_cols * h_expand);
+
+  inrow = outrow = 0;
+  while (inrow < cinfo->max_v_samp_factor) {
+    outptr = output_data[outrow];
+    for (outcol = 0, outcol_h = 0; outcol < output_cols;
+	 outcol++, outcol_h += h_expand) {
+      outvalue = 0;
+      for (v = 0; v < v_expand; v++) {
+	inptr = input_data[inrow+v] + outcol_h;
+	for (h = 0; h < h_expand; h++) {
+	  outvalue += (INT32) GETJSAMPLE(*inptr++);
+	}
+      }
+      *outptr++ = (JSAMPLE) ((outvalue + numpix2) / numpix);
+    }
+    inrow += v_expand;
+    outrow++;
+  }
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the special case of a full-size component,
+ * without smoothing.
+ */
+
+METHODDEF(void)
+fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+		     JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+  /* Copy the data */
+  jcopy_sample_rows(input_data, 0, output_data, 0,
+		    cinfo->max_v_samp_factor, cinfo->image_width);
+  /* Edge-expand */
+  expand_right_edge(output_data, cinfo->max_v_samp_factor, cinfo->image_width,
+		    compptr->width_in_blocks * compptr->DCT_h_scaled_size);
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the common case of 2:1 horizontal and 1:1 vertical,
+ * without smoothing.
+ *
+ * A note about the "bias" calculations: when rounding fractional values to
+ * integer, we do not want to always round 0.5 up to the next integer.
+ * If we did that, we'd introduce a noticeable bias towards larger values.
+ * Instead, this code is arranged so that 0.5 will be rounded up or down at
+ * alternate pixel locations (a simple ordered dither pattern).
+ */
+
+METHODDEF(void)
+h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+		 JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+  int inrow;
+  JDIMENSION outcol;
+  JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
+  register JSAMPROW inptr, outptr;
+  register int bias;
+
+  /* Expand input data enough to let all the output samples be generated
+   * by the standard loop.  Special-casing padded output would be more
+   * efficient.
+   */
+  expand_right_edge(input_data, cinfo->max_v_samp_factor,
+		    cinfo->image_width, output_cols * 2);
+
+  for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) {
+    outptr = output_data[inrow];
+    inptr = input_data[inrow];
+    bias = 0;			/* bias = 0,1,0,1,... for successive samples */
+    for (outcol = 0; outcol < output_cols; outcol++) {
+      *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr) + GETJSAMPLE(inptr[1])
+			      + bias) >> 1);
+      bias ^= 1;		/* 0=>1, 1=>0 */
+      inptr += 2;
+    }
+  }
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the standard case of 2:1 horizontal and 2:1 vertical,
+ * without smoothing.
+ */
+
+METHODDEF(void)
+h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+		 JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+  int inrow, outrow;
+  JDIMENSION outcol;
+  JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
+  register JSAMPROW inptr0, inptr1, outptr;
+  register int bias;
+
+  /* Expand input data enough to let all the output samples be generated
+   * by the standard loop.  Special-casing padded output would be more
+   * efficient.
+   */
+  expand_right_edge(input_data, cinfo->max_v_samp_factor,
+		    cinfo->image_width, output_cols * 2);
+
+  inrow = outrow = 0;
+  while (inrow < cinfo->max_v_samp_factor) {
+    outptr = output_data[outrow];
+    inptr0 = input_data[inrow];
+    inptr1 = input_data[inrow+1];
+    bias = 1;			/* bias = 1,2,1,2,... for successive samples */
+    for (outcol = 0; outcol < output_cols; outcol++) {
+      *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
+			      GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1])
+			      + bias) >> 2);
+      bias ^= 3;		/* 1=>2, 2=>1 */
+      inptr0 += 2; inptr1 += 2;
+    }
+    inrow += 2;
+    outrow++;
+  }
+}
+
+
+#ifdef INPUT_SMOOTHING_SUPPORTED
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the standard case of 2:1 horizontal and 2:1 vertical,
+ * with smoothing.  One row of context is required.
+ */
+
+METHODDEF(void)
+h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+			JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+  int inrow, outrow;
+  JDIMENSION colctr;
+  JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
+  register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr;
+  INT32 membersum, neighsum, memberscale, neighscale;
+
+  /* Expand input data enough to let all the output samples be generated
+   * by the standard loop.  Special-casing padded output would be more
+   * efficient.
+   */
+  expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2,
+		    cinfo->image_width, output_cols * 2);
+
+  /* We don't bother to form the individual "smoothed" input pixel values;
+   * we can directly compute the output which is the average of the four
+   * smoothed values.  Each of the four member pixels contributes a fraction
+   * (1-8*SF) to its own smoothed image and a fraction SF to each of the three
+   * other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final
+   * output.  The four corner-adjacent neighbor pixels contribute a fraction
+   * SF to just one smoothed pixel, or SF/4 to the final output; while the
+   * eight edge-adjacent neighbors contribute SF to each of two smoothed
+   * pixels, or SF/2 overall.  In order to use integer arithmetic, these
+   * factors are scaled by 2^16 = 65536.
+   * Also recall that SF = smoothing_factor / 1024.
+   */
+
+  memberscale = 16384 - cinfo->smoothing_factor * 80; /* scaled (1-5*SF)/4 */
+  neighscale = cinfo->smoothing_factor * 16; /* scaled SF/4 */
+
+  inrow = outrow = 0;
+  while (inrow < cinfo->max_v_samp_factor) {
+    outptr = output_data[outrow];
+    inptr0 = input_data[inrow];
+    inptr1 = input_data[inrow+1];
+    above_ptr = input_data[inrow-1];
+    below_ptr = input_data[inrow+2];
+
+    /* Special case for first column: pretend column -1 is same as column 0 */
+    membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
+		GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
+    neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
+	       GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
+	       GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[2]) +
+	       GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[2]);
+    neighsum += neighsum;
+    neighsum += GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[2]) +
+		GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[2]);
+    membersum = membersum * memberscale + neighsum * neighscale;
+    *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
+    inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;
+
+    for (colctr = output_cols - 2; colctr > 0; colctr--) {
+      /* sum of pixels directly mapped to this output element */
+      membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
+		  GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
+      /* sum of edge-neighbor pixels */
+      neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
+		 GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
+		 GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[2]) +
+		 GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[2]);
+      /* The edge-neighbors count twice as much as corner-neighbors */
+      neighsum += neighsum;
+      /* Add in the corner-neighbors */
+      neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[2]) +
+		  GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[2]);
+      /* form final output scaled up by 2^16 */
+      membersum = membersum * memberscale + neighsum * neighscale;
+      /* round, descale and output it */
+      *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
+      inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;
+    }
+
+    /* Special case for last column */
+    membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
+		GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
+    neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
+	       GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
+	       GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[1]) +
+	       GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[1]);
+    neighsum += neighsum;
+    neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[1]) +
+		GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[1]);
+    membersum = membersum * memberscale + neighsum * neighscale;
+    *outptr = (JSAMPLE) ((membersum + 32768) >> 16);
+
+    inrow += 2;
+    outrow++;
+  }
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the special case of a full-size component,
+ * with smoothing.  One row of context is required.
+ */
+
+METHODDEF(void)
+fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
+			    JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+  int inrow;
+  JDIMENSION colctr;
+  JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
+  register JSAMPROW inptr, above_ptr, below_ptr, outptr;
+  INT32 membersum, neighsum, memberscale, neighscale;
+  int colsum, lastcolsum, nextcolsum;
+
+  /* Expand input data enough to let all the output samples be generated
+   * by the standard loop.  Special-casing padded output would be more
+   * efficient.
+   */
+  expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2,
+		    cinfo->image_width, output_cols);
+
+  /* Each of the eight neighbor pixels contributes a fraction SF to the
+   * smoothed pixel, while the main pixel contributes (1-8*SF).  In order
+   * to use integer arithmetic, these factors are multiplied by 2^16 = 65536.
+   * Also recall that SF = smoothing_factor / 1024.
+   */
+
+  memberscale = 65536L - cinfo->smoothing_factor * 512L; /* scaled 1-8*SF */
+  neighscale = cinfo->smoothing_factor * 64; /* scaled SF */
+
+  for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) {
+    outptr = output_data[inrow];
+    inptr = input_data[inrow];
+    above_ptr = input_data[inrow-1];
+    below_ptr = input_data[inrow+1];
+
+    /* Special case for first column */
+    colsum = GETJSAMPLE(*above_ptr++) + GETJSAMPLE(*below_ptr++) +
+	     GETJSAMPLE(*inptr);
+    membersum = GETJSAMPLE(*inptr++);
+    nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) +
+		 GETJSAMPLE(*inptr);
+    neighsum = colsum + (colsum - membersum) + nextcolsum;
+    membersum = membersum * memberscale + neighsum * neighscale;
+    *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
+    lastcolsum = colsum; colsum = nextcolsum;
+
+    for (colctr = output_cols - 2; colctr > 0; colctr--) {
+      membersum = GETJSAMPLE(*inptr++);
+      above_ptr++; below_ptr++;
+      nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) +
+		   GETJSAMPLE(*inptr);
+      neighsum = lastcolsum + (colsum - membersum) + nextcolsum;
+      membersum = membersum * memberscale + neighsum * neighscale;
+      *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
+      lastcolsum = colsum; colsum = nextcolsum;
+    }
+
+    /* Special case for last column */
+    membersum = GETJSAMPLE(*inptr);
+    neighsum = lastcolsum + (colsum - membersum) + colsum;
+    membersum = membersum * memberscale + neighsum * neighscale;
+    *outptr = (JSAMPLE) ((membersum + 32768) >> 16);
+
+  }
+}
+
+#endif /* INPUT_SMOOTHING_SUPPORTED */
+
+
+/*
+ * Module initialization routine for downsampling.
+ * Note that we must select a routine for each component.
+ */
+
+GLOBAL(void)
+jinit_downsampler (j_compress_ptr cinfo)
+{
+  my_downsample_ptr downsample;
+  int ci;
+  jpeg_component_info * compptr;
+  boolean smoothok = TRUE;
+  int h_in_group, v_in_group, h_out_group, v_out_group;
+
+  downsample = (my_downsample_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(my_downsampler));
+  cinfo->downsample = (struct jpeg_downsampler *) downsample;
+  downsample->pub.start_pass = start_pass_downsample;
+  downsample->pub.downsample = sep_downsample;
+  downsample->pub.need_context_rows = FALSE;
+
+  if (cinfo->CCIR601_sampling)
+    ERREXIT(cinfo, JERR_CCIR601_NOTIMPL);
+
+  /* Verify we can handle the sampling factors, and set up method pointers */
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    /* Compute size of an "output group" for DCT scaling.  This many samples
+     * are to be converted from max_h_samp_factor * max_v_samp_factor pixels.
+     */
+    h_out_group = (compptr->h_samp_factor * compptr->DCT_h_scaled_size) /
+		  cinfo->min_DCT_h_scaled_size;
+    v_out_group = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+		  cinfo->min_DCT_v_scaled_size;
+    h_in_group = cinfo->max_h_samp_factor;
+    v_in_group = cinfo->max_v_samp_factor;
+    downsample->rowgroup_height[ci] = v_out_group; /* save for use later */
+    if (h_in_group == h_out_group && v_in_group == v_out_group) {
+#ifdef INPUT_SMOOTHING_SUPPORTED
+      if (cinfo->smoothing_factor) {
+	downsample->methods[ci] = fullsize_smooth_downsample;
+	downsample->pub.need_context_rows = TRUE;
+      } else
+#endif
+	downsample->methods[ci] = fullsize_downsample;
+    } else if (h_in_group == h_out_group * 2 &&
+	       v_in_group == v_out_group) {
+      smoothok = FALSE;
+      downsample->methods[ci] = h2v1_downsample;
+    } else if (h_in_group == h_out_group * 2 &&
+	       v_in_group == v_out_group * 2) {
+#ifdef INPUT_SMOOTHING_SUPPORTED
+      if (cinfo->smoothing_factor) {
+	downsample->methods[ci] = h2v2_smooth_downsample;
+	downsample->pub.need_context_rows = TRUE;
+      } else
+#endif
+	downsample->methods[ci] = h2v2_downsample;
+    } else if ((h_in_group % h_out_group) == 0 &&
+	       (v_in_group % v_out_group) == 0) {
+      smoothok = FALSE;
+      downsample->methods[ci] = int_downsample;
+      downsample->h_expand[ci] = (UINT8) (h_in_group / h_out_group);
+      downsample->v_expand[ci] = (UINT8) (v_in_group / v_out_group);
+    } else
+      ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);
+  }
+
+#ifdef INPUT_SMOOTHING_SUPPORTED
+  if (cinfo->smoothing_factor && !smoothok)
+    TRACEMS(cinfo, 0, JTRC_SMOOTH_NOTIMPL);
+#endif
+}
diff --git a/source/Irrlicht/jpeglib/jctrans.c b/source/Irrlicht/jpeglib/jctrans.c
new file mode 100644
index 00000000..38f06e09
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jctrans.c
@@ -0,0 +1,385 @@
+/*
+ * jctrans.c
+ *
+ * Copyright (C) 1995-1998, Thomas G. Lane.
+ * Modified 2000-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains library routines for transcoding compression,
+ * that is, writing raw DCT coefficient arrays to an output JPEG file.
+ * The routines in jcapimin.c will also be needed by a transcoder.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Forward declarations */
+LOCAL(void) transencode_master_selection
+	JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays));
+LOCAL(void) transencode_coef_controller
+	JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays));
+
+
+/*
+ * Compression initialization for writing raw-coefficient data.
+ * Before calling this, all parameters and a data destination must be set up.
+ * Call jpeg_finish_compress() to actually write the data.
+ *
+ * The number of passed virtual arrays must match cinfo->num_components.
+ * Note that the virtual arrays need not be filled or even realized at
+ * the time write_coefficients is called; indeed, if the virtual arrays
+ * were requested from this compression object's memory manager, they
+ * typically will be realized during this routine and filled afterwards.
+ */
+
+GLOBAL(void)
+jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)
+{
+  if (cinfo->global_state != CSTATE_START)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+  /* Mark all tables to be written */
+  jpeg_suppress_tables(cinfo, FALSE);
+  /* (Re)initialize error mgr and destination modules */
+  (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
+  (*cinfo->dest->init_destination) (cinfo);
+  /* Perform master selection of active modules */
+  transencode_master_selection(cinfo, coef_arrays);
+  /* Wait for jpeg_finish_compress() call */
+  cinfo->next_scanline = 0;	/* so jpeg_write_marker works */
+  cinfo->global_state = CSTATE_WRCOEFS;
+}
+
+
+/*
+ * Initialize the compression object with default parameters,
+ * then copy from the source object all parameters needed for lossless
+ * transcoding.  Parameters that can be varied without loss (such as
+ * scan script and Huffman optimization) are left in their default states.
+ */
+
+GLOBAL(void)
+jpeg_copy_critical_parameters (j_decompress_ptr srcinfo,
+			       j_compress_ptr dstinfo)
+{
+  JQUANT_TBL ** qtblptr;
+  jpeg_component_info *incomp, *outcomp;
+  JQUANT_TBL *c_quant, *slot_quant;
+  int tblno, ci, coefi;
+
+  /* Safety check to ensure start_compress not called yet. */
+  if (dstinfo->global_state != CSTATE_START)
+    ERREXIT1(dstinfo, JERR_BAD_STATE, dstinfo->global_state);
+  /* Copy fundamental image dimensions */
+  dstinfo->image_width = srcinfo->image_width;
+  dstinfo->image_height = srcinfo->image_height;
+  dstinfo->input_components = srcinfo->num_components;
+  dstinfo->in_color_space = srcinfo->jpeg_color_space;
+  dstinfo->jpeg_width = srcinfo->output_width;
+  dstinfo->jpeg_height = srcinfo->output_height;
+  dstinfo->min_DCT_h_scaled_size = srcinfo->min_DCT_h_scaled_size;
+  dstinfo->min_DCT_v_scaled_size = srcinfo->min_DCT_v_scaled_size;
+  /* Initialize all parameters to default values */
+  jpeg_set_defaults(dstinfo);
+  /* jpeg_set_defaults may choose wrong colorspace, eg YCbCr if input is RGB.
+   * Fix it to get the right header markers for the image colorspace.
+   * Note: Entropy table assignment in jpeg_set_colorspace depends
+   * on color_transform.
+   */
+  dstinfo->color_transform = srcinfo->color_transform;
+  jpeg_set_colorspace(dstinfo, srcinfo->jpeg_color_space);
+  dstinfo->data_precision = srcinfo->data_precision;
+  dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling;
+  /* Copy the source's quantization tables. */
+  for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
+    if (srcinfo->quant_tbl_ptrs[tblno] != NULL) {
+      qtblptr = & dstinfo->quant_tbl_ptrs[tblno];
+      if (*qtblptr == NULL)
+	*qtblptr = jpeg_alloc_quant_table((j_common_ptr) dstinfo);
+      MEMCOPY((*qtblptr)->quantval,
+	      srcinfo->quant_tbl_ptrs[tblno]->quantval,
+	      SIZEOF((*qtblptr)->quantval));
+      (*qtblptr)->sent_table = FALSE;
+    }
+  }
+  /* Copy the source's per-component info.
+   * Note we assume jpeg_set_defaults has allocated the dest comp_info array.
+   */
+  dstinfo->num_components = srcinfo->num_components;
+  if (dstinfo->num_components < 1 || dstinfo->num_components > MAX_COMPONENTS)
+    ERREXIT2(dstinfo, JERR_COMPONENT_COUNT, dstinfo->num_components,
+	     MAX_COMPONENTS);
+  for (ci = 0, incomp = srcinfo->comp_info, outcomp = dstinfo->comp_info;
+       ci < dstinfo->num_components; ci++, incomp++, outcomp++) {
+    outcomp->component_id = incomp->component_id;
+    outcomp->h_samp_factor = incomp->h_samp_factor;
+    outcomp->v_samp_factor = incomp->v_samp_factor;
+    outcomp->quant_tbl_no = incomp->quant_tbl_no;
+    /* Make sure saved quantization table for component matches the qtable
+     * slot.  If not, the input file re-used this qtable slot.
+     * IJG encoder currently cannot duplicate this.
+     */
+    tblno = outcomp->quant_tbl_no;
+    if (tblno < 0 || tblno >= NUM_QUANT_TBLS ||
+	srcinfo->quant_tbl_ptrs[tblno] == NULL)
+      ERREXIT1(dstinfo, JERR_NO_QUANT_TABLE, tblno);
+    slot_quant = srcinfo->quant_tbl_ptrs[tblno];
+    c_quant = incomp->quant_table;
+    if (c_quant != NULL) {
+      for (coefi = 0; coefi < DCTSIZE2; coefi++) {
+	if (c_quant->quantval[coefi] != slot_quant->quantval[coefi])
+	  ERREXIT1(dstinfo, JERR_MISMATCHED_QUANT_TABLE, tblno);
+      }
+    }
+    /* Note: we do not copy the source's entropy table assignments;
+     * instead we rely on jpeg_set_colorspace to have made a suitable choice.
+     */
+  }
+  /* Also copy JFIF version and resolution information, if available.
+   * Strictly speaking this isn't "critical" info, but it's nearly
+   * always appropriate to copy it if available.  In particular,
+   * if the application chooses to copy JFIF 1.02 extension markers from
+   * the source file, we need to copy the version to make sure we don't
+   * emit a file that has 1.02 extensions but a claimed version of 1.01.
+   */
+  if (srcinfo->saw_JFIF_marker) {
+    if (srcinfo->JFIF_major_version == 1 ||
+	srcinfo->JFIF_major_version == 2) {
+      dstinfo->JFIF_major_version = srcinfo->JFIF_major_version;
+      dstinfo->JFIF_minor_version = srcinfo->JFIF_minor_version;
+    }
+    dstinfo->density_unit = srcinfo->density_unit;
+    dstinfo->X_density = srcinfo->X_density;
+    dstinfo->Y_density = srcinfo->Y_density;
+  }
+}
+
+
+/*
+ * Master selection of compression modules for transcoding.
+ * This substitutes for jcinit.c's initialization of the full compressor.
+ */
+
+LOCAL(void)
+transencode_master_selection (j_compress_ptr cinfo,
+			      jvirt_barray_ptr * coef_arrays)
+{
+  /* Initialize master control (includes parameter checking/processing) */
+  jinit_c_master_control(cinfo, TRUE /* transcode only */);
+
+  /* Entropy encoding: either Huffman or arithmetic coding. */
+  if (cinfo->arith_code)
+    jinit_arith_encoder(cinfo);
+  else {
+    jinit_huff_encoder(cinfo);
+  }
+
+  /* We need a special coefficient buffer controller. */
+  transencode_coef_controller(cinfo, coef_arrays);
+
+  jinit_marker_writer(cinfo);
+
+  /* We can now tell the memory manager to allocate virtual arrays. */
+  (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
+
+  /* Write the datastream header (SOI, JFIF) immediately.
+   * Frame and scan headers are postponed till later.
+   * This lets application insert special markers after the SOI.
+   */
+  (*cinfo->marker->write_file_header) (cinfo);
+}
+
+
+/*
+ * The rest of this file is a special implementation of the coefficient
+ * buffer controller.  This is similar to jccoefct.c, but it handles only
+ * output from presupplied virtual arrays.  Furthermore, we generate any
+ * dummy padding blocks on-the-fly rather than expecting them to be present
+ * in the arrays.
+ */
+
+/* Private buffer controller object */
+
+typedef struct {
+  struct jpeg_c_coef_controller pub; /* public fields */
+
+  JDIMENSION iMCU_row_num;	/* iMCU row # within image */
+  JDIMENSION mcu_ctr;		/* counts MCUs processed in current row */
+  int MCU_vert_offset;		/* counts MCU rows within iMCU row */
+  int MCU_rows_per_iMCU_row;	/* number of such rows needed */
+
+  /* Virtual block array for each component. */
+  jvirt_barray_ptr * whole_image;
+
+  /* Workspace for constructing dummy blocks at right/bottom edges. */
+  JBLOCKROW dummy_buffer[C_MAX_BLOCKS_IN_MCU];
+} my_coef_controller;
+
+typedef my_coef_controller * my_coef_ptr;
+
+
+LOCAL(void)
+start_iMCU_row (j_compress_ptr cinfo)
+/* Reset within-iMCU-row counters for a new row */
+{
+  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+  /* In an interleaved scan, an MCU row is the same as an iMCU row.
+   * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
+   * But at the bottom of the image, process only what's left.
+   */
+  if (cinfo->comps_in_scan > 1) {
+    coef->MCU_rows_per_iMCU_row = 1;
+  } else {
+    if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1))
+      coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
+    else
+      coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
+  }
+
+  coef->mcu_ctr = 0;
+  coef->MCU_vert_offset = 0;
+}
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+  if (pass_mode != JBUF_CRANK_DEST)
+    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+
+  coef->iMCU_row_num = 0;
+  start_iMCU_row(cinfo);
+}
+
+
+/*
+ * Process some data.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor block rows for each component in the scan.
+ * The data is obtained from the virtual arrays and fed to the entropy coder.
+ * Returns TRUE if the iMCU row is completed, FALSE if suspended.
+ *
+ * NB: input_buf is ignored; it is likely to be a NULL pointer.
+ */
+
+METHODDEF(boolean)
+compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+{
+  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+  JDIMENSION MCU_col_num;	/* index of current MCU within row */
+  JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
+  JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+  int blkn, ci, xindex, yindex, yoffset, blockcnt;
+  JDIMENSION start_col;
+  JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];
+  JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU];
+  JBLOCKROW buffer_ptr;
+  jpeg_component_info *compptr;
+
+  /* Align the virtual buffers for the components used in this scan. */
+  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+    compptr = cinfo->cur_comp_info[ci];
+    buffer[ci] = (*cinfo->mem->access_virt_barray)
+      ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],
+       coef->iMCU_row_num * compptr->v_samp_factor,
+       (JDIMENSION) compptr->v_samp_factor, FALSE);
+  }
+
+  /* Loop to process one whole iMCU row */
+  for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+       yoffset++) {
+    for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row;
+	 MCU_col_num++) {
+      /* Construct list of pointers to DCT blocks belonging to this MCU */
+      blkn = 0;			/* index of current DCT block within MCU */
+      for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+	compptr = cinfo->cur_comp_info[ci];
+	start_col = MCU_col_num * compptr->MCU_width;
+	blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
+						: compptr->last_col_width;
+	for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+	  if (coef->iMCU_row_num < last_iMCU_row ||
+	      yindex+yoffset < compptr->last_row_height) {
+	    /* Fill in pointers to real blocks in this row */
+	    buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
+	    for (xindex = 0; xindex < blockcnt; xindex++)
+	      MCU_buffer[blkn++] = buffer_ptr++;
+	  } else {
+	    /* At bottom of image, need a whole row of dummy blocks */
+	    xindex = 0;
+	  }
+	  /* Fill in any dummy blocks needed in this row.
+	   * Dummy blocks are filled in the same way as in jccoefct.c:
+	   * all zeroes in the AC entries, DC entries equal to previous
+	   * block's DC value.  The init routine has already zeroed the
+	   * AC entries, so we need only set the DC entries correctly.
+	   */
+	  for (; xindex < compptr->MCU_width; xindex++) {
+	    MCU_buffer[blkn] = coef->dummy_buffer[blkn];
+	    MCU_buffer[blkn][0][0] = MCU_buffer[blkn-1][0][0];
+	    blkn++;
+	  }
+	}
+      }
+      /* Try to write the MCU. */
+      if (! (*cinfo->entropy->encode_mcu) (cinfo, MCU_buffer)) {
+	/* Suspension forced; update state counters and exit */
+	coef->MCU_vert_offset = yoffset;
+	coef->mcu_ctr = MCU_col_num;
+	return FALSE;
+      }
+    }
+    /* Completed an MCU row, but perhaps not an iMCU row */
+    coef->mcu_ctr = 0;
+  }
+  /* Completed the iMCU row, advance counters for next one */
+  coef->iMCU_row_num++;
+  start_iMCU_row(cinfo);
+  return TRUE;
+}
+
+
+/*
+ * Initialize coefficient buffer controller.
+ *
+ * Each passed coefficient array must be the right size for that
+ * coefficient: width_in_blocks wide and height_in_blocks high,
+ * with unitheight at least v_samp_factor.
+ */
+
+LOCAL(void)
+transencode_coef_controller (j_compress_ptr cinfo,
+			     jvirt_barray_ptr * coef_arrays)
+{
+  my_coef_ptr coef;
+  JBLOCKROW buffer;
+  int i;
+
+  coef = (my_coef_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(my_coef_controller));
+  cinfo->coef = &coef->pub;
+  coef->pub.start_pass = start_pass_coef;
+  coef->pub.compress_data = compress_output;
+
+  /* Save pointer to virtual arrays */
+  coef->whole_image = coef_arrays;
+
+  /* Allocate and pre-zero space for dummy DCT blocks. */
+  buffer = (JBLOCKROW)
+    (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
+  FMEMZERO((void FAR *) buffer, C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
+  for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) {
+    coef->dummy_buffer[i] = buffer + i;
+  }
+}
diff --git a/source/Irrlicht/jpeglib/jdapimin.c b/source/Irrlicht/jpeglib/jdapimin.c
new file mode 100644
index 00000000..c1b88f75
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jdapimin.c
@@ -0,0 +1,399 @@
+/*
+ * jdapimin.c
+ *
+ * Copyright (C) 1994-1998, Thomas G. Lane.
+ * Modified 2009-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface code for the decompression half
+ * of the JPEG library.  These are the "minimum" API routines that may be
+ * needed in either the normal full-decompression case or the
+ * transcoding-only case.
+ *
+ * Most of the routines intended to be called directly by an application
+ * are in this file or in jdapistd.c.  But also see jcomapi.c for routines
+ * shared by compression and decompression, and jdtrans.c for the transcoding
+ * case.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Initialization of a JPEG decompression object.
+ * The error manager must already be set up (in case memory manager fails).
+ */
+
+GLOBAL(void)
+jpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize)
+{
+  int i;
+
+  /* Guard against version mismatches between library and caller. */
+  cinfo->mem = NULL;		/* so jpeg_destroy knows mem mgr not called */
+  if (version != JPEG_LIB_VERSION)
+    ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version);
+  if (structsize != SIZEOF(struct jpeg_decompress_struct))
+    ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, 
+	     (int) SIZEOF(struct jpeg_decompress_struct), (int) structsize);
+
+  /* For debugging purposes, we zero the whole master structure.
+   * But the application has already set the err pointer, and may have set
+   * client_data, so we have to save and restore those fields.
+   * Note: if application hasn't set client_data, tools like Purify may
+   * complain here.
+   */
+  {
+    struct jpeg_error_mgr * err = cinfo->err;
+    void * client_data = cinfo->client_data; /* ignore Purify complaint here */
+    MEMZERO(cinfo, SIZEOF(struct jpeg_decompress_struct));
+    cinfo->err = err;
+    cinfo->client_data = client_data;
+  }
+  cinfo->is_decompressor = TRUE;
+
+  /* Initialize a memory manager instance for this object */
+  jinit_memory_mgr((j_common_ptr) cinfo);
+
+  /* Zero out pointers to permanent structures. */
+  cinfo->progress = NULL;
+  cinfo->src = NULL;
+
+  for (i = 0; i < NUM_QUANT_TBLS; i++)
+    cinfo->quant_tbl_ptrs[i] = NULL;
+
+  for (i = 0; i < NUM_HUFF_TBLS; i++) {
+    cinfo->dc_huff_tbl_ptrs[i] = NULL;
+    cinfo->ac_huff_tbl_ptrs[i] = NULL;
+  }
+
+  /* Initialize marker processor so application can override methods
+   * for COM, APPn markers before calling jpeg_read_header.
+   */
+  cinfo->marker_list = NULL;
+  jinit_marker_reader(cinfo);
+
+  /* And initialize the overall input controller. */
+  jinit_input_controller(cinfo);
+
+  /* OK, I'm ready */
+  cinfo->global_state = DSTATE_START;
+}
+
+
+/*
+ * Destruction of a JPEG decompression object
+ */
+
+GLOBAL(void)
+jpeg_destroy_decompress (j_decompress_ptr cinfo)
+{
+  jpeg_destroy((j_common_ptr) cinfo); /* use common routine */
+}
+
+
+/*
+ * Abort processing of a JPEG decompression operation,
+ * but don't destroy the object itself.
+ */
+
+GLOBAL(void)
+jpeg_abort_decompress (j_decompress_ptr cinfo)
+{
+  jpeg_abort((j_common_ptr) cinfo); /* use common routine */
+}
+
+
+/*
+ * Set default decompression parameters.
+ */
+
+LOCAL(void)
+default_decompress_parms (j_decompress_ptr cinfo)
+{
+  int cid0, cid1, cid2;
+
+  /* Guess the input colorspace, and set output colorspace accordingly. */
+  /* Note application may override our guesses. */
+  switch (cinfo->num_components) {
+  case 1:
+    cinfo->jpeg_color_space = JCS_GRAYSCALE;
+    cinfo->out_color_space = JCS_GRAYSCALE;
+    break;
+    
+  case 3:
+    cid0 = cinfo->comp_info[0].component_id;
+    cid1 = cinfo->comp_info[1].component_id;
+    cid2 = cinfo->comp_info[2].component_id;
+
+    /* First try to guess from the component IDs */
+    if      (cid0 == 0x01 && cid1 == 0x02 && cid2 == 0x03)
+      cinfo->jpeg_color_space = JCS_YCbCr;
+    else if (cid0 == 0x01 && cid1 == 0x22 && cid2 == 0x23)
+      cinfo->jpeg_color_space = JCS_BG_YCC;
+    else if (cid0 == 0x52 && cid1 == 0x47 && cid2 == 0x42)
+      cinfo->jpeg_color_space = JCS_RGB;	/* ASCII 'R', 'G', 'B' */
+    else if (cid0 == 0x72 && cid1 == 0x67 && cid2 == 0x62)
+      cinfo->jpeg_color_space = JCS_BG_RGB;	/* ASCII 'r', 'g', 'b' */
+    else if (cinfo->saw_JFIF_marker)
+      cinfo->jpeg_color_space = JCS_YCbCr;	/* assume it's YCbCr */
+    else if (cinfo->saw_Adobe_marker) {
+      switch (cinfo->Adobe_transform) {
+      case 0:
+	cinfo->jpeg_color_space = JCS_RGB;
+	break;
+      case 1:
+	cinfo->jpeg_color_space = JCS_YCbCr;
+	break;
+      default:
+	WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform);
+	cinfo->jpeg_color_space = JCS_YCbCr;	/* assume it's YCbCr */
+	break;
+      }
+    } else {
+      TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2);
+      cinfo->jpeg_color_space = JCS_YCbCr;	/* assume it's YCbCr */
+    }
+    /* Always guess RGB is proper output colorspace. */
+    cinfo->out_color_space = JCS_RGB;
+    break;
+    
+  case 4:
+    if (cinfo->saw_Adobe_marker) {
+      switch (cinfo->Adobe_transform) {
+      case 0:
+	cinfo->jpeg_color_space = JCS_CMYK;
+	break;
+      case 2:
+	cinfo->jpeg_color_space = JCS_YCCK;
+	break;
+      default:
+	WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform);
+	cinfo->jpeg_color_space = JCS_YCCK;	/* assume it's YCCK */
+	break;
+      }
+    } else {
+      /* No special markers, assume straight CMYK. */
+      cinfo->jpeg_color_space = JCS_CMYK;
+    }
+    cinfo->out_color_space = JCS_CMYK;
+    break;
+    
+  default:
+    cinfo->jpeg_color_space = JCS_UNKNOWN;
+    cinfo->out_color_space = JCS_UNKNOWN;
+    break;
+  }
+
+  /* Set defaults for other decompression parameters. */
+  cinfo->scale_num = cinfo->block_size;		/* 1:1 scaling */
+  cinfo->scale_denom = cinfo->block_size;
+  cinfo->output_gamma = 1.0;
+  cinfo->buffered_image = FALSE;
+  cinfo->raw_data_out = FALSE;
+  cinfo->dct_method = JDCT_DEFAULT;
+  cinfo->do_fancy_upsampling = TRUE;
+  cinfo->do_block_smoothing = TRUE;
+  cinfo->quantize_colors = FALSE;
+  /* We set these in case application only sets quantize_colors. */
+  cinfo->dither_mode = JDITHER_FS;
+#ifdef QUANT_2PASS_SUPPORTED
+  cinfo->two_pass_quantize = TRUE;
+#else
+  cinfo->two_pass_quantize = FALSE;
+#endif
+  cinfo->desired_number_of_colors = 256;
+  cinfo->colormap = NULL;
+  /* Initialize for no mode change in buffered-image mode. */
+  cinfo->enable_1pass_quant = FALSE;
+  cinfo->enable_external_quant = FALSE;
+  cinfo->enable_2pass_quant = FALSE;
+}
+
+
+/*
+ * Decompression startup: read start of JPEG datastream to see what's there.
+ * Need only initialize JPEG object and supply a data source before calling.
+ *
+ * This routine will read as far as the first SOS marker (ie, actual start of
+ * compressed data), and will save all tables and parameters in the JPEG
+ * object.  It will also initialize the decompression parameters to default
+ * values, and finally return JPEG_HEADER_OK.  On return, the application may
+ * adjust the decompression parameters and then call jpeg_start_decompress.
+ * (Or, if the application only wanted to determine the image parameters,
+ * the data need not be decompressed.  In that case, call jpeg_abort or
+ * jpeg_destroy to release any temporary space.)
+ * If an abbreviated (tables only) datastream is presented, the routine will
+ * return JPEG_HEADER_TABLES_ONLY upon reaching EOI.  The application may then
+ * re-use the JPEG object to read the abbreviated image datastream(s).
+ * It is unnecessary (but OK) to call jpeg_abort in this case.
+ * The JPEG_SUSPENDED return code only occurs if the data source module
+ * requests suspension of the decompressor.  In this case the application
+ * should load more source data and then re-call jpeg_read_header to resume
+ * processing.
+ * If a non-suspending data source is used and require_image is TRUE, then the
+ * return code need not be inspected since only JPEG_HEADER_OK is possible.
+ *
+ * This routine is now just a front end to jpeg_consume_input, with some
+ * extra error checking.
+ */
+
+GLOBAL(int)
+jpeg_read_header (j_decompress_ptr cinfo, boolean require_image)
+{
+  int retcode;
+
+  if (cinfo->global_state != DSTATE_START &&
+      cinfo->global_state != DSTATE_INHEADER)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+  retcode = jpeg_consume_input(cinfo);
+
+  switch (retcode) {
+  case JPEG_REACHED_SOS:
+    retcode = JPEG_HEADER_OK;
+    break;
+  case JPEG_REACHED_EOI:
+    if (require_image)		/* Complain if application wanted an image */
+      ERREXIT(cinfo, JERR_NO_IMAGE);
+    /* Reset to start state; it would be safer to require the application to
+     * call jpeg_abort, but we can't change it now for compatibility reasons.
+     * A side effect is to free any temporary memory (there shouldn't be any).
+     */
+    jpeg_abort((j_common_ptr) cinfo); /* sets state = DSTATE_START */
+    retcode = JPEG_HEADER_TABLES_ONLY;
+    break;
+  case JPEG_SUSPENDED:
+    /* no work */
+    break;
+  }
+
+  return retcode;
+}
+
+
+/*
+ * Consume data in advance of what the decompressor requires.
+ * This can be called at any time once the decompressor object has
+ * been created and a data source has been set up.
+ *
+ * This routine is essentially a state machine that handles a couple
+ * of critical state-transition actions, namely initial setup and
+ * transition from header scanning to ready-for-start_decompress.
+ * All the actual input is done via the input controller's consume_input
+ * method.
+ */
+
+GLOBAL(int)
+jpeg_consume_input (j_decompress_ptr cinfo)
+{
+  int retcode = JPEG_SUSPENDED;
+
+  /* NB: every possible DSTATE value should be listed in this switch */
+  switch (cinfo->global_state) {
+  case DSTATE_START:
+    /* Start-of-datastream actions: reset appropriate modules */
+    (*cinfo->inputctl->reset_input_controller) (cinfo);
+    /* Initialize application's data source module */
+    (*cinfo->src->init_source) (cinfo);
+    cinfo->global_state = DSTATE_INHEADER;
+    /*FALLTHROUGH*/
+  case DSTATE_INHEADER:
+    retcode = (*cinfo->inputctl->consume_input) (cinfo);
+    if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */
+      /* Set up default parameters based on header data */
+      default_decompress_parms(cinfo);
+      /* Set global state: ready for start_decompress */
+      cinfo->global_state = DSTATE_READY;
+    }
+    break;
+  case DSTATE_READY:
+    /* Can't advance past first SOS until start_decompress is called */
+    retcode = JPEG_REACHED_SOS;
+    break;
+  case DSTATE_PRELOAD:
+  case DSTATE_PRESCAN:
+  case DSTATE_SCANNING:
+  case DSTATE_RAW_OK:
+  case DSTATE_BUFIMAGE:
+  case DSTATE_BUFPOST:
+  case DSTATE_STOPPING:
+    retcode = (*cinfo->inputctl->consume_input) (cinfo);
+    break;
+  default:
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+  }
+  return retcode;
+}
+
+
+/*
+ * Have we finished reading the input file?
+ */
+
+GLOBAL(boolean)
+jpeg_input_complete (j_decompress_ptr cinfo)
+{
+  /* Check for valid jpeg object */
+  if (cinfo->global_state < DSTATE_START ||
+      cinfo->global_state > DSTATE_STOPPING)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+  return cinfo->inputctl->eoi_reached;
+}
+
+
+/*
+ * Is there more than one scan?
+ */
+
+GLOBAL(boolean)
+jpeg_has_multiple_scans (j_decompress_ptr cinfo)
+{
+  /* Only valid after jpeg_read_header completes */
+  if (cinfo->global_state < DSTATE_READY ||
+      cinfo->global_state > DSTATE_STOPPING)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+  return cinfo->inputctl->has_multiple_scans;
+}
+
+
+/*
+ * Finish JPEG decompression.
+ *
+ * This will normally just verify the file trailer and release temp storage.
+ *
+ * Returns FALSE if suspended.  The return value need be inspected only if
+ * a suspending data source is used.
+ */
+
+GLOBAL(boolean)
+jpeg_finish_decompress (j_decompress_ptr cinfo)
+{
+  if ((cinfo->global_state == DSTATE_SCANNING ||
+       cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) {
+    /* Terminate final pass of non-buffered mode */
+    if (cinfo->output_scanline < cinfo->output_height)
+      ERREXIT(cinfo, JERR_TOO_LITTLE_DATA);
+    (*cinfo->master->finish_output_pass) (cinfo);
+    cinfo->global_state = DSTATE_STOPPING;
+  } else if (cinfo->global_state == DSTATE_BUFIMAGE) {
+    /* Finishing after a buffered-image operation */
+    cinfo->global_state = DSTATE_STOPPING;
+  } else if (cinfo->global_state != DSTATE_STOPPING) {
+    /* STOPPING = repeat call after a suspension, anything else is error */
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+  }
+  /* Read until EOI */
+  while (! cinfo->inputctl->eoi_reached) {
+    if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED)
+      return FALSE;		/* Suspend, come back later */
+  }
+  /* Do final cleanup */
+  (*cinfo->src->term_source) (cinfo);
+  /* We can use jpeg_abort to release memory and reset global_state */
+  jpeg_abort((j_common_ptr) cinfo);
+  return TRUE;
+}
diff --git a/source/Irrlicht/jpeglib/jdapistd.c b/source/Irrlicht/jpeglib/jdapistd.c
new file mode 100644
index 00000000..6437dc56
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jdapistd.c
@@ -0,0 +1,276 @@
+/*
+ * jdapistd.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2002-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface code for the decompression half
+ * of the JPEG library.  These are the "standard" API routines that are
+ * used in the normal full-decompression case.  They are not used by a
+ * transcoding-only application.  Note that if an application links in
+ * jpeg_start_decompress, it will end up linking in the entire decompressor.
+ * We thus must separate this file from jdapimin.c to avoid linking the
+ * whole decompression library into a transcoder.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Forward declarations */
+LOCAL(boolean) output_pass_setup JPP((j_decompress_ptr cinfo));
+
+
+/*
+ * Decompression initialization.
+ * jpeg_read_header must be completed before calling this.
+ *
+ * If a multipass operating mode was selected, this will do all but the
+ * last pass, and thus may take a great deal of time.
+ *
+ * Returns FALSE if suspended.  The return value need be inspected only if
+ * a suspending data source is used.
+ */
+
+GLOBAL(boolean)
+jpeg_start_decompress (j_decompress_ptr cinfo)
+{
+  if (cinfo->global_state == DSTATE_READY) {
+    /* First call: initialize master control, select active modules */
+    jinit_master_decompress(cinfo);
+    if (cinfo->buffered_image) {
+      /* No more work here; expecting jpeg_start_output next */
+      cinfo->global_state = DSTATE_BUFIMAGE;
+      return TRUE;
+    }
+    cinfo->global_state = DSTATE_PRELOAD;
+  }
+  if (cinfo->global_state == DSTATE_PRELOAD) {
+    /* If file has multiple scans, absorb them all into the coef buffer */
+    if (cinfo->inputctl->has_multiple_scans) {
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+      for (;;) {
+	int retcode;
+	/* Call progress monitor hook if present */
+	if (cinfo->progress != NULL)
+	  (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+	/* Absorb some more input */
+	retcode = (*cinfo->inputctl->consume_input) (cinfo);
+	if (retcode == JPEG_SUSPENDED)
+	  return FALSE;
+	if (retcode == JPEG_REACHED_EOI)
+	  break;
+	/* Advance progress counter if appropriate */
+	if (cinfo->progress != NULL &&
+	    (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {
+	  if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) {
+	    /* jdmaster underestimated number of scans; ratchet up one scan */
+	    cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows;
+	  }
+	}
+      }
+#else
+      ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+    }
+    cinfo->output_scan_number = cinfo->input_scan_number;
+  } else if (cinfo->global_state != DSTATE_PRESCAN)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+  /* Perform any dummy output passes, and set up for the final pass */
+  return output_pass_setup(cinfo);
+}
+
+
+/*
+ * Set up for an output pass, and perform any dummy pass(es) needed.
+ * Common subroutine for jpeg_start_decompress and jpeg_start_output.
+ * Entry: global_state = DSTATE_PRESCAN only if previously suspended.
+ * Exit: If done, returns TRUE and sets global_state for proper output mode.
+ *       If suspended, returns FALSE and sets global_state = DSTATE_PRESCAN.
+ */
+
+LOCAL(boolean)
+output_pass_setup (j_decompress_ptr cinfo)
+{
+  if (cinfo->global_state != DSTATE_PRESCAN) {
+    /* First call: do pass setup */
+    (*cinfo->master->prepare_for_output_pass) (cinfo);
+    cinfo->output_scanline = 0;
+    cinfo->global_state = DSTATE_PRESCAN;
+  }
+  /* Loop over any required dummy passes */
+  while (cinfo->master->is_dummy_pass) {
+#ifdef QUANT_2PASS_SUPPORTED
+    /* Crank through the dummy pass */
+    while (cinfo->output_scanline < cinfo->output_height) {
+      JDIMENSION last_scanline;
+      /* Call progress monitor hook if present */
+      if (cinfo->progress != NULL) {
+	cinfo->progress->pass_counter = (long) cinfo->output_scanline;
+	cinfo->progress->pass_limit = (long) cinfo->output_height;
+	(*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+      }
+      /* Process some data */
+      last_scanline = cinfo->output_scanline;
+      (*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL,
+				    &cinfo->output_scanline, (JDIMENSION) 0);
+      if (cinfo->output_scanline == last_scanline)
+	return FALSE;		/* No progress made, must suspend */
+    }
+    /* Finish up dummy pass, and set up for another one */
+    (*cinfo->master->finish_output_pass) (cinfo);
+    (*cinfo->master->prepare_for_output_pass) (cinfo);
+    cinfo->output_scanline = 0;
+#else
+    ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif /* QUANT_2PASS_SUPPORTED */
+  }
+  /* Ready for application to drive output pass through
+   * jpeg_read_scanlines or jpeg_read_raw_data.
+   */
+  cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING;
+  return TRUE;
+}
+
+
+/*
+ * Read some scanlines of data from the JPEG decompressor.
+ *
+ * The return value will be the number of lines actually read.
+ * This may be less than the number requested in several cases,
+ * including bottom of image, data source suspension, and operating
+ * modes that emit multiple scanlines at a time.
+ *
+ * Note: we warn about excess calls to jpeg_read_scanlines() since
+ * this likely signals an application programmer error.  However,
+ * an oversize buffer (max_lines > scanlines remaining) is not an error.
+ */
+
+GLOBAL(JDIMENSION)
+jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines,
+		     JDIMENSION max_lines)
+{
+  JDIMENSION row_ctr;
+
+  if (cinfo->global_state != DSTATE_SCANNING)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+  if (cinfo->output_scanline >= cinfo->output_height) {
+    WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+    return 0;
+  }
+
+  /* Call progress monitor hook if present */
+  if (cinfo->progress != NULL) {
+    cinfo->progress->pass_counter = (long) cinfo->output_scanline;
+    cinfo->progress->pass_limit = (long) cinfo->output_height;
+    (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+  }
+
+  /* Process some data */
+  row_ctr = 0;
+  (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines);
+  cinfo->output_scanline += row_ctr;
+  return row_ctr;
+}
+
+
+/*
+ * Alternate entry point to read raw data.
+ * Processes exactly one iMCU row per call, unless suspended.
+ */
+
+GLOBAL(JDIMENSION)
+jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data,
+		    JDIMENSION max_lines)
+{
+  JDIMENSION lines_per_iMCU_row;
+
+  if (cinfo->global_state != DSTATE_RAW_OK)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+  if (cinfo->output_scanline >= cinfo->output_height) {
+    WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+    return 0;
+  }
+
+  /* Call progress monitor hook if present */
+  if (cinfo->progress != NULL) {
+    cinfo->progress->pass_counter = (long) cinfo->output_scanline;
+    cinfo->progress->pass_limit = (long) cinfo->output_height;
+    (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+  }
+
+  /* Verify that at least one iMCU row can be returned. */
+  lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_v_scaled_size;
+  if (max_lines < lines_per_iMCU_row)
+    ERREXIT(cinfo, JERR_BUFFER_SIZE);
+
+  /* Decompress directly into user's buffer. */
+  if (! (*cinfo->coef->decompress_data) (cinfo, data))
+    return 0;			/* suspension forced, can do nothing more */
+
+  /* OK, we processed one iMCU row. */
+  cinfo->output_scanline += lines_per_iMCU_row;
+  return lines_per_iMCU_row;
+}
+
+
+/* Additional entry points for buffered-image mode. */
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+
+/*
+ * Initialize for an output pass in buffered-image mode.
+ */
+
+GLOBAL(boolean)
+jpeg_start_output (j_decompress_ptr cinfo, int scan_number)
+{
+  if (cinfo->global_state != DSTATE_BUFIMAGE &&
+      cinfo->global_state != DSTATE_PRESCAN)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+  /* Limit scan number to valid range */
+  if (scan_number <= 0)
+    scan_number = 1;
+  if (cinfo->inputctl->eoi_reached &&
+      scan_number > cinfo->input_scan_number)
+    scan_number = cinfo->input_scan_number;
+  cinfo->output_scan_number = scan_number;
+  /* Perform any dummy output passes, and set up for the real pass */
+  return output_pass_setup(cinfo);
+}
+
+
+/*
+ * Finish up after an output pass in buffered-image mode.
+ *
+ * Returns FALSE if suspended.  The return value need be inspected only if
+ * a suspending data source is used.
+ */
+
+GLOBAL(boolean)
+jpeg_finish_output (j_decompress_ptr cinfo)
+{
+  if ((cinfo->global_state == DSTATE_SCANNING ||
+       cinfo->global_state == DSTATE_RAW_OK) && cinfo->buffered_image) {
+    /* Terminate this pass. */
+    /* We do not require the whole pass to have been completed. */
+    (*cinfo->master->finish_output_pass) (cinfo);
+    cinfo->global_state = DSTATE_BUFPOST;
+  } else if (cinfo->global_state != DSTATE_BUFPOST) {
+    /* BUFPOST = repeat call after a suspension, anything else is error */
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+  }
+  /* Read markers looking for SOS or EOI */
+  while (cinfo->input_scan_number <= cinfo->output_scan_number &&
+	 ! cinfo->inputctl->eoi_reached) {
+    if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED)
+      return FALSE;		/* Suspend, come back later */
+  }
+  cinfo->global_state = DSTATE_BUFIMAGE;
+  return TRUE;
+}
+
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
diff --git a/source/Irrlicht/jpeglib/jdarith.c b/source/Irrlicht/jpeglib/jdarith.c
new file mode 100644
index 00000000..efdb26d3
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jdarith.c
@@ -0,0 +1,796 @@
+/*
+ * jdarith.c
+ *
+ * Developed 1997-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains portable arithmetic entropy decoding routines for JPEG
+ * (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81).
+ *
+ * Both sequential and progressive modes are supported in this single module.
+ *
+ * Suspension is not currently supported in this module.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Expanded entropy decoder object for arithmetic decoding. */
+
+typedef struct {
+  struct jpeg_entropy_decoder pub; /* public fields */
+
+  INT32 c;       /* C register, base of coding interval + input bit buffer */
+  INT32 a;               /* A register, normalized size of coding interval */
+  int ct;     /* bit shift counter, # of bits left in bit buffer part of C */
+                                                         /* init: ct = -16 */
+                                                         /* run: ct = 0..7 */
+                                                         /* error: ct = -1 */
+  int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
+  int dc_context[MAX_COMPS_IN_SCAN]; /* context index for DC conditioning */
+
+  unsigned int restarts_to_go;	/* MCUs left in this restart interval */
+
+  /* Pointers to statistics areas (these workspaces have image lifespan) */
+  unsigned char * dc_stats[NUM_ARITH_TBLS];
+  unsigned char * ac_stats[NUM_ARITH_TBLS];
+
+  /* Statistics bin for coding with fixed probability 0.5 */
+  unsigned char fixed_bin[4];
+} arith_entropy_decoder;
+
+typedef arith_entropy_decoder * arith_entropy_ptr;
+
+/* The following two definitions specify the allocation chunk size
+ * for the statistics area.
+ * According to sections F.1.4.4.1.3 and F.1.4.4.2, we need at least
+ * 49 statistics bins for DC, and 245 statistics bins for AC coding.
+ *
+ * We use a compact representation with 1 byte per statistics bin,
+ * thus the numbers directly represent byte sizes.
+ * This 1 byte per statistics bin contains the meaning of the MPS
+ * (more probable symbol) in the highest bit (mask 0x80), and the
+ * index into the probability estimation state machine table
+ * in the lower bits (mask 0x7F).
+ */
+
+#define DC_STAT_BINS 64
+#define AC_STAT_BINS 256
+
+
+LOCAL(int)
+get_byte (j_decompress_ptr cinfo)
+/* Read next input byte; we do not support suspension in this module. */
+{
+  struct jpeg_source_mgr * src = cinfo->src;
+
+  if (src->bytes_in_buffer == 0)
+    if (! (*src->fill_input_buffer) (cinfo))
+      ERREXIT(cinfo, JERR_CANT_SUSPEND);
+  src->bytes_in_buffer--;
+  return GETJOCTET(*src->next_input_byte++);
+}
+
+
+/*
+ * The core arithmetic decoding routine (common in JPEG and JBIG).
+ * This needs to go as fast as possible.
+ * Machine-dependent optimization facilities
+ * are not utilized in this portable implementation.
+ * However, this code should be fairly efficient and
+ * may be a good base for further optimizations anyway.
+ *
+ * Return value is 0 or 1 (binary decision).
+ *
+ * Note: I've changed the handling of the code base & bit
+ * buffer register C compared to other implementations
+ * based on the standards layout & procedures.
+ * While it also contains both the actual base of the
+ * coding interval (16 bits) and the next-bits buffer,
+ * the cut-point between these two parts is floating
+ * (instead of fixed) with the bit shift counter CT.
+ * Thus, we also need only one (variable instead of
+ * fixed size) shift for the LPS/MPS decision, and
+ * we can get away with any renormalization update
+ * of C (except for new data insertion, of course).
+ *
+ * I've also introduced a new scheme for accessing
+ * the probability estimation state machine table,
+ * derived from Markus Kuhn's JBIG implementation.
+ */
+
+LOCAL(int)
+arith_decode (j_decompress_ptr cinfo, unsigned char *st)
+{
+  register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
+  register unsigned char nl, nm;
+  register INT32 qe, temp;
+  register int sv, data;
+
+  /* Renormalization & data input per section D.2.6 */
+  while (e->a < 0x8000L) {
+    if (--e->ct < 0) {
+      /* Need to fetch next data byte */
+      if (cinfo->unread_marker)
+	data = 0;		/* stuff zero data */
+      else {
+	data = get_byte(cinfo);	/* read next input byte */
+	if (data == 0xFF) {	/* zero stuff or marker code */
+	  do data = get_byte(cinfo);
+	  while (data == 0xFF);	/* swallow extra 0xFF bytes */
+	  if (data == 0)
+	    data = 0xFF;	/* discard stuffed zero byte */
+	  else {
+	    /* Note: Different from the Huffman decoder, hitting
+	     * a marker while processing the compressed data
+	     * segment is legal in arithmetic coding.
+	     * The convention is to supply zero data
+	     * then until decoding is complete.
+	     */
+	    cinfo->unread_marker = data;
+	    data = 0;
+	  }
+	}
+      }
+      e->c = (e->c << 8) | data; /* insert data into C register */
+      if ((e->ct += 8) < 0)	 /* update bit shift counter */
+	/* Need more initial bytes */
+	if (++e->ct == 0)
+	  /* Got 2 initial bytes -> re-init A and exit loop */
+	  e->a = 0x8000L; /* => e->a = 0x10000L after loop exit */
+    }
+    e->a <<= 1;
+  }
+
+  /* Fetch values from our compact representation of Table D.3(D.2):
+   * Qe values and probability estimation state machine
+   */
+  sv = *st;
+  qe = jpeg_aritab[sv & 0x7F];	/* => Qe_Value */
+  nl = qe & 0xFF; qe >>= 8;	/* Next_Index_LPS + Switch_MPS */
+  nm = qe & 0xFF; qe >>= 8;	/* Next_Index_MPS */
+
+  /* Decode & estimation procedures per sections D.2.4 & D.2.5 */
+  temp = e->a - qe;
+  e->a = temp;
+  temp <<= e->ct;
+  if (e->c >= temp) {
+    e->c -= temp;
+    /* Conditional LPS (less probable symbol) exchange */
+    if (e->a < qe) {
+      e->a = qe;
+      *st = (sv & 0x80) ^ nm;	/* Estimate_after_MPS */
+    } else {
+      e->a = qe;
+      *st = (sv & 0x80) ^ nl;	/* Estimate_after_LPS */
+      sv ^= 0x80;		/* Exchange LPS/MPS */
+    }
+  } else if (e->a < 0x8000L) {
+    /* Conditional MPS (more probable symbol) exchange */
+    if (e->a < qe) {
+      *st = (sv & 0x80) ^ nl;	/* Estimate_after_LPS */
+      sv ^= 0x80;		/* Exchange LPS/MPS */
+    } else {
+      *st = (sv & 0x80) ^ nm;	/* Estimate_after_MPS */
+    }
+  }
+
+  return sv >> 7;
+}
+
+
+/*
+ * Check for a restart marker & resynchronize decoder.
+ */
+
+LOCAL(void)
+process_restart (j_decompress_ptr cinfo)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  int ci;
+  jpeg_component_info * compptr;
+
+  /* Advance past the RSTn marker */
+  if (! (*cinfo->marker->read_restart_marker) (cinfo))
+    ERREXIT(cinfo, JERR_CANT_SUSPEND);
+
+  /* Re-initialize statistics areas */
+  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+    compptr = cinfo->cur_comp_info[ci];
+    if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
+      MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS);
+      /* Reset DC predictions to 0 */
+      entropy->last_dc_val[ci] = 0;
+      entropy->dc_context[ci] = 0;
+    }
+    if ((! cinfo->progressive_mode && cinfo->lim_Se) ||
+	(cinfo->progressive_mode && cinfo->Ss)) {
+      MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS);
+    }
+  }
+
+  /* Reset arithmetic decoding variables */
+  entropy->c = 0;
+  entropy->a = 0;
+  entropy->ct = -16;	/* force reading 2 initial bytes to fill C */
+
+  /* Reset restart counter */
+  entropy->restarts_to_go = cinfo->restart_interval;
+}
+
+
+/*
+ * Arithmetic MCU decoding.
+ * Each of these routines decodes and returns one MCU's worth of
+ * arithmetic-compressed coefficients.
+ * The coefficients are reordered from zigzag order into natural array order,
+ * but are not dequantized.
+ *
+ * The i'th block of the MCU is stored into the block pointed to by
+ * MCU_data[i].  WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER.
+ */
+
+/*
+ * MCU decoding for DC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  JBLOCKROW block;
+  unsigned char *st;
+  int blkn, ci, tbl, sign;
+  int v, m;
+
+  /* Process restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0)
+      process_restart(cinfo);
+    entropy->restarts_to_go--;
+  }
+
+  if (entropy->ct == -1) return TRUE;	/* if error do nothing */
+
+  /* Outer loop handles each block in the MCU */
+
+  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+    block = MCU_data[blkn];
+    ci = cinfo->MCU_membership[blkn];
+    tbl = cinfo->cur_comp_info[ci]->dc_tbl_no;
+
+    /* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */
+
+    /* Table F.4: Point to statistics bin S0 for DC coefficient coding */
+    st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
+
+    /* Figure F.19: Decode_DC_DIFF */
+    if (arith_decode(cinfo, st) == 0)
+      entropy->dc_context[ci] = 0;
+    else {
+      /* Figure F.21: Decoding nonzero value v */
+      /* Figure F.22: Decoding the sign of v */
+      sign = arith_decode(cinfo, st + 1);
+      st += 2; st += sign;
+      /* Figure F.23: Decoding the magnitude category of v */
+      if ((m = arith_decode(cinfo, st)) != 0) {
+	st = entropy->dc_stats[tbl] + 20;	/* Table F.4: X1 = 20 */
+	while (arith_decode(cinfo, st)) {
+	  if ((m <<= 1) == 0x8000) {
+	    WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+	    entropy->ct = -1;			/* magnitude overflow */
+	    return TRUE;
+	  }
+	  st += 1;
+	}
+      }
+      /* Section F.1.4.4.1.2: Establish dc_context conditioning category */
+      if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
+	entropy->dc_context[ci] = 0;		   /* zero diff category */
+      else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
+	entropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */
+      else
+	entropy->dc_context[ci] = 4 + (sign * 4);  /* small diff category */
+      v = m;
+      /* Figure F.24: Decoding the magnitude bit pattern of v */
+      st += 14;
+      while (m >>= 1)
+	if (arith_decode(cinfo, st)) v |= m;
+      v += 1; if (sign) v = -v;
+      entropy->last_dc_val[ci] += v;
+    }
+
+    /* Scale and output the DC coefficient (assumes jpeg_natural_order[0]=0) */
+    (*block)[0] = (JCOEF) (entropy->last_dc_val[ci] << cinfo->Al);
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * MCU decoding for AC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  JBLOCKROW block;
+  unsigned char *st;
+  int tbl, sign, k;
+  int v, m;
+  const int * natural_order;
+
+  /* Process restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0)
+      process_restart(cinfo);
+    entropy->restarts_to_go--;
+  }
+
+  if (entropy->ct == -1) return TRUE;	/* if error do nothing */
+
+  natural_order = cinfo->natural_order;
+
+  /* There is always only one block per MCU */
+  block = MCU_data[0];
+  tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
+
+  /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */
+
+  /* Figure F.20: Decode_AC_coefficients */
+  k = cinfo->Ss - 1;
+  do {
+    st = entropy->ac_stats[tbl] + 3 * k;
+    if (arith_decode(cinfo, st)) break;		/* EOB flag */
+    for (;;) {
+      k++;
+      if (arith_decode(cinfo, st + 1)) break;
+      st += 3;
+      if (k >= cinfo->Se) {
+	WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+	entropy->ct = -1;			/* spectral overflow */
+	return TRUE;
+      }
+    }
+    /* Figure F.21: Decoding nonzero value v */
+    /* Figure F.22: Decoding the sign of v */
+    sign = arith_decode(cinfo, entropy->fixed_bin);
+    st += 2;
+    /* Figure F.23: Decoding the magnitude category of v */
+    if ((m = arith_decode(cinfo, st)) != 0) {
+      if (arith_decode(cinfo, st)) {
+	m <<= 1;
+	st = entropy->ac_stats[tbl] +
+	     (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
+	while (arith_decode(cinfo, st)) {
+	  if ((m <<= 1) == 0x8000) {
+	    WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+	    entropy->ct = -1;			/* magnitude overflow */
+	    return TRUE;
+	  }
+	  st += 1;
+	}
+      }
+    }
+    v = m;
+    /* Figure F.24: Decoding the magnitude bit pattern of v */
+    st += 14;
+    while (m >>= 1)
+      if (arith_decode(cinfo, st)) v |= m;
+    v += 1; if (sign) v = -v;
+    /* Scale and output coefficient in natural (dezigzagged) order */
+    (*block)[natural_order[k]] = (JCOEF) (v << cinfo->Al);
+  } while (k < cinfo->Se);
+
+  return TRUE;
+}
+
+
+/*
+ * MCU decoding for DC successive approximation refinement scan.
+ * Note: we assume such scans can be multi-component,
+ * although the spec is not very clear on the point.
+ */
+
+METHODDEF(boolean)
+decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  unsigned char *st;
+  int p1, blkn;
+
+  /* Process restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0)
+      process_restart(cinfo);
+    entropy->restarts_to_go--;
+  }
+
+  st = entropy->fixed_bin;	/* use fixed probability estimation */
+  p1 = 1 << cinfo->Al;		/* 1 in the bit position being coded */
+
+  /* Outer loop handles each block in the MCU */
+
+  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+    /* Encoded data is simply the next bit of the two's-complement DC value */
+    if (arith_decode(cinfo, st))
+      MCU_data[blkn][0][0] |= p1;
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * MCU decoding for AC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  JBLOCKROW block;
+  JCOEFPTR thiscoef;
+  unsigned char *st;
+  int tbl, k, kex;
+  int p1, m1;
+  const int * natural_order;
+
+  /* Process restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0)
+      process_restart(cinfo);
+    entropy->restarts_to_go--;
+  }
+
+  if (entropy->ct == -1) return TRUE;	/* if error do nothing */
+
+  natural_order = cinfo->natural_order;
+
+  /* There is always only one block per MCU */
+  block = MCU_data[0];
+  tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
+
+  p1 = 1 << cinfo->Al;		/* 1 in the bit position being coded */
+  m1 = (-1) << cinfo->Al;	/* -1 in the bit position being coded */
+
+  /* Establish EOBx (previous stage end-of-block) index */
+  kex = cinfo->Se;
+  do {
+    if ((*block)[natural_order[kex]]) break;
+  } while (--kex);
+
+  k = cinfo->Ss - 1;
+  do {
+    st = entropy->ac_stats[tbl] + 3 * k;
+    if (k >= kex)
+      if (arith_decode(cinfo, st)) break;	/* EOB flag */
+    for (;;) {
+      thiscoef = *block + natural_order[++k];
+      if (*thiscoef) {				/* previously nonzero coef */
+	if (arith_decode(cinfo, st + 2)) {
+	  if (*thiscoef < 0)
+	    *thiscoef += m1;
+	  else
+	    *thiscoef += p1;
+	}
+	break;
+      }
+      if (arith_decode(cinfo, st + 1)) {	/* newly nonzero coef */
+	if (arith_decode(cinfo, entropy->fixed_bin))
+	  *thiscoef = m1;
+	else
+	  *thiscoef = p1;
+	break;
+      }
+      st += 3;
+      if (k >= cinfo->Se) {
+	WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+	entropy->ct = -1;			/* spectral overflow */
+	return TRUE;
+      }
+    }
+  } while (k < cinfo->Se);
+
+  return TRUE;
+}
+
+
+/*
+ * Decode one MCU's worth of arithmetic-compressed coefficients.
+ */
+
+METHODDEF(boolean)
+decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  jpeg_component_info * compptr;
+  JBLOCKROW block;
+  unsigned char *st;
+  int blkn, ci, tbl, sign, k;
+  int v, m;
+  const int * natural_order;
+
+  /* Process restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0)
+      process_restart(cinfo);
+    entropy->restarts_to_go--;
+  }
+
+  if (entropy->ct == -1) return TRUE;	/* if error do nothing */
+
+  natural_order = cinfo->natural_order;
+
+  /* Outer loop handles each block in the MCU */
+
+  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+    block = MCU_data[blkn];
+    ci = cinfo->MCU_membership[blkn];
+    compptr = cinfo->cur_comp_info[ci];
+
+    /* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */
+
+    tbl = compptr->dc_tbl_no;
+
+    /* Table F.4: Point to statistics bin S0 for DC coefficient coding */
+    st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
+
+    /* Figure F.19: Decode_DC_DIFF */
+    if (arith_decode(cinfo, st) == 0)
+      entropy->dc_context[ci] = 0;
+    else {
+      /* Figure F.21: Decoding nonzero value v */
+      /* Figure F.22: Decoding the sign of v */
+      sign = arith_decode(cinfo, st + 1);
+      st += 2; st += sign;
+      /* Figure F.23: Decoding the magnitude category of v */
+      if ((m = arith_decode(cinfo, st)) != 0) {
+	st = entropy->dc_stats[tbl] + 20;	/* Table F.4: X1 = 20 */
+	while (arith_decode(cinfo, st)) {
+	  if ((m <<= 1) == 0x8000) {
+	    WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+	    entropy->ct = -1;			/* magnitude overflow */
+	    return TRUE;
+	  }
+	  st += 1;
+	}
+      }
+      /* Section F.1.4.4.1.2: Establish dc_context conditioning category */
+      if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
+	entropy->dc_context[ci] = 0;		   /* zero diff category */
+      else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
+	entropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */
+      else
+	entropy->dc_context[ci] = 4 + (sign * 4);  /* small diff category */
+      v = m;
+      /* Figure F.24: Decoding the magnitude bit pattern of v */
+      st += 14;
+      while (m >>= 1)
+	if (arith_decode(cinfo, st)) v |= m;
+      v += 1; if (sign) v = -v;
+      entropy->last_dc_val[ci] += v;
+    }
+
+    (*block)[0] = (JCOEF) entropy->last_dc_val[ci];
+
+    /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */
+
+    if (cinfo->lim_Se == 0) continue;
+    tbl = compptr->ac_tbl_no;
+    k = 0;
+
+    /* Figure F.20: Decode_AC_coefficients */
+    do {
+      st = entropy->ac_stats[tbl] + 3 * k;
+      if (arith_decode(cinfo, st)) break;	/* EOB flag */
+      for (;;) {
+	k++;
+	if (arith_decode(cinfo, st + 1)) break;
+	st += 3;
+	if (k >= cinfo->lim_Se) {
+	  WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+	  entropy->ct = -1;			/* spectral overflow */
+	  return TRUE;
+	}
+      }
+      /* Figure F.21: Decoding nonzero value v */
+      /* Figure F.22: Decoding the sign of v */
+      sign = arith_decode(cinfo, entropy->fixed_bin);
+      st += 2;
+      /* Figure F.23: Decoding the magnitude category of v */
+      if ((m = arith_decode(cinfo, st)) != 0) {
+	if (arith_decode(cinfo, st)) {
+	  m <<= 1;
+	  st = entropy->ac_stats[tbl] +
+	       (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
+	  while (arith_decode(cinfo, st)) {
+	    if ((m <<= 1) == 0x8000) {
+	      WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+	      entropy->ct = -1;			/* magnitude overflow */
+	      return TRUE;
+	    }
+	    st += 1;
+	  }
+	}
+      }
+      v = m;
+      /* Figure F.24: Decoding the magnitude bit pattern of v */
+      st += 14;
+      while (m >>= 1)
+	if (arith_decode(cinfo, st)) v |= m;
+      v += 1; if (sign) v = -v;
+      (*block)[natural_order[k]] = (JCOEF) v;
+    } while (k < cinfo->lim_Se);
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * Initialize for an arithmetic-compressed scan.
+ */
+
+METHODDEF(void)
+start_pass (j_decompress_ptr cinfo)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  int ci, tbl;
+  jpeg_component_info * compptr;
+
+  if (cinfo->progressive_mode) {
+    /* Validate progressive scan parameters */
+    if (cinfo->Ss == 0) {
+      if (cinfo->Se != 0)
+	goto bad;
+    } else {
+      /* need not check Ss/Se < 0 since they came from unsigned bytes */
+      if (cinfo->Se < cinfo->Ss || cinfo->Se > cinfo->lim_Se)
+	goto bad;
+      /* AC scans may have only one component */
+      if (cinfo->comps_in_scan != 1)
+	goto bad;
+    }
+    if (cinfo->Ah != 0) {
+      /* Successive approximation refinement scan: must have Al = Ah-1. */
+      if (cinfo->Ah-1 != cinfo->Al)
+	goto bad;
+    }
+    if (cinfo->Al > 13) {	/* need not check for < 0 */
+      bad:
+      ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
+	       cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
+    }
+    /* Update progression status, and verify that scan order is legal.
+     * Note that inter-scan inconsistencies are treated as warnings
+     * not fatal errors ... not clear if this is right way to behave.
+     */
+    for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+      int coefi, cindex = cinfo->cur_comp_info[ci]->component_index;
+      int *coef_bit_ptr = & cinfo->coef_bits[cindex][0];
+      if (cinfo->Ss && coef_bit_ptr[0] < 0) /* AC without prior DC scan */
+	WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0);
+      for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) {
+	int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi];
+	if (cinfo->Ah != expected)
+	  WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi);
+	coef_bit_ptr[coefi] = cinfo->Al;
+      }
+    }
+    /* Select MCU decoding routine */
+    if (cinfo->Ah == 0) {
+      if (cinfo->Ss == 0)
+	entropy->pub.decode_mcu = decode_mcu_DC_first;
+      else
+	entropy->pub.decode_mcu = decode_mcu_AC_first;
+    } else {
+      if (cinfo->Ss == 0)
+	entropy->pub.decode_mcu = decode_mcu_DC_refine;
+      else
+	entropy->pub.decode_mcu = decode_mcu_AC_refine;
+    }
+  } else {
+    /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.
+     * This ought to be an error condition, but we make it a warning.
+     */
+    if (cinfo->Ss != 0 || cinfo->Ah != 0 || cinfo->Al != 0 ||
+	(cinfo->Se < DCTSIZE2 && cinfo->Se != cinfo->lim_Se))
+      WARNMS(cinfo, JWRN_NOT_SEQUENTIAL);
+    /* Select MCU decoding routine */
+    entropy->pub.decode_mcu = decode_mcu;
+  }
+
+  /* Allocate & initialize requested statistics areas */
+  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+    compptr = cinfo->cur_comp_info[ci];
+    if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
+      tbl = compptr->dc_tbl_no;
+      if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
+	ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
+      if (entropy->dc_stats[tbl] == NULL)
+	entropy->dc_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
+	  ((j_common_ptr) cinfo, JPOOL_IMAGE, DC_STAT_BINS);
+      MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS);
+      /* Initialize DC predictions to 0 */
+      entropy->last_dc_val[ci] = 0;
+      entropy->dc_context[ci] = 0;
+    }
+    if ((! cinfo->progressive_mode && cinfo->lim_Se) ||
+	(cinfo->progressive_mode && cinfo->Ss)) {
+      tbl = compptr->ac_tbl_no;
+      if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
+	ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
+      if (entropy->ac_stats[tbl] == NULL)
+	entropy->ac_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
+	  ((j_common_ptr) cinfo, JPOOL_IMAGE, AC_STAT_BINS);
+      MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS);
+    }
+  }
+
+  /* Initialize arithmetic decoding variables */
+  entropy->c = 0;
+  entropy->a = 0;
+  entropy->ct = -16;	/* force reading 2 initial bytes to fill C */
+
+  /* Initialize restart counter */
+  entropy->restarts_to_go = cinfo->restart_interval;
+}
+
+
+/*
+ * Finish up at the end of an arithmetic-compressed scan.
+ */
+
+METHODDEF(void)
+finish_pass (j_decompress_ptr cinfo)
+{
+  /* no work necessary here */
+}
+
+
+/*
+ * Module initialization routine for arithmetic entropy decoding.
+ */
+
+GLOBAL(void)
+jinit_arith_decoder (j_decompress_ptr cinfo)
+{
+  arith_entropy_ptr entropy;
+  int i;
+
+  entropy = (arith_entropy_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(arith_entropy_decoder));
+  cinfo->entropy = &entropy->pub;
+  entropy->pub.start_pass = start_pass;
+  entropy->pub.finish_pass = finish_pass;
+
+  /* Mark tables unallocated */
+  for (i = 0; i < NUM_ARITH_TBLS; i++) {
+    entropy->dc_stats[i] = NULL;
+    entropy->ac_stats[i] = NULL;
+  }
+
+  /* Initialize index for fixed probability estimation */
+  entropy->fixed_bin[0] = 113;
+
+  if (cinfo->progressive_mode) {
+    /* Create progression status table */
+    int *coef_bit_ptr, ci;
+    cinfo->coef_bits = (int (*)[DCTSIZE2])
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  cinfo->num_components*DCTSIZE2*SIZEOF(int));
+    coef_bit_ptr = & cinfo->coef_bits[0][0];
+    for (ci = 0; ci < cinfo->num_components; ci++) 
+      for (i = 0; i < DCTSIZE2; i++)
+	*coef_bit_ptr++ = -1;
+  }
+}
diff --git a/source/Irrlicht/jpeglib/jdatadst.c b/source/Irrlicht/jpeglib/jdatadst.c
new file mode 100644
index 00000000..677e4634
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jdatadst.c
@@ -0,0 +1,270 @@
+/*
+ * jdatadst.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2009-2012 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains compression data destination routines for the case of
+ * emitting JPEG data to memory or to a file (or any stdio stream).
+ * While these routines are sufficient for most applications,
+ * some will want to use a different destination manager.
+ * IMPORTANT: we assume that fwrite() will correctly transcribe an array of
+ * JOCTETs into 8-bit-wide elements on external storage.  If char is wider
+ * than 8 bits on your machine, you may need to do some tweaking.
+ */
+
+/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jerror.h"
+
+#ifndef HAVE_STDLIB_H		/*  should declare malloc(),free() */
+extern void * malloc JPP((size_t size));
+extern void free JPP((void *ptr));
+#endif
+
+
+/* Expanded data destination object for stdio output */
+
+typedef struct {
+  struct jpeg_destination_mgr pub; /* public fields */
+
+  FILE * outfile;		/* target stream */
+  JOCTET * buffer;		/* start of buffer */
+} my_destination_mgr;
+
+typedef my_destination_mgr * my_dest_ptr;
+
+#define OUTPUT_BUF_SIZE  4096	/* choose an efficiently fwrite'able size */
+
+
+/* Expanded data destination object for memory output */
+
+typedef struct {
+  struct jpeg_destination_mgr pub; /* public fields */
+
+  unsigned char ** outbuffer;	/* target buffer */
+  unsigned long * outsize;
+  unsigned char * newbuffer;	/* newly allocated buffer */
+  JOCTET * buffer;		/* start of buffer */
+  size_t bufsize;
+} my_mem_destination_mgr;
+
+typedef my_mem_destination_mgr * my_mem_dest_ptr;
+
+
+/*
+ * Initialize destination --- called by jpeg_start_compress
+ * before any data is actually written.
+ */
+
+METHODDEF(void)
+init_destination (j_compress_ptr cinfo)
+{
+  my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+
+  /* Allocate the output buffer --- it will be released when done with image */
+  dest->buffer = (JOCTET *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  OUTPUT_BUF_SIZE * SIZEOF(JOCTET));
+
+  dest->pub.next_output_byte = dest->buffer;
+  dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
+}
+
+METHODDEF(void)
+init_mem_destination (j_compress_ptr cinfo)
+{
+  /* no work necessary here */
+}
+
+
+/*
+ * Empty the output buffer --- called whenever buffer fills up.
+ *
+ * In typical applications, this should write the entire output buffer
+ * (ignoring the current state of next_output_byte & free_in_buffer),
+ * reset the pointer & count to the start of the buffer, and return TRUE
+ * indicating that the buffer has been dumped.
+ *
+ * In applications that need to be able to suspend compression due to output
+ * overrun, a FALSE return indicates that the buffer cannot be emptied now.
+ * In this situation, the compressor will return to its caller (possibly with
+ * an indication that it has not accepted all the supplied scanlines).  The
+ * application should resume compression after it has made more room in the
+ * output buffer.  Note that there are substantial restrictions on the use of
+ * suspension --- see the documentation.
+ *
+ * When suspending, the compressor will back up to a convenient restart point
+ * (typically the start of the current MCU). next_output_byte & free_in_buffer
+ * indicate where the restart point will be if the current call returns FALSE.
+ * Data beyond this point will be regenerated after resumption, so do not
+ * write it out when emptying the buffer externally.
+ */
+
+METHODDEF(boolean)
+empty_output_buffer (j_compress_ptr cinfo)
+{
+  my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+
+  if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) !=
+      (size_t) OUTPUT_BUF_SIZE)
+    ERREXIT(cinfo, JERR_FILE_WRITE);
+
+  dest->pub.next_output_byte = dest->buffer;
+  dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
+
+  return TRUE;
+}
+
+METHODDEF(boolean)
+empty_mem_output_buffer (j_compress_ptr cinfo)
+{
+  size_t nextsize;
+  JOCTET * nextbuffer;
+  my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;
+
+  /* Try to allocate new buffer with double size */
+  nextsize = dest->bufsize * 2;
+  nextbuffer = (JOCTET *) malloc(nextsize);
+
+  if (nextbuffer == NULL)
+    ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
+
+  MEMCOPY(nextbuffer, dest->buffer, dest->bufsize);
+
+  if (dest->newbuffer != NULL)
+    free(dest->newbuffer);
+
+  dest->newbuffer = nextbuffer;
+
+  dest->pub.next_output_byte = nextbuffer + dest->bufsize;
+  dest->pub.free_in_buffer = dest->bufsize;
+
+  dest->buffer = nextbuffer;
+  dest->bufsize = nextsize;
+
+  return TRUE;
+}
+
+
+/*
+ * Terminate destination --- called by jpeg_finish_compress
+ * after all data has been written.  Usually needs to flush buffer.
+ *
+ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
+ * application must deal with any cleanup that should happen even
+ * for error exit.
+ */
+
+METHODDEF(void)
+term_destination (j_compress_ptr cinfo)
+{
+  my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+  size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
+
+  /* Write any data remaining in the buffer */
+  if (datacount > 0) {
+    if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount)
+      ERREXIT(cinfo, JERR_FILE_WRITE);
+  }
+  fflush(dest->outfile);
+  /* Make sure we wrote the output file OK */
+  if (ferror(dest->outfile))
+    ERREXIT(cinfo, JERR_FILE_WRITE);
+}
+
+METHODDEF(void)
+term_mem_destination (j_compress_ptr cinfo)
+{
+  my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;
+
+  *dest->outbuffer = dest->buffer;
+  *dest->outsize = dest->bufsize - dest->pub.free_in_buffer;
+}
+
+
+/*
+ * Prepare for output to a stdio stream.
+ * The caller must have already opened the stream, and is responsible
+ * for closing it after finishing compression.
+ */
+
+GLOBAL(void)
+jpeg_stdio_dest (j_compress_ptr cinfo, FILE * outfile)
+{
+  my_dest_ptr dest;
+
+  /* The destination object is made permanent so that multiple JPEG images
+   * can be written to the same file without re-executing jpeg_stdio_dest.
+   * This makes it dangerous to use this manager and a different destination
+   * manager serially with the same JPEG object, because their private object
+   * sizes may be different.  Caveat programmer.
+   */
+  if (cinfo->dest == NULL) {	/* first time for this JPEG object? */
+    cinfo->dest = (struct jpeg_destination_mgr *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+				  SIZEOF(my_destination_mgr));
+  }
+
+  dest = (my_dest_ptr) cinfo->dest;
+  dest->pub.init_destination = init_destination;
+  dest->pub.empty_output_buffer = empty_output_buffer;
+  dest->pub.term_destination = term_destination;
+  dest->outfile = outfile;
+}
+
+
+/*
+ * Prepare for output to a memory buffer.
+ * The caller may supply an own initial buffer with appropriate size.
+ * Otherwise, or when the actual data output exceeds the given size,
+ * the library adapts the buffer size as necessary.
+ * The standard library functions malloc/free are used for allocating
+ * larger memory, so the buffer is available to the application after
+ * finishing compression, and then the application is responsible for
+ * freeing the requested memory.
+ * Note:  An initial buffer supplied by the caller is expected to be
+ * managed by the application.  The library does not free such buffer
+ * when allocating a larger buffer.
+ */
+
+GLOBAL(void)
+jpeg_mem_dest (j_compress_ptr cinfo,
+	       unsigned char ** outbuffer, unsigned long * outsize)
+{
+  my_mem_dest_ptr dest;
+
+  if (outbuffer == NULL || outsize == NULL)	/* sanity check */
+    ERREXIT(cinfo, JERR_BUFFER_SIZE);
+
+  /* The destination object is made permanent so that multiple JPEG images
+   * can be written to the same buffer without re-executing jpeg_mem_dest.
+   */
+  if (cinfo->dest == NULL) {	/* first time for this JPEG object? */
+    cinfo->dest = (struct jpeg_destination_mgr *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+				  SIZEOF(my_mem_destination_mgr));
+  }
+
+  dest = (my_mem_dest_ptr) cinfo->dest;
+  dest->pub.init_destination = init_mem_destination;
+  dest->pub.empty_output_buffer = empty_mem_output_buffer;
+  dest->pub.term_destination = term_mem_destination;
+  dest->outbuffer = outbuffer;
+  dest->outsize = outsize;
+  dest->newbuffer = NULL;
+
+  if (*outbuffer == NULL || *outsize == 0) {
+    /* Allocate initial buffer */
+    dest->newbuffer = *outbuffer = (unsigned char *) malloc(OUTPUT_BUF_SIZE);
+    if (dest->newbuffer == NULL)
+      ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
+    *outsize = OUTPUT_BUF_SIZE;
+  }
+
+  dest->pub.next_output_byte = dest->buffer = *outbuffer;
+  dest->pub.free_in_buffer = dest->bufsize = *outsize;
+}
diff --git a/source/Irrlicht/jpeglib/jdatasrc.c b/source/Irrlicht/jpeglib/jdatasrc.c
new file mode 100644
index 00000000..e8bca76c
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jdatasrc.c
@@ -0,0 +1,275 @@
+/*
+ * jdatasrc.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2009-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains decompression data source routines for the case of
+ * reading JPEG data from memory or from a file (or any stdio stream).
+ * While these routines are sufficient for most applications,
+ * some will want to use a different source manager.
+ * IMPORTANT: we assume that fread() will correctly transcribe an array of
+ * JOCTETs from 8-bit-wide elements on external storage.  If char is wider
+ * than 8 bits on your machine, you may need to do some tweaking.
+ */
+
+/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jerror.h"
+
+
+/* Expanded data source object for stdio input */
+
+typedef struct {
+  struct jpeg_source_mgr pub;	/* public fields */
+
+  FILE * infile;		/* source stream */
+  JOCTET * buffer;		/* start of buffer */
+  boolean start_of_file;	/* have we gotten any data yet? */
+} my_source_mgr;
+
+typedef my_source_mgr * my_src_ptr;
+
+#define INPUT_BUF_SIZE  4096	/* choose an efficiently fread'able size */
+
+
+/*
+ * Initialize source --- called by jpeg_read_header
+ * before any data is actually read.
+ */
+
+METHODDEF(void)
+init_source (j_decompress_ptr cinfo)
+{
+  my_src_ptr src = (my_src_ptr) cinfo->src;
+
+  /* We reset the empty-input-file flag for each image,
+   * but we don't clear the input buffer.
+   * This is correct behavior for reading a series of images from one source.
+   */
+  src->start_of_file = TRUE;
+}
+
+METHODDEF(void)
+init_mem_source (j_decompress_ptr cinfo)
+{
+  /* no work necessary here */
+}
+
+
+/*
+ * Fill the input buffer --- called whenever buffer is emptied.
+ *
+ * In typical applications, this should read fresh data into the buffer
+ * (ignoring the current state of next_input_byte & bytes_in_buffer),
+ * reset the pointer & count to the start of the buffer, and return TRUE
+ * indicating that the buffer has been reloaded.  It is not necessary to
+ * fill the buffer entirely, only to obtain at least one more byte.
+ *
+ * There is no such thing as an EOF return.  If the end of the file has been
+ * reached, the routine has a choice of ERREXIT() or inserting fake data into
+ * the buffer.  In most cases, generating a warning message and inserting a
+ * fake EOI marker is the best course of action --- this will allow the
+ * decompressor to output however much of the image is there.  However,
+ * the resulting error message is misleading if the real problem is an empty
+ * input file, so we handle that case specially.
+ *
+ * In applications that need to be able to suspend compression due to input
+ * not being available yet, a FALSE return indicates that no more data can be
+ * obtained right now, but more may be forthcoming later.  In this situation,
+ * the decompressor will return to its caller (with an indication of the
+ * number of scanlines it has read, if any).  The application should resume
+ * decompression after it has loaded more data into the input buffer.  Note
+ * that there are substantial restrictions on the use of suspension --- see
+ * the documentation.
+ *
+ * When suspending, the decompressor will back up to a convenient restart point
+ * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
+ * indicate where the restart point will be if the current call returns FALSE.
+ * Data beyond this point must be rescanned after resumption, so move it to
+ * the front of the buffer rather than discarding it.
+ */
+
+METHODDEF(boolean)
+fill_input_buffer (j_decompress_ptr cinfo)
+{
+  my_src_ptr src = (my_src_ptr) cinfo->src;
+  size_t nbytes;
+
+  nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE);
+
+  if (nbytes <= 0) {
+    if (src->start_of_file)	/* Treat empty input file as fatal error */
+      ERREXIT(cinfo, JERR_INPUT_EMPTY);
+    WARNMS(cinfo, JWRN_JPEG_EOF);
+    /* Insert a fake EOI marker */
+    src->buffer[0] = (JOCTET) 0xFF;
+    src->buffer[1] = (JOCTET) JPEG_EOI;
+    nbytes = 2;
+  }
+
+  src->pub.next_input_byte = src->buffer;
+  src->pub.bytes_in_buffer = nbytes;
+  src->start_of_file = FALSE;
+
+  return TRUE;
+}
+
+METHODDEF(boolean)
+fill_mem_input_buffer (j_decompress_ptr cinfo)
+{
+  static const JOCTET mybuffer[4] = {
+    (JOCTET) 0xFF, (JOCTET) JPEG_EOI, 0, 0
+  };
+
+  /* The whole JPEG data is expected to reside in the supplied memory
+   * buffer, so any request for more data beyond the given buffer size
+   * is treated as an error.
+   */
+  WARNMS(cinfo, JWRN_JPEG_EOF);
+
+  /* Insert a fake EOI marker */
+
+  cinfo->src->next_input_byte = mybuffer;
+  cinfo->src->bytes_in_buffer = 2;
+
+  return TRUE;
+}
+
+
+/*
+ * Skip data --- used to skip over a potentially large amount of
+ * uninteresting data (such as an APPn marker).
+ *
+ * Writers of suspendable-input applications must note that skip_input_data
+ * is not granted the right to give a suspension return.  If the skip extends
+ * beyond the data currently in the buffer, the buffer can be marked empty so
+ * that the next read will cause a fill_input_buffer call that can suspend.
+ * Arranging for additional bytes to be discarded before reloading the input
+ * buffer is the application writer's problem.
+ */
+
+METHODDEF(void)
+skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+  struct jpeg_source_mgr * src = cinfo->src;
+
+  /* Just a dumb implementation for now.  Could use fseek() except
+   * it doesn't work on pipes.  Not clear that being smart is worth
+   * any trouble anyway --- large skips are infrequent.
+   */
+  if (num_bytes > 0) {
+    while (num_bytes > (long) src->bytes_in_buffer) {
+      num_bytes -= (long) src->bytes_in_buffer;
+      (void) (*src->fill_input_buffer) (cinfo);
+      /* note we assume that fill_input_buffer will never return FALSE,
+       * so suspension need not be handled.
+       */
+    }
+    src->next_input_byte += (size_t) num_bytes;
+    src->bytes_in_buffer -= (size_t) num_bytes;
+  }
+}
+
+
+/*
+ * An additional method that can be provided by data source modules is the
+ * resync_to_restart method for error recovery in the presence of RST markers.
+ * For the moment, this source module just uses the default resync method
+ * provided by the JPEG library.  That method assumes that no backtracking
+ * is possible.
+ */
+
+
+/*
+ * Terminate source --- called by jpeg_finish_decompress
+ * after all data has been read.  Often a no-op.
+ *
+ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
+ * application must deal with any cleanup that should happen even
+ * for error exit.
+ */
+
+METHODDEF(void)
+term_source (j_decompress_ptr cinfo)
+{
+  /* no work necessary here */
+}
+
+
+/*
+ * Prepare for input from a stdio stream.
+ * The caller must have already opened the stream, and is responsible
+ * for closing it after finishing decompression.
+ */
+
+GLOBAL(void)
+jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile)
+{
+  my_src_ptr src;
+
+  /* The source object and input buffer are made permanent so that a series
+   * of JPEG images can be read from the same file by calling jpeg_stdio_src
+   * only before the first one.  (If we discarded the buffer at the end of
+   * one image, we'd likely lose the start of the next one.)
+   * This makes it unsafe to use this manager and a different source
+   * manager serially with the same JPEG object.  Caveat programmer.
+   */
+  if (cinfo->src == NULL) {	/* first time for this JPEG object? */
+    cinfo->src = (struct jpeg_source_mgr *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+				  SIZEOF(my_source_mgr));
+    src = (my_src_ptr) cinfo->src;
+    src->buffer = (JOCTET *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+				  INPUT_BUF_SIZE * SIZEOF(JOCTET));
+  }
+
+  src = (my_src_ptr) cinfo->src;
+  src->pub.init_source = init_source;
+  src->pub.fill_input_buffer = fill_input_buffer;
+  src->pub.skip_input_data = skip_input_data;
+  src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
+  src->pub.term_source = term_source;
+  src->infile = infile;
+  src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
+  src->pub.next_input_byte = NULL; /* until buffer loaded */
+}
+
+
+/*
+ * Prepare for input from a supplied memory buffer.
+ * The buffer must contain the whole JPEG data.
+ */
+
+GLOBAL(void)
+jpeg_mem_src (j_decompress_ptr cinfo,
+	      unsigned char * inbuffer, unsigned long insize)
+{
+  struct jpeg_source_mgr * src;
+
+  if (inbuffer == NULL || insize == 0)	/* Treat empty input as fatal error */
+    ERREXIT(cinfo, JERR_INPUT_EMPTY);
+
+  /* The source object is made permanent so that a series of JPEG images
+   * can be read from the same buffer by calling jpeg_mem_src only before
+   * the first one.
+   */
+  if (cinfo->src == NULL) {	/* first time for this JPEG object? */
+    cinfo->src = (struct jpeg_source_mgr *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+				  SIZEOF(struct jpeg_source_mgr));
+  }
+
+  src = cinfo->src;
+  src->init_source = init_mem_source;
+  src->fill_input_buffer = fill_mem_input_buffer;
+  src->skip_input_data = skip_input_data;
+  src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
+  src->term_source = term_source;
+  src->bytes_in_buffer = (size_t) insize;
+  src->next_input_byte = (JOCTET *) inbuffer;
+}
diff --git a/source/Irrlicht/jpeglib/jdcoefct.c b/source/Irrlicht/jpeglib/jdcoefct.c
new file mode 100644
index 00000000..75ee51f0
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jdcoefct.c
@@ -0,0 +1,741 @@
+/*
+ * jdcoefct.c
+ *
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * Modified 2002-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the coefficient buffer controller for decompression.
+ * This controller is the top level of the JPEG decompressor proper.
+ * The coefficient buffer lies between entropy decoding and inverse-DCT steps.
+ *
+ * In buffered-image mode, this controller is the interface between
+ * input-oriented processing and output-oriented processing.
+ * Also, the input side (only) is used when reading a file for transcoding.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+/* Block smoothing is only applicable for progressive JPEG, so: */
+#ifndef D_PROGRESSIVE_SUPPORTED
+#undef BLOCK_SMOOTHING_SUPPORTED
+#endif
+
+/* Private buffer controller object */
+
+typedef struct {
+  struct jpeg_d_coef_controller pub; /* public fields */
+
+  /* These variables keep track of the current location of the input side. */
+  /* cinfo->input_iMCU_row is also used for this. */
+  JDIMENSION MCU_ctr;		/* counts MCUs processed in current row */
+  int MCU_vert_offset;		/* counts MCU rows within iMCU row */
+  int MCU_rows_per_iMCU_row;	/* number of such rows needed */
+
+  /* The output side's location is represented by cinfo->output_iMCU_row. */
+
+  /* In single-pass modes, it's sufficient to buffer just one MCU.
+   * We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks,
+   * and let the entropy decoder write into that workspace each time.
+   * (On 80x86, the workspace is FAR even though it's not really very big;
+   * this is to keep the module interfaces unchanged when a large coefficient
+   * buffer is necessary.)
+   * In multi-pass modes, this array points to the current MCU's blocks
+   * within the virtual arrays; it is used only by the input side.
+   */
+  JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU];
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+  /* In multi-pass modes, we need a virtual block array for each component. */
+  jvirt_barray_ptr whole_image[MAX_COMPONENTS];
+#endif
+
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+  /* When doing block smoothing, we latch coefficient Al values here */
+  int * coef_bits_latch;
+#define SAVED_COEFS  6		/* we save coef_bits[0..5] */
+#endif
+} my_coef_controller;
+
+typedef my_coef_controller * my_coef_ptr;
+
+/* Forward declarations */
+METHODDEF(int) decompress_onepass
+	JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+METHODDEF(int) decompress_data
+	JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));
+#endif
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+LOCAL(boolean) smoothing_ok JPP((j_decompress_ptr cinfo));
+METHODDEF(int) decompress_smooth_data
+	JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));
+#endif
+
+
+LOCAL(void)
+start_iMCU_row (j_decompress_ptr cinfo)
+/* Reset within-iMCU-row counters for a new row (input side) */
+{
+  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+  /* In an interleaved scan, an MCU row is the same as an iMCU row.
+   * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
+   * But at the bottom of the image, process only what's left.
+   */
+  if (cinfo->comps_in_scan > 1) {
+    coef->MCU_rows_per_iMCU_row = 1;
+  } else {
+    if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1))
+      coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
+    else
+      coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
+  }
+
+  coef->MCU_ctr = 0;
+  coef->MCU_vert_offset = 0;
+}
+
+
+/*
+ * Initialize for an input processing pass.
+ */
+
+METHODDEF(void)
+start_input_pass (j_decompress_ptr cinfo)
+{
+  cinfo->input_iMCU_row = 0;
+  start_iMCU_row(cinfo);
+}
+
+
+/*
+ * Initialize for an output processing pass.
+ */
+
+METHODDEF(void)
+start_output_pass (j_decompress_ptr cinfo)
+{
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+  /* If multipass, check to see whether to use block smoothing on this pass */
+  if (coef->pub.coef_arrays != NULL) {
+    if (cinfo->do_block_smoothing && smoothing_ok(cinfo))
+      coef->pub.decompress_data = decompress_smooth_data;
+    else
+      coef->pub.decompress_data = decompress_data;
+  }
+#endif
+  cinfo->output_iMCU_row = 0;
+}
+
+
+/*
+ * Decompress and return some data in the single-pass case.
+ * Always attempts to emit one fully interleaved MCU row ("iMCU" row).
+ * Input and output must run in lockstep since we have only a one-MCU buffer.
+ * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+ *
+ * NB: output_buf contains a plane for each component in image,
+ * which we index according to the component's SOF position.
+ */
+
+METHODDEF(int)
+decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
+{
+  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+  JDIMENSION MCU_col_num;	/* index of current MCU within row */
+  JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
+  JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+  int blkn, ci, xindex, yindex, yoffset, useful_width;
+  JSAMPARRAY output_ptr;
+  JDIMENSION start_col, output_col;
+  jpeg_component_info *compptr;
+  inverse_DCT_method_ptr inverse_DCT;
+
+  /* Loop to process as much as one whole iMCU row */
+  for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+       yoffset++) {
+    for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col;
+	 MCU_col_num++) {
+      /* Try to fetch an MCU.  Entropy decoder expects buffer to be zeroed. */
+      if (cinfo->lim_Se)	/* can bypass in DC only case */
+	FMEMZERO((void FAR *) coef->MCU_buffer[0],
+		 (size_t) (cinfo->blocks_in_MCU * SIZEOF(JBLOCK)));
+      if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
+	/* Suspension forced; update state counters and exit */
+	coef->MCU_vert_offset = yoffset;
+	coef->MCU_ctr = MCU_col_num;
+	return JPEG_SUSPENDED;
+      }
+      /* Determine where data should go in output_buf and do the IDCT thing.
+       * We skip dummy blocks at the right and bottom edges (but blkn gets
+       * incremented past them!).  Note the inner loop relies on having
+       * allocated the MCU_buffer[] blocks sequentially.
+       */
+      blkn = 0;			/* index of current DCT block within MCU */
+      for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+	compptr = cinfo->cur_comp_info[ci];
+	/* Don't bother to IDCT an uninteresting component. */
+	if (! compptr->component_needed) {
+	  blkn += compptr->MCU_blocks;
+	  continue;
+	}
+	inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index];
+	useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
+						    : compptr->last_col_width;
+	output_ptr = output_buf[compptr->component_index] +
+	  yoffset * compptr->DCT_v_scaled_size;
+	start_col = MCU_col_num * compptr->MCU_sample_width;
+	for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+	  if (cinfo->input_iMCU_row < last_iMCU_row ||
+	      yoffset+yindex < compptr->last_row_height) {
+	    output_col = start_col;
+	    for (xindex = 0; xindex < useful_width; xindex++) {
+	      (*inverse_DCT) (cinfo, compptr,
+			      (JCOEFPTR) coef->MCU_buffer[blkn+xindex],
+			      output_ptr, output_col);
+	      output_col += compptr->DCT_h_scaled_size;
+	    }
+	  }
+	  blkn += compptr->MCU_width;
+	  output_ptr += compptr->DCT_v_scaled_size;
+	}
+      }
+    }
+    /* Completed an MCU row, but perhaps not an iMCU row */
+    coef->MCU_ctr = 0;
+  }
+  /* Completed the iMCU row, advance counters for next one */
+  cinfo->output_iMCU_row++;
+  if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) {
+    start_iMCU_row(cinfo);
+    return JPEG_ROW_COMPLETED;
+  }
+  /* Completed the scan */
+  (*cinfo->inputctl->finish_input_pass) (cinfo);
+  return JPEG_SCAN_COMPLETED;
+}
+
+
+/*
+ * Dummy consume-input routine for single-pass operation.
+ */
+
+METHODDEF(int)
+dummy_consume_data (j_decompress_ptr cinfo)
+{
+  return JPEG_SUSPENDED;	/* Always indicate nothing was done */
+}
+
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+
+/*
+ * Consume input data and store it in the full-image coefficient buffer.
+ * We read as much as one fully interleaved MCU row ("iMCU" row) per call,
+ * ie, v_samp_factor block rows for each component in the scan.
+ * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+ */
+
+METHODDEF(int)
+consume_data (j_decompress_ptr cinfo)
+{
+  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+  JDIMENSION MCU_col_num;	/* index of current MCU within row */
+  int blkn, ci, xindex, yindex, yoffset;
+  JDIMENSION start_col;
+  JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];
+  JBLOCKROW buffer_ptr;
+  jpeg_component_info *compptr;
+
+  /* Align the virtual buffers for the components used in this scan. */
+  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+    compptr = cinfo->cur_comp_info[ci];
+    buffer[ci] = (*cinfo->mem->access_virt_barray)
+      ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],
+       cinfo->input_iMCU_row * compptr->v_samp_factor,
+       (JDIMENSION) compptr->v_samp_factor, TRUE);
+    /* Note: entropy decoder expects buffer to be zeroed,
+     * but this is handled automatically by the memory manager
+     * because we requested a pre-zeroed array.
+     */
+  }
+
+  /* Loop to process one whole iMCU row */
+  for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+       yoffset++) {
+    for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row;
+	 MCU_col_num++) {
+      /* Construct list of pointers to DCT blocks belonging to this MCU */
+      blkn = 0;			/* index of current DCT block within MCU */
+      for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+	compptr = cinfo->cur_comp_info[ci];
+	start_col = MCU_col_num * compptr->MCU_width;
+	for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+	  buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
+	  for (xindex = 0; xindex < compptr->MCU_width; xindex++) {
+	    coef->MCU_buffer[blkn++] = buffer_ptr++;
+	  }
+	}
+      }
+      /* Try to fetch the MCU. */
+      if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
+	/* Suspension forced; update state counters and exit */
+	coef->MCU_vert_offset = yoffset;
+	coef->MCU_ctr = MCU_col_num;
+	return JPEG_SUSPENDED;
+      }
+    }
+    /* Completed an MCU row, but perhaps not an iMCU row */
+    coef->MCU_ctr = 0;
+  }
+  /* Completed the iMCU row, advance counters for next one */
+  if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) {
+    start_iMCU_row(cinfo);
+    return JPEG_ROW_COMPLETED;
+  }
+  /* Completed the scan */
+  (*cinfo->inputctl->finish_input_pass) (cinfo);
+  return JPEG_SCAN_COMPLETED;
+}
+
+
+/*
+ * Decompress and return some data in the multi-pass case.
+ * Always attempts to emit one fully interleaved MCU row ("iMCU" row).
+ * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+ *
+ * NB: output_buf contains a plane for each component in image.
+ */
+
+METHODDEF(int)
+decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
+{
+  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+  JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+  JDIMENSION block_num;
+  int ci, block_row, block_rows;
+  JBLOCKARRAY buffer;
+  JBLOCKROW buffer_ptr;
+  JSAMPARRAY output_ptr;
+  JDIMENSION output_col;
+  jpeg_component_info *compptr;
+  inverse_DCT_method_ptr inverse_DCT;
+
+  /* Force some input to be done if we are getting ahead of the input. */
+  while (cinfo->input_scan_number < cinfo->output_scan_number ||
+	 (cinfo->input_scan_number == cinfo->output_scan_number &&
+	  cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) {
+    if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED)
+      return JPEG_SUSPENDED;
+  }
+
+  /* OK, output from the virtual arrays. */
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    /* Don't bother to IDCT an uninteresting component. */
+    if (! compptr->component_needed)
+      continue;
+    /* Align the virtual buffer for this component. */
+    buffer = (*cinfo->mem->access_virt_barray)
+      ((j_common_ptr) cinfo, coef->whole_image[ci],
+       cinfo->output_iMCU_row * compptr->v_samp_factor,
+       (JDIMENSION) compptr->v_samp_factor, FALSE);
+    /* Count non-dummy DCT block rows in this iMCU row. */
+    if (cinfo->output_iMCU_row < last_iMCU_row)
+      block_rows = compptr->v_samp_factor;
+    else {
+      /* NB: can't use last_row_height here; it is input-side-dependent! */
+      block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+      if (block_rows == 0) block_rows = compptr->v_samp_factor;
+    }
+    inverse_DCT = cinfo->idct->inverse_DCT[ci];
+    output_ptr = output_buf[ci];
+    /* Loop over all DCT blocks to be processed. */
+    for (block_row = 0; block_row < block_rows; block_row++) {
+      buffer_ptr = buffer[block_row];
+      output_col = 0;
+      for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) {
+	(*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr,
+			output_ptr, output_col);
+	buffer_ptr++;
+	output_col += compptr->DCT_h_scaled_size;
+      }
+      output_ptr += compptr->DCT_v_scaled_size;
+    }
+  }
+
+  if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows)
+    return JPEG_ROW_COMPLETED;
+  return JPEG_SCAN_COMPLETED;
+}
+
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+
+
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+
+/*
+ * This code applies interblock smoothing as described by section K.8
+ * of the JPEG standard: the first 5 AC coefficients are estimated from
+ * the DC values of a DCT block and its 8 neighboring blocks.
+ * We apply smoothing only for progressive JPEG decoding, and only if
+ * the coefficients it can estimate are not yet known to full precision.
+ */
+
+/* Natural-order array positions of the first 5 zigzag-order coefficients */
+#define Q01_POS  1
+#define Q10_POS  8
+#define Q20_POS  16
+#define Q11_POS  9
+#define Q02_POS  2
+
+/*
+ * Determine whether block smoothing is applicable and safe.
+ * We also latch the current states of the coef_bits[] entries for the
+ * AC coefficients; otherwise, if the input side of the decompressor
+ * advances into a new scan, we might think the coefficients are known
+ * more accurately than they really are.
+ */
+
+LOCAL(boolean)
+smoothing_ok (j_decompress_ptr cinfo)
+{
+  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+  boolean smoothing_useful = FALSE;
+  int ci, coefi;
+  jpeg_component_info *compptr;
+  JQUANT_TBL * qtable;
+  int * coef_bits;
+  int * coef_bits_latch;
+
+  if (! cinfo->progressive_mode || cinfo->coef_bits == NULL)
+    return FALSE;
+
+  /* Allocate latch area if not already done */
+  if (coef->coef_bits_latch == NULL)
+    coef->coef_bits_latch = (int *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  cinfo->num_components *
+				  (SAVED_COEFS * SIZEOF(int)));
+  coef_bits_latch = coef->coef_bits_latch;
+
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    /* All components' quantization values must already be latched. */
+    if ((qtable = compptr->quant_table) == NULL)
+      return FALSE;
+    /* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */
+    if (qtable->quantval[0] == 0 ||
+	qtable->quantval[Q01_POS] == 0 ||
+	qtable->quantval[Q10_POS] == 0 ||
+	qtable->quantval[Q20_POS] == 0 ||
+	qtable->quantval[Q11_POS] == 0 ||
+	qtable->quantval[Q02_POS] == 0)
+      return FALSE;
+    /* DC values must be at least partly known for all components. */
+    coef_bits = cinfo->coef_bits[ci];
+    if (coef_bits[0] < 0)
+      return FALSE;
+    /* Block smoothing is helpful if some AC coefficients remain inaccurate. */
+    for (coefi = 1; coefi <= 5; coefi++) {
+      coef_bits_latch[coefi] = coef_bits[coefi];
+      if (coef_bits[coefi] != 0)
+	smoothing_useful = TRUE;
+    }
+    coef_bits_latch += SAVED_COEFS;
+  }
+
+  return smoothing_useful;
+}
+
+
+/*
+ * Variant of decompress_data for use when doing block smoothing.
+ */
+
+METHODDEF(int)
+decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
+{
+  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+  JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+  JDIMENSION block_num, last_block_column;
+  int ci, block_row, block_rows, access_rows;
+  JBLOCKARRAY buffer;
+  JBLOCKROW buffer_ptr, prev_block_row, next_block_row;
+  JSAMPARRAY output_ptr;
+  JDIMENSION output_col;
+  jpeg_component_info *compptr;
+  inverse_DCT_method_ptr inverse_DCT;
+  boolean first_row, last_row;
+  JBLOCK workspace;
+  int *coef_bits;
+  JQUANT_TBL *quanttbl;
+  INT32 Q00,Q01,Q02,Q10,Q11,Q20, num;
+  int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9;
+  int Al, pred;
+
+  /* Force some input to be done if we are getting ahead of the input. */
+  while (cinfo->input_scan_number <= cinfo->output_scan_number &&
+	 ! cinfo->inputctl->eoi_reached) {
+    if (cinfo->input_scan_number == cinfo->output_scan_number) {
+      /* If input is working on current scan, we ordinarily want it to
+       * have completed the current row.  But if input scan is DC,
+       * we want it to keep one row ahead so that next block row's DC
+       * values are up to date.
+       */
+      JDIMENSION delta = (cinfo->Ss == 0) ? 1 : 0;
+      if (cinfo->input_iMCU_row > cinfo->output_iMCU_row+delta)
+	break;
+    }
+    if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED)
+      return JPEG_SUSPENDED;
+  }
+
+  /* OK, output from the virtual arrays. */
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    /* Don't bother to IDCT an uninteresting component. */
+    if (! compptr->component_needed)
+      continue;
+    /* Count non-dummy DCT block rows in this iMCU row. */
+    if (cinfo->output_iMCU_row < last_iMCU_row) {
+      block_rows = compptr->v_samp_factor;
+      access_rows = block_rows * 2; /* this and next iMCU row */
+      last_row = FALSE;
+    } else {
+      /* NB: can't use last_row_height here; it is input-side-dependent! */
+      block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+      if (block_rows == 0) block_rows = compptr->v_samp_factor;
+      access_rows = block_rows; /* this iMCU row only */
+      last_row = TRUE;
+    }
+    /* Align the virtual buffer for this component. */
+    if (cinfo->output_iMCU_row > 0) {
+      access_rows += compptr->v_samp_factor; /* prior iMCU row too */
+      buffer = (*cinfo->mem->access_virt_barray)
+	((j_common_ptr) cinfo, coef->whole_image[ci],
+	 (cinfo->output_iMCU_row - 1) * compptr->v_samp_factor,
+	 (JDIMENSION) access_rows, FALSE);
+      buffer += compptr->v_samp_factor;	/* point to current iMCU row */
+      first_row = FALSE;
+    } else {
+      buffer = (*cinfo->mem->access_virt_barray)
+	((j_common_ptr) cinfo, coef->whole_image[ci],
+	 (JDIMENSION) 0, (JDIMENSION) access_rows, FALSE);
+      first_row = TRUE;
+    }
+    /* Fetch component-dependent info */
+    coef_bits = coef->coef_bits_latch + (ci * SAVED_COEFS);
+    quanttbl = compptr->quant_table;
+    Q00 = quanttbl->quantval[0];
+    Q01 = quanttbl->quantval[Q01_POS];
+    Q10 = quanttbl->quantval[Q10_POS];
+    Q20 = quanttbl->quantval[Q20_POS];
+    Q11 = quanttbl->quantval[Q11_POS];
+    Q02 = quanttbl->quantval[Q02_POS];
+    inverse_DCT = cinfo->idct->inverse_DCT[ci];
+    output_ptr = output_buf[ci];
+    /* Loop over all DCT blocks to be processed. */
+    for (block_row = 0; block_row < block_rows; block_row++) {
+      buffer_ptr = buffer[block_row];
+      if (first_row && block_row == 0)
+	prev_block_row = buffer_ptr;
+      else
+	prev_block_row = buffer[block_row-1];
+      if (last_row && block_row == block_rows-1)
+	next_block_row = buffer_ptr;
+      else
+	next_block_row = buffer[block_row+1];
+      /* We fetch the surrounding DC values using a sliding-register approach.
+       * Initialize all nine here so as to do the right thing on narrow pics.
+       */
+      DC1 = DC2 = DC3 = (int) prev_block_row[0][0];
+      DC4 = DC5 = DC6 = (int) buffer_ptr[0][0];
+      DC7 = DC8 = DC9 = (int) next_block_row[0][0];
+      output_col = 0;
+      last_block_column = compptr->width_in_blocks - 1;
+      for (block_num = 0; block_num <= last_block_column; block_num++) {
+	/* Fetch current DCT block into workspace so we can modify it. */
+	jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1);
+	/* Update DC values */
+	if (block_num < last_block_column) {
+	  DC3 = (int) prev_block_row[1][0];
+	  DC6 = (int) buffer_ptr[1][0];
+	  DC9 = (int) next_block_row[1][0];
+	}
+	/* Compute coefficient estimates per K.8.
+	 * An estimate is applied only if coefficient is still zero,
+	 * and is not known to be fully accurate.
+	 */
+	/* AC01 */
+	if ((Al=coef_bits[1]) != 0 && workspace[1] == 0) {
+	  num = 36 * Q00 * (DC4 - DC6);
+	  if (num >= 0) {
+	    pred = (int) (((Q01<<7) + num) / (Q01<<8));
+	    if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) {
+	    pred = (int) (((Q10<<7) + num) / (Q10<<8));
+	    if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) {
+	    pred = (int) (((Q20<<7) + num) / (Q20<<8));
+	    if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) {
+	    pred = (int) (((Q11<<7) + num) / (Q11<<8));
+	    if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) {
+	    pred = (int) (((Q02<<7) + num) / (Q02<<8));
+	    if (Al > 0 && pred >= (1< 0 && pred >= (1<DCT_h_scaled_size;
+      }
+      output_ptr += compptr->DCT_v_scaled_size;
+    }
+  }
+
+  if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows)
+    return JPEG_ROW_COMPLETED;
+  return JPEG_SCAN_COMPLETED;
+}
+
+#endif /* BLOCK_SMOOTHING_SUPPORTED */
+
+
+/*
+ * Initialize coefficient buffer controller.
+ */
+
+GLOBAL(void)
+jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
+{
+  my_coef_ptr coef;
+
+  coef = (my_coef_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(my_coef_controller));
+  cinfo->coef = (struct jpeg_d_coef_controller *) coef;
+  coef->pub.start_input_pass = start_input_pass;
+  coef->pub.start_output_pass = start_output_pass;
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+  coef->coef_bits_latch = NULL;
+#endif
+
+  /* Create the coefficient buffer. */
+  if (need_full_buffer) {
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+    /* Allocate a full-image virtual array for each component, */
+    /* padded to a multiple of samp_factor DCT blocks in each direction. */
+    /* Note we ask for a pre-zeroed array. */
+    int ci, access_rows;
+    jpeg_component_info *compptr;
+
+    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+	 ci++, compptr++) {
+      access_rows = compptr->v_samp_factor;
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+      /* If block smoothing could be used, need a bigger window */
+      if (cinfo->progressive_mode)
+	access_rows *= 3;
+#endif
+      coef->whole_image[ci] = (*cinfo->mem->request_virt_barray)
+	((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE,
+	 (JDIMENSION) jround_up((long) compptr->width_in_blocks,
+				(long) compptr->h_samp_factor),
+	 (JDIMENSION) jround_up((long) compptr->height_in_blocks,
+				(long) compptr->v_samp_factor),
+	 (JDIMENSION) access_rows);
+    }
+    coef->pub.consume_data = consume_data;
+    coef->pub.decompress_data = decompress_data;
+    coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */
+#else
+    ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+  } else {
+    /* We only need a single-MCU buffer. */
+    JBLOCKROW buffer;
+    int i;
+
+    buffer = (JBLOCKROW)
+      (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
+    for (i = 0; i < D_MAX_BLOCKS_IN_MCU; i++) {
+      coef->MCU_buffer[i] = buffer + i;
+    }
+    if (cinfo->lim_Se == 0)	/* DC only case: want to bypass later */
+      FMEMZERO((void FAR *) buffer,
+	       (size_t) (D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)));
+    coef->pub.consume_data = dummy_consume_data;
+    coef->pub.decompress_data = decompress_onepass;
+    coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */
+  }
+}
diff --git a/source/Irrlicht/jpeglib/jdcolor.c b/source/Irrlicht/jpeglib/jdcolor.c
new file mode 100644
index 00000000..b1357765
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jdcolor.c
@@ -0,0 +1,748 @@
+/*
+ * jdcolor.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2011-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains output colorspace conversion routines.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private subobject */
+
+typedef struct {
+  struct jpeg_color_deconverter pub; /* public fields */
+
+  /* Private state for YCbCr->RGB and BG_YCC->RGB conversion */
+  int * Cr_r_tab;		/* => table for Cr to R conversion */
+  int * Cb_b_tab;		/* => table for Cb to B conversion */
+  INT32 * Cr_g_tab;		/* => table for Cr to G conversion */
+  INT32 * Cb_g_tab;		/* => table for Cb to G conversion */
+
+  JSAMPLE * range_limit; /* pointer to normal sample range limit table, */
+		     /* or extended sample range limit table for BG_YCC */
+
+  /* Private state for RGB->Y conversion */
+  INT32 * rgb_y_tab;		/* => table for RGB to Y conversion */
+} my_color_deconverter;
+
+typedef my_color_deconverter * my_cconvert_ptr;
+
+
+/***************  YCbCr -> RGB conversion: most common case **************/
+/*************** BG_YCC -> RGB conversion: less common case **************/
+/***************    RGB -> Y   conversion: less common case **************/
+
+/*
+ * YCbCr is defined per Recommendation ITU-R BT.601-7 (03/2011),
+ * previously known as Recommendation CCIR 601-1, except that Cb and Cr
+ * are normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
+ * sRGB (standard RGB color space) is defined per IEC 61966-2-1:1999.
+ * sYCC (standard luma-chroma-chroma color space with extended gamut)
+ * is defined per IEC 61966-2-1:1999 Amendment A1:2003 Annex F.
+ * bg-sRGB and bg-sYCC (big gamut standard color spaces)
+ * are defined per IEC 61966-2-1:1999 Amendment A1:2003 Annex G.
+ * Note that the derived conversion coefficients given in some of these
+ * documents are imprecise.  The general conversion equations are
+ *
+ *	R = Y + K * (1 - Kr) * Cr
+ *	G = Y - K * (Kb * (1 - Kb) * Cb + Kr * (1 - Kr) * Cr) / (1 - Kr - Kb)
+ *	B = Y + K * (1 - Kb) * Cb
+ *
+ *	Y = Kr * R + (1 - Kr - Kb) * G + Kb * B
+ *
+ * With Kr = 0.299 and Kb = 0.114 (derived according to SMPTE RP 177-1993
+ * from the 1953 FCC NTSC primaries and CIE Illuminant C), K = 2 for sYCC,
+ * the conversion equations to be implemented are therefore
+ *
+ *	R = Y + 1.402 * Cr
+ *	G = Y - 0.344136286 * Cb - 0.714136286 * Cr
+ *	B = Y + 1.772 * Cb
+ *
+ *	Y = 0.299 * R + 0.587 * G + 0.114 * B
+ *
+ * where Cb and Cr represent the incoming values less CENTERJSAMPLE.
+ * For bg-sYCC, with K = 4, the equations are
+ *
+ *	R = Y + 2.804 * Cr
+ *	G = Y - 0.688272572 * Cb - 1.428272572 * Cr
+ *	B = Y + 3.544 * Cb
+ *
+ * To avoid floating-point arithmetic, we represent the fractional constants
+ * as integers scaled up by 2^16 (about 4 digits precision); we have to divide
+ * the products by 2^16, with appropriate rounding, to get the correct answer.
+ * Notice that Y, being an integral input, does not contribute any fraction
+ * so it need not participate in the rounding.
+ *
+ * For even more speed, we avoid doing any multiplications in the inner loop
+ * by precalculating the constants times Cb and Cr for all possible values.
+ * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
+ * for 9-bit to 12-bit samples it is still acceptable.  It's not very
+ * reasonable for 16-bit samples, but if you want lossless storage you
+ * shouldn't be changing colorspace anyway.
+ * The Cr=>R and Cb=>B values can be rounded to integers in advance; the
+ * values for the G calculation are left scaled up, since we must add them
+ * together before rounding.
+ */
+
+#define SCALEBITS	16	/* speediest right-shift on some machines */
+#define ONE_HALF	((INT32) 1 << (SCALEBITS-1))
+#define FIX(x)		((INT32) ((x) * (1L<Y conversion and divide it up into
+ * three parts, instead of doing three alloc_small requests.  This lets us
+ * use a single table base address, which can be held in a register in the
+ * inner loops on many machines (more than can hold all three addresses,
+ * anyway).
+ */
+
+#define R_Y_OFF		0			/* offset to R => Y section */
+#define G_Y_OFF		(1*(MAXJSAMPLE+1))	/* offset to G => Y section */
+#define B_Y_OFF		(2*(MAXJSAMPLE+1))	/* etc. */
+#define TABLE_SIZE	(3*(MAXJSAMPLE+1))
+
+
+/*
+ * Initialize tables for YCbCr->RGB and BG_YCC->RGB colorspace conversion.
+ */
+
+LOCAL(void)
+build_ycc_rgb_table (j_decompress_ptr cinfo)
+/* Normal case, sYCC */
+{
+  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+  int i;
+  INT32 x;
+  SHIFT_TEMPS
+
+  cconvert->Cr_r_tab = (int *)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				(MAXJSAMPLE+1) * SIZEOF(int));
+  cconvert->Cb_b_tab = (int *)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				(MAXJSAMPLE+1) * SIZEOF(int));
+  cconvert->Cr_g_tab = (INT32 *)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				(MAXJSAMPLE+1) * SIZEOF(INT32));
+  cconvert->Cb_g_tab = (INT32 *)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				(MAXJSAMPLE+1) * SIZEOF(INT32));
+
+  cconvert->range_limit = cinfo->sample_range_limit;
+
+  for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
+    /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
+    /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
+    /* Cr=>R value is nearest int to 1.402 * x */
+    cconvert->Cr_r_tab[i] = (int)
+		    RIGHT_SHIFT(FIX(1.402) * x + ONE_HALF, SCALEBITS);
+    /* Cb=>B value is nearest int to 1.772 * x */
+    cconvert->Cb_b_tab[i] = (int)
+		    RIGHT_SHIFT(FIX(1.772) * x + ONE_HALF, SCALEBITS);
+    /* Cr=>G value is scaled-up -0.714136286 * x */
+    cconvert->Cr_g_tab[i] = (- FIX(0.714136286)) * x;
+    /* Cb=>G value is scaled-up -0.344136286 * x */
+    /* We also add in ONE_HALF so that need not do it in inner loop */
+    cconvert->Cb_g_tab[i] = (- FIX(0.344136286)) * x + ONE_HALF;
+  }
+}
+
+
+LOCAL(void)
+build_bg_ycc_rgb_table (j_decompress_ptr cinfo)
+/* Wide gamut case, bg-sYCC */
+{
+  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+  int i;
+  INT32 x;
+  SHIFT_TEMPS
+
+  cconvert->Cr_r_tab = (int *)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				(MAXJSAMPLE+1) * SIZEOF(int));
+  cconvert->Cb_b_tab = (int *)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				(MAXJSAMPLE+1) * SIZEOF(int));
+  cconvert->Cr_g_tab = (INT32 *)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				(MAXJSAMPLE+1) * SIZEOF(INT32));
+  cconvert->Cb_g_tab = (INT32 *)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				(MAXJSAMPLE+1) * SIZEOF(INT32));
+
+  cconvert->range_limit = (JSAMPLE *)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				5 * (MAXJSAMPLE+1) * SIZEOF(JSAMPLE));
+
+  for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
+    /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
+    /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
+    /* Cr=>R value is nearest int to 2.804 * x */
+    cconvert->Cr_r_tab[i] = (int)
+		    RIGHT_SHIFT(FIX(2.804) * x + ONE_HALF, SCALEBITS);
+    /* Cb=>B value is nearest int to 3.544 * x */
+    cconvert->Cb_b_tab[i] = (int)
+		    RIGHT_SHIFT(FIX(3.544) * x + ONE_HALF, SCALEBITS);
+    /* Cr=>G value is scaled-up -1.428272572 * x */
+    cconvert->Cr_g_tab[i] = (- FIX(1.428272572)) * x;
+    /* Cb=>G value is scaled-up -0.688272572 * x */
+    /* We also add in ONE_HALF so that need not do it in inner loop */
+    cconvert->Cb_g_tab[i] = (- FIX(0.688272572)) * x + ONE_HALF;
+  }
+
+  /* Cb and Cr portions can extend to double range in wide gamut case,
+   * so we prepare an appropriate extended range limit table.
+   */
+
+  /* First segment of range limit table: limit[x] = 0 for x < 0 */
+  MEMZERO(cconvert->range_limit, 2 * (MAXJSAMPLE+1) * SIZEOF(JSAMPLE));
+  cconvert->range_limit += 2 * (MAXJSAMPLE+1);
+  /* Main part of range limit table: limit[x] = x */
+  for (i = 0; i <= MAXJSAMPLE; i++)
+    cconvert->range_limit[i] = (JSAMPLE) i;
+  /* End of range limit table: limit[x] = MAXJSAMPLE for x > MAXJSAMPLE */
+  for (; i < 3 * (MAXJSAMPLE+1); i++)
+    cconvert->range_limit[i] = MAXJSAMPLE;
+}
+
+
+/*
+ * Convert some rows of samples to the output colorspace.
+ *
+ * Note that we change from noninterleaved, one-plane-per-component format
+ * to interleaved-pixel format.  The output buffer is therefore three times
+ * as wide as the input buffer.
+ * A starting row offset is provided only for the input buffer.  The caller
+ * can easily adjust the passed output_buf value to accommodate any row
+ * offset required on that side.
+ */
+
+METHODDEF(void)
+ycc_rgb_convert (j_decompress_ptr cinfo,
+		 JSAMPIMAGE input_buf, JDIMENSION input_row,
+		 JSAMPARRAY output_buf, int num_rows)
+{
+  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+  register int y, cb, cr;
+  register JSAMPROW outptr;
+  register JSAMPROW inptr0, inptr1, inptr2;
+  register JDIMENSION col;
+  JDIMENSION num_cols = cinfo->output_width;
+  /* copy these pointers into registers if possible */
+  register JSAMPLE * range_limit = cconvert->range_limit;
+  register int * Crrtab = cconvert->Cr_r_tab;
+  register int * Cbbtab = cconvert->Cb_b_tab;
+  register INT32 * Crgtab = cconvert->Cr_g_tab;
+  register INT32 * Cbgtab = cconvert->Cb_g_tab;
+  SHIFT_TEMPS
+
+  while (--num_rows >= 0) {
+    inptr0 = input_buf[0][input_row];
+    inptr1 = input_buf[1][input_row];
+    inptr2 = input_buf[2][input_row];
+    input_row++;
+    outptr = *output_buf++;
+    for (col = 0; col < num_cols; col++) {
+      y  = GETJSAMPLE(inptr0[col]);
+      cb = GETJSAMPLE(inptr1[col]);
+      cr = GETJSAMPLE(inptr2[col]);
+      /* Range-limiting is essential due to noise introduced by DCT losses,
+       * for extended gamut (sYCC) and wide gamut (bg-sYCC) encodings.
+       */
+      outptr[RGB_RED]   = range_limit[y + Crrtab[cr]];
+      outptr[RGB_GREEN] = range_limit[y +
+			      ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
+						 SCALEBITS))];
+      outptr[RGB_BLUE]  = range_limit[y + Cbbtab[cb]];
+      outptr += RGB_PIXELSIZE;
+    }
+  }
+}
+
+
+/**************** Cases other than YCC -> RGB ****************/
+
+
+/*
+ * Initialize for RGB->grayscale colorspace conversion.
+ */
+
+LOCAL(void)
+build_rgb_y_table (j_decompress_ptr cinfo)
+{
+  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+  INT32 * rgb_y_tab;
+  INT32 i;
+
+  /* Allocate and fill in the conversion tables. */
+  cconvert->rgb_y_tab = rgb_y_tab = (INT32 *)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				(TABLE_SIZE * SIZEOF(INT32)));
+
+  for (i = 0; i <= MAXJSAMPLE; i++) {
+    rgb_y_tab[i+R_Y_OFF] = FIX(0.299) * i;
+    rgb_y_tab[i+G_Y_OFF] = FIX(0.587) * i;
+    rgb_y_tab[i+B_Y_OFF] = FIX(0.114) * i + ONE_HALF;
+  }
+}
+
+
+/*
+ * Convert RGB to grayscale.
+ */
+
+METHODDEF(void)
+rgb_gray_convert (j_decompress_ptr cinfo,
+		  JSAMPIMAGE input_buf, JDIMENSION input_row,
+		  JSAMPARRAY output_buf, int num_rows)
+{
+  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+  register INT32 * ctab = cconvert->rgb_y_tab;
+  register int r, g, b;
+  register JSAMPROW outptr;
+  register JSAMPROW inptr0, inptr1, inptr2;
+  register JDIMENSION col;
+  JDIMENSION num_cols = cinfo->output_width;
+
+  while (--num_rows >= 0) {
+    inptr0 = input_buf[0][input_row];
+    inptr1 = input_buf[1][input_row];
+    inptr2 = input_buf[2][input_row];
+    input_row++;
+    outptr = *output_buf++;
+    for (col = 0; col < num_cols; col++) {
+      r = GETJSAMPLE(inptr0[col]);
+      g = GETJSAMPLE(inptr1[col]);
+      b = GETJSAMPLE(inptr2[col]);
+      /* Y */
+      outptr[col] = (JSAMPLE)
+		((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
+		 >> SCALEBITS);
+    }
+  }
+}
+
+
+/*
+ * [R-G,G,B-G] to [R,G,B] conversion with modulo calculation
+ * (inverse color transform).
+ * This can be seen as an adaption of the general YCbCr->RGB
+ * conversion equation with Kr = Kb = 0, while replacing the
+ * normalization by modulo calculation.
+ */
+
+METHODDEF(void)
+rgb1_rgb_convert (j_decompress_ptr cinfo,
+		  JSAMPIMAGE input_buf, JDIMENSION input_row,
+		  JSAMPARRAY output_buf, int num_rows)
+{
+  register int r, g, b;
+  register JSAMPROW outptr;
+  register JSAMPROW inptr0, inptr1, inptr2;
+  register JDIMENSION col;
+  JDIMENSION num_cols = cinfo->output_width;
+
+  while (--num_rows >= 0) {
+    inptr0 = input_buf[0][input_row];
+    inptr1 = input_buf[1][input_row];
+    inptr2 = input_buf[2][input_row];
+    input_row++;
+    outptr = *output_buf++;
+    for (col = 0; col < num_cols; col++) {
+      r = GETJSAMPLE(inptr0[col]);
+      g = GETJSAMPLE(inptr1[col]);
+      b = GETJSAMPLE(inptr2[col]);
+      /* Assume that MAXJSAMPLE+1 is a power of 2, so that the MOD
+       * (modulo) operator is equivalent to the bitmask operator AND.
+       */
+      outptr[RGB_RED]   = (JSAMPLE) ((r + g - CENTERJSAMPLE) & MAXJSAMPLE);
+      outptr[RGB_GREEN] = (JSAMPLE) g;
+      outptr[RGB_BLUE]  = (JSAMPLE) ((b + g - CENTERJSAMPLE) & MAXJSAMPLE);
+      outptr += RGB_PIXELSIZE;
+    }
+  }
+}
+
+
+/*
+ * [R-G,G,B-G] to grayscale conversion with modulo calculation
+ * (inverse color transform).
+ */
+
+METHODDEF(void)
+rgb1_gray_convert (j_decompress_ptr cinfo,
+		   JSAMPIMAGE input_buf, JDIMENSION input_row,
+		   JSAMPARRAY output_buf, int num_rows)
+{
+  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+  register INT32 * ctab = cconvert->rgb_y_tab;
+  register int r, g, b;
+  register JSAMPROW outptr;
+  register JSAMPROW inptr0, inptr1, inptr2;
+  register JDIMENSION col;
+  JDIMENSION num_cols = cinfo->output_width;
+
+  while (--num_rows >= 0) {
+    inptr0 = input_buf[0][input_row];
+    inptr1 = input_buf[1][input_row];
+    inptr2 = input_buf[2][input_row];
+    input_row++;
+    outptr = *output_buf++;
+    for (col = 0; col < num_cols; col++) {
+      r = GETJSAMPLE(inptr0[col]);
+      g = GETJSAMPLE(inptr1[col]);
+      b = GETJSAMPLE(inptr2[col]);
+      /* Assume that MAXJSAMPLE+1 is a power of 2, so that the MOD
+       * (modulo) operator is equivalent to the bitmask operator AND.
+       */
+      r = (r + g - CENTERJSAMPLE) & MAXJSAMPLE;
+      b = (b + g - CENTERJSAMPLE) & MAXJSAMPLE;
+      /* Y */
+      outptr[col] = (JSAMPLE)
+		((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
+		 >> SCALEBITS);
+    }
+  }
+}
+
+
+/*
+ * No colorspace change, but conversion from separate-planes
+ * to interleaved representation.
+ */
+
+METHODDEF(void)
+rgb_convert (j_decompress_ptr cinfo,
+	     JSAMPIMAGE input_buf, JDIMENSION input_row,
+	     JSAMPARRAY output_buf, int num_rows)
+{
+  register JSAMPROW outptr;
+  register JSAMPROW inptr0, inptr1, inptr2;
+  register JDIMENSION col;
+  JDIMENSION num_cols = cinfo->output_width;
+
+  while (--num_rows >= 0) {
+    inptr0 = input_buf[0][input_row];
+    inptr1 = input_buf[1][input_row];
+    inptr2 = input_buf[2][input_row];
+    input_row++;
+    outptr = *output_buf++;
+    for (col = 0; col < num_cols; col++) {
+      /* We can dispense with GETJSAMPLE() here */
+      outptr[RGB_RED]   = inptr0[col];
+      outptr[RGB_GREEN] = inptr1[col];
+      outptr[RGB_BLUE]  = inptr2[col];
+      outptr += RGB_PIXELSIZE;
+    }
+  }
+}
+
+
+/*
+ * Color conversion for no colorspace change: just copy the data,
+ * converting from separate-planes to interleaved representation.
+ */
+
+METHODDEF(void)
+null_convert (j_decompress_ptr cinfo,
+	      JSAMPIMAGE input_buf, JDIMENSION input_row,
+	      JSAMPARRAY output_buf, int num_rows)
+{
+  int ci;
+  register int nc = cinfo->num_components;
+  register JSAMPROW outptr;
+  register JSAMPROW inptr;
+  register JDIMENSION col;
+  JDIMENSION num_cols = cinfo->output_width;
+
+  while (--num_rows >= 0) {
+    for (ci = 0; ci < nc; ci++) {
+      inptr = input_buf[ci][input_row];
+      outptr = output_buf[0] + ci;
+      for (col = 0; col < num_cols; col++) {
+	*outptr = *inptr++;	/* needn't bother with GETJSAMPLE() here */
+	outptr += nc;
+      }
+    }
+    input_row++;
+    output_buf++;
+  }
+}
+
+
+/*
+ * Color conversion for grayscale: just copy the data.
+ * This also works for YCC -> grayscale conversion, in which
+ * we just copy the Y (luminance) component and ignore chrominance.
+ */
+
+METHODDEF(void)
+grayscale_convert (j_decompress_ptr cinfo,
+		   JSAMPIMAGE input_buf, JDIMENSION input_row,
+		   JSAMPARRAY output_buf, int num_rows)
+{
+  jcopy_sample_rows(input_buf[0], (int) input_row, output_buf, 0,
+		    num_rows, cinfo->output_width);
+}
+
+
+/*
+ * Convert grayscale to RGB: just duplicate the graylevel three times.
+ * This is provided to support applications that don't want to cope
+ * with grayscale as a separate case.
+ */
+
+METHODDEF(void)
+gray_rgb_convert (j_decompress_ptr cinfo,
+		  JSAMPIMAGE input_buf, JDIMENSION input_row,
+		  JSAMPARRAY output_buf, int num_rows)
+{
+  register JSAMPROW outptr;
+  register JSAMPROW inptr;
+  register JDIMENSION col;
+  JDIMENSION num_cols = cinfo->output_width;
+
+  while (--num_rows >= 0) {
+    inptr = input_buf[0][input_row++];
+    outptr = *output_buf++;
+    for (col = 0; col < num_cols; col++) {
+      /* We can dispense with GETJSAMPLE() here */
+      outptr[RGB_RED] = outptr[RGB_GREEN] = outptr[RGB_BLUE] = inptr[col];
+      outptr += RGB_PIXELSIZE;
+    }
+  }
+}
+
+
+/*
+ * Adobe-style YCCK->CMYK conversion.
+ * We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same
+ * conversion as above, while passing K (black) unchanged.
+ * We assume build_ycc_rgb_table has been called.
+ */
+
+METHODDEF(void)
+ycck_cmyk_convert (j_decompress_ptr cinfo,
+		   JSAMPIMAGE input_buf, JDIMENSION input_row,
+		   JSAMPARRAY output_buf, int num_rows)
+{
+  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+  register int y, cb, cr;
+  register JSAMPROW outptr;
+  register JSAMPROW inptr0, inptr1, inptr2, inptr3;
+  register JDIMENSION col;
+  JDIMENSION num_cols = cinfo->output_width;
+  /* copy these pointers into registers if possible */
+  register JSAMPLE * range_limit = cinfo->sample_range_limit;
+  register int * Crrtab = cconvert->Cr_r_tab;
+  register int * Cbbtab = cconvert->Cb_b_tab;
+  register INT32 * Crgtab = cconvert->Cr_g_tab;
+  register INT32 * Cbgtab = cconvert->Cb_g_tab;
+  SHIFT_TEMPS
+
+  while (--num_rows >= 0) {
+    inptr0 = input_buf[0][input_row];
+    inptr1 = input_buf[1][input_row];
+    inptr2 = input_buf[2][input_row];
+    inptr3 = input_buf[3][input_row];
+    input_row++;
+    outptr = *output_buf++;
+    for (col = 0; col < num_cols; col++) {
+      y  = GETJSAMPLE(inptr0[col]);
+      cb = GETJSAMPLE(inptr1[col]);
+      cr = GETJSAMPLE(inptr2[col]);
+      /* Range-limiting is essential due to noise introduced by DCT losses,
+       * and for extended gamut encodings (sYCC).
+       */
+      outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])];	/* red */
+      outptr[1] = range_limit[MAXJSAMPLE - (y +			/* green */
+			      ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
+						 SCALEBITS)))];
+      outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])];	/* blue */
+      /* K passes through unchanged */
+      outptr[3] = inptr3[col];	/* don't need GETJSAMPLE here */
+      outptr += 4;
+    }
+  }
+}
+
+
+/*
+ * Empty method for start_pass.
+ */
+
+METHODDEF(void)
+start_pass_dcolor (j_decompress_ptr cinfo)
+{
+  /* no work needed */
+}
+
+
+/*
+ * Module initialization routine for output colorspace conversion.
+ */
+
+GLOBAL(void)
+jinit_color_deconverter (j_decompress_ptr cinfo)
+{
+  my_cconvert_ptr cconvert;
+  int ci;
+
+  cconvert = (my_cconvert_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(my_color_deconverter));
+  cinfo->cconvert = &cconvert->pub;
+  cconvert->pub.start_pass = start_pass_dcolor;
+
+  /* Make sure num_components agrees with jpeg_color_space */
+  switch (cinfo->jpeg_color_space) {
+  case JCS_GRAYSCALE:
+    if (cinfo->num_components != 1)
+      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+    break;
+
+  case JCS_RGB:
+  case JCS_YCbCr:
+  case JCS_BG_RGB:
+  case JCS_BG_YCC:
+    if (cinfo->num_components != 3)
+      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+    break;
+
+  case JCS_CMYK:
+  case JCS_YCCK:
+    if (cinfo->num_components != 4)
+      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+    break;
+
+  default:			/* JCS_UNKNOWN can be anything */
+    if (cinfo->num_components < 1)
+      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+    break;
+  }
+
+  /* Support color transform only for RGB colorspaces */
+  if (cinfo->color_transform &&
+      cinfo->jpeg_color_space != JCS_RGB &&
+      cinfo->jpeg_color_space != JCS_BG_RGB)
+    ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+
+  /* Set out_color_components and conversion method based on requested space.
+   * Also clear the component_needed flags for any unused components,
+   * so that earlier pipeline stages can avoid useless computation.
+   */
+
+  switch (cinfo->out_color_space) {
+  case JCS_GRAYSCALE:
+    cinfo->out_color_components = 1;
+    switch (cinfo->jpeg_color_space) {
+    case JCS_GRAYSCALE:
+    case JCS_YCbCr:
+    case JCS_BG_YCC:
+      cconvert->pub.color_convert = grayscale_convert;
+      /* For color->grayscale conversion, only the Y (0) component is needed */
+      for (ci = 1; ci < cinfo->num_components; ci++)
+	cinfo->comp_info[ci].component_needed = FALSE;
+      break;
+    case JCS_RGB:
+      switch (cinfo->color_transform) {
+      case JCT_NONE:
+	cconvert->pub.color_convert = rgb_gray_convert;
+	break;
+      case JCT_SUBTRACT_GREEN:
+	cconvert->pub.color_convert = rgb1_gray_convert;
+	break;
+      default:
+	ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+      }
+      build_rgb_y_table(cinfo);
+      break;
+    default:
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+    }
+    break;
+
+  case JCS_RGB:
+    cinfo->out_color_components = RGB_PIXELSIZE;
+    switch (cinfo->jpeg_color_space) {
+    case JCS_GRAYSCALE:
+      cconvert->pub.color_convert = gray_rgb_convert;
+      break;
+    case JCS_YCbCr:
+      cconvert->pub.color_convert = ycc_rgb_convert;
+      build_ycc_rgb_table(cinfo);
+      break;
+    case JCS_BG_YCC:
+      cconvert->pub.color_convert = ycc_rgb_convert;
+      build_bg_ycc_rgb_table(cinfo);
+      break;
+    case JCS_RGB:
+      switch (cinfo->color_transform) {
+      case JCT_NONE:
+	cconvert->pub.color_convert = rgb_convert;
+	break;
+      case JCT_SUBTRACT_GREEN:
+	cconvert->pub.color_convert = rgb1_rgb_convert;
+	break;
+      default:
+	ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+      }
+      break;
+    default:
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+    }
+    break;
+
+  case JCS_BG_RGB:
+    cinfo->out_color_components = RGB_PIXELSIZE;
+    if (cinfo->jpeg_color_space == JCS_BG_RGB) {
+      switch (cinfo->color_transform) {
+      case JCT_NONE:
+	cconvert->pub.color_convert = rgb_convert;
+	break;
+      case JCT_SUBTRACT_GREEN:
+	cconvert->pub.color_convert = rgb1_rgb_convert;
+	break;
+      default:
+	ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+      }
+    } else
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+    break;
+
+  case JCS_CMYK:
+    cinfo->out_color_components = 4;
+    switch (cinfo->jpeg_color_space) {
+    case JCS_YCCK:
+      cconvert->pub.color_convert = ycck_cmyk_convert;
+      build_ycc_rgb_table(cinfo);
+      break;
+    case JCS_CMYK:
+      cconvert->pub.color_convert = null_convert;
+      break;
+    default:
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+    }
+    break;
+
+  default:
+    /* Permit null conversion to same output space */
+    if (cinfo->out_color_space == cinfo->jpeg_color_space) {
+      cinfo->out_color_components = cinfo->num_components;
+      cconvert->pub.color_convert = null_convert;
+    } else			/* unsupported non-null conversion */
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+    break;
+  }
+
+  if (cinfo->quantize_colors)
+    cinfo->output_components = 1; /* single colormapped output component */
+  else
+    cinfo->output_components = cinfo->out_color_components;
+}
diff --git a/source/Irrlicht/jpeglib/jdct.h b/source/Irrlicht/jpeglib/jdct.h
new file mode 100644
index 00000000..b1ff9125
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jdct.h
@@ -0,0 +1,393 @@
+/*
+ * jdct.h
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This include file contains common declarations for the forward and
+ * inverse DCT modules.  These declarations are private to the DCT managers
+ * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms.
+ * The individual DCT algorithms are kept in separate files to ease 
+ * machine-dependent tuning (e.g., assembly coding).
+ */
+
+
+/*
+ * A forward DCT routine is given a pointer to an input sample array and
+ * a pointer to a work area of type DCTELEM[]; the DCT is to be performed
+ * in-place in that buffer.  Type DCTELEM is int for 8-bit samples, INT32
+ * for 12-bit samples.  (NOTE: Floating-point DCT implementations use an
+ * array of type FAST_FLOAT, instead.)
+ * The input data is to be fetched from the sample array starting at a
+ * specified column.  (Any row offset needed will be applied to the array
+ * pointer before it is passed to the FDCT code.)
+ * Note that the number of samples fetched by the FDCT routine is
+ * DCT_h_scaled_size * DCT_v_scaled_size.
+ * The DCT outputs are returned scaled up by a factor of 8; they therefore
+ * have a range of +-8K for 8-bit data, +-128K for 12-bit data.  This
+ * convention improves accuracy in integer implementations and saves some
+ * work in floating-point ones.
+ * Quantization of the output coefficients is done by jcdctmgr.c.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+typedef int DCTELEM;		/* 16 or 32 bits is fine */
+#else
+typedef INT32 DCTELEM;		/* must have 32 bits */
+#endif
+
+typedef JMETHOD(void, forward_DCT_method_ptr, (DCTELEM * data,
+					       JSAMPARRAY sample_data,
+					       JDIMENSION start_col));
+typedef JMETHOD(void, float_DCT_method_ptr, (FAST_FLOAT * data,
+					     JSAMPARRAY sample_data,
+					     JDIMENSION start_col));
+
+
+/*
+ * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer
+ * to an output sample array.  The routine must dequantize the input data as
+ * well as perform the IDCT; for dequantization, it uses the multiplier table
+ * pointed to by compptr->dct_table.  The output data is to be placed into the
+ * sample array starting at a specified column.  (Any row offset needed will
+ * be applied to the array pointer before it is passed to the IDCT code.)
+ * Note that the number of samples emitted by the IDCT routine is
+ * DCT_h_scaled_size * DCT_v_scaled_size.
+ */
+
+/* typedef inverse_DCT_method_ptr is declared in jpegint.h */
+
+/*
+ * Each IDCT routine has its own ideas about the best dct_table element type.
+ */
+
+typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */
+#if BITS_IN_JSAMPLE == 8
+typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */
+#define IFAST_SCALE_BITS  2	/* fractional bits in scale factors */
+#else
+typedef INT32 IFAST_MULT_TYPE;	/* need 32 bits for scaled quantizers */
+#define IFAST_SCALE_BITS  13	/* fractional bits in scale factors */
+#endif
+typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */
+
+
+/*
+ * Each IDCT routine is responsible for range-limiting its results and
+ * converting them to unsigned form (0..MAXJSAMPLE).  The raw outputs could
+ * be quite far out of range if the input data is corrupt, so a bulletproof
+ * range-limiting step is required.  We use a mask-and-table-lookup method
+ * to do the combined operations quickly.  See the comments with
+ * prepare_range_limit_table (in jdmaster.c) for more info.
+ */
+
+#define IDCT_range_limit(cinfo)  ((cinfo)->sample_range_limit + CENTERJSAMPLE)
+
+#define RANGE_MASK  (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */
+
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jpeg_fdct_islow		jFDislow
+#define jpeg_fdct_ifast		jFDifast
+#define jpeg_fdct_float		jFDfloat
+#define jpeg_fdct_7x7		jFD7x7
+#define jpeg_fdct_6x6		jFD6x6
+#define jpeg_fdct_5x5		jFD5x5
+#define jpeg_fdct_4x4		jFD4x4
+#define jpeg_fdct_3x3		jFD3x3
+#define jpeg_fdct_2x2		jFD2x2
+#define jpeg_fdct_1x1		jFD1x1
+#define jpeg_fdct_9x9		jFD9x9
+#define jpeg_fdct_10x10		jFD10x10
+#define jpeg_fdct_11x11		jFD11x11
+#define jpeg_fdct_12x12		jFD12x12
+#define jpeg_fdct_13x13		jFD13x13
+#define jpeg_fdct_14x14		jFD14x14
+#define jpeg_fdct_15x15		jFD15x15
+#define jpeg_fdct_16x16		jFD16x16
+#define jpeg_fdct_16x8		jFD16x8
+#define jpeg_fdct_14x7		jFD14x7
+#define jpeg_fdct_12x6		jFD12x6
+#define jpeg_fdct_10x5		jFD10x5
+#define jpeg_fdct_8x4		jFD8x4
+#define jpeg_fdct_6x3		jFD6x3
+#define jpeg_fdct_4x2		jFD4x2
+#define jpeg_fdct_2x1		jFD2x1
+#define jpeg_fdct_8x16		jFD8x16
+#define jpeg_fdct_7x14		jFD7x14
+#define jpeg_fdct_6x12		jFD6x12
+#define jpeg_fdct_5x10		jFD5x10
+#define jpeg_fdct_4x8		jFD4x8
+#define jpeg_fdct_3x6		jFD3x6
+#define jpeg_fdct_2x4		jFD2x4
+#define jpeg_fdct_1x2		jFD1x2
+#define jpeg_idct_islow		jRDislow
+#define jpeg_idct_ifast		jRDifast
+#define jpeg_idct_float		jRDfloat
+#define jpeg_idct_7x7		jRD7x7
+#define jpeg_idct_6x6		jRD6x6
+#define jpeg_idct_5x5		jRD5x5
+#define jpeg_idct_4x4		jRD4x4
+#define jpeg_idct_3x3		jRD3x3
+#define jpeg_idct_2x2		jRD2x2
+#define jpeg_idct_1x1		jRD1x1
+#define jpeg_idct_9x9		jRD9x9
+#define jpeg_idct_10x10		jRD10x10
+#define jpeg_idct_11x11		jRD11x11
+#define jpeg_idct_12x12		jRD12x12
+#define jpeg_idct_13x13		jRD13x13
+#define jpeg_idct_14x14		jRD14x14
+#define jpeg_idct_15x15		jRD15x15
+#define jpeg_idct_16x16		jRD16x16
+#define jpeg_idct_16x8		jRD16x8
+#define jpeg_idct_14x7		jRD14x7
+#define jpeg_idct_12x6		jRD12x6
+#define jpeg_idct_10x5		jRD10x5
+#define jpeg_idct_8x4		jRD8x4
+#define jpeg_idct_6x3		jRD6x3
+#define jpeg_idct_4x2		jRD4x2
+#define jpeg_idct_2x1		jRD2x1
+#define jpeg_idct_8x16		jRD8x16
+#define jpeg_idct_7x14		jRD7x14
+#define jpeg_idct_6x12		jRD6x12
+#define jpeg_idct_5x10		jRD5x10
+#define jpeg_idct_4x8		jRD4x8
+#define jpeg_idct_3x6		jRD3x8
+#define jpeg_idct_2x4		jRD2x4
+#define jpeg_idct_1x2		jRD1x2
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+/* Extern declarations for the forward and inverse DCT routines. */
+
+EXTERN(void) jpeg_fdct_islow
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_ifast
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_float
+    JPP((FAST_FLOAT * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_7x7
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_6x6
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_5x5
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_4x4
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_3x3
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_2x2
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_1x1
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_9x9
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_10x10
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_11x11
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_12x12
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_13x13
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_14x14
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_15x15
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_16x16
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_16x8
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_14x7
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_12x6
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_10x5
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_8x4
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_6x3
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_4x2
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_2x1
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_8x16
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_7x14
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_6x12
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_5x10
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_4x8
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_3x6
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_2x4
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_1x2
+    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+
+EXTERN(void) jpeg_idct_islow
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_ifast
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_float
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_7x7
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_6x6
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_5x5
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_4x4
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_3x3
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_2x2
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_1x1
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_9x9
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_10x10
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_11x11
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_12x12
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_13x13
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_14x14
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_15x15
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_16x16
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_16x8
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_14x7
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_12x6
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_10x5
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_8x4
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_6x3
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_4x2
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_2x1
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_8x16
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_7x14
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_6x12
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_5x10
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_4x8
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_3x6
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_2x4
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_1x2
+    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	 JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+
+
+/*
+ * Macros for handling fixed-point arithmetic; these are used by many
+ * but not all of the DCT/IDCT modules.
+ *
+ * All values are expected to be of type INT32.
+ * Fractional constants are scaled left by CONST_BITS bits.
+ * CONST_BITS is defined within each module using these macros,
+ * and may differ from one module to the next.
+ */
+
+#define ONE	((INT32) 1)
+#define CONST_SCALE (ONE << CONST_BITS)
+
+/* Convert a positive real constant to an integer scaled by CONST_SCALE.
+ * Caution: some C compilers fail to reduce "FIX(constant)" at compile time,
+ * thus causing a lot of useless floating-point operations at run time.
+ */
+
+#define FIX(x)	((INT32) ((x) * CONST_SCALE + 0.5))
+
+/* Descale and correctly round an INT32 value that's scaled by N bits.
+ * We assume RIGHT_SHIFT rounds towards minus infinity, so adding
+ * the fudge factor is correct for either sign of X.
+ */
+
+#define DESCALE(x,n)  RIGHT_SHIFT((x) + (ONE << ((n)-1)), n)
+
+/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
+ * This macro is used only when the two inputs will actually be no more than
+ * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a
+ * full 32x32 multiply.  This provides a useful speedup on many machines.
+ * Unfortunately there is no way to specify a 16x16->32 multiply portably
+ * in C, but some C compilers will do the right thing if you provide the
+ * correct combination of casts.
+ */
+
+#ifdef SHORTxSHORT_32		/* may work if 'int' is 32 bits */
+#define MULTIPLY16C16(var,const)  (((INT16) (var)) * ((INT16) (const)))
+#endif
+#ifdef SHORTxLCONST_32		/* known to work with Microsoft C 6.0 */
+#define MULTIPLY16C16(var,const)  (((INT16) (var)) * ((INT32) (const)))
+#endif
+
+#ifndef MULTIPLY16C16		/* default definition */
+#define MULTIPLY16C16(var,const)  ((var) * (const))
+#endif
+
+/* Same except both inputs are variables. */
+
+#ifdef SHORTxSHORT_32		/* may work if 'int' is 32 bits */
+#define MULTIPLY16V16(var1,var2)  (((INT16) (var1)) * ((INT16) (var2)))
+#endif
+
+#ifndef MULTIPLY16V16		/* default definition */
+#define MULTIPLY16V16(var1,var2)  ((var1) * (var2))
+#endif
diff --git a/source/Irrlicht/jpeglib/jddctmgr.c b/source/Irrlicht/jpeglib/jddctmgr.c
new file mode 100644
index 00000000..b2f5a36d
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jddctmgr.c
@@ -0,0 +1,384 @@
+/*
+ * jddctmgr.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2002-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the inverse-DCT management logic.
+ * This code selects a particular IDCT implementation to be used,
+ * and it performs related housekeeping chores.  No code in this file
+ * is executed per IDCT step, only during output pass setup.
+ *
+ * Note that the IDCT routines are responsible for performing coefficient
+ * dequantization as well as the IDCT proper.  This module sets up the
+ * dequantization multiplier table needed by the IDCT routine.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h"		/* Private declarations for DCT subsystem */
+
+
+/*
+ * The decompressor input side (jdinput.c) saves away the appropriate
+ * quantization table for each component at the start of the first scan
+ * involving that component.  (This is necessary in order to correctly
+ * decode files that reuse Q-table slots.)
+ * When we are ready to make an output pass, the saved Q-table is converted
+ * to a multiplier table that will actually be used by the IDCT routine.
+ * The multiplier table contents are IDCT-method-dependent.  To support
+ * application changes in IDCT method between scans, we can remake the
+ * multiplier tables if necessary.
+ * In buffered-image mode, the first output pass may occur before any data
+ * has been seen for some components, and thus before their Q-tables have
+ * been saved away.  To handle this case, multiplier tables are preset
+ * to zeroes; the result of the IDCT will be a neutral gray level.
+ */
+
+
+/* Private subobject for this module */
+
+typedef struct {
+  struct jpeg_inverse_dct pub;	/* public fields */
+
+  /* This array contains the IDCT method code that each multiplier table
+   * is currently set up for, or -1 if it's not yet set up.
+   * The actual multiplier tables are pointed to by dct_table in the
+   * per-component comp_info structures.
+   */
+  int cur_method[MAX_COMPONENTS];
+} my_idct_controller;
+
+typedef my_idct_controller * my_idct_ptr;
+
+
+/* Allocated multiplier tables: big enough for any supported variant */
+
+typedef union {
+  ISLOW_MULT_TYPE islow_array[DCTSIZE2];
+#ifdef DCT_IFAST_SUPPORTED
+  IFAST_MULT_TYPE ifast_array[DCTSIZE2];
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+  FLOAT_MULT_TYPE float_array[DCTSIZE2];
+#endif
+} multiplier_table;
+
+
+/* The current scaled-IDCT routines require ISLOW-style multiplier tables,
+ * so be sure to compile that code if either ISLOW or SCALING is requested.
+ */
+#ifdef DCT_ISLOW_SUPPORTED
+#define PROVIDE_ISLOW_TABLES
+#else
+#ifdef IDCT_SCALING_SUPPORTED
+#define PROVIDE_ISLOW_TABLES
+#endif
+#endif
+
+
+/*
+ * Prepare for an output pass.
+ * Here we select the proper IDCT routine for each component and build
+ * a matching multiplier table.
+ */
+
+METHODDEF(void)
+start_pass (j_decompress_ptr cinfo)
+{
+  my_idct_ptr idct = (my_idct_ptr) cinfo->idct;
+  int ci, i;
+  jpeg_component_info *compptr;
+  int method = 0;
+  inverse_DCT_method_ptr method_ptr = NULL;
+  JQUANT_TBL * qtbl;
+
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    /* Select the proper IDCT routine for this component's scaling */
+    switch ((compptr->DCT_h_scaled_size << 8) + compptr->DCT_v_scaled_size) {
+#ifdef IDCT_SCALING_SUPPORTED
+    case ((1 << 8) + 1):
+      method_ptr = jpeg_idct_1x1;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((2 << 8) + 2):
+      method_ptr = jpeg_idct_2x2;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((3 << 8) + 3):
+      method_ptr = jpeg_idct_3x3;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((4 << 8) + 4):
+      method_ptr = jpeg_idct_4x4;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((5 << 8) + 5):
+      method_ptr = jpeg_idct_5x5;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((6 << 8) + 6):
+      method_ptr = jpeg_idct_6x6;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((7 << 8) + 7):
+      method_ptr = jpeg_idct_7x7;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((9 << 8) + 9):
+      method_ptr = jpeg_idct_9x9;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((10 << 8) + 10):
+      method_ptr = jpeg_idct_10x10;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((11 << 8) + 11):
+      method_ptr = jpeg_idct_11x11;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((12 << 8) + 12):
+      method_ptr = jpeg_idct_12x12;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((13 << 8) + 13):
+      method_ptr = jpeg_idct_13x13;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((14 << 8) + 14):
+      method_ptr = jpeg_idct_14x14;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((15 << 8) + 15):
+      method_ptr = jpeg_idct_15x15;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((16 << 8) + 16):
+      method_ptr = jpeg_idct_16x16;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((16 << 8) + 8):
+      method_ptr = jpeg_idct_16x8;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((14 << 8) + 7):
+      method_ptr = jpeg_idct_14x7;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((12 << 8) + 6):
+      method_ptr = jpeg_idct_12x6;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((10 << 8) + 5):
+      method_ptr = jpeg_idct_10x5;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((8 << 8) + 4):
+      method_ptr = jpeg_idct_8x4;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((6 << 8) + 3):
+      method_ptr = jpeg_idct_6x3;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((4 << 8) + 2):
+      method_ptr = jpeg_idct_4x2;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((2 << 8) + 1):
+      method_ptr = jpeg_idct_2x1;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((8 << 8) + 16):
+      method_ptr = jpeg_idct_8x16;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((7 << 8) + 14):
+      method_ptr = jpeg_idct_7x14;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((6 << 8) + 12):
+      method_ptr = jpeg_idct_6x12;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((5 << 8) + 10):
+      method_ptr = jpeg_idct_5x10;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((4 << 8) + 8):
+      method_ptr = jpeg_idct_4x8;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((3 << 8) + 6):
+      method_ptr = jpeg_idct_3x6;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((2 << 8) + 4):
+      method_ptr = jpeg_idct_2x4;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+    case ((1 << 8) + 2):
+      method_ptr = jpeg_idct_1x2;
+      method = JDCT_ISLOW;	/* jidctint uses islow-style table */
+      break;
+#endif
+    case ((DCTSIZE << 8) + DCTSIZE):
+      switch (cinfo->dct_method) {
+#ifdef DCT_ISLOW_SUPPORTED
+      case JDCT_ISLOW:
+	method_ptr = jpeg_idct_islow;
+	method = JDCT_ISLOW;
+	break;
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+      case JDCT_IFAST:
+	method_ptr = jpeg_idct_ifast;
+	method = JDCT_IFAST;
+	break;
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+      case JDCT_FLOAT:
+	method_ptr = jpeg_idct_float;
+	method = JDCT_FLOAT;
+	break;
+#endif
+      default:
+	ERREXIT(cinfo, JERR_NOT_COMPILED);
+	break;
+      }
+      break;
+    default:
+      ERREXIT2(cinfo, JERR_BAD_DCTSIZE,
+	       compptr->DCT_h_scaled_size, compptr->DCT_v_scaled_size);
+      break;
+    }
+    idct->pub.inverse_DCT[ci] = method_ptr;
+    /* Create multiplier table from quant table.
+     * However, we can skip this if the component is uninteresting
+     * or if we already built the table.  Also, if no quant table
+     * has yet been saved for the component, we leave the
+     * multiplier table all-zero; we'll be reading zeroes from the
+     * coefficient controller's buffer anyway.
+     */
+    if (! compptr->component_needed || idct->cur_method[ci] == method)
+      continue;
+    qtbl = compptr->quant_table;
+    if (qtbl == NULL)		/* happens if no data yet for component */
+      continue;
+    idct->cur_method[ci] = method;
+    switch (method) {
+#ifdef PROVIDE_ISLOW_TABLES
+    case JDCT_ISLOW:
+      {
+	/* For LL&M IDCT method, multipliers are equal to raw quantization
+	 * coefficients, but are stored as ints to ensure access efficiency.
+	 */
+	ISLOW_MULT_TYPE * ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table;
+	for (i = 0; i < DCTSIZE2; i++) {
+	  ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[i];
+	}
+      }
+      break;
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+    case JDCT_IFAST:
+      {
+	/* For AA&N IDCT method, multipliers are equal to quantization
+	 * coefficients scaled by scalefactor[row]*scalefactor[col], where
+	 *   scalefactor[0] = 1
+	 *   scalefactor[k] = cos(k*PI/16) * sqrt(2)    for k=1..7
+	 * For integer operation, the multiplier table is to be scaled by
+	 * IFAST_SCALE_BITS.
+	 */
+	IFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table;
+#define CONST_BITS 14
+	static const INT16 aanscales[DCTSIZE2] = {
+	  /* precomputed values scaled up by 14 bits */
+	  16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,
+	  22725, 31521, 29692, 26722, 22725, 17855, 12299,  6270,
+	  21407, 29692, 27969, 25172, 21407, 16819, 11585,  5906,
+	  19266, 26722, 25172, 22654, 19266, 15137, 10426,  5315,
+	  16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,
+	  12873, 17855, 16819, 15137, 12873, 10114,  6967,  3552,
+	   8867, 12299, 11585, 10426,  8867,  6967,  4799,  2446,
+	   4520,  6270,  5906,  5315,  4520,  3552,  2446,  1247
+	};
+	SHIFT_TEMPS
+
+	for (i = 0; i < DCTSIZE2; i++) {
+	  ifmtbl[i] = (IFAST_MULT_TYPE)
+	    DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],
+				  (INT32) aanscales[i]),
+		    CONST_BITS-IFAST_SCALE_BITS);
+	}
+      }
+      break;
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+    case JDCT_FLOAT:
+      {
+	/* For float AA&N IDCT method, multipliers are equal to quantization
+	 * coefficients scaled by scalefactor[row]*scalefactor[col], where
+	 *   scalefactor[0] = 1
+	 *   scalefactor[k] = cos(k*PI/16) * sqrt(2)    for k=1..7
+	 * We apply a further scale factor of 1/8.
+	 */
+	FLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table;
+	int row, col;
+	static const double aanscalefactor[DCTSIZE] = {
+	  1.0, 1.387039845, 1.306562965, 1.175875602,
+	  1.0, 0.785694958, 0.541196100, 0.275899379
+	};
+
+	i = 0;
+	for (row = 0; row < DCTSIZE; row++) {
+	  for (col = 0; col < DCTSIZE; col++) {
+	    fmtbl[i] = (FLOAT_MULT_TYPE)
+	      ((double) qtbl->quantval[i] *
+	       aanscalefactor[row] * aanscalefactor[col] * 0.125);
+	    i++;
+	  }
+	}
+      }
+      break;
+#endif
+    default:
+      ERREXIT(cinfo, JERR_NOT_COMPILED);
+      break;
+    }
+  }
+}
+
+
+/*
+ * Initialize IDCT manager.
+ */
+
+GLOBAL(void)
+jinit_inverse_dct (j_decompress_ptr cinfo)
+{
+  my_idct_ptr idct;
+  int ci;
+  jpeg_component_info *compptr;
+
+  idct = (my_idct_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(my_idct_controller));
+  cinfo->idct = &idct->pub;
+  idct->pub.start_pass = start_pass;
+
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    /* Allocate and pre-zero a multiplier table for each component */
+    compptr->dct_table =
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  SIZEOF(multiplier_table));
+    MEMZERO(compptr->dct_table, SIZEOF(multiplier_table));
+    /* Mark multiplier table not yet set up for any method */
+    idct->cur_method[ci] = -1;
+  }
+}
diff --git a/source/Irrlicht/jpeglib/jdhuff.c b/source/Irrlicht/jpeglib/jdhuff.c
new file mode 100644
index 00000000..85a98bd3
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jdhuff.c
@@ -0,0 +1,1554 @@
+/*
+ * jdhuff.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2006-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains Huffman entropy decoding routines.
+ * Both sequential and progressive modes are supported in this single module.
+ *
+ * Much of the complexity here has to do with supporting input suspension.
+ * If the data source module demands suspension, we want to be able to back
+ * up to the start of the current MCU.  To do this, we copy state variables
+ * into local working storage, and update them back to the permanent
+ * storage only upon successful completion of an MCU.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Derived data constructed for each Huffman table */
+
+#define HUFF_LOOKAHEAD	8	/* # of bits of lookahead */
+
+typedef struct {
+  /* Basic tables: (element [0] of each array is unused) */
+  INT32 maxcode[18];		/* largest code of length k (-1 if none) */
+  /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */
+  INT32 valoffset[17];		/* huffval[] offset for codes of length k */
+  /* valoffset[k] = huffval[] index of 1st symbol of code length k, less
+   * the smallest code of length k; so given a code of length k, the
+   * corresponding symbol is huffval[code + valoffset[k]]
+   */
+
+  /* Link to public Huffman table (needed only in jpeg_huff_decode) */
+  JHUFF_TBL *pub;
+
+  /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of
+   * the input data stream.  If the next Huffman code is no more
+   * than HUFF_LOOKAHEAD bits long, we can obtain its length and
+   * the corresponding symbol directly from these tables.
+   */
+  int look_nbits[1< 32 bits on your machine, and shifting/masking longs is
+ * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE
+ * appropriately should be a win.  Unfortunately we can't define the size
+ * with something like  #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8)
+ * because not all machines measure sizeof in 8-bit bytes.
+ */
+
+typedef struct {		/* Bitreading state saved across MCUs */
+  bit_buf_type get_buffer;	/* current bit-extraction buffer */
+  int bits_left;		/* # of unused bits in it */
+} bitread_perm_state;
+
+typedef struct {		/* Bitreading working state within an MCU */
+  /* Current data source location */
+  /* We need a copy, rather than munging the original, in case of suspension */
+  const JOCTET * next_input_byte; /* => next byte to read from source */
+  size_t bytes_in_buffer;	/* # of bytes remaining in source buffer */
+  /* Bit input buffer --- note these values are kept in register variables,
+   * not in this struct, inside the inner loops.
+   */
+  bit_buf_type get_buffer;	/* current bit-extraction buffer */
+  int bits_left;		/* # of unused bits in it */
+  /* Pointer needed by jpeg_fill_bit_buffer. */
+  j_decompress_ptr cinfo;	/* back link to decompress master record */
+} bitread_working_state;
+
+/* Macros to declare and load/save bitread local variables. */
+#define BITREAD_STATE_VARS  \
+	register bit_buf_type get_buffer;  \
+	register int bits_left;  \
+	bitread_working_state br_state
+
+#define BITREAD_LOAD_STATE(cinfop,permstate)  \
+	br_state.cinfo = cinfop; \
+	br_state.next_input_byte = cinfop->src->next_input_byte; \
+	br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \
+	get_buffer = permstate.get_buffer; \
+	bits_left = permstate.bits_left;
+
+#define BITREAD_SAVE_STATE(cinfop,permstate)  \
+	cinfop->src->next_input_byte = br_state.next_input_byte; \
+	cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \
+	permstate.get_buffer = get_buffer; \
+	permstate.bits_left = bits_left
+
+/*
+ * These macros provide the in-line portion of bit fetching.
+ * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer
+ * before using GET_BITS, PEEK_BITS, or DROP_BITS.
+ * The variables get_buffer and bits_left are assumed to be locals,
+ * but the state struct might not be (jpeg_huff_decode needs this).
+ *	CHECK_BIT_BUFFER(state,n,action);
+ *		Ensure there are N bits in get_buffer; if suspend, take action.
+ *      val = GET_BITS(n);
+ *		Fetch next N bits.
+ *      val = PEEK_BITS(n);
+ *		Fetch next N bits without removing them from the buffer.
+ *	DROP_BITS(n);
+ *		Discard next N bits.
+ * The value N should be a simple variable, not an expression, because it
+ * is evaluated multiple times.
+ */
+
+#define CHECK_BIT_BUFFER(state,nbits,action) \
+	{ if (bits_left < (nbits)) {  \
+	    if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits))  \
+	      { action; }  \
+	    get_buffer = (state).get_buffer; bits_left = (state).bits_left; } }
+
+#define GET_BITS(nbits) \
+	(((int) (get_buffer >> (bits_left -= (nbits)))) & BIT_MASK(nbits))
+
+#define PEEK_BITS(nbits) \
+	(((int) (get_buffer >> (bits_left -  (nbits)))) & BIT_MASK(nbits))
+
+#define DROP_BITS(nbits) \
+	(bits_left -= (nbits))
+
+
+/*
+ * Code for extracting next Huffman-coded symbol from input bit stream.
+ * Again, this is time-critical and we make the main paths be macros.
+ *
+ * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits
+ * without looping.  Usually, more than 95% of the Huffman codes will be 8
+ * or fewer bits long.  The few overlength codes are handled with a loop,
+ * which need not be inline code.
+ *
+ * Notes about the HUFF_DECODE macro:
+ * 1. Near the end of the data segment, we may fail to get enough bits
+ *    for a lookahead.  In that case, we do it the hard way.
+ * 2. If the lookahead table contains no entry, the next code must be
+ *    more than HUFF_LOOKAHEAD bits long.
+ * 3. jpeg_huff_decode returns -1 if forced to suspend.
+ */
+
+#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \
+{ register int nb, look; \
+  if (bits_left < HUFF_LOOKAHEAD) { \
+    if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \
+    get_buffer = state.get_buffer; bits_left = state.bits_left; \
+    if (bits_left < HUFF_LOOKAHEAD) { \
+      nb = 1; goto slowlabel; \
+    } \
+  } \
+  look = PEEK_BITS(HUFF_LOOKAHEAD); \
+  if ((nb = htbl->look_nbits[look]) != 0) { \
+    DROP_BITS(nb); \
+    result = htbl->look_sym[look]; \
+  } else { \
+    nb = HUFF_LOOKAHEAD+1; \
+slowlabel: \
+    if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \
+	{ failaction; } \
+    get_buffer = state.get_buffer; bits_left = state.bits_left; \
+  } \
+}
+
+
+/*
+ * Expanded entropy decoder object for Huffman decoding.
+ *
+ * The savable_state subrecord contains fields that change within an MCU,
+ * but must not be updated permanently until we complete the MCU.
+ */
+
+typedef struct {
+  unsigned int EOBRUN;			/* remaining EOBs in EOBRUN */
+  int last_dc_val[MAX_COMPS_IN_SCAN];	/* last DC coef for each component */
+} savable_state;
+
+/* This macro is to work around compilers with missing or broken
+ * structure assignment.  You'll need to fix this code if you have
+ * such a compiler and you change MAX_COMPS_IN_SCAN.
+ */
+
+#ifndef NO_STRUCT_ASSIGN
+#define ASSIGN_STATE(dest,src)  ((dest) = (src))
+#else
+#if MAX_COMPS_IN_SCAN == 4
+#define ASSIGN_STATE(dest,src)  \
+	((dest).EOBRUN = (src).EOBRUN, \
+	 (dest).last_dc_val[0] = (src).last_dc_val[0], \
+	 (dest).last_dc_val[1] = (src).last_dc_val[1], \
+	 (dest).last_dc_val[2] = (src).last_dc_val[2], \
+	 (dest).last_dc_val[3] = (src).last_dc_val[3])
+#endif
+#endif
+
+
+typedef struct {
+  struct jpeg_entropy_decoder pub; /* public fields */
+
+  /* These fields are loaded into local variables at start of each MCU.
+   * In case of suspension, we exit WITHOUT updating them.
+   */
+  bitread_perm_state bitstate;	/* Bit buffer at start of MCU */
+  savable_state saved;		/* Other state at start of MCU */
+
+  /* These fields are NOT loaded into local working state. */
+  boolean insufficient_data;	/* set TRUE after emitting warning */
+  unsigned int restarts_to_go;	/* MCUs left in this restart interval */
+
+  /* Following two fields used only in progressive mode */
+
+  /* Pointers to derived tables (these workspaces have image lifespan) */
+  d_derived_tbl * derived_tbls[NUM_HUFF_TBLS];
+
+  d_derived_tbl * ac_derived_tbl; /* active table during an AC scan */
+
+  /* Following fields used only in sequential mode */
+
+  /* Pointers to derived tables (these workspaces have image lifespan) */
+  d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];
+  d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];
+
+  /* Precalculated info set up by start_pass for use in decode_mcu: */
+
+  /* Pointers to derived tables to be used for each block within an MCU */
+  d_derived_tbl * dc_cur_tbls[D_MAX_BLOCKS_IN_MCU];
+  d_derived_tbl * ac_cur_tbls[D_MAX_BLOCKS_IN_MCU];
+  /* Whether we care about the DC and AC coefficient values for each block */
+  int coef_limit[D_MAX_BLOCKS_IN_MCU];
+} huff_entropy_decoder;
+
+typedef huff_entropy_decoder * huff_entropy_ptr;
+
+
+static const int jpeg_zigzag_order[8][8] = {
+  {  0,  1,  5,  6, 14, 15, 27, 28 },
+  {  2,  4,  7, 13, 16, 26, 29, 42 },
+  {  3,  8, 12, 17, 25, 30, 41, 43 },
+  {  9, 11, 18, 24, 31, 40, 44, 53 },
+  { 10, 19, 23, 32, 39, 45, 52, 54 },
+  { 20, 22, 33, 38, 46, 51, 55, 60 },
+  { 21, 34, 37, 47, 50, 56, 59, 61 },
+  { 35, 36, 48, 49, 57, 58, 62, 63 }
+};
+
+static const int jpeg_zigzag_order7[7][7] = {
+  {  0,  1,  5,  6, 14, 15, 27 },
+  {  2,  4,  7, 13, 16, 26, 28 },
+  {  3,  8, 12, 17, 25, 29, 38 },
+  {  9, 11, 18, 24, 30, 37, 39 },
+  { 10, 19, 23, 31, 36, 40, 45 },
+  { 20, 22, 32, 35, 41, 44, 46 },
+  { 21, 33, 34, 42, 43, 47, 48 }
+};
+
+static const int jpeg_zigzag_order6[6][6] = {
+  {  0,  1,  5,  6, 14, 15 },
+  {  2,  4,  7, 13, 16, 25 },
+  {  3,  8, 12, 17, 24, 26 },
+  {  9, 11, 18, 23, 27, 32 },
+  { 10, 19, 22, 28, 31, 33 },
+  { 20, 21, 29, 30, 34, 35 }
+};
+
+static const int jpeg_zigzag_order5[5][5] = {
+  {  0,  1,  5,  6, 14 },
+  {  2,  4,  7, 13, 15 },
+  {  3,  8, 12, 16, 21 },
+  {  9, 11, 17, 20, 22 },
+  { 10, 18, 19, 23, 24 }
+};
+
+static const int jpeg_zigzag_order4[4][4] = {
+  { 0,  1,  5,  6 },
+  { 2,  4,  7, 12 },
+  { 3,  8, 11, 13 },
+  { 9, 10, 14, 15 }
+};
+
+static const int jpeg_zigzag_order3[3][3] = {
+  { 0, 1, 5 },
+  { 2, 4, 6 },
+  { 3, 7, 8 }
+};
+
+static const int jpeg_zigzag_order2[2][2] = {
+  { 0, 1 },
+  { 2, 3 }
+};
+
+
+/*
+ * Compute the derived values for a Huffman table.
+ * This routine also performs some validation checks on the table.
+ */
+
+LOCAL(void)
+jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno,
+			 d_derived_tbl ** pdtbl)
+{
+  JHUFF_TBL *htbl;
+  d_derived_tbl *dtbl;
+  int p, i, l, si, numsymbols;
+  int lookbits, ctr;
+  char huffsize[257];
+  unsigned int huffcode[257];
+  unsigned int code;
+
+  /* Note that huffsize[] and huffcode[] are filled in code-length order,
+   * paralleling the order of the symbols themselves in htbl->huffval[].
+   */
+
+  /* Find the input Huffman table */
+  if (tblno < 0 || tblno >= NUM_HUFF_TBLS)
+    ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);
+  htbl =
+    isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno];
+  if (htbl == NULL)
+    ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);
+
+  /* Allocate a workspace if we haven't already done so. */
+  if (*pdtbl == NULL)
+    *pdtbl = (d_derived_tbl *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  SIZEOF(d_derived_tbl));
+  dtbl = *pdtbl;
+  dtbl->pub = htbl;		/* fill in back link */
+  
+  /* Figure C.1: make table of Huffman code length for each symbol */
+
+  p = 0;
+  for (l = 1; l <= 16; l++) {
+    i = (int) htbl->bits[l];
+    if (i < 0 || p + i > 256)	/* protect against table overrun */
+      ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+    while (i--)
+      huffsize[p++] = (char) l;
+  }
+  huffsize[p] = 0;
+  numsymbols = p;
+  
+  /* Figure C.2: generate the codes themselves */
+  /* We also validate that the counts represent a legal Huffman code tree. */
+  
+  code = 0;
+  si = huffsize[0];
+  p = 0;
+  while (huffsize[p]) {
+    while (((int) huffsize[p]) == si) {
+      huffcode[p++] = code;
+      code++;
+    }
+    /* code is now 1 more than the last code used for codelength si; but
+     * it must still fit in si bits, since no code is allowed to be all ones.
+     */
+    if (((INT32) code) >= (((INT32) 1) << si))
+      ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+    code <<= 1;
+    si++;
+  }
+
+  /* Figure F.15: generate decoding tables for bit-sequential decoding */
+
+  p = 0;
+  for (l = 1; l <= 16; l++) {
+    if (htbl->bits[l]) {
+      /* valoffset[l] = huffval[] index of 1st symbol of code length l,
+       * minus the minimum code of length l
+       */
+      dtbl->valoffset[l] = (INT32) p - (INT32) huffcode[p];
+      p += htbl->bits[l];
+      dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */
+    } else {
+      dtbl->maxcode[l] = -1;	/* -1 if no codes of this length */
+    }
+  }
+  dtbl->maxcode[17] = 0xFFFFFL; /* ensures jpeg_huff_decode terminates */
+
+  /* Compute lookahead tables to speed up decoding.
+   * First we set all the table entries to 0, indicating "too long";
+   * then we iterate through the Huffman codes that are short enough and
+   * fill in all the entries that correspond to bit sequences starting
+   * with that code.
+   */
+
+  MEMZERO(dtbl->look_nbits, SIZEOF(dtbl->look_nbits));
+
+  p = 0;
+  for (l = 1; l <= HUFF_LOOKAHEAD; l++) {
+    for (i = 1; i <= (int) htbl->bits[l]; i++, p++) {
+      /* l = current code's length, p = its index in huffcode[] & huffval[]. */
+      /* Generate left-justified code followed by all possible bit sequences */
+      lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l);
+      for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) {
+	dtbl->look_nbits[lookbits] = l;
+	dtbl->look_sym[lookbits] = htbl->huffval[p];
+	lookbits++;
+      }
+    }
+  }
+
+  /* Validate symbols as being reasonable.
+   * For AC tables, we make no check, but accept all byte values 0..255.
+   * For DC tables, we require the symbols to be in range 0..15.
+   * (Tighter bounds could be applied depending on the data depth and mode,
+   * but this is sufficient to ensure safe decoding.)
+   */
+  if (isDC) {
+    for (i = 0; i < numsymbols; i++) {
+      int sym = htbl->huffval[i];
+      if (sym < 0 || sym > 15)
+	ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+    }
+  }
+}
+
+
+/*
+ * Out-of-line code for bit fetching.
+ * Note: current values of get_buffer and bits_left are passed as parameters,
+ * but are returned in the corresponding fields of the state struct.
+ *
+ * On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width
+ * of get_buffer to be used.  (On machines with wider words, an even larger
+ * buffer could be used.)  However, on some machines 32-bit shifts are
+ * quite slow and take time proportional to the number of places shifted.
+ * (This is true with most PC compilers, for instance.)  In this case it may
+ * be a win to set MIN_GET_BITS to the minimum value of 15.  This reduces the
+ * average shift distance at the cost of more calls to jpeg_fill_bit_buffer.
+ */
+
+#ifdef SLOW_SHIFT_32
+#define MIN_GET_BITS  15	/* minimum allowable value */
+#else
+#define MIN_GET_BITS  (BIT_BUF_SIZE-7)
+#endif
+
+
+LOCAL(boolean)
+jpeg_fill_bit_buffer (bitread_working_state * state,
+		      register bit_buf_type get_buffer, register int bits_left,
+		      int nbits)
+/* Load up the bit buffer to a depth of at least nbits */
+{
+  /* Copy heavily used state fields into locals (hopefully registers) */
+  register const JOCTET * next_input_byte = state->next_input_byte;
+  register size_t bytes_in_buffer = state->bytes_in_buffer;
+  j_decompress_ptr cinfo = state->cinfo;
+
+  /* Attempt to load at least MIN_GET_BITS bits into get_buffer. */
+  /* (It is assumed that no request will be for more than that many bits.) */
+  /* We fail to do so only if we hit a marker or are forced to suspend. */
+
+  if (cinfo->unread_marker == 0) {	/* cannot advance past a marker */
+    while (bits_left < MIN_GET_BITS) {
+      register int c;
+
+      /* Attempt to read a byte */
+      if (bytes_in_buffer == 0) {
+	if (! (*cinfo->src->fill_input_buffer) (cinfo))
+	  return FALSE;
+	next_input_byte = cinfo->src->next_input_byte;
+	bytes_in_buffer = cinfo->src->bytes_in_buffer;
+      }
+      bytes_in_buffer--;
+      c = GETJOCTET(*next_input_byte++);
+
+      /* If it's 0xFF, check and discard stuffed zero byte */
+      if (c == 0xFF) {
+	/* Loop here to discard any padding FF's on terminating marker,
+	 * so that we can save a valid unread_marker value.  NOTE: we will
+	 * accept multiple FF's followed by a 0 as meaning a single FF data
+	 * byte.  This data pattern is not valid according to the standard.
+	 */
+	do {
+	  if (bytes_in_buffer == 0) {
+	    if (! (*cinfo->src->fill_input_buffer) (cinfo))
+	      return FALSE;
+	    next_input_byte = cinfo->src->next_input_byte;
+	    bytes_in_buffer = cinfo->src->bytes_in_buffer;
+	  }
+	  bytes_in_buffer--;
+	  c = GETJOCTET(*next_input_byte++);
+	} while (c == 0xFF);
+
+	if (c == 0) {
+	  /* Found FF/00, which represents an FF data byte */
+	  c = 0xFF;
+	} else {
+	  /* Oops, it's actually a marker indicating end of compressed data.
+	   * Save the marker code for later use.
+	   * Fine point: it might appear that we should save the marker into
+	   * bitread working state, not straight into permanent state.  But
+	   * once we have hit a marker, we cannot need to suspend within the
+	   * current MCU, because we will read no more bytes from the data
+	   * source.  So it is OK to update permanent state right away.
+	   */
+	  cinfo->unread_marker = c;
+	  /* See if we need to insert some fake zero bits. */
+	  goto no_more_bytes;
+	}
+      }
+
+      /* OK, load c into get_buffer */
+      get_buffer = (get_buffer << 8) | c;
+      bits_left += 8;
+    } /* end while */
+  } else {
+  no_more_bytes:
+    /* We get here if we've read the marker that terminates the compressed
+     * data segment.  There should be enough bits in the buffer register
+     * to satisfy the request; if so, no problem.
+     */
+    if (nbits > bits_left) {
+      /* Uh-oh.  Report corrupted data to user and stuff zeroes into
+       * the data stream, so that we can produce some kind of image.
+       * We use a nonvolatile flag to ensure that only one warning message
+       * appears per data segment.
+       */
+      if (! ((huff_entropy_ptr) cinfo->entropy)->insufficient_data) {
+	WARNMS(cinfo, JWRN_HIT_MARKER);
+	((huff_entropy_ptr) cinfo->entropy)->insufficient_data = TRUE;
+      }
+      /* Fill the buffer with zero bits */
+      get_buffer <<= MIN_GET_BITS - bits_left;
+      bits_left = MIN_GET_BITS;
+    }
+  }
+
+  /* Unload the local registers */
+  state->next_input_byte = next_input_byte;
+  state->bytes_in_buffer = bytes_in_buffer;
+  state->get_buffer = get_buffer;
+  state->bits_left = bits_left;
+
+  return TRUE;
+}
+
+
+/*
+ * Figure F.12: extend sign bit.
+ * On some machines, a shift and sub will be faster than a table lookup.
+ */
+
+#ifdef AVOID_TABLES
+
+#define BIT_MASK(nbits)   ((1<<(nbits))-1)
+#define HUFF_EXTEND(x,s)  ((x) < (1<<((s)-1)) ? (x) - ((1<<(s))-1) : (x))
+
+#else
+
+#define BIT_MASK(nbits)   bmask[nbits]
+#define HUFF_EXTEND(x,s)  ((x) <= bmask[(s) - 1] ? (x) - bmask[s] : (x))
+
+static const int bmask[16] =	/* bmask[n] is mask for n rightmost bits */
+  { 0, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
+    0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF };
+
+#endif /* AVOID_TABLES */
+
+
+/*
+ * Out-of-line code for Huffman code decoding.
+ */
+
+LOCAL(int)
+jpeg_huff_decode (bitread_working_state * state,
+		  register bit_buf_type get_buffer, register int bits_left,
+		  d_derived_tbl * htbl, int min_bits)
+{
+  register int l = min_bits;
+  register INT32 code;
+
+  /* HUFF_DECODE has determined that the code is at least min_bits */
+  /* bits long, so fetch that many bits in one swoop. */
+
+  CHECK_BIT_BUFFER(*state, l, return -1);
+  code = GET_BITS(l);
+
+  /* Collect the rest of the Huffman code one bit at a time. */
+  /* This is per Figure F.16 in the JPEG spec. */
+
+  while (code > htbl->maxcode[l]) {
+    code <<= 1;
+    CHECK_BIT_BUFFER(*state, 1, return -1);
+    code |= GET_BITS(1);
+    l++;
+  }
+
+  /* Unload the local registers */
+  state->get_buffer = get_buffer;
+  state->bits_left = bits_left;
+
+  /* With garbage input we may reach the sentinel value l = 17. */
+
+  if (l > 16) {
+    WARNMS(state->cinfo, JWRN_HUFF_BAD_CODE);
+    return 0;			/* fake a zero as the safest result */
+  }
+
+  return htbl->pub->huffval[ (int) (code + htbl->valoffset[l]) ];
+}
+
+
+/*
+ * Finish up at the end of a Huffman-compressed scan.
+ */
+
+METHODDEF(void)
+finish_pass_huff (j_decompress_ptr cinfo)
+{
+  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+
+  /* Throw away any unused bits remaining in bit buffer; */
+  /* include any full bytes in next_marker's count of discarded bytes */
+  cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8;
+  entropy->bitstate.bits_left = 0;
+}
+
+
+/*
+ * Check for a restart marker & resynchronize decoder.
+ * Returns FALSE if must suspend.
+ */
+
+LOCAL(boolean)
+process_restart (j_decompress_ptr cinfo)
+{
+  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+  int ci;
+
+  finish_pass_huff(cinfo);
+
+  /* Advance past the RSTn marker */
+  if (! (*cinfo->marker->read_restart_marker) (cinfo))
+    return FALSE;
+
+  /* Re-initialize DC predictions to 0 */
+  for (ci = 0; ci < cinfo->comps_in_scan; ci++)
+    entropy->saved.last_dc_val[ci] = 0;
+  /* Re-init EOB run count, too */
+  entropy->saved.EOBRUN = 0;
+
+  /* Reset restart counter */
+  entropy->restarts_to_go = cinfo->restart_interval;
+
+  /* Reset out-of-data flag, unless read_restart_marker left us smack up
+   * against a marker.  In that case we will end up treating the next data
+   * segment as empty, and we can avoid producing bogus output pixels by
+   * leaving the flag set.
+   */
+  if (cinfo->unread_marker == 0)
+    entropy->insufficient_data = FALSE;
+
+  return TRUE;
+}
+
+
+/*
+ * Huffman MCU decoding.
+ * Each of these routines decodes and returns one MCU's worth of
+ * Huffman-compressed coefficients. 
+ * The coefficients are reordered from zigzag order into natural array order,
+ * but are not dequantized.
+ *
+ * The i'th block of the MCU is stored into the block pointed to by
+ * MCU_data[i].  WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER.
+ * (Wholesale zeroing is usually a little faster than retail...)
+ *
+ * We return FALSE if data source requested suspension.  In that case no
+ * changes have been made to permanent state.  (Exception: some output
+ * coefficients may already have been assigned.  This is harmless for
+ * spectral selection, since we'll just re-assign them on the next call.
+ * Successive approximation AC refinement has to be more careful, however.)
+ */
+
+/*
+ * MCU decoding for DC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{   
+  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+  int Al = cinfo->Al;
+  register int s, r;
+  int blkn, ci;
+  JBLOCKROW block;
+  BITREAD_STATE_VARS;
+  savable_state state;
+  d_derived_tbl * tbl;
+  jpeg_component_info * compptr;
+
+  /* Process restart marker if needed; may have to suspend */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0)
+      if (! process_restart(cinfo))
+	return FALSE;
+  }
+
+  /* If we've run out of data, just leave the MCU set to zeroes.
+   * This way, we return uniform gray for the remainder of the segment.
+   */
+  if (! entropy->insufficient_data) {
+
+    /* Load up working state */
+    BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+    ASSIGN_STATE(state, entropy->saved);
+
+    /* Outer loop handles each block in the MCU */
+
+    for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+      block = MCU_data[blkn];
+      ci = cinfo->MCU_membership[blkn];
+      compptr = cinfo->cur_comp_info[ci];
+      tbl = entropy->derived_tbls[compptr->dc_tbl_no];
+
+      /* Decode a single block's worth of coefficients */
+
+      /* Section F.2.2.1: decode the DC coefficient difference */
+      HUFF_DECODE(s, br_state, tbl, return FALSE, label1);
+      if (s) {
+	CHECK_BIT_BUFFER(br_state, s, return FALSE);
+	r = GET_BITS(s);
+	s = HUFF_EXTEND(r, s);
+      }
+
+      /* Convert DC difference to actual value, update last_dc_val */
+      s += state.last_dc_val[ci];
+      state.last_dc_val[ci] = s;
+      /* Scale and output the coefficient (assumes jpeg_natural_order[0]=0) */
+      (*block)[0] = (JCOEF) (s << Al);
+    }
+
+    /* Completed MCU, so update state */
+    BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+    ASSIGN_STATE(entropy->saved, state);
+  }
+
+  /* Account for restart interval (no-op if not using restarts) */
+  entropy->restarts_to_go--;
+
+  return TRUE;
+}
+
+
+/*
+ * MCU decoding for AC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{   
+  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+  register int s, k, r;
+  unsigned int EOBRUN;
+  int Se, Al;
+  const int * natural_order;
+  JBLOCKROW block;
+  BITREAD_STATE_VARS;
+  d_derived_tbl * tbl;
+
+  /* Process restart marker if needed; may have to suspend */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0)
+      if (! process_restart(cinfo))
+	return FALSE;
+  }
+
+  /* If we've run out of data, just leave the MCU set to zeroes.
+   * This way, we return uniform gray for the remainder of the segment.
+   */
+  if (! entropy->insufficient_data) {
+
+    Se = cinfo->Se;
+    Al = cinfo->Al;
+    natural_order = cinfo->natural_order;
+
+    /* Load up working state.
+     * We can avoid loading/saving bitread state if in an EOB run.
+     */
+    EOBRUN = entropy->saved.EOBRUN;	/* only part of saved state we need */
+
+    /* There is always only one block per MCU */
+
+    if (EOBRUN)			/* if it's a band of zeroes... */
+      EOBRUN--;			/* ...process it now (we do nothing) */
+    else {
+      BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+      block = MCU_data[0];
+      tbl = entropy->ac_derived_tbl;
+
+      for (k = cinfo->Ss; k <= Se; k++) {
+	HUFF_DECODE(s, br_state, tbl, return FALSE, label2);
+	r = s >> 4;
+	s &= 15;
+	if (s) {
+	  k += r;
+	  CHECK_BIT_BUFFER(br_state, s, return FALSE);
+	  r = GET_BITS(s);
+	  s = HUFF_EXTEND(r, s);
+	  /* Scale and output coefficient in natural (dezigzagged) order */
+	  (*block)[natural_order[k]] = (JCOEF) (s << Al);
+	} else {
+	  if (r != 15) {	/* EOBr, run length is 2^r + appended bits */
+	    if (r) {		/* EOBr, r > 0 */
+	      EOBRUN = 1 << r;
+	      CHECK_BIT_BUFFER(br_state, r, return FALSE);
+	      r = GET_BITS(r);
+	      EOBRUN += r;
+	      EOBRUN--;		/* this band is processed at this moment */
+	    }
+	    break;		/* force end-of-band */
+	  }
+	  k += 15;		/* ZRL: skip 15 zeroes in band */
+	}
+      }
+
+      BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+    }
+
+    /* Completed MCU, so update state */
+    entropy->saved.EOBRUN = EOBRUN;	/* only part of saved state we need */
+  }
+
+  /* Account for restart interval (no-op if not using restarts) */
+  entropy->restarts_to_go--;
+
+  return TRUE;
+}
+
+
+/*
+ * MCU decoding for DC successive approximation refinement scan.
+ * Note: we assume such scans can be multi-component,
+ * although the spec is not very clear on the point.
+ */
+
+METHODDEF(boolean)
+decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{   
+  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+  int p1, blkn;
+  BITREAD_STATE_VARS;
+
+  /* Process restart marker if needed; may have to suspend */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0)
+      if (! process_restart(cinfo))
+	return FALSE;
+  }
+
+  /* Not worth the cycles to check insufficient_data here,
+   * since we will not change the data anyway if we read zeroes.
+   */
+
+  /* Load up working state */
+  BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+
+  p1 = 1 << cinfo->Al;		/* 1 in the bit position being coded */
+
+  /* Outer loop handles each block in the MCU */
+
+  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+    /* Encoded data is simply the next bit of the two's-complement DC value */
+    CHECK_BIT_BUFFER(br_state, 1, return FALSE);
+    if (GET_BITS(1))
+      MCU_data[blkn][0][0] |= p1;
+    /* Note: since we use |=, repeating the assignment later is safe */
+  }
+
+  /* Completed MCU, so update state */
+  BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+
+  /* Account for restart interval (no-op if not using restarts) */
+  entropy->restarts_to_go--;
+
+  return TRUE;
+}
+
+
+/*
+ * MCU decoding for AC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{   
+  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+  register int s, k, r;
+  unsigned int EOBRUN;
+  int Se, p1, m1;
+  const int * natural_order;
+  JBLOCKROW block;
+  JCOEFPTR thiscoef;
+  BITREAD_STATE_VARS;
+  d_derived_tbl * tbl;
+  int num_newnz;
+  int newnz_pos[DCTSIZE2];
+
+  /* Process restart marker if needed; may have to suspend */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0)
+      if (! process_restart(cinfo))
+	return FALSE;
+  }
+
+  /* If we've run out of data, don't modify the MCU.
+   */
+  if (! entropy->insufficient_data) {
+
+    Se = cinfo->Se;
+    p1 = 1 << cinfo->Al;	/* 1 in the bit position being coded */
+    m1 = (-1) << cinfo->Al;	/* -1 in the bit position being coded */
+    natural_order = cinfo->natural_order;
+
+    /* Load up working state */
+    BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+    EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */
+
+    /* There is always only one block per MCU */
+    block = MCU_data[0];
+    tbl = entropy->ac_derived_tbl;
+
+    /* If we are forced to suspend, we must undo the assignments to any newly
+     * nonzero coefficients in the block, because otherwise we'd get confused
+     * next time about which coefficients were already nonzero.
+     * But we need not undo addition of bits to already-nonzero coefficients;
+     * instead, we can test the current bit to see if we already did it.
+     */
+    num_newnz = 0;
+
+    /* initialize coefficient loop counter to start of band */
+    k = cinfo->Ss;
+
+    if (EOBRUN == 0) {
+      do {
+	HUFF_DECODE(s, br_state, tbl, goto undoit, label3);
+	r = s >> 4;
+	s &= 15;
+	if (s) {
+	  if (s != 1)		/* size of new coef should always be 1 */
+	    WARNMS(cinfo, JWRN_HUFF_BAD_CODE);
+	  CHECK_BIT_BUFFER(br_state, 1, goto undoit);
+	  if (GET_BITS(1))
+	    s = p1;		/* newly nonzero coef is positive */
+	  else
+	    s = m1;		/* newly nonzero coef is negative */
+	} else {
+	  if (r != 15) {
+	    EOBRUN = 1 << r;	/* EOBr, run length is 2^r + appended bits */
+	    if (r) {
+	      CHECK_BIT_BUFFER(br_state, r, goto undoit);
+	      r = GET_BITS(r);
+	      EOBRUN += r;
+	    }
+	    break;		/* rest of block is handled by EOB logic */
+	  }
+	  /* note s = 0 for processing ZRL */
+	}
+	/* Advance over already-nonzero coefs and r still-zero coefs,
+	 * appending correction bits to the nonzeroes.  A correction bit is 1
+	 * if the absolute value of the coefficient must be increased.
+	 */
+	do {
+	  thiscoef = *block + natural_order[k];
+	  if (*thiscoef) {
+	    CHECK_BIT_BUFFER(br_state, 1, goto undoit);
+	    if (GET_BITS(1)) {
+	      if ((*thiscoef & p1) == 0) { /* do nothing if already set it */
+		if (*thiscoef >= 0)
+		  *thiscoef += p1;
+		else
+		  *thiscoef += m1;
+	      }
+	    }
+	  } else {
+	    if (--r < 0)
+	      break;		/* reached target zero coefficient */
+	  }
+	  k++;
+	} while (k <= Se);
+	if (s) {
+	  int pos = natural_order[k];
+	  /* Output newly nonzero coefficient */
+	  (*block)[pos] = (JCOEF) s;
+	  /* Remember its position in case we have to suspend */
+	  newnz_pos[num_newnz++] = pos;
+	}
+	k++;
+      } while (k <= Se);
+    }
+
+    if (EOBRUN) {
+      /* Scan any remaining coefficient positions after the end-of-band
+       * (the last newly nonzero coefficient, if any).  Append a correction
+       * bit to each already-nonzero coefficient.  A correction bit is 1
+       * if the absolute value of the coefficient must be increased.
+       */
+      do {
+	thiscoef = *block + natural_order[k];
+	if (*thiscoef) {
+	  CHECK_BIT_BUFFER(br_state, 1, goto undoit);
+	  if (GET_BITS(1)) {
+	    if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */
+	      if (*thiscoef >= 0)
+		*thiscoef += p1;
+	      else
+		*thiscoef += m1;
+	    }
+	  }
+	}
+	k++;
+      } while (k <= Se);
+      /* Count one block completed in EOB run */
+      EOBRUN--;
+    }
+
+    /* Completed MCU, so update state */
+    BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+    entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */
+  }
+
+  /* Account for restart interval (no-op if not using restarts) */
+  entropy->restarts_to_go--;
+
+  return TRUE;
+
+undoit:
+  /* Re-zero any output coefficients that we made newly nonzero */
+  while (num_newnz)
+    (*block)[newnz_pos[--num_newnz]] = 0;
+
+  return FALSE;
+}
+
+
+/*
+ * Decode one MCU's worth of Huffman-compressed coefficients,
+ * partial blocks.
+ */
+
+METHODDEF(boolean)
+decode_mcu_sub (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+  const int * natural_order;
+  int Se, blkn;
+  BITREAD_STATE_VARS;
+  savable_state state;
+
+  /* Process restart marker if needed; may have to suspend */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0)
+      if (! process_restart(cinfo))
+	return FALSE;
+  }
+
+  /* If we've run out of data, just leave the MCU set to zeroes.
+   * This way, we return uniform gray for the remainder of the segment.
+   */
+  if (! entropy->insufficient_data) {
+
+    natural_order = cinfo->natural_order;
+    Se = cinfo->lim_Se;
+
+    /* Load up working state */
+    BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+    ASSIGN_STATE(state, entropy->saved);
+
+    /* Outer loop handles each block in the MCU */
+
+    for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+      JBLOCKROW block = MCU_data[blkn];
+      d_derived_tbl * htbl;
+      register int s, k, r;
+      int coef_limit, ci;
+
+      /* Decode a single block's worth of coefficients */
+
+      /* Section F.2.2.1: decode the DC coefficient difference */
+      htbl = entropy->dc_cur_tbls[blkn];
+      HUFF_DECODE(s, br_state, htbl, return FALSE, label1);
+
+      htbl = entropy->ac_cur_tbls[blkn];
+      k = 1;
+      coef_limit = entropy->coef_limit[blkn];
+      if (coef_limit) {
+	/* Convert DC difference to actual value, update last_dc_val */
+	if (s) {
+	  CHECK_BIT_BUFFER(br_state, s, return FALSE);
+	  r = GET_BITS(s);
+	  s = HUFF_EXTEND(r, s);
+	}
+	ci = cinfo->MCU_membership[blkn];
+	s += state.last_dc_val[ci];
+	state.last_dc_val[ci] = s;
+	/* Output the DC coefficient */
+	(*block)[0] = (JCOEF) s;
+
+	/* Section F.2.2.2: decode the AC coefficients */
+	/* Since zeroes are skipped, output area must be cleared beforehand */
+	for (; k < coef_limit; k++) {
+	  HUFF_DECODE(s, br_state, htbl, return FALSE, label2);
+
+	  r = s >> 4;
+	  s &= 15;
+
+	  if (s) {
+	    k += r;
+	    CHECK_BIT_BUFFER(br_state, s, return FALSE);
+	    r = GET_BITS(s);
+	    s = HUFF_EXTEND(r, s);
+	    /* Output coefficient in natural (dezigzagged) order.
+	     * Note: the extra entries in natural_order[] will save us
+	     * if k > Se, which could happen if the data is corrupted.
+	     */
+	    (*block)[natural_order[k]] = (JCOEF) s;
+	  } else {
+	    if (r != 15)
+	      goto EndOfBlock;
+	    k += 15;
+	  }
+	}
+      } else {
+	if (s) {
+	  CHECK_BIT_BUFFER(br_state, s, return FALSE);
+	  DROP_BITS(s);
+	}
+      }
+
+      /* Section F.2.2.2: decode the AC coefficients */
+      /* In this path we just discard the values */
+      for (; k <= Se; k++) {
+	HUFF_DECODE(s, br_state, htbl, return FALSE, label3);
+
+	r = s >> 4;
+	s &= 15;
+
+	if (s) {
+	  k += r;
+	  CHECK_BIT_BUFFER(br_state, s, return FALSE);
+	  DROP_BITS(s);
+	} else {
+	  if (r != 15)
+	    break;
+	  k += 15;
+	}
+      }
+
+      EndOfBlock: ;
+    }
+
+    /* Completed MCU, so update state */
+    BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+    ASSIGN_STATE(entropy->saved, state);
+  }
+
+  /* Account for restart interval (no-op if not using restarts) */
+  entropy->restarts_to_go--;
+
+  return TRUE;
+}
+
+
+/*
+ * Decode one MCU's worth of Huffman-compressed coefficients,
+ * full-size blocks.
+ */
+
+METHODDEF(boolean)
+decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+  int blkn;
+  BITREAD_STATE_VARS;
+  savable_state state;
+
+  /* Process restart marker if needed; may have to suspend */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0)
+      if (! process_restart(cinfo))
+	return FALSE;
+  }
+
+  /* If we've run out of data, just leave the MCU set to zeroes.
+   * This way, we return uniform gray for the remainder of the segment.
+   */
+  if (! entropy->insufficient_data) {
+
+    /* Load up working state */
+    BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+    ASSIGN_STATE(state, entropy->saved);
+
+    /* Outer loop handles each block in the MCU */
+
+    for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+      JBLOCKROW block = MCU_data[blkn];
+      d_derived_tbl * htbl;
+      register int s, k, r;
+      int coef_limit, ci;
+
+      /* Decode a single block's worth of coefficients */
+
+      /* Section F.2.2.1: decode the DC coefficient difference */
+      htbl = entropy->dc_cur_tbls[blkn];
+      HUFF_DECODE(s, br_state, htbl, return FALSE, label1);
+
+      htbl = entropy->ac_cur_tbls[blkn];
+      k = 1;
+      coef_limit = entropy->coef_limit[blkn];
+      if (coef_limit) {
+	/* Convert DC difference to actual value, update last_dc_val */
+	if (s) {
+	  CHECK_BIT_BUFFER(br_state, s, return FALSE);
+	  r = GET_BITS(s);
+	  s = HUFF_EXTEND(r, s);
+	}
+	ci = cinfo->MCU_membership[blkn];
+	s += state.last_dc_val[ci];
+	state.last_dc_val[ci] = s;
+	/* Output the DC coefficient */
+	(*block)[0] = (JCOEF) s;
+
+	/* Section F.2.2.2: decode the AC coefficients */
+	/* Since zeroes are skipped, output area must be cleared beforehand */
+	for (; k < coef_limit; k++) {
+	  HUFF_DECODE(s, br_state, htbl, return FALSE, label2);
+
+	  r = s >> 4;
+	  s &= 15;
+
+	  if (s) {
+	    k += r;
+	    CHECK_BIT_BUFFER(br_state, s, return FALSE);
+	    r = GET_BITS(s);
+	    s = HUFF_EXTEND(r, s);
+	    /* Output coefficient in natural (dezigzagged) order.
+	     * Note: the extra entries in jpeg_natural_order[] will save us
+	     * if k >= DCTSIZE2, which could happen if the data is corrupted.
+	     */
+	    (*block)[jpeg_natural_order[k]] = (JCOEF) s;
+	  } else {
+	    if (r != 15)
+	      goto EndOfBlock;
+	    k += 15;
+	  }
+	}
+      } else {
+	if (s) {
+	  CHECK_BIT_BUFFER(br_state, s, return FALSE);
+	  DROP_BITS(s);
+	}
+      }
+
+      /* Section F.2.2.2: decode the AC coefficients */
+      /* In this path we just discard the values */
+      for (; k < DCTSIZE2; k++) {
+	HUFF_DECODE(s, br_state, htbl, return FALSE, label3);
+
+	r = s >> 4;
+	s &= 15;
+
+	if (s) {
+	  k += r;
+	  CHECK_BIT_BUFFER(br_state, s, return FALSE);
+	  DROP_BITS(s);
+	} else {
+	  if (r != 15)
+	    break;
+	  k += 15;
+	}
+      }
+
+      EndOfBlock: ;
+    }
+
+    /* Completed MCU, so update state */
+    BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+    ASSIGN_STATE(entropy->saved, state);
+  }
+
+  /* Account for restart interval (no-op if not using restarts) */
+  entropy->restarts_to_go--;
+
+  return TRUE;
+}
+
+
+/*
+ * Initialize for a Huffman-compressed scan.
+ */
+
+METHODDEF(void)
+start_pass_huff_decoder (j_decompress_ptr cinfo)
+{
+  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+  int ci, blkn, tbl, i;
+  jpeg_component_info * compptr;
+
+  if (cinfo->progressive_mode) {
+    /* Validate progressive scan parameters */
+    if (cinfo->Ss == 0) {
+      if (cinfo->Se != 0)
+	goto bad;
+    } else {
+      /* need not check Ss/Se < 0 since they came from unsigned bytes */
+      if (cinfo->Se < cinfo->Ss || cinfo->Se > cinfo->lim_Se)
+	goto bad;
+      /* AC scans may have only one component */
+      if (cinfo->comps_in_scan != 1)
+	goto bad;
+    }
+    if (cinfo->Ah != 0) {
+      /* Successive approximation refinement scan: must have Al = Ah-1. */
+      if (cinfo->Ah-1 != cinfo->Al)
+	goto bad;
+    }
+    if (cinfo->Al > 13) {	/* need not check for < 0 */
+      /* Arguably the maximum Al value should be less than 13 for 8-bit precision,
+       * but the spec doesn't say so, and we try to be liberal about what we
+       * accept.  Note: large Al values could result in out-of-range DC
+       * coefficients during early scans, leading to bizarre displays due to
+       * overflows in the IDCT math.  But we won't crash.
+       */
+      bad:
+      ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
+	       cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
+    }
+    /* Update progression status, and verify that scan order is legal.
+     * Note that inter-scan inconsistencies are treated as warnings
+     * not fatal errors ... not clear if this is right way to behave.
+     */
+    for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+      int coefi, cindex = cinfo->cur_comp_info[ci]->component_index;
+      int *coef_bit_ptr = & cinfo->coef_bits[cindex][0];
+      if (cinfo->Ss && coef_bit_ptr[0] < 0) /* AC without prior DC scan */
+	WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0);
+      for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) {
+	int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi];
+	if (cinfo->Ah != expected)
+	  WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi);
+	coef_bit_ptr[coefi] = cinfo->Al;
+      }
+    }
+
+    /* Select MCU decoding routine */
+    if (cinfo->Ah == 0) {
+      if (cinfo->Ss == 0)
+	entropy->pub.decode_mcu = decode_mcu_DC_first;
+      else
+	entropy->pub.decode_mcu = decode_mcu_AC_first;
+    } else {
+      if (cinfo->Ss == 0)
+	entropy->pub.decode_mcu = decode_mcu_DC_refine;
+      else
+	entropy->pub.decode_mcu = decode_mcu_AC_refine;
+    }
+
+    for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+      compptr = cinfo->cur_comp_info[ci];
+      /* Make sure requested tables are present, and compute derived tables.
+       * We may build same derived table more than once, but it's not expensive.
+       */
+      if (cinfo->Ss == 0) {
+	if (cinfo->Ah == 0) {	/* DC refinement needs no table */
+	  tbl = compptr->dc_tbl_no;
+	  jpeg_make_d_derived_tbl(cinfo, TRUE, tbl,
+				  & entropy->derived_tbls[tbl]);
+	}
+      } else {
+	tbl = compptr->ac_tbl_no;
+	jpeg_make_d_derived_tbl(cinfo, FALSE, tbl,
+				& entropy->derived_tbls[tbl]);
+	/* remember the single active table */
+	entropy->ac_derived_tbl = entropy->derived_tbls[tbl];
+      }
+      /* Initialize DC predictions to 0 */
+      entropy->saved.last_dc_val[ci] = 0;
+    }
+
+    /* Initialize private state variables */
+    entropy->saved.EOBRUN = 0;
+  } else {
+    /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.
+     * This ought to be an error condition, but we make it a warning because
+     * there are some baseline files out there with all zeroes in these bytes.
+     */
+    if (cinfo->Ss != 0 || cinfo->Ah != 0 || cinfo->Al != 0 ||
+	((cinfo->is_baseline || cinfo->Se < DCTSIZE2) &&
+	cinfo->Se != cinfo->lim_Se))
+      WARNMS(cinfo, JWRN_NOT_SEQUENTIAL);
+
+    /* Select MCU decoding routine */
+    /* We retain the hard-coded case for full-size blocks.
+     * This is not necessary, but it appears that this version is slightly
+     * more performant in the given implementation.
+     * With an improved implementation we would prefer a single optimized
+     * function.
+     */
+    if (cinfo->lim_Se != DCTSIZE2-1)
+      entropy->pub.decode_mcu = decode_mcu_sub;
+    else
+      entropy->pub.decode_mcu = decode_mcu;
+
+    for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+      compptr = cinfo->cur_comp_info[ci];
+      /* Compute derived values for Huffman tables */
+      /* We may do this more than once for a table, but it's not expensive */
+      tbl = compptr->dc_tbl_no;
+      jpeg_make_d_derived_tbl(cinfo, TRUE, tbl,
+			      & entropy->dc_derived_tbls[tbl]);
+      if (cinfo->lim_Se) {	/* AC needs no table when not present */
+	tbl = compptr->ac_tbl_no;
+	jpeg_make_d_derived_tbl(cinfo, FALSE, tbl,
+				& entropy->ac_derived_tbls[tbl]);
+      }
+      /* Initialize DC predictions to 0 */
+      entropy->saved.last_dc_val[ci] = 0;
+    }
+
+    /* Precalculate decoding info for each block in an MCU of this scan */
+    for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+      ci = cinfo->MCU_membership[blkn];
+      compptr = cinfo->cur_comp_info[ci];
+      /* Precalculate which table to use for each block */
+      entropy->dc_cur_tbls[blkn] = entropy->dc_derived_tbls[compptr->dc_tbl_no];
+      entropy->ac_cur_tbls[blkn] = entropy->ac_derived_tbls[compptr->ac_tbl_no];
+      /* Decide whether we really care about the coefficient values */
+      if (compptr->component_needed) {
+	ci = compptr->DCT_v_scaled_size;
+	i = compptr->DCT_h_scaled_size;
+	switch (cinfo->lim_Se) {
+	case (1*1-1):
+	  entropy->coef_limit[blkn] = 1;
+	  break;
+	case (2*2-1):
+	  if (ci <= 0 || ci > 2) ci = 2;
+	  if (i <= 0 || i > 2) i = 2;
+	  entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order2[ci - 1][i - 1];
+	  break;
+	case (3*3-1):
+	  if (ci <= 0 || ci > 3) ci = 3;
+	  if (i <= 0 || i > 3) i = 3;
+	  entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order3[ci - 1][i - 1];
+	  break;
+	case (4*4-1):
+	  if (ci <= 0 || ci > 4) ci = 4;
+	  if (i <= 0 || i > 4) i = 4;
+	  entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order4[ci - 1][i - 1];
+	  break;
+	case (5*5-1):
+	  if (ci <= 0 || ci > 5) ci = 5;
+	  if (i <= 0 || i > 5) i = 5;
+	  entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order5[ci - 1][i - 1];
+	  break;
+	case (6*6-1):
+	  if (ci <= 0 || ci > 6) ci = 6;
+	  if (i <= 0 || i > 6) i = 6;
+	  entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order6[ci - 1][i - 1];
+	  break;
+	case (7*7-1):
+	  if (ci <= 0 || ci > 7) ci = 7;
+	  if (i <= 0 || i > 7) i = 7;
+	  entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order7[ci - 1][i - 1];
+	  break;
+	default:
+	  if (ci <= 0 || ci > 8) ci = 8;
+	  if (i <= 0 || i > 8) i = 8;
+	  entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order[ci - 1][i - 1];
+	  break;
+	}
+      } else {
+	entropy->coef_limit[blkn] = 0;
+      }
+    }
+  }
+
+  /* Initialize bitread state variables */
+  entropy->bitstate.bits_left = 0;
+  entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */
+  entropy->insufficient_data = FALSE;
+
+  /* Initialize restart counter */
+  entropy->restarts_to_go = cinfo->restart_interval;
+}
+
+
+/*
+ * Module initialization routine for Huffman entropy decoding.
+ */
+
+GLOBAL(void)
+jinit_huff_decoder (j_decompress_ptr cinfo)
+{
+  huff_entropy_ptr entropy;
+  int i;
+
+  entropy = (huff_entropy_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(huff_entropy_decoder));
+  cinfo->entropy = &entropy->pub;
+  entropy->pub.start_pass = start_pass_huff_decoder;
+  entropy->pub.finish_pass = finish_pass_huff;
+
+  if (cinfo->progressive_mode) {
+    /* Create progression status table */
+    int *coef_bit_ptr, ci;
+    cinfo->coef_bits = (int (*)[DCTSIZE2])
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  cinfo->num_components*DCTSIZE2*SIZEOF(int));
+    coef_bit_ptr = & cinfo->coef_bits[0][0];
+    for (ci = 0; ci < cinfo->num_components; ci++)
+      for (i = 0; i < DCTSIZE2; i++)
+	*coef_bit_ptr++ = -1;
+
+    /* Mark derived tables unallocated */
+    for (i = 0; i < NUM_HUFF_TBLS; i++) {
+      entropy->derived_tbls[i] = NULL;
+    }
+  } else {
+    /* Mark tables unallocated */
+    for (i = 0; i < NUM_HUFF_TBLS; i++) {
+      entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL;
+    }
+  }
+}
diff --git a/source/Irrlicht/jpeglib/jdinput.c b/source/Irrlicht/jpeglib/jdinput.c
new file mode 100644
index 00000000..80bdef56
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jdinput.c
@@ -0,0 +1,662 @@
+/*
+ * jdinput.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2002-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains input control logic for the JPEG decompressor.
+ * These routines are concerned with controlling the decompressor's input
+ * processing (marker reading and coefficient decoding).  The actual input
+ * reading is done in jdmarker.c, jdhuff.c, and jdarith.c.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private state */
+
+typedef struct {
+  struct jpeg_input_controller pub; /* public fields */
+
+  int inheaders;		/* Nonzero until first SOS is reached */
+} my_input_controller;
+
+typedef my_input_controller * my_inputctl_ptr;
+
+
+/* Forward declarations */
+METHODDEF(int) consume_markers JPP((j_decompress_ptr cinfo));
+
+
+/*
+ * Routines to calculate various quantities related to the size of the image.
+ */
+
+
+/*
+ * Compute output image dimensions and related values.
+ * NOTE: this is exported for possible use by application.
+ * Hence it mustn't do anything that can't be done twice.
+ */
+
+GLOBAL(void)
+jpeg_core_output_dimensions (j_decompress_ptr cinfo)
+/* Do computations that are needed before master selection phase.
+ * This function is used for transcoding and full decompression.
+ */
+{
+#ifdef IDCT_SCALING_SUPPORTED
+  int ci;
+  jpeg_component_info *compptr;
+
+  /* Compute actual output image dimensions and DCT scaling choices. */
+  if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom) {
+    /* Provide 1/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 1;
+    cinfo->min_DCT_v_scaled_size = 1;
+  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 2) {
+    /* Provide 2/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * 2L, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * 2L, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 2;
+    cinfo->min_DCT_v_scaled_size = 2;
+  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 3) {
+    /* Provide 3/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * 3L, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * 3L, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 3;
+    cinfo->min_DCT_v_scaled_size = 3;
+  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 4) {
+    /* Provide 4/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * 4L, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * 4L, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 4;
+    cinfo->min_DCT_v_scaled_size = 4;
+  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 5) {
+    /* Provide 5/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * 5L, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * 5L, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 5;
+    cinfo->min_DCT_v_scaled_size = 5;
+  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 6) {
+    /* Provide 6/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * 6L, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * 6L, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 6;
+    cinfo->min_DCT_v_scaled_size = 6;
+  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 7) {
+    /* Provide 7/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * 7L, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * 7L, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 7;
+    cinfo->min_DCT_v_scaled_size = 7;
+  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 8) {
+    /* Provide 8/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * 8L, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * 8L, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 8;
+    cinfo->min_DCT_v_scaled_size = 8;
+  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 9) {
+    /* Provide 9/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * 9L, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * 9L, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 9;
+    cinfo->min_DCT_v_scaled_size = 9;
+  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 10) {
+    /* Provide 10/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * 10L, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * 10L, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 10;
+    cinfo->min_DCT_v_scaled_size = 10;
+  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 11) {
+    /* Provide 11/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * 11L, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * 11L, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 11;
+    cinfo->min_DCT_v_scaled_size = 11;
+  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 12) {
+    /* Provide 12/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * 12L, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * 12L, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 12;
+    cinfo->min_DCT_v_scaled_size = 12;
+  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 13) {
+    /* Provide 13/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * 13L, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * 13L, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 13;
+    cinfo->min_DCT_v_scaled_size = 13;
+  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 14) {
+    /* Provide 14/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * 14L, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * 14L, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 14;
+    cinfo->min_DCT_v_scaled_size = 14;
+  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 15) {
+    /* Provide 15/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * 15L, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * 15L, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 15;
+    cinfo->min_DCT_v_scaled_size = 15;
+  } else {
+    /* Provide 16/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * 16L, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * 16L, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 16;
+    cinfo->min_DCT_v_scaled_size = 16;
+  }
+
+  /* Recompute dimensions of components */
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size;
+    compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size;
+  }
+
+#else /* !IDCT_SCALING_SUPPORTED */
+
+  /* Hardwire it to "no scaling" */
+  cinfo->output_width = cinfo->image_width;
+  cinfo->output_height = cinfo->image_height;
+  /* initial_setup has already initialized DCT_scaled_size,
+   * and has computed unscaled downsampled_width and downsampled_height.
+   */
+
+#endif /* IDCT_SCALING_SUPPORTED */
+}
+
+
+LOCAL(void)
+initial_setup (j_decompress_ptr cinfo)
+/* Called once, when first SOS marker is reached */
+{
+  int ci;
+  jpeg_component_info *compptr;
+
+  /* Make sure image isn't bigger than I can handle */
+  if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION ||
+      (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION)
+    ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
+
+  /* Only 8 to 12 bits data precision are supported for DCT based JPEG */
+  if (cinfo->data_precision < 8 || cinfo->data_precision > 12)
+    ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+  /* Check that number of components won't exceed internal array sizes */
+  if (cinfo->num_components > MAX_COMPONENTS)
+    ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
+	     MAX_COMPONENTS);
+
+  /* Compute maximum sampling factors; check factor validity */
+  cinfo->max_h_samp_factor = 1;
+  cinfo->max_v_samp_factor = 1;
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR ||
+	compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR)
+      ERREXIT(cinfo, JERR_BAD_SAMPLING);
+    cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor,
+				   compptr->h_samp_factor);
+    cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor,
+				   compptr->v_samp_factor);
+  }
+
+  /* Derive block_size, natural_order, and lim_Se */
+  if (cinfo->is_baseline || (cinfo->progressive_mode &&
+      cinfo->comps_in_scan)) { /* no pseudo SOS marker */
+    cinfo->block_size = DCTSIZE;
+    cinfo->natural_order = jpeg_natural_order;
+    cinfo->lim_Se = DCTSIZE2-1;
+  } else
+    switch (cinfo->Se) {
+    case (1*1-1):
+      cinfo->block_size = 1;
+      cinfo->natural_order = jpeg_natural_order; /* not needed */
+      cinfo->lim_Se = cinfo->Se;
+      break;
+    case (2*2-1):
+      cinfo->block_size = 2;
+      cinfo->natural_order = jpeg_natural_order2;
+      cinfo->lim_Se = cinfo->Se;
+      break;
+    case (3*3-1):
+      cinfo->block_size = 3;
+      cinfo->natural_order = jpeg_natural_order3;
+      cinfo->lim_Se = cinfo->Se;
+      break;
+    case (4*4-1):
+      cinfo->block_size = 4;
+      cinfo->natural_order = jpeg_natural_order4;
+      cinfo->lim_Se = cinfo->Se;
+      break;
+    case (5*5-1):
+      cinfo->block_size = 5;
+      cinfo->natural_order = jpeg_natural_order5;
+      cinfo->lim_Se = cinfo->Se;
+      break;
+    case (6*6-1):
+      cinfo->block_size = 6;
+      cinfo->natural_order = jpeg_natural_order6;
+      cinfo->lim_Se = cinfo->Se;
+      break;
+    case (7*7-1):
+      cinfo->block_size = 7;
+      cinfo->natural_order = jpeg_natural_order7;
+      cinfo->lim_Se = cinfo->Se;
+      break;
+    case (8*8-1):
+      cinfo->block_size = 8;
+      cinfo->natural_order = jpeg_natural_order;
+      cinfo->lim_Se = DCTSIZE2-1;
+      break;
+    case (9*9-1):
+      cinfo->block_size = 9;
+      cinfo->natural_order = jpeg_natural_order;
+      cinfo->lim_Se = DCTSIZE2-1;
+      break;
+    case (10*10-1):
+      cinfo->block_size = 10;
+      cinfo->natural_order = jpeg_natural_order;
+      cinfo->lim_Se = DCTSIZE2-1;
+      break;
+    case (11*11-1):
+      cinfo->block_size = 11;
+      cinfo->natural_order = jpeg_natural_order;
+      cinfo->lim_Se = DCTSIZE2-1;
+      break;
+    case (12*12-1):
+      cinfo->block_size = 12;
+      cinfo->natural_order = jpeg_natural_order;
+      cinfo->lim_Se = DCTSIZE2-1;
+      break;
+    case (13*13-1):
+      cinfo->block_size = 13;
+      cinfo->natural_order = jpeg_natural_order;
+      cinfo->lim_Se = DCTSIZE2-1;
+      break;
+    case (14*14-1):
+      cinfo->block_size = 14;
+      cinfo->natural_order = jpeg_natural_order;
+      cinfo->lim_Se = DCTSIZE2-1;
+      break;
+    case (15*15-1):
+      cinfo->block_size = 15;
+      cinfo->natural_order = jpeg_natural_order;
+      cinfo->lim_Se = DCTSIZE2-1;
+      break;
+    case (16*16-1):
+      cinfo->block_size = 16;
+      cinfo->natural_order = jpeg_natural_order;
+      cinfo->lim_Se = DCTSIZE2-1;
+      break;
+    default:
+      ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
+	       cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
+      break;
+    }
+
+  /* We initialize DCT_scaled_size and min_DCT_scaled_size to block_size.
+   * In the full decompressor,
+   * this will be overridden by jpeg_calc_output_dimensions in jdmaster.c;
+   * but in the transcoder,
+   * jpeg_calc_output_dimensions is not used, so we must do it here.
+   */
+  cinfo->min_DCT_h_scaled_size = cinfo->block_size;
+  cinfo->min_DCT_v_scaled_size = cinfo->block_size;
+
+  /* Compute dimensions of components */
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    compptr->DCT_h_scaled_size = cinfo->block_size;
+    compptr->DCT_v_scaled_size = cinfo->block_size;
+    /* Size in DCT blocks */
+    compptr->width_in_blocks = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
+		    (long) (cinfo->max_h_samp_factor * cinfo->block_size));
+    compptr->height_in_blocks = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
+		    (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+    /* downsampled_width and downsampled_height will also be overridden by
+     * jdmaster.c if we are doing full decompression.  The transcoder library
+     * doesn't use these values, but the calling application might.
+     */
+    /* Size in samples */
+    compptr->downsampled_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
+		    (long) cinfo->max_h_samp_factor);
+    compptr->downsampled_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
+		    (long) cinfo->max_v_samp_factor);
+    /* Mark component needed, until color conversion says otherwise */
+    compptr->component_needed = TRUE;
+    /* Mark no quantization table yet saved for component */
+    compptr->quant_table = NULL;
+  }
+
+  /* Compute number of fully interleaved MCU rows. */
+  cinfo->total_iMCU_rows = (JDIMENSION)
+    jdiv_round_up((long) cinfo->image_height,
+	          (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+
+  /* Decide whether file contains multiple scans */
+  if (cinfo->comps_in_scan < cinfo->num_components || cinfo->progressive_mode)
+    cinfo->inputctl->has_multiple_scans = TRUE;
+  else
+    cinfo->inputctl->has_multiple_scans = FALSE;
+}
+
+
+LOCAL(void)
+per_scan_setup (j_decompress_ptr cinfo)
+/* Do computations that are needed before processing a JPEG scan */
+/* cinfo->comps_in_scan and cinfo->cur_comp_info[] were set from SOS marker */
+{
+  int ci, mcublks, tmp;
+  jpeg_component_info *compptr;
+  
+  if (cinfo->comps_in_scan == 1) {
+    
+    /* Noninterleaved (single-component) scan */
+    compptr = cinfo->cur_comp_info[0];
+    
+    /* Overall image size in MCUs */
+    cinfo->MCUs_per_row = compptr->width_in_blocks;
+    cinfo->MCU_rows_in_scan = compptr->height_in_blocks;
+    
+    /* For noninterleaved scan, always one block per MCU */
+    compptr->MCU_width = 1;
+    compptr->MCU_height = 1;
+    compptr->MCU_blocks = 1;
+    compptr->MCU_sample_width = compptr->DCT_h_scaled_size;
+    compptr->last_col_width = 1;
+    /* For noninterleaved scans, it is convenient to define last_row_height
+     * as the number of block rows present in the last iMCU row.
+     */
+    tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+    if (tmp == 0) tmp = compptr->v_samp_factor;
+    compptr->last_row_height = tmp;
+    
+    /* Prepare array describing MCU composition */
+    cinfo->blocks_in_MCU = 1;
+    cinfo->MCU_membership[0] = 0;
+    
+  } else {
+    
+    /* Interleaved (multi-component) scan */
+    if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN)
+      ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan,
+	       MAX_COMPS_IN_SCAN);
+    
+    /* Overall image size in MCUs */
+    cinfo->MCUs_per_row = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width,
+		    (long) (cinfo->max_h_samp_factor * cinfo->block_size));
+    cinfo->MCU_rows_in_scan = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height,
+		    (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+    
+    cinfo->blocks_in_MCU = 0;
+    
+    for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+      compptr = cinfo->cur_comp_info[ci];
+      /* Sampling factors give # of blocks of component in each MCU */
+      compptr->MCU_width = compptr->h_samp_factor;
+      compptr->MCU_height = compptr->v_samp_factor;
+      compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
+      compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_h_scaled_size;
+      /* Figure number of non-dummy blocks in last MCU column & row */
+      tmp = (int) (compptr->width_in_blocks % compptr->MCU_width);
+      if (tmp == 0) tmp = compptr->MCU_width;
+      compptr->last_col_width = tmp;
+      tmp = (int) (compptr->height_in_blocks % compptr->MCU_height);
+      if (tmp == 0) tmp = compptr->MCU_height;
+      compptr->last_row_height = tmp;
+      /* Prepare array describing MCU composition */
+      mcublks = compptr->MCU_blocks;
+      if (cinfo->blocks_in_MCU + mcublks > D_MAX_BLOCKS_IN_MCU)
+	ERREXIT(cinfo, JERR_BAD_MCU_SIZE);
+      while (mcublks-- > 0) {
+	cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci;
+      }
+    }
+    
+  }
+}
+
+
+/*
+ * Save away a copy of the Q-table referenced by each component present
+ * in the current scan, unless already saved during a prior scan.
+ *
+ * In a multiple-scan JPEG file, the encoder could assign different components
+ * the same Q-table slot number, but change table definitions between scans
+ * so that each component uses a different Q-table.  (The IJG encoder is not
+ * currently capable of doing this, but other encoders might.)  Since we want
+ * to be able to dequantize all the components at the end of the file, this
+ * means that we have to save away the table actually used for each component.
+ * We do this by copying the table at the start of the first scan containing
+ * the component.
+ * The JPEG spec prohibits the encoder from changing the contents of a Q-table
+ * slot between scans of a component using that slot.  If the encoder does so
+ * anyway, this decoder will simply use the Q-table values that were current
+ * at the start of the first scan for the component.
+ *
+ * The decompressor output side looks only at the saved quant tables,
+ * not at the current Q-table slots.
+ */
+
+LOCAL(void)
+latch_quant_tables (j_decompress_ptr cinfo)
+{
+  int ci, qtblno;
+  jpeg_component_info *compptr;
+  JQUANT_TBL * qtbl;
+
+  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+    compptr = cinfo->cur_comp_info[ci];
+    /* No work if we already saved Q-table for this component */
+    if (compptr->quant_table != NULL)
+      continue;
+    /* Make sure specified quantization table is present */
+    qtblno = compptr->quant_tbl_no;
+    if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS ||
+	cinfo->quant_tbl_ptrs[qtblno] == NULL)
+      ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno);
+    /* OK, save away the quantization table */
+    qtbl = (JQUANT_TBL *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  SIZEOF(JQUANT_TBL));
+    MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL));
+    compptr->quant_table = qtbl;
+  }
+}
+
+
+/*
+ * Initialize the input modules to read a scan of compressed data.
+ * The first call to this is done by jdmaster.c after initializing
+ * the entire decompressor (during jpeg_start_decompress).
+ * Subsequent calls come from consume_markers, below.
+ */
+
+METHODDEF(void)
+start_input_pass (j_decompress_ptr cinfo)
+{
+  per_scan_setup(cinfo);
+  latch_quant_tables(cinfo);
+  (*cinfo->entropy->start_pass) (cinfo);
+  (*cinfo->coef->start_input_pass) (cinfo);
+  cinfo->inputctl->consume_input = cinfo->coef->consume_data;
+}
+
+
+/*
+ * Finish up after inputting a compressed-data scan.
+ * This is called by the coefficient controller after it's read all
+ * the expected data of the scan.
+ */
+
+METHODDEF(void)
+finish_input_pass (j_decompress_ptr cinfo)
+{
+  (*cinfo->entropy->finish_pass) (cinfo);
+  cinfo->inputctl->consume_input = consume_markers;
+}
+
+
+/*
+ * Read JPEG markers before, between, or after compressed-data scans.
+ * Change state as necessary when a new scan is reached.
+ * Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
+ *
+ * The consume_input method pointer points either here or to the
+ * coefficient controller's consume_data routine, depending on whether
+ * we are reading a compressed data segment or inter-segment markers.
+ *
+ * Note: This function should NOT return a pseudo SOS marker (with zero
+ * component number) to the caller.  A pseudo marker received by
+ * read_markers is processed and then skipped for other markers.
+ */
+
+METHODDEF(int)
+consume_markers (j_decompress_ptr cinfo)
+{
+  my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl;
+  int val;
+
+  if (inputctl->pub.eoi_reached) /* After hitting EOI, read no further */
+    return JPEG_REACHED_EOI;
+
+  for (;;) {			/* Loop to pass pseudo SOS marker */
+    val = (*cinfo->marker->read_markers) (cinfo);
+
+    switch (val) {
+    case JPEG_REACHED_SOS:	/* Found SOS */
+      if (inputctl->inheaders) { /* 1st SOS */
+	if (inputctl->inheaders == 1)
+	  initial_setup(cinfo);
+	if (cinfo->comps_in_scan == 0) { /* pseudo SOS marker */
+	  inputctl->inheaders = 2;
+	  break;
+	}
+	inputctl->inheaders = 0;
+	/* Note: start_input_pass must be called by jdmaster.c
+	 * before any more input can be consumed.  jdapimin.c is
+	 * responsible for enforcing this sequencing.
+	 */
+      } else {			/* 2nd or later SOS marker */
+	if (! inputctl->pub.has_multiple_scans)
+	  ERREXIT(cinfo, JERR_EOI_EXPECTED); /* Oops, I wasn't expecting this! */
+	if (cinfo->comps_in_scan == 0) /* unexpected pseudo SOS marker */
+	  break;
+	start_input_pass(cinfo);
+      }
+      return val;
+    case JPEG_REACHED_EOI:	/* Found EOI */
+      inputctl->pub.eoi_reached = TRUE;
+      if (inputctl->inheaders) { /* Tables-only datastream, apparently */
+	if (cinfo->marker->saw_SOF)
+	  ERREXIT(cinfo, JERR_SOF_NO_SOS);
+      } else {
+	/* Prevent infinite loop in coef ctlr's decompress_data routine
+	 * if user set output_scan_number larger than number of scans.
+	 */
+	if (cinfo->output_scan_number > cinfo->input_scan_number)
+	  cinfo->output_scan_number = cinfo->input_scan_number;
+      }
+      return val;
+    case JPEG_SUSPENDED:
+      return val;
+    default:
+      return val;
+    }
+  }
+}
+
+
+/*
+ * Reset state to begin a fresh datastream.
+ */
+
+METHODDEF(void)
+reset_input_controller (j_decompress_ptr cinfo)
+{
+  my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl;
+
+  inputctl->pub.consume_input = consume_markers;
+  inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */
+  inputctl->pub.eoi_reached = FALSE;
+  inputctl->inheaders = 1;
+  /* Reset other modules */
+  (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
+  (*cinfo->marker->reset_marker_reader) (cinfo);
+  /* Reset progression state -- would be cleaner if entropy decoder did this */
+  cinfo->coef_bits = NULL;
+}
+
+
+/*
+ * Initialize the input controller module.
+ * This is called only once, when the decompression object is created.
+ */
+
+GLOBAL(void)
+jinit_input_controller (j_decompress_ptr cinfo)
+{
+  my_inputctl_ptr inputctl;
+
+  /* Create subobject in permanent pool */
+  inputctl = (my_inputctl_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+				SIZEOF(my_input_controller));
+  cinfo->inputctl = &inputctl->pub;
+  /* Initialize method pointers */
+  inputctl->pub.consume_input = consume_markers;
+  inputctl->pub.reset_input_controller = reset_input_controller;
+  inputctl->pub.start_input_pass = start_input_pass;
+  inputctl->pub.finish_input_pass = finish_input_pass;
+  /* Initialize state: can't use reset_input_controller since we don't
+   * want to try to reset other modules yet.
+   */
+  inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */
+  inputctl->pub.eoi_reached = FALSE;
+  inputctl->inheaders = 1;
+}
diff --git a/source/Irrlicht/jpeglib/jdmainct.c b/source/Irrlicht/jpeglib/jdmainct.c
new file mode 100644
index 00000000..7ced4386
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jdmainct.c
@@ -0,0 +1,513 @@
+/*
+ * jdmainct.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2002-2012 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the main buffer controller for decompression.
+ * The main buffer lies between the JPEG decompressor proper and the
+ * post-processor; it holds downsampled data in the JPEG colorspace.
+ *
+ * Note that this code is bypassed in raw-data mode, since the application
+ * supplies the equivalent of the main buffer in that case.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * In the current system design, the main buffer need never be a full-image
+ * buffer; any full-height buffers will be found inside the coefficient or
+ * postprocessing controllers.  Nonetheless, the main controller is not
+ * trivial.  Its responsibility is to provide context rows for upsampling/
+ * rescaling, and doing this in an efficient fashion is a bit tricky.
+ *
+ * Postprocessor input data is counted in "row groups".  A row group
+ * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size)
+ * sample rows of each component.  (We require DCT_scaled_size values to be
+ * chosen such that these numbers are integers.  In practice DCT_scaled_size
+ * values will likely be powers of two, so we actually have the stronger
+ * condition that DCT_scaled_size / min_DCT_scaled_size is an integer.)
+ * Upsampling will typically produce max_v_samp_factor pixel rows from each
+ * row group (times any additional scale factor that the upsampler is
+ * applying).
+ *
+ * The coefficient controller will deliver data to us one iMCU row at a time;
+ * each iMCU row contains v_samp_factor * DCT_scaled_size sample rows, or
+ * exactly min_DCT_scaled_size row groups.  (This amount of data corresponds
+ * to one row of MCUs when the image is fully interleaved.)  Note that the
+ * number of sample rows varies across components, but the number of row
+ * groups does not.  Some garbage sample rows may be included in the last iMCU
+ * row at the bottom of the image.
+ *
+ * Depending on the vertical scaling algorithm used, the upsampler may need
+ * access to the sample row(s) above and below its current input row group.
+ * The upsampler is required to set need_context_rows TRUE at global selection
+ * time if so.  When need_context_rows is FALSE, this controller can simply
+ * obtain one iMCU row at a time from the coefficient controller and dole it
+ * out as row groups to the postprocessor.
+ *
+ * When need_context_rows is TRUE, this controller guarantees that the buffer
+ * passed to postprocessing contains at least one row group's worth of samples
+ * above and below the row group(s) being processed.  Note that the context
+ * rows "above" the first passed row group appear at negative row offsets in
+ * the passed buffer.  At the top and bottom of the image, the required
+ * context rows are manufactured by duplicating the first or last real sample
+ * row; this avoids having special cases in the upsampling inner loops.
+ *
+ * The amount of context is fixed at one row group just because that's a
+ * convenient number for this controller to work with.  The existing
+ * upsamplers really only need one sample row of context.  An upsampler
+ * supporting arbitrary output rescaling might wish for more than one row
+ * group of context when shrinking the image; tough, we don't handle that.
+ * (This is justified by the assumption that downsizing will be handled mostly
+ * by adjusting the DCT_scaled_size values, so that the actual scale factor at
+ * the upsample step needn't be much less than one.)
+ *
+ * To provide the desired context, we have to retain the last two row groups
+ * of one iMCU row while reading in the next iMCU row.  (The last row group
+ * can't be processed until we have another row group for its below-context,
+ * and so we have to save the next-to-last group too for its above-context.)
+ * We could do this most simply by copying data around in our buffer, but
+ * that'd be very slow.  We can avoid copying any data by creating a rather
+ * strange pointer structure.  Here's how it works.  We allocate a workspace
+ * consisting of M+2 row groups (where M = min_DCT_scaled_size is the number
+ * of row groups per iMCU row).  We create two sets of redundant pointers to
+ * the workspace.  Labeling the physical row groups 0 to M+1, the synthesized
+ * pointer lists look like this:
+ *                   M+1                          M-1
+ * master pointer --> 0         master pointer --> 0
+ *                    1                            1
+ *                   ...                          ...
+ *                   M-3                          M-3
+ *                   M-2                           M
+ *                   M-1                          M+1
+ *                    M                           M-2
+ *                   M+1                          M-1
+ *                    0                            0
+ * We read alternate iMCU rows using each master pointer; thus the last two
+ * row groups of the previous iMCU row remain un-overwritten in the workspace.
+ * The pointer lists are set up so that the required context rows appear to
+ * be adjacent to the proper places when we pass the pointer lists to the
+ * upsampler.
+ *
+ * The above pictures describe the normal state of the pointer lists.
+ * At top and bottom of the image, we diddle the pointer lists to duplicate
+ * the first or last sample row as necessary (this is cheaper than copying
+ * sample rows around).
+ *
+ * This scheme breaks down if M < 2, ie, min_DCT_scaled_size is 1.  In that
+ * situation each iMCU row provides only one row group so the buffering logic
+ * must be different (eg, we must read two iMCU rows before we can emit the
+ * first row group).  For now, we simply do not support providing context
+ * rows when min_DCT_scaled_size is 1.  That combination seems unlikely to
+ * be worth providing --- if someone wants a 1/8th-size preview, they probably
+ * want it quick and dirty, so a context-free upsampler is sufficient.
+ */
+
+
+/* Private buffer controller object */
+
+typedef struct {
+  struct jpeg_d_main_controller pub; /* public fields */
+
+  /* Pointer to allocated workspace (M or M+2 row groups). */
+  JSAMPARRAY buffer[MAX_COMPONENTS];
+
+  boolean buffer_full;		/* Have we gotten an iMCU row from decoder? */
+  JDIMENSION rowgroup_ctr;	/* counts row groups output to postprocessor */
+
+  /* Remaining fields are only used in the context case. */
+
+  /* These are the master pointers to the funny-order pointer lists. */
+  JSAMPIMAGE xbuffer[2];	/* pointers to weird pointer lists */
+
+  int whichptr;			/* indicates which pointer set is now in use */
+  int context_state;		/* process_data state machine status */
+  JDIMENSION rowgroups_avail;	/* row groups available to postprocessor */
+  JDIMENSION iMCU_row_ctr;	/* counts iMCU rows to detect image top/bot */
+} my_main_controller;
+
+typedef my_main_controller * my_main_ptr;
+
+/* context_state values: */
+#define CTX_PREPARE_FOR_IMCU	0	/* need to prepare for MCU row */
+#define CTX_PROCESS_IMCU	1	/* feeding iMCU to postprocessor */
+#define CTX_POSTPONED_ROW	2	/* feeding postponed row group */
+
+
+/* Forward declarations */
+METHODDEF(void) process_data_simple_main
+	JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,
+	     JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));
+METHODDEF(void) process_data_context_main
+	JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,
+	     JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));
+#ifdef QUANT_2PASS_SUPPORTED
+METHODDEF(void) process_data_crank_post
+	JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,
+	     JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));
+#endif
+
+
+LOCAL(void)
+alloc_funny_pointers (j_decompress_ptr cinfo)
+/* Allocate space for the funny pointer lists.
+ * This is done only once, not once per pass.
+ */
+{
+  my_main_ptr mainp = (my_main_ptr) cinfo->main;
+  int ci, rgroup;
+  int M = cinfo->min_DCT_v_scaled_size;
+  jpeg_component_info *compptr;
+  JSAMPARRAY xbuf;
+
+  /* Get top-level space for component array pointers.
+   * We alloc both arrays with one call to save a few cycles.
+   */
+  mainp->xbuffer[0] = (JSAMPIMAGE)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				cinfo->num_components * 2 * SIZEOF(JSAMPARRAY));
+  mainp->xbuffer[1] = mainp->xbuffer[0] + cinfo->num_components;
+
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+      cinfo->min_DCT_v_scaled_size; /* height of a row group of component */
+    /* Get space for pointer lists --- M+4 row groups in each list.
+     * We alloc both pointer lists with one call to save a few cycles.
+     */
+    xbuf = (JSAMPARRAY)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW));
+    xbuf += rgroup;		/* want one row group at negative offsets */
+    mainp->xbuffer[0][ci] = xbuf;
+    xbuf += rgroup * (M + 4);
+    mainp->xbuffer[1][ci] = xbuf;
+  }
+}
+
+
+LOCAL(void)
+make_funny_pointers (j_decompress_ptr cinfo)
+/* Create the funny pointer lists discussed in the comments above.
+ * The actual workspace is already allocated (in main->buffer),
+ * and the space for the pointer lists is allocated too.
+ * This routine just fills in the curiously ordered lists.
+ * This will be repeated at the beginning of each pass.
+ */
+{
+  my_main_ptr mainp = (my_main_ptr) cinfo->main;
+  int ci, i, rgroup;
+  int M = cinfo->min_DCT_v_scaled_size;
+  jpeg_component_info *compptr;
+  JSAMPARRAY buf, xbuf0, xbuf1;
+
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+      cinfo->min_DCT_v_scaled_size; /* height of a row group of component */
+    xbuf0 = mainp->xbuffer[0][ci];
+    xbuf1 = mainp->xbuffer[1][ci];
+    /* First copy the workspace pointers as-is */
+    buf = mainp->buffer[ci];
+    for (i = 0; i < rgroup * (M + 2); i++) {
+      xbuf0[i] = xbuf1[i] = buf[i];
+    }
+    /* In the second list, put the last four row groups in swapped order */
+    for (i = 0; i < rgroup * 2; i++) {
+      xbuf1[rgroup*(M-2) + i] = buf[rgroup*M + i];
+      xbuf1[rgroup*M + i] = buf[rgroup*(M-2) + i];
+    }
+    /* The wraparound pointers at top and bottom will be filled later
+     * (see set_wraparound_pointers, below).  Initially we want the "above"
+     * pointers to duplicate the first actual data line.  This only needs
+     * to happen in xbuffer[0].
+     */
+    for (i = 0; i < rgroup; i++) {
+      xbuf0[i - rgroup] = xbuf0[0];
+    }
+  }
+}
+
+
+LOCAL(void)
+set_wraparound_pointers (j_decompress_ptr cinfo)
+/* Set up the "wraparound" pointers at top and bottom of the pointer lists.
+ * This changes the pointer list state from top-of-image to the normal state.
+ */
+{
+  my_main_ptr mainp = (my_main_ptr) cinfo->main;
+  int ci, i, rgroup;
+  int M = cinfo->min_DCT_v_scaled_size;
+  jpeg_component_info *compptr;
+  JSAMPARRAY xbuf0, xbuf1;
+
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+      cinfo->min_DCT_v_scaled_size; /* height of a row group of component */
+    xbuf0 = mainp->xbuffer[0][ci];
+    xbuf1 = mainp->xbuffer[1][ci];
+    for (i = 0; i < rgroup; i++) {
+      xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i];
+      xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i];
+      xbuf0[rgroup*(M+2) + i] = xbuf0[i];
+      xbuf1[rgroup*(M+2) + i] = xbuf1[i];
+    }
+  }
+}
+
+
+LOCAL(void)
+set_bottom_pointers (j_decompress_ptr cinfo)
+/* Change the pointer lists to duplicate the last sample row at the bottom
+ * of the image.  whichptr indicates which xbuffer holds the final iMCU row.
+ * Also sets rowgroups_avail to indicate number of nondummy row groups in row.
+ */
+{
+  my_main_ptr mainp = (my_main_ptr) cinfo->main;
+  int ci, i, rgroup, iMCUheight, rows_left;
+  jpeg_component_info *compptr;
+  JSAMPARRAY xbuf;
+
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    /* Count sample rows in one iMCU row and in one row group */
+    iMCUheight = compptr->v_samp_factor * compptr->DCT_v_scaled_size;
+    rgroup = iMCUheight / cinfo->min_DCT_v_scaled_size;
+    /* Count nondummy sample rows remaining for this component */
+    rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight);
+    if (rows_left == 0) rows_left = iMCUheight;
+    /* Count nondummy row groups.  Should get same answer for each component,
+     * so we need only do it once.
+     */
+    if (ci == 0) {
+      mainp->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1);
+    }
+    /* Duplicate the last real sample row rgroup*2 times; this pads out the
+     * last partial rowgroup and ensures at least one full rowgroup of context.
+     */
+    xbuf = mainp->xbuffer[mainp->whichptr][ci];
+    for (i = 0; i < rgroup * 2; i++) {
+      xbuf[rows_left + i] = xbuf[rows_left-1];
+    }
+  }
+}
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+  my_main_ptr mainp = (my_main_ptr) cinfo->main;
+
+  switch (pass_mode) {
+  case JBUF_PASS_THRU:
+    if (cinfo->upsample->need_context_rows) {
+      mainp->pub.process_data = process_data_context_main;
+      make_funny_pointers(cinfo); /* Create the xbuffer[] lists */
+      mainp->whichptr = 0;	/* Read first iMCU row into xbuffer[0] */
+      mainp->context_state = CTX_PREPARE_FOR_IMCU;
+      mainp->iMCU_row_ctr = 0;
+    } else {
+      /* Simple case with no context needed */
+      mainp->pub.process_data = process_data_simple_main;
+    }
+    mainp->buffer_full = FALSE;	/* Mark buffer empty */
+    mainp->rowgroup_ctr = 0;
+    break;
+#ifdef QUANT_2PASS_SUPPORTED
+  case JBUF_CRANK_DEST:
+    /* For last pass of 2-pass quantization, just crank the postprocessor */
+    mainp->pub.process_data = process_data_crank_post;
+    break;
+#endif
+  default:
+    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+    break;
+  }
+}
+
+
+/*
+ * Process some data.
+ * This handles the simple case where no context is required.
+ */
+
+METHODDEF(void)
+process_data_simple_main (j_decompress_ptr cinfo,
+			  JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+			  JDIMENSION out_rows_avail)
+{
+  my_main_ptr mainp = (my_main_ptr) cinfo->main;
+  JDIMENSION rowgroups_avail;
+
+  /* Read input data if we haven't filled the main buffer yet */
+  if (! mainp->buffer_full) {
+    if (! (*cinfo->coef->decompress_data) (cinfo, mainp->buffer))
+      return;			/* suspension forced, can do nothing more */
+    mainp->buffer_full = TRUE;	/* OK, we have an iMCU row to work with */
+  }
+
+  /* There are always min_DCT_scaled_size row groups in an iMCU row. */
+  rowgroups_avail = (JDIMENSION) cinfo->min_DCT_v_scaled_size;
+  /* Note: at the bottom of the image, we may pass extra garbage row groups
+   * to the postprocessor.  The postprocessor has to check for bottom
+   * of image anyway (at row resolution), so no point in us doing it too.
+   */
+
+  /* Feed the postprocessor */
+  (*cinfo->post->post_process_data) (cinfo, mainp->buffer,
+				     &mainp->rowgroup_ctr, rowgroups_avail,
+				     output_buf, out_row_ctr, out_rows_avail);
+
+  /* Has postprocessor consumed all the data yet? If so, mark buffer empty */
+  if (mainp->rowgroup_ctr >= rowgroups_avail) {
+    mainp->buffer_full = FALSE;
+    mainp->rowgroup_ctr = 0;
+  }
+}
+
+
+/*
+ * Process some data.
+ * This handles the case where context rows must be provided.
+ */
+
+METHODDEF(void)
+process_data_context_main (j_decompress_ptr cinfo,
+			   JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+			   JDIMENSION out_rows_avail)
+{
+  my_main_ptr mainp = (my_main_ptr) cinfo->main;
+
+  /* Read input data if we haven't filled the main buffer yet */
+  if (! mainp->buffer_full) {
+    if (! (*cinfo->coef->decompress_data) (cinfo,
+					   mainp->xbuffer[mainp->whichptr]))
+      return;			/* suspension forced, can do nothing more */
+    mainp->buffer_full = TRUE;	/* OK, we have an iMCU row to work with */
+    mainp->iMCU_row_ctr++;	/* count rows received */
+  }
+
+  /* Postprocessor typically will not swallow all the input data it is handed
+   * in one call (due to filling the output buffer first).  Must be prepared
+   * to exit and restart.  This switch lets us keep track of how far we got.
+   * Note that each case falls through to the next on successful completion.
+   */
+  switch (mainp->context_state) {
+  case CTX_POSTPONED_ROW:
+    /* Call postprocessor using previously set pointers for postponed row */
+    (*cinfo->post->post_process_data) (cinfo, mainp->xbuffer[mainp->whichptr],
+			&mainp->rowgroup_ctr, mainp->rowgroups_avail,
+			output_buf, out_row_ctr, out_rows_avail);
+    if (mainp->rowgroup_ctr < mainp->rowgroups_avail)
+      return;			/* Need to suspend */
+    mainp->context_state = CTX_PREPARE_FOR_IMCU;
+    if (*out_row_ctr >= out_rows_avail)
+      return;			/* Postprocessor exactly filled output buf */
+    /*FALLTHROUGH*/
+  case CTX_PREPARE_FOR_IMCU:
+    /* Prepare to process first M-1 row groups of this iMCU row */
+    mainp->rowgroup_ctr = 0;
+    mainp->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_v_scaled_size - 1);
+    /* Check for bottom of image: if so, tweak pointers to "duplicate"
+     * the last sample row, and adjust rowgroups_avail to ignore padding rows.
+     */
+    if (mainp->iMCU_row_ctr == cinfo->total_iMCU_rows)
+      set_bottom_pointers(cinfo);
+    mainp->context_state = CTX_PROCESS_IMCU;
+    /*FALLTHROUGH*/
+  case CTX_PROCESS_IMCU:
+    /* Call postprocessor using previously set pointers */
+    (*cinfo->post->post_process_data) (cinfo, mainp->xbuffer[mainp->whichptr],
+			&mainp->rowgroup_ctr, mainp->rowgroups_avail,
+			output_buf, out_row_ctr, out_rows_avail);
+    if (mainp->rowgroup_ctr < mainp->rowgroups_avail)
+      return;			/* Need to suspend */
+    /* After the first iMCU, change wraparound pointers to normal state */
+    if (mainp->iMCU_row_ctr == 1)
+      set_wraparound_pointers(cinfo);
+    /* Prepare to load new iMCU row using other xbuffer list */
+    mainp->whichptr ^= 1;	/* 0=>1 or 1=>0 */
+    mainp->buffer_full = FALSE;
+    /* Still need to process last row group of this iMCU row, */
+    /* which is saved at index M+1 of the other xbuffer */
+    mainp->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_v_scaled_size + 1);
+    mainp->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_v_scaled_size + 2);
+    mainp->context_state = CTX_POSTPONED_ROW;
+  }
+}
+
+
+/*
+ * Process some data.
+ * Final pass of two-pass quantization: just call the postprocessor.
+ * Source data will be the postprocessor controller's internal buffer.
+ */
+
+#ifdef QUANT_2PASS_SUPPORTED
+
+METHODDEF(void)
+process_data_crank_post (j_decompress_ptr cinfo,
+			 JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+			 JDIMENSION out_rows_avail)
+{
+  (*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE) NULL,
+				     (JDIMENSION *) NULL, (JDIMENSION) 0,
+				     output_buf, out_row_ctr, out_rows_avail);
+}
+
+#endif /* QUANT_2PASS_SUPPORTED */
+
+
+/*
+ * Initialize main buffer controller.
+ */
+
+GLOBAL(void)
+jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
+{
+  my_main_ptr mainp;
+  int ci, rgroup, ngroups;
+  jpeg_component_info *compptr;
+
+  mainp = (my_main_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(my_main_controller));
+  cinfo->main = &mainp->pub;
+  mainp->pub.start_pass = start_pass_main;
+
+  if (need_full_buffer)		/* shouldn't happen */
+    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+
+  /* Allocate the workspace.
+   * ngroups is the number of row groups we need.
+   */
+  if (cinfo->upsample->need_context_rows) {
+    if (cinfo->min_DCT_v_scaled_size < 2) /* unsupported, see comments above */
+      ERREXIT(cinfo, JERR_NOTIMPL);
+    alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */
+    ngroups = cinfo->min_DCT_v_scaled_size + 2;
+  } else {
+    ngroups = cinfo->min_DCT_v_scaled_size;
+  }
+
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+      cinfo->min_DCT_v_scaled_size; /* height of a row group of component */
+    mainp->buffer[ci] = (*cinfo->mem->alloc_sarray)
+      ((j_common_ptr) cinfo, JPOOL_IMAGE,
+       compptr->width_in_blocks * ((JDIMENSION) compptr->DCT_h_scaled_size),
+       (JDIMENSION) (rgroup * ngroups));
+  }
+}
diff --git a/source/Irrlicht/jpeglib/jdmarker.c b/source/Irrlicht/jpeglib/jdmarker.c
new file mode 100644
index 00000000..b1faf88f
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jdmarker.c
@@ -0,0 +1,1511 @@
+/*
+ * jdmarker.c
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Modified 2009-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to decode JPEG datastream markers.
+ * Most of the complexity arises from our desire to support input
+ * suspension: if not all of the data for a marker is available,
+ * we must exit back to the application.  On resumption, we reprocess
+ * the marker.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+typedef enum {			/* JPEG marker codes */
+  M_SOF0  = 0xc0,
+  M_SOF1  = 0xc1,
+  M_SOF2  = 0xc2,
+  M_SOF3  = 0xc3,
+
+  M_SOF5  = 0xc5,
+  M_SOF6  = 0xc6,
+  M_SOF7  = 0xc7,
+
+  M_JPG   = 0xc8,
+  M_SOF9  = 0xc9,
+  M_SOF10 = 0xca,
+  M_SOF11 = 0xcb,
+
+  M_SOF13 = 0xcd,
+  M_SOF14 = 0xce,
+  M_SOF15 = 0xcf,
+
+  M_DHT   = 0xc4,
+
+  M_DAC   = 0xcc,
+
+  M_RST0  = 0xd0,
+  M_RST1  = 0xd1,
+  M_RST2  = 0xd2,
+  M_RST3  = 0xd3,
+  M_RST4  = 0xd4,
+  M_RST5  = 0xd5,
+  M_RST6  = 0xd6,
+  M_RST7  = 0xd7,
+
+  M_SOI   = 0xd8,
+  M_EOI   = 0xd9,
+  M_SOS   = 0xda,
+  M_DQT   = 0xdb,
+  M_DNL   = 0xdc,
+  M_DRI   = 0xdd,
+  M_DHP   = 0xde,
+  M_EXP   = 0xdf,
+
+  M_APP0  = 0xe0,
+  M_APP1  = 0xe1,
+  M_APP2  = 0xe2,
+  M_APP3  = 0xe3,
+  M_APP4  = 0xe4,
+  M_APP5  = 0xe5,
+  M_APP6  = 0xe6,
+  M_APP7  = 0xe7,
+  M_APP8  = 0xe8,
+  M_APP9  = 0xe9,
+  M_APP10 = 0xea,
+  M_APP11 = 0xeb,
+  M_APP12 = 0xec,
+  M_APP13 = 0xed,
+  M_APP14 = 0xee,
+  M_APP15 = 0xef,
+
+  M_JPG0  = 0xf0,
+  M_JPG8  = 0xf8,
+  M_JPG13 = 0xfd,
+  M_COM   = 0xfe,
+
+  M_TEM   = 0x01,
+
+  M_ERROR = 0x100
+} JPEG_MARKER;
+
+
+/* Private state */
+
+typedef struct {
+  struct jpeg_marker_reader pub; /* public fields */
+
+  /* Application-overridable marker processing methods */
+  jpeg_marker_parser_method process_COM;
+  jpeg_marker_parser_method process_APPn[16];
+
+  /* Limit on marker data length to save for each marker type */
+  unsigned int length_limit_COM;
+  unsigned int length_limit_APPn[16];
+
+  /* Status of COM/APPn marker saving */
+  jpeg_saved_marker_ptr cur_marker;	/* NULL if not processing a marker */
+  unsigned int bytes_read;		/* data bytes read so far in marker */
+  /* Note: cur_marker is not linked into marker_list until it's all read. */
+} my_marker_reader;
+
+typedef my_marker_reader * my_marker_ptr;
+
+
+/*
+ * Macros for fetching data from the data source module.
+ *
+ * At all times, cinfo->src->next_input_byte and ->bytes_in_buffer reflect
+ * the current restart point; we update them only when we have reached a
+ * suitable place to restart if a suspension occurs.
+ */
+
+/* Declare and initialize local copies of input pointer/count */
+#define INPUT_VARS(cinfo)  \
+	struct jpeg_source_mgr * datasrc = (cinfo)->src;  \
+	const JOCTET * next_input_byte = datasrc->next_input_byte;  \
+	size_t bytes_in_buffer = datasrc->bytes_in_buffer
+
+/* Unload the local copies --- do this only at a restart boundary */
+#define INPUT_SYNC(cinfo)  \
+	( datasrc->next_input_byte = next_input_byte,  \
+	  datasrc->bytes_in_buffer = bytes_in_buffer )
+
+/* Reload the local copies --- used only in MAKE_BYTE_AVAIL */
+#define INPUT_RELOAD(cinfo)  \
+	( next_input_byte = datasrc->next_input_byte,  \
+	  bytes_in_buffer = datasrc->bytes_in_buffer )
+
+/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available.
+ * Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+ * but we must reload the local copies after a successful fill.
+ */
+#define MAKE_BYTE_AVAIL(cinfo,action)  \
+	if (bytes_in_buffer == 0) {  \
+	  if (! (*datasrc->fill_input_buffer) (cinfo))  \
+	    { action; }  \
+	  INPUT_RELOAD(cinfo);  \
+	}
+
+/* Read a byte into variable V.
+ * If must suspend, take the specified action (typically "return FALSE").
+ */
+#define INPUT_BYTE(cinfo,V,action)  \
+	MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \
+		  bytes_in_buffer--; \
+		  V = GETJOCTET(*next_input_byte++); )
+
+/* As above, but read two bytes interpreted as an unsigned 16-bit integer.
+ * V should be declared unsigned int or perhaps INT32.
+ */
+#define INPUT_2BYTES(cinfo,V,action)  \
+	MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \
+		  bytes_in_buffer--; \
+		  V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \
+		  MAKE_BYTE_AVAIL(cinfo,action); \
+		  bytes_in_buffer--; \
+		  V += GETJOCTET(*next_input_byte++); )
+
+
+/*
+ * Routines to process JPEG markers.
+ *
+ * Entry condition: JPEG marker itself has been read and its code saved
+ *   in cinfo->unread_marker; input restart point is just after the marker.
+ *
+ * Exit: if return TRUE, have read and processed any parameters, and have
+ *   updated the restart point to point after the parameters.
+ *   If return FALSE, was forced to suspend before reaching end of
+ *   marker parameters; restart point has not been moved.  Same routine
+ *   will be called again after application supplies more input data.
+ *
+ * This approach to suspension assumes that all of a marker's parameters
+ * can fit into a single input bufferload.  This should hold for "normal"
+ * markers.  Some COM/APPn markers might have large parameter segments
+ * that might not fit.  If we are simply dropping such a marker, we use
+ * skip_input_data to get past it, and thereby put the problem on the
+ * source manager's shoulders.  If we are saving the marker's contents
+ * into memory, we use a slightly different convention: when forced to
+ * suspend, the marker processor updates the restart point to the end of
+ * what it's consumed (ie, the end of the buffer) before returning FALSE.
+ * On resumption, cinfo->unread_marker still contains the marker code,
+ * but the data source will point to the next chunk of marker data.
+ * The marker processor must retain internal state to deal with this.
+ *
+ * Note that we don't bother to avoid duplicate trace messages if a
+ * suspension occurs within marker parameters.  Other side effects
+ * require more care.
+ */
+
+
+LOCAL(boolean)
+get_soi (j_decompress_ptr cinfo)
+/* Process an SOI marker */
+{
+  int i;
+  
+  TRACEMS(cinfo, 1, JTRC_SOI);
+
+  if (cinfo->marker->saw_SOI)
+    ERREXIT(cinfo, JERR_SOI_DUPLICATE);
+
+  /* Reset all parameters that are defined to be reset by SOI */
+
+  for (i = 0; i < NUM_ARITH_TBLS; i++) {
+    cinfo->arith_dc_L[i] = 0;
+    cinfo->arith_dc_U[i] = 1;
+    cinfo->arith_ac_K[i] = 5;
+  }
+  cinfo->restart_interval = 0;
+
+  /* Set initial assumptions for colorspace etc */
+
+  cinfo->jpeg_color_space = JCS_UNKNOWN;
+  cinfo->color_transform = JCT_NONE;
+  cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling??? */
+
+  cinfo->saw_JFIF_marker = FALSE;
+  cinfo->JFIF_major_version = 1; /* set default JFIF APP0 values */
+  cinfo->JFIF_minor_version = 1;
+  cinfo->density_unit = 0;
+  cinfo->X_density = 1;
+  cinfo->Y_density = 1;
+  cinfo->saw_Adobe_marker = FALSE;
+  cinfo->Adobe_transform = 0;
+
+  cinfo->marker->saw_SOI = TRUE;
+
+  return TRUE;
+}
+
+
+LOCAL(boolean)
+get_sof (j_decompress_ptr cinfo, boolean is_baseline, boolean is_prog,
+	 boolean is_arith)
+/* Process a SOFn marker */
+{
+  INT32 length;
+  int c, ci, i;
+  jpeg_component_info * compptr;
+  INPUT_VARS(cinfo);
+
+  cinfo->is_baseline = is_baseline;
+  cinfo->progressive_mode = is_prog;
+  cinfo->arith_code = is_arith;
+
+  INPUT_2BYTES(cinfo, length, return FALSE);
+
+  INPUT_BYTE(cinfo, cinfo->data_precision, return FALSE);
+  INPUT_2BYTES(cinfo, cinfo->image_height, return FALSE);
+  INPUT_2BYTES(cinfo, cinfo->image_width, return FALSE);
+  INPUT_BYTE(cinfo, cinfo->num_components, return FALSE);
+
+  length -= 8;
+
+  TRACEMS4(cinfo, 1, JTRC_SOF, cinfo->unread_marker,
+	   (int) cinfo->image_width, (int) cinfo->image_height,
+	   cinfo->num_components);
+
+  if (cinfo->marker->saw_SOF)
+    ERREXIT(cinfo, JERR_SOF_DUPLICATE);
+
+  /* We don't support files in which the image height is initially specified */
+  /* as 0 and is later redefined by DNL.  As long as we have to check that,  */
+  /* might as well have a general sanity check. */
+  if (cinfo->image_height <= 0 || cinfo->image_width <= 0 ||
+      cinfo->num_components <= 0)
+    ERREXIT(cinfo, JERR_EMPTY_IMAGE);
+
+  if (length != (cinfo->num_components * 3))
+    ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+  if (cinfo->comp_info == NULL)	/* do only once, even if suspend */
+    cinfo->comp_info = (jpeg_component_info *) (*cinfo->mem->alloc_small)
+			((j_common_ptr) cinfo, JPOOL_IMAGE,
+			 cinfo->num_components * SIZEOF(jpeg_component_info));
+
+  for (ci = 0; ci < cinfo->num_components; ci++) {
+    INPUT_BYTE(cinfo, c, return FALSE);
+    /* Check to see whether component id has already been seen   */
+    /* (in violation of the spec, but unfortunately seen in some */
+    /* files).  If so, create "fake" component id equal to the   */
+    /* max id seen so far + 1. */
+    for (i = 0, compptr = cinfo->comp_info; i < ci; i++, compptr++) {
+      if (c == compptr->component_id) {
+	compptr = cinfo->comp_info;
+	c = compptr->component_id;
+	compptr++;
+	for (i = 1; i < ci; i++, compptr++) {
+	  if (compptr->component_id > c) c = compptr->component_id;
+	}
+	c++;
+	break;
+      }
+    }
+    compptr->component_id = c;
+    compptr->component_index = ci;
+    INPUT_BYTE(cinfo, c, return FALSE);
+    compptr->h_samp_factor = (c >> 4) & 15;
+    compptr->v_samp_factor = (c     ) & 15;
+    INPUT_BYTE(cinfo, compptr->quant_tbl_no, return FALSE);
+
+    TRACEMS4(cinfo, 1, JTRC_SOF_COMPONENT,
+	     compptr->component_id, compptr->h_samp_factor,
+	     compptr->v_samp_factor, compptr->quant_tbl_no);
+  }
+
+  cinfo->marker->saw_SOF = TRUE;
+
+  INPUT_SYNC(cinfo);
+  return TRUE;
+}
+
+
+LOCAL(boolean)
+get_sos (j_decompress_ptr cinfo)
+/* Process a SOS marker */
+{
+  INT32 length;
+  int c, ci, i, n;
+  jpeg_component_info * compptr;
+  INPUT_VARS(cinfo);
+
+  if (! cinfo->marker->saw_SOF)
+    ERREXITS(cinfo, JERR_SOF_BEFORE, "SOS");
+
+  INPUT_2BYTES(cinfo, length, return FALSE);
+
+  INPUT_BYTE(cinfo, n, return FALSE); /* Number of components */
+
+  TRACEMS1(cinfo, 1, JTRC_SOS, n);
+
+  if (length != (n * 2 + 6) || n > MAX_COMPS_IN_SCAN ||
+      (n == 0 && !cinfo->progressive_mode))
+      /* pseudo SOS marker only allowed in progressive mode */
+    ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+  cinfo->comps_in_scan = n;
+
+  /* Collect the component-spec parameters */
+
+  for (i = 0; i < n; i++) {
+    INPUT_BYTE(cinfo, c, return FALSE);
+
+    /* Detect the case where component id's are not unique, and, if so, */
+    /* create a fake component id using the same logic as in get_sof.   */
+    /* Note:  This also ensures that all of the SOF components are      */
+    /* referenced in the single scan case, which prevents access to     */
+    /* uninitialized memory in later decoding stages. */
+    for (ci = 0; ci < i; ci++) {
+      if (c == cinfo->cur_comp_info[ci]->component_id) {
+	c = cinfo->cur_comp_info[0]->component_id;
+	for (ci = 1; ci < i; ci++) {
+	  compptr = cinfo->cur_comp_info[ci];
+	  if (compptr->component_id > c) c = compptr->component_id;
+	}
+	c++;
+	break;
+      }
+    }
+
+    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+	 ci++, compptr++) {
+      if (c == compptr->component_id)
+	goto id_found;
+    }
+
+    ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, c);
+
+  id_found:
+
+    cinfo->cur_comp_info[i] = compptr;
+    INPUT_BYTE(cinfo, c, return FALSE);
+    compptr->dc_tbl_no = (c >> 4) & 15;
+    compptr->ac_tbl_no = (c     ) & 15;
+
+    TRACEMS3(cinfo, 1, JTRC_SOS_COMPONENT, compptr->component_id,
+	     compptr->dc_tbl_no, compptr->ac_tbl_no);
+  }
+
+  /* Collect the additional scan parameters Ss, Se, Ah/Al. */
+  INPUT_BYTE(cinfo, c, return FALSE);
+  cinfo->Ss = c;
+  INPUT_BYTE(cinfo, c, return FALSE);
+  cinfo->Se = c;
+  INPUT_BYTE(cinfo, c, return FALSE);
+  cinfo->Ah = (c >> 4) & 15;
+  cinfo->Al = (c     ) & 15;
+
+  TRACEMS4(cinfo, 1, JTRC_SOS_PARAMS, cinfo->Ss, cinfo->Se,
+	   cinfo->Ah, cinfo->Al);
+
+  /* Prepare to scan data & restart markers */
+  cinfo->marker->next_restart_num = 0;
+
+  /* Count another (non-pseudo) SOS marker */
+  if (n) cinfo->input_scan_number++;
+
+  INPUT_SYNC(cinfo);
+  return TRUE;
+}
+
+
+#ifdef D_ARITH_CODING_SUPPORTED
+
+LOCAL(boolean)
+get_dac (j_decompress_ptr cinfo)
+/* Process a DAC marker */
+{
+  INT32 length;
+  int index, val;
+  INPUT_VARS(cinfo);
+
+  INPUT_2BYTES(cinfo, length, return FALSE);
+  length -= 2;
+  
+  while (length > 0) {
+    INPUT_BYTE(cinfo, index, return FALSE);
+    INPUT_BYTE(cinfo, val, return FALSE);
+
+    length -= 2;
+
+    TRACEMS2(cinfo, 1, JTRC_DAC, index, val);
+
+    if (index < 0 || index >= (2*NUM_ARITH_TBLS))
+      ERREXIT1(cinfo, JERR_DAC_INDEX, index);
+
+    if (index >= NUM_ARITH_TBLS) { /* define AC table */
+      cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = (UINT8) val;
+    } else {			/* define DC table */
+      cinfo->arith_dc_L[index] = (UINT8) (val & 0x0F);
+      cinfo->arith_dc_U[index] = (UINT8) (val >> 4);
+      if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index])
+	ERREXIT1(cinfo, JERR_DAC_VALUE, val);
+    }
+  }
+
+  if (length != 0)
+    ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+  INPUT_SYNC(cinfo);
+  return TRUE;
+}
+
+#else /* ! D_ARITH_CODING_SUPPORTED */
+
+#define get_dac(cinfo)  skip_variable(cinfo)
+
+#endif /* D_ARITH_CODING_SUPPORTED */
+
+
+LOCAL(boolean)
+get_dht (j_decompress_ptr cinfo)
+/* Process a DHT marker */
+{
+  INT32 length;
+  UINT8 bits[17];
+  UINT8 huffval[256];
+  int i, index, count;
+  JHUFF_TBL **htblptr;
+  INPUT_VARS(cinfo);
+
+  INPUT_2BYTES(cinfo, length, return FALSE);
+  length -= 2;
+  
+  while (length > 16) {
+    INPUT_BYTE(cinfo, index, return FALSE);
+
+    TRACEMS1(cinfo, 1, JTRC_DHT, index);
+      
+    bits[0] = 0;
+    count = 0;
+    for (i = 1; i <= 16; i++) {
+      INPUT_BYTE(cinfo, bits[i], return FALSE);
+      count += bits[i];
+    }
+
+    length -= 1 + 16;
+
+    TRACEMS8(cinfo, 2, JTRC_HUFFBITS,
+	     bits[1], bits[2], bits[3], bits[4],
+	     bits[5], bits[6], bits[7], bits[8]);
+    TRACEMS8(cinfo, 2, JTRC_HUFFBITS,
+	     bits[9], bits[10], bits[11], bits[12],
+	     bits[13], bits[14], bits[15], bits[16]);
+
+    /* Here we just do minimal validation of the counts to avoid walking
+     * off the end of our table space.  jdhuff.c will check more carefully.
+     */
+    if (count > 256 || ((INT32) count) > length)
+      ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+
+    MEMZERO(huffval, SIZEOF(huffval)); /* pre-zero array for later copy */
+
+    for (i = 0; i < count; i++)
+      INPUT_BYTE(cinfo, huffval[i], return FALSE);
+
+    length -= count;
+
+    if (index & 0x10) {		/* AC table definition */
+      index -= 0x10;
+      htblptr = &cinfo->ac_huff_tbl_ptrs[index];
+    } else {			/* DC table definition */
+      htblptr = &cinfo->dc_huff_tbl_ptrs[index];
+    }
+
+    if (index < 0 || index >= NUM_HUFF_TBLS)
+      ERREXIT1(cinfo, JERR_DHT_INDEX, index);
+
+    if (*htblptr == NULL)
+      *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
+  
+    MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits));
+    MEMCOPY((*htblptr)->huffval, huffval, SIZEOF((*htblptr)->huffval));
+  }
+
+  if (length != 0)
+    ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+  INPUT_SYNC(cinfo);
+  return TRUE;
+}
+
+
+LOCAL(boolean)
+get_dqt (j_decompress_ptr cinfo)
+/* Process a DQT marker */
+{
+  INT32 length, count, i;
+  int n, prec;
+  unsigned int tmp;
+  JQUANT_TBL *quant_ptr;
+  const int *natural_order;
+  INPUT_VARS(cinfo);
+
+  INPUT_2BYTES(cinfo, length, return FALSE);
+  length -= 2;
+
+  while (length > 0) {
+    length--;
+    INPUT_BYTE(cinfo, n, return FALSE);
+    prec = n >> 4;
+    n &= 0x0F;
+
+    TRACEMS2(cinfo, 1, JTRC_DQT, n, prec);
+
+    if (n >= NUM_QUANT_TBLS)
+      ERREXIT1(cinfo, JERR_DQT_INDEX, n);
+      
+    if (cinfo->quant_tbl_ptrs[n] == NULL)
+      cinfo->quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) cinfo);
+    quant_ptr = cinfo->quant_tbl_ptrs[n];
+
+    if (prec) {
+      if (length < DCTSIZE2 * 2) {
+	/* Initialize full table for safety. */
+	for (i = 0; i < DCTSIZE2; i++) {
+	  quant_ptr->quantval[i] = 1;
+	}
+	count = length >> 1;
+      } else
+	count = DCTSIZE2;
+    } else {
+      if (length < DCTSIZE2) {
+	/* Initialize full table for safety. */
+	for (i = 0; i < DCTSIZE2; i++) {
+	  quant_ptr->quantval[i] = 1;
+	}
+	count = length;
+      } else
+	count = DCTSIZE2;
+    }
+
+    switch (count) {
+    case (2*2): natural_order = jpeg_natural_order2; break;
+    case (3*3): natural_order = jpeg_natural_order3; break;
+    case (4*4): natural_order = jpeg_natural_order4; break;
+    case (5*5): natural_order = jpeg_natural_order5; break;
+    case (6*6): natural_order = jpeg_natural_order6; break;
+    case (7*7): natural_order = jpeg_natural_order7; break;
+    default:    natural_order = jpeg_natural_order;  break;
+    }
+
+    for (i = 0; i < count; i++) {
+      if (prec)
+	INPUT_2BYTES(cinfo, tmp, return FALSE);
+      else
+	INPUT_BYTE(cinfo, tmp, return FALSE);
+      /* We convert the zigzag-order table to natural array order. */
+      quant_ptr->quantval[natural_order[i]] = (UINT16) tmp;
+    }
+
+    if (cinfo->err->trace_level >= 2) {
+      for (i = 0; i < DCTSIZE2; i += 8) {
+	TRACEMS8(cinfo, 2, JTRC_QUANTVALS,
+		 quant_ptr->quantval[i],   quant_ptr->quantval[i+1],
+		 quant_ptr->quantval[i+2], quant_ptr->quantval[i+3],
+		 quant_ptr->quantval[i+4], quant_ptr->quantval[i+5],
+		 quant_ptr->quantval[i+6], quant_ptr->quantval[i+7]);
+      }
+    }
+
+    length -= count;
+    if (prec) length -= count;
+  }
+
+  if (length != 0)
+    ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+  INPUT_SYNC(cinfo);
+  return TRUE;
+}
+
+
+LOCAL(boolean)
+get_dri (j_decompress_ptr cinfo)
+/* Process a DRI marker */
+{
+  INT32 length;
+  unsigned int tmp;
+  INPUT_VARS(cinfo);
+
+  INPUT_2BYTES(cinfo, length, return FALSE);
+  
+  if (length != 4)
+    ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+  INPUT_2BYTES(cinfo, tmp, return FALSE);
+
+  TRACEMS1(cinfo, 1, JTRC_DRI, tmp);
+
+  cinfo->restart_interval = tmp;
+
+  INPUT_SYNC(cinfo);
+  return TRUE;
+}
+
+
+LOCAL(boolean)
+get_lse (j_decompress_ptr cinfo)
+/* Process an LSE marker */
+{
+  INT32 length;
+  unsigned int tmp;
+  int cid;
+  INPUT_VARS(cinfo);
+
+  if (! cinfo->marker->saw_SOF)
+    ERREXITS(cinfo, JERR_SOF_BEFORE, "LSE");
+
+  if (cinfo->num_components < 3) goto bad;
+
+  INPUT_2BYTES(cinfo, length, return FALSE);
+
+  if (length != 24)
+    ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+  INPUT_BYTE(cinfo, tmp, return FALSE);
+  if (tmp != 0x0D)	/* ID inverse transform specification */
+    ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker);
+  INPUT_2BYTES(cinfo, tmp, return FALSE);
+  if (tmp != MAXJSAMPLE) goto bad;		/* MAXTRANS */
+  INPUT_BYTE(cinfo, tmp, return FALSE);
+  if (tmp != 3) goto bad;			/* Nt=3 */
+  INPUT_BYTE(cinfo, cid, return FALSE);
+  if (cid != cinfo->comp_info[1].component_id) goto bad;
+  INPUT_BYTE(cinfo, cid, return FALSE);
+  if (cid != cinfo->comp_info[0].component_id) goto bad;
+  INPUT_BYTE(cinfo, cid, return FALSE);
+  if (cid != cinfo->comp_info[2].component_id) goto bad;
+  INPUT_BYTE(cinfo, tmp, return FALSE);
+  if (tmp != 0x80) goto bad;		/* F1: CENTER1=1, NORM1=0 */
+  INPUT_2BYTES(cinfo, tmp, return FALSE);
+  if (tmp != 0) goto bad;			/* A(1,1)=0 */
+  INPUT_2BYTES(cinfo, tmp, return FALSE);
+  if (tmp != 0) goto bad;			/* A(1,2)=0 */
+  INPUT_BYTE(cinfo, tmp, return FALSE);
+  if (tmp != 0) goto bad;		/* F2: CENTER2=0, NORM2=0 */
+  INPUT_2BYTES(cinfo, tmp, return FALSE);
+  if (tmp != 1) goto bad;			/* A(2,1)=1 */
+  INPUT_2BYTES(cinfo, tmp, return FALSE);
+  if (tmp != 0) goto bad;			/* A(2,2)=0 */
+  INPUT_BYTE(cinfo, tmp, return FALSE);
+  if (tmp != 0) goto bad;		/* F3: CENTER3=0, NORM3=0 */
+  INPUT_2BYTES(cinfo, tmp, return FALSE);
+  if (tmp != 1) goto bad;			/* A(3,1)=1 */
+  INPUT_2BYTES(cinfo, tmp, return FALSE);
+  if (tmp != 0) {				/* A(3,2)=0 */
+    bad:
+    ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+  }
+
+  /* OK, valid transform that we can handle. */
+  cinfo->color_transform = JCT_SUBTRACT_GREEN;
+
+  INPUT_SYNC(cinfo);
+  return TRUE;
+}
+
+
+/*
+ * Routines for processing APPn and COM markers.
+ * These are either saved in memory or discarded, per application request.
+ * APP0 and APP14 are specially checked to see if they are
+ * JFIF and Adobe markers, respectively.
+ */
+
+#define APP0_DATA_LEN	14	/* Length of interesting data in APP0 */
+#define APP14_DATA_LEN	12	/* Length of interesting data in APP14 */
+#define APPN_DATA_LEN	14	/* Must be the largest of the above!! */
+
+
+LOCAL(void)
+examine_app0 (j_decompress_ptr cinfo, JOCTET FAR * data,
+	      unsigned int datalen, INT32 remaining)
+/* Examine first few bytes from an APP0.
+ * Take appropriate action if it is a JFIF marker.
+ * datalen is # of bytes at data[], remaining is length of rest of marker data.
+ */
+{
+  INT32 totallen = (INT32) datalen + remaining;
+
+  if (datalen >= APP0_DATA_LEN &&
+      GETJOCTET(data[0]) == 0x4A &&
+      GETJOCTET(data[1]) == 0x46 &&
+      GETJOCTET(data[2]) == 0x49 &&
+      GETJOCTET(data[3]) == 0x46 &&
+      GETJOCTET(data[4]) == 0) {
+    /* Found JFIF APP0 marker: save info */
+    cinfo->saw_JFIF_marker = TRUE;
+    cinfo->JFIF_major_version = GETJOCTET(data[5]);
+    cinfo->JFIF_minor_version = GETJOCTET(data[6]);
+    cinfo->density_unit = GETJOCTET(data[7]);
+    cinfo->X_density = (GETJOCTET(data[8]) << 8) + GETJOCTET(data[9]);
+    cinfo->Y_density = (GETJOCTET(data[10]) << 8) + GETJOCTET(data[11]);
+    /* Check version.
+     * Major version must be 1 or 2, anything else signals an incompatible
+     * change.
+     * (We used to treat this as an error, but now it's a nonfatal warning,
+     * because some bozo at Hijaak couldn't read the spec.)
+     * Minor version should be 0..2, but process anyway if newer.
+     */
+    if (cinfo->JFIF_major_version != 1 && cinfo->JFIF_major_version != 2)
+      WARNMS2(cinfo, JWRN_JFIF_MAJOR,
+	      cinfo->JFIF_major_version, cinfo->JFIF_minor_version);
+    /* Generate trace messages */
+    TRACEMS5(cinfo, 1, JTRC_JFIF,
+	     cinfo->JFIF_major_version, cinfo->JFIF_minor_version,
+	     cinfo->X_density, cinfo->Y_density, cinfo->density_unit);
+    /* Validate thumbnail dimensions and issue appropriate messages */
+    if (GETJOCTET(data[12]) | GETJOCTET(data[13]))
+      TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL,
+	       GETJOCTET(data[12]), GETJOCTET(data[13]));
+    totallen -= APP0_DATA_LEN;
+    if (totallen !=
+	((INT32)GETJOCTET(data[12]) * (INT32)GETJOCTET(data[13]) * (INT32) 3))
+      TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) totallen);
+  } else if (datalen >= 6 &&
+      GETJOCTET(data[0]) == 0x4A &&
+      GETJOCTET(data[1]) == 0x46 &&
+      GETJOCTET(data[2]) == 0x58 &&
+      GETJOCTET(data[3]) == 0x58 &&
+      GETJOCTET(data[4]) == 0) {
+    /* Found JFIF "JFXX" extension APP0 marker */
+    /* The library doesn't actually do anything with these,
+     * but we try to produce a helpful trace message.
+     */
+    switch (GETJOCTET(data[5])) {
+    case 0x10:
+      TRACEMS1(cinfo, 1, JTRC_THUMB_JPEG, (int) totallen);
+      break;
+    case 0x11:
+      TRACEMS1(cinfo, 1, JTRC_THUMB_PALETTE, (int) totallen);
+      break;
+    case 0x13:
+      TRACEMS1(cinfo, 1, JTRC_THUMB_RGB, (int) totallen);
+      break;
+    default:
+      TRACEMS2(cinfo, 1, JTRC_JFIF_EXTENSION,
+	       GETJOCTET(data[5]), (int) totallen);
+      break;
+    }
+  } else {
+    /* Start of APP0 does not match "JFIF" or "JFXX", or too short */
+    TRACEMS1(cinfo, 1, JTRC_APP0, (int) totallen);
+  }
+}
+
+
+LOCAL(void)
+examine_app14 (j_decompress_ptr cinfo, JOCTET FAR * data,
+	       unsigned int datalen, INT32 remaining)
+/* Examine first few bytes from an APP14.
+ * Take appropriate action if it is an Adobe marker.
+ * datalen is # of bytes at data[], remaining is length of rest of marker data.
+ */
+{
+  unsigned int version, flags0, flags1, transform;
+
+  if (datalen >= APP14_DATA_LEN &&
+      GETJOCTET(data[0]) == 0x41 &&
+      GETJOCTET(data[1]) == 0x64 &&
+      GETJOCTET(data[2]) == 0x6F &&
+      GETJOCTET(data[3]) == 0x62 &&
+      GETJOCTET(data[4]) == 0x65) {
+    /* Found Adobe APP14 marker */
+    version = (GETJOCTET(data[5]) << 8) + GETJOCTET(data[6]);
+    flags0 = (GETJOCTET(data[7]) << 8) + GETJOCTET(data[8]);
+    flags1 = (GETJOCTET(data[9]) << 8) + GETJOCTET(data[10]);
+    transform = GETJOCTET(data[11]);
+    TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform);
+    cinfo->saw_Adobe_marker = TRUE;
+    cinfo->Adobe_transform = (UINT8) transform;
+  } else {
+    /* Start of APP14 does not match "Adobe", or too short */
+    TRACEMS1(cinfo, 1, JTRC_APP14, (int) (datalen + remaining));
+  }
+}
+
+
+METHODDEF(boolean)
+get_interesting_appn (j_decompress_ptr cinfo)
+/* Process an APP0 or APP14 marker without saving it */
+{
+  INT32 length;
+  JOCTET b[APPN_DATA_LEN];
+  unsigned int i, numtoread;
+  INPUT_VARS(cinfo);
+
+  INPUT_2BYTES(cinfo, length, return FALSE);
+  length -= 2;
+
+  /* get the interesting part of the marker data */
+  if (length >= APPN_DATA_LEN)
+    numtoread = APPN_DATA_LEN;
+  else if (length > 0)
+    numtoread = (unsigned int) length;
+  else
+    numtoread = 0;
+  for (i = 0; i < numtoread; i++)
+    INPUT_BYTE(cinfo, b[i], return FALSE);
+  length -= numtoread;
+
+  /* process it */
+  switch (cinfo->unread_marker) {
+  case M_APP0:
+    examine_app0(cinfo, (JOCTET FAR *) b, numtoread, length);
+    break;
+  case M_APP14:
+    examine_app14(cinfo, (JOCTET FAR *) b, numtoread, length);
+    break;
+  default:
+    /* can't get here unless jpeg_save_markers chooses wrong processor */
+    ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker);
+    break;
+  }
+
+  /* skip any remaining data -- could be lots */
+  INPUT_SYNC(cinfo);
+  if (length > 0)
+    (*cinfo->src->skip_input_data) (cinfo, (long) length);
+
+  return TRUE;
+}
+
+
+#ifdef SAVE_MARKERS_SUPPORTED
+
+METHODDEF(boolean)
+save_marker (j_decompress_ptr cinfo)
+/* Save an APPn or COM marker into the marker list */
+{
+  my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
+  jpeg_saved_marker_ptr cur_marker = marker->cur_marker;
+  unsigned int bytes_read, data_length;
+  JOCTET FAR * data;
+  INT32 length = 0;
+  INPUT_VARS(cinfo);
+
+  if (cur_marker == NULL) {
+    /* begin reading a marker */
+    INPUT_2BYTES(cinfo, length, return FALSE);
+    length -= 2;
+    if (length >= 0) {		/* watch out for bogus length word */
+      /* figure out how much we want to save */
+      unsigned int limit;
+      if (cinfo->unread_marker == (int) M_COM)
+	limit = marker->length_limit_COM;
+      else
+	limit = marker->length_limit_APPn[cinfo->unread_marker - (int) M_APP0];
+      if ((unsigned int) length < limit)
+	limit = (unsigned int) length;
+      /* allocate and initialize the marker item */
+      cur_marker = (jpeg_saved_marker_ptr)
+	(*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				    SIZEOF(struct jpeg_marker_struct) + limit);
+      cur_marker->next = NULL;
+      cur_marker->marker = (UINT8) cinfo->unread_marker;
+      cur_marker->original_length = (unsigned int) length;
+      cur_marker->data_length = limit;
+      /* data area is just beyond the jpeg_marker_struct */
+      data = cur_marker->data = (JOCTET FAR *) (cur_marker + 1);
+      marker->cur_marker = cur_marker;
+      marker->bytes_read = 0;
+      bytes_read = 0;
+      data_length = limit;
+    } else {
+      /* deal with bogus length word */
+      bytes_read = data_length = 0;
+      data = NULL;
+    }
+  } else {
+    /* resume reading a marker */
+    bytes_read = marker->bytes_read;
+    data_length = cur_marker->data_length;
+    data = cur_marker->data + bytes_read;
+  }
+
+  while (bytes_read < data_length) {
+    INPUT_SYNC(cinfo);		/* move the restart point to here */
+    marker->bytes_read = bytes_read;
+    /* If there's not at least one byte in buffer, suspend */
+    MAKE_BYTE_AVAIL(cinfo, return FALSE);
+    /* Copy bytes with reasonable rapidity */
+    while (bytes_read < data_length && bytes_in_buffer > 0) {
+      *data++ = *next_input_byte++;
+      bytes_in_buffer--;
+      bytes_read++;
+    }
+  }
+
+  /* Done reading what we want to read */
+  if (cur_marker != NULL) {	/* will be NULL if bogus length word */
+    /* Add new marker to end of list */
+    if (cinfo->marker_list == NULL) {
+      cinfo->marker_list = cur_marker;
+    } else {
+      jpeg_saved_marker_ptr prev = cinfo->marker_list;
+      while (prev->next != NULL)
+	prev = prev->next;
+      prev->next = cur_marker;
+    }
+    /* Reset pointer & calc remaining data length */
+    data = cur_marker->data;
+    length = cur_marker->original_length - data_length;
+  }
+  /* Reset to initial state for next marker */
+  marker->cur_marker = NULL;
+
+  /* Process the marker if interesting; else just make a generic trace msg */
+  switch (cinfo->unread_marker) {
+  case M_APP0:
+    examine_app0(cinfo, data, data_length, length);
+    break;
+  case M_APP14:
+    examine_app14(cinfo, data, data_length, length);
+    break;
+  default:
+    TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker,
+	     (int) (data_length + length));
+    break;
+  }
+
+  /* skip any remaining data -- could be lots */
+  INPUT_SYNC(cinfo);		/* do before skip_input_data */
+  if (length > 0)
+    (*cinfo->src->skip_input_data) (cinfo, (long) length);
+
+  return TRUE;
+}
+
+#endif /* SAVE_MARKERS_SUPPORTED */
+
+
+METHODDEF(boolean)
+skip_variable (j_decompress_ptr cinfo)
+/* Skip over an unknown or uninteresting variable-length marker */
+{
+  INT32 length;
+  INPUT_VARS(cinfo);
+
+  INPUT_2BYTES(cinfo, length, return FALSE);
+  length -= 2;
+  
+  TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, (int) length);
+
+  INPUT_SYNC(cinfo);		/* do before skip_input_data */
+  if (length > 0)
+    (*cinfo->src->skip_input_data) (cinfo, (long) length);
+
+  return TRUE;
+}
+
+
+/*
+ * Find the next JPEG marker, save it in cinfo->unread_marker.
+ * Returns FALSE if had to suspend before reaching a marker;
+ * in that case cinfo->unread_marker is unchanged.
+ *
+ * Note that the result might not be a valid marker code,
+ * but it will never be 0 or FF.
+ */
+
+LOCAL(boolean)
+next_marker (j_decompress_ptr cinfo)
+{
+  int c;
+  INPUT_VARS(cinfo);
+
+  for (;;) {
+    INPUT_BYTE(cinfo, c, return FALSE);
+    /* Skip any non-FF bytes.
+     * This may look a bit inefficient, but it will not occur in a valid file.
+     * We sync after each discarded byte so that a suspending data source
+     * can discard the byte from its buffer.
+     */
+    while (c != 0xFF) {
+      cinfo->marker->discarded_bytes++;
+      INPUT_SYNC(cinfo);
+      INPUT_BYTE(cinfo, c, return FALSE);
+    }
+    /* This loop swallows any duplicate FF bytes.  Extra FFs are legal as
+     * pad bytes, so don't count them in discarded_bytes.  We assume there
+     * will not be so many consecutive FF bytes as to overflow a suspending
+     * data source's input buffer.
+     */
+    do {
+      INPUT_BYTE(cinfo, c, return FALSE);
+    } while (c == 0xFF);
+    if (c != 0)
+      break;			/* found a valid marker, exit loop */
+    /* Reach here if we found a stuffed-zero data sequence (FF/00).
+     * Discard it and loop back to try again.
+     */
+    cinfo->marker->discarded_bytes += 2;
+    INPUT_SYNC(cinfo);
+  }
+
+  if (cinfo->marker->discarded_bytes != 0) {
+    WARNMS2(cinfo, JWRN_EXTRANEOUS_DATA, cinfo->marker->discarded_bytes, c);
+    cinfo->marker->discarded_bytes = 0;
+  }
+
+  cinfo->unread_marker = c;
+
+  INPUT_SYNC(cinfo);
+  return TRUE;
+}
+
+
+LOCAL(boolean)
+first_marker (j_decompress_ptr cinfo)
+/* Like next_marker, but used to obtain the initial SOI marker. */
+/* For this marker, we do not allow preceding garbage or fill; otherwise,
+ * we might well scan an entire input file before realizing it ain't JPEG.
+ * If an application wants to process non-JFIF files, it must seek to the
+ * SOI before calling the JPEG library.
+ */
+{
+  int c, c2;
+  INPUT_VARS(cinfo);
+
+  INPUT_BYTE(cinfo, c, return FALSE);
+  INPUT_BYTE(cinfo, c2, return FALSE);
+  if (c != 0xFF || c2 != (int) M_SOI)
+    ERREXIT2(cinfo, JERR_NO_SOI, c, c2);
+
+  cinfo->unread_marker = c2;
+
+  INPUT_SYNC(cinfo);
+  return TRUE;
+}
+
+
+/*
+ * Read markers until SOS or EOI.
+ *
+ * Returns same codes as are defined for jpeg_consume_input:
+ * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
+ *
+ * Note: This function may return a pseudo SOS marker (with zero
+ * component number) for treat by input controller's consume_input.
+ * consume_input itself should filter out (skip) the pseudo marker
+ * after processing for the caller.
+ */
+
+METHODDEF(int)
+read_markers (j_decompress_ptr cinfo)
+{
+  /* Outer loop repeats once for each marker. */
+  for (;;) {
+    /* Collect the marker proper, unless we already did. */
+    /* NB: first_marker() enforces the requirement that SOI appear first. */
+    if (cinfo->unread_marker == 0) {
+      if (! cinfo->marker->saw_SOI) {
+	if (! first_marker(cinfo))
+	  return JPEG_SUSPENDED;
+      } else {
+	if (! next_marker(cinfo))
+	  return JPEG_SUSPENDED;
+      }
+    }
+    /* At this point cinfo->unread_marker contains the marker code and the
+     * input point is just past the marker proper, but before any parameters.
+     * A suspension will cause us to return with this state still true.
+     */
+    switch (cinfo->unread_marker) {
+    case M_SOI:
+      if (! get_soi(cinfo))
+	return JPEG_SUSPENDED;
+      break;
+
+    case M_SOF0:		/* Baseline */
+      if (! get_sof(cinfo, TRUE, FALSE, FALSE))
+	return JPEG_SUSPENDED;
+      break;
+
+    case M_SOF1:		/* Extended sequential, Huffman */
+      if (! get_sof(cinfo, FALSE, FALSE, FALSE))
+	return JPEG_SUSPENDED;
+      break;
+
+    case M_SOF2:		/* Progressive, Huffman */
+      if (! get_sof(cinfo, FALSE, TRUE, FALSE))
+	return JPEG_SUSPENDED;
+      break;
+
+    case M_SOF9:		/* Extended sequential, arithmetic */
+      if (! get_sof(cinfo, FALSE, FALSE, TRUE))
+	return JPEG_SUSPENDED;
+      break;
+
+    case M_SOF10:		/* Progressive, arithmetic */
+      if (! get_sof(cinfo, FALSE, TRUE, TRUE))
+	return JPEG_SUSPENDED;
+      break;
+
+    /* Currently unsupported SOFn types */
+    case M_SOF3:		/* Lossless, Huffman */
+    case M_SOF5:		/* Differential sequential, Huffman */
+    case M_SOF6:		/* Differential progressive, Huffman */
+    case M_SOF7:		/* Differential lossless, Huffman */
+    case M_JPG:			/* Reserved for JPEG extensions */
+    case M_SOF11:		/* Lossless, arithmetic */
+    case M_SOF13:		/* Differential sequential, arithmetic */
+    case M_SOF14:		/* Differential progressive, arithmetic */
+    case M_SOF15:		/* Differential lossless, arithmetic */
+      ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo->unread_marker);
+      break;
+
+    case M_SOS:
+      if (! get_sos(cinfo))
+	return JPEG_SUSPENDED;
+      cinfo->unread_marker = 0;	/* processed the marker */
+      return JPEG_REACHED_SOS;
+
+    case M_EOI:
+      TRACEMS(cinfo, 1, JTRC_EOI);
+      cinfo->unread_marker = 0;	/* processed the marker */
+      return JPEG_REACHED_EOI;
+
+    case M_DAC:
+      if (! get_dac(cinfo))
+	return JPEG_SUSPENDED;
+      break;
+
+    case M_DHT:
+      if (! get_dht(cinfo))
+	return JPEG_SUSPENDED;
+      break;
+
+    case M_DQT:
+      if (! get_dqt(cinfo))
+	return JPEG_SUSPENDED;
+      break;
+
+    case M_DRI:
+      if (! get_dri(cinfo))
+	return JPEG_SUSPENDED;
+      break;
+
+    case M_JPG8:
+      if (! get_lse(cinfo))
+	return JPEG_SUSPENDED;
+      break;
+
+    case M_APP0:
+    case M_APP1:
+    case M_APP2:
+    case M_APP3:
+    case M_APP4:
+    case M_APP5:
+    case M_APP6:
+    case M_APP7:
+    case M_APP8:
+    case M_APP9:
+    case M_APP10:
+    case M_APP11:
+    case M_APP12:
+    case M_APP13:
+    case M_APP14:
+    case M_APP15:
+      if (! (*((my_marker_ptr) cinfo->marker)->process_APPn[
+		cinfo->unread_marker - (int) M_APP0]) (cinfo))
+	return JPEG_SUSPENDED;
+      break;
+
+    case M_COM:
+      if (! (*((my_marker_ptr) cinfo->marker)->process_COM) (cinfo))
+	return JPEG_SUSPENDED;
+      break;
+
+    case M_RST0:		/* these are all parameterless */
+    case M_RST1:
+    case M_RST2:
+    case M_RST3:
+    case M_RST4:
+    case M_RST5:
+    case M_RST6:
+    case M_RST7:
+    case M_TEM:
+      TRACEMS1(cinfo, 1, JTRC_PARMLESS_MARKER, cinfo->unread_marker);
+      break;
+
+    case M_DNL:			/* Ignore DNL ... perhaps the wrong thing */
+      if (! skip_variable(cinfo))
+	return JPEG_SUSPENDED;
+      break;
+
+    default:			/* must be DHP, EXP, JPGn, or RESn */
+      /* For now, we treat the reserved markers as fatal errors since they are
+       * likely to be used to signal incompatible JPEG Part 3 extensions.
+       * Once the JPEG 3 version-number marker is well defined, this code
+       * ought to change!
+       */
+      ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker);
+      break;
+    }
+    /* Successfully processed marker, so reset state variable */
+    cinfo->unread_marker = 0;
+  } /* end loop */
+}
+
+
+/*
+ * Read a restart marker, which is expected to appear next in the datastream;
+ * if the marker is not there, take appropriate recovery action.
+ * Returns FALSE if suspension is required.
+ *
+ * This is called by the entropy decoder after it has read an appropriate
+ * number of MCUs.  cinfo->unread_marker may be nonzero if the entropy decoder
+ * has already read a marker from the data source.  Under normal conditions
+ * cinfo->unread_marker will be reset to 0 before returning; if not reset,
+ * it holds a marker which the decoder will be unable to read past.
+ */
+
+METHODDEF(boolean)
+read_restart_marker (j_decompress_ptr cinfo)
+{
+  /* Obtain a marker unless we already did. */
+  /* Note that next_marker will complain if it skips any data. */
+  if (cinfo->unread_marker == 0) {
+    if (! next_marker(cinfo))
+      return FALSE;
+  }
+
+  if (cinfo->unread_marker ==
+      ((int) M_RST0 + cinfo->marker->next_restart_num)) {
+    /* Normal case --- swallow the marker and let entropy decoder continue */
+    TRACEMS1(cinfo, 3, JTRC_RST, cinfo->marker->next_restart_num);
+    cinfo->unread_marker = 0;
+  } else {
+    /* Uh-oh, the restart markers have been messed up. */
+    /* Let the data source manager determine how to resync. */
+    if (! (*cinfo->src->resync_to_restart) (cinfo,
+					    cinfo->marker->next_restart_num))
+      return FALSE;
+  }
+
+  /* Update next-restart state */
+  cinfo->marker->next_restart_num = (cinfo->marker->next_restart_num + 1) & 7;
+
+  return TRUE;
+}
+
+
+/*
+ * This is the default resync_to_restart method for data source managers
+ * to use if they don't have any better approach.  Some data source managers
+ * may be able to back up, or may have additional knowledge about the data
+ * which permits a more intelligent recovery strategy; such managers would
+ * presumably supply their own resync method.
+ *
+ * read_restart_marker calls resync_to_restart if it finds a marker other than
+ * the restart marker it was expecting.  (This code is *not* used unless
+ * a nonzero restart interval has been declared.)  cinfo->unread_marker is
+ * the marker code actually found (might be anything, except 0 or FF).
+ * The desired restart marker number (0..7) is passed as a parameter.
+ * This routine is supposed to apply whatever error recovery strategy seems
+ * appropriate in order to position the input stream to the next data segment.
+ * Note that cinfo->unread_marker is treated as a marker appearing before
+ * the current data-source input point; usually it should be reset to zero
+ * before returning.
+ * Returns FALSE if suspension is required.
+ *
+ * This implementation is substantially constrained by wanting to treat the
+ * input as a data stream; this means we can't back up.  Therefore, we have
+ * only the following actions to work with:
+ *   1. Simply discard the marker and let the entropy decoder resume at next
+ *      byte of file.
+ *   2. Read forward until we find another marker, discarding intervening
+ *      data.  (In theory we could look ahead within the current bufferload,
+ *      without having to discard data if we don't find the desired marker.
+ *      This idea is not implemented here, in part because it makes behavior
+ *      dependent on buffer size and chance buffer-boundary positions.)
+ *   3. Leave the marker unread (by failing to zero cinfo->unread_marker).
+ *      This will cause the entropy decoder to process an empty data segment,
+ *      inserting dummy zeroes, and then we will reprocess the marker.
+ *
+ * #2 is appropriate if we think the desired marker lies ahead, while #3 is
+ * appropriate if the found marker is a future restart marker (indicating
+ * that we have missed the desired restart marker, probably because it got
+ * corrupted).
+ * We apply #2 or #3 if the found marker is a restart marker no more than
+ * two counts behind or ahead of the expected one.  We also apply #2 if the
+ * found marker is not a legal JPEG marker code (it's certainly bogus data).
+ * If the found marker is a restart marker more than 2 counts away, we do #1
+ * (too much risk that the marker is erroneous; with luck we will be able to
+ * resync at some future point).
+ * For any valid non-restart JPEG marker, we apply #3.  This keeps us from
+ * overrunning the end of a scan.  An implementation limited to single-scan
+ * files might find it better to apply #2 for markers other than EOI, since
+ * any other marker would have to be bogus data in that case.
+ */
+
+GLOBAL(boolean)
+jpeg_resync_to_restart (j_decompress_ptr cinfo, int desired)
+{
+  int marker = cinfo->unread_marker;
+  int action = 1;
+  
+  /* Always put up a warning. */
+  WARNMS2(cinfo, JWRN_MUST_RESYNC, marker, desired);
+  
+  /* Outer loop handles repeated decision after scanning forward. */
+  for (;;) {
+    if (marker < (int) M_SOF0)
+      action = 2;		/* invalid marker */
+    else if (marker < (int) M_RST0 || marker > (int) M_RST7)
+      action = 3;		/* valid non-restart marker */
+    else {
+      if (marker == ((int) M_RST0 + ((desired+1) & 7)) ||
+	  marker == ((int) M_RST0 + ((desired+2) & 7)))
+	action = 3;		/* one of the next two expected restarts */
+      else if (marker == ((int) M_RST0 + ((desired-1) & 7)) ||
+	       marker == ((int) M_RST0 + ((desired-2) & 7)))
+	action = 2;		/* a prior restart, so advance */
+      else
+	action = 1;		/* desired restart or too far away */
+    }
+    TRACEMS2(cinfo, 4, JTRC_RECOVERY_ACTION, marker, action);
+    switch (action) {
+    case 1:
+      /* Discard marker and let entropy decoder resume processing. */
+      cinfo->unread_marker = 0;
+      return TRUE;
+    case 2:
+      /* Scan to the next marker, and repeat the decision loop. */
+      if (! next_marker(cinfo))
+	return FALSE;
+      marker = cinfo->unread_marker;
+      break;
+    case 3:
+      /* Return without advancing past this marker. */
+      /* Entropy decoder will be forced to process an empty segment. */
+      return TRUE;
+    }
+  } /* end loop */
+}
+
+
+/*
+ * Reset marker processing state to begin a fresh datastream.
+ */
+
+METHODDEF(void)
+reset_marker_reader (j_decompress_ptr cinfo)
+{
+  my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
+
+  cinfo->comp_info = NULL;		/* until allocated by get_sof */
+  cinfo->input_scan_number = 0;		/* no SOS seen yet */
+  cinfo->unread_marker = 0;		/* no pending marker */
+  marker->pub.saw_SOI = FALSE;		/* set internal state too */
+  marker->pub.saw_SOF = FALSE;
+  marker->pub.discarded_bytes = 0;
+  marker->cur_marker = NULL;
+}
+
+
+/*
+ * Initialize the marker reader module.
+ * This is called only once, when the decompression object is created.
+ */
+
+GLOBAL(void)
+jinit_marker_reader (j_decompress_ptr cinfo)
+{
+  my_marker_ptr marker;
+  int i;
+
+  /* Create subobject in permanent pool */
+  marker = (my_marker_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+				SIZEOF(my_marker_reader));
+  cinfo->marker = &marker->pub;
+  /* Initialize public method pointers */
+  marker->pub.reset_marker_reader = reset_marker_reader;
+  marker->pub.read_markers = read_markers;
+  marker->pub.read_restart_marker = read_restart_marker;
+  /* Initialize COM/APPn processing.
+   * By default, we examine and then discard APP0 and APP14,
+   * but simply discard COM and all other APPn.
+   */
+  marker->process_COM = skip_variable;
+  marker->length_limit_COM = 0;
+  for (i = 0; i < 16; i++) {
+    marker->process_APPn[i] = skip_variable;
+    marker->length_limit_APPn[i] = 0;
+  }
+  marker->process_APPn[0] = get_interesting_appn;
+  marker->process_APPn[14] = get_interesting_appn;
+  /* Reset marker processing state */
+  reset_marker_reader(cinfo);
+}
+
+
+/*
+ * Control saving of COM and APPn markers into marker_list.
+ */
+
+#ifdef SAVE_MARKERS_SUPPORTED
+
+GLOBAL(void)
+jpeg_save_markers (j_decompress_ptr cinfo, int marker_code,
+		   unsigned int length_limit)
+{
+  my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
+  long maxlength;
+  jpeg_marker_parser_method processor;
+
+  /* Length limit mustn't be larger than what we can allocate
+   * (should only be a concern in a 16-bit environment).
+   */
+  maxlength = cinfo->mem->max_alloc_chunk - SIZEOF(struct jpeg_marker_struct);
+  if (((long) length_limit) > maxlength)
+    length_limit = (unsigned int) maxlength;
+
+  /* Choose processor routine to use.
+   * APP0/APP14 have special requirements.
+   */
+  if (length_limit) {
+    processor = save_marker;
+    /* If saving APP0/APP14, save at least enough for our internal use. */
+    if (marker_code == (int) M_APP0 && length_limit < APP0_DATA_LEN)
+      length_limit = APP0_DATA_LEN;
+    else if (marker_code == (int) M_APP14 && length_limit < APP14_DATA_LEN)
+      length_limit = APP14_DATA_LEN;
+  } else {
+    processor = skip_variable;
+    /* If discarding APP0/APP14, use our regular on-the-fly processor. */
+    if (marker_code == (int) M_APP0 || marker_code == (int) M_APP14)
+      processor = get_interesting_appn;
+  }
+
+  if (marker_code == (int) M_COM) {
+    marker->process_COM = processor;
+    marker->length_limit_COM = length_limit;
+  } else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) {
+    marker->process_APPn[marker_code - (int) M_APP0] = processor;
+    marker->length_limit_APPn[marker_code - (int) M_APP0] = length_limit;
+  } else
+    ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code);
+}
+
+#endif /* SAVE_MARKERS_SUPPORTED */
+
+
+/*
+ * Install a special processing method for COM or APPn markers.
+ */
+
+GLOBAL(void)
+jpeg_set_marker_processor (j_decompress_ptr cinfo, int marker_code,
+			   jpeg_marker_parser_method routine)
+{
+  my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
+
+  if (marker_code == (int) M_COM)
+    marker->process_COM = routine;
+  else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15)
+    marker->process_APPn[marker_code - (int) M_APP0] = routine;
+  else
+    ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code);
+}
diff --git a/source/Irrlicht/jpeglib/jdmaster.c b/source/Irrlicht/jpeglib/jdmaster.c
new file mode 100644
index 00000000..ed6b4996
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jdmaster.c
@@ -0,0 +1,543 @@
+/*
+ * jdmaster.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2002-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains master control logic for the JPEG decompressor.
+ * These routines are concerned with selecting the modules to be executed
+ * and with determining the number of passes and the work to be done in each
+ * pass.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private state */
+
+typedef struct {
+  struct jpeg_decomp_master pub; /* public fields */
+
+  int pass_number;		/* # of passes completed */
+
+  boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */
+
+  /* Saved references to initialized quantizer modules,
+   * in case we need to switch modes.
+   */
+  struct jpeg_color_quantizer * quantizer_1pass;
+  struct jpeg_color_quantizer * quantizer_2pass;
+} my_decomp_master;
+
+typedef my_decomp_master * my_master_ptr;
+
+
+/*
+ * Determine whether merged upsample/color conversion should be used.
+ * CRUCIAL: this must match the actual capabilities of jdmerge.c!
+ */
+
+LOCAL(boolean)
+use_merged_upsample (j_decompress_ptr cinfo)
+{
+#ifdef UPSAMPLE_MERGING_SUPPORTED
+  /* Merging is the equivalent of plain box-filter upsampling */
+  if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling)
+    return FALSE;
+  /* jdmerge.c only supports YCC=>RGB color conversion */
+  if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 ||
+      cinfo->out_color_space != JCS_RGB ||
+      cinfo->out_color_components != RGB_PIXELSIZE ||
+      cinfo->color_transform)
+    return FALSE;
+  /* and it only handles 2h1v or 2h2v sampling ratios */
+  if (cinfo->comp_info[0].h_samp_factor != 2 ||
+      cinfo->comp_info[1].h_samp_factor != 1 ||
+      cinfo->comp_info[2].h_samp_factor != 1 ||
+      cinfo->comp_info[0].v_samp_factor >  2 ||
+      cinfo->comp_info[1].v_samp_factor != 1 ||
+      cinfo->comp_info[2].v_samp_factor != 1)
+    return FALSE;
+  /* furthermore, it doesn't work if we've scaled the IDCTs differently */
+  if (cinfo->comp_info[0].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size ||
+      cinfo->comp_info[1].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size ||
+      cinfo->comp_info[2].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size ||
+      cinfo->comp_info[0].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size ||
+      cinfo->comp_info[1].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size ||
+      cinfo->comp_info[2].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size)
+    return FALSE;
+  /* ??? also need to test for upsample-time rescaling, when & if supported */
+  return TRUE;			/* by golly, it'll work... */
+#else
+  return FALSE;
+#endif
+}
+
+
+/*
+ * Compute output image dimensions and related values.
+ * NOTE: this is exported for possible use by application.
+ * Hence it mustn't do anything that can't be done twice.
+ * Also note that it may be called before the master module is initialized!
+ */
+
+GLOBAL(void)
+jpeg_calc_output_dimensions (j_decompress_ptr cinfo)
+/* Do computations that are needed before master selection phase.
+ * This function is used for full decompression.
+ */
+{
+#ifdef IDCT_SCALING_SUPPORTED
+  int ci;
+  jpeg_component_info *compptr;
+#endif
+
+  /* Prevent application from calling me at wrong times */
+  if (cinfo->global_state != DSTATE_READY)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+  /* Compute core output image dimensions and DCT scaling choices. */
+  jpeg_core_output_dimensions(cinfo);
+
+#ifdef IDCT_SCALING_SUPPORTED
+
+  /* In selecting the actual DCT scaling for each component, we try to
+   * scale up the chroma components via IDCT scaling rather than upsampling.
+   * This saves time if the upsampler gets to use 1:1 scaling.
+   * Note this code adapts subsampling ratios which are powers of 2.
+   */
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    int ssize = 1;
+    while (cinfo->min_DCT_h_scaled_size * ssize <=
+	   (cinfo->do_fancy_upsampling ? DCTSIZE : DCTSIZE / 2) &&
+	   (cinfo->max_h_samp_factor % (compptr->h_samp_factor * ssize * 2)) == 0) {
+      ssize = ssize * 2;
+    }
+    compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size * ssize;
+    ssize = 1;
+    while (cinfo->min_DCT_v_scaled_size * ssize <=
+	   (cinfo->do_fancy_upsampling ? DCTSIZE : DCTSIZE / 2) &&
+	   (cinfo->max_v_samp_factor % (compptr->v_samp_factor * ssize * 2)) == 0) {
+      ssize = ssize * 2;
+    }
+    compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size * ssize;
+
+    /* We don't support IDCT ratios larger than 2. */
+    if (compptr->DCT_h_scaled_size > compptr->DCT_v_scaled_size * 2)
+	compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size * 2;
+    else if (compptr->DCT_v_scaled_size > compptr->DCT_h_scaled_size * 2)
+	compptr->DCT_v_scaled_size = compptr->DCT_h_scaled_size * 2;
+  }
+
+  /* Recompute downsampled dimensions of components;
+   * application needs to know these if using raw downsampled data.
+   */
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    /* Size in samples, after IDCT scaling */
+    compptr->downsampled_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width *
+		    (long) (compptr->h_samp_factor * compptr->DCT_h_scaled_size),
+		    (long) (cinfo->max_h_samp_factor * cinfo->block_size));
+    compptr->downsampled_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height *
+		    (long) (compptr->v_samp_factor * compptr->DCT_v_scaled_size),
+		    (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+  }
+
+#endif /* IDCT_SCALING_SUPPORTED */
+
+  /* Report number of components in selected colorspace. */
+  /* Probably this should be in the color conversion module... */
+  switch (cinfo->out_color_space) {
+  case JCS_GRAYSCALE:
+    cinfo->out_color_components = 1;
+    break;
+  case JCS_RGB:
+  case JCS_BG_RGB:
+    cinfo->out_color_components = RGB_PIXELSIZE;
+    break;
+  case JCS_YCbCr:
+  case JCS_BG_YCC:
+    cinfo->out_color_components = 3;
+    break;
+  case JCS_CMYK:
+  case JCS_YCCK:
+    cinfo->out_color_components = 4;
+    break;
+  default:			/* else must be same colorspace as in file */
+    cinfo->out_color_components = cinfo->num_components;
+    break;
+  }
+  cinfo->output_components = (cinfo->quantize_colors ? 1 :
+			      cinfo->out_color_components);
+
+  /* See if upsampler will want to emit more than one row at a time */
+  if (use_merged_upsample(cinfo))
+    cinfo->rec_outbuf_height = cinfo->max_v_samp_factor;
+  else
+    cinfo->rec_outbuf_height = 1;
+}
+
+
+/*
+ * Several decompression processes need to range-limit values to the range
+ * 0..MAXJSAMPLE; the input value may fall somewhat outside this range
+ * due to noise introduced by quantization, roundoff error, etc.  These
+ * processes are inner loops and need to be as fast as possible.  On most
+ * machines, particularly CPUs with pipelines or instruction prefetch,
+ * a (subscript-check-less) C table lookup
+ *		x = sample_range_limit[x];
+ * is faster than explicit tests
+ *		if (x < 0)  x = 0;
+ *		else if (x > MAXJSAMPLE)  x = MAXJSAMPLE;
+ * These processes all use a common table prepared by the routine below.
+ *
+ * For most steps we can mathematically guarantee that the initial value
+ * of x is within MAXJSAMPLE+1 of the legal range, so a table running from
+ * -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient.  But for the initial
+ * limiting step (just after the IDCT), a wildly out-of-range value is 
+ * possible if the input data is corrupt.  To avoid any chance of indexing
+ * off the end of memory and getting a bad-pointer trap, we perform the
+ * post-IDCT limiting thus:
+ *		x = range_limit[x & MASK];
+ * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit
+ * samples.  Under normal circumstances this is more than enough range and
+ * a correct output will be generated; with bogus input data the mask will
+ * cause wraparound, and we will safely generate a bogus-but-in-range output.
+ * For the post-IDCT step, we want to convert the data from signed to unsigned
+ * representation by adding CENTERJSAMPLE at the same time that we limit it.
+ * So the post-IDCT limiting table ends up looking like this:
+ *   CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE,
+ *   MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
+ *   0          (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
+ *   0,1,...,CENTERJSAMPLE-1
+ * Negative inputs select values from the upper half of the table after
+ * masking.
+ *
+ * We can save some space by overlapping the start of the post-IDCT table
+ * with the simpler range limiting table.  The post-IDCT table begins at
+ * sample_range_limit + CENTERJSAMPLE.
+ *
+ * Note that the table is allocated in near data space on PCs; it's small
+ * enough and used often enough to justify this.
+ */
+
+LOCAL(void)
+prepare_range_limit_table (j_decompress_ptr cinfo)
+/* Allocate and fill in the sample_range_limit table */
+{
+  JSAMPLE * table;
+  int i;
+
+  table = (JSAMPLE *)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+		(5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * SIZEOF(JSAMPLE));
+  table += (MAXJSAMPLE+1);	/* allow negative subscripts of simple table */
+  cinfo->sample_range_limit = table;
+  /* First segment of "simple" table: limit[x] = 0 for x < 0 */
+  MEMZERO(table - (MAXJSAMPLE+1), (MAXJSAMPLE+1) * SIZEOF(JSAMPLE));
+  /* Main part of "simple" table: limit[x] = x */
+  for (i = 0; i <= MAXJSAMPLE; i++)
+    table[i] = (JSAMPLE) i;
+  table += CENTERJSAMPLE;	/* Point to where post-IDCT table starts */
+  /* End of simple table, rest of first half of post-IDCT table */
+  for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++)
+    table[i] = MAXJSAMPLE;
+  /* Second half of post-IDCT table */
+  MEMZERO(table + (2 * (MAXJSAMPLE+1)),
+	  (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * SIZEOF(JSAMPLE));
+  MEMCOPY(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE),
+	  cinfo->sample_range_limit, CENTERJSAMPLE * SIZEOF(JSAMPLE));
+}
+
+
+/*
+ * Master selection of decompression modules.
+ * This is done once at jpeg_start_decompress time.  We determine
+ * which modules will be used and give them appropriate initialization calls.
+ * We also initialize the decompressor input side to begin consuming data.
+ *
+ * Since jpeg_read_header has finished, we know what is in the SOF
+ * and (first) SOS markers.  We also have all the application parameter
+ * settings.
+ */
+
+LOCAL(void)
+master_selection (j_decompress_ptr cinfo)
+{
+  my_master_ptr master = (my_master_ptr) cinfo->master;
+  boolean use_c_buffer;
+  long samplesperrow;
+  JDIMENSION jd_samplesperrow;
+
+  /* For now, precision must match compiled-in value... */
+  if (cinfo->data_precision != BITS_IN_JSAMPLE)
+    ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+  /* Initialize dimensions and other stuff */
+  jpeg_calc_output_dimensions(cinfo);
+  prepare_range_limit_table(cinfo);
+
+  /* Sanity check on image dimensions */
+  if (cinfo->output_height <= 0 || cinfo->output_width <= 0 ||
+      cinfo->out_color_components <= 0)
+    ERREXIT(cinfo, JERR_EMPTY_IMAGE);
+
+  /* Width of an output scanline must be representable as JDIMENSION. */
+  samplesperrow = (long) cinfo->output_width * (long) cinfo->out_color_components;
+  jd_samplesperrow = (JDIMENSION) samplesperrow;
+  if ((long) jd_samplesperrow != samplesperrow)
+    ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+
+  /* Initialize my private state */
+  master->pass_number = 0;
+  master->using_merged_upsample = use_merged_upsample(cinfo);
+
+  /* Color quantizer selection */
+  master->quantizer_1pass = NULL;
+  master->quantizer_2pass = NULL;
+  /* No mode changes if not using buffered-image mode. */
+  if (! cinfo->quantize_colors || ! cinfo->buffered_image) {
+    cinfo->enable_1pass_quant = FALSE;
+    cinfo->enable_external_quant = FALSE;
+    cinfo->enable_2pass_quant = FALSE;
+  }
+  if (cinfo->quantize_colors) {
+    if (cinfo->raw_data_out)
+      ERREXIT(cinfo, JERR_NOTIMPL);
+    /* 2-pass quantizer only works in 3-component color space. */
+    if (cinfo->out_color_components != 3) {
+      cinfo->enable_1pass_quant = TRUE;
+      cinfo->enable_external_quant = FALSE;
+      cinfo->enable_2pass_quant = FALSE;
+      cinfo->colormap = NULL;
+    } else if (cinfo->colormap != NULL) {
+      cinfo->enable_external_quant = TRUE;
+    } else if (cinfo->two_pass_quantize) {
+      cinfo->enable_2pass_quant = TRUE;
+    } else {
+      cinfo->enable_1pass_quant = TRUE;
+    }
+
+    if (cinfo->enable_1pass_quant) {
+#ifdef QUANT_1PASS_SUPPORTED
+      jinit_1pass_quantizer(cinfo);
+      master->quantizer_1pass = cinfo->cquantize;
+#else
+      ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+    }
+
+    /* We use the 2-pass code to map to external colormaps. */
+    if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) {
+#ifdef QUANT_2PASS_SUPPORTED
+      jinit_2pass_quantizer(cinfo);
+      master->quantizer_2pass = cinfo->cquantize;
+#else
+      ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+    }
+    /* If both quantizers are initialized, the 2-pass one is left active;
+     * this is necessary for starting with quantization to an external map.
+     */
+  }
+
+  /* Post-processing: in particular, color conversion first */
+  if (! cinfo->raw_data_out) {
+    if (master->using_merged_upsample) {
+#ifdef UPSAMPLE_MERGING_SUPPORTED
+      jinit_merged_upsampler(cinfo); /* does color conversion too */
+#else
+      ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+    } else {
+      jinit_color_deconverter(cinfo);
+      jinit_upsampler(cinfo);
+    }
+    jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant);
+  }
+  /* Inverse DCT */
+  jinit_inverse_dct(cinfo);
+  /* Entropy decoding: either Huffman or arithmetic coding. */
+  if (cinfo->arith_code)
+    jinit_arith_decoder(cinfo);
+  else {
+    jinit_huff_decoder(cinfo);
+  }
+
+  /* Initialize principal buffer controllers. */
+  use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image;
+  jinit_d_coef_controller(cinfo, use_c_buffer);
+
+  if (! cinfo->raw_data_out)
+    jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */);
+
+  /* We can now tell the memory manager to allocate virtual arrays. */
+  (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
+
+  /* Initialize input side of decompressor to consume first scan. */
+  (*cinfo->inputctl->start_input_pass) (cinfo);
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+  /* If jpeg_start_decompress will read the whole file, initialize
+   * progress monitoring appropriately.  The input step is counted
+   * as one pass.
+   */
+  if (cinfo->progress != NULL && ! cinfo->buffered_image &&
+      cinfo->inputctl->has_multiple_scans) {
+    int nscans;
+    /* Estimate number of scans to set pass_limit. */
+    if (cinfo->progressive_mode) {
+      /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */
+      nscans = 2 + 3 * cinfo->num_components;
+    } else {
+      /* For a nonprogressive multiscan file, estimate 1 scan per component. */
+      nscans = cinfo->num_components;
+    }
+    cinfo->progress->pass_counter = 0L;
+    cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans;
+    cinfo->progress->completed_passes = 0;
+    cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2);
+    /* Count the input pass as done */
+    master->pass_number++;
+  }
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+}
+
+
+/*
+ * Per-pass setup.
+ * This is called at the beginning of each output pass.  We determine which
+ * modules will be active during this pass and give them appropriate
+ * start_pass calls.  We also set is_dummy_pass to indicate whether this
+ * is a "real" output pass or a dummy pass for color quantization.
+ * (In the latter case, jdapistd.c will crank the pass to completion.)
+ */
+
+METHODDEF(void)
+prepare_for_output_pass (j_decompress_ptr cinfo)
+{
+  my_master_ptr master = (my_master_ptr) cinfo->master;
+
+  if (master->pub.is_dummy_pass) {
+#ifdef QUANT_2PASS_SUPPORTED
+    /* Final pass of 2-pass quantization */
+    master->pub.is_dummy_pass = FALSE;
+    (*cinfo->cquantize->start_pass) (cinfo, FALSE);
+    (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST);
+    (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST);
+#else
+    ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif /* QUANT_2PASS_SUPPORTED */
+  } else {
+    if (cinfo->quantize_colors && cinfo->colormap == NULL) {
+      /* Select new quantization method */
+      if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) {
+	cinfo->cquantize = master->quantizer_2pass;
+	master->pub.is_dummy_pass = TRUE;
+      } else if (cinfo->enable_1pass_quant) {
+	cinfo->cquantize = master->quantizer_1pass;
+      } else {
+	ERREXIT(cinfo, JERR_MODE_CHANGE);
+      }
+    }
+    (*cinfo->idct->start_pass) (cinfo);
+    (*cinfo->coef->start_output_pass) (cinfo);
+    if (! cinfo->raw_data_out) {
+      if (! master->using_merged_upsample)
+	(*cinfo->cconvert->start_pass) (cinfo);
+      (*cinfo->upsample->start_pass) (cinfo);
+      if (cinfo->quantize_colors)
+	(*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass);
+      (*cinfo->post->start_pass) (cinfo,
+	    (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));
+      (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU);
+    }
+  }
+
+  /* Set up progress monitor's pass info if present */
+  if (cinfo->progress != NULL) {
+    cinfo->progress->completed_passes = master->pass_number;
+    cinfo->progress->total_passes = master->pass_number +
+				    (master->pub.is_dummy_pass ? 2 : 1);
+    /* In buffered-image mode, we assume one more output pass if EOI not
+     * yet reached, but no more passes if EOI has been reached.
+     */
+    if (cinfo->buffered_image && ! cinfo->inputctl->eoi_reached) {
+      cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1);
+    }
+  }
+}
+
+
+/*
+ * Finish up at end of an output pass.
+ */
+
+METHODDEF(void)
+finish_output_pass (j_decompress_ptr cinfo)
+{
+  my_master_ptr master = (my_master_ptr) cinfo->master;
+
+  if (cinfo->quantize_colors)
+    (*cinfo->cquantize->finish_pass) (cinfo);
+  master->pass_number++;
+}
+
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+
+/*
+ * Switch to a new external colormap between output passes.
+ */
+
+GLOBAL(void)
+jpeg_new_colormap (j_decompress_ptr cinfo)
+{
+  my_master_ptr master = (my_master_ptr) cinfo->master;
+
+  /* Prevent application from calling me at wrong times */
+  if (cinfo->global_state != DSTATE_BUFIMAGE)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+  if (cinfo->quantize_colors && cinfo->enable_external_quant &&
+      cinfo->colormap != NULL) {
+    /* Select 2-pass quantizer for external colormap use */
+    cinfo->cquantize = master->quantizer_2pass;
+    /* Notify quantizer of colormap change */
+    (*cinfo->cquantize->new_color_map) (cinfo);
+    master->pub.is_dummy_pass = FALSE; /* just in case */
+  } else
+    ERREXIT(cinfo, JERR_MODE_CHANGE);
+}
+
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+
+
+/*
+ * Initialize master decompression control and select active modules.
+ * This is performed at the start of jpeg_start_decompress.
+ */
+
+GLOBAL(void)
+jinit_master_decompress (j_decompress_ptr cinfo)
+{
+  my_master_ptr master;
+
+  master = (my_master_ptr)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  SIZEOF(my_decomp_master));
+  cinfo->master = &master->pub;
+  master->pub.prepare_for_output_pass = prepare_for_output_pass;
+  master->pub.finish_output_pass = finish_output_pass;
+
+  master->pub.is_dummy_pass = FALSE;
+
+  master_selection(cinfo);
+}
diff --git a/source/Irrlicht/jpeglib/jdmerge.c b/source/Irrlicht/jpeglib/jdmerge.c
new file mode 100644
index 00000000..605e858c
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jdmerge.c
@@ -0,0 +1,401 @@
+/*
+ * jdmerge.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains code for merged upsampling/color conversion.
+ *
+ * This file combines functions from jdsample.c and jdcolor.c;
+ * read those files first to understand what's going on.
+ *
+ * When the chroma components are to be upsampled by simple replication
+ * (ie, box filtering), we can save some work in color conversion by
+ * calculating all the output pixels corresponding to a pair of chroma
+ * samples at one time.  In the conversion equations
+ *	R = Y           + K1 * Cr
+ *	G = Y + K2 * Cb + K3 * Cr
+ *	B = Y + K4 * Cb
+ * only the Y term varies among the group of pixels corresponding to a pair
+ * of chroma samples, so the rest of the terms can be calculated just once.
+ * At typical sampling ratios, this eliminates half or three-quarters of the
+ * multiplications needed for color conversion.
+ *
+ * This file currently provides implementations for the following cases:
+ *	YCbCr => RGB color conversion only.
+ *	Sampling ratios of 2h1v or 2h2v.
+ *	No scaling needed at upsample time.
+ *	Corner-aligned (non-CCIR601) sampling alignment.
+ * Other special cases could be added, but in most applications these are
+ * the only common cases.  (For uncommon cases we fall back on the more
+ * general code in jdsample.c and jdcolor.c.)
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+#ifdef UPSAMPLE_MERGING_SUPPORTED
+
+
+/* Private subobject */
+
+typedef struct {
+  struct jpeg_upsampler pub;	/* public fields */
+
+  /* Pointer to routine to do actual upsampling/conversion of one row group */
+  JMETHOD(void, upmethod, (j_decompress_ptr cinfo,
+			   JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+			   JSAMPARRAY output_buf));
+
+  /* Private state for YCC->RGB conversion */
+  int * Cr_r_tab;		/* => table for Cr to R conversion */
+  int * Cb_b_tab;		/* => table for Cb to B conversion */
+  INT32 * Cr_g_tab;		/* => table for Cr to G conversion */
+  INT32 * Cb_g_tab;		/* => table for Cb to G conversion */
+
+  /* For 2:1 vertical sampling, we produce two output rows at a time.
+   * We need a "spare" row buffer to hold the second output row if the
+   * application provides just a one-row buffer; we also use the spare
+   * to discard the dummy last row if the image height is odd.
+   */
+  JSAMPROW spare_row;
+  boolean spare_full;		/* T if spare buffer is occupied */
+
+  JDIMENSION out_row_width;	/* samples per output row */
+  JDIMENSION rows_to_go;	/* counts rows remaining in image */
+} my_upsampler;
+
+typedef my_upsampler * my_upsample_ptr;
+
+#define SCALEBITS	16	/* speediest right-shift on some machines */
+#define ONE_HALF	((INT32) 1 << (SCALEBITS-1))
+#define FIX(x)		((INT32) ((x) * (1L<RGB colorspace conversion.
+ * This is taken directly from jdcolor.c; see that file for more info.
+ */
+
+LOCAL(void)
+build_ycc_rgb_table (j_decompress_ptr cinfo)
+{
+  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+  int i;
+  INT32 x;
+  SHIFT_TEMPS
+
+  upsample->Cr_r_tab = (int *)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				(MAXJSAMPLE+1) * SIZEOF(int));
+  upsample->Cb_b_tab = (int *)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				(MAXJSAMPLE+1) * SIZEOF(int));
+  upsample->Cr_g_tab = (INT32 *)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				(MAXJSAMPLE+1) * SIZEOF(INT32));
+  upsample->Cb_g_tab = (INT32 *)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				(MAXJSAMPLE+1) * SIZEOF(INT32));
+
+  for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
+    /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
+    /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
+    /* Cr=>R value is nearest int to 1.402 * x */
+    upsample->Cr_r_tab[i] = (int)
+		    RIGHT_SHIFT(FIX(1.402) * x + ONE_HALF, SCALEBITS);
+    /* Cb=>B value is nearest int to 1.772 * x */
+    upsample->Cb_b_tab[i] = (int)
+		    RIGHT_SHIFT(FIX(1.772) * x + ONE_HALF, SCALEBITS);
+    /* Cr=>G value is scaled-up -0.714136286 * x */
+    upsample->Cr_g_tab[i] = (- FIX(0.714136286)) * x;
+    /* Cb=>G value is scaled-up -0.344136286 * x */
+    /* We also add in ONE_HALF so that need not do it in inner loop */
+    upsample->Cb_g_tab[i] = (- FIX(0.344136286)) * x + ONE_HALF;
+  }
+}
+
+
+/*
+ * Initialize for an upsampling pass.
+ */
+
+METHODDEF(void)
+start_pass_merged_upsample (j_decompress_ptr cinfo)
+{
+  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+
+  /* Mark the spare buffer empty */
+  upsample->spare_full = FALSE;
+  /* Initialize total-height counter for detecting bottom of image */
+  upsample->rows_to_go = cinfo->output_height;
+}
+
+
+/*
+ * Control routine to do upsampling (and color conversion).
+ *
+ * The control routine just handles the row buffering considerations.
+ */
+
+METHODDEF(void)
+merged_2v_upsample (j_decompress_ptr cinfo,
+		    JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+		    JDIMENSION in_row_groups_avail,
+		    JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+		    JDIMENSION out_rows_avail)
+/* 2:1 vertical sampling case: may need a spare row. */
+{
+  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+  JSAMPROW work_ptrs[2];
+  JDIMENSION num_rows;		/* number of rows returned to caller */
+
+  if (upsample->spare_full) {
+    /* If we have a spare row saved from a previous cycle, just return it. */
+    jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0,
+		      1, upsample->out_row_width);
+    num_rows = 1;
+    upsample->spare_full = FALSE;
+  } else {
+    /* Figure number of rows to return to caller. */
+    num_rows = 2;
+    /* Not more than the distance to the end of the image. */
+    if (num_rows > upsample->rows_to_go)
+      num_rows = upsample->rows_to_go;
+    /* And not more than what the client can accept: */
+    out_rows_avail -= *out_row_ctr;
+    if (num_rows > out_rows_avail)
+      num_rows = out_rows_avail;
+    /* Create output pointer array for upsampler. */
+    work_ptrs[0] = output_buf[*out_row_ctr];
+    if (num_rows > 1) {
+      work_ptrs[1] = output_buf[*out_row_ctr + 1];
+    } else {
+      work_ptrs[1] = upsample->spare_row;
+      upsample->spare_full = TRUE;
+    }
+    /* Now do the upsampling. */
+    (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, work_ptrs);
+  }
+
+  /* Adjust counts */
+  *out_row_ctr += num_rows;
+  upsample->rows_to_go -= num_rows;
+  /* When the buffer is emptied, declare this input row group consumed */
+  if (! upsample->spare_full)
+    (*in_row_group_ctr)++;
+}
+
+
+METHODDEF(void)
+merged_1v_upsample (j_decompress_ptr cinfo,
+		    JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+		    JDIMENSION in_row_groups_avail,
+		    JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+		    JDIMENSION out_rows_avail)
+/* 1:1 vertical sampling case: much easier, never need a spare row. */
+{
+  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+
+  /* Just do the upsampling. */
+  (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr,
+			 output_buf + *out_row_ctr);
+  /* Adjust counts */
+  (*out_row_ctr)++;
+  (*in_row_group_ctr)++;
+}
+
+
+/*
+ * These are the routines invoked by the control routines to do
+ * the actual upsampling/conversion.  One row group is processed per call.
+ *
+ * Note: since we may be writing directly into application-supplied buffers,
+ * we have to be honest about the output width; we can't assume the buffer
+ * has been rounded up to an even width.
+ */
+
+
+/*
+ * Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical.
+ */
+
+METHODDEF(void)
+h2v1_merged_upsample (j_decompress_ptr cinfo,
+		      JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+		      JSAMPARRAY output_buf)
+{
+  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+  register int y, cred, cgreen, cblue;
+  int cb, cr;
+  register JSAMPROW outptr;
+  JSAMPROW inptr0, inptr1, inptr2;
+  JDIMENSION col;
+  /* copy these pointers into registers if possible */
+  register JSAMPLE * range_limit = cinfo->sample_range_limit;
+  int * Crrtab = upsample->Cr_r_tab;
+  int * Cbbtab = upsample->Cb_b_tab;
+  INT32 * Crgtab = upsample->Cr_g_tab;
+  INT32 * Cbgtab = upsample->Cb_g_tab;
+  SHIFT_TEMPS
+
+  inptr0 = input_buf[0][in_row_group_ctr];
+  inptr1 = input_buf[1][in_row_group_ctr];
+  inptr2 = input_buf[2][in_row_group_ctr];
+  outptr = output_buf[0];
+  /* Loop for each pair of output pixels */
+  for (col = cinfo->output_width >> 1; col > 0; col--) {
+    /* Do the chroma part of the calculation */
+    cb = GETJSAMPLE(*inptr1++);
+    cr = GETJSAMPLE(*inptr2++);
+    cred = Crrtab[cr];
+    cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+    cblue = Cbbtab[cb];
+    /* Fetch 2 Y values and emit 2 pixels */
+    y  = GETJSAMPLE(*inptr0++);
+    outptr[RGB_RED] =   range_limit[y + cred];
+    outptr[RGB_GREEN] = range_limit[y + cgreen];
+    outptr[RGB_BLUE] =  range_limit[y + cblue];
+    outptr += RGB_PIXELSIZE;
+    y  = GETJSAMPLE(*inptr0++);
+    outptr[RGB_RED] =   range_limit[y + cred];
+    outptr[RGB_GREEN] = range_limit[y + cgreen];
+    outptr[RGB_BLUE] =  range_limit[y + cblue];
+    outptr += RGB_PIXELSIZE;
+  }
+  /* If image width is odd, do the last output column separately */
+  if (cinfo->output_width & 1) {
+    cb = GETJSAMPLE(*inptr1);
+    cr = GETJSAMPLE(*inptr2);
+    cred = Crrtab[cr];
+    cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+    cblue = Cbbtab[cb];
+    y  = GETJSAMPLE(*inptr0);
+    outptr[RGB_RED] =   range_limit[y + cred];
+    outptr[RGB_GREEN] = range_limit[y + cgreen];
+    outptr[RGB_BLUE] =  range_limit[y + cblue];
+  }
+}
+
+
+/*
+ * Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical.
+ */
+
+METHODDEF(void)
+h2v2_merged_upsample (j_decompress_ptr cinfo,
+		      JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+		      JSAMPARRAY output_buf)
+{
+  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+  register int y, cred, cgreen, cblue;
+  int cb, cr;
+  register JSAMPROW outptr0, outptr1;
+  JSAMPROW inptr00, inptr01, inptr1, inptr2;
+  JDIMENSION col;
+  /* copy these pointers into registers if possible */
+  register JSAMPLE * range_limit = cinfo->sample_range_limit;
+  int * Crrtab = upsample->Cr_r_tab;
+  int * Cbbtab = upsample->Cb_b_tab;
+  INT32 * Crgtab = upsample->Cr_g_tab;
+  INT32 * Cbgtab = upsample->Cb_g_tab;
+  SHIFT_TEMPS
+
+  inptr00 = input_buf[0][in_row_group_ctr*2];
+  inptr01 = input_buf[0][in_row_group_ctr*2 + 1];
+  inptr1 = input_buf[1][in_row_group_ctr];
+  inptr2 = input_buf[2][in_row_group_ctr];
+  outptr0 = output_buf[0];
+  outptr1 = output_buf[1];
+  /* Loop for each group of output pixels */
+  for (col = cinfo->output_width >> 1; col > 0; col--) {
+    /* Do the chroma part of the calculation */
+    cb = GETJSAMPLE(*inptr1++);
+    cr = GETJSAMPLE(*inptr2++);
+    cred = Crrtab[cr];
+    cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+    cblue = Cbbtab[cb];
+    /* Fetch 4 Y values and emit 4 pixels */
+    y  = GETJSAMPLE(*inptr00++);
+    outptr0[RGB_RED] =   range_limit[y + cred];
+    outptr0[RGB_GREEN] = range_limit[y + cgreen];
+    outptr0[RGB_BLUE] =  range_limit[y + cblue];
+    outptr0 += RGB_PIXELSIZE;
+    y  = GETJSAMPLE(*inptr00++);
+    outptr0[RGB_RED] =   range_limit[y + cred];
+    outptr0[RGB_GREEN] = range_limit[y + cgreen];
+    outptr0[RGB_BLUE] =  range_limit[y + cblue];
+    outptr0 += RGB_PIXELSIZE;
+    y  = GETJSAMPLE(*inptr01++);
+    outptr1[RGB_RED] =   range_limit[y + cred];
+    outptr1[RGB_GREEN] = range_limit[y + cgreen];
+    outptr1[RGB_BLUE] =  range_limit[y + cblue];
+    outptr1 += RGB_PIXELSIZE;
+    y  = GETJSAMPLE(*inptr01++);
+    outptr1[RGB_RED] =   range_limit[y + cred];
+    outptr1[RGB_GREEN] = range_limit[y + cgreen];
+    outptr1[RGB_BLUE] =  range_limit[y + cblue];
+    outptr1 += RGB_PIXELSIZE;
+  }
+  /* If image width is odd, do the last output column separately */
+  if (cinfo->output_width & 1) {
+    cb = GETJSAMPLE(*inptr1);
+    cr = GETJSAMPLE(*inptr2);
+    cred = Crrtab[cr];
+    cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+    cblue = Cbbtab[cb];
+    y  = GETJSAMPLE(*inptr00);
+    outptr0[RGB_RED] =   range_limit[y + cred];
+    outptr0[RGB_GREEN] = range_limit[y + cgreen];
+    outptr0[RGB_BLUE] =  range_limit[y + cblue];
+    y  = GETJSAMPLE(*inptr01);
+    outptr1[RGB_RED] =   range_limit[y + cred];
+    outptr1[RGB_GREEN] = range_limit[y + cgreen];
+    outptr1[RGB_BLUE] =  range_limit[y + cblue];
+  }
+}
+
+
+/*
+ * Module initialization routine for merged upsampling/color conversion.
+ *
+ * NB: this is called under the conditions determined by use_merged_upsample()
+ * in jdmaster.c.  That routine MUST correspond to the actual capabilities
+ * of this module; no safety checks are made here.
+ */
+
+GLOBAL(void)
+jinit_merged_upsampler (j_decompress_ptr cinfo)
+{
+  my_upsample_ptr upsample;
+
+  upsample = (my_upsample_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(my_upsampler));
+  cinfo->upsample = (struct jpeg_upsampler *) upsample;
+  upsample->pub.start_pass = start_pass_merged_upsample;
+  upsample->pub.need_context_rows = FALSE;
+
+  upsample->out_row_width = cinfo->output_width * cinfo->out_color_components;
+
+  if (cinfo->max_v_samp_factor == 2) {
+    upsample->pub.upsample = merged_2v_upsample;
+    upsample->upmethod = h2v2_merged_upsample;
+    /* Allocate a spare row buffer */
+    upsample->spare_row = (JSAMPROW)
+      (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+		(size_t) (upsample->out_row_width * SIZEOF(JSAMPLE)));
+  } else {
+    upsample->pub.upsample = merged_1v_upsample;
+    upsample->upmethod = h2v1_merged_upsample;
+    /* No spare row needed */
+    upsample->spare_row = NULL;
+  }
+
+  build_ycc_rgb_table(cinfo);
+}
+
+#endif /* UPSAMPLE_MERGING_SUPPORTED */
diff --git a/source/Irrlicht/jpeglib/jdosaobj.txt b/source/Irrlicht/jpeglib/jdosaobj.txt
new file mode 100644
index 00000000..b3b15add
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jdosaobj.txt
@@ -0,0 +1,16 @@
+This archive contains already-assembled object files for JMEMDOSA.ASM
+of the Independent JPEG Group's JPEG package.  These files will be helpful
+if you want to compile the IJG code for DOS, but don't have an assembler.
+
+These files were prepared from the 3/13/1992 version of JMEMDOSA.ASM,
+which is still unchanged as of mid-1998.  You can use these files with
+releases 3 through 6 of the IJG code, and probably future releases too.
+
+To use these files, copy the proper version to JMEMDOSA.OBJ.  Make sure
+this file has a newer date than JMEMDOSA.ASM.  Then compile the code as
+usual.
+
+Object files included:
+
+JDOSAMSC.OBJ	For Microsoft C version 5 or later.
+JDOSABCC.OBJ	For Borland C version 3.0 or later.
diff --git a/source/Irrlicht/jpeglib/jdpostct.c b/source/Irrlicht/jpeglib/jdpostct.c
new file mode 100644
index 00000000..7ba9eed5
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jdpostct.c
@@ -0,0 +1,290 @@
+/*
+ * jdpostct.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the decompression postprocessing controller.
+ * This controller manages the upsampling, color conversion, and color
+ * quantization/reduction steps; specifically, it controls the buffering
+ * between upsample/color conversion and color quantization/reduction.
+ *
+ * If no color quantization/reduction is required, then this module has no
+ * work to do, and it just hands off to the upsample/color conversion code.
+ * An integrated upsample/convert/quantize process would replace this module
+ * entirely.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private buffer controller object */
+
+typedef struct {
+  struct jpeg_d_post_controller pub; /* public fields */
+
+  /* Color quantization source buffer: this holds output data from
+   * the upsample/color conversion step to be passed to the quantizer.
+   * For two-pass color quantization, we need a full-image buffer;
+   * for one-pass operation, a strip buffer is sufficient.
+   */
+  jvirt_sarray_ptr whole_image;	/* virtual array, or NULL if one-pass */
+  JSAMPARRAY buffer;		/* strip buffer, or current strip of virtual */
+  JDIMENSION strip_height;	/* buffer size in rows */
+  /* for two-pass mode only: */
+  JDIMENSION starting_row;	/* row # of first row in current strip */
+  JDIMENSION next_row;		/* index of next row to fill/empty in strip */
+} my_post_controller;
+
+typedef my_post_controller * my_post_ptr;
+
+
+/* Forward declarations */
+METHODDEF(void) post_process_1pass
+	JPP((j_decompress_ptr cinfo,
+	     JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+	     JDIMENSION in_row_groups_avail,
+	     JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+	     JDIMENSION out_rows_avail));
+#ifdef QUANT_2PASS_SUPPORTED
+METHODDEF(void) post_process_prepass
+	JPP((j_decompress_ptr cinfo,
+	     JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+	     JDIMENSION in_row_groups_avail,
+	     JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+	     JDIMENSION out_rows_avail));
+METHODDEF(void) post_process_2pass
+	JPP((j_decompress_ptr cinfo,
+	     JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+	     JDIMENSION in_row_groups_avail,
+	     JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+	     JDIMENSION out_rows_avail));
+#endif
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_dpost (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+  my_post_ptr post = (my_post_ptr) cinfo->post;
+
+  switch (pass_mode) {
+  case JBUF_PASS_THRU:
+    if (cinfo->quantize_colors) {
+      /* Single-pass processing with color quantization. */
+      post->pub.post_process_data = post_process_1pass;
+      /* We could be doing buffered-image output before starting a 2-pass
+       * color quantization; in that case, jinit_d_post_controller did not
+       * allocate a strip buffer.  Use the virtual-array buffer as workspace.
+       */
+      if (post->buffer == NULL) {
+	post->buffer = (*cinfo->mem->access_virt_sarray)
+	  ((j_common_ptr) cinfo, post->whole_image,
+	   (JDIMENSION) 0, post->strip_height, TRUE);
+      }
+    } else {
+      /* For single-pass processing without color quantization,
+       * I have no work to do; just call the upsampler directly.
+       */
+      post->pub.post_process_data = cinfo->upsample->upsample;
+    }
+    break;
+#ifdef QUANT_2PASS_SUPPORTED
+  case JBUF_SAVE_AND_PASS:
+    /* First pass of 2-pass quantization */
+    if (post->whole_image == NULL)
+      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+    post->pub.post_process_data = post_process_prepass;
+    break;
+  case JBUF_CRANK_DEST:
+    /* Second pass of 2-pass quantization */
+    if (post->whole_image == NULL)
+      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+    post->pub.post_process_data = post_process_2pass;
+    break;
+#endif /* QUANT_2PASS_SUPPORTED */
+  default:
+    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+    break;
+  }
+  post->starting_row = post->next_row = 0;
+}
+
+
+/*
+ * Process some data in the one-pass (strip buffer) case.
+ * This is used for color precision reduction as well as one-pass quantization.
+ */
+
+METHODDEF(void)
+post_process_1pass (j_decompress_ptr cinfo,
+		    JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+		    JDIMENSION in_row_groups_avail,
+		    JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+		    JDIMENSION out_rows_avail)
+{
+  my_post_ptr post = (my_post_ptr) cinfo->post;
+  JDIMENSION num_rows, max_rows;
+
+  /* Fill the buffer, but not more than what we can dump out in one go. */
+  /* Note we rely on the upsampler to detect bottom of image. */
+  max_rows = out_rows_avail - *out_row_ctr;
+  if (max_rows > post->strip_height)
+    max_rows = post->strip_height;
+  num_rows = 0;
+  (*cinfo->upsample->upsample) (cinfo,
+		input_buf, in_row_group_ctr, in_row_groups_avail,
+		post->buffer, &num_rows, max_rows);
+  /* Quantize and emit data. */
+  (*cinfo->cquantize->color_quantize) (cinfo,
+		post->buffer, output_buf + *out_row_ctr, (int) num_rows);
+  *out_row_ctr += num_rows;
+}
+
+
+#ifdef QUANT_2PASS_SUPPORTED
+
+/*
+ * Process some data in the first pass of 2-pass quantization.
+ */
+
+METHODDEF(void)
+post_process_prepass (j_decompress_ptr cinfo,
+		      JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+		      JDIMENSION in_row_groups_avail,
+		      JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+		      JDIMENSION out_rows_avail)
+{
+  my_post_ptr post = (my_post_ptr) cinfo->post;
+  JDIMENSION old_next_row, num_rows;
+
+  /* Reposition virtual buffer if at start of strip. */
+  if (post->next_row == 0) {
+    post->buffer = (*cinfo->mem->access_virt_sarray)
+	((j_common_ptr) cinfo, post->whole_image,
+	 post->starting_row, post->strip_height, TRUE);
+  }
+
+  /* Upsample some data (up to a strip height's worth). */
+  old_next_row = post->next_row;
+  (*cinfo->upsample->upsample) (cinfo,
+		input_buf, in_row_group_ctr, in_row_groups_avail,
+		post->buffer, &post->next_row, post->strip_height);
+
+  /* Allow quantizer to scan new data.  No data is emitted, */
+  /* but we advance out_row_ctr so outer loop can tell when we're done. */
+  if (post->next_row > old_next_row) {
+    num_rows = post->next_row - old_next_row;
+    (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row,
+					 (JSAMPARRAY) NULL, (int) num_rows);
+    *out_row_ctr += num_rows;
+  }
+
+  /* Advance if we filled the strip. */
+  if (post->next_row >= post->strip_height) {
+    post->starting_row += post->strip_height;
+    post->next_row = 0;
+  }
+}
+
+
+/*
+ * Process some data in the second pass of 2-pass quantization.
+ */
+
+METHODDEF(void)
+post_process_2pass (j_decompress_ptr cinfo,
+		    JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+		    JDIMENSION in_row_groups_avail,
+		    JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+		    JDIMENSION out_rows_avail)
+{
+  my_post_ptr post = (my_post_ptr) cinfo->post;
+  JDIMENSION num_rows, max_rows;
+
+  /* Reposition virtual buffer if at start of strip. */
+  if (post->next_row == 0) {
+    post->buffer = (*cinfo->mem->access_virt_sarray)
+	((j_common_ptr) cinfo, post->whole_image,
+	 post->starting_row, post->strip_height, FALSE);
+  }
+
+  /* Determine number of rows to emit. */
+  num_rows = post->strip_height - post->next_row; /* available in strip */
+  max_rows = out_rows_avail - *out_row_ctr; /* available in output area */
+  if (num_rows > max_rows)
+    num_rows = max_rows;
+  /* We have to check bottom of image here, can't depend on upsampler. */
+  max_rows = cinfo->output_height - post->starting_row;
+  if (num_rows > max_rows)
+    num_rows = max_rows;
+
+  /* Quantize and emit data. */
+  (*cinfo->cquantize->color_quantize) (cinfo,
+		post->buffer + post->next_row, output_buf + *out_row_ctr,
+		(int) num_rows);
+  *out_row_ctr += num_rows;
+
+  /* Advance if we filled the strip. */
+  post->next_row += num_rows;
+  if (post->next_row >= post->strip_height) {
+    post->starting_row += post->strip_height;
+    post->next_row = 0;
+  }
+}
+
+#endif /* QUANT_2PASS_SUPPORTED */
+
+
+/*
+ * Initialize postprocessing controller.
+ */
+
+GLOBAL(void)
+jinit_d_post_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
+{
+  my_post_ptr post;
+
+  post = (my_post_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(my_post_controller));
+  cinfo->post = (struct jpeg_d_post_controller *) post;
+  post->pub.start_pass = start_pass_dpost;
+  post->whole_image = NULL;	/* flag for no virtual arrays */
+  post->buffer = NULL;		/* flag for no strip buffer */
+
+  /* Create the quantization buffer, if needed */
+  if (cinfo->quantize_colors) {
+    /* The buffer strip height is max_v_samp_factor, which is typically
+     * an efficient number of rows for upsampling to return.
+     * (In the presence of output rescaling, we might want to be smarter?)
+     */
+    post->strip_height = (JDIMENSION) cinfo->max_v_samp_factor;
+    if (need_full_buffer) {
+      /* Two-pass color quantization: need full-image storage. */
+      /* We round up the number of rows to a multiple of the strip height. */
+#ifdef QUANT_2PASS_SUPPORTED
+      post->whole_image = (*cinfo->mem->request_virt_sarray)
+	((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+	 cinfo->output_width * cinfo->out_color_components,
+	 (JDIMENSION) jround_up((long) cinfo->output_height,
+				(long) post->strip_height),
+	 post->strip_height);
+#else
+      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+#endif /* QUANT_2PASS_SUPPORTED */
+    } else {
+      /* One-pass color quantization: just make a strip buffer. */
+      post->buffer = (*cinfo->mem->alloc_sarray)
+	((j_common_ptr) cinfo, JPOOL_IMAGE,
+	 cinfo->output_width * cinfo->out_color_components,
+	 post->strip_height);
+    }
+  }
+}
diff --git a/source/Irrlicht/jpeglib/jdsample.c b/source/Irrlicht/jpeglib/jdsample.c
new file mode 100644
index 00000000..94f9599f
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jdsample.c
@@ -0,0 +1,361 @@
+/*
+ * jdsample.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * Modified 2002-2008 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains upsampling routines.
+ *
+ * Upsampling input data is counted in "row groups".  A row group
+ * is defined to be (v_samp_factor * DCT_v_scaled_size / min_DCT_v_scaled_size)
+ * sample rows of each component.  Upsampling will normally produce
+ * max_v_samp_factor pixel rows from each row group (but this could vary
+ * if the upsampler is applying a scale factor of its own).
+ *
+ * An excellent reference for image resampling is
+ *   Digital Image Warping, George Wolberg, 1990.
+ *   Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Pointer to routine to upsample a single component */
+typedef JMETHOD(void, upsample1_ptr,
+		(j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		 JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr));
+
+/* Private subobject */
+
+typedef struct {
+  struct jpeg_upsampler pub;	/* public fields */
+
+  /* Color conversion buffer.  When using separate upsampling and color
+   * conversion steps, this buffer holds one upsampled row group until it
+   * has been color converted and output.
+   * Note: we do not allocate any storage for component(s) which are full-size,
+   * ie do not need rescaling.  The corresponding entry of color_buf[] is
+   * simply set to point to the input data array, thereby avoiding copying.
+   */
+  JSAMPARRAY color_buf[MAX_COMPONENTS];
+
+  /* Per-component upsampling method pointers */
+  upsample1_ptr methods[MAX_COMPONENTS];
+
+  int next_row_out;		/* counts rows emitted from color_buf */
+  JDIMENSION rows_to_go;	/* counts rows remaining in image */
+
+  /* Height of an input row group for each component. */
+  int rowgroup_height[MAX_COMPONENTS];
+
+  /* These arrays save pixel expansion factors so that int_expand need not
+   * recompute them each time.  They are unused for other upsampling methods.
+   */
+  UINT8 h_expand[MAX_COMPONENTS];
+  UINT8 v_expand[MAX_COMPONENTS];
+} my_upsampler;
+
+typedef my_upsampler * my_upsample_ptr;
+
+
+/*
+ * Initialize for an upsampling pass.
+ */
+
+METHODDEF(void)
+start_pass_upsample (j_decompress_ptr cinfo)
+{
+  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+
+  /* Mark the conversion buffer empty */
+  upsample->next_row_out = cinfo->max_v_samp_factor;
+  /* Initialize total-height counter for detecting bottom of image */
+  upsample->rows_to_go = cinfo->output_height;
+}
+
+
+/*
+ * Control routine to do upsampling (and color conversion).
+ *
+ * In this version we upsample each component independently.
+ * We upsample one row group into the conversion buffer, then apply
+ * color conversion a row at a time.
+ */
+
+METHODDEF(void)
+sep_upsample (j_decompress_ptr cinfo,
+	      JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+	      JDIMENSION in_row_groups_avail,
+	      JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+	      JDIMENSION out_rows_avail)
+{
+  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+  int ci;
+  jpeg_component_info * compptr;
+  JDIMENSION num_rows;
+
+  /* Fill the conversion buffer, if it's empty */
+  if (upsample->next_row_out >= cinfo->max_v_samp_factor) {
+    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+	 ci++, compptr++) {
+      /* Invoke per-component upsample method.  Notice we pass a POINTER
+       * to color_buf[ci], so that fullsize_upsample can change it.
+       */
+      (*upsample->methods[ci]) (cinfo, compptr,
+	input_buf[ci] + (*in_row_group_ctr * upsample->rowgroup_height[ci]),
+	upsample->color_buf + ci);
+    }
+    upsample->next_row_out = 0;
+  }
+
+  /* Color-convert and emit rows */
+
+  /* How many we have in the buffer: */
+  num_rows = (JDIMENSION) (cinfo->max_v_samp_factor - upsample->next_row_out);
+  /* Not more than the distance to the end of the image.  Need this test
+   * in case the image height is not a multiple of max_v_samp_factor:
+   */
+  if (num_rows > upsample->rows_to_go) 
+    num_rows = upsample->rows_to_go;
+  /* And not more than what the client can accept: */
+  out_rows_avail -= *out_row_ctr;
+  if (num_rows > out_rows_avail)
+    num_rows = out_rows_avail;
+
+  (*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf,
+				     (JDIMENSION) upsample->next_row_out,
+				     output_buf + *out_row_ctr,
+				     (int) num_rows);
+
+  /* Adjust counts */
+  *out_row_ctr += num_rows;
+  upsample->rows_to_go -= num_rows;
+  upsample->next_row_out += num_rows;
+  /* When the buffer is emptied, declare this input row group consumed */
+  if (upsample->next_row_out >= cinfo->max_v_samp_factor)
+    (*in_row_group_ctr)++;
+}
+
+
+/*
+ * These are the routines invoked by sep_upsample to upsample pixel values
+ * of a single component.  One row group is processed per call.
+ */
+
+
+/*
+ * For full-size components, we just make color_buf[ci] point at the
+ * input buffer, and thus avoid copying any data.  Note that this is
+ * safe only because sep_upsample doesn't declare the input row group
+ * "consumed" until we are done color converting and emitting it.
+ */
+
+METHODDEF(void)
+fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		   JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+  *output_data_ptr = input_data;
+}
+
+
+/*
+ * This is a no-op version used for "uninteresting" components.
+ * These components will not be referenced by color conversion.
+ */
+
+METHODDEF(void)
+noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	       JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+  *output_data_ptr = NULL;	/* safety check */
+}
+
+
+/*
+ * This version handles any integral sampling ratios.
+ * This is not used for typical JPEG files, so it need not be fast.
+ * Nor, for that matter, is it particularly accurate: the algorithm is
+ * simple replication of the input pixel onto the corresponding output
+ * pixels.  The hi-falutin sampling literature refers to this as a
+ * "box filter".  A box filter tends to introduce visible artifacts,
+ * so if you are actually going to use 3:1 or 4:1 sampling ratios
+ * you would be well advised to improve this code.
+ */
+
+METHODDEF(void)
+int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	      JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+  JSAMPARRAY output_data = *output_data_ptr;
+  register JSAMPROW inptr, outptr;
+  register JSAMPLE invalue;
+  register int h;
+  JSAMPROW outend;
+  int h_expand, v_expand;
+  int inrow, outrow;
+
+  h_expand = upsample->h_expand[compptr->component_index];
+  v_expand = upsample->v_expand[compptr->component_index];
+
+  inrow = outrow = 0;
+  while (outrow < cinfo->max_v_samp_factor) {
+    /* Generate one output row with proper horizontal expansion */
+    inptr = input_data[inrow];
+    outptr = output_data[outrow];
+    outend = outptr + cinfo->output_width;
+    while (outptr < outend) {
+      invalue = *inptr++;	/* don't need GETJSAMPLE() here */
+      for (h = h_expand; h > 0; h--) {
+	*outptr++ = invalue;
+      }
+    }
+    /* Generate any additional output rows by duplicating the first one */
+    if (v_expand > 1) {
+      jcopy_sample_rows(output_data, outrow, output_data, outrow+1,
+			v_expand-1, cinfo->output_width);
+    }
+    inrow++;
+    outrow += v_expand;
+  }
+}
+
+
+/*
+ * Fast processing for the common case of 2:1 horizontal and 1:1 vertical.
+ * It's still a box filter.
+ */
+
+METHODDEF(void)
+h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	       JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+  JSAMPARRAY output_data = *output_data_ptr;
+  register JSAMPROW inptr, outptr;
+  register JSAMPLE invalue;
+  JSAMPROW outend;
+  int outrow;
+
+  for (outrow = 0; outrow < cinfo->max_v_samp_factor; outrow++) {
+    inptr = input_data[outrow];
+    outptr = output_data[outrow];
+    outend = outptr + cinfo->output_width;
+    while (outptr < outend) {
+      invalue = *inptr++;	/* don't need GETJSAMPLE() here */
+      *outptr++ = invalue;
+      *outptr++ = invalue;
+    }
+  }
+}
+
+
+/*
+ * Fast processing for the common case of 2:1 horizontal and 2:1 vertical.
+ * It's still a box filter.
+ */
+
+METHODDEF(void)
+h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	       JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+  JSAMPARRAY output_data = *output_data_ptr;
+  register JSAMPROW inptr, outptr;
+  register JSAMPLE invalue;
+  JSAMPROW outend;
+  int inrow, outrow;
+
+  inrow = outrow = 0;
+  while (outrow < cinfo->max_v_samp_factor) {
+    inptr = input_data[inrow];
+    outptr = output_data[outrow];
+    outend = outptr + cinfo->output_width;
+    while (outptr < outend) {
+      invalue = *inptr++;	/* don't need GETJSAMPLE() here */
+      *outptr++ = invalue;
+      *outptr++ = invalue;
+    }
+    jcopy_sample_rows(output_data, outrow, output_data, outrow+1,
+		      1, cinfo->output_width);
+    inrow++;
+    outrow += 2;
+  }
+}
+
+
+/*
+ * Module initialization routine for upsampling.
+ */
+
+GLOBAL(void)
+jinit_upsampler (j_decompress_ptr cinfo)
+{
+  my_upsample_ptr upsample;
+  int ci;
+  jpeg_component_info * compptr;
+  boolean need_buffer;
+  int h_in_group, v_in_group, h_out_group, v_out_group;
+
+  upsample = (my_upsample_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(my_upsampler));
+  cinfo->upsample = (struct jpeg_upsampler *) upsample;
+  upsample->pub.start_pass = start_pass_upsample;
+  upsample->pub.upsample = sep_upsample;
+  upsample->pub.need_context_rows = FALSE; /* until we find out differently */
+
+  if (cinfo->CCIR601_sampling)	/* this isn't supported */
+    ERREXIT(cinfo, JERR_CCIR601_NOTIMPL);
+
+  /* Verify we can handle the sampling factors, select per-component methods,
+   * and create storage as needed.
+   */
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    /* Compute size of an "input group" after IDCT scaling.  This many samples
+     * are to be converted to max_h_samp_factor * max_v_samp_factor pixels.
+     */
+    h_in_group = (compptr->h_samp_factor * compptr->DCT_h_scaled_size) /
+		 cinfo->min_DCT_h_scaled_size;
+    v_in_group = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+		 cinfo->min_DCT_v_scaled_size;
+    h_out_group = cinfo->max_h_samp_factor;
+    v_out_group = cinfo->max_v_samp_factor;
+    upsample->rowgroup_height[ci] = v_in_group; /* save for use later */
+    need_buffer = TRUE;
+    if (! compptr->component_needed) {
+      /* Don't bother to upsample an uninteresting component. */
+      upsample->methods[ci] = noop_upsample;
+      need_buffer = FALSE;
+    } else if (h_in_group == h_out_group && v_in_group == v_out_group) {
+      /* Fullsize components can be processed without any work. */
+      upsample->methods[ci] = fullsize_upsample;
+      need_buffer = FALSE;
+    } else if (h_in_group * 2 == h_out_group &&
+	       v_in_group == v_out_group) {
+      /* Special case for 2h1v upsampling */
+      upsample->methods[ci] = h2v1_upsample;
+    } else if (h_in_group * 2 == h_out_group &&
+	       v_in_group * 2 == v_out_group) {
+      /* Special case for 2h2v upsampling */
+      upsample->methods[ci] = h2v2_upsample;
+    } else if ((h_out_group % h_in_group) == 0 &&
+	       (v_out_group % v_in_group) == 0) {
+      /* Generic integral-factors upsampling method */
+      upsample->methods[ci] = int_upsample;
+      upsample->h_expand[ci] = (UINT8) (h_out_group / h_in_group);
+      upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group);
+    } else
+      ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);
+    if (need_buffer) {
+      upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray)
+	((j_common_ptr) cinfo, JPOOL_IMAGE,
+	 (JDIMENSION) jround_up((long) cinfo->output_width,
+				(long) cinfo->max_h_samp_factor),
+	 (JDIMENSION) cinfo->max_v_samp_factor);
+    }
+  }
+}
diff --git a/source/Irrlicht/jpeglib/jdtrans.c b/source/Irrlicht/jpeglib/jdtrans.c
new file mode 100644
index 00000000..a51d69de
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jdtrans.c
@@ -0,0 +1,140 @@
+/*
+ * jdtrans.c
+ *
+ * Copyright (C) 1995-1997, Thomas G. Lane.
+ * Modified 2000-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains library routines for transcoding decompression,
+ * that is, reading raw DCT coefficient arrays from an input JPEG file.
+ * The routines in jdapimin.c will also be needed by a transcoder.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Forward declarations */
+LOCAL(void) transdecode_master_selection JPP((j_decompress_ptr cinfo));
+
+
+/*
+ * Read the coefficient arrays from a JPEG file.
+ * jpeg_read_header must be completed before calling this.
+ *
+ * The entire image is read into a set of virtual coefficient-block arrays,
+ * one per component.  The return value is a pointer to the array of
+ * virtual-array descriptors.  These can be manipulated directly via the
+ * JPEG memory manager, or handed off to jpeg_write_coefficients().
+ * To release the memory occupied by the virtual arrays, call
+ * jpeg_finish_decompress() when done with the data.
+ *
+ * An alternative usage is to simply obtain access to the coefficient arrays
+ * during a buffered-image-mode decompression operation.  This is allowed
+ * after any jpeg_finish_output() call.  The arrays can be accessed until
+ * jpeg_finish_decompress() is called.  (Note that any call to the library
+ * may reposition the arrays, so don't rely on access_virt_barray() results
+ * to stay valid across library calls.)
+ *
+ * Returns NULL if suspended.  This case need be checked only if
+ * a suspending data source is used.
+ */
+
+GLOBAL(jvirt_barray_ptr *)
+jpeg_read_coefficients (j_decompress_ptr cinfo)
+{
+  if (cinfo->global_state == DSTATE_READY) {
+    /* First call: initialize active modules */
+    transdecode_master_selection(cinfo);
+    cinfo->global_state = DSTATE_RDCOEFS;
+  }
+  if (cinfo->global_state == DSTATE_RDCOEFS) {
+    /* Absorb whole file into the coef buffer */
+    for (;;) {
+      int retcode;
+      /* Call progress monitor hook if present */
+      if (cinfo->progress != NULL)
+	(*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+      /* Absorb some more input */
+      retcode = (*cinfo->inputctl->consume_input) (cinfo);
+      if (retcode == JPEG_SUSPENDED)
+	return NULL;
+      if (retcode == JPEG_REACHED_EOI)
+	break;
+      /* Advance progress counter if appropriate */
+      if (cinfo->progress != NULL &&
+	  (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {
+	if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) {
+	  /* startup underestimated number of scans; ratchet up one scan */
+	  cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows;
+	}
+      }
+    }
+    /* Set state so that jpeg_finish_decompress does the right thing */
+    cinfo->global_state = DSTATE_STOPPING;
+  }
+  /* At this point we should be in state DSTATE_STOPPING if being used
+   * standalone, or in state DSTATE_BUFIMAGE if being invoked to get access
+   * to the coefficients during a full buffered-image-mode decompression.
+   */
+  if ((cinfo->global_state == DSTATE_STOPPING ||
+       cinfo->global_state == DSTATE_BUFIMAGE) && cinfo->buffered_image) {
+    return cinfo->coef->coef_arrays;
+  }
+  /* Oops, improper usage */
+  ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+  return NULL;			/* keep compiler happy */
+}
+
+
+/*
+ * Master selection of decompression modules for transcoding.
+ * This substitutes for jdmaster.c's initialization of the full decompressor.
+ */
+
+LOCAL(void)
+transdecode_master_selection (j_decompress_ptr cinfo)
+{
+  /* This is effectively a buffered-image operation. */
+  cinfo->buffered_image = TRUE;
+
+  /* Compute output image dimensions and related values. */
+  jpeg_core_output_dimensions(cinfo);
+
+  /* Entropy decoding: either Huffman or arithmetic coding. */
+  if (cinfo->arith_code)
+    jinit_arith_decoder(cinfo);
+  else {
+    jinit_huff_decoder(cinfo);
+  }
+
+  /* Always get a full-image coefficient buffer. */
+  jinit_d_coef_controller(cinfo, TRUE);
+
+  /* We can now tell the memory manager to allocate virtual arrays. */
+  (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
+
+  /* Initialize input side of decompressor to consume first scan. */
+  (*cinfo->inputctl->start_input_pass) (cinfo);
+
+  /* Initialize progress monitoring. */
+  if (cinfo->progress != NULL) {
+    int nscans;
+    /* Estimate number of scans to set pass_limit. */
+    if (cinfo->progressive_mode) {
+      /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */
+      nscans = 2 + 3 * cinfo->num_components;
+    } else if (cinfo->inputctl->has_multiple_scans) {
+      /* For a nonprogressive multiscan file, estimate 1 scan per component. */
+      nscans = cinfo->num_components;
+    } else {
+      nscans = 1;
+    }
+    cinfo->progress->pass_counter = 0L;
+    cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans;
+    cinfo->progress->completed_passes = 0;
+    cinfo->progress->total_passes = 1;
+  }
+}
diff --git a/source/Irrlicht/jpeglib/jerror.c b/source/Irrlicht/jpeglib/jerror.c
new file mode 100644
index 00000000..dcba3980
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jerror.c
@@ -0,0 +1,253 @@
+/*
+ * jerror.c
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Modified 2012 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains simple error-reporting and trace-message routines.
+ * These are suitable for Unix-like systems and others where writing to
+ * stderr is the right thing to do.  Many applications will want to replace
+ * some or all of these routines.
+ *
+ * If you define USE_WINDOWS_MESSAGEBOX in jconfig.h or in the makefile,
+ * you get a Windows-specific hack to display error messages in a dialog box.
+ * It ain't much, but it beats dropping error messages into the bit bucket,
+ * which is what happens to output to stderr under most Windows C compilers.
+ *
+ * These routines are used by both the compression and decompression code.
+ */
+
+/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jversion.h"
+#include "jerror.h"
+
+#ifdef USE_WINDOWS_MESSAGEBOX
+#include 
+#endif
+
+#ifndef EXIT_FAILURE		/* define exit() codes if not provided */
+#define EXIT_FAILURE  1
+#endif
+
+
+/*
+ * Create the message string table.
+ * We do this from the master message list in jerror.h by re-reading
+ * jerror.h with a suitable definition for macro JMESSAGE.
+ * The message table is made an external symbol just in case any applications
+ * want to refer to it directly.
+ */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jpeg_std_message_table	jMsgTable
+#endif
+
+#define JMESSAGE(code,string)	string ,
+
+const char * const jpeg_std_message_table[] = {
+#include "jerror.h"
+  NULL
+};
+
+
+/*
+ * Error exit handler: must not return to caller.
+ *
+ * Applications may override this if they want to get control back after
+ * an error.  Typically one would longjmp somewhere instead of exiting.
+ * The setjmp buffer can be made a private field within an expanded error
+ * handler object.  Note that the info needed to generate an error message
+ * is stored in the error object, so you can generate the message now or
+ * later, at your convenience.
+ * You should make sure that the JPEG object is cleaned up (with jpeg_abort
+ * or jpeg_destroy) at some point.
+ */
+
+METHODDEF(noreturn_t)
+error_exit (j_common_ptr cinfo)
+{
+  /* Always display the message */
+  (*cinfo->err->output_message) (cinfo);
+
+  /* Let the memory manager delete any temp files before we die */
+  jpeg_destroy(cinfo);
+
+  exit(EXIT_FAILURE);
+}
+
+
+/*
+ * Actual output of an error or trace message.
+ * Applications may override this method to send JPEG messages somewhere
+ * other than stderr.
+ *
+ * On Windows, printing to stderr is generally completely useless,
+ * so we provide optional code to produce an error-dialog popup.
+ * Most Windows applications will still prefer to override this routine,
+ * but if they don't, it'll do something at least marginally useful.
+ *
+ * NOTE: to use the library in an environment that doesn't support the
+ * C stdio library, you may have to delete the call to fprintf() entirely,
+ * not just not use this routine.
+ */
+
+METHODDEF(void)
+output_message (j_common_ptr cinfo)
+{
+  char buffer[JMSG_LENGTH_MAX];
+
+  /* Create the message */
+  (*cinfo->err->format_message) (cinfo, buffer);
+
+#ifdef USE_WINDOWS_MESSAGEBOX
+  /* Display it in a message dialog box */
+  MessageBox(GetActiveWindow(), buffer, "JPEG Library Error",
+	     MB_OK | MB_ICONERROR);
+#else
+  /* Send it to stderr, adding a newline */
+  fprintf(stderr, "%s\n", buffer);
+#endif
+}
+
+
+/*
+ * Decide whether to emit a trace or warning message.
+ * msg_level is one of:
+ *   -1: recoverable corrupt-data warning, may want to abort.
+ *    0: important advisory messages (always display to user).
+ *    1: first level of tracing detail.
+ *    2,3,...: successively more detailed tracing messages.
+ * An application might override this method if it wanted to abort on warnings
+ * or change the policy about which messages to display.
+ */
+
+METHODDEF(void)
+emit_message (j_common_ptr cinfo, int msg_level)
+{
+  struct jpeg_error_mgr * err = cinfo->err;
+
+  if (msg_level < 0) {
+    /* It's a warning message.  Since corrupt files may generate many warnings,
+     * the policy implemented here is to show only the first warning,
+     * unless trace_level >= 3.
+     */
+    if (err->num_warnings == 0 || err->trace_level >= 3)
+      (*err->output_message) (cinfo);
+    /* Always count warnings in num_warnings. */
+    err->num_warnings++;
+  } else {
+    /* It's a trace message.  Show it if trace_level >= msg_level. */
+    if (err->trace_level >= msg_level)
+      (*err->output_message) (cinfo);
+  }
+}
+
+
+/*
+ * Format a message string for the most recent JPEG error or message.
+ * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX
+ * characters.  Note that no '\n' character is added to the string.
+ * Few applications should need to override this method.
+ */
+
+METHODDEF(void)
+format_message (j_common_ptr cinfo, char * buffer)
+{
+  struct jpeg_error_mgr * err = cinfo->err;
+  int msg_code = err->msg_code;
+  const char * msgtext = NULL;
+  const char * msgptr;
+  char ch;
+  boolean isstring;
+
+  /* Look up message string in proper table */
+  if (msg_code > 0 && msg_code <= err->last_jpeg_message) {
+    msgtext = err->jpeg_message_table[msg_code];
+  } else if (err->addon_message_table != NULL &&
+	     msg_code >= err->first_addon_message &&
+	     msg_code <= err->last_addon_message) {
+    msgtext = err->addon_message_table[msg_code - err->first_addon_message];
+  }
+
+  /* Defend against bogus message number */
+  if (msgtext == NULL) {
+    err->msg_parm.i[0] = msg_code;
+    msgtext = err->jpeg_message_table[0];
+  }
+
+  /* Check for string parameter, as indicated by %s in the message text */
+  isstring = FALSE;
+  msgptr = msgtext;
+  while ((ch = *msgptr++) != '\0') {
+    if (ch == '%') {
+      if (*msgptr == 's') isstring = TRUE;
+      break;
+    }
+  }
+
+  /* Format the message into the passed buffer */
+  if (isstring)
+    sprintf(buffer, msgtext, err->msg_parm.s);
+  else
+    sprintf(buffer, msgtext,
+	    err->msg_parm.i[0], err->msg_parm.i[1],
+	    err->msg_parm.i[2], err->msg_parm.i[3],
+	    err->msg_parm.i[4], err->msg_parm.i[5],
+	    err->msg_parm.i[6], err->msg_parm.i[7]);
+}
+
+
+/*
+ * Reset error state variables at start of a new image.
+ * This is called during compression startup to reset trace/error
+ * processing to default state, without losing any application-specific
+ * method pointers.  An application might possibly want to override
+ * this method if it has additional error processing state.
+ */
+
+METHODDEF(void)
+reset_error_mgr (j_common_ptr cinfo)
+{
+  cinfo->err->num_warnings = 0;
+  /* trace_level is not reset since it is an application-supplied parameter */
+  cinfo->err->msg_code = 0;	/* may be useful as a flag for "no error" */
+}
+
+
+/*
+ * Fill in the standard error-handling methods in a jpeg_error_mgr object.
+ * Typical call is:
+ *	struct jpeg_compress_struct cinfo;
+ *	struct jpeg_error_mgr err;
+ *
+ *	cinfo.err = jpeg_std_error(&err);
+ * after which the application may override some of the methods.
+ */
+
+GLOBAL(struct jpeg_error_mgr *)
+jpeg_std_error (struct jpeg_error_mgr * err)
+{
+  err->error_exit = error_exit;
+  err->emit_message = emit_message;
+  err->output_message = output_message;
+  err->format_message = format_message;
+  err->reset_error_mgr = reset_error_mgr;
+
+  err->trace_level = 0;		/* default = no tracing */
+  err->num_warnings = 0;	/* no warnings emitted yet */
+  err->msg_code = 0;		/* may be useful as a flag for "no error" */
+
+  /* Initialize message table pointers */
+  err->jpeg_message_table = jpeg_std_message_table;
+  err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1;
+
+  err->addon_message_table = NULL;
+  err->first_addon_message = 0;	/* for safety */
+  err->last_addon_message = 0;
+
+  return err;
+}
diff --git a/source/Irrlicht/jpeglib/jerror.h b/source/Irrlicht/jpeglib/jerror.h
new file mode 100644
index 00000000..b32da9a5
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jerror.h
@@ -0,0 +1,304 @@
+/*
+ * jerror.h
+ *
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * Modified 1997-2012 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file defines the error and message codes for the JPEG library.
+ * Edit this file to add new codes, or to translate the message strings to
+ * some other language.
+ * A set of error-reporting macros are defined too.  Some applications using
+ * the JPEG library may wish to include this file to get the error codes
+ * and/or the macros.
+ */
+
+/*
+ * To define the enum list of message codes, include this file without
+ * defining macro JMESSAGE.  To create a message string table, include it
+ * again with a suitable JMESSAGE definition (see jerror.c for an example).
+ */
+#ifndef JMESSAGE
+#ifndef JERROR_H
+/* First time through, define the enum list */
+#define JMAKE_ENUM_LIST
+#else
+/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */
+#define JMESSAGE(code,string)
+#endif /* JERROR_H */
+#endif /* JMESSAGE */
+
+#ifdef JMAKE_ENUM_LIST
+
+typedef enum {
+
+#define JMESSAGE(code,string)	code ,
+
+#endif /* JMAKE_ENUM_LIST */
+
+JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */
+
+/* For maintenance convenience, list is alphabetical by message code name */
+JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix")
+JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix")
+JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode")
+JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS")
+JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request")
+JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range")
+JMESSAGE(JERR_BAD_DCTSIZE, "DCT scaled block size %dx%d not supported")
+JMESSAGE(JERR_BAD_DROP_SAMPLING,
+	 "Component index %d: mismatching sampling ratio %d:%d, %d:%d, %c")
+JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition")
+JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace")
+JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace")
+JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length")
+JMESSAGE(JERR_BAD_LIB_VERSION,
+	 "Wrong JPEG library version: library is %d, caller expects %d")
+JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan")
+JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d")
+JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d")
+JMESSAGE(JERR_BAD_PROGRESSION,
+	 "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d")
+JMESSAGE(JERR_BAD_PROG_SCRIPT,
+	 "Invalid progressive parameters at scan script entry %d")
+JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors")
+JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d")
+JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d")
+JMESSAGE(JERR_BAD_STRUCT_SIZE,
+	 "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u")
+JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access")
+JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small")
+JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here")
+JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet")
+JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d")
+JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request")
+JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d")
+JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x")
+JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d")
+JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d")
+JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)")
+JMESSAGE(JERR_EMS_READ, "Read from EMS failed")
+JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed")
+JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan")
+JMESSAGE(JERR_FILE_READ, "Input file read error")
+JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?")
+JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet")
+JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow")
+JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry")
+JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels")
+JMESSAGE(JERR_INPUT_EMPTY, "Empty input file")
+JMESSAGE(JERR_INPUT_EOF, "Premature end of input file")
+JMESSAGE(JERR_MISMATCHED_QUANT_TABLE,
+	 "Cannot transcode due to multiple use of quantization table %d")
+JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data")
+JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change")
+JMESSAGE(JERR_NOTIMPL, "Not implemented yet")
+JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time")
+JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined")
+JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported")
+JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined")
+JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image")
+JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined")
+JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x")
+JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)")
+JMESSAGE(JERR_QUANT_COMPONENTS,
+	 "Cannot quantize more than %d color components")
+JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors")
+JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors")
+JMESSAGE(JERR_SOF_BEFORE, "Invalid JPEG file structure: %s before SOF")
+JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers")
+JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker")
+JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x")
+JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers")
+JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s")
+JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file")
+JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file")
+JMESSAGE(JERR_TFILE_WRITE,
+	 "Write failed on temporary file --- out of disk space?")
+JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines")
+JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x")
+JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up")
+JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation")
+JMESSAGE(JERR_XMS_READ, "Read from XMS failed")
+JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed")
+JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT)
+JMESSAGE(JMSG_VERSION, JVERSION)
+JMESSAGE(JTRC_16BIT_TABLES,
+	 "Caution: quantization tables are too coarse for baseline JPEG")
+JMESSAGE(JTRC_ADOBE,
+	 "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d")
+JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u")
+JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u")
+JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x")
+JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x")
+JMESSAGE(JTRC_DQT, "Define Quantization Table %d  precision %d")
+JMESSAGE(JTRC_DRI, "Define Restart Interval %u")
+JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u")
+JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u")
+JMESSAGE(JTRC_EOI, "End Of Image")
+JMESSAGE(JTRC_HUFFBITS, "        %3d %3d %3d %3d %3d %3d %3d %3d")
+JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d  %d")
+JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE,
+	 "Warning: thumbnail image size does not match data length %u")
+JMESSAGE(JTRC_JFIF_EXTENSION,
+	 "JFIF extension marker: type 0x%02x, length %u")
+JMESSAGE(JTRC_JFIF_THUMBNAIL, "    with %d x %d thumbnail image")
+JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u")
+JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x")
+JMESSAGE(JTRC_QUANTVALS, "        %4u %4u %4u %4u %4u %4u %4u %4u")
+JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors")
+JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors")
+JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization")
+JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d")
+JMESSAGE(JTRC_RST, "RST%d")
+JMESSAGE(JTRC_SMOOTH_NOTIMPL,
+	 "Smoothing not supported with nonstandard sampling ratios")
+JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d")
+JMESSAGE(JTRC_SOF_COMPONENT, "    Component %d: %dhx%dv q=%d")
+JMESSAGE(JTRC_SOI, "Start of Image")
+JMESSAGE(JTRC_SOS, "Start Of Scan: %d components")
+JMESSAGE(JTRC_SOS_COMPONENT, "    Component %d: dc=%d ac=%d")
+JMESSAGE(JTRC_SOS_PARAMS, "  Ss=%d, Se=%d, Ah=%d, Al=%d")
+JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s")
+JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s")
+JMESSAGE(JTRC_THUMB_JPEG,
+	 "JFIF extension marker: JPEG-compressed thumbnail image, length %u")
+JMESSAGE(JTRC_THUMB_PALETTE,
+	 "JFIF extension marker: palette thumbnail image, length %u")
+JMESSAGE(JTRC_THUMB_RGB,
+	 "JFIF extension marker: RGB thumbnail image, length %u")
+JMESSAGE(JTRC_UNKNOWN_IDS,
+	 "Unrecognized component IDs %d %d %d, assuming YCbCr")
+JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u")
+JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u")
+JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d")
+JMESSAGE(JWRN_ARITH_BAD_CODE, "Corrupt JPEG data: bad arithmetic code")
+JMESSAGE(JWRN_BOGUS_PROGRESSION,
+	 "Inconsistent progression sequence for component %d coefficient %d")
+JMESSAGE(JWRN_EXTRANEOUS_DATA,
+	 "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x")
+JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment")
+JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code")
+JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d")
+JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file")
+JMESSAGE(JWRN_MUST_RESYNC,
+	 "Corrupt JPEG data: found marker 0x%02x instead of RST%d")
+JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG")
+JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines")
+
+#ifdef JMAKE_ENUM_LIST
+
+  JMSG_LASTMSGCODE
+} J_MESSAGE_CODE;
+
+#undef JMAKE_ENUM_LIST
+#endif /* JMAKE_ENUM_LIST */
+
+/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */
+#undef JMESSAGE
+
+
+#ifndef JERROR_H
+#define JERROR_H
+
+/* Macros to simplify using the error and trace message stuff */
+/* The first parameter is either type of cinfo pointer */
+
+/* Fatal errors (print message and exit) */
+#define ERREXIT(cinfo,code)  \
+  ((cinfo)->err->msg_code = (code), \
+   (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT1(cinfo,code,p1)  \
+  ((cinfo)->err->msg_code = (code), \
+   (cinfo)->err->msg_parm.i[0] = (p1), \
+   (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT2(cinfo,code,p1,p2)  \
+  ((cinfo)->err->msg_code = (code), \
+   (cinfo)->err->msg_parm.i[0] = (p1), \
+   (cinfo)->err->msg_parm.i[1] = (p2), \
+   (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT3(cinfo,code,p1,p2,p3)  \
+  ((cinfo)->err->msg_code = (code), \
+   (cinfo)->err->msg_parm.i[0] = (p1), \
+   (cinfo)->err->msg_parm.i[1] = (p2), \
+   (cinfo)->err->msg_parm.i[2] = (p3), \
+   (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT4(cinfo,code,p1,p2,p3,p4)  \
+  ((cinfo)->err->msg_code = (code), \
+   (cinfo)->err->msg_parm.i[0] = (p1), \
+   (cinfo)->err->msg_parm.i[1] = (p2), \
+   (cinfo)->err->msg_parm.i[2] = (p3), \
+   (cinfo)->err->msg_parm.i[3] = (p4), \
+   (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT6(cinfo,code,p1,p2,p3,p4,p5,p6)  \
+  ((cinfo)->err->msg_code = (code), \
+   (cinfo)->err->msg_parm.i[0] = (p1), \
+   (cinfo)->err->msg_parm.i[1] = (p2), \
+   (cinfo)->err->msg_parm.i[2] = (p3), \
+   (cinfo)->err->msg_parm.i[3] = (p4), \
+   (cinfo)->err->msg_parm.i[4] = (p5), \
+   (cinfo)->err->msg_parm.i[5] = (p6), \
+   (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXITS(cinfo,code,str)  \
+  ((cinfo)->err->msg_code = (code), \
+   strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
+   (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+
+#define MAKESTMT(stuff)		do { stuff } while (0)
+
+/* Nonfatal errors (we can keep going, but the data is probably corrupt) */
+#define WARNMS(cinfo,code)  \
+  ((cinfo)->err->msg_code = (code), \
+   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
+#define WARNMS1(cinfo,code,p1)  \
+  ((cinfo)->err->msg_code = (code), \
+   (cinfo)->err->msg_parm.i[0] = (p1), \
+   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
+#define WARNMS2(cinfo,code,p1,p2)  \
+  ((cinfo)->err->msg_code = (code), \
+   (cinfo)->err->msg_parm.i[0] = (p1), \
+   (cinfo)->err->msg_parm.i[1] = (p2), \
+   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
+
+/* Informational/debugging messages */
+#define TRACEMS(cinfo,lvl,code)  \
+  ((cinfo)->err->msg_code = (code), \
+   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+#define TRACEMS1(cinfo,lvl,code,p1)  \
+  ((cinfo)->err->msg_code = (code), \
+   (cinfo)->err->msg_parm.i[0] = (p1), \
+   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+#define TRACEMS2(cinfo,lvl,code,p1,p2)  \
+  ((cinfo)->err->msg_code = (code), \
+   (cinfo)->err->msg_parm.i[0] = (p1), \
+   (cinfo)->err->msg_parm.i[1] = (p2), \
+   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+#define TRACEMS3(cinfo,lvl,code,p1,p2,p3)  \
+  MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+	   _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \
+	   (cinfo)->err->msg_code = (code); \
+	   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4)  \
+  MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+	   _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
+	   (cinfo)->err->msg_code = (code); \
+	   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5)  \
+  MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+	   _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
+	   _mp[4] = (p5); \
+	   (cinfo)->err->msg_code = (code); \
+	   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8)  \
+  MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+	   _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
+	   _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \
+	   (cinfo)->err->msg_code = (code); \
+	   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMSS(cinfo,lvl,code,str)  \
+  ((cinfo)->err->msg_code = (code), \
+   strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
+   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+
+#endif /* JERROR_H */
diff --git a/source/Irrlicht/jpeglib/jfdctflt.c b/source/Irrlicht/jpeglib/jfdctflt.c
new file mode 100644
index 00000000..3c1b1748
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jfdctflt.c
@@ -0,0 +1,174 @@
+/*
+ * jfdctflt.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2003-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a floating-point implementation of the
+ * forward DCT (Discrete Cosine Transform).
+ *
+ * This implementation should be more accurate than either of the integer
+ * DCT implementations.  However, it may not give the same results on all
+ * machines because of differences in roundoff behavior.  Speed will depend
+ * on the hardware's floating point capacity.
+ *
+ * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
+ * on each column.  Direct algorithms are also available, but they are
+ * much more complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on Arai, Agui, and Nakajima's algorithm for
+ * scaled DCT.  Their original paper (Trans. IEICE E-71(11):1095) is in
+ * Japanese, but the algorithm is described in the Pennebaker & Mitchell
+ * JPEG textbook (see REFERENCES section in file README).  The following code
+ * is based directly on figure 4-8 in P&M.
+ * While an 8-point DCT cannot be done in less than 11 multiplies, it is
+ * possible to arrange the computation so that many of the multiplies are
+ * simple scalings of the final outputs.  These multiplies can then be
+ * folded into the multiplications or divisions by the JPEG quantization
+ * table entries.  The AA&N method leaves only 5 multiplies and 29 adds
+ * to be done in the DCT itself.
+ * The primary disadvantage of this method is that with a fixed-point
+ * implementation, accuracy is lost due to imprecise representation of the
+ * scaled quantization values.  However, that problem does not arise if
+ * we use floating point arithmetic.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h"		/* Private declarations for DCT subsystem */
+
+#ifdef DCT_FLOAT_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+  Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/*
+ * Perform the forward DCT on one block of samples.
+ */
+
+GLOBAL(void)
+jpeg_fdct_float (FAST_FLOAT * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+  FAST_FLOAT tmp10, tmp11, tmp12, tmp13;
+  FAST_FLOAT z1, z2, z3, z4, z5, z11, z13;
+  FAST_FLOAT *dataptr;
+  JSAMPROW elemptr;
+  int ctr;
+
+  /* Pass 1: process rows. */
+
+  dataptr = data;
+  for (ctr = 0; ctr < DCTSIZE; ctr++) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Load data into workspace */
+    tmp0 = (FAST_FLOAT) (GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]));
+    tmp7 = (FAST_FLOAT) (GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]));
+    tmp1 = (FAST_FLOAT) (GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]));
+    tmp6 = (FAST_FLOAT) (GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]));
+    tmp2 = (FAST_FLOAT) (GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]));
+    tmp5 = (FAST_FLOAT) (GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]));
+    tmp3 = (FAST_FLOAT) (GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]));
+    tmp4 = (FAST_FLOAT) (GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]));
+
+    /* Even part */
+
+    tmp10 = tmp0 + tmp3;	/* phase 2 */
+    tmp13 = tmp0 - tmp3;
+    tmp11 = tmp1 + tmp2;
+    tmp12 = tmp1 - tmp2;
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = tmp10 + tmp11 - 8 * CENTERJSAMPLE; /* phase 3 */
+    dataptr[4] = tmp10 - tmp11;
+
+    z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */
+    dataptr[2] = tmp13 + z1;	/* phase 5 */
+    dataptr[6] = tmp13 - z1;
+
+    /* Odd part */
+
+    tmp10 = tmp4 + tmp5;	/* phase 2 */
+    tmp11 = tmp5 + tmp6;
+    tmp12 = tmp6 + tmp7;
+
+    /* The rotator is modified from fig 4-8 to avoid extra negations. */
+    z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */
+    z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */
+    z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */
+    z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */
+
+    z11 = tmp7 + z3;		/* phase 5 */
+    z13 = tmp7 - z3;
+
+    dataptr[5] = z13 + z2;	/* phase 6 */
+    dataptr[3] = z13 - z2;
+    dataptr[1] = z11 + z4;
+    dataptr[7] = z11 - z4;
+
+    dataptr += DCTSIZE;		/* advance pointer to next row */
+  }
+
+  /* Pass 2: process columns. */
+
+  dataptr = data;
+  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
+    tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
+    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
+    tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
+    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
+    tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
+    tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
+    tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
+
+    /* Even part */
+
+    tmp10 = tmp0 + tmp3;	/* phase 2 */
+    tmp13 = tmp0 - tmp3;
+    tmp11 = tmp1 + tmp2;
+    tmp12 = tmp1 - tmp2;
+
+    dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */
+    dataptr[DCTSIZE*4] = tmp10 - tmp11;
+
+    z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */
+    dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */
+    dataptr[DCTSIZE*6] = tmp13 - z1;
+
+    /* Odd part */
+
+    tmp10 = tmp4 + tmp5;	/* phase 2 */
+    tmp11 = tmp5 + tmp6;
+    tmp12 = tmp6 + tmp7;
+
+    /* The rotator is modified from fig 4-8 to avoid extra negations. */
+    z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */
+    z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */
+    z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */
+    z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */
+
+    z11 = tmp7 + z3;		/* phase 5 */
+    z13 = tmp7 - z3;
+
+    dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */
+    dataptr[DCTSIZE*3] = z13 - z2;
+    dataptr[DCTSIZE*1] = z11 + z4;
+    dataptr[DCTSIZE*7] = z11 - z4;
+
+    dataptr++;			/* advance pointer to next column */
+  }
+}
+
+#endif /* DCT_FLOAT_SUPPORTED */
diff --git a/source/Irrlicht/jpeglib/jfdctfst.c b/source/Irrlicht/jpeglib/jfdctfst.c
new file mode 100644
index 00000000..82b92317
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jfdctfst.c
@@ -0,0 +1,230 @@
+/*
+ * jfdctfst.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2003-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a fast, not so accurate integer implementation of the
+ * forward DCT (Discrete Cosine Transform).
+ *
+ * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
+ * on each column.  Direct algorithms are also available, but they are
+ * much more complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on Arai, Agui, and Nakajima's algorithm for
+ * scaled DCT.  Their original paper (Trans. IEICE E-71(11):1095) is in
+ * Japanese, but the algorithm is described in the Pennebaker & Mitchell
+ * JPEG textbook (see REFERENCES section in file README).  The following code
+ * is based directly on figure 4-8 in P&M.
+ * While an 8-point DCT cannot be done in less than 11 multiplies, it is
+ * possible to arrange the computation so that many of the multiplies are
+ * simple scalings of the final outputs.  These multiplies can then be
+ * folded into the multiplications or divisions by the JPEG quantization
+ * table entries.  The AA&N method leaves only 5 multiplies and 29 adds
+ * to be done in the DCT itself.
+ * The primary disadvantage of this method is that with fixed-point math,
+ * accuracy is lost due to imprecise representation of the scaled
+ * quantization values.  The smaller the quantization table entry, the less
+ * precise the scaled value, so this implementation does worse with high-
+ * quality-setting files than with low-quality ones.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h"		/* Private declarations for DCT subsystem */
+
+#ifdef DCT_IFAST_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+  Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/* Scaling decisions are generally the same as in the LL&M algorithm;
+ * see jfdctint.c for more details.  However, we choose to descale
+ * (right shift) multiplication products as soon as they are formed,
+ * rather than carrying additional fractional bits into subsequent additions.
+ * This compromises accuracy slightly, but it lets us save a few shifts.
+ * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples)
+ * everywhere except in the multiplications proper; this saves a good deal
+ * of work on 16-bit-int machines.
+ *
+ * Again to save a few shifts, the intermediate results between pass 1 and
+ * pass 2 are not upscaled, but are represented only to integral precision.
+ *
+ * A final compromise is to represent the multiplicative constants to only
+ * 8 fractional bits, rather than 13.  This saves some shifting work on some
+ * machines, and may also reduce the cost of multiplication (since there
+ * are fewer one-bits in the constants).
+ */
+
+#define CONST_BITS  8
+
+
+/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
+ * causing a lot of useless floating-point operations at run time.
+ * To get around this we use the following pre-calculated constants.
+ * If you change CONST_BITS you may want to add appropriate values.
+ * (With a reasonable C compiler, you can just rely on the FIX() macro...)
+ */
+
+#if CONST_BITS == 8
+#define FIX_0_382683433  ((INT32)   98)		/* FIX(0.382683433) */
+#define FIX_0_541196100  ((INT32)  139)		/* FIX(0.541196100) */
+#define FIX_0_707106781  ((INT32)  181)		/* FIX(0.707106781) */
+#define FIX_1_306562965  ((INT32)  334)		/* FIX(1.306562965) */
+#else
+#define FIX_0_382683433  FIX(0.382683433)
+#define FIX_0_541196100  FIX(0.541196100)
+#define FIX_0_707106781  FIX(0.707106781)
+#define FIX_1_306562965  FIX(1.306562965)
+#endif
+
+
+/* We can gain a little more speed, with a further compromise in accuracy,
+ * by omitting the addition in a descaling shift.  This yields an incorrectly
+ * rounded result half the time...
+ */
+
+#ifndef USE_ACCURATE_ROUNDING
+#undef DESCALE
+#define DESCALE(x,n)  RIGHT_SHIFT(x, n)
+#endif
+
+
+/* Multiply a DCTELEM variable by an INT32 constant, and immediately
+ * descale to yield a DCTELEM result.
+ */
+
+#define MULTIPLY(var,const)  ((DCTELEM) DESCALE((var) * (const), CONST_BITS))
+
+
+/*
+ * Perform the forward DCT on one block of samples.
+ */
+
+GLOBAL(void)
+jpeg_fdct_ifast (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+  DCTELEM tmp10, tmp11, tmp12, tmp13;
+  DCTELEM z1, z2, z3, z4, z5, z11, z13;
+  DCTELEM *dataptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pass 1: process rows. */
+
+  dataptr = data;
+  for (ctr = 0; ctr < DCTSIZE; ctr++) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Load data into workspace */
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]);
+    tmp7 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]);
+    tmp6 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]);
+    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]);
+    tmp5 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]);
+    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]);
+    tmp4 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]);
+
+    /* Even part */
+
+    tmp10 = tmp0 + tmp3;	/* phase 2 */
+    tmp13 = tmp0 - tmp3;
+    tmp11 = tmp1 + tmp2;
+    tmp12 = tmp1 - tmp2;
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = tmp10 + tmp11 - 8 * CENTERJSAMPLE; /* phase 3 */
+    dataptr[4] = tmp10 - tmp11;
+
+    z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */
+    dataptr[2] = tmp13 + z1;	/* phase 5 */
+    dataptr[6] = tmp13 - z1;
+
+    /* Odd part */
+
+    tmp10 = tmp4 + tmp5;	/* phase 2 */
+    tmp11 = tmp5 + tmp6;
+    tmp12 = tmp6 + tmp7;
+
+    /* The rotator is modified from fig 4-8 to avoid extra negations. */
+    z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */
+    z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */
+    z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */
+    z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */
+
+    z11 = tmp7 + z3;		/* phase 5 */
+    z13 = tmp7 - z3;
+
+    dataptr[5] = z13 + z2;	/* phase 6 */
+    dataptr[3] = z13 - z2;
+    dataptr[1] = z11 + z4;
+    dataptr[7] = z11 - z4;
+
+    dataptr += DCTSIZE;		/* advance pointer to next row */
+  }
+
+  /* Pass 2: process columns. */
+
+  dataptr = data;
+  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
+    tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
+    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
+    tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
+    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
+    tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
+    tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
+    tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
+
+    /* Even part */
+
+    tmp10 = tmp0 + tmp3;	/* phase 2 */
+    tmp13 = tmp0 - tmp3;
+    tmp11 = tmp1 + tmp2;
+    tmp12 = tmp1 - tmp2;
+
+    dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */
+    dataptr[DCTSIZE*4] = tmp10 - tmp11;
+
+    z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */
+    dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */
+    dataptr[DCTSIZE*6] = tmp13 - z1;
+
+    /* Odd part */
+
+    tmp10 = tmp4 + tmp5;	/* phase 2 */
+    tmp11 = tmp5 + tmp6;
+    tmp12 = tmp6 + tmp7;
+
+    /* The rotator is modified from fig 4-8 to avoid extra negations. */
+    z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */
+    z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */
+    z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */
+    z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */
+
+    z11 = tmp7 + z3;		/* phase 5 */
+    z13 = tmp7 - z3;
+
+    dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */
+    dataptr[DCTSIZE*3] = z13 - z2;
+    dataptr[DCTSIZE*1] = z11 + z4;
+    dataptr[DCTSIZE*7] = z11 - z4;
+
+    dataptr++;			/* advance pointer to next column */
+  }
+}
+
+#endif /* DCT_IFAST_SUPPORTED */
diff --git a/source/Irrlicht/jpeglib/jfdctint.c b/source/Irrlicht/jpeglib/jfdctint.c
new file mode 100644
index 00000000..4dd7cb9e
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jfdctint.c
@@ -0,0 +1,4406 @@
+/*
+ * jfdctint.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * Modification developed 2003-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a slow-but-accurate integer implementation of the
+ * forward DCT (Discrete Cosine Transform).
+ *
+ * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
+ * on each column.  Direct algorithms are also available, but they are
+ * much more complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on an algorithm described in
+ *   C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT
+ *   Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics,
+ *   Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.
+ * The primary algorithm described there uses 11 multiplies and 29 adds.
+ * We use their alternate method with 12 multiplies and 32 adds.
+ * The advantage of this method is that no data path contains more than one
+ * multiplication; this allows a very simple and accurate implementation in
+ * scaled fixed-point arithmetic, with a minimal number of shifts.
+ *
+ * We also provide FDCT routines with various input sample block sizes for
+ * direct resolution reduction or enlargement and for direct resolving the
+ * common 2x1 and 1x2 subsampling cases without additional resampling: NxN
+ * (N=1...16), 2NxN, and Nx2N (N=1...8) pixels for one 8x8 output DCT block.
+ *
+ * For N<8 we fill the remaining block coefficients with zero.
+ * For N>8 we apply a partial N-point FDCT on the input samples, computing
+ * just the lower 8 frequency coefficients and discarding the rest.
+ *
+ * We must scale the output coefficients of the N-point FDCT appropriately
+ * to the standard 8-point FDCT level by 8/N per 1-D pass.  This scaling
+ * is folded into the constant multipliers (pass 2) and/or final/initial
+ * shifting.
+ *
+ * CAUTION: We rely on the FIX() macro except for the N=1,2,4,8 cases
+ * since there would be too many additional constants to pre-calculate.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h"		/* Private declarations for DCT subsystem */
+
+#ifdef DCT_ISLOW_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+  Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */
+#endif
+
+
+/*
+ * The poop on this scaling stuff is as follows:
+ *
+ * Each 1-D DCT step produces outputs which are a factor of sqrt(N)
+ * larger than the true DCT outputs.  The final outputs are therefore
+ * a factor of N larger than desired; since N=8 this can be cured by
+ * a simple right shift at the end of the algorithm.  The advantage of
+ * this arrangement is that we save two multiplications per 1-D DCT,
+ * because the y0 and y4 outputs need not be divided by sqrt(N).
+ * In the IJG code, this factor of 8 is removed by the quantization step
+ * (in jcdctmgr.c), NOT in this module.
+ *
+ * We have to do addition and subtraction of the integer inputs, which
+ * is no problem, and multiplication by fractional constants, which is
+ * a problem to do in integer arithmetic.  We multiply all the constants
+ * by CONST_SCALE and convert them to integer constants (thus retaining
+ * CONST_BITS bits of precision in the constants).  After doing a
+ * multiplication we have to divide the product by CONST_SCALE, with proper
+ * rounding, to produce the correct output.  This division can be done
+ * cheaply as a right shift of CONST_BITS bits.  We postpone shifting
+ * as long as possible so that partial sums can be added together with
+ * full fractional precision.
+ *
+ * The outputs of the first pass are scaled up by PASS1_BITS bits so that
+ * they are represented to better-than-integral precision.  These outputs
+ * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word
+ * with the recommended scaling.  (For 12-bit sample data, the intermediate
+ * array is INT32 anyway.)
+ *
+ * To avoid overflow of the 32-bit intermediate results in pass 2, we must
+ * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26.  Error analysis
+ * shows that the values given below are the most effective.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define CONST_BITS  13
+#define PASS1_BITS  2
+#else
+#define CONST_BITS  13
+#define PASS1_BITS  1		/* lose a little precision to avoid overflow */
+#endif
+
+/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
+ * causing a lot of useless floating-point operations at run time.
+ * To get around this we use the following pre-calculated constants.
+ * If you change CONST_BITS you may want to add appropriate values.
+ * (With a reasonable C compiler, you can just rely on the FIX() macro...)
+ */
+
+#if CONST_BITS == 13
+#define FIX_0_298631336  ((INT32)  2446)	/* FIX(0.298631336) */
+#define FIX_0_390180644  ((INT32)  3196)	/* FIX(0.390180644) */
+#define FIX_0_541196100  ((INT32)  4433)	/* FIX(0.541196100) */
+#define FIX_0_765366865  ((INT32)  6270)	/* FIX(0.765366865) */
+#define FIX_0_899976223  ((INT32)  7373)	/* FIX(0.899976223) */
+#define FIX_1_175875602  ((INT32)  9633)	/* FIX(1.175875602) */
+#define FIX_1_501321110  ((INT32)  12299)	/* FIX(1.501321110) */
+#define FIX_1_847759065  ((INT32)  15137)	/* FIX(1.847759065) */
+#define FIX_1_961570560  ((INT32)  16069)	/* FIX(1.961570560) */
+#define FIX_2_053119869  ((INT32)  16819)	/* FIX(2.053119869) */
+#define FIX_2_562915447  ((INT32)  20995)	/* FIX(2.562915447) */
+#define FIX_3_072711026  ((INT32)  25172)	/* FIX(3.072711026) */
+#else
+#define FIX_0_298631336  FIX(0.298631336)
+#define FIX_0_390180644  FIX(0.390180644)
+#define FIX_0_541196100  FIX(0.541196100)
+#define FIX_0_765366865  FIX(0.765366865)
+#define FIX_0_899976223  FIX(0.899976223)
+#define FIX_1_175875602  FIX(1.175875602)
+#define FIX_1_501321110  FIX(1.501321110)
+#define FIX_1_847759065  FIX(1.847759065)
+#define FIX_1_961570560  FIX(1.961570560)
+#define FIX_2_053119869  FIX(2.053119869)
+#define FIX_2_562915447  FIX(2.562915447)
+#define FIX_3_072711026  FIX(3.072711026)
+#endif
+
+
+/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
+ * For 8-bit samples with the recommended scaling, all the variable
+ * and constant values involved are no more than 16 bits wide, so a
+ * 16x16->32 bit multiply can be used instead of a full 32x32 multiply.
+ * For 12-bit samples, a full 32-bit multiplication will be needed.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define MULTIPLY(var,const)  MULTIPLY16C16(var,const)
+#else
+#define MULTIPLY(var,const)  ((var) * (const))
+#endif
+
+
+/*
+ * Perform the forward DCT on one block of samples.
+ */
+
+GLOBAL(void)
+jpeg_fdct_islow (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3;
+  INT32 tmp10, tmp11, tmp12, tmp13;
+  INT32 z1;
+  DCTELEM *dataptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * cK represents sqrt(2) * cos(K*pi/16).
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < DCTSIZE; ctr++) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part per LL&M figure 1 --- note that published figure is faulty;
+     * rotator "c1" should be "c6".
+     */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]);
+    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]);
+    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]);
+
+    tmp10 = tmp0 + tmp3;
+    tmp12 = tmp0 - tmp3;
+    tmp11 = tmp1 + tmp2;
+    tmp13 = tmp1 - tmp2;
+
+    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]);
+    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]);
+    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]);
+    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM) ((tmp10 + tmp11 - 8 * CENTERJSAMPLE) << PASS1_BITS);
+    dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS);
+
+    z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);       /* c6 */
+    /* Add fudge factor here for final descale. */
+    z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+    dataptr[2] = (DCTELEM)
+      RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), /* c2-c6 */
+		  CONST_BITS-PASS1_BITS);
+    dataptr[6] = (DCTELEM)
+      RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), /* c2+c6 */
+		  CONST_BITS-PASS1_BITS);
+
+    /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+     * i0..i3 in the paper are tmp0..tmp3 here.
+     */
+
+    tmp12 = tmp0 + tmp2;
+    tmp13 = tmp1 + tmp3;
+
+    z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602);       /*  c3 */
+    /* Add fudge factor here for final descale. */
+    z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+    tmp12 = MULTIPLY(tmp12, - FIX_0_390180644);          /* -c3+c5 */
+    tmp13 = MULTIPLY(tmp13, - FIX_1_961570560);          /* -c3-c5 */
+    tmp12 += z1;
+    tmp13 += z1;
+
+    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223);       /* -c3+c7 */
+    tmp0 = MULTIPLY(tmp0, FIX_1_501321110);              /*  c1+c3-c5-c7 */
+    tmp3 = MULTIPLY(tmp3, FIX_0_298631336);              /* -c1+c3+c5-c7 */
+    tmp0 += z1 + tmp12;
+    tmp3 += z1 + tmp13;
+
+    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447);       /* -c1-c3 */
+    tmp1 = MULTIPLY(tmp1, FIX_3_072711026);              /*  c1+c3+c5-c7 */
+    tmp2 = MULTIPLY(tmp2, FIX_2_053119869);              /*  c1+c3-c5+c7 */
+    tmp1 += z1 + tmp13;
+    tmp2 += z1 + tmp12;
+
+    dataptr[1] = (DCTELEM) RIGHT_SHIFT(tmp0, CONST_BITS-PASS1_BITS);
+    dataptr[3] = (DCTELEM) RIGHT_SHIFT(tmp1, CONST_BITS-PASS1_BITS);
+    dataptr[5] = (DCTELEM) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS);
+    dataptr[7] = (DCTELEM) RIGHT_SHIFT(tmp3, CONST_BITS-PASS1_BITS);
+
+    dataptr += DCTSIZE;		/* advance pointer to next row */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   * cK represents sqrt(2) * cos(K*pi/16).
+   */
+
+  dataptr = data;
+  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+    /* Even part per LL&M figure 1 --- note that published figure is faulty;
+     * rotator "c1" should be "c6".
+     */
+
+    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
+    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
+    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
+    tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
+
+    /* Add fudge factor here for final descale. */
+    tmp10 = tmp0 + tmp3 + (ONE << (PASS1_BITS-1));
+    tmp12 = tmp0 - tmp3;
+    tmp11 = tmp1 + tmp2;
+    tmp13 = tmp1 - tmp2;
+
+    tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
+    tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
+    tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
+    tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
+
+    dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp10 + tmp11, PASS1_BITS);
+    dataptr[DCTSIZE*4] = (DCTELEM) RIGHT_SHIFT(tmp10 - tmp11, PASS1_BITS);
+
+    z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);       /* c6 */
+    /* Add fudge factor here for final descale. */
+    z1 += ONE << (CONST_BITS+PASS1_BITS-1);
+
+    dataptr[DCTSIZE*2] = (DCTELEM)
+      RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), /* c2-c6 */
+		  CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*6] = (DCTELEM)
+      RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), /* c2+c6 */
+		  CONST_BITS+PASS1_BITS);
+
+    /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+     * i0..i3 in the paper are tmp0..tmp3 here.
+     */
+
+    tmp12 = tmp0 + tmp2;
+    tmp13 = tmp1 + tmp3;
+
+    z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602);       /*  c3 */
+    /* Add fudge factor here for final descale. */
+    z1 += ONE << (CONST_BITS+PASS1_BITS-1);
+
+    tmp12 = MULTIPLY(tmp12, - FIX_0_390180644);          /* -c3+c5 */
+    tmp13 = MULTIPLY(tmp13, - FIX_1_961570560);          /* -c3-c5 */
+    tmp12 += z1;
+    tmp13 += z1;
+
+    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223);       /* -c3+c7 */
+    tmp0 = MULTIPLY(tmp0, FIX_1_501321110);              /*  c1+c3-c5-c7 */
+    tmp3 = MULTIPLY(tmp3, FIX_0_298631336);              /* -c1+c3+c5-c7 */
+    tmp0 += z1 + tmp12;
+    tmp3 += z1 + tmp13;
+
+    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447);       /* -c1-c3 */
+    tmp1 = MULTIPLY(tmp1, FIX_3_072711026);              /*  c1+c3+c5-c7 */
+    tmp2 = MULTIPLY(tmp2, FIX_2_053119869);              /*  c1+c3-c5+c7 */
+    tmp1 += z1 + tmp13;
+    tmp2 += z1 + tmp12;
+
+    dataptr[DCTSIZE*1] = (DCTELEM) RIGHT_SHIFT(tmp0, CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*3] = (DCTELEM) RIGHT_SHIFT(tmp1, CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*5] = (DCTELEM) RIGHT_SHIFT(tmp2, CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*7] = (DCTELEM) RIGHT_SHIFT(tmp3, CONST_BITS+PASS1_BITS);
+
+    dataptr++;			/* advance pointer to next column */
+  }
+}
+
+#ifdef DCT_SCALING_SUPPORTED
+
+
+/*
+ * Perform the forward DCT on a 7x7 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_7x7 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3;
+  INT32 tmp10, tmp11, tmp12;
+  INT32 z1, z2, z3;
+  DCTELEM *dataptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pre-zero output coefficient block. */
+  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * cK represents sqrt(2) * cos(K*pi/14).
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 7; ctr++) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[6]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[5]);
+    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[4]);
+    tmp3 = GETJSAMPLE(elemptr[3]);
+
+    tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[6]);
+    tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[5]);
+    tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[4]);
+
+    z1 = tmp0 + tmp2;
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((z1 + tmp1 + tmp3 - 7 * CENTERJSAMPLE) << PASS1_BITS);
+    tmp3 += tmp3;
+    z1 -= tmp3;
+    z1 -= tmp3;
+    z1 = MULTIPLY(z1, FIX(0.353553391));                /* (c2+c6-c4)/2 */
+    z2 = MULTIPLY(tmp0 - tmp2, FIX(0.920609002));       /* (c2+c4-c6)/2 */
+    z3 = MULTIPLY(tmp1 - tmp2, FIX(0.314692123));       /* c6 */
+    dataptr[2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS-PASS1_BITS);
+    z1 -= z2;
+    z2 = MULTIPLY(tmp0 - tmp1, FIX(0.881747734));       /* c4 */
+    dataptr[4] = (DCTELEM)
+      DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.707106781)), /* c2+c6-c4 */
+	      CONST_BITS-PASS1_BITS);
+    dataptr[6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS-PASS1_BITS);
+
+    /* Odd part */
+
+    tmp1 = MULTIPLY(tmp10 + tmp11, FIX(0.935414347));   /* (c3+c1-c5)/2 */
+    tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.170262339));   /* (c3+c5-c1)/2 */
+    tmp0 = tmp1 - tmp2;
+    tmp1 += tmp2;
+    tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.378756276)); /* -c1 */
+    tmp1 += tmp2;
+    tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.613604268));   /* c5 */
+    tmp0 += tmp3;
+    tmp2 += tmp3 + MULTIPLY(tmp12, FIX(1.870828693));   /* c3+c1-c5 */
+
+    dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-PASS1_BITS);
+    dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-PASS1_BITS);
+    dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-PASS1_BITS);
+
+    dataptr += DCTSIZE;		/* advance pointer to next row */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   * We must also scale the output by (8/7)**2 = 64/49, which we fold
+   * into the constant multipliers:
+   * cK now represents sqrt(2) * cos(K*pi/14) * 64/49.
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 7; ctr++) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*6];
+    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*5];
+    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*4];
+    tmp3 = dataptr[DCTSIZE*3];
+
+    tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*6];
+    tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*5];
+    tmp12 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*4];
+
+    z1 = tmp0 + tmp2;
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(MULTIPLY(z1 + tmp1 + tmp3, FIX(1.306122449)), /* 64/49 */
+	      CONST_BITS+PASS1_BITS);
+    tmp3 += tmp3;
+    z1 -= tmp3;
+    z1 -= tmp3;
+    z1 = MULTIPLY(z1, FIX(0.461784020));                /* (c2+c6-c4)/2 */
+    z2 = MULTIPLY(tmp0 - tmp2, FIX(1.202428084));       /* (c2+c4-c6)/2 */
+    z3 = MULTIPLY(tmp1 - tmp2, FIX(0.411026446));       /* c6 */
+    dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS+PASS1_BITS);
+    z1 -= z2;
+    z2 = MULTIPLY(tmp0 - tmp1, FIX(1.151670509));       /* c4 */
+    dataptr[DCTSIZE*4] = (DCTELEM)
+      DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.923568041)), /* c2+c6-c4 */
+	      CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS+PASS1_BITS);
+
+    /* Odd part */
+
+    tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.221765677));   /* (c3+c1-c5)/2 */
+    tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.222383464));   /* (c3+c5-c1)/2 */
+    tmp0 = tmp1 - tmp2;
+    tmp1 += tmp2;
+    tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.800824523)); /* -c1 */
+    tmp1 += tmp2;
+    tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.801442310));   /* c5 */
+    tmp0 += tmp3;
+    tmp2 += tmp3 + MULTIPLY(tmp12, FIX(2.443531355));   /* c3+c1-c5 */
+
+    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+PASS1_BITS);
+
+    dataptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 6x6 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_6x6 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2;
+  INT32 tmp10, tmp11, tmp12;
+  DCTELEM *dataptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pre-zero output coefficient block. */
+  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * cK represents sqrt(2) * cos(K*pi/12).
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 6; ctr++) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[5]);
+    tmp11 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[4]);
+    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[3]);
+
+    tmp10 = tmp0 + tmp2;
+    tmp12 = tmp0 - tmp2;
+
+    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[5]);
+    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[4]);
+    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[3]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((tmp10 + tmp11 - 6 * CENTERJSAMPLE) << PASS1_BITS);
+    dataptr[2] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp12, FIX(1.224744871)),                 /* c2 */
+	      CONST_BITS-PASS1_BITS);
+    dataptr[4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(0.707106781)), /* c4 */
+	      CONST_BITS-PASS1_BITS);
+
+    /* Odd part */
+
+    tmp10 = DESCALE(MULTIPLY(tmp0 + tmp2, FIX(0.366025404)),     /* c5 */
+		    CONST_BITS-PASS1_BITS);
+
+    dataptr[1] = (DCTELEM) (tmp10 + ((tmp0 + tmp1) << PASS1_BITS));
+    dataptr[3] = (DCTELEM) ((tmp0 - tmp1 - tmp2) << PASS1_BITS);
+    dataptr[5] = (DCTELEM) (tmp10 + ((tmp2 - tmp1) << PASS1_BITS));
+
+    dataptr += DCTSIZE;		/* advance pointer to next row */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   * We must also scale the output by (8/6)**2 = 16/9, which we fold
+   * into the constant multipliers:
+   * cK now represents sqrt(2) * cos(K*pi/12) * 16/9.
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 6; ctr++) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*5];
+    tmp11 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*4];
+    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*3];
+
+    tmp10 = tmp0 + tmp2;
+    tmp12 = tmp0 - tmp2;
+
+    tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*5];
+    tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*4];
+    tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*3];
+
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 + tmp11, FIX(1.777777778)),         /* 16/9 */
+	      CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*2] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp12, FIX(2.177324216)),                 /* c2 */
+	      CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(1.257078722)), /* c4 */
+	      CONST_BITS+PASS1_BITS);
+
+    /* Odd part */
+
+    tmp10 = MULTIPLY(tmp0 + tmp2, FIX(0.650711829));             /* c5 */
+
+    dataptr[DCTSIZE*1] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp0 + tmp1, FIX(1.777777778)),   /* 16/9 */
+	      CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*3] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp0 - tmp1 - tmp2, FIX(1.777777778)),    /* 16/9 */
+	      CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*5] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp2 - tmp1, FIX(1.777777778)),   /* 16/9 */
+	      CONST_BITS+PASS1_BITS);
+
+    dataptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 5x5 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_5x5 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2;
+  INT32 tmp10, tmp11;
+  DCTELEM *dataptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pre-zero output coefficient block. */
+  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * We scale the results further by 2 as part of output adaption
+   * scaling for different DCT size.
+   * cK represents sqrt(2) * cos(K*pi/10).
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 5; ctr++) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[4]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[3]);
+    tmp2 = GETJSAMPLE(elemptr[2]);
+
+    tmp10 = tmp0 + tmp1;
+    tmp11 = tmp0 - tmp1;
+
+    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[4]);
+    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[3]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((tmp10 + tmp2 - 5 * CENTERJSAMPLE) << (PASS1_BITS+1));
+    tmp11 = MULTIPLY(tmp11, FIX(0.790569415));          /* (c2+c4)/2 */
+    tmp10 -= tmp2 << 2;
+    tmp10 = MULTIPLY(tmp10, FIX(0.353553391));          /* (c2-c4)/2 */
+    dataptr[2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS-PASS1_BITS-1);
+    dataptr[4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS-PASS1_BITS-1);
+
+    /* Odd part */
+
+    tmp10 = MULTIPLY(tmp0 + tmp1, FIX(0.831253876));    /* c3 */
+
+    dataptr[1] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.513743148)), /* c1-c3 */
+	      CONST_BITS-PASS1_BITS-1);
+    dataptr[3] = (DCTELEM)
+      DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.176250899)), /* c1+c3 */
+	      CONST_BITS-PASS1_BITS-1);
+
+    dataptr += DCTSIZE;		/* advance pointer to next row */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   * We must also scale the output by (8/5)**2 = 64/25, which we partially
+   * fold into the constant multipliers (other part was done in pass 1):
+   * cK now represents sqrt(2) * cos(K*pi/10) * 32/25.
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 5; ctr++) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*4];
+    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*3];
+    tmp2 = dataptr[DCTSIZE*2];
+
+    tmp10 = tmp0 + tmp1;
+    tmp11 = tmp0 - tmp1;
+
+    tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*4];
+    tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*3];
+
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 + tmp2, FIX(1.28)),        /* 32/25 */
+	      CONST_BITS+PASS1_BITS);
+    tmp11 = MULTIPLY(tmp11, FIX(1.011928851));          /* (c2+c4)/2 */
+    tmp10 -= tmp2 << 2;
+    tmp10 = MULTIPLY(tmp10, FIX(0.452548340));          /* (c2-c4)/2 */
+    dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS+PASS1_BITS);
+
+    /* Odd part */
+
+    tmp10 = MULTIPLY(tmp0 + tmp1, FIX(1.064004961));    /* c3 */
+
+    dataptr[DCTSIZE*1] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.657591230)), /* c1-c3 */
+	      CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*3] = (DCTELEM)
+      DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.785601151)), /* c1+c3 */
+	      CONST_BITS+PASS1_BITS);
+
+    dataptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 4x4 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_4x4 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1;
+  INT32 tmp10, tmp11;
+  DCTELEM *dataptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pre-zero output coefficient block. */
+  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * We must also scale the output by (8/4)**2 = 2**2, which we add here.
+   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT].
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 4; ctr++) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]);
+
+    tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]);
+    tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((tmp0 + tmp1 - 4 * CENTERJSAMPLE) << (PASS1_BITS+2));
+    dataptr[2] = (DCTELEM) ((tmp0 - tmp1) << (PASS1_BITS+2));
+
+    /* Odd part */
+
+    tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100);       /* c6 */
+    /* Add fudge factor here for final descale. */
+    tmp0 += ONE << (CONST_BITS-PASS1_BITS-3);
+
+    dataptr[1] = (DCTELEM)
+      RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */
+		  CONST_BITS-PASS1_BITS-2);
+    dataptr[3] = (DCTELEM)
+      RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */
+		  CONST_BITS-PASS1_BITS-2);
+
+    dataptr += DCTSIZE;		/* advance pointer to next row */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT].
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 4; ctr++) {
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*3] + (ONE << (PASS1_BITS-1));
+    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*2];
+
+    tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*3];
+    tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*2];
+
+    dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp0 + tmp1, PASS1_BITS);
+    dataptr[DCTSIZE*2] = (DCTELEM) RIGHT_SHIFT(tmp0 - tmp1, PASS1_BITS);
+
+    /* Odd part */
+
+    tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100);       /* c6 */
+    /* Add fudge factor here for final descale. */
+    tmp0 += ONE << (CONST_BITS+PASS1_BITS-1);
+
+    dataptr[DCTSIZE*1] = (DCTELEM)
+      RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */
+		  CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*3] = (DCTELEM)
+      RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */
+		  CONST_BITS+PASS1_BITS);
+
+    dataptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 3x3 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_3x3 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2;
+  DCTELEM *dataptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pre-zero output coefficient block. */
+  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * We scale the results further by 2**2 as part of output adaption
+   * scaling for different DCT size.
+   * cK represents sqrt(2) * cos(K*pi/6).
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 3; ctr++) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[2]);
+    tmp1 = GETJSAMPLE(elemptr[1]);
+
+    tmp2 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[2]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((tmp0 + tmp1 - 3 * CENTERJSAMPLE) << (PASS1_BITS+2));
+    dataptr[2] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(0.707106781)), /* c2 */
+	      CONST_BITS-PASS1_BITS-2);
+
+    /* Odd part */
+
+    dataptr[1] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp2, FIX(1.224744871)),               /* c1 */
+	      CONST_BITS-PASS1_BITS-2);
+
+    dataptr += DCTSIZE;		/* advance pointer to next row */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   * We must also scale the output by (8/3)**2 = 64/9, which we partially
+   * fold into the constant multipliers (other part was done in pass 1):
+   * cK now represents sqrt(2) * cos(K*pi/6) * 16/9.
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 3; ctr++) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*2];
+    tmp1 = dataptr[DCTSIZE*1];
+
+    tmp2 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*2];
+
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp0 + tmp1, FIX(1.777777778)),        /* 16/9 */
+	      CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*2] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(1.257078722)), /* c2 */
+	      CONST_BITS+PASS1_BITS);
+
+    /* Odd part */
+
+    dataptr[DCTSIZE*1] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp2, FIX(2.177324216)),               /* c1 */
+	      CONST_BITS+PASS1_BITS);
+
+    dataptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 2x2 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_2x2 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3;
+  JSAMPROW elemptr;
+
+  /* Pre-zero output coefficient block. */
+  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT.
+   */
+
+  /* Row 0 */
+  elemptr = sample_data[0] + start_col;
+
+  tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[1]);
+  tmp1 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[1]);
+
+  /* Row 1 */
+  elemptr = sample_data[1] + start_col;
+
+  tmp2 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[1]);
+  tmp3 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[1]);
+
+  /* Pass 2: process columns.
+   * We leave the results scaled up by an overall factor of 8.
+   * We must also scale the output by (8/2)**2 = 2**4.
+   */
+
+  /* Column 0 */
+  /* Apply unsigned->signed conversion */
+  data[DCTSIZE*0] = (DCTELEM) ((tmp0 + tmp2 - 4 * CENTERJSAMPLE) << 4);
+  data[DCTSIZE*1] = (DCTELEM) ((tmp0 - tmp2) << 4);
+
+  /* Column 1 */
+  data[DCTSIZE*0+1] = (DCTELEM) ((tmp1 + tmp3) << 4);
+  data[DCTSIZE*1+1] = (DCTELEM) ((tmp1 - tmp3) << 4);
+}
+
+
+/*
+ * Perform the forward DCT on a 1x1 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_1x1 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  /* Pre-zero output coefficient block. */
+  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+  /* We leave the result scaled up by an overall factor of 8. */
+  /* We must also scale the output by (8/1)**2 = 2**6. */
+  /* Apply unsigned->signed conversion */
+  data[0] = (DCTELEM)
+    ((GETJSAMPLE(sample_data[0][start_col]) - CENTERJSAMPLE) << 6);
+}
+
+
+/*
+ * Perform the forward DCT on a 9x9 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_9x9 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp4;
+  INT32 tmp10, tmp11, tmp12, tmp13;
+  INT32 z1, z2;
+  DCTELEM workspace[8];
+  DCTELEM *dataptr;
+  DCTELEM *wsptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * we scale the results further by 2 as part of output adaption
+   * scaling for different DCT size.
+   * cK represents sqrt(2) * cos(K*pi/18).
+   */
+
+  dataptr = data;
+  ctr = 0;
+  for (;;) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[8]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[7]);
+    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[6]);
+    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[5]);
+    tmp4 = GETJSAMPLE(elemptr[4]);
+
+    tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[8]);
+    tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[7]);
+    tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[6]);
+    tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[5]);
+
+    z1 = tmp0 + tmp2 + tmp3;
+    z2 = tmp1 + tmp4;
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM) ((z1 + z2 - 9 * CENTERJSAMPLE) << 1);
+    dataptr[6] = (DCTELEM)
+      DESCALE(MULTIPLY(z1 - z2 - z2, FIX(0.707106781)),  /* c6 */
+	      CONST_BITS-1);
+    z1 = MULTIPLY(tmp0 - tmp2, FIX(1.328926049));        /* c2 */
+    z2 = MULTIPLY(tmp1 - tmp4 - tmp4, FIX(0.707106781)); /* c6 */
+    dataptr[2] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp2 - tmp3, FIX(1.083350441))    /* c4 */
+	      + z1 + z2, CONST_BITS-1);
+    dataptr[4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp3 - tmp0, FIX(0.245575608))    /* c8 */
+	      + z1 - z2, CONST_BITS-1);
+
+    /* Odd part */
+
+    dataptr[3] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp12 - tmp13, FIX(1.224744871)), /* c3 */
+	      CONST_BITS-1);
+
+    tmp11 = MULTIPLY(tmp11, FIX(1.224744871));        /* c3 */
+    tmp0 = MULTIPLY(tmp10 + tmp12, FIX(0.909038955)); /* c5 */
+    tmp1 = MULTIPLY(tmp10 + tmp13, FIX(0.483689525)); /* c7 */
+
+    dataptr[1] = (DCTELEM) DESCALE(tmp11 + tmp0 + tmp1, CONST_BITS-1);
+
+    tmp2 = MULTIPLY(tmp12 - tmp13, FIX(1.392728481)); /* c1 */
+
+    dataptr[5] = (DCTELEM) DESCALE(tmp0 - tmp11 - tmp2, CONST_BITS-1);
+    dataptr[7] = (DCTELEM) DESCALE(tmp1 - tmp11 + tmp2, CONST_BITS-1);
+
+    ctr++;
+
+    if (ctr != DCTSIZE) {
+      if (ctr == 9)
+	break;			/* Done. */
+      dataptr += DCTSIZE;	/* advance pointer to next row */
+    } else
+      dataptr = workspace;	/* switch pointer to extended workspace */
+  }
+
+  /* Pass 2: process columns.
+   * We leave the results scaled up by an overall factor of 8.
+   * We must also scale the output by (8/9)**2 = 64/81, which we partially
+   * fold into the constant multipliers and final/initial shifting:
+   * cK now represents sqrt(2) * cos(K*pi/18) * 128/81.
+   */
+
+  dataptr = data;
+  wsptr = workspace;
+  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*0];
+    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*7];
+    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*6];
+    tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*5];
+    tmp4 = dataptr[DCTSIZE*4];
+
+    tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*0];
+    tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*7];
+    tmp12 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*6];
+    tmp13 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*5];
+
+    z1 = tmp0 + tmp2 + tmp3;
+    z2 = tmp1 + tmp4;
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(MULTIPLY(z1 + z2, FIX(1.580246914)),       /* 128/81 */
+	      CONST_BITS+2);
+    dataptr[DCTSIZE*6] = (DCTELEM)
+      DESCALE(MULTIPLY(z1 - z2 - z2, FIX(1.117403309)),  /* c6 */
+	      CONST_BITS+2);
+    z1 = MULTIPLY(tmp0 - tmp2, FIX(2.100031287));        /* c2 */
+    z2 = MULTIPLY(tmp1 - tmp4 - tmp4, FIX(1.117403309)); /* c6 */
+    dataptr[DCTSIZE*2] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp2 - tmp3, FIX(1.711961190))    /* c4 */
+	      + z1 + z2, CONST_BITS+2);
+    dataptr[DCTSIZE*4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp3 - tmp0, FIX(0.388070096))    /* c8 */
+	      + z1 - z2, CONST_BITS+2);
+
+    /* Odd part */
+
+    dataptr[DCTSIZE*3] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp12 - tmp13, FIX(1.935399303)), /* c3 */
+	      CONST_BITS+2);
+
+    tmp11 = MULTIPLY(tmp11, FIX(1.935399303));        /* c3 */
+    tmp0 = MULTIPLY(tmp10 + tmp12, FIX(1.436506004)); /* c5 */
+    tmp1 = MULTIPLY(tmp10 + tmp13, FIX(0.764348879)); /* c7 */
+
+    dataptr[DCTSIZE*1] = (DCTELEM)
+      DESCALE(tmp11 + tmp0 + tmp1, CONST_BITS+2);
+
+    tmp2 = MULTIPLY(tmp12 - tmp13, FIX(2.200854883)); /* c1 */
+
+    dataptr[DCTSIZE*5] = (DCTELEM)
+      DESCALE(tmp0 - tmp11 - tmp2, CONST_BITS+2);
+    dataptr[DCTSIZE*7] = (DCTELEM)
+      DESCALE(tmp1 - tmp11 + tmp2, CONST_BITS+2);
+
+    dataptr++;			/* advance pointer to next column */
+    wsptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 10x10 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_10x10 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp4;
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+  DCTELEM workspace[8*2];
+  DCTELEM *dataptr;
+  DCTELEM *wsptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * we scale the results further by 2 as part of output adaption
+   * scaling for different DCT size.
+   * cK represents sqrt(2) * cos(K*pi/20).
+   */
+
+  dataptr = data;
+  ctr = 0;
+  for (;;) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[9]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[8]);
+    tmp12 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[7]);
+    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[6]);
+    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[5]);
+
+    tmp10 = tmp0 + tmp4;
+    tmp13 = tmp0 - tmp4;
+    tmp11 = tmp1 + tmp3;
+    tmp14 = tmp1 - tmp3;
+
+    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[9]);
+    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[8]);
+    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[7]);
+    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[6]);
+    tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[5]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((tmp10 + tmp11 + tmp12 - 10 * CENTERJSAMPLE) << 1);
+    tmp12 += tmp12;
+    dataptr[4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.144122806)) - /* c4 */
+	      MULTIPLY(tmp11 - tmp12, FIX(0.437016024)),  /* c8 */
+	      CONST_BITS-1);
+    tmp10 = MULTIPLY(tmp13 + tmp14, FIX(0.831253876));    /* c6 */
+    dataptr[2] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.513743148)),  /* c2-c6 */
+	      CONST_BITS-1);
+    dataptr[6] = (DCTELEM)
+      DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.176250899)),  /* c2+c6 */
+	      CONST_BITS-1);
+
+    /* Odd part */
+
+    tmp10 = tmp0 + tmp4;
+    tmp11 = tmp1 - tmp3;
+    dataptr[5] = (DCTELEM) ((tmp10 - tmp11 - tmp2) << 1);
+    tmp2 <<= CONST_BITS;
+    dataptr[1] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp0, FIX(1.396802247)) +          /* c1 */
+	      MULTIPLY(tmp1, FIX(1.260073511)) + tmp2 +   /* c3 */
+	      MULTIPLY(tmp3, FIX(0.642039522)) +          /* c7 */
+	      MULTIPLY(tmp4, FIX(0.221231742)),           /* c9 */
+	      CONST_BITS-1);
+    tmp12 = MULTIPLY(tmp0 - tmp4, FIX(0.951056516)) -     /* (c3+c7)/2 */
+	    MULTIPLY(tmp1 + tmp3, FIX(0.587785252));      /* (c1-c9)/2 */
+    tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.309016994)) +   /* (c3-c7)/2 */
+	    (tmp11 << (CONST_BITS - 1)) - tmp2;
+    dataptr[3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS-1);
+    dataptr[7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS-1);
+
+    ctr++;
+
+    if (ctr != DCTSIZE) {
+      if (ctr == 10)
+	break;			/* Done. */
+      dataptr += DCTSIZE;	/* advance pointer to next row */
+    } else
+      dataptr = workspace;	/* switch pointer to extended workspace */
+  }
+
+  /* Pass 2: process columns.
+   * We leave the results scaled up by an overall factor of 8.
+   * We must also scale the output by (8/10)**2 = 16/25, which we partially
+   * fold into the constant multipliers and final/initial shifting:
+   * cK now represents sqrt(2) * cos(K*pi/20) * 32/25.
+   */
+
+  dataptr = data;
+  wsptr = workspace;
+  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*1];
+    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*0];
+    tmp12 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*7];
+    tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*6];
+    tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*5];
+
+    tmp10 = tmp0 + tmp4;
+    tmp13 = tmp0 - tmp4;
+    tmp11 = tmp1 + tmp3;
+    tmp14 = tmp1 - tmp3;
+
+    tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*1];
+    tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*0];
+    tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*7];
+    tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*6];
+    tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*5];
+
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(1.28)), /* 32/25 */
+	      CONST_BITS+2);
+    tmp12 += tmp12;
+    dataptr[DCTSIZE*4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.464477191)) - /* c4 */
+	      MULTIPLY(tmp11 - tmp12, FIX(0.559380511)),  /* c8 */
+	      CONST_BITS+2);
+    tmp10 = MULTIPLY(tmp13 + tmp14, FIX(1.064004961));    /* c6 */
+    dataptr[DCTSIZE*2] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.657591230)),  /* c2-c6 */
+	      CONST_BITS+2);
+    dataptr[DCTSIZE*6] = (DCTELEM)
+      DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.785601151)),  /* c2+c6 */
+	      CONST_BITS+2);
+
+    /* Odd part */
+
+    tmp10 = tmp0 + tmp4;
+    tmp11 = tmp1 - tmp3;
+    dataptr[DCTSIZE*5] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp11 - tmp2, FIX(1.28)),  /* 32/25 */
+	      CONST_BITS+2);
+    tmp2 = MULTIPLY(tmp2, FIX(1.28));                     /* 32/25 */
+    dataptr[DCTSIZE*1] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp0, FIX(1.787906876)) +          /* c1 */
+	      MULTIPLY(tmp1, FIX(1.612894094)) + tmp2 +   /* c3 */
+	      MULTIPLY(tmp3, FIX(0.821810588)) +          /* c7 */
+	      MULTIPLY(tmp4, FIX(0.283176630)),           /* c9 */
+	      CONST_BITS+2);
+    tmp12 = MULTIPLY(tmp0 - tmp4, FIX(1.217352341)) -     /* (c3+c7)/2 */
+	    MULTIPLY(tmp1 + tmp3, FIX(0.752365123));      /* (c1-c9)/2 */
+    tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.395541753)) +   /* (c3-c7)/2 */
+	    MULTIPLY(tmp11, FIX(0.64)) - tmp2;            /* 16/25 */
+    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS+2);
+    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS+2);
+
+    dataptr++;			/* advance pointer to next column */
+    wsptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on an 11x11 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_11x11 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+  INT32 z1, z2, z3;
+  DCTELEM workspace[8*3];
+  DCTELEM *dataptr;
+  DCTELEM *wsptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * we scale the results further by 2 as part of output adaption
+   * scaling for different DCT size.
+   * cK represents sqrt(2) * cos(K*pi/22).
+   */
+
+  dataptr = data;
+  ctr = 0;
+  for (;;) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[10]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[9]);
+    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[8]);
+    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[7]);
+    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[6]);
+    tmp5 = GETJSAMPLE(elemptr[5]);
+
+    tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[10]);
+    tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[9]);
+    tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[8]);
+    tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[7]);
+    tmp14 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[6]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 - 11 * CENTERJSAMPLE) << 1);
+    tmp5 += tmp5;
+    tmp0 -= tmp5;
+    tmp1 -= tmp5;
+    tmp2 -= tmp5;
+    tmp3 -= tmp5;
+    tmp4 -= tmp5;
+    z1 = MULTIPLY(tmp0 + tmp3, FIX(1.356927976)) +       /* c2 */
+	 MULTIPLY(tmp2 + tmp4, FIX(0.201263574));        /* c10 */
+    z2 = MULTIPLY(tmp1 - tmp3, FIX(0.926112931));        /* c6 */
+    z3 = MULTIPLY(tmp0 - tmp1, FIX(1.189712156));        /* c4 */
+    dataptr[2] = (DCTELEM)
+      DESCALE(z1 + z2 - MULTIPLY(tmp3, FIX(1.018300590)) /* c2+c8-c6 */
+	      - MULTIPLY(tmp4, FIX(1.390975730)),        /* c4+c10 */
+	      CONST_BITS-1);
+    dataptr[4] = (DCTELEM)
+      DESCALE(z2 + z3 + MULTIPLY(tmp1, FIX(0.062335650)) /* c4-c6-c10 */
+	      - MULTIPLY(tmp2, FIX(1.356927976))         /* c2 */
+	      + MULTIPLY(tmp4, FIX(0.587485545)),        /* c8 */
+	      CONST_BITS-1);
+    dataptr[6] = (DCTELEM)
+      DESCALE(z1 + z3 - MULTIPLY(tmp0, FIX(1.620527200)) /* c2+c4-c6 */
+	      - MULTIPLY(tmp2, FIX(0.788749120)),        /* c8+c10 */
+	      CONST_BITS-1);
+
+    /* Odd part */
+
+    tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.286413905));    /* c3 */
+    tmp2 = MULTIPLY(tmp10 + tmp12, FIX(1.068791298));    /* c5 */
+    tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.764581576));    /* c7 */
+    tmp0 = tmp1 + tmp2 + tmp3 - MULTIPLY(tmp10, FIX(1.719967871)) /* c7+c5+c3-c1 */
+	   + MULTIPLY(tmp14, FIX(0.398430003));          /* c9 */
+    tmp4 = MULTIPLY(tmp11 + tmp12, - FIX(0.764581576));  /* -c7 */
+    tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(1.399818907));  /* -c1 */
+    tmp1 += tmp4 + tmp5 + MULTIPLY(tmp11, FIX(1.276416582)) /* c9+c7+c1-c3 */
+	    - MULTIPLY(tmp14, FIX(1.068791298));         /* c5 */
+    tmp10 = MULTIPLY(tmp12 + tmp13, FIX(0.398430003));   /* c9 */
+    tmp2 += tmp4 + tmp10 - MULTIPLY(tmp12, FIX(1.989053629)) /* c9+c5+c3-c7 */
+	    + MULTIPLY(tmp14, FIX(1.399818907));         /* c1 */
+    tmp3 += tmp5 + tmp10 + MULTIPLY(tmp13, FIX(1.305598626)) /* c1+c5-c9-c7 */
+	    - MULTIPLY(tmp14, FIX(1.286413905));         /* c3 */
+
+    dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-1);
+    dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-1);
+    dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-1);
+    dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS-1);
+
+    ctr++;
+
+    if (ctr != DCTSIZE) {
+      if (ctr == 11)
+	break;			/* Done. */
+      dataptr += DCTSIZE;	/* advance pointer to next row */
+    } else
+      dataptr = workspace;	/* switch pointer to extended workspace */
+  }
+
+  /* Pass 2: process columns.
+   * We leave the results scaled up by an overall factor of 8.
+   * We must also scale the output by (8/11)**2 = 64/121, which we partially
+   * fold into the constant multipliers and final/initial shifting:
+   * cK now represents sqrt(2) * cos(K*pi/22) * 128/121.
+   */
+
+  dataptr = data;
+  wsptr = workspace;
+  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*2];
+    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*1];
+    tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*0];
+    tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*7];
+    tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*6];
+    tmp5 = dataptr[DCTSIZE*5];
+
+    tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*2];
+    tmp11 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*1];
+    tmp12 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*0];
+    tmp13 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*7];
+    tmp14 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*6];
+
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5,
+		       FIX(1.057851240)),                /* 128/121 */
+	      CONST_BITS+2);
+    tmp5 += tmp5;
+    tmp0 -= tmp5;
+    tmp1 -= tmp5;
+    tmp2 -= tmp5;
+    tmp3 -= tmp5;
+    tmp4 -= tmp5;
+    z1 = MULTIPLY(tmp0 + tmp3, FIX(1.435427942)) +       /* c2 */
+	 MULTIPLY(tmp2 + tmp4, FIX(0.212906922));        /* c10 */
+    z2 = MULTIPLY(tmp1 - tmp3, FIX(0.979689713));        /* c6 */
+    z3 = MULTIPLY(tmp0 - tmp1, FIX(1.258538479));        /* c4 */
+    dataptr[DCTSIZE*2] = (DCTELEM)
+      DESCALE(z1 + z2 - MULTIPLY(tmp3, FIX(1.077210542)) /* c2+c8-c6 */
+	      - MULTIPLY(tmp4, FIX(1.471445400)),        /* c4+c10 */
+	      CONST_BITS+2);
+    dataptr[DCTSIZE*4] = (DCTELEM)
+      DESCALE(z2 + z3 + MULTIPLY(tmp1, FIX(0.065941844)) /* c4-c6-c10 */
+	      - MULTIPLY(tmp2, FIX(1.435427942))         /* c2 */
+	      + MULTIPLY(tmp4, FIX(0.621472312)),        /* c8 */
+	      CONST_BITS+2);
+    dataptr[DCTSIZE*6] = (DCTELEM)
+      DESCALE(z1 + z3 - MULTIPLY(tmp0, FIX(1.714276708)) /* c2+c4-c6 */
+	      - MULTIPLY(tmp2, FIX(0.834379234)),        /* c8+c10 */
+	      CONST_BITS+2);
+
+    /* Odd part */
+
+    tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.360834544));    /* c3 */
+    tmp2 = MULTIPLY(tmp10 + tmp12, FIX(1.130622199));    /* c5 */
+    tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.808813568));    /* c7 */
+    tmp0 = tmp1 + tmp2 + tmp3 - MULTIPLY(tmp10, FIX(1.819470145)) /* c7+c5+c3-c1 */
+	   + MULTIPLY(tmp14, FIX(0.421479672));          /* c9 */
+    tmp4 = MULTIPLY(tmp11 + tmp12, - FIX(0.808813568));  /* -c7 */
+    tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(1.480800167));  /* -c1 */
+    tmp1 += tmp4 + tmp5 + MULTIPLY(tmp11, FIX(1.350258864)) /* c9+c7+c1-c3 */
+	    - MULTIPLY(tmp14, FIX(1.130622199));         /* c5 */
+    tmp10 = MULTIPLY(tmp12 + tmp13, FIX(0.421479672));   /* c9 */
+    tmp2 += tmp4 + tmp10 - MULTIPLY(tmp12, FIX(2.104122847)) /* c9+c5+c3-c7 */
+	    + MULTIPLY(tmp14, FIX(1.480800167));         /* c1 */
+    tmp3 += tmp5 + tmp10 + MULTIPLY(tmp13, FIX(1.381129125)) /* c1+c5-c9-c7 */
+	    - MULTIPLY(tmp14, FIX(1.360834544));         /* c3 */
+
+    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+2);
+    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+2);
+    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+2);
+    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+2);
+
+    dataptr++;			/* advance pointer to next column */
+    wsptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 12x12 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_12x12 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+  DCTELEM workspace[8*4];
+  DCTELEM *dataptr;
+  DCTELEM *wsptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT.
+   * cK represents sqrt(2) * cos(K*pi/24).
+   */
+
+  dataptr = data;
+  ctr = 0;
+  for (;;) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[11]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[10]);
+    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[9]);
+    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[8]);
+    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[7]);
+    tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[6]);
+
+    tmp10 = tmp0 + tmp5;
+    tmp13 = tmp0 - tmp5;
+    tmp11 = tmp1 + tmp4;
+    tmp14 = tmp1 - tmp4;
+    tmp12 = tmp2 + tmp3;
+    tmp15 = tmp2 - tmp3;
+
+    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[11]);
+    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[10]);
+    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[9]);
+    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[8]);
+    tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[7]);
+    tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[6]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM) (tmp10 + tmp11 + tmp12 - 12 * CENTERJSAMPLE);
+    dataptr[6] = (DCTELEM) (tmp13 - tmp14 - tmp15);
+    dataptr[4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.224744871)), /* c4 */
+	      CONST_BITS);
+    dataptr[2] = (DCTELEM)
+      DESCALE(tmp14 - tmp15 + MULTIPLY(tmp13 + tmp15, FIX(1.366025404)), /* c2 */
+	      CONST_BITS);
+
+    /* Odd part */
+
+    tmp10 = MULTIPLY(tmp1 + tmp4, FIX_0_541196100);    /* c9 */
+    tmp14 = tmp10 + MULTIPLY(tmp1, FIX_0_765366865);   /* c3-c9 */
+    tmp15 = tmp10 - MULTIPLY(tmp4, FIX_1_847759065);   /* c3+c9 */
+    tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.121971054));   /* c5 */
+    tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.860918669));   /* c7 */
+    tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.580774953)) /* c5+c7-c1 */
+	    + MULTIPLY(tmp5, FIX(0.184591911));        /* c11 */
+    tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.184591911)); /* -c11 */
+    tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.339493912)) /* c1+c5-c11 */
+	    + MULTIPLY(tmp5, FIX(0.860918669));        /* c7 */
+    tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.725788011)) /* c1+c11-c7 */
+	    - MULTIPLY(tmp5, FIX(1.121971054));        /* c5 */
+    tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.306562965)) /* c3 */
+	    - MULTIPLY(tmp2 + tmp5, FIX_0_541196100);  /* c9 */
+
+    dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS);
+    dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS);
+    dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS);
+    dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS);
+
+    ctr++;
+
+    if (ctr != DCTSIZE) {
+      if (ctr == 12)
+	break;			/* Done. */
+      dataptr += DCTSIZE;	/* advance pointer to next row */
+    } else
+      dataptr = workspace;	/* switch pointer to extended workspace */
+  }
+
+  /* Pass 2: process columns.
+   * We leave the results scaled up by an overall factor of 8.
+   * We must also scale the output by (8/12)**2 = 4/9, which we partially
+   * fold into the constant multipliers and final shifting:
+   * cK now represents sqrt(2) * cos(K*pi/24) * 8/9.
+   */
+
+  dataptr = data;
+  wsptr = workspace;
+  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*3];
+    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*2];
+    tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*1];
+    tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*0];
+    tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*7];
+    tmp5 = dataptr[DCTSIZE*5] + dataptr[DCTSIZE*6];
+
+    tmp10 = tmp0 + tmp5;
+    tmp13 = tmp0 - tmp5;
+    tmp11 = tmp1 + tmp4;
+    tmp14 = tmp1 - tmp4;
+    tmp12 = tmp2 + tmp3;
+    tmp15 = tmp2 - tmp3;
+
+    tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*3];
+    tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*2];
+    tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*1];
+    tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*0];
+    tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*7];
+    tmp5 = dataptr[DCTSIZE*5] - dataptr[DCTSIZE*6];
+
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(0.888888889)), /* 8/9 */
+	      CONST_BITS+1);
+    dataptr[DCTSIZE*6] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp13 - tmp14 - tmp15, FIX(0.888888889)), /* 8/9 */
+	      CONST_BITS+1);
+    dataptr[DCTSIZE*4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.088662108)),         /* c4 */
+	      CONST_BITS+1);
+    dataptr[DCTSIZE*2] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp14 - tmp15, FIX(0.888888889)) +        /* 8/9 */
+	      MULTIPLY(tmp13 + tmp15, FIX(1.214244803)),         /* c2 */
+	      CONST_BITS+1);
+
+    /* Odd part */
+
+    tmp10 = MULTIPLY(tmp1 + tmp4, FIX(0.481063200));   /* c9 */
+    tmp14 = tmp10 + MULTIPLY(tmp1, FIX(0.680326102));  /* c3-c9 */
+    tmp15 = tmp10 - MULTIPLY(tmp4, FIX(1.642452502));  /* c3+c9 */
+    tmp12 = MULTIPLY(tmp0 + tmp2, FIX(0.997307603));   /* c5 */
+    tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.765261039));   /* c7 */
+    tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.516244403)) /* c5+c7-c1 */
+	    + MULTIPLY(tmp5, FIX(0.164081699));        /* c11 */
+    tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.164081699)); /* -c11 */
+    tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.079550144)) /* c1+c5-c11 */
+	    + MULTIPLY(tmp5, FIX(0.765261039));        /* c7 */
+    tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.645144899)) /* c1+c11-c7 */
+	    - MULTIPLY(tmp5, FIX(0.997307603));        /* c5 */
+    tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.161389302)) /* c3 */
+	    - MULTIPLY(tmp2 + tmp5, FIX(0.481063200)); /* c9 */
+
+    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+1);
+    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+1);
+    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+1);
+    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+1);
+
+    dataptr++;			/* advance pointer to next column */
+    wsptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 13x13 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_13x13 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+  INT32 z1, z2;
+  DCTELEM workspace[8*5];
+  DCTELEM *dataptr;
+  DCTELEM *wsptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT.
+   * cK represents sqrt(2) * cos(K*pi/26).
+   */
+
+  dataptr = data;
+  ctr = 0;
+  for (;;) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[12]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[11]);
+    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[10]);
+    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[9]);
+    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[8]);
+    tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[7]);
+    tmp6 = GETJSAMPLE(elemptr[6]);
+
+    tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[12]);
+    tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[11]);
+    tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[10]);
+    tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[9]);
+    tmp14 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[8]);
+    tmp15 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[7]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      (tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6 - 13 * CENTERJSAMPLE);
+    tmp6 += tmp6;
+    tmp0 -= tmp6;
+    tmp1 -= tmp6;
+    tmp2 -= tmp6;
+    tmp3 -= tmp6;
+    tmp4 -= tmp6;
+    tmp5 -= tmp6;
+    dataptr[2] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp0, FIX(1.373119086)) +   /* c2 */
+	      MULTIPLY(tmp1, FIX(1.058554052)) +   /* c6 */
+	      MULTIPLY(tmp2, FIX(0.501487041)) -   /* c10 */
+	      MULTIPLY(tmp3, FIX(0.170464608)) -   /* c12 */
+	      MULTIPLY(tmp4, FIX(0.803364869)) -   /* c8 */
+	      MULTIPLY(tmp5, FIX(1.252223920)),    /* c4 */
+	      CONST_BITS);
+    z1 = MULTIPLY(tmp0 - tmp2, FIX(1.155388986)) - /* (c4+c6)/2 */
+	 MULTIPLY(tmp3 - tmp4, FIX(0.435816023)) - /* (c2-c10)/2 */
+	 MULTIPLY(tmp1 - tmp5, FIX(0.316450131));  /* (c8-c12)/2 */
+    z2 = MULTIPLY(tmp0 + tmp2, FIX(0.096834934)) - /* (c4-c6)/2 */
+	 MULTIPLY(tmp3 + tmp4, FIX(0.937303064)) + /* (c2+c10)/2 */
+	 MULTIPLY(tmp1 + tmp5, FIX(0.486914739));  /* (c8+c12)/2 */
+
+    dataptr[4] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS);
+    dataptr[6] = (DCTELEM) DESCALE(z1 - z2, CONST_BITS);
+
+    /* Odd part */
+
+    tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.322312651));   /* c3 */
+    tmp2 = MULTIPLY(tmp10 + tmp12, FIX(1.163874945));   /* c5 */
+    tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.937797057)) +  /* c7 */
+	   MULTIPLY(tmp14 + tmp15, FIX(0.338443458));   /* c11 */
+    tmp0 = tmp1 + tmp2 + tmp3 -
+	   MULTIPLY(tmp10, FIX(2.020082300)) +          /* c3+c5+c7-c1 */
+	   MULTIPLY(tmp14, FIX(0.318774355));           /* c9-c11 */
+    tmp4 = MULTIPLY(tmp14 - tmp15, FIX(0.937797057)) -  /* c7 */
+	   MULTIPLY(tmp11 + tmp12, FIX(0.338443458));   /* c11 */
+    tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(1.163874945)); /* -c5 */
+    tmp1 += tmp4 + tmp5 +
+	    MULTIPLY(tmp11, FIX(0.837223564)) -         /* c5+c9+c11-c3 */
+	    MULTIPLY(tmp14, FIX(2.341699410));          /* c1+c7 */
+    tmp6 = MULTIPLY(tmp12 + tmp13, - FIX(0.657217813)); /* -c9 */
+    tmp2 += tmp4 + tmp6 -
+	    MULTIPLY(tmp12, FIX(1.572116027)) +         /* c1+c5-c9-c11 */
+	    MULTIPLY(tmp15, FIX(2.260109708));          /* c3+c7 */
+    tmp3 += tmp5 + tmp6 +
+	    MULTIPLY(tmp13, FIX(2.205608352)) -         /* c3+c5+c9-c7 */
+	    MULTIPLY(tmp15, FIX(1.742345811));          /* c1+c11 */
+
+    dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS);
+    dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS);
+    dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS);
+    dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS);
+
+    ctr++;
+
+    if (ctr != DCTSIZE) {
+      if (ctr == 13)
+	break;			/* Done. */
+      dataptr += DCTSIZE;	/* advance pointer to next row */
+    } else
+      dataptr = workspace;	/* switch pointer to extended workspace */
+  }
+
+  /* Pass 2: process columns.
+   * We leave the results scaled up by an overall factor of 8.
+   * We must also scale the output by (8/13)**2 = 64/169, which we partially
+   * fold into the constant multipliers and final shifting:
+   * cK now represents sqrt(2) * cos(K*pi/26) * 128/169.
+   */
+
+  dataptr = data;
+  wsptr = workspace;
+  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*4];
+    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*3];
+    tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*2];
+    tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*1];
+    tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*0];
+    tmp5 = dataptr[DCTSIZE*5] + dataptr[DCTSIZE*7];
+    tmp6 = dataptr[DCTSIZE*6];
+
+    tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*4];
+    tmp11 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*3];
+    tmp12 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*2];
+    tmp13 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*1];
+    tmp14 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*0];
+    tmp15 = dataptr[DCTSIZE*5] - dataptr[DCTSIZE*7];
+
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6,
+		       FIX(0.757396450)),          /* 128/169 */
+	      CONST_BITS+1);
+    tmp6 += tmp6;
+    tmp0 -= tmp6;
+    tmp1 -= tmp6;
+    tmp2 -= tmp6;
+    tmp3 -= tmp6;
+    tmp4 -= tmp6;
+    tmp5 -= tmp6;
+    dataptr[DCTSIZE*2] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp0, FIX(1.039995521)) +   /* c2 */
+	      MULTIPLY(tmp1, FIX(0.801745081)) +   /* c6 */
+	      MULTIPLY(tmp2, FIX(0.379824504)) -   /* c10 */
+	      MULTIPLY(tmp3, FIX(0.129109289)) -   /* c12 */
+	      MULTIPLY(tmp4, FIX(0.608465700)) -   /* c8 */
+	      MULTIPLY(tmp5, FIX(0.948429952)),    /* c4 */
+	      CONST_BITS+1);
+    z1 = MULTIPLY(tmp0 - tmp2, FIX(0.875087516)) - /* (c4+c6)/2 */
+	 MULTIPLY(tmp3 - tmp4, FIX(0.330085509)) - /* (c2-c10)/2 */
+	 MULTIPLY(tmp1 - tmp5, FIX(0.239678205));  /* (c8-c12)/2 */
+    z2 = MULTIPLY(tmp0 + tmp2, FIX(0.073342435)) - /* (c4-c6)/2 */
+	 MULTIPLY(tmp3 + tmp4, FIX(0.709910013)) + /* (c2+c10)/2 */
+	 MULTIPLY(tmp1 + tmp5, FIX(0.368787494));  /* (c8+c12)/2 */
+
+    dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS+1);
+    dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 - z2, CONST_BITS+1);
+
+    /* Odd part */
+
+    tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.001514908));   /* c3 */
+    tmp2 = MULTIPLY(tmp10 + tmp12, FIX(0.881514751));   /* c5 */
+    tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.710284161)) +  /* c7 */
+	   MULTIPLY(tmp14 + tmp15, FIX(0.256335874));   /* c11 */
+    tmp0 = tmp1 + tmp2 + tmp3 -
+	   MULTIPLY(tmp10, FIX(1.530003162)) +          /* c3+c5+c7-c1 */
+	   MULTIPLY(tmp14, FIX(0.241438564));           /* c9-c11 */
+    tmp4 = MULTIPLY(tmp14 - tmp15, FIX(0.710284161)) -  /* c7 */
+	   MULTIPLY(tmp11 + tmp12, FIX(0.256335874));   /* c11 */
+    tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(0.881514751)); /* -c5 */
+    tmp1 += tmp4 + tmp5 +
+	    MULTIPLY(tmp11, FIX(0.634110155)) -         /* c5+c9+c11-c3 */
+	    MULTIPLY(tmp14, FIX(1.773594819));          /* c1+c7 */
+    tmp6 = MULTIPLY(tmp12 + tmp13, - FIX(0.497774438)); /* -c9 */
+    tmp2 += tmp4 + tmp6 -
+	    MULTIPLY(tmp12, FIX(1.190715098)) +         /* c1+c5-c9-c11 */
+	    MULTIPLY(tmp15, FIX(1.711799069));          /* c3+c7 */
+    tmp3 += tmp5 + tmp6 +
+	    MULTIPLY(tmp13, FIX(1.670519935)) -         /* c3+c5+c9-c7 */
+	    MULTIPLY(tmp15, FIX(1.319646532));          /* c1+c11 */
+
+    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+1);
+    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+1);
+    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+1);
+    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+1);
+
+    dataptr++;			/* advance pointer to next column */
+    wsptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 14x14 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_14x14 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+  DCTELEM workspace[8*6];
+  DCTELEM *dataptr;
+  DCTELEM *wsptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT.
+   * cK represents sqrt(2) * cos(K*pi/28).
+   */
+
+  dataptr = data;
+  ctr = 0;
+  for (;;) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[13]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[12]);
+    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[11]);
+    tmp13 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[10]);
+    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[9]);
+    tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[8]);
+    tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[7]);
+
+    tmp10 = tmp0 + tmp6;
+    tmp14 = tmp0 - tmp6;
+    tmp11 = tmp1 + tmp5;
+    tmp15 = tmp1 - tmp5;
+    tmp12 = tmp2 + tmp4;
+    tmp16 = tmp2 - tmp4;
+
+    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[13]);
+    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[12]);
+    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[11]);
+    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[10]);
+    tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[9]);
+    tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[8]);
+    tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[7]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      (tmp10 + tmp11 + tmp12 + tmp13 - 14 * CENTERJSAMPLE);
+    tmp13 += tmp13;
+    dataptr[4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.274162392)) + /* c4 */
+	      MULTIPLY(tmp11 - tmp13, FIX(0.314692123)) - /* c12 */
+	      MULTIPLY(tmp12 - tmp13, FIX(0.881747734)),  /* c8 */
+	      CONST_BITS);
+
+    tmp10 = MULTIPLY(tmp14 + tmp15, FIX(1.105676686));    /* c6 */
+
+    dataptr[2] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.273079590))   /* c2-c6 */
+	      + MULTIPLY(tmp16, FIX(0.613604268)),        /* c10 */
+	      CONST_BITS);
+    dataptr[6] = (DCTELEM)
+      DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.719280954))   /* c6+c10 */
+	      - MULTIPLY(tmp16, FIX(1.378756276)),        /* c2 */
+	      CONST_BITS);
+
+    /* Odd part */
+
+    tmp10 = tmp1 + tmp2;
+    tmp11 = tmp5 - tmp4;
+    dataptr[7] = (DCTELEM) (tmp0 - tmp10 + tmp3 - tmp11 - tmp6);
+    tmp3 <<= CONST_BITS;
+    tmp10 = MULTIPLY(tmp10, - FIX(0.158341681));          /* -c13 */
+    tmp11 = MULTIPLY(tmp11, FIX(1.405321284));            /* c1 */
+    tmp10 += tmp11 - tmp3;
+    tmp11 = MULTIPLY(tmp0 + tmp2, FIX(1.197448846)) +     /* c5 */
+	    MULTIPLY(tmp4 + tmp6, FIX(0.752406978));      /* c9 */
+    dataptr[5] = (DCTELEM)
+      DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(2.373959773)) /* c3+c5-c13 */
+	      + MULTIPLY(tmp4, FIX(1.119999435)),         /* c1+c11-c9 */
+	      CONST_BITS);
+    tmp12 = MULTIPLY(tmp0 + tmp1, FIX(1.334852607)) +     /* c3 */
+	    MULTIPLY(tmp5 - tmp6, FIX(0.467085129));      /* c11 */
+    dataptr[3] = (DCTELEM)
+      DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.424103948)) /* c3-c9-c13 */
+	      - MULTIPLY(tmp5, FIX(3.069855259)),         /* c1+c5+c11 */
+	      CONST_BITS);
+    dataptr[1] = (DCTELEM)
+      DESCALE(tmp11 + tmp12 + tmp3 + tmp6 -
+	      MULTIPLY(tmp0 + tmp6, FIX(1.126980169)),    /* c3+c5-c1 */
+	      CONST_BITS);
+
+    ctr++;
+
+    if (ctr != DCTSIZE) {
+      if (ctr == 14)
+	break;			/* Done. */
+      dataptr += DCTSIZE;	/* advance pointer to next row */
+    } else
+      dataptr = workspace;	/* switch pointer to extended workspace */
+  }
+
+  /* Pass 2: process columns.
+   * We leave the results scaled up by an overall factor of 8.
+   * We must also scale the output by (8/14)**2 = 16/49, which we partially
+   * fold into the constant multipliers and final shifting:
+   * cK now represents sqrt(2) * cos(K*pi/28) * 32/49.
+   */
+
+  dataptr = data;
+  wsptr = workspace;
+  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*5];
+    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*4];
+    tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*3];
+    tmp13 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*2];
+    tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*1];
+    tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*0];
+    tmp6 = dataptr[DCTSIZE*6] + dataptr[DCTSIZE*7];
+
+    tmp10 = tmp0 + tmp6;
+    tmp14 = tmp0 - tmp6;
+    tmp11 = tmp1 + tmp5;
+    tmp15 = tmp1 - tmp5;
+    tmp12 = tmp2 + tmp4;
+    tmp16 = tmp2 - tmp4;
+
+    tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*5];
+    tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*4];
+    tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*3];
+    tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*2];
+    tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*1];
+    tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*0];
+    tmp6 = dataptr[DCTSIZE*6] - dataptr[DCTSIZE*7];
+
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12 + tmp13,
+		       FIX(0.653061224)),                 /* 32/49 */
+	      CONST_BITS+1);
+    tmp13 += tmp13;
+    dataptr[DCTSIZE*4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp13, FIX(0.832106052)) + /* c4 */
+	      MULTIPLY(tmp11 - tmp13, FIX(0.205513223)) - /* c12 */
+	      MULTIPLY(tmp12 - tmp13, FIX(0.575835255)),  /* c8 */
+	      CONST_BITS+1);
+
+    tmp10 = MULTIPLY(tmp14 + tmp15, FIX(0.722074570));    /* c6 */
+
+    dataptr[DCTSIZE*2] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.178337691))   /* c2-c6 */
+	      + MULTIPLY(tmp16, FIX(0.400721155)),        /* c10 */
+	      CONST_BITS+1);
+    dataptr[DCTSIZE*6] = (DCTELEM)
+      DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.122795725))   /* c6+c10 */
+	      - MULTIPLY(tmp16, FIX(0.900412262)),        /* c2 */
+	      CONST_BITS+1);
+
+    /* Odd part */
+
+    tmp10 = tmp1 + tmp2;
+    tmp11 = tmp5 - tmp4;
+    dataptr[DCTSIZE*7] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp0 - tmp10 + tmp3 - tmp11 - tmp6,
+		       FIX(0.653061224)),                 /* 32/49 */
+	      CONST_BITS+1);
+    tmp3  = MULTIPLY(tmp3 , FIX(0.653061224));            /* 32/49 */
+    tmp10 = MULTIPLY(tmp10, - FIX(0.103406812));          /* -c13 */
+    tmp11 = MULTIPLY(tmp11, FIX(0.917760839));            /* c1 */
+    tmp10 += tmp11 - tmp3;
+    tmp11 = MULTIPLY(tmp0 + tmp2, FIX(0.782007410)) +     /* c5 */
+	    MULTIPLY(tmp4 + tmp6, FIX(0.491367823));      /* c9 */
+    dataptr[DCTSIZE*5] = (DCTELEM)
+      DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(1.550341076)) /* c3+c5-c13 */
+	      + MULTIPLY(tmp4, FIX(0.731428202)),         /* c1+c11-c9 */
+	      CONST_BITS+1);
+    tmp12 = MULTIPLY(tmp0 + tmp1, FIX(0.871740478)) +     /* c3 */
+	    MULTIPLY(tmp5 - tmp6, FIX(0.305035186));      /* c11 */
+    dataptr[DCTSIZE*3] = (DCTELEM)
+      DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.276965844)) /* c3-c9-c13 */
+	      - MULTIPLY(tmp5, FIX(2.004803435)),         /* c1+c5+c11 */
+	      CONST_BITS+1);
+    dataptr[DCTSIZE*1] = (DCTELEM)
+      DESCALE(tmp11 + tmp12 + tmp3
+	      - MULTIPLY(tmp0, FIX(0.735987049))          /* c3+c5-c1 */
+	      - MULTIPLY(tmp6, FIX(0.082925825)),         /* c9-c11-c13 */
+	      CONST_BITS+1);
+
+    dataptr++;			/* advance pointer to next column */
+    wsptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 15x15 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_15x15 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+  INT32 z1, z2, z3;
+  DCTELEM workspace[8*7];
+  DCTELEM *dataptr;
+  DCTELEM *wsptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT.
+   * cK represents sqrt(2) * cos(K*pi/30).
+   */
+
+  dataptr = data;
+  ctr = 0;
+  for (;;) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[14]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[13]);
+    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[12]);
+    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[11]);
+    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[10]);
+    tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[9]);
+    tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[8]);
+    tmp7 = GETJSAMPLE(elemptr[7]);
+
+    tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[14]);
+    tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[13]);
+    tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[12]);
+    tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[11]);
+    tmp14 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[10]);
+    tmp15 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[9]);
+    tmp16 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[8]);
+
+    z1 = tmp0 + tmp4 + tmp5;
+    z2 = tmp1 + tmp3 + tmp6;
+    z3 = tmp2 + tmp7;
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM) (z1 + z2 + z3 - 15 * CENTERJSAMPLE);
+    z3 += z3;
+    dataptr[6] = (DCTELEM)
+      DESCALE(MULTIPLY(z1 - z3, FIX(1.144122806)) - /* c6 */
+	      MULTIPLY(z2 - z3, FIX(0.437016024)),  /* c12 */
+	      CONST_BITS);
+    tmp2 += ((tmp1 + tmp4) >> 1) - tmp7 - tmp7;
+    z1 = MULTIPLY(tmp3 - tmp2, FIX(1.531135173)) -  /* c2+c14 */
+         MULTIPLY(tmp6 - tmp2, FIX(2.238241955));   /* c4+c8 */
+    z2 = MULTIPLY(tmp5 - tmp2, FIX(0.798468008)) -  /* c8-c14 */
+	 MULTIPLY(tmp0 - tmp2, FIX(0.091361227));   /* c2-c4 */
+    z3 = MULTIPLY(tmp0 - tmp3, FIX(1.383309603)) +  /* c2 */
+	 MULTIPLY(tmp6 - tmp5, FIX(0.946293579)) +  /* c8 */
+	 MULTIPLY(tmp1 - tmp4, FIX(0.790569415));   /* (c6+c12)/2 */
+
+    dataptr[2] = (DCTELEM) DESCALE(z1 + z3, CONST_BITS);
+    dataptr[4] = (DCTELEM) DESCALE(z2 + z3, CONST_BITS);
+
+    /* Odd part */
+
+    tmp2 = MULTIPLY(tmp10 - tmp12 - tmp13 + tmp15 + tmp16,
+		    FIX(1.224744871));                         /* c5 */
+    tmp1 = MULTIPLY(tmp10 - tmp14 - tmp15, FIX(1.344997024)) + /* c3 */
+	   MULTIPLY(tmp11 - tmp13 - tmp16, FIX(0.831253876));  /* c9 */
+    tmp12 = MULTIPLY(tmp12, FIX(1.224744871));                 /* c5 */
+    tmp4 = MULTIPLY(tmp10 - tmp16, FIX(1.406466353)) +         /* c1 */
+	   MULTIPLY(tmp11 + tmp14, FIX(1.344997024)) +         /* c3 */
+	   MULTIPLY(tmp13 + tmp15, FIX(0.575212477));          /* c11 */
+    tmp0 = MULTIPLY(tmp13, FIX(0.475753014)) -                 /* c7-c11 */
+	   MULTIPLY(tmp14, FIX(0.513743148)) +                 /* c3-c9 */
+	   MULTIPLY(tmp16, FIX(1.700497885)) + tmp4 + tmp12;   /* c1+c13 */
+    tmp3 = MULTIPLY(tmp10, - FIX(0.355500862)) -               /* -(c1-c7) */
+	   MULTIPLY(tmp11, FIX(2.176250899)) -                 /* c3+c9 */
+	   MULTIPLY(tmp15, FIX(0.869244010)) + tmp4 - tmp12;   /* c11+c13 */
+
+    dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS);
+    dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS);
+    dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS);
+    dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS);
+
+    ctr++;
+
+    if (ctr != DCTSIZE) {
+      if (ctr == 15)
+	break;			/* Done. */
+      dataptr += DCTSIZE;	/* advance pointer to next row */
+    } else
+      dataptr = workspace;	/* switch pointer to extended workspace */
+  }
+
+  /* Pass 2: process columns.
+   * We leave the results scaled up by an overall factor of 8.
+   * We must also scale the output by (8/15)**2 = 64/225, which we partially
+   * fold into the constant multipliers and final shifting:
+   * cK now represents sqrt(2) * cos(K*pi/30) * 256/225.
+   */
+
+  dataptr = data;
+  wsptr = workspace;
+  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*6];
+    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*5];
+    tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*4];
+    tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*3];
+    tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*2];
+    tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*1];
+    tmp6 = dataptr[DCTSIZE*6] + wsptr[DCTSIZE*0];
+    tmp7 = dataptr[DCTSIZE*7];
+
+    tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*6];
+    tmp11 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*5];
+    tmp12 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*4];
+    tmp13 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*3];
+    tmp14 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*2];
+    tmp15 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*1];
+    tmp16 = dataptr[DCTSIZE*6] - wsptr[DCTSIZE*0];
+
+    z1 = tmp0 + tmp4 + tmp5;
+    z2 = tmp1 + tmp3 + tmp6;
+    z3 = tmp2 + tmp7;
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(MULTIPLY(z1 + z2 + z3, FIX(1.137777778)), /* 256/225 */
+	      CONST_BITS+2);
+    z3 += z3;
+    dataptr[DCTSIZE*6] = (DCTELEM)
+      DESCALE(MULTIPLY(z1 - z3, FIX(1.301757503)) - /* c6 */
+	      MULTIPLY(z2 - z3, FIX(0.497227121)),  /* c12 */
+	      CONST_BITS+2);
+    tmp2 += ((tmp1 + tmp4) >> 1) - tmp7 - tmp7;
+    z1 = MULTIPLY(tmp3 - tmp2, FIX(1.742091575)) -  /* c2+c14 */
+         MULTIPLY(tmp6 - tmp2, FIX(2.546621957));   /* c4+c8 */
+    z2 = MULTIPLY(tmp5 - tmp2, FIX(0.908479156)) -  /* c8-c14 */
+	 MULTIPLY(tmp0 - tmp2, FIX(0.103948774));   /* c2-c4 */
+    z3 = MULTIPLY(tmp0 - tmp3, FIX(1.573898926)) +  /* c2 */
+	 MULTIPLY(tmp6 - tmp5, FIX(1.076671805)) +  /* c8 */
+	 MULTIPLY(tmp1 - tmp4, FIX(0.899492312));   /* (c6+c12)/2 */
+
+    dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + z3, CONST_BITS+2);
+    dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(z2 + z3, CONST_BITS+2);
+
+    /* Odd part */
+
+    tmp2 = MULTIPLY(tmp10 - tmp12 - tmp13 + tmp15 + tmp16,
+		    FIX(1.393487498));                         /* c5 */
+    tmp1 = MULTIPLY(tmp10 - tmp14 - tmp15, FIX(1.530307725)) + /* c3 */
+	   MULTIPLY(tmp11 - tmp13 - tmp16, FIX(0.945782187));  /* c9 */
+    tmp12 = MULTIPLY(tmp12, FIX(1.393487498));                 /* c5 */
+    tmp4 = MULTIPLY(tmp10 - tmp16, FIX(1.600246161)) +         /* c1 */
+	   MULTIPLY(tmp11 + tmp14, FIX(1.530307725)) +         /* c3 */
+	   MULTIPLY(tmp13 + tmp15, FIX(0.654463974));          /* c11 */
+    tmp0 = MULTIPLY(tmp13, FIX(0.541301207)) -                 /* c7-c11 */
+	   MULTIPLY(tmp14, FIX(0.584525538)) +                 /* c3-c9 */
+	   MULTIPLY(tmp16, FIX(1.934788705)) + tmp4 + tmp12;   /* c1+c13 */
+    tmp3 = MULTIPLY(tmp10, - FIX(0.404480980)) -               /* -(c1-c7) */
+	   MULTIPLY(tmp11, FIX(2.476089912)) -                 /* c3+c9 */
+	   MULTIPLY(tmp15, FIX(0.989006518)) + tmp4 - tmp12;   /* c11+c13 */
+
+    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+2);
+    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+2);
+    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+2);
+    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+2);
+
+    dataptr++;			/* advance pointer to next column */
+    wsptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 16x16 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_16x16 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17;
+  DCTELEM workspace[DCTSIZE2];
+  DCTELEM *dataptr;
+  DCTELEM *wsptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * cK represents sqrt(2) * cos(K*pi/32).
+   */
+
+  dataptr = data;
+  ctr = 0;
+  for (;;) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[15]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[14]);
+    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[13]);
+    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[12]);
+    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[11]);
+    tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[10]);
+    tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[9]);
+    tmp7 = GETJSAMPLE(elemptr[7]) + GETJSAMPLE(elemptr[8]);
+
+    tmp10 = tmp0 + tmp7;
+    tmp14 = tmp0 - tmp7;
+    tmp11 = tmp1 + tmp6;
+    tmp15 = tmp1 - tmp6;
+    tmp12 = tmp2 + tmp5;
+    tmp16 = tmp2 - tmp5;
+    tmp13 = tmp3 + tmp4;
+    tmp17 = tmp3 - tmp4;
+
+    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[15]);
+    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[14]);
+    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[13]);
+    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[12]);
+    tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[11]);
+    tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[10]);
+    tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[9]);
+    tmp7 = GETJSAMPLE(elemptr[7]) - GETJSAMPLE(elemptr[8]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((tmp10 + tmp11 + tmp12 + tmp13 - 16 * CENTERJSAMPLE) << PASS1_BITS);
+    dataptr[4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */
+	      MULTIPLY(tmp11 - tmp12, FIX_0_541196100),   /* c12[16] = c6[8] */
+	      CONST_BITS-PASS1_BITS);
+
+    tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) +   /* c14[16] = c7[8] */
+	    MULTIPLY(tmp14 - tmp16, FIX(1.387039845));    /* c2[16] = c1[8] */
+
+    dataptr[2] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982))   /* c6+c14 */
+	      + MULTIPLY(tmp16, FIX(2.172734804)),        /* c2+c10 */
+	      CONST_BITS-PASS1_BITS);
+    dataptr[6] = (DCTELEM)
+      DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243))   /* c2-c6 */
+	      - MULTIPLY(tmp17, FIX(1.061594338)),        /* c10+c14 */
+	      CONST_BITS-PASS1_BITS);
+
+    /* Odd part */
+
+    tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) +         /* c3 */
+	    MULTIPLY(tmp6 - tmp7, FIX(0.410524528));          /* c13 */
+    tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) +         /* c5 */
+	    MULTIPLY(tmp5 + tmp7, FIX(0.666655658));          /* c11 */
+    tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) +         /* c7 */
+	    MULTIPLY(tmp4 - tmp7, FIX(0.897167586));          /* c9 */
+    tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) +         /* c15 */
+	    MULTIPLY(tmp6 - tmp5, FIX(1.407403738));          /* c1 */
+    tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) +       /* -c11 */
+	    MULTIPLY(tmp4 + tmp6, - FIX(1.247225013));        /* -c5 */
+    tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) +       /* -c3 */
+	    MULTIPLY(tmp5 - tmp4, FIX(0.410524528));          /* c13 */
+    tmp10 = tmp11 + tmp12 + tmp13 -
+	    MULTIPLY(tmp0, FIX(2.286341144)) +                /* c7+c5+c3-c1 */
+	    MULTIPLY(tmp7, FIX(0.779653625));                 /* c15+c13-c11+c9 */
+    tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */
+	     - MULTIPLY(tmp6, FIX(1.663905119));              /* c7+c13+c1-c5 */
+    tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */
+	     + MULTIPLY(tmp5, FIX(1.227391138));              /* c9-c11+c1-c13 */
+    tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */
+	     + MULTIPLY(tmp4, FIX(2.167985692));              /* c1+c13+c5-c9 */
+
+    dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS-PASS1_BITS);
+    dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS-PASS1_BITS);
+    dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS-PASS1_BITS);
+    dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS-PASS1_BITS);
+
+    ctr++;
+
+    if (ctr != DCTSIZE) {
+      if (ctr == DCTSIZE * 2)
+	break;			/* Done. */
+      dataptr += DCTSIZE;	/* advance pointer to next row */
+    } else
+      dataptr = workspace;	/* switch pointer to extended workspace */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   * We must also scale the output by (8/16)**2 = 1/2**2.
+   * cK represents sqrt(2) * cos(K*pi/32).
+   */
+
+  dataptr = data;
+  wsptr = workspace;
+  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*7];
+    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*6];
+    tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*5];
+    tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*4];
+    tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*3];
+    tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*2];
+    tmp6 = dataptr[DCTSIZE*6] + wsptr[DCTSIZE*1];
+    tmp7 = dataptr[DCTSIZE*7] + wsptr[DCTSIZE*0];
+
+    tmp10 = tmp0 + tmp7;
+    tmp14 = tmp0 - tmp7;
+    tmp11 = tmp1 + tmp6;
+    tmp15 = tmp1 - tmp6;
+    tmp12 = tmp2 + tmp5;
+    tmp16 = tmp2 - tmp5;
+    tmp13 = tmp3 + tmp4;
+    tmp17 = tmp3 - tmp4;
+
+    tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*7];
+    tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*6];
+    tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*5];
+    tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*4];
+    tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*3];
+    tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*2];
+    tmp6 = dataptr[DCTSIZE*6] - wsptr[DCTSIZE*1];
+    tmp7 = dataptr[DCTSIZE*7] - wsptr[DCTSIZE*0];
+
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(tmp10 + tmp11 + tmp12 + tmp13, PASS1_BITS+2);
+    dataptr[DCTSIZE*4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */
+	      MULTIPLY(tmp11 - tmp12, FIX_0_541196100),   /* c12[16] = c6[8] */
+	      CONST_BITS+PASS1_BITS+2);
+
+    tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) +   /* c14[16] = c7[8] */
+	    MULTIPLY(tmp14 - tmp16, FIX(1.387039845));    /* c2[16] = c1[8] */
+
+    dataptr[DCTSIZE*2] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982))   /* c6+c14 */
+	      + MULTIPLY(tmp16, FIX(2.172734804)),        /* c2+10 */
+	      CONST_BITS+PASS1_BITS+2);
+    dataptr[DCTSIZE*6] = (DCTELEM)
+      DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243))   /* c2-c6 */
+	      - MULTIPLY(tmp17, FIX(1.061594338)),        /* c10+c14 */
+	      CONST_BITS+PASS1_BITS+2);
+
+    /* Odd part */
+
+    tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) +         /* c3 */
+	    MULTIPLY(tmp6 - tmp7, FIX(0.410524528));          /* c13 */
+    tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) +         /* c5 */
+	    MULTIPLY(tmp5 + tmp7, FIX(0.666655658));          /* c11 */
+    tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) +         /* c7 */
+	    MULTIPLY(tmp4 - tmp7, FIX(0.897167586));          /* c9 */
+    tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) +         /* c15 */
+	    MULTIPLY(tmp6 - tmp5, FIX(1.407403738));          /* c1 */
+    tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) +       /* -c11 */
+	    MULTIPLY(tmp4 + tmp6, - FIX(1.247225013));        /* -c5 */
+    tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) +       /* -c3 */
+	    MULTIPLY(tmp5 - tmp4, FIX(0.410524528));          /* c13 */
+    tmp10 = tmp11 + tmp12 + tmp13 -
+	    MULTIPLY(tmp0, FIX(2.286341144)) +                /* c7+c5+c3-c1 */
+	    MULTIPLY(tmp7, FIX(0.779653625));                 /* c15+c13-c11+c9 */
+    tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */
+	     - MULTIPLY(tmp6, FIX(1.663905119));              /* c7+c13+c1-c5 */
+    tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */
+	     + MULTIPLY(tmp5, FIX(1.227391138));              /* c9-c11+c1-c13 */
+    tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */
+	     + MULTIPLY(tmp4, FIX(2.167985692));              /* c1+c13+c5-c9 */
+
+    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+PASS1_BITS+2);
+    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+PASS1_BITS+2);
+    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+PASS1_BITS+2);
+    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+PASS1_BITS+2);
+
+    dataptr++;			/* advance pointer to next column */
+    wsptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 16x8 sample block.
+ *
+ * 16-point FDCT in pass 1 (rows), 8-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_16x8 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17;
+  INT32 z1;
+  DCTELEM *dataptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * 16-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/32).
+   */
+
+  dataptr = data;
+  ctr = 0;
+  for (ctr = 0; ctr < DCTSIZE; ctr++) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[15]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[14]);
+    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[13]);
+    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[12]);
+    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[11]);
+    tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[10]);
+    tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[9]);
+    tmp7 = GETJSAMPLE(elemptr[7]) + GETJSAMPLE(elemptr[8]);
+
+    tmp10 = tmp0 + tmp7;
+    tmp14 = tmp0 - tmp7;
+    tmp11 = tmp1 + tmp6;
+    tmp15 = tmp1 - tmp6;
+    tmp12 = tmp2 + tmp5;
+    tmp16 = tmp2 - tmp5;
+    tmp13 = tmp3 + tmp4;
+    tmp17 = tmp3 - tmp4;
+
+    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[15]);
+    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[14]);
+    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[13]);
+    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[12]);
+    tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[11]);
+    tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[10]);
+    tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[9]);
+    tmp7 = GETJSAMPLE(elemptr[7]) - GETJSAMPLE(elemptr[8]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((tmp10 + tmp11 + tmp12 + tmp13 - 16 * CENTERJSAMPLE) << PASS1_BITS);
+    dataptr[4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */
+	      MULTIPLY(tmp11 - tmp12, FIX_0_541196100),   /* c12[16] = c6[8] */
+	      CONST_BITS-PASS1_BITS);
+
+    tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) +   /* c14[16] = c7[8] */
+	    MULTIPLY(tmp14 - tmp16, FIX(1.387039845));    /* c2[16] = c1[8] */
+
+    dataptr[2] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982))   /* c6+c14 */
+	      + MULTIPLY(tmp16, FIX(2.172734804)),        /* c2+c10 */
+	      CONST_BITS-PASS1_BITS);
+    dataptr[6] = (DCTELEM)
+      DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243))   /* c2-c6 */
+	      - MULTIPLY(tmp17, FIX(1.061594338)),        /* c10+c14 */
+	      CONST_BITS-PASS1_BITS);
+
+    /* Odd part */
+
+    tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) +         /* c3 */
+	    MULTIPLY(tmp6 - tmp7, FIX(0.410524528));          /* c13 */
+    tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) +         /* c5 */
+	    MULTIPLY(tmp5 + tmp7, FIX(0.666655658));          /* c11 */
+    tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) +         /* c7 */
+	    MULTIPLY(tmp4 - tmp7, FIX(0.897167586));          /* c9 */
+    tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) +         /* c15 */
+	    MULTIPLY(tmp6 - tmp5, FIX(1.407403738));          /* c1 */
+    tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) +       /* -c11 */
+	    MULTIPLY(tmp4 + tmp6, - FIX(1.247225013));        /* -c5 */
+    tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) +       /* -c3 */
+	    MULTIPLY(tmp5 - tmp4, FIX(0.410524528));          /* c13 */
+    tmp10 = tmp11 + tmp12 + tmp13 -
+	    MULTIPLY(tmp0, FIX(2.286341144)) +                /* c7+c5+c3-c1 */
+	    MULTIPLY(tmp7, FIX(0.779653625));                 /* c15+c13-c11+c9 */
+    tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */
+	     - MULTIPLY(tmp6, FIX(1.663905119));              /* c7+c13+c1-c5 */
+    tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */
+	     + MULTIPLY(tmp5, FIX(1.227391138));              /* c9-c11+c1-c13 */
+    tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */
+	     + MULTIPLY(tmp4, FIX(2.167985692));              /* c1+c13+c5-c9 */
+
+    dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS-PASS1_BITS);
+    dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS-PASS1_BITS);
+    dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS-PASS1_BITS);
+    dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS-PASS1_BITS);
+
+    dataptr += DCTSIZE;		/* advance pointer to next row */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   * We must also scale the output by 8/16 = 1/2.
+   * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+   */
+
+  dataptr = data;
+  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+    /* Even part per LL&M figure 1 --- note that published figure is faulty;
+     * rotator "c1" should be "c6".
+     */
+
+    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
+    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
+    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
+    tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
+
+    tmp10 = tmp0 + tmp3;
+    tmp12 = tmp0 - tmp3;
+    tmp11 = tmp1 + tmp2;
+    tmp13 = tmp1 - tmp2;
+
+    tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
+    tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
+    tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
+    tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
+
+    dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp11, PASS1_BITS+1);
+    dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp10 - tmp11, PASS1_BITS+1);
+
+    z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);   /* c6 */
+    dataptr[DCTSIZE*2] = (DCTELEM)
+      DESCALE(z1 + MULTIPLY(tmp12, FIX_0_765366865), /* c2-c6 */
+	      CONST_BITS+PASS1_BITS+1);
+    dataptr[DCTSIZE*6] = (DCTELEM)
+      DESCALE(z1 - MULTIPLY(tmp13, FIX_1_847759065), /* c2+c6 */
+	      CONST_BITS+PASS1_BITS+1);
+
+    /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+     * i0..i3 in the paper are tmp0..tmp3 here.
+     */
+
+    tmp12 = tmp0 + tmp2;
+    tmp13 = tmp1 + tmp3;
+
+    z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602);   /*  c3 */
+    tmp12 = MULTIPLY(tmp12, - FIX_0_390180644);      /* -c3+c5 */
+    tmp13 = MULTIPLY(tmp13, - FIX_1_961570560);      /* -c3-c5 */
+    tmp12 += z1;
+    tmp13 += z1;
+
+    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223);   /* -c3+c7 */
+    tmp0 = MULTIPLY(tmp0, FIX_1_501321110);          /*  c1+c3-c5-c7 */
+    tmp3 = MULTIPLY(tmp3, FIX_0_298631336);          /* -c1+c3+c5-c7 */
+    tmp0 += z1 + tmp12;
+    tmp3 += z1 + tmp13;
+
+    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447);   /* -c1-c3 */
+    tmp1 = MULTIPLY(tmp1, FIX_3_072711026);          /*  c1+c3+c5-c7 */
+    tmp2 = MULTIPLY(tmp2, FIX_2_053119869);          /*  c1+c3-c5+c7 */
+    tmp1 += z1 + tmp13;
+    tmp2 += z1 + tmp12;
+
+    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+PASS1_BITS+1);
+    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+PASS1_BITS+1);
+    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+PASS1_BITS+1);
+    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+PASS1_BITS+1);
+
+    dataptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 14x7 sample block.
+ *
+ * 14-point FDCT in pass 1 (rows), 7-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_14x7 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+  INT32 z1, z2, z3;
+  DCTELEM *dataptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Zero bottom row of output coefficient block. */
+  MEMZERO(&data[DCTSIZE*7], SIZEOF(DCTELEM) * DCTSIZE);
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * 14-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/28).
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 7; ctr++) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[13]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[12]);
+    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[11]);
+    tmp13 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[10]);
+    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[9]);
+    tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[8]);
+    tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[7]);
+
+    tmp10 = tmp0 + tmp6;
+    tmp14 = tmp0 - tmp6;
+    tmp11 = tmp1 + tmp5;
+    tmp15 = tmp1 - tmp5;
+    tmp12 = tmp2 + tmp4;
+    tmp16 = tmp2 - tmp4;
+
+    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[13]);
+    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[12]);
+    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[11]);
+    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[10]);
+    tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[9]);
+    tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[8]);
+    tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[7]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((tmp10 + tmp11 + tmp12 + tmp13 - 14 * CENTERJSAMPLE) << PASS1_BITS);
+    tmp13 += tmp13;
+    dataptr[4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.274162392)) + /* c4 */
+	      MULTIPLY(tmp11 - tmp13, FIX(0.314692123)) - /* c12 */
+	      MULTIPLY(tmp12 - tmp13, FIX(0.881747734)),  /* c8 */
+	      CONST_BITS-PASS1_BITS);
+
+    tmp10 = MULTIPLY(tmp14 + tmp15, FIX(1.105676686));    /* c6 */
+
+    dataptr[2] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.273079590))   /* c2-c6 */
+	      + MULTIPLY(tmp16, FIX(0.613604268)),        /* c10 */
+	      CONST_BITS-PASS1_BITS);
+    dataptr[6] = (DCTELEM)
+      DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.719280954))   /* c6+c10 */
+	      - MULTIPLY(tmp16, FIX(1.378756276)),        /* c2 */
+	      CONST_BITS-PASS1_BITS);
+
+    /* Odd part */
+
+    tmp10 = tmp1 + tmp2;
+    tmp11 = tmp5 - tmp4;
+    dataptr[7] = (DCTELEM) ((tmp0 - tmp10 + tmp3 - tmp11 - tmp6) << PASS1_BITS);
+    tmp3 <<= CONST_BITS;
+    tmp10 = MULTIPLY(tmp10, - FIX(0.158341681));          /* -c13 */
+    tmp11 = MULTIPLY(tmp11, FIX(1.405321284));            /* c1 */
+    tmp10 += tmp11 - tmp3;
+    tmp11 = MULTIPLY(tmp0 + tmp2, FIX(1.197448846)) +     /* c5 */
+	    MULTIPLY(tmp4 + tmp6, FIX(0.752406978));      /* c9 */
+    dataptr[5] = (DCTELEM)
+      DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(2.373959773)) /* c3+c5-c13 */
+	      + MULTIPLY(tmp4, FIX(1.119999435)),         /* c1+c11-c9 */
+	      CONST_BITS-PASS1_BITS);
+    tmp12 = MULTIPLY(tmp0 + tmp1, FIX(1.334852607)) +     /* c3 */
+	    MULTIPLY(tmp5 - tmp6, FIX(0.467085129));      /* c11 */
+    dataptr[3] = (DCTELEM)
+      DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.424103948)) /* c3-c9-c13 */
+	      - MULTIPLY(tmp5, FIX(3.069855259)),         /* c1+c5+c11 */
+	      CONST_BITS-PASS1_BITS);
+    dataptr[1] = (DCTELEM)
+      DESCALE(tmp11 + tmp12 + tmp3 + tmp6 -
+	      MULTIPLY(tmp0 + tmp6, FIX(1.126980169)),    /* c3+c5-c1 */
+	      CONST_BITS-PASS1_BITS);
+
+    dataptr += DCTSIZE;		/* advance pointer to next row */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   * We must also scale the output by (8/14)*(8/7) = 32/49, which we
+   * partially fold into the constant multipliers and final shifting:
+   * 7-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/14) * 64/49.
+   */
+
+  dataptr = data;
+  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*6];
+    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*5];
+    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*4];
+    tmp3 = dataptr[DCTSIZE*3];
+
+    tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*6];
+    tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*5];
+    tmp12 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*4];
+
+    z1 = tmp0 + tmp2;
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(MULTIPLY(z1 + tmp1 + tmp3, FIX(1.306122449)), /* 64/49 */
+	      CONST_BITS+PASS1_BITS+1);
+    tmp3 += tmp3;
+    z1 -= tmp3;
+    z1 -= tmp3;
+    z1 = MULTIPLY(z1, FIX(0.461784020));                /* (c2+c6-c4)/2 */
+    z2 = MULTIPLY(tmp0 - tmp2, FIX(1.202428084));       /* (c2+c4-c6)/2 */
+    z3 = MULTIPLY(tmp1 - tmp2, FIX(0.411026446));       /* c6 */
+    dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS+PASS1_BITS+1);
+    z1 -= z2;
+    z2 = MULTIPLY(tmp0 - tmp1, FIX(1.151670509));       /* c4 */
+    dataptr[DCTSIZE*4] = (DCTELEM)
+      DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.923568041)), /* c2+c6-c4 */
+	      CONST_BITS+PASS1_BITS+1);
+    dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS+PASS1_BITS+1);
+
+    /* Odd part */
+
+    tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.221765677));   /* (c3+c1-c5)/2 */
+    tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.222383464));   /* (c3+c5-c1)/2 */
+    tmp0 = tmp1 - tmp2;
+    tmp1 += tmp2;
+    tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.800824523)); /* -c1 */
+    tmp1 += tmp2;
+    tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.801442310));   /* c5 */
+    tmp0 += tmp3;
+    tmp2 += tmp3 + MULTIPLY(tmp12, FIX(2.443531355));   /* c3+c1-c5 */
+
+    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+PASS1_BITS+1);
+    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+PASS1_BITS+1);
+    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+PASS1_BITS+1);
+
+    dataptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 12x6 sample block.
+ *
+ * 12-point FDCT in pass 1 (rows), 6-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_12x6 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+  DCTELEM *dataptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Zero 2 bottom rows of output coefficient block. */
+  MEMZERO(&data[DCTSIZE*6], SIZEOF(DCTELEM) * DCTSIZE * 2);
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * 12-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/24).
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 6; ctr++) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[11]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[10]);
+    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[9]);
+    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[8]);
+    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[7]);
+    tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[6]);
+
+    tmp10 = tmp0 + tmp5;
+    tmp13 = tmp0 - tmp5;
+    tmp11 = tmp1 + tmp4;
+    tmp14 = tmp1 - tmp4;
+    tmp12 = tmp2 + tmp3;
+    tmp15 = tmp2 - tmp3;
+
+    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[11]);
+    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[10]);
+    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[9]);
+    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[8]);
+    tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[7]);
+    tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[6]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((tmp10 + tmp11 + tmp12 - 12 * CENTERJSAMPLE) << PASS1_BITS);
+    dataptr[6] = (DCTELEM) ((tmp13 - tmp14 - tmp15) << PASS1_BITS);
+    dataptr[4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.224744871)), /* c4 */
+	      CONST_BITS-PASS1_BITS);
+    dataptr[2] = (DCTELEM)
+      DESCALE(tmp14 - tmp15 + MULTIPLY(tmp13 + tmp15, FIX(1.366025404)), /* c2 */
+	      CONST_BITS-PASS1_BITS);
+
+    /* Odd part */
+
+    tmp10 = MULTIPLY(tmp1 + tmp4, FIX_0_541196100);    /* c9 */
+    tmp14 = tmp10 + MULTIPLY(tmp1, FIX_0_765366865);   /* c3-c9 */
+    tmp15 = tmp10 - MULTIPLY(tmp4, FIX_1_847759065);   /* c3+c9 */
+    tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.121971054));   /* c5 */
+    tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.860918669));   /* c7 */
+    tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.580774953)) /* c5+c7-c1 */
+	    + MULTIPLY(tmp5, FIX(0.184591911));        /* c11 */
+    tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.184591911)); /* -c11 */
+    tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.339493912)) /* c1+c5-c11 */
+	    + MULTIPLY(tmp5, FIX(0.860918669));        /* c7 */
+    tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.725788011)) /* c1+c11-c7 */
+	    - MULTIPLY(tmp5, FIX(1.121971054));        /* c5 */
+    tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.306562965)) /* c3 */
+	    - MULTIPLY(tmp2 + tmp5, FIX_0_541196100);  /* c9 */
+
+    dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS-PASS1_BITS);
+    dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS-PASS1_BITS);
+    dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS-PASS1_BITS);
+    dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS-PASS1_BITS);
+
+    dataptr += DCTSIZE;		/* advance pointer to next row */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   * We must also scale the output by (8/12)*(8/6) = 8/9, which we
+   * partially fold into the constant multipliers and final shifting:
+   * 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12) * 16/9.
+   */
+
+  dataptr = data;
+  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*5];
+    tmp11 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*4];
+    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*3];
+
+    tmp10 = tmp0 + tmp2;
+    tmp12 = tmp0 - tmp2;
+
+    tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*5];
+    tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*4];
+    tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*3];
+
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 + tmp11, FIX(1.777777778)),         /* 16/9 */
+	      CONST_BITS+PASS1_BITS+1);
+    dataptr[DCTSIZE*2] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp12, FIX(2.177324216)),                 /* c2 */
+	      CONST_BITS+PASS1_BITS+1);
+    dataptr[DCTSIZE*4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(1.257078722)), /* c4 */
+	      CONST_BITS+PASS1_BITS+1);
+
+    /* Odd part */
+
+    tmp10 = MULTIPLY(tmp0 + tmp2, FIX(0.650711829));             /* c5 */
+
+    dataptr[DCTSIZE*1] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp0 + tmp1, FIX(1.777777778)),   /* 16/9 */
+	      CONST_BITS+PASS1_BITS+1);
+    dataptr[DCTSIZE*3] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp0 - tmp1 - tmp2, FIX(1.777777778)),    /* 16/9 */
+	      CONST_BITS+PASS1_BITS+1);
+    dataptr[DCTSIZE*5] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp2 - tmp1, FIX(1.777777778)),   /* 16/9 */
+	      CONST_BITS+PASS1_BITS+1);
+
+    dataptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 10x5 sample block.
+ *
+ * 10-point FDCT in pass 1 (rows), 5-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_10x5 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp4;
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+  DCTELEM *dataptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Zero 3 bottom rows of output coefficient block. */
+  MEMZERO(&data[DCTSIZE*5], SIZEOF(DCTELEM) * DCTSIZE * 3);
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * 10-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/20).
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 5; ctr++) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[9]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[8]);
+    tmp12 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[7]);
+    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[6]);
+    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[5]);
+
+    tmp10 = tmp0 + tmp4;
+    tmp13 = tmp0 - tmp4;
+    tmp11 = tmp1 + tmp3;
+    tmp14 = tmp1 - tmp3;
+
+    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[9]);
+    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[8]);
+    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[7]);
+    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[6]);
+    tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[5]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((tmp10 + tmp11 + tmp12 - 10 * CENTERJSAMPLE) << PASS1_BITS);
+    tmp12 += tmp12;
+    dataptr[4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.144122806)) - /* c4 */
+	      MULTIPLY(tmp11 - tmp12, FIX(0.437016024)),  /* c8 */
+	      CONST_BITS-PASS1_BITS);
+    tmp10 = MULTIPLY(tmp13 + tmp14, FIX(0.831253876));    /* c6 */
+    dataptr[2] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.513743148)),  /* c2-c6 */
+	      CONST_BITS-PASS1_BITS);
+    dataptr[6] = (DCTELEM)
+      DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.176250899)),  /* c2+c6 */
+	      CONST_BITS-PASS1_BITS);
+
+    /* Odd part */
+
+    tmp10 = tmp0 + tmp4;
+    tmp11 = tmp1 - tmp3;
+    dataptr[5] = (DCTELEM) ((tmp10 - tmp11 - tmp2) << PASS1_BITS);
+    tmp2 <<= CONST_BITS;
+    dataptr[1] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp0, FIX(1.396802247)) +          /* c1 */
+	      MULTIPLY(tmp1, FIX(1.260073511)) + tmp2 +   /* c3 */
+	      MULTIPLY(tmp3, FIX(0.642039522)) +          /* c7 */
+	      MULTIPLY(tmp4, FIX(0.221231742)),           /* c9 */
+	      CONST_BITS-PASS1_BITS);
+    tmp12 = MULTIPLY(tmp0 - tmp4, FIX(0.951056516)) -     /* (c3+c7)/2 */
+	    MULTIPLY(tmp1 + tmp3, FIX(0.587785252));      /* (c1-c9)/2 */
+    tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.309016994)) +   /* (c3-c7)/2 */
+	    (tmp11 << (CONST_BITS - 1)) - tmp2;
+    dataptr[3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS-PASS1_BITS);
+    dataptr[7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS-PASS1_BITS);
+
+    dataptr += DCTSIZE;		/* advance pointer to next row */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   * We must also scale the output by (8/10)*(8/5) = 32/25, which we
+   * fold into the constant multipliers:
+   * 5-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/10) * 32/25.
+   */
+
+  dataptr = data;
+  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*4];
+    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*3];
+    tmp2 = dataptr[DCTSIZE*2];
+
+    tmp10 = tmp0 + tmp1;
+    tmp11 = tmp0 - tmp1;
+
+    tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*4];
+    tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*3];
+
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 + tmp2, FIX(1.28)),        /* 32/25 */
+	      CONST_BITS+PASS1_BITS);
+    tmp11 = MULTIPLY(tmp11, FIX(1.011928851));          /* (c2+c4)/2 */
+    tmp10 -= tmp2 << 2;
+    tmp10 = MULTIPLY(tmp10, FIX(0.452548340));          /* (c2-c4)/2 */
+    dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS+PASS1_BITS);
+
+    /* Odd part */
+
+    tmp10 = MULTIPLY(tmp0 + tmp1, FIX(1.064004961));    /* c3 */
+
+    dataptr[DCTSIZE*1] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.657591230)), /* c1-c3 */
+	      CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*3] = (DCTELEM)
+      DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.785601151)), /* c1+c3 */
+	      CONST_BITS+PASS1_BITS);
+
+    dataptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on an 8x4 sample block.
+ *
+ * 8-point FDCT in pass 1 (rows), 4-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_8x4 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3;
+  INT32 tmp10, tmp11, tmp12, tmp13;
+  INT32 z1;
+  DCTELEM *dataptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Zero 4 bottom rows of output coefficient block. */
+  MEMZERO(&data[DCTSIZE*4], SIZEOF(DCTELEM) * DCTSIZE * 4);
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * We must also scale the output by 8/4 = 2, which we add here.
+   * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 4; ctr++) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part per LL&M figure 1 --- note that published figure is faulty;
+     * rotator "c1" should be "c6".
+     */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]);
+    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]);
+    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]);
+
+    tmp10 = tmp0 + tmp3;
+    tmp12 = tmp0 - tmp3;
+    tmp11 = tmp1 + tmp2;
+    tmp13 = tmp1 - tmp2;
+
+    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]);
+    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]);
+    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]);
+    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((tmp10 + tmp11 - 8 * CENTERJSAMPLE) << (PASS1_BITS+1));
+    dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << (PASS1_BITS+1));
+
+    z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);       /* c6 */
+    /* Add fudge factor here for final descale. */
+    z1 += ONE << (CONST_BITS-PASS1_BITS-2);
+
+    dataptr[2] = (DCTELEM)
+      RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), /* c2-c6 */
+		  CONST_BITS-PASS1_BITS-1);
+    dataptr[6] = (DCTELEM)
+      RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), /* c2+c6 */
+		  CONST_BITS-PASS1_BITS-1);
+
+    /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+     * i0..i3 in the paper are tmp0..tmp3 here.
+     */
+
+    tmp12 = tmp0 + tmp2;
+    tmp13 = tmp1 + tmp3;
+
+    z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602);       /*  c3 */
+    /* Add fudge factor here for final descale. */
+    z1 += ONE << (CONST_BITS-PASS1_BITS-2);
+
+    tmp12 = MULTIPLY(tmp12, - FIX_0_390180644);          /* -c3+c5 */
+    tmp13 = MULTIPLY(tmp13, - FIX_1_961570560);          /* -c3-c5 */
+    tmp12 += z1;
+    tmp13 += z1;
+
+    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223);       /* -c3+c7 */
+    tmp0 = MULTIPLY(tmp0, FIX_1_501321110);              /*  c1+c3-c5-c7 */
+    tmp3 = MULTIPLY(tmp3, FIX_0_298631336);              /* -c1+c3+c5-c7 */
+    tmp0 += z1 + tmp12;
+    tmp3 += z1 + tmp13;
+
+    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447);       /* -c1-c3 */
+    tmp1 = MULTIPLY(tmp1, FIX_3_072711026);              /*  c1+c3+c5-c7 */
+    tmp2 = MULTIPLY(tmp2, FIX_2_053119869);              /*  c1+c3-c5+c7 */
+    tmp1 += z1 + tmp13;
+    tmp2 += z1 + tmp12;
+
+    dataptr[1] = (DCTELEM) RIGHT_SHIFT(tmp0, CONST_BITS-PASS1_BITS-1);
+    dataptr[3] = (DCTELEM) RIGHT_SHIFT(tmp1, CONST_BITS-PASS1_BITS-1);
+    dataptr[5] = (DCTELEM) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS-1);
+    dataptr[7] = (DCTELEM) RIGHT_SHIFT(tmp3, CONST_BITS-PASS1_BITS-1);
+
+    dataptr += DCTSIZE;		/* advance pointer to next row */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   * 4-point FDCT kernel,
+   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT].
+   */
+
+  dataptr = data;
+  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*3] + (ONE << (PASS1_BITS-1));
+    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*2];
+
+    tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*3];
+    tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*2];
+
+    dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp0 + tmp1, PASS1_BITS);
+    dataptr[DCTSIZE*2] = (DCTELEM) RIGHT_SHIFT(tmp0 - tmp1, PASS1_BITS);
+
+    /* Odd part */
+
+    tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100);       /* c6 */
+    /* Add fudge factor here for final descale. */
+    tmp0 += ONE << (CONST_BITS+PASS1_BITS-1);
+
+    dataptr[DCTSIZE*1] = (DCTELEM)
+      RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */
+		  CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*3] = (DCTELEM)
+      RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */
+		  CONST_BITS+PASS1_BITS);
+
+    dataptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 6x3 sample block.
+ *
+ * 6-point FDCT in pass 1 (rows), 3-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_6x3 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2;
+  INT32 tmp10, tmp11, tmp12;
+  DCTELEM *dataptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pre-zero output coefficient block. */
+  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * We scale the results further by 2 as part of output adaption
+   * scaling for different DCT size.
+   * 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12).
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 3; ctr++) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[5]);
+    tmp11 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[4]);
+    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[3]);
+
+    tmp10 = tmp0 + tmp2;
+    tmp12 = tmp0 - tmp2;
+
+    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[5]);
+    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[4]);
+    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[3]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((tmp10 + tmp11 - 6 * CENTERJSAMPLE) << (PASS1_BITS+1));
+    dataptr[2] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp12, FIX(1.224744871)),                 /* c2 */
+	      CONST_BITS-PASS1_BITS-1);
+    dataptr[4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(0.707106781)), /* c4 */
+	      CONST_BITS-PASS1_BITS-1);
+
+    /* Odd part */
+
+    tmp10 = DESCALE(MULTIPLY(tmp0 + tmp2, FIX(0.366025404)),     /* c5 */
+		    CONST_BITS-PASS1_BITS-1);
+
+    dataptr[1] = (DCTELEM) (tmp10 + ((tmp0 + tmp1) << (PASS1_BITS+1)));
+    dataptr[3] = (DCTELEM) ((tmp0 - tmp1 - tmp2) << (PASS1_BITS+1));
+    dataptr[5] = (DCTELEM) (tmp10 + ((tmp2 - tmp1) << (PASS1_BITS+1)));
+
+    dataptr += DCTSIZE;		/* advance pointer to next row */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   * We must also scale the output by (8/6)*(8/3) = 32/9, which we partially
+   * fold into the constant multipliers (other part was done in pass 1):
+   * 3-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/6) * 16/9.
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 6; ctr++) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*2];
+    tmp1 = dataptr[DCTSIZE*1];
+
+    tmp2 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*2];
+
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp0 + tmp1, FIX(1.777777778)),        /* 16/9 */
+	      CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*2] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(1.257078722)), /* c2 */
+	      CONST_BITS+PASS1_BITS);
+
+    /* Odd part */
+
+    dataptr[DCTSIZE*1] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp2, FIX(2.177324216)),               /* c1 */
+	      CONST_BITS+PASS1_BITS);
+
+    dataptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 4x2 sample block.
+ *
+ * 4-point FDCT in pass 1 (rows), 2-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_4x2 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1;
+  INT32 tmp10, tmp11;
+  DCTELEM *dataptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pre-zero output coefficient block. */
+  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * We must also scale the output by (8/4)*(8/2) = 2**3, which we add here.
+   * 4-point FDCT kernel,
+   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT].
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 2; ctr++) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]);
+
+    tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]);
+    tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((tmp0 + tmp1 - 4 * CENTERJSAMPLE) << (PASS1_BITS+3));
+    dataptr[2] = (DCTELEM) ((tmp0 - tmp1) << (PASS1_BITS+3));
+
+    /* Odd part */
+
+    tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100);       /* c6 */
+    /* Add fudge factor here for final descale. */
+    tmp0 += ONE << (CONST_BITS-PASS1_BITS-4);
+
+    dataptr[1] = (DCTELEM)
+      RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */
+		  CONST_BITS-PASS1_BITS-3);
+    dataptr[3] = (DCTELEM)
+      RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */
+		  CONST_BITS-PASS1_BITS-3);
+
+    dataptr += DCTSIZE;		/* advance pointer to next row */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 4; ctr++) {
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp0 = dataptr[DCTSIZE*0] + (ONE << (PASS1_BITS-1));
+    tmp1 = dataptr[DCTSIZE*1];
+
+    dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp0 + tmp1, PASS1_BITS);
+
+    /* Odd part */
+
+    dataptr[DCTSIZE*1] = (DCTELEM) RIGHT_SHIFT(tmp0 - tmp1, PASS1_BITS);
+
+    dataptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 2x1 sample block.
+ *
+ * 2-point FDCT in pass 1 (rows), 1-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_2x1 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1;
+  JSAMPROW elemptr;
+
+  /* Pre-zero output coefficient block. */
+  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+  elemptr = sample_data[0] + start_col;
+
+  tmp0 = GETJSAMPLE(elemptr[0]);
+  tmp1 = GETJSAMPLE(elemptr[1]);
+
+  /* We leave the results scaled up by an overall factor of 8.
+   * We must also scale the output by (8/2)*(8/1) = 2**5.
+   */
+
+  /* Even part */
+
+  /* Apply unsigned->signed conversion */
+  data[0] = (DCTELEM) ((tmp0 + tmp1 - 2 * CENTERJSAMPLE) << 5);
+
+  /* Odd part */
+
+  data[1] = (DCTELEM) ((tmp0 - tmp1) << 5);
+}
+
+
+/*
+ * Perform the forward DCT on an 8x16 sample block.
+ *
+ * 8-point FDCT in pass 1 (rows), 16-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_8x16 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17;
+  INT32 z1;
+  DCTELEM workspace[DCTSIZE2];
+  DCTELEM *dataptr;
+  DCTELEM *wsptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+   */
+
+  dataptr = data;
+  ctr = 0;
+  for (;;) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part per LL&M figure 1 --- note that published figure is faulty;
+     * rotator "c1" should be "c6".
+     */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]);
+    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]);
+    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]);
+
+    tmp10 = tmp0 + tmp3;
+    tmp12 = tmp0 - tmp3;
+    tmp11 = tmp1 + tmp2;
+    tmp13 = tmp1 - tmp2;
+
+    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]);
+    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]);
+    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]);
+    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM) ((tmp10 + tmp11 - 8 * CENTERJSAMPLE) << PASS1_BITS);
+    dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS);
+
+    z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);   /* c6 */
+    dataptr[2] = (DCTELEM)
+      DESCALE(z1 + MULTIPLY(tmp12, FIX_0_765366865), /* c2-c6 */
+	      CONST_BITS-PASS1_BITS);
+    dataptr[6] = (DCTELEM)
+      DESCALE(z1 - MULTIPLY(tmp13, FIX_1_847759065), /* c2+c6 */
+	      CONST_BITS-PASS1_BITS);
+
+    /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+     * i0..i3 in the paper are tmp0..tmp3 here.
+     */
+
+    tmp12 = tmp0 + tmp2;
+    tmp13 = tmp1 + tmp3;
+
+    z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602);   /*  c3 */
+    tmp12 = MULTIPLY(tmp12, - FIX_0_390180644);      /* -c3+c5 */
+    tmp13 = MULTIPLY(tmp13, - FIX_1_961570560);      /* -c3-c5 */
+    tmp12 += z1;
+    tmp13 += z1;
+
+    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223);   /* -c3+c7 */
+    tmp0 = MULTIPLY(tmp0, FIX_1_501321110);          /*  c1+c3-c5-c7 */
+    tmp3 = MULTIPLY(tmp3, FIX_0_298631336);          /* -c1+c3+c5-c7 */
+    tmp0 += z1 + tmp12;
+    tmp3 += z1 + tmp13;
+
+    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447);   /* -c1-c3 */
+    tmp1 = MULTIPLY(tmp1, FIX_3_072711026);          /*  c1+c3+c5-c7 */
+    tmp2 = MULTIPLY(tmp2, FIX_2_053119869);          /*  c1+c3-c5+c7 */
+    tmp1 += z1 + tmp13;
+    tmp2 += z1 + tmp12;
+
+    dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-PASS1_BITS);
+    dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-PASS1_BITS);
+    dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-PASS1_BITS);
+    dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS-PASS1_BITS);
+
+    ctr++;
+
+    if (ctr != DCTSIZE) {
+      if (ctr == DCTSIZE * 2)
+	break;			/* Done. */
+      dataptr += DCTSIZE;	/* advance pointer to next row */
+    } else
+      dataptr = workspace;	/* switch pointer to extended workspace */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   * We must also scale the output by 8/16 = 1/2.
+   * 16-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/32).
+   */
+
+  dataptr = data;
+  wsptr = workspace;
+  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*7];
+    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*6];
+    tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*5];
+    tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*4];
+    tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*3];
+    tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*2];
+    tmp6 = dataptr[DCTSIZE*6] + wsptr[DCTSIZE*1];
+    tmp7 = dataptr[DCTSIZE*7] + wsptr[DCTSIZE*0];
+
+    tmp10 = tmp0 + tmp7;
+    tmp14 = tmp0 - tmp7;
+    tmp11 = tmp1 + tmp6;
+    tmp15 = tmp1 - tmp6;
+    tmp12 = tmp2 + tmp5;
+    tmp16 = tmp2 - tmp5;
+    tmp13 = tmp3 + tmp4;
+    tmp17 = tmp3 - tmp4;
+
+    tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*7];
+    tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*6];
+    tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*5];
+    tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*4];
+    tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*3];
+    tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*2];
+    tmp6 = dataptr[DCTSIZE*6] - wsptr[DCTSIZE*1];
+    tmp7 = dataptr[DCTSIZE*7] - wsptr[DCTSIZE*0];
+
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(tmp10 + tmp11 + tmp12 + tmp13, PASS1_BITS+1);
+    dataptr[DCTSIZE*4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */
+	      MULTIPLY(tmp11 - tmp12, FIX_0_541196100),   /* c12[16] = c6[8] */
+	      CONST_BITS+PASS1_BITS+1);
+
+    tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) +   /* c14[16] = c7[8] */
+	    MULTIPLY(tmp14 - tmp16, FIX(1.387039845));    /* c2[16] = c1[8] */
+
+    dataptr[DCTSIZE*2] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982))   /* c6+c14 */
+	      + MULTIPLY(tmp16, FIX(2.172734804)),        /* c2+c10 */
+	      CONST_BITS+PASS1_BITS+1);
+    dataptr[DCTSIZE*6] = (DCTELEM)
+      DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243))   /* c2-c6 */
+	      - MULTIPLY(tmp17, FIX(1.061594338)),        /* c10+c14 */
+	      CONST_BITS+PASS1_BITS+1);
+
+    /* Odd part */
+
+    tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) +         /* c3 */
+	    MULTIPLY(tmp6 - tmp7, FIX(0.410524528));          /* c13 */
+    tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) +         /* c5 */
+	    MULTIPLY(tmp5 + tmp7, FIX(0.666655658));          /* c11 */
+    tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) +         /* c7 */
+	    MULTIPLY(tmp4 - tmp7, FIX(0.897167586));          /* c9 */
+    tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) +         /* c15 */
+	    MULTIPLY(tmp6 - tmp5, FIX(1.407403738));          /* c1 */
+    tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) +       /* -c11 */
+	    MULTIPLY(tmp4 + tmp6, - FIX(1.247225013));        /* -c5 */
+    tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) +       /* -c3 */
+	    MULTIPLY(tmp5 - tmp4, FIX(0.410524528));          /* c13 */
+    tmp10 = tmp11 + tmp12 + tmp13 -
+	    MULTIPLY(tmp0, FIX(2.286341144)) +                /* c7+c5+c3-c1 */
+	    MULTIPLY(tmp7, FIX(0.779653625));                 /* c15+c13-c11+c9 */
+    tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */
+	     - MULTIPLY(tmp6, FIX(1.663905119));              /* c7+c13+c1-c5 */
+    tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */
+	     + MULTIPLY(tmp5, FIX(1.227391138));              /* c9-c11+c1-c13 */
+    tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */
+	     + MULTIPLY(tmp4, FIX(2.167985692));              /* c1+c13+c5-c9 */
+
+    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+PASS1_BITS+1);
+    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+PASS1_BITS+1);
+    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+PASS1_BITS+1);
+    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+PASS1_BITS+1);
+
+    dataptr++;			/* advance pointer to next column */
+    wsptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 7x14 sample block.
+ *
+ * 7-point FDCT in pass 1 (rows), 14-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_7x14 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+  INT32 z1, z2, z3;
+  DCTELEM workspace[8*6];
+  DCTELEM *dataptr;
+  DCTELEM *wsptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pre-zero output coefficient block. */
+  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * 7-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/14).
+   */
+
+  dataptr = data;
+  ctr = 0;
+  for (;;) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[6]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[5]);
+    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[4]);
+    tmp3 = GETJSAMPLE(elemptr[3]);
+
+    tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[6]);
+    tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[5]);
+    tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[4]);
+
+    z1 = tmp0 + tmp2;
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((z1 + tmp1 + tmp3 - 7 * CENTERJSAMPLE) << PASS1_BITS);
+    tmp3 += tmp3;
+    z1 -= tmp3;
+    z1 -= tmp3;
+    z1 = MULTIPLY(z1, FIX(0.353553391));                /* (c2+c6-c4)/2 */
+    z2 = MULTIPLY(tmp0 - tmp2, FIX(0.920609002));       /* (c2+c4-c6)/2 */
+    z3 = MULTIPLY(tmp1 - tmp2, FIX(0.314692123));       /* c6 */
+    dataptr[2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS-PASS1_BITS);
+    z1 -= z2;
+    z2 = MULTIPLY(tmp0 - tmp1, FIX(0.881747734));       /* c4 */
+    dataptr[4] = (DCTELEM)
+      DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.707106781)), /* c2+c6-c4 */
+	      CONST_BITS-PASS1_BITS);
+    dataptr[6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS-PASS1_BITS);
+
+    /* Odd part */
+
+    tmp1 = MULTIPLY(tmp10 + tmp11, FIX(0.935414347));   /* (c3+c1-c5)/2 */
+    tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.170262339));   /* (c3+c5-c1)/2 */
+    tmp0 = tmp1 - tmp2;
+    tmp1 += tmp2;
+    tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.378756276)); /* -c1 */
+    tmp1 += tmp2;
+    tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.613604268));   /* c5 */
+    tmp0 += tmp3;
+    tmp2 += tmp3 + MULTIPLY(tmp12, FIX(1.870828693));   /* c3+c1-c5 */
+
+    dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-PASS1_BITS);
+    dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-PASS1_BITS);
+    dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-PASS1_BITS);
+
+    ctr++;
+
+    if (ctr != DCTSIZE) {
+      if (ctr == 14)
+	break;			/* Done. */
+      dataptr += DCTSIZE;	/* advance pointer to next row */
+    } else
+      dataptr = workspace;	/* switch pointer to extended workspace */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   * We must also scale the output by (8/7)*(8/14) = 32/49, which we
+   * fold into the constant multipliers:
+   * 14-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/28) * 32/49.
+   */
+
+  dataptr = data;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 7; ctr++) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*5];
+    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*4];
+    tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*3];
+    tmp13 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*2];
+    tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*1];
+    tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*0];
+    tmp6 = dataptr[DCTSIZE*6] + dataptr[DCTSIZE*7];
+
+    tmp10 = tmp0 + tmp6;
+    tmp14 = tmp0 - tmp6;
+    tmp11 = tmp1 + tmp5;
+    tmp15 = tmp1 - tmp5;
+    tmp12 = tmp2 + tmp4;
+    tmp16 = tmp2 - tmp4;
+
+    tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*5];
+    tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*4];
+    tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*3];
+    tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*2];
+    tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*1];
+    tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*0];
+    tmp6 = dataptr[DCTSIZE*6] - dataptr[DCTSIZE*7];
+
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12 + tmp13,
+		       FIX(0.653061224)),                 /* 32/49 */
+	      CONST_BITS+PASS1_BITS);
+    tmp13 += tmp13;
+    dataptr[DCTSIZE*4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp13, FIX(0.832106052)) + /* c4 */
+	      MULTIPLY(tmp11 - tmp13, FIX(0.205513223)) - /* c12 */
+	      MULTIPLY(tmp12 - tmp13, FIX(0.575835255)),  /* c8 */
+	      CONST_BITS+PASS1_BITS);
+
+    tmp10 = MULTIPLY(tmp14 + tmp15, FIX(0.722074570));    /* c6 */
+
+    dataptr[DCTSIZE*2] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.178337691))   /* c2-c6 */
+	      + MULTIPLY(tmp16, FIX(0.400721155)),        /* c10 */
+	      CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*6] = (DCTELEM)
+      DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.122795725))   /* c6+c10 */
+	      - MULTIPLY(tmp16, FIX(0.900412262)),        /* c2 */
+	      CONST_BITS+PASS1_BITS);
+
+    /* Odd part */
+
+    tmp10 = tmp1 + tmp2;
+    tmp11 = tmp5 - tmp4;
+    dataptr[DCTSIZE*7] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp0 - tmp10 + tmp3 - tmp11 - tmp6,
+		       FIX(0.653061224)),                 /* 32/49 */
+	      CONST_BITS+PASS1_BITS);
+    tmp3  = MULTIPLY(tmp3 , FIX(0.653061224));            /* 32/49 */
+    tmp10 = MULTIPLY(tmp10, - FIX(0.103406812));          /* -c13 */
+    tmp11 = MULTIPLY(tmp11, FIX(0.917760839));            /* c1 */
+    tmp10 += tmp11 - tmp3;
+    tmp11 = MULTIPLY(tmp0 + tmp2, FIX(0.782007410)) +     /* c5 */
+	    MULTIPLY(tmp4 + tmp6, FIX(0.491367823));      /* c9 */
+    dataptr[DCTSIZE*5] = (DCTELEM)
+      DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(1.550341076)) /* c3+c5-c13 */
+	      + MULTIPLY(tmp4, FIX(0.731428202)),         /* c1+c11-c9 */
+	      CONST_BITS+PASS1_BITS);
+    tmp12 = MULTIPLY(tmp0 + tmp1, FIX(0.871740478)) +     /* c3 */
+	    MULTIPLY(tmp5 - tmp6, FIX(0.305035186));      /* c11 */
+    dataptr[DCTSIZE*3] = (DCTELEM)
+      DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.276965844)) /* c3-c9-c13 */
+	      - MULTIPLY(tmp5, FIX(2.004803435)),         /* c1+c5+c11 */
+	      CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*1] = (DCTELEM)
+      DESCALE(tmp11 + tmp12 + tmp3
+	      - MULTIPLY(tmp0, FIX(0.735987049))          /* c3+c5-c1 */
+	      - MULTIPLY(tmp6, FIX(0.082925825)),         /* c9-c11-c13 */
+	      CONST_BITS+PASS1_BITS);
+
+    dataptr++;			/* advance pointer to next column */
+    wsptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 6x12 sample block.
+ *
+ * 6-point FDCT in pass 1 (rows), 12-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_6x12 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+  DCTELEM workspace[8*4];
+  DCTELEM *dataptr;
+  DCTELEM *wsptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pre-zero output coefficient block. */
+  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12).
+   */
+
+  dataptr = data;
+  ctr = 0;
+  for (;;) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[5]);
+    tmp11 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[4]);
+    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[3]);
+
+    tmp10 = tmp0 + tmp2;
+    tmp12 = tmp0 - tmp2;
+
+    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[5]);
+    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[4]);
+    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[3]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((tmp10 + tmp11 - 6 * CENTERJSAMPLE) << PASS1_BITS);
+    dataptr[2] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp12, FIX(1.224744871)),                 /* c2 */
+	      CONST_BITS-PASS1_BITS);
+    dataptr[4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(0.707106781)), /* c4 */
+	      CONST_BITS-PASS1_BITS);
+
+    /* Odd part */
+
+    tmp10 = DESCALE(MULTIPLY(tmp0 + tmp2, FIX(0.366025404)),     /* c5 */
+		    CONST_BITS-PASS1_BITS);
+
+    dataptr[1] = (DCTELEM) (tmp10 + ((tmp0 + tmp1) << PASS1_BITS));
+    dataptr[3] = (DCTELEM) ((tmp0 - tmp1 - tmp2) << PASS1_BITS);
+    dataptr[5] = (DCTELEM) (tmp10 + ((tmp2 - tmp1) << PASS1_BITS));
+
+    ctr++;
+
+    if (ctr != DCTSIZE) {
+      if (ctr == 12)
+	break;			/* Done. */
+      dataptr += DCTSIZE;	/* advance pointer to next row */
+    } else
+      dataptr = workspace;	/* switch pointer to extended workspace */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   * We must also scale the output by (8/6)*(8/12) = 8/9, which we
+   * fold into the constant multipliers:
+   * 12-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/24) * 8/9.
+   */
+
+  dataptr = data;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 6; ctr++) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*3];
+    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*2];
+    tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*1];
+    tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*0];
+    tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*7];
+    tmp5 = dataptr[DCTSIZE*5] + dataptr[DCTSIZE*6];
+
+    tmp10 = tmp0 + tmp5;
+    tmp13 = tmp0 - tmp5;
+    tmp11 = tmp1 + tmp4;
+    tmp14 = tmp1 - tmp4;
+    tmp12 = tmp2 + tmp3;
+    tmp15 = tmp2 - tmp3;
+
+    tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*3];
+    tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*2];
+    tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*1];
+    tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*0];
+    tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*7];
+    tmp5 = dataptr[DCTSIZE*5] - dataptr[DCTSIZE*6];
+
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(0.888888889)), /* 8/9 */
+	      CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*6] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp13 - tmp14 - tmp15, FIX(0.888888889)), /* 8/9 */
+	      CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.088662108)),         /* c4 */
+	      CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*2] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp14 - tmp15, FIX(0.888888889)) +        /* 8/9 */
+	      MULTIPLY(tmp13 + tmp15, FIX(1.214244803)),         /* c2 */
+	      CONST_BITS+PASS1_BITS);
+
+    /* Odd part */
+
+    tmp10 = MULTIPLY(tmp1 + tmp4, FIX(0.481063200));   /* c9 */
+    tmp14 = tmp10 + MULTIPLY(tmp1, FIX(0.680326102));  /* c3-c9 */
+    tmp15 = tmp10 - MULTIPLY(tmp4, FIX(1.642452502));  /* c3+c9 */
+    tmp12 = MULTIPLY(tmp0 + tmp2, FIX(0.997307603));   /* c5 */
+    tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.765261039));   /* c7 */
+    tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.516244403)) /* c5+c7-c1 */
+	    + MULTIPLY(tmp5, FIX(0.164081699));        /* c11 */
+    tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.164081699)); /* -c11 */
+    tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.079550144)) /* c1+c5-c11 */
+	    + MULTIPLY(tmp5, FIX(0.765261039));        /* c7 */
+    tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.645144899)) /* c1+c11-c7 */
+	    - MULTIPLY(tmp5, FIX(0.997307603));        /* c5 */
+    tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.161389302)) /* c3 */
+	    - MULTIPLY(tmp2 + tmp5, FIX(0.481063200)); /* c9 */
+
+    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+PASS1_BITS);
+
+    dataptr++;			/* advance pointer to next column */
+    wsptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 5x10 sample block.
+ *
+ * 5-point FDCT in pass 1 (rows), 10-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_5x10 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp4;
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+  DCTELEM workspace[8*2];
+  DCTELEM *dataptr;
+  DCTELEM *wsptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pre-zero output coefficient block. */
+  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * 5-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/10).
+   */
+
+  dataptr = data;
+  ctr = 0;
+  for (;;) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[4]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[3]);
+    tmp2 = GETJSAMPLE(elemptr[2]);
+
+    tmp10 = tmp0 + tmp1;
+    tmp11 = tmp0 - tmp1;
+
+    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[4]);
+    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[3]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((tmp10 + tmp2 - 5 * CENTERJSAMPLE) << PASS1_BITS);
+    tmp11 = MULTIPLY(tmp11, FIX(0.790569415));          /* (c2+c4)/2 */
+    tmp10 -= tmp2 << 2;
+    tmp10 = MULTIPLY(tmp10, FIX(0.353553391));          /* (c2-c4)/2 */
+    dataptr[2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS-PASS1_BITS);
+    dataptr[4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS-PASS1_BITS);
+
+    /* Odd part */
+
+    tmp10 = MULTIPLY(tmp0 + tmp1, FIX(0.831253876));    /* c3 */
+
+    dataptr[1] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.513743148)), /* c1-c3 */
+	      CONST_BITS-PASS1_BITS);
+    dataptr[3] = (DCTELEM)
+      DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.176250899)), /* c1+c3 */
+	      CONST_BITS-PASS1_BITS);
+
+    ctr++;
+
+    if (ctr != DCTSIZE) {
+      if (ctr == 10)
+	break;			/* Done. */
+      dataptr += DCTSIZE;	/* advance pointer to next row */
+    } else
+      dataptr = workspace;	/* switch pointer to extended workspace */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   * We must also scale the output by (8/5)*(8/10) = 32/25, which we
+   * fold into the constant multipliers:
+   * 10-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/20) * 32/25.
+   */
+
+  dataptr = data;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 5; ctr++) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*1];
+    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*0];
+    tmp12 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*7];
+    tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*6];
+    tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*5];
+
+    tmp10 = tmp0 + tmp4;
+    tmp13 = tmp0 - tmp4;
+    tmp11 = tmp1 + tmp3;
+    tmp14 = tmp1 - tmp3;
+
+    tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*1];
+    tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*0];
+    tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*7];
+    tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*6];
+    tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*5];
+
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(1.28)), /* 32/25 */
+	      CONST_BITS+PASS1_BITS);
+    tmp12 += tmp12;
+    dataptr[DCTSIZE*4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.464477191)) - /* c4 */
+	      MULTIPLY(tmp11 - tmp12, FIX(0.559380511)),  /* c8 */
+	      CONST_BITS+PASS1_BITS);
+    tmp10 = MULTIPLY(tmp13 + tmp14, FIX(1.064004961));    /* c6 */
+    dataptr[DCTSIZE*2] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.657591230)),  /* c2-c6 */
+	      CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*6] = (DCTELEM)
+      DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.785601151)),  /* c2+c6 */
+	      CONST_BITS+PASS1_BITS);
+
+    /* Odd part */
+
+    tmp10 = tmp0 + tmp4;
+    tmp11 = tmp1 - tmp3;
+    dataptr[DCTSIZE*5] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp11 - tmp2, FIX(1.28)),  /* 32/25 */
+	      CONST_BITS+PASS1_BITS);
+    tmp2 = MULTIPLY(tmp2, FIX(1.28));                     /* 32/25 */
+    dataptr[DCTSIZE*1] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp0, FIX(1.787906876)) +          /* c1 */
+	      MULTIPLY(tmp1, FIX(1.612894094)) + tmp2 +   /* c3 */
+	      MULTIPLY(tmp3, FIX(0.821810588)) +          /* c7 */
+	      MULTIPLY(tmp4, FIX(0.283176630)),           /* c9 */
+	      CONST_BITS+PASS1_BITS);
+    tmp12 = MULTIPLY(tmp0 - tmp4, FIX(1.217352341)) -     /* (c3+c7)/2 */
+	    MULTIPLY(tmp1 + tmp3, FIX(0.752365123));      /* (c1-c9)/2 */
+    tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.395541753)) +   /* (c3-c7)/2 */
+	    MULTIPLY(tmp11, FIX(0.64)) - tmp2;            /* 16/25 */
+    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS+PASS1_BITS);
+
+    dataptr++;			/* advance pointer to next column */
+    wsptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 4x8 sample block.
+ *
+ * 4-point FDCT in pass 1 (rows), 8-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_4x8 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3;
+  INT32 tmp10, tmp11, tmp12, tmp13;
+  INT32 z1;
+  DCTELEM *dataptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pre-zero output coefficient block. */
+  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * We must also scale the output by 8/4 = 2, which we add here.
+   * 4-point FDCT kernel,
+   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT].
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < DCTSIZE; ctr++) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]);
+    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]);
+
+    tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]);
+    tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((tmp0 + tmp1 - 4 * CENTERJSAMPLE) << (PASS1_BITS+1));
+    dataptr[2] = (DCTELEM) ((tmp0 - tmp1) << (PASS1_BITS+1));
+
+    /* Odd part */
+
+    tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100);       /* c6 */
+    /* Add fudge factor here for final descale. */
+    tmp0 += ONE << (CONST_BITS-PASS1_BITS-2);
+
+    dataptr[1] = (DCTELEM)
+      RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */
+		  CONST_BITS-PASS1_BITS-1);
+    dataptr[3] = (DCTELEM)
+      RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */
+		  CONST_BITS-PASS1_BITS-1);
+
+    dataptr += DCTSIZE;		/* advance pointer to next row */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 4; ctr++) {
+    /* Even part per LL&M figure 1 --- note that published figure is faulty;
+     * rotator "c1" should be "c6".
+     */
+
+    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
+    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
+    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
+    tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
+
+    /* Add fudge factor here for final descale. */
+    tmp10 = tmp0 + tmp3 + (ONE << (PASS1_BITS-1));
+    tmp12 = tmp0 - tmp3;
+    tmp11 = tmp1 + tmp2;
+    tmp13 = tmp1 - tmp2;
+
+    tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
+    tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
+    tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
+    tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
+
+    dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp10 + tmp11, PASS1_BITS);
+    dataptr[DCTSIZE*4] = (DCTELEM) RIGHT_SHIFT(tmp10 - tmp11, PASS1_BITS);
+
+    z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);       /* c6 */
+    /* Add fudge factor here for final descale. */
+    z1 += ONE << (CONST_BITS+PASS1_BITS-1);
+
+    dataptr[DCTSIZE*2] = (DCTELEM)
+      RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), /* c2-c6 */
+		  CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*6] = (DCTELEM)
+      RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), /* c2+c6 */
+		  CONST_BITS+PASS1_BITS);
+
+    /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+     * i0..i3 in the paper are tmp0..tmp3 here.
+     */
+
+    tmp12 = tmp0 + tmp2;
+    tmp13 = tmp1 + tmp3;
+
+    z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602);       /*  c3 */
+    /* Add fudge factor here for final descale. */
+    z1 += ONE << (CONST_BITS+PASS1_BITS-1);
+
+    tmp12 = MULTIPLY(tmp12, - FIX_0_390180644);          /* -c3+c5 */
+    tmp13 = MULTIPLY(tmp13, - FIX_1_961570560);          /* -c3-c5 */
+    tmp12 += z1;
+    tmp13 += z1;
+
+    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223);       /* -c3+c7 */
+    tmp0 = MULTIPLY(tmp0, FIX_1_501321110);              /*  c1+c3-c5-c7 */
+    tmp3 = MULTIPLY(tmp3, FIX_0_298631336);              /* -c1+c3+c5-c7 */
+    tmp0 += z1 + tmp12;
+    tmp3 += z1 + tmp13;
+
+    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447);       /* -c1-c3 */
+    tmp1 = MULTIPLY(tmp1, FIX_3_072711026);              /*  c1+c3+c5-c7 */
+    tmp2 = MULTIPLY(tmp2, FIX_2_053119869);              /*  c1+c3-c5+c7 */
+    tmp1 += z1 + tmp13;
+    tmp2 += z1 + tmp12;
+
+    dataptr[DCTSIZE*1] = (DCTELEM) RIGHT_SHIFT(tmp0, CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*3] = (DCTELEM) RIGHT_SHIFT(tmp1, CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*5] = (DCTELEM) RIGHT_SHIFT(tmp2, CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*7] = (DCTELEM) RIGHT_SHIFT(tmp3, CONST_BITS+PASS1_BITS);
+
+    dataptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 3x6 sample block.
+ *
+ * 3-point FDCT in pass 1 (rows), 6-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_3x6 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1, tmp2;
+  INT32 tmp10, tmp11, tmp12;
+  DCTELEM *dataptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pre-zero output coefficient block. */
+  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * We scale the results further by 2 as part of output adaption
+   * scaling for different DCT size.
+   * 3-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/6).
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 6; ctr++) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[2]);
+    tmp1 = GETJSAMPLE(elemptr[1]);
+
+    tmp2 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[2]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM)
+      ((tmp0 + tmp1 - 3 * CENTERJSAMPLE) << (PASS1_BITS+1));
+    dataptr[2] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(0.707106781)), /* c2 */
+	      CONST_BITS-PASS1_BITS-1);
+
+    /* Odd part */
+
+    dataptr[1] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp2, FIX(1.224744871)),               /* c1 */
+	      CONST_BITS-PASS1_BITS-1);
+
+    dataptr += DCTSIZE;		/* advance pointer to next row */
+  }
+
+  /* Pass 2: process columns.
+   * We remove the PASS1_BITS scaling, but leave the results scaled up
+   * by an overall factor of 8.
+   * We must also scale the output by (8/6)*(8/3) = 32/9, which we partially
+   * fold into the constant multipliers (other part was done in pass 1):
+   * 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12) * 16/9.
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 3; ctr++) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*5];
+    tmp11 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*4];
+    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*3];
+
+    tmp10 = tmp0 + tmp2;
+    tmp12 = tmp0 - tmp2;
+
+    tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*5];
+    tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*4];
+    tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*3];
+
+    dataptr[DCTSIZE*0] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 + tmp11, FIX(1.777777778)),         /* 16/9 */
+	      CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*2] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp12, FIX(2.177324216)),                 /* c2 */
+	      CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*4] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(1.257078722)), /* c4 */
+	      CONST_BITS+PASS1_BITS);
+
+    /* Odd part */
+
+    tmp10 = MULTIPLY(tmp0 + tmp2, FIX(0.650711829));             /* c5 */
+
+    dataptr[DCTSIZE*1] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp0 + tmp1, FIX(1.777777778)),   /* 16/9 */
+	      CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*3] = (DCTELEM)
+      DESCALE(MULTIPLY(tmp0 - tmp1 - tmp2, FIX(1.777777778)),    /* 16/9 */
+	      CONST_BITS+PASS1_BITS);
+    dataptr[DCTSIZE*5] = (DCTELEM)
+      DESCALE(tmp10 + MULTIPLY(tmp2 - tmp1, FIX(1.777777778)),   /* 16/9 */
+	      CONST_BITS+PASS1_BITS);
+
+    dataptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 2x4 sample block.
+ *
+ * 2-point FDCT in pass 1 (rows), 4-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_2x4 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1;
+  INT32 tmp10, tmp11;
+  DCTELEM *dataptr;
+  JSAMPROW elemptr;
+  int ctr;
+  SHIFT_TEMPS
+
+  /* Pre-zero output coefficient block. */
+  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+  /* Pass 1: process rows.
+   * Note results are scaled up by sqrt(8) compared to a true DCT.
+   * We must also scale the output by (8/2)*(8/4) = 2**3, which we add here.
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 4; ctr++) {
+    elemptr = sample_data[ctr] + start_col;
+
+    /* Even part */
+
+    tmp0 = GETJSAMPLE(elemptr[0]);
+    tmp1 = GETJSAMPLE(elemptr[1]);
+
+    /* Apply unsigned->signed conversion */
+    dataptr[0] = (DCTELEM) ((tmp0 + tmp1 - 2 * CENTERJSAMPLE) << 3);
+
+    /* Odd part */
+
+    dataptr[1] = (DCTELEM) ((tmp0 - tmp1) << 3);
+
+    dataptr += DCTSIZE;		/* advance pointer to next row */
+  }
+
+  /* Pass 2: process columns.
+   * We leave the results scaled up by an overall factor of 8.
+   * 4-point FDCT kernel,
+   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT].
+   */
+
+  dataptr = data;
+  for (ctr = 0; ctr < 2; ctr++) {
+    /* Even part */
+
+    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*3];
+    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*2];
+
+    tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*3];
+    tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*2];
+
+    dataptr[DCTSIZE*0] = (DCTELEM) (tmp0 + tmp1);
+    dataptr[DCTSIZE*2] = (DCTELEM) (tmp0 - tmp1);
+
+    /* Odd part */
+
+    tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100);       /* c6 */
+    /* Add fudge factor here for final descale. */
+    tmp0 += ONE << (CONST_BITS-1);
+
+    dataptr[DCTSIZE*1] = (DCTELEM)
+      RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */
+		  CONST_BITS);
+    dataptr[DCTSIZE*3] = (DCTELEM)
+      RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */
+		  CONST_BITS);
+
+    dataptr++;			/* advance pointer to next column */
+  }
+}
+
+
+/*
+ * Perform the forward DCT on a 1x2 sample block.
+ *
+ * 1-point FDCT in pass 1 (rows), 2-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_1x2 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+  INT32 tmp0, tmp1;
+
+  /* Pre-zero output coefficient block. */
+  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+  /* Pass 1: empty. */
+
+  /* Pass 2: process columns.
+   * We leave the results scaled up by an overall factor of 8.
+   * We must also scale the output by (8/1)*(8/2) = 2**5.
+   */
+
+  /* Even part */
+
+  tmp0 = GETJSAMPLE(sample_data[0][start_col]);
+  tmp1 = GETJSAMPLE(sample_data[1][start_col]);
+
+  /* Apply unsigned->signed conversion */
+  data[DCTSIZE*0] = (DCTELEM) ((tmp0 + tmp1 - 2 * CENTERJSAMPLE) << 5);
+
+  /* Odd part */
+
+  data[DCTSIZE*1] = (DCTELEM) ((tmp0 - tmp1) << 5);
+}
+
+#endif /* DCT_SCALING_SUPPORTED */
+#endif /* DCT_ISLOW_SUPPORTED */
diff --git a/source/Irrlicht/jpeglib/jidctflt.c b/source/Irrlicht/jpeglib/jidctflt.c
new file mode 100644
index 00000000..f399600c
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jidctflt.c
@@ -0,0 +1,235 @@
+/*
+ * jidctflt.c
+ *
+ * Copyright (C) 1994-1998, Thomas G. Lane.
+ * Modified 2010 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a floating-point implementation of the
+ * inverse DCT (Discrete Cosine Transform).  In the IJG code, this routine
+ * must also perform dequantization of the input coefficients.
+ *
+ * This implementation should be more accurate than either of the integer
+ * IDCT implementations.  However, it may not give the same results on all
+ * machines because of differences in roundoff behavior.  Speed will depend
+ * on the hardware's floating point capacity.
+ *
+ * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
+ * on each row (or vice versa, but it's more convenient to emit a row at
+ * a time).  Direct algorithms are also available, but they are much more
+ * complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on Arai, Agui, and Nakajima's algorithm for
+ * scaled DCT.  Their original paper (Trans. IEICE E-71(11):1095) is in
+ * Japanese, but the algorithm is described in the Pennebaker & Mitchell
+ * JPEG textbook (see REFERENCES section in file README).  The following code
+ * is based directly on figure 4-8 in P&M.
+ * While an 8-point DCT cannot be done in less than 11 multiplies, it is
+ * possible to arrange the computation so that many of the multiplies are
+ * simple scalings of the final outputs.  These multiplies can then be
+ * folded into the multiplications or divisions by the JPEG quantization
+ * table entries.  The AA&N method leaves only 5 multiplies and 29 adds
+ * to be done in the DCT itself.
+ * The primary disadvantage of this method is that with a fixed-point
+ * implementation, accuracy is lost due to imprecise representation of the
+ * scaled quantization values.  However, that problem does not arise if
+ * we use floating point arithmetic.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h"		/* Private declarations for DCT subsystem */
+
+#ifdef DCT_FLOAT_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+  Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/* Dequantize a coefficient by multiplying it by the multiplier-table
+ * entry; produce a float result.
+ */
+
+#define DEQUANTIZE(coef,quantval)  (((FAST_FLOAT) (coef)) * (quantval))
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients.
+ */
+
+GLOBAL(void)
+jpeg_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		 JCOEFPTR coef_block,
+		 JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+  FAST_FLOAT tmp10, tmp11, tmp12, tmp13;
+  FAST_FLOAT z5, z10, z11, z12, z13;
+  JCOEFPTR inptr;
+  FLOAT_MULT_TYPE * quantptr;
+  FAST_FLOAT * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = cinfo->sample_range_limit;
+  int ctr;
+  FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */
+
+  /* Pass 1: process columns from input, store into work array. */
+
+  inptr = coef_block;
+  quantptr = (FLOAT_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = DCTSIZE; ctr > 0; ctr--) {
+    /* Due to quantization, we will usually find that many of the input
+     * coefficients are zero, especially the AC terms.  We can exploit this
+     * by short-circuiting the IDCT calculation for any column in which all
+     * the AC terms are zero.  In that case each output is equal to the
+     * DC coefficient (with scale factor as needed).
+     * With typical images and quantization tables, half or more of the
+     * column DCT calculations can be simplified this way.
+     */
+    
+    if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
+	inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
+	inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
+	inptr[DCTSIZE*7] == 0) {
+      /* AC terms all zero */
+      FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+      
+      wsptr[DCTSIZE*0] = dcval;
+      wsptr[DCTSIZE*1] = dcval;
+      wsptr[DCTSIZE*2] = dcval;
+      wsptr[DCTSIZE*3] = dcval;
+      wsptr[DCTSIZE*4] = dcval;
+      wsptr[DCTSIZE*5] = dcval;
+      wsptr[DCTSIZE*6] = dcval;
+      wsptr[DCTSIZE*7] = dcval;
+      
+      inptr++;			/* advance pointers to next column */
+      quantptr++;
+      wsptr++;
+      continue;
+    }
+    
+    /* Even part */
+
+    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+    tmp10 = tmp0 + tmp2;	/* phase 3 */
+    tmp11 = tmp0 - tmp2;
+
+    tmp13 = tmp1 + tmp3;	/* phases 5-3 */
+    tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */
+
+    tmp0 = tmp10 + tmp13;	/* phase 2 */
+    tmp3 = tmp10 - tmp13;
+    tmp1 = tmp11 + tmp12;
+    tmp2 = tmp11 - tmp12;
+    
+    /* Odd part */
+
+    tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+    z13 = tmp6 + tmp5;		/* phase 6 */
+    z10 = tmp6 - tmp5;
+    z11 = tmp4 + tmp7;
+    z12 = tmp4 - tmp7;
+
+    tmp7 = z11 + z13;		/* phase 5 */
+    tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */
+
+    z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
+    tmp10 = z5 - z12 * ((FAST_FLOAT) 1.082392200); /* 2*(c2-c6) */
+    tmp12 = z5 - z10 * ((FAST_FLOAT) 2.613125930); /* 2*(c2+c6) */
+
+    tmp6 = tmp12 - tmp7;	/* phase 2 */
+    tmp5 = tmp11 - tmp6;
+    tmp4 = tmp10 - tmp5;
+
+    wsptr[DCTSIZE*0] = tmp0 + tmp7;
+    wsptr[DCTSIZE*7] = tmp0 - tmp7;
+    wsptr[DCTSIZE*1] = tmp1 + tmp6;
+    wsptr[DCTSIZE*6] = tmp1 - tmp6;
+    wsptr[DCTSIZE*2] = tmp2 + tmp5;
+    wsptr[DCTSIZE*5] = tmp2 - tmp5;
+    wsptr[DCTSIZE*3] = tmp3 + tmp4;
+    wsptr[DCTSIZE*4] = tmp3 - tmp4;
+
+    inptr++;			/* advance pointers to next column */
+    quantptr++;
+    wsptr++;
+  }
+  
+  /* Pass 2: process rows from work array, store into output array. */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < DCTSIZE; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+    /* Rows of zeroes can be exploited in the same way as we did with columns.
+     * However, the column calculation has created many nonzero AC terms, so
+     * the simplification applies less often (typically 5% to 10% of the time).
+     * And testing floats for zero is relatively expensive, so we don't bother.
+     */
+    
+    /* Even part */
+
+    /* Apply signed->unsigned and prepare float->int conversion */
+    z5 = wsptr[0] + ((FAST_FLOAT) CENTERJSAMPLE + (FAST_FLOAT) 0.5);
+    tmp10 = z5 + wsptr[4];
+    tmp11 = z5 - wsptr[4];
+
+    tmp13 = wsptr[2] + wsptr[6];
+    tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13;
+
+    tmp0 = tmp10 + tmp13;
+    tmp3 = tmp10 - tmp13;
+    tmp1 = tmp11 + tmp12;
+    tmp2 = tmp11 - tmp12;
+
+    /* Odd part */
+
+    z13 = wsptr[5] + wsptr[3];
+    z10 = wsptr[5] - wsptr[3];
+    z11 = wsptr[1] + wsptr[7];
+    z12 = wsptr[1] - wsptr[7];
+
+    tmp7 = z11 + z13;
+    tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562);
+
+    z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
+    tmp10 = z5 - z12 * ((FAST_FLOAT) 1.082392200); /* 2*(c2-c6) */
+    tmp12 = z5 - z10 * ((FAST_FLOAT) 2.613125930); /* 2*(c2+c6) */
+
+    tmp6 = tmp12 - tmp7;
+    tmp5 = tmp11 - tmp6;
+    tmp4 = tmp10 - tmp5;
+
+    /* Final output stage: float->int conversion and range-limit */
+
+    outptr[0] = range_limit[((int) (tmp0 + tmp7)) & RANGE_MASK];
+    outptr[7] = range_limit[((int) (tmp0 - tmp7)) & RANGE_MASK];
+    outptr[1] = range_limit[((int) (tmp1 + tmp6)) & RANGE_MASK];
+    outptr[6] = range_limit[((int) (tmp1 - tmp6)) & RANGE_MASK];
+    outptr[2] = range_limit[((int) (tmp2 + tmp5)) & RANGE_MASK];
+    outptr[5] = range_limit[((int) (tmp2 - tmp5)) & RANGE_MASK];
+    outptr[3] = range_limit[((int) (tmp3 + tmp4)) & RANGE_MASK];
+    outptr[4] = range_limit[((int) (tmp3 - tmp4)) & RANGE_MASK];
+    
+    wsptr += DCTSIZE;		/* advance pointer to next row */
+  }
+}
+
+#endif /* DCT_FLOAT_SUPPORTED */
diff --git a/source/Irrlicht/jpeglib/jidctfst.c b/source/Irrlicht/jpeglib/jidctfst.c
new file mode 100644
index 00000000..078b8c44
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jidctfst.c
@@ -0,0 +1,368 @@
+/*
+ * jidctfst.c
+ *
+ * Copyright (C) 1994-1998, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a fast, not so accurate integer implementation of the
+ * inverse DCT (Discrete Cosine Transform).  In the IJG code, this routine
+ * must also perform dequantization of the input coefficients.
+ *
+ * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
+ * on each row (or vice versa, but it's more convenient to emit a row at
+ * a time).  Direct algorithms are also available, but they are much more
+ * complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on Arai, Agui, and Nakajima's algorithm for
+ * scaled DCT.  Their original paper (Trans. IEICE E-71(11):1095) is in
+ * Japanese, but the algorithm is described in the Pennebaker & Mitchell
+ * JPEG textbook (see REFERENCES section in file README).  The following code
+ * is based directly on figure 4-8 in P&M.
+ * While an 8-point DCT cannot be done in less than 11 multiplies, it is
+ * possible to arrange the computation so that many of the multiplies are
+ * simple scalings of the final outputs.  These multiplies can then be
+ * folded into the multiplications or divisions by the JPEG quantization
+ * table entries.  The AA&N method leaves only 5 multiplies and 29 adds
+ * to be done in the DCT itself.
+ * The primary disadvantage of this method is that with fixed-point math,
+ * accuracy is lost due to imprecise representation of the scaled
+ * quantization values.  The smaller the quantization table entry, the less
+ * precise the scaled value, so this implementation does worse with high-
+ * quality-setting files than with low-quality ones.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h"		/* Private declarations for DCT subsystem */
+
+#ifdef DCT_IFAST_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+  Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/* Scaling decisions are generally the same as in the LL&M algorithm;
+ * see jidctint.c for more details.  However, we choose to descale
+ * (right shift) multiplication products as soon as they are formed,
+ * rather than carrying additional fractional bits into subsequent additions.
+ * This compromises accuracy slightly, but it lets us save a few shifts.
+ * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples)
+ * everywhere except in the multiplications proper; this saves a good deal
+ * of work on 16-bit-int machines.
+ *
+ * The dequantized coefficients are not integers because the AA&N scaling
+ * factors have been incorporated.  We represent them scaled up by PASS1_BITS,
+ * so that the first and second IDCT rounds have the same input scaling.
+ * For 8-bit JSAMPLEs, we choose IFAST_SCALE_BITS = PASS1_BITS so as to
+ * avoid a descaling shift; this compromises accuracy rather drastically
+ * for small quantization table entries, but it saves a lot of shifts.
+ * For 12-bit JSAMPLEs, there's no hope of using 16x16 multiplies anyway,
+ * so we use a much larger scaling factor to preserve accuracy.
+ *
+ * A final compromise is to represent the multiplicative constants to only
+ * 8 fractional bits, rather than 13.  This saves some shifting work on some
+ * machines, and may also reduce the cost of multiplication (since there
+ * are fewer one-bits in the constants).
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define CONST_BITS  8
+#define PASS1_BITS  2
+#else
+#define CONST_BITS  8
+#define PASS1_BITS  1		/* lose a little precision to avoid overflow */
+#endif
+
+/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
+ * causing a lot of useless floating-point operations at run time.
+ * To get around this we use the following pre-calculated constants.
+ * If you change CONST_BITS you may want to add appropriate values.
+ * (With a reasonable C compiler, you can just rely on the FIX() macro...)
+ */
+
+#if CONST_BITS == 8
+#define FIX_1_082392200  ((INT32)  277)		/* FIX(1.082392200) */
+#define FIX_1_414213562  ((INT32)  362)		/* FIX(1.414213562) */
+#define FIX_1_847759065  ((INT32)  473)		/* FIX(1.847759065) */
+#define FIX_2_613125930  ((INT32)  669)		/* FIX(2.613125930) */
+#else
+#define FIX_1_082392200  FIX(1.082392200)
+#define FIX_1_414213562  FIX(1.414213562)
+#define FIX_1_847759065  FIX(1.847759065)
+#define FIX_2_613125930  FIX(2.613125930)
+#endif
+
+
+/* We can gain a little more speed, with a further compromise in accuracy,
+ * by omitting the addition in a descaling shift.  This yields an incorrectly
+ * rounded result half the time...
+ */
+
+#ifndef USE_ACCURATE_ROUNDING
+#undef DESCALE
+#define DESCALE(x,n)  RIGHT_SHIFT(x, n)
+#endif
+
+
+/* Multiply a DCTELEM variable by an INT32 constant, and immediately
+ * descale to yield a DCTELEM result.
+ */
+
+#define MULTIPLY(var,const)  ((DCTELEM) DESCALE((var) * (const), CONST_BITS))
+
+
+/* Dequantize a coefficient by multiplying it by the multiplier-table
+ * entry; produce a DCTELEM result.  For 8-bit data a 16x16->16
+ * multiplication will do.  For 12-bit data, the multiplier table is
+ * declared INT32, so a 32-bit multiply will be used.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define DEQUANTIZE(coef,quantval)  (((IFAST_MULT_TYPE) (coef)) * (quantval))
+#else
+#define DEQUANTIZE(coef,quantval)  \
+	DESCALE((coef)*(quantval), IFAST_SCALE_BITS-PASS1_BITS)
+#endif
+
+
+/* Like DESCALE, but applies to a DCTELEM and produces an int.
+ * We assume that int right shift is unsigned if INT32 right shift is.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define ISHIFT_TEMPS	DCTELEM ishift_temp;
+#if BITS_IN_JSAMPLE == 8
+#define DCTELEMBITS  16		/* DCTELEM may be 16 or 32 bits */
+#else
+#define DCTELEMBITS  32		/* DCTELEM must be 32 bits */
+#endif
+#define IRIGHT_SHIFT(x,shft)  \
+    ((ishift_temp = (x)) < 0 ? \
+     (ishift_temp >> (shft)) | ((~((DCTELEM) 0)) << (DCTELEMBITS-(shft))) : \
+     (ishift_temp >> (shft)))
+#else
+#define ISHIFT_TEMPS
+#define IRIGHT_SHIFT(x,shft)	((x) >> (shft))
+#endif
+
+#ifdef USE_ACCURATE_ROUNDING
+#define IDESCALE(x,n)  ((int) IRIGHT_SHIFT((x) + (1 << ((n)-1)), n))
+#else
+#define IDESCALE(x,n)  ((int) IRIGHT_SHIFT(x, n))
+#endif
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients.
+ */
+
+GLOBAL(void)
+jpeg_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		 JCOEFPTR coef_block,
+		 JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+  DCTELEM tmp10, tmp11, tmp12, tmp13;
+  DCTELEM z5, z10, z11, z12, z13;
+  JCOEFPTR inptr;
+  IFAST_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[DCTSIZE2];	/* buffers data between passes */
+  SHIFT_TEMPS			/* for DESCALE */
+  ISHIFT_TEMPS			/* for IDESCALE */
+
+  /* Pass 1: process columns from input, store into work array. */
+
+  inptr = coef_block;
+  quantptr = (IFAST_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = DCTSIZE; ctr > 0; ctr--) {
+    /* Due to quantization, we will usually find that many of the input
+     * coefficients are zero, especially the AC terms.  We can exploit this
+     * by short-circuiting the IDCT calculation for any column in which all
+     * the AC terms are zero.  In that case each output is equal to the
+     * DC coefficient (with scale factor as needed).
+     * With typical images and quantization tables, half or more of the
+     * column DCT calculations can be simplified this way.
+     */
+    
+    if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
+	inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
+	inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
+	inptr[DCTSIZE*7] == 0) {
+      /* AC terms all zero */
+      int dcval = (int) DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+
+      wsptr[DCTSIZE*0] = dcval;
+      wsptr[DCTSIZE*1] = dcval;
+      wsptr[DCTSIZE*2] = dcval;
+      wsptr[DCTSIZE*3] = dcval;
+      wsptr[DCTSIZE*4] = dcval;
+      wsptr[DCTSIZE*5] = dcval;
+      wsptr[DCTSIZE*6] = dcval;
+      wsptr[DCTSIZE*7] = dcval;
+      
+      inptr++;			/* advance pointers to next column */
+      quantptr++;
+      wsptr++;
+      continue;
+    }
+    
+    /* Even part */
+
+    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+    tmp10 = tmp0 + tmp2;	/* phase 3 */
+    tmp11 = tmp0 - tmp2;
+
+    tmp13 = tmp1 + tmp3;	/* phases 5-3 */
+    tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */
+
+    tmp0 = tmp10 + tmp13;	/* phase 2 */
+    tmp3 = tmp10 - tmp13;
+    tmp1 = tmp11 + tmp12;
+    tmp2 = tmp11 - tmp12;
+    
+    /* Odd part */
+
+    tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+    z13 = tmp6 + tmp5;		/* phase 6 */
+    z10 = tmp6 - tmp5;
+    z11 = tmp4 + tmp7;
+    z12 = tmp4 - tmp7;
+
+    tmp7 = z11 + z13;		/* phase 5 */
+    tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
+
+    z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */
+    tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */
+    tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */
+
+    tmp6 = tmp12 - tmp7;	/* phase 2 */
+    tmp5 = tmp11 - tmp6;
+    tmp4 = tmp10 + tmp5;
+
+    wsptr[DCTSIZE*0] = (int) (tmp0 + tmp7);
+    wsptr[DCTSIZE*7] = (int) (tmp0 - tmp7);
+    wsptr[DCTSIZE*1] = (int) (tmp1 + tmp6);
+    wsptr[DCTSIZE*6] = (int) (tmp1 - tmp6);
+    wsptr[DCTSIZE*2] = (int) (tmp2 + tmp5);
+    wsptr[DCTSIZE*5] = (int) (tmp2 - tmp5);
+    wsptr[DCTSIZE*4] = (int) (tmp3 + tmp4);
+    wsptr[DCTSIZE*3] = (int) (tmp3 - tmp4);
+
+    inptr++;			/* advance pointers to next column */
+    quantptr++;
+    wsptr++;
+  }
+  
+  /* Pass 2: process rows from work array, store into output array. */
+  /* Note that we must descale the results by a factor of 8 == 2**3, */
+  /* and also undo the PASS1_BITS scaling. */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < DCTSIZE; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+    /* Rows of zeroes can be exploited in the same way as we did with columns.
+     * However, the column calculation has created many nonzero AC terms, so
+     * the simplification applies less often (typically 5% to 10% of the time).
+     * On machines with very fast multiplication, it's possible that the
+     * test takes more time than it's worth.  In that case this section
+     * may be commented out.
+     */
+    
+#ifndef NO_ZERO_ROW_TEST
+    if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 &&
+	wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) {
+      /* AC terms all zero */
+      JSAMPLE dcval = range_limit[IDESCALE(wsptr[0], PASS1_BITS+3)
+				  & RANGE_MASK];
+      
+      outptr[0] = dcval;
+      outptr[1] = dcval;
+      outptr[2] = dcval;
+      outptr[3] = dcval;
+      outptr[4] = dcval;
+      outptr[5] = dcval;
+      outptr[6] = dcval;
+      outptr[7] = dcval;
+
+      wsptr += DCTSIZE;		/* advance pointer to next row */
+      continue;
+    }
+#endif
+    
+    /* Even part */
+
+    tmp10 = ((DCTELEM) wsptr[0] + (DCTELEM) wsptr[4]);
+    tmp11 = ((DCTELEM) wsptr[0] - (DCTELEM) wsptr[4]);
+
+    tmp13 = ((DCTELEM) wsptr[2] + (DCTELEM) wsptr[6]);
+    tmp12 = MULTIPLY((DCTELEM) wsptr[2] - (DCTELEM) wsptr[6], FIX_1_414213562)
+	    - tmp13;
+
+    tmp0 = tmp10 + tmp13;
+    tmp3 = tmp10 - tmp13;
+    tmp1 = tmp11 + tmp12;
+    tmp2 = tmp11 - tmp12;
+
+    /* Odd part */
+
+    z13 = (DCTELEM) wsptr[5] + (DCTELEM) wsptr[3];
+    z10 = (DCTELEM) wsptr[5] - (DCTELEM) wsptr[3];
+    z11 = (DCTELEM) wsptr[1] + (DCTELEM) wsptr[7];
+    z12 = (DCTELEM) wsptr[1] - (DCTELEM) wsptr[7];
+
+    tmp7 = z11 + z13;		/* phase 5 */
+    tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
+
+    z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */
+    tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */
+    tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */
+
+    tmp6 = tmp12 - tmp7;	/* phase 2 */
+    tmp5 = tmp11 - tmp6;
+    tmp4 = tmp10 + tmp5;
+
+    /* Final output stage: scale down by a factor of 8 and range-limit */
+
+    outptr[0] = range_limit[IDESCALE(tmp0 + tmp7, PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[7] = range_limit[IDESCALE(tmp0 - tmp7, PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[IDESCALE(tmp1 + tmp6, PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[6] = range_limit[IDESCALE(tmp1 - tmp6, PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[2] = range_limit[IDESCALE(tmp2 + tmp5, PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[5] = range_limit[IDESCALE(tmp2 - tmp5, PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[4] = range_limit[IDESCALE(tmp3 + tmp4, PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[3] = range_limit[IDESCALE(tmp3 - tmp4, PASS1_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += DCTSIZE;		/* advance pointer to next row */
+  }
+}
+
+#endif /* DCT_IFAST_SUPPORTED */
diff --git a/source/Irrlicht/jpeglib/jidctint.c b/source/Irrlicht/jpeglib/jidctint.c
new file mode 100644
index 00000000..6be271c6
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jidctint.c
@@ -0,0 +1,5179 @@
+/*
+ * jidctint.c
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Modification developed 2002-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a slow-but-accurate integer implementation of the
+ * inverse DCT (Discrete Cosine Transform).  In the IJG code, this routine
+ * must also perform dequantization of the input coefficients.
+ *
+ * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
+ * on each row (or vice versa, but it's more convenient to emit a row at
+ * a time).  Direct algorithms are also available, but they are much more
+ * complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on an algorithm described in
+ *   C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT
+ *   Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics,
+ *   Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.
+ * The primary algorithm described there uses 11 multiplies and 29 adds.
+ * We use their alternate method with 12 multiplies and 32 adds.
+ * The advantage of this method is that no data path contains more than one
+ * multiplication; this allows a very simple and accurate implementation in
+ * scaled fixed-point arithmetic, with a minimal number of shifts.
+ *
+ * We also provide IDCT routines with various output sample block sizes for
+ * direct resolution reduction or enlargement and for direct resolving the
+ * common 2x1 and 1x2 subsampling cases without additional resampling: NxN
+ * (N=1...16), 2NxN, and Nx2N (N=1...8) pixels for one 8x8 input DCT block.
+ *
+ * For N<8 we simply take the corresponding low-frequency coefficients of
+ * the 8x8 input DCT block and apply an NxN point IDCT on the sub-block
+ * to yield the downscaled outputs.
+ * This can be seen as direct low-pass downsampling from the DCT domain
+ * point of view rather than the usual spatial domain point of view,
+ * yielding significant computational savings and results at least
+ * as good as common bilinear (averaging) spatial downsampling.
+ *
+ * For N>8 we apply a partial NxN IDCT on the 8 input coefficients as
+ * lower frequencies and higher frequencies assumed to be zero.
+ * It turns out that the computational effort is similar to the 8x8 IDCT
+ * regarding the output size.
+ * Furthermore, the scaling and descaling is the same for all IDCT sizes.
+ *
+ * CAUTION: We rely on the FIX() macro except for the N=1,2,4,8 cases
+ * since there would be too many additional constants to pre-calculate.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h"		/* Private declarations for DCT subsystem */
+
+#ifdef DCT_ISLOW_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+  Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */
+#endif
+
+
+/*
+ * The poop on this scaling stuff is as follows:
+ *
+ * Each 1-D IDCT step produces outputs which are a factor of sqrt(N)
+ * larger than the true IDCT outputs.  The final outputs are therefore
+ * a factor of N larger than desired; since N=8 this can be cured by
+ * a simple right shift at the end of the algorithm.  The advantage of
+ * this arrangement is that we save two multiplications per 1-D IDCT,
+ * because the y0 and y4 inputs need not be divided by sqrt(N).
+ *
+ * We have to do addition and subtraction of the integer inputs, which
+ * is no problem, and multiplication by fractional constants, which is
+ * a problem to do in integer arithmetic.  We multiply all the constants
+ * by CONST_SCALE and convert them to integer constants (thus retaining
+ * CONST_BITS bits of precision in the constants).  After doing a
+ * multiplication we have to divide the product by CONST_SCALE, with proper
+ * rounding, to produce the correct output.  This division can be done
+ * cheaply as a right shift of CONST_BITS bits.  We postpone shifting
+ * as long as possible so that partial sums can be added together with
+ * full fractional precision.
+ *
+ * The outputs of the first pass are scaled up by PASS1_BITS bits so that
+ * they are represented to better-than-integral precision.  These outputs
+ * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word
+ * with the recommended scaling.  (To scale up 12-bit sample data further, an
+ * intermediate INT32 array would be needed.)
+ *
+ * To avoid overflow of the 32-bit intermediate results in pass 2, we must
+ * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26.  Error analysis
+ * shows that the values given below are the most effective.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define CONST_BITS  13
+#define PASS1_BITS  2
+#else
+#define CONST_BITS  13
+#define PASS1_BITS  1		/* lose a little precision to avoid overflow */
+#endif
+
+/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
+ * causing a lot of useless floating-point operations at run time.
+ * To get around this we use the following pre-calculated constants.
+ * If you change CONST_BITS you may want to add appropriate values.
+ * (With a reasonable C compiler, you can just rely on the FIX() macro...)
+ */
+
+#if CONST_BITS == 13
+#define FIX_0_298631336  ((INT32)  2446)	/* FIX(0.298631336) */
+#define FIX_0_390180644  ((INT32)  3196)	/* FIX(0.390180644) */
+#define FIX_0_541196100  ((INT32)  4433)	/* FIX(0.541196100) */
+#define FIX_0_765366865  ((INT32)  6270)	/* FIX(0.765366865) */
+#define FIX_0_899976223  ((INT32)  7373)	/* FIX(0.899976223) */
+#define FIX_1_175875602  ((INT32)  9633)	/* FIX(1.175875602) */
+#define FIX_1_501321110  ((INT32)  12299)	/* FIX(1.501321110) */
+#define FIX_1_847759065  ((INT32)  15137)	/* FIX(1.847759065) */
+#define FIX_1_961570560  ((INT32)  16069)	/* FIX(1.961570560) */
+#define FIX_2_053119869  ((INT32)  16819)	/* FIX(2.053119869) */
+#define FIX_2_562915447  ((INT32)  20995)	/* FIX(2.562915447) */
+#define FIX_3_072711026  ((INT32)  25172)	/* FIX(3.072711026) */
+#else
+#define FIX_0_298631336  FIX(0.298631336)
+#define FIX_0_390180644  FIX(0.390180644)
+#define FIX_0_541196100  FIX(0.541196100)
+#define FIX_0_765366865  FIX(0.765366865)
+#define FIX_0_899976223  FIX(0.899976223)
+#define FIX_1_175875602  FIX(1.175875602)
+#define FIX_1_501321110  FIX(1.501321110)
+#define FIX_1_847759065  FIX(1.847759065)
+#define FIX_1_961570560  FIX(1.961570560)
+#define FIX_2_053119869  FIX(2.053119869)
+#define FIX_2_562915447  FIX(2.562915447)
+#define FIX_3_072711026  FIX(3.072711026)
+#endif
+
+
+/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
+ * For 8-bit samples with the recommended scaling, all the variable
+ * and constant values involved are no more than 16 bits wide, so a
+ * 16x16->32 bit multiply can be used instead of a full 32x32 multiply.
+ * For 12-bit samples, a full 32-bit multiplication will be needed.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define MULTIPLY(var,const)  MULTIPLY16C16(var,const)
+#else
+#define MULTIPLY(var,const)  ((var) * (const))
+#endif
+
+
+/* Dequantize a coefficient by multiplying it by the multiplier-table
+ * entry; produce an int result.  In this module, both inputs and result
+ * are 16 bits or less, so either int or short multiply will work.
+ */
+
+#define DEQUANTIZE(coef,quantval)  (((ISLOW_MULT_TYPE) (coef)) * (quantval))
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients.
+ *
+ * cK represents sqrt(2) * cos(K*pi/16).
+ */
+
+GLOBAL(void)
+jpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		 JCOEFPTR coef_block,
+		 JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3;
+  INT32 tmp10, tmp11, tmp12, tmp13;
+  INT32 z1, z2, z3;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[DCTSIZE2];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array.
+   * Note results are scaled up by sqrt(8) compared to a true IDCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = DCTSIZE; ctr > 0; ctr--) {
+    /* Due to quantization, we will usually find that many of the input
+     * coefficients are zero, especially the AC terms.  We can exploit this
+     * by short-circuiting the IDCT calculation for any column in which all
+     * the AC terms are zero.  In that case each output is equal to the
+     * DC coefficient (with scale factor as needed).
+     * With typical images and quantization tables, half or more of the
+     * column DCT calculations can be simplified this way.
+     */
+
+    if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
+	inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
+	inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
+	inptr[DCTSIZE*7] == 0) {
+      /* AC terms all zero */
+      int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;
+
+      wsptr[DCTSIZE*0] = dcval;
+      wsptr[DCTSIZE*1] = dcval;
+      wsptr[DCTSIZE*2] = dcval;
+      wsptr[DCTSIZE*3] = dcval;
+      wsptr[DCTSIZE*4] = dcval;
+      wsptr[DCTSIZE*5] = dcval;
+      wsptr[DCTSIZE*6] = dcval;
+      wsptr[DCTSIZE*7] = dcval;
+
+      inptr++;			/* advance pointers to next column */
+      quantptr++;
+      wsptr++;
+      continue;
+    }
+
+    /* Even part: reverse the even part of the forward DCT.
+     * The rotator is c(-6).
+     */
+
+    z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);       /* c6 */
+    tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);     /* c2-c6 */
+    tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);     /* c2+c6 */
+
+    z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    z2 <<= CONST_BITS;
+    z3 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    z2 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+    tmp0 = z2 + z3;
+    tmp1 = z2 - z3;
+
+    tmp10 = tmp0 + tmp2;
+    tmp13 = tmp0 - tmp2;
+    tmp11 = tmp1 + tmp3;
+    tmp12 = tmp1 - tmp3;
+
+    /* Odd part per figure 8; the matrix is unitary and hence its
+     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.
+     */
+
+    tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+    tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+
+    z2 = tmp0 + tmp2;
+    z3 = tmp1 + tmp3;
+
+    z1 = MULTIPLY(z2 + z3, FIX_1_175875602);       /*  c3 */
+    z2 = MULTIPLY(z2, - FIX_1_961570560);          /* -c3-c5 */
+    z3 = MULTIPLY(z3, - FIX_0_390180644);          /* -c3+c5 */
+    z2 += z1;
+    z3 += z1;
+
+    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */
+    tmp0 = MULTIPLY(tmp0, FIX_0_298631336);        /* -c1+c3+c5-c7 */
+    tmp3 = MULTIPLY(tmp3, FIX_1_501321110);        /*  c1+c3-c5-c7 */
+    tmp0 += z1 + z2;
+    tmp3 += z1 + z3;
+
+    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */
+    tmp1 = MULTIPLY(tmp1, FIX_2_053119869);        /*  c1+c3-c5+c7 */
+    tmp2 = MULTIPLY(tmp2, FIX_3_072711026);        /*  c1+c3+c5-c7 */
+    tmp1 += z1 + z3;
+    tmp2 += z1 + z2;
+
+    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+    wsptr[DCTSIZE*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS);
+    wsptr[DCTSIZE*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS);
+    wsptr[DCTSIZE*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS);
+    wsptr[DCTSIZE*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS);
+    wsptr[DCTSIZE*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS);
+    wsptr[DCTSIZE*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS);
+    wsptr[DCTSIZE*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS);
+    wsptr[DCTSIZE*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS);
+
+    inptr++;			/* advance pointers to next column */
+    quantptr++;
+    wsptr++;
+  }
+
+  /* Pass 2: process rows from work array, store into output array.
+   * Note that we must descale the results by a factor of 8 == 2**3,
+   * and also undo the PASS1_BITS scaling.
+   */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < DCTSIZE; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+    /* Rows of zeroes can be exploited in the same way as we did with columns.
+     * However, the column calculation has created many nonzero AC terms, so
+     * the simplification applies less often (typically 5% to 10% of the time).
+     * On machines with very fast multiplication, it's possible that the
+     * test takes more time than it's worth.  In that case this section
+     * may be commented out.
+     */
+
+#ifndef NO_ZERO_ROW_TEST
+    if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 &&
+	wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) {
+      /* AC terms all zero */
+      JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3)
+				  & RANGE_MASK];
+
+      outptr[0] = dcval;
+      outptr[1] = dcval;
+      outptr[2] = dcval;
+      outptr[3] = dcval;
+      outptr[4] = dcval;
+      outptr[5] = dcval;
+      outptr[6] = dcval;
+      outptr[7] = dcval;
+
+      wsptr += DCTSIZE;		/* advance pointer to next row */
+      continue;
+    }
+#endif
+
+    /* Even part: reverse the even part of the forward DCT.
+     * The rotator is c(-6).
+     */
+
+    z2 = (INT32) wsptr[2];
+    z3 = (INT32) wsptr[6];
+
+    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);       /* c6 */
+    tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);     /* c2-c6 */
+    tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);     /* c2+c6 */
+
+    /* Add fudge factor here for final descale. */
+    z2 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    z3 = (INT32) wsptr[4];
+
+    tmp0 = (z2 + z3) << CONST_BITS;
+    tmp1 = (z2 - z3) << CONST_BITS;
+
+    tmp10 = tmp0 + tmp2;
+    tmp13 = tmp0 - tmp2;
+    tmp11 = tmp1 + tmp3;
+    tmp12 = tmp1 - tmp3;
+
+    /* Odd part per figure 8; the matrix is unitary and hence its
+     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.
+     */
+
+    tmp0 = (INT32) wsptr[7];
+    tmp1 = (INT32) wsptr[5];
+    tmp2 = (INT32) wsptr[3];
+    tmp3 = (INT32) wsptr[1];
+
+    z2 = tmp0 + tmp2;
+    z3 = tmp1 + tmp3;
+
+    z1 = MULTIPLY(z2 + z3, FIX_1_175875602);       /*  c3 */
+    z2 = MULTIPLY(z2, - FIX_1_961570560);          /* -c3-c5 */
+    z3 = MULTIPLY(z3, - FIX_0_390180644);          /* -c3+c5 */
+    z2 += z1;
+    z3 += z1;
+
+    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */
+    tmp0 = MULTIPLY(tmp0, FIX_0_298631336);        /* -c1+c3+c5-c7 */
+    tmp3 = MULTIPLY(tmp3, FIX_1_501321110);        /*  c1+c3-c5-c7 */
+    tmp0 += z1 + z2;
+    tmp3 += z1 + z3;
+
+    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */
+    tmp1 = MULTIPLY(tmp1, FIX_2_053119869);        /*  c1+c3-c5+c7 */
+    tmp2 = MULTIPLY(tmp2, FIX_3_072711026);        /*  c1+c3+c5-c7 */
+    tmp1 += z1 + z3;
+    tmp2 += z1 + z2;
+
+    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += DCTSIZE;		/* advance pointer to next row */
+  }
+}
+
+#ifdef IDCT_SCALING_SUPPORTED
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 7x7 output block.
+ *
+ * Optimized algorithm with 12 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/14).
+ */
+
+GLOBAL(void)
+jpeg_idct_7x7 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	       JCOEFPTR coef_block,
+	       JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12, tmp13;
+  INT32 z1, z2, z3;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[7*7];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array. */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 7; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    tmp13 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    tmp13 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    tmp13 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+    tmp10 = MULTIPLY(z2 - z3, FIX(0.881747734));     /* c4 */
+    tmp12 = MULTIPLY(z1 - z2, FIX(0.314692123));     /* c6 */
+    tmp11 = tmp10 + tmp12 + tmp13 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */
+    tmp0 = z1 + z3;
+    z2 -= tmp0;
+    tmp0 = MULTIPLY(tmp0, FIX(1.274162392)) + tmp13; /* c2 */
+    tmp10 += tmp0 - MULTIPLY(z3, FIX(0.077722536));  /* c2-c4-c6 */
+    tmp12 += tmp0 - MULTIPLY(z1, FIX(2.470602249));  /* c2+c4+c6 */
+    tmp13 += MULTIPLY(z2, FIX(1.414213562));         /* c0 */
+
+    /* Odd part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+
+    tmp1 = MULTIPLY(z1 + z2, FIX(0.935414347));      /* (c3+c1-c5)/2 */
+    tmp2 = MULTIPLY(z1 - z2, FIX(0.170262339));      /* (c3+c5-c1)/2 */
+    tmp0 = tmp1 - tmp2;
+    tmp1 += tmp2;
+    tmp2 = MULTIPLY(z2 + z3, - FIX(1.378756276));    /* -c1 */
+    tmp1 += tmp2;
+    z2 = MULTIPLY(z1 + z3, FIX(0.613604268));        /* c5 */
+    tmp0 += z2;
+    tmp2 += z2 + MULTIPLY(z3, FIX(1.870828693));     /* c3+c1-c5 */
+
+    /* Final output stage */
+
+    wsptr[7*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+    wsptr[7*6] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+    wsptr[7*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS);
+    wsptr[7*5] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS);
+    wsptr[7*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS);
+    wsptr[7*4] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS);
+    wsptr[7*3] = (int) RIGHT_SHIFT(tmp13, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process 7 rows from work array, store into output array. */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 7; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp13 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    tmp13 <<= CONST_BITS;
+
+    z1 = (INT32) wsptr[2];
+    z2 = (INT32) wsptr[4];
+    z3 = (INT32) wsptr[6];
+
+    tmp10 = MULTIPLY(z2 - z3, FIX(0.881747734));     /* c4 */
+    tmp12 = MULTIPLY(z1 - z2, FIX(0.314692123));     /* c6 */
+    tmp11 = tmp10 + tmp12 + tmp13 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */
+    tmp0 = z1 + z3;
+    z2 -= tmp0;
+    tmp0 = MULTIPLY(tmp0, FIX(1.274162392)) + tmp13; /* c2 */
+    tmp10 += tmp0 - MULTIPLY(z3, FIX(0.077722536));  /* c2-c4-c6 */
+    tmp12 += tmp0 - MULTIPLY(z1, FIX(2.470602249));  /* c2+c4+c6 */
+    tmp13 += MULTIPLY(z2, FIX(1.414213562));         /* c0 */
+
+    /* Odd part */
+
+    z1 = (INT32) wsptr[1];
+    z2 = (INT32) wsptr[3];
+    z3 = (INT32) wsptr[5];
+
+    tmp1 = MULTIPLY(z1 + z2, FIX(0.935414347));      /* (c3+c1-c5)/2 */
+    tmp2 = MULTIPLY(z1 - z2, FIX(0.170262339));      /* (c3+c5-c1)/2 */
+    tmp0 = tmp1 - tmp2;
+    tmp1 += tmp2;
+    tmp2 = MULTIPLY(z2 + z3, - FIX(1.378756276));    /* -c1 */
+    tmp1 += tmp2;
+    z2 = MULTIPLY(z1 + z3, FIX(0.613604268));        /* c5 */
+    tmp0 += z2;
+    tmp2 += z2 + MULTIPLY(z3, FIX(1.870828693));     /* c3+c1-c5 */
+
+    /* Final output stage */
+
+    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += 7;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 6x6 output block.
+ *
+ * Optimized algorithm with 3 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/12).
+ */
+
+GLOBAL(void)
+jpeg_idct_6x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	       JCOEFPTR coef_block,
+	       JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12;
+  INT32 z1, z2, z3;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[6*6];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array. */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    tmp0 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);
+    tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    tmp10 = MULTIPLY(tmp2, FIX(0.707106781));   /* c4 */
+    tmp1 = tmp0 + tmp10;
+    tmp11 = RIGHT_SHIFT(tmp0 - tmp10 - tmp10, CONST_BITS-PASS1_BITS);
+    tmp10 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    tmp0 = MULTIPLY(tmp10, FIX(1.224744871));   /* c2 */
+    tmp10 = tmp1 + tmp0;
+    tmp12 = tmp1 - tmp0;
+
+    /* Odd part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */
+    tmp0 = tmp1 + ((z1 + z2) << CONST_BITS);
+    tmp2 = tmp1 + ((z3 - z2) << CONST_BITS);
+    tmp1 = (z1 - z2 - z3) << PASS1_BITS;
+
+    /* Final output stage */
+
+    wsptr[6*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+    wsptr[6*5] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+    wsptr[6*1] = (int) (tmp11 + tmp1);
+    wsptr[6*4] = (int) (tmp11 - tmp1);
+    wsptr[6*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS);
+    wsptr[6*3] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process 6 rows from work array, store into output array. */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 6; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    tmp0 <<= CONST_BITS;
+    tmp2 = (INT32) wsptr[4];
+    tmp10 = MULTIPLY(tmp2, FIX(0.707106781));   /* c4 */
+    tmp1 = tmp0 + tmp10;
+    tmp11 = tmp0 - tmp10 - tmp10;
+    tmp10 = (INT32) wsptr[2];
+    tmp0 = MULTIPLY(tmp10, FIX(1.224744871));   /* c2 */
+    tmp10 = tmp1 + tmp0;
+    tmp12 = tmp1 - tmp0;
+
+    /* Odd part */
+
+    z1 = (INT32) wsptr[1];
+    z2 = (INT32) wsptr[3];
+    z3 = (INT32) wsptr[5];
+    tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */
+    tmp0 = tmp1 + ((z1 + z2) << CONST_BITS);
+    tmp2 = tmp1 + ((z3 - z2) << CONST_BITS);
+    tmp1 = (z1 - z2 - z3) << CONST_BITS;
+
+    /* Final output stage */
+
+    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += 6;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 5x5 output block.
+ *
+ * Optimized algorithm with 5 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/10).
+ */
+
+GLOBAL(void)
+jpeg_idct_5x5 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	       JCOEFPTR coef_block,
+	       JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp0, tmp1, tmp10, tmp11, tmp12;
+  INT32 z1, z2, z3;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[5*5];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array. */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 5; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    tmp12 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    tmp12 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    tmp12 += ONE << (CONST_BITS-PASS1_BITS-1);
+    tmp0 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    tmp1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    z1 = MULTIPLY(tmp0 + tmp1, FIX(0.790569415)); /* (c2+c4)/2 */
+    z2 = MULTIPLY(tmp0 - tmp1, FIX(0.353553391)); /* (c2-c4)/2 */
+    z3 = tmp12 + z2;
+    tmp10 = z3 + z1;
+    tmp11 = z3 - z1;
+    tmp12 -= z2 << 2;
+
+    /* Odd part */
+
+    z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+
+    z1 = MULTIPLY(z2 + z3, FIX(0.831253876));     /* c3 */
+    tmp0 = z1 + MULTIPLY(z2, FIX(0.513743148));   /* c1-c3 */
+    tmp1 = z1 - MULTIPLY(z3, FIX(2.176250899));   /* c1+c3 */
+
+    /* Final output stage */
+
+    wsptr[5*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+    wsptr[5*4] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+    wsptr[5*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS);
+    wsptr[5*3] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS);
+    wsptr[5*2] = (int) RIGHT_SHIFT(tmp12, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process 5 rows from work array, store into output array. */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 5; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp12 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    tmp12 <<= CONST_BITS;
+    tmp0 = (INT32) wsptr[2];
+    tmp1 = (INT32) wsptr[4];
+    z1 = MULTIPLY(tmp0 + tmp1, FIX(0.790569415)); /* (c2+c4)/2 */
+    z2 = MULTIPLY(tmp0 - tmp1, FIX(0.353553391)); /* (c2-c4)/2 */
+    z3 = tmp12 + z2;
+    tmp10 = z3 + z1;
+    tmp11 = z3 - z1;
+    tmp12 -= z2 << 2;
+
+    /* Odd part */
+
+    z2 = (INT32) wsptr[1];
+    z3 = (INT32) wsptr[3];
+
+    z1 = MULTIPLY(z2 + z3, FIX(0.831253876));     /* c3 */
+    tmp0 = z1 + MULTIPLY(z2, FIX(0.513743148));   /* c1-c3 */
+    tmp1 = z1 - MULTIPLY(z3, FIX(2.176250899));   /* c1+c3 */
+
+    /* Final output stage */
+
+    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += 5;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 4x4 output block.
+ *
+ * Optimized algorithm with 3 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT].
+ */
+
+GLOBAL(void)
+jpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	       JCOEFPTR coef_block,
+	       JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp0, tmp2, tmp10, tmp12;
+  INT32 z1, z2, z3;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[4*4];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array. */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 4; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    
+    tmp10 = (tmp0 + tmp2) << PASS1_BITS;
+    tmp12 = (tmp0 - tmp2) << PASS1_BITS;
+
+    /* Odd part */
+    /* Same rotation as in the even part of the 8x8 LL&M IDCT */
+
+    z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+
+    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);               /* c6 */
+    /* Add fudge factor here for final descale. */
+    z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+    tmp0 = RIGHT_SHIFT(z1 + MULTIPLY(z2, FIX_0_765366865), /* c2-c6 */
+		       CONST_BITS-PASS1_BITS);
+    tmp2 = RIGHT_SHIFT(z1 - MULTIPLY(z3, FIX_1_847759065), /* c2+c6 */
+		       CONST_BITS-PASS1_BITS);
+
+    /* Final output stage */
+
+    wsptr[4*0] = (int) (tmp10 + tmp0);
+    wsptr[4*3] = (int) (tmp10 - tmp0);
+    wsptr[4*1] = (int) (tmp12 + tmp2);
+    wsptr[4*2] = (int) (tmp12 - tmp2);
+  }
+
+  /* Pass 2: process 4 rows from work array, store into output array. */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 4; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    tmp2 = (INT32) wsptr[2];
+
+    tmp10 = (tmp0 + tmp2) << CONST_BITS;
+    tmp12 = (tmp0 - tmp2) << CONST_BITS;
+
+    /* Odd part */
+    /* Same rotation as in the even part of the 8x8 LL&M IDCT */
+
+    z2 = (INT32) wsptr[1];
+    z3 = (INT32) wsptr[3];
+
+    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);   /* c6 */
+    tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */
+    tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */
+
+    /* Final output stage */
+
+    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += 4;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 3x3 output block.
+ *
+ * Optimized algorithm with 2 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/6).
+ */
+
+GLOBAL(void)
+jpeg_idct_3x3 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	       JCOEFPTR coef_block,
+	       JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp0, tmp2, tmp10, tmp12;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[3*3];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array. */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 3; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    tmp0 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);
+    tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */
+    tmp10 = tmp0 + tmp12;
+    tmp2 = tmp0 - tmp12 - tmp12;
+
+    /* Odd part */
+
+    tmp12 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */
+
+    /* Final output stage */
+
+    wsptr[3*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+    wsptr[3*2] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+    wsptr[3*1] = (int) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process 3 rows from work array, store into output array. */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 3; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    tmp0 <<= CONST_BITS;
+    tmp2 = (INT32) wsptr[2];
+    tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */
+    tmp10 = tmp0 + tmp12;
+    tmp2 = tmp0 - tmp12 - tmp12;
+
+    /* Odd part */
+
+    tmp12 = (INT32) wsptr[1];
+    tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */
+
+    /* Final output stage */
+
+    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += 3;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 2x2 output block.
+ *
+ * Multiplication-less algorithm.
+ */
+
+GLOBAL(void)
+jpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	       JCOEFPTR coef_block,
+	       JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
+  ISLOW_MULT_TYPE * quantptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input. */
+
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+
+  /* Column 0 */
+  tmp4 = DEQUANTIZE(coef_block[DCTSIZE*0], quantptr[DCTSIZE*0]);
+  tmp5 = DEQUANTIZE(coef_block[DCTSIZE*1], quantptr[DCTSIZE*1]);
+  /* Add fudge factor here for final descale. */
+  tmp4 += ONE << 2;
+
+  tmp0 = tmp4 + tmp5;
+  tmp2 = tmp4 - tmp5;
+
+  /* Column 1 */
+  tmp4 = DEQUANTIZE(coef_block[DCTSIZE*0+1], quantptr[DCTSIZE*0+1]);
+  tmp5 = DEQUANTIZE(coef_block[DCTSIZE*1+1], quantptr[DCTSIZE*1+1]);
+
+  tmp1 = tmp4 + tmp5;
+  tmp3 = tmp4 - tmp5;
+
+  /* Pass 2: process 2 rows, store into output array. */
+
+  /* Row 0 */
+  outptr = output_buf[0] + output_col;
+
+  outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp0 + tmp1, 3) & RANGE_MASK];
+  outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp0 - tmp1, 3) & RANGE_MASK];
+
+  /* Row 1 */
+  outptr = output_buf[1] + output_col;
+
+  outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp2 + tmp3, 3) & RANGE_MASK];
+  outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp2 - tmp3, 3) & RANGE_MASK];
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 1x1 output block.
+ *
+ * We hardly need an inverse DCT routine for this: just take the
+ * average pixel value, which is one-eighth of the DC coefficient.
+ */
+
+GLOBAL(void)
+jpeg_idct_1x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	       JCOEFPTR coef_block,
+	       JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  int dcval;
+  ISLOW_MULT_TYPE * quantptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  SHIFT_TEMPS
+
+  /* 1x1 is trivial: just take the DC coefficient divided by 8. */
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  dcval = DEQUANTIZE(coef_block[0], quantptr[0]);
+  dcval = (int) DESCALE((INT32) dcval, 3);
+
+  output_buf[0][output_col] = range_limit[dcval & RANGE_MASK];
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 9x9 output block.
+ *
+ * Optimized algorithm with 10 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/18).
+ */
+
+GLOBAL(void)
+jpeg_idct_9x9 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	       JCOEFPTR coef_block,
+	       JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13, tmp14;
+  INT32 z1, z2, z3, z4;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[8*9];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array. */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    tmp0 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+    tmp3 = MULTIPLY(z3, FIX(0.707106781));      /* c6 */
+    tmp1 = tmp0 + tmp3;
+    tmp2 = tmp0 - tmp3 - tmp3;
+
+    tmp0 = MULTIPLY(z1 - z2, FIX(0.707106781)); /* c6 */
+    tmp11 = tmp2 + tmp0;
+    tmp14 = tmp2 - tmp0 - tmp0;
+
+    tmp0 = MULTIPLY(z1 + z2, FIX(1.328926049)); /* c2 */
+    tmp2 = MULTIPLY(z1, FIX(1.083350441));      /* c4 */
+    tmp3 = MULTIPLY(z2, FIX(0.245575608));      /* c8 */
+
+    tmp10 = tmp1 + tmp0 - tmp3;
+    tmp12 = tmp1 - tmp0 + tmp2;
+    tmp13 = tmp1 - tmp2 + tmp3;
+
+    /* Odd part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+    z2 = MULTIPLY(z2, - FIX(1.224744871));           /* -c3 */
+
+    tmp2 = MULTIPLY(z1 + z3, FIX(0.909038955));      /* c5 */
+    tmp3 = MULTIPLY(z1 + z4, FIX(0.483689525));      /* c7 */
+    tmp0 = tmp2 + tmp3 - z2;
+    tmp1 = MULTIPLY(z3 - z4, FIX(1.392728481));      /* c1 */
+    tmp2 += z2 - tmp1;
+    tmp3 += z2 + tmp1;
+    tmp1 = MULTIPLY(z1 - z3 - z4, FIX(1.224744871)); /* c3 */
+
+    /* Final output stage */
+
+    wsptr[8*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+    wsptr[8*8] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+    wsptr[8*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS);
+    wsptr[8*7] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS);
+    wsptr[8*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS);
+    wsptr[8*6] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS);
+    wsptr[8*3] = (int) RIGHT_SHIFT(tmp13 + tmp3, CONST_BITS-PASS1_BITS);
+    wsptr[8*5] = (int) RIGHT_SHIFT(tmp13 - tmp3, CONST_BITS-PASS1_BITS);
+    wsptr[8*4] = (int) RIGHT_SHIFT(tmp14, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process 9 rows from work array, store into output array. */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 9; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    tmp0 <<= CONST_BITS;
+
+    z1 = (INT32) wsptr[2];
+    z2 = (INT32) wsptr[4];
+    z3 = (INT32) wsptr[6];
+
+    tmp3 = MULTIPLY(z3, FIX(0.707106781));      /* c6 */
+    tmp1 = tmp0 + tmp3;
+    tmp2 = tmp0 - tmp3 - tmp3;
+
+    tmp0 = MULTIPLY(z1 - z2, FIX(0.707106781)); /* c6 */
+    tmp11 = tmp2 + tmp0;
+    tmp14 = tmp2 - tmp0 - tmp0;
+
+    tmp0 = MULTIPLY(z1 + z2, FIX(1.328926049)); /* c2 */
+    tmp2 = MULTIPLY(z1, FIX(1.083350441));      /* c4 */
+    tmp3 = MULTIPLY(z2, FIX(0.245575608));      /* c8 */
+
+    tmp10 = tmp1 + tmp0 - tmp3;
+    tmp12 = tmp1 - tmp0 + tmp2;
+    tmp13 = tmp1 - tmp2 + tmp3;
+
+    /* Odd part */
+
+    z1 = (INT32) wsptr[1];
+    z2 = (INT32) wsptr[3];
+    z3 = (INT32) wsptr[5];
+    z4 = (INT32) wsptr[7];
+
+    z2 = MULTIPLY(z2, - FIX(1.224744871));           /* -c3 */
+
+    tmp2 = MULTIPLY(z1 + z3, FIX(0.909038955));      /* c5 */
+    tmp3 = MULTIPLY(z1 + z4, FIX(0.483689525));      /* c7 */
+    tmp0 = tmp2 + tmp3 - z2;
+    tmp1 = MULTIPLY(z3 - z4, FIX(1.392728481));      /* c1 */
+    tmp2 += z2 - tmp1;
+    tmp3 += z2 + tmp1;
+    tmp1 = MULTIPLY(z1 - z3 - z4, FIX(1.224744871)); /* c3 */
+
+    /* Final output stage */
+
+    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp3,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp3,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp14,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += 8;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 10x10 output block.
+ *
+ * Optimized algorithm with 12 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/20).
+ */
+
+GLOBAL(void)
+jpeg_idct_10x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		 JCOEFPTR coef_block,
+		 JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+  INT32 tmp20, tmp21, tmp22, tmp23, tmp24;
+  INT32 z1, z2, z3, z4, z5;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[8*10];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array. */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    z3 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    z3 += ONE << (CONST_BITS-PASS1_BITS-1);
+    z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    z1 = MULTIPLY(z4, FIX(1.144122806));         /* c4 */
+    z2 = MULTIPLY(z4, FIX(0.437016024));         /* c8 */
+    tmp10 = z3 + z1;
+    tmp11 = z3 - z2;
+
+    tmp22 = RIGHT_SHIFT(z3 - ((z1 - z2) << 1),   /* c0 = (c4-c8)*2 */
+			CONST_BITS-PASS1_BITS);
+
+    z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+    z1 = MULTIPLY(z2 + z3, FIX(0.831253876));    /* c6 */
+    tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */
+    tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */
+
+    tmp20 = tmp10 + tmp12;
+    tmp24 = tmp10 - tmp12;
+    tmp21 = tmp11 + tmp13;
+    tmp23 = tmp11 - tmp13;
+
+    /* Odd part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+    tmp11 = z2 + z4;
+    tmp13 = z2 - z4;
+
+    tmp12 = MULTIPLY(tmp13, FIX(0.309016994));        /* (c3-c7)/2 */
+    z5 = z3 << CONST_BITS;
+
+    z2 = MULTIPLY(tmp11, FIX(0.951056516));           /* (c3+c7)/2 */
+    z4 = z5 + tmp12;
+
+    tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */
+    tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */
+
+    z2 = MULTIPLY(tmp11, FIX(0.587785252));           /* (c1-c9)/2 */
+    z4 = z5 - tmp12 - (tmp13 << (CONST_BITS - 1));
+
+    tmp12 = (z1 - tmp13 - z3) << PASS1_BITS;
+
+    tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */
+    tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */
+
+    /* Final output stage */
+
+    wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*9] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[8*8] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[8*2] = (int) (tmp22 + tmp12);
+    wsptr[8*7] = (int) (tmp22 - tmp12);
+    wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+    wsptr[8*6] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+    wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+    wsptr[8*5] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process 10 rows from work array, store into output array. */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 10; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    z3 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    z3 <<= CONST_BITS;
+    z4 = (INT32) wsptr[4];
+    z1 = MULTIPLY(z4, FIX(1.144122806));         /* c4 */
+    z2 = MULTIPLY(z4, FIX(0.437016024));         /* c8 */
+    tmp10 = z3 + z1;
+    tmp11 = z3 - z2;
+
+    tmp22 = z3 - ((z1 - z2) << 1);               /* c0 = (c4-c8)*2 */
+
+    z2 = (INT32) wsptr[2];
+    z3 = (INT32) wsptr[6];
+
+    z1 = MULTIPLY(z2 + z3, FIX(0.831253876));    /* c6 */
+    tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */
+    tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */
+
+    tmp20 = tmp10 + tmp12;
+    tmp24 = tmp10 - tmp12;
+    tmp21 = tmp11 + tmp13;
+    tmp23 = tmp11 - tmp13;
+
+    /* Odd part */
+
+    z1 = (INT32) wsptr[1];
+    z2 = (INT32) wsptr[3];
+    z3 = (INT32) wsptr[5];
+    z3 <<= CONST_BITS;
+    z4 = (INT32) wsptr[7];
+
+    tmp11 = z2 + z4;
+    tmp13 = z2 - z4;
+
+    tmp12 = MULTIPLY(tmp13, FIX(0.309016994));        /* (c3-c7)/2 */
+
+    z2 = MULTIPLY(tmp11, FIX(0.951056516));           /* (c3+c7)/2 */
+    z4 = z3 + tmp12;
+
+    tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */
+    tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */
+
+    z2 = MULTIPLY(tmp11, FIX(0.587785252));           /* (c1-c9)/2 */
+    z4 = z3 - tmp12 - (tmp13 << (CONST_BITS - 1));
+
+    tmp12 = ((z1 - tmp13) << CONST_BITS) - z3;
+
+    tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */
+    tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */
+
+    /* Final output stage */
+
+    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += 8;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 11x11 output block.
+ *
+ * Optimized algorithm with 24 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/22).
+ */
+
+GLOBAL(void)
+jpeg_idct_11x11 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		 JCOEFPTR coef_block,
+		 JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;
+  INT32 z1, z2, z3, z4;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[8*11];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array. */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    tmp10 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    tmp10 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+    tmp20 = MULTIPLY(z2 - z3, FIX(2.546640132));     /* c2+c4 */
+    tmp23 = MULTIPLY(z2 - z1, FIX(0.430815045));     /* c2-c6 */
+    z4 = z1 + z3;
+    tmp24 = MULTIPLY(z4, - FIX(1.155664402));        /* -(c2-c10) */
+    z4 -= z2;
+    tmp25 = tmp10 + MULTIPLY(z4, FIX(1.356927976));  /* c2 */
+    tmp21 = tmp20 + tmp23 + tmp25 -
+	    MULTIPLY(z2, FIX(1.821790775));          /* c2+c4+c10-c6 */
+    tmp20 += tmp25 + MULTIPLY(z3, FIX(2.115825087)); /* c4+c6 */
+    tmp23 += tmp25 - MULTIPLY(z1, FIX(1.513598477)); /* c6+c8 */
+    tmp24 += tmp25;
+    tmp22 = tmp24 - MULTIPLY(z3, FIX(0.788749120));  /* c8+c10 */
+    tmp24 += MULTIPLY(z2, FIX(1.944413522)) -        /* c2+c8 */
+	     MULTIPLY(z1, FIX(1.390975730));         /* c4+c10 */
+    tmp25 = tmp10 - MULTIPLY(z4, FIX(1.414213562));  /* c0 */
+
+    /* Odd part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+    tmp11 = z1 + z2;
+    tmp14 = MULTIPLY(tmp11 + z3 + z4, FIX(0.398430003)); /* c9 */
+    tmp11 = MULTIPLY(tmp11, FIX(0.887983902));           /* c3-c9 */
+    tmp12 = MULTIPLY(z1 + z3, FIX(0.670361295));         /* c5-c9 */
+    tmp13 = tmp14 + MULTIPLY(z1 + z4, FIX(0.366151574)); /* c7-c9 */
+    tmp10 = tmp11 + tmp12 + tmp13 -
+	    MULTIPLY(z1, FIX(0.923107866));              /* c7+c5+c3-c1-2*c9 */
+    z1    = tmp14 - MULTIPLY(z2 + z3, FIX(1.163011579)); /* c7+c9 */
+    tmp11 += z1 + MULTIPLY(z2, FIX(2.073276588));        /* c1+c7+3*c9-c3 */
+    tmp12 += z1 - MULTIPLY(z3, FIX(1.192193623));        /* c3+c5-c7-c9 */
+    z1    = MULTIPLY(z2 + z4, - FIX(1.798248910));       /* -(c1+c9) */
+    tmp11 += z1;
+    tmp13 += z1 + MULTIPLY(z4, FIX(2.102458632));        /* c1+c5+c9-c7 */
+    tmp14 += MULTIPLY(z2, - FIX(1.467221301)) +          /* -(c5+c9) */
+	     MULTIPLY(z3, FIX(1.001388905)) -            /* c1-c9 */
+	     MULTIPLY(z4, FIX(1.684843907));             /* c3+c9 */
+
+    /* Final output stage */
+
+    wsptr[8*0]  = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*10] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*1]  = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[8*9]  = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[8*2]  = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[8*8]  = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[8*3]  = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+    wsptr[8*7]  = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+    wsptr[8*4]  = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+    wsptr[8*6]  = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+    wsptr[8*5]  = (int) RIGHT_SHIFT(tmp25, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process 11 rows from work array, store into output array. */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 11; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp10 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    tmp10 <<= CONST_BITS;
+
+    z1 = (INT32) wsptr[2];
+    z2 = (INT32) wsptr[4];
+    z3 = (INT32) wsptr[6];
+
+    tmp20 = MULTIPLY(z2 - z3, FIX(2.546640132));     /* c2+c4 */
+    tmp23 = MULTIPLY(z2 - z1, FIX(0.430815045));     /* c2-c6 */
+    z4 = z1 + z3;
+    tmp24 = MULTIPLY(z4, - FIX(1.155664402));        /* -(c2-c10) */
+    z4 -= z2;
+    tmp25 = tmp10 + MULTIPLY(z4, FIX(1.356927976));  /* c2 */
+    tmp21 = tmp20 + tmp23 + tmp25 -
+	    MULTIPLY(z2, FIX(1.821790775));          /* c2+c4+c10-c6 */
+    tmp20 += tmp25 + MULTIPLY(z3, FIX(2.115825087)); /* c4+c6 */
+    tmp23 += tmp25 - MULTIPLY(z1, FIX(1.513598477)); /* c6+c8 */
+    tmp24 += tmp25;
+    tmp22 = tmp24 - MULTIPLY(z3, FIX(0.788749120));  /* c8+c10 */
+    tmp24 += MULTIPLY(z2, FIX(1.944413522)) -        /* c2+c8 */
+	     MULTIPLY(z1, FIX(1.390975730));         /* c4+c10 */
+    tmp25 = tmp10 - MULTIPLY(z4, FIX(1.414213562));  /* c0 */
+
+    /* Odd part */
+
+    z1 = (INT32) wsptr[1];
+    z2 = (INT32) wsptr[3];
+    z3 = (INT32) wsptr[5];
+    z4 = (INT32) wsptr[7];
+
+    tmp11 = z1 + z2;
+    tmp14 = MULTIPLY(tmp11 + z3 + z4, FIX(0.398430003)); /* c9 */
+    tmp11 = MULTIPLY(tmp11, FIX(0.887983902));           /* c3-c9 */
+    tmp12 = MULTIPLY(z1 + z3, FIX(0.670361295));         /* c5-c9 */
+    tmp13 = tmp14 + MULTIPLY(z1 + z4, FIX(0.366151574)); /* c7-c9 */
+    tmp10 = tmp11 + tmp12 + tmp13 -
+	    MULTIPLY(z1, FIX(0.923107866));              /* c7+c5+c3-c1-2*c9 */
+    z1    = tmp14 - MULTIPLY(z2 + z3, FIX(1.163011579)); /* c7+c9 */
+    tmp11 += z1 + MULTIPLY(z2, FIX(2.073276588));        /* c1+c7+3*c9-c3 */
+    tmp12 += z1 - MULTIPLY(z3, FIX(1.192193623));        /* c3+c5-c7-c9 */
+    z1    = MULTIPLY(z2 + z4, - FIX(1.798248910));       /* -(c1+c9) */
+    tmp11 += z1;
+    tmp13 += z1 + MULTIPLY(z4, FIX(2.102458632));        /* c1+c5+c9-c7 */
+    tmp14 += MULTIPLY(z2, - FIX(1.467221301)) +          /* -(c5+c9) */
+	     MULTIPLY(z3, FIX(1.001388905)) -            /* c1-c9 */
+	     MULTIPLY(z4, FIX(1.684843907));             /* c3+c9 */
+
+    /* Final output stage */
+
+    outptr[0]  = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[1]  = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[9]  = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[2]  = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[8]  = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[3]  = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[7]  = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[4]  = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[6]  = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[5]  = range_limit[(int) RIGHT_SHIFT(tmp25,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+
+    wsptr += 8;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 12x12 output block.
+ *
+ * Optimized algorithm with 15 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/24).
+ */
+
+GLOBAL(void)
+jpeg_idct_12x12 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		 JCOEFPTR coef_block,
+		 JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;
+  INT32 z1, z2, z3, z4;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[8*12];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array. */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    z3 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    z3 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+    z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */
+
+    tmp10 = z3 + z4;
+    tmp11 = z3 - z4;
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */
+    z1 <<= CONST_BITS;
+    z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+    z2 <<= CONST_BITS;
+
+    tmp12 = z1 - z2;
+
+    tmp21 = z3 + tmp12;
+    tmp24 = z3 - tmp12;
+
+    tmp12 = z4 + z2;
+
+    tmp20 = tmp10 + tmp12;
+    tmp25 = tmp10 - tmp12;
+
+    tmp12 = z4 - z1 - z2;
+
+    tmp22 = tmp11 + tmp12;
+    tmp23 = tmp11 - tmp12;
+
+    /* Odd part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+    tmp11 = MULTIPLY(z2, FIX(1.306562965));                  /* c3 */
+    tmp14 = MULTIPLY(z2, - FIX_0_541196100);                 /* -c9 */
+
+    tmp10 = z1 + z3;
+    tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669));          /* c7 */
+    tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384));       /* c5-c7 */
+    tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716));  /* c1-c5 */
+    tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580));           /* -(c7+c11) */
+    tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */
+    tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */
+    tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) -        /* c7-c11 */
+	     MULTIPLY(z4, FIX(1.982889723));                 /* c5+c7 */
+
+    z1 -= z4;
+    z2 -= z3;
+    z3 = MULTIPLY(z1 + z2, FIX_0_541196100);                 /* c9 */
+    tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865);              /* c3-c9 */
+    tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065);              /* c3+c9 */
+
+    /* Final output stage */
+
+    wsptr[8*0]  = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*11] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*1]  = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[8*10] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[8*2]  = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[8*9]  = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[8*3]  = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+    wsptr[8*8]  = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+    wsptr[8*4]  = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+    wsptr[8*7]  = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+    wsptr[8*5]  = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);
+    wsptr[8*6]  = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process 12 rows from work array, store into output array. */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 12; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    z3 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    z3 <<= CONST_BITS;
+
+    z4 = (INT32) wsptr[4];
+    z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */
+
+    tmp10 = z3 + z4;
+    tmp11 = z3 - z4;
+
+    z1 = (INT32) wsptr[2];
+    z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */
+    z1 <<= CONST_BITS;
+    z2 = (INT32) wsptr[6];
+    z2 <<= CONST_BITS;
+
+    tmp12 = z1 - z2;
+
+    tmp21 = z3 + tmp12;
+    tmp24 = z3 - tmp12;
+
+    tmp12 = z4 + z2;
+
+    tmp20 = tmp10 + tmp12;
+    tmp25 = tmp10 - tmp12;
+
+    tmp12 = z4 - z1 - z2;
+
+    tmp22 = tmp11 + tmp12;
+    tmp23 = tmp11 - tmp12;
+
+    /* Odd part */
+
+    z1 = (INT32) wsptr[1];
+    z2 = (INT32) wsptr[3];
+    z3 = (INT32) wsptr[5];
+    z4 = (INT32) wsptr[7];
+
+    tmp11 = MULTIPLY(z2, FIX(1.306562965));                  /* c3 */
+    tmp14 = MULTIPLY(z2, - FIX_0_541196100);                 /* -c9 */
+
+    tmp10 = z1 + z3;
+    tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669));          /* c7 */
+    tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384));       /* c5-c7 */
+    tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716));  /* c1-c5 */
+    tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580));           /* -(c7+c11) */
+    tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */
+    tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */
+    tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) -        /* c7-c11 */
+	     MULTIPLY(z4, FIX(1.982889723));                 /* c5+c7 */
+
+    z1 -= z4;
+    z2 -= z3;
+    z3 = MULTIPLY(z1 + z2, FIX_0_541196100);                 /* c9 */
+    tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865);              /* c3-c9 */
+    tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065);              /* c3+c9 */
+
+    /* Final output stage */
+
+    outptr[0]  = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[1]  = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[2]  = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[9]  = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[3]  = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[8]  = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[4]  = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[7]  = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[5]  = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[6]  = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+
+    wsptr += 8;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 13x13 output block.
+ *
+ * Optimized algorithm with 29 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/26).
+ */
+
+GLOBAL(void)
+jpeg_idct_13x13 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		 JCOEFPTR coef_block,
+		 JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;
+  INT32 z1, z2, z3, z4;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[8*13];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array. */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    z1 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+    z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    z4 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+    tmp10 = z3 + z4;
+    tmp11 = z3 - z4;
+
+    tmp12 = MULTIPLY(tmp10, FIX(1.155388986));                /* (c4+c6)/2 */
+    tmp13 = MULTIPLY(tmp11, FIX(0.096834934)) + z1;           /* (c4-c6)/2 */
+
+    tmp20 = MULTIPLY(z2, FIX(1.373119086)) + tmp12 + tmp13;   /* c2 */
+    tmp22 = MULTIPLY(z2, FIX(0.501487041)) - tmp12 + tmp13;   /* c10 */
+
+    tmp12 = MULTIPLY(tmp10, FIX(0.316450131));                /* (c8-c12)/2 */
+    tmp13 = MULTIPLY(tmp11, FIX(0.486914739)) + z1;           /* (c8+c12)/2 */
+
+    tmp21 = MULTIPLY(z2, FIX(1.058554052)) - tmp12 + tmp13;   /* c6 */
+    tmp25 = MULTIPLY(z2, - FIX(1.252223920)) + tmp12 + tmp13; /* c4 */
+
+    tmp12 = MULTIPLY(tmp10, FIX(0.435816023));                /* (c2-c10)/2 */
+    tmp13 = MULTIPLY(tmp11, FIX(0.937303064)) - z1;           /* (c2+c10)/2 */
+
+    tmp23 = MULTIPLY(z2, - FIX(0.170464608)) - tmp12 - tmp13; /* c12 */
+    tmp24 = MULTIPLY(z2, - FIX(0.803364869)) + tmp12 - tmp13; /* c8 */
+
+    tmp26 = MULTIPLY(tmp11 - z2, FIX(1.414213562)) + z1;      /* c0 */
+
+    /* Odd part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+    tmp11 = MULTIPLY(z1 + z2, FIX(1.322312651));     /* c3 */
+    tmp12 = MULTIPLY(z1 + z3, FIX(1.163874945));     /* c5 */
+    tmp15 = z1 + z4;
+    tmp13 = MULTIPLY(tmp15, FIX(0.937797057));       /* c7 */
+    tmp10 = tmp11 + tmp12 + tmp13 -
+	    MULTIPLY(z1, FIX(2.020082300));          /* c7+c5+c3-c1 */
+    tmp14 = MULTIPLY(z2 + z3, - FIX(0.338443458));   /* -c11 */
+    tmp11 += tmp14 + MULTIPLY(z2, FIX(0.837223564)); /* c5+c9+c11-c3 */
+    tmp12 += tmp14 - MULTIPLY(z3, FIX(1.572116027)); /* c1+c5-c9-c11 */
+    tmp14 = MULTIPLY(z2 + z4, - FIX(1.163874945));   /* -c5 */
+    tmp11 += tmp14;
+    tmp13 += tmp14 + MULTIPLY(z4, FIX(2.205608352)); /* c3+c5+c9-c7 */
+    tmp14 = MULTIPLY(z3 + z4, - FIX(0.657217813));   /* -c9 */
+    tmp12 += tmp14;
+    tmp13 += tmp14;
+    tmp15 = MULTIPLY(tmp15, FIX(0.338443458));       /* c11 */
+    tmp14 = tmp15 + MULTIPLY(z1, FIX(0.318774355)) - /* c9-c11 */
+	    MULTIPLY(z2, FIX(0.466105296));          /* c1-c7 */
+    z1    = MULTIPLY(z3 - z2, FIX(0.937797057));     /* c7 */
+    tmp14 += z1;
+    tmp15 += z1 + MULTIPLY(z3, FIX(0.384515595)) -   /* c3-c7 */
+	     MULTIPLY(z4, FIX(1.742345811));         /* c1+c11 */
+
+    /* Final output stage */
+
+    wsptr[8*0]  = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*12] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*1]  = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[8*11] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[8*2]  = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[8*10] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[8*3]  = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+    wsptr[8*9]  = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+    wsptr[8*4]  = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+    wsptr[8*8]  = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+    wsptr[8*5]  = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);
+    wsptr[8*7]  = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);
+    wsptr[8*6]  = (int) RIGHT_SHIFT(tmp26, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process 13 rows from work array, store into output array. */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 13; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    z1 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    z1 <<= CONST_BITS;
+
+    z2 = (INT32) wsptr[2];
+    z3 = (INT32) wsptr[4];
+    z4 = (INT32) wsptr[6];
+
+    tmp10 = z3 + z4;
+    tmp11 = z3 - z4;
+
+    tmp12 = MULTIPLY(tmp10, FIX(1.155388986));                /* (c4+c6)/2 */
+    tmp13 = MULTIPLY(tmp11, FIX(0.096834934)) + z1;           /* (c4-c6)/2 */
+
+    tmp20 = MULTIPLY(z2, FIX(1.373119086)) + tmp12 + tmp13;   /* c2 */
+    tmp22 = MULTIPLY(z2, FIX(0.501487041)) - tmp12 + tmp13;   /* c10 */
+
+    tmp12 = MULTIPLY(tmp10, FIX(0.316450131));                /* (c8-c12)/2 */
+    tmp13 = MULTIPLY(tmp11, FIX(0.486914739)) + z1;           /* (c8+c12)/2 */
+
+    tmp21 = MULTIPLY(z2, FIX(1.058554052)) - tmp12 + tmp13;   /* c6 */
+    tmp25 = MULTIPLY(z2, - FIX(1.252223920)) + tmp12 + tmp13; /* c4 */
+
+    tmp12 = MULTIPLY(tmp10, FIX(0.435816023));                /* (c2-c10)/2 */
+    tmp13 = MULTIPLY(tmp11, FIX(0.937303064)) - z1;           /* (c2+c10)/2 */
+
+    tmp23 = MULTIPLY(z2, - FIX(0.170464608)) - tmp12 - tmp13; /* c12 */
+    tmp24 = MULTIPLY(z2, - FIX(0.803364869)) + tmp12 - tmp13; /* c8 */
+
+    tmp26 = MULTIPLY(tmp11 - z2, FIX(1.414213562)) + z1;      /* c0 */
+
+    /* Odd part */
+
+    z1 = (INT32) wsptr[1];
+    z2 = (INT32) wsptr[3];
+    z3 = (INT32) wsptr[5];
+    z4 = (INT32) wsptr[7];
+
+    tmp11 = MULTIPLY(z1 + z2, FIX(1.322312651));     /* c3 */
+    tmp12 = MULTIPLY(z1 + z3, FIX(1.163874945));     /* c5 */
+    tmp15 = z1 + z4;
+    tmp13 = MULTIPLY(tmp15, FIX(0.937797057));       /* c7 */
+    tmp10 = tmp11 + tmp12 + tmp13 -
+	    MULTIPLY(z1, FIX(2.020082300));          /* c7+c5+c3-c1 */
+    tmp14 = MULTIPLY(z2 + z3, - FIX(0.338443458));   /* -c11 */
+    tmp11 += tmp14 + MULTIPLY(z2, FIX(0.837223564)); /* c5+c9+c11-c3 */
+    tmp12 += tmp14 - MULTIPLY(z3, FIX(1.572116027)); /* c1+c5-c9-c11 */
+    tmp14 = MULTIPLY(z2 + z4, - FIX(1.163874945));   /* -c5 */
+    tmp11 += tmp14;
+    tmp13 += tmp14 + MULTIPLY(z4, FIX(2.205608352)); /* c3+c5+c9-c7 */
+    tmp14 = MULTIPLY(z3 + z4, - FIX(0.657217813));   /* -c9 */
+    tmp12 += tmp14;
+    tmp13 += tmp14;
+    tmp15 = MULTIPLY(tmp15, FIX(0.338443458));       /* c11 */
+    tmp14 = tmp15 + MULTIPLY(z1, FIX(0.318774355)) - /* c9-c11 */
+	    MULTIPLY(z2, FIX(0.466105296));          /* c1-c7 */
+    z1    = MULTIPLY(z3 - z2, FIX(0.937797057));     /* c7 */
+    tmp14 += z1;
+    tmp15 += z1 + MULTIPLY(z3, FIX(0.384515595)) -   /* c3-c7 */
+	     MULTIPLY(z4, FIX(1.742345811));         /* c1+c11 */
+
+    /* Final output stage */
+
+    outptr[0]  = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[1]  = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[2]  = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[3]  = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[9]  = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[4]  = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[8]  = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[5]  = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[7]  = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[6]  = range_limit[(int) RIGHT_SHIFT(tmp26,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+
+    wsptr += 8;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 14x14 output block.
+ *
+ * Optimized algorithm with 20 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/28).
+ */
+
+GLOBAL(void)
+jpeg_idct_14x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		 JCOEFPTR coef_block,
+		 JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;
+  INT32 z1, z2, z3, z4;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[8*14];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array. */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    z1 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+    z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    z2 = MULTIPLY(z4, FIX(1.274162392));         /* c4 */
+    z3 = MULTIPLY(z4, FIX(0.314692123));         /* c12 */
+    z4 = MULTIPLY(z4, FIX(0.881747734));         /* c8 */
+
+    tmp10 = z1 + z2;
+    tmp11 = z1 + z3;
+    tmp12 = z1 - z4;
+
+    tmp23 = RIGHT_SHIFT(z1 - ((z2 + z3 - z4) << 1), /* c0 = (c4+c12-c8)*2 */
+			CONST_BITS-PASS1_BITS);
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+    z3 = MULTIPLY(z1 + z2, FIX(1.105676686));    /* c6 */
+
+    tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */
+    tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */
+    tmp15 = MULTIPLY(z1, FIX(0.613604268)) -     /* c10 */
+	    MULTIPLY(z2, FIX(1.378756276));      /* c2 */
+
+    tmp20 = tmp10 + tmp13;
+    tmp26 = tmp10 - tmp13;
+    tmp21 = tmp11 + tmp14;
+    tmp25 = tmp11 - tmp14;
+    tmp22 = tmp12 + tmp15;
+    tmp24 = tmp12 - tmp15;
+
+    /* Odd part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+    tmp13 = z4 << CONST_BITS;
+
+    tmp14 = z1 + z3;
+    tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607));           /* c3 */
+    tmp12 = MULTIPLY(tmp14, FIX(1.197448846));             /* c5 */
+    tmp10 = tmp11 + tmp12 + tmp13 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */
+    tmp14 = MULTIPLY(tmp14, FIX(0.752406978));             /* c9 */
+    tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426));        /* c9+c11-c13 */
+    z1    -= z2;
+    tmp15 = MULTIPLY(z1, FIX(0.467085129)) - tmp13;        /* c11 */
+    tmp16 += tmp15;
+    z1    += z4;
+    z4    = MULTIPLY(z2 + z3, - FIX(0.158341681)) - tmp13; /* -c13 */
+    tmp11 += z4 - MULTIPLY(z2, FIX(0.424103948));          /* c3-c9-c13 */
+    tmp12 += z4 - MULTIPLY(z3, FIX(2.373959773));          /* c3+c5-c13 */
+    z4    = MULTIPLY(z3 - z2, FIX(1.405321284));           /* c1 */
+    tmp14 += z4 + tmp13 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */
+    tmp15 += z4 + MULTIPLY(z2, FIX(0.674957567));          /* c1+c11-c5 */
+
+    tmp13 = (z1 - z3) << PASS1_BITS;
+
+    /* Final output stage */
+
+    wsptr[8*0]  = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*13] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*1]  = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[8*12] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[8*2]  = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[8*11] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[8*3]  = (int) (tmp23 + tmp13);
+    wsptr[8*10] = (int) (tmp23 - tmp13);
+    wsptr[8*4]  = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+    wsptr[8*9]  = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+    wsptr[8*5]  = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);
+    wsptr[8*8]  = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);
+    wsptr[8*6]  = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS);
+    wsptr[8*7]  = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process 14 rows from work array, store into output array. */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 14; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    z1 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    z1 <<= CONST_BITS;
+    z4 = (INT32) wsptr[4];
+    z2 = MULTIPLY(z4, FIX(1.274162392));         /* c4 */
+    z3 = MULTIPLY(z4, FIX(0.314692123));         /* c12 */
+    z4 = MULTIPLY(z4, FIX(0.881747734));         /* c8 */
+
+    tmp10 = z1 + z2;
+    tmp11 = z1 + z3;
+    tmp12 = z1 - z4;
+
+    tmp23 = z1 - ((z2 + z3 - z4) << 1);          /* c0 = (c4+c12-c8)*2 */
+
+    z1 = (INT32) wsptr[2];
+    z2 = (INT32) wsptr[6];
+
+    z3 = MULTIPLY(z1 + z2, FIX(1.105676686));    /* c6 */
+
+    tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */
+    tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */
+    tmp15 = MULTIPLY(z1, FIX(0.613604268)) -     /* c10 */
+	    MULTIPLY(z2, FIX(1.378756276));      /* c2 */
+
+    tmp20 = tmp10 + tmp13;
+    tmp26 = tmp10 - tmp13;
+    tmp21 = tmp11 + tmp14;
+    tmp25 = tmp11 - tmp14;
+    tmp22 = tmp12 + tmp15;
+    tmp24 = tmp12 - tmp15;
+
+    /* Odd part */
+
+    z1 = (INT32) wsptr[1];
+    z2 = (INT32) wsptr[3];
+    z3 = (INT32) wsptr[5];
+    z4 = (INT32) wsptr[7];
+    z4 <<= CONST_BITS;
+
+    tmp14 = z1 + z3;
+    tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607));           /* c3 */
+    tmp12 = MULTIPLY(tmp14, FIX(1.197448846));             /* c5 */
+    tmp10 = tmp11 + tmp12 + z4 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */
+    tmp14 = MULTIPLY(tmp14, FIX(0.752406978));             /* c9 */
+    tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426));        /* c9+c11-c13 */
+    z1    -= z2;
+    tmp15 = MULTIPLY(z1, FIX(0.467085129)) - z4;           /* c11 */
+    tmp16 += tmp15;
+    tmp13 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - z4;    /* -c13 */
+    tmp11 += tmp13 - MULTIPLY(z2, FIX(0.424103948));       /* c3-c9-c13 */
+    tmp12 += tmp13 - MULTIPLY(z3, FIX(2.373959773));       /* c3+c5-c13 */
+    tmp13 = MULTIPLY(z3 - z2, FIX(1.405321284));           /* c1 */
+    tmp14 += tmp13 + z4 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */
+    tmp15 += tmp13 + MULTIPLY(z2, FIX(0.674957567));       /* c1+c11-c5 */
+
+    tmp13 = ((z1 - z3) << CONST_BITS) + z4;
+
+    /* Final output stage */
+
+    outptr[0]  = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[1]  = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[2]  = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[3]  = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[4]  = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[9]  = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[5]  = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[8]  = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[6]  = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[7]  = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+
+    wsptr += 8;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 15x15 output block.
+ *
+ * Optimized algorithm with 22 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/30).
+ */
+
+GLOBAL(void)
+jpeg_idct_15x15 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		 JCOEFPTR coef_block,
+		 JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;
+  INT32 z1, z2, z3, z4;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[8*15];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array. */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    z1 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+    z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    z4 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+    tmp10 = MULTIPLY(z4, FIX(0.437016024)); /* c12 */
+    tmp11 = MULTIPLY(z4, FIX(1.144122806)); /* c6 */
+
+    tmp12 = z1 - tmp10;
+    tmp13 = z1 + tmp11;
+    z1 -= (tmp11 - tmp10) << 1;             /* c0 = (c6-c12)*2 */
+
+    z4 = z2 - z3;
+    z3 += z2;
+    tmp10 = MULTIPLY(z3, FIX(1.337628990)); /* (c2+c4)/2 */
+    tmp11 = MULTIPLY(z4, FIX(0.045680613)); /* (c2-c4)/2 */
+    z2 = MULTIPLY(z2, FIX(1.439773946));    /* c4+c14 */
+
+    tmp20 = tmp13 + tmp10 + tmp11;
+    tmp23 = tmp12 - tmp10 + tmp11 + z2;
+
+    tmp10 = MULTIPLY(z3, FIX(0.547059574)); /* (c8+c14)/2 */
+    tmp11 = MULTIPLY(z4, FIX(0.399234004)); /* (c8-c14)/2 */
+
+    tmp25 = tmp13 - tmp10 - tmp11;
+    tmp26 = tmp12 + tmp10 - tmp11 - z2;
+
+    tmp10 = MULTIPLY(z3, FIX(0.790569415)); /* (c6+c12)/2 */
+    tmp11 = MULTIPLY(z4, FIX(0.353553391)); /* (c6-c12)/2 */
+
+    tmp21 = tmp12 + tmp10 + tmp11;
+    tmp24 = tmp13 - tmp10 + tmp11;
+    tmp11 += tmp11;
+    tmp22 = z1 + tmp11;                     /* c10 = c6-c12 */
+    tmp27 = z1 - tmp11 - tmp11;             /* c0 = (c6-c12)*2 */
+
+    /* Odd part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    z4 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    z3 = MULTIPLY(z4, FIX(1.224744871));                    /* c5 */
+    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+    tmp13 = z2 - z4;
+    tmp15 = MULTIPLY(z1 + tmp13, FIX(0.831253876));         /* c9 */
+    tmp11 = tmp15 + MULTIPLY(z1, FIX(0.513743148));         /* c3-c9 */
+    tmp14 = tmp15 - MULTIPLY(tmp13, FIX(2.176250899));      /* c3+c9 */
+
+    tmp13 = MULTIPLY(z2, - FIX(0.831253876));               /* -c9 */
+    tmp15 = MULTIPLY(z2, - FIX(1.344997024));               /* -c3 */
+    z2 = z1 - z4;
+    tmp12 = z3 + MULTIPLY(z2, FIX(1.406466353));            /* c1 */
+
+    tmp10 = tmp12 + MULTIPLY(z4, FIX(2.457431844)) - tmp15; /* c1+c7 */
+    tmp16 = tmp12 - MULTIPLY(z1, FIX(1.112434820)) + tmp13; /* c1-c13 */
+    tmp12 = MULTIPLY(z2, FIX(1.224744871)) - z3;            /* c5 */
+    z2 = MULTIPLY(z1 + z4, FIX(0.575212477));               /* c11 */
+    tmp13 += z2 + MULTIPLY(z1, FIX(0.475753014)) - z3;      /* c7-c11 */
+    tmp15 += z2 - MULTIPLY(z4, FIX(0.869244010)) + z3;      /* c11+c13 */
+
+    /* Final output stage */
+
+    wsptr[8*0]  = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*14] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*1]  = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[8*13] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[8*2]  = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[8*12] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[8*3]  = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+    wsptr[8*11] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+    wsptr[8*4]  = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+    wsptr[8*10] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+    wsptr[8*5]  = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);
+    wsptr[8*9]  = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);
+    wsptr[8*6]  = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS);
+    wsptr[8*8]  = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS);
+    wsptr[8*7]  = (int) RIGHT_SHIFT(tmp27, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process 15 rows from work array, store into output array. */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 15; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    z1 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    z1 <<= CONST_BITS;
+
+    z2 = (INT32) wsptr[2];
+    z3 = (INT32) wsptr[4];
+    z4 = (INT32) wsptr[6];
+
+    tmp10 = MULTIPLY(z4, FIX(0.437016024)); /* c12 */
+    tmp11 = MULTIPLY(z4, FIX(1.144122806)); /* c6 */
+
+    tmp12 = z1 - tmp10;
+    tmp13 = z1 + tmp11;
+    z1 -= (tmp11 - tmp10) << 1;             /* c0 = (c6-c12)*2 */
+
+    z4 = z2 - z3;
+    z3 += z2;
+    tmp10 = MULTIPLY(z3, FIX(1.337628990)); /* (c2+c4)/2 */
+    tmp11 = MULTIPLY(z4, FIX(0.045680613)); /* (c2-c4)/2 */
+    z2 = MULTIPLY(z2, FIX(1.439773946));    /* c4+c14 */
+
+    tmp20 = tmp13 + tmp10 + tmp11;
+    tmp23 = tmp12 - tmp10 + tmp11 + z2;
+
+    tmp10 = MULTIPLY(z3, FIX(0.547059574)); /* (c8+c14)/2 */
+    tmp11 = MULTIPLY(z4, FIX(0.399234004)); /* (c8-c14)/2 */
+
+    tmp25 = tmp13 - tmp10 - tmp11;
+    tmp26 = tmp12 + tmp10 - tmp11 - z2;
+
+    tmp10 = MULTIPLY(z3, FIX(0.790569415)); /* (c6+c12)/2 */
+    tmp11 = MULTIPLY(z4, FIX(0.353553391)); /* (c6-c12)/2 */
+
+    tmp21 = tmp12 + tmp10 + tmp11;
+    tmp24 = tmp13 - tmp10 + tmp11;
+    tmp11 += tmp11;
+    tmp22 = z1 + tmp11;                     /* c10 = c6-c12 */
+    tmp27 = z1 - tmp11 - tmp11;             /* c0 = (c6-c12)*2 */
+
+    /* Odd part */
+
+    z1 = (INT32) wsptr[1];
+    z2 = (INT32) wsptr[3];
+    z4 = (INT32) wsptr[5];
+    z3 = MULTIPLY(z4, FIX(1.224744871));                    /* c5 */
+    z4 = (INT32) wsptr[7];
+
+    tmp13 = z2 - z4;
+    tmp15 = MULTIPLY(z1 + tmp13, FIX(0.831253876));         /* c9 */
+    tmp11 = tmp15 + MULTIPLY(z1, FIX(0.513743148));         /* c3-c9 */
+    tmp14 = tmp15 - MULTIPLY(tmp13, FIX(2.176250899));      /* c3+c9 */
+
+    tmp13 = MULTIPLY(z2, - FIX(0.831253876));               /* -c9 */
+    tmp15 = MULTIPLY(z2, - FIX(1.344997024));               /* -c3 */
+    z2 = z1 - z4;
+    tmp12 = z3 + MULTIPLY(z2, FIX(1.406466353));            /* c1 */
+
+    tmp10 = tmp12 + MULTIPLY(z4, FIX(2.457431844)) - tmp15; /* c1+c7 */
+    tmp16 = tmp12 - MULTIPLY(z1, FIX(1.112434820)) + tmp13; /* c1-c13 */
+    tmp12 = MULTIPLY(z2, FIX(1.224744871)) - z3;            /* c5 */
+    z2 = MULTIPLY(z1 + z4, FIX(0.575212477));               /* c11 */
+    tmp13 += z2 + MULTIPLY(z1, FIX(0.475753014)) - z3;      /* c7-c11 */
+    tmp15 += z2 - MULTIPLY(z4, FIX(0.869244010)) + z3;      /* c11+c13 */
+
+    /* Final output stage */
+
+    outptr[0]  = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[1]  = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[2]  = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[3]  = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[4]  = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[5]  = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[9]  = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[6]  = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[8]  = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[7]  = range_limit[(int) RIGHT_SHIFT(tmp27,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+
+    wsptr += 8;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 16x16 output block.
+ *
+ * Optimized algorithm with 28 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/32).
+ */
+
+GLOBAL(void)
+jpeg_idct_16x16 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		 JCOEFPTR coef_block,
+		 JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13;
+  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;
+  INT32 z1, z2, z3, z4;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[8*16];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array. */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    tmp0 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    tmp0 += 1 << (CONST_BITS-PASS1_BITS-1);
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    tmp1 = MULTIPLY(z1, FIX(1.306562965));      /* c4[16] = c2[8] */
+    tmp2 = MULTIPLY(z1, FIX_0_541196100);       /* c12[16] = c6[8] */
+
+    tmp10 = tmp0 + tmp1;
+    tmp11 = tmp0 - tmp1;
+    tmp12 = tmp0 + tmp2;
+    tmp13 = tmp0 - tmp2;
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+    z3 = z1 - z2;
+    z4 = MULTIPLY(z3, FIX(0.275899379));        /* c14[16] = c7[8] */
+    z3 = MULTIPLY(z3, FIX(1.387039845));        /* c2[16] = c1[8] */
+
+    tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447);  /* (c6+c2)[16] = (c3+c1)[8] */
+    tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223);  /* (c6-c14)[16] = (c3-c7)[8] */
+    tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */
+    tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */
+
+    tmp20 = tmp10 + tmp0;
+    tmp27 = tmp10 - tmp0;
+    tmp21 = tmp12 + tmp1;
+    tmp26 = tmp12 - tmp1;
+    tmp22 = tmp13 + tmp2;
+    tmp25 = tmp13 - tmp2;
+    tmp23 = tmp11 + tmp3;
+    tmp24 = tmp11 - tmp3;
+
+    /* Odd part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+    tmp11 = z1 + z3;
+
+    tmp1  = MULTIPLY(z1 + z2, FIX(1.353318001));   /* c3 */
+    tmp2  = MULTIPLY(tmp11,   FIX(1.247225013));   /* c5 */
+    tmp3  = MULTIPLY(z1 + z4, FIX(1.093201867));   /* c7 */
+    tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586));   /* c9 */
+    tmp11 = MULTIPLY(tmp11,   FIX(0.666655658));   /* c11 */
+    tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528));   /* c13 */
+    tmp0  = tmp1 + tmp2 + tmp3 -
+	    MULTIPLY(z1, FIX(2.286341144));        /* c7+c5+c3-c1 */
+    tmp13 = tmp10 + tmp11 + tmp12 -
+	    MULTIPLY(z1, FIX(1.835730603));        /* c9+c11+c13-c15 */
+    z1    = MULTIPLY(z2 + z3, FIX(0.138617169));   /* c15 */
+    tmp1  += z1 + MULTIPLY(z2, FIX(0.071888074));  /* c9+c11-c3-c15 */
+    tmp2  += z1 - MULTIPLY(z3, FIX(1.125726048));  /* c5+c7+c15-c3 */
+    z1    = MULTIPLY(z3 - z2, FIX(1.407403738));   /* c1 */
+    tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282));  /* c1+c11-c9-c13 */
+    tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411));  /* c1+c5+c13-c7 */
+    z2    += z4;
+    z1    = MULTIPLY(z2, - FIX(0.666655658));      /* -c11 */
+    tmp1  += z1;
+    tmp3  += z1 + MULTIPLY(z4, FIX(1.065388962));  /* c3+c11+c15-c7 */
+    z2    = MULTIPLY(z2, - FIX(1.247225013));      /* -c5 */
+    tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809));  /* c1+c5+c9-c13 */
+    tmp12 += z2;
+    z2    = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */
+    tmp2  += z2;
+    tmp3  += z2;
+    z2    = MULTIPLY(z4 - z3, FIX(0.410524528));   /* c13 */
+    tmp10 += z2;
+    tmp11 += z2;
+
+    /* Final output stage */
+
+    wsptr[8*0]  = (int) RIGHT_SHIFT(tmp20 + tmp0,  CONST_BITS-PASS1_BITS);
+    wsptr[8*15] = (int) RIGHT_SHIFT(tmp20 - tmp0,  CONST_BITS-PASS1_BITS);
+    wsptr[8*1]  = (int) RIGHT_SHIFT(tmp21 + tmp1,  CONST_BITS-PASS1_BITS);
+    wsptr[8*14] = (int) RIGHT_SHIFT(tmp21 - tmp1,  CONST_BITS-PASS1_BITS);
+    wsptr[8*2]  = (int) RIGHT_SHIFT(tmp22 + tmp2,  CONST_BITS-PASS1_BITS);
+    wsptr[8*13] = (int) RIGHT_SHIFT(tmp22 - tmp2,  CONST_BITS-PASS1_BITS);
+    wsptr[8*3]  = (int) RIGHT_SHIFT(tmp23 + tmp3,  CONST_BITS-PASS1_BITS);
+    wsptr[8*12] = (int) RIGHT_SHIFT(tmp23 - tmp3,  CONST_BITS-PASS1_BITS);
+    wsptr[8*4]  = (int) RIGHT_SHIFT(tmp24 + tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*11] = (int) RIGHT_SHIFT(tmp24 - tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*5]  = (int) RIGHT_SHIFT(tmp25 + tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[8*10] = (int) RIGHT_SHIFT(tmp25 - tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[8*6]  = (int) RIGHT_SHIFT(tmp26 + tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[8*9]  = (int) RIGHT_SHIFT(tmp26 - tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[8*7]  = (int) RIGHT_SHIFT(tmp27 + tmp13, CONST_BITS-PASS1_BITS);
+    wsptr[8*8]  = (int) RIGHT_SHIFT(tmp27 - tmp13, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process 16 rows from work array, store into output array. */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 16; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    tmp0 <<= CONST_BITS;
+
+    z1 = (INT32) wsptr[4];
+    tmp1 = MULTIPLY(z1, FIX(1.306562965));      /* c4[16] = c2[8] */
+    tmp2 = MULTIPLY(z1, FIX_0_541196100);       /* c12[16] = c6[8] */
+
+    tmp10 = tmp0 + tmp1;
+    tmp11 = tmp0 - tmp1;
+    tmp12 = tmp0 + tmp2;
+    tmp13 = tmp0 - tmp2;
+
+    z1 = (INT32) wsptr[2];
+    z2 = (INT32) wsptr[6];
+    z3 = z1 - z2;
+    z4 = MULTIPLY(z3, FIX(0.275899379));        /* c14[16] = c7[8] */
+    z3 = MULTIPLY(z3, FIX(1.387039845));        /* c2[16] = c1[8] */
+
+    tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447);  /* (c6+c2)[16] = (c3+c1)[8] */
+    tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223);  /* (c6-c14)[16] = (c3-c7)[8] */
+    tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */
+    tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */
+
+    tmp20 = tmp10 + tmp0;
+    tmp27 = tmp10 - tmp0;
+    tmp21 = tmp12 + tmp1;
+    tmp26 = tmp12 - tmp1;
+    tmp22 = tmp13 + tmp2;
+    tmp25 = tmp13 - tmp2;
+    tmp23 = tmp11 + tmp3;
+    tmp24 = tmp11 - tmp3;
+
+    /* Odd part */
+
+    z1 = (INT32) wsptr[1];
+    z2 = (INT32) wsptr[3];
+    z3 = (INT32) wsptr[5];
+    z4 = (INT32) wsptr[7];
+
+    tmp11 = z1 + z3;
+
+    tmp1  = MULTIPLY(z1 + z2, FIX(1.353318001));   /* c3 */
+    tmp2  = MULTIPLY(tmp11,   FIX(1.247225013));   /* c5 */
+    tmp3  = MULTIPLY(z1 + z4, FIX(1.093201867));   /* c7 */
+    tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586));   /* c9 */
+    tmp11 = MULTIPLY(tmp11,   FIX(0.666655658));   /* c11 */
+    tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528));   /* c13 */
+    tmp0  = tmp1 + tmp2 + tmp3 -
+	    MULTIPLY(z1, FIX(2.286341144));        /* c7+c5+c3-c1 */
+    tmp13 = tmp10 + tmp11 + tmp12 -
+	    MULTIPLY(z1, FIX(1.835730603));        /* c9+c11+c13-c15 */
+    z1    = MULTIPLY(z2 + z3, FIX(0.138617169));   /* c15 */
+    tmp1  += z1 + MULTIPLY(z2, FIX(0.071888074));  /* c9+c11-c3-c15 */
+    tmp2  += z1 - MULTIPLY(z3, FIX(1.125726048));  /* c5+c7+c15-c3 */
+    z1    = MULTIPLY(z3 - z2, FIX(1.407403738));   /* c1 */
+    tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282));  /* c1+c11-c9-c13 */
+    tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411));  /* c1+c5+c13-c7 */
+    z2    += z4;
+    z1    = MULTIPLY(z2, - FIX(0.666655658));      /* -c11 */
+    tmp1  += z1;
+    tmp3  += z1 + MULTIPLY(z4, FIX(1.065388962));  /* c3+c11+c15-c7 */
+    z2    = MULTIPLY(z2, - FIX(1.247225013));      /* -c5 */
+    tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809));  /* c1+c5+c9-c13 */
+    tmp12 += z2;
+    z2    = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */
+    tmp2  += z2;
+    tmp3  += z2;
+    z2    = MULTIPLY(z4 - z3, FIX(0.410524528));   /* c13 */
+    tmp10 += z2;
+    tmp11 += z2;
+
+    /* Final output stage */
+
+    outptr[0]  = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp0,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[15] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp0,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[1]  = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp1,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp1,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[2]  = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp2,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp2,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[3]  = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp3,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp3,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[4]  = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp10,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp10,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[5]  = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp11,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp11,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[6]  = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp12,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[9]  = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp12,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[7]  = range_limit[(int) RIGHT_SHIFT(tmp27 + tmp13,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[8]  = range_limit[(int) RIGHT_SHIFT(tmp27 - tmp13,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+
+    wsptr += 8;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 16x8 output block.
+ *
+ * 8-point IDCT in pass 1 (columns), 16-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_16x8 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		JCOEFPTR coef_block,
+		JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13;
+  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;
+  INT32 z1, z2, z3, z4;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[8*8];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array.
+   * Note results are scaled up by sqrt(8) compared to a true IDCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * 8-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+   */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = DCTSIZE; ctr > 0; ctr--) {
+    /* Due to quantization, we will usually find that many of the input
+     * coefficients are zero, especially the AC terms.  We can exploit this
+     * by short-circuiting the IDCT calculation for any column in which all
+     * the AC terms are zero.  In that case each output is equal to the
+     * DC coefficient (with scale factor as needed).
+     * With typical images and quantization tables, half or more of the
+     * column DCT calculations can be simplified this way.
+     */
+
+    if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
+	inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
+	inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
+	inptr[DCTSIZE*7] == 0) {
+      /* AC terms all zero */
+      int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;
+
+      wsptr[DCTSIZE*0] = dcval;
+      wsptr[DCTSIZE*1] = dcval;
+      wsptr[DCTSIZE*2] = dcval;
+      wsptr[DCTSIZE*3] = dcval;
+      wsptr[DCTSIZE*4] = dcval;
+      wsptr[DCTSIZE*5] = dcval;
+      wsptr[DCTSIZE*6] = dcval;
+      wsptr[DCTSIZE*7] = dcval;
+
+      inptr++;			/* advance pointers to next column */
+      quantptr++;
+      wsptr++;
+      continue;
+    }
+
+    /* Even part: reverse the even part of the forward DCT.
+     * The rotator is c(-6).
+     */
+
+    z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);       /* c6 */
+    tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);     /* c2-c6 */
+    tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);     /* c2+c6 */
+
+    z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    z2 <<= CONST_BITS;
+    z3 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    z2 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+    tmp0 = z2 + z3;
+    tmp1 = z2 - z3;
+
+    tmp10 = tmp0 + tmp2;
+    tmp13 = tmp0 - tmp2;
+    tmp11 = tmp1 + tmp3;
+    tmp12 = tmp1 - tmp3;
+
+    /* Odd part per figure 8; the matrix is unitary and hence its
+     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.
+     */
+
+    tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+    tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+
+    z2 = tmp0 + tmp2;
+    z3 = tmp1 + tmp3;
+
+    z1 = MULTIPLY(z2 + z3, FIX_1_175875602);       /*  c3 */
+    z2 = MULTIPLY(z2, - FIX_1_961570560);          /* -c3-c5 */
+    z3 = MULTIPLY(z3, - FIX_0_390180644);          /* -c3+c5 */
+    z2 += z1;
+    z3 += z1;
+
+    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */
+    tmp0 = MULTIPLY(tmp0, FIX_0_298631336);        /* -c1+c3+c5-c7 */
+    tmp3 = MULTIPLY(tmp3, FIX_1_501321110);        /*  c1+c3-c5-c7 */
+    tmp0 += z1 + z2;
+    tmp3 += z1 + z3;
+
+    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */
+    tmp1 = MULTIPLY(tmp1, FIX_2_053119869);        /*  c1+c3-c5+c7 */
+    tmp2 = MULTIPLY(tmp2, FIX_3_072711026);        /*  c1+c3+c5-c7 */
+    tmp1 += z1 + z3;
+    tmp2 += z1 + z2;
+
+    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+    wsptr[DCTSIZE*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS);
+    wsptr[DCTSIZE*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS);
+    wsptr[DCTSIZE*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS);
+    wsptr[DCTSIZE*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS);
+    wsptr[DCTSIZE*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS);
+    wsptr[DCTSIZE*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS);
+    wsptr[DCTSIZE*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS);
+    wsptr[DCTSIZE*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS);
+
+    inptr++;			/* advance pointers to next column */
+    quantptr++;
+    wsptr++;
+  }
+
+  /* Pass 2: process 8 rows from work array, store into output array.
+   * 16-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/32).
+   */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 8; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    tmp0 <<= CONST_BITS;
+
+    z1 = (INT32) wsptr[4];
+    tmp1 = MULTIPLY(z1, FIX(1.306562965));      /* c4[16] = c2[8] */
+    tmp2 = MULTIPLY(z1, FIX_0_541196100);       /* c12[16] = c6[8] */
+
+    tmp10 = tmp0 + tmp1;
+    tmp11 = tmp0 - tmp1;
+    tmp12 = tmp0 + tmp2;
+    tmp13 = tmp0 - tmp2;
+
+    z1 = (INT32) wsptr[2];
+    z2 = (INT32) wsptr[6];
+    z3 = z1 - z2;
+    z4 = MULTIPLY(z3, FIX(0.275899379));        /* c14[16] = c7[8] */
+    z3 = MULTIPLY(z3, FIX(1.387039845));        /* c2[16] = c1[8] */
+
+    tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447);  /* (c6+c2)[16] = (c3+c1)[8] */
+    tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223);  /* (c6-c14)[16] = (c3-c7)[8] */
+    tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */
+    tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */
+
+    tmp20 = tmp10 + tmp0;
+    tmp27 = tmp10 - tmp0;
+    tmp21 = tmp12 + tmp1;
+    tmp26 = tmp12 - tmp1;
+    tmp22 = tmp13 + tmp2;
+    tmp25 = tmp13 - tmp2;
+    tmp23 = tmp11 + tmp3;
+    tmp24 = tmp11 - tmp3;
+
+    /* Odd part */
+
+    z1 = (INT32) wsptr[1];
+    z2 = (INT32) wsptr[3];
+    z3 = (INT32) wsptr[5];
+    z4 = (INT32) wsptr[7];
+
+    tmp11 = z1 + z3;
+
+    tmp1  = MULTIPLY(z1 + z2, FIX(1.353318001));   /* c3 */
+    tmp2  = MULTIPLY(tmp11,   FIX(1.247225013));   /* c5 */
+    tmp3  = MULTIPLY(z1 + z4, FIX(1.093201867));   /* c7 */
+    tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586));   /* c9 */
+    tmp11 = MULTIPLY(tmp11,   FIX(0.666655658));   /* c11 */
+    tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528));   /* c13 */
+    tmp0  = tmp1 + tmp2 + tmp3 -
+	    MULTIPLY(z1, FIX(2.286341144));        /* c7+c5+c3-c1 */
+    tmp13 = tmp10 + tmp11 + tmp12 -
+	    MULTIPLY(z1, FIX(1.835730603));        /* c9+c11+c13-c15 */
+    z1    = MULTIPLY(z2 + z3, FIX(0.138617169));   /* c15 */
+    tmp1  += z1 + MULTIPLY(z2, FIX(0.071888074));  /* c9+c11-c3-c15 */
+    tmp2  += z1 - MULTIPLY(z3, FIX(1.125726048));  /* c5+c7+c15-c3 */
+    z1    = MULTIPLY(z3 - z2, FIX(1.407403738));   /* c1 */
+    tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282));  /* c1+c11-c9-c13 */
+    tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411));  /* c1+c5+c13-c7 */
+    z2    += z4;
+    z1    = MULTIPLY(z2, - FIX(0.666655658));      /* -c11 */
+    tmp1  += z1;
+    tmp3  += z1 + MULTIPLY(z4, FIX(1.065388962));  /* c3+c11+c15-c7 */
+    z2    = MULTIPLY(z2, - FIX(1.247225013));      /* -c5 */
+    tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809));  /* c1+c5+c9-c13 */
+    tmp12 += z2;
+    z2    = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */
+    tmp2  += z2;
+    tmp3  += z2;
+    z2    = MULTIPLY(z4 - z3, FIX(0.410524528));   /* c13 */
+    tmp10 += z2;
+    tmp11 += z2;
+
+    /* Final output stage */
+
+    outptr[0]  = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp0,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[15] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp0,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[1]  = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp1,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp1,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[2]  = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp2,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp2,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[3]  = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp3,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp3,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[4]  = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp10,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp10,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[5]  = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp11,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp11,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[6]  = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp12,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[9]  = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp12,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[7]  = range_limit[(int) RIGHT_SHIFT(tmp27 + tmp13,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[8]  = range_limit[(int) RIGHT_SHIFT(tmp27 - tmp13,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+
+    wsptr += 8;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 14x7 output block.
+ *
+ * 7-point IDCT in pass 1 (columns), 14-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_14x7 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		JCOEFPTR coef_block,
+		JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;
+  INT32 z1, z2, z3, z4;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[8*7];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array.
+   * 7-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/14).
+   */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    tmp23 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    tmp23 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    tmp23 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+    tmp20 = MULTIPLY(z2 - z3, FIX(0.881747734));       /* c4 */
+    tmp22 = MULTIPLY(z1 - z2, FIX(0.314692123));       /* c6 */
+    tmp21 = tmp20 + tmp22 + tmp23 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */
+    tmp10 = z1 + z3;
+    z2 -= tmp10;
+    tmp10 = MULTIPLY(tmp10, FIX(1.274162392)) + tmp23; /* c2 */
+    tmp20 += tmp10 - MULTIPLY(z3, FIX(0.077722536));   /* c2-c4-c6 */
+    tmp22 += tmp10 - MULTIPLY(z1, FIX(2.470602249));   /* c2+c4+c6 */
+    tmp23 += MULTIPLY(z2, FIX(1.414213562));           /* c0 */
+
+    /* Odd part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+
+    tmp11 = MULTIPLY(z1 + z2, FIX(0.935414347));       /* (c3+c1-c5)/2 */
+    tmp12 = MULTIPLY(z1 - z2, FIX(0.170262339));       /* (c3+c5-c1)/2 */
+    tmp10 = tmp11 - tmp12;
+    tmp11 += tmp12;
+    tmp12 = MULTIPLY(z2 + z3, - FIX(1.378756276));     /* -c1 */
+    tmp11 += tmp12;
+    z2 = MULTIPLY(z1 + z3, FIX(0.613604268));          /* c5 */
+    tmp10 += z2;
+    tmp12 += z2 + MULTIPLY(z3, FIX(1.870828693));      /* c3+c1-c5 */
+
+    /* Final output stage */
+
+    wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*6] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[8*5] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[8*4] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[8*3] = (int) RIGHT_SHIFT(tmp23, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process 7 rows from work array, store into output array.
+   * 14-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/28).
+   */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 7; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    z1 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    z1 <<= CONST_BITS;
+    z4 = (INT32) wsptr[4];
+    z2 = MULTIPLY(z4, FIX(1.274162392));         /* c4 */
+    z3 = MULTIPLY(z4, FIX(0.314692123));         /* c12 */
+    z4 = MULTIPLY(z4, FIX(0.881747734));         /* c8 */
+
+    tmp10 = z1 + z2;
+    tmp11 = z1 + z3;
+    tmp12 = z1 - z4;
+
+    tmp23 = z1 - ((z2 + z3 - z4) << 1);          /* c0 = (c4+c12-c8)*2 */
+
+    z1 = (INT32) wsptr[2];
+    z2 = (INT32) wsptr[6];
+
+    z3 = MULTIPLY(z1 + z2, FIX(1.105676686));    /* c6 */
+
+    tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */
+    tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */
+    tmp15 = MULTIPLY(z1, FIX(0.613604268)) -     /* c10 */
+	    MULTIPLY(z2, FIX(1.378756276));      /* c2 */
+
+    tmp20 = tmp10 + tmp13;
+    tmp26 = tmp10 - tmp13;
+    tmp21 = tmp11 + tmp14;
+    tmp25 = tmp11 - tmp14;
+    tmp22 = tmp12 + tmp15;
+    tmp24 = tmp12 - tmp15;
+
+    /* Odd part */
+
+    z1 = (INT32) wsptr[1];
+    z2 = (INT32) wsptr[3];
+    z3 = (INT32) wsptr[5];
+    z4 = (INT32) wsptr[7];
+    z4 <<= CONST_BITS;
+
+    tmp14 = z1 + z3;
+    tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607));           /* c3 */
+    tmp12 = MULTIPLY(tmp14, FIX(1.197448846));             /* c5 */
+    tmp10 = tmp11 + tmp12 + z4 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */
+    tmp14 = MULTIPLY(tmp14, FIX(0.752406978));             /* c9 */
+    tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426));        /* c9+c11-c13 */
+    z1    -= z2;
+    tmp15 = MULTIPLY(z1, FIX(0.467085129)) - z4;           /* c11 */
+    tmp16 += tmp15;
+    tmp13 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - z4;    /* -c13 */
+    tmp11 += tmp13 - MULTIPLY(z2, FIX(0.424103948));       /* c3-c9-c13 */
+    tmp12 += tmp13 - MULTIPLY(z3, FIX(2.373959773));       /* c3+c5-c13 */
+    tmp13 = MULTIPLY(z3 - z2, FIX(1.405321284));           /* c1 */
+    tmp14 += tmp13 + z4 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */
+    tmp15 += tmp13 + MULTIPLY(z2, FIX(0.674957567));       /* c1+c11-c5 */
+
+    tmp13 = ((z1 - z3) << CONST_BITS) + z4;
+
+    /* Final output stage */
+
+    outptr[0]  = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[1]  = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[2]  = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[3]  = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[4]  = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[9]  = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[5]  = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[8]  = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[6]  = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[7]  = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+
+    wsptr += 8;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 12x6 output block.
+ *
+ * 6-point IDCT in pass 1 (columns), 12-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_12x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		JCOEFPTR coef_block,
+		JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;
+  INT32 z1, z2, z3, z4;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[8*6];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array.
+   * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12).
+   */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    tmp10 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    tmp10 += ONE << (CONST_BITS-PASS1_BITS-1);
+    tmp12 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    tmp20 = MULTIPLY(tmp12, FIX(0.707106781));   /* c4 */
+    tmp11 = tmp10 + tmp20;
+    tmp21 = RIGHT_SHIFT(tmp10 - tmp20 - tmp20, CONST_BITS-PASS1_BITS);
+    tmp20 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    tmp10 = MULTIPLY(tmp20, FIX(1.224744871));   /* c2 */
+    tmp20 = tmp11 + tmp10;
+    tmp22 = tmp11 - tmp10;
+
+    /* Odd part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    tmp11 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */
+    tmp10 = tmp11 + ((z1 + z2) << CONST_BITS);
+    tmp12 = tmp11 + ((z3 - z2) << CONST_BITS);
+    tmp11 = (z1 - z2 - z3) << PASS1_BITS;
+
+    /* Final output stage */
+
+    wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*5] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*1] = (int) (tmp21 + tmp11);
+    wsptr[8*4] = (int) (tmp21 - tmp11);
+    wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[8*3] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process 6 rows from work array, store into output array.
+   * 12-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/24).
+   */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 6; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    z3 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    z3 <<= CONST_BITS;
+
+    z4 = (INT32) wsptr[4];
+    z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */
+
+    tmp10 = z3 + z4;
+    tmp11 = z3 - z4;
+
+    z1 = (INT32) wsptr[2];
+    z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */
+    z1 <<= CONST_BITS;
+    z2 = (INT32) wsptr[6];
+    z2 <<= CONST_BITS;
+
+    tmp12 = z1 - z2;
+
+    tmp21 = z3 + tmp12;
+    tmp24 = z3 - tmp12;
+
+    tmp12 = z4 + z2;
+
+    tmp20 = tmp10 + tmp12;
+    tmp25 = tmp10 - tmp12;
+
+    tmp12 = z4 - z1 - z2;
+
+    tmp22 = tmp11 + tmp12;
+    tmp23 = tmp11 - tmp12;
+
+    /* Odd part */
+
+    z1 = (INT32) wsptr[1];
+    z2 = (INT32) wsptr[3];
+    z3 = (INT32) wsptr[5];
+    z4 = (INT32) wsptr[7];
+
+    tmp11 = MULTIPLY(z2, FIX(1.306562965));                  /* c3 */
+    tmp14 = MULTIPLY(z2, - FIX_0_541196100);                 /* -c9 */
+
+    tmp10 = z1 + z3;
+    tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669));          /* c7 */
+    tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384));       /* c5-c7 */
+    tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716));  /* c1-c5 */
+    tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580));           /* -(c7+c11) */
+    tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */
+    tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */
+    tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) -        /* c7-c11 */
+	     MULTIPLY(z4, FIX(1.982889723));                 /* c5+c7 */
+
+    z1 -= z4;
+    z2 -= z3;
+    z3 = MULTIPLY(z1 + z2, FIX_0_541196100);                 /* c9 */
+    tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865);              /* c3-c9 */
+    tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065);              /* c3+c9 */
+
+    /* Final output stage */
+
+    outptr[0]  = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[1]  = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[2]  = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[9]  = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[3]  = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[8]  = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[4]  = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[7]  = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[5]  = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+    outptr[6]  = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,
+					       CONST_BITS+PASS1_BITS+3)
+			     & RANGE_MASK];
+
+    wsptr += 8;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 10x5 output block.
+ *
+ * 5-point IDCT in pass 1 (columns), 10-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_10x5 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		JCOEFPTR coef_block,
+		JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+  INT32 tmp20, tmp21, tmp22, tmp23, tmp24;
+  INT32 z1, z2, z3, z4;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[8*5];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array.
+   * 5-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/10).
+   */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    tmp12 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    tmp12 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    tmp12 += ONE << (CONST_BITS-PASS1_BITS-1);
+    tmp13 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    tmp14 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    z1 = MULTIPLY(tmp13 + tmp14, FIX(0.790569415)); /* (c2+c4)/2 */
+    z2 = MULTIPLY(tmp13 - tmp14, FIX(0.353553391)); /* (c2-c4)/2 */
+    z3 = tmp12 + z2;
+    tmp10 = z3 + z1;
+    tmp11 = z3 - z1;
+    tmp12 -= z2 << 2;
+
+    /* Odd part */
+
+    z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+
+    z1 = MULTIPLY(z2 + z3, FIX(0.831253876));       /* c3 */
+    tmp13 = z1 + MULTIPLY(z2, FIX(0.513743148));    /* c1-c3 */
+    tmp14 = z1 - MULTIPLY(z3, FIX(2.176250899));    /* c1+c3 */
+
+    /* Final output stage */
+
+    wsptr[8*0] = (int) RIGHT_SHIFT(tmp10 + tmp13, CONST_BITS-PASS1_BITS);
+    wsptr[8*4] = (int) RIGHT_SHIFT(tmp10 - tmp13, CONST_BITS-PASS1_BITS);
+    wsptr[8*1] = (int) RIGHT_SHIFT(tmp11 + tmp14, CONST_BITS-PASS1_BITS);
+    wsptr[8*3] = (int) RIGHT_SHIFT(tmp11 - tmp14, CONST_BITS-PASS1_BITS);
+    wsptr[8*2] = (int) RIGHT_SHIFT(tmp12, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process 5 rows from work array, store into output array.
+   * 10-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/20).
+   */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 5; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    z3 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    z3 <<= CONST_BITS;
+    z4 = (INT32) wsptr[4];
+    z1 = MULTIPLY(z4, FIX(1.144122806));         /* c4 */
+    z2 = MULTIPLY(z4, FIX(0.437016024));         /* c8 */
+    tmp10 = z3 + z1;
+    tmp11 = z3 - z2;
+
+    tmp22 = z3 - ((z1 - z2) << 1);               /* c0 = (c4-c8)*2 */
+
+    z2 = (INT32) wsptr[2];
+    z3 = (INT32) wsptr[6];
+
+    z1 = MULTIPLY(z2 + z3, FIX(0.831253876));    /* c6 */
+    tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */
+    tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */
+
+    tmp20 = tmp10 + tmp12;
+    tmp24 = tmp10 - tmp12;
+    tmp21 = tmp11 + tmp13;
+    tmp23 = tmp11 - tmp13;
+
+    /* Odd part */
+
+    z1 = (INT32) wsptr[1];
+    z2 = (INT32) wsptr[3];
+    z3 = (INT32) wsptr[5];
+    z3 <<= CONST_BITS;
+    z4 = (INT32) wsptr[7];
+
+    tmp11 = z2 + z4;
+    tmp13 = z2 - z4;
+
+    tmp12 = MULTIPLY(tmp13, FIX(0.309016994));        /* (c3-c7)/2 */
+
+    z2 = MULTIPLY(tmp11, FIX(0.951056516));           /* (c3+c7)/2 */
+    z4 = z3 + tmp12;
+
+    tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */
+    tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */
+
+    z2 = MULTIPLY(tmp11, FIX(0.587785252));           /* (c1-c9)/2 */
+    z4 = z3 - tmp12 - (tmp13 << (CONST_BITS - 1));
+
+    tmp12 = ((z1 - tmp13) << CONST_BITS) - z3;
+
+    tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */
+    tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */
+
+    /* Final output stage */
+
+    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += 8;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 8x4 output block.
+ *
+ * 4-point IDCT in pass 1 (columns), 8-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_8x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	       JCOEFPTR coef_block,
+	       JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3;
+  INT32 tmp10, tmp11, tmp12, tmp13;
+  INT32 z1, z2, z3;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[8*4];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array.
+   * 4-point IDCT kernel,
+   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT].
+   */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+
+    tmp10 = (tmp0 + tmp2) << PASS1_BITS;
+    tmp12 = (tmp0 - tmp2) << PASS1_BITS;
+
+    /* Odd part */
+    /* Same rotation as in the even part of the 8x8 LL&M IDCT */
+
+    z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+
+    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);               /* c6 */
+    /* Add fudge factor here for final descale. */
+    z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+    tmp0 = RIGHT_SHIFT(z1 + MULTIPLY(z2, FIX_0_765366865), /* c2-c6 */
+		       CONST_BITS-PASS1_BITS);
+    tmp2 = RIGHT_SHIFT(z1 - MULTIPLY(z3, FIX_1_847759065), /* c2+c6 */
+		       CONST_BITS-PASS1_BITS);
+
+    /* Final output stage */
+
+    wsptr[8*0] = (int) (tmp10 + tmp0);
+    wsptr[8*3] = (int) (tmp10 - tmp0);
+    wsptr[8*1] = (int) (tmp12 + tmp2);
+    wsptr[8*2] = (int) (tmp12 - tmp2);
+  }
+
+  /* Pass 2: process rows from work array, store into output array.
+   * Note that we must descale the results by a factor of 8 == 2**3,
+   * and also undo the PASS1_BITS scaling.
+   * 8-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+   */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 4; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part: reverse the even part of the forward DCT.
+     * The rotator is c(-6).
+     */
+
+    z2 = (INT32) wsptr[2];
+    z3 = (INT32) wsptr[6];
+
+    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);       /* c6 */
+    tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);     /* c2-c6 */
+    tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);     /* c2+c6 */
+
+    /* Add fudge factor here for final descale. */
+    z2 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    z3 = (INT32) wsptr[4];
+
+    tmp0 = (z2 + z3) << CONST_BITS;
+    tmp1 = (z2 - z3) << CONST_BITS;
+
+    tmp10 = tmp0 + tmp2;
+    tmp13 = tmp0 - tmp2;
+    tmp11 = tmp1 + tmp3;
+    tmp12 = tmp1 - tmp3;
+
+    /* Odd part per figure 8; the matrix is unitary and hence its
+     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.
+     */
+
+    tmp0 = (INT32) wsptr[7];
+    tmp1 = (INT32) wsptr[5];
+    tmp2 = (INT32) wsptr[3];
+    tmp3 = (INT32) wsptr[1];
+
+    z2 = tmp0 + tmp2;
+    z3 = tmp1 + tmp3;
+
+    z1 = MULTIPLY(z2 + z3, FIX_1_175875602);       /*  c3 */
+    z2 = MULTIPLY(z2, - FIX_1_961570560);          /* -c3-c5 */
+    z3 = MULTIPLY(z3, - FIX_0_390180644);          /* -c3+c5 */
+    z2 += z1;
+    z3 += z1;
+
+    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */
+    tmp0 = MULTIPLY(tmp0, FIX_0_298631336);        /* -c1+c3+c5-c7 */
+    tmp3 = MULTIPLY(tmp3, FIX_1_501321110);        /*  c1+c3-c5-c7 */
+    tmp0 += z1 + z2;
+    tmp3 += z1 + z3;
+
+    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */
+    tmp1 = MULTIPLY(tmp1, FIX_2_053119869);        /*  c1+c3-c5+c7 */
+    tmp2 = MULTIPLY(tmp2, FIX_3_072711026);        /*  c1+c3+c5-c7 */
+    tmp1 += z1 + z3;
+    tmp2 += z1 + z2;
+
+    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += DCTSIZE;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 6x3 output block.
+ *
+ * 3-point IDCT in pass 1 (columns), 6-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_6x3 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	       JCOEFPTR coef_block,
+	       JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12;
+  INT32 z1, z2, z3;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[6*3];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array.
+   * 3-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/6).
+   */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    tmp0 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);
+    tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */
+    tmp10 = tmp0 + tmp12;
+    tmp2 = tmp0 - tmp12 - tmp12;
+
+    /* Odd part */
+
+    tmp12 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */
+
+    /* Final output stage */
+
+    wsptr[6*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+    wsptr[6*2] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+    wsptr[6*1] = (int) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS);
+  }
+  
+  /* Pass 2: process 3 rows from work array, store into output array.
+   * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12).
+   */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 3; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    tmp0 <<= CONST_BITS;
+    tmp2 = (INT32) wsptr[4];
+    tmp10 = MULTIPLY(tmp2, FIX(0.707106781));   /* c4 */
+    tmp1 = tmp0 + tmp10;
+    tmp11 = tmp0 - tmp10 - tmp10;
+    tmp10 = (INT32) wsptr[2];
+    tmp0 = MULTIPLY(tmp10, FIX(1.224744871));   /* c2 */
+    tmp10 = tmp1 + tmp0;
+    tmp12 = tmp1 - tmp0;
+
+    /* Odd part */
+
+    z1 = (INT32) wsptr[1];
+    z2 = (INT32) wsptr[3];
+    z3 = (INT32) wsptr[5];
+    tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */
+    tmp0 = tmp1 + ((z1 + z2) << CONST_BITS);
+    tmp2 = tmp1 + ((z3 - z2) << CONST_BITS);
+    tmp1 = (z1 - z2 - z3) << CONST_BITS;
+
+    /* Final output stage */
+
+    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += 6;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 4x2 output block.
+ *
+ * 2-point IDCT in pass 1 (columns), 4-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_4x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	       JCOEFPTR coef_block,
+	       JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp0, tmp2, tmp10, tmp12;
+  INT32 z1, z2, z3;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  INT32 * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  INT32 workspace[4*2];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array. */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 4; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+
+    /* Odd part */
+
+    tmp0 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+
+    /* Final output stage */
+
+    wsptr[4*0] = tmp10 + tmp0;
+    wsptr[4*1] = tmp10 - tmp0;
+  }
+
+  /* Pass 2: process 2 rows from work array, store into output array.
+   * 4-point IDCT kernel,
+   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT].
+   */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 2; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp0 = wsptr[0] + (ONE << 2);
+    tmp2 = wsptr[2];
+
+    tmp10 = (tmp0 + tmp2) << CONST_BITS;
+    tmp12 = (tmp0 - tmp2) << CONST_BITS;
+
+    /* Odd part */
+    /* Same rotation as in the even part of the 8x8 LL&M IDCT */
+
+    z2 = wsptr[1];
+    z3 = wsptr[3];
+
+    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);   /* c6 */
+    tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */
+    tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */
+
+    /* Final output stage */
+
+    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+					      CONST_BITS+3)
+			    & RANGE_MASK];
+    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+					      CONST_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+					      CONST_BITS+3)
+			    & RANGE_MASK];
+    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+					      CONST_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += 4;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 2x1 output block.
+ *
+ * 1-point IDCT in pass 1 (columns), 2-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_2x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	       JCOEFPTR coef_block,
+	       JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp0, tmp1;
+  ISLOW_MULT_TYPE * quantptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  SHIFT_TEMPS
+
+  /* Pass 1: empty. */
+
+  /* Pass 2: process 1 row from input, store into output array. */
+
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  outptr = output_buf[0] + output_col;
+
+  /* Even part */
+
+  tmp0 = DEQUANTIZE(coef_block[0], quantptr[0]);
+  /* Add fudge factor here for final descale. */
+  tmp0 += ONE << 2;
+
+  /* Odd part */
+
+  tmp1 = DEQUANTIZE(coef_block[1], quantptr[1]);
+
+  /* Final output stage */
+
+  outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp0 + tmp1, 3) & RANGE_MASK];
+  outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp0 - tmp1, 3) & RANGE_MASK];
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 8x16 output block.
+ *
+ * 16-point IDCT in pass 1 (columns), 8-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_8x16 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		JCOEFPTR coef_block,
+		JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13;
+  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;
+  INT32 z1, z2, z3, z4;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[8*16];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array.
+   * 16-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/32).
+   */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    tmp0 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    tmp1 = MULTIPLY(z1, FIX(1.306562965));      /* c4[16] = c2[8] */
+    tmp2 = MULTIPLY(z1, FIX_0_541196100);       /* c12[16] = c6[8] */
+
+    tmp10 = tmp0 + tmp1;
+    tmp11 = tmp0 - tmp1;
+    tmp12 = tmp0 + tmp2;
+    tmp13 = tmp0 - tmp2;
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+    z3 = z1 - z2;
+    z4 = MULTIPLY(z3, FIX(0.275899379));        /* c14[16] = c7[8] */
+    z3 = MULTIPLY(z3, FIX(1.387039845));        /* c2[16] = c1[8] */
+
+    tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447);  /* (c6+c2)[16] = (c3+c1)[8] */
+    tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223);  /* (c6-c14)[16] = (c3-c7)[8] */
+    tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */
+    tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */
+
+    tmp20 = tmp10 + tmp0;
+    tmp27 = tmp10 - tmp0;
+    tmp21 = tmp12 + tmp1;
+    tmp26 = tmp12 - tmp1;
+    tmp22 = tmp13 + tmp2;
+    tmp25 = tmp13 - tmp2;
+    tmp23 = tmp11 + tmp3;
+    tmp24 = tmp11 - tmp3;
+
+    /* Odd part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+    tmp11 = z1 + z3;
+
+    tmp1  = MULTIPLY(z1 + z2, FIX(1.353318001));   /* c3 */
+    tmp2  = MULTIPLY(tmp11,   FIX(1.247225013));   /* c5 */
+    tmp3  = MULTIPLY(z1 + z4, FIX(1.093201867));   /* c7 */
+    tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586));   /* c9 */
+    tmp11 = MULTIPLY(tmp11,   FIX(0.666655658));   /* c11 */
+    tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528));   /* c13 */
+    tmp0  = tmp1 + tmp2 + tmp3 -
+	    MULTIPLY(z1, FIX(2.286341144));        /* c7+c5+c3-c1 */
+    tmp13 = tmp10 + tmp11 + tmp12 -
+	    MULTIPLY(z1, FIX(1.835730603));        /* c9+c11+c13-c15 */
+    z1    = MULTIPLY(z2 + z3, FIX(0.138617169));   /* c15 */
+    tmp1  += z1 + MULTIPLY(z2, FIX(0.071888074));  /* c9+c11-c3-c15 */
+    tmp2  += z1 - MULTIPLY(z3, FIX(1.125726048));  /* c5+c7+c15-c3 */
+    z1    = MULTIPLY(z3 - z2, FIX(1.407403738));   /* c1 */
+    tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282));  /* c1+c11-c9-c13 */
+    tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411));  /* c1+c5+c13-c7 */
+    z2    += z4;
+    z1    = MULTIPLY(z2, - FIX(0.666655658));      /* -c11 */
+    tmp1  += z1;
+    tmp3  += z1 + MULTIPLY(z4, FIX(1.065388962));  /* c3+c11+c15-c7 */
+    z2    = MULTIPLY(z2, - FIX(1.247225013));      /* -c5 */
+    tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809));  /* c1+c5+c9-c13 */
+    tmp12 += z2;
+    z2    = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */
+    tmp2  += z2;
+    tmp3  += z2;
+    z2    = MULTIPLY(z4 - z3, FIX(0.410524528));   /* c13 */
+    tmp10 += z2;
+    tmp11 += z2;
+
+    /* Final output stage */
+
+    wsptr[8*0]  = (int) RIGHT_SHIFT(tmp20 + tmp0,  CONST_BITS-PASS1_BITS);
+    wsptr[8*15] = (int) RIGHT_SHIFT(tmp20 - tmp0,  CONST_BITS-PASS1_BITS);
+    wsptr[8*1]  = (int) RIGHT_SHIFT(tmp21 + tmp1,  CONST_BITS-PASS1_BITS);
+    wsptr[8*14] = (int) RIGHT_SHIFT(tmp21 - tmp1,  CONST_BITS-PASS1_BITS);
+    wsptr[8*2]  = (int) RIGHT_SHIFT(tmp22 + tmp2,  CONST_BITS-PASS1_BITS);
+    wsptr[8*13] = (int) RIGHT_SHIFT(tmp22 - tmp2,  CONST_BITS-PASS1_BITS);
+    wsptr[8*3]  = (int) RIGHT_SHIFT(tmp23 + tmp3,  CONST_BITS-PASS1_BITS);
+    wsptr[8*12] = (int) RIGHT_SHIFT(tmp23 - tmp3,  CONST_BITS-PASS1_BITS);
+    wsptr[8*4]  = (int) RIGHT_SHIFT(tmp24 + tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*11] = (int) RIGHT_SHIFT(tmp24 - tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[8*5]  = (int) RIGHT_SHIFT(tmp25 + tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[8*10] = (int) RIGHT_SHIFT(tmp25 - tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[8*6]  = (int) RIGHT_SHIFT(tmp26 + tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[8*9]  = (int) RIGHT_SHIFT(tmp26 - tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[8*7]  = (int) RIGHT_SHIFT(tmp27 + tmp13, CONST_BITS-PASS1_BITS);
+    wsptr[8*8]  = (int) RIGHT_SHIFT(tmp27 - tmp13, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process rows from work array, store into output array.
+   * Note that we must descale the results by a factor of 8 == 2**3,
+   * and also undo the PASS1_BITS scaling.
+   * 8-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+   */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 16; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part: reverse the even part of the forward DCT.
+     * The rotator is c(-6).
+     */
+
+    z2 = (INT32) wsptr[2];
+    z3 = (INT32) wsptr[6];
+
+    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);       /* c6 */
+    tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);     /* c2-c6 */
+    tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);     /* c2+c6 */
+
+    /* Add fudge factor here for final descale. */
+    z2 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    z3 = (INT32) wsptr[4];
+
+    tmp0 = (z2 + z3) << CONST_BITS;
+    tmp1 = (z2 - z3) << CONST_BITS;
+
+    tmp10 = tmp0 + tmp2;
+    tmp13 = tmp0 - tmp2;
+    tmp11 = tmp1 + tmp3;
+    tmp12 = tmp1 - tmp3;
+
+    /* Odd part per figure 8; the matrix is unitary and hence its
+     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.
+     */
+
+    tmp0 = (INT32) wsptr[7];
+    tmp1 = (INT32) wsptr[5];
+    tmp2 = (INT32) wsptr[3];
+    tmp3 = (INT32) wsptr[1];
+
+    z2 = tmp0 + tmp2;
+    z3 = tmp1 + tmp3;
+
+    z1 = MULTIPLY(z2 + z3, FIX_1_175875602);       /*  c3 */
+    z2 = MULTIPLY(z2, - FIX_1_961570560);          /* -c3-c5 */
+    z3 = MULTIPLY(z3, - FIX_0_390180644);          /* -c3+c5 */
+    z2 += z1;
+    z3 += z1;
+
+    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */
+    tmp0 = MULTIPLY(tmp0, FIX_0_298631336);        /* -c1+c3+c5-c7 */
+    tmp3 = MULTIPLY(tmp3, FIX_1_501321110);        /*  c1+c3-c5-c7 */
+    tmp0 += z1 + z2;
+    tmp3 += z1 + z3;
+
+    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */
+    tmp1 = MULTIPLY(tmp1, FIX_2_053119869);        /*  c1+c3-c5+c7 */
+    tmp2 = MULTIPLY(tmp2, FIX_3_072711026);        /*  c1+c3+c5-c7 */
+    tmp1 += z1 + z3;
+    tmp2 += z1 + z2;
+
+    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += DCTSIZE;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 7x14 output block.
+ *
+ * 14-point IDCT in pass 1 (columns), 7-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_7x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		JCOEFPTR coef_block,
+		JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;
+  INT32 z1, z2, z3, z4;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[7*14];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array.
+   * 14-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/28).
+   */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 7; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    z1 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+    z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    z2 = MULTIPLY(z4, FIX(1.274162392));         /* c4 */
+    z3 = MULTIPLY(z4, FIX(0.314692123));         /* c12 */
+    z4 = MULTIPLY(z4, FIX(0.881747734));         /* c8 */
+
+    tmp10 = z1 + z2;
+    tmp11 = z1 + z3;
+    tmp12 = z1 - z4;
+
+    tmp23 = RIGHT_SHIFT(z1 - ((z2 + z3 - z4) << 1), /* c0 = (c4+c12-c8)*2 */
+			CONST_BITS-PASS1_BITS);
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+    z3 = MULTIPLY(z1 + z2, FIX(1.105676686));    /* c6 */
+
+    tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */
+    tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */
+    tmp15 = MULTIPLY(z1, FIX(0.613604268)) -     /* c10 */
+	    MULTIPLY(z2, FIX(1.378756276));      /* c2 */
+
+    tmp20 = tmp10 + tmp13;
+    tmp26 = tmp10 - tmp13;
+    tmp21 = tmp11 + tmp14;
+    tmp25 = tmp11 - tmp14;
+    tmp22 = tmp12 + tmp15;
+    tmp24 = tmp12 - tmp15;
+
+    /* Odd part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+    tmp13 = z4 << CONST_BITS;
+
+    tmp14 = z1 + z3;
+    tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607));           /* c3 */
+    tmp12 = MULTIPLY(tmp14, FIX(1.197448846));             /* c5 */
+    tmp10 = tmp11 + tmp12 + tmp13 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */
+    tmp14 = MULTIPLY(tmp14, FIX(0.752406978));             /* c9 */
+    tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426));        /* c9+c11-c13 */
+    z1    -= z2;
+    tmp15 = MULTIPLY(z1, FIX(0.467085129)) - tmp13;        /* c11 */
+    tmp16 += tmp15;
+    z1    += z4;
+    z4    = MULTIPLY(z2 + z3, - FIX(0.158341681)) - tmp13; /* -c13 */
+    tmp11 += z4 - MULTIPLY(z2, FIX(0.424103948));          /* c3-c9-c13 */
+    tmp12 += z4 - MULTIPLY(z3, FIX(2.373959773));          /* c3+c5-c13 */
+    z4    = MULTIPLY(z3 - z2, FIX(1.405321284));           /* c1 */
+    tmp14 += z4 + tmp13 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */
+    tmp15 += z4 + MULTIPLY(z2, FIX(0.674957567));          /* c1+c11-c5 */
+
+    tmp13 = (z1 - z3) << PASS1_BITS;
+
+    /* Final output stage */
+
+    wsptr[7*0]  = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[7*13] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[7*1]  = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[7*12] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[7*2]  = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[7*11] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[7*3]  = (int) (tmp23 + tmp13);
+    wsptr[7*10] = (int) (tmp23 - tmp13);
+    wsptr[7*4]  = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+    wsptr[7*9]  = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+    wsptr[7*5]  = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);
+    wsptr[7*8]  = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);
+    wsptr[7*6]  = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS);
+    wsptr[7*7]  = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process 14 rows from work array, store into output array.
+   * 7-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/14).
+   */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 14; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp23 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    tmp23 <<= CONST_BITS;
+
+    z1 = (INT32) wsptr[2];
+    z2 = (INT32) wsptr[4];
+    z3 = (INT32) wsptr[6];
+
+    tmp20 = MULTIPLY(z2 - z3, FIX(0.881747734));       /* c4 */
+    tmp22 = MULTIPLY(z1 - z2, FIX(0.314692123));       /* c6 */
+    tmp21 = tmp20 + tmp22 + tmp23 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */
+    tmp10 = z1 + z3;
+    z2 -= tmp10;
+    tmp10 = MULTIPLY(tmp10, FIX(1.274162392)) + tmp23; /* c2 */
+    tmp20 += tmp10 - MULTIPLY(z3, FIX(0.077722536));   /* c2-c4-c6 */
+    tmp22 += tmp10 - MULTIPLY(z1, FIX(2.470602249));   /* c2+c4+c6 */
+    tmp23 += MULTIPLY(z2, FIX(1.414213562));           /* c0 */
+
+    /* Odd part */
+
+    z1 = (INT32) wsptr[1];
+    z2 = (INT32) wsptr[3];
+    z3 = (INT32) wsptr[5];
+
+    tmp11 = MULTIPLY(z1 + z2, FIX(0.935414347));       /* (c3+c1-c5)/2 */
+    tmp12 = MULTIPLY(z1 - z2, FIX(0.170262339));       /* (c3+c5-c1)/2 */
+    tmp10 = tmp11 - tmp12;
+    tmp11 += tmp12;
+    tmp12 = MULTIPLY(z2 + z3, - FIX(1.378756276));     /* -c1 */
+    tmp11 += tmp12;
+    z2 = MULTIPLY(z1 + z3, FIX(0.613604268));          /* c5 */
+    tmp10 += z2;
+    tmp12 += z2 + MULTIPLY(z3, FIX(1.870828693));      /* c3+c1-c5 */
+
+    /* Final output stage */
+
+    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += 7;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 6x12 output block.
+ *
+ * 12-point IDCT in pass 1 (columns), 6-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_6x12 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		JCOEFPTR coef_block,
+		JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;
+  INT32 z1, z2, z3, z4;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[6*12];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array.
+   * 12-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/24).
+   */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    z3 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    z3 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+    z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */
+
+    tmp10 = z3 + z4;
+    tmp11 = z3 - z4;
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */
+    z1 <<= CONST_BITS;
+    z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+    z2 <<= CONST_BITS;
+
+    tmp12 = z1 - z2;
+
+    tmp21 = z3 + tmp12;
+    tmp24 = z3 - tmp12;
+
+    tmp12 = z4 + z2;
+
+    tmp20 = tmp10 + tmp12;
+    tmp25 = tmp10 - tmp12;
+
+    tmp12 = z4 - z1 - z2;
+
+    tmp22 = tmp11 + tmp12;
+    tmp23 = tmp11 - tmp12;
+
+    /* Odd part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+    tmp11 = MULTIPLY(z2, FIX(1.306562965));                  /* c3 */
+    tmp14 = MULTIPLY(z2, - FIX_0_541196100);                 /* -c9 */
+
+    tmp10 = z1 + z3;
+    tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669));          /* c7 */
+    tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384));       /* c5-c7 */
+    tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716));  /* c1-c5 */
+    tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580));           /* -(c7+c11) */
+    tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */
+    tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */
+    tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) -        /* c7-c11 */
+	     MULTIPLY(z4, FIX(1.982889723));                 /* c5+c7 */
+
+    z1 -= z4;
+    z2 -= z3;
+    z3 = MULTIPLY(z1 + z2, FIX_0_541196100);                 /* c9 */
+    tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865);              /* c3-c9 */
+    tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065);              /* c3+c9 */
+
+    /* Final output stage */
+
+    wsptr[6*0]  = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[6*11] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[6*1]  = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[6*10] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[6*2]  = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[6*9]  = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+    wsptr[6*3]  = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+    wsptr[6*8]  = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+    wsptr[6*4]  = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+    wsptr[6*7]  = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+    wsptr[6*5]  = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);
+    wsptr[6*6]  = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process 12 rows from work array, store into output array.
+   * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12).
+   */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 12; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp10 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    tmp10 <<= CONST_BITS;
+    tmp12 = (INT32) wsptr[4];
+    tmp20 = MULTIPLY(tmp12, FIX(0.707106781));   /* c4 */
+    tmp11 = tmp10 + tmp20;
+    tmp21 = tmp10 - tmp20 - tmp20;
+    tmp20 = (INT32) wsptr[2];
+    tmp10 = MULTIPLY(tmp20, FIX(1.224744871));   /* c2 */
+    tmp20 = tmp11 + tmp10;
+    tmp22 = tmp11 - tmp10;
+
+    /* Odd part */
+
+    z1 = (INT32) wsptr[1];
+    z2 = (INT32) wsptr[3];
+    z3 = (INT32) wsptr[5];
+    tmp11 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */
+    tmp10 = tmp11 + ((z1 + z2) << CONST_BITS);
+    tmp12 = tmp11 + ((z3 - z2) << CONST_BITS);
+    tmp11 = (z1 - z2 - z3) << CONST_BITS;
+
+    /* Final output stage */
+
+    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += 6;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 5x10 output block.
+ *
+ * 10-point IDCT in pass 1 (columns), 5-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_5x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		JCOEFPTR coef_block,
+		JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+  INT32 tmp20, tmp21, tmp22, tmp23, tmp24;
+  INT32 z1, z2, z3, z4, z5;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[5*10];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array.
+   * 10-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/20).
+   */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 5; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    z3 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    z3 += ONE << (CONST_BITS-PASS1_BITS-1);
+    z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    z1 = MULTIPLY(z4, FIX(1.144122806));         /* c4 */
+    z2 = MULTIPLY(z4, FIX(0.437016024));         /* c8 */
+    tmp10 = z3 + z1;
+    tmp11 = z3 - z2;
+
+    tmp22 = RIGHT_SHIFT(z3 - ((z1 - z2) << 1),   /* c0 = (c4-c8)*2 */
+			CONST_BITS-PASS1_BITS);
+
+    z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+    z1 = MULTIPLY(z2 + z3, FIX(0.831253876));    /* c6 */
+    tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */
+    tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */
+
+    tmp20 = tmp10 + tmp12;
+    tmp24 = tmp10 - tmp12;
+    tmp21 = tmp11 + tmp13;
+    tmp23 = tmp11 - tmp13;
+
+    /* Odd part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+    tmp11 = z2 + z4;
+    tmp13 = z2 - z4;
+
+    tmp12 = MULTIPLY(tmp13, FIX(0.309016994));        /* (c3-c7)/2 */
+    z5 = z3 << CONST_BITS;
+
+    z2 = MULTIPLY(tmp11, FIX(0.951056516));           /* (c3+c7)/2 */
+    z4 = z5 + tmp12;
+
+    tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */
+    tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */
+
+    z2 = MULTIPLY(tmp11, FIX(0.587785252));           /* (c1-c9)/2 */
+    z4 = z5 - tmp12 - (tmp13 << (CONST_BITS - 1));
+
+    tmp12 = (z1 - tmp13 - z3) << PASS1_BITS;
+
+    tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */
+    tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */
+
+    /* Final output stage */
+
+    wsptr[5*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[5*9] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+    wsptr[5*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[5*8] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+    wsptr[5*2] = (int) (tmp22 + tmp12);
+    wsptr[5*7] = (int) (tmp22 - tmp12);
+    wsptr[5*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+    wsptr[5*6] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+    wsptr[5*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+    wsptr[5*5] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process 10 rows from work array, store into output array.
+   * 5-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/10).
+   */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 10; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp12 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    tmp12 <<= CONST_BITS;
+    tmp13 = (INT32) wsptr[2];
+    tmp14 = (INT32) wsptr[4];
+    z1 = MULTIPLY(tmp13 + tmp14, FIX(0.790569415)); /* (c2+c4)/2 */
+    z2 = MULTIPLY(tmp13 - tmp14, FIX(0.353553391)); /* (c2-c4)/2 */
+    z3 = tmp12 + z2;
+    tmp10 = z3 + z1;
+    tmp11 = z3 - z1;
+    tmp12 -= z2 << 2;
+
+    /* Odd part */
+
+    z2 = (INT32) wsptr[1];
+    z3 = (INT32) wsptr[3];
+
+    z1 = MULTIPLY(z2 + z3, FIX(0.831253876));       /* c3 */
+    tmp13 = z1 + MULTIPLY(z2, FIX(0.513743148));    /* c1-c3 */
+    tmp14 = z1 - MULTIPLY(z3, FIX(2.176250899));    /* c1+c3 */
+
+    /* Final output stage */
+
+    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp13,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp13,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp14,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp14,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += 5;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 4x8 output block.
+ *
+ * 8-point IDCT in pass 1 (columns), 4-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_4x8 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	       JCOEFPTR coef_block,
+	       JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp3;
+  INT32 tmp10, tmp11, tmp12, tmp13;
+  INT32 z1, z2, z3;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[4*8];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array.
+   * Note results are scaled up by sqrt(8) compared to a true IDCT;
+   * furthermore, we scale the results by 2**PASS1_BITS.
+   * 8-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+   */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 4; ctr > 0; ctr--) {
+    /* Due to quantization, we will usually find that many of the input
+     * coefficients are zero, especially the AC terms.  We can exploit this
+     * by short-circuiting the IDCT calculation for any column in which all
+     * the AC terms are zero.  In that case each output is equal to the
+     * DC coefficient (with scale factor as needed).
+     * With typical images and quantization tables, half or more of the
+     * column DCT calculations can be simplified this way.
+     */
+
+    if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
+	inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
+	inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
+	inptr[DCTSIZE*7] == 0) {
+      /* AC terms all zero */
+      int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;
+
+      wsptr[4*0] = dcval;
+      wsptr[4*1] = dcval;
+      wsptr[4*2] = dcval;
+      wsptr[4*3] = dcval;
+      wsptr[4*4] = dcval;
+      wsptr[4*5] = dcval;
+      wsptr[4*6] = dcval;
+      wsptr[4*7] = dcval;
+
+      inptr++;			/* advance pointers to next column */
+      quantptr++;
+      wsptr++;
+      continue;
+    }
+
+    /* Even part: reverse the even part of the forward DCT.
+     * The rotator is c(-6).
+     */
+
+    z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);       /* c6 */
+    tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);     /* c2-c6 */
+    tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);     /* c2+c6 */
+
+    z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    z2 <<= CONST_BITS;
+    z3 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    z2 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+    tmp0 = z2 + z3;
+    tmp1 = z2 - z3;
+
+    tmp10 = tmp0 + tmp2;
+    tmp13 = tmp0 - tmp2;
+    tmp11 = tmp1 + tmp3;
+    tmp12 = tmp1 - tmp3;
+
+    /* Odd part per figure 8; the matrix is unitary and hence its
+     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.
+     */
+
+    tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+    tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+
+    z2 = tmp0 + tmp2;
+    z3 = tmp1 + tmp3;
+
+    z1 = MULTIPLY(z2 + z3, FIX_1_175875602);       /*  c3 */
+    z2 = MULTIPLY(z2, - FIX_1_961570560);          /* -c3-c5 */
+    z3 = MULTIPLY(z3, - FIX_0_390180644);          /* -c3+c5 */
+    z2 += z1;
+    z3 += z1;
+
+    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */
+    tmp0 = MULTIPLY(tmp0, FIX_0_298631336);        /* -c1+c3+c5-c7 */
+    tmp3 = MULTIPLY(tmp3, FIX_1_501321110);        /*  c1+c3-c5-c7 */
+    tmp0 += z1 + z2;
+    tmp3 += z1 + z3;
+
+    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */
+    tmp1 = MULTIPLY(tmp1, FIX_2_053119869);        /*  c1+c3-c5+c7 */
+    tmp2 = MULTIPLY(tmp2, FIX_3_072711026);        /*  c1+c3+c5-c7 */
+    tmp1 += z1 + z3;
+    tmp2 += z1 + z2;
+
+    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+    wsptr[4*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS);
+    wsptr[4*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS);
+    wsptr[4*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS);
+    wsptr[4*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS);
+    wsptr[4*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS);
+    wsptr[4*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS);
+    wsptr[4*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS);
+    wsptr[4*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS);
+
+    inptr++;			/* advance pointers to next column */
+    quantptr++;
+    wsptr++;
+  }
+
+  /* Pass 2: process 8 rows from work array, store into output array.
+   * 4-point IDCT kernel,
+   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT].
+   */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 8; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    tmp2 = (INT32) wsptr[2];
+
+    tmp10 = (tmp0 + tmp2) << CONST_BITS;
+    tmp12 = (tmp0 - tmp2) << CONST_BITS;
+
+    /* Odd part */
+    /* Same rotation as in the even part of the 8x8 LL&M IDCT */
+
+    z2 = (INT32) wsptr[1];
+    z3 = (INT32) wsptr[3];
+
+    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);   /* c6 */
+    tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */
+    tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */
+
+    /* Final output stage */
+
+    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += 4;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 3x6 output block.
+ *
+ * 6-point IDCT in pass 1 (columns), 3-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_3x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	       JCOEFPTR coef_block,
+	       JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12;
+  INT32 z1, z2, z3;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  int * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  int workspace[3*6];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array.
+   * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12).
+   */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 3; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    tmp0 <<= CONST_BITS;
+    /* Add fudge factor here for final descale. */
+    tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);
+    tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    tmp10 = MULTIPLY(tmp2, FIX(0.707106781));   /* c4 */
+    tmp1 = tmp0 + tmp10;
+    tmp11 = RIGHT_SHIFT(tmp0 - tmp10 - tmp10, CONST_BITS-PASS1_BITS);
+    tmp10 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    tmp0 = MULTIPLY(tmp10, FIX(1.224744871));   /* c2 */
+    tmp10 = tmp1 + tmp0;
+    tmp12 = tmp1 - tmp0;
+
+    /* Odd part */
+
+    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */
+    tmp0 = tmp1 + ((z1 + z2) << CONST_BITS);
+    tmp2 = tmp1 + ((z3 - z2) << CONST_BITS);
+    tmp1 = (z1 - z2 - z3) << PASS1_BITS;
+
+    /* Final output stage */
+
+    wsptr[3*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+    wsptr[3*5] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+    wsptr[3*1] = (int) (tmp11 + tmp1);
+    wsptr[3*4] = (int) (tmp11 - tmp1);
+    wsptr[3*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS);
+    wsptr[3*3] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS);
+  }
+
+  /* Pass 2: process 6 rows from work array, store into output array.
+   * 3-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/6).
+   */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 6; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+    tmp0 <<= CONST_BITS;
+    tmp2 = (INT32) wsptr[2];
+    tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */
+    tmp10 = tmp0 + tmp12;
+    tmp2 = tmp0 - tmp12 - tmp12;
+
+    /* Odd part */
+
+    tmp12 = (INT32) wsptr[1];
+    tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */
+
+    /* Final output stage */
+
+    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp2,
+					      CONST_BITS+PASS1_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += 3;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 2x4 output block.
+ *
+ * 4-point IDCT in pass 1 (columns), 2-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_2x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	       JCOEFPTR coef_block,
+	       JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp0, tmp2, tmp10, tmp12;
+  INT32 z1, z2, z3;
+  JCOEFPTR inptr;
+  ISLOW_MULT_TYPE * quantptr;
+  INT32 * wsptr;
+  JSAMPROW outptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  int ctr;
+  INT32 workspace[2*4];	/* buffers data between passes */
+  SHIFT_TEMPS
+
+  /* Pass 1: process columns from input, store into work array.
+   * 4-point IDCT kernel,
+   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT].
+   */
+
+  inptr = coef_block;
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+  wsptr = workspace;
+  for (ctr = 0; ctr < 2; ctr++, inptr++, quantptr++, wsptr++) {
+    /* Even part */
+
+    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+
+    tmp10 = (tmp0 + tmp2) << CONST_BITS;
+    tmp12 = (tmp0 - tmp2) << CONST_BITS;
+
+    /* Odd part */
+    /* Same rotation as in the even part of the 8x8 LL&M IDCT */
+
+    z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+
+    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);   /* c6 */
+    tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */
+    tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */
+
+    /* Final output stage */
+
+    wsptr[2*0] = tmp10 + tmp0;
+    wsptr[2*3] = tmp10 - tmp0;
+    wsptr[2*1] = tmp12 + tmp2;
+    wsptr[2*2] = tmp12 - tmp2;
+  }
+
+  /* Pass 2: process 4 rows from work array, store into output array. */
+
+  wsptr = workspace;
+  for (ctr = 0; ctr < 4; ctr++) {
+    outptr = output_buf[ctr] + output_col;
+
+    /* Even part */
+
+    /* Add fudge factor here for final descale. */
+    tmp10 = wsptr[0] + (ONE << (CONST_BITS+2));
+
+    /* Odd part */
+
+    tmp0 = wsptr[1];
+
+    /* Final output stage */
+
+    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS+3)
+			    & RANGE_MASK];
+    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS+3)
+			    & RANGE_MASK];
+
+    wsptr += 2;		/* advance pointer to next row */
+  }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 1x2 output block.
+ *
+ * 2-point IDCT in pass 1 (columns), 1-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_1x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+	       JCOEFPTR coef_block,
+	       JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  INT32 tmp0, tmp1;
+  ISLOW_MULT_TYPE * quantptr;
+  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+  SHIFT_TEMPS
+
+  /* Process 1 column from input, store into output array. */
+
+  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+
+  /* Even part */
+    
+  tmp0 = DEQUANTIZE(coef_block[DCTSIZE*0], quantptr[DCTSIZE*0]);
+  /* Add fudge factor here for final descale. */
+  tmp0 += ONE << 2;
+
+  /* Odd part */
+
+  tmp1 = DEQUANTIZE(coef_block[DCTSIZE*1], quantptr[DCTSIZE*1]);
+
+  /* Final output stage */
+
+  output_buf[0][output_col] = range_limit[(int) RIGHT_SHIFT(tmp0 + tmp1, 3)
+					  & RANGE_MASK];
+  output_buf[1][output_col] = range_limit[(int) RIGHT_SHIFT(tmp0 - tmp1, 3)
+					  & RANGE_MASK];
+}
+
+#endif /* IDCT_SCALING_SUPPORTED */
+#endif /* DCT_ISLOW_SUPPORTED */
diff --git a/source/Irrlicht/jpeglib/jinclude.h b/source/Irrlicht/jpeglib/jinclude.h
new file mode 100644
index 00000000..5ff60fed
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jinclude.h
@@ -0,0 +1,91 @@
+/*
+ * jinclude.h
+ *
+ * Copyright (C) 1991-1994, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file exists to provide a single place to fix any problems with
+ * including the wrong system include files.  (Common problems are taken
+ * care of by the standard jconfig symbols, but on really weird systems
+ * you may have to edit this file.)
+ *
+ * NOTE: this file is NOT intended to be included by applications using the
+ * JPEG library.  Most applications need only include jpeglib.h.
+ */
+
+
+/* Include auto-config file to find out which system include files we need. */
+
+#include "jconfig.h"		/* auto configuration options */
+#define JCONFIG_INCLUDED	/* so that jpeglib.h doesn't do it again */
+
+/*
+ * We need the NULL macro and size_t typedef.
+ * On an ANSI-conforming system it is sufficient to include .
+ * Otherwise, we get them from  or ; we may have to
+ * pull in  as well.
+ * Note that the core JPEG library does not require ;
+ * only the default error handler and data source/destination modules do.
+ * But we must pull it in because of the references to FILE in jpeglib.h.
+ * You can remove those references if you want to compile without .
+ */
+
+#ifdef HAVE_STDDEF_H
+#include 
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include 
+#endif
+
+#ifdef NEED_SYS_TYPES_H
+#include 
+#endif
+
+#include 
+
+/*
+ * We need memory copying and zeroing functions, plus strncpy().
+ * ANSI and System V implementations declare these in .
+ * BSD doesn't have the mem() functions, but it does have bcopy()/bzero().
+ * Some systems may declare memset and memcpy in .
+ *
+ * NOTE: we assume the size parameters to these functions are of type size_t.
+ * Change the casts in these macros if not!
+ */
+
+#ifdef NEED_BSD_STRINGS
+
+#include 
+#define MEMZERO(target,size)	bzero((void *)(target), (size_t)(size))
+#define MEMCOPY(dest,src,size)	bcopy((const void *)(src), (void *)(dest), (size_t)(size))
+
+#else /* not BSD, assume ANSI/SysV string lib */
+
+#include 
+#define MEMZERO(target,size)	memset((void *)(target), 0, (size_t)(size))
+#define MEMCOPY(dest,src,size)	memcpy((void *)(dest), (const void *)(src), (size_t)(size))
+
+#endif
+
+/*
+ * In ANSI C, and indeed any rational implementation, size_t is also the
+ * type returned by sizeof().  However, it seems there are some irrational
+ * implementations out there, in which sizeof() returns an int even though
+ * size_t is defined as long or unsigned long.  To ensure consistent results
+ * we always use this SIZEOF() macro in place of using sizeof() directly.
+ */
+
+#define SIZEOF(object)	((size_t) sizeof(object))
+
+/*
+ * The modules that use fread() and fwrite() always invoke them through
+ * these macros.  On some systems you may need to twiddle the argument casts.
+ * CAUTION: argument order is different from underlying functions!
+ */
+
+#define JFREAD(file,buf,sizeofbuf)  \
+  ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))
+#define JFWRITE(file,buf,sizeofbuf)  \
+  ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))
diff --git a/source/Irrlicht/jpeglib/jmemansi.c b/source/Irrlicht/jpeglib/jmemansi.c
new file mode 100644
index 00000000..b5da4743
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jmemansi.c
@@ -0,0 +1,167 @@
+/*
+ * jmemansi.c
+ *
+ * Copyright (C) 1992-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file provides a simple generic implementation of the system-
+ * dependent portion of the JPEG memory manager.  This implementation
+ * assumes that you have the ANSI-standard library routine tmpfile().
+ * Also, the problem of determining the amount of memory available
+ * is shoved onto the user.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h"		/* import the system-dependent declarations */
+
+#ifndef HAVE_STDLIB_H		/*  should declare malloc(),free() */
+extern void * malloc JPP((size_t size));
+extern void free JPP((void *ptr));
+#endif
+
+#ifndef SEEK_SET		/* pre-ANSI systems may not define this; */
+#define SEEK_SET  0		/* if not, assume 0 is correct */
+#endif
+
+
+/*
+ * Memory allocation and freeing are controlled by the regular library
+ * routines malloc() and free().
+ */
+
+GLOBAL(void *)
+jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
+{
+  return (void *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
+{
+  free(object);
+}
+
+
+/*
+ * "Large" objects are treated the same as "small" ones.
+ * NB: although we include FAR keywords in the routine declarations,
+ * this file won't actually work in 80x86 small/medium model; at least,
+ * you probably won't be able to process useful-size images in only 64KB.
+ */
+
+GLOBAL(void FAR *)
+jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
+{
+  return (void FAR *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
+{
+  free(object);
+}
+
+
+/*
+ * This routine computes the total memory space available for allocation.
+ * It's impossible to do this in a portable way; our current solution is
+ * to make the user tell us (with a default value set at compile time).
+ * If you can actually get the available space, it's a good idea to subtract
+ * a slop factor of 5% or so.
+ */
+
+#ifndef DEFAULT_MAX_MEM		/* so can override from makefile */
+#define DEFAULT_MAX_MEM		1000000L /* default: one megabyte */
+#endif
+
+GLOBAL(long)
+jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
+		    long max_bytes_needed, long already_allocated)
+{
+  return cinfo->mem->max_memory_to_use - already_allocated;
+}
+
+
+/*
+ * Backing store (temporary file) management.
+ * Backing store objects are only used when the value returned by
+ * jpeg_mem_available is less than the total space needed.  You can dispense
+ * with these routines if you have plenty of virtual memory; see jmemnobs.c.
+ */
+
+
+METHODDEF(void)
+read_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+		    void FAR * buffer_address,
+		    long file_offset, long byte_count)
+{
+  if (fseek(info->temp_file, file_offset, SEEK_SET))
+    ERREXIT(cinfo, JERR_TFILE_SEEK);
+  if (JFREAD(info->temp_file, buffer_address, byte_count)
+      != (size_t) byte_count)
+    ERREXIT(cinfo, JERR_TFILE_READ);
+}
+
+
+METHODDEF(void)
+write_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+		     void FAR * buffer_address,
+		     long file_offset, long byte_count)
+{
+  if (fseek(info->temp_file, file_offset, SEEK_SET))
+    ERREXIT(cinfo, JERR_TFILE_SEEK);
+  if (JFWRITE(info->temp_file, buffer_address, byte_count)
+      != (size_t) byte_count)
+    ERREXIT(cinfo, JERR_TFILE_WRITE);
+}
+
+
+METHODDEF(void)
+close_backing_store (j_common_ptr cinfo, backing_store_ptr info)
+{
+  fclose(info->temp_file);
+  /* Since this implementation uses tmpfile() to create the file,
+   * no explicit file deletion is needed.
+   */
+}
+
+
+/*
+ * Initial opening of a backing-store object.
+ *
+ * This version uses tmpfile(), which constructs a suitable file name
+ * behind the scenes.  We don't have to use info->temp_name[] at all;
+ * indeed, we can't even find out the actual name of the temp file.
+ */
+
+GLOBAL(void)
+jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+			 long total_bytes_needed)
+{
+  if ((info->temp_file = tmpfile()) == NULL)
+    ERREXITS(cinfo, JERR_TFILE_CREATE, "");
+  info->read_backing_store = read_backing_store;
+  info->write_backing_store = write_backing_store;
+  info->close_backing_store = close_backing_store;
+}
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required.
+ */
+
+GLOBAL(long)
+jpeg_mem_init (j_common_ptr cinfo)
+{
+  return DEFAULT_MAX_MEM;	/* default for max_memory_to_use */
+}
+
+GLOBAL(void)
+jpeg_mem_term (j_common_ptr cinfo)
+{
+  /* no work */
+}
diff --git a/source/Irrlicht/jpeglib/jmemdos.c b/source/Irrlicht/jpeglib/jmemdos.c
new file mode 100644
index 00000000..0955047e
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jmemdos.c
@@ -0,0 +1,638 @@
+/*
+ * jmemdos.c
+ *
+ * Copyright (C) 1992-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file provides an MS-DOS-compatible implementation of the system-
+ * dependent portion of the JPEG memory manager.  Temporary data can be
+ * stored in extended or expanded memory as well as in regular DOS files.
+ *
+ * If you use this file, you must be sure that NEED_FAR_POINTERS is defined
+ * if you compile in a small-data memory model; it should NOT be defined if
+ * you use a large-data memory model.  This file is not recommended if you
+ * are using a flat-memory-space 386 environment such as DJGCC or Watcom C.
+ * Also, this code will NOT work if struct fields are aligned on greater than
+ * 2-byte boundaries.
+ *
+ * Based on code contributed by Ge' Weijers.
+ */
+
+/*
+ * If you have both extended and expanded memory, you may want to change the
+ * order in which they are tried in jopen_backing_store.  On a 286 machine
+ * expanded memory is usually faster, since extended memory access involves
+ * an expensive protected-mode-and-back switch.  On 386 and better, extended
+ * memory is usually faster.  As distributed, the code tries extended memory
+ * first (what? not everyone has a 386? :-).
+ *
+ * You can disable use of extended/expanded memory entirely by altering these
+ * definitions or overriding them from the Makefile (eg, -DEMS_SUPPORTED=0).
+ */
+
+#ifndef XMS_SUPPORTED
+#define XMS_SUPPORTED  1
+#endif
+#ifndef EMS_SUPPORTED
+#define EMS_SUPPORTED  1
+#endif
+
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h"		/* import the system-dependent declarations */
+
+#ifndef HAVE_STDLIB_H		/*  should declare these */
+extern void * malloc JPP((size_t size));
+extern void free JPP((void *ptr));
+extern char * getenv JPP((const char * name));
+#endif
+
+#ifdef NEED_FAR_POINTERS
+
+#ifdef __TURBOC__
+/* These definitions work for Borland C (Turbo C) */
+#include 		/* need farmalloc(), farfree() */
+#define far_malloc(x)	farmalloc(x)
+#define far_free(x)	farfree(x)
+#else
+/* These definitions work for Microsoft C and compatible compilers */
+#include 		/* need _fmalloc(), _ffree() */
+#define far_malloc(x)	_fmalloc(x)
+#define far_free(x)	_ffree(x)
+#endif
+
+#else /* not NEED_FAR_POINTERS */
+
+#define far_malloc(x)	malloc(x)
+#define far_free(x)	free(x)
+
+#endif /* NEED_FAR_POINTERS */
+
+#ifdef DONT_USE_B_MODE		/* define mode parameters for fopen() */
+#define READ_BINARY	"r"
+#else
+#define READ_BINARY	"rb"
+#endif
+
+#ifndef USE_MSDOS_MEMMGR	/* make sure user got configuration right */
+  You forgot to define USE_MSDOS_MEMMGR in jconfig.h. /* deliberate syntax error */
+#endif
+
+#if MAX_ALLOC_CHUNK >= 65535L	/* make sure jconfig.h got this right */
+  MAX_ALLOC_CHUNK should be less than 64K. /* deliberate syntax error */
+#endif
+
+
+/*
+ * Declarations for assembly-language support routines (see jmemdosa.asm).
+ *
+ * The functions are declared "far" as are all their pointer arguments;
+ * this ensures the assembly source code will work regardless of the
+ * compiler memory model.  We assume "short" is 16 bits, "long" is 32.
+ */
+
+typedef void far * XMSDRIVER;	/* actually a pointer to code */
+typedef struct {		/* registers for calling XMS driver */
+	unsigned short ax, dx, bx;
+	void far * ds_si;
+      } XMScontext;
+typedef struct {		/* registers for calling EMS driver */
+	unsigned short ax, dx, bx;
+	void far * ds_si;
+      } EMScontext;
+
+extern short far jdos_open JPP((short far * handle, char far * filename));
+extern short far jdos_close JPP((short handle));
+extern short far jdos_seek JPP((short handle, long offset));
+extern short far jdos_read JPP((short handle, void far * buffer,
+				unsigned short count));
+extern short far jdos_write JPP((short handle, void far * buffer,
+				 unsigned short count));
+extern void far jxms_getdriver JPP((XMSDRIVER far *));
+extern void far jxms_calldriver JPP((XMSDRIVER, XMScontext far *));
+extern short far jems_available JPP((void));
+extern void far jems_calldriver JPP((EMScontext far *));
+
+
+/*
+ * Selection of a file name for a temporary file.
+ * This is highly system-dependent, and you may want to customize it.
+ */
+
+static int next_file_num;	/* to distinguish among several temp files */
+
+LOCAL(void)
+select_file_name (char * fname)
+{
+  const char * env;
+  char * ptr;
+  FILE * tfile;
+
+  /* Keep generating file names till we find one that's not in use */
+  for (;;) {
+    /* Get temp directory name from environment TMP or TEMP variable;
+     * if none, use "."
+     */
+    if ((env = (const char *) getenv("TMP")) == NULL)
+      if ((env = (const char *) getenv("TEMP")) == NULL)
+	env = ".";
+    if (*env == '\0')		/* null string means "." */
+      env = ".";
+    ptr = fname;		/* copy name to fname */
+    while (*env != '\0')
+      *ptr++ = *env++;
+    if (ptr[-1] != '\\' && ptr[-1] != '/')
+      *ptr++ = '\\';		/* append backslash if not in env variable */
+    /* Append a suitable file name */
+    next_file_num++;		/* advance counter */
+    sprintf(ptr, "JPG%03d.TMP", next_file_num);
+    /* Probe to see if file name is already in use */
+    if ((tfile = fopen(fname, READ_BINARY)) == NULL)
+      break;
+    fclose(tfile);		/* oops, it's there; close tfile & try again */
+  }
+}
+
+
+/*
+ * Near-memory allocation and freeing are controlled by the regular library
+ * routines malloc() and free().
+ */
+
+GLOBAL(void *)
+jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
+{
+  return (void *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
+{
+  free(object);
+}
+
+
+/*
+ * "Large" objects are allocated in far memory, if possible
+ */
+
+GLOBAL(void FAR *)
+jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
+{
+  return (void FAR *) far_malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
+{
+  far_free(object);
+}
+
+
+/*
+ * This routine computes the total memory space available for allocation.
+ * It's impossible to do this in a portable way; our current solution is
+ * to make the user tell us (with a default value set at compile time).
+ * If you can actually get the available space, it's a good idea to subtract
+ * a slop factor of 5% or so.
+ */
+
+#ifndef DEFAULT_MAX_MEM		/* so can override from makefile */
+#define DEFAULT_MAX_MEM		300000L /* for total usage about 450K */
+#endif
+
+GLOBAL(long)
+jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
+		    long max_bytes_needed, long already_allocated)
+{
+  return cinfo->mem->max_memory_to_use - already_allocated;
+}
+
+
+/*
+ * Backing store (temporary file) management.
+ * Backing store objects are only used when the value returned by
+ * jpeg_mem_available is less than the total space needed.  You can dispense
+ * with these routines if you have plenty of virtual memory; see jmemnobs.c.
+ */
+
+/*
+ * For MS-DOS we support three types of backing storage:
+ *   1. Conventional DOS files.  We access these by direct DOS calls rather
+ *      than via the stdio package.  This provides a bit better performance,
+ *      but the real reason is that the buffers to be read or written are FAR.
+ *      The stdio library for small-data memory models can't cope with that.
+ *   2. Extended memory, accessed per the XMS V2.0 specification.
+ *   3. Expanded memory, accessed per the LIM/EMS 4.0 specification.
+ * You'll need copies of those specs to make sense of the related code.
+ * The specs are available by Internet FTP from the SIMTEL archives 
+ * (oak.oakland.edu and its various mirror sites).  See files
+ * pub/msdos/microsoft/xms20.arc and pub/msdos/info/limems41.zip.
+ */
+
+
+/*
+ * Access methods for a DOS file.
+ */
+
+
+METHODDEF(void)
+read_file_store (j_common_ptr cinfo, backing_store_ptr info,
+		 void FAR * buffer_address,
+		 long file_offset, long byte_count)
+{
+  if (jdos_seek(info->handle.file_handle, file_offset))
+    ERREXIT(cinfo, JERR_TFILE_SEEK);
+  /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
+  if (byte_count > 65535L)	/* safety check */
+    ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
+  if (jdos_read(info->handle.file_handle, buffer_address,
+		(unsigned short) byte_count))
+    ERREXIT(cinfo, JERR_TFILE_READ);
+}
+
+
+METHODDEF(void)
+write_file_store (j_common_ptr cinfo, backing_store_ptr info,
+		  void FAR * buffer_address,
+		  long file_offset, long byte_count)
+{
+  if (jdos_seek(info->handle.file_handle, file_offset))
+    ERREXIT(cinfo, JERR_TFILE_SEEK);
+  /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
+  if (byte_count > 65535L)	/* safety check */
+    ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
+  if (jdos_write(info->handle.file_handle, buffer_address,
+		 (unsigned short) byte_count))
+    ERREXIT(cinfo, JERR_TFILE_WRITE);
+}
+
+
+METHODDEF(void)
+close_file_store (j_common_ptr cinfo, backing_store_ptr info)
+{
+  jdos_close(info->handle.file_handle);	/* close the file */
+  remove(info->temp_name);	/* delete the file */
+/* If your system doesn't have remove(), try unlink() instead.
+ * remove() is the ANSI-standard name for this function, but
+ * unlink() was more common in pre-ANSI systems.
+ */
+  TRACEMSS(cinfo, 1, JTRC_TFILE_CLOSE, info->temp_name);
+}
+
+
+LOCAL(boolean)
+open_file_store (j_common_ptr cinfo, backing_store_ptr info,
+		 long total_bytes_needed)
+{
+  short handle;
+
+  select_file_name(info->temp_name);
+  if (jdos_open((short far *) & handle, (char far *) info->temp_name)) {
+    /* might as well exit since jpeg_open_backing_store will fail anyway */
+    ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
+    return FALSE;
+  }
+  info->handle.file_handle = handle;
+  info->read_backing_store = read_file_store;
+  info->write_backing_store = write_file_store;
+  info->close_backing_store = close_file_store;
+  TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name);
+  return TRUE;			/* succeeded */
+}
+
+
+/*
+ * Access methods for extended memory.
+ */
+
+#if XMS_SUPPORTED
+
+static XMSDRIVER xms_driver;	/* saved address of XMS driver */
+
+typedef union {			/* either long offset or real-mode pointer */
+	long offset;
+	void far * ptr;
+      } XMSPTR;
+
+typedef struct {		/* XMS move specification structure */
+	long length;
+	XMSH src_handle;
+	XMSPTR src;
+	XMSH dst_handle;
+	XMSPTR dst;
+      } XMSspec;
+
+#define ODD(X)	(((X) & 1L) != 0)
+
+
+METHODDEF(void)
+read_xms_store (j_common_ptr cinfo, backing_store_ptr info,
+		void FAR * buffer_address,
+		long file_offset, long byte_count)
+{
+  XMScontext ctx;
+  XMSspec spec;
+  char endbuffer[2];
+
+  /* The XMS driver can't cope with an odd length, so handle the last byte
+   * specially if byte_count is odd.  We don't expect this to be common.
+   */
+
+  spec.length = byte_count & (~ 1L);
+  spec.src_handle = info->handle.xms_handle;
+  spec.src.offset = file_offset;
+  spec.dst_handle = 0;
+  spec.dst.ptr = buffer_address;
+  
+  ctx.ds_si = (void far *) & spec;
+  ctx.ax = 0x0b00;		/* EMB move */
+  jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
+  if (ctx.ax != 1)
+    ERREXIT(cinfo, JERR_XMS_READ);
+
+  if (ODD(byte_count)) {
+    read_xms_store(cinfo, info, (void FAR *) endbuffer,
+		   file_offset + byte_count - 1L, 2L);
+    ((char FAR *) buffer_address)[byte_count - 1L] = endbuffer[0];
+  }
+}
+
+
+METHODDEF(void)
+write_xms_store (j_common_ptr cinfo, backing_store_ptr info,
+		 void FAR * buffer_address,
+		 long file_offset, long byte_count)
+{
+  XMScontext ctx;
+  XMSspec spec;
+  char endbuffer[2];
+
+  /* The XMS driver can't cope with an odd length, so handle the last byte
+   * specially if byte_count is odd.  We don't expect this to be common.
+   */
+
+  spec.length = byte_count & (~ 1L);
+  spec.src_handle = 0;
+  spec.src.ptr = buffer_address;
+  spec.dst_handle = info->handle.xms_handle;
+  spec.dst.offset = file_offset;
+
+  ctx.ds_si = (void far *) & spec;
+  ctx.ax = 0x0b00;		/* EMB move */
+  jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
+  if (ctx.ax != 1)
+    ERREXIT(cinfo, JERR_XMS_WRITE);
+
+  if (ODD(byte_count)) {
+    read_xms_store(cinfo, info, (void FAR *) endbuffer,
+		   file_offset + byte_count - 1L, 2L);
+    endbuffer[0] = ((char FAR *) buffer_address)[byte_count - 1L];
+    write_xms_store(cinfo, info, (void FAR *) endbuffer,
+		    file_offset + byte_count - 1L, 2L);
+  }
+}
+
+
+METHODDEF(void)
+close_xms_store (j_common_ptr cinfo, backing_store_ptr info)
+{
+  XMScontext ctx;
+
+  ctx.dx = info->handle.xms_handle;
+  ctx.ax = 0x0a00;
+  jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
+  TRACEMS1(cinfo, 1, JTRC_XMS_CLOSE, info->handle.xms_handle);
+  /* we ignore any error return from the driver */
+}
+
+
+LOCAL(boolean)
+open_xms_store (j_common_ptr cinfo, backing_store_ptr info,
+		long total_bytes_needed)
+{
+  XMScontext ctx;
+
+  /* Get address of XMS driver */
+  jxms_getdriver((XMSDRIVER far *) & xms_driver);
+  if (xms_driver == NULL)
+    return FALSE;		/* no driver to be had */
+
+  /* Get version number, must be >= 2.00 */
+  ctx.ax = 0x0000;
+  jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
+  if (ctx.ax < (unsigned short) 0x0200)
+    return FALSE;
+
+  /* Try to get space (expressed in kilobytes) */
+  ctx.dx = (unsigned short) ((total_bytes_needed + 1023L) >> 10);
+  ctx.ax = 0x0900;
+  jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
+  if (ctx.ax != 1)
+    return FALSE;
+
+  /* Succeeded, save the handle and away we go */
+  info->handle.xms_handle = ctx.dx;
+  info->read_backing_store = read_xms_store;
+  info->write_backing_store = write_xms_store;
+  info->close_backing_store = close_xms_store;
+  TRACEMS1(cinfo, 1, JTRC_XMS_OPEN, ctx.dx);
+  return TRUE;			/* succeeded */
+}
+
+#endif /* XMS_SUPPORTED */
+
+
+/*
+ * Access methods for expanded memory.
+ */
+
+#if EMS_SUPPORTED
+
+/* The EMS move specification structure requires word and long fields aligned
+ * at odd byte boundaries.  Some compilers will align struct fields at even
+ * byte boundaries.  While it's usually possible to force byte alignment,
+ * that causes an overall performance penalty and may pose problems in merging
+ * JPEG into a larger application.  Instead we accept some rather dirty code
+ * here.  Note this code would fail if the hardware did not allow odd-byte
+ * word & long accesses, but all 80x86 CPUs do.
+ */
+
+typedef void far * EMSPTR;
+
+typedef union {			/* EMS move specification structure */
+	long length;		/* It's easy to access first 4 bytes */
+	char bytes[18];		/* Misaligned fields in here! */
+      } EMSspec;
+
+/* Macros for accessing misaligned fields */
+#define FIELD_AT(spec,offset,type)  (*((type *) &(spec.bytes[offset])))
+#define SRC_TYPE(spec)		FIELD_AT(spec,4,char)
+#define SRC_HANDLE(spec)	FIELD_AT(spec,5,EMSH)
+#define SRC_OFFSET(spec)	FIELD_AT(spec,7,unsigned short)
+#define SRC_PAGE(spec)		FIELD_AT(spec,9,unsigned short)
+#define SRC_PTR(spec)		FIELD_AT(spec,7,EMSPTR)
+#define DST_TYPE(spec)		FIELD_AT(spec,11,char)
+#define DST_HANDLE(spec)	FIELD_AT(spec,12,EMSH)
+#define DST_OFFSET(spec)	FIELD_AT(spec,14,unsigned short)
+#define DST_PAGE(spec)		FIELD_AT(spec,16,unsigned short)
+#define DST_PTR(spec)		FIELD_AT(spec,14,EMSPTR)
+
+#define EMSPAGESIZE	16384L	/* gospel, see the EMS specs */
+
+#define HIBYTE(W)  (((W) >> 8) & 0xFF)
+#define LOBYTE(W)  ((W) & 0xFF)
+
+
+METHODDEF(void)
+read_ems_store (j_common_ptr cinfo, backing_store_ptr info,
+		void FAR * buffer_address,
+		long file_offset, long byte_count)
+{
+  EMScontext ctx;
+  EMSspec spec;
+
+  spec.length = byte_count;
+  SRC_TYPE(spec) = 1;
+  SRC_HANDLE(spec) = info->handle.ems_handle;
+  SRC_PAGE(spec)   = (unsigned short) (file_offset / EMSPAGESIZE);
+  SRC_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE);
+  DST_TYPE(spec) = 0;
+  DST_HANDLE(spec) = 0;
+  DST_PTR(spec)    = buffer_address;
+  
+  ctx.ds_si = (void far *) & spec;
+  ctx.ax = 0x5700;		/* move memory region */
+  jems_calldriver((EMScontext far *) & ctx);
+  if (HIBYTE(ctx.ax) != 0)
+    ERREXIT(cinfo, JERR_EMS_READ);
+}
+
+
+METHODDEF(void)
+write_ems_store (j_common_ptr cinfo, backing_store_ptr info,
+		 void FAR * buffer_address,
+		 long file_offset, long byte_count)
+{
+  EMScontext ctx;
+  EMSspec spec;
+
+  spec.length = byte_count;
+  SRC_TYPE(spec) = 0;
+  SRC_HANDLE(spec) = 0;
+  SRC_PTR(spec)    = buffer_address;
+  DST_TYPE(spec) = 1;
+  DST_HANDLE(spec) = info->handle.ems_handle;
+  DST_PAGE(spec)   = (unsigned short) (file_offset / EMSPAGESIZE);
+  DST_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE);
+  
+  ctx.ds_si = (void far *) & spec;
+  ctx.ax = 0x5700;		/* move memory region */
+  jems_calldriver((EMScontext far *) & ctx);
+  if (HIBYTE(ctx.ax) != 0)
+    ERREXIT(cinfo, JERR_EMS_WRITE);
+}
+
+
+METHODDEF(void)
+close_ems_store (j_common_ptr cinfo, backing_store_ptr info)
+{
+  EMScontext ctx;
+
+  ctx.ax = 0x4500;
+  ctx.dx = info->handle.ems_handle;
+  jems_calldriver((EMScontext far *) & ctx);
+  TRACEMS1(cinfo, 1, JTRC_EMS_CLOSE, info->handle.ems_handle);
+  /* we ignore any error return from the driver */
+}
+
+
+LOCAL(boolean)
+open_ems_store (j_common_ptr cinfo, backing_store_ptr info,
+		long total_bytes_needed)
+{
+  EMScontext ctx;
+
+  /* Is EMS driver there? */
+  if (! jems_available())
+    return FALSE;
+
+  /* Get status, make sure EMS is OK */
+  ctx.ax = 0x4000;
+  jems_calldriver((EMScontext far *) & ctx);
+  if (HIBYTE(ctx.ax) != 0)
+    return FALSE;
+
+  /* Get version, must be >= 4.0 */
+  ctx.ax = 0x4600;
+  jems_calldriver((EMScontext far *) & ctx);
+  if (HIBYTE(ctx.ax) != 0 || LOBYTE(ctx.ax) < 0x40)
+    return FALSE;
+
+  /* Try to allocate requested space */
+  ctx.ax = 0x4300;
+  ctx.bx = (unsigned short) ((total_bytes_needed + EMSPAGESIZE-1L) / EMSPAGESIZE);
+  jems_calldriver((EMScontext far *) & ctx);
+  if (HIBYTE(ctx.ax) != 0)
+    return FALSE;
+
+  /* Succeeded, save the handle and away we go */
+  info->handle.ems_handle = ctx.dx;
+  info->read_backing_store = read_ems_store;
+  info->write_backing_store = write_ems_store;
+  info->close_backing_store = close_ems_store;
+  TRACEMS1(cinfo, 1, JTRC_EMS_OPEN, ctx.dx);
+  return TRUE;			/* succeeded */
+}
+
+#endif /* EMS_SUPPORTED */
+
+
+/*
+ * Initial opening of a backing-store object.
+ */
+
+GLOBAL(void)
+jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+			 long total_bytes_needed)
+{
+  /* Try extended memory, then expanded memory, then regular file. */
+#if XMS_SUPPORTED
+  if (open_xms_store(cinfo, info, total_bytes_needed))
+    return;
+#endif
+#if EMS_SUPPORTED
+  if (open_ems_store(cinfo, info, total_bytes_needed))
+    return;
+#endif
+  if (open_file_store(cinfo, info, total_bytes_needed))
+    return;
+  ERREXITS(cinfo, JERR_TFILE_CREATE, "");
+}
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required.
+ */
+
+GLOBAL(long)
+jpeg_mem_init (j_common_ptr cinfo)
+{
+  next_file_num = 0;		/* initialize temp file name generator */
+  return DEFAULT_MAX_MEM;	/* default for max_memory_to_use */
+}
+
+GLOBAL(void)
+jpeg_mem_term (j_common_ptr cinfo)
+{
+  /* Microsoft C, at least in v6.00A, will not successfully reclaim freed
+   * blocks of size > 32Kbytes unless we give it a kick in the rear, like so:
+   */
+#ifdef NEED_FHEAPMIN
+  _fheapmin();
+#endif
+}
diff --git a/source/Irrlicht/jpeglib/jmemdosa.asm b/source/Irrlicht/jpeglib/jmemdosa.asm
new file mode 100644
index 00000000..ecd43729
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jmemdosa.asm
@@ -0,0 +1,379 @@
+;
+; jmemdosa.asm
+;
+; Copyright (C) 1992, Thomas G. Lane.
+; This file is part of the Independent JPEG Group's software.
+; For conditions of distribution and use, see the accompanying README file.
+;
+; This file contains low-level interface routines to support the MS-DOS
+; backing store manager (jmemdos.c).  Routines are provided to access disk
+; files through direct DOS calls, and to access XMS and EMS drivers.
+;
+; This file should assemble with Microsoft's MASM or any compatible
+; assembler (including Borland's Turbo Assembler).  If you haven't got
+; a compatible assembler, better fall back to jmemansi.c or jmemname.c.
+;
+; To minimize dependence on the C compiler's register usage conventions,
+; we save and restore all 8086 registers, even though most compilers only
+; require SI,DI,DS to be preserved.  Also, we use only 16-bit-wide return
+; values, which everybody returns in AX.
+;
+; Based on code contributed by Ge' Weijers.
+;
+
+JMEMDOSA_TXT	segment byte public 'CODE'
+
+		assume	cs:JMEMDOSA_TXT
+
+		public	_jdos_open
+		public	_jdos_close
+		public	_jdos_seek
+		public	_jdos_read
+		public	_jdos_write
+		public	_jxms_getdriver
+		public	_jxms_calldriver
+		public	_jems_available
+		public	_jems_calldriver
+
+;
+; short far jdos_open (short far * handle, char far * filename)
+;
+; Create and open a temporary file
+;
+_jdos_open	proc	far
+		push	bp			; linkage
+		mov 	bp,sp
+		push	si			; save all registers for safety
+		push	di
+		push	bx
+		push	cx
+		push	dx
+		push	es
+		push	ds
+		mov	cx,0			; normal file attributes
+		lds	dx,dword ptr [bp+10]	; get filename pointer
+		mov	ah,3ch			; create file
+		int	21h
+		jc	open_err		; if failed, return error code
+		lds	bx,dword ptr [bp+6]	; get handle pointer
+		mov	word ptr [bx],ax	; save the handle
+		xor	ax,ax			; return zero for OK
+open_err:	pop	ds			; restore registers and exit
+		pop	es
+		pop	dx
+		pop	cx
+		pop	bx
+		pop	di
+		pop	si
+		pop 	bp
+		ret
+_jdos_open	endp
+
+
+;
+; short far jdos_close (short handle)
+;
+; Close the file handle
+;
+_jdos_close	proc	far
+		push	bp			; linkage
+		mov 	bp,sp
+		push	si			; save all registers for safety
+		push	di
+		push	bx
+		push	cx
+		push	dx
+		push	es
+		push	ds
+		mov	bx,word ptr [bp+6]	; file handle
+		mov	ah,3eh			; close file
+		int	21h
+		jc	close_err		; if failed, return error code
+		xor	ax,ax			; return zero for OK
+close_err:	pop	ds			; restore registers and exit
+		pop	es
+		pop	dx
+		pop	cx
+		pop	bx
+		pop	di
+		pop	si
+		pop 	bp
+		ret
+_jdos_close	endp
+
+
+;
+; short far jdos_seek (short handle, long offset)
+;
+; Set file position
+;
+_jdos_seek	proc	far
+		push	bp			; linkage
+		mov 	bp,sp
+		push	si			; save all registers for safety
+		push	di
+		push	bx
+		push	cx
+		push	dx
+		push	es
+		push	ds
+		mov	bx,word ptr [bp+6]	; file handle
+		mov	dx,word ptr [bp+8]	; LS offset
+		mov	cx,word ptr [bp+10]	; MS offset
+		mov	ax,4200h		; absolute seek
+		int	21h
+		jc	seek_err		; if failed, return error code
+		xor	ax,ax			; return zero for OK
+seek_err:	pop	ds			; restore registers and exit
+		pop	es
+		pop	dx
+		pop	cx
+		pop	bx
+		pop	di
+		pop	si
+		pop 	bp
+		ret
+_jdos_seek	endp
+
+
+;
+; short far jdos_read (short handle, void far * buffer, unsigned short count)
+;
+; Read from file
+;
+_jdos_read	proc	far
+		push	bp			; linkage
+		mov 	bp,sp
+		push	si			; save all registers for safety
+		push	di
+		push	bx
+		push	cx
+		push	dx
+		push	es
+		push	ds
+		mov	bx,word ptr [bp+6]	; file handle
+		lds	dx,dword ptr [bp+8]	; buffer address
+		mov	cx,word ptr [bp+12]	; number of bytes
+		mov	ah,3fh			; read file
+		int	21h
+		jc	read_err		; if failed, return error code
+		cmp	ax,word ptr [bp+12]	; make sure all bytes were read
+		je	read_ok
+		mov	ax,1			; else return 1 for not OK
+		jmp	short read_err
+read_ok:	xor	ax,ax			; return zero for OK
+read_err:	pop	ds			; restore registers and exit
+		pop	es
+		pop	dx
+		pop	cx
+		pop	bx
+		pop	di
+		pop	si
+		pop 	bp
+		ret
+_jdos_read	endp
+
+
+;
+; short far jdos_write (short handle, void far * buffer, unsigned short count)
+;
+; Write to file
+;
+_jdos_write	proc	far
+		push	bp			; linkage
+		mov 	bp,sp
+		push	si			; save all registers for safety
+		push	di
+		push	bx
+		push	cx
+		push	dx
+		push	es
+		push	ds
+		mov	bx,word ptr [bp+6]	; file handle
+		lds	dx,dword ptr [bp+8]	; buffer address
+		mov	cx,word ptr [bp+12]	; number of bytes
+		mov	ah,40h			; write file
+		int	21h
+		jc	write_err		; if failed, return error code
+		cmp	ax,word ptr [bp+12]	; make sure all bytes written
+		je	write_ok
+		mov	ax,1			; else return 1 for not OK
+		jmp	short write_err
+write_ok:	xor	ax,ax			; return zero for OK
+write_err:	pop	ds			; restore registers and exit
+		pop	es
+		pop	dx
+		pop	cx
+		pop	bx
+		pop	di
+		pop	si
+		pop 	bp
+		ret
+_jdos_write	endp
+
+
+;
+; void far jxms_getdriver (XMSDRIVER far *)
+;
+; Get the address of the XMS driver, or NULL if not available
+;
+_jxms_getdriver	proc	far
+		push	bp			; linkage
+		mov 	bp,sp
+		push	si			; save all registers for safety
+		push	di
+		push	bx
+		push	cx
+		push	dx
+		push	es
+		push	ds
+		mov 	ax,4300h		; call multiplex interrupt with
+		int	2fh			; a magic cookie, hex 4300
+		cmp 	al,80h			; AL should contain hex 80
+		je	xmsavail
+		xor 	dx,dx			; no XMS driver available
+		xor 	ax,ax			; return a nil pointer
+		jmp	short xmsavail_done
+xmsavail:	mov 	ax,4310h		; fetch driver address with
+		int	2fh			; another magic cookie
+		mov 	dx,es			; copy address to dx:ax
+		mov 	ax,bx
+xmsavail_done:	les 	bx,dword ptr [bp+6]	; get pointer to return value
+		mov	word ptr es:[bx],ax
+		mov	word ptr es:[bx+2],dx
+		pop	ds			; restore registers and exit
+		pop	es
+		pop	dx
+		pop	cx
+		pop	bx
+		pop	di
+		pop	si
+		pop	bp
+		ret
+_jxms_getdriver	endp
+
+
+;
+; void far jxms_calldriver (XMSDRIVER, XMScontext far *)
+;
+; The XMScontext structure contains values for the AX,DX,BX,SI,DS registers.
+; These are loaded, the XMS call is performed, and the new values of the
+; AX,DX,BX registers are written back to the context structure.
+;
+_jxms_calldriver 	proc	far
+		push	bp			; linkage
+		mov 	bp,sp
+		push	si			; save all registers for safety
+		push	di
+		push	bx
+		push	cx
+		push	dx
+		push	es
+		push	ds
+		les 	bx,dword ptr [bp+10]	; get XMScontext pointer
+		mov 	ax,word ptr es:[bx]	; load registers
+		mov 	dx,word ptr es:[bx+2]
+		mov 	si,word ptr es:[bx+6]
+		mov 	ds,word ptr es:[bx+8]
+		mov 	bx,word ptr es:[bx+4]
+		call	dword ptr [bp+6]	; call the driver
+		mov	cx,bx			; save returned BX for a sec
+		les 	bx,dword ptr [bp+10]	; get XMScontext pointer
+		mov 	word ptr es:[bx],ax	; put back ax,dx,bx
+		mov 	word ptr es:[bx+2],dx
+		mov 	word ptr es:[bx+4],cx
+		pop	ds			; restore registers and exit
+		pop	es
+		pop	dx
+		pop	cx
+		pop	bx
+		pop	di
+		pop	si
+		pop 	bp
+		ret
+_jxms_calldriver 	endp
+
+
+;
+; short far jems_available (void)
+;
+; Have we got an EMS driver? (this comes straight from the EMS 4.0 specs)
+;
+_jems_available	proc	far
+		push	si			; save all registers for safety
+		push	di
+		push	bx
+		push	cx
+		push	dx
+		push	es
+		push	ds
+		mov	ax,3567h		; get interrupt vector 67h
+		int	21h
+		push	cs
+		pop	ds
+		mov	di,000ah		; check offs 10 in returned seg
+		lea	si,ASCII_device_name	; against literal string
+		mov	cx,8
+		cld
+		repe cmpsb
+		jne	no_ems
+		mov	ax,1			; match, it's there
+		jmp	short avail_done
+no_ems:		xor	ax,ax			; it's not there
+avail_done:	pop	ds			; restore registers and exit
+		pop	es
+		pop	dx
+		pop	cx
+		pop	bx
+		pop	di
+		pop	si
+		ret
+
+ASCII_device_name	db	"EMMXXXX0"
+
+_jems_available	endp
+
+
+;
+; void far jems_calldriver (EMScontext far *)
+;
+; The EMScontext structure contains values for the AX,DX,BX,SI,DS registers.
+; These are loaded, the EMS trap is performed, and the new values of the
+; AX,DX,BX registers are written back to the context structure.
+;
+_jems_calldriver	proc far
+		push	bp			; linkage
+		mov 	bp,sp
+		push	si			; save all registers for safety
+		push	di
+		push	bx
+		push	cx
+		push	dx
+		push	es
+		push	ds
+		les 	bx,dword ptr [bp+6]	; get EMScontext pointer
+		mov 	ax,word ptr es:[bx]	; load registers
+		mov 	dx,word ptr es:[bx+2]
+		mov 	si,word ptr es:[bx+6]
+		mov 	ds,word ptr es:[bx+8]
+		mov 	bx,word ptr es:[bx+4]
+		int	67h			; call the EMS driver
+		mov	cx,bx			; save returned BX for a sec
+		les 	bx,dword ptr [bp+6]	; get EMScontext pointer
+		mov 	word ptr es:[bx],ax	; put back ax,dx,bx
+		mov 	word ptr es:[bx+2],dx
+		mov 	word ptr es:[bx+4],cx
+		pop	ds			; restore registers and exit
+		pop	es
+		pop	dx
+		pop	cx
+		pop	bx
+		pop	di
+		pop	si
+		pop 	bp
+		ret
+_jems_calldriver	endp
+
+JMEMDOSA_TXT	ends
+
+		end
diff --git a/source/Irrlicht/jpeglib/jmemmac.c b/source/Irrlicht/jpeglib/jmemmac.c
new file mode 100644
index 00000000..a6f043ed
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jmemmac.c
@@ -0,0 +1,289 @@
+/*
+ * jmemmac.c
+ *
+ * Copyright (C) 1992-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * jmemmac.c provides an Apple Macintosh implementation of the system-
+ * dependent portion of the JPEG memory manager.
+ *
+ * If you use jmemmac.c, then you must define USE_MAC_MEMMGR in the
+ * JPEG_INTERNALS part of jconfig.h.
+ *
+ * jmemmac.c uses the Macintosh toolbox routines NewPtr and DisposePtr
+ * instead of malloc and free.  It accurately determines the amount of
+ * memory available by using CompactMem.  Notice that if left to its
+ * own devices, this code can chew up all available space in the
+ * application's zone, with the exception of the rather small "slop"
+ * factor computed in jpeg_mem_available().  The application can ensure
+ * that more space is left over by reducing max_memory_to_use.
+ *
+ * Large images are swapped to disk using temporary files and System 7.0+'s
+ * temporary folder functionality.
+ *
+ * Note that jmemmac.c depends on two features of MacOS that were first
+ * introduced in System 7: FindFolder and the FSSpec-based calls.
+ * If your application uses jmemmac.c and is run under System 6 or earlier,
+ * and the jpeg library decides it needs a temporary file, it will abort,
+ * printing error messages about requiring System 7.  (If no temporary files
+ * are created, it will run fine.)
+ *
+ * If you want to use jmemmac.c in an application that might be used with
+ * System 6 or earlier, then you should remove dependencies on FindFolder
+ * and the FSSpec calls.  You will need to replace FindFolder with some
+ * other mechanism for finding a place to put temporary files, and you
+ * should replace the FSSpec calls with their HFS equivalents:
+ *
+ *     FSpDelete     ->  HDelete
+ *     FSpGetFInfo   ->  HGetFInfo
+ *     FSpCreate     ->  HCreate
+ *     FSpOpenDF     ->  HOpen      *** Note: not HOpenDF ***
+ *     FSMakeFSSpec  ->  (fill in spec by hand.)
+ *
+ * (Use HOpen instead of HOpenDF.  HOpen is just a glue-interface to PBHOpen,
+ * which is on all HFS macs.  HOpenDF is a System 7 addition which avoids the
+ * ages-old problem of names starting with a period.)
+ *
+ * Contributed by Sam Bushell (jsam@iagu.on.net) and
+ * Dan Gildor (gyld@in-touch.com).
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h"    /* import the system-dependent declarations */
+
+#ifndef USE_MAC_MEMMGR	/* make sure user got configuration right */
+  You forgot to define USE_MAC_MEMMGR in jconfig.h. /* deliberate syntax error */
+#endif
+
+#include      /* we use the MacOS memory manager */
+#include       /* we use the MacOS File stuff */
+#include     /* we use the MacOS HFS stuff */
+#include      /* for smSystemScript */
+#include     /* we use Gestalt to test for specific functionality */
+
+#ifndef TEMP_FILE_NAME		/* can override from jconfig.h or Makefile */
+#define TEMP_FILE_NAME  "JPG%03d.TMP"
+#endif
+
+static int next_file_num;	/* to distinguish among several temp files */
+
+
+/*
+ * Memory allocation and freeing are controlled by the MacOS library
+ * routines NewPtr() and DisposePtr(), which allocate fixed-address
+ * storage.  Unfortunately, the IJG library isn't smart enough to cope
+ * with relocatable storage.
+ */
+
+GLOBAL(void *)
+jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
+{
+  return (void *) NewPtr(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
+{
+  DisposePtr((Ptr) object);
+}
+
+
+/*
+ * "Large" objects are treated the same as "small" ones.
+ * NB: we include FAR keywords in the routine declarations simply for
+ * consistency with the rest of the IJG code; FAR should expand to empty
+ * on rational architectures like the Mac.
+ */
+
+GLOBAL(void FAR *)
+jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
+{
+  return (void FAR *) NewPtr(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
+{
+  DisposePtr((Ptr) object);
+}
+
+
+/*
+ * This routine computes the total memory space available for allocation.
+ */
+
+GLOBAL(long)
+jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
+		    long max_bytes_needed, long already_allocated)
+{
+  long limit = cinfo->mem->max_memory_to_use - already_allocated;
+  long slop, mem;
+
+  /* Don't ask for more than what application has told us we may use */
+  if (max_bytes_needed > limit && limit > 0)
+    max_bytes_needed = limit;
+  /* Find whether there's a big enough free block in the heap.
+   * CompactMem tries to create a contiguous block of the requested size,
+   * and then returns the size of the largest free block (which could be
+   * much more or much less than we asked for).
+   * We add some slop to ensure we don't use up all available memory.
+   */
+  slop = max_bytes_needed / 16 + 32768L;
+  mem = CompactMem(max_bytes_needed + slop) - slop;
+  if (mem < 0)
+    mem = 0;			/* sigh, couldn't even get the slop */
+  /* Don't take more than the application says we can have */
+  if (mem > limit && limit > 0)
+    mem = limit;
+  return mem;
+}
+
+
+/*
+ * Backing store (temporary file) management.
+ * Backing store objects are only used when the value returned by
+ * jpeg_mem_available is less than the total space needed.  You can dispense
+ * with these routines if you have plenty of virtual memory; see jmemnobs.c.
+ */
+
+
+METHODDEF(void)
+read_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+		    void FAR * buffer_address,
+		    long file_offset, long byte_count)
+{
+  long bytes = byte_count;
+  long retVal;
+
+  if ( SetFPos ( info->temp_file, fsFromStart, file_offset ) != noErr )
+    ERREXIT(cinfo, JERR_TFILE_SEEK);
+
+  retVal = FSRead ( info->temp_file, &bytes,
+		    (unsigned char *) buffer_address );
+  if ( retVal != noErr || bytes != byte_count )
+    ERREXIT(cinfo, JERR_TFILE_READ);
+}
+
+
+METHODDEF(void)
+write_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+		     void FAR * buffer_address,
+		     long file_offset, long byte_count)
+{
+  long bytes = byte_count;
+  long retVal;
+
+  if ( SetFPos ( info->temp_file, fsFromStart, file_offset ) != noErr )
+    ERREXIT(cinfo, JERR_TFILE_SEEK);
+
+  retVal = FSWrite ( info->temp_file, &bytes,
+		     (unsigned char *) buffer_address );
+  if ( retVal != noErr || bytes != byte_count )
+    ERREXIT(cinfo, JERR_TFILE_WRITE);
+}
+
+
+METHODDEF(void)
+close_backing_store (j_common_ptr cinfo, backing_store_ptr info)
+{
+  FSClose ( info->temp_file );
+  FSpDelete ( &(info->tempSpec) );
+}
+
+
+/*
+ * Initial opening of a backing-store object.
+ *
+ * This version uses FindFolder to find the Temporary Items folder,
+ * and puts the temporary file in there.
+ */
+
+GLOBAL(void)
+jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+			 long total_bytes_needed)
+{
+  short         tmpRef, vRefNum;
+  long          dirID;
+  FInfo         finderInfo;
+  FSSpec        theSpec;
+  Str255        fName;
+  OSErr         osErr;
+  long          gestaltResponse = 0;
+
+  /* Check that FSSpec calls are available. */
+  osErr = Gestalt( gestaltFSAttr, &gestaltResponse );
+  if ( ( osErr != noErr )
+       || !( gestaltResponse & (1<temp_name, TEMP_FILE_NAME, next_file_num);
+    strcpy ( (Ptr)fName+1, info->temp_name );
+    *fName = strlen (info->temp_name);
+    osErr = FSMakeFSSpec ( vRefNum, dirID, fName, &theSpec );
+
+    if ( (osErr = FSpGetFInfo ( &theSpec, &finderInfo ) ) != noErr )
+      break;
+  }
+
+  osErr = FSpCreate ( &theSpec, '????', '????', smSystemScript );
+  if ( osErr != noErr )
+    ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
+
+  osErr = FSpOpenDF ( &theSpec, fsRdWrPerm, &(info->temp_file) );
+  if ( osErr != noErr )
+    ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
+
+  info->tempSpec = theSpec;
+
+  info->read_backing_store = read_backing_store;
+  info->write_backing_store = write_backing_store;
+  info->close_backing_store = close_backing_store;
+  TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name);
+}
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required.
+ */
+
+GLOBAL(long)
+jpeg_mem_init (j_common_ptr cinfo)
+{
+  next_file_num = 0;
+
+  /* max_memory_to_use will be initialized to FreeMem()'s result;
+   * the calling application might later reduce it, for example
+   * to leave room to invoke multiple JPEG objects.
+   * Note that FreeMem returns the total number of free bytes;
+   * it may not be possible to allocate a single block of this size.
+   */
+  return FreeMem();
+}
+
+GLOBAL(void)
+jpeg_mem_term (j_common_ptr cinfo)
+{
+  /* no work */
+}
diff --git a/source/Irrlicht/jpeglib/jmemmgr.c b/source/Irrlicht/jpeglib/jmemmgr.c
new file mode 100644
index 00000000..ea934202
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jmemmgr.c
@@ -0,0 +1,1119 @@
+/*
+ * jmemmgr.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2011-2012 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the JPEG system-independent memory management
+ * routines.  This code is usable across a wide variety of machines; most
+ * of the system dependencies have been isolated in a separate file.
+ * The major functions provided here are:
+ *   * pool-based allocation and freeing of memory;
+ *   * policy decisions about how to divide available memory among the
+ *     virtual arrays;
+ *   * control logic for swapping virtual arrays between main memory and
+ *     backing storage.
+ * The separate system-dependent file provides the actual backing-storage
+ * access code, and it contains the policy decision about how much total
+ * main memory to use.
+ * This file is system-dependent in the sense that some of its functions
+ * are unnecessary in some systems.  For example, if there is enough virtual
+ * memory so that backing storage will never be used, much of the virtual
+ * array control logic could be removed.  (Of course, if you have that much
+ * memory then you shouldn't care about a little bit of unused code...)
+ */
+
+#define JPEG_INTERNALS
+#define AM_MEMORY_MANAGER	/* we define jvirt_Xarray_control structs */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h"		/* import the system-dependent declarations */
+
+#ifndef NO_GETENV
+#ifndef HAVE_STDLIB_H		/*  should declare getenv() */
+extern char * getenv JPP((const char * name));
+#endif
+#endif
+
+
+/*
+ * Some important notes:
+ *   The allocation routines provided here must never return NULL.
+ *   They should exit to error_exit if unsuccessful.
+ *
+ *   It's not a good idea to try to merge the sarray and barray routines,
+ *   even though they are textually almost the same, because samples are
+ *   usually stored as bytes while coefficients are shorts or ints.  Thus,
+ *   in machines where byte pointers have a different representation from
+ *   word pointers, the resulting machine code could not be the same.
+ */
+
+
+/*
+ * Many machines require storage alignment: longs must start on 4-byte
+ * boundaries, doubles on 8-byte boundaries, etc.  On such machines, malloc()
+ * always returns pointers that are multiples of the worst-case alignment
+ * requirement, and we had better do so too.
+ * There isn't any really portable way to determine the worst-case alignment
+ * requirement.  This module assumes that the alignment requirement is
+ * multiples of sizeof(ALIGN_TYPE).
+ * By default, we define ALIGN_TYPE as double.  This is necessary on some
+ * workstations (where doubles really do need 8-byte alignment) and will work
+ * fine on nearly everything.  If your machine has lesser alignment needs,
+ * you can save a few bytes by making ALIGN_TYPE smaller.
+ * The only place I know of where this will NOT work is certain Macintosh
+ * 680x0 compilers that define double as a 10-byte IEEE extended float.
+ * Doing 10-byte alignment is counterproductive because longwords won't be
+ * aligned well.  Put "#define ALIGN_TYPE long" in jconfig.h if you have
+ * such a compiler.
+ */
+
+#ifndef ALIGN_TYPE		/* so can override from jconfig.h */
+#define ALIGN_TYPE  double
+#endif
+
+
+/*
+ * We allocate objects from "pools", where each pool is gotten with a single
+ * request to jpeg_get_small() or jpeg_get_large().  There is no per-object
+ * overhead within a pool, except for alignment padding.  Each pool has a
+ * header with a link to the next pool of the same class.
+ * Small and large pool headers are identical except that the latter's
+ * link pointer must be FAR on 80x86 machines.
+ * Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE
+ * field.  This forces the compiler to make SIZEOF(small_pool_hdr) a multiple
+ * of the alignment requirement of ALIGN_TYPE.
+ */
+
+typedef union small_pool_struct * small_pool_ptr;
+
+typedef union small_pool_struct {
+  struct {
+    small_pool_ptr next;	/* next in list of pools */
+    size_t bytes_used;		/* how many bytes already used within pool */
+    size_t bytes_left;		/* bytes still available in this pool */
+  } hdr;
+  ALIGN_TYPE dummy;		/* included in union to ensure alignment */
+} small_pool_hdr;
+
+typedef union large_pool_struct FAR * large_pool_ptr;
+
+typedef union large_pool_struct {
+  struct {
+    large_pool_ptr next;	/* next in list of pools */
+    size_t bytes_used;		/* how many bytes already used within pool */
+    size_t bytes_left;		/* bytes still available in this pool */
+  } hdr;
+  ALIGN_TYPE dummy;		/* included in union to ensure alignment */
+} large_pool_hdr;
+
+
+/*
+ * Here is the full definition of a memory manager object.
+ */
+
+typedef struct {
+  struct jpeg_memory_mgr pub;	/* public fields */
+
+  /* Each pool identifier (lifetime class) names a linked list of pools. */
+  small_pool_ptr small_list[JPOOL_NUMPOOLS];
+  large_pool_ptr large_list[JPOOL_NUMPOOLS];
+
+  /* Since we only have one lifetime class of virtual arrays, only one
+   * linked list is necessary (for each datatype).  Note that the virtual
+   * array control blocks being linked together are actually stored somewhere
+   * in the small-pool list.
+   */
+  jvirt_sarray_ptr virt_sarray_list;
+  jvirt_barray_ptr virt_barray_list;
+
+  /* This counts total space obtained from jpeg_get_small/large */
+  long total_space_allocated;
+
+  /* alloc_sarray and alloc_barray set this value for use by virtual
+   * array routines.
+   */
+  JDIMENSION last_rowsperchunk;	/* from most recent alloc_sarray/barray */
+} my_memory_mgr;
+
+typedef my_memory_mgr * my_mem_ptr;
+
+
+/*
+ * The control blocks for virtual arrays.
+ * Note that these blocks are allocated in the "small" pool area.
+ * System-dependent info for the associated backing store (if any) is hidden
+ * inside the backing_store_info struct.
+ */
+
+struct jvirt_sarray_control {
+  JSAMPARRAY mem_buffer;	/* => the in-memory buffer */
+  JDIMENSION rows_in_array;	/* total virtual array height */
+  JDIMENSION samplesperrow;	/* width of array (and of memory buffer) */
+  JDIMENSION maxaccess;		/* max rows accessed by access_virt_sarray */
+  JDIMENSION rows_in_mem;	/* height of memory buffer */
+  JDIMENSION rowsperchunk;	/* allocation chunk size in mem_buffer */
+  JDIMENSION cur_start_row;	/* first logical row # in the buffer */
+  JDIMENSION first_undef_row;	/* row # of first uninitialized row */
+  boolean pre_zero;		/* pre-zero mode requested? */
+  boolean dirty;		/* do current buffer contents need written? */
+  boolean b_s_open;		/* is backing-store data valid? */
+  jvirt_sarray_ptr next;	/* link to next virtual sarray control block */
+  backing_store_info b_s_info;	/* System-dependent control info */
+};
+
+struct jvirt_barray_control {
+  JBLOCKARRAY mem_buffer;	/* => the in-memory buffer */
+  JDIMENSION rows_in_array;	/* total virtual array height */
+  JDIMENSION blocksperrow;	/* width of array (and of memory buffer) */
+  JDIMENSION maxaccess;		/* max rows accessed by access_virt_barray */
+  JDIMENSION rows_in_mem;	/* height of memory buffer */
+  JDIMENSION rowsperchunk;	/* allocation chunk size in mem_buffer */
+  JDIMENSION cur_start_row;	/* first logical row # in the buffer */
+  JDIMENSION first_undef_row;	/* row # of first uninitialized row */
+  boolean pre_zero;		/* pre-zero mode requested? */
+  boolean dirty;		/* do current buffer contents need written? */
+  boolean b_s_open;		/* is backing-store data valid? */
+  jvirt_barray_ptr next;	/* link to next virtual barray control block */
+  backing_store_info b_s_info;	/* System-dependent control info */
+};
+
+
+#ifdef MEM_STATS		/* optional extra stuff for statistics */
+
+LOCAL(void)
+print_mem_stats (j_common_ptr cinfo, int pool_id)
+{
+  my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+  small_pool_ptr shdr_ptr;
+  large_pool_ptr lhdr_ptr;
+
+  /* Since this is only a debugging stub, we can cheat a little by using
+   * fprintf directly rather than going through the trace message code.
+   * This is helpful because message parm array can't handle longs.
+   */
+  fprintf(stderr, "Freeing pool %d, total space = %ld\n",
+	  pool_id, mem->total_space_allocated);
+
+  for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL;
+       lhdr_ptr = lhdr_ptr->hdr.next) {
+    fprintf(stderr, "  Large chunk used %ld\n",
+	    (long) lhdr_ptr->hdr.bytes_used);
+  }
+
+  for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL;
+       shdr_ptr = shdr_ptr->hdr.next) {
+    fprintf(stderr, "  Small chunk used %ld free %ld\n",
+	    (long) shdr_ptr->hdr.bytes_used,
+	    (long) shdr_ptr->hdr.bytes_left);
+  }
+}
+
+#endif /* MEM_STATS */
+
+
+LOCAL(noreturn_t)
+out_of_memory (j_common_ptr cinfo, int which)
+/* Report an out-of-memory error and stop execution */
+/* If we compiled MEM_STATS support, report alloc requests before dying */
+{
+#ifdef MEM_STATS
+  cinfo->err->trace_level = 2;	/* force self_destruct to report stats */
+#endif
+  ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which);
+}
+
+
+/*
+ * Allocation of "small" objects.
+ *
+ * For these, we use pooled storage.  When a new pool must be created,
+ * we try to get enough space for the current request plus a "slop" factor,
+ * where the slop will be the amount of leftover space in the new pool.
+ * The speed vs. space tradeoff is largely determined by the slop values.
+ * A different slop value is provided for each pool class (lifetime),
+ * and we also distinguish the first pool of a class from later ones.
+ * NOTE: the values given work fairly well on both 16- and 32-bit-int
+ * machines, but may be too small if longs are 64 bits or more.
+ */
+
+static const size_t first_pool_slop[JPOOL_NUMPOOLS] = 
+{
+	1600,			/* first PERMANENT pool */
+	16000			/* first IMAGE pool */
+};
+
+static const size_t extra_pool_slop[JPOOL_NUMPOOLS] = 
+{
+	0,			/* additional PERMANENT pools */
+	5000			/* additional IMAGE pools */
+};
+
+#define MIN_SLOP  50		/* greater than 0 to avoid futile looping */
+
+
+METHODDEF(void *)
+alloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject)
+/* Allocate a "small" object */
+{
+  my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+  small_pool_ptr hdr_ptr, prev_hdr_ptr;
+  char * data_ptr;
+  size_t odd_bytes, min_request, slop;
+
+  /* Check for unsatisfiable request (do now to ensure no overflow below) */
+  if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr)))
+    out_of_memory(cinfo, 1);	/* request exceeds malloc's ability */
+
+  /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */
+  odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE);
+  if (odd_bytes > 0)
+    sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes;
+
+  /* See if space is available in any existing pool */
+  if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)
+    ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id);	/* safety check */
+  prev_hdr_ptr = NULL;
+  hdr_ptr = mem->small_list[pool_id];
+  while (hdr_ptr != NULL) {
+    if (hdr_ptr->hdr.bytes_left >= sizeofobject)
+      break;			/* found pool with enough space */
+    prev_hdr_ptr = hdr_ptr;
+    hdr_ptr = hdr_ptr->hdr.next;
+  }
+
+  /* Time to make a new pool? */
+  if (hdr_ptr == NULL) {
+    /* min_request is what we need now, slop is what will be leftover */
+    min_request = sizeofobject + SIZEOF(small_pool_hdr);
+    if (prev_hdr_ptr == NULL)	/* first pool in class? */
+      slop = first_pool_slop[pool_id];
+    else
+      slop = extra_pool_slop[pool_id];
+    /* Don't ask for more than MAX_ALLOC_CHUNK */
+    if (slop > (size_t) (MAX_ALLOC_CHUNK-min_request))
+      slop = (size_t) (MAX_ALLOC_CHUNK-min_request);
+    /* Try to get space, if fail reduce slop and try again */
+    for (;;) {
+      hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop);
+      if (hdr_ptr != NULL)
+	break;
+      slop /= 2;
+      if (slop < MIN_SLOP)	/* give up when it gets real small */
+	out_of_memory(cinfo, 2); /* jpeg_get_small failed */
+    }
+    mem->total_space_allocated += min_request + slop;
+    /* Success, initialize the new pool header and add to end of list */
+    hdr_ptr->hdr.next = NULL;
+    hdr_ptr->hdr.bytes_used = 0;
+    hdr_ptr->hdr.bytes_left = sizeofobject + slop;
+    if (prev_hdr_ptr == NULL)	/* first pool in class? */
+      mem->small_list[pool_id] = hdr_ptr;
+    else
+      prev_hdr_ptr->hdr.next = hdr_ptr;
+  }
+
+  /* OK, allocate the object from the current pool */
+  data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */
+  data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */
+  hdr_ptr->hdr.bytes_used += sizeofobject;
+  hdr_ptr->hdr.bytes_left -= sizeofobject;
+
+  return (void *) data_ptr;
+}
+
+
+/*
+ * Allocation of "large" objects.
+ *
+ * The external semantics of these are the same as "small" objects,
+ * except that FAR pointers are used on 80x86.  However the pool
+ * management heuristics are quite different.  We assume that each
+ * request is large enough that it may as well be passed directly to
+ * jpeg_get_large; the pool management just links everything together
+ * so that we can free it all on demand.
+ * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY
+ * structures.  The routines that create these structures (see below)
+ * deliberately bunch rows together to ensure a large request size.
+ */
+
+METHODDEF(void FAR *)
+alloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject)
+/* Allocate a "large" object */
+{
+  my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+  large_pool_ptr hdr_ptr;
+  size_t odd_bytes;
+
+  /* Check for unsatisfiable request (do now to ensure no overflow below) */
+  if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)))
+    out_of_memory(cinfo, 3);	/* request exceeds malloc's ability */
+
+  /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */
+  odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE);
+  if (odd_bytes > 0)
+    sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes;
+
+  /* Always make a new pool */
+  if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)
+    ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id);	/* safety check */
+
+  hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject +
+					    SIZEOF(large_pool_hdr));
+  if (hdr_ptr == NULL)
+    out_of_memory(cinfo, 4);	/* jpeg_get_large failed */
+  mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr);
+
+  /* Success, initialize the new pool header and add to list */
+  hdr_ptr->hdr.next = mem->large_list[pool_id];
+  /* We maintain space counts in each pool header for statistical purposes,
+   * even though they are not needed for allocation.
+   */
+  hdr_ptr->hdr.bytes_used = sizeofobject;
+  hdr_ptr->hdr.bytes_left = 0;
+  mem->large_list[pool_id] = hdr_ptr;
+
+  return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */
+}
+
+
+/*
+ * Creation of 2-D sample arrays.
+ * The pointers are in near heap, the samples themselves in FAR heap.
+ *
+ * To minimize allocation overhead and to allow I/O of large contiguous
+ * blocks, we allocate the sample rows in groups of as many rows as possible
+ * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request.
+ * NB: the virtual array control routines, later in this file, know about
+ * this chunking of rows.  The rowsperchunk value is left in the mem manager
+ * object so that it can be saved away if this sarray is the workspace for
+ * a virtual array.
+ */
+
+METHODDEF(JSAMPARRAY)
+alloc_sarray (j_common_ptr cinfo, int pool_id,
+	      JDIMENSION samplesperrow, JDIMENSION numrows)
+/* Allocate a 2-D sample array */
+{
+  my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+  JSAMPARRAY result;
+  JSAMPROW workspace;
+  JDIMENSION rowsperchunk, currow, i;
+  long ltemp;
+
+  /* Calculate max # of rows allowed in one allocation chunk */
+  ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) /
+	  ((long) samplesperrow * SIZEOF(JSAMPLE));
+  if (ltemp <= 0)
+    ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+  if (ltemp < (long) numrows)
+    rowsperchunk = (JDIMENSION) ltemp;
+  else
+    rowsperchunk = numrows;
+  mem->last_rowsperchunk = rowsperchunk;
+
+  /* Get space for row pointers (small object) */
+  result = (JSAMPARRAY) alloc_small(cinfo, pool_id,
+				    (size_t) (numrows * SIZEOF(JSAMPROW)));
+
+  /* Get the rows themselves (large objects) */
+  currow = 0;
+  while (currow < numrows) {
+    rowsperchunk = MIN(rowsperchunk, numrows - currow);
+    workspace = (JSAMPROW) alloc_large(cinfo, pool_id,
+	(size_t) ((size_t) rowsperchunk * (size_t) samplesperrow
+		  * SIZEOF(JSAMPLE)));
+    for (i = rowsperchunk; i > 0; i--) {
+      result[currow++] = workspace;
+      workspace += samplesperrow;
+    }
+  }
+
+  return result;
+}
+
+
+/*
+ * Creation of 2-D coefficient-block arrays.
+ * This is essentially the same as the code for sample arrays, above.
+ */
+
+METHODDEF(JBLOCKARRAY)
+alloc_barray (j_common_ptr cinfo, int pool_id,
+	      JDIMENSION blocksperrow, JDIMENSION numrows)
+/* Allocate a 2-D coefficient-block array */
+{
+  my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+  JBLOCKARRAY result;
+  JBLOCKROW workspace;
+  JDIMENSION rowsperchunk, currow, i;
+  long ltemp;
+
+  /* Calculate max # of rows allowed in one allocation chunk */
+  ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) /
+	  ((long) blocksperrow * SIZEOF(JBLOCK));
+  if (ltemp <= 0)
+    ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+  if (ltemp < (long) numrows)
+    rowsperchunk = (JDIMENSION) ltemp;
+  else
+    rowsperchunk = numrows;
+  mem->last_rowsperchunk = rowsperchunk;
+
+  /* Get space for row pointers (small object) */
+  result = (JBLOCKARRAY) alloc_small(cinfo, pool_id,
+				     (size_t) (numrows * SIZEOF(JBLOCKROW)));
+
+  /* Get the rows themselves (large objects) */
+  currow = 0;
+  while (currow < numrows) {
+    rowsperchunk = MIN(rowsperchunk, numrows - currow);
+    workspace = (JBLOCKROW) alloc_large(cinfo, pool_id,
+	(size_t) ((size_t) rowsperchunk * (size_t) blocksperrow
+		  * SIZEOF(JBLOCK)));
+    for (i = rowsperchunk; i > 0; i--) {
+      result[currow++] = workspace;
+      workspace += blocksperrow;
+    }
+  }
+
+  return result;
+}
+
+
+/*
+ * About virtual array management:
+ *
+ * The above "normal" array routines are only used to allocate strip buffers
+ * (as wide as the image, but just a few rows high).  Full-image-sized buffers
+ * are handled as "virtual" arrays.  The array is still accessed a strip at a
+ * time, but the memory manager must save the whole array for repeated
+ * accesses.  The intended implementation is that there is a strip buffer in
+ * memory (as high as is possible given the desired memory limit), plus a
+ * backing file that holds the rest of the array.
+ *
+ * The request_virt_array routines are told the total size of the image and
+ * the maximum number of rows that will be accessed at once.  The in-memory
+ * buffer must be at least as large as the maxaccess value.
+ *
+ * The request routines create control blocks but not the in-memory buffers.
+ * That is postponed until realize_virt_arrays is called.  At that time the
+ * total amount of space needed is known (approximately, anyway), so free
+ * memory can be divided up fairly.
+ *
+ * The access_virt_array routines are responsible for making a specific strip
+ * area accessible (after reading or writing the backing file, if necessary).
+ * Note that the access routines are told whether the caller intends to modify
+ * the accessed strip; during a read-only pass this saves having to rewrite
+ * data to disk.  The access routines are also responsible for pre-zeroing
+ * any newly accessed rows, if pre-zeroing was requested.
+ *
+ * In current usage, the access requests are usually for nonoverlapping
+ * strips; that is, successive access start_row numbers differ by exactly
+ * num_rows = maxaccess.  This means we can get good performance with simple
+ * buffer dump/reload logic, by making the in-memory buffer be a multiple
+ * of the access height; then there will never be accesses across bufferload
+ * boundaries.  The code will still work with overlapping access requests,
+ * but it doesn't handle bufferload overlaps very efficiently.
+ */
+
+
+METHODDEF(jvirt_sarray_ptr)
+request_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero,
+		     JDIMENSION samplesperrow, JDIMENSION numrows,
+		     JDIMENSION maxaccess)
+/* Request a virtual 2-D sample array */
+{
+  my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+  jvirt_sarray_ptr result;
+
+  /* Only IMAGE-lifetime virtual arrays are currently supported */
+  if (pool_id != JPOOL_IMAGE)
+    ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id);	/* safety check */
+
+  /* get control block */
+  result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id,
+					  SIZEOF(struct jvirt_sarray_control));
+
+  result->mem_buffer = NULL;	/* marks array not yet realized */
+  result->rows_in_array = numrows;
+  result->samplesperrow = samplesperrow;
+  result->maxaccess = maxaccess;
+  result->pre_zero = pre_zero;
+  result->b_s_open = FALSE;	/* no associated backing-store object */
+  result->next = mem->virt_sarray_list; /* add to list of virtual arrays */
+  mem->virt_sarray_list = result;
+
+  return result;
+}
+
+
+METHODDEF(jvirt_barray_ptr)
+request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero,
+		     JDIMENSION blocksperrow, JDIMENSION numrows,
+		     JDIMENSION maxaccess)
+/* Request a virtual 2-D coefficient-block array */
+{
+  my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+  jvirt_barray_ptr result;
+
+  /* Only IMAGE-lifetime virtual arrays are currently supported */
+  if (pool_id != JPOOL_IMAGE)
+    ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id);	/* safety check */
+
+  /* get control block */
+  result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id,
+					  SIZEOF(struct jvirt_barray_control));
+
+  result->mem_buffer = NULL;	/* marks array not yet realized */
+  result->rows_in_array = numrows;
+  result->blocksperrow = blocksperrow;
+  result->maxaccess = maxaccess;
+  result->pre_zero = pre_zero;
+  result->b_s_open = FALSE;	/* no associated backing-store object */
+  result->next = mem->virt_barray_list; /* add to list of virtual arrays */
+  mem->virt_barray_list = result;
+
+  return result;
+}
+
+
+METHODDEF(void)
+realize_virt_arrays (j_common_ptr cinfo)
+/* Allocate the in-memory buffers for any unrealized virtual arrays */
+{
+  my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+  long space_per_minheight, maximum_space, avail_mem;
+  long minheights, max_minheights;
+  jvirt_sarray_ptr sptr;
+  jvirt_barray_ptr bptr;
+
+  /* Compute the minimum space needed (maxaccess rows in each buffer)
+   * and the maximum space needed (full image height in each buffer).
+   * These may be of use to the system-dependent jpeg_mem_available routine.
+   */
+  space_per_minheight = 0;
+  maximum_space = 0;
+  for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
+    if (sptr->mem_buffer == NULL) { /* if not realized yet */
+      space_per_minheight += (long) sptr->maxaccess *
+			     (long) sptr->samplesperrow * SIZEOF(JSAMPLE);
+      maximum_space += (long) sptr->rows_in_array *
+		       (long) sptr->samplesperrow * SIZEOF(JSAMPLE);
+    }
+  }
+  for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {
+    if (bptr->mem_buffer == NULL) { /* if not realized yet */
+      space_per_minheight += (long) bptr->maxaccess *
+			     (long) bptr->blocksperrow * SIZEOF(JBLOCK);
+      maximum_space += (long) bptr->rows_in_array *
+		       (long) bptr->blocksperrow * SIZEOF(JBLOCK);
+    }
+  }
+
+  if (space_per_minheight <= 0)
+    return;			/* no unrealized arrays, no work */
+
+  /* Determine amount of memory to actually use; this is system-dependent. */
+  avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space,
+				 mem->total_space_allocated);
+
+  /* If the maximum space needed is available, make all the buffers full
+   * height; otherwise parcel it out with the same number of minheights
+   * in each buffer.
+   */
+  if (avail_mem >= maximum_space)
+    max_minheights = 1000000000L;
+  else {
+    max_minheights = avail_mem / space_per_minheight;
+    /* If there doesn't seem to be enough space, try to get the minimum
+     * anyway.  This allows a "stub" implementation of jpeg_mem_available().
+     */
+    if (max_minheights <= 0)
+      max_minheights = 1;
+  }
+
+  /* Allocate the in-memory buffers and initialize backing store as needed. */
+
+  for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
+    if (sptr->mem_buffer == NULL) { /* if not realized yet */
+      minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L;
+      if (minheights <= max_minheights) {
+	/* This buffer fits in memory */
+	sptr->rows_in_mem = sptr->rows_in_array;
+      } else {
+	/* It doesn't fit in memory, create backing store. */
+	sptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess);
+	jpeg_open_backing_store(cinfo, & sptr->b_s_info,
+				(long) sptr->rows_in_array *
+				(long) sptr->samplesperrow *
+				(long) SIZEOF(JSAMPLE));
+	sptr->b_s_open = TRUE;
+      }
+      sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE,
+				      sptr->samplesperrow, sptr->rows_in_mem);
+      sptr->rowsperchunk = mem->last_rowsperchunk;
+      sptr->cur_start_row = 0;
+      sptr->first_undef_row = 0;
+      sptr->dirty = FALSE;
+    }
+  }
+
+  for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {
+    if (bptr->mem_buffer == NULL) { /* if not realized yet */
+      minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L;
+      if (minheights <= max_minheights) {
+	/* This buffer fits in memory */
+	bptr->rows_in_mem = bptr->rows_in_array;
+      } else {
+	/* It doesn't fit in memory, create backing store. */
+	bptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess);
+	jpeg_open_backing_store(cinfo, & bptr->b_s_info,
+				(long) bptr->rows_in_array *
+				(long) bptr->blocksperrow *
+				(long) SIZEOF(JBLOCK));
+	bptr->b_s_open = TRUE;
+      }
+      bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE,
+				      bptr->blocksperrow, bptr->rows_in_mem);
+      bptr->rowsperchunk = mem->last_rowsperchunk;
+      bptr->cur_start_row = 0;
+      bptr->first_undef_row = 0;
+      bptr->dirty = FALSE;
+    }
+  }
+}
+
+
+LOCAL(void)
+do_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing)
+/* Do backing store read or write of a virtual sample array */
+{
+  long bytesperrow, file_offset, byte_count, rows, thisrow, i;
+
+  bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE);
+  file_offset = ptr->cur_start_row * bytesperrow;
+  /* Loop to read or write each allocation chunk in mem_buffer */
+  for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) {
+    /* One chunk, but check for short chunk at end of buffer */
+    rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i);
+    /* Transfer no more than is currently defined */
+    thisrow = (long) ptr->cur_start_row + i;
+    rows = MIN(rows, (long) ptr->first_undef_row - thisrow);
+    /* Transfer no more than fits in file */
+    rows = MIN(rows, (long) ptr->rows_in_array - thisrow);
+    if (rows <= 0)		/* this chunk might be past end of file! */
+      break;
+    byte_count = rows * bytesperrow;
+    if (writing)
+      (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info,
+					    (void FAR *) ptr->mem_buffer[i],
+					    file_offset, byte_count);
+    else
+      (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info,
+					   (void FAR *) ptr->mem_buffer[i],
+					   file_offset, byte_count);
+    file_offset += byte_count;
+  }
+}
+
+
+LOCAL(void)
+do_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing)
+/* Do backing store read or write of a virtual coefficient-block array */
+{
+  long bytesperrow, file_offset, byte_count, rows, thisrow, i;
+
+  bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK);
+  file_offset = ptr->cur_start_row * bytesperrow;
+  /* Loop to read or write each allocation chunk in mem_buffer */
+  for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) {
+    /* One chunk, but check for short chunk at end of buffer */
+    rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i);
+    /* Transfer no more than is currently defined */
+    thisrow = (long) ptr->cur_start_row + i;
+    rows = MIN(rows, (long) ptr->first_undef_row - thisrow);
+    /* Transfer no more than fits in file */
+    rows = MIN(rows, (long) ptr->rows_in_array - thisrow);
+    if (rows <= 0)		/* this chunk might be past end of file! */
+      break;
+    byte_count = rows * bytesperrow;
+    if (writing)
+      (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info,
+					    (void FAR *) ptr->mem_buffer[i],
+					    file_offset, byte_count);
+    else
+      (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info,
+					   (void FAR *) ptr->mem_buffer[i],
+					   file_offset, byte_count);
+    file_offset += byte_count;
+  }
+}
+
+
+METHODDEF(JSAMPARRAY)
+access_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr,
+		    JDIMENSION start_row, JDIMENSION num_rows,
+		    boolean writable)
+/* Access the part of a virtual sample array starting at start_row */
+/* and extending for num_rows rows.  writable is true if  */
+/* caller intends to modify the accessed area. */
+{
+  JDIMENSION end_row = start_row + num_rows;
+  JDIMENSION undef_row;
+
+  /* debugging check */
+  if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||
+      ptr->mem_buffer == NULL)
+    ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+
+  /* Make the desired part of the virtual array accessible */
+  if (start_row < ptr->cur_start_row ||
+      end_row > ptr->cur_start_row+ptr->rows_in_mem) {
+    if (! ptr->b_s_open)
+      ERREXIT(cinfo, JERR_VIRTUAL_BUG);
+    /* Flush old buffer contents if necessary */
+    if (ptr->dirty) {
+      do_sarray_io(cinfo, ptr, TRUE);
+      ptr->dirty = FALSE;
+    }
+    /* Decide what part of virtual array to access.
+     * Algorithm: if target address > current window, assume forward scan,
+     * load starting at target address.  If target address < current window,
+     * assume backward scan, load so that target area is top of window.
+     * Note that when switching from forward write to forward read, will have
+     * start_row = 0, so the limiting case applies and we load from 0 anyway.
+     */
+    if (start_row > ptr->cur_start_row) {
+      ptr->cur_start_row = start_row;
+    } else {
+      /* use long arithmetic here to avoid overflow & unsigned problems */
+      long ltemp;
+
+      ltemp = (long) end_row - (long) ptr->rows_in_mem;
+      if (ltemp < 0)
+	ltemp = 0;		/* don't fall off front end of file */
+      ptr->cur_start_row = (JDIMENSION) ltemp;
+    }
+    /* Read in the selected part of the array.
+     * During the initial write pass, we will do no actual read
+     * because the selected part is all undefined.
+     */
+    do_sarray_io(cinfo, ptr, FALSE);
+  }
+  /* Ensure the accessed part of the array is defined; prezero if needed.
+   * To improve locality of access, we only prezero the part of the array
+   * that the caller is about to access, not the entire in-memory array.
+   */
+  if (ptr->first_undef_row < end_row) {
+    if (ptr->first_undef_row < start_row) {
+      if (writable)		/* writer skipped over a section of array */
+	ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+      undef_row = start_row;	/* but reader is allowed to read ahead */
+    } else {
+      undef_row = ptr->first_undef_row;
+    }
+    if (writable)
+      ptr->first_undef_row = end_row;
+    if (ptr->pre_zero) {
+      size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE);
+      undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */
+      end_row -= ptr->cur_start_row;
+      while (undef_row < end_row) {
+	FMEMZERO((void FAR *) ptr->mem_buffer[undef_row], bytesperrow);
+	undef_row++;
+      }
+    } else {
+      if (! writable)		/* reader looking at undefined data */
+	ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+    }
+  }
+  /* Flag the buffer dirty if caller will write in it */
+  if (writable)
+    ptr->dirty = TRUE;
+  /* Return address of proper part of the buffer */
+  return ptr->mem_buffer + (start_row - ptr->cur_start_row);
+}
+
+
+METHODDEF(JBLOCKARRAY)
+access_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr,
+		    JDIMENSION start_row, JDIMENSION num_rows,
+		    boolean writable)
+/* Access the part of a virtual block array starting at start_row */
+/* and extending for num_rows rows.  writable is true if  */
+/* caller intends to modify the accessed area. */
+{
+  JDIMENSION end_row = start_row + num_rows;
+  JDIMENSION undef_row;
+
+  /* debugging check */
+  if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||
+      ptr->mem_buffer == NULL)
+    ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+
+  /* Make the desired part of the virtual array accessible */
+  if (start_row < ptr->cur_start_row ||
+      end_row > ptr->cur_start_row+ptr->rows_in_mem) {
+    if (! ptr->b_s_open)
+      ERREXIT(cinfo, JERR_VIRTUAL_BUG);
+    /* Flush old buffer contents if necessary */
+    if (ptr->dirty) {
+      do_barray_io(cinfo, ptr, TRUE);
+      ptr->dirty = FALSE;
+    }
+    /* Decide what part of virtual array to access.
+     * Algorithm: if target address > current window, assume forward scan,
+     * load starting at target address.  If target address < current window,
+     * assume backward scan, load so that target area is top of window.
+     * Note that when switching from forward write to forward read, will have
+     * start_row = 0, so the limiting case applies and we load from 0 anyway.
+     */
+    if (start_row > ptr->cur_start_row) {
+      ptr->cur_start_row = start_row;
+    } else {
+      /* use long arithmetic here to avoid overflow & unsigned problems */
+      long ltemp;
+
+      ltemp = (long) end_row - (long) ptr->rows_in_mem;
+      if (ltemp < 0)
+	ltemp = 0;		/* don't fall off front end of file */
+      ptr->cur_start_row = (JDIMENSION) ltemp;
+    }
+    /* Read in the selected part of the array.
+     * During the initial write pass, we will do no actual read
+     * because the selected part is all undefined.
+     */
+    do_barray_io(cinfo, ptr, FALSE);
+  }
+  /* Ensure the accessed part of the array is defined; prezero if needed.
+   * To improve locality of access, we only prezero the part of the array
+   * that the caller is about to access, not the entire in-memory array.
+   */
+  if (ptr->first_undef_row < end_row) {
+    if (ptr->first_undef_row < start_row) {
+      if (writable)		/* writer skipped over a section of array */
+	ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+      undef_row = start_row;	/* but reader is allowed to read ahead */
+    } else {
+      undef_row = ptr->first_undef_row;
+    }
+    if (writable)
+      ptr->first_undef_row = end_row;
+    if (ptr->pre_zero) {
+      size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK);
+      undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */
+      end_row -= ptr->cur_start_row;
+      while (undef_row < end_row) {
+	FMEMZERO((void FAR *) ptr->mem_buffer[undef_row], bytesperrow);
+	undef_row++;
+      }
+    } else {
+      if (! writable)		/* reader looking at undefined data */
+	ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+    }
+  }
+  /* Flag the buffer dirty if caller will write in it */
+  if (writable)
+    ptr->dirty = TRUE;
+  /* Return address of proper part of the buffer */
+  return ptr->mem_buffer + (start_row - ptr->cur_start_row);
+}
+
+
+/*
+ * Release all objects belonging to a specified pool.
+ */
+
+METHODDEF(void)
+free_pool (j_common_ptr cinfo, int pool_id)
+{
+  my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+  small_pool_ptr shdr_ptr;
+  large_pool_ptr lhdr_ptr;
+  size_t space_freed;
+
+  if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)
+    ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id);	/* safety check */
+
+#ifdef MEM_STATS
+  if (cinfo->err->trace_level > 1)
+    print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */
+#endif
+
+  /* If freeing IMAGE pool, close any virtual arrays first */
+  if (pool_id == JPOOL_IMAGE) {
+    jvirt_sarray_ptr sptr;
+    jvirt_barray_ptr bptr;
+
+    for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
+      if (sptr->b_s_open) {	/* there may be no backing store */
+	sptr->b_s_open = FALSE;	/* prevent recursive close if error */
+	(*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info);
+      }
+    }
+    mem->virt_sarray_list = NULL;
+    for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {
+      if (bptr->b_s_open) {	/* there may be no backing store */
+	bptr->b_s_open = FALSE;	/* prevent recursive close if error */
+	(*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info);
+      }
+    }
+    mem->virt_barray_list = NULL;
+  }
+
+  /* Release large objects */
+  lhdr_ptr = mem->large_list[pool_id];
+  mem->large_list[pool_id] = NULL;
+
+  while (lhdr_ptr != NULL) {
+    large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next;
+    space_freed = lhdr_ptr->hdr.bytes_used +
+		  lhdr_ptr->hdr.bytes_left +
+		  SIZEOF(large_pool_hdr);
+    jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed);
+    mem->total_space_allocated -= space_freed;
+    lhdr_ptr = next_lhdr_ptr;
+  }
+
+  /* Release small objects */
+  shdr_ptr = mem->small_list[pool_id];
+  mem->small_list[pool_id] = NULL;
+
+  while (shdr_ptr != NULL) {
+    small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next;
+    space_freed = shdr_ptr->hdr.bytes_used +
+		  shdr_ptr->hdr.bytes_left +
+		  SIZEOF(small_pool_hdr);
+    jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed);
+    mem->total_space_allocated -= space_freed;
+    shdr_ptr = next_shdr_ptr;
+  }
+}
+
+
+/*
+ * Close up shop entirely.
+ * Note that this cannot be called unless cinfo->mem is non-NULL.
+ */
+
+METHODDEF(void)
+self_destruct (j_common_ptr cinfo)
+{
+  int pool;
+
+  /* Close all backing store, release all memory.
+   * Releasing pools in reverse order might help avoid fragmentation
+   * with some (brain-damaged) malloc libraries.
+   */
+  for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) {
+    free_pool(cinfo, pool);
+  }
+
+  /* Release the memory manager control block too. */
+  jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr));
+  cinfo->mem = NULL;		/* ensures I will be called only once */
+
+  jpeg_mem_term(cinfo);		/* system-dependent cleanup */
+}
+
+
+/*
+ * Memory manager initialization.
+ * When this is called, only the error manager pointer is valid in cinfo!
+ */
+
+GLOBAL(void)
+jinit_memory_mgr (j_common_ptr cinfo)
+{
+  my_mem_ptr mem;
+  long max_to_use;
+  int pool;
+  size_t test_mac;
+
+  cinfo->mem = NULL;		/* for safety if init fails */
+
+  /* Check for configuration errors.
+   * SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably
+   * doesn't reflect any real hardware alignment requirement.
+   * The test is a little tricky: for X>0, X and X-1 have no one-bits
+   * in common if and only if X is a power of 2, ie has only one one-bit.
+   * Some compilers may give an "unreachable code" warning here; ignore it.
+   */
+  if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0)
+    ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE);
+  /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be
+   * a multiple of SIZEOF(ALIGN_TYPE).
+   * Again, an "unreachable code" warning may be ignored here.
+   * But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK.
+   */
+  test_mac = (size_t) MAX_ALLOC_CHUNK;
+  if ((long) test_mac != MAX_ALLOC_CHUNK ||
+      (MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0)
+    ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
+
+  max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */
+
+  /* Attempt to allocate memory manager's control block */
+  mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr));
+
+  if (mem == NULL) {
+    jpeg_mem_term(cinfo);	/* system-dependent cleanup */
+    ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0);
+  }
+
+  /* OK, fill in the method pointers */
+  mem->pub.alloc_small = alloc_small;
+  mem->pub.alloc_large = alloc_large;
+  mem->pub.alloc_sarray = alloc_sarray;
+  mem->pub.alloc_barray = alloc_barray;
+  mem->pub.request_virt_sarray = request_virt_sarray;
+  mem->pub.request_virt_barray = request_virt_barray;
+  mem->pub.realize_virt_arrays = realize_virt_arrays;
+  mem->pub.access_virt_sarray = access_virt_sarray;
+  mem->pub.access_virt_barray = access_virt_barray;
+  mem->pub.free_pool = free_pool;
+  mem->pub.self_destruct = self_destruct;
+
+  /* Make MAX_ALLOC_CHUNK accessible to other modules */
+  mem->pub.max_alloc_chunk = MAX_ALLOC_CHUNK;
+
+  /* Initialize working state */
+  mem->pub.max_memory_to_use = max_to_use;
+
+  for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) {
+    mem->small_list[pool] = NULL;
+    mem->large_list[pool] = NULL;
+  }
+  mem->virt_sarray_list = NULL;
+  mem->virt_barray_list = NULL;
+
+  mem->total_space_allocated = SIZEOF(my_memory_mgr);
+
+  /* Declare ourselves open for business */
+  cinfo->mem = & mem->pub;
+
+  /* Check for an environment variable JPEGMEM; if found, override the
+   * default max_memory setting from jpeg_mem_init.  Note that the
+   * surrounding application may again override this value.
+   * If your system doesn't support getenv(), define NO_GETENV to disable
+   * this feature.
+   */
+#ifndef NO_GETENV
+  { char * memenv;
+
+    if ((memenv = getenv("JPEGMEM")) != NULL) {
+      char ch = 'x';
+
+      if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) {
+	if (ch == 'm' || ch == 'M')
+	  max_to_use *= 1000L;
+	mem->pub.max_memory_to_use = max_to_use * 1000L;
+      }
+    }
+  }
+#endif
+
+}
diff --git a/source/Irrlicht/jpeglib/jmemname.c b/source/Irrlicht/jpeglib/jmemname.c
new file mode 100644
index 00000000..e28b212f
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jmemname.c
@@ -0,0 +1,276 @@
+/*
+ * jmemname.c
+ *
+ * Copyright (C) 1992-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file provides a generic implementation of the system-dependent
+ * portion of the JPEG memory manager.  This implementation assumes that
+ * you must explicitly construct a name for each temp file.
+ * Also, the problem of determining the amount of memory available
+ * is shoved onto the user.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h"		/* import the system-dependent declarations */
+
+#ifndef HAVE_STDLIB_H		/*  should declare malloc(),free() */
+extern void * malloc JPP((size_t size));
+extern void free JPP((void *ptr));
+#endif
+
+#ifndef SEEK_SET		/* pre-ANSI systems may not define this; */
+#define SEEK_SET  0		/* if not, assume 0 is correct */
+#endif
+
+#ifdef DONT_USE_B_MODE		/* define mode parameters for fopen() */
+#define READ_BINARY	"r"
+#define RW_BINARY	"w+"
+#else
+#ifdef VMS			/* VMS is very nonstandard */
+#define READ_BINARY	"rb", "ctx=stm"
+#define RW_BINARY	"w+b", "ctx=stm"
+#else				/* standard ANSI-compliant case */
+#define READ_BINARY	"rb"
+#define RW_BINARY	"w+b"
+#endif
+#endif
+
+
+/*
+ * Selection of a file name for a temporary file.
+ * This is system-dependent!
+ *
+ * The code as given is suitable for most Unix systems, and it is easily
+ * modified for most non-Unix systems.  Some notes:
+ *  1.  The temp file is created in the directory named by TEMP_DIRECTORY.
+ *      The default value is /usr/tmp, which is the conventional place for
+ *      creating large temp files on Unix.  On other systems you'll probably
+ *      want to change the file location.  You can do this by editing the
+ *      #define, or (preferred) by defining TEMP_DIRECTORY in jconfig.h.
+ *
+ *  2.  If you need to change the file name as well as its location,
+ *      you can override the TEMP_FILE_NAME macro.  (Note that this is
+ *      actually a printf format string; it must contain %s and %d.)
+ *      Few people should need to do this.
+ *
+ *  3.  mktemp() is used to ensure that multiple processes running
+ *      simultaneously won't select the same file names.  If your system
+ *      doesn't have mktemp(), define NO_MKTEMP to do it the hard way.
+ *      (If you don't have , also define NO_ERRNO_H.)
+ *
+ *  4.  You probably want to define NEED_SIGNAL_CATCHER so that cjpeg.c/djpeg.c
+ *      will cause the temp files to be removed if you stop the program early.
+ */
+
+#ifndef TEMP_DIRECTORY		/* can override from jconfig.h or Makefile */
+#define TEMP_DIRECTORY  "/usr/tmp/" /* recommended setting for Unix */
+#endif
+
+static int next_file_num;	/* to distinguish among several temp files */
+
+#ifdef NO_MKTEMP
+
+#ifndef TEMP_FILE_NAME		/* can override from jconfig.h or Makefile */
+#define TEMP_FILE_NAME  "%sJPG%03d.TMP"
+#endif
+
+#ifndef NO_ERRNO_H
+#include 		/* to define ENOENT */
+#endif
+
+/* ANSI C specifies that errno is a macro, but on older systems it's more
+ * likely to be a plain int variable.  And not all versions of errno.h
+ * bother to declare it, so we have to in order to be most portable.  Thus:
+ */
+#ifndef errno
+extern int errno;
+#endif
+
+
+LOCAL(void)
+select_file_name (char * fname)
+{
+  FILE * tfile;
+
+  /* Keep generating file names till we find one that's not in use */
+  for (;;) {
+    next_file_num++;		/* advance counter */
+    sprintf(fname, TEMP_FILE_NAME, TEMP_DIRECTORY, next_file_num);
+    if ((tfile = fopen(fname, READ_BINARY)) == NULL) {
+      /* fopen could have failed for a reason other than the file not
+       * being there; for example, file there but unreadable.
+       * If  isn't available, then we cannot test the cause.
+       */
+#ifdef ENOENT
+      if (errno != ENOENT)
+	continue;
+#endif
+      break;
+    }
+    fclose(tfile);		/* oops, it's there; close tfile & try again */
+  }
+}
+
+#else /* ! NO_MKTEMP */
+
+/* Note that mktemp() requires the initial filename to end in six X's */
+#ifndef TEMP_FILE_NAME		/* can override from jconfig.h or Makefile */
+#define TEMP_FILE_NAME  "%sJPG%dXXXXXX"
+#endif
+
+LOCAL(void)
+select_file_name (char * fname)
+{
+  next_file_num++;		/* advance counter */
+  sprintf(fname, TEMP_FILE_NAME, TEMP_DIRECTORY, next_file_num);
+  mktemp(fname);		/* make sure file name is unique */
+  /* mktemp replaces the trailing XXXXXX with a unique string of characters */
+}
+
+#endif /* NO_MKTEMP */
+
+
+/*
+ * Memory allocation and freeing are controlled by the regular library
+ * routines malloc() and free().
+ */
+
+GLOBAL(void *)
+jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
+{
+  return (void *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
+{
+  free(object);
+}
+
+
+/*
+ * "Large" objects are treated the same as "small" ones.
+ * NB: although we include FAR keywords in the routine declarations,
+ * this file won't actually work in 80x86 small/medium model; at least,
+ * you probably won't be able to process useful-size images in only 64KB.
+ */
+
+GLOBAL(void FAR *)
+jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
+{
+  return (void FAR *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
+{
+  free(object);
+}
+
+
+/*
+ * This routine computes the total memory space available for allocation.
+ * It's impossible to do this in a portable way; our current solution is
+ * to make the user tell us (with a default value set at compile time).
+ * If you can actually get the available space, it's a good idea to subtract
+ * a slop factor of 5% or so.
+ */
+
+#ifndef DEFAULT_MAX_MEM		/* so can override from makefile */
+#define DEFAULT_MAX_MEM		1000000L /* default: one megabyte */
+#endif
+
+GLOBAL(long)
+jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
+		    long max_bytes_needed, long already_allocated)
+{
+  return cinfo->mem->max_memory_to_use - already_allocated;
+}
+
+
+/*
+ * Backing store (temporary file) management.
+ * Backing store objects are only used when the value returned by
+ * jpeg_mem_available is less than the total space needed.  You can dispense
+ * with these routines if you have plenty of virtual memory; see jmemnobs.c.
+ */
+
+
+METHODDEF(void)
+read_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+		    void FAR * buffer_address,
+		    long file_offset, long byte_count)
+{
+  if (fseek(info->temp_file, file_offset, SEEK_SET))
+    ERREXIT(cinfo, JERR_TFILE_SEEK);
+  if (JFREAD(info->temp_file, buffer_address, byte_count)
+      != (size_t) byte_count)
+    ERREXIT(cinfo, JERR_TFILE_READ);
+}
+
+
+METHODDEF(void)
+write_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+		     void FAR * buffer_address,
+		     long file_offset, long byte_count)
+{
+  if (fseek(info->temp_file, file_offset, SEEK_SET))
+    ERREXIT(cinfo, JERR_TFILE_SEEK);
+  if (JFWRITE(info->temp_file, buffer_address, byte_count)
+      != (size_t) byte_count)
+    ERREXIT(cinfo, JERR_TFILE_WRITE);
+}
+
+
+METHODDEF(void)
+close_backing_store (j_common_ptr cinfo, backing_store_ptr info)
+{
+  fclose(info->temp_file);	/* close the file */
+  unlink(info->temp_name);	/* delete the file */
+/* If your system doesn't have unlink(), use remove() instead.
+ * remove() is the ANSI-standard name for this function, but if
+ * your system was ANSI you'd be using jmemansi.c, right?
+ */
+  TRACEMSS(cinfo, 1, JTRC_TFILE_CLOSE, info->temp_name);
+}
+
+
+/*
+ * Initial opening of a backing-store object.
+ */
+
+GLOBAL(void)
+jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+			 long total_bytes_needed)
+{
+  select_file_name(info->temp_name);
+  if ((info->temp_file = fopen(info->temp_name, RW_BINARY)) == NULL)
+    ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
+  info->read_backing_store = read_backing_store;
+  info->write_backing_store = write_backing_store;
+  info->close_backing_store = close_backing_store;
+  TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name);
+}
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required.
+ */
+
+GLOBAL(long)
+jpeg_mem_init (j_common_ptr cinfo)
+{
+  next_file_num = 0;		/* initialize temp file name generator */
+  return DEFAULT_MAX_MEM;	/* default for max_memory_to_use */
+}
+
+GLOBAL(void)
+jpeg_mem_term (j_common_ptr cinfo)
+{
+  /* no work */
+}
diff --git a/source/Irrlicht/jpeglib/jmemnobs.c b/source/Irrlicht/jpeglib/jmemnobs.c
new file mode 100644
index 00000000..6aa1e929
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jmemnobs.c
@@ -0,0 +1,109 @@
+/*
+ * jmemnobs.c
+ *
+ * Copyright (C) 1992-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file provides a really simple implementation of the system-
+ * dependent portion of the JPEG memory manager.  This implementation
+ * assumes that no backing-store files are needed: all required space
+ * can be obtained from malloc().
+ * This is very portable in the sense that it'll compile on almost anything,
+ * but you'd better have lots of main memory (or virtual memory) if you want
+ * to process big images.
+ * Note that the max_memory_to_use option is ignored by this implementation.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h"		/* import the system-dependent declarations */
+
+#ifndef HAVE_STDLIB_H		/*  should declare malloc(),free() */
+extern void * malloc JPP((size_t size));
+extern void free JPP((void *ptr));
+#endif
+
+
+/*
+ * Memory allocation and freeing are controlled by the regular library
+ * routines malloc() and free().
+ */
+
+GLOBAL(void *)
+jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
+{
+  return (void *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
+{
+  free(object);
+}
+
+
+/*
+ * "Large" objects are treated the same as "small" ones.
+ * NB: although we include FAR keywords in the routine declarations,
+ * this file won't actually work in 80x86 small/medium model; at least,
+ * you probably won't be able to process useful-size images in only 64KB.
+ */
+
+GLOBAL(void FAR *)
+jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
+{
+  return (void FAR *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
+{
+  free(object);
+}
+
+
+/*
+ * This routine computes the total memory space available for allocation.
+ * Here we always say, "we got all you want bud!"
+ */
+
+GLOBAL(long)
+jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
+		    long max_bytes_needed, long already_allocated)
+{
+  return max_bytes_needed;
+}
+
+
+/*
+ * Backing store (temporary file) management.
+ * Since jpeg_mem_available always promised the moon,
+ * this should never be called and we can just error out.
+ */
+
+GLOBAL(void)
+jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+			 long total_bytes_needed)
+{
+  ERREXIT(cinfo, JERR_NO_BACKING_STORE);
+}
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required.  Here, there isn't any.
+ */
+
+GLOBAL(long)
+jpeg_mem_init (j_common_ptr cinfo)
+{
+  return 0;			/* just set max_memory_to_use to 0 */
+}
+
+GLOBAL(void)
+jpeg_mem_term (j_common_ptr cinfo)
+{
+  /* no work */
+}
diff --git a/source/Irrlicht/jpeglib/jmemsys.h b/source/Irrlicht/jpeglib/jmemsys.h
new file mode 100644
index 00000000..2a879611
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jmemsys.h
@@ -0,0 +1,198 @@
+/*
+ * jmemsys.h
+ *
+ * Copyright (C) 1992-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This include file defines the interface between the system-independent
+ * and system-dependent portions of the JPEG memory manager.  No other
+ * modules need include it.  (The system-independent portion is jmemmgr.c;
+ * there are several different versions of the system-dependent portion.)
+ *
+ * This file works as-is for the system-dependent memory managers supplied
+ * in the IJG distribution.  You may need to modify it if you write a
+ * custom memory manager.  If system-dependent changes are needed in
+ * this file, the best method is to #ifdef them based on a configuration
+ * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR
+ * and USE_MAC_MEMMGR.
+ */
+
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jpeg_get_small		jGetSmall
+#define jpeg_free_small		jFreeSmall
+#define jpeg_get_large		jGetLarge
+#define jpeg_free_large		jFreeLarge
+#define jpeg_mem_available	jMemAvail
+#define jpeg_open_backing_store	jOpenBackStore
+#define jpeg_mem_init		jMemInit
+#define jpeg_mem_term		jMemTerm
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+
+/*
+ * These two functions are used to allocate and release small chunks of
+ * memory.  (Typically the total amount requested through jpeg_get_small is
+ * no more than 20K or so; this will be requested in chunks of a few K each.)
+ * Behavior should be the same as for the standard library functions malloc
+ * and free; in particular, jpeg_get_small must return NULL on failure.
+ * On most systems, these ARE malloc and free.  jpeg_free_small is passed the
+ * size of the object being freed, just in case it's needed.
+ * On an 80x86 machine using small-data memory model, these manage near heap.
+ */
+
+EXTERN(void *) jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject));
+EXTERN(void) jpeg_free_small JPP((j_common_ptr cinfo, void * object,
+				  size_t sizeofobject));
+
+/*
+ * These two functions are used to allocate and release large chunks of
+ * memory (up to the total free space designated by jpeg_mem_available).
+ * The interface is the same as above, except that on an 80x86 machine,
+ * far pointers are used.  On most other machines these are identical to
+ * the jpeg_get/free_small routines; but we keep them separate anyway,
+ * in case a different allocation strategy is desirable for large chunks.
+ */
+
+EXTERN(void FAR *) jpeg_get_large JPP((j_common_ptr cinfo,
+				       size_t sizeofobject));
+EXTERN(void) jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object,
+				  size_t sizeofobject));
+
+/*
+ * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may
+ * be requested in a single call to jpeg_get_large (and jpeg_get_small for that
+ * matter, but that case should never come into play).  This macro is needed
+ * to model the 64Kb-segment-size limit of far addressing on 80x86 machines.
+ * On those machines, we expect that jconfig.h will provide a proper value.
+ * On machines with 32-bit flat address spaces, any large constant may be used.
+ *
+ * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type
+ * size_t and will be a multiple of sizeof(align_type).
+ */
+
+#ifndef MAX_ALLOC_CHUNK		/* may be overridden in jconfig.h */
+#define MAX_ALLOC_CHUNK  1000000000L
+#endif
+
+/*
+ * This routine computes the total space still available for allocation by
+ * jpeg_get_large.  If more space than this is needed, backing store will be
+ * used.  NOTE: any memory already allocated must not be counted.
+ *
+ * There is a minimum space requirement, corresponding to the minimum
+ * feasible buffer sizes; jmemmgr.c will request that much space even if
+ * jpeg_mem_available returns zero.  The maximum space needed, enough to hold
+ * all working storage in memory, is also passed in case it is useful.
+ * Finally, the total space already allocated is passed.  If no better
+ * method is available, cinfo->mem->max_memory_to_use - already_allocated
+ * is often a suitable calculation.
+ *
+ * It is OK for jpeg_mem_available to underestimate the space available
+ * (that'll just lead to more backing-store access than is really necessary).
+ * However, an overestimate will lead to failure.  Hence it's wise to subtract
+ * a slop factor from the true available space.  5% should be enough.
+ *
+ * On machines with lots of virtual memory, any large constant may be returned.
+ * Conversely, zero may be returned to always use the minimum amount of memory.
+ */
+
+EXTERN(long) jpeg_mem_available JPP((j_common_ptr cinfo,
+				     long min_bytes_needed,
+				     long max_bytes_needed,
+				     long already_allocated));
+
+
+/*
+ * This structure holds whatever state is needed to access a single
+ * backing-store object.  The read/write/close method pointers are called
+ * by jmemmgr.c to manipulate the backing-store object; all other fields
+ * are private to the system-dependent backing store routines.
+ */
+
+#define TEMP_NAME_LENGTH   64	/* max length of a temporary file's name */
+
+
+#ifdef USE_MSDOS_MEMMGR		/* DOS-specific junk */
+
+typedef unsigned short XMSH;	/* type of extended-memory handles */
+typedef unsigned short EMSH;	/* type of expanded-memory handles */
+
+typedef union {
+  short file_handle;		/* DOS file handle if it's a temp file */
+  XMSH xms_handle;		/* handle if it's a chunk of XMS */
+  EMSH ems_handle;		/* handle if it's a chunk of EMS */
+} handle_union;
+
+#endif /* USE_MSDOS_MEMMGR */
+
+#ifdef USE_MAC_MEMMGR		/* Mac-specific junk */
+#include 
+#endif /* USE_MAC_MEMMGR */
+
+
+typedef struct backing_store_struct * backing_store_ptr;
+
+typedef struct backing_store_struct {
+  /* Methods for reading/writing/closing this backing-store object */
+  JMETHOD(void, read_backing_store, (j_common_ptr cinfo,
+				     backing_store_ptr info,
+				     void FAR * buffer_address,
+				     long file_offset, long byte_count));
+  JMETHOD(void, write_backing_store, (j_common_ptr cinfo,
+				      backing_store_ptr info,
+				      void FAR * buffer_address,
+				      long file_offset, long byte_count));
+  JMETHOD(void, close_backing_store, (j_common_ptr cinfo,
+				      backing_store_ptr info));
+
+  /* Private fields for system-dependent backing-store management */
+#ifdef USE_MSDOS_MEMMGR
+  /* For the MS-DOS manager (jmemdos.c), we need: */
+  handle_union handle;		/* reference to backing-store storage object */
+  char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */
+#else
+#ifdef USE_MAC_MEMMGR
+  /* For the Mac manager (jmemmac.c), we need: */
+  short temp_file;		/* file reference number to temp file */
+  FSSpec tempSpec;		/* the FSSpec for the temp file */
+  char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */
+#else
+  /* For a typical implementation with temp files, we need: */
+  FILE * temp_file;		/* stdio reference to temp file */
+  char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */
+#endif
+#endif
+} backing_store_info;
+
+
+/*
+ * Initial opening of a backing-store object.  This must fill in the
+ * read/write/close pointers in the object.  The read/write routines
+ * may take an error exit if the specified maximum file size is exceeded.
+ * (If jpeg_mem_available always returns a large value, this routine can
+ * just take an error exit.)
+ */
+
+EXTERN(void) jpeg_open_backing_store JPP((j_common_ptr cinfo,
+					  backing_store_ptr info,
+					  long total_bytes_needed));
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required.  jpeg_mem_init will be called before anything is
+ * allocated (and, therefore, nothing in cinfo is of use except the error
+ * manager pointer).  It should return a suitable default value for
+ * max_memory_to_use; this may subsequently be overridden by the surrounding
+ * application.  (Note that max_memory_to_use is only important if
+ * jpeg_mem_available chooses to consult it ... no one else will.)
+ * jpeg_mem_term may assume that all requested memory has been freed and that
+ * all opened backing-store objects have been closed.
+ */
+
+EXTERN(long) jpeg_mem_init JPP((j_common_ptr cinfo));
+EXTERN(void) jpeg_mem_term JPP((j_common_ptr cinfo));
diff --git a/source/Irrlicht/jpeglib/jmorecfg.h b/source/Irrlicht/jpeglib/jmorecfg.h
new file mode 100644
index 00000000..7407ac79
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jmorecfg.h
@@ -0,0 +1,446 @@
+/*
+ * jmorecfg.h
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 1997-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains additional configuration options that customize the
+ * JPEG software for special applications or support machine-dependent
+ * optimizations.  Most users will not need to touch this file.
+ */
+
+
+/*
+ * Define BITS_IN_JSAMPLE as either
+ *   8   for 8-bit sample values (the usual setting)
+ *   9   for 9-bit sample values
+ *   10  for 10-bit sample values
+ *   11  for 11-bit sample values
+ *   12  for 12-bit sample values
+ * Only 8, 9, 10, 11, and 12 bits sample data precision are supported for
+ * full-feature DCT processing.  Further depths up to 16-bit may be added
+ * later for the lossless modes of operation.
+ * Run-time selection and conversion of data precision will be added later
+ * and are currently not supported, sorry.
+ * Exception:  The transcoding part (jpegtran) supports all settings in a
+ * single instance, since it operates on the level of DCT coefficients and
+ * not sample values.  The DCT coefficients are of the same type (16 bits)
+ * in all cases (see below).
+ */
+
+#define BITS_IN_JSAMPLE  8	/* use 8, 9, 10, 11, or 12 */
+
+
+/*
+ * Maximum number of components (color channels) allowed in JPEG image.
+ * To meet the letter of the JPEG spec, set this to 255.  However, darn
+ * few applications need more than 4 channels (maybe 5 for CMYK + alpha
+ * mask).  We recommend 10 as a reasonable compromise; use 4 if you are
+ * really short on memory.  (Each allowed component costs a hundred or so
+ * bytes of storage, whether actually used in an image or not.)
+ */
+
+#define MAX_COMPONENTS  10	/* maximum number of image components */
+
+
+/*
+ * Basic data types.
+ * You may need to change these if you have a machine with unusual data
+ * type sizes; for example, "char" not 8 bits, "short" not 16 bits,
+ * or "long" not 32 bits.  We don't care whether "int" is 16 or 32 bits,
+ * but it had better be at least 16.
+ */
+
+/* Representation of a single sample (pixel element value).
+ * We frequently allocate large arrays of these, so it's important to keep
+ * them small.  But if you have memory to burn and access to char or short
+ * arrays is very slow on your hardware, you might want to change these.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+/* JSAMPLE should be the smallest type that will hold the values 0..255.
+ * You can use a signed char by having GETJSAMPLE mask it with 0xFF.
+ */
+
+#ifdef HAVE_UNSIGNED_CHAR
+
+typedef unsigned char JSAMPLE;
+#define GETJSAMPLE(value)  ((int) (value))
+
+#else /* not HAVE_UNSIGNED_CHAR */
+
+typedef char JSAMPLE;
+#ifdef CHAR_IS_UNSIGNED
+#define GETJSAMPLE(value)  ((int) (value))
+#else
+#define GETJSAMPLE(value)  ((int) (value) & 0xFF)
+#endif /* CHAR_IS_UNSIGNED */
+
+#endif /* HAVE_UNSIGNED_CHAR */
+
+#define MAXJSAMPLE	255
+#define CENTERJSAMPLE	128
+
+#endif /* BITS_IN_JSAMPLE == 8 */
+
+
+#if BITS_IN_JSAMPLE == 9
+/* JSAMPLE should be the smallest type that will hold the values 0..511.
+ * On nearly all machines "short" will do nicely.
+ */
+
+typedef short JSAMPLE;
+#define GETJSAMPLE(value)  ((int) (value))
+
+#define MAXJSAMPLE	511
+#define CENTERJSAMPLE	256
+
+#endif /* BITS_IN_JSAMPLE == 9 */
+
+
+#if BITS_IN_JSAMPLE == 10
+/* JSAMPLE should be the smallest type that will hold the values 0..1023.
+ * On nearly all machines "short" will do nicely.
+ */
+
+typedef short JSAMPLE;
+#define GETJSAMPLE(value)  ((int) (value))
+
+#define MAXJSAMPLE	1023
+#define CENTERJSAMPLE	512
+
+#endif /* BITS_IN_JSAMPLE == 10 */
+
+
+#if BITS_IN_JSAMPLE == 11
+/* JSAMPLE should be the smallest type that will hold the values 0..2047.
+ * On nearly all machines "short" will do nicely.
+ */
+
+typedef short JSAMPLE;
+#define GETJSAMPLE(value)  ((int) (value))
+
+#define MAXJSAMPLE	2047
+#define CENTERJSAMPLE	1024
+
+#endif /* BITS_IN_JSAMPLE == 11 */
+
+
+#if BITS_IN_JSAMPLE == 12
+/* JSAMPLE should be the smallest type that will hold the values 0..4095.
+ * On nearly all machines "short" will do nicely.
+ */
+
+typedef short JSAMPLE;
+#define GETJSAMPLE(value)  ((int) (value))
+
+#define MAXJSAMPLE	4095
+#define CENTERJSAMPLE	2048
+
+#endif /* BITS_IN_JSAMPLE == 12 */
+
+
+/* Representation of a DCT frequency coefficient.
+ * This should be a signed value of at least 16 bits; "short" is usually OK.
+ * Again, we allocate large arrays of these, but you can change to int
+ * if you have memory to burn and "short" is really slow.
+ */
+
+typedef short JCOEF;
+
+
+/* Compressed datastreams are represented as arrays of JOCTET.
+ * These must be EXACTLY 8 bits wide, at least once they are written to
+ * external storage.  Note that when using the stdio data source/destination
+ * managers, this is also the data type passed to fread/fwrite.
+ */
+
+#ifdef HAVE_UNSIGNED_CHAR
+
+typedef unsigned char JOCTET;
+#define GETJOCTET(value)  (value)
+
+#else /* not HAVE_UNSIGNED_CHAR */
+
+typedef char JOCTET;
+#ifdef CHAR_IS_UNSIGNED
+#define GETJOCTET(value)  (value)
+#else
+#define GETJOCTET(value)  ((value) & 0xFF)
+#endif /* CHAR_IS_UNSIGNED */
+
+#endif /* HAVE_UNSIGNED_CHAR */
+
+
+/* These typedefs are used for various table entries and so forth.
+ * They must be at least as wide as specified; but making them too big
+ * won't cost a huge amount of memory, so we don't provide special
+ * extraction code like we did for JSAMPLE.  (In other words, these
+ * typedefs live at a different point on the speed/space tradeoff curve.)
+ */
+
+/* UINT8 must hold at least the values 0..255. */
+
+#ifdef HAVE_UNSIGNED_CHAR
+typedef unsigned char UINT8;
+#else /* not HAVE_UNSIGNED_CHAR */
+#ifdef CHAR_IS_UNSIGNED
+typedef char UINT8;
+#else /* not CHAR_IS_UNSIGNED */
+typedef short UINT8;
+#endif /* CHAR_IS_UNSIGNED */
+#endif /* HAVE_UNSIGNED_CHAR */
+
+/* UINT16 must hold at least the values 0..65535. */
+
+#ifdef HAVE_UNSIGNED_SHORT
+typedef unsigned short UINT16;
+#else /* not HAVE_UNSIGNED_SHORT */
+typedef unsigned int UINT16;
+#endif /* HAVE_UNSIGNED_SHORT */
+
+/* INT16 must hold at least the values -32768..32767. */
+
+#ifndef XMD_H			/* X11/xmd.h correctly defines INT16 */
+typedef short INT16;
+#endif
+
+/* INT32 must hold at least signed 32-bit values. */
+
+#ifndef XMD_H			/* X11/xmd.h correctly defines INT32 */
+#ifndef _BASETSD_H_		/* Microsoft defines it in basetsd.h */
+#ifndef _BASETSD_H		/* MinGW is slightly different */
+#ifndef QGLOBAL_H		/* Qt defines it in qglobal.h */
+typedef long INT32;
+#endif
+#endif
+#endif
+#endif
+
+/* Datatype used for image dimensions.  The JPEG standard only supports
+ * images up to 64K*64K due to 16-bit fields in SOF markers.  Therefore
+ * "unsigned int" is sufficient on all machines.  However, if you need to
+ * handle larger images and you don't mind deviating from the spec, you
+ * can change this datatype.
+ */
+
+typedef unsigned int JDIMENSION;
+
+#define JPEG_MAX_DIMENSION  65500L  /* a tad under 64K to prevent overflows */
+
+
+/* These macros are used in all function definitions and extern declarations.
+ * You could modify them if you need to change function linkage conventions;
+ * in particular, you'll need to do that to make the library a Windows DLL.
+ * Another application is to make all functions global for use with debuggers
+ * or code profilers that require it.
+ */
+
+/* a function called through method pointers: */
+#define METHODDEF(type)		static type
+/* a function used only in its module: */
+#define LOCAL(type)		static type
+/* a function referenced thru EXTERNs: */
+#define GLOBAL(type)		type
+/* a reference to a GLOBAL function: */
+#define EXTERN(type)		extern type
+
+
+/* This macro is used to declare a "method", that is, a function pointer.
+ * We want to supply prototype parameters if the compiler can cope.
+ * Note that the arglist parameter must be parenthesized!
+ * Again, you can customize this if you need special linkage keywords.
+ */
+
+#ifdef HAVE_PROTOTYPES
+#define JMETHOD(type,methodname,arglist)  type (*methodname) arglist
+#else
+#define JMETHOD(type,methodname,arglist)  type (*methodname) ()
+#endif
+
+
+/* The noreturn type identifier is used to declare functions
+ * which cannot return.
+ * Compilers can thus create more optimized code and perform
+ * better checks for warnings and errors.
+ * Static analyzer tools can make improved inferences about
+ * execution paths and are prevented from giving false alerts.
+ *
+ * Unfortunately, the proposed specifications of corresponding
+ * extensions in the Dec 2011 ISO C standard revision (C11),
+ * GCC, MSVC, etc. are not viable.
+ * Thus we introduce a user defined type to declare noreturn
+ * functions at least for clarity.  A proper compiler would
+ * have a suitable noreturn type to match in place of void.
+ */
+
+#ifndef HAVE_NORETURN_T
+typedef void noreturn_t;
+#endif
+
+
+/* Here is the pseudo-keyword for declaring pointers that must be "far"
+ * on 80x86 machines.  Most of the specialized coding for 80x86 is handled
+ * by just saying "FAR *" where such a pointer is needed.  In a few places
+ * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol.
+ */
+
+#ifndef FAR
+#ifdef NEED_FAR_POINTERS
+#define FAR  far
+#else
+#define FAR
+#endif
+#endif
+
+
+/*
+ * On a few systems, type boolean and/or its values FALSE, TRUE may appear
+ * in standard header files.  Or you may have conflicts with application-
+ * specific header files that you want to include together with these files.
+ * Defining HAVE_BOOLEAN before including jpeglib.h should make it work.
+ */
+
+#ifndef HAVE_BOOLEAN
+#if defined FALSE || defined TRUE || defined QGLOBAL_H
+/* Qt3 defines FALSE and TRUE as "const" variables in qglobal.h */
+typedef int boolean;
+#ifndef FALSE			/* in case these macros already exist */
+#define FALSE	0		/* values of boolean */
+#endif
+#ifndef TRUE
+#define TRUE	1
+#endif
+#else
+typedef enum { FALSE = 0, TRUE = 1 } boolean;
+#endif
+#endif
+
+
+/*
+ * The remaining options affect code selection within the JPEG library,
+ * but they don't need to be visible to most applications using the library.
+ * To minimize application namespace pollution, the symbols won't be
+ * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined.
+ */
+
+#ifdef JPEG_INTERNALS
+#define JPEG_INTERNAL_OPTIONS
+#endif
+
+#ifdef JPEG_INTERNAL_OPTIONS
+
+
+/*
+ * These defines indicate whether to include various optional functions.
+ * Undefining some of these symbols will produce a smaller but less capable
+ * library.  Note that you can leave certain source files out of the
+ * compilation/linking process if you've #undef'd the corresponding symbols.
+ * (You may HAVE to do that if your compiler doesn't like null source files.)
+ */
+
+/* Capability options common to encoder and decoder: */
+
+#define DCT_ISLOW_SUPPORTED	/* slow but accurate integer algorithm */
+#define DCT_IFAST_SUPPORTED	/* faster, less accurate integer method */
+#define DCT_FLOAT_SUPPORTED	/* floating-point: accurate, fast on fast HW */
+
+/* Encoder capability options: */
+
+#define C_ARITH_CODING_SUPPORTED    /* Arithmetic coding back end? */
+#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
+#define C_PROGRESSIVE_SUPPORTED	    /* Progressive JPEG? (Requires MULTISCAN)*/
+#define DCT_SCALING_SUPPORTED	    /* Input rescaling via DCT? (Requires DCT_ISLOW)*/
+#define ENTROPY_OPT_SUPPORTED	    /* Optimization of entropy coding parms? */
+/* Note: if you selected more than 8-bit data precision, it is dangerous to
+ * turn off ENTROPY_OPT_SUPPORTED.  The standard Huffman tables are only
+ * good for 8-bit precision, so arithmetic coding is recommended for higher
+ * precision.  The Huffman encoder normally uses entropy optimization to
+ * compute usable tables for higher precision.  Otherwise, you'll have to
+ * supply different default Huffman tables.
+ * The exact same statements apply for progressive JPEG: the default tables
+ * don't work for progressive mode.  (This may get fixed, however.)
+ */
+#define INPUT_SMOOTHING_SUPPORTED   /* Input image smoothing option? */
+
+/* Decoder capability options: */
+
+#define D_ARITH_CODING_SUPPORTED    /* Arithmetic coding back end? */
+#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
+#define D_PROGRESSIVE_SUPPORTED	    /* Progressive JPEG? (Requires MULTISCAN)*/
+#define IDCT_SCALING_SUPPORTED	    /* Output rescaling via IDCT? (Requires DCT_ISLOW)*/
+#define SAVE_MARKERS_SUPPORTED	    /* jpeg_save_markers() needed? */
+#define BLOCK_SMOOTHING_SUPPORTED   /* Block smoothing? (Progressive only) */
+#undef  UPSAMPLE_SCALING_SUPPORTED  /* Output rescaling at upsample stage? */
+#define UPSAMPLE_MERGING_SUPPORTED  /* Fast path for sloppy upsampling? */
+#define QUANT_1PASS_SUPPORTED	    /* 1-pass color quantization? */
+#define QUANT_2PASS_SUPPORTED	    /* 2-pass color quantization? */
+
+/* more capability options later, no doubt */
+
+
+/*
+ * Ordering of RGB data in scanlines passed to or from the application.
+ * If your application wants to deal with data in the order B,G,R, just
+ * change these macros.  You can also deal with formats such as R,G,B,X
+ * (one extra byte per pixel) by changing RGB_PIXELSIZE.  Note that changing
+ * the offsets will also change the order in which colormap data is organized.
+ * RESTRICTIONS:
+ * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats.
+ * 2. The color quantizer modules will not behave desirably if RGB_PIXELSIZE
+ *    is not 3 (they don't understand about dummy color components!).  So you
+ *    can't use color quantization if you change that value.
+ */
+
+#define RGB_RED		0	/* Offset of Red in an RGB scanline element */
+#define RGB_GREEN	1	/* Offset of Green */
+#define RGB_BLUE	2	/* Offset of Blue */
+#define RGB_PIXELSIZE	3	/* JSAMPLEs per RGB scanline element */
+
+
+/* Definitions for speed-related optimizations. */
+
+
+/* If your compiler supports inline functions, define INLINE
+ * as the inline keyword; otherwise define it as empty.
+ */
+
+#ifndef INLINE
+#ifdef __GNUC__			/* for instance, GNU C knows about inline */
+#define INLINE __inline__
+#endif
+#ifndef INLINE
+#define INLINE			/* default is to define it as empty */
+#endif
+#endif
+
+
+/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying
+ * two 16-bit shorts is faster than multiplying two ints.  Define MULTIPLIER
+ * as short on such a machine.  MULTIPLIER must be at least 16 bits wide.
+ */
+
+#ifndef MULTIPLIER
+#define MULTIPLIER  int		/* type for fastest integer multiply */
+#endif
+
+
+/* FAST_FLOAT should be either float or double, whichever is done faster
+ * by your compiler.  (Note that this type is only used in the floating point
+ * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.)
+ * Typically, float is faster in ANSI C compilers, while double is faster in
+ * pre-ANSI compilers (because they insist on converting to double anyway).
+ * The code below therefore chooses float if we have ANSI-style prototypes.
+ */
+
+#ifndef FAST_FLOAT
+#ifdef HAVE_PROTOTYPES
+#define FAST_FLOAT  float
+#else
+#define FAST_FLOAT  double
+#endif
+#endif
+
+#endif /* JPEG_INTERNAL_OPTIONS */
diff --git a/source/Irrlicht/jpeglib/jpegint.h b/source/Irrlicht/jpeglib/jpegint.h
new file mode 100644
index 00000000..ec14a1eb
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jpegint.h
@@ -0,0 +1,426 @@
+/*
+ * jpegint.h
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 1997-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file provides common declarations for the various JPEG modules.
+ * These declarations are considered internal to the JPEG library; most
+ * applications using the library shouldn't need to include this file.
+ */
+
+
+/* Declarations for both compression & decompression */
+
+typedef enum {			/* Operating modes for buffer controllers */
+	JBUF_PASS_THRU,		/* Plain stripwise operation */
+	/* Remaining modes require a full-image buffer to have been created */
+	JBUF_SAVE_SOURCE,	/* Run source subobject only, save output */
+	JBUF_CRANK_DEST,	/* Run dest subobject only, using saved data */
+	JBUF_SAVE_AND_PASS	/* Run both subobjects, save output */
+} J_BUF_MODE;
+
+/* Values of global_state field (jdapi.c has some dependencies on ordering!) */
+#define CSTATE_START	100	/* after create_compress */
+#define CSTATE_SCANNING	101	/* start_compress done, write_scanlines OK */
+#define CSTATE_RAW_OK	102	/* start_compress done, write_raw_data OK */
+#define CSTATE_WRCOEFS	103	/* jpeg_write_coefficients done */
+#define DSTATE_START	200	/* after create_decompress */
+#define DSTATE_INHEADER	201	/* reading header markers, no SOS yet */
+#define DSTATE_READY	202	/* found SOS, ready for start_decompress */
+#define DSTATE_PRELOAD	203	/* reading multiscan file in start_decompress*/
+#define DSTATE_PRESCAN	204	/* performing dummy pass for 2-pass quant */
+#define DSTATE_SCANNING	205	/* start_decompress done, read_scanlines OK */
+#define DSTATE_RAW_OK	206	/* start_decompress done, read_raw_data OK */
+#define DSTATE_BUFIMAGE	207	/* expecting jpeg_start_output */
+#define DSTATE_BUFPOST	208	/* looking for SOS/EOI in jpeg_finish_output */
+#define DSTATE_RDCOEFS	209	/* reading file in jpeg_read_coefficients */
+#define DSTATE_STOPPING	210	/* looking for EOI in jpeg_finish_decompress */
+
+
+/* Declarations for compression modules */
+
+/* Master control module */
+struct jpeg_comp_master {
+  JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo));
+  JMETHOD(void, pass_startup, (j_compress_ptr cinfo));
+  JMETHOD(void, finish_pass, (j_compress_ptr cinfo));
+
+  /* State variables made visible to other modules */
+  boolean call_pass_startup;	/* True if pass_startup must be called */
+  boolean is_last_pass;		/* True during last pass */
+};
+
+/* Main buffer control (downsampled-data buffer) */
+struct jpeg_c_main_controller {
+  JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
+  JMETHOD(void, process_data, (j_compress_ptr cinfo,
+			       JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+			       JDIMENSION in_rows_avail));
+};
+
+/* Compression preprocessing (downsampling input buffer control) */
+struct jpeg_c_prep_controller {
+  JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
+  JMETHOD(void, pre_process_data, (j_compress_ptr cinfo,
+				   JSAMPARRAY input_buf,
+				   JDIMENSION *in_row_ctr,
+				   JDIMENSION in_rows_avail,
+				   JSAMPIMAGE output_buf,
+				   JDIMENSION *out_row_group_ctr,
+				   JDIMENSION out_row_groups_avail));
+};
+
+/* Coefficient buffer control */
+struct jpeg_c_coef_controller {
+  JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
+  JMETHOD(boolean, compress_data, (j_compress_ptr cinfo,
+				   JSAMPIMAGE input_buf));
+};
+
+/* Colorspace conversion */
+struct jpeg_color_converter {
+  JMETHOD(void, start_pass, (j_compress_ptr cinfo));
+  JMETHOD(void, color_convert, (j_compress_ptr cinfo,
+				JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+				JDIMENSION output_row, int num_rows));
+};
+
+/* Downsampling */
+struct jpeg_downsampler {
+  JMETHOD(void, start_pass, (j_compress_ptr cinfo));
+  JMETHOD(void, downsample, (j_compress_ptr cinfo,
+			     JSAMPIMAGE input_buf, JDIMENSION in_row_index,
+			     JSAMPIMAGE output_buf,
+			     JDIMENSION out_row_group_index));
+
+  boolean need_context_rows;	/* TRUE if need rows above & below */
+};
+
+/* Forward DCT (also controls coefficient quantization) */
+typedef JMETHOD(void, forward_DCT_ptr,
+		(j_compress_ptr cinfo, jpeg_component_info * compptr,
+		 JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
+		 JDIMENSION start_row, JDIMENSION start_col,
+		 JDIMENSION num_blocks));
+
+struct jpeg_forward_dct {
+  JMETHOD(void, start_pass, (j_compress_ptr cinfo));
+  /* It is useful to allow each component to have a separate FDCT method. */
+  forward_DCT_ptr forward_DCT[MAX_COMPONENTS];
+};
+
+/* Entropy encoding */
+struct jpeg_entropy_encoder {
+  JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics));
+  JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data));
+  JMETHOD(void, finish_pass, (j_compress_ptr cinfo));
+};
+
+/* Marker writing */
+struct jpeg_marker_writer {
+  JMETHOD(void, write_file_header, (j_compress_ptr cinfo));
+  JMETHOD(void, write_frame_header, (j_compress_ptr cinfo));
+  JMETHOD(void, write_scan_header, (j_compress_ptr cinfo));
+  JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo));
+  JMETHOD(void, write_tables_only, (j_compress_ptr cinfo));
+  /* These routines are exported to allow insertion of extra markers */
+  /* Probably only COM and APPn markers should be written this way */
+  JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker,
+				      unsigned int datalen));
+  JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val));
+};
+
+
+/* Declarations for decompression modules */
+
+/* Master control module */
+struct jpeg_decomp_master {
+  JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo));
+  JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo));
+
+  /* State variables made visible to other modules */
+  boolean is_dummy_pass;	/* True during 1st pass for 2-pass quant */
+};
+
+/* Input control module */
+struct jpeg_input_controller {
+  JMETHOD(int, consume_input, (j_decompress_ptr cinfo));
+  JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo));
+  JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo));
+  JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo));
+
+  /* State variables made visible to other modules */
+  boolean has_multiple_scans;	/* True if file has multiple scans */
+  boolean eoi_reached;		/* True when EOI has been consumed */
+};
+
+/* Main buffer control (downsampled-data buffer) */
+struct jpeg_d_main_controller {
+  JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode));
+  JMETHOD(void, process_data, (j_decompress_ptr cinfo,
+			       JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+			       JDIMENSION out_rows_avail));
+};
+
+/* Coefficient buffer control */
+struct jpeg_d_coef_controller {
+  JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo));
+  JMETHOD(int, consume_data, (j_decompress_ptr cinfo));
+  JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo));
+  JMETHOD(int, decompress_data, (j_decompress_ptr cinfo,
+				 JSAMPIMAGE output_buf));
+  /* Pointer to array of coefficient virtual arrays, or NULL if none */
+  jvirt_barray_ptr *coef_arrays;
+};
+
+/* Decompression postprocessing (color quantization buffer control) */
+struct jpeg_d_post_controller {
+  JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode));
+  JMETHOD(void, post_process_data, (j_decompress_ptr cinfo,
+				    JSAMPIMAGE input_buf,
+				    JDIMENSION *in_row_group_ctr,
+				    JDIMENSION in_row_groups_avail,
+				    JSAMPARRAY output_buf,
+				    JDIMENSION *out_row_ctr,
+				    JDIMENSION out_rows_avail));
+};
+
+/* Marker reading & parsing */
+struct jpeg_marker_reader {
+  JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo));
+  /* Read markers until SOS or EOI.
+   * Returns same codes as are defined for jpeg_consume_input:
+   * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
+   */
+  JMETHOD(int, read_markers, (j_decompress_ptr cinfo));
+  /* Read a restart marker --- exported for use by entropy decoder only */
+  jpeg_marker_parser_method read_restart_marker;
+
+  /* State of marker reader --- nominally internal, but applications
+   * supplying COM or APPn handlers might like to know the state.
+   */
+  boolean saw_SOI;		/* found SOI? */
+  boolean saw_SOF;		/* found SOF? */
+  int next_restart_num;		/* next restart number expected (0-7) */
+  unsigned int discarded_bytes;	/* # of bytes skipped looking for a marker */
+};
+
+/* Entropy decoding */
+struct jpeg_entropy_decoder {
+  JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+  JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, JBLOCKROW *MCU_data));
+  JMETHOD(void, finish_pass, (j_decompress_ptr cinfo));
+};
+
+/* Inverse DCT (also performs dequantization) */
+typedef JMETHOD(void, inverse_DCT_method_ptr,
+		(j_decompress_ptr cinfo, jpeg_component_info * compptr,
+		 JCOEFPTR coef_block,
+		 JSAMPARRAY output_buf, JDIMENSION output_col));
+
+struct jpeg_inverse_dct {
+  JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+  /* It is useful to allow each component to have a separate IDCT method. */
+  inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS];
+};
+
+/* Upsampling (note that upsampler must also call color converter) */
+struct jpeg_upsampler {
+  JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+  JMETHOD(void, upsample, (j_decompress_ptr cinfo,
+			   JSAMPIMAGE input_buf,
+			   JDIMENSION *in_row_group_ctr,
+			   JDIMENSION in_row_groups_avail,
+			   JSAMPARRAY output_buf,
+			   JDIMENSION *out_row_ctr,
+			   JDIMENSION out_rows_avail));
+
+  boolean need_context_rows;	/* TRUE if need rows above & below */
+};
+
+/* Colorspace conversion */
+struct jpeg_color_deconverter {
+  JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+  JMETHOD(void, color_convert, (j_decompress_ptr cinfo,
+				JSAMPIMAGE input_buf, JDIMENSION input_row,
+				JSAMPARRAY output_buf, int num_rows));
+};
+
+/* Color quantization or color precision reduction */
+struct jpeg_color_quantizer {
+  JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan));
+  JMETHOD(void, color_quantize, (j_decompress_ptr cinfo,
+				 JSAMPARRAY input_buf, JSAMPARRAY output_buf,
+				 int num_rows));
+  JMETHOD(void, finish_pass, (j_decompress_ptr cinfo));
+  JMETHOD(void, new_color_map, (j_decompress_ptr cinfo));
+};
+
+
+/* Miscellaneous useful macros */
+
+#undef MAX
+#define MAX(a,b)	((a) > (b) ? (a) : (b))
+#undef MIN
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+
+
+/* We assume that right shift corresponds to signed division by 2 with
+ * rounding towards minus infinity.  This is correct for typical "arithmetic
+ * shift" instructions that shift in copies of the sign bit.  But some
+ * C compilers implement >> with an unsigned shift.  For these machines you
+ * must define RIGHT_SHIFT_IS_UNSIGNED.
+ * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity.
+ * It is only applied with constant shift counts.  SHIFT_TEMPS must be
+ * included in the variables of any routine using RIGHT_SHIFT.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define SHIFT_TEMPS	INT32 shift_temp;
+#define RIGHT_SHIFT(x,shft)  \
+	((shift_temp = (x)) < 0 ? \
+	 (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \
+	 (shift_temp >> (shft)))
+#else
+#define SHIFT_TEMPS
+#define RIGHT_SHIFT(x,shft)	((x) >> (shft))
+#endif
+
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jinit_compress_master	jICompress
+#define jinit_c_master_control	jICMaster
+#define jinit_c_main_controller	jICMainC
+#define jinit_c_prep_controller	jICPrepC
+#define jinit_c_coef_controller	jICCoefC
+#define jinit_color_converter	jICColor
+#define jinit_downsampler	jIDownsampler
+#define jinit_forward_dct	jIFDCT
+#define jinit_huff_encoder	jIHEncoder
+#define jinit_arith_encoder	jIAEncoder
+#define jinit_marker_writer	jIMWriter
+#define jinit_master_decompress	jIDMaster
+#define jinit_d_main_controller	jIDMainC
+#define jinit_d_coef_controller	jIDCoefC
+#define jinit_d_post_controller	jIDPostC
+#define jinit_input_controller	jIInCtlr
+#define jinit_marker_reader	jIMReader
+#define jinit_huff_decoder	jIHDecoder
+#define jinit_arith_decoder	jIADecoder
+#define jinit_inverse_dct	jIIDCT
+#define jinit_upsampler		jIUpsampler
+#define jinit_color_deconverter	jIDColor
+#define jinit_1pass_quantizer	jI1Quant
+#define jinit_2pass_quantizer	jI2Quant
+#define jinit_merged_upsampler	jIMUpsampler
+#define jinit_memory_mgr	jIMemMgr
+#define jdiv_round_up		jDivRound
+#define jround_up		jRound
+#define jzero_far		jZeroFar
+#define jcopy_sample_rows	jCopySamples
+#define jcopy_block_row		jCopyBlocks
+#define jpeg_zigzag_order	jZIGTable
+#define jpeg_natural_order	jZAGTable
+#define jpeg_natural_order7	jZAG7Table
+#define jpeg_natural_order6	jZAG6Table
+#define jpeg_natural_order5	jZAG5Table
+#define jpeg_natural_order4	jZAG4Table
+#define jpeg_natural_order3	jZAG3Table
+#define jpeg_natural_order2	jZAG2Table
+#define jpeg_aritab		jAriTab
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+
+/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays
+ * and coefficient-block arrays.  This won't work on 80x86 because the arrays
+ * are FAR and we're assuming a small-pointer memory model.  However, some
+ * DOS compilers provide far-pointer versions of memcpy() and memset() even
+ * in the small-model libraries.  These will be used if USE_FMEM is defined.
+ * Otherwise, the routines in jutils.c do it the hard way.
+ */
+
+#ifndef NEED_FAR_POINTERS	/* normal case, same as regular macro */
+#define FMEMZERO(target,size)	MEMZERO(target,size)
+#else				/* 80x86 case */
+#ifdef USE_FMEM
+#define FMEMZERO(target,size)	_fmemset((void FAR *)(target), 0, (size_t)(size))
+#else
+EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero));
+#define FMEMZERO(target,size)	jzero_far(target, size)
+#endif
+#endif
+
+
+/* Compression module initialization routines */
+EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo,
+					 boolean transcode_only));
+EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo,
+					  boolean need_full_buffer));
+EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo,
+					  boolean need_full_buffer));
+EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo,
+					  boolean need_full_buffer));
+EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_arith_encoder JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo));
+/* Decompression module initialization routines */
+EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo,
+					  boolean need_full_buffer));
+EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo,
+					  boolean need_full_buffer));
+EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo,
+					  boolean need_full_buffer));
+EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_arith_decoder JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo));
+/* Memory manager initialization */
+EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo));
+
+/* Utility routines in jutils.c */
+EXTERN(long) jdiv_round_up JPP((long a, long b));
+EXTERN(long) jround_up JPP((long a, long b));
+EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row,
+				    JSAMPARRAY output_array, int dest_row,
+				    int num_rows, JDIMENSION num_cols));
+EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row,
+				  JDIMENSION num_blocks));
+/* Constant tables in jutils.c */
+#if 0				/* This table is not actually needed in v6a */
+extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */
+#endif
+extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */
+extern const int jpeg_natural_order7[]; /* zz to natural order for 7x7 block */
+extern const int jpeg_natural_order6[]; /* zz to natural order for 6x6 block */
+extern const int jpeg_natural_order5[]; /* zz to natural order for 5x5 block */
+extern const int jpeg_natural_order4[]; /* zz to natural order for 4x4 block */
+extern const int jpeg_natural_order3[]; /* zz to natural order for 3x3 block */
+extern const int jpeg_natural_order2[]; /* zz to natural order for 2x2 block */
+
+/* Arithmetic coding probability estimation tables in jaricom.c */
+extern const INT32 jpeg_aritab[];
+
+/* Suppress undefined-structure complaints if necessary. */
+
+#ifdef INCOMPLETE_TYPES_BROKEN
+#ifndef AM_MEMORY_MANAGER	/* only jmemmgr.c defines these */
+struct jvirt_sarray_control { long dummy; };
+struct jvirt_barray_control { long dummy; };
+#endif
+#endif /* INCOMPLETE_TYPES_BROKEN */
diff --git a/source/Irrlicht/jpeglib/jpeglib.h b/source/Irrlicht/jpeglib/jpeglib.h
new file mode 100644
index 00000000..8eb0085e
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jpeglib.h
@@ -0,0 +1,1180 @@
+/*
+ * jpeglib.h
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Modified 2002-2013 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file defines the application interface for the JPEG library.
+ * Most applications using the library need only include this file,
+ * and perhaps jerror.h if they want to know the exact error codes.
+ */
+
+#ifndef JPEGLIB_H
+#define JPEGLIB_H
+
+/*
+ * First we include the configuration files that record how this
+ * installation of the JPEG library is set up.  jconfig.h can be
+ * generated automatically for many systems.  jmorecfg.h contains
+ * manual configuration options that most people need not worry about.
+ */
+
+#ifndef JCONFIG_INCLUDED	/* in case jinclude.h already did */
+#include "jconfig.h"		/* widely used configuration options */
+#endif
+#include "jmorecfg.h"		/* seldom changed options */
+
+
+#ifdef __cplusplus
+#ifndef DONT_USE_EXTERN_C
+extern "C" {
+#endif
+#endif
+
+/* Version IDs for the JPEG library.
+ * Might be useful for tests like "#if JPEG_LIB_VERSION >= 90".
+ */
+
+#define JPEG_LIB_VERSION        90	/* Compatibility version 9.0 */
+#define JPEG_LIB_VERSION_MAJOR  9
+#define JPEG_LIB_VERSION_MINOR  1
+
+
+/* Various constants determining the sizes of things.
+ * All of these are specified by the JPEG standard,
+ * so don't change them if you want to be compatible.
+ */
+
+#define DCTSIZE		    8	/* The basic DCT block is 8x8 coefficients */
+#define DCTSIZE2	    64	/* DCTSIZE squared; # of elements in a block */
+#define NUM_QUANT_TBLS      4	/* Quantization tables are numbered 0..3 */
+#define NUM_HUFF_TBLS       4	/* Huffman tables are numbered 0..3 */
+#define NUM_ARITH_TBLS      16	/* Arith-coding tables are numbered 0..15 */
+#define MAX_COMPS_IN_SCAN   4	/* JPEG limit on # of components in one scan */
+#define MAX_SAMP_FACTOR     4	/* JPEG limit on sampling factors */
+/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard;
+ * the PostScript DCT filter can emit files with many more than 10 blocks/MCU.
+ * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU
+ * to handle it.  We even let you do this from the jconfig.h file.  However,
+ * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe
+ * sometimes emits noncompliant files doesn't mean you should too.
+ */
+#define C_MAX_BLOCKS_IN_MCU   10 /* compressor's limit on blocks per MCU */
+#ifndef D_MAX_BLOCKS_IN_MCU
+#define D_MAX_BLOCKS_IN_MCU   10 /* decompressor's limit on blocks per MCU */
+#endif
+
+
+/* Data structures for images (arrays of samples and of DCT coefficients).
+ * On 80x86 machines, the image arrays are too big for near pointers,
+ * but the pointer arrays can fit in near memory.
+ */
+
+typedef JSAMPLE FAR *JSAMPROW;	/* ptr to one image row of pixel samples. */
+typedef JSAMPROW *JSAMPARRAY;	/* ptr to some rows (a 2-D sample array) */
+typedef JSAMPARRAY *JSAMPIMAGE;	/* a 3-D sample array: top index is color */
+
+typedef JCOEF JBLOCK[DCTSIZE2];	/* one block of coefficients */
+typedef JBLOCK FAR *JBLOCKROW;	/* pointer to one row of coefficient blocks */
+typedef JBLOCKROW *JBLOCKARRAY;		/* a 2-D array of coefficient blocks */
+typedef JBLOCKARRAY *JBLOCKIMAGE;	/* a 3-D array of coefficient blocks */
+
+typedef JCOEF FAR *JCOEFPTR;	/* useful in a couple of places */
+
+
+/* Types for JPEG compression parameters and working tables. */
+
+
+/* DCT coefficient quantization tables. */
+
+typedef struct {
+  /* This array gives the coefficient quantizers in natural array order
+   * (not the zigzag order in which they are stored in a JPEG DQT marker).
+   * CAUTION: IJG versions prior to v6a kept this array in zigzag order.
+   */
+  UINT16 quantval[DCTSIZE2];	/* quantization step for each coefficient */
+  /* This field is used only during compression.  It's initialized FALSE when
+   * the table is created, and set TRUE when it's been output to the file.
+   * You could suppress output of a table by setting this to TRUE.
+   * (See jpeg_suppress_tables for an example.)
+   */
+  boolean sent_table;		/* TRUE when table has been output */
+} JQUANT_TBL;
+
+
+/* Huffman coding tables. */
+
+typedef struct {
+  /* These two fields directly represent the contents of a JPEG DHT marker */
+  UINT8 bits[17];		/* bits[k] = # of symbols with codes of */
+				/* length k bits; bits[0] is unused */
+  UINT8 huffval[256];		/* The symbols, in order of incr code length */
+  /* This field is used only during compression.  It's initialized FALSE when
+   * the table is created, and set TRUE when it's been output to the file.
+   * You could suppress output of a table by setting this to TRUE.
+   * (See jpeg_suppress_tables for an example.)
+   */
+  boolean sent_table;		/* TRUE when table has been output */
+} JHUFF_TBL;
+
+
+/* Basic info about one component (color channel). */
+
+typedef struct {
+  /* These values are fixed over the whole image. */
+  /* For compression, they must be supplied by parameter setup; */
+  /* for decompression, they are read from the SOF marker. */
+  int component_id;		/* identifier for this component (0..255) */
+  int component_index;		/* its index in SOF or cinfo->comp_info[] */
+  int h_samp_factor;		/* horizontal sampling factor (1..4) */
+  int v_samp_factor;		/* vertical sampling factor (1..4) */
+  int quant_tbl_no;		/* quantization table selector (0..3) */
+  /* These values may vary between scans. */
+  /* For compression, they must be supplied by parameter setup; */
+  /* for decompression, they are read from the SOS marker. */
+  /* The decompressor output side may not use these variables. */
+  int dc_tbl_no;		/* DC entropy table selector (0..3) */
+  int ac_tbl_no;		/* AC entropy table selector (0..3) */
+  
+  /* Remaining fields should be treated as private by applications. */
+  
+  /* These values are computed during compression or decompression startup: */
+  /* Component's size in DCT blocks.
+   * Any dummy blocks added to complete an MCU are not counted; therefore
+   * these values do not depend on whether a scan is interleaved or not.
+   */
+  JDIMENSION width_in_blocks;
+  JDIMENSION height_in_blocks;
+  /* Size of a DCT block in samples,
+   * reflecting any scaling we choose to apply during the DCT step.
+   * Values from 1 to 16 are supported.
+   * Note that different components may receive different DCT scalings.
+   */
+  int DCT_h_scaled_size;
+  int DCT_v_scaled_size;
+  /* The downsampled dimensions are the component's actual, unpadded number
+   * of samples at the main buffer (preprocessing/compression interface);
+   * DCT scaling is included, so
+   * downsampled_width =
+   *   ceil(image_width * Hi/Hmax * DCT_h_scaled_size/block_size)
+   * and similarly for height.
+   */
+  JDIMENSION downsampled_width;	 /* actual width in samples */
+  JDIMENSION downsampled_height; /* actual height in samples */
+  /* For decompression, in cases where some of the components will be
+   * ignored (eg grayscale output from YCbCr image), we can skip most
+   * computations for the unused components.
+   * For compression, some of the components will need further quantization
+   * scale by factor of 2 after DCT (eg BG_YCC output from normal RGB input).
+   * The field is first set TRUE for decompression, FALSE for compression
+   * in initial_setup, and then adapted in color conversion setup.
+   */
+  boolean component_needed;
+
+  /* These values are computed before starting a scan of the component. */
+  /* The decompressor output side may not use these variables. */
+  int MCU_width;		/* number of blocks per MCU, horizontally */
+  int MCU_height;		/* number of blocks per MCU, vertically */
+  int MCU_blocks;		/* MCU_width * MCU_height */
+  int MCU_sample_width;	/* MCU width in samples: MCU_width * DCT_h_scaled_size */
+  int last_col_width;		/* # of non-dummy blocks across in last MCU */
+  int last_row_height;		/* # of non-dummy blocks down in last MCU */
+
+  /* Saved quantization table for component; NULL if none yet saved.
+   * See jdinput.c comments about the need for this information.
+   * This field is currently used only for decompression.
+   */
+  JQUANT_TBL * quant_table;
+
+  /* Private per-component storage for DCT or IDCT subsystem. */
+  void * dct_table;
+} jpeg_component_info;
+
+
+/* The script for encoding a multiple-scan file is an array of these: */
+
+typedef struct {
+  int comps_in_scan;		/* number of components encoded in this scan */
+  int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */
+  int Ss, Se;			/* progressive JPEG spectral selection parms */
+  int Ah, Al;			/* progressive JPEG successive approx. parms */
+} jpeg_scan_info;
+
+/* The decompressor can save APPn and COM markers in a list of these: */
+
+typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr;
+
+struct jpeg_marker_struct {
+  jpeg_saved_marker_ptr next;	/* next in list, or NULL */
+  UINT8 marker;			/* marker code: JPEG_COM, or JPEG_APP0+n */
+  unsigned int original_length;	/* # bytes of data in the file */
+  unsigned int data_length;	/* # bytes of data saved at data[] */
+  JOCTET FAR * data;		/* the data contained in the marker */
+  /* the marker length word is not counted in data_length or original_length */
+};
+
+/* Known color spaces. */
+
+typedef enum {
+	JCS_UNKNOWN,		/* error/unspecified */
+	JCS_GRAYSCALE,		/* monochrome */
+	JCS_RGB,		/* red/green/blue, standard RGB (sRGB) */
+	JCS_YCbCr,		/* Y/Cb/Cr (also known as YUV), standard YCC */
+	JCS_CMYK,		/* C/M/Y/K */
+	JCS_YCCK,		/* Y/Cb/Cr/K */
+	JCS_BG_RGB,		/* big gamut red/green/blue, bg-sRGB */
+	JCS_BG_YCC		/* big gamut Y/Cb/Cr, bg-sYCC */
+} J_COLOR_SPACE;
+
+/* Supported color transforms. */
+
+typedef enum {
+	JCT_NONE           = 0,
+	JCT_SUBTRACT_GREEN = 1
+} J_COLOR_TRANSFORM;
+
+/* DCT/IDCT algorithm options. */
+
+typedef enum {
+	JDCT_ISLOW,		/* slow but accurate integer algorithm */
+	JDCT_IFAST,		/* faster, less accurate integer method */
+	JDCT_FLOAT		/* floating-point: accurate, fast on fast HW */
+} J_DCT_METHOD;
+
+#ifndef JDCT_DEFAULT		/* may be overridden in jconfig.h */
+#define JDCT_DEFAULT  JDCT_ISLOW
+#endif
+#ifndef JDCT_FASTEST		/* may be overridden in jconfig.h */
+#define JDCT_FASTEST  JDCT_IFAST
+#endif
+
+/* Dithering options for decompression. */
+
+typedef enum {
+	JDITHER_NONE,		/* no dithering */
+	JDITHER_ORDERED,	/* simple ordered dither */
+	JDITHER_FS		/* Floyd-Steinberg error diffusion dither */
+} J_DITHER_MODE;
+
+
+/* Common fields between JPEG compression and decompression master structs. */
+
+#define jpeg_common_fields \
+  struct jpeg_error_mgr * err;	/* Error handler module */\
+  struct jpeg_memory_mgr * mem;	/* Memory manager module */\
+  struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\
+  void * client_data;		/* Available for use by application */\
+  boolean is_decompressor;	/* So common code can tell which is which */\
+  int global_state		/* For checking call sequence validity */
+
+/* Routines that are to be used by both halves of the library are declared
+ * to receive a pointer to this structure.  There are no actual instances of
+ * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct.
+ */
+struct jpeg_common_struct {
+  jpeg_common_fields;		/* Fields common to both master struct types */
+  /* Additional fields follow in an actual jpeg_compress_struct or
+   * jpeg_decompress_struct.  All three structs must agree on these
+   * initial fields!  (This would be a lot cleaner in C++.)
+   */
+};
+
+typedef struct jpeg_common_struct * j_common_ptr;
+typedef struct jpeg_compress_struct * j_compress_ptr;
+typedef struct jpeg_decompress_struct * j_decompress_ptr;
+
+
+/* Master record for a compression instance */
+
+struct jpeg_compress_struct {
+  jpeg_common_fields;		/* Fields shared with jpeg_decompress_struct */
+
+  /* Destination for compressed data */
+  struct jpeg_destination_mgr * dest;
+
+  /* Description of source image --- these fields must be filled in by
+   * outer application before starting compression.  in_color_space must
+   * be correct before you can even call jpeg_set_defaults().
+   */
+
+  JDIMENSION image_width;	/* input image width */
+  JDIMENSION image_height;	/* input image height */
+  int input_components;		/* # of color components in input image */
+  J_COLOR_SPACE in_color_space;	/* colorspace of input image */
+
+  double input_gamma;		/* image gamma of input image */
+
+  /* Compression parameters --- these fields must be set before calling
+   * jpeg_start_compress().  We recommend calling jpeg_set_defaults() to
+   * initialize everything to reasonable defaults, then changing anything
+   * the application specifically wants to change.  That way you won't get
+   * burnt when new parameters are added.  Also note that there are several
+   * helper routines to simplify changing parameters.
+   */
+
+  unsigned int scale_num, scale_denom; /* fraction by which to scale image */
+
+  JDIMENSION jpeg_width;	/* scaled JPEG image width */
+  JDIMENSION jpeg_height;	/* scaled JPEG image height */
+  /* Dimensions of actual JPEG image that will be written to file,
+   * derived from input dimensions by scaling factors above.
+   * These fields are computed by jpeg_start_compress().
+   * You can also use jpeg_calc_jpeg_dimensions() to determine these values
+   * in advance of calling jpeg_start_compress().
+   */
+
+  int data_precision;		/* bits of precision in image data */
+
+  int num_components;		/* # of color components in JPEG image */
+  J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */
+
+  jpeg_component_info * comp_info;
+  /* comp_info[i] describes component that appears i'th in SOF */
+
+  JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS];
+  int q_scale_factor[NUM_QUANT_TBLS];
+  /* ptrs to coefficient quantization tables, or NULL if not defined,
+   * and corresponding scale factors (percentage, initialized 100).
+   */
+
+  JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS];
+  JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS];
+  /* ptrs to Huffman coding tables, or NULL if not defined */
+
+  UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */
+  UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */
+  UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */
+
+  int num_scans;		/* # of entries in scan_info array */
+  const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */
+  /* The default value of scan_info is NULL, which causes a single-scan
+   * sequential JPEG file to be emitted.  To create a multi-scan file,
+   * set num_scans and scan_info to point to an array of scan definitions.
+   */
+
+  boolean raw_data_in;		/* TRUE=caller supplies downsampled data */
+  boolean arith_code;		/* TRUE=arithmetic coding, FALSE=Huffman */
+  boolean optimize_coding;	/* TRUE=optimize entropy encoding parms */
+  boolean CCIR601_sampling;	/* TRUE=first samples are cosited */
+  boolean do_fancy_downsampling; /* TRUE=apply fancy downsampling */
+  int smoothing_factor;		/* 1..100, or 0 for no input smoothing */
+  J_DCT_METHOD dct_method;	/* DCT algorithm selector */
+
+  /* The restart interval can be specified in absolute MCUs by setting
+   * restart_interval, or in MCU rows by setting restart_in_rows
+   * (in which case the correct restart_interval will be figured
+   * for each scan).
+   */
+  unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */
+  int restart_in_rows;		/* if > 0, MCU rows per restart interval */
+
+  /* Parameters controlling emission of special markers. */
+
+  boolean write_JFIF_header;	/* should a JFIF marker be written? */
+  UINT8 JFIF_major_version;	/* What to write for the JFIF version number */
+  UINT8 JFIF_minor_version;
+  /* These three values are not used by the JPEG code, merely copied */
+  /* into the JFIF APP0 marker.  density_unit can be 0 for unknown, */
+  /* 1 for dots/inch, or 2 for dots/cm.  Note that the pixel aspect */
+  /* ratio is defined by X_density/Y_density even when density_unit=0. */
+  UINT8 density_unit;		/* JFIF code for pixel size units */
+  UINT16 X_density;		/* Horizontal pixel density */
+  UINT16 Y_density;		/* Vertical pixel density */
+  boolean write_Adobe_marker;	/* should an Adobe marker be written? */
+
+  J_COLOR_TRANSFORM color_transform;
+  /* Color transform identifier, writes LSE marker if nonzero */
+
+  /* State variable: index of next scanline to be written to
+   * jpeg_write_scanlines().  Application may use this to control its
+   * processing loop, e.g., "while (next_scanline < image_height)".
+   */
+
+  JDIMENSION next_scanline;	/* 0 .. image_height-1  */
+
+  /* Remaining fields are known throughout compressor, but generally
+   * should not be touched by a surrounding application.
+   */
+
+  /*
+   * These fields are computed during compression startup
+   */
+  boolean progressive_mode;	/* TRUE if scan script uses progressive mode */
+  int max_h_samp_factor;	/* largest h_samp_factor */
+  int max_v_samp_factor;	/* largest v_samp_factor */
+
+  int min_DCT_h_scaled_size;	/* smallest DCT_h_scaled_size of any component */
+  int min_DCT_v_scaled_size;	/* smallest DCT_v_scaled_size of any component */
+
+  JDIMENSION total_iMCU_rows;	/* # of iMCU rows to be input to coef ctlr */
+  /* The coefficient controller receives data in units of MCU rows as defined
+   * for fully interleaved scans (whether the JPEG file is interleaved or not).
+   * There are v_samp_factor * DCTSIZE sample rows of each component in an
+   * "iMCU" (interleaved MCU) row.
+   */
+  
+  /*
+   * These fields are valid during any one scan.
+   * They describe the components and MCUs actually appearing in the scan.
+   */
+  int comps_in_scan;		/* # of JPEG components in this scan */
+  jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN];
+  /* *cur_comp_info[i] describes component that appears i'th in SOS */
+  
+  JDIMENSION MCUs_per_row;	/* # of MCUs across the image */
+  JDIMENSION MCU_rows_in_scan;	/* # of MCU rows in the image */
+  
+  int blocks_in_MCU;		/* # of DCT blocks per MCU */
+  int MCU_membership[C_MAX_BLOCKS_IN_MCU];
+  /* MCU_membership[i] is index in cur_comp_info of component owning */
+  /* i'th block in an MCU */
+
+  int Ss, Se, Ah, Al;		/* progressive JPEG parameters for scan */
+
+  int block_size;		/* the basic DCT block size: 1..16 */
+  const int * natural_order;	/* natural-order position array */
+  int lim_Se;			/* min( Se, DCTSIZE2-1 ) */
+
+  /*
+   * Links to compression subobjects (methods and private variables of modules)
+   */
+  struct jpeg_comp_master * master;
+  struct jpeg_c_main_controller * main;
+  struct jpeg_c_prep_controller * prep;
+  struct jpeg_c_coef_controller * coef;
+  struct jpeg_marker_writer * marker;
+  struct jpeg_color_converter * cconvert;
+  struct jpeg_downsampler * downsample;
+  struct jpeg_forward_dct * fdct;
+  struct jpeg_entropy_encoder * entropy;
+  jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */
+  int script_space_size;
+};
+
+
+/* Master record for a decompression instance */
+
+struct jpeg_decompress_struct {
+  jpeg_common_fields;		/* Fields shared with jpeg_compress_struct */
+
+  /* Source of compressed data */
+  struct jpeg_source_mgr * src;
+
+  /* Basic description of image --- filled in by jpeg_read_header(). */
+  /* Application may inspect these values to decide how to process image. */
+
+  JDIMENSION image_width;	/* nominal image width (from SOF marker) */
+  JDIMENSION image_height;	/* nominal image height */
+  int num_components;		/* # of color components in JPEG image */
+  J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */
+
+  /* Decompression processing parameters --- these fields must be set before
+   * calling jpeg_start_decompress().  Note that jpeg_read_header() initializes
+   * them to default values.
+   */
+
+  J_COLOR_SPACE out_color_space; /* colorspace for output */
+
+  unsigned int scale_num, scale_denom; /* fraction by which to scale image */
+
+  double output_gamma;		/* image gamma wanted in output */
+
+  boolean buffered_image;	/* TRUE=multiple output passes */
+  boolean raw_data_out;		/* TRUE=downsampled data wanted */
+
+  J_DCT_METHOD dct_method;	/* IDCT algorithm selector */
+  boolean do_fancy_upsampling;	/* TRUE=apply fancy upsampling */
+  boolean do_block_smoothing;	/* TRUE=apply interblock smoothing */
+
+  boolean quantize_colors;	/* TRUE=colormapped output wanted */
+  /* the following are ignored if not quantize_colors: */
+  J_DITHER_MODE dither_mode;	/* type of color dithering to use */
+  boolean two_pass_quantize;	/* TRUE=use two-pass color quantization */
+  int desired_number_of_colors;	/* max # colors to use in created colormap */
+  /* these are significant only in buffered-image mode: */
+  boolean enable_1pass_quant;	/* enable future use of 1-pass quantizer */
+  boolean enable_external_quant;/* enable future use of external colormap */
+  boolean enable_2pass_quant;	/* enable future use of 2-pass quantizer */
+
+  /* Description of actual output image that will be returned to application.
+   * These fields are computed by jpeg_start_decompress().
+   * You can also use jpeg_calc_output_dimensions() to determine these values
+   * in advance of calling jpeg_start_decompress().
+   */
+
+  JDIMENSION output_width;	/* scaled image width */
+  JDIMENSION output_height;	/* scaled image height */
+  int out_color_components;	/* # of color components in out_color_space */
+  int output_components;	/* # of color components returned */
+  /* output_components is 1 (a colormap index) when quantizing colors;
+   * otherwise it equals out_color_components.
+   */
+  int rec_outbuf_height;	/* min recommended height of scanline buffer */
+  /* If the buffer passed to jpeg_read_scanlines() is less than this many rows
+   * high, space and time will be wasted due to unnecessary data copying.
+   * Usually rec_outbuf_height will be 1 or 2, at most 4.
+   */
+
+  /* When quantizing colors, the output colormap is described by these fields.
+   * The application can supply a colormap by setting colormap non-NULL before
+   * calling jpeg_start_decompress; otherwise a colormap is created during
+   * jpeg_start_decompress or jpeg_start_output.
+   * The map has out_color_components rows and actual_number_of_colors columns.
+   */
+  int actual_number_of_colors;	/* number of entries in use */
+  JSAMPARRAY colormap;		/* The color map as a 2-D pixel array */
+
+  /* State variables: these variables indicate the progress of decompression.
+   * The application may examine these but must not modify them.
+   */
+
+  /* Row index of next scanline to be read from jpeg_read_scanlines().
+   * Application may use this to control its processing loop, e.g.,
+   * "while (output_scanline < output_height)".
+   */
+  JDIMENSION output_scanline;	/* 0 .. output_height-1  */
+
+  /* Current input scan number and number of iMCU rows completed in scan.
+   * These indicate the progress of the decompressor input side.
+   */
+  int input_scan_number;	/* Number of SOS markers seen so far */
+  JDIMENSION input_iMCU_row;	/* Number of iMCU rows completed */
+
+  /* The "output scan number" is the notional scan being displayed by the
+   * output side.  The decompressor will not allow output scan/row number
+   * to get ahead of input scan/row, but it can fall arbitrarily far behind.
+   */
+  int output_scan_number;	/* Nominal scan number being displayed */
+  JDIMENSION output_iMCU_row;	/* Number of iMCU rows read */
+
+  /* Current progression status.  coef_bits[c][i] indicates the precision
+   * with which component c's DCT coefficient i (in zigzag order) is known.
+   * It is -1 when no data has yet been received, otherwise it is the point
+   * transform (shift) value for the most recent scan of the coefficient
+   * (thus, 0 at completion of the progression).
+   * This pointer is NULL when reading a non-progressive file.
+   */
+  int (*coef_bits)[DCTSIZE2];	/* -1 or current Al value for each coef */
+
+  /* Internal JPEG parameters --- the application usually need not look at
+   * these fields.  Note that the decompressor output side may not use
+   * any parameters that can change between scans.
+   */
+
+  /* Quantization and Huffman tables are carried forward across input
+   * datastreams when processing abbreviated JPEG datastreams.
+   */
+
+  JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS];
+  /* ptrs to coefficient quantization tables, or NULL if not defined */
+
+  JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS];
+  JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS];
+  /* ptrs to Huffman coding tables, or NULL if not defined */
+
+  /* These parameters are never carried across datastreams, since they
+   * are given in SOF/SOS markers or defined to be reset by SOI.
+   */
+
+  int data_precision;		/* bits of precision in image data */
+
+  jpeg_component_info * comp_info;
+  /* comp_info[i] describes component that appears i'th in SOF */
+
+  boolean is_baseline;		/* TRUE if Baseline SOF0 encountered */
+  boolean progressive_mode;	/* TRUE if SOFn specifies progressive mode */
+  boolean arith_code;		/* TRUE=arithmetic coding, FALSE=Huffman */
+
+  UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */
+  UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */
+  UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */
+
+  unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */
+
+  /* These fields record data obtained from optional markers recognized by
+   * the JPEG library.
+   */
+  boolean saw_JFIF_marker;	/* TRUE iff a JFIF APP0 marker was found */
+  /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */
+  UINT8 JFIF_major_version;	/* JFIF version number */
+  UINT8 JFIF_minor_version;
+  UINT8 density_unit;		/* JFIF code for pixel size units */
+  UINT16 X_density;		/* Horizontal pixel density */
+  UINT16 Y_density;		/* Vertical pixel density */
+  boolean saw_Adobe_marker;	/* TRUE iff an Adobe APP14 marker was found */
+  UINT8 Adobe_transform;	/* Color transform code from Adobe marker */
+
+  J_COLOR_TRANSFORM color_transform;
+  /* Color transform identifier derived from LSE marker, otherwise zero */
+
+  boolean CCIR601_sampling;	/* TRUE=first samples are cosited */
+
+  /* Aside from the specific data retained from APPn markers known to the
+   * library, the uninterpreted contents of any or all APPn and COM markers
+   * can be saved in a list for examination by the application.
+   */
+  jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */
+
+  /* Remaining fields are known throughout decompressor, but generally
+   * should not be touched by a surrounding application.
+   */
+
+  /*
+   * These fields are computed during decompression startup
+   */
+  int max_h_samp_factor;	/* largest h_samp_factor */
+  int max_v_samp_factor;	/* largest v_samp_factor */
+
+  int min_DCT_h_scaled_size;	/* smallest DCT_h_scaled_size of any component */
+  int min_DCT_v_scaled_size;	/* smallest DCT_v_scaled_size of any component */
+
+  JDIMENSION total_iMCU_rows;	/* # of iMCU rows in image */
+  /* The coefficient controller's input and output progress is measured in
+   * units of "iMCU" (interleaved MCU) rows.  These are the same as MCU rows
+   * in fully interleaved JPEG scans, but are used whether the scan is
+   * interleaved or not.  We define an iMCU row as v_samp_factor DCT block
+   * rows of each component.  Therefore, the IDCT output contains
+   * v_samp_factor*DCT_v_scaled_size sample rows of a component per iMCU row.
+   */
+
+  JSAMPLE * sample_range_limit; /* table for fast range-limiting */
+
+  /*
+   * These fields are valid during any one scan.
+   * They describe the components and MCUs actually appearing in the scan.
+   * Note that the decompressor output side must not use these fields.
+   */
+  int comps_in_scan;		/* # of JPEG components in this scan */
+  jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN];
+  /* *cur_comp_info[i] describes component that appears i'th in SOS */
+
+  JDIMENSION MCUs_per_row;	/* # of MCUs across the image */
+  JDIMENSION MCU_rows_in_scan;	/* # of MCU rows in the image */
+
+  int blocks_in_MCU;		/* # of DCT blocks per MCU */
+  int MCU_membership[D_MAX_BLOCKS_IN_MCU];
+  /* MCU_membership[i] is index in cur_comp_info of component owning */
+  /* i'th block in an MCU */
+
+  int Ss, Se, Ah, Al;		/* progressive JPEG parameters for scan */
+
+  /* These fields are derived from Se of first SOS marker.
+   */
+  int block_size;		/* the basic DCT block size: 1..16 */
+  const int * natural_order; /* natural-order position array for entropy decode */
+  int lim_Se;			/* min( Se, DCTSIZE2-1 ) for entropy decode */
+
+  /* This field is shared between entropy decoder and marker parser.
+   * It is either zero or the code of a JPEG marker that has been
+   * read from the data source, but has not yet been processed.
+   */
+  int unread_marker;
+
+  /*
+   * Links to decompression subobjects (methods, private variables of modules)
+   */
+  struct jpeg_decomp_master * master;
+  struct jpeg_d_main_controller * main;
+  struct jpeg_d_coef_controller * coef;
+  struct jpeg_d_post_controller * post;
+  struct jpeg_input_controller * inputctl;
+  struct jpeg_marker_reader * marker;
+  struct jpeg_entropy_decoder * entropy;
+  struct jpeg_inverse_dct * idct;
+  struct jpeg_upsampler * upsample;
+  struct jpeg_color_deconverter * cconvert;
+  struct jpeg_color_quantizer * cquantize;
+};
+
+
+/* "Object" declarations for JPEG modules that may be supplied or called
+ * directly by the surrounding application.
+ * As with all objects in the JPEG library, these structs only define the
+ * publicly visible methods and state variables of a module.  Additional
+ * private fields may exist after the public ones.
+ */
+
+
+/* Error handler object */
+
+struct jpeg_error_mgr {
+  /* Error exit handler: does not return to caller */
+  JMETHOD(noreturn_t, error_exit, (j_common_ptr cinfo));
+  /* Conditionally emit a trace or warning message */
+  JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level));
+  /* Routine that actually outputs a trace or error message */
+  JMETHOD(void, output_message, (j_common_ptr cinfo));
+  /* Format a message string for the most recent JPEG error or message */
+  JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer));
+#define JMSG_LENGTH_MAX  200	/* recommended size of format_message buffer */
+  /* Reset error state variables at start of a new image */
+  JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo));
+  
+  /* The message ID code and any parameters are saved here.
+   * A message can have one string parameter or up to 8 int parameters.
+   */
+  int msg_code;
+#define JMSG_STR_PARM_MAX  80
+  union {
+    int i[8];
+    char s[JMSG_STR_PARM_MAX];
+  } msg_parm;
+  
+  /* Standard state variables for error facility */
+  
+  int trace_level;		/* max msg_level that will be displayed */
+  
+  /* For recoverable corrupt-data errors, we emit a warning message,
+   * but keep going unless emit_message chooses to abort.  emit_message
+   * should count warnings in num_warnings.  The surrounding application
+   * can check for bad data by seeing if num_warnings is nonzero at the
+   * end of processing.
+   */
+  long num_warnings;		/* number of corrupt-data warnings */
+
+  /* These fields point to the table(s) of error message strings.
+   * An application can change the table pointer to switch to a different
+   * message list (typically, to change the language in which errors are
+   * reported).  Some applications may wish to add additional error codes
+   * that will be handled by the JPEG library error mechanism; the second
+   * table pointer is used for this purpose.
+   *
+   * First table includes all errors generated by JPEG library itself.
+   * Error code 0 is reserved for a "no such error string" message.
+   */
+  const char * const * jpeg_message_table; /* Library errors */
+  int last_jpeg_message;    /* Table contains strings 0..last_jpeg_message */
+  /* Second table can be added by application (see cjpeg/djpeg for example).
+   * It contains strings numbered first_addon_message..last_addon_message.
+   */
+  const char * const * addon_message_table; /* Non-library errors */
+  int first_addon_message;	/* code for first string in addon table */
+  int last_addon_message;	/* code for last string in addon table */
+};
+
+
+/* Progress monitor object */
+
+struct jpeg_progress_mgr {
+  JMETHOD(void, progress_monitor, (j_common_ptr cinfo));
+
+  long pass_counter;		/* work units completed in this pass */
+  long pass_limit;		/* total number of work units in this pass */
+  int completed_passes;		/* passes completed so far */
+  int total_passes;		/* total number of passes expected */
+};
+
+
+/* Data destination object for compression */
+
+struct jpeg_destination_mgr {
+  JOCTET * next_output_byte;	/* => next byte to write in buffer */
+  size_t free_in_buffer;	/* # of byte spaces remaining in buffer */
+
+  JMETHOD(void, init_destination, (j_compress_ptr cinfo));
+  JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo));
+  JMETHOD(void, term_destination, (j_compress_ptr cinfo));
+};
+
+
+/* Data source object for decompression */
+
+struct jpeg_source_mgr {
+  const JOCTET * next_input_byte; /* => next byte to read from buffer */
+  size_t bytes_in_buffer;	/* # of bytes remaining in buffer */
+
+  JMETHOD(void, init_source, (j_decompress_ptr cinfo));
+  JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo));
+  JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes));
+  JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired));
+  JMETHOD(void, term_source, (j_decompress_ptr cinfo));
+};
+
+
+/* Memory manager object.
+ * Allocates "small" objects (a few K total), "large" objects (tens of K),
+ * and "really big" objects (virtual arrays with backing store if needed).
+ * The memory manager does not allow individual objects to be freed; rather,
+ * each created object is assigned to a pool, and whole pools can be freed
+ * at once.  This is faster and more convenient than remembering exactly what
+ * to free, especially where malloc()/free() are not too speedy.
+ * NB: alloc routines never return NULL.  They exit to error_exit if not
+ * successful.
+ */
+
+#define JPOOL_PERMANENT	0	/* lasts until master record is destroyed */
+#define JPOOL_IMAGE	1	/* lasts until done with image/datastream */
+#define JPOOL_NUMPOOLS	2
+
+typedef struct jvirt_sarray_control * jvirt_sarray_ptr;
+typedef struct jvirt_barray_control * jvirt_barray_ptr;
+
+
+struct jpeg_memory_mgr {
+  /* Method pointers */
+  JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id,
+				size_t sizeofobject));
+  JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id,
+				     size_t sizeofobject));
+  JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id,
+				     JDIMENSION samplesperrow,
+				     JDIMENSION numrows));
+  JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id,
+				      JDIMENSION blocksperrow,
+				      JDIMENSION numrows));
+  JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo,
+						  int pool_id,
+						  boolean pre_zero,
+						  JDIMENSION samplesperrow,
+						  JDIMENSION numrows,
+						  JDIMENSION maxaccess));
+  JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo,
+						  int pool_id,
+						  boolean pre_zero,
+						  JDIMENSION blocksperrow,
+						  JDIMENSION numrows,
+						  JDIMENSION maxaccess));
+  JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo));
+  JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo,
+					   jvirt_sarray_ptr ptr,
+					   JDIMENSION start_row,
+					   JDIMENSION num_rows,
+					   boolean writable));
+  JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo,
+					    jvirt_barray_ptr ptr,
+					    JDIMENSION start_row,
+					    JDIMENSION num_rows,
+					    boolean writable));
+  JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id));
+  JMETHOD(void, self_destruct, (j_common_ptr cinfo));
+
+  /* Limit on memory allocation for this JPEG object.  (Note that this is
+   * merely advisory, not a guaranteed maximum; it only affects the space
+   * used for virtual-array buffers.)  May be changed by outer application
+   * after creating the JPEG object.
+   */
+  long max_memory_to_use;
+
+  /* Maximum allocation request accepted by alloc_large. */
+  long max_alloc_chunk;
+};
+
+
+/* Routine signature for application-supplied marker processing methods.
+ * Need not pass marker code since it is stored in cinfo->unread_marker.
+ */
+typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo));
+
+
+/* Declarations for routines called by application.
+ * The JPP macro hides prototype parameters from compilers that can't cope.
+ * Note JPP requires double parentheses.
+ */
+
+#ifdef HAVE_PROTOTYPES
+#define JPP(arglist)	arglist
+#else
+#define JPP(arglist)	()
+#endif
+
+
+/* Short forms of external names for systems with brain-damaged linkers.
+ * We shorten external names to be unique in the first six letters, which
+ * is good enough for all known systems.
+ * (If your compiler itself needs names to be unique in less than 15 
+ * characters, you are out of luck.  Get a better compiler.)
+ */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jpeg_std_error		jStdError
+#define jpeg_CreateCompress	jCreaCompress
+#define jpeg_CreateDecompress	jCreaDecompress
+#define jpeg_destroy_compress	jDestCompress
+#define jpeg_destroy_decompress	jDestDecompress
+#define jpeg_stdio_dest		jStdDest
+#define jpeg_stdio_src		jStdSrc
+#define jpeg_mem_dest		jMemDest
+#define jpeg_mem_src		jMemSrc
+#define jpeg_set_defaults	jSetDefaults
+#define jpeg_set_colorspace	jSetColorspace
+#define jpeg_default_colorspace	jDefColorspace
+#define jpeg_set_quality	jSetQuality
+#define jpeg_set_linear_quality	jSetLQuality
+#define jpeg_default_qtables	jDefQTables
+#define jpeg_add_quant_table	jAddQuantTable
+#define jpeg_quality_scaling	jQualityScaling
+#define jpeg_simple_progression	jSimProgress
+#define jpeg_suppress_tables	jSuppressTables
+#define jpeg_alloc_quant_table	jAlcQTable
+#define jpeg_alloc_huff_table	jAlcHTable
+#define jpeg_start_compress	jStrtCompress
+#define jpeg_write_scanlines	jWrtScanlines
+#define jpeg_finish_compress	jFinCompress
+#define jpeg_calc_jpeg_dimensions	jCjpegDimensions
+#define jpeg_write_raw_data	jWrtRawData
+#define jpeg_write_marker	jWrtMarker
+#define jpeg_write_m_header	jWrtMHeader
+#define jpeg_write_m_byte	jWrtMByte
+#define jpeg_write_tables	jWrtTables
+#define jpeg_read_header	jReadHeader
+#define jpeg_start_decompress	jStrtDecompress
+#define jpeg_read_scanlines	jReadScanlines
+#define jpeg_finish_decompress	jFinDecompress
+#define jpeg_read_raw_data	jReadRawData
+#define jpeg_has_multiple_scans	jHasMultScn
+#define jpeg_start_output	jStrtOutput
+#define jpeg_finish_output	jFinOutput
+#define jpeg_input_complete	jInComplete
+#define jpeg_new_colormap	jNewCMap
+#define jpeg_consume_input	jConsumeInput
+#define jpeg_core_output_dimensions	jCoreDimensions
+#define jpeg_calc_output_dimensions	jCalcDimensions
+#define jpeg_save_markers	jSaveMarkers
+#define jpeg_set_marker_processor	jSetMarker
+#define jpeg_read_coefficients	jReadCoefs
+#define jpeg_write_coefficients	jWrtCoefs
+#define jpeg_copy_critical_parameters	jCopyCrit
+#define jpeg_abort_compress	jAbrtCompress
+#define jpeg_abort_decompress	jAbrtDecompress
+#define jpeg_abort		jAbort
+#define jpeg_destroy		jDestroy
+#define jpeg_resync_to_restart	jResyncRestart
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+
+/* Default error-management setup */
+EXTERN(struct jpeg_error_mgr *) jpeg_std_error
+	JPP((struct jpeg_error_mgr * err));
+
+/* Initialization of JPEG compression objects.
+ * jpeg_create_compress() and jpeg_create_decompress() are the exported
+ * names that applications should call.  These expand to calls on
+ * jpeg_CreateCompress and jpeg_CreateDecompress with additional information
+ * passed for version mismatch checking.
+ * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx.
+ */
+#define jpeg_create_compress(cinfo) \
+    jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \
+			(size_t) sizeof(struct jpeg_compress_struct))
+#define jpeg_create_decompress(cinfo) \
+    jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \
+			  (size_t) sizeof(struct jpeg_decompress_struct))
+EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo,
+				      int version, size_t structsize));
+EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo,
+					int version, size_t structsize));
+/* Destruction of JPEG compression objects */
+EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo));
+EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo));
+
+/* Standard data source and destination managers: stdio streams. */
+/* Caller is responsible for opening the file before and closing after. */
+EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile));
+EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile));
+
+/* Data source and destination managers: memory buffers. */
+EXTERN(void) jpeg_mem_dest JPP((j_compress_ptr cinfo,
+			       unsigned char ** outbuffer,
+			       unsigned long * outsize));
+EXTERN(void) jpeg_mem_src JPP((j_decompress_ptr cinfo,
+			      unsigned char * inbuffer,
+			      unsigned long insize));
+
+/* Default parameter setup for compression */
+EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo));
+/* Compression parameter setup aids */
+EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo,
+				      J_COLOR_SPACE colorspace));
+EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo));
+EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality,
+				   boolean force_baseline));
+EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo,
+					  int scale_factor,
+					  boolean force_baseline));
+EXTERN(void) jpeg_default_qtables JPP((j_compress_ptr cinfo,
+				       boolean force_baseline));
+EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl,
+				       const unsigned int *basic_table,
+				       int scale_factor,
+				       boolean force_baseline));
+EXTERN(int) jpeg_quality_scaling JPP((int quality));
+EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo));
+EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo,
+				       boolean suppress));
+EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo));
+EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo));
+
+/* Main entry points for compression */
+EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo,
+				      boolean write_all_tables));
+EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo,
+					     JSAMPARRAY scanlines,
+					     JDIMENSION num_lines));
+EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo));
+
+/* Precalculate JPEG dimensions for current compression parameters. */
+EXTERN(void) jpeg_calc_jpeg_dimensions JPP((j_compress_ptr cinfo));
+
+/* Replaces jpeg_write_scanlines when writing raw downsampled data. */
+EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo,
+					    JSAMPIMAGE data,
+					    JDIMENSION num_lines));
+
+/* Write a special marker.  See libjpeg.txt concerning safe usage. */
+EXTERN(void) jpeg_write_marker
+	JPP((j_compress_ptr cinfo, int marker,
+	     const JOCTET * dataptr, unsigned int datalen));
+/* Same, but piecemeal. */
+EXTERN(void) jpeg_write_m_header
+	JPP((j_compress_ptr cinfo, int marker, unsigned int datalen));
+EXTERN(void) jpeg_write_m_byte
+	JPP((j_compress_ptr cinfo, int val));
+
+/* Alternate compression function: just write an abbreviated table file */
+EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo));
+
+/* Decompression startup: read start of JPEG datastream to see what's there */
+EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo,
+				  boolean require_image));
+/* Return value is one of: */
+#define JPEG_SUSPENDED		0 /* Suspended due to lack of input data */
+#define JPEG_HEADER_OK		1 /* Found valid image datastream */
+#define JPEG_HEADER_TABLES_ONLY	2 /* Found valid table-specs-only datastream */
+/* If you pass require_image = TRUE (normal case), you need not check for
+ * a TABLES_ONLY return code; an abbreviated file will cause an error exit.
+ * JPEG_SUSPENDED is only possible if you use a data source module that can
+ * give a suspension return (the stdio source module doesn't).
+ */
+
+/* Main entry points for decompression */
+EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo));
+EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo,
+					    JSAMPARRAY scanlines,
+					    JDIMENSION max_lines));
+EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo));
+
+/* Replaces jpeg_read_scanlines when reading raw downsampled data. */
+EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo,
+					   JSAMPIMAGE data,
+					   JDIMENSION max_lines));
+
+/* Additional entry points for buffered-image mode. */
+EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo));
+EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo,
+				       int scan_number));
+EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo));
+EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo));
+EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo));
+EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo));
+/* Return value is one of: */
+/* #define JPEG_SUSPENDED	0    Suspended due to lack of input data */
+#define JPEG_REACHED_SOS	1 /* Reached start of new scan */
+#define JPEG_REACHED_EOI	2 /* Reached end of image */
+#define JPEG_ROW_COMPLETED	3 /* Completed one iMCU row */
+#define JPEG_SCAN_COMPLETED	4 /* Completed last iMCU row of a scan */
+
+/* Precalculate output dimensions for current decompression parameters. */
+EXTERN(void) jpeg_core_output_dimensions JPP((j_decompress_ptr cinfo));
+EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo));
+
+/* Control saving of COM and APPn markers into marker_list. */
+EXTERN(void) jpeg_save_markers
+	JPP((j_decompress_ptr cinfo, int marker_code,
+	     unsigned int length_limit));
+
+/* Install a special processing method for COM or APPn markers. */
+EXTERN(void) jpeg_set_marker_processor
+	JPP((j_decompress_ptr cinfo, int marker_code,
+	     jpeg_marker_parser_method routine));
+
+/* Read or write raw DCT coefficients --- useful for lossless transcoding. */
+EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo));
+EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo,
+					  jvirt_barray_ptr * coef_arrays));
+EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo,
+						j_compress_ptr dstinfo));
+
+/* If you choose to abort compression or decompression before completing
+ * jpeg_finish_(de)compress, then you need to clean up to release memory,
+ * temporary files, etc.  You can just call jpeg_destroy_(de)compress
+ * if you're done with the JPEG object, but if you want to clean it up and
+ * reuse it, call this:
+ */
+EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo));
+EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo));
+
+/* Generic versions of jpeg_abort and jpeg_destroy that work on either
+ * flavor of JPEG object.  These may be more convenient in some places.
+ */
+EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo));
+EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo));
+
+/* Default restart-marker-resync procedure for use by data source modules */
+EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo,
+					    int desired));
+
+
+/* These marker codes are exported since applications and data source modules
+ * are likely to want to use them.
+ */
+
+#define JPEG_RST0	0xD0	/* RST0 marker code */
+#define JPEG_EOI	0xD9	/* EOI marker code */
+#define JPEG_APP0	0xE0	/* APP0 marker code */
+#define JPEG_COM	0xFE	/* COM marker code */
+
+
+/* If we have a brain-damaged compiler that emits warnings (or worse, errors)
+ * for structure definitions that are never filled in, keep it quiet by
+ * supplying dummy definitions for the various substructures.
+ */
+
+#ifdef INCOMPLETE_TYPES_BROKEN
+#ifndef JPEG_INTERNALS		/* will be defined in jpegint.h */
+struct jvirt_sarray_control { long dummy; };
+struct jvirt_barray_control { long dummy; };
+struct jpeg_comp_master { long dummy; };
+struct jpeg_c_main_controller { long dummy; };
+struct jpeg_c_prep_controller { long dummy; };
+struct jpeg_c_coef_controller { long dummy; };
+struct jpeg_marker_writer { long dummy; };
+struct jpeg_color_converter { long dummy; };
+struct jpeg_downsampler { long dummy; };
+struct jpeg_forward_dct { long dummy; };
+struct jpeg_entropy_encoder { long dummy; };
+struct jpeg_decomp_master { long dummy; };
+struct jpeg_d_main_controller { long dummy; };
+struct jpeg_d_coef_controller { long dummy; };
+struct jpeg_d_post_controller { long dummy; };
+struct jpeg_input_controller { long dummy; };
+struct jpeg_marker_reader { long dummy; };
+struct jpeg_entropy_decoder { long dummy; };
+struct jpeg_inverse_dct { long dummy; };
+struct jpeg_upsampler { long dummy; };
+struct jpeg_color_deconverter { long dummy; };
+struct jpeg_color_quantizer { long dummy; };
+#endif /* JPEG_INTERNALS */
+#endif /* INCOMPLETE_TYPES_BROKEN */
+
+
+/*
+ * The JPEG library modules define JPEG_INTERNALS before including this file.
+ * The internal structure declarations are read only when that is true.
+ * Applications using the library should not include jpegint.h, but may wish
+ * to include jerror.h.
+ */
+
+#ifdef JPEG_INTERNALS
+#include "jpegint.h"		/* fetch private declarations */
+#include "jerror.h"		/* fetch error codes too */
+#endif
+
+#ifdef __cplusplus
+#ifndef DONT_USE_EXTERN_C
+}
+#endif
+#endif
+
+#endif /* JPEGLIB_H */
diff --git a/source/Irrlicht/jpeglib/jpegtran.1 b/source/Irrlicht/jpeglib/jpegtran.1
new file mode 100644
index 00000000..2220f7a5
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jpegtran.1
@@ -0,0 +1,293 @@
+.TH JPEGTRAN 1 "13 September 2013"
+.SH NAME
+jpegtran \- lossless transformation of JPEG files
+.SH SYNOPSIS
+.B jpegtran
+[
+.I options
+]
+[
+.I filename
+]
+.LP
+.SH DESCRIPTION
+.LP
+.B jpegtran
+performs various useful transformations of JPEG files.
+It can translate the coded representation from one variant of JPEG to another,
+for example from baseline JPEG to progressive JPEG or vice versa.  It can also
+perform some rearrangements of the image data, for example turning an image
+from landscape to portrait format by rotation.
+.PP
+.B jpegtran
+works by rearranging the compressed data (DCT coefficients), without
+ever fully decoding the image.  Therefore, its transformations are lossless:
+there is no image degradation at all, which would not be true if you used
+.B djpeg
+followed by
+.B cjpeg
+to accomplish the same conversion.  But by the same token,
+.B jpegtran
+cannot perform lossy operations such as changing the image quality.
+.PP
+.B jpegtran
+reads the named JPEG/JFIF file, or the standard input if no file is
+named, and produces a JPEG/JFIF file on the standard output.
+.SH OPTIONS
+All switch names may be abbreviated; for example,
+.B \-optimize
+may be written
+.B \-opt
+or
+.BR \-o .
+Upper and lower case are equivalent.
+British spellings are also accepted (e.g.,
+.BR \-optimise ),
+though for brevity these are not mentioned below.
+.PP
+To specify the coded JPEG representation used in the output file,
+.B jpegtran
+accepts a subset of the switches recognized by
+.BR cjpeg :
+.TP
+.B \-optimize
+Perform optimization of entropy encoding parameters.
+.TP
+.B \-progressive
+Create progressive JPEG file.
+.TP
+.BI \-restart " N"
+Emit a JPEG restart marker every N MCU rows, or every N MCU blocks if "B" is
+attached to the number.
+.TP
+.B \-arithmetic
+Use arithmetic coding.
+.TP
+.BI \-scans " file"
+Use the scan script given in the specified text file.
+.PP
+See
+.BR cjpeg (1)
+for more details about these switches.
+If you specify none of these switches, you get a plain baseline-JPEG output
+file.  The quality setting and so forth are determined by the input file.
+.PP
+The image can be losslessly transformed by giving one of these switches:
+.TP
+.B \-flip horizontal
+Mirror image horizontally (left-right).
+.TP
+.B \-flip vertical
+Mirror image vertically (top-bottom).
+.TP
+.B \-rotate 90
+Rotate image 90 degrees clockwise.
+.TP
+.B \-rotate 180
+Rotate image 180 degrees.
+.TP
+.B \-rotate 270
+Rotate image 270 degrees clockwise (or 90 ccw).
+.TP
+.B \-transpose
+Transpose image (across UL-to-LR axis).
+.TP
+.B \-transverse
+Transverse transpose (across UR-to-LL axis).
+.IP
+The transpose transformation has no restrictions regarding image dimensions.
+The other transformations operate rather oddly if the image dimensions are not
+a multiple of the iMCU size (usually 8 or 16 pixels), because they can only
+transform complete blocks of DCT coefficient data in the desired way.
+.IP
+.BR jpegtran 's
+default behavior when transforming an odd-size image is designed
+to preserve exact reversibility and mathematical consistency of the
+transformation set.  As stated, transpose is able to flip the entire image
+area.  Horizontal mirroring leaves any partial iMCU column at the right edge
+untouched, but is able to flip all rows of the image.  Similarly, vertical
+mirroring leaves any partial iMCU row at the bottom edge untouched, but is
+able to flip all columns.  The other transforms can be built up as sequences
+of transpose and flip operations; for consistency, their actions on edge
+pixels are defined to be the same as the end result of the corresponding
+transpose-and-flip sequence.
+.IP
+For practical use, you may prefer to discard any untransformable edge pixels
+rather than having a strange-looking strip along the right and/or bottom edges
+of a transformed image.  To do this, add the
+.B \-trim
+switch:
+.TP
+.B \-trim
+Drop non-transformable edge blocks.
+.IP
+Obviously, a transformation with
+.B \-trim
+is not reversible, so strictly speaking
+.B jpegtran
+with this switch is not lossless.  Also, the expected mathematical
+equivalences between the transformations no longer hold.  For example,
+.B \-rot 270 -trim
+trims only the bottom edge, but
+.B \-rot 90 -trim
+followed by
+.B \-rot 180 -trim
+trims both edges.
+.IP
+If you are only interested in perfect transformation, add the
+.B \-perfect
+switch:
+.TP
+.B \-perfect
+Fails with an error if the transformation is not perfect.
+.IP
+For example you may want to do
+.IP
+.B (jpegtran \-rot 90 -perfect
+.I foo.jpg
+.B || djpeg
+.I foo.jpg
+.B | pnmflip \-r90 | cjpeg)
+.IP
+to do a perfect rotation if available or an approximated one if not.
+.PP
+We also offer a lossless-crop option, which discards data outside a given
+image region but losslessly preserves what is inside.  Like the rotate and
+flip transforms, lossless crop is restricted by the current JPEG format: the
+upper left corner of the selected region must fall on an iMCU boundary.  If
+this does not hold for the given crop parameters, we silently move the upper
+left corner up and/or left to make it so, simultaneously increasing the
+region dimensions to keep the lower right crop corner unchanged.  (Thus, the
+output image covers at least the requested region, but may cover more.)
+The adjustment of the region dimensions may be optionally disabled.
+
+The image can be losslessly cropped by giving the switch:
+.TP
+.B \-crop WxH+X+Y
+Crop to a rectangular subarea of width W, height H starting at point X,Y.
+.PP
+A complementary lossless-wipe option is provided to discard (gray out) data
+inside a given image region while losslessly preserving what is outside:
+.TP
+.B \-wipe WxH+X+Y
+Wipe (gray out) a rectangular subarea of width W, height H starting at point
+X,Y.
+.PP
+Other not-strictly-lossless transformation switches are:
+.TP
+.B \-grayscale
+Force grayscale output.
+.IP
+This option discards the chrominance channels if the input image is YCbCr
+(ie, a standard color JPEG), resulting in a grayscale JPEG file.  The
+luminance channel is preserved exactly, so this is a better method of reducing
+to grayscale than decompression, conversion, and recompression.  This switch
+is particularly handy for fixing a monochrome picture that was mistakenly
+encoded as a color JPEG.  (In such a case, the space savings from getting rid
+of the near-empty chroma channels won't be large; but the decoding time for
+a grayscale JPEG is substantially less than that for a color JPEG.)
+.TP
+.BI \-scale " M/N"
+Scale the output image by a factor M/N.
+.IP
+Currently supported scale factors are M/N with all M from 1 to 16, where N is
+the source DCT size, which is 8 for baseline JPEG.  If the /N part is omitted,
+then M specifies the DCT scaled size to be applied on the given input.  For
+baseline JPEG this is equivalent to M/8 scaling, since the source DCT size
+for baseline JPEG is 8.
+.B Caution:
+An implementation of the JPEG SmartScale extension is required for this
+feature.  SmartScale enabled JPEG is not yet widely implemented, so many
+decoders will be unable to view a SmartScale extended JPEG file at all.
+.PP
+.B jpegtran
+also recognizes these switches that control what to do with "extra" markers,
+such as comment blocks:
+.TP
+.B \-copy none
+Copy no extra markers from source file.  This setting suppresses all
+comments and other excess baggage present in the source file.
+.TP
+.B \-copy comments
+Copy only comment markers.  This setting copies comments from the source file,
+but discards any other inessential (for image display) data.
+.TP
+.B \-copy all
+Copy all extra markers.  This setting preserves miscellaneous markers
+found in the source file, such as JFIF thumbnails, Exif data, and Photoshop
+settings.  In some files these extra markers can be sizable.
+.IP
+The default behavior is
+.BR "\-copy comments" .
+(Note: in IJG releases v6 and v6a,
+.B jpegtran
+always did the equivalent of
+.BR "\-copy none" .)
+.PP
+Additional switches recognized by jpegtran are:
+.TP
+.BI \-maxmemory " N"
+Set limit for amount of memory to use in processing large images.  Value is
+in thousands of bytes, or millions of bytes if "M" is attached to the
+number.  For example,
+.B \-max 4m
+selects 4000000 bytes.  If more space is needed, temporary files will be used.
+.TP
+.BI \-outfile " name"
+Send output image to the named file, not to standard output.
+.TP
+.B \-verbose
+Enable debug printout.  More
+.BR \-v 's
+give more output.  Also, version information is printed at startup.
+.TP
+.B \-debug
+Same as
+.BR \-verbose .
+.SH EXAMPLES
+.LP
+This example converts a baseline JPEG file to progressive form:
+.IP
+.B jpegtran \-progressive
+.I foo.jpg
+.B >
+.I fooprog.jpg
+.PP
+This example rotates an image 90 degrees clockwise, discarding any
+unrotatable edge pixels:
+.IP
+.B jpegtran \-rot 90 -trim
+.I foo.jpg
+.B >
+.I foo90.jpg
+.SH ENVIRONMENT
+.TP
+.B JPEGMEM
+If this environment variable is set, its value is the default memory limit.
+The value is specified as described for the
+.B \-maxmemory
+switch.
+.B JPEGMEM
+overrides the default value specified when the program was compiled, and
+itself is overridden by an explicit
+.BR \-maxmemory .
+.SH SEE ALSO
+.BR cjpeg (1),
+.BR djpeg (1),
+.BR rdjpgcom (1),
+.BR wrjpgcom (1)
+.br
+Wallace, Gregory K.  "The JPEG Still Picture Compression Standard",
+Communications of the ACM, April 1991 (vol. 34, no. 4), pp. 30-44.
+.SH AUTHOR
+Independent JPEG Group
+.SH BUGS
+The transform options can't transform odd-size images perfectly.  Use
+.B \-trim
+or
+.B \-perfect
+if you don't like the results.
+.PP
+The entire image is read into memory and then written out again, even in
+cases where this isn't really necessary.  Expect swapping on large images,
+especially when using the more complex transform options.
diff --git a/source/Irrlicht/jpeglib/jpegtran.c b/source/Irrlicht/jpeglib/jpegtran.c
new file mode 100644
index 00000000..f3175aee
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jpegtran.c
@@ -0,0 +1,577 @@
+/*
+ * jpegtran.c
+ *
+ * Copyright (C) 1995-2013, Thomas G. Lane, Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a command-line user interface for JPEG transcoding.
+ * It is very similar to cjpeg.c, and partly to djpeg.c, but provides
+ * lossless transcoding between different JPEG file formats.  It also
+ * provides some lossless and sort-of-lossless transformations of JPEG data.
+ */
+
+#include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
+#include "transupp.h"		/* Support routines for jpegtran */
+#include "jversion.h"		/* for version message */
+
+#ifdef USE_CCOMMAND		/* command-line reader for Macintosh */
+#ifdef __MWERKS__
+#include               /* Metrowerks needs this */
+#include 		/* ... and this */
+#endif
+#ifdef THINK_C
+#include 		/* Think declares it here */
+#endif
+#endif
+
+
+/*
+ * Argument-parsing code.
+ * The switch parser is designed to be useful with DOS-style command line
+ * syntax, ie, intermixed switches and file names, where only the switches
+ * to the left of a given file name affect processing of that file.
+ * The main program in this file doesn't actually use this capability...
+ */
+
+
+static const char * progname;	/* program name for error messages */
+static char * outfilename;	/* for -outfile switch */
+static char * scaleoption;	/* -scale switch */
+static JCOPY_OPTION copyoption;	/* -copy switch */
+static jpeg_transform_info transformoption; /* image transformation options */
+
+
+LOCAL(void)
+usage (void)
+/* complain about bad command line */
+{
+  fprintf(stderr, "usage: %s [switches] ", progname);
+#ifdef TWO_FILE_COMMANDLINE
+  fprintf(stderr, "inputfile outputfile\n");
+#else
+  fprintf(stderr, "[inputfile]\n");
+#endif
+
+  fprintf(stderr, "Switches (names may be abbreviated):\n");
+  fprintf(stderr, "  -copy none     Copy no extra markers from source file\n");
+  fprintf(stderr, "  -copy comments Copy only comment markers (default)\n");
+  fprintf(stderr, "  -copy all      Copy all extra markers\n");
+#ifdef ENTROPY_OPT_SUPPORTED
+  fprintf(stderr, "  -optimize      Optimize Huffman table (smaller file, but slow compression)\n");
+#endif
+#ifdef C_PROGRESSIVE_SUPPORTED
+  fprintf(stderr, "  -progressive   Create progressive JPEG file\n");
+#endif
+  fprintf(stderr, "Switches for modifying the image:\n");
+#if TRANSFORMS_SUPPORTED
+  fprintf(stderr, "  -crop WxH+X+Y  Crop to a rectangular subarea\n");
+  fprintf(stderr, "  -flip [horizontal|vertical]  Mirror image (left-right or top-bottom)\n");
+  fprintf(stderr, "  -grayscale     Reduce to grayscale (omit color data)\n");
+  fprintf(stderr, "  -perfect       Fail if there is non-transformable edge blocks\n");
+  fprintf(stderr, "  -rotate [90|180|270]         Rotate image (degrees clockwise)\n");
+#endif
+  fprintf(stderr, "  -scale M/N     Scale output image by fraction M/N, eg, 1/8\n");
+#if TRANSFORMS_SUPPORTED
+  fprintf(stderr, "  -transpose     Transpose image\n");
+  fprintf(stderr, "  -transverse    Transverse transpose image\n");
+  fprintf(stderr, "  -trim          Drop non-transformable edge blocks\n");
+  fprintf(stderr, "  -wipe WxH+X+Y  Wipe (gray out) a rectangular subarea\n");
+#endif
+  fprintf(stderr, "Switches for advanced users:\n");
+#ifdef C_ARITH_CODING_SUPPORTED
+  fprintf(stderr, "  -arithmetic    Use arithmetic coding\n");
+#endif
+  fprintf(stderr, "  -restart N     Set restart interval in rows, or in blocks with B\n");
+  fprintf(stderr, "  -maxmemory N   Maximum memory to use (in kbytes)\n");
+  fprintf(stderr, "  -outfile name  Specify name for output file\n");
+  fprintf(stderr, "  -verbose  or  -debug   Emit debug output\n");
+  fprintf(stderr, "Switches for wizards:\n");
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+  fprintf(stderr, "  -scans file    Create multi-scan JPEG per script file\n");
+#endif
+  exit(EXIT_FAILURE);
+}
+
+
+LOCAL(void)
+select_transform (JXFORM_CODE transform)
+/* Silly little routine to detect multiple transform options,
+ * which we can't handle.
+ */
+{
+#if TRANSFORMS_SUPPORTED
+  if (transformoption.transform == JXFORM_NONE ||
+      transformoption.transform == transform) {
+    transformoption.transform = transform;
+  } else {
+    fprintf(stderr, "%s: can only do one image transformation at a time\n",
+	    progname);
+    usage();
+  }
+#else
+  fprintf(stderr, "%s: sorry, image transformation was not compiled\n",
+	  progname);
+  exit(EXIT_FAILURE);
+#endif
+}
+
+
+LOCAL(int)
+parse_switches (j_compress_ptr cinfo, int argc, char **argv,
+		int last_file_arg_seen, boolean for_real)
+/* Parse optional switches.
+ * Returns argv[] index of first file-name argument (== argc if none).
+ * Any file names with indexes <= last_file_arg_seen are ignored;
+ * they have presumably been processed in a previous iteration.
+ * (Pass 0 for last_file_arg_seen on the first or only iteration.)
+ * for_real is FALSE on the first (dummy) pass; we may skip any expensive
+ * processing.
+ */
+{
+  int argn;
+  char * arg;
+  boolean simple_progressive;
+  char * scansarg = NULL;	/* saves -scans parm if any */
+
+  /* Set up default JPEG parameters. */
+  simple_progressive = FALSE;
+  outfilename = NULL;
+  scaleoption = NULL;
+  copyoption = JCOPYOPT_DEFAULT;
+  transformoption.transform = JXFORM_NONE;
+  transformoption.perfect = FALSE;
+  transformoption.trim = FALSE;
+  transformoption.force_grayscale = FALSE;
+  transformoption.crop = FALSE;
+  cinfo->err->trace_level = 0;
+
+  /* Scan command line options, adjust parameters */
+
+  for (argn = 1; argn < argc; argn++) {
+    arg = argv[argn];
+    if (*arg != '-') {
+      /* Not a switch, must be a file name argument */
+      if (argn <= last_file_arg_seen) {
+	outfilename = NULL;	/* -outfile applies to just one input file */
+	continue;		/* ignore this name if previously processed */
+      }
+      break;			/* else done parsing switches */
+    }
+    arg++;			/* advance past switch marker character */
+
+    if (keymatch(arg, "arithmetic", 1)) {
+      /* Use arithmetic coding. */
+#ifdef C_ARITH_CODING_SUPPORTED
+      cinfo->arith_code = TRUE;
+#else
+      fprintf(stderr, "%s: sorry, arithmetic coding not supported\n",
+	      progname);
+      exit(EXIT_FAILURE);
+#endif
+
+    } else if (keymatch(arg, "copy", 2)) {
+      /* Select which extra markers to copy. */
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (keymatch(argv[argn], "none", 1)) {
+	copyoption = JCOPYOPT_NONE;
+      } else if (keymatch(argv[argn], "comments", 1)) {
+	copyoption = JCOPYOPT_COMMENTS;
+      } else if (keymatch(argv[argn], "all", 1)) {
+	copyoption = JCOPYOPT_ALL;
+      } else
+	usage();
+
+    } else if (keymatch(arg, "crop", 2)) {
+      /* Perform lossless cropping. */
+#if TRANSFORMS_SUPPORTED
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (transformoption.crop /* reject multiple crop/wipe requests */ ||
+	  ! jtransform_parse_crop_spec(&transformoption, argv[argn])) {
+	fprintf(stderr, "%s: bogus -crop argument '%s'\n",
+		progname, argv[argn]);
+	exit(EXIT_FAILURE);
+      }
+#else
+      select_transform(JXFORM_NONE);	/* force an error */
+#endif
+
+    } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
+      /* Enable debug printouts. */
+      /* On first -d, print version identification */
+      static boolean printed_version = FALSE;
+
+      if (! printed_version) {
+	fprintf(stderr, "Independent JPEG Group's JPEGTRAN, version %s\n%s\n",
+		JVERSION, JCOPYRIGHT);
+	printed_version = TRUE;
+      }
+      cinfo->err->trace_level++;
+
+    } else if (keymatch(arg, "flip", 1)) {
+      /* Mirror left-right or top-bottom. */
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (keymatch(argv[argn], "horizontal", 1))
+	select_transform(JXFORM_FLIP_H);
+      else if (keymatch(argv[argn], "vertical", 1))
+	select_transform(JXFORM_FLIP_V);
+      else
+	usage();
+
+    } else if (keymatch(arg, "grayscale", 1) || keymatch(arg, "greyscale",1)) {
+      /* Force to grayscale. */
+#if TRANSFORMS_SUPPORTED
+      transformoption.force_grayscale = TRUE;
+#else
+      select_transform(JXFORM_NONE);	/* force an error */
+#endif
+
+    } else if (keymatch(arg, "maxmemory", 3)) {
+      /* Maximum memory in Kb (or Mb with 'm'). */
+      long lval;
+      char ch = 'x';
+
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
+	usage();
+      if (ch == 'm' || ch == 'M')
+	lval *= 1000L;
+      cinfo->mem->max_memory_to_use = lval * 1000L;
+
+    } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) {
+      /* Enable entropy parm optimization. */
+#ifdef ENTROPY_OPT_SUPPORTED
+      cinfo->optimize_coding = TRUE;
+#else
+      fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n",
+	      progname);
+      exit(EXIT_FAILURE);
+#endif
+
+    } else if (keymatch(arg, "outfile", 4)) {
+      /* Set output file name. */
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      outfilename = argv[argn];	/* save it away for later use */
+
+    } else if (keymatch(arg, "perfect", 2)) {
+      /* Fail if there is any partial edge MCUs that the transform can't
+       * handle. */
+      transformoption.perfect = TRUE;
+
+    } else if (keymatch(arg, "progressive", 2)) {
+      /* Select simple progressive mode. */
+#ifdef C_PROGRESSIVE_SUPPORTED
+      simple_progressive = TRUE;
+      /* We must postpone execution until num_components is known. */
+#else
+      fprintf(stderr, "%s: sorry, progressive output was not compiled\n",
+	      progname);
+      exit(EXIT_FAILURE);
+#endif
+
+    } else if (keymatch(arg, "restart", 1)) {
+      /* Restart interval in MCU rows (or in MCUs with 'b'). */
+      long lval;
+      char ch = 'x';
+
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
+	usage();
+      if (lval < 0 || lval > 65535L)
+	usage();
+      if (ch == 'b' || ch == 'B') {
+	cinfo->restart_interval = (unsigned int) lval;
+	cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */
+      } else {
+	cinfo->restart_in_rows = (int) lval;
+	/* restart_interval will be computed during startup */
+      }
+
+    } else if (keymatch(arg, "rotate", 2)) {
+      /* Rotate 90, 180, or 270 degrees (measured clockwise). */
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (keymatch(argv[argn], "90", 2))
+	select_transform(JXFORM_ROT_90);
+      else if (keymatch(argv[argn], "180", 3))
+	select_transform(JXFORM_ROT_180);
+      else if (keymatch(argv[argn], "270", 3))
+	select_transform(JXFORM_ROT_270);
+      else
+	usage();
+
+    } else if (keymatch(arg, "scale", 4)) {
+      /* Scale the output image by a fraction M/N. */
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      scaleoption = argv[argn];
+      /* We must postpone processing until decompression startup. */
+
+    } else if (keymatch(arg, "scans", 1)) {
+      /* Set scan script. */
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      scansarg = argv[argn];
+      /* We must postpone reading the file in case -progressive appears. */
+#else
+      fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n",
+	      progname);
+      exit(EXIT_FAILURE);
+#endif
+
+    } else if (keymatch(arg, "transpose", 1)) {
+      /* Transpose (across UL-to-LR axis). */
+      select_transform(JXFORM_TRANSPOSE);
+
+    } else if (keymatch(arg, "transverse", 6)) {
+      /* Transverse transpose (across UR-to-LL axis). */
+      select_transform(JXFORM_TRANSVERSE);
+
+    } else if (keymatch(arg, "trim", 3)) {
+      /* Trim off any partial edge MCUs that the transform can't handle. */
+      transformoption.trim = TRUE;
+
+    } else if (keymatch(arg, "wipe", 1)) {
+#if TRANSFORMS_SUPPORTED
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (transformoption.crop /* reject multiple crop/wipe requests */ ||
+	  ! jtransform_parse_crop_spec(&transformoption, argv[argn])) {
+	fprintf(stderr, "%s: bogus -wipe argument '%s'\n",
+		progname, argv[argn]);
+	exit(EXIT_FAILURE);
+      }
+      select_transform(JXFORM_WIPE);
+#else
+      select_transform(JXFORM_NONE);	/* force an error */
+#endif
+
+    } else {
+      usage();			/* bogus switch */
+    }
+  }
+
+  /* Post-switch-scanning cleanup */
+
+  if (for_real) {
+
+#ifdef C_PROGRESSIVE_SUPPORTED
+    if (simple_progressive)	/* process -progressive; -scans can override */
+      jpeg_simple_progression(cinfo);
+#endif
+
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+    if (scansarg != NULL)	/* process -scans if it was present */
+      if (! read_scan_script(cinfo, scansarg))
+	usage();
+#endif
+  }
+
+  return argn;			/* return index of next arg (file name) */
+}
+
+
+/*
+ * The main program.
+ */
+
+int
+main (int argc, char **argv)
+{
+  struct jpeg_decompress_struct srcinfo;
+  struct jpeg_compress_struct dstinfo;
+  struct jpeg_error_mgr jsrcerr, jdsterr;
+#ifdef PROGRESS_REPORT
+  struct cdjpeg_progress_mgr progress;
+#endif
+  jvirt_barray_ptr * src_coef_arrays;
+  jvirt_barray_ptr * dst_coef_arrays;
+  int file_index;
+  /* We assume all-in-memory processing and can therefore use only a
+   * single file pointer for sequential input and output operation. 
+   */
+  FILE * fp;
+
+  /* On Mac, fetch a command line. */
+#ifdef USE_CCOMMAND
+  argc = ccommand(&argv);
+#endif
+
+  progname = argv[0];
+  if (progname == NULL || progname[0] == 0)
+    progname = "jpegtran";	/* in case C library doesn't provide it */
+
+  /* Initialize the JPEG decompression object with default error handling. */
+  srcinfo.err = jpeg_std_error(&jsrcerr);
+  jpeg_create_decompress(&srcinfo);
+  /* Initialize the JPEG compression object with default error handling. */
+  dstinfo.err = jpeg_std_error(&jdsterr);
+  jpeg_create_compress(&dstinfo);
+
+  /* Now safe to enable signal catcher.
+   * Note: we assume only the decompression object will have virtual arrays.
+   */
+#ifdef NEED_SIGNAL_CATCHER
+  enable_signal_catcher((j_common_ptr) &srcinfo);
+#endif
+
+  /* Scan command line to find file names.
+   * It is convenient to use just one switch-parsing routine, but the switch
+   * values read here are mostly ignored; we will rescan the switches after
+   * opening the input file.  Also note that most of the switches affect the
+   * destination JPEG object, so we parse into that and then copy over what
+   * needs to affects the source too.
+   */
+
+  file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE);
+  jsrcerr.trace_level = jdsterr.trace_level;
+  srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use;
+
+#ifdef TWO_FILE_COMMANDLINE
+  /* Must have either -outfile switch or explicit output file name */
+  if (outfilename == NULL) {
+    if (file_index != argc-2) {
+      fprintf(stderr, "%s: must name one input and one output file\n",
+	      progname);
+      usage();
+    }
+    outfilename = argv[file_index+1];
+  } else {
+    if (file_index != argc-1) {
+      fprintf(stderr, "%s: must name one input and one output file\n",
+	      progname);
+      usage();
+    }
+  }
+#else
+  /* Unix style: expect zero or one file name */
+  if (file_index < argc-1) {
+    fprintf(stderr, "%s: only one input file\n", progname);
+    usage();
+  }
+#endif /* TWO_FILE_COMMANDLINE */
+
+  /* Open the input file. */
+  if (file_index < argc) {
+    if ((fp = fopen(argv[file_index], READ_BINARY)) == NULL) {
+      fprintf(stderr, "%s: can't open %s for reading\n", progname, argv[file_index]);
+      exit(EXIT_FAILURE);
+    }
+  } else {
+    /* default input file is stdin */
+    fp = read_stdin();
+  }
+
+#ifdef PROGRESS_REPORT
+  start_progress_monitor((j_common_ptr) &dstinfo, &progress);
+#endif
+
+  /* Specify data source for decompression */
+  jpeg_stdio_src(&srcinfo, fp);
+
+  /* Enable saving of extra markers that we want to copy */
+  jcopy_markers_setup(&srcinfo, copyoption);
+
+  /* Read file header */
+  (void) jpeg_read_header(&srcinfo, TRUE);
+
+  /* Adjust default decompression parameters */
+  if (scaleoption != NULL)
+    if (sscanf(scaleoption, "%u/%u",
+	&srcinfo.scale_num, &srcinfo.scale_denom) < 1)
+      usage();
+
+  /* Any space needed by a transform option must be requested before
+   * jpeg_read_coefficients so that memory allocation will be done right.
+   */
+#if TRANSFORMS_SUPPORTED
+  /* Fail right away if -perfect is given and transformation is not perfect.
+   */
+  if (!jtransform_request_workspace(&srcinfo, &transformoption)) {
+    fprintf(stderr, "%s: transformation is not perfect\n", progname);
+    exit(EXIT_FAILURE);
+  }
+#endif
+
+  /* Read source file as DCT coefficients */
+  src_coef_arrays = jpeg_read_coefficients(&srcinfo);
+
+  /* Initialize destination compression parameters from source values */
+  jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
+
+  /* Adjust destination parameters if required by transform options;
+   * also find out which set of coefficient arrays will hold the output.
+   */
+#if TRANSFORMS_SUPPORTED
+  dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo,
+						 src_coef_arrays,
+						 &transformoption);
+#else
+  dst_coef_arrays = src_coef_arrays;
+#endif
+
+  /* Close input file, if we opened it.
+   * Note: we assume that jpeg_read_coefficients consumed all input
+   * until JPEG_REACHED_EOI, and that jpeg_finish_decompress will
+   * only consume more while (! cinfo->inputctl->eoi_reached).
+   * We cannot call jpeg_finish_decompress here since we still need the
+   * virtual arrays allocated from the source object for processing.
+   */
+  if (fp != stdin)
+    fclose(fp);
+
+  /* Open the output file. */
+  if (outfilename != NULL) {
+    if ((fp = fopen(outfilename, WRITE_BINARY)) == NULL) {
+      fprintf(stderr, "%s: can't open %s for writing\n", progname, outfilename);
+      exit(EXIT_FAILURE);
+    }
+  } else {
+    /* default output file is stdout */
+    fp = write_stdout();
+  }
+
+  /* Adjust default compression parameters by re-parsing the options */
+  file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE);
+
+  /* Specify data destination for compression */
+  jpeg_stdio_dest(&dstinfo, fp);
+
+  /* Start compressor (note no image data is actually written here) */
+  jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
+
+  /* Copy to the output file any extra markers that we want to preserve */
+  jcopy_markers_execute(&srcinfo, &dstinfo, copyoption);
+
+  /* Execute image transformation, if any */
+#if TRANSFORMS_SUPPORTED
+  jtransform_execute_transformation(&srcinfo, &dstinfo,
+				    src_coef_arrays,
+				    &transformoption);
+#endif
+
+  /* Finish compression and release memory */
+  jpeg_finish_compress(&dstinfo);
+  jpeg_destroy_compress(&dstinfo);
+  (void) jpeg_finish_decompress(&srcinfo);
+  jpeg_destroy_decompress(&srcinfo);
+
+  /* Close output file, if we opened it */
+  if (fp != stdout)
+    fclose(fp);
+
+#ifdef PROGRESS_REPORT
+  end_progress_monitor((j_common_ptr) &dstinfo);
+#endif
+
+  /* All done. */
+  exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS);
+  return 0;			/* suppress no-return-value warnings */
+}
diff --git a/source/Irrlicht/jpeglib/jquant1.c b/source/Irrlicht/jpeglib/jquant1.c
new file mode 100644
index 00000000..1c482bc4
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jquant1.c
@@ -0,0 +1,857 @@
+/*
+ * jquant1.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * Modified 2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains 1-pass color quantization (color mapping) routines.
+ * These routines provide mapping to a fixed color map using equally spaced
+ * color values.  Optional Floyd-Steinberg or ordered dithering is available.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+#ifdef QUANT_1PASS_SUPPORTED
+
+
+/*
+ * The main purpose of 1-pass quantization is to provide a fast, if not very
+ * high quality, colormapped output capability.  A 2-pass quantizer usually
+ * gives better visual quality; however, for quantized grayscale output this
+ * quantizer is perfectly adequate.  Dithering is highly recommended with this
+ * quantizer, though you can turn it off if you really want to.
+ *
+ * In 1-pass quantization the colormap must be chosen in advance of seeing the
+ * image.  We use a map consisting of all combinations of Ncolors[i] color
+ * values for the i'th component.  The Ncolors[] values are chosen so that
+ * their product, the total number of colors, is no more than that requested.
+ * (In most cases, the product will be somewhat less.)
+ *
+ * Since the colormap is orthogonal, the representative value for each color
+ * component can be determined without considering the other components;
+ * then these indexes can be combined into a colormap index by a standard
+ * N-dimensional-array-subscript calculation.  Most of the arithmetic involved
+ * can be precalculated and stored in the lookup table colorindex[].
+ * colorindex[i][j] maps pixel value j in component i to the nearest
+ * representative value (grid plane) for that component; this index is
+ * multiplied by the array stride for component i, so that the
+ * index of the colormap entry closest to a given pixel value is just
+ *    sum( colorindex[component-number][pixel-component-value] )
+ * Aside from being fast, this scheme allows for variable spacing between
+ * representative values with no additional lookup cost.
+ *
+ * If gamma correction has been applied in color conversion, it might be wise
+ * to adjust the color grid spacing so that the representative colors are
+ * equidistant in linear space.  At this writing, gamma correction is not
+ * implemented by jdcolor, so nothing is done here.
+ */
+
+
+/* Declarations for ordered dithering.
+ *
+ * We use a standard 16x16 ordered dither array.  The basic concept of ordered
+ * dithering is described in many references, for instance Dale Schumacher's
+ * chapter II.2 of Graphics Gems II (James Arvo, ed. Academic Press, 1991).
+ * In place of Schumacher's comparisons against a "threshold" value, we add a
+ * "dither" value to the input pixel and then round the result to the nearest
+ * output value.  The dither value is equivalent to (0.5 - threshold) times
+ * the distance between output values.  For ordered dithering, we assume that
+ * the output colors are equally spaced; if not, results will probably be
+ * worse, since the dither may be too much or too little at a given point.
+ *
+ * The normal calculation would be to form pixel value + dither, range-limit
+ * this to 0..MAXJSAMPLE, and then index into the colorindex table as usual.
+ * We can skip the separate range-limiting step by extending the colorindex
+ * table in both directions.
+ */
+
+#define ODITHER_SIZE  16	/* dimension of dither matrix */
+/* NB: if ODITHER_SIZE is not a power of 2, ODITHER_MASK uses will break */
+#define ODITHER_CELLS (ODITHER_SIZE*ODITHER_SIZE)	/* # cells in matrix */
+#define ODITHER_MASK  (ODITHER_SIZE-1) /* mask for wrapping around counters */
+
+typedef int ODITHER_MATRIX[ODITHER_SIZE][ODITHER_SIZE];
+typedef int (*ODITHER_MATRIX_PTR)[ODITHER_SIZE];
+
+static const UINT8 base_dither_matrix[ODITHER_SIZE][ODITHER_SIZE] = {
+  /* Bayer's order-4 dither array.  Generated by the code given in
+   * Stephen Hawley's article "Ordered Dithering" in Graphics Gems I.
+   * The values in this array must range from 0 to ODITHER_CELLS-1.
+   */
+  {   0,192, 48,240, 12,204, 60,252,  3,195, 51,243, 15,207, 63,255 },
+  { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
+  {  32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
+  { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
+  {   8,200, 56,248,  4,196, 52,244, 11,203, 59,251,  7,199, 55,247 },
+  { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
+  {  40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
+  { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
+  {   2,194, 50,242, 14,206, 62,254,  1,193, 49,241, 13,205, 61,253 },
+  { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
+  {  34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
+  { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
+  {  10,202, 58,250,  6,198, 54,246,  9,201, 57,249,  5,197, 53,245 },
+  { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
+  {  42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
+  { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
+};
+
+
+/* Declarations for Floyd-Steinberg dithering.
+ *
+ * Errors are accumulated into the array fserrors[], at a resolution of
+ * 1/16th of a pixel count.  The error at a given pixel is propagated
+ * to its not-yet-processed neighbors using the standard F-S fractions,
+ *		...	(here)	7/16
+ *		3/16	5/16	1/16
+ * We work left-to-right on even rows, right-to-left on odd rows.
+ *
+ * We can get away with a single array (holding one row's worth of errors)
+ * by using it to store the current row's errors at pixel columns not yet
+ * processed, but the next row's errors at columns already processed.  We
+ * need only a few extra variables to hold the errors immediately around the
+ * current column.  (If we are lucky, those variables are in registers, but
+ * even if not, they're probably cheaper to access than array elements are.)
+ *
+ * The fserrors[] array is indexed [component#][position].
+ * We provide (#columns + 2) entries per component; the extra entry at each
+ * end saves us from special-casing the first and last pixels.
+ *
+ * Note: on a wide image, we might not have enough room in a PC's near data
+ * segment to hold the error array; so it is allocated with alloc_large.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+typedef INT16 FSERROR;		/* 16 bits should be enough */
+typedef int LOCFSERROR;		/* use 'int' for calculation temps */
+#else
+typedef INT32 FSERROR;		/* may need more than 16 bits */
+typedef INT32 LOCFSERROR;	/* be sure calculation temps are big enough */
+#endif
+
+typedef FSERROR FAR *FSERRPTR;	/* pointer to error array (in FAR storage!) */
+
+
+/* Private subobject */
+
+#define MAX_Q_COMPS 4		/* max components I can handle */
+
+typedef struct {
+  struct jpeg_color_quantizer pub; /* public fields */
+
+  /* Initially allocated colormap is saved here */
+  JSAMPARRAY sv_colormap;	/* The color map as a 2-D pixel array */
+  int sv_actual;		/* number of entries in use */
+
+  JSAMPARRAY colorindex;	/* Precomputed mapping for speed */
+  /* colorindex[i][j] = index of color closest to pixel value j in component i,
+   * premultiplied as described above.  Since colormap indexes must fit into
+   * JSAMPLEs, the entries of this array will too.
+   */
+  boolean is_padded;		/* is the colorindex padded for odither? */
+
+  int Ncolors[MAX_Q_COMPS];	/* # of values alloced to each component */
+
+  /* Variables for ordered dithering */
+  int row_index;		/* cur row's vertical index in dither matrix */
+  ODITHER_MATRIX_PTR odither[MAX_Q_COMPS]; /* one dither array per component */
+
+  /* Variables for Floyd-Steinberg dithering */
+  FSERRPTR fserrors[MAX_Q_COMPS]; /* accumulated errors */
+  boolean on_odd_row;		/* flag to remember which row we are on */
+} my_cquantizer;
+
+typedef my_cquantizer * my_cquantize_ptr;
+
+
+/*
+ * Policy-making subroutines for create_colormap and create_colorindex.
+ * These routines determine the colormap to be used.  The rest of the module
+ * only assumes that the colormap is orthogonal.
+ *
+ *  * select_ncolors decides how to divvy up the available colors
+ *    among the components.
+ *  * output_value defines the set of representative values for a component.
+ *  * largest_input_value defines the mapping from input values to
+ *    representative values for a component.
+ * Note that the latter two routines may impose different policies for
+ * different components, though this is not currently done.
+ */
+
+
+LOCAL(int)
+select_ncolors (j_decompress_ptr cinfo, int Ncolors[])
+/* Determine allocation of desired colors to components, */
+/* and fill in Ncolors[] array to indicate choice. */
+/* Return value is total number of colors (product of Ncolors[] values). */
+{
+  int nc = cinfo->out_color_components; /* number of color components */
+  int max_colors = cinfo->desired_number_of_colors;
+  int total_colors, iroot, i, j;
+  boolean changed;
+  long temp;
+  static const int RGB_order[3] = { RGB_GREEN, RGB_RED, RGB_BLUE };
+
+  /* We can allocate at least the nc'th root of max_colors per component. */
+  /* Compute floor(nc'th root of max_colors). */
+  iroot = 1;
+  do {
+    iroot++;
+    temp = iroot;		/* set temp = iroot ** nc */
+    for (i = 1; i < nc; i++)
+      temp *= iroot;
+  } while (temp <= (long) max_colors); /* repeat till iroot exceeds root */
+  iroot--;			/* now iroot = floor(root) */
+
+  /* Must have at least 2 color values per component */
+  if (iroot < 2)
+    ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, (int) temp);
+
+  /* Initialize to iroot color values for each component */
+  total_colors = 1;
+  for (i = 0; i < nc; i++) {
+    Ncolors[i] = iroot;
+    total_colors *= iroot;
+  }
+  /* We may be able to increment the count for one or more components without
+   * exceeding max_colors, though we know not all can be incremented.
+   * Sometimes, the first component can be incremented more than once!
+   * (Example: for 16 colors, we start at 2*2*2, go to 3*2*2, then 4*2*2.)
+   * In RGB colorspace, try to increment G first, then R, then B.
+   */
+  do {
+    changed = FALSE;
+    for (i = 0; i < nc; i++) {
+      j = (cinfo->out_color_space == JCS_RGB ? RGB_order[i] : i);
+      /* calculate new total_colors if Ncolors[j] is incremented */
+      temp = total_colors / Ncolors[j];
+      temp *= Ncolors[j]+1;	/* done in long arith to avoid oflo */
+      if (temp > (long) max_colors)
+	break;			/* won't fit, done with this pass */
+      Ncolors[j]++;		/* OK, apply the increment */
+      total_colors = (int) temp;
+      changed = TRUE;
+    }
+  } while (changed);
+
+  return total_colors;
+}
+
+
+LOCAL(int)
+output_value (j_decompress_ptr cinfo, int ci, int j, int maxj)
+/* Return j'th output value, where j will range from 0 to maxj */
+/* The output values must fall in 0..MAXJSAMPLE in increasing order */
+{
+  /* We always provide values 0 and MAXJSAMPLE for each component;
+   * any additional values are equally spaced between these limits.
+   * (Forcing the upper and lower values to the limits ensures that
+   * dithering can't produce a color outside the selected gamut.)
+   */
+  return (int) (((INT32) j * MAXJSAMPLE + maxj/2) / maxj);
+}
+
+
+LOCAL(int)
+largest_input_value (j_decompress_ptr cinfo, int ci, int j, int maxj)
+/* Return largest input value that should map to j'th output value */
+/* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */
+{
+  /* Breakpoints are halfway between values returned by output_value */
+  return (int) (((INT32) (2*j + 1) * MAXJSAMPLE + maxj) / (2*maxj));
+}
+
+
+/*
+ * Create the colormap.
+ */
+
+LOCAL(void)
+create_colormap (j_decompress_ptr cinfo)
+{
+  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+  JSAMPARRAY colormap;		/* Created colormap */
+  int total_colors;		/* Number of distinct output colors */
+  int i,j,k, nci, blksize, blkdist, ptr, val;
+
+  /* Select number of colors for each component */
+  total_colors = select_ncolors(cinfo, cquantize->Ncolors);
+
+  /* Report selected color counts */
+  if (cinfo->out_color_components == 3)
+    TRACEMS4(cinfo, 1, JTRC_QUANT_3_NCOLORS,
+	     total_colors, cquantize->Ncolors[0],
+	     cquantize->Ncolors[1], cquantize->Ncolors[2]);
+  else
+    TRACEMS1(cinfo, 1, JTRC_QUANT_NCOLORS, total_colors);
+
+  /* Allocate and fill in the colormap. */
+  /* The colors are ordered in the map in standard row-major order, */
+  /* i.e. rightmost (highest-indexed) color changes most rapidly. */
+
+  colormap = (*cinfo->mem->alloc_sarray)
+    ((j_common_ptr) cinfo, JPOOL_IMAGE,
+     (JDIMENSION) total_colors, (JDIMENSION) cinfo->out_color_components);
+
+  /* blksize is number of adjacent repeated entries for a component */
+  /* blkdist is distance between groups of identical entries for a component */
+  blkdist = total_colors;
+
+  for (i = 0; i < cinfo->out_color_components; i++) {
+    /* fill in colormap entries for i'th color component */
+    nci = cquantize->Ncolors[i]; /* # of distinct values for this color */
+    blksize = blkdist / nci;
+    for (j = 0; j < nci; j++) {
+      /* Compute j'th output value (out of nci) for component */
+      val = output_value(cinfo, i, j, nci-1);
+      /* Fill in all colormap entries that have this value of this component */
+      for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) {
+	/* fill in blksize entries beginning at ptr */
+	for (k = 0; k < blksize; k++)
+	  colormap[i][ptr+k] = (JSAMPLE) val;
+      }
+    }
+    blkdist = blksize;		/* blksize of this color is blkdist of next */
+  }
+
+  /* Save the colormap in private storage,
+   * where it will survive color quantization mode changes.
+   */
+  cquantize->sv_colormap = colormap;
+  cquantize->sv_actual = total_colors;
+}
+
+
+/*
+ * Create the color index table.
+ */
+
+LOCAL(void)
+create_colorindex (j_decompress_ptr cinfo)
+{
+  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+  JSAMPROW indexptr;
+  int i,j,k, nci, blksize, val, pad;
+
+  /* For ordered dither, we pad the color index tables by MAXJSAMPLE in
+   * each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE).
+   * This is not necessary in the other dithering modes.  However, we
+   * flag whether it was done in case user changes dithering mode.
+   */
+  if (cinfo->dither_mode == JDITHER_ORDERED) {
+    pad = MAXJSAMPLE*2;
+    cquantize->is_padded = TRUE;
+  } else {
+    pad = 0;
+    cquantize->is_padded = FALSE;
+  }
+
+  cquantize->colorindex = (*cinfo->mem->alloc_sarray)
+    ((j_common_ptr) cinfo, JPOOL_IMAGE,
+     (JDIMENSION) (MAXJSAMPLE+1 + pad),
+     (JDIMENSION) cinfo->out_color_components);
+
+  /* blksize is number of adjacent repeated entries for a component */
+  blksize = cquantize->sv_actual;
+
+  for (i = 0; i < cinfo->out_color_components; i++) {
+    /* fill in colorindex entries for i'th color component */
+    nci = cquantize->Ncolors[i]; /* # of distinct values for this color */
+    blksize = blksize / nci;
+
+    /* adjust colorindex pointers to provide padding at negative indexes. */
+    if (pad)
+      cquantize->colorindex[i] += MAXJSAMPLE;
+
+    /* in loop, val = index of current output value, */
+    /* and k = largest j that maps to current val */
+    indexptr = cquantize->colorindex[i];
+    val = 0;
+    k = largest_input_value(cinfo, i, 0, nci-1);
+    for (j = 0; j <= MAXJSAMPLE; j++) {
+      while (j > k)		/* advance val if past boundary */
+	k = largest_input_value(cinfo, i, ++val, nci-1);
+      /* premultiply so that no multiplication needed in main processing */
+      indexptr[j] = (JSAMPLE) (val * blksize);
+    }
+    /* Pad at both ends if necessary */
+    if (pad)
+      for (j = 1; j <= MAXJSAMPLE; j++) {
+	indexptr[-j] = indexptr[0];
+	indexptr[MAXJSAMPLE+j] = indexptr[MAXJSAMPLE];
+      }
+  }
+}
+
+
+/*
+ * Create an ordered-dither array for a component having ncolors
+ * distinct output values.
+ */
+
+LOCAL(ODITHER_MATRIX_PTR)
+make_odither_array (j_decompress_ptr cinfo, int ncolors)
+{
+  ODITHER_MATRIX_PTR odither;
+  int j,k;
+  INT32 num,den;
+
+  odither = (ODITHER_MATRIX_PTR)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(ODITHER_MATRIX));
+  /* The inter-value distance for this color is MAXJSAMPLE/(ncolors-1).
+   * Hence the dither value for the matrix cell with fill order f
+   * (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1).
+   * On 16-bit-int machine, be careful to avoid overflow.
+   */
+  den = 2 * ODITHER_CELLS * ((INT32) (ncolors - 1));
+  for (j = 0; j < ODITHER_SIZE; j++) {
+    for (k = 0; k < ODITHER_SIZE; k++) {
+      num = ((INT32) (ODITHER_CELLS-1 - 2*((int)base_dither_matrix[j][k])))
+	    * MAXJSAMPLE;
+      /* Ensure round towards zero despite C's lack of consistency
+       * about rounding negative values in integer division...
+       */
+      odither[j][k] = (int) (num<0 ? -((-num)/den) : num/den);
+    }
+  }
+  return odither;
+}
+
+
+/*
+ * Create the ordered-dither tables.
+ * Components having the same number of representative colors may 
+ * share a dither table.
+ */
+
+LOCAL(void)
+create_odither_tables (j_decompress_ptr cinfo)
+{
+  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+  ODITHER_MATRIX_PTR odither;
+  int i, j, nci;
+
+  for (i = 0; i < cinfo->out_color_components; i++) {
+    nci = cquantize->Ncolors[i]; /* # of distinct values for this color */
+    odither = NULL;		/* search for matching prior component */
+    for (j = 0; j < i; j++) {
+      if (nci == cquantize->Ncolors[j]) {
+	odither = cquantize->odither[j];
+	break;
+      }
+    }
+    if (odither == NULL)	/* need a new table? */
+      odither = make_odither_array(cinfo, nci);
+    cquantize->odither[i] = odither;
+  }
+}
+
+
+/*
+ * Map some rows of pixels to the output colormapped representation.
+ */
+
+METHODDEF(void)
+color_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+		JSAMPARRAY output_buf, int num_rows)
+/* General case, no dithering */
+{
+  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+  JSAMPARRAY colorindex = cquantize->colorindex;
+  register int pixcode, ci;
+  register JSAMPROW ptrin, ptrout;
+  int row;
+  JDIMENSION col;
+  JDIMENSION width = cinfo->output_width;
+  register int nc = cinfo->out_color_components;
+
+  for (row = 0; row < num_rows; row++) {
+    ptrin = input_buf[row];
+    ptrout = output_buf[row];
+    for (col = width; col > 0; col--) {
+      pixcode = 0;
+      for (ci = 0; ci < nc; ci++) {
+	pixcode += GETJSAMPLE(colorindex[ci][GETJSAMPLE(*ptrin++)]);
+      }
+      *ptrout++ = (JSAMPLE) pixcode;
+    }
+  }
+}
+
+
+METHODDEF(void)
+color_quantize3 (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+		 JSAMPARRAY output_buf, int num_rows)
+/* Fast path for out_color_components==3, no dithering */
+{
+  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+  register int pixcode;
+  register JSAMPROW ptrin, ptrout;
+  JSAMPROW colorindex0 = cquantize->colorindex[0];
+  JSAMPROW colorindex1 = cquantize->colorindex[1];
+  JSAMPROW colorindex2 = cquantize->colorindex[2];
+  int row;
+  JDIMENSION col;
+  JDIMENSION width = cinfo->output_width;
+
+  for (row = 0; row < num_rows; row++) {
+    ptrin = input_buf[row];
+    ptrout = output_buf[row];
+    for (col = width; col > 0; col--) {
+      pixcode  = GETJSAMPLE(colorindex0[GETJSAMPLE(*ptrin++)]);
+      pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*ptrin++)]);
+      pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*ptrin++)]);
+      *ptrout++ = (JSAMPLE) pixcode;
+    }
+  }
+}
+
+
+METHODDEF(void)
+quantize_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+		     JSAMPARRAY output_buf, int num_rows)
+/* General case, with ordered dithering */
+{
+  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+  register JSAMPROW input_ptr;
+  register JSAMPROW output_ptr;
+  JSAMPROW colorindex_ci;
+  int * dither;			/* points to active row of dither matrix */
+  int row_index, col_index;	/* current indexes into dither matrix */
+  int nc = cinfo->out_color_components;
+  int ci;
+  int row;
+  JDIMENSION col;
+  JDIMENSION width = cinfo->output_width;
+
+  for (row = 0; row < num_rows; row++) {
+    /* Initialize output values to 0 so can process components separately */
+    FMEMZERO((void FAR *) output_buf[row],
+	     (size_t) (width * SIZEOF(JSAMPLE)));
+    row_index = cquantize->row_index;
+    for (ci = 0; ci < nc; ci++) {
+      input_ptr = input_buf[row] + ci;
+      output_ptr = output_buf[row];
+      colorindex_ci = cquantize->colorindex[ci];
+      dither = cquantize->odither[ci][row_index];
+      col_index = 0;
+
+      for (col = width; col > 0; col--) {
+	/* Form pixel value + dither, range-limit to 0..MAXJSAMPLE,
+	 * select output value, accumulate into output code for this pixel.
+	 * Range-limiting need not be done explicitly, as we have extended
+	 * the colorindex table to produce the right answers for out-of-range
+	 * inputs.  The maximum dither is +- MAXJSAMPLE; this sets the
+	 * required amount of padding.
+	 */
+	*output_ptr += colorindex_ci[GETJSAMPLE(*input_ptr)+dither[col_index]];
+	input_ptr += nc;
+	output_ptr++;
+	col_index = (col_index + 1) & ODITHER_MASK;
+      }
+    }
+    /* Advance row index for next row */
+    row_index = (row_index + 1) & ODITHER_MASK;
+    cquantize->row_index = row_index;
+  }
+}
+
+
+METHODDEF(void)
+quantize3_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+		      JSAMPARRAY output_buf, int num_rows)
+/* Fast path for out_color_components==3, with ordered dithering */
+{
+  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+  register int pixcode;
+  register JSAMPROW input_ptr;
+  register JSAMPROW output_ptr;
+  JSAMPROW colorindex0 = cquantize->colorindex[0];
+  JSAMPROW colorindex1 = cquantize->colorindex[1];
+  JSAMPROW colorindex2 = cquantize->colorindex[2];
+  int * dither0;		/* points to active row of dither matrix */
+  int * dither1;
+  int * dither2;
+  int row_index, col_index;	/* current indexes into dither matrix */
+  int row;
+  JDIMENSION col;
+  JDIMENSION width = cinfo->output_width;
+
+  for (row = 0; row < num_rows; row++) {
+    row_index = cquantize->row_index;
+    input_ptr = input_buf[row];
+    output_ptr = output_buf[row];
+    dither0 = cquantize->odither[0][row_index];
+    dither1 = cquantize->odither[1][row_index];
+    dither2 = cquantize->odither[2][row_index];
+    col_index = 0;
+
+    for (col = width; col > 0; col--) {
+      pixcode  = GETJSAMPLE(colorindex0[GETJSAMPLE(*input_ptr++) +
+					dither0[col_index]]);
+      pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*input_ptr++) +
+					dither1[col_index]]);
+      pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*input_ptr++) +
+					dither2[col_index]]);
+      *output_ptr++ = (JSAMPLE) pixcode;
+      col_index = (col_index + 1) & ODITHER_MASK;
+    }
+    row_index = (row_index + 1) & ODITHER_MASK;
+    cquantize->row_index = row_index;
+  }
+}
+
+
+METHODDEF(void)
+quantize_fs_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+		    JSAMPARRAY output_buf, int num_rows)
+/* General case, with Floyd-Steinberg dithering */
+{
+  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+  register LOCFSERROR cur;	/* current error or pixel value */
+  LOCFSERROR belowerr;		/* error for pixel below cur */
+  LOCFSERROR bpreverr;		/* error for below/prev col */
+  LOCFSERROR bnexterr;		/* error for below/next col */
+  LOCFSERROR delta;
+  register FSERRPTR errorptr;	/* => fserrors[] at column before current */
+  register JSAMPROW input_ptr;
+  register JSAMPROW output_ptr;
+  JSAMPROW colorindex_ci;
+  JSAMPROW colormap_ci;
+  int pixcode;
+  int nc = cinfo->out_color_components;
+  int dir;			/* 1 for left-to-right, -1 for right-to-left */
+  int dirnc;			/* dir * nc */
+  int ci;
+  int row;
+  JDIMENSION col;
+  JDIMENSION width = cinfo->output_width;
+  JSAMPLE *range_limit = cinfo->sample_range_limit;
+  SHIFT_TEMPS
+
+  for (row = 0; row < num_rows; row++) {
+    /* Initialize output values to 0 so can process components separately */
+    FMEMZERO((void FAR *) output_buf[row],
+	     (size_t) (width * SIZEOF(JSAMPLE)));
+    for (ci = 0; ci < nc; ci++) {
+      input_ptr = input_buf[row] + ci;
+      output_ptr = output_buf[row];
+      if (cquantize->on_odd_row) {
+	/* work right to left in this row */
+	input_ptr += (width-1) * nc; /* so point to rightmost pixel */
+	output_ptr += width-1;
+	dir = -1;
+	dirnc = -nc;
+	errorptr = cquantize->fserrors[ci] + (width+1); /* => entry after last column */
+      } else {
+	/* work left to right in this row */
+	dir = 1;
+	dirnc = nc;
+	errorptr = cquantize->fserrors[ci]; /* => entry before first column */
+      }
+      colorindex_ci = cquantize->colorindex[ci];
+      colormap_ci = cquantize->sv_colormap[ci];
+      /* Preset error values: no error propagated to first pixel from left */
+      cur = 0;
+      /* and no error propagated to row below yet */
+      belowerr = bpreverr = 0;
+
+      for (col = width; col > 0; col--) {
+	/* cur holds the error propagated from the previous pixel on the
+	 * current line.  Add the error propagated from the previous line
+	 * to form the complete error correction term for this pixel, and
+	 * round the error term (which is expressed * 16) to an integer.
+	 * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
+	 * for either sign of the error value.
+	 * Note: errorptr points to *previous* column's array entry.
+	 */
+	cur = RIGHT_SHIFT(cur + errorptr[dir] + 8, 4);
+	/* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
+	 * The maximum error is +- MAXJSAMPLE; this sets the required size
+	 * of the range_limit array.
+	 */
+	cur += GETJSAMPLE(*input_ptr);
+	cur = GETJSAMPLE(range_limit[cur]);
+	/* Select output value, accumulate into output code for this pixel */
+	pixcode = GETJSAMPLE(colorindex_ci[cur]);
+	*output_ptr += (JSAMPLE) pixcode;
+	/* Compute actual representation error at this pixel */
+	/* Note: we can do this even though we don't have the final */
+	/* pixel code, because the colormap is orthogonal. */
+	cur -= GETJSAMPLE(colormap_ci[pixcode]);
+	/* Compute error fractions to be propagated to adjacent pixels.
+	 * Add these into the running sums, and simultaneously shift the
+	 * next-line error sums left by 1 column.
+	 */
+	bnexterr = cur;
+	delta = cur * 2;
+	cur += delta;		/* form error * 3 */
+	errorptr[0] = (FSERROR) (bpreverr + cur);
+	cur += delta;		/* form error * 5 */
+	bpreverr = belowerr + cur;
+	belowerr = bnexterr;
+	cur += delta;		/* form error * 7 */
+	/* At this point cur contains the 7/16 error value to be propagated
+	 * to the next pixel on the current line, and all the errors for the
+	 * next line have been shifted over. We are therefore ready to move on.
+	 */
+	input_ptr += dirnc;	/* advance input ptr to next column */
+	output_ptr += dir;	/* advance output ptr to next column */
+	errorptr += dir;	/* advance errorptr to current column */
+      }
+      /* Post-loop cleanup: we must unload the final error value into the
+       * final fserrors[] entry.  Note we need not unload belowerr because
+       * it is for the dummy column before or after the actual array.
+       */
+      errorptr[0] = (FSERROR) bpreverr; /* unload prev err into array */
+    }
+    cquantize->on_odd_row = (cquantize->on_odd_row ? FALSE : TRUE);
+  }
+}
+
+
+/*
+ * Allocate workspace for Floyd-Steinberg errors.
+ */
+
+LOCAL(void)
+alloc_fs_workspace (j_decompress_ptr cinfo)
+{
+  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+  size_t arraysize;
+  int i;
+
+  arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR));
+  for (i = 0; i < cinfo->out_color_components; i++) {
+    cquantize->fserrors[i] = (FSERRPTR)
+      (*cinfo->mem->alloc_large)((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize);
+  }
+}
+
+
+/*
+ * Initialize for one-pass color quantization.
+ */
+
+METHODDEF(void)
+start_pass_1_quant (j_decompress_ptr cinfo, boolean is_pre_scan)
+{
+  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+  size_t arraysize;
+  int i;
+
+  /* Install my colormap. */
+  cinfo->colormap = cquantize->sv_colormap;
+  cinfo->actual_number_of_colors = cquantize->sv_actual;
+
+  /* Initialize for desired dithering mode. */
+  switch (cinfo->dither_mode) {
+  case JDITHER_NONE:
+    if (cinfo->out_color_components == 3)
+      cquantize->pub.color_quantize = color_quantize3;
+    else
+      cquantize->pub.color_quantize = color_quantize;
+    break;
+  case JDITHER_ORDERED:
+    if (cinfo->out_color_components == 3)
+      cquantize->pub.color_quantize = quantize3_ord_dither;
+    else
+      cquantize->pub.color_quantize = quantize_ord_dither;
+    cquantize->row_index = 0;	/* initialize state for ordered dither */
+    /* If user changed to ordered dither from another mode,
+     * we must recreate the color index table with padding.
+     * This will cost extra space, but probably isn't very likely.
+     */
+    if (! cquantize->is_padded)
+      create_colorindex(cinfo);
+    /* Create ordered-dither tables if we didn't already. */
+    if (cquantize->odither[0] == NULL)
+      create_odither_tables(cinfo);
+    break;
+  case JDITHER_FS:
+    cquantize->pub.color_quantize = quantize_fs_dither;
+    cquantize->on_odd_row = FALSE; /* initialize state for F-S dither */
+    /* Allocate Floyd-Steinberg workspace if didn't already. */
+    if (cquantize->fserrors[0] == NULL)
+      alloc_fs_workspace(cinfo);
+    /* Initialize the propagated errors to zero. */
+    arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR));
+    for (i = 0; i < cinfo->out_color_components; i++)
+      FMEMZERO((void FAR *) cquantize->fserrors[i], arraysize);
+    break;
+  default:
+    ERREXIT(cinfo, JERR_NOT_COMPILED);
+    break;
+  }
+}
+
+
+/*
+ * Finish up at the end of the pass.
+ */
+
+METHODDEF(void)
+finish_pass_1_quant (j_decompress_ptr cinfo)
+{
+  /* no work in 1-pass case */
+}
+
+
+/*
+ * Switch to a new external colormap between output passes.
+ * Shouldn't get to this module!
+ */
+
+METHODDEF(void)
+new_color_map_1_quant (j_decompress_ptr cinfo)
+{
+  ERREXIT(cinfo, JERR_MODE_CHANGE);
+}
+
+
+/*
+ * Module initialization routine for 1-pass color quantization.
+ */
+
+GLOBAL(void)
+jinit_1pass_quantizer (j_decompress_ptr cinfo)
+{
+  my_cquantize_ptr cquantize;
+
+  cquantize = (my_cquantize_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(my_cquantizer));
+  cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize;
+  cquantize->pub.start_pass = start_pass_1_quant;
+  cquantize->pub.finish_pass = finish_pass_1_quant;
+  cquantize->pub.new_color_map = new_color_map_1_quant;
+  cquantize->fserrors[0] = NULL; /* Flag FS workspace not allocated */
+  cquantize->odither[0] = NULL;	/* Also flag odither arrays not allocated */
+
+  /* Make sure my internal arrays won't overflow */
+  if (cinfo->out_color_components > MAX_Q_COMPS)
+    ERREXIT1(cinfo, JERR_QUANT_COMPONENTS, MAX_Q_COMPS);
+  /* Make sure colormap indexes can be represented by JSAMPLEs */
+  if (cinfo->desired_number_of_colors > (MAXJSAMPLE+1))
+    ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXJSAMPLE+1);
+
+  /* Create the colormap and color index table. */
+  create_colormap(cinfo);
+  create_colorindex(cinfo);
+
+  /* Allocate Floyd-Steinberg workspace now if requested.
+   * We do this now since it is FAR storage and may affect the memory
+   * manager's space calculations.  If the user changes to FS dither
+   * mode in a later pass, we will allocate the space then, and will
+   * possibly overrun the max_memory_to_use setting.
+   */
+  if (cinfo->dither_mode == JDITHER_FS)
+    alloc_fs_workspace(cinfo);
+}
+
+#endif /* QUANT_1PASS_SUPPORTED */
diff --git a/source/Irrlicht/jpeglib/jquant2.c b/source/Irrlicht/jpeglib/jquant2.c
new file mode 100644
index 00000000..f7e351f2
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jquant2.c
@@ -0,0 +1,1311 @@
+/*
+ * jquant2.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * Modified 2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains 2-pass color quantization (color mapping) routines.
+ * These routines provide selection of a custom color map for an image,
+ * followed by mapping of the image to that color map, with optional
+ * Floyd-Steinberg dithering.
+ * It is also possible to use just the second pass to map to an arbitrary
+ * externally-given color map.
+ *
+ * Note: ordered dithering is not supported, since there isn't any fast
+ * way to compute intercolor distances; it's unclear that ordered dither's
+ * fundamental assumptions even hold with an irregularly spaced color map.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+#ifdef QUANT_2PASS_SUPPORTED
+
+
+/*
+ * This module implements the well-known Heckbert paradigm for color
+ * quantization.  Most of the ideas used here can be traced back to
+ * Heckbert's seminal paper
+ *   Heckbert, Paul.  "Color Image Quantization for Frame Buffer Display",
+ *   Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304.
+ *
+ * In the first pass over the image, we accumulate a histogram showing the
+ * usage count of each possible color.  To keep the histogram to a reasonable
+ * size, we reduce the precision of the input; typical practice is to retain
+ * 5 or 6 bits per color, so that 8 or 4 different input values are counted
+ * in the same histogram cell.
+ *
+ * Next, the color-selection step begins with a box representing the whole
+ * color space, and repeatedly splits the "largest" remaining box until we
+ * have as many boxes as desired colors.  Then the mean color in each
+ * remaining box becomes one of the possible output colors.
+ * 
+ * The second pass over the image maps each input pixel to the closest output
+ * color (optionally after applying a Floyd-Steinberg dithering correction).
+ * This mapping is logically trivial, but making it go fast enough requires
+ * considerable care.
+ *
+ * Heckbert-style quantizers vary a good deal in their policies for choosing
+ * the "largest" box and deciding where to cut it.  The particular policies
+ * used here have proved out well in experimental comparisons, but better ones
+ * may yet be found.
+ *
+ * In earlier versions of the IJG code, this module quantized in YCbCr color
+ * space, processing the raw upsampled data without a color conversion step.
+ * This allowed the color conversion math to be done only once per colormap
+ * entry, not once per pixel.  However, that optimization precluded other
+ * useful optimizations (such as merging color conversion with upsampling)
+ * and it also interfered with desired capabilities such as quantizing to an
+ * externally-supplied colormap.  We have therefore abandoned that approach.
+ * The present code works in the post-conversion color space, typically RGB.
+ *
+ * To improve the visual quality of the results, we actually work in scaled
+ * RGB space, giving G distances more weight than R, and R in turn more than
+ * B.  To do everything in integer math, we must use integer scale factors.
+ * The 2/3/1 scale factors used here correspond loosely to the relative
+ * weights of the colors in the NTSC grayscale equation.
+ * If you want to use this code to quantize a non-RGB color space, you'll
+ * probably need to change these scale factors.
+ */
+
+#define R_SCALE 2		/* scale R distances by this much */
+#define G_SCALE 3		/* scale G distances by this much */
+#define B_SCALE 1		/* and B by this much */
+
+/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined
+ * in jmorecfg.h.  As the code stands, it will do the right thing for R,G,B
+ * and B,G,R orders.  If you define some other weird order in jmorecfg.h,
+ * you'll get compile errors until you extend this logic.  In that case
+ * you'll probably want to tweak the histogram sizes too.
+ */
+
+#if RGB_RED == 0
+#define C0_SCALE R_SCALE
+#endif
+#if RGB_BLUE == 0
+#define C0_SCALE B_SCALE
+#endif
+#if RGB_GREEN == 1
+#define C1_SCALE G_SCALE
+#endif
+#if RGB_RED == 2
+#define C2_SCALE R_SCALE
+#endif
+#if RGB_BLUE == 2
+#define C2_SCALE B_SCALE
+#endif
+
+
+/*
+ * First we have the histogram data structure and routines for creating it.
+ *
+ * The number of bits of precision can be adjusted by changing these symbols.
+ * We recommend keeping 6 bits for G and 5 each for R and B.
+ * If you have plenty of memory and cycles, 6 bits all around gives marginally
+ * better results; if you are short of memory, 5 bits all around will save
+ * some space but degrade the results.
+ * To maintain a fully accurate histogram, we'd need to allocate a "long"
+ * (preferably unsigned long) for each cell.  In practice this is overkill;
+ * we can get by with 16 bits per cell.  Few of the cell counts will overflow,
+ * and clamping those that do overflow to the maximum value will give close-
+ * enough results.  This reduces the recommended histogram size from 256Kb
+ * to 128Kb, which is a useful savings on PC-class machines.
+ * (In the second pass the histogram space is re-used for pixel mapping data;
+ * in that capacity, each cell must be able to store zero to the number of
+ * desired colors.  16 bits/cell is plenty for that too.)
+ * Since the JPEG code is intended to run in small memory model on 80x86
+ * machines, we can't just allocate the histogram in one chunk.  Instead
+ * of a true 3-D array, we use a row of pointers to 2-D arrays.  Each
+ * pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and
+ * each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries.  Note that
+ * on 80x86 machines, the pointer row is in near memory but the actual
+ * arrays are in far memory (same arrangement as we use for image arrays).
+ */
+
+#define MAXNUMCOLORS  (MAXJSAMPLE+1) /* maximum size of colormap */
+
+/* These will do the right thing for either R,G,B or B,G,R color order,
+ * but you may not like the results for other color orders.
+ */
+#define HIST_C0_BITS  5		/* bits of precision in R/B histogram */
+#define HIST_C1_BITS  6		/* bits of precision in G histogram */
+#define HIST_C2_BITS  5		/* bits of precision in B/R histogram */
+
+/* Number of elements along histogram axes. */
+#define HIST_C0_ELEMS  (1<cquantize;
+  register JSAMPROW ptr;
+  register histptr histp;
+  register hist3d histogram = cquantize->histogram;
+  int row;
+  JDIMENSION col;
+  JDIMENSION width = cinfo->output_width;
+
+  for (row = 0; row < num_rows; row++) {
+    ptr = input_buf[row];
+    for (col = width; col > 0; col--) {
+      /* get pixel value and index into the histogram */
+      histp = & histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT]
+			 [GETJSAMPLE(ptr[1]) >> C1_SHIFT]
+			 [GETJSAMPLE(ptr[2]) >> C2_SHIFT];
+      /* increment, check for overflow and undo increment if so. */
+      if (++(*histp) <= 0)
+	(*histp)--;
+      ptr += 3;
+    }
+  }
+}
+
+
+/*
+ * Next we have the really interesting routines: selection of a colormap
+ * given the completed histogram.
+ * These routines work with a list of "boxes", each representing a rectangular
+ * subset of the input color space (to histogram precision).
+ */
+
+typedef struct {
+  /* The bounds of the box (inclusive); expressed as histogram indexes */
+  int c0min, c0max;
+  int c1min, c1max;
+  int c2min, c2max;
+  /* The volume (actually 2-norm) of the box */
+  INT32 volume;
+  /* The number of nonzero histogram cells within this box */
+  long colorcount;
+} box;
+
+typedef box * boxptr;
+
+
+LOCAL(boxptr)
+find_biggest_color_pop (boxptr boxlist, int numboxes)
+/* Find the splittable box with the largest color population */
+/* Returns NULL if no splittable boxes remain */
+{
+  register boxptr boxp;
+  register int i;
+  register long maxc = 0;
+  boxptr which = NULL;
+  
+  for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) {
+    if (boxp->colorcount > maxc && boxp->volume > 0) {
+      which = boxp;
+      maxc = boxp->colorcount;
+    }
+  }
+  return which;
+}
+
+
+LOCAL(boxptr)
+find_biggest_volume (boxptr boxlist, int numboxes)
+/* Find the splittable box with the largest (scaled) volume */
+/* Returns NULL if no splittable boxes remain */
+{
+  register boxptr boxp;
+  register int i;
+  register INT32 maxv = 0;
+  boxptr which = NULL;
+  
+  for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) {
+    if (boxp->volume > maxv) {
+      which = boxp;
+      maxv = boxp->volume;
+    }
+  }
+  return which;
+}
+
+
+LOCAL(void)
+update_box (j_decompress_ptr cinfo, boxptr boxp)
+/* Shrink the min/max bounds of a box to enclose only nonzero elements, */
+/* and recompute its volume and population */
+{
+  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+  hist3d histogram = cquantize->histogram;
+  histptr histp;
+  int c0,c1,c2;
+  int c0min,c0max,c1min,c1max,c2min,c2max;
+  INT32 dist0,dist1,dist2;
+  long ccount;
+  
+  c0min = boxp->c0min;  c0max = boxp->c0max;
+  c1min = boxp->c1min;  c1max = boxp->c1max;
+  c2min = boxp->c2min;  c2max = boxp->c2max;
+  
+  if (c0max > c0min)
+    for (c0 = c0min; c0 <= c0max; c0++)
+      for (c1 = c1min; c1 <= c1max; c1++) {
+	histp = & histogram[c0][c1][c2min];
+	for (c2 = c2min; c2 <= c2max; c2++)
+	  if (*histp++ != 0) {
+	    boxp->c0min = c0min = c0;
+	    goto have_c0min;
+	  }
+      }
+ have_c0min:
+  if (c0max > c0min)
+    for (c0 = c0max; c0 >= c0min; c0--)
+      for (c1 = c1min; c1 <= c1max; c1++) {
+	histp = & histogram[c0][c1][c2min];
+	for (c2 = c2min; c2 <= c2max; c2++)
+	  if (*histp++ != 0) {
+	    boxp->c0max = c0max = c0;
+	    goto have_c0max;
+	  }
+      }
+ have_c0max:
+  if (c1max > c1min)
+    for (c1 = c1min; c1 <= c1max; c1++)
+      for (c0 = c0min; c0 <= c0max; c0++) {
+	histp = & histogram[c0][c1][c2min];
+	for (c2 = c2min; c2 <= c2max; c2++)
+	  if (*histp++ != 0) {
+	    boxp->c1min = c1min = c1;
+	    goto have_c1min;
+	  }
+      }
+ have_c1min:
+  if (c1max > c1min)
+    for (c1 = c1max; c1 >= c1min; c1--)
+      for (c0 = c0min; c0 <= c0max; c0++) {
+	histp = & histogram[c0][c1][c2min];
+	for (c2 = c2min; c2 <= c2max; c2++)
+	  if (*histp++ != 0) {
+	    boxp->c1max = c1max = c1;
+	    goto have_c1max;
+	  }
+      }
+ have_c1max:
+  if (c2max > c2min)
+    for (c2 = c2min; c2 <= c2max; c2++)
+      for (c0 = c0min; c0 <= c0max; c0++) {
+	histp = & histogram[c0][c1min][c2];
+	for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS)
+	  if (*histp != 0) {
+	    boxp->c2min = c2min = c2;
+	    goto have_c2min;
+	  }
+      }
+ have_c2min:
+  if (c2max > c2min)
+    for (c2 = c2max; c2 >= c2min; c2--)
+      for (c0 = c0min; c0 <= c0max; c0++) {
+	histp = & histogram[c0][c1min][c2];
+	for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS)
+	  if (*histp != 0) {
+	    boxp->c2max = c2max = c2;
+	    goto have_c2max;
+	  }
+      }
+ have_c2max:
+
+  /* Update box volume.
+   * We use 2-norm rather than real volume here; this biases the method
+   * against making long narrow boxes, and it has the side benefit that
+   * a box is splittable iff norm > 0.
+   * Since the differences are expressed in histogram-cell units,
+   * we have to shift back to JSAMPLE units to get consistent distances;
+   * after which, we scale according to the selected distance scale factors.
+   */
+  dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE;
+  dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE;
+  dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE;
+  boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2;
+  
+  /* Now scan remaining volume of box and compute population */
+  ccount = 0;
+  for (c0 = c0min; c0 <= c0max; c0++)
+    for (c1 = c1min; c1 <= c1max; c1++) {
+      histp = & histogram[c0][c1][c2min];
+      for (c2 = c2min; c2 <= c2max; c2++, histp++)
+	if (*histp != 0) {
+	  ccount++;
+	}
+    }
+  boxp->colorcount = ccount;
+}
+
+
+LOCAL(int)
+median_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes,
+	    int desired_colors)
+/* Repeatedly select and split the largest box until we have enough boxes */
+{
+  int n,lb;
+  int c0,c1,c2,cmax;
+  register boxptr b1,b2;
+
+  while (numboxes < desired_colors) {
+    /* Select box to split.
+     * Current algorithm: by population for first half, then by volume.
+     */
+    if (numboxes*2 <= desired_colors) {
+      b1 = find_biggest_color_pop(boxlist, numboxes);
+    } else {
+      b1 = find_biggest_volume(boxlist, numboxes);
+    }
+    if (b1 == NULL)		/* no splittable boxes left! */
+      break;
+    b2 = &boxlist[numboxes];	/* where new box will go */
+    /* Copy the color bounds to the new box. */
+    b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max;
+    b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min;
+    /* Choose which axis to split the box on.
+     * Current algorithm: longest scaled axis.
+     * See notes in update_box about scaling distances.
+     */
+    c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE;
+    c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE;
+    c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE;
+    /* We want to break any ties in favor of green, then red, blue last.
+     * This code does the right thing for R,G,B or B,G,R color orders only.
+     */
+#if RGB_RED == 0
+    cmax = c1; n = 1;
+    if (c0 > cmax) { cmax = c0; n = 0; }
+    if (c2 > cmax) { n = 2; }
+#else
+    cmax = c1; n = 1;
+    if (c2 > cmax) { cmax = c2; n = 2; }
+    if (c0 > cmax) { n = 0; }
+#endif
+    /* Choose split point along selected axis, and update box bounds.
+     * Current algorithm: split at halfway point.
+     * (Since the box has been shrunk to minimum volume,
+     * any split will produce two nonempty subboxes.)
+     * Note that lb value is max for lower box, so must be < old max.
+     */
+    switch (n) {
+    case 0:
+      lb = (b1->c0max + b1->c0min) / 2;
+      b1->c0max = lb;
+      b2->c0min = lb+1;
+      break;
+    case 1:
+      lb = (b1->c1max + b1->c1min) / 2;
+      b1->c1max = lb;
+      b2->c1min = lb+1;
+      break;
+    case 2:
+      lb = (b1->c2max + b1->c2min) / 2;
+      b1->c2max = lb;
+      b2->c2min = lb+1;
+      break;
+    }
+    /* Update stats for boxes */
+    update_box(cinfo, b1);
+    update_box(cinfo, b2);
+    numboxes++;
+  }
+  return numboxes;
+}
+
+
+LOCAL(void)
+compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor)
+/* Compute representative color for a box, put it in colormap[icolor] */
+{
+  /* Current algorithm: mean weighted by pixels (not colors) */
+  /* Note it is important to get the rounding correct! */
+  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+  hist3d histogram = cquantize->histogram;
+  histptr histp;
+  int c0,c1,c2;
+  int c0min,c0max,c1min,c1max,c2min,c2max;
+  long count;
+  long total = 0;
+  long c0total = 0;
+  long c1total = 0;
+  long c2total = 0;
+  
+  c0min = boxp->c0min;  c0max = boxp->c0max;
+  c1min = boxp->c1min;  c1max = boxp->c1max;
+  c2min = boxp->c2min;  c2max = boxp->c2max;
+  
+  for (c0 = c0min; c0 <= c0max; c0++)
+    for (c1 = c1min; c1 <= c1max; c1++) {
+      histp = & histogram[c0][c1][c2min];
+      for (c2 = c2min; c2 <= c2max; c2++) {
+	if ((count = *histp++) != 0) {
+	  total += count;
+	  c0total += ((c0 << C0_SHIFT) + ((1<>1)) * count;
+	  c1total += ((c1 << C1_SHIFT) + ((1<>1)) * count;
+	  c2total += ((c2 << C2_SHIFT) + ((1<>1)) * count;
+	}
+      }
+    }
+  
+  cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total);
+  cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total);
+  cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total);
+}
+
+
+LOCAL(void)
+select_colors (j_decompress_ptr cinfo, int desired_colors)
+/* Master routine for color selection */
+{
+  boxptr boxlist;
+  int numboxes;
+  int i;
+
+  /* Allocate workspace for box list */
+  boxlist = (boxptr) (*cinfo->mem->alloc_small)
+    ((j_common_ptr) cinfo, JPOOL_IMAGE, desired_colors * SIZEOF(box));
+  /* Initialize one box containing whole space */
+  numboxes = 1;
+  boxlist[0].c0min = 0;
+  boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT;
+  boxlist[0].c1min = 0;
+  boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT;
+  boxlist[0].c2min = 0;
+  boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT;
+  /* Shrink it to actually-used volume and set its statistics */
+  update_box(cinfo, & boxlist[0]);
+  /* Perform median-cut to produce final box list */
+  numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors);
+  /* Compute the representative color for each box, fill colormap */
+  for (i = 0; i < numboxes; i++)
+    compute_color(cinfo, & boxlist[i], i);
+  cinfo->actual_number_of_colors = numboxes;
+  TRACEMS1(cinfo, 1, JTRC_QUANT_SELECTED, numboxes);
+}
+
+
+/*
+ * These routines are concerned with the time-critical task of mapping input
+ * colors to the nearest color in the selected colormap.
+ *
+ * We re-use the histogram space as an "inverse color map", essentially a
+ * cache for the results of nearest-color searches.  All colors within a
+ * histogram cell will be mapped to the same colormap entry, namely the one
+ * closest to the cell's center.  This may not be quite the closest entry to
+ * the actual input color, but it's almost as good.  A zero in the cache
+ * indicates we haven't found the nearest color for that cell yet; the array
+ * is cleared to zeroes before starting the mapping pass.  When we find the
+ * nearest color for a cell, its colormap index plus one is recorded in the
+ * cache for future use.  The pass2 scanning routines call fill_inverse_cmap
+ * when they need to use an unfilled entry in the cache.
+ *
+ * Our method of efficiently finding nearest colors is based on the "locally
+ * sorted search" idea described by Heckbert and on the incremental distance
+ * calculation described by Spencer W. Thomas in chapter III.1 of Graphics
+ * Gems II (James Arvo, ed.  Academic Press, 1991).  Thomas points out that
+ * the distances from a given colormap entry to each cell of the histogram can
+ * be computed quickly using an incremental method: the differences between
+ * distances to adjacent cells themselves differ by a constant.  This allows a
+ * fairly fast implementation of the "brute force" approach of computing the
+ * distance from every colormap entry to every histogram cell.  Unfortunately,
+ * it needs a work array to hold the best-distance-so-far for each histogram
+ * cell (because the inner loop has to be over cells, not colormap entries).
+ * The work array elements have to be INT32s, so the work array would need
+ * 256Kb at our recommended precision.  This is not feasible in DOS machines.
+ *
+ * To get around these problems, we apply Thomas' method to compute the
+ * nearest colors for only the cells within a small subbox of the histogram.
+ * The work array need be only as big as the subbox, so the memory usage
+ * problem is solved.  Furthermore, we need not fill subboxes that are never
+ * referenced in pass2; many images use only part of the color gamut, so a
+ * fair amount of work is saved.  An additional advantage of this
+ * approach is that we can apply Heckbert's locality criterion to quickly
+ * eliminate colormap entries that are far away from the subbox; typically
+ * three-fourths of the colormap entries are rejected by Heckbert's criterion,
+ * and we need not compute their distances to individual cells in the subbox.
+ * The speed of this approach is heavily influenced by the subbox size: too
+ * small means too much overhead, too big loses because Heckbert's criterion
+ * can't eliminate as many colormap entries.  Empirically the best subbox
+ * size seems to be about 1/512th of the histogram (1/8th in each direction).
+ *
+ * Thomas' article also describes a refined method which is asymptotically
+ * faster than the brute-force method, but it is also far more complex and
+ * cannot efficiently be applied to small subboxes.  It is therefore not
+ * useful for programs intended to be portable to DOS machines.  On machines
+ * with plenty of memory, filling the whole histogram in one shot with Thomas'
+ * refined method might be faster than the present code --- but then again,
+ * it might not be any faster, and it's certainly more complicated.
+ */
+
+
+/* log2(histogram cells in update box) for each axis; this can be adjusted */
+#define BOX_C0_LOG  (HIST_C0_BITS-3)
+#define BOX_C1_LOG  (HIST_C1_BITS-3)
+#define BOX_C2_LOG  (HIST_C2_BITS-3)
+
+#define BOX_C0_ELEMS  (1<actual_number_of_colors;
+  int maxc0, maxc1, maxc2;
+  int centerc0, centerc1, centerc2;
+  int i, x, ncolors;
+  INT32 minmaxdist, min_dist, max_dist, tdist;
+  INT32 mindist[MAXNUMCOLORS];	/* min distance to colormap entry i */
+
+  /* Compute true coordinates of update box's upper corner and center.
+   * Actually we compute the coordinates of the center of the upper-corner
+   * histogram cell, which are the upper bounds of the volume we care about.
+   * Note that since ">>" rounds down, the "center" values may be closer to
+   * min than to max; hence comparisons to them must be "<=", not "<".
+   */
+  maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT));
+  centerc0 = (minc0 + maxc0) >> 1;
+  maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT));
+  centerc1 = (minc1 + maxc1) >> 1;
+  maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT));
+  centerc2 = (minc2 + maxc2) >> 1;
+
+  /* For each color in colormap, find:
+   *  1. its minimum squared-distance to any point in the update box
+   *     (zero if color is within update box);
+   *  2. its maximum squared-distance to any point in the update box.
+   * Both of these can be found by considering only the corners of the box.
+   * We save the minimum distance for each color in mindist[];
+   * only the smallest maximum distance is of interest.
+   */
+  minmaxdist = 0x7FFFFFFFL;
+
+  for (i = 0; i < numcolors; i++) {
+    /* We compute the squared-c0-distance term, then add in the other two. */
+    x = GETJSAMPLE(cinfo->colormap[0][i]);
+    if (x < minc0) {
+      tdist = (x - minc0) * C0_SCALE;
+      min_dist = tdist*tdist;
+      tdist = (x - maxc0) * C0_SCALE;
+      max_dist = tdist*tdist;
+    } else if (x > maxc0) {
+      tdist = (x - maxc0) * C0_SCALE;
+      min_dist = tdist*tdist;
+      tdist = (x - minc0) * C0_SCALE;
+      max_dist = tdist*tdist;
+    } else {
+      /* within cell range so no contribution to min_dist */
+      min_dist = 0;
+      if (x <= centerc0) {
+	tdist = (x - maxc0) * C0_SCALE;
+	max_dist = tdist*tdist;
+      } else {
+	tdist = (x - minc0) * C0_SCALE;
+	max_dist = tdist*tdist;
+      }
+    }
+
+    x = GETJSAMPLE(cinfo->colormap[1][i]);
+    if (x < minc1) {
+      tdist = (x - minc1) * C1_SCALE;
+      min_dist += tdist*tdist;
+      tdist = (x - maxc1) * C1_SCALE;
+      max_dist += tdist*tdist;
+    } else if (x > maxc1) {
+      tdist = (x - maxc1) * C1_SCALE;
+      min_dist += tdist*tdist;
+      tdist = (x - minc1) * C1_SCALE;
+      max_dist += tdist*tdist;
+    } else {
+      /* within cell range so no contribution to min_dist */
+      if (x <= centerc1) {
+	tdist = (x - maxc1) * C1_SCALE;
+	max_dist += tdist*tdist;
+      } else {
+	tdist = (x - minc1) * C1_SCALE;
+	max_dist += tdist*tdist;
+      }
+    }
+
+    x = GETJSAMPLE(cinfo->colormap[2][i]);
+    if (x < minc2) {
+      tdist = (x - minc2) * C2_SCALE;
+      min_dist += tdist*tdist;
+      tdist = (x - maxc2) * C2_SCALE;
+      max_dist += tdist*tdist;
+    } else if (x > maxc2) {
+      tdist = (x - maxc2) * C2_SCALE;
+      min_dist += tdist*tdist;
+      tdist = (x - minc2) * C2_SCALE;
+      max_dist += tdist*tdist;
+    } else {
+      /* within cell range so no contribution to min_dist */
+      if (x <= centerc2) {
+	tdist = (x - maxc2) * C2_SCALE;
+	max_dist += tdist*tdist;
+      } else {
+	tdist = (x - minc2) * C2_SCALE;
+	max_dist += tdist*tdist;
+      }
+    }
+
+    mindist[i] = min_dist;	/* save away the results */
+    if (max_dist < minmaxdist)
+      minmaxdist = max_dist;
+  }
+
+  /* Now we know that no cell in the update box is more than minmaxdist
+   * away from some colormap entry.  Therefore, only colors that are
+   * within minmaxdist of some part of the box need be considered.
+   */
+  ncolors = 0;
+  for (i = 0; i < numcolors; i++) {
+    if (mindist[i] <= minmaxdist)
+      colorlist[ncolors++] = (JSAMPLE) i;
+  }
+  return ncolors;
+}
+
+
+LOCAL(void)
+find_best_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
+		  int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[])
+/* Find the closest colormap entry for each cell in the update box,
+ * given the list of candidate colors prepared by find_nearby_colors.
+ * Return the indexes of the closest entries in the bestcolor[] array.
+ * This routine uses Thomas' incremental distance calculation method to
+ * find the distance from a colormap entry to successive cells in the box.
+ */
+{
+  int ic0, ic1, ic2;
+  int i, icolor;
+  register INT32 * bptr;	/* pointer into bestdist[] array */
+  JSAMPLE * cptr;		/* pointer into bestcolor[] array */
+  INT32 dist0, dist1;		/* initial distance values */
+  register INT32 dist2;		/* current distance in inner loop */
+  INT32 xx0, xx1;		/* distance increments */
+  register INT32 xx2;
+  INT32 inc0, inc1, inc2;	/* initial values for increments */
+  /* This array holds the distance to the nearest-so-far color for each cell */
+  INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS];
+
+  /* Initialize best-distance for each cell of the update box */
+  bptr = bestdist;
+  for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--)
+    *bptr++ = 0x7FFFFFFFL;
+  
+  /* For each color selected by find_nearby_colors,
+   * compute its distance to the center of each cell in the box.
+   * If that's less than best-so-far, update best distance and color number.
+   */
+  
+  /* Nominal steps between cell centers ("x" in Thomas article) */
+#define STEP_C0  ((1 << C0_SHIFT) * C0_SCALE)
+#define STEP_C1  ((1 << C1_SHIFT) * C1_SCALE)
+#define STEP_C2  ((1 << C2_SHIFT) * C2_SCALE)
+  
+  for (i = 0; i < numcolors; i++) {
+    icolor = GETJSAMPLE(colorlist[i]);
+    /* Compute (square of) distance from minc0/c1/c2 to this color */
+    inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE;
+    dist0 = inc0*inc0;
+    inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE;
+    dist0 += inc1*inc1;
+    inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE;
+    dist0 += inc2*inc2;
+    /* Form the initial difference increments */
+    inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0;
+    inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1;
+    inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2;
+    /* Now loop over all cells in box, updating distance per Thomas method */
+    bptr = bestdist;
+    cptr = bestcolor;
+    xx0 = inc0;
+    for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) {
+      dist1 = dist0;
+      xx1 = inc1;
+      for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) {
+	dist2 = dist1;
+	xx2 = inc2;
+	for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) {
+	  if (dist2 < *bptr) {
+	    *bptr = dist2;
+	    *cptr = (JSAMPLE) icolor;
+	  }
+	  dist2 += xx2;
+	  xx2 += 2 * STEP_C2 * STEP_C2;
+	  bptr++;
+	  cptr++;
+	}
+	dist1 += xx1;
+	xx1 += 2 * STEP_C1 * STEP_C1;
+      }
+      dist0 += xx0;
+      xx0 += 2 * STEP_C0 * STEP_C0;
+    }
+  }
+}
+
+
+LOCAL(void)
+fill_inverse_cmap (j_decompress_ptr cinfo, int c0, int c1, int c2)
+/* Fill the inverse-colormap entries in the update box that contains */
+/* histogram cell c0/c1/c2.  (Only that one cell MUST be filled, but */
+/* we can fill as many others as we wish.) */
+{
+  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+  hist3d histogram = cquantize->histogram;
+  int minc0, minc1, minc2;	/* lower left corner of update box */
+  int ic0, ic1, ic2;
+  register JSAMPLE * cptr;	/* pointer into bestcolor[] array */
+  register histptr cachep;	/* pointer into main cache array */
+  /* This array lists the candidate colormap indexes. */
+  JSAMPLE colorlist[MAXNUMCOLORS];
+  int numcolors;		/* number of candidate colors */
+  /* This array holds the actually closest colormap index for each cell. */
+  JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS];
+
+  /* Convert cell coordinates to update box ID */
+  c0 >>= BOX_C0_LOG;
+  c1 >>= BOX_C1_LOG;
+  c2 >>= BOX_C2_LOG;
+
+  /* Compute true coordinates of update box's origin corner.
+   * Actually we compute the coordinates of the center of the corner
+   * histogram cell, which are the lower bounds of the volume we care about.
+   */
+  minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1);
+  minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1);
+  minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1);
+  
+  /* Determine which colormap entries are close enough to be candidates
+   * for the nearest entry to some cell in the update box.
+   */
+  numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist);
+
+  /* Determine the actually nearest colors. */
+  find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist,
+		   bestcolor);
+
+  /* Save the best color numbers (plus 1) in the main cache array */
+  c0 <<= BOX_C0_LOG;		/* convert ID back to base cell indexes */
+  c1 <<= BOX_C1_LOG;
+  c2 <<= BOX_C2_LOG;
+  cptr = bestcolor;
+  for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) {
+    for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) {
+      cachep = & histogram[c0+ic0][c1+ic1][c2];
+      for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) {
+	*cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1);
+      }
+    }
+  }
+}
+
+
+/*
+ * Map some rows of pixels to the output colormapped representation.
+ */
+
+METHODDEF(void)
+pass2_no_dither (j_decompress_ptr cinfo,
+		 JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows)
+/* This version performs no dithering */
+{
+  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+  hist3d histogram = cquantize->histogram;
+  register JSAMPROW inptr, outptr;
+  register histptr cachep;
+  register int c0, c1, c2;
+  int row;
+  JDIMENSION col;
+  JDIMENSION width = cinfo->output_width;
+
+  for (row = 0; row < num_rows; row++) {
+    inptr = input_buf[row];
+    outptr = output_buf[row];
+    for (col = width; col > 0; col--) {
+      /* get pixel value and index into the cache */
+      c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT;
+      c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT;
+      c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT;
+      cachep = & histogram[c0][c1][c2];
+      /* If we have not seen this color before, find nearest colormap entry */
+      /* and update the cache */
+      if (*cachep == 0)
+	fill_inverse_cmap(cinfo, c0,c1,c2);
+      /* Now emit the colormap index for this cell */
+      *outptr++ = (JSAMPLE) (*cachep - 1);
+    }
+  }
+}
+
+
+METHODDEF(void)
+pass2_fs_dither (j_decompress_ptr cinfo,
+		 JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows)
+/* This version performs Floyd-Steinberg dithering */
+{
+  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+  hist3d histogram = cquantize->histogram;
+  register LOCFSERROR cur0, cur1, cur2;	/* current error or pixel value */
+  LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */
+  LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */
+  register FSERRPTR errorptr;	/* => fserrors[] at column before current */
+  JSAMPROW inptr;		/* => current input pixel */
+  JSAMPROW outptr;		/* => current output pixel */
+  histptr cachep;
+  int dir;			/* +1 or -1 depending on direction */
+  int dir3;			/* 3*dir, for advancing inptr & errorptr */
+  int row;
+  JDIMENSION col;
+  JDIMENSION width = cinfo->output_width;
+  JSAMPLE *range_limit = cinfo->sample_range_limit;
+  int *error_limit = cquantize->error_limiter;
+  JSAMPROW colormap0 = cinfo->colormap[0];
+  JSAMPROW colormap1 = cinfo->colormap[1];
+  JSAMPROW colormap2 = cinfo->colormap[2];
+  SHIFT_TEMPS
+
+  for (row = 0; row < num_rows; row++) {
+    inptr = input_buf[row];
+    outptr = output_buf[row];
+    if (cquantize->on_odd_row) {
+      /* work right to left in this row */
+      inptr += (width-1) * 3;	/* so point to rightmost pixel */
+      outptr += width-1;
+      dir = -1;
+      dir3 = -3;
+      errorptr = cquantize->fserrors + (width+1)*3; /* => entry after last column */
+      cquantize->on_odd_row = FALSE; /* flip for next time */
+    } else {
+      /* work left to right in this row */
+      dir = 1;
+      dir3 = 3;
+      errorptr = cquantize->fserrors; /* => entry before first real column */
+      cquantize->on_odd_row = TRUE; /* flip for next time */
+    }
+    /* Preset error values: no error propagated to first pixel from left */
+    cur0 = cur1 = cur2 = 0;
+    /* and no error propagated to row below yet */
+    belowerr0 = belowerr1 = belowerr2 = 0;
+    bpreverr0 = bpreverr1 = bpreverr2 = 0;
+
+    for (col = width; col > 0; col--) {
+      /* curN holds the error propagated from the previous pixel on the
+       * current line.  Add the error propagated from the previous line
+       * to form the complete error correction term for this pixel, and
+       * round the error term (which is expressed * 16) to an integer.
+       * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
+       * for either sign of the error value.
+       * Note: errorptr points to *previous* column's array entry.
+       */
+      cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4);
+      cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4);
+      cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4);
+      /* Limit the error using transfer function set by init_error_limit.
+       * See comments with init_error_limit for rationale.
+       */
+      cur0 = error_limit[cur0];
+      cur1 = error_limit[cur1];
+      cur2 = error_limit[cur2];
+      /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
+       * The maximum error is +- MAXJSAMPLE (or less with error limiting);
+       * this sets the required size of the range_limit array.
+       */
+      cur0 += GETJSAMPLE(inptr[0]);
+      cur1 += GETJSAMPLE(inptr[1]);
+      cur2 += GETJSAMPLE(inptr[2]);
+      cur0 = GETJSAMPLE(range_limit[cur0]);
+      cur1 = GETJSAMPLE(range_limit[cur1]);
+      cur2 = GETJSAMPLE(range_limit[cur2]);
+      /* Index into the cache with adjusted pixel value */
+      cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT];
+      /* If we have not seen this color before, find nearest colormap */
+      /* entry and update the cache */
+      if (*cachep == 0)
+	fill_inverse_cmap(cinfo, cur0>>C0_SHIFT,cur1>>C1_SHIFT,cur2>>C2_SHIFT);
+      /* Now emit the colormap index for this cell */
+      { register int pixcode = *cachep - 1;
+	*outptr = (JSAMPLE) pixcode;
+	/* Compute representation error for this pixel */
+	cur0 -= GETJSAMPLE(colormap0[pixcode]);
+	cur1 -= GETJSAMPLE(colormap1[pixcode]);
+	cur2 -= GETJSAMPLE(colormap2[pixcode]);
+      }
+      /* Compute error fractions to be propagated to adjacent pixels.
+       * Add these into the running sums, and simultaneously shift the
+       * next-line error sums left by 1 column.
+       */
+      { register LOCFSERROR bnexterr, delta;
+
+	bnexterr = cur0;	/* Process component 0 */
+	delta = cur0 * 2;
+	cur0 += delta;		/* form error * 3 */
+	errorptr[0] = (FSERROR) (bpreverr0 + cur0);
+	cur0 += delta;		/* form error * 5 */
+	bpreverr0 = belowerr0 + cur0;
+	belowerr0 = bnexterr;
+	cur0 += delta;		/* form error * 7 */
+	bnexterr = cur1;	/* Process component 1 */
+	delta = cur1 * 2;
+	cur1 += delta;		/* form error * 3 */
+	errorptr[1] = (FSERROR) (bpreverr1 + cur1);
+	cur1 += delta;		/* form error * 5 */
+	bpreverr1 = belowerr1 + cur1;
+	belowerr1 = bnexterr;
+	cur1 += delta;		/* form error * 7 */
+	bnexterr = cur2;	/* Process component 2 */
+	delta = cur2 * 2;
+	cur2 += delta;		/* form error * 3 */
+	errorptr[2] = (FSERROR) (bpreverr2 + cur2);
+	cur2 += delta;		/* form error * 5 */
+	bpreverr2 = belowerr2 + cur2;
+	belowerr2 = bnexterr;
+	cur2 += delta;		/* form error * 7 */
+      }
+      /* At this point curN contains the 7/16 error value to be propagated
+       * to the next pixel on the current line, and all the errors for the
+       * next line have been shifted over.  We are therefore ready to move on.
+       */
+      inptr += dir3;		/* Advance pixel pointers to next column */
+      outptr += dir;
+      errorptr += dir3;		/* advance errorptr to current column */
+    }
+    /* Post-loop cleanup: we must unload the final error values into the
+     * final fserrors[] entry.  Note we need not unload belowerrN because
+     * it is for the dummy column before or after the actual array.
+     */
+    errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */
+    errorptr[1] = (FSERROR) bpreverr1;
+    errorptr[2] = (FSERROR) bpreverr2;
+  }
+}
+
+
+/*
+ * Initialize the error-limiting transfer function (lookup table).
+ * The raw F-S error computation can potentially compute error values of up to
+ * +- MAXJSAMPLE.  But we want the maximum correction applied to a pixel to be
+ * much less, otherwise obviously wrong pixels will be created.  (Typical
+ * effects include weird fringes at color-area boundaries, isolated bright
+ * pixels in a dark area, etc.)  The standard advice for avoiding this problem
+ * is to ensure that the "corners" of the color cube are allocated as output
+ * colors; then repeated errors in the same direction cannot cause cascading
+ * error buildup.  However, that only prevents the error from getting
+ * completely out of hand; Aaron Giles reports that error limiting improves
+ * the results even with corner colors allocated.
+ * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty
+ * well, but the smoother transfer function used below is even better.  Thanks
+ * to Aaron Giles for this idea.
+ */
+
+LOCAL(void)
+init_error_limit (j_decompress_ptr cinfo)
+/* Allocate and fill in the error_limiter table */
+{
+  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+  int * table;
+  int in, out;
+
+  table = (int *) (*cinfo->mem->alloc_small)
+    ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE*2+1) * SIZEOF(int));
+  table += MAXJSAMPLE;		/* so can index -MAXJSAMPLE .. +MAXJSAMPLE */
+  cquantize->error_limiter = table;
+
+#define STEPSIZE ((MAXJSAMPLE+1)/16)
+  /* Map errors 1:1 up to +- MAXJSAMPLE/16 */
+  out = 0;
+  for (in = 0; in < STEPSIZE; in++, out++) {
+    table[in] = out; table[-in] = -out;
+  }
+  /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */
+  for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) {
+    table[in] = out; table[-in] = -out;
+  }
+  /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */
+  for (; in <= MAXJSAMPLE; in++) {
+    table[in] = out; table[-in] = -out;
+  }
+#undef STEPSIZE
+}
+
+
+/*
+ * Finish up at the end of each pass.
+ */
+
+METHODDEF(void)
+finish_pass1 (j_decompress_ptr cinfo)
+{
+  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+
+  /* Select the representative colors and fill in cinfo->colormap */
+  cinfo->colormap = cquantize->sv_colormap;
+  select_colors(cinfo, cquantize->desired);
+  /* Force next pass to zero the color index table */
+  cquantize->needs_zeroed = TRUE;
+}
+
+
+METHODDEF(void)
+finish_pass2 (j_decompress_ptr cinfo)
+{
+  /* no work */
+}
+
+
+/*
+ * Initialize for each processing pass.
+ */
+
+METHODDEF(void)
+start_pass_2_quant (j_decompress_ptr cinfo, boolean is_pre_scan)
+{
+  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+  hist3d histogram = cquantize->histogram;
+  int i;
+
+  /* Only F-S dithering or no dithering is supported. */
+  /* If user asks for ordered dither, give him F-S. */
+  if (cinfo->dither_mode != JDITHER_NONE)
+    cinfo->dither_mode = JDITHER_FS;
+
+  if (is_pre_scan) {
+    /* Set up method pointers */
+    cquantize->pub.color_quantize = prescan_quantize;
+    cquantize->pub.finish_pass = finish_pass1;
+    cquantize->needs_zeroed = TRUE; /* Always zero histogram */
+  } else {
+    /* Set up method pointers */
+    if (cinfo->dither_mode == JDITHER_FS)
+      cquantize->pub.color_quantize = pass2_fs_dither;
+    else
+      cquantize->pub.color_quantize = pass2_no_dither;
+    cquantize->pub.finish_pass = finish_pass2;
+
+    /* Make sure color count is acceptable */
+    i = cinfo->actual_number_of_colors;
+    if (i < 1)
+      ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 1);
+    if (i > MAXNUMCOLORS)
+      ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS);
+
+    if (cinfo->dither_mode == JDITHER_FS) {
+      size_t arraysize = (size_t) ((cinfo->output_width + 2) *
+				   (3 * SIZEOF(FSERROR)));
+      /* Allocate Floyd-Steinberg workspace if we didn't already. */
+      if (cquantize->fserrors == NULL)
+	cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large)
+	  ((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize);
+      /* Initialize the propagated errors to zero. */
+      FMEMZERO((void FAR *) cquantize->fserrors, arraysize);
+      /* Make the error-limit table if we didn't already. */
+      if (cquantize->error_limiter == NULL)
+	init_error_limit(cinfo);
+      cquantize->on_odd_row = FALSE;
+    }
+
+  }
+  /* Zero the histogram or inverse color map, if necessary */
+  if (cquantize->needs_zeroed) {
+    for (i = 0; i < HIST_C0_ELEMS; i++) {
+      FMEMZERO((void FAR *) histogram[i],
+	       HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell));
+    }
+    cquantize->needs_zeroed = FALSE;
+  }
+}
+
+
+/*
+ * Switch to a new external colormap between output passes.
+ */
+
+METHODDEF(void)
+new_color_map_2_quant (j_decompress_ptr cinfo)
+{
+  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+
+  /* Reset the inverse color map */
+  cquantize->needs_zeroed = TRUE;
+}
+
+
+/*
+ * Module initialization routine for 2-pass color quantization.
+ */
+
+GLOBAL(void)
+jinit_2pass_quantizer (j_decompress_ptr cinfo)
+{
+  my_cquantize_ptr cquantize;
+  int i;
+
+  cquantize = (my_cquantize_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(my_cquantizer));
+  cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize;
+  cquantize->pub.start_pass = start_pass_2_quant;
+  cquantize->pub.new_color_map = new_color_map_2_quant;
+  cquantize->fserrors = NULL;	/* flag optional arrays not allocated */
+  cquantize->error_limiter = NULL;
+
+  /* Make sure jdmaster didn't give me a case I can't handle */
+  if (cinfo->out_color_components != 3)
+    ERREXIT(cinfo, JERR_NOTIMPL);
+
+  /* Allocate the histogram/inverse colormap storage */
+  cquantize->histogram = (hist3d) (*cinfo->mem->alloc_small)
+    ((j_common_ptr) cinfo, JPOOL_IMAGE, HIST_C0_ELEMS * SIZEOF(hist2d));
+  for (i = 0; i < HIST_C0_ELEMS; i++) {
+    cquantize->histogram[i] = (hist2d) (*cinfo->mem->alloc_large)
+      ((j_common_ptr) cinfo, JPOOL_IMAGE,
+       HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell));
+  }
+  cquantize->needs_zeroed = TRUE; /* histogram is garbage now */
+
+  /* Allocate storage for the completed colormap, if required.
+   * We do this now since it is FAR storage and may affect
+   * the memory manager's space calculations.
+   */
+  if (cinfo->enable_2pass_quant) {
+    /* Make sure color count is acceptable */
+    int desired = cinfo->desired_number_of_colors;
+    /* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */
+    if (desired < 8)
+      ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 8);
+    /* Make sure colormap indexes can be represented by JSAMPLEs */
+    if (desired > MAXNUMCOLORS)
+      ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS);
+    cquantize->sv_colormap = (*cinfo->mem->alloc_sarray)
+      ((j_common_ptr) cinfo,JPOOL_IMAGE, (JDIMENSION) desired, (JDIMENSION) 3);
+    cquantize->desired = desired;
+  } else
+    cquantize->sv_colormap = NULL;
+
+  /* Only F-S dithering or no dithering is supported. */
+  /* If user asks for ordered dither, give him F-S. */
+  if (cinfo->dither_mode != JDITHER_NONE)
+    cinfo->dither_mode = JDITHER_FS;
+
+  /* Allocate Floyd-Steinberg workspace if necessary.
+   * This isn't really needed until pass 2, but again it is FAR storage.
+   * Although we will cope with a later change in dither_mode,
+   * we do not promise to honor max_memory_to_use if dither_mode changes.
+   */
+  if (cinfo->dither_mode == JDITHER_FS) {
+    cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large)
+      ((j_common_ptr) cinfo, JPOOL_IMAGE,
+       (size_t) ((cinfo->output_width + 2) * (3 * SIZEOF(FSERROR))));
+    /* Might as well create the error-limiting table too. */
+    init_error_limit(cinfo);
+  }
+}
+
+#endif /* QUANT_2PASS_SUPPORTED */
diff --git a/source/Irrlicht/jpeglib/jutils.c b/source/Irrlicht/jpeglib/jutils.c
new file mode 100644
index 00000000..037a7952
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jutils.c
@@ -0,0 +1,227 @@
+/*
+ * jutils.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * Modified 2009-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains tables and miscellaneous utility routines needed
+ * for both compression and decompression.
+ * Note we prefix all global names with "j" to minimize conflicts with
+ * a surrounding application.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * jpeg_zigzag_order[i] is the zigzag-order position of the i'th element
+ * of a DCT block read in natural order (left to right, top to bottom).
+ */
+
+#if 0				/* This table is not actually needed in v6a */
+
+const int jpeg_zigzag_order[DCTSIZE2] = {
+   0,  1,  5,  6, 14, 15, 27, 28,
+   2,  4,  7, 13, 16, 26, 29, 42,
+   3,  8, 12, 17, 25, 30, 41, 43,
+   9, 11, 18, 24, 31, 40, 44, 53,
+  10, 19, 23, 32, 39, 45, 52, 54,
+  20, 22, 33, 38, 46, 51, 55, 60,
+  21, 34, 37, 47, 50, 56, 59, 61,
+  35, 36, 48, 49, 57, 58, 62, 63
+};
+
+#endif
+
+/*
+ * jpeg_natural_order[i] is the natural-order position of the i'th element
+ * of zigzag order.
+ *
+ * When reading corrupted data, the Huffman decoders could attempt
+ * to reference an entry beyond the end of this array (if the decoded
+ * zero run length reaches past the end of the block).  To prevent
+ * wild stores without adding an inner-loop test, we put some extra
+ * "63"s after the real entries.  This will cause the extra coefficient
+ * to be stored in location 63 of the block, not somewhere random.
+ * The worst case would be a run-length of 15, which means we need 16
+ * fake entries.
+ */
+
+const int jpeg_natural_order[DCTSIZE2+16] = {
+  0,  1,  8, 16,  9,  2,  3, 10,
+ 17, 24, 32, 25, 18, 11,  4,  5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13,  6,  7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+const int jpeg_natural_order7[7*7+16] = {
+  0,  1,  8, 16,  9,  2,  3, 10,
+ 17, 24, 32, 25, 18, 11,  4,  5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13,  6, 14, 21, 28, 35,
+ 42, 49, 50, 43, 36, 29, 22, 30,
+ 37, 44, 51, 52, 45, 38, 46, 53,
+ 54,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+const int jpeg_natural_order6[6*6+16] = {
+  0,  1,  8, 16,  9,  2,  3, 10,
+ 17, 24, 32, 25, 18, 11,  4,  5,
+ 12, 19, 26, 33, 40, 41, 34, 27,
+ 20, 13, 21, 28, 35, 42, 43, 36,
+ 29, 37, 44, 45,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+const int jpeg_natural_order5[5*5+16] = {
+  0,  1,  8, 16,  9,  2,  3, 10,
+ 17, 24, 32, 25, 18, 11,  4, 12,
+ 19, 26, 33, 34, 27, 20, 28, 35,
+ 36,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+const int jpeg_natural_order4[4*4+16] = {
+  0,  1,  8, 16,  9,  2,  3, 10,
+ 17, 24, 25, 18, 11, 19, 26, 27,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+const int jpeg_natural_order3[3*3+16] = {
+  0,  1,  8, 16,  9,  2, 10, 17,
+ 18,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+const int jpeg_natural_order2[2*2+16] = {
+  0,  1,  8,  9,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+
+/*
+ * Arithmetic utilities
+ */
+
+GLOBAL(long)
+jdiv_round_up (long a, long b)
+/* Compute a/b rounded up to next integer, ie, ceil(a/b) */
+/* Assumes a >= 0, b > 0 */
+{
+  return (a + b - 1L) / b;
+}
+
+
+GLOBAL(long)
+jround_up (long a, long b)
+/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */
+/* Assumes a >= 0, b > 0 */
+{
+  a += b - 1L;
+  return a - (a % b);
+}
+
+
+/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays
+ * and coefficient-block arrays.  This won't work on 80x86 because the arrays
+ * are FAR and we're assuming a small-pointer memory model.  However, some
+ * DOS compilers provide far-pointer versions of memcpy() and memset() even
+ * in the small-model libraries.  These will be used if USE_FMEM is defined.
+ * Otherwise, the routines below do it the hard way.  (The performance cost
+ * is not all that great, because these routines aren't very heavily used.)
+ */
+
+#ifndef NEED_FAR_POINTERS	/* normal case, same as regular macro */
+#define FMEMCOPY(dest,src,size)	MEMCOPY(dest,src,size)
+#else				/* 80x86 case, define if we can */
+#ifdef USE_FMEM
+#define FMEMCOPY(dest,src,size)	_fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size))
+#else
+/* This function is for use by the FMEMZERO macro defined in jpegint.h.
+ * Do not call this function directly, use the FMEMZERO macro instead.
+ */
+GLOBAL(void)
+jzero_far (void FAR * target, size_t bytestozero)
+/* Zero out a chunk of FAR memory. */
+/* This might be sample-array data, block-array data, or alloc_large data. */
+{
+  register char FAR * ptr = (char FAR *) target;
+  register size_t count;
+
+  for (count = bytestozero; count > 0; count--) {
+    *ptr++ = 0;
+  }
+}
+#endif
+#endif
+
+
+GLOBAL(void)
+jcopy_sample_rows (JSAMPARRAY input_array, int source_row,
+		   JSAMPARRAY output_array, int dest_row,
+		   int num_rows, JDIMENSION num_cols)
+/* Copy some rows of samples from one place to another.
+ * num_rows rows are copied from input_array[source_row++]
+ * to output_array[dest_row++]; these areas may overlap for duplication.
+ * The source and destination arrays must be at least as wide as num_cols.
+ */
+{
+  register JSAMPROW inptr, outptr;
+#ifdef FMEMCOPY
+  register size_t count = (size_t) (num_cols * SIZEOF(JSAMPLE));
+#else
+  register JDIMENSION count;
+#endif
+  register int row;
+
+  input_array += source_row;
+  output_array += dest_row;
+
+  for (row = num_rows; row > 0; row--) {
+    inptr = *input_array++;
+    outptr = *output_array++;
+#ifdef FMEMCOPY
+    FMEMCOPY(outptr, inptr, count);
+#else
+    for (count = num_cols; count > 0; count--)
+      *outptr++ = *inptr++;	/* needn't bother with GETJSAMPLE() here */
+#endif
+  }
+}
+
+
+GLOBAL(void)
+jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row,
+		 JDIMENSION num_blocks)
+/* Copy a row of coefficient blocks from one place to another. */
+{
+#ifdef FMEMCOPY
+  FMEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * SIZEOF(JCOEF)));
+#else
+  register JCOEFPTR inptr, outptr;
+  register long count;
+
+  inptr = (JCOEFPTR) input_row;
+  outptr = (JCOEFPTR) output_row;
+  for (count = (long) num_blocks * DCTSIZE2; count > 0; count--) {
+    *outptr++ = *inptr++;
+  }
+#endif
+}
diff --git a/source/Irrlicht/jpeglib/jversion.h b/source/Irrlicht/jpeglib/jversion.h
new file mode 100644
index 00000000..8bd2b522
--- /dev/null
+++ b/source/Irrlicht/jpeglib/jversion.h
@@ -0,0 +1,14 @@
+/*
+ * jversion.h
+ *
+ * Copyright (C) 1991-2014, Thomas G. Lane, Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains software version identification.
+ */
+
+
+#define JVERSION	"9a  19-Jan-2014"
+
+#define JCOPYRIGHT	"Copyright (C) 2014, Thomas G. Lane, Guido Vollbeding"
diff --git a/source/Irrlicht/jpeglib/libjpeg.map b/source/Irrlicht/jpeglib/libjpeg.map
new file mode 100644
index 00000000..fa70b1f1
--- /dev/null
+++ b/source/Irrlicht/jpeglib/libjpeg.map
@@ -0,0 +1,4 @@
+LIBJPEG_9.0 {
+  global:
+    *;
+};
diff --git a/source/Irrlicht/jpeglib/libjpeg.txt b/source/Irrlicht/jpeglib/libjpeg.txt
new file mode 100644
index 00000000..4243c246
--- /dev/null
+++ b/source/Irrlicht/jpeglib/libjpeg.txt
@@ -0,0 +1,3111 @@
+USING THE IJG JPEG LIBRARY
+
+Copyright (C) 1994-2013, Thomas G. Lane, Guido Vollbeding.
+This file is part of the Independent JPEG Group's software.
+For conditions of distribution and use, see the accompanying README file.
+
+
+This file describes how to use the IJG JPEG library within an application
+program.  Read it if you want to write a program that uses the library.
+
+The file example.c provides heavily commented skeleton code for calling the
+JPEG library.  Also see jpeglib.h (the include file to be used by application
+programs) for full details about data structures and function parameter lists.
+The library source code, of course, is the ultimate reference.
+
+Note that there have been *major* changes from the application interface
+presented by IJG version 4 and earlier versions.  The old design had several
+inherent limitations, and it had accumulated a lot of cruft as we added
+features while trying to minimize application-interface changes.  We have
+sacrificed backward compatibility in the version 5 rewrite, but we think the
+improvements justify this.
+
+
+TABLE OF CONTENTS
+-----------------
+
+Overview:
+	Functions provided by the library
+	Outline of typical usage
+Basic library usage:
+	Data formats
+	Compression details
+	Decompression details
+	Mechanics of usage: include files, linking, etc
+Advanced features:
+	Compression parameter selection
+	Decompression parameter selection
+	Special color spaces
+	Error handling
+	Compressed data handling (source and destination managers)
+	I/O suspension
+	Progressive JPEG support
+	Buffered-image mode
+	Abbreviated datastreams and multiple images
+	Special markers
+	Raw (downsampled) image data
+	Really raw data: DCT coefficients
+	Progress monitoring
+	Memory management
+	Memory usage
+	Library compile-time options
+	Portability considerations
+	Notes for MS-DOS implementors
+
+You should read at least the overview and basic usage sections before trying
+to program with the library.  The sections on advanced features can be read
+if and when you need them.
+
+
+OVERVIEW
+========
+
+Functions provided by the library
+---------------------------------
+
+The IJG JPEG library provides C code to read and write JPEG-compressed image
+files.  The surrounding application program receives or supplies image data a
+scanline at a time, using a straightforward uncompressed image format.  All
+details of color conversion and other preprocessing/postprocessing can be
+handled by the library.
+
+The library includes a substantial amount of code that is not covered by the
+JPEG standard but is necessary for typical applications of JPEG.  These
+functions preprocess the image before JPEG compression or postprocess it after
+decompression.  They include colorspace conversion, downsampling/upsampling,
+and color quantization.  The application indirectly selects use of this code
+by specifying the format in which it wishes to supply or receive image data.
+For example, if colormapped output is requested, then the decompression
+library automatically invokes color quantization.
+
+A wide range of quality vs. speed tradeoffs are possible in JPEG processing,
+and even more so in decompression postprocessing.  The decompression library
+provides multiple implementations that cover most of the useful tradeoffs,
+ranging from very-high-quality down to fast-preview operation.  On the
+compression side we have generally not provided low-quality choices, since
+compression is normally less time-critical.  It should be understood that the
+low-quality modes may not meet the JPEG standard's accuracy requirements;
+nonetheless, they are useful for viewers.
+
+A word about functions *not* provided by the library.  We handle a subset of
+the ISO JPEG standard; most baseline, extended-sequential, and progressive
+JPEG processes are supported.  (Our subset includes all features now in common
+use.)  Unsupported ISO options include:
+	* Hierarchical storage
+	* Lossless JPEG
+	* DNL marker
+	* Nonintegral subsampling ratios
+We support 8-bit to 12-bit data precision, but this is a compile-time choice
+rather than a run-time choice; hence it is difficult to use different
+precisions in a single application.
+
+By itself, the library handles only interchange JPEG datastreams --- in
+particular the widely used JFIF file format.  The library can be used by
+surrounding code to process interchange or abbreviated JPEG datastreams that
+are embedded in more complex file formats.  (For example, this library is
+used by the free LIBTIFF library to support JPEG compression in TIFF.)
+
+
+Outline of typical usage
+------------------------
+
+The rough outline of a JPEG compression operation is:
+
+	Allocate and initialize a JPEG compression object
+	Specify the destination for the compressed data (eg, a file)
+	Set parameters for compression, including image size & colorspace
+	jpeg_start_compress(...);
+	while (scan lines remain to be written)
+		jpeg_write_scanlines(...);
+	jpeg_finish_compress(...);
+	Release the JPEG compression object
+
+A JPEG compression object holds parameters and working state for the JPEG
+library.  We make creation/destruction of the object separate from starting
+or finishing compression of an image; the same object can be re-used for a
+series of image compression operations.  This makes it easy to re-use the
+same parameter settings for a sequence of images.  Re-use of a JPEG object
+also has important implications for processing abbreviated JPEG datastreams,
+as discussed later.
+
+The image data to be compressed is supplied to jpeg_write_scanlines() from
+in-memory buffers.  If the application is doing file-to-file compression,
+reading image data from the source file is the application's responsibility.
+The library emits compressed data by calling a "data destination manager",
+which typically will write the data into a file; but the application can
+provide its own destination manager to do something else.
+
+Similarly, the rough outline of a JPEG decompression operation is:
+
+	Allocate and initialize a JPEG decompression object
+	Specify the source of the compressed data (eg, a file)
+	Call jpeg_read_header() to obtain image info
+	Set parameters for decompression
+	jpeg_start_decompress(...);
+	while (scan lines remain to be read)
+		jpeg_read_scanlines(...);
+	jpeg_finish_decompress(...);
+	Release the JPEG decompression object
+
+This is comparable to the compression outline except that reading the
+datastream header is a separate step.  This is helpful because information
+about the image's size, colorspace, etc is available when the application
+selects decompression parameters.  For example, the application can choose an
+output scaling ratio that will fit the image into the available screen size.
+
+The decompression library obtains compressed data by calling a data source
+manager, which typically will read the data from a file; but other behaviors
+can be obtained with a custom source manager.  Decompressed data is delivered
+into in-memory buffers passed to jpeg_read_scanlines().
+
+It is possible to abort an incomplete compression or decompression operation
+by calling jpeg_abort(); or, if you do not need to retain the JPEG object,
+simply release it by calling jpeg_destroy().
+
+JPEG compression and decompression objects are two separate struct types.
+However, they share some common fields, and certain routines such as
+jpeg_destroy() can work on either type of object.
+
+The JPEG library has no static variables: all state is in the compression
+or decompression object.  Therefore it is possible to process multiple
+compression and decompression operations concurrently, using multiple JPEG
+objects.
+
+Both compression and decompression can be done in an incremental memory-to-
+memory fashion, if suitable source/destination managers are used.  See the
+section on "I/O suspension" for more details.
+
+
+BASIC LIBRARY USAGE
+===================
+
+Data formats
+------------
+
+Before diving into procedural details, it is helpful to understand the
+image data format that the JPEG library expects or returns.
+
+The standard input image format is a rectangular array of pixels, with each
+pixel having the same number of "component" or "sample" values (color
+channels).  You must specify how many components there are and the colorspace
+interpretation of the components.  Most applications will use RGB data
+(three components per pixel) or grayscale data (one component per pixel).
+PLEASE NOTE THAT RGB DATA IS THREE SAMPLES PER PIXEL, GRAYSCALE ONLY ONE.
+A remarkable number of people manage to miss this, only to find that their
+programs don't work with grayscale JPEG files.
+
+There is no provision for colormapped input.  JPEG files are always full-color
+or full grayscale (or sometimes another colorspace such as CMYK).  You can
+feed in a colormapped image by expanding it to full-color format.  However
+JPEG often doesn't work very well with source data that has been colormapped,
+because of dithering noise.  This is discussed in more detail in the JPEG FAQ
+and the other references mentioned in the README file.
+
+Pixels are stored by scanlines, with each scanline running from left to
+right.  The component values for each pixel are adjacent in the row; for
+example, R,G,B,R,G,B,R,G,B,... for 24-bit RGB color.  Each scanline is an
+array of data type JSAMPLE --- which is typically "unsigned char", unless
+you've changed jmorecfg.h.  (You can also change the RGB pixel layout, say
+to B,G,R order, by modifying jmorecfg.h.  But see the restrictions listed in
+that file before doing so.)
+
+A 2-D array of pixels is formed by making a list of pointers to the starts of
+scanlines; so the scanlines need not be physically adjacent in memory.  Even
+if you process just one scanline at a time, you must make a one-element
+pointer array to conform to this structure.  Pointers to JSAMPLE rows are of
+type JSAMPROW, and the pointer to the pointer array is of type JSAMPARRAY.
+
+The library accepts or supplies one or more complete scanlines per call.
+It is not possible to process part of a row at a time.  Scanlines are always
+processed top-to-bottom.  You can process an entire image in one call if you
+have it all in memory, but usually it's simplest to process one scanline at
+a time.
+
+For best results, source data values should have the precision specified by
+BITS_IN_JSAMPLE (normally 8 bits).  For instance, if you choose to compress
+data that's only 6 bits/channel, you should left-justify each value in a
+byte before passing it to the compressor.  If you need to compress data
+that has more than 8 bits/channel, compile with BITS_IN_JSAMPLE = 9 to 12.
+(See "Library compile-time options", later.)
+
+
+The data format returned by the decompressor is the same in all details,
+except that colormapped output is supported.  (Again, a JPEG file is never
+colormapped.  But you can ask the decompressor to perform on-the-fly color
+quantization to deliver colormapped output.)  If you request colormapped
+output then the returned data array contains a single JSAMPLE per pixel;
+its value is an index into a color map.  The color map is represented as
+a 2-D JSAMPARRAY in which each row holds the values of one color component,
+that is, colormap[i][j] is the value of the i'th color component for pixel
+value (map index) j.  Note that since the colormap indexes are stored in
+JSAMPLEs, the maximum number of colors is limited by the size of JSAMPLE
+(ie, at most 256 colors for an 8-bit JPEG library).
+
+
+Compression details
+-------------------
+
+Here we revisit the JPEG compression outline given in the overview.
+
+1. Allocate and initialize a JPEG compression object.
+
+A JPEG compression object is a "struct jpeg_compress_struct".  (It also has
+a bunch of subsidiary structures which are allocated via malloc(), but the
+application doesn't control those directly.)  This struct can be just a local
+variable in the calling routine, if a single routine is going to execute the
+whole JPEG compression sequence.  Otherwise it can be static or allocated
+from malloc().
+
+You will also need a structure representing a JPEG error handler.  The part
+of this that the library cares about is a "struct jpeg_error_mgr".  If you
+are providing your own error handler, you'll typically want to embed the
+jpeg_error_mgr struct in a larger structure; this is discussed later under
+"Error handling".  For now we'll assume you are just using the default error
+handler.  The default error handler will print JPEG error/warning messages
+on stderr, and it will call exit() if a fatal error occurs.
+
+You must initialize the error handler structure, store a pointer to it into
+the JPEG object's "err" field, and then call jpeg_create_compress() to
+initialize the rest of the JPEG object.
+
+Typical code for this step, if you are using the default error handler, is
+
+	struct jpeg_compress_struct cinfo;
+	struct jpeg_error_mgr jerr;
+	...
+	cinfo.err = jpeg_std_error(&jerr);
+	jpeg_create_compress(&cinfo);
+
+jpeg_create_compress allocates a small amount of memory, so it could fail
+if you are out of memory.  In that case it will exit via the error handler;
+that's why the error handler must be initialized first.
+
+
+2. Specify the destination for the compressed data (eg, a file).
+
+As previously mentioned, the JPEG library delivers compressed data to a
+"data destination" module.  The library includes one data destination
+module which knows how to write to a stdio stream.  You can use your own
+destination module if you want to do something else, as discussed later.
+
+If you use the standard destination module, you must open the target stdio
+stream beforehand.  Typical code for this step looks like:
+
+	FILE * outfile;
+	...
+	if ((outfile = fopen(filename, "wb")) == NULL) {
+	    fprintf(stderr, "can't open %s\n", filename);
+	    exit(1);
+	}
+	jpeg_stdio_dest(&cinfo, outfile);
+
+where the last line invokes the standard destination module.
+
+WARNING: it is critical that the binary compressed data be delivered to the
+output file unchanged.  On non-Unix systems the stdio library may perform
+newline translation or otherwise corrupt binary data.  To suppress this
+behavior, you may need to use a "b" option to fopen (as shown above), or use
+setmode() or another routine to put the stdio stream in binary mode.  See
+cjpeg.c and djpeg.c for code that has been found to work on many systems.
+
+You can select the data destination after setting other parameters (step 3),
+if that's more convenient.  You may not change the destination between
+calling jpeg_start_compress() and jpeg_finish_compress().
+
+
+3. Set parameters for compression, including image size & colorspace.
+
+You must supply information about the source image by setting the following
+fields in the JPEG object (cinfo structure):
+
+	image_width		Width of image, in pixels
+	image_height		Height of image, in pixels
+	input_components	Number of color channels (samples per pixel)
+	in_color_space		Color space of source image
+
+The image dimensions are, hopefully, obvious.  JPEG supports image dimensions
+of 1 to 64K pixels in either direction.  The input color space is typically
+RGB or grayscale, and input_components is 3 or 1 accordingly.  (See "Special
+color spaces", later, for more info.)  The in_color_space field must be
+assigned one of the J_COLOR_SPACE enum constants, typically JCS_RGB or
+JCS_GRAYSCALE.
+
+JPEG has a large number of compression parameters that determine how the
+image is encoded.  Most applications don't need or want to know about all
+these parameters.  You can set all the parameters to reasonable defaults by
+calling jpeg_set_defaults(); then, if there are particular values you want
+to change, you can do so after that.  The "Compression parameter selection"
+section tells about all the parameters.
+
+You must set in_color_space correctly before calling jpeg_set_defaults(),
+because the defaults depend on the source image colorspace.  However the
+other three source image parameters need not be valid until you call
+jpeg_start_compress().  There's no harm in calling jpeg_set_defaults() more
+than once, if that happens to be convenient.
+
+Typical code for a 24-bit RGB source image is
+
+	cinfo.image_width = Width; 	/* image width and height, in pixels */
+	cinfo.image_height = Height;
+	cinfo.input_components = 3;	/* # of color components per pixel */
+	cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
+
+	jpeg_set_defaults(&cinfo);
+	/* Make optional parameter settings here */
+
+
+4. jpeg_start_compress(...);
+
+After you have established the data destination and set all the necessary
+source image info and other parameters, call jpeg_start_compress() to begin
+a compression cycle.  This will initialize internal state, allocate working
+storage, and emit the first few bytes of the JPEG datastream header.
+
+Typical code:
+
+	jpeg_start_compress(&cinfo, TRUE);
+
+The "TRUE" parameter ensures that a complete JPEG interchange datastream
+will be written.  This is appropriate in most cases.  If you think you might
+want to use an abbreviated datastream, read the section on abbreviated
+datastreams, below.
+
+Once you have called jpeg_start_compress(), you may not alter any JPEG
+parameters or other fields of the JPEG object until you have completed
+the compression cycle.
+
+
+5. while (scan lines remain to be written)
+	jpeg_write_scanlines(...);
+
+Now write all the required image data by calling jpeg_write_scanlines()
+one or more times.  You can pass one or more scanlines in each call, up
+to the total image height.  In most applications it is convenient to pass
+just one or a few scanlines at a time.  The expected format for the passed
+data is discussed under "Data formats", above.
+
+Image data should be written in top-to-bottom scanline order.  The JPEG spec
+contains some weasel wording about how top and bottom are application-defined
+terms (a curious interpretation of the English language...) but if you want
+your files to be compatible with everyone else's, you WILL use top-to-bottom
+order.  If the source data must be read in bottom-to-top order, you can use
+the JPEG library's virtual array mechanism to invert the data efficiently.
+Examples of this can be found in the sample application cjpeg.
+
+The library maintains a count of the number of scanlines written so far
+in the next_scanline field of the JPEG object.  Usually you can just use
+this variable as the loop counter, so that the loop test looks like
+"while (cinfo.next_scanline < cinfo.image_height)".
+
+Code for this step depends heavily on the way that you store the source data.
+example.c shows the following code for the case of a full-size 2-D source
+array containing 3-byte RGB pixels:
+
+	JSAMPROW row_pointer[1];	/* pointer to a single row */
+	int row_stride;			/* physical row width in buffer */
+
+	row_stride = image_width * 3;	/* JSAMPLEs per row in image_buffer */
+
+	while (cinfo.next_scanline < cinfo.image_height) {
+	    row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
+	    jpeg_write_scanlines(&cinfo, row_pointer, 1);
+	}
+
+jpeg_write_scanlines() returns the number of scanlines actually written.
+This will normally be equal to the number passed in, so you can usually
+ignore the return value.  It is different in just two cases:
+  * If you try to write more scanlines than the declared image height,
+    the additional scanlines are ignored.
+  * If you use a suspending data destination manager, output buffer overrun
+    will cause the compressor to return before accepting all the passed lines.
+    This feature is discussed under "I/O suspension", below.  The normal
+    stdio destination manager will NOT cause this to happen.
+In any case, the return value is the same as the change in the value of
+next_scanline.
+
+
+6. jpeg_finish_compress(...);
+
+After all the image data has been written, call jpeg_finish_compress() to
+complete the compression cycle.  This step is ESSENTIAL to ensure that the
+last bufferload of data is written to the data destination.
+jpeg_finish_compress() also releases working memory associated with the JPEG
+object.
+
+Typical code:
+
+	jpeg_finish_compress(&cinfo);
+
+If using the stdio destination manager, don't forget to close the output
+stdio stream (if necessary) afterwards.
+
+If you have requested a multi-pass operating mode, such as Huffman code
+optimization, jpeg_finish_compress() will perform the additional passes using
+data buffered by the first pass.  In this case jpeg_finish_compress() may take
+quite a while to complete.  With the default compression parameters, this will
+not happen.
+
+It is an error to call jpeg_finish_compress() before writing the necessary
+total number of scanlines.  If you wish to abort compression, call
+jpeg_abort() as discussed below.
+
+After completing a compression cycle, you may dispose of the JPEG object
+as discussed next, or you may use it to compress another image.  In that case
+return to step 2, 3, or 4 as appropriate.  If you do not change the
+destination manager, the new datastream will be written to the same target.
+If you do not change any JPEG parameters, the new datastream will be written
+with the same parameters as before.  Note that you can change the input image
+dimensions freely between cycles, but if you change the input colorspace, you
+should call jpeg_set_defaults() to adjust for the new colorspace; and then
+you'll need to repeat all of step 3.
+
+
+7. Release the JPEG compression object.
+
+When you are done with a JPEG compression object, destroy it by calling
+jpeg_destroy_compress().  This will free all subsidiary memory (regardless of
+the previous state of the object).  Or you can call jpeg_destroy(), which
+works for either compression or decompression objects --- this may be more
+convenient if you are sharing code between compression and decompression
+cases.  (Actually, these routines are equivalent except for the declared type
+of the passed pointer.  To avoid gripes from ANSI C compilers, jpeg_destroy()
+should be passed a j_common_ptr.)
+
+If you allocated the jpeg_compress_struct structure from malloc(), freeing
+it is your responsibility --- jpeg_destroy() won't.  Ditto for the error
+handler structure.
+
+Typical code:
+
+	jpeg_destroy_compress(&cinfo);
+
+
+8. Aborting.
+
+If you decide to abort a compression cycle before finishing, you can clean up
+in either of two ways:
+
+* If you don't need the JPEG object any more, just call
+  jpeg_destroy_compress() or jpeg_destroy() to release memory.  This is
+  legitimate at any point after calling jpeg_create_compress() --- in fact,
+  it's safe even if jpeg_create_compress() fails.
+
+* If you want to re-use the JPEG object, call jpeg_abort_compress(), or call
+  jpeg_abort() which works on both compression and decompression objects.
+  This will return the object to an idle state, releasing any working memory.
+  jpeg_abort() is allowed at any time after successful object creation.
+
+Note that cleaning up the data destination, if required, is your
+responsibility; neither of these routines will call term_destination().
+(See "Compressed data handling", below, for more about that.)
+
+jpeg_destroy() and jpeg_abort() are the only safe calls to make on a JPEG
+object that has reported an error by calling error_exit (see "Error handling"
+for more info).  The internal state of such an object is likely to be out of
+whack.  Either of these two routines will return the object to a known state.
+
+
+Decompression details
+---------------------
+
+Here we revisit the JPEG decompression outline given in the overview.
+
+1. Allocate and initialize a JPEG decompression object.
+
+This is just like initialization for compression, as discussed above,
+except that the object is a "struct jpeg_decompress_struct" and you
+call jpeg_create_decompress().  Error handling is exactly the same.
+
+Typical code:
+
+	struct jpeg_decompress_struct cinfo;
+	struct jpeg_error_mgr jerr;
+	...
+	cinfo.err = jpeg_std_error(&jerr);
+	jpeg_create_decompress(&cinfo);
+
+(Both here and in the IJG code, we usually use variable name "cinfo" for
+both compression and decompression objects.)
+
+
+2. Specify the source of the compressed data (eg, a file).
+
+As previously mentioned, the JPEG library reads compressed data from a "data
+source" module.  The library includes one data source module which knows how
+to read from a stdio stream.  You can use your own source module if you want
+to do something else, as discussed later.
+
+If you use the standard source module, you must open the source stdio stream
+beforehand.  Typical code for this step looks like:
+
+	FILE * infile;
+	...
+	if ((infile = fopen(filename, "rb")) == NULL) {
+	    fprintf(stderr, "can't open %s\n", filename);
+	    exit(1);
+	}
+	jpeg_stdio_src(&cinfo, infile);
+
+where the last line invokes the standard source module.
+
+WARNING: it is critical that the binary compressed data be read unchanged.
+On non-Unix systems the stdio library may perform newline translation or
+otherwise corrupt binary data.  To suppress this behavior, you may need to use
+a "b" option to fopen (as shown above), or use setmode() or another routine to
+put the stdio stream in binary mode.  See cjpeg.c and djpeg.c for code that
+has been found to work on many systems.
+
+You may not change the data source between calling jpeg_read_header() and
+jpeg_finish_decompress().  If you wish to read a series of JPEG images from
+a single source file, you should repeat the jpeg_read_header() to
+jpeg_finish_decompress() sequence without reinitializing either the JPEG
+object or the data source module; this prevents buffered input data from
+being discarded.
+
+
+3. Call jpeg_read_header() to obtain image info.
+
+Typical code for this step is just
+
+	jpeg_read_header(&cinfo, TRUE);
+
+This will read the source datastream header markers, up to the beginning
+of the compressed data proper.  On return, the image dimensions and other
+info have been stored in the JPEG object.  The application may wish to
+consult this information before selecting decompression parameters.
+
+More complex code is necessary if
+  * A suspending data source is used --- in that case jpeg_read_header()
+    may return before it has read all the header data.  See "I/O suspension",
+    below.  The normal stdio source manager will NOT cause this to happen.
+  * Abbreviated JPEG files are to be processed --- see the section on
+    abbreviated datastreams.  Standard applications that deal only in
+    interchange JPEG files need not be concerned with this case either.
+
+It is permissible to stop at this point if you just wanted to find out the
+image dimensions and other header info for a JPEG file.  In that case,
+call jpeg_destroy() when you are done with the JPEG object, or call
+jpeg_abort() to return it to an idle state before selecting a new data
+source and reading another header.
+
+
+4. Set parameters for decompression.
+
+jpeg_read_header() sets appropriate default decompression parameters based on
+the properties of the image (in particular, its colorspace).  However, you
+may well want to alter these defaults before beginning the decompression.
+For example, the default is to produce full color output from a color file.
+If you want colormapped output you must ask for it.  Other options allow the
+returned image to be scaled and allow various speed/quality tradeoffs to be
+selected.  "Decompression parameter selection", below, gives details.
+
+If the defaults are appropriate, nothing need be done at this step.
+
+Note that all default values are set by each call to jpeg_read_header().
+If you reuse a decompression object, you cannot expect your parameter
+settings to be preserved across cycles, as you can for compression.
+You must set desired parameter values each time.
+
+
+5. jpeg_start_decompress(...);
+
+Once the parameter values are satisfactory, call jpeg_start_decompress() to
+begin decompression.  This will initialize internal state, allocate working
+memory, and prepare for returning data.
+
+Typical code is just
+
+	jpeg_start_decompress(&cinfo);
+
+If you have requested a multi-pass operating mode, such as 2-pass color
+quantization, jpeg_start_decompress() will do everything needed before data
+output can begin.  In this case jpeg_start_decompress() may take quite a while
+to complete.  With a single-scan (non progressive) JPEG file and default
+decompression parameters, this will not happen; jpeg_start_decompress() will
+return quickly.
+
+After this call, the final output image dimensions, including any requested
+scaling, are available in the JPEG object; so is the selected colormap, if
+colormapped output has been requested.  Useful fields include
+
+	output_width		image width and height, as scaled
+	output_height
+	out_color_components	# of color components in out_color_space
+	output_components	# of color components returned per pixel
+	colormap		the selected colormap, if any
+	actual_number_of_colors		number of entries in colormap
+
+output_components is 1 (a colormap index) when quantizing colors; otherwise it
+equals out_color_components.  It is the number of JSAMPLE values that will be
+emitted per pixel in the output arrays.
+
+Typically you will need to allocate data buffers to hold the incoming image.
+You will need output_width * output_components JSAMPLEs per scanline in your
+output buffer, and a total of output_height scanlines will be returned.
+
+Note: if you are using the JPEG library's internal memory manager to allocate
+data buffers (as djpeg does), then the manager's protocol requires that you
+request large buffers *before* calling jpeg_start_decompress().  This is a
+little tricky since the output_XXX fields are not normally valid then.  You
+can make them valid by calling jpeg_calc_output_dimensions() after setting the
+relevant parameters (scaling, output color space, and quantization flag).
+
+
+6. while (scan lines remain to be read)
+	jpeg_read_scanlines(...);
+
+Now you can read the decompressed image data by calling jpeg_read_scanlines()
+one or more times.  At each call, you pass in the maximum number of scanlines
+to be read (ie, the height of your working buffer); jpeg_read_scanlines()
+will return up to that many lines.  The return value is the number of lines
+actually read.  The format of the returned data is discussed under "Data
+formats", above.  Don't forget that grayscale and color JPEGs will return
+different data formats!
+
+Image data is returned in top-to-bottom scanline order.  If you must write
+out the image in bottom-to-top order, you can use the JPEG library's virtual
+array mechanism to invert the data efficiently.  Examples of this can be
+found in the sample application djpeg.
+
+The library maintains a count of the number of scanlines returned so far
+in the output_scanline field of the JPEG object.  Usually you can just use
+this variable as the loop counter, so that the loop test looks like
+"while (cinfo.output_scanline < cinfo.output_height)".  (Note that the test
+should NOT be against image_height, unless you never use scaling.  The
+image_height field is the height of the original unscaled image.)
+The return value always equals the change in the value of output_scanline.
+
+If you don't use a suspending data source, it is safe to assume that
+jpeg_read_scanlines() reads at least one scanline per call, until the
+bottom of the image has been reached.
+
+If you use a buffer larger than one scanline, it is NOT safe to assume that
+jpeg_read_scanlines() fills it.  (The current implementation returns only a
+few scanlines per call, no matter how large a buffer you pass.)  So you must
+always provide a loop that calls jpeg_read_scanlines() repeatedly until the
+whole image has been read.
+
+
+7. jpeg_finish_decompress(...);
+
+After all the image data has been read, call jpeg_finish_decompress() to
+complete the decompression cycle.  This causes working memory associated
+with the JPEG object to be released.
+
+Typical code:
+
+	jpeg_finish_decompress(&cinfo);
+
+If using the stdio source manager, don't forget to close the source stdio
+stream if necessary.
+
+It is an error to call jpeg_finish_decompress() before reading the correct
+total number of scanlines.  If you wish to abort decompression, call
+jpeg_abort() as discussed below.
+
+After completing a decompression cycle, you may dispose of the JPEG object as
+discussed next, or you may use it to decompress another image.  In that case
+return to step 2 or 3 as appropriate.  If you do not change the source
+manager, the next image will be read from the same source.
+
+
+8. Release the JPEG decompression object.
+
+When you are done with a JPEG decompression object, destroy it by calling
+jpeg_destroy_decompress() or jpeg_destroy().  The previous discussion of
+destroying compression objects applies here too.
+
+Typical code:
+
+	jpeg_destroy_decompress(&cinfo);
+
+
+9. Aborting.
+
+You can abort a decompression cycle by calling jpeg_destroy_decompress() or
+jpeg_destroy() if you don't need the JPEG object any more, or
+jpeg_abort_decompress() or jpeg_abort() if you want to reuse the object.
+The previous discussion of aborting compression cycles applies here too.
+
+
+Mechanics of usage: include files, linking, etc
+-----------------------------------------------
+
+Applications using the JPEG library should include the header file jpeglib.h
+to obtain declarations of data types and routines.  Before including
+jpeglib.h, include system headers that define at least the typedefs FILE and
+size_t.  On ANSI-conforming systems, including  is sufficient; on
+older Unix systems, you may need  to define size_t.
+
+If the application needs to refer to individual JPEG library error codes, also
+include jerror.h to define those symbols.
+
+jpeglib.h indirectly includes the files jconfig.h and jmorecfg.h.  If you are
+installing the JPEG header files in a system directory, you will want to
+install all four files: jpeglib.h, jerror.h, jconfig.h, jmorecfg.h.
+
+The most convenient way to include the JPEG code into your executable program
+is to prepare a library file ("libjpeg.a", or a corresponding name on non-Unix
+machines) and reference it at your link step.  If you use only half of the
+library (only compression or only decompression), only that much code will be
+included from the library, unless your linker is hopelessly brain-damaged.
+The supplied makefiles build libjpeg.a automatically (see install.txt).
+
+While you can build the JPEG library as a shared library if the whim strikes
+you, we don't really recommend it.  The trouble with shared libraries is that
+at some point you'll probably try to substitute a new version of the library
+without recompiling the calling applications.  That generally doesn't work
+because the parameter struct declarations usually change with each new
+version.  In other words, the library's API is *not* guaranteed binary
+compatible across versions; we only try to ensure source-code compatibility.
+(In hindsight, it might have been smarter to hide the parameter structs from
+applications and introduce a ton of access functions instead.  Too late now,
+however.)
+
+On some systems your application may need to set up a signal handler to ensure
+that temporary files are deleted if the program is interrupted.  This is most
+critical if you are on MS-DOS and use the jmemdos.c memory manager back end;
+it will try to grab extended memory for temp files, and that space will NOT be
+freed automatically.  See cjpeg.c or djpeg.c for an example signal handler.
+
+It may be worth pointing out that the core JPEG library does not actually
+require the stdio library: only the default source/destination managers and
+error handler need it.  You can use the library in a stdio-less environment
+if you replace those modules and use jmemnobs.c (or another memory manager of
+your own devising).  More info about the minimum system library requirements
+may be found in jinclude.h.
+
+
+ADVANCED FEATURES
+=================
+
+Compression parameter selection
+-------------------------------
+
+This section describes all the optional parameters you can set for JPEG
+compression, as well as the "helper" routines provided to assist in this
+task.  Proper setting of some parameters requires detailed understanding
+of the JPEG standard; if you don't know what a parameter is for, it's best
+not to mess with it!  See REFERENCES in the README file for pointers to
+more info about JPEG.
+
+It's a good idea to call jpeg_set_defaults() first, even if you plan to set
+all the parameters; that way your code is more likely to work with future JPEG
+libraries that have additional parameters.  For the same reason, we recommend
+you use a helper routine where one is provided, in preference to twiddling
+cinfo fields directly.
+
+The helper routines are:
+
+jpeg_set_defaults (j_compress_ptr cinfo)
+	This routine sets all JPEG parameters to reasonable defaults, using
+	only the input image's color space (field in_color_space, which must
+	already be set in cinfo).  Many applications will only need to use
+	this routine and perhaps jpeg_set_quality().
+
+jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
+	Sets the JPEG file's colorspace (field jpeg_color_space) as specified,
+	and sets other color-space-dependent parameters appropriately.  See
+	"Special color spaces", below, before using this.  A large number of
+	parameters, including all per-component parameters, are set by this
+	routine; if you want to twiddle individual parameters you should call
+	jpeg_set_colorspace() before rather than after.
+
+jpeg_default_colorspace (j_compress_ptr cinfo)
+	Selects an appropriate JPEG colorspace based on cinfo->in_color_space,
+	and calls jpeg_set_colorspace().  This is actually a subroutine of
+	jpeg_set_defaults().  It's broken out in case you want to change
+	just the colorspace-dependent JPEG parameters.
+
+jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline)
+	Constructs JPEG quantization tables appropriate for the indicated
+	quality setting.  The quality value is expressed on the 0..100 scale
+	recommended by IJG (cjpeg's "-quality" switch uses this routine).
+	Note that the exact mapping from quality values to tables may change
+	in future IJG releases as more is learned about DCT quantization.
+	If the force_baseline parameter is TRUE, then the quantization table
+	entries are constrained to the range 1..255 for full JPEG baseline
+	compatibility.  In the current implementation, this only makes a
+	difference for quality settings below 25, and it effectively prevents
+	very small/low quality files from being generated.  The IJG decoder
+	is capable of reading the non-baseline files generated at low quality
+	settings when force_baseline is FALSE, but other decoders may not be.
+
+jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor,
+			 boolean force_baseline)
+	Same as jpeg_set_quality() except that the generated tables are the
+	sample tables given in the JPEC spec section K.1, multiplied by the
+	specified scale factor (which is expressed as a percentage; thus
+	scale_factor = 100 reproduces the spec's tables).  Note that larger
+	scale factors give lower quality.  This entry point is useful for
+	conforming to the Adobe PostScript DCT conventions, but we do not
+	recommend linear scaling as a user-visible quality scale otherwise.
+	force_baseline again constrains the computed table entries to 1..255.
+
+int jpeg_quality_scaling (int quality)
+	Converts a value on the IJG-recommended quality scale to a linear
+	scaling percentage.  Note that this routine may change or go away
+	in future releases --- IJG may choose to adopt a scaling method that
+	can't be expressed as a simple scalar multiplier, in which case the
+	premise of this routine collapses.  Caveat user.
+
+jpeg_default_qtables (j_compress_ptr cinfo, boolean force_baseline)
+	Set default quantization tables with linear q_scale_factor[] values
+	(see below).
+
+jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl,
+		      const unsigned int *basic_table,
+		      int scale_factor, boolean force_baseline)
+	Allows an arbitrary quantization table to be created.  which_tbl
+	indicates which table slot to fill.  basic_table points to an array
+	of 64 unsigned ints given in normal array order.  These values are
+	multiplied by scale_factor/100 and then clamped to the range 1..65535
+	(or to 1..255 if force_baseline is TRUE).
+	CAUTION: prior to library version 6a, jpeg_add_quant_table expected
+	the basic table to be given in JPEG zigzag order.  If you need to
+	write code that works with either older or newer versions of this
+	routine, you must check the library version number.  Something like
+	"#if JPEG_LIB_VERSION >= 61" is the right test.
+
+jpeg_simple_progression (j_compress_ptr cinfo)
+	Generates a default scan script for writing a progressive-JPEG file.
+	This is the recommended method of creating a progressive file,
+	unless you want to make a custom scan sequence.  You must ensure that
+	the JPEG color space is set correctly before calling this routine.
+
+
+Compression parameters (cinfo fields) include:
+
+boolean arith_code
+	If TRUE, use arithmetic coding.
+	If FALSE, use Huffman coding.
+
+int block_size
+	Set DCT block size.  All N from 1 to 16 are possible.
+	Default is 8 (baseline format).
+	Larger values produce higher compression,
+	smaller values produce higher quality.
+	An exact DCT stage is possible with 1 or 2.
+	With the default quality of 75 and default Luminance qtable
+	the DCT+Quantization stage is lossless for value 1.
+	Note that values other than 8 require a SmartScale capable decoder,
+	introduced with IJG JPEG 8.  Setting the block_size parameter for
+	compression works with version 8c and later.
+
+J_DCT_METHOD dct_method
+	Selects the algorithm used for the DCT step.  Choices are:
+		JDCT_ISLOW: slow but accurate integer algorithm
+		JDCT_IFAST: faster, less accurate integer method
+		JDCT_FLOAT: floating-point method
+		JDCT_DEFAULT: default method (normally JDCT_ISLOW)
+		JDCT_FASTEST: fastest method (normally JDCT_IFAST)
+	The FLOAT method is very slightly more accurate than the ISLOW method,
+	but may give different results on different machines due to varying
+	roundoff behavior.  The integer methods should give the same results
+	on all machines.  On machines with sufficiently fast FP hardware, the
+	floating-point method may also be the fastest.  The IFAST method is
+	considerably less accurate than the other two; its use is not
+	recommended if high quality is a concern.  JDCT_DEFAULT and
+	JDCT_FASTEST are macros configurable by each installation.
+
+unsigned int scale_num, scale_denom
+	Scale the image by the fraction scale_num/scale_denom.  Default is
+	1/1, or no scaling.  Currently, the supported scaling ratios are
+	M/N with all N from 1 to 16, where M is the destination DCT size,
+	which is 8 by default (see block_size parameter above).
+	(The library design allows for arbitrary scaling ratios but this
+	is not likely to be implemented any time soon.)
+
+J_COLOR_SPACE jpeg_color_space
+int num_components
+	The JPEG color space and corresponding number of components; see
+	"Special color spaces", below, for more info.  We recommend using
+	jpeg_set_colorspace() if you want to change these.
+
+J_COLOR_TRANSFORM color_transform
+	Internal color transform identifier, writes LSE marker if nonzero
+	(requires decoder with inverse color transform support, introduced
+	with IJG JPEG 9).
+	Two values are currently possible: JCT_NONE and JCT_SUBTRACT_GREEN.
+	Set this value for lossless RGB application *before* calling
+	jpeg_set_colorspace(), because entropy table assignment in
+	jpeg_set_colorspace() depends on color_transform.
+
+boolean optimize_coding
+	TRUE causes the compressor to compute optimal Huffman coding tables
+	for the image.  This requires an extra pass over the data and
+	therefore costs a good deal of space and time.  The default is
+	FALSE, which tells the compressor to use the supplied or default
+	Huffman tables.  In most cases optimal tables save only a few percent
+	of file size compared to the default tables.  Note that when this is
+	TRUE, you need not supply Huffman tables at all, and any you do
+	supply will be overwritten.
+
+unsigned int restart_interval
+int restart_in_rows
+	To emit restart markers in the JPEG file, set one of these nonzero.
+	Set restart_interval to specify the exact interval in MCU blocks.
+	Set restart_in_rows to specify the interval in MCU rows.  (If
+	restart_in_rows is not 0, then restart_interval is set after the
+	image width in MCUs is computed.)  Defaults are zero (no restarts).
+	One restart marker per MCU row is often a good choice.
+	NOTE: the overhead of restart markers is higher in grayscale JPEG
+	files than in color files, and MUCH higher in progressive JPEGs.
+	If you use restarts, you may want to use larger intervals in those
+	cases.
+
+const jpeg_scan_info * scan_info
+int num_scans
+	By default, scan_info is NULL; this causes the compressor to write a
+	single-scan sequential JPEG file.  If not NULL, scan_info points to
+	an array of scan definition records of length num_scans.  The
+	compressor will then write a JPEG file having one scan for each scan
+	definition record.  This is used to generate noninterleaved or
+	progressive JPEG files.  The library checks that the scan array
+	defines a valid JPEG scan sequence.  (jpeg_simple_progression creates
+	a suitable scan definition array for progressive JPEG.)  This is
+	discussed further under "Progressive JPEG support".
+
+boolean do_fancy_downsampling
+	If TRUE, use direct DCT scaling with DCT size > 8 for downsampling
+	of chroma components.
+	If FALSE, use only DCT size <= 8 and simple separate downsampling.
+	Default is TRUE.
+	For better image stability in multiple generation compression cycles
+	it is preferable that this value matches the corresponding
+	do_fancy_upsampling value in decompression.
+
+int smoothing_factor
+	If non-zero, the input image is smoothed; the value should be 1 for
+	minimal smoothing to 100 for maximum smoothing.  Consult jcsample.c
+	for details of the smoothing algorithm.  The default is zero.
+
+boolean write_JFIF_header
+	If TRUE, a JFIF APP0 marker is emitted.  jpeg_set_defaults() and
+	jpeg_set_colorspace() set this TRUE if a JFIF-legal JPEG color space
+	(ie, YCbCr or grayscale) is selected, otherwise FALSE.
+
+UINT8 JFIF_major_version
+UINT8 JFIF_minor_version
+	The version number to be written into the JFIF marker.
+	jpeg_set_defaults() initializes the version to 1.01 (major=minor=1).
+	You should set it to 1.02 (major=1, minor=2) if you plan to write
+	any JFIF 1.02 extension markers.
+
+UINT8 density_unit
+UINT16 X_density
+UINT16 Y_density
+	The resolution information to be written into the JFIF marker;
+	not used otherwise.  density_unit may be 0 for unknown,
+	1 for dots/inch, or 2 for dots/cm.  The default values are 0,1,1
+	indicating square pixels of unknown size.
+
+boolean write_Adobe_marker
+	If TRUE, an Adobe APP14 marker is emitted.  jpeg_set_defaults() and
+	jpeg_set_colorspace() set this TRUE if JPEG color space RGB, CMYK,
+	or YCCK is selected, otherwise FALSE.  It is generally a bad idea
+	to set both write_JFIF_header and write_Adobe_marker.  In fact,
+	you probably shouldn't change the default settings at all --- the
+	default behavior ensures that the JPEG file's color space can be
+	recognized by the decoder.
+
+JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]
+	Pointers to coefficient quantization tables, one per table slot,
+	or NULL if no table is defined for a slot.  Usually these should
+	be set via one of the above helper routines; jpeg_add_quant_table()
+	is general enough to define any quantization table.  The other
+	routines will set up table slot 0 for luminance quality and table
+	slot 1 for chrominance.
+
+int q_scale_factor[NUM_QUANT_TBLS]
+	Linear quantization scaling factors (percentage, initialized 100)
+	for use with jpeg_default_qtables().
+	See rdswitch.c and cjpeg.c for an example of usage.
+	Note that the q_scale_factor[] fields are the "linear" scales, so you
+	have to convert from user-defined ratings via jpeg_quality_scaling().
+	Here is an example code which corresponds to cjpeg -quality 90,70:
+
+		jpeg_set_defaults(cinfo);
+
+		/* Set luminance quality 90. */
+		cinfo->q_scale_factor[0] = jpeg_quality_scaling(90);
+		/* Set chrominance quality 70. */
+		cinfo->q_scale_factor[1] = jpeg_quality_scaling(70);
+
+		jpeg_default_qtables(cinfo, force_baseline);
+
+	CAUTION: You must also set 1x1 subsampling for efficient separate
+	color quality selection, since the default value used by library
+	is 2x2:
+
+		cinfo->comp_info[0].v_samp_factor = 1;
+		cinfo->comp_info[0].h_samp_factor = 1;
+
+JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]
+JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]
+	Pointers to Huffman coding tables, one per table slot, or NULL if
+	no table is defined for a slot.  Slots 0 and 1 are filled with the
+	JPEG sample tables by jpeg_set_defaults().  If you need to allocate
+	more table structures, jpeg_alloc_huff_table() may be used.
+	Note that optimal Huffman tables can be computed for an image
+	by setting optimize_coding, as discussed above; there's seldom
+	any need to mess with providing your own Huffman tables.
+
+
+The actual dimensions of the JPEG image that will be written to the file are
+given by the following fields.  These are computed from the input image
+dimensions and the compression parameters by jpeg_start_compress().  You can
+also call jpeg_calc_jpeg_dimensions() to obtain the values that will result
+from the current parameter settings.  This can be useful if you are trying
+to pick a scaling ratio that will get close to a desired target size.
+
+JDIMENSION jpeg_width		Actual dimensions of output image.
+JDIMENSION jpeg_height
+
+
+Per-component parameters are stored in the struct cinfo.comp_info[i] for
+component number i.  Note that components here refer to components of the
+JPEG color space, *not* the source image color space.  A suitably large
+comp_info[] array is allocated by jpeg_set_defaults(); if you choose not
+to use that routine, it's up to you to allocate the array.
+
+int component_id
+	The one-byte identifier code to be recorded in the JPEG file for
+	this component.  For the standard color spaces, we recommend you
+	leave the default values alone.
+
+int h_samp_factor
+int v_samp_factor
+	Horizontal and vertical sampling factors for the component; must
+	be 1..4 according to the JPEG standard.  Note that larger sampling
+	factors indicate a higher-resolution component; many people find
+	this behavior quite unintuitive.  The default values are 2,2 for
+	luminance components and 1,1 for chrominance components, except
+	for grayscale where 1,1 is used.
+
+int quant_tbl_no
+	Quantization table number for component.  The default value is
+	0 for luminance components and 1 for chrominance components.
+
+int dc_tbl_no
+int ac_tbl_no
+	DC and AC entropy coding table numbers.  The default values are
+	0 for luminance components and 1 for chrominance components.
+
+int component_index
+	Must equal the component's index in comp_info[].  (Beginning in
+	release v6, the compressor library will fill this in automatically;
+	you don't have to.)
+
+
+Decompression parameter selection
+---------------------------------
+
+Decompression parameter selection is somewhat simpler than compression
+parameter selection, since all of the JPEG internal parameters are
+recorded in the source file and need not be supplied by the application.
+(Unless you are working with abbreviated files, in which case see
+"Abbreviated datastreams", below.)  Decompression parameters control
+the postprocessing done on the image to deliver it in a format suitable
+for the application's use.  Many of the parameters control speed/quality
+tradeoffs, in which faster decompression may be obtained at the price of
+a poorer-quality image.  The defaults select the highest quality (slowest)
+processing.
+
+The following fields in the JPEG object are set by jpeg_read_header() and
+may be useful to the application in choosing decompression parameters:
+
+JDIMENSION image_width			Width and height of image
+JDIMENSION image_height
+int num_components			Number of color components
+J_COLOR_SPACE jpeg_color_space		Colorspace of image
+boolean saw_JFIF_marker			TRUE if a JFIF APP0 marker was seen
+  UINT8 JFIF_major_version		Version information from JFIF marker
+  UINT8 JFIF_minor_version
+  UINT8 density_unit			Resolution data from JFIF marker
+  UINT16 X_density
+  UINT16 Y_density
+boolean saw_Adobe_marker		TRUE if an Adobe APP14 marker was seen
+  UINT8 Adobe_transform			Color transform code from Adobe marker
+
+The JPEG color space, unfortunately, is something of a guess since the JPEG
+standard proper does not provide a way to record it.  In practice most files
+adhere to the JFIF or Adobe conventions, and the decoder will recognize these
+correctly.  See "Special color spaces", below, for more info.
+
+
+The decompression parameters that determine the basic properties of the
+returned image are:
+
+J_COLOR_SPACE out_color_space
+	Output color space.  jpeg_read_header() sets an appropriate default
+	based on jpeg_color_space; typically it will be RGB or grayscale.
+	The application can change this field to request output in a different
+	colorspace.  For example, set it to JCS_GRAYSCALE to get grayscale
+	output from a color file.  (This is useful for previewing: grayscale
+	output is faster than full color since the color components need not
+	be processed.)  Note that not all possible color space transforms are
+	currently implemented; you may need to extend jdcolor.c if you want an
+	unusual conversion.
+
+unsigned int scale_num, scale_denom
+	Scale the image by the fraction scale_num/scale_denom.  Currently,
+	the supported scaling ratios are M/N with all M from 1 to 16, where
+	N is the source DCT size, which is 8 for baseline JPEG.  (The library
+	design allows for arbitrary scaling ratios but this is not likely
+	to be implemented any time soon.)  The values are initialized by
+	jpeg_read_header() with the source DCT size.  For baseline JPEG
+	this is 8/8.  If you change only the scale_num value while leaving
+	the other unchanged, then this specifies the DCT scaled size to be
+	applied on the given input.  For baseline JPEG this is equivalent
+	to M/8 scaling, since the source DCT size for baseline JPEG is 8.
+	Smaller scaling ratios permit significantly faster decoding since
+	fewer pixels need be processed and a simpler IDCT method can be used.
+
+boolean quantize_colors
+	If set TRUE, colormapped output will be delivered.  Default is FALSE,
+	meaning that full-color output will be delivered.
+
+The next three parameters are relevant only if quantize_colors is TRUE.
+
+int desired_number_of_colors
+	Maximum number of colors to use in generating a library-supplied color
+	map (the actual number of colors is returned in a different field).
+	Default 256.  Ignored when the application supplies its own color map.
+
+boolean two_pass_quantize
+	If TRUE, an extra pass over the image is made to select a custom color
+	map for the image.  This usually looks a lot better than the one-size-
+	fits-all colormap that is used otherwise.  Default is TRUE.  Ignored
+	when the application supplies its own color map.
+
+J_DITHER_MODE dither_mode
+	Selects color dithering method.  Supported values are:
+		JDITHER_NONE	no dithering: fast, very low quality
+		JDITHER_ORDERED	ordered dither: moderate speed and quality
+		JDITHER_FS	Floyd-Steinberg dither: slow, high quality
+	Default is JDITHER_FS.  (At present, ordered dither is implemented
+	only in the single-pass, standard-colormap case.  If you ask for
+	ordered dither when two_pass_quantize is TRUE or when you supply
+	an external color map, you'll get F-S dithering.)
+
+When quantize_colors is TRUE, the target color map is described by the next
+two fields.  colormap is set to NULL by jpeg_read_header().  The application
+can supply a color map by setting colormap non-NULL and setting
+actual_number_of_colors to the map size.  Otherwise, jpeg_start_decompress()
+selects a suitable color map and sets these two fields itself.
+[Implementation restriction: at present, an externally supplied colormap is
+only accepted for 3-component output color spaces.]
+
+JSAMPARRAY colormap
+	The color map, represented as a 2-D pixel array of out_color_components
+	rows and actual_number_of_colors columns.  Ignored if not quantizing.
+	CAUTION: if the JPEG library creates its own colormap, the storage
+	pointed to by this field is released by jpeg_finish_decompress().
+	Copy the colormap somewhere else first, if you want to save it.
+
+int actual_number_of_colors
+	The number of colors in the color map.
+
+Additional decompression parameters that the application may set include:
+
+J_DCT_METHOD dct_method
+	Selects the algorithm used for the DCT step.  Choices are the same
+	as described above for compression.
+
+boolean do_fancy_upsampling
+	If TRUE, use direct DCT scaling with DCT size > 8 for upsampling
+	of chroma components.
+	If FALSE, use only DCT size <= 8 and simple separate upsampling.
+	Default is TRUE.
+	For better image stability in multiple generation compression cycles
+	it is preferable that this value matches the corresponding
+	do_fancy_downsampling value in compression.
+
+boolean do_block_smoothing
+	If TRUE, interblock smoothing is applied in early stages of decoding
+	progressive JPEG files; if FALSE, not.  Default is TRUE.  Early
+	progression stages look "fuzzy" with smoothing, "blocky" without.
+	In any case, block smoothing ceases to be applied after the first few
+	AC coefficients are known to full accuracy, so it is relevant only
+	when using buffered-image mode for progressive images.
+
+boolean enable_1pass_quant
+boolean enable_external_quant
+boolean enable_2pass_quant
+	These are significant only in buffered-image mode, which is
+	described in its own section below.
+
+
+The output image dimensions are given by the following fields.  These are
+computed from the source image dimensions and the decompression parameters
+by jpeg_start_decompress().  You can also call jpeg_calc_output_dimensions()
+to obtain the values that will result from the current parameter settings.
+This can be useful if you are trying to pick a scaling ratio that will get
+close to a desired target size.  It's also important if you are using the
+JPEG library's memory manager to allocate output buffer space, because you
+are supposed to request such buffers *before* jpeg_start_decompress().
+
+JDIMENSION output_width		Actual dimensions of output image.
+JDIMENSION output_height
+int out_color_components	Number of color components in out_color_space.
+int output_components		Number of color components returned.
+int rec_outbuf_height		Recommended height of scanline buffer.
+
+When quantizing colors, output_components is 1, indicating a single color map
+index per pixel.  Otherwise it equals out_color_components.  The output arrays
+are required to be output_width * output_components JSAMPLEs wide.
+
+rec_outbuf_height is the recommended minimum height (in scanlines) of the
+buffer passed to jpeg_read_scanlines().  If the buffer is smaller, the
+library will still work, but time will be wasted due to unnecessary data
+copying.  In high-quality modes, rec_outbuf_height is always 1, but some
+faster, lower-quality modes set it to larger values (typically 2 to 4).
+If you are going to ask for a high-speed processing mode, you may as well
+go to the trouble of honoring rec_outbuf_height so as to avoid data copying.
+(An output buffer larger than rec_outbuf_height lines is OK, but won't
+provide any material speed improvement over that height.)
+
+
+Special color spaces
+--------------------
+
+The JPEG standard itself is "color blind" and doesn't specify any particular
+color space.  It is customary to convert color data to a luminance/chrominance
+color space before compressing, since this permits greater compression.  The
+existing JPEG file interchange format standards specify YCbCr or GRAYSCALE
+data (JFIF version 1), GRAYSCALE, RGB, YCbCr, CMYK, or YCCK (Adobe), or BG_RGB
+or BG_YCC (big gamut color spaces, JFIF version 2).  For special applications
+such as multispectral images, other color spaces can be used,
+but it must be understood that such files will be unportable.
+
+The JPEG library can handle the most common colorspace conversions (namely
+RGB <=> YCbCr and CMYK <=> YCCK).  It can also deal with data of an unknown
+color space, passing it through without conversion.  If you deal extensively
+with an unusual color space, you can easily extend the library to understand
+additional color spaces and perform appropriate conversions.
+
+For compression, the source data's color space is specified by field
+in_color_space.  This is transformed to the JPEG file's color space given
+by jpeg_color_space.  jpeg_set_defaults() chooses a reasonable JPEG color
+space depending on in_color_space, but you can override this by calling
+jpeg_set_colorspace().  Of course you must select a supported transformation.
+jccolor.c currently supports the following transformations:
+	RGB => YCbCr
+	RGB => GRAYSCALE
+	RGB => BG_YCC
+	YCbCr => GRAYSCALE
+	YCbCr => BG_YCC
+	CMYK => YCCK
+plus the null transforms: GRAYSCALE => GRAYSCALE, RGB => RGB,
+BG_RGB => BG_RGB, YCbCr => YCbCr, BG_YCC => BG_YCC, CMYK => CMYK,
+YCCK => YCCK, and UNKNOWN => UNKNOWN.
+
+The file interchange format standards (JFIF and Adobe) specify APPn markers
+that indicate the color space of the JPEG file.  It is important to ensure
+that these are written correctly, or omitted if the JPEG file's color space
+is not one of the ones supported by the interchange standards.
+jpeg_set_colorspace() will set the compression parameters to include or omit
+the APPn markers properly, so long as it is told the truth about the JPEG
+color space.  For example, if you are writing some random 3-component color
+space without conversion, don't try to fake out the library by setting
+in_color_space and jpeg_color_space to JCS_YCbCr; use JCS_UNKNOWN.
+You may want to write an APPn marker of your own devising to identify
+the colorspace --- see "Special markers", below.
+
+When told that the color space is UNKNOWN, the library will default to using
+luminance-quality compression parameters for all color components.  You may
+well want to change these parameters.  See the source code for
+jpeg_set_colorspace(), in jcparam.c, for details.
+
+For decompression, the JPEG file's color space is given in jpeg_color_space,
+and this is transformed to the output color space out_color_space.
+jpeg_read_header's setting of jpeg_color_space can be relied on if the file
+conforms to JFIF or Adobe conventions, but otherwise it is no better than a
+guess.  If you know the JPEG file's color space for certain, you can override
+jpeg_read_header's guess by setting jpeg_color_space.  jpeg_read_header also
+selects a default output color space based on (its guess of) jpeg_color_space;
+set out_color_space to override this.  Again, you must select a supported
+transformation.  jdcolor.c currently supports
+	YCbCr => RGB
+	YCbCr => GRAYSCALE
+	BG_YCC => RGB
+	BG_YCC => GRAYSCALE
+	RGB => GRAYSCALE
+	GRAYSCALE => RGB
+	YCCK => CMYK
+as well as the null transforms.  (Since GRAYSCALE=>RGB is provided, an
+application can force grayscale JPEGs to look like color JPEGs if it only
+wants to handle one case.)
+
+The two-pass color quantizer, jquant2.c, is specialized to handle RGB data
+(it weights distances appropriately for RGB colors).  You'll need to modify
+the code if you want to use it for non-RGB output color spaces.  Note that
+jquant2.c is used to map to an application-supplied colormap as well as for
+the normal two-pass colormap selection process.
+
+CAUTION: it appears that Adobe Photoshop writes inverted data in CMYK JPEG
+files: 0 represents 100% ink coverage, rather than 0% ink as you'd expect.
+This is arguably a bug in Photoshop, but if you need to work with Photoshop
+CMYK files, you will have to deal with it in your application.  We cannot
+"fix" this in the library by inverting the data during the CMYK<=>YCCK
+transform, because that would break other applications, notably Ghostscript.
+Photoshop versions prior to 3.0 write EPS files containing JPEG-encoded CMYK
+data in the same inverted-YCCK representation used in bare JPEG files, but
+the surrounding PostScript code performs an inversion using the PS image
+operator.  I am told that Photoshop 3.0 will write uninverted YCCK in
+EPS/JPEG files, and will omit the PS-level inversion.  (But the data
+polarity used in bare JPEG files will not change in 3.0.)  In either case,
+the JPEG library must not invert the data itself, or else Ghostscript would
+read these EPS files incorrectly.
+
+
+Error handling
+--------------
+
+When the default error handler is used, any error detected inside the JPEG
+routines will cause a message to be printed on stderr, followed by exit().
+You can supply your own error handling routines to override this behavior
+and to control the treatment of nonfatal warnings and trace/debug messages.
+The file example.c illustrates the most common case, which is to have the
+application regain control after an error rather than exiting.
+
+The JPEG library never writes any message directly; it always goes through
+the error handling routines.  Three classes of messages are recognized:
+  * Fatal errors: the library cannot continue.
+  * Warnings: the library can continue, but the data is corrupt, and a
+    damaged output image is likely to result.
+  * Trace/informational messages.  These come with a trace level indicating
+    the importance of the message; you can control the verbosity of the
+    program by adjusting the maximum trace level that will be displayed.
+
+You may, if you wish, simply replace the entire JPEG error handling module
+(jerror.c) with your own code.  However, you can avoid code duplication by
+only replacing some of the routines depending on the behavior you need.
+This is accomplished by calling jpeg_std_error() as usual, but then overriding
+some of the method pointers in the jpeg_error_mgr struct, as illustrated by
+example.c.
+
+All of the error handling routines will receive a pointer to the JPEG object
+(a j_common_ptr which points to either a jpeg_compress_struct or a
+jpeg_decompress_struct; if you need to tell which, test the is_decompressor
+field).  This struct includes a pointer to the error manager struct in its
+"err" field.  Frequently, custom error handler routines will need to access
+additional data which is not known to the JPEG library or the standard error
+handler.  The most convenient way to do this is to embed either the JPEG
+object or the jpeg_error_mgr struct in a larger structure that contains
+additional fields; then casting the passed pointer provides access to the
+additional fields.  Again, see example.c for one way to do it.  (Beginning
+with IJG version 6b, there is also a void pointer "client_data" in each
+JPEG object, which the application can also use to find related data.
+The library does not touch client_data at all.)
+
+The individual methods that you might wish to override are:
+
+error_exit (j_common_ptr cinfo)
+	Receives control for a fatal error.  Information sufficient to
+	generate the error message has been stored in cinfo->err; call
+	output_message to display it.  Control must NOT return to the caller;
+	generally this routine will exit() or longjmp() somewhere.
+	Typically you would override this routine to get rid of the exit()
+	default behavior.  Note that if you continue processing, you should
+	clean up the JPEG object with jpeg_abort() or jpeg_destroy().
+
+output_message (j_common_ptr cinfo)
+	Actual output of any JPEG message.  Override this to send messages
+	somewhere other than stderr.  Note that this method does not know
+	how to generate a message, only where to send it.
+
+format_message (j_common_ptr cinfo, char * buffer)
+	Constructs a readable error message string based on the error info
+	stored in cinfo->err.  This method is called by output_message.  Few
+	applications should need to override this method.  One possible
+	reason for doing so is to implement dynamic switching of error message
+	language.
+
+emit_message (j_common_ptr cinfo, int msg_level)
+	Decide whether or not to emit a warning or trace message; if so,
+	calls output_message.  The main reason for overriding this method
+	would be to abort on warnings.  msg_level is -1 for warnings,
+	0 and up for trace messages.
+
+Only error_exit() and emit_message() are called from the rest of the JPEG
+library; the other two are internal to the error handler.
+
+The actual message texts are stored in an array of strings which is pointed to
+by the field err->jpeg_message_table.  The messages are numbered from 0 to
+err->last_jpeg_message, and it is these code numbers that are used in the
+JPEG library code.  You could replace the message texts (for instance, with
+messages in French or German) by changing the message table pointer.  See
+jerror.h for the default texts.  CAUTION: this table will almost certainly
+change or grow from one library version to the next.
+
+It may be useful for an application to add its own message texts that are
+handled by the same mechanism.  The error handler supports a second "add-on"
+message table for this purpose.  To define an addon table, set the pointer
+err->addon_message_table and the message numbers err->first_addon_message and
+err->last_addon_message.  If you number the addon messages beginning at 1000
+or so, you won't have to worry about conflicts with the library's built-in
+messages.  See the sample applications cjpeg/djpeg for an example of using
+addon messages (the addon messages are defined in cderror.h).
+
+Actual invocation of the error handler is done via macros defined in jerror.h:
+	ERREXITn(...)	for fatal errors
+	WARNMSn(...)	for corrupt-data warnings
+	TRACEMSn(...)	for trace and informational messages.
+These macros store the message code and any additional parameters into the
+error handler struct, then invoke the error_exit() or emit_message() method.
+The variants of each macro are for varying numbers of additional parameters.
+The additional parameters are inserted into the generated message using
+standard printf() format codes.
+
+See jerror.h and jerror.c for further details.
+
+
+Compressed data handling (source and destination managers)
+----------------------------------------------------------
+
+The JPEG compression library sends its compressed data to a "destination
+manager" module.  The default destination manager just writes the data to a
+memory buffer or to a stdio stream, but you can provide your own manager to
+do something else.  Similarly, the decompression library calls a "source
+manager" to obtain the compressed data; you can provide your own source
+manager if you want the data to come from somewhere other than a memory
+buffer or a stdio stream.
+
+In both cases, compressed data is processed a bufferload at a time: the
+destination or source manager provides a work buffer, and the library invokes
+the manager only when the buffer is filled or emptied.  (You could define a
+one-character buffer to force the manager to be invoked for each byte, but
+that would be rather inefficient.)  The buffer's size and location are
+controlled by the manager, not by the library.  For example, the memory
+source manager just makes the buffer pointer and length point to the original
+data in memory.  In this case the buffer-reload procedure will be invoked
+only if the decompressor ran off the end of the datastream, which would
+indicate an erroneous datastream.
+
+The work buffer is defined as an array of datatype JOCTET, which is generally
+"char" or "unsigned char".  On a machine where char is not exactly 8 bits
+wide, you must define JOCTET as a wider data type and then modify the data
+source and destination modules to transcribe the work arrays into 8-bit units
+on external storage.
+
+A data destination manager struct contains a pointer and count defining the
+next byte to write in the work buffer and the remaining free space:
+
+	JOCTET * next_output_byte;  /* => next byte to write in buffer */
+	size_t free_in_buffer;      /* # of byte spaces remaining in buffer */
+
+The library increments the pointer and decrements the count until the buffer
+is filled.  The manager's empty_output_buffer method must reset the pointer
+and count.  The manager is expected to remember the buffer's starting address
+and total size in private fields not visible to the library.
+
+A data destination manager provides three methods:
+
+init_destination (j_compress_ptr cinfo)
+	Initialize destination.  This is called by jpeg_start_compress()
+	before any data is actually written.  It must initialize
+	next_output_byte and free_in_buffer.  free_in_buffer must be
+	initialized to a positive value.
+
+empty_output_buffer (j_compress_ptr cinfo)
+	This is called whenever the buffer has filled (free_in_buffer
+	reaches zero).  In typical applications, it should write out the
+	*entire* buffer (use the saved start address and buffer length;
+	ignore the current state of next_output_byte and free_in_buffer).
+	Then reset the pointer & count to the start of the buffer, and
+	return TRUE indicating that the buffer has been dumped.
+	free_in_buffer must be set to a positive value when TRUE is
+	returned.  A FALSE return should only be used when I/O suspension is
+	desired (this operating mode is discussed in the next section).
+
+term_destination (j_compress_ptr cinfo)
+	Terminate destination --- called by jpeg_finish_compress() after all
+	data has been written.  In most applications, this must flush any
+	data remaining in the buffer.  Use either next_output_byte or
+	free_in_buffer to determine how much data is in the buffer.
+
+term_destination() is NOT called by jpeg_abort() or jpeg_destroy().  If you
+want the destination manager to be cleaned up during an abort, you must do it
+yourself.
+
+You will also need code to create a jpeg_destination_mgr struct, fill in its
+method pointers, and insert a pointer to the struct into the "dest" field of
+the JPEG compression object.  This can be done in-line in your setup code if
+you like, but it's probably cleaner to provide a separate routine similar to
+the jpeg_stdio_dest() or jpeg_mem_dest() routines of the supplied destination
+managers.
+
+Decompression source managers follow a parallel design, but with some
+additional frammishes.  The source manager struct contains a pointer and count
+defining the next byte to read from the work buffer and the number of bytes
+remaining:
+
+	const JOCTET * next_input_byte; /* => next byte to read from buffer */
+	size_t bytes_in_buffer;         /* # of bytes remaining in buffer */
+
+The library increments the pointer and decrements the count until the buffer
+is emptied.  The manager's fill_input_buffer method must reset the pointer and
+count.  In most applications, the manager must remember the buffer's starting
+address and total size in private fields not visible to the library.
+
+A data source manager provides five methods:
+
+init_source (j_decompress_ptr cinfo)
+	Initialize source.  This is called by jpeg_read_header() before any
+	data is actually read.  Unlike init_destination(), it may leave
+	bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
+	will occur immediately).
+
+fill_input_buffer (j_decompress_ptr cinfo)
+	This is called whenever bytes_in_buffer has reached zero and more
+	data is wanted.  In typical applications, it should read fresh data
+	into the buffer (ignoring the current state of next_input_byte and
+	bytes_in_buffer), reset the pointer & count to the start of the
+	buffer, and return TRUE indicating that the buffer has been reloaded.
+	It is not necessary to fill the buffer entirely, only to obtain at
+	least one more byte.  bytes_in_buffer MUST be set to a positive value
+	if TRUE is returned.  A FALSE return should only be used when I/O
+	suspension is desired (this mode is discussed in the next section).
+
+skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+	Skip num_bytes worth of data.  The buffer pointer and count should
+	be advanced over num_bytes input bytes, refilling the buffer as
+	needed.  This is used to skip over a potentially large amount of
+	uninteresting data (such as an APPn marker).  In some applications
+	it may be possible to optimize away the reading of the skipped data,
+	but it's not clear that being smart is worth much trouble; large
+	skips are uncommon.  bytes_in_buffer may be zero on return.
+	A zero or negative skip count should be treated as a no-op.
+
+resync_to_restart (j_decompress_ptr cinfo, int desired)
+	This routine is called only when the decompressor has failed to find
+	a restart (RSTn) marker where one is expected.  Its mission is to
+	find a suitable point for resuming decompression.  For most
+	applications, we recommend that you just use the default resync
+	procedure, jpeg_resync_to_restart().  However, if you are able to back
+	up in the input data stream, or if you have a-priori knowledge about
+	the likely location of restart markers, you may be able to do better.
+	Read the read_restart_marker() and jpeg_resync_to_restart() routines
+	in jdmarker.c if you think you'd like to implement your own resync
+	procedure.
+
+term_source (j_decompress_ptr cinfo)
+	Terminate source --- called by jpeg_finish_decompress() after all
+	data has been read.  Often a no-op.
+
+For both fill_input_buffer() and skip_input_data(), there is no such thing
+as an EOF return.  If the end of the file has been reached, the routine has
+a choice of exiting via ERREXIT() or inserting fake data into the buffer.
+In most cases, generating a warning message and inserting a fake EOI marker
+is the best course of action --- this will allow the decompressor to output
+however much of the image is there.  In pathological cases, the decompressor
+may swallow the EOI and again demand data ... just keep feeding it fake EOIs.
+jdatasrc.c illustrates the recommended error recovery behavior.
+
+term_source() is NOT called by jpeg_abort() or jpeg_destroy().  If you want
+the source manager to be cleaned up during an abort, you must do it yourself.
+
+You will also need code to create a jpeg_source_mgr struct, fill in its method
+pointers, and insert a pointer to the struct into the "src" field of the JPEG
+decompression object.  This can be done in-line in your setup code if you
+like, but it's probably cleaner to provide a separate routine similar to the
+jpeg_stdio_src() or jpeg_mem_src() routines of the supplied source managers.
+
+For more information, consult the memory and stdio source and destination
+managers in jdatasrc.c and jdatadst.c.
+
+
+I/O suspension
+--------------
+
+Some applications need to use the JPEG library as an incremental memory-to-
+memory filter: when the compressed data buffer is filled or emptied, they want
+control to return to the outer loop, rather than expecting that the buffer can
+be emptied or reloaded within the data source/destination manager subroutine.
+The library supports this need by providing an "I/O suspension" mode, which we
+describe in this section.
+
+The I/O suspension mode is not a panacea: nothing is guaranteed about the
+maximum amount of time spent in any one call to the library, so it will not
+eliminate response-time problems in single-threaded applications.  If you
+need guaranteed response time, we suggest you "bite the bullet" and implement
+a real multi-tasking capability.
+
+To use I/O suspension, cooperation is needed between the calling application
+and the data source or destination manager; you will always need a custom
+source/destination manager.  (Please read the previous section if you haven't
+already.)  The basic idea is that the empty_output_buffer() or
+fill_input_buffer() routine is a no-op, merely returning FALSE to indicate
+that it has done nothing.  Upon seeing this, the JPEG library suspends
+operation and returns to its caller.  The surrounding application is
+responsible for emptying or refilling the work buffer before calling the
+JPEG library again.
+
+Compression suspension:
+
+For compression suspension, use an empty_output_buffer() routine that returns
+FALSE; typically it will not do anything else.  This will cause the
+compressor to return to the caller of jpeg_write_scanlines(), with the return
+value indicating that not all the supplied scanlines have been accepted.
+The application must make more room in the output buffer, adjust the output
+buffer pointer/count appropriately, and then call jpeg_write_scanlines()
+again, pointing to the first unconsumed scanline.
+
+When forced to suspend, the compressor will backtrack to a convenient stopping
+point (usually the start of the current MCU); it will regenerate some output
+data when restarted.  Therefore, although empty_output_buffer() is only
+called when the buffer is filled, you should NOT write out the entire buffer
+after a suspension.  Write only the data up to the current position of
+next_output_byte/free_in_buffer.  The data beyond that point will be
+regenerated after resumption.
+
+Because of the backtracking behavior, a good-size output buffer is essential
+for efficiency; you don't want the compressor to suspend often.  (In fact, an
+overly small buffer could lead to infinite looping, if a single MCU required
+more data than would fit in the buffer.)  We recommend a buffer of at least
+several Kbytes.  You may want to insert explicit code to ensure that you don't
+call jpeg_write_scanlines() unless there is a reasonable amount of space in
+the output buffer; in other words, flush the buffer before trying to compress
+more data.
+
+The compressor does not allow suspension while it is trying to write JPEG
+markers at the beginning and end of the file.  This means that:
+  * At the beginning of a compression operation, there must be enough free
+    space in the output buffer to hold the header markers (typically 600 or
+    so bytes).  The recommended buffer size is bigger than this anyway, so
+    this is not a problem as long as you start with an empty buffer.  However,
+    this restriction might catch you if you insert large special markers, such
+    as a JFIF thumbnail image, without flushing the buffer afterwards.
+  * When you call jpeg_finish_compress(), there must be enough space in the
+    output buffer to emit any buffered data and the final EOI marker.  In the
+    current implementation, half a dozen bytes should suffice for this, but
+    for safety's sake we recommend ensuring that at least 100 bytes are free
+    before calling jpeg_finish_compress().
+
+A more significant restriction is that jpeg_finish_compress() cannot suspend.
+This means you cannot use suspension with multi-pass operating modes, namely
+Huffman code optimization and multiple-scan output.  Those modes write the
+whole file during jpeg_finish_compress(), which will certainly result in
+buffer overrun.  (Note that this restriction applies only to compression,
+not decompression.  The decompressor supports input suspension in all of its
+operating modes.)
+
+Decompression suspension:
+
+For decompression suspension, use a fill_input_buffer() routine that simply
+returns FALSE (except perhaps during error recovery, as discussed below).
+This will cause the decompressor to return to its caller with an indication
+that suspension has occurred.  This can happen at four places:
+  * jpeg_read_header(): will return JPEG_SUSPENDED.
+  * jpeg_start_decompress(): will return FALSE, rather than its usual TRUE.
+  * jpeg_read_scanlines(): will return the number of scanlines already
+	completed (possibly 0).
+  * jpeg_finish_decompress(): will return FALSE, rather than its usual TRUE.
+The surrounding application must recognize these cases, load more data into
+the input buffer, and repeat the call.  In the case of jpeg_read_scanlines(),
+increment the passed pointers past any scanlines successfully read.
+
+Just as with compression, the decompressor will typically backtrack to a
+convenient restart point before suspending.  When fill_input_buffer() is
+called, next_input_byte/bytes_in_buffer point to the current restart point,
+which is where the decompressor will backtrack to if FALSE is returned.
+The data beyond that position must NOT be discarded if you suspend; it needs
+to be re-read upon resumption.  In most implementations, you'll need to shift
+this data down to the start of your work buffer and then load more data after
+it.  Again, this behavior means that a several-Kbyte work buffer is essential
+for decent performance; furthermore, you should load a reasonable amount of
+new data before resuming decompression.  (If you loaded, say, only one new
+byte each time around, you could waste a LOT of cycles.)
+
+The skip_input_data() source manager routine requires special care in a
+suspension scenario.  This routine is NOT granted the ability to suspend the
+decompressor; it can decrement bytes_in_buffer to zero, but no more.  If the
+requested skip distance exceeds the amount of data currently in the input
+buffer, then skip_input_data() must set bytes_in_buffer to zero and record the
+additional skip distance somewhere else.  The decompressor will immediately
+call fill_input_buffer(), which should return FALSE, which will cause a
+suspension return.  The surrounding application must then arrange to discard
+the recorded number of bytes before it resumes loading the input buffer.
+(Yes, this design is rather baroque, but it avoids complexity in the far more
+common case where a non-suspending source manager is used.)
+
+If the input data has been exhausted, we recommend that you emit a warning
+and insert dummy EOI markers just as a non-suspending data source manager
+would do.  This can be handled either in the surrounding application logic or
+within fill_input_buffer(); the latter is probably more efficient.  If
+fill_input_buffer() knows that no more data is available, it can set the
+pointer/count to point to a dummy EOI marker and then return TRUE just as
+though it had read more data in a non-suspending situation.
+
+The decompressor does not attempt to suspend within standard JPEG markers;
+instead it will backtrack to the start of the marker and reprocess the whole
+marker next time.  Hence the input buffer must be large enough to hold the
+longest standard marker in the file.  Standard JPEG markers should normally
+not exceed a few hundred bytes each (DHT tables are typically the longest).
+We recommend at least a 2K buffer for performance reasons, which is much
+larger than any correct marker is likely to be.  For robustness against
+damaged marker length counts, you may wish to insert a test in your
+application for the case that the input buffer is completely full and yet
+the decoder has suspended without consuming any data --- otherwise, if this
+situation did occur, it would lead to an endless loop.  (The library can't
+provide this test since it has no idea whether "the buffer is full", or
+even whether there is a fixed-size input buffer.)
+
+The input buffer would need to be 64K to allow for arbitrary COM or APPn
+markers, but these are handled specially: they are either saved into allocated
+memory, or skipped over by calling skip_input_data().  In the former case,
+suspension is handled correctly, and in the latter case, the problem of
+buffer overrun is placed on skip_input_data's shoulders, as explained above.
+Note that if you provide your own marker handling routine for large markers,
+you should consider how to deal with buffer overflow.
+
+Multiple-buffer management:
+
+In some applications it is desirable to store the compressed data in a linked
+list of buffer areas, so as to avoid data copying.  This can be handled by
+having empty_output_buffer() or fill_input_buffer() set the pointer and count
+to reference the next available buffer; FALSE is returned only if no more
+buffers are available.  Although seemingly straightforward, there is a
+pitfall in this approach: the backtrack that occurs when FALSE is returned
+could back up into an earlier buffer.  For example, when fill_input_buffer()
+is called, the current pointer & count indicate the backtrack restart point.
+Since fill_input_buffer() will set the pointer and count to refer to a new
+buffer, the restart position must be saved somewhere else.  Suppose a second
+call to fill_input_buffer() occurs in the same library call, and no
+additional input data is available, so fill_input_buffer must return FALSE.
+If the JPEG library has not moved the pointer/count forward in the current
+buffer, then *the correct restart point is the saved position in the prior
+buffer*.  Prior buffers may be discarded only after the library establishes
+a restart point within a later buffer.  Similar remarks apply for output into
+a chain of buffers.
+
+The library will never attempt to backtrack over a skip_input_data() call,
+so any skipped data can be permanently discarded.  You still have to deal
+with the case of skipping not-yet-received data, however.
+
+It's much simpler to use only a single buffer; when fill_input_buffer() is
+called, move any unconsumed data (beyond the current pointer/count) down to
+the beginning of this buffer and then load new data into the remaining buffer
+space.  This approach requires a little more data copying but is far easier
+to get right.
+
+
+Progressive JPEG support
+------------------------
+
+Progressive JPEG rearranges the stored data into a series of scans of
+increasing quality.  In situations where a JPEG file is transmitted across a
+slow communications link, a decoder can generate a low-quality image very
+quickly from the first scan, then gradually improve the displayed quality as
+more scans are received.  The final image after all scans are complete is
+identical to that of a regular (sequential) JPEG file of the same quality
+setting.  Progressive JPEG files are often slightly smaller than equivalent
+sequential JPEG files, but the possibility of incremental display is the main
+reason for using progressive JPEG.
+
+The IJG encoder library generates progressive JPEG files when given a
+suitable "scan script" defining how to divide the data into scans.
+Creation of progressive JPEG files is otherwise transparent to the encoder.
+Progressive JPEG files can also be read transparently by the decoder library.
+If the decoding application simply uses the library as defined above, it
+will receive a final decoded image without any indication that the file was
+progressive.  Of course, this approach does not allow incremental display.
+To perform incremental display, an application needs to use the decoder
+library's "buffered-image" mode, in which it receives a decoded image
+multiple times.
+
+Each displayed scan requires about as much work to decode as a full JPEG
+image of the same size, so the decoder must be fairly fast in relation to the
+data transmission rate in order to make incremental display useful.  However,
+it is possible to skip displaying the image and simply add the incoming bits
+to the decoder's coefficient buffer.  This is fast because only Huffman
+decoding need be done, not IDCT, upsampling, colorspace conversion, etc.
+The IJG decoder library allows the application to switch dynamically between
+displaying the image and simply absorbing the incoming bits.  A properly
+coded application can automatically adapt the number of display passes to
+suit the time available as the image is received.  Also, a final
+higher-quality display cycle can be performed from the buffered data after
+the end of the file is reached.
+
+Progressive compression:
+
+To create a progressive JPEG file (or a multiple-scan sequential JPEG file),
+set the scan_info cinfo field to point to an array of scan descriptors, and
+perform compression as usual.  Instead of constructing your own scan list,
+you can call the jpeg_simple_progression() helper routine to create a
+recommended progression sequence; this method should be used by all
+applications that don't want to get involved in the nitty-gritty of
+progressive scan sequence design.  (If you want to provide user control of
+scan sequences, you may wish to borrow the scan script reading code found
+in rdswitch.c, so that you can read scan script files just like cjpeg's.)
+When scan_info is not NULL, the compression library will store DCT'd data
+into a buffer array as jpeg_write_scanlines() is called, and will emit all
+the requested scans during jpeg_finish_compress().  This implies that
+multiple-scan output cannot be created with a suspending data destination
+manager, since jpeg_finish_compress() does not support suspension.  We
+should also note that the compressor currently forces Huffman optimization
+mode when creating a progressive JPEG file, because the default Huffman
+tables are unsuitable for progressive files.
+
+Progressive decompression:
+
+When buffered-image mode is not used, the decoder library will read all of
+a multi-scan file during jpeg_start_decompress(), so that it can provide a
+final decoded image.  (Here "multi-scan" means either progressive or
+multi-scan sequential.)  This makes multi-scan files transparent to the
+decoding application.  However, existing applications that used suspending
+input with version 5 of the IJG library will need to be modified to check
+for a suspension return from jpeg_start_decompress().
+
+To perform incremental display, an application must use the library's
+buffered-image mode.  This is described in the next section.
+
+
+Buffered-image mode
+-------------------
+
+In buffered-image mode, the library stores the partially decoded image in a
+coefficient buffer, from which it can be read out as many times as desired.
+This mode is typically used for incremental display of progressive JPEG files,
+but it can be used with any JPEG file.  Each scan of a progressive JPEG file
+adds more data (more detail) to the buffered image.  The application can
+display in lockstep with the source file (one display pass per input scan),
+or it can allow input processing to outrun display processing.  By making
+input and display processing run independently, it is possible for the
+application to adapt progressive display to a wide range of data transmission
+rates.
+
+The basic control flow for buffered-image decoding is
+
+	jpeg_create_decompress()
+	set data source
+	jpeg_read_header()
+	set overall decompression parameters
+	cinfo.buffered_image = TRUE;	/* select buffered-image mode */
+	jpeg_start_decompress()
+	for (each output pass) {
+	    adjust output decompression parameters if required
+	    jpeg_start_output()		/* start a new output pass */
+	    for (all scanlines in image) {
+	        jpeg_read_scanlines()
+	        display scanlines
+	    }
+	    jpeg_finish_output()	/* terminate output pass */
+	}
+	jpeg_finish_decompress()
+	jpeg_destroy_decompress()
+
+This differs from ordinary unbuffered decoding in that there is an additional
+level of looping.  The application can choose how many output passes to make
+and how to display each pass.
+
+The simplest approach to displaying progressive images is to do one display
+pass for each scan appearing in the input file.  In this case the outer loop
+condition is typically
+	while (! jpeg_input_complete(&cinfo))
+and the start-output call should read
+	jpeg_start_output(&cinfo, cinfo.input_scan_number);
+The second parameter to jpeg_start_output() indicates which scan of the input
+file is to be displayed; the scans are numbered starting at 1 for this
+purpose.  (You can use a loop counter starting at 1 if you like, but using
+the library's input scan counter is easier.)  The library automatically reads
+data as necessary to complete each requested scan, and jpeg_finish_output()
+advances to the next scan or end-of-image marker (hence input_scan_number
+will be incremented by the time control arrives back at jpeg_start_output()).
+With this technique, data is read from the input file only as needed, and
+input and output processing run in lockstep.
+
+After reading the final scan and reaching the end of the input file, the
+buffered image remains available; it can be read additional times by
+repeating the jpeg_start_output()/jpeg_read_scanlines()/jpeg_finish_output()
+sequence.  For example, a useful technique is to use fast one-pass color
+quantization for display passes made while the image is arriving, followed by
+a final display pass using two-pass quantization for highest quality.  This
+is done by changing the library parameters before the final output pass.
+Changing parameters between passes is discussed in detail below.
+
+In general the last scan of a progressive file cannot be recognized as such
+until after it is read, so a post-input display pass is the best approach if
+you want special processing in the final pass.
+
+When done with the image, be sure to call jpeg_finish_decompress() to release
+the buffered image (or just use jpeg_destroy_decompress()).
+
+If input data arrives faster than it can be displayed, the application can
+cause the library to decode input data in advance of what's needed to produce
+output.  This is done by calling the routine jpeg_consume_input().
+The return value is one of the following:
+	JPEG_REACHED_SOS:    reached an SOS marker (the start of a new scan)
+	JPEG_REACHED_EOI:    reached the EOI marker (end of image)
+	JPEG_ROW_COMPLETED:  completed reading one MCU row of compressed data
+	JPEG_SCAN_COMPLETED: completed reading last MCU row of current scan
+	JPEG_SUSPENDED:      suspended before completing any of the above
+(JPEG_SUSPENDED can occur only if a suspending data source is used.)  This
+routine can be called at any time after initializing the JPEG object.  It
+reads some additional data and returns when one of the indicated significant
+events occurs.  (If called after the EOI marker is reached, it will
+immediately return JPEG_REACHED_EOI without attempting to read more data.)
+
+The library's output processing will automatically call jpeg_consume_input()
+whenever the output processing overtakes the input; thus, simple lockstep
+display requires no direct calls to jpeg_consume_input().  But by adding
+calls to jpeg_consume_input(), you can absorb data in advance of what is
+being displayed.  This has two benefits:
+  * You can limit buildup of unprocessed data in your input buffer.
+  * You can eliminate extra display passes by paying attention to the
+    state of the library's input processing.
+
+The first of these benefits only requires interspersing calls to
+jpeg_consume_input() with your display operations and any other processing
+you may be doing.  To avoid wasting cycles due to backtracking, it's best to
+call jpeg_consume_input() only after a hundred or so new bytes have arrived.
+This is discussed further under "I/O suspension", above.  (Note: the JPEG
+library currently is not thread-safe.  You must not call jpeg_consume_input()
+from one thread of control if a different library routine is working on the
+same JPEG object in another thread.)
+
+When input arrives fast enough that more than one new scan is available
+before you start a new output pass, you may as well skip the output pass
+corresponding to the completed scan.  This occurs for free if you pass
+cinfo.input_scan_number as the target scan number to jpeg_start_output().
+The input_scan_number field is simply the index of the scan currently being
+consumed by the input processor.  You can ensure that this is up-to-date by
+emptying the input buffer just before calling jpeg_start_output(): call
+jpeg_consume_input() repeatedly until it returns JPEG_SUSPENDED or
+JPEG_REACHED_EOI.
+
+The target scan number passed to jpeg_start_output() is saved in the
+cinfo.output_scan_number field.  The library's output processing calls
+jpeg_consume_input() whenever the current input scan number and row within
+that scan is less than or equal to the current output scan number and row.
+Thus, input processing can "get ahead" of the output processing but is not
+allowed to "fall behind".  You can achieve several different effects by
+manipulating this interlock rule.  For example, if you pass a target scan
+number greater than the current input scan number, the output processor will
+wait until that scan starts to arrive before producing any output.  (To avoid
+an infinite loop, the target scan number is automatically reset to the last
+scan number when the end of image is reached.  Thus, if you specify a large
+target scan number, the library will just absorb the entire input file and
+then perform an output pass.  This is effectively the same as what
+jpeg_start_decompress() does when you don't select buffered-image mode.)
+When you pass a target scan number equal to the current input scan number,
+the image is displayed no faster than the current input scan arrives.  The
+final possibility is to pass a target scan number less than the current input
+scan number; this disables the input/output interlock and causes the output
+processor to simply display whatever it finds in the image buffer, without
+waiting for input.  (However, the library will not accept a target scan
+number less than one, so you can't avoid waiting for the first scan.)
+
+When data is arriving faster than the output display processing can advance
+through the image, jpeg_consume_input() will store data into the buffered
+image beyond the point at which the output processing is reading data out
+again.  If the input arrives fast enough, it may "wrap around" the buffer to
+the point where the input is more than one whole scan ahead of the output.
+If the output processing simply proceeds through its display pass without
+paying attention to the input, the effect seen on-screen is that the lower
+part of the image is one or more scans better in quality than the upper part.
+Then, when the next output scan is started, you have a choice of what target
+scan number to use.  The recommended choice is to use the current input scan
+number at that time, which implies that you've skipped the output scans
+corresponding to the input scans that were completed while you processed the
+previous output scan.  In this way, the decoder automatically adapts its
+speed to the arriving data, by skipping output scans as necessary to keep up
+with the arriving data.
+
+When using this strategy, you'll want to be sure that you perform a final
+output pass after receiving all the data; otherwise your last display may not
+be full quality across the whole screen.  So the right outer loop logic is
+something like this:
+	do {
+	    absorb any waiting input by calling jpeg_consume_input()
+	    final_pass = jpeg_input_complete(&cinfo);
+	    adjust output decompression parameters if required
+	    jpeg_start_output(&cinfo, cinfo.input_scan_number);
+	    ...
+	    jpeg_finish_output()
+	} while (! final_pass);
+rather than quitting as soon as jpeg_input_complete() returns TRUE.  This
+arrangement makes it simple to use higher-quality decoding parameters
+for the final pass.  But if you don't want to use special parameters for
+the final pass, the right loop logic is like this:
+	for (;;) {
+	    absorb any waiting input by calling jpeg_consume_input()
+	    jpeg_start_output(&cinfo, cinfo.input_scan_number);
+	    ...
+	    jpeg_finish_output()
+	    if (jpeg_input_complete(&cinfo) &&
+	        cinfo.input_scan_number == cinfo.output_scan_number)
+	      break;
+	}
+In this case you don't need to know in advance whether an output pass is to
+be the last one, so it's not necessary to have reached EOF before starting
+the final output pass; rather, what you want to test is whether the output
+pass was performed in sync with the final input scan.  This form of the loop
+will avoid an extra output pass whenever the decoder is able (or nearly able)
+to keep up with the incoming data.
+
+When the data transmission speed is high, you might begin a display pass,
+then find that much or all of the file has arrived before you can complete
+the pass.  (You can detect this by noting the JPEG_REACHED_EOI return code
+from jpeg_consume_input(), or equivalently by testing jpeg_input_complete().)
+In this situation you may wish to abort the current display pass and start a
+new one using the newly arrived information.  To do so, just call
+jpeg_finish_output() and then start a new pass with jpeg_start_output().
+
+A variant strategy is to abort and restart display if more than one complete
+scan arrives during an output pass; this can be detected by noting
+JPEG_REACHED_SOS returns and/or examining cinfo.input_scan_number.  This
+idea should be employed with caution, however, since the display process
+might never get to the bottom of the image before being aborted, resulting
+in the lower part of the screen being several passes worse than the upper.
+In most cases it's probably best to abort an output pass only if the whole
+file has arrived and you want to begin the final output pass immediately.
+
+When receiving data across a communication link, we recommend always using
+the current input scan number for the output target scan number; if a
+higher-quality final pass is to be done, it should be started (aborting any
+incomplete output pass) as soon as the end of file is received.  However,
+many other strategies are possible.  For example, the application can examine
+the parameters of the current input scan and decide whether to display it or
+not.  If the scan contains only chroma data, one might choose not to use it
+as the target scan, expecting that the scan will be small and will arrive
+quickly.  To skip to the next scan, call jpeg_consume_input() until it
+returns JPEG_REACHED_SOS or JPEG_REACHED_EOI.  Or just use the next higher
+number as the target scan for jpeg_start_output(); but that method doesn't
+let you inspect the next scan's parameters before deciding to display it.
+
+
+In buffered-image mode, jpeg_start_decompress() never performs input and
+thus never suspends.  An application that uses input suspension with
+buffered-image mode must be prepared for suspension returns from these
+routines:
+* jpeg_start_output() performs input only if you request 2-pass quantization
+  and the target scan isn't fully read yet.  (This is discussed below.)
+* jpeg_read_scanlines(), as always, returns the number of scanlines that it
+  was able to produce before suspending.
+* jpeg_finish_output() will read any markers following the target scan,
+  up to the end of the file or the SOS marker that begins another scan.
+  (But it reads no input if jpeg_consume_input() has already reached the
+  end of the file or a SOS marker beyond the target output scan.)
+* jpeg_finish_decompress() will read until the end of file, and thus can
+  suspend if the end hasn't already been reached (as can be tested by
+  calling jpeg_input_complete()).
+jpeg_start_output(), jpeg_finish_output(), and jpeg_finish_decompress()
+all return TRUE if they completed their tasks, FALSE if they had to suspend.
+In the event of a FALSE return, the application must load more input data
+and repeat the call.  Applications that use non-suspending data sources need
+not check the return values of these three routines.
+
+
+It is possible to change decoding parameters between output passes in the
+buffered-image mode.  The decoder library currently supports only very
+limited changes of parameters.  ONLY THE FOLLOWING parameter changes are
+allowed after jpeg_start_decompress() is called:
+* dct_method can be changed before each call to jpeg_start_output().
+  For example, one could use a fast DCT method for early scans, changing
+  to a higher quality method for the final scan.
+* dither_mode can be changed before each call to jpeg_start_output();
+  of course this has no impact if not using color quantization.  Typically
+  one would use ordered dither for initial passes, then switch to
+  Floyd-Steinberg dither for the final pass.  Caution: changing dither mode
+  can cause more memory to be allocated by the library.  Although the amount
+  of memory involved is not large (a scanline or so), it may cause the
+  initial max_memory_to_use specification to be exceeded, which in the worst
+  case would result in an out-of-memory failure.
+* do_block_smoothing can be changed before each call to jpeg_start_output().
+  This setting is relevant only when decoding a progressive JPEG image.
+  During the first DC-only scan, block smoothing provides a very "fuzzy" look
+  instead of the very "blocky" look seen without it; which is better seems a
+  matter of personal taste.  But block smoothing is nearly always a win
+  during later stages, especially when decoding a successive-approximation
+  image: smoothing helps to hide the slight blockiness that otherwise shows
+  up on smooth gradients until the lowest coefficient bits are sent.
+* Color quantization mode can be changed under the rules described below.
+  You *cannot* change between full-color and quantized output (because that
+  would alter the required I/O buffer sizes), but you can change which
+  quantization method is used.
+
+When generating color-quantized output, changing quantization method is a
+very useful way of switching between high-speed and high-quality display.
+The library allows you to change among its three quantization methods:
+1. Single-pass quantization to a fixed color cube.
+   Selected by cinfo.two_pass_quantize = FALSE and cinfo.colormap = NULL.
+2. Single-pass quantization to an application-supplied colormap.
+   Selected by setting cinfo.colormap to point to the colormap (the value of
+   two_pass_quantize is ignored); also set cinfo.actual_number_of_colors.
+3. Two-pass quantization to a colormap chosen specifically for the image.
+   Selected by cinfo.two_pass_quantize = TRUE and cinfo.colormap = NULL.
+   (This is the default setting selected by jpeg_read_header, but it is
+   probably NOT what you want for the first pass of progressive display!)
+These methods offer successively better quality and lesser speed.  However,
+only the first method is available for quantizing in non-RGB color spaces.
+
+IMPORTANT: because the different quantizer methods have very different
+working-storage requirements, the library requires you to indicate which
+one(s) you intend to use before you call jpeg_start_decompress().  (If we did
+not require this, the max_memory_to_use setting would be a complete fiction.)
+You do this by setting one or more of these three cinfo fields to TRUE:
+	enable_1pass_quant		Fixed color cube colormap
+	enable_external_quant		Externally-supplied colormap
+	enable_2pass_quant		Two-pass custom colormap
+All three are initialized FALSE by jpeg_read_header().  But
+jpeg_start_decompress() automatically sets TRUE the one selected by the
+current two_pass_quantize and colormap settings, so you only need to set the
+enable flags for any other quantization methods you plan to change to later.
+
+After setting the enable flags correctly at jpeg_start_decompress() time, you
+can change to any enabled quantization method by setting two_pass_quantize
+and colormap properly just before calling jpeg_start_output().  The following
+special rules apply:
+1. You must explicitly set cinfo.colormap to NULL when switching to 1-pass
+   or 2-pass mode from a different mode, or when you want the 2-pass
+   quantizer to be re-run to generate a new colormap.
+2. To switch to an external colormap, or to change to a different external
+   colormap than was used on the prior pass, you must call
+   jpeg_new_colormap() after setting cinfo.colormap.
+NOTE: if you want to use the same colormap as was used in the prior pass,
+you should not do either of these things.  This will save some nontrivial
+switchover costs.
+(These requirements exist because cinfo.colormap will always be non-NULL
+after completing a prior output pass, since both the 1-pass and 2-pass
+quantizers set it to point to their output colormaps.  Thus you have to
+do one of these two things to notify the library that something has changed.
+Yup, it's a bit klugy, but it's necessary to do it this way for backwards
+compatibility.)
+
+Note that in buffered-image mode, the library generates any requested colormap
+during jpeg_start_output(), not during jpeg_start_decompress().
+
+When using two-pass quantization, jpeg_start_output() makes a pass over the
+buffered image to determine the optimum color map; it therefore may take a
+significant amount of time, whereas ordinarily it does little work.  The
+progress monitor hook is called during this pass, if defined.  It is also
+important to realize that if the specified target scan number is greater than
+or equal to the current input scan number, jpeg_start_output() will attempt
+to consume input as it makes this pass.  If you use a suspending data source,
+you need to check for a FALSE return from jpeg_start_output() under these
+conditions.  The combination of 2-pass quantization and a not-yet-fully-read
+target scan is the only case in which jpeg_start_output() will consume input.
+
+
+Application authors who support buffered-image mode may be tempted to use it
+for all JPEG images, even single-scan ones.  This will work, but it is
+inefficient: there is no need to create an image-sized coefficient buffer for
+single-scan images.  Requesting buffered-image mode for such an image wastes
+memory.  Worse, it can cost time on large images, since the buffered data has
+to be swapped out or written to a temporary file.  If you are concerned about
+maximum performance on baseline JPEG files, you should use buffered-image
+mode only when the incoming file actually has multiple scans.  This can be
+tested by calling jpeg_has_multiple_scans(), which will return a correct
+result at any time after jpeg_read_header() completes.
+
+It is also worth noting that when you use jpeg_consume_input() to let input
+processing get ahead of output processing, the resulting pattern of access to
+the coefficient buffer is quite nonsequential.  It's best to use the memory
+manager jmemnobs.c if you can (ie, if you have enough real or virtual main
+memory).  If not, at least make sure that max_memory_to_use is set as high as
+possible.  If the JPEG memory manager has to use a temporary file, you will
+probably see a lot of disk traffic and poor performance.  (This could be
+improved with additional work on the memory manager, but we haven't gotten
+around to it yet.)
+
+In some applications it may be convenient to use jpeg_consume_input() for all
+input processing, including reading the initial markers; that is, you may
+wish to call jpeg_consume_input() instead of jpeg_read_header() during
+startup.  This works, but note that you must check for JPEG_REACHED_SOS and
+JPEG_REACHED_EOI return codes as the equivalent of jpeg_read_header's codes.
+Once the first SOS marker has been reached, you must call
+jpeg_start_decompress() before jpeg_consume_input() will consume more input;
+it'll just keep returning JPEG_REACHED_SOS until you do.  If you read a
+tables-only file this way, jpeg_consume_input() will return JPEG_REACHED_EOI
+without ever returning JPEG_REACHED_SOS; be sure to check for this case.
+If this happens, the decompressor will not read any more input until you call
+jpeg_abort() to reset it.  It is OK to call jpeg_consume_input() even when not
+using buffered-image mode, but in that case it's basically a no-op after the
+initial markers have been read: it will just return JPEG_SUSPENDED.
+
+
+Abbreviated datastreams and multiple images
+-------------------------------------------
+
+A JPEG compression or decompression object can be reused to process multiple
+images.  This saves a small amount of time per image by eliminating the
+"create" and "destroy" operations, but that isn't the real purpose of the
+feature.  Rather, reuse of an object provides support for abbreviated JPEG
+datastreams.  Object reuse can also simplify processing a series of images in
+a single input or output file.  This section explains these features.
+
+A JPEG file normally contains several hundred bytes worth of quantization
+and Huffman tables.  In a situation where many images will be stored or
+transmitted with identical tables, this may represent an annoying overhead.
+The JPEG standard therefore permits tables to be omitted.  The standard
+defines three classes of JPEG datastreams:
+  * "Interchange" datastreams contain an image and all tables needed to decode
+     the image.  These are the usual kind of JPEG file.
+  * "Abbreviated image" datastreams contain an image, but are missing some or
+    all of the tables needed to decode that image.
+  * "Abbreviated table specification" (henceforth "tables-only") datastreams
+    contain only table specifications.
+To decode an abbreviated image, it is necessary to load the missing table(s)
+into the decoder beforehand.  This can be accomplished by reading a separate
+tables-only file.  A variant scheme uses a series of images in which the first
+image is an interchange (complete) datastream, while subsequent ones are
+abbreviated and rely on the tables loaded by the first image.  It is assumed
+that once the decoder has read a table, it will remember that table until a
+new definition for the same table number is encountered.
+
+It is the application designer's responsibility to figure out how to associate
+the correct tables with an abbreviated image.  While abbreviated datastreams
+can be useful in a closed environment, their use is strongly discouraged in
+any situation where data exchange with other applications might be needed.
+Caveat designer.
+
+The JPEG library provides support for reading and writing any combination of
+tables-only datastreams and abbreviated images.  In both compression and
+decompression objects, a quantization or Huffman table will be retained for
+the lifetime of the object, unless it is overwritten by a new table definition.
+
+
+To create abbreviated image datastreams, it is only necessary to tell the
+compressor not to emit some or all of the tables it is using.  Each
+quantization and Huffman table struct contains a boolean field "sent_table",
+which normally is initialized to FALSE.  For each table used by the image, the
+header-writing process emits the table and sets sent_table = TRUE unless it is
+already TRUE.  (In normal usage, this prevents outputting the same table
+definition multiple times, as would otherwise occur because the chroma
+components typically share tables.)  Thus, setting this field to TRUE before
+calling jpeg_start_compress() will prevent the table from being written at
+all.
+
+If you want to create a "pure" abbreviated image file containing no tables,
+just call "jpeg_suppress_tables(&cinfo, TRUE)" after constructing all the
+tables.  If you want to emit some but not all tables, you'll need to set the
+individual sent_table fields directly.
+
+To create an abbreviated image, you must also call jpeg_start_compress()
+with a second parameter of FALSE, not TRUE.  Otherwise jpeg_start_compress()
+will force all the sent_table fields to FALSE.  (This is a safety feature to
+prevent abbreviated images from being created accidentally.)
+
+To create a tables-only file, perform the same parameter setup that you
+normally would, but instead of calling jpeg_start_compress() and so on, call
+jpeg_write_tables(&cinfo).  This will write an abbreviated datastream
+containing only SOI, DQT and/or DHT markers, and EOI.  All the quantization
+and Huffman tables that are currently defined in the compression object will
+be emitted unless their sent_tables flag is already TRUE, and then all the
+sent_tables flags will be set TRUE.
+
+A sure-fire way to create matching tables-only and abbreviated image files
+is to proceed as follows:
+
+	create JPEG compression object
+	set JPEG parameters
+	set destination to tables-only file
+	jpeg_write_tables(&cinfo);
+	set destination to image file
+	jpeg_start_compress(&cinfo, FALSE);
+	write data...
+	jpeg_finish_compress(&cinfo);
+
+Since the JPEG parameters are not altered between writing the table file and
+the abbreviated image file, the same tables are sure to be used.  Of course,
+you can repeat the jpeg_start_compress() ... jpeg_finish_compress() sequence
+many times to produce many abbreviated image files matching the table file.
+
+You cannot suppress output of the computed Huffman tables when Huffman
+optimization is selected.  (If you could, there'd be no way to decode the
+image...)  Generally, you don't want to set optimize_coding = TRUE when
+you are trying to produce abbreviated files.
+
+In some cases you might want to compress an image using tables which are
+not stored in the application, but are defined in an interchange or
+tables-only file readable by the application.  This can be done by setting up
+a JPEG decompression object to read the specification file, then copying the
+tables into your compression object.  See jpeg_copy_critical_parameters()
+for an example of copying quantization tables.
+
+
+To read abbreviated image files, you simply need to load the proper tables
+into the decompression object before trying to read the abbreviated image.
+If the proper tables are stored in the application program, you can just
+allocate the table structs and fill in their contents directly.  For example,
+to load a fixed quantization table into table slot "n":
+
+    if (cinfo.quant_tbl_ptrs[n] == NULL)
+      cinfo.quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) &cinfo);
+    quant_ptr = cinfo.quant_tbl_ptrs[n];	/* quant_ptr is JQUANT_TBL* */
+    for (i = 0; i < 64; i++) {
+      /* Qtable[] is desired quantization table, in natural array order */
+      quant_ptr->quantval[i] = Qtable[i];
+    }
+
+Code to load a fixed Huffman table is typically (for AC table "n"):
+
+    if (cinfo.ac_huff_tbl_ptrs[n] == NULL)
+      cinfo.ac_huff_tbl_ptrs[n] = jpeg_alloc_huff_table((j_common_ptr) &cinfo);
+    huff_ptr = cinfo.ac_huff_tbl_ptrs[n];	/* huff_ptr is JHUFF_TBL* */
+    for (i = 1; i <= 16; i++) {
+      /* counts[i] is number of Huffman codes of length i bits, i=1..16 */
+      huff_ptr->bits[i] = counts[i];
+    }
+    for (i = 0; i < 256; i++) {
+      /* symbols[] is the list of Huffman symbols, in code-length order */
+      huff_ptr->huffval[i] = symbols[i];
+    }
+
+(Note that trying to set cinfo.quant_tbl_ptrs[n] to point directly at a
+constant JQUANT_TBL object is not safe.  If the incoming file happened to
+contain a quantization table definition, your master table would get
+overwritten!  Instead allocate a working table copy and copy the master table
+into it, as illustrated above.  Ditto for Huffman tables, of course.)
+
+You might want to read the tables from a tables-only file, rather than
+hard-wiring them into your application.  The jpeg_read_header() call is
+sufficient to read a tables-only file.  You must pass a second parameter of
+FALSE to indicate that you do not require an image to be present.  Thus, the
+typical scenario is
+
+	create JPEG decompression object
+	set source to tables-only file
+	jpeg_read_header(&cinfo, FALSE);
+	set source to abbreviated image file
+	jpeg_read_header(&cinfo, TRUE);
+	set decompression parameters
+	jpeg_start_decompress(&cinfo);
+	read data...
+	jpeg_finish_decompress(&cinfo);
+
+In some cases, you may want to read a file without knowing whether it contains
+an image or just tables.  In that case, pass FALSE and check the return value
+from jpeg_read_header(): it will be JPEG_HEADER_OK if an image was found,
+JPEG_HEADER_TABLES_ONLY if only tables were found.  (A third return value,
+JPEG_SUSPENDED, is possible when using a suspending data source manager.)
+Note that jpeg_read_header() will not complain if you read an abbreviated
+image for which you haven't loaded the missing tables; the missing-table check
+occurs later, in jpeg_start_decompress().
+
+
+It is possible to read a series of images from a single source file by
+repeating the jpeg_read_header() ... jpeg_finish_decompress() sequence,
+without releasing/recreating the JPEG object or the data source module.
+(If you did reinitialize, any partial bufferload left in the data source
+buffer at the end of one image would be discarded, causing you to lose the
+start of the next image.)  When you use this method, stored tables are
+automatically carried forward, so some of the images can be abbreviated images
+that depend on tables from earlier images.
+
+If you intend to write a series of images into a single destination file,
+you might want to make a specialized data destination module that doesn't
+flush the output buffer at term_destination() time.  This would speed things
+up by some trifling amount.  Of course, you'd need to remember to flush the
+buffer after the last image.  You can make the later images be abbreviated
+ones by passing FALSE to jpeg_start_compress().
+
+
+Special markers
+---------------
+
+Some applications may need to insert or extract special data in the JPEG
+datastream.  The JPEG standard provides marker types "COM" (comment) and
+"APP0" through "APP15" (application) to hold application-specific data.
+Unfortunately, the use of these markers is not specified by the standard.
+COM markers are fairly widely used to hold user-supplied text.  The JFIF file
+format spec uses APP0 markers with specified initial strings to hold certain
+data.  Adobe applications use APP14 markers beginning with the string "Adobe"
+for miscellaneous data.  Other APPn markers are rarely seen, but might
+contain almost anything.
+
+If you wish to store user-supplied text, we recommend you use COM markers
+and place readable 7-bit ASCII text in them.  Newline conventions are not
+standardized --- expect to find LF (Unix style), CR/LF (DOS style), or CR
+(Mac style).  A robust COM reader should be able to cope with random binary
+garbage, including nulls, since some applications generate COM markers
+containing non-ASCII junk.  (But yours should not be one of them.)
+
+For program-supplied data, use an APPn marker, and be sure to begin it with an
+identifying string so that you can tell whether the marker is actually yours.
+It's probably best to avoid using APP0 or APP14 for any private markers.
+(NOTE: the upcoming SPIFF standard will use APP8 markers; we recommend you
+not use APP8 markers for any private purposes, either.)
+
+Keep in mind that at most 65533 bytes can be put into one marker, but you
+can have as many markers as you like.
+
+By default, the IJG compression library will write a JFIF APP0 marker if the
+selected JPEG colorspace is grayscale or YCbCr, or an Adobe APP14 marker if
+the selected colorspace is RGB, CMYK, or YCCK.  You can disable this, but
+we don't recommend it.  The decompression library will recognize JFIF and
+Adobe markers and will set the JPEG colorspace properly when one is found.
+
+
+You can write special markers immediately following the datastream header by
+calling jpeg_write_marker() after jpeg_start_compress() and before the first
+call to jpeg_write_scanlines().  When you do this, the markers appear after
+the SOI and the JFIF APP0 and Adobe APP14 markers (if written), but before
+all else.  Specify the marker type parameter as "JPEG_COM" for COM or
+"JPEG_APP0 + n" for APPn.  (Actually, jpeg_write_marker will let you write
+any marker type, but we don't recommend writing any other kinds of marker.)
+For example, to write a user comment string pointed to by comment_text:
+	jpeg_write_marker(cinfo, JPEG_COM, comment_text, strlen(comment_text));
+
+If it's not convenient to store all the marker data in memory at once,
+you can instead call jpeg_write_m_header() followed by multiple calls to
+jpeg_write_m_byte().  If you do it this way, it's your responsibility to
+call jpeg_write_m_byte() exactly the number of times given in the length
+parameter to jpeg_write_m_header().  (This method lets you empty the
+output buffer partway through a marker, which might be important when
+using a suspending data destination module.  In any case, if you are using
+a suspending destination, you should flush its buffer after inserting
+any special markers.  See "I/O suspension".)
+
+Or, if you prefer to synthesize the marker byte sequence yourself,
+you can just cram it straight into the data destination module.
+
+If you are writing JFIF 1.02 extension markers (thumbnail images), don't
+forget to set cinfo.JFIF_minor_version = 2 so that the encoder will write the
+correct JFIF version number in the JFIF header marker.  The library's default
+is to write version 1.01, but that's wrong if you insert any 1.02 extension
+markers.  (We could probably get away with just defaulting to 1.02, but there
+used to be broken decoders that would complain about unknown minor version
+numbers.  To reduce compatibility risks it's safest not to write 1.02 unless
+you are actually using 1.02 extensions.)
+
+
+When reading, two methods of handling special markers are available:
+1. You can ask the library to save the contents of COM and/or APPn markers
+into memory, and then examine them at your leisure afterwards.
+2. You can supply your own routine to process COM and/or APPn markers
+on-the-fly as they are read.
+The first method is simpler to use, especially if you are using a suspending
+data source; writing a marker processor that copes with input suspension is
+not easy (consider what happens if the marker is longer than your available
+input buffer).  However, the second method conserves memory since the marker
+data need not be kept around after it's been processed.
+
+For either method, you'd normally set up marker handling after creating a
+decompression object and before calling jpeg_read_header(), because the
+markers of interest will typically be near the head of the file and so will
+be scanned by jpeg_read_header.  Once you've established a marker handling
+method, it will be used for the life of that decompression object
+(potentially many datastreams), unless you change it.  Marker handling is
+determined separately for COM markers and for each APPn marker code.
+
+
+To save the contents of special markers in memory, call
+	jpeg_save_markers(cinfo, marker_code, length_limit)
+where marker_code is the marker type to save, JPEG_COM or JPEG_APP0+n.
+(To arrange to save all the special marker types, you need to call this
+routine 17 times, for COM and APP0-APP15.)  If the incoming marker is longer
+than length_limit data bytes, only length_limit bytes will be saved; this
+parameter allows you to avoid chewing up memory when you only need to see the
+first few bytes of a potentially large marker.  If you want to save all the
+data, set length_limit to 0xFFFF; that is enough since marker lengths are only
+16 bits.  As a special case, setting length_limit to 0 prevents that marker
+type from being saved at all.  (That is the default behavior, in fact.)
+
+After jpeg_read_header() completes, you can examine the special markers by
+following the cinfo->marker_list pointer chain.  All the special markers in
+the file appear in this list, in order of their occurrence in the file (but
+omitting any markers of types you didn't ask for).  Both the original data
+length and the saved data length are recorded for each list entry; the latter
+will not exceed length_limit for the particular marker type.  Note that these
+lengths exclude the marker length word, whereas the stored representation
+within the JPEG file includes it.  (Hence the maximum data length is really
+only 65533.)
+
+It is possible that additional special markers appear in the file beyond the
+SOS marker at which jpeg_read_header stops; if so, the marker list will be
+extended during reading of the rest of the file.  This is not expected to be
+common, however.  If you are short on memory you may want to reset the length
+limit to zero for all marker types after finishing jpeg_read_header, to
+ensure that the max_memory_to_use setting cannot be exceeded due to addition
+of later markers.
+
+The marker list remains stored until you call jpeg_finish_decompress or
+jpeg_abort, at which point the memory is freed and the list is set to empty.
+(jpeg_destroy also releases the storage, of course.)
+
+Note that the library is internally interested in APP0 and APP14 markers;
+if you try to set a small nonzero length limit on these types, the library
+will silently force the length up to the minimum it wants.  (But you can set
+a zero length limit to prevent them from being saved at all.)  Also, in a
+16-bit environment, the maximum length limit may be constrained to less than
+65533 by malloc() limitations.  It is therefore best not to assume that the
+effective length limit is exactly what you set it to be.
+
+
+If you want to supply your own marker-reading routine, you do it by calling
+jpeg_set_marker_processor().  A marker processor routine must have the
+signature
+	boolean jpeg_marker_parser_method (j_decompress_ptr cinfo)
+Although the marker code is not explicitly passed, the routine can find it
+in cinfo->unread_marker.  At the time of call, the marker proper has been
+read from the data source module.  The processor routine is responsible for
+reading the marker length word and the remaining parameter bytes, if any.
+Return TRUE to indicate success.  (FALSE should be returned only if you are
+using a suspending data source and it tells you to suspend.  See the standard
+marker processors in jdmarker.c for appropriate coding methods if you need to
+use a suspending data source.)
+
+If you override the default APP0 or APP14 processors, it is up to you to
+recognize JFIF and Adobe markers if you want colorspace recognition to occur
+properly.  We recommend copying and extending the default processors if you
+want to do that.  (A better idea is to save these marker types for later
+examination by calling jpeg_save_markers(); that method doesn't interfere
+with the library's own processing of these markers.)
+
+jpeg_set_marker_processor() and jpeg_save_markers() are mutually exclusive
+--- if you call one it overrides any previous call to the other, for the
+particular marker type specified.
+
+A simple example of an external COM processor can be found in djpeg.c.
+Also, see jpegtran.c for an example of using jpeg_save_markers.
+
+
+Raw (downsampled) image data
+----------------------------
+
+Some applications need to supply already-downsampled image data to the JPEG
+compressor, or to receive raw downsampled data from the decompressor.  The
+library supports this requirement by allowing the application to write or
+read raw data, bypassing the normal preprocessing or postprocessing steps.
+The interface is different from the standard one and is somewhat harder to
+use.  If your interest is merely in bypassing color conversion, we recommend
+that you use the standard interface and simply set jpeg_color_space =
+in_color_space (or jpeg_color_space = out_color_space for decompression).
+The mechanism described in this section is necessary only to supply or
+receive downsampled image data, in which not all components have the same
+dimensions.
+
+
+To compress raw data, you must supply the data in the colorspace to be used
+in the JPEG file (please read the earlier section on Special color spaces)
+and downsampled to the sampling factors specified in the JPEG parameters.
+You must supply the data in the format used internally by the JPEG library,
+namely a JSAMPIMAGE array.  This is an array of pointers to two-dimensional
+arrays, each of type JSAMPARRAY.  Each 2-D array holds the values for one
+color component.  This structure is necessary since the components are of
+different sizes.  If the image dimensions are not a multiple of the MCU size,
+you must also pad the data correctly (usually, this is done by replicating
+the last column and/or row).  The data must be padded to a multiple of a DCT
+block in each component: that is, each downsampled row must contain a
+multiple of block_size valid samples, and there must be a multiple of
+block_size sample rows for each component.  (For applications such as
+conversion of digital TV images, the standard image size is usually a
+multiple of the DCT block size, so that no padding need actually be done.)
+
+The procedure for compression of raw data is basically the same as normal
+compression, except that you call jpeg_write_raw_data() in place of
+jpeg_write_scanlines().  Before calling jpeg_start_compress(), you must do
+the following:
+  * Set cinfo->raw_data_in to TRUE.  (It is set FALSE by jpeg_set_defaults().)
+    This notifies the library that you will be supplying raw data.
+    Furthermore, set cinfo->do_fancy_downsampling to FALSE if you want to use
+    real downsampled data.  (It is set TRUE by jpeg_set_defaults().)
+  * Ensure jpeg_color_space is correct --- an explicit jpeg_set_colorspace()
+    call is a good idea.  Note that since color conversion is bypassed,
+    in_color_space is ignored, except that jpeg_set_defaults() uses it to
+    choose the default jpeg_color_space setting.
+  * Ensure the sampling factors, cinfo->comp_info[i].h_samp_factor and
+    cinfo->comp_info[i].v_samp_factor, are correct.  Since these indicate the
+    dimensions of the data you are supplying, it's wise to set them
+    explicitly, rather than assuming the library's defaults are what you want.
+
+To pass raw data to the library, call jpeg_write_raw_data() in place of
+jpeg_write_scanlines().  The two routines work similarly except that
+jpeg_write_raw_data takes a JSAMPIMAGE data array rather than JSAMPARRAY.
+The scanlines count passed to and returned from jpeg_write_raw_data is
+measured in terms of the component with the largest v_samp_factor.
+
+jpeg_write_raw_data() processes one MCU row per call, which is to say
+v_samp_factor*block_size sample rows of each component.  The passed num_lines
+value must be at least max_v_samp_factor*block_size, and the return value
+will be exactly that amount (or possibly some multiple of that amount, in
+future library versions).  This is true even on the last call at the bottom
+of the image; don't forget to pad your data as necessary.
+
+The required dimensions of the supplied data can be computed for each
+component as
+	cinfo->comp_info[i].width_in_blocks*block_size  samples per row
+	cinfo->comp_info[i].height_in_blocks*block_size rows in image
+after jpeg_start_compress() has initialized those fields.  If the valid data
+is smaller than this, it must be padded appropriately.  For some sampling
+factors and image sizes, additional dummy DCT blocks are inserted to make
+the image a multiple of the MCU dimensions.  The library creates such dummy
+blocks itself; it does not read them from your supplied data.  Therefore you
+need never pad by more than block_size samples.  An example may help here.
+Assume 2h2v downsampling of YCbCr data, that is
+	cinfo->comp_info[0].h_samp_factor = 2		for Y
+	cinfo->comp_info[0].v_samp_factor = 2
+	cinfo->comp_info[1].h_samp_factor = 1		for Cb
+	cinfo->comp_info[1].v_samp_factor = 1
+	cinfo->comp_info[2].h_samp_factor = 1		for Cr
+	cinfo->comp_info[2].v_samp_factor = 1
+and suppose that the nominal image dimensions (cinfo->image_width and
+cinfo->image_height) are 101x101 pixels.  Then jpeg_start_compress() will
+compute downsampled_width = 101 and width_in_blocks = 13 for Y,
+downsampled_width = 51 and width_in_blocks = 7 for Cb and Cr (and the same
+for the height fields).  You must pad the Y data to at least 13*8 = 104
+columns and rows, the Cb/Cr data to at least 7*8 = 56 columns and rows.  The
+MCU height is max_v_samp_factor = 2 DCT rows so you must pass at least 16
+scanlines on each call to jpeg_write_raw_data(), which is to say 16 actual
+sample rows of Y and 8 each of Cb and Cr.  A total of 7 MCU rows are needed,
+so you must pass a total of 7*16 = 112 "scanlines".  The last DCT block row
+of Y data is dummy, so it doesn't matter what you pass for it in the data
+arrays, but the scanlines count must total up to 112 so that all of the Cb
+and Cr data gets passed.
+
+Output suspension is supported with raw-data compression: if the data
+destination module suspends, jpeg_write_raw_data() will return 0.
+In this case the same data rows must be passed again on the next call.
+
+
+Decompression with raw data output implies bypassing all postprocessing.
+You must deal with the color space and sampling factors present in the
+incoming file.  If your application only handles, say, 2h1v YCbCr data,
+you must check for and fail on other color spaces or other sampling factors.
+The library will not convert to a different color space for you.
+
+To obtain raw data output, set cinfo->raw_data_out = TRUE before
+jpeg_start_decompress() (it is set FALSE by jpeg_read_header()).  Be sure to
+verify that the color space and sampling factors are ones you can handle.
+Furthermore, set cinfo->do_fancy_upsampling = FALSE if you want to get real
+downsampled data (it is set TRUE by jpeg_read_header()).
+Then call jpeg_read_raw_data() in place of jpeg_read_scanlines().  The
+decompression process is otherwise the same as usual.
+
+jpeg_read_raw_data() returns one MCU row per call, and thus you must pass a
+buffer of at least max_v_samp_factor*block_size scanlines (scanline counting
+is the same as for raw-data compression).  The buffer you pass must be large
+enough to hold the actual data plus padding to DCT-block boundaries.  As with
+compression, any entirely dummy DCT blocks are not processed so you need not
+allocate space for them, but the total scanline count includes them.  The
+above example of computing buffer dimensions for raw-data compression is
+equally valid for decompression.
+
+Input suspension is supported with raw-data decompression: if the data source
+module suspends, jpeg_read_raw_data() will return 0.  You can also use
+buffered-image mode to read raw data in multiple passes.
+
+
+Really raw data: DCT coefficients
+---------------------------------
+
+It is possible to read or write the contents of a JPEG file as raw DCT
+coefficients.  This facility is mainly intended for use in lossless
+transcoding between different JPEG file formats.  Other possible applications
+include lossless cropping of a JPEG image, lossless reassembly of a
+multi-strip or multi-tile TIFF/JPEG file into a single JPEG datastream, etc.
+
+To read the contents of a JPEG file as DCT coefficients, open the file and do
+jpeg_read_header() as usual.  But instead of calling jpeg_start_decompress()
+and jpeg_read_scanlines(), call jpeg_read_coefficients().  This will read the
+entire image into a set of virtual coefficient-block arrays, one array per
+component.  The return value is a pointer to an array of virtual-array
+descriptors.  Each virtual array can be accessed directly using the JPEG
+memory manager's access_virt_barray method (see Memory management, below,
+and also read structure.txt's discussion of virtual array handling).  Or,
+for simple transcoding to a different JPEG file format, the array list can
+just be handed directly to jpeg_write_coefficients().
+
+Each block in the block arrays contains quantized coefficient values in
+normal array order (not JPEG zigzag order).  The block arrays contain only
+DCT blocks containing real data; any entirely-dummy blocks added to fill out
+interleaved MCUs at the right or bottom edges of the image are discarded
+during reading and are not stored in the block arrays.  (The size of each
+block array can be determined from the width_in_blocks and height_in_blocks
+fields of the component's comp_info entry.)  This is also the data format
+expected by jpeg_write_coefficients().
+
+When you are done using the virtual arrays, call jpeg_finish_decompress()
+to release the array storage and return the decompression object to an idle
+state; or just call jpeg_destroy() if you don't need to reuse the object.
+
+If you use a suspending data source, jpeg_read_coefficients() will return
+NULL if it is forced to suspend; a non-NULL return value indicates successful
+completion.  You need not test for a NULL return value when using a
+non-suspending data source.
+
+It is also possible to call jpeg_read_coefficients() to obtain access to the
+decoder's coefficient arrays during a normal decode cycle in buffered-image
+mode.  This frammish might be useful for progressively displaying an incoming
+image and then re-encoding it without loss.  To do this, decode in buffered-
+image mode as discussed previously, then call jpeg_read_coefficients() after
+the last jpeg_finish_output() call.  The arrays will be available for your use
+until you call jpeg_finish_decompress().
+
+
+To write the contents of a JPEG file as DCT coefficients, you must provide
+the DCT coefficients stored in virtual block arrays.  You can either pass
+block arrays read from an input JPEG file by jpeg_read_coefficients(), or
+allocate virtual arrays from the JPEG compression object and fill them
+yourself.  In either case, jpeg_write_coefficients() is substituted for
+jpeg_start_compress() and jpeg_write_scanlines().  Thus the sequence is
+  * Create compression object
+  * Set all compression parameters as necessary
+  * Request virtual arrays if needed
+  * jpeg_write_coefficients()
+  * jpeg_finish_compress()
+  * Destroy or re-use compression object
+jpeg_write_coefficients() is passed a pointer to an array of virtual block
+array descriptors; the number of arrays is equal to cinfo.num_components.
+
+The virtual arrays need only have been requested, not realized, before
+jpeg_write_coefficients() is called.  A side-effect of
+jpeg_write_coefficients() is to realize any virtual arrays that have been
+requested from the compression object's memory manager.  Thus, when obtaining
+the virtual arrays from the compression object, you should fill the arrays
+after calling jpeg_write_coefficients().  The data is actually written out
+when you call jpeg_finish_compress(); jpeg_write_coefficients() only writes
+the file header.
+
+When writing raw DCT coefficients, it is crucial that the JPEG quantization
+tables and sampling factors match the way the data was encoded, or the
+resulting file will be invalid.  For transcoding from an existing JPEG file,
+we recommend using jpeg_copy_critical_parameters().  This routine initializes
+all the compression parameters to default values (like jpeg_set_defaults()),
+then copies the critical information from a source decompression object.
+The decompression object should have just been used to read the entire
+JPEG input file --- that is, it should be awaiting jpeg_finish_decompress().
+
+jpeg_write_coefficients() marks all tables stored in the compression object
+as needing to be written to the output file (thus, it acts like
+jpeg_start_compress(cinfo, TRUE)).  This is for safety's sake, to avoid
+emitting abbreviated JPEG files by accident.  If you really want to emit an
+abbreviated JPEG file, call jpeg_suppress_tables(), or set the tables'
+individual sent_table flags, between calling jpeg_write_coefficients() and
+jpeg_finish_compress().
+
+
+Progress monitoring
+-------------------
+
+Some applications may need to regain control from the JPEG library every so
+often.  The typical use of this feature is to produce a percent-done bar or
+other progress display.  (For a simple example, see cjpeg.c or djpeg.c.)
+Although you do get control back frequently during the data-transferring pass
+(the jpeg_read_scanlines or jpeg_write_scanlines loop), any additional passes
+will occur inside jpeg_finish_compress or jpeg_start_decompress; those
+routines may take a long time to execute, and you don't get control back
+until they are done.
+
+You can define a progress-monitor routine which will be called periodically
+by the library.  No guarantees are made about how often this call will occur,
+so we don't recommend you use it for mouse tracking or anything like that.
+At present, a call will occur once per MCU row, scanline, or sample row
+group, whichever unit is convenient for the current processing mode; so the
+wider the image, the longer the time between calls.  During the data
+transferring pass, only one call occurs per call of jpeg_read_scanlines or
+jpeg_write_scanlines, so don't pass a large number of scanlines at once if
+you want fine resolution in the progress count.  (If you really need to use
+the callback mechanism for time-critical tasks like mouse tracking, you could
+insert additional calls inside some of the library's inner loops.)
+
+To establish a progress-monitor callback, create a struct jpeg_progress_mgr,
+fill in its progress_monitor field with a pointer to your callback routine,
+and set cinfo->progress to point to the struct.  The callback will be called
+whenever cinfo->progress is non-NULL.  (This pointer is set to NULL by
+jpeg_create_compress or jpeg_create_decompress; the library will not change
+it thereafter.  So if you allocate dynamic storage for the progress struct,
+make sure it will live as long as the JPEG object does.  Allocating from the
+JPEG memory manager with lifetime JPOOL_PERMANENT will work nicely.)  You
+can use the same callback routine for both compression and decompression.
+
+The jpeg_progress_mgr struct contains four fields which are set by the library:
+	long pass_counter;	/* work units completed in this pass */
+	long pass_limit;	/* total number of work units in this pass */
+	int completed_passes;	/* passes completed so far */
+	int total_passes;	/* total number of passes expected */
+During any one pass, pass_counter increases from 0 up to (not including)
+pass_limit; the step size is usually but not necessarily 1.  The pass_limit
+value may change from one pass to another.  The expected total number of
+passes is in total_passes, and the number of passes already completed is in
+completed_passes.  Thus the fraction of work completed may be estimated as
+		completed_passes + (pass_counter/pass_limit)
+		--------------------------------------------
+				total_passes
+ignoring the fact that the passes may not be equal amounts of work.
+
+When decompressing, pass_limit can even change within a pass, because it
+depends on the number of scans in the JPEG file, which isn't always known in
+advance.  The computed fraction-of-work-done may jump suddenly (if the library
+discovers it has overestimated the number of scans) or even decrease (in the
+opposite case).  It is not wise to put great faith in the work estimate.
+
+When using the decompressor's buffered-image mode, the progress monitor work
+estimate is likely to be completely unhelpful, because the library has no way
+to know how many output passes will be demanded of it.  Currently, the library
+sets total_passes based on the assumption that there will be one more output
+pass if the input file end hasn't yet been read (jpeg_input_complete() isn't
+TRUE), but no more output passes if the file end has been reached when the
+output pass is started.  This means that total_passes will rise as additional
+output passes are requested.  If you have a way of determining the input file
+size, estimating progress based on the fraction of the file that's been read
+will probably be more useful than using the library's value.
+
+
+Memory management
+-----------------
+
+This section covers some key facts about the JPEG library's built-in memory
+manager.  For more info, please read structure.txt's section about the memory
+manager, and consult the source code if necessary.
+
+All memory and temporary file allocation within the library is done via the
+memory manager.  If necessary, you can replace the "back end" of the memory
+manager to control allocation yourself (for example, if you don't want the
+library to use malloc() and free() for some reason).
+
+Some data is allocated "permanently" and will not be freed until the JPEG
+object is destroyed.  Most data is allocated "per image" and is freed by
+jpeg_finish_compress, jpeg_finish_decompress, or jpeg_abort.  You can call the
+memory manager yourself to allocate structures that will automatically be
+freed at these times.  Typical code for this is
+  ptr = (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, size);
+Use JPOOL_PERMANENT to get storage that lasts as long as the JPEG object.
+Use alloc_large instead of alloc_small for anything bigger than a few Kbytes.
+There are also alloc_sarray and alloc_barray routines that automatically
+build 2-D sample or block arrays.
+
+The library's minimum space requirements to process an image depend on the
+image's width, but not on its height, because the library ordinarily works
+with "strip" buffers that are as wide as the image but just a few rows high.
+Some operating modes (eg, two-pass color quantization) require full-image
+buffers.  Such buffers are treated as "virtual arrays": only the current strip
+need be in memory, and the rest can be swapped out to a temporary file.
+
+If you use the simplest memory manager back end (jmemnobs.c), then no
+temporary files are used; virtual arrays are simply malloc()'d.  Images bigger
+than memory can be processed only if your system supports virtual memory.
+The other memory manager back ends support temporary files of various flavors
+and thus work in machines without virtual memory.  They may also be useful on
+Unix machines if you need to process images that exceed available swap space.
+
+When using temporary files, the library will make the in-memory buffers for
+its virtual arrays just big enough to stay within a "maximum memory" setting.
+Your application can set this limit by setting cinfo->mem->max_memory_to_use
+after creating the JPEG object.  (Of course, there is still a minimum size for
+the buffers, so the max-memory setting is effective only if it is bigger than
+the minimum space needed.)  If you allocate any large structures yourself, you
+must allocate them before jpeg_start_compress() or jpeg_start_decompress() in
+order to have them counted against the max memory limit.  Also keep in mind
+that space allocated with alloc_small() is ignored, on the assumption that
+it's too small to be worth worrying about; so a reasonable safety margin
+should be left when setting max_memory_to_use.
+
+If you use the jmemname.c or jmemdos.c memory manager back end, it is
+important to clean up the JPEG object properly to ensure that the temporary
+files get deleted.  (This is especially crucial with jmemdos.c, where the
+"temporary files" may be extended-memory segments; if they are not freed,
+DOS will require a reboot to recover the memory.)  Thus, with these memory
+managers, it's a good idea to provide a signal handler that will trap any
+early exit from your program.  The handler should call either jpeg_abort()
+or jpeg_destroy() for any active JPEG objects.  A handler is not needed with
+jmemnobs.c, and shouldn't be necessary with jmemansi.c or jmemmac.c either,
+since the C library is supposed to take care of deleting files made with
+tmpfile().
+
+
+Memory usage
+------------
+
+Working memory requirements while performing compression or decompression
+depend on image dimensions, image characteristics (such as colorspace and
+JPEG process), and operating mode (application-selected options).
+
+As of v6b, the decompressor requires:
+ 1. About 24K in more-or-less-fixed-size data.  This varies a bit depending
+    on operating mode and image characteristics (particularly color vs.
+    grayscale), but it doesn't depend on image dimensions.
+ 2. Strip buffers (of size proportional to the image width) for IDCT and
+    upsampling results.  The worst case for commonly used sampling factors
+    is about 34 bytes * width in pixels for a color image.  A grayscale image
+    only needs about 8 bytes per pixel column.
+ 3. A full-image DCT coefficient buffer is needed to decode a multi-scan JPEG
+    file (including progressive JPEGs), or whenever you select buffered-image
+    mode.  This takes 2 bytes/coefficient.  At typical 2x2 sampling, that's
+    3 bytes per pixel for a color image.  Worst case (1x1 sampling) requires
+    6 bytes/pixel.  For grayscale, figure 2 bytes/pixel.
+ 4. To perform 2-pass color quantization, the decompressor also needs a
+    128K color lookup table and a full-image pixel buffer (3 bytes/pixel).
+This does not count any memory allocated by the application, such as a
+buffer to hold the final output image.
+
+The above figures are valid for 8-bit JPEG data precision and a machine with
+32-bit ints.  For 9-bit to 12-bit JPEG data, double the size of the strip
+buffers and quantization pixel buffer.  The "fixed-size" data will be
+somewhat smaller with 16-bit ints, larger with 64-bit ints.  Also, CMYK
+or other unusual color spaces will require different amounts of space.
+
+The full-image coefficient and pixel buffers, if needed at all, do not
+have to be fully RAM resident; you can have the library use temporary
+files instead when the total memory usage would exceed a limit you set.
+(But if your OS supports virtual memory, it's probably better to just use
+jmemnobs and let the OS do the swapping.)
+
+The compressor's memory requirements are similar, except that it has no need
+for color quantization.  Also, it needs a full-image DCT coefficient buffer
+if Huffman-table optimization is asked for, even if progressive mode is not
+requested.
+
+If you need more detailed information about memory usage in a particular
+situation, you can enable the MEM_STATS code in jmemmgr.c.
+
+
+Library compile-time options
+----------------------------
+
+A number of compile-time options are available by modifying jmorecfg.h.
+
+The IJG code currently supports 8-bit to 12-bit sample data precision by
+defining BITS_IN_JSAMPLE as 8, 9, 10, 11, or 12.
+Note that a value larger than 8 causes JSAMPLE to be larger than a char,
+so it affects the surrounding application's image data.
+The sample applications cjpeg and djpeg can support deeper than 8-bit data
+only for PPM and GIF file formats; you must disable the other file formats
+to compile a 9-bit to 12-bit cjpeg or djpeg.  (install.txt has more
+information about that.)
+Run-time selection and conversion of data precision are currently not
+supported and may be added later.
+Exception:  The transcoding part (jpegtran) supports all settings in a
+single instance, since it operates on the level of DCT coefficients and
+not sample values.
+(If you need to include an 8-bit library and a 9-bit to 12-bit library for
+compression or decompression in a single application, you could probably do
+it by defining NEED_SHORT_EXTERNAL_NAMES for just one of the copies.  You'd
+have to access the 8-bit and the 9-bit to 12-bit copies from separate
+application source files.  This is untested ... if you try it, we'd like to
+hear whether it works!)
+
+Note that the standard Huffman tables are only valid for 8-bit data precision.
+If you selected more than 8-bit data precision, cjpeg uses arithmetic coding
+by default.  The Huffman encoder normally uses entropy optimization to
+compute usable tables for higher precision.  Otherwise, you'll have to
+supply different default Huffman tables.  You may also want to supply your
+own DCT quantization tables; the existing quality-scaling code has been
+developed for 8-bit use, and probably doesn't generate especially good tables
+for 9-bit to 12-bit.
+
+The maximum number of components (color channels) in the image is determined
+by MAX_COMPONENTS.  The JPEG standard allows up to 255 components, but we
+expect that few applications will need more than four or so.
+
+On machines with unusual data type sizes, you may be able to improve
+performance or reduce memory space by tweaking the various typedefs in
+jmorecfg.h.  In particular, on some RISC CPUs, access to arrays of "short"s
+is quite slow; consider trading memory for speed by making JCOEF, INT16, and
+UINT16 be "int" or "unsigned int".  UINT8 is also a candidate to become int.
+You probably don't want to make JSAMPLE be int unless you have lots of memory
+to burn.
+
+You can reduce the size of the library by compiling out various optional
+functions.  To do this, undefine xxx_SUPPORTED symbols as necessary.
+
+You can also save a few K by not having text error messages in the library;
+the standard error message table occupies about 5Kb.  This is particularly
+reasonable for embedded applications where there's no good way to display 
+a message anyway.  To do this, remove the creation of the message table
+(jpeg_std_message_table[]) from jerror.c, and alter format_message to do
+something reasonable without it.  You could output the numeric value of the
+message code number, for example.  If you do this, you can also save a couple
+more K by modifying the TRACEMSn() macros in jerror.h to expand to nothing;
+you don't need trace capability anyway, right?
+
+
+Portability considerations
+--------------------------
+
+The JPEG library has been written to be extremely portable; the sample
+applications cjpeg and djpeg are slightly less so.  This section summarizes
+the design goals in this area.  (If you encounter any bugs that cause the
+library to be less portable than is claimed here, we'd appreciate hearing
+about them.)
+
+The code works fine on ANSI C, C++, and pre-ANSI C compilers, using any of
+the popular system include file setups, and some not-so-popular ones too.
+See install.txt for configuration procedures.
+
+The code is not dependent on the exact sizes of the C data types.  As
+distributed, we make the assumptions that
+	char	is at least 8 bits wide
+	short	is at least 16 bits wide
+	int	is at least 16 bits wide
+	long	is at least 32 bits wide
+(These are the minimum requirements of the ANSI C standard.)  Wider types will
+work fine, although memory may be used inefficiently if char is much larger
+than 8 bits or short is much bigger than 16 bits.  The code should work
+equally well with 16- or 32-bit ints.
+
+In a system where these assumptions are not met, you may be able to make the
+code work by modifying the typedefs in jmorecfg.h.  However, you will probably
+have difficulty if int is less than 16 bits wide, since references to plain
+int abound in the code.
+
+char can be either signed or unsigned, although the code runs faster if an
+unsigned char type is available.  If char is wider than 8 bits, you will need
+to redefine JOCTET and/or provide custom data source/destination managers so
+that JOCTET represents exactly 8 bits of data on external storage.
+
+The JPEG library proper does not assume ASCII representation of characters.
+But some of the image file I/O modules in cjpeg/djpeg do have ASCII
+dependencies in file-header manipulation; so does cjpeg's select_file_type()
+routine.
+
+The JPEG library does not rely heavily on the C library.  In particular, C
+stdio is used only by the data source/destination modules and the error
+handler, all of which are application-replaceable.  (cjpeg/djpeg are more
+heavily dependent on stdio.)  malloc and free are called only from the memory
+manager "back end" module, so you can use a different memory allocator by
+replacing that one file.
+
+The code generally assumes that C names must be unique in the first 15
+characters.  However, global function names can be made unique in the
+first 6 characters by defining NEED_SHORT_EXTERNAL_NAMES.
+
+More info about porting the code may be gleaned by reading jconfig.txt,
+jmorecfg.h, and jinclude.h.
+
+
+Notes for MS-DOS implementors
+-----------------------------
+
+The IJG code is designed to work efficiently in 80x86 "small" or "medium"
+memory models (i.e., data pointers are 16 bits unless explicitly declared
+"far"; code pointers can be either size).  You may be able to use small
+model to compile cjpeg or djpeg by itself, but you will probably have to use
+medium model for any larger application.  This won't make much difference in
+performance.  You *will* take a noticeable performance hit if you use a
+large-data memory model (perhaps 10%-25%), and you should avoid "huge" model
+if at all possible.
+
+The JPEG library typically needs 2Kb-3Kb of stack space.  It will also
+malloc about 20K-30K of near heap space while executing (and lots of far
+heap, but that doesn't count in this calculation).  This figure will vary
+depending on selected operating mode, and to a lesser extent on image size.
+There is also about 5Kb-6Kb of constant data which will be allocated in the
+near data segment (about 4Kb of this is the error message table).
+Thus you have perhaps 20K available for other modules' static data and near
+heap space before you need to go to a larger memory model.  The C library's
+static data will account for several K of this, but that still leaves a good
+deal for your needs.  (If you are tight on space, you could reduce the sizes
+of the I/O buffers allocated by jdatasrc.c and jdatadst.c, say from 4K to
+1K.  Another possibility is to move the error message table to far memory;
+this should be doable with only localized hacking on jerror.c.)
+
+About 2K of the near heap space is "permanent" memory that will not be
+released until you destroy the JPEG object.  This is only an issue if you
+save a JPEG object between compression or decompression operations.
+
+Far data space may also be a tight resource when you are dealing with large
+images.  The most memory-intensive case is decompression with two-pass color
+quantization, or single-pass quantization to an externally supplied color
+map.  This requires a 128Kb color lookup table plus strip buffers amounting
+to about 40 bytes per column for typical sampling ratios (eg, about 25600
+bytes for a 640-pixel-wide image).  You may not be able to process wide
+images if you have large data structures of your own.
+
+Of course, all of these concerns vanish if you use a 32-bit flat-memory-model
+compiler, such as DJGPP or Watcom C.  We highly recommend flat model if you
+can use it; the JPEG library is significantly faster in flat model.
diff --git a/source/Irrlicht/jpeglib/ltmain.sh b/source/Irrlicht/jpeglib/ltmain.sh
new file mode 100644
index 00000000..63ae69dc
--- /dev/null
+++ b/source/Irrlicht/jpeglib/ltmain.sh
@@ -0,0 +1,9655 @@
+
+# libtool (GNU libtool) 2.4.2
+# Written by Gordon Matzigkeit , 1996
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
+# 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html,
+# or obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Usage: $progname [OPTION]... [MODE-ARG]...
+#
+# Provide generalized library-building support services.
+#
+#       --config             show all configuration variables
+#       --debug              enable verbose shell tracing
+#   -n, --dry-run            display commands without modifying any files
+#       --features           display basic configuration information and exit
+#       --mode=MODE          use operation mode MODE
+#       --preserve-dup-deps  don't remove duplicate dependency libraries
+#       --quiet, --silent    don't print informational messages
+#       --no-quiet, --no-silent
+#                            print informational messages (default)
+#       --no-warn            don't display warning messages
+#       --tag=TAG            use configuration variables from tag TAG
+#   -v, --verbose            print more informational messages than default
+#       --no-verbose         don't print the extra informational messages
+#       --version            print version information
+#   -h, --help, --help-all   print short, long, or detailed help message
+#
+# MODE must be one of the following:
+#
+#         clean              remove files from the build directory
+#         compile            compile a source file into a libtool object
+#         execute            automatically set library path, then run a program
+#         finish             complete the installation of libtool libraries
+#         install            install libraries or executables
+#         link               create a library or an executable
+#         uninstall          remove libraries from an installed directory
+#
+# MODE-ARGS vary depending on the MODE.  When passed as first option,
+# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that.
+# Try `$progname --help --mode=MODE' for a more detailed description of MODE.
+#
+# When reporting a bug, please describe a test case to reproduce it and
+# include the following information:
+#
+#         host-triplet:	$host
+#         shell:		$SHELL
+#         compiler:		$LTCC
+#         compiler flags:		$LTCFLAGS
+#         linker:		$LD (gnu? $with_gnu_ld)
+#         $progname:	(GNU libtool) 2.4.2
+#         automake:	$automake_version
+#         autoconf:	$autoconf_version
+#
+# Report bugs to .
+# GNU libtool home page: .
+# General help using GNU software: .
+
+PROGRAM=libtool
+PACKAGE=libtool
+VERSION=2.4.2
+TIMESTAMP=""
+package_revision=1.3337
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# NLS nuisances: We save the old values to restore during execute mode.
+lt_user_locale=
+lt_safe_locale=
+for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+  eval "if test \"\${$lt_var+set}\" = set; then
+          save_$lt_var=\$$lt_var
+          $lt_var=C
+	  export $lt_var
+	  lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\"
+	  lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\"
+	fi"
+done
+LC_ALL=C
+LANGUAGE=C
+export LANGUAGE LC_ALL
+
+$lt_unset CDPATH
+
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+
+
+: ${CP="cp -f"}
+test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'}
+: ${MAKE="make"}
+: ${MKDIR="mkdir"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+: ${Xsed="$SED -e 1s/^X//"}
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63  # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77	  # $? = 77 is used to indicate a skipped test to automake.
+
+exit_status=$EXIT_SUCCESS
+
+# Make sure IFS has a sensible default
+lt_nl='
+'
+IFS=" 	$lt_nl"
+
+dirname="s,/[^/]*$,,"
+basename="s,^.*/,,"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+    func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
+    if test "X$func_dirname_result" = "X${1}"; then
+      func_dirname_result="${3}"
+    else
+      func_dirname_result="$func_dirname_result${2}"
+    fi
+} # func_dirname may be replaced by extended shell implementation
+
+
+# func_basename file
+func_basename ()
+{
+    func_basename_result=`$ECHO "${1}" | $SED "$basename"`
+} # func_basename may be replaced by extended shell implementation
+
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+#   dirname:  Compute the dirname of FILE.  If nonempty,
+#             add APPEND to the result, otherwise set result
+#             to NONDIR_REPLACEMENT.
+#             value returned in "$func_dirname_result"
+#   basename: Compute filename of FILE.
+#             value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+    # Extract subdirectory from the argument.
+    func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"`
+    if test "X$func_dirname_result" = "X${1}"; then
+      func_dirname_result="${3}"
+    else
+      func_dirname_result="$func_dirname_result${2}"
+    fi
+    func_basename_result=`$ECHO "${1}" | $SED -e "$basename"`
+} # func_dirname_and_basename may be replaced by extended shell implementation
+
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+    case ${2} in
+      .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+      *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+    esac
+} # func_stripname may be replaced by extended shell implementation
+
+
+# These SED scripts presuppose an absolute path with a trailing slash.
+pathcar='s,^/\([^/]*\).*$,\1,'
+pathcdr='s,^/[^/]*,,'
+removedotparts=':dotsl
+		s@/\./@/@g
+		t dotsl
+		s,/\.$,/,'
+collapseslashes='s@/\{1,\}@/@g'
+finalslash='s,/*$,/,'
+
+# func_normal_abspath PATH
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+#             value returned in "$func_normal_abspath_result"
+func_normal_abspath ()
+{
+  # Start from root dir and reassemble the path.
+  func_normal_abspath_result=
+  func_normal_abspath_tpath=$1
+  func_normal_abspath_altnamespace=
+  case $func_normal_abspath_tpath in
+    "")
+      # Empty path, that just means $cwd.
+      func_stripname '' '/' "`pwd`"
+      func_normal_abspath_result=$func_stripname_result
+      return
+    ;;
+    # The next three entries are used to spot a run of precisely
+    # two leading slashes without using negated character classes;
+    # we take advantage of case's first-match behaviour.
+    ///*)
+      # Unusual form of absolute path, do nothing.
+    ;;
+    //*)
+      # Not necessarily an ordinary path; POSIX reserves leading '//'
+      # and for example Cygwin uses it to access remote file shares
+      # over CIFS/SMB, so we conserve a leading double slash if found.
+      func_normal_abspath_altnamespace=/
+    ;;
+    /*)
+      # Absolute path, do nothing.
+    ;;
+    *)
+      # Relative path, prepend $cwd.
+      func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+    ;;
+  esac
+  # Cancel out all the simple stuff to save iterations.  We also want
+  # the path to end with a slash for ease of parsing, so make sure
+  # there is one (and only one) here.
+  func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"`
+  while :; do
+    # Processed it all yet?
+    if test "$func_normal_abspath_tpath" = / ; then
+      # If we ascended to the root using ".." the result may be empty now.
+      if test -z "$func_normal_abspath_result" ; then
+        func_normal_abspath_result=/
+      fi
+      break
+    fi
+    func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$pathcar"`
+    func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$pathcdr"`
+    # Figure out what to do with it
+    case $func_normal_abspath_tcomponent in
+      "")
+        # Trailing empty path component, ignore it.
+      ;;
+      ..)
+        # Parent dir; strip last assembled component from result.
+        func_dirname "$func_normal_abspath_result"
+        func_normal_abspath_result=$func_dirname_result
+      ;;
+      *)
+        # Actual path component, append it.
+        func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent
+      ;;
+    esac
+  done
+  # Restore leading double-slash if one was found on entry.
+  func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+# func_relative_path SRCDIR DSTDIR
+# generates a relative path from SRCDIR to DSTDIR, with a trailing
+# slash if non-empty, suitable for immediately appending a filename
+# without needing to append a separator.
+#             value returned in "$func_relative_path_result"
+func_relative_path ()
+{
+  func_relative_path_result=
+  func_normal_abspath "$1"
+  func_relative_path_tlibdir=$func_normal_abspath_result
+  func_normal_abspath "$2"
+  func_relative_path_tbindir=$func_normal_abspath_result
+
+  # Ascend the tree starting from libdir
+  while :; do
+    # check if we have found a prefix of bindir
+    case $func_relative_path_tbindir in
+      $func_relative_path_tlibdir)
+        # found an exact match
+        func_relative_path_tcancelled=
+        break
+        ;;
+      $func_relative_path_tlibdir*)
+        # found a matching prefix
+        func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+        func_relative_path_tcancelled=$func_stripname_result
+        if test -z "$func_relative_path_result"; then
+          func_relative_path_result=.
+        fi
+        break
+        ;;
+      *)
+        func_dirname $func_relative_path_tlibdir
+        func_relative_path_tlibdir=${func_dirname_result}
+        if test "x$func_relative_path_tlibdir" = x ; then
+          # Have to descend all the way to the root!
+          func_relative_path_result=../$func_relative_path_result
+          func_relative_path_tcancelled=$func_relative_path_tbindir
+          break
+        fi
+        func_relative_path_result=../$func_relative_path_result
+        ;;
+    esac
+  done
+
+  # Now calculate path; take care to avoid doubling-up slashes.
+  func_stripname '' '/' "$func_relative_path_result"
+  func_relative_path_result=$func_stripname_result
+  func_stripname '/' '/' "$func_relative_path_tcancelled"
+  if test "x$func_stripname_result" != x ; then
+    func_relative_path_result=${func_relative_path_result}/${func_stripname_result}
+  fi
+
+  # Normalisation. If bindir is libdir, return empty string,
+  # else relative path ending with a slash; either way, target
+  # file name can be directly appended.
+  if test ! -z "$func_relative_path_result"; then
+    func_stripname './' '' "$func_relative_path_result/"
+    func_relative_path_result=$func_stripname_result
+  fi
+}
+
+# The name of this program:
+func_dirname_and_basename "$progpath"
+progname=$func_basename_result
+
+# Make sure we have an absolute path for reexecution:
+case $progpath in
+  [\\/]*|[A-Za-z]:\\*) ;;
+  *[\\/]*)
+     progdir=$func_dirname_result
+     progdir=`cd "$progdir" && pwd`
+     progpath="$progdir/$progname"
+     ;;
+  *)
+     save_IFS="$IFS"
+     IFS=${PATH_SEPARATOR-:}
+     for progdir in $PATH; do
+       IFS="$save_IFS"
+       test -x "$progdir/$progname" && break
+     done
+     IFS="$save_IFS"
+     test -n "$progdir" || progdir=`pwd`
+     progpath="$progdir/$progname"
+     ;;
+esac
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution that turns a string into a regex matching for the
+# string literally.
+sed_make_literal_regex='s,[].[^$\\*\/],\\&,g'
+
+# Sed substitution that converts a w32 file name or path
+# which contains forward slashes, into one that contains
+# (escaped) backslashes.  A very naive implementation.
+lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+
+# Re-`\' parameter expansions in output of double_quote_subst that were
+# `\'-ed in input to the same.  If an odd number of `\' preceded a '$'
+# in input to double_quote_subst, that '$' was protected from expansion.
+# Since each input `\' is now two `\'s, look for any number of runs of
+# four `\'s followed by two `\'s and then a '$'.  `\' that '$'.
+bs='\\'
+bs2='\\\\'
+bs4='\\\\\\\\'
+dollar='\$'
+sed_double_backslash="\
+  s/$bs4/&\\
+/g
+  s/^$bs2$dollar/$bs&/
+  s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g
+  s/\n//g"
+
+# Standard options:
+opt_dry_run=false
+opt_help=false
+opt_quiet=false
+opt_verbose=false
+opt_warning=:
+
+# func_echo arg...
+# Echo program name prefixed message, along with the current mode
+# name if it has been set yet.
+func_echo ()
+{
+    $ECHO "$progname: ${opt_mode+$opt_mode: }$*"
+}
+
+# func_verbose arg...
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+    $opt_verbose && func_echo ${1+"$@"}
+
+    # A bug in bash halts the script if the last line of a function
+    # fails when set -e is in force, so we need another command to
+    # work around that:
+    :
+}
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*"
+}
+
+# func_error arg...
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+    $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
+}
+
+# func_warning arg...
+# Echo program name prefixed warning message to standard error.
+func_warning ()
+{
+    $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
+
+    # bash bug again:
+    :
+}
+
+# func_fatal_error arg...
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+    func_error ${1+"$@"}
+    exit $EXIT_FAILURE
+}
+
+# func_fatal_help arg...
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+    func_error ${1+"$@"}
+    func_fatal_error "$help"
+}
+help="Try \`$progname --help' for more information."  ## default
+
+
+# func_grep expression filename
+# Check whether EXPRESSION matches any line of FILENAME, without output.
+func_grep ()
+{
+    $GREP "$1" "$2" >/dev/null 2>&1
+}
+
+
+# func_mkdir_p directory-path
+# Make sure the entire path to DIRECTORY-PATH is available.
+func_mkdir_p ()
+{
+    my_directory_path="$1"
+    my_dir_list=
+
+    if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then
+
+      # Protect directory names starting with `-'
+      case $my_directory_path in
+        -*) my_directory_path="./$my_directory_path" ;;
+      esac
+
+      # While some portion of DIR does not yet exist...
+      while test ! -d "$my_directory_path"; do
+        # ...make a list in topmost first order.  Use a colon delimited
+	# list incase some portion of path contains whitespace.
+        my_dir_list="$my_directory_path:$my_dir_list"
+
+        # If the last portion added has no slash in it, the list is done
+        case $my_directory_path in */*) ;; *) break ;; esac
+
+        # ...otherwise throw away the child directory and loop
+        my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"`
+      done
+      my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'`
+
+      save_mkdir_p_IFS="$IFS"; IFS=':'
+      for my_dir in $my_dir_list; do
+	IFS="$save_mkdir_p_IFS"
+        # mkdir can fail with a `File exist' error if two processes
+        # try to create one of the directories concurrently.  Don't
+        # stop in that case!
+        $MKDIR "$my_dir" 2>/dev/null || :
+      done
+      IFS="$save_mkdir_p_IFS"
+
+      # Bail out if we (or some other process) failed to create a directory.
+      test -d "$my_directory_path" || \
+        func_fatal_error "Failed to create \`$1'"
+    fi
+}
+
+
+# func_mktempdir [string]
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible.  If
+# given, STRING is the basename for that directory.
+func_mktempdir ()
+{
+    my_template="${TMPDIR-/tmp}/${1-$progname}"
+
+    if test "$opt_dry_run" = ":"; then
+      # Return a directory name, but don't create it in dry-run mode
+      my_tmpdir="${my_template}-$$"
+    else
+
+      # If mktemp works, use that first and foremost
+      my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
+
+      if test ! -d "$my_tmpdir"; then
+        # Failing that, at least try and use $RANDOM to avoid a race
+        my_tmpdir="${my_template}-${RANDOM-0}$$"
+
+        save_mktempdir_umask=`umask`
+        umask 0077
+        $MKDIR "$my_tmpdir"
+        umask $save_mktempdir_umask
+      fi
+
+      # If we're not in dry-run mode, bomb out on failure
+      test -d "$my_tmpdir" || \
+        func_fatal_error "cannot create temporary directory \`$my_tmpdir'"
+    fi
+
+    $ECHO "$my_tmpdir"
+}
+
+
+# func_quote_for_eval arg
+# Aesthetically quote ARG to be evaled later.
+# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT
+# is double-quoted, suitable for a subsequent eval, whereas
+# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters
+# which are still active within double quotes backslashified.
+func_quote_for_eval ()
+{
+    case $1 in
+      *[\\\`\"\$]*)
+	func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;;
+      *)
+        func_quote_for_eval_unquoted_result="$1" ;;
+    esac
+
+    case $func_quote_for_eval_unquoted_result in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting, command substitution and and variable
+      # expansion for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+        func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\""
+        ;;
+      *)
+        func_quote_for_eval_result="$func_quote_for_eval_unquoted_result"
+    esac
+}
+
+
+# func_quote_for_expand arg
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+    case $1 in
+      *[\\\`\"]*)
+	my_arg=`$ECHO "$1" | $SED \
+	    -e "$double_quote_subst" -e "$sed_double_backslash"` ;;
+      *)
+        my_arg="$1" ;;
+    esac
+
+    case $my_arg in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting and command substitution for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+        my_arg="\"$my_arg\""
+        ;;
+    esac
+
+    func_quote_for_expand_result="$my_arg"
+}
+
+
+# func_show_eval cmd [fail_exp]
+# Unless opt_silent is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+    my_cmd="$1"
+    my_fail_exp="${2-:}"
+
+    ${opt_silent-false} || {
+      func_quote_for_expand "$my_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    if ${opt_dry_run-false}; then :; else
+      eval "$my_cmd"
+      my_status=$?
+      if test "$my_status" -eq 0; then :; else
+	eval "(exit $my_status); $my_fail_exp"
+      fi
+    fi
+}
+
+
+# func_show_eval_locale cmd [fail_exp]
+# Unless opt_silent is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.  Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+    my_cmd="$1"
+    my_fail_exp="${2-:}"
+
+    ${opt_silent-false} || {
+      func_quote_for_expand "$my_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    if ${opt_dry_run-false}; then :; else
+      eval "$lt_user_locale
+	    $my_cmd"
+      my_status=$?
+      eval "$lt_safe_locale"
+      if test "$my_status" -eq 0; then :; else
+	eval "(exit $my_status); $my_fail_exp"
+      fi
+    fi
+}
+
+# func_tr_sh
+# Turn $1 into a string suitable for a shell variable name.
+# Result is stored in $func_tr_sh_result.  All characters
+# not in the set a-zA-Z0-9_ are replaced with '_'. Further,
+# if $1 begins with a digit, a '_' is prepended as well.
+func_tr_sh ()
+{
+  case $1 in
+  [0-9]* | *[!a-zA-Z0-9_]*)
+    func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'`
+    ;;
+  * )
+    func_tr_sh_result=$1
+    ;;
+  esac
+}
+
+
+# func_version
+# Echo version message to standard output and exit.
+func_version ()
+{
+    $opt_debug
+
+    $SED -n '/(C)/!b go
+	:more
+	/\./!{
+	  N
+	  s/\n# / /
+	  b more
+	}
+	:go
+	/^# '$PROGRAM' (GNU /,/# warranty; / {
+        s/^# //
+	s/^# *$//
+        s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/
+        p
+     }' < "$progpath"
+     exit $?
+}
+
+# func_usage
+# Echo short help message to standard output and exit.
+func_usage ()
+{
+    $opt_debug
+
+    $SED -n '/^# Usage:/,/^#  *.*--help/ {
+        s/^# //
+	s/^# *$//
+	s/\$progname/'$progname'/
+	p
+    }' < "$progpath"
+    echo
+    $ECHO "run \`$progname --help | more' for full usage"
+    exit $?
+}
+
+# func_help [NOEXIT]
+# Echo long help message to standard output and exit,
+# unless 'noexit' is passed as argument.
+func_help ()
+{
+    $opt_debug
+
+    $SED -n '/^# Usage:/,/# Report bugs to/ {
+	:print
+        s/^# //
+	s/^# *$//
+	s*\$progname*'$progname'*
+	s*\$host*'"$host"'*
+	s*\$SHELL*'"$SHELL"'*
+	s*\$LTCC*'"$LTCC"'*
+	s*\$LTCFLAGS*'"$LTCFLAGS"'*
+	s*\$LD*'"$LD"'*
+	s/\$with_gnu_ld/'"$with_gnu_ld"'/
+	s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/
+	s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/
+	p
+	d
+     }
+     /^# .* home page:/b print
+     /^# General help using/b print
+     ' < "$progpath"
+    ret=$?
+    if test -z "$1"; then
+      exit $ret
+    fi
+}
+
+# func_missing_arg argname
+# Echo program name prefixed message to standard error and set global
+# exit_cmd.
+func_missing_arg ()
+{
+    $opt_debug
+
+    func_error "missing argument for $1."
+    exit_cmd=exit
+}
+
+
+# func_split_short_opt shortopt
+# Set func_split_short_opt_name and func_split_short_opt_arg shell
+# variables after splitting SHORTOPT after the 2nd character.
+func_split_short_opt ()
+{
+    my_sed_short_opt='1s/^\(..\).*$/\1/;q'
+    my_sed_short_rest='1s/^..\(.*\)$/\1/;q'
+
+    func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"`
+    func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"`
+} # func_split_short_opt may be replaced by extended shell implementation
+
+
+# func_split_long_opt longopt
+# Set func_split_long_opt_name and func_split_long_opt_arg shell
+# variables after splitting LONGOPT at the `=' sign.
+func_split_long_opt ()
+{
+    my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q'
+    my_sed_long_arg='1s/^--[^=]*=//'
+
+    func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"`
+    func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"`
+} # func_split_long_opt may be replaced by extended shell implementation
+
+exit_cmd=:
+
+
+
+
+
+magic="%%%MAGIC variable%%%"
+magic_exe="%%%MAGIC EXE variable%%%"
+
+# Global variables.
+nonopt=
+preserve_args=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+extracted_archives=
+extracted_serial=0
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end.  This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+    eval "${1}=\$${1}\${2}"
+} # func_append may be replaced by extended shell implementation
+
+# func_append_quoted var value
+# Quote VALUE and append to the end of shell variable VAR, separated
+# by a space.
+func_append_quoted ()
+{
+    func_quote_for_eval "${2}"
+    eval "${1}=\$${1}\\ \$func_quote_for_eval_result"
+} # func_append_quoted may be replaced by extended shell implementation
+
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+    func_arith_result=`expr "${@}"`
+} # func_arith may be replaced by extended shell implementation
+
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+    func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len`
+} # func_len may be replaced by extended shell implementation
+
+
+# func_lo2o object
+func_lo2o ()
+{
+    func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
+} # func_lo2o may be replaced by extended shell implementation
+
+
+# func_xform libobj-or-source
+func_xform ()
+{
+    func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'`
+} # func_xform may be replaced by extended shell implementation
+
+
+# func_fatal_configuration arg...
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+    func_error ${1+"$@"}
+    func_error "See the $PACKAGE documentation for more information."
+    func_fatal_error "Fatal configuration error."
+}
+
+
+# func_config
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+    re_begincf='^# ### BEGIN LIBTOOL'
+    re_endcf='^# ### END LIBTOOL'
+
+    # Default configuration.
+    $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+    # Now print the configurations for the tags.
+    for tagname in $taglist; do
+      $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+    done
+
+    exit $?
+}
+
+# func_features
+# Display the features supported by this script.
+func_features ()
+{
+    echo "host: $host"
+    if test "$build_libtool_libs" = yes; then
+      echo "enable shared libraries"
+    else
+      echo "disable shared libraries"
+    fi
+    if test "$build_old_libs" = yes; then
+      echo "enable static libraries"
+    else
+      echo "disable static libraries"
+    fi
+
+    exit $?
+}
+
+# func_enable_tag tagname
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag.  We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+  # Global variable:
+  tagname="$1"
+
+  re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+  re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+  sed_extractcf="/$re_begincf/,/$re_endcf/p"
+
+  # Validate tagname.
+  case $tagname in
+    *[!-_A-Za-z0-9,/]*)
+      func_fatal_error "invalid tag name: $tagname"
+      ;;
+  esac
+
+  # Don't test for the "default" C tag, as we know it's
+  # there but not specially marked.
+  case $tagname in
+    CC) ;;
+    *)
+      if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+	taglist="$taglist $tagname"
+
+	# Evaluate the configuration.  Be careful to quote the path
+	# and the sed script, to avoid splitting on whitespace, but
+	# also don't use non-portable quotes within backquotes within
+	# quotes we have to do it in 2 steps:
+	extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+	eval "$extractedcf"
+      else
+	func_error "ignoring unknown tag $tagname"
+      fi
+      ;;
+  esac
+}
+
+# func_check_version_match
+# Ensure that we are using m4 macros, and libtool script from the same
+# release of libtool.
+func_check_version_match ()
+{
+  if test "$package_revision" != "$macro_revision"; then
+    if test "$VERSION" != "$macro_version"; then
+      if test -z "$macro_version"; then
+        cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from an older release.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+      else
+        cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+      fi
+    else
+      cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, revision $package_revision,
+$progname: but the definition of this LT_INIT comes from revision $macro_revision.
+$progname: You should recreate aclocal.m4 with macros from revision $package_revision
+$progname: of $PACKAGE $VERSION and run autoconf again.
+_LT_EOF
+    fi
+
+    exit $EXIT_MISMATCH
+  fi
+}
+
+
+# Shorthand for --mode=foo, only valid as the first argument
+case $1 in
+clean|clea|cle|cl)
+  shift; set dummy --mode clean ${1+"$@"}; shift
+  ;;
+compile|compil|compi|comp|com|co|c)
+  shift; set dummy --mode compile ${1+"$@"}; shift
+  ;;
+execute|execut|execu|exec|exe|ex|e)
+  shift; set dummy --mode execute ${1+"$@"}; shift
+  ;;
+finish|finis|fini|fin|fi|f)
+  shift; set dummy --mode finish ${1+"$@"}; shift
+  ;;
+install|instal|insta|inst|ins|in|i)
+  shift; set dummy --mode install ${1+"$@"}; shift
+  ;;
+link|lin|li|l)
+  shift; set dummy --mode link ${1+"$@"}; shift
+  ;;
+uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+  shift; set dummy --mode uninstall ${1+"$@"}; shift
+  ;;
+esac
+
+
+
+# Option defaults:
+opt_debug=:
+opt_dry_run=false
+opt_config=false
+opt_preserve_dup_deps=false
+opt_features=false
+opt_finish=false
+opt_help=false
+opt_help_all=false
+opt_silent=:
+opt_warning=:
+opt_verbose=:
+opt_silent=false
+opt_verbose=false
+
+
+# Parse options once, thoroughly.  This comes as soon as possible in the
+# script to make things like `--version' happen as quickly as we can.
+{
+  # this just eases exit handling
+  while test $# -gt 0; do
+    opt="$1"
+    shift
+    case $opt in
+      --debug|-x)	opt_debug='set -x'
+			func_echo "enabling shell trace mode"
+			$opt_debug
+			;;
+      --dry-run|--dryrun|-n)
+			opt_dry_run=:
+			;;
+      --config)
+			opt_config=:
+func_config
+			;;
+      --dlopen|-dlopen)
+			optarg="$1"
+			opt_dlopen="${opt_dlopen+$opt_dlopen
+}$optarg"
+			shift
+			;;
+      --preserve-dup-deps)
+			opt_preserve_dup_deps=:
+			;;
+      --features)
+			opt_features=:
+func_features
+			;;
+      --finish)
+			opt_finish=:
+set dummy --mode finish ${1+"$@"}; shift
+			;;
+      --help)
+			opt_help=:
+			;;
+      --help-all)
+			opt_help_all=:
+opt_help=': help-all'
+			;;
+      --mode)
+			test $# = 0 && func_missing_arg $opt && break
+			optarg="$1"
+			opt_mode="$optarg"
+case $optarg in
+  # Valid mode arguments:
+  clean|compile|execute|finish|install|link|relink|uninstall) ;;
+
+  # Catch anything else as an error
+  *) func_error "invalid argument for $opt"
+     exit_cmd=exit
+     break
+     ;;
+esac
+			shift
+			;;
+      --no-silent|--no-quiet)
+			opt_silent=false
+func_append preserve_args " $opt"
+			;;
+      --no-warning|--no-warn)
+			opt_warning=false
+func_append preserve_args " $opt"
+			;;
+      --no-verbose)
+			opt_verbose=false
+func_append preserve_args " $opt"
+			;;
+      --silent|--quiet)
+			opt_silent=:
+func_append preserve_args " $opt"
+        opt_verbose=false
+			;;
+      --verbose|-v)
+			opt_verbose=:
+func_append preserve_args " $opt"
+opt_silent=false
+			;;
+      --tag)
+			test $# = 0 && func_missing_arg $opt && break
+			optarg="$1"
+			opt_tag="$optarg"
+func_append preserve_args " $opt $optarg"
+func_enable_tag "$optarg"
+			shift
+			;;
+
+      -\?|-h)		func_usage				;;
+      --help)		func_help				;;
+      --version)	func_version				;;
+
+      # Separate optargs to long options:
+      --*=*)
+			func_split_long_opt "$opt"
+			set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"}
+			shift
+			;;
+
+      # Separate non-argument short options:
+      -\?*|-h*|-n*|-v*)
+			func_split_short_opt "$opt"
+			set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"}
+			shift
+			;;
+
+      --)		break					;;
+      -*)		func_fatal_help "unrecognized option \`$opt'" ;;
+      *)		set dummy "$opt" ${1+"$@"};	shift; break  ;;
+    esac
+  done
+
+  # Validate options:
+
+  # save first non-option argument
+  if test "$#" -gt 0; then
+    nonopt="$opt"
+    shift
+  fi
+
+  # preserve --debug
+  test "$opt_debug" = : || func_append preserve_args " --debug"
+
+  case $host in
+    *cygwin* | *mingw* | *pw32* | *cegcc*)
+      # don't eliminate duplications in $postdeps and $predeps
+      opt_duplicate_compiler_generated_deps=:
+      ;;
+    *)
+      opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps
+      ;;
+  esac
+
+  $opt_help || {
+    # Sanity checks first:
+    func_check_version_match
+
+    if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+      func_fatal_configuration "not configured to build any kind of library"
+    fi
+
+    # Darwin sucks
+    eval std_shrext=\"$shrext_cmds\"
+
+    # Only execute mode is allowed to have -dlopen flags.
+    if test -n "$opt_dlopen" && test "$opt_mode" != execute; then
+      func_error "unrecognized option \`-dlopen'"
+      $ECHO "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    # Change the help message to a mode-specific one.
+    generic_help="$help"
+    help="Try \`$progname --help --mode=$opt_mode' for more information."
+  }
+
+
+  # Bail if the options were screwed
+  $exit_cmd $EXIT_FAILURE
+}
+
+
+
+
+## ----------- ##
+##    Main.    ##
+## ----------- ##
+
+# func_lalib_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_lalib_p ()
+{
+    test -f "$1" &&
+      $SED -e 4q "$1" 2>/dev/null \
+        | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
+# func_lalib_unsafe_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function implements the same check as func_lalib_p without
+# resorting to external programs.  To this end, it redirects stdin and
+# closes it afterwards, without saving the original file descriptor.
+# As a safety measure, use it only where a negative result would be
+# fatal anyway.  Works if `file' does not exist.
+func_lalib_unsafe_p ()
+{
+    lalib_p=no
+    if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
+	for lalib_p_l in 1 2 3 4
+	do
+	    read lalib_p_line
+	    case "$lalib_p_line" in
+		\#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
+	    esac
+	done
+	exec 0<&5 5<&-
+    fi
+    test "$lalib_p" = yes
+}
+
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+    func_lalib_p "$1"
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+    func_ltwrapper_exec_suffix=
+    case $1 in
+    *.exe) ;;
+    *) func_ltwrapper_exec_suffix=.exe ;;
+    esac
+    $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
+}
+
+# func_ltwrapper_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_scriptname ()
+{
+    func_dirname_and_basename "$1" "" "."
+    func_stripname '' '.exe' "$func_basename_result"
+    func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper"
+}
+
+# func_ltwrapper_p file
+# True iff FILE is a libtool wrapper script or wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_p ()
+{
+    func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
+}
+
+
+# func_execute_cmds commands fail_cmd
+# Execute tilde-delimited COMMANDS.
+# If FAIL_CMD is given, eval that upon failure.
+# FAIL_CMD may read-access the current command in variable CMD!
+func_execute_cmds ()
+{
+    $opt_debug
+    save_ifs=$IFS; IFS='~'
+    for cmd in $1; do
+      IFS=$save_ifs
+      eval cmd=\"$cmd\"
+      func_show_eval "$cmd" "${2-:}"
+    done
+    IFS=$save_ifs
+}
+
+
+# func_source file
+# Source FILE, adding directory component if necessary.
+# Note that it is not necessary on cygwin/mingw to append a dot to
+# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
+# behavior happens only for exec(3), not for open(2)!  Also, sourcing
+# `FILE.' does not work on cygwin managed mounts.
+func_source ()
+{
+    $opt_debug
+    case $1 in
+    */* | *\\*)	. "$1" ;;
+    *)		. "./$1" ;;
+    esac
+}
+
+
+# func_resolve_sysroot PATH
+# Replace a leading = in PATH with a sysroot.  Store the result into
+# func_resolve_sysroot_result
+func_resolve_sysroot ()
+{
+  func_resolve_sysroot_result=$1
+  case $func_resolve_sysroot_result in
+  =*)
+    func_stripname '=' '' "$func_resolve_sysroot_result"
+    func_resolve_sysroot_result=$lt_sysroot$func_stripname_result
+    ;;
+  esac
+}
+
+# func_replace_sysroot PATH
+# If PATH begins with the sysroot, replace it with = and
+# store the result into func_replace_sysroot_result.
+func_replace_sysroot ()
+{
+  case "$lt_sysroot:$1" in
+  ?*:"$lt_sysroot"*)
+    func_stripname "$lt_sysroot" '' "$1"
+    func_replace_sysroot_result="=$func_stripname_result"
+    ;;
+  *)
+    # Including no sysroot.
+    func_replace_sysroot_result=$1
+    ;;
+  esac
+}
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+    $opt_debug
+    if test -n "$available_tags" && test -z "$tagname"; then
+      CC_quoted=
+      for arg in $CC; do
+	func_append_quoted CC_quoted "$arg"
+      done
+      CC_expanded=`func_echo_all $CC`
+      CC_quoted_expanded=`func_echo_all $CC_quoted`
+      case $@ in
+      # Blanks in the command may have been stripped by the calling shell,
+      # but not from the CC environment variable when configure was run.
+      " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+      " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
+      # Blanks at the start of $base_compile will cause this to fail
+      # if we don't check for them as well.
+      *)
+	for z in $available_tags; do
+	  if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+	    # Evaluate the configuration.
+	    eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+	    CC_quoted=
+	    for arg in $CC; do
+	      # Double-quote args containing other shell metacharacters.
+	      func_append_quoted CC_quoted "$arg"
+	    done
+	    CC_expanded=`func_echo_all $CC`
+	    CC_quoted_expanded=`func_echo_all $CC_quoted`
+	    case "$@ " in
+	    " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+	    " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
+	      # The compiler in the base compile command matches
+	      # the one in the tagged configuration.
+	      # Assume this is the tagged configuration we want.
+	      tagname=$z
+	      break
+	      ;;
+	    esac
+	  fi
+	done
+	# If $tagname still isn't set, then no tagged configuration
+	# was found and let the user know that the "--tag" command
+	# line option must be used.
+	if test -z "$tagname"; then
+	  func_echo "unable to infer tagged configuration"
+	  func_fatal_error "specify a tag with \`--tag'"
+#	else
+#	  func_verbose "using $tagname tagged configuration"
+	fi
+	;;
+      esac
+    fi
+}
+
+
+
+# func_write_libtool_object output_name pic_name nonpic_name
+# Create a libtool object file (analogous to a ".la" file),
+# but don't create it if we're doing a dry run.
+func_write_libtool_object ()
+{
+    write_libobj=${1}
+    if test "$build_libtool_libs" = yes; then
+      write_lobj=\'${2}\'
+    else
+      write_lobj=none
+    fi
+
+    if test "$build_old_libs" = yes; then
+      write_oldobj=\'${3}\'
+    else
+      write_oldobj=none
+    fi
+
+    $opt_dry_run || {
+      cat >${write_libobj}T </dev/null`
+    if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then
+      func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" |
+        $SED -e "$lt_sed_naive_backslashify"`
+    else
+      func_convert_core_file_wine_to_w32_result=
+    fi
+  fi
+}
+# end: func_convert_core_file_wine_to_w32
+
+
+# func_convert_core_path_wine_to_w32 ARG
+# Helper function used by path conversion functions when $build is *nix, and
+# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly
+# configured wine environment available, with the winepath program in $build's
+# $PATH. Assumes ARG has no leading or trailing path separator characters.
+#
+# ARG is path to be converted from $build format to win32.
+# Result is available in $func_convert_core_path_wine_to_w32_result.
+# Unconvertible file (directory) names in ARG are skipped; if no directory names
+# are convertible, then the result may be empty.
+func_convert_core_path_wine_to_w32 ()
+{
+  $opt_debug
+  # unfortunately, winepath doesn't convert paths, only file names
+  func_convert_core_path_wine_to_w32_result=""
+  if test -n "$1"; then
+    oldIFS=$IFS
+    IFS=:
+    for func_convert_core_path_wine_to_w32_f in $1; do
+      IFS=$oldIFS
+      func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f"
+      if test -n "$func_convert_core_file_wine_to_w32_result" ; then
+        if test -z "$func_convert_core_path_wine_to_w32_result"; then
+          func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result"
+        else
+          func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result"
+        fi
+      fi
+    done
+    IFS=$oldIFS
+  fi
+}
+# end: func_convert_core_path_wine_to_w32
+
+
+# func_cygpath ARGS...
+# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when
+# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2)
+# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or
+# (2), returns the Cygwin file name or path in func_cygpath_result (input
+# file name or path is assumed to be in w32 format, as previously converted
+# from $build's *nix or MSYS format). In case (3), returns the w32 file name
+# or path in func_cygpath_result (input file name or path is assumed to be in
+# Cygwin format). Returns an empty string on error.
+#
+# ARGS are passed to cygpath, with the last one being the file name or path to
+# be converted.
+#
+# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH
+# environment variable; do not put it in $PATH.
+func_cygpath ()
+{
+  $opt_debug
+  if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then
+    func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null`
+    if test "$?" -ne 0; then
+      # on failure, ensure result is empty
+      func_cygpath_result=
+    fi
+  else
+    func_cygpath_result=
+    func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'"
+  fi
+}
+#end: func_cygpath
+
+
+# func_convert_core_msys_to_w32 ARG
+# Convert file name or path ARG from MSYS format to w32 format.  Return
+# result in func_convert_core_msys_to_w32_result.
+func_convert_core_msys_to_w32 ()
+{
+  $opt_debug
+  # awkward: cmd appends spaces to result
+  func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null |
+    $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"`
+}
+#end: func_convert_core_msys_to_w32
+
+
+# func_convert_file_check ARG1 ARG2
+# Verify that ARG1 (a file name in $build format) was converted to $host
+# format in ARG2. Otherwise, emit an error message, but continue (resetting
+# func_to_host_file_result to ARG1).
+func_convert_file_check ()
+{
+  $opt_debug
+  if test -z "$2" && test -n "$1" ; then
+    func_error "Could not determine host file name corresponding to"
+    func_error "  \`$1'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback:
+    func_to_host_file_result="$1"
+  fi
+}
+# end func_convert_file_check
+
+
+# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH
+# Verify that FROM_PATH (a path in $build format) was converted to $host
+# format in TO_PATH. Otherwise, emit an error message, but continue, resetting
+# func_to_host_file_result to a simplistic fallback value (see below).
+func_convert_path_check ()
+{
+  $opt_debug
+  if test -z "$4" && test -n "$3"; then
+    func_error "Could not determine the host path corresponding to"
+    func_error "  \`$3'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback.  This is a deliberately simplistic "conversion" and
+    # should not be "improved".  See libtool.info.
+    if test "x$1" != "x$2"; then
+      lt_replace_pathsep_chars="s|$1|$2|g"
+      func_to_host_path_result=`echo "$3" |
+        $SED -e "$lt_replace_pathsep_chars"`
+    else
+      func_to_host_path_result="$3"
+    fi
+  fi
+}
+# end func_convert_path_check
+
+
+# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG
+# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT
+# and appending REPL if ORIG matches BACKPAT.
+func_convert_path_front_back_pathsep ()
+{
+  $opt_debug
+  case $4 in
+  $1 ) func_to_host_path_result="$3$func_to_host_path_result"
+    ;;
+  esac
+  case $4 in
+  $2 ) func_append func_to_host_path_result "$3"
+    ;;
+  esac
+}
+# end func_convert_path_front_back_pathsep
+
+
+##################################################
+# $build to $host FILE NAME CONVERSION FUNCTIONS #
+##################################################
+# invoked via `$to_host_file_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# Result will be available in $func_to_host_file_result.
+
+
+# func_to_host_file ARG
+# Converts the file name ARG from $build format to $host format. Return result
+# in func_to_host_file_result.
+func_to_host_file ()
+{
+  $opt_debug
+  $to_host_file_cmd "$1"
+}
+# end func_to_host_file
+
+
+# func_to_tool_file ARG LAZY
+# converts the file name ARG from $build format to toolchain format. Return
+# result in func_to_tool_file_result.  If the conversion in use is listed
+# in (the comma separated) LAZY, no conversion takes place.
+func_to_tool_file ()
+{
+  $opt_debug
+  case ,$2, in
+    *,"$to_tool_file_cmd",*)
+      func_to_tool_file_result=$1
+      ;;
+    *)
+      $to_tool_file_cmd "$1"
+      func_to_tool_file_result=$func_to_host_file_result
+      ;;
+  esac
+}
+# end func_to_tool_file
+
+
+# func_convert_file_noop ARG
+# Copy ARG to func_to_host_file_result.
+func_convert_file_noop ()
+{
+  func_to_host_file_result="$1"
+}
+# end func_convert_file_noop
+
+
+# func_convert_file_msys_to_w32 ARG
+# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper.  Returns result in
+# func_to_host_file_result.
+func_convert_file_msys_to_w32 ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    func_convert_core_msys_to_w32 "$1"
+    func_to_host_file_result="$func_convert_core_msys_to_w32_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_w32
+
+
+# func_convert_file_cygwin_to_w32 ARG
+# Convert file name ARG from Cygwin to w32 format.  Returns result in
+# func_to_host_file_result.
+func_convert_file_cygwin_to_w32 ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    # because $build is cygwin, we call "the" cygpath in $PATH; no need to use
+    # LT_CYGPATH in this case.
+    func_to_host_file_result=`cygpath -m "$1"`
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_cygwin_to_w32
+
+
+# func_convert_file_nix_to_w32 ARG
+# Convert file name ARG from *nix to w32 format.  Requires a wine environment
+# and a working winepath. Returns result in func_to_host_file_result.
+func_convert_file_nix_to_w32 ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    func_convert_core_file_wine_to_w32 "$1"
+    func_to_host_file_result="$func_convert_core_file_wine_to_w32_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_w32
+
+
+# func_convert_file_msys_to_cygwin ARG
+# Convert file name ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_file_msys_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    func_convert_core_msys_to_w32 "$1"
+    func_cygpath -u "$func_convert_core_msys_to_w32_result"
+    func_to_host_file_result="$func_cygpath_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_cygwin
+
+
+# func_convert_file_nix_to_cygwin ARG
+# Convert file name ARG from *nix to Cygwin format.  Requires Cygwin installed
+# in a wine environment, working winepath, and LT_CYGPATH set.  Returns result
+# in func_to_host_file_result.
+func_convert_file_nix_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    # convert from *nix to w32, then use cygpath to convert from w32 to cygwin.
+    func_convert_core_file_wine_to_w32 "$1"
+    func_cygpath -u "$func_convert_core_file_wine_to_w32_result"
+    func_to_host_file_result="$func_cygpath_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_cygwin
+
+
+#############################################
+# $build to $host PATH CONVERSION FUNCTIONS #
+#############################################
+# invoked via `$to_host_path_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# The result will be available in $func_to_host_path_result.
+#
+# Path separators are also converted from $build format to $host format.  If
+# ARG begins or ends with a path separator character, it is preserved (but
+# converted to $host format) on output.
+#
+# All path conversion functions are named using the following convention:
+#   file name conversion function    : func_convert_file_X_to_Y ()
+#   path conversion function         : func_convert_path_X_to_Y ()
+# where, for any given $build/$host combination the 'X_to_Y' value is the
+# same.  If conversion functions are added for new $build/$host combinations,
+# the two new functions must follow this pattern, or func_init_to_host_path_cmd
+# will break.
+
+
+# func_init_to_host_path_cmd
+# Ensures that function "pointer" variable $to_host_path_cmd is set to the
+# appropriate value, based on the value of $to_host_file_cmd.
+to_host_path_cmd=
+func_init_to_host_path_cmd ()
+{
+  $opt_debug
+  if test -z "$to_host_path_cmd"; then
+    func_stripname 'func_convert_file_' '' "$to_host_file_cmd"
+    to_host_path_cmd="func_convert_path_${func_stripname_result}"
+  fi
+}
+
+
+# func_to_host_path ARG
+# Converts the path ARG from $build format to $host format. Return result
+# in func_to_host_path_result.
+func_to_host_path ()
+{
+  $opt_debug
+  func_init_to_host_path_cmd
+  $to_host_path_cmd "$1"
+}
+# end func_to_host_path
+
+
+# func_convert_path_noop ARG
+# Copy ARG to func_to_host_path_result.
+func_convert_path_noop ()
+{
+  func_to_host_path_result="$1"
+}
+# end func_convert_path_noop
+
+
+# func_convert_path_msys_to_w32 ARG
+# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper.  Returns result in
+# func_to_host_path_result.
+func_convert_path_msys_to_w32 ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from ARG.  MSYS
+    # behavior is inconsistent here; cygpath turns them into '.;' and ';.';
+    # and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+    func_to_host_path_result="$func_convert_core_msys_to_w32_result"
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_msys_to_w32
+
+
+# func_convert_path_cygwin_to_w32 ARG
+# Convert path ARG from Cygwin to w32 format.  Returns result in
+# func_to_host_file_result.
+func_convert_path_cygwin_to_w32 ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"`
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_cygwin_to_w32
+
+
+# func_convert_path_nix_to_w32 ARG
+# Convert path ARG from *nix to w32 format.  Requires a wine environment and
+# a working winepath.  Returns result in func_to_host_file_result.
+func_convert_path_nix_to_w32 ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+    func_to_host_path_result="$func_convert_core_path_wine_to_w32_result"
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_nix_to_w32
+
+
+# func_convert_path_msys_to_cygwin ARG
+# Convert path ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_path_msys_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+    func_cygpath -u -p "$func_convert_core_msys_to_w32_result"
+    func_to_host_path_result="$func_cygpath_result"
+    func_convert_path_check : : \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+  fi
+}
+# end func_convert_path_msys_to_cygwin
+
+
+# func_convert_path_nix_to_cygwin ARG
+# Convert path ARG from *nix to Cygwin format.  Requires Cygwin installed in a
+# a wine environment, working winepath, and LT_CYGPATH set.  Returns result in
+# func_to_host_file_result.
+func_convert_path_nix_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from
+    # ARG. msys behavior is inconsistent here, cygpath turns them
+    # into '.;' and ';.', and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+    func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result"
+    func_to_host_path_result="$func_cygpath_result"
+    func_convert_path_check : : \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+  fi
+}
+# end func_convert_path_nix_to_cygwin
+
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+    $opt_debug
+    # Get the compilation command and the source file.
+    base_compile=
+    srcfile="$nonopt"  #  always keep a non-empty value in "srcfile"
+    suppress_opt=yes
+    suppress_output=
+    arg_mode=normal
+    libobj=
+    later=
+    pie_flag=
+
+    for arg
+    do
+      case $arg_mode in
+      arg  )
+	# do not "continue".  Instead, add this to base_compile
+	lastarg="$arg"
+	arg_mode=normal
+	;;
+
+      target )
+	libobj="$arg"
+	arg_mode=normal
+	continue
+	;;
+
+      normal )
+	# Accept any command-line options.
+	case $arg in
+	-o)
+	  test -n "$libobj" && \
+	    func_fatal_error "you cannot specify \`-o' more than once"
+	  arg_mode=target
+	  continue
+	  ;;
+
+	-pie | -fpie | -fPIE)
+          func_append pie_flag " $arg"
+	  continue
+	  ;;
+
+	-shared | -static | -prefer-pic | -prefer-non-pic)
+	  func_append later " $arg"
+	  continue
+	  ;;
+
+	-no-suppress)
+	  suppress_opt=no
+	  continue
+	  ;;
+
+	-Xcompiler)
+	  arg_mode=arg  #  the next one goes into the "base_compile" arg list
+	  continue      #  The current "srcfile" will either be retained or
+	  ;;            #  replaced later.  I would guess that would be a bug.
+
+	-Wc,*)
+	  func_stripname '-Wc,' '' "$arg"
+	  args=$func_stripname_result
+	  lastarg=
+	  save_ifs="$IFS"; IFS=','
+	  for arg in $args; do
+	    IFS="$save_ifs"
+	    func_append_quoted lastarg "$arg"
+	  done
+	  IFS="$save_ifs"
+	  func_stripname ' ' '' "$lastarg"
+	  lastarg=$func_stripname_result
+
+	  # Add the arguments to base_compile.
+	  func_append base_compile " $lastarg"
+	  continue
+	  ;;
+
+	*)
+	  # Accept the current argument as the source file.
+	  # The previous "srcfile" becomes the current argument.
+	  #
+	  lastarg="$srcfile"
+	  srcfile="$arg"
+	  ;;
+	esac  #  case $arg
+	;;
+      esac    #  case $arg_mode
+
+      # Aesthetically quote the previous argument.
+      func_append_quoted base_compile "$lastarg"
+    done # for arg
+
+    case $arg_mode in
+    arg)
+      func_fatal_error "you must specify an argument for -Xcompile"
+      ;;
+    target)
+      func_fatal_error "you must specify a target with \`-o'"
+      ;;
+    *)
+      # Get the name of the library object.
+      test -z "$libobj" && {
+	func_basename "$srcfile"
+	libobj="$func_basename_result"
+      }
+      ;;
+    esac
+
+    # Recognize several different file suffixes.
+    # If the user specifies -o file.o, it is replaced with file.lo
+    case $libobj in
+    *.[cCFSifmso] | \
+    *.ada | *.adb | *.ads | *.asm | \
+    *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+    *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup)
+      func_xform "$libobj"
+      libobj=$func_xform_result
+      ;;
+    esac
+
+    case $libobj in
+    *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+    *)
+      func_fatal_error "cannot determine name of library object from \`$libobj'"
+      ;;
+    esac
+
+    func_infer_tag $base_compile
+
+    for arg in $later; do
+      case $arg in
+      -shared)
+	test "$build_libtool_libs" != yes && \
+	  func_fatal_configuration "can not build a shared library"
+	build_old_libs=no
+	continue
+	;;
+
+      -static)
+	build_libtool_libs=no
+	build_old_libs=yes
+	continue
+	;;
+
+      -prefer-pic)
+	pic_mode=yes
+	continue
+	;;
+
+      -prefer-non-pic)
+	pic_mode=no
+	continue
+	;;
+      esac
+    done
+
+    func_quote_for_eval "$libobj"
+    test "X$libobj" != "X$func_quote_for_eval_result" \
+      && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"'	 &()|`$[]' \
+      && func_warning "libobj name \`$libobj' may not contain shell special characters."
+    func_dirname_and_basename "$obj" "/" ""
+    objname="$func_basename_result"
+    xdir="$func_dirname_result"
+    lobj=${xdir}$objdir/$objname
+
+    test -z "$base_compile" && \
+      func_fatal_help "you must specify a compilation command"
+
+    # Delete any leftover library objects.
+    if test "$build_old_libs" = yes; then
+      removelist="$obj $lobj $libobj ${libobj}T"
+    else
+      removelist="$lobj $libobj ${libobj}T"
+    fi
+
+    # On Cygwin there's no "real" PIC flag so we must build both object types
+    case $host_os in
+    cygwin* | mingw* | pw32* | os2* | cegcc*)
+      pic_mode=default
+      ;;
+    esac
+    if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+      # non-PIC code in shared libraries is not supported
+      pic_mode=default
+    fi
+
+    # Calculate the filename of the output object if compiler does
+    # not support -o with -c
+    if test "$compiler_c_o" = no; then
+      output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext}
+      lockfile="$output_obj.lock"
+    else
+      output_obj=
+      need_locks=no
+      lockfile=
+    fi
+
+    # Lock this critical section if it is needed
+    # We use this script file to make the link, it avoids creating a new file
+    if test "$need_locks" = yes; then
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+	func_echo "Waiting for $lockfile to be removed"
+	sleep 2
+      done
+    elif test "$need_locks" = warn; then
+      if test -f "$lockfile"; then
+	$ECHO "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+      func_append removelist " $output_obj"
+      $ECHO "$srcfile" > "$lockfile"
+    fi
+
+    $opt_dry_run || $RM $removelist
+    func_append removelist " $lockfile"
+    trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
+
+    func_to_tool_file "$srcfile" func_convert_file_msys_to_w32
+    srcfile=$func_to_tool_file_result
+    func_quote_for_eval "$srcfile"
+    qsrcfile=$func_quote_for_eval_result
+
+    # Only build a PIC object if we are building libtool libraries.
+    if test "$build_libtool_libs" = yes; then
+      # Without this assignment, base_compile gets emptied.
+      fbsd_hideous_sh_bug=$base_compile
+
+      if test "$pic_mode" != no; then
+	command="$base_compile $qsrcfile $pic_flag"
+      else
+	# Don't build PIC code
+	command="$base_compile $qsrcfile"
+      fi
+
+      func_mkdir_p "$xdir$objdir"
+
+      if test -z "$output_obj"; then
+	# Place PIC objects in $objdir
+	func_append command " -o $lobj"
+      fi
+
+      func_show_eval_locale "$command"	\
+          'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
+
+      if test "$need_locks" = warn &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed, then go on to compile the next one
+      if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+	func_show_eval '$MV "$output_obj" "$lobj"' \
+	  'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+
+      # Allow error messages only from the first compilation.
+      if test "$suppress_opt" = yes; then
+	suppress_output=' >/dev/null 2>&1'
+      fi
+    fi
+
+    # Only build a position-dependent object if we build old libraries.
+    if test "$build_old_libs" = yes; then
+      if test "$pic_mode" != yes; then
+	# Don't build PIC code
+	command="$base_compile $qsrcfile$pie_flag"
+      else
+	command="$base_compile $qsrcfile $pic_flag"
+      fi
+      if test "$compiler_c_o" = yes; then
+	func_append command " -o $obj"
+      fi
+
+      # Suppress compiler output if we already did a PIC compilation.
+      func_append command "$suppress_output"
+      func_show_eval_locale "$command" \
+        '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
+
+      if test "$need_locks" = warn &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed
+      if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+	func_show_eval '$MV "$output_obj" "$obj"' \
+	  'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+    fi
+
+    $opt_dry_run || {
+      func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
+
+      # Unlock the critical section if it was locked
+      if test "$need_locks" != no; then
+	removelist=$lockfile
+        $RM "$lockfile"
+      fi
+    }
+
+    exit $EXIT_SUCCESS
+}
+
+$opt_help || {
+  test "$opt_mode" = compile && func_mode_compile ${1+"$@"}
+}
+
+func_mode_help ()
+{
+    # We need to display help for each of the modes.
+    case $opt_mode in
+      "")
+        # Generic help is extracted from the usage comments
+        # at the start of this file.
+        func_help
+        ;;
+
+      clean)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      compile)
+      $ECHO \
+"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+  -o OUTPUT-FILE    set the output file name to OUTPUT-FILE
+  -no-suppress      do not suppress compiler output for multiple passes
+  -prefer-pic       try to build PIC objects only
+  -prefer-non-pic   try to build non-PIC objects only
+  -shared           do not build a \`.o' file suitable for static linking
+  -static           only build a \`.o' file suitable for static linking
+  -Wc,FLAG          pass FLAG directly to the compiler
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+        ;;
+
+      execute)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+  -dlopen FILE      add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+        ;;
+
+      finish)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges.  Use
+the \`--dry-run' option if you just want to see what would be executed."
+        ;;
+
+      install)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command.  The first component should be
+either the \`install' or \`cp' program.
+
+The following components of INSTALL-COMMAND are treated specially:
+
+  -inst-prefix-dir PREFIX-DIR  Use PREFIX-DIR as a staging area for installation
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+        ;;
+
+      link)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+  -all-static       do not do any dynamic linking at all
+  -avoid-version    do not add a version suffix if possible
+  -bindir BINDIR    specify path to binaries directory (for systems where
+                    libraries must be found in the PATH setting at runtime)
+  -dlopen FILE      \`-dlpreopen' FILE if it cannot be dlopened at runtime
+  -dlpreopen FILE   link in FILE and add its symbols to lt_preloaded_symbols
+  -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+  -export-symbols SYMFILE
+                    try to export only the symbols listed in SYMFILE
+  -export-symbols-regex REGEX
+                    try to export only the symbols matching REGEX
+  -LLIBDIR          search LIBDIR for required installed libraries
+  -lNAME            OUTPUT-FILE requires the installed library libNAME
+  -module           build a library that can dlopened
+  -no-fast-install  disable the fast-install mode
+  -no-install       link a not-installable executable
+  -no-undefined     declare that a library does not refer to external symbols
+  -o OUTPUT-FILE    create OUTPUT-FILE from the specified objects
+  -objectlist FILE  Use a list of object files found in FILE to specify objects
+  -precious-files-regex REGEX
+                    don't remove output files matching REGEX
+  -release RELEASE  specify package release information
+  -rpath LIBDIR     the created library will eventually be installed in LIBDIR
+  -R[ ]LIBDIR       add LIBDIR to the runtime path of programs and libraries
+  -shared           only do dynamic linking of libtool libraries
+  -shrext SUFFIX    override the standard shared library file extension
+  -static           do not do any dynamic linking of uninstalled libtool libraries
+  -static-libtool-libs
+                    do not do any dynamic linking of libtool libraries
+  -version-info CURRENT[:REVISION[:AGE]]
+                    specify library version info [each variable defaults to 0]
+  -weak LIBNAME     declare that the target provides the LIBNAME interface
+  -Wc,FLAG
+  -Xcompiler FLAG   pass linker-specific FLAG directly to the compiler
+  -Wl,FLAG
+  -Xlinker FLAG     pass linker-specific FLAG directly to the linker
+  -XCClinker FLAG   pass link-specific FLAG to the compiler driver (CC)
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename.  Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+        ;;
+
+      uninstall)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      *)
+        func_fatal_help "invalid operation mode \`$opt_mode'"
+        ;;
+    esac
+
+    echo
+    $ECHO "Try \`$progname --help' for more information about other modes."
+}
+
+# Now that we've collected a possible --mode arg, show help if necessary
+if $opt_help; then
+  if test "$opt_help" = :; then
+    func_mode_help
+  else
+    {
+      func_help noexit
+      for opt_mode in compile link execute install finish uninstall clean; do
+	func_mode_help
+      done
+    } | sed -n '1p; 2,$s/^Usage:/  or: /p'
+    {
+      func_help noexit
+      for opt_mode in compile link execute install finish uninstall clean; do
+	echo
+	func_mode_help
+      done
+    } |
+    sed '1d
+      /^When reporting/,/^Report/{
+	H
+	d
+      }
+      $x
+      /information about other modes/d
+      /more detailed .*MODE/d
+      s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
+  fi
+  exit $?
+fi
+
+
+# func_mode_execute arg...
+func_mode_execute ()
+{
+    $opt_debug
+    # The first argument is the command name.
+    cmd="$nonopt"
+    test -z "$cmd" && \
+      func_fatal_help "you must specify a COMMAND"
+
+    # Handle -dlopen flags immediately.
+    for file in $opt_dlopen; do
+      test -f "$file" \
+	|| func_fatal_help "\`$file' is not a file"
+
+      dir=
+      case $file in
+      *.la)
+	func_resolve_sysroot "$file"
+	file=$func_resolve_sysroot_result
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$file" \
+	  || func_fatal_help "\`$lib' is not a valid libtool archive"
+
+	# Read the libtool library.
+	dlname=
+	library_names=
+	func_source "$file"
+
+	# Skip this library if it cannot be dlopened.
+	if test -z "$dlname"; then
+	  # Warn if it was a shared library.
+	  test -n "$library_names" && \
+	    func_warning "\`$file' was not linked with \`-export-dynamic'"
+	  continue
+	fi
+
+	func_dirname "$file" "" "."
+	dir="$func_dirname_result"
+
+	if test -f "$dir/$objdir/$dlname"; then
+	  func_append dir "/$objdir"
+	else
+	  if test ! -f "$dir/$dlname"; then
+	    func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'"
+	  fi
+	fi
+	;;
+
+      *.lo)
+	# Just add the directory containing the .lo file.
+	func_dirname "$file" "" "."
+	dir="$func_dirname_result"
+	;;
+
+      *)
+	func_warning "\`-dlopen' is ignored for non-libtool libraries and objects"
+	continue
+	;;
+      esac
+
+      # Get the absolute pathname.
+      absdir=`cd "$dir" && pwd`
+      test -n "$absdir" && dir="$absdir"
+
+      # Now add the directory to shlibpath_var.
+      if eval "test -z \"\$$shlibpath_var\""; then
+	eval "$shlibpath_var=\"\$dir\""
+      else
+	eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+      fi
+    done
+
+    # This variable tells wrapper scripts just to set shlibpath_var
+    # rather than running their programs.
+    libtool_execute_magic="$magic"
+
+    # Check if any of the arguments is a wrapper script.
+    args=
+    for file
+    do
+      case $file in
+      -* | *.la | *.lo ) ;;
+      *)
+	# Do a test to see if this is really a libtool program.
+	if func_ltwrapper_script_p "$file"; then
+	  func_source "$file"
+	  # Transform arg to wrapped name.
+	  file="$progdir/$program"
+	elif func_ltwrapper_executable_p "$file"; then
+	  func_ltwrapper_scriptname "$file"
+	  func_source "$func_ltwrapper_scriptname_result"
+	  # Transform arg to wrapped name.
+	  file="$progdir/$program"
+	fi
+	;;
+      esac
+      # Quote arguments (to preserve shell metacharacters).
+      func_append_quoted args "$file"
+    done
+
+    if test "X$opt_dry_run" = Xfalse; then
+      if test -n "$shlibpath_var"; then
+	# Export the shlibpath_var.
+	eval "export $shlibpath_var"
+      fi
+
+      # Restore saved environment variables
+      for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+      do
+	eval "if test \"\${save_$lt_var+set}\" = set; then
+                $lt_var=\$save_$lt_var; export $lt_var
+	      else
+		$lt_unset $lt_var
+	      fi"
+      done
+
+      # Now prepare to actually exec the command.
+      exec_cmd="\$cmd$args"
+    else
+      # Display what would be done.
+      if test -n "$shlibpath_var"; then
+	eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+	echo "export $shlibpath_var"
+      fi
+      $ECHO "$cmd$args"
+      exit $EXIT_SUCCESS
+    fi
+}
+
+test "$opt_mode" = execute && func_mode_execute ${1+"$@"}
+
+
+# func_mode_finish arg...
+func_mode_finish ()
+{
+    $opt_debug
+    libs=
+    libdirs=
+    admincmds=
+
+    for opt in "$nonopt" ${1+"$@"}
+    do
+      if test -d "$opt"; then
+	func_append libdirs " $opt"
+
+      elif test -f "$opt"; then
+	if func_lalib_unsafe_p "$opt"; then
+	  func_append libs " $opt"
+	else
+	  func_warning "\`$opt' is not a valid libtool archive"
+	fi
+
+      else
+	func_fatal_error "invalid argument \`$opt'"
+      fi
+    done
+
+    if test -n "$libs"; then
+      if test -n "$lt_sysroot"; then
+        sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"`
+        sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;"
+      else
+        sysroot_cmd=
+      fi
+
+      # Remove sysroot references
+      if $opt_dry_run; then
+        for lib in $libs; do
+          echo "removing references to $lt_sysroot and \`=' prefixes from $lib"
+        done
+      else
+        tmpdir=`func_mktempdir`
+        for lib in $libs; do
+	  sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \
+	    > $tmpdir/tmp-la
+	  mv -f $tmpdir/tmp-la $lib
+	done
+        ${RM}r "$tmpdir"
+      fi
+    fi
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      for libdir in $libdirs; do
+	if test -n "$finish_cmds"; then
+	  # Do each command in the finish commands.
+	  func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
+'"$cmd"'"'
+	fi
+	if test -n "$finish_eval"; then
+	  # Do the single finish_eval.
+	  eval cmds=\"$finish_eval\"
+	  $opt_dry_run || eval "$cmds" || func_append admincmds "
+       $cmds"
+	fi
+      done
+    fi
+
+    # Exit here if they wanted silent mode.
+    $opt_silent && exit $EXIT_SUCCESS
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      echo "----------------------------------------------------------------------"
+      echo "Libraries have been installed in:"
+      for libdir in $libdirs; do
+	$ECHO "   $libdir"
+      done
+      echo
+      echo "If you ever happen to want to link against installed libraries"
+      echo "in a given directory, LIBDIR, you must either use libtool, and"
+      echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+      echo "flag during linking and do at least one of the following:"
+      if test -n "$shlibpath_var"; then
+	echo "   - add LIBDIR to the \`$shlibpath_var' environment variable"
+	echo "     during execution"
+      fi
+      if test -n "$runpath_var"; then
+	echo "   - add LIBDIR to the \`$runpath_var' environment variable"
+	echo "     during linking"
+      fi
+      if test -n "$hardcode_libdir_flag_spec"; then
+	libdir=LIBDIR
+	eval flag=\"$hardcode_libdir_flag_spec\"
+
+	$ECHO "   - use the \`$flag' linker flag"
+      fi
+      if test -n "$admincmds"; then
+	$ECHO "   - have your system administrator run these commands:$admincmds"
+      fi
+      if test -f /etc/ld.so.conf; then
+	echo "   - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+      fi
+      echo
+
+      echo "See any operating system documentation about shared libraries for"
+      case $host in
+	solaris2.[6789]|solaris2.1[0-9])
+	  echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+	  echo "pages."
+	  ;;
+	*)
+	  echo "more information, such as the ld(1) and ld.so(8) manual pages."
+	  ;;
+      esac
+      echo "----------------------------------------------------------------------"
+    fi
+    exit $EXIT_SUCCESS
+}
+
+test "$opt_mode" = finish && func_mode_finish ${1+"$@"}
+
+
+# func_mode_install arg...
+func_mode_install ()
+{
+    $opt_debug
+    # There may be an optional sh(1) argument at the beginning of
+    # install_prog (especially on Windows NT).
+    if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+       # Allow the use of GNU shtool's install command.
+       case $nonopt in *shtool*) :;; *) false;; esac; then
+      # Aesthetically quote it.
+      func_quote_for_eval "$nonopt"
+      install_prog="$func_quote_for_eval_result "
+      arg=$1
+      shift
+    else
+      install_prog=
+      arg=$nonopt
+    fi
+
+    # The real first argument should be the name of the installation program.
+    # Aesthetically quote it.
+    func_quote_for_eval "$arg"
+    func_append install_prog "$func_quote_for_eval_result"
+    install_shared_prog=$install_prog
+    case " $install_prog " in
+      *[\\\ /]cp\ *) install_cp=: ;;
+      *) install_cp=false ;;
+    esac
+
+    # We need to accept at least all the BSD install flags.
+    dest=
+    files=
+    opts=
+    prev=
+    install_type=
+    isdir=no
+    stripme=
+    no_mode=:
+    for arg
+    do
+      arg2=
+      if test -n "$dest"; then
+	func_append files " $dest"
+	dest=$arg
+	continue
+      fi
+
+      case $arg in
+      -d) isdir=yes ;;
+      -f)
+	if $install_cp; then :; else
+	  prev=$arg
+	fi
+	;;
+      -g | -m | -o)
+	prev=$arg
+	;;
+      -s)
+	stripme=" -s"
+	continue
+	;;
+      -*)
+	;;
+      *)
+	# If the previous option needed an argument, then skip it.
+	if test -n "$prev"; then
+	  if test "x$prev" = x-m && test -n "$install_override_mode"; then
+	    arg2=$install_override_mode
+	    no_mode=false
+	  fi
+	  prev=
+	else
+	  dest=$arg
+	  continue
+	fi
+	;;
+      esac
+
+      # Aesthetically quote the argument.
+      func_quote_for_eval "$arg"
+      func_append install_prog " $func_quote_for_eval_result"
+      if test -n "$arg2"; then
+	func_quote_for_eval "$arg2"
+      fi
+      func_append install_shared_prog " $func_quote_for_eval_result"
+    done
+
+    test -z "$install_prog" && \
+      func_fatal_help "you must specify an install program"
+
+    test -n "$prev" && \
+      func_fatal_help "the \`$prev' option requires an argument"
+
+    if test -n "$install_override_mode" && $no_mode; then
+      if $install_cp; then :; else
+	func_quote_for_eval "$install_override_mode"
+	func_append install_shared_prog " -m $func_quote_for_eval_result"
+      fi
+    fi
+
+    if test -z "$files"; then
+      if test -z "$dest"; then
+	func_fatal_help "no file or destination specified"
+      else
+	func_fatal_help "you must specify a destination"
+      fi
+    fi
+
+    # Strip any trailing slash from the destination.
+    func_stripname '' '/' "$dest"
+    dest=$func_stripname_result
+
+    # Check to see that the destination is a directory.
+    test -d "$dest" && isdir=yes
+    if test "$isdir" = yes; then
+      destdir="$dest"
+      destname=
+    else
+      func_dirname_and_basename "$dest" "" "."
+      destdir="$func_dirname_result"
+      destname="$func_basename_result"
+
+      # Not a directory, so check to see that there is only one file specified.
+      set dummy $files; shift
+      test "$#" -gt 1 && \
+	func_fatal_help "\`$dest' is not a directory"
+    fi
+    case $destdir in
+    [\\/]* | [A-Za-z]:[\\/]*) ;;
+    *)
+      for file in $files; do
+	case $file in
+	*.lo) ;;
+	*)
+	  func_fatal_help "\`$destdir' must be an absolute directory name"
+	  ;;
+	esac
+      done
+      ;;
+    esac
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    staticlibs=
+    future_libdirs=
+    current_libdirs=
+    for file in $files; do
+
+      # Do each installation.
+      case $file in
+      *.$libext)
+	# Do the static libraries later.
+	func_append staticlibs " $file"
+	;;
+
+      *.la)
+	func_resolve_sysroot "$file"
+	file=$func_resolve_sysroot_result
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$file" \
+	  || func_fatal_help "\`$file' is not a valid libtool archive"
+
+	library_names=
+	old_library=
+	relink_command=
+	func_source "$file"
+
+	# Add the libdir to current_libdirs if it is the destination.
+	if test "X$destdir" = "X$libdir"; then
+	  case "$current_libdirs " in
+	  *" $libdir "*) ;;
+	  *) func_append current_libdirs " $libdir" ;;
+	  esac
+	else
+	  # Note the libdir as a future libdir.
+	  case "$future_libdirs " in
+	  *" $libdir "*) ;;
+	  *) func_append future_libdirs " $libdir" ;;
+	  esac
+	fi
+
+	func_dirname "$file" "/" ""
+	dir="$func_dirname_result"
+	func_append dir "$objdir"
+
+	if test -n "$relink_command"; then
+	  # Determine the prefix the user has applied to our future dir.
+	  inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
+
+	  # Don't allow the user to place us outside of our expected
+	  # location b/c this prevents finding dependent libraries that
+	  # are installed to the same prefix.
+	  # At present, this check doesn't affect windows .dll's that
+	  # are installed into $libdir/../bin (currently, that works fine)
+	  # but it's something to keep an eye on.
+	  test "$inst_prefix_dir" = "$destdir" && \
+	    func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
+
+	  if test -n "$inst_prefix_dir"; then
+	    # Stick the inst_prefix_dir data into the link command.
+	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+	  else
+	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+	  fi
+
+	  func_warning "relinking \`$file'"
+	  func_show_eval "$relink_command" \
+	    'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
+	fi
+
+	# See the names of the shared library.
+	set dummy $library_names; shift
+	if test -n "$1"; then
+	  realname="$1"
+	  shift
+
+	  srcname="$realname"
+	  test -n "$relink_command" && srcname="$realname"T
+
+	  # Install the shared library and build the symlinks.
+	  func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
+	      'exit $?'
+	  tstripme="$stripme"
+	  case $host_os in
+	  cygwin* | mingw* | pw32* | cegcc*)
+	    case $realname in
+	    *.dll.a)
+	      tstripme=""
+	      ;;
+	    esac
+	    ;;
+	  esac
+	  if test -n "$tstripme" && test -n "$striplib"; then
+	    func_show_eval "$striplib $destdir/$realname" 'exit $?'
+	  fi
+
+	  if test "$#" -gt 0; then
+	    # Delete the old symlinks, and create new ones.
+	    # Try `ln -sf' first, because the `ln' binary might depend on
+	    # the symlink we replace!  Solaris /bin/ln does not understand -f,
+	    # so we also need to try rm && ln -s.
+	    for linkname
+	    do
+	      test "$linkname" != "$realname" \
+		&& func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
+	    done
+	  fi
+
+	  # Do each command in the postinstall commands.
+	  lib="$destdir/$realname"
+	  func_execute_cmds "$postinstall_cmds" 'exit $?'
+	fi
+
+	# Install the pseudo-library for information purposes.
+	func_basename "$file"
+	name="$func_basename_result"
+	instname="$dir/$name"i
+	func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
+
+	# Maybe install the static library, too.
+	test -n "$old_library" && func_append staticlibs " $dir/$old_library"
+	;;
+
+      *.lo)
+	# Install (i.e. copy) a libtool object.
+
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile="$destdir/$destname"
+	else
+	  func_basename "$file"
+	  destfile="$func_basename_result"
+	  destfile="$destdir/$destfile"
+	fi
+
+	# Deduce the name of the destination old-style object file.
+	case $destfile in
+	*.lo)
+	  func_lo2o "$destfile"
+	  staticdest=$func_lo2o_result
+	  ;;
+	*.$objext)
+	  staticdest="$destfile"
+	  destfile=
+	  ;;
+	*)
+	  func_fatal_help "cannot copy a libtool object to \`$destfile'"
+	  ;;
+	esac
+
+	# Install the libtool object if requested.
+	test -n "$destfile" && \
+	  func_show_eval "$install_prog $file $destfile" 'exit $?'
+
+	# Install the old object if enabled.
+	if test "$build_old_libs" = yes; then
+	  # Deduce the name of the old-style object file.
+	  func_lo2o "$file"
+	  staticobj=$func_lo2o_result
+	  func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
+	fi
+	exit $EXIT_SUCCESS
+	;;
+
+      *)
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile="$destdir/$destname"
+	else
+	  func_basename "$file"
+	  destfile="$func_basename_result"
+	  destfile="$destdir/$destfile"
+	fi
+
+	# If the file is missing, and there is a .exe on the end, strip it
+	# because it is most likely a libtool script we actually want to
+	# install
+	stripped_ext=""
+	case $file in
+	  *.exe)
+	    if test ! -f "$file"; then
+	      func_stripname '' '.exe' "$file"
+	      file=$func_stripname_result
+	      stripped_ext=".exe"
+	    fi
+	    ;;
+	esac
+
+	# Do a test to see if this is really a libtool program.
+	case $host in
+	*cygwin* | *mingw*)
+	    if func_ltwrapper_executable_p "$file"; then
+	      func_ltwrapper_scriptname "$file"
+	      wrapper=$func_ltwrapper_scriptname_result
+	    else
+	      func_stripname '' '.exe' "$file"
+	      wrapper=$func_stripname_result
+	    fi
+	    ;;
+	*)
+	    wrapper=$file
+	    ;;
+	esac
+	if func_ltwrapper_script_p "$wrapper"; then
+	  notinst_deplibs=
+	  relink_command=
+
+	  func_source "$wrapper"
+
+	  # Check the variables that should have been set.
+	  test -z "$generated_by_libtool_version" && \
+	    func_fatal_error "invalid libtool wrapper script \`$wrapper'"
+
+	  finalize=yes
+	  for lib in $notinst_deplibs; do
+	    # Check to see that each library is installed.
+	    libdir=
+	    if test -f "$lib"; then
+	      func_source "$lib"
+	    fi
+	    libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test
+	    if test -n "$libdir" && test ! -f "$libfile"; then
+	      func_warning "\`$lib' has not been installed in \`$libdir'"
+	      finalize=no
+	    fi
+	  done
+
+	  relink_command=
+	  func_source "$wrapper"
+
+	  outputname=
+	  if test "$fast_install" = no && test -n "$relink_command"; then
+	    $opt_dry_run || {
+	      if test "$finalize" = yes; then
+	        tmpdir=`func_mktempdir`
+		func_basename "$file$stripped_ext"
+		file="$func_basename_result"
+	        outputname="$tmpdir/$file"
+	        # Replace the output file specification.
+	        relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
+
+	        $opt_silent || {
+	          func_quote_for_expand "$relink_command"
+		  eval "func_echo $func_quote_for_expand_result"
+	        }
+	        if eval "$relink_command"; then :
+	          else
+		  func_error "error: relink \`$file' with the above command before installing it"
+		  $opt_dry_run || ${RM}r "$tmpdir"
+		  continue
+	        fi
+	        file="$outputname"
+	      else
+	        func_warning "cannot relink \`$file'"
+	      fi
+	    }
+	  else
+	    # Install the binary that we compiled earlier.
+	    file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
+	  fi
+	fi
+
+	# remove .exe since cygwin /usr/bin/install will append another
+	# one anyway
+	case $install_prog,$host in
+	*/usr/bin/install*,*cygwin*)
+	  case $file:$destfile in
+	  *.exe:*.exe)
+	    # this is ok
+	    ;;
+	  *.exe:*)
+	    destfile=$destfile.exe
+	    ;;
+	  *:*.exe)
+	    func_stripname '' '.exe' "$destfile"
+	    destfile=$func_stripname_result
+	    ;;
+	  esac
+	  ;;
+	esac
+	func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
+	$opt_dry_run || if test -n "$outputname"; then
+	  ${RM}r "$tmpdir"
+	fi
+	;;
+      esac
+    done
+
+    for file in $staticlibs; do
+      func_basename "$file"
+      name="$func_basename_result"
+
+      # Set up the ranlib parameters.
+      oldlib="$destdir/$name"
+      func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+      tool_oldlib=$func_to_tool_file_result
+
+      func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
+
+      if test -n "$stripme" && test -n "$old_striplib"; then
+	func_show_eval "$old_striplib $tool_oldlib" 'exit $?'
+      fi
+
+      # Do each command in the postinstall commands.
+      func_execute_cmds "$old_postinstall_cmds" 'exit $?'
+    done
+
+    test -n "$future_libdirs" && \
+      func_warning "remember to run \`$progname --finish$future_libdirs'"
+
+    if test -n "$current_libdirs"; then
+      # Maybe just do a dry run.
+      $opt_dry_run && current_libdirs=" -n$current_libdirs"
+      exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+    else
+      exit $EXIT_SUCCESS
+    fi
+}
+
+test "$opt_mode" = install && func_mode_install ${1+"$@"}
+
+
+# func_generate_dlsyms outputname originator pic_p
+# Extract symbols from dlprefiles and create ${outputname}S.o with
+# a dlpreopen symbol table.
+func_generate_dlsyms ()
+{
+    $opt_debug
+    my_outputname="$1"
+    my_originator="$2"
+    my_pic_p="${3-no}"
+    my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'`
+    my_dlsyms=
+
+    if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+      if test -n "$NM" && test -n "$global_symbol_pipe"; then
+	my_dlsyms="${my_outputname}S.c"
+      else
+	func_error "not configured to extract global symbols from dlpreopened files"
+      fi
+    fi
+
+    if test -n "$my_dlsyms"; then
+      case $my_dlsyms in
+      "") ;;
+      *.c)
+	# Discover the nlist of each of the dlfiles.
+	nlist="$output_objdir/${my_outputname}.nm"
+
+	func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
+
+	# Parse the name list into a source file.
+	func_verbose "creating $output_objdir/$my_dlsyms"
+
+	$opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
+/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#endif
+
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data.  */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+/* External symbol declarations for the compiler. */\
+"
+
+	if test "$dlself" = yes; then
+	  func_verbose "generating symbol list for \`$output'"
+
+	  $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
+
+	  # Add our own program objects to the symbol list.
+	  progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	  for progfile in $progfiles; do
+	    func_to_tool_file "$progfile" func_convert_file_msys_to_w32
+	    func_verbose "extracting global C symbols from \`$func_to_tool_file_result'"
+	    $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'"
+	  done
+
+	  if test -n "$exclude_expsyms"; then
+	    $opt_dry_run || {
+	      eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	    }
+	  fi
+
+	  if test -n "$export_symbols_regex"; then
+	    $opt_dry_run || {
+	      eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	    }
+	  fi
+
+	  # Prepare the list of exported symbols
+	  if test -z "$export_symbols"; then
+	    export_symbols="$output_objdir/$outputname.exp"
+	    $opt_dry_run || {
+	      $RM $export_symbols
+	      eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+	      case $host in
+	      *cygwin* | *mingw* | *cegcc* )
+                eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+                eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+	        ;;
+	      esac
+	    }
+	  else
+	    $opt_dry_run || {
+	      eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+	      eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	      case $host in
+	        *cygwin* | *mingw* | *cegcc* )
+	          eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+	          eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+	          ;;
+	      esac
+	    }
+	  fi
+	fi
+
+	for dlprefile in $dlprefiles; do
+	  func_verbose "extracting global C symbols from \`$dlprefile'"
+	  func_basename "$dlprefile"
+	  name="$func_basename_result"
+          case $host in
+	    *cygwin* | *mingw* | *cegcc* )
+	      # if an import library, we need to obtain dlname
+	      if func_win32_import_lib_p "$dlprefile"; then
+	        func_tr_sh "$dlprefile"
+	        eval "curr_lafile=\$libfile_$func_tr_sh_result"
+	        dlprefile_dlbasename=""
+	        if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then
+	          # Use subshell, to avoid clobbering current variable values
+	          dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"`
+	          if test -n "$dlprefile_dlname" ; then
+	            func_basename "$dlprefile_dlname"
+	            dlprefile_dlbasename="$func_basename_result"
+	          else
+	            # no lafile. user explicitly requested -dlpreopen .
+	            $sharedlib_from_linklib_cmd "$dlprefile"
+	            dlprefile_dlbasename=$sharedlib_from_linklib_result
+	          fi
+	        fi
+	        $opt_dry_run || {
+	          if test -n "$dlprefile_dlbasename" ; then
+	            eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"'
+	          else
+	            func_warning "Could not compute DLL name from $name"
+	            eval '$ECHO ": $name " >> "$nlist"'
+	          fi
+	          func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	          eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe |
+	            $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'"
+	        }
+	      else # not an import lib
+	        $opt_dry_run || {
+	          eval '$ECHO ": $name " >> "$nlist"'
+	          func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	          eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+	        }
+	      fi
+	    ;;
+	    *)
+	      $opt_dry_run || {
+	        eval '$ECHO ": $name " >> "$nlist"'
+	        func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	        eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+	      }
+	    ;;
+          esac
+	done
+
+	$opt_dry_run || {
+	  # Make sure we have at least an empty file.
+	  test -f "$nlist" || : > "$nlist"
+
+	  if test -n "$exclude_expsyms"; then
+	    $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+	    $MV "$nlist"T "$nlist"
+	  fi
+
+	  # Try sorting and uniquifying the output.
+	  if $GREP -v "^: " < "$nlist" |
+	      if sort -k 3 /dev/null 2>&1; then
+		sort -k 3
+	      else
+		sort +2
+	      fi |
+	      uniq > "$nlist"S; then
+	    :
+	  else
+	    $GREP -v "^: " < "$nlist" > "$nlist"S
+	  fi
+
+	  if test -f "$nlist"S; then
+	    eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
+	  else
+	    echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
+	  fi
+
+	  echo >> "$output_objdir/$my_dlsyms" "\
+
+/* The mapping between symbol names and symbols.  */
+typedef struct {
+  const char *name;
+  void *address;
+} lt_dlsymlist;
+extern LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[];
+LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[] =
+{\
+  { \"$my_originator\", (void *) 0 },"
+
+	  case $need_lib_prefix in
+	  no)
+	    eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
+	    ;;
+	  *)
+	    eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
+	    ;;
+	  esac
+	  echo >> "$output_objdir/$my_dlsyms" "\
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt_${my_prefix}_LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+	} # !$opt_dry_run
+
+	pic_flag_for_symtable=
+	case "$compile_command " in
+	*" -static "*) ;;
+	*)
+	  case $host in
+	  # compiling the symbol table file with pic_flag works around
+	  # a FreeBSD bug that causes programs to crash when -lm is
+	  # linked before any other PIC object.  But we must not use
+	  # pic_flag when linking with -static.  The problem exists in
+	  # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+	  *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+	    pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
+	  *-*-hpux*)
+	    pic_flag_for_symtable=" $pic_flag"  ;;
+	  *)
+	    if test "X$my_pic_p" != Xno; then
+	      pic_flag_for_symtable=" $pic_flag"
+	    fi
+	    ;;
+	  esac
+	  ;;
+	esac
+	symtab_cflags=
+	for arg in $LTCFLAGS; do
+	  case $arg in
+	  -pie | -fpie | -fPIE) ;;
+	  *) func_append symtab_cflags " $arg" ;;
+	  esac
+	done
+
+	# Now compile the dynamic symbol file.
+	func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
+
+	# Clean up the generated files.
+	func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"'
+
+	# Transform the symbol file into the correct name.
+	symfileobj="$output_objdir/${my_outputname}S.$objext"
+	case $host in
+	*cygwin* | *mingw* | *cegcc* )
+	  if test -f "$output_objdir/$my_outputname.def"; then
+	    compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+	    finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+	  else
+	    compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	    finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  fi
+	  ;;
+	*)
+	  compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  ;;
+	esac
+	;;
+      *)
+	func_fatal_error "unknown suffix for \`$my_dlsyms'"
+	;;
+      esac
+    else
+      # We keep going just in case the user didn't refer to
+      # lt_preloaded_symbols.  The linker will fail if global_symbol_pipe
+      # really was required.
+
+      # Nullify the symbol file.
+      compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
+      finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
+    fi
+}
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+# Despite the name, also deal with 64 bit binaries.
+func_win32_libid ()
+{
+  $opt_debug
+  win32_libid_type="unknown"
+  win32_fileres=`file -L $1 2>/dev/null`
+  case $win32_fileres in
+  *ar\ archive\ import\ library*) # definitely import
+    win32_libid_type="x86 archive import"
+    ;;
+  *ar\ archive*) # could be an import, or static
+    # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
+    if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
+       $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
+      func_to_tool_file "$1" func_convert_file_msys_to_w32
+      win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" |
+	$SED -n -e '
+	    1,100{
+		/ I /{
+		    s,.*,import,
+		    p
+		    q
+		}
+	    }'`
+      case $win32_nmres in
+      import*)  win32_libid_type="x86 archive import";;
+      *)        win32_libid_type="x86 archive static";;
+      esac
+    fi
+    ;;
+  *DLL*)
+    win32_libid_type="x86 DLL"
+    ;;
+  *executable*) # but shell scripts are "executable" too...
+    case $win32_fileres in
+    *MS\ Windows\ PE\ Intel*)
+      win32_libid_type="x86 DLL"
+      ;;
+    esac
+    ;;
+  esac
+  $ECHO "$win32_libid_type"
+}
+
+# func_cygming_dll_for_implib ARG
+#
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib ()
+{
+  $opt_debug
+  sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"`
+}
+
+# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs
+#
+# The is the core of a fallback implementation of a
+# platform-specific function to extract the name of the
+# DLL associated with the specified import library LIBNAME.
+#
+# SECTION_NAME is either .idata$6 or .idata$7, depending
+# on the platform and compiler that created the implib.
+#
+# Echos the name of the DLL associated with the
+# specified import library.
+func_cygming_dll_for_implib_fallback_core ()
+{
+  $opt_debug
+  match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"`
+  $OBJDUMP -s --section "$1" "$2" 2>/dev/null |
+    $SED '/^Contents of section '"$match_literal"':/{
+      # Place marker at beginning of archive member dllname section
+      s/.*/====MARK====/
+      p
+      d
+    }
+    # These lines can sometimes be longer than 43 characters, but
+    # are always uninteresting
+    /:[	 ]*file format pe[i]\{,1\}-/d
+    /^In archive [^:]*:/d
+    # Ensure marker is printed
+    /^====MARK====/p
+    # Remove all lines with less than 43 characters
+    /^.\{43\}/!d
+    # From remaining lines, remove first 43 characters
+    s/^.\{43\}//' |
+    $SED -n '
+      # Join marker and all lines until next marker into a single line
+      /^====MARK====/ b para
+      H
+      $ b para
+      b
+      :para
+      x
+      s/\n//g
+      # Remove the marker
+      s/^====MARK====//
+      # Remove trailing dots and whitespace
+      s/[\. \t]*$//
+      # Print
+      /./p' |
+    # we now have a list, one entry per line, of the stringified
+    # contents of the appropriate section of all members of the
+    # archive which possess that section. Heuristic: eliminate
+    # all those which have a first or second character that is
+    # a '.' (that is, objdump's representation of an unprintable
+    # character.) This should work for all archives with less than
+    # 0x302f exports -- but will fail for DLLs whose name actually
+    # begins with a literal '.' or a single character followed by
+    # a '.'.
+    #
+    # Of those that remain, print the first one.
+    $SED -e '/^\./d;/^.\./d;q'
+}
+
+# func_cygming_gnu_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is a GNU/binutils-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_gnu_implib_p ()
+{
+  $opt_debug
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'`
+  test -n "$func_cygming_gnu_implib_tmp"
+}
+
+# func_cygming_ms_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is an MS-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_ms_implib_p ()
+{
+  $opt_debug
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'`
+  test -n "$func_cygming_ms_implib_tmp"
+}
+
+# func_cygming_dll_for_implib_fallback ARG
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+#
+# This fallback implementation is for use when $DLLTOOL
+# does not support the --identify-strict option.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib_fallback ()
+{
+  $opt_debug
+  if func_cygming_gnu_implib_p "$1" ; then
+    # binutils import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"`
+  elif func_cygming_ms_implib_p "$1" ; then
+    # ms-generated import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"`
+  else
+    # unknown
+    sharedlib_from_linklib_result=""
+  fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+    $opt_debug
+    f_ex_an_ar_dir="$1"; shift
+    f_ex_an_ar_oldlib="$1"
+    if test "$lock_old_archive_extraction" = yes; then
+      lockfile=$f_ex_an_ar_oldlib.lock
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+	func_echo "Waiting for $lockfile to be removed"
+	sleep 2
+      done
+    fi
+    func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
+		   'stat=$?; rm -f "$lockfile"; exit $stat'
+    if test "$lock_old_archive_extraction" = yes; then
+      $opt_dry_run || rm -f "$lockfile"
+    fi
+    if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+     :
+    else
+      func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
+    fi
+}
+
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+    $opt_debug
+    my_gentop="$1"; shift
+    my_oldlibs=${1+"$@"}
+    my_oldobjs=""
+    my_xlib=""
+    my_xabs=""
+    my_xdir=""
+
+    for my_xlib in $my_oldlibs; do
+      # Extract the objects.
+      case $my_xlib in
+	[\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+	*) my_xabs=`pwd`"/$my_xlib" ;;
+      esac
+      func_basename "$my_xlib"
+      my_xlib="$func_basename_result"
+      my_xlib_u=$my_xlib
+      while :; do
+        case " $extracted_archives " in
+	*" $my_xlib_u "*)
+	  func_arith $extracted_serial + 1
+	  extracted_serial=$func_arith_result
+	  my_xlib_u=lt$extracted_serial-$my_xlib ;;
+	*) break ;;
+	esac
+      done
+      extracted_archives="$extracted_archives $my_xlib_u"
+      my_xdir="$my_gentop/$my_xlib_u"
+
+      func_mkdir_p "$my_xdir"
+
+      case $host in
+      *-darwin*)
+	func_verbose "Extracting $my_xabs"
+	# Do not bother doing anything if just a dry run
+	$opt_dry_run || {
+	  darwin_orig_dir=`pwd`
+	  cd $my_xdir || exit $?
+	  darwin_archive=$my_xabs
+	  darwin_curdir=`pwd`
+	  darwin_base_archive=`basename "$darwin_archive"`
+	  darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
+	  if test -n "$darwin_arches"; then
+	    darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
+	    darwin_arch=
+	    func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
+	    for darwin_arch in  $darwin_arches ; do
+	      func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+	      $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
+	      cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+	      func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+	      cd "$darwin_curdir"
+	      $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+	    done # $darwin_arches
+            ## Okay now we've a bunch of thin objects, gotta fatten them up :)
+	    darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u`
+	    darwin_file=
+	    darwin_files=
+	    for darwin_file in $darwin_filelist; do
+	      darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
+	      $LIPO -create -output "$darwin_file" $darwin_files
+	    done # $darwin_filelist
+	    $RM -rf unfat-$$
+	    cd "$darwin_orig_dir"
+	  else
+	    cd $darwin_orig_dir
+	    func_extract_an_archive "$my_xdir" "$my_xabs"
+	  fi # $darwin_arches
+	} # !$opt_dry_run
+	;;
+      *)
+        func_extract_an_archive "$my_xdir" "$my_xabs"
+	;;
+      esac
+      my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
+    done
+
+    func_extract_archives_result="$my_oldobjs"
+}
+
+
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable.  Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
+#
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take.  If 'yes', then the emitted script
+# will assume that the directory in which it is stored is
+# the $objdir directory.  This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
+{
+	func_emit_wrapper_arg1=${1-no}
+
+	$ECHO "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+  # install mode needs the following variables:
+  generated_by_libtool_version='$macro_version'
+  notinst_deplibs='$notinst_deplibs'
+else
+  # When we are sourced in execute mode, \$file and \$ECHO are already set.
+  if test \"\$libtool_execute_magic\" != \"$magic\"; then
+    file=\"\$0\""
+
+    qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+    $ECHO "\
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+    ECHO=\"$qECHO\"
+  fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ which is used only on
+# windows platforms, and (c) all begin with the string "--lt-"
+# (application programs are unlikely to have options which match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's $0 value, followed by "$@".
+lt_option_debug=
+func_parse_lt_options ()
+{
+  lt_script_arg0=\$0
+  shift
+  for lt_opt
+  do
+    case \"\$lt_opt\" in
+    --lt-debug) lt_option_debug=1 ;;
+    --lt-dump-script)
+        lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\`
+        test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=.
+        lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\`
+        cat \"\$lt_dump_D/\$lt_dump_F\"
+        exit 0
+      ;;
+    --lt-*)
+        \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2
+        exit 1
+      ;;
+    esac
+  done
+
+  # Print the debug banner immediately:
+  if test -n \"\$lt_option_debug\"; then
+    echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2
+  fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+  lt_dump_args_N=1;
+  for lt_arg
+  do
+    \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\"
+    lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
+  done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+"
+  case $host in
+  # Backslashes separate directories on plain windows
+  *-*-mingw | *-*-os2* | *-cegcc*)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+    ;;
+
+  *)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+    ;;
+  esac
+  $ECHO "\
+      \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+      exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from \$@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+  case \" \$* \" in
+  *\\ --lt-*)
+    for lt_wr_arg
+    do
+      case \$lt_wr_arg in
+      --lt-*) ;;
+      *) set x \"\$@\" \"\$lt_wr_arg\"; shift;;
+      esac
+      shift
+    done ;;
+  esac
+  func_exec_program_core \${1+\"\$@\"}
+}
+
+  # Parse options
+  func_parse_lt_options \"\$0\" \${1+\"\$@\"}
+
+  # Find the directory that this script lives in.
+  thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
+  test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+  # Follow symbolic links until we get to the real thisdir.
+  file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
+  while test -n \"\$file\"; do
+    destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
+
+    # If there was a directory component, then change thisdir.
+    if test \"x\$destdir\" != \"x\$file\"; then
+      case \"\$destdir\" in
+      [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+      *) thisdir=\"\$thisdir/\$destdir\" ;;
+      esac
+    fi
+
+    file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
+    file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
+  done
+
+  # Usually 'no', except on cygwin/mingw when embedded into
+  # the cwrapper.
+  WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
+  if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+    # special case for '.'
+    if test \"\$thisdir\" = \".\"; then
+      thisdir=\`pwd\`
+    fi
+    # remove .libs from thisdir
+    case \"\$thisdir\" in
+    *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
+    $objdir )   thisdir=. ;;
+    esac
+  fi
+
+  # Try to get the absolute directory name.
+  absdir=\`cd \"\$thisdir\" && pwd\`
+  test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+	if test "$fast_install" = yes; then
+	  $ECHO "\
+  program=lt-'$outputname'$exeext
+  progdir=\"\$thisdir/$objdir\"
+
+  if test ! -f \"\$progdir/\$program\" ||
+     { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+       test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+    file=\"\$\$-\$program\"
+
+    if test ! -d \"\$progdir\"; then
+      $MKDIR \"\$progdir\"
+    else
+      $RM \"\$progdir/\$file\"
+    fi"
+
+	  $ECHO "\
+
+    # relink executable if necessary
+    if test -n \"\$relink_command\"; then
+      if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+      else
+	$ECHO \"\$relink_command_output\" >&2
+	$RM \"\$progdir/\$file\"
+	exit 1
+      fi
+    fi
+
+    $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+    { $RM \"\$progdir/\$program\";
+      $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+    $RM \"\$progdir/\$file\"
+  fi"
+	else
+	  $ECHO "\
+  program='$outputname'
+  progdir=\"\$thisdir/$objdir\"
+"
+	fi
+
+	$ECHO "\
+
+  if test -f \"\$progdir/\$program\"; then"
+
+	# fixup the dll searchpath if we need to.
+	#
+	# Fix the DLL searchpath if we need to.  Do this before prepending
+	# to shlibpath, because on Windows, both are PATH and uninstalled
+	# libraries must come first.
+	if test -n "$dllsearchpath"; then
+	  $ECHO "\
+    # Add the dll search path components to the executable PATH
+    PATH=$dllsearchpath:\$PATH
+"
+	fi
+
+	# Export our shlibpath_var if we have one.
+	if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+	  $ECHO "\
+    # Add our own library path to $shlibpath_var
+    $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+    # Some systems cannot cope with colon-terminated $shlibpath_var
+    # The second colon is a workaround for a bug in BeOS R4 sed
+    $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
+
+    export $shlibpath_var
+"
+	fi
+
+	$ECHO "\
+    if test \"\$libtool_execute_magic\" != \"$magic\"; then
+      # Run the actual program with our arguments.
+      func_exec_program \${1+\"\$@\"}
+    fi
+  else
+    # The program doesn't exist.
+    \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
+    \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
+    \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+    exit 1
+  fi
+fi\
+"
+}
+
+
+# func_emit_cwrapperexe_src
+# emit the source code for a wrapper executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_cwrapperexe_src ()
+{
+	cat <
+#include 
+#ifdef _MSC_VER
+# include 
+# include 
+# include 
+#else
+# include 
+# include 
+# ifdef __CYGWIN__
+#  include 
+# endif
+#endif
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* declarations of non-ANSI functions */
+#if defined(__MINGW32__)
+# ifdef __STRICT_ANSI__
+int _putenv (const char *);
+# endif
+#elif defined(__CYGWIN__)
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+/* #elif defined (other platforms) ... */
+#endif
+
+/* portability defines, excluding path handling macros */
+#if defined(_MSC_VER)
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+# define S_IXUSR _S_IEXEC
+# ifndef _INTPTR_T_DEFINED
+#  define _INTPTR_T_DEFINED
+#  define intptr_t int
+# endif
+#elif defined(__MINGW32__)
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+#elif defined(__CYGWIN__)
+# define HAVE_SETENV
+# define FOPEN_WB "wb"
+/* #elif defined (other platforms) ... */
+#endif
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+
+/* path handling portability macros */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+  defined (__OS2__)
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# define FOPEN_WB "wb"
+# ifndef DIR_SEPARATOR_2
+#  define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+#  define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+	(((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#ifndef FOPEN_WB
+# define FOPEN_WB "w"
+#endif
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#define XMALLOC(type, num)      ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+  if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+#if defined(LT_DEBUGWRAPPER)
+static int lt_debug = 1;
+#else
+static int lt_debug = 0;
+#endif
+
+const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */
+
+void *xmalloc (size_t num);
+char *xstrdup (const char *string);
+const char *base_name (const char *name);
+char *find_executable (const char *wrapper);
+char *chase_symlinks (const char *pathspec);
+int make_executable (const char *path);
+int check_executable (const char *path);
+char *strendzap (char *str, const char *pat);
+void lt_debugprintf (const char *file, int line, const char *fmt, ...);
+void lt_fatal (const char *file, int line, const char *message, ...);
+static const char *nonnull (const char *s);
+static const char *nonempty (const char *s);
+void lt_setenv (const char *name, const char *value);
+char *lt_extend_str (const char *orig_value, const char *add, int to_end);
+void lt_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+char **prepare_spawn (char **argv);
+void lt_dump_script (FILE *f);
+EOF
+
+	    cat <= 0)
+      && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+    return 1;
+  else
+    return 0;
+}
+
+int
+make_executable (const char *path)
+{
+  int rval = 0;
+  struct stat st;
+
+  lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n",
+                  nonempty (path));
+  if ((!path) || (!*path))
+    return 0;
+
+  if (stat (path, &st) >= 0)
+    {
+      rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
+    }
+  return rval;
+}
+
+/* Searches for the full path of the wrapper.  Returns
+   newly allocated full path name if found, NULL otherwise
+   Does not chase symlinks, even on platforms that support them.
+*/
+char *
+find_executable (const char *wrapper)
+{
+  int has_slash = 0;
+  const char *p;
+  const char *p_next;
+  /* static buffer for getcwd */
+  char tmp[LT_PATHMAX + 1];
+  int tmp_len;
+  char *concat_name;
+
+  lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
+                  nonempty (wrapper));
+
+  if ((wrapper == NULL) || (*wrapper == '\0'))
+    return NULL;
+
+  /* Absolute path? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
+    {
+      concat_name = xstrdup (wrapper);
+      if (check_executable (concat_name))
+	return concat_name;
+      XFREE (concat_name);
+    }
+  else
+    {
+#endif
+      if (IS_DIR_SEPARATOR (wrapper[0]))
+	{
+	  concat_name = xstrdup (wrapper);
+	  if (check_executable (concat_name))
+	    return concat_name;
+	  XFREE (concat_name);
+	}
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+    }
+#endif
+
+  for (p = wrapper; *p; p++)
+    if (*p == '/')
+      {
+	has_slash = 1;
+	break;
+      }
+  if (!has_slash)
+    {
+      /* no slashes; search PATH */
+      const char *path = getenv ("PATH");
+      if (path != NULL)
+	{
+	  for (p = path; *p; p = p_next)
+	    {
+	      const char *q;
+	      size_t p_len;
+	      for (q = p; *q; q++)
+		if (IS_PATH_SEPARATOR (*q))
+		  break;
+	      p_len = q - p;
+	      p_next = (*q == '\0' ? q : q + 1);
+	      if (p_len == 0)
+		{
+		  /* empty path: current directory */
+		  if (getcwd (tmp, LT_PATHMAX) == NULL)
+		    lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+                              nonnull (strerror (errno)));
+		  tmp_len = strlen (tmp);
+		  concat_name =
+		    XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+		  memcpy (concat_name, tmp, tmp_len);
+		  concat_name[tmp_len] = '/';
+		  strcpy (concat_name + tmp_len + 1, wrapper);
+		}
+	      else
+		{
+		  concat_name =
+		    XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
+		  memcpy (concat_name, p, p_len);
+		  concat_name[p_len] = '/';
+		  strcpy (concat_name + p_len + 1, wrapper);
+		}
+	      if (check_executable (concat_name))
+		return concat_name;
+	      XFREE (concat_name);
+	    }
+	}
+      /* not found in PATH; assume curdir */
+    }
+  /* Relative path | not found in path: prepend cwd */
+  if (getcwd (tmp, LT_PATHMAX) == NULL)
+    lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+              nonnull (strerror (errno)));
+  tmp_len = strlen (tmp);
+  concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+  memcpy (concat_name, tmp, tmp_len);
+  concat_name[tmp_len] = '/';
+  strcpy (concat_name + tmp_len + 1, wrapper);
+
+  if (check_executable (concat_name))
+    return concat_name;
+  XFREE (concat_name);
+  return NULL;
+}
+
+char *
+chase_symlinks (const char *pathspec)
+{
+#ifndef S_ISLNK
+  return xstrdup (pathspec);
+#else
+  char buf[LT_PATHMAX];
+  struct stat s;
+  char *tmp_pathspec = xstrdup (pathspec);
+  char *p;
+  int has_symlinks = 0;
+  while (strlen (tmp_pathspec) && !has_symlinks)
+    {
+      lt_debugprintf (__FILE__, __LINE__,
+		      "checking path component for symlinks: %s\n",
+		      tmp_pathspec);
+      if (lstat (tmp_pathspec, &s) == 0)
+	{
+	  if (S_ISLNK (s.st_mode) != 0)
+	    {
+	      has_symlinks = 1;
+	      break;
+	    }
+
+	  /* search backwards for last DIR_SEPARATOR */
+	  p = tmp_pathspec + strlen (tmp_pathspec) - 1;
+	  while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+	    p--;
+	  if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+	    {
+	      /* no more DIR_SEPARATORS left */
+	      break;
+	    }
+	  *p = '\0';
+	}
+      else
+	{
+	  lt_fatal (__FILE__, __LINE__,
+		    "error accessing file \"%s\": %s",
+		    tmp_pathspec, nonnull (strerror (errno)));
+	}
+    }
+  XFREE (tmp_pathspec);
+
+  if (!has_symlinks)
+    {
+      return xstrdup (pathspec);
+    }
+
+  tmp_pathspec = realpath (pathspec, buf);
+  if (tmp_pathspec == 0)
+    {
+      lt_fatal (__FILE__, __LINE__,
+		"could not follow symlinks for %s", pathspec);
+    }
+  return xstrdup (tmp_pathspec);
+#endif
+}
+
+char *
+strendzap (char *str, const char *pat)
+{
+  size_t len, patlen;
+
+  assert (str != NULL);
+  assert (pat != NULL);
+
+  len = strlen (str);
+  patlen = strlen (pat);
+
+  if (patlen <= len)
+    {
+      str += len - patlen;
+      if (strcmp (str, pat) == 0)
+	*str = '\0';
+    }
+  return str;
+}
+
+void
+lt_debugprintf (const char *file, int line, const char *fmt, ...)
+{
+  va_list args;
+  if (lt_debug)
+    {
+      (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line);
+      va_start (args, fmt);
+      (void) vfprintf (stderr, fmt, args);
+      va_end (args);
+    }
+}
+
+static void
+lt_error_core (int exit_status, const char *file,
+	       int line, const char *mode,
+	       const char *message, va_list ap)
+{
+  fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode);
+  vfprintf (stderr, message, ap);
+  fprintf (stderr, ".\n");
+
+  if (exit_status >= 0)
+    exit (exit_status);
+}
+
+void
+lt_fatal (const char *file, int line, const char *message, ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap);
+  va_end (ap);
+}
+
+static const char *
+nonnull (const char *s)
+{
+  return s ? s : "(null)";
+}
+
+static const char *
+nonempty (const char *s)
+{
+  return (s && !*s) ? "(empty)" : nonnull (s);
+}
+
+void
+lt_setenv (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_setenv) setting '%s' to '%s'\n",
+                  nonnull (name), nonnull (value));
+  {
+#ifdef HAVE_SETENV
+    /* always make a copy, for consistency with !HAVE_SETENV */
+    char *str = xstrdup (value);
+    setenv (name, str, 1);
+#else
+    int len = strlen (name) + 1 + strlen (value) + 1;
+    char *str = XMALLOC (char, len);
+    sprintf (str, "%s=%s", name, value);
+    if (putenv (str) != EXIT_SUCCESS)
+      {
+        XFREE (str);
+      }
+#endif
+  }
+}
+
+char *
+lt_extend_str (const char *orig_value, const char *add, int to_end)
+{
+  char *new_value;
+  if (orig_value && *orig_value)
+    {
+      int orig_value_len = strlen (orig_value);
+      int add_len = strlen (add);
+      new_value = XMALLOC (char, add_len + orig_value_len + 1);
+      if (to_end)
+        {
+          strcpy (new_value, orig_value);
+          strcpy (new_value + orig_value_len, add);
+        }
+      else
+        {
+          strcpy (new_value, add);
+          strcpy (new_value + add_len, orig_value);
+        }
+    }
+  else
+    {
+      new_value = xstrdup (add);
+    }
+  return new_value;
+}
+
+void
+lt_update_exe_path (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      /* some systems can't cope with a ':'-terminated path #' */
+      int len = strlen (new_value);
+      while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+        {
+          new_value[len-1] = '\0';
+        }
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+void
+lt_update_lib_path (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+EOF
+	    case $host_os in
+	      mingw*)
+		cat <<"EOF"
+
+/* Prepares an argument vector before calling spawn().
+   Note that spawn() does not by itself call the command interpreter
+     (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
+      ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+         GetVersionEx(&v);
+         v.dwPlatformId == VER_PLATFORM_WIN32_NT;
+      }) ? "cmd.exe" : "command.com").
+   Instead it simply concatenates the arguments, separated by ' ', and calls
+   CreateProcess().  We must quote the arguments since Win32 CreateProcess()
+   interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
+   special way:
+   - Space and tab are interpreted as delimiters. They are not treated as
+     delimiters if they are surrounded by double quotes: "...".
+   - Unescaped double quotes are removed from the input. Their only effect is
+     that within double quotes, space and tab are treated like normal
+     characters.
+   - Backslashes not followed by double quotes are not special.
+   - But 2*n+1 backslashes followed by a double quote become
+     n backslashes followed by a double quote (n >= 0):
+       \" -> "
+       \\\" -> \"
+       \\\\\" -> \\"
+ */
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+char **
+prepare_spawn (char **argv)
+{
+  size_t argc;
+  char **new_argv;
+  size_t i;
+
+  /* Count number of arguments.  */
+  for (argc = 0; argv[argc] != NULL; argc++)
+    ;
+
+  /* Allocate new argument vector.  */
+  new_argv = XMALLOC (char *, argc + 1);
+
+  /* Put quoted arguments into the new argument vector.  */
+  for (i = 0; i < argc; i++)
+    {
+      const char *string = argv[i];
+
+      if (string[0] == '\0')
+	new_argv[i] = xstrdup ("\"\"");
+      else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
+	{
+	  int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+	  size_t length;
+	  unsigned int backslashes;
+	  const char *s;
+	  char *quoted_string;
+	  char *p;
+
+	  length = 0;
+	  backslashes = 0;
+	  if (quote_around)
+	    length++;
+	  for (s = string; *s != '\0'; s++)
+	    {
+	      char c = *s;
+	      if (c == '"')
+		length += backslashes + 1;
+	      length++;
+	      if (c == '\\')
+		backslashes++;
+	      else
+		backslashes = 0;
+	    }
+	  if (quote_around)
+	    length += backslashes + 1;
+
+	  quoted_string = XMALLOC (char, length + 1);
+
+	  p = quoted_string;
+	  backslashes = 0;
+	  if (quote_around)
+	    *p++ = '"';
+	  for (s = string; *s != '\0'; s++)
+	    {
+	      char c = *s;
+	      if (c == '"')
+		{
+		  unsigned int j;
+		  for (j = backslashes + 1; j > 0; j--)
+		    *p++ = '\\';
+		}
+	      *p++ = c;
+	      if (c == '\\')
+		backslashes++;
+	      else
+		backslashes = 0;
+	    }
+	  if (quote_around)
+	    {
+	      unsigned int j;
+	      for (j = backslashes; j > 0; j--)
+		*p++ = '\\';
+	      *p++ = '"';
+	    }
+	  *p = '\0';
+
+	  new_argv[i] = quoted_string;
+	}
+      else
+	new_argv[i] = (char *) string;
+    }
+  new_argv[argc] = NULL;
+
+  return new_argv;
+}
+EOF
+		;;
+	    esac
+
+            cat <<"EOF"
+void lt_dump_script (FILE* f)
+{
+EOF
+	    func_emit_wrapper yes |
+	      $SED -n -e '
+s/^\(.\{79\}\)\(..*\)/\1\
+\2/
+h
+s/\([\\"]\)/\\\1/g
+s/$/\\n/
+s/\([^\n]*\).*/  fputs ("\1", f);/p
+g
+D'
+            cat <<"EOF"
+}
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_win32_import_lib_p ARG
+# True if ARG is an import lib, as indicated by $file_magic_cmd
+func_win32_import_lib_p ()
+{
+    $opt_debug
+    case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
+    *import*) : ;;
+    *) false ;;
+    esac
+}
+
+# func_mode_link arg...
+func_mode_link ()
+{
+    $opt_debug
+    case $host in
+    *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+      # It is impossible to link a dll without this setting, and
+      # we shouldn't force the makefile maintainer to figure out
+      # which system we are compiling for in order to pass an extra
+      # flag for every libtool invocation.
+      # allow_undefined=no
+
+      # FIXME: Unfortunately, there are problems with the above when trying
+      # to make a dll which has undefined symbols, in which case not
+      # even a static library is built.  For now, we need to specify
+      # -no-undefined on the libtool link line when we can be certain
+      # that all symbols are satisfied, otherwise we get a static library.
+      allow_undefined=yes
+      ;;
+    *)
+      allow_undefined=yes
+      ;;
+    esac
+    libtool_args=$nonopt
+    base_compile="$nonopt $@"
+    compile_command=$nonopt
+    finalize_command=$nonopt
+
+    compile_rpath=
+    finalize_rpath=
+    compile_shlibpath=
+    finalize_shlibpath=
+    convenience=
+    old_convenience=
+    deplibs=
+    old_deplibs=
+    compiler_flags=
+    linker_flags=
+    dllsearchpath=
+    lib_search_path=`pwd`
+    inst_prefix_dir=
+    new_inherited_linker_flags=
+
+    avoid_version=no
+    bindir=
+    dlfiles=
+    dlprefiles=
+    dlself=no
+    export_dynamic=no
+    export_symbols=
+    export_symbols_regex=
+    generated=
+    libobjs=
+    ltlibs=
+    module=no
+    no_install=no
+    objs=
+    non_pic_objects=
+    precious_files_regex=
+    prefer_static_libs=no
+    preload=no
+    prev=
+    prevarg=
+    release=
+    rpath=
+    xrpath=
+    perm_rpath=
+    temp_rpath=
+    thread_safe=no
+    vinfo=
+    vinfo_number=no
+    weak_libs=
+    single_module="${wl}-single_module"
+    func_infer_tag $base_compile
+
+    # We need to know -static, to get the right output filenames.
+    for arg
+    do
+      case $arg in
+      -shared)
+	test "$build_libtool_libs" != yes && \
+	  func_fatal_configuration "can not build a shared library"
+	build_old_libs=no
+	break
+	;;
+      -all-static | -static | -static-libtool-libs)
+	case $arg in
+	-all-static)
+	  if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+	    func_warning "complete static linking is impossible in this configuration"
+	  fi
+	  if test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	-static)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=built
+	  ;;
+	-static-libtool-libs)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	esac
+	build_libtool_libs=no
+	build_old_libs=yes
+	break
+	;;
+      esac
+    done
+
+    # See if our shared archives depend on static archives.
+    test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+    # Go through the arguments, transforming them on the way.
+    while test "$#" -gt 0; do
+      arg="$1"
+      shift
+      func_quote_for_eval "$arg"
+      qarg=$func_quote_for_eval_unquoted_result
+      func_append libtool_args " $func_quote_for_eval_result"
+
+      # If the previous option needs an argument, assign it.
+      if test -n "$prev"; then
+	case $prev in
+	output)
+	  func_append compile_command " @OUTPUT@"
+	  func_append finalize_command " @OUTPUT@"
+	  ;;
+	esac
+
+	case $prev in
+	bindir)
+	  bindir="$arg"
+	  prev=
+	  continue
+	  ;;
+	dlfiles|dlprefiles)
+	  if test "$preload" = no; then
+	    # Add the symbol object into the linking commands.
+	    func_append compile_command " @SYMFILE@"
+	    func_append finalize_command " @SYMFILE@"
+	    preload=yes
+	  fi
+	  case $arg in
+	  *.la | *.lo) ;;  # We handle these cases below.
+	  force)
+	    if test "$dlself" = no; then
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  self)
+	    if test "$prev" = dlprefiles; then
+	      dlself=yes
+	    elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+	      dlself=yes
+	    else
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  *)
+	    if test "$prev" = dlfiles; then
+	      func_append dlfiles " $arg"
+	    else
+	      func_append dlprefiles " $arg"
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  esac
+	  ;;
+	expsyms)
+	  export_symbols="$arg"
+	  test -f "$arg" \
+	    || func_fatal_error "symbol file \`$arg' does not exist"
+	  prev=
+	  continue
+	  ;;
+	expsyms_regex)
+	  export_symbols_regex="$arg"
+	  prev=
+	  continue
+	  ;;
+	framework)
+	  case $host in
+	    *-*-darwin*)
+	      case "$deplibs " in
+		*" $qarg.ltframework "*) ;;
+		*) func_append deplibs " $qarg.ltframework" # this is fixed later
+		   ;;
+	      esac
+	      ;;
+	  esac
+	  prev=
+	  continue
+	  ;;
+	inst_prefix)
+	  inst_prefix_dir="$arg"
+	  prev=
+	  continue
+	  ;;
+	objectlist)
+	  if test -f "$arg"; then
+	    save_arg=$arg
+	    moreargs=
+	    for fil in `cat "$save_arg"`
+	    do
+#	      func_append moreargs " $fil"
+	      arg=$fil
+	      # A libtool-controlled object.
+
+	      # Check to see that this really is a libtool object.
+	      if func_lalib_unsafe_p "$arg"; then
+		pic_object=
+		non_pic_object=
+
+		# Read the .lo file
+		func_source "$arg"
+
+		if test -z "$pic_object" ||
+		   test -z "$non_pic_object" ||
+		   test "$pic_object" = none &&
+		   test "$non_pic_object" = none; then
+		  func_fatal_error "cannot find name of object for \`$arg'"
+		fi
+
+		# Extract subdirectory from the argument.
+		func_dirname "$arg" "/" ""
+		xdir="$func_dirname_result"
+
+		if test "$pic_object" != none; then
+		  # Prepend the subdirectory the object is found in.
+		  pic_object="$xdir$pic_object"
+
+		  if test "$prev" = dlfiles; then
+		    if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+		      func_append dlfiles " $pic_object"
+		      prev=
+		      continue
+		    else
+		      # If libtool objects are unsupported, then we need to preload.
+		      prev=dlprefiles
+		    fi
+		  fi
+
+		  # CHECK ME:  I think I busted this.  -Ossama
+		  if test "$prev" = dlprefiles; then
+		    # Preload the old-style object.
+		    func_append dlprefiles " $pic_object"
+		    prev=
+		  fi
+
+		  # A PIC object.
+		  func_append libobjs " $pic_object"
+		  arg="$pic_object"
+		fi
+
+		# Non-PIC object.
+		if test "$non_pic_object" != none; then
+		  # Prepend the subdirectory the object is found in.
+		  non_pic_object="$xdir$non_pic_object"
+
+		  # A standard non-PIC object
+		  func_append non_pic_objects " $non_pic_object"
+		  if test -z "$pic_object" || test "$pic_object" = none ; then
+		    arg="$non_pic_object"
+		  fi
+		else
+		  # If the PIC object exists, use it instead.
+		  # $xdir was prepended to $pic_object above.
+		  non_pic_object="$pic_object"
+		  func_append non_pic_objects " $non_pic_object"
+		fi
+	      else
+		# Only an error if not doing a dry-run.
+		if $opt_dry_run; then
+		  # Extract subdirectory from the argument.
+		  func_dirname "$arg" "/" ""
+		  xdir="$func_dirname_result"
+
+		  func_lo2o "$arg"
+		  pic_object=$xdir$objdir/$func_lo2o_result
+		  non_pic_object=$xdir$func_lo2o_result
+		  func_append libobjs " $pic_object"
+		  func_append non_pic_objects " $non_pic_object"
+	        else
+		  func_fatal_error "\`$arg' is not a valid libtool object"
+		fi
+	      fi
+	    done
+	  else
+	    func_fatal_error "link input file \`$arg' does not exist"
+	  fi
+	  arg=$save_arg
+	  prev=
+	  continue
+	  ;;
+	precious_regex)
+	  precious_files_regex="$arg"
+	  prev=
+	  continue
+	  ;;
+	release)
+	  release="-$arg"
+	  prev=
+	  continue
+	  ;;
+	rpath | xrpath)
+	  # We need an absolute path.
+	  case $arg in
+	  [\\/]* | [A-Za-z]:[\\/]*) ;;
+	  *)
+	    func_fatal_error "only absolute run-paths are allowed"
+	    ;;
+	  esac
+	  if test "$prev" = rpath; then
+	    case "$rpath " in
+	    *" $arg "*) ;;
+	    *) func_append rpath " $arg" ;;
+	    esac
+	  else
+	    case "$xrpath " in
+	    *" $arg "*) ;;
+	    *) func_append xrpath " $arg" ;;
+	    esac
+	  fi
+	  prev=
+	  continue
+	  ;;
+	shrext)
+	  shrext_cmds="$arg"
+	  prev=
+	  continue
+	  ;;
+	weak)
+	  func_append weak_libs " $arg"
+	  prev=
+	  continue
+	  ;;
+	xcclinker)
+	  func_append linker_flags " $qarg"
+	  func_append compiler_flags " $qarg"
+	  prev=
+	  func_append compile_command " $qarg"
+	  func_append finalize_command " $qarg"
+	  continue
+	  ;;
+	xcompiler)
+	  func_append compiler_flags " $qarg"
+	  prev=
+	  func_append compile_command " $qarg"
+	  func_append finalize_command " $qarg"
+	  continue
+	  ;;
+	xlinker)
+	  func_append linker_flags " $qarg"
+	  func_append compiler_flags " $wl$qarg"
+	  prev=
+	  func_append compile_command " $wl$qarg"
+	  func_append finalize_command " $wl$qarg"
+	  continue
+	  ;;
+	*)
+	  eval "$prev=\"\$arg\""
+	  prev=
+	  continue
+	  ;;
+	esac
+      fi # test -n "$prev"
+
+      prevarg="$arg"
+
+      case $arg in
+      -all-static)
+	if test -n "$link_static_flag"; then
+	  # See comment for -static flag below, for more details.
+	  func_append compile_command " $link_static_flag"
+	  func_append finalize_command " $link_static_flag"
+	fi
+	continue
+	;;
+
+      -allow-undefined)
+	# FIXME: remove this flag sometime in the future.
+	func_fatal_error "\`-allow-undefined' must not be used because it is the default"
+	;;
+
+      -avoid-version)
+	avoid_version=yes
+	continue
+	;;
+
+      -bindir)
+	prev=bindir
+	continue
+	;;
+
+      -dlopen)
+	prev=dlfiles
+	continue
+	;;
+
+      -dlpreopen)
+	prev=dlprefiles
+	continue
+	;;
+
+      -export-dynamic)
+	export_dynamic=yes
+	continue
+	;;
+
+      -export-symbols | -export-symbols-regex)
+	if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+	  func_fatal_error "more than one -exported-symbols argument is not allowed"
+	fi
+	if test "X$arg" = "X-export-symbols"; then
+	  prev=expsyms
+	else
+	  prev=expsyms_regex
+	fi
+	continue
+	;;
+
+      -framework)
+	prev=framework
+	continue
+	;;
+
+      -inst-prefix-dir)
+	prev=inst_prefix
+	continue
+	;;
+
+      # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+      # so, if we see these flags be careful not to treat them like -L
+      -L[A-Z][A-Z]*:*)
+	case $with_gcc/$host in
+	no/*-*-irix* | /*-*-irix*)
+	  func_append compile_command " $arg"
+	  func_append finalize_command " $arg"
+	  ;;
+	esac
+	continue
+	;;
+
+      -L*)
+	func_stripname "-L" '' "$arg"
+	if test -z "$func_stripname_result"; then
+	  if test "$#" -gt 0; then
+	    func_fatal_error "require no space between \`-L' and \`$1'"
+	  else
+	    func_fatal_error "need path for \`-L' option"
+	  fi
+	fi
+	func_resolve_sysroot "$func_stripname_result"
+	dir=$func_resolve_sysroot_result
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	*)
+	  absdir=`cd "$dir" && pwd`
+	  test -z "$absdir" && \
+	    func_fatal_error "cannot determine absolute directory name of \`$dir'"
+	  dir="$absdir"
+	  ;;
+	esac
+	case "$deplibs " in
+	*" -L$dir "* | *" $arg "*)
+	  # Will only happen for absolute or sysroot arguments
+	  ;;
+	*)
+	  # Preserve sysroot, but never include relative directories
+	  case $dir in
+	    [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;;
+	    *) func_append deplibs " -L$dir" ;;
+	  esac
+	  func_append lib_search_path " $dir"
+	  ;;
+	esac
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	  testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$dir:"*) ;;
+	  ::) dllsearchpath=$dir;;
+	  *) func_append dllsearchpath ":$dir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  ::) dllsearchpath=$testbindir;;
+	  *) func_append dllsearchpath ":$testbindir";;
+	  esac
+	  ;;
+	esac
+	continue
+	;;
+
+      -l*)
+	if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
+	    # These systems don't actually have a C or math library (as such)
+	    continue
+	    ;;
+	  *-*-os2*)
+	    # These systems don't actually have a C library (as such)
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	    # Do not include libc due to us having libc/libc_r.
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C and math libraries are in the System framework
+	    func_append deplibs " System.ltframework"
+	    continue
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  esac
+	elif test "X$arg" = "X-lc_r"; then
+	 case $host in
+	 *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	   # Do not include libc_r directly, use -pthread flag.
+	   continue
+	   ;;
+	 esac
+	fi
+	func_append deplibs " $arg"
+	continue
+	;;
+
+      -module)
+	module=yes
+	continue
+	;;
+
+      # Tru64 UNIX uses -model [arg] to determine the layout of C++
+      # classes, name mangling, and exception handling.
+      # Darwin uses the -arch flag to determine output architecture.
+      -model|-arch|-isysroot|--sysroot)
+	func_append compiler_flags " $arg"
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+	prev=xcompiler
+	continue
+	;;
+
+      -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+      |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+	func_append compiler_flags " $arg"
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+	case "$new_inherited_linker_flags " in
+	    *" $arg "*) ;;
+	    * ) func_append new_inherited_linker_flags " $arg" ;;
+	esac
+	continue
+	;;
+
+      -multi_module)
+	single_module="${wl}-multi_module"
+	continue
+	;;
+
+      -no-fast-install)
+	fast_install=no
+	continue
+	;;
+
+      -no-install)
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+	  # The PATH hackery in wrapper scripts is required on Windows
+	  # and Darwin in order for the loader to find any dlls it needs.
+	  func_warning "\`-no-install' is ignored for $host"
+	  func_warning "assuming \`-no-fast-install' instead"
+	  fast_install=no
+	  ;;
+	*) no_install=yes ;;
+	esac
+	continue
+	;;
+
+      -no-undefined)
+	allow_undefined=no
+	continue
+	;;
+
+      -objectlist)
+	prev=objectlist
+	continue
+	;;
+
+      -o) prev=output ;;
+
+      -precious-files-regex)
+	prev=precious_regex
+	continue
+	;;
+
+      -release)
+	prev=release
+	continue
+	;;
+
+      -rpath)
+	prev=rpath
+	continue
+	;;
+
+      -R)
+	prev=xrpath
+	continue
+	;;
+
+      -R*)
+	func_stripname '-R' '' "$arg"
+	dir=$func_stripname_result
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	=*)
+	  func_stripname '=' '' "$dir"
+	  dir=$lt_sysroot$func_stripname_result
+	  ;;
+	*)
+	  func_fatal_error "only absolute run-paths are allowed"
+	  ;;
+	esac
+	case "$xrpath " in
+	*" $dir "*) ;;
+	*) func_append xrpath " $dir" ;;
+	esac
+	continue
+	;;
+
+      -shared)
+	# The effects of -shared are defined in a previous loop.
+	continue
+	;;
+
+      -shrext)
+	prev=shrext
+	continue
+	;;
+
+      -static | -static-libtool-libs)
+	# The effects of -static are defined in a previous loop.
+	# We used to do the same as -all-static on platforms that
+	# didn't have a PIC flag, but the assumption that the effects
+	# would be equivalent was wrong.  It would break on at least
+	# Digital Unix and AIX.
+	continue
+	;;
+
+      -thread-safe)
+	thread_safe=yes
+	continue
+	;;
+
+      -version-info)
+	prev=vinfo
+	continue
+	;;
+
+      -version-number)
+	prev=vinfo
+	vinfo_number=yes
+	continue
+	;;
+
+      -weak)
+        prev=weak
+	continue
+	;;
+
+      -Wc,*)
+	func_stripname '-Wc,' '' "$arg"
+	args=$func_stripname_result
+	arg=
+	save_ifs="$IFS"; IFS=','
+	for flag in $args; do
+	  IFS="$save_ifs"
+          func_quote_for_eval "$flag"
+	  func_append arg " $func_quote_for_eval_result"
+	  func_append compiler_flags " $func_quote_for_eval_result"
+	done
+	IFS="$save_ifs"
+	func_stripname ' ' '' "$arg"
+	arg=$func_stripname_result
+	;;
+
+      -Wl,*)
+	func_stripname '-Wl,' '' "$arg"
+	args=$func_stripname_result
+	arg=
+	save_ifs="$IFS"; IFS=','
+	for flag in $args; do
+	  IFS="$save_ifs"
+          func_quote_for_eval "$flag"
+	  func_append arg " $wl$func_quote_for_eval_result"
+	  func_append compiler_flags " $wl$func_quote_for_eval_result"
+	  func_append linker_flags " $func_quote_for_eval_result"
+	done
+	IFS="$save_ifs"
+	func_stripname ' ' '' "$arg"
+	arg=$func_stripname_result
+	;;
+
+      -Xcompiler)
+	prev=xcompiler
+	continue
+	;;
+
+      -Xlinker)
+	prev=xlinker
+	continue
+	;;
+
+      -XCClinker)
+	prev=xcclinker
+	continue
+	;;
+
+      # -msg_* for osf cc
+      -msg_*)
+	func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+
+      # Flags to be passed through unchanged, with rationale:
+      # -64, -mips[0-9]      enable 64-bit mode for the SGI compiler
+      # -r[0-9][0-9]*        specify processor for the SGI compiler
+      # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler
+      # +DA*, +DD*           enable 64-bit mode for the HP compiler
+      # -q*                  compiler args for the IBM compiler
+      # -m*, -t[45]*, -txscale* architecture-specific flags for GCC
+      # -F/path              path to uninstalled frameworks, gcc on darwin
+      # -p, -pg, --coverage, -fprofile-*  profiling flags for GCC
+      # @file                GCC response files
+      # -tp=*                Portland pgcc target processor selection
+      # --sysroot=*          for sysroot support
+      # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+      -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+      -O*|-flto*|-fwhopr*|-fuse-linker-plugin)
+        func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+        func_append compile_command " $arg"
+        func_append finalize_command " $arg"
+        func_append compiler_flags " $arg"
+        continue
+        ;;
+
+      # Some other compiler flag.
+      -* | +*)
+        func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+
+      *.$objext)
+	# A standard object.
+	func_append objs " $arg"
+	;;
+
+      *.lo)
+	# A libtool-controlled object.
+
+	# Check to see that this really is a libtool object.
+	if func_lalib_unsafe_p "$arg"; then
+	  pic_object=
+	  non_pic_object=
+
+	  # Read the .lo file
+	  func_source "$arg"
+
+	  if test -z "$pic_object" ||
+	     test -z "$non_pic_object" ||
+	     test "$pic_object" = none &&
+	     test "$non_pic_object" = none; then
+	    func_fatal_error "cannot find name of object for \`$arg'"
+	  fi
+
+	  # Extract subdirectory from the argument.
+	  func_dirname "$arg" "/" ""
+	  xdir="$func_dirname_result"
+
+	  if test "$pic_object" != none; then
+	    # Prepend the subdirectory the object is found in.
+	    pic_object="$xdir$pic_object"
+
+	    if test "$prev" = dlfiles; then
+	      if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+		func_append dlfiles " $pic_object"
+		prev=
+		continue
+	      else
+		# If libtool objects are unsupported, then we need to preload.
+		prev=dlprefiles
+	      fi
+	    fi
+
+	    # CHECK ME:  I think I busted this.  -Ossama
+	    if test "$prev" = dlprefiles; then
+	      # Preload the old-style object.
+	      func_append dlprefiles " $pic_object"
+	      prev=
+	    fi
+
+	    # A PIC object.
+	    func_append libobjs " $pic_object"
+	    arg="$pic_object"
+	  fi
+
+	  # Non-PIC object.
+	  if test "$non_pic_object" != none; then
+	    # Prepend the subdirectory the object is found in.
+	    non_pic_object="$xdir$non_pic_object"
+
+	    # A standard non-PIC object
+	    func_append non_pic_objects " $non_pic_object"
+	    if test -z "$pic_object" || test "$pic_object" = none ; then
+	      arg="$non_pic_object"
+	    fi
+	  else
+	    # If the PIC object exists, use it instead.
+	    # $xdir was prepended to $pic_object above.
+	    non_pic_object="$pic_object"
+	    func_append non_pic_objects " $non_pic_object"
+	  fi
+	else
+	  # Only an error if not doing a dry-run.
+	  if $opt_dry_run; then
+	    # Extract subdirectory from the argument.
+	    func_dirname "$arg" "/" ""
+	    xdir="$func_dirname_result"
+
+	    func_lo2o "$arg"
+	    pic_object=$xdir$objdir/$func_lo2o_result
+	    non_pic_object=$xdir$func_lo2o_result
+	    func_append libobjs " $pic_object"
+	    func_append non_pic_objects " $non_pic_object"
+	  else
+	    func_fatal_error "\`$arg' is not a valid libtool object"
+	  fi
+	fi
+	;;
+
+      *.$libext)
+	# An archive.
+	func_append deplibs " $arg"
+	func_append old_deplibs " $arg"
+	continue
+	;;
+
+      *.la)
+	# A libtool-controlled library.
+
+	func_resolve_sysroot "$arg"
+	if test "$prev" = dlfiles; then
+	  # This library was specified with -dlopen.
+	  func_append dlfiles " $func_resolve_sysroot_result"
+	  prev=
+	elif test "$prev" = dlprefiles; then
+	  # The library was specified with -dlpreopen.
+	  func_append dlprefiles " $func_resolve_sysroot_result"
+	  prev=
+	else
+	  func_append deplibs " $func_resolve_sysroot_result"
+	fi
+	continue
+	;;
+
+      # Some other compiler argument.
+      *)
+	# Unknown arguments in both finalize_command and compile_command need
+	# to be aesthetically quoted because they are evaled later.
+	func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+      esac # arg
+
+      # Now actually substitute the argument into the commands.
+      if test -n "$arg"; then
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+      fi
+    done # argument parsing loop
+
+    test -n "$prev" && \
+      func_fatal_help "the \`$prevarg' option requires an argument"
+
+    if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+      eval arg=\"$export_dynamic_flag_spec\"
+      func_append compile_command " $arg"
+      func_append finalize_command " $arg"
+    fi
+
+    oldlibs=
+    # calculate the name of the file, without its directory
+    func_basename "$output"
+    outputname="$func_basename_result"
+    libobjs_save="$libobjs"
+
+    if test -n "$shlibpath_var"; then
+      # get the directories listed in $shlibpath_var
+      eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\`
+    else
+      shlib_search_path=
+    fi
+    eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+    eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+    func_dirname "$output" "/" ""
+    output_objdir="$func_dirname_result$objdir"
+    func_to_tool_file "$output_objdir/"
+    tool_output_objdir=$func_to_tool_file_result
+    # Create the object directory.
+    func_mkdir_p "$output_objdir"
+
+    # Determine the type of output
+    case $output in
+    "")
+      func_fatal_help "you must specify an output file"
+      ;;
+    *.$libext) linkmode=oldlib ;;
+    *.lo | *.$objext) linkmode=obj ;;
+    *.la) linkmode=lib ;;
+    *) linkmode=prog ;; # Anything else should be a program.
+    esac
+
+    specialdeplibs=
+
+    libs=
+    # Find all interdependent deplibs by searching for libraries
+    # that are linked more than once (e.g. -la -lb -la)
+    for deplib in $deplibs; do
+      if $opt_preserve_dup_deps ; then
+	case "$libs " in
+	*" $deplib "*) func_append specialdeplibs " $deplib" ;;
+	esac
+      fi
+      func_append libs " $deplib"
+    done
+
+    if test "$linkmode" = lib; then
+      libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+      # Compute libraries that are listed more than once in $predeps
+      # $postdeps and mark them as special (i.e., whose duplicates are
+      # not to be eliminated).
+      pre_post_deps=
+      if $opt_duplicate_compiler_generated_deps; then
+	for pre_post_dep in $predeps $postdeps; do
+	  case "$pre_post_deps " in
+	  *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;;
+	  esac
+	  func_append pre_post_deps " $pre_post_dep"
+	done
+      fi
+      pre_post_deps=
+    fi
+
+    deplibs=
+    newdependency_libs=
+    newlib_search_path=
+    need_relink=no # whether we're linking any uninstalled libtool libraries
+    notinst_deplibs= # not-installed libtool libraries
+    notinst_path= # paths that contain not-installed libtool libraries
+
+    case $linkmode in
+    lib)
+	passes="conv dlpreopen link"
+	for file in $dlfiles $dlprefiles; do
+	  case $file in
+	  *.la) ;;
+	  *)
+	    func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file"
+	    ;;
+	  esac
+	done
+	;;
+    prog)
+	compile_deplibs=
+	finalize_deplibs=
+	alldeplibs=no
+	newdlfiles=
+	newdlprefiles=
+	passes="conv scan dlopen dlpreopen link"
+	;;
+    *)  passes="conv"
+	;;
+    esac
+
+    for pass in $passes; do
+      # The preopen pass in lib mode reverses $deplibs; put it back here
+      # so that -L comes before libs that need it for instance...
+      if test "$linkmode,$pass" = "lib,link"; then
+	## FIXME: Find the place where the list is rebuilt in the wrong
+	##        order, and fix it there properly
+        tmp_deplibs=
+	for deplib in $deplibs; do
+	  tmp_deplibs="$deplib $tmp_deplibs"
+	done
+	deplibs="$tmp_deplibs"
+      fi
+
+      if test "$linkmode,$pass" = "lib,link" ||
+	 test "$linkmode,$pass" = "prog,scan"; then
+	libs="$deplibs"
+	deplibs=
+      fi
+      if test "$linkmode" = prog; then
+	case $pass in
+	dlopen) libs="$dlfiles" ;;
+	dlpreopen) libs="$dlprefiles" ;;
+	link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+	esac
+      fi
+      if test "$linkmode,$pass" = "lib,dlpreopen"; then
+	# Collect and forward deplibs of preopened libtool libs
+	for lib in $dlprefiles; do
+	  # Ignore non-libtool-libs
+	  dependency_libs=
+	  func_resolve_sysroot "$lib"
+	  case $lib in
+	  *.la)	func_source "$func_resolve_sysroot_result" ;;
+	  esac
+
+	  # Collect preopened libtool deplibs, except any this library
+	  # has declared as weak libs
+	  for deplib in $dependency_libs; do
+	    func_basename "$deplib"
+            deplib_base=$func_basename_result
+	    case " $weak_libs " in
+	    *" $deplib_base "*) ;;
+	    *) func_append deplibs " $deplib" ;;
+	    esac
+	  done
+	done
+	libs="$dlprefiles"
+      fi
+      if test "$pass" = dlopen; then
+	# Collect dlpreopened libraries
+	save_deplibs="$deplibs"
+	deplibs=
+      fi
+
+      for deplib in $libs; do
+	lib=
+	found=no
+	case $deplib in
+	-mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+        |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+	  if test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    func_append compiler_flags " $deplib"
+	    if test "$linkmode" = lib ; then
+		case "$new_inherited_linker_flags " in
+		    *" $deplib "*) ;;
+		    * ) func_append new_inherited_linker_flags " $deplib" ;;
+		esac
+	    fi
+	  fi
+	  continue
+	  ;;
+	-l*)
+	  if test "$linkmode" != lib && test "$linkmode" != prog; then
+	    func_warning "\`-l' is ignored for archives/objects"
+	    continue
+	  fi
+	  func_stripname '-l' '' "$deplib"
+	  name=$func_stripname_result
+	  if test "$linkmode" = lib; then
+	    searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+	  else
+	    searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+	  fi
+	  for searchdir in $searchdirs; do
+	    for search_ext in .la $std_shrext .so .a; do
+	      # Search the libtool library
+	      lib="$searchdir/lib${name}${search_ext}"
+	      if test -f "$lib"; then
+		if test "$search_ext" = ".la"; then
+		  found=yes
+		else
+		  found=no
+		fi
+		break 2
+	      fi
+	    done
+	  done
+	  if test "$found" != yes; then
+	    # deplib doesn't seem to be a libtool library
+	    if test "$linkmode,$pass" = "prog,link"; then
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      deplibs="$deplib $deplibs"
+	      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    continue
+	  else # deplib is a libtool library
+	    # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+	    # We need to do some special things here, and not later.
+	    if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	      case " $predeps $postdeps " in
+	      *" $deplib "*)
+		if func_lalib_p "$lib"; then
+		  library_names=
+		  old_library=
+		  func_source "$lib"
+		  for l in $old_library $library_names; do
+		    ll="$l"
+		  done
+		  if test "X$ll" = "X$old_library" ; then # only static version available
+		    found=no
+		    func_dirname "$lib" "" "."
+		    ladir="$func_dirname_result"
+		    lib=$ladir/$old_library
+		    if test "$linkmode,$pass" = "prog,link"; then
+		      compile_deplibs="$deplib $compile_deplibs"
+		      finalize_deplibs="$deplib $finalize_deplibs"
+		    else
+		      deplibs="$deplib $deplibs"
+		      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+		    fi
+		    continue
+		  fi
+		fi
+		;;
+	      *) ;;
+	      esac
+	    fi
+	  fi
+	  ;; # -l
+	*.ltframework)
+	  if test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    deplibs="$deplib $deplibs"
+	    if test "$linkmode" = lib ; then
+		case "$new_inherited_linker_flags " in
+		    *" $deplib "*) ;;
+		    * ) func_append new_inherited_linker_flags " $deplib" ;;
+		esac
+	    fi
+	  fi
+	  continue
+	  ;;
+	-L*)
+	  case $linkmode in
+	  lib)
+	    deplibs="$deplib $deplibs"
+	    test "$pass" = conv && continue
+	    newdependency_libs="$deplib $newdependency_libs"
+	    func_stripname '-L' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    func_append newlib_search_path " $func_resolve_sysroot_result"
+	    ;;
+	  prog)
+	    if test "$pass" = conv; then
+	      deplibs="$deplib $deplibs"
+	      continue
+	    fi
+	    if test "$pass" = scan; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    func_stripname '-L' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    func_append newlib_search_path " $func_resolve_sysroot_result"
+	    ;;
+	  *)
+	    func_warning "\`-L' is ignored for archives/objects"
+	    ;;
+	  esac # linkmode
+	  continue
+	  ;; # -L
+	-R*)
+	  if test "$pass" = link; then
+	    func_stripname '-R' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    dir=$func_resolve_sysroot_result
+	    # Make sure the xrpath contains only unique directories.
+	    case "$xrpath " in
+	    *" $dir "*) ;;
+	    *) func_append xrpath " $dir" ;;
+	    esac
+	  fi
+	  deplibs="$deplib $deplibs"
+	  continue
+	  ;;
+	*.la)
+	  func_resolve_sysroot "$deplib"
+	  lib=$func_resolve_sysroot_result
+	  ;;
+	*.$libext)
+	  if test "$pass" = conv; then
+	    deplibs="$deplib $deplibs"
+	    continue
+	  fi
+	  case $linkmode in
+	  lib)
+	    # Linking convenience modules into shared libraries is allowed,
+	    # but linking other static libraries is non-portable.
+	    case " $dlpreconveniencelibs " in
+	    *" $deplib "*) ;;
+	    *)
+	      valid_a_lib=no
+	      case $deplibs_check_method in
+		match_pattern*)
+		  set dummy $deplibs_check_method; shift
+		  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+		  if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
+		    | $EGREP "$match_pattern_regex" > /dev/null; then
+		    valid_a_lib=yes
+		  fi
+		;;
+		pass_all)
+		  valid_a_lib=yes
+		;;
+	      esac
+	      if test "$valid_a_lib" != yes; then
+		echo
+		$ECHO "*** Warning: Trying to link with static lib archive $deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because the file extensions .$libext of this argument makes me believe"
+		echo "*** that it is just a static archive that I should not use here."
+	      else
+		echo
+		$ECHO "*** Warning: Linking the shared library $output against the"
+		$ECHO "*** static library $deplib is not portable!"
+		deplibs="$deplib $deplibs"
+	      fi
+	      ;;
+	    esac
+	    continue
+	    ;;
+	  prog)
+	    if test "$pass" != link; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    continue
+	    ;;
+	  esac # linkmode
+	  ;; # *.$libext
+	*.lo | *.$objext)
+	  if test "$pass" = conv; then
+	    deplibs="$deplib $deplibs"
+	  elif test "$linkmode" = prog; then
+	    if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+	      # If there is no dlopen support or we're linking statically,
+	      # we need to preload.
+	      func_append newdlprefiles " $deplib"
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      func_append newdlfiles " $deplib"
+	    fi
+	  fi
+	  continue
+	  ;;
+	%DEPLIBS%)
+	  alldeplibs=yes
+	  continue
+	  ;;
+	esac # case $deplib
+
+	if test "$found" = yes || test -f "$lib"; then :
+	else
+	  func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'"
+	fi
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$lib" \
+	  || func_fatal_error "\`$lib' is not a valid libtool archive"
+
+	func_dirname "$lib" "" "."
+	ladir="$func_dirname_result"
+
+	dlname=
+	dlopen=
+	dlpreopen=
+	libdir=
+	library_names=
+	old_library=
+	inherited_linker_flags=
+	# If the library was installed with an old release of libtool,
+	# it will not redefine variables installed, or shouldnotlink
+	installed=yes
+	shouldnotlink=no
+	avoidtemprpath=
+
+
+	# Read the .la file
+	func_source "$lib"
+
+	# Convert "-framework foo" to "foo.ltframework"
+	if test -n "$inherited_linker_flags"; then
+	  tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
+	  for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
+	    case " $new_inherited_linker_flags " in
+	      *" $tmp_inherited_linker_flag "*) ;;
+	      *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";;
+	    esac
+	  done
+	fi
+	dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	if test "$linkmode,$pass" = "lib,link" ||
+	   test "$linkmode,$pass" = "prog,scan" ||
+	   { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+	  test -n "$dlopen" && func_append dlfiles " $dlopen"
+	  test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen"
+	fi
+
+	if test "$pass" = conv; then
+	  # Only check for convenience libraries
+	  deplibs="$lib $deplibs"
+	  if test -z "$libdir"; then
+	    if test -z "$old_library"; then
+	      func_fatal_error "cannot find name of link library for \`$lib'"
+	    fi
+	    # It is a libtool convenience library, so add in its objects.
+	    func_append convenience " $ladir/$objdir/$old_library"
+	    func_append old_convenience " $ladir/$objdir/$old_library"
+	  elif test "$linkmode" != prog && test "$linkmode" != lib; then
+	    func_fatal_error "\`$lib' is not a convenience library"
+	  fi
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    deplibs="$deplib $deplibs"
+	    if $opt_preserve_dup_deps ; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+	      esac
+	    fi
+	    func_append tmp_libs " $deplib"
+	  done
+	  continue
+	fi # $pass = conv
+
+
+	# Get the name of the library we link against.
+	linklib=
+	if test -n "$old_library" &&
+	   { test "$prefer_static_libs" = yes ||
+	     test "$prefer_static_libs,$installed" = "built,no"; }; then
+	  linklib=$old_library
+	else
+	  for l in $old_library $library_names; do
+	    linklib="$l"
+	  done
+	fi
+	if test -z "$linklib"; then
+	  func_fatal_error "cannot find name of link library for \`$lib'"
+	fi
+
+	# This library was specified with -dlopen.
+	if test "$pass" = dlopen; then
+	  if test -z "$libdir"; then
+	    func_fatal_error "cannot -dlopen a convenience library: \`$lib'"
+	  fi
+	  if test -z "$dlname" ||
+	     test "$dlopen_support" != yes ||
+	     test "$build_libtool_libs" = no; then
+	    # If there is no dlname, no dlopen support or we're linking
+	    # statically, we need to preload.  We also need to preload any
+	    # dependent libraries so libltdl's deplib preloader doesn't
+	    # bomb out in the load deplibs phase.
+	    func_append dlprefiles " $lib $dependency_libs"
+	  else
+	    func_append newdlfiles " $lib"
+	  fi
+	  continue
+	fi # $pass = dlopen
+
+	# We need an absolute path.
+	case $ladir in
+	[\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+	*)
+	  abs_ladir=`cd "$ladir" && pwd`
+	  if test -z "$abs_ladir"; then
+	    func_warning "cannot determine absolute directory name of \`$ladir'"
+	    func_warning "passing it literally to the linker, although it might fail"
+	    abs_ladir="$ladir"
+	  fi
+	  ;;
+	esac
+	func_basename "$lib"
+	laname="$func_basename_result"
+
+	# Find the relevant object directory and library name.
+	if test "X$installed" = Xyes; then
+	  if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    func_warning "library \`$lib' was moved."
+	    dir="$ladir"
+	    absdir="$abs_ladir"
+	    libdir="$abs_ladir"
+	  else
+	    dir="$lt_sysroot$libdir"
+	    absdir="$lt_sysroot$libdir"
+	  fi
+	  test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+	else
+	  if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    dir="$ladir"
+	    absdir="$abs_ladir"
+	    # Remove this search path later
+	    func_append notinst_path " $abs_ladir"
+	  else
+	    dir="$ladir/$objdir"
+	    absdir="$abs_ladir/$objdir"
+	    # Remove this search path later
+	    func_append notinst_path " $abs_ladir"
+	  fi
+	fi # $installed = yes
+	func_stripname 'lib' '.la' "$laname"
+	name=$func_stripname_result
+
+	# This library was specified with -dlpreopen.
+	if test "$pass" = dlpreopen; then
+	  if test -z "$libdir" && test "$linkmode" = prog; then
+	    func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'"
+	  fi
+	  case "$host" in
+	    # special handling for platforms with PE-DLLs.
+	    *cygwin* | *mingw* | *cegcc* )
+	      # Linker will automatically link against shared library if both
+	      # static and shared are present.  Therefore, ensure we extract
+	      # symbols from the import library if a shared library is present
+	      # (otherwise, the dlopen module name will be incorrect).  We do
+	      # this by putting the import library name into $newdlprefiles.
+	      # We recover the dlopen module name by 'saving' the la file
+	      # name in a special purpose variable, and (later) extracting the
+	      # dlname from the la file.
+	      if test -n "$dlname"; then
+	        func_tr_sh "$dir/$linklib"
+	        eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname"
+	        func_append newdlprefiles " $dir/$linklib"
+	      else
+	        func_append newdlprefiles " $dir/$old_library"
+	        # Keep a list of preopened convenience libraries to check
+	        # that they are being used correctly in the link pass.
+	        test -z "$libdir" && \
+	          func_append dlpreconveniencelibs " $dir/$old_library"
+	      fi
+	    ;;
+	    * )
+	      # Prefer using a static library (so that no silly _DYNAMIC symbols
+	      # are required to link).
+	      if test -n "$old_library"; then
+	        func_append newdlprefiles " $dir/$old_library"
+	        # Keep a list of preopened convenience libraries to check
+	        # that they are being used correctly in the link pass.
+	        test -z "$libdir" && \
+	          func_append dlpreconveniencelibs " $dir/$old_library"
+	      # Otherwise, use the dlname, so that lt_dlopen finds it.
+	      elif test -n "$dlname"; then
+	        func_append newdlprefiles " $dir/$dlname"
+	      else
+	        func_append newdlprefiles " $dir/$linklib"
+	      fi
+	    ;;
+	  esac
+	fi # $pass = dlpreopen
+
+	if test -z "$libdir"; then
+	  # Link the convenience library
+	  if test "$linkmode" = lib; then
+	    deplibs="$dir/$old_library $deplibs"
+	  elif test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$dir/$old_library $compile_deplibs"
+	    finalize_deplibs="$dir/$old_library $finalize_deplibs"
+	  else
+	    deplibs="$lib $deplibs" # used for prog,scan pass
+	  fi
+	  continue
+	fi
+
+
+	if test "$linkmode" = prog && test "$pass" != link; then
+	  func_append newlib_search_path " $ladir"
+	  deplibs="$lib $deplibs"
+
+	  linkalldeplibs=no
+	  if test "$link_all_deplibs" != no || test -z "$library_names" ||
+	     test "$build_libtool_libs" = no; then
+	    linkalldeplibs=yes
+	  fi
+
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    case $deplib in
+	    -L*) func_stripname '-L' '' "$deplib"
+	         func_resolve_sysroot "$func_stripname_result"
+	         func_append newlib_search_path " $func_resolve_sysroot_result"
+		 ;;
+	    esac
+	    # Need to link against all dependency_libs?
+	    if test "$linkalldeplibs" = yes; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      # Need to hardcode shared library paths
+	      # or/and link against static libraries
+	      newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    if $opt_preserve_dup_deps ; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+	      esac
+	    fi
+	    func_append tmp_libs " $deplib"
+	  done # for deplib
+	  continue
+	fi # $linkmode = prog...
+
+	if test "$linkmode,$pass" = "prog,link"; then
+	  if test -n "$library_names" &&
+	     { { test "$prefer_static_libs" = no ||
+	         test "$prefer_static_libs,$installed" = "built,yes"; } ||
+	       test -z "$old_library"; }; then
+	    # We need to hardcode the library path
+	    if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
+	      # Make sure the rpath contains only unique directories.
+	      case "$temp_rpath:" in
+	      *"$absdir:"*) ;;
+	      *) func_append temp_rpath "$absdir:" ;;
+	      esac
+	    fi
+
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) func_append compile_rpath " $absdir" ;;
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append finalize_rpath " $libdir" ;;
+	      esac
+	      ;;
+	    esac
+	  fi # $linkmode,$pass = prog,link...
+
+	  if test "$alldeplibs" = yes &&
+	     { test "$deplibs_check_method" = pass_all ||
+	       { test "$build_libtool_libs" = yes &&
+		 test -n "$library_names"; }; }; then
+	    # We only need to search for static libraries
+	    continue
+	  fi
+	fi
+
+	link_static=no # Whether the deplib will be linked statically
+	use_static_libs=$prefer_static_libs
+	if test "$use_static_libs" = built && test "$installed" = yes; then
+	  use_static_libs=no
+	fi
+	if test -n "$library_names" &&
+	   { test "$use_static_libs" = no || test -z "$old_library"; }; then
+	  case $host in
+	  *cygwin* | *mingw* | *cegcc*)
+	      # No point in relinking DLLs because paths are not encoded
+	      func_append notinst_deplibs " $lib"
+	      need_relink=no
+	    ;;
+	  *)
+	    if test "$installed" = no; then
+	      func_append notinst_deplibs " $lib"
+	      need_relink=yes
+	    fi
+	    ;;
+	  esac
+	  # This is a shared library
+
+	  # Warn about portability, can't link against -module's on some
+	  # systems (darwin).  Don't bleat about dlopened modules though!
+	  dlopenmodule=""
+	  for dlpremoduletest in $dlprefiles; do
+	    if test "X$dlpremoduletest" = "X$lib"; then
+	      dlopenmodule="$dlpremoduletest"
+	      break
+	    fi
+	  done
+	  if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then
+	    echo
+	    if test "$linkmode" = prog; then
+	      $ECHO "*** Warning: Linking the executable $output against the loadable module"
+	    else
+	      $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+	    fi
+	    $ECHO "*** $linklib is not portable!"
+	  fi
+	  if test "$linkmode" = lib &&
+	     test "$hardcode_into_libs" = yes; then
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) func_append compile_rpath " $absdir" ;;
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append finalize_rpath " $libdir" ;;
+	      esac
+	      ;;
+	    esac
+	  fi
+
+	  if test -n "$old_archive_from_expsyms_cmds"; then
+	    # figure out the soname
+	    set dummy $library_names
+	    shift
+	    realname="$1"
+	    shift
+	    libname=`eval "\\$ECHO \"$libname_spec\""`
+	    # use dlname if we got it. it's perfectly good, no?
+	    if test -n "$dlname"; then
+	      soname="$dlname"
+	    elif test -n "$soname_spec"; then
+	      # bleh windows
+	      case $host in
+	      *cygwin* | mingw* | *cegcc*)
+	        func_arith $current - $age
+		major=$func_arith_result
+		versuffix="-$major"
+		;;
+	      esac
+	      eval soname=\"$soname_spec\"
+	    else
+	      soname="$realname"
+	    fi
+
+	    # Make a new name for the extract_expsyms_cmds to use
+	    soroot="$soname"
+	    func_basename "$soroot"
+	    soname="$func_basename_result"
+	    func_stripname 'lib' '.dll' "$soname"
+	    newlib=libimp-$func_stripname_result.a
+
+	    # If the library has no export list, then create one now
+	    if test -f "$output_objdir/$soname-def"; then :
+	    else
+	      func_verbose "extracting exported symbol list from \`$soname'"
+	      func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
+	    fi
+
+	    # Create $newlib
+	    if test -f "$output_objdir/$newlib"; then :; else
+	      func_verbose "generating import library for \`$soname'"
+	      func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
+	    fi
+	    # make sure the library variables are pointing to the new library
+	    dir=$output_objdir
+	    linklib=$newlib
+	  fi # test -n "$old_archive_from_expsyms_cmds"
+
+	  if test "$linkmode" = prog || test "$opt_mode" != relink; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    lib_linked=yes
+	    case $hardcode_action in
+	    immediate | unsupported)
+	      if test "$hardcode_direct" = no; then
+		add="$dir/$linklib"
+		case $host in
+		  *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
+		  *-*-sysv4*uw2*) add_dir="-L$dir" ;;
+		  *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+		    *-*-unixware7*) add_dir="-L$dir" ;;
+		  *-*-darwin* )
+		    # if the lib is a (non-dlopened) module then we can not
+		    # link against it, someone is ignoring the earlier warnings
+		    if /usr/bin/file -L $add 2> /dev/null |
+			 $GREP ": [^:]* bundle" >/dev/null ; then
+		      if test "X$dlopenmodule" != "X$lib"; then
+			$ECHO "*** Warning: lib $linklib is a module, not a shared library"
+			if test -z "$old_library" ; then
+			  echo
+			  echo "*** And there doesn't seem to be a static archive available"
+			  echo "*** The link will probably fail, sorry"
+			else
+			  add="$dir/$old_library"
+			fi
+		      elif test -n "$old_library"; then
+			add="$dir/$old_library"
+		      fi
+		    fi
+		esac
+	      elif test "$hardcode_minus_L" = no; then
+		case $host in
+		*-*-sunos*) add_shlibpath="$dir" ;;
+		esac
+		add_dir="-L$dir"
+		add="-l$name"
+	      elif test "$hardcode_shlibpath_var" = no; then
+		add_shlibpath="$dir"
+		add="-l$name"
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    relink)
+	      if test "$hardcode_direct" = yes &&
+	         test "$hardcode_direct_absolute" = no; then
+		add="$dir/$linklib"
+	      elif test "$hardcode_minus_L" = yes; then
+		add_dir="-L$absdir"
+		# Try looking first in the location we're being installed to.
+		if test -n "$inst_prefix_dir"; then
+		  case $libdir in
+		    [\\/]*)
+		      func_append add_dir " -L$inst_prefix_dir$libdir"
+		      ;;
+		  esac
+		fi
+		add="-l$name"
+	      elif test "$hardcode_shlibpath_var" = yes; then
+		add_shlibpath="$dir"
+		add="-l$name"
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    *) lib_linked=no ;;
+	    esac
+
+	    if test "$lib_linked" != yes; then
+	      func_fatal_configuration "unsupported hardcode properties"
+	    fi
+
+	    if test -n "$add_shlibpath"; then
+	      case :$compile_shlibpath: in
+	      *":$add_shlibpath:"*) ;;
+	      *) func_append compile_shlibpath "$add_shlibpath:" ;;
+	      esac
+	    fi
+	    if test "$linkmode" = prog; then
+	      test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+	      test -n "$add" && compile_deplibs="$add $compile_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	      if test "$hardcode_direct" != yes &&
+		 test "$hardcode_minus_L" != yes &&
+		 test "$hardcode_shlibpath_var" = yes; then
+		case :$finalize_shlibpath: in
+		*":$libdir:"*) ;;
+		*) func_append finalize_shlibpath "$libdir:" ;;
+		esac
+	      fi
+	    fi
+	  fi
+
+	  if test "$linkmode" = prog || test "$opt_mode" = relink; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    # Finalize command for both is simple: just hardcode it.
+	    if test "$hardcode_direct" = yes &&
+	       test "$hardcode_direct_absolute" = no; then
+	      add="$libdir/$linklib"
+	    elif test "$hardcode_minus_L" = yes; then
+	      add_dir="-L$libdir"
+	      add="-l$name"
+	    elif test "$hardcode_shlibpath_var" = yes; then
+	      case :$finalize_shlibpath: in
+	      *":$libdir:"*) ;;
+	      *) func_append finalize_shlibpath "$libdir:" ;;
+	      esac
+	      add="-l$name"
+	    elif test "$hardcode_automatic" = yes; then
+	      if test -n "$inst_prefix_dir" &&
+		 test -f "$inst_prefix_dir$libdir/$linklib" ; then
+		add="$inst_prefix_dir$libdir/$linklib"
+	      else
+		add="$libdir/$linklib"
+	      fi
+	    else
+	      # We cannot seem to hardcode it, guess we'll fake it.
+	      add_dir="-L$libdir"
+	      # Try looking first in the location we're being installed to.
+	      if test -n "$inst_prefix_dir"; then
+		case $libdir in
+		  [\\/]*)
+		    func_append add_dir " -L$inst_prefix_dir$libdir"
+		    ;;
+		esac
+	      fi
+	      add="-l$name"
+	    fi
+
+	    if test "$linkmode" = prog; then
+	      test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+	      test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	    fi
+	  fi
+	elif test "$linkmode" = prog; then
+	  # Here we assume that one of hardcode_direct or hardcode_minus_L
+	  # is not unsupported.  This is valid on all known static and
+	  # shared platforms.
+	  if test "$hardcode_direct" != unsupported; then
+	    test -n "$old_library" && linklib="$old_library"
+	    compile_deplibs="$dir/$linklib $compile_deplibs"
+	    finalize_deplibs="$dir/$linklib $finalize_deplibs"
+	  else
+	    compile_deplibs="-l$name -L$dir $compile_deplibs"
+	    finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+	  fi
+	elif test "$build_libtool_libs" = yes; then
+	  # Not a shared library
+	  if test "$deplibs_check_method" != pass_all; then
+	    # We're trying link a shared library against a static one
+	    # but the system doesn't support it.
+
+	    # Just print a warning and add the library to dependency_libs so
+	    # that the program can be linked against the static library.
+	    echo
+	    $ECHO "*** Warning: This system can not link to static lib archive $lib."
+	    echo "*** I have the capability to make that library automatically link in when"
+	    echo "*** you link to this library.  But I can only do this if you have a"
+	    echo "*** shared version of the library, which you do not appear to have."
+	    if test "$module" = yes; then
+	      echo "*** But as you try to build a module library, libtool will still create "
+	      echo "*** a static module, that should work as long as the dlopening application"
+	      echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+	      if test -z "$global_symbol_pipe"; then
+		echo
+		echo "*** However, this would only work if libtool was able to extract symbol"
+		echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+		echo "*** not find such a program.  So, this module is probably useless."
+		echo "*** \`nm' from GNU binutils and a full rebuild may help."
+	      fi
+	      if test "$build_old_libs" = no; then
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  else
+	    deplibs="$dir/$old_library $deplibs"
+	    link_static=yes
+	  fi
+	fi # link shared/static library?
+
+	if test "$linkmode" = lib; then
+	  if test -n "$dependency_libs" &&
+	     { test "$hardcode_into_libs" != yes ||
+	       test "$build_old_libs" = yes ||
+	       test "$link_static" = yes; }; then
+	    # Extract -R from dependency_libs
+	    temp_deplibs=
+	    for libdir in $dependency_libs; do
+	      case $libdir in
+	      -R*) func_stripname '-R' '' "$libdir"
+	           temp_xrpath=$func_stripname_result
+		   case " $xrpath " in
+		   *" $temp_xrpath "*) ;;
+		   *) func_append xrpath " $temp_xrpath";;
+		   esac;;
+	      *) func_append temp_deplibs " $libdir";;
+	      esac
+	    done
+	    dependency_libs="$temp_deplibs"
+	  fi
+
+	  func_append newlib_search_path " $absdir"
+	  # Link against this library
+	  test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+	  # ... and its dependency_libs
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    newdependency_libs="$deplib $newdependency_libs"
+	    case $deplib in
+              -L*) func_stripname '-L' '' "$deplib"
+                   func_resolve_sysroot "$func_stripname_result";;
+              *) func_resolve_sysroot "$deplib" ;;
+            esac
+	    if $opt_preserve_dup_deps ; then
+	      case "$tmp_libs " in
+	      *" $func_resolve_sysroot_result "*)
+                func_append specialdeplibs " $func_resolve_sysroot_result" ;;
+	      esac
+	    fi
+	    func_append tmp_libs " $func_resolve_sysroot_result"
+	  done
+
+	  if test "$link_all_deplibs" != no; then
+	    # Add the search paths of all dependency libraries
+	    for deplib in $dependency_libs; do
+	      path=
+	      case $deplib in
+	      -L*) path="$deplib" ;;
+	      *.la)
+	        func_resolve_sysroot "$deplib"
+	        deplib=$func_resolve_sysroot_result
+	        func_dirname "$deplib" "" "."
+		dir=$func_dirname_result
+		# We need an absolute path.
+		case $dir in
+		[\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+		*)
+		  absdir=`cd "$dir" && pwd`
+		  if test -z "$absdir"; then
+		    func_warning "cannot determine absolute directory name of \`$dir'"
+		    absdir="$dir"
+		  fi
+		  ;;
+		esac
+		if $GREP "^installed=no" $deplib > /dev/null; then
+		case $host in
+		*-*-darwin*)
+		  depdepl=
+		  eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+		  if test -n "$deplibrary_names" ; then
+		    for tmp in $deplibrary_names ; do
+		      depdepl=$tmp
+		    done
+		    if test -f "$absdir/$objdir/$depdepl" ; then
+		      depdepl="$absdir/$objdir/$depdepl"
+		      darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+                      if test -z "$darwin_install_name"; then
+                          darwin_install_name=`${OTOOL64} -L $depdepl  | awk '{if (NR == 2) {print $1;exit}}'`
+                      fi
+		      func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}"
+		      func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}"
+		      path=
+		    fi
+		  fi
+		  ;;
+		*)
+		  path="-L$absdir/$objdir"
+		  ;;
+		esac
+		else
+		  eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+		  test -z "$libdir" && \
+		    func_fatal_error "\`$deplib' is not a valid libtool archive"
+		  test "$absdir" != "$libdir" && \
+		    func_warning "\`$deplib' seems to be moved"
+
+		  path="-L$absdir"
+		fi
+		;;
+	      esac
+	      case " $deplibs " in
+	      *" $path "*) ;;
+	      *) deplibs="$path $deplibs" ;;
+	      esac
+	    done
+	  fi # link_all_deplibs != no
+	fi # linkmode = lib
+      done # for deplib in $libs
+      if test "$pass" = link; then
+	if test "$linkmode" = "prog"; then
+	  compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
+	  finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
+	else
+	  compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	fi
+      fi
+      dependency_libs="$newdependency_libs"
+      if test "$pass" = dlpreopen; then
+	# Link the dlpreopened libraries before other libraries
+	for deplib in $save_deplibs; do
+	  deplibs="$deplib $deplibs"
+	done
+      fi
+      if test "$pass" != dlopen; then
+	if test "$pass" != conv; then
+	  # Make sure lib_search_path contains only unique directories.
+	  lib_search_path=
+	  for dir in $newlib_search_path; do
+	    case "$lib_search_path " in
+	    *" $dir "*) ;;
+	    *) func_append lib_search_path " $dir" ;;
+	    esac
+	  done
+	  newlib_search_path=
+	fi
+
+	if test "$linkmode,$pass" != "prog,link"; then
+	  vars="deplibs"
+	else
+	  vars="compile_deplibs finalize_deplibs"
+	fi
+	for var in $vars dependency_libs; do
+	  # Add libraries to $var in reverse order
+	  eval tmp_libs=\"\$$var\"
+	  new_libs=
+	  for deplib in $tmp_libs; do
+	    # FIXME: Pedantically, this is the right thing to do, so
+	    #        that some nasty dependency loop isn't accidentally
+	    #        broken:
+	    #new_libs="$deplib $new_libs"
+	    # Pragmatically, this seems to cause very few problems in
+	    # practice:
+	    case $deplib in
+	    -L*) new_libs="$deplib $new_libs" ;;
+	    -R*) ;;
+	    *)
+	      # And here is the reason: when a library appears more
+	      # than once as an explicit dependence of a library, or
+	      # is implicitly linked in more than once by the
+	      # compiler, it is considered special, and multiple
+	      # occurrences thereof are not removed.  Compare this
+	      # with having the same library being listed as a
+	      # dependency of multiple other libraries: in this case,
+	      # we know (pedantically, we assume) the library does not
+	      # need to be listed more than once, so we keep only the
+	      # last copy.  This is not always right, but it is rare
+	      # enough that we require users that really mean to play
+	      # such unportable linking tricks to link the library
+	      # using -Wl,-lname, so that libtool does not consider it
+	      # for duplicate removal.
+	      case " $specialdeplibs " in
+	      *" $deplib "*) new_libs="$deplib $new_libs" ;;
+	      *)
+		case " $new_libs " in
+		*" $deplib "*) ;;
+		*) new_libs="$deplib $new_libs" ;;
+		esac
+		;;
+	      esac
+	      ;;
+	    esac
+	  done
+	  tmp_libs=
+	  for deplib in $new_libs; do
+	    case $deplib in
+	    -L*)
+	      case " $tmp_libs " in
+	      *" $deplib "*) ;;
+	      *) func_append tmp_libs " $deplib" ;;
+	      esac
+	      ;;
+	    *) func_append tmp_libs " $deplib" ;;
+	    esac
+	  done
+	  eval $var=\"$tmp_libs\"
+	done # for var
+      fi
+      # Last step: remove runtime libs from dependency_libs
+      # (they stay in deplibs)
+      tmp_libs=
+      for i in $dependency_libs ; do
+	case " $predeps $postdeps $compiler_lib_search_path " in
+	*" $i "*)
+	  i=""
+	  ;;
+	esac
+	if test -n "$i" ; then
+	  func_append tmp_libs " $i"
+	fi
+      done
+      dependency_libs=$tmp_libs
+    done # for pass
+    if test "$linkmode" = prog; then
+      dlfiles="$newdlfiles"
+    fi
+    if test "$linkmode" = prog || test "$linkmode" = lib; then
+      dlprefiles="$newdlprefiles"
+    fi
+
+    case $linkmode in
+    oldlib)
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	func_warning "\`-dlopen' is ignored for archives"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	func_warning "\`-l' and \`-L' are ignored for archives" ;;
+      esac
+
+      test -n "$rpath" && \
+	func_warning "\`-rpath' is ignored for archives"
+
+      test -n "$xrpath" && \
+	func_warning "\`-R' is ignored for archives"
+
+      test -n "$vinfo" && \
+	func_warning "\`-version-info/-version-number' is ignored for archives"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for archives"
+
+      test -n "$export_symbols$export_symbols_regex" && \
+	func_warning "\`-export-symbols' is ignored for archives"
+
+      # Now set the variables for building old libraries.
+      build_libtool_libs=no
+      oldlibs="$output"
+      func_append objs "$old_deplibs"
+      ;;
+
+    lib)
+      # Make sure we only generate libraries of the form `libNAME.la'.
+      case $outputname in
+      lib*)
+	func_stripname 'lib' '.la' "$outputname"
+	name=$func_stripname_result
+	eval shared_ext=\"$shrext_cmds\"
+	eval libname=\"$libname_spec\"
+	;;
+      *)
+	test "$module" = no && \
+	  func_fatal_help "libtool library \`$output' must begin with \`lib'"
+
+	if test "$need_lib_prefix" != no; then
+	  # Add the "lib" prefix for modules if required
+	  func_stripname '' '.la' "$outputname"
+	  name=$func_stripname_result
+	  eval shared_ext=\"$shrext_cmds\"
+	  eval libname=\"$libname_spec\"
+	else
+	  func_stripname '' '.la' "$outputname"
+	  libname=$func_stripname_result
+	fi
+	;;
+      esac
+
+      if test -n "$objs"; then
+	if test "$deplibs_check_method" != pass_all; then
+	  func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs"
+	else
+	  echo
+	  $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
+	  $ECHO "*** objects $objs is not portable!"
+	  func_append libobjs " $objs"
+	fi
+      fi
+
+      test "$dlself" != no && \
+	func_warning "\`-dlopen self' is ignored for libtool libraries"
+
+      set dummy $rpath
+      shift
+      test "$#" -gt 1 && \
+	func_warning "ignoring multiple \`-rpath's for a libtool library"
+
+      install_libdir="$1"
+
+      oldlibs=
+      if test -z "$rpath"; then
+	if test "$build_libtool_libs" = yes; then
+	  # Building a libtool convenience library.
+	  # Some compilers have problems with a `.al' extension so
+	  # convenience libraries should have the same extension an
+	  # archive normally would.
+	  oldlibs="$output_objdir/$libname.$libext $oldlibs"
+	  build_libtool_libs=convenience
+	  build_old_libs=yes
+	fi
+
+	test -n "$vinfo" && \
+	  func_warning "\`-version-info/-version-number' is ignored for convenience libraries"
+
+	test -n "$release" && \
+	  func_warning "\`-release' is ignored for convenience libraries"
+      else
+
+	# Parse the version information argument.
+	save_ifs="$IFS"; IFS=':'
+	set dummy $vinfo 0 0 0
+	shift
+	IFS="$save_ifs"
+
+	test -n "$7" && \
+	  func_fatal_help "too many parameters to \`-version-info'"
+
+	# convert absolute version numbers to libtool ages
+	# this retains compatibility with .la files and attempts
+	# to make the code below a bit more comprehensible
+
+	case $vinfo_number in
+	yes)
+	  number_major="$1"
+	  number_minor="$2"
+	  number_revision="$3"
+	  #
+	  # There are really only two kinds -- those that
+	  # use the current revision as the major version
+	  # and those that subtract age and use age as
+	  # a minor version.  But, then there is irix
+	  # which has an extra 1 added just for fun
+	  #
+	  case $version_type in
+	  # correct linux to gnu/linux during the next big refactor
+	  darwin|linux|osf|windows|none)
+	    func_arith $number_major + $number_minor
+	    current=$func_arith_result
+	    age="$number_minor"
+	    revision="$number_revision"
+	    ;;
+	  freebsd-aout|freebsd-elf|qnx|sunos)
+	    current="$number_major"
+	    revision="$number_minor"
+	    age="0"
+	    ;;
+	  irix|nonstopux)
+	    func_arith $number_major + $number_minor
+	    current=$func_arith_result
+	    age="$number_minor"
+	    revision="$number_minor"
+	    lt_irix_increment=no
+	    ;;
+	  esac
+	  ;;
+	no)
+	  current="$1"
+	  revision="$2"
+	  age="$3"
+	  ;;
+	esac
+
+	# Check that each of the things are valid numbers.
+	case $current in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "CURRENT \`$current' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	case $revision in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "REVISION \`$revision' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	case $age in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "AGE \`$age' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	if test "$age" -gt "$current"; then
+	  func_error "AGE \`$age' is greater than the current interface number \`$current'"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	fi
+
+	# Calculate the version variables.
+	major=
+	versuffix=
+	verstring=
+	case $version_type in
+	none) ;;
+
+	darwin)
+	  # Like Linux, but with the current version available in
+	  # verstring for coding it into the library header
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix="$major.$age.$revision"
+	  # Darwin ld doesn't like 0 for these options...
+	  func_arith $current + 1
+	  minor_current=$func_arith_result
+	  xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
+	  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+	  ;;
+
+	freebsd-aout)
+	  major=".$current"
+	  versuffix=".$current.$revision";
+	  ;;
+
+	freebsd-elf)
+	  major=".$current"
+	  versuffix=".$current"
+	  ;;
+
+	irix | nonstopux)
+	  if test "X$lt_irix_increment" = "Xno"; then
+	    func_arith $current - $age
+	  else
+	    func_arith $current - $age + 1
+	  fi
+	  major=$func_arith_result
+
+	  case $version_type in
+	    nonstopux) verstring_prefix=nonstopux ;;
+	    *)         verstring_prefix=sgi ;;
+	  esac
+	  verstring="$verstring_prefix$major.$revision"
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$revision
+	  while test "$loop" -ne 0; do
+	    func_arith $revision - $loop
+	    iface=$func_arith_result
+	    func_arith $loop - 1
+	    loop=$func_arith_result
+	    verstring="$verstring_prefix$major.$iface:$verstring"
+	  done
+
+	  # Before this point, $major must not contain `.'.
+	  major=.$major
+	  versuffix="$major.$revision"
+	  ;;
+
+	linux) # correct to gnu/linux during the next big refactor
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix="$major.$age.$revision"
+	  ;;
+
+	osf)
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix=".$current.$age.$revision"
+	  verstring="$current.$age.$revision"
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$age
+	  while test "$loop" -ne 0; do
+	    func_arith $current - $loop
+	    iface=$func_arith_result
+	    func_arith $loop - 1
+	    loop=$func_arith_result
+	    verstring="$verstring:${iface}.0"
+	  done
+
+	  # Make executables depend on our current version.
+	  func_append verstring ":${current}.0"
+	  ;;
+
+	qnx)
+	  major=".$current"
+	  versuffix=".$current"
+	  ;;
+
+	sunos)
+	  major=".$current"
+	  versuffix=".$current.$revision"
+	  ;;
+
+	windows)
+	  # Use '-' rather than '.', since we only want one
+	  # extension on DOS 8.3 filesystems.
+	  func_arith $current - $age
+	  major=$func_arith_result
+	  versuffix="-$major"
+	  ;;
+
+	*)
+	  func_fatal_configuration "unknown library version type \`$version_type'"
+	  ;;
+	esac
+
+	# Clear the version info if we defaulted, and they specified a release.
+	if test -z "$vinfo" && test -n "$release"; then
+	  major=
+	  case $version_type in
+	  darwin)
+	    # we can't check for "0.0" in archive_cmds due to quoting
+	    # problems, so we reset it completely
+	    verstring=
+	    ;;
+	  *)
+	    verstring="0.0"
+	    ;;
+	  esac
+	  if test "$need_version" = no; then
+	    versuffix=
+	  else
+	    versuffix=".0.0"
+	  fi
+	fi
+
+	# Remove version info from name if versioning should be avoided
+	if test "$avoid_version" = yes && test "$need_version" = no; then
+	  major=
+	  versuffix=
+	  verstring=""
+	fi
+
+	# Check to see if the archive will have undefined symbols.
+	if test "$allow_undefined" = yes; then
+	  if test "$allow_undefined_flag" = unsupported; then
+	    func_warning "undefined symbols not allowed in $host shared libraries"
+	    build_libtool_libs=no
+	    build_old_libs=yes
+	  fi
+	else
+	  # Don't allow undefined symbols.
+	  allow_undefined_flag="$no_undefined_flag"
+	fi
+
+      fi
+
+      func_generate_dlsyms "$libname" "$libname" "yes"
+      func_append libobjs " $symfileobj"
+      test "X$libobjs" = "X " && libobjs=
+
+      if test "$opt_mode" != relink; then
+	# Remove our outputs, but don't remove object files since they
+	# may have been created when compiling PIC objects.
+	removelist=
+	tempremovelist=`$ECHO "$output_objdir/*"`
+	for p in $tempremovelist; do
+	  case $p in
+	    *.$objext | *.gcno)
+	       ;;
+	    $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+	       if test "X$precious_files_regex" != "X"; then
+		 if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+		 then
+		   continue
+		 fi
+	       fi
+	       func_append removelist " $p"
+	       ;;
+	    *) ;;
+	  esac
+	done
+	test -n "$removelist" && \
+	  func_show_eval "${RM}r \$removelist"
+      fi
+
+      # Now set the variables for building old libraries.
+      if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+	func_append oldlibs " $output_objdir/$libname.$libext"
+
+	# Transform .lo files to .o files.
+	oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP`
+      fi
+
+      # Eliminate all temporary directories.
+      #for path in $notinst_path; do
+      #	lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
+      #	deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
+      #	dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
+      #done
+
+      if test -n "$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	temp_xrpath=
+	for libdir in $xrpath; do
+	  func_replace_sysroot "$libdir"
+	  func_append temp_xrpath " -R$func_replace_sysroot_result"
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_rpath " $libdir" ;;
+	  esac
+	done
+	if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+	  dependency_libs="$temp_xrpath $dependency_libs"
+	fi
+      fi
+
+      # Make sure dlfiles contains only unique files that won't be dlpreopened
+      old_dlfiles="$dlfiles"
+      dlfiles=
+      for lib in $old_dlfiles; do
+	case " $dlprefiles $dlfiles " in
+	*" $lib "*) ;;
+	*) func_append dlfiles " $lib" ;;
+	esac
+      done
+
+      # Make sure dlprefiles contains only unique files
+      old_dlprefiles="$dlprefiles"
+      dlprefiles=
+      for lib in $old_dlprefiles; do
+	case "$dlprefiles " in
+	*" $lib "*) ;;
+	*) func_append dlprefiles " $lib" ;;
+	esac
+      done
+
+      if test "$build_libtool_libs" = yes; then
+	if test -n "$rpath"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
+	    # these systems don't actually have a c library (as such)!
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C library is in the System framework
+	    func_append deplibs " System.ltframework"
+	    ;;
+	  *-*-netbsd*)
+	    # Don't link with libc until the a.out ld.so is fixed.
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	    # Do not include libc due to us having libc/libc_r.
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    ;;
+	  *)
+	    # Add libc to deplibs on all other systems if necessary.
+	    if test "$build_libtool_need_lc" = "yes"; then
+	      func_append deplibs " -lc"
+	    fi
+	    ;;
+	  esac
+	fi
+
+	# Transform deplibs into only deplibs that can be linked in shared.
+	name_save=$name
+	libname_save=$libname
+	release_save=$release
+	versuffix_save=$versuffix
+	major_save=$major
+	# I'm not sure if I'm treating the release correctly.  I think
+	# release should show up in the -l (ie -lgmp5) so we don't want to
+	# add it in twice.  Is that correct?
+	release=""
+	versuffix=""
+	major=""
+	newdeplibs=
+	droppeddeps=no
+	case $deplibs_check_method in
+	pass_all)
+	  # Don't check for shared/static.  Everything works.
+	  # This might be a little naive.  We might want to check
+	  # whether the library exists or not.  But this is on
+	  # osf3 & osf4 and I'm not really sure... Just
+	  # implementing what was already the behavior.
+	  newdeplibs=$deplibs
+	  ;;
+	test_compile)
+	  # This code stresses the "libraries are programs" paradigm to its
+	  # limits. Maybe even breaks it.  We compile a program, linking it
+	  # against the deplibs as a proxy for the library.  Then we can check
+	  # whether they linked in statically or dynamically with ldd.
+	  $opt_dry_run || $RM conftest.c
+	  cat > conftest.c </dev/null`
+		    $nocaseglob
+		  else
+		    potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+		  fi
+		  for potent_lib in $potential_libs; do
+		      # Follow soft links.
+		      if ls -lLd "$potent_lib" 2>/dev/null |
+			 $GREP " -> " >/dev/null; then
+			continue
+		      fi
+		      # The statement above tries to avoid entering an
+		      # endless loop below, in case of cyclic links.
+		      # We might still enter an endless loop, since a link
+		      # loop can be closed while we follow links,
+		      # but so what?
+		      potlib="$potent_lib"
+		      while test -h "$potlib" 2>/dev/null; do
+			potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+			case $potliblink in
+			[\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+			*) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";;
+			esac
+		      done
+		      if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
+			 $SED -e 10q |
+			 $EGREP "$file_magic_regex" > /dev/null; then
+			func_append newdeplibs " $a_deplib"
+			a_deplib=""
+			break 2
+		      fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib" ; then
+		droppeddeps=yes
+		echo
+		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib" ; then
+		  $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+		else
+		  $ECHO "*** with $libname and none of the candidates passed a file format test"
+		  $ECHO "*** using a file magic. Last file checked: $potlib"
+		fi
+	      fi
+	      ;;
+	    *)
+	      # Add a -L argument.
+	      func_append newdeplibs " $a_deplib"
+	      ;;
+	    esac
+	  done # Gone through all deplibs.
+	  ;;
+	match_pattern*)
+	  set dummy $deplibs_check_method; shift
+	  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    case $a_deplib in
+	    -l*)
+	      func_stripname -l '' "$a_deplib"
+	      name=$func_stripname_result
+	      if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  func_append newdeplibs " $a_deplib"
+		  a_deplib=""
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib" ; then
+		libname=`eval "\\$ECHO \"$libname_spec\""`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+		  for potent_lib in $potential_libs; do
+		    potlib="$potent_lib" # see symlink-check above in file_magic test
+		    if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
+		       $EGREP "$match_pattern_regex" > /dev/null; then
+		      func_append newdeplibs " $a_deplib"
+		      a_deplib=""
+		      break 2
+		    fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib" ; then
+		droppeddeps=yes
+		echo
+		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib" ; then
+		  $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+		else
+		  $ECHO "*** with $libname and none of the candidates passed a file format test"
+		  $ECHO "*** using a regex pattern. Last file checked: $potlib"
+		fi
+	      fi
+	      ;;
+	    *)
+	      # Add a -L argument.
+	      func_append newdeplibs " $a_deplib"
+	      ;;
+	    esac
+	  done # Gone through all deplibs.
+	  ;;
+	none | unknown | *)
+	  newdeplibs=""
+	  tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
+	  if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	    for i in $predeps $postdeps ; do
+	      # can't use Xsed below, because $i might contain '/'
+	      tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"`
+	    done
+	  fi
+	  case $tmp_deplibs in
+	  *[!\	\ ]*)
+	    echo
+	    if test "X$deplibs_check_method" = "Xnone"; then
+	      echo "*** Warning: inter-library dependencies are not supported in this platform."
+	    else
+	      echo "*** Warning: inter-library dependencies are not known to be supported."
+	    fi
+	    echo "*** All declared inter-library dependencies are being dropped."
+	    droppeddeps=yes
+	    ;;
+	  esac
+	  ;;
+	esac
+	versuffix=$versuffix_save
+	major=$major_save
+	release=$release_save
+	libname=$libname_save
+	name=$name_save
+
+	case $host in
+	*-*-rhapsody* | *-*-darwin1.[012])
+	  # On Rhapsody replace the C library with the System framework
+	  newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
+	  ;;
+	esac
+
+	if test "$droppeddeps" = yes; then
+	  if test "$module" = yes; then
+	    echo
+	    echo "*** Warning: libtool could not satisfy all declared inter-library"
+	    $ECHO "*** dependencies of module $libname.  Therefore, libtool will create"
+	    echo "*** a static module, that should work as long as the dlopening"
+	    echo "*** application is linked with the -dlopen flag."
+	    if test -z "$global_symbol_pipe"; then
+	      echo
+	      echo "*** However, this would only work if libtool was able to extract symbol"
+	      echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+	      echo "*** not find such a program.  So, this module is probably useless."
+	      echo "*** \`nm' from GNU binutils and a full rebuild may help."
+	    fi
+	    if test "$build_old_libs" = no; then
+	      oldlibs="$output_objdir/$libname.$libext"
+	      build_libtool_libs=module
+	      build_old_libs=yes
+	    else
+	      build_libtool_libs=no
+	    fi
+	  else
+	    echo "*** The inter-library dependencies that have been dropped here will be"
+	    echo "*** automatically added whenever a program is linked with this library"
+	    echo "*** or is declared to -dlopen it."
+
+	    if test "$allow_undefined" = no; then
+	      echo
+	      echo "*** Since this library must not contain undefined symbols,"
+	      echo "*** because either the platform does not support them or"
+	      echo "*** it was explicitly requested with -no-undefined,"
+	      echo "*** libtool will only create a static version of it."
+	      if test "$build_old_libs" = no; then
+		oldlibs="$output_objdir/$libname.$libext"
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  fi
+	fi
+	# Done checking deplibs!
+	deplibs=$newdeplibs
+      fi
+      # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+      case $host in
+	*-*-darwin*)
+	  newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  ;;
+      esac
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $deplibs " in
+	  *" -L$path/$objdir "*)
+	    func_append new_libs " -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) func_append new_libs " $deplib" ;;
+	  esac
+	  ;;
+	*) func_append new_libs " $deplib" ;;
+	esac
+      done
+      deplibs="$new_libs"
+
+      # All the library-specific variables (install_libdir is set above).
+      library_names=
+      old_library=
+      dlname=
+
+      # Test again, we may have decided not to build it any more
+      if test "$build_libtool_libs" = yes; then
+	# Remove ${wl} instances when linking with ld.
+	# FIXME: should test the right _cmds variable.
+	case $archive_cmds in
+	  *\$LD\ *) wl= ;;
+        esac
+	if test "$hardcode_into_libs" = yes; then
+	  # Hardcode the library paths
+	  hardcode_libdirs=
+	  dep_rpath=
+	  rpath="$finalize_rpath"
+	  test "$opt_mode" != relink && rpath="$compile_rpath$rpath"
+	  for libdir in $rpath; do
+	    if test -n "$hardcode_libdir_flag_spec"; then
+	      if test -n "$hardcode_libdir_separator"; then
+		func_replace_sysroot "$libdir"
+		libdir=$func_replace_sysroot_result
+		if test -z "$hardcode_libdirs"; then
+		  hardcode_libdirs="$libdir"
+		else
+		  # Just accumulate the unique libdirs.
+		  case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+		  *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		    ;;
+		  *)
+		    func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		    ;;
+		  esac
+		fi
+	      else
+		eval flag=\"$hardcode_libdir_flag_spec\"
+		func_append dep_rpath " $flag"
+	      fi
+	    elif test -n "$runpath_var"; then
+	      case "$perm_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append perm_rpath " $libdir" ;;
+	      esac
+	    fi
+	  done
+	  # Substitute the hardcoded libdirs into the rpath.
+	  if test -n "$hardcode_libdir_separator" &&
+	     test -n "$hardcode_libdirs"; then
+	    libdir="$hardcode_libdirs"
+	    eval "dep_rpath=\"$hardcode_libdir_flag_spec\""
+	  fi
+	  if test -n "$runpath_var" && test -n "$perm_rpath"; then
+	    # We should set the runpath_var.
+	    rpath=
+	    for dir in $perm_rpath; do
+	      func_append rpath "$dir:"
+	    done
+	    eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+	  fi
+	  test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+	fi
+
+	shlibpath="$finalize_shlibpath"
+	test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+	if test -n "$shlibpath"; then
+	  eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+	fi
+
+	# Get the real and link names of the library.
+	eval shared_ext=\"$shrext_cmds\"
+	eval library_names=\"$library_names_spec\"
+	set dummy $library_names
+	shift
+	realname="$1"
+	shift
+
+	if test -n "$soname_spec"; then
+	  eval soname=\"$soname_spec\"
+	else
+	  soname="$realname"
+	fi
+	if test -z "$dlname"; then
+	  dlname=$soname
+	fi
+
+	lib="$output_objdir/$realname"
+	linknames=
+	for link
+	do
+	  func_append linknames " $link"
+	done
+
+	# Use standard objects if they are pic
+	test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	test "X$libobjs" = "X " && libobjs=
+
+	delfiles=
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
+	  export_symbols="$output_objdir/$libname.uexp"
+	  func_append delfiles " $export_symbols"
+	fi
+
+	orig_export_symbols=
+	case $host_os in
+	cygwin* | mingw* | cegcc*)
+	  if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
+	    # exporting using user supplied symfile
+	    if test "x`$SED 1q $export_symbols`" != xEXPORTS; then
+	      # and it's NOT already a .def file. Must figure out
+	      # which of the given symbols are data symbols and tag
+	      # them as such. So, trigger use of export_symbols_cmds.
+	      # export_symbols gets reassigned inside the "prepare
+	      # the list of exported symbols" if statement, so the
+	      # include_expsyms logic still works.
+	      orig_export_symbols="$export_symbols"
+	      export_symbols=
+	      always_export_symbols=yes
+	    fi
+	  fi
+	  ;;
+	esac
+
+	# Prepare the list of exported symbols
+	if test -z "$export_symbols"; then
+	  if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+	    func_verbose "generating symbol list for \`$libname.la'"
+	    export_symbols="$output_objdir/$libname.exp"
+	    $opt_dry_run || $RM $export_symbols
+	    cmds=$export_symbols_cmds
+	    save_ifs="$IFS"; IFS='~'
+	    for cmd1 in $cmds; do
+	      IFS="$save_ifs"
+	      # Take the normal branch if the nm_file_list_spec branch
+	      # doesn't work or if tool conversion is not needed.
+	      case $nm_file_list_spec~$to_tool_file_cmd in
+		*~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*)
+		  try_normal_branch=yes
+		  eval cmd=\"$cmd1\"
+		  func_len " $cmd"
+		  len=$func_len_result
+		  ;;
+		*)
+		  try_normal_branch=no
+		  ;;
+	      esac
+	      if test "$try_normal_branch" = yes \
+		 && { test "$len" -lt "$max_cmd_len" \
+		      || test "$max_cmd_len" -le -1; }
+	      then
+		func_show_eval "$cmd" 'exit $?'
+		skipped_export=false
+	      elif test -n "$nm_file_list_spec"; then
+		func_basename "$output"
+		output_la=$func_basename_result
+		save_libobjs=$libobjs
+		save_output=$output
+		output=${output_objdir}/${output_la}.nm
+		func_to_tool_file "$output"
+		libobjs=$nm_file_list_spec$func_to_tool_file_result
+		func_append delfiles " $output"
+		func_verbose "creating $NM input file list: $output"
+		for obj in $save_libobjs; do
+		  func_to_tool_file "$obj"
+		  $ECHO "$func_to_tool_file_result"
+		done > "$output"
+		eval cmd=\"$cmd1\"
+		func_show_eval "$cmd" 'exit $?'
+		output=$save_output
+		libobjs=$save_libobjs
+		skipped_export=false
+	      else
+		# The command line is too long to execute in one step.
+		func_verbose "using reloadable object file for export list..."
+		skipped_export=:
+		# Break out early, otherwise skipped_export may be
+		# set to false by a later but shorter cmd.
+		break
+	      fi
+	    done
+	    IFS="$save_ifs"
+	    if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then
+	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+	fi
+
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  tmp_export_symbols="$export_symbols"
+	  test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+	  $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+	fi
+
+	if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then
+	  # The given exports_symbols file has to be filtered, so filter it.
+	  func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+	  # FIXME: $output_objdir/$libname.filter potentially contains lots of
+	  # 's' commands which not all seds can handle. GNU sed should be fine
+	  # though. Also, the filter scales superlinearly with the number of
+	  # global variables. join(1) would be nice here, but unfortunately
+	  # isn't a blessed tool.
+	  $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+	  func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+	  export_symbols=$output_objdir/$libname.def
+	  $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+	fi
+
+	tmp_deplibs=
+	for test_deplib in $deplibs; do
+	  case " $convenience " in
+	  *" $test_deplib "*) ;;
+	  *)
+	    func_append tmp_deplibs " $test_deplib"
+	    ;;
+	  esac
+	done
+	deplibs="$tmp_deplibs"
+
+	if test -n "$convenience"; then
+	  if test -n "$whole_archive_flag_spec" &&
+	    test "$compiler_needs_object" = yes &&
+	    test -z "$libobjs"; then
+	    # extract the archives, so we have objects to list.
+	    # TODO: could optimize this to just extract one archive.
+	    whole_archive_flag_spec=
+	  fi
+	  if test -n "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	    test "X$libobjs" = "X " && libobjs=
+	  else
+	    gentop="$output_objdir/${outputname}x"
+	    func_append generated " $gentop"
+
+	    func_extract_archives $gentop $convenience
+	    func_append libobjs " $func_extract_archives_result"
+	    test "X$libobjs" = "X " && libobjs=
+	  fi
+	fi
+
+	if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+	  eval flag=\"$thread_safe_flag_spec\"
+	  func_append linker_flags " $flag"
+	fi
+
+	# Make a backup of the uninstalled library when relinking
+	if test "$opt_mode" = relink; then
+	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
+	fi
+
+	# Do each of the archive commands.
+	if test "$module" = yes && test -n "$module_cmds" ; then
+	  if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	    eval test_cmds=\"$module_expsym_cmds\"
+	    cmds=$module_expsym_cmds
+	  else
+	    eval test_cmds=\"$module_cmds\"
+	    cmds=$module_cmds
+	  fi
+	else
+	  if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	    eval test_cmds=\"$archive_expsym_cmds\"
+	    cmds=$archive_expsym_cmds
+	  else
+	    eval test_cmds=\"$archive_cmds\"
+	    cmds=$archive_cmds
+	  fi
+	fi
+
+	if test "X$skipped_export" != "X:" &&
+	   func_len " $test_cmds" &&
+	   len=$func_len_result &&
+	   test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  :
+	else
+	  # The command line is too long to link in one step, link piecewise
+	  # or, if using GNU ld and skipped_export is not :, use a linker
+	  # script.
+
+	  # Save the value of $output and $libobjs because we want to
+	  # use them later.  If we have whole_archive_flag_spec, we
+	  # want to use save_libobjs as it was before
+	  # whole_archive_flag_spec was expanded, because we can't
+	  # assume the linker understands whole_archive_flag_spec.
+	  # This may have to be revisited, in case too many
+	  # convenience libraries get linked in and end up exceeding
+	  # the spec.
+	  if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	  fi
+	  save_output=$output
+	  func_basename "$output"
+	  output_la=$func_basename_result
+
+	  # Clear the reloadable object creation command queue and
+	  # initialize k to one.
+	  test_cmds=
+	  concat_cmds=
+	  objlist=
+	  last_robj=
+	  k=1
+
+	  if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then
+	    output=${output_objdir}/${output_la}.lnkscript
+	    func_verbose "creating GNU ld script: $output"
+	    echo 'INPUT (' > $output
+	    for obj in $save_libobjs
+	    do
+	      func_to_tool_file "$obj"
+	      $ECHO "$func_to_tool_file_result" >> $output
+	    done
+	    echo ')' >> $output
+	    func_append delfiles " $output"
+	    func_to_tool_file "$output"
+	    output=$func_to_tool_file_result
+	  elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then
+	    output=${output_objdir}/${output_la}.lnk
+	    func_verbose "creating linker input file list: $output"
+	    : > $output
+	    set x $save_libobjs
+	    shift
+	    firstobj=
+	    if test "$compiler_needs_object" = yes; then
+	      firstobj="$1 "
+	      shift
+	    fi
+	    for obj
+	    do
+	      func_to_tool_file "$obj"
+	      $ECHO "$func_to_tool_file_result" >> $output
+	    done
+	    func_append delfiles " $output"
+	    func_to_tool_file "$output"
+	    output=$firstobj\"$file_list_spec$func_to_tool_file_result\"
+	  else
+	    if test -n "$save_libobjs"; then
+	      func_verbose "creating reloadable object files..."
+	      output=$output_objdir/$output_la-${k}.$objext
+	      eval test_cmds=\"$reload_cmds\"
+	      func_len " $test_cmds"
+	      len0=$func_len_result
+	      len=$len0
+
+	      # Loop over the list of objects to be linked.
+	      for obj in $save_libobjs
+	      do
+		func_len " $obj"
+		func_arith $len + $func_len_result
+		len=$func_arith_result
+		if test "X$objlist" = X ||
+		   test "$len" -lt "$max_cmd_len"; then
+		  func_append objlist " $obj"
+		else
+		  # The command $test_cmds is almost too long, add a
+		  # command to the queue.
+		  if test "$k" -eq 1 ; then
+		    # The first file doesn't have a previous command to add.
+		    reload_objs=$objlist
+		    eval concat_cmds=\"$reload_cmds\"
+		  else
+		    # All subsequent reloadable object files will link in
+		    # the last one created.
+		    reload_objs="$objlist $last_robj"
+		    eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
+		  fi
+		  last_robj=$output_objdir/$output_la-${k}.$objext
+		  func_arith $k + 1
+		  k=$func_arith_result
+		  output=$output_objdir/$output_la-${k}.$objext
+		  objlist=" $obj"
+		  func_len " $last_robj"
+		  func_arith $len0 + $func_len_result
+		  len=$func_arith_result
+		fi
+	      done
+	      # Handle the remaining objects by creating one last
+	      # reloadable object file.  All subsequent reloadable object
+	      # files will link in the last one created.
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      reload_objs="$objlist $last_robj"
+	      eval concat_cmds=\"\${concat_cmds}$reload_cmds\"
+	      if test -n "$last_robj"; then
+	        eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\"
+	      fi
+	      func_append delfiles " $output"
+
+	    else
+	      output=
+	    fi
+
+	    if ${skipped_export-false}; then
+	      func_verbose "generating symbol list for \`$libname.la'"
+	      export_symbols="$output_objdir/$libname.exp"
+	      $opt_dry_run || $RM $export_symbols
+	      libobjs=$output
+	      # Append the command to create the export file.
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
+	      if test -n "$last_robj"; then
+		eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+	      fi
+	    fi
+
+	    test -n "$save_libobjs" &&
+	      func_verbose "creating a temporary reloadable object file: $output"
+
+	    # Loop through the commands generated above and execute them.
+	    save_ifs="$IFS"; IFS='~'
+	    for cmd in $concat_cmds; do
+	      IFS="$save_ifs"
+	      $opt_silent || {
+		  func_quote_for_expand "$cmd"
+		  eval "func_echo $func_quote_for_expand_result"
+	      }
+	      $opt_dry_run || eval "$cmd" || {
+		lt_exit=$?
+
+		# Restore the uninstalled library and exit
+		if test "$opt_mode" = relink; then
+		  ( cd "$output_objdir" && \
+		    $RM "${realname}T" && \
+		    $MV "${realname}U" "$realname" )
+		fi
+
+		exit $lt_exit
+	      }
+	    done
+	    IFS="$save_ifs"
+
+	    if test -n "$export_symbols_regex" && ${skipped_export-false}; then
+	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+
+          if ${skipped_export-false}; then
+	    if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	      tmp_export_symbols="$export_symbols"
+	      test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+	      $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+	    fi
+
+	    if test -n "$orig_export_symbols"; then
+	      # The given exports_symbols file has to be filtered, so filter it.
+	      func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+	      # FIXME: $output_objdir/$libname.filter potentially contains lots of
+	      # 's' commands which not all seds can handle. GNU sed should be fine
+	      # though. Also, the filter scales superlinearly with the number of
+	      # global variables. join(1) would be nice here, but unfortunately
+	      # isn't a blessed tool.
+	      $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+	      func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+	      export_symbols=$output_objdir/$libname.def
+	      $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+	    fi
+	  fi
+
+	  libobjs=$output
+	  # Restore the value of output.
+	  output=$save_output
+
+	  if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	    test "X$libobjs" = "X " && libobjs=
+	  fi
+	  # Expand the library linking commands again to reset the
+	  # value of $libobjs for piecewise linking.
+
+	  # Do each of the archive commands.
+	  if test "$module" = yes && test -n "$module_cmds" ; then
+	    if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	      cmds=$module_expsym_cmds
+	    else
+	      cmds=$module_cmds
+	    fi
+	  else
+	    if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	      cmds=$archive_expsym_cmds
+	    else
+	      cmds=$archive_cmds
+	    fi
+	  fi
+	fi
+
+	if test -n "$delfiles"; then
+	  # Append the command to remove temporary files to $cmds.
+	  eval cmds=\"\$cmds~\$RM $delfiles\"
+	fi
+
+	# Add any objects from preloaded convenience libraries
+	if test -n "$dlprefiles"; then
+	  gentop="$output_objdir/${outputname}x"
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $dlprefiles
+	  func_append libobjs " $func_extract_archives_result"
+	  test "X$libobjs" = "X " && libobjs=
+	fi
+
+	save_ifs="$IFS"; IFS='~'
+	for cmd in $cmds; do
+	  IFS="$save_ifs"
+	  eval cmd=\"$cmd\"
+	  $opt_silent || {
+	    func_quote_for_expand "$cmd"
+	    eval "func_echo $func_quote_for_expand_result"
+	  }
+	  $opt_dry_run || eval "$cmd" || {
+	    lt_exit=$?
+
+	    # Restore the uninstalled library and exit
+	    if test "$opt_mode" = relink; then
+	      ( cd "$output_objdir" && \
+	        $RM "${realname}T" && \
+		$MV "${realname}U" "$realname" )
+	    fi
+
+	    exit $lt_exit
+	  }
+	done
+	IFS="$save_ifs"
+
+	# Restore the uninstalled library and exit
+	if test "$opt_mode" = relink; then
+	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
+
+	  if test -n "$convenience"; then
+	    if test -z "$whole_archive_flag_spec"; then
+	      func_show_eval '${RM}r "$gentop"'
+	    fi
+	  fi
+
+	  exit $EXIT_SUCCESS
+	fi
+
+	# Create links to the real library.
+	for linkname in $linknames; do
+	  if test "$realname" != "$linkname"; then
+	    func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
+	  fi
+	done
+
+	# If -module or -export-dynamic was specified, set the dlname.
+	if test "$module" = yes || test "$export_dynamic" = yes; then
+	  # On all known operating systems, these are identical.
+	  dlname="$soname"
+	fi
+      fi
+      ;;
+
+    obj)
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	func_warning "\`-dlopen' is ignored for objects"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	func_warning "\`-l' and \`-L' are ignored for objects" ;;
+      esac
+
+      test -n "$rpath" && \
+	func_warning "\`-rpath' is ignored for objects"
+
+      test -n "$xrpath" && \
+	func_warning "\`-R' is ignored for objects"
+
+      test -n "$vinfo" && \
+	func_warning "\`-version-info' is ignored for objects"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for objects"
+
+      case $output in
+      *.lo)
+	test -n "$objs$old_deplibs" && \
+	  func_fatal_error "cannot build library object \`$output' from non-libtool objects"
+
+	libobj=$output
+	func_lo2o "$libobj"
+	obj=$func_lo2o_result
+	;;
+      *)
+	libobj=
+	obj="$output"
+	;;
+      esac
+
+      # Delete the old objects.
+      $opt_dry_run || $RM $obj $libobj
+
+      # Objects from convenience libraries.  This assumes
+      # single-version convenience libraries.  Whenever we create
+      # different ones for PIC/non-PIC, this we'll have to duplicate
+      # the extraction.
+      reload_conv_objs=
+      gentop=
+      # reload_cmds runs $LD directly, so let us get rid of
+      # -Wl from whole_archive_flag_spec and hope we can get by with
+      # turning comma into space..
+      wl=
+
+      if test -n "$convenience"; then
+	if test -n "$whole_archive_flag_spec"; then
+	  eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+	  reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+	else
+	  gentop="$output_objdir/${obj}x"
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $convenience
+	  reload_conv_objs="$reload_objs $func_extract_archives_result"
+	fi
+      fi
+
+      # If we're not building shared, we need to use non_pic_objs
+      test "$build_libtool_libs" != yes && libobjs="$non_pic_objects"
+
+      # Create the old-style object.
+      reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+      output="$obj"
+      func_execute_cmds "$reload_cmds" 'exit $?'
+
+      # Exit if we aren't doing a library object file.
+      if test -z "$libobj"; then
+	if test -n "$gentop"; then
+	  func_show_eval '${RM}r "$gentop"'
+	fi
+
+	exit $EXIT_SUCCESS
+      fi
+
+      if test "$build_libtool_libs" != yes; then
+	if test -n "$gentop"; then
+	  func_show_eval '${RM}r "$gentop"'
+	fi
+
+	# Create an invalid libtool object if no PIC, so that we don't
+	# accidentally link it into a program.
+	# $show "echo timestamp > $libobj"
+	# $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
+	exit $EXIT_SUCCESS
+      fi
+
+      if test -n "$pic_flag" || test "$pic_mode" != default; then
+	# Only do commands if we really have different PIC objects.
+	reload_objs="$libobjs $reload_conv_objs"
+	output="$libobj"
+	func_execute_cmds "$reload_cmds" 'exit $?'
+      fi
+
+      if test -n "$gentop"; then
+	func_show_eval '${RM}r "$gentop"'
+      fi
+
+      exit $EXIT_SUCCESS
+      ;;
+
+    prog)
+      case $host in
+	*cygwin*) func_stripname '' '.exe' "$output"
+	          output=$func_stripname_result.exe;;
+      esac
+      test -n "$vinfo" && \
+	func_warning "\`-version-info' is ignored for programs"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for programs"
+
+      test "$preload" = yes \
+        && test "$dlopen_support" = unknown \
+	&& test "$dlopen_self" = unknown \
+	&& test "$dlopen_self_static" = unknown && \
+	  func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support."
+
+      case $host in
+      *-*-rhapsody* | *-*-darwin1.[012])
+	# On Rhapsody replace the C library is the System framework
+	compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
+	finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
+	;;
+      esac
+
+      case $host in
+      *-*-darwin*)
+	# Don't allow lazy linking, it breaks C++ global constructors
+	# But is supposedly fixed on 10.4 or later (yay!).
+	if test "$tagname" = CXX ; then
+	  case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+	    10.[0123])
+	      func_append compile_command " ${wl}-bind_at_load"
+	      func_append finalize_command " ${wl}-bind_at_load"
+	    ;;
+	  esac
+	fi
+	# Time to change all our "foo.ltframework" stuff back to "-framework foo"
+	compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	;;
+      esac
+
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $compile_deplibs " in
+	  *" -L$path/$objdir "*)
+	    func_append new_libs " -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $compile_deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) func_append new_libs " $deplib" ;;
+	  esac
+	  ;;
+	*) func_append new_libs " $deplib" ;;
+	esac
+      done
+      compile_deplibs="$new_libs"
+
+
+      func_append compile_command " $compile_deplibs"
+      func_append finalize_command " $finalize_deplibs"
+
+      if test -n "$rpath$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	for libdir in $rpath $xrpath; do
+	  # This is the magic to use -rpath.
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_rpath " $libdir" ;;
+	  esac
+	done
+      fi
+
+      # Now hardcode the library paths
+      rpath=
+      hardcode_libdirs=
+      for libdir in $compile_rpath $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs="$libdir"
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    func_append rpath " $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append perm_rpath " $libdir" ;;
+	  esac
+	fi
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	  testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$libdir:"*) ;;
+	  ::) dllsearchpath=$libdir;;
+	  *) func_append dllsearchpath ":$libdir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  ::) dllsearchpath=$testbindir;;
+	  *) func_append dllsearchpath ":$testbindir";;
+	  esac
+	  ;;
+	esac
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir="$hardcode_libdirs"
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      compile_rpath="$rpath"
+
+      rpath=
+      hardcode_libdirs=
+      for libdir in $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs="$libdir"
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    func_append rpath " $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$finalize_perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_perm_rpath " $libdir" ;;
+	  esac
+	fi
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir="$hardcode_libdirs"
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      finalize_rpath="$rpath"
+
+      if test -n "$libobjs" && test "$build_old_libs" = yes; then
+	# Transform all the library objects into standard objects.
+	compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+      fi
+
+      func_generate_dlsyms "$outputname" "@PROGRAM@" "no"
+
+      # template prelinking step
+      if test -n "$prelink_cmds"; then
+	func_execute_cmds "$prelink_cmds" 'exit $?'
+      fi
+
+      wrappers_required=yes
+      case $host in
+      *cegcc* | *mingw32ce*)
+        # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
+        wrappers_required=no
+        ;;
+      *cygwin* | *mingw* )
+        if test "$build_libtool_libs" != yes; then
+          wrappers_required=no
+        fi
+        ;;
+      *)
+        if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+          wrappers_required=no
+        fi
+        ;;
+      esac
+      if test "$wrappers_required" = no; then
+	# Replace the output file specification.
+	compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+	link_command="$compile_command$compile_rpath"
+
+	# We have no uninstalled library dependencies, so finalize right now.
+	exit_status=0
+	func_show_eval "$link_command" 'exit_status=$?'
+
+	if test -n "$postlink_cmds"; then
+	  func_to_tool_file "$output"
+	  postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	  func_execute_cmds "$postlink_cmds" 'exit $?'
+	fi
+
+	# Delete the generated files.
+	if test -f "$output_objdir/${outputname}S.${objext}"; then
+	  func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"'
+	fi
+
+	exit $exit_status
+      fi
+
+      if test -n "$compile_shlibpath$finalize_shlibpath"; then
+	compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+      fi
+      if test -n "$finalize_shlibpath"; then
+	finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+      fi
+
+      compile_var=
+      finalize_var=
+      if test -n "$runpath_var"; then
+	if test -n "$perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $perm_rpath; do
+	    func_append rpath "$dir:"
+	  done
+	  compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+	if test -n "$finalize_perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $finalize_perm_rpath; do
+	    func_append rpath "$dir:"
+	  done
+	  finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+      fi
+
+      if test "$no_install" = yes; then
+	# We don't need to create a wrapper script.
+	link_command="$compile_var$compile_command$compile_rpath"
+	# Replace the output file specification.
+	link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+	# Delete the old output file.
+	$opt_dry_run || $RM $output
+	# Link the executable and exit
+	func_show_eval "$link_command" 'exit $?'
+
+	if test -n "$postlink_cmds"; then
+	  func_to_tool_file "$output"
+	  postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	  func_execute_cmds "$postlink_cmds" 'exit $?'
+	fi
+
+	exit $EXIT_SUCCESS
+      fi
+
+      if test "$hardcode_action" = relink; then
+	# Fast installation is not supported
+	link_command="$compile_var$compile_command$compile_rpath"
+	relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+	func_warning "this platform does not like uninstalled shared libraries"
+	func_warning "\`$output' will be relinked during installation"
+      else
+	if test "$fast_install" != no; then
+	  link_command="$finalize_var$compile_command$finalize_rpath"
+	  if test "$fast_install" = yes; then
+	    relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
+	  else
+	    # fast_install is set to needless
+	    relink_command=
+	  fi
+	else
+	  link_command="$compile_var$compile_command$compile_rpath"
+	  relink_command="$finalize_var$finalize_command$finalize_rpath"
+	fi
+      fi
+
+      # Replace the output file specification.
+      link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+      # Delete the old output files.
+      $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+      func_show_eval "$link_command" 'exit $?'
+
+      if test -n "$postlink_cmds"; then
+	func_to_tool_file "$output_objdir/$outputname"
+	postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	func_execute_cmds "$postlink_cmds" 'exit $?'
+      fi
+
+      # Now create the wrapper script.
+      func_verbose "creating $output"
+
+      # Quote the relink command for shipping.
+      if test -n "$relink_command"; then
+	# Preserve any variables that may affect compiler behavior
+	for var in $variables_saved_for_relink; do
+	  if eval test -z \"\${$var+set}\"; then
+	    relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+	  elif eval var_value=\$$var; test -z "$var_value"; then
+	    relink_command="$var=; export $var; $relink_command"
+	  else
+	    func_quote_for_eval "$var_value"
+	    relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+	  fi
+	done
+	relink_command="(cd `pwd`; $relink_command)"
+	relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      fi
+
+      # Only actually do things if not in dry run mode.
+      $opt_dry_run || {
+	# win32 will think the script is a binary if it has
+	# a .exe suffix, so we strip it off here.
+	case $output in
+	  *.exe) func_stripname '' '.exe' "$output"
+	         output=$func_stripname_result ;;
+	esac
+	# test for cygwin because mv fails w/o .exe extensions
+	case $host in
+	  *cygwin*)
+	    exeext=.exe
+	    func_stripname '' '.exe' "$outputname"
+	    outputname=$func_stripname_result ;;
+	  *) exeext= ;;
+	esac
+	case $host in
+	  *cygwin* | *mingw* )
+	    func_dirname_and_basename "$output" "" "."
+	    output_name=$func_basename_result
+	    output_path=$func_dirname_result
+	    cwrappersource="$output_path/$objdir/lt-$output_name.c"
+	    cwrapper="$output_path/$output_name.exe"
+	    $RM $cwrappersource $cwrapper
+	    trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+	    func_emit_cwrapperexe_src > $cwrappersource
+
+	    # The wrapper executable is built using the $host compiler,
+	    # because it contains $host paths and files. If cross-
+	    # compiling, it, like the target executable, must be
+	    # executed on the $host or under an emulation environment.
+	    $opt_dry_run || {
+	      $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
+	      $STRIP $cwrapper
+	    }
+
+	    # Now, create the wrapper script for func_source use:
+	    func_ltwrapper_scriptname $cwrapper
+	    $RM $func_ltwrapper_scriptname_result
+	    trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
+	    $opt_dry_run || {
+	      # note: this script will not be executed, so do not chmod.
+	      if test "x$build" = "x$host" ; then
+		$cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
+	      else
+		func_emit_wrapper no > $func_ltwrapper_scriptname_result
+	      fi
+	    }
+	  ;;
+	  * )
+	    $RM $output
+	    trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+	    func_emit_wrapper no > $output
+	    chmod +x $output
+	  ;;
+	esac
+      }
+      exit $EXIT_SUCCESS
+      ;;
+    esac
+
+    # See if we need to build an old-fashioned archive.
+    for oldlib in $oldlibs; do
+
+      if test "$build_libtool_libs" = convenience; then
+	oldobjs="$libobjs_save $symfileobj"
+	addlibs="$convenience"
+	build_libtool_libs=no
+      else
+	if test "$build_libtool_libs" = module; then
+	  oldobjs="$libobjs_save"
+	  build_libtool_libs=no
+	else
+	  oldobjs="$old_deplibs $non_pic_objects"
+	  if test "$preload" = yes && test -f "$symfileobj"; then
+	    func_append oldobjs " $symfileobj"
+	  fi
+	fi
+	addlibs="$old_convenience"
+      fi
+
+      if test -n "$addlibs"; then
+	gentop="$output_objdir/${outputname}x"
+	func_append generated " $gentop"
+
+	func_extract_archives $gentop $addlibs
+	func_append oldobjs " $func_extract_archives_result"
+      fi
+
+      # Do each command in the archive commands.
+      if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+	cmds=$old_archive_from_new_cmds
+      else
+
+	# Add any objects from preloaded convenience libraries
+	if test -n "$dlprefiles"; then
+	  gentop="$output_objdir/${outputname}x"
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $dlprefiles
+	  func_append oldobjs " $func_extract_archives_result"
+	fi
+
+	# POSIX demands no paths to be encoded in archives.  We have
+	# to avoid creating archives with duplicate basenames if we
+	# might have to extract them afterwards, e.g., when creating a
+	# static archive out of a convenience library, or when linking
+	# the entirety of a libtool archive into another (currently
+	# not supported by libtool).
+	if (for obj in $oldobjs
+	    do
+	      func_basename "$obj"
+	      $ECHO "$func_basename_result"
+	    done | sort | sort -uc >/dev/null 2>&1); then
+	  :
+	else
+	  echo "copying selected object files to avoid basename conflicts..."
+	  gentop="$output_objdir/${outputname}x"
+	  func_append generated " $gentop"
+	  func_mkdir_p "$gentop"
+	  save_oldobjs=$oldobjs
+	  oldobjs=
+	  counter=1
+	  for obj in $save_oldobjs
+	  do
+	    func_basename "$obj"
+	    objbase="$func_basename_result"
+	    case " $oldobjs " in
+	    " ") oldobjs=$obj ;;
+	    *[\ /]"$objbase "*)
+	      while :; do
+		# Make sure we don't pick an alternate name that also
+		# overlaps.
+		newobj=lt$counter-$objbase
+		func_arith $counter + 1
+		counter=$func_arith_result
+		case " $oldobjs " in
+		*[\ /]"$newobj "*) ;;
+		*) if test ! -f "$gentop/$newobj"; then break; fi ;;
+		esac
+	      done
+	      func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+	      func_append oldobjs " $gentop/$newobj"
+	      ;;
+	    *) func_append oldobjs " $obj" ;;
+	    esac
+	  done
+	fi
+	func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+	tool_oldlib=$func_to_tool_file_result
+	eval cmds=\"$old_archive_cmds\"
+
+	func_len " $cmds"
+	len=$func_len_result
+	if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  cmds=$old_archive_cmds
+	elif test -n "$archiver_list_spec"; then
+	  func_verbose "using command file archive linking..."
+	  for obj in $oldobjs
+	  do
+	    func_to_tool_file "$obj"
+	    $ECHO "$func_to_tool_file_result"
+	  done > $output_objdir/$libname.libcmd
+	  func_to_tool_file "$output_objdir/$libname.libcmd"
+	  oldobjs=" $archiver_list_spec$func_to_tool_file_result"
+	  cmds=$old_archive_cmds
+	else
+	  # the command line is too long to link in one step, link in parts
+	  func_verbose "using piecewise archive linking..."
+	  save_RANLIB=$RANLIB
+	  RANLIB=:
+	  objlist=
+	  concat_cmds=
+	  save_oldobjs=$oldobjs
+	  oldobjs=
+	  # Is there a better way of finding the last object in the list?
+	  for obj in $save_oldobjs
+	  do
+	    last_oldobj=$obj
+	  done
+	  eval test_cmds=\"$old_archive_cmds\"
+	  func_len " $test_cmds"
+	  len0=$func_len_result
+	  len=$len0
+	  for obj in $save_oldobjs
+	  do
+	    func_len " $obj"
+	    func_arith $len + $func_len_result
+	    len=$func_arith_result
+	    func_append objlist " $obj"
+	    if test "$len" -lt "$max_cmd_len"; then
+	      :
+	    else
+	      # the above command should be used before it gets too long
+	      oldobjs=$objlist
+	      if test "$obj" = "$last_oldobj" ; then
+		RANLIB=$save_RANLIB
+	      fi
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+	      objlist=
+	      len=$len0
+	    fi
+	  done
+	  RANLIB=$save_RANLIB
+	  oldobjs=$objlist
+	  if test "X$oldobjs" = "X" ; then
+	    eval cmds=\"\$concat_cmds\"
+	  else
+	    eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+	  fi
+	fi
+      fi
+      func_execute_cmds "$cmds" 'exit $?'
+    done
+
+    test -n "$generated" && \
+      func_show_eval "${RM}r$generated"
+
+    # Now create the libtool archive.
+    case $output in
+    *.la)
+      old_library=
+      test "$build_old_libs" = yes && old_library="$libname.$libext"
+      func_verbose "creating $output"
+
+      # Preserve any variables that may affect compiler behavior
+      for var in $variables_saved_for_relink; do
+	if eval test -z \"\${$var+set}\"; then
+	  relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+	elif eval var_value=\$$var; test -z "$var_value"; then
+	  relink_command="$var=; export $var; $relink_command"
+	else
+	  func_quote_for_eval "$var_value"
+	  relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+	fi
+      done
+      # Quote the link command for shipping.
+      relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+      relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      if test "$hardcode_automatic" = yes ; then
+	relink_command=
+      fi
+
+      # Only create the output if not a dry run.
+      $opt_dry_run || {
+	for installed in no yes; do
+	  if test "$installed" = yes; then
+	    if test -z "$install_libdir"; then
+	      break
+	    fi
+	    output="$output_objdir/$outputname"i
+	    # Replace all uninstalled libtool libraries with the installed ones
+	    newdependency_libs=
+	    for deplib in $dependency_libs; do
+	      case $deplib in
+	      *.la)
+		func_basename "$deplib"
+		name="$func_basename_result"
+		func_resolve_sysroot "$deplib"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$deplib' is not a valid libtool archive"
+		func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      -L*)
+		func_stripname -L '' "$deplib"
+		func_replace_sysroot "$func_stripname_result"
+		func_append newdependency_libs " -L$func_replace_sysroot_result"
+		;;
+	      -R*)
+		func_stripname -R '' "$deplib"
+		func_replace_sysroot "$func_stripname_result"
+		func_append newdependency_libs " -R$func_replace_sysroot_result"
+		;;
+	      *) func_append newdependency_libs " $deplib" ;;
+	      esac
+	    done
+	    dependency_libs="$newdependency_libs"
+	    newdlfiles=
+
+	    for lib in $dlfiles; do
+	      case $lib in
+	      *.la)
+	        func_basename "$lib"
+		name="$func_basename_result"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$lib' is not a valid libtool archive"
+		func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      *) func_append newdlfiles " $lib" ;;
+	      esac
+	    done
+	    dlfiles="$newdlfiles"
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+	      *.la)
+		# Only pass preopened files to the pseudo-archive (for
+		# eventual linking with the app. that links it) if we
+		# didn't already link the preopened objects directly into
+		# the library:
+		func_basename "$lib"
+		name="$func_basename_result"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$lib' is not a valid libtool archive"
+		func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      esac
+	    done
+	    dlprefiles="$newdlprefiles"
+	  else
+	    newdlfiles=
+	    for lib in $dlfiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      func_append newdlfiles " $abs"
+	    done
+	    dlfiles="$newdlfiles"
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      func_append newdlprefiles " $abs"
+	    done
+	    dlprefiles="$newdlprefiles"
+	  fi
+	  $RM $output
+	  # place dlname in correct position for cygwin
+	  # In fact, it would be nice if we could use this code for all target
+	  # systems that can't hard-code library paths into their executables
+	  # and that have no shared library path variable independent of PATH,
+	  # but it turns out we can't easily determine that from inspecting
+	  # libtool variables, so we have to hard-code the OSs to which it
+	  # applies here; at the moment, that means platforms that use the PE
+	  # object format with DLL files.  See the long comment at the top of
+	  # tests/bindir.at for full details.
+	  tdlname=$dlname
+	  case $host,$output,$installed,$module,$dlname in
+	    *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+	      # If a -bindir argument was supplied, place the dll there.
+	      if test "x$bindir" != x ;
+	      then
+		func_relative_path "$install_libdir" "$bindir"
+		tdlname=$func_relative_path_result$dlname
+	      else
+		# Otherwise fall back on heuristic.
+		tdlname=../bin/$dlname
+	      fi
+	      ;;
+	  esac
+	  $ECHO > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags='$new_inherited_linker_flags'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Names of additional weak libraries provided by this library
+weak_library_names='$weak_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+	  if test "$installed" = no && test "$need_relink" = yes; then
+	    $ECHO >> $output "\
+relink_command=\"$relink_command\""
+	  fi
+	done
+      }
+
+      # Do a symbolic link so that the libtool archive can be found in
+      # LD_LIBRARY_PATH before the program is installed.
+      func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
+      ;;
+    esac
+    exit $EXIT_SUCCESS
+}
+
+{ test "$opt_mode" = link || test "$opt_mode" = relink; } &&
+    func_mode_link ${1+"$@"}
+
+
+# func_mode_uninstall arg...
+func_mode_uninstall ()
+{
+    $opt_debug
+    RM="$nonopt"
+    files=
+    rmforce=
+    exit_status=0
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    for arg
+    do
+      case $arg in
+      -f) func_append RM " $arg"; rmforce=yes ;;
+      -*) func_append RM " $arg" ;;
+      *) func_append files " $arg" ;;
+      esac
+    done
+
+    test -z "$RM" && \
+      func_fatal_help "you must specify an RM program"
+
+    rmdirs=
+
+    for file in $files; do
+      func_dirname "$file" "" "."
+      dir="$func_dirname_result"
+      if test "X$dir" = X.; then
+	odir="$objdir"
+      else
+	odir="$dir/$objdir"
+      fi
+      func_basename "$file"
+      name="$func_basename_result"
+      test "$opt_mode" = uninstall && odir="$dir"
+
+      # Remember odir for removal later, being careful to avoid duplicates
+      if test "$opt_mode" = clean; then
+	case " $rmdirs " in
+	  *" $odir "*) ;;
+	  *) func_append rmdirs " $odir" ;;
+	esac
+      fi
+
+      # Don't error if the file doesn't exist and rm -f was used.
+      if { test -L "$file"; } >/dev/null 2>&1 ||
+	 { test -h "$file"; } >/dev/null 2>&1 ||
+	 test -f "$file"; then
+	:
+      elif test -d "$file"; then
+	exit_status=1
+	continue
+      elif test "$rmforce" = yes; then
+	continue
+      fi
+
+      rmfiles="$file"
+
+      case $name in
+      *.la)
+	# Possibly a libtool archive, so verify it.
+	if func_lalib_p "$file"; then
+	  func_source $dir/$name
+
+	  # Delete the libtool libraries and symlinks.
+	  for n in $library_names; do
+	    func_append rmfiles " $odir/$n"
+	  done
+	  test -n "$old_library" && func_append rmfiles " $odir/$old_library"
+
+	  case "$opt_mode" in
+	  clean)
+	    case " $library_names " in
+	    *" $dlname "*) ;;
+	    *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;;
+	    esac
+	    test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i"
+	    ;;
+	  uninstall)
+	    if test -n "$library_names"; then
+	      # Do each command in the postuninstall commands.
+	      func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+	    fi
+
+	    if test -n "$old_library"; then
+	      # Do each command in the old_postuninstall commands.
+	      func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+	    fi
+	    # FIXME: should reinstall the best remaining shared library.
+	    ;;
+	  esac
+	fi
+	;;
+
+      *.lo)
+	# Possibly a libtool object, so verify it.
+	if func_lalib_p "$file"; then
+
+	  # Read the .lo file
+	  func_source $dir/$name
+
+	  # Add PIC object to the list of files to remove.
+	  if test -n "$pic_object" &&
+	     test "$pic_object" != none; then
+	    func_append rmfiles " $dir/$pic_object"
+	  fi
+
+	  # Add non-PIC object to the list of files to remove.
+	  if test -n "$non_pic_object" &&
+	     test "$non_pic_object" != none; then
+	    func_append rmfiles " $dir/$non_pic_object"
+	  fi
+	fi
+	;;
+
+      *)
+	if test "$opt_mode" = clean ; then
+	  noexename=$name
+	  case $file in
+	  *.exe)
+	    func_stripname '' '.exe' "$file"
+	    file=$func_stripname_result
+	    func_stripname '' '.exe' "$name"
+	    noexename=$func_stripname_result
+	    # $file with .exe has already been added to rmfiles,
+	    # add $file without .exe
+	    func_append rmfiles " $file"
+	    ;;
+	  esac
+	  # Do a test to see if this is a libtool program.
+	  if func_ltwrapper_p "$file"; then
+	    if func_ltwrapper_executable_p "$file"; then
+	      func_ltwrapper_scriptname "$file"
+	      relink_command=
+	      func_source $func_ltwrapper_scriptname_result
+	      func_append rmfiles " $func_ltwrapper_scriptname_result"
+	    else
+	      relink_command=
+	      func_source $dir/$noexename
+	    fi
+
+	    # note $name still contains .exe if it was in $file originally
+	    # as does the version of $file that was added into $rmfiles
+	    func_append rmfiles " $odir/$name $odir/${name}S.${objext}"
+	    if test "$fast_install" = yes && test -n "$relink_command"; then
+	      func_append rmfiles " $odir/lt-$name"
+	    fi
+	    if test "X$noexename" != "X$name" ; then
+	      func_append rmfiles " $odir/lt-${noexename}.c"
+	    fi
+	  fi
+	fi
+	;;
+      esac
+      func_show_eval "$RM $rmfiles" 'exit_status=1'
+    done
+
+    # Try to remove the ${objdir}s in the directories where we deleted files
+    for dir in $rmdirs; do
+      if test -d "$dir"; then
+	func_show_eval "rmdir $dir >/dev/null 2>&1"
+      fi
+    done
+
+    exit $exit_status
+}
+
+{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } &&
+    func_mode_uninstall ${1+"$@"}
+
+test -z "$opt_mode" && {
+  help="$generic_help"
+  func_fatal_help "you must specify a MODE"
+}
+
+test -z "$exec_cmd" && \
+  func_fatal_help "invalid operation mode \`$opt_mode'"
+
+if test -n "$exec_cmd"; then
+  eval exec "$exec_cmd"
+  exit $EXIT_FAILURE
+fi
+
+exit $exit_status
+
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries.  Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them.  This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration.  But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
+# vi:sw=2
+
diff --git a/source/Irrlicht/jpeglib/makcjpeg.st b/source/Irrlicht/jpeglib/makcjpeg.st
new file mode 100644
index 00000000..628f5335
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makcjpeg.st
@@ -0,0 +1,36 @@
+; Project file for Independent JPEG Group's software
+;
+; This project file is for Atari ST/STE/TT systems using Pure C or Turbo C.
+; Thanks to Frank Moehle, B. Setzepfandt, and Guido Vollbeding.
+;
+; To use this file, rename it to cjpeg.prj.
+; If you are using Turbo C, change filenames beginning with "pc..." to "tc..."
+; Read installation instructions before trying to make the program!
+;
+;
+;      * * * Output file * * *
+cjpeg.ttp
+;
+; * * * COMPILER OPTIONS * * *  
+.C[-P]        ; absolute calls
+.C[-M]        ; and no string merging, folks
+.C[-w-cln]    ; no "constant is long" warnings
+.C[-w-par]    ; no "parameter xxxx unused"
+.C[-w-rch]    ; no "unreachable code"
+.C[-wsig]     ; warn if significant digits may be lost
+=
+; * * * * List of modules * * * * 
+pcstart.o
+cjpeg.c		(cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h,jversion.h)
+cdjpeg.c	(cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdswitch.c	(cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdppm.c		(cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdgif.c		(cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdtarga.c	(cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdbmp.c		(cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdrle.c		(cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+libjpeg.lib        ; built by libjpeg.prj
+pcfltlib.lib       ; floating point library
+; the float library can be omitted if you've turned off DCT_FLOAT_SUPPORTED
+pcstdlib.lib       ; standard library
+pcextlib.lib       ; extended library
diff --git a/source/Irrlicht/jpeglib/makdjpeg.st b/source/Irrlicht/jpeglib/makdjpeg.st
new file mode 100644
index 00000000..4b61404a
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makdjpeg.st
@@ -0,0 +1,36 @@
+; Project file for Independent JPEG Group's software
+;
+; This project file is for Atari ST/STE/TT systems using Pure C or Turbo C.
+; Thanks to Frank Moehle, B. Setzepfandt, and Guido Vollbeding.
+;
+; To use this file, rename it to djpeg.prj.
+; If you are using Turbo C, change filenames beginning with "pc..." to "tc..."
+; Read installation instructions before trying to make the program!
+;
+;
+;      * * * Output file * * *
+djpeg.ttp
+;
+; * * * COMPILER OPTIONS * * *  
+.C[-P]        ; absolute calls
+.C[-M]        ; and no string merging, folks
+.C[-w-cln]    ; no "constant is long" warnings
+.C[-w-par]    ; no "parameter xxxx unused"
+.C[-w-rch]    ; no "unreachable code"
+.C[-wsig]     ; warn if significant digits may be lost
+=
+; * * * * List of modules * * * * 
+pcstart.o
+djpeg.c		(cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h,jversion.h)
+cdjpeg.c	(cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdcolmap.c	(cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+wrppm.c		(cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+wrgif.c		(cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+wrtarga.c	(cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+wrbmp.c		(cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+wrrle.c		(cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+libjpeg.lib        ; built by libjpeg.prj
+pcfltlib.lib       ; floating point library
+; the float library can be omitted if you've turned off DCT_FLOAT_SUPPORTED
+pcstdlib.lib       ; standard library
+pcextlib.lib       ; extended library
diff --git a/source/Irrlicht/jpeglib/makeadsw.vc6 b/source/Irrlicht/jpeglib/makeadsw.vc6
new file mode 100644
index 00000000..80459c53
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makeadsw.vc6
@@ -0,0 +1,77 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNUNG: DIESE ARBEITSBEREICHSDATEI DARF NICHT BEARBEITET ODER GELSCHT WERDEN!
+
+###############################################################################
+
+Project: "cjpeg"=".\cjpeg.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "djpeg"=".\djpeg.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "jpegtran"=".\jpegtran.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "rdjpgcom"=".\rdjpgcom.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "wrjpgcom"=".\wrjpgcom.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/source/Irrlicht/jpeglib/makeasln.v10 b/source/Irrlicht/jpeglib/makeasln.v10
new file mode 100644
index 00000000..617d9e94
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makeasln.v10
@@ -0,0 +1,33 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual C++ Express 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cjpeg", "cjpeg.vcxproj", "{2E7FAAD9-2F58-4BDE-81F2-1D6D3FB8BF57}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "djpeg", "djpeg.vcxproj", "{11043137-B453-4DFA-9010-4D2B9DC1545C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jpegtran", "jpegtran.vcxproj", "{025BAC50-51B5-4FFE-BC47-3F920BB4047E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rdjpgcom", "rdjpgcom.vcxproj", "{C81513DB-78DC-46BC-BC98-82E745203976}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wrjpgcom", "wrjpgcom.vcxproj", "{B57065D4-DDDA-4668-BAF5-2D49270C973C}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{2E7FAAD9-2F58-4BDE-81F2-1D6D3FB8BF57}.Release|Win32.ActiveCfg = Release|Win32
+		{2E7FAAD9-2F58-4BDE-81F2-1D6D3FB8BF57}.Release|Win32.Build.0 = Release|Win32
+		{11043137-B453-4DFA-9010-4D2B9DC1545C}.Release|Win32.ActiveCfg = Release|Win32
+		{11043137-B453-4DFA-9010-4D2B9DC1545C}.Release|Win32.Build.0 = Release|Win32
+		{025BAC50-51B5-4FFE-BC47-3F920BB4047E}.Release|Win32.ActiveCfg = Release|Win32
+		{025BAC50-51B5-4FFE-BC47-3F920BB4047E}.Release|Win32.Build.0 = Release|Win32
+		{C81513DB-78DC-46BC-BC98-82E745203976}.Release|Win32.ActiveCfg = Release|Win32
+		{C81513DB-78DC-46BC-BC98-82E745203976}.Release|Win32.Build.0 = Release|Win32
+		{B57065D4-DDDA-4668-BAF5-2D49270C973C}.Release|Win32.ActiveCfg = Release|Win32
+		{B57065D4-DDDA-4668-BAF5-2D49270C973C}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/source/Irrlicht/jpeglib/makecdep.vc6 b/source/Irrlicht/jpeglib/makecdep.vc6
new file mode 100644
index 00000000..11dff777
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makecdep.vc6
@@ -0,0 +1,82 @@
+# Microsoft Developer Studio erstellte Abhngigkeitsdatei, einbezogen von cjpeg.mak
+
+.\cdjpeg.c : \
+	".\cderror.h"\
+	".\cdjpeg.h"\
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	
+
+.\cjpeg.c : \
+	".\cderror.h"\
+	".\cdjpeg.h"\
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	".\jversion.h"\
+	
+
+.\rdbmp.c : \
+	".\cderror.h"\
+	".\cdjpeg.h"\
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	
+
+.\rdgif.c : \
+	".\cderror.h"\
+	".\cdjpeg.h"\
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	
+
+.\rdppm.c : \
+	".\cderror.h"\
+	".\cdjpeg.h"\
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	
+
+.\rdrle.c : \
+	".\cderror.h"\
+	".\cdjpeg.h"\
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	
+
+.\rdswitch.c : \
+	".\cderror.h"\
+	".\cdjpeg.h"\
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	
+
+.\rdtarga.c : \
+	".\cderror.h"\
+	".\cdjpeg.h"\
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	
diff --git a/source/Irrlicht/jpeglib/makecdsp.vc6 b/source/Irrlicht/jpeglib/makecdsp.vc6
new file mode 100644
index 00000000..3ab59651
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makecdsp.vc6
@@ -0,0 +1,130 @@
+# Microsoft Developer Studio Project File - Name="cjpeg" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** NICHT BEARBEITEN **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=cjpeg - Win32
+!MESSAGE Dies ist kein gltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und fhren Sie den Befehl
+!MESSAGE 
+!MESSAGE NMAKE /f "cjpeg.mak".
+!MESSAGE 
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE 
+!MESSAGE NMAKE /f "cjpeg.mak" CFG="cjpeg - Win32"
+!MESSAGE 
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE 
+!MESSAGE "cjpeg - Win32" (basierend auf  "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\cjpeg\Release"
+# PROP BASE Intermediate_Dir ".\cjpeg\Release"
+# PROP BASE Target_Dir ".\cjpeg"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\cjpeg\Release"
+# PROP Intermediate_Dir ".\cjpeg\Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ".\cjpeg"
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# Begin Target
+
+# Name "cjpeg - Win32"
+# Begin Group "Quellcodedateien"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\cdjpeg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\cjpeg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rdbmp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rdgif.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rdppm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rdrle.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rdswitch.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rdtarga.c
+# End Source File
+# End Group
+# Begin Group "Header-Dateien"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\cderror.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\cdjpeg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jconfig.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jerror.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jinclude.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jmorecfg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jpeglib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jversion.h
+# End Source File
+# End Group
+# Begin Group "Ressourcendateien"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/source/Irrlicht/jpeglib/makecfil.v10 b/source/Irrlicht/jpeglib/makecfil.v10
new file mode 100644
index 00000000..a4f81ac3
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makecfil.v10
@@ -0,0 +1,69 @@
+
+
+  
+    
+      {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+      cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+    
+    
+      {93995380-89BD-4b04-88EB-625FBE52EBFB}
+      h;hpp;hxx;hm;inl;inc;xsd
+    
+    
+      {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+      rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+    
+  
+  
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+  
+  
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+  
+
\ No newline at end of file
diff --git a/source/Irrlicht/jpeglib/makecmak.vc6 b/source/Irrlicht/jpeglib/makecmak.vc6
new file mode 100644
index 00000000..bee03bf9
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makecmak.vc6
@@ -0,0 +1,159 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on cjpeg.dsp
+!IF "$(CFG)" == ""
+CFG=cjpeg - Win32
+!MESSAGE Keine Konfiguration angegeben. cjpeg - Win32 wird als Standard verwendet.
+!ENDIF 
+
+!IF "$(CFG)" != "cjpeg - Win32"
+!MESSAGE Ungltige Konfiguration "$(CFG)" angegeben.
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE 
+!MESSAGE NMAKE /f "cjpeg.mak" CFG="cjpeg - Win32"
+!MESSAGE 
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE 
+!MESSAGE "cjpeg - Win32" (basierend auf  "Win32 (x86) Console Application")
+!MESSAGE 
+!ERROR Eine ungltige Konfiguration wurde angegeben.
+!ENDIF 
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE 
+NULL=nul
+!ENDIF 
+
+CPP=cl.exe
+RSC=rc.exe
+OUTDIR=.\cjpeg\Release
+INTDIR=.\cjpeg\Release
+# Begin Custom Macros
+OutDir=.\cjpeg\Release
+# End Custom Macros
+
+ALL : "$(OUTDIR)\cjpeg.exe"
+
+
+CLEAN :
+	-@erase "$(INTDIR)\cdjpeg.obj"
+	-@erase "$(INTDIR)\cjpeg.obj"
+	-@erase "$(INTDIR)\rdbmp.obj"
+	-@erase "$(INTDIR)\rdgif.obj"
+	-@erase "$(INTDIR)\rdppm.obj"
+	-@erase "$(INTDIR)\rdrle.obj"
+	-@erase "$(INTDIR)\rdswitch.obj"
+	-@erase "$(INTDIR)\rdtarga.obj"
+	-@erase "$(INTDIR)\vc60.idb"
+	-@erase "$(OUTDIR)\cjpeg.exe"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\cjpeg.bsc" 
+BSC32_SBRS= \
+	
+LINK32=link.exe
+LINK32_FLAGS=Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\cjpeg.pdb" /machine:I386 /out:"$(OUTDIR)\cjpeg.exe" 
+LINK32_OBJS= \
+	"$(INTDIR)\cdjpeg.obj" \
+	"$(INTDIR)\cjpeg.obj" \
+	"$(INTDIR)\rdbmp.obj" \
+	"$(INTDIR)\rdgif.obj" \
+	"$(INTDIR)\rdppm.obj" \
+	"$(INTDIR)\rdrle.obj" \
+	"$(INTDIR)\rdswitch.obj" \
+	"$(INTDIR)\rdtarga.obj"
+
+"$(OUTDIR)\cjpeg.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+CPP_PROJ=/nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /Fp"$(INTDIR)\cjpeg.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 
+
+.c{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.c{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("cjpeg.dep")
+!INCLUDE "cjpeg.dep"
+!ELSE 
+!MESSAGE Warning: cannot find "cjpeg.dep"
+!ENDIF 
+!ENDIF 
+
+
+!IF "$(CFG)" == "cjpeg - Win32"
+SOURCE=.\cdjpeg.c
+
+"$(INTDIR)\cdjpeg.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\cjpeg.c
+
+"$(INTDIR)\cjpeg.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\rdbmp.c
+
+"$(INTDIR)\rdbmp.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\rdgif.c
+
+"$(INTDIR)\rdgif.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\rdppm.c
+
+"$(INTDIR)\rdppm.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\rdrle.c
+
+"$(INTDIR)\rdrle.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\rdswitch.c
+
+"$(INTDIR)\rdswitch.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\rdtarga.c
+
+"$(INTDIR)\rdtarga.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF 
+
diff --git a/source/Irrlicht/jpeglib/makecvcx.v10 b/source/Irrlicht/jpeglib/makecvcx.v10
new file mode 100644
index 00000000..5df5c68f
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makecvcx.v10
@@ -0,0 +1,76 @@
+
+
+  
+    
+      Release
+      Win32
+    
+  
+  
+    {2E7FAAD9-2F58-4BDE-81F2-1D6D3FB8BF57}
+    Win32Proj
+    cjpeg
+  
+  
+  
+    Application
+    false
+    true
+    Unicode
+  
+  
+  
+  
+  
+    
+  
+  
+  
+    false
+    $(ProjectName)\$(Configuration)\
+    $(ProjectName)\$(Configuration)\
+  
+  
+    
+      Level3
+      NotUsing
+      Full
+      true
+      false
+      WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS
+      true
+      true
+      4996
+    
+    
+      Console
+      true
+      true
+      true
+      Release\jpeg.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+    
+  
+  
+    
+    
+    
+    
+    
+    
+    
+    
+  
+  
+    
+    
+    
+    
+    
+    
+    
+    
+  
+  
+  
+  
+
\ No newline at end of file
diff --git a/source/Irrlicht/jpeglib/makeddep.vc6 b/source/Irrlicht/jpeglib/makeddep.vc6
new file mode 100644
index 00000000..f911eba7
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makeddep.vc6
@@ -0,0 +1,82 @@
+# Microsoft Developer Studio erstellte Abhngigkeitsdatei, einbezogen von djpeg.mak
+
+.\cdjpeg.c : \
+	".\cderror.h"\
+	".\cdjpeg.h"\
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	
+
+.\djpeg.c : \
+	".\cderror.h"\
+	".\cdjpeg.h"\
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	".\jversion.h"\
+	
+
+.\rdcolmap.c : \
+	".\cderror.h"\
+	".\cdjpeg.h"\
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	
+
+.\wrbmp.c : \
+	".\cderror.h"\
+	".\cdjpeg.h"\
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	
+
+.\wrgif.c : \
+	".\cderror.h"\
+	".\cdjpeg.h"\
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	
+
+.\wrppm.c : \
+	".\cderror.h"\
+	".\cdjpeg.h"\
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	
+
+.\wrrle.c : \
+	".\cderror.h"\
+	".\cdjpeg.h"\
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	
+
+.\wrtarga.c : \
+	".\cderror.h"\
+	".\cdjpeg.h"\
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	
diff --git a/source/Irrlicht/jpeglib/makeddsp.vc6 b/source/Irrlicht/jpeglib/makeddsp.vc6
new file mode 100644
index 00000000..f583a0f6
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makeddsp.vc6
@@ -0,0 +1,130 @@
+# Microsoft Developer Studio Project File - Name="djpeg" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** NICHT BEARBEITEN **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=djpeg - Win32
+!MESSAGE Dies ist kein gltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und fhren Sie den Befehl
+!MESSAGE 
+!MESSAGE NMAKE /f "djpeg.mak".
+!MESSAGE 
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE 
+!MESSAGE NMAKE /f "djpeg.mak" CFG="djpeg - Win32"
+!MESSAGE 
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE 
+!MESSAGE "djpeg - Win32" (basierend auf  "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\djpeg\Release"
+# PROP BASE Intermediate_Dir ".\djpeg\Release"
+# PROP BASE Target_Dir ".\djpeg"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\djpeg\Release"
+# PROP Intermediate_Dir ".\djpeg\Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ".\djpeg"
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# Begin Target
+
+# Name "djpeg - Win32"
+# Begin Group "Quellcodedateien"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\cdjpeg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\djpeg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rdcolmap.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\wrbmp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\wrgif.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\wrppm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\wrrle.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\wrtarga.c
+# End Source File
+# End Group
+# Begin Group "Header-Dateien"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\cderror.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\cdjpeg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jconfig.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jerror.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jinclude.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jmorecfg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jpeglib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jversion.h
+# End Source File
+# End Group
+# Begin Group "Ressourcendateien"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/source/Irrlicht/jpeglib/makedfil.v10 b/source/Irrlicht/jpeglib/makedfil.v10
new file mode 100644
index 00000000..b4a83abf
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makedfil.v10
@@ -0,0 +1,69 @@
+
+
+  
+    
+      {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+      cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+    
+    
+      {93995380-89BD-4b04-88EB-625FBE52EBFB}
+      h;hpp;hxx;hm;inl;inc;xsd
+    
+    
+      {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+      rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+    
+  
+  
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+  
+  
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+  
+
\ No newline at end of file
diff --git a/source/Irrlicht/jpeglib/makedmak.vc6 b/source/Irrlicht/jpeglib/makedmak.vc6
new file mode 100644
index 00000000..e16487ff
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makedmak.vc6
@@ -0,0 +1,159 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on djpeg.dsp
+!IF "$(CFG)" == ""
+CFG=djpeg - Win32
+!MESSAGE Keine Konfiguration angegeben. djpeg - Win32 wird als Standard verwendet.
+!ENDIF 
+
+!IF "$(CFG)" != "djpeg - Win32"
+!MESSAGE Ungltige Konfiguration "$(CFG)" angegeben.
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE 
+!MESSAGE NMAKE /f "djpeg.mak" CFG="djpeg - Win32"
+!MESSAGE 
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE 
+!MESSAGE "djpeg - Win32" (basierend auf  "Win32 (x86) Console Application")
+!MESSAGE 
+!ERROR Eine ungltige Konfiguration wurde angegeben.
+!ENDIF 
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE 
+NULL=nul
+!ENDIF 
+
+CPP=cl.exe
+RSC=rc.exe
+OUTDIR=.\djpeg\Release
+INTDIR=.\djpeg\Release
+# Begin Custom Macros
+OutDir=.\djpeg\Release
+# End Custom Macros
+
+ALL : "$(OUTDIR)\djpeg.exe"
+
+
+CLEAN :
+	-@erase "$(INTDIR)\cdjpeg.obj"
+	-@erase "$(INTDIR)\djpeg.obj"
+	-@erase "$(INTDIR)\rdcolmap.obj"
+	-@erase "$(INTDIR)\vc60.idb"
+	-@erase "$(INTDIR)\wrbmp.obj"
+	-@erase "$(INTDIR)\wrgif.obj"
+	-@erase "$(INTDIR)\wrppm.obj"
+	-@erase "$(INTDIR)\wrrle.obj"
+	-@erase "$(INTDIR)\wrtarga.obj"
+	-@erase "$(OUTDIR)\djpeg.exe"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\djpeg.bsc" 
+BSC32_SBRS= \
+	
+LINK32=link.exe
+LINK32_FLAGS=Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\djpeg.pdb" /machine:I386 /out:"$(OUTDIR)\djpeg.exe" 
+LINK32_OBJS= \
+	"$(INTDIR)\cdjpeg.obj" \
+	"$(INTDIR)\djpeg.obj" \
+	"$(INTDIR)\rdcolmap.obj" \
+	"$(INTDIR)\wrbmp.obj" \
+	"$(INTDIR)\wrgif.obj" \
+	"$(INTDIR)\wrppm.obj" \
+	"$(INTDIR)\wrrle.obj" \
+	"$(INTDIR)\wrtarga.obj"
+
+"$(OUTDIR)\djpeg.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+CPP_PROJ=/nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /Fp"$(INTDIR)\djpeg.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 
+
+.c{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.c{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("djpeg.dep")
+!INCLUDE "djpeg.dep"
+!ELSE 
+!MESSAGE Warning: cannot find "djpeg.dep"
+!ENDIF 
+!ENDIF 
+
+
+!IF "$(CFG)" == "djpeg - Win32"
+SOURCE=.\cdjpeg.c
+
+"$(INTDIR)\cdjpeg.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\djpeg.c
+
+"$(INTDIR)\djpeg.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\rdcolmap.c
+
+"$(INTDIR)\rdcolmap.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\wrbmp.c
+
+"$(INTDIR)\wrbmp.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\wrgif.c
+
+"$(INTDIR)\wrgif.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\wrppm.c
+
+"$(INTDIR)\wrppm.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\wrrle.c
+
+"$(INTDIR)\wrrle.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\wrtarga.c
+
+"$(INTDIR)\wrtarga.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF 
+
diff --git a/source/Irrlicht/jpeglib/makedvcx.v10 b/source/Irrlicht/jpeglib/makedvcx.v10
new file mode 100644
index 00000000..9ad2d413
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makedvcx.v10
@@ -0,0 +1,76 @@
+
+
+  
+    
+      Release
+      Win32
+    
+  
+  
+    {11043137-B453-4DFA-9010-4D2B9DC1545C}
+    Win32Proj
+    djpeg
+  
+  
+  
+    Application
+    false
+    true
+    Unicode
+  
+  
+  
+  
+  
+    
+  
+  
+  
+    false
+    $(ProjectName)\$(Configuration)\
+    $(ProjectName)\$(Configuration)\
+  
+  
+    
+      Level3
+      NotUsing
+      Full
+      true
+      false
+      WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS
+      true
+      true
+      4996
+    
+    
+      Console
+      true
+      true
+      true
+      Release\jpeg.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+    
+  
+  
+    
+    
+    
+    
+    
+    
+    
+    
+  
+  
+    
+    
+    
+    
+    
+    
+    
+    
+  
+  
+  
+  
+
\ No newline at end of file
diff --git a/source/Irrlicht/jpeglib/makefile.ansi b/source/Irrlicht/jpeglib/makefile.ansi
new file mode 100644
index 00000000..c0fe72b1
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makefile.ansi
@@ -0,0 +1,221 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is suitable for Unix-like systems with ANSI-capable compilers.
+# If you have a non-ANSI compiler, makefile.unix is a better starting point.
+
+# Read installation instructions before saying "make" !!
+
+# The name of your C compiler:
+CC= cc
+
+# You may need to adjust these cc options:
+CFLAGS= -O
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+
+# Link-time cc options:
+LDFLAGS= 
+
+# To link any special libraries, add the necessary -l commands here.
+LDLIBS= 
+
+# Put here the object file name for the correct system-dependent memory
+# manager file.  For Unix this is usually jmemnobs.o, but you may want
+# to use jmemansi.o or jmemname.o if you have limited swap space.
+SYSDEPMEM= jmemnobs.o
+
+# miscellaneous OS-dependent stuff
+# linker
+LN= $(CC)
+# file deletion command
+RM= rm -f
+# library (.a) file creation command
+AR= ar rc
+# second step in .a creation (use "touch" if not needed)
+AR2= ranlib
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+        jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+        jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+        jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+        jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+        jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+        jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+        jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \
+        rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \
+        rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h \
+        jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
+# documentation, test, and support files
+DOCS= README install.txt usage.txt cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+        wrjpgcom.1 wizard.txt example.c libjpeg.txt structure.txt \
+        coderules.txt filelist.txt change.log
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+        makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+        makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+        makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+        maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+        makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+        makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+        makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+        makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+        makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+        makefile.mms makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+        jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+        jconfig.vms
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp \
+        missing ar-lib
+OTHERFILES= jconfig.txt ckconfig.c jmemdosa.asm libjpeg.map
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+        testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+        $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jaricom.o jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.o jcapistd.o jcarith.o jctrans.o jcparam.o \
+        jdatadst.o jcinit.o jcmaster.o jcmarker.o jcmainct.o jcprepct.o \
+        jccoefct.o jccolor.o jcsample.o jchuff.o jcdctmgr.o jfdctfst.o \
+        jfdctflt.o jfdctint.o
+# decompression library object files
+DLIBOBJECTS= jdapimin.o jdapistd.o jdarith.o jdtrans.o jdatasrc.o \
+        jdmaster.o jdinput.o jdmarker.o jdhuff.o jdmainct.o \
+        jdcoefct.o jdpostct.o jddctmgr.o jidctfst.o jidctflt.o \
+        jidctint.o jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o
+# These objectfiles are included in libjpeg.a
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \
+        cdjpeg.o
+DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \
+        cdjpeg.o
+TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o transupp.o
+
+
+all: libjpeg.a cjpeg djpeg jpegtran rdjpgcom wrjpgcom
+
+libjpeg.a: $(LIBOBJECTS)
+	$(RM) libjpeg.a
+	$(AR) libjpeg.a  $(LIBOBJECTS)
+	$(AR2) libjpeg.a
+
+cjpeg: $(COBJECTS) libjpeg.a
+	$(LN) $(LDFLAGS) -o cjpeg $(COBJECTS) libjpeg.a $(LDLIBS)
+
+djpeg: $(DOBJECTS) libjpeg.a
+	$(LN) $(LDFLAGS) -o djpeg $(DOBJECTS) libjpeg.a $(LDLIBS)
+
+jpegtran: $(TROBJECTS) libjpeg.a
+	$(LN) $(LDFLAGS) -o jpegtran $(TROBJECTS) libjpeg.a $(LDLIBS)
+
+rdjpgcom: rdjpgcom.o
+	$(LN) $(LDFLAGS) -o rdjpgcom rdjpgcom.o $(LDLIBS)
+
+wrjpgcom: wrjpgcom.o
+	$(LN) $(LDFLAGS) -o wrjpgcom wrjpgcom.o $(LDLIBS)
+
+jconfig.h: jconfig.txt
+	echo You must prepare a system-dependent jconfig.h file.
+	echo Please read the installation directions in install.txt.
+	exit 1
+
+clean:
+	$(RM) *.o cjpeg djpeg jpegtran libjpeg.a rdjpgcom wrjpgcom
+	$(RM) core testout*
+
+test: cjpeg djpeg jpegtran
+	$(RM) testout*
+	./djpeg -dct int -ppm -outfile testout.ppm  testorig.jpg
+	./djpeg -dct int -bmp -colors 256 -outfile testout.bmp  testorig.jpg
+	./cjpeg -dct int -outfile testout.jpg  testimg.ppm
+	./djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+	./cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+	./jpegtran -outfile testoutt.jpg testprog.jpg
+	cmp testimg.ppm testout.ppm
+	cmp testimg.bmp testout.bmp
+	cmp testimg.jpg testout.jpg
+	cmp testimg.ppm testoutp.ppm
+	cmp testimgp.jpg testoutp.jpg
+	cmp testorig.jpg testoutt.jpg
+
+
+jaricom.o: jaricom.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapimin.o: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.o: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcarith.o: jcarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.o: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.o: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.o: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.o: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcinit.o: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.o: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.o: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.o: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.o: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.o: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcprepct.o: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.o: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.o: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.o: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.o: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdarith.o: jdarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.o: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.o: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.o: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.o: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.o: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.o: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdinput.o: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.o: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.o: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.o: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.o: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdpostct.o: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.o: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.o: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.o: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.o: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.o: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.o: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.o: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.o: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.o: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.o: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.o: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.o: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.o: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.o: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.o: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.o: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.o: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.o: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.o: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.o: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.o: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h
+rdjpgcom.o: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.o: wrjpgcom.c jinclude.h jconfig.h
+cdjpeg.o: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.o: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.o: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+transupp.o: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h
+rdppm.o: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.o: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.o: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.o: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.o: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.o: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.o: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.o: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.o: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.o: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/source/Irrlicht/jpeglib/makefile.bcc b/source/Irrlicht/jpeglib/makefile.bcc
new file mode 100644
index 00000000..68d68ef0
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makefile.bcc
@@ -0,0 +1,292 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is suitable for Borland C on MS-DOS or OS/2.
+# It works with Borland C++ for DOS, revision 3.0 or later,
+# and has been tested with Borland C++ for OS/2.
+# Watch out for optimization bugs in the OS/2 compilers --- see notes below!
+# Thanks to Tom Wright and Ge' Weijers (original DOS) and
+# Ken Porter (OS/2) for this file.
+
+# Read installation instructions before saying "make" !!
+
+# Are we under DOS or OS/2?
+!if !$d(DOS) && !$d(OS2)
+!if $d(__OS2__)
+OS2=1
+!else
+DOS=1
+!endif
+!endif
+
+# The name of your C compiler:
+CC= bcc
+
+# You may need to adjust these cc options:
+!if $d(DOS)
+CFLAGS= -O2 -mm -w-par -w-stu -w-ccc -w-rch
+!else
+CFLAGS= -O1 -w-par -w-stu -w-ccc -w-rch
+!endif
+# -O2 enables full code optimization (for pre-3.0 Borland C++, use -O -G -Z).
+# -O2 is buggy in Borland OS/2 C++ revision 2.0, so use -O1 there for now.
+# If you have Borland OS/2 C++ revision 1.0, use -O or no optimization at all.
+# -mm selects medium memory model (near data, far code pointers; DOS only!)
+# -w-par suppresses warnings about unused function parameters
+# -w-stu suppresses warnings about incomplete structures
+# -w-ccc suppresses warnings about compile-time-constant conditions
+# -w-rch suppresses warnings about unreachable code
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+
+# Link-time cc options:
+!if $d(DOS)
+LDFLAGS= -mm
+# memory model option here must match CFLAGS!
+!else
+LDFLAGS=
+# -lai full-screen app
+# -lc case-significant link
+!endif
+
+# Put here the object file name for the correct system-dependent memory
+# manager file.
+# For DOS, we recommend jmemdos.c and jmemdosa.asm.
+# For OS/2, we recommend jmemnobs.c (flat memory!)
+# SYSDEPMEMLIB must list the same files with "+" signs for the librarian.
+!if $d(DOS)
+SYSDEPMEM= jmemdos.obj jmemdosa.obj
+SYSDEPMEMLIB= +jmemdos.obj +jmemdosa.obj
+!else
+SYSDEPMEM= jmemnobs.obj
+SYSDEPMEMLIB= +jmemnobs.obj
+!endif
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+        jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+        jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+        jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+        jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+        jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+        jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+        jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \
+        rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \
+        rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h \
+        jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
+# documentation, test, and support files
+DOCS= README install.txt usage.txt cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+        wrjpgcom.1 wizard.txt example.c libjpeg.txt structure.txt \
+        coderules.txt filelist.txt change.log
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+        makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+        makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+        makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+        maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+        makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+        makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+        makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+        makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+        makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+        makefile.mms makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+        jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+        jconfig.vms
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp \
+        missing ar-lib
+OTHERFILES= jconfig.txt ckconfig.c jmemdosa.asm libjpeg.map
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+        testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+        $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jaricom.obj jcomapi.obj jutils.obj jerror.obj jmemmgr.obj $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.obj jcapistd.obj jcarith.obj jctrans.obj jcparam.obj \
+        jdatadst.obj jcinit.obj jcmaster.obj jcmarker.obj jcmainct.obj \
+        jcprepct.obj jccoefct.obj jccolor.obj jcsample.obj jchuff.obj \
+        jcdctmgr.obj jfdctfst.obj jfdctflt.obj jfdctint.obj
+# decompression library object files
+DLIBOBJECTS= jdapimin.obj jdapistd.obj jdarith.obj jdtrans.obj jdatasrc.obj \
+        jdmaster.obj jdinput.obj jdmarker.obj jdhuff.obj jdmainct.obj \
+        jdcoefct.obj jdpostct.obj jddctmgr.obj jidctfst.obj jidctflt.obj \
+        jidctint.obj jdsample.obj jdcolor.obj jquant1.obj jquant2.obj \
+        jdmerge.obj
+# These objectfiles are included in libjpeg.lib
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.obj rdppm.obj rdgif.obj rdtarga.obj rdrle.obj rdbmp.obj \
+        rdswitch.obj cdjpeg.obj
+DOBJECTS= djpeg.obj wrppm.obj wrgif.obj wrtarga.obj wrrle.obj wrbmp.obj \
+        rdcolmap.obj cdjpeg.obj
+TROBJECTS= jpegtran.obj rdswitch.obj cdjpeg.obj transupp.obj
+
+
+all: libjpeg.lib cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe
+
+libjpeg.lib: $(LIBOBJECTS)
+	- del libjpeg.lib
+	tlib libjpeg.lib /E /C @&&|
++jcapimin.obj +jcapistd.obj +jcarith.obj +jctrans.obj +jcparam.obj &
++jdatadst.obj +jcinit.obj +jcmaster.obj +jcmarker.obj +jcmainct.obj &
++jcprepct.obj +jccoefct.obj +jccolor.obj +jcsample.obj +jchuff.obj &
++jcdctmgr.obj +jfdctfst.obj +jfdctflt.obj +jfdctint.obj +jdapimin.obj &
++jdapistd.obj +jdarith.obj +jdtrans.obj +jdatasrc.obj +jdmaster.obj &
++jdinput.obj +jdmarker.obj +jdhuff.obj +jdmainct.obj +jdcoefct.obj &
++jdpostct.obj +jddctmgr.obj +jidctfst.obj +jidctflt.obj +jidctint.obj &
++jdsample.obj +jdcolor.obj +jquant1.obj +jquant2.obj +jdmerge.obj &
++jaricom.obj +jcomapi.obj +jutils.obj +jerror.obj +jmemmgr.obj &
+$(SYSDEPMEMLIB)
+|
+
+cjpeg.exe: $(COBJECTS) libjpeg.lib
+	$(CC) $(LDFLAGS) -ecjpeg.exe $(COBJECTS) libjpeg.lib
+
+djpeg.exe: $(DOBJECTS) libjpeg.lib
+	$(CC) $(LDFLAGS) -edjpeg.exe $(DOBJECTS) libjpeg.lib
+
+jpegtran.exe: $(TROBJECTS) libjpeg.lib
+	$(CC) $(LDFLAGS) -ejpegtran.exe $(TROBJECTS) libjpeg.lib
+
+rdjpgcom.exe: rdjpgcom.c
+!if $d(DOS)
+	$(CC) -ms -O rdjpgcom.c
+!else
+	$(CC) $(CFLAGS) rdjpgcom.c
+!endif
+
+# On DOS, wrjpgcom needs large model so it can malloc a 64K chunk
+wrjpgcom.exe: wrjpgcom.c
+!if $d(DOS)
+	$(CC) -ml -O wrjpgcom.c
+!else
+	$(CC) $(CFLAGS) wrjpgcom.c
+!endif
+
+# This "{}" syntax allows Borland Make to "batch" source files.
+# In this way, each run of the compiler can build many modules.
+.c.obj:
+	$(CC) $(CFLAGS) -c{ $<}
+
+jconfig.h: jconfig.txt
+	echo You must prepare a system-dependent jconfig.h file.
+	echo Please read the installation directions in install.txt.
+	exit 1
+
+clean:
+	- del *.obj
+	- del libjpeg.lib
+	- del cjpeg.exe
+	- del djpeg.exe
+	- del jpegtran.exe
+	- del rdjpgcom.exe
+	- del wrjpgcom.exe
+	- del testout*.*
+
+test: cjpeg.exe djpeg.exe jpegtran.exe
+	- del testout*.*
+	djpeg -dct int -ppm -outfile testout.ppm  testorig.jpg
+	djpeg -dct int -bmp -colors 256 -outfile testout.bmp  testorig.jpg
+	cjpeg -dct int -outfile testout.jpg  testimg.ppm
+	djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+	cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+	jpegtran -outfile testoutt.jpg testprog.jpg
+!if $d(DOS)
+	fc /b testimg.ppm testout.ppm
+	fc /b testimg.bmp testout.bmp
+	fc /b testimg.jpg testout.jpg
+	fc /b testimg.ppm testoutp.ppm
+	fc /b testimgp.jpg testoutp.jpg
+	fc /b testorig.jpg testoutt.jpg
+!else
+	echo n > n.tmp
+	comp testimg.ppm testout.ppm < n.tmp
+	comp testimg.bmp testout.bmp < n.tmp
+	comp testimg.jpg testout.jpg < n.tmp
+	comp testimg.ppm testoutp.ppm < n.tmp
+	comp testimgp.jpg testoutp.jpg < n.tmp
+	comp testorig.jpg testoutt.jpg < n.tmp
+	del n.tmp
+!endif
+
+
+jaricom.obj: jaricom.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapimin.obj: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.obj: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcarith.obj: jcarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.obj: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.obj: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.obj: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.obj: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcinit.obj: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.obj: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.obj: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.obj: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.obj: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.obj: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcprepct.obj: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.obj: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.obj: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.obj: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.obj: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdarith.obj: jdarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.obj: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.obj: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.obj: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.obj: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.obj: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.obj: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdinput.obj: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.obj: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.obj: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.obj: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.obj: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdpostct.obj: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.obj: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.obj: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.obj: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.obj: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.obj: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.obj: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.obj: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.obj: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.obj: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.obj: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.obj: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.obj: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.obj: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.obj: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.obj: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.obj: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.obj: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.obj: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.obj: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.obj: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.obj: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h
+rdjpgcom.obj: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.obj: wrjpgcom.c jinclude.h jconfig.h
+cdjpeg.obj: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.obj: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.obj: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+transupp.obj: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h
+rdppm.obj: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.obj: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.obj: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.obj: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.obj: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.obj: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.obj: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.obj: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.obj: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.obj: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+jmemdosa.obj: jmemdosa.asm
+	tasm /mx jmemdosa.asm
diff --git a/source/Irrlicht/jpeglib/makefile.dj b/source/Irrlicht/jpeglib/makefile.dj
new file mode 100644
index 00000000..f37c1216
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makefile.dj
@@ -0,0 +1,227 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is for DJGPP (Delorie's GNU C port on MS-DOS), v2.0 or later.
+# Thanks to Frank J. Donahoe for this version.
+
+# Read installation instructions before saying "make" !!
+
+# The name of your C compiler:
+CC= gcc
+
+# You may need to adjust these cc options:
+CFLAGS= -O2 -Wall -I.
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+
+# Link-time cc options:
+LDFLAGS= -s
+
+# To link any special libraries, add the necessary -l commands here.
+LDLIBS= 
+
+# Put here the object file name for the correct system-dependent memory
+# manager file.  For DJGPP this is usually jmemnobs.o, but you could
+# use jmemname.o if you want to use named temp files instead of swap space.
+SYSDEPMEM= jmemnobs.o
+
+# miscellaneous OS-dependent stuff
+# linker
+LN= $(CC)
+# file deletion command
+RM= del
+# library (.a) file creation command
+AR= ar rc
+# second step in .a creation (use "touch" if not needed)
+AR2= ranlib
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+        jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+        jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+        jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+        jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+        jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+        jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+        jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \
+        rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \
+        rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h \
+        jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
+# documentation, test, and support files
+DOCS= README install.txt usage.txt cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+        wrjpgcom.1 wizard.txt example.c libjpeg.txt structure.txt \
+        coderules.txt filelist.txt change.log
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+        makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+        makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+        makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+        maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+        makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+        makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+        makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+        makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+        makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+        makefile.mms makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+        jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+        jconfig.vms
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp \
+        missing ar-lib
+OTHERFILES= jconfig.txt ckconfig.c jmemdosa.asm libjpeg.map
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+        testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+        $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jaricom.o jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.o jcapistd.o jcarith.o jctrans.o jcparam.o \
+        jdatadst.o jcinit.o jcmaster.o jcmarker.o jcmainct.o jcprepct.o \
+        jccoefct.o jccolor.o jcsample.o jchuff.o jcdctmgr.o jfdctfst.o \
+        jfdctflt.o jfdctint.o
+# decompression library object files
+DLIBOBJECTS= jdapimin.o jdapistd.o jdarith.o jdtrans.o jdatasrc.o \
+        jdmaster.o jdinput.o jdmarker.o jdhuff.o jdmainct.o \
+        jdcoefct.o jdpostct.o jddctmgr.o jidctfst.o jidctflt.o \
+        jidctint.o jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o
+# These objectfiles are included in libjpeg.a
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \
+        cdjpeg.o
+DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \
+        cdjpeg.o
+TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o transupp.o
+
+
+all: libjpeg.a cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe
+
+libjpeg.a: $(LIBOBJECTS)
+	$(RM) libjpeg.a
+	$(AR) libjpeg.a  $(LIBOBJECTS)
+	$(AR2) libjpeg.a
+
+cjpeg.exe: $(COBJECTS) libjpeg.a
+	$(LN) $(LDFLAGS) -o cjpeg.exe $(COBJECTS) libjpeg.a $(LDLIBS)
+
+djpeg.exe: $(DOBJECTS) libjpeg.a
+	$(LN) $(LDFLAGS) -o djpeg.exe $(DOBJECTS) libjpeg.a $(LDLIBS)
+
+jpegtran.exe: $(TROBJECTS) libjpeg.a
+	$(LN) $(LDFLAGS) -o jpegtran.exe $(TROBJECTS) libjpeg.a $(LDLIBS)
+
+rdjpgcom.exe: rdjpgcom.o
+	$(LN) $(LDFLAGS) -o rdjpgcom.exe rdjpgcom.o $(LDLIBS)
+
+wrjpgcom.exe: wrjpgcom.o
+	$(LN) $(LDFLAGS) -o wrjpgcom.exe wrjpgcom.o $(LDLIBS)
+
+jconfig.h: jconfig.txt
+	echo You must prepare a system-dependent jconfig.h file.
+	echo Please read the installation directions in install.txt.
+	exit 1
+
+clean:
+	$(RM) *.o
+	$(RM) cjpeg.exe
+	$(RM) djpeg.exe
+	$(RM) jpegtran.exe
+	$(RM) rdjpgcom.exe
+	$(RM) wrjpgcom.exe
+	$(RM) libjpeg.a
+	$(RM) testout*.*
+
+test: cjpeg.exe djpeg.exe jpegtran.exe
+	$(RM) testout*.*
+	./djpeg -dct int -ppm -outfile testout.ppm  testorig.jpg
+	./djpeg -dct int -bmp -colors 256 -outfile testout.bmp  testorig.jpg
+	./cjpeg -dct int -outfile testout.jpg  testimg.ppm
+	./djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+	./cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+	./jpegtran -outfile testoutt.jpg testprog.jpg
+	fc /b testimg.ppm testout.ppm
+	fc /b testimg.bmp testout.bmp
+	fc /b testimg.jpg testout.jpg
+	fc /b testimg.ppm testoutp.ppm
+	fc /b testimgp.jpg testoutp.jpg
+	fc /b testorig.jpg testoutt.jpg
+
+
+jaricom.o: jaricom.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapimin.o: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.o: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcarith.o: jcarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.o: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.o: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.o: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.o: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcinit.o: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.o: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.o: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.o: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.o: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.o: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcprepct.o: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.o: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.o: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.o: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.o: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdarith.o: jdarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.o: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.o: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.o: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.o: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.o: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.o: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdinput.o: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.o: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.o: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.o: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.o: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdpostct.o: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.o: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.o: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.o: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.o: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.o: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.o: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.o: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.o: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.o: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.o: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.o: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.o: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.o: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.o: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.o: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.o: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.o: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.o: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.o: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.o: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.o: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h
+rdjpgcom.o: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.o: wrjpgcom.c jinclude.h jconfig.h
+cdjpeg.o: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.o: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.o: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+transupp.o: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h
+rdppm.o: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.o: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.o: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.o: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.o: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.o: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.o: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.o: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.o: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.o: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/source/Irrlicht/jpeglib/makefile.manx b/source/Irrlicht/jpeglib/makefile.manx
new file mode 100644
index 00000000..57a1bb93
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makefile.manx
@@ -0,0 +1,221 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is for Amiga systems using Manx Aztec C ver 5.x.
+# Thanks to D.J. James (djjames@cup.portal.com) for this version.
+
+# Read installation instructions before saying "make" !!
+
+# The name of your C compiler:
+CC= cc
+
+# You may need to adjust these cc options:
+# Uncomment for generic 68000 code (will work on any Amiga)
+ARCHFLAGS= -sn
+
+# Uncomment for 68020/68030 code (faster, but won't run on 68000 CPU)
+#ARCHFLAGS= -c2
+
+CFLAGS= -MC -MD $(ARCHFLAGS) -spfam -r4
+
+# Link-time cc options:
+LDFLAGS= -g
+
+# To link any special libraries, add the necessary -l commands here.
+LDLIBS= -lml -lcl
+
+# Put here the object file name for the correct system-dependent memory
+# manager file.  For Amiga we recommend jmemname.o.
+SYSDEPMEM= jmemname.o
+
+# miscellaneous OS-dependent stuff
+# linker
+LN= ln
+# file deletion command
+RM= delete quiet
+# library (.lib) file creation command
+AR= lb
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+        jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+        jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+        jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+        jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+        jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+        jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+        jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \
+        rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \
+        rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h \
+        jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
+# documentation, test, and support files
+DOCS= README install.txt usage.txt cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+        wrjpgcom.1 wizard.txt example.c libjpeg.txt structure.txt \
+        coderules.txt filelist.txt change.log
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+        makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+        makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+        makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+        maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+        makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+        makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+        makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+        makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+        makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+        makefile.mms makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+        jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+        jconfig.vms
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp \
+        missing ar-lib
+OTHERFILES= jconfig.txt ckconfig.c jmemdosa.asm libjpeg.map
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+        testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+        $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jaricom.o jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.o jcapistd.o jcarith.o jctrans.o jcparam.o \
+        jdatadst.o jcinit.o jcmaster.o jcmarker.o jcmainct.o jcprepct.o \
+        jccoefct.o jccolor.o jcsample.o jchuff.o jcdctmgr.o jfdctfst.o \
+        jfdctflt.o jfdctint.o
+# decompression library object files
+DLIBOBJECTS= jdapimin.o jdapistd.o jdarith.o jdtrans.o jdatasrc.o \
+        jdmaster.o jdinput.o jdmarker.o jdhuff.o jdmainct.o \
+        jdcoefct.o jdpostct.o jddctmgr.o jidctfst.o jidctflt.o \
+        jidctint.o jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o
+# These objectfiles are included in libjpeg.lib
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \
+        cdjpeg.o
+DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \
+        cdjpeg.o
+TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o transupp.o
+
+
+all: libjpeg.lib cjpeg djpeg jpegtran rdjpgcom wrjpgcom
+
+libjpeg.lib: $(LIBOBJECTS)
+	-$(RM) libjpeg.lib
+	$(AR) libjpeg.lib  $(LIBOBJECTS)
+
+cjpeg: $(COBJECTS) libjpeg.lib
+	$(LN) $(LDFLAGS) -o cjpeg $(COBJECTS) libjpeg.lib $(LDLIBS)
+
+djpeg: $(DOBJECTS) libjpeg.lib
+	$(LN) $(LDFLAGS) -o djpeg $(DOBJECTS) libjpeg.lib $(LDLIBS)
+
+jpegtran: $(TROBJECTS) libjpeg.lib
+	$(LN) $(LDFLAGS) -o jpegtran $(TROBJECTS) libjpeg.lib $(LDLIBS)
+
+rdjpgcom: rdjpgcom.o
+	$(LN) $(LDFLAGS) -o rdjpgcom rdjpgcom.o $(LDLIBS)
+
+wrjpgcom: wrjpgcom.o
+	$(LN) $(LDFLAGS) -o wrjpgcom wrjpgcom.o $(LDLIBS)
+
+jconfig.h: jconfig.txt
+	echo You must prepare a system-dependent jconfig.h file.
+	echo Please read the installation directions in install.txt.
+	exit 1
+
+clean:
+	-$(RM) *.o cjpeg djpeg jpegtran libjpeg.lib rdjpgcom wrjpgcom
+	-$(RM) core testout*.*
+
+test: cjpeg djpeg jpegtran
+	-$(RM) testout*.*
+	djpeg -dct int -ppm -outfile testout.ppm  testorig.jpg
+	djpeg -dct int -bmp -colors 256 -outfile testout.bmp  testorig.jpg
+	cjpeg -dct int -outfile testout.jpg  testimg.ppm
+	djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+	cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+	jpegtran -outfile testoutt.jpg testprog.jpg
+	cmp testimg.ppm testout.ppm
+	cmp testimg.bmp testout.bmp
+	cmp testimg.jpg testout.jpg
+	cmp testimg.ppm testoutp.ppm
+	cmp testimgp.jpg testoutp.jpg
+	cmp testorig.jpg testoutt.jpg
+
+
+jaricom.o: jaricom.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapimin.o: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.o: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcarith.o: jcarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.o: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.o: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.o: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.o: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcinit.o: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.o: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.o: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.o: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.o: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.o: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcprepct.o: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.o: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.o: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.o: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.o: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdarith.o: jdarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.o: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.o: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.o: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.o: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.o: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.o: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdinput.o: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.o: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.o: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.o: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.o: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdpostct.o: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.o: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.o: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.o: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.o: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.o: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.o: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.o: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.o: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.o: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.o: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.o: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.o: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.o: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.o: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.o: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.o: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.o: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.o: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.o: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.o: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.o: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h
+rdjpgcom.o: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.o: wrjpgcom.c jinclude.h jconfig.h
+cdjpeg.o: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.o: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.o: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+transupp.o: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h
+rdppm.o: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.o: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.o: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.o: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.o: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.o: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.o: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.o: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.o: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.o: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/source/Irrlicht/jpeglib/makefile.mc6 b/source/Irrlicht/jpeglib/makefile.mc6
new file mode 100644
index 00000000..7dd37f19
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makefile.mc6
@@ -0,0 +1,256 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is for Microsoft C for MS-DOS, version 6.00A and up.
+# Use NMAKE, not Microsoft's brain-damaged MAKE.
+# Thanks to Alan Wright and Chris Turner of Olivetti Research Ltd.
+
+# Read installation instructions before saying "nmake" !!
+
+# You may need to adjust these compiler options:
+CFLAGS = -AM -Oecigt -Gs -W3
+# -AM medium memory model (or use -AS for small model, if you remove features)
+# -Oecigt -Gs  maximum safe optimisation (-Ol has bugs in MSC 6.00A)
+# -W3 warning level 3
+# You might also want to add -G2 if you have an 80286, etc.
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+
+# Jan-Herman Buining suggests the following switches for MS C 8.0 and a 486:
+# CFLAGS = /AM /f- /FPi87 /G3 /Gs /Gy /Ob1 /Oc /Oe /Og /Oi /Ol /On /Oo /Ot \
+#          /OV4 /W3
+# except for jquant1.c, which must be compiled with /Oo- to avoid a compiler
+# crash.
+
+# Ingar Steinsland suggests the following switches when building
+# a 16-bit Windows DLL:
+# CFLAGS = -ALw -Gsw -Zpe -W3 -O2 -Zi -Zd
+
+# Put here the object file name for the correct system-dependent memory
+# manager file.  For DOS, we recommend jmemdos.c and jmemdosa.asm.
+# (But not for Windows; see install.txt if you use this makefile for Windows.)
+SYSDEPMEM= jmemdos.obj jmemdosa.obj
+# SYSDEPMEMLIB must list the same files with "+" signs for the librarian.
+SYSDEPMEMLIB= +jmemdos.obj +jmemdosa.obj
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+        jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+        jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+        jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+        jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+        jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+        jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+        jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \
+        rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \
+        rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h \
+        jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
+# documentation, test, and support files
+DOCS= README install.txt usage.txt cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+        wrjpgcom.1 wizard.txt example.c libjpeg.txt structure.txt \
+        coderules.txt filelist.txt change.log
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+        makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+        makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+        makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+        maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+        makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+        makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+        makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+        makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+        makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+        makefile.mms makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+        jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+        jconfig.vms
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp \
+        missing ar-lib
+OTHERFILES= jconfig.txt ckconfig.c jmemdosa.asm libjpeg.map
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+        testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+        $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jaricom.obj jcomapi.obj jutils.obj jerror.obj jmemmgr.obj $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.obj jcapistd.obj jcarith.obj jctrans.obj jcparam.obj \
+        jdatadst.obj jcinit.obj jcmaster.obj jcmarker.obj jcmainct.obj \
+        jcprepct.obj jccoefct.obj jccolor.obj jcsample.obj jchuff.obj \
+        jcdctmgr.obj jfdctfst.obj jfdctflt.obj jfdctint.obj
+# decompression library object files
+DLIBOBJECTS= jdapimin.obj jdapistd.obj jdarith.obj jdtrans.obj jdatasrc.obj \
+        jdmaster.obj jdinput.obj jdmarker.obj jdhuff.obj jdmainct.obj \
+        jdcoefct.obj jdpostct.obj jddctmgr.obj jidctfst.obj jidctflt.obj \
+        jidctint.obj jdsample.obj jdcolor.obj jquant1.obj jquant2.obj \
+        jdmerge.obj
+# These objectfiles are included in libjpeg.lib
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.obj rdppm.obj rdgif.obj rdtarga.obj rdrle.obj rdbmp.obj \
+        rdswitch.obj cdjpeg.obj
+DOBJECTS= djpeg.obj wrppm.obj wrgif.obj wrtarga.obj wrrle.obj wrbmp.obj \
+        rdcolmap.obj cdjpeg.obj
+TROBJECTS= jpegtran.obj rdswitch.obj cdjpeg.obj transupp.obj
+
+# need linker response file because file list > 128 chars
+RFILE = libjpeg.ans
+
+
+all: libjpeg.lib cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe
+
+libjpeg.lib: $(LIBOBJECTS) $(RFILE)
+	del libjpeg.lib
+	lib @$(RFILE)
+
+# linker response file for building libjpeg.lib
+$(RFILE) : makefile
+	del $(RFILE)
+	echo libjpeg.lib >$(RFILE)
+# silly want-to-create-it prompt:
+	echo y >>$(RFILE)
+	echo +jcapimin.obj +jcapistd.obj +jcarith.obj +jctrans.obj & >>$(RFILE)
+	echo +jcparam.obj +jdatadst.obj +jcinit.obj +jcmaster.obj & >>$(RFILE)
+	echo +jcmarker.obj +jcmainct.obj +jcprepct.obj & >>$(RFILE)
+	echo +jccoefct.obj +jccolor.obj +jcsample.obj +jchuff.obj & >>$(RFILE)
+	echo +jcdctmgr.obj +jfdctfst.obj +jfdctflt.obj & >>$(RFILE)
+	echo +jfdctint.obj +jdapimin.obj +jdapistd.obj & >>$(RFILE)
+	echo +jdarith.obj +jdtrans.obj +jdatasrc.obj +jdmaster.obj & >>$(RFILE)
+	echo +jdinput.obj +jdmarker.obj +jdhuff.obj +jdmainct.obj & >>$(RFILE)
+	echo +jdcoefct.obj +jdpostct.obj +jddctmgr.obj & >>$(RFILE)
+	echo +jidctfst.obj +jidctflt.obj +jidctint.obj & >>$(RFILE)
+	echo +jdsample.obj +jdcolor.obj +jquant1.obj & >>$(RFILE)
+	echo +jquant2.obj +jdmerge.obj +jaricom.obj +jcomapi.obj & >>$(RFILE)
+	echo +jutils.obj +jerror.obj +jmemmgr.obj & >>$(RFILE)
+	echo $(SYSDEPMEMLIB) ; >>$(RFILE)
+
+cjpeg.exe: $(COBJECTS) libjpeg.lib
+	echo $(COBJECTS) >cjpeg.lst
+	link /STACK:4096 /EXEPACK @cjpeg.lst, cjpeg.exe, , libjpeg.lib, ;
+	del cjpeg.lst
+
+djpeg.exe: $(DOBJECTS) libjpeg.lib
+	echo $(DOBJECTS) >djpeg.lst
+	link /STACK:4096 /EXEPACK @djpeg.lst, djpeg.exe, , libjpeg.lib, ;
+	del djpeg.lst
+
+jpegtran.exe: $(TROBJECTS) libjpeg.lib
+	link /STACK:4096 /EXEPACK $(TROBJECTS), jpegtran.exe, , libjpeg.lib, ;
+
+rdjpgcom.exe: rdjpgcom.c
+	$(CC) -AS -O -W3 rdjpgcom.c
+
+# wrjpgcom needs large model so it can malloc a 64K chunk
+wrjpgcom.exe: wrjpgcom.c
+	$(CC) -AL -O -W3 wrjpgcom.c
+
+jconfig.h: jconfig.txt
+	echo You must prepare a system-dependent jconfig.h file.
+	echo Please read the installation directions in install.txt.
+	exit 1
+
+clean:
+	del *.obj
+	del libjpeg.lib
+	del cjpeg.exe
+	del djpeg.exe
+	del jpegtran.exe
+	del rdjpgcom.exe
+	del wrjpgcom.exe
+	del testout*.*
+
+test: cjpeg.exe djpeg.exe jpegtran.exe
+	del testout*.*
+	djpeg -dct int -ppm -outfile testout.ppm  testorig.jpg
+	djpeg -dct int -bmp -colors 256 -outfile testout.bmp  testorig.jpg
+	cjpeg -dct int -outfile testout.jpg  testimg.ppm
+	djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+	cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+	jpegtran -outfile testoutt.jpg testprog.jpg
+	fc /b testimg.ppm testout.ppm
+	fc /b testimg.bmp testout.bmp
+	fc /b testimg.jpg testout.jpg
+	fc /b testimg.ppm testoutp.ppm
+	fc /b testimgp.jpg testoutp.jpg
+	fc /b testorig.jpg testoutt.jpg
+
+
+jaricom.obj: jaricom.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapimin.obj: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.obj: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcarith.obj: jcarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.obj: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.obj: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.obj: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.obj: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcinit.obj: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.obj: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.obj: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.obj: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.obj: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.obj: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcprepct.obj: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.obj: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.obj: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.obj: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.obj: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdarith.obj: jdarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.obj: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.obj: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.obj: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.obj: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.obj: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.obj: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdinput.obj: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.obj: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.obj: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.obj: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.obj: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdpostct.obj: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.obj: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.obj: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.obj: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.obj: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.obj: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.obj: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.obj: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.obj: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.obj: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.obj: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.obj: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.obj: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.obj: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.obj: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.obj: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.obj: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.obj: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.obj: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.obj: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.obj: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.obj: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h
+rdjpgcom.obj: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.obj: wrjpgcom.c jinclude.h jconfig.h
+cdjpeg.obj: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.obj: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.obj: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+transupp.obj: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h
+rdppm.obj: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.obj: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.obj: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.obj: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.obj: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.obj: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.obj: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.obj: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.obj: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.obj: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+jmemdosa.obj : jmemdosa.asm
+	masm /mx $*;
diff --git a/source/Irrlicht/jpeglib/makefile.mms b/source/Irrlicht/jpeglib/makefile.mms
new file mode 100644
index 00000000..53493060
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makefile.mms
@@ -0,0 +1,225 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is for use with MMS on Digital VMS systems.
+# Thanks to Rick Dyson (dyson@iowasp.physics.uiowa.edu)
+# and Tim Bell (tbell@netcom.com) for their help.
+
+# Read installation instructions before saying "MMS" !!
+
+# You may need to adjust these cc options:
+CFLAGS= $(CFLAGS) /NoDebug /Optimize
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via /Define switches here.
+.ifdef ALPHA
+OPT=
+.else
+OPT= ,Sys$Disk:[]MAKVMS.OPT/Option
+.endif
+
+# Put here the object file name for the correct system-dependent memory
+# manager file.  For Unix this is usually jmemnobs.o, but you may want
+# to use jmemansi.o or jmemname.o if you have limited swap space.
+SYSDEPMEM= jmemnobs.obj
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+        jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+        jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+        jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+        jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+        jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+        jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+        jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \
+        rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \
+        rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h \
+        jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
+# documentation, test, and support files
+DOCS= README install.txt usage.txt cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+        wrjpgcom.1 wizard.txt example.c libjpeg.txt structure.txt \
+        coderules.txt filelist.txt change.log
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+        makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+        makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+        makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+        maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+        makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+        makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+        makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+        makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+        makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+        makefile.mms makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+        jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+        jconfig.vms
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp \
+        missing ar-lib
+OTHERFILES= jconfig.txt ckconfig.c jmemdosa.asm libjpeg.map
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+        testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+        $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jaricom.obj jcomapi.obj jutils.obj jerror.obj jmemmgr.obj $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.obj jcapistd.obj jcarith.obj jctrans.obj jcparam.obj \
+        jdatadst.obj jcinit.obj jcmaster.obj jcmarker.obj jcmainct.obj \
+        jcprepct.obj jccoefct.obj jccolor.obj jcsample.obj jchuff.obj \
+        jcdctmgr.obj jfdctfst.obj jfdctflt.obj jfdctint.obj
+# decompression library object files
+DLIBOBJECTS= jdapimin.obj jdapistd.obj jdarith.obj jdtrans.obj jdatasrc.obj \
+        jdmaster.obj jdinput.obj jdmarker.obj jdhuff.obj jdmainct.obj \
+        jdcoefct.obj jdpostct.obj jddctmgr.obj jidctfst.obj jidctflt.obj \
+        jidctint.obj jdsample.obj jdcolor.obj jquant1.obj jquant2.obj \
+        jdmerge.obj
+# These objectfiles are included in libjpeg.olb
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.obj rdppm.obj rdgif.obj rdtarga.obj rdrle.obj rdbmp.obj \
+        rdswitch.obj cdjpeg.obj
+DOBJECTS= djpeg.obj wrppm.obj wrgif.obj wrtarga.obj wrrle.obj wrbmp.obj \
+        rdcolmap.obj cdjpeg.obj
+TROBJECTS= jpegtran.obj rdswitch.obj cdjpeg.obj transupp.obj
+# objectfile lists with commas --- what a crock
+COBJLIST= cjpeg.obj,rdppm.obj,rdgif.obj,rdtarga.obj,rdrle.obj,rdbmp.obj,\
+          rdswitch.obj,cdjpeg.obj
+DOBJLIST= djpeg.obj,wrppm.obj,wrgif.obj,wrtarga.obj,wrrle.obj,wrbmp.obj,\
+          rdcolmap.obj,cdjpeg.obj
+TROBJLIST= jpegtran.obj,rdswitch.obj,cdjpeg.obj,transupp.obj
+LIBOBJLIST= jaricom.obj,jcapimin.obj,jcapistd.obj,jcarith.obj,jctrans.obj,\
+          jcparam.obj,jdatadst.obj,jcinit.obj,jcmaster.obj,jcmarker.obj,\
+          jcmainct.obj,jcprepct.obj,jccoefct.obj,jccolor.obj,jcsample.obj,\
+          jchuff.obj,jcdctmgr.obj,jfdctfst.obj,jfdctflt.obj,jfdctint.obj,\
+          jdapimin.obj,jdapistd.obj,jdarith.obj,jdtrans.obj,jdatasrc.obj,\
+          jdmaster.obj,jdinput.obj,jdmarker.obj,jdhuff.obj,jdmainct.obj,\
+          jdcoefct.obj,jdpostct.obj,jddctmgr.obj,jidctfst.obj,jidctflt.obj,\
+          jidctint.obj,jdsample.obj,jdcolor.obj,jquant1.obj,jquant2.obj,\
+          jdmerge.obj,jcomapi.obj,jutils.obj,jerror.obj,jmemmgr.obj,$(SYSDEPMEM)
+
+
+.first
+	@- Define /NoLog Sys Sys$Library
+
+ALL : libjpeg.olb cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe
+	@ Continue
+
+libjpeg.olb : $(LIBOBJECTS)
+	Library /Create libjpeg.olb $(LIBOBJLIST)
+
+cjpeg.exe : $(COBJECTS) libjpeg.olb
+	$(LINK) $(LFLAGS) /Executable = cjpeg.exe $(COBJLIST),libjpeg.olb/Library$(OPT)
+
+djpeg.exe : $(DOBJECTS) libjpeg.olb
+	$(LINK) $(LFLAGS) /Executable = djpeg.exe $(DOBJLIST),libjpeg.olb/Library$(OPT)
+
+jpegtran.exe : $(TROBJECTS) libjpeg.olb
+	$(LINK) $(LFLAGS) /Executable = jpegtran.exe $(TROBJLIST),libjpeg.olb/Library$(OPT)
+
+rdjpgcom.exe : rdjpgcom.obj
+	$(LINK) $(LFLAGS) /Executable = rdjpgcom.exe rdjpgcom.obj$(OPT)
+
+wrjpgcom.exe : wrjpgcom.obj
+	$(LINK) $(LFLAGS) /Executable = wrjpgcom.exe wrjpgcom.obj$(OPT)
+
+jconfig.h : jconfig.vms
+	@- Copy jconfig.vms jconfig.h
+
+clean :
+	@- Set Protection = Owner:RWED *.*;-1
+	@- Set Protection = Owner:RWED *.OBJ
+	- Purge /NoLog /NoConfirm *.*
+	- Delete /NoLog /NoConfirm *.OBJ;
+
+test : cjpeg.exe djpeg.exe jpegtran.exe
+	mcr sys$disk:[]djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+	mcr sys$disk:[]djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg
+	mcr sys$disk:[]cjpeg -dct int      -outfile testout.jpg testimg.ppm
+	mcr sys$disk:[]djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+	mcr sys$disk:[]cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+	mcr sys$disk:[]jpegtran -outfile testoutt.jpg testprog.jpg
+	- Backup /Compare/Log	  testimg.ppm testout.ppm
+	- Backup /Compare/Log	  testimg.bmp testout.bmp
+	- Backup /Compare/Log	  testimg.jpg testout.jpg
+	- Backup /Compare/Log	  testimg.ppm testoutp.ppm
+	- Backup /Compare/Log	  testimgp.jpg testoutp.jpg
+	- Backup /Compare/Log	  testorig.jpg testoutt.jpg
+
+
+jaricom.obj : jaricom.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapimin.obj : jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.obj : jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcarith.obj : jcarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.obj : jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.obj : jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.obj : jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.obj : jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcinit.obj : jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.obj : jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.obj : jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.obj : jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.obj : jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.obj : jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcprepct.obj : jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.obj : jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.obj : jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.obj : jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.obj : jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdarith.obj : jdarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.obj : jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.obj : jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.obj : jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.obj : jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.obj : jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.obj : jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdinput.obj : jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.obj : jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.obj : jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.obj : jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.obj : jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdpostct.obj : jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.obj : jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.obj : jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.obj : jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.obj : jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.obj : jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.obj : jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.obj : jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.obj : jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.obj : jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.obj : jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.obj : jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.obj : jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.obj : jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.obj : jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.obj : jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.obj : jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.obj : jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.obj : jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.obj : cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.obj : djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.obj : jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h
+rdjpgcom.obj : rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.obj : wrjpgcom.c jinclude.h jconfig.h
+cdjpeg.obj : cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.obj : rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.obj : rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+transupp.obj : transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h
+rdppm.obj : rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.obj : wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.obj : rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.obj : wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.obj : rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.obj : wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.obj : rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.obj : wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.obj : rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.obj : wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/source/Irrlicht/jpeglib/makefile.sas b/source/Irrlicht/jpeglib/makefile.sas
new file mode 100644
index 00000000..ba0d63b9
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makefile.sas
@@ -0,0 +1,259 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is for Amiga systems using SAS C 6.0 and up.
+# Thanks to Ed Hanway, Mark Rinfret, and Jim Zepeda.
+
+# Read installation instructions before saying "make" !!
+
+# The name of your C compiler:
+CC= sc
+
+# You may need to adjust these cc options:
+# Uncomment the following lines for generic 680x0 version
+ARCHFLAGS= cpu=any
+SUFFIX=
+
+# Uncomment the following lines for 68030-only version
+#ARCHFLAGS= cpu=68030
+#SUFFIX=.030
+
+CFLAGS= nostackcheck data=near parms=register optimize $(ARCHFLAGS) \
+	ignore=104 ignore=304 ignore=306
+# ignore=104 disables warnings for mismatched const qualifiers
+# ignore=304 disables warnings for variables being optimized out
+# ignore=306 disables warnings for the inlining of functions
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via define switches here.
+
+# Link-time cc options:
+LDFLAGS= SC SD ND BATCH
+
+# To link any special libraries, add the necessary commands here.
+LDLIBS= LIB:scm.lib LIB:sc.lib
+
+# Put here the object file name for the correct system-dependent memory
+# manager file.  For Amiga we recommend jmemname.o.
+SYSDEPMEM= jmemname.o
+
+# miscellaneous OS-dependent stuff
+# linker
+LN= slink
+# file deletion command
+RM= delete quiet
+# library (.lib) file creation command
+AR= oml
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+        jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+        jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+        jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+        jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+        jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+        jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+        jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \
+        rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \
+        rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h \
+        jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
+# documentation, test, and support files
+DOCS= README install.txt usage.txt cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+        wrjpgcom.1 wizard.txt example.c libjpeg.txt structure.txt \
+        coderules.txt filelist.txt change.log
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+        makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+        makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+        makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+        maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+        makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+        makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+        makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+        makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+        makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+        makefile.mms makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+        jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+        jconfig.vms
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp \
+        missing ar-lib
+OTHERFILES= jconfig.txt ckconfig.c jmemdosa.asm libjpeg.map
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+        testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+        $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jaricom.o jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.o jcapistd.o jcarith.o jctrans.o jcparam.o \
+        jdatadst.o jcinit.o jcmaster.o jcmarker.o jcmainct.o jcprepct.o \
+        jccoefct.o jccolor.o jcsample.o jchuff.o jcdctmgr.o jfdctfst.o \
+        jfdctflt.o jfdctint.o
+# decompression library object files
+DLIBOBJECTS= jdapimin.o jdapistd.o jdarith.o jdtrans.o jdatasrc.o \
+        jdmaster.o jdinput.o jdmarker.o jdhuff.o jdmainct.o \
+        jdcoefct.o jdpostct.o jddctmgr.o jidctfst.o jidctflt.o \
+        jidctint.o jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o
+# These objectfiles are included in libjpeg.lib
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \
+        cdjpeg.o
+DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \
+        cdjpeg.o
+TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o transupp.o
+
+
+all: libjpeg.lib cjpeg$(SUFFIX) djpeg$(SUFFIX) jpegtran$(SUFFIX) rdjpgcom$(SUFFIX) wrjpgcom$(SUFFIX)
+
+# note: do several AR steps to avoid command line length limitations
+
+libjpeg.lib: $(LIBOBJECTS)
+	-$(RM) libjpeg.lib
+	$(AR) libjpeg.lib r $(CLIBOBJECTS)
+	$(AR) libjpeg.lib r $(DLIBOBJECTS)
+	$(AR) libjpeg.lib r $(COMOBJECTS)
+
+cjpeg$(SUFFIX): $(COBJECTS) libjpeg.lib
+	$(LN) 
+
+# You may want to adjust these compiler options:
+CFLAGS= $(cflags) $(cdebug) $(cvars) -I.
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+
+# Link-time options:
+LDFLAGS= $(ldebug) $(conlflags)
+
+# To link any special libraries, add the necessary commands here.
+LDLIBS= $(conlibs)
+
+# Put here the object file name for the correct system-dependent memory
+# manager file.  For NT we suggest jmemnobs.obj, which expects the OS to
+# provide adequate virtual memory.
+SYSDEPMEM= jmemnobs.obj
+
+# miscellaneous OS-dependent stuff
+# file deletion command
+RM= del
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+        jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+        jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+        jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+        jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+        jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+        jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+        jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \
+        rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \
+        rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h \
+        jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
+# documentation, test, and support files
+DOCS= README install.txt usage.txt cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+        wrjpgcom.1 wizard.txt example.c libjpeg.txt structure.txt \
+        coderules.txt filelist.txt change.log
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+        makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+        makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+        makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+        maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+        makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+        makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+        makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+        makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+        makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+        makefile.mms makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+        jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+        jconfig.vms
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp \
+        missing ar-lib
+OTHERFILES= jconfig.txt ckconfig.c jmemdosa.asm libjpeg.map
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+        testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+        $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jaricom.obj jcomapi.obj jutils.obj jerror.obj jmemmgr.obj $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.obj jcapistd.obj jcarith.obj jctrans.obj jcparam.obj \
+        jdatadst.obj jcinit.obj jcmaster.obj jcmarker.obj jcmainct.obj \
+        jcprepct.obj jccoefct.obj jccolor.obj jcsample.obj jchuff.obj \
+        jcdctmgr.obj jfdctfst.obj jfdctflt.obj jfdctint.obj
+# decompression library object files
+DLIBOBJECTS= jdapimin.obj jdapistd.obj jdarith.obj jdtrans.obj jdatasrc.obj \
+        jdmaster.obj jdinput.obj jdmarker.obj jdhuff.obj jdmainct.obj \
+        jdcoefct.obj jdpostct.obj jddctmgr.obj jidctfst.obj jidctflt.obj \
+        jidctint.obj jdsample.obj jdcolor.obj jquant1.obj jquant2.obj \
+        jdmerge.obj
+# These objectfiles are included in libjpeg.lib
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.obj rdppm.obj rdgif.obj rdtarga.obj rdrle.obj rdbmp.obj \
+        rdswitch.obj cdjpeg.obj
+DOBJECTS= djpeg.obj wrppm.obj wrgif.obj wrtarga.obj wrrle.obj wrbmp.obj \
+        rdcolmap.obj cdjpeg.obj
+TROBJECTS= jpegtran.obj rdswitch.obj cdjpeg.obj transupp.obj
+
+# Template command for compiling .c to .obj
+.c.obj:
+	$(cc) $(CFLAGS) $*.c
+
+
+all: libjpeg.lib cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe
+
+libjpeg.lib: $(LIBOBJECTS)
+	$(RM) libjpeg.lib
+	lib -out:libjpeg.lib  $(LIBOBJECTS)
+
+cjpeg.exe: $(COBJECTS) libjpeg.lib
+	$(link) $(LDFLAGS) -out:cjpeg.exe $(COBJECTS) libjpeg.lib $(LDLIBS)
+
+djpeg.exe: $(DOBJECTS) libjpeg.lib
+	$(link) $(LDFLAGS) -out:djpeg.exe $(DOBJECTS) libjpeg.lib $(LDLIBS)
+
+jpegtran.exe: $(TROBJECTS) libjpeg.lib
+	$(link) $(LDFLAGS) -out:jpegtran.exe $(TROBJECTS) libjpeg.lib $(LDLIBS)
+
+rdjpgcom.exe: rdjpgcom.obj
+	$(link) $(LDFLAGS) -out:rdjpgcom.exe rdjpgcom.obj $(LDLIBS)
+
+wrjpgcom.exe: wrjpgcom.obj
+	$(link) $(LDFLAGS) -out:wrjpgcom.exe wrjpgcom.obj $(LDLIBS)
+
+
+clean:
+	$(RM) *.obj *.exe libjpeg.lib
+	$(RM) testout*
+
+setup-vc6:
+	ren jconfig.vc jconfig.h
+	ren makejdsw.vc6 jpeg.dsw
+	ren makeadsw.vc6 apps.dsw
+	ren makejmak.vc6 jpeg.mak
+	ren makejdep.vc6 jpeg.dep
+	ren makejdsp.vc6 jpeg.dsp
+	ren makecmak.vc6 cjpeg.mak
+	ren makecdep.vc6 cjpeg.dep
+	ren makecdsp.vc6 cjpeg.dsp
+	ren makedmak.vc6 djpeg.mak
+	ren makeddep.vc6 djpeg.dep
+	ren makeddsp.vc6 djpeg.dsp
+	ren maketmak.vc6 jpegtran.mak
+	ren maketdep.vc6 jpegtran.dep
+	ren maketdsp.vc6 jpegtran.dsp
+	ren makermak.vc6 rdjpgcom.mak
+	ren makerdep.vc6 rdjpgcom.dep
+	ren makerdsp.vc6 rdjpgcom.dsp
+	ren makewmak.vc6 wrjpgcom.mak
+	ren makewdep.vc6 wrjpgcom.dep
+	ren makewdsp.vc6 wrjpgcom.dsp
+
+setup-v10:
+	ren jconfig.vc jconfig.h
+	ren makejsln.v10 jpeg.sln
+	ren makeasln.v10 apps.sln
+	ren makejvcx.v10 jpeg.vcxproj
+	ren makejfil.v10 jpeg.vcxproj.filters
+	ren makecvcx.v10 cjpeg.vcxproj
+	ren makecfil.v10 cjpeg.vcxproj.filters
+	ren makedvcx.v10 djpeg.vcxproj
+	ren makedfil.v10 djpeg.vcxproj.filters
+	ren maketvcx.v10 jpegtran.vcxproj
+	ren maketfil.v10 jpegtran.vcxproj.filters
+	ren makervcx.v10 rdjpgcom.vcxproj
+	ren makerfil.v10 rdjpgcom.vcxproj.filters
+	ren makewvcx.v10 wrjpgcom.vcxproj
+	ren makewfil.v10 wrjpgcom.vcxproj.filters
+
+test:
+	IF EXIST testout* $(RM) testout*
+	.\djpeg -dct int -ppm -outfile testout.ppm  testorig.jpg
+	.\djpeg -dct int -bmp -colors 256 -outfile testout.bmp  testorig.jpg
+	.\cjpeg -dct int -outfile testout.jpg  testimg.ppm
+	.\djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+	.\cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+	.\jpegtran -outfile testoutt.jpg testprog.jpg
+	fc /b testimg.ppm testout.ppm
+	fc /b testimg.bmp testout.bmp
+	fc /b testimg.jpg testout.jpg
+	fc /b testimg.ppm testoutp.ppm
+	fc /b testimgp.jpg testoutp.jpg
+	fc /b testorig.jpg testoutt.jpg
+
+test-build:
+	IF EXIST testout* $(RM) testout*
+	.\djpeg\Release\djpeg -dct int -ppm -outfile testout.ppm  testorig.jpg
+	.\djpeg\Release\djpeg -dct int -bmp -colors 256 -outfile testout.bmp  testorig.jpg
+	.\cjpeg\Release\cjpeg -dct int -outfile testout.jpg  testimg.ppm
+	.\djpeg\Release\djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+	.\cjpeg\Release\cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+	.\jpegtran\Release\jpegtran -outfile testoutt.jpg testprog.jpg
+	fc /b testimg.ppm testout.ppm
+	fc /b testimg.bmp testout.bmp
+	fc /b testimg.jpg testout.jpg
+	fc /b testimg.ppm testoutp.ppm
+	fc /b testimgp.jpg testoutp.jpg
+	fc /b testorig.jpg testoutt.jpg
+
+
+jaricom.obj: jaricom.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapimin.obj: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.obj: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcarith.obj: jcarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.obj: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.obj: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.obj: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.obj: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcinit.obj: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.obj: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.obj: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.obj: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.obj: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.obj: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcprepct.obj: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.obj: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.obj: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.obj: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.obj: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdarith.obj: jdarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.obj: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.obj: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.obj: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.obj: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.obj: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.obj: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdinput.obj: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.obj: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.obj: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.obj: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.obj: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdpostct.obj: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.obj: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.obj: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.obj: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.obj: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.obj: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.obj: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.obj: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.obj: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.obj: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.obj: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.obj: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.obj: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.obj: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.obj: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.obj: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.obj: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.obj: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.obj: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.obj: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.obj: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.obj: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h
+rdjpgcom.obj: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.obj: wrjpgcom.c jinclude.h jconfig.h
+cdjpeg.obj: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.obj: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.obj: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+transupp.obj: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h
+rdppm.obj: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.obj: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.obj: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.obj: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.obj: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.obj: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.obj: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.obj: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.obj: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.obj: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/source/Irrlicht/jpeglib/makefile.vms b/source/Irrlicht/jpeglib/makefile.vms
new file mode 100644
index 00000000..a07d070d
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makefile.vms
@@ -0,0 +1,142 @@
+$! Makefile for Independent JPEG Group's software
+$!
+$! This is a command procedure for Digital VMS systems that do not have MMS.
+$! It builds the JPEG software by brute force, recompiling everything whether
+$! or not it is necessary.  It then runs the basic self-test.
+$! Thanks to Rick Dyson (dyson@iowasp.physics.uiowa.edu)
+$! and Tim Bell (tbell@netcom.com) for their help.
+$!
+$! Read installation instructions before running this!!
+$!
+$ If F$Mode () .eqs. "INTERACTIVE"
+$   Then
+$       VERIFY = F$Verify (0)
+$   Else
+$       VERIFY = F$Verify (1)
+$ EndIf
+$ On Control_Y Then GoTo End
+$ On Error     Then GoTo End
+$
+$ If F$GetSyi ("HW_MODEL") .gt. 1023 
+$   Then
+$       OPT = ""
+$   Else
+$       OPT = ",Sys$Disk:[]makvms.opt/Option"
+$ EndIf
+$ 
+$ DoCompile := CC /NoDebug /Optimize /NoList
+$!
+$ DoCompile jaricom.c
+$ DoCompile jcapimin.c
+$ DoCompile jcapistd.c
+$ DoCompile jcarith.c
+$ DoCompile jctrans.c
+$ DoCompile jcparam.c
+$ DoCompile jdatadst.c
+$ DoCompile jcinit.c
+$ DoCompile jcmaster.c
+$ DoCompile jcmarker.c
+$ DoCompile jcmainct.c
+$ DoCompile jcprepct.c
+$ DoCompile jccoefct.c
+$ DoCompile jccolor.c
+$ DoCompile jcsample.c
+$ DoCompile jchuff.c
+$ DoCompile jcdctmgr.c
+$ DoCompile jfdctfst.c
+$ DoCompile jfdctflt.c
+$ DoCompile jfdctint.c
+$ DoCompile jdapimin.c
+$ DoCompile jdapistd.c
+$ DoCompile jdarith.c
+$ DoCompile jdtrans.c
+$ DoCompile jdatasrc.c
+$ DoCompile jdmaster.c
+$ DoCompile jdinput.c
+$ DoCompile jdmarker.c
+$ DoCompile jdhuff.c
+$ DoCompile jdmainct.c
+$ DoCompile jdcoefct.c
+$ DoCompile jdpostct.c
+$ DoCompile jddctmgr.c
+$ DoCompile jidctfst.c
+$ DoCompile jidctflt.c
+$ DoCompile jidctint.c
+$ DoCompile jdsample.c
+$ DoCompile jdcolor.c
+$ DoCompile jquant1.c
+$ DoCompile jquant2.c
+$ DoCompile jdmerge.c
+$ DoCompile jcomapi.c
+$ DoCompile jutils.c
+$ DoCompile jerror.c
+$ DoCompile jmemmgr.c
+$ DoCompile jmemnobs.c
+$!
+$ Library /Create libjpeg.olb  jaricom.obj,jcapimin.obj,jcapistd.obj, -
+          jcarith.obj,jctrans.obj,jcparam.obj,jdatadst.obj,jcinit.obj, -
+          jcmaster.obj,jcmarker.obj,jcmainct.obj,jcprepct.obj,jccoefct.obj, -
+          jccolor.obj,jcsample.obj,jchuff.obj,jcdctmgr.obj,jfdctfst.obj, -
+          jfdctflt.obj,jfdctint.obj,jdapimin.obj,jdapistd.obj,jdarith.obj, -
+          jdtrans.obj,jdatasrc.obj,jdmaster.obj,jdinput.obj,jdmarker.obj, -
+          jdhuff.obj,jdmainct.obj,jdcoefct.obj,jdpostct.obj,jddctmgr.obj, -
+          jidctfst.obj,jidctflt.obj,jidctint.obj,jdsample.obj,jdcolor.obj, -
+          jquant1.obj,jquant2.obj,jdmerge.obj,jcomapi.obj,jutils.obj, -
+          jerror.obj,jmemmgr.obj,jmemnobs.obj
+$!
+$ DoCompile cjpeg.c
+$ DoCompile rdppm.c
+$ DoCompile rdgif.c
+$ DoCompile rdtarga.c
+$ DoCompile rdrle.c
+$ DoCompile rdbmp.c
+$ DoCompile rdswitch.c
+$ DoCompile cdjpeg.c
+$!
+$ Link /NoMap /Executable = cjpeg.exe  cjpeg.obj,rdppm.obj,rdgif.obj, -
+          rdtarga.obj,rdrle.obj,rdbmp.obj,rdswitch.obj,cdjpeg.obj,libjpeg.olb/Library'OPT'
+$!
+$ DoCompile djpeg.c
+$ DoCompile wrppm.c
+$ DoCompile wrgif.c
+$ DoCompile wrtarga.c
+$ DoCompile wrrle.c
+$ DoCompile wrbmp.c
+$ DoCompile rdcolmap.c
+$ DoCompile cdjpeg.c
+$!
+$ Link /NoMap /Executable = djpeg.exe  djpeg.obj,wrppm.obj,wrgif.obj, -
+          wrtarga.obj,wrrle.obj,wrbmp.obj,rdcolmap.obj,cdjpeg.obj,libjpeg.olb/Library'OPT'
+$!
+$ DoCompile jpegtran.c
+$ DoCompile rdswitch.c
+$ DoCompile cdjpeg.c
+$ DoCompile transupp.c
+$!
+$ Link /NoMap /Executable = jpegtran.exe  jpegtran.obj,rdswitch.obj, -
+          cdjpeg.obj,transupp.obj,libjpeg.olb/Library'OPT'
+$!
+$ DoCompile rdjpgcom.c
+$ Link /NoMap /Executable = rdjpgcom.exe  rdjpgcom.obj'OPT'
+$!
+$ DoCompile wrjpgcom.c
+$ Link /NoMap /Executable = wrjpgcom.exe  wrjpgcom.obj'OPT'
+$!
+$! Run the self-test
+$!
+$ mcr sys$disk:[]djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+$ mcr sys$disk:[]djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg
+$ mcr sys$disk:[]cjpeg -dct int      -outfile testout.jpg testimg.ppm
+$ mcr sys$disk:[]djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+$ mcr sys$disk:[]cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+$ mcr sys$disk:[]jpegtran -outfile testoutt.jpg testprog.jpg
+$ Backup /Compare/Log testimg.ppm testout.ppm
+$ Backup /Compare/Log testimg.bmp testout.bmp
+$ Backup /Compare/Log testimg.jpg testout.jpg
+$ Backup /Compare/Log testimg.ppm testoutp.ppm
+$ Backup /Compare/Log testimgp.jpg testoutp.jpg
+$ Backup /Compare/Log testorig.jpg testoutt.jpg
+$!
+$End:
+$   If Verify Then Set Verify
+$ Exit
diff --git a/source/Irrlicht/jpeglib/makefile.wat b/source/Irrlicht/jpeglib/makefile.wat
new file mode 100644
index 00000000..9cb8d611
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makefile.wat
@@ -0,0 +1,240 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is suitable for Watcom C/C++ 10.0 on MS-DOS (using
+# dos4g extender), OS/2, and Windows NT console mode.
+# Thanks to Janos Haide, jhaide@btrvtech.com.
+
+# Read installation instructions before saying "wmake" !!
+
+# Uncomment line for desired system
+SYSTEM=DOS
+#SYSTEM=OS2
+#SYSTEM=NT
+
+# The name of your C compiler:
+CC= wcl386
+
+# You may need to adjust these cc options:
+CFLAGS= -4r -ort -wx -zq -bt=$(SYSTEM)
+# Caution: avoid -ol or -ox; these generate bad code with 10.0 or 10.0a.
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+
+# Link-time cc options:
+!ifeq SYSTEM DOS
+LDFLAGS= -zq -l=dos4g
+!else ifeq SYSTEM OS2
+LDFLAGS= -zq -l=os2v2
+!else ifeq SYSTEM NT
+LDFLAGS= -zq -l=nt
+!endif
+
+# Put here the object file name for the correct system-dependent memory
+# manager file.  jmemnobs should work fine for dos4g or OS/2 environment.
+SYSDEPMEM= jmemnobs.obj
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c &
+        jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c &
+        jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c &
+        jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c &
+        jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c &
+        jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c &
+        jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c &
+        jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c &
+        rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c &
+        rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h &
+        jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
+# documentation, test, and support files
+DOCS= README install.txt usage.txt cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 &
+        wrjpgcom.1 wizard.txt example.c libjpeg.txt structure.txt &
+        coderules.txt filelist.txt change.log
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc &
+        makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 &
+        makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 &
+        makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 &
+        maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 &
+        makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 &
+        makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 &
+        makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 &
+        makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st &
+        makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas &
+        makefile.mms makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat &
+        jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas &
+        jconfig.vms
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp &
+        missing ar-lib
+OTHERFILES= jconfig.txt ckconfig.c jmemdosa.asm libjpeg.map
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg &
+        testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) &
+        $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jaricom.obj jcomapi.obj jutils.obj jerror.obj jmemmgr.obj $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.obj jcapistd.obj jcarith.obj jctrans.obj jcparam.obj &
+        jdatadst.obj jcinit.obj jcmaster.obj jcmarker.obj jcmainct.obj &
+        jcprepct.obj jccoefct.obj jccolor.obj jcsample.obj jchuff.obj &
+        jcdctmgr.obj jfdctfst.obj jfdctflt.obj jfdctint.obj
+# decompression library object files
+DLIBOBJECTS= jdapimin.obj jdapistd.obj jdarith.obj jdtrans.obj jdatasrc.obj &
+        jdmaster.obj jdinput.obj jdmarker.obj jdhuff.obj jdmainct.obj &
+        jdcoefct.obj jdpostct.obj jddctmgr.obj jidctfst.obj jidctflt.obj &
+        jidctint.obj jdsample.obj jdcolor.obj jquant1.obj jquant2.obj &
+        jdmerge.obj
+# These objectfiles are included in libjpeg.lib
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.obj rdppm.obj rdgif.obj rdtarga.obj rdrle.obj rdbmp.obj &
+        rdswitch.obj cdjpeg.obj
+DOBJECTS= djpeg.obj wrppm.obj wrgif.obj wrtarga.obj wrrle.obj wrbmp.obj &
+        rdcolmap.obj cdjpeg.obj
+TROBJECTS= jpegtran.obj rdswitch.obj cdjpeg.obj transupp.obj
+
+
+all: libjpeg.lib cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe
+
+libjpeg.lib: $(LIBOBJECTS)
+	- del libjpeg.lib
+	* wlib -n libjpeg.lib $(LIBOBJECTS)
+
+cjpeg.exe: $(COBJECTS) libjpeg.lib
+	$(CC) $(LDFLAGS) $(COBJECTS) libjpeg.lib
+
+djpeg.exe: $(DOBJECTS) libjpeg.lib
+	$(CC) $(LDFLAGS) $(DOBJECTS) libjpeg.lib
+
+jpegtran.exe: $(TROBJECTS) libjpeg.lib
+	$(CC) $(LDFLAGS) $(TROBJECTS) libjpeg.lib
+
+rdjpgcom.exe: rdjpgcom.c
+	$(CC) $(CFLAGS) $(LDFLAGS) rdjpgcom.c
+
+wrjpgcom.exe: wrjpgcom.c
+	$(CC) $(CFLAGS) $(LDFLAGS) wrjpgcom.c
+
+.c.obj:
+	$(CC) $(CFLAGS) -c $<
+
+jconfig.h: jconfig.txt
+	echo You must prepare a system-dependent jconfig.h file.
+	echo Please read the installation directions in install.txt.
+	exit 1
+
+clean: .SYMBOLIC
+	- del *.obj
+	- del libjpeg.lib
+	- del cjpeg.exe
+	- del djpeg.exe
+	- del jpegtran.exe
+	- del rdjpgcom.exe
+	- del wrjpgcom.exe
+	- del testout*.*
+
+test: cjpeg.exe djpeg.exe jpegtran.exe  .SYMBOLIC
+	- del testout*.*
+	djpeg -dct int -ppm -outfile testout.ppm  testorig.jpg
+	djpeg -dct int -bmp -colors 256 -outfile testout.bmp  testorig.jpg
+	cjpeg -dct int -outfile testout.jpg  testimg.ppm
+	djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+	cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+	jpegtran -outfile testoutt.jpg testprog.jpg
+!ifeq SYSTEM DOS
+	fc /b testimg.ppm testout.ppm
+	fc /b testimg.bmp testout.bmp
+	fc /b testimg.jpg testout.jpg
+	fc /b testimg.ppm testoutp.ppm
+	fc /b testimgp.jpg testoutp.jpg
+	fc /b testorig.jpg testoutt.jpg
+!else
+	echo n > n.tmp
+	comp testimg.ppm testout.ppm < n.tmp
+	comp testimg.bmp testout.bmp < n.tmp
+	comp testimg.jpg testout.jpg < n.tmp
+	comp testimg.ppm testoutp.ppm < n.tmp
+	comp testimgp.jpg testoutp.jpg < n.tmp
+	comp testorig.jpg testoutt.jpg < n.tmp
+	del n.tmp
+!endif
+
+
+jaricom.obj: jaricom.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapimin.obj: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.obj: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcarith.obj: jcarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.obj: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.obj: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.obj: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.obj: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcinit.obj: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.obj: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.obj: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.obj: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.obj: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.obj: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcprepct.obj: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.obj: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.obj: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.obj: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.obj: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdarith.obj: jdarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.obj: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.obj: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.obj: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.obj: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.obj: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.obj: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdinput.obj: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.obj: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.obj: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.obj: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.obj: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdpostct.obj: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.obj: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.obj: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.obj: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.obj: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.obj: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.obj: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.obj: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.obj: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.obj: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.obj: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.obj: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.obj: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.obj: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.obj: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.obj: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.obj: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.obj: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.obj: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.obj: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.obj: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.obj: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h
+rdjpgcom.obj: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.obj: wrjpgcom.c jinclude.h jconfig.h
+cdjpeg.obj: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.obj: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.obj: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+transupp.obj: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h
+rdppm.obj: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.obj: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.obj: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.obj: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.obj: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.obj: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.obj: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.obj: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.obj: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.obj: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/source/Irrlicht/jpeglib/makejdep.vc6 b/source/Irrlicht/jpeglib/makejdep.vc6
new file mode 100644
index 00000000..1065b214
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makejdep.vc6
@@ -0,0 +1,423 @@
+# Microsoft Developer Studio erstellte Abhngigkeitsdatei, einbezogen von jpeg.mak
+
+.\jaricom.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jcapimin.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jcapistd.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jcarith.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jccoefct.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jccolor.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jcdctmgr.c : \
+	".\jconfig.h"\
+	".\jdct.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jchuff.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jcinit.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jcmainct.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jcmarker.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jcmaster.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jcomapi.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jcparam.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jcprepct.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jcsample.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jctrans.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jdapimin.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jdapistd.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jdarith.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jdatadst.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	
+
+.\jdatasrc.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	
+
+.\jdcoefct.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jdcolor.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jddctmgr.c : \
+	".\jconfig.h"\
+	".\jdct.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jdhuff.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jdinput.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jdmainct.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jdmarker.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jdmaster.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jdmerge.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jdpostct.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jdsample.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jdtrans.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jerror.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	".\jversion.h"\
+	
+
+.\jfdctflt.c : \
+	".\jconfig.h"\
+	".\jdct.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jfdctfst.c : \
+	".\jconfig.h"\
+	".\jdct.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jfdctint.c : \
+	".\jconfig.h"\
+	".\jdct.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jidctflt.c : \
+	".\jconfig.h"\
+	".\jdct.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jidctfst.c : \
+	".\jconfig.h"\
+	".\jdct.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jidctint.c : \
+	".\jconfig.h"\
+	".\jdct.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jmemmgr.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmemsys.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jmemnobs.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmemsys.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jquant1.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jquant2.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
+
+.\jutils.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	
diff --git a/source/Irrlicht/jpeglib/makejdsp.vc6 b/source/Irrlicht/jpeglib/makejdsp.vc6
new file mode 100644
index 00000000..738f1ab4
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makejdsp.vc6
@@ -0,0 +1,285 @@
+# Microsoft Developer Studio Project File - Name="jpeg" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** NICHT BEARBEITEN **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=jpeg - Win32
+!MESSAGE Dies ist kein gltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und fhren Sie den Befehl
+!MESSAGE 
+!MESSAGE NMAKE /f "jpeg.mak".
+!MESSAGE 
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE 
+!MESSAGE NMAKE /f "jpeg.mak" CFG="jpeg - Win32"
+!MESSAGE 
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE 
+!MESSAGE "jpeg - Win32" (basierend auf  "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\Release"
+# PROP BASE Intermediate_Dir ".\Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\Release"
+# PROP Intermediate_Dir ".\Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD BASE RSC /l 0x407
+# ADD RSC /l 0x407
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+# Begin Target
+
+# Name "jpeg - Win32"
+# Begin Group "Quellcodedateien"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\jaricom.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcapimin.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcapistd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcarith.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jccoefct.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jccolor.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcdctmgr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jchuff.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcinit.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcmainct.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcmarker.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcmaster.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcomapi.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcparam.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcprepct.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcsample.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jctrans.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdapimin.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdapistd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdarith.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdatadst.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdatasrc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdcoefct.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdcolor.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jddctmgr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdhuff.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdinput.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdmainct.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdmarker.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdmaster.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdmerge.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdpostct.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdsample.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdtrans.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jerror.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jfdctflt.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jfdctfst.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jfdctint.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jidctflt.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jidctfst.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jidctint.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jmemmgr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jmemnobs.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jquant1.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jquant2.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jutils.c
+# End Source File
+# End Group
+# Begin Group "Header-Dateien"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\jconfig.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdct.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jerror.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jinclude.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jmemsys.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jmorecfg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jpegint.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jpeglib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jversion.h
+# End Source File
+# End Group
+# Begin Group "Ressourcendateien"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/source/Irrlicht/jpeglib/makejdsw.vc6 b/source/Irrlicht/jpeglib/makejdsw.vc6
new file mode 100644
index 00000000..d11fab1d
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makejdsw.vc6
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNUNG: DIESE ARBEITSBEREICHSDATEI DARF NICHT BEARBEITET ODER GELSCHT WERDEN!
+
+###############################################################################
+
+Project: "jpeg"=".\jpeg.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/source/Irrlicht/jpeglib/makejfil.v10 b/source/Irrlicht/jpeglib/makejfil.v10
new file mode 100644
index 00000000..654bfc09
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makejfil.v10
@@ -0,0 +1,186 @@
+
+
+  
+    
+      {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+      cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+    
+    
+      {93995380-89BD-4b04-88EB-625FBE52EBFB}
+      h;hpp;hxx;hm;inl;inc;xsd
+    
+    
+      {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+      rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+    
+  
+  
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+  
+  
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+  
+
\ No newline at end of file
diff --git a/source/Irrlicht/jpeglib/makejmak.vc6 b/source/Irrlicht/jpeglib/makejmak.vc6
new file mode 100644
index 00000000..1107336b
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makejmak.vc6
@@ -0,0 +1,425 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on jpeg.dsp
+!IF "$(CFG)" == ""
+CFG=jpeg - Win32
+!MESSAGE Keine Konfiguration angegeben. jpeg - Win32 wird als Standard verwendet.
+!ENDIF 
+
+!IF "$(CFG)" != "jpeg - Win32"
+!MESSAGE Ungltige Konfiguration "$(CFG)" angegeben.
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE 
+!MESSAGE NMAKE /f "jpeg.mak" CFG="jpeg - Win32"
+!MESSAGE 
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE 
+!MESSAGE "jpeg - Win32" (basierend auf  "Win32 (x86) Static Library")
+!MESSAGE 
+!ERROR Eine ungltige Konfiguration wurde angegeben.
+!ENDIF 
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE 
+NULL=nul
+!ENDIF 
+
+OUTDIR=.\Release
+INTDIR=.\Release
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+ALL : "$(OUTDIR)\jpeg.lib"
+
+
+CLEAN :
+	-@erase "$(INTDIR)\jaricom.obj"
+	-@erase "$(INTDIR)\jcapimin.obj"
+	-@erase "$(INTDIR)\jcapistd.obj"
+	-@erase "$(INTDIR)\jcarith.obj"
+	-@erase "$(INTDIR)\jccoefct.obj"
+	-@erase "$(INTDIR)\jccolor.obj"
+	-@erase "$(INTDIR)\jcdctmgr.obj"
+	-@erase "$(INTDIR)\jchuff.obj"
+	-@erase "$(INTDIR)\jcinit.obj"
+	-@erase "$(INTDIR)\jcmainct.obj"
+	-@erase "$(INTDIR)\jcmarker.obj"
+	-@erase "$(INTDIR)\jcmaster.obj"
+	-@erase "$(INTDIR)\jcomapi.obj"
+	-@erase "$(INTDIR)\jcparam.obj"
+	-@erase "$(INTDIR)\jcprepct.obj"
+	-@erase "$(INTDIR)\jcsample.obj"
+	-@erase "$(INTDIR)\jctrans.obj"
+	-@erase "$(INTDIR)\jdapimin.obj"
+	-@erase "$(INTDIR)\jdapistd.obj"
+	-@erase "$(INTDIR)\jdarith.obj"
+	-@erase "$(INTDIR)\jdatadst.obj"
+	-@erase "$(INTDIR)\jdatasrc.obj"
+	-@erase "$(INTDIR)\jdcoefct.obj"
+	-@erase "$(INTDIR)\jdcolor.obj"
+	-@erase "$(INTDIR)\jddctmgr.obj"
+	-@erase "$(INTDIR)\jdhuff.obj"
+	-@erase "$(INTDIR)\jdinput.obj"
+	-@erase "$(INTDIR)\jdmainct.obj"
+	-@erase "$(INTDIR)\jdmarker.obj"
+	-@erase "$(INTDIR)\jdmaster.obj"
+	-@erase "$(INTDIR)\jdmerge.obj"
+	-@erase "$(INTDIR)\jdpostct.obj"
+	-@erase "$(INTDIR)\jdsample.obj"
+	-@erase "$(INTDIR)\jdtrans.obj"
+	-@erase "$(INTDIR)\jerror.obj"
+	-@erase "$(INTDIR)\jfdctflt.obj"
+	-@erase "$(INTDIR)\jfdctfst.obj"
+	-@erase "$(INTDIR)\jfdctint.obj"
+	-@erase "$(INTDIR)\jidctflt.obj"
+	-@erase "$(INTDIR)\jidctfst.obj"
+	-@erase "$(INTDIR)\jidctint.obj"
+	-@erase "$(INTDIR)\jmemmgr.obj"
+	-@erase "$(INTDIR)\jmemnobs.obj"
+	-@erase "$(INTDIR)\jquant1.obj"
+	-@erase "$(INTDIR)\jquant2.obj"
+	-@erase "$(INTDIR)\jutils.obj"
+	-@erase "$(INTDIR)\vc60.idb"
+	-@erase "$(OUTDIR)\jpeg.lib"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fp"$(INTDIR)\jpeg.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 
+
+.c{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.c{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+RSC=rc.exe
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\jpeg.bsc" 
+BSC32_SBRS= \
+	
+LIB32=link.exe -lib
+LIB32_FLAGS=/nologo /out:"$(OUTDIR)\jpeg.lib" 
+LIB32_OBJS= \
+	"$(INTDIR)\jaricom.obj" \
+	"$(INTDIR)\jcapimin.obj" \
+	"$(INTDIR)\jcapistd.obj" \
+	"$(INTDIR)\jcarith.obj" \
+	"$(INTDIR)\jccoefct.obj" \
+	"$(INTDIR)\jccolor.obj" \
+	"$(INTDIR)\jcdctmgr.obj" \
+	"$(INTDIR)\jchuff.obj" \
+	"$(INTDIR)\jcinit.obj" \
+	"$(INTDIR)\jcmainct.obj" \
+	"$(INTDIR)\jcmarker.obj" \
+	"$(INTDIR)\jcmaster.obj" \
+	"$(INTDIR)\jcomapi.obj" \
+	"$(INTDIR)\jcparam.obj" \
+	"$(INTDIR)\jcprepct.obj" \
+	"$(INTDIR)\jcsample.obj" \
+	"$(INTDIR)\jctrans.obj" \
+	"$(INTDIR)\jdapimin.obj" \
+	"$(INTDIR)\jdapistd.obj" \
+	"$(INTDIR)\jdarith.obj" \
+	"$(INTDIR)\jdatadst.obj" \
+	"$(INTDIR)\jdatasrc.obj" \
+	"$(INTDIR)\jdcoefct.obj" \
+	"$(INTDIR)\jdcolor.obj" \
+	"$(INTDIR)\jddctmgr.obj" \
+	"$(INTDIR)\jdhuff.obj" \
+	"$(INTDIR)\jdinput.obj" \
+	"$(INTDIR)\jdmainct.obj" \
+	"$(INTDIR)\jdmarker.obj" \
+	"$(INTDIR)\jdmaster.obj" \
+	"$(INTDIR)\jdmerge.obj" \
+	"$(INTDIR)\jdpostct.obj" \
+	"$(INTDIR)\jdsample.obj" \
+	"$(INTDIR)\jdtrans.obj" \
+	"$(INTDIR)\jerror.obj" \
+	"$(INTDIR)\jfdctflt.obj" \
+	"$(INTDIR)\jfdctfst.obj" \
+	"$(INTDIR)\jfdctint.obj" \
+	"$(INTDIR)\jidctflt.obj" \
+	"$(INTDIR)\jidctfst.obj" \
+	"$(INTDIR)\jidctint.obj" \
+	"$(INTDIR)\jmemmgr.obj" \
+	"$(INTDIR)\jmemnobs.obj" \
+	"$(INTDIR)\jquant1.obj" \
+	"$(INTDIR)\jquant2.obj" \
+	"$(INTDIR)\jutils.obj"
+
+"$(OUTDIR)\jpeg.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+    $(LIB32) @<<
+  $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("jpeg.dep")
+!INCLUDE "jpeg.dep"
+!ELSE 
+!MESSAGE Warning: cannot find "jpeg.dep"
+!ENDIF 
+!ENDIF 
+
+
+!IF "$(CFG)" == "jpeg - Win32"
+SOURCE=.\jaricom.c
+
+"$(INTDIR)\jaricom.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcapimin.c
+
+"$(INTDIR)\jcapimin.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcapistd.c
+
+"$(INTDIR)\jcapistd.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcarith.c
+
+"$(INTDIR)\jcarith.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jccoefct.c
+
+"$(INTDIR)\jccoefct.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jccolor.c
+
+"$(INTDIR)\jccolor.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcdctmgr.c
+
+"$(INTDIR)\jcdctmgr.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jchuff.c
+
+"$(INTDIR)\jchuff.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcinit.c
+
+"$(INTDIR)\jcinit.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcmainct.c
+
+"$(INTDIR)\jcmainct.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcmarker.c
+
+"$(INTDIR)\jcmarker.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcmaster.c
+
+"$(INTDIR)\jcmaster.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcomapi.c
+
+"$(INTDIR)\jcomapi.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcparam.c
+
+"$(INTDIR)\jcparam.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcprepct.c
+
+"$(INTDIR)\jcprepct.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcsample.c
+
+"$(INTDIR)\jcsample.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jctrans.c
+
+"$(INTDIR)\jctrans.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdapimin.c
+
+"$(INTDIR)\jdapimin.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdapistd.c
+
+"$(INTDIR)\jdapistd.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdarith.c
+
+"$(INTDIR)\jdarith.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdatadst.c
+
+"$(INTDIR)\jdatadst.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdatasrc.c
+
+"$(INTDIR)\jdatasrc.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdcoefct.c
+
+"$(INTDIR)\jdcoefct.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdcolor.c
+
+"$(INTDIR)\jdcolor.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jddctmgr.c
+
+"$(INTDIR)\jddctmgr.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdhuff.c
+
+"$(INTDIR)\jdhuff.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdinput.c
+
+"$(INTDIR)\jdinput.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdmainct.c
+
+"$(INTDIR)\jdmainct.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdmarker.c
+
+"$(INTDIR)\jdmarker.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdmaster.c
+
+"$(INTDIR)\jdmaster.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdmerge.c
+
+"$(INTDIR)\jdmerge.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdpostct.c
+
+"$(INTDIR)\jdpostct.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdsample.c
+
+"$(INTDIR)\jdsample.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdtrans.c
+
+"$(INTDIR)\jdtrans.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jerror.c
+
+"$(INTDIR)\jerror.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jfdctflt.c
+
+"$(INTDIR)\jfdctflt.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jfdctfst.c
+
+"$(INTDIR)\jfdctfst.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jfdctint.c
+
+"$(INTDIR)\jfdctint.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jidctflt.c
+
+"$(INTDIR)\jidctflt.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jidctfst.c
+
+"$(INTDIR)\jidctfst.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jidctint.c
+
+"$(INTDIR)\jidctint.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jmemmgr.c
+
+"$(INTDIR)\jmemmgr.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jmemnobs.c
+
+"$(INTDIR)\jmemnobs.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jquant1.c
+
+"$(INTDIR)\jquant1.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jquant2.c
+
+"$(INTDIR)\jquant2.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jutils.c
+
+"$(INTDIR)\jutils.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF 
+
diff --git a/source/Irrlicht/jpeglib/makejsln.v10 b/source/Irrlicht/jpeglib/makejsln.v10
new file mode 100644
index 00000000..6a5befdf
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makejsln.v10
@@ -0,0 +1,17 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual C++ Express 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jpeg", "jpeg.vcxproj", "{019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Release|Win32.ActiveCfg = Release|Win32
+		{019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/source/Irrlicht/jpeglib/makejvcx.v10 b/source/Irrlicht/jpeglib/makejvcx.v10
new file mode 100644
index 00000000..ccee2878
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makejvcx.v10
@@ -0,0 +1,112 @@
+
+
+  
+    
+      Release
+      Win32
+    
+  
+  
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  
+  
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+      Disabled
+      false
+    
+    
+  
+  
+    {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}
+    Win32Proj
+    jpeg
+  
+  
+  
+    StaticLibrary
+    false
+    true
+    Unicode
+  
+  
+  
+  
+  
+    
+  
+  
+  
+  
+    
+      Level3
+      NotUsing
+      Full
+      true
+      false
+      WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS
+      true
+      true
+    
+    
+      Windows
+      true
+      true
+      true
+    
+  
+  
+  
+  
+
\ No newline at end of file
diff --git a/source/Irrlicht/jpeglib/makeproj.mac b/source/Irrlicht/jpeglib/makeproj.mac
new file mode 100644
index 00000000..e5b51023
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makeproj.mac
@@ -0,0 +1,213 @@
+--
+-- makeproj.mac
+--
+-- This AppleScript builds Code Warrior PRO Release 2 project files for the
+-- libjpeg library as well as the test programs 'cjpeg', 'djpeg', 'jpegtran'.
+-- (We'd distribute real project files, except they're not text
+-- and would create maintenance headaches.)
+--
+-- The script then compiles and links the library and the test programs.
+-- NOTE: if you haven't already created a 'jconfig.h' file, the script
+-- automatically copies 'jconfig.mac' to 'jconfig.h'.
+--
+-- To use this script, you must have AppleScript 1.1 or later installed
+-- and a suitable AppleScript editor like Script Editor or Script Debugger
+-- (http://www.latenightsw.com). Open this file with your AppleScript
+-- editor and execute the "run" command to build the projects.
+--
+-- Thanks to Dan Sears and Don Agro for this script.
+-- Questions about this script can be addressed to dogpark@interlog.com
+--
+
+on run
+
+	choose folder with prompt ">>> Select IJG source folder <<<"
+	set ijg_folder to result
+
+	choose folder with prompt ">>> Select MetroWerks folder <<<"
+	set cw_folder to result
+
+	-- if jconfig.h doesn't already exist, copy jconfig.mac
+
+	tell application "Finder"
+		if not (exists file "jconfig.h" of ijg_folder) then
+			duplicate {file "jconfig.mac" of folder ijg_folder}
+			select file "jconfig.mac copy" of folder ijg_folder
+			set name of selection to "jconfig.h"
+		end if
+	end tell
+
+	tell application "CodeWarrior IDE 2.1"
+	  with timeout of 10000 seconds
+
+		-- create libjpeg project
+
+		activate
+		Create Project (ijg_folder as string) & "libjpeg.proj"
+		Set Preferences of panel "Target Settings" to {Target Name:"libjpeg"}
+		Set Preferences of panel "PPC Project" to {File Name:"libjpeg"}
+		Set Preferences of panel "Target Settings" to {Linker:"MacOS PPC Linker"}
+		Set Preferences of panel "PPC Project" to {Project Type:library}
+		Set Preferences of panel "C/C++ Compiler" to {ANSI Strict:true}
+		Set Preferences of panel "C/C++ Compiler" to {Enums Always Ints:true}
+		Set Preferences of panel "PPC Codegen" to {Struct Alignment:PowerPC}
+		Set Preferences of panel "PPC Linker" to {Generate SYM File:false}
+
+		Add Files (ijg_folder as string) & "jaricom.c" To Segment 1
+		Add Files (ijg_folder as string) & "jcapimin.c" To Segment 1
+		Add Files (ijg_folder as string) & "jcapistd.c" To Segment 1
+		Add Files (ijg_folder as string) & "jcarith.c" To Segment 1
+		Add Files (ijg_folder as string) & "jctrans.c" To Segment 1
+		Add Files (ijg_folder as string) & "jcparam.c" To Segment 1
+		Add Files (ijg_folder as string) & "jdatadst.c" To Segment 1
+		Add Files (ijg_folder as string) & "jcinit.c" To Segment 1
+		Add Files (ijg_folder as string) & "jcmaster.c" To Segment 1
+		Add Files (ijg_folder as string) & "jcmarker.c" To Segment 1
+		Add Files (ijg_folder as string) & "jcmainct.c" To Segment 1
+		Add Files (ijg_folder as string) & "jcprepct.c" To Segment 1
+		Add Files (ijg_folder as string) & "jccoefct.c" To Segment 1
+		Add Files (ijg_folder as string) & "jccolor.c" To Segment 1
+		Add Files (ijg_folder as string) & "jcsample.c" To Segment 1
+		Add Files (ijg_folder as string) & "jchuff.c" To Segment 1
+		Add Files (ijg_folder as string) & "jcdctmgr.c" To Segment 1
+		Add Files (ijg_folder as string) & "jfdctfst.c" To Segment 1
+		Add Files (ijg_folder as string) & "jfdctflt.c" To Segment 1
+		Add Files (ijg_folder as string) & "jfdctint.c" To Segment 1
+		Add Files (ijg_folder as string) & "jdapimin.c" To Segment 1
+		Add Files (ijg_folder as string) & "jdapistd.c" To Segment 1
+		Add Files (ijg_folder as string) & "jdarith.c" To Segment 1
+		Add Files (ijg_folder as string) & "jdtrans.c" To Segment 1
+		Add Files (ijg_folder as string) & "jdatasrc.c" To Segment 1
+		Add Files (ijg_folder as string) & "jdmaster.c" To Segment 1
+		Add Files (ijg_folder as string) & "jdinput.c" To Segment 1
+		Add Files (ijg_folder as string) & "jdmarker.c" To Segment 1
+		Add Files (ijg_folder as string) & "jdhuff.c" To Segment 1
+		Add Files (ijg_folder as string) & "jdmainct.c" To Segment 1
+		Add Files (ijg_folder as string) & "jdcoefct.c" To Segment 1
+		Add Files (ijg_folder as string) & "jdpostct.c" To Segment 1
+		Add Files (ijg_folder as string) & "jddctmgr.c" To Segment 1
+		Add Files (ijg_folder as string) & "jidctfst.c" To Segment 1
+		Add Files (ijg_folder as string) & "jidctflt.c" To Segment 1
+		Add Files (ijg_folder as string) & "jidctint.c" To Segment 1
+		Add Files (ijg_folder as string) & "jdsample.c" To Segment 1
+		Add Files (ijg_folder as string) & "jdcolor.c" To Segment 1
+		Add Files (ijg_folder as string) & "jquant1.c" To Segment 1
+		Add Files (ijg_folder as string) & "jquant2.c" To Segment 1
+		Add Files (ijg_folder as string) & "jdmerge.c" To Segment 1
+		Add Files (ijg_folder as string) & "jcomapi.c" To Segment 1
+		Add Files (ijg_folder as string) & "jutils.c" To Segment 1
+		Add Files (ijg_folder as string) & "jerror.c" To Segment 1
+		Add Files (ijg_folder as string) & "jmemmgr.c" To Segment 1
+		Add Files (ijg_folder as string) & "jmemmac.c" To Segment 1
+
+		-- compile and link the library
+
+		Make Project
+		Close Project
+
+		-- create cjpeg project
+
+		activate
+		Create Project (ijg_folder as string) & "cjpeg.proj"
+		Set Preferences of panel "Target Settings" to {Target Name:"cjpeg"}
+		Set Preferences of panel "PPC Project" to {File Name:"cjpeg"}
+		Set Preferences of panel "Target Settings" to {Linker:"MacOS PPC Linker"}
+		Set Preferences of panel "C/C++ Compiler" to {ANSI Strict:true}
+		Set Preferences of panel "C/C++ Compiler" to {Enums Always Ints:true}
+		Set Preferences of panel "PPC Codegen" to {Struct Alignment:PowerPC}
+		Set Preferences of panel "PPC Linker" to {Generate SYM File:false}
+
+		Add Files (ijg_folder as string) & "cjpeg.c" To Segment 1
+		Add Files (ijg_folder as string) & "rdppm.c" To Segment 1
+		Add Files (ijg_folder as string) & "rdgif.c" To Segment 1
+		Add Files (ijg_folder as string) & "rdtarga.c" To Segment 1
+		Add Files (ijg_folder as string) & "rdrle.c" To Segment 1
+		Add Files (ijg_folder as string) & "rdbmp.c" To Segment 1
+		Add Files (ijg_folder as string) & "rdswitch.c" To Segment 1
+		Add Files (ijg_folder as string) & "cdjpeg.c" To Segment 1
+
+		Add Files (ijg_folder as string) & "libjpeg" To Segment 2
+
+		Add Files (cw_folder as string) & "Metrowerks CodeWarrior:Metrowerks Standard Library:MSL C:Bin:MSL C.PPC.Lib" To Segment 3
+		Add Files (cw_folder as string) & "Metrowerks CodeWarrior:Metrowerks Standard Library:MSL C:Bin:MSL SIOUX.PPC.Lib" To Segment 3
+		Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:Runtime:Runtime PPC:MSL RuntimePPC.Lib" To Segment 3
+
+		Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:MacOS Common:InterfaceLib" To Segment 4
+		Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:MacOS Common:MathLib" To Segment 4
+
+		-- compile and link cjpeg
+
+		Make Project
+		Close Project
+
+		-- create djpeg project
+
+		activate
+		Create Project (ijg_folder as string) & "djpeg.proj"
+		Set Preferences of panel "Target Settings" to {Target Name:"djpeg"}
+		Set Preferences of panel "PPC Project" to {File Name:"djpeg"}
+		Set Preferences of panel "Target Settings" to {Linker:"MacOS PPC Linker"}
+		Set Preferences of panel "C/C++ Compiler" to {ANSI Strict:true}
+		Set Preferences of panel "C/C++ Compiler" to {Enums Always Ints:true}
+		Set Preferences of panel "PPC Codegen" to {Struct Alignment:PowerPC}
+		Set Preferences of panel "PPC Linker" to {Generate SYM File:false}
+
+		Add Files (ijg_folder as string) & "djpeg.c" To Segment 1
+		Add Files (ijg_folder as string) & "wrppm.c" To Segment 1
+		Add Files (ijg_folder as string) & "wrgif.c" To Segment 1
+		Add Files (ijg_folder as string) & "wrtarga.c" To Segment 1
+		Add Files (ijg_folder as string) & "wrrle.c" To Segment 1
+		Add Files (ijg_folder as string) & "wrbmp.c" To Segment 1
+		Add Files (ijg_folder as string) & "rdcolmap.c" To Segment 1
+		Add Files (ijg_folder as string) & "cdjpeg.c" To Segment 1
+
+		Add Files (ijg_folder as string) & "libjpeg" To Segment 2
+
+		Add Files (cw_folder as string) & "Metrowerks CodeWarrior:Metrowerks Standard Library:MSL C:Bin:MSL C.PPC.Lib" To Segment 3
+		Add Files (cw_folder as string) & "Metrowerks CodeWarrior:Metrowerks Standard Library:MSL C:Bin:MSL SIOUX.PPC.Lib" To Segment 3
+		Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:Runtime:Runtime PPC:MSL RuntimePPC.Lib" To Segment 3
+
+		Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:MacOS Common:InterfaceLib" To Segment 4
+		Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:MacOS Common:MathLib" To Segment 4
+
+		-- compile and link djpeg
+
+		Make Project
+		Close Project
+
+		-- create jpegtran project
+
+		activate
+		Create Project (ijg_folder as string) & "jpegtran.proj"
+		Set Preferences of panel "Target Settings" to {Target Name:"jpegtran"}
+		Set Preferences of panel "PPC Project" to {File Name:"jpegtran"}
+		Set Preferences of panel "Target Settings" to {Linker:"MacOS PPC Linker"}
+		Set Preferences of panel "C/C++ Compiler" to {ANSI Strict:true}
+		Set Preferences of panel "C/C++ Compiler" to {Enums Always Ints:true}
+		Set Preferences of panel "PPC Codegen" to {Struct Alignment:PowerPC}
+		Set Preferences of panel "PPC Linker" to {Generate SYM File:false}
+
+		Add Files (ijg_folder as string) & "jpegtran.c" To Segment 1
+		Add Files (ijg_folder as string) & "rdswitch.c" To Segment 1
+		Add Files (ijg_folder as string) & "cdjpeg.c" To Segment 1
+		Add Files (ijg_folder as string) & "transupp.c" To Segment 1
+
+		Add Files (ijg_folder as string) & "libjpeg" To Segment 2
+
+		Add Files (cw_folder as string) & "Metrowerks CodeWarrior:Metrowerks Standard Library:MSL C:Bin:MSL C.PPC.Lib" To Segment 3
+		Add Files (cw_folder as string) & "Metrowerks CodeWarrior:Metrowerks Standard Library:MSL C:Bin:MSL SIOUX.PPC.Lib" To Segment 3
+		Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:Runtime:Runtime PPC:MSL RuntimePPC.Lib" To Segment 3
+
+		Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:MacOS Common:InterfaceLib" To Segment 4
+		Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:MacOS Common:MathLib" To Segment 4
+
+		-- compile and link jpegtran
+
+		Make Project
+		Close Project
+
+		quit
+
+	  end timeout
+	end tell
+end run
diff --git a/source/Irrlicht/jpeglib/makerdep.vc6 b/source/Irrlicht/jpeglib/makerdep.vc6
new file mode 100644
index 00000000..94748d01
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makerdep.vc6
@@ -0,0 +1,6 @@
+# Microsoft Developer Studio erstellte Abhngigkeitsdatei, einbezogen von rdjpgcom.mak
+
+.\rdjpgcom.c : \
+	".\jconfig.h"\
+	".\jinclude.h"\
+	
diff --git a/source/Irrlicht/jpeglib/makerdsp.vc6 b/source/Irrlicht/jpeglib/makerdsp.vc6
new file mode 100644
index 00000000..60de09af
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makerdsp.vc6
@@ -0,0 +1,78 @@
+# Microsoft Developer Studio Project File - Name="rdjpgcom" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** NICHT BEARBEITEN **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=rdjpgcom - Win32
+!MESSAGE Dies ist kein gltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und fhren Sie den Befehl
+!MESSAGE 
+!MESSAGE NMAKE /f "rdjpgcom.mak".
+!MESSAGE 
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE 
+!MESSAGE NMAKE /f "rdjpgcom.mak" CFG="rdjpgcom - Win32"
+!MESSAGE 
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE 
+!MESSAGE "rdjpgcom - Win32" (basierend auf  "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\rdjpgcom\Release"
+# PROP BASE Intermediate_Dir ".\rdjpgcom\Release"
+# PROP BASE Target_Dir ".\rdjpgcom"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\rdjpgcom\Release"
+# PROP Intermediate_Dir ".\rdjpgcom\Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ".\rdjpgcom"
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# Begin Target
+
+# Name "rdjpgcom - Win32"
+# Begin Group "Quellcodedateien"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\rdjpgcom.c
+# End Source File
+# End Group
+# Begin Group "Header-Dateien"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\jconfig.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jinclude.h
+# End Source File
+# End Group
+# Begin Group "Ressourcendateien"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/source/Irrlicht/jpeglib/makerfil.v10 b/source/Irrlicht/jpeglib/makerfil.v10
new file mode 100644
index 00000000..d14914af
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makerfil.v10
@@ -0,0 +1,30 @@
+
+
+  
+    
+      {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+      cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+    
+    
+      {93995380-89BD-4b04-88EB-625FBE52EBFB}
+      h;hpp;hxx;hm;inl;inc;xsd
+    
+    
+      {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+      rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+    
+  
+  
+    
+      Header Files
+    
+    
+      Header Files
+    
+  
+  
+    
+      Source Files
+    
+  
+
\ No newline at end of file
diff --git a/source/Irrlicht/jpeglib/makermak.vc6 b/source/Irrlicht/jpeglib/makermak.vc6
new file mode 100644
index 00000000..6d2d4c73
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makermak.vc6
@@ -0,0 +1,110 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on rdjpgcom.dsp
+!IF "$(CFG)" == ""
+CFG=rdjpgcom - Win32
+!MESSAGE Keine Konfiguration angegeben. rdjpgcom - Win32 wird als Standard verwendet.
+!ENDIF 
+
+!IF "$(CFG)" != "rdjpgcom - Win32"
+!MESSAGE Ungltige Konfiguration "$(CFG)" angegeben.
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE 
+!MESSAGE NMAKE /f "rdjpgcom.mak" CFG="rdjpgcom - Win32"
+!MESSAGE 
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE 
+!MESSAGE "rdjpgcom - Win32" (basierend auf  "Win32 (x86) Console Application")
+!MESSAGE 
+!ERROR Eine ungltige Konfiguration wurde angegeben.
+!ENDIF 
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE 
+NULL=nul
+!ENDIF 
+
+CPP=cl.exe
+RSC=rc.exe
+OUTDIR=.\rdjpgcom\Release
+INTDIR=.\rdjpgcom\Release
+# Begin Custom Macros
+OutDir=.\rdjpgcom\Release
+# End Custom Macros
+
+ALL : "$(OUTDIR)\rdjpgcom.exe"
+
+
+CLEAN :
+	-@erase "$(INTDIR)\rdjpgcom.obj"
+	-@erase "$(INTDIR)\vc60.idb"
+	-@erase "$(OUTDIR)\rdjpgcom.exe"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\rdjpgcom.bsc" 
+BSC32_SBRS= \
+	
+LINK32=link.exe
+LINK32_FLAGS=Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\rdjpgcom.pdb" /machine:I386 /out:"$(OUTDIR)\rdjpgcom.exe" 
+LINK32_OBJS= \
+	"$(INTDIR)\rdjpgcom.obj"
+
+"$(OUTDIR)\rdjpgcom.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+CPP_PROJ=/nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /Fp"$(INTDIR)\rdjpgcom.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 
+
+.c{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.c{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("rdjpgcom.dep")
+!INCLUDE "rdjpgcom.dep"
+!ELSE 
+!MESSAGE Warning: cannot find "rdjpgcom.dep"
+!ENDIF 
+!ENDIF 
+
+
+!IF "$(CFG)" == "rdjpgcom - Win32"
+SOURCE=.\rdjpgcom.c
+
+"$(INTDIR)\rdjpgcom.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF 
+
diff --git a/source/Irrlicht/jpeglib/makervcx.v10 b/source/Irrlicht/jpeglib/makervcx.v10
new file mode 100644
index 00000000..366d4fcb
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makervcx.v10
@@ -0,0 +1,62 @@
+
+
+  
+    
+      Release
+      Win32
+    
+  
+  
+    {C81513DB-78DC-46BC-BC98-82E745203976}
+    Win32Proj
+    rdjpgcom
+  
+  
+  
+    Application
+    false
+    true
+    Unicode
+  
+  
+  
+  
+  
+    
+  
+  
+  
+    false
+    $(ProjectName)\$(Configuration)\
+    $(ProjectName)\$(Configuration)\
+  
+  
+    
+      Level3
+      NotUsing
+      Full
+      true
+      false
+      WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS
+      true
+      true
+      4996
+    
+    
+      Console
+      true
+      true
+      true
+    
+  
+  
+    
+    
+  
+  
+    
+  
+  
+  
+  
+
\ No newline at end of file
diff --git a/source/Irrlicht/jpeglib/maketdep.vc6 b/source/Irrlicht/jpeglib/maketdep.vc6
new file mode 100644
index 00000000..e177ecbf
--- /dev/null
+++ b/source/Irrlicht/jpeglib/maketdep.vc6
@@ -0,0 +1,43 @@
+# Microsoft Developer Studio erstellte Abhngigkeitsdatei, einbezogen von jpegtran.mak
+
+.\cdjpeg.c : \
+	".\cderror.h"\
+	".\cdjpeg.h"\
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	
+
+.\jpegtran.c : \
+	".\cderror.h"\
+	".\cdjpeg.h"\
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	".\jversion.h"\
+	".\transupp.h"\
+	
+
+.\rdswitch.c : \
+	".\cderror.h"\
+	".\cdjpeg.h"\
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpeglib.h"\
+	
+
+.\transupp.c : \
+	".\jconfig.h"\
+	".\jerror.h"\
+	".\jinclude.h"\
+	".\jmorecfg.h"\
+	".\jpegint.h"\
+	".\jpeglib.h"\
+	".\transupp.h"\
+	
diff --git a/source/Irrlicht/jpeglib/maketdsp.vc6 b/source/Irrlicht/jpeglib/maketdsp.vc6
new file mode 100644
index 00000000..fe1ae9a3
--- /dev/null
+++ b/source/Irrlicht/jpeglib/maketdsp.vc6
@@ -0,0 +1,122 @@
+# Microsoft Developer Studio Project File - Name="jpegtran" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** NICHT BEARBEITEN **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=jpegtran - Win32
+!MESSAGE Dies ist kein gltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und fhren Sie den Befehl
+!MESSAGE 
+!MESSAGE NMAKE /f "jpegtran.mak".
+!MESSAGE 
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE 
+!MESSAGE NMAKE /f "jpegtran.mak" CFG="jpegtran - Win32"
+!MESSAGE 
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE 
+!MESSAGE "jpegtran - Win32" (basierend auf  "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\jpegtran\Release"
+# PROP BASE Intermediate_Dir ".\jpegtran\Release"
+# PROP BASE Target_Dir ".\jpegtran"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\jpegtran\Release"
+# PROP Intermediate_Dir ".\jpegtran\Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ".\jpegtran"
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# Begin Target
+
+# Name "jpegtran - Win32"
+# Begin Group "Quellcodedateien"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\cdjpeg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jpegtran.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rdswitch.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\transupp.c
+# End Source File
+# End Group
+# Begin Group "Header-Dateien"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\cderror.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\cdjpeg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jconfig.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jerror.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jinclude.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jmorecfg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jpegint.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jpeglib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jversion.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\transupp.h
+# End Source File
+# End Group
+# Begin Group "Ressourcendateien"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/source/Irrlicht/jpeglib/maketfil.v10 b/source/Irrlicht/jpeglib/maketfil.v10
new file mode 100644
index 00000000..fae00941
--- /dev/null
+++ b/source/Irrlicht/jpeglib/maketfil.v10
@@ -0,0 +1,63 @@
+
+
+  
+    
+      {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+      cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+    
+    
+      {93995380-89BD-4b04-88EB-625FBE52EBFB}
+      h;hpp;hxx;hm;inl;inc;xsd
+    
+    
+      {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+      rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+    
+  
+  
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+  
+  
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+  
+
\ No newline at end of file
diff --git a/source/Irrlicht/jpeglib/maketmak.vc6 b/source/Irrlicht/jpeglib/maketmak.vc6
new file mode 100644
index 00000000..a0de38c0
--- /dev/null
+++ b/source/Irrlicht/jpeglib/maketmak.vc6
@@ -0,0 +1,131 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on jpegtran.dsp
+!IF "$(CFG)" == ""
+CFG=jpegtran - Win32
+!MESSAGE Keine Konfiguration angegeben. jpegtran - Win32 wird als Standard verwendet.
+!ENDIF 
+
+!IF "$(CFG)" != "jpegtran - Win32"
+!MESSAGE Ungltige Konfiguration "$(CFG)" angegeben.
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE 
+!MESSAGE NMAKE /f "jpegtran.mak" CFG="jpegtran - Win32"
+!MESSAGE 
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE 
+!MESSAGE "jpegtran - Win32" (basierend auf  "Win32 (x86) Console Application")
+!MESSAGE 
+!ERROR Eine ungltige Konfiguration wurde angegeben.
+!ENDIF 
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE 
+NULL=nul
+!ENDIF 
+
+CPP=cl.exe
+RSC=rc.exe
+OUTDIR=.\jpegtran\Release
+INTDIR=.\jpegtran\Release
+# Begin Custom Macros
+OutDir=.\jpegtran\Release
+# End Custom Macros
+
+ALL : "$(OUTDIR)\jpegtran.exe"
+
+
+CLEAN :
+	-@erase "$(INTDIR)\cdjpeg.obj"
+	-@erase "$(INTDIR)\jpegtran.obj"
+	-@erase "$(INTDIR)\rdswitch.obj"
+	-@erase "$(INTDIR)\transupp.obj"
+	-@erase "$(INTDIR)\vc60.idb"
+	-@erase "$(OUTDIR)\jpegtran.exe"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\jpegtran.bsc" 
+BSC32_SBRS= \
+	
+LINK32=link.exe
+LINK32_FLAGS=Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\jpegtran.pdb" /machine:I386 /out:"$(OUTDIR)\jpegtran.exe" 
+LINK32_OBJS= \
+	"$(INTDIR)\cdjpeg.obj" \
+	"$(INTDIR)\jpegtran.obj" \
+	"$(INTDIR)\rdswitch.obj" \
+	"$(INTDIR)\transupp.obj"
+
+"$(OUTDIR)\jpegtran.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+CPP_PROJ=/nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /Fp"$(INTDIR)\jpegtran.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 
+
+.c{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.c{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("jpegtran.dep")
+!INCLUDE "jpegtran.dep"
+!ELSE 
+!MESSAGE Warning: cannot find "jpegtran.dep"
+!ENDIF 
+!ENDIF 
+
+
+!IF "$(CFG)" == "jpegtran - Win32"
+SOURCE=.\cdjpeg.c
+
+"$(INTDIR)\cdjpeg.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jpegtran.c
+
+"$(INTDIR)\jpegtran.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\rdswitch.c
+
+"$(INTDIR)\rdswitch.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\transupp.c
+
+"$(INTDIR)\transupp.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF 
+
diff --git a/source/Irrlicht/jpeglib/maketvcx.v10 b/source/Irrlicht/jpeglib/maketvcx.v10
new file mode 100644
index 00000000..e2b4ea36
--- /dev/null
+++ b/source/Irrlicht/jpeglib/maketvcx.v10
@@ -0,0 +1,74 @@
+
+
+  
+    
+      Release
+      Win32
+    
+  
+  
+    {025BAC50-51B5-4FFE-BC47-3F920BB4047E}
+    Win32Proj
+    jpegtran
+  
+  
+  
+    Application
+    false
+    true
+    Unicode
+  
+  
+  
+  
+  
+    
+  
+  
+  
+    false
+    $(ProjectName)\$(Configuration)\
+    $(ProjectName)\$(Configuration)\
+  
+  
+    
+      Level3
+      NotUsing
+      Full
+      true
+      false
+      WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS
+      true
+      true
+      4996
+    
+    
+      Console
+      true
+      true
+      true
+      Release\jpeg.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+    
+  
+  
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  
+  
+    
+    
+    
+    
+  
+  
+  
+  
+
\ No newline at end of file
diff --git a/source/Irrlicht/jpeglib/makewdep.vc6 b/source/Irrlicht/jpeglib/makewdep.vc6
new file mode 100644
index 00000000..15929bfe
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makewdep.vc6
@@ -0,0 +1,6 @@
+# Microsoft Developer Studio erstellte Abhngigkeitsdatei, einbezogen von wrjpgcom.mak
+
+.\wrjpgcom.c : \
+	".\jconfig.h"\
+	".\jinclude.h"\
+	
diff --git a/source/Irrlicht/jpeglib/makewdsp.vc6 b/source/Irrlicht/jpeglib/makewdsp.vc6
new file mode 100644
index 00000000..2063b1a5
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makewdsp.vc6
@@ -0,0 +1,78 @@
+# Microsoft Developer Studio Project File - Name="wrjpgcom" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** NICHT BEARBEITEN **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=wrjpgcom - Win32
+!MESSAGE Dies ist kein gltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und fhren Sie den Befehl
+!MESSAGE 
+!MESSAGE NMAKE /f "wrjpgcom.mak".
+!MESSAGE 
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE 
+!MESSAGE NMAKE /f "wrjpgcom.mak" CFG="wrjpgcom - Win32"
+!MESSAGE 
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE 
+!MESSAGE "wrjpgcom - Win32" (basierend auf  "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\wrjpgcom\Release"
+# PROP BASE Intermediate_Dir ".\wrjpgcom\Release"
+# PROP BASE Target_Dir ".\wrjpgcom"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\wrjpgcom\Release"
+# PROP Intermediate_Dir ".\wrjpgcom\Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ".\wrjpgcom"
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# Begin Target
+
+# Name "wrjpgcom - Win32"
+# Begin Group "Quellcodedateien"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\wrjpgcom.c
+# End Source File
+# End Group
+# Begin Group "Header-Dateien"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\jconfig.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jinclude.h
+# End Source File
+# End Group
+# Begin Group "Ressourcendateien"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/source/Irrlicht/jpeglib/makewfil.v10 b/source/Irrlicht/jpeglib/makewfil.v10
new file mode 100644
index 00000000..72c58566
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makewfil.v10
@@ -0,0 +1,30 @@
+
+
+  
+    
+      {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+      cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+    
+    
+      {93995380-89BD-4b04-88EB-625FBE52EBFB}
+      h;hpp;hxx;hm;inl;inc;xsd
+    
+    
+      {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+      rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+    
+  
+  
+    
+      Header Files
+    
+    
+      Header Files
+    
+  
+  
+    
+      Source Files
+    
+  
+
\ No newline at end of file
diff --git a/source/Irrlicht/jpeglib/makewmak.vc6 b/source/Irrlicht/jpeglib/makewmak.vc6
new file mode 100644
index 00000000..22b90862
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makewmak.vc6
@@ -0,0 +1,110 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on wrjpgcom.dsp
+!IF "$(CFG)" == ""
+CFG=wrjpgcom - Win32
+!MESSAGE Keine Konfiguration angegeben. wrjpgcom - Win32 wird als Standard verwendet.
+!ENDIF 
+
+!IF "$(CFG)" != "wrjpgcom - Win32"
+!MESSAGE Ungltige Konfiguration "$(CFG)" angegeben.
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE 
+!MESSAGE NMAKE /f "wrjpgcom.mak" CFG="wrjpgcom - Win32"
+!MESSAGE 
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE 
+!MESSAGE "wrjpgcom - Win32" (basierend auf  "Win32 (x86) Console Application")
+!MESSAGE 
+!ERROR Eine ungltige Konfiguration wurde angegeben.
+!ENDIF 
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE 
+NULL=nul
+!ENDIF 
+
+CPP=cl.exe
+RSC=rc.exe
+OUTDIR=.\wrjpgcom\Release
+INTDIR=.\wrjpgcom\Release
+# Begin Custom Macros
+OutDir=.\wrjpgcom\Release
+# End Custom Macros
+
+ALL : "$(OUTDIR)\wrjpgcom.exe"
+
+
+CLEAN :
+	-@erase "$(INTDIR)\vc60.idb"
+	-@erase "$(INTDIR)\wrjpgcom.obj"
+	-@erase "$(OUTDIR)\wrjpgcom.exe"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\wrjpgcom.bsc" 
+BSC32_SBRS= \
+	
+LINK32=link.exe
+LINK32_FLAGS=Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\wrjpgcom.pdb" /machine:I386 /out:"$(OUTDIR)\wrjpgcom.exe" 
+LINK32_OBJS= \
+	"$(INTDIR)\wrjpgcom.obj"
+
+"$(OUTDIR)\wrjpgcom.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+CPP_PROJ=/nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /Fp"$(INTDIR)\wrjpgcom.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 
+
+.c{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.c{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("wrjpgcom.dep")
+!INCLUDE "wrjpgcom.dep"
+!ELSE 
+!MESSAGE Warning: cannot find "wrjpgcom.dep"
+!ENDIF 
+!ENDIF 
+
+
+!IF "$(CFG)" == "wrjpgcom - Win32"
+SOURCE=.\wrjpgcom.c
+
+"$(INTDIR)\wrjpgcom.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF 
+
diff --git a/source/Irrlicht/jpeglib/makewvcx.v10 b/source/Irrlicht/jpeglib/makewvcx.v10
new file mode 100644
index 00000000..e6c546af
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makewvcx.v10
@@ -0,0 +1,62 @@
+
+
+  
+    
+      Release
+      Win32
+    
+  
+  
+    {B57065D4-DDDA-4668-BAF5-2D49270C973C}
+    Win32Proj
+    wrjpgcom
+  
+  
+  
+    Application
+    false
+    true
+    Unicode
+  
+  
+  
+  
+  
+    
+  
+  
+  
+    false
+    $(ProjectName)\$(Configuration)\
+    $(ProjectName)\$(Configuration)\
+  
+  
+    
+      Level3
+      NotUsing
+      Full
+      true
+      false
+      WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS
+      true
+      true
+      4996
+    
+    
+      Console
+      true
+      true
+      true
+    
+  
+  
+    
+    
+  
+  
+    
+  
+  
+  
+  
+
\ No newline at end of file
diff --git a/source/Irrlicht/jpeglib/makljpeg.st b/source/Irrlicht/jpeglib/makljpeg.st
new file mode 100644
index 00000000..cc1ba015
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makljpeg.st
@@ -0,0 +1,68 @@
+; Project file for Independent JPEG Group's software
+;
+; This project file is for Atari ST/STE/TT systems using Pure C or Turbo C.
+; Thanks to Frank Moehle, B. Setzepfandt, and Guido Vollbeding.
+;
+; To use this file, rename it to libjpeg.prj.
+; Read installation instructions before trying to make the program!
+;
+;
+;      * * * Output file * * *
+libjpeg.lib
+;
+; * * * COMPILER OPTIONS * * *  
+.C[-P]        ; absolute calls
+.C[-M]        ; and no string merging, folks
+.C[-w-cln]    ; no "constant is long" warnings
+.C[-w-par]    ; no "parameter xxxx unused"
+.C[-w-rch]    ; no "unreachable code"
+.C[-wsig]     ; warn if significant digits may be lost
+.L[-J]        ; link new Obj-format (so we get a library)
+=
+; * * * * List of modules * * * * 
+jaricom.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcapimin.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcapistd.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcarith.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jccoefct.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jccolor.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcdctmgr.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jchuff.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcinit.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcmainct.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcmarker.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcmaster.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcomapi.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcparam.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcprepct.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcsample.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jctrans.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdapimin.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdapistd.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdarith.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdatadst.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h)
+jdatasrc.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h)
+jdcoefct.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdcolor.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jddctmgr.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jdhuff.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdinput.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdmainct.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdmarker.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdmaster.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdmerge.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdpostct.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdsample.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdtrans.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jerror.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jversion.h,jerror.h)
+jfdctflt.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jfdctfst.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jfdctint.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jidctflt.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jidctfst.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jidctint.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jquant1.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jquant2.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jutils.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jmemmgr.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jmemsys.h)
+jmemansi.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jmemsys.h)
diff --git a/source/Irrlicht/jpeglib/maktjpeg.st b/source/Irrlicht/jpeglib/maktjpeg.st
new file mode 100644
index 00000000..43f078a9
--- /dev/null
+++ b/source/Irrlicht/jpeglib/maktjpeg.st
@@ -0,0 +1,30 @@
+; Project file for Independent JPEG Group's software
+;
+; This project file is for Atari ST/STE/TT systems using Pure C or Turbo C.
+; Thanks to Frank Moehle, B. Setzepfandt, and Guido Vollbeding.
+;
+; To use this file, rename it to jpegtran.prj.
+; If you are using Turbo C, change filenames beginning with "pc..." to "tc..."
+; Read installation instructions before trying to make the program!
+;
+;
+;      * * * Output file * * *
+jpegtran.ttp
+;
+; * * * COMPILER OPTIONS * * *  
+.C[-P]        ; absolute calls
+.C[-M]        ; and no string merging, folks
+.C[-w-cln]    ; no "constant is long" warnings
+.C[-w-par]    ; no "parameter xxxx unused"
+.C[-w-rch]    ; no "unreachable code"
+.C[-wsig]     ; warn if significant digits may be lost
+=
+; * * * * List of modules * * * * 
+pcstart.o
+jpegtran.c	(cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h,transupp.h,jversion.h)
+cdjpeg.c	(cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdswitch.c	(cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+transupp.c	(jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,transupp.h)
+libjpeg.lib        ; built by libjpeg.prj
+pcstdlib.lib       ; standard library
+pcextlib.lib       ; extended library
diff --git a/source/Irrlicht/jpeglib/makvms.opt b/source/Irrlicht/jpeglib/makvms.opt
new file mode 100644
index 00000000..675e8fe9
--- /dev/null
+++ b/source/Irrlicht/jpeglib/makvms.opt
@@ -0,0 +1,4 @@
+! A pointer to the VAX/VMS C Run-Time Shareable Library.
+! This file is needed by makefile.mms and makefile.vms,
+! but only for the older VAX C compiler.  DEC C does not need it.
+Sys$Library:VAXCRTL.EXE /Share
diff --git a/source/Irrlicht/jpeglib/missing b/source/Irrlicht/jpeglib/missing
new file mode 100644
index 00000000..db98974f
--- /dev/null
+++ b/source/Irrlicht/jpeglib/missing
@@ -0,0 +1,215 @@
+#! /bin/sh
+# Common wrapper for a few potentially missing GNU programs.
+
+scriptversion=2013-10-28.13; # UTC
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Originally written by Fran,cois Pinard , 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see .
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try '$0 --help' for more information"
+  exit 1
+fi
+
+case $1 in
+
+  --is-lightweight)
+    # Used by our autoconf macros to check whether the available missing
+    # script is modern enough.
+    exit 0
+    ;;
+
+  --run)
+    # Back-compat with the calling convention used by older automake.
+    shift
+    ;;
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
+to PROGRAM being missing or too old.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+
+Supported PROGRAM values:
+  aclocal   autoconf  autoheader   autom4te  automake  makeinfo
+  bison     yacc      flex         lex       help2man
+
+Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
+'g' are ignored when checking the name.
+
+Send bug reports to ."
+    exit $?
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing $scriptversion (GNU Automake)"
+    exit $?
+    ;;
+
+  -*)
+    echo 1>&2 "$0: unknown '$1' option"
+    echo 1>&2 "Try '$0 --help' for more information"
+    exit 1
+    ;;
+
+esac
+
+# Run the given program, remember its exit status.
+"$@"; st=$?
+
+# If it succeeded, we are done.
+test $st -eq 0 && exit 0
+
+# Also exit now if we it failed (or wasn't found), and '--version' was
+# passed; such an option is passed most likely to detect whether the
+# program is present and works.
+case $2 in --version|--help) exit $st;; esac
+
+# Exit code 63 means version mismatch.  This often happens when the user
+# tries to use an ancient version of a tool on a file that requires a
+# minimum version.
+if test $st -eq 63; then
+  msg="probably too old"
+elif test $st -eq 127; then
+  # Program was missing.
+  msg="missing on your system"
+else
+  # Program was found and executed, but failed.  Give up.
+  exit $st
+fi
+
+perl_URL=http://www.perl.org/
+flex_URL=http://flex.sourceforge.net/
+gnu_software_URL=http://www.gnu.org/software
+
+program_details ()
+{
+  case $1 in
+    aclocal|automake)
+      echo "The '$1' program is part of the GNU Automake package:"
+      echo "<$gnu_software_URL/automake>"
+      echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
+      echo "<$gnu_software_URL/autoconf>"
+      echo "<$gnu_software_URL/m4/>"
+      echo "<$perl_URL>"
+      ;;
+    autoconf|autom4te|autoheader)
+      echo "The '$1' program is part of the GNU Autoconf package:"
+      echo "<$gnu_software_URL/autoconf/>"
+      echo "It also requires GNU m4 and Perl in order to run:"
+      echo "<$gnu_software_URL/m4/>"
+      echo "<$perl_URL>"
+      ;;
+  esac
+}
+
+give_advice ()
+{
+  # Normalize program name to check for.
+  normalized_program=`echo "$1" | sed '
+    s/^gnu-//; t
+    s/^gnu//; t
+    s/^g//; t'`
+
+  printf '%s\n' "'$1' is $msg."
+
+  configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
+  case $normalized_program in
+    autoconf*)
+      echo "You should only need it if you modified 'configure.ac',"
+      echo "or m4 files included by it."
+      program_details 'autoconf'
+      ;;
+    autoheader*)
+      echo "You should only need it if you modified 'acconfig.h' or"
+      echo "$configure_deps."
+      program_details 'autoheader'
+      ;;
+    automake*)
+      echo "You should only need it if you modified 'Makefile.am' or"
+      echo "$configure_deps."
+      program_details 'automake'
+      ;;
+    aclocal*)
+      echo "You should only need it if you modified 'acinclude.m4' or"
+      echo "$configure_deps."
+      program_details 'aclocal'
+      ;;
+   autom4te*)
+      echo "You might have modified some maintainer files that require"
+      echo "the 'autom4te' program to be rebuilt."
+      program_details 'autom4te'
+      ;;
+    bison*|yacc*)
+      echo "You should only need it if you modified a '.y' file."
+      echo "You may want to install the GNU Bison package:"
+      echo "<$gnu_software_URL/bison/>"
+      ;;
+    lex*|flex*)
+      echo "You should only need it if you modified a '.l' file."
+      echo "You may want to install the Fast Lexical Analyzer package:"
+      echo "<$flex_URL>"
+      ;;
+    help2man*)
+      echo "You should only need it if you modified a dependency" \
+           "of a man page."
+      echo "You may want to install the GNU Help2man package:"
+      echo "<$gnu_software_URL/help2man/>"
+    ;;
+    makeinfo*)
+      echo "You should only need it if you modified a '.texi' file, or"
+      echo "any other file indirectly affecting the aspect of the manual."
+      echo "You might want to install the Texinfo package:"
+      echo "<$gnu_software_URL/texinfo/>"
+      echo "The spurious makeinfo call might also be the consequence of"
+      echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
+      echo "want to install GNU make:"
+      echo "<$gnu_software_URL/make/>"
+      ;;
+    *)
+      echo "You might have modified some files without having the proper"
+      echo "tools for further handling them.  Check the 'README' file, it"
+      echo "often tells you about the needed prerequisites for installing"
+      echo "this package.  You may also peek at any GNU archive site, in"
+      echo "case some other package contains this missing '$1' program."
+      ;;
+  esac
+}
+
+give_advice "$1" | sed -e '1s/^/WARNING: /' \
+                       -e '2,$s/^/         /' >&2
+
+# Propagate the correct exit status (expected to be 127 for a program
+# not found, 63 for a program that failed due to version mismatch).
+exit $st
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/source/Irrlicht/jpeglib/rdbmp.c b/source/Irrlicht/jpeglib/rdbmp.c
new file mode 100644
index 00000000..dfdf96ff
--- /dev/null
+++ b/source/Irrlicht/jpeglib/rdbmp.c
@@ -0,0 +1,480 @@
+/*
+ * rdbmp.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2009-2010 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to read input images in Microsoft "BMP"
+ * format (MS Windows 3.x, OS/2 1.x, and OS/2 2.x flavors).
+ * Currently, only 8-bit and 24-bit images are supported, not 1-bit or
+ * 4-bit (feeding such low-depth images into JPEG would be silly anyway).
+ * Also, we don't support RLE-compressed files.
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications.  As they stand, they assume input from
+ * an ordinary stdio stream.  They further assume that reading begins
+ * at the start of the file; start_input may need work if the
+ * user interface has already read some data (e.g., to determine that
+ * the file is indeed BMP format).
+ *
+ * This code contributed by James Arthur Boucher.
+ */
+
+#include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
+
+#ifdef BMP_SUPPORTED
+
+
+/* Macros to deal with unsigned chars as efficiently as compiler allows */
+
+#ifdef HAVE_UNSIGNED_CHAR
+typedef unsigned char U_CHAR;
+#define UCH(x)	((int) (x))
+#else /* !HAVE_UNSIGNED_CHAR */
+#ifdef CHAR_IS_UNSIGNED
+typedef char U_CHAR;
+#define UCH(x)	((int) (x))
+#else
+typedef char U_CHAR;
+#define UCH(x)	((int) (x) & 0xFF)
+#endif
+#endif /* HAVE_UNSIGNED_CHAR */
+
+
+#define	ReadOK(file,buffer,len)	(JFREAD(file,buffer,len) == ((size_t) (len)))
+
+
+/* Private version of data source object */
+
+typedef struct _bmp_source_struct * bmp_source_ptr;
+
+typedef struct _bmp_source_struct {
+  struct cjpeg_source_struct pub; /* public fields */
+
+  j_compress_ptr cinfo;		/* back link saves passing separate parm */
+
+  JSAMPARRAY colormap;		/* BMP colormap (converted to my format) */
+
+  jvirt_sarray_ptr whole_image;	/* Needed to reverse row order */
+  JDIMENSION source_row;	/* Current source row number */
+  JDIMENSION row_width;		/* Physical width of scanlines in file */
+
+  int bits_per_pixel;		/* remembers 8- or 24-bit format */
+} bmp_source_struct;
+
+
+LOCAL(int)
+read_byte (bmp_source_ptr sinfo)
+/* Read next byte from BMP file */
+{
+  register FILE *infile = sinfo->pub.input_file;
+  register int c;
+
+  if ((c = getc(infile)) == EOF)
+    ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
+  return c;
+}
+
+
+LOCAL(void)
+read_colormap (bmp_source_ptr sinfo, int cmaplen, int mapentrysize)
+/* Read the colormap from a BMP file */
+{
+  int i;
+
+  switch (mapentrysize) {
+  case 3:
+    /* BGR format (occurs in OS/2 files) */
+    for (i = 0; i < cmaplen; i++) {
+      sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo);
+      sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo);
+      sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo);
+    }
+    break;
+  case 4:
+    /* BGR0 format (occurs in MS Windows files) */
+    for (i = 0; i < cmaplen; i++) {
+      sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo);
+      sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo);
+      sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo);
+      (void) read_byte(sinfo);
+    }
+    break;
+  default:
+    ERREXIT(sinfo->cinfo, JERR_BMP_BADCMAP);
+    break;
+  }
+}
+
+
+/*
+ * Read one row of pixels.
+ * The image has been read into the whole_image array, but is otherwise
+ * unprocessed.  We must read it out in top-to-bottom row order, and if
+ * it is an 8-bit image, we must expand colormapped pixels to 24bit format.
+ */
+
+METHODDEF(JDIMENSION)
+get_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 8-bit colormap indexes */
+{
+  bmp_source_ptr source = (bmp_source_ptr) sinfo;
+  register JSAMPARRAY colormap = source->colormap;
+  JSAMPARRAY image_ptr;
+  register int t;
+  register JSAMPROW inptr, outptr;
+  register JDIMENSION col;
+
+  /* Fetch next row from virtual array */
+  source->source_row--;
+  image_ptr = (*cinfo->mem->access_virt_sarray)
+    ((j_common_ptr) cinfo, source->whole_image,
+     source->source_row, (JDIMENSION) 1, FALSE);
+
+  /* Expand the colormap indexes to real data */
+  inptr = image_ptr[0];
+  outptr = source->pub.buffer[0];
+  for (col = cinfo->image_width; col > 0; col--) {
+    t = GETJSAMPLE(*inptr++);
+    *outptr++ = colormap[0][t];	/* can omit GETJSAMPLE() safely */
+    *outptr++ = colormap[1][t];
+    *outptr++ = colormap[2][t];
+  }
+
+  return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 24-bit pixels */
+{
+  bmp_source_ptr source = (bmp_source_ptr) sinfo;
+  JSAMPARRAY image_ptr;
+  register JSAMPROW inptr, outptr;
+  register JDIMENSION col;
+
+  /* Fetch next row from virtual array */
+  source->source_row--;
+  image_ptr = (*cinfo->mem->access_virt_sarray)
+    ((j_common_ptr) cinfo, source->whole_image,
+     source->source_row, (JDIMENSION) 1, FALSE);
+
+  /* Transfer data.  Note source values are in BGR order
+   * (even though Microsoft's own documents say the opposite).
+   */
+  inptr = image_ptr[0];
+  outptr = source->pub.buffer[0];
+  for (col = cinfo->image_width; col > 0; col--) {
+    outptr[2] = *inptr++;	/* can omit GETJSAMPLE() safely */
+    outptr[1] = *inptr++;
+    outptr[0] = *inptr++;
+    outptr += 3;
+  }
+
+  return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_32bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 32-bit pixels */
+{
+  bmp_source_ptr source = (bmp_source_ptr) sinfo;
+  JSAMPARRAY image_ptr;
+  register JSAMPROW inptr, outptr;
+  register JDIMENSION col;
+
+  /* Fetch next row from virtual array */
+  source->source_row--;
+  image_ptr = (*cinfo->mem->access_virt_sarray)
+    ((j_common_ptr) cinfo, source->whole_image,
+     source->source_row, (JDIMENSION) 1, FALSE);
+  /* Transfer data.  Note source values are in BGR order
+   * (even though Microsoft's own documents say the opposite).
+   */
+  inptr = image_ptr[0];
+  outptr = source->pub.buffer[0];
+  for (col = cinfo->image_width; col > 0; col--) {
+    outptr[2] = *inptr++;	/* can omit GETJSAMPLE() safely */
+    outptr[1] = *inptr++;
+    outptr[0] = *inptr++;
+    inptr++;			/* skip the 4th byte (Alpha channel) */
+    outptr += 3;
+  }
+
+  return 1;
+}
+
+
+/*
+ * This method loads the image into whole_image during the first call on
+ * get_pixel_rows.  The get_pixel_rows pointer is then adjusted to call
+ * get_8bit_row, get_24bit_row, or get_32bit_row on subsequent calls.
+ */
+
+METHODDEF(JDIMENSION)
+preload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+  bmp_source_ptr source = (bmp_source_ptr) sinfo;
+  register FILE *infile = source->pub.input_file;
+  register int c;
+  register JSAMPROW out_ptr;
+  JSAMPARRAY image_ptr;
+  JDIMENSION row, col;
+  cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+
+  /* Read the data into a virtual array in input-file row order. */
+  for (row = 0; row < cinfo->image_height; row++) {
+    if (progress != NULL) {
+      progress->pub.pass_counter = (long) row;
+      progress->pub.pass_limit = (long) cinfo->image_height;
+      (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+    }
+    image_ptr = (*cinfo->mem->access_virt_sarray)
+      ((j_common_ptr) cinfo, source->whole_image,
+       row, (JDIMENSION) 1, TRUE);
+    out_ptr = image_ptr[0];
+    for (col = source->row_width; col > 0; col--) {
+      /* inline copy of read_byte() for speed */
+      if ((c = getc(infile)) == EOF)
+	ERREXIT(cinfo, JERR_INPUT_EOF);
+      *out_ptr++ = (JSAMPLE) c;
+    }
+  }
+  if (progress != NULL)
+    progress->completed_extra_passes++;
+
+  /* Set up to read from the virtual array in top-to-bottom order */
+  switch (source->bits_per_pixel) {
+  case 8:
+    source->pub.get_pixel_rows = get_8bit_row;
+    break;
+  case 24:
+    source->pub.get_pixel_rows = get_24bit_row;
+    break;
+  case 32:
+    source->pub.get_pixel_rows = get_32bit_row;
+    break;
+  default:
+    ERREXIT(cinfo, JERR_BMP_BADDEPTH);
+  }
+  source->source_row = cinfo->image_height;
+
+  /* And read the first row */
+  return (*source->pub.get_pixel_rows) (cinfo, sinfo);
+}
+
+
+/*
+ * Read the file header; return image size and component count.
+ */
+
+METHODDEF(void)
+start_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+  bmp_source_ptr source = (bmp_source_ptr) sinfo;
+  U_CHAR bmpfileheader[14];
+  U_CHAR bmpinfoheader[64];
+#define GET_2B(array,offset)  ((unsigned int) UCH(array[offset]) + \
+			       (((unsigned int) UCH(array[offset+1])) << 8))
+#define GET_4B(array,offset)  ((INT32) UCH(array[offset]) + \
+			       (((INT32) UCH(array[offset+1])) << 8) + \
+			       (((INT32) UCH(array[offset+2])) << 16) + \
+			       (((INT32) UCH(array[offset+3])) << 24))
+  INT32 bfOffBits;
+  INT32 headerSize;
+  INT32 biWidth;
+  INT32 biHeight;
+  unsigned int biPlanes;
+  INT32 biCompression;
+  INT32 biXPelsPerMeter,biYPelsPerMeter;
+  INT32 biClrUsed = 0;
+  int mapentrysize = 0;		/* 0 indicates no colormap */
+  INT32 bPad;
+  JDIMENSION row_width;
+
+  /* Read and verify the bitmap file header */
+  if (! ReadOK(source->pub.input_file, bmpfileheader, 14))
+    ERREXIT(cinfo, JERR_INPUT_EOF);
+  if (GET_2B(bmpfileheader,0) != 0x4D42) /* 'BM' */
+    ERREXIT(cinfo, JERR_BMP_NOT);
+  bfOffBits = (INT32) GET_4B(bmpfileheader,10);
+  /* We ignore the remaining fileheader fields */
+
+  /* The infoheader might be 12 bytes (OS/2 1.x), 40 bytes (Windows),
+   * or 64 bytes (OS/2 2.x).  Check the first 4 bytes to find out which.
+   */
+  if (! ReadOK(source->pub.input_file, bmpinfoheader, 4))
+    ERREXIT(cinfo, JERR_INPUT_EOF);
+  headerSize = (INT32) GET_4B(bmpinfoheader,0);
+  if (headerSize < 12 || headerSize > 64)
+    ERREXIT(cinfo, JERR_BMP_BADHEADER);
+  if (! ReadOK(source->pub.input_file, bmpinfoheader+4, headerSize-4))
+    ERREXIT(cinfo, JERR_INPUT_EOF);
+
+  switch ((int) headerSize) {
+  case 12:
+    /* Decode OS/2 1.x header (Microsoft calls this a BITMAPCOREHEADER) */
+    biWidth = (INT32) GET_2B(bmpinfoheader,4);
+    biHeight = (INT32) GET_2B(bmpinfoheader,6);
+    biPlanes = GET_2B(bmpinfoheader,8);
+    source->bits_per_pixel = (int) GET_2B(bmpinfoheader,10);
+
+    switch (source->bits_per_pixel) {
+    case 8:			/* colormapped image */
+      mapentrysize = 3;		/* OS/2 uses RGBTRIPLE colormap */
+      TRACEMS2(cinfo, 1, JTRC_BMP_OS2_MAPPED, (int) biWidth, (int) biHeight);
+      break;
+    case 24:			/* RGB image */
+      TRACEMS2(cinfo, 1, JTRC_BMP_OS2, (int) biWidth, (int) biHeight);
+      break;
+    default:
+      ERREXIT(cinfo, JERR_BMP_BADDEPTH);
+      break;
+    }
+    break;
+  case 40:
+  case 64:
+    /* Decode Windows 3.x header (Microsoft calls this a BITMAPINFOHEADER) */
+    /* or OS/2 2.x header, which has additional fields that we ignore */
+    biWidth = GET_4B(bmpinfoheader,4);
+    biHeight = GET_4B(bmpinfoheader,8);
+    biPlanes = GET_2B(bmpinfoheader,12);
+    source->bits_per_pixel = (int) GET_2B(bmpinfoheader,14);
+    biCompression = GET_4B(bmpinfoheader,16);
+    biXPelsPerMeter = GET_4B(bmpinfoheader,24);
+    biYPelsPerMeter = GET_4B(bmpinfoheader,28);
+    biClrUsed = GET_4B(bmpinfoheader,32);
+    /* biSizeImage, biClrImportant fields are ignored */
+
+    switch (source->bits_per_pixel) {
+    case 8:			/* colormapped image */
+      mapentrysize = 4;		/* Windows uses RGBQUAD colormap */
+      TRACEMS2(cinfo, 1, JTRC_BMP_MAPPED, (int) biWidth, (int) biHeight);
+      break;
+    case 24:			/* RGB image */
+      TRACEMS2(cinfo, 1, JTRC_BMP, (int) biWidth, (int) biHeight);
+      break;
+    case 32:			/* RGB image + Alpha channel */
+      TRACEMS2(cinfo, 1, JTRC_BMP, (int) biWidth, (int) biHeight);
+      break;
+    default:
+      ERREXIT(cinfo, JERR_BMP_BADDEPTH);
+      break;
+    }
+    if (biCompression != 0)
+      ERREXIT(cinfo, JERR_BMP_COMPRESSED);
+
+    if (biXPelsPerMeter > 0 && biYPelsPerMeter > 0) {
+      /* Set JFIF density parameters from the BMP data */
+      cinfo->X_density = (UINT16) (biXPelsPerMeter/100); /* 100 cm per meter */
+      cinfo->Y_density = (UINT16) (biYPelsPerMeter/100);
+      cinfo->density_unit = 2;	/* dots/cm */
+    }
+    break;
+  default:
+    ERREXIT(cinfo, JERR_BMP_BADHEADER);
+    return;
+  }
+
+  if (biWidth <= 0 || biHeight <= 0)
+    ERREXIT(cinfo, JERR_BMP_EMPTY);
+  if (biPlanes != 1)
+    ERREXIT(cinfo, JERR_BMP_BADPLANES);
+
+  /* Compute distance to bitmap data --- will adjust for colormap below */
+  bPad = bfOffBits - (headerSize + 14);
+
+  /* Read the colormap, if any */
+  if (mapentrysize > 0) {
+    if (biClrUsed <= 0)
+      biClrUsed = 256;		/* assume it's 256 */
+    else if (biClrUsed > 256)
+      ERREXIT(cinfo, JERR_BMP_BADCMAP);
+    /* Allocate space to store the colormap */
+    source->colormap = (*cinfo->mem->alloc_sarray)
+      ((j_common_ptr) cinfo, JPOOL_IMAGE,
+       (JDIMENSION) biClrUsed, (JDIMENSION) 3);
+    /* and read it from the file */
+    read_colormap(source, (int) biClrUsed, mapentrysize);
+    /* account for size of colormap */
+    bPad -= biClrUsed * mapentrysize;
+  }
+
+  /* Skip any remaining pad bytes */
+  if (bPad < 0)			/* incorrect bfOffBits value? */
+    ERREXIT(cinfo, JERR_BMP_BADHEADER);
+  while (--bPad >= 0) {
+    (void) read_byte(source);
+  }
+
+  /* Compute row width in file, including padding to 4-byte boundary */
+  if (source->bits_per_pixel == 24)
+    row_width = (JDIMENSION) (biWidth * 3);
+  else if (source->bits_per_pixel == 32)
+    row_width = (JDIMENSION) (biWidth * 4);
+  else
+    row_width = (JDIMENSION) biWidth;
+  while ((row_width & 3) != 0) row_width++;
+  source->row_width = row_width;
+
+  /* Allocate space for inversion array, prepare for preload pass */
+  source->whole_image = (*cinfo->mem->request_virt_sarray)
+    ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+     row_width, (JDIMENSION) biHeight, (JDIMENSION) 1);
+  source->pub.get_pixel_rows = preload_image;
+  if (cinfo->progress != NULL) {
+    cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+    progress->total_extra_passes++; /* count file input as separate pass */
+  }
+
+  /* Allocate one-row buffer for returned data */
+  source->pub.buffer = (*cinfo->mem->alloc_sarray)
+    ((j_common_ptr) cinfo, JPOOL_IMAGE,
+     (JDIMENSION) (biWidth * 3), (JDIMENSION) 1);
+  source->pub.buffer_height = 1;
+
+  cinfo->in_color_space = JCS_RGB;
+  cinfo->input_components = 3;
+  cinfo->data_precision = 8;
+  cinfo->image_width = (JDIMENSION) biWidth;
+  cinfo->image_height = (JDIMENSION) biHeight;
+}
+
+
+/*
+ * Finish up at the end of the file.
+ */
+
+METHODDEF(void)
+finish_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+  /* no work */
+}
+
+
+/*
+ * The module selection routine for BMP format input.
+ */
+
+GLOBAL(cjpeg_source_ptr)
+jinit_read_bmp (j_compress_ptr cinfo)
+{
+  bmp_source_ptr source;
+
+  /* Create module interface object */
+  source = (bmp_source_ptr)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  SIZEOF(bmp_source_struct));
+  source->cinfo = cinfo;	/* make back link for subroutines */
+  /* Fill in method ptrs, except get_pixel_rows which start_input sets */
+  source->pub.start_input = start_input_bmp;
+  source->pub.finish_input = finish_input_bmp;
+
+  return (cjpeg_source_ptr) source;
+}
+
+#endif /* BMP_SUPPORTED */
diff --git a/source/Irrlicht/jpeglib/rdcolmap.c b/source/Irrlicht/jpeglib/rdcolmap.c
new file mode 100644
index 00000000..eebf8346
--- /dev/null
+++ b/source/Irrlicht/jpeglib/rdcolmap.c
@@ -0,0 +1,253 @@
+/*
+ * rdcolmap.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file implements djpeg's "-map file" switch.  It reads a source image
+ * and constructs a colormap to be supplied to the JPEG decompressor.
+ *
+ * Currently, these file formats are supported for the map file:
+ *   GIF: the contents of the GIF's global colormap are used.
+ *   PPM (either text or raw flavor): the entire file is read and
+ *      each unique pixel value is entered in the map.
+ * Note that reading a large PPM file will be horrendously slow.
+ * Typically, a PPM-format map file should contain just one pixel
+ * of each desired color.  Such a file can be extracted from an
+ * ordinary image PPM file with ppmtomap(1).
+ *
+ * Rescaling a PPM that has a maxval unequal to MAXJSAMPLE is not
+ * currently implemented.
+ */
+
+#include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
+
+#ifdef QUANT_2PASS_SUPPORTED	/* otherwise can't quantize to supplied map */
+
+/* Portions of this code are based on the PBMPLUS library, which is:
+**
+** Copyright (C) 1988 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation.  This software is provided "as is" without express or
+** implied warranty.
+*/
+
+
+/*
+ * Add a (potentially) new color to the color map.
+ */
+
+LOCAL(void)
+add_map_entry (j_decompress_ptr cinfo, int R, int G, int B)
+{
+  JSAMPROW colormap0 = cinfo->colormap[0];
+  JSAMPROW colormap1 = cinfo->colormap[1];
+  JSAMPROW colormap2 = cinfo->colormap[2];
+  int ncolors = cinfo->actual_number_of_colors;
+  int index;
+
+  /* Check for duplicate color. */
+  for (index = 0; index < ncolors; index++) {
+    if (GETJSAMPLE(colormap0[index]) == R &&
+	GETJSAMPLE(colormap1[index]) == G &&
+	GETJSAMPLE(colormap2[index]) == B)
+      return;			/* color is already in map */
+  }
+
+  /* Check for map overflow. */
+  if (ncolors >= (MAXJSAMPLE+1))
+    ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, (MAXJSAMPLE+1));
+
+  /* OK, add color to map. */
+  colormap0[ncolors] = (JSAMPLE) R;
+  colormap1[ncolors] = (JSAMPLE) G;
+  colormap2[ncolors] = (JSAMPLE) B;
+  cinfo->actual_number_of_colors++;
+}
+
+
+/*
+ * Extract color map from a GIF file.
+ */
+
+LOCAL(void)
+read_gif_map (j_decompress_ptr cinfo, FILE * infile)
+{
+  int header[13];
+  int i, colormaplen;
+  int R, G, B;
+
+  /* Initial 'G' has already been read by read_color_map */
+  /* Read the rest of the GIF header and logical screen descriptor */
+  for (i = 1; i < 13; i++) {
+    if ((header[i] = getc(infile)) == EOF)
+      ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+  }
+
+  /* Verify GIF Header */
+  if (header[1] != 'I' || header[2] != 'F')
+    ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+
+  /* There must be a global color map. */
+  if ((header[10] & 0x80) == 0)
+    ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+
+  /* OK, fetch it. */
+  colormaplen = 2 << (header[10] & 0x07);
+
+  for (i = 0; i < colormaplen; i++) {
+    R = getc(infile);
+    G = getc(infile);
+    B = getc(infile);
+    if (R == EOF || G == EOF || B == EOF)
+      ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+    add_map_entry(cinfo,
+		  R << (BITS_IN_JSAMPLE-8),
+		  G << (BITS_IN_JSAMPLE-8),
+		  B << (BITS_IN_JSAMPLE-8));
+  }
+}
+
+
+/* Support routines for reading PPM */
+
+
+LOCAL(int)
+pbm_getc (FILE * infile)
+/* Read next char, skipping over any comments */
+/* A comment/newline sequence is returned as a newline */
+{
+  register int ch;
+  
+  ch = getc(infile);
+  if (ch == '#') {
+    do {
+      ch = getc(infile);
+    } while (ch != '\n' && ch != EOF);
+  }
+  return ch;
+}
+
+
+LOCAL(unsigned int)
+read_pbm_integer (j_decompress_ptr cinfo, FILE * infile)
+/* Read an unsigned decimal integer from the PPM file */
+/* Swallows one trailing character after the integer */
+/* Note that on a 16-bit-int machine, only values up to 64k can be read. */
+/* This should not be a problem in practice. */
+{
+  register int ch;
+  register unsigned int val;
+  
+  /* Skip any leading whitespace */
+  do {
+    ch = pbm_getc(infile);
+    if (ch == EOF)
+      ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+  } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
+  
+  if (ch < '0' || ch > '9')
+    ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+  
+  val = ch - '0';
+  while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') {
+    val *= 10;
+    val += ch - '0';
+  }
+  return val;
+}
+
+
+/*
+ * Extract color map from a PPM file.
+ */
+
+LOCAL(void)
+read_ppm_map (j_decompress_ptr cinfo, FILE * infile)
+{
+  int c;
+  unsigned int w, h, maxval, row, col;
+  int R, G, B;
+
+  /* Initial 'P' has already been read by read_color_map */
+  c = getc(infile);		/* save format discriminator for a sec */
+
+  /* while we fetch the remaining header info */
+  w = read_pbm_integer(cinfo, infile);
+  h = read_pbm_integer(cinfo, infile);
+  maxval = read_pbm_integer(cinfo, infile);
+
+  if (w <= 0 || h <= 0 || maxval <= 0) /* error check */
+    ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+
+  /* For now, we don't support rescaling from an unusual maxval. */
+  if (maxval != (unsigned int) MAXJSAMPLE)
+    ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+
+  switch (c) {
+  case '3':			/* it's a text-format PPM file */
+    for (row = 0; row < h; row++) {
+      for (col = 0; col < w; col++) {
+	R = read_pbm_integer(cinfo, infile);
+	G = read_pbm_integer(cinfo, infile);
+	B = read_pbm_integer(cinfo, infile);
+	add_map_entry(cinfo, R, G, B);
+      }
+    }
+    break;
+
+  case '6':			/* it's a raw-format PPM file */
+    for (row = 0; row < h; row++) {
+      for (col = 0; col < w; col++) {
+	R = getc(infile);
+	G = getc(infile);
+	B = getc(infile);
+	if (R == EOF || G == EOF || B == EOF)
+	  ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+	add_map_entry(cinfo, R, G, B);
+      }
+    }
+    break;
+
+  default:
+    ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+    break;
+  }
+}
+
+
+/*
+ * Main entry point from djpeg.c.
+ *  Input: opened input file (from file name argument on command line).
+ *  Output: colormap and actual_number_of_colors fields are set in cinfo.
+ */
+
+GLOBAL(void)
+read_color_map (j_decompress_ptr cinfo, FILE * infile)
+{
+  /* Allocate space for a color map of maximum supported size. */
+  cinfo->colormap = (*cinfo->mem->alloc_sarray)
+    ((j_common_ptr) cinfo, JPOOL_IMAGE,
+     (JDIMENSION) (MAXJSAMPLE+1), (JDIMENSION) 3);
+  cinfo->actual_number_of_colors = 0; /* initialize map to empty */
+
+  /* Read first byte to determine file format */
+  switch (getc(infile)) {
+  case 'G':
+    read_gif_map(cinfo, infile);
+    break;
+  case 'P':
+    read_ppm_map(cinfo, infile);
+    break;
+  default:
+    ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+    break;
+  }
+}
+
+#endif /* QUANT_2PASS_SUPPORTED */
diff --git a/source/Irrlicht/jpeglib/rdgif.c b/source/Irrlicht/jpeglib/rdgif.c
new file mode 100644
index 00000000..b0757e71
--- /dev/null
+++ b/source/Irrlicht/jpeglib/rdgif.c
@@ -0,0 +1,38 @@
+/*
+ * rdgif.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to read input images in GIF format.
+ *
+ *****************************************************************************
+ * NOTE: to avoid entanglements with Unisys' patent on LZW compression,      *
+ * the ability to read GIF files has been removed from the IJG distribution. *
+ * Sorry about that.                                                         *
+ *****************************************************************************
+ *
+ * We are required to state that
+ *    "The Graphics Interchange Format(c) is the Copyright property of
+ *    CompuServe Incorporated. GIF(sm) is a Service Mark property of
+ *    CompuServe Incorporated."
+ */
+
+#include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
+
+#ifdef GIF_SUPPORTED
+
+/*
+ * The module selection routine for GIF format input.
+ */
+
+GLOBAL(cjpeg_source_ptr)
+jinit_read_gif (j_compress_ptr cinfo)
+{
+  fprintf(stderr, "GIF input is unsupported for legal reasons.  Sorry.\n");
+  exit(EXIT_FAILURE);
+  return NULL;			/* keep compiler happy */
+}
+
+#endif /* GIF_SUPPORTED */
diff --git a/source/Irrlicht/jpeglib/rdjpgcom.1 b/source/Irrlicht/jpeglib/rdjpgcom.1
new file mode 100644
index 00000000..d7741fb9
--- /dev/null
+++ b/source/Irrlicht/jpeglib/rdjpgcom.1
@@ -0,0 +1,63 @@
+.TH RDJPGCOM 1 "13 September 2013"
+.SH NAME
+rdjpgcom \- display text comments from a JPEG file
+.SH SYNOPSIS
+.B rdjpgcom
+[
+.B \-raw
+]
+[
+.B \-verbose
+]
+[
+.I filename
+]
+.LP
+.SH DESCRIPTION
+.LP
+.B rdjpgcom
+reads the named JPEG/JFIF file, or the standard input if no file is named,
+and prints any text comments found in the file on the standard output.
+.PP
+The JPEG standard allows "comment" (COM) blocks to occur within a JPEG file.
+Although the standard doesn't actually define what COM blocks are for, they
+are widely used to hold user-supplied text strings.  This lets you add
+annotations, titles, index terms, etc to your JPEG files, and later retrieve
+them as text.  COM blocks do not interfere with the image stored in the JPEG
+file.  The maximum size of a COM block is 64K, but you can have as many of
+them as you like in one JPEG file.
+.SH OPTIONS
+.TP
+.B \-raw
+Normally
+.B rdjpgcom
+escapes non-printable characters in comments, for security reasons.
+This option avoids that.
+.PP
+.B \-verbose
+Causes
+.B rdjpgcom
+to also display the JPEG image dimensions.
+.PP
+Switch names may be abbreviated, and are not case sensitive.
+.SH HINTS
+.B rdjpgcom
+does not depend on the IJG JPEG library.  Its source code is intended as an
+illustration of the minimum amount of code required to parse a JPEG file
+header correctly.
+.PP
+In
+.B \-verbose
+mode,
+.B rdjpgcom
+will also attempt to print the contents of any "APP12" markers as text.
+Some digital cameras produce APP12 markers containing useful textual
+information.  If you like, you can modify the source code to print
+other APPn marker types as well.
+.SH SEE ALSO
+.BR cjpeg (1),
+.BR djpeg (1),
+.BR jpegtran (1),
+.BR wrjpgcom (1)
+.SH AUTHOR
+Independent JPEG Group
diff --git a/source/Irrlicht/jpeglib/rdjpgcom.c b/source/Irrlicht/jpeglib/rdjpgcom.c
new file mode 100644
index 00000000..ab09b443
--- /dev/null
+++ b/source/Irrlicht/jpeglib/rdjpgcom.c
@@ -0,0 +1,515 @@
+/*
+ * rdjpgcom.c
+ *
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * Modified 2009 by Bill Allombert, Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a very simple stand-alone application that displays
+ * the text in COM (comment) markers in a JFIF file.
+ * This may be useful as an example of the minimum logic needed to parse
+ * JPEG markers.
+ */
+
+#define JPEG_CJPEG_DJPEG	/* to get the command-line config symbols */
+#include "jinclude.h"		/* get auto-config symbols,  */
+
+#ifdef HAVE_LOCALE_H
+#include 		/* Bill Allombert: use locale for isprint */
+#endif
+#include 		/* to declare isupper(), tolower() */
+#ifdef USE_SETMODE
+#include 		/* to declare setmode()'s parameter macros */
+/* If you have setmode() but not , just delete this line: */
+#include 			/* to declare setmode() */
+#endif
+
+#ifdef USE_CCOMMAND		/* command-line reader for Macintosh */
+#ifdef __MWERKS__
+#include               /* Metrowerks needs this */
+#include 		/* ... and this */
+#endif
+#ifdef THINK_C
+#include 		/* Think declares it here */
+#endif
+#endif
+
+#ifdef DONT_USE_B_MODE		/* define mode parameters for fopen() */
+#define READ_BINARY	"r"
+#else
+#ifdef VMS			/* VMS is very nonstandard */
+#define READ_BINARY	"rb", "ctx=stm"
+#else				/* standard ANSI-compliant case */
+#define READ_BINARY	"rb"
+#endif
+#endif
+
+#ifndef EXIT_FAILURE		/* define exit() codes if not provided */
+#define EXIT_FAILURE  1
+#endif
+#ifndef EXIT_SUCCESS
+#ifdef VMS
+#define EXIT_SUCCESS  1		/* VMS is very nonstandard */
+#else
+#define EXIT_SUCCESS  0
+#endif
+#endif
+
+
+/*
+ * These macros are used to read the input file.
+ * To reuse this code in another application, you might need to change these.
+ */
+
+static FILE * infile;		/* input JPEG file */
+
+/* Return next input byte, or EOF if no more */
+#define NEXTBYTE()  getc(infile)
+
+
+/* Error exit handler */
+#define ERREXIT(msg)  (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE))
+
+
+/* Read one byte, testing for EOF */
+static int
+read_1_byte (void)
+{
+  int c;
+
+  c = NEXTBYTE();
+  if (c == EOF)
+    ERREXIT("Premature EOF in JPEG file");
+  return c;
+}
+
+/* Read 2 bytes, convert to unsigned int */
+/* All 2-byte quantities in JPEG markers are MSB first */
+static unsigned int
+read_2_bytes (void)
+{
+  int c1, c2;
+
+  c1 = NEXTBYTE();
+  if (c1 == EOF)
+    ERREXIT("Premature EOF in JPEG file");
+  c2 = NEXTBYTE();
+  if (c2 == EOF)
+    ERREXIT("Premature EOF in JPEG file");
+  return (((unsigned int) c1) << 8) + ((unsigned int) c2);
+}
+
+
+/*
+ * JPEG markers consist of one or more 0xFF bytes, followed by a marker
+ * code byte (which is not an FF).  Here are the marker codes of interest
+ * in this program.  (See jdmarker.c for a more complete list.)
+ */
+
+#define M_SOF0  0xC0		/* Start Of Frame N */
+#define M_SOF1  0xC1		/* N indicates which compression process */
+#define M_SOF2  0xC2		/* Only SOF0-SOF2 are now in common use */
+#define M_SOF3  0xC3
+#define M_SOF5  0xC5		/* NB: codes C4 and CC are NOT SOF markers */
+#define M_SOF6  0xC6
+#define M_SOF7  0xC7
+#define M_SOF9  0xC9
+#define M_SOF10 0xCA
+#define M_SOF11 0xCB
+#define M_SOF13 0xCD
+#define M_SOF14 0xCE
+#define M_SOF15 0xCF
+#define M_SOI   0xD8		/* Start Of Image (beginning of datastream) */
+#define M_EOI   0xD9		/* End Of Image (end of datastream) */
+#define M_SOS   0xDA		/* Start Of Scan (begins compressed data) */
+#define M_APP0	0xE0		/* Application-specific marker, type N */
+#define M_APP12	0xEC		/* (we don't bother to list all 16 APPn's) */
+#define M_COM   0xFE		/* COMment */
+
+
+/*
+ * Find the next JPEG marker and return its marker code.
+ * We expect at least one FF byte, possibly more if the compressor used FFs
+ * to pad the file.
+ * There could also be non-FF garbage between markers.  The treatment of such
+ * garbage is unspecified; we choose to skip over it but emit a warning msg.
+ * NB: this routine must not be used after seeing SOS marker, since it will
+ * not deal correctly with FF/00 sequences in the compressed image data...
+ */
+
+static int
+next_marker (void)
+{
+  int c;
+  int discarded_bytes = 0;
+
+  /* Find 0xFF byte; count and skip any non-FFs. */
+  c = read_1_byte();
+  while (c != 0xFF) {
+    discarded_bytes++;
+    c = read_1_byte();
+  }
+  /* Get marker code byte, swallowing any duplicate FF bytes.  Extra FFs
+   * are legal as pad bytes, so don't count them in discarded_bytes.
+   */
+  do {
+    c = read_1_byte();
+  } while (c == 0xFF);
+
+  if (discarded_bytes != 0) {
+    fprintf(stderr, "Warning: garbage data found in JPEG file\n");
+  }
+
+  return c;
+}
+
+
+/*
+ * Read the initial marker, which should be SOI.
+ * For a JFIF file, the first two bytes of the file should be literally
+ * 0xFF M_SOI.  To be more general, we could use next_marker, but if the
+ * input file weren't actually JPEG at all, next_marker might read the whole
+ * file and then return a misleading error message...
+ */
+
+static int
+first_marker (void)
+{
+  int c1, c2;
+
+  c1 = NEXTBYTE();
+  c2 = NEXTBYTE();
+  if (c1 != 0xFF || c2 != M_SOI)
+    ERREXIT("Not a JPEG file");
+  return c2;
+}
+
+
+/*
+ * Most types of marker are followed by a variable-length parameter segment.
+ * This routine skips over the parameters for any marker we don't otherwise
+ * want to process.
+ * Note that we MUST skip the parameter segment explicitly in order not to
+ * be fooled by 0xFF bytes that might appear within the parameter segment;
+ * such bytes do NOT introduce new markers.
+ */
+
+static void
+skip_variable (void)
+/* Skip over an unknown or uninteresting variable-length marker */
+{
+  unsigned int length;
+
+  /* Get the marker parameter length count */
+  length = read_2_bytes();
+  /* Length includes itself, so must be at least 2 */
+  if (length < 2)
+    ERREXIT("Erroneous JPEG marker length");
+  length -= 2;
+  /* Skip over the remaining bytes */
+  while (length > 0) {
+    (void) read_1_byte();
+    length--;
+  }
+}
+
+
+/*
+ * Process a COM marker.
+ * We want to print out the marker contents as legible text;
+ * we must guard against non-text junk and varying newline representations.
+ */
+
+static void
+process_COM (int raw)
+{
+  unsigned int length;
+  int ch;
+  int lastch = 0;
+
+  /* Bill Allombert: set locale properly for isprint */
+#ifdef HAVE_LOCALE_H
+  setlocale(LC_CTYPE, "");
+#endif
+
+  /* Get the marker parameter length count */
+  length = read_2_bytes();
+  /* Length includes itself, so must be at least 2 */
+  if (length < 2)
+    ERREXIT("Erroneous JPEG marker length");
+  length -= 2;
+
+  while (length > 0) {
+    ch = read_1_byte();
+    if (raw) {
+      putc(ch, stdout);
+    /* Emit the character in a readable form.
+     * Nonprintables are converted to \nnn form,
+     * while \ is converted to \\.
+     * Newlines in CR, CR/LF, or LF form will be printed as one newline.
+     */
+    } else if (ch == '\r') {
+      printf("\n");
+    } else if (ch == '\n') {
+      if (lastch != '\r')
+	printf("\n");
+    } else if (ch == '\\') {
+      printf("\\\\");
+    } else if (isprint(ch)) {
+      putc(ch, stdout);
+    } else {
+      printf("\\%03o", ch);
+    }
+    lastch = ch;
+    length--;
+  }
+  printf("\n");
+
+  /* Bill Allombert: revert to C locale */
+#ifdef HAVE_LOCALE_H
+  setlocale(LC_CTYPE, "C");
+#endif
+}
+
+
+/*
+ * Process a SOFn marker.
+ * This code is only needed if you want to know the image dimensions...
+ */
+
+static void
+process_SOFn (int marker)
+{
+  unsigned int length;
+  unsigned int image_height, image_width;
+  int data_precision, num_components;
+  const char * process;
+  int ci;
+
+  length = read_2_bytes();	/* usual parameter length count */
+
+  data_precision = read_1_byte();
+  image_height = read_2_bytes();
+  image_width = read_2_bytes();
+  num_components = read_1_byte();
+
+  switch (marker) {
+  case M_SOF0:	process = "Baseline";  break;
+  case M_SOF1:	process = "Extended sequential";  break;
+  case M_SOF2:	process = "Progressive";  break;
+  case M_SOF3:	process = "Lossless";  break;
+  case M_SOF5:	process = "Differential sequential";  break;
+  case M_SOF6:	process = "Differential progressive";  break;
+  case M_SOF7:	process = "Differential lossless";  break;
+  case M_SOF9:	process = "Extended sequential, arithmetic coding";  break;
+  case M_SOF10:	process = "Progressive, arithmetic coding";  break;
+  case M_SOF11:	process = "Lossless, arithmetic coding";  break;
+  case M_SOF13:	process = "Differential sequential, arithmetic coding";  break;
+  case M_SOF14:	process = "Differential progressive, arithmetic coding"; break;
+  case M_SOF15:	process = "Differential lossless, arithmetic coding";  break;
+  default:	process = "Unknown";  break;
+  }
+
+  printf("JPEG image is %uw * %uh, %d color components, %d bits per sample\n",
+	 image_width, image_height, num_components, data_precision);
+  printf("JPEG process: %s\n", process);
+
+  if (length != (unsigned int) (8 + num_components * 3))
+    ERREXIT("Bogus SOF marker length");
+
+  for (ci = 0; ci < num_components; ci++) {
+    (void) read_1_byte();	/* Component ID code */
+    (void) read_1_byte();	/* H, V sampling factors */
+    (void) read_1_byte();	/* Quantization table number */
+  }
+}
+
+
+/*
+ * Parse the marker stream until SOS or EOI is seen;
+ * display any COM markers.
+ * While the companion program wrjpgcom will always insert COM markers before
+ * SOFn, other implementations might not, so we scan to SOS before stopping.
+ * If we were only interested in the image dimensions, we would stop at SOFn.
+ * (Conversely, if we only cared about COM markers, there would be no need
+ * for special code to handle SOFn; we could treat it like other markers.)
+ */
+
+static int
+scan_JPEG_header (int verbose, int raw)
+{
+  int marker;
+
+  /* Expect SOI at start of file */
+  if (first_marker() != M_SOI)
+    ERREXIT("Expected SOI marker first");
+
+  /* Scan miscellaneous markers until we reach SOS. */
+  for (;;) {
+    marker = next_marker();
+    switch (marker) {
+      /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be,
+       * treated as SOFn.  C4 in particular is actually DHT.
+       */
+    case M_SOF0:		/* Baseline */
+    case M_SOF1:		/* Extended sequential, Huffman */
+    case M_SOF2:		/* Progressive, Huffman */
+    case M_SOF3:		/* Lossless, Huffman */
+    case M_SOF5:		/* Differential sequential, Huffman */
+    case M_SOF6:		/* Differential progressive, Huffman */
+    case M_SOF7:		/* Differential lossless, Huffman */
+    case M_SOF9:		/* Extended sequential, arithmetic */
+    case M_SOF10:		/* Progressive, arithmetic */
+    case M_SOF11:		/* Lossless, arithmetic */
+    case M_SOF13:		/* Differential sequential, arithmetic */
+    case M_SOF14:		/* Differential progressive, arithmetic */
+    case M_SOF15:		/* Differential lossless, arithmetic */
+      if (verbose)
+	process_SOFn(marker);
+      else
+	skip_variable();
+      break;
+
+    case M_SOS:			/* stop before hitting compressed data */
+      return marker;
+
+    case M_EOI:			/* in case it's a tables-only JPEG stream */
+      return marker;
+
+    case M_COM:
+      process_COM(raw);
+      break;
+
+    case M_APP12:
+      /* Some digital camera makers put useful textual information into
+       * APP12 markers, so we print those out too when in -verbose mode.
+       */
+      if (verbose) {
+	printf("APP12 contains:\n");
+	process_COM(raw);
+      } else
+	skip_variable();
+      break;
+
+    default:			/* Anything else just gets skipped */
+      skip_variable();		/* we assume it has a parameter count... */
+      break;
+    }
+  } /* end loop */
+}
+
+
+/* Command line parsing code */
+
+static const char * progname;	/* program name for error messages */
+
+
+static void
+usage (void)
+/* complain about bad command line */
+{
+  fprintf(stderr, "rdjpgcom displays any textual comments in a JPEG file.\n");
+
+  fprintf(stderr, "Usage: %s [switches] [inputfile]\n", progname);
+
+  fprintf(stderr, "Switches (names may be abbreviated):\n");
+  fprintf(stderr, "  -raw        Display non-printable characters in comments (unsafe)\n");
+  fprintf(stderr, "  -verbose    Also display dimensions of JPEG image\n");
+
+  exit(EXIT_FAILURE);
+}
+
+
+static int
+keymatch (char * arg, const char * keyword, int minchars)
+/* Case-insensitive matching of (possibly abbreviated) keyword switches. */
+/* keyword is the constant keyword (must be lower case already), */
+/* minchars is length of minimum legal abbreviation. */
+{
+  register int ca, ck;
+  register int nmatched = 0;
+
+  while ((ca = *arg++) != '\0') {
+    if ((ck = *keyword++) == '\0')
+      return 0;			/* arg longer than keyword, no good */
+    if (isupper(ca))		/* force arg to lcase (assume ck is already) */
+      ca = tolower(ca);
+    if (ca != ck)
+      return 0;			/* no good */
+    nmatched++;			/* count matched characters */
+  }
+  /* reached end of argument; fail if it's too short for unique abbrev */
+  if (nmatched < minchars)
+    return 0;
+  return 1;			/* A-OK */
+}
+
+
+/*
+ * The main program.
+ */
+
+int
+main (int argc, char **argv)
+{
+  int argn;
+  char * arg;
+  int verbose = 0, raw = 0;
+
+  /* On Mac, fetch a command line. */
+#ifdef USE_CCOMMAND
+  argc = ccommand(&argv);
+#endif
+
+  progname = argv[0];
+  if (progname == NULL || progname[0] == 0)
+    progname = "rdjpgcom";	/* in case C library doesn't provide it */
+
+  /* Parse switches, if any */
+  for (argn = 1; argn < argc; argn++) {
+    arg = argv[argn];
+    if (arg[0] != '-')
+      break;			/* not switch, must be file name */
+    arg++;			/* advance over '-' */
+    if (keymatch(arg, "verbose", 1)) {
+      verbose++;
+    } else if (keymatch(arg, "raw", 1)) {
+      raw = 1;
+    } else
+      usage();
+  }
+
+  /* Open the input file. */
+  /* Unix style: expect zero or one file name */
+  if (argn < argc-1) {
+    fprintf(stderr, "%s: only one input file\n", progname);
+    usage();
+  }
+  if (argn < argc) {
+    if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) {
+      fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
+      exit(EXIT_FAILURE);
+    }
+  } else {
+    /* default input file is stdin */
+#ifdef USE_SETMODE		/* need to hack file mode? */
+    setmode(fileno(stdin), O_BINARY);
+#endif
+#ifdef USE_FDOPEN		/* need to re-open in binary mode? */
+    if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
+      fprintf(stderr, "%s: can't open stdin\n", progname);
+      exit(EXIT_FAILURE);
+    }
+#else
+    infile = stdin;
+#endif
+  }
+
+  /* Scan the JPEG headers. */
+  (void) scan_JPEG_header(verbose, raw);
+
+  /* All done. */
+  exit(EXIT_SUCCESS);
+  return 0;			/* suppress no-return-value warnings */
+}
diff --git a/source/Irrlicht/jpeglib/rdppm.c b/source/Irrlicht/jpeglib/rdppm.c
new file mode 100644
index 00000000..9dcd2dc2
--- /dev/null
+++ b/source/Irrlicht/jpeglib/rdppm.c
@@ -0,0 +1,459 @@
+/*
+ * rdppm.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2009 by Bill Allombert, Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to read input images in PPM/PGM format.
+ * The extended 2-byte-per-sample raw PPM/PGM formats are supported.
+ * The PBMPLUS library is NOT required to compile this software
+ * (but it is highly useful as a set of PPM image manipulation programs).
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications.  As they stand, they assume input from
+ * an ordinary stdio stream.  They further assume that reading begins
+ * at the start of the file; start_input may need work if the
+ * user interface has already read some data (e.g., to determine that
+ * the file is indeed PPM format).
+ */
+
+#include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
+
+#ifdef PPM_SUPPORTED
+
+
+/* Portions of this code are based on the PBMPLUS library, which is:
+**
+** Copyright (C) 1988 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation.  This software is provided "as is" without express or
+** implied warranty.
+*/
+
+
+/* Macros to deal with unsigned chars as efficiently as compiler allows */
+
+#ifdef HAVE_UNSIGNED_CHAR
+typedef unsigned char U_CHAR;
+#define UCH(x)	((int) (x))
+#else /* !HAVE_UNSIGNED_CHAR */
+#ifdef CHAR_IS_UNSIGNED
+typedef char U_CHAR;
+#define UCH(x)	((int) (x))
+#else
+typedef char U_CHAR;
+#define UCH(x)	((int) (x) & 0xFF)
+#endif
+#endif /* HAVE_UNSIGNED_CHAR */
+
+
+#define	ReadOK(file,buffer,len)	(JFREAD(file,buffer,len) == ((size_t) (len)))
+
+
+/*
+ * On most systems, reading individual bytes with getc() is drastically less
+ * efficient than buffering a row at a time with fread().  On PCs, we must
+ * allocate the buffer in near data space, because we are assuming small-data
+ * memory model, wherein fread() can't reach far memory.  If you need to
+ * process very wide images on a PC, you might have to compile in large-memory
+ * model, or else replace fread() with a getc() loop --- which will be much
+ * slower.
+ */
+
+
+/* Private version of data source object */
+
+typedef struct {
+  struct cjpeg_source_struct pub; /* public fields */
+
+  U_CHAR *iobuffer;		/* non-FAR pointer to I/O buffer */
+  JSAMPROW pixrow;		/* FAR pointer to same */
+  size_t buffer_width;		/* width of I/O buffer */
+  JSAMPLE *rescale;		/* => maxval-remapping array, or NULL */
+} ppm_source_struct;
+
+typedef ppm_source_struct * ppm_source_ptr;
+
+
+LOCAL(int)
+pbm_getc (FILE * infile)
+/* Read next char, skipping over any comments */
+/* A comment/newline sequence is returned as a newline */
+{
+  register int ch;
+
+  ch = getc(infile);
+  if (ch == '#') {
+    do {
+      ch = getc(infile);
+    } while (ch != '\n' && ch != EOF);
+  }
+  return ch;
+}
+
+
+LOCAL(unsigned int)
+read_pbm_integer (j_compress_ptr cinfo, FILE * infile)
+/* Read an unsigned decimal integer from the PPM file */
+/* Swallows one trailing character after the integer */
+/* Note that on a 16-bit-int machine, only values up to 64k can be read. */
+/* This should not be a problem in practice. */
+{
+  register int ch;
+  register unsigned int val;
+
+  /* Skip any leading whitespace */
+  do {
+    ch = pbm_getc(infile);
+    if (ch == EOF)
+      ERREXIT(cinfo, JERR_INPUT_EOF);
+  } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
+
+  if (ch < '0' || ch > '9')
+    ERREXIT(cinfo, JERR_PPM_NONNUMERIC);
+
+  val = ch - '0';
+  while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') {
+    val *= 10;
+    val += ch - '0';
+  }
+  return val;
+}
+
+
+/*
+ * Read one row of pixels.
+ *
+ * We provide several different versions depending on input file format.
+ * In all cases, input is scaled to the size of JSAMPLE.
+ *
+ * A really fast path is provided for reading byte/sample raw files with
+ * maxval = MAXJSAMPLE, which is the normal case for 8-bit data.
+ */
+
+
+METHODDEF(JDIMENSION)
+get_text_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading text-format PGM files with any maxval */
+{
+  ppm_source_ptr source = (ppm_source_ptr) sinfo;
+  FILE * infile = source->pub.input_file;
+  register JSAMPROW ptr;
+  register JSAMPLE *rescale = source->rescale;
+  JDIMENSION col;
+
+  ptr = source->pub.buffer[0];
+  for (col = cinfo->image_width; col > 0; col--) {
+    *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
+  }
+  return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_text_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading text-format PPM files with any maxval */
+{
+  ppm_source_ptr source = (ppm_source_ptr) sinfo;
+  FILE * infile = source->pub.input_file;
+  register JSAMPROW ptr;
+  register JSAMPLE *rescale = source->rescale;
+  JDIMENSION col;
+
+  ptr = source->pub.buffer[0];
+  for (col = cinfo->image_width; col > 0; col--) {
+    *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
+    *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
+    *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
+  }
+  return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_scaled_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-byte-format PGM files with any maxval */
+{
+  ppm_source_ptr source = (ppm_source_ptr) sinfo;
+  register JSAMPROW ptr;
+  register U_CHAR * bufferptr;
+  register JSAMPLE *rescale = source->rescale;
+  JDIMENSION col;
+
+  if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+    ERREXIT(cinfo, JERR_INPUT_EOF);
+  ptr = source->pub.buffer[0];
+  bufferptr = source->iobuffer;
+  for (col = cinfo->image_width; col > 0; col--) {
+    *ptr++ = rescale[UCH(*bufferptr++)];
+  }
+  return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_scaled_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-byte-format PPM files with any maxval */
+{
+  ppm_source_ptr source = (ppm_source_ptr) sinfo;
+  register JSAMPROW ptr;
+  register U_CHAR * bufferptr;
+  register JSAMPLE *rescale = source->rescale;
+  JDIMENSION col;
+
+  if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+    ERREXIT(cinfo, JERR_INPUT_EOF);
+  ptr = source->pub.buffer[0];
+  bufferptr = source->iobuffer;
+  for (col = cinfo->image_width; col > 0; col--) {
+    *ptr++ = rescale[UCH(*bufferptr++)];
+    *ptr++ = rescale[UCH(*bufferptr++)];
+    *ptr++ = rescale[UCH(*bufferptr++)];
+  }
+  return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_raw_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-byte-format files with maxval = MAXJSAMPLE.
+ * In this case we just read right into the JSAMPLE buffer!
+ * Note that same code works for PPM and PGM files.
+ */
+{
+  ppm_source_ptr source = (ppm_source_ptr) sinfo;
+
+  if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+    ERREXIT(cinfo, JERR_INPUT_EOF);
+  return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_word_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-word-format PGM files with any maxval */
+{
+  ppm_source_ptr source = (ppm_source_ptr) sinfo;
+  register JSAMPROW ptr;
+  register U_CHAR * bufferptr;
+  register JSAMPLE *rescale = source->rescale;
+  JDIMENSION col;
+
+  if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+    ERREXIT(cinfo, JERR_INPUT_EOF);
+  ptr = source->pub.buffer[0];
+  bufferptr = source->iobuffer;
+  for (col = cinfo->image_width; col > 0; col--) {
+    register int temp;
+    temp  = UCH(*bufferptr++) << 8;
+    temp |= UCH(*bufferptr++);
+    *ptr++ = rescale[temp];
+  }
+  return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_word_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-word-format PPM files with any maxval */
+{
+  ppm_source_ptr source = (ppm_source_ptr) sinfo;
+  register JSAMPROW ptr;
+  register U_CHAR * bufferptr;
+  register JSAMPLE *rescale = source->rescale;
+  JDIMENSION col;
+
+  if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+    ERREXIT(cinfo, JERR_INPUT_EOF);
+  ptr = source->pub.buffer[0];
+  bufferptr = source->iobuffer;
+  for (col = cinfo->image_width; col > 0; col--) {
+    register int temp;
+    temp  = UCH(*bufferptr++) << 8;
+    temp |= UCH(*bufferptr++);
+    *ptr++ = rescale[temp];
+    temp  = UCH(*bufferptr++) << 8;
+    temp |= UCH(*bufferptr++);
+    *ptr++ = rescale[temp];
+    temp  = UCH(*bufferptr++) << 8;
+    temp |= UCH(*bufferptr++);
+    *ptr++ = rescale[temp];
+  }
+  return 1;
+}
+
+
+/*
+ * Read the file header; return image size and component count.
+ */
+
+METHODDEF(void)
+start_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+  ppm_source_ptr source = (ppm_source_ptr) sinfo;
+  int c;
+  unsigned int w, h, maxval;
+  boolean need_iobuffer, use_raw_buffer, need_rescale;
+
+  if (getc(source->pub.input_file) != 'P')
+    ERREXIT(cinfo, JERR_PPM_NOT);
+
+  c = getc(source->pub.input_file); /* subformat discriminator character */
+
+  /* detect unsupported variants (ie, PBM) before trying to read header */
+  switch (c) {
+  case '2':			/* it's a text-format PGM file */
+  case '3':			/* it's a text-format PPM file */
+  case '5':			/* it's a raw-format PGM file */
+  case '6':			/* it's a raw-format PPM file */
+    break;
+  default:
+    ERREXIT(cinfo, JERR_PPM_NOT);
+    break;
+  }
+
+  /* fetch the remaining header info */
+  w = read_pbm_integer(cinfo, source->pub.input_file);
+  h = read_pbm_integer(cinfo, source->pub.input_file);
+  maxval = read_pbm_integer(cinfo, source->pub.input_file);
+
+  if (w <= 0 || h <= 0 || maxval <= 0) /* error check */
+    ERREXIT(cinfo, JERR_PPM_NOT);
+
+  cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */
+  cinfo->image_width = (JDIMENSION) w;
+  cinfo->image_height = (JDIMENSION) h;
+
+  /* initialize flags to most common settings */
+  need_iobuffer = TRUE;		/* do we need an I/O buffer? */
+  use_raw_buffer = FALSE;	/* do we map input buffer onto I/O buffer? */
+  need_rescale = TRUE;		/* do we need a rescale array? */
+
+  switch (c) {
+  case '2':			/* it's a text-format PGM file */
+    cinfo->input_components = 1;
+    cinfo->in_color_space = JCS_GRAYSCALE;
+    TRACEMS2(cinfo, 1, JTRC_PGM_TEXT, w, h);
+    source->pub.get_pixel_rows = get_text_gray_row;
+    need_iobuffer = FALSE;
+    break;
+
+  case '3':			/* it's a text-format PPM file */
+    cinfo->input_components = 3;
+    cinfo->in_color_space = JCS_RGB;
+    TRACEMS2(cinfo, 1, JTRC_PPM_TEXT, w, h);
+    source->pub.get_pixel_rows = get_text_rgb_row;
+    need_iobuffer = FALSE;
+    break;
+
+  case '5':			/* it's a raw-format PGM file */
+    cinfo->input_components = 1;
+    cinfo->in_color_space = JCS_GRAYSCALE;
+    TRACEMS2(cinfo, 1, JTRC_PGM, w, h);
+    if (maxval > 255) {
+      source->pub.get_pixel_rows = get_word_gray_row;
+    } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) {
+      source->pub.get_pixel_rows = get_raw_row;
+      use_raw_buffer = TRUE;
+      need_rescale = FALSE;
+    } else {
+      source->pub.get_pixel_rows = get_scaled_gray_row;
+    }
+    break;
+
+  case '6':			/* it's a raw-format PPM file */
+    cinfo->input_components = 3;
+    cinfo->in_color_space = JCS_RGB;
+    TRACEMS2(cinfo, 1, JTRC_PPM, w, h);
+    if (maxval > 255) {
+      source->pub.get_pixel_rows = get_word_rgb_row;
+    } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) {
+      source->pub.get_pixel_rows = get_raw_row;
+      use_raw_buffer = TRUE;
+      need_rescale = FALSE;
+    } else {
+      source->pub.get_pixel_rows = get_scaled_rgb_row;
+    }
+    break;
+  }
+
+  /* Allocate space for I/O buffer: 1 or 3 bytes or words/pixel. */
+  if (need_iobuffer) {
+    source->buffer_width = (size_t) w * cinfo->input_components *
+      ((maxval<=255) ? SIZEOF(U_CHAR) : (2*SIZEOF(U_CHAR)));
+    source->iobuffer = (U_CHAR *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  source->buffer_width);
+  }
+
+  /* Create compressor input buffer. */
+  if (use_raw_buffer) {
+    /* For unscaled raw-input case, we can just map it onto the I/O buffer. */
+    /* Synthesize a JSAMPARRAY pointer structure */
+    /* Cast here implies near->far pointer conversion on PCs */
+    source->pixrow = (JSAMPROW) source->iobuffer;
+    source->pub.buffer = & source->pixrow;
+    source->pub.buffer_height = 1;
+  } else {
+    /* Need to translate anyway, so make a separate sample buffer. */
+    source->pub.buffer = (*cinfo->mem->alloc_sarray)
+      ((j_common_ptr) cinfo, JPOOL_IMAGE,
+       (JDIMENSION) w * cinfo->input_components, (JDIMENSION) 1);
+    source->pub.buffer_height = 1;
+  }
+
+  /* Compute the rescaling array if required. */
+  if (need_rescale) {
+    INT32 val, half_maxval;
+
+    /* On 16-bit-int machines we have to be careful of maxval = 65535 */
+    source->rescale = (JSAMPLE *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  (size_t) (((long) maxval + 1L) * SIZEOF(JSAMPLE)));
+    half_maxval = maxval / 2;
+    for (val = 0; val <= (INT32) maxval; val++) {
+      /* The multiplication here must be done in 32 bits to avoid overflow */
+      source->rescale[val] = (JSAMPLE) ((val*MAXJSAMPLE + half_maxval)/maxval);
+    }
+  }
+}
+
+
+/*
+ * Finish up at the end of the file.
+ */
+
+METHODDEF(void)
+finish_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+  /* no work */
+}
+
+
+/*
+ * The module selection routine for PPM format input.
+ */
+
+GLOBAL(cjpeg_source_ptr)
+jinit_read_ppm (j_compress_ptr cinfo)
+{
+  ppm_source_ptr source;
+
+  /* Create module interface object */
+  source = (ppm_source_ptr)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  SIZEOF(ppm_source_struct));
+  /* Fill in method ptrs, except get_pixel_rows which start_input sets */
+  source->pub.start_input = start_input_ppm;
+  source->pub.finish_input = finish_input_ppm;
+
+  return (cjpeg_source_ptr) source;
+}
+
+#endif /* PPM_SUPPORTED */
diff --git a/source/Irrlicht/jpeglib/rdrle.c b/source/Irrlicht/jpeglib/rdrle.c
new file mode 100644
index 00000000..df871e00
--- /dev/null
+++ b/source/Irrlicht/jpeglib/rdrle.c
@@ -0,0 +1,387 @@
+/*
+ * rdrle.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to read input images in Utah RLE format.
+ * The Utah Raster Toolkit library is required (version 3.1 or later).
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications.  As they stand, they assume input from
+ * an ordinary stdio stream.  They further assume that reading begins
+ * at the start of the file; start_input may need work if the
+ * user interface has already read some data (e.g., to determine that
+ * the file is indeed RLE format).
+ *
+ * Based on code contributed by Mike Lijewski,
+ * with updates from Robert Hutchinson.
+ */
+
+#include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
+
+#ifdef RLE_SUPPORTED
+
+/* rle.h is provided by the Utah Raster Toolkit. */
+
+#include 
+
+/*
+ * We assume that JSAMPLE has the same representation as rle_pixel,
+ * to wit, "unsigned char".  Hence we can't cope with 12- or 16-bit samples.
+ */
+
+#if BITS_IN_JSAMPLE != 8
+  Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
+#endif
+
+/*
+ * We support the following types of RLE files:
+ *   
+ *   GRAYSCALE   - 8 bits, no colormap
+ *   MAPPEDGRAY  - 8 bits, 1 channel colomap
+ *   PSEUDOCOLOR - 8 bits, 3 channel colormap
+ *   TRUECOLOR   - 24 bits, 3 channel colormap
+ *   DIRECTCOLOR - 24 bits, no colormap
+ *
+ * For now, we ignore any alpha channel in the image.
+ */
+
+typedef enum
+  { GRAYSCALE, MAPPEDGRAY, PSEUDOCOLOR, TRUECOLOR, DIRECTCOLOR } rle_kind;
+
+
+/*
+ * Since RLE stores scanlines bottom-to-top, we have to invert the image
+ * to conform to JPEG's top-to-bottom order.  To do this, we read the
+ * incoming image into a virtual array on the first get_pixel_rows call,
+ * then fetch the required row from the virtual array on subsequent calls.
+ */
+
+typedef struct _rle_source_struct * rle_source_ptr;
+
+typedef struct _rle_source_struct {
+  struct cjpeg_source_struct pub; /* public fields */
+
+  rle_kind visual;              /* actual type of input file */
+  jvirt_sarray_ptr image;       /* virtual array to hold the image */
+  JDIMENSION row;		/* current row # in the virtual array */
+  rle_hdr header;               /* Input file information */
+  rle_pixel** rle_row;          /* holds a row returned by rle_getrow() */
+
+} rle_source_struct;
+
+
+/*
+ * Read the file header; return image size and component count.
+ */
+
+METHODDEF(void)
+start_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+  rle_source_ptr source = (rle_source_ptr) sinfo;
+  JDIMENSION width, height;
+#ifdef PROGRESS_REPORT
+  cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+#endif
+
+  /* Use RLE library routine to get the header info */
+  source->header = *rle_hdr_init(NULL);
+  source->header.rle_file = source->pub.input_file;
+  switch (rle_get_setup(&(source->header))) {
+  case RLE_SUCCESS:
+    /* A-OK */
+    break;
+  case RLE_NOT_RLE:
+    ERREXIT(cinfo, JERR_RLE_NOT);
+    break;
+  case RLE_NO_SPACE:
+    ERREXIT(cinfo, JERR_RLE_MEM);
+    break;
+  case RLE_EMPTY:
+    ERREXIT(cinfo, JERR_RLE_EMPTY);
+    break;
+  case RLE_EOF:
+    ERREXIT(cinfo, JERR_RLE_EOF);
+    break;
+  default:
+    ERREXIT(cinfo, JERR_RLE_BADERROR);
+    break;
+  }
+
+  /* Figure out what we have, set private vars and return values accordingly */
+  
+  width  = source->header.xmax - source->header.xmin + 1;
+  height = source->header.ymax - source->header.ymin + 1;
+  source->header.xmin = 0;		/* realign horizontally */
+  source->header.xmax = width-1;
+
+  cinfo->image_width      = width;
+  cinfo->image_height     = height;
+  cinfo->data_precision   = 8;  /* we can only handle 8 bit data */
+
+  if (source->header.ncolors == 1 && source->header.ncmap == 0) {
+    source->visual     = GRAYSCALE;
+    TRACEMS2(cinfo, 1, JTRC_RLE_GRAY, width, height);
+  } else if (source->header.ncolors == 1 && source->header.ncmap == 1) {
+    source->visual     = MAPPEDGRAY;
+    TRACEMS3(cinfo, 1, JTRC_RLE_MAPGRAY, width, height,
+             1 << source->header.cmaplen);
+  } else if (source->header.ncolors == 1 && source->header.ncmap == 3) {
+    source->visual     = PSEUDOCOLOR;
+    TRACEMS3(cinfo, 1, JTRC_RLE_MAPPED, width, height,
+	     1 << source->header.cmaplen);
+  } else if (source->header.ncolors == 3 && source->header.ncmap == 3) {
+    source->visual     = TRUECOLOR;
+    TRACEMS3(cinfo, 1, JTRC_RLE_FULLMAP, width, height,
+	     1 << source->header.cmaplen);
+  } else if (source->header.ncolors == 3 && source->header.ncmap == 0) {
+    source->visual     = DIRECTCOLOR;
+    TRACEMS2(cinfo, 1, JTRC_RLE, width, height);
+  } else
+    ERREXIT(cinfo, JERR_RLE_UNSUPPORTED);
+  
+  if (source->visual == GRAYSCALE || source->visual == MAPPEDGRAY) {
+    cinfo->in_color_space   = JCS_GRAYSCALE;
+    cinfo->input_components = 1;
+  } else {
+    cinfo->in_color_space   = JCS_RGB;
+    cinfo->input_components = 3;
+  }
+
+  /*
+   * A place to hold each scanline while it's converted.
+   * (GRAYSCALE scanlines don't need converting)
+   */
+  if (source->visual != GRAYSCALE) {
+    source->rle_row = (rle_pixel**) (*cinfo->mem->alloc_sarray)
+      ((j_common_ptr) cinfo, JPOOL_IMAGE,
+       (JDIMENSION) width, (JDIMENSION) cinfo->input_components);
+  }
+
+  /* request a virtual array to hold the image */
+  source->image = (*cinfo->mem->request_virt_sarray)
+    ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+     (JDIMENSION) (width * source->header.ncolors),
+     (JDIMENSION) height, (JDIMENSION) 1);
+
+#ifdef PROGRESS_REPORT
+  if (progress != NULL) {
+    /* count file input as separate pass */
+    progress->total_extra_passes++;
+  }
+#endif
+
+  source->pub.buffer_height = 1;
+}
+
+
+/*
+ * Read one row of pixels.
+ * Called only after load_image has read the image into the virtual array.
+ * Used for GRAYSCALE, MAPPEDGRAY, TRUECOLOR, and DIRECTCOLOR images.
+ */
+
+METHODDEF(JDIMENSION)
+get_rle_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+  rle_source_ptr source = (rle_source_ptr) sinfo;
+
+  source->row--;
+  source->pub.buffer = (*cinfo->mem->access_virt_sarray)
+    ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);
+
+  return 1;
+}
+
+/*
+ * Read one row of pixels.
+ * Called only after load_image has read the image into the virtual array.
+ * Used for PSEUDOCOLOR images.
+ */
+
+METHODDEF(JDIMENSION)
+get_pseudocolor_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+  rle_source_ptr source = (rle_source_ptr) sinfo;
+  JSAMPROW src_row, dest_row;
+  JDIMENSION col;
+  rle_map *colormap;
+  int val;
+
+  colormap = source->header.cmap;
+  dest_row = source->pub.buffer[0];
+  source->row--;
+  src_row = * (*cinfo->mem->access_virt_sarray)
+    ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);
+
+  for (col = cinfo->image_width; col > 0; col--) {
+    val = GETJSAMPLE(*src_row++);
+    *dest_row++ = (JSAMPLE) (colormap[val      ] >> 8);
+    *dest_row++ = (JSAMPLE) (colormap[val + 256] >> 8);
+    *dest_row++ = (JSAMPLE) (colormap[val + 512] >> 8);
+  }
+
+  return 1;
+}
+
+
+/*
+ * Load the image into a virtual array.  We have to do this because RLE
+ * files start at the lower left while the JPEG standard has them starting
+ * in the upper left.  This is called the first time we want to get a row
+ * of input.  What we do is load the RLE data into the array and then call
+ * the appropriate routine to read one row from the array.  Before returning,
+ * we set source->pub.get_pixel_rows so that subsequent calls go straight to
+ * the appropriate row-reading routine.
+ */
+
+METHODDEF(JDIMENSION)
+load_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+  rle_source_ptr source = (rle_source_ptr) sinfo;
+  JDIMENSION row, col;
+  JSAMPROW  scanline, red_ptr, green_ptr, blue_ptr;
+  rle_pixel **rle_row;
+  rle_map *colormap;
+  char channel;
+#ifdef PROGRESS_REPORT
+  cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+#endif
+
+  colormap = source->header.cmap;
+  rle_row = source->rle_row;
+
+  /* Read the RLE data into our virtual array.
+   * We assume here that (a) rle_pixel is represented the same as JSAMPLE,
+   * and (b) we are not on a machine where FAR pointers differ from regular.
+   */
+  RLE_CLR_BIT(source->header, RLE_ALPHA); /* don't read the alpha channel */
+
+#ifdef PROGRESS_REPORT
+  if (progress != NULL) {
+    progress->pub.pass_limit = cinfo->image_height;
+    progress->pub.pass_counter = 0;
+    (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+  }
+#endif
+
+  switch (source->visual) {
+
+  case GRAYSCALE:
+  case PSEUDOCOLOR:
+    for (row = 0; row < cinfo->image_height; row++) {
+      rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray)
+         ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
+      rle_getrow(&source->header, rle_row);
+#ifdef PROGRESS_REPORT
+      if (progress != NULL) {
+        progress->pub.pass_counter++;
+        (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+      }
+#endif
+    }
+    break;
+
+  case MAPPEDGRAY:
+  case TRUECOLOR:
+    for (row = 0; row < cinfo->image_height; row++) {
+      scanline = * (*cinfo->mem->access_virt_sarray)
+        ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
+      rle_row = source->rle_row;
+      rle_getrow(&source->header, rle_row);
+
+      for (col = 0; col < cinfo->image_width; col++) {
+        for (channel = 0; channel < source->header.ncolors; channel++) {
+          *scanline++ = (JSAMPLE)
+            (colormap[GETJSAMPLE(rle_row[channel][col]) + 256 * channel] >> 8);
+        }
+      }
+
+#ifdef PROGRESS_REPORT
+      if (progress != NULL) {
+        progress->pub.pass_counter++;
+        (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+      }
+#endif
+    }
+    break;
+
+  case DIRECTCOLOR:
+    for (row = 0; row < cinfo->image_height; row++) {
+      scanline = * (*cinfo->mem->access_virt_sarray)
+        ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
+      rle_getrow(&source->header, rle_row);
+
+      red_ptr   = rle_row[0];
+      green_ptr = rle_row[1];
+      blue_ptr  = rle_row[2];
+
+      for (col = cinfo->image_width; col > 0; col--) {
+        *scanline++ = *red_ptr++;
+        *scanline++ = *green_ptr++;
+        *scanline++ = *blue_ptr++;
+      }
+
+#ifdef PROGRESS_REPORT
+      if (progress != NULL) {
+        progress->pub.pass_counter++;
+        (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+      }
+#endif
+    }
+  }
+
+#ifdef PROGRESS_REPORT
+  if (progress != NULL)
+    progress->completed_extra_passes++;
+#endif
+
+  /* Set up to call proper row-extraction routine in future */
+  if (source->visual == PSEUDOCOLOR) {
+    source->pub.buffer = source->rle_row;
+    source->pub.get_pixel_rows = get_pseudocolor_row;
+  } else {
+    source->pub.get_pixel_rows = get_rle_row;
+  }
+  source->row = cinfo->image_height;
+
+  /* And fetch the topmost (bottommost) row */
+  return (*source->pub.get_pixel_rows) (cinfo, sinfo);   
+}
+
+
+/*
+ * Finish up at the end of the file.
+ */
+
+METHODDEF(void)
+finish_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+  /* no work */
+}
+
+
+/*
+ * The module selection routine for RLE format input.
+ */
+
+GLOBAL(cjpeg_source_ptr)
+jinit_read_rle (j_compress_ptr cinfo)
+{
+  rle_source_ptr source;
+
+  /* Create module interface object */
+  source = (rle_source_ptr)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+                                  SIZEOF(rle_source_struct));
+  /* Fill in method ptrs */
+  source->pub.start_input = start_input_rle;
+  source->pub.finish_input = finish_input_rle;
+  source->pub.get_pixel_rows = load_image;
+
+  return (cjpeg_source_ptr) source;
+}
+
+#endif /* RLE_SUPPORTED */
diff --git a/source/Irrlicht/jpeglib/rdswitch.c b/source/Irrlicht/jpeglib/rdswitch.c
new file mode 100644
index 00000000..5eebcc1e
--- /dev/null
+++ b/source/Irrlicht/jpeglib/rdswitch.c
@@ -0,0 +1,365 @@
+/*
+ * rdswitch.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to process some of cjpeg's more complicated
+ * command-line switches.  Switches processed here are:
+ *	-qtables file		Read quantization tables from text file
+ *	-scans file		Read scan script from text file
+ *	-quality N[,N,...]	Set quality ratings
+ *	-qslots N[,N,...]	Set component quantization table selectors
+ *	-sample HxV[,HxV,...]	Set component sampling factors
+ */
+
+#include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
+#include 		/* to declare isdigit(), isspace() */
+
+
+LOCAL(int)
+text_getc (FILE * file)
+/* Read next char, skipping over any comments (# to end of line) */
+/* A comment/newline sequence is returned as a newline */
+{
+  register int ch;
+  
+  ch = getc(file);
+  if (ch == '#') {
+    do {
+      ch = getc(file);
+    } while (ch != '\n' && ch != EOF);
+  }
+  return ch;
+}
+
+
+LOCAL(boolean)
+read_text_integer (FILE * file, long * result, int * termchar)
+/* Read an unsigned decimal integer from a file, store it in result */
+/* Reads one trailing character after the integer; returns it in termchar */
+{
+  register int ch;
+  register long val;
+  
+  /* Skip any leading whitespace, detect EOF */
+  do {
+    ch = text_getc(file);
+    if (ch == EOF) {
+      *termchar = ch;
+      return FALSE;
+    }
+  } while (isspace(ch));
+  
+  if (! isdigit(ch)) {
+    *termchar = ch;
+    return FALSE;
+  }
+
+  val = ch - '0';
+  while ((ch = text_getc(file)) != EOF) {
+    if (! isdigit(ch))
+      break;
+    val *= 10;
+    val += ch - '0';
+  }
+  *result = val;
+  *termchar = ch;
+  return TRUE;
+}
+
+
+GLOBAL(boolean)
+read_quant_tables (j_compress_ptr cinfo, char * filename, boolean force_baseline)
+/* Read a set of quantization tables from the specified file.
+ * The file is plain ASCII text: decimal numbers with whitespace between.
+ * Comments preceded by '#' may be included in the file.
+ * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values.
+ * The tables are implicitly numbered 0,1,etc.
+ * NOTE: does not affect the qslots mapping, which will default to selecting
+ * table 0 for luminance (or primary) components, 1 for chrominance components.
+ * You must use -qslots if you want a different component->table mapping.
+ */
+{
+  FILE * fp;
+  int tblno, i, termchar;
+  long val;
+  unsigned int table[DCTSIZE2];
+
+  if ((fp = fopen(filename, "r")) == NULL) {
+    fprintf(stderr, "Can't open table file %s\n", filename);
+    return FALSE;
+  }
+  tblno = 0;
+
+  while (read_text_integer(fp, &val, &termchar)) { /* read 1st element of table */
+    if (tblno >= NUM_QUANT_TBLS) {
+      fprintf(stderr, "Too many tables in file %s\n", filename);
+      fclose(fp);
+      return FALSE;
+    }
+    table[0] = (unsigned int) val;
+    for (i = 1; i < DCTSIZE2; i++) {
+      if (! read_text_integer(fp, &val, &termchar)) {
+	fprintf(stderr, "Invalid table data in file %s\n", filename);
+	fclose(fp);
+	return FALSE;
+      }
+      table[i] = (unsigned int) val;
+    }
+    jpeg_add_quant_table(cinfo, tblno, table, cinfo->q_scale_factor[tblno],
+			 force_baseline);
+    tblno++;
+  }
+
+  if (termchar != EOF) {
+    fprintf(stderr, "Non-numeric data in file %s\n", filename);
+    fclose(fp);
+    return FALSE;
+  }
+
+  fclose(fp);
+  return TRUE;
+}
+
+
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+
+LOCAL(boolean)
+read_scan_integer (FILE * file, long * result, int * termchar)
+/* Variant of read_text_integer that always looks for a non-space termchar;
+ * this simplifies parsing of punctuation in scan scripts.
+ */
+{
+  register int ch;
+
+  if (! read_text_integer(file, result, termchar))
+    return FALSE;
+  ch = *termchar;
+  while (ch != EOF && isspace(ch))
+    ch = text_getc(file);
+  if (isdigit(ch)) {		/* oops, put it back */
+    if (ungetc(ch, file) == EOF)
+      return FALSE;
+    ch = ' ';
+  } else {
+    /* Any separators other than ';' and ':' are ignored;
+     * this allows user to insert commas, etc, if desired.
+     */
+    if (ch != EOF && ch != ';' && ch != ':')
+      ch = ' ';
+  }
+  *termchar = ch;
+  return TRUE;
+}
+
+
+GLOBAL(boolean)
+read_scan_script (j_compress_ptr cinfo, char * filename)
+/* Read a scan script from the specified text file.
+ * Each entry in the file defines one scan to be emitted.
+ * Entries are separated by semicolons ';'.
+ * An entry contains one to four component indexes,
+ * optionally followed by a colon ':' and four progressive-JPEG parameters.
+ * The component indexes denote which component(s) are to be transmitted
+ * in the current scan.  The first component has index 0.
+ * Sequential JPEG is used if the progressive-JPEG parameters are omitted.
+ * The file is free format text: any whitespace may appear between numbers
+ * and the ':' and ';' punctuation marks.  Also, other punctuation (such
+ * as commas or dashes) can be placed between numbers if desired.
+ * Comments preceded by '#' may be included in the file.
+ * Note: we do very little validity checking here;
+ * jcmaster.c will validate the script parameters.
+ */
+{
+  FILE * fp;
+  int scanno, ncomps, termchar;
+  long val;
+  jpeg_scan_info * scanptr;
+#define MAX_SCANS  100		/* quite arbitrary limit */
+  jpeg_scan_info scans[MAX_SCANS];
+
+  if ((fp = fopen(filename, "r")) == NULL) {
+    fprintf(stderr, "Can't open scan definition file %s\n", filename);
+    return FALSE;
+  }
+  scanptr = scans;
+  scanno = 0;
+
+  while (read_scan_integer(fp, &val, &termchar)) {
+    if (scanno >= MAX_SCANS) {
+      fprintf(stderr, "Too many scans defined in file %s\n", filename);
+      fclose(fp);
+      return FALSE;
+    }
+    scanptr->component_index[0] = (int) val;
+    ncomps = 1;
+    while (termchar == ' ') {
+      if (ncomps >= MAX_COMPS_IN_SCAN) {
+	fprintf(stderr, "Too many components in one scan in file %s\n",
+		filename);
+	fclose(fp);
+	return FALSE;
+      }
+      if (! read_scan_integer(fp, &val, &termchar))
+	goto bogus;
+      scanptr->component_index[ncomps] = (int) val;
+      ncomps++;
+    }
+    scanptr->comps_in_scan = ncomps;
+    if (termchar == ':') {
+      if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
+	goto bogus;
+      scanptr->Ss = (int) val;
+      if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
+	goto bogus;
+      scanptr->Se = (int) val;
+      if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
+	goto bogus;
+      scanptr->Ah = (int) val;
+      if (! read_scan_integer(fp, &val, &termchar))
+	goto bogus;
+      scanptr->Al = (int) val;
+    } else {
+      /* set non-progressive parameters */
+      scanptr->Ss = 0;
+      scanptr->Se = DCTSIZE2-1;
+      scanptr->Ah = 0;
+      scanptr->Al = 0;
+    }
+    if (termchar != ';' && termchar != EOF) {
+bogus:
+      fprintf(stderr, "Invalid scan entry format in file %s\n", filename);
+      fclose(fp);
+      return FALSE;
+    }
+    scanptr++, scanno++;
+  }
+
+  if (termchar != EOF) {
+    fprintf(stderr, "Non-numeric data in file %s\n", filename);
+    fclose(fp);
+    return FALSE;
+  }
+
+  if (scanno > 0) {
+    /* Stash completed scan list in cinfo structure.
+     * NOTE: for cjpeg's use, JPOOL_IMAGE is the right lifetime for this data,
+     * but if you want to compress multiple images you'd want JPOOL_PERMANENT.
+     */
+    scanptr = (jpeg_scan_info *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  scanno * SIZEOF(jpeg_scan_info));
+    MEMCOPY(scanptr, scans, scanno * SIZEOF(jpeg_scan_info));
+    cinfo->scan_info = scanptr;
+    cinfo->num_scans = scanno;
+  }
+
+  fclose(fp);
+  return TRUE;
+}
+
+#endif /* C_MULTISCAN_FILES_SUPPORTED */
+
+
+GLOBAL(boolean)
+set_quality_ratings (j_compress_ptr cinfo, char *arg, boolean force_baseline)
+/* Process a quality-ratings parameter string, of the form
+ *     N[,N,...]
+ * If there are more q-table slots than parameters, the last value is replicated.
+ */
+{
+  int val = 75;			/* default value */
+  int tblno;
+  char ch;
+
+  for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
+    if (*arg) {
+      ch = ',';			/* if not set by sscanf, will be ',' */
+      if (sscanf(arg, "%d%c", &val, &ch) < 1)
+	return FALSE;
+      if (ch != ',')		/* syntax check */
+	return FALSE;
+      /* Convert user 0-100 rating to percentage scaling */
+      cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
+      while (*arg && *arg++ != ',') /* advance to next segment of arg string */
+	;
+    } else {
+      /* reached end of parameter, set remaining factors to last value */
+      cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
+    }
+  }
+  jpeg_default_qtables(cinfo, force_baseline);
+  return TRUE;
+}
+
+
+GLOBAL(boolean)
+set_quant_slots (j_compress_ptr cinfo, char *arg)
+/* Process a quantization-table-selectors parameter string, of the form
+ *     N[,N,...]
+ * If there are more components than parameters, the last value is replicated.
+ */
+{
+  int val = 0;			/* default table # */
+  int ci;
+  char ch;
+
+  for (ci = 0; ci < MAX_COMPONENTS; ci++) {
+    if (*arg) {
+      ch = ',';			/* if not set by sscanf, will be ',' */
+      if (sscanf(arg, "%d%c", &val, &ch) < 1)
+	return FALSE;
+      if (ch != ',')		/* syntax check */
+	return FALSE;
+      if (val < 0 || val >= NUM_QUANT_TBLS) {
+	fprintf(stderr, "JPEG quantization tables are numbered 0..%d\n",
+		NUM_QUANT_TBLS-1);
+	return FALSE;
+      }
+      cinfo->comp_info[ci].quant_tbl_no = val;
+      while (*arg && *arg++ != ',') /* advance to next segment of arg string */
+	;
+    } else {
+      /* reached end of parameter, set remaining components to last table */
+      cinfo->comp_info[ci].quant_tbl_no = val;
+    }
+  }
+  return TRUE;
+}
+
+
+GLOBAL(boolean)
+set_sample_factors (j_compress_ptr cinfo, char *arg)
+/* Process a sample-factors parameter string, of the form
+ *     HxV[,HxV,...]
+ * If there are more components than parameters, "1x1" is assumed for the rest.
+ */
+{
+  int ci, val1, val2;
+  char ch1, ch2;
+
+  for (ci = 0; ci < MAX_COMPONENTS; ci++) {
+    if (*arg) {
+      ch2 = ',';		/* if not set by sscanf, will be ',' */
+      if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3)
+	return FALSE;
+      if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */
+	return FALSE;
+      if (val1 <= 0 || val1 > 4 || val2 <= 0 || val2 > 4) {
+	fprintf(stderr, "JPEG sampling factors must be 1..4\n");
+	return FALSE;
+      }
+      cinfo->comp_info[ci].h_samp_factor = val1;
+      cinfo->comp_info[ci].v_samp_factor = val2;
+      while (*arg && *arg++ != ',') /* advance to next segment of arg string */
+	;
+    } else {
+      /* reached end of parameter, set remaining components to 1x1 sampling */
+      cinfo->comp_info[ci].h_samp_factor = 1;
+      cinfo->comp_info[ci].v_samp_factor = 1;
+    }
+  }
+  return TRUE;
+}
diff --git a/source/Irrlicht/jpeglib/rdtarga.c b/source/Irrlicht/jpeglib/rdtarga.c
new file mode 100644
index 00000000..d7ffc33e
--- /dev/null
+++ b/source/Irrlicht/jpeglib/rdtarga.c
@@ -0,0 +1,500 @@
+/*
+ * rdtarga.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to read input images in Targa format.
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications.  As they stand, they assume input from
+ * an ordinary stdio stream.  They further assume that reading begins
+ * at the start of the file; start_input may need work if the
+ * user interface has already read some data (e.g., to determine that
+ * the file is indeed Targa format).
+ *
+ * Based on code contributed by Lee Daniel Crocker.
+ */
+
+#include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
+
+#ifdef TARGA_SUPPORTED
+
+
+/* Macros to deal with unsigned chars as efficiently as compiler allows */
+
+#ifdef HAVE_UNSIGNED_CHAR
+typedef unsigned char U_CHAR;
+#define UCH(x)	((int) (x))
+#else /* !HAVE_UNSIGNED_CHAR */
+#ifdef CHAR_IS_UNSIGNED
+typedef char U_CHAR;
+#define UCH(x)	((int) (x))
+#else
+typedef char U_CHAR;
+#define UCH(x)	((int) (x) & 0xFF)
+#endif
+#endif /* HAVE_UNSIGNED_CHAR */
+
+
+#define	ReadOK(file,buffer,len)	(JFREAD(file,buffer,len) == ((size_t) (len)))
+
+
+/* Private version of data source object */
+
+typedef struct _tga_source_struct * tga_source_ptr;
+
+typedef struct _tga_source_struct {
+  struct cjpeg_source_struct pub; /* public fields */
+
+  j_compress_ptr cinfo;		/* back link saves passing separate parm */
+
+  JSAMPARRAY colormap;		/* Targa colormap (converted to my format) */
+
+  jvirt_sarray_ptr whole_image;	/* Needed if funny input row order */
+  JDIMENSION current_row;	/* Current logical row number to read */
+
+  /* Pointer to routine to extract next Targa pixel from input file */
+  JMETHOD(void, read_pixel, (tga_source_ptr sinfo));
+
+  /* Result of read_pixel is delivered here: */
+  U_CHAR tga_pixel[4];
+
+  int pixel_size;		/* Bytes per Targa pixel (1 to 4) */
+
+  /* State info for reading RLE-coded pixels; both counts must be init to 0 */
+  int block_count;		/* # of pixels remaining in RLE block */
+  int dup_pixel_count;		/* # of times to duplicate previous pixel */
+
+  /* This saves the correct pixel-row-expansion method for preload_image */
+  JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo,
+				       cjpeg_source_ptr sinfo));
+} tga_source_struct;
+
+
+/* For expanding 5-bit pixel values to 8-bit with best rounding */
+
+static const UINT8 c5to8bits[32] = {
+    0,   8,  16,  25,  33,  41,  49,  58,
+   66,  74,  82,  90,  99, 107, 115, 123,
+  132, 140, 148, 156, 165, 173, 181, 189,
+  197, 206, 214, 222, 230, 239, 247, 255
+};
+
+
+
+LOCAL(int)
+read_byte (tga_source_ptr sinfo)
+/* Read next byte from Targa file */
+{
+  register FILE *infile = sinfo->pub.input_file;
+  register int c;
+
+  if ((c = getc(infile)) == EOF)
+    ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
+  return c;
+}
+
+
+LOCAL(void)
+read_colormap (tga_source_ptr sinfo, int cmaplen, int mapentrysize)
+/* Read the colormap from a Targa file */
+{
+  int i;
+
+  /* Presently only handles 24-bit BGR format */
+  if (mapentrysize != 24)
+    ERREXIT(sinfo->cinfo, JERR_TGA_BADCMAP);
+
+  for (i = 0; i < cmaplen; i++) {
+    sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo);
+    sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo);
+    sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo);
+  }
+}
+
+
+/*
+ * read_pixel methods: get a single pixel from Targa file into tga_pixel[]
+ */
+
+METHODDEF(void)
+read_non_rle_pixel (tga_source_ptr sinfo)
+/* Read one Targa pixel from the input file; no RLE expansion */
+{
+  register FILE *infile = sinfo->pub.input_file;
+  register int i;
+
+  for (i = 0; i < sinfo->pixel_size; i++) {
+    sinfo->tga_pixel[i] = (U_CHAR) getc(infile);
+  }
+}
+
+
+METHODDEF(void)
+read_rle_pixel (tga_source_ptr sinfo)
+/* Read one Targa pixel from the input file, expanding RLE data as needed */
+{
+  register FILE *infile = sinfo->pub.input_file;
+  register int i;
+
+  /* Duplicate previously read pixel? */
+  if (sinfo->dup_pixel_count > 0) {
+    sinfo->dup_pixel_count--;
+    return;
+  }
+
+  /* Time to read RLE block header? */
+  if (--sinfo->block_count < 0) { /* decrement pixels remaining in block */
+    i = read_byte(sinfo);
+    if (i & 0x80) {		/* Start of duplicate-pixel block? */
+      sinfo->dup_pixel_count = i & 0x7F; /* number of dups after this one */
+      sinfo->block_count = 0;	/* then read new block header */
+    } else {
+      sinfo->block_count = i & 0x7F; /* number of pixels after this one */
+    }
+  }
+
+  /* Read next pixel */
+  for (i = 0; i < sinfo->pixel_size; i++) {
+    sinfo->tga_pixel[i] = (U_CHAR) getc(infile);
+  }
+}
+
+
+/*
+ * Read one row of pixels.
+ *
+ * We provide several different versions depending on input file format.
+ */
+
+
+METHODDEF(JDIMENSION)
+get_8bit_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 8-bit grayscale pixels */
+{
+  tga_source_ptr source = (tga_source_ptr) sinfo;
+  register JSAMPROW ptr;
+  register JDIMENSION col;
+  
+  ptr = source->pub.buffer[0];
+  for (col = cinfo->image_width; col > 0; col--) {
+    (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
+    *ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]);
+  }
+  return 1;
+}
+
+METHODDEF(JDIMENSION)
+get_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 8-bit colormap indexes */
+{
+  tga_source_ptr source = (tga_source_ptr) sinfo;
+  register int t;
+  register JSAMPROW ptr;
+  register JDIMENSION col;
+  register JSAMPARRAY colormap = source->colormap;
+
+  ptr = source->pub.buffer[0];
+  for (col = cinfo->image_width; col > 0; col--) {
+    (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
+    t = UCH(source->tga_pixel[0]);
+    *ptr++ = colormap[0][t];
+    *ptr++ = colormap[1][t];
+    *ptr++ = colormap[2][t];
+  }
+  return 1;
+}
+
+METHODDEF(JDIMENSION)
+get_16bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 16-bit pixels */
+{
+  tga_source_ptr source = (tga_source_ptr) sinfo;
+  register int t;
+  register JSAMPROW ptr;
+  register JDIMENSION col;
+  
+  ptr = source->pub.buffer[0];
+  for (col = cinfo->image_width; col > 0; col--) {
+    (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
+    t = UCH(source->tga_pixel[0]);
+    t += UCH(source->tga_pixel[1]) << 8;
+    /* We expand 5 bit data to 8 bit sample width.
+     * The format of the 16-bit (LSB first) input word is
+     *     xRRRRRGGGGGBBBBB
+     */
+    ptr[2] = (JSAMPLE) c5to8bits[t & 0x1F];
+    t >>= 5;
+    ptr[1] = (JSAMPLE) c5to8bits[t & 0x1F];
+    t >>= 5;
+    ptr[0] = (JSAMPLE) c5to8bits[t & 0x1F];
+    ptr += 3;
+  }
+  return 1;
+}
+
+METHODDEF(JDIMENSION)
+get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 24-bit pixels */
+{
+  tga_source_ptr source = (tga_source_ptr) sinfo;
+  register JSAMPROW ptr;
+  register JDIMENSION col;
+  
+  ptr = source->pub.buffer[0];
+  for (col = cinfo->image_width; col > 0; col--) {
+    (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
+    *ptr++ = (JSAMPLE) UCH(source->tga_pixel[2]); /* change BGR to RGB order */
+    *ptr++ = (JSAMPLE) UCH(source->tga_pixel[1]);
+    *ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]);
+  }
+  return 1;
+}
+
+/*
+ * Targa also defines a 32-bit pixel format with order B,G,R,A.
+ * We presently ignore the attribute byte, so the code for reading
+ * these pixels is identical to the 24-bit routine above.
+ * This works because the actual pixel length is only known to read_pixel.
+ */
+
+#define get_32bit_row  get_24bit_row
+
+
+/*
+ * This method is for re-reading the input data in standard top-down
+ * row order.  The entire image has already been read into whole_image
+ * with proper conversion of pixel format, but it's in a funny row order.
+ */
+
+METHODDEF(JDIMENSION)
+get_memory_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+  tga_source_ptr source = (tga_source_ptr) sinfo;
+  JDIMENSION source_row;
+
+  /* Compute row of source that maps to current_row of normal order */
+  /* For now, assume image is bottom-up and not interlaced. */
+  /* NEEDS WORK to support interlaced images! */
+  source_row = cinfo->image_height - source->current_row - 1;
+
+  /* Fetch that row from virtual array */
+  source->pub.buffer = (*cinfo->mem->access_virt_sarray)
+    ((j_common_ptr) cinfo, source->whole_image,
+     source_row, (JDIMENSION) 1, FALSE);
+
+  source->current_row++;
+  return 1;
+}
+
+
+/*
+ * This method loads the image into whole_image during the first call on
+ * get_pixel_rows.  The get_pixel_rows pointer is then adjusted to call
+ * get_memory_row on subsequent calls.
+ */
+
+METHODDEF(JDIMENSION)
+preload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+  tga_source_ptr source = (tga_source_ptr) sinfo;
+  JDIMENSION row;
+  cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+
+  /* Read the data into a virtual array in input-file row order. */
+  for (row = 0; row < cinfo->image_height; row++) {
+    if (progress != NULL) {
+      progress->pub.pass_counter = (long) row;
+      progress->pub.pass_limit = (long) cinfo->image_height;
+      (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+    }
+    source->pub.buffer = (*cinfo->mem->access_virt_sarray)
+      ((j_common_ptr) cinfo, source->whole_image, row, (JDIMENSION) 1, TRUE);
+    (*source->get_pixel_rows) (cinfo, sinfo);
+  }
+  if (progress != NULL)
+    progress->completed_extra_passes++;
+
+  /* Set up to read from the virtual array in unscrambled order */
+  source->pub.get_pixel_rows = get_memory_row;
+  source->current_row = 0;
+  /* And read the first row */
+  return get_memory_row(cinfo, sinfo);
+}
+
+
+/*
+ * Read the file header; return image size and component count.
+ */
+
+METHODDEF(void)
+start_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+  tga_source_ptr source = (tga_source_ptr) sinfo;
+  U_CHAR targaheader[18];
+  int idlen, cmaptype, subtype, flags, interlace_type, components;
+  unsigned int width, height, maplen;
+  boolean is_bottom_up;
+
+#define GET_2B(offset)	((unsigned int) UCH(targaheader[offset]) + \
+			 (((unsigned int) UCH(targaheader[offset+1])) << 8))
+
+  if (! ReadOK(source->pub.input_file, targaheader, 18))
+    ERREXIT(cinfo, JERR_INPUT_EOF);
+
+  /* Pretend "15-bit" pixels are 16-bit --- we ignore attribute bit anyway */
+  if (targaheader[16] == 15)
+    targaheader[16] = 16;
+
+  idlen = UCH(targaheader[0]);
+  cmaptype = UCH(targaheader[1]);
+  subtype = UCH(targaheader[2]);
+  maplen = GET_2B(5);
+  width = GET_2B(12);
+  height = GET_2B(14);
+  source->pixel_size = UCH(targaheader[16]) >> 3;
+  flags = UCH(targaheader[17]);	/* Image Descriptor byte */
+
+  is_bottom_up = ((flags & 0x20) == 0);	/* bit 5 set => top-down */
+  interlace_type = flags >> 6;	/* bits 6/7 are interlace code */
+
+  if (cmaptype > 1 ||		/* cmaptype must be 0 or 1 */
+      source->pixel_size < 1 || source->pixel_size > 4 ||
+      (UCH(targaheader[16]) & 7) != 0 || /* bits/pixel must be multiple of 8 */
+      interlace_type != 0)	/* currently don't allow interlaced image */
+    ERREXIT(cinfo, JERR_TGA_BADPARMS);
+  
+  if (subtype > 8) {
+    /* It's an RLE-coded file */
+    source->read_pixel = read_rle_pixel;
+    source->block_count = source->dup_pixel_count = 0;
+    subtype -= 8;
+  } else {
+    /* Non-RLE file */
+    source->read_pixel = read_non_rle_pixel;
+  }
+
+  /* Now should have subtype 1, 2, or 3 */
+  components = 3;		/* until proven different */
+  cinfo->in_color_space = JCS_RGB;
+
+  switch (subtype) {
+  case 1:			/* Colormapped image */
+    if (source->pixel_size == 1 && cmaptype == 1)
+      source->get_pixel_rows = get_8bit_row;
+    else
+      ERREXIT(cinfo, JERR_TGA_BADPARMS);
+    TRACEMS2(cinfo, 1, JTRC_TGA_MAPPED, width, height);
+    break;
+  case 2:			/* RGB image */
+    switch (source->pixel_size) {
+    case 2:
+      source->get_pixel_rows = get_16bit_row;
+      break;
+    case 3:
+      source->get_pixel_rows = get_24bit_row;
+      break;
+    case 4:
+      source->get_pixel_rows = get_32bit_row;
+      break;
+    default:
+      ERREXIT(cinfo, JERR_TGA_BADPARMS);
+      break;
+    }
+    TRACEMS2(cinfo, 1, JTRC_TGA, width, height);
+    break;
+  case 3:			/* Grayscale image */
+    components = 1;
+    cinfo->in_color_space = JCS_GRAYSCALE;
+    if (source->pixel_size == 1)
+      source->get_pixel_rows = get_8bit_gray_row;
+    else
+      ERREXIT(cinfo, JERR_TGA_BADPARMS);
+    TRACEMS2(cinfo, 1, JTRC_TGA_GRAY, width, height);
+    break;
+  default:
+    ERREXIT(cinfo, JERR_TGA_BADPARMS);
+    break;
+  }
+
+  if (is_bottom_up) {
+    /* Create a virtual array to buffer the upside-down image. */
+    source->whole_image = (*cinfo->mem->request_virt_sarray)
+      ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+       (JDIMENSION) width * components, (JDIMENSION) height, (JDIMENSION) 1);
+    if (cinfo->progress != NULL) {
+      cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+      progress->total_extra_passes++; /* count file input as separate pass */
+    }
+    /* source->pub.buffer will point to the virtual array. */
+    source->pub.buffer_height = 1; /* in case anyone looks at it */
+    source->pub.get_pixel_rows = preload_image;
+  } else {
+    /* Don't need a virtual array, but do need a one-row input buffer. */
+    source->whole_image = NULL;
+    source->pub.buffer = (*cinfo->mem->alloc_sarray)
+      ((j_common_ptr) cinfo, JPOOL_IMAGE,
+       (JDIMENSION) width * components, (JDIMENSION) 1);
+    source->pub.buffer_height = 1;
+    source->pub.get_pixel_rows = source->get_pixel_rows;
+  }
+  
+  while (idlen--)		/* Throw away ID field */
+    (void) read_byte(source);
+
+  if (maplen > 0) {
+    if (maplen > 256 || GET_2B(3) != 0)
+      ERREXIT(cinfo, JERR_TGA_BADCMAP);
+    /* Allocate space to store the colormap */
+    source->colormap = (*cinfo->mem->alloc_sarray)
+      ((j_common_ptr) cinfo, JPOOL_IMAGE, (JDIMENSION) maplen, (JDIMENSION) 3);
+    /* and read it from the file */
+    read_colormap(source, (int) maplen, UCH(targaheader[7]));
+  } else {
+    if (cmaptype)		/* but you promised a cmap! */
+      ERREXIT(cinfo, JERR_TGA_BADPARMS);
+    source->colormap = NULL;
+  }
+
+  cinfo->input_components = components;
+  cinfo->data_precision = 8;
+  cinfo->image_width = width;
+  cinfo->image_height = height;
+}
+
+
+/*
+ * Finish up at the end of the file.
+ */
+
+METHODDEF(void)
+finish_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+  /* no work */
+}
+
+
+/*
+ * The module selection routine for Targa format input.
+ */
+
+GLOBAL(cjpeg_source_ptr)
+jinit_read_targa (j_compress_ptr cinfo)
+{
+  tga_source_ptr source;
+
+  /* Create module interface object */
+  source = (tga_source_ptr)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  SIZEOF(tga_source_struct));
+  source->cinfo = cinfo;	/* make back link for subroutines */
+  /* Fill in method ptrs, except get_pixel_rows which start_input sets */
+  source->pub.start_input = start_input_tga;
+  source->pub.finish_input = finish_input_tga;
+
+  return (cjpeg_source_ptr) source;
+}
+
+#endif /* TARGA_SUPPORTED */
diff --git a/source/Irrlicht/jpeglib/readme.dos b/source/Irrlicht/jpeglib/readme.dos
new file mode 100644
index 00000000..4d10d2d7
--- /dev/null
+++ b/source/Irrlicht/jpeglib/readme.dos
@@ -0,0 +1,15 @@
+This archive contains a DOS-friendly version of the Independent JPEG Group's
+source code.  It differs from the normal distribution in that:
+
+1. The archive format is zip rather than tar+gzip.  You should be able to
+unpack it with PKUNZIP (2.04g or later) or Info-Zip's unzip or 7-Zip.
+
+2. Newlines have been converted from Unix (LF) to DOS (CR/LF) style in all
+text files, but not in the binary files (test*.*).
+
+3. Object files have been included for jmemdosa.asm.  See jdosaobj.txt.
+
+Please see the main README file for the primary documentation.
+
+If you'd rather have a non-DOSified archive, see the ARCHIVE LOCATIONS section
+of README.
diff --git a/source/Irrlicht/jpeglib/structure.txt b/source/Irrlicht/jpeglib/structure.txt
new file mode 100644
index 00000000..98e20c7c
--- /dev/null
+++ b/source/Irrlicht/jpeglib/structure.txt
@@ -0,0 +1,942 @@
+IJG JPEG LIBRARY:  SYSTEM ARCHITECTURE
+
+Copyright (C) 1991-2013, Thomas G. Lane, Guido Vollbeding.
+This file is part of the Independent JPEG Group's software.
+For conditions of distribution and use, see the accompanying README file.
+
+
+This file provides an overview of the architecture of the IJG JPEG software;
+that is, the functions of the various modules in the system and the interfaces
+between modules.  For more precise details about any data structure or calling
+convention, see the include files and comments in the source code.
+
+We assume that the reader is already somewhat familiar with the JPEG standard.
+The README file includes references for learning about JPEG.  The file
+libjpeg.txt describes the library from the viewpoint of an application
+programmer using the library; it's best to read that file before this one.
+Also, the file coderules.txt describes the coding style conventions we use.
+
+In this document, JPEG-specific terminology follows the JPEG standard:
+  A "component" means a color channel, e.g., Red or Luminance.
+  A "sample" is a single component value (i.e., one number in the image data).
+  A "coefficient" is a frequency coefficient (a DCT transform output number).
+  A "block" is an array of samples or coefficients.
+  An "MCU" (minimum coded unit) is an interleaved set of blocks of size
+	determined by the sampling factors, or a single block in a
+	noninterleaved scan.
+We do not use the terms "pixel" and "sample" interchangeably.  When we say
+pixel, we mean an element of the full-size image, while a sample is an element
+of the downsampled image.  Thus the number of samples may vary across
+components while the number of pixels does not.  (This terminology is not used
+rigorously throughout the code, but it is used in places where confusion would
+otherwise result.)
+
+
+*** System features ***
+
+The IJG distribution contains two parts:
+  * A subroutine library for JPEG compression and decompression.
+  * cjpeg/djpeg, two sample applications that use the library to transform
+    JFIF JPEG files to and from several other image formats.
+cjpeg/djpeg are of no great intellectual complexity: they merely add a simple
+command-line user interface and I/O routines for several uncompressed image
+formats.  This document concentrates on the library itself.
+
+We desire the library to be capable of supporting all JPEG baseline, extended
+sequential, and progressive DCT processes.  The library does not support the
+hierarchical or lossless processes defined in the standard.
+
+Within these limits, any set of compression parameters allowed by the JPEG
+spec should be readable for decompression.  (We can be more restrictive about
+what formats we can generate.)  Although the system design allows for all
+parameter values, some uncommon settings are not yet implemented and may
+never be; nonintegral sampling ratios are the prime example.  Furthermore,
+we treat 8-bit vs. 12-bit data precision as a compile-time switch, not a
+run-time option, because most machines can store 8-bit pixels much more
+compactly than 12-bit.
+
+By itself, the library handles only interchange JPEG datastreams --- in
+particular the widely used JFIF file format.  The library can be used by
+surrounding code to process interchange or abbreviated JPEG datastreams that
+are embedded in more complex file formats.  (For example, libtiff uses this
+library to implement JPEG compression within the TIFF file format.)
+
+The library includes a substantial amount of code that is not covered by the
+JPEG standard but is necessary for typical applications of JPEG.  These
+functions preprocess the image before JPEG compression or postprocess it after
+decompression.  They include colorspace conversion, downsampling/upsampling,
+and color quantization.  This code can be omitted if not needed.
+
+A wide range of quality vs. speed tradeoffs are possible in JPEG processing,
+and even more so in decompression postprocessing.  The decompression library
+provides multiple implementations that cover most of the useful tradeoffs,
+ranging from very-high-quality down to fast-preview operation.  On the
+compression side we have generally not provided low-quality choices, since
+compression is normally less time-critical.  It should be understood that the
+low-quality modes may not meet the JPEG standard's accuracy requirements;
+nonetheless, they are useful for viewers.
+
+
+*** Portability issues ***
+
+Portability is an essential requirement for the library.  The key portability
+issues that show up at the level of system architecture are:
+
+1.  Memory usage.  We want the code to be able to run on PC-class machines
+with limited memory.  Images should therefore be processed sequentially (in
+strips), to avoid holding the whole image in memory at once.  Where a
+full-image buffer is necessary, we should be able to use either virtual memory
+or temporary files.
+
+2.  Near/far pointer distinction.  To run efficiently on 80x86 machines, the
+code should distinguish "small" objects (kept in near data space) from
+"large" ones (kept in far data space).  This is an annoying restriction, but
+fortunately it does not impact code quality for less brain-damaged machines,
+and the source code clutter turns out to be minimal with sufficient use of
+pointer typedefs.
+
+3. Data precision.  We assume that "char" is at least 8 bits, "short" and
+"int" at least 16, "long" at least 32.  The code will work fine with larger
+data sizes, although memory may be used inefficiently in some cases.  However,
+the JPEG compressed datastream must ultimately appear on external storage as a
+sequence of 8-bit bytes if it is to conform to the standard.  This may pose a
+problem on machines where char is wider than 8 bits.  The library represents
+compressed data as an array of values of typedef JOCTET.  If no data type
+exactly 8 bits wide is available, custom data source and data destination
+modules must be written to unpack and pack the chosen JOCTET datatype into
+8-bit external representation.
+
+
+*** System overview ***
+
+The compressor and decompressor are each divided into two main sections:
+the JPEG compressor or decompressor proper, and the preprocessing or
+postprocessing functions.  The interface between these two sections is the
+image data that the official JPEG spec regards as its input or output: this
+data is in the colorspace to be used for compression, and it is downsampled
+to the sampling factors to be used.  The preprocessing and postprocessing
+steps are responsible for converting a normal image representation to or from
+this form.  (Those few applications that want to deal with YCbCr downsampled
+data can skip the preprocessing or postprocessing step.)
+
+Looking more closely, the compressor library contains the following main
+elements:
+
+  Preprocessing:
+    * Color space conversion (e.g., RGB to YCbCr).
+    * Edge expansion and downsampling.  Optionally, this step can do simple
+      smoothing --- this is often helpful for low-quality source data.
+  JPEG proper:
+    * MCU assembly, DCT, quantization.
+    * Entropy coding (sequential or progressive, Huffman or arithmetic).
+
+In addition to these modules we need overall control, marker generation,
+and support code (memory management & error handling).  There is also a
+module responsible for physically writing the output data --- typically
+this is just an interface to fwrite(), but some applications may need to
+do something else with the data.
+
+The decompressor library contains the following main elements:
+
+  JPEG proper:
+    * Entropy decoding (sequential or progressive, Huffman or arithmetic).
+    * Dequantization, inverse DCT, MCU disassembly.
+  Postprocessing:
+    * Upsampling.  Optionally, this step may be able to do more general
+      rescaling of the image.
+    * Color space conversion (e.g., YCbCr to RGB).  This step may also
+      provide gamma adjustment [ currently it does not ].
+    * Optional color quantization (e.g., reduction to 256 colors).
+    * Optional color precision reduction (e.g., 24-bit to 15-bit color).
+      [This feature is not currently implemented.]
+
+We also need overall control, marker parsing, and a data source module.
+The support code (memory management & error handling) can be shared with
+the compression half of the library.
+
+There may be several implementations of each of these elements, particularly
+in the decompressor, where a wide range of speed/quality tradeoffs is very
+useful.  It must be understood that some of the best speedups involve
+merging adjacent steps in the pipeline.  For example, upsampling, color space
+conversion, and color quantization might all be done at once when using a
+low-quality ordered-dither technique.  The system architecture is designed to
+allow such merging where appropriate.
+
+
+Note: it is convenient to regard edge expansion (padding to block boundaries)
+as a preprocessing/postprocessing function, even though the JPEG spec includes
+it in compression/decompression.  We do this because downsampling/upsampling
+can be simplified a little if they work on padded data: it's not necessary to
+have special cases at the right and bottom edges.  Therefore the interface
+buffer is always an integral number of blocks wide and high, and we expect
+compression preprocessing to pad the source data properly.  Padding will occur
+only to the next block (block_size-sample) boundary.  In an interleaved-scan
+situation, additional dummy blocks may be used to fill out MCUs, but the MCU
+assembly and disassembly logic will create or discard these blocks internally.
+(This is advantageous for speed reasons, since we avoid DCTing the dummy
+blocks.  It also permits a small reduction in file size, because the
+compressor can choose dummy block contents so as to minimize their size
+in compressed form.  Finally, it makes the interface buffer specification
+independent of whether the file is actually interleaved or not.)
+Applications that wish to deal directly with the downsampled data must
+provide similar buffering and padding for odd-sized images.
+
+
+*** Poor man's object-oriented programming ***
+
+It should be clear by now that we have a lot of quasi-independent processing
+steps, many of which have several possible behaviors.  To avoid cluttering the
+code with lots of switch statements, we use a simple form of object-style
+programming to separate out the different possibilities.
+
+For example, two different color quantization algorithms could be implemented
+as two separate modules that present the same external interface; at runtime,
+the calling code will access the proper module indirectly through an "object".
+
+We can get the limited features we need while staying within portable C.
+The basic tool is a function pointer.  An "object" is just a struct
+containing one or more function pointer fields, each of which corresponds to
+a method name in real object-oriented languages.  During initialization we
+fill in the function pointers with references to whichever module we have
+determined we need to use in this run.  Then invocation of the module is done
+by indirecting through a function pointer; on most machines this is no more
+expensive than a switch statement, which would be the only other way of
+making the required run-time choice.  The really significant benefit, of
+course, is keeping the source code clean and well structured.
+
+We can also arrange to have private storage that varies between different
+implementations of the same kind of object.  We do this by making all the
+module-specific object structs be separately allocated entities, which will
+be accessed via pointers in the master compression or decompression struct.
+The "public" fields or methods for a given kind of object are specified by
+a commonly known struct.  But a module's initialization code can allocate
+a larger struct that contains the common struct as its first member, plus
+additional private fields.  With appropriate pointer casting, the module's
+internal functions can access these private fields.  (For a simple example,
+see jdatadst.c, which implements the external interface specified by struct
+jpeg_destination_mgr, but adds extra fields.)
+
+(Of course this would all be a lot easier if we were using C++, but we are
+not yet prepared to assume that everyone has a C++ compiler.)
+
+An important benefit of this scheme is that it is easy to provide multiple
+versions of any method, each tuned to a particular case.  While a lot of
+precalculation might be done to select an optimal implementation of a method,
+the cost per invocation is constant.  For example, the upsampling step might
+have a "generic" method, plus one or more "hardwired" methods for the most
+popular sampling factors; the hardwired methods would be faster because they'd
+use straight-line code instead of for-loops.  The cost to determine which
+method to use is paid only once, at startup, and the selection criteria are
+hidden from the callers of the method.
+
+This plan differs a little bit from usual object-oriented structures, in that
+only one instance of each object class will exist during execution.  The
+reason for having the class structure is that on different runs we may create
+different instances (choose to execute different modules).  You can think of
+the term "method" as denoting the common interface presented by a particular
+set of interchangeable functions, and "object" as denoting a group of related
+methods, or the total shared interface behavior of a group of modules.
+
+
+*** Overall control structure ***
+
+We previously mentioned the need for overall control logic in the compression
+and decompression libraries.  In IJG implementations prior to v5, overall
+control was mostly provided by "pipeline control" modules, which proved to be
+large, unwieldy, and hard to understand.  To improve the situation, the
+control logic has been subdivided into multiple modules.  The control modules
+consist of:
+
+1. Master control for module selection and initialization.  This has two
+responsibilities:
+
+   1A.  Startup initialization at the beginning of image processing.
+        The individual processing modules to be used in this run are selected
+        and given initialization calls.
+
+   1B.  Per-pass control.  This determines how many passes will be performed
+        and calls each active processing module to configure itself
+        appropriately at the beginning of each pass.  End-of-pass processing,
+	where necessary, is also invoked from the master control module.
+
+   Method selection is partially distributed, in that a particular processing
+   module may contain several possible implementations of a particular method,
+   which it will select among when given its initialization call.  The master
+   control code need only be concerned with decisions that affect more than
+   one module.
+ 
+2. Data buffering control.  A separate control module exists for each
+   inter-processing-step data buffer.  This module is responsible for
+   invoking the processing steps that write or read that data buffer.
+
+Each buffer controller sees the world as follows:
+
+input data => processing step A => buffer => processing step B => output data
+                      |              |               |
+              ------------------ controller ------------------
+
+The controller knows the dataflow requirements of steps A and B: how much data
+they want to accept in one chunk and how much they output in one chunk.  Its
+function is to manage its buffer and call A and B at the proper times.
+
+A data buffer control module may itself be viewed as a processing step by a
+higher-level control module; thus the control modules form a binary tree with
+elementary processing steps at the leaves of the tree.
+
+The control modules are objects.  A considerable amount of flexibility can
+be had by replacing implementations of a control module.  For example:
+* Merging of adjacent steps in the pipeline is done by replacing a control
+  module and its pair of processing-step modules with a single processing-
+  step module.  (Hence the possible merges are determined by the tree of
+  control modules.)
+* In some processing modes, a given interstep buffer need only be a "strip"
+  buffer large enough to accommodate the desired data chunk sizes.  In other
+  modes, a full-image buffer is needed and several passes are required.
+  The control module determines which kind of buffer is used and manipulates
+  virtual array buffers as needed.  One or both processing steps may be
+  unaware of the multi-pass behavior.
+
+In theory, we might be able to make all of the data buffer controllers
+interchangeable and provide just one set of implementations for all.  In
+practice, each one contains considerable special-case processing for its
+particular job.  The buffer controller concept should be regarded as an
+overall system structuring principle, not as a complete description of the
+task performed by any one controller.
+
+
+*** Compression object structure ***
+
+Here is a sketch of the logical structure of the JPEG compression library:
+
+                                                 |-- Colorspace conversion
+                  |-- Preprocessing controller --|
+                  |                              |-- Downsampling
+Main controller --|
+                  |                            |-- Forward DCT, quantize
+                  |-- Coefficient controller --|
+                                               |-- Entropy encoding
+
+This sketch also describes the flow of control (subroutine calls) during
+typical image data processing.  Each of the components shown in the diagram is
+an "object" which may have several different implementations available.  One
+or more source code files contain the actual implementation(s) of each object.
+
+The objects shown above are:
+
+* Main controller: buffer controller for the subsampled-data buffer, which
+  holds the preprocessed input data.  This controller invokes preprocessing to
+  fill the subsampled-data buffer, and JPEG compression to empty it.  There is
+  usually no need for a full-image buffer here; a strip buffer is adequate.
+
+* Preprocessing controller: buffer controller for the downsampling input data
+  buffer, which lies between colorspace conversion and downsampling.  Note
+  that a unified conversion/downsampling module would probably replace this
+  controller entirely.
+
+* Colorspace conversion: converts application image data into the desired
+  JPEG color space; also changes the data from pixel-interleaved layout to
+  separate component planes.  Processes one pixel row at a time.
+
+* Downsampling: performs reduction of chroma components as required.
+  Optionally may perform pixel-level smoothing as well.  Processes a "row
+  group" at a time, where a row group is defined as Vmax pixel rows of each
+  component before downsampling, and Vk sample rows afterwards (remember Vk
+  differs across components).  Some downsampling or smoothing algorithms may
+  require context rows above and below the current row group; the
+  preprocessing controller is responsible for supplying these rows via proper
+  buffering.  The downsampler is responsible for edge expansion at the right
+  edge (i.e., extending each sample row to a multiple of block_size samples);
+  but the preprocessing controller is responsible for vertical edge expansion
+  (i.e., duplicating the bottom sample row as needed to make a multiple of
+  block_size rows).
+
+* Coefficient controller: buffer controller for the DCT-coefficient data.
+  This controller handles MCU assembly, including insertion of dummy DCT
+  blocks when needed at the right or bottom edge.  When performing
+  Huffman-code optimization or emitting a multiscan JPEG file, this
+  controller is responsible for buffering the full image.  The equivalent of
+  one fully interleaved MCU row of subsampled data is processed per call,
+  even when the JPEG file is noninterleaved.
+
+* Forward DCT and quantization: Perform DCT, quantize, and emit coefficients.
+  Works on one or more DCT blocks at a time.  (Note: the coefficients are now
+  emitted in normal array order, which the entropy encoder is expected to
+  convert to zigzag order as necessary.  Prior versions of the IJG code did
+  the conversion to zigzag order within the quantization step.)
+
+* Entropy encoding: Perform Huffman or arithmetic entropy coding and emit the
+  coded data to the data destination module.  Works on one MCU per call.
+  For progressive JPEG, the same DCT blocks are fed to the entropy coder
+  during each pass, and the coder must emit the appropriate subset of
+  coefficients.
+
+In addition to the above objects, the compression library includes these
+objects:
+
+* Master control: determines the number of passes required, controls overall
+  and per-pass initialization of the other modules.
+
+* Marker writing: generates JPEG markers (except for RSTn, which is emitted
+  by the entropy encoder when needed).
+
+* Data destination manager: writes the output JPEG datastream to its final
+  destination (e.g., a file).  The destination manager supplied with the
+  library knows how to write to a stdio stream or to a memory buffer;
+  for other behaviors, the surrounding application may provide its own
+  destination manager.
+
+* Memory manager: allocates and releases memory, controls virtual arrays
+  (with backing store management, where required).
+
+* Error handler: performs formatting and output of error and trace messages;
+  determines handling of nonfatal errors.  The surrounding application may
+  override some or all of this object's methods to change error handling.
+
+* Progress monitor: supports output of "percent-done" progress reports.
+  This object represents an optional callback to the surrounding application:
+  if wanted, it must be supplied by the application.
+
+The error handler, destination manager, and progress monitor objects are
+defined as separate objects in order to simplify application-specific
+customization of the JPEG library.  A surrounding application may override
+individual methods or supply its own all-new implementation of one of these
+objects.  The object interfaces for these objects are therefore treated as
+part of the application interface of the library, whereas the other objects
+are internal to the library.
+
+The error handler and memory manager are shared by JPEG compression and
+decompression; the progress monitor, if used, may be shared as well.
+
+
+*** Decompression object structure ***
+
+Here is a sketch of the logical structure of the JPEG decompression library:
+
+                                               |-- Entropy decoding
+                  |-- Coefficient controller --|
+                  |                            |-- Dequantize, Inverse DCT
+Main controller --|
+                  |                               |-- Upsampling
+                  |-- Postprocessing controller --|   |-- Colorspace conversion
+                                                  |-- Color quantization
+                                                  |-- Color precision reduction
+
+As before, this diagram also represents typical control flow.  The objects
+shown are:
+
+* Main controller: buffer controller for the subsampled-data buffer, which
+  holds the output of JPEG decompression proper.  This controller's primary
+  task is to feed the postprocessing procedure.  Some upsampling algorithms
+  may require context rows above and below the current row group; when this
+  is true, the main controller is responsible for managing its buffer so as
+  to make context rows available.  In the current design, the main buffer is
+  always a strip buffer; a full-image buffer is never required.
+
+* Coefficient controller: buffer controller for the DCT-coefficient data.
+  This controller handles MCU disassembly, including deletion of any dummy
+  DCT blocks at the right or bottom edge.  When reading a multiscan JPEG
+  file, this controller is responsible for buffering the full image.
+  (Buffering DCT coefficients, rather than samples, is necessary to support
+  progressive JPEG.)  The equivalent of one fully interleaved MCU row of
+  subsampled data is processed per call, even when the source JPEG file is
+  noninterleaved.
+
+* Entropy decoding: Read coded data from the data source module and perform
+  Huffman or arithmetic entropy decoding.  Works on one MCU per call.
+  For progressive JPEG decoding, the coefficient controller supplies the prior
+  coefficients of each MCU (initially all zeroes), which the entropy decoder
+  modifies in each scan.
+
+* Dequantization and inverse DCT: like it says.  Note that the coefficients
+  buffered by the coefficient controller have NOT been dequantized; we
+  merge dequantization and inverse DCT into a single step for speed reasons.
+  When scaled-down output is asked for, simplified DCT algorithms may be used
+  that need fewer coefficients and emit fewer samples per DCT block, not the
+  full 8x8.  Works on one DCT block at a time.
+
+* Postprocessing controller: buffer controller for the color quantization
+  input buffer, when quantization is in use.  (Without quantization, this
+  controller just calls the upsampler.)  For two-pass quantization, this
+  controller is responsible for buffering the full-image data.
+
+* Upsampling: restores chroma components to full size.  (May support more
+  general output rescaling, too.  Note that if undersized DCT outputs have
+  been emitted by the DCT module, this module must adjust so that properly
+  sized outputs are created.)  Works on one row group at a time.  This module
+  also calls the color conversion module, so its top level is effectively a
+  buffer controller for the upsampling->color conversion buffer.  However, in
+  all but the highest-quality operating modes, upsampling and color
+  conversion are likely to be merged into a single step.
+
+* Colorspace conversion: convert from JPEG color space to output color space,
+  and change data layout from separate component planes to pixel-interleaved.
+  Works on one pixel row at a time.
+
+* Color quantization: reduce the data to colormapped form, using either an
+  externally specified colormap or an internally generated one.  This module
+  is not used for full-color output.  Works on one pixel row at a time; may
+  require two passes to generate a color map.  Note that the output will
+  always be a single component representing colormap indexes.  In the current
+  design, the output values are JSAMPLEs, so an 8-bit compilation cannot
+  quantize to more than 256 colors.  This is unlikely to be a problem in
+  practice.
+
+* Color reduction: this module handles color precision reduction, e.g.,
+  generating 15-bit color (5 bits/primary) from JPEG's 24-bit output.
+  Not quite clear yet how this should be handled... should we merge it with
+  colorspace conversion???
+
+Note that some high-speed operating modes might condense the entire
+postprocessing sequence to a single module (upsample, color convert, and
+quantize in one step).
+
+In addition to the above objects, the decompression library includes these
+objects:
+
+* Master control: determines the number of passes required, controls overall
+  and per-pass initialization of the other modules.  This is subdivided into
+  input and output control: jdinput.c controls only input-side processing,
+  while jdmaster.c handles overall initialization and output-side control.
+
+* Marker reading: decodes JPEG markers (except for RSTn).
+
+* Data source manager: supplies the input JPEG datastream.  The source
+  manager supplied with the library knows how to read from a stdio stream
+  or from a memory buffer;  for other behaviors, the surrounding application
+  may provide its own source manager.
+
+* Memory manager: same as for compression library.
+
+* Error handler: same as for compression library.
+
+* Progress monitor: same as for compression library.
+
+As with compression, the data source manager, error handler, and progress
+monitor are candidates for replacement by a surrounding application.
+
+
+*** Decompression input and output separation ***
+
+To support efficient incremental display of progressive JPEG files, the
+decompressor is divided into two sections that can run independently:
+
+1. Data input includes marker parsing, entropy decoding, and input into the
+   coefficient controller's DCT coefficient buffer.  Note that this
+   processing is relatively cheap and fast.
+
+2. Data output reads from the DCT coefficient buffer and performs the IDCT
+   and all postprocessing steps.
+
+For a progressive JPEG file, the data input processing is allowed to get
+arbitrarily far ahead of the data output processing.  (This occurs only
+if the application calls jpeg_consume_input(); otherwise input and output
+run in lockstep, since the input section is called only when the output
+section needs more data.)  In this way the application can avoid making
+extra display passes when data is arriving faster than the display pass
+can run.  Furthermore, it is possible to abort an output pass without
+losing anything, since the coefficient buffer is read-only as far as the
+output section is concerned.  See libjpeg.txt for more detail.
+
+A full-image coefficient array is only created if the JPEG file has multiple
+scans (or if the application specifies buffered-image mode anyway).  When
+reading a single-scan file, the coefficient controller normally creates only
+a one-MCU buffer, so input and output processing must run in lockstep in this
+case.  jpeg_consume_input() is effectively a no-op in this situation.
+
+The main impact of dividing the decompressor in this fashion is that we must
+be very careful with shared variables in the cinfo data structure.  Each
+variable that can change during the course of decompression must be
+classified as belonging to data input or data output, and each section must
+look only at its own variables.  For example, the data output section may not
+depend on any of the variables that describe the current scan in the JPEG
+file, because these may change as the data input section advances into a new
+scan.
+
+The progress monitor is (somewhat arbitrarily) defined to treat input of the
+file as one pass when buffered-image mode is not used, and to ignore data
+input work completely when buffered-image mode is used.  Note that the
+library has no reliable way to predict the number of passes when dealing
+with a progressive JPEG file, nor can it predict the number of output passes
+in buffered-image mode.  So the work estimate is inherently bogus anyway.
+
+No comparable division is currently made in the compression library, because
+there isn't any real need for it.
+
+
+*** Data formats ***
+
+Arrays of pixel sample values use the following data structure:
+
+    typedef something JSAMPLE;		a pixel component value, 0..MAXJSAMPLE
+    typedef JSAMPLE *JSAMPROW;		ptr to a row of samples
+    typedef JSAMPROW *JSAMPARRAY;	ptr to a list of rows
+    typedef JSAMPARRAY *JSAMPIMAGE;	ptr to a list of color-component arrays
+
+The basic element type JSAMPLE will typically be one of unsigned char,
+(signed) char, or short.  Short will be used if samples wider than 8 bits are
+to be supported (this is a compile-time option).  Otherwise, unsigned char is
+used if possible.  If the compiler only supports signed chars, then it is
+necessary to mask off the value when reading.  Thus, all reads of JSAMPLE
+values must be coded as "GETJSAMPLE(value)", where the macro will be defined
+as "((value) & 0xFF)" on signed-char machines and "((int) (value))" elsewhere.
+
+With these conventions, JSAMPLE values can be assumed to be >= 0.  This helps
+simplify correct rounding during downsampling, etc.  The JPEG standard's
+specification that sample values run from -128..127 is accommodated by
+subtracting 128 from the sample value in the DCT step.  Similarly, during
+decompression the output of the IDCT step will be immediately shifted back to
+0..255.  (NB: different values are required when 12-bit samples are in use.
+The code is written in terms of MAXJSAMPLE and CENTERJSAMPLE, which will be
+defined as 255 and 128 respectively in an 8-bit implementation, and as 4095
+and 2048 in a 12-bit implementation.)
+
+We use a pointer per row, rather than a two-dimensional JSAMPLE array.  This
+choice costs only a small amount of memory and has several benefits:
+* Code using the data structure doesn't need to know the allocated width of
+  the rows.  This simplifies edge expansion/compression, since we can work
+  in an array that's wider than the logical picture width.
+* Indexing doesn't require multiplication; this is a performance win on many
+  machines.
+* Arrays with more than 64K total elements can be supported even on machines
+  where malloc() cannot allocate chunks larger than 64K.
+* The rows forming a component array may be allocated at different times
+  without extra copying.  This trick allows some speedups in smoothing steps
+  that need access to the previous and next rows.
+
+Note that each color component is stored in a separate array; we don't use the
+traditional layout in which the components of a pixel are stored together.
+This simplifies coding of modules that work on each component independently,
+because they don't need to know how many components there are.  Furthermore,
+we can read or write each component to a temporary file independently, which
+is helpful when dealing with noninterleaved JPEG files.
+
+In general, a specific sample value is accessed by code such as
+	GETJSAMPLE(image[colorcomponent][row][col])
+where col is measured from the image left edge, but row is measured from the
+first sample row currently in memory.  Either of the first two indexings can
+be precomputed by copying the relevant pointer.
+
+
+Since most image-processing applications prefer to work on images in which
+the components of a pixel are stored together, the data passed to or from the
+surrounding application uses the traditional convention: a single pixel is
+represented by N consecutive JSAMPLE values, and an image row is an array of
+(# of color components)*(image width) JSAMPLEs.  One or more rows of data can
+be represented by a pointer of type JSAMPARRAY in this scheme.  This scheme is
+converted to component-wise storage inside the JPEG library.  (Applications
+that want to skip JPEG preprocessing or postprocessing will have to contend
+with component-wise storage.)
+
+
+Arrays of DCT-coefficient values use the following data structure:
+
+    typedef short JCOEF;		a 16-bit signed integer
+    typedef JCOEF JBLOCK[DCTSIZE2];	an 8x8 block of coefficients
+    typedef JBLOCK *JBLOCKROW;		ptr to one horizontal row of 8x8 blocks
+    typedef JBLOCKROW *JBLOCKARRAY;	ptr to a list of such rows
+    typedef JBLOCKARRAY *JBLOCKIMAGE;	ptr to a list of color component arrays
+
+The underlying type is at least a 16-bit signed integer; while "short" is big
+enough on all machines of interest, on some machines it is preferable to use
+"int" for speed reasons, despite the storage cost.  Coefficients are grouped
+into 8x8 blocks (but we always use #defines DCTSIZE and DCTSIZE2 rather than
+"8" and "64").
+
+The contents of a coefficient block may be in either "natural" or zigzagged
+order, and may be true values or divided by the quantization coefficients,
+depending on where the block is in the processing pipeline.  In the current
+library, coefficient blocks are kept in natural order everywhere; the entropy
+codecs zigzag or dezigzag the data as it is written or read.  The blocks
+contain quantized coefficients everywhere outside the DCT/IDCT subsystems.
+(This latter decision may need to be revisited to support variable
+quantization a la JPEG Part 3.)
+
+Notice that the allocation unit is now a row of 8x8 coefficient blocks,
+corresponding to block_size rows of samples.  Otherwise the structure
+is much the same as for samples, and for the same reasons.
+
+On machines where malloc() can't handle a request bigger than 64Kb, this data
+structure limits us to rows of less than 512 JBLOCKs, or a picture width of
+4000+ pixels.  This seems an acceptable restriction.
+
+
+On 80x86 machines, the bottom-level pointer types (JSAMPROW and JBLOCKROW)
+must be declared as "far" pointers, but the upper levels can be "near"
+(implying that the pointer lists are allocated in the DS segment).
+We use a #define symbol FAR, which expands to the "far" keyword when
+compiling on 80x86 machines and to nothing elsewhere.
+
+
+*** Suspendable processing ***
+
+In some applications it is desirable to use the JPEG library as an
+incremental, memory-to-memory filter.  In this situation the data source or
+destination may be a limited-size buffer, and we can't rely on being able to
+empty or refill the buffer at arbitrary times.  Instead the application would
+like to have control return from the library at buffer overflow/underrun, and
+then resume compression or decompression at a later time.
+
+This scenario is supported for simple cases.  (For anything more complex, we
+recommend that the application "bite the bullet" and develop real multitasking
+capability.)  The libjpeg.txt file goes into more detail about the usage and
+limitations of this capability; here we address the implications for library
+structure.
+
+The essence of the problem is that the entropy codec (coder or decoder) must
+be prepared to stop at arbitrary times.  In turn, the controllers that call
+the entropy codec must be able to stop before having produced or consumed all
+the data that they normally would handle in one call.  That part is reasonably
+straightforward: we make the controller call interfaces include "progress
+counters" which indicate the number of data chunks successfully processed, and
+we require callers to test the counter rather than just assume all of the data
+was processed.
+
+Rather than trying to restart at an arbitrary point, the current Huffman
+codecs are designed to restart at the beginning of the current MCU after a
+suspension due to buffer overflow/underrun.  At the start of each call, the
+codec's internal state is loaded from permanent storage (in the JPEG object
+structures) into local variables.  On successful completion of the MCU, the
+permanent state is updated.  (This copying is not very expensive, and may even
+lead to *improved* performance if the local variables can be registerized.)
+If a suspension occurs, the codec simply returns without updating the state,
+thus effectively reverting to the start of the MCU.  Note that this implies
+leaving some data unprocessed in the source/destination buffer (ie, the
+compressed partial MCU).  The data source/destination module interfaces are
+specified so as to make this possible.  This also implies that the data buffer
+must be large enough to hold a worst-case compressed MCU; a couple thousand
+bytes should be enough.
+
+In a successive-approximation AC refinement scan, the progressive Huffman
+decoder has to be able to undo assignments of newly nonzero coefficients if it
+suspends before the MCU is complete, since decoding requires distinguishing
+previously-zero and previously-nonzero coefficients.  This is a bit tedious
+but probably won't have much effect on performance.  Other variants of Huffman
+decoding need not worry about this, since they will just store the same values
+again if forced to repeat the MCU.
+
+This approach would probably not work for an arithmetic codec, since its
+modifiable state is quite large and couldn't be copied cheaply.  Instead it
+would have to suspend and resume exactly at the point of the buffer end.
+
+The JPEG marker reader is designed to cope with suspension at an arbitrary
+point.  It does so by backing up to the start of the marker parameter segment,
+so the data buffer must be big enough to hold the largest marker of interest.
+Again, a couple KB should be adequate.  (A special "skip" convention is used
+to bypass COM and APPn markers, so these can be larger than the buffer size
+without causing problems; otherwise a 64K buffer would be needed in the worst
+case.)
+
+The JPEG marker writer currently does *not* cope with suspension.
+We feel that this is not necessary; it is much easier simply to require
+the application to ensure there is enough buffer space before starting.  (An
+empty 2K buffer is more than sufficient for the header markers; and ensuring
+there are a dozen or two bytes available before calling jpeg_finish_compress()
+will suffice for the trailer.)  This would not work for writing multi-scan
+JPEG files, but we simply do not intend to support that capability with
+suspension.
+
+
+*** Memory manager services ***
+
+The JPEG library's memory manager controls allocation and deallocation of
+memory, and it manages large "virtual" data arrays on machines where the
+operating system does not provide virtual memory.  Note that the same
+memory manager serves both compression and decompression operations.
+
+In all cases, allocated objects are tied to a particular compression or
+decompression master record, and they will be released when that master
+record is destroyed.
+
+The memory manager does not provide explicit deallocation of objects.
+Instead, objects are created in "pools" of free storage, and a whole pool
+can be freed at once.  This approach helps prevent storage-leak bugs, and
+it speeds up operations whenever malloc/free are slow (as they often are).
+The pools can be regarded as lifetime identifiers for objects.  Two
+pools/lifetimes are defined:
+  * JPOOL_PERMANENT	lasts until master record is destroyed
+  * JPOOL_IMAGE		lasts until done with image (JPEG datastream)
+Permanent lifetime is used for parameters and tables that should be carried
+across from one datastream to another; this includes all application-visible
+parameters.  Image lifetime is used for everything else.  (A third lifetime,
+JPOOL_PASS = one processing pass, was originally planned.  However it was
+dropped as not being worthwhile.  The actual usage patterns are such that the
+peak memory usage would be about the same anyway; and having per-pass storage
+substantially complicates the virtual memory allocation rules --- see below.)
+
+The memory manager deals with three kinds of object:
+1. "Small" objects.  Typically these require no more than 10K-20K total.
+2. "Large" objects.  These may require tens to hundreds of K depending on
+   image size.  Semantically they behave the same as small objects, but we
+   distinguish them for two reasons:
+     * On MS-DOS machines, large objects are referenced by FAR pointers,
+       small objects by NEAR pointers.
+     * Pool allocation heuristics may differ for large and small objects.
+   Note that individual "large" objects cannot exceed the size allowed by
+   type size_t, which may be 64K or less on some machines.
+3. "Virtual" objects.  These are large 2-D arrays of JSAMPLEs or JBLOCKs
+   (typically large enough for the entire image being processed).  The
+   memory manager provides stripwise access to these arrays.  On machines
+   without virtual memory, the rest of the array may be swapped out to a
+   temporary file.
+
+(Note: JSAMPARRAY and JBLOCKARRAY data structures are a combination of large
+objects for the data proper and small objects for the row pointers.  For
+convenience and speed, the memory manager provides single routines to create
+these structures.  Similarly, virtual arrays include a small control block
+and a JSAMPARRAY or JBLOCKARRAY working buffer, all created with one call.)
+
+In the present implementation, virtual arrays are only permitted to have image
+lifespan.  (Permanent lifespan would not be reasonable, and pass lifespan is
+not very useful since a virtual array's raison d'etre is to store data for
+multiple passes through the image.)  We also expect that only "small" objects
+will be given permanent lifespan, though this restriction is not required by
+the memory manager.
+
+In a non-virtual-memory machine, some performance benefit can be gained by
+making the in-memory buffers for virtual arrays be as large as possible.
+(For small images, the buffers might fit entirely in memory, so blind
+swapping would be very wasteful.)  The memory manager will adjust the height
+of the buffers to fit within a prespecified maximum memory usage.  In order
+to do this in a reasonably optimal fashion, the manager needs to allocate all
+of the virtual arrays at once.  Therefore, there isn't a one-step allocation
+routine for virtual arrays; instead, there is a "request" routine that simply
+allocates the control block, and a "realize" routine (called just once) that
+determines space allocation and creates all of the actual buffers.  The
+realize routine must allow for space occupied by non-virtual large objects.
+(We don't bother to factor in the space needed for small objects, on the
+grounds that it isn't worth the trouble.)
+
+To support all this, we establish the following protocol for doing business
+with the memory manager:
+  1. Modules must request virtual arrays (which may have only image lifespan)
+     during the initial setup phase, i.e., in their jinit_xxx routines.
+  2. All "large" objects (including JSAMPARRAYs and JBLOCKARRAYs) must also be
+     allocated during initial setup.
+  3. realize_virt_arrays will be called at the completion of initial setup.
+     The above conventions ensure that sufficient information is available
+     for it to choose a good size for virtual array buffers.
+Small objects of any lifespan may be allocated at any time.  We expect that
+the total space used for small objects will be small enough to be negligible
+in the realize_virt_arrays computation.
+
+In a virtual-memory machine, we simply pretend that the available space is
+infinite, thus causing realize_virt_arrays to decide that it can allocate all
+the virtual arrays as full-size in-memory buffers.  The overhead of the
+virtual-array access protocol is very small when no swapping occurs.
+
+A virtual array can be specified to be "pre-zeroed"; when this flag is set,
+never-yet-written sections of the array are set to zero before being made
+available to the caller.  If this flag is not set, never-written sections
+of the array contain garbage.  (This feature exists primarily because the
+equivalent logic would otherwise be needed in jdcoefct.c for progressive
+JPEG mode; we may as well make it available for possible other uses.)
+
+The first write pass on a virtual array is required to occur in top-to-bottom
+order; read passes, as well as any write passes after the first one, may
+access the array in any order.  This restriction exists partly to simplify
+the virtual array control logic, and partly because some file systems may not
+support seeking beyond the current end-of-file in a temporary file.  The main
+implication of this restriction is that rearrangement of rows (such as
+converting top-to-bottom data order to bottom-to-top) must be handled while
+reading data out of the virtual array, not while putting it in.
+
+
+*** Memory manager internal structure ***
+
+To isolate system dependencies as much as possible, we have broken the
+memory manager into two parts.  There is a reasonably system-independent
+"front end" (jmemmgr.c) and a "back end" that contains only the code
+likely to change across systems.  All of the memory management methods
+outlined above are implemented by the front end.  The back end provides
+the following routines for use by the front end (none of these routines
+are known to the rest of the JPEG code):
+
+jpeg_mem_init, jpeg_mem_term	system-dependent initialization/shutdown
+
+jpeg_get_small, jpeg_free_small	interface to malloc and free library routines
+				(or their equivalents)
+
+jpeg_get_large, jpeg_free_large	interface to FAR malloc/free in MSDOS machines;
+				else usually the same as
+				jpeg_get_small/jpeg_free_small
+
+jpeg_mem_available		estimate available memory
+
+jpeg_open_backing_store		create a backing-store object
+
+read_backing_store,		manipulate a backing-store object
+write_backing_store,
+close_backing_store
+
+On some systems there will be more than one type of backing-store object
+(specifically, in MS-DOS a backing store file might be an area of extended
+memory as well as a disk file).  jpeg_open_backing_store is responsible for
+choosing how to implement a given object.  The read/write/close routines
+are method pointers in the structure that describes a given object; this
+lets them be different for different object types.
+
+It may be necessary to ensure that backing store objects are explicitly
+released upon abnormal program termination.  For example, MS-DOS won't free
+extended memory by itself.  To support this, we will expect the main program
+or surrounding application to arrange to call self_destruct (typically via
+jpeg_destroy) upon abnormal termination.  This may require a SIGINT signal
+handler or equivalent.  We don't want to have the back end module install its
+own signal handler, because that would pre-empt the surrounding application's
+ability to control signal handling.
+
+The IJG distribution includes several memory manager back end implementations.
+Usually the same back end should be suitable for all applications on a given
+system, but it is possible for an application to supply its own back end at
+need.
+
+
+*** Implications of DNL marker ***
+
+Some JPEG files may use a DNL marker to postpone definition of the image
+height (this would be useful for a fax-like scanner's output, for instance).
+In these files the SOF marker claims the image height is 0, and you only
+find out the true image height at the end of the first scan.
+
+We could read these files as follows:
+1. Upon seeing zero image height, replace it by 65535 (the maximum allowed).
+2. When the DNL is found, update the image height in the global image
+   descriptor.
+This implies that control modules must avoid making copies of the image
+height, and must re-test for termination after each MCU row.  This would
+be easy enough to do.
+
+In cases where image-size data structures are allocated, this approach will
+result in very inefficient use of virtual memory or much-larger-than-necessary
+temporary files.  This seems acceptable for something that probably won't be a
+mainstream usage.  People might have to forgo use of memory-hogging options
+(such as two-pass color quantization or noninterleaved JPEG files) if they
+want efficient conversion of such files.  (One could improve efficiency by
+demanding a user-supplied upper bound for the height, less than 65536; in most
+cases it could be much less.)
+
+The standard also permits the SOF marker to overestimate the image height,
+with a DNL to give the true, smaller height at the end of the first scan.
+This would solve the space problems if the overestimate wasn't too great.
+However, it implies that you don't even know whether DNL will be used.
+
+This leads to a couple of very serious objections:
+1. Testing for a DNL marker must occur in the inner loop of the decompressor's
+   Huffman decoder; this implies a speed penalty whether the feature is used
+   or not.
+2. There is no way to hide the last-minute change in image height from an
+   application using the decoder.  Thus *every* application using the IJG
+   library would suffer a complexity penalty whether it cared about DNL or
+   not.
+We currently do not support DNL because of these problems.
+
+A different approach is to insist that DNL-using files be preprocessed by a
+separate program that reads ahead to the DNL, then goes back and fixes the SOF
+marker.  This is a much simpler solution and is probably far more efficient.
+Even if one wants piped input, buffering the first scan of the JPEG file needs
+a lot smaller temp file than is implied by the maximum-height method.  For
+this approach we'd simply treat DNL as a no-op in the decompressor (at most,
+check that it matches the SOF image height).
+
+We will not worry about making the compressor capable of outputting DNL.
+Something similar to the first scheme above could be applied if anyone ever
+wants to make that work.
diff --git a/source/Irrlicht/jpeglib/testimg.bmp b/source/Irrlicht/jpeglib/testimg.bmp
new file mode 100644
index 00000000..11aa0cbf
Binary files /dev/null and b/source/Irrlicht/jpeglib/testimg.bmp differ
diff --git a/source/Irrlicht/jpeglib/testimg.jpg b/source/Irrlicht/jpeglib/testimg.jpg
new file mode 100644
index 00000000..a026e486
Binary files /dev/null and b/source/Irrlicht/jpeglib/testimg.jpg differ
diff --git a/source/Irrlicht/jpeglib/testimg.ppm b/source/Irrlicht/jpeglib/testimg.ppm
new file mode 100644
index 00000000..1377eef2
--- /dev/null
+++ b/source/Irrlicht/jpeglib/testimg.ppm
@@ -0,0 +1,4 @@
+P6
+227 149
+255
+0/-0/-10.21/51.51.62/72.83/83/83/:3-:3-:3-:3-:3-:2/91.91.80-80-91.91.:2/80-80-80-80-80-80-80-80-6.+6.+6.+5-*5-*4,)4,)4,)4,)4,)4,)4,)4,)4,)4,)4,).+$/,%/,%0-&1.'2/(30)30)63,63,74-85.85.96/:70:70A;/B<0D>2F@2IA4JB5KC6KD4MD5MD5MD3NB2OC3OC3PD4QE5T>1Y?2b@4nB5}E6G8G9E7F9F9E8F;F>F?G@G@CNCLCLDKDIBF>B@?@?<=;@.@.@.?-?-@-?-?-@,A.A-B,A*A)@*A*?/?/?/>,>,<+<+<+?+?+=*=*=*>+?+@,?:>7=4?1B3D3D3D4?/@2E8H;H9mB2T8*D3#:659549547326216005//50-72/72/72/61-61-50,50,50,.0-.0-.0-//-//-0/-2.-3--5,-4+,4*+4(*7(+=.1E69LUPdUPdUPd0/-0/-10.10.40-51.62/72.83/83/83/:3-:3-:3-:3-:3-91.91.80-80-80-80-91.91.80-80-80-80-80-80-80-80-6.+6.+5-*5-*5-*4,)4,)4,)5-*5-*5-*5-*5-*5-*5-*5-*/,%0-&0-&1.'2/(30)41*41*63,63,74-74-85.96/:70:70@:.A;/C=1E?3H@3IA4JB5JC3LC4LC4KB3MA1MA1NB2OC3PD4P>0U?1^A3jC4xD6D4D5B3B3@2@4B7C:EAKAICIDHDGBD@D>C;A9@9?.>.>,=+<+<+>->*>*=*=*>+?,@-@8>5>3?1A3D4D3C4A2B6E8I;G:kA3S9*D4$<66;55:4493382271161.61.72/72/72/61-61-50,50,50,.0-.0-.0-//-//-0/-2.-2.-3--5,-4*+4(*5)+<-0C47I:=h<;vDCJILJST`hk{r{|ylv[\QHsQBkOFaOFaNI_RN_[Yfnot~ojk[]\JVUCXQaXQaXQa/.,/.,0/-10.40-40-51.51.72.72.72.92,92,92,92,92,91.80-7/,7/,7/,7/,80-91.80-80-80-80-80-80-80-80-6.+5-*5-*5-*4,)4,)4,)4,)5-*5-*5-*5-*5-*5-*5-*5-*1.'1.'2/(30)30)41*41*52+63,63,63,74-85.96/96/:70?9-@:.B<0D>2G?4H@3H@3H@3I@1I@1I@1K?1K?/L@0MA1NB2MA1QA2YB2dC2qC3|C2A2@0<+:+;,>0@4C8F=G>?E@FBGCFDFCEAD?D;@:?:@=@@@A=@;>7@-@-@-?,?,?->,?,?-@-@,A+A,@*A*@)?/>.>.>.=+=+=+<+=,=,<+=)>*>*?+@,B7?5>3>2A4C5D5C4D6F9I=I=F;gA4P:,B6&=77=77<66:4493383072/72/62/62/62/52-52-41,41,41,,1-,1-.0-.0-//-//-0/-2.-5//4..5,-4*+4*+9-/>24C79_83l?:|E@IBNKZ^ftnw~zsdmUUNEtO?lMBbPEcQHcMH^NK\[[estx|xzlghXZ[KVTEZT`ZT`ZT`.-+/.,/.,0/-10.40-40-40-51.61-61-61-81+81+81+81+50-50-4/,4/,4/,4/,50-50-61.61.61.61.61.61.61.61.3.+3.+3.+2-*2-*2-*1,)1,)4/,4/,4/,4/,4/,4/,4/,4/,30+30+30+41,41,52-52-52-52-52-63.74/850850961961>8,?9-@:.B<0E=2E=2F>1F>1G=1G>/F=.I=/I=/J>0L@0L@0JD4NE4TD4^D3hE2sB1~A/>-9'9'9)<-@3E8I@CACCEDECDAC@C>A;@:?:>=@A?B=A7>5@,@,@,?->,>,?,>-?-?,@-@,@+@*@)@(>.>.>.=-=-=-<*<*=+=+<*<*=+=,>->-B6?5?2@2B4C6B5B5F:H>K@J@|F:aA4K;.?9+@86@86?75>64:5294183073062/62/62/32.32-21,21,21,-2.-2.-2./1./1.00.00.10.5106005//5,-4+,6,-:01>45W6-b<3qA7}D9H@RQ_iis|zu~my^gRQMDyM?rN@dPEgQFfLC^GBVNLZ^^fjnquzvx}vzvwzokoa`bUWYKTUG]V^]V^]V^.-+.-+.-+/.,0/-10.3/,40-3/,4/+4/+4/+4/+6/)6/)6/)4/,4/,3.+3.+3.+3.+4/,4/,50-50-50-50-50-50-50-50-3.+3.+2-*2-*2-*1,)1,)1,)4/,4/,4/,4/,4/,4/,4/,4/,41,41,41,41,41,52-52-52-52-52-63.63.74/850961961<5+=6,?8.@9/B:/C;0C;0C;.D:.D:.D:.G;-H<.I=/J>0K?1GH6KH7PG6XG5aF3jD1uB/|?,;):';(=,B2G7KDBDCDBEBC@@@>>:>:=9<;>?>B>C:A5?0@-?,?,?,>+>+>-?-?,?-?,?+?*?+?*>)?.?.>->->-=,=,=,=,=,=,=,<,=->.>.B4A4@1@3B5C7A8@7B;G?KCJ@uE;Y>3C9-78*@86@86?75>64=53:5294173062/43/43/32.23.12-12,12,,2.-2.-2.-2./1./1.00.00.3205105104..2,,4+,7./901P5*Y9,e>/n@1tB7|KGYcg~pxxs{js]eTTOGLAyPAjPAhMAeJA`GBYHEXKKWMPU^bc`fbcha`f\Z`TWZOUYKWYL`WZ`WZ`WZ,,,,,,---.-+/.,0/-10.3/,2.+2.+3.*3.*3.*3.*3.*3.*3.+3.+2-*1,)1,)2-*3.+3.+3.+3.+3.+3.+3.+3.+3.+3.+2-*2-*2-*2-*1,)1,)1,)0+(3.+3.+3.+3.+3.+3.+3.+3.+41,41,41,41,41,41,41,41,41,52-52-63.74/850850850;4*<5+=6,>7-@7.A8/A9.A9.C9/C9-C9-F:.G;/H<.J>0K?1FI8GH6MH5TG6[F3dC0lA.t?-{<*;);*=,A1F5J:M=E@FAFAE@C?@>==9<:<9;;=?=B=D8A2>,@,@,?+>->->,>,>.>-?,?,>,?+>*>)?)>->->->-=,=,=,<+=,<+<+<+<+=.>/?0C2A2@2A5B9C:@:@9@9H@NGNEoG=R@4?;039-A75A75@64>63<4194083/74/63.43.34/23.13.02-02-02--3/-3/-3/.3/.3/02/02/11/11/32032040/2.-1-,4..5//H4)M5)X8+a<,f>2nGBzYblu{|u|mubi[[SLLBQAnN?jI=cH>`HB^FCX@BO2K?3DG6EF6KE5PD4VC2^C2e@.m>,v=,|;):);*=.B2F7I:DG>F>E>C?@><>9:9:;<@.=->->,?.?-?,>,>*?*>)>->->-=,=,=,<-<-<-<-<,<,=-=0=0>1D2C1A3B6C:AkK5.>5.>5.>5,B8/B8/C9/E8/G:1I<3J=4K?3EC6FB6IC5NB4TA3\@2b>0h=-q<.w9*}8)7*:,=/B2D5E9F;GF@C?@@:9:9=;A;D:E4A-?(A-A-@.@.?.>-?->/>.@.?.?->+?*>)>+>->->-=,=.=-=-=-1?2D2C1B4B6C;C>C>D?PJ[Te\f]s_TYUJFNC>KA@70@72>71=6094.83-63,63.43.34.34.13.13..3-.3-.3--3/-3/-3/.3/.3/.3/.3/02/.0-00.22022000.0/-0/-10.8,,;,)B1*K7.S<4^IHtbnzʂyrwikXVGDI^C@[ABV>DP>EMGQSKWUQ^WU`XS_UR^TT^SV`UaZHaZHaZH,-/,-/------------.-+.-+/.,/.,1-*0,)0,)0,)/+(0+'/+*/+*/+*/+*/+*/+*/+*0,+/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*0,+0,+1-,1-,2.-1-,1-,1-,1-,1-,1-,1-,1-,0,)1-*2.+3/,3/,3/,3/,3/,3/,3/,3/,3/,40-51.62/73081+92,:3-;4.=4/>5.>5.>5.?4.?5,@6-C6.D7.F90G:1H;2F?5H@5J@6N@5R>3W<1\:0a7+k9.t8-|8+9,;/=0?1?2@3B5D8E:G=F>D?B>?=A?D?E>C8C1B.B,A.@-?,?,=-=->.?.<,=,=+>-=,=+=*>*<+<+<+<,<,<,;-;-=/F@C>DAKGXRf]qfth|rfik^S_SCSHQJBLE=D=5<8/95,74-63,33+43.34.23-13.02--2,,1+,1+-2.-2.-2.-2.-2.-2./1./1.02/02/11/11/11/11/11/11/5*2;/3A32C4/J;6]OOymyӐ݂tzjn_bYZPHmHBdA>]>>X?AVBHVLU^U`bbqnn}xv|pulyoguh_k_T`Ta[Eb\Fc]G,-/,-/,-/,-/---------.-+/.,.-+.-+0,)/+(/+(/+(/+(.*).*).*).*)/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*0,+0,+0,+1-,1-,1-,1-,1-,1-,1-,1-,1-,1-,0,)0,)1-*2.+3/,3/,2.+2.+2.+2.+2.+2.+3/,40-51.62/80-91.:2/;30=4/>50>50=4-?4.?4.?4.B5-C6.E80G:2H;3H>5J=5L=6O>6Q=4V;2Z90_7/h8.p7.y6-8-9.;1<1>1@3A5B5E8E:FF8C2B/C-B0A/@.?-?->->.>.=,=.=-=,=+>-=,>,=+=+<,<,<,;-;-<-4@6A7B8H7F7G:I@HBFAJFTMdZre~op~|mlteYgZJZOPLAKI=EC7@>2=:1:7.44*11)23+23-12,/1,/1,.0+.0+.0-/1./1./1./1./1./1./1./1.02/11/11/11/11/11/11/11/5*:9-9<15?53H?:^VTxszΐׄxpykten__yXZsSUjRWjU]j\gmguvrv}vypsfteXfW_YA`ZBb\D,-/,-/,-/,-/,-/---------.-+.-+.-+-,*/+(.*'.*'.*'.*+.*+.*+.*+-)*-)*-)*-)*/+,/+,/+,/+,/+,/+,/+,/+,.*+.*+/+,/+,/+,0,-0,-0,-0,-0,-0,-1-.1-.1-.1-.1-.0,+0,+1-,2.-2.-2.-2.-1-,1-,1-,1-,1-,2.-3/.40/51080-91.:2/;30=31=31=4/=4/?40?4.?4.A4.C60D7/F91G:2H;5J;6K<7N=6P;6S:5V72[60c60k6.t5,}7/9/:0<0<1@3@4@3A3C6C8D:CG@HBH?E:C3B0B.B/A.@->->->->-?0<-=-=,=.>-=,=+=+<*<,<,;+;+<-;,;-<0<0<2>3?4A8C:D;KJDIFKGSM_Vrgqz{wrocqbVdWPQCMN@HI;DD8@@4::055+/0(01)01+/0*/0+./*./*//-//-//-//-//-//-//-//-//-//-00.00.00.00.00.00.00.00.6*>6+;8.6;63HE>_^Yyz|Î˄}{||yq~o|n}oy|{j{iXiW\V<^X>`Z@-.0-.0-.0-.0-.0-.0......---.-+-,*-,*,+).*'.*'.*',*++)*+)*+)*+)**()*()*(),*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+-+,-+,-+,-+,.,-.,-.,-.,-/-./-./-./+*0,+1-,1-,1-,1-,0,+0,+0,+0,+0,+0,+1-,2.-3/.40/91/:20;31<42=31=31=31=31>3/>3/>3/@3-A4.C60D71E82G83H94I:5L:6M:6N94Q83T50^72e60o6/x8/90:/;1=1?4?4?2@1A2C5D7D:FIAH>F:C4B0B.A.A.?->,>,=.=.=.<,<.=.=-<.=-=-<,;);+;+;+;,;,;-:,;/<1<1>5@7C:EIICLGPL\Tj^oyzym{lam_UYHQUDKO@EI:@D6;=057,13(01)/0*/.).-).-).-+/.,0/-/.,/.,/.,/.,/.,/.,/.,/.,0/-0/-0/-0/-0/-0/-0/-0/-8*A6):3-1961HJ=bfX{y}~k|iUfSXT7ZV9^Z=+/2+/2-.0-.0-.0-.0-.0...------.-+-,*-,*,+),+),+),*+,*+,*++)*+)**()*()*(),*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*++)*+)*+)*,*+-+,-+,.,-.,-/-./-./-./+*0,+0,+0,+0,+0,+/+*.*)/+*/+*/+*/+*0,+1-,3/.40/91/:20;31<42=32=32<20<20=20=2.=2.?1.@2/A4.B5/C60D63C84D95G96G96H94K84N51V72_60h70r7/}:1<1=2>2?7?5?5?3A3C5D6E8E;F=G>F=D8B5@0@/A-A-?,>+<,<,=-=/<.<-=-<.<-<,<,<,;+:*:*:*:+:+:,:.;0<1=4?6B9D;G@HALAH?HAKGOLWQf]whw|}tqlte\eRV_LMVCEL0-?1.@2/A30A30?61@72@93A96A96B94E74G51O61W6/a6/j8/u9.0>7>5?5@4B4C4C4D4B5C8E:E;C7@4?1?2A,?-=,=,<+<+<.<.;-E5:@29<134,22*1.)/+(/*'0**3*+4+,1++1++1++1++1++1++1++0,+1-,1-,1-,1-,1-,1-,1-,/.,;(;5(23+(56$CL-\hDt`wƤШɯʰ˯ɪ{wrdx]MaHQQ5QQ5RR6,03,03,03,03./1./1./1./1/////////0/-/.,/.,.-+.-+/-..,-.,--+,,*++)*+)**()+)*+)*+)*+)*+)*+)*+)*+)*+)*+)*+)**()*()*())'()'(+)*+)*,*+-+,.,-.,-/-./-./+*/+*/+*/+*/+*.*)-)(,('0,+0,+0,+0,+1-,2.-40/40/:12;23;23<34=32<21<21;10<1/<1/<1/=/,>0->0-?1.@2/;60;62;83<94=:5=:5?82A60F5.O4-W5+b6+n8,x:-<,<.:6<5=5@4A4B3B2@0?1@4B7B9@6?5=2?2@-?->,<+;*;,;-;-;,<.;-<-;.;-;,;,9)9)9)9*9*9+~8,}9,=1=4@7B9E>HCKFMHIAGAJFSO\Xh`{ny~w{nixacr[ZhQP]IIUACL;>D60-?1.?1.96/:729839839:4:94;83>71A2+I2*S2)^4(j6)s8*|:*~;+84:5=4@3B3A1@/>-<-=0@4A7@7>4=4=3@-?,=+<*;*;,;,<-;.<.;-;,:-;-;,;,9)9)9(9*9*8*~8,}9,>2?5@7C5.>5.>5.=4-<3.<1-=2.<1-<1/;0.=/.>0/>0/?11H-&C1';5)2:++=-(=.-;.45-?-+H()R%(X((Z.+Z8.[A2\G6wC-{B.C1A3?1;0:/8+;->.B1D0D0B.?,<*6383:2<1@1B0|A/|A/C2A1>1=0;/:.9-9-v:/|@5u=0n9)s@/s@/t<+{@0{<-?4D9H?LANBQCRCHKTRd]ue{lwsz|yk{awhea]\zV[sS]mR[cLVTEPH=J;6G53B,/=&,:#+:#-9#/8".#/-#-,$-,&*+))+-(.1'/2'/4'06&14'14'13'32(32(30(3.)-0,-0,)//'=>0WZErx\gspqrrs{{z{~}|zvroi{e[jWLZIKO@CG8>B3/0*01+01+01+12,12,21,32-43.63.74/74/63.61-50,50,7/,7/,6.+6.,5-+2-*1++0,+0,-/-./-0--/-,1+*/)*.()-/(//(//(//(//)-/)-.*+.*+/+*-,*.-).-)/.*./)./)./)..0....../-./.,/.,1-*3.+3.*5.(6/)8/(90);0*<2)=3*>5,>5,>5.>5.>5.=4-<3,=2.=2.<1-;0.;0.;0.=/.>0/?10F/'D0)A3*=4+96-85.83-<1-?-+D*)K)(P*'U.)[4-_:1c?3s@+xA-A0?2?4;3:1;19.<->.A0B1B/A/@/93:3;2=1?0@0@/?/A1>0=0;/;.:-:,:,w9.x<1s9-n9)r?.s>.q9*u:,}=1@5E:H?K@MBPCQCDJQRd]vfp}w~w}oxag\`VZU}XWyXWpSPbJKVECI;@A998340-0,+/+,.)--(,*,+)+***,+),-(,/)-2(03(03(02(02(10)1/*1-*1,+3,+32-12./0,)--%9:,TWBox[iolnpppw{xwy||{xuqnh{eYjWL[HGK<@D5:>/12,12,12,12,23-23-43.43.54/74/85085085083/72.61-80-80-7/,6.,6.,3.+2,,1-,1-./-.0.1..0--/,+0+*/*).1'//(//(//)-/)-/)-.*+.*+0,+0,+/.*/.*/.*0/*/0*/0*/////////0./0/-1-,1-*2-)4/+70*90+:1*<1+=3*>4+?5,?6-?6-@7.@70?6/>5.=4->3/=2.<1-;0.;0.;0.;0.<1/=20C2*E0+H/+L,-N+/M*.J*/E+.A-,@.*@/(C/(M/'Y0*d1-j30i;+o;-w;0=4<4;594:4;2=2>2@1A2A3B5C6=2=1>1>0>/=.=.=.<.;.:-9,;,;+~=+z=*}=3z<1v:/u;-x@1x@1v<.v;-?3B6F=H?JAKANCPDDHQQc^ugnt~}{ak[eXaV`W`W]QtVMiPC[E=RA6F9/<2*5-&1+%.)$-(1&*1&*1&*1&*1&*1(-2).1+//*0-+0,+0+,0),1(-1&.1&.14.24.0.*'**"66*PUAmv[~ik~hjnn~mqx|zwvtuwyy}}ywspmh{eYkUL[HEG:=?28:-23-23-34.34.34.45/54/54/650961961:72:72:51940940:2/91.91.80-7/-4/,4/,3/.3/.3/01/01/00.1..0--/,,.2).2).2).0*.0*,0*,0*,/+*1-,1-*0/+0/+10+10+10+10+11111100010.10.2.+2.+3.*91.92,;2+<3,>4+@6-@6-A7.A8/A8/B90A8/A81@70>5.?4.=2.=2.<1-;0.;0.<1/=20=20?5,E2.O-.W(0]#/\"0W#/L'.C/.:3-55);5)E1(U.'c+*l*+e;/j;1s=3}<6;8;9;7:6>9?9B9C9B9B9A9@7B/B/@.@.>-<,:+9+8*8*9*9)<)z=(w?(t@(=3{7,x8,z3/>3/=2.=2.=20=20>31>31>7/C41O/2Y*2_%3`#2Y%1N+1B3077-39+68*?5)N1)]-)e+)c;3h<3r=7z=:<<<=;;;:;9>8A:C;CJ?K@LDOGSJycL~hSoYu]}biu|~|~|}{yn}lylwkwmtjogl~dbqZ[hTSZHIK=B@4=6,8/&5+":&(8%'6&'2&&0(&-)(++)).*'+*&,*&,*'+*'+,)*,**,**,-#$2*(50,85,BC5UZFfpWn}^tcqbtexiwkshsiwmzmxlwkvlyq{u{w|wxuzwwtqomhd{_WkPJ^CFB9>:195,560560671671782782872872983<94=:5>;6>;6?:6>95>95?74?74>63=52;62:5294194184184195484373243132021/6-.6-.6-.6-.6-.4..4/,4/,40-40-40-52-32-32-43.43.431431542540841850940:5/=60?6/@7.B8/C9/F90G:1H;2F<3F<3F<3F<3E;2C90B71A60@5/@51>50=4/=4/>42?53?53=82A64I35Q16V.6U-5R/5J22A62::08<.9;-?9)H6*P4)U3)]2+c4.k62t76}77897978}75{:6|=8{?7@9@:@;?;|E0}D0C0A/=.;-:-9,8+9+:+<+{>+x?+uA+tB+2,2,LEXQA8|90F;J>yH:zJ<{M@|NA~NBPEUJYN_uNgwRtzX{^|bis|z||x~tyqvponpp}pxmskk~bgu\_iQWZGPM0%:,+7,*5+)1,(-,'+.').((/().(+-*,,*/+*3)*6',7&,9&,2)$<3,E>4JF:QR@]bLgqVizXm]j\j]pbqeodoerhukrhqitlxrzvyvyvvtwturokjfc|^UlOJ^BHA9@91;4,671782782782893893983:94:94=:5>;6?<7?<7@;7@;7@;7B:7B:7A96@85=84=84<73<73<74<74<74;74:6395284173080.80.80.80.80.80.61.61.61-52-52-52-63.63.54/54/540540651952:72=84=82@93?80A8/C90D:0E;1H;2I=1I=1H>4H>4H>4G=4F<3D:1B8/A60B71@70@72?61?61@72@72A83=84@85B86D97E:8G96G96E:4C90B90B:/B:-D;,F:*H;*H;*].&b0)n3/x7398;;<<>;A>A<?6}=4~;3;5=8>:~C3B3A2?2=1<0;/;/;.|=.{=.|>/|>/|>/}>/}>/.*;8kf~yZTC3-<3,92*41(01).1(+1'+0)/0*2/*6,*:*+@'+D%+G$+H#+A7+LC4WP@[XE`bLgmQiwVj{Wl[gWfWj^nananbrfrkohniqnwsyvxuutssutspnlicb{[TmMH`@MD=E<5@707827828938938939:4:94:94;:5>;6?<7@=8@=8A<8A<8A<8A<8A<8A<8@;7?:6>95>95=84>95>95>95>95=84<73:51940:0.:0.:0.91.91.91.91.72.61-61-63.63.63.74/74/74/540651961;83<94?:4@;5B;3A8/B90C9/E;1H<0I=1J>2K=2K>5K>5J=4J=4F<3E;2C90B8/B92B92A81@72@72@93A:4A:4?74>95=<7>?7?@8@@6D@5J=4J70N5.Q6-Q6+O8*M:+I<)H=)l3(r6,~;3@:DAHDJGLHQJMDD;;28-7-91;4?7?7=6<5=5=4|>3y?3vA3uA3uA3y?3}=3:38373%$<;{zhcG@K@wI:mNfW@jX@r\E}aLeQj{O{{Uw\l`^_R\M[O^muxx΅~}xurruuus{sxrqlphiadtW]gLVX@LJ3GB.L40H3.D3,?2*:1(70&40'40'81):/+?-+C++H(+M%-O$-Q#-PE1[P:d^FgfJilOnuTm{Wl~VkZgVgVm]papbrdvhrlokmipmwtyxwwtustutsqokicb{[TmMGa>SJCKB;F=69:49:49:49:49:4:;5=<7=<7=<7?<7@=8@=8A>9C>:D?;D?;E@8C>8D=7B;5B;5B;5B;5B;5B;5A:4A:4A83A83A83@72@72>71>71>71<71<71;60:5/85085074/74/761961961:72<71=82A:2B;1C:1E;1F<2J>2K?3L@2N@3N@3M@7M@7L?6K>5I<3F<2E;2E;2B90A81A81?80?80?82@93@93<5/LE?IB:E<5OB:K:2J3+\>6Z5-`5.`4+^/'\0%b8,g@1gB2I;G;I?LAF>>7=6D;NDQEVHYKPB@5:0=49;9:675496@:{@8o?3oC6lB4m?2u:27435-3(1EEbaEDWUyvVOFd02b22\31L)'D'#I2,J70F5.E2,E0+H0.I-,I)*O+-V24VK/`W:f_BgdEkoLu}Xu]oWjWlXn]q`sbubudveqksmsoqosrwxzzyzxyqrmjjghdazZTnKIc@TKBSJAPG>9:49:49:49:4:;5;<6>=8?>9>=8@=8A>9A>9B?:D?;D?;D?;FA;E@:E@:E@:D?9D?9E>8E>8E>8E>6E>6D=5C<4D;4D;4C:3B92B92B92B92A81A81@91@93>71<71;60;60:5/85.74-74-96196/96/;60<8/>:1A:0C:1C;0E;1G=1J>0L@2M?2NA1NA1N@5N@5M?6J=4I<3H;2E;1E;2C:1B90A81@91@91@91?;2?;2C:3G81I0,V..j68u99{;;ECD?H@I?G>JANHPLMKE3C2B4B6>36-7+<0C5@.@.E3F6E5H9N@KRGN@F9=8:?=>?_\XQ@5UDvbJa]@Z_?ekIonOshJ{fKkP]V][SZ7SD=]P.dY9ga?ifCnrMz[zbt^r]o]o^q^ubwcwcwcrmwrzvyw~}z|qqljhc`yYTnKJdAWQEVPDUOC8938938939:4;<6<=7?>9@?:@?:B?:C@;C@;C@;D?;D?;D?;FA;FA;FA;E@:E@:G@:G@8F?7IB:HA9H?8G>5F=4E<3E<3D;2D:1D:1D:1C:1D;2D;4D;4C<4?80?80<71;60:5/:5/94.94.96/96/96/;7.<8/@9/A:0C;0E;1F<0I=/K?1M@0M@0NA1M@0N@5M?4L>3K=2I<3H;2E;1D:0C:1C:1A:0A:2?;2@<3@<3A=4SEI?MAOBRJSRNSENE2B0@0?1:-7*8+=/E4>+7$:%>+@/B2C5/89BDLKRNRLLB>}:1u;/q9,s5*2-478@?:A@;BA4G=3F<2E;1D:0D:0E;1E;1D;2E<3E<3E<3@91?80?80<71;60:5/:5/:5/96/96-;7.;7.=9.@9/C;0D<1F<0F=.J>0L?/M@0M@0O?/O?/O>4O>4N=3K=2J<1G:1G:1D:0D;2D;2B;1B;1@<3A=4A>5A>5Q9/X+&:?P`OeOfPcGO20:/?.C3F=FG>H2BH6F5B3@3?1>1B4D6G5B/<);&<(:(5&3$7<8>7>6=9@?:BA4G=1H<0G;/E;/E;/E;/E;1E;1D<1D;2D;2@9/@91@91?82<71;60;60:5/;7.;7.;7.<8-?8.A;/C;0D4N=3N=3J<1I;0G;/F90D:0D<1D;2B;1@<1A=2A>5B?6C@7_4-t42KSYiH_:Q2C#+/)9(;&=)@3A=:?0;D4B3?2>2?5C7G;J<>/?-=+:)9':*;-LDTLTNKJ>C3>.<5+7.0+9482@9[PUDxO9~dIlPbF]FeTqdsjb?eAiBkBmAm@o@o@qAqBn=hEmJpGhMiZrbsYc@D]($M-"PC2PR=CO76H.WH1eYCujT{gy~þþyvh{e\sWTmONiHTYBUZCW\E560560671782893:;5=<7>=8@?:B?:C@;DAGB>GD=GD=HC=ID>IE0I=/G>/G>/F<0F<0E;/E;1D<1C:1B90A:2@91@91?82<71;60;60;7.;7.;7,<8-?8.A;/D0K?/M@0NA0P@0O?/O@-P>2N>1M<2L;1I;0H:/F90C9/C;0B<0B;1@<1A=2A?3B@4C@7t50FEY_Ub@Q5F0;*+1%9#;!: =&=.902-:,:-9-6,91A9E;E:?2@0<,6'6)=0D9G=9*@4D=A@D<@?>C>JBRMZWPREL;G6F2D/B1G6L:T:T:T:W=\?aBeDih?jAm@n?o>m=mFn:a>dInJlMmSoXnp_jILt:6\6-O9+OD2SN:`PArdW|p̿m~k^u[VoQSlNU_DV`EWaF560560560560671893:94;:5=<7@=8A>9C@;DAHC?HC?GD=HE>ID>ID>JF=LE=MF2G=1F<0D<1D<1C:1B;1A:2@91?82?82<71<71<8/<8-<8->7-@:.B:/D2B@4@@4+)JKSV=B/6.3./0)1 9!=!== =#;#6"6-8/5.3,71@:B<@6B7A57`UqeSWCN:XGe[a_PTBIDK@D@?BHC?ID@HE>HE>ID>JE?JF=MF>MF2G=1E=2D<1C:1C:1A:2A:2@93?82<71<71<8-<8-<8-?8.@:.B:/D2??3@@467]_Z[78,,/,,#0#8$B(G*G'F$F$C!? 81;29250:6B>D=>7<3<272:<$:*.($&''%%(,)2*5*3(2'/&-%=(2>05)7/?7C9qdm]YFVEi\lfSS@H?L46,4.44BH8G2F3H5I7GY=X:W6W5Y5\6_7e;k:m;ot>vEbNkTqIf?\Rqff^wbvkys{rvfeZVTN~ĻþĪyvi|f`w[\uWbqRapQ`oP201312423653875984984983;:5<<4==5??5AA7CC9EE9EE9HH@HH>HH3B90E<5C:5@85?74@86?67>56:44F85E76B87@78>:;<:=<<>==????A@,B0D2D0B/?,>*<*=-C4F7>03&6+8,:-=/=.(9%44 9%8&6&@4QEIAMIUUVXJP9A4?9DCHCFAA?;=3=/?/@0Q@QCLCC=??@E>G8CGMENEQESAR=S>XCbGiBhHH7H?8F=6C:5C<6A:4?74?74@85>95=84;63>3/=4/>42<74=98<;9=<:>=;@?;C@9G@6J@4L@0O@-P?+P>(=B,?A,E=0H92K63J46F35A57>=;8=69?5?A4C=-J9)^B4sRCK=;-2#6&:'8$9%?(;%=(@,@-=,9*6(5(;+:*9);+?.B/B/@.?.:(<+E6H9?18+7+5+7,:.;/=/;/8/4/0----+/+4)8(;'=&:'7"8%=*;*5&;/G8;1;-<->.F5M?NEGC?@>B>F>HDJCLDPFTBS=S>XBaFhCi?i@lBpGvJzL|IxHtKpRs]z`{XwMqCkAlCjJg^ppugNIv̲Ų}/.,0/-10.21/43/540762761:94::2<<4>>4@@6BB8CC9DD8IF=IG;JH;KJ8MJ7NL7NL7OL9KI:NKBTSQ_^dihxmmlkihcYd[QZQGPJ@IH>FG>CC=A@::1>:1=90:3-94.;60=82=:3>;4?<5?<3C?4F@4I?3L@2O?0P?-Q>-P>*3@&7?'<=+A;-B8/A62>42;31=85B:7H94O2.[+)o-.:=EJ9+2$1"9'<)7$8$<&;&=)A-A/>.<-:-:.>0<.9+:+<+>->-=,?-9(>/L=H:6*2&;05*6+8,:.;/9.7/2,/-.+.+0)2'6&8$:#7$5#8'>-=.7)8.A7<5?8EAKIIJCC?A@CDCC?B;=4:.9*;*<+9)E8NEIE?@X@_DfCiDmFpIwK{L|K{CvGwJtNtZ|aUvCdHkRv=\H`z}~\F;rճξ/.,/.,0/-10,21-32.54/650872991;;3==3??5AA7BB8CC9IE<0?=1@<0?<-A;+F?/H?.K?/M@/O?/P?/Q>/P=.<@)=?*?>,?<-?;0=:3;:5:94<94D95N43[*-o&--83C7H7)7&9(?-?,9&9#;&:&<)>,@/>/<0=/=0@5=2:,8*9+:,:,:*;,;-B4E9?31'2(:13+4*7,8-8.7,3,1,0,.+.)0(1&4$6 8/04$;,4Vet͑]=2aP@wlѥº10,10,0/+0/+10,21,43.54/77/880991;;1==3??5AA7BB8KD:LF:OG:QJ:RK9SL9RM:QK=OKBVTUfdowxÎƏ{wrlid_[~UPnNJaJGXEBM?=B;7696196-86*86)581692891;;/><-?<+C<)D<'I>*J?+L?,M@/M@0M?2M?4L>3M?4K?3F<2B90=909:25<44>57<5>:1H3.\0/{48;D9E2A<+<+@.A/@-<'<'>*8%:'<+=.;/;.<0<1A6>3:/7,7,8+8+8+7+A5C88.1&3)7-6-2+3)5+6,5,4-2*/*/,.*/)0'1#4!67//2"5)9-:0?6E=F>@9<5@9KDNGF<;1=1<0C>EBJJTJYFXCYB]@_BdFjJsOxOzLyIxGwRQ}IqImStVtNiD^F]YkKFd2)jc͖ɿ˾Ⱦȿ84163.52-30+30+41,52-63,85.96/:70<90>;2@=4B?6B?6KC8ME:PF:SJ9TK:UL;SL<=;:6;8396/267465672880<:-A<)D>(G?(I?&J?)IA,JA0IA4IA6HA9G@:R9?46<*=+?-?->,>*?+@-8%9(:+:+9,9.:0;2>7;4818.8.9/8.6,7-C9?50&,#7/<44,1*1*2)3*3+2+/*.(.*-)/)2&3$5"7 75#3#2$2&5)7,;3?8YRRJHAD;F0A3A6<5<6A?EEGIJMMQAD?ECIJTN[JZF\F]A]BaEiJpNwOzMxKxR{R{OvOtVw]{SoD^UjQddt`cKLkeώ<94;8385052-41*41*52+63,74-85.96/;8/=:1?<3A>5B?6KA7MC7RF8UI9WK;WK;UL=SJASJK[Xcnlǚޞ졩홛敘ߔ֐̈zzrqfd|XWiPN\IGRFCJDBG=?K==G;:?;:8<92A;-D=*F@*F@(GA)GB.ED2CC7BC=AC@>BAG9HH,>,?+@,@-?-=*8'8)9*9,8-8.91;3;4:3818192:2706/<3>5912*3*;2<35,0(1)1*1+0+/)-(,(-).)0)2(5%6#7!8 8%8%5%4%4(6+7.7/NGXPZQRIH>E9B5?1<&<&<(;'9(;*>0@4D;?9@:FCIHHGIHJMCFADDIKSQZN]L]J`D^DaFfIlNuOxOxNyYzWvVuYx]{ZuQkI`WkUgN\^kKZSaSaQ_jfɂ~窧@=6=:3:7074-52+52+52+63,74-74-96/;8/=:1?<3@=4A>5M@7OC7RF8WJ:XK:YL-C@-CB.BC3AE7>E=UEYFL7A+A+@,A-A-A-A.A/=+7&7(8)8+8-6-7/8/;2736161729494816/A:8/3*7/=5=58/6-0'0'0(/).)-)+(+(-)/)1)4)5'8&8$8#8$9%7$6&7)8,7+4*3+NGd\`YOFB9<2:/?&>&=&;%9&9*;/>3C9A9E?KHLIGDFEJIFGCDDHMSRZR\N^OaG^GbGdIiNrRvRyRy[u\x`}_|UpMgPgYn[mbsL]SdM_RgI_E]d`tqښA>5@=4?<3=:1;8/96-74+63*52)52)63*74-:70=:3@=6B?8J@6OC7RF8VI9WJ9XK;ZL?[NHTIMXR`gd|}̗瞩꟡ܙҍurhe]ZXR~YP{YQxVOpOG_E?M?:@?;8@@6>>2@B5@F:>E=:C>9CB*?,@.@.?-=,;,6'5(6*7-7-8/91818495:685616183:3C<=670@7[Rlc]T@71'2)1*/)*&'%(&*(-)0*2)1%0#1"5$:(=&=&=)<*;,9+8,6-@871GAc^XQB<@93.<#<$<&<&:(:)<.=2>4C;PJXTOJ@;@:KEFEFEJKPTQWNVKVL\RdOfKeJfMnRsRvPt[wZuZu[w]xZsWnVictVg\mYlDXBXMeIbnhhcˎ赲C?4B>3A=2?;0=90;7.:6-95,73*73*73*83-:5/=82@;5B=7I?5LB6QE7UH8VI8YI9YK>ZMEUKLXP_ebyzɔ䚧䘘،ɀ~uqieb^cVbU]TWOtNHdFCTBAIAAA;=8@C9<7<7=9A=C=B\Q?46,+#)#,)./,-((0.4/7/6,4)2&3%5&='<'<(;(:(7)6(4(8/5-<6PJSOLHA?/,=%>&='<'9(8(9,:/>4B:OFWPQKD=B5JB7ND8RF6TG6WG7YI:YKBWKKXP[b^wsuޗ뙗Ղxtqml`i]dY^VVQyNKhEDV@@J76;?=>HBBKABN?BYFJmX_}fnt}}wpcRpE^I\EP9<3,7(;%; <*<*;);*<,<-<-<.6*8.<1>5@8>7<3:273403/93A;E?A<<5<44,4*7-2', 6*H@64--)+*+,+,*,))/+3,5.4+2(2'2':&;'<(;);*:,8+8,4+;4:5<7ONXYEE02=(<(<(:'9)8*7*7,>2A6JAUKRIH>E:H@IDHCLGSPSSPQMQNWXdZh[pZrUoQlPnRpFmOvZ}[{VqSkVk[mYhYh`m`k\fenfmT[cY}NDlfØ߹IE9HD8FB6D@4B>2@<1?;0>:/:6-95,95,94.:5/<71>93@;5E>6HA7LD7QE5RE4UF3WG7WIC_@EmDJOU]fjreklf]TyFg8U0H>PBM:<7/@.B*/?0@3@36*KBJE50FFZ\HK?B=-;+:*:*:*9,9+8,<0>2F9OBPDH3A=2=9.<8/;7.;60;60<71>93?:4B?8EA8JD8NE4PE1TE0VG4XH9ZMEVMR[Whkl~В噧铕⊌لӅ{umkdd_aX[QQsNHbUFY_CRlBLEOLVU][d]fJuNxPuLnFc?Y5J+?5EAMFK><>6H8J6B)>-=-<->/?2B4D7E:E9B7>5:26-5,3+2*1*4-6090807/6.5,/&5+6)2#1"9)>-<+=-D7KAD?56)-)-.26755301,/,/,0-/-80:1:1<0<0=0?0>17+WL`X;6;:OQEHOT=2:/8,8,:-;.;-:.:-<.B3H9I:D6@2>0E3;18/4*3*4+4,5-9/<2=4<3905-5,6-.$;.<.1".8$=);&:'9+:1=9@@;?27+1,.+,+)+(/.4488:;5564736/7-5*5(5&5'PEmcHA42CC>BUYB;=6706-9/<1=1=.9)<+@.B0B0?.=,<+C8D9H=PGSLOIOJOP_caiitm|duUjRgWoSxUtWp_poyy~msXaam`maos{숊ɂ|wjyhhpYMO:^WGqgݿSM=RL4D=5B;3A:4@93A:4A96B:7@A;CC;IE:NG7QF2RF.UF/WH5XJ=RHFXR\jh}ƒږ奦띤蛢晞⒚ۊ҅ʂ‚ymczWiP]KWGP?H9A;6<5B6H7J5G1D.@/UGG?;76488:;9866=.<.;.;,8+6*3)1&5*3*3(2)3*5,6.7/>3<2;18/7.6,4*3)3&3%4%6&=)>*9$2;(5%3'60;<=@7=27-1..--0.449:;=;>.4/3011/1*2(1%3$2#>/j_TL95@@:=RUJEB=935.8.;0<0=-<*?-@.?-;(;(<)=*>2>2D8LBPFNFMGNLbcbfhqo{hxYmUj[pXs\tbqkt퉇yy_dhrl|cskw餟z\pWFRRL4:B*D)H)N+O(L%H%D&WBF8;5>>BH>F5>08F8E7D7A3=08,3)0%0&1(2(3*5,5,4,4,C8=27-7-:/9/5+1'7*0"0!9&9%5 9#E.:&:)7+3.//055;;BIMGJDD@@>>9:28.4'/(/*.-.0+2*5)7(0!/eY]TA,A/B0=)8%9&;)>,8+8+>1GTK8>=@D@HB;D;BCG99B@D@/-HIHKAG;D8A:?<><;<9A=>9C=LCK@>27+;-9,8-7-3,0,/-1134A19)1 1"8(;*6%22454 3"3%3(3).(2+6+8*8(7&7%6'3'2,3101+2*2+4-6+1*/+,.-4.8,7(5#.3 XHZL<2OG5/IFQRLKDB<8807,9+;+;):'9%:&<)=+=+=,9.;.=1?1?1@1@2A4k_qed[mirocbjituk|ivdm_hafgjnkqk|w}Yj[wZpaz]sMIZ6LR6snX˷YPAXO@XO@VM>UL=TKD:B7?7;89:8;7F?<5<4G>LAC7;,9+7*7+7-4-2.3/5366?0<-6)4&6%6%4"4:":":#;&<*;,8,5*3.5-7-8*6&4"4!3"2$1(/+.,,-,1-3.4*,,-0.2.3*5'7'9'@,*E5?1F>WPC?BAWVRRKJC>=59.9+8(;);(:';'>+?-@/>-9.;0=0=1?0?1B3C6i\mdb[kfolbakluvpo|ir^fY^adqn|vyux~RdUrXnXn[tLN_;QZ;us\úZQBYPAYPAWN?VM>UL=TKCC>C;C7=?AA@D?=896WWBC=B:A7<586696;6HA:35+A5K>H:=/8)7)7+8,7.606387;;5)6*6*6*5(7):*?,556 7"9)8+4(0&=;>8=5*B/1 TE<0A;C?JITSVVSSOMIEC;<28+6&7&7%7$:'<*>-=,=,:.;/<.=/=.?0B4E7\Og]aYlgpoabfgkoP`^khqem`edgqqzwvsnuJ]MjUm񜡟PcVoEOd=Va?ww]\PB\PB[OAZN@YM?YM?XL>XL>UI;TH:SG9RF8RF8RF8RF8RF8JF=KG>@FCA<71>:[WAB?C=@:=8997=8A:E;9/2(/9(8)8+:,:/8083;7=:3+3,5,4-6-7.:.>/9(<)>->.=/=2>6>7?>?*<(=,^PF<3/.-?BUXvurojg^YPIA75(.8'9&8&:)=,=->,<-<.<.=/<-;->0B3E9MA`Wa[pltr`a]a^dFVYegpgodljpstxvssenCXEbRk뒘N\Ql?Ri?ZhDy|_\PB\PB[OA[OAZN@YM?YM?YM?WK=VJc7U8IAEFAIAIAFCAG;J8JDI>A@?JE?83,D@>?>=@'9&5$5'9,;0:/8-?1;-8'7&:'<)=';&>-:*>2B:.+::142673;7C>JEQISHTHUG?0>.<,<->.@.?/?.=0=.<.<.<,=.A3D6LAbZc]nlrr`c`e`gixozlt`h^fkqw{{|pq^h@W>]Oh懍XaXuE\vIgwPfŻ㾺޺޼[OA[OA[OAZN@ZN@YM?YM?YM?XL>XL>WK=VJPI?QI>SK>UL;XM9YM7YM7XM;WK=ULGYSWc_nmktt|~ȍώԏՍӐӋʂ{u|ovgpckn~eyZvMo?c2V0L6G@CGBLBMCIGCJID<45*I@LFCA>=:;;;?=E=H(9$8$8&:,?1A5B5A6I8B1<*:&<)?*<)9&;*6)0'B<1/>A.2'-3-4.71928.5*2&1#E5A2=.:+9):+:,:,/=.<+=,?/A4SGg^d_kinochjqoxp}t~mwcjdlqzw|sukpXfAY:[Kf}lojXoZx`rū٫ӦѥԩԮֱںZN>ZN>ZN>ZN>YM=YM=YM=YM=XL@E@JBKCHGBL8E;F9E68(:*:*:'8%:&:':&9&:);*9+7+5+3+4-)-)/,3.4071828587;8<9?9A9D6G6H5J)1,2024/7-9*<+=,7&9*2?4>4?6?6N0/-.38384-6.80:1;1;0:.:/L?F:?29*7)7*8*8*<->/?0=/<+<+<,>0KAc[c^kioshnrzveroyr{jslvvu}ioflRbA[6YFat{~zf{fhu˭շˮŨґēș˝ˡΧҮٻǾ[N>ZM=ZM=ZM=ZM=ZM=YLXL>YN<=A=E?GBDHAK=M:OBAGDA583.,)&.*:3C9D6@0:(<)<):';(=(;'8%6"7%8)7*5(3(3)3*03587<38,2&-'-)1,3'0%/'6+=(A:2".&0+10/1,4+5)6*6+90>5>7:4615061L?K/6(3%6)9-5*6-C<7421  89352(3)4)5)5+5*5+7+YNRFH;@4=@ABICMAN>NA<@9?6?3=/=0E8MD61;61.2.C.&/(<7E@:7/,.*41:7?3;.5)3&5*:.;08.bWZOD86,:/9-3)6,1%2&2&4'7':,<.=/:.C;\Wppsvv~yq|{xu}s{r~q}lxisbmI\=\8[:Vek}~i|d}cju|vxqwo|rtwuy§̹־ʻZM1B6?6?8A==;:<:@7=4<16;3:06-2.314364/:572DADA/+2."41?/E5G7C8?9=<9>9A:E>GAH@E@B<4908-:*9(:*?3F9665:7C=OEI<4%9&:'<)=+>,=*:)9)8'2#/#4*=3?6912+7&6&3#/"-"+%,&+(++(+'-(5%8523(5.;4?8C;D+616=8<7=4<2;/:.7*6);/@8TMgeorz~{{zxwsl}ftbn]kG^:Z9\AZ_cgk^eOhOlRtX{\}^x\qX`yO_P`UeYm`ug{jmptvyyz~ǹ˸̴[K;[K;[K;[K;[K;[K;[K;[K;ZJ:ZJ:ZJ:[K;[K;\L<\L<\L<]K=]K=]L<^M=^M;^O<^O<^O<`P@^Q@]P@\NC\NE[NF\OI]PJ`NdcSmfX{g^ohzu|{yxucOyAF@@A=F;J;J;F9B:@?;A:D7>850-&:)8)5(2'/'.',(,*+*(,)1+7';";="A8G(6/;P\`lP\^N>^N?^N?_OB`PC`OEbM\cPdcUodZlevr~wv~‰ЁwkXuFf=MDPJNJHG>GBB>C>G@HCIDDB=?9A5=/:+;*:)9*<.?6FB<;ABAA:8JBXLL>@08(3#8(<-:*7)8+0%3)8/;4:3500++'4,4-2.314345586;/4.60=1C.F*G,L1TP3D2A3>5<89733*/$2*-(61XT\ZXV@AHHB@<7706-8-9+7'3!:%9$;(=-;-6)8.>5NGEA501->9?:8171/011427392:/9.:.6*7-IB_Ynl}v}x~zxsj{dt_nUeF]6V7ZF_TRvaBJoR-H:QCTDK@AA>DAEBEFAF@EBFDEEAC:?4@3;-8(9(:)9(:-;3IE??;>682/A:ZPg[QCA34'6)9+8+6+8,0&5-;4:440/,-+-,4;3;3<2=1>0=0?0@1A2D5K5O0P-Q1X:d7BO\an`nXfQbEX8J@S:G2;/23-9-=+>(9/2(JBkcLGPM<9;9LJ@<7/7-(;%=)?-9)4':1C=HAC?722.;7:62.2-)++,.-3/61:1<1>26)4)B:XRjh|}v}y{xqh{bt^oSeI`9X9[I_QNmZ:Em8ZvCa|InSvY|]bgll{m|o}p~onllqqrronptvtwï̾ŽӫZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8[L9[L9\M:\M:\M:`J<`J<^K<_L=^M;_N<_N<^O<^O<_P;_P;aPH$H0Q;UA6>1?19+7':)=*=,>1>7=:79/3/03294NElaj[QCD>61;7UQF@918-:,9(:&;%B)<&<&=*8(3(=4MFGCEB96307341/+2-)/*/--0/4/7/;1>2:,4(;2NHb^yzz}}xn~dw^p[lN`Ha8W7YH]JGcS1Al6ZtDf~NuZcfjnsttr}p}nmlknpoolknpsrwƱοŷҤZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8[L9[L9\M:\M:\M:`J<`J<^K<_L=^M=_N<_N<^O<`Q>aR=bQ=bQ=bR;bP:aO9`N8jNMgNRbQ[cWkjfuv}}y{˃{|qsgjTXAG#M.T7W9P>NEMEH?BBDAC@AA?C?B9?4=0?19+8(=,A.B1C7D=6457,002880+5-UKzn^RD7=0<06,6+90708271401/105387=>>>==<=:@$I&N$Q%U0e=sgralXeR_Q`M]?R1B:J4?-0-(5'>&C%E"7&9(WH<0A87/3/C@XSHA916*6&5$6"9#B*<%:%<*7&3'A7SLIEGE:82.411-.)4.'-',)+*)-(1*5,9->13(7.HB\Xwu~xl|`sZlXiHZE^4S3RCXE@\L*?j4Uo?d|Lw\hlptx{xt|mzi}ghhkmmlj}ilostx«ǶȻӞ]K7]K7]K7]K7]K7]K7]K7]K7^L8^L8^L8^L8^L8^L8^L8^L8\J>]K?]M@\L=ZM=ZO=\Q?^SA_T@_R?^Q@aQAcRBdQCdNAcM@pKEjKIfOUgZknlv|}̃{~uml]fRN[DQ>LANCQ>K:G4;/8+:$C0=,6(?5D=;56183716-7)9(=';"774PLXOD98(?.C3;-4+GD.14;4?+9@Q(9&+*-*-"#$()(("+1 )&1.<$5Yn+@`j^iYcT[PTHI@;:1A2F2D.;$57#;)=+8183EC;9234544CAKFKED;:04+4*3+2*?19,.#',"7/C:G=PFE;801*/-01/3.4141201/00.1+4+8-=/2#?0>3`Wtqwe}[wXuSoJgDc7Y9]>[]kC=PI/F`;Xw^N?^N?[N>ZO=\Q?^SA_TB]QA]P@_OB`NBbPFcOFcOFkLGjMOgS\h_rnow~~̢wx|xuhjYZgN\FRHUJVER?J;E9A:>::=:?7>4+?-9(:,A6<47/<7404-4*4(7&:&;%;"52A;MDI>>/8(8);.<2JF/15<6A.68,E4H6?,1)()-':6TRHG5445<=WUGBGAB99/4+6,7/5.?5:15.3+4.83?9E=JBA86/1*0-1103.3141201/00.1+4+8->03$=.=2^Uvsue|[vWtQoIhAa8Z=_F`Q\{?7NH.Ga>Yx=eKsYxawbzf|i}j|i|i|h{e{d}c}cd{l}n}l}i}e}cccfkpu|zdoqR]_]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8^K<_N>aP@`P@]P?[O?[O?[RC[QE[QE\OF\OG_PKcQOfTRhTUiTQiVXi]kmisvz͉ٟ֗ʪ}烅~tve`kS\GQFQHREQ@K=G6=7:99<7@7A4?0=-@-=+;*B4I?;20)926/5.7,7*7(7$:%<'3/4.A9OCH:6%3#@2>5HD134;6@4@ES3A),"&#&03--''%%12(*7:+1)13?R^=KYiafV\OTMREI:;74?96,?2C5>18-3),%' % 0*FC::,,44AB^]>:C;A9=39/=4@8@9A>=;>=A??>;9?=IDA;=45,2+2-3112/2040201/0/.0+4+8-?14%9*;0[Rzw~rcyZtTqMmFg=_:^BbQg?Fn<1OK2KcA[z?hLrZu^t_wc{gzgyfyfycxbyb{a|b}byj{j{h{e{az^|^`hnstwvypngVb`COM4@>^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^L6`N:aP<`Q>]P?ZN>YPAXPEXOH[RM_UTcWYeX_iYcl\fm]hlbclemolrtx~τߊ狇ޝ٬ɳy{߁yvnrbgU\LUFPBM>G;D5;7:97=7A6B4B1?.;,=/>0G:RGH?6.1)9181;0<0;-6%6&9'402-=4OCK=;,8*B67.>:/0164<8BNZKW>C38$&/1,,22+*0.::37-29BENYcLY?AADCF>C9=8988:58391:2A:NHVSNNAB82:5KGNLQRYZRQYX51>6C9@7?5A9CC:?58=?LJ93704+3,5.302101040201.0/.0+3+8-@26'6'9.WM}y{ocwXqNmFh?c8\=`IdYh25d<0SQ8TgG`}EjPsYt\u^wbyeyfwdvawav`x`z`{a|byhzg|fzbz_z]|]~_emrsustii_RaZDSL8G@^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;_K2_M5aO9_P;\O>ZN@XPEXQKYQO^X\g`hnfsshysg{sg}tfnnzorrwv|y~׃刋쒍뛌ߞƞtkmqvj{illklfi]`QWEM;B5=596898>7A7C5C0A-8+@3;.;1RH]SNC;2907,9/>1=16*4'7(2-60=5E9F9C3A2?20&620/-1-47?OYZd[_OS.103--EE66,,-.>@2537ch=C*2-4();=AE7:378;89..43<9HESS`chndk[eB7Eb8_4\@aMcWap/+\A0XX>]lMbIlSt\u_v_xcyexbu`u`u_v_w_z`{a|byd{f|dz`y^yZ{Z}\_gmpst{nrffvi[k^RbU_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<`L1aM2`N6^O:[N>YOE[RMZTT_Zahbprmzu{tyrzpyoovpyt}wz~Ճዋ唏㗊ҙ~yl[X>H?PIVRVURRJM=C387<9;;9=8A8C4B0@-9.A65+.$J?h\eZVI=26)4):0;05,3)6+/+61;2:/?0F7C39+1&3-31-.*.17EJS[_d\a9<9<+.JK89//55()(+YZ?B9=7: %))=>BE49,217/5(,37KNaehncl_k_m_nNIOJ]ZVTMMGH3231AcWh[fYPB?25)7,:05,2+6.0,4/7/8.>1C4?04'4*1)2/..-.1468?COTY^FKRW47FJ889;>=A6<-4)219/>)7-:9CAHAB1/4-5,5,4-3,5/50.4.2.1-0../+3+7-:.>02$7,<3tqrj}bt]pRjBb6`5a8_KfN[z;6Y?.LH/TZ@]cIbzJjTr[v^yc{dxas\pYpYqZqZt\u]y_z`x_y^z^y\xWvUwV{X~]dhlormxgrlk}ecu]_O?_O?_O?_O?_O?_O?_O?_O?^N>^N>^N>^N>^N>^N>^N>^N>eQ6cR8aP<]P@ZPG\TR_Zab^otryx~~yxwvxwt}w}Ƃƅȸп¡ϼDzkS\FG5=0H=VQVTNO?A=?<<<;=:=5;18.82<5:3>5PDYM]PgXdWM@:-8.913-2,50402-5-<3C7C4:-3%5*-&0+.,2144.,00EIY]W\puDJHN=C[aou>C~mqQT>@02<>EI9>7==F6@-8>J\hmwitdl]g^kap]nWh_YOKJG740.54/.95D?JDJA@86/5-7194$0/<1=*6/:>E>C443.5.6-5,3*3,4/5/.4.2.1-0...+2+6-9-@21$6,7/pokcx]pZnPiAd7a8d=bPiQW^2'RG3DH/PV`P@`P@_O?_O?_O?aQAbRB_O?]M=]M=aQAcSCbRB`P@eS;aP<_O?^QH[QOZSZeapsqxxz|~}xyrsnoqwv{̋ȖäŲͭЩУѠѡ̚Ɣզg_FzgteG?QMbaIL>A799;997561949550B;=5I?XKPAeVdVYKG;:/6-6/5/3//-2,70=4<08)5(8*/$/(.)0-204051408X`~~owgoipfj\_Y[^`RYCK8B7A1>+9/>=IS_`kgpepbobp`o[lTOFA853110/.2186D=B:?7<4908183845=4;3;4<5;49331/3,6-7.5+3+2,1,2./503/2.1///,3,7.@49,7+/&<5XW~he|]rRhHeAe9b5`JlRd==K. >>&?I.IO5]]EWlAcxMqZxby`t\rXqWlSmRnSoVrXt\u]u]tVtWvXwWvUvUuTtS{[{\z\uZnUc}MXrCSj>AW1?U/`P@`P@`P@_O?`P@aQAbRB`P@_O?`P@bRBcSCbRB`P@fVF_QD\OF_TRcZ_f`nmkwvwy{}}x|qtlolnoqsu|}ىԘШƹƵϩףܞߞޝܞ٠ҜʖѼ~dċw}mVJ`YqnZZJL>@<>>@:;5634=:73?86.>3L@I;^Op`aSH<5)0&5-4-/)4395<7<38.5)5(5*6.4-1+0+0,2,4.5.9;>AIMW[\d\d]e`kR]MXQ[_gjqfl[`RU07+5+5-9&5/'67DP\[dclemepdo[hP^FB<9646353202/62>9>7<2:1918295969;7:7:797957313,4,7-7.6,2+1*0,1.0503/2.1///,3,6.=2>28-2*82Z[w{a{^vWqOkFf=b:c=cLhJVw<8F5#7=#9C(DH/UP`rJnXw_v]tZpVnTkOkPlQmRoVrZs[s[tVuWuWuUtTrQqPqQnPlNhLbFXu?Nh8F]/@W+@W-@W-AX.YL<[N>^QA^QA^QA^QA_RB`SCaTD`SC_RB`SCaTDaTD`SC^QAbUM^QK[QPcYakesqmvuy{y{y~w}nseibfjnrv}zᇃᖔߩټظۤϠĘkpp`RG]Umius^_HL@D@D=@7:36>;;6A:707.?3=/G8j\j[\MB62(4+6-1*44A>GC=62)1'2'0%3*1).)/)2,7/=4A7-,43CEVX^bYaS]P[FQHSNY\fmvmtY_AG*2,41<1>*9&66EJXISOYW__fdkaiQ[BJ956375<8<9855160:3;290908183:6:8;9:999988884403+6,8-8,6,3)/)/,0.151302.1//0,3,6.9/D99/4.0,`bnu_zWsPmLlDf8_9_GfReDJi=4K@,7@%8@(ED/LE2N^9YkEg|Qr[tZqUmRkMiKhKiLkPmToUpXqZuWuWtUrTpRmMkKjLdGaE\~AUt;Li3E_/AX*>U'B\/E_2Ic6WJ:ZM=\O?^QA]P@^QA_RBaTD`SC`SC`SCaTDaTD`SC_RB]P@YNR[PVbXcjcsqmvuxzz|w|symrbi]caglrv|ȋ攑褡淴޿ܨҧßvqsecWi`rmut[[KNCG?D;?8=:8;8D?C;:0;/7)2#J;bRk]SG9.3)5+4+33ML[XKF803*4+2(-&,%,%,'0)6-<0?20(4,:6CBFHEKGPLVQ]VbXd[ggpmuY_=C.2-4-4*4%2(6@?<;857292:1908071738687<9;9:7;8:8845.4+7,8-8,7*3)/)/)/+252312/1//0,3,6.8.G<903.-*fjyjr`{TqKkFj=c3[<^PhXeDBbE7WP=DH1@D-JH3JB/IW4Sc?btLmUpXoRkNiKgIgIhKjMkPmToWpYtVsUqSnQjLgIeHdG`D]AWy=Rq8Mi6Lf6Ne7Pe:Lf6Oi9Sm=UH8WJ:[N>\O?]P@]P@_RBaTD_RB`SCaTDaTD`SC_RB_RB_RBTLY`Xgnf{tpxtxwxzy{syjq`g\b`fkqv|~Ε䞞譭齼߳سѴůy}qwkskngoi扄~sredVYLNCE>A95:7B=E?<3=3B51%1"I;YKN@=/8*6*3'34UUkh]XE>;3;2804-1,1+0)/'0$/$0#9,4'3):5CAEGBG@HDOOZVaVa^igoYaDI885526183;9CHSVa6?4;7;AFKOIM;@056195;8;9;9:77370;2;1;2:282736465<8;8;8:9;7956/4,8-9,9-7*3)0'/)0+453322010/1,3,6.7.D:7/1-21jprzhr]vPmCf_L;_ZFQP;KI4PI6MB0DR1M[8[kFf|NmSmPlMhHfGgHgIiLjOlSnVoXtVqUnPjLfIcFaF_DZ@X|?St;Pn8Pj:Tk=XmB[pEUp=Vq>Wr?RE5UH8XK;ZM=[N>\O?^QA`SC`SCaTDaTDaTD`SC`SCbUEdWG]Ulje|yu}yzywyvxswlqcj[c]ehpw}ǁІՙܡ௲廿Źxzuwvqulg~mfoib[a[smzu{|yrpccSTHHB=>:<6A;:1D:TJ>26):,=.?/A3C5?18*23LM_]XSD?;48170929292929/9.9+8))3"@2I>E>;:7;9@8AHTUaYb^g`iU[CI?:?;AAGJMRQYT]V^4:/5037:=A:?48/2619595411/20404.<4=4=3;293734333:898888987754/4+7-9,9-7*2(0&0(0*454332111/1,3,5.90<3700-AAnukucoSkIf;c1`3bRJ7QF4MB0AL.GU4Sc>`rHgMjMjKhGeFfGfHgJiNkRlUmVqSoQjNgKcH`E_F_G\E[~DWxAVr?Uo?YpB]rG_tKYtAYtAXs@NB2QE5UI9WK;XL\P@^RBaUEbVFbVFaUE_SCaUEfZJj^Nkgup|x{ywxvwptjoah^f_gempx~͉؏ܙϠ֪۴ߺ߾̼ƻŴqqstpqogevhenj`Ye_[Tg`tn{v{wwshf[ZQKGB=6C=;4G=\R;0<07+6(>.D3C2A1A08:>@DCC@=8917/7/:393:3;3>5A5E6G8.;%K8L==30+108>BJKVU`Ze]eYaLR?D4+8/<7@@DFEJBI?F5;26368<7914-2.44095640.,*/,2.2-=5=4>4<3:58565555757575656422.1*7.:-:+8*3(1&1(1*555342111/1,3,5.;24+;420UVpxcn[gKbEf7b+]1b@hKeRYd8/ZI7SN:UN;[P>VI8M@0MA1=H*CN.K[6Xj@ayGfHhIgFeDcBcEeHgLhOiRjTnPlNhLdJbH_F_H`H_H_H]~I]yH]wH`wKcxOdyP[vA[vAZu@MA1PD4SG7VJ:WK;YM=[O?]QAcWGdXHdXHbVFaUEcWGj^NpdTvqyuxvtsrrsulpbgZa^femltu}ƁЍڕ⚤ȟͦԬٰ۱ڲڵ۳ֲѮ˫Ī¦{|ydbgidhbY\g[[xeauXRe]OHVOaYjcvp}zwuljZUPJD>MGB9F>WO,"2'5'=0E6>-2!8%F4DF9;3262;6<7<6<6;4825.4+5+8+<.>/U;I/=';+=2;56537KRLVOYS]WaU\LSCG5)8-816455584:288<6;9=853cepy\hR_HaGh:e*]/a@hE]AFQ-!UJ8PN9OH5\O>YH8L<-NB2:D)?J*GU2Rd:]sBcEfGeDcBa@aCcFeJfMgPhRlPkOfLcIaG_H_H`I\G]H]~I`|Ka{Ld{Of{Rg|S]xC^yD_zEAC8CE:IF=OH@RGAWI@]M>`O=aQ:aS9`T>_VGaZTfaeljwrowozt~wzurohfa`^^bahgqo|xυڏ㗐흖٣ڥܦݧݦۥڦ٥֣ҢС͞ɗymrvghlc_`e[ZlYUtUPULVKRGZNZP\Smd|t~xyyyabPQEEYV611(5(7&6%8%9':+<.?18+=/?1;-5'4&:.?590907.7+7);)@+C,;3?7DC;<42*,$>5G>QHXO[RYPPGE<)<*6.648;;94:5<4;5:593736225445464717.6,6)9*:(:&9&8%8%7#7#414/4.3.4,5)6(8*:.7/96>BlyasRlGdIj5Y5];e=cPjLVT)":1 9<)EF4RL>PH;BC39E15K4FGHJ#MQ,U\:\jGcuOf}QeNcHbBa>c@eDjIlNmQjIiFgFfFfHfIcIcGdJdIc~Gc~GdFfFe~Dc|BX}8[;^>[K>^M;`O;`Q:^S?^WGa\Vhcinlyrqtnvptppmgfaa]^\\edkjtr}{φَ蘒웗Ҝӝ֞ם֝՜ҝўќ͜ʛǙēwtmtkdkf]`e[YiZSoWMzVJVIUK\RYRXRf_qjvowuufdTSYU2+/%7)7&7%8%9&:*;-=/8,9,:,:,9+9+8+8,;1908.8,8*:(;&;%4-80=5@8A9?7<4915->6H@OGQINFC;7/89"8)4,./*3(7(:+B*B)A&A$@ >=<89$;);-9297;;;94:5;6;5:593736225365464717.5,6)9*:(:&9&9%8%7#7#4-3-4,4*4*5(6)7*c@eDiHkMlPlIjGhGfFfHfIdJdHeKdIcHdHeGeGfEd}C\<_?bB69.:<1??7E@:KB=OE/>/6(/":.7-7,8,9+:)9&8#4*6,8.:0=3@6A7B8;1@6E;FG=@68.6!7&7,3/03,5*9*<'='=%=#;!:87766#8*;1<6=9;;:86:5;6;5:585736226475565616/5,5(9)9)9'8%8%7$7$7$4+4)4*5(6(7&7'8)=12+98lt]nPi=[Jl5\=e4[<`Tq?Oa#(H1+79+-8'18&:;)B=*A<(@>)@B*?GY`4s~Tfwbi~Ub|MaI`C`?a>c@hEjJkMlPnKkHhGgGgIhKfKfJeKeJcHeGfHfGeFcDbBeEhH06*58-;<4A>9G@:KB;RE.?.8(/!6)5)4(6)9+<+=*;(9/9/9/9/:0;1<2=3E;E;B8=3=3A7A7=34#6)5.31/5+6(7)<&9&;&;'<&<%<$:#:!7"7%7-95>:?9:8786:5;6;59585655427376665726/5,5(8*8(9&8&7$7$6#6#6'7(8'9(9(:(:':+;/3.IKo{VjDa=_Ci/[7`=cLlOe0=G >3--3'+8'2=,=B.B@+C;$G="MA'R_*q}Mp|mjW_{J]~E_Ca@b?fCkHlLmQmSoLlIiHhHhJiLhMiMfLdJdGeHfHhIfEeDfFiIlL-3'17-7:3<;6B=9G?UOCZUQa_dhgukklljgbaXVPPQQXY`cfjorux|Ѓֆ׉؊׌،̋ˊ͉ЉшъӉЌϋȍ}xvpScQ\qUT`^RVcOTbH_]DvUBLBRRPWPY\dejljwqvlph~v{~ka?28(;(='='=';':'8(8)8/7.8,9+;+;*:)7(9+7+8,7+7*8*<,>-=0<0<0;/:.8,7+5*@5@5=28.8.;1:06,.$0)2.23/8-9+;+>-?.?0@/@/A.?-?->)9)8*70:6=9=775386:5;6:79585655438485676746/6,5*9*9*9(9&9&8&7$7$9%:&<'=(=(=(>*=.8-;8^eaqPi;\Ai6a/].WIjYq>NX'-?+,730*1)-9-5@/:B+<<"B;VG(iV6vPlwo[aK^F`BcBeBjGoLpPoSoUoLlKiHgGiJiLiNhNfJeIdHfIgIhHgGfFgIiKlN*2%.4*470894<;7B=:HA;KD(>(=(;(;)9)8*3+6-:.:,:)9';)=,>.@2A4=17*4&8)<,:,:,;-;-;-9+6)5(6*;/>2>3?4>37,.#)%-*02290;/>/?0A0@1@2@0=/:-9,8*7/&?'A(A*@,=.71IKgrOdHf7]Am/_1^1XOjWfh39@*,?994443524925>-2<#29ECl`8}RuΗȕ}vbeQ_F`Bc@gDoJrOrRqUpVoLlKhGfFhIiLiNiOgKfJeIfIhIjJiGgEhJkMnP(0#*2'/4-350664<87@<9C>8IE3>0>0@/?.$?%A(@*>-;1:6U\_oGc>b8c6g0c4\CbMaBIL44:97<<>948>58<7379+3="8DS[,PoȈˎ̒Í}{ggQ^E^@c@iDoJsPsSqUoUnMkJgGeEgHhKiNiNfLdIdIgHiJjIiFhEiKlNoQ&.!(0%-2+130333756:97>;6GD=DD*<'8$5#B2OAN@B47)7)>/;+:*8(6'6'6(8*8+;.;/9-5*7,;1<29/7:8=:A8B4A.>,;,:/;19385857483645496;9<69453386;986979899896967465:5:7:7985827/7+8+9+:*;*:*:*:(9(: : =$?%@(@+=.81hCoJrOrRpTnToMkIgFeFfGhKiNiNfKeJdGeHgHhGhGfDjLmOpR(0!'/"(-&+-*.0/333775:94==5?@8DE?JLKQQYVWiZ\s]^|YW[Y^]eennwxڄ䊌솇䂂܀ԂӃҀāǃɄΆ҈Ջ֌ҊNJ~xwpxkeec^XpZMm[Mi\Kf^Kd_IcaHfbGl`FlR;UA^OaYYXPTQ[XbkcYRD<707/;//@/@-=*9'9)0"VJJ?.#=12<07,7->4E;AF8?3:4?2>-;,:2=7@5;687899:98665==<<:<8977767575979899::9;9<9<8<6;5:7:9::9;5907,7+9):):):):);*;)9!>%;#5:$E3@60.^eVgHc;\0X/[5cc?iDnImLlNkQjRjHfDcBcDfGhKgLdJgMhNgKfHeEfEjImJpSrUtW*0")/#).'+-(-/.222553782;<4>@5BC;HJGOPTSUaXYm[[s\Z^]dakjus}Їዋ퍌텄 ڀ~ҀσυƆȇˉ΋ьЍΎɊ{x{stknkd^e\SbaLb`Ke^Kh]Ii\Ij^Hk_Gm_EraG{]C[F[LWPQSPXS`WQKF>9505/908,8*8&8&8&8)7)5,3,2,1'4)9+=-A/@-=*9(9)<.QEH<4(:-:,5&=+=+;*;*:)8)7)6(7*8,7,3)1'1(7.=4BH7>07/:0;.;1<6?6<3632:8EBJFEA?<:9:89796858598988788999:9;9<8=7<5:596888:8:5917-8*:*:*;*;*<+<+<+9"?);$5;'>];2@>/3A05?4E=:X;?T-0X51ZI7bjEu[p||}yr`YuESq?\{B_>b>iCmFlKkMhMhQhFeDcBcDgHiLhNgMiOiMiKgGgGfGjImLnQoRrU-1"-1#,/&,.).0-11/34/45-9;0<>1@B5EH?KMLQRWUTbXWi\Yx^]fcpmzxύᐏ퐎釃~|}ȁ}DžĈƊʌˌˌnj|v{pujpod`i_Ue\MXeK]bKa_Jh[HmZIp[Hq\Go]EtcItZ?V=WDYMTSNTIU@<<984616/6.6+7(6&8&8&8'6)5,3,1,5(6(9)<+@-@-=+8(5'J=E:A57@=C7;AANKZUZURLB>62727474748596;8::7788898;9<8<7<7<38475777:7:48/7,8+:+;+<+<+<+<+<+9$@*9$7$;+2%40OTZiH`8U6V>]FfHfEat?9e?6QA2@C04?.29)>5,O61K*#W:,j\B_t{yv|m\uKHa7Nh9[xB_}?c?hBlEjGhJgLeMeCdCcBeFhIjNkOjNkOkOiMhJgHiHlIpMsVtWvY25$13&02'01+12-23.34.46+9;-;>-?B1DF9IJBNNNRQWTR]XVd\Zoda~nlzwČؑ唑쓏펋扅ڂ{}}Ë}{vzm~sfmoa`k^Vi[NgZJVdJZbJa_JjZJpYIsYJtZIs]FqY?tU9T;ZF\PRNEG:A3/4151505.4+6)8)7$8$8&9'6)5*3,2,8+7)7(:*=->/;-8+3)TK;38.A64'<->-7&8'9(:)8)7)6(3'5*3)2)4,:3>7?9>847596;5;2:397=<@UVc`njidVQA<613/71717182859697::78898;9<8<8<8<8<48686787;7<49/8.9,;,;+<+<+<+;*;*:'@,8&9';-+"54_gSdE];U1B2SE*okHfttqt}l\K_:BV1Lc7Yq?_{@d@iAkDiFgIdJbLcBcBdCgHjMkOmQnRjPjNjLiJgGiGmKqMuYvZx\78(78*66,56056156167/68+;>-=@+@C.DG4IK=NNFQPNSQTVUSYY[a_lkius}Ȍ֕㔐䐍ދӄƁ}|{~zxsznzrfjm_\j[Tk[NjZKjYI^bK_aKe^Kk[KpZLtZKw\Kz[G{WAS=U?XFSFF?76012-3/5/4.2*2'5(9(7$9$:$:'8)7*5,3,>-:)6%8';+=.;.6,80\T=54+A53$:(@-9):*:+:,;-:-8-7-3*1)1+71;7>:;77477;<7=7=69797:::=:=7;2;/9*;*<*<)=)<(<(<(:(=*9':*9-0)AAgrL^E[BYF[N^T]VWSQSU@LN9JG4JE1FD-AA'>C#@G%MU.^g,?=.==1==5=<7;<6;=2;=/?B-@D+CG,GI1KM8NOASPITQLYXDZ[M_^Zgepqo{yƏӏՍъǃ~zzw{uzw|y|~~y|tzrvkqrffm`Zl[QlZNl[KmZKmZIg^Mi]Mi]Mj]Mn]Ms^My^M[I`OWGN@I=@56.0)0*515/4/4-2)3'6&;(9$;$<$<':)9*7,5,A.;(6#5#:)=.;/6->7ZTHA90@36&4 >)7'7'7'7(7)7*7,8-<3:293<7>:=9854196<9::8:>@ORccqpheUP=82+5.;7<::9<3:2:4837365556869697;8<8>7=7=6<8:8;8:;:>:>7<2+>467>O#Jh4gTt\cdfltxpn}\Q`C=J09F,BO3O_;Xi=czDgBkDkDhFeF`G`GfCiFjKlMlOkOmQlRmQmQmPlLkJmJrOuQy]y]x\CB0DB3DB6EB9CC;CC;BB8AD3CG0EH-GJ-JM0OO7RQ?TREURI[\:\\@\]Kaa_ihvrq{z~È{ystpqmolrntqwrwrtoskxrilmb^l_Vj\OlZLn[Lo\Kq\Kq\KrZNq[Nn\Nl_Ol`PqaQy_N[K_SOEA8:25-1(1(5*706/4-3*4(5(6%9#;"<$>$>'<';*9,8,D/<(5!4!9(<.9/5-83NISMB9B5@.2?(;,9+8*6)7+9.;1;3D=A;=;;:8877939584;:JJ\[dcca=9824.81B=E@=;42;3;3928484667777696;6;8<8>7=7=6<686989;9>9>6<1<.8););(;';&;%:'9&?-7%=,:)3'QKkm\fN^I\HWJUSS]RfQjP=Sg{FhClEkDiGcFaG^GiFlImNnOlOjNkOkQpTpSpRoPoNqNvRwUz^z^y]GD3HE6HF9HE613/5/5+7*8)6/4-3,4*6*7'7%7 <">">$?'>'<*:,9,E/='33 8';.9/5./*?;YTI@D7I75D,F7D5A3?2?3B7F9;77464657799>7:473<:IHML=;(%-(5/@9C=A;=8>;?>:2:292849596999:7:6;7<8<8>7=6<7<595878:8<7<4<0:-8(:(;';&:':&:&9%?,4">,:*1&\Xy|T_TbI[DRGOSPbSlS{rSC[C?H3B7%O6"_K0prJiǀyt{qu]oHy}JXy|O\d5:D)3=$4>&WN?XO@YPAZQB\SD]TE]TEcZKbYJbXNcXRg\Zmacsfmwjs|n{~p}ss~p}wjtobli\fcb]a`[a^W_\U_[R^ZOa[ObZMe\Kg\Ji\Ii]Gk\El]Fm]Dm]D_gOkiTqZH{M@RIWLTIWHN:G2?*;(:.7223,17.7.7.8.8.7-6+6+7+7+7+7+8+8+8+8+=.=.8(2!2!;*>/:,6+6-:2B8I>G9;,1!OGIAE=E;H?G@C><:54678:9:7772:3>5KAE;=07)5&8)>.A2;/<2>5=8;97967687>7>7<8:9997:5:35.6/818497989:9:;>9;99<,<*;(:'9&8%F2>//%-(IKkolqWZOPTQVOYP[P]R^V`XMb!:O3JOf xIhrtpakN\lEWdHS\GHN@=C9;<,AB4=?2:=2,:)9,7042226-7.8.8.7-8-7,7+7+7+7+8+8+8+8+9+>/=.9(2 3 :)=.;,:-4*3+;0E:PBRCQAE@@;<6;5>7=89633696879687797=9?:C9?2:,6'5&8)=-@1A4A4@7=8976756686<6<7:89879795:392:3:3;6:8:899999;:=<=?=@;?6<2;-;+<,=+<);(:&8&7%z;)8)5*;5QPce]aMMNLSOYP\R^S^U_V^VSg*Sg(^r3zOlzn`jFau@Sf9IY5FP7?H59?358/;<,AB4=?2:=2;A5:C2@M3Rc?]uCgHqLpJmHkJkLhKmTnToSmQkLjHlHmHpJnJpLsOuTxXxXxZm\bQYH]TE]TE]TE]TE]TE]TE]TE]TE[RC\SD]TE^UF_VG`WHaXIaXIe]He]Jd[Jd[Le[Qf[Uh]Yh\\i]]j^`k_ak__i]]f[YbWU`USYVMWTKTQHRNCQMBSOCWQCXRB^WG^WEaYFc[Fg\Hi^Hk`Jk`J^cOmhUy_PXN[TVQHEE>@7>3<-9*8+9.:/;17-7-7-8.8-7,8,7+7+7+7+8+8+8+9+9+@1>.9(2 3:&=,=.?07+2(3(<0F9M?QB87432052:7>;=<;<8<5:27245697<8=8;-9+6'4%5%8(<+=.D7C6B8=7966455675:6:69797795:3:3:3;4<6<6;8:999889:;<@>A=>7:17+7(;,=+=*<(;(9&8%7$u8%y6%9,E=ROVTOOHHLHSLZO^SbUaW_V]UgxB{UnzzYYp:?R$AS)AQ-?L0:C.6<.690581:;+@A3=?29<1;A59B1@M3Qb>_wEiJsNrLoJmLmNkNpVqUoSnPlKkIlHmIpJpJpLuSxXy[uWqU_NVEOx>aXIaXIaXIaXIaXIaXIaXIaXI_VG`WH`WHaXIbYJcZKd[Ld[Le]Ff^Gf^Ig_Lg^Of\Pf\Rf\Sh]Wh]Wh^Uh^Ug]Se[QdZNdZN]YNZVKVRFRNBPL@PM>RO@UO?WQAYTA[VC^WDaZGd]Jf`JgaKadSleUt]O[Qb\YXDD9:;8:6808-8):*@.C17*7*8+8+8+8*8*8)8)8)8)8)8)9)9)9)A2>.9'4 28"=)@.>/9+6*4*7+;.02614023488;<=?;?6<38/505477764307(6'6&7&7&9':):*A3A4A7?8:78576676:6:68768694:4;492:2:4;7:8989789<:@3B%:F.=F3;A3:=2;<4<=79:*?@2<>19<1:@49B1?L2Pa=`xFjKtOsMqLoNoPmPpTqUpRoPmLlJnJoKqMrNtSyX|]w[mSdJ[LS|DNw?cZKcZKcZKcZKcZKcZKcZKcZKcZKcZKd[Ld[Le\Mf]Nf]Nf]Nf_Eg`Fh`IiaLiaNi`Oh_Ng^OjaRi`Qi`Qh_Nh`Mh`Mh`KiaLb_P^[LYVGTQBPM>NKTQ>VS@YVC\YF^[H^]I`aSf^QmWJ[Rhcb`LM@C:<7974709+>)D+H-7)7)8*9+9+9*9*8)8)8)8)9)9)9)9)9)A2>.:(7"57 >&B-<*;*:,8-8.:.<0>25<3:2736464646155:39385:8:662/,(9(:(:(:(:(:(9&7&:+<-?3?7=8:68687566666748493:3;3:2;2=5=9=:><=;==A6:;3::29:*>?1;=08;09?38A0>K1Pa=ayGkLuPtNrMqPqRoRrSrSrQpOmKmIpLrOtQvSxY{^z_qVdJY?]NVGQzBe\Me\Me\Me\Me\Me\Me\Me\Me\Mf]Nf]Nf]Ng^Og^Oh_Ph_Pg`Fh`IiaJjbMjbMjbOjbOjbOjbOiaNh`Kh`Ih`IhaGibHjcGe`Mb]J^XHXRBSM=MJ9KH7IH6KJ8LK9LM;NO=PQ?QTASVESVEYYM]WKcQEzXNhaeaUUOR=C8>6762:.@+E*I*7(7(8)9*9*9*9*8)8)9)9)9)9)9)9):)@4=/<+:$76<#B*C.@/;,7*2(4+:2@81<2<5=8>:>;>:=9<485:8<;>;<861--'<+=,>*>*=)<(:'8%6%7);.=3<5;7;8;77575758494;4;4=4>5?7A:A;A>A?????B:@8<38-5(5'8(<*;*<)<(:&9'7%6$5#y<)r3!}:*OAYLRGOEVJZN[M[M[O\Q^T`Ya[s}Xy`r|ZU`B9F,/;'0;+1;03=44;35<4:?8?B9?A6<<277+89)>?1:27@/=J0O`HO?HO?PPDVRGYOChREYMULRLXWGJ:A?CBCAC@A>?1256::<;;7734.3+>+>+>+?,>+>(<';'7$7'8+8.8.92<7?;85858494:4;4=4>4A7C9C3:/8+6(7'8):);(=)=*<):'9&7&6%~5$v4$x5%B2UEXKQCPDZLZM[N]O\Q\R\U[V\W`hCX_=JS4>G,6?*2=-4>35?74=88>:=B/;9*78(=>0:26?.=J0N_;`xFkLuPuOsNrQrSpSqMrNqMpLoKrNuRyX`~az]qUfL_G[E\HbRYISzCh_Ph_Ph_Ph_Ph_Ph_Ph_Ph_Pg^Oh_Ph_Ph_Ph_Ph_Pi`Qi`QmcWlbVjaRi`Qh_Pg^Og^Mh_NiaNiaLiaLiaJh`IhaGhaGhaGh`Kg_Je_Ib[H\WCUR?PM:ML:EF4DG6DH7BI9BI9BJ;BJ;BJ;JJ@QQERPAUNYSQOCE8:55:3>/>)<$8'8'9(;*;*;*;*;*:):):):):):):):)=2:.<,>+9#59@':$<)?0;18.7/<5A;;B>FBGCE@?;7501.0,51:5<6:29.9,9,>+>+?,@-@-A+>*=*<(:(7(5)4*80?8D>:5:5;4;4<4=4?4@5C9D:C;A9?:;685739-7*5'6':)<*:)9&=*=+=*<)~:'|7'{6&{6&y1#8*G8REPBK?SE_SXKZN\R]T\V[VYTXSV^7EM(6@8A&>G27@E>GJ?GI;BC1?>);;#78(=>09;.69.8>26?.E5>F7?G8=H8AE4HK6YS;_F0K9j]f`SSDE@@?==5=0>/3$5&6'7(7(8);,=.<-<-<-<-;,;,;,;,3,7.;-;)8"78:"B-<+7)4*6/<7C?HCBGDHCC:661808.5+:/9.8.8-9,:+<+>-=*=*>+?,@-A.B-@-<*:(7(6)6+8-;1=4:4<6?6@7A7A6@4@5G=E;A6;26.3-1,1+;-:,:+:*:);)<+=+~:'|9(|9({:({:(z9'x6&w4$z, A4NCMAL>REVHRG\R\RUMTLZUXSWR`^R[0IQ(AK&BK,>H/7@-2=-4>34;3HPEX^RW[LLO?1;=0:=29?34=,;H.Pa=bzHlMuPsMqLpOrSqTpJqKrLrNsPvU{\bfx^iO_G]G`JfOhRdU[LTyEi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qj^^j_]j_]j_[j_Yj`Wj`Vj`Vj`TjaRjaRjaRjaRjaRjaRjaRj_Kh`Kg_Jg_Jd]J^YEUR?ONE5?E7>F7>F7=E6BF8>E5=F1DN5HK0PB'yS>@=>982:+<-=.<.;-:,9+9+:,:,:,:,:,:,:,:,?9A:A7=/6#2235#7(;0A8E?IDJFJGBCEDC@;59/>1A1?.@1@0>0?/?-?.A.B.;*;*<+=,?+?+?,>+@.=-:,9*8+8-:0:190;2>5A7C7D7D9E8B6A4=1:08-5.5,5.=,=,;,;+:*;*<,=,~;*|;)y:)y:)x9(w8'u6't5&1)C9NCK?J>PDTIRGSJWQUOUR\XWTSO\XT]0Zc8_j@[eBIT66C)4@*0:-;H.Pa=c{IlMuPtNqLqPrSqTqKpLpJqMtQxW|_c{aoUcJ]FaJeNeNcLdU[LTyEi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qj^`j^`j^^j_]j_[j_Yj`Wj`Vj`Vj`Tj`Tj`Tj`Tj`Vj`Vj`VlaMk`LiaLiaNf_La\I[VCTQ@ML:HI9DG6AE6AE6?E7>D6=C5=F57@-?H3EM5AA%QA']Eu`WHbZebRSEFFHBD799+:,:,:,:,8+6)6)8+7+7+7+7+8,8,7,3/5/5-3(0"01 4$A2C7G?KFLGJFFBC?CCDA@:;1=/C1F4G3E3E2C2B0B0B/{B.xD.8*9+:);*<+<+=,<*?.=-;+9*8+9-:/;/7.90;0>3?3@4@3A4:,:,9+7+7+7,8.91=-<,<+;,:+;+<+<,};+z;*z;,w9*v8)u7(t6's5&91FMKB3;I27C-EJ3IG0K<%mN9dO`NA5SLc_^^RUJMDH>C;/9-7+7+9-:/;0;0>4>4>4>4?5?5?5?5?=B>D>F=GN@PDSJOGLGIEFCC?A=@.D2H3J6G4F3D3C1B0zA.wC.uB/8+9+9+:,:,;-;+;+:+:)8)8*9,<-=/>09/8.9/:.:.:,9+8*7)7*7(6*7+8-9/;0=.<-;,9*:+~9*}:*};-|:,z;,y;,w9,s8*q6(q7)q7)B8G=K?HB'=A&;>#78(:;-79,9<1;A57@/MKH/JH1Q?+e>-ZL`S>64+@9XUigdeRUINKQJ@F<@6>4@6D:G=G>JAJAJBJBKCJCKDKDRTSTTPSMSLSLTNUNLHHFEBB@B@B@EBEBJHD@>7>2A2C1F3I6F3D3C3@0@1}?0y@/x@19.9.:.:.;/;-;-;-9*9*9+9,:+;-<.=/;/:/9-:.9,8*8*8*8)8)8(8)9*:,:-;-;-:,9+~9*}8)}7+|8+{9+z8*y9-x:-t9+q5*o5)q7+r:-G;HJY.AR&IZ0Wi?dvLj|TXjDL\8?M,:D)C-=@-:=*89):;-68+8;0H-NC-b=-D:VPMJ++:9=;TPpnwvehY^]cVOOHG@CA=JIB@<6>3@3A2B0D3A2@2>1=1<2<1=1}=1:3;3;1;1<1<1=/=/=/.9)9*:*;+;,;+;,;+:,9+7)~6*{5){5)z6)z6+x6*x8,w9.s7,o5)o5)r:-u=0L>K>JG*SA+{E9NLEH5<19@E?@JIb`rpopbeZ^RJLDD=B;D=E>CC?C?D@EAEA?D@DDFFHIHJIIIFHACADAEACAA@>>:=8EG=<73;4@4?1>0A1=/<0;1928193:4;4:4:4<3<3<3}=3}=3|<0{=0{=0{=.{<-z;,y:+z8*z8*:0:.:-:.:.;.<.=-9):):*;*;+;,<+}<*8,8,~6*}5)|4(z4(z4*y5*u3'v6,v8-r6+n4(n5*s:/v@4PBN?N=R@VFXIUJRINIRPSO\VfZl\LML7BL3@O.KZ9WgC`rJezOdzLVl=G]/AV+7I#0A!5C*=F5QJ:MG7IC3GA13M*>G*[B.PGVV7?'3BN:C9>;:HG][gf[]ILJDF@C=C>GBGBB>=9C?B?C@DADBECECFD>C?DBEEGGGFFBC=AAD>C;A<>>>A?D@FA@C7830:4?4>1=/?2;.9.8061717384:5:3:3:3~;3|<3|<2{=2{=2u9.v;-w<.w<.x=-x=-y;,y;,{;1};/~8,7*6)5'6(5&7(8(:);)<+<,~=+{<*8,7+~6*|4(|4({2)y3)y5*t1(u5+v8-r6+n4)n5*t;0xB6TEQ@P>UBYHYISGNGSNRPPKVObUeZHFK4;K0IX;[jKgxVewQYnCSi;Me5I`28M"-B*;2@):E7;B;8<;7;<<=-<=/79,9<1=C77@/6C)DU1Rj8_{@mHpJqLrQtUrUqQtVuYsYmSdN\HZDdNaJ`HcIfJiIeDa>`PWyGPr@i`Qi`Qi`QjaRjaRkbSkbSkbSjaRjaRjaRjaRjaRjaRjaRjaRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlcTo\Nq_QtdUrdWnbTj`Th`ShbTgaSebQa^K[VBVQ;TN6NH.GA'RD)N=#cI2iVzmng[WPQBE@E@GBFDGEIGIGIBEBEBDEEDBC;D:H;F7H9H:G?EBBD?F=EBDBDBDDEDEEDEDEDDAC@B?@>?=?=?=@>E??8:280:0>4@3?2A4|@5}?4<3:3837372<-<-<-;,;-:,:,:,9-9-9-~:/~:/~:/~:/~:/~80~80}90}90}90}90|90|90|90|90z:0y9/y9/x8.w9.w9.w8/w8/v7.t8.s7-r6,q5+p6+l2'q7,m4)l3(o6+m4)q8-H=ULTLQKPJNJNLNMPLSMUK\NdOkaFTW8JX5N_;gT`zMWpFTkARg@O`0CA4B@4@<12:/2:/4:.5;-9=.A,>D*T^4E9F9G=G>GDCEAE?GCDCDCDDEDEFDFDFDEAC@B?A>A=A=@=A>FAB<=6:090;/=0=0A4|@5}?4<3:3917172<-<-;,;,;-:,:,:,9-9-9-~:/~:/~:/~:/~:/}90}90}90}90}90}90|90|90|90z:0z:0y9/y9/x:/w9.w9.w8/w8/t8.s7-r6,r6,p6+p6+k1&q7,m4)l3(o6+l3(p7,~H2><03;03;05;/6<09=/A,>D*Q[9^mDmPpRrSqRsSsRxa|exakT`I]F]F\E`IaJcLeNdMbK`I^G]MRtBIk9i`Qi`Qi`QjaRjaRkbSkbSkbSjaRjaRjaRjaRjaRjaRjaRjaRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlcTtbTo_Pm]Pm_ToeYog\keYhbVfbVpl`{xi~{jzgzuapiVf`JPVG@GCFFEFDGCDCDCDCDDEECECECDBE@D?C>C=C=B=B=F@E=C:>5:/8-9,<-A2~@3}?2=1:1918180<-;,;,;,:,:,:,:.9-9-9-~:/~:/~:/~:/~:/}90}90}90}90|90{8/{8/{8/{;1{;1z:0y;0x:/x:/x:/x:/t8.t8.s7-s7-r6,q5+o5*o5*k1&o6+m4)k2'n5*i3'm7+}G;QIPIQJQLRMRNTPUPVO[P^OtbNoiQnrWjwYfwWPf@K_:EY6BV3EV6GV7FU8ER8?I1*7;*:<.<>0<=/:;-5<45<46<26<09=/<>0=@-=C)MV7Zi@h|KlNpOqRuStSzcw`nWcL\E\E\EZC_HaJbKdMcLaJ_H]F[}KPr@Gi7i`Qi`Qi`QjaRjaRkbSkbSkbSjaRjaRjaRjaRjaRjaRjaRjaRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlcTtdWqaTm_Rk_SkaWlcZle[jf]jf]wuiy|rygZfNLV>AI2CF1ED0D?,I=-TD5M:+O8*R6*T7)X8+];/a?3eA5KASLUQNKEDABCCEF?>@=B>D@EAFDEDEDCDCDDDDDDDEDEBGCFBE?E>E>D=D=E=E=C@8;/8,9+;.@2@1~?0=/;/:/9/90;,;,;-:,:,:,9+9-9-9-~:/~:/~:/~:/~:/~:/}90|90|90{8/{8/{8/y9/x8.{;1y;0y;0y;0x:/x:/v:/v:/s7-s7-s7-r6,p6+o5*o5*n4)j1&o6+l3(h2&k5)h2&l6*|F:OGPHQIRMSNUPWPYQ]RaUy_PiZGd_IciOZgKN]@EU8AQ4=M0G2:A/7>,9=,9=.8<-7;,6=66=66;46<29<1;=/dxGjLpOsTwUwT{dr[eN\EZC\E\EZC_H`IaJbKaJ`I^G]FY{INp>Ef7i`Qi`Qi`QjaRjaRkbSkbSkbSjaRjaRjaRjaRjaRjaRjaRjaRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlcTseXugZsg[mcYjaXle]snhzwp~wv~i`hSLSADK9AJ7>G4>G4BI7GNB?@AAC@EAEAEAEADFDFDFDDEDEDEDEAFBFAF>E=F=F=F=G>@9B;D=B9>3:-;.=/?0?/~?0=/<-:-:-:.;-;-:,:,:,9+9-9-9-~:/~:/~:/~:/}:1}:1}:1|90|90|90{8/y9/x8.x8.v8-y;0y;0x:/v:/v:/u9.u9.u9.s7/r6.q6.p5-o4,n3+m4+m4+j1(o6-j4*h2(j4*g1'k5+zF;MGNHPJSLUOWPZPZQ{YMv\OkZJ]UBYXDY^HOYA>L3;G18D.5A+5A+8D.=I3AM7EN;BK8?H5.5<,4;+5;75<56;56;48;2:-;@)GP1Ra:buGiKqPuVyWxUzcnW`IZ}C[~D^G^G]F`IaJbKbKaJ`I_H^GW{KLp@Bf6haQhaQhaQibRibRjcSjcSjcSibRibRibRibRibRibRibRibRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlcTmaUndXpf\lcZkd\rmg|ľtfcTPQAEI8=F38E18G45F35F44E36D58D6;E:?G<@H=<6(L0=/=.>/?/>.=-<-;,;,;-:,:,:,:,9+9-9-~8,~:/~:/~:/~:/}:1}:1}:1}:1z:1z:1y90y90x8/v7.v7.v7.u9/u9/u9/s9.s9.s9.r8-r8-q6.q6.p5-o4,n3+m4+l3*l3*h2(l6,i3)f2'h4)e1&i5*xD9KEMFPJTLVOXNYO|\Os\Nk[L_XFUTBPS@JQ?@I64@,3<+2;*09(09(2;*5>-9B1-;@*CL/O^7_rDiMrSwXyWvUs\fOZ}CX{A\E]F]F^G`I`I`I`I`I_H^G]FVzLJn@Ae7haQhaQhaQibRibRjcSjcSjcSibRibRibRibRibRibRibRibRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlcTiaVjbWkdZmf^upjҺzym__YIKL:>F19E1>2J91`94HH\__dVZOSMOLKJJHEFBDAA?DFDFDFCECEBBCBCBDCD@E?F?F8?:B9C:C8A4<-9)>->.>-=,=,<,;,<-:,:,:,9+9-9-~8,}9.~:/~:/~:/}:1}:1}:1}:1}:1y:1y:1x90x90w8/t8.s7-s7-s9.s9.r8-r8-q8-p7,p7,p7,p5-o6-n5,n5,m4+l3*i3)i3)g1'k7,h4)e1&h4)d0%f4)uC8JELHPJTLWNYOx[Mp]Nj^N]WGPQAKN=CJ:9B12:+08)36-17-06,/5+/5)17+2:-4<-9D4;F6=H7*0640641622716929;0:<.:?)?H+KY5]pChLsTwYwWrQiT^IUx@WzB[~F[~F[~F]H_J_J_J_J^I^I]H]HUvKJk@@a6haQhaQhaQibRibRjcSjcSjcSibRibRibRibRibRibRibRibRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlcToh^ng_lh_tqjũsbaZGML7CH2AI4AH6BF7BD7C@9D<9C98C772?5;@9@93H/+c76QRgimm[\YWUSQNKKGFBB@ACGDFDFBEBEADBBBBDCCBC?C>E>E>F-=,=,<,<*=+:,:,:.9-9-~8,}9.}9.~:/~:/}:1}:1}:1}:1}:1{;2w;1w;1v:0u9/t8.s9.r8-q7,r8-q8-p7,p7,n8,m7+m7+m7+o6-o6-n5,m4+j4*j4*i3)h4)f2'k7,h4)c1&e3(b0%e3(uC8JGNIQJTMXOzZMq[Mh\LXUDHK:=D4=E69A208+/7*5=056157257247005.06,08-19,6A3:E5=J9>K9;J77F12A,0?*.42.420511605818:/:<.:?+WzB[~FY|DY|D\G_J_J^I^I^I]H]H]HSsJHh?>^5icSicSicSicSicSicSicSicSicSicSicSicSicSicSicSicSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUmdUmdUmdUmdUmdUmdUfc\gd]vsnȷɴicbFGG-EG/DF0GD3IC5H;3F42G34M797@;;@:@;8G85cGFkjŔ譩ҋtn]XSNNNIKEICGFHHKCF:>>@FIDG:;@@@@A@B>C>B.>/?.>-=,<+=*=*9-9-9-~8,~8,|8-|8-|8-}9.|90|90|90z:1z:1z:1z:1x=5w<4v;3u:2t91r7/p7.p7.o6-m7-m7-m7-m7-l8-l8-l8-i2+m6/p92o81k4-g2*g2*h3+e0(i7.d2)^,#`0&_/%b2(p@6LJOKQJQJ}YMv_QfYIRO>CF5=F58C35@02=/3;04:04:077577566446135016/05..6+.9+2=/6C29H5:I68G42D./A+,20,2.-2..3-36/780:&DR1YkChRu[w_rWjN\}HXyDTu@Tu@WxCZ{F[|GZ{F^JbNbN^J\}H_K`L^JTrNFd@:X4icSicSicSicSicSicSicSicSicSicSicSicSicSicSicSicSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUmdUmdUmdUmdUmdUmdUed_onjͱcgkJMP1II/EC,HA/J>2L93M85Q99;;9BA?MHE\RQyjg̳ǿ괪̃|c\VTPSFM=DEEEEGHIKEG<><>@C>???@@A@B>B=A/>.>-=,<+=,<,9-9-9-~8,}9.|8-|8-|8-|90|90|90z:1z:1{;2{;2{;2v=4u<3t;2s:1r90p7.m7-m7-m7-l8-l8-l8-l8-j8-j8-j8-l5.n70n91n91l7/i4,g2*e3*c1(e3*_/%^.$b2(^.$`0&n?5IEQLWRWOrVKdRDQJ:>?/:A16A14A02>02<14<15;17:388677577557446116005./7,.8-1<.4A07E49H58G44E22D.062.40.3--2,14-45-8:-9=,7?'DQ3YkEhSv`wbpYfNZzHWwETtBTtBVvDYyGYyGYyG[{I_M_M\|J[{I^~L^~L\|JTmOF_A9R4icSicSicSicSicSicSicSicSicSicSicSicSicSicSicSicSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUmdUmdUmdUneVneVneVddby{xشĝj`hCRW7DG,EC.KD4MC9N?8L=8C:;SJKi`axv画ecACBINVVRLIDABAFEEFCDBD=?>>??@?A@A=B=A/>.=-<+=,=,9-9-9-}9.}9.|8-|8-{8/}:1}:1{;2{;2{;2{;2{;2{;2t;2s:1p:0o9/n8.m7-k7,k7,l8-l8-j8-j8-j8-j8-i9-i9-n91m80m80m80m80i7.f4+c1(c3)a1']-#_0&c4*\-#_0&sD:OKUPXQqSK^J?OC7?<-37(2:+/<+0<.2=/4<15;17:37:388688668557257227016/08-.8-0;-2?.6C27E48G48G48G46=53:2/4-,1*.1(13(57*6:)6>'DQ5[lHkZyfwflX^KWwEUuCRr@Rr@TtBVvDWwEWwEXxF[{I]}K[{I[{I]}K\|JXxFPfOAW@3I2icSicSicSicSicSicSicSicSicSicSicSicSicSicSicSicSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUmdUneVneVneVneVofWgkl۲™}cdnKLS4EI0HJ5KI:GE9D@7QEEk__莎bd>CPITMOJF@FBMJJI??>>>??>@?A?B?B?C?>8?:C=E?E>B9=5;2<1=0=1=0=-~<,=-=-~:/~:/~:/}9.}9.|8-{8/{8/~;2|<3|<3{;2{;2z;4z;4z;4p:0o9/o9/m9.l8-k7,j6+h6+i7,i7,h8,h8,h8,h8,h8,h8,o:4j81h6/i70j81j81e4-a0)e4-b1*].&a2*b3+Y*"_3*zNE~]XvWRiNGWC:J<3@:.:;-8<.08)/:,1<.2=/5=25;169078079468368349338138119.19..9+/:,1<.2?.5B18E4:I6;J7;C87?428.-3)-0%/1&24'48)4<'ER8_pPrd}nwifXT}EUrBTqASp@Sp@TqAUrBVsCVsCWtD[xH]zJ\yI^{K_|L\yIVsCK\JD8f\Z|z즤ifK=QDYN[QQHD=A@?B>C?C?C?C?>9@5<4<3=2=1=0=/~<.=/Qn>Qn>Qn>Qn>Qn>Sp@Sp@WtD[xH]zJ]zJ_|L_|LZwGQn>ESF6D7(6)gdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUneVneVofWpgXpgXpgXinrz׹ĥregOMP;EL:EM>EODGSG~zqƽߑ}fSK:UFWKF;@8KEC>C?B?C@C>D>D>C=@6:6-85,99/8:/47,36+4:.5;/5;/69.69.68-57,46+19,19,19,19,19,19,19,19,08+.9+.9+/:*0;+3>.6A17B2gw]umvnf_RwKAh;Mj:Nk;Pm=Pm=Nk;Nk;OlVsCZwG]zJ^{K_|L_|LVsCLi9=H@/:2#.&gdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUneVneVofWpgXqhYqhYcjpmtzƯ}vn[ZWFOQCQWKYcZbmeq[WDSCQBMAJAG@E?E@E@E>D=Ce9Jg9Li;Nk=Nk=Li;Li;Mj
    UrDYvH[xJ]zL^{M\yKQn@Eb47@;+4/!*%gdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUneVofWpgXpgXqhYriZhowmt|ʹƯsce]P[YM_bYovo|Ȱ}gO=Q@RDC8IAH@F@F@E=D6qB:n?7pD;g;2g;2SJaXTKpE<6=52913:27<5492/5+25,9<345-35*24)13(13(35(46)57*,7',7'-8(-8(-8(-8(-8(/7(19*08)08+/7*/7*/7*08+08+7@+9B-=D2=D2=A29;-35'/3$3:*JVBcr[f}a\wVLnICgA=c:He7Kh:Nk=Nk=Kh:Jg9Li;Nk=TqCWtFZwI[xJ]zLZwINk=A^05;9*0.!'%heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheTheVhdYkd\kd\md]meZmfVg`MjeOnlWnl]ff^eeeqqyֵymvW\fK`lTq~lЪa\D=MEKBC:A7D:H>JAI>G>J2K4L5K4H2F2E3E5D5C6@4>3;29/7/6-~:1~:1}90|8/{7.z7.y6-x5,w7-w7-x8.x8.v8-u7,s5*q3(h91h91h91g80h70g6/g6/g6/f5.h6/i70j81i70h6/f4-g2,k1-k4/n70m80k9.j:.i>.iB1dC2gJ8aJ8raOyn\|jqOL;4:04:04:039/39/39/28.28.17-17-17-06,06,/5+/5+/5+/4./4./4./4./4./4./4./4.05//4./4..3-.3-/4./4.05/0;32=55A77C98D86B64@22?.3@.DQ=WeN\jSSaHHV=DR8FT:Ic>Ke@Ke@Ke>JeOjAUpGYtK\vO]wR]wTWpPHaC8Q3).2&+/$)-heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheTheVhdYkd\kd\md]meZmfVjcPlgQmkVlj[gg_lll~~ЯvkrSYaI_kUto}uJ@K@JJ>D9=2?6D;H3J7M9J7G5C4D6F7C7C8A7>5<4:19181}:2}:2|91z:1y90x8/w7.v7.u6-v7.t8.t8.t8.r6,p4*o3)i81i81i81h70h70h70g6/g6/e3,e3,g5.h6/j81j81j81k92k60l71m80l:1k;/l>1j@0iD2hG6kP=gR?ufSvdsrML:4:039/39/39/28.28.28.17-17-17-17-06,06,/5+/5+/5+/4./4./4./4./4./4./4./4.05//4..3-.3-.3-.3-/4.05/-80/:21=34@66B66B66B45B16C1CPAO6BP7FT:Ic@Jd?Ke@Ke>Ic3L/).2',0$)-heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheTheVhdYkd\kd\md]meZmfVmhTmhRmkVjk[jkcvxwۿʫyuy^kpZt{iٞL=Q@K;>1G9XMTJ?6D6H9J=I=B7?5A7E=A9A9@:>8~>5<4<4;4x<2x<2w;1w;1v:0u9/t:/t:/s9.r9.r9.r9.q8-n8,l6*k5)j81j81j81j81i70i70i70h6/g5.g5.g5.g6/h70i81k:3k:3l;4k:3i:0j;1k?2lB4iD2fE2fI7lVAjYEviVl{mEF439/28.28.28.17-17-17-06,17-17-17-06,06,/5+/5+/5+/4./4./4./4./4./4./4./4./4./4..3--2,-2,.3-/4./4.*5-+6.-9//;12>24@46B47D38E3?L:ER>CQ:;I28F->L3ES:H`>Jb@LdBKc?Ia=G`9F_8G`9RkDXpL]uS^vVZqTPgK=T8,C)).2',0%*.heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheTheVjcYkd\kd\md]meZmfVniUljSlkVlm]pqiؼǫ}ſınQ>P=XHL?D7G<>4D;H?F>?9;6=8A>?;@<@<}@;z?9y@9x?8v?8v=4v=4v=4u<3s=3r<2r<2q;1o;0o;0o;0l:/k9.j8-j8-i7,n72n72m61l71l71k60i70i70l:3j92h70g6/f7/f7/h91h91j?6f>4e=1f>2hC3iE5gF3cG2cJ6hV@k\GskVnzor_9>*28.28.17-17-17-06,06,06,17-17-17-06,06,/5+/5+/5+.3-.3-.3-.3-.3-.3-.3-.3-.3-.3--2,-2,-2,-2,.3-.3-)4,)4,*6,+7-.:01=14@25A36C2:G5=7A;D?C?<;989:====>>@?|A=xA6s>6s>6r=5p>5p>5p>5n>4n>4m=3l<2j;1j;1i:0i:0i:0p62p62p62o51m61m61k60i70l;4k:3h91e90e90e90e:1f;2dB6cA5cC4dD5fG5eH6cH3_I2^L6eV?jbKrmWnr[`L3;&28.28.17-17-17-06,06,06,17-17-17-06,06,/5+/5+/5+.3-.3-.3-.3-.3-.3-.3-.3--2,-2,,1+,1+,1+,1+-2,-2,,6.+5-*4,*4++5,.8-0:/2=/2=-5@06A05A-1=)1=)5A+9E/=O5AS9FY=I\@J]?J]=K^>L_?TgG\oQcvZbtZYkSK]G6G4$5"&+.$),"'*heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheTheVjcYkd\lc\md]meZlfVlgSljSlnXorasvmθͺƶø̧lXZGVCM;A8BD??>;;99:;<<>??=}@=wB7o>7n?7o@8n?7m>6i=4h<3h<3h<3i=4r73q62q62p62o51m61l71j81h70g80e90e:1d<2f>4f@5gA6]C4aG8cL:dM;cM8`K6]K3]M4]Q9`Y?miPss[mt|eFO:2>(39/28.28.28.17-17-17-06,17-17-17-06,06,/5+/5+/5+-2,-2,-2,-2,-2,-2,-2,-2,-2,,1++0*+0*+0*+0*,1+-2,,6.,6.*4,*4+*4++5*-7,.9+-8*0;+4?/5@/4?.3>-3?+4@,7F/;J3@P6DT:GWH=H>G@F@C@=:97<;=;>;A5i=4j>5j>5k?6s63r73q62p62n72l71j81i81d8/d90c;1d>3d@4cA5cA5bB5VG4^OmmSsw^zjcmU2>(5C,4:039/39/39/28.28.28.17-17-17-17-06,06,/5+/5+/5+-2,-2,-2,-2,-2,-2,-2,-2,,1+,1++0**/)*/)+0*,1+,1++5-+5-*4,*4,+5,+5,,6+-7,,7)/:,2=/6A17B27B25@/4?.2?+5B.:G3>L5AO6ES:JX?M[BTbI]kTcqZ_lXUbPERA2>0#/#(..&,,$**heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVjdTjdVjcYkd\lc\md]lfZlfVomXmmUimVgkZembr{x׭sYSAQ?N>O?OBJ@C:<4<7>8?6@7{B7tD6qE8nG8s>:s>:s>:q>:q>:q>:q>:p?:sB=rA8l=7l=7m>8n?9r73r73q73n72m82j81i81f:1f;2d>3d@4bB5`C5]A3\@2[?1QI4[S>f^Gg_H`Y?ZS9ZS7\W:ZV;WW;knSrx^u}eUaI%37E.4:04:04:039/39/39/28.28.17-17-17-06,06,/5+/5+/5+-2,-2,-2,-2,-2,-2,-2,-2,,1++0*+0**/)*/)+0*+0*,1+)3+)3+*4,+5-+5,,6--7.-7,,6+.8-2=/6A39D69D67B46A1/<*2?-5B09F2:u@:s@9o>9o>9n72n72n93m;4l;4j;3g<3d<2c?3^>1dG9cG9T=-O8(M8'D/TR;PN7KI0MK2]Y>ieJeaDVU7XX<]`CosXzfcmT=I1,:#1?(5;15;14:04:04:039/39/39/39/39/39/28.17-17-17-06,16016005/05//4./4./4./4.,1+,1+,1+,1+,1+,1++0*+0*.5.-4--4-,3,-4--4-.5-.5-+2*-4,08-5=29A6=E:?G7B25@03>-1<+2>*9E/BN8IU?O[EVbN]hWYdTLWIF5F4D4D2}B0yB.s@-o?+v?:t=8u>9v?:t?9q<6r=7sA:q?8q?8q?8o>7o>7n=6n=6n=6l;4m<5m>6k?6j?6h@6eA5cA5dG9[A2^G7\I8N=+F7$G8%A4!IM4GK2DG,BE*MM1[[?abC`aBYY=dgJsw\sy_X`H8D,/;%6D-7=36<26<26<25;15;15;15;15;15;15;14:04:039/39/39/27127127116016016005/05/.3-.3--2,-2,,1+,1++0*+0**1**1*)0))0))0)*1*+2+,3,.5--4,.5-07/4;39@8?F>BIA:G69F56C13@.2?+5B.;I2?M6KXDR_KXeSVcRKWI8p;5q<6vA;sA:p>7r@9xG@n=6n=6n=6m>6l=5l=5l=5l=5g?5h@6gA6gC7eC7cC6`C5^D5aL;UB1ZI7`S@RG3C;&E=(GA+>G,BH.@F*<@%?B%LO2_`AijKaaEnqTvz_gmSHP84<%4=(=F18>48>48>48>47=37=37=36<28>48>47=37=37=36<26<26<25:449349349338238238227105/05//4..3--2,,1++0*+0*(/((/((/((/((/()0)*1*+2+070.5.+2++2+.5.5<5K:4-9/-3/-3/,2.gdUgdUheVheVheVheVifWifWifWifWifWifWifWifWifWifWleUldWlcZmd]md]mf^mg[khWmlWimThpXht`hthm|wڻּҽzyS3i?3i?3i?3f>2f>2f>2f>2aA4`C5`C5_C5^D5[D4ZE4VE3XI6OB/\T?oiSc^HMK4IG0LJ3;E*?H->G*48>47=37=37=39?58>48>48>48>48>48>48>47<67<67<66;56;56;55:45:438238216005//4.-2,,1+,1++0,+0,*/+*/++0,,1--2.-2.051.3/+0,+0,-2.2738=9'4.:0.5..5.-4-gdUgdUgdUheVheVifWifWifWifWifWifWifWifWifWifWifWleUldWlcZmd]md]mf^mg[khWkmWjnUiqYgs_drejytܽչѷѾӾϴu`yVBlI5mH6rM;uP>mF7iB3gB2jE5nI9oJ:pK;oK;eA1eA1cB1cB1cB1cB1cB1bC1\G6\G6\G6ZG6YH6WH5TG4RG3PH3MH2fdM~~fprZVX@IM4HL3;E*A.;>+9?59?59?58>48>47=37=37=38>48>48>48>48>48>48>48>49>89>89>88=78=78=77<67<66;55:449338227105//4./4.-2.-2.,1-+0,+0,,1--2.-2.,1-,1-,1-,1-.21043376598:H7=L9@O<@O:8F91?2,9/.5.-4-,3,fcTfcTgdUheVheVifWjgXjgXifWifWifWifWifWifWifWifWleUldWlcZmd]md]mf^mg[khWkmWioUiqYgs_bpcgxrڻѵ˴˺ӿһurd|]I}^JrVAaE0W;&Y=(Z?*X=(`E0`E0_F0_F0`G1`G1^H1^H1[L9ZM:ZM:XM9XM9UM8RL6QL6NL5QQ9ikS|glrXSY?DM2>G,:G+48>48>48>47=37=38>48>48>48>49?59?5:?9:?9:?9:?99>89>89>88=78=78=77<66;55:4493382382/40.3/-2.,1-+0,+0,+0,+0,+/.,0/-10.21/32/32/32.210A.5F3;M7>P:=O7:L47I/6H.3E-6H0:L6MJ9EB1;A7;A7;A7;A7:@6:@6:@69?58>48>48>49?59?5:@6:@6:@6;@:;@:;@::?9:?99>89>89>8:?9:?99>89>88=78=77<67<6495273162/40-2.,1-+0,+/.,0/,0/-10.21.21.23-12,01):'/@-6H2;M5=O7?I.9F*?L0=J.AN2DN3HQ4LR6IN0JM0ZY;miLhdIc]C_YA_ZD`[GZUBQN=LI8=C9=C9=C989>89>8;@:;@:;@:;@::?9:?9:?9:?99>:8=95:6384162/40.3/.21.21.21-10-12,01,01-12-12$5"*<&3E/9K3XW9UT6SR3KE/JD.FA-D?,A>/@>1??3>@5<=5;>59?59A67B48C57C57D3:B79A69A68@58@59A69A6:B7:B7:B79A6:B7;C8F;7B:7C97A66A16?.4<-39-270.5./51-7/-9+-<%.B3J7O7Z 8Y$8W+:U2:R8;P==O?>O=:L6@R8EX:EZ;DY:>U93J0(>'.5-,3++2*ZgM[hN\hP_iQakSckTglXhkXghVihVifWifWkeWmeXmeZnf[khWkhYkg[kg^jf]jf]hfZgeVgjWglVfoZerajwnz̹˾NjlRM0TM0QK+SJ+WN/UO/UN1TO1SO2QP4QP4PP6QM2PO3PN5PP6MO7KO6HM6EM5HQ6EN3BK.AH)BI(GM+JP,KQ-NR/PT1VZ9^aBaaE[[?VVVV>XV=YW>XW;XW9WV8VU7QK5OI3LG3ID1DA2B@3??3>@5<=5;>59?59A67B48C57C57D3:B79A69A68@58@59A69A6:B7:B7:B7:B7:B7;C8F;76<83=51=/3B+9M*BY-Ia1Nq7Mn9Ji=Fa>AY?:L<:K9=O9DV5:@69A67B47B47C57D3:B7:B79A69A69A69A6:B7:B7:B7:B7:B7:B7;C8F;>F;>IA>J@?I>>I9?H7>F7>D8=B;>E>;A=6@85A39H1BV3Pg;ZrB]F\}HVuIMhEBZ@9N;5G74E3XR6F;?G<>H=>I9?H7>F7>D8=B;=D=;A=6@85A39H1DX5Ri=]uEY|BXyDRqEIdA,6H2@R8L_AQfGShIMdH@W=4J329107/-4,YgMZhN\hP^jRblTemVgoZjo[lo\lm[mk\mj[nhZnhZoi]ph]liXkhYjfZie\ie\ie\ig[igXfiVchRajUerao|s{ѿɶıþ˾Ÿ̌oRL2UN2TM0WN1VM.UO/WP3VQ3UQ4QP2ON2MM1PL1NM1NL3MM3LN6LP7KP9JR:LU:IR7JS6QX9SZ9U[9]c?gmIasxpr|Z\bFLP7KM7LK6KI4NI5PK7TM:VP:WQ;VP:SN:QL9LI:IG:EE9CE:=>6F;?G<=G<=H8>G6=E6=C7=B;:A:9?;5?75A39H1BV3Ne9Wo?Sv /* to declare isdigit() */ + + +#if TRANSFORMS_SUPPORTED + +/* + * Lossless image transformation routines. These routines work on DCT + * coefficient arrays and thus do not require any lossy decompression + * or recompression of the image. + * Thanks to Guido Vollbeding for the initial design and code of this feature, + * and to Ben Jackson for introducing the cropping feature. + * + * Horizontal flipping is done in-place, using a single top-to-bottom + * pass through the virtual source array. It will thus be much the + * fastest option for images larger than main memory. + * + * The other routines require a set of destination virtual arrays, so they + * need twice as much memory as jpegtran normally does. The destination + * arrays are always written in normal scan order (top to bottom) because + * the virtual array manager expects this. The source arrays will be scanned + * in the corresponding order, which means multiple passes through the source + * arrays for most of the transforms. That could result in much thrashing + * if the image is larger than main memory. + * + * If cropping or trimming is involved, the destination arrays may be smaller + * than the source arrays. Note it is not possible to do horizontal flip + * in-place when a nonzero Y crop offset is specified, since we'd have to move + * data from one block row to another but the virtual array manager doesn't + * guarantee we can touch more than one row at a time. So in that case, + * we have to use a separate destination array. + * + * Some notes about the operating environment of the individual transform + * routines: + * 1. Both the source and destination virtual arrays are allocated from the + * source JPEG object, and therefore should be manipulated by calling the + * source's memory manager. + * 2. The destination's component count should be used. It may be smaller + * than the source's when forcing to grayscale. + * 3. Likewise the destination's sampling factors should be used. When + * forcing to grayscale the destination's sampling factors will be all 1, + * and we may as well take that as the effective iMCU size. + * 4. When "trim" is in effect, the destination's dimensions will be the + * trimmed values but the source's will be untrimmed. + * 5. When "crop" is in effect, the destination's dimensions will be the + * cropped values but the source's will be uncropped. Each transform + * routine is responsible for picking up source data starting at the + * correct X and Y offset for the crop region. (The X and Y offsets + * passed to the transform routines are measured in iMCU blocks of the + * destination.) + * 6. All the routines assume that the source and destination buffers are + * padded out to a full iMCU boundary. This is true, although for the + * source buffer it is an undocumented property of jdcoefct.c. + */ + + +LOCAL(void) +do_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Crop. This is only used when no rotate/flip is requested with the crop. */ +{ + JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks; + int ci, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + jpeg_component_info *compptr; + + /* We simply have to copy the right amount of data (the destination's + * image size) starting at the given X and Y offsets in the source. + */ + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_y + y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, + dst_buffer[offset_y], + compptr->width_in_blocks); + } + } + } +} + + +LOCAL(void) +do_crop_ext (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Crop. This is only used when no rotate/flip is requested with the crop. + * Extension: If the destination size is larger than the source, we fill in + * the extra area with zero (neutral gray). Note we also have to zero partial + * iMCUs at the right and bottom edge of the source image area in this case. + */ +{ + JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height; + JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks; + int ci, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + jpeg_component_info *compptr; + + MCU_cols = srcinfo->output_width / + (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); + MCU_rows = srcinfo->output_height / + (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + comp_height = MCU_rows * compptr->v_samp_factor; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + if (dstinfo->jpeg_height > srcinfo->output_height) { + if (dst_blk_y < y_crop_blocks || + dst_blk_y >= comp_height + y_crop_blocks) { + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + FMEMZERO(dst_buffer[offset_y], + compptr->width_in_blocks * SIZEOF(JBLOCK)); + } + continue; + } + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_y - y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } else { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_y + y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + if (dstinfo->jpeg_width > srcinfo->output_width) { + if (x_crop_blocks > 0) { + FMEMZERO(dst_buffer[offset_y], + x_crop_blocks * SIZEOF(JBLOCK)); + } + jcopy_block_row(src_buffer[offset_y], + dst_buffer[offset_y] + x_crop_blocks, + comp_width); + if (compptr->width_in_blocks > comp_width + x_crop_blocks) { + FMEMZERO(dst_buffer[offset_y] + + comp_width + x_crop_blocks, + (compptr->width_in_blocks - + comp_width - x_crop_blocks) * SIZEOF(JBLOCK)); + } + } else { + jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, + dst_buffer[offset_y], + compptr->width_in_blocks); + } + } + } + } +} + + +LOCAL(void) +do_wipe (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + JDIMENSION drop_width, JDIMENSION drop_height) +/* Wipe - drop content of specified area, fill with zero (neutral gray) */ +{ + JDIMENSION comp_width, comp_height; + JDIMENSION blk_y, x_wipe_blocks, y_wipe_blocks; + int ci, offset_y; + JBLOCKARRAY buffer; + jpeg_component_info *compptr; + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = drop_width * compptr->h_samp_factor; + comp_height = drop_height * compptr->v_samp_factor; + x_wipe_blocks = x_crop_offset * compptr->h_samp_factor; + y_wipe_blocks = y_crop_offset * compptr->v_samp_factor; + for (blk_y = 0; blk_y < comp_height; blk_y += compptr->v_samp_factor) { + buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y + y_wipe_blocks, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + FMEMZERO(buffer[offset_y] + x_wipe_blocks, + comp_width * SIZEOF(JBLOCK)); + } + } + } +} + + +LOCAL(void) +do_flip_h_no_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, + jvirt_barray_ptr *src_coef_arrays) +/* Horizontal flip; done in-place, so no separate dest array is required. + * NB: this only works when y_crop_offset is zero. + */ +{ + JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks; + int ci, k, offset_y; + JBLOCKARRAY buffer; + JCOEFPTR ptr1, ptr2; + JCOEF temp1, temp2; + jpeg_component_info *compptr; + + /* Horizontal mirroring of DCT blocks is accomplished by swapping + * pairs of blocks in-place. Within a DCT block, we perform horizontal + * mirroring by changing the signs of odd-numbered columns. + * Partial iMCUs at the right edge are left untouched. + */ + MCU_cols = srcinfo->output_width / + (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + for (blk_y = 0; blk_y < compptr->height_in_blocks; + blk_y += compptr->v_samp_factor) { + buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + /* Do the mirroring */ + for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) { + ptr1 = buffer[offset_y][blk_x]; + ptr2 = buffer[offset_y][comp_width - blk_x - 1]; + /* this unrolled loop doesn't need to know which row it's on... */ + for (k = 0; k < DCTSIZE2; k += 2) { + temp1 = *ptr1; /* swap even column */ + temp2 = *ptr2; + *ptr1++ = temp2; + *ptr2++ = temp1; + temp1 = *ptr1; /* swap odd column with sign change */ + temp2 = *ptr2; + *ptr1++ = -temp2; + *ptr2++ = -temp1; + } + } + if (x_crop_blocks > 0) { + /* Now left-justify the portion of the data to be kept. + * We can't use a single jcopy_block_row() call because that routine + * depends on memcpy(), whose behavior is unspecified for overlapping + * source and destination areas. Sigh. + */ + for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) { + jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks, + buffer[offset_y] + blk_x, + (JDIMENSION) 1); + } + } + } + } + } +} + + +LOCAL(void) +do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Horizontal flip in general cropping case */ +{ + JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; + JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, k, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JBLOCKROW src_row_ptr, dst_row_ptr; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* Here we must output into a separate array because we can't touch + * different rows of a single virtual array simultaneously. Otherwise, + * this is essentially the same as the routine above. + */ + MCU_cols = srcinfo->output_width / + (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_y + y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + dst_row_ptr = dst_buffer[offset_y]; + src_row_ptr = src_buffer[offset_y]; + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { + if (x_crop_blocks + dst_blk_x < comp_width) { + /* Do the mirrorable blocks */ + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; + /* this unrolled loop doesn't need to know which row it's on... */ + for (k = 0; k < DCTSIZE2; k += 2) { + *dst_ptr++ = *src_ptr++; /* copy even column */ + *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */ + } + } else { + /* Copy last partial block(s) verbatim */ + jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, + dst_row_ptr + dst_blk_x, + (JDIMENSION) 1); + } + } + } + } + } +} + + +LOCAL(void) +do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Vertical flip */ +{ + JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; + JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JBLOCKROW src_row_ptr, dst_row_ptr; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* We output into a separate array because we can't touch different + * rows of the source virtual array simultaneously. Otherwise, this + * is a pretty straightforward analog of horizontal flip. + * Within a DCT block, vertical mirroring is done by changing the signs + * of odd-numbered rows. + * Partial iMCUs at the bottom edge are copied verbatim. + */ + MCU_rows = srcinfo->output_height / + (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_height = MCU_rows * compptr->v_samp_factor; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + if (y_crop_blocks + dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + comp_height - y_crop_blocks - dst_blk_y - + (JDIMENSION) compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } else { + /* Bottom-edge blocks will be copied verbatim. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_y + y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + if (y_crop_blocks + dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ + dst_row_ptr = dst_buffer[offset_y]; + src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; + src_row_ptr += x_crop_blocks; + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[dst_blk_x]; + for (i = 0; i < DCTSIZE; i += 2) { + /* copy even row */ + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = *src_ptr++; + /* copy odd row with sign change */ + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = - *src_ptr++; + } + } + } else { + /* Just copy row verbatim. */ + jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, + dst_buffer[offset_y], + compptr->width_in_blocks); + } + } + } + } +} + + +LOCAL(void) +do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Transpose source into destination */ +{ + JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* Transposing pixels within a block just requires transposing the + * DCT coefficients. + * Partial iMCUs at the edges require no special treatment; we simply + * process all the available DCT blocks for every component. + */ + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_x + x_crop_blocks, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } +} + + +LOCAL(void) +do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* 90 degree rotation is equivalent to + * 1. Transposing the image; + * 2. Horizontal mirroring. + * These two steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; + JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* Because of the horizontal mirror step, we can't process partial iMCUs + * at the (output) right edge properly. They just get transposed and + * not mirrored. + */ + MCU_cols = srcinfo->output_height / + (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + if (x_crop_blocks + dst_blk_x < comp_width) { + /* Block is within the mirrorable area. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + comp_width - x_crop_blocks - dst_blk_x - + (JDIMENSION) compptr->h_samp_factor, + (JDIMENSION) compptr->h_samp_factor, FALSE); + } else { + /* Edge blocks are transposed but not mirrored. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_x + x_crop_blocks, + (JDIMENSION) compptr->h_samp_factor, FALSE); + } + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + if (x_crop_blocks + dst_blk_x < comp_width) { + /* Block is within the mirrorable area. */ + src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] + [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + i++; + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } else { + /* Edge blocks are transposed but not mirrored. */ + src_ptr = src_buffer[offset_x] + [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } + } +} + + +LOCAL(void) +do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* 270 degree rotation is equivalent to + * 1. Horizontal mirroring; + * 2. Transposing the image. + * These two steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; + JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* Because of the horizontal mirror step, we can't process partial iMCUs + * at the (output) bottom edge properly. They just get transposed and + * not mirrored. + */ + MCU_rows = srcinfo->output_width / + (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_height = MCU_rows * compptr->v_samp_factor; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_x + x_crop_blocks, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + if (y_crop_blocks + dst_blk_y < comp_height) { + /* Block is within the mirrorable area. */ + src_ptr = src_buffer[offset_x] + [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } + } else { + /* Edge blocks are transposed but not mirrored. */ + src_ptr = src_buffer[offset_x] + [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } + } +} + + +LOCAL(void) +do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* 180 degree rotation is equivalent to + * 1. Vertical mirroring; + * 2. Horizontal mirroring. + * These two steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; + JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JBLOCKROW src_row_ptr, dst_row_ptr; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + MCU_cols = srcinfo->output_width / + (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); + MCU_rows = srcinfo->output_height / + (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + comp_height = MCU_rows * compptr->v_samp_factor; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + if (y_crop_blocks + dst_blk_y < comp_height) { + /* Row is within the vertically mirrorable area. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + comp_height - y_crop_blocks - dst_blk_y - + (JDIMENSION) compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } else { + /* Bottom-edge rows are only mirrored horizontally. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_y + y_crop_blocks, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + dst_row_ptr = dst_buffer[offset_y]; + if (y_crop_blocks + dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ + src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; + if (x_crop_blocks + dst_blk_x < comp_width) { + /* Process the blocks that can be mirrored both ways. */ + src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; + for (i = 0; i < DCTSIZE; i += 2) { + /* For even row, negate every odd column. */ + for (j = 0; j < DCTSIZE; j += 2) { + *dst_ptr++ = *src_ptr++; + *dst_ptr++ = - *src_ptr++; + } + /* For odd row, negate every even column. */ + for (j = 0; j < DCTSIZE; j += 2) { + *dst_ptr++ = - *src_ptr++; + *dst_ptr++ = *src_ptr++; + } + } + } else { + /* Any remaining right-edge blocks are only mirrored vertically. */ + src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x]; + for (i = 0; i < DCTSIZE; i += 2) { + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = *src_ptr++; + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = - *src_ptr++; + } + } + } + } else { + /* Remaining rows are just mirrored horizontally. */ + src_row_ptr = src_buffer[offset_y]; + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { + if (x_crop_blocks + dst_blk_x < comp_width) { + /* Process the blocks that can be mirrored. */ + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; + for (i = 0; i < DCTSIZE2; i += 2) { + *dst_ptr++ = *src_ptr++; + *dst_ptr++ = - *src_ptr++; + } + } else { + /* Any remaining right-edge blocks are only copied. */ + jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, + dst_row_ptr + dst_blk_x, + (JDIMENSION) 1); + } + } + } + } + } + } +} + + +LOCAL(void) +do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Transverse transpose is equivalent to + * 1. 180 degree rotation; + * 2. Transposition; + * or + * 1. Horizontal mirroring; + * 2. Transposition; + * 3. Horizontal mirroring. + * These steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; + JDIMENSION x_crop_blocks, y_crop_blocks; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + MCU_cols = srcinfo->output_height / + (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size); + MCU_rows = srcinfo->output_width / + (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + comp_height = MCU_rows * compptr->v_samp_factor; + x_crop_blocks = x_crop_offset * compptr->h_samp_factor; + y_crop_blocks = y_crop_offset * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + if (x_crop_blocks + dst_blk_x < comp_width) { + /* Block is within the mirrorable area. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + comp_width - x_crop_blocks - dst_blk_x - + (JDIMENSION) compptr->h_samp_factor, + (JDIMENSION) compptr->h_samp_factor, FALSE); + } else { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + dst_blk_x + x_crop_blocks, + (JDIMENSION) compptr->h_samp_factor, FALSE); + } + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + if (y_crop_blocks + dst_blk_y < comp_height) { + if (x_crop_blocks + dst_blk_x < comp_width) { + /* Block is within the mirrorable area. */ + src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] + [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + i++; + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } else { + /* Right-edge blocks are mirrored in y only */ + src_ptr = src_buffer[offset_x] + [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } + } + } else { + if (x_crop_blocks + dst_blk_x < comp_width) { + /* Bottom-edge blocks are mirrored in x only */ + src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] + [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + i++; + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } else { + /* At lower right corner, just transpose, no mirroring */ + src_ptr = src_buffer[offset_x] + [dst_blk_y + offset_y + y_crop_blocks]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } + } + } +} + + +/* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec. + * Returns TRUE if valid integer found, FALSE if not. + * *strptr is advanced over the digit string, and *result is set to its value. + */ + +LOCAL(boolean) +jt_read_integer (const char ** strptr, JDIMENSION * result) +{ + const char * ptr = *strptr; + JDIMENSION val = 0; + + for (; isdigit(*ptr); ptr++) { + val = val * 10 + (JDIMENSION) (*ptr - '0'); + } + *result = val; + if (ptr == *strptr) + return FALSE; /* oops, no digits */ + *strptr = ptr; + return TRUE; +} + + +/* Parse a crop specification (written in X11 geometry style). + * The routine returns TRUE if the spec string is valid, FALSE if not. + * + * The crop spec string should have the format + * [f]x[f]{+-}{+-} + * where width, height, xoffset, and yoffset are unsigned integers. + * Each of the elements can be omitted to indicate a default value. + * (A weakness of this style is that it is not possible to omit xoffset + * while specifying yoffset, since they look alike.) + * + * This code is loosely based on XParseGeometry from the X11 distribution. + */ + +GLOBAL(boolean) +jtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec) +{ + info->crop = FALSE; + info->crop_width_set = JCROP_UNSET; + info->crop_height_set = JCROP_UNSET; + info->crop_xoffset_set = JCROP_UNSET; + info->crop_yoffset_set = JCROP_UNSET; + + if (isdigit(*spec)) { + /* fetch width */ + if (! jt_read_integer(&spec, &info->crop_width)) + return FALSE; + if (*spec == 'f' || *spec == 'F') { + spec++; + info->crop_width_set = JCROP_FORCE; + } else + info->crop_width_set = JCROP_POS; + } + if (*spec == 'x' || *spec == 'X') { + /* fetch height */ + spec++; + if (! jt_read_integer(&spec, &info->crop_height)) + return FALSE; + if (*spec == 'f' || *spec == 'F') { + spec++; + info->crop_height_set = JCROP_FORCE; + } else + info->crop_height_set = JCROP_POS; + } + if (*spec == '+' || *spec == '-') { + /* fetch xoffset */ + info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; + spec++; + if (! jt_read_integer(&spec, &info->crop_xoffset)) + return FALSE; + } + if (*spec == '+' || *spec == '-') { + /* fetch yoffset */ + info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; + spec++; + if (! jt_read_integer(&spec, &info->crop_yoffset)) + return FALSE; + } + /* We had better have gotten to the end of the string. */ + if (*spec != '\0') + return FALSE; + info->crop = TRUE; + return TRUE; +} + + +/* Trim off any partial iMCUs on the indicated destination edge */ + +LOCAL(void) +trim_right_edge (jpeg_transform_info *info, JDIMENSION full_width) +{ + JDIMENSION MCU_cols; + + MCU_cols = info->output_width / info->iMCU_sample_width; + if (MCU_cols > 0 && info->x_crop_offset + MCU_cols == + full_width / info->iMCU_sample_width) + info->output_width = MCU_cols * info->iMCU_sample_width; +} + +LOCAL(void) +trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height) +{ + JDIMENSION MCU_rows; + + MCU_rows = info->output_height / info->iMCU_sample_height; + if (MCU_rows > 0 && info->y_crop_offset + MCU_rows == + full_height / info->iMCU_sample_height) + info->output_height = MCU_rows * info->iMCU_sample_height; +} + + +/* Request any required workspace. + * + * This routine figures out the size that the output image will be + * (which implies that all the transform parameters must be set before + * it is called). + * + * We allocate the workspace virtual arrays from the source decompression + * object, so that all the arrays (both the original data and the workspace) + * will be taken into account while making memory management decisions. + * Hence, this routine must be called after jpeg_read_header (which reads + * the image dimensions) and before jpeg_read_coefficients (which realizes + * the source's virtual arrays). + * + * This function returns FALSE right away if -perfect is given + * and transformation is not perfect. Otherwise returns TRUE. + */ + +GLOBAL(boolean) +jtransform_request_workspace (j_decompress_ptr srcinfo, + jpeg_transform_info *info) +{ + jvirt_barray_ptr *coef_arrays; + boolean need_workspace, transpose_it; + jpeg_component_info *compptr; + JDIMENSION xoffset, yoffset; + JDIMENSION width_in_iMCUs, height_in_iMCUs; + JDIMENSION width_in_blocks, height_in_blocks; + int ci, h_samp_factor, v_samp_factor; + + /* Determine number of components in output image */ + if (info->force_grayscale && + (srcinfo->jpeg_color_space == JCS_YCbCr || + srcinfo->jpeg_color_space == JCS_BG_YCC) && + srcinfo->num_components == 3) + /* We'll only process the first component */ + info->num_components = 1; + else + /* Process all the components */ + info->num_components = srcinfo->num_components; + + /* Compute output image dimensions and related values. */ + jpeg_core_output_dimensions(srcinfo); + + /* Return right away if -perfect is given and transformation is not perfect. + */ + if (info->perfect) { + if (info->num_components == 1) { + if (!jtransform_perfect_transform(srcinfo->output_width, + srcinfo->output_height, + srcinfo->min_DCT_h_scaled_size, + srcinfo->min_DCT_v_scaled_size, + info->transform)) + return FALSE; + } else { + if (!jtransform_perfect_transform(srcinfo->output_width, + srcinfo->output_height, + srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size, + srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size, + info->transform)) + return FALSE; + } + } + + /* If there is only one output component, force the iMCU size to be 1; + * else use the source iMCU size. (This allows us to do the right thing + * when reducing color to grayscale, and also provides a handy way of + * cleaning up "funny" grayscale images whose sampling factors are not 1x1.) + */ + switch (info->transform) { + case JXFORM_TRANSPOSE: + case JXFORM_TRANSVERSE: + case JXFORM_ROT_90: + case JXFORM_ROT_270: + info->output_width = srcinfo->output_height; + info->output_height = srcinfo->output_width; + if (info->num_components == 1) { + info->iMCU_sample_width = srcinfo->min_DCT_v_scaled_size; + info->iMCU_sample_height = srcinfo->min_DCT_h_scaled_size; + } else { + info->iMCU_sample_width = + srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size; + info->iMCU_sample_height = + srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size; + } + break; + default: + info->output_width = srcinfo->output_width; + info->output_height = srcinfo->output_height; + if (info->num_components == 1) { + info->iMCU_sample_width = srcinfo->min_DCT_h_scaled_size; + info->iMCU_sample_height = srcinfo->min_DCT_v_scaled_size; + } else { + info->iMCU_sample_width = + srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size; + info->iMCU_sample_height = + srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size; + } + break; + } + + /* If cropping has been requested, compute the crop area's position and + * dimensions, ensuring that its upper left corner falls at an iMCU boundary. + */ + if (info->crop) { + /* Insert default values for unset crop parameters */ + if (info->crop_xoffset_set == JCROP_UNSET) + info->crop_xoffset = 0; /* default to +0 */ + if (info->crop_yoffset_set == JCROP_UNSET) + info->crop_yoffset = 0; /* default to +0 */ + if (info->crop_width_set == JCROP_UNSET) { + if (info->crop_xoffset >= info->output_width) + ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); + info->crop_width = info->output_width - info->crop_xoffset; + } else { + /* Check for crop extension */ + if (info->crop_width > info->output_width) { + /* Crop extension does not work when transforming! */ + if (info->transform != JXFORM_NONE || + info->crop_xoffset >= info->crop_width || + info->crop_xoffset > info->crop_width - info->output_width) + ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); + } else { + if (info->crop_xoffset >= info->output_width || + info->crop_width <= 0 || + info->crop_xoffset > info->output_width - info->crop_width) + ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); + } + } + if (info->crop_height_set == JCROP_UNSET) { + if (info->crop_yoffset >= info->output_height) + ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); + info->crop_height = info->output_height - info->crop_yoffset; + } else { + /* Check for crop extension */ + if (info->crop_height > info->output_height) { + /* Crop extension does not work when transforming! */ + if (info->transform != JXFORM_NONE || + info->crop_yoffset >= info->crop_height || + info->crop_yoffset > info->crop_height - info->output_height) + ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); + } else { + if (info->crop_yoffset >= info->output_height || + info->crop_height <= 0 || + info->crop_yoffset > info->output_height - info->crop_height) + ERREXIT(srcinfo, JERR_BAD_CROP_SPEC); + } + } + /* Convert negative crop offsets into regular offsets */ + if (info->crop_xoffset_set != JCROP_NEG) + xoffset = info->crop_xoffset; + else if (info->crop_width > info->output_width) /* crop extension */ + xoffset = info->crop_width - info->output_width - info->crop_xoffset; + else + xoffset = info->output_width - info->crop_width - info->crop_xoffset; + if (info->crop_yoffset_set != JCROP_NEG) + yoffset = info->crop_yoffset; + else if (info->crop_height > info->output_height) /* crop extension */ + yoffset = info->crop_height - info->output_height - info->crop_yoffset; + else + yoffset = info->output_height - info->crop_height - info->crop_yoffset; + /* Now adjust so that upper left corner falls at an iMCU boundary */ + if (info->transform == JXFORM_WIPE) { + /* Ensure the effective wipe region will cover the requested */ + info->drop_width = (JDIMENSION) jdiv_round_up + ((long) (info->crop_width + (xoffset % info->iMCU_sample_width)), + (long) info->iMCU_sample_width); + info->drop_height = (JDIMENSION) jdiv_round_up + ((long) (info->crop_height + (yoffset % info->iMCU_sample_height)), + (long) info->iMCU_sample_height); + } else { + /* Ensure the effective crop region will cover the requested */ + if (info->crop_width_set == JCROP_FORCE || + info->crop_width > info->output_width) + info->output_width = info->crop_width; + else + info->output_width = + info->crop_width + (xoffset % info->iMCU_sample_width); + if (info->crop_height_set == JCROP_FORCE || + info->crop_height > info->output_height) + info->output_height = info->crop_height; + else + info->output_height = + info->crop_height + (yoffset % info->iMCU_sample_height); + } + /* Save x/y offsets measured in iMCUs */ + info->x_crop_offset = xoffset / info->iMCU_sample_width; + info->y_crop_offset = yoffset / info->iMCU_sample_height; + } else { + info->x_crop_offset = 0; + info->y_crop_offset = 0; + } + + /* Figure out whether we need workspace arrays, + * and if so whether they are transposed relative to the source. + */ + need_workspace = FALSE; + transpose_it = FALSE; + switch (info->transform) { + case JXFORM_NONE: + if (info->x_crop_offset != 0 || info->y_crop_offset != 0 || + info->output_width > srcinfo->output_width || + info->output_height > srcinfo->output_height) + need_workspace = TRUE; + /* No workspace needed if neither cropping nor transforming */ + break; + case JXFORM_FLIP_H: + if (info->trim) + trim_right_edge(info, srcinfo->output_width); + if (info->y_crop_offset != 0) + need_workspace = TRUE; + /* do_flip_h_no_crop doesn't need a workspace array */ + break; + case JXFORM_FLIP_V: + if (info->trim) + trim_bottom_edge(info, srcinfo->output_height); + /* Need workspace arrays having same dimensions as source image. */ + need_workspace = TRUE; + break; + case JXFORM_TRANSPOSE: + /* transpose does NOT have to trim anything */ + /* Need workspace arrays having transposed dimensions. */ + need_workspace = TRUE; + transpose_it = TRUE; + break; + case JXFORM_TRANSVERSE: + if (info->trim) { + trim_right_edge(info, srcinfo->output_height); + trim_bottom_edge(info, srcinfo->output_width); + } + /* Need workspace arrays having transposed dimensions. */ + need_workspace = TRUE; + transpose_it = TRUE; + break; + case JXFORM_ROT_90: + if (info->trim) + trim_right_edge(info, srcinfo->output_height); + /* Need workspace arrays having transposed dimensions. */ + need_workspace = TRUE; + transpose_it = TRUE; + break; + case JXFORM_ROT_180: + if (info->trim) { + trim_right_edge(info, srcinfo->output_width); + trim_bottom_edge(info, srcinfo->output_height); + } + /* Need workspace arrays having same dimensions as source image. */ + need_workspace = TRUE; + break; + case JXFORM_ROT_270: + if (info->trim) + trim_bottom_edge(info, srcinfo->output_width); + /* Need workspace arrays having transposed dimensions. */ + need_workspace = TRUE; + transpose_it = TRUE; + break; + case JXFORM_WIPE: + break; + } + + /* Allocate workspace if needed. + * Note that we allocate arrays padded out to the next iMCU boundary, + * so that transform routines need not worry about missing edge blocks. + */ + if (need_workspace) { + coef_arrays = (jvirt_barray_ptr *) + (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, + SIZEOF(jvirt_barray_ptr) * info->num_components); + width_in_iMCUs = (JDIMENSION) + jdiv_round_up((long) info->output_width, + (long) info->iMCU_sample_width); + height_in_iMCUs = (JDIMENSION) + jdiv_round_up((long) info->output_height, + (long) info->iMCU_sample_height); + for (ci = 0; ci < info->num_components; ci++) { + compptr = srcinfo->comp_info + ci; + if (info->num_components == 1) { + /* we're going to force samp factors to 1x1 in this case */ + h_samp_factor = v_samp_factor = 1; + } else if (transpose_it) { + h_samp_factor = compptr->v_samp_factor; + v_samp_factor = compptr->h_samp_factor; + } else { + h_samp_factor = compptr->h_samp_factor; + v_samp_factor = compptr->v_samp_factor; + } + width_in_blocks = width_in_iMCUs * h_samp_factor; + height_in_blocks = height_in_iMCUs * v_samp_factor; + coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) + ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, + width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor); + } + info->workspace_coef_arrays = coef_arrays; + } else + info->workspace_coef_arrays = NULL; + + return TRUE; +} + + +/* Transpose destination image parameters */ + +LOCAL(void) +transpose_critical_parameters (j_compress_ptr dstinfo) +{ + int tblno, i, j, ci, itemp; + jpeg_component_info *compptr; + JQUANT_TBL *qtblptr; + JDIMENSION jtemp; + UINT16 qtemp; + + /* Transpose image dimensions */ + jtemp = dstinfo->image_width; + dstinfo->image_width = dstinfo->image_height; + dstinfo->image_height = jtemp; + itemp = dstinfo->min_DCT_h_scaled_size; + dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size; + dstinfo->min_DCT_v_scaled_size = itemp; + + /* Transpose sampling factors */ + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + itemp = compptr->h_samp_factor; + compptr->h_samp_factor = compptr->v_samp_factor; + compptr->v_samp_factor = itemp; + } + + /* Transpose quantization tables */ + for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { + qtblptr = dstinfo->quant_tbl_ptrs[tblno]; + if (qtblptr != NULL) { + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < i; j++) { + qtemp = qtblptr->quantval[i*DCTSIZE+j]; + qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i]; + qtblptr->quantval[j*DCTSIZE+i] = qtemp; + } + } + } + } +} + + +/* Adjust Exif image parameters. + * + * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible. + */ + +LOCAL(void) +adjust_exif_parameters (JOCTET FAR * data, unsigned int length, + JDIMENSION new_width, JDIMENSION new_height) +{ + boolean is_motorola; /* Flag for byte order */ + unsigned int number_of_tags, tagnum; + unsigned int firstoffset, offset; + JDIMENSION new_value; + + if (length < 12) return; /* Length of an IFD entry */ + + /* Discover byte order */ + if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49) + is_motorola = FALSE; + else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D) + is_motorola = TRUE; + else + return; + + /* Check Tag Mark */ + if (is_motorola) { + if (GETJOCTET(data[2]) != 0) return; + if (GETJOCTET(data[3]) != 0x2A) return; + } else { + if (GETJOCTET(data[3]) != 0) return; + if (GETJOCTET(data[2]) != 0x2A) return; + } + + /* Get first IFD offset (offset to IFD0) */ + if (is_motorola) { + if (GETJOCTET(data[4]) != 0) return; + if (GETJOCTET(data[5]) != 0) return; + firstoffset = GETJOCTET(data[6]); + firstoffset <<= 8; + firstoffset += GETJOCTET(data[7]); + } else { + if (GETJOCTET(data[7]) != 0) return; + if (GETJOCTET(data[6]) != 0) return; + firstoffset = GETJOCTET(data[5]); + firstoffset <<= 8; + firstoffset += GETJOCTET(data[4]); + } + if (firstoffset > length - 2) return; /* check end of data segment */ + + /* Get the number of directory entries contained in this IFD */ + if (is_motorola) { + number_of_tags = GETJOCTET(data[firstoffset]); + number_of_tags <<= 8; + number_of_tags += GETJOCTET(data[firstoffset+1]); + } else { + number_of_tags = GETJOCTET(data[firstoffset+1]); + number_of_tags <<= 8; + number_of_tags += GETJOCTET(data[firstoffset]); + } + if (number_of_tags == 0) return; + firstoffset += 2; + + /* Search for ExifSubIFD offset Tag in IFD0 */ + for (;;) { + if (firstoffset > length - 12) return; /* check end of data segment */ + /* Get Tag number */ + if (is_motorola) { + tagnum = GETJOCTET(data[firstoffset]); + tagnum <<= 8; + tagnum += GETJOCTET(data[firstoffset+1]); + } else { + tagnum = GETJOCTET(data[firstoffset+1]); + tagnum <<= 8; + tagnum += GETJOCTET(data[firstoffset]); + } + if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */ + if (--number_of_tags == 0) return; + firstoffset += 12; + } + + /* Get the ExifSubIFD offset */ + if (is_motorola) { + if (GETJOCTET(data[firstoffset+8]) != 0) return; + if (GETJOCTET(data[firstoffset+9]) != 0) return; + offset = GETJOCTET(data[firstoffset+10]); + offset <<= 8; + offset += GETJOCTET(data[firstoffset+11]); + } else { + if (GETJOCTET(data[firstoffset+11]) != 0) return; + if (GETJOCTET(data[firstoffset+10]) != 0) return; + offset = GETJOCTET(data[firstoffset+9]); + offset <<= 8; + offset += GETJOCTET(data[firstoffset+8]); + } + if (offset > length - 2) return; /* check end of data segment */ + + /* Get the number of directory entries contained in this SubIFD */ + if (is_motorola) { + number_of_tags = GETJOCTET(data[offset]); + number_of_tags <<= 8; + number_of_tags += GETJOCTET(data[offset+1]); + } else { + number_of_tags = GETJOCTET(data[offset+1]); + number_of_tags <<= 8; + number_of_tags += GETJOCTET(data[offset]); + } + if (number_of_tags < 2) return; + offset += 2; + + /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */ + do { + if (offset > length - 12) return; /* check end of data segment */ + /* Get Tag number */ + if (is_motorola) { + tagnum = GETJOCTET(data[offset]); + tagnum <<= 8; + tagnum += GETJOCTET(data[offset+1]); + } else { + tagnum = GETJOCTET(data[offset+1]); + tagnum <<= 8; + tagnum += GETJOCTET(data[offset]); + } + if (tagnum == 0xA002 || tagnum == 0xA003) { + if (tagnum == 0xA002) + new_value = new_width; /* ExifImageWidth Tag */ + else + new_value = new_height; /* ExifImageHeight Tag */ + if (is_motorola) { + data[offset+2] = 0; /* Format = unsigned long (4 octets) */ + data[offset+3] = 4; + data[offset+4] = 0; /* Number Of Components = 1 */ + data[offset+5] = 0; + data[offset+6] = 0; + data[offset+7] = 1; + data[offset+8] = 0; + data[offset+9] = 0; + data[offset+10] = (JOCTET)((new_value >> 8) & 0xFF); + data[offset+11] = (JOCTET)(new_value & 0xFF); + } else { + data[offset+2] = 4; /* Format = unsigned long (4 octets) */ + data[offset+3] = 0; + data[offset+4] = 1; /* Number Of Components = 1 */ + data[offset+5] = 0; + data[offset+6] = 0; + data[offset+7] = 0; + data[offset+8] = (JOCTET)(new_value & 0xFF); + data[offset+9] = (JOCTET)((new_value >> 8) & 0xFF); + data[offset+10] = 0; + data[offset+11] = 0; + } + } + offset += 12; + } while (--number_of_tags); +} + + +/* Adjust output image parameters as needed. + * + * This must be called after jpeg_copy_critical_parameters() + * and before jpeg_write_coefficients(). + * + * The return value is the set of virtual coefficient arrays to be written + * (either the ones allocated by jtransform_request_workspace, or the + * original source data arrays). The caller will need to pass this value + * to jpeg_write_coefficients(). + */ + +GLOBAL(jvirt_barray_ptr *) +jtransform_adjust_parameters (j_decompress_ptr srcinfo, + j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info) +{ + /* If force-to-grayscale is requested, adjust destination parameters */ + if (info->force_grayscale) { + /* First, ensure we have YCC or grayscale data, and that the source's + * Y channel is full resolution. (No reasonable person would make Y + * be less than full resolution, so actually coping with that case + * isn't worth extra code space. But we check it to avoid crashing.) + */ + if ((((dstinfo->jpeg_color_space == JCS_YCbCr || + dstinfo->jpeg_color_space == JCS_BG_YCC) && + dstinfo->num_components == 3) || + (dstinfo->jpeg_color_space == JCS_GRAYSCALE && + dstinfo->num_components == 1)) && + srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor && + srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) { + /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed + * properly. Among other things, it sets the target h_samp_factor & + * v_samp_factor to 1, which typically won't match the source. + * We have to preserve the source's quantization table number, however. + */ + int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no; + jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE); + dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no; + } else { + /* Sorry, can't do it */ + ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL); + } + } else if (info->num_components == 1) { + /* For a single-component source, we force the destination sampling factors + * to 1x1, with or without force_grayscale. This is useful because some + * decoders choke on grayscale images with other sampling factors. + */ + dstinfo->comp_info[0].h_samp_factor = 1; + dstinfo->comp_info[0].v_samp_factor = 1; + } + + /* Correct the destination's image dimensions as necessary + * for rotate/flip, resize, and crop operations. + */ + dstinfo->jpeg_width = info->output_width; + dstinfo->jpeg_height = info->output_height; + + /* Transpose destination image parameters */ + switch (info->transform) { + case JXFORM_TRANSPOSE: + case JXFORM_TRANSVERSE: + case JXFORM_ROT_90: + case JXFORM_ROT_270: + transpose_critical_parameters(dstinfo); + break; + default: + break; + } + + /* Adjust Exif properties */ + if (srcinfo->marker_list != NULL && + srcinfo->marker_list->marker == JPEG_APP0+1 && + srcinfo->marker_list->data_length >= 6 && + GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 && + GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 && + GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 && + GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 && + GETJOCTET(srcinfo->marker_list->data[4]) == 0 && + GETJOCTET(srcinfo->marker_list->data[5]) == 0) { + /* Suppress output of JFIF marker */ + dstinfo->write_JFIF_header = FALSE; + /* Adjust Exif image parameters */ + if (dstinfo->jpeg_width != srcinfo->image_width || + dstinfo->jpeg_height != srcinfo->image_height) + /* Align data segment to start of TIFF structure for parsing */ + adjust_exif_parameters(srcinfo->marker_list->data + 6, + srcinfo->marker_list->data_length - 6, + dstinfo->jpeg_width, dstinfo->jpeg_height); + } + + /* Return the appropriate output data set */ + if (info->workspace_coef_arrays != NULL) + return info->workspace_coef_arrays; + return src_coef_arrays; +} + + +/* Execute the actual transformation, if any. + * + * This must be called *after* jpeg_write_coefficients, because it depends + * on jpeg_write_coefficients to have computed subsidiary values such as + * the per-component width and height fields in the destination object. + * + * Note that some transformations will modify the source data arrays! + */ + +GLOBAL(void) +jtransform_execute_transform (j_decompress_ptr srcinfo, + j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info) +{ + jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays; + + /* Note: conditions tested here should match those in switch statement + * in jtransform_request_workspace() + */ + switch (info->transform) { + case JXFORM_NONE: + if (info->output_width > srcinfo->output_width || + info->output_height > srcinfo->output_height) + do_crop_ext(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + else if (info->x_crop_offset != 0 || info->y_crop_offset != 0) + do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_FLIP_H: + if (info->y_crop_offset != 0) + do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + else + do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset, + src_coef_arrays); + break; + case JXFORM_FLIP_V: + do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_TRANSPOSE: + do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_TRANSVERSE: + do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_90: + do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_180: + do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_270: + do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_WIPE: + do_wipe(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, + src_coef_arrays, info->drop_width, info->drop_height); + break; + } +} + +/* jtransform_perfect_transform + * + * Determine whether lossless transformation is perfectly + * possible for a specified image and transformation. + * + * Inputs: + * image_width, image_height: source image dimensions. + * MCU_width, MCU_height: pixel dimensions of MCU. + * transform: transformation identifier. + * Parameter sources from initialized jpeg_struct + * (after reading source header): + * image_width = cinfo.image_width + * image_height = cinfo.image_height + * MCU_width = cinfo.max_h_samp_factor * cinfo.block_size + * MCU_height = cinfo.max_v_samp_factor * cinfo.block_size + * Result: + * TRUE = perfect transformation possible + * FALSE = perfect transformation not possible + * (may use custom action then) + */ + +GLOBAL(boolean) +jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height, + int MCU_width, int MCU_height, + JXFORM_CODE transform) +{ + boolean result = TRUE; /* initialize TRUE */ + + switch (transform) { + case JXFORM_FLIP_H: + case JXFORM_ROT_270: + if (image_width % (JDIMENSION) MCU_width) + result = FALSE; + break; + case JXFORM_FLIP_V: + case JXFORM_ROT_90: + if (image_height % (JDIMENSION) MCU_height) + result = FALSE; + break; + case JXFORM_TRANSVERSE: + case JXFORM_ROT_180: + if (image_width % (JDIMENSION) MCU_width) + result = FALSE; + if (image_height % (JDIMENSION) MCU_height) + result = FALSE; + break; + default: + break; + } + + return result; +} + +#endif /* TRANSFORMS_SUPPORTED */ + + +/* Setup decompression object to save desired markers in memory. + * This must be called before jpeg_read_header() to have the desired effect. + */ + +GLOBAL(void) +jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option) +{ +#ifdef SAVE_MARKERS_SUPPORTED + int m; + + /* Save comments except under NONE option */ + if (option != JCOPYOPT_NONE) { + jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF); + } + /* Save all types of APPn markers iff ALL option */ + if (option == JCOPYOPT_ALL) { + for (m = 0; m < 16; m++) + jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF); + } +#endif /* SAVE_MARKERS_SUPPORTED */ +} + +/* Copy markers saved in the given source object to the destination object. + * This should be called just after jpeg_start_compress() or + * jpeg_write_coefficients(). + * Note that those routines will have written the SOI, and also the + * JFIF APP0 or Adobe APP14 markers if selected. + */ + +GLOBAL(void) +jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JCOPY_OPTION option) +{ + jpeg_saved_marker_ptr marker; + + /* In the current implementation, we don't actually need to examine the + * option flag here; we just copy everything that got saved. + * But to avoid confusion, we do not output JFIF and Adobe APP14 markers + * if the encoder library already wrote one. + */ + for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) { + if (dstinfo->write_JFIF_header && + marker->marker == JPEG_APP0 && + marker->data_length >= 5 && + GETJOCTET(marker->data[0]) == 0x4A && + GETJOCTET(marker->data[1]) == 0x46 && + GETJOCTET(marker->data[2]) == 0x49 && + GETJOCTET(marker->data[3]) == 0x46 && + GETJOCTET(marker->data[4]) == 0) + continue; /* reject duplicate JFIF */ + if (dstinfo->write_Adobe_marker && + marker->marker == JPEG_APP0+14 && + marker->data_length >= 5 && + GETJOCTET(marker->data[0]) == 0x41 && + GETJOCTET(marker->data[1]) == 0x64 && + GETJOCTET(marker->data[2]) == 0x6F && + GETJOCTET(marker->data[3]) == 0x62 && + GETJOCTET(marker->data[4]) == 0x65) + continue; /* reject duplicate Adobe */ +#ifdef NEED_FAR_POINTERS + /* We could use jpeg_write_marker if the data weren't FAR... */ + { + unsigned int i; + jpeg_write_m_header(dstinfo, marker->marker, marker->data_length); + for (i = 0; i < marker->data_length; i++) + jpeg_write_m_byte(dstinfo, marker->data[i]); + } +#else + jpeg_write_marker(dstinfo, marker->marker, + marker->data, marker->data_length); +#endif + } +} diff --git a/source/Irrlicht/jpeglib/transupp.h b/source/Irrlicht/jpeglib/transupp.h new file mode 100644 index 00000000..28a1a9cb --- /dev/null +++ b/source/Irrlicht/jpeglib/transupp.h @@ -0,0 +1,219 @@ +/* + * transupp.h + * + * Copyright (C) 1997-2013, Thomas G. Lane, Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for image transformation routines and + * other utility code used by the jpegtran sample application. These are + * NOT part of the core JPEG library. But we keep these routines separate + * from jpegtran.c to ease the task of maintaining jpegtran-like programs + * that have other user interfaces. + * + * NOTE: all the routines declared here have very specific requirements + * about when they are to be executed during the reading and writing of the + * source and destination files. See the comments in transupp.c, or see + * jpegtran.c for an example of correct usage. + */ + +/* If you happen not to want the image transform support, disable it here */ +#ifndef TRANSFORMS_SUPPORTED +#define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */ +#endif + +/* + * Although rotating and flipping data expressed as DCT coefficients is not + * hard, there is an asymmetry in the JPEG format specification for images + * whose dimensions aren't multiples of the iMCU size. The right and bottom + * image edges are padded out to the next iMCU boundary with junk data; but + * no padding is possible at the top and left edges. If we were to flip + * the whole image including the pad data, then pad garbage would become + * visible at the top and/or left, and real pixels would disappear into the + * pad margins --- perhaps permanently, since encoders & decoders may not + * bother to preserve DCT blocks that appear to be completely outside the + * nominal image area. So, we have to exclude any partial iMCUs from the + * basic transformation. + * + * Transpose is the only transformation that can handle partial iMCUs at the + * right and bottom edges completely cleanly. flip_h can flip partial iMCUs + * at the bottom, but leaves any partial iMCUs at the right edge untouched. + * Similarly flip_v leaves any partial iMCUs at the bottom edge untouched. + * The other transforms are defined as combinations of these basic transforms + * and process edge blocks in a way that preserves the equivalence. + * + * The "trim" option causes untransformable partial iMCUs to be dropped; + * this is not strictly lossless, but it usually gives the best-looking + * result for odd-size images. Note that when this option is active, + * the expected mathematical equivalences between the transforms may not hold. + * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim + * followed by -rot 180 -trim trims both edges.) + * + * We also offer a lossless-crop option, which discards data outside a given + * image region but losslessly preserves what is inside. Like the rotate and + * flip transforms, lossless crop is restricted by the current JPEG format: the + * upper left corner of the selected region must fall on an iMCU boundary. If + * this does not hold for the given crop parameters, we silently move the upper + * left corner up and/or left to make it so, simultaneously increasing the + * region dimensions to keep the lower right crop corner unchanged. (Thus, the + * output image covers at least the requested region, but may cover more.) + * The adjustment of the region dimensions may be optionally disabled. + * + * A complementary lossless-wipe option is provided to discard (gray out) data + * inside a given image region while losslessly preserving what is outside. + * + * We also provide a lossless-resize option, which is kind of a lossless-crop + * operation in the DCT coefficient block domain - it discards higher-order + * coefficients and losslessly preserves lower-order coefficients of a + * sub-block. + * + * Rotate/flip transform, resize, and crop can be requested together in a + * single invocation. The crop is applied last --- that is, the crop region + * is specified in terms of the destination image after transform/resize. + * + * We also offer a "force to grayscale" option, which simply discards the + * chrominance channels of a YCbCr image. This is lossless in the sense that + * the luminance channel is preserved exactly. It's not the same kind of + * thing as the rotate/flip transformations, but it's convenient to handle it + * as part of this package, mainly because the transformation routines have to + * be aware of the option to know how many components to work on. + */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jtransform_parse_crop_spec jTrParCrop +#define jtransform_request_workspace jTrRequest +#define jtransform_adjust_parameters jTrAdjust +#define jtransform_execute_transform jTrExec +#define jtransform_perfect_transform jTrPerfect +#define jcopy_markers_setup jCMrkSetup +#define jcopy_markers_execute jCMrkExec +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* + * Codes for supported types of image transformations. + */ + +typedef enum { + JXFORM_NONE, /* no transformation */ + JXFORM_FLIP_H, /* horizontal flip */ + JXFORM_FLIP_V, /* vertical flip */ + JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ + JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */ + JXFORM_ROT_90, /* 90-degree clockwise rotation */ + JXFORM_ROT_180, /* 180-degree rotation */ + JXFORM_ROT_270, /* 270-degree clockwise (or 90 ccw) */ + JXFORM_WIPE /* wipe */ +} JXFORM_CODE; + +/* + * Codes for crop parameters, which can individually be unspecified, + * positive or negative for xoffset or yoffset, + * positive or forced for width or height. + */ + +typedef enum { + JCROP_UNSET, + JCROP_POS, + JCROP_NEG, + JCROP_FORCE +} JCROP_CODE; + +/* + * Transform parameters struct. + * NB: application must not change any elements of this struct after + * calling jtransform_request_workspace. + */ + +typedef struct { + /* Options: set by caller */ + JXFORM_CODE transform; /* image transform operator */ + boolean perfect; /* if TRUE, fail if partial MCUs are requested */ + boolean trim; /* if TRUE, trim partial MCUs as needed */ + boolean force_grayscale; /* if TRUE, convert color image to grayscale */ + boolean crop; /* if TRUE, crop or wipe source image */ + + /* Crop parameters: application need not set these unless crop is TRUE. + * These can be filled in by jtransform_parse_crop_spec(). + */ + JDIMENSION crop_width; /* Width of selected region */ + JCROP_CODE crop_width_set; /* (forced disables adjustment) */ + JDIMENSION crop_height; /* Height of selected region */ + JCROP_CODE crop_height_set; /* (forced disables adjustment) */ + JDIMENSION crop_xoffset; /* X offset of selected region */ + JCROP_CODE crop_xoffset_set; /* (negative measures from right edge) */ + JDIMENSION crop_yoffset; /* Y offset of selected region */ + JCROP_CODE crop_yoffset_set; /* (negative measures from bottom edge) */ + + /* Internal workspace: caller should not touch these */ + int num_components; /* # of components in workspace */ + jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */ + JDIMENSION output_width; /* cropped destination dimensions */ + JDIMENSION output_height; + JDIMENSION x_crop_offset; /* destination crop offsets measured in iMCUs */ + JDIMENSION y_crop_offset; + JDIMENSION drop_width; /* drop/wipe dimensions measured in iMCUs */ + JDIMENSION drop_height; + int iMCU_sample_width; /* destination iMCU size */ + int iMCU_sample_height; +} jpeg_transform_info; + + +#if TRANSFORMS_SUPPORTED + +/* Parse a crop specification (written in X11 geometry style) */ +EXTERN(boolean) jtransform_parse_crop_spec + JPP((jpeg_transform_info *info, const char *spec)); +/* Request any required workspace */ +EXTERN(boolean) jtransform_request_workspace + JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info)); +/* Adjust output image parameters */ +EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); +/* Execute the actual transformation, if any */ +EXTERN(void) jtransform_execute_transform + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); +/* Determine whether lossless transformation is perfectly + * possible for a specified image and transformation. + */ +EXTERN(boolean) jtransform_perfect_transform + JPP((JDIMENSION image_width, JDIMENSION image_height, + int MCU_width, int MCU_height, + JXFORM_CODE transform)); + +/* jtransform_execute_transform used to be called + * jtransform_execute_transformation, but some compilers complain about + * routine names that long. This macro is here to avoid breaking any + * old source code that uses the original name... + */ +#define jtransform_execute_transformation jtransform_execute_transform + +#endif /* TRANSFORMS_SUPPORTED */ + + +/* + * Support for copying optional markers from source to destination file. + */ + +typedef enum { + JCOPYOPT_NONE, /* copy no optional markers */ + JCOPYOPT_COMMENTS, /* copy only comment (COM) markers */ + JCOPYOPT_ALL /* copy all optional markers */ +} JCOPY_OPTION; + +#define JCOPYOPT_DEFAULT JCOPYOPT_COMMENTS /* recommended default */ + +/* Setup decompression object to save desired markers in memory */ +EXTERN(void) jcopy_markers_setup + JPP((j_decompress_ptr srcinfo, JCOPY_OPTION option)); +/* Copy markers saved in the given source object to the destination object */ +EXTERN(void) jcopy_markers_execute + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JCOPY_OPTION option)); diff --git a/source/Irrlicht/jpeglib/usage.txt b/source/Irrlicht/jpeglib/usage.txt new file mode 100644 index 00000000..75140e59 --- /dev/null +++ b/source/Irrlicht/jpeglib/usage.txt @@ -0,0 +1,677 @@ +USAGE instructions for the Independent JPEG Group's JPEG software +================================================================= + +This file describes usage of the JPEG conversion programs cjpeg and djpeg, +as well as the utility programs jpegtran, rdjpgcom and wrjpgcom. (See +the other documentation files if you wish to use the JPEG library within +your own programs.) + +If you are on a Unix machine you may prefer to read the Unix-style manual +pages in files cjpeg.1, djpeg.1, jpegtran.1, rdjpgcom.1, wrjpgcom.1. + + +INTRODUCTION + +These programs implement JPEG image encoding, decoding, and transcoding. +JPEG (pronounced "jay-peg") is a standardized compression method for +full-color and gray-scale images. + + +GENERAL USAGE + +We provide two programs, cjpeg to compress an image file into JPEG format, +and djpeg to decompress a JPEG file back into a conventional image format. + +On Unix-like systems, you say: + cjpeg [switches] [imagefile] >jpegfile +or + djpeg [switches] [jpegfile] >imagefile +The programs read the specified input file, or standard input if none is +named. They always write to standard output (with trace/error messages to +standard error). These conventions are handy for piping images between +programs. + +On most non-Unix systems, you say: + cjpeg [switches] imagefile jpegfile +or + djpeg [switches] jpegfile imagefile +i.e., both the input and output files are named on the command line. This +style is a little more foolproof, and it loses no functionality if you don't +have pipes. (You can get this style on Unix too, if you prefer, by defining +TWO_FILE_COMMANDLINE when you compile the programs; see install.txt.) + +You can also say: + cjpeg [switches] -outfile jpegfile imagefile +or + djpeg [switches] -outfile imagefile jpegfile +This syntax works on all systems, so it is useful for scripts. + +The currently supported image file formats are: PPM (PBMPLUS color format), +PGM (PBMPLUS gray-scale format), BMP, Targa, and RLE (Utah Raster Toolkit +format). (RLE is supported only if the URT library is available.) +cjpeg recognizes the input image format automatically, with the exception +of some Targa-format files. You have to tell djpeg which format to generate. + +JPEG files are in the defacto standard JFIF file format. There are other, +less widely used JPEG-based file formats, but we don't support them. + +All switch names may be abbreviated; for example, -grayscale may be written +-gray or -gr. Most of the "basic" switches can be abbreviated to as little as +one letter. Upper and lower case are equivalent (-BMP is the same as -bmp). +British spellings are also accepted (e.g., -greyscale), though for brevity +these are not mentioned below. + + +CJPEG DETAILS + +The basic command line switches for cjpeg are: + + -quality N[,...] Scale quantization tables to adjust image quality. + Quality is 0 (worst) to 100 (best); default is 75. + (See below for more info.) + + -grayscale Create monochrome JPEG file from color input. + Be sure to use this switch when compressing a grayscale + BMP file, because cjpeg isn't bright enough to notice + whether a BMP file uses only shades of gray. By + saying -grayscale, you'll get a smaller JPEG file that + takes less time to process. + + -rgb Create RGB JPEG file. + Using this switch suppresses the conversion from RGB + colorspace input to the default YCbCr JPEG colorspace. + You can use this switch in combination with the + -block N switch (see below) for lossless JPEG coding. + See also the -rgb1 switch below. + + -optimize Perform optimization of entropy encoding parameters. + Without this, default encoding parameters are used. + -optimize usually makes the JPEG file a little smaller, + but cjpeg runs somewhat slower and needs much more + memory. Image quality and speed of decompression are + unaffected by -optimize. + + -progressive Create progressive JPEG file (see below). + + -scale M/N Scale the output image by a factor M/N. Currently + supported scale factors are M/N with all N from 1 to + 16, where M is the destination DCT size, which is 8 by + default (see -block N switch below). + + -targa Input file is Targa format. Targa files that contain + an "identification" field will not be automatically + recognized by cjpeg; for such files you must specify + -targa to make cjpeg treat the input as Targa format. + For most Targa files, you won't need this switch. + +The -quality switch lets you trade off compressed file size against quality of +the reconstructed image: the higher the quality setting, the larger the JPEG +file, and the closer the output image will be to the original input. Normally +you want to use the lowest quality setting (smallest file) that decompresses +into something visually indistinguishable from the original image. For this +purpose the quality setting should be between 50 and 95; the default of 75 is +often about right. If you see defects at -quality 75, then go up 5 or 10 +counts at a time until you are happy with the output image. (The optimal +setting will vary from one image to another.) + +-quality 100 will generate a quantization table of all 1's, minimizing loss +in the quantization step (but there is still information loss in subsampling, +as well as roundoff error). This setting is mainly of interest for +experimental purposes. Quality values above about 95 are NOT recommended for +normal use; the compressed file size goes up dramatically for hardly any gain +in output image quality. + +In the other direction, quality values below 50 will produce very small files +of low image quality. Settings around 5 to 10 might be useful in preparing an +index of a large image library, for example. Try -quality 2 (or so) for some +amusing Cubist effects. (Note: quality values below about 25 generate 2-byte +quantization tables, which are considered optional in the JPEG standard. +cjpeg emits a warning message when you give such a quality value, because some +other JPEG programs may be unable to decode the resulting file. Use -baseline +if you need to ensure compatibility at low quality values.) + +The -quality option has been extended in IJG version 7 for support of separate +quality settings for luminance and chrominance (or in general, for every +provided quantization table slot). This feature is useful for high-quality +applications which cannot accept the damage of color data by coarse +subsampling settings. You can now easily reduce the color data amount more +smoothly with finer control without separate subsampling. The resulting file +is fully compliant with standard JPEG decoders. +Note that the -quality ratings refer to the quantization table slots, and that +the last value is replicated if there are more q-table slots than parameters. +The default q-table slots are 0 for luminance and 1 for chrominance with +default tables as given in the JPEG standard. This is compatible with the old +behaviour in case that only one parameter is given, which is then used for +both luminance and chrominance (slots 0 and 1). More or custom quantization +tables can be set with -qtables and assigned to components with -qslots +parameter (see the "wizard" switches below). +CAUTION: You must explicitly add -sample 1x1 for efficient separate color +quality selection, since the default value used by library is 2x2! + +The -progressive switch creates a "progressive JPEG" file. In this type of +JPEG file, the data is stored in multiple scans of increasing quality. If the +file is being transmitted over a slow communications link, the decoder can use +the first scan to display a low-quality image very quickly, and can then +improve the display with each subsequent scan. The final image is exactly +equivalent to a standard JPEG file of the same quality setting, and the total +file size is about the same --- often a little smaller. + +Switches for advanced users: + + -arithmetic Use arithmetic coding. + CAUTION: arithmetic coded JPEG is not yet widely + implemented, so many decoders will be unable to + view an arithmetic coded JPEG file at all. + + -block N Set DCT block size. All N from 1 to 16 are possible. + Default is 8 (baseline format). + Larger values produce higher compression, + smaller values produce higher quality + (exact DCT stage possible with 1 or 2; with the + default quality of 75 and default Luminance qtable + the DCT+Quantization stage is lossless for N=1). + CAUTION: An implementation of the JPEG SmartScale + extension is required for this feature. SmartScale + enabled JPEG is not yet widely implemented, so many + decoders will be unable to view a SmartScale extended + JPEG file at all. + + -rgb1 Create RGB JPEG file with reversible color transform. + Works like the -rgb switch (see above) and inserts a + simple reversible color transform into the processing + which significantly improves the compression. + Use this switch in combination with the -block N + switch (see above) for lossless JPEG coding. + CAUTION: A decoder with inverse color transform + support is required for this feature. Reversible + color transform support is not yet widely implemented, + so many decoders will be unable to view a reversible + color transformed JPEG file at all. + + -bgycc Create big gamut YCC JPEG file. + In this type of encoding the color difference + components are quantized further by a factor of 2 + compared to the normal Cb/Cr values, thus creating + space to allow larger color values with higher + saturation than the normal gamut limits to be encoded. + In order to compensate for the loss of color fidelity + compared to a normal YCC encoded file, the color + quantization tables can be adjusted accordingly. + For example, cjpeg -bgycc -quality 80,90 will give + similar results as cjpeg -quality 80. + CAUTION: For correct decompression a decoder with big + gamut YCC support (JFIF version 2) is required. + An old decoder may or may not display a big gamut YCC + encoded JPEG file, depending on JFIF version check + and corresponding warning/error configuration. + In case of a granted decompression the old decoder + will display the image with half saturated colors. + + -dct int Use integer DCT method (default). + -dct fast Use fast integer DCT (less accurate). + -dct float Use floating-point DCT method. + The float method is very slightly more accurate than + the int method, but is much slower unless your machine + has very fast floating-point hardware. Also note that + results of the floating-point method may vary slightly + across machines, while the integer methods should give + the same results everywhere. The fast integer method + is much less accurate than the other two. + + -nosmooth Don't use high-quality downsampling. + + -restart N Emit a JPEG restart marker every N MCU rows, or every + N MCU blocks if "B" is attached to the number. + -restart 0 (the default) means no restart markers. + + -smooth N Smooth the input image to eliminate dithering noise. + N, ranging from 1 to 100, indicates the strength of + smoothing. 0 (the default) means no smoothing. + + -maxmemory N Set limit for amount of memory to use in processing + large images. Value is in thousands of bytes, or + millions of bytes if "M" is attached to the number. + For example, -max 4m selects 4000000 bytes. If more + space is needed, temporary files will be used. + + -verbose Enable debug printout. More -v's give more printout. + or -debug Also, version information is printed at startup. + +The -restart option inserts extra markers that allow a JPEG decoder to +resynchronize after a transmission error. Without restart markers, any damage +to a compressed file will usually ruin the image from the point of the error +to the end of the image; with restart markers, the damage is usually confined +to the portion of the image up to the next restart marker. Of course, the +restart markers occupy extra space. We recommend -restart 1 for images that +will be transmitted across unreliable networks such as Usenet. + +The -smooth option filters the input to eliminate fine-scale noise. This is +often useful when converting dithered images to JPEG: a moderate smoothing +factor of 10 to 50 gets rid of dithering patterns in the input file, resulting +in a smaller JPEG file and a better-looking image. Too large a smoothing +factor will visibly blur the image, however. + +Switches for wizards: + + -baseline Force baseline-compatible quantization tables to be + generated. This clamps quantization values to 8 bits + even at low quality settings. (This switch is poorly + named, since it does not ensure that the output is + actually baseline JPEG. For example, you can use + -baseline and -progressive together.) + + -qtables file Use the quantization tables given in the specified + text file. + + -qslots N[,...] Select which quantization table to use for each color + component. + + -sample HxV[,...] Set JPEG sampling factors for each color component. + + -scans file Use the scan script given in the specified text file. + +The "wizard" switches are intended for experimentation with JPEG. If you +don't know what you are doing, DON'T USE THEM. These switches are documented +further in the file wizard.txt. + + +DJPEG DETAILS + +The basic command line switches for djpeg are: + + -colors N Reduce image to at most N colors. This reduces the + or -quantize N number of colors used in the output image, so that it + can be displayed on a colormapped display or stored in + a colormapped file format. For example, if you have + an 8-bit display, you'd need to reduce to 256 or fewer + colors. (-colors is the recommended name, -quantize + is provided only for backwards compatibility.) + + -fast Select recommended processing options for fast, low + quality output. (The default options are chosen for + highest quality output.) Currently, this is equivalent + to "-dct fast -nosmooth -onepass -dither ordered". + + -grayscale Force gray-scale output even if JPEG file is color. + Useful for viewing on monochrome displays; also, + djpeg runs noticeably faster in this mode. + + -scale M/N Scale the output image by a factor M/N. Currently + supported scale factors are M/N with all M from 1 to + 16, where N is the source DCT size, which is 8 for + baseline JPEG. If the /N part is omitted, then M + specifies the DCT scaled size to be applied on the + given input. For baseline JPEG this is equivalent to + M/8 scaling, since the source DCT size for baseline + JPEG is 8. Scaling is handy if the image is larger + than your screen; also, djpeg runs much faster when + scaling down the output. + + -bmp Select BMP output format (Windows flavor). 8-bit + colormapped format is emitted if -colors or -grayscale + is specified, or if the JPEG file is gray-scale; + otherwise, 24-bit full-color format is emitted. + + -gif Select GIF output format. Since GIF does not support + more than 256 colors, -colors 256 is assumed (unless + you specify a smaller number of colors). If you + specify -fast, the default number of colors is 216. + + -os2 Select BMP output format (OS/2 1.x flavor). 8-bit + colormapped format is emitted if -colors or -grayscale + is specified, or if the JPEG file is gray-scale; + otherwise, 24-bit full-color format is emitted. + + -pnm Select PBMPLUS (PPM/PGM) output format (this is the + default format). PGM is emitted if the JPEG file is + gray-scale or if -grayscale is specified; otherwise + PPM is emitted. + + -rle Select RLE output format. (Requires URT library.) + + -targa Select Targa output format. Gray-scale format is + emitted if the JPEG file is gray-scale or if + -grayscale is specified; otherwise, colormapped format + is emitted if -colors is specified; otherwise, 24-bit + full-color format is emitted. + +Switches for advanced users: + + -dct int Use integer DCT method (default). + -dct fast Use fast integer DCT (less accurate). + -dct float Use floating-point DCT method. + The float method is very slightly more accurate than + the int method, but is much slower unless your machine + has very fast floating-point hardware. Also note that + results of the floating-point method may vary slightly + across machines, while the integer methods should give + the same results everywhere. The fast integer method + is much less accurate than the other two. + + -dither fs Use Floyd-Steinberg dithering in color quantization. + -dither ordered Use ordered dithering in color quantization. + -dither none Do not use dithering in color quantization. + By default, Floyd-Steinberg dithering is applied when + quantizing colors; this is slow but usually produces + the best results. Ordered dither is a compromise + between speed and quality; no dithering is fast but + usually looks awful. Note that these switches have + no effect unless color quantization is being done. + Ordered dither is only available in -onepass mode. + + -map FILE Quantize to the colors used in the specified image + file. This is useful for producing multiple files + with identical color maps, or for forcing a predefined + set of colors to be used. The FILE must be a GIF + or PPM file. This option overrides -colors and + -onepass. + + -nosmooth Don't use high-quality upsampling. + + -onepass Use one-pass instead of two-pass color quantization. + The one-pass method is faster and needs less memory, + but it produces a lower-quality image. -onepass is + ignored unless you also say -colors N. Also, + the one-pass method is always used for gray-scale + output (the two-pass method is no improvement then). + + -maxmemory N Set limit for amount of memory to use in processing + large images. Value is in thousands of bytes, or + millions of bytes if "M" is attached to the number. + For example, -max 4m selects 4000000 bytes. If more + space is needed, temporary files will be used. + + -verbose Enable debug printout. More -v's give more printout. + or -debug Also, version information is printed at startup. + + +HINTS FOR CJPEG + +Color GIF files are not the ideal input for JPEG; JPEG is really intended for +compressing full-color (24-bit) images. In particular, don't try to convert +cartoons, line drawings, and other images that have only a few distinct +colors. GIF works great on these, JPEG does not. If you want to convert a +GIF to JPEG, you should experiment with cjpeg's -quality and -smooth options +to get a satisfactory conversion. -smooth 10 or so is often helpful. + +Avoid running an image through a series of JPEG compression/decompression +cycles. Image quality loss will accumulate; after ten or so cycles the image +may be noticeably worse than it was after one cycle. It's best to use a +lossless format while manipulating an image, then convert to JPEG format when +you are ready to file the image away. + +The -optimize option to cjpeg is worth using when you are making a "final" +version for posting or archiving. It's also a win when you are using low +quality settings to make very small JPEG files; the percentage improvement +is often a lot more than it is on larger files. (At present, -optimize +mode is always selected when generating progressive JPEG files.) + +GIF input files are no longer supported, to avoid the Unisys LZW patent +(now expired). +(Conversion of GIF files to JPEG is usually a bad idea anyway.) + + +HINTS FOR DJPEG + +To get a quick preview of an image, use the -grayscale and/or -scale switches. +"-grayscale -scale 1/8" is the fastest case. + +Several options are available that trade off image quality to gain speed. +"-fast" turns on the recommended settings. + +"-dct fast" and/or "-nosmooth" gain speed at a small sacrifice in quality. +When producing a color-quantized image, "-onepass -dither ordered" is fast but +much lower quality than the default behavior. "-dither none" may give +acceptable results in two-pass mode, but is seldom tolerable in one-pass mode. + +If you are fortunate enough to have very fast floating point hardware, +"-dct float" may be even faster than "-dct fast". But on most machines +"-dct float" is slower than "-dct int"; in this case it is not worth using, +because its theoretical accuracy advantage is too small to be significant +in practice. + +Two-pass color quantization requires a good deal of memory; on MS-DOS machines +it may run out of memory even with -maxmemory 0. In that case you can still +decompress, with some loss of image quality, by specifying -onepass for +one-pass quantization. + +To avoid the Unisys LZW patent (now expired), djpeg produces uncompressed GIF +files. These are larger than they should be, but are readable by standard GIF +decoders. + + +HINTS FOR BOTH PROGRAMS + +If more space is needed than will fit in the available main memory (as +determined by -maxmemory), temporary files will be used. (MS-DOS versions +will try to get extended or expanded memory first.) The temporary files are +often rather large: in typical cases they occupy three bytes per pixel, for +example 3*800*600 = 1.44Mb for an 800x600 image. If you don't have enough +free disk space, leave out -progressive and -optimize (for cjpeg) or specify +-onepass (for djpeg). + +On MS-DOS, the temporary files are created in the directory named by the TMP +or TEMP environment variable, or in the current directory if neither of those +exist. Amiga implementations put the temp files in the directory named by +JPEGTMP:, so be sure to assign JPEGTMP: to a disk partition with adequate free +space. + +The default memory usage limit (-maxmemory) is set when the software is +compiled. If you get an "insufficient memory" error, try specifying a smaller +-maxmemory value, even -maxmemory 0 to use the absolute minimum space. You +may want to recompile with a smaller default value if this happens often. + +On machines that have "environment" variables, you can define the environment +variable JPEGMEM to set the default memory limit. The value is specified as +described for the -maxmemory switch. JPEGMEM overrides the default value +specified when the program was compiled, and itself is overridden by an +explicit -maxmemory switch. + +On MS-DOS machines, -maxmemory is the amount of main (conventional) memory to +use. (Extended or expanded memory is also used if available.) Most +DOS-specific versions of this software do their own memory space estimation +and do not need you to specify -maxmemory. + + +JPEGTRAN + +jpegtran performs various useful transformations of JPEG files. +It can translate the coded representation from one variant of JPEG to another, +for example from baseline JPEG to progressive JPEG or vice versa. It can also +perform some rearrangements of the image data, for example turning an image +from landscape to portrait format by rotation. + +jpegtran works by rearranging the compressed data (DCT coefficients), without +ever fully decoding the image. Therefore, its transformations are lossless: +there is no image degradation at all, which would not be true if you used +djpeg followed by cjpeg to accomplish the same conversion. But by the same +token, jpegtran cannot perform lossy operations such as changing the image +quality. + +jpegtran uses a command line syntax similar to cjpeg or djpeg. +On Unix-like systems, you say: + jpegtran [switches] [inputfile] >outputfile +On most non-Unix systems, you say: + jpegtran [switches] inputfile outputfile +where both the input and output files are JPEG files. + +To specify the coded JPEG representation used in the output file, +jpegtran accepts a subset of the switches recognized by cjpeg: + -optimize Perform optimization of entropy encoding parameters. + -progressive Create progressive JPEG file. + -arithmetic Use arithmetic coding. + -restart N Emit a JPEG restart marker every N MCU rows, or every + N MCU blocks if "B" is attached to the number. + -scans file Use the scan script given in the specified text file. +See the previous discussion of cjpeg for more details about these switches. +If you specify none of these switches, you get a plain baseline-JPEG output +file. The quality setting and so forth are determined by the input file. + +The image can be losslessly transformed by giving one of these switches: + -flip horizontal Mirror image horizontally (left-right). + -flip vertical Mirror image vertically (top-bottom). + -rotate 90 Rotate image 90 degrees clockwise. + -rotate 180 Rotate image 180 degrees. + -rotate 270 Rotate image 270 degrees clockwise (or 90 ccw). + -transpose Transpose image (across UL-to-LR axis). + -transverse Transverse transpose (across UR-to-LL axis). + +The transpose transformation has no restrictions regarding image dimensions. +The other transformations operate rather oddly if the image dimensions are not +a multiple of the iMCU size (usually 8 or 16 pixels), because they can only +transform complete blocks of DCT coefficient data in the desired way. + +jpegtran's default behavior when transforming an odd-size image is designed +to preserve exact reversibility and mathematical consistency of the +transformation set. As stated, transpose is able to flip the entire image +area. Horizontal mirroring leaves any partial iMCU column at the right edge +untouched, but is able to flip all rows of the image. Similarly, vertical +mirroring leaves any partial iMCU row at the bottom edge untouched, but is +able to flip all columns. The other transforms can be built up as sequences +of transpose and flip operations; for consistency, their actions on edge +pixels are defined to be the same as the end result of the corresponding +transpose-and-flip sequence. + +For practical use, you may prefer to discard any untransformable edge pixels +rather than having a strange-looking strip along the right and/or bottom edges +of a transformed image. To do this, add the -trim switch: + -trim Drop non-transformable edge blocks. +Obviously, a transformation with -trim is not reversible, so strictly speaking +jpegtran with this switch is not lossless. Also, the expected mathematical +equivalences between the transformations no longer hold. For example, +"-rot 270 -trim" trims only the bottom edge, but "-rot 90 -trim" followed by +"-rot 180 -trim" trims both edges. + +If you are only interested in perfect transformation, add the -perfect switch: + -perfect Fails with an error if the transformation is not + perfect. +For example you may want to do + jpegtran -rot 90 -perfect foo.jpg || djpeg foo.jpg | pnmflip -r90 | cjpeg +to do a perfect rotation if available or an approximated one if not. + +We also offer a lossless-crop option, which discards data outside a given +image region but losslessly preserves what is inside. Like the rotate and +flip transforms, lossless crop is restricted by the current JPEG format: the +upper left corner of the selected region must fall on an iMCU boundary. If +this does not hold for the given crop parameters, we silently move the upper +left corner up and/or left to make it so, simultaneously increasing the +region dimensions to keep the lower right crop corner unchanged. (Thus, the +output image covers at least the requested region, but may cover more.) +The adjustment of the region dimensions may be optionally disabled. + +The image can be losslessly cropped by giving the switch: + -crop WxH+X+Y Crop to a rectangular subarea of width W, height H + starting at point X,Y. + +A complementary lossless-wipe option is provided to discard (gray out) data +inside a given image region while losslessly preserving what is outside: + -wipe WxH+X+Y Wipe (gray out) a rectangular subarea of + width W, height H starting at point X,Y. + +Other not-strictly-lossless transformation switches are: + + -grayscale Force grayscale output. +This option discards the chrominance channels if the input image is YCbCr +(ie, a standard color JPEG), resulting in a grayscale JPEG file. The +luminance channel is preserved exactly, so this is a better method of reducing +to grayscale than decompression, conversion, and recompression. This switch +is particularly handy for fixing a monochrome picture that was mistakenly +encoded as a color JPEG. (In such a case, the space savings from getting rid +of the near-empty chroma channels won't be large; but the decoding time for +a grayscale JPEG is substantially less than that for a color JPEG.) + + -scale M/N Scale the output image by a factor M/N. +Currently supported scale factors are M/N with all M from 1 to 16, where N is +the source DCT size, which is 8 for baseline JPEG. If the /N part is omitted, +then M specifies the DCT scaled size to be applied on the given input. For +baseline JPEG this is equivalent to M/8 scaling, since the source DCT size +for baseline JPEG is 8. CAUTION: An implementation of the JPEG SmartScale +extension is required for this feature. SmartScale enabled JPEG is not yet +widely implemented, so many decoders will be unable to view a SmartScale +extended JPEG file at all. + +jpegtran also recognizes these switches that control what to do with "extra" +markers, such as comment blocks: + -copy none Copy no extra markers from source file. This setting + suppresses all comments and other excess baggage + present in the source file. + -copy comments Copy only comment markers. This setting copies + comments from the source file, but discards + any other inessential (for image display) data. + -copy all Copy all extra markers. This setting preserves + miscellaneous markers found in the source file, such + as JFIF thumbnails, Exif data, and Photoshop settings. + In some files these extra markers can be sizable. +The default behavior is -copy comments. (Note: in IJG releases v6 and v6a, +jpegtran always did the equivalent of -copy none.) + +Additional switches recognized by jpegtran are: + -outfile filename + -maxmemory N + -verbose + -debug +These work the same as in cjpeg or djpeg. + + +THE COMMENT UTILITIES + +The JPEG standard allows "comment" (COM) blocks to occur within a JPEG file. +Although the standard doesn't actually define what COM blocks are for, they +are widely used to hold user-supplied text strings. This lets you add +annotations, titles, index terms, etc to your JPEG files, and later retrieve +them as text. COM blocks do not interfere with the image stored in the JPEG +file. The maximum size of a COM block is 64K, but you can have as many of +them as you like in one JPEG file. + +We provide two utility programs to display COM block contents and add COM +blocks to a JPEG file. + +rdjpgcom searches a JPEG file and prints the contents of any COM blocks on +standard output. The command line syntax is + rdjpgcom [-raw] [-verbose] [inputfilename] +The switch "-raw" (or just "-r") causes rdjpgcom to also output non-printable +characters in comments, which are normally escaped for security reasons. +The switch "-verbose" (or just "-v") causes rdjpgcom to also display the JPEG +image dimensions. If you omit the input file name from the command line, +the JPEG file is read from standard input. (This may not work on some +operating systems, if binary data can't be read from stdin.) + +wrjpgcom adds a COM block, containing text you provide, to a JPEG file. +Ordinarily, the COM block is added after any existing COM blocks, but you +can delete the old COM blocks if you wish. wrjpgcom produces a new JPEG +file; it does not modify the input file. DO NOT try to overwrite the input +file by directing wrjpgcom's output back into it; on most systems this will +just destroy your file. + +The command line syntax for wrjpgcom is similar to cjpeg's. On Unix-like +systems, it is + wrjpgcom [switches] [inputfilename] +The output file is written to standard output. The input file comes from +the named file, or from standard input if no input file is named. + +On most non-Unix systems, the syntax is + wrjpgcom [switches] inputfilename outputfilename +where both input and output file names must be given explicitly. + +wrjpgcom understands three switches: + -replace Delete any existing COM blocks from the file. + -comment "Comment text" Supply new COM text on command line. + -cfile name Read text for new COM block from named file. +(Switch names can be abbreviated.) If you have only one line of comment text +to add, you can provide it on the command line with -comment. The comment +text must be surrounded with quotes so that it is treated as a single +argument. Longer comments can be read from a text file. + +If you give neither -comment nor -cfile, then wrjpgcom will read the comment +text from standard input. (In this case an input image file name MUST be +supplied, so that the source JPEG file comes from somewhere else.) You can +enter multiple lines, up to 64KB worth. Type an end-of-file indicator +(usually control-D or control-Z) to terminate the comment text entry. + +wrjpgcom will not add a COM block if the provided comment string is empty. +Therefore -replace -comment "" can be used to delete all COM blocks from a +file. + +These utility programs do not depend on the IJG JPEG library. In +particular, the source code for rdjpgcom is intended as an illustration of +the minimum amount of code required to parse a JPEG file header correctly. diff --git a/source/Irrlicht/jpeglib/wizard.txt b/source/Irrlicht/jpeglib/wizard.txt new file mode 100644 index 00000000..54170b22 --- /dev/null +++ b/source/Irrlicht/jpeglib/wizard.txt @@ -0,0 +1,211 @@ +Advanced usage instructions for the Independent JPEG Group's JPEG software +========================================================================== + +This file describes cjpeg's "switches for wizards". + +The "wizard" switches are intended for experimentation with JPEG by persons +who are reasonably knowledgeable about the JPEG standard. If you don't know +what you are doing, DON'T USE THESE SWITCHES. You'll likely produce files +with worse image quality and/or poorer compression than you'd get from the +default settings. Furthermore, these switches must be used with caution +when making files intended for general use, because not all JPEG decoders +will support unusual JPEG parameter settings. + + +Quantization Table Adjustment +----------------------------- + +Ordinarily, cjpeg starts with a default set of tables (the same ones given +as examples in the JPEG standard) and scales them up or down according to +the -quality setting. The details of the scaling algorithm can be found in +jcparam.c. At very low quality settings, some quantization table entries +can get scaled up to values exceeding 255. Although 2-byte quantization +values are supported by the IJG software, this feature is not in baseline +JPEG and is not supported by all implementations. If you need to ensure +wide compatibility of low-quality files, you can constrain the scaled +quantization values to no more than 255 by giving the -baseline switch. +Note that use of -baseline will result in poorer quality for the same file +size, since more bits than necessary are expended on higher AC coefficients. + +You can substitute a different set of quantization values by using the +-qtables switch: + + -qtables file Use the quantization tables given in the named file. + +The specified file should be a text file containing decimal quantization +values. The file should contain one to four tables, each of 64 elements. +The tables are implicitly numbered 0,1,etc. in order of appearance. Table +entries appear in normal array order (NOT in the zigzag order in which they +will be stored in the JPEG file). + +Quantization table files are free format, in that arbitrary whitespace can +appear between numbers. Also, comments can be included: a comment starts +with '#' and extends to the end of the line. Here is an example file that +duplicates the default quantization tables: + + # Quantization tables given in JPEG spec, section K.1 + + # This is table 0 (the luminance table): + 16 11 10 16 24 40 51 61 + 12 12 14 19 26 58 60 55 + 14 13 16 24 40 57 69 56 + 14 17 22 29 51 87 80 62 + 18 22 37 56 68 109 103 77 + 24 35 55 64 81 104 113 92 + 49 64 78 87 103 121 120 101 + 72 92 95 98 112 100 103 99 + + # This is table 1 (the chrominance table): + 17 18 24 47 99 99 99 99 + 18 21 26 66 99 99 99 99 + 24 26 56 99 99 99 99 99 + 47 66 99 99 99 99 99 99 + 99 99 99 99 99 99 99 99 + 99 99 99 99 99 99 99 99 + 99 99 99 99 99 99 99 99 + 99 99 99 99 99 99 99 99 + +If the -qtables switch is used without -quality, then the specified tables +are used exactly as-is. If both -qtables and -quality are used, then the +tables taken from the file are scaled in the same fashion that the default +tables would be scaled for that quality setting. If -baseline appears, then +the quantization values are constrained to the range 1-255. + +By default, cjpeg will use quantization table 0 for luminance components and +table 1 for chrominance components. To override this choice, use the -qslots +switch: + + -qslots N[,...] Select which quantization table to use for + each color component. + +The -qslots switch specifies a quantization table number for each color +component, in the order in which the components appear in the JPEG SOF marker. +For example, to create a separate table for each of Y,Cb,Cr, you could +provide a -qtables file that defines three quantization tables and say +"-qslots 0,1,2". If -qslots gives fewer table numbers than there are color +components, then the last table number is repeated as necessary. + + +Sampling Factor Adjustment +-------------------------- + +By default, cjpeg uses 2:1 horizontal and vertical downsampling when +compressing YCbCr data, and no downsampling for all other color spaces. +You can override this default with the -sample switch: + + -sample HxV[,...] Set JPEG sampling factors for each color + component. + +The -sample switch specifies the JPEG sampling factors for each color +component, in the order in which they appear in the JPEG SOF marker. +If you specify fewer HxV pairs than there are components, the remaining +components are set to 1x1 sampling. For example, the default YCbCr setting +is equivalent to "-sample 2x2,1x1,1x1", which can be abbreviated to +"-sample 2x2". + +There are still some JPEG decoders in existence that support only 2x1 +sampling (also called 4:2:2 sampling). Compatibility with such decoders can +be achieved by specifying "-sample 2x1". This is not recommended unless +really necessary, since it increases file size and encoding/decoding time +with very little quality gain. + + +Multiple Scan / Progression Control +----------------------------------- + +By default, cjpeg emits a single-scan sequential JPEG file. The +-progressive switch generates a progressive JPEG file using a default series +of progression parameters. You can create multiple-scan sequential JPEG +files or progressive JPEG files with custom progression parameters by using +the -scans switch: + + -scans file Use the scan sequence given in the named file. + +The specified file should be a text file containing a "scan script". +The script specifies the contents and ordering of the scans to be emitted. +Each entry in the script defines one scan. A scan definition specifies +the components to be included in the scan, and for progressive JPEG it also +specifies the progression parameters Ss,Se,Ah,Al for the scan. Scan +definitions are separated by semicolons (';'). A semicolon after the last +scan definition is optional. + +Each scan definition contains one to four component indexes, optionally +followed by a colon (':') and the four progressive-JPEG parameters. The +component indexes denote which color component(s) are to be transmitted in +the scan. Components are numbered in the order in which they appear in the +JPEG SOF marker, with the first component being numbered 0. (Note that these +indexes are not the "component ID" codes assigned to the components, just +positional indexes.) + +The progression parameters for each scan are: + Ss Zigzag index of first coefficient included in scan + Se Zigzag index of last coefficient included in scan + Ah Zero for first scan of a coefficient, else Al of prior scan + Al Successive approximation low bit position for scan +If the progression parameters are omitted, the values 0,63,0,0 are used, +producing a sequential JPEG file. cjpeg automatically determines whether +the script represents a progressive or sequential file, by observing whether +Ss and Se values other than 0 and 63 appear. (The -progressive switch is +not needed to specify this; in fact, it is ignored when -scans appears.) +The scan script must meet the JPEG restrictions on progression sequences. +(cjpeg checks that the spec's requirements are obeyed.) + +Scan script files are free format, in that arbitrary whitespace can appear +between numbers and around punctuation. Also, comments can be included: a +comment starts with '#' and extends to the end of the line. For additional +legibility, commas or dashes can be placed between values. (Actually, any +single punctuation character other than ':' or ';' can be inserted.) For +example, the following two scan definitions are equivalent: + 0 1 2: 0 63 0 0; + 0,1,2 : 0-63, 0,0 ; + +Here is an example of a scan script that generates a partially interleaved +sequential JPEG file: + + 0; # Y only in first scan + 1 2; # Cb and Cr in second scan + +Here is an example of a progressive scan script using only spectral selection +(no successive approximation): + + # Interleaved DC scan for Y,Cb,Cr: + 0,1,2: 0-0, 0, 0 ; + # AC scans: + 0: 1-2, 0, 0 ; # First two Y AC coefficients + 0: 3-5, 0, 0 ; # Three more + 1: 1-63, 0, 0 ; # All AC coefficients for Cb + 2: 1-63, 0, 0 ; # All AC coefficients for Cr + 0: 6-9, 0, 0 ; # More Y coefficients + 0: 10-63, 0, 0 ; # Remaining Y coefficients + +Here is an example of a successive-approximation script. This is equivalent +to the default script used by "cjpeg -progressive" for YCbCr images: + + # Initial DC scan for Y,Cb,Cr (lowest bit not sent) + 0,1,2: 0-0, 0, 1 ; + # First AC scan: send first 5 Y AC coefficients, minus 2 lowest bits: + 0: 1-5, 0, 2 ; + # Send all Cr,Cb AC coefficients, minus lowest bit: + # (chroma data is usually too small to be worth subdividing further; + # but note we send Cr first since eye is least sensitive to Cb) + 2: 1-63, 0, 1 ; + 1: 1-63, 0, 1 ; + # Send remaining Y AC coefficients, minus 2 lowest bits: + 0: 6-63, 0, 2 ; + # Send next-to-lowest bit of all Y AC coefficients: + 0: 1-63, 2, 1 ; + # At this point we've sent all but the lowest bit of all coefficients. + # Send lowest bit of DC coefficients + 0,1,2: 0-0, 1, 0 ; + # Send lowest bit of AC coefficients + 2: 1-63, 1, 0 ; + 1: 1-63, 1, 0 ; + # Y AC lowest bit scan is last; it's usually the largest scan + 0: 1-63, 1, 0 ; + +It may be worth pointing out that this script is tuned for quality settings +of around 50 to 75. For lower quality settings, you'd probably want to use +a script with fewer stages of successive approximation (otherwise the +initial scans will be really bad). For higher quality settings, you might +want to use more stages of successive approximation (so that the initial +scans are not too large). diff --git a/source/Irrlicht/jpeglib/wrbmp.c b/source/Irrlicht/jpeglib/wrbmp.c new file mode 100644 index 00000000..2b8146e2 --- /dev/null +++ b/source/Irrlicht/jpeglib/wrbmp.c @@ -0,0 +1,442 @@ +/* + * wrbmp.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in Microsoft "BMP" + * format (MS Windows 3.x and OS/2 1.x flavors). + * Either 8-bit colormapped or 24-bit full-color format can be written. + * No compression is supported. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + * + * This code contributed by James Arthur Boucher. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef BMP_SUPPORTED + + +/* + * To support 12-bit JPEG data, we'd have to scale output down to 8 bits. + * This is not yet implemented. + */ + +#if BITS_IN_JSAMPLE != 8 + Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */ +#endif + +/* + * Since BMP stores scanlines bottom-to-top, we have to invert the image + * from JPEG's top-to-bottom order. To do this, we save the outgoing data + * in a virtual array during put_pixel_row calls, then actually emit the + * BMP file during finish_output. The virtual array contains one JSAMPLE per + * pixel if the output is grayscale or colormapped, three if it is full color. + */ + +/* Private version of data destination object */ + +typedef struct { + struct djpeg_dest_struct pub; /* public fields */ + + boolean is_os2; /* saves the OS2 format request flag */ + + jvirt_sarray_ptr whole_image; /* needed to reverse row order */ + JDIMENSION data_width; /* JSAMPLEs per row */ + JDIMENSION row_width; /* physical width of one row in the BMP file */ + int pad_bytes; /* number of padding bytes needed per row */ + JDIMENSION cur_output_row; /* next row# to write to virtual array */ +} bmp_dest_struct; + +typedef bmp_dest_struct * bmp_dest_ptr; + + +/* Forward declarations */ +LOCAL(void) write_colormap + JPP((j_decompress_ptr cinfo, bmp_dest_ptr dest, + int map_colors, int map_entry_size)); + + +/* + * Write some pixel data. + * In this module rows_supplied will always be 1. + */ + +METHODDEF(void) +put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +/* This version is for writing 24-bit pixels */ +{ + bmp_dest_ptr dest = (bmp_dest_ptr) dinfo; + JSAMPARRAY image_ptr; + register JSAMPROW inptr, outptr; + register JDIMENSION col; + int pad; + + /* Access next row in virtual array */ + image_ptr = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->whole_image, + dest->cur_output_row, (JDIMENSION) 1, TRUE); + dest->cur_output_row++; + + /* Transfer data. Note destination values must be in BGR order + * (even though Microsoft's own documents say the opposite). + */ + inptr = dest->pub.buffer[0]; + outptr = image_ptr[0]; + for (col = cinfo->output_width; col > 0; col--) { + outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */ + outptr[1] = *inptr++; + outptr[0] = *inptr++; + outptr += 3; + } + + /* Zero out the pad bytes. */ + pad = dest->pad_bytes; + while (--pad >= 0) + *outptr++ = 0; +} + +METHODDEF(void) +put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +/* This version is for grayscale OR quantized color output */ +{ + bmp_dest_ptr dest = (bmp_dest_ptr) dinfo; + JSAMPARRAY image_ptr; + register JSAMPROW inptr, outptr; + register JDIMENSION col; + int pad; + + /* Access next row in virtual array */ + image_ptr = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->whole_image, + dest->cur_output_row, (JDIMENSION) 1, TRUE); + dest->cur_output_row++; + + /* Transfer data. */ + inptr = dest->pub.buffer[0]; + outptr = image_ptr[0]; + for (col = cinfo->output_width; col > 0; col--) { + *outptr++ = *inptr++; /* can omit GETJSAMPLE() safely */ + } + + /* Zero out the pad bytes. */ + pad = dest->pad_bytes; + while (--pad >= 0) + *outptr++ = 0; +} + + +/* + * Startup: normally writes the file header. + * In this module we may as well postpone everything until finish_output. + */ + +METHODDEF(void) +start_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + /* no work here */ +} + + +/* + * Finish up at the end of the file. + * + * Here is where we really output the BMP file. + * + * First, routines to write the Windows and OS/2 variants of the file header. + */ + +LOCAL(void) +write_bmp_header (j_decompress_ptr cinfo, bmp_dest_ptr dest) +/* Write a Windows-style BMP file header, including colormap if needed */ +{ + char bmpfileheader[14]; + char bmpinfoheader[40]; +#define PUT_2B(array,offset,value) \ + (array[offset] = (char) ((value) & 0xFF), \ + array[offset+1] = (char) (((value) >> 8) & 0xFF)) +#define PUT_4B(array,offset,value) \ + (array[offset] = (char) ((value) & 0xFF), \ + array[offset+1] = (char) (((value) >> 8) & 0xFF), \ + array[offset+2] = (char) (((value) >> 16) & 0xFF), \ + array[offset+3] = (char) (((value) >> 24) & 0xFF)) + INT32 headersize, bfSize; + int bits_per_pixel, cmap_entries; + + /* Compute colormap size and total file size */ + if (cinfo->out_color_space == JCS_RGB) { + if (cinfo->quantize_colors) { + /* Colormapped RGB */ + bits_per_pixel = 8; + cmap_entries = 256; + } else { + /* Unquantized, full color RGB */ + bits_per_pixel = 24; + cmap_entries = 0; + } + } else { + /* Grayscale output. We need to fake a 256-entry colormap. */ + bits_per_pixel = 8; + cmap_entries = 256; + } + /* File size */ + headersize = 14 + 40 + cmap_entries * 4; /* Header and colormap */ + bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height; + + /* Set unused fields of header to 0 */ + MEMZERO(bmpfileheader, SIZEOF(bmpfileheader)); + MEMZERO(bmpinfoheader, SIZEOF(bmpinfoheader)); + + /* Fill the file header */ + bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */ + bmpfileheader[1] = 0x4D; + PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */ + /* we leave bfReserved1 & bfReserved2 = 0 */ + PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */ + + /* Fill the info header (Microsoft calls this a BITMAPINFOHEADER) */ + PUT_2B(bmpinfoheader, 0, 40); /* biSize */ + PUT_4B(bmpinfoheader, 4, cinfo->output_width); /* biWidth */ + PUT_4B(bmpinfoheader, 8, cinfo->output_height); /* biHeight */ + PUT_2B(bmpinfoheader, 12, 1); /* biPlanes - must be 1 */ + PUT_2B(bmpinfoheader, 14, bits_per_pixel); /* biBitCount */ + /* we leave biCompression = 0, for none */ + /* we leave biSizeImage = 0; this is correct for uncompressed data */ + if (cinfo->density_unit == 2) { /* if have density in dots/cm, then */ + PUT_4B(bmpinfoheader, 24, (INT32) (cinfo->X_density*100)); /* XPels/M */ + PUT_4B(bmpinfoheader, 28, (INT32) (cinfo->Y_density*100)); /* XPels/M */ + } + PUT_2B(bmpinfoheader, 32, cmap_entries); /* biClrUsed */ + /* we leave biClrImportant = 0 */ + + if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14) + ERREXIT(cinfo, JERR_FILE_WRITE); + if (JFWRITE(dest->pub.output_file, bmpinfoheader, 40) != (size_t) 40) + ERREXIT(cinfo, JERR_FILE_WRITE); + + if (cmap_entries > 0) + write_colormap(cinfo, dest, cmap_entries, 4); +} + + +LOCAL(void) +write_os2_header (j_decompress_ptr cinfo, bmp_dest_ptr dest) +/* Write an OS2-style BMP file header, including colormap if needed */ +{ + char bmpfileheader[14]; + char bmpcoreheader[12]; + INT32 headersize, bfSize; + int bits_per_pixel, cmap_entries; + + /* Compute colormap size and total file size */ + if (cinfo->out_color_space == JCS_RGB) { + if (cinfo->quantize_colors) { + /* Colormapped RGB */ + bits_per_pixel = 8; + cmap_entries = 256; + } else { + /* Unquantized, full color RGB */ + bits_per_pixel = 24; + cmap_entries = 0; + } + } else { + /* Grayscale output. We need to fake a 256-entry colormap. */ + bits_per_pixel = 8; + cmap_entries = 256; + } + /* File size */ + headersize = 14 + 12 + cmap_entries * 3; /* Header and colormap */ + bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height; + + /* Set unused fields of header to 0 */ + MEMZERO(bmpfileheader, SIZEOF(bmpfileheader)); + MEMZERO(bmpcoreheader, SIZEOF(bmpcoreheader)); + + /* Fill the file header */ + bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */ + bmpfileheader[1] = 0x4D; + PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */ + /* we leave bfReserved1 & bfReserved2 = 0 */ + PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */ + + /* Fill the info header (Microsoft calls this a BITMAPCOREHEADER) */ + PUT_2B(bmpcoreheader, 0, 12); /* bcSize */ + PUT_2B(bmpcoreheader, 4, cinfo->output_width); /* bcWidth */ + PUT_2B(bmpcoreheader, 6, cinfo->output_height); /* bcHeight */ + PUT_2B(bmpcoreheader, 8, 1); /* bcPlanes - must be 1 */ + PUT_2B(bmpcoreheader, 10, bits_per_pixel); /* bcBitCount */ + + if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14) + ERREXIT(cinfo, JERR_FILE_WRITE); + if (JFWRITE(dest->pub.output_file, bmpcoreheader, 12) != (size_t) 12) + ERREXIT(cinfo, JERR_FILE_WRITE); + + if (cmap_entries > 0) + write_colormap(cinfo, dest, cmap_entries, 3); +} + + +/* + * Write the colormap. + * Windows uses BGR0 map entries; OS/2 uses BGR entries. + */ + +LOCAL(void) +write_colormap (j_decompress_ptr cinfo, bmp_dest_ptr dest, + int map_colors, int map_entry_size) +{ + JSAMPARRAY colormap = cinfo->colormap; + int num_colors = cinfo->actual_number_of_colors; + FILE * outfile = dest->pub.output_file; + int i; + + if (colormap != NULL) { + if (cinfo->out_color_components == 3) { + /* Normal case with RGB colormap */ + for (i = 0; i < num_colors; i++) { + putc(GETJSAMPLE(colormap[2][i]), outfile); + putc(GETJSAMPLE(colormap[1][i]), outfile); + putc(GETJSAMPLE(colormap[0][i]), outfile); + if (map_entry_size == 4) + putc(0, outfile); + } + } else { + /* Grayscale colormap (only happens with grayscale quantization) */ + for (i = 0; i < num_colors; i++) { + putc(GETJSAMPLE(colormap[0][i]), outfile); + putc(GETJSAMPLE(colormap[0][i]), outfile); + putc(GETJSAMPLE(colormap[0][i]), outfile); + if (map_entry_size == 4) + putc(0, outfile); + } + } + } else { + /* If no colormap, must be grayscale data. Generate a linear "map". */ + for (i = 0; i < 256; i++) { + putc(i, outfile); + putc(i, outfile); + putc(i, outfile); + if (map_entry_size == 4) + putc(0, outfile); + } + } + /* Pad colormap with zeros to ensure specified number of colormap entries */ + if (i > map_colors) + ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, i); + for (; i < map_colors; i++) { + putc(0, outfile); + putc(0, outfile); + putc(0, outfile); + if (map_entry_size == 4) + putc(0, outfile); + } +} + + +METHODDEF(void) +finish_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + bmp_dest_ptr dest = (bmp_dest_ptr) dinfo; + register FILE * outfile = dest->pub.output_file; + JSAMPARRAY image_ptr; + register JSAMPROW data_ptr; + JDIMENSION row; + register JDIMENSION col; + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + + /* Write the header and colormap */ + if (dest->is_os2) + write_os2_header(cinfo, dest); + else + write_bmp_header(cinfo, dest); + + /* Write the file body from our virtual array */ + for (row = cinfo->output_height; row > 0; row--) { + if (progress != NULL) { + progress->pub.pass_counter = (long) (cinfo->output_height - row); + progress->pub.pass_limit = (long) cinfo->output_height; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } + image_ptr = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->whole_image, row-1, (JDIMENSION) 1, FALSE); + data_ptr = image_ptr[0]; + for (col = dest->row_width; col > 0; col--) { + putc(GETJSAMPLE(*data_ptr), outfile); + data_ptr++; + } + } + if (progress != NULL) + progress->completed_extra_passes++; + + /* Make sure we wrote the output file OK */ + fflush(outfile); + if (ferror(outfile)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for BMP format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2) +{ + bmp_dest_ptr dest; + JDIMENSION row_width; + + /* Create module interface object, fill in method pointers */ + dest = (bmp_dest_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(bmp_dest_struct)); + dest->pub.start_output = start_output_bmp; + dest->pub.finish_output = finish_output_bmp; + dest->is_os2 = is_os2; + + if (cinfo->out_color_space == JCS_GRAYSCALE) { + dest->pub.put_pixel_rows = put_gray_rows; + } else if (cinfo->out_color_space == JCS_RGB) { + if (cinfo->quantize_colors) + dest->pub.put_pixel_rows = put_gray_rows; + else + dest->pub.put_pixel_rows = put_pixel_rows; + } else { + ERREXIT(cinfo, JERR_BMP_COLORSPACE); + } + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + /* Determine width of rows in the BMP file (padded to 4-byte boundary). */ + row_width = cinfo->output_width * cinfo->output_components; + dest->data_width = row_width; + while ((row_width & 3) != 0) row_width++; + dest->row_width = row_width; + dest->pad_bytes = (int) (row_width - dest->data_width); + + /* Allocate space for inversion array, prepare for write pass */ + dest->whole_image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + row_width, cinfo->output_height, (JDIMENSION) 1); + dest->cur_output_row = 0; + if (cinfo->progress != NULL) { + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + progress->total_extra_passes++; /* count file input as separate pass */ + } + + /* Create decompressor output buffer. */ + dest->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, row_width, (JDIMENSION) 1); + dest->pub.buffer_height = 1; + + return (djpeg_dest_ptr) dest; +} + +#endif /* BMP_SUPPORTED */ diff --git a/source/Irrlicht/jpeglib/wrgif.c b/source/Irrlicht/jpeglib/wrgif.c new file mode 100644 index 00000000..13f953b5 --- /dev/null +++ b/source/Irrlicht/jpeglib/wrgif.c @@ -0,0 +1,399 @@ +/* + * wrgif.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in GIF format. + * + ************************************************************************** + * NOTE: to avoid entanglements with Unisys' patent on LZW compression, * + * this code has been modified to output "uncompressed GIF" files. * + * There is no trace of the LZW algorithm in this file. * + ************************************************************************** + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + */ + +/* + * This code is loosely based on ppmtogif from the PBMPLUS distribution + * of Feb. 1991. That file contains the following copyright notice: + * Based on GIFENCODE by David Rowley . + * Lempel-Ziv compression based on "compress" by Spencer W. Thomas et al. + * Copyright (C) 1989 by Jef Poskanzer. + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. This software is provided "as is" without express or + * implied warranty. + * + * We are also required to state that + * "The Graphics Interchange Format(c) is the Copyright property of + * CompuServe Incorporated. GIF(sm) is a Service Mark property of + * CompuServe Incorporated." + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef GIF_SUPPORTED + + +/* Private version of data destination object */ + +typedef struct { + struct djpeg_dest_struct pub; /* public fields */ + + j_decompress_ptr cinfo; /* back link saves passing separate parm */ + + /* State for packing variable-width codes into a bitstream */ + int n_bits; /* current number of bits/code */ + int maxcode; /* maximum code, given n_bits */ + INT32 cur_accum; /* holds bits not yet output */ + int cur_bits; /* # of bits in cur_accum */ + + /* State for GIF code assignment */ + int ClearCode; /* clear code (doesn't change) */ + int EOFCode; /* EOF code (ditto) */ + int code_counter; /* counts output symbols */ + + /* GIF data packet construction buffer */ + int bytesinpkt; /* # of bytes in current packet */ + char packetbuf[256]; /* workspace for accumulating packet */ + +} gif_dest_struct; + +typedef gif_dest_struct * gif_dest_ptr; + +/* Largest value that will fit in N bits */ +#define MAXCODE(n_bits) ((1 << (n_bits)) - 1) + + +/* + * Routines to package finished data bytes into GIF data blocks. + * A data block consists of a count byte (1..255) and that many data bytes. + */ + +LOCAL(void) +flush_packet (gif_dest_ptr dinfo) +/* flush any accumulated data */ +{ + if (dinfo->bytesinpkt > 0) { /* never write zero-length packet */ + dinfo->packetbuf[0] = (char) dinfo->bytesinpkt++; + if (JFWRITE(dinfo->pub.output_file, dinfo->packetbuf, dinfo->bytesinpkt) + != (size_t) dinfo->bytesinpkt) + ERREXIT(dinfo->cinfo, JERR_FILE_WRITE); + dinfo->bytesinpkt = 0; + } +} + + +/* Add a character to current packet; flush to disk if necessary */ +#define CHAR_OUT(dinfo,c) \ + { (dinfo)->packetbuf[++(dinfo)->bytesinpkt] = (char) (c); \ + if ((dinfo)->bytesinpkt >= 255) \ + flush_packet(dinfo); \ + } + + +/* Routine to convert variable-width codes into a byte stream */ + +LOCAL(void) +output (gif_dest_ptr dinfo, int code) +/* Emit a code of n_bits bits */ +/* Uses cur_accum and cur_bits to reblock into 8-bit bytes */ +{ + dinfo->cur_accum |= ((INT32) code) << dinfo->cur_bits; + dinfo->cur_bits += dinfo->n_bits; + + while (dinfo->cur_bits >= 8) { + CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF); + dinfo->cur_accum >>= 8; + dinfo->cur_bits -= 8; + } +} + + +/* The pseudo-compression algorithm. + * + * In this module we simply output each pixel value as a separate symbol; + * thus, no compression occurs. In fact, there is expansion of one bit per + * pixel, because we use a symbol width one bit wider than the pixel width. + * + * GIF ordinarily uses variable-width symbols, and the decoder will expect + * to ratchet up the symbol width after a fixed number of symbols. + * To simplify the logic and keep the expansion penalty down, we emit a + * GIF Clear code to reset the decoder just before the width would ratchet up. + * Thus, all the symbols in the output file will have the same bit width. + * Note that emitting the Clear codes at the right times is a mere matter of + * counting output symbols and is in no way dependent on the LZW patent. + * + * With a small basic pixel width (low color count), Clear codes will be + * needed very frequently, causing the file to expand even more. So this + * simplistic approach wouldn't work too well on bilevel images, for example. + * But for output of JPEG conversions the pixel width will usually be 8 bits + * (129 to 256 colors), so the overhead added by Clear symbols is only about + * one symbol in every 256. + */ + +LOCAL(void) +compress_init (gif_dest_ptr dinfo, int i_bits) +/* Initialize pseudo-compressor */ +{ + /* init all the state variables */ + dinfo->n_bits = i_bits; + dinfo->maxcode = MAXCODE(dinfo->n_bits); + dinfo->ClearCode = (1 << (i_bits - 1)); + dinfo->EOFCode = dinfo->ClearCode + 1; + dinfo->code_counter = dinfo->ClearCode + 2; + /* init output buffering vars */ + dinfo->bytesinpkt = 0; + dinfo->cur_accum = 0; + dinfo->cur_bits = 0; + /* GIF specifies an initial Clear code */ + output(dinfo, dinfo->ClearCode); +} + + +LOCAL(void) +compress_pixel (gif_dest_ptr dinfo, int c) +/* Accept and "compress" one pixel value. + * The given value must be less than n_bits wide. + */ +{ + /* Output the given pixel value as a symbol. */ + output(dinfo, c); + /* Issue Clear codes often enough to keep the reader from ratcheting up + * its symbol size. + */ + if (dinfo->code_counter < dinfo->maxcode) { + dinfo->code_counter++; + } else { + output(dinfo, dinfo->ClearCode); + dinfo->code_counter = dinfo->ClearCode + 2; /* reset the counter */ + } +} + + +LOCAL(void) +compress_term (gif_dest_ptr dinfo) +/* Clean up at end */ +{ + /* Send an EOF code */ + output(dinfo, dinfo->EOFCode); + /* Flush the bit-packing buffer */ + if (dinfo->cur_bits > 0) { + CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF); + } + /* Flush the packet buffer */ + flush_packet(dinfo); +} + + +/* GIF header construction */ + + +LOCAL(void) +put_word (gif_dest_ptr dinfo, unsigned int w) +/* Emit a 16-bit word, LSB first */ +{ + putc(w & 0xFF, dinfo->pub.output_file); + putc((w >> 8) & 0xFF, dinfo->pub.output_file); +} + + +LOCAL(void) +put_3bytes (gif_dest_ptr dinfo, int val) +/* Emit 3 copies of same byte value --- handy subr for colormap construction */ +{ + putc(val, dinfo->pub.output_file); + putc(val, dinfo->pub.output_file); + putc(val, dinfo->pub.output_file); +} + + +LOCAL(void) +emit_header (gif_dest_ptr dinfo, int num_colors, JSAMPARRAY colormap) +/* Output the GIF file header, including color map */ +/* If colormap==NULL, synthesize a gray-scale colormap */ +{ + int BitsPerPixel, ColorMapSize, InitCodeSize, FlagByte; + int cshift = dinfo->cinfo->data_precision - 8; + int i; + + if (num_colors > 256) + ERREXIT1(dinfo->cinfo, JERR_TOO_MANY_COLORS, num_colors); + /* Compute bits/pixel and related values */ + BitsPerPixel = 1; + while (num_colors > (1 << BitsPerPixel)) + BitsPerPixel++; + ColorMapSize = 1 << BitsPerPixel; + if (BitsPerPixel <= 1) + InitCodeSize = 2; + else + InitCodeSize = BitsPerPixel; + /* + * Write the GIF header. + * Note that we generate a plain GIF87 header for maximum compatibility. + */ + putc('G', dinfo->pub.output_file); + putc('I', dinfo->pub.output_file); + putc('F', dinfo->pub.output_file); + putc('8', dinfo->pub.output_file); + putc('7', dinfo->pub.output_file); + putc('a', dinfo->pub.output_file); + /* Write the Logical Screen Descriptor */ + put_word(dinfo, (unsigned int) dinfo->cinfo->output_width); + put_word(dinfo, (unsigned int) dinfo->cinfo->output_height); + FlagByte = 0x80; /* Yes, there is a global color table */ + FlagByte |= (BitsPerPixel-1) << 4; /* color resolution */ + FlagByte |= (BitsPerPixel-1); /* size of global color table */ + putc(FlagByte, dinfo->pub.output_file); + putc(0, dinfo->pub.output_file); /* Background color index */ + putc(0, dinfo->pub.output_file); /* Reserved (aspect ratio in GIF89) */ + /* Write the Global Color Map */ + /* If the color map is more than 8 bits precision, */ + /* we reduce it to 8 bits by shifting */ + for (i=0; i < ColorMapSize; i++) { + if (i < num_colors) { + if (colormap != NULL) { + if (dinfo->cinfo->out_color_space == JCS_RGB) { + /* Normal case: RGB color map */ + putc(GETJSAMPLE(colormap[0][i]) >> cshift, dinfo->pub.output_file); + putc(GETJSAMPLE(colormap[1][i]) >> cshift, dinfo->pub.output_file); + putc(GETJSAMPLE(colormap[2][i]) >> cshift, dinfo->pub.output_file); + } else { + /* Grayscale "color map": possible if quantizing grayscale image */ + put_3bytes(dinfo, GETJSAMPLE(colormap[0][i]) >> cshift); + } + } else { + /* Create a gray-scale map of num_colors values, range 0..255 */ + put_3bytes(dinfo, (i * 255 + (num_colors-1)/2) / (num_colors-1)); + } + } else { + /* fill out the map to a power of 2 */ + put_3bytes(dinfo, 0); + } + } + /* Write image separator and Image Descriptor */ + putc(',', dinfo->pub.output_file); /* separator */ + put_word(dinfo, 0); /* left/top offset */ + put_word(dinfo, 0); + put_word(dinfo, (unsigned int) dinfo->cinfo->output_width); /* image size */ + put_word(dinfo, (unsigned int) dinfo->cinfo->output_height); + /* flag byte: not interlaced, no local color map */ + putc(0x00, dinfo->pub.output_file); + /* Write Initial Code Size byte */ + putc(InitCodeSize, dinfo->pub.output_file); + + /* Initialize for "compression" of image data */ + compress_init(dinfo, InitCodeSize+1); +} + + +/* + * Startup: write the file header. + */ + +METHODDEF(void) +start_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + gif_dest_ptr dest = (gif_dest_ptr) dinfo; + + if (cinfo->quantize_colors) + emit_header(dest, cinfo->actual_number_of_colors, cinfo->colormap); + else + emit_header(dest, 256, (JSAMPARRAY) NULL); +} + + +/* + * Write some pixel data. + * In this module rows_supplied will always be 1. + */ + +METHODDEF(void) +put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + gif_dest_ptr dest = (gif_dest_ptr) dinfo; + register JSAMPROW ptr; + register JDIMENSION col; + + ptr = dest->pub.buffer[0]; + for (col = cinfo->output_width; col > 0; col--) { + compress_pixel(dest, GETJSAMPLE(*ptr++)); + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + gif_dest_ptr dest = (gif_dest_ptr) dinfo; + + /* Flush "compression" mechanism */ + compress_term(dest); + /* Write a zero-length data block to end the series */ + putc(0, dest->pub.output_file); + /* Write the GIF terminator mark */ + putc(';', dest->pub.output_file); + /* Make sure we wrote the output file OK */ + fflush(dest->pub.output_file); + if (ferror(dest->pub.output_file)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for GIF format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_gif (j_decompress_ptr cinfo) +{ + gif_dest_ptr dest; + + /* Create module interface object, fill in method pointers */ + dest = (gif_dest_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(gif_dest_struct)); + dest->cinfo = cinfo; /* make back link for subroutines */ + dest->pub.start_output = start_output_gif; + dest->pub.put_pixel_rows = put_pixel_rows; + dest->pub.finish_output = finish_output_gif; + + if (cinfo->out_color_space != JCS_GRAYSCALE && + cinfo->out_color_space != JCS_RGB) + ERREXIT(cinfo, JERR_GIF_COLORSPACE); + + /* Force quantization if color or if > 8 bits input */ + if (cinfo->out_color_space != JCS_GRAYSCALE || cinfo->data_precision > 8) { + /* Force quantization to at most 256 colors */ + cinfo->quantize_colors = TRUE; + if (cinfo->desired_number_of_colors > 256) + cinfo->desired_number_of_colors = 256; + } + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + if (cinfo->output_components != 1) /* safety check: just one component? */ + ERREXIT(cinfo, JERR_GIF_BUG); + + /* Create decompressor output buffer. */ + dest->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, cinfo->output_width, (JDIMENSION) 1); + dest->pub.buffer_height = 1; + + return (djpeg_dest_ptr) dest; +} + +#endif /* GIF_SUPPORTED */ diff --git a/source/Irrlicht/jpeglib/wrjpgcom.1 b/source/Irrlicht/jpeglib/wrjpgcom.1 new file mode 100644 index 00000000..d419a999 --- /dev/null +++ b/source/Irrlicht/jpeglib/wrjpgcom.1 @@ -0,0 +1,103 @@ +.TH WRJPGCOM 1 "15 June 1995" +.SH NAME +wrjpgcom \- insert text comments into a JPEG file +.SH SYNOPSIS +.B wrjpgcom +[ +.B \-replace +] +[ +.BI \-comment " text" +] +[ +.BI \-cfile " name" +] +[ +.I filename +] +.LP +.SH DESCRIPTION +.LP +.B wrjpgcom +reads the named JPEG/JFIF file, or the standard input if no file is named, +and generates a new JPEG/JFIF file on standard output. A comment block is +added to the file. +.PP +The JPEG standard allows "comment" (COM) blocks to occur within a JPEG file. +Although the standard doesn't actually define what COM blocks are for, they +are widely used to hold user-supplied text strings. This lets you add +annotations, titles, index terms, etc to your JPEG files, and later retrieve +them as text. COM blocks do not interfere with the image stored in the JPEG +file. The maximum size of a COM block is 64K, but you can have as many of +them as you like in one JPEG file. +.PP +.B wrjpgcom +adds a COM block, containing text you provide, to a JPEG file. +Ordinarily, the COM block is added after any existing COM blocks; but you +can delete the old COM blocks if you wish. +.SH OPTIONS +Switch names may be abbreviated, and are not case sensitive. +.TP +.B \-replace +Delete any existing COM blocks from the file. +.TP +.BI \-comment " text" +Supply text for new COM block on command line. +.TP +.BI \-cfile " name" +Read text for new COM block from named file. +.PP +If you have only one line of comment text to add, you can provide it on the +command line with +.BR \-comment . +The comment text must be surrounded with quotes so that it is treated as a +single argument. Longer comments can be read from a text file. +.PP +If you give neither +.B \-comment +nor +.BR \-cfile , +then +.B wrjpgcom +will read the comment text from standard input. (In this case an input image +file name MUST be supplied, so that the source JPEG file comes from somewhere +else.) You can enter multiple lines, up to 64KB worth. Type an end-of-file +indicator (usually control-D) to terminate the comment text entry. +.PP +.B wrjpgcom +will not add a COM block if the provided comment string is empty. Therefore +\fB\-replace \-comment ""\fR can be used to delete all COM blocks from a file. +.SH EXAMPLES +.LP +Add a short comment to in.jpg, producing out.jpg: +.IP +.B wrjpgcom \-c +\fI"View of my back yard" in.jpg +.B > +.I out.jpg +.PP +Attach a long comment previously stored in comment.txt: +.IP +.B wrjpgcom +.I in.jpg +.B < +.I comment.txt +.B > +.I out.jpg +.PP +or equivalently +.IP +.B wrjpgcom +.B -cfile +.I comment.txt +.B < +.I in.jpg +.B > +.I out.jpg +.SH SEE ALSO +.BR cjpeg (1), +.BR djpeg (1), +.BR jpegtran (1), +.BR rdjpgcom (1) +.SH AUTHOR +Independent JPEG Group diff --git a/source/Irrlicht/jpeglib/wrjpgcom.c b/source/Irrlicht/jpeglib/wrjpgcom.c new file mode 100644 index 00000000..7d10ee66 --- /dev/null +++ b/source/Irrlicht/jpeglib/wrjpgcom.c @@ -0,0 +1,583 @@ +/* + * wrjpgcom.c + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a very simple stand-alone application that inserts + * user-supplied text as a COM (comment) marker in a JFIF file. + * This may be useful as an example of the minimum logic needed to parse + * JPEG markers. + */ + +#define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */ +#include "jinclude.h" /* get auto-config symbols, */ + +#ifndef HAVE_STDLIB_H /* should declare malloc() */ +extern void * malloc (); +#endif +#include /* to declare isupper(), tolower() */ +#ifdef USE_SETMODE +#include /* to declare setmode()'s parameter macros */ +/* If you have setmode() but not , just delete this line: */ +#include /* to declare setmode() */ +#endif + +#ifdef USE_CCOMMAND /* command-line reader for Macintosh */ +#ifdef __MWERKS__ +#include /* Metrowerks needs this */ +#include /* ... and this */ +#endif +#ifdef THINK_C +#include /* Think declares it here */ +#endif +#endif + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#define WRITE_BINARY "w" +#else +#ifdef VMS /* VMS is very nonstandard */ +#define READ_BINARY "rb", "ctx=stm" +#define WRITE_BINARY "wb", "ctx=stm" +#else /* standard ANSI-compliant case */ +#define READ_BINARY "rb" +#define WRITE_BINARY "wb" +#endif +#endif + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif +#ifndef EXIT_SUCCESS +#ifdef VMS +#define EXIT_SUCCESS 1 /* VMS is very nonstandard */ +#else +#define EXIT_SUCCESS 0 +#endif +#endif + +/* Reduce this value if your malloc() can't allocate blocks up to 64K. + * On DOS, compiling in large model is usually a better solution. + */ + +#ifndef MAX_COM_LENGTH +#define MAX_COM_LENGTH 65000L /* must be <= 65533 in any case */ +#endif + + +/* + * These macros are used to read the input file and write the output file. + * To reuse this code in another application, you might need to change these. + */ + +static FILE * infile; /* input JPEG file */ + +/* Return next input byte, or EOF if no more */ +#define NEXTBYTE() getc(infile) + +static FILE * outfile; /* output JPEG file */ + +/* Emit an output byte */ +#define PUTBYTE(x) putc((x), outfile) + + +/* Error exit handler */ +#define ERREXIT(msg) (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE)) + + +/* Read one byte, testing for EOF */ +static int +read_1_byte (void) +{ + int c; + + c = NEXTBYTE(); + if (c == EOF) + ERREXIT("Premature EOF in JPEG file"); + return c; +} + +/* Read 2 bytes, convert to unsigned int */ +/* All 2-byte quantities in JPEG markers are MSB first */ +static unsigned int +read_2_bytes (void) +{ + int c1, c2; + + c1 = NEXTBYTE(); + if (c1 == EOF) + ERREXIT("Premature EOF in JPEG file"); + c2 = NEXTBYTE(); + if (c2 == EOF) + ERREXIT("Premature EOF in JPEG file"); + return (((unsigned int) c1) << 8) + ((unsigned int) c2); +} + + +/* Routines to write data to output file */ + +static void +write_1_byte (int c) +{ + PUTBYTE(c); +} + +static void +write_2_bytes (unsigned int val) +{ + PUTBYTE((val >> 8) & 0xFF); + PUTBYTE(val & 0xFF); +} + +static void +write_marker (int marker) +{ + PUTBYTE(0xFF); + PUTBYTE(marker); +} + +static void +copy_rest_of_file (void) +{ + int c; + + while ((c = NEXTBYTE()) != EOF) + PUTBYTE(c); +} + + +/* + * JPEG markers consist of one or more 0xFF bytes, followed by a marker + * code byte (which is not an FF). Here are the marker codes of interest + * in this program. (See jdmarker.c for a more complete list.) + */ + +#define M_SOF0 0xC0 /* Start Of Frame N */ +#define M_SOF1 0xC1 /* N indicates which compression process */ +#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */ +#define M_SOF3 0xC3 +#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */ +#define M_SOF6 0xC6 +#define M_SOF7 0xC7 +#define M_SOF9 0xC9 +#define M_SOF10 0xCA +#define M_SOF11 0xCB +#define M_SOF13 0xCD +#define M_SOF14 0xCE +#define M_SOF15 0xCF +#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */ +#define M_EOI 0xD9 /* End Of Image (end of datastream) */ +#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */ +#define M_COM 0xFE /* COMment */ + + +/* + * Find the next JPEG marker and return its marker code. + * We expect at least one FF byte, possibly more if the compressor used FFs + * to pad the file. (Padding FFs will NOT be replicated in the output file.) + * There could also be non-FF garbage between markers. The treatment of such + * garbage is unspecified; we choose to skip over it but emit a warning msg. + * NB: this routine must not be used after seeing SOS marker, since it will + * not deal correctly with FF/00 sequences in the compressed image data... + */ + +static int +next_marker (void) +{ + int c; + int discarded_bytes = 0; + + /* Find 0xFF byte; count and skip any non-FFs. */ + c = read_1_byte(); + while (c != 0xFF) { + discarded_bytes++; + c = read_1_byte(); + } + /* Get marker code byte, swallowing any duplicate FF bytes. Extra FFs + * are legal as pad bytes, so don't count them in discarded_bytes. + */ + do { + c = read_1_byte(); + } while (c == 0xFF); + + if (discarded_bytes != 0) { + fprintf(stderr, "Warning: garbage data found in JPEG file\n"); + } + + return c; +} + + +/* + * Read the initial marker, which should be SOI. + * For a JFIF file, the first two bytes of the file should be literally + * 0xFF M_SOI. To be more general, we could use next_marker, but if the + * input file weren't actually JPEG at all, next_marker might read the whole + * file and then return a misleading error message... + */ + +static int +first_marker (void) +{ + int c1, c2; + + c1 = NEXTBYTE(); + c2 = NEXTBYTE(); + if (c1 != 0xFF || c2 != M_SOI) + ERREXIT("Not a JPEG file"); + return c2; +} + + +/* + * Most types of marker are followed by a variable-length parameter segment. + * This routine skips over the parameters for any marker we don't otherwise + * want to process. + * Note that we MUST skip the parameter segment explicitly in order not to + * be fooled by 0xFF bytes that might appear within the parameter segment; + * such bytes do NOT introduce new markers. + */ + +static void +copy_variable (void) +/* Copy an unknown or uninteresting variable-length marker */ +{ + unsigned int length; + + /* Get the marker parameter length count */ + length = read_2_bytes(); + write_2_bytes(length); + /* Length includes itself, so must be at least 2 */ + if (length < 2) + ERREXIT("Erroneous JPEG marker length"); + length -= 2; + /* Skip over the remaining bytes */ + while (length > 0) { + write_1_byte(read_1_byte()); + length--; + } +} + +static void +skip_variable (void) +/* Skip over an unknown or uninteresting variable-length marker */ +{ + unsigned int length; + + /* Get the marker parameter length count */ + length = read_2_bytes(); + /* Length includes itself, so must be at least 2 */ + if (length < 2) + ERREXIT("Erroneous JPEG marker length"); + length -= 2; + /* Skip over the remaining bytes */ + while (length > 0) { + (void) read_1_byte(); + length--; + } +} + + +/* + * Parse the marker stream until SOFn or EOI is seen; + * copy data to output, but discard COM markers unless keep_COM is true. + */ + +static int +scan_JPEG_header (int keep_COM) +{ + int marker; + + /* Expect SOI at start of file */ + if (first_marker() != M_SOI) + ERREXIT("Expected SOI marker first"); + write_marker(M_SOI); + + /* Scan miscellaneous markers until we reach SOFn. */ + for (;;) { + marker = next_marker(); + switch (marker) { + /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be, + * treated as SOFn. C4 in particular is actually DHT. + */ + case M_SOF0: /* Baseline */ + case M_SOF1: /* Extended sequential, Huffman */ + case M_SOF2: /* Progressive, Huffman */ + case M_SOF3: /* Lossless, Huffman */ + case M_SOF5: /* Differential sequential, Huffman */ + case M_SOF6: /* Differential progressive, Huffman */ + case M_SOF7: /* Differential lossless, Huffman */ + case M_SOF9: /* Extended sequential, arithmetic */ + case M_SOF10: /* Progressive, arithmetic */ + case M_SOF11: /* Lossless, arithmetic */ + case M_SOF13: /* Differential sequential, arithmetic */ + case M_SOF14: /* Differential progressive, arithmetic */ + case M_SOF15: /* Differential lossless, arithmetic */ + return marker; + + case M_SOS: /* should not see compressed data before SOF */ + ERREXIT("SOS without prior SOFn"); + break; + + case M_EOI: /* in case it's a tables-only JPEG stream */ + return marker; + + case M_COM: /* Existing COM: conditionally discard */ + if (keep_COM) { + write_marker(marker); + copy_variable(); + } else { + skip_variable(); + } + break; + + default: /* Anything else just gets copied */ + write_marker(marker); + copy_variable(); /* we assume it has a parameter count... */ + break; + } + } /* end loop */ +} + + +/* Command line parsing code */ + +static const char * progname; /* program name for error messages */ + + +static void +usage (void) +/* complain about bad command line */ +{ + fprintf(stderr, "wrjpgcom inserts a textual comment in a JPEG file.\n"); + fprintf(stderr, "You can add to or replace any existing comment(s).\n"); + + fprintf(stderr, "Usage: %s [switches] ", progname); +#ifdef TWO_FILE_COMMANDLINE + fprintf(stderr, "inputfile outputfile\n"); +#else + fprintf(stderr, "[inputfile]\n"); +#endif + + fprintf(stderr, "Switches (names may be abbreviated):\n"); + fprintf(stderr, " -replace Delete any existing comments\n"); + fprintf(stderr, " -comment \"text\" Insert comment with given text\n"); + fprintf(stderr, " -cfile name Read comment from named file\n"); + fprintf(stderr, "Notice that you must put quotes around the comment text\n"); + fprintf(stderr, "when you use -comment.\n"); + fprintf(stderr, "If you do not give either -comment or -cfile on the command line,\n"); + fprintf(stderr, "then the comment text is read from standard input.\n"); + fprintf(stderr, "It can be multiple lines, up to %u characters total.\n", + (unsigned int) MAX_COM_LENGTH); +#ifndef TWO_FILE_COMMANDLINE + fprintf(stderr, "You must specify an input JPEG file name when supplying\n"); + fprintf(stderr, "comment text from standard input.\n"); +#endif + + exit(EXIT_FAILURE); +} + + +static int +keymatch (char * arg, const char * keyword, int minchars) +/* Case-insensitive matching of (possibly abbreviated) keyword switches. */ +/* keyword is the constant keyword (must be lower case already), */ +/* minchars is length of minimum legal abbreviation. */ +{ + register int ca, ck; + register int nmatched = 0; + + while ((ca = *arg++) != '\0') { + if ((ck = *keyword++) == '\0') + return 0; /* arg longer than keyword, no good */ + if (isupper(ca)) /* force arg to lcase (assume ck is already) */ + ca = tolower(ca); + if (ca != ck) + return 0; /* no good */ + nmatched++; /* count matched characters */ + } + /* reached end of argument; fail if it's too short for unique abbrev */ + if (nmatched < minchars) + return 0; + return 1; /* A-OK */ +} + + +/* + * The main program. + */ + +int +main (int argc, char **argv) +{ + int argn; + char * arg; + int keep_COM = 1; + char * comment_arg = NULL; + FILE * comment_file = NULL; + unsigned int comment_length = 0; + int marker; + + /* On Mac, fetch a command line. */ +#ifdef USE_CCOMMAND + argc = ccommand(&argv); +#endif + + progname = argv[0]; + if (progname == NULL || progname[0] == 0) + progname = "wrjpgcom"; /* in case C library doesn't provide it */ + + /* Parse switches, if any */ + for (argn = 1; argn < argc; argn++) { + arg = argv[argn]; + if (arg[0] != '-') + break; /* not switch, must be file name */ + arg++; /* advance over '-' */ + if (keymatch(arg, "replace", 1)) { + keep_COM = 0; + } else if (keymatch(arg, "cfile", 2)) { + if (++argn >= argc) usage(); + if ((comment_file = fopen(argv[argn], "r")) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); + exit(EXIT_FAILURE); + } + } else if (keymatch(arg, "comment", 1)) { + if (++argn >= argc) usage(); + comment_arg = argv[argn]; + /* If the comment text starts with '"', then we are probably running + * under MS-DOG and must parse out the quoted string ourselves. Sigh. + */ + if (comment_arg[0] == '"') { + comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH); + if (comment_arg == NULL) + ERREXIT("Insufficient memory"); + strcpy(comment_arg, argv[argn]+1); + for (;;) { + comment_length = (unsigned int) strlen(comment_arg); + if (comment_length > 0 && comment_arg[comment_length-1] == '"') { + comment_arg[comment_length-1] = '\0'; /* zap terminating quote */ + break; + } + if (++argn >= argc) + ERREXIT("Missing ending quote mark"); + strcat(comment_arg, " "); + strcat(comment_arg, argv[argn]); + } + } + comment_length = (unsigned int) strlen(comment_arg); + } else + usage(); + } + + /* Cannot use both -comment and -cfile. */ + if (comment_arg != NULL && comment_file != NULL) + usage(); + /* If there is neither -comment nor -cfile, we will read the comment text + * from stdin; in this case there MUST be an input JPEG file name. + */ + if (comment_arg == NULL && comment_file == NULL && argn >= argc) + usage(); + + /* Open the input file. */ + if (argn < argc) { + if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); + exit(EXIT_FAILURE); + } + } else { + /* default input file is stdin */ +#ifdef USE_SETMODE /* need to hack file mode? */ + setmode(fileno(stdin), O_BINARY); +#endif +#ifdef USE_FDOPEN /* need to re-open in binary mode? */ + if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open stdin\n", progname); + exit(EXIT_FAILURE); + } +#else + infile = stdin; +#endif + } + + /* Open the output file. */ +#ifdef TWO_FILE_COMMANDLINE + /* Must have explicit output file name */ + if (argn != argc-2) { + fprintf(stderr, "%s: must name one input and one output file\n", + progname); + usage(); + } + if ((outfile = fopen(argv[argn+1], WRITE_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[argn+1]); + exit(EXIT_FAILURE); + } +#else + /* Unix style: expect zero or one file name */ + if (argn < argc-1) { + fprintf(stderr, "%s: only one input file\n", progname); + usage(); + } + /* default output file is stdout */ +#ifdef USE_SETMODE /* need to hack file mode? */ + setmode(fileno(stdout), O_BINARY); +#endif +#ifdef USE_FDOPEN /* need to re-open in binary mode? */ + if ((outfile = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open stdout\n", progname); + exit(EXIT_FAILURE); + } +#else + outfile = stdout; +#endif +#endif /* TWO_FILE_COMMANDLINE */ + + /* Collect comment text from comment_file or stdin, if necessary */ + if (comment_arg == NULL) { + FILE * src_file; + int c; + + comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH); + if (comment_arg == NULL) + ERREXIT("Insufficient memory"); + comment_length = 0; + src_file = (comment_file != NULL ? comment_file : stdin); + while ((c = getc(src_file)) != EOF) { + if (comment_length >= (unsigned int) MAX_COM_LENGTH) { + fprintf(stderr, "Comment text may not exceed %u bytes\n", + (unsigned int) MAX_COM_LENGTH); + exit(EXIT_FAILURE); + } + comment_arg[comment_length++] = (char) c; + } + if (comment_file != NULL) + fclose(comment_file); + } + + /* Copy JPEG headers until SOFn marker; + * we will insert the new comment marker just before SOFn. + * This (a) causes the new comment to appear after, rather than before, + * existing comments; and (b) ensures that comments come after any JFIF + * or JFXX markers, as required by the JFIF specification. + */ + marker = scan_JPEG_header(keep_COM); + /* Insert the new COM marker, but only if nonempty text has been supplied */ + if (comment_length > 0) { + write_marker(M_COM); + write_2_bytes(comment_length + 2); + while (comment_length > 0) { + write_1_byte(*comment_arg++); + comment_length--; + } + } + /* Duplicate the remainder of the source file. + * Note that any COM markers occuring after SOF will not be touched. + */ + write_marker(marker); + copy_rest_of_file(); + + /* All done. */ + exit(EXIT_SUCCESS); + return 0; /* suppress no-return-value warnings */ +} diff --git a/source/Irrlicht/jpeglib/wrppm.c b/source/Irrlicht/jpeglib/wrppm.c new file mode 100644 index 00000000..1e56d9c5 --- /dev/null +++ b/source/Irrlicht/jpeglib/wrppm.c @@ -0,0 +1,269 @@ +/* + * wrppm.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * Modified 2009 by Guido Vollbeding. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in PPM/PGM format. + * The extended 2-byte-per-sample raw PPM/PGM formats are supported. + * The PBMPLUS library is NOT required to compile this software + * (but it is highly useful as a set of PPM image manipulation programs). + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef PPM_SUPPORTED + + +/* + * For 12-bit JPEG data, we either downscale the values to 8 bits + * (to write standard byte-per-sample PPM/PGM files), or output + * nonstandard word-per-sample PPM/PGM files. Downscaling is done + * if PPM_NORAWWORD is defined (this can be done in the Makefile + * or in jconfig.h). + * (When the core library supports data precision reduction, a cleaner + * implementation will be to ask for that instead.) + */ + +#if BITS_IN_JSAMPLE == 8 +#define PUTPPMSAMPLE(ptr,v) *ptr++ = (char) (v) +#define BYTESPERSAMPLE 1 +#define PPM_MAXVAL 255 +#else +#ifdef PPM_NORAWWORD +#define PUTPPMSAMPLE(ptr,v) *ptr++ = (char) ((v) >> (BITS_IN_JSAMPLE-8)) +#define BYTESPERSAMPLE 1 +#define PPM_MAXVAL 255 +#else +/* The word-per-sample format always puts the MSB first. */ +#define PUTPPMSAMPLE(ptr,v) \ + { register int val_ = v; \ + *ptr++ = (char) ((val_ >> 8) & 0xFF); \ + *ptr++ = (char) (val_ & 0xFF); \ + } +#define BYTESPERSAMPLE 2 +#define PPM_MAXVAL ((1<pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * This code is used when we have to copy the data and apply a pixel + * format translation. Typically this only happens in 12-bit mode. + */ + +METHODDEF(void) +copy_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; + register char * bufferptr; + register JSAMPROW ptr; + register JDIMENSION col; + + ptr = dest->pub.buffer[0]; + bufferptr = dest->iobuffer; + for (col = dest->samples_per_row; col > 0; col--) { + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(*ptr++)); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * Write some pixel data when color quantization is in effect. + * We have to demap the color index values to straight data. + */ + +METHODDEF(void) +put_demapped_rgb (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; + register char * bufferptr; + register int pixval; + register JSAMPROW ptr; + register JSAMPROW color_map0 = cinfo->colormap[0]; + register JSAMPROW color_map1 = cinfo->colormap[1]; + register JSAMPROW color_map2 = cinfo->colormap[2]; + register JDIMENSION col; + + ptr = dest->pub.buffer[0]; + bufferptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + pixval = GETJSAMPLE(*ptr++); + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map0[pixval])); + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map1[pixval])); + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map2[pixval])); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +METHODDEF(void) +put_demapped_gray (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; + register char * bufferptr; + register JSAMPROW ptr; + register JSAMPROW color_map = cinfo->colormap[0]; + register JDIMENSION col; + + ptr = dest->pub.buffer[0]; + bufferptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map[GETJSAMPLE(*ptr++)])); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * Startup: write the file header. + */ + +METHODDEF(void) +start_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; + + /* Emit file header */ + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + /* emit header for raw PGM format */ + fprintf(dest->pub.output_file, "P5\n%ld %ld\n%d\n", + (long) cinfo->output_width, (long) cinfo->output_height, + PPM_MAXVAL); + break; + case JCS_RGB: + /* emit header for raw PPM format */ + fprintf(dest->pub.output_file, "P6\n%ld %ld\n%d\n", + (long) cinfo->output_width, (long) cinfo->output_height, + PPM_MAXVAL); + break; + default: + ERREXIT(cinfo, JERR_PPM_COLORSPACE); + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + /* Make sure we wrote the output file OK */ + fflush(dinfo->output_file); + if (ferror(dinfo->output_file)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for PPM format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_ppm (j_decompress_ptr cinfo) +{ + ppm_dest_ptr dest; + + /* Create module interface object, fill in method pointers */ + dest = (ppm_dest_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(ppm_dest_struct)); + dest->pub.start_output = start_output_ppm; + dest->pub.finish_output = finish_output_ppm; + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + /* Create physical I/O buffer. Note we make this near on a PC. */ + dest->samples_per_row = cinfo->output_width * cinfo->out_color_components; + dest->buffer_width = dest->samples_per_row * (BYTESPERSAMPLE * SIZEOF(char)); + dest->iobuffer = (char *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, dest->buffer_width); + + if (cinfo->quantize_colors || BITS_IN_JSAMPLE != 8 || + SIZEOF(JSAMPLE) != SIZEOF(char)) { + /* When quantizing, we need an output buffer for colormap indexes + * that's separate from the physical I/O buffer. We also need a + * separate buffer if pixel format translation must take place. + */ + dest->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->output_width * cinfo->output_components, (JDIMENSION) 1); + dest->pub.buffer_height = 1; + if (! cinfo->quantize_colors) + dest->pub.put_pixel_rows = copy_pixel_rows; + else if (cinfo->out_color_space == JCS_GRAYSCALE) + dest->pub.put_pixel_rows = put_demapped_gray; + else + dest->pub.put_pixel_rows = put_demapped_rgb; + } else { + /* We will fwrite() directly from decompressor output buffer. */ + /* Synthesize a JSAMPARRAY pointer structure */ + /* Cast here implies near->far pointer conversion on PCs */ + dest->pixrow = (JSAMPROW) dest->iobuffer; + dest->pub.buffer = & dest->pixrow; + dest->pub.buffer_height = 1; + dest->pub.put_pixel_rows = put_pixel_rows; + } + + return (djpeg_dest_ptr) dest; +} + +#endif /* PPM_SUPPORTED */ diff --git a/source/Irrlicht/jpeglib/wrrle.c b/source/Irrlicht/jpeglib/wrrle.c new file mode 100644 index 00000000..7a00c0dd --- /dev/null +++ b/source/Irrlicht/jpeglib/wrrle.c @@ -0,0 +1,305 @@ +/* + * wrrle.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in RLE format. + * The Utah Raster Toolkit library is required (version 3.1 or later). + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + * + * Based on code contributed by Mike Lijewski, + * with updates from Robert Hutchinson. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef RLE_SUPPORTED + +/* rle.h is provided by the Utah Raster Toolkit. */ + +#include + +/* + * We assume that JSAMPLE has the same representation as rle_pixel, + * to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples. + */ + +#if BITS_IN_JSAMPLE != 8 + Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */ +#endif + + +/* + * Since RLE stores scanlines bottom-to-top, we have to invert the image + * from JPEG's top-to-bottom order. To do this, we save the outgoing data + * in a virtual array during put_pixel_row calls, then actually emit the + * RLE file during finish_output. + */ + + +/* + * For now, if we emit an RLE color map then it is always 256 entries long, + * though not all of the entries need be used. + */ + +#define CMAPBITS 8 +#define CMAPLENGTH (1<<(CMAPBITS)) + +typedef struct { + struct djpeg_dest_struct pub; /* public fields */ + + jvirt_sarray_ptr image; /* virtual array to store the output image */ + rle_map *colormap; /* RLE-style color map, or NULL if none */ + rle_pixel **rle_row; /* To pass rows to rle_putrow() */ + +} rle_dest_struct; + +typedef rle_dest_struct * rle_dest_ptr; + +/* Forward declarations */ +METHODDEF(void) rle_put_pixel_rows + JPP((j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied)); + + +/* + * Write the file header. + * + * In this module it's easier to wait till finish_output to write anything. + */ + +METHODDEF(void) +start_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + rle_dest_ptr dest = (rle_dest_ptr) dinfo; + size_t cmapsize; + int i, ci; +#ifdef PROGRESS_REPORT + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; +#endif + + /* + * Make sure the image can be stored in RLE format. + * + * - RLE stores image dimensions as *signed* 16 bit integers. JPEG + * uses unsigned, so we have to check the width. + * + * - Colorspace is expected to be grayscale or RGB. + * + * - The number of channels (components) is expected to be 1 (grayscale/ + * pseudocolor) or 3 (truecolor/directcolor). + * (could be 2 or 4 if using an alpha channel, but we aren't) + */ + + if (cinfo->output_width > 32767 || cinfo->output_height > 32767) + ERREXIT2(cinfo, JERR_RLE_DIMENSIONS, cinfo->output_width, + cinfo->output_height); + + if (cinfo->out_color_space != JCS_GRAYSCALE && + cinfo->out_color_space != JCS_RGB) + ERREXIT(cinfo, JERR_RLE_COLORSPACE); + + if (cinfo->output_components != 1 && cinfo->output_components != 3) + ERREXIT1(cinfo, JERR_RLE_TOOMANYCHANNELS, cinfo->num_components); + + /* Convert colormap, if any, to RLE format. */ + + dest->colormap = NULL; + + if (cinfo->quantize_colors) { + /* Allocate storage for RLE-style cmap, zero any extra entries */ + cmapsize = cinfo->out_color_components * CMAPLENGTH * SIZEOF(rle_map); + dest->colormap = (rle_map *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, cmapsize); + MEMZERO(dest->colormap, cmapsize); + + /* Save away data in RLE format --- note 8-bit left shift! */ + /* Shifting would need adjustment for JSAMPLEs wider than 8 bits. */ + for (ci = 0; ci < cinfo->out_color_components; ci++) { + for (i = 0; i < cinfo->actual_number_of_colors; i++) { + dest->colormap[ci * CMAPLENGTH + i] = + GETJSAMPLE(cinfo->colormap[ci][i]) << 8; + } + } + } + + /* Set the output buffer to the first row */ + dest->pub.buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->image, (JDIMENSION) 0, (JDIMENSION) 1, TRUE); + dest->pub.buffer_height = 1; + + dest->pub.put_pixel_rows = rle_put_pixel_rows; + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->total_extra_passes++; /* count file writing as separate pass */ + } +#endif +} + + +/* + * Write some pixel data. + * + * This routine just saves the data away in a virtual array. + */ + +METHODDEF(void) +rle_put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + rle_dest_ptr dest = (rle_dest_ptr) dinfo; + + if (cinfo->output_scanline < cinfo->output_height) { + dest->pub.buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->image, + cinfo->output_scanline, (JDIMENSION) 1, TRUE); + } +} + +/* + * Finish up at the end of the file. + * + * Here is where we really output the RLE file. + */ + +METHODDEF(void) +finish_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + rle_dest_ptr dest = (rle_dest_ptr) dinfo; + rle_hdr header; /* Output file information */ + rle_pixel **rle_row, *red, *green, *blue; + JSAMPROW output_row; + char cmapcomment[80]; + int row, col; + int ci; +#ifdef PROGRESS_REPORT + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; +#endif + + /* Initialize the header info */ + header = *rle_hdr_init(NULL); + header.rle_file = dest->pub.output_file; + header.xmin = 0; + header.xmax = cinfo->output_width - 1; + header.ymin = 0; + header.ymax = cinfo->output_height - 1; + header.alpha = 0; + header.ncolors = cinfo->output_components; + for (ci = 0; ci < cinfo->output_components; ci++) { + RLE_SET_BIT(header, ci); + } + if (cinfo->quantize_colors) { + header.ncmap = cinfo->out_color_components; + header.cmaplen = CMAPBITS; + header.cmap = dest->colormap; + /* Add a comment to the output image with the true colormap length. */ + sprintf(cmapcomment, "color_map_length=%d", cinfo->actual_number_of_colors); + rle_putcom(cmapcomment, &header); + } + + /* Emit the RLE header and color map (if any) */ + rle_put_setup(&header); + + /* Now output the RLE data from our virtual array. + * We assume here that (a) rle_pixel is represented the same as JSAMPLE, + * and (b) we are not on a machine where FAR pointers differ from regular. + */ + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_limit = cinfo->output_height; + progress->pub.pass_counter = 0; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + + if (cinfo->output_components == 1) { + for (row = cinfo->output_height-1; row >= 0; row--) { + rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->image, + (JDIMENSION) row, (JDIMENSION) 1, FALSE); + rle_putrow(rle_row, (int) cinfo->output_width, &header); +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_counter++; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + } + } else { + for (row = cinfo->output_height-1; row >= 0; row--) { + rle_row = (rle_pixel **) dest->rle_row; + output_row = * (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->image, + (JDIMENSION) row, (JDIMENSION) 1, FALSE); + red = rle_row[0]; + green = rle_row[1]; + blue = rle_row[2]; + for (col = cinfo->output_width; col > 0; col--) { + *red++ = GETJSAMPLE(*output_row++); + *green++ = GETJSAMPLE(*output_row++); + *blue++ = GETJSAMPLE(*output_row++); + } + rle_putrow(rle_row, (int) cinfo->output_width, &header); +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_counter++; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + } + } + +#ifdef PROGRESS_REPORT + if (progress != NULL) + progress->completed_extra_passes++; +#endif + + /* Emit file trailer */ + rle_puteof(&header); + fflush(dest->pub.output_file); + if (ferror(dest->pub.output_file)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for RLE format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_rle (j_decompress_ptr cinfo) +{ + rle_dest_ptr dest; + + /* Create module interface object, fill in method pointers */ + dest = (rle_dest_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(rle_dest_struct)); + dest->pub.start_output = start_output_rle; + dest->pub.finish_output = finish_output_rle; + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + /* Allocate a work array for output to the RLE library. */ + dest->rle_row = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->output_width, (JDIMENSION) cinfo->output_components); + + /* Allocate a virtual array to hold the image. */ + dest->image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) (cinfo->output_width * cinfo->output_components), + cinfo->output_height, (JDIMENSION) 1); + + return (djpeg_dest_ptr) dest; +} + +#endif /* RLE_SUPPORTED */ diff --git a/source/Irrlicht/jpeglib/wrtarga.c b/source/Irrlicht/jpeglib/wrtarga.c new file mode 100644 index 00000000..65662738 --- /dev/null +++ b/source/Irrlicht/jpeglib/wrtarga.c @@ -0,0 +1,253 @@ +/* + * wrtarga.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in Targa format. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + * + * Based on code contributed by Lee Daniel Crocker. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef TARGA_SUPPORTED + + +/* + * To support 12-bit JPEG data, we'd have to scale output down to 8 bits. + * This is not yet implemented. + */ + +#if BITS_IN_JSAMPLE != 8 + Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */ +#endif + +/* + * The output buffer needs to be writable by fwrite(). On PCs, we must + * allocate the buffer in near data space, because we are assuming small-data + * memory model, wherein fwrite() can't reach far memory. If you need to + * process very wide images on a PC, you might have to compile in large-memory + * model, or else replace fwrite() with a putc() loop --- which will be much + * slower. + */ + + +/* Private version of data destination object */ + +typedef struct { + struct djpeg_dest_struct pub; /* public fields */ + + char *iobuffer; /* physical I/O buffer */ + JDIMENSION buffer_width; /* width of one row */ +} tga_dest_struct; + +typedef tga_dest_struct * tga_dest_ptr; + + +LOCAL(void) +write_header (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, int num_colors) +/* Create and write a Targa header */ +{ + char targaheader[18]; + + /* Set unused fields of header to 0 */ + MEMZERO(targaheader, SIZEOF(targaheader)); + + if (num_colors > 0) { + targaheader[1] = 1; /* color map type 1 */ + targaheader[5] = (char) (num_colors & 0xFF); + targaheader[6] = (char) (num_colors >> 8); + targaheader[7] = 24; /* 24 bits per cmap entry */ + } + + targaheader[12] = (char) (cinfo->output_width & 0xFF); + targaheader[13] = (char) (cinfo->output_width >> 8); + targaheader[14] = (char) (cinfo->output_height & 0xFF); + targaheader[15] = (char) (cinfo->output_height >> 8); + targaheader[17] = 0x20; /* Top-down, non-interlaced */ + + if (cinfo->out_color_space == JCS_GRAYSCALE) { + targaheader[2] = 3; /* image type = uncompressed gray-scale */ + targaheader[16] = 8; /* bits per pixel */ + } else { /* must be RGB */ + if (num_colors > 0) { + targaheader[2] = 1; /* image type = colormapped RGB */ + targaheader[16] = 8; + } else { + targaheader[2] = 2; /* image type = uncompressed RGB */ + targaheader[16] = 24; + } + } + + if (JFWRITE(dinfo->output_file, targaheader, 18) != (size_t) 18) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * Write some pixel data. + * In this module rows_supplied will always be 1. + */ + +METHODDEF(void) +put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +/* used for unquantized full-color output */ +{ + tga_dest_ptr dest = (tga_dest_ptr) dinfo; + register JSAMPROW inptr; + register char * outptr; + register JDIMENSION col; + + inptr = dest->pub.buffer[0]; + outptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + outptr[0] = (char) GETJSAMPLE(inptr[2]); /* RGB to BGR order */ + outptr[1] = (char) GETJSAMPLE(inptr[1]); + outptr[2] = (char) GETJSAMPLE(inptr[0]); + inptr += 3, outptr += 3; + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + +METHODDEF(void) +put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +/* used for grayscale OR quantized color output */ +{ + tga_dest_ptr dest = (tga_dest_ptr) dinfo; + register JSAMPROW inptr; + register char * outptr; + register JDIMENSION col; + + inptr = dest->pub.buffer[0]; + outptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + *outptr++ = (char) GETJSAMPLE(*inptr++); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * Write some demapped pixel data when color quantization is in effect. + * For Targa, this is only applied to grayscale data. + */ + +METHODDEF(void) +put_demapped_gray (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + tga_dest_ptr dest = (tga_dest_ptr) dinfo; + register JSAMPROW inptr; + register char * outptr; + register JSAMPROW color_map0 = cinfo->colormap[0]; + register JDIMENSION col; + + inptr = dest->pub.buffer[0]; + outptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + *outptr++ = (char) GETJSAMPLE(color_map0[GETJSAMPLE(*inptr++)]); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * Startup: write the file header. + */ + +METHODDEF(void) +start_output_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + tga_dest_ptr dest = (tga_dest_ptr) dinfo; + int num_colors, i; + FILE *outfile; + + if (cinfo->out_color_space == JCS_GRAYSCALE) { + /* Targa doesn't have a mapped grayscale format, so we will */ + /* demap quantized gray output. Never emit a colormap. */ + write_header(cinfo, dinfo, 0); + if (cinfo->quantize_colors) + dest->pub.put_pixel_rows = put_demapped_gray; + else + dest->pub.put_pixel_rows = put_gray_rows; + } else if (cinfo->out_color_space == JCS_RGB) { + if (cinfo->quantize_colors) { + /* We only support 8-bit colormap indexes, so only 256 colors */ + num_colors = cinfo->actual_number_of_colors; + if (num_colors > 256) + ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, num_colors); + write_header(cinfo, dinfo, num_colors); + /* Write the colormap. Note Targa uses BGR byte order */ + outfile = dest->pub.output_file; + for (i = 0; i < num_colors; i++) { + putc(GETJSAMPLE(cinfo->colormap[2][i]), outfile); + putc(GETJSAMPLE(cinfo->colormap[1][i]), outfile); + putc(GETJSAMPLE(cinfo->colormap[0][i]), outfile); + } + dest->pub.put_pixel_rows = put_gray_rows; + } else { + write_header(cinfo, dinfo, 0); + dest->pub.put_pixel_rows = put_pixel_rows; + } + } else { + ERREXIT(cinfo, JERR_TGA_COLORSPACE); + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_output_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + /* Make sure we wrote the output file OK */ + fflush(dinfo->output_file); + if (ferror(dinfo->output_file)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for Targa format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_targa (j_decompress_ptr cinfo) +{ + tga_dest_ptr dest; + + /* Create module interface object, fill in method pointers */ + dest = (tga_dest_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(tga_dest_struct)); + dest->pub.start_output = start_output_tga; + dest->pub.finish_output = finish_output_tga; + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + /* Create I/O buffer. Note we make this near on a PC. */ + dest->buffer_width = cinfo->output_width * cinfo->output_components; + dest->iobuffer = (char *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (size_t) (dest->buffer_width * SIZEOF(char))); + + /* Create decompressor output buffer. */ + dest->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, dest->buffer_width, (JDIMENSION) 1); + dest->pub.buffer_height = 1; + + return (djpeg_dest_ptr) dest; +} + +#endif /* TARGA_SUPPORTED */ diff --git a/source/Irrlicht/leakHunter.cpp b/source/Irrlicht/leakHunter.cpp new file mode 100644 index 00000000..4935767b --- /dev/null +++ b/source/Irrlicht/leakHunter.cpp @@ -0,0 +1,15 @@ +// Copyright (C) 2013 Michael Zeilfelder +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "leakHunter.h" + +#ifdef _IRR_COMPILE_WITH_LEAK_HUNTER_ + +namespace irr +{ + irr::core::array LeakHunter::ReferenceCountedObjects; +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_LEAK_HUNTER_ + diff --git a/source/Irrlicht/libpng/ANNOUNCE b/source/Irrlicht/libpng/ANNOUNCE new file mode 100644 index 00000000..e427fd4a --- /dev/null +++ b/source/Irrlicht/libpng/ANNOUNCE @@ -0,0 +1,48 @@ +Libpng 1.6.23 - June 9, 2016 + +This is a public release of libpng, intended for use in production codes. + +Files available for download: + +Source files with LF line endings (for Unix/Linux) and with a +"configure" script + + libpng-1.6.23.tar.xz (LZMA-compressed, recommended) + libpng-1.6.23.tar.gz + +Source files with CRLF line endings (for Windows), without the +"configure" script + + lpng1623.7z (LZMA-compressed, recommended) + lpng1623.zip + +Other information: + + libpng-1.6.23-README.txt + libpng-1.6.23-LICENSE.txt + libpng-1.6.23-*.asc (armored detached GPG signatures) + +Changes since the last public release (1.6.22): + + Stop a potential memory leak in png_set_tRNS() (Bug report by Ted Ying). + Fixed the progressive reader to handle empty first IDAT chunk properly + (patch by Timothy Nikkel). This bug was introduced in libpng-1.6.0 and + only affected the libpng16 branch. + Added tests in pngvalid.c to check zero-length IDAT chunks in various + positions. Fixed the sequential reader to handle these more robustly + (John Bowler). + Corrected progressive read input buffer in pngvalid.c. The previous version + the code invariably passed just one byte at a time to libpng. The intent + was to pass a random number of bytes in the range 0..511. + Moved sse2 prototype from pngpriv.h to contrib/intel/intel_sse.patch. + Added missing ")" in pngerror.c (Matt Sarrett). + Fixed undefined behavior in png_push_save_buffer(). Do not call + memcpy() with a null source, even if count is zero (Leon Scroggins III). + Fixed bad link to RFC2083 in png.5 (Nikola Forro). + +(subscription required; visit +https://lists.sourceforge.net/lists/listinfo/png-mng-implement +to subscribe) +or to glennrp at users.sourceforge.net + +Glenn R-P diff --git a/source/Irrlicht/libpng/CHANGES b/source/Irrlicht/libpng/CHANGES new file mode 100644 index 00000000..55a4d469 --- /dev/null +++ b/source/Irrlicht/libpng/CHANGES @@ -0,0 +1,5606 @@ +#if 0 +CHANGES - changes for libpng + +version 0.1 [March 29, 1995] + initial work-in-progress release + +version 0.2 [April 1, 1995] + added reader into png.h + fixed small problems in stub file + +version 0.3 [April 8, 1995] + added pull reader + split up pngwrite.c to several files + added pnglib.txt + added example.c + cleaned up writer, adding a few new transformations + fixed some bugs in writer + interfaced with zlib 0.5 + added K&R support + added check for 64 KB blocks for 16 bit machines + +version 0.4 [April 26, 1995] + cleaned up code and commented code + simplified time handling into png_time + created png_color_16 and png_color_8 to handle color needs + cleaned up color type defines + fixed various bugs + made various names more consistent + interfaced with zlib 0.71 + cleaned up zTXt reader and writer (using zlib's Reset functions) + split transformations into pngrtran.c and pngwtran.c + +version 0.5 [April 30, 1995] + interfaced with zlib 0.8 + fixed many reading and writing bugs + saved using 3 spaces instead of tabs + +version 0.6 [May 1, 1995] + first beta release + added png_large_malloc() and png_large_free() + added png_size_t + cleaned up some compiler warnings + added png_start_read_image() + +version 0.7 [June 24, 1995] + cleaned up lots of bugs + finished dithering and other stuff + added test program + changed name from pnglib to libpng + +version 0.71 [June 26, 1995] + changed pngtest.png for zlib 0.93 + fixed error in libpng.txt and example.c + +version 0.8 [August 20, 1995] + cleaned up some bugs + added png_set_filler() + split up pngstub.c into pngmem.c, pngio.c, and pngerror.c + added #define's to remove unwanted code + moved png_info_init() to png.c + added old_size into png_realloc() + added functions to manually set filtering and compression info + changed compression parameters based on image type + optimized filter selection code + added version info + changed external functions passing floats to doubles (k&r problems?) + put all the configurable stuff in pngconf.h + enabled png_set_shift to work with paletted images on read + added png_read_update_info() - updates info structure with transformations + +Version 0.81 [August, 1995] + incorporated Tim Wegner's medium model code (thanks, Tim) + +Version 0.82 [September, 1995] + [unspecified changes] + +Version 0.85 [December, 1995] + added more medium model code (almost everything's a far) + added i/o, error, and memory callback functions + fixed some bugs (16-bit, 4-bit interlaced, etc.) + added first run progressive reader (barely tested) + +Version 0.86 [January, 1996] + fixed bugs + improved documentation + +Version 0.87 [January, 1996] + fixed medium model bugs + fixed other bugs introduced in 0.85 and 0.86 + added some minor documentation + +Version 0.88 [January, 1996] + fixed progressive bugs + replaced tabs with spaces + cleaned up documentation + added callbacks for read/write and warning/error functions + +Version 0.89 [June 5, 1996] + Added new initialization API to make libpng work better with shared libs + we now have png_create_read_struct(), png_create_write_struct(), + png_create_info_struct(), png_destroy_read_struct(), and + png_destroy_write_struct() instead of the separate calls to + malloc and png_read_init(), png_info_init(), and png_write_init() + Changed warning/error callback functions to fix bug - this means you + should use the new initialization API if you were using the old + png_set_message_fn() calls, and that the old API no longer exists + so that people are aware that they need to change their code + Changed filter selection API to allow selection of multiple filters + since it didn't work in previous versions of libpng anyways + Optimized filter selection code + Fixed png_set_background() to allow using an arbitrary RGB color for + paletted images + Fixed gamma and background correction for paletted images, so + png_correct_palette is not needed unless you are correcting an + external palette (you will need to #define PNG_CORRECT_PALETTE_SUPPORTED + in pngconf.h) - if nobody uses this, it may disappear in the future. + Fixed bug with Borland 64K memory allocation (Alexander Lehmann) + Fixed bug in interlace handling (Smarasderagd, I think) + Added more error checking for writing and image to reduce invalid files + Separated read and write functions so that they won't both be linked + into a binary when only reading or writing functionality is used + New pngtest image also has interlacing and zTXt + Updated documentation to reflect new API + +Version 0.89c [June 17, 1996] + Bug fixes. + +Version 0.90 [January, 1997] + Made CRC errors/warnings on critical and ancillary chunks configurable + libpng will use the zlib CRC routines by (compile-time) default + Changed DOS small/medium model memory support - needs zlib 1.04 (Tim Wegner) + Added external C++ wrapper statements to png.h (Gilles Dauphin) + Allow PNG file to be read when some or all of file signature has already + been read from the beginning of the stream. ****This affects the size + of info_struct and invalidates all programs that use a shared libpng**** + Fixed png_filler() declarations + Fixed? background color conversions + Fixed order of error function pointers to match documentation + Current chunk name is now available in png_struct to reduce the number + of nearly identical error messages (will simplify multi-lingual + support when available) + Try to get ready for unknown-chunk callback functions: + - previously read critical chunks are flagged, so the chunk handling + routines can determine if the chunk is in the right place + - all chunk handling routines have the same prototypes, so we will + be able to handle all chunks via a callback mechanism + Try to fix Linux "setjmp" buffer size problems + Removed png_large_malloc, png_large_free, and png_realloc functions. + +Version 0.95 [March, 1997] + Fixed bug in pngwutil.c allocating "up_row" twice and "avg_row" never + Fixed bug in PNG file signature compares when start != 0 + Changed parameter type of png_set_filler(...filler...) from png_byte + to png_uint_32 + Added test for MACOS to ensure that both math.h and fp.h are not #included + Added macros for libpng to be compiled as a Windows DLL (Andreas Kupries) + Added "packswap" transformation, which changes the endianness of + packed-pixel bytes (Kevin Bracey) + Added "strip_alpha" transformation, which removes the alpha channel of + input images without using it (not necessarily a good idea) + Added "swap_alpha" transformation, which puts the alpha channel in front + of the color bytes instead of after + Removed all implicit variable tests which assume NULL == 0 (I think) + Changed several variables to "png_size_t" to show 16/32-bit limitations + Added new pCAL chunk read/write support + Added experimental filter selection weighting (Greg Roelofs) + Removed old png_set_rgbx() and png_set_xrgb() functions that have been + obsolete for about 2 years now (use png_set_filler() instead) + Added macros to read 16- and 32-bit ints directly from buffer, to be + used only on those systems that support it (namely PowerPC and 680x0) + With some testing, this may become the default for MACOS/PPC systems. + Only calculate CRC on data if we are going to use it + Added macros for zTXt compression type PNG_zTXt_COMPRESSION_??? + Added macros for simple libpng debugging output selectable at compile time + Removed PNG_READ_END_MODE in progressive reader (Smarasderagd) + More description of info_struct in libpng.txt and png.h + More instructions in example.c + More chunk types tested in pngtest.c + Renamed pngrcb.c to pngset.c, and all png_read_ functions to be + png_set_. We now have corresponding png_get_ + functions in pngget.c to get information in info_ptr. This isolates + the application from the internal organization of png_info_struct + (good for shared library implementations). + +Version 0.96 [May, 1997] + Fixed serious bug with < 8bpp images introduced in 0.95 + Fixed 256-color transparency bug (Greg Roelofs) + Fixed up documentation (Greg Roelofs, Laszlo Nyul) + Fixed "error" in pngconf.h for Linux setjmp() behavior + Fixed DOS medium model support (Tim Wegner) + Fixed png_check_keyword() for case with error in static string text + Added read of CRC after IEND chunk for embedded PNGs (Laszlo Nyul) + Added typecasts to quiet compiler errors + Added more debugging info + +Version 0.97 [January, 1998] + Removed PNG_USE_OWN_CRC capability + Relocated png_set_crc_action from pngrutil.c to pngrtran.c + Fixed typecasts of "new_key", etc. (Andreas Dilger) + Added RFC 1152 [sic] date support + Fixed bug in gamma handling of 4-bit grayscale + Added 2-bit grayscale gamma handling (Glenn R-P) + Added more typecasts. 65536L becomes (png_uint_32)65536L, etc. (Glenn R-P) + Minor corrections in libpng.txt + Added simple sRGB support (Glenn R-P) + Easier conditional compiling, e.g., + define PNG_READ/WRITE_NOT_FULLY_SUPPORTED; + all configurable options can be selected from command-line instead + of having to edit pngconf.h (Glenn R-P) + Fixed memory leak in pngwrite.c (free info_ptr->text) (Glenn R-P) + Added more conditions for png_do_background, to avoid changing + black pixels to background when a background is supplied and + no pixels are transparent + Repaired PNG_NO_STDIO behavior + Tested NODIV support and made it default behavior (Greg Roelofs) + Added "-m" option and PNGTEST_DEBUG_MEMORY to pngtest (John Bowler) + Regularized version numbering scheme and bumped shared-library major + version number to 2 to avoid problems with libpng 0.89 apps + (Greg Roelofs) + +Version 0.98 [January, 1998] + Cleaned up some typos in libpng.txt and in code documentation + Fixed memory leaks in pCAL chunk processing (Glenn R-P and John Bowler) + Cosmetic change "display_gamma" to "screen_gamma" in pngrtran.c + Changed recommendation about file_gamma for PC images to .51 from .45, + in example.c and libpng.txt, added comments to distinguish between + screen_gamma, viewing_gamma, and display_gamma. + Changed all references to RFC1152 to read RFC1123 and changed the + PNG_TIME_RFC1152_SUPPORTED macro to PNG_TIME_RFC1123_SUPPORTED + Added png_invert_alpha capability (Glenn R-P -- suggestion by Jon Vincent) + Changed srgb_intent from png_byte to int to avoid compiler bugs + +Version 0.99 [January 30, 1998] + Free info_ptr->text instead of end_info_ptr->text in pngread.c (John Bowler) + Fixed a longstanding "packswap" bug in pngtrans.c + Fixed some inconsistencies in pngconf.h that prevented compiling with + PNG_READ_GAMMA_SUPPORTED and PNG_READ_hIST_SUPPORTED undefined + Fixed some typos and made other minor rearrangement of libpng.txt (Andreas) + Changed recommendation about file_gamma for PC images to .50 from .51 in + example.c and libpng.txt, and changed file_gamma for sRGB images to .45 + Added a number of functions to access information from the png structure + png_get_image_height(), etc. (Glenn R-P, suggestion by Brad Pettit) + Added TARGET_MACOS similar to zlib-1.0.8 + Define PNG_ALWAYS_EXTERN when __MWERKS__ && WIN32 are defined + Added type casting to all png_malloc() function calls + +Version 0.99a [January 31, 1998] + Added type casts and parentheses to all returns that return a value.(Tim W.) + +Version 0.99b [February 4, 1998] + Added type cast png_uint_32 on malloc function calls where needed. + Changed type of num_hist from png_uint_32 to int (same as num_palette). + Added checks for rowbytes overflow, in case png_size_t is less than 32 bits. + Renamed makefile.elf to makefile.lnx. + +Version 0.99c [February 7, 1998] + More type casting. Removed erroneous overflow test in pngmem.c. + Added png_buffered_memcpy() and png_buffered_memset(), apply them to rowbytes. + Added UNIX manual pages libpng.3 (incorporating libpng.txt) and png.5. + +Version 0.99d [February 11, 1998] + Renamed "far_to_near()" "png_far_to_near()" + Revised libpng.3 + Version 99c "buffered" operations didn't work as intended. Replaced them + with png_memcpy_check() and png_memset_check(). + Added many "if (png_ptr == NULL) return" to quell compiler warnings about + unused png_ptr, mostly in pngget.c and pngset.c. + Check for overlength tRNS chunk present when indexed-color PLTE is read. + Cleaned up spelling errors in libpng.3/libpng.txt + Corrected a problem with png_get_tRNS() which returned undefined trans array + +Version 0.99e [February 28, 1998] + Corrected png_get_tRNS() again. + Add parentheses for easier reading of pngget.c, fixed "||" should be "&&". + Touched up example.c to make more of it compileable, although the entire + file still can't be compiled (Willem van Schaik) + Fixed a bug in png_do_shift() (Bryan Tsai) + Added a space in png.h prototype for png_write_chunk_start() + Replaced pngtest.png with one created with zlib 1.1.1 + Changed pngtest to report PASS even when file size is different (Jean-loup G.) + Corrected some logic errors in png_do_invert_alpha() (Chris Patterson) + +Version 0.99f [March 5, 1998] + Corrected a bug in pngpread() introduced in version 99c (Kevin Bracey) + Moved makefiles into a "scripts" directory, and added INSTALL instruction file + Added makefile.os2 and pngos2.def (A. Zabolotny) and makefile.s2x (W. Sebok) + Added pointers to "note on libpng versions" in makefile.lnx and README + Added row callback feature when reading and writing nonprogressive rows + and added a test of this feature in pngtest.c + Added user transform callbacks, with test of the feature in pngtest.c + +Version 0.99g [March 6, 1998, morning] + Minor changes to pngtest.c to suppress compiler warnings. + Removed "beta" language from documentation. + +Version 0.99h [March 6, 1998, evening] + Minor changes to previous minor changes to pngtest.c + Changed PNG_READ_NOT_FULLY_SUPPORTED to PNG_READ_TRANSFORMS_NOT_SUPPORTED + and added PNG_PROGRESSIVE_READ_NOT_SUPPORTED macro + Added user transform capability + +Version 1.00 [March 7, 1998] + Changed several typedefs in pngrutil.c + Added makefile.wat (Pawel Mrochen), updated makefile.tc3 (Willem van Schaik) + Replaced "while(1)" with "for(;;)" + Added PNGARG() to prototypes in pngtest.c and removed some prototypes + Updated some of the makefiles (Tom Lane) + Changed some typedefs (s_start, etc.) in pngrutil.c + Fixed dimensions of "short_months" array in pngwrite.c + Replaced ansi2knr.c with the one from jpeg-v6 + +Version 1.0.0 [March 8, 1998] + Changed name from 1.00 to 1.0.0 (Adam Costello) + Added smakefile.ppc (with SCOPTIONS.ppc) for Amiga PPC (Andreas Kleinert) + +Version 1.0.0a [March 9, 1998] + Fixed three bugs in pngrtran.c to make gamma+background handling consistent + (Greg Roelofs) + Changed format of the PNG_LIBPNG_VER integer to xyyzz instead of xyz + for major, minor, and bugfix releases. This is 10001. (Adam Costello, + Tom Lane) + Make months range from 1-12 in png_convert_to_rfc1123 + +Version 1.0.0b [March 13, 1998] + Quieted compiler complaints about two empty "for" loops in pngrutil.c + Minor changes to makefile.s2x + Removed #ifdef/#endif around a png_free() in pngread.c + +Version 1.0.1 [March 14, 1998] + Changed makefile.s2x to reduce security risk of using a relative pathname + Fixed some typos in the documentation (Greg). + Fixed a problem with value of "channels" returned by png_read_update_info() + +Version 1.0.1a [April 21, 1998] + Optimized Paeth calculations by replacing abs() function calls with intrinsics + plus other loop optimizations. Improves avg decoding speed by about 20%. + Commented out i386istic "align" compiler flags in makefile.lnx. + Reduced the default warning level in some makefiles, to make them consistent. + Removed references to IJG and JPEG in the ansi2knr.c copyright statement. + Fixed a bug in png_do_strip_filler with XXRRGGBB => RRGGBB transformation. + Added grayscale and 16-bit capability to png_do_read_filler(). + Fixed a bug in pngset.c, introduced in version 0.99c, that sets rowbytes + too large when writing an image with bit_depth < 8 (Bob Dellaca). + Corrected some bugs in the experimental weighted filtering heuristics. + Moved a misplaced pngrutil code block that truncates tRNS if it has more + than num_palette entries -- test was done before num_palette was defined. + Fixed a png_convert_to_rfc1123() bug that converts day 31 to 0 (Steve Eddins). + Changed compiler flags in makefile.wat for better optimization + (Pawel Mrochen). + +Version 1.0.1b [May 2, 1998] + Relocated png_do_gray_to_rgb() within png_do_read_transformations() (Greg). + Relocated the png_composite macros from pngrtran.c to png.h (Greg). + Added makefile.sco (contributed by Mike Hopkirk). + Fixed two bugs (missing definitions of "istop") introduced in libpng-1.0.1a. + Fixed a bug in pngrtran.c that would set channels=5 under some circumstances. + More work on the Paeth-filtering, achieving imperceptible speedup + (A Kleinert). + More work on loop optimization which may help when compiled with C++ + compilers. + Added warnings when people try to use transforms they've defined out. + Collapsed 4 "i" and "c" loops into single "i" loops in pngrtran and pngwtran. + Revised paragraph about png_set_expand() in libpng.txt and libpng.3 (Greg) + +Version 1.0.1c [May 11, 1998] + Fixed a bug in pngrtran.c (introduced in libpng-1.0.1a) where the masks for + filler bytes should have been 0xff instead of 0xf. + Added max_pixel_depth=32 in pngrutil.c when using FILLER with palette images. + Moved PNG_WRITE_WEIGHTED_FILTER_SUPPORTED and PNG_WRITE_FLUSH_SUPPORTED + out of the PNG_WRITE_TRANSFORMS_NOT_SUPPORTED block of pngconf.h + Added "PNG_NO_WRITE_TRANSFORMS" etc., as alternatives for *_NOT_SUPPORTED, + for consistency, in pngconf.h + Added individual "ifndef PNG_NO_[CAPABILITY]" in pngconf.h to make it easier + to remove unwanted capabilities via the compile line + Made some corrections to grammar (which, it's) in documentation (Greg). + Corrected example.c, use of row_pointers in png_write_image(). + +Version 1.0.1d [May 24, 1998] + Corrected several statements that used side effects illegally in pngrutil.c + and pngtrans.c, that were introduced in version 1.0.1b + Revised png_read_rows() to avoid repeated if-testing for NULL (A Kleinert) + More corrections to example.c, use of row_pointers in png_write_image() + and png_read_rows(). + Added pngdll.mak and pngdef.pas to scripts directory, contributed by + Bob Dellaca, to make a png32bd.dll with Borland C++ 4.5 + Fixed error in example.c with png_set_text: num_text is 3, not 2 (Guido V.) + Changed several loops from count-down to count-up, for consistency. + +Version 1.0.1e [June 6, 1998] + Revised libpng.txt and libpng.3 description of png_set_read|write_fn(), and + added warnings when people try to set png_read_fn and png_write_fn in + the same structure. + Added a test such that png_do_gamma will be done when num_trans==0 + for truecolor images that have defined a background. This corrects an + error that was introduced in libpng-0.90 that can cause gamma processing + to be skipped. + Added tests in png.h to include "trans" and "trans_values" in structures + when PNG_READ_BACKGROUND_SUPPORTED or PNG_READ_EXPAND_SUPPORTED is defined. + Add png_free(png_ptr->time_buffer) in png_destroy_read_struct() + Moved png_convert_to_rfc_1123() from pngwrite.c to png.c + Added capability for user-provided malloc_fn() and free_fn() functions, + and revised pngtest.c to demonstrate their use, replacing the + PNGTEST_DEBUG_MEM feature. + Added makefile.w32, for Microsoft C++ 4.0 and later (Tim Wegner). + +Version 1.0.2 [June 14, 1998] + Fixed two bugs in makefile.bor . + +Version 1.0.2a [December 30, 1998] + Replaced and extended code that was removed from png_set_filler() in 1.0.1a. + Fixed a bug in png_do_filler() that made it fail to write filler bytes in + the left-most pixel of each row (Kevin Bracey). + Changed "static pngcharp tIME_string" to "static char tIME_string[30]" + in pngtest.c (Duncan Simpson). + Fixed a bug in pngtest.c that caused pngtest to try to write a tIME chunk + even when no tIME chunk was present in the source file. + Fixed a problem in pngrutil.c: gray_to_rgb didn't always work with 16-bit. + Fixed a problem in png_read_push_finish_row(), which would not skip some + passes that it should skip, for images that are less than 3 pixels high. + Interchanged the order of calls to png_do_swap() and png_do_shift() + in pngwtran.c (John Cromer). + Added #ifdef PNG_DEBUG/#endif surrounding use of PNG_DEBUG in png.h . + Changed "bad adaptive filter type" from error to warning in pngrutil.c . + Fixed a documentation error about default filtering with 8-bit indexed-color. + Separated the PNG_NO_STDIO macro into PNG_NO_STDIO and PNG_NO_CONSOLE_IO + (L. Peter Deutsch). + Added png_set_rgb_to_gray() and png_get_rgb_to_gray_status() functions. + Added png_get_copyright() and png_get_header_version() functions. + Revised comments on png_set_progressive_read_fn() in libpng.txt and example.c + Added information about debugging in libpng.txt and libpng.3 . + Changed "ln -sf" to "ln -s -f" in makefile.s2x, makefile.lnx, and + makefile.sco. + Removed lines after Dynamic Dependencies" in makefile.aco . + Revised makefile.dec to make a shared library (Jeremie Petit). + Removed trailing blanks from all files. + +Version 1.0.2a [January 6, 1999] + Removed misplaced #endif and #ifdef PNG_NO_EXTERN near the end of png.h + Added "if" tests to silence complaints about unused png_ptr in png.h and png.c + Changed "check_if_png" function in example.c to return true (nonzero) if PNG. + Changed libpng.txt to demonstrate png_sig_cmp() instead of png_check_sig() + which is obsolete. + +Version 1.0.3 [January 14, 1999] + Added makefile.hux, for Hewlett Packard HPUX 10.20 and 11.00 (Jim Rice) + Added a statement of Y2K compliance in png.h, libpng.3, and Y2KINFO. + +Version 1.0.3a [August 12, 1999] + Added check for PNG_READ_INTERLACE_SUPPORTED in pngread.c; issue a warning + if an attempt is made to read an interlaced image when it's not supported. + Added check if png_ptr->trans is defined before freeing it in pngread.c + Modified the Y2K statement to include versions back to version 0.71 + Fixed a bug in the check for valid IHDR bit_depth/color_types in pngrutil.c + Modified makefile.wat (added -zp8 flag, ".symbolic", changed some comments) + Replaced leading blanks with tab characters in makefile.hux + Changed "dworkin.wustl.edu" to "ccrc.wustl.edu" in various documents. + Changed (float)red and (float)green to (double)red, (double)green + in png_set_rgb_to_gray() to avoid "promotion" problems in AIX. + Fixed a bug in pngconf.h that omitted when PNG_DEBUG==0 (K Bracey). + Reformatted libpng.3 and libpngpf.3 with proper fonts (script by J. vanZandt). + Updated documentation to refer to the PNG-1.2 specification. + Removed ansi2knr.c and left pointers to the latest source for ansi2knr.c + in makefile.knr, INSTALL, and README (L. Peter Deutsch) + Fixed bugs in calculation of the length of rowbytes when adding alpha + channels to 16-bit images, in pngrtran.c (Chris Nokleberg) + Added function png_set_user_transform_info() to store user_transform_ptr, + user_depth, and user_channels into the png_struct, and a function + png_get_user_transform_ptr() to retrieve the pointer (Chris Nokleberg) + Added function png_set_empty_plte_permitted() to make libpng useable + in MNG applications. + Corrected the typedef for png_free_ptr in png.h (Jesse Jones). + Correct gamma with srgb is 45455 instead of 45000 in pngrutil.c, to be + consistent with PNG-1.2, and allow variance of 500 before complaining. + Added assembler code contributed by Intel in file pngvcrd.c and modified + makefile.w32 to use it (Nirav Chhatrapati, INTEL Corporation, + Gilles Vollant) + Changed "ln -s -f" to "ln -f -s" in the makefiles to make Solaris happy. + Added some aliases for png_set_expand() in pngrtran.c, namely + png_set_expand_PLTE(), png_set_expand_depth(), and png_set_expand_tRNS() + (Greg Roelofs, in "PNG: The Definitive Guide"). + Added makefile.beo for BEOS on X86, contributed by Sander Stok. + +Version 1.0.3b [August 26, 1999] + Replaced 2147483647L several places with PNG_MAX_UINT macro, defined in png.h + Changed leading blanks to tabs in all makefiles. + Define PNG_USE_PNGVCRD in makefile.w32, to get MMX assembler code. + Made alternate versions of png_set_expand() in pngrtran.c, namely + png_set_gray_1_2_4_to_8, png_set_palette_to_rgb, and png_set_tRNS_to_alpha + (Greg Roelofs, in "PNG: The Definitive Guide"). Deleted the 1.0.3a aliases. + Relocated start of 'extern "C"' block in png.h so it doesn't include pngconf.h + Revised calculation of num_blocks in pngmem.c to avoid a potentially + negative shift distance, whose results are undefined in the C language. + Added a check in pngset.c to prevent writing multiple tIME chunks. + Added a check in pngwrite.c to detect invalid small window_bits sizes. + +Version 1.0.3d [September 4, 1999] + Fixed type casting of igamma in pngrutil.c + Added new png_expand functions to scripts/pngdef.pas and pngos2.def + Added a demo read_user_transform_fn that examines the row filters in pngtest.c + +Version 1.0.4 [September 24, 1999, not distributed publicly] + Define PNG_ALWAYS_EXTERN in pngconf.h if __STDC__ is defined + Delete #define PNG_INTERNAL and include "png.h" from pngasmrd.h + Made several minor corrections to pngtest.c + Renamed the makefiles with longer but more user friendly extensions. + Copied the PNG copyright and license to a separate LICENSE file. + Revised documentation, png.h, and example.c to remove reference to + "viewing_gamma" which no longer appears in the PNG specification. + Revised pngvcrd.c to use MMX code for interlacing only on the final pass. + Updated pngvcrd.c to use the faster C filter algorithms from libpng-1.0.1a + Split makefile.win32vc into two versions, makefile.vcawin32 (uses MMX + assembler code) and makefile.vcwin32 (doesn't). + Added a CPU timing report to pngtest.c (enabled by defining PNGTEST_TIMING) + Added a copy of pngnow.png to the distribution. + +Version 1.0.4a [September 25, 1999] + Increase max_pixel_depth in pngrutil.c if a user transform needs it. + Changed several division operations to right-shifts in pngvcrd.c + +Version 1.0.4b [September 30, 1999] + Added parentheses in line 3732 of pngvcrd.c + Added a comment in makefile.linux warning about buggy -O3 in pgcc 2.95.1 + +Version 1.0.4c [October 1, 1999] + Added a "png_check_version" function in png.c and pngtest.c that will generate + a helpful compiler error if an old png.h is found in the search path. + Changed type of png_user_transform_depth|channels from int to png_byte. + Added "Libpng is OSI Certified Open Source Software" statement to png.h + +Version 1.0.4d [October 6, 1999] + Changed 0.45 to 0.45455 in png_set_sRGB() + Removed unused PLTE entries from pngnow.png + Re-enabled some parts of pngvcrd.c (png_combine_row) that work properly. + +Version 1.0.4e [October 10, 1999] + Fixed sign error in pngvcrd.c (Greg Roelofs) + Replaced some instances of memcpy with simple assignments in pngvcrd (GR-P) + +Version 1.0.4f [October 15, 1999] + Surrounded example.c code with #if 0 .. #endif to prevent people from + inadvertently trying to compile it. + Changed png_get_header_version() from a function to a macro in png.h + Added type casting mostly in pngrtran.c and pngwtran.c + Removed some pointless "ptr = NULL" in pngmem.c + Added a "contrib" directory containing the source code from Greg's book. + +Version 1.0.5 [October 15, 1999] + Minor editing of the INSTALL and README files. + +Version 1.0.5a [October 23, 1999] + Added contrib/pngsuite and contrib/pngminus (Willem van Schaik) + Fixed a typo in the png_set_sRGB() function call in example.c (Jan Nijtmans) + Further optimization and bugfix of pngvcrd.c + Revised pngset.c so that it does not allocate or free memory in the user's + text_ptr structure. Instead, it makes its own copy. + Created separate write_end_info_struct in pngtest.c for a more severe test. + Added code in pngwrite.c to free info_ptr->text[i].key to stop a memory leak. + +Version 1.0.5b [November 23, 1999] + Moved PNG_FLAG_HAVE_CHUNK_HEADER, PNG_FLAG_BACKGROUND_IS_GRAY and + PNG_FLAG_WROTE_tIME from flags to mode. + Added png_write_info_before_PLTE() function. + Fixed some typecasting in contrib/gregbook/*.c + Updated scripts/makevms.com and added makevms.com to contrib/gregbook + and contrib/pngminus (Martin Zinser) + +Version 1.0.5c [November 26, 1999] + Moved png_get_header_version from png.h to png.c, to accommodate ansi2knr. + Removed all global arrays (according to PNG_NO_GLOBAL_ARRAYS macro), to + accommodate making DLL's: Moved usr_png_ver from global variable to function + png_get_header_ver() in png.c. Moved png_sig to png_sig_bytes in png.c and + eliminated use of png_sig in pngwutil.c. Moved the various png_CHNK arrays + into pngtypes.h. Eliminated use of global png_pass arrays. Declared the + png_CHNK and png_pass arrays to be "const". Made the global arrays + available to applications (although none are used in libpng itself) when + PNG_NO_GLOBAL_ARRAYS is not defined or when PNG_GLOBAL_ARRAYS is defined. + Removed some extraneous "-I" from contrib/pngminus/makefile.std + Changed the PNG_sRGB_INTENT macros in png.h to be consistent with PNG-1.2. + Change PNG_SRGB_INTENT to PNG_sRGB_INTENT in libpng.txt and libpng.3 + +Version 1.0.5d [November 29, 1999] + Add type cast (png_const_charp) two places in png.c + Eliminated pngtypes.h; use macros instead to declare PNG_CHNK arrays. + Renamed "PNG_GLOBAL_ARRAYS" to "PNG_USE_GLOBAL_ARRAYS" and made available + to applications a macro "PNG_USE_LOCAL_ARRAYS". + comment out (with #ifdef) all the new declarations when + PNG_USE_GLOBAL_ARRAYS is defined. + Added PNG_EXPORT_VAR macro to accommodate making DLL's. + +Version 1.0.5e [November 30, 1999] + Added iCCP, iTXt, and sPLT support; added "lang" member to the png_text + structure; refactored the inflate/deflate support to make adding new chunks + with trailing compressed parts easier in the future, and added new functions + png_free_iCCP, png_free_pCAL, png_free_sPLT, png_free_text, png_get_iCCP, + png_get_spalettes, png_set_iCCP, png_set_spalettes (Eric S. Raymond). + NOTE: Applications that write text chunks MUST define png_text->lang + before calling png_set_text(). It must be set to NULL if you want to + write tEXt or zTXt chunks. If you want your application to be able to + run with older versions of libpng, use + + #ifdef PNG_iTXt_SUPPORTED + png_text[i].lang = NULL; + #endif + + Changed png_get_oFFs() and png_set_oFFs() to use signed rather than unsigned + offsets (Eric S. Raymond). + Combined PNG_READ_cHNK_SUPPORTED and PNG_WRITE_cHNK_SUPPORTED macros into + PNG_cHNK_SUPPORTED and combined the three types of PNG_text_SUPPORTED + macros, leaving the separate macros also available. + Removed comments on #endifs at the end of many short, non-nested #if-blocks. + +Version 1.0.5f [December 6, 1999] + Changed makefile.solaris to issue a warning about potential problems when + the ucb "ld" is in the path ahead of the ccs "ld". + Removed "- [date]" from the "synopsis" line in libpng.3 and libpngpf.3. + Added sCAL chunk support (Eric S. Raymond). + +Version 1.0.5g [December 7, 1999] + Fixed "png_free_spallettes" typo in png.h + Added code to handle new chunks in pngpread.c + Moved PNG_CHNK string macro definitions outside of PNG_NO_EXTERN block + Added "translated_key" to png_text structure and png_write_iTXt(). + Added code in pngwrite.c to work around a newly discovered zlib bug. + +Version 1.0.5h [December 10, 1999] + NOTE: regarding the note for version 1.0.5e, the following must also + be included in your code: + png_text[i].translated_key = NULL; + Unknown chunk handling is now supported. + Option to eliminate all floating point support was added. Some new + fixed-point functions such as png_set_gAMA_fixed() were added. + Expanded tabs and removed trailing blanks in source files. + +Version 1.0.5i [December 13, 1999] + Added some type casts to silence compiler warnings. + Renamed "png_free_spalette" to "png_free_spalettes" for consistency. + Removed leading blanks from a #define in pngvcrd.c + Added some parameters to the new png_set_keep_unknown_chunks() function. + Added a test for up->location != 0 in the first instance of writing + unknown chunks in pngwrite.c + Changed "num" to "i" in png_free_spalettes() and png_free_unknowns() to + prevent recursion. + Added png_free_hIST() function. + Various patches to fix bugs in the sCAL and integer cHRM processing, + and to add some convenience macros for use with sCAL. + +Version 1.0.5j [December 21, 1999] + Changed "unit" parameter of png_write_sCAL from png_byte to int, to work + around buggy compilers. + Added new type "png_fixed_point" for integers that hold float*100000 values + Restored backward compatibility of tEXt/zTXt chunk processing: + Restored the first four members of png_text to the same order as v.1.0.5d. + Added members "lang_key" and "itxt_length" to png_text struct. Set + text_length=0 when "text" contains iTXt data. Use the "compression" + member to distinguish among tEXt/zTXt/iTXt types. Added + PNG_ITXT_COMPRESSION_NONE (1) and PNG_ITXT_COMPRESSION_zTXt(2) macros. + The "Note" above, about backward incompatibility of libpng-1.0.5e, no + longer applies. + Fixed png_read|write_iTXt() to read|write parameters in the right order, + and to write the iTXt chunk after IDAT if it appears in the end_ptr. + Added pnggccrd.c, version of pngvcrd.c Intel assembler for gcc (Greg Roelofs) + Reversed the order of trying to write floating-point and fixed-point gAMA. + +Version 1.0.5k [December 27, 1999] + Added many parentheses, e.g., "if (a && b & c)" becomes "if (a && (b & c))" + Added png_handle_as_unknown() function (Glenn) + Added png_free_chunk_list() function and chunk_list and num_chunk_list members + of png_ptr. + Eliminated erroneous warnings about multiple sPLT chunks and sPLT-after-PLTE. + Fixed a libpng-1.0.5h bug in pngrutil.c that was issuing erroneous warnings + about ignoring incorrect gAMA with sRGB (gAMA was in fact not ignored) + Added png_free_tRNS(); png_set_tRNS() now malloc's its own trans array (ESR). + Define png_get_int_32 when oFFs chunk is supported as well as when pCAL is. + Changed type of proflen from png_int_32 to png_uint_32 in png_get_iCCP(). + +Version 1.0.5l [January 1, 2000] + Added functions png_set_read_user_chunk_fn() and png_get_user_chunk_ptr() + for setting a callback function to handle unknown chunks and for + retrieving the associated user pointer (Glenn). + +Version 1.0.5m [January 7, 2000] + Added high-level functions png_read_png(), png_write_png(), png_free_pixels(). + +Version 1.0.5n [January 9, 2000] + Added png_free_PLTE() function, and modified png_set_PLTE() to malloc its + own memory for info_ptr->palette. This makes it safe for the calling + application to free its copy of the palette any time after it calls + png_set_PLTE(). + +Version 1.0.5o [January 20, 2000] + Cosmetic changes only (removed some trailing blanks and TABs) + +Version 1.0.5p [January 31, 2000] + Renamed pngdll.mak to makefile.bd32 + Cosmetic changes in pngtest.c + +Version 1.0.5q [February 5, 2000] + Relocated the makefile.solaris warning about PATH problems. + Fixed pngvcrd.c bug by pushing/popping registers in mmxsupport (Bruce Oberg) + Revised makefile.gcmmx + Added PNG_SETJMP_SUPPORTED, PNG_SETJMP_NOT_SUPPORTED, and PNG_ABORT() macros + +Version 1.0.5r [February 7, 2000] + Removed superfluous prototype for png_get_itxt from png.h + Fixed a bug in pngrtran.c that improperly expanded the background color. + Return *num_text=0 from png_get_text() when appropriate, and fix documentation + of png_get_text() in libpng.txt/libpng.3. + +Version 1.0.5s [February 18, 2000] + Added "png_jmp_env()" macro to pngconf.h, to help people migrate to the + new error handler that's planned for the next libpng release, and changed + example.c, pngtest.c, and contrib programs to use this macro. + Revised some of the DLL-export macros in pngconf.h (Greg Roelofs) + Fixed a bug in png_read_png() that caused it to fail to expand some images + that it should have expanded. + Fixed some mistakes in the unused and undocumented INCH_CONVERSIONS functions + in pngget.c + Changed the allocation of palette, history, and trans arrays back to + the version 1.0.5 method (linking instead of copying) which restores + backward compatibility with version 1.0.5. Added some remarks about + that in example.c. Added "free_me" member to info_ptr and png_ptr + and added png_free_data() function. + Updated makefile.linux and makefile.gccmmx to make directories conditionally. + Made cosmetic changes to pngasmrd.h + Added png_set_rows() and png_get_rows(), for use with png_read|write_png(). + Modified png_read_png() to allocate info_ptr->row_pointers only if it + hasn't already been allocated. + +Version 1.0.5t [March 4, 2000] + Changed png_jmp_env() migration aiding macro to png_jmpbuf(). + Fixed "interlace" typo (should be "interlaced") in contrib/gregbook/read2-x.c + Fixed bug with use of PNG_BEFORE_IHDR bit in png_ptr->mode, introduced when + PNG_FLAG_HAVE_CHUNK_HEADER was moved into png_ptr->mode in version 1.0.5b + Files in contrib/gregbook were revised to use png_jmpbuf() and to select + a 24-bit visual if one is available, and to allow abbreviated options. + Files in contrib/pngminus were revised to use the png_jmpbuf() macro. + Removed spaces in makefile.linux and makefile.gcmmx, introduced in 1.0.5s + +Version 1.0.5u [March 5, 2000] + Simplified the code that detects old png.h in png.c and pngtest.c + Renamed png_spalette (_p, _pp) to png_sPLT_t (_tp, _tpp) + Increased precision of rgb_to_gray calculations from 8 to 15 bits and + added png_set_rgb_to_gray_fixed() function. + Added makefile.bc32 (32-bit Borland C++, C mode) + +Version 1.0.5v [March 11, 2000] + Added some parentheses to the png_jmpbuf macro definition. + Updated references to the zlib home page, which has moved to freesoftware.com. + Corrected bugs in documentation regarding png_read_row() and png_write_row(). + Updated documentation of png_rgb_to_gray calculations in libpng.3/libpng.txt. + Renamed makefile.borland,turboc3 back to makefile.bor,tc3 as in version 1.0.3, + revised borland makefiles; added makefile.ibmvac3 and makefile.gcc (Cosmin) + +Version 1.0.6 [March 20, 2000] + Minor revisions of makefile.bor, libpng.txt, and gregbook/rpng2-win.c + Added makefile.sggcc (SGI IRIX with gcc) + +Version 1.0.6d [April 7, 2000] + Changed sprintf() to strcpy() in png_write_sCAL_s() to work without STDIO + Added data_length parameter to png_decompress_chunk() function + Revised documentation to remove reference to abandoned png_free_chnk functions + Fixed an error in png_rgb_to_gray_fixed() + Revised example.c, usage of png_destroy_write_struct(). + Renamed makefile.ibmvac3 to makefile.ibmc, added libpng.icc IBM project file + Added a check for info_ptr->free_me&PNG_FREE_TEXT when freeing text in png.c + Simplify png_sig_bytes() function to remove use of non-ISO-C strdup(). + +Version 1.0.6e [April 9, 2000] + Added png_data_freer() function. + In the code that checks for over-length tRNS chunks, added check of + info_ptr->num_trans as well as png_ptr->num_trans (Matthias Benckmann) + Minor revisions of libpng.txt/libpng.3. + Check for existing data and free it if the free_me flag is set, in png_set_*() + and png_handle_*(). + Only define PNG_WEIGHTED_FILTERS_SUPPORTED when PNG_FLOATING_POINT_SUPPORTED + is defined. + Changed several instances of PNG_NO_CONSOLE_ID to PNG_NO_STDIO in pngrutil.c + and mentioned the purposes of the two macros in libpng.txt/libpng.3. + +Version 1.0.6f [April 14, 2000] + Revised png_set_iCCP() and png_set_rows() to avoid prematurely freeing data. + Add checks in png_set_text() for NULL members of the input text structure. + Revised libpng.txt/libpng.3. + Removed superfluous prototype for png_set_iTXt from png.h + Removed "else" from pngread.c, after png_error(), and changed "0" to "length". + Changed several png_errors about malformed ancillary chunks to png_warnings. + +Version 1.0.6g [April 24, 2000] + Added png_pass-* arrays to pnggccrd.c when PNG_USE_LOCAL_ARRAYS is defined. + Relocated paragraph about png_set_background() in libpng.3/libpng.txt + and other revisions (Matthias Benckmann) + Relocated info_ptr->free_me, png_ptr->free_me, and other info_ptr and + png_ptr members to restore binary compatibility with libpng-1.0.5 + (breaks compatibility with libpng-1.0.6). + +Version 1.0.6h [April 24, 2000] + Changed shared library so-number pattern from 2.x.y.z to xy.z (this builds + libpng.so.10 & libpng.so.10.6h instead of libpng.so.2 & libpng.so.2.1.0.6h) + This is a temporary change for test purposes. + +Version 1.0.6i [May 2, 2000] + Rearranged some members at the end of png_info and png_struct, to put + unknown_chunks_num and free_me within the original size of the png_structs + and free_me, png_read_user_fn, and png_free_fn within the original png_info, + because some old applications allocate the structs directly instead of + using png_create_*(). + Added documentation of user memory functions in libpng.txt/libpng.3 + Modified png_read_png so that it will use user_allocated row_pointers + if present, unless free_me directs that it be freed, and added description + of the use of png_set_rows() and png_get_rows() in libpng.txt/libpng.3. + Added PNG_LEGACY_SUPPORTED macro, and #ifdef out all new (since version + 1.00) members of png_struct and png_info, to regain binary compatibility + when you define this macro. Capabilities lost in this event + are user transforms (new in version 1.0.0),the user transform pointer + (new in version 1.0.2), rgb_to_gray (new in 1.0.5), iCCP, sCAL, sPLT, + the high-level interface, and unknown chunks support (all new in 1.0.6). + This was necessary because of old applications that allocate the structs + directly as authors were instructed to do in libpng-0.88 and earlier, + instead of using png_create_*(). + Added modes PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT which + can be used to detect codes that directly allocate the structs, and + code to check these modes in png_read_init() and png_write_init() and + generate a libpng error if the modes aren't set and PNG_LEGACY_SUPPORTED + was not defined. + Added makefile.intel and updated makefile.watcom (Pawel Mrochen) + +Version 1.0.6j [May 3, 2000] + Overloaded png_read_init() and png_write_init() with macros that convert + calls to png_read_init_2() or png_write_init_2() that check the version + and structure sizes. + +Version 1.0.7beta11 [May 7, 2000] + Removed the new PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT modes + which are no longer used. + Eliminated the three new members of png_text when PNG_LEGACY_SUPPORTED is + defined or when neither PNG_READ_iTXt_SUPPORTED nor PNG_WRITE_iTXT_SUPPORTED + is defined. + Made PNG_NO_READ|WRITE_iTXt the default setting, to avoid memory + overrun when old applications fill the info_ptr->text structure directly. + Added PNGAPI macro, and added it to the definitions of all exported functions. + Relocated version macro definitions ahead of the includes of zlib.h and + pngconf.h in png.h. + +Version 1.0.7beta12 [May 12, 2000] + Revised pngset.c to avoid a problem with expanding the png_debug macro. + Deleted some extraneous defines from pngconf.h + Made PNG_NO_CONSOLE_IO the default condition when PNG_BUILD_DLL is defined. + Use MSC _RPTn debugging instead of fprintf if _MSC_VER is defined. + Added png_access_version_number() function. + Check for mask&PNG_FREE_CHNK (for TEXT, SCAL, PCAL) in png_free_data(). + Expanded libpng.3/libpng.txt information about png_data_freer(). + +Version 1.0.7beta14 [May 17, 2000] (beta13 was not published) + Changed pnggccrd.c and pngvcrd.c to handle bad adaptive filter types as + warnings instead of errors, as pngrutil.c does. + Set the PNG_INFO_IDAT valid flag in png_set_rows() so png_write_png() + will actually write IDATs. + Made the default PNG_USE_LOCAL_ARRAYS depend on PNG_DLL instead of WIN32. + Make png_free_data() ignore its final parameter except when freeing data + that can have multiple instances (text, sPLT, unknowns). + Fixed a new bug in png_set_rows(). + Removed info_ptr->valid tests from png_free_data(), as in version 1.0.5. + Added png_set_invalid() function. + Fixed incorrect illustrations of png_destroy_write_struct() in example.c. + +Version 1.0.7beta15 [May 30, 2000] + Revised the deliberately erroneous Linux setjmp code in pngconf.h to produce + fewer error messages. + Rearranged checks for Z_OK to check the most likely path first in pngpread.c + and pngwutil.c. + Added checks in pngtest.c for png_create_*() returning NULL, and mentioned + in libpng.txt/libpng.3 the need for applications to check this. + Changed names of png_default_*() functions in pngtest to pngtest_*(). + Changed return type of png_get_x|y_offset_*() from png_uint_32 to png_int_32. + Fixed some bugs in the unused PNG_INCH_CONVERSIONS functions in pngget.c + Set each pointer to NULL after freeing it in png_free_data(). + Worked around a problem in pngconf.h; AIX's strings.h defines an "index" + macro that conflicts with libpng's png_color_16.index. (Dimitri + Papadapoulos) + Added "msvc" directory with MSVC++ project files (Simon-Pierre Cadieux). + +Version 1.0.7beta16 [June 4, 2000] + Revised the workaround of AIX string.h "index" bug. + Added a check for overlength PLTE chunk in pngrutil.c. + Added PNG_NO_POINTER_INDEXING macro to use array-indexing instead of pointer + indexing in pngrutil.c and pngwutil.c to accommodate a buggy compiler. + Added a warning in png_decompress_chunk() when it runs out of data, e.g. + when it tries to read an erroneous PhotoShop iCCP chunk. + Added PNG_USE_DLL macro. + Revised the copyright/disclaimer/license notice. + Added contrib/msvctest directory + +Version 1.0.7rc1 [June 9, 2000] + Corrected the definition of PNG_TRANSFORM_INVERT_ALPHA (0x0400 not 0x0200) + Added contrib/visupng directory (Willem van Schaik) + +Version 1.0.7beta18 [June 23, 2000] + Revised PNGAPI definition, and pngvcrd.c to work with __GCC__ + and do not redefine PNGAPI if it is passed in via a compiler directive. + Revised visupng/PngFile.c to remove returns from within the Try block. + Removed leading underscores from "_PNG_H" and "_PNG_SAVE_BSD_SOURCE" macros. + Updated contrib/visupng/cexcept.h to version 1.0.0. + Fixed bugs in pngwrite.c and pngwutil.c that prevented writing iCCP chunks. + +Version 1.0.7rc2 [June 28, 2000] + Updated license to include disclaimers required by UCITA. + Fixed "DJBPP" typo in pnggccrd.c introduced in beta18. + +Version 1.0.7 [July 1, 2000] + Revised the definition of "trans_values" in libpng.3/libpng.txt + +Version 1.0.8beta1 [July 8, 2000] + Added png_free(png_ptr, key) two places in pngpread.c to stop memory leaks. + Changed PNG_NO_STDIO to PNG_NO_CONSOLE_IO, several places in pngrutil.c and + pngwutil.c. + Changed PNG_EXPORT_VAR to use PNG_IMPEXP, in pngconf.h. + Removed unused "#include " from png.c + Added WindowsCE support. + Revised pnggccrd.c to work with gcc-2.95.2 and in the Cygwin environment. + +Version 1.0.8beta2 [July 10, 2000] + Added project files to the wince directory and made further revisions + of pngtest.c, pngrio.c, and pngwio.c in support of WindowsCE. + +Version 1.0.8beta3 [July 11, 2000] + Only set the PNG_FLAG_FREE_TRNS or PNG_FREE_TRNS flag in png_handle_tRNS() + for indexed-color input files to avoid potential double-freeing trans array + under some unusual conditions; problem was introduced in version 1.0.6f. + Further revisions to pngtest.c and files in the wince subdirectory. + +Version 1.0.8beta4 [July 14, 2000] + Added the files pngbar.png and pngbar.jpg to the distribution. + Added makefile.cygwin, and cygwin support in pngconf.h + Added PNG_NO_ZALLOC_ZERO macro (makes png_zalloc skip zeroing memory) + +Version 1.0.8rc1 [July 16, 2000] + Revised png_debug() macros and statements to eliminate compiler warnings. + +Version 1.0.8 [July 24, 2000] + Added png_flush() in pngwrite.c, after png_write_IEND(). + Updated makefile.hpux to build a shared library. + +Version 1.0.9beta1 [November 10, 2000] + Fixed typo in scripts/makefile.hpux + Updated makevms.com in scripts and contrib/* and contrib/* (Martin Zinser) + Fixed seqence-point bug in contrib/pngminus/png2pnm (Martin Zinser) + Changed "cdrom.com" in documentation to "libpng.org" + Revised pnggccrd.c to get it all working, and updated makefile.gcmmx (Greg). + Changed type of "params" from voidp to png_voidp in png_read|write_png(). + Make sure PNGAPI and PNG_IMPEXP are defined in pngconf.h. + Revised the 3 instances of WRITEFILE in pngtest.c. + Relocated "msvc" and "wince" project subdirectories into "dll" subdirectory. + Updated png.rc in dll/msvc project + Revised makefile.dec to define and use LIBPATH and INCPATH + Increased size of global png_libpng_ver[] array from 12 to 18 chars. + Made global png_libpng_ver[], png_sig[] and png_pass_*[] arrays const. + Removed duplicate png_crc_finish() from png_handle_bKGD() function. + Added a warning when application calls png_read_update_info() multiple times. + Revised makefile.cygwin + Fixed bugs in iCCP support in pngrutil.c and pngwutil.c. + Replaced png_set_empty_plte_permitted() with png_permit_mng_features(). + +Version 1.0.9beta2 [November 19, 2000] + Renamed the "dll" subdirectory "projects". + Added borland project files to "projects" subdirectory. + Set VS_FF_PRERELEASE and VS_FF_PATCHED flags in msvc/png.rc when appropriate. + Add error message in png_set_compression_buffer_size() when malloc fails. + +Version 1.0.9beta3 [November 23, 2000] + Revised PNG_LIBPNG_BUILD_TYPE macro in png.h, used in the msvc project. + Removed the png_flush() in pngwrite.c that crashes some applications + that don't set png_output_flush_fn. + Added makefile.macosx and makefile.aix to scripts directory. + +Version 1.0.9beta4 [December 1, 2000] + Change png_chunk_warning to png_warning in png_check_keyword(). + Increased the first part of msg buffer from 16 to 18 in png_chunk_error(). + +Version 1.0.9beta5 [December 15, 2000] + Added support for filter method 64 (for PNG datastreams embedded in MNG). + +Version 1.0.9beta6 [December 18, 2000] + Revised png_set_filter() to accept filter method 64 when appropriate. + Added new PNG_HAVE_PNG_SIGNATURE bit to png_ptr->mode and use it to + help prevent applications from using MNG features in PNG datastreams. + Added png_permit_mng_features() function. + Revised libpng.3/libpng.txt. Changed "filter type" to "filter method". + +Version 1.0.9rc1 [December 23, 2000] + Revised test for PNG_HAVE_PNG_SIGNATURE in pngrutil.c + Fixed error handling of unknown compression type in png_decompress_chunk(). + In pngconf.h, define __cdecl when _MSC_VER is defined. + +Version 1.0.9beta7 [December 28, 2000] + Changed PNG_TEXT_COMPRESSION_zTXt to PNG_COMPRESSION_TYPE_BASE several places. + Revised memory management in png_set_hIST and png_handle_hIST in a backward + compatible manner. PLTE and tRNS were revised similarly. + Revised the iCCP chunk reader to ignore trailing garbage. + +Version 1.0.9beta8 [January 12, 2001] + Moved pngasmrd.h into pngconf.h. + Improved handling of out-of-spec garbage iCCP chunks generated by PhotoShop. + +Version 1.0.9beta9 [January 15, 2001] + Added png_set_invalid, png_permit_mng_features, and png_mmx_supported to + wince and msvc project module definition files. + Minor revision of makefile.cygwin. + Fixed bug with progressive reading of narrow interlaced images in pngpread.c + +Version 1.0.9beta10 [January 16, 2001] + Do not typedef png_FILE_p in pngconf.h when PNG_NO_STDIO is defined. + Fixed "png_mmx_supported" typo in project definition files. + +Version 1.0.9beta11 [January 19, 2001] + Updated makefile.sgi to make shared library. + Removed png_mmx_support() function and disabled PNG_MNG_FEATURES_SUPPORTED + by default, for the benefit of DLL forward compatibility. These will + be re-enabled in version 1.2.0. + +Version 1.0.9rc2 [January 22, 2001] + Revised cygwin support. + +Version 1.0.9 [January 31, 2001] + Added check of cygwin's ALL_STATIC in pngconf.h + Added "-nommx" parameter to contrib/gregbook/rpng2-win and rpng2-x demos. + +Version 1.0.10beta1 [March 14, 2001] + Revised makefile.dec, makefile.sgi, and makefile.sggcc; added makefile.hpgcc. + Reformatted libpng.3 to eliminate bad line breaks. + Added checks for _mmx_supported in the read_filter_row function of pnggccrd.c + Added prototype for png_mmx_support() near the top of pnggccrd.c + Moved some error checking from png_handle_IHDR to png_set_IHDR. + Added PNG_NO_READ_SUPPORTED and PNG_NO_WRITE_SUPPORTED macros. + Revised png_mmx_support() function in pnggccrd.c + Restored version 1.0.8 PNG_WRITE_EMPTY_PLTE_SUPPORTED behavior in pngwutil.c + Fixed memory leak in contrib/visupng/PngFile.c + Fixed bugs in png_combine_row() in pnggccrd.c and pngvcrd.c (C version) + Added warnings when retrieving or setting gamma=0. + Increased the first part of msg buffer from 16 to 18 in png_chunk_warning(). + +Version 1.0.10rc1 [March 23, 2001] + Changed all instances of memcpy, strcpy, and strlen to png_memcpy, png_strcpy, + and png_strlen. + Revised png_mmx_supported() function in pnggccrd.c to return proper value. + Fixed bug in progressive reading (pngpread.c) with small images (height < 8). + +Version 1.0.10 [March 30, 2001] + Deleted extraneous space (introduced in 1.0.9) from line 42 of makefile.cygwin + Added beos project files (Chris Herborth) + +Version 1.0.11beta1 [April 3, 2001] + Added type casts on several png_malloc() calls (Dimitri Papadapoulos). + Removed a no-longer needed AIX work-around from pngconf.h + Changed several "//" single-line comments to C-style in pnggccrd.c + +Version 1.0.11beta2 [April 11, 2001] + Removed PNGAPI from several functions whose prototypes did not have PNGAPI. + Updated scripts/pngos2.def + +Version 1.0.11beta3 [April 14, 2001] + Added checking the results of many instances of png_malloc() for NULL + +Version 1.0.11beta4 [April 20, 2001] + Undid the changes from version 1.0.11beta3. Added a check for NULL return + from user's malloc_fn(). + Removed some useless type casts of the NULL pointer. + Added makefile.netbsd + +Version 1.0.11 [April 27, 2001] + Revised makefile.netbsd + +Version 1.0.12beta1 [May 14, 2001] + Test for Windows platform in pngconf.h when including malloc.h (Emmanuel Blot) + Updated makefile.cygwin and handling of Cygwin's ALL_STATIC in pngconf.h + Added some never-to-be-executed code in pnggccrd.c to quiet compiler warnings. + Eliminated the png_error about apps using png_read|write_init(). Instead, + libpng will reallocate the png_struct and info_struct if they are too small. + This retains future binary compatibility for old applications written for + libpng-0.88 and earlier. + +Version 1.2.0beta1 [May 6, 2001] + Bumped DLLNUM to 2. + Re-enabled PNG_MNG_FEATURES_SUPPORTED and enabled PNG_ASSEMBLER_CODE_SUPPORTED + by default. + Added runtime selection of MMX features. + Added png_set_strip_error_numbers function and related macros. + +Version 1.2.0beta2 [May 7, 2001] + Finished merging 1.2.0beta1 with version 1.0.11 + Added a check for attempts to read or write PLTE in grayscale PNG datastreams. + +Version 1.2.0beta3 [May 17, 2001] + Enabled user memory function by default. + Modified png_create_struct so it passes user mem_ptr to user memory allocator. + Increased png_mng_features flag from png_byte to png_uint_32. + Bumped shared-library (so-number) and dll-number to 3. + +Version 1.2.0beta4 [June 23, 2001] + Check for missing profile length field in iCCP chunk and free chunk_data + in case of truncated iCCP chunk. + Bumped shared-library number to 3 in makefile.sgi and makefile.sggcc + Bumped dll-number from 2 to 3 in makefile.cygwin + Revised contrib/gregbook/rpng*-x.c to avoid a memory leak and to exit cleanly + if user attempts to run it on an 8-bit display. + Updated contrib/gregbook + Use png_malloc instead of png_zalloc to allocate palette in pngset.c + Updated makefile.ibmc + Added some typecasts to eliminate gcc 3.0 warnings. Changed prototypes + of png_write_oFFS width and height from png_uint_32 to png_int_32. + Updated example.c + Revised prototypes for png_debug_malloc and png_debug_free in pngtest.c + +Version 1.2.0beta5 [August 8, 2001] + Revised contrib/gregbook + Revised makefile.gcmmx + Revised pnggccrd.c to conditionally compile some thread-unsafe code only + when PNG_THREAD_UNSAFE_OK is defined. + Added tests to prevent pngwutil.c from writing a bKGD or tRNS chunk with + value exceeding 2^bit_depth-1 + Revised makefile.sgi and makefile.sggcc + Replaced calls to fprintf(stderr,...) with png_warning() in pnggccrd.c + Removed restriction that do_invert_mono only operate on 1-bit opaque files + +Version 1.2.0 [September 1, 2001] + Changed a png_warning() to png_debug() in pnggccrd.c + Fixed contrib/gregbook/rpng-x.c, rpng2-x.c to avoid crash with XFreeGC(). + +Version 1.2.1beta1 [October 19, 2001] + Revised makefile.std in contrib/pngminus + Include background_1 in png_struct regardless of gamma support. + Revised makefile.netbsd and makefile.macosx, added makefile.darwin. + Revised example.c to provide more details about using row_callback(). + +Version 1.2.1beta2 [October 25, 2001] + Added type cast to each NULL appearing in a function call, except for + WINCE functions. + Added makefile.so9. + +Version 1.2.1beta3 [October 27, 2001] + Removed type casts from all NULLs. + Simplified png_create_struct_2(). + +Version 1.2.1beta4 [November 7, 2001] + Revised png_create_info_struct() and png_creat_struct_2(). + Added error message if png_write_info() was omitted. + Type cast NULLs appearing in function calls when _NO_PROTO or + PNG_TYPECAST_NULL is defined. + +Version 1.2.1rc1 [November 24, 2001] + Type cast NULLs appearing in function calls except when PNG_NO_TYPECAST_NULL + is defined. + Changed typecast of "size" argument to png_size_t in pngmem.c calls to + the user malloc_fn, to agree with the prototype in png.h + Added a pop/push operation to pnggccrd.c, to preserve Eflag (Maxim Sobolev) + Updated makefile.sgi to recognize LIBPATH and INCPATH. + Updated various makefiles so "make clean" does not remove previous major + version of the shared library. + +Version 1.2.1rc2 [December 4, 2001] + Always allocate 256-entry internal palette, hist, and trans arrays, to + avoid out-of-bounds memory reference caused by invalid PNG datastreams. + Added a check for prefix_length > data_length in iCCP chunk handler. + +Version 1.2.1 [December 7, 2001] + None. + +Version 1.2.2beta1 [February 22, 2002] + Fixed a bug with reading the length of iCCP profiles (Larry Reeves). + Revised makefile.linux, makefile.gcmmx, and makefile.sgi to generate + libpng.a, libpng12.so (not libpng.so.3), and libpng12/png.h + Revised makefile.darwin to remove "-undefined suppress" option. + Added checks for gamma and chromaticity values over 21474.83, which exceed + the limit for PNG unsigned 32-bit integers when encoded. + Revised calls to png_create_read_struct() and png_create_write_struct() + for simpler debugging. + Revised png_zalloc() so zlib handles errors (uses PNG_FLAG_MALLOC_NULL_MEM_OK) + +Version 1.2.2beta2 [February 23, 2002] + Check chunk_length and idat_size for invalid (over PNG_MAX_UINT) lengths. + Check for invalid image dimensions in png_get_IHDR. + Added missing "fi;" in the install target of the SGI makefiles. + Added install-static to all makefiles that make shared libraries. + Always do gamma compensation when image is partially transparent. + +Version 1.2.2beta3 [March 7, 2002] + Compute background.gray and background_1.gray even when color_type is RGB + in case image gets reduced to gray later. + Modified shared-library makefiles to install pkgconfig/libpngNN.pc. + Export (with PNGAPI) png_zalloc, png_zfree, and png_handle_as_unknown + Removed unused png_write_destroy_info prototype from png.h + Eliminated incorrect use of width_mmx from pnggccrd.c in pixel_bytes == 8 case + Added install-shared target to all makefiles that make shared libraries. + Stopped a double free of palette, hist, and trans when not using free_me. + Added makefile.32sunu for Sun Ultra 32 and makefile.64sunu for Sun Ultra 64. + +Version 1.2.2beta4 [March 8, 2002] + Compute background.gray and background_1.gray even when color_type is RGB + in case image gets reduced to gray later (Jason Summers). + Relocated a misplaced /bin/rm in the "install-shared" makefile targets + Added PNG_1_0_X macro which can be used to build a 1.0.x-compatible library. + +Version 1.2.2beta5 [March 26, 2002] + Added missing PNGAPI to several function definitions. + Check for invalid bit_depth or color_type in png_get_IHDR(), and + check for missing PLTE or IHDR in png_push_read_chunk() (Matthias Clasen). + Revised iTXt support to accept NULL for lang and lang_key. + Compute gamma for color components of background even when color_type is gray. + Changed "()" to "{}" in scripts/libpng.pc.in. + Revised makefiles to put png.h and pngconf.h only in $prefix/include/libpngNN + Revised makefiles to make symlink to libpng.so.NN in addition to libpngNN.so + +Version 1.2.2beta6 [March 31, 2002] + +Version 1.0.13beta1 [March 31, 2002] + Prevent png_zalloc() from trying to memset memory that it failed to acquire. + Add typecasts of PNG_MAX_UINT in pngset_cHRM_fixed() (Matt Holgate). + Ensure that the right function (user or default) is used to free the + png_struct after an error in png_create_read_struct_2(). + +Version 1.2.2rc1 [April 7, 2002] + +Version 1.0.13rc1 [April 7, 2002] + Save the ebx register in pnggccrd.c (Sami Farin) + Add "mem_ptr = png_ptr->mem_ptr" in png_destroy_write_struct() (Paul Gardner). + Updated makefiles to put headers in include/libpng and remove old include/*.h. + +Version 1.2.2 [April 15, 2002] + +Version 1.0.13 [April 15, 2002] + Revised description of png_set_filter() in libpng.3/libpng.txt. + Revised makefile.netbsd and added makefile.neNNbsd and makefile.freebsd + +Version 1.0.13patch01 [April 17, 2002] + +Version 1.2.2patch01 [April 17, 2002] + Changed ${PNGMAJ}.${PNGVER} bug to ${PNGVER} in makefile.sgi and + makefile.sggcc + Fixed VER -> PNGVER typo in makefile.macosx and added install-static to + install + Added install: target to makefile.32sunu and makefile.64sunu + +Version 1.0.13patch03 [April 18, 2002] + +Version 1.2.2patch03 [April 18, 2002] + Revised 15 makefiles to link libpng.a to libpngNN.a and the include libpng + subdirectory to libpngNN subdirectory without the full pathname. + Moved generation of libpng.pc from "install" to "all" in 15 makefiles. + +Version 1.2.3rc1 [April 28, 2002] + Added install-man target to 15 makefiles (Dimitri Papadopolous-Orfanos). + Added $(DESTDIR) feature to 24 makefiles (Tim Mooney) + Fixed bug with $prefix, should be $(prefix) in makefile.hpux. + Updated cygwin-specific portion of pngconf.h and revised makefile.cygwin + Added a link from libpngNN.pc to libpng.pc in 15 makefiles. + Added links from include/libpngNN/*.h to include/*.h in 24 makefiles. + Revised makefile.darwin to make relative links without full pathname. + Added setjmp() at the end of png_create_*_struct_2() in case user forgets + to put one in their application. + Restored png_zalloc() and png_zfree() prototypes to version 1.2.1 and + removed them from module definition files. + +Version 1.2.3rc2 [May 1, 2002] + Fixed bug in reporting number of channels in pngget.c and pngset.c, + that was introduced in version 1.2.2beta5. + Exported png_zalloc(), png_zfree(), png_default_read(), png_default_write(), + png_default_flush(), and png_push_fill_buffer() and included them in + module definition files. + Added "libpng.pc" dependency to the "install-shared" target in 15 makefiles. + +Version 1.2.3rc3 [May 1, 2002] + Revised prototype for png_default_flush() + Remove old libpng.pc and libpngNN.pc before installing new ones. + +Version 1.2.3rc4 [May 2, 2002] + Typos in *.def files (png_default_read|write -> png_default_read|write_data) + In makefiles, changed rm libpng.NN.pc to rm libpngNN.pc + Added libpng-config and libpngNN-config and modified makefiles to install + them. + Changed $(MANPATH) to $(DESTDIR)$(MANPATH) in makefiles + Added "Win32 DLL VB" configuration to projects/msvc/libpng.dsp + +Version 1.2.3rc5 [May 11, 2002] + Changed "error" and "message" in prototypes to "error_message" and + "warning_message" to avoid namespace conflict. + Revised 15 makefiles to build libpng-config from libpng-config-*.in + Once more restored png_zalloc and png_zfree to regular nonexported form. + Restored png_default_read|write_data, png_default_flush, png_read_fill_buffer + to nonexported form, but with PNGAPI, and removed them from module def + files. + +Version 1.2.3rc6 [May 14, 2002] + Removed "PNGAPI" from png_zalloc() and png_zfree() in png.c + Changed "Gz" to "Gd" in projects/msvc/libpng.dsp and zlib.dsp. + Removed leftover libpng-config "sed" script from four makefiles. + Revised libpng-config creating script in 16 makefiles. + +Version 1.2.3 [May 22, 2002] + Revised libpng-config target in makefile.cygwin. + Removed description of png_set_mem_fn() from documentation. + Revised makefile.freebsd. + Minor cosmetic changes to 15 makefiles, e.g., $(DI) = $(DESTDIR)/$(INCDIR). + Revised projects/msvc/README.txt + Changed -lpng to -lpngNN in LDFLAGS in several makefiles. + +Version 1.2.4beta1 [May 24, 2002] + Added libpng.pc and libpng-config to "all:" target in 16 makefiles. + Fixed bug in 16 makefiles: $(DESTDIR)/$(LIBPATH) to $(DESTDIR)$(LIBPATH) + Added missing "\" before closing double quote in makefile.gcmmx. + Plugged various memory leaks; added png_malloc_warn() and png_set_text_2() + functions. + +Version 1.2.4beta2 [June 25, 2002] + Plugged memory leak of png_ptr->current_text (Matt Holgate). + Check for buffer overflow before reading CRC in pngpread.c (Warwick Allison) + Added -soname to the loader flags in makefile.dec, makefile.sgi, and + makefile.sggcc. + Added "test-installed" target to makefile.linux, makefile.gcmmx, + makefile.sgi, and makefile.sggcc. + +Version 1.2.4beta3 [June 28, 2002] + Plugged memory leak of row_buf in pngtest.c when there is a png_error(). + Detect buffer overflow in pngpread.c when IDAT is corrupted with extra data. + Added "test-installed" target to makefile.32sunu, makefile.64sunu, + makefile.beos, makefile.darwin, makefile.dec, makefile.macosx, + makefile.solaris, makefile.hpux, makefile.hpgcc, and makefile.so9. + +Version 1.2.4rc1 and 1.0.14rc1 [July 2, 2002] + Added "test-installed" target to makefile.cygwin and makefile.sco. + Revised pnggccrd.c to be able to back out version 1.0.x via PNG_1_0_X macro. + +Version 1.2.4 and 1.0.14 [July 8, 2002] + Changed png_warning() to png_error() when width is too large to process. + +Version 1.2.4patch01 [July 20, 2002] + Revised makefile.cygwin to use DLL number 12 instead of 13. + +Version 1.2.5beta1 [August 6, 2002] + Added code to contrib/gregbook/readpng2.c to ignore unused chunks. + Replaced toucan.png in contrib/gregbook (it has been corrupt since 1.0.11) + Removed some stray *.o files from contrib/gregbook. + Changed png_error() to png_warning() about "Too much data" in pngpread.c + and about "Extra compressed data" in pngrutil.c. + Prevent png_ptr->pass from exceeding 7 in png_push_finish_row(). + Updated makefile.hpgcc + Updated png.c and pnggccrd.c handling of return from png_mmx_support() + +Version 1.2.5beta2 [August 15, 2002] + Only issue png_warning() about "Too much data" in pngpread.c when avail_in + is nonzero. + Updated makefiles to install a separate libpng.so.3 with its own rpath. + +Version 1.2.5rc1 and 1.0.15rc1 [August 24, 2002] + Revised makefiles to not remove previous minor versions of shared libraries. + +Version 1.2.5rc2 and 1.0.15rc2 [September 16, 2002] + Revised 13 makefiles to remove "-lz" and "-L$(ZLIBLIB)", etc., from shared + library loader directive. + Added missing "$OBJSDLL" line to makefile.gcmmx. + Added missing "; fi" to makefile.32sunu. + +Version 1.2.5rc3 and 1.0.15rc3 [September 18, 2002] + Revised libpng-config script. + +Version 1.2.5 and 1.0.15 [October 3, 2002] + Revised makefile.macosx, makefile.darwin, makefile.hpgcc, and makefile.hpux, + and makefile.aix. + Relocated two misplaced PNGAPI lines in pngtest.c + +Version 1.2.6beta1 [October 22, 2002] + Commented out warning about uninitialized mmx_support in pnggccrd.c. + Changed "IBMCPP__" flag to "__IBMCPP__" in pngconf.h. + Relocated two more misplaced PNGAPI lines in pngtest.c + Fixed memory overrun bug in png_do_read_filler() with 16-bit datastreams, + introduced in version 1.0.2. + Revised makefile.macosx, makefile.dec, makefile.aix, and makefile.32sunu. + +Version 1.2.6beta2 [November 1, 2002] + Added libpng-config "--ldopts" output. + Added "AR=ar" and "ARFLAGS=rc" and changed "ar rc" to "$(AR) $(ARFLAGS)" + in makefiles. + +Version 1.2.6beta3 [July 18, 2004] + Reverted makefile changes from version 1.2.6beta2 and some of the changes + from version 1.2.6beta1; these will be postponed until version 1.2.7. + Version 1.2.6 is going to be a simple bugfix release. + Changed the one instance of "ln -sf" to "ln -f -s" in each Sun makefile. + Fixed potential overrun in pngerror.c by using strncpy instead of memcpy. + Added "#!/bin/sh" at the top of configure, for recognition of the + 'x' flag under Cygwin (Cosmin). + Optimized vacuous tests that silence compiler warnings, in png.c (Cosmin). + Added support for PNG_USER_CONFIG, in pngconf.h (Cosmin). + Fixed the special memory handler for Borland C under DOS, in pngmem.c + (Cosmin). + Removed some spurious assignments in pngrutil.c (Cosmin). + Replaced 65536 with 65536L, and 0xffff with 0xffffL, to silence warnings + on 16-bit platforms (Cosmin). + Enclosed shift op expressions in parentheses, to silence warnings (Cosmin). + Used proper type png_fixed_point, to avoid problems on 16-bit platforms, + in png_handle_sRGB() (Cosmin). + Added compression_type to png_struct, and optimized the window size + inside the deflate stream (Cosmin). + Fixed definition of isnonalpha(), in pngerror.c and pngrutil.c (Cosmin). + Fixed handling of unknown chunks that come after IDAT (Cosmin). + Allowed png_error() and png_warning() to work even if png_ptr == NULL + (Cosmin). + Replaced row_info->rowbytes with row_bytes in png_write_find_filter() + (Cosmin). + Fixed definition of PNG_LIBPNG_VER_DLLNUM (Simon-Pierre). + Used PNG_LIBPNG_VER and PNG_LIBPNG_VER_STRING instead of the hardcoded + values in png.c (Simon-Pierre, Cosmin). + Initialized png_libpng_ver[] with PNG_LIBPNG_VER_STRING (Simon-Pierre). + Replaced PNG_LIBPNG_VER_MAJOR with PNG_LIBPNG_VER_DLLNUM in png.rc + (Simon-Pierre). + Moved the definition of PNG_HEADER_VERSION_STRING near the definitions + of the other PNG_LIBPNG_VER_... symbols in png.h (Cosmin). + Relocated #ifndef PNGAPI guards in pngconf.h (Simon-Pierre, Cosmin). + Updated scripts/makefile.vc(a)win32 (Cosmin). + Updated the MSVC project (Simon-Pierre, Cosmin). + Updated the Borland C++ Builder project (Cosmin). + Avoided access to asm_flags in pngvcrd.c, if PNG_1_0_X is defined (Cosmin). + Commented out warning about uninitialized mmx_support in pngvcrd.c (Cosmin). + Removed scripts/makefile.bd32 and scripts/pngdef.pas (Cosmin). + Added extra guard around inclusion of Turbo C memory headers, in pngconf.h + (Cosmin). + Renamed projects/msvc/ to projects/visualc6/, and projects/borland/ to + projects/cbuilder5/ (Cosmin). + Moved projects/visualc6/png32ms.def to scripts/pngw32.def, + and projects/visualc6/png.rc to scripts/pngw32.rc (Cosmin). + Added projects/visualc6/pngtest.dsp; removed contrib/msvctest/ (Cosmin). + Changed line endings to DOS style in cbuilder5 and visualc6 files, even + in the tar.* distributions (Cosmin). + Updated contrib/visupng/VisualPng.dsp (Cosmin). + Updated contrib/visupng/cexcept.h to version 2.0.0 (Cosmin). + Added a separate distribution with "configure" and supporting files (Junichi). + +Version 1.2.6beta4 [July 28, 2004] + Added user ability to change png_size_t via a PNG_SIZE_T macro. + Added png_sizeof() and png_convert_size() functions. + Added PNG_SIZE_MAX (maximum value of a png_size_t variable. + Added check in png_malloc_default() for (size_t)size != (png_uint_32)size + which would indicate an overflow. + Changed sPLT failure action from png_error to png_warning and abandon chunk. + Changed sCAL and iCCP failures from png_error to png_warning and abandon. + Added png_get_uint_31(png_ptr, buf) function. + Added PNG_UINT_32_MAX macro. + Renamed PNG_MAX_UINT to PNG_UINT_31_MAX. + Made png_zalloc() issue a png_warning and return NULL on potential + overflow. + Turn on PNG_NO_ZALLOC_ZERO by default in version 1.2.x + Revised "clobber list" in pnggccrd.c so it will compile under gcc-3.4. + Revised Borland portion of png_malloc() to return NULL or issue + png_error() according to setting of PNG_FLAG_MALLOC_NULL_MEM_OK. + Added PNG_NO_SEQUENTIAL_READ_SUPPORTED macro to conditionally remove + sequential read support. + Added some "#if PNG_WRITE_SUPPORTED" blocks. + Added #ifdef to remove some redundancy in png_malloc_default(). + Use png_malloc instead of png_zalloc to allocate the pallete. + +Version 1.0.16rc1 and 1.2.6rc1 [August 4, 2004] + Fixed buffer overflow vulnerability (CVE-2004-0597) in png_handle_tRNS(). + Fixed NULL dereference vulnerability (CVE-2004-0598) in png_handle_iCCP(). + Fixed integer overflow vulnerability (CVE-2004-0599) in png_read_png(). + Fixed some harmless bugs in png_handle_sBIT, etc, that would cause + duplicate chunk types to go undetected. + Fixed some timestamps in the -config version + Rearranged order of processing of color types in png_handle_tRNS(). + Added ROWBYTES macro to calculate rowbytes without integer overflow. + Updated makefile.darwin and removed makefile.macosx from scripts directory. + Imposed default one million column, one-million row limits on the image + dimensions, and added png_set_user_limits() function to override them. + Revised use of PNG_SET_USER_LIMITS_SUPPORTED macro. + Fixed wrong cast of returns from png_get_user_width|height_max(). + Changed some "keep the compiler happy" from empty statements to returns, + Revised libpng.txt to remove 1.2.x stuff from the 1.0.x distribution + +Version 1.0.16rc2 and 1.2.6rc2 [August 7, 2004] + Revised makefile.darwin and makefile.solaris. Removed makefile.macosx. + Revised pngtest's png_debug_malloc() to use png_malloc() instead of + png_malloc_default() which is not supposed to be exported. + Fixed off-by-one error in one of the conversions to PNG_ROWBYTES() in + pngpread.c. Bug was introduced in 1.2.6rc1. + Fixed bug in RGB to RGBX transformation introduced in 1.2.6rc1. + Fixed old bug in RGB to Gray transformation. + Fixed problem with 64-bit compilers by casting arguments to abs() + to png_int_32. + Changed "ln -sf" to "ln -f -s" in three makefiles (solaris, sco, so9). + Changed "HANDLE_CHUNK_*" to "PNG_HANDLE_CHUNK_*" (Cosmin) + Added "-@/bin/rm -f $(DL)/$(LIBNAME).so.$(PNGMAJ)" to 15 *NIX makefiles. + Added code to update the row_info->colortype in png_do_read_filler() (MSB). + +Version 1.0.16rc3 and 1.2.6rc3 [August 9, 2004] + Eliminated use of "abs()" in testing cHRM and gAMA values, to avoid + trouble with some 64-bit compilers. Created PNG_OUT_OF_RANGE() macro. + Revised documentation of png_set_keep_unknown_chunks(). + Check handle_as_unknown status in pngpread.c, as in pngread.c previously. + Moved "PNG_HANDLE_CHUNK_*" macros out of PNG_INTERNAL section of png.h + Added "rim" definitions for CONST4 and CONST6 in pnggccrd.c + +Version 1.0.16rc4 and 1.2.6rc4 [August 10, 2004] + Fixed mistake in pngtest.c introduced in 1.2.6rc2 (declaration of + "pinfo" was out of place). + +Version 1.0.16rc5 and 1.2.6rc5 [August 10, 2004] + Moved "PNG_HANDLE_CHUNK_*" macros out of PNG_ASSEMBLER_CODE_SUPPORTED + section of png.h where they were inadvertently placed in version rc3. + +Version 1.2.6 and 1.0.16 [August 15, 2004] + Revised pngtest so memory allocation testing is only done when PNG_DEBUG==1. + +Version 1.2.7beta1 [August 26, 2004] + Removed unused pngasmrd.h file. + Removed references to uu.net for archived files. Added references to + PNG Spec (second edition) and the PNG ISO/IEC Standard. + Added "test-dd" target in 15 makefiles, to run pngtest in DESTDIR. + Fixed bug with "optimized window size" in the IDAT datastream, that + causes libpng to write PNG files with incorrect zlib header bytes. + +Version 1.2.7beta2 [August 28, 2004] + Fixed bug with sCAL chunk and big-endian machines (David Munro). + Undid new code added in 1.2.6rc2 to update the color_type in + png_set_filler(). + Added png_set_add_alpha() that updates color type. + +Version 1.0.17rc1 and 1.2.7rc1 [September 4, 2004] + Revised png_set_strip_filler() to not remove alpha if color_type has alpha. + +Version 1.2.7 and 1.0.17 [September 12, 2004] + Added makefile.hp64 + Changed projects/msvc/png32ms.def to scripts/png32ms.def in makefile.cygwin + +Version 1.2.8beta1 [November 1, 2004] + Fixed bug in png_text_compress() that would fail to complete a large block. + Fixed bug, introduced in libpng-1.2.7, that overruns a buffer during + strip alpha operation in png_do_strip_filler(). + Added PNG_1_2_X definition in pngconf.h + Use #ifdef to comment out png_info_init in png.c and png_read_init in + pngread.c (as of 1.3.0) + +Version 1.2.8beta2 [November 2, 2004] + Reduce color_type to a nonalpha type after strip alpha operation in + png_do_strip_filler(). + +Version 1.2.8beta3 [November 3, 2004] + Revised definitions of PNG_MAX_UINT_32, PNG_MAX_SIZE, and PNG_MAXSUM + +Version 1.2.8beta4 [November 12, 2004] + Fixed (again) definition of PNG_LIBPNG_VER_DLLNUM in png.h (Cosmin). + Added PNG_LIBPNG_BUILD_PRIVATE in png.h (Cosmin). + Set png_ptr->zstream.data_type to Z_BINARY, to avoid unnecessary detection + of data type in deflate (Cosmin). + Deprecated but continue to support SPECIALBUILD and PRIVATEBUILD in favor of + PNG_LIBPNG_BUILD_SPECIAL_STRING and PNG_LIBPNG_BUILD_PRIVATE_STRING. + +Version 1.2.8beta5 [November 20, 2004] + Use png_ptr->flags instead of png_ptr->transformations to pass + PNG_STRIP_ALPHA info to png_do_strip_filler(), to preserve ABI + compatibility. + Revised handling of SPECIALBUILD, PRIVATEBUILD, + PNG_LIBPNG_BUILD_SPECIAL_STRING and PNG_LIBPNG_BUILD_PRIVATE_STRING. + +Version 1.2.8rc1 [November 24, 2004] + Moved handling of BUILD macros from pngconf.h to png.h + Added definition of PNG_LIBPNG_BASE_TYPE in png.h, inadvertently + omitted from beta5. + Revised scripts/pngw32.rc + Despammed mailing addresses by masking "@" with "at". + Inadvertently installed a supposedly faster test version of pngrutil.c + +Version 1.2.8rc2 [November 26, 2004] + Added two missing "\" in png.h + Change tests in pngread.c and pngpread.c to + if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) + png_do_read_transformations(png_ptr); + +Version 1.2.8rc3 [November 28, 2004] + Reverted pngrutil.c to version libpng-1.2.8beta5. + Added scripts/makefile.elf with supporting code in pngconf.h for symbol + versioning (John Bowler). + +Version 1.2.8rc4 [November 29, 2004] + Added projects/visualc7 (Simon-pierre). + +Version 1.2.8rc5 [November 29, 2004] + Fixed new typo in scripts/pngw32.rc + +Version 1.2.8 [December 3, 2004] + Removed projects/visualc7, added projects/visualc71. + +Version 1.2.9beta1 [February 21, 2006] + Initialized some structure members in pngwutil.c to avoid gcc-4.0.0 complaints + Revised man page and libpng.txt to make it clear that one should not call + png_read_end or png_write_end after png_read_png or png_write_png. + Updated references to png-mng-implement mailing list. + Fixed an incorrect typecast in pngrutil.c + Added PNG_NO_READ_SUPPORTED conditional for making a write-only library. + Added PNG_NO_WRITE_INTERLACING_SUPPORTED conditional. + Optimized alpha-inversion loops in pngwtran.c + Moved test for nonzero gamma outside of png_build_gamma_table() in pngrtran.c + Make sure num_trans is <= 256 before copying data in png_set_tRNS(). + Make sure num_palette is <= 256 before copying data in png_set_PLTE(). + Interchanged order of write_swap_alpha and write_invert_alpha transforms. + Added parentheses in the definition of PNG_LIBPNG_BUILD_TYPE (Cosmin). + Optimized zlib window flag (CINFO) in contrib/pngsuite/*.png (Cosmin). + Updated scripts/makefile.bc32 for Borland C++ 5.6 (Cosmin). + Exported png_get_uint_32, png_save_uint_32, png_get_uint_16, png_save_uint_16, + png_get_int_32, png_save_int_32, png_get_uint_31 (Cosmin). + Added type cast (png_byte) in png_write_sCAL() (Cosmin). + Fixed scripts/makefile.cygwin (Christian Biesinger, Cosmin). + Default iTXt support was inadvertently enabled. + +Version 1.2.9beta2 [February 21, 2006] + Check for png_rgb_to_gray and png_gray_to_rgb read transformations before + checking for png_read_dither in pngrtran.c + Revised checking of chromaticity limits to accommodate extended RGB + colorspace (John Denker). + Changed line endings in some of the project files to CRLF, even in the + "Unix" tar distributions (Cosmin). + Made png_get_int_32 and png_save_int_32 always available (Cosmin). + Updated scripts/pngos2.def, scripts/pngw32.def and projects/wince/png32ce.def + with the newly exported functions. + Eliminated distributions without the "configure" script. + Updated INSTALL instructions. + +Version 1.2.9beta3 [February 24, 2006] + Fixed CRCRLF line endings in contrib/visupng/VisualPng.dsp + Made libpng.pc respect EXEC_PREFIX (D. P. Kreil, J. Bowler) + Removed reference to pngasmrd.h from Makefile.am + Renamed CHANGES to ChangeLog. + Renamed LICENSE to COPYING. + Renamed ANNOUNCE to NEWS. + Created AUTHORS file. + +Version 1.2.9beta4 [March 3, 2006] + Changed definition of PKGCONFIG from $prefix/lib to $libdir in configure.ac + Reverted to filenames LICENSE and ANNOUNCE; removed AUTHORS and COPYING. + Removed newline from the end of some error and warning messages. + Removed test for sqrt() from configure.ac and configure. + Made swap tables in pngtrans.c PNG_CONST (Carlo Bramix). + Disabled default iTXt support that was inadvertently enabled in + libpng-1.2.9beta1. + Added "OS2" to list of systems that don't need underscores, in pnggccrd.c + Removed libpng version and date from *.c files. + +Version 1.2.9beta5 [March 4, 2006] + Removed trailing blanks from source files. + Put version and date of latest change in each source file, and changed + copyright year accordingly. + More cleanup of configure.ac, Makefile.am, and associated scripts. + Restored scripts/makefile.elf which was inadvertently deleted. + +Version 1.2.9beta6 [March 6, 2006] + Fixed typo (RELEASE) in configuration files. + +Version 1.2.9beta7 [March 7, 2006] + Removed libpng.vers and libpng.sym from libpng12_la_SOURCES in Makefile.am + Fixed inconsistent #ifdef's around png_sig_bytes() and png_set_sCAL_s() + in png.h. + Updated makefile.elf as suggested by debian. + Made cosmetic changes to some makefiles, adding LN_SF and other macros. + Made some makefiles accept "exec_prefix". + +Version 1.2.9beta8 [March 9, 2006] + Fixed some "#if defined (..." which should be "#if defined(..." + Bug introduced in libpng-1.2.8. + Fixed inconsistency in definition of png_default_read_data() + Restored blank that was lost from makefile.sggcc "clean" target in beta7. + Revised calculation of "current" and "major" for irix in ltmain.sh + Changed "mkdir" to "MKDIR_P" in some makefiles. + Separated PNG_EXPAND and PNG_EXPAND_tRNS. + Added png_set_expand_gray_1_2_4_to_8() and deprecated + png_set_gray_1_2_4_to_8() which also expands tRNS to alpha. + +Version 1.2.9beta9 [March 10, 2006] + Include "config.h" in pngconf.h when available. + Added some checks for NULL png_ptr or NULL info_ptr (timeless) + +Version 1.2.9beta10 [March 20, 2006] + Removed extra CR from contrib/visualpng/VisualPng.dsw (Cosmin) + Made pnggccrd.c PIC-compliant (Christian Aichinger). + Added makefile.mingw (Wolfgang Glas). + Revised pngconf.h MMX checking. + +Version 1.2.9beta11 [March 22, 2006] + Fixed out-of-order declaration in pngwrite.c that was introduced in beta9 + Simplified some makefiles by using LIBSO, LIBSOMAJ, and LIBSOVER macros. + +Version 1.2.9rc1 [March 31, 2006] + Defined PNG_USER_PRIVATEBUILD when including "pngusr.h" (Cosmin). + Removed nonsensical assertion check from pngtest.c (Cosmin). + +Version 1.2.9 [April 14, 2006] + Revised makefile.beos and added "none" selector in ltmain.sh + +Version 1.2.10beta1 [April 15, 2006] + Renamed "config.h" to "png_conf.h" and revised Makefile.am to add + -DPNG_BUILDING_LIBPNG to compile directive, and modified pngconf.h + to include png_conf.h only when PNG_BUILDING_LIBPNG is defined. + +Version 1.2.10beta2 [April 15, 2006] + Manually updated Makefile.in and configure. Changed png_conf.h.in + back to config.h. + +Version 1.2.10beta3 [April 15, 2006] + Change png_conf.h back to config.h in pngconf.h. + +Version 1.2.10beta4 [April 16, 2006] + Change PNG_BUILDING_LIBPNG to PNG_CONFIGURE_LIBPNG in config/Makefile*. + +Version 1.2.10beta5 [April 16, 2006] + Added a configure check for compiling assembler code in pnggccrd.c + +Version 1.2.10beta6 [April 17, 2006] + Revised the configure check for pnggccrd.c + Moved -DPNG_CONFIGURE_LIBPNG into @LIBPNG_DEFINES@ + Added @LIBPNG_DEFINES@ to arguments when building libpng.sym + +Version 1.2.10beta7 [April 18, 2006] + Change "exec_prefix=$prefix" to "exec_prefix=$(prefix)" in makefiles. + +Version 1.2.10rc1 [April 19, 2006] + Ensure pngconf.h doesn't define both PNG_USE_PNGGCCRD and PNG_USE_PNGVCRD + Fixed "LN_FS" typo in makefile.sco and makefile.solaris. + +Version 1.2.10rc2 [April 20, 2006] + Added a backslash between -DPNG_CONFIGURE_LIBPNG and -DPNG_NO_ASSEMBLER_CODE + in configure.ac and configure + Made the configure warning about versioned symbols less arrogant. + +Version 1.2.10rc3 [April 21, 2006] + Added a note in libpng.txt that png_set_sig_bytes(8) can be used when + writing an embedded PNG without the 8-byte signature. + Revised makefiles and configure to avoid making links to libpng.so.* + +Version 1.2.10 [April 23, 2006] + Reverted configure to "rc2" state. + +Version 1.2.11beta1 [May 31, 2006] + scripts/libpng.pc.in contained "configure" style version info and would + not work with makefiles. + The shared-library makefiles were linking to libpng.so.0 instead of + libpng.so.3 compatibility as the library. + +Version 1.2.11beta2 [June 2, 2006] + Increased sprintf buffer from 50 to 52 chars in pngrutil.c to avoid + buffer overflow. + Fixed bug in example.c (png_set_palette_rgb -> png_set_palette_to_rgb) + +Version 1.2.11beta3 [June 5, 2006] + Prepended "#! /bin/sh" to ltmail.sh and contrib/pngminus/*.sh (Cosmin). + Removed the accidental leftover Makefile.in~ (Cosmin). + Avoided potential buffer overflow and optimized buffer in + png_write_sCAL(), png_write_sCAL_s() (Cosmin). + Removed the include directories and libraries from CFLAGS and LDFLAGS + in scripts/makefile.gcc (Nelson A. de Oliveira, Cosmin). + +Version 1.2.11beta4 [June 6, 2006] + Allow zero-length IDAT chunks after the entire zlib datastream, but not + after another intervening chunk type. + +Version 1.0.19rc1, 1.2.11rc1 [June 13, 2006] + Deleted extraneous square brackets from [config.h] in configure.ac + +Version 1.0.19rc2, 1.2.11rc2 [June 14, 2006] + Added prototypes for PNG_INCH_CONVERSIONS functions to png.h + Revised INSTALL and autogen.sh + Fixed typo in several makefiles (-W1 should be -Wl) + Added typedef for png_int_32 and png_uint_32 on 64-bit systems. + +Version 1.0.19rc3, 1.2.11rc3 [June 15, 2006] + Removed the new typedefs for 64-bit systems (delay until version 1.4.0) + Added one zero element to png_gamma_shift[] array in pngrtran.c to avoid + reading out of bounds. + +Version 1.0.19rc4, 1.2.11rc4 [June 15, 2006] + Really removed the new typedefs for 64-bit systems. + +Version 1.0.19rc5, 1.2.11rc5 [June 22, 2006] + Removed png_sig_bytes entry from scripts/pngw32.def + +Version 1.0.19, 1.2.11 [June 26, 2006] + None. + +Version 1.0.20, 1.2.12 [June 27, 2006] + Really increased sprintf buffer from 50 to 52 chars in pngrutil.c to avoid + buffer overflow. + +Version 1.2.13beta1 [October 2, 2006] + Removed AC_FUNC_MALLOC from configure.ac + Work around Intel-Mac compiler bug by setting PNG_NO_MMX_CODE in pngconf.h + Change "logical" to "bitwise" throughout documentation. + Detect and fix attempt to write wrong iCCP profile length (CVE-2006-7244) + +Version 1.0.21, 1.2.13 [November 14, 2006] + Fix potential buffer overflow in sPLT chunk handler. + Fix Makefile.am to not try to link to noexistent files. + Check all exported functions for NULL png_ptr. + +Version 1.2.14beta1 [November 17, 2006] + Relocated three misplaced tests for NULL png_ptr. + Built Makefile.in with automake-1.9.6 instead of 1.9.2. + Build configure with autoconf-2.60 instead of 2.59 + +Version 1.2.14beta2 [November 17, 2006] + Added some typecasts in png_zalloc(). + +Version 1.2.14rc1 [November 20, 2006] + Changed "strtod" to "png_strtod" in pngrutil.c + +Version 1.0.22, 1.2.14 [November 27, 2006] + Added missing "$(srcdir)" in Makefile.am and Makefile.in + +Version 1.2.15beta1 [December 3, 2006] + Generated configure with autoconf-2.61 instead of 2.60 + Revised configure.ac to update libpng.pc and libpng-config. + +Version 1.2.15beta2 [December 3, 2006] + Always export MMX asm functions, just stubs if not building pnggccrd.c + +Version 1.2.15beta3 [December 4, 2006] + Add "png_bytep" typecast to profile while calculating length in pngwutil.c + +Version 1.2.15beta4 [December 7, 2006] + Added scripts/CMakeLists.txt + Changed PNG_NO_ASSEMBLER_CODE to PNG_NO_MMX_CODE in scripts, like 1.4.0beta + +Version 1.2.15beta5 [December 7, 2006] + Changed some instances of PNG_ASSEMBLER_* to PNG_MMX_* in pnggccrd.c + Revised scripts/CMakeLists.txt + +Version 1.2.15beta6 [December 13, 2006] + Revised scripts/CMakeLists.txt and configure.ac + +Version 1.2.15rc1 [December 18, 2006] + Revised scripts/CMakeLists.txt + +Version 1.2.15rc2 [December 21, 2006] + Added conditional #undef jmpbuf in pngtest.c to undo #define in AIX headers. + Added scripts/makefile.nommx + +Version 1.2.15rc3 [December 25, 2006] + Fixed shared library numbering error that was introduced in 1.2.15beta6. + +Version 1.2.15rc4 [December 27, 2006] + Fixed handling of rgb_to_gray when png_ptr->color.gray isn't set. + +Version 1.2.15rc5 [December 31, 2006] + Revised handling of rgb_to_gray. + +Version 1.2.15 [January 5, 2007] + Added some (unsigned long) typecasts in pngtest.c to avoid printing errors. + +Version 1.2.16beta1 [January 6, 2007] + Fix bugs in makefile.nommx + +Version 1.2.16beta2 [January 16, 2007] + Revised scripts/CMakeLists.txt + +Version 1.2.16 [January 31, 2007] + No changes. + +Version 1.2.17beta1 [March 6, 2007] + Revised scripts/CMakeLists.txt to install both shared and static libraries. + Deleted a redundant line from pngset.c. + +Version 1.2.17beta2 [April 26, 2007] + Relocated misplaced test for png_ptr == NULL in pngpread.c + Change "==" to "&" for testing PNG_RGB_TO_GRAY_ERR & PNG_RGB_TO_GRAY_WARN + flags. + Changed remaining instances of PNG_ASSEMBLER_* to PNG_MMX_* + Added pngerror() when write_IHDR fails in deflateInit2(). + Added "const" to some array declarations. + Mention examples of libpng usage in the libpng*.txt and libpng.3 documents. + +Version 1.2.17rc1 [May 4, 2007] + No changes. + +Version 1.2.17rc2 [May 8, 2007] + Moved several PNG_HAVE_* macros out of PNG_INTERNAL because applications + calling set_unknown_chunk_location() need them. + Changed transformation flag from PNG_EXPAND_tRNS to PNG_EXPAND in + png_set_expand_gray_1_2_4_to_8(). + Added png_ptr->unknown_chunk to hold working unknown chunk data, so it + can be free'ed in case of error. Revised unknown chunk handling in + pngrutil.c and pngpread.c to use this structure. + +Version 1.2.17rc3 [May 8, 2007] + Revised symbol-handling in configure script. + +Version 1.2.17rc4 [May 10, 2007] + Revised unknown chunk handling to avoid storing unknown critical chunks. + +Version 1.0.25 [May 15, 2007] +Version 1.2.17 [May 15, 2007] + Added "png_ptr->num_trans=0" before error return in png_handle_tRNS, + to eliminate a vulnerability (CVE-2007-2445, CERT VU#684664) + +Version 1.0.26 [May 15, 2007] +Version 1.2.18 [May 15, 2007] + Reverted the libpng-1.2.17rc3 change to symbol-handling in configure script + +Version 1.2.19beta1 [May 18, 2007] + Changed "const static" to "static PNG_CONST" everywhere, mostly undoing + change of libpng-1.2.17beta2. Changed other "const" to "PNG_CONST" + Changed some handling of unused parameters, to avoid compiler warnings. + "if (unused == NULL) return;" becomes "unused = unused". + +Version 1.2.19beta2 [May 18, 2007] + Only use the valid bits of tRNS value in png_do_expand() (Brian Cartier) + +Version 1.2.19beta3 [May 19, 2007] + Add some "png_byte" typecasts in png_check_keyword() and write new_key + instead of key in zTXt chunk (Kevin Ryde). + +Version 1.2.19beta4 [May 21, 2007] + Add png_snprintf() function and use it in place of sprint() for improved + defense against buffer overflows. + +Version 1.2.19beta5 [May 21, 2007] + Fixed png_handle_tRNS() to only use the valid bits of tRNS value. + Changed handling of more unused parameters, to avoid compiler warnings. + Removed some PNG_CONST in pngwutil.c to avoid compiler warnings. + +Version 1.2.19beta6 [May 22, 2007] + Added some #ifdef PNG_MMX_CODE_SUPPORTED where needed in pngvcrd.c + Added a special "_MSC_VER" case that defines png_snprintf to _snprintf + +Version 1.2.19beta7 [May 22, 2007] + Squelched png_squelch_warnings() in pnggccrd.c and added + an #ifdef PNG_MMX_CODE_SUPPORTED block around the declarations that caused + the warnings that png_squelch_warnings was squelching. + +Version 1.2.19beta8 [May 22, 2007] + Removed __MMX__ from test in pngconf.h. + +Version 1.2.19beta9 [May 23, 2007] + Made png_squelch_warnings() available via PNG_SQUELCH_WARNINGS macro. + Revised png_squelch_warnings() so it might work. + Updated makefile.sgcc and makefile.solaris; added makefile.solaris-x86. + +Version 1.2.19beta10 [May 24, 2007] + Resquelched png_squelch_warnings(), use "__attribute__((used))" instead. + +Version 1.4.0beta1 [April 20, 2006] + Enabled iTXt support (changes png_struct, thus requires so-number change). + Cleaned up PNG_ASSEMBLER_CODE_SUPPORTED vs PNG_MMX_CODE_SUPPORTED + Eliminated PNG_1_0_X and PNG_1_2_X macros. + Removed deprecated functions png_read_init, png_write_init, png_info_init, + png_permit_empty_plte, png_set_gray_1_2_4_to_8, png_check_sig, and + removed the deprecated macro PNG_MAX_UINT. + Moved "PNG_INTERNAL" parts of png.h and pngconf.h into pngintrn.h + Removed many WIN32_WCE #ifdefs (Cosmin). + Reduced dependency on C-runtime library when on Windows (Simon-Pierre) + Replaced sprintf() with png_sprintf() (Simon-Pierre) + +Version 1.4.0beta2 [April 20, 2006] + Revised makefiles and configure to avoid making links to libpng.so.* + Moved some leftover MMX-related defines from pngconf.h to pngintrn.h + Updated scripts/pngos2.def, pngw32.def, and projects/wince/png32ce.def + +Version 1.4.0beta3 [May 10, 2006] + Updated scripts/pngw32.def to comment out MMX functions. + Added PNG_NO_GET_INT_32 and PNG_NO_SAVE_INT_32 macros. + Scripts/libpng.pc.in contained "configure" style version info and would + not work with makefiles. + Revised pngconf.h and added pngconf.h.in, so makefiles and configure can + pass defines to libpng and applications. + +Version 1.4.0beta4 [May 11, 2006] + Revised configure.ac, Makefile.am, and many of the makefiles to write + their defines in pngconf.h. + +Version 1.4.0beta5 [May 15, 2006] + Added a missing semicolon in Makefile.am and Makefile.in + Deleted extraneous square brackets from configure.ac + +Version 1.4.0beta6 [June 2, 2006] + Increased sprintf buffer from 50 to 52 chars in pngrutil.c to avoid + buffer overflow. + Changed sonum from 0 to 1. + Removed unused prototype for png_check_sig() from png.h + +Version 1.4.0beta7 [June 16, 2006] + Exported png_write_sig (Cosmin). + Optimized buffer in png_handle_cHRM() (Cosmin). + Set pHYs = 2835 x 2835 pixels per meter, and added + sCAL = 0.352778e-3 x 0.352778e-3 meters, in pngtest.png (Cosmin). + Added png_set_benign_errors(), png_benign_error(), png_chunk_benign_error(). + Added typedef for png_int_32 and png_uint_32 on 64-bit systems. + Added "(unsigned long)" typecast on png_uint_32 variables in printf lists. + +Version 1.4.0beta8 [June 22, 2006] + Added demonstration of user chunk support in pngtest.c, to support the + public sTER chunk and a private vpAg chunk. + +Version 1.4.0beta9 [July 3, 2006] + Removed ordinals from scripts/pngw32.def and removed png_info_int and + png_set_gray_1_2_4_to_8 entries. + Inline call of png_get_uint_32() in png_get_uint_31(). + Use png_get_uint_31() to get vpAg width and height in pngtest.c + Removed WINCE and Netware projects. + Removed standalone Y2KINFO file. + +Version 1.4.0beta10 [July 12, 2006] + Eliminated automatic copy of pngconf.h to pngconf.h.in from configure and + some makefiles, because it was not working reliably. Instead, distribute + pngconf.h.in along with pngconf.h and cause configure and some of the + makefiles to update pngconf.h from pngconf.h.in. + Added pngconf.h to DEPENDENCIES in Makefile.am + +Version 1.4.0beta11 [August 19, 2006] + Removed AC_FUNC_MALLOC from configure.ac. + Added a warning when writing iCCP profile with mismatched profile length. + Patched pnggccrd.c to assemble on x86_64 platforms. + Moved chunk header reading into a separate function png_read_chunk_header() + in pngrutil.c. The chunk header (len+sig) is now serialized in a single + operation (Cosmin). + Implemented support for I/O states. Added png_ptr member io_state, and + functions png_get_io_chunk_name() and png_get_io_state() in pngget.c + (Cosmin). + Added png_get_io_chunk_name and png_get_io_state to scripts/*.def (Cosmin). + Renamed scripts/pngw32.* to scripts/pngwin.* (Cosmin). + Removed the include directories and libraries from CFLAGS and LDFLAGS + in scripts/makefile.gcc (Cosmin). + Used png_save_uint_32() to set vpAg width and height in pngtest.c (Cosmin). + Cast to proper type when getting/setting vpAg units in pngtest.c (Cosmin). + Added pngintrn.h to the Visual C++ projects (Cosmin). + Removed scripts/list (Cosmin). + Updated copyright year in scripts/pngwin.def (Cosmin). + Removed PNG_TYPECAST_NULL and used standard NULL consistently (Cosmin). + Disallowed the user to redefine png_size_t, and enforced a consistent use + of png_size_t across libpng (Cosmin). + Changed the type of png_ptr->rowbytes, PNG_ROWBYTES() and friends + to png_size_t (Cosmin). + Removed png_convert_size() and replaced png_sizeof with sizeof (Cosmin). + Removed some unnecessary type casts (Cosmin). + Changed prototype of png_get_compression_buffer_size() and + png_set_compression_buffer_size() to work with png_size_t instead of + png_uint_32 (Cosmin). + Removed png_memcpy_check() and png_memset_check() (Cosmin). + Fixed a typo (png_byte --> png_bytep) in libpng.3 and libpng.txt (Cosmin). + Clarified that png_zalloc() does not clear the allocated memory, + and png_zalloc() and png_zfree() cannot be PNGAPI (Cosmin). + Renamed png_mem_size_t to png_alloc_size_t, fixed its definition in + pngconf.h, and used it in all memory allocation functions (Cosmin). + Renamed pngintrn.h to pngpriv.h, added a comment at the top of the file + mentioning that the symbols declared in that file are private, and + updated the scripts and the Visual C++ projects accordingly (Cosmin). + Removed circular references between pngconf.h and pngconf.h.in in + scripts/makefile.vc*win32 (Cosmin). + Removing trailing '.' from the warning and error messages (Cosmin). + Added pngdefs.h that is built by makefile or configure, instead of + pngconf.h.in (Glenn). + Detect and fix attempt to write wrong iCCP profile length. + +Version 1.4.0beta12 [October 19, 2006] + Changed "logical" to "bitwise" in the documentation. + Work around Intel-Mac compiler bug by setting PNG_NO_MMX_CODE in pngconf.h + Add a typecast to stifle compiler warning in pngrutil.c + +Version 1.4.0beta13 [November 10, 2006] + Fix potential buffer overflow in sPLT chunk handler. + Fix Makefile.am to not try to link to noexistent files. + +Version 1.4.0beta14 [November 15, 2006] + Check all exported functions for NULL png_ptr. + +Version 1.4.0beta15 [November 17, 2006] + Relocated two misplaced tests for NULL png_ptr. + Built Makefile.in with automake-1.9.6 instead of 1.9.2. + Build configure with autoconf-2.60 instead of 2.59 + Add "install: all" in Makefile.am so "configure; make install" will work. + +Version 1.4.0beta16 [November 17, 2006] + Added a typecast in png_zalloc(). + +Version 1.4.0beta17 [December 4, 2006] + Changed "new_key[79] = '\0';" to "(*new_key)[79] = '\0';" in pngwutil.c + Add "png_bytep" typecast to profile while calculating length in pngwutil.c + +Version 1.4.0beta18 [December 7, 2006] + Added scripts/CMakeLists.txt + +Version 1.4.0beta19 [May 16, 2007] + Revised scripts/CMakeLists.txt + Rebuilt configure and Makefile.in with newer tools. + Added conditional #undef jmpbuf in pngtest.c to undo #define in AIX headers. + Added scripts/makefile.nommx + +Version 1.4.0beta20 [July 9, 2008] + Moved several PNG_HAVE_* macros from pngpriv.h to png.h because applications + calling set_unknown_chunk_location() need them. + Moved several macro definitions from pngpriv.h to pngconf.h + Merge with changes to the 1.2.X branch, as of 1.2.30beta04. + Deleted all use of the MMX assembler code and Intel-licensed optimizations. + Revised makefile.mingw + +Version 1.4.0beta21 [July 21, 2008] + Moved local array "chunkdata" from pngrutil.c to the png_struct, so + it will be freed by png_read_destroy() in case of a read error (Kurt + Christensen). + +Version 1.4.0beta22 [July 21, 2008] + Change "purpose" and "buffer" to png_ptr->chunkdata to avoid memory leaking. + +Version 1.4.0beta23 [July 22, 2008] + Change "chunkdata = NULL" to "png_ptr->chunkdata = NULL" several places in + png_decompress_chunk(). + +Version 1.4.0beta24 [July 25, 2008] + Change all remaining "chunkdata" to "png_ptr->chunkdata" in + png_decompress_chunk(), and remove "chunkdata" from parameter list. + Put a call to png_check_chunk_name() in png_read_chunk_header(). + Revised png_check_chunk_name() to reject a name with a lowercase 3rd byte. + Removed two calls to png_check_chunk_name() occurring later in the process. + Define PNG_NO_ERROR_NUMBERS by default in pngconf.h + +Version 1.4.0beta25 [July 30, 2008] + Added a call to png_check_chunk_name() in pngpread.c + Reverted png_check_chunk_name() to accept a name with a lowercase 3rd byte. + Added png_push_have_buffer() function to pngpread.c + Eliminated PNG_BIG_ENDIAN_SUPPORTED and associated png_get_* macros. + Made inline expansion of png_get_*() optional with PNG_USE_READ_MACROS. + Eliminated all PNG_USELESS_TESTS and PNG_CORRECT_PALETTE_SUPPORTED code. + Synced contrib directory and configure files with libpng-1.2.30beta06. + Eliminated no-longer-used pngdefs.h (but it's still built in the makefiles) + Relocated a misplaced "#endif /* PNG_NO_WRITE_FILTER */" in pngwutil.c + +Version 1.4.0beta26 [August 4, 2008] + Removed png_push_have_buffer() function in pngpread.c. It increased the + compiled library size slightly. + Changed "-Wall" to "-W -Wall" in the CFLAGS in all makefiles (Cosmin Truta) + Declared png_ptr "volatile" in pngread.c and pngwrite.c to avoid warnings. + Updated contrib/visupng/cexcept.h to version 2.0.1 + Added PNG_LITERAL_CHARACTER macros for #, [, and ]. + +Version 1.4.0beta27 [August 5, 2008] + Revised usage of PNG_LITERAL_SHARP in pngerror.c. + Moved newline character from individual png_debug messages into the + png_debug macros. + Allow user to #define their own png_debug, png_debug1, and png_debug2. + +Version 1.4.0beta28 [August 5, 2008] + Revised usage of PNG_LITERAL_SHARP in pngerror.c. + Added PNG_STRING_NEWLINE macro + +Version 1.4.0beta29 [August 9, 2008] + Revised usage of PNG_STRING_NEWLINE to work on non-ISO compilers. + Added PNG_STRING_COPYRIGHT macro. + Added non-ISO versions of png_debug macros. + +Version 1.4.0beta30 [August 14, 2008] + Added premultiplied alpha feature (Volker Wiendl). + +Version 1.4.0beta31 [August 18, 2008] + Moved png_set_premultiply_alpha from pngtrans.c to pngrtran.c + Removed extra crc check at the end of png_handle_cHRM(). Bug introduced + in libpng-1.4.0beta20. + +Version 1.4.0beta32 [August 19, 2008] + Added PNG_WRITE_FLUSH_SUPPORTED block around new png_flush() call. + Revised PNG_NO_STDIO version of png_write_flush() + +Version 1.4.0beta33 [August 20, 2008] + Added png_get|set_chunk_cache_max() to limit the total number of sPLT, + text, and unknown chunks that can be stored. + +Version 1.4.0beta34 [September 6, 2008] + Shortened tIME_string to 29 bytes in pngtest.c + Fixed off-by-one error introduced in png_push_read_zTXt() function in + libpng-1.2.30beta04/pngpread.c (Harald van Dijk) + +Version 1.4.0beta35 [October 6, 2008] + Changed "trans_values" to "trans_color". + Changed so-number from 0 to 14. Some OS do not like 0. + Revised makefile.darwin to fix shared library numbering. + Change png_set_gray_1_2_4_to_8() to png_set_expand_gray_1_2_4_to_8() + in example.c (debian bug report) + +Version 1.4.0beta36 [October 25, 2008] + Sync with tEXt vulnerability fix in libpng-1.2.33rc02. + +Version 1.4.0beta37 [November 13, 2008] + Added png_check_cHRM in png.c and moved checking from pngget.c, pngrutil.c, + and pngwrite.c + +Version 1.4.0beta38 [November 22, 2008] + Added check for zero-area RGB cHRM triangle in png_check_cHRM() and + png_check_cHRM_fixed(). + +Version 1.4.0beta39 [November 23, 2008] + Revised png_warning() to write its message on standard output by default + when warning_fn is NULL. + +Version 1.4.0beta40 [November 24, 2008] + Eliminated png_check_cHRM(). Instead, always use png_check_cHRM_fixed(). + In png_check_cHRM_fixed(), ensure white_y is > 0, and removed redundant + check for all-zero coordinates that is detected by the triangle check. + +Version 1.4.0beta41 [November 26, 2008] + Fixed string vs pointer-to-string error in png_check_keyword(). + Rearranged test expressions in png_check_cHRM_fixed() to avoid internal + overflows. + Added PNG_NO_CHECK_cHRM conditional. + +Version 1.4.0beta42, 43 [December 1, 2008] + Merge png_debug with version 1.2.34beta04. + +Version 1.4.0beta44 [December 6, 2008] + Removed redundant check for key==NULL before calling png_check_keyword() + to ensure that new_key gets initialized and removed extra warning + (Merge with version 1.2.34beta05 -- Arvan Pritchard). + +Version 1.4.0beta45 [December 9, 2008] + In png_write_png(), respect the placement of the filler bytes in an earlier + call to png_set_filler() (Jim Barry). + +Version 1.4.0beta46 [December 10, 2008] + Undid previous change and added PNG_TRANSFORM_STRIP_FILLER_BEFORE and + PNG_TRANSFORM_STRIP_FILLER_AFTER conditionals and deprecated + PNG_TRANSFORM_STRIP_FILLER (Jim Barry). + +Version 1.4.0beta47 [December 15, 2008] + Support for dithering was disabled by default, because it has never + been well tested and doesn't work very well. The code has not + been removed, however, and can be enabled by building libpng with + PNG_READ_DITHER_SUPPORTED defined. + +Version 1.4.0beta48 [February 14, 2009] + Added new exported function png_calloc(). + Combined several instances of png_malloc(); png_memset() into png_calloc(). + Removed prototype for png_freeptr() that was added in libpng-1.4.0beta24 + but was never defined. + +Version 1.4.0beta49 [February 28, 2009] + Added png_fileno() macro to pngconf.h, used in pngwio.c + Corrected order of #ifdef's in png_debug definition in png.h + Fixed bug introduced in libpng-1.4.0beta48 with the memset arguments + for pcal_params. + Fixed order of #ifdef directives in the png_debug defines in png.h + (bug introduced in libpng-1.2.34/1.4.0beta29). + Revised comments in png_set_read_fn() and png_set_write_fn(). + +Version 1.4.0beta50 [March 18, 2009] + Use png_calloc() instead of png_malloc() to allocate big_row_buf when + reading an interlaced file, to avoid a possible UMR. + Undid revision of PNG_NO_STDIO version of png_write_flush(). Users + having trouble with fflush() can build with PNG_NO_WRITE_FLUSH defined + or supply their own flush_fn() replacement. + Revised libpng*.txt and png.h documentation about use of png_write_flush() + and png_set_write_fn(). + Removed fflush() from pngtest.c. + Added "#define PNG_NO_WRITE_FLUSH" to contrib/pngminim/encoder/pngusr.h + +Version 1.4.0beta51 [March 21, 2009] + Removed new png_fileno() macro from pngconf.h . + +Version 1.4.0beta52 [March 27, 2009] + Relocated png_do_chop() ahead of building gamma tables in pngrtran.c + This avoids building 16-bit gamma tables unnecessarily. + Removed fflush() from pngtest.c. + Added "#define PNG_NO_WRITE_FLUSH" to contrib/pngminim/encoder/pngusr.h + Added a section on differences between 1.0.x and 1.2.x to libpng.3/libpng.txt + +Version 1.4.0beta53 [April 1, 2009] + Removed some remaining MMX macros from pngpriv.h + Fixed potential memory leak of "new_name" in png_write_iCCP() (Ralph Giles) + +Version 1.4.0beta54 [April 13, 2009] + Added "ifndef PNG_SKIP_SETJMP_CHECK" block in pngconf.h to allow + application code writers to bypass the check for multiple inclusion + of setjmp.h when they know that it is safe to ignore the situation. + Eliminated internal use of setjmp() in pngread.c and pngwrite.c + Reordered ancillary chunks in pngtest.png to be the same as what + pngtest now produces, and made some cosmetic changes to pngtest output. + Eliminated deprecated png_read_init_3() and png_write_init_3() functions. + +Version 1.4.0beta55 [April 15, 2009] + Simplified error handling in pngread.c and pngwrite.c by putting + the new png_read_cleanup() and png_write_cleanup() functions inline. + +Version 1.4.0beta56 [April 25, 2009] + Renamed "user_chunk_data" to "my_user_chunk_data" in pngtest.c to suppress + "shadowed declaration" warning from gcc-4.3.3. + Renamed "gamma" to "png_gamma" in pngset.c to avoid "shadowed declaration" + warning about a global "gamma" variable in math.h on some platforms. + +Version 1.4.0beta57 [May 2, 2009] + Removed prototype for png_freeptr() that was added in libpng-1.4.0beta24 + but was never defined (again). + Rebuilt configure scripts with autoconf-2.63 instead of 2.62 + Removed pngprefs.h and MMX from makefiles + +Version 1.4.0beta58 [May 14, 2009] + Changed pngw32.def to pngwin.def in makefile.mingw (typo was introduced + in beta57). + Clarified usage of sig_bit versus sig_bit_p in example.c (Vincent Torri) + +Version 1.4.0beta59 [May 15, 2009] + Reformated sources in libpng style (3-space intentation, comment format) + Fixed typo in libpng docs (PNG_FILTER_AVE should be PNG_FILTER_AVG) + Added sections about the git repository and our coding style to the + documentation + Relocated misplaced #endif in pngwrite.c, sCAL chunk handler. + +Version 1.4.0beta60 [May 19, 2009] + Conditionally compile png_read_finish_row() which is not used by + progressive readers. + Added contrib/pngminim/preader to demonstrate building minimal progressive + decoder, based on contrib/gregbook with embedded libpng and zlib. + +Version 1.4.0beta61 [May 20, 2009] + In contrib/pngminim/*, renamed "makefile.std" to "makefile", since there + is only one makefile in those directories, and revised the README files + accordingly. + More reformatting of comments, mostly to capitalize sentences. + +Version 1.4.0beta62 [June 2, 2009] + Added "#define PNG_NO_WRITE_SWAP" to contrib/pngminim/encoder/pngusr.h + and "define PNG_NO_READ_SWAP" to decoder/pngusr.h and preader/pngusr.h + Reformatted several remaining "else statement" into two lines. + Added a section to the libpng documentation about using png_get_io_ptr() + in configure scripts to detect the presence of libpng. + +Version 1.4.0beta63 [June 15, 2009] + Revised libpng*.txt and libpng.3 to mention calling png_set_IHDR() + multiple times and to specify the sample order in the tRNS chunk, + because the ISO PNG specification has a typo in the tRNS table. + Changed several PNG_UNKNOWN_CHUNK_SUPPORTED to + PNG_HANDLE_AS_UNKNOWN_SUPPORTED, to make the png_set_keep mechanism + available for ignoring known chunks even when not saving unknown chunks. + Adopted preference for consistent use of "#ifdef" and "#ifndef" versus + "#if defined()" and "if !defined()" where possible. + +Version 1.4.0beta64 [June 24, 2009] + Eliminated PNG_LEGACY_SUPPORTED code. + Moved the various unknown chunk macro definitions outside of the + PNG_READ|WRITE_ANCILLARY_CHUNK_SUPPORTED blocks. + +Version 1.4.0beta65 [June 26, 2009] + Added a reference to the libpng license in each file. + +Version 1.4.0beta66 [June 27, 2009] + Refer to the libpng license instead of the libpng license in each file. + +Version 1.4.0beta67 [July 6, 2009] + Relocated INVERT_ALPHA within png_read_png() and png_write_png(). + Added high-level API transform PNG_TRANSFORM_GRAY_TO_RGB. + Added an "xcode" project to the projects directory (Alam Arias). + +Version 1.4.0beta68 [July 19, 2009] + Avoid some tests in filter selection in pngwutil.c + +Version 1.4.0beta69 [July 25, 2009] + Simplified the new filter-selection test. This runs faster in the + common "PNG_ALL_FILTERS" and PNG_FILTER_NONE cases. + Removed extraneous declaration from the new call to png_read_gray_to_rgb() + (bug introduced in libpng-1.4.0beta67). + Fixed up xcode project (Alam Arias) + Added a prototype for png_64bit_product() in png.c + +Version 1.4.0beta70 [July 27, 2009] + Avoid a possible NULL dereference in debug build, in png_set_text_2(). + (bug introduced in libpng-0.95, discovered by Evan Rouault) + +Version 1.4.0beta71 [July 29, 2009] + Rebuilt configure scripts with autoconf-2.64. + +Version 1.4.0beta72 [August 1, 2009] + Replaced *.tar.lzma with *.tar.xz in distribution. Get the xz codec + from . + +Version 1.4.0beta73 [August 1, 2009] + Reject attempt to write iCCP chunk with negative embedded profile length + (JD Chen) (CVE-2009-5063). + +Version 1.4.0beta74 [August 8, 2009] + Changed png_ptr and info_ptr member "trans" to "trans_alpha". + +Version 1.4.0beta75 [August 21, 2009] + Removed an extra png_debug() recently added to png_write_find_filter(). + Fixed incorrect #ifdef in pngset.c regarding unknown chunk support. + +Version 1.4.0beta76 [August 22, 2009] + Moved an incorrectly located test in png_read_row() in pngread.c + +Version 1.4.0beta77 [August 27, 2009] + Removed lpXYZ.tar.bz2 (with CRLF), KNOWNBUG, libpng-x.y.z-KNOWNBUG.txt, + and the "noconfig" files from the distribution. + Moved CMakeLists.txt from scripts into the main libpng directory. + Various bugfixes and improvements to CMakeLists.txt (Philip Lowman) + +Version 1.4.0beta78 [August 31, 2009] + Converted all PNG_NO_* tests to PNG_*_SUPPORTED everywhere except pngconf.h + Eliminated PNG_NO_FREE_ME and PNG_FREE_ME_SUPPORTED macros. + Use png_malloc plus a loop instead of png_calloc() to initialize + row_pointers in png_read_png(). + +Version 1.4.0beta79 [September 1, 2009] + Eliminated PNG_GLOBAL_ARRAYS and PNG_LOCAL_ARRAYS; always use local arrays. + Eliminated PNG_CALLOC_SUPPORTED macro and always provide png_calloc(). + +Version 1.4.0beta80 [September 17, 2009] + Removed scripts/libpng.icc + Changed typecast of filler from png_byte to png_uint_16 in png_set_filler(). + (Dennis Gustafsson) + Fixed typo introduced in beta78 in pngtest.c ("#if def " should be "#ifdef ") + +Version 1.4.0beta81 [September 23, 2009] + Eliminated unused PNG_FLAG_FREE_* defines from pngpriv.h + Expanded TAB characters in pngrtran.c + Removed PNG_CONST from all "PNG_CONST PNG_CHNK" declarations to avoid + compiler complaints about doubly declaring things "const". + Changed all "#if [!]defined(X)" to "if[n]def X" where possible. + Eliminated unused png_ptr->row_buf_size + +Version 1.4.0beta82 [September 25, 2009] + Moved redundant IHDR checking into new png_check_IHDR() in png.c + and report all errors found in the IHDR data. + Eliminated useless call to png_check_cHRM() from pngset.c + +Version 1.4.0beta83 [September 25, 2009] + Revised png_check_IHDR() to eliminate bogus complaint about filter_type. + +Version 1.4.0beta84 [September 30, 2009] + Fixed some inconsistent indentation in pngconf.h + Revised png_check_IHDR() to add a test for width variable less than 32-bit. + +Version 1.4.0beta85 [October 1, 2009] + Revised png_check_IHDR() again, to check info_ptr members instead of + the contents of the returned parameters. + +Version 1.4.0beta86 [October 9, 2009] + Updated the "xcode" project (Alam Arias). + Eliminated a shadowed declaration of "pp" in png_handle_sPLT(). + +Version 1.4.0rc01 [October 19, 2009] + Trivial cosmetic changes. + +Version 1.4.0beta87 [October 30, 2009] + Moved version 1.4.0 back into beta. + +Version 1.4.0beta88 [October 30, 2009] + Revised libpng*.txt section about differences between 1.2.x and 1.4.0 + because most of the new features have now been ported back to 1.2.41 + +Version 1.4.0beta89 [November 1, 2009] + More bugfixes and improvements to CMakeLists.txt (Philip Lowman) + Removed a harmless extra png_set_invert_alpha() from pngwrite.c + Apply png_user_chunk_cache_max within png_decompress_chunk(). + Merged libpng-1.2.41.txt with libpng-1.4.0.txt where appropriate. + +Version 1.4.0beta90 [November 2, 2009] + Removed all remaining WIN32_WCE #ifdefs except those involving the + time.h "tm" structure + +Version 1.4.0beta91 [November 3, 2009] + Updated scripts/pngw32.def and projects/wince/png32ce.def + Copied projects/wince/png32ce.def to the scripts directory. + Added scripts/makefile.wce + Patched ltmain.sh for wince support. + Added PNG_CONVERT_tIME_SUPPORTED macro. + +Version 1.4.0beta92 [November 4, 2009] + Make inclusion of time.h in pngconf.h depend on PNG_CONVERT_tIME_SUPPORTED + Make #define PNG_CONVERT_tIME_SUPPORTED depend on PNG_WRITE_tIME_SUPPORTED + Revised libpng*.txt to describe differences from 1.2.40 to 1.4.0 (instead + of differences from 1.2.41 to 1.4.0) + +Version 1.4.0beta93 [November 7, 2009] + Added PNG_DEPSTRUCT, PNG_DEPRECATED, PNG_USE_RESULT, PNG_NORETURN, and + PNG_ALLOCATED macros to detect deprecated direct access to the + png_struct or info_struct members and other deprecated usage in + applications (John Bowler). + Updated scripts/makefile* to add "-DPNG_CONFIGURE_LIBPNG" to CFLAGS, + to prevent warnings about direct access to png structs by libpng + functions while building libpng. They need to be tested, especially + those using compilers other than gcc. + Updated projects/visualc6 and visualc71 with "/d PNG_CONFIGURE_LIBPNG". + They should work but still need to be updated to remove + references to pnggccrd.c or pngvcrd.c and ASM building. + Added README.txt to the beos, cbuilder5, netware, and xcode projects warning + that they need to be updated, to remove references to pnggccrd.c and + pngvcrd.c and to depend on pngpriv.h + Removed three direct references to read_info_ptr members in pngtest.c + that were detected by the new PNG_DEPSTRUCT macro. + Moved the png_debug macro definitions and the png_read_destroy(), + png_write_destroy() and png_far_to_near() prototypes from png.h + to pngpriv.h (John Bowler) + Moved the synopsis lines for png_read_destroy(), png_write_destroy() + png_debug(), png_debug1(), and png_debug2() from libpng.3 to libpngpf.3. + +Version 1.4.0beta94 [November 9, 2009] + Removed the obsolete, unused pnggccrd.c and pngvcrd.c files. + Updated CMakeLists.txt to add "-DPNG_CONFIGURE_LIBPNG" to the definitions. + Removed dependency of pngtest.o on pngpriv.h in the makefiles. + Only #define PNG_DEPSTRUCT, etc. in pngconf.h if not already defined. + +Version 1.4.0beta95 [November 10, 2009] + Changed png_check_sig() to !png_sig_cmp() in contrib programs. + Added -DPNG_CONFIGURE_LIBPNG to contrib/pngminm/*/makefile + Changed png_check_sig() to !png_sig_cmp() in contrib programs. + Corrected the png_get_IHDR() call in contrib/gregbook/readpng2.c + Changed pngminim/*/gather.sh to stop trying to remove pnggccrd.c and pngvcrd.c + Added dependency on pngpriv.h in contrib/pngminim/*/makefile + +Version 1.4.0beta96 [November 12, 2009] + Renamed scripts/makefile.wce to scripts/makefile.cegcc + Revised Makefile.am to use libpng.sys while building libpng.so + so that only PNG_EXPORT functions are exported. + Removed the deprecated png_check_sig() function/macro. + Removed recently removed function names from scripts/*.def + Revised pngtest.png to put chunks in the same order written by pngtest + (evidently the same change made in libpng-1.0beta54 was lost). + Added PNG_PRIVATE macro definition in pngconf.h for possible future use. + +Version 1.4.0beta97 [November 13, 2009] + Restored pngtest.png to the libpng-1.4.0beta7 version. + Removed projects/beos and netware.txt; no one seems to be supporting them. + Revised Makefile.in + +Version 1.4.0beta98 [November 13, 2009] + Added the "xcode" project to zip distributions, + Fixed a typo in scripts/pngwin.def introduced in beta97. + +Version 1.4.0beta99 [November 14, 2009] + Moved libpng-config.in and libpng.pc-configure.in out of the scripts + directory, to libpng-config.in and libpng-pc.in, respectively, and + modified Makefile.am and configure.ac accordingly. Now "configure" + needs nothing from the "scripts" directory. + Avoid redefining PNG_CONST in pngconf.h + +Version 1.4.0beta100 [November 14, 2009] + Removed ASM builds from projects/visualc6 and projects/visualc71 + Removed scripts/makefile.nommx and makefile.vcawin32 + Revised CMakeLists.txt to account for new location of libpng-config.in + and libpng-pc.in + Updated INSTALL to reflect removal and relocation of files. + +Version 1.4.0beta101 [November 14, 2009] + Restored the binary files (*.jpg, *.png, some project files) that were + accidentally deleted from the zip and 7z distributions when the xcode + project was added. + +Version 1.4.0beta102 [November 18, 2009] + Added libpng-config.in and libpng-pc.in to the zip and 7z distributions. + Fixed a typo in projects/visualc6/pngtest.dsp, introduced in beta100. + Moved descriptions of makefiles and other scripts out of INSTALL into + scripts/README.txt + Updated the copyright year in scripts/pngwin.rc from 2006 to 2009. + +Version 1.4.0beta103 [November 21, 2009] + Removed obsolete comments about ASM from projects/visualc71/README_zlib.txt + Align row_buf on 16-byte boundary in memory. + Restored the PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED guard around the call + to png_flush() after png_write_IEND(). See 1.4.0beta32, 1.4.0beta50 + changes above and 1.2.30, 1.2.30rc01 and rc03 in 1.2.41 CHANGES. Someone + needs this feature. + Make the 'png_jmpbuf' macro expand to a call that records the correct + longjmp function as well as returning a pointer to the setjmp + jmp_buf buffer, and marked direct access to jmpbuf 'deprecated'. + (John Bowler) + +Version 1.4.0beta104 [November 22, 2009] + Removed png_longjmp_ptr from scripts/*.def and libpng.3 + Rebuilt configure scripts with autoconf-2.65 + +Version 1.4.0beta105 [November 25, 2009] + Use fast integer PNG_DIVIDE_BY_255() or PNG_DIVIDE_BY_65535() + to accomplish alpha premultiplication when + PNG_READ_COMPOSITE_NODIV_SUPPORTED is defined. + Changed "/255" to "/255.0" in background calculations to make it clear + that the 255 is used as a double. + +Version 1.4.0beta106 [November 27, 2009] + Removed premultiplied alpha feature. + +Version 1.4.0beta107 [December 4, 2009] + Updated README + Added "#define PNG_NO_PEDANTIC_WARNINGS" in the libpng source files. + Removed "-DPNG_CONFIGURE_LIBPNG" from the makefiles and projects. + Revised scripts/makefile.netbsd, makefile.openbsd, and makefile.sco + to put png.h and pngconf.h in $prefix/include, like the other scripts, + instead of in $prefix/include/libpng. Also revised makefile.sco + to put them in $prefix/include/libpng15 instead of in + $prefix/include/libpng/libpng15. + +Version 1.4.0beta108 [December 11, 2009] + Removed leftover "-DPNG_CONFIGURE_LIBPNG" from contrib/pngminim/*/makefile + Relocated png_do_chop() to its original position in pngrtran.c; the + change in version 1.2.41beta08 caused transparency to be handled wrong + in some 16-bit datastreams (Yusaku Sugai). + +Version 1.4.0beta109 [December 13, 2009] + Added "bit_depth" parameter to the private png_build_gamma_table() function. + Pass bit_depth=8 to png_build_gamma_table() when bit_depth is 16 but the + PNG_16_TO_8 transform has been set, to avoid unnecessary build of 16-bit + tables. + +Version 1.4.0rc02 [December 20, 2009] + Declared png_cleanup_needed "volatile" in pngread.c and pngwrite.c + +Version 1.4.0rc03 [December 22, 2009] + Renamed libpng-pc.in back to libpng.pc.in and revised CMakeLists.txt + (revising the change in 1.4.0beta99) + +Version 1.4.0rc04 [December 25, 2009] + Swapped PNG_UNKNOWN_CHUNKS_SUPPORTED and PNG_HANDLE_AS_UNKNOWN_SUPPORTED + in pngset.c to be consistent with other changes in version 1.2.38. + +Version 1.4.0rc05 [December 25, 2009] + Changed "libpng-pc.in" to "libpng.pc.in" in configure.ac, configure, and + Makefile.in to be consistent with changes in libpng-1.4.0rc03 + +Version 1.4.0rc06 [December 29, 2009] + Reverted the gamma_table changes from libpng-1.4.0beta109. + Fixed some indentation errors. + +Version 1.4.0rc07 [January 1, 2010] + Revised libpng*.txt and libpng.3 about 1.2.x->1.4.x differences. + Use png_calloc() instead of png_malloc(); png_memset() in pngrutil.c + Update copyright year to 2010. + +Version 1.4.0rc08 [January 2, 2010] + Avoid deprecated references to png_ptr-io_ptr and png_ptr->error_ptr + in pngtest.c + +Version 1.4.0 [January 3, 2010] + No changes. + +Version 1.4.1beta01 [January 8, 2010] + Updated CMakeLists.txt for consistent indentation and to avoid an + unclosed if-statement warning (Philip Lowman). + Revised Makefile.am and Makefile.in to remove references to Y2KINFO, + KNOWNBUG, and libpng.la (Robert Schwebel). + Revised the makefiles to install the same files and symbolic + links as configure, except for libpng.la and libpng14.la. + Make png_set|get_compression_buffer_size() available even when + PNG_WRITE_SUPPORTED is not enabled. + Revised Makefile.am and Makefile.in to simplify their maintenance. + Revised scripts/makefile.linux to install a link to libpng14.so.14.1 + +Version 1.4.1beta02 [January 9, 2010] + Revised the rest of the makefiles to install a link to libpng14.so.14.1 + +Version 1.4.1beta03 [January 10, 2010] + Removed png_set_premultiply_alpha() from scripts/*.def + +Version 1.4.1rc01 [January 16, 2010] + No changes. + +Version 1.4.1beta04 [January 23, 2010] + Revised png_decompress_chunk() to improve speed and memory usage when + decoding large chunks. + Added png_set|get_chunk_malloc_max() functions. + +Version 1.4.1beta05 [January 26, 2010] + Relocated "int k" declaration in pngtest.c to minimize its scope. + +Version 1.4.1beta06 [January 28, 2010] + Revised png_decompress_chunk() to use a two-pass method suggested by + John Bowler. + +Version 1.4.1beta07 [February 6, 2010] + Folded some long lines in the source files. + Added defineable PNG_USER_CHUNK_CACHE_MAX, PNG_USER_CHUNK_MALLOC_MAX, + and a PNG_USER_LIMITS_SUPPORTED flag. + Eliminated use of png_ptr->irowbytes and reused the slot in png_ptr as + png_ptr->png_user_chunk_malloc_max. + Revised png_push_save_buffer() to do fewer but larger png_malloc() calls. + +Version 1.4.1beta08 [February 6, 2010] + Minor cleanup and updating of dates and copyright year. + +Version 1.5.0beta01 [February 7, 2010] + Moved declaration of png_struct into private pngstruct.h and png_info + into pnginfo.h + +Version 1.4.1beta09 and 1.5.0beta02 [February 7, 2010] + Reverted to original png_push_save_buffer() code. + +Version 1.4.1beta10 and 1.5.0beta03 [February 8, 2010] + Return allocated "old_buffer" in png_push_save_buffer() before + calling png_error(), to avoid a potential memory leak. + Updated configure script to use SO number 15. + +Version 1.5.0beta04 [February 9, 2010] + Removed malformed "incomplete struct declaration" of png_info from png.h + +Version 1.5.0beta05 [February 12, 2010] + Removed PNG_DEPSTRUCT markup in pngstruct.h and pnginfo.h, and undid the + linewrapping that it entailed. + Revised comments in pngstruct.h and pnginfo.h and added pointers to + the libpng license. + Changed PNG_INTERNAL to PNG_EXPOSE_INTERNAL_STRUCTURES + Removed the cbuilder5 project, which has not been updated to 1.4.0. + +Version 1.4.1beta12 and 1.5.0beta06 [February 14, 2010] + Fixed type declaration of png_get_chunk_malloc_max() in pngget.c (Daisuke + Nishikawa) + +Version 1.5.0beta07 [omitted] + +Version 1.5.0beta08 [February 19, 2010] + Changed #ifdef PNG_NO_STDIO_SUPPORTED to #ifdef PNG_NO_CONSOLE_IO_SUPPORTED + wherever png_snprintf() is used to construct error and warning messages. + Noted in scripts/makefile.mingw that it expects to be run under MSYS. + Removed obsolete unused MMX-querying support from contrib/gregbook + Added exported png_longjmp() function. + Removed the AIX redefinition of jmpbuf in png.h + Added -D_ALLSOURCE in configure.ac, makefile.aix, and CMakeLists.txt + when building on AIX. + +Version 1.5.0beta09 [February 19, 2010] + Removed -D_ALLSOURCE from configure.ac, makefile.aix, and CMakeLists.txt. + Changed the name of png_ptr->jmpbuf to png_ptr->png_jmpbuf in pngstruct.h + +Version 1.5.0beta10 [February 25, 2010] + Removed unused gzio.c from contrib/pngminim gather and makefile scripts + Removed replacement error handlers from contrib/gregbook. Because of + the new png_longjmp() function they are no longer needed. + +Version 1.5.0beta11 [March 6, 2010] + Removed checking for already-included setjmp.h from pngconf.h + Fixed inconsistent indentations and made numerous cosmetic changes. + Revised the "SEE ALSO" style of libpng.3, libpngpf.3, and png.5 + +Version 1.5.0beta12 [March 9, 2010] + Moved "#include png.h" inside pngpriv.h and removed "#include png.h" from + the source files, along with "#define PNG_EXPOSE_INTERNAL_STRUCTURES" + and "#define PNG_NO_PEDANTIC_WARNINGS" (John Bowler). + Created new pngdebug.h and moved debug definitions there. + +Version 1.5.0beta13 [March 10, 2010] + Protect pngstruct.h, pnginfo.h, and pngdebug.h from being included twice. + Revise the "#ifdef" blocks in png_inflate() so it will compile when neither + PNG_USER_CHUNK_MALLOC_MAX nor PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED + is defined. + Removed unused png_measure_compressed_chunk() from pngpriv.h and libpngpf.3 + Moved the 'config.h' support from pngconf.h to pngpriv.h + Removed PNGAPI from the png_longjmp_ptr typedef. + Eliminated dependence of pngtest.c on the private pngdebug.h file. + Make all png_debug macros into *unterminated* statements or + expressions (i.e. a trailing ';' must always be added) and correct + the format statements in various png_debug messages. + +Version 1.5.0beta14 [March 14, 2010] + Removed direct access to png_ptr->io_ptr from the Windows code in pngtest.c + Revised Makefile.am to account for recent additions and replacements. + Corrected CE and OS/2 DEF files (scripts/png*def) for symbols removed and + added ordinal numbers to the Windows DEF file and corrected the duplicated + ordinal numbers on CE symbols that are commented out. + Added back in export symbols that can be present in the Windows build but + are disabled by default. + PNG_EXPORT changed to include an 'ordinal' field for DEF file generation. + PNG_CALLBACK added to make callback definitions uniform. PNGAPI split + into PNGCAPI (base C form), PNGAPI (exports) and PNGCBAPI (callbacks), + and appropriate changes made to all files. Cygwin builds re-hinged to + allow procedure call standard changes and to remove the need for the DEF + file (fixes build on Cygwin). + Enabled 'attribute' warnings that are relevant to library APIs and callbacks. + Changed rules for generation of the various symbol files and added a new + rule for a DEF file (which is also added to the distribution). + Updated the symbol file generation to stop it adding spurious spaces + to EOL (coming from preprocessor macro expansion). Added a facility + to join tokens in the output and rewrite *.dfn to use this. + Eliminated scripts/*.def in favor of libpng.def; updated projects/visualc71 + and removed scripts/makefile.cygwin. + Made PNG_BUILD_DLL safe: it can be set whenever a DLL is being built. + Removed the include of sys/types.h - apparently unnecessary now on the + platforms on which it happened (all but Mac OS and RISC OS). + Moved the Mac OS test into pngpriv.h (the only place it is used.) + +Version 1.5.0beta15 [March 17, 2010] + Added symbols.chk target to Makefile.am to validate the symbols in png.h + against the new DEF file scripts/symbols.def. + Changed the default DEF file back to pngwin.def. + Removed makefile.mingw. + Eliminated PNG_NO_EXTERN and PNG_ALL_EXTERN + +Version 1.5.0beta16 [April 1, 2010] + Make png_text_struct independent of PNG_iTXt_SUPPORTED, so that + fields are initialized in all configurations. The READ/WRITE + macros (PNG_(READ|WRITE)_iTXt_SUPPORTED) still function as + before to disable code to actually read or write iTXt chunks + and iTXt_SUPPORTED can be used to detect presence of either + read or write support (but it is probably better to check for + the one actually required - read or write.) + Combined multiple png_warning() calls for a single error. + Restored the macro definition of png_check_sig(). + +Version 1.5.0beta17 [April 17, 2010] + Added some "(long)" typecasts to printf calls in png_handle_cHRM(). + Documented the fact that png_set_dither() was disabled since libpng-1.4.0. + Reenabled png_set_dither() but renamed it to png_set_quantize() to reflect + more accurately what it actually does. At the same time, renamed + the PNG_DITHER_[RED,GREEN_BLUE]_BITS macros to + PNG_QUANTIZE_[RED,GREEN,BLUE]_BITS. + Added some "(long)" typecasts to printf calls in png_handle_cHRM(). + Freeze build-time only configuration in the build. + In all prior versions of libpng most configuration options + controlled by compiler #defines had to be repeated by the + application code that used libpng. This patch changes this + so that compilation options that can only be changed at build + time are frozen in the build. Options that are compiler + dependent (and those that are system dependent) are evaluated + each time - pngconf.h holds these. Options that can be changed + per-file in the application are in png.h. Frozen options are + in the new installed header file pnglibconf.h (John Bowler) + Removed the xcode project because it has not been updated to work + with libpng-1.5.0. + Removed the ability to include optional pngusr.h + +Version 1.5.0beta18 [April 17, 2010] + Restored the ability to include optional pngusr.h + Moved replacements for png_error() and png_warning() from the + contrib/pngminim project to pngerror.c, for use when warnings or + errors are disabled via PNG_NO_WARN or PNG_NO_ERROR_TEXT, to avoid + storing unneeded error/warning text. + Updated contrib/pngminim project to work with the new pnglibconf.h + Added some PNG_NO_* defines to contrib/pngminim/*/pngusr.h to save space. + +Version 1.5.0beta19 [April 24, 2010] + Added PNG_{READ,WRITE}_INT_FUNCTIONS_SUPPORTED. This allows the functions + to read and write ints to be disabled independently of PNG_USE_READ_MACROS, + which allows libpng to be built with the functions even though the default + is to use the macros - this allows applications to choose at app build + time whether or not to use macros (previously impossible because the + functions weren't in the default build.) + Changed Windows calling convention back to __cdecl for API functions. + For Windows/x86 platforms only: + __stdcall is no longer needed for Visual Basic, so libpng-1.5.0 uses + __cdecl throughout (both API functions and callbacks) on Windows/x86 + platforms. + Replaced visualc6 and visualc71 projects with new vstudio project + Relaxed the overly-restrictive permissions of some files. + +Version 1.5.0beta20 [April 24, 2010] + Relaxed more overly-restrictive permissions of some files. + +Version 1.5.0beta21 [April 27, 2010] + Removed some unwanted binary bytes and changed CRLF to NEWLINE in the new + vstudio project files, and some trivial editing of some files in the + scripts directory. + Set PNG_NO_READ_BGR, PNG_NO_IO_STATE, and PNG_NO_TIME_RFC1123 in + contrib/pngminim/decoder/pngusr.h to make a smaller decoder application. + +Version 1.5.0beta22 [April 28, 2010] + Fixed dependencies of GET_INT_32 - it does not require READ_INT_FUNCTIONS + because it has a macro equivalent. + Improved the options.awk script; added an "everything off" option. + Revised contrib/pngminim to use the "everything off" option in pngusr.dfa. + +Version 1.5.0beta23 [April 29, 2010] + Corrected PNG_REMOVED macro to take five arguments. + The macro was documented with two arguments (name,ordinal), however + the symbol checking .dfn files assumed five arguments. The five + argument form seems more useful so it is changed to that. + Corrected PNG_UNKNOWN_CHUNKS_SUPPORTED to PNG_HANDLE_AS_UNKNOWN_SUPPORTED + in gregbook/readpng2.c + Corrected protection of png_get_user_transform_ptr. The API declaration in + png.h is removed if both READ and WRITE USER_TRANSFORM are turned off + but was left defined in pngtrans.c + Added logunsupported=1 to cause pnglibconf.h to document disabled options. + This makes the installed pnglibconf.h more readable but causes no + other change. The intention is that users of libpng will find it + easier to understand if an API they need is missing. + Include png_reset_zstream() in png.c only when PNG_READ_SUPPORTED is defined. + Removed dummy_inflate.c from contrib/pngminim/encoder + Removed contrib/pngminim/*/gather.sh; gathering is now done in the makefile. + +Version 1.5.0beta24 [May 7, 2010] + Use bitwise "&" instead of arithmetic mod in pngrutil.c calculation of the + offset of the png_ptr->rowbuf pointer into png_ptr->big_row_buf. + Added more blank lines for readability. + +Version 1.5.0beta25 [June 18, 2010] + In pngpread.c: png_push_have_row() add check for new_row > height + Removed the now-redundant check for out-of-bounds new_row from example.c + +Version 1.5.0beta26 [June 18, 2010] + In pngpread.c: png_push_process_row() add check for too many rows. + +Version 1.5.0beta27 [June 18, 2010] + Removed the check added in beta25 as it is now redundant. + +Version 1.5.0beta28 [June 20, 2010] + Rewrote png_process_IDAT_data to consistently treat extra data as warnings + and handle end conditions more cleanly. + Removed the new (beta26) check in png_push_process_row(). + +Version 1.5.0beta29 [June 21, 2010] + Revised scripts/options.awk to work on Sunos (but still doesn't work) + Added comment to options.awk and contrib/pngminim/*/makefile to try nawk. + +Version 1.5.0beta30 [June 22, 2010] + Stop memory leak when reading a malformed sCAL chunk. + +Version 1.5.0beta31 [June 26, 2010] + Revised pngpread.c patch of beta28 to avoid an endless loop. + Removed some trailing blanks. + +Version 1.5.0beta32 [June 26, 2010] + Removed leftover scripts/options.patch and scripts/options.rej + +Version 1.5.0beta33 [July 6, 3010] + Made FIXED and FLOATING options consistent in the APIs they enable and + disable. Corrected scripts/options.awk to handle both command line + options and options specified in the .dfa files. + Changed char *msg to PNG_CONST char *msg in pngrutil.c + Make png_set_sRGB_gAMA_and_cHRM set values using either the fixed or + floating point APIs, but not both. + Reversed patch to remove error handler when the jmp_buf is stored in the + main program structure, not the png_struct. + The error handler is needed because the default handler in libpng will + always use the jmp_buf in the library control structure; this is never + set. The gregbook code is a useful example because, even though it + uses setjmp/longjmp, it shows how error handling can be implemented + using control mechanisms not directly supported by libpng. The + technique will work correctly with mechanisms such as Microsoft + Structure Exceptions or C++ exceptions (compiler willing - note that gcc + does not by default support interworking of C and C++ error handling.) + Reverted changes to call png_longjmp in contrib/gregbook where it is not + appropriate. If mainprog->jmpbuf is used by setjmp, then png_longjmp + cannot be used. + Changed "extern PNG_EXPORT" to "PNG_EXPORT" in png.h (Jan Nijtmans) + Changed "extern" to "PNG_EXTERN" in pngpriv.h (except for the 'extern "C" {') + +Version 1.5.0beta34 [July 12, 2010] + Put #ifndef PNG_EXTERN, #endif around the define PNG_EXTERN in pngpriv.h + +Version 1.5.0beta35 [July 24, 2010] + Removed some newly-added TAB characters. + Added -DNO_PNG_SNPRINTF to CFLAGS in scripts/makefile.dj2 + Moved the definition of png_snprintf() outside of the enclosing + #ifdef blocks in pngconf.h + +Version 1.5.0beta36 [July 29, 2010] + Patches by John Bowler: + Fixed point APIs are now supported throughout (no missing APIs). + Internal fixed point arithmetic support exists for all internal floating + point operations. + sCAL validates the floating point strings it is passed. + Safe, albeit rudimentary, Watcom support is provided by PNG_API_RULE==2 + Two new APIs exist to get the number of passes without turning on the + PNG_INTERLACE transform and to get the number of rows in the current + pass. + A new test program, pngvalid.c, validates the gamma code. + Errors in the 16-bit gamma correction (overflows) have been corrected. + cHRM chunk testing is done consistently (previously the floating point + API bypassed it, because the test really didn't work on FP, now the test + is performed on the actual values to be stored in the PNG file so it + works in the FP case too.) + Most floating point APIs now simply call the fixed point APIs after + converting the values to the fixed point form used in the PNG file. + The standard headers no longer include zlib.h, which is currently only + required for pngstruct.h and can therefore be internal. + Revised png_get_int_32 to undo the PNG two's complement representation of + negative numbers. + +Version 1.5.0beta37 [July 30, 2010] + Added a typecast in png_get_int_32() in png.h and pngrutil.h to avoid + a compiler warning. + Replaced oFFs 0,0 with oFFs -10,20 in pngtest.png + +Version 1.5.0beta38 [July 31, 2010] + Implemented remaining "_fixed" functions. + Corrected a number of recently introduced warnings mostly resulting from + safe but uncast assignments to shorter integers. Also added a zlib + VStudio release library project because the latest zlib Official Windows + build does not include such a thing. + Revised png_get_int_16() to be similar to png_get_int_32(). + Restored projects/visualc71. + +Version 1.5.0beta39 [August 2, 2010] + VisualC/GCC warning fixes, VisualC build fixes + The changes include support for function attributes in VC in addition to + those already present in GCC - necessary because without these some + warnings are unavoidable. Fixes include signed/unsigned fixes in + pngvalid and checks with gcc -Wall -Wextra -Wunused. + VC requires function attributes on function definitions as well as + declarations, PNG_FUNCTION has been added to enable this and the + relevant function definitions changed. + +Version 1.5.0beta40 [August 6, 2010] + Correct use of _WINDOWS_ in pngconf.h + Removed png_mem_ #defines; they are no longer used. + Added the sRGB chunk to pngtest.png + +Version 1.5.0beta41 [August 11, 2010] + Added the cHRM chunk to pngtest.png + Don't try to use version-script with cygwin/mingw. + Revised contrib/gregbook to work under cygwin/mingw. + +Version 1.5.0beta42 [August 18, 2010] + Add .dll.a to the list of extensions to be symlinked by Makefile.am (Yaakov) + Made all API functions that have const arguments and constant string + literal pointers declare them (John Bowler). + +Version 1.5.0beta43 [August 20, 2010] + Removed spurious tabs, shorten long lines (no source change) + Also added scripts/chkfmt to validate the format of all the files that can + reasonably be validated (it is suggested to run "make distclean" before + checking, because some machine generated files have long lines.) + Reformatted the CHANGES file to be more consistent throughout. + Made changes to address various issues identified by GCC, mostly + signed/unsigned and shortening problems on assignment but also a few + difficult to optimize (for GCC) loops. + Fixed non-GCC fixed point builds. In png.c a declaration was misplaced + in an earlier update. Fixed to declare the auto variables at the head. + Use cexcept.h in pngvalid.c. + +Version 1.5.0beta44 [August 24, 2010] + Updated CMakeLists.txt to use CMAKE_INSTALL_LIBDIR variable; useful for + installing libpng in /usr/lib64 (Funda Wang). + Revised CMakeLists.txt to put the man pages in share/man/man* not man/man* + Revised CMakeLists.txt to make symlinks instead of copies when installing. + Changed PNG_LIB_NAME from pngNN to libpngNN in CMakeLists.txt (Philip Lowman) + Implemented memory checks within pngvalid + Reformatted/rearranged pngvalid.c to assist use of progressive reader. + Check interlaced images in pngvalid + Clarified pngusr.h comments in pnglibconf.dfa + Simplified the pngvalid error-handling code now that cexcept.h is in place. + Implemented progressive reader in pngvalid.c for standard tests + Implemented progressive read in pngvalid.c gamma tests + Turn on progressive reader in pngvalid.c by default and tidy code. + +Version 1.5.0beta45 [August 26, 2010] + Added an explicit make step to projects/vstudio for pnglibconf.h + Also corrected zlib.vcxproj into which Visual Studio had introduced + what it calls an "authoring error". The change to make pnglibconf.h + simply copies the file; in the future it may actually generate the + file from scripts/pnglibconf.dfa as the other build systems do. + Changed pngvalid to work when floating point APIs are disabled + Renamed the prebuilt scripts/pnglibconf.h to scripts/pnglibconf.h.prebuilt + Supply default values for PNG_USER_PRIVATEBUILD and PNG_USER_DLLFNAME_POSTFIX + in pngpriv.h in case the user neglected to define them in their pngusr.h + +Version 1.5.0beta46 [August 28, 2010] + Added new private header files to libpng_sources in CMakeLists.txt + Added PNG_READ_16BIT, PNG_WRITE_16BIT, and PNG_16BIT options. + Added reference to scripts/pnglibconf.h.prebuilt in the visualc71 project. + +Version 1.5.0beta47 [September 11, 2010] + Fixed a number of problems with 64-bit compilation reported by Visual + Studio 2010 (John Bowler). + +Version 1.5.0beta48 [October 4, 2010] + Updated CMakeLists.txt (Philip Lowman). + Revised autogen.sh to recognize and use $AUTOCONF, $AUTOMAKE, $AUTOHEADER, + $AUTOPOINT, $ACLOCAL and $LIBTOOLIZE + Fixed problem with symbols creation in Makefile.am which was assuming that + all versions of ccp write to standard output by default (Martin Banky). The + bug was introduced in libpng-1.2.9beta5. + Removed unused mkinstalldirs. + +Version 1.5.0beta49 [October 8, 2010] + Undid Makefile.am revision of 1.5.0beta48. + +Version 1.5.0beta50 [October 14, 2010] + Revised Makefile.in to account for mkinstalldirs being removed. + Added some "(unsigned long)" typecasts in printf statements in pngvalid.c. + Suppressed a compiler warning in png_handle_sPLT(). + Check for out-of-range text compression mode in png_set_text(). + +Version 1.5.0beta51 [October 15, 2010] + Changed embedded dates to "(PENDING RELEASE) in beta releases (and future + rc releases) to minimize the difference between releases. + +Version 1.5.0beta52 [October 16, 2010] + Restored some of the embedded dates (in png.h, png.c, documentation, etc.) + +Version 1.5.0beta53 [October 18, 2010] + Updated INSTALL to mention using "make maintainer-clean" and to remove + obsolete statement about a custom ltmain.sh + Disabled "color-tests" by default in Makefile.am so it will work with + automake versions earlier than 1.11.1 + Use document name "libpng-manual.txt" instead of "libpng-.txt" + to simplify version differences. + Removed obsolete remarks about setjmp handling from INSTALL. + Revised and renamed the typedef in png.h and png.c that was designed + to catch library and header mismatch. + +Version 1.5.0beta54 [November 10, 2010] + Require 48 bytes, not 64 bytes, for big_row_buf in overflow checks. + Used a consistent structure for the pngget.c functions. + +Version 1.5.0beta55 [November 21, 2010] + Revised png_get_uint_32, png_get_int_32, png_get_uint_16 (Cosmin) + Moved reading of file signature into png_read_sig (Cosmin) + Fixed atomicity of chunk header serialization (Cosmin) + Added test for io_state in pngtest.c (Cosmin) + Added "#!/bin/sh" at the top of contrib/pngminim/*/gather.sh scripts. + Changes to remove gcc warnings (John Bowler) + Certain optional gcc warning flags resulted in warnings in libpng code. + With these changes only -Wconversion and -Wcast-qual cannot be turned on. + Changes are trivial rearrangements of code. -Wconversion is not possible + for pngrutil.c (because of the widespread use of += et al on variables + smaller than (int) or (unsigned int)) and -Wcast-qual is not possible + with pngwio.c and pngwutil.c because the 'write' callback and zlib + compression both fail to declare their input buffers with 'const'. + +Version 1.5.0beta56 [December 7, 2010] + Added the private PNG_UNUSED() macro definition in pngpriv.h. + Added some commentary about PNG_EXPORT in png.h and pngconf.h + Revised PNG_EXPORT() macro and added PNG_EXPORTA() macro, with the + objective of simplifying and improving the cosmetic appearance of png.h. + Fixed some incorrect "=" macro names in pnglibconf.dfa + Included documentation of changes in 1.5.0 from 1.4.x in libpng-manual.txt + +Version 1.5.0beta57 [December 9, 2010] + Documented the pngvalid gamma error summary with additional comments and + print statements. + Improved missing symbol handling in checksym.awk; symbols missing in both + the old and new files can now be optionally ignored, treated as errors + or warnings. + Removed references to pngvcrd.c and pnggccrd.c from the vstudio project. + Updated "libpng14" to "libpng15" in the visualc71 project. + Enabled the strip16 tests in pngvalid.` + Don't display test results (except PASS/FAIL) when running "make test". + Instead put them in pngtest-log.txt + Added "--with-zprefix=" to configure.ac + Updated the prebuilt configuration files to autoconf version 2.68 + +Version 1.5.0beta58 [December 19, 2010] + Fixed interlace image handling and add test cases (John Bowler) + Fixed the clean rule in Makefile.am to remove pngtest-log.txt + Made minor changes to work around warnings in gcc 3.4 + +Version 1.5.0rc01 [December 27, 2010] + No changes. + +Version 1.5.0rc02 [December 27, 2010] + Eliminated references to the scripts/*.def files in project/visualc71. + +Version 1.5.0rc03 [December 28, 2010] + Eliminated scripts/*.def and revised Makefile.am accordingly + +Version 1.5.0rc04 [December 29, 2010] + Fixed bug in background transformation handling in pngrtran.c (it was + looking for the flag in png_ptr->transformations instead of in + png_ptr->flags) (David Raymond). + +Version 1.5.0rc05 [December 31, 2010] + Fixed typo in a comment in CMakeLists.txt (libpng14 => libpng15) (Cosmin) + +Version 1.5.0rc06 [January 4, 2011] + Changed the new configure option "zprefix=string" to "zlib-prefix=string" + +Version 1.5.0rc07 [January 4, 2011] + Updated copyright year. + +Version 1.5.0 [January 6, 2011] + No changes. + +version 1.5.1beta01 [January 8, 2011] + Added description of png_set_crc_action() to the manual. + Added a note in the manual that the type of the iCCP profile was changed + from png_charpp to png_bytepp in png_get_iCCP(). This change happened + in version 1.5.0beta36 but is not noted in the CHANGES. Similarly, + it was changed from png_charpp to png_const_bytepp in png_set_iCCP(). + Ensure that png_rgb_to_gray ignores palette mapped images, if libpng + internally happens to call it with one, and fixed a failure to handle + palette mapped images correctly. This fixes CVE-2690. + +Version 1.5.1beta02 [January 14, 2011] + Fixed a bug in handling of interlaced images (bero at arklinux.org). + Updated CMakeLists.txt (Clifford Yapp) + +Version 1.5.1beta03 [January 14, 2011] + Fixed typecasting of some png_debug() statements (Cosmin) + +Version 1.5.1beta04 [January 16, 2011] + Updated documentation of png_set|get_tRNS() (Thomas Klausner). + Mentioned in the documentation that applications must #include "zlib.h" + if they need access to anything in zlib.h, and that a number of + macros such as png_memset() are no longer accessible by applications. + Corrected pngvalid gamma test "sample" function to access all of the color + samples of each pixel, instead of sampling the red channel three times. + Prefixed variable names index, div, exp, gamma with "png_" to avoid "shadow" + warnings, and (mistakenly) changed png_exp() to exp(). + +Version 1.5.1beta05 [January 16, 2011] + Changed variable names png_index, png_div, png_exp, and png_gamma to + char_index, divisor, exp_b10, and gamma_val, respectively, and + changed exp() back to png_exp(). + +Version 1.5.1beta06 [January 20, 2011] + Prevent png_push_crc_skip() from hanging while reading an unknown chunk + or an over-large compressed zTXt chunk with the progressive reader. + Eliminated more GCC "shadow" warnings. + Revised png_fixed() in png.c to avoid compiler warning about reaching the + end without returning anything. + +Version 1.5.1beta07 [January 22, 2011] + In the manual, describe the png_get_IHDR() arguments in the correct order. + Added const_png_structp and const_png_infop types, and used them in + prototypes for most png_get_*() functions. + +Version 1.5.1beta08 [January 23, 2011] + Added png_get_io_chunk_type() and deprecated png_get_io_chunk_name() + Added synopses for the IO_STATE functions and other missing synopses + to the manual. Removed the synopses from libpngpf.3 because they + were out of date and no longer useful. Better information can be + obtained by reading the prototypes and comments in pngpriv.h + Attempted to fix cpp on Solaris with S. Studio 12 cc, fix build + Added a make macro DFNCPP that is a CPP that will accept the tokens in + a .dfn file and adds configure stuff to test for such a CPP. ./configure + should fail if one is not available. + Corrected const_png_ in png.h to png_const_ to avoid polluting the namespace. + Added png_get_current_row_number and png_get_current_pass_number for the + benefit of the user transform callback. + Added png_process_data_pause and png_process_data_skip for the benefit of + progressive readers that need to stop data processing or want to optimize + skipping of unread data (e.g., if the reader marks a chunk to be skipped.) + +Version 1.5.1beta09 [January 24, 2011] + Enhanced pngvalid, corrected an error in gray_to_rgb, corrected doc error. + pngvalid contains tests of transforms, which tests are currently disabled + because they are incompletely tested. gray_to_rgb was failing to expand + the bit depth for smaller bit depth images; this seems to be a long + standing error and resulted, apparently, in invalid output + (CVE-2011-0408, CERT VU#643140). The documentation did not accurately + describe what libpng really does when converting RGB to gray. + +Version 1.5.1beta10 [January 27, 2010] + Fixed incorrect examples of callback prototypes in the manual, that were + introduced in libpng-1.0.0. + In addition the order of the png_get_uint macros with respect to the + relevant function definitions has been reversed. This helps the + preprocessing of the symbol files be more robust. Furthermore, the + symbol file preprocessing now uses -DPNG_NO_USE_READ_MACROS even when + the library may actually be built with PNG_USE_READ_MACROS; this stops + the read macros interfering with the symbol file format. + Made the manual, synopses, and function prototypes use the function + argument names file_gamma, int_file_gamma, and srgb_intent consistently. + +Version 1.5.1beta11 [January 28, 2011] + Changed PNG_UNUSED from "param=param;" to "{if(param){}}". + Corrected local variable type in new API png_process_data_skip() + The type was self-evidently incorrect but only causes problems on 64-bit + architectures. + Added transform tests to pngvalid and simplified the arguments. + +Version 1.5.1rc01 [January 29, 2011] + No changes. + +Version 1.5.1rc02 [January 31, 2011] + Added a request in the manual that applications do not use "png_" or + "PNG_" to begin any of their own symbols. + Changed PNG_UNUSED to "(void)param;" and updated the commentary in pngpriv.h + +Version 1.5.1 [February 3, 2011] + No changes. + +Version 1.5.2beta01 [February 13, 2011] + More -Wshadow fixes for older gcc compilers. Older gcc versions apparently + check formal parameters names in function declarations (as well as + definitions) to see if they match a name in the global namespace. + Revised PNG_EXPORTA macro to not use an empty parameter, to accommodate the + old VisualC++ preprocessor. + Turned on interlace handling in png_read_png(). + Fixed gcc pendantic warnings. + Handle longjmp in Cygwin. + Fixed png_get_current_row_number() in the interlaced case. + Cleaned up ALPHA flags and transformations. + Implemented expansion to 16 bits. + +Version 1.5.2beta02 [February 19, 2011] + Fixed mistake in the descriptions of user read_transform and write_transform + function prototypes in the manual. The row_info struct is png_row_infop. + Reverted png_get_current_row_number() to previous (1.5.2beta01) behavior. + Corrected png_get_current_row_number documentation + Fixed the read/write row callback documentation. + This documents the current behavior, where the callback is called after + every row with information pertaining to the next row. + +Version 1.5.2beta03 [March 3, 2011] + Fixed scripts/makefile.vcwin32 + Updated contrib/pngsuite/README to add the word "modify". + Define PNG_ALLOCATED to blank when _MSC_VER<1300. + +Version 1.5.2rc01 [March 19, 2011] + Define remaining attributes to blank when MSC_VER<1300. + ifdef out mask arrays in pngread.c when interlacing is not supported. + +Version 1.5.2rc02 [March 22, 2011] + Added a hint to try CPP=/bin/cpp if "cpp -E" fails in scripts/pnglibconf.mak + and in contrib/pngminim/*/makefile, eg., on SunOS 5.10, and removed "strip" + from the makefiles. + Fixed a bug (present since libpng-1.0.7) that makes png_handle_sPLT() fail + to compile when PNG_NO_POINTER_INDEXING is defined (Chubanov Kirill) + +Version 1.5.2rc03 [March 24, 2011] + Don't include standard header files in png.h while building the symbol table, + to avoid cpp failure on SunOS (introduced PNG_BUILDING_SYMBOL_TABLE macro). + +Version 1.5.2 [March 31, 2011] + No changes. + +Version 1.5.3beta01 [April 1, 2011] + Re-initialize the zlib compressor before compressing non-IDAT chunks. + Added API functions (png_set_text_compression_level() and four others) to + set parameters for zlib compression of non-IDAT chunks. + +Version 1.5.3beta02 [April 3, 2011] + Updated scripts/symbols.def with new API functions. + Only compile the new zlib re-initializing code when text or iCCP is + supported, using PNG_WRITE_COMPRESSED_TEXT_SUPPORTED macro. + Improved the optimization of the zlib CMF byte (see libpng-1.2.6beta03). + Optimize the zlib CMF byte in non-IDAT compressed chunks + +Version 1.5.3beta03 [April 16, 2011] + Fixed gcc -ansi -pedantic compile. A strict ANSI system does not have + snprintf, and the "__STRICT_ANSI__" detects that condition more reliably + than __STDC__ (John Bowler). + Removed the PNG_PTR_NORETURN attribute because it too dangerous. It tells + the compiler that a user supplied callback (the error handler) does not + return, yet there is no guarantee in practice that the application code + will correctly implement the error handler because the compiler only + issues a warning if there is a mistake (John Bowler). + Removed the no-longer-used PNG_DEPSTRUCT macro. + Updated the zlib version to 1.2.5 in the VStudio project. + Fixed 64-bit builds where png_uint_32 is smaller than png_size_t in + pngwutil.c (John Bowler). + Fixed bug with stripping the filler or alpha channel when writing, that + was introduced in libpng-1.5.2beta01 (bug report by Andrew Church). + +Version 1.5.3beta04 [April 27, 2011] + Updated pngtest.png with the new zlib CMF optimization. + Cleaned up conditional compilation code and of background/gamma handling + Internal changes only except a new option to avoid compiling the + png_build_grayscale_palette API (which is not used at all internally.) + The main change is to move the transform tests (READ_TRANSFORMS, + WRITE_TRANSFORMS) up one level to the caller of the APIs. This avoids + calls to spurious functions if all transforms are disabled and slightly + simplifies those functions. Pngvalid modified to handle this. + A minor change is to stop the strip_16 and expand_16 interfaces from + disabling each other; this allows the future alpha premultiplication + code to use 16-bit intermediate values while still producing 8-bit output. + png_do_background and png_do_gamma have been simplified to take a single + pointer to the png_struct rather than pointers to every item required + from the png_struct. This makes no practical difference to the internal + code. + A serious bug in the pngvalid internal routine 'standard_display_init' has + been fixed - this failed to initialize the red channel and accidentally + initialized the alpha channel twice. + Changed png_struct jmp_buf member name from png_jmpbuf to tmp_jmpbuf to + avoid a possible clash with the png_jmpbuf macro on some platforms. + +Version 1.5.3beta05 [May 6, 2011] + Added the "_POSIX_SOURCE" feature test macro to ensure libpng sees the + correct API. _POSIX_SOURCE is defined in pngpriv.h, pngtest.c and + pngvalid.c to ensure that POSIX conformant systems disable non-POSIX APIs. + Removed png_snprintf and added formatted warning messages. This change adds + internal APIs to allow png_warning messages to have parameters without + requiring the host OS to implement snprintf. As a side effect the + dependency of the tIME-supporting RFC1132 code on stdio is removed and + PNG_NO_WARNINGS does actually work now. + Pass "" instead of '\0' to png_default_error() in png_err(). This mistake + was introduced in libpng-1.2.20beta01. This fixes CVE-2011-2691. + Added PNG_WRITE_OPTIMIZE_CMF_SUPPORTED macro to make the zlib "CMF" byte + optimization configureable. + IDAT compression failed if preceded by a compressed text chunk (bug + introduced in libpng-1.5.3beta01-02). This was because the attempt to + reset the zlib stream in png_write_IDAT happened after the first IDAT + chunk had been deflated - much too late. In this change internal + functions were added to claim/release the z_stream and, hopefully, make + the code more robust. Also deflateEnd checking is added - previously + libpng would ignore an error at the end of the stream. + +Version 1.5.3beta06 [May 8, 2011] + Removed the -D_ALL_SOURCE from definitions for AIX in CMakeLists.txt + Implemented premultiplied alpha support: png_set_alpha_mode API + +Version 1.5.3beta07 [May 11, 2011] + Added expand_16 support to the high level interface. + Added named value and 'flag' gamma support to png_set_gamma. Made a minor + change from the previous (unreleased) ABI/API to hide the exact value used + for Macs - it's not a good idea to embed this in the ABI! + Moved macro definitions for PNG_HAVE_IHDR, PNG_HAVE_PLTE, and PNG_AFTER_IDAT + from pngpriv.h to png.h because they must be visible to applications + that call png_set_unknown_chunks(). + Check for up->location !PNG_AFTER_IDAT when writing unknown chunks + before IDAT. + +Version 1.5.3beta08 [May 16, 2011] + Improved "pngvalid --speed" to exclude more of pngvalid from the time. + Documented png_set_alpha_mode(), other changes in libpng.3/libpng-manual.txt + The cHRM chunk now sets the defaults for png_set_rgb_to_gray() (when negative + parameters are supplied by the caller), while in the absence of cHRM + sRGB/Rec 709 values are still used. This introduced a divide-by-zero + bug in png_handle_cHRM(). + The bKGD chunk no longer overwrites the background value set by + png_set_background(), allowing the latter to be used before the file + header is read. It never performed any useful function to override + the default anyway. + Added memory overwrite and palette image checks to pngvalid.c + Previously palette image code was poorly checked. Since the transformation + code has a special palette path in most cases this was a severe weakness. + Minor cleanup and some extra checking in pngrutil.c and pngrtran.c. When + expanding an indexed image, always expand to RGBA if transparency is + present. + +Version 1.5.3beta09 [May 17, 2011] + Reversed earlier 1.5.3 change of transformation order; move png_expand_16 + back where it was. The change doesn't work because it requires 16-bit + gamma tables when the code only generates 8-bit ones. This fails + silently; the libpng code just doesn't do any gamma correction. Moving + the tests back leaves the old, inaccurate, 8-bit gamma calculations, but + these are clearly better than none! + +Version 1.5.3beta10 [May 20, 2011] + + png_set_background() and png_expand_16() did not work together correctly. + This problem is present in 1.5.2; if png_set_background is called with + need_expand false and the matching 16 bit color libpng erroneously just + treats it as an 8-bit color because of where png_do_expand_16 is in the + transform list. This simple fix reduces the supplied colour to 8-bits, + so it gets smashed, but this is better than the current behavior. + Added tests for expand16, more fixes for palette image tests to pngvalid. + Corrects the code for palette image tests and disables attempts to + validate palette colors. + +Version 1.5.3rc01 [June 3, 2011] + No changes. + +Version 1.5.3rc02 [June 8, 2011] + Fixed uninitialized memory read in png_format_buffer() (Bug report by + Frank Busse, CVE-2011-2501, related to CVE-2004-0421). + +Version 1.5.3beta11 [June 11, 2011] + Fixed png_handle_sCAL which is broken in 1.5. This fixes CVE 2011-2692. + Added sCAL to pngtest.png + Revised documentation about png_set_user_limits() to say that it also affects + png writing. + Revised handling of png_set_user_limits() so that it can increase the + limit beyond the PNG_USER_WIDTH|HEIGHT_MAX; previously it could only + reduce it. + Make the 16-to-8 scaling accurate. Dividing by 256 with no rounding is + wrong (high by one) 25% of the time. Dividing by 257 with rounding is + wrong in 128 out of 65536 cases. Getting the right answer all the time + without division is easy. + Added "_SUPPORTED" to the PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION macro. + Added projects/owatcom, an IDE project for OpenWatcom to replace + scripts/makefile.watcom. This project works with OpenWatcom 1.9. The + IDE autogenerates appropriate makefiles (libpng.mk) for batch processing. + The project is configurable, unlike the Visual Studio project, so long + as the developer has an awk. + Changed png_set_gAMA to limit the gamma value range so that the inverse + of the stored value cannot overflow the fixed point representation, + and changed other things OpenWatcom warns about. + Revised pngvalid.c to test PNG_ALPHA_MODE_SUPPORTED correctly. This allows + pngvalid to build when ALPHA_MODE is not supported, which is required if + it is to build on libpng 1.4. + Removed string/memory macros that are no longer used and are not + necessarily fully supportable, particularly png_strncpy and png_snprintf. + Added log option to pngvalid.c and attempted to improve gamma messages. + +Version 1.5.3 [omitted] + People found the presence of a beta release following an rc release + to be confusing; therefore we bump the version to libpng-1.5.4beta01 + and there will be no libpng-1.5.3 release. + +Version 1.5.4beta01 [June 14, 2011] + Made it possible to undefine PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED + to get the same (inaccurate) output as libpng-1.5.2 and earlier. + Moved definitions of PNG_HAVE_IHDR, PNG_AFTER_IDAT, and PNG_HAVE_PLTE + outside of an unknown-chunk block in png.h because they are also + needed for other uses. + +Version 1.5.4beta02 [June 14, 2011] + Fixed and clarified LEGACY 16-to-8 scaling code. + Added png_set_chop_16() API, to match inaccurate results from previous + libpng versions. + Removed the ACCURATE and LEGACY options (they are no longer useable) + Use the old scaling method for background if png_set_chop_16() was + called. + Made png_set_chop_16() API removeable by disabling PNG_CHOP_16_TO_8_SUPPORTED + +Version 1.5.4beta03 [June 15, 2011] + Fixed a problem in png_do_expand_palette() exposed by optimization in + 1.5.3beta06 + Also removed a spurious and confusing "trans" member ("trans") from png_info. + The palette expand optimization prevented expansion to an intermediate RGBA + form if tRNS was present but alpha was marked to be stripped; this exposed + a check for tRNS in png_do_expand_palette() which is inconsistent with the + code elsewhere in libpng. + Correction to the expand_16 code; removed extra instance of + png_set_scale_16_to_8 from pngpriv.h + +Version 1.5.4beta04 [June 16, 2011] + Added a missing "#ifdef PNG_READ_BACKGROUND_SUPPORTED/#endif" in pngrtran.c + Added PNG_TRANSFORM_CHOP_16 to the high-level read transforms. + Made PNG_READ_16_TO_8_ACCURATE_SCALE configurable again. If this is + not enabled, png_set_strip_16() and png_do_scale_16_to_8() aren't built. + Revised contrib/visupng, gregbook, and pngminim to demonstrate chop_16_to_8 + +Version 1.5.4beta05 [June 16, 2011] + Renamed png_set_strip_16() to png_set_scale_16() and renamed + png_set_chop_16() to png_set_strip(16) in an attempt to minimize the + behavior changes between libpng14 and libpng15. + +Version 1.5.4beta06 [June 18, 2011] + Fixed new bug that was causing both strip_16 and scale_16 to be applied. + +Version 1.5.4beta07 [June 19, 2011] + Fixed pngvalid, simplified macros, added checking for 0 in sCAL. + The ACCURATE scale macro is no longer defined in 1.5 - call the + png_scale_16_to_8 API. Made sure that PNG_READ_16_TO_8 is still defined + if the png_strip_16_to_8 API is present. png_check_fp_number now + maintains some state so that positive, negative and zero values are + identified. sCAL uses these to be strictly spec conformant. + +Version 1.5.4beta08 [June 23, 2011] + Fixed pngvalid if ACCURATE_SCALE is defined. + Updated scripts/pnglibconf.h.prebuilt. + +Version 1.5.4rc01 [June 30, 2011] + Define PNG_ALLOCATED to "restrict" only if MSC_VER >= 1400. + +Version 1.5.4 [July 7, 2011] + No changes. + +Version 1.5.5beta01 [July 13, 2011] + Fixed some typos and made other minor changes in the manual. + Updated contrib/pngminus/makefile.std (Samuli Souminen) + +Version 1.5.5beta02 [July 14, 2011] + Revised Makefile.am and Makefile.in to look in the right directory for + pnglibconf.h.prebuilt + +Version 1.5.5beta03 [July 27, 2011] + Enabled compilation with g++ compiler. This compiler does not recognize + the file extension, so it always compiles with C++ rules. Made minor + changes to pngrutil.c to cast results where C++ expects it but C does not. + Minor editing of libpng.3 and libpng-manual.txt. + +Version 1.5.5beta04 [July 29, 2011] + Revised CMakeLists.txt (Clifford Yapp) + Updated commentary about the png_rgb_to_gray() default coefficients + in the manual and in pngrtran.c + +Version 1.5.5beta05 [August 17, 2011] + Prevent unexpected API exports from non-libpng DLLs on Windows. The "_DLL" + is removed from the test of whether a DLL is being built (this erroneously + caused the libpng APIs to be marked as DLL exports in static builds under + Microsoft Visual Studio). Almost all of the libpng building configuration + is moved from pngconf.h to pngpriv.h, but PNG_DLL_EXPORT remains in + pngconf.h, though, so that it is colocated with the import definition (it + is no longer used anywhere in the installed headers). The VStudio project + definitions have been cleaned up: "_USRDLL" has been removed from the + static library builds (this was incorrect), and PNG_USE_DLL has been added + to pngvalid to test the functionality (pngtest does not supply it, + deliberately). The spurious "_EXPORTS" has been removed from the + libpng build (all these errors were a result of copy/paste between project + configurations.) + Added new types and internal functions for CIE RGB end point handling to + pngpriv.h (functions yet to be implemented). + +Version 1.5.5beta06 [August 26, 2011] + Ensure the CMAKE_LIBRARY_OUTPUT_DIRECTORY is set in CMakeLists.txt + (Clifford Yap) + Fixes to rgb_to_gray and cHRM XYZ APIs (John Bowler): + The rgb_to_gray code had errors when combined with gamma correction. + Some pixels were treated as true grey when they weren't and such pixels + and true grey ones were not gamma corrected (the original value of the + red component was used instead). APIs to get and set cHRM using color + space end points have been added and the rgb_to_gray code that defaults + based on cHRM, and the divide-by-zero bug in png_handle_cHRM (CERT + VU#477046, CVE-2011-3328, introduced in 1.5.4) have been corrected. + A considerable number of tests has been added to pngvalid for the + rgb_to_gray transform. + Arithmetic errors in rgb_to_gray whereby the calculated gray value was + truncated to the bit depth rather than rounded have been fixed except in + the 8-bit non-gamma-corrected case (where consistency seems more important + than correctness.) The code still has considerable inaccuracies in the + 8-bit case because 8-bit linear arithmetic is used. + +Version 1.5.5beta07 [September 7, 2011] + Added "$(ARCH)" option to makefile.darwin + Added SunOS support to configure.ac and Makefile.am + Changed png_chunk_benign_error() to png_warning() in png.c, in + png_XYZ_from_xy_checked(). + +Version 1.5.5beta08 [September 10, 2011] + Fixed 64-bit compilation errors (gcc). The errors fixed relate + to conditions where types that are 32 bits in the GCC 32-bit + world (uLong and png_size_t) become 64 bits in the 64-bit + world. This produces potential truncation errors which the + compiler correctly flags. + Relocated new HAVE_SOLARIS_LD definition in configure.ac + Constant changes for 64-bit compatibility (removal of L suffixes). The + 16-bit cases still use "L" as we don't have a 16-bit test system. + +Version 1.5.5rc01 [September 15, 2011] + Removed "L" suffixes in pngpriv.h + +Version 1.5.5 [September 22, 2011] + No changes. + +Version 1.5.6beta01 [September 22, 2011] + Fixed some 64-bit type conversion warnings in pngrtran.c + Moved row_info from png_struct to a local variable. + The various interlace mask arrays have been made into arrays of + bytes and made PNG_CONST and static (previously some arrays were + marked PNG_CONST and some weren't). + Additional checks have been added to the transform code to validate the + pixel depths after the transforms on both read and write. + Removed some redundant code from pngwrite.c, in png_destroy_write_struct(). + Changed chunk reading/writing code to use png_uint_32 instead of png_byte[4]. + This removes the need to allocate temporary strings for chunk names on + the stack in the read/write code. Unknown chunk handling still uses the + string form because this is exposed in the API. + +Version 1.5.6beta02 [September 26, 2011] + Added a note in the manual the png_read_update_info() must be called only + once with a particular info_ptr. + Fixed a typo in the definition of the new PNG_STRING_FROM_CHUNK(s,c) macro. + +Version 1.5.6beta03 [September 28, 2011] + Revised test-pngtest.sh to report FAIL when pngtest fails. + Added "--strict" option to pngtest, to report FAIL when the failure is + only because the resulting valid files are different. + Revised CMakeLists.txt to work with mingw and removed some material from + CMakeLists.txt that is no longer useful in libpng-1.5. + +Version 1.5.6beta04 [October 5, 2011] + Fixed typo in Makefile.in and Makefile.am ("-M Wl" should be "-M -Wl")." + +Version 1.5.6beta05 [October 12, 2011] + Speed up png_combine_row() for interlaced images. This reduces the generality + of the code, allowing it to be optimized for Adam7 interlace. The masks + passed to png_combine_row() are now generated internally, avoiding + some code duplication and localizing the interlace handling somewhat. + Align png_struct::row_buf - previously it was always unaligned, caused by + a bug in the code that attempted to align it; the code needs to subtract + one from the pointer to take account of the filter byte prepended to + each row. + Optimized png_combine_row() when rows are aligned. This gains a small + percentage for 16-bit and 32-bit pixels in the typical case where the + output row buffers are appropriately aligned. The optimization was not + previously possible because the png_struct buffer was always misaligned. + Fixed bug in png_write_chunk_header() debug print, introduced in 1.5.6beta01. + +Version 1.5.6beta06 [October 17, 2011] + Removed two redundant tests for unitialized row. + Fixed a relatively harmless memory overwrite in compressed text writing + with a 1 byte zlib buffer. + Add ability to call png_read_update_info multiple times to pngvalid.c. + Fixes for multiple calls to png_read_update_info. These fixes attend to + most of the errors revealed in pngvalid, however doing the gamma work + twice results in inaccuracies that can't be easily fixed. There is now + a warning in the code if this is going to happen. + Turned on multiple png_read_update_info in pngvalid transform tests. + Prevent libpng from overwriting unused bits at the end of the image when + it is not byte aligned, while reading. Prior to libpng-1.5.6 libpng would + overwrite the partial byte at the end of each row if the row width was not + an exact multiple of 8 bits and the image is not interlaced. + +Version 1.5.6beta07 [October 21, 2011] + Made png_ptr->prev_row an aligned pointer into png_ptr->big_prev_row + (Mans Rullgard). + +Version 1.5.6rc01 [October 26, 2011] + Changed misleading "Missing PLTE before cHRM" warning to "Out of place cHRM" + +Version 1.5.6rc02 [October 27, 2011] + Added LSR() macro to defend against buggy compilers that evaluate non-taken + code branches and complain about out-of-range shifts. + +Version 1.5.6rc03 [October 28, 2011] + Renamed the LSR() macro to PNG_LSR() and added PNG_LSL() macro. + Fixed compiler warnings with Intel and MSYS compilers. The logical shift + fix for Microsoft Visual C is required by other compilers, so this + enables that fix for all compilers when using compile-time constants. + Under MSYS 'byte' is a name declared in a system header file, so we + changed the name of a local variable to avoid the warnings that result. + Added #define PNG_ALIGN_TYPE PNG_ALIGN_NONE to contrib/pngminim/*/pngusr.h + +Version 1.5.6 [November 3, 2011] + No changes. + +Version 1.5.7beta01 [November 4, 2011] + Added support for ARM processor, when decoding all PNG up-filtered rows + and any other-filtered rows with 3 or 4 bytes per pixel (Mans Rullgard). + Fixed bug in pngvalid on early allocation failure; fixed type cast in + pngmem.c; pngvalid would attempt to call png_error() if the allocation + of a png_struct or png_info failed. This would probably have led to a + crash. The pngmem.c implementation of png_malloc() included a cast + to png_size_t which would fail on large allocations on 16-bit systems. + Fix for the preprocessor of the Intel C compiler. The preprocessor + splits adjacent @ signs with a space; this changes the concatentation + token from @-@-@ to PNG_JOIN; that should work with all compiler + preprocessors. + Paeth filter speed improvements from work by Siarhei Siamashka. This + changes the 'Paeth' reconstruction function to improve the GCC code + generation on x86. The changes are only part of the suggested ones; + just the changes that definitely improve speed and remain simple. + The changes also slightly increase the clarity of the code. + +Version 1.5.7beta02 [November 11, 2011] + Check compression_type parameter in png_get_iCCP and remove spurious + casts. The compression_type parameter is always assigned to, so must + be non-NULL. The cast of the profile length potentially truncated the + value unnecessarily on a 16-bit int system, so the cast of the (byte) + compression type to (int) is specified by ANSI-C anyway. + Fixed FP division by zero in pngvalid.c; the 'test_pixel' code left + the sBIT fields in the test pixel as 0, which resulted in a floating + point division by zero which was irrelevant but causes systems where + FP exceptions cause a crash. Added code to pngvalid to turn on FP + exceptions if the appropriate glibc support is there to ensure this is + tested in the future. + Updated scripts/pnglibconf.mak and scripts/makefile.std to handle the + new PNG_JOIN macro. + Added versioning to pnglibconf.h comments. + Simplified read/write API initial version; basic read/write tested on + a variety of images, limited documentation (in the header file.) + Installed more accurate linear to sRGB conversion tables. The slightly + modified tables reduce the number of 16-bit values that + convert to an off-by-one 8-bit value. The "makesRGB.c" code that was used + to generate the tables is now in a contrib/sRGBtables sub-directory. + +Version 1.5.7beta03 [November 17, 2011] + Removed PNG_CONST from the sRGB table declarations in pngpriv.h and png.c + Added run-time detection of NEON support. + Added contrib/libtests; includes simplified API test and timing test and + a color conversion utility for rapid checking of failed 'pngstest' results. + Multiple transform bug fixes plus a work-round for double gamma correction. + libpng does not support more than one transform that requires linear data + at once - if this is tried typically the results is double gamma + correction. Since the simplified APIs can need rgb to gray combined with + a compose operation it is necessary to do one of these outside the main + libpng transform code. This check-in also contains fixes to various bugs + in the simplified APIs themselves and to some bugs in compose and rgb to + gray (on palette) itself. + Fixes for C++ compilation using g++ When libpng source is compiled + using g++. The compiler imposes C++ rules on the C source; thus it + is desireable to make the source work with either C or C++ rules + without throwing away useful error information. This change adds + png_voidcast to allow C semantic (void*) cases or the corresponding + C++ static_cast operation, as appropriate. + Added --noexecstack to assembler file compilation. GCC does not set + this on assembler compilation, even though it does on C compilation. + This creates security issues if assembler code is enabled; the + work-around is to set it by default in the flags for $(CCAS) + Work around compilers that don't support declaration of const data. Some + compilers fault 'extern const' data declarations (because the data is + not initialized); this turns on const-ness only for compilers where + this is known to work. + +Version 1.5.7beta04 [November 17, 2011] + Since the gcc driver does not recognize the --noexecstack flag, we must + use the -Wa prefix to have it passed through to the assembler. + Also removed a duplicate setting of this flag. + Added files that were omitted from the libpng-1.5.7beta03 zip distribution. + +Version 1.5.7beta05 [November 25, 2011] + Removed "zTXt" from warning in generic chunk decompression function. + Validate time settings passed to png_set_tIME() and png_convert_to_rfc1123() + (Frank Busse). Note: This prevented CVE-2015-7981 from affecting + libpng-1.5.7 and later. + Added MINGW support to CMakeLists.txt + Reject invalid compression flag or method when reading the iTXt chunk. + Backed out 'simplified' API changes. The API seems too complex and there + is a lack of consensus or enthusiasm for the proposals. The API also + reveals significant bugs inside libpng (double gamma correction and the + known bug of being unable to retrieve a corrected palette). It seems + better to wait until the bugs, at least, are corrected. + Moved pngvalid.c into contrib/libtests + Rebuilt Makefile.in, configure, etc., with autoconf-2.68 + +Version 1.5.7rc01 [December 1, 2011] + Replaced an "#if" with "#ifdef" in pngrtran.c + Revised #if PNG_DO_BC block in png.c (use #ifdef and add #else) + +Version 1.5.7rc02 [December 5, 2011] + Revised project files and contrib/pngvalid/pngvalid.c to account for + the relocation of pngvalid into contrib/libtests. + Revised pngconf.h to use " __declspec(restrict)" only when MSC_VER >= 1400, + as in libpng-1.5.4. + Put CRLF line endings in the owatcom project files. + +Version 1.5.7rc03 [December 7, 2011] + Updated CMakeLists.txt to account for the relocation of pngvalid.c + +Version 1.5.7 [December 15, 2011] + Minor fixes to pngvalid.c for gcc 4.6.2 compatibility to remove warnings + reported by earlier versions. + Fixed minor memset/sizeof errors in pngvalid.c. + +Version 1.6.0beta01 [December 15, 2011] + Removed machine-generated configure files from the GIT repository (they will + continue to appear in the tarball distributions and in the libpng15 and + earlier GIT branches). + Restored the new 'simplified' API, which was started in libpng-1.5.7beta02 + but later deleted from libpng-1.5.7beta05. + Added example programs for the new 'simplified' API. + Added ANSI-C (C90) headers and require them, and take advantage of the + change. Also fixed some of the projects/* and contrib/* files that needed + updates for libpng16 and the move of pngvalid.c. + With this change the required ANSI-C header files are assumed to exist: the + implementation must provide float.h, limits.h, stdarg.h and stddef.h and + libpng relies on limits.h and stddef.h existing and behaving as defined + (the other two required headers aren't used). Non-ANSI systems that don't + have stddef.h or limits.h will have to provide an appropriate fake + containing the relevant types and #defines. + Dropped support for 16-bit platforms. The use of FAR/far has been eliminated + and the definition of png_alloc_size_t is now controlled by a flag so + that 'small size_t' systems can select it if necessary. Libpng 1.6 may + not currently work on such systems -- it seems likely that it will + ask 'malloc' for more than 65535 bytes with any image that has a + sufficiently large row size (rather than simply failing to read such + images). + New tools directory containing tools used to generate libpng code. + Fixed race conditions in parallel make builds. With higher degrees of + parallelism during 'make' the use of the same temporary file names such + as 'dfn*' can result in a race where a temporary file from one arm of the + build is deleted or overwritten in another arm. This changes the + temporary files for suffix rules to always use $* and ensures that the + non-suffix rules use unique file names. + +Version 1.6.0beta02 [December 21, 2011] + Correct configure builds where build and source directories are separate. + The include path of 'config.h' was erroneously made relative in pngvalid.c + in libpng 1.5.7. + +Version 1.6.0beta03 [December 22, 2011] + Start-up code size improvements, error handler flexibility. These changes + alter how the tricky allocation of the initial png_struct and png_info + structures are handled. png_info is now handled in pretty much the same + way as everything else, except that the allocations handle NULL return + silently. png_struct is changed in a similar way on allocation and on + deallocation a 'safety' error handler is put in place (which should never + be required). The error handler itself is changed to permit mismatches + in the application and libpng error buffer size; however, this means a + silent change to the API to return the jmp_buf if the size doesn't match + the size from the libpng compilation; libpng now allocates the memory and + this may fail. Overall these changes result in slight code size + reductions; however, this is a reduction in code that is always executed + so is particularly valuable. Overall on a 64-bit system the libpng DLL + decreases in code size by 1733 bytes. pngerror.o increases in size by + about 465 bytes because of the new functionality. + Added png_convert_to_rfc1123_buffer() and deprecated png_convert_to_rfc1123() + to avoid including a spurious buffer in the png_struct. + +Version 1.6.0beta04 [December 30, 2011] + Regenerated configure scripts with automake-1.11.2 + Eliminated png_info_destroy(). It is now used only in png.c and only calls + one other internal function and memset(). + Enabled png_get_sCAL_fixed() if floating point APIs are enabled. Previously + it was disabled whenever internal fixed point arithmetic was selected, + which meant it didn't exist even on systems where FP was available but not + preferred. + Added pngvalid.c compile time checks for const APIs. + Implemented 'restrict' for png_info and png_struct. Because of the way + libpng works both png_info and png_struct are always accessed via a + single pointer. This means adding C99 'restrict' to the pointer gives + the compiler some opportunity to optimize the code. This change allows + that. + Moved AC_MSG_CHECKING([if libraries can be versioned]) later to the proper + location in configure.ac (Gilles Espinasse). + Changed png_memcpy to C assignment where appropriate. Changed all those + uses of png_memcpy that were doing a simple assignment to assignments + (all those cases where the thing being copied is a non-array C L-value). + Added some error checking to png_set_*() routines. + Removed the reference to the non-exported function png_memcpy() from + example.c. + Fixed the Visual C 64-bit build - it requires jmp_buf to be aligned, but + it had become misaligned. + Revised contrib/pngminus/pnm2png.c to avoid warnings when png_uint_32 + and unsigned long are of different sizes. + +Version 1.6.0beta05 [January 15, 2012] + Updated manual with description of the simplified API (copied from png.h) + Fix bug in pngerror.c: some long warnings were being improperly truncated + (CVE-2011-3464, bug introduced in libpng-1.5.3beta05). + +Version 1.6.0beta06 [January 24, 2012] + Added palette support to the simplified APIs. This commit + changes some of the macro definitions in png.h, app code + may need corresponding changes. + Increased the formatted warning buffer to 192 bytes. + Added color-map support to simplified API. This is an initial version for + review; the documentation has not yet been updated. + Fixed Min/GW uninstall to remove libpng.dll.a + +Version 1.6.0beta07 [January 28, 2012] + Eliminated Intel icc/icl compiler warnings. The Intel (GCC derived) + compiler issues slightly different warnings from those issued by the + current vesions of GCC. This eliminates those warnings by + adding/removing casts and small code rewrites. + Updated configure.ac from autoupdate: added --enable-werror option. + Also some layout regularization and removal of introduced tab characters + (replaced with 3-character indentation). Obsolete macros identified by + autoupdate have been removed; the replacements are all in 2.59 so + the pre-req hasn't been changed. --enable-werror checks for support + for -Werror (or the given argument) in the compiler. This mimics the + gcc configure option by allowing -Werror to be turned on safely; without + the option the tests written in configure itself fail compilation because + they cause compiler warnings. + Rewrote autogen.sh to run autoreconf instead of running tools one-by-one. + Conditionalize the install rules for MINGW and CYGWIN in CMakeLists.txt and + set CMAKE_LIBRARY_OUTPUT_DIRECTORY to "lib" on all platforms (C. Yapp). + Freeze libtool files in the 'scripts' directory. This version of autogen.sh + attempts to dissuade people from running it when it is not, or should not, + be necessary. In fact, autogen.sh does not work when run in a libpng + directory extracted from a tar distribution anymore. You must run it in + a GIT clone instead. + Added two images to contrib/pngsuite (1-bit and 2-bit transparent grayscale), + and renamed three whose names were inconsistent with those in + pngsuite/README.txt. + +Version 1.6.0beta08 [February 1, 2012] + Fixed Image::colormap misalignment in pngstest.c + Check libtool/libtoolize version number (2.4.2) in configure.ac + Divide test-pngstest.sh into separate pngstest runs for basic and + transparent images. + Moved automake options to AM_INIT_AUTOMAKE in configure.ac + Added color-tests, silent-rules (Not yet implemented in Makefile.am) and + version checking to configure.ac + Improved pngstest speed by not doing redundant tests and add const to + the background parameter of png_image_finish_read. The --background + option is now done automagically only when required, so that commandline + option no longer exists. + Cleaned up pngpriv.h to consistently declare all functions and data. + Also eliminated PNG_CONST_DATA, which is apparently not needed but we + can't be sure until it is gone. + Added symbol prefixing that allows all the libpng external symbols + to be prefixed (suggested by Reuben Hawkins). + Updated "ftbb*.png" list in the owatcom and vstudio projects. + Fixed 'prefix' builds on clean systems. The generation of pngprefix.h + should not require itself. + Updated INSTALL to explain that autogen.sh must be run in a GIT clone, + not in a libpng directory extracted from a tar distribution. + +Version 1.6.0beta09 [February 1, 2012] + Reverted the prebuilt configure files to libpng-1.6.0beta05 condition. + +Version 1.6.0beta10 [February 3, 2012] + Added Z_SOLO for zlib-1.2.6+ and correct pngstest tests + Updated list of test images in CMakeLists.txt + Updated the prebuilt configure files to current condition. + Revised INSTALL information about autogen.sh; it works in tar distributions. + +Version 1.6.0beta11 [February 16, 2012] + Fix character count in pngstest command in projects/owatcom/pngstest.tgt + Revised test-pngstest.sh to report PASS/FAIL for each image. + Updated documentation about the simplified API. + Corrected estimate of error in libpng png_set_rgb_to_gray API. The API is + extremely inaccurate for sRGB conversions because it uses an 8-bit + intermediate linear value and it does not use the sRGB transform, so it + suffers from the known instability in gamma transforms for values close + to 0 (see Poynton). The net result is that the calculation has a maximum + error of 14.99/255; 0.5/255^(1/2.2). pngstest now uses 15 for the + permitted 8-bit error. This may still not be enough because of arithmetic + error. + Removed some unused arrays (with #ifdef) from png_read_push_finish_row(). + Fixed a memory overwrite bug in simplified read of RGB PNG with + non-linear gamma Also bugs in the error checking in pngread.c and changed + quite a lot of the checks in pngstest.c to be correct; either correctly + written or not over-optimistic. The pngstest changes are insufficient to + allow all possible RGB transforms to be passed; pngstest cmppixel needs + to be rewritten to make it clearer which errors it allows and then changed + to permit known inaccuracies. + Removed tests for no-longer-used *_EMPTY_PLTE_SUPPORTED from pngstruct.h + Fixed fixed/float API export conditionals. 1) If FIXED_POINT or + FLOATING_POINT options were switched off, png.h ended up with lone ';' + characters. This is not valid ANSI-C outside a function. The ';' + characters have been moved inside the definition of PNG_FP_EXPORT and + PNG_FIXED_EXPORT. 2) If either option was switched off, the declaration + of the corresponding functions were completely omitted, even though some + of them are still used internally. The result is still valid, but + produces warnings from gcc with some warning options (including -Wall). The + fix is to cause png.h to declare the functions with PNG_INTERNAL_FUNCTION + when png.h is included from pngpriv.h. + Check for invalid palette index while reading paletted PNG. When one is + found, issue a warning and increase png_ptr->num_palette accordingly. + Apps are responsible for checking to see if that happened. + +Version 1.6.0beta12 [February 18, 2012] + Do not increase num_palette on invalid_index. + Relocated check for invalid palette index to pngrtran.c, after unpacking + the sub-8-bit pixels. + Fixed CVE-2011-3026 buffer overrun bug. This bug was introduced when + iCCP chunk support was added at libpng-1.0.6. Deal more correctly with the + test on iCCP chunk length. Also removed spurious casts that may hide + problems on 16-bit systems. + +Version 1.6.0beta13 [February 24, 2012] + Eliminated redundant png_push_read_tEXt|zTXt|iTXt|unknown code from + pngpread.c and use the sequential png_handle_tEXt, etc., in pngrutil.c; + now that png_ptr->buffer is inaccessible to applications, the special + handling is no longer useful. + Added PNG_SAFE_LIMITS feature to pnglibconf.dfa, pngpriv.h, and new + pngusr.dfa to reset the user limits to safe ones if PNG_SAFE_LIMITS is + defined. To enable, use "CPPFLAGS=-DPNG_SAFE_LIMITS_SUPPORTED=1" on the + configure command or put #define PNG_SAFE_LIMITS_SUPPORTED in + pnglibconf.h.prebuilt and pnglibconf.h. + +Version 1.6.0beta14 [February 27, 2012] + Added information about the new limits in the manual. + Updated Makefile.in + +Version 1.6.0beta15 [March 2, 2012] + Removed unused "current_text" members of png_struct and the png_free() + of png_ptr->current_text from pngread.c + Rewrote pngstest.c for substantial speed improvement. + Fixed transparent pixel and 16-bit rgb tests in pngstest and removed a + spurious check in pngwrite.c + Added PNG_IMAGE_FLAG_FAST for the benefit of applications that store + intermediate files, or intermediate in-memory data, while processing + image data with the simplified API. The option makes the files larger + but faster to write and read. pngstest now uses this by default; this + can be disabled with the --slow option. + Improved pngstest fine tuning of error numbers, new test file generator. + The generator generates images that test the full range of sample values, + allow the error numbers in pngstest to be tuned and checked. makepng + also allows generation of images with extra chunks, although this is + still work-in-progress. + Added check for invalid palette index while reading. + Fixed some bugs in ICC profile writing. The code should now accept + all potentially valid ICC profiles and reject obviously invalid ones. + It now uses png_error() to do so rather than casually writing a PNG + without the necessary color data. + Removed whitespace from the end of lines in all source files and scripts. + +Version 1.6.0beta16 [March 6, 2012] + Relocated palette-index checking function from pngrutil.c to pngtrans.c + Added palette-index checking while writing. + Changed png_inflate() and calling routines to avoid overflow problems. + This is an intermediate check-in that solves the immediate problems and + introduces one performance improvement (avoiding a copy via png_ptr->zbuf.) + Further changes will be made to make ICC profile handling more secure. + Fixed build warnings (MSVC, GCC, GCC v3). Cygwin GCC with default options + declares 'index' as a global, causing a warning if it is used as a local + variable. GCC 64-bit warns about assigning a (size_t) (unsigned 64-bit) + to an (int) (signed 32-bit). MSVC, however, warns about using the + unary '-' operator on an unsigned value (even though it is well defined + by ANSI-C to be ~x+1). The padding calculation was changed to use a + different method. Removed the tests on png_ptr->pass. + Added contrib/libtests/tarith.c to test internal arithmetic functions from + png.c. This is a libpng maintainer program used to validate changes to the + internal arithmetic functions. + Made read 'inflate' handling like write 'deflate' handling. The read + code now claims and releases png_ptr->zstream, like the write code. + The bug whereby the progressive reader failed to release the zstream + is now fixed, all initialization is delayed, and the code checks for + changed parameters on deflate rather than always calling + deflatedEnd/deflateInit. + Validate the zTXt strings in pngvalid. + Added code to validate the windowBits value passed to deflateInit2(). + If the call to deflateInit2() is wrong a png_warning will be issued + (in fact this is harmless, but the PNG data produced may be sub-optimal). + +Version 1.6.0beta17 [March 10, 2012] + Fixed PNG_LIBPNG_BUILD_BASE_TYPE definition. + Reject all iCCP chunks after the first, even if the first one is invalid. + Deflate/inflate was reworked to move common zlib calls into single + functions [rw]util.c. A new shared keyword check routine was also added + and the 'zbuf' is no longer allocated on progressive read. It is now + possible to call png_inflate() incrementally. A warning is no longer + issued if the language tag or translated keyword in the iTXt chunk + has zero length. + If benign errors are disabled use maximum window on ancilliary inflate. + This works round a bug introduced in 1.5.4 where compressed ancillary + chunks could end up with a too-small windowBits value in the deflate + header. + +Version 1.6.0beta18 [March 16, 2012] + Issue a png_benign_error() instead of png_warning() about bad palette index. + In pngtest, treat benign errors as errors if "-strict" is present. + Fixed an off-by-one error in the palette index checking function. + Fixed a compiler warning under Cygwin (Windows-7, 32-bit system) + Revised example.c to put text strings in a temporary character array + instead of directly assigning string constants to png_textp members. + This avoids compiler warnings when -Wwrite-strings is enabled. + Added output flushing to aid debugging under Visual Studio. Unfortunately + this is necessary because the VS2010 output window otherwise simply loses + the error messages on error (they weren't flushed to the window before + the process exited, apparently!) + Added configuration support for benign errors and changed the read + default. Also changed some warnings in the iCCP and sRGB handling + from to benign errors. Configuration now makes read benign + errors warnings and write benign errors to errors by default (thus + changing the behavior on read). The simplified API always forces + read benign errors to warnings (regardless of the system default, unless + this is disabled in which case the simplified API can't be built.) + +Version 1.6.0beta19 [March 18, 2012] + Work around for duplicate row start calls; added warning messages. + This turns on PNG_FLAG_DETECT_UNINITIALIZED to detect app code that + fails to call one of the 'start' routines (not enabled in libpng-1.5 + because it is technically an API change, since it did normally work + before.) It also makes duplicate calls to png_read_start_row (an + internal function called at the start of the image read) benign, as + they were before changes to use png_inflate_claim. Somehow webkit is + causing this to happen; this is probably a mis-feature in the zlib + changes so this commit is only a work-round. + Removed erroneous setting of DETECT_UNINITIALIZED and added more + checks. The code now does a png_error if an attempt is made to do the + row initialization twice; this is an application error and it has + serious consequences because the transform data in png_struct is + changed by each call. + Added application error reporting and added chunk names to read + benign errors; also added --strict to pngstest - not enabled + yet because a warning is produced. + Avoid the double gamma correction warning in the simplified API. + This allows the --strict option to pass in the pngstest checks + +Version 1.6.0beta20 [March 29, 2012] + Changed chunk handler warnings into benign errors, incrementally load iCCP + Added checksum-icc.c to contrib/tools + Prevent PNG_EXPAND+PNG_SHIFT doing the shift twice. + Recognize known sRGB ICC profiles while reading; prefer writing the + iCCP profile over writing the sRGB chunk, controlled by the + PNG_sRGB_PROFILE_CHECKS option. + Revised png_set_text_2() to avoid potential memory corruption (fixes + CVE-2011-3048, also known as CVE-2012-3425). + +Version 1.6.0beta21 [April 27, 2012] + Revised scripts/makefile.darwin: use system zlib; remove quotes around + architecture list; add missing ppc architecture; add architecture options + to shared library link; don't try to create a shared lib based on missing + RELEASE variable. + Enable png_set_check_for_invalid_index() for both read and write. + Removed #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED in pngpriv.h around + declaration of png_handle_unknown(). + Added -lssp_nonshared in a comment in scripts/makefile.freebsd + and changed deprecated NOOBJ and NOPROFILE to NO_OBJ and NO_PROFILE. + +Version 1.6.0beta22 [May 23, 2012] + Removed need for -Wno-cast-align with clang. clang correctly warns on + alignment increasing pointer casts when -Wcast-align is passed. This + fixes the cases that clang warns about either by eliminating the + casts from png_bytep to png_uint_16p (pngread.c), or, for pngrutil.c + where the cast is previously verified or pngstest.c where it is OK, by + introducing new png_aligncast macros to do the cast in a way that clang + accepts. + +Version 1.6.0beta23 [June 6, 2012] + Revised CMakeLists.txt to not attempt to make a symlink under mingw. + Made fixes for new optimization warnings from gcc 4.7.0. The compiler + performs an optimization which is safe; however it then warns about it. + Changing the type of 'palette_number' in pngvalid.c removes the warning. + Do not depend upon a GCC feature macro being available for use in generating + the linker mapfile symbol prefix. + Improved performance of new do_check_palette_indexes() function (only + update the value when it actually increases, move test for whether + the check is wanted out of the function. + +Version 1.6.0beta24 [June 7, 2012] + Don't check palette indexes if num_palette is 0 (as it can be in MNG files). + +Version 1.6.0beta25 [June 16, 2012] + Revised png_set_keep_unknown_chunks() so num_chunks < 0 means ignore all + unknown chunks and all known chunks except for IHDR, PLTE, tRNS, IDAT, + and IEND. Previously it only meant ignore all unknown chunks, the + same as num_chunks == 0. Revised png_image_skip_unused_chunks() to + provide a list of chunks to be processed instead of a list of chunks to + ignore. Revised contrib/gregbook/readpng2.c accordingly. + +Version 1.6.0beta26 [July 10, 2012] + Removed scripts/makefile.cegcc from the *.zip and *.7z distributions; it + depends on configure, which is not included in those archives. + Moved scripts/chkfmt to contrib/tools. + Changed "a+w" to "u+w" in Makefile.in to fix CVE-2012-3386. + +Version 1.6.0beta27 [August 11, 2012] + Do not compile PNG_DEPRECATED, PNG_ALLOC and PNG_PRIVATE when __GNUC__ < 3. + Do not use __restrict when GNUC is <= 3.1 + Removed references to png_zalloc() and png_zfree() from the manual. + Fixed configurations where floating point is completely disabled. Because + of the changes to support symbol prefixing PNG_INTERNAL_FUNCTION declares + floating point APIs during libpng builds even if they are completely + disabled. This requires the png floating point types (png_double*) to be + declared even though the functions are never actually defined. This + change provides a dummy definition so that the declarations work, yet any + implementation will fail to compile because of an incomplete type. + Re-eliminated the use of strcpy() in pngtest.c. An unncessary use of + strcpy() was accidentally re-introduced in libpng16; this change replaces + it with strncpy(). + Eliminated use of png_sizeof(); use sizeof() instead. + Use a consistent style for (sizeof type) and (sizeof (array)) + Cleanup of png_set_filler(). This function does very different things on + read and write. In libpng 1.6 the two cases can be distinguished and + considerable code cleanup, and extra error checking, is possible. This + makes calls on the write side that have no effect be ignored with a + png_app_error(), which can be disabled in the app using + png_set_benign_errors(), and removes the spurious use of usr_channels + on the read side. + Insist on autotools 1.12.1 for git builds because there are security issues + with 1.12 and insisting on anything less would allow 1.12 to be used. + Removed info_ptr->signature[8] from WRITE-only builds. + Add some conditions for compiling png_fixed(). This is a small function + but it requires "-lm" on some platforms. + Cause pngtest --strict to fail on any warning from libpng (not just errors) + and cause it not to fail at the comparison step if libpng lacks support + for writing chunks that it reads from the input (currently only implemented + for compressed text chunks). + Make all three "make check" test programs work without READ or WRITE support. + Now "make check" will succeed even if libpng is compiled with -DPNG_NO_READ + or -DPNG_NO_WRITE. The tests performed are reduced, but the basic reading + and writing of a PNG file is always tested by one or more of the tests. + Consistently use strlen(), memset(), memcpy(), and memcmp() instead of the + png_strlen(), png_memset(), png_memcpy(), and png_memcmp() macros. + Removed the png_sizeof(), png_strlen(), png_memset(), png_memcpy(), and + png_memcmp() macros. + Work around gcc 3.x and Microsoft Visual Studio 2010 complaints. Both object + to the split initialization of num_chunks. + +Version 1.6.0beta28 [August 29, 2012] + Unknown handling fixes and clean up. This adds more correct option + control of the unknown handling, corrects the pre-existing bug where + the per-chunk 'keep' setting is ignored and makes it possible to skip + IDAT chunks in the sequential reader (broken in earlier 1.6 versions). + There is a new test program, test-unknown.c, which is a work in progress + (not currently part of the test suite). Comments in the header files now + explain how the unknown handling works. + Allow fine grain control of unknown chunk APIs. This change allows + png_set_keep_unknown_chunks() to be turned off if not required and causes + both read and write to behave appropriately (on read this is only possible + if the user callback is used to handle unknown chunks). The change + also removes the support for storing unknown chunks in the info_struct + if the only unknown handling enabled is via the callback, allowing libpng + to be configured with callback reading and none of the unnecessary code. + Corrected fix for unknown handling in pngtest. This reinstates the + libpng handling of unknown chunks other than vpAg and sTER (including + unsafe-to-copy chunks which were dropped before) and eliminates the + repositioning of vpAg and sTER in pngtest.png by changing pngtest.png + (so the chunks are where libpng would put them). + Added "tunknown" test and corrected a logic error in png_handle_unknown() + when SAVE support is absent. Moved the shell test scripts for + contrib/libtests from the libpng top directory to contrib/libtests. + png_handle_unknown() must always read or skip the chunk, if + SAVE_UNKNOWN_CHUNKS is turned off *and* the application does not set + a user callback an unknown chunk will not be read, leading to a read + error, which was revealed by the "tunknown" test. + Cleaned up and corrected ICC profile handling. + contrib/libtests/makepng: corrected 'rgb' and 'gray' cases. profile_error + messages could be truncated; made a correct buffer size calculation and + adjusted pngerror.c appropriately. png_icc_check_* checking improved; + changed the functions to receive the correct color type of the PNG on read + or write and check that it matches the color space of the profile (despite + what the comments said before, there is danger in assuming the app will + cope correctly with an RGB profile on a grayscale image and, since it + violates the PNG spec, allowing it is certain to produce inconsistent + app behavior and might even cause app crashes.) Check that profiles + contain the tags needed to process the PNG (tags all required by the ICC + spec). Removed unused PNG_STATIC from pngpriv.h. + +Version 1.6.0beta29 [September 4, 2012] + Fixed the simplified API example programs to add the *colormap parameter + to several of he API and improved the error message if the version field + is not set. + Added contrib/examples/* to the *.zip and *.7z distributions. + Updated simplified API synopses and description of the png_image structure + in the manual. + Made makepng and pngtest produce identical PNGs, add "--relaxed" option + to pngtest. The "--relaxed" option turns off the benign errors that are + enabled by default in pre-RC builds. makepng can now write ICC profiles + where the length has not been extended to a multiple of 4, and pngtest + now intercepts all libpng errors, allowing the previously-introduced + "--strict test" on no warnings to actually work. + Improved ICC profile handling including cHRM chunk generation and fixed + Cygwin+MSVC build errors. The ICC profile handling now includes more + checking. Several errors that caused rejection of the profile are now + handled with a warning in such a way that the invalid profiles will be + read by default in release (but not pre-RC) builds but will not be + written by default. The easy part of handling the cHRM chunk is written, + where the ICC profile contains the required data. The more difficult + part plus guessing a gAMA value requires code to pass selected RGB values + through the profile. + +Version 1.6.0beta30 [October 24, 2012] + Changed ICC profile matrix/vector types to not depend on array type rules. + By the ANSI-C standard the new types should be identical to the previous + versions, and all known versions of gcc tested with the previous versions + except for GCC-4.2.1 work with this version. The change makes the ANSI-C + rule that const applied to an array of elements applies instead to the + elements in the array moot by explicitly applying const to the base + elements of the png_icc_matrix and png_icc_vector types. The accidental + (harmless) 'const' previously applied to the parameters of two of the + functions have also been removed. + Added a work around for GCC 4.2 optimization bug. + Marked the broken (bad white point) original HP sRGB profiles correctly and + correct comments. + Added -DZ_SOLO to contrib/pngminim/*/makefile to work with zlib-1.2.7 + Use /MDd for vstudio debug builds. Also added pngunkown to the vstudio + builds, fixed build errors and corrected a minor exit code error in + pngvalid if the 'touch' file name is invalid. + Add updated WARNING file to projects/vstudio from libpng 1.5/vstudio + Fixed build when using #define PNG_NO_READ_GAMMA in png_do_compose() in + pngrtran.c (Domani Hannes). + +Version 1.6.0beta31 [November 1, 2012] + Undid the erroneous change to vstudio/pngvalid build in libpng-1.6.0beta30. + Made pngvalid so that it will build outside the libpng source tree. + Made builds -DPNG_NO_READ_GAMMA compile (the unit tests still fail). + Made PNG_NO_READ_GAMMA switch off interfaces that depend on READ_GAMMA. + Prior to 1.6.0 switching off READ_GAMMA did unpredictable things to the + interfaces that use it (specifically, png_do_background in 1.4 would + simply display composite for grayscale images but do composition + with the incorrect arithmetic for color ones). In 1.6 the semantic + of -DPNG_NO_READ_GAMMA is changed to simply disable any interface that + depends on it; this obliges people who set it to consider whether they + really want it off if they happen to use any of the interfaces in + question (typically most users who disable it won't). + Fixed GUIDs in projects/vstudio. Some were duplicated or missing, + resulting in VS2010 having to update the files. + Removed non-working ICC profile support code that was mostly added to + libpng-1.6.0beta29 and beta30. There was too much code for too little + gain; implementing full ICC color correction may be desireable but is left + up to applications. + +Version 1.6.0beta32 [November 25, 2012] + Fixed an intermittent SEGV in pngstest due to an uninitialized array element. + Added the ability for contrib/libtests/makepng.c to make a PNG with just one + color. This is useful for debugging pngstest color inaccuracy reports. + Fixed error checking in the simplified write API (Olaf van der Spek) + Made png_user_version_check() ok to use with libpng version 1.10.x and later. + +Version 1.6.0beta33 [December 15, 2012] + Fixed typo in png.c (PNG_SET_CHUNK_MALLOC_MAX should be PNG_CHUNK_MALLOC_MAX) + that causes the MALLOC_MAX limit not to work (John Bowler) + Change png_warning() to png_app_error() in pngwrite.c and comment the + fall-through condition. + Change png_warning() to png_app_warning() in png_write_tRNS(). + Rearranged the ARM-NEON optimizations: Isolated the machine specific code + to the hardware subdirectory and added comments to pngrutil.c so that + implementors of other optimizations know what to do. + Fixed cases of unquoted DESTDIR in Makefile.am + Rebuilt Makefile.in, etc., with autoconf-2.69 and automake-1.12.5. + +Version 1.6.0beta34 [December 19, 2012] + Cleaned up whitespace in the synopsis portion of the manpage "libpng.3" + Disassembled the version number in scripts/options.awk (necessary for + building on SunOs). + +Version 1.6.0beta35 [December 23, 2012] + Made default Zlib compression settings be configurable. This adds #defines to + pnglibconf.h to control the defaults. + Fixed Windows build issues, enabled ARM compilation. Various warnings issued + by earlier versions of GCC fixed for Cygwin and Min/GW (which both use old + GCCs.) ARM support is enabled by default in zlib.props (unsupported by + Microsoft) and ARM compilation is made possible by deleting the check for + x86. The test programs cannot be run because they are not signed. + +Version 1.6.0beta36 [January 2, 2013] + Discontinued distributing libpng-1.x.x.tar.bz2. + Discontinued distributing libpng-1.7.0-1.6.0-diff.txt and similar. + Rebuilt configure with autoconf-2.69 (inadvertently not done in beta33) + Fixed 'make distcheck' on SUN OS - libpng.so was not being removed + +Version 1.6.0beta37 [January 10, 2013] + Fixed conceivable but difficult to repro overflow. Also added two test + programs to generate and test a PNG which should have the problem. + +Version 1.6.0beta39 [January 19, 2013] + Again corrected attempt at overflow detection in png_set_unknown_chunks() + (CVE-2013-7353). Added overflow detection in png_set_sPLT() and + png_set_text_2() (CVE-2013-7354). + +Version 1.6.0beta40 [January 20, 2013] + Use consistent handling of overflows in text, sPLT and unknown png_set_* APIs + +Version 1.6.0rc01 [January 26, 2013] + No changes. + +Version 1.6.0rc02 [February 4, 2013] + Added png_get_palette_max() function. + +Version 1.6.0rc03 [February 5, 2013] + Fixed the png_get_palette_max API. + +Version 1.6.0rc04 [February 7, 2013] + Turn serial tests back on (recently turned off by autotools upgrade). + +Version 1.6.0rc05 [February 8, 2013] + Update manual about png_get_palette_max(). + +Version 1.6.0rc06 [February 9, 2013] + Fixed missing dependency in --prefix builds The intermediate + internal 'prefix.h' file can only be generated correctly after + pnglibconf.h, however the dependency was not in Makefile.am. The + symptoms are unpredictable depending on the order make chooses to + build pngprefix.h and pnglibconf.h, often the error goes unnoticed + because there is a system pnglibconf.h to use instead. + +Version 1.6.0rc07 [February 10, 2013] + Enclosed the new png_get_palette_max in #ifdef PNG_GET_PALETTE_MAX_SUPPORTED + block, and revised pnglibconf.h and pnglibconf.h.prebuilt accordingly. + +Version 1.6.0rc08 [February 10, 2013] + Fix typo in png.h #ifdef + +Version 1.6.0 [February 14, 2013] + No changes. + +Version 1.6.1beta01 [February 16, 2013] + Made symbol prefixing work with the ARM neon optimizations. Also allow + pngpriv.h to be included for preprocessor definitions only, so it can + be used in non-C/C++ files. Back ported from libpng 1.7. + Made sRGB check numbers consistent. + Ported libpng 1.5 options.awk/dfn file handling to 1.6, fixed one bug. + Removed cc -E workround, corrected png_get_palette_max API Tested on + SUN OS cc 5.9, which demonstrates the tokenization problem previously + avoided by using /lib/cpp. Since all .dfn output is now protected in + double quotes unless it is to be macro substituted the fix should + work everywhere. + Enabled parallel tests - back ported from libpng-1.7. + scripts/pnglibconf.dfa formatting improvements back ported from libpng17. + Fixed a race condition in the creation of the build 'scripts' directory + while building with a parallel make. + Use approved/supported Android method to check for NEON, use Linux/POSIX + 1003.1 API to check /proc/self/auxv avoiding buffer allocation and other + library calls (ported from libpng15). + +Version 1.6.1beta02 [February 19, 2013] + Use parentheses more consistently in "#if defined(MACRO)" tests. + Folded long lines. + Reenabled code to allow zero length PLTE chunks for MNG. + +Version 1.6.1beta03 [February 22, 2013] + Fixed ALIGNED_MEMORY support. + Added a new configure option: + --enable-arm-neon=always will stop the run-time checks. New checks + within arm/arm_init.c will cause the code not to be compiled unless + __ARM_NEON__ is set. This should make it fail safe (if someone asks + for it on then the build will fail if it can't be done.) + Updated the INSTALL document. + +Version 1.6.1beta04 [February 27, 2013] + Revised INSTALL to recommend using CPPFLAGS instead of INCLUDES. + Revised scripts/makefile.freebsd to respect ZLIBLIB and ZLIBINC. + Revised scripts/dfn.awk to work with the buggy MSYS awk that has trouble + with CRLF line endings. + +Version 1.6.1beta05 [March 1, 2013] + Avoid a possible memory leak in contrib/gregbook/readpng.c + +Version 1.6.1beta06 [March 4, 2013] + Better documentation of unknown handling API interactions. + Corrected Android builds and corrected libpng.vers with symbol + prefixing. It also makes those tests compile and link on Android. + Added an API png_set_option() to set optimization options externally, + providing an alternative and general solution for the non-portable + run-time tests used by the ARM Neon code, using the PNG_ARM_NEON option. + The order of settings vs options in pnglibconf.h is reversed to allow + settings to depend on options and options can now set (or override) the + defaults for settings. + +Version 1.6.1beta07 [March 7, 2013] + Corrected simplified API default gamma for color-mapped output, added + a flag to change default. In 1.6.0 when the simplified API was used + to produce color-mapped output from an input image with no gamma + information the gamma assumed for the input could be different from + that assumed for non-color-mapped output. In particular 16-bit depth + input files were assumed to be sRGB encoded, whereas in the 'direct' + case they were assumed to have linear data. This was an error. The + fix makes the simplified API treat all input files the same way and + adds a new flag to the png_image::flags member to allow the + application/user to specify that 16-bit files contain sRGB data + rather than the default linear. + Fixed bugs in the pngpixel and makepng test programs. + +Version 1.6.1beta08 [March 7, 2013] + Fixed CMakelists.txt to allow building a single variant of the library + (Claudio Bley): + Introduced a PNG_LIB_TARGETS variable that lists all activated library + targets. It is an error if this variable ends up empty, ie. you have + to build at least one library variant. + Made the *_COPY targets only depend on library targets actually being build. + Use PNG_LIB_TARGETS to unify a code path. + Changed the CREATE_SYMLINK macro to expect the full path to a file as the + first argument. When symlinking the filename component of that path is + determined and used as the link target. + Use copy_if_different in the CREATE_SYMLINK macro. + +Version 1.6.1beta09 [March 13, 2013] + Eliminated two warnings from the Intel C compiler. The warnings are + technically valid, although a reasonable treatment of division would + show it to be incorrect. + +Version 1.6.1rc01 [March 21, 2013] + No changes. + +Version 1.6.1 [March 28, 2013] + No changes. + +Version 1.6.2beta01 [April 14, 2013] + Updated documentation of 1.5.x to 1.6.x changes in iCCP chunk handling. + Fixed incorrect warning of excess deflate data. End condition - the + warning would be produced if the end of the deflate stream wasn't read + in the last row. The warning is harmless. + Corrected the test on user transform changes on read. It was in the + png_set of the transform function, but that doesn't matter unless the + transform function changes the rowbuf size, and that is only valid if + transform_info is called. + Corrected a misplaced closing bracket in contrib/libtests/pngvalid.c + (Flavio Medeiros). + Corrected length written to uncompressed iTXt chunks (Samuli Suominen). + Bug was introduced in libpng-1.6.0. + +Version 1.6.2rc01 [April 18, 2013] + Added contrib/tools/fixitxt.c, to repair the erroneous iTXt chunk length + written by libpng-1.6.0 and 1.6.1. + Disallow storing sRGB information when the sRGB is not supported. + +Version 1.6.2rc02 [April 18, 2013] + Merge pngtest.c with libpng-1.7.0 + +Version 1.6.2rc03 [April 22, 2013] + Trivial spelling cleanup. + +Version 1.6.2rc04 and 1.6.2rc05 [omitted] + +Version 1.6.2rc06 [April 24, 2013] + Reverted to version 1.6.2rc03. Recent changes to arm/neon support + have been ported to libpng-1.7.0beta09 and will reappear in version + 1.6.3beta01. + +Version 1.6.2 [April 25, 2013] + No changes. + +Version 1.6.3beta01 [April 25, 2013] + Revised stack marking in arm/filter_neon.S and configure.ac. + Ensure that NEON filter stuff is completely disabled when switched 'off'. + Previously the ARM NEON specific files were still built if the option + was switched 'off' as opposed to being explicitly disabled. + +Version 1.6.3beta02 [April 26, 2013] + Test for 'arm*' not just 'arm' in the host_cpu configure variable. + Rebuilt the configure scripts. + +Version 1.6.3beta03 [April 30, 2013] + Expanded manual paragraph about writing private chunks, particularly + the need to call png_set_keep_unknown_chunks() when writing them. + Avoid dereferencing NULL pointer possibly returned from + png_create_write_struct() (Andrew Church). + +Version 1.6.3beta05 [May 9, 2013] + Calculate our own zlib windowBits when decoding rather than trusting the + CMF bytes in the PNG datastream. + Added an option to force maximum window size for inflating, which was + the behavior of libpng15 and earlier, via a new PNG_MAXIMUM_INFLATE_WINDOW + option for png_set_options(). + Added png-fix-itxt and png-fix-too-far-back to the built programs and + removed warnings from the source code and timepng that are revealed as + a result. + Detect wrong libpng versions linked to png-fix-too-far-back, which currently + only works with libpng versions that can be made to reliably fail when + the deflate data contains an out-of-window reference. This means only + 1.6 and later. + Fixed gnu issues: g++ needs a static_cast, gcc 4.4.7 has a broken warning + message which it is easier to work round than ignore. + Updated contrib/pngminus/pnm2png.c (Paul Stewart): + Check for EOF + Ignore "#" delimited comments in input file to pnm2png.c. + Fixed whitespace handling + Added a call to png_set_packing() + Initialize dimension values so if sscanf fails at least we have known + invalid values. + Attempt to detect configuration issues with png-fix-too-far-back, which + requires both the correct libpng and the correct zlib to function + correctly. + Check ZLIB_VERNUM for mismatches, enclose #error in quotes + Added information in the documentation about problems with and fixes for + the bad CRC and bad iTXt chunk situations. + +Version 1.6.3beta06 [May 12, 2013] + Allow contrib/pngminus/pnm2png.c to compile without WRITE_INVERT and + WRITE_PACK supported (writes error message that it can't read P1 or + P4 PBM files). + Improved png-fix-too-far-back usage message, added --suffix option. + Revised contrib/pngminim/*/makefile to generate pnglibconf.h with the + right zlib header files. + Separated CPPFLAGS and CFLAGS in contrib/pngminim/*/makefile + +Version 1.6.3beta07 [June 8, 2013] + Removed a redundant test in png_set_IHDR(). + Added set(CMAKE_CONFIGURATION_TYPES ...) to CMakeLists.txt (Andrew Hundt) + Deleted set(CMAKE_BUILD_TYPE) block from CMakeLists.txt + Enclose the prototypes for the simplified write API in + #ifdef PNG_STDIO_SUPPORTED/#endif + Make ARM NEON support work at compile time (not just configure time). + This moves the test on __ARM_NEON__ into pngconf.h to avoid issues when + using a compiler that compiles for multiple architectures at one time. + Removed PNG_FILTER_OPTIMIZATIONS and PNG_ARM_NEON_SUPPORTED from + pnglibconf.h, allowing more of the decisions to be made internally + (pngpriv.h) during the compile. Without this, symbol prefixing is broken + under certain circumstances on ARM platforms. Now only the API parts of + the optimizations ('check' vs 'api') are exposed in the public header files + except that the new setting PNG_ARM_NEON_OPT documents how libpng makes the + decision about whether or not to use the optimizations. + Protect symbol prefixing against CC/CPPFLAGS/CFLAGS useage. + Previous iOS/Xcode fixes for the ARM NEON optimizations moved the test + on __ARM_NEON__ from configure time to compile time. This breaks symbol + prefixing because the definition of the special png_init_filter_functions + call was hidden at configure time if the relevant compiler arguments are + passed in CFLAGS as opposed to CC. This change attempts to avoid all + the confusion that would result by declaring the init function even when + it is not used, so that it will always get prefixed. + +Version 1.6.3beta08 [June 18, 2013] + Revised libpng.3 so that "doclifter" can process it. + +Version 1.6.3beta09 [June 27, 2013] + Revised example.c to illustrate use of PNG_DEFAULT_sRGB and PNG_GAMMA_MAC_18 + as parameters for png_set_gamma(). These have been available since + libpng-1.5.4. + Renamed contrib/tools/png-fix-too-far-back.c to pngfix.c and revised it + to check all compressed chunks known to libpng. + +Version 1.6.3beta10 [July 5, 2013] + Updated documentation to show default behavior of benign errors correctly. + Only compile ARM code when PNG_READ_SUPPORTED is defined. + Fixed undefined behavior in contrib/tools/pngfix.c and added new strip + option. pngfix relied on undefined behavior and even a simple change from + gcc to g++ caused it to fail. The new strip option 'unsafe' has been + implemented and is the default if --max is given. Option names have + been clarified, with --strip=transform now stripping the bKGD chunk, + which was stripped previously with --strip=unused. + Added all documented chunk types to pngpriv.h + Unified pngfix.c source with libpng17. + +Version 1.6.3rc01 [July 11, 2013] + No changes. + +Version 1.6.3 [July 18, 2013] + Revised manual about changes in iTXt chunk handling made in libpng-1.6.0. + Added "/* SAFE */" comments in pngrutil.c and pngrtran.c where warnings + may be erroneously issued by code-checking applications. + +Version 1.6.4beta01 [August 21, 2013] + Added information about png_set_options() to the manual. + Delay calling png_init_filter_functions() until a row with nonzero filter + is found. + +Version 1.6.4beta02 [August 30, 2013] + Fixed inconsistent conditional compilation of png_chunk_unknown_handling() + prototype, definition, and usage. Made it depend on + PNG_HANDLE_AS_UNKNOWN_SUPPORTED everywhere. + +Version 1.6.4rc01 [September 5, 2013] + No changes. + +Version 1.6.4 [September 12, 2013] + No changes. + +Version 1.6.5 [September 14, 2013] + Removed two stray lines of code from arm/arm_init.c. + +Version 1.6.6 [September 16, 2013] + Removed two stray lines of code from arm/arm_init.c, again. + +Version 1.6.7beta01 [September 30, 2013] + Revised unknown chunk code to correct several bugs in the NO_SAVE_/NO_WRITE + combination + Allow HANDLE_AS_UNKNOWN to work when other options are configured off. Also + fixed the pngminim makefiles to work when $(MAKEFLAGS) contains stuff + which terminates the make options (as by default in recent versions of + Gentoo). + Avoid up-cast warnings in pngvalid.c. On ARM the alignment requirements of + png_modifier are greater than that of png_store and as a consequence + compilation of pngvalid.c results in a warning about increased alignment + requirements because of the bare cast to (png_modifier*). The code is safe, + because the pointer is known to point to a stack allocated png_modifier, + but this change avoids the warning. + Fixed default behavior of ARM_NEON_API. If the ARM NEON API option was + compiled without the CHECK option it defaulted to on, not off. + Check user callback behavior in pngunknown.c. Previous versions compiled + if SAVE_UNKNOWN was not available but did nothing since the callback + was never implemented. + Merged pngunknown.c with 1.7 version and back ported 1.7 improvements/fixes + +Version 1.6.7beta02 [October 12, 2013] + Made changes for compatibility with automake 1.14: + 1) Added the 'compile' program to the list of programs that must be cleaned + in autogen.sh + 2) Added 'subdir-objects' which causes .c files in sub-directories to be + compiled such that the corresponding .o files are also in the + sub-directory. This is because automake 1.14 warns that the + current behavior of compiling to the top level directory may be removed + in the future. + 3) Updated dependencies on pnglibconf.h to match the new .o locations and + added all the files in contrib/libtests and contrib/tools that depend + on pnglibconf.h + 4) Added 'BUILD_SOURCES = pnglibconf.h'; this is the automake recommended + way of handling the dependencies of sources that are machine generated; + unfortunately it only works if the user does 'make all' or 'make check', + so the dependencies (3) are still required. + Cleaned up (char*) casts of zlib messages. The latest version of the Intel C + compiler complains about casting a string literal as (char*), so copied the + treatment of z_const from the library code into pngfix.c + Simplified error message code in pngunknown. The simplification has the + useful side effect of avoiding a bogus warning generated by the latest + version of the Intel C compiler (it objects to + condition ? string-literal : string-literal). + Make autogen.sh work with automake 1.13 as well as 1.14. Do this by always + removing the 1.14 'compile' script but never checking for it. + +Version 1.6.7beta03 [October 19, 2013] + Added ARMv8 support (James Yu ). Added file + arm/filter_neon_intrinsics.c; enable with -mfpu=neon. + Revised pngvalid to generate size images with as many filters as it can + manage, limited by the number of rows. + Cleaned up ARM NEON compilation handling. The tests are now in pngpriv.h + and detect the broken GCC compilers. + +Version 1.6.7beta04 [October 26, 2013] + Allow clang derived from older GCC versions to use ARM intrinsics. This + causes all clang builds that use -mfpu=neon to use the intrinsics code, + not the assembler code. This has only been tested on iOS 7. It may be + necessary to exclude some earlier clang versions but this seems unlikely. + Changed NEON implementation selection mechanism. This allows assembler + or intrinsics to be turned on at compile time during the build by defining + PNG_ARM_NEON_IMPLEMENTATION to the correct value (2 or 1). This macro + is undefined by default and the build type is selected in pngpriv.h. + +Version 1.6.7rc01 [November 2, 2013] + No changes. + +Version 1.6.7rc02 [November 7, 2013] + Fixed #include in filter_neon_intrinsics.c and ctype macros. The ctype char + checking macros take an unsigned char argument, not a signed char. + +Version 1.6.7 [November 14, 2013] + No changes. + +Version 1.6.8beta01 [November 24, 2013] + Moved prototype for png_handle_unknown() in pngpriv.h outside of + the #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED/#endif block. + Added "-Wall" to CFLAGS in contrib/pngminim/*/makefile + Conditionally compile some unused functions reported by -Wall in + pngminim. + Fixed 'minimal' builds. Various obviously useful minimal configurations + don't build because of missing contrib/libtests test programs and + overly complex dependencies in scripts/pnglibconf.dfa. This change + adds contrib/conftest/*.dfa files that can be used in automatic build + scripts to ensure that these configurations continue to build. + Enabled WRITE_INVERT and WRITE_PACK in contrib/pngminim/encoder. + Fixed pngvalid 'fail' function declaration on the Intel C Compiler. + This reverts to the previous 'static' implementation and works round + the 'unused static function' warning by using PNG_UNUSED(). + +Version 1.6.8beta02 [November 30, 2013] + Removed or marked PNG_UNUSED some harmless "dead assignments" reported + by clang scan-build. + Changed tabs to 3 spaces in png_debug macros and changed '"%s"m' + to '"%s" m' to improve portability among compilers. + Changed png_free_default() to free() in pngtest.c + +Version 1.6.8rc01 [December 12, 2013] + Tidied up pngfix inits and fixed pngtest no-write builds. + +Version 1.6.8rc02 [December 14, 2013] + Handle zero-length PLTE chunk or NULL palette with png_error() + instead of png_chunk_report(), which by default issues a warning + rather than an error, leading to later reading from a NULL pointer + (png_ptr->palette) in png_do_expand_palette(). This is CVE-2013-6954 + and VU#650142. Libpng-1.6.1 through 1.6.7 are vulnerable. + Libpng-1.6.0 and earlier do not have this bug. + +Version 1.6.8 [December 19, 2013] + No changes. + +Version 1.6.9beta01 [December 26, 2013] + Bookkeeping: Moved functions around (no changes). Moved transform + function definitions before the place where they are called so that + they can be made static. Move the intrapixel functions and the + grayscale palette builder out of the png?tran.c files. The latter + isn't a transform function and is no longer used internally, and the + former MNG specific functions are better placed in pngread/pngwrite.c + Made transform implementation functions static. This makes the internal + functions called by png_do_{read|write}_transformations static. On an + x86-64 DLL build (Gentoo Linux) this reduces the size of the text + segment of the DLL by 1208 bytes, about 0.6%. It also simplifies + maintenance by removing the declarations from pngpriv.h and allowing + easier changes to the internal interfaces. + Rebuilt configure scripts with automake-1.14.1 and autoconf-2.69 + in the tar distributions. + +Version 1.6.9beta02 [January 1, 2014] + Added checks for libpng 1.5 to pngvalid.c. This supports the use of + this version of pngvalid in libpng 1.5 + Merged with pngvalid.c from libpng-1.7 changes to create a single + pngvalid.c + Removed #error macro from contrib/tools/pngfix.c (Thomas Klausner). + Merged pngrio.c, pngtrans.c, pngwio.c, and pngerror.c with libpng-1.7.0 + Merged libpng-1.7.0 changes to make no-interlace configurations work + with test programs. + Revised pngvalid.c to support libpng 1.5, which does not support the + PNG_MAXIMUM_INFLATE_WINDOW option, so #define it out when appropriate in + pngvalid.c + Allow unversioned links created on install to be disabled in configure. + In configure builds 'make install' changes/adds links like png.h + and libpng.a to point to the newly installed, versioned, files (e.g. + libpng17/png.h and libpng17.a). Three new configure options and some + rearrangement of Makefile.am allow creation of these links to be disabled. + +Version 1.6.9beta03 [January 10, 2014] + Removed potentially misleading warning from png_check_IHDR(). + +Version 1.6.9beta04 [January 20, 2014] + Updated scripts/makefile.* to use CPPFLAGS (Cosmin). + Added clang attribute support (Cosmin). + +Version 1.6.9rc01 [January 28, 2014] + No changes. + +Version 1.6.9rc02 [January 30, 2014] + Quiet an uninitialized memory warning from VC2013 in png_get_png(). + +Version 1.6.9 [February 6, 2014] + +Version 1.6.10beta01 [February 9, 2014] + Backported changes from libpng-1.7.0beta30 and beta31: + Fixed a large number of instances where PNGCBAPI was omitted from + function definitions. + Added pngimage test program for png_read_png() and png_write_png() + with two new test scripts. + Removed dependence on !PNG_READ_EXPAND_SUPPORTED for calling + png_set_packing() in png_read_png(). + Fixed combination of ~alpha with shift. On read invert alpha, processing + occurred after shift processing, which causes the final values to be + outside the range that should be produced by the shift. Reversing the + order on read makes the two transforms work together correctly and mirrors + the order used on write. + Do not read invalid sBIT chunks. Previously libpng only checked sBIT + values on write, so a malicious PNG writer could therefore cause + the read code to return an invalid sBIT chunk, which might lead to + application errors or crashes. Such chunks are now skipped (with + chunk_benign_error). + Make png_read_png() and png_write_png() prototypes in png.h depend + upon PNG_READ_SUPPORTED and PNG_WRITE_SUPPORTED. + Support builds with unsupported PNG_TRANSFORM_* values. All of the + PNG_TRANSFORM_* values are always defined in png.h and, because they + are used for both read and write in some cases, it is not reliable + to #if out ones that are totally unsupported. This change adds error + detection in png_read_image() and png_write_image() to do a + png_app_error() if the app requests something that cannot be done + and it adds corresponding code to pngimage.c to handle such options + by not attempting to test them. + +Version 1.6.10beta02 [February 23, 2014] + Moved redefines of png_error(), png_warning(), png_chunk_error(), + and png_chunk_warning() from pngpriv.h to png.h to make them visible + to libpng-calling applications. + Moved OS dependent code from arm/arm_init.c, to allow the included + implementation of the ARM NEON discovery function to be set at + build-time and provide sample implementations from the current code in the + contrib/arm-neon subdirectory. The __linux__ code has also been changed to + compile and link on Android by using /proc/cpuinfo, and the old linux code + is in contrib/arm-neon/linux-auxv.c. The new code avoids POSIX and Linux + dependencies apart from opening /proc/cpuinfo and is C90 compliant. + Check for info_ptr == NULL early in png_read_end() so we don't need to + run all the png_handle_*() and depend on them to return if info_ptr == NULL. + This improves the performance of png_read_end(png_ptr, NULL) and makes + it more robust against future programming errors. + Check for __has_extension before using it in pngconf.h, to + support older Clang versions (Jeremy Sequoia). + Treat CRC error handling with png_set_crc_action(), instead of with + png_set_benign_errors(), which has been the case since libpng-1.6.0beta18. + Use a user warning handler in contrib/gregbook/readpng2.c instead of default, + so warnings will be put on stderr even if libpng has CONSOLE_IO disabled. + Added png_ptr->process_mode = PNG_READ_IDAT_MODE in png_push_read_chunk + after recognizing the IDAT chunk, which avoids an infinite loop while + reading a datastream whose first IDAT chunk is of zero-length. + This fixes CERT VU#684412 and CVE-2014-0333. + Don't recognize known sRGB profiles as sRGB if they have been hacked, + but don't reject them and don't issue a copyright violation warning. + +Version 1.6.10beta03 [February 25, 2014] + Moved some documentation from png.h to libpng.3 and libpng-manual.txt + Minor editing of contrib/arm-neon/README and contrib/examples/*.c + +Version 1.6.10rc01 [February 27, 2014] + Fixed typos in the manual and in scripts/pnglibconf.dfa (CFLAGS -> CPPFLAGS + and PNG_USR_CONFIG -> PNG_USER_CONFIG). + +Version 1.6.10rc02 [February 28, 2014] + Removed unreachable return statement after png_chunk_error() + in pngrutil.c + +Version 1.6.10rc03 [March 4, 2014] + Un-deprecated png_data_freer(). + +Version 1.6.10 [March 6, 2014] + No changes. + +Version 1.6.11beta01 [March 17, 2014] + Use "if (value != 0)" instead of "if (value)" consistently. + Changed ZlibSrcDir from 1.2.5 to 1.2.8 in projects/vstudio. + Moved configuration information from the manual to the INSTALL file. + +Version 1.6.11beta02 [April 6, 2014] + Removed #if/#else/#endif from inside two pow() calls in pngvalid.c because + they were handled improperly by Portland Group's PGI-14.1 - PGI-14.3 + when using its "__builtin_pow()" function. + Silence 'unused parameter' build warnings (Cosmin Truta). + $(CP) is now used alongside $(RM_F). Also, use 'copy' instead of 'cp' + where applicable, and applied other minor makefile changes (Cosmin). + Don't warn about invalid dimensions exceeding user limits (Cosmin). + Allow an easy replacement of the default pre-built configuration + header with a custom header, via the make PNGLIBCONF_H_PREBUILT + macro (Cosmin). + +Version 1.6.11beta03 [April 6, 2014] + Fixed a typo in pngrutil.c, introduced in libpng-1.5.6, that interferes + with "blocky" expansion of sub-8-bit interlaced PNG files (Eric Huss). + Optionally use __builtin_bswap16() in png_do_swap(). + +Version 1.6.11beta04 [April 19, 2014] + Made progressive reading of interlaced images consistent with the + behavior of the sequential reader and consistent with the manual, by + moving some code out of the PNG_READ_INTERLACING_SUPPORTED blocks. The + row_callback now receives the proper pass number and unexpanded rows, when + png_combine_row() isn't built or used, and png_set_interlace_handling() + is not called. + Allow PNG_sRGB_PROFILE_CHECKING = (-1) to mean no sRGB profile checking. + +Version 1.6.11beta05 [April 26, 2014] + Do not reject ICC V2 profiles that lack padding (Kai-Uwe Behrmann). + Relocated closing bracket of the sRGB profile test loop to avoid getting + "Not recognizing known sRGB profile that has been edited" warning for + ICC V2 profiles that lack the MD5 signature in the profile header. + +Version 1.6.11beta06 [May 19, 2014] + Added PNG_SKIP_sRGB_CHECK_PROFILE choice for png_set_option(). + +Version 1.6.11rc01 [May 27, 2014] + No changes. + +Version 1.6.11rc02 [June 3, 2014] + Test ZLIB_VERNUM instead of PNG_ZLIB_VERNUM in contrib/tools/pngfix.c + +Version 1.6.11 [June 5, 2014] + No changes. + +Version 1.6.12rc01 [June 6, 2014] + Relocated new code from 1.6.11beta06 in png.c to a point after the + declarations (Max Stepin). + +Version 1.6.12rc02 [June 7, 2014] + Changed file permissions of contrib/tools/intgamma.sh, + test-driver, and compile from 0644 to 0755 (Cosmin). + +Version 1.6.12rc03 [June 8, 2014] + Ensure "__has_attribute()" macro exists before trying to use it with + old clang compilers (MacPorts Ticket #43939). + +Version 1.6.12 [June 12, 2014] + No changes. + +Version 1.6.13beta01 [July 4, 2014] + Quieted -Wsign-compare and -Wclobber compiler warnings in + contrib/pngminus/*.c + Added "(void) png_ptr;" where needed in contrib/gregbook to quiet + compiler complaints about unused pointers. + Split a long output string in contrib/gregbook/rpng2-x.c. + Added "PNG_SET_OPTION" requirement for sRGB chunk support to pnglibconf.dfa, + Needed for write-only support (John Bowler). + Changed "if defined(__ARM_NEON__)" to + "if (defined(__ARM_NEON__) || defined(__ARM_NEON))" (James Wu). + Fixed clang no-warning builds: png_digit was defined but never used. + +Version 1.6.13beta02 [July 21, 2014] + Fixed an incorrect separator ("/" should be "\") in scripts/makefile.vcwin32 + (bug report from Wolfgang S. Kechel). Bug was introduced in libpng-1.6.11. + Also fixed makefile.bc32, makefile.bor, makefile.msc, makefile.intel, and + makefile.tc3 similarly. + +Version 1.6.13beta03 [August 3, 2014] + Removed scripts/makefile.elf. It has not worked since libpng-1.5.0beta14 + due to elimination of the PNG_FUNCTION_EXPORT and PNG_DATA_EXPORT + definitions from pngconf.h. + Ensure that CMakeLists.txt makes the target "lib" directory before making + symbolic link into it (SourceForge bug report #226 by Rolf Timmermans). + +Version 1.6.13beta04 [August 8, 2014] + Added opinion that the ECCN (Export Control Classification Number) for + libpng is EAR99 to the README file. + Eliminated use of "$<" in makefile explicit rules, when copying + $PNGLIBCONF_H_PREBUILT. This does not work on some versions of make; + bug introduced in libpng version 1.6.11. + +Version 1.6.13rc01 [August 14, 2014] + Made "ccopts" agree with "CFLAGS" in scripts/makefile.hp* and makefile.*sunu + +Version 1.6.13 [August 21, 2014] + No changes. + +Version 1.6.14beta01 [September 14, 2014] + Guard usage of png_ptr->options with #ifdef PNG_SET_OPTION_SUPPORTED. + Do not build contrib/tools/pngfix.c when PNG_SETJMP_NOT_SUPPORTED, + to allow "make" to complete without setjmp support (bug report by + Claudio Fontana) + Add "#include " to contrib/tools/pngfix.c (John Bowler) + +Version 1.6.14beta02 [September 18, 2014] + Use nanosleep() instead of usleep() in contrib/gregbook/rpng2-x.c + because usleep() is deprecated. + Define usleep() in contrib/gregbook/rpng2-x.c if not already defined + in unistd.h and nanosleep() is not available; fixes error introduced + in libpng-1.6.13. + Disable floating point exception handling in pngvalid.c when + PNG_FLOATING_ARITHMETIC is not supported (bug report by "zootus + at users.sourceforge.net"). + +Version 1.6.14beta03 [September 19, 2014] + Define FE_DIVBYZERO, FE_INVALID, and FE_OVERFLOW in pngvalid.c if not + already defined. Revert floating point exception handling in pngvalid.c + to version 1.6.14beta01 behavior. + +Version 1.6.14beta04 [September 27, 2014] + Fixed incorrect handling of the iTXt compression flag in pngrutil.c + (bug report by Shunsaku Hirata). Bug was introduced in libpng-1.6.0. + +Version 1.6.14beta05 [October 1, 2014] + Added "option READ_iCCP enables READ_COMPRESSED_TEXT" to pnglibconf.dfa + +Version 1.6.14beta06 [October 5, 2014] + Removed unused "text_len" parameter from private function png_write_zTXt(). + Conditionally compile some code in png_deflate_claim(), when + PNG_WARNINGS_SUPPORTED and PNG_ERROR_TEXT_SUPPORTED are disabled. + Replaced repeated code in pngpread.c with PNG_PUSH_SAVE_BUFFER_IF_FULL. + Added "chunk iTXt enables TEXT" and "chunk zTXt enables TEXT" + to pnglibconf.dfa. + Removed "option READ_COMPRESSED_TEXT enables READ_TEXT" from pnglibconf.dfa, + to make it possible to configure a libpng that supports iCCP but not TEXT. + +Version 1.6.14beta07 [October 7, 2014] + Removed "option WRITE_COMPRESSED_TEXT enables WRITE_TEXT" from pnglibconf.dfa + Only mark text chunks as written after successfully writing them. + +Version 1.6.14rc01 [October 15, 2014] + Fixed some typos in comments. + +Version 1.6.14rc02 [October 17, 2014] + Changed png_convert_to_rfc_1123() to png_convert_to_rfc_1123_buffer() + in the manual, to reflect the change made in libpng-1.6.0. + Updated README file to explain that direct access to the png_struct + and info_struct members has not been permitted since libpng-1.5.0. + +Version 1.6.14 [October 23, 2014] + No changes. + +Version 1.6.15beta01 [October 29, 2014] + Changed "if (!x)" to "if (x == 0)" and "if (x)" to "if (x != 0)" + Simplified png_free_data(). + Added missing "ptr = NULL" after some instances of png_free(). + +Version 1.6.15beta02 [November 1, 2014] + Changed remaining "if (!x)" to "if (x == 0)" and "if (x)" to "if (x != 0)" + +Version 1.6.15beta03 [November 3, 2014] + Added PNG_USE_ARM_NEON configuration flag (Marcin Juszkiewicz). + +Version 1.6.15beta04 [November 4, 2014] + Removed new PNG_USE_ARM_NEON configuration flag and made a one-line + revision to configure.ac to support ARM on aarch64 instead (John Bowler). + +Version 1.6.15beta05 [November 5, 2014] + Use png_get_libpng_ver(NULL) instead of PNG_LIBPNG_VER_STRING in + example.c, pngtest.c, and applications in the contrib directory. + Fixed an out-of-range read in png_user_version_check() (Bug report from + Qixue Xiao, CVE-2015-8540). + Simplified and future-proofed png_user_version_check(). + Fixed GCC unsigned int->float warnings. Various versions of GCC + seem to generate warnings when an unsigned value is implicitly + converted to double. This is probably a GCC bug but this change + avoids the issue by explicitly converting to (int) where safe. + Free all allocated memory in pngimage. The file buffer cache was left + allocated at the end of the program, harmless but it causes memory + leak reports from clang. + Fixed array size calculations to avoid warnings. At various points + in the code the number of elements in an array is calculated using + sizeof. This generates a compile time constant of type (size_t) which + is then typically assigned to an (unsigned int) or (int). Some versions + of GCC on 64-bit systems warn about the apparent narrowing, even though + the same compiler does apparently generate the correct, in-range, + numeric constant. This adds appropriate, safe, casts to make the + warnings go away. + +Version 1.6.15beta06 [November 6, 2014] + Reverted use png_get_libpng_ver(NULL) instead of PNG_LIBPNG_VER_STRING + in the manual, example.c, pngtest.c, and applications in the contrib + directory. It was incorrect advice. + +Version 1.6.15beta07 [November 7, 2014] + Removed #ifdef PNG_16BIT_SUPPORTED/#endif around png_product2(); it is + needed by png_reciprocal2(). + Added #ifdef PNG_16BIT_SUPPORTED/#endif around png_log16bit() and + png_do_swap(). + Changed all "#endif /* PNG_FEATURE_SUPPORTED */" to "#endif /* FEATURE */" + +Version 1.6.15beta08 [November 8, 2014] + More housecleaning in *.h + +Version 1.6.15rc01 [November 13, 2014] + +Version 1.6.15rc02 [November 14, 2014] + The macros passed in the command line to Borland make were ignored if + similarly-named macros were already defined in makefiles. This behavior + is different from POSIX make and other make programs. Surround the + macro definitions with ifndef guards (Cosmin). + +Version 1.6.15rc03 [November 16, 2014] + Added "-D_CRT_SECURE_NO_WARNINGS" to CFLAGS in scripts/makefile.vcwin32. + Removed the obsolete $ARCH variable from scripts/makefile.darwin. + +Version 1.6.15 [November 20, 2014] + No changes. + +Version 1.6.16beta01 [December 14, 2014] + Added ".align 2" to arm/filter_neon.S to support old GAS assemblers that + don't do alignment correctly. + Revised Makefile.am and scripts/symbols.dfn to work with MinGW/MSYS + (Bob Friesenhahn). + +Version 1.6.16beta02 [December 15, 2014] + Revised Makefile.am and scripts/*.dfn again to work with MinGW/MSYS; + renamed scripts/*.dfn to scripts/*.c (John Bowler). + +Version 1.6.16beta03 [December 21, 2014] + Quiet a "comparison always true" warning in pngstest.c (John Bowler). + +Version 1.6.16rc01 [December 21, 2014] + Restored a test on width that was removed from png.c at libpng-1.6.9 + (Bug report by Alex Eubanks, CVE-2015-0973). + +Version 1.6.16rc02 [December 21, 2014] + Undid the update to pngrutil.c in 1.6.16rc01. + +Version 1.6.16rc03 [December 21, 2014] + Fixed an overflow in png_combine_row() with very wide interlaced images + (Bug report and fix by John Bowler, CVE-2014-9495). + +Version 1.6.16 [December 22, 2014] + No changes. + +Version 1.6.17beta01 [January 29, 2015] + Removed duplicate PNG_SAFE_LIMITS_SUPPORTED handling from pngconf.h + Corrected the width limit calculation in png_check_IHDR(). + Removed user limits from pngfix. Also pass NULL pointers to + png_read_row to skip the unnecessary row de-interlace stuff. + Added testing of png_set_packing() to pngvalid.c + Regenerated configure scripts in the *.tar distributions with libtool-2.4.4 + Implement previously untested cases of libpng transforms in pngvalid.c + Fixed byte order in png_do_read_filler() with 16-bit input. Previously + the high and low bytes of the filler, from png_set_filler() or from + png_set_add_alpha(), were read in the wrong order. + Made the check for out-of-range values in png_set_tRNS() detect + values that are exactly 2^bit_depth, and work on 16-bit platforms. + Merged some parts of libpng-1.6.17beta01 and libpng-1.7.0beta47. + Added #ifndef __COVERITY__ where needed in png.c, pngrutil.c and + pngset.c to avoid warnings about dead code. + Added "& 0xff" to many instances of expressions that are typecast + to (png_byte), to avoid Coverity warnings. + +Version 1.6.17beta02 [February 7, 2015] + Work around one more Coverity-scan dead-code warning. + Do not build png_product2() when it is unused. + +Version 1.6.17beta03 [February 17, 2015] + Display user limits in the output from pngtest. + Eliminated the PNG_SAFE_LIMITS macro and restored the 1-million-column + and 1-million-row default limits in pnglibconf.dfa, that can be reset + by the user at build time or run time. This provides a more robust + defense against DOS and as-yet undiscovered overflows. + +Version 1.6.17beta04 [February 21, 2015] + Added PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED macro, on by default. + Allow user to call png_get_IHDR() with NULL arguments (Reuben Hawkins). + Rebuilt configure scripts with automake-1.15 and libtool-2.4.6 + +Version 1.6.17beta05 [February 25, 2015] + Restored compiling of png_reciprocal2 with PNG_NO_16BIT. + +Version 1.6.17beta06 [February 27, 2015] + Moved png_set_filter() prototype into a PNG_WRITE_SUPPORTED block + of png.h. + Avoid runtime checks when converting integer to png_byte with + Visual Studio (Sergey Kosarevsky) + +Version 1.6.17rc01 [March 4, 2015] + No changes. + +Version 1.6.17rc02 [March 9, 2015] + Removed some comments that the configure script did not handle + properly from scripts/pnglibconf.dfa and pnglibconf.h.prebuilt. + Free the unknown_chunks structure even when it contains no data. + +Version 1.6.17rc03 [March 12, 2015] + Updated CMakeLists.txt to add OSX framework, change YES/NO to ON/OFF + for consistency, and remove some useless tests (Alexey Petruchik). + +Version 1.6.17rc04 [March 16, 2015] + Remove pnglibconf.h, pnglibconf.c, and pnglibconf.out instead of + pnglibconf.* in "make clean" (Cosmin). + Fix bug in calculation of maxbits, in png_write_sBIT, introduced + in libpng-1.6.17beta01 (John Bowler). + +Version 1.6.17rc05 [March 21, 2015] + Define PNG_FILTER_* and PNG_FILTER_VALUE_* in png.h even when WRITE + is not supported (John Bowler). This fixes an error introduced in + libpng-1.6.17beta06. + Reverted "& 0xff" additions of version 1.6.17beta01. Libpng passes + the Coverity scan without them. + +Version 1.6.17rc06 [March 23, 2015] + Remove pnglibconf.dfn and pnglibconf.pre with "make clean". + Reformatted some "&0xff" instances to "& 0xff". + Fixed simplified 8-bit-linear to sRGB alpha. The calculated alpha + value was wrong. It's not clear if this affected the final stored + value; in the obvious code path the upper and lower 8-bits of the + alpha value were identical and the alpha was truncated to 8-bits + rather than dividing by 257 (John Bowler). + +Version 1.6.17 [March 26, 2015] + No changes. + +Version 1.6.18beta01 [April 1, 2015] + Removed PNG_SET_CHUNK_[CACHE|MALLOC]_LIMIT_SUPPORTED macros. They + have been combined with PNG_SET_USER_LIMITS_SUPPORTED (resolves + bug report by Andrew Church). + Fixed rgb_to_gray checks and added tRNS checks to pngvalid.c. This + fixes some arithmetic errors that caused some tests to fail on + some 32-bit platforms (Bug reports by Peter Breitenlohner [i686] + and Petr Gajdos [i586]). + +Version 1.6.18beta02 [April 26, 2015] + Suppressed some warnings from the Borland C++ 5.5.1/5.82 compiler + (Bug report by Viktor Szakats). + +Version 1.6.18beta03 [May 6, 2015] + Replaced "unexpected" with an integer (0xabadca11) in pngset.c + where a long was expected, to avoid a compiler warning when PNG_DEBUG > 1. + Added contrib/examples/simpleover.c, to demonstrate how to handle + alpha compositing of multiple images, using the "simplified API" + and an example PNG generation tool, contrib/examples/genpng.c + (John Bowler). + +Version 1.6.18beta04 [May 20, 2015] + PNG_RELEASE_BUILD replaces tests where the code depended on the build base + type and can be defined on the command line, allowing testing in beta + builds (John Bowler). + Avoid Coverity issue 80858 (REVERSE NULL) in pngtest.c PNG_DEBUG builds. + Avoid a harmless potential integer overflow in png_XYZ_from_xy() (Bug + report from Christopher Ferris). + +Version 1.6.18beta05 [May 31, 2015] + Backport filter selection code from libpng-1.7.0beta51, to combine + sub_row, up_row, avg_row, and paeth_row into try_row and tst_row. + Changed png_voidcast(), etc., to voidcast(), etc., in contrib/tools/pngfix.c + to avoid confusion with the libpng private macros. + Fixed old cut&paste bug in the weighted filter selection code in + pngwutil.c, introduced in libpng-0.95, March 1997. + +Version 1.6.18beta06 [June 1, 2015] + Removed WRITE_WEIGHTED_FILTERED code, to save a few kbytes of the + compiled library size. It never worked properly and as far as we can + tell, no one uses it. The png_set_filter_heuristics() and + png_set_filter_heuristics_fixed() APIs are retained but deprecated + and do nothing. + +Version 1.6.18beta07 [June 6, 2015] + Removed non-working progressive reader 'skip' function. This + function has apparently never been used. It was implemented + to support back-door modification of png_struct in libpng-1.4.x + but (because it does nothing and cannot do anything) was apparently + never tested (John Bowler). + Fixed cexcept.h in which GCC 5 now reports that one of the auto + variables in the Try macro needs to be volatile to prevent value + being lost over the setjmp (John Bowler). + Fixed NO_WRITE_FILTER and -Wconversion build breaks (John Bowler). + Fix g++ build breaks (John Bowler). + Quieted some Coverity issues in pngfix.c, png-fix-itxt.c, pngvalid.c, + pngstest.c, and pngimage.c. Most seem harmless, but png-fix-itxt + would only work with iTXt chunks with length 255 or less. + Added #ifdef's to contrib/examples programs so people don't try + to compile them without the minimum required support enabled + (suggested by Flavio Medeiros). + +Version 1.6.18beta08 [June 30, 2015] + Eliminated the final two Coverity defects (insecure temporary file + handling in contrib/libtests/pngstest.c; possible overflow of + unsigned char in contrib/tools/png-fix-itxt.c). To use the "secure" + file handling, define PNG_USE_MKSTEMP, otherwise "tmpfile()" will + be used. + Removed some unused WEIGHTED_FILTER macros from png.h and pngstruct.h + +Version 1.6.18beta09 [July 5, 2015] + Removed some useless typecasts from contrib/tools/png-fix-itxt.c + Fixed a new signed-unsigned comparison in pngrtran.c (Max Stepin). + Replaced arbitrary use of 'extern' with #define PNG_LINKAGE_*. To + preserve API compatibility, the new defines all default to "extern" + (requested by Jan Nijtmans). + +Version 1.6.18rc01 [July 9, 2015] + Belatedly added Mans Rullgard and James Yu to the list of Contributing + Authors. + +Version 1.6.18rc02 [July 12, 2015] + Restored unused FILTER_HEURISTIC macros removed at libpng-1.6.18beta08 + to png.h to avoid compatibility warnings. + +Version 1.6.18rc03 [July 15, 2015] + Minor changes to the man page + +Version 1.6.18 [July 23, 2015] + No changes. + +Version 1.6.19beta01 [July 30, 2015] + Updated obsolete information about the simplified API macros in the + manual pages (Bug report by Arc Riley). + Avoid potentially dereferencing NULL info_ptr in png_info_init_3(). + Rearranged png.h to put the major sections in the same order as + in libpng17. + Eliminated unused PNG_COST_SHIFT, PNG_WEIGHT_SHIFT, PNG_COST_FACTOR, and + PNG_WEIGHT_FACTOR macros. + Suppressed some warnings from the Borland C++ 5.5.1/5.82 compiler + (Bug report by Viktor Szakats). Several warnings remain and are + unavoidable, where we test for overflow. + Fixed potential leak of png_pixels in contrib/pngminus/pnm2png.c + Fixed uninitialized variable in contrib/gregbook/rpng2-x.c + +Version 1.6.19beta02 [August 19, 2015] + Moved config.h.in~ from the "libpng_autotools_files" list to the + "libpng_autotools_extra" list in autogen.sh because it was causing a + false positive for missing files (bug report by Robert C. Seacord). + Removed unreachable "break" statements in png.c, pngread.c, and pngrtran.c + to suppress clang warnings (Bug report by Viktor Szakats). + Fixed some bad links in the man page. + Changed "n bit" to "n-bit" in comments. + Added signed/unsigned 16-bit safety net. This removes the dubious + 0x8000 flag definitions on 16-bit systems. They aren't supported + yet the defs *probably* work, however it seems much safer to do this + and be advised if anyone, contrary to advice, is building libpng 1.6 + on a 16-bit system. It also adds back various switch default clauses + for GCC; GCC errors out if they are not present (with an appropriately + high level of warnings). + Safely convert num_bytes to a png_byte in png_set_sig_bytes() (Robert + Seacord). + Fixed the recently reported 1's complement security issue by replacing + the value that is illegal in the PNG spec, in both signed and unsigned + values, with 0. Illegal unsigned values (anything greater than or equal + to 0x80000000) can still pass through, but since these are not illegal + in ANSI-C (unlike 0x80000000 in the signed case) the checking that + occurs later can catch them (John Bowler). + +Version 1.6.19beta03 [September 26, 2015] + Fixed png_save_int_32 when int is not 2's complement (John Bowler). + Updated libpng16 with all the recent test changes from libpng17, + including changes to pngvalid.c to ensure that the original, + distributed, version of contrib/visupng/cexcept.h can be used + (John Bowler). + pngvalid contains the correction to the use of SAVE/STORE_ + UNKNOWN_CHUNKS; a bug revealed by changes in libpng 1.7. More + tests contain the --strict option to detect warnings and the + pngvalid-standard test has been corrected so that it does not + turn on progressive-read. There is a separate test which does + that. (John Bowler) + Also made some signed/unsigned fixes. + Make pngstest error limits version specific. Splitting the machine + generated error structs out to a file allows the values to be updated + without changing pngstest.c itself. Since libpng 1.6 and 1.7 have + slightly different error limits this simplifies maintenance. The + makepngs.sh script has also been updated to more accurately reflect + current problems in libpng 1.7 (John Bowler). + Incorporated new test PNG files into make check. tests/pngstest-* + are changed so that the new test files are divided into 8 groups by + gamma and alpha channel. These tests have considerably better code + and pixel-value coverage than contrib/pngsuite; however,coverage is + still incomplete (John Bowler). + Removed the '--strict' in 1.6 because of the double-gamma-correction + warning, updated pngstest-errors.h for the errors detected with the + new contrib/testspngs PNG test files (John Bowler). + +Version 1.6.19beta04 [October 15, 2015] + Worked around rgb-to-gray issues in libpng 1.6. The previous + attempts to ignore the errors in the code aren't quite enough to + deal with the 'channel selection' encoding added to libpng 1.7; abort. + pngvalid.c is changed to drop this encoding in prior versions. + Fixed 'pow' macros in pngvalid.c. It is legal for 'pow' to be a + macro, therefore the argument list cannot contain preprocessing + directives. Make sure pow is a function where this happens. This is + a minimal safe fix, the issue only arises in non-performance-critical + code (bug report by Curtis Leach, fix by John Bowler). + Added sPLT support to pngtest.c + +Version 1.6.19rc01 [October 23, 2015] + No changes. + +Version 1.6.19rc02 [October 31, 2015] + Prevent setting or writing over-length PLTE chunk (Cosmin Truta). + Silently truncate over-length PLTE chunk while reading. + Libpng incorrectly calculated the output rowbytes when the application + decreased either the number of channels or the bit depth (or both) in + a user transform. This was safe; libpng overallocated buffer space + (potentially by quite a lot; up to 4 times the amount required) but, + from 1.5.4 on, resulted in a png_error (John Bowler). + +Version 1.6.19rc03 [November 3, 2015] + Fixed some inconsequential cut-and-paste typos in png_set_cHRM_XYZ_fixed(). + Clarified COPYRIGHT information to state explicitly that versions + are derived from previous versions. + Removed much of the long list of previous versions from png.h and + libpng.3. + +Version 1.6.19rc04 [November 5, 2015] + Fixed new bug with CRC error after reading an over-length palette + (bug report by Cosmin Truta) (CVE-2015-8126). + +Version 1.6.19 [November 12, 2015] + Cleaned up coding style in png_handle_PLTE(). + +Version 1.6.20beta01 [November 20, 2015] + Avoid potential pointer overflow/underflow in png_handle_sPLT() and + png_handle_pCAL() (Bug report by John Regehr). + +Version 1.6.20beta02 [November 23, 2015] + Fixed incorrect implementation of png_set_PLTE() that uses png_ptr + not info_ptr, that left png_set_PLTE() open to the CVE-2015-8126 + vulnerability. Fixes CVE-2015-8472. + +Version 1.6.20beta03 [November 24, 2015] + Backported tests from libpng-1.7.0beta69. + +Version 1.6.20rc01 [November 26, 2015] + Fixed an error in handling of bad zlib CMINFO field in pngfix, found by + American Fuzzy Lop, reported by Brian Carpenter. inflate() doesn't + immediately fault a bad CMINFO field; instead a 'too far back' error + happens later (at least some times). pngfix failed to limit CMINFO to + the allowed values but then assumed that window_bits was in range, + triggering an assert. The bug is mostly harmless; the PNG file cannot + be fixed. + +Version 1.6.20rc02 [November 29, 2015] + In libpng 1.6 zlib initialization was changed to use the window size + in the zlib stream, not a fixed value. This causes some invalid images, + where CINFO is too large, to display 'correctly' if the rest of the + data is valid. This provides a workaround for zlib versions where the + error arises (ones that support the API change to use the window size + in the stream). + +Version 1.6.20 [December 3, 2015] + No changes. + +Version 1.6.21beta01 [December 11, 2015] + Fixed syntax "$(command)" in tests/pngstest that some shells other than + bash could not parse (Bug report by Nelson Beebe). Use `command` instead. + +Version 1.6.21beta02 [December 14, 2015] + Moved png_check_keyword() from pngwutil.c to pngset.c + Removed LE/BE dependencies in pngvalid, to 'fix' the current problem + in the BigEndian tests by not testing it, making the BE code the same + as the LE version. + Fixes to pngvalid for various reduced build configurations (eliminate unused + statics) and a fix for the case in rgb_to_gray when the digitize option + reduces graylo to 0, producing a large error. + +Version 1.6.21beta03 [December 18, 2015] + Widened the 'limit' check on the internally calculated error limits in + the 'DIGITIZE' case (the code used prior to 1.7 for rgb_to_gray error + checks) and changed the check to only operate in non-release builds + (base build type not RC or RELEASE.) + Fixed undefined behavior in pngvalid.c, undefined because + (png_byte) << shift is undefined if it changes the signed bit + (because png_byte is promoted to int). The libpng exported functions + png_get_uint_32 and png_get_uint_16 handle this. (Bug reported by + David Drysdale as a result of reports from UBSAN in clang 3.8). + This changes pngvalid to use BE random numbers; this used to produce + errors but these should not be fixed as a result of the previous changes. + +Version 1.6.21rc01 [January 4, 2016] + In projects/vstudio, combined readme.txt and WARNING into README.txt + +Version 1.6.21rc02 [January 7, 2016] + Relocated assert() in contrib/tools/pngfix.c, bug found by American + Fuzzy Lop, reported by Brian Carpenter. + Marked 'limit' UNUSED in transform_range_check(). This only affects + release builds. + +Version 1.6.21 [January 15, 2016] + Worked around a false-positive Coverity issue in pngvalid.c. + +Version 1.6.22beta01 [January 23, 2016] + Changed PNG_USE_MKSTEMP to __COVERITY__ to select alternate + "tmpfile()" implementation in contrib/libtests/pngstest.c + Fixed NO_STDIO build of pngunknown.c to skip calling png_init_io() + if there is no stdio.h support. + Added a png_image_write_to_memory() API and a number of assist macros + to allow an application that uses the simplified API write to bypass + stdio and write directly to memory. + Added some warnings (png.h) and some check code to detect *possible* + overflow in the ROW_STRIDE and simplified image SIZE macros. This + disallows image width/height/format that *might* overflow. This is + a quiet API change that limits in-memory image size (uncompressed) to + less than 4GByte and image row size (stride) to less than 2GByte. + Revised workaround for false-positive Coverity issue in pngvalid.c. + +Version 1.6.22beta02 [February 8, 2016] + Only use exit(77) in configure builds. + Corrected error in PNG_IMAGE_PNG_SIZE_MAX. This new macro underreported + the palette size because it failed to take into account that the memory + palette has to be expanded to full RGB when it is written to PNG. + Updated CMakeLists.txt, added supporting scripts/gen*.cmake.in + and test.cmake.in (Roger Leigh). + Relaxed limit checks on gamma values in pngrtran.c. As suggested in + the comments gamma values outside the range currently permitted + by png_set_alpha_mode are useful for HDR data encoding. These values + are already permitted by png_set_gamma so it is reasonable caution to + extend the png_set_alpha_mode range as HDR imaging systems are starting + to emerge. + +Version 1.6.22beta03 [March 9, 2016] + Added a common-law trademark notice and export control information + to the LICENSE file, png.h, and the man page. + Restored "& 0xff" in png_save_uint_16() and png_save_uint_32() that + were accidentally removed from libpng-1.6.17. + Changed PNG_INFO_cHNK and PNG_FREE_cHNK from 0xnnnn to 0xnnnnU in png.h + (Robert C. Seacord). + Removed dubious "#if INT_MAX" test from png.h that was added to + libpng-1.6.19beta02 (John Bowler). + Add ${INCLUDES} in scripts/genout.cmake.in (Bug report by Nixon Kwok). + Updated LICENSE to say files in the contrib directory are not + necessarily under the libpng license, and that some makefiles have + other copyright owners. + Added INTEL-SSE2 support (Mike Klein and Matt Sarett, Google, Inc.). + Made contrib/libtests/timepng more robust. The code no longer gives + up/fails on invalid PNG data, it just skips it (with error messages). + The code no longer fails on PNG files with data beyond IEND. Options + exist to use png_read_png (reading the whole image, not by row) and, in + that case, to apply any of the supported transforms. This makes for + more realistic testing; the decoded data actually gets used in a + meaningful fashion (John Bowler). + Fixed some misleading indentation (Krishnaraj Bhat). + +Version 1.6.22beta04 [April 5, 2016] + Force GCC compilation to C89 if needed (Dagobert Michelsen). + SSE filter speed improvements for bpp=3: + memcpy-free implementations of load3() / store3(). + call load3() only when needed at the end of a scanline. + +Version 1.6.22beta05 [April 27, 2016] + Added PNG_FAST_FILTERS macro (defined as + PNG_FILTER_NONE|PNG_FILTER_SUB|PNG_FILTER_UP). + Various fixes for contrib/libtests/timepng.c + Moved INTEL-SSE code from pngpriv.h into contrib/intel/intel_sse.patch. + Fixed typo (missing underscore) in #define PNG_READ_16_TO_8_SUPPORTED + (Bug report by Y.Ohashik). + +Version 1.6.22beta06 [May 5, 2016] + Rebased contrib/intel_sse.patch. + Quieted two Coverity issues in contrib/libtests/timepng.c. + Fixed issues with scripts/genout.cmake.in (David Capello, Nixon Kwok): + Added support to use multiple directories in ZLIBINCDIR variable, + Fixed CMAKE_C_FLAGS with multiple values when genout is compiled on MSVC, + Fixed pnglibconf.c compilation on OS X including the sysroot path. + +Version 1.6.22rc01 [May 14, 2016] + No changes. + +Version 1.6.22rc02 [May 16, 2016] + Removed contrib/timepng from default build; it does not build on platforms + that don't supply clock_gettime(). + +Version 1.6.22rc03 [May 17, 2016] + Restored contrib/timepng to default build but check for the presence + of clock_gettime() in configure.ac and Makefile.am. + +Version 1.6.22 [May 26, 2016] + No changes. + +Version 1.6.23beta01 [May 29, 2016] + Stop a potential memory leak in png_set_tRNS() (Bug report by Ted Ying). + Fixed the progressive reader to handle empty first IDAT chunk properly + (patch by Timothy Nikkel). This bug was introduced in libpng-1.6.0 and + only affected the libpng16 branch. + Added tests in pngvalid.c to check zero-length IDAT chunks in various + positions. Fixed the sequential reader to handle these more robustly + (John Bowler). + +Version 1.6.23rc01 [June 2, 2016] + Corrected progressive read input buffer in pngvalid.c. The previous version + the code invariably passed just one byte at a time to libpng. The intent + was to pass a random number of bytes in the range 0..511. + Moved sse2 prototype from pngpriv.h to contrib/intel/intel_sse.patch. + Added missing ")" in pngerror.c (Matt Sarrett). + +Version 1.6.23rc02 [June 4, 2016] + Fixed undefined behavior in png_push_save_buffer(). Do not call + memcpy() with a null source, even if count is zero (Leon Scroggins III). + +Version 1.6.23 [June 9, 2016] + Fixed bad link to RFC2083 in png.5 (Nikola Forro). + +Send comments/corrections/commendations to png-mng-implement at lists.sf.net +(subscription required; visit +https://lists.sourceforge.net/lists/listinfo/png-mng-implement +to subscribe) +or to glennrp at users.sourceforge.net + +Glenn R-P +#endif diff --git a/source/Irrlicht/libpng/CMakeLists.txt b/source/Irrlicht/libpng/CMakeLists.txt new file mode 100644 index 00000000..ddc796b8 --- /dev/null +++ b/source/Irrlicht/libpng/CMakeLists.txt @@ -0,0 +1,804 @@ +# CMakeLists.txt + +# Copyright (C) 2007,2009-2016 Glenn Randers-Pehrson +# Written by Christian Ehrlicher, 2007 +# Revised by Roger Lowman, 2009-2010 +# Revised by Clifford Yapp, 2011-2012 +# Revised by Roger Leigh, 2016 + +# This code is released under the libpng license. +# For conditions of distribution and use, see the disclaimer +# and license in png.h + +cmake_minimum_required(VERSION 2.8.3) +cmake_policy(VERSION 2.8.3) + +# Set MacOSX @rpath usage globally. +if (POLICY CMP0020) + cmake_policy(SET CMP0020 NEW) +endif(POLICY CMP0020) +if (POLICY CMP0042) + cmake_policy(SET CMP0042 NEW) +endif(POLICY CMP0042) +# Use new variable expansion policy. +if (POLICY CMP0053) + cmake_policy(SET CMP0053 NEW) +endif(POLICY CMP0053) +if (POLICY CMP0054) + cmake_policy(SET CMP0054 NEW) +endif(POLICY CMP0054) + +set(CMAKE_CONFIGURATION_TYPES "Release;Debug;MinSizeRel;RelWithDebInfo") + +project(libpng C) +enable_testing() + +set(PNGLIB_MAJOR 1) +set(PNGLIB_MINOR 6) +set(PNGLIB_RELEASE 23) +set(PNGLIB_NAME libpng${PNGLIB_MAJOR}${PNGLIB_MINOR}) +set(PNGLIB_VERSION ${PNGLIB_MAJOR}.${PNGLIB_MINOR}.${PNGLIB_RELEASE}) + +# needed packages +find_package(ZLIB REQUIRED) +include_directories(${ZLIB_INCLUDE_DIR}) + +if(NOT WIN32) + find_library(M_LIBRARY + NAMES m + PATHS /usr/lib /usr/local/lib + ) + if(NOT M_LIBRARY) + message(STATUS "math lib 'libm' not found; floating point support disabled") + endif() +else() + # not needed on windows + set(M_LIBRARY "") +endif() + +# COMMAND LINE OPTIONS +option(PNG_SHARED "Build shared lib" ON) +option(PNG_STATIC "Build static lib" ON) +option(PNG_TESTS "Build libpng tests" ON) + +# Many more configuration options could be added here +option(PNG_FRAMEWORK "Build OS X framework" OFF) +option(PNG_DEBUG "Build with debug output" OFF) +option(PNGARG "Disable ANSI-C prototypes" OFF) + +set(PNG_PREFIX "" CACHE STRING "Prefix to add to the API function names") +set(DFA_XTRA "" CACHE FILEPATH "File containing extra configuration settings") + +# SET LIBNAME +set(PNG_LIB_NAME png${PNGLIB_MAJOR}${PNGLIB_MINOR}) + +# to distinguish between debug and release lib +set(CMAKE_DEBUG_POSTFIX "d") + +include(CheckCSourceCompiles) +option(ld-version-script "Enable linker version script" ON) +if(ld-version-script AND NOT APPLE) + # Check if LD supports linker scripts. + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/conftest.map" "VERS_1 { + global: sym; + local: *; +}; + +VERS_2 { + global: sym2; + main; +} VERS_1; +") + set(CMAKE_REQUIRED_FLAGS_SAVE ${CMAKE_REQUIRED_FLAGS}) + set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} "-Wl,--version-script='${CMAKE_CURRENT_BINARY_DIR}/conftest.map'") + check_c_source_compiles("void sym(void) {} +void sym2(void) {} +int main(void) {return 0;} +" HAVE_LD_VERSION_SCRIPT) + if(NOT HAVE_LD_VERSION_SCRIPT) + set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS_SAVE} "-Wl,-M -Wl,${CMAKE_CURRENT_BINARY_DIR}/conftest.map") + check_c_source_compiles("void sym(void) {} +void sym2(void) {} +int main(void) {return 0;} +" HAVE_SOLARIS_LD_VERSION_SCRIPT) + endif() + set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS_SAVE}) + file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/conftest.map") +endif() + +# Find symbol prefix. Likely obsolete and unnecessary with recent +# toolchains (it's not done in many other projects). +function(symbol_prefix) + set(SYMBOL_PREFIX) + + execute_process(COMMAND "${CMAKE_C_COMPILER}" "-E" "-" + INPUT_FILE /dev/null + OUTPUT_VARIABLE OUT + RESULT_VARIABLE STATUS) + + if(CPP_FAIL) + message(WARNING "Failed to run the C preprocessor") + endif() + + string(REPLACE "\n" ";" OUT "${OUT}") + foreach(line ${OUT}) + string(REGEX MATCH "^PREFIX=" found_match "${line}") + if(found_match) + STRING(REGEX REPLACE "^PREFIX=(.*\)" "\\1" prefix "${line}") + string(REGEX MATCH "__USER_LABEL_PREFIX__" found_match "${prefix}") + if(found_match) + STRING(REGEX REPLACE "(.*)__USER_LABEL_PREFIX__(.*)" "\\1\\2" prefix "${prefix}") + endif() + set(SYMBOL_PREFIX "${prefix}") + endif() + endforeach() + + message(STATUS "Symbol prefix: ${SYMBOL_PREFIX}") + set(SYMBOL_PREFIX "${SYMBOL_PREFIX}" PARENT_SCOPE) +endfunction() + +if(UNIX) + symbol_prefix() +endif() + +find_program(AWK NAMES gawk awk) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +if(NOT AWK) + # No awk available to generate sources; use pre-built pnglibconf.h + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/pnglibconf.h.prebuilt + ${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h) + add_custom_target(genfiles) # Dummy +else() + include(CMakeParseArguments) + # Generate .chk from .out with awk + # generate_chk(INPUT inputfile OUTPUT outputfile [DEPENDS dep1 [dep2...]]) + function(generate_chk) + set(options) + set(oneValueArgs INPUT OUTPUT) + set(multiValueArgs DEPENDS) + cmake_parse_arguments(_GC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + if (NOT _GC_INPUT) + message(FATAL_ERROR "Invalid arguments. generate_out requires input.") + endif() + if (NOT _GC_OUTPUT) + message(FATAL_ERROR "Invalid arguments. generate_out requires output.") + endif() + + add_custom_command(OUTPUT "${_GC_OUTPUT}" + COMMAND "${CMAKE_COMMAND}" + "-DINPUT=${_GC_INPUT}" + "-DOUTPUT=${_GC_OUTPUT}" + -P "${CMAKE_CURRENT_BINARY_DIR}/scripts/genchk.cmake" + DEPENDS "${_GC_INPUT}" ${_GC_DEPENDS} + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + endfunction() + + # Generate .out from .c with awk + # generate_out(INPUT inputfile OUTPUT outputfile [DEPENDS dep1 [dep2...]]) + function(generate_out) + set(options) + set(oneValueArgs INPUT OUTPUT) + set(multiValueArgs DEPENDS) + cmake_parse_arguments(_GO "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + if (NOT _GO_INPUT) + message(FATAL_ERROR "Invalid arguments. generate_out requires input.") + endif() + if (NOT _GO_OUTPUT) + message(FATAL_ERROR "Invalid arguments. generate_out requires output.") + endif() + + add_custom_command(OUTPUT "${_GO_OUTPUT}" + COMMAND "${CMAKE_COMMAND}" + "-DINPUT=${_GO_INPUT}" + "-DOUTPUT=${_GO_OUTPUT}" + -P "${CMAKE_CURRENT_BINARY_DIR}/scripts/genout.cmake" + DEPENDS "${_GO_INPUT}" ${_GO_DEPENDS} + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + endfunction() + + # Generate specific source file with awk + # generate_source(OUTPUT outputfile [DEPENDS dep1 [dep2...]]) + function(generate_source) + set(options) + set(oneValueArgs OUTPUT) + set(multiValueArgs DEPENDS) + cmake_parse_arguments(_GSO "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + if (NOT _GSO_OUTPUT) + message(FATAL_ERROR "Invalid arguments. generate_source requires output.") + endif() + + add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${_GSO_OUTPUT}" + COMMAND "${CMAKE_COMMAND}" + "-DOUTPUT=${_GSO_OUTPUT}" + -P "${CMAKE_CURRENT_BINARY_DIR}/scripts/gensrc.cmake" + DEPENDS ${_GSO_DEPENDS} + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + endfunction() + + # Copy file + function(generate_copy source destination) + add_custom_command(OUTPUT "${destination}" + COMMAND "${CMAKE_COMMAND}" -E remove "${destination}" + COMMAND "${CMAKE_COMMAND}" -E copy "${source}" + "${destination}" + DEPENDS "${source}") + endfunction() + + # Generate scripts/pnglibconf.h + generate_source(OUTPUT "scripts/pnglibconf.c" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/scripts/pnglibconf.dfa" + "${CMAKE_CURRENT_SOURCE_DIR}/scripts/options.awk" + "${CMAKE_CURRENT_SOURCE_DIR}/pngconf.h") + + # Generate pnglibconf.c + generate_source(OUTPUT "pnglibconf.c" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/scripts/pnglibconf.dfa" + "${CMAKE_CURRENT_SOURCE_DIR}/scripts/options.awk" + "${CMAKE_CURRENT_SOURCE_DIR}/pngconf.h") + + if(PNG_PREFIX) + set(PNGLIBCONF_H_EXTRA_DEPENDS + "${CMAKE_CURRENT_BINARY_DIR}/scripts/prefix.out" + "${CMAKE_CURRENT_SOURCE_DIR}/scripts/macro.lst") + set(PNGPREFIX_H_EXTRA_DEPENDS + "${CMAKE_CURRENT_BINARY_DIR}/scripts/intprefix.out") + endif() + + generate_out(INPUT "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.c" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.out") + + # Generate pnglibconf.h + generate_source(OUTPUT "pnglibconf.h" + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.out" + ${PNGLIBCONF_H_EXTRA_DEPENDS}) + + generate_out(INPUT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/intprefix.c" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/intprefix.out" + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h") + + generate_out(INPUT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/prefix.c" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/prefix.out" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/png.h" + "${CMAKE_CURRENT_SOURCE_DIR}/pngconf.h" + "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.out") + + # Generate pngprefix.h + generate_source(OUTPUT "pngprefix.h" + DEPENDS ${PNGPREFIX_H_EXTRA_DEPENDS}) + + generate_out(INPUT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/sym.c" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/sym.out" + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h") + + generate_out(INPUT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/symbols.c" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.out" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/png.h" + "${CMAKE_CURRENT_SOURCE_DIR}/pngconf.h" + "${CMAKE_CURRENT_SOURCE_DIR}/scripts/pnglibconf.h.prebuilt") + + generate_out(INPUT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/vers.c" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/vers.out" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/png.h" + "${CMAKE_CURRENT_SOURCE_DIR}/pngconf.h" + "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h") + + generate_chk(INPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.out" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.chk" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/scripts/checksym.awk" + "${CMAKE_CURRENT_SOURCE_DIR}/scripts/symbols.def") + + add_custom_target(symbol-check DEPENDS + "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.chk") + + generate_copy("${CMAKE_CURRENT_BINARY_DIR}/scripts/sym.out" + "${CMAKE_CURRENT_BINARY_DIR}/libpng.sym") + generate_copy("${CMAKE_CURRENT_BINARY_DIR}/scripts/vers.out" + "${CMAKE_CURRENT_BINARY_DIR}/libpng.vers") + + add_custom_target(genvers DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/libpng.vers") + add_custom_target(gensym DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/libpng.sym") + + add_custom_target("genprebuilt" + COMMAND "${CMAKE_COMMAND}" + "-DOUTPUT=scripts/pnglibconf.h.prebuilt" + -P "${CMAKE_CURRENT_BINARY_DIR}/scripts/gensrc.cmake" + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + + # A single target handles generation of all generated files. If + # they are dependend upon separately by multiple targets, this + # confuses parallel make (it would require a separate top-level + # target for each file to track the dependencies properly). + add_custom_target(genfiles DEPENDS + "${CMAKE_CURRENT_BINARY_DIR}/libpng.sym" + "${CMAKE_CURRENT_BINARY_DIR}/libpng.vers" + "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.c" + "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h" + "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.out" + "${CMAKE_CURRENT_BINARY_DIR}/pngprefix.h" + "${CMAKE_CURRENT_BINARY_DIR}/scripts/intprefix.out" + "${CMAKE_CURRENT_BINARY_DIR}/scripts/pnglibconf.c" + "${CMAKE_CURRENT_BINARY_DIR}/scripts/prefix.out" + "${CMAKE_CURRENT_BINARY_DIR}/scripts/sym.out" + "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.chk" + "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.out" + "${CMAKE_CURRENT_BINARY_DIR}/scripts/vers.out") +endif(NOT AWK) + +# OUR SOURCES +set(libpng_public_hdrs + png.h + pngconf.h + "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h" +) +set(libpng_private_hdrs + pngpriv.h + pngdebug.h + pnginfo.h + pngstruct.h +) +if(AWK) + list(APPEND libpng_private_hdrs "${CMAKE_CURRENT_BINARY_DIR}/pngprefix.h") +endif() +set(libpng_sources + ${libpng_public_hdrs} + ${libpng_private_hdrs} + png.c + pngerror.c + pngget.c + pngmem.c + pngpread.c + pngread.c + pngrio.c + pngrtran.c + pngrutil.c + pngset.c + pngtrans.c + pngwio.c + pngwrite.c + pngwtran.c + pngwutil.c +) +set(pngtest_sources + pngtest.c +) +set(pngvalid_sources + contrib/libtests/pngvalid.c +) +set(pngstest_sources + contrib/libtests/pngstest.c +) +set(pngunknown_sources + contrib/libtests/pngunknown.c +) +set(pngimage_sources + contrib/libtests/pngimage.c +) +set(pngfix_sources + contrib/tools/pngfix.c +) +set(png_fix_itxt_sources + contrib/tools/png-fix-itxt.c +) + +if(MSVC) + add_definitions(-D_CRT_SECURE_NO_DEPRECATE) +endif(MSVC) + +if(PNG_DEBUG) + add_definitions(-DPNG_DEBUG) +endif() + +# NOW BUILD OUR TARGET +include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${ZLIB_INCLUDE_DIR}) + +unset(PNG_LIB_TARGETS) + +if(PNG_SHARED) + add_library(png SHARED ${libpng_sources}) + set(PNG_LIB_TARGETS png) + set_target_properties(png PROPERTIES OUTPUT_NAME ${PNG_LIB_NAME}) + add_dependencies(png genfiles) + if(MSVC) + # msvc does not append 'lib' - do it here to have consistent name + set_target_properties(png PROPERTIES PREFIX "lib") + set_target_properties(png PROPERTIES IMPORT_PREFIX "lib") + endif() + target_link_libraries(png ${ZLIB_LIBRARY} ${M_LIBRARY}) + + if(UNIX AND AWK) + if(HAVE_LD_VERSION_SCRIPT) + set_target_properties(png PROPERTIES LINK_FLAGS + "-Wl,--version-script='${CMAKE_CURRENT_BINARY_DIR}/libpng.vers'") + elseif(HAVE_SOLARIS_LD_VERSION_SCRIPT) + set_target_properties(png PROPERTIES LINK_FLAGS + "-Wl,-M -Wl,'${CMAKE_CURRENT_BINARY_DIR}/libpng.vers'") + endif() + endif() +endif() + +if(PNG_STATIC) + # does not work without changing name + set(PNG_LIB_NAME_STATIC png_static) + add_library(png_static STATIC ${libpng_sources}) + add_dependencies(png_static genfiles) + # MSVC doesn't use a different file extension for shared vs. static + # libs. We are able to change OUTPUT_NAME to remove the _static + # for all other platforms. + if(NOT MSVC) + set_target_properties(png_static PROPERTIES + OUTPUT_NAME "${PNG_LIB_NAME}" + CLEAN_DIRECT_OUTPUT 1) + else() + set_target_properties(png_static PROPERTIES + OUTPUT_NAME "${PNG_LIB_NAME}_static" + CLEAN_DIRECT_OUTPUT 1) + endif() + list(APPEND PNG_LIB_TARGETS png_static) + if(MSVC) + # msvc does not append 'lib' - do it here to have consistent name + set_target_properties(png_static PROPERTIES PREFIX "lib") + endif() + target_link_libraries(png_static ${ZLIB_LIBRARY} ${M_LIBRARY}) +endif() + +if(PNG_FRAMEWORK) + set(PNG_LIB_NAME_FRAMEWORK png_framework) + add_library(png_framework SHARED ${libpng_sources}) + add_dependencies(png_framework genfiles) + list(APPEND PNG_LIB_TARGETS png_framework) + set_target_properties(png_framework PROPERTIES + FRAMEWORK TRUE + FRAMEWORK_VERSION ${PNGLIB_VERSION} + MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${PNGLIB_MAJOR}.${PNGLIB_MINOR} + MACOSX_FRAMEWORK_BUNDLE_VERSION ${PNGLIB_VERSION} + MACOSX_FRAMEWORK_IDENTIFIER org.libpng.libpng + XCODE_ATTRIBUTE_INSTALL_PATH "@rpath" + PUBLIC_HEADER "${libpng_public_hdrs}" + OUTPUT_NAME png) + target_link_libraries(png_framework ${ZLIB_LIBRARY} ${M_LIBRARY}) +endif() + +if(NOT PNG_LIB_TARGETS) + message(SEND_ERROR + "No library variant selected to build. " + "Please enable at least one of the following options: " + " PNG_STATIC, PNG_SHARED, PNG_FRAMEWORK") +endif() + +if(PNG_SHARED AND WIN32) + set_target_properties(png PROPERTIES DEFINE_SYMBOL PNG_BUILD_DLL) +endif() + +function(png_add_test) + set(options) + set(oneValueArgs NAME COMMAND) + set(multiValueArgs OPTIONS FILES) + cmake_parse_arguments(_PAT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if (NOT _PAT_NAME) + message(FATAL_ERROR "Invalid arguments. png_add_test requires name.") + endif() + if (NOT _PAT_COMMAND) + message(FATAL_ERROR "Invalid arguments. png_add_test requires command.") + endif() + + set(TEST_OPTIONS "${_PAT_OPTIONS}") + set(TEST_FILES "${_PAT_FILES}") + + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scripts/test.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/tests/${_PAT_NAME}.cmake" @ONLY) + if(CMAKE_MAJOR_VERSION GREATER 2) # have generator expressions + add_test(NAME "${_PAT_NAME}" + COMMAND "${CMAKE_COMMAND}" + "-DLIBPNG=$" + "-DTEST_COMMAND=$" + -P "${CMAKE_CURRENT_BINARY_DIR}/tests/${_PAT_NAME}.cmake") + else() # old 2.x add_test; limited and won't work well on Windows + # Note LIBPNG is a dummy value as there are no generator expressions + add_test("${_PAT_NAME}" "${CMAKE_COMMAND}" + "-DLIBPNG=${CMAKE_CURRENT_BINARY_DIR}/libpng.so" + "-DTEST_COMMAND=./${_PAT_COMMAND}" + -P "${CMAKE_CURRENT_BINARY_DIR}/tests/${_PAT_NAME}.cmake") + endif() +endfunction() + +if(PNG_TESTS AND PNG_SHARED) + # Find test PNG files by globbing, but sort lists to ensure + # consistency between different filesystems. + file(GLOB PNGSUITE_PNGS "${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/*.png") + list(SORT PNGSUITE_PNGS) + file(GLOB TEST_PNGS "${CMAKE_CURRENT_SOURCE_DIR}/contrib/testpngs/*.png") + list(SORT TEST_PNGS) + + set(PNGTEST_PNG "${CMAKE_CURRENT_SOURCE_DIR}/pngtest.png") + + add_executable(pngtest ${pngtest_sources}) + target_link_libraries(pngtest png) + + png_add_test(NAME pngtest COMMAND pngtest FILES "${PNGTEST_PNG}") + + add_executable(pngvalid ${pngvalid_sources}) + target_link_libraries(pngvalid png) + + png_add_test(NAME pngvalid-gamma-16-to-8 + COMMAND pngvalid OPTIONS --gamma-16-to-8) + png_add_test(NAME pngvalid-gamma-alpha-mode + COMMAND pngvalid OPTIONS --gamma-alpha-mode) + png_add_test(NAME pngvalid-gamma-background + COMMAND pngvalid OPTIONS --gamma-background) + png_add_test(NAME pngvalid-gamma-expand16-alpha-mode + COMMAND pngvalid OPTIONS --gamma-alpha-mode --expand16) + png_add_test(NAME pngvalid-gamma-expand16-background + COMMAND pngvalid OPTIONS --gamma-background --expand16) + png_add_test(NAME pngvalid-gamma-expand16-transform + COMMAND pngvalid OPTIONS --gamma-transform --expand16) + png_add_test(NAME pngvalid-gamma-sbit + COMMAND pngvalid OPTIONS --gamma-sbit) + png_add_test(NAME pngvalid-gamma-threshold + COMMAND pngvalid OPTIONS --gamma-threshold) + png_add_test(NAME pngvalid-gamma-transform + COMMAND pngvalid OPTIONS --gamma-transform) + png_add_test(NAME pngvalid-progressive-interlace-standard + COMMAND pngvalid OPTIONS --standard --progressive-read --interlace) + png_add_test(NAME pngvalid-progressive-size + COMMAND pngvalid OPTIONS --size --progressive-read) + png_add_test(NAME pngvalid-progressive-standard + COMMAND pngvalid OPTIONS --standard --progressive-read) + png_add_test(NAME pngvalid-standard + COMMAND pngvalid OPTIONS --standard) + png_add_test(NAME pngvalid-transform + COMMAND pngvalid OPTIONS --transform) + + add_executable(pngstest ${pngstest_sources}) + target_link_libraries(pngstest png) + + foreach(gamma_type 1.8 linear none sRGB) + foreach(alpha_type none alpha) + set(PNGSTEST_FILES) + foreach(test_png ${TEST_PNGS}) + string(REGEX MATCH ".*-linear[-.].*" TEST_PNG_LINEAR "${test_png}") + string(REGEX MATCH ".*-sRGB[-.].*" TEST_PNG_SRGB "${test_png}") + string(REGEX MATCH ".*-1.8[-.].*" TEST_PNG_G18 "${test_png}") + string(REGEX MATCH ".*-alpha-.*" TEST_PNG_ALPHA "${test_png}") + + set(TEST_PNG_VALID TRUE) + + if(TEST_PNG_ALPHA) + if (NOT "${alpha_type}" STREQUAL "alpha") + set(TEST_PNG_VALID FALSE) + endif() + else() + if ("${alpha_type}" STREQUAL "alpha") + set(TEST_PNG_VALID FALSE) + endif() + endif() + + if(TEST_PNG_LINEAR) + if(NOT "${gamma_type}" STREQUAL "linear") + set(TEST_PNG_VALID FALSE) + endif() + elseif(TEST_PNG_SRGB) + if(NOT "${gamma_type}" STREQUAL "sRGB") + set(TEST_PNG_VALID FALSE) + endif() + elseif(TEST_PNG_G18) + if(NOT "${gamma_type}" STREQUAL "1.8") + set(TEST_PNG_VALID FALSE) + endif() + else() + if(NOT "${gamma_type}" STREQUAL "none") + set(TEST_PNG_VALID FALSE) + endif() + endif() + + if(TEST_PNG_VALID) + list(APPEND PNGSTEST_FILES "${test_png}") + endif() + endforeach() + # Should already be sorted, but sort anyway to be certain. + list(SORT PNGSTEST_FILES) + png_add_test(NAME pngstest-${gamma_type}-${alpha_type} + COMMAND pngstest + OPTIONS --tmpfile "${gamma_type}-${alpha_type}-" --log + FILES ${PNGSTEST_FILES}) + endforeach() + endforeach() + + add_executable(pngunknown ${pngunknown_sources}) + target_link_libraries(pngunknown png) + + png_add_test(NAME pngunknown-discard COMMAND pngunknown OPTIONS --strict default=discard FILES "${PNGTEST_PNG}") + png_add_test(NAME pngunknown-IDAT COMMAND pngunknown OPTIONS --strict default=discard IDAT=save FILES "${PNGTEST_PNG}") + png_add_test(NAME pngunknown-if-safe COMMAND pngunknown OPTIONS --strict default=if-safe FILES "${PNGTEST_PNG}") + png_add_test(NAME pngunknown-sAPI COMMAND pngunknown OPTIONS --strict bKGD=save cHRM=save gAMA=save all=discard iCCP=save sBIT=save sRGB=save FILES "${PNGTEST_PNG}") + png_add_test(NAME pngunknown-save COMMAND pngunknown OPTIONS --strict default=save FILES "${PNGTEST_PNG}") + png_add_test(NAME pngunknown-sTER COMMAND pngunknown OPTIONS --strict sTER=if-safe FILES "${PNGTEST_PNG}") + png_add_test(NAME pngunknown-vpAg COMMAND pngunknown OPTIONS --strict vpAg=if-safe FILES "${PNGTEST_PNG}") + + add_executable(pngimage ${pngimage_sources}) + target_link_libraries(pngimage png) + + png_add_test(NAME pngimage-quick COMMAND pngimage OPTIONS --list-combos --log FILES ${PNGSUITE_PNGS}) + png_add_test(NAME pngimage-full COMMAND pngimage OPTIONS --exhaustive --list-combos --log FILES ${PNGSUITE_PNGS}) +endif() + +if(PNG_SHARED) + add_executable(pngfix ${pngfix_sources}) + target_link_libraries(pngfix png) + set(PNG_BIN_TARGETS pngfix) + + add_executable(png-fix-itxt ${png_fix_itxt_sources}) + target_link_libraries(png-fix-itxt ${ZLIB_LIBRARY} ${M_LIBRARY}) + list(APPEND PNG_BIN_TARGETS png-fix-itxt) +endif() + +# Ensure the CMAKE_LIBRARY_OUTPUT_DIRECTORY is set +IF(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) + SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "lib") +ENDIF(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) + +# Set a variable with CMake code which: +# Creates a symlink from src to dest (if possible) or alternatively +# copies if different. +macro(CREATE_SYMLINK SRC_FILE DEST_FILE) + FILE(REMOVE ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${DEST_FILE}) + if(WIN32 AND NOT CYGWIN AND NOT MSYS) + ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${DEST_FILE} ${CMAKE_CURRENT_BINARY_DIR}/${DEST_FILE} + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SRC_FILE}" ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${DEST_FILE} + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SRC_FILE}" ${CMAKE_CURRENT_BINARY_DIR}/${DEST_FILE} + DEPENDS ${PNG_LIB_TARGETS} + ) + ADD_CUSTOM_TARGET(${DEST_FILE}_COPY ALL DEPENDS ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${DEST_FILE}) + else(WIN32 AND NOT CYGWIN AND NOT MSYS) + get_filename_component(LINK_TARGET "${SRC_FILE}" NAME) + execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${LINK_TARGET}" ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${DEST_FILE} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${LINK_TARGET}" ${DEST_FILE} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + endif(WIN32 AND NOT CYGWIN AND NOT MSYS) +endmacro() + +# Create source generation scripts. +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/genchk.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/scripts/genchk.cmake @ONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/genout.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/scripts/genout.cmake @ONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/gensrc.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/scripts/gensrc.cmake @ONLY) + + +# libpng is a library so default to 'lib' +if(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR lib) +endif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + +# CREATE PKGCONFIG FILES +# we use the same files like ./configure, so we have to set its vars +# Only do this on Windows for Cygwin - the files don't make much sense outside +# a UNIX look alike +if(NOT WIN32 OR CYGWIN OR MINGW) + set(prefix ${CMAKE_INSTALL_PREFIX}) + set(exec_prefix ${CMAKE_INSTALL_PREFIX}) + set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) + set(includedir ${CMAKE_INSTALL_PREFIX}/include) + set(LIBS "-lz -lm") + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libpng.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}.pc @ONLY) + CREATE_SYMLINK(${PNGLIB_NAME}.pc libpng.pc) + + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libpng-config.in + ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config @ONLY) + CREATE_SYMLINK(${PNGLIB_NAME}-config libpng-config) +endif(NOT WIN32 OR CYGWIN OR MINGW) + +# SET UP LINKS +if(PNG_SHARED) + set_target_properties(png PROPERTIES +# VERSION 16.${PNGLIB_RELEASE}.1.6.23 + VERSION 16.${PNGLIB_RELEASE}.0 + SOVERSION 16 + CLEAN_DIRECT_OUTPUT 1) +endif() + +# If CMake > 2.4.x, we set a variable used below to export +# targets to an export file. +# TODO: Use VERSION_GREATER after our cmake_minimum_required >= 2.6.2 +if(CMAKE_MAJOR_VERSION GREATER 1 AND CMAKE_MINOR_VERSION GREATER 4) + set(PNG_EXPORT_RULE EXPORT libpng) +elseif(CMAKE_MAJOR_VERSION GREATER 2) # future proof + set(PNG_EXPORT_RULE EXPORT libpng) +endif() + +# INSTALL +if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL ) + install(TARGETS ${PNG_LIB_TARGETS} + ${PNG_EXPORT_RULE} + RUNTIME DESTINATION bin + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + if(PNG_SHARED) + # Create a symlink for libpng.dll.a => libpng16.dll.a on Cygwin + if(CYGWIN OR MINGW) + get_target_property(BUILD_TARGET_LOCATION png LOCATION_${CMAKE_BUILD_TYPE}) + CREATE_SYMLINK(${BUILD_TARGET_LOCATION} libpng${CMAKE_IMPORT_LIBRARY_SUFFIX}) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpng${CMAKE_IMPORT_LIBRARY_SUFFIX} + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(CYGWIN OR MINGW) + + if(NOT WIN32) + get_target_property(BUILD_TARGET_LOCATION png LOCATION_${CMAKE_BUILD_TYPE}) + CREATE_SYMLINK(${BUILD_TARGET_LOCATION} libpng${CMAKE_SHARED_LIBRARY_SUFFIX}) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpng${CMAKE_SHARED_LIBRARY_SUFFIX} + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(NOT WIN32) + endif(PNG_SHARED) + + if(PNG_STATIC) + if(NOT WIN32 OR CYGWIN OR MINGW) + get_target_property(BUILD_TARGET_LOCATION png_static LOCATION_${CMAKE_BUILD_TYPE}) + CREATE_SYMLINK(${BUILD_TARGET_LOCATION} libpng${CMAKE_STATIC_LIBRARY_SUFFIX}) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpng${CMAKE_STATIC_LIBRARY_SUFFIX} + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + endif(NOT WIN32 OR CYGWIN OR MINGW) + endif() +endif() + +if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL ) + install(FILES ${libpng_public_hdrs} DESTINATION include) + install(FILES ${libpng_public_hdrs} DESTINATION include/${PNGLIB_NAME}) +endif() +if(NOT SKIP_INSTALL_EXECUTABLES AND NOT SKIP_INSTALL_ALL ) + if(NOT WIN32 OR CYGWIN OR MINGW) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/libpng-config DESTINATION bin) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config + DESTINATION bin) + endif(NOT WIN32 OR CYGWIN OR MINGW) +endif() + +if(NOT SKIP_INSTALL_PROGRAMS AND NOT SKIP_INSTALL_ALL ) + install(TARGETS ${PNG_BIN_TARGETS} + RUNTIME DESTINATION bin) +endif() + +if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) + # Install man pages + if(NOT PNG_MAN_DIR) + set(PNG_MAN_DIR "share/man") + endif() + install(FILES libpng.3 libpngpf.3 DESTINATION ${PNG_MAN_DIR}/man3) + install(FILES png.5 DESTINATION ${PNG_MAN_DIR}/man5) + # Install pkg-config files + if(NOT WIN32 OR CYGWIN OR MINGW) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpng.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/libpng-config + DESTINATION bin) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config + DESTINATION bin) + endif(NOT WIN32 OR CYGWIN OR MINGW) +endif() + +# On versions of CMake that support it, create an export file CMake +# users can include() to import our targets +if(PNG_EXPORT_RULE AND NOT SKIP_INSTALL_EXPORT AND NOT SKIP_INSTALL_ALL ) + install(EXPORT libpng DESTINATION lib/libpng FILE lib${PNG_LIB_NAME}.cmake) +endif() + +# what's with libpng-manual.txt and all the extra files? + +# UNINSTALL +# do we need this? + +# DIST +# do we need this? + +# to create msvc import lib for mingw compiled shared lib +# pexports libpng.dll > libpng.def +# lib /def:libpng.def /machine:x86 + diff --git a/source/Irrlicht/libpng/INSTALL b/source/Irrlicht/libpng/INSTALL new file mode 100644 index 00000000..601a85b4 --- /dev/null +++ b/source/Irrlicht/libpng/INSTALL @@ -0,0 +1,389 @@ + +Installing libpng + +Contents + + I. Simple installation + II. Rebuilding the configure scripts + III. Using scripts/makefile* + IV. Using cmake + V. Directory structure + VI. Building with project files + VII. Building with makefiles +VIII. Configuring libpng for 16-bit platforms + IX. Configuring for DOS + X. Configuring for Medium Model + XI. Prepending a prefix to exported symbols + XII. Configuring for compiler xxx: +XIII. Removing unwanted object code + XIV. Changes to the build and configuration of libpng in libpng-1.5.x + XV. Setjmp/longjmp issues + XVI. Other sources of information about libpng + +I. Simple installation + +On Unix/Linux and similar systems, you can simply type + + ./configure [--prefix=/path] + make check + make install + +and ignore the rest of this document. "/path" is the path to the directory +where you want to install the libpng "lib", "include", and "bin" +subdirectories. + +If you downloaded a GIT clone, you will need to run ./autogen.sh before +running ./configure, to create "configure" and "Makefile.in" which are +not included in the GIT repository. + +Note that "configure" is only included in the "*.tar" distributions and not +in the "*.zip" or "*.7z" distributions. If you downloaded one of those +distributions, see "Building with project files" or "Building with makefiles", +below. + +II. Rebuilding the configure scripts + +If configure does not work on your system, or if you have a need to +change configure.ac or Makefile.am, and you have a reasonably +up-to-date set of tools, running ./autogen.sh in a git clone before +running ./configure may fix the problem. To be really sure that you +aren't using any of the included pre-built scripts, especially if you +are building from a tar distribution instead of a git distribution, +do this: + + ./configure --enable-maintainer-mode + make maintainer-clean + ./autogen.sh --maintainer --clean + ./autogen.sh --maintainer + ./configure [--prefix=/path] [other options] + make + make install + make check + +III. Using scripts/makefile* + +Instead, you can use one of the custom-built makefiles in the +"scripts" directory + + cp scripts/pnglibconf.h.prebuilt pnglibconf.h + cp scripts/makefile.system makefile + make test + make install + +The files that are presently available in the scripts directory +are listed and described in scripts/README.txt. + +Or you can use one of the "projects" in the "projects" directory. + +Before installing libpng, you must first install zlib, if it +is not already on your system. zlib can usually be found +wherever you got libpng; otherwise go to http://zlib.net. You can place +zlib in in the same directory as libpng or in another directory. + +If your system already has a preinstalled zlib you will still need +to have access to the zlib.h and zconf.h include files that +correspond to the version of zlib that's installed. + +If you wish to test with a particular zlib that is not first in the +standard library search path, put ZLIBLIB, ZLIBINC, CPPFLAGS, LDFLAGS, +and LD_LIBRARY_PATH in your environment before running "make test" +or "make distcheck": + +ZLIBLIB=/path/to/lib export ZLIBLIB +ZLIBINC=/path/to/include export ZLIBINC +CPPFLAGS="-I$ZLIBINC" export CPPFLAGS +LDFLAGS="-L$ZLIBLIB" export LDFLAGS +LD_LIBRARY_PATH="$ZLIBLIB:$LD_LIBRARY_PATH" export LD_LIBRARY_PATH + +If you are using one of the makefile scripts, put ZLIBLIB and ZLIBINC +in your environment and type "make ZLIBLIB=$ZLIBLIB ZLIBINC=$ZLIBINC test". + +IV. Using cmake + +If you want to use "cmake" (see www.cmake.org), type + + cmake . -DCMAKE_INSTALL_PREFIX=/path + make + make install + +As when using the simple configure method described above, "/path" points to +the installation directory where you want to put the libpng "lib", "include", +and "bin" subdirectories. + +V. Directory structure + +You can rename the directories that you downloaded (they +might be called "libpng-x.y.z" or "libpngNN" and "zlib-1.2.8" +or "zlib128") so that you have directories called "zlib" and "libpng". + +Your directory structure should look like this: + + .. (the parent directory) + libpng (this directory) + INSTALL (this file) + README + *.h, *.c => libpng source files + CMakeLists.txt => "cmake" script + configuration files: + configure.ac, configure, Makefile.am, Makefile.in, + autogen.sh, config.guess, ltmain.sh, missing, libpng.pc.in, + libpng-config.in, aclocal.m4, config.h.in, config.sub, + depcomp, install-sh, mkinstalldirs, test-pngtest.sh + contrib + arm-neon, conftest, examples, gregbook, libtests, pngminim, + pngminus, pngsuite, tools, visupng + projects + cbuilder5, owatcom, visualc71, vstudio, xcode + scripts + makefile.* + *.def (module definition files) + etc. + pngtest.png + etc. + zlib + README, *.h, *.c contrib, etc. + +If the line endings in the files look funny, you may wish to get the other +distribution of libpng. It is available in both tar.gz (UNIX style line +endings) and zip (DOS style line endings) formats. + +VI. Building with project files + +If you are building libpng with MSVC, you can enter the +libpng projects\visualc71 or vstudio directory and follow the instructions +in README.txt. + +Otherwise enter the zlib directory and follow the instructions in zlib/README, +then come back here and run "configure" or choose the appropriate +makefile.sys in the scripts directory. + +VII. Building with makefiles + +Copy the file (or files) that you need from the +scripts directory into this directory, for example + + MSDOS example: copy scripts\makefile.msc makefile + copy scripts\pnglibconf.h.prebuilt pnglibconf.h + UNIX example: cp scripts/makefile.std makefile + cp scripts/pnglibconf.h.prebuilt pnglibconf.h + +Read the makefile to see if you need to change any source or +target directories to match your preferences. + +Then read pnglibconf.dfa to see if you want to make any configuration +changes. + +Then just run "make" which will create the libpng library in +this directory and "make test" which will run a quick test that reads +the "pngtest.png" file and writes a "pngout.png" file that should be +identical to it. Look for "9782 zero samples" in the output of the +test. For more confidence, you can run another test by typing +"pngtest pngnow.png" and looking for "289 zero samples" in the output. +Also, you can run "pngtest -m contrib/pngsuite/*.png" and compare +your output with the result shown in contrib/pngsuite/README. + +Most of the makefiles will allow you to run "make install" to +put the library in its final resting place (if you want to +do that, run "make install" in the zlib directory first if necessary). +Some also allow you to run "make test-installed" after you have +run "make install". + +VIII. Configuring libpng for 16-bit platforms + +You will want to look into zconf.h to tell zlib (and thus libpng) that +it cannot allocate more than 64K at a time. Even if you can, the memory +won't be accessible. So limit zlib and libpng to 64K by defining MAXSEG_64K. + +IX. Configuring for DOS + +For DOS users who only have access to the lower 640K, you will +have to limit zlib's memory usage via a png_set_compression_mem_level() +call. See zlib.h or zconf.h in the zlib library for more information. + +X. Configuring for Medium Model + +Libpng's support for medium model has been tested on most of the popular +compilers. Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets +defined, and FAR gets defined to far in pngconf.h, and you should be +all set. Everything in the library (except for zlib's structure) is +expecting far data. You must use the typedefs with the p or pp on +the end for pointers (or at least look at them and be careful). Make +note that the rows of data are defined as png_bytepp, which is +an "unsigned char far * far *". + +XI. Prepending a prefix to exported symbols + +Starting with libpng-1.6.0, you can configure libpng (when using the +"configure" script) to prefix all exported symbols by means of the +configuration option "--with-libpng-prefix=FOO_", where FOO_ can be any +string beginning with a letter and containing only uppercase +and lowercase letters, digits, and the underscore (i.e., a C language +identifier). This creates a set of macros in pnglibconf.h, so this is +transparent to applications; their function calls get transformed by +the macros to use the modified names. + +XII. Configuring for compiler xxx: + +All includes for libpng are in pngconf.h. If you need to add, change +or delete an include, this is the place to do it. +The includes that are not needed outside libpng are placed in pngpriv.h, +which is only used by the routines inside libpng itself. +The files in libpng proper only include pngpriv.h and png.h, which +in turn includes pngconf.h and, as of libpng-1.5.0, pnglibconf.h. +As of libpng-1.5.0, pngpriv.h also includes three other private header +files, pngstruct.h, pnginfo.h, and pngdebug.h, which contain material +that previously appeared in the public headers. + +XIII. Removing unwanted object code + +There are a bunch of #define's in pngconf.h that control what parts of +libpng are compiled. All the defines end in _SUPPORTED. If you are +never going to use a capability, you can change the #define to #undef +before recompiling libpng and save yourself code and data space, or +you can turn off individual capabilities with defines that begin with +PNG_NO_. + +In libpng-1.5.0 and later, the #define's are in pnglibconf.h instead. + +You can also turn all of the transforms and ancillary chunk capabilities +off en masse with compiler directives that define +PNG_NO_READ[or WRITE]_TRANSFORMS, or PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS, +or all four, along with directives to turn on any of the capabilities that +you do want. The PNG_NO_READ[or WRITE]_TRANSFORMS directives disable the +extra transformations but still leave the library fully capable of reading +and writing PNG files with all known public chunks. Use of the +PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS directive produces a library +that is incapable of reading or writing ancillary chunks. If you are +not using the progressive reading capability, you can turn that off +with PNG_NO_PROGRESSIVE_READ (don't confuse this with the INTERLACING +capability, which you'll still have). + +All the reading and writing specific code are in separate files, so the +linker should only grab the files it needs. However, if you want to +make sure, or if you are building a stand alone library, all the +reading files start with "pngr" and all the writing files start with "pngw". +The files that don't match either (like png.c, pngtrans.c, etc.) +are used for both reading and writing, and always need to be included. +The progressive reader is in pngpread.c + +If you are creating or distributing a dynamically linked library (a .so +or DLL file), you should not remove or disable any parts of the library, +as this will cause applications linked with different versions of the +library to fail if they call functions not available in your library. +The size of the library itself should not be an issue, because only +those sections that are actually used will be loaded into memory. + +XIV. Changes to the build and configuration of libpng in libpng-1.5.x + +Details of internal changes to the library code can be found in the CHANGES +file and in the GIT repository logs. These will be of no concern to the vast +majority of library users or builders; however, the few who configure libpng +to a non-default feature set may need to change how this is done. + +There should be no need for library builders to alter build scripts if +these use the distributed build support - configure or the makefiles - +however, users of the makefiles may care to update their build scripts +to build pnglibconf.h where the corresponding makefile does not do so. + +Building libpng with a non-default configuration has changed completely. +The old method using pngusr.h should still work correctly even though the +way pngusr.h is used in the build has been changed; however, library +builders will probably want to examine the changes to take advantage of +new capabilities and to simplify their build system. + +A. Specific changes to library configuration capabilities + +The exact mechanism used to control attributes of API functions has +changed. A single set of operating system independent macro definitions +is used and operating system specific directives are defined in +pnglibconf.h + +As part of this the mechanism used to choose procedure call standards on +those systems that allow a choice has been changed. At present this only +affects certain Microsoft (DOS, Windows) and IBM (OS/2) operating systems +running on Intel processors. As before, PNGAPI is defined where required +to control the exported API functions; however, two new macros, PNGCBAPI +and PNGCAPI, are used instead for callback functions (PNGCBAPI) and +(PNGCAPI) for functions that must match a C library prototype (currently +only png_longjmp_ptr, which must match the C longjmp function.) The new +approach is documented in pngconf.h + +Despite these changes, libpng 1.5.0 only supports the native C function +calling standard on those platforms tested so far (__cdecl on Microsoft +Windows). This is because the support requirements for alternative +calling conventions seem to no longer exist. Developers who find it +necessary to set PNG_API_RULE to 1 should advise the mailing list +(png-mng-implement) of this and library builders who use Openwatcom and +therefore set PNG_API_RULE to 2 should also contact the mailing list. + +B. Changes to the configuration mechanism + +Prior to libpng-1.5.0 library builders who needed to configure libpng +had either to modify the exported pngconf.h header file to add system +specific configuration or had to write feature selection macros into +pngusr.h and cause this to be included into pngconf.h by defining +PNG_USER_CONFIG. The latter mechanism had the disadvantage that an +application built without PNG_USER_CONFIG defined would see the +unmodified, default, libpng API and thus would probably fail to link. + +These mechanisms still work in the configure build and in any makefile +build that builds pnglibconf.h, although the feature selection macros +have changed somewhat as described above. In 1.5.0, however, pngusr.h is +processed only once, at the time the exported header file pnglibconf.h is +built. pngconf.h no longer includes pngusr.h; therefore, pngusr.h is ignored +after the build of pnglibconf.h and it is never included in an application +build. + +The formerly used alternative of adding a list of feature macros to the +CPPFLAGS setting in the build also still works; however, the macros will be +copied to pnglibconf.h and this may produce macro redefinition warnings +when the individual C files are compiled. + +All configuration now only works if pnglibconf.h is built from +scripts/pnglibconf.dfa. This requires the program awk. Brian Kernighan +(the original author of awk) maintains C source code of that awk and this +and all known later implementations (often called by subtly different +names - nawk and gawk for example) are adequate to build pnglibconf.h. +The Sun Microsystems (now Oracle) program 'awk' is an earlier version +and does not work; this may also apply to other systems that have a +functioning awk called 'nawk'. + +Configuration options are now documented in scripts/pnglibconf.dfa. This +file also includes dependency information that ensures a configuration is +consistent; that is, if a feature is switched off, dependent features are +also switched off. As a recommended alternative to using feature macros in +pngusr.h a system builder may also define equivalent options in pngusr.dfa +(or, indeed, any file) and add that to the configuration by setting +DFA_XTRA to the file name. The makefiles in contrib/pngminim illustrate +how to do this, and also illustrate a case where pngusr.h is still required. + +After you have built libpng, the definitions that were recorded in +pnglibconf.h are available to your application (pnglibconf.h is included +in png.h and gets installed alongside png.h and pngconf.h in your +$PREFIX/include directory). Do not edit pnglibconf.h after you have built +libpng, because than the settings would not accurately reflect the settings +that were used to build libpng. + +XV. Setjmp/longjmp issues + +Libpng uses setjmp()/longjmp() for error handling. Unfortunately setjmp() +is known to be not thread-safe on some platforms and we don't know of +any platform where it is guaranteed to be thread-safe. Therefore, if +your application is going to be using multiple threads, you should +configure libpng with PNG_NO_SETJMP in your pngusr.dfa file, with +-DPNG_NO_SETJMP on your compile line, or with + + #undef PNG_SETJMP_SUPPORTED + +in your pnglibconf.h or pngusr.h. + +Starting with libpng-1.6.0, the library included a "simplified API". +This requires setjmp/longjmp, so you must either build the library +with PNG_SETJMP_SUPPORTED defined, or with PNG_SIMPLIFIED_READ_SUPPORTED +and PNG_SIMPLIFIED_WRITE_SUPPORTED undefined. + +XVI. Other sources of information about libpng: + +Further information can be found in the README and libpng-manual.txt +files, in the individual makefiles, in png.h, and the manual pages +libpng.3 and png.5. diff --git a/source/Irrlicht/libpng/LICENSE b/source/Irrlicht/libpng/LICENSE new file mode 100644 index 00000000..e4c9ecc7 --- /dev/null +++ b/source/Irrlicht/libpng/LICENSE @@ -0,0 +1,130 @@ + +This copy of the libpng notices is provided for your convenience. In case of +any discrepancy between this copy and the notices in the file png.h that is +included in the libpng distribution, the latter shall prevail. + +COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: + +If you modify libpng you may insert additional notices immediately following +this sentence. + +This code is released under the libpng license. + +libpng versions 1.0.7, July 1, 2000 through 1.6.23, June 9, 2016 are +Copyright (c) 2000-2002, 2004, 2006-2016 Glenn Randers-Pehrson, are +derived from libpng-1.0.6, and are distributed according to the same +disclaimer and license as libpng-1.0.6 with the following individuals +added to the list of Contributing Authors: + + Simon-Pierre Cadieux + Eric S. Raymond + Mans Rullgard + Cosmin Truta + Gilles Vollant + James Yu + +and with the following additions to the disclaimer: + + There is no warranty against interference with your enjoyment of the + library or against infringement. There is no warranty that our + efforts or the library will fulfill any of your particular purposes + or needs. This library is provided with all faults, and the entire + risk of satisfactory quality, performance, accuracy, and effort is with + the user. + +Some files in the "contrib" directory and some configure-generated +files that are distributed with libpng have other copyright owners and +are released under other open source licenses. + +libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are +Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from +libpng-0.96, and are distributed according to the same disclaimer and +license as libpng-0.96, with the following individuals added to the list +of Contributing Authors: + + Tom Lane + Glenn Randers-Pehrson + Willem van Schaik + +libpng versions 0.89, June 1996, through 0.96, May 1997, are +Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88, +and are distributed according to the same disclaimer and license as +libpng-0.88, with the following individuals added to the list of +Contributing Authors: + + John Bowler + Kevin Bracey + Sam Bushell + Magnus Holmgren + Greg Roelofs + Tom Tanner + +Some files in the "scripts" directory have other copyright owners +but are released under this license. + +libpng versions 0.5, May 1995, through 0.88, January 1996, are +Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + +For the purposes of this copyright and license, "Contributing Authors" +is defined as the following set of individuals: + + Andreas Dilger + Dave Martindale + Guy Eric Schalnat + Paul Schmidt + Tim Wegner + +The PNG Reference Library is supplied "AS IS". The Contributing Authors +and Group 42, Inc. disclaim all warranties, expressed or implied, +including, without limitation, the warranties of merchantability and of +fitness for any purpose. The Contributing Authors and Group 42, Inc. +assume no liability for direct, indirect, incidental, special, exemplary, +or consequential damages, which may result from the use of the PNG +Reference Library, even if advised of the possibility of such damage. + +Permission is hereby granted to use, copy, modify, and distribute this +source code, or portions hereof, for any purpose, without fee, subject +to the following restrictions: + + 1. The origin of this source code must not be misrepresented. + + 2. Altered versions must be plainly marked as such and must not + be misrepresented as being the original source. + + 3. This Copyright notice may not be removed or altered from any + source or altered source distribution. + +The Contributing Authors and Group 42, Inc. specifically permit, without +fee, and encourage the use of this source code as a component to +supporting the PNG file format in commercial products. If you use this +source code in a product, acknowledgment is not required but would be +appreciated. + +END OF COPYRIGHT NOTICE, DISCLAIMER, and LICENSE. + +TRADEMARK: + +The name "libpng" has not been registered by the Copyright owner +as a trademark in any jurisdiction. However, because libpng has +been distributed and maintained world-wide, continually since 1995, +the Copyright owner claims "common-law trademark protection" in any +jurisdiction where common-law trademark is recognized. + +OSI CERTIFICATION: + +Libpng is OSI Certified Open Source Software. OSI Certified Open Source is +a certification mark of the Open Source Initiative. OSI has not addressed +the additional disclaimers inserted at version 1.0.7. + +EXPORT CONTROL: + +The Copyright owner believes that the Export Control Classification +Number (ECCN) for libpng is EAR99, which means not subject to export +controls or International Traffic in Arms Regulations (ITAR) because +it is open source, publicly available software, that does not contain +any encryption software. See the EAR, paragraphs 734.3(b)(3) and +734.7(b). + +Glenn Randers-Pehrson +glennrp at users.sourceforge.net +June 9, 2016 diff --git a/source/Irrlicht/libpng/README b/source/Irrlicht/libpng/README new file mode 100644 index 00000000..8f615b74 --- /dev/null +++ b/source/Irrlicht/libpng/README @@ -0,0 +1,215 @@ +README for libpng version 1.6.23 - June 9, 2016 (shared library 16.0) +See the note about version numbers near the top of png.h + +See INSTALL for instructions on how to install libpng. + +Libpng comes in several distribution formats. Get libpng-*.tar.gz or +libpng-*.tar.xz or if you want UNIX-style line endings in the text files, +or lpng*.7z or lpng*.zip if you want DOS-style line endings. + +Version 0.89 was the first official release of libpng. Don't let the +fact that it's the first release fool you. The libpng library has been in +extensive use and testing since mid-1995. By late 1997 it had +finally gotten to the stage where there hadn't been significant +changes to the API in some time, and people have a bad feeling about +libraries with versions < 1.0. Version 1.0.0 was released in +March 1998. + +**** +Note that some of the changes to the png_info structure render this +version of the library binary incompatible with libpng-0.89 or +earlier versions if you are using a shared library. The type of the +"filler" parameter for png_set_filler() has changed from png_byte to +png_uint_32, which will affect shared-library applications that use +this function. + +To avoid problems with changes to the internals of png info_struct, +new APIs have been made available in 0.95 to avoid direct application +access to info_ptr. These functions are the png_set_ and +png_get_ functions. These functions should be used when +accessing/storing the info_struct data, rather than manipulating it +directly, to avoid such problems in the future. + +It is important to note that the APIs did not make current programs +that access the info struct directly incompatible with the new +library, through libpng-1.2.x. In libpng-1.4.x, which was meant to +be a transitional release, members of the png_struct and the +info_struct can still be accessed, but the compiler will issue a +warning about deprecated usage. Since libpng-1.5.0, direct access +to these structs is not allowed, and the definitions of the structs +reside in private pngstruct.h and pnginfo.h header files that are not +accessible to applications. It is strongly suggested that new +programs use the new APIs (as shown in example.c and pngtest.c), and +older programs be converted to the new format, to facilitate upgrades +in the future. +**** + +Additions since 0.90 include the ability to compile libpng as a +Windows DLL, and new APIs for accessing data in the info struct. +Experimental functions include the ability to set weighting and cost +factors for row filter selection, direct reads of integers from buffers +on big-endian processors that support misaligned data access, faster +methods of doing alpha composition, and more accurate 16->8 bit color +conversion. + +The additions since 0.89 include the ability to read from a PNG stream +which has had some (or all) of the signature bytes read by the calling +application. This also allows the reading of embedded PNG streams that +do not have the PNG file signature. As well, it is now possible to set +the library action on the detection of chunk CRC errors. It is possible +to set different actions based on whether the CRC error occurred in a +critical or an ancillary chunk. + +The changes made to the library, and bugs fixed are based on discussions +on the PNG-implement mailing list and not on material submitted +privately to Guy, Andreas, or Glenn. They will forward any good +suggestions to the list. + +For a detailed description on using libpng, read libpng-manual.txt. For +examples of libpng in a program, see example.c and pngtest.c. For usage +information and restrictions (what little they are) on libpng, see +png.h. For a description on using zlib (the compression library used by +libpng) and zlib's restrictions, see zlib.h + +I have included a general makefile, as well as several machine and +compiler specific ones, but you may have to modify one for your own needs. + +You should use zlib 1.0.4 or later to run this, but it MAY work with +versions as old as zlib 0.95. Even so, there are bugs in older zlib +versions which can cause the output of invalid compression streams for +some images. You will definitely need zlib 1.0.4 or later if you are +taking advantage of the MS-DOS "far" structure allocation for the small +and medium memory models. You should also note that zlib is a +compression library that is useful for more things than just PNG files. +You can use zlib as a drop-in replacement for fread() and fwrite() if +you are so inclined. + +zlib should be available at the same place that libpng is, or at zlib.net. + +You may also want a copy of the PNG specification. It is available +as an RFC, a W3C Recommendation, and an ISO/IEC Standard. You can find +these at http://www.libpng.org/pub/png/documents/ + +This code is currently being archived at libpng.sf.net in the +[DOWNLOAD] area, and at ftp://ftp.simplesystems.org. If you can't find it +in any of those places, e-mail me, and I'll help you find it. + +I am not a lawyer, but I believe that the Export Control Classification +Number (ECCN) for libpng is EAR99, which means not subject to export +controls or International Traffic in Arms Regulations (ITAR) because it +is open source, publicly available software, that does not contain any +encryption software. See the EAR, paragraphs 734.3(b)(3) and 734.7(b). + +If you have any code changes, requests, problems, etc., please e-mail +them to me. Also, I'd appreciate any make files or project files, +and any modifications you needed to make to get libpng to compile, +along with a #define variable to tell what compiler/system you are on. +If you needed to add transformations to libpng, or wish libpng would +provide the image in a different way, drop me a note (and code, if +possible), so I can consider supporting the transformation. +Finally, if you get any warning messages when compiling libpng +(note: not zlib), and they are easy to fix, I'd appreciate the +fix. Please mention "libpng" somewhere in the subject line. Thanks. + +This release was created and will be supported by myself (of course +based in a large way on Guy's and Andreas' earlier work), and the PNG +development group. + +Send comments/corrections/commendations to png-mng-implement at +lists.sourceforge.net (subscription required; visit +https://lists.sourceforge.net/lists/listinfo/png-mng-implement +to subscribe) or to glennrp at users.sourceforge.net + +You can't reach Guy, the original libpng author, at the addresses +given in previous versions of this document. He and Andreas will +read mail addressed to the png-implement list, however. + +Please do not send general questions about PNG. Send them to +png-mng-misc at lists.sf.net (subscription required; visit +https://lists.sourceforge.net/lists/listinfo/png-mng-misc to +subscribe). If you have a question about something +in the PNG specification that is related to using libpng, send it +to me. Send me any questions that start with "I was using libpng, +and ...". If in doubt, send questions to me. I'll bounce them +to others, if necessary. + +Please do not send suggestions on how to change PNG. We have +been discussing PNG for twenty years now, and it is official and +finished. If you have suggestions for libpng, however, I'll +gladly listen. Even if your suggestion is not used immediately, +it may be used later. + +Files in this distribution: + + ANNOUNCE => Announcement of this version, with recent changes + CHANGES => Description of changes between libpng versions + KNOWNBUG => List of known bugs and deficiencies + LICENSE => License to use and redistribute libpng + README => This file + TODO => Things not implemented in the current library + Y2KINFO => Statement of Y2K compliance + example.c => Example code for using libpng functions + libpng.3 => manual page for libpng (includes libpng-manual.txt) + libpng-manual.txt => Description of libpng and its functions + libpngpf.3 => manual page for libpng's private functions + png.5 => manual page for the PNG format + png.c => Basic interface functions common to library + png.h => Library function and interface declarations (public) + pngpriv.h => Library function and interface declarations (private) + pngconf.h => System specific library configuration (public) + pngstruct.h => png_struct declaration (private) + pnginfo.h => png_info struct declaration (private) + pngdebug.h => debugging macros (private) + pngerror.c => Error/warning message I/O functions + pngget.c => Functions for retrieving info from struct + pngmem.c => Memory handling functions + pngbar.png => PNG logo, 88x31 + pngnow.png => PNG logo, 98x31 + pngpread.c => Progressive reading functions + pngread.c => Read data/helper high-level functions + pngrio.c => Lowest-level data read I/O functions + pngrtran.c => Read data transformation functions + pngrutil.c => Read data utility functions + pngset.c => Functions for storing data into the info_struct + pngtest.c => Library test program + pngtest.png => Library test sample image + pngtrans.c => Common data transformation functions + pngwio.c => Lowest-level write I/O functions + pngwrite.c => High-level write functions + pngwtran.c => Write data transformations + pngwutil.c => Write utility functions + arm => Contains optimized code for the ARM platform + contrib => Contributions + examples => Example programs + gregbook => source code for PNG reading and writing, from + Greg Roelofs' "PNG: The Definitive Guide", + O'Reilly, 1999 + libtests => Test programs + pngminim => Minimal decoder, encoder, and progressive decoder + programs demonstrating use of pngusr.dfa + pngminus => Simple pnm2png and png2pnm programs + pngsuite => Test images + tools => Various tools + visupng => Contains a MSVC workspace for VisualPng + projects => Contains project files and workspaces for + building a DLL + owatcom => Contains a WATCOM project for building libpng + visualc71 => Contains a Microsoft Visual C++ (MSVC) + workspace for building libpng and zlib + vstudio => Contains a Microsoft Visual C++ (MSVC) + workspace for building libpng and zlib + scripts => Directory containing scripts for building libpng: + (see scripts/README.txt for the list of scripts) + +Good luck, and happy coding. + +-Glenn Randers-Pehrson (current maintainer, since 1998) + Internet: glennrp at users.sourceforge.net + +-Andreas Eric Dilger (former maintainer, 1996-1997) + Internet: adilger at enel.ucalgary.ca + Web: http://www-mddsp.enel.ucalgary.ca/People/adilger/ + +-Guy Eric Schalnat (original author and former maintainer, 1995-1996) + (formerly of Group 42, Inc) + Internet: gschal at infinet.com diff --git a/source/Irrlicht/libpng/TODO b/source/Irrlicht/libpng/TODO new file mode 100644 index 00000000..fc18bba9 --- /dev/null +++ b/source/Irrlicht/libpng/TODO @@ -0,0 +1,29 @@ +/* +TODO - list of things to do for libpng: + +Final bug fixes. +Better C++ wrapper/full C++ implementation? +Fix problem with C++ and EXTERN "C". +cHRM transformation. +Remove setjmp/longjmp usage in favor of returning error codes. +Palette creation. +Add "grayscale->palette" transformation and "palette->grayscale" detection. +Improved dithering. +Multi-lingual error and warning message support. +Complete sRGB transformation (presently it simply uses gamma=0.45455). +Make profile checking optional via a png_set_something() call. +Man pages for function calls. +Better documentation. +Better filter selection + (counting huffman bits/precompression? filter inertia? filter costs?). +Histogram creation. +Text conversion between different code pages (Latin-1 -> Mac and DOS). +Avoid building gamma tables whenever possible. +Use greater precision when changing to linear gamma for compositing against + background and doing rgb-to-gray transformation. +Investigate pre-incremented loop counters and other loop constructions. +Add interpolated method of handling interlacing. +Switch to the simpler zlib (zlib/libpng) license if legally possible. +Extend pngvalid.c to validate more of the libpng transformations. + +*/ diff --git a/source/Irrlicht/libpng/configure b/source/Irrlicht/libpng/configure new file mode 100644 index 00000000..0a32060c --- /dev/null +++ b/source/Irrlicht/libpng/configure @@ -0,0 +1,19 @@ + +echo " + There is no \"configure\" script in this distribution (*.zip or *.7z) of + libpng-1.6.23. + + Instead, please copy the appropriate makefile for your system from the + \"scripts\" directory. Read the INSTALL file for more details. + + Update, July 2004: you can get a \"configure\" based distribution + from the libpng distribution sites. Download the file + libpng-1.6.23.tar.gz or libpng-1.6.23.tar.xz. + + If the line endings in the files look funny, which is likely to be the + case if you were trying to run \"configure\" on a Linux machine, you may + wish to get the other distribution of libpng. It is available in both + tar.gz/tar.xz (UNIX style line endings, with \"configure\") and .7z/.zip + (DOS style line endings, without \"configure\") formats. +" + diff --git a/source/Irrlicht/libpng/example.c b/source/Irrlicht/libpng/example.c new file mode 100644 index 00000000..103e8cc3 --- /dev/null +++ b/source/Irrlicht/libpng/example.c @@ -0,0 +1,1061 @@ + +#if 0 /* in case someone actually tries to compile this */ + +/* example.c - an example of using libpng + * Last changed in libpng 1.6.15 [November 20, 2014] + * Maintained 1998-2014 Glenn Randers-Pehrson + * Maintained 1996, 1997 Andreas Dilger) + * Written 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * To the extent possible under law, the authors have waived + * all copyright and related or neighboring rights to this file. + * This work is published from: United States. + */ + +/* This is an example of how to use libpng to read and write PNG files. + * The file libpng-manual.txt is much more verbose then this. If you have not + * read it, do so first. This was designed to be a starting point of an + * implementation. This is not officially part of libpng, is hereby placed + * in the public domain, and therefore does not require a copyright notice. + * + * This file does not currently compile, because it is missing certain + * parts, like allocating memory to hold an image. You will have to + * supply these parts to get it to compile. For an example of a minimal + * working PNG reader/writer, see pngtest.c, included in this distribution; + * see also the programs in the contrib directory. + */ + +/* The simple, but restricted, approach to reading a PNG file or data stream + * just requires two function calls, as in the following complete program. + * Writing a file just needs one function call, so long as the data has an + * appropriate layout. + * + * The following code reads PNG image data from a file and writes it, in a + * potentially new format, to a new file. While this code will compile there is + * minimal (insufficient) error checking; for a more realistic version look at + * contrib/examples/pngtopng.c + */ +#include +#include +#include +#include +#include +#include + +int main(int argc, const char **argv) +{ + if (argc == 3) + { + png_image image; /* The control structure used by libpng */ + + /* Initialize the 'png_image' structure. */ + memset(&image, 0, (sizeof image)); + image.version = PNG_IMAGE_VERSION; + + /* The first argument is the file to read: */ + if (png_image_begin_read_from_file(&image, argv[1]) != 0) + { + png_bytep buffer; + + /* Set the format in which to read the PNG file; this code chooses a + * simple sRGB format with a non-associated alpha channel, adequate to + * store most images. + */ + image.format = PNG_FORMAT_RGBA; + + /* Now allocate enough memory to hold the image in this format; the + * PNG_IMAGE_SIZE macro uses the information about the image (width, + * height and format) stored in 'image'. + */ + buffer = malloc(PNG_IMAGE_SIZE(image)); + + /* If enough memory was available read the image in the desired format + * then write the result out to the new file. 'background' is not + * necessary when reading the image because the alpha channel is + * preserved; if it were to be removed, for example if we requested + * PNG_FORMAT_RGB, then either a solid background color would have to + * be supplied or the output buffer would have to be initialized to the + * actual background of the image. + * + * The fourth argument to png_image_finish_read is the 'row_stride' - + * this is the number of components allocated for the image in each + * row. It has to be at least as big as the value returned by + * PNG_IMAGE_ROW_STRIDE, but if you just allocate space for the + * default, minimum, size using PNG_IMAGE_SIZE as above you can pass + * zero. + * + * The final argument is a pointer to a buffer for the colormap; + * colormaps have exactly the same format as a row of image pixels (so + * you choose what format to make the colormap by setting + * image.format). A colormap is only returned if + * PNG_FORMAT_FLAG_COLORMAP is also set in image.format, so in this + * case NULL is passed as the final argument. If you do want to force + * all images into an index/color-mapped format then you can use: + * + * PNG_IMAGE_COLORMAP_SIZE(image) + * + * to find the maximum size of the colormap in bytes. + */ + if (buffer != NULL && + png_image_finish_read(&image, NULL/*background*/, buffer, + 0/*row_stride*/, NULL/*colormap*/) != 0) + { + /* Now write the image out to the second argument. In the write + * call 'convert_to_8bit' allows 16-bit data to be squashed down to + * 8 bits; this isn't necessary here because the original read was + * to the 8-bit format. + */ + if (png_image_write_to_file(&image, argv[2], 0/*convert_to_8bit*/, + buffer, 0/*row_stride*/, NULL/*colormap*/) != 0) + { + /* The image has been written successfully. */ + exit(0); + } + } + + else + { + /* Calling png_free_image is optional unless the simplified API was + * not run to completion. In this case if there wasn't enough + * memory for 'buffer' we didn't complete the read, so we must free + * the image: + */ + if (buffer == NULL) + png_free_image(&image); + + else + free(buffer); + } + + /* Something went wrong reading or writing the image. libpng stores a + * textual message in the 'png_image' structure: + */ + fprintf(stderr, "pngtopng: error: %s\n", image.message); + exit (1); + } + + fprintf(stderr, "pngtopng: usage: pngtopng input-file output-file\n"); + exit(1); +} + +/* That's it ;-) Of course you probably want to do more with PNG files than + * just converting them all to 32-bit RGBA PNG files; you can do that between + * the call to png_image_finish_read and png_image_write_to_file. You can also + * ask for the image data to be presented in a number of different formats. You + * do this by simply changing the 'format' parameter set before allocating the + * buffer. + * + * The format parameter consists of five flags that define various aspects of + * the image, you can simply add these together to get the format or you can use + * one of the predefined macros from png.h (as above): + * + * PNG_FORMAT_FLAG_COLOR: if set the image will have three color components per + * pixel (red, green and blue), if not set the image will just have one + * luminance (grayscale) component. + * + * PNG_FORMAT_FLAG_ALPHA: if set each pixel in the image will have an additional + * alpha value; a linear value that describes the degree the image pixel + * covers (overwrites) the contents of the existing pixel on the display. + * + * PNG_FORMAT_FLAG_LINEAR: if set the components of each pixel will be returned + * as a series of 16-bit linear values, if not set the components will be + * returned as a series of 8-bit values encoded according to the 'sRGB' + * standard. The 8-bit format is the normal format for images intended for + * direct display, because almost all display devices do the inverse of the + * sRGB transformation to the data they receive. The 16-bit format is more + * common for scientific data and image data that must be further processed; + * because it is linear simple math can be done on the component values. + * Regardless of the setting of this flag the alpha channel is always linear, + * although it will be 8 bits or 16 bits wide as specified by the flag. + * + * PNG_FORMAT_FLAG_BGR: if set the components of a color pixel will be returned + * in the order blue, then green, then red. If not set the pixel components + * are in the order red, then green, then blue. + * + * PNG_FORMAT_FLAG_AFIRST: if set the alpha channel (if present) precedes the + * color or grayscale components. If not set the alpha channel follows the + * components. + * + * You do not have to read directly from a file. You can read from memory or, + * on systems that support it, from a FILE*. This is controlled by + * the particular png_image_read_from_ function you call at the start. Likewise + * on write you can write to a FILE* if your system supports it. Check the + * macro PNG_STDIO_SUPPORTED to see if stdio support has been included in your + * libpng build. + * + * If you read 16-bit (PNG_FORMAT_FLAG_LINEAR) data you may need to write it in + * the 8-bit format for display. You do this by setting the convert_to_8bit + * flag to 'true'. + * + * Don't repeatedly convert between the 8-bit and 16-bit forms. There is + * significant data loss when 16-bit data is converted to the 8-bit encoding and + * the current libpng implementation of conversion to 16-bit is also + * significantly lossy. The latter will be fixed in the future, but the former + * is unavoidable - the 8-bit format just doesn't have enough resolution. + */ + +/* If your program needs more information from the PNG data it reads, or if you + * need to do more complex transformations, or minimize transformations, on the + * data you read, then you must use one of the several lower level libpng + * interfaces. + * + * All these interfaces require that you do your own error handling - your + * program must be able to arrange for control to return to your own code any + * time libpng encounters a problem. There are several ways to do this, but the + * standard way is to use the ANSI-C (C90) interface to establish a + * return point within your own code. You must do this if you do not use the + * simplified interface (above). + * + * The first step is to include the header files you need, including the libpng + * header file. Include any standard headers and feature test macros your + * program requires before including png.h: + */ +#include + + /* The png_jmpbuf() macro, used in error handling, became available in + * libpng version 1.0.6. If you want to be able to run your code with older + * versions of libpng, you must define the macro yourself (but only if it + * is not already defined by libpng!). + */ + +#ifndef png_jmpbuf +# define png_jmpbuf(png_ptr) ((png_ptr)->png_jmpbuf) +#endif + +/* Check to see if a file is a PNG file using png_sig_cmp(). png_sig_cmp() + * returns zero if the image is a PNG and nonzero if it isn't a PNG. + * + * The function check_if_png() shown here, but not used, returns nonzero (true) + * if the file can be opened and is a PNG, 0 (false) otherwise. + * + * If this call is successful, and you are going to keep the file open, + * you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once + * you have created the png_ptr, so that libpng knows your application + * has read that many bytes from the start of the file. Make sure you + * don't call png_set_sig_bytes() with more than 8 bytes read or give it + * an incorrect number of bytes read, or you will either have read too + * many bytes (your fault), or you are telling libpng to read the wrong + * number of magic bytes (also your fault). + * + * Many applications already read the first 2 or 4 bytes from the start + * of the image to determine the file type, so it would be easiest just + * to pass the bytes to png_sig_cmp() or even skip that if you know + * you have a PNG file, and call png_set_sig_bytes(). + */ +#define PNG_BYTES_TO_CHECK 4 +int check_if_png(char *file_name, FILE **fp) +{ + char buf[PNG_BYTES_TO_CHECK]; + + /* Open the prospective PNG file. */ + if ((*fp = fopen(file_name, "rb")) == NULL) + return 0; + + /* Read in some of the signature bytes */ + if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK) + return 0; + + /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature. + Return nonzero (true) if they match */ + + return(!png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK)); +} + +/* Read a PNG file. You may want to return an error code if the read + * fails (depending upon the failure). There are two "prototypes" given + * here - one where we are given the filename, and we need to open the + * file, and the other where we are given an open file (possibly with + * some or all of the magic bytes read - see comments above). + */ +#ifdef open_file /* prototype 1 */ +void read_png(char *file_name) /* We need to open the file */ +{ + png_structp png_ptr; + png_infop info_ptr; + int sig_read = 0; + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; + FILE *fp; + + if ((fp = fopen(file_name, "rb")) == NULL) + return (ERROR); + +#else no_open_file /* prototype 2 */ +void read_png(FILE *fp, int sig_read) /* File is already open */ +{ + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; +#endif no_open_file /* Only use one prototype! */ + + /* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also supply the + * the compiler header file version, so that we know if the application + * was compiled with a compatible version of the library. REQUIRED + */ + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + png_voidp user_error_ptr, user_error_fn, user_warning_fn); + + if (png_ptr == NULL) + { + fclose(fp); + return (ERROR); + } + + /* Allocate/initialize the memory for image information. REQUIRED. */ + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + fclose(fp); + png_destroy_read_struct(&png_ptr, NULL, NULL); + return (ERROR); + } + + /* Set error handling if you are using the setjmp/longjmp method (this is + * the normal method of doing things with libpng). REQUIRED unless you + * set up your own error handlers in the png_create_read_struct() earlier. + */ + + if (setjmp(png_jmpbuf(png_ptr))) + { + /* Free all of the memory associated with the png_ptr and info_ptr */ + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + fclose(fp); + /* If we get here, we had a problem reading the file */ + return (ERROR); + } + + /* One of the following I/O initialization methods is REQUIRED */ +#ifdef streams /* PNG file I/O method 1 */ + /* Set up the input control if you are using standard C streams */ + png_init_io(png_ptr, fp); + +#else no_streams /* PNG file I/O method 2 */ + /* If you are using replacement read functions, instead of calling + * png_init_io() here you would call: + */ + png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn); + /* where user_io_ptr is a structure you want available to the callbacks */ +#endif no_streams /* Use only one I/O method! */ + + /* If we have already read some of the signature */ + png_set_sig_bytes(png_ptr, sig_read); + +#ifdef hilevel + /* + * If you have enough memory to read in the entire image at once, + * and you need to specify only transforms that can be controlled + * with one of the PNG_TRANSFORM_* bits (this presently excludes + * quantizing, filling, setting background, and doing gamma + * adjustment), then you can read the entire image (including + * pixels) into the info structure with this call: + */ + png_read_png(png_ptr, info_ptr, png_transforms, NULL); + +#else + /* OK, you're doing it the hard way, with the lower-level functions */ + + /* The call to png_read_info() gives us all of the information from the + * PNG file before the first IDAT (image data chunk). REQUIRED + */ + png_read_info(png_ptr, info_ptr); + + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, + &interlace_type, NULL, NULL); + + /* Set up the data transformations you want. Note that these are all + * optional. Only call them if you want/need them. Many of the + * transformations only work on specific types of images, and many + * are mutually exclusive. + */ + + /* Tell libpng to strip 16 bits/color files down to 8 bits/color. + * Use accurate scaling if it's available, otherwise just chop off the + * low byte. + */ +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + png_set_scale_16(png_ptr); +#else + png_set_strip_16(png_ptr); +#endif + + /* Strip alpha bytes from the input data without combining with the + * background (not recommended). + */ + png_set_strip_alpha(png_ptr); + + /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single + * byte into separate bytes (useful for paletted and grayscale images). + */ + png_set_packing(png_ptr); + + /* Change the order of packed pixels to least significant bit first + * (not useful if you are using png_set_packing). */ + png_set_packswap(png_ptr); + + /* Expand paletted colors into true RGB triplets */ + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + + /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand_gray_1_2_4_to_8(png_ptr); + + /* Expand paletted or RGB images with transparency to full alpha channels + * so the data will be available as RGBA quartets. + */ + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) != 0) + png_set_tRNS_to_alpha(png_ptr); + + /* Set the background color to draw transparent and alpha images over. + * It is possible to set the red, green, and blue components directly + * for paletted images instead of supplying a palette index. Note that + * even if the PNG file supplies a background, you are not required to + * use it - you should use the (solid) application background if it has one. + */ + + png_color_16 my_background, *image_background; + + if (png_get_bKGD(png_ptr, info_ptr, &image_background) != 0) + png_set_background(png_ptr, image_background, + PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + else + png_set_background(png_ptr, &my_background, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + + /* Some suggestions as to how to get a screen gamma value + * + * Note that screen gamma is the display_exponent, which includes + * the CRT_exponent and any correction for viewing conditions + */ + if (/* We have a user-defined screen gamma value */) + { + screen_gamma = user-defined screen_gamma; + } + /* This is one way that applications share the same screen gamma value */ + else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL) + { + screen_gamma = atof(gamma_str); + } + /* If we don't have another value */ + else + { + screen_gamma = PNG_DEFAULT_sRGB; /* A good guess for a PC monitor + in a dimly lit room */ + screen_gamma = PNG_GAMMA_MAC_18 or 1.0; /* Good guesses for Mac systems */ + } + + /* Tell libpng to handle the gamma conversion for you. The final call + * is a good guess for PC generated images, but it should be configurable + * by the user at run time by the user. It is strongly suggested that + * your application support gamma correction. + */ + + int intent; + + if (png_get_sRGB(png_ptr, info_ptr, &intent) != 0) + png_set_gamma(png_ptr, screen_gamma, PNG_DEFAULT_sRGB); + else + { + double image_gamma; + if (png_get_gAMA(png_ptr, info_ptr, &image_gamma) != 0) + png_set_gamma(png_ptr, screen_gamma, image_gamma); + else + png_set_gamma(png_ptr, screen_gamma, 0.45455); + } + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + /* Quantize RGB files down to 8-bit palette or reduce palettes + * to the number of colors available on your screen. + */ + if ((color_type & PNG_COLOR_MASK_COLOR) != 0) + { + int num_palette; + png_colorp palette; + + /* This reduces the image to the application supplied palette */ + if (/* We have our own palette */) + { + /* An array of colors to which the image should be quantized */ + png_color std_color_cube[MAX_SCREEN_COLORS]; + + png_set_quantize(png_ptr, std_color_cube, MAX_SCREEN_COLORS, + MAX_SCREEN_COLORS, NULL, 0); + } + /* This reduces the image to the palette supplied in the file */ + else if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette) != 0) + { + png_uint_16p histogram = NULL; + + png_get_hIST(png_ptr, info_ptr, &histogram); + + png_set_quantize(png_ptr, palette, num_palette, + max_screen_colors, histogram, 0); + } + } +#endif /* READ_QUANTIZE */ + + /* Invert monochrome files to have 0 as white and 1 as black */ + png_set_invert_mono(png_ptr); + + /* If you want to shift the pixel values from the range [0,255] or + * [0,65535] to the original [0,7] or [0,31], or whatever range the + * colors were originally in: + */ + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT) != 0) + { + png_color_8p sig_bit_p; + + png_get_sBIT(png_ptr, info_ptr, &sig_bit_p); + png_set_shift(png_ptr, sig_bit_p); + } + + /* Flip the RGB pixels to BGR (or RGBA to BGRA) */ + if ((color_type & PNG_COLOR_MASK_COLOR) != 0) + png_set_bgr(png_ptr); + + /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ + png_set_swap_alpha(png_ptr); + + /* Swap bytes of 16-bit files to least significant byte first */ + png_set_swap(png_ptr); + + /* Add filler (or alpha) byte (before/after each RGB triplet) */ + png_set_filler(png_ptr, 0xffff, PNG_FILLER_AFTER); + +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Turn on interlace handling. REQUIRED if you are not using + * png_read_image(). To see how to handle interlacing passes, + * see the png_read_row() method below: + */ + number_passes = png_set_interlace_handling(png_ptr); +#else + number_passes = 1; +#endif /* READ_INTERLACING */ + + + /* Optional call to gamma correct and add the background to the palette + * and update info structure. REQUIRED if you are expecting libpng to + * update the palette for you (ie you selected such a transform above). + */ + png_read_update_info(png_ptr, info_ptr); + + /* Allocate the memory to hold the image using the fields of info_ptr. */ + + /* The easiest way to read the image: */ + png_bytep row_pointers[height]; + + /* Clear the pointer array */ + for (row = 0; row < height; row++) + row_pointers[row] = NULL; + + for (row = 0; row < height; row++) + row_pointers[row] = png_malloc(png_ptr, png_get_rowbytes(png_ptr, + info_ptr)); + + /* Now it's time to read the image. One of these methods is REQUIRED */ +#ifdef entire /* Read the entire image in one go */ + png_read_image(png_ptr, row_pointers); + +#else no_entire /* Read the image one or more scanlines at a time */ + /* The other way to read images - deal with interlacing: */ + + for (pass = 0; pass < number_passes; pass++) + { +#ifdef single /* Read the image a single row at a time */ + for (y = 0; y < height; y++) + { + png_read_rows(png_ptr, &row_pointers[y], NULL, 1); + } + +#else no_single /* Read the image several rows at a time */ + for (y = 0; y < height; y += number_of_rows) + { +#ifdef sparkle /* Read the image using the "sparkle" effect. */ + png_read_rows(png_ptr, &row_pointers[y], NULL, + number_of_rows); +#else no_sparkle /* Read the image using the "rectangle" effect */ + png_read_rows(png_ptr, NULL, &row_pointers[y], + number_of_rows); +#endif no_sparkle /* Use only one of these two methods */ + } + + /* If you want to display the image after every pass, do so here */ +#endif no_single /* Use only one of these two methods */ + } +#endif no_entire /* Use only one of these two methods */ + + /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ + png_read_end(png_ptr, info_ptr); +#endif hilevel + + /* At this point you have read the entire image */ + + /* Clean up after the read, and free any memory allocated - REQUIRED */ + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + + /* Close the file */ + fclose(fp); + + /* That's it */ + return (OK); +} + +/* Progressively read a file */ + +int +initialize_png_reader(png_structp *png_ptr, png_infop *info_ptr) +{ + /* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also check that + * the library version is compatible in case we are using dynamically + * linked libraries. + */ + *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + png_voidp user_error_ptr, user_error_fn, user_warning_fn); + + if (*png_ptr == NULL) + { + *info_ptr = NULL; + return (ERROR); + } + + *info_ptr = png_create_info_struct(png_ptr); + + if (*info_ptr == NULL) + { + png_destroy_read_struct(png_ptr, info_ptr, NULL); + return (ERROR); + } + + if (setjmp(png_jmpbuf((*png_ptr)))) + { + png_destroy_read_struct(png_ptr, info_ptr, NULL); + return (ERROR); + } + + /* This one's new. You will need to provide all three + * function callbacks, even if you aren't using them all. + * If you aren't using all functions, you can specify NULL + * parameters. Even when all three functions are NULL, + * you need to call png_set_progressive_read_fn(). + * These functions shouldn't be dependent on global or + * static variables if you are decoding several images + * simultaneously. You should store stream specific data + * in a separate struct, given as the second parameter, + * and retrieve the pointer from inside the callbacks using + * the function png_get_progressive_ptr(png_ptr). + */ + png_set_progressive_read_fn(*png_ptr, (void *)stream_data, + info_callback, row_callback, end_callback); + + return (OK); +} + +int +process_data(png_structp *png_ptr, png_infop *info_ptr, + png_bytep buffer, png_uint_32 length) +{ + if (setjmp(png_jmpbuf((*png_ptr)))) + { + /* Free the png_ptr and info_ptr memory on error */ + png_destroy_read_struct(png_ptr, info_ptr, NULL); + return (ERROR); + } + + /* This one's new also. Simply give it chunks of data as + * they arrive from the data stream (in order, of course). + * On segmented machines, don't give it any more than 64K. + * The library seems to run fine with sizes of 4K, although + * you can give it much less if necessary (I assume you can + * give it chunks of 1 byte, but I haven't tried with less + * than 256 bytes yet). When this function returns, you may + * want to display any rows that were generated in the row + * callback, if you aren't already displaying them there. + */ + png_process_data(*png_ptr, *info_ptr, buffer, length); + return (OK); +} + +info_callback(png_structp png_ptr, png_infop info) +{ + /* Do any setup here, including setting any of the transformations + * mentioned in the Reading PNG files section. For now, you _must_ + * call either png_start_read_image() or png_read_update_info() + * after all the transformations are set (even if you don't set + * any). You may start getting rows before png_process_data() + * returns, so this is your last chance to prepare for that. + */ +} + +row_callback(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass) +{ + /* + * This function is called for every row in the image. If the + * image is interlaced, and you turned on the interlace handler, + * this function will be called for every row in every pass. + * + * In this function you will receive a pointer to new row data from + * libpng called new_row that is to replace a corresponding row (of + * the same data format) in a buffer allocated by your application. + * + * The new row data pointer "new_row" may be NULL, indicating there is + * no new data to be replaced (in cases of interlace loading). + * + * If new_row is not NULL then you need to call + * png_progressive_combine_row() to replace the corresponding row as + * shown below: + */ + + /* Get pointer to corresponding row in our + * PNG read buffer. + */ + png_bytep old_row = ((png_bytep *)our_data)[row_num]; + +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* If both rows are allocated then copy the new row + * data to the corresponding row data. + */ + if ((old_row != NULL) && (new_row != NULL)) + png_progressive_combine_row(png_ptr, old_row, new_row); + + /* + * The rows and passes are called in order, so you don't really + * need the row_num and pass, but I'm supplying them because it + * may make your life easier. + * + * For the non-NULL rows of interlaced images, you must call + * png_progressive_combine_row() passing in the new row and the + * old row, as demonstrated above. You can call this function for + * NULL rows (it will just return) and for non-interlaced images + * (it just does the memcpy for you) if it will make the code + * easier. Thus, you can just do this for all cases: + */ + + png_progressive_combine_row(png_ptr, old_row, new_row); + + /* where old_row is what was displayed for previous rows. Note + * that the first pass (pass == 0 really) will completely cover + * the old row, so the rows do not have to be initialized. After + * the first pass (and only for interlaced images), you will have + * to pass the current row as new_row, and the function will combine + * the old row and the new row. + */ +#endif /* READ_INTERLACING */ +} + +end_callback(png_structp png_ptr, png_infop info) +{ + /* This function is called when the whole image has been read, + * including any chunks after the image (up to and including + * the IEND). You will usually have the same info chunk as you + * had in the header, although some data may have been added + * to the comments and time fields. + * + * Most people won't do much here, perhaps setting a flag that + * marks the image as finished. + */ +} + +/* Write a png file */ +void write_png(char *file_name /* , ... other image information ... */) +{ + FILE *fp; + png_structp png_ptr; + png_infop info_ptr; + png_colorp palette; + + /* Open the file */ + fp = fopen(file_name, "wb"); + if (fp == NULL) + return (ERROR); + + /* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also check that + * the library version is compatible with the one used at compile time, + * in case we are using dynamically linked libraries. REQUIRED. + */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + png_voidp user_error_ptr, user_error_fn, user_warning_fn); + + if (png_ptr == NULL) + { + fclose(fp); + return (ERROR); + } + + /* Allocate/initialize the image information data. REQUIRED */ + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + fclose(fp); + png_destroy_write_struct(&png_ptr, NULL); + return (ERROR); + } + + /* Set error handling. REQUIRED if you aren't supplying your own + * error handling functions in the png_create_write_struct() call. + */ + if (setjmp(png_jmpbuf(png_ptr))) + { + /* If we get here, we had a problem writing the file */ + fclose(fp); + png_destroy_write_struct(&png_ptr, &info_ptr); + return (ERROR); + } + + /* One of the following I/O initialization functions is REQUIRED */ + +#ifdef streams /* I/O initialization method 1 */ + /* Set up the output control if you are using standard C streams */ + png_init_io(png_ptr, fp); + +#else no_streams /* I/O initialization method 2 */ + /* If you are using replacement write functions, instead of calling + * png_init_io() here you would call + */ + png_set_write_fn(png_ptr, (void *)user_io_ptr, user_write_fn, + user_IO_flush_function); + /* where user_io_ptr is a structure you want available to the callbacks */ +#endif no_streams /* Only use one initialization method */ + +#ifdef hilevel + /* This is the easy way. Use it if you already have all the + * image info living in the structure. You could "|" many + * PNG_TRANSFORM flags into the png_transforms integer here. + */ + png_write_png(png_ptr, info_ptr, png_transforms, NULL); + +#else + /* This is the hard way */ + + /* Set the image information here. Width and height are up to 2^31, + * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on + * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, + * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, + * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or + * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST + * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED + */ + png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_???, + PNG_INTERLACE_????, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + /* Set the palette if there is one. REQUIRED for indexed-color images */ + palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH + * (sizeof (png_color))); + /* ... Set palette colors ... */ + png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); + /* You must not free palette here, because png_set_PLTE only makes a link to + * the palette that you malloced. Wait until you are about to destroy + * the png structure. + */ + + /* Optional significant bit (sBIT) chunk */ + png_color_8 sig_bit; + + /* If we are dealing with a grayscale image then */ + sig_bit.gray = true_bit_depth; + + /* Otherwise, if we are dealing with a color image then */ + sig_bit.red = true_red_bit_depth; + sig_bit.green = true_green_bit_depth; + sig_bit.blue = true_blue_bit_depth; + + /* If the image has an alpha channel then */ + sig_bit.alpha = true_alpha_bit_depth; + + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + + + /* Optional gamma chunk is strongly suggested if you have any guess + * as to the correct gamma of the image. + */ + png_set_gAMA(png_ptr, info_ptr, gamma); + + /* Optionally write comments into the image */ + { + png_text text_ptr[3]; + + char key0[]="Title"; + char text0[]="Mona Lisa"; + text_ptr[0].key = key0; + text_ptr[0].text = text0; + text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE; + text_ptr[0].itxt_length = 0; + text_ptr[0].lang = NULL; + text_ptr[0].lang_key = NULL; + + char key1[]="Author"; + char text1[]="Leonardo DaVinci"; + text_ptr[1].key = key1; + text_ptr[1].text = text1; + text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE; + text_ptr[1].itxt_length = 0; + text_ptr[1].lang = NULL; + text_ptr[1].lang_key = NULL; + + char key2[]="Description"; + char text2[]=""; + text_ptr[2].key = key2; + text_ptr[2].text = text2; + text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt; + text_ptr[2].itxt_length = 0; + text_ptr[2].lang = NULL; + text_ptr[2].lang_key = NULL; + + png_set_text(write_ptr, write_info_ptr, text_ptr, 3); + } + + /* Other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs */ + + /* Note that if sRGB is present the gAMA and cHRM chunks must be ignored + * on read and, if your application chooses to write them, they must + * be written in accordance with the sRGB profile + */ + + /* Write the file header information. REQUIRED */ + png_write_info(png_ptr, info_ptr); + + /* If you want, you can write the info in two steps, in case you need to + * write your private chunk ahead of PLTE: + * + * png_write_info_before_PLTE(write_ptr, write_info_ptr); + * write_my_chunk(); + * png_write_info(png_ptr, info_ptr); + * + * However, given the level of known- and unknown-chunk support in 1.2.0 + * and up, this should no longer be necessary. + */ + + /* Once we write out the header, the compression type on the text + * chunk gets changed to PNG_TEXT_COMPRESSION_NONE_WR or + * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again + * at the end. + */ + + /* Set up the transformations you want. Note that these are + * all optional. Only call them if you want them. + */ + + /* Invert monochrome pixels */ + png_set_invert_mono(png_ptr); + + /* Shift the pixels up to a legal bit depth and fill in + * as appropriate to correctly scale the image. + */ + png_set_shift(png_ptr, &sig_bit); + + /* Pack pixels into bytes */ + png_set_packing(png_ptr); + + /* Swap location of alpha bytes from ARGB to RGBA */ + png_set_swap_alpha(png_ptr); + + /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into + * RGB (4 channels -> 3 channels). The second parameter is not used. + */ + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); + + /* Flip BGR pixels to RGB */ + png_set_bgr(png_ptr); + + /* Swap bytes of 16-bit files to most significant byte first */ + png_set_swap(png_ptr); + + /* Swap bits of 1-bit, 2-bit, 4-bit packed pixel formats */ + png_set_packswap(png_ptr); + + /* Turn on interlace handling if you are not using png_write_image() */ + if (interlacing != 0) + number_passes = png_set_interlace_handling(png_ptr); + + else + number_passes = 1; + + /* The easiest way to write the image (you may have a different memory + * layout, however, so choose what fits your needs best). You need to + * use the first method if you aren't handling interlacing yourself. + */ + png_uint_32 k, height, width; + + /* In this example, "image" is a one-dimensional array of bytes */ + png_byte image[height*width*bytes_per_pixel]; + + png_bytep row_pointers[height]; + + if (height > PNG_UINT_32_MAX/(sizeof (png_bytep))) + png_error (png_ptr, "Image is too tall to process in memory"); + + /* Set up pointers into your "image" byte array */ + for (k = 0; k < height; k++) + row_pointers[k] = image + k*width*bytes_per_pixel; + + /* One of the following output methods is REQUIRED */ + +#ifdef entire /* Write out the entire image data in one call */ + png_write_image(png_ptr, row_pointers); + + /* The other way to write the image - deal with interlacing */ + +#else no_entire /* Write out the image data by one or more scanlines */ + + /* The number of passes is either 1 for non-interlaced images, + * or 7 for interlaced images. + */ + for (pass = 0; pass < number_passes; pass++) + { + /* Write a few rows at a time. */ + png_write_rows(png_ptr, &row_pointers[first_row], number_of_rows); + + /* If you are only writing one row at a time, this works */ + for (y = 0; y < height; y++) + png_write_rows(png_ptr, &row_pointers[y], 1); + } +#endif no_entire /* Use only one output method */ + + /* You can write optional chunks like tEXt, zTXt, and tIME at the end + * as well. Shouldn't be necessary in 1.2.0 and up as all the public + * chunks are supported and you can use png_set_unknown_chunks() to + * register unknown chunks into the info structure to be written out. + */ + + /* It is REQUIRED to call this to finish writing the rest of the file */ + png_write_end(png_ptr, info_ptr); +#endif hilevel + + /* If you png_malloced a palette, free it here (don't free info_ptr->palette, + * as recommended in versions 1.0.5m and earlier of this example; if + * libpng mallocs info_ptr->palette, libpng will free it). If you + * allocated it with malloc() instead of png_malloc(), use free() instead + * of png_free(). + */ + png_free(png_ptr, palette); + palette = NULL; + + /* Similarly, if you png_malloced any data that you passed in with + * png_set_something(), such as a hist or trans array, free it here, + * when you can be sure that libpng is through with it. + */ + png_free(png_ptr, trans); + trans = NULL; + /* Whenever you use png_free() it is a good idea to set the pointer to + * NULL in case your application inadvertently tries to png_free() it + * again. When png_free() sees a NULL it returns without action, thus + * avoiding the double-free security problem. + */ + + /* Clean up after the write, and free any memory allocated */ + png_destroy_write_struct(&png_ptr, &info_ptr); + + /* Close the file */ + fclose(fp); + + /* That's it */ + return (OK); +} + +#endif /* if 0 */ diff --git a/source/Irrlicht/libpng/libpng-config.in b/source/Irrlicht/libpng/libpng-config.in new file mode 100644 index 00000000..199ad876 --- /dev/null +++ b/source/Irrlicht/libpng/libpng-config.in @@ -0,0 +1,127 @@ +#! /bin/sh + +# libpng-config +# provides configuration info for libpng. + +# Copyright (C) 2002, 2004, 2006, 2007 Glenn Randers-Pehrson + +# This code is released under the libpng license. +# For conditions of distribution and use, see the disclaimer +# and license in png.h + +# Modeled after libxml-config. + +version="@PNGLIB_VERSION@" +prefix="@prefix@" +exec_prefix="@exec_prefix@" +libdir="@libdir@" +includedir="@includedir@/libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@" +libs="-lpng@PNGLIB_MAJOR@@PNGLIB_MINOR@" +all_libs="-lpng@PNGLIB_MAJOR@@PNGLIB_MINOR@ @LIBS@" +I_opts="-I${includedir}" +L_opts="-L${libdir}" +R_opts="" +cppflags="" +ccopts="" +ldopts="" + +usage() +{ + cat < + Copyright (c) 1998-2016 Glenn Randers-Pehrson + + This document is released under the libpng license. + For conditions of distribution and use, see the disclaimer + and license in png.h + + Based on: + + libpng versions 0.97, January 1998, through 1.6.23 - June 9, 2016 + Updated and distributed by Glenn Randers-Pehrson + Copyright (c) 1998-2016 Glenn Randers-Pehrson + + libpng 1.0 beta 6 - version 0.96 - May 28, 1997 + Updated and distributed by Andreas Dilger + Copyright (c) 1996, 1997 Andreas Dilger + + libpng 1.0 beta 2 - version 0.88 - January 26, 1996 + For conditions of distribution and use, see copyright + notice in png.h. Copyright (c) 1995, 1996 Guy Eric + Schalnat, Group 42, Inc. + + Updated/rewritten per request in the libpng FAQ + Copyright (c) 1995, 1996 Frank J. T. Wojcik + December 18, 1995 & January 20, 1996 + + TABLE OF CONTENTS + + I. Introduction + II. Structures + III. Reading + IV. Writing + V. Simplified API + VI. Modifying/Customizing libpng + VII. MNG support + VIII. Changes to Libpng from version 0.88 + IX. Changes to Libpng from version 1.0.x to 1.2.x + X. Changes to Libpng from version 1.0.x/1.2.x to 1.4.x + XI. Changes to Libpng from version 1.4.x to 1.5.x + XII. Changes to Libpng from version 1.5.x to 1.6.x + XIII. Detecting libpng + XIV. Source code repository + XV. Coding style + XVI. Y2K Compliance in libpng + +I. Introduction + +This file describes how to use and modify the PNG reference library +(known as libpng) for your own use. In addition to this +file, example.c is a good starting point for using the library, as +it is heavily commented and should include everything most people +will need. We assume that libpng is already installed; see the +INSTALL file for instructions on how to configure and install libpng. + +For examples of libpng usage, see the files "example.c", "pngtest.c", +and the files in the "contrib" directory, all of which are included in +the libpng distribution. + +Libpng was written as a companion to the PNG specification, as a way +of reducing the amount of time and effort it takes to support the PNG +file format in application programs. + +The PNG specification (second edition), November 2003, is available as +a W3C Recommendation and as an ISO Standard (ISO/IEC 15948:2004 (E)) at +. +It is technically equivalent +to the PNG specification (second edition) but has some additional material. + +The PNG-1.0 specification is available as RFC 2083 + and as a +W3C Recommendation . + +Some additional chunks are described in the special-purpose public chunks +documents at + +Other information +about PNG, and the latest version of libpng, can be found at the PNG home +page, . + +Most users will not have to modify the library significantly; advanced +users may want to modify it more. All attempts were made to make it as +complete as possible, while keeping the code easy to understand. +Currently, this library only supports C. Support for other languages +is being considered. + +Libpng has been designed to handle multiple sessions at one time, +to be easily modifiable, to be portable to the vast majority of +machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy +to use. The ultimate goal of libpng is to promote the acceptance of +the PNG file format in whatever way possible. While there is still +work to be done (see the TODO file), libpng should cover the +majority of the needs of its users. + +Libpng uses zlib for its compression and decompression of PNG files. +Further information about zlib, and the latest version of zlib, can +be found at the zlib home page, . +The zlib compression utility is a general purpose utility that is +useful for more than PNG files, and can be used without libpng. +See the documentation delivered with zlib for more details. +You can usually find the source files for the zlib utility wherever you +find the libpng source files. + +Libpng is thread safe, provided the threads are using different +instances of the structures. Each thread should have its own +png_struct and png_info instances, and thus its own image. +Libpng does not protect itself against two threads using the +same instance of a structure. + +II. Structures + +There are two main structures that are important to libpng, png_struct +and png_info. Both are internal structures that are no longer exposed +in the libpng interface (as of libpng 1.5.0). + +The png_info structure is designed to provide information about the +PNG file. At one time, the fields of png_info were intended to be +directly accessible to the user. However, this tended to cause problems +with applications using dynamically loaded libraries, and as a result +a set of interface functions for png_info (the png_get_*() and png_set_*() +functions) was developed, and direct access to the png_info fields was +deprecated.. + +The png_struct structure is the object used by the library to decode a +single image. As of 1.5.0 this structure is also not exposed. + +Almost all libpng APIs require a pointer to a png_struct as the first argument. +Many (in particular the png_set and png_get APIs) also require a pointer +to png_info as the second argument. Some application visible macros +defined in png.h designed for basic data access (reading and writing +integers in the PNG format) don't take a png_info pointer, but it's almost +always safe to assume that a (png_struct*) has to be passed to call an API +function. + +You can have more than one png_info structure associated with an image, +as illustrated in pngtest.c, one for information valid prior to the +IDAT chunks and another (called "end_info" below) for things after them. + +The png.h header file is an invaluable reference for programming with libpng. +And while I'm on the topic, make sure you include the libpng header file: + +#include + +and also (as of libpng-1.5.0) the zlib header file, if you need it: + +#include + +Types + +The png.h header file defines a number of integral types used by the +APIs. Most of these are fairly obvious; for example types corresponding +to integers of particular sizes and types for passing color values. + +One exception is how non-integral numbers are handled. For application +convenience most APIs that take such numbers have C (double) arguments; +however, internally PNG, and libpng, use 32 bit signed integers and encode +the value by multiplying by 100,000. As of libpng 1.5.0 a convenience +macro PNG_FP_1 is defined in png.h along with a type (png_fixed_point) +which is simply (png_int_32). + +All APIs that take (double) arguments also have a matching API that +takes the corresponding fixed point integer arguments. The fixed point +API has the same name as the floating point one with "_fixed" appended. +The actual range of values permitted in the APIs is frequently less than +the full range of (png_fixed_point) (-21474 to +21474). When APIs require +a non-negative argument the type is recorded as png_uint_32 above. Consult +the header file and the text below for more information. + +Special care must be take with sCAL chunk handling because the chunk itself +uses non-integral values encoded as strings containing decimal floating point +numbers. See the comments in the header file. + +Configuration + +The main header file function declarations are frequently protected by C +preprocessing directives of the form: + + #ifdef PNG_feature_SUPPORTED + declare-function + #endif + ... + #ifdef PNG_feature_SUPPORTED + use-function + #endif + +The library can be built without support for these APIs, although a +standard build will have all implemented APIs. Application programs +should check the feature macros before using an API for maximum +portability. From libpng 1.5.0 the feature macros set during the build +of libpng are recorded in the header file "pnglibconf.h" and this file +is always included by png.h. + +If you don't need to change the library configuration from the default, skip to +the next section ("Reading"). + +Notice that some of the makefiles in the 'scripts' directory and (in 1.5.0) all +of the build project files in the 'projects' directory simply copy +scripts/pnglibconf.h.prebuilt to pnglibconf.h. This means that these build +systems do not permit easy auto-configuration of the library - they only +support the default configuration. + +The easiest way to make minor changes to the libpng configuration when +auto-configuration is supported is to add definitions to the command line +using (typically) CPPFLAGS. For example: + +CPPFLAGS=-DPNG_NO_FLOATING_ARITHMETIC + +will change the internal libpng math implementation for gamma correction and +other arithmetic calculations to fixed point, avoiding the need for fast +floating point support. The result can be seen in the generated pnglibconf.h - +make sure it contains the changed feature macro setting. + +If you need to make more extensive configuration changes - more than one or two +feature macro settings - you can either add -DPNG_USER_CONFIG to the build +command line and put a list of feature macro settings in pngusr.h or you can set +DFA_XTRA (a makefile variable) to a file containing the same information in the +form of 'option' settings. + +A. Changing pnglibconf.h + +A variety of methods exist to build libpng. Not all of these support +reconfiguration of pnglibconf.h. To reconfigure pnglibconf.h it must either be +rebuilt from scripts/pnglibconf.dfa using awk or it must be edited by hand. + +Hand editing is achieved by copying scripts/pnglibconf.h.prebuilt to +pnglibconf.h and changing the lines defining the supported features, paying +very close attention to the 'option' information in scripts/pnglibconf.dfa +that describes those features and their requirements. This is easy to get +wrong. + +B. Configuration using DFA_XTRA + +Rebuilding from pnglibconf.dfa is easy if a functioning 'awk', or a later +variant such as 'nawk' or 'gawk', is available. The configure build will +automatically find an appropriate awk and build pnglibconf.h. +The scripts/pnglibconf.mak file contains a set of make rules for doing the +same thing if configure is not used, and many of the makefiles in the scripts +directory use this approach. + +When rebuilding simply write a new file containing changed options and set +DFA_XTRA to the name of this file. This causes the build to append the new file +to the end of scripts/pnglibconf.dfa. The pngusr.dfa file should contain lines +of the following forms: + +everything = off + +This turns all optional features off. Include it at the start of pngusr.dfa to +make it easier to build a minimal configuration. You will need to turn at least +some features on afterward to enable either reading or writing code, or both. + +option feature on +option feature off + +Enable or disable a single feature. This will automatically enable other +features required by a feature that is turned on or disable other features that +require a feature which is turned off. Conflicting settings will cause an error +message to be emitted by awk. + +setting feature default value + +Changes the default value of setting 'feature' to 'value'. There are a small +number of settings listed at the top of pnglibconf.h, they are documented in the +source code. Most of these values have performance implications for the library +but most of them have no visible effect on the API. Some can also be overridden +from the API. + +This method of building a customized pnglibconf.h is illustrated in +contrib/pngminim/*. See the "$(PNGCONF):" target in the makefile and +pngusr.dfa in these directories. + +C. Configuration using PNG_USER_CONFIG + +If -DPNG_USER_CONFIG is added to the CPPFLAGS when pnglibconf.h is built, +the file pngusr.h will automatically be included before the options in +scripts/pnglibconf.dfa are processed. Your pngusr.h file should contain only +macro definitions turning features on or off or setting settings. + +Apart from the global setting "everything = off" all the options listed above +can be set using macros in pngusr.h: + +#define PNG_feature_SUPPORTED + +is equivalent to: + +option feature on + +#define PNG_NO_feature + +is equivalent to: + +option feature off + +#define PNG_feature value + +is equivalent to: + +setting feature default value + +Notice that in both cases, pngusr.dfa and pngusr.h, the contents of the +pngusr file you supply override the contents of scripts/pnglibconf.dfa + +If confusing or incomprehensible behavior results it is possible to +examine the intermediate file pnglibconf.dfn to find the full set of +dependency information for each setting and option. Simply locate the +feature in the file and read the C comments that precede it. + +This method is also illustrated in the contrib/pngminim/* makefiles and +pngusr.h. + +III. Reading + +We'll now walk you through the possible functions to call when reading +in a PNG file sequentially, briefly explaining the syntax and purpose +of each one. See example.c and png.h for more detail. While +progressive reading is covered in the next section, you will still +need some of the functions discussed in this section to read a PNG +file. + +Setup + +You will want to do the I/O initialization(*) before you get into libpng, +so if it doesn't work, you don't have much to undo. Of course, you +will also want to insure that you are, in fact, dealing with a PNG +file. Libpng provides a simple check to see if a file is a PNG file. +To use it, pass in the first 1 to 8 bytes of the file to the function +png_sig_cmp(), and it will return 0 (false) if the bytes match the +corresponding bytes of the PNG signature, or nonzero (true) otherwise. +Of course, the more bytes you pass in, the greater the accuracy of the +prediction. + +If you are intending to keep the file pointer open for use in libpng, +you must ensure you don't read more than 8 bytes from the beginning +of the file, and you also have to make a call to png_set_sig_bytes() +with the number of bytes you read from the beginning. Libpng will +then only check the bytes (if any) that your program didn't read. + +(*): If you are not using the standard I/O functions, you will need +to replace them with custom functions. See the discussion under +Customizing libpng. + + FILE *fp = fopen(file_name, "rb"); + if (!fp) + { + return (ERROR); + } + + if (fread(header, 1, number, fp) != number) + { + return (ERROR); + } + + is_png = !png_sig_cmp(header, 0, number); + if (!is_png) + { + return (NOT_PNG); + } + +Next, png_struct and png_info need to be allocated and initialized. In +order to ensure that the size of these structures is correct even with a +dynamically linked libpng, there are functions to initialize and +allocate the structures. We also pass the library version, optional +pointers to error handling functions, and a pointer to a data struct for +use by the error functions, if necessary (the pointer and functions can +be NULL if the default error handlers are to be used). See the section +on Changes to Libpng below regarding the old initialization functions. +The structure allocation functions quietly return NULL if they fail to +create the structure, so your application should check for that. + + png_structp png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + + if (!png_ptr) + return (ERROR); + + png_infop info_ptr = png_create_info_struct(png_ptr); + + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, + (png_infopp)NULL, (png_infopp)NULL); + return (ERROR); + } + +If you want to use your own memory allocation routines, +use a libpng that was built with PNG_USER_MEM_SUPPORTED defined, and use +png_create_read_struct_2() instead of png_create_read_struct(): + + png_structp png_ptr = png_create_read_struct_2 + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn, (png_voidp) + user_mem_ptr, user_malloc_fn, user_free_fn); + +The error handling routines passed to png_create_read_struct() +and the memory alloc/free routines passed to png_create_struct_2() +are only necessary if you are not using the libpng supplied error +handling and memory alloc/free functions. + +When libpng encounters an error, it expects to longjmp back +to your routine. Therefore, you will need to call setjmp and pass +your png_jmpbuf(png_ptr). If you read the file from different +routines, you will need to update the longjmp buffer every time you enter +a new routine that will call a png_*() function. + +See your documentation of setjmp/longjmp for your compiler for more +information on setjmp/longjmp. See the discussion on libpng error +handling in the Customizing Libpng section below for more information +on the libpng error handling. If an error occurs, and libpng longjmp's +back to your setjmp, you will want to call png_destroy_read_struct() to +free any memory. + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + &end_info); + fclose(fp); + return (ERROR); + } + +Pass (png_infopp)NULL instead of &end_info if you didn't create +an end_info structure. + +If you would rather avoid the complexity of setjmp/longjmp issues, +you can compile libpng with PNG_NO_SETJMP, in which case +errors will result in a call to PNG_ABORT() which defaults to abort(). + +You can #define PNG_ABORT() to a function that does something +more useful than abort(), as long as your function does not +return. + +Now you need to set up the input code. The default for libpng is to +use the C function fread(). If you use this, you will need to pass a +valid FILE * in the function png_init_io(). Be sure that the file is +opened in binary mode. If you wish to handle reading data in another +way, you need not call the png_init_io() function, but you must then +implement the libpng I/O methods discussed in the Customizing Libpng +section below. + + png_init_io(png_ptr, fp); + +If you had previously opened the file and read any of the signature from +the beginning in order to see if this was a PNG file, you need to let +libpng know that there are some bytes missing from the start of the file. + + png_set_sig_bytes(png_ptr, number); + +You can change the zlib compression buffer size to be used while +reading compressed data with + + png_set_compression_buffer_size(png_ptr, buffer_size); + +where the default size is 8192 bytes. Note that the buffer size +is changed immediately and the buffer is reallocated immediately, +instead of setting a flag to be acted upon later. + +If you want CRC errors to be handled in a different manner than +the default, use + + png_set_crc_action(png_ptr, crit_action, ancil_action); + +The values for png_set_crc_action() say how libpng is to handle CRC errors in +ancillary and critical chunks, and whether to use the data contained +therein. Note that it is impossible to "discard" data in a critical +chunk. + +Choices for (int) crit_action are + PNG_CRC_DEFAULT 0 error/quit + PNG_CRC_ERROR_QUIT 1 error/quit + PNG_CRC_WARN_USE 3 warn/use data + PNG_CRC_QUIET_USE 4 quiet/use data + PNG_CRC_NO_CHANGE 5 use the current value + +Choices for (int) ancil_action are + PNG_CRC_DEFAULT 0 error/quit + PNG_CRC_ERROR_QUIT 1 error/quit + PNG_CRC_WARN_DISCARD 2 warn/discard data + PNG_CRC_WARN_USE 3 warn/use data + PNG_CRC_QUIET_USE 4 quiet/use data + PNG_CRC_NO_CHANGE 5 use the current value + +Setting up callback code + +You can set up a callback function to handle any unknown chunks in the +input stream. You must supply the function + + read_chunk_callback(png_structp png_ptr, + png_unknown_chunkp chunk); + { + /* The unknown chunk structure contains your + chunk data, along with similar data for any other + unknown chunks: */ + + png_byte name[5]; + png_byte *data; + png_size_t size; + + /* Note that libpng has already taken care of + the CRC handling */ + + /* put your code here. Search for your chunk in the + unknown chunk structure, process it, and return one + of the following: */ + + return (-n); /* chunk had an error */ + return (0); /* did not recognize */ + return (n); /* success */ + } + +(You can give your function another name that you like instead of +"read_chunk_callback") + +To inform libpng about your function, use + + png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, + read_chunk_callback); + +This names not only the callback function, but also a user pointer that +you can retrieve with + + png_get_user_chunk_ptr(png_ptr); + +If you call the png_set_read_user_chunk_fn() function, then all unknown +chunks which the callback does not handle will be saved when read. You can +cause them to be discarded by returning '1' ("handled") instead of '0'. This +behavior will change in libpng 1.7 and the default handling set by the +png_set_keep_unknown_chunks() function, described below, will be used when the +callback returns 0. If you want the existing behavior you should set the global +default to PNG_HANDLE_CHUNK_IF_SAFE now; this is compatible with all current +versions of libpng and with 1.7. Libpng 1.6 issues a warning if you keep the +default, or PNG_HANDLE_CHUNK_NEVER, and the callback returns 0. + +At this point, you can set up a callback function that will be +called after each row has been read, which you can use to control +a progress meter or the like. It's demonstrated in pngtest.c. +You must supply a function + + void read_row_callback(png_structp png_ptr, + png_uint_32 row, int pass); + { + /* put your code here */ + } + +(You can give it another name that you like instead of "read_row_callback") + +To inform libpng about your function, use + + png_set_read_status_fn(png_ptr, read_row_callback); + +When this function is called the row has already been completely processed and +the 'row' and 'pass' refer to the next row to be handled. For the +non-interlaced case the row that was just handled is simply one less than the +passed in row number, and pass will always be 0. For the interlaced case the +same applies unless the row value is 0, in which case the row just handled was +the last one from one of the preceding passes. Because interlacing may skip a +pass you cannot be sure that the preceding pass is just 'pass-1', if you really +need to know what the last pass is record (row,pass) from the callback and use +the last recorded value each time. + +As with the user transform you can find the output row using the +PNG_ROW_FROM_PASS_ROW macro. + +Unknown-chunk handling + +Now you get to set the way the library processes unknown chunks in the +input PNG stream. Both known and unknown chunks will be read. Normal +behavior is that known chunks will be parsed into information in +various info_ptr members while unknown chunks will be discarded. This +behavior can be wasteful if your application will never use some known +chunk types. To change this, you can call: + + png_set_keep_unknown_chunks(png_ptr, keep, + chunk_list, num_chunks); + + keep - 0: default unknown chunk handling + 1: ignore; do not keep + 2: keep only if safe-to-copy + 3: keep even if unsafe-to-copy + + You can use these definitions: + PNG_HANDLE_CHUNK_AS_DEFAULT 0 + PNG_HANDLE_CHUNK_NEVER 1 + PNG_HANDLE_CHUNK_IF_SAFE 2 + PNG_HANDLE_CHUNK_ALWAYS 3 + + chunk_list - list of chunks affected (a byte string, + five bytes per chunk, NULL or '\0' if + num_chunks is positive; ignored if + numchunks <= 0). + + num_chunks - number of chunks affected; if 0, all + unknown chunks are affected. If positive, + only the chunks in the list are affected, + and if negative all unknown chunks and + all known chunks except for the IHDR, + PLTE, tRNS, IDAT, and IEND chunks are + affected. + +Unknown chunks declared in this way will be saved as raw data onto a +list of png_unknown_chunk structures. If a chunk that is normally +known to libpng is named in the list, it will be handled as unknown, +according to the "keep" directive. If a chunk is named in successive +instances of png_set_keep_unknown_chunks(), the final instance will +take precedence. The IHDR and IEND chunks should not be named in +chunk_list; if they are, libpng will process them normally anyway. +If you know that your application will never make use of some particular +chunks, use PNG_HANDLE_CHUNK_NEVER (or 1) as demonstrated below. + +Here is an example of the usage of png_set_keep_unknown_chunks(), +where the private "vpAg" chunk will later be processed by a user chunk +callback function: + + png_byte vpAg[5]={118, 112, 65, 103, (png_byte) '\0'}; + + #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + png_byte unused_chunks[]= + { + 104, 73, 83, 84, (png_byte) '\0', /* hIST */ + 105, 84, 88, 116, (png_byte) '\0', /* iTXt */ + 112, 67, 65, 76, (png_byte) '\0', /* pCAL */ + 115, 67, 65, 76, (png_byte) '\0', /* sCAL */ + 115, 80, 76, 84, (png_byte) '\0', /* sPLT */ + 116, 73, 77, 69, (png_byte) '\0', /* tIME */ + }; + #endif + + ... + + #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + /* ignore all unknown chunks + * (use global setting "2" for libpng16 and earlier): + */ + png_set_keep_unknown_chunks(read_ptr, 2, NULL, 0); + + /* except for vpAg: */ + png_set_keep_unknown_chunks(read_ptr, 2, vpAg, 1); + + /* also ignore unused known chunks: */ + png_set_keep_unknown_chunks(read_ptr, 1, unused_chunks, + (int)(sizeof unused_chunks)/5); + #endif + +User limits + +The PNG specification allows the width and height of an image to be as +large as 2^31-1 (0x7fffffff), or about 2.147 billion rows and columns. +For safety, libpng imposes a default limit of 1 million rows and columns. +Larger images will be rejected immediately with a png_error() call. If +you wish to change these limits, you can use + + png_set_user_limits(png_ptr, width_max, height_max); + +to set your own limits (libpng may reject some very wide images +anyway because of potential buffer overflow conditions). + +You should put this statement after you create the PNG structure and +before calling png_read_info(), png_read_png(), or png_process_data(). + +When writing a PNG datastream, put this statement before calling +png_write_info() or png_write_png(). + +If you need to retrieve the limits that are being applied, use + + width_max = png_get_user_width_max(png_ptr); + height_max = png_get_user_height_max(png_ptr); + +The PNG specification sets no limit on the number of ancillary chunks +allowed in a PNG datastream. By default, libpng imposes a limit of +a total of 1000 sPLT, tEXt, iTXt, zTXt, and unknown chunks to be stored. +If you have set up both info_ptr and end_info_ptr, the limit applies +separately to each. You can change the limit on the total number of such +chunks that will be stored, with + + png_set_chunk_cache_max(png_ptr, user_chunk_cache_max); + +where 0x7fffffffL means unlimited. You can retrieve this limit with + + chunk_cache_max = png_get_chunk_cache_max(png_ptr); + +Libpng imposes a limit of 8 Megabytes (8,000,000 bytes) on the amount of +memory that a compressed chunk other than IDAT can occupy, when decompressed. +You can change this limit with + + png_set_chunk_malloc_max(png_ptr, user_chunk_malloc_max); + +and you can retrieve the limit with + + chunk_malloc_max = png_get_chunk_malloc_max(png_ptr); + +Any chunks that would cause either of these limits to be exceeded will +be ignored. + +Information about your system + +If you intend to display the PNG or to incorporate it in other image data you +need to tell libpng information about your display or drawing surface so that +libpng can convert the values in the image to match the display. + +From libpng-1.5.4 this information can be set before reading the PNG file +header. In earlier versions png_set_gamma() existed but behaved incorrectly if +called before the PNG file header had been read and png_set_alpha_mode() did not +exist. + +If you need to support versions prior to libpng-1.5.4 test the version number +as illustrated below using "PNG_LIBPNG_VER >= 10504" and follow the procedures +described in the appropriate manual page. + +You give libpng the encoding expected by your system expressed as a 'gamma' +value. You can also specify a default encoding for the PNG file in +case the required information is missing from the file. By default libpng +assumes that the PNG data matches your system, to keep this default call: + + png_set_gamma(png_ptr, screen_gamma, output_gamma); + +or you can use the fixed point equivalent: + + png_set_gamma_fixed(png_ptr, PNG_FP_1*screen_gamma, + PNG_FP_1*output_gamma); + +If you don't know the gamma for your system it is probably 2.2 - a good +approximation to the IEC standard for display systems (sRGB). If images are +too contrasty or washed out you got the value wrong - check your system +documentation! + +Many systems permit the system gamma to be changed via a lookup table in the +display driver, a few systems, including older Macs, change the response by +default. As of 1.5.4 three special values are available to handle common +situations: + + PNG_DEFAULT_sRGB: Indicates that the system conforms to the + IEC 61966-2-1 standard. This matches almost + all systems. + PNG_GAMMA_MAC_18: Indicates that the system is an older + (pre Mac OS 10.6) Apple Macintosh system with + the default settings. + PNG_GAMMA_LINEAR: Just the fixed point value for 1.0 - indicates + that the system expects data with no gamma + encoding. + +You would use the linear (unencoded) value if you need to process the pixel +values further because this avoids the need to decode and re-encode each +component value whenever arithmetic is performed. A lot of graphics software +uses linear values for this reason, often with higher precision component values +to preserve overall accuracy. + + +The output_gamma value expresses how to decode the output values, not how +they are encoded. The values used correspond to the normal numbers used to +describe the overall gamma of a computer display system; for example 2.2 for +an sRGB conformant system. The values are scaled by 100000 in the _fixed +version of the API (so 220000 for sRGB.) + +The inverse of the value is always used to provide a default for the PNG file +encoding if it has no gAMA chunk and if png_set_gamma() has not been called +to override the PNG gamma information. + +When the ALPHA_OPTIMIZED mode is selected the output gamma is used to encode +opaque pixels however pixels with lower alpha values are not encoded, +regardless of the output gamma setting. + +When the standard Porter Duff handling is requested with mode 1 the output +encoding is set to be linear and the output_gamma value is only relevant +as a default for input data that has no gamma information. The linear output +encoding will be overridden if png_set_gamma() is called - the results may be +highly unexpected! + +The following numbers are derived from the sRGB standard and the research +behind it. sRGB is defined to be approximated by a PNG gAMA chunk value of +0.45455 (1/2.2) for PNG. The value implicitly includes any viewing +correction required to take account of any differences in the color +environment of the original scene and the intended display environment; the +value expresses how to *decode* the image for display, not how the original +data was *encoded*. + +sRGB provides a peg for the PNG standard by defining a viewing environment. +sRGB itself, and earlier TV standards, actually use a more complex transform +(a linear portion then a gamma 2.4 power law) than PNG can express. (PNG is +limited to simple power laws.) By saying that an image for direct display on +an sRGB conformant system should be stored with a gAMA chunk value of 45455 +(11.3.3.2 and 11.3.3.5 of the ISO PNG specification) the PNG specification +makes it possible to derive values for other display systems and +environments. + +The Mac value is deduced from the sRGB based on an assumption that the actual +extra viewing correction used in early Mac display systems was implemented as +a power 1.45 lookup table. + +Any system where a programmable lookup table is used or where the behavior of +the final display device characteristics can be changed requires system +specific code to obtain the current characteristic. However this can be +difficult and most PNG gamma correction only requires an approximate value. + +By default, if png_set_alpha_mode() is not called, libpng assumes that all +values are unencoded, linear, values and that the output device also has a +linear characteristic. This is only very rarely correct - it is invariably +better to call png_set_alpha_mode() with PNG_DEFAULT_sRGB than rely on the +default if you don't know what the right answer is! + +The special value PNG_GAMMA_MAC_18 indicates an older Mac system (pre Mac OS +10.6) which used a correction table to implement a somewhat lower gamma on an +otherwise sRGB system. + +Both these values are reserved (not simple gamma values) in order to allow +more precise correction internally in the future. + +NOTE: the values can be passed to either the fixed or floating +point APIs, but the floating point API will also accept floating point +values. + +The second thing you may need to tell libpng about is how your system handles +alpha channel information. Some, but not all, PNG files contain an alpha +channel. To display these files correctly you need to compose the data onto a +suitable background, as described in the PNG specification. + +Libpng only supports composing onto a single color (using png_set_background; +see below). Otherwise you must do the composition yourself and, in this case, +you may need to call png_set_alpha_mode: + + #if PNG_LIBPNG_VER >= 10504 + png_set_alpha_mode(png_ptr, mode, screen_gamma); + #else + png_set_gamma(png_ptr, screen_gamma, 1.0/screen_gamma); + #endif + +The screen_gamma value is the same as the argument to png_set_gamma; however, +how it affects the output depends on the mode. png_set_alpha_mode() sets the +file gamma default to 1/screen_gamma, so normally you don't need to call +png_set_gamma. If you need different defaults call png_set_gamma() before +png_set_alpha_mode() - if you call it after it will override the settings made +by png_set_alpha_mode(). + +The mode is as follows: + + PNG_ALPHA_PNG: The data is encoded according to the PNG +specification. Red, green and blue, or gray, components are +gamma encoded color values and are not premultiplied by the +alpha value. The alpha value is a linear measure of the +contribution of the pixel to the corresponding final output pixel. + +You should normally use this format if you intend to perform +color correction on the color values; most, maybe all, color +correction software has no handling for the alpha channel and, +anyway, the math to handle pre-multiplied component values is +unnecessarily complex. + +Before you do any arithmetic on the component values you need +to remove the gamma encoding and multiply out the alpha +channel. See the PNG specification for more detail. It is +important to note that when an image with an alpha channel is +scaled, linear encoded, pre-multiplied component values must +be used! + +The remaining modes assume you don't need to do any further color correction or +that if you do, your color correction software knows all about alpha (it +probably doesn't!). They 'associate' the alpha with the color information by +storing color channel values that have been scaled by the alpha. The +advantage is that the color channels can be resampled (the image can be +scaled) in this form. The disadvantage is that normal practice is to store +linear, not (gamma) encoded, values and this requires 16-bit channels for +still images rather than the 8-bit channels that are just about sufficient if +gamma encoding is used. In addition all non-transparent pixel values, +including completely opaque ones, must be gamma encoded to produce the final +image. These are the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' modes +described below (the latter being the two common names for associated alpha +color channels). Note that PNG files always contain non-associated color +channels; png_set_alpha_mode() with one of the modes causes the decoder to +convert the pixels to an associated form before returning them to your +application. + +Since it is not necessary to perform arithmetic on opaque color values so +long as they are not to be resampled and are in the final color space it is +possible to optimize the handling of alpha by storing the opaque pixels in +the PNG format (adjusted for the output color space) while storing partially +opaque pixels in the standard, linear, format. The accuracy required for +standard alpha composition is relatively low, because the pixels are +isolated, therefore typically the accuracy loss in storing 8-bit linear +values is acceptable. (This is not true if the alpha channel is used to +simulate transparency over large areas - use 16 bits or the PNG mode in +this case!) This is the 'OPTIMIZED' mode. For this mode a pixel is +treated as opaque only if the alpha value is equal to the maximum value. + + PNG_ALPHA_STANDARD: The data libpng produces is encoded in the +standard way assumed by most correctly written graphics software. +The gamma encoding will be removed by libpng and the +linear component values will be pre-multiplied by the +alpha channel. + +With this format the final image must be re-encoded to +match the display gamma before the image is displayed. +If your system doesn't do that, yet still seems to +perform arithmetic on the pixels without decoding them, +it is broken - check out the modes below. + +With PNG_ALPHA_STANDARD libpng always produces linear +component values, whatever screen_gamma you supply. The +screen_gamma value is, however, used as a default for +the file gamma if the PNG file has no gamma information. + +If you call png_set_gamma() after png_set_alpha_mode() you +will override the linear encoding. Instead the +pre-multiplied pixel values will be gamma encoded but +the alpha channel will still be linear. This may +actually match the requirements of some broken software, +but it is unlikely. + +While linear 8-bit data is often used it has +insufficient precision for any image with a reasonable +dynamic range. To avoid problems, and if your software +supports it, use png_set_expand_16() to force all +components to 16 bits. + + PNG_ALPHA_OPTIMIZED: This mode is the same as PNG_ALPHA_STANDARD +except that completely opaque pixels are gamma encoded according to +the screen_gamma value. Pixels with alpha less than 1.0 +will still have linear components. + +Use this format if you have control over your +compositing software and so don't do other arithmetic +(such as scaling) on the data you get from libpng. Your +compositing software can simply copy opaque pixels to +the output but still has linear values for the +non-opaque pixels. + +In normal compositing, where the alpha channel encodes +partial pixel coverage (as opposed to broad area +translucency), the inaccuracies of the 8-bit +representation of non-opaque pixels are irrelevant. + +You can also try this format if your software is broken; +it might look better. + + PNG_ALPHA_BROKEN: This is PNG_ALPHA_STANDARD; however, all component +values, including the alpha channel are gamma encoded. This is +broken because, in practice, no implementation that uses this choice +correctly undoes the encoding before handling alpha composition. Use this +choice only if other serious errors in the software or hardware you use +mandate it. In most cases of broken software or hardware the bug in the +final display manifests as a subtle halo around composited parts of the +image. You may not even perceive this as a halo; the composited part of +the image may simply appear separate from the background, as though it had +been cut out of paper and pasted on afterward. + +If you don't have to deal with bugs in software or hardware, or if you can fix +them, there are three recommended ways of using png_set_alpha_mode(): + + png_set_alpha_mode(png_ptr, PNG_ALPHA_PNG, + screen_gamma); + +You can do color correction on the result (libpng does not currently +support color correction internally). When you handle the alpha channel +you need to undo the gamma encoding and multiply out the alpha. + + png_set_alpha_mode(png_ptr, PNG_ALPHA_STANDARD, + screen_gamma); + png_set_expand_16(png_ptr); + +If you are using the high level interface, don't call png_set_expand_16(); +instead pass PNG_TRANSFORM_EXPAND_16 to the interface. + +With this mode you can't do color correction, but you can do arithmetic, +including composition and scaling, on the data without further processing. + + png_set_alpha_mode(png_ptr, PNG_ALPHA_OPTIMIZED, + screen_gamma); + +You can avoid the expansion to 16-bit components with this mode, but you +lose the ability to scale the image or perform other linear arithmetic. +All you can do is compose the result onto a matching output. Since this +mode is libpng-specific you also need to write your own composition +software. + +The following are examples of calls to png_set_alpha_mode to achieve the +required overall gamma correction and, where necessary, alpha +premultiplication. + + png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + +This is the default libpng handling of the alpha channel - it is not +pre-multiplied into the color components. In addition the call states +that the output is for a sRGB system and causes all PNG files without gAMA +chunks to be assumed to be encoded using sRGB. + + png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + +In this case the output is assumed to be something like an sRGB conformant +display preceeded by a power-law lookup table of power 1.45. This is how +early Mac systems behaved. + + png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR); + +This is the classic Jim Blinn approach and will work in academic +environments where everything is done by the book. It has the shortcoming +of assuming that input PNG data with no gamma information is linear - this +is unlikely to be correct unless the PNG files where generated locally. +Most of the time the output precision will be so low as to show +significant banding in dark areas of the image. + + png_set_expand_16(pp); + png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_DEFAULT_sRGB); + +This is a somewhat more realistic Jim Blinn inspired approach. PNG files +are assumed to have the sRGB encoding if not marked with a gamma value and +the output is always 16 bits per component. This permits accurate scaling +and processing of the data. If you know that your input PNG files were +generated locally you might need to replace PNG_DEFAULT_sRGB with the +correct value for your system. + + png_set_alpha_mode(pp, PNG_ALPHA_OPTIMIZED, PNG_DEFAULT_sRGB); + +If you just need to composite the PNG image onto an existing background +and if you control the code that does this you can use the optimization +setting. In this case you just copy completely opaque pixels to the +output. For pixels that are not completely transparent (you just skip +those) you do the composition math using png_composite or png_composite_16 +below then encode the resultant 8-bit or 16-bit values to match the output +encoding. + + Other cases + +If neither the PNG nor the standard linear encoding work for you because +of the software or hardware you use then you have a big problem. The PNG +case will probably result in halos around the image. The linear encoding +will probably result in a washed out, too bright, image (it's actually too +contrasty.) Try the ALPHA_OPTIMIZED mode above - this will probably +substantially reduce the halos. Alternatively try: + + png_set_alpha_mode(pp, PNG_ALPHA_BROKEN, PNG_DEFAULT_sRGB); + +This option will also reduce the halos, but there will be slight dark +halos round the opaque parts of the image where the background is light. +In the OPTIMIZED mode the halos will be light halos where the background +is dark. Take your pick - the halos are unavoidable unless you can get +your hardware/software fixed! (The OPTIMIZED approach is slightly +faster.) + +When the default gamma of PNG files doesn't match the output gamma. +If you have PNG files with no gamma information png_set_alpha_mode allows +you to provide a default gamma, but it also sets the ouput gamma to the +matching value. If you know your PNG files have a gamma that doesn't +match the output you can take advantage of the fact that +png_set_alpha_mode always sets the output gamma but only sets the PNG +default if it is not already set: + + png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + +The first call sets both the default and the output gamma values, the +second call overrides the output gamma without changing the default. This +is easier than achieving the same effect with png_set_gamma. You must use +PNG_ALPHA_PNG for the first call - internal checking in png_set_alpha will +fire if more than one call to png_set_alpha_mode and png_set_background is +made in the same read operation, however multiple calls with PNG_ALPHA_PNG +are ignored. + +If you don't need, or can't handle, the alpha channel you can call +png_set_background() to remove it by compositing against a fixed color. Don't +call png_set_strip_alpha() to do this - it will leave spurious pixel values in +transparent parts of this image. + + png_set_background(png_ptr, &background_color, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1); + +The background_color is an RGB or grayscale value according to the data format +libpng will produce for you. Because you don't yet know the format of the PNG +file, if you call png_set_background at this point you must arrange for the +format produced by libpng to always have 8-bit or 16-bit components and then +store the color as an 8-bit or 16-bit color as appropriate. The color contains +separate gray and RGB component values, so you can let libpng produce gray or +RGB output according to the input format, but low bit depth grayscale images +must always be converted to at least 8-bit format. (Even though low bit depth +grayscale images can't have an alpha channel they can have a transparent +color!) + +You set the transforms you need later, either as flags to the high level +interface or libpng API calls for the low level interface. For reference the +settings and API calls required are: + +8-bit values: + PNG_TRANSFORM_SCALE_16 | PNG_EXPAND + png_set_expand(png_ptr); png_set_scale_16(png_ptr); + + If you must get exactly the same inaccurate results + produced by default in versions prior to libpng-1.5.4, + use PNG_TRANSFORM_STRIP_16 and png_set_strip_16(png_ptr) + instead. + +16-bit values: + PNG_TRANSFORM_EXPAND_16 + png_set_expand_16(png_ptr); + +In either case palette image data will be expanded to RGB. If you just want +color data you can add PNG_TRANSFORM_GRAY_TO_RGB or png_set_gray_to_rgb(png_ptr) +to the list. + +Calling png_set_background before the PNG file header is read will not work +prior to libpng-1.5.4. Because the failure may result in unexpected warnings or +errors it is therefore much safer to call png_set_background after the head has +been read. Unfortunately this means that prior to libpng-1.5.4 it cannot be +used with the high level interface. + +The high-level read interface + +At this point there are two ways to proceed; through the high-level +read interface, or through a sequence of low-level read operations. +You can use the high-level interface if (a) you are willing to read +the entire image into memory, and (b) the input transformations +you want to do are limited to the following set: + + PNG_TRANSFORM_IDENTITY No transformation + PNG_TRANSFORM_SCALE_16 Strip 16-bit samples to + 8-bit accurately + PNG_TRANSFORM_STRIP_16 Chop 16-bit samples to + 8-bit less accurately + PNG_TRANSFORM_STRIP_ALPHA Discard the alpha channel + PNG_TRANSFORM_PACKING Expand 1, 2 and 4-bit + samples to bytes + PNG_TRANSFORM_PACKSWAP Change order of packed + pixels to LSB first + PNG_TRANSFORM_EXPAND Perform set_expand() + PNG_TRANSFORM_INVERT_MONO Invert monochrome images + PNG_TRANSFORM_SHIFT Normalize pixels to the + sBIT depth + PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA + to BGRA + PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA + to AG + PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity + to transparency + PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples + PNG_TRANSFORM_GRAY_TO_RGB Expand grayscale samples + to RGB (or GA to RGBA) + PNG_TRANSFORM_EXPAND_16 Expand samples to 16 bits + +(This excludes setting a background color, doing gamma transformation, +quantizing, and setting filler.) If this is the case, simply do this: + + png_read_png(png_ptr, info_ptr, png_transforms, NULL) + +where png_transforms is an integer containing the bitwise OR of some +set of transformation flags. This call is equivalent to png_read_info(), +followed the set of transformations indicated by the transform mask, +then png_read_image(), and finally png_read_end(). + +(The final parameter of this call is not yet used. Someday it might point +to transformation parameters required by some future input transform.) + +You must use png_transforms and not call any png_set_transform() functions +when you use png_read_png(). + +After you have called png_read_png(), you can retrieve the image data +with + + row_pointers = png_get_rows(png_ptr, info_ptr); + +where row_pointers is an array of pointers to the pixel data for each row: + + png_bytep row_pointers[height]; + +If you know your image size and pixel size ahead of time, you can allocate +row_pointers prior to calling png_read_png() with + + if (height > PNG_UINT_32_MAX/(sizeof (png_byte))) + png_error (png_ptr, + "Image is too tall to process in memory"); + + if (width > PNG_UINT_32_MAX/pixel_size) + png_error (png_ptr, + "Image is too wide to process in memory"); + + row_pointers = png_malloc(png_ptr, + height*(sizeof (png_bytep))); + + for (int i=0; i) and +png_get_(png_ptr, info_ptr, ...) functions return non-zero if the +data has been read, or zero if it is missing. The parameters to the +png_get_ are set directly if they are simple data types, or a +pointer into the info_ptr is returned for any complex types. + +The colorspace data from gAMA, cHRM, sRGB, iCCP, and sBIT chunks +is simply returned to give the application information about how the +image was encoded. Libpng itself only does transformations using the file +gamma when combining semitransparent pixels with the background color, and, +since libpng-1.6.0, when converting between 8-bit sRGB and 16-bit linear pixels +within the simplified API. Libpng also uses the file gamma when converting +RGB to gray, beginning with libpng-1.0.5, if the application calls +png_set_rgb_to_gray()). + + png_get_PLTE(png_ptr, info_ptr, &palette, + &num_palette); + + palette - the palette for the file + (array of png_color) + + num_palette - number of entries in the palette + + png_get_gAMA(png_ptr, info_ptr, &file_gamma); + png_get_gAMA_fixed(png_ptr, info_ptr, &int_file_gamma); + + file_gamma - the gamma at which the file is + written (PNG_INFO_gAMA) + + int_file_gamma - 100,000 times the gamma at which the + file is written + + png_get_cHRM(png_ptr, info_ptr, &white_x, &white_y, &red_x, + &red_y, &green_x, &green_y, &blue_x, &blue_y) + png_get_cHRM_XYZ(png_ptr, info_ptr, &red_X, &red_Y, &red_Z, + &green_X, &green_Y, &green_Z, &blue_X, &blue_Y, + &blue_Z) + png_get_cHRM_fixed(png_ptr, info_ptr, &int_white_x, + &int_white_y, &int_red_x, &int_red_y, + &int_green_x, &int_green_y, &int_blue_x, + &int_blue_y) + png_get_cHRM_XYZ_fixed(png_ptr, info_ptr, &int_red_X, &int_red_Y, + &int_red_Z, &int_green_X, &int_green_Y, + &int_green_Z, &int_blue_X, &int_blue_Y, + &int_blue_Z) + + {white,red,green,blue}_{x,y} + A color space encoding specified using the + chromaticities of the end points and the + white point. (PNG_INFO_cHRM) + + {red,green,blue}_{X,Y,Z} + A color space encoding specified using the + encoding end points - the CIE tristimulus + specification of the intended color of the red, + green and blue channels in the PNG RGB data. + The white point is simply the sum of the three + end points. (PNG_INFO_cHRM) + + png_get_sRGB(png_ptr, info_ptr, &srgb_intent); + + srgb_intent - the rendering intent (PNG_INFO_sRGB) + The presence of the sRGB chunk + means that the pixel data is in the + sRGB color space. This chunk also + implies specific values of gAMA and + cHRM. + + png_get_iCCP(png_ptr, info_ptr, &name, + &compression_type, &profile, &proflen); + + name - The profile name. + + compression_type - The compression type; always + PNG_COMPRESSION_TYPE_BASE for PNG 1.0. + You may give NULL to this argument to + ignore it. + + profile - International Color Consortium color + profile data. May contain NULs. + + proflen - length of profile data in bytes. + + png_get_sBIT(png_ptr, info_ptr, &sig_bit); + + sig_bit - the number of significant bits for + (PNG_INFO_sBIT) each of the gray, + red, green, and blue channels, + whichever are appropriate for the + given color type (png_color_16) + + png_get_tRNS(png_ptr, info_ptr, &trans_alpha, + &num_trans, &trans_color); + + trans_alpha - array of alpha (transparency) + entries for palette (PNG_INFO_tRNS) + + num_trans - number of transparent entries + (PNG_INFO_tRNS) + + trans_color - graylevel or color sample values of + the single transparent color for + non-paletted images (PNG_INFO_tRNS) + + png_get_hIST(png_ptr, info_ptr, &hist); + (PNG_INFO_hIST) + + hist - histogram of palette (array of + png_uint_16) + + png_get_tIME(png_ptr, info_ptr, &mod_time); + + mod_time - time image was last modified + (PNG_VALID_tIME) + + png_get_bKGD(png_ptr, info_ptr, &background); + + background - background color (of type + png_color_16p) (PNG_VALID_bKGD) + valid 16-bit red, green and blue + values, regardless of color_type + + num_comments = png_get_text(png_ptr, info_ptr, + &text_ptr, &num_text); + + num_comments - number of comments + + text_ptr - array of png_text holding image + comments + + text_ptr[i].compression - type of compression used + on "text" PNG_TEXT_COMPRESSION_NONE + PNG_TEXT_COMPRESSION_zTXt + PNG_ITXT_COMPRESSION_NONE + PNG_ITXT_COMPRESSION_zTXt + + text_ptr[i].key - keyword for comment. Must contain + 1-79 characters. + + text_ptr[i].text - text comments for current + keyword. Can be empty. + + text_ptr[i].text_length - length of text string, + after decompression, 0 for iTXt + + text_ptr[i].itxt_length - length of itxt string, + after decompression, 0 for tEXt/zTXt + + text_ptr[i].lang - language of comment (empty + string for unknown). + + text_ptr[i].lang_key - keyword in UTF-8 + (empty string for unknown). + + Note that the itxt_length, lang, and lang_key + members of the text_ptr structure only exist when the + library is built with iTXt chunk support. Prior to + libpng-1.4.0 the library was built by default without + iTXt support. Also note that when iTXt is supported, + they contain NULL pointers when the "compression" + field contains PNG_TEXT_COMPRESSION_NONE or + PNG_TEXT_COMPRESSION_zTXt. + + num_text - number of comments (same as + num_comments; you can put NULL here + to avoid the duplication) + + Note while png_set_text() will accept text, language, + and translated keywords that can be NULL pointers, the + structure returned by png_get_text will always contain + regular zero-terminated C strings. They might be + empty strings but they will never be NULL pointers. + + num_spalettes = png_get_sPLT(png_ptr, info_ptr, + &palette_ptr); + + num_spalettes - number of sPLT chunks read. + + palette_ptr - array of palette structures holding + contents of one or more sPLT chunks + read. + + png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, + &unit_type); + + offset_x - positive offset from the left edge + of the screen (can be negative) + + offset_y - positive offset from the top edge + of the screen (can be negative) + + unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER + + png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, + &unit_type); + + res_x - pixels/unit physical resolution in + x direction + + res_y - pixels/unit physical resolution in + x direction + + unit_type - PNG_RESOLUTION_UNKNOWN, + PNG_RESOLUTION_METER + + png_get_sCAL(png_ptr, info_ptr, &unit, &width, + &height) + + unit - physical scale units (an integer) + + width - width of a pixel in physical scale units + + height - height of a pixel in physical scale units + (width and height are doubles) + + png_get_sCAL_s(png_ptr, info_ptr, &unit, &width, + &height) + + unit - physical scale units (an integer) + + width - width of a pixel in physical scale units + (expressed as a string) + + height - height of a pixel in physical scale units + (width and height are strings like "2.54") + + num_unknown_chunks = png_get_unknown_chunks(png_ptr, + info_ptr, &unknowns) + + unknowns - array of png_unknown_chunk + structures holding unknown chunks + + unknowns[i].name - name of unknown chunk + + unknowns[i].data - data of unknown chunk + + unknowns[i].size - size of unknown chunk's data + + unknowns[i].location - position of chunk in file + + The value of "i" corresponds to the order in which the + chunks were read from the PNG file or inserted with the + png_set_unknown_chunks() function. + + The value of "location" is a bitwise "or" of + + PNG_HAVE_IHDR (0x01) + PNG_HAVE_PLTE (0x02) + PNG_AFTER_IDAT (0x08) + +The data from the pHYs chunk can be retrieved in several convenient +forms: + + res_x = png_get_x_pixels_per_meter(png_ptr, + info_ptr) + + res_y = png_get_y_pixels_per_meter(png_ptr, + info_ptr) + + res_x_and_y = png_get_pixels_per_meter(png_ptr, + info_ptr) + + res_x = png_get_x_pixels_per_inch(png_ptr, + info_ptr) + + res_y = png_get_y_pixels_per_inch(png_ptr, + info_ptr) + + res_x_and_y = png_get_pixels_per_inch(png_ptr, + info_ptr) + + aspect_ratio = png_get_pixel_aspect_ratio(png_ptr, + info_ptr) + + Each of these returns 0 [signifying "unknown"] if + the data is not present or if res_x is 0; + res_x_and_y is 0 if res_x != res_y + + Note that because of the way the resolutions are + stored internally, the inch conversions won't + come out to exactly even number. For example, + 72 dpi is stored as 0.28346 pixels/meter, and + when this is retrieved it is 71.9988 dpi, so + be sure to round the returned value appropriately + if you want to display a reasonable-looking result. + +The data from the oFFs chunk can be retrieved in several convenient +forms: + + x_offset = png_get_x_offset_microns(png_ptr, info_ptr); + + y_offset = png_get_y_offset_microns(png_ptr, info_ptr); + + x_offset = png_get_x_offset_inches(png_ptr, info_ptr); + + y_offset = png_get_y_offset_inches(png_ptr, info_ptr); + + Each of these returns 0 [signifying "unknown" if both + x and y are 0] if the data is not present or if the + chunk is present but the unit is the pixel. The + remark about inexact inch conversions applies here + as well, because a value in inches can't always be + converted to microns and back without some loss + of precision. + +For more information, see the +PNG specification for chunk contents. Be careful with trusting +rowbytes, as some of the transformations could increase the space +needed to hold a row (expand, filler, gray_to_rgb, etc.). +See png_read_update_info(), below. + +A quick word about text_ptr and num_text. PNG stores comments in +keyword/text pairs, one pair per chunk, with no limit on the number +of text chunks, and a 2^31 byte limit on their size. While there are +suggested keywords, there is no requirement to restrict the use to these +strings. It is strongly suggested that keywords and text be sensible +to humans (that's the point), so don't use abbreviations. Non-printing +symbols are not allowed. See the PNG specification for more details. +There is also no requirement to have text after the keyword. + +Keywords should be limited to 79 Latin-1 characters without leading or +trailing spaces, but non-consecutive spaces are allowed within the +keyword. It is possible to have the same keyword any number of times. +The text_ptr is an array of png_text structures, each holding a +pointer to a language string, a pointer to a keyword and a pointer to +a text string. The text string, language code, and translated +keyword may be empty or NULL pointers. The keyword/text +pairs are put into the array in the order that they are received. +However, some or all of the text chunks may be after the image, so, to +make sure you have read all the text chunks, don't mess with these +until after you read the stuff after the image. This will be +mentioned again below in the discussion that goes with png_read_end(). + +Input transformations + +After you've read the header information, you can set up the library +to handle any special transformations of the image data. The various +ways to transform the data will be described in the order that they +should occur. This is important, as some of these change the color +type and/or bit depth of the data, and some others only work on +certain color types and bit depths. + +Transformations you request are ignored if they don't have any meaning for a +particular input data format. However some transformations can have an effect +as a result of a previous transformation. If you specify a contradictory set of +transformations, for example both adding and removing the alpha channel, you +cannot predict the final result. + +The color used for the transparency values should be supplied in the same +format/depth as the current image data. It is stored in the same format/depth +as the image data in a tRNS chunk, so this is what libpng expects for this data. + +The color used for the background value depends on the need_expand argument as +described below. + +Data will be decoded into the supplied row buffers packed into bytes +unless the library has been told to transform it into another format. +For example, 4 bit/pixel paletted or grayscale data will be returned +2 pixels/byte with the leftmost pixel in the high-order bits of the byte, +unless png_set_packing() is called. 8-bit RGB data will be stored +in RGB RGB RGB format unless png_set_filler() or png_set_add_alpha() +is called to insert filler bytes, either before or after each RGB triplet. + +16-bit RGB data will be returned RRGGBB RRGGBB, with the most significant +byte of the color value first, unless png_set_scale_16() is called to +transform it to regular RGB RGB triplets, or png_set_filler() or +png_set_add alpha() is called to insert two filler bytes, either before +or after each RRGGBB triplet. Similarly, 8-bit or 16-bit grayscale data can +be modified with png_set_filler(), png_set_add_alpha(), png_set_strip_16(), +or png_set_scale_16(). + +The following code transforms grayscale images of less than 8 to 8 bits, +changes paletted images to RGB, and adds a full alpha channel if there is +transparency information in a tRNS chunk. This is most useful on +grayscale images with bit depths of 2 or 4 or if there is a multiple-image +viewing application that wishes to treat all images in the same way. + + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + + if (png_get_valid(png_ptr, info_ptr, + PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); + + if (color_type == PNG_COLOR_TYPE_GRAY && + bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); + +The first two functions are actually aliases for png_set_expand(), added +in libpng version 1.0.4, with the function names expanded to improve code +readability. In some future version they may actually do different +things. + +As of libpng version 1.2.9, png_set_expand_gray_1_2_4_to_8() was +added. It expands the sample depth without changing tRNS to alpha. + +As of libpng version 1.5.2, png_set_expand_16() was added. It behaves as +png_set_expand(); however, the resultant channels have 16 bits rather than 8. +Use this when the output color or gray channels are made linear to avoid fairly +severe accuracy loss. + + if (bit_depth < 16) + png_set_expand_16(png_ptr); + +PNG can have files with 16 bits per channel. If you only can handle +8 bits per channel, this will strip the pixels down to 8-bit. + + if (bit_depth == 16) +#if PNG_LIBPNG_VER >= 10504 + png_set_scale_16(png_ptr); +#else + png_set_strip_16(png_ptr); +#endif + +(The more accurate "png_set_scale_16()" API became available in libpng version +1.5.4). + +If you need to process the alpha channel on the image separately from the image +data (for example if you convert it to a bitmap mask) it is possible to have +libpng strip the channel leaving just RGB or gray data: + + if (color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(png_ptr); + +If you strip the alpha channel you need to find some other way of dealing with +the information. If, instead, you want to convert the image to an opaque +version with no alpha channel use png_set_background; see below. + +As of libpng version 1.5.2, almost all useful expansions are supported, the +major ommissions are conversion of grayscale to indexed images (which can be +done trivially in the application) and conversion of indexed to grayscale (which +can be done by a trivial manipulation of the palette.) + +In the following table, the 01 means grayscale with depth<8, 31 means +indexed with depth<8, other numerals represent the color type, "T" means +the tRNS chunk is present, A means an alpha channel is present, and O +means tRNS or alpha is present but all pixels in the image are opaque. + + FROM 01 31 0 0T 0O 2 2T 2O 3 3T 3O 4A 4O 6A 6O + TO + 01 - [G] - - - - - - - - - - - - - + 31 [Q] Q [Q] [Q] [Q] Q Q Q Q Q Q [Q] [Q] Q Q + 0 1 G + . . G G G G G G B B GB GB + 0T lt Gt t + . Gt G G Gt G G Bt Bt GBt GBt + 0O lt Gt t . + Gt Gt G Gt Gt G Bt Bt GBt GBt + 2 C P C C C + . . C - - CB CB B B + 2T Ct - Ct C C t + t - - - CBt CBt Bt Bt + 2O Ct - Ct C C t t + - - - CBt CBt Bt Bt + 3 [Q] p [Q] [Q] [Q] Q Q Q + . . [Q] [Q] Q Q + 3T [Qt] p [Qt][Q] [Q] Qt Qt Qt t + t [Qt][Qt] Qt Qt + 3O [Qt] p [Qt][Q] [Q] Qt Qt Qt t t + [Qt][Qt] Qt Qt + 4A lA G A T T GA GT GT GA GT GT + BA G GBA + 4O lA GBA A T T GA GT GT GA GT GT BA + GBA G + 6A CA PA CA C C A T tT PA P P C CBA + BA + 6O CA PBA CA C C A tT T PA P P CBA C BA + + +Within the matrix, + "+" identifies entries where 'from' and 'to' are the same. + "-" means the transformation is not supported. + "." means nothing is necessary (a tRNS chunk can just be ignored). + "t" means the transformation is obtained by png_set_tRNS. + "A" means the transformation is obtained by png_set_add_alpha(). + "X" means the transformation is obtained by png_set_expand(). + "1" means the transformation is obtained by + png_set_expand_gray_1_2_4_to_8() (and by png_set_expand() + if there is no transparency in the original or the final + format). + "C" means the transformation is obtained by png_set_gray_to_rgb(). + "G" means the transformation is obtained by png_set_rgb_to_gray(). + "P" means the transformation is obtained by + png_set_expand_palette_to_rgb(). + "p" means the transformation is obtained by png_set_packing(). + "Q" means the transformation is obtained by png_set_quantize(). + "T" means the transformation is obtained by + png_set_tRNS_to_alpha(). + "B" means the transformation is obtained by + png_set_background(), or png_strip_alpha(). + +When an entry has multiple transforms listed all are required to cause the +right overall transformation. When two transforms are separated by a comma +either will do the job. When transforms are enclosed in [] the transform should +do the job but this is currently unimplemented - a different format will result +if the suggested transformations are used. + +In PNG files, the alpha channel in an image +is the level of opacity. If you need the alpha channel in an image to +be the level of transparency instead of opacity, you can invert the +alpha channel (or the tRNS chunk data) after it's read, so that 0 is +fully opaque and 255 (in 8-bit or paletted images) or 65535 (in 16-bit +images) is fully transparent, with + + png_set_invert_alpha(png_ptr); + +PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as +they can, resulting in, for example, 8 pixels per byte for 1 bit +files. This code expands to 1 pixel per byte without changing the +values of the pixels: + + if (bit_depth < 8) + png_set_packing(png_ptr); + +PNG files have possible bit depths of 1, 2, 4, 8, and 16. All pixels +stored in a PNG image have been "scaled" or "shifted" up to the next +higher possible bit depth (e.g. from 5 bits/sample in the range [0,31] +to 8 bits/sample in the range [0, 255]). However, it is also possible +to convert the PNG pixel data back to the original bit depth of the +image. This call reduces the pixels back down to the original bit depth: + + png_color_8p sig_bit; + + if (png_get_sBIT(png_ptr, info_ptr, &sig_bit)) + png_set_shift(png_ptr, sig_bit); + +PNG files store 3-color pixels in red, green, blue order. This code +changes the storage of the pixels to blue, green, red: + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_bgr(png_ptr); + +PNG files store RGB pixels packed into 3 or 6 bytes. This code expands them +into 4 or 8 bytes for windowing systems that need them in this format: + + if (color_type == PNG_COLOR_TYPE_RGB) + png_set_filler(png_ptr, filler, PNG_FILLER_BEFORE); + +where "filler" is the 8-bit or 16-bit number to fill with, and the location +is either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether +you want the filler before the RGB or after. When filling an 8-bit pixel, +the least significant 8 bits of the number are used, if a 16-bit number is +supplied. This transformation does not affect images that already have full +alpha channels. To add an opaque alpha channel, use filler=0xffff and +PNG_FILLER_AFTER which will generate RGBA pixels. + +Note that png_set_filler() does not change the color type. If you want +to do that, you can add a true alpha channel with + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_GRAY) + png_set_add_alpha(png_ptr, filler, PNG_FILLER_AFTER); + +where "filler" contains the alpha value to assign to each pixel. +The png_set_add_alpha() function was added in libpng-1.2.7. + +If you are reading an image with an alpha channel, and you need the +data as ARGB instead of the normal PNG format RGBA: + + if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_swap_alpha(png_ptr); + +For some uses, you may want a grayscale image to be represented as +RGB. This code will do that conversion: + + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + +Conversely, you can convert an RGB or RGBA image to grayscale or grayscale +with alpha. + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_rgb_to_gray(png_ptr, error_action, + double red_weight, double green_weight); + + error_action = 1: silently do the conversion + + error_action = 2: issue a warning if the original + image has any pixel where + red != green or red != blue + + error_action = 3: issue an error and abort the + conversion if the original + image has any pixel where + red != green or red != blue + + red_weight: weight of red component + + green_weight: weight of green component + If either weight is negative, default + weights are used. + +In the corresponding fixed point API the red_weight and green_weight values are +simply scaled by 100,000: + + png_set_rgb_to_gray(png_ptr, error_action, + png_fixed_point red_weight, + png_fixed_point green_weight); + +If you have set error_action = 1 or 2, you can +later check whether the image really was gray, after processing +the image rows, with the png_get_rgb_to_gray_status(png_ptr) function. +It will return a png_byte that is zero if the image was gray or +1 if there were any non-gray pixels. Background and sBIT data +will be silently converted to grayscale, using the green channel +data for sBIT, regardless of the error_action setting. + +The default values come from the PNG file cHRM chunk if present; otherwise, the +defaults correspond to the ITU-R recommendation 709, and also the sRGB color +space, as recommended in the Charles Poynton's Colour FAQ, +Copyright (c) 2006-11-28 Charles Poynton, in section 9: + + + + Y = 0.2126 * R + 0.7152 * G + 0.0722 * B + +Previous versions of this document, 1998 through 2002, recommended a slightly +different formula: + + Y = 0.212671 * R + 0.715160 * G + 0.072169 * B + +Libpng uses an integer approximation: + + Y = (6968 * R + 23434 * G + 2366 * B)/32768 + +The calculation is done in a linear colorspace, if the image gamma +can be determined. + +The png_set_background() function has been described already; it tells libpng to +composite images with alpha or simple transparency against the supplied +background color. For compatibility with versions of libpng earlier than +libpng-1.5.4 it is recommended that you call the function after reading the file +header, even if you don't want to use the color in a bKGD chunk, if one exists. + +If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid), +you may use this color, or supply another color more suitable for +the current display (e.g., the background color from a web page). You +need to tell libpng how the color is represented, both the format of the +component values in the color (the number of bits) and the gamma encoding of the +color. The function takes two arguments, background_gamma_mode and need_expand +to convey this information; however, only two combinations are likely to be +useful: + + png_color_16 my_background; + png_color_16p image_background; + + if (png_get_bKGD(png_ptr, info_ptr, &image_background)) + png_set_background(png_ptr, image_background, + PNG_BACKGROUND_GAMMA_FILE, 1/*needs to be expanded*/, 1); + else + png_set_background(png_ptr, &my_background, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*do not expand*/, 1); + +The second call was described above - my_background is in the format of the +final, display, output produced by libpng. Because you now know the format of +the PNG it is possible to avoid the need to choose either 8-bit or 16-bit +output and to retain palette images (the palette colors will be modified +appropriately and the tRNS chunk removed.) However, if you are doing this, +take great care not to ask for transformations without checking first that +they apply! + +In the first call the background color has the original bit depth and color type +of the PNG file. So, for palette images the color is supplied as a palette +index and for low bit greyscale images the color is a reduced bit value in +image_background->gray. + +If you didn't call png_set_gamma() before reading the file header, for example +if you need your code to remain compatible with older versions of libpng prior +to libpng-1.5.4, this is the place to call it. + +Do not call it if you called png_set_alpha_mode(); doing so will damage the +settings put in place by png_set_alpha_mode(). (If png_set_alpha_mode() is +supported then you can certainly do png_set_gamma() before reading the PNG +header.) + +This API unconditionally sets the screen and file gamma values, so it will +override the value in the PNG file unless it is called before the PNG file +reading starts. For this reason you must always call it with the PNG file +value when you call it in this position: + + if (png_get_gAMA(png_ptr, info_ptr, &file_gamma)) + png_set_gamma(png_ptr, screen_gamma, file_gamma); + + else + png_set_gamma(png_ptr, screen_gamma, 0.45455); + +If you need to reduce an RGB file to a paletted file, or if a paletted +file has more entries than will fit on your screen, png_set_quantize() +will do that. Note that this is a simple match quantization that merely +finds the closest color available. This should work fairly well with +optimized palettes, but fairly badly with linear color cubes. If you +pass a palette that is larger than maximum_colors, the file will +reduce the number of colors in the palette so it will fit into +maximum_colors. If there is a histogram, libpng will use it to make +more intelligent choices when reducing the palette. If there is no +histogram, it may not do as good a job. + + if (color_type & PNG_COLOR_MASK_COLOR) + { + if (png_get_valid(png_ptr, info_ptr, + PNG_INFO_PLTE)) + { + png_uint_16p histogram = NULL; + + png_get_hIST(png_ptr, info_ptr, + &histogram); + png_set_quantize(png_ptr, palette, num_palette, + max_screen_colors, histogram, 1); + } + + else + { + png_color std_color_cube[MAX_SCREEN_COLORS] = + { ... colors ... }; + + png_set_quantize(png_ptr, std_color_cube, + MAX_SCREEN_COLORS, MAX_SCREEN_COLORS, + NULL,0); + } + } + +PNG files describe monochrome as black being zero and white being one. +The following code will reverse this (make black be one and white be +zero): + + if (bit_depth == 1 && color_type == PNG_COLOR_TYPE_GRAY) + png_set_invert_mono(png_ptr); + +This function can also be used to invert grayscale and gray-alpha images: + + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_invert_mono(png_ptr); + +PNG files store 16-bit pixels in network byte order (big-endian, +ie. most significant bits first). This code changes the storage to the +other way (little-endian, i.e. least significant bits first, the +way PCs store them): + + if (bit_depth == 16) + png_set_swap(png_ptr); + +If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you +need to change the order the pixels are packed into bytes, you can use: + + if (bit_depth < 8) + png_set_packswap(png_ptr); + +Finally, you can write your own transformation function if none of +the existing ones meets your needs. This is done by setting a callback +with + + png_set_read_user_transform_fn(png_ptr, + read_transform_fn); + +You must supply the function + + void read_transform_fn(png_structp png_ptr, png_row_infop + row_info, png_bytep data) + +See pngtest.c for a working example. Your function will be called +after all of the other transformations have been processed. Take care with +interlaced images if you do the interlace yourself - the width of the row is the +width in 'row_info', not the overall image width. + +If supported, libpng provides two information routines that you can use to find +where you are in processing the image: + + png_get_current_pass_number(png_structp png_ptr); + png_get_current_row_number(png_structp png_ptr); + +Don't try using these outside a transform callback - firstly they are only +supported if user transforms are supported, secondly they may well return +unexpected results unless the row is actually being processed at the moment they +are called. + +With interlaced +images the value returned is the row in the input sub-image image. Use +PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to +find the output pixel (x,y) given an interlaced sub-image pixel (row,col,pass). + +The discussion of interlace handling above contains more information on how to +use these values. + +You can also set up a pointer to a user structure for use by your +callback function, and you can inform libpng that your transform +function will change the number of channels or bit depth with the +function + + png_set_user_transform_info(png_ptr, user_ptr, + user_depth, user_channels); + +The user's application, not libpng, is responsible for allocating and +freeing any memory required for the user structure. + +You can retrieve the pointer via the function +png_get_user_transform_ptr(). For example: + + voidp read_user_transform_ptr = + png_get_user_transform_ptr(png_ptr); + +The last thing to handle is interlacing; this is covered in detail below, +but you must call the function here if you want libpng to handle expansion +of the interlaced image. + + number_of_passes = png_set_interlace_handling(png_ptr); + +After setting the transformations, libpng can update your png_info +structure to reflect any transformations you've requested with this +call. + + png_read_update_info(png_ptr, info_ptr); + +This is most useful to update the info structure's rowbytes +field so you can use it to allocate your image memory. This function +will also update your palette with the correct screen_gamma and +background if these have been given with the calls above. You may +only call png_read_update_info() once with a particular info_ptr. + +After you call png_read_update_info(), you can allocate any +memory you need to hold the image. The row data is simply +raw byte data for all forms of images. As the actual allocation +varies among applications, no example will be given. If you +are allocating one large chunk, you will need to build an +array of pointers to each row, as it will be needed for some +of the functions below. + +Remember: Before you call png_read_update_info(), the png_get_*() +functions return the values corresponding to the original PNG image. +After you call png_read_update_info the values refer to the image +that libpng will output. Consequently you must call all the png_set_ +functions before you call png_read_update_info(). This is particularly +important for png_set_interlace_handling() - if you are going to call +png_read_update_info() you must call png_set_interlace_handling() before +it unless you want to receive interlaced output. + +Reading image data + +After you've allocated memory, you can read the image data. +The simplest way to do this is in one function call. If you are +allocating enough memory to hold the whole image, you can just +call png_read_image() and libpng will read in all the image data +and put it in the memory area supplied. You will need to pass in +an array of pointers to each row. + +This function automatically handles interlacing, so you don't +need to call png_set_interlace_handling() (unless you call +png_read_update_info()) or call this function multiple times, or any +of that other stuff necessary with png_read_rows(). + + png_read_image(png_ptr, row_pointers); + +where row_pointers is: + + png_bytep row_pointers[height]; + +You can point to void or char or whatever you use for pixels. + +If you don't want to read in the whole image at once, you can +use png_read_rows() instead. If there is no interlacing (check +interlace_type == PNG_INTERLACE_NONE), this is simple: + + png_read_rows(png_ptr, row_pointers, NULL, + number_of_rows); + +where row_pointers is the same as in the png_read_image() call. + +If you are doing this just one row at a time, you can do this with +a single row_pointer instead of an array of row_pointers: + + png_bytep row_pointer = row; + png_read_row(png_ptr, row_pointer, NULL); + +If the file is interlaced (interlace_type != 0 in the IHDR chunk), things +get somewhat harder. The only current (PNG Specification version 1.2) +interlacing type for PNG is (interlace_type == PNG_INTERLACE_ADAM7); +a somewhat complicated 2D interlace scheme, known as Adam7, that +breaks down an image into seven smaller images of varying size, based +on an 8x8 grid. This number is defined (from libpng 1.5) as +PNG_INTERLACE_ADAM7_PASSES in png.h + +libpng can fill out those images or it can give them to you "as is". +It is almost always better to have libpng handle the interlacing for you. +If you want the images filled out, there are two ways to do that. The one +mentioned in the PNG specification is to expand each pixel to cover +those pixels that have not been read yet (the "rectangle" method). +This results in a blocky image for the first pass, which gradually +smooths out as more pixels are read. The other method is the "sparkle" +method, where pixels are drawn only in their final locations, with the +rest of the image remaining whatever colors they were initialized to +before the start of the read. The first method usually looks better, +but tends to be slower, as there are more pixels to put in the rows. + +If, as is likely, you want libpng to expand the images, call this before +calling png_start_read_image() or png_read_update_info(): + + if (interlace_type == PNG_INTERLACE_ADAM7) + number_of_passes + = png_set_interlace_handling(png_ptr); + +This will return the number of passes needed. Currently, this is seven, +but may change if another interlace type is added. This function can be +called even if the file is not interlaced, where it will return one pass. +You then need to read the whole image 'number_of_passes' times. Each time +will distribute the pixels from the current pass to the correct place in +the output image, so you need to supply the same rows to png_read_rows in +each pass. + +If you are not going to display the image after each pass, but are +going to wait until the entire image is read in, use the sparkle +effect. This effect is faster and the end result of either method +is exactly the same. If you are planning on displaying the image +after each pass, the "rectangle" effect is generally considered the +better looking one. + +If you only want the "sparkle" effect, just call png_read_rows() as +normal, with the third parameter NULL. Make sure you make pass over +the image number_of_passes times, and you don't change the data in the +rows between calls. You can change the locations of the data, just +not the data. Each pass only writes the pixels appropriate for that +pass, and assumes the data from previous passes is still valid. + + png_read_rows(png_ptr, row_pointers, NULL, + number_of_rows); + +If you only want the first effect (the rectangles), do the same as +before except pass the row buffer in the third parameter, and leave +the second parameter NULL. + + png_read_rows(png_ptr, NULL, row_pointers, + number_of_rows); + +If you don't want libpng to handle the interlacing details, just call +png_read_rows() PNG_INTERLACE_ADAM7_PASSES times to read in all the images. +Each of the images is a valid image by itself; however, you will almost +certainly need to distribute the pixels from each sub-image to the +correct place. This is where everything gets very tricky. + +If you want to retrieve the separate images you must pass the correct +number of rows to each successive call of png_read_rows(). The calculation +gets pretty complicated for small images, where some sub-images may +not even exist because either their width or height ends up zero. +libpng provides two macros to help you in 1.5 and later versions: + + png_uint_32 width = PNG_PASS_COLS(image_width, pass_number); + png_uint_32 height = PNG_PASS_ROWS(image_height, pass_number); + +Respectively these tell you the width and height of the sub-image +corresponding to the numbered pass. 'pass' is in in the range 0 to 6 - +this can be confusing because the specification refers to the same passes +as 1 to 7! Be careful, you must check both the width and height before +calling png_read_rows() and not call it for that pass if either is zero. + +You can, of course, read each sub-image row by row. If you want to +produce optimal code to make a pixel-by-pixel transformation of an +interlaced image this is the best approach; read each row of each pass, +transform it, and write it out to a new interlaced image. + +If you want to de-interlace the image yourself libpng provides further +macros to help that tell you where to place the pixels in the output image. +Because the interlacing scheme is rectangular - sub-image pixels are always +arranged on a rectangular grid - all you need to know for each pass is the +starting column and row in the output image of the first pixel plus the +spacing between each pixel. As of libpng 1.5 there are four macros to +retrieve this information: + + png_uint_32 x = PNG_PASS_START_COL(pass); + png_uint_32 y = PNG_PASS_START_ROW(pass); + png_uint_32 xStep = 1U << PNG_PASS_COL_SHIFT(pass); + png_uint_32 yStep = 1U << PNG_PASS_ROW_SHIFT(pass); + +These allow you to write the obvious loop: + + png_uint_32 input_y = 0; + png_uint_32 output_y = PNG_PASS_START_ROW(pass); + + while (output_y < output_image_height) + { + png_uint_32 input_x = 0; + png_uint_32 output_x = PNG_PASS_START_COL(pass); + + while (output_x < output_image_width) + { + image[output_y][output_x] = + subimage[pass][input_y][input_x++]; + + output_x += xStep; + } + + ++input_y; + output_y += yStep; + } + +Notice that the steps between successive output rows and columns are +returned as shifts. This is possible because the pixels in the subimages +are always a power of 2 apart - 1, 2, 4 or 8 pixels - in the original +image. In practice you may need to directly calculate the output coordinate +given an input coordinate. libpng provides two further macros for this +purpose: + + png_uint_32 output_x = PNG_COL_FROM_PASS_COL(input_x, pass); + png_uint_32 output_y = PNG_ROW_FROM_PASS_ROW(input_y, pass); + +Finally a pair of macros are provided to tell you if a particular image +row or column appears in a given pass: + + int col_in_pass = PNG_COL_IN_INTERLACE_PASS(output_x, pass); + int row_in_pass = PNG_ROW_IN_INTERLACE_PASS(output_y, pass); + +Bear in mind that you will probably also need to check the width and height +of the pass in addition to the above to be sure the pass even exists! + +With any luck you are convinced by now that you don't want to do your own +interlace handling. In reality normally the only good reason for doing this +is if you are processing PNG files on a pixel-by-pixel basis and don't want +to load the whole file into memory when it is interlaced. + +libpng includes a test program, pngvalid, that illustrates reading and +writing of interlaced images. If you can't get interlacing to work in your +code and don't want to leave it to libpng (the recommended approach), see +how pngvalid.c does it. + +Finishing a sequential read + +After you are finished reading the image through the +low-level interface, you can finish reading the file. + +If you want to use a different crc action for handling CRC errors in +chunks after the image data, you can call png_set_crc_action() +again at this point. + +If you are interested in comments or time, which may be stored either +before or after the image data, you should pass the separate png_info +struct if you want to keep the comments from before and after the image +separate. + + png_infop end_info = png_create_info_struct(png_ptr); + + if (!end_info) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + + png_read_end(png_ptr, end_info); + +If you are not interested, you should still call png_read_end() +but you can pass NULL, avoiding the need to create an end_info structure. +If you do this, libpng will not process any chunks after IDAT other than +skipping over them and perhaps (depending on whether you have called +png_set_crc_action) checking their CRCs while looking for the IEND chunk. + + png_read_end(png_ptr, (png_infop)NULL); + +If you don't call png_read_end(), then your file pointer will be +left pointing to the first chunk after the last IDAT, which is probably +not what you want if you expect to read something beyond the end of +the PNG datastream. + +When you are done, you can free all memory allocated by libpng like this: + + png_destroy_read_struct(&png_ptr, &info_ptr, + &end_info); + +or, if you didn't create an end_info structure, + + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + +It is also possible to individually free the info_ptr members that +point to libpng-allocated storage with the following function: + + png_free_data(png_ptr, info_ptr, mask, seq) + + mask - identifies data to be freed, a mask + containing the bitwise OR of one or + more of + PNG_FREE_PLTE, PNG_FREE_TRNS, + PNG_FREE_HIST, PNG_FREE_ICCP, + PNG_FREE_PCAL, PNG_FREE_ROWS, + PNG_FREE_SCAL, PNG_FREE_SPLT, + PNG_FREE_TEXT, PNG_FREE_UNKN, + or simply PNG_FREE_ALL + + seq - sequence number of item to be freed + (-1 for all items) + +This function may be safely called when the relevant storage has +already been freed, or has not yet been allocated, or was allocated +by the user and not by libpng, and will in those cases do nothing. +The "seq" parameter is ignored if only one item of the selected data +type, such as PLTE, is allowed. If "seq" is not -1, and multiple items +are allowed for the data type identified in the mask, such as text or +sPLT, only the n'th item in the structure is freed, where n is "seq". + +The default behavior is only to free data that was allocated internally +by libpng. This can be changed, so that libpng will not free the data, +or so that it will free data that was allocated by the user with png_malloc() +or png_calloc() and passed in via a png_set_*() function, with + + png_data_freer(png_ptr, info_ptr, freer, mask) + + freer - one of + PNG_DESTROY_WILL_FREE_DATA + PNG_SET_WILL_FREE_DATA + PNG_USER_WILL_FREE_DATA + + mask - which data elements are affected + same choices as in png_free_data() + +This function only affects data that has already been allocated. +You can call this function after reading the PNG data but before calling +any png_set_*() functions, to control whether the user or the png_set_*() +function is responsible for freeing any existing data that might be present, +and again after the png_set_*() functions to control whether the user +or png_destroy_*() is supposed to free the data. When the user assumes +responsibility for libpng-allocated data, the application must use +png_free() to free it, and when the user transfers responsibility to libpng +for data that the user has allocated, the user must have used png_malloc() +or png_calloc() to allocate it. + +If you allocated your row_pointers in a single block, as suggested above in +the description of the high level read interface, you must not transfer +responsibility for freeing it to the png_set_rows or png_read_destroy function, +because they would also try to free the individual row_pointers[i]. + +If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword +separately, do not transfer responsibility for freeing text_ptr to libpng, +because when libpng fills a png_text structure it combines these members with +the key member, and png_free_data() will free only text_ptr.key. Similarly, +if you transfer responsibility for free'ing text_ptr from libpng to your +application, your application must not separately free those members. + +The png_free_data() function will turn off the "valid" flag for anything +it frees. If you need to turn the flag off for a chunk that was freed by +your application instead of by libpng, you can use + + png_set_invalid(png_ptr, info_ptr, mask); + + mask - identifies the chunks to be made invalid, + containing the bitwise OR of one or + more of + PNG_INFO_gAMA, PNG_INFO_sBIT, + PNG_INFO_cHRM, PNG_INFO_PLTE, + PNG_INFO_tRNS, PNG_INFO_bKGD, + PNG_INFO_hIST, PNG_INFO_pHYs, + PNG_INFO_oFFs, PNG_INFO_tIME, + PNG_INFO_pCAL, PNG_INFO_sRGB, + PNG_INFO_iCCP, PNG_INFO_sPLT, + PNG_INFO_sCAL, PNG_INFO_IDAT + +For a more compact example of reading a PNG image, see the file example.c. + +Reading PNG files progressively + +The progressive reader is slightly different from the non-progressive +reader. Instead of calling png_read_info(), png_read_rows(), and +png_read_end(), you make one call to png_process_data(), which calls +callbacks when it has the info, a row, or the end of the image. You +set up these callbacks with png_set_progressive_read_fn(). You don't +have to worry about the input/output functions of libpng, as you are +giving the library the data directly in png_process_data(). I will +assume that you have read the section on reading PNG files above, +so I will only highlight the differences (although I will show +all of the code). + +png_structp png_ptr; +png_infop info_ptr; + + /* An example code fragment of how you would + initialize the progressive reader in your + application. */ + int + initialize_png_reader() + { + png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + + if (!png_ptr) + return (ERROR); + + info_ptr = png_create_info_struct(png_ptr); + + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, + (png_infopp)NULL, (png_infopp)NULL); + return (ERROR); + } + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + + /* This one's new. You can provide functions + to be called when the header info is valid, + when each row is completed, and when the image + is finished. If you aren't using all functions, + you can specify NULL parameters. Even when all + three functions are NULL, you need to call + png_set_progressive_read_fn(). You can use + any struct as the user_ptr (cast to a void pointer + for the function call), and retrieve the pointer + from inside the callbacks using the function + + png_get_progressive_ptr(png_ptr); + + which will return a void pointer, which you have + to cast appropriately. + */ + png_set_progressive_read_fn(png_ptr, (void *)user_ptr, + info_callback, row_callback, end_callback); + + return 0; + } + + /* A code fragment that you call as you receive blocks + of data */ + int + process_data(png_bytep buffer, png_uint_32 length) + { + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + + /* This one's new also. Simply give it a chunk + of data from the file stream (in order, of + course). On machines with segmented memory + models machines, don't give it any more than + 64K. The library seems to run fine with sizes + of 4K. Although you can give it much less if + necessary (I assume you can give it chunks of + 1 byte, I haven't tried less than 256 bytes + yet). When this function returns, you may + want to display any rows that were generated + in the row callback if you don't already do + so there. + */ + png_process_data(png_ptr, info_ptr, buffer, length); + + /* At this point you can call png_process_data_skip if + you want to handle data the library will skip yourself; + it simply returns the number of bytes to skip (and stops + libpng skipping that number of bytes on the next + png_process_data call). + return 0; + } + + /* This function is called (as set by + png_set_progressive_read_fn() above) when enough data + has been supplied so all of the header has been + read. + */ + void + info_callback(png_structp png_ptr, png_infop info) + { + /* Do any setup here, including setting any of + the transformations mentioned in the Reading + PNG files section. For now, you _must_ call + either png_start_read_image() or + png_read_update_info() after all the + transformations are set (even if you don't set + any). You may start getting rows before + png_process_data() returns, so this is your + last chance to prepare for that. + + This is where you turn on interlace handling, + assuming you don't want to do it yourself. + + If you need to you can stop the processing of + your original input data at this point by calling + png_process_data_pause. This returns the number + of unprocessed bytes from the last png_process_data + call - it is up to you to ensure that the next call + sees these bytes again. If you don't want to bother + with this you can get libpng to cache the unread + bytes by setting the 'save' parameter (see png.h) but + then libpng will have to copy the data internally. + */ + } + + /* This function is called when each row of image + data is complete */ + void + row_callback(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass) + { + /* If the image is interlaced, and you turned + on the interlace handler, this function will + be called for every row in every pass. Some + of these rows will not be changed from the + previous pass. When the row is not changed, + the new_row variable will be NULL. The rows + and passes are called in order, so you don't + really need the row_num and pass, but I'm + supplying them because it may make your life + easier. + + If you did not turn on interlace handling then + the callback is called for each row of each + sub-image when the image is interlaced. In this + case 'row_num' is the row in the sub-image, not + the row in the output image as it is in all other + cases. + + For the non-NULL rows of interlaced images when + you have switched on libpng interlace handling, + you must call png_progressive_combine_row() + passing in the row and the old row. You can + call this function for NULL rows (it will just + return) and for non-interlaced images (it just + does the memcpy for you) if it will make the + code easier. Thus, you can just do this for + all cases if you switch on interlace handling; + */ + + png_progressive_combine_row(png_ptr, old_row, + new_row); + + /* where old_row is what was displayed + previously for the row. Note that the first + pass (pass == 0, really) will completely cover + the old row, so the rows do not have to be + initialized. After the first pass (and only + for interlaced images), you will have to pass + the current row, and the function will combine + the old row and the new row. + + You can also call png_process_data_pause in this + callback - see above. + */ + } + + void + end_callback(png_structp png_ptr, png_infop info) + { + /* This function is called after the whole image + has been read, including any chunks after the + image (up to and including the IEND). You + will usually have the same info chunk as you + had in the header, although some data may have + been added to the comments and time fields. + + Most people won't do much here, perhaps setting + a flag that marks the image as finished. + */ + } + + + +IV. Writing + +Much of this is very similar to reading. However, everything of +importance is repeated here, so you won't have to constantly look +back up in the reading section to understand writing. + +Setup + +You will want to do the I/O initialization before you get into libpng, +so if it doesn't work, you don't have anything to undo. If you are not +using the standard I/O functions, you will need to replace them with +custom writing functions. See the discussion under Customizing libpng. + + FILE *fp = fopen(file_name, "wb"); + + if (!fp) + return (ERROR); + +Next, png_struct and png_info need to be allocated and initialized. +As these can be both relatively large, you may not want to store these +on the stack, unless you have stack space to spare. Of course, you +will want to check if they return NULL. If you are also reading, +you won't want to name your read structure and your write structure +both "png_ptr"; you can call them anything you like, such as +"read_ptr" and "write_ptr". Look at pngtest.c, for example. + + png_structp png_ptr = png_create_write_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + + if (!png_ptr) + return (ERROR); + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_write_struct(&png_ptr, + (png_infopp)NULL); + return (ERROR); + } + +If you want to use your own memory allocation routines, +define PNG_USER_MEM_SUPPORTED and use +png_create_write_struct_2() instead of png_create_write_struct(): + + png_structp png_ptr = png_create_write_struct_2 + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn, (png_voidp) + user_mem_ptr, user_malloc_fn, user_free_fn); + +After you have these structures, you will need to set up the +error handling. When libpng encounters an error, it expects to +longjmp() back to your routine. Therefore, you will need to call +setjmp() and pass the png_jmpbuf(png_ptr). If you +write the file from different routines, you will need to update +the png_jmpbuf(png_ptr) every time you enter a new routine that will +call a png_*() function. See your documentation of setjmp/longjmp +for your compiler for more information on setjmp/longjmp. See +the discussion on libpng error handling in the Customizing Libpng +section below for more information on the libpng error handling. + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + return (ERROR); + } + ... + return; + +If you would rather avoid the complexity of setjmp/longjmp issues, +you can compile libpng with PNG_NO_SETJMP, in which case +errors will result in a call to PNG_ABORT() which defaults to abort(). + +You can #define PNG_ABORT() to a function that does something +more useful than abort(), as long as your function does not +return. + +Checking for invalid palette index on write was added at libpng +1.5.10. If a pixel contains an invalid (out-of-range) index libpng issues +a benign error. This is enabled by default because this condition is an +error according to the PNG specification, Clause 11.3.2, but the error can +be ignored in each png_ptr with + + png_set_check_for_invalid_index(png_ptr, 0); + +If the error is ignored, or if png_benign_error() treats it as a warning, +any invalid pixels are written as-is by the encoder, resulting in an +invalid PNG datastream as output. In this case the application is +responsible for ensuring that the pixel indexes are in range when it writes +a PLTE chunk with fewer entries than the bit depth would allow. + +Now you need to set up the output code. The default for libpng is to +use the C function fwrite(). If you use this, you will need to pass a +valid FILE * in the function png_init_io(). Be sure that the file is +opened in binary mode. Again, if you wish to handle writing data in +another way, see the discussion on libpng I/O handling in the Customizing +Libpng section below. + + png_init_io(png_ptr, fp); + +If you are embedding your PNG into a datastream such as MNG, and don't +want libpng to write the 8-byte signature, or if you have already +written the signature in your application, use + + png_set_sig_bytes(png_ptr, 8); + +to inform libpng that it should not write a signature. + +Write callbacks + +At this point, you can set up a callback function that will be +called after each row has been written, which you can use to control +a progress meter or the like. It's demonstrated in pngtest.c. +You must supply a function + + void write_row_callback(png_structp png_ptr, png_uint_32 row, + int pass); + { + /* put your code here */ + } + +(You can give it another name that you like instead of "write_row_callback") + +To inform libpng about your function, use + + png_set_write_status_fn(png_ptr, write_row_callback); + +When this function is called the row has already been completely processed and +it has also been written out. The 'row' and 'pass' refer to the next row to be +handled. For the +non-interlaced case the row that was just handled is simply one less than the +passed in row number, and pass will always be 0. For the interlaced case the +same applies unless the row value is 0, in which case the row just handled was +the last one from one of the preceding passes. Because interlacing may skip a +pass you cannot be sure that the preceding pass is just 'pass-1', if you really +need to know what the last pass is record (row,pass) from the callback and use +the last recorded value each time. + +As with the user transform you can find the output row using the +PNG_ROW_FROM_PASS_ROW macro. + +You now have the option of modifying how the compression library will +run. The following functions are mainly for testing, but may be useful +in some cases, like if you need to write PNG files extremely fast and +are willing to give up some compression, or if you want to get the +maximum possible compression at the expense of slower writing. If you +have no special needs in this area, let the library do what it wants by +not calling this function at all, as it has been tuned to deliver a good +speed/compression ratio. The second parameter to png_set_filter() is +the filter method, for which the only valid values are 0 (as of the +July 1999 PNG specification, version 1.2) or 64 (if you are writing +a PNG datastream that is to be embedded in a MNG datastream). The third +parameter is a flag that indicates which filter type(s) are to be tested +for each scanline. See the PNG specification for details on the specific +filter types. + + + /* turn on or off filtering, and/or choose + specific filters. You can use either a single + PNG_FILTER_VALUE_NAME or the bitwise OR of one + or more PNG_FILTER_NAME masks. + */ + png_set_filter(png_ptr, 0, + PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | + PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB | + PNG_FILTER_UP | PNG_FILTER_VALUE_UP | + PNG_FILTER_AVG | PNG_FILTER_VALUE_AVG | + PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH| + PNG_ALL_FILTERS | PNG_FAST_FILTERS); + +If an application wants to start and stop using particular filters during +compression, it should start out with all of the filters (to ensure that +the previous row of pixels will be stored in case it's needed later), +and then add and remove them after the start of compression. + +If you are writing a PNG datastream that is to be embedded in a MNG +datastream, the second parameter can be either 0 or 64. + +The png_set_compression_*() functions interface to the zlib compression +library, and should mostly be ignored unless you really know what you are +doing. The only generally useful call is png_set_compression_level() +which changes how much time zlib spends on trying to compress the image +data. See the Compression Library (zlib.h and algorithm.txt, distributed +with zlib) for details on the compression levels. + + #include zlib.h + + /* Set the zlib compression level */ + png_set_compression_level(png_ptr, + Z_BEST_COMPRESSION); + + /* Set other zlib parameters for compressing IDAT */ + png_set_compression_mem_level(png_ptr, 8); + png_set_compression_strategy(png_ptr, + Z_DEFAULT_STRATEGY); + png_set_compression_window_bits(png_ptr, 15); + png_set_compression_method(png_ptr, 8); + png_set_compression_buffer_size(png_ptr, 8192) + + /* Set zlib parameters for text compression + * If you don't call these, the parameters + * fall back on those defined for IDAT chunks + */ + png_set_text_compression_mem_level(png_ptr, 8); + png_set_text_compression_strategy(png_ptr, + Z_DEFAULT_STRATEGY); + png_set_text_compression_window_bits(png_ptr, 15); + png_set_text_compression_method(png_ptr, 8); + +Setting the contents of info for output + +You now need to fill in the png_info structure with all the data you +wish to write before the actual image. Note that the only thing you +are allowed to write after the image is the text chunks and the time +chunk (as of PNG Specification 1.2, anyway). See png_write_end() and +the latest PNG specification for more information on that. If you +wish to write them before the image, fill them in now, and flag that +data as being valid. If you want to wait until after the data, don't +fill them until png_write_end(). For all the fields in png_info and +their data types, see png.h. For explanations of what the fields +contain, see the PNG specification. + +Some of the more important parts of the png_info are: + + png_set_IHDR(png_ptr, info_ptr, width, height, + bit_depth, color_type, interlace_type, + compression_type, filter_method) + + width - holds the width of the image + in pixels (up to 2^31). + + height - holds the height of the image + in pixels (up to 2^31). + + bit_depth - holds the bit depth of one of the + image channels. + (valid values are 1, 2, 4, 8, 16 + and depend also on the + color_type. See also significant + bits (sBIT) below). + + color_type - describes which color/alpha + channels are present. + PNG_COLOR_TYPE_GRAY + (bit depths 1, 2, 4, 8, 16) + PNG_COLOR_TYPE_GRAY_ALPHA + (bit depths 8, 16) + PNG_COLOR_TYPE_PALETTE + (bit depths 1, 2, 4, 8) + PNG_COLOR_TYPE_RGB + (bit_depths 8, 16) + PNG_COLOR_TYPE_RGB_ALPHA + (bit_depths 8, 16) + + PNG_COLOR_MASK_PALETTE + PNG_COLOR_MASK_COLOR + PNG_COLOR_MASK_ALPHA + + interlace_type - PNG_INTERLACE_NONE or + PNG_INTERLACE_ADAM7 + + compression_type - (must be + PNG_COMPRESSION_TYPE_DEFAULT) + + filter_method - (must be PNG_FILTER_TYPE_DEFAULT + or, if you are writing a PNG to + be embedded in a MNG datastream, + can also be + PNG_INTRAPIXEL_DIFFERENCING) + +If you call png_set_IHDR(), the call must appear before any of the +other png_set_*() functions, because they might require access to some of +the IHDR settings. The remaining png_set_*() functions can be called +in any order. + +If you wish, you can reset the compression_type, interlace_type, or +filter_method later by calling png_set_IHDR() again; if you do this, the +width, height, bit_depth, and color_type must be the same in each call. + + png_set_PLTE(png_ptr, info_ptr, palette, + num_palette); + + palette - the palette for the file + (array of png_color) + num_palette - number of entries in the palette + + + png_set_gAMA(png_ptr, info_ptr, file_gamma); + png_set_gAMA_fixed(png_ptr, info_ptr, int_file_gamma); + + file_gamma - the gamma at which the image was + created (PNG_INFO_gAMA) + + int_file_gamma - 100,000 times the gamma at which + the image was created + + png_set_cHRM(png_ptr, info_ptr, white_x, white_y, red_x, red_y, + green_x, green_y, blue_x, blue_y) + png_set_cHRM_XYZ(png_ptr, info_ptr, red_X, red_Y, red_Z, green_X, + green_Y, green_Z, blue_X, blue_Y, blue_Z) + png_set_cHRM_fixed(png_ptr, info_ptr, int_white_x, int_white_y, + int_red_x, int_red_y, int_green_x, int_green_y, + int_blue_x, int_blue_y) + png_set_cHRM_XYZ_fixed(png_ptr, info_ptr, int_red_X, int_red_Y, + int_red_Z, int_green_X, int_green_Y, int_green_Z, + int_blue_X, int_blue_Y, int_blue_Z) + + {white,red,green,blue}_{x,y} + A color space encoding specified using the chromaticities + of the end points and the white point. + + {red,green,blue}_{X,Y,Z} + A color space encoding specified using the encoding end + points - the CIE tristimulus specification of the intended + color of the red, green and blue channels in the PNG RGB + data. The white point is simply the sum of the three end + points. + + png_set_sRGB(png_ptr, info_ptr, srgb_intent); + + srgb_intent - the rendering intent + (PNG_INFO_sRGB) The presence of + the sRGB chunk means that the pixel + data is in the sRGB color space. + This chunk also implies specific + values of gAMA and cHRM. Rendering + intent is the CSS-1 property that + has been defined by the International + Color Consortium + (http://www.color.org). + It can be one of + PNG_sRGB_INTENT_SATURATION, + PNG_sRGB_INTENT_PERCEPTUAL, + PNG_sRGB_INTENT_ABSOLUTE, or + PNG_sRGB_INTENT_RELATIVE. + + + png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, + srgb_intent); + + srgb_intent - the rendering intent + (PNG_INFO_sRGB) The presence of the + sRGB chunk means that the pixel + data is in the sRGB color space. + This function also causes gAMA and + cHRM chunks with the specific values + that are consistent with sRGB to be + written. + + png_set_iCCP(png_ptr, info_ptr, name, compression_type, + profile, proflen); + + name - The profile name. + + compression_type - The compression type; always + PNG_COMPRESSION_TYPE_BASE for PNG 1.0. + You may give NULL to this argument to + ignore it. + + profile - International Color Consortium color + profile data. May contain NULs. + + proflen - length of profile data in bytes. + + png_set_sBIT(png_ptr, info_ptr, sig_bit); + + sig_bit - the number of significant bits for + (PNG_INFO_sBIT) each of the gray, red, + green, and blue channels, whichever are + appropriate for the given color type + (png_color_16) + + png_set_tRNS(png_ptr, info_ptr, trans_alpha, + num_trans, trans_color); + + trans_alpha - array of alpha (transparency) + entries for palette (PNG_INFO_tRNS) + + num_trans - number of transparent entries + (PNG_INFO_tRNS) + + trans_color - graylevel or color sample values + (in order red, green, blue) of the + single transparent color for + non-paletted images (PNG_INFO_tRNS) + + png_set_hIST(png_ptr, info_ptr, hist); + + hist - histogram of palette (array of + png_uint_16) (PNG_INFO_hIST) + + png_set_tIME(png_ptr, info_ptr, mod_time); + + mod_time - time image was last modified + (PNG_VALID_tIME) + + png_set_bKGD(png_ptr, info_ptr, background); + + background - background color (of type + png_color_16p) (PNG_VALID_bKGD) + + png_set_text(png_ptr, info_ptr, text_ptr, num_text); + + text_ptr - array of png_text holding image + comments + + text_ptr[i].compression - type of compression used + on "text" PNG_TEXT_COMPRESSION_NONE + PNG_TEXT_COMPRESSION_zTXt + PNG_ITXT_COMPRESSION_NONE + PNG_ITXT_COMPRESSION_zTXt + text_ptr[i].key - keyword for comment. Must contain + 1-79 characters. + text_ptr[i].text - text comments for current + keyword. Can be NULL or empty. + text_ptr[i].text_length - length of text string, + after decompression, 0 for iTXt + text_ptr[i].itxt_length - length of itxt string, + after decompression, 0 for tEXt/zTXt + text_ptr[i].lang - language of comment (NULL or + empty for unknown). + text_ptr[i].translated_keyword - keyword in UTF-8 (NULL + or empty for unknown). + + Note that the itxt_length, lang, and lang_key + members of the text_ptr structure only exist when the + library is built with iTXt chunk support. Prior to + libpng-1.4.0 the library was built by default without + iTXt support. Also note that when iTXt is supported, + they contain NULL pointers when the "compression" + field contains PNG_TEXT_COMPRESSION_NONE or + PNG_TEXT_COMPRESSION_zTXt. + + num_text - number of comments + + png_set_sPLT(png_ptr, info_ptr, &palette_ptr, + num_spalettes); + + palette_ptr - array of png_sPLT_struct structures + to be added to the list of palettes + in the info structure. + num_spalettes - number of palette structures to be + added. + + png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, + unit_type); + + offset_x - positive offset from the left + edge of the screen + + offset_y - positive offset from the top + edge of the screen + + unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER + + png_set_pHYs(png_ptr, info_ptr, res_x, res_y, + unit_type); + + res_x - pixels/unit physical resolution + in x direction + + res_y - pixels/unit physical resolution + in y direction + + unit_type - PNG_RESOLUTION_UNKNOWN, + PNG_RESOLUTION_METER + + png_set_sCAL(png_ptr, info_ptr, unit, width, height) + + unit - physical scale units (an integer) + + width - width of a pixel in physical scale units + + height - height of a pixel in physical scale units + (width and height are doubles) + + png_set_sCAL_s(png_ptr, info_ptr, unit, width, height) + + unit - physical scale units (an integer) + + width - width of a pixel in physical scale units + expressed as a string + + height - height of a pixel in physical scale units + (width and height are strings like "2.54") + + png_set_unknown_chunks(png_ptr, info_ptr, &unknowns, + num_unknowns) + + unknowns - array of png_unknown_chunk + structures holding unknown chunks + unknowns[i].name - name of unknown chunk + unknowns[i].data - data of unknown chunk + unknowns[i].size - size of unknown chunk's data + unknowns[i].location - position to write chunk in file + 0: do not write chunk + PNG_HAVE_IHDR: before PLTE + PNG_HAVE_PLTE: before IDAT + PNG_AFTER_IDAT: after IDAT + +The "location" member is set automatically according to +what part of the output file has already been written. +You can change its value after calling png_set_unknown_chunks() +as demonstrated in pngtest.c. Within each of the "locations", +the chunks are sequenced according to their position in the +structure (that is, the value of "i", which is the order in which +the chunk was either read from the input file or defined with +png_set_unknown_chunks). + +A quick word about text and num_text. text is an array of png_text +structures. num_text is the number of valid structures in the array. +Each png_text structure holds a language code, a keyword, a text value, +and a compression type. + +The compression types have the same valid numbers as the compression +types of the image data. Currently, the only valid number is zero. +However, you can store text either compressed or uncompressed, unlike +images, which always have to be compressed. So if you don't want the +text compressed, set the compression type to PNG_TEXT_COMPRESSION_NONE. +Because tEXt and zTXt chunks don't have a language field, if you +specify PNG_TEXT_COMPRESSION_NONE or PNG_TEXT_COMPRESSION_zTXt +any language code or translated keyword will not be written out. + +Until text gets around a few hundred bytes, it is not worth compressing it. +After the text has been written out to the file, the compression type +is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR, +so that it isn't written out again at the end (in case you are calling +png_write_end() with the same struct). + +The keywords that are given in the PNG Specification are: + + Title Short (one line) title or + caption for image + + Author Name of image's creator + + Description Description of image (possibly long) + + Copyright Copyright notice + + Creation Time Time of original image creation + (usually RFC 1123 format, see below) + + Software Software used to create the image + + Disclaimer Legal disclaimer + + Warning Warning of nature of content + + Source Device used to create the image + + Comment Miscellaneous comment; conversion + from other image format + +The keyword-text pairs work like this. Keywords should be short +simple descriptions of what the comment is about. Some typical +keywords are found in the PNG specification, as is some recommendations +on keywords. You can repeat keywords in a file. You can even write +some text before the image and some after. For example, you may want +to put a description of the image before the image, but leave the +disclaimer until after, so viewers working over modem connections +don't have to wait for the disclaimer to go over the modem before +they start seeing the image. Finally, keywords should be full +words, not abbreviations. Keywords and text are in the ISO 8859-1 +(Latin-1) character set (a superset of regular ASCII) and can not +contain NUL characters, and should not contain control or other +unprintable characters. To make the comments widely readable, stick +with basic ASCII, and avoid machine specific character set extensions +like the IBM-PC character set. The keyword must be present, but +you can leave off the text string on non-compressed pairs. +Compressed pairs must have a text string, as only the text string +is compressed anyway, so the compression would be meaningless. + +PNG supports modification time via the png_time structure. Two +conversion routines are provided, png_convert_from_time_t() for +time_t and png_convert_from_struct_tm() for struct tm. The +time_t routine uses gmtime(). You don't have to use either of +these, but if you wish to fill in the png_time structure directly, +you should provide the time in universal time (GMT) if possible +instead of your local time. Note that the year number is the full +year (e.g. 1998, rather than 98 - PNG is year 2000 compliant!), and +that months start with 1. + +If you want to store the time of the original image creation, you should +use a plain tEXt chunk with the "Creation Time" keyword. This is +necessary because the "creation time" of a PNG image is somewhat vague, +depending on whether you mean the PNG file, the time the image was +created in a non-PNG format, a still photo from which the image was +scanned, or possibly the subject matter itself. In order to facilitate +machine-readable dates, it is recommended that the "Creation Time" +tEXt chunk use RFC 1123 format dates (e.g. "22 May 1997 18:07:10 GMT"), +although this isn't a requirement. Unlike the tIME chunk, the +"Creation Time" tEXt chunk is not expected to be automatically changed +by the software. To facilitate the use of RFC 1123 dates, a function +png_convert_to_rfc1123_buffer(buffer, png_timep) is provided to +convert from PNG time to an RFC 1123 format string. The caller must provide +a writeable buffer of at least 29 bytes. + +Writing unknown chunks + +You can use the png_set_unknown_chunks function to queue up private chunks +for writing. You give it a chunk name, location, raw data, and a size. You +also must use png_set_keep_unknown_chunks() to ensure that libpng will +handle them. That's all there is to it. The chunks will be written by the +next following png_write_info_before_PLTE, png_write_info, or png_write_end +function, depending upon the specified location. Any chunks previously +read into the info structure's unknown-chunk list will also be written out +in a sequence that satisfies the PNG specification's ordering rules. + +Here is an example of writing two private chunks, prVt and miNE: + + #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + /* Set unknown chunk data */ + png_unknown_chunk unk_chunk[2]; + strcpy((char *) unk_chunk[0].name, "prVt"; + unk_chunk[0].data = (unsigned char *) "PRIVATE DATA"; + unk_chunk[0].size = strlen(unk_chunk[0].data)+1; + unk_chunk[0].location = PNG_HAVE_IHDR; + strcpy((char *) unk_chunk[1].name, "miNE"; + unk_chunk[1].data = (unsigned char *) "MY CHUNK DATA"; + unk_chunk[1].size = strlen(unk_chunk[0].data)+1; + unk_chunk[1].location = PNG_AFTER_IDAT; + png_set_unknown_chunks(write_ptr, write_info_ptr, + unk_chunk, 2); + /* Needed because miNE is not safe-to-copy */ + png_set_keep_unknown_chunks(png, PNG_HANDLE_CHUNK_ALWAYS, + (png_bytep) "miNE", 1); + # if PNG_LIBPNG_VER < 10600 + /* Deal with unknown chunk location bug in 1.5.x and earlier */ + png_set_unknown_chunk_location(png, info, 0, PNG_HAVE_IHDR); + png_set_unknown_chunk_location(png, info, 1, PNG_AFTER_IDAT); + # endif + # if PNG_LIBPNG_VER < 10500 + /* PNG_AFTER_IDAT writes two copies of the chunk prior to libpng-1.5.0, + * one before IDAT and another after IDAT, so don't use it; only use + * PNG_HAVE_IHDR location. This call resets the location previously + * set by assignment and png_set_unknown_chunk_location() for chunk 1. + */ + png_set_unknown_chunk_location(png, info, 1, PNG_HAVE_IHDR); + # endif + #endif + +The high-level write interface + +At this point there are two ways to proceed; through the high-level +write interface, or through a sequence of low-level write operations. +You can use the high-level interface if your image data is present +in the info structure. All defined output +transformations are permitted, enabled by the following masks. + + PNG_TRANSFORM_IDENTITY No transformation + PNG_TRANSFORM_PACKING Pack 1, 2 and 4-bit samples + PNG_TRANSFORM_PACKSWAP Change order of packed + pixels to LSB first + PNG_TRANSFORM_INVERT_MONO Invert monochrome images + PNG_TRANSFORM_SHIFT Normalize pixels to the + sBIT depth + PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA + to BGRA + PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA + to AG + PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity + to transparency + PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples + PNG_TRANSFORM_STRIP_FILLER Strip out filler + bytes (deprecated). + PNG_TRANSFORM_STRIP_FILLER_BEFORE Strip out leading + filler bytes + PNG_TRANSFORM_STRIP_FILLER_AFTER Strip out trailing + filler bytes + +If you have valid image data in the info structure (you can use +png_set_rows() to put image data in the info structure), simply do this: + + png_write_png(png_ptr, info_ptr, png_transforms, NULL) + +where png_transforms is an integer containing the bitwise OR of some set of +transformation flags. This call is equivalent to png_write_info(), +followed the set of transformations indicated by the transform mask, +then png_write_image(), and finally png_write_end(). + +(The final parameter of this call is not yet used. Someday it might point +to transformation parameters required by some future output transform.) + +You must use png_transforms and not call any png_set_transform() functions +when you use png_write_png(). + +The low-level write interface + +If you are going the low-level route instead, you are now ready to +write all the file information up to the actual image data. You do +this with a call to png_write_info(). + + png_write_info(png_ptr, info_ptr); + +Note that there is one transformation you may need to do before +png_write_info(). In PNG files, the alpha channel in an image is the +level of opacity. If your data is supplied as a level of transparency, +you can invert the alpha channel before you write it, so that 0 is +fully transparent and 255 (in 8-bit or paletted images) or 65535 +(in 16-bit images) is fully opaque, with + + png_set_invert_alpha(png_ptr); + +This must appear before png_write_info() instead of later with the +other transformations because in the case of paletted images the tRNS +chunk data has to be inverted before the tRNS chunk is written. If +your image is not a paletted image, the tRNS data (which in such cases +represents a single color to be rendered as transparent) won't need to +be changed, and you can safely do this transformation after your +png_write_info() call. + +If you need to write a private chunk that you want to appear before +the PLTE chunk when PLTE is present, you can write the PNG info in +two steps, and insert code to write your own chunk between them: + + png_write_info_before_PLTE(png_ptr, info_ptr); + png_set_unknown_chunks(png_ptr, info_ptr, ...); + png_write_info(png_ptr, info_ptr); + +After you've written the file information, you can set up the library +to handle any special transformations of the image data. The various +ways to transform the data will be described in the order that they +should occur. This is important, as some of these change the color +type and/or bit depth of the data, and some others only work on +certain color types and bit depths. Even though each transformation +checks to see if it has data that it can do something with, you should +make sure to only enable a transformation if it will be valid for the +data. For example, don't swap red and blue on grayscale data. + +PNG files store RGB pixels packed into 3 or 6 bytes. This code tells +the library to strip input data that has 4 or 8 bytes per pixel down +to 3 or 6 bytes (or strip 2 or 4-byte grayscale+filler data to 1 or 2 +bytes per pixel). + + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); + +where the 0 is unused, and the location is either PNG_FILLER_BEFORE or +PNG_FILLER_AFTER, depending upon whether the filler byte in the pixel +is stored XRGB or RGBX. + +PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as +they can, resulting in, for example, 8 pixels per byte for 1 bit files. +If the data is supplied at 1 pixel per byte, use this code, which will +correctly pack the pixels into a single byte: + + png_set_packing(png_ptr); + +PNG files reduce possible bit depths to 1, 2, 4, 8, and 16. If your +data is of another bit depth, you can write an sBIT chunk into the +file so that decoders can recover the original data if desired. + + /* Set the true bit depth of the image data */ + if (color_type & PNG_COLOR_MASK_COLOR) + { + sig_bit.red = true_bit_depth; + sig_bit.green = true_bit_depth; + sig_bit.blue = true_bit_depth; + } + + else + { + sig_bit.gray = true_bit_depth; + } + + if (color_type & PNG_COLOR_MASK_ALPHA) + { + sig_bit.alpha = true_bit_depth; + } + + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + +If the data is stored in the row buffer in a bit depth other than +one supported by PNG (e.g. 3 bit data in the range 0-7 for a 4-bit PNG), +this will scale the values to appear to be the correct bit depth as +is required by PNG. + + png_set_shift(png_ptr, &sig_bit); + +PNG files store 16-bit pixels in network byte order (big-endian, +ie. most significant bits first). This code would be used if they are +supplied the other way (little-endian, i.e. least significant bits +first, the way PCs store them): + + if (bit_depth > 8) + png_set_swap(png_ptr); + +If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you +need to change the order the pixels are packed into bytes, you can use: + + if (bit_depth < 8) + png_set_packswap(png_ptr); + +PNG files store 3 color pixels in red, green, blue order. This code +would be used if they are supplied as blue, green, red: + + png_set_bgr(png_ptr); + +PNG files describe monochrome as black being zero and white being +one. This code would be used if the pixels are supplied with this reversed +(black being one and white being zero): + + png_set_invert_mono(png_ptr); + +Finally, you can write your own transformation function if none of +the existing ones meets your needs. This is done by setting a callback +with + + png_set_write_user_transform_fn(png_ptr, + write_transform_fn); + +You must supply the function + + void write_transform_fn(png_structp png_ptr, png_row_infop + row_info, png_bytep data) + +See pngtest.c for a working example. Your function will be called +before any of the other transformations are processed. If supported +libpng also supplies an information routine that may be called from +your callback: + + png_get_current_row_number(png_ptr); + png_get_current_pass_number(png_ptr); + +This returns the current row passed to the transform. With interlaced +images the value returned is the row in the input sub-image image. Use +PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to +find the output pixel (x,y) given an interlaced sub-image pixel (row,col,pass). + +The discussion of interlace handling above contains more information on how to +use these values. + +You can also set up a pointer to a user structure for use by your +callback function. + + png_set_user_transform_info(png_ptr, user_ptr, 0, 0); + +The user_channels and user_depth parameters of this function are ignored +when writing; you can set them to zero as shown. + +You can retrieve the pointer via the function png_get_user_transform_ptr(). +For example: + + voidp write_user_transform_ptr = + png_get_user_transform_ptr(png_ptr); + +It is possible to have libpng flush any pending output, either manually, +or automatically after a certain number of lines have been written. To +flush the output stream a single time call: + + png_write_flush(png_ptr); + +and to have libpng flush the output stream periodically after a certain +number of scanlines have been written, call: + + png_set_flush(png_ptr, nrows); + +Note that the distance between rows is from the last time png_write_flush() +was called, or the first row of the image if it has never been called. +So if you write 50 lines, and then png_set_flush 25, it will flush the +output on the next scanline, and every 25 lines thereafter, unless +png_write_flush() is called before 25 more lines have been written. +If nrows is too small (less than about 10 lines for a 640 pixel wide +RGB image) the image compression may decrease noticeably (although this +may be acceptable for real-time applications). Infrequent flushing will +only degrade the compression performance by a few percent over images +that do not use flushing. + +Writing the image data + +That's it for the transformations. Now you can write the image data. +The simplest way to do this is in one function call. If you have the +whole image in memory, you can just call png_write_image() and libpng +will write the image. You will need to pass in an array of pointers to +each row. This function automatically handles interlacing, so you don't +need to call png_set_interlace_handling() or call this function multiple +times, or any of that other stuff necessary with png_write_rows(). + + png_write_image(png_ptr, row_pointers); + +where row_pointers is: + + png_byte *row_pointers[height]; + +You can point to void or char or whatever you use for pixels. + +If you don't want to write the whole image at once, you can +use png_write_rows() instead. If the file is not interlaced, +this is simple: + + png_write_rows(png_ptr, row_pointers, + number_of_rows); + +row_pointers is the same as in the png_write_image() call. + +If you are just writing one row at a time, you can do this with +a single row_pointer instead of an array of row_pointers: + + png_bytep row_pointer = row; + + png_write_row(png_ptr, row_pointer); + +When the file is interlaced, things can get a good deal more complicated. +The only currently (as of the PNG Specification version 1.2, dated July +1999) defined interlacing scheme for PNG files is the "Adam7" interlace +scheme, that breaks down an image into seven smaller images of varying +size. libpng will build these images for you, or you can do them +yourself. If you want to build them yourself, see the PNG specification +for details of which pixels to write when. + +If you don't want libpng to handle the interlacing details, just +use png_set_interlace_handling() and call png_write_rows() the +correct number of times to write all the sub-images +(png_set_interlace_handling() returns the number of sub-images.) + +If you want libpng to build the sub-images, call this before you start +writing any rows: + + number_of_passes = png_set_interlace_handling(png_ptr); + +This will return the number of passes needed. Currently, this is seven, +but may change if another interlace type is added. + +Then write the complete image number_of_passes times. + + png_write_rows(png_ptr, row_pointers, number_of_rows); + +Think carefully before you write an interlaced image. Typically code that +reads such images reads all the image data into memory, uncompressed, before +doing any processing. Only code that can display an image on the fly can +take advantage of the interlacing and even then the image has to be exactly +the correct size for the output device, because scaling an image requires +adjacent pixels and these are not available until all the passes have been +read. + +If you do write an interlaced image you will hardly ever need to handle +the interlacing yourself. Call png_set_interlace_handling() and use the +approach described above. + +The only time it is conceivable that you will really need to write an +interlaced image pass-by-pass is when you have read one pass by pass and +made some pixel-by-pixel transformation to it, as described in the read +code above. In this case use the PNG_PASS_ROWS and PNG_PASS_COLS macros +to determine the size of each sub-image in turn and simply write the rows +you obtained from the read code. + +Finishing a sequential write + +After you are finished writing the image, you should finish writing +the file. If you are interested in writing comments or time, you should +pass an appropriately filled png_info pointer. If you are not interested, +you can pass NULL. + + png_write_end(png_ptr, info_ptr); + +When you are done, you can free all memory used by libpng like this: + + png_destroy_write_struct(&png_ptr, &info_ptr); + +It is also possible to individually free the info_ptr members that +point to libpng-allocated storage with the following function: + + png_free_data(png_ptr, info_ptr, mask, seq) + + mask - identifies data to be freed, a mask + containing the bitwise OR of one or + more of + PNG_FREE_PLTE, PNG_FREE_TRNS, + PNG_FREE_HIST, PNG_FREE_ICCP, + PNG_FREE_PCAL, PNG_FREE_ROWS, + PNG_FREE_SCAL, PNG_FREE_SPLT, + PNG_FREE_TEXT, PNG_FREE_UNKN, + or simply PNG_FREE_ALL + + seq - sequence number of item to be freed + (-1 for all items) + +This function may be safely called when the relevant storage has +already been freed, or has not yet been allocated, or was allocated +by the user and not by libpng, and will in those cases do nothing. +The "seq" parameter is ignored if only one item of the selected data +type, such as PLTE, is allowed. If "seq" is not -1, and multiple items +are allowed for the data type identified in the mask, such as text or +sPLT, only the n'th item in the structure is freed, where n is "seq". + +If you allocated data such as a palette that you passed in to libpng +with png_set_*, you must not free it until just before the call to +png_destroy_write_struct(). + +The default behavior is only to free data that was allocated internally +by libpng. This can be changed, so that libpng will not free the data, +or so that it will free data that was allocated by the user with png_malloc() +or png_calloc() and passed in via a png_set_*() function, with + + png_data_freer(png_ptr, info_ptr, freer, mask) + + freer - one of + PNG_DESTROY_WILL_FREE_DATA + PNG_SET_WILL_FREE_DATA + PNG_USER_WILL_FREE_DATA + + mask - which data elements are affected + same choices as in png_free_data() + +For example, to transfer responsibility for some data from a read structure +to a write structure, you could use + + png_data_freer(read_ptr, read_info_ptr, + PNG_USER_WILL_FREE_DATA, + PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) + + png_data_freer(write_ptr, write_info_ptr, + PNG_DESTROY_WILL_FREE_DATA, + PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) + +thereby briefly reassigning responsibility for freeing to the user but +immediately afterwards reassigning it once more to the write_destroy +function. Having done this, it would then be safe to destroy the read +structure and continue to use the PLTE, tRNS, and hIST data in the write +structure. + +This function only affects data that has already been allocated. +You can call this function before calling after the png_set_*() functions +to control whether the user or png_destroy_*() is supposed to free the data. +When the user assumes responsibility for libpng-allocated data, the +application must use +png_free() to free it, and when the user transfers responsibility to libpng +for data that the user has allocated, the user must have used png_malloc() +or png_calloc() to allocate it. + +If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword +separately, do not transfer responsibility for freeing text_ptr to libpng, +because when libpng fills a png_text structure it combines these members with +the key member, and png_free_data() will free only text_ptr.key. Similarly, +if you transfer responsibility for free'ing text_ptr from libpng to your +application, your application must not separately free those members. +For a more compact example of writing a PNG image, see the file example.c. + +V. Simplified API + +The simplified API, which became available in libpng-1.6.0, hides the details +of both libpng and the PNG file format itself. +It allows PNG files to be read into a very limited number of +in-memory bitmap formats or to be written from the same formats. If these +formats do not accommodate your needs then you can, and should, use the more +sophisticated APIs above - these support a wide variety of in-memory formats +and a wide variety of sophisticated transformations to those formats as well +as a wide variety of APIs to manipulate ancilliary information. + +To read a PNG file using the simplified API: + + 1) Declare a 'png_image' structure (see below) on the stack, set the + version field to PNG_IMAGE_VERSION and the 'opaque' pointer to NULL + (this is REQUIRED, your program may crash if you don't do it.) + + 2) Call the appropriate png_image_begin_read... function. + + 3) Set the png_image 'format' member to the required sample format. + + 4) Allocate a buffer for the image and, if required, the color-map. + + 5) Call png_image_finish_read to read the image and, if required, the + color-map into your buffers. + +There are no restrictions on the format of the PNG input itself; all valid +color types, bit depths, and interlace methods are acceptable, and the +input image is transformed as necessary to the requested in-memory format +during the png_image_finish_read() step. The only caveat is that if you +request a color-mapped image from a PNG that is full-color or makes +complex use of an alpha channel the transformation is extremely lossy and the +result may look terrible. + +To write a PNG file using the simplified API: + + 1) Declare a 'png_image' structure on the stack and memset() + it to all zero. + + 2) Initialize the members of the structure that describe the + image, setting the 'format' member to the format of the + image samples. + + 3) Call the appropriate png_image_write... function with a + pointer to the image and, if necessary, the color-map to write + the PNG data. + +png_image is a structure that describes the in-memory format of an image +when it is being read or defines the in-memory format of an image that you +need to write. The "png_image" structure contains the following members: + + png_controlp opaque Initialize to NULL, free with png_image_free + png_uint_32 version Set to PNG_IMAGE_VERSION + png_uint_32 width Image width in pixels (columns) + png_uint_32 height Image height in pixels (rows) + png_uint_32 format Image format as defined below + png_uint_32 flags A bit mask containing informational flags + png_uint_32 colormap_entries; Number of entries in the color-map + png_uint_32 warning_or_error; + char message[64]; + +In the event of an error or warning the "warning_or_error" +field will be set to a non-zero value and the 'message' field will contain +a '\0' terminated string with the libpng error or warning message. If both +warnings and an error were encountered, only the error is recorded. If there +are multiple warnings, only the first one is recorded. + +The upper 30 bits of the "warning_or_error" value are reserved; the low two +bits contain a two bit code such that a value more than 1 indicates a failure +in the API just called: + + 0 - no warning or error + 1 - warning + 2 - error + 3 - error preceded by warning + +The pixels (samples) of the image have one to four channels whose components +have original values in the range 0 to 1.0: + + 1: A single gray or luminance channel (G). + 2: A gray/luminance channel and an alpha channel (GA). + 3: Three red, green, blue color channels (RGB). + 4: Three color channels and an alpha channel (RGBA). + +The channels are encoded in one of two ways: + + a) As a small integer, value 0..255, contained in a single byte. For the +alpha channel the original value is simply value/255. For the color or +luminance channels the value is encoded according to the sRGB specification +and matches the 8-bit format expected by typical display devices. + +The color/gray channels are not scaled (pre-multiplied) by the alpha +channel and are suitable for passing to color management software. + + b) As a value in the range 0..65535, contained in a 2-byte integer, in +the native byte order of the platform on which the application is running. +All channels can be converted to the original value by dividing by 65535; all +channels are linear. Color channels use the RGB encoding (RGB end-points) of +the sRGB specification. This encoding is identified by the +PNG_FORMAT_FLAG_LINEAR flag below. + +When the simplified API needs to convert between sRGB and linear colorspaces, +the actual sRGB transfer curve defined in the sRGB specification (see the +article at http://en.wikipedia.org/wiki/SRGB) is used, not the gamma=1/2.2 +approximation used elsewhere in libpng. + +When an alpha channel is present it is expected to denote pixel coverage +of the color or luminance channels and is returned as an associated alpha +channel: the color/gray channels are scaled (pre-multiplied) by the alpha +value. + +The samples are either contained directly in the image data, between 1 and 8 +bytes per pixel according to the encoding, or are held in a color-map indexed +by bytes in the image data. In the case of a color-map the color-map entries +are individual samples, encoded as above, and the image data has one byte per +pixel to select the relevant sample from the color-map. + +PNG_FORMAT_* + +The #defines to be used in png_image::format. Each #define identifies a +particular layout of channel data and, if present, alpha values. There are +separate defines for each of the two component encodings. + +A format is built up using single bit flag values. All combinations are +valid. Formats can be built up from the flag values or you can use one of +the predefined values below. When testing formats always use the FORMAT_FLAG +macros to test for individual features - future versions of the library may +add new flags. + +When reading or writing color-mapped images the format should be set to the +format of the entries in the color-map then png_image_{read,write}_colormap +called to read or write the color-map and set the format correctly for the +image data. Do not set the PNG_FORMAT_FLAG_COLORMAP bit directly! + +NOTE: libpng can be built with particular features disabled. If you see +compiler errors because the definition of one of the following flags has been +compiled out it is because libpng does not have the required support. It is +possible, however, for the libpng configuration to enable the format on just +read or just write; in that case you may see an error at run time. +You can guard against this by checking for the definition of the +appropriate "_SUPPORTED" macro, one of: + + PNG_SIMPLIFIED_{READ,WRITE}_{BGR,AFIRST}_SUPPORTED + + PNG_FORMAT_FLAG_ALPHA format with an alpha channel + PNG_FORMAT_FLAG_COLOR color format: otherwise grayscale + PNG_FORMAT_FLAG_LINEAR 2-byte channels else 1-byte + PNG_FORMAT_FLAG_COLORMAP image data is color-mapped + PNG_FORMAT_FLAG_BGR BGR colors, else order is RGB + PNG_FORMAT_FLAG_AFIRST alpha channel comes first + +Supported formats are as follows. Future versions of libpng may support more +formats; for compatibility with older versions simply check if the format +macro is defined using #ifdef. These defines describe the in-memory layout +of the components of the pixels of the image. + +First the single byte (sRGB) formats: + + PNG_FORMAT_GRAY + PNG_FORMAT_GA + PNG_FORMAT_AG + PNG_FORMAT_RGB + PNG_FORMAT_BGR + PNG_FORMAT_RGBA + PNG_FORMAT_ARGB + PNG_FORMAT_BGRA + PNG_FORMAT_ABGR + +Then the linear 2-byte formats. When naming these "Y" is used to +indicate a luminance (gray) channel. The component order within the pixel +is always the same - there is no provision for swapping the order of the +components in the linear format. The components are 16-bit integers in +the native byte order for your platform, and there is no provision for +swapping the bytes to a different endian condition. + + PNG_FORMAT_LINEAR_Y + PNG_FORMAT_LINEAR_Y_ALPHA + PNG_FORMAT_LINEAR_RGB + PNG_FORMAT_LINEAR_RGB_ALPHA + +With color-mapped formats the image data is one byte for each pixel. The byte +is an index into the color-map which is formatted as above. To obtain a +color-mapped format it is sufficient just to add the PNG_FOMAT_FLAG_COLORMAP +to one of the above definitions, or you can use one of the definitions below. + + PNG_FORMAT_RGB_COLORMAP + PNG_FORMAT_BGR_COLORMAP + PNG_FORMAT_RGBA_COLORMAP + PNG_FORMAT_ARGB_COLORMAP + PNG_FORMAT_BGRA_COLORMAP + PNG_FORMAT_ABGR_COLORMAP + +PNG_IMAGE macros + +These are convenience macros to derive information from a png_image +structure. The PNG_IMAGE_SAMPLE_ macros return values appropriate to the +actual image sample values - either the entries in the color-map or the +pixels in the image. The PNG_IMAGE_PIXEL_ macros return corresponding values +for the pixels and will always return 1 for color-mapped formats. The +remaining macros return information about the rows in the image and the +complete image. + +NOTE: All the macros that take a png_image::format parameter are compile time +constants if the format parameter is, itself, a constant. Therefore these +macros can be used in array declarations and case labels where required. +Similarly the macros are also pre-processor constants (sizeof is not used) so +they can be used in #if tests. + + PNG_IMAGE_SAMPLE_CHANNELS(fmt) + Returns the total number of channels in a given format: 1..4 + + PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt) + Returns the size in bytes of a single component of a pixel or color-map + entry (as appropriate) in the image: 1 or 2. + + PNG_IMAGE_SAMPLE_SIZE(fmt) + This is the size of the sample data for one sample. If the image is + color-mapped it is the size of one color-map entry (and image pixels are + one byte in size), otherwise it is the size of one image pixel. + + PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(fmt) + The maximum size of the color-map required by the format expressed in a + count of components. This can be used to compile-time allocate a + color-map: + + png_uint_16 colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(linear_fmt)]; + + png_byte colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(sRGB_fmt)]; + + Alternatively use the PNG_IMAGE_COLORMAP_SIZE macro below to use the + information from one of the png_image_begin_read_ APIs and dynamically + allocate the required memory. + + PNG_IMAGE_COLORMAP_SIZE(fmt) + The size of the color-map required by the format; this is the size of the + color-map buffer passed to the png_image_{read,write}_colormap APIs. It is + a fixed number determined by the format so can easily be allocated on the + stack if necessary. + +Corresponding information about the pixels + + PNG_IMAGE_PIXEL_CHANNELS(fmt) + The number of separate channels (components) in a pixel; 1 for a + color-mapped image. + + PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)\ + The size, in bytes, of each component in a pixel; 1 for a color-mapped + image. + + PNG_IMAGE_PIXEL_SIZE(fmt) + The size, in bytes, of a complete pixel; 1 for a color-mapped image. + +Information about the whole row, or whole image + + PNG_IMAGE_ROW_STRIDE(image) + Returns the total number of components in a single row of the image; this + is the minimum 'row stride', the minimum count of components between each + row. For a color-mapped image this is the minimum number of bytes in a + row. + + If you need the stride measured in bytes, row_stride_bytes is + PNG_IMAGE_ROW_STRIDE(image) * PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt) + plus any padding bytes that your application might need, for example + to start the next row on a 4-byte boundary. + + PNG_IMAGE_BUFFER_SIZE(image, row_stride) + Return the size, in bytes, of an image buffer given a png_image and a row + stride - the number of components to leave space for in each row. + + PNG_IMAGE_SIZE(image) + Return the size, in bytes, of the image in memory given just a png_image; + the row stride is the minimum stride required for the image. + + PNG_IMAGE_COLORMAP_SIZE(image) + Return the size, in bytes, of the color-map of this image. If the image + format is not a color-map format this will return a size sufficient for + 256 entries in the given format; check PNG_FORMAT_FLAG_COLORMAP if + you don't want to allocate a color-map in this case. + +PNG_IMAGE_FLAG_* + +Flags containing additional information about the image are held in +the 'flags' field of png_image. + + PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB == 0x01 + This indicates the the RGB values of the in-memory bitmap do not + correspond to the red, green and blue end-points defined by sRGB. + + PNG_IMAGE_FLAG_FAST == 0x02 + On write emphasise speed over compression; the resultant PNG file will be + larger but will be produced significantly faster, particular for large + images. Do not use this option for images which will be distributed, only + used it when producing intermediate files that will be read back in + repeatedly. For a typical 24-bit image the option will double the read + speed at the cost of increasing the image size by 25%, however for many + more compressible images the PNG file can be 10 times larger with only a + slight speed gain. + + PNG_IMAGE_FLAG_16BIT_sRGB == 0x04 + On read if the image is a 16-bit per component image and there is no gAMA + or sRGB chunk assume that the components are sRGB encoded. Notice that + images output by the simplified API always have gamma information; setting + this flag only affects the interpretation of 16-bit images from an + external source. It is recommended that the application expose this flag + to the user; the user can normally easily recognize the difference between + linear and sRGB encoding. This flag has no effect on write - the data + passed to the write APIs must have the correct encoding (as defined + above.) + + If the flag is not set (the default) input 16-bit per component data is + assumed to be linear. + + NOTE: the flag can only be set after the png_image_begin_read_ call, + because that call initializes the 'flags' field. + +READ APIs + + The png_image passed to the read APIs must have been initialized by setting + the png_controlp field 'opaque' to NULL (or, better, memset the whole thing.) + + int png_image_begin_read_from_file( png_imagep image, + const char *file_name) + + The named file is opened for read and the image header + is filled in from the PNG header in the file. + + int png_image_begin_read_from_stdio (png_imagep image, + FILE* file) + + The PNG header is read from the stdio FILE object. + + int png_image_begin_read_from_memory(png_imagep image, + png_const_voidp memory, png_size_t size) + + The PNG header is read from the given memory buffer. + + int png_image_finish_read(png_imagep image, + png_colorp background, void *buffer, + png_int_32 row_stride, void *colormap)); + + Finish reading the image into the supplied buffer and + clean up the png_image structure. + + row_stride is the step, in png_byte or png_uint_16 units + as appropriate, between adjacent rows. A positive stride + indicates that the top-most row is first in the buffer - + the normal top-down arrangement. A negative stride + indicates that the bottom-most row is first in the buffer. + + background need only be supplied if an alpha channel must + be removed from a png_byte format and the removal is to be + done by compositing on a solid color; otherwise it may be + NULL and any composition will be done directly onto the + buffer. The value is an sRGB color to use for the + background, for grayscale output the green channel is used. + + For linear output removing the alpha channel is always done + by compositing on black. + + void png_image_free(png_imagep image) + + Free any data allocated by libpng in image->opaque, + setting the pointer to NULL. May be called at any time + after the structure is initialized. + +When the simplified API needs to convert between sRGB and linear colorspaces, +the actual sRGB transfer curve defined in the sRGB specification (see the +article at http://en.wikipedia.org/wiki/SRGB) is used, not the gamma=1/2.2 +approximation used elsewhere in libpng. + +WRITE APIS + +For write you must initialize a png_image structure to describe the image to +be written: + + version: must be set to PNG_IMAGE_VERSION + opaque: must be initialized to NULL + width: image width in pixels + height: image height in rows + format: the format of the data you wish to write + flags: set to 0 unless one of the defined flags applies; set + PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB for color format images + where the RGB values do not correspond to the colors in sRGB. + colormap_entries: set to the number of entries in the color-map (0 to 256) + + int png_image_write_to_file, (png_imagep image, + const char *file, int convert_to_8bit, const void *buffer, + png_int_32 row_stride, const void *colormap)); + + Write the image to the named file. + + int png_image_write_to_memory (png_imagep image, void *memory, + png_alloc_size_t * PNG_RESTRICT memory_bytes, + int convert_to_8_bit, const void *buffer, ptrdiff_t row_stride, + const void *colormap)); + + Write the image to memory. + + int png_image_write_to_stdio(png_imagep image, FILE *file, + int convert_to_8_bit, const void *buffer, + png_int_32 row_stride, const void *colormap) + + Write the image to the given (FILE*). + +With all write APIs if image is in one of the linear formats with +(png_uint_16) data then setting convert_to_8_bit will cause the output to be +a (png_byte) PNG gamma encoded according to the sRGB specification, otherwise +a 16-bit linear encoded PNG file is written. + +With all APIs row_stride is handled as in the read APIs - it is the spacing +from one row to the next in component sized units (float) and if negative +indicates a bottom-up row layout in the buffer. If you pass zero, libpng will +calculate the row_stride for you from the width and number of channels. + +Note that the write API does not support interlacing, sub-8-bit pixels, +indexed (paletted) images, or most ancillary chunks. + +VI. Modifying/Customizing libpng + +There are two issues here. The first is changing how libpng does +standard things like memory allocation, input/output, and error handling. +The second deals with more complicated things like adding new chunks, +adding new transformations, and generally changing how libpng works. +Both of those are compile-time issues; that is, they are generally +determined at the time the code is written, and there is rarely a need +to provide the user with a means of changing them. + +Memory allocation, input/output, and error handling + +All of the memory allocation, input/output, and error handling in libpng +goes through callbacks that are user-settable. The default routines are +in pngmem.c, pngrio.c, pngwio.c, and pngerror.c, respectively. To change +these functions, call the appropriate png_set_*_fn() function. + +Memory allocation is done through the functions png_malloc(), png_calloc(), +and png_free(). The png_malloc() and png_free() functions currently just +call the standard C functions and png_calloc() calls png_malloc() and then +clears the newly allocated memory to zero; note that png_calloc(png_ptr, size) +is not the same as the calloc(number, size) function provided by stdlib.h. +There is limited support for certain systems with segmented memory +architectures and the types of pointers declared by png.h match this; you +will have to use appropriate pointers in your application. If you prefer +to use a different method of allocating and freeing data, you can use +png_create_read_struct_2() or png_create_write_struct_2() to register your +own functions as described above. These functions also provide a void +pointer that can be retrieved via + + mem_ptr=png_get_mem_ptr(png_ptr); + +Your replacement memory functions must have prototypes as follows: + + png_voidp malloc_fn(png_structp png_ptr, + png_alloc_size_t size); + + void free_fn(png_structp png_ptr, png_voidp ptr); + +Your malloc_fn() must return NULL in case of failure. The png_malloc() +function will normally call png_error() if it receives a NULL from the +system memory allocator or from your replacement malloc_fn(). + +Your free_fn() will never be called with a NULL ptr, since libpng's +png_free() checks for NULL before calling free_fn(). + +Input/Output in libpng is done through png_read() and png_write(), +which currently just call fread() and fwrite(). The FILE * is stored in +png_struct and is initialized via png_init_io(). If you wish to change +the method of I/O, the library supplies callbacks that you can set +through the function png_set_read_fn() and png_set_write_fn() at run +time, instead of calling the png_init_io() function. These functions +also provide a void pointer that can be retrieved via the function +png_get_io_ptr(). For example: + + png_set_read_fn(png_structp read_ptr, + voidp read_io_ptr, png_rw_ptr read_data_fn) + + png_set_write_fn(png_structp write_ptr, + voidp write_io_ptr, png_rw_ptr write_data_fn, + png_flush_ptr output_flush_fn); + + voidp read_io_ptr = png_get_io_ptr(read_ptr); + voidp write_io_ptr = png_get_io_ptr(write_ptr); + +The replacement I/O functions must have prototypes as follows: + + void user_read_data(png_structp png_ptr, + png_bytep data, png_size_t length); + + void user_write_data(png_structp png_ptr, + png_bytep data, png_size_t length); + + void user_flush_data(png_structp png_ptr); + +The user_read_data() function is responsible for detecting and +handling end-of-data errors. + +Supplying NULL for the read, write, or flush functions sets them back +to using the default C stream functions, which expect the io_ptr to +point to a standard *FILE structure. It is probably a mistake +to use NULL for one of write_data_fn and output_flush_fn but not both +of them, unless you have built libpng with PNG_NO_WRITE_FLUSH defined. +It is an error to read from a write stream, and vice versa. + +Error handling in libpng is done through png_error() and png_warning(). +Errors handled through png_error() are fatal, meaning that png_error() +should never return to its caller. Currently, this is handled via +setjmp() and longjmp() (unless you have compiled libpng with +PNG_NO_SETJMP, in which case it is handled via PNG_ABORT()), +but you could change this to do things like exit() if you should wish, +as long as your function does not return. + +On non-fatal errors, png_warning() is called +to print a warning message, and then control returns to the calling code. +By default png_error() and png_warning() print a message on stderr via +fprintf() unless the library is compiled with PNG_NO_CONSOLE_IO defined +(because you don't want the messages) or PNG_NO_STDIO defined (because +fprintf() isn't available). If you wish to change the behavior of the error +functions, you will need to set up your own message callbacks. These +functions are normally supplied at the time that the png_struct is created. +It is also possible to redirect errors and warnings to your own replacement +functions after png_create_*_struct() has been called by calling: + + png_set_error_fn(png_structp png_ptr, + png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warning_fn); + + png_voidp error_ptr = png_get_error_ptr(png_ptr); + +If NULL is supplied for either error_fn or warning_fn, then the libpng +default function will be used, calling fprintf() and/or longjmp() if a +problem is encountered. The replacement error functions should have +parameters as follows: + + void user_error_fn(png_structp png_ptr, + png_const_charp error_msg); + + void user_warning_fn(png_structp png_ptr, + png_const_charp warning_msg); + +The motivation behind using setjmp() and longjmp() is the C++ throw and +catch exception handling methods. This makes the code much easier to write, +as there is no need to check every return code of every function call. +However, there are some uncertainties about the status of local variables +after a longjmp, so the user may want to be careful about doing anything +after setjmp returns non-zero besides returning itself. Consult your +compiler documentation for more details. For an alternative approach, you +may wish to use the "cexcept" facility (see http://cexcept.sourceforge.net), +which is illustrated in pngvalid.c and in contrib/visupng. + +Beginning in libpng-1.4.0, the png_set_benign_errors() API became available. +You can use this to handle certain errors (normally handled as errors) +as warnings. + + png_set_benign_errors (png_ptr, int allowed); + + allowed: 0: treat png_benign_error() as an error. + 1: treat png_benign_error() as a warning. + +As of libpng-1.6.0, the default condition is to treat benign errors as +warnings while reading and as errors while writing. + +Custom chunks + +If you need to read or write custom chunks, you may need to get deeper +into the libpng code. The library now has mechanisms for storing +and writing chunks of unknown type; you can even declare callbacks +for custom chunks. However, this may not be good enough if the +library code itself needs to know about interactions between your +chunk and existing `intrinsic' chunks. + +If you need to write a new intrinsic chunk, first read the PNG +specification. Acquire a first level of understanding of how it works. +Pay particular attention to the sections that describe chunk names, +and look at how other chunks were designed, so you can do things +similarly. Second, check out the sections of libpng that read and +write chunks. Try to find a chunk that is similar to yours and use +it as a template. More details can be found in the comments inside +the code. It is best to handle private or unknown chunks in a generic method, +via callback functions, instead of by modifying libpng functions. This +is illustrated in pngtest.c, which uses a callback function to handle a +private "vpAg" chunk and the new "sTER" chunk, which are both unknown to +libpng. + +If you wish to write your own transformation for the data, look through +the part of the code that does the transformations, and check out some of +the simpler ones to get an idea of how they work. Try to find a similar +transformation to the one you want to add and copy off of it. More details +can be found in the comments inside the code itself. + +Configuring for gui/windowing platforms: + +You will need to write new error and warning functions that use the GUI +interface, as described previously, and set them to be the error and +warning functions at the time that png_create_*_struct() is called, +in order to have them available during the structure initialization. +They can be changed later via png_set_error_fn(). On some compilers, +you may also have to change the memory allocators (png_malloc, etc.). + +Configuring zlib: + +There are special functions to configure the compression. Perhaps the +most useful one changes the compression level, which currently uses +input compression values in the range 0 - 9. The library normally +uses the default compression level (Z_DEFAULT_COMPRESSION = 6). Tests +have shown that for a large majority of images, compression values in +the range 3-6 compress nearly as well as higher levels, and do so much +faster. For online applications it may be desirable to have maximum speed +(Z_BEST_SPEED = 1). With versions of zlib after v0.99, you can also +specify no compression (Z_NO_COMPRESSION = 0), but this would create +files larger than just storing the raw bitmap. You can specify the +compression level by calling: + + #include zlib.h + png_set_compression_level(png_ptr, level); + +Another useful one is to reduce the memory level used by the library. +The memory level defaults to 8, but it can be lowered if you are +short on memory (running DOS, for example, where you only have 640K). +Note that the memory level does have an effect on compression; among +other things, lower levels will result in sections of incompressible +data being emitted in smaller stored blocks, with a correspondingly +larger relative overhead of up to 15% in the worst case. + + #include zlib.h + png_set_compression_mem_level(png_ptr, level); + +The other functions are for configuring zlib. They are not recommended +for normal use and may result in writing an invalid PNG file. See +zlib.h for more information on what these mean. + + #include zlib.h + png_set_compression_strategy(png_ptr, + strategy); + + png_set_compression_window_bits(png_ptr, + window_bits); + + png_set_compression_method(png_ptr, method); + +This controls the size of the IDAT chunks (default 8192): + + png_set_compression_buffer_size(png_ptr, size); + +As of libpng version 1.5.4, additional APIs became +available to set these separately for non-IDAT +compressed chunks such as zTXt, iTXt, and iCCP: + + #include zlib.h + #if PNG_LIBPNG_VER >= 10504 + png_set_text_compression_level(png_ptr, level); + + png_set_text_compression_mem_level(png_ptr, level); + + png_set_text_compression_strategy(png_ptr, + strategy); + + png_set_text_compression_window_bits(png_ptr, + window_bits); + + png_set_text_compression_method(png_ptr, method); + #endif + +Controlling row filtering + +If you want to control whether libpng uses filtering or not, which +filters are used, and how it goes about picking row filters, you +can call one of these functions. The selection and configuration +of row filters can have a significant impact on the size and +encoding speed and a somewhat lesser impact on the decoding speed +of an image. Filtering is enabled by default for RGB and grayscale +images (with and without alpha), but not for paletted images nor +for any images with bit depths less than 8 bits/pixel. + +The 'method' parameter sets the main filtering method, which is +currently only '0' in the PNG 1.2 specification. The 'filters' +parameter sets which filter(s), if any, should be used for each +scanline. Possible values are PNG_ALL_FILTERS, PNG_NO_FILTERS, +or PNG_FAST_FILTERS to turn filtering on and off, or to turn on +just the fast-decoding subset of filters, respectively. + +Individual filter types are PNG_FILTER_NONE, PNG_FILTER_SUB, +PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH, which can be bitwise +ORed together with '|' to specify one or more filters to use. +These filters are described in more detail in the PNG specification. +If you intend to change the filter type during the course of writing +the image, you should start with flags set for all of the filters +you intend to use so that libpng can initialize its internal +structures appropriately for all of the filter types. (Note that this +means the first row must always be adaptively filtered, because libpng +currently does not allocate the filter buffers until png_write_row() +is called for the first time.) + + filters = PNG_NO_FILTERS; + filters = PNG_ALL_FILTERS; + filters = PNG_FAST_FILTERS; + + or + + filters = PNG_FILTER_NONE | PNG_FILTER_SUB | + PNG_FILTER_UP | PNG_FILTER_AVG | + PNG_FILTER_PAETH; + + png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, + filters); + + The second parameter can also be + PNG_INTRAPIXEL_DIFFERENCING if you are + writing a PNG to be embedded in a MNG + datastream. This parameter must be the + same as the value of filter_method used + in png_set_IHDR(). + +Requesting debug printout + +The macro definition PNG_DEBUG can be used to request debugging +printout. Set it to an integer value in the range 0 to 3. Higher +numbers result in increasing amounts of debugging information. The +information is printed to the "stderr" file, unless another file +name is specified in the PNG_DEBUG_FILE macro definition. + +When PNG_DEBUG > 0, the following functions (macros) become available: + + png_debug(level, message) + png_debug1(level, message, p1) + png_debug2(level, message, p1, p2) + +in which "level" is compared to PNG_DEBUG to decide whether to print +the message, "message" is the formatted string to be printed, +and p1 and p2 are parameters that are to be embedded in the string +according to printf-style formatting directives. For example, + + png_debug1(2, "foo=%d", foo); + +is expanded to + + if (PNG_DEBUG > 2) + fprintf(PNG_DEBUG_FILE, "foo=%d\n", foo); + +When PNG_DEBUG is defined but is zero, the macros aren't defined, but you +can still use PNG_DEBUG to control your own debugging: + + #ifdef PNG_DEBUG + fprintf(stderr, ... + #endif + +When PNG_DEBUG = 1, the macros are defined, but only png_debug statements +having level = 0 will be printed. There aren't any such statements in +this version of libpng, but if you insert some they will be printed. + +VII. MNG support + +The MNG specification (available at http://www.libpng.org/pub/mng) allows +certain extensions to PNG for PNG images that are embedded in MNG datastreams. +Libpng can support some of these extensions. To enable them, use the +png_permit_mng_features() function: + + feature_set = png_permit_mng_features(png_ptr, mask) + + mask is a png_uint_32 containing the bitwise OR of the + features you want to enable. These include + PNG_FLAG_MNG_EMPTY_PLTE + PNG_FLAG_MNG_FILTER_64 + PNG_ALL_MNG_FEATURES + + feature_set is a png_uint_32 that is the bitwise AND of + your mask with the set of MNG features that is + supported by the version of libpng that you are using. + +It is an error to use this function when reading or writing a standalone +PNG file with the PNG 8-byte signature. The PNG datastream must be wrapped +in a MNG datastream. As a minimum, it must have the MNG 8-byte signature +and the MHDR and MEND chunks. Libpng does not provide support for these +or any other MNG chunks; your application must provide its own support for +them. You may wish to consider using libmng (available at +http://www.libmng.com) instead. + +VIII. Changes to Libpng from version 0.88 + +It should be noted that versions of libpng later than 0.96 are not +distributed by the original libpng author, Guy Schalnat, nor by +Andreas Dilger, who had taken over from Guy during 1996 and 1997, and +distributed versions 0.89 through 0.96, but rather by another member +of the original PNG Group, Glenn Randers-Pehrson. Guy and Andreas are +still alive and well, but they have moved on to other things. + +The old libpng functions png_read_init(), png_write_init(), +png_info_init(), png_read_destroy(), and png_write_destroy() have been +moved to PNG_INTERNAL in version 0.95 to discourage their use. These +functions will be removed from libpng version 1.4.0. + +The preferred method of creating and initializing the libpng structures is +via the png_create_read_struct(), png_create_write_struct(), and +png_create_info_struct() because they isolate the size of the structures +from the application, allow version error checking, and also allow the +use of custom error handling routines during the initialization, which +the old functions do not. The functions png_read_destroy() and +png_write_destroy() do not actually free the memory that libpng +allocated for these structs, but just reset the data structures, so they +can be used instead of png_destroy_read_struct() and +png_destroy_write_struct() if you feel there is too much system overhead +allocating and freeing the png_struct for each image read. + +Setting the error callbacks via png_set_message_fn() before +png_read_init() as was suggested in libpng-0.88 is no longer supported +because this caused applications that do not use custom error functions +to fail if the png_ptr was not initialized to zero. It is still possible +to set the error callbacks AFTER png_read_init(), or to change them with +png_set_error_fn(), which is essentially the same function, but with a new +name to force compilation errors with applications that try to use the old +method. + +Support for the sCAL, iCCP, iTXt, and sPLT chunks was added at libpng-1.0.6; +however, iTXt support was not enabled by default. + +Starting with version 1.0.7, you can find out which version of the library +you are using at run-time: + + png_uint_32 libpng_vn = png_access_version_number(); + +The number libpng_vn is constructed from the major version, minor +version with leading zero, and release number with leading zero, +(e.g., libpng_vn for version 1.0.7 is 10007). + +Note that this function does not take a png_ptr, so you can call it +before you've created one. + +You can also check which version of png.h you used when compiling your +application: + + png_uint_32 application_vn = PNG_LIBPNG_VER; + +IX. Changes to Libpng from version 1.0.x to 1.2.x + +Support for user memory management was enabled by default. To +accomplish this, the functions png_create_read_struct_2(), +png_create_write_struct_2(), png_set_mem_fn(), png_get_mem_ptr(), +png_malloc_default(), and png_free_default() were added. + +Support for the iTXt chunk has been enabled by default as of +version 1.2.41. + +Support for certain MNG features was enabled. + +Support for numbered error messages was added. However, we never got +around to actually numbering the error messages. The function +png_set_strip_error_numbers() was added (Note: the prototype for this +function was inadvertently removed from png.h in PNG_NO_ASSEMBLER_CODE +builds of libpng-1.2.15. It was restored in libpng-1.2.36). + +The png_malloc_warn() function was added at libpng-1.2.3. This issues +a png_warning and returns NULL instead of aborting when it fails to +acquire the requested memory allocation. + +Support for setting user limits on image width and height was enabled +by default. The functions png_set_user_limits(), png_get_user_width_max(), +and png_get_user_height_max() were added at libpng-1.2.6. + +The png_set_add_alpha() function was added at libpng-1.2.7. + +The function png_set_expand_gray_1_2_4_to_8() was added at libpng-1.2.9. +Unlike png_set_gray_1_2_4_to_8(), the new function does not expand the +tRNS chunk to alpha. The png_set_gray_1_2_4_to_8() function is +deprecated. + +A number of macro definitions in support of runtime selection of +assembler code features (especially Intel MMX code support) were +added at libpng-1.2.0: + + PNG_ASM_FLAG_MMX_SUPPORT_COMPILED + PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU + PNG_ASM_FLAG_MMX_READ_COMBINE_ROW + PNG_ASM_FLAG_MMX_READ_INTERLACE + PNG_ASM_FLAG_MMX_READ_FILTER_SUB + PNG_ASM_FLAG_MMX_READ_FILTER_UP + PNG_ASM_FLAG_MMX_READ_FILTER_AVG + PNG_ASM_FLAG_MMX_READ_FILTER_PAETH + PNG_ASM_FLAGS_INITIALIZED + PNG_MMX_READ_FLAGS + PNG_MMX_FLAGS + PNG_MMX_WRITE_FLAGS + PNG_MMX_FLAGS + +We added the following functions in support of runtime +selection of assembler code features: + + png_get_mmx_flagmask() + png_set_mmx_thresholds() + png_get_asm_flags() + png_get_mmx_bitdepth_threshold() + png_get_mmx_rowbytes_threshold() + png_set_asm_flags() + +We replaced all of these functions with simple stubs in libpng-1.2.20, +when the Intel assembler code was removed due to a licensing issue. + +These macros are deprecated: + + PNG_READ_TRANSFORMS_NOT_SUPPORTED + PNG_PROGRESSIVE_READ_NOT_SUPPORTED + PNG_NO_SEQUENTIAL_READ_SUPPORTED + PNG_WRITE_TRANSFORMS_NOT_SUPPORTED + PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED + PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED + +They have been replaced, respectively, by: + + PNG_NO_READ_TRANSFORMS + PNG_NO_PROGRESSIVE_READ + PNG_NO_SEQUENTIAL_READ + PNG_NO_WRITE_TRANSFORMS + PNG_NO_READ_ANCILLARY_CHUNKS + PNG_NO_WRITE_ANCILLARY_CHUNKS + +PNG_MAX_UINT was replaced with PNG_UINT_31_MAX. It has been +deprecated since libpng-1.0.16 and libpng-1.2.6. + +The function + png_check_sig(sig, num) +was replaced with + !png_sig_cmp(sig, 0, num) +It has been deprecated since libpng-0.90. + +The function + png_set_gray_1_2_4_to_8() +which also expands tRNS to alpha was replaced with + png_set_expand_gray_1_2_4_to_8() +which does not. It has been deprecated since libpng-1.0.18 and 1.2.9. + +X. Changes to Libpng from version 1.0.x/1.2.x to 1.4.x + +Private libpng prototypes and macro definitions were moved from +png.h and pngconf.h into a new pngpriv.h header file. + +Functions png_set_benign_errors(), png_benign_error(), and +png_chunk_benign_error() were added. + +Support for setting the maximum amount of memory that the application +will allocate for reading chunks was added, as a security measure. +The functions png_set_chunk_cache_max() and png_get_chunk_cache_max() +were added to the library. + +We implemented support for I/O states by adding png_ptr member io_state +and functions png_get_io_chunk_name() and png_get_io_state() in pngget.c + +We added PNG_TRANSFORM_GRAY_TO_RGB to the available high-level +input transforms. + +Checking for and reporting of errors in the IHDR chunk is more thorough. + +Support for global arrays was removed, to improve thread safety. + +Some obsolete/deprecated macros and functions have been removed. + +Typecasted NULL definitions such as + #define png_voidp_NULL (png_voidp)NULL +were eliminated. If you used these in your application, just use +NULL instead. + +The png_struct and info_struct members "trans" and "trans_values" were +changed to "trans_alpha" and "trans_color", respectively. + +The obsolete, unused pnggccrd.c and pngvcrd.c files and related makefiles +were removed. + +The PNG_1_0_X and PNG_1_2_X macros were eliminated. + +The PNG_LEGACY_SUPPORTED macro was eliminated. + +Many WIN32_WCE #ifdefs were removed. + +The functions png_read_init(info_ptr), png_write_init(info_ptr), +png_info_init(info_ptr), png_read_destroy(), and png_write_destroy() +have been removed. They have been deprecated since libpng-0.95. + +The png_permit_empty_plte() was removed. It has been deprecated +since libpng-1.0.9. Use png_permit_mng_features() instead. + +We removed the obsolete stub functions png_get_mmx_flagmask(), +png_set_mmx_thresholds(), png_get_asm_flags(), +png_get_mmx_bitdepth_threshold(), png_get_mmx_rowbytes_threshold(), +png_set_asm_flags(), and png_mmx_supported() + +We removed the obsolete png_check_sig(), png_memcpy_check(), and +png_memset_check() functions. Instead use !png_sig_cmp(), memcpy(), +and memset(), respectively. + +The function png_set_gray_1_2_4_to_8() was removed. It has been +deprecated since libpng-1.0.18 and 1.2.9, when it was replaced with +png_set_expand_gray_1_2_4_to_8() because the former function also +expanded any tRNS chunk to an alpha channel. + +Macros for png_get_uint_16, png_get_uint_32, and png_get_int_32 +were added and are used by default instead of the corresponding +functions. Unfortunately, +from libpng-1.4.0 until 1.4.4, the png_get_uint_16 macro (but not the +function) incorrectly returned a value of type png_uint_32. + +We changed the prototype for png_malloc() from + png_malloc(png_structp png_ptr, png_uint_32 size) +to + png_malloc(png_structp png_ptr, png_alloc_size_t size) + +This also applies to the prototype for the user replacement malloc_fn(). + +The png_calloc() function was added and is used in place of +of "png_malloc(); memset();" except in the case in png_read_png() +where the array consists of pointers; in this case a "for" loop is used +after the png_malloc() to set the pointers to NULL, to give robust. +behavior in case the application runs out of memory part-way through +the process. + +We changed the prototypes of png_get_compression_buffer_size() and +png_set_compression_buffer_size() to work with png_size_t instead of +png_uint_32. + +Support for numbered error messages was removed by default, since we +never got around to actually numbering the error messages. The function +png_set_strip_error_numbers() was removed from the library by default. + +The png_zalloc() and png_zfree() functions are no longer exported. +The png_zalloc() function no longer zeroes out the memory that it +allocates. Applications that called png_zalloc(png_ptr, number, size) +can call png_calloc(png_ptr, number*size) instead, and can call +png_free() instead of png_zfree(). + +Support for dithering was disabled by default in libpng-1.4.0, because +it has not been well tested and doesn't actually "dither". +The code was not +removed, however, and could be enabled by building libpng with +PNG_READ_DITHER_SUPPORTED defined. In libpng-1.4.2, this support +was re-enabled, but the function was renamed png_set_quantize() to +reflect more accurately what it actually does. At the same time, +the PNG_DITHER_[RED,GREEN_BLUE]_BITS macros were also renamed to +PNG_QUANTIZE_[RED,GREEN,BLUE]_BITS, and PNG_READ_DITHER_SUPPORTED +was renamed to PNG_READ_QUANTIZE_SUPPORTED. + +We removed the trailing '.' from the warning and error messages. + +XI. Changes to Libpng from version 1.4.x to 1.5.x + +From libpng-1.4.0 until 1.4.4, the png_get_uint_16 macro (but not the +function) incorrectly returned a value of type png_uint_32. +The incorrect macro was removed from libpng-1.4.5. + +Checking for invalid palette index on write was added at libpng +1.5.10. If a pixel contains an invalid (out-of-range) index libpng issues +a benign error. This is enabled by default because this condition is an +error according to the PNG specification, Clause 11.3.2, but the error can +be ignored in each png_ptr with + + png_set_check_for_invalid_index(png_ptr, allowed); + + allowed - one of + 0: disable benign error (accept the + invalid data without warning). + 1: enable benign error (treat the + invalid data as an error or a + warning). + +If the error is ignored, or if png_benign_error() treats it as a warning, +any invalid pixels are decoded as opaque black by the decoder and written +as-is by the encoder. + +Retrieving the maximum palette index found was added at libpng-1.5.15. +This statement must appear after png_read_png() or png_read_image() while +reading, and after png_write_png() or png_write_image() while writing. + + int max_palette = png_get_palette_max(png_ptr, info_ptr); + +This will return the maximum palette index found in the image, or "-1" if +the palette was not checked, or "0" if no palette was found. Note that this +does not account for any palette index used by ancillary chunks such as the +bKGD chunk; you must check those separately to determine the maximum +palette index actually used. + +There are no substantial API changes between the non-deprecated parts of +the 1.4.5 API and the 1.5.0 API; however, the ability to directly access +members of the main libpng control structures, png_struct and png_info, +deprecated in earlier versions of libpng, has been completely removed from +libpng 1.5, and new private "pngstruct.h", "pnginfo.h", and "pngdebug.h" +header files were created. + +We no longer include zlib.h in png.h. The include statement has been moved +to pngstruct.h, where it is not accessible by applications. Applications that +need access to information in zlib.h will need to add the '#include "zlib.h"' +directive. It does not matter whether this is placed prior to or after +the '"#include png.h"' directive. + +The png_sprintf(), png_strcpy(), and png_strncpy() macros are no longer used +and were removed. + +We moved the png_strlen(), png_memcpy(), png_memset(), and png_memcmp() +macros into a private header file (pngpriv.h) that is not accessible to +applications. + +In png_get_iCCP, the type of "profile" was changed from png_charpp +to png_bytepp, and in png_set_iCCP, from png_charp to png_const_bytep. + +There are changes of form in png.h, including new and changed macros to +declare parts of the API. Some API functions with arguments that are +pointers to data not modified within the function have been corrected to +declare these arguments with PNG_CONST. + +Much of the internal use of C macros to control the library build has also +changed and some of this is visible in the exported header files, in +particular the use of macros to control data and API elements visible +during application compilation may require significant revision to +application code. (It is extremely rare for an application to do this.) + +Any program that compiled against libpng 1.4 and did not use deprecated +features or access internal library structures should compile and work +against libpng 1.5, except for the change in the prototype for +png_get_iCCP() and png_set_iCCP() API functions mentioned above. + +libpng 1.5.0 adds PNG_ PASS macros to help in the reading and writing of +interlaced images. The macros return the number of rows and columns in +each pass and information that can be used to de-interlace and (if +absolutely necessary) interlace an image. + +libpng 1.5.0 adds an API png_longjmp(png_ptr, value). This API calls +the application-provided png_longjmp_ptr on the internal, but application +initialized, longjmp buffer. It is provided as a convenience to avoid +the need to use the png_jmpbuf macro, which had the unnecessary side +effect of resetting the internal png_longjmp_ptr value. + +libpng 1.5.0 includes a complete fixed point API. By default this is +present along with the corresponding floating point API. In general the +fixed point API is faster and smaller than the floating point one because +the PNG file format used fixed point, not floating point. This applies +even if the library uses floating point in internal calculations. A new +macro, PNG_FLOATING_ARITHMETIC_SUPPORTED, reveals whether the library +uses floating point arithmetic (the default) or fixed point arithmetic +internally for performance critical calculations such as gamma correction. +In some cases, the gamma calculations may produce slightly different +results. This has changed the results in png_rgb_to_gray and in alpha +composition (png_set_background for example). This applies even if the +original image was already linear (gamma == 1.0) and, therefore, it is +not necessary to linearize the image. This is because libpng has *not* +been changed to optimize that case correctly, yet. + +Fixed point support for the sCAL chunk comes with an important caveat; +the sCAL specification uses a decimal encoding of floating point values +and the accuracy of PNG fixed point values is insufficient for +representation of these values. Consequently a "string" API +(png_get_sCAL_s and png_set_sCAL_s) is the only reliable way of reading +arbitrary sCAL chunks in the absence of either the floating point API or +internal floating point calculations. Starting with libpng-1.5.0, both +of these functions are present when PNG_sCAL_SUPPORTED is defined. Prior +to libpng-1.5.0, their presence also depended upon PNG_FIXED_POINT_SUPPORTED +being defined and PNG_FLOATING_POINT_SUPPORTED not being defined. + +Applications no longer need to include the optional distribution header +file pngusr.h or define the corresponding macros during application +build in order to see the correct variant of the libpng API. From 1.5.0 +application code can check for the corresponding _SUPPORTED macro: + +#ifdef PNG_INCH_CONVERSIONS_SUPPORTED + /* code that uses the inch conversion APIs. */ +#endif + +This macro will only be defined if the inch conversion functions have been +compiled into libpng. The full set of macros, and whether or not support +has been compiled in, are available in the header file pnglibconf.h. +This header file is specific to the libpng build. Notice that prior to +1.5.0 the _SUPPORTED macros would always have the default definition unless +reset by pngusr.h or by explicit settings on the compiler command line. +These settings may produce compiler warnings or errors in 1.5.0 because +of macro redefinition. + +Applications can now choose whether to use these macros or to call the +corresponding function by defining PNG_USE_READ_MACROS or +PNG_NO_USE_READ_MACROS before including png.h. Notice that this is +only supported from 1.5.0; defining PNG_NO_USE_READ_MACROS prior to 1.5.0 +will lead to a link failure. + +Prior to libpng-1.5.4, the zlib compressor used the same set of parameters +when compressing the IDAT data and textual data such as zTXt and iCCP. +In libpng-1.5.4 we reinitialized the zlib stream for each type of data. +We added five png_set_text_*() functions for setting the parameters to +use with textual data. + +Prior to libpng-1.5.4, the PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +option was off by default, and slightly inaccurate scaling occurred. +This option can no longer be turned off, and the choice of accurate +or inaccurate 16-to-8 scaling is by using the new png_set_scale_16_to_8() +API for accurate scaling or the old png_set_strip_16_to_8() API for simple +chopping. In libpng-1.5.4, the PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +macro became PNG_READ_SCALE_16_TO_8_SUPPORTED, and the PNG_READ_16_TO_8 +macro became PNG_READ_STRIP_16_TO_8_SUPPORTED, to enable the two +png_set_*_16_to_8() functions separately. + +Prior to libpng-1.5.4, the png_set_user_limits() function could only be +used to reduce the width and height limits from the value of +PNG_USER_WIDTH_MAX and PNG_USER_HEIGHT_MAX, although this document said +that it could be used to override them. Now this function will reduce or +increase the limits. + +Starting in libpng-1.5.10, the user limits can be set en masse with the +configuration option PNG_SAFE_LIMITS_SUPPORTED. If this option is enabled, +a set of "safe" limits is applied in pngpriv.h. These can be overridden by +application calls to png_set_user_limits(), png_set_user_chunk_cache_max(), +and/or png_set_user_malloc_max() that increase or decrease the limits. Also, +in libpng-1.5.10 the default width and height limits were increased +from 1,000,000 to 0x7fffffff (i.e., made unlimited). Therefore, the +limits are now + default safe + png_user_width_max 0x7fffffff 1,000,000 + png_user_height_max 0x7fffffff 1,000,000 + png_user_chunk_cache_max 0 (unlimited) 128 + png_user_chunk_malloc_max 0 (unlimited) 8,000,000 + +The png_set_option() function (and the "options" member of the png struct) was +added to libpng-1.5.15, with option PNG_ARM_NEON. + +The library now supports a complete fixed point implementation and can +thus be used on systems that have no floating point support or very +limited or slow support. Previously gamma correction, an essential part +of complete PNG support, required reasonably fast floating point. + +As part of this the choice of internal implementation has been made +independent of the choice of fixed versus floating point APIs and all the +missing fixed point APIs have been implemented. + +The exact mechanism used to control attributes of API functions has +changed, as described in the INSTALL file. + +A new test program, pngvalid, is provided in addition to pngtest. +pngvalid validates the arithmetic accuracy of the gamma correction +calculations and includes a number of validations of the file format. +A subset of the full range of tests is run when "make check" is done +(in the 'configure' build.) pngvalid also allows total allocated memory +usage to be evaluated and performs additional memory overwrite validation. + +Many changes to individual feature macros have been made. The following +are the changes most likely to be noticed by library builders who +configure libpng: + +1) All feature macros now have consistent naming: + +#define PNG_NO_feature turns the feature off +#define PNG_feature_SUPPORTED turns the feature on + +pnglibconf.h contains one line for each feature macro which is either: + +#define PNG_feature_SUPPORTED + +if the feature is supported or: + +/*#undef PNG_feature_SUPPORTED*/ + +if it is not. Library code consistently checks for the 'SUPPORTED' macro. +It does not, and libpng applications should not, check for the 'NO' macro +which will not normally be defined even if the feature is not supported. +The 'NO' macros are only used internally for setting or not setting the +corresponding 'SUPPORTED' macros. + +Compatibility with the old names is provided as follows: + +PNG_INCH_CONVERSIONS turns on PNG_INCH_CONVERSIONS_SUPPORTED + +And the following definitions disable the corresponding feature: + +PNG_SETJMP_NOT_SUPPORTED disables SETJMP +PNG_READ_TRANSFORMS_NOT_SUPPORTED disables READ_TRANSFORMS +PNG_NO_READ_COMPOSITED_NODIV disables READ_COMPOSITE_NODIV +PNG_WRITE_TRANSFORMS_NOT_SUPPORTED disables WRITE_TRANSFORMS +PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED disables READ_ANCILLARY_CHUNKS +PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED disables WRITE_ANCILLARY_CHUNKS + +Library builders should remove use of the above, inconsistent, names. + +2) Warning and error message formatting was previously conditional on +the STDIO feature. The library has been changed to use the +CONSOLE_IO feature instead. This means that if CONSOLE_IO is disabled +the library no longer uses the printf(3) functions, even though the +default read/write implementations use (FILE) style stdio.h functions. + +3) Three feature macros now control the fixed/floating point decisions: + +PNG_FLOATING_POINT_SUPPORTED enables the floating point APIs + +PNG_FIXED_POINT_SUPPORTED enables the fixed point APIs; however, in +practice these are normally required internally anyway (because the PNG +file format is fixed point), therefore in most cases PNG_NO_FIXED_POINT +merely stops the function from being exported. + +PNG_FLOATING_ARITHMETIC_SUPPORTED chooses between the internal floating +point implementation or the fixed point one. Typically the fixed point +implementation is larger and slower than the floating point implementation +on a system that supports floating point; however, it may be faster on a +system which lacks floating point hardware and therefore uses a software +emulation. + +4) Added PNG_{READ,WRITE}_INT_FUNCTIONS_SUPPORTED. This allows the +functions to read and write ints to be disabled independently of +PNG_USE_READ_MACROS, which allows libpng to be built with the functions +even though the default is to use the macros - this allows applications +to choose at app buildtime whether or not to use macros (previously +impossible because the functions weren't in the default build.) + +XII. Changes to Libpng from version 1.5.x to 1.6.x + +A "simplified API" has been added (see documentation in png.h and a simple +example in contrib/examples/pngtopng.c). The new publicly visible API +includes the following: + + macros: + PNG_FORMAT_* + PNG_IMAGE_* + structures: + png_control + png_image + read functions + png_image_begin_read_from_file() + png_image_begin_read_from_stdio() + png_image_begin_read_from_memory() + png_image_finish_read() + png_image_free() + write functions + png_image_write_to_file() + png_image_write_to_memory() + png_image_write_to_stdio() + +Starting with libpng-1.6.0, you can configure libpng to prefix all exported +symbols, using the PNG_PREFIX macro. + +We no longer include string.h in png.h. The include statement has been moved +to pngpriv.h, where it is not accessible by applications. Applications that +need access to information in string.h must add an '#include ' +directive. It does not matter whether this is placed prior to or after +the '#include "png.h"' directive. + +The following API are now DEPRECATED: + png_info_init_3() + png_convert_to_rfc1123() which has been replaced + with png_convert_to_rfc1123_buffer() + png_malloc_default() + png_free_default() + png_reset_zstream() + +The following have been removed: + png_get_io_chunk_name(), which has been replaced + with png_get_io_chunk_type(). The new + function returns a 32-bit integer instead of + a string. + The png_sizeof(), png_strlen(), png_memcpy(), png_memcmp(), and + png_memset() macros are no longer used in the libpng sources and + have been removed. These had already been made invisible to applications + (i.e., defined in the private pngpriv.h header file) since libpng-1.5.0. + +The signatures of many exported functions were changed, such that + png_structp became png_structrp or png_const_structrp + png_infop became png_inforp or png_const_inforp +where "rp" indicates a "restricted pointer". + +Dropped support for 16-bit platforms. The support for FAR/far types has +been eliminated and the definition of png_alloc_size_t is now controlled +by a flag so that 'small size_t' systems can select it if necessary. + +Error detection in some chunks has improved; in particular the iCCP chunk +reader now does pretty complete validation of the basic format. Some bad +profiles that were previously accepted are now accepted with a warning or +rejected, depending upon the png_set_benign_errors() setting, in particular +the very old broken Microsoft/HP 3144-byte sRGB profile. Starting with +libpng-1.6.11, recognizing and checking sRGB profiles can be avoided by +means of + + #if defined(PNG_SKIP_sRGB_CHECK_PROFILE) && \ + defined(PNG_SET_OPTION_SUPPORTED) + png_set_option(png_ptr, PNG_SKIP_sRGB_CHECK_PROFILE, + PNG_OPTION_ON); + #endif + +It's not a good idea to do this if you are using the "simplified API", +which needs to be able to recognize sRGB profiles conveyed via the iCCP +chunk. + +The PNG spec requirement that only grayscale profiles may appear in images +with color type 0 or 4 and that even if the image only contains gray pixels, +only RGB profiles may appear in images with color type 2, 3, or 6, is now +enforced. The sRGB chunk is allowed to appear in images with any color type +and is interpreted by libpng to convey a one-tracer-curve gray profile or a +three-tracer-curve RGB profile as appropriate. + +Libpng 1.5.x erroneously used /MD for Debug DLL builds; if you used the debug +builds in your app and you changed your app to use /MD you will need to +change it back to /MDd for libpng 1.6.x. + +Prior to libpng-1.6.0 a warning would be issued if the iTXt chunk contained +an empty language field or an empty translated keyword. Both of these +are allowed by the PNG specification, so these warnings are no longer issued. + +The library now issues an error if the application attempts to set a +transform after it calls png_read_update_info() or if it attempts to call +both png_read_update_info() and png_start_read_image() or to call either +of them more than once. + +The default condition for benign_errors is now to treat benign errors as +warnings while reading and as errors while writing. + +The library now issues a warning if both background processing and RGB to +gray are used when gamma correction happens. As with previous versions of +the library the results are numerically very incorrect in this case. + +There are some minor arithmetic changes in some transforms such as +png_set_background(), that might be detected by certain regression tests. + +Unknown chunk handling has been improved internally, without any API change. +This adds more correct option control of the unknown handling, corrects +a pre-existing bug where the per-chunk 'keep' setting is ignored, and makes +it possible to skip IDAT chunks in the sequential reader. + +The machine-generated configure files are no longer included in branches +libpng16 and later of the GIT repository. They continue to be included +in the tarball releases, however. + +Libpng-1.6.0 through 1.6.2 used the CMF bytes at the beginning of the IDAT +stream to set the size of the sliding window for reading instead of using the +default 32-kbyte sliding window size. It was discovered that there are +hundreds of PNG files in the wild that have incorrect CMF bytes that caused +zlib to issue the "invalid distance too far back" error and reject the file. +Libpng-1.6.3 and later calculate their own safe CMF from the image dimensions, +provide a way to revert to the libpng-1.5.x behavior (ignoring the CMF bytes +and using a 32-kbyte sliding window), by using + + png_set_option(png_ptr, PNG_MAXIMUM_INFLATE_WINDOW, + PNG_OPTION_ON); + +and provide a tool (contrib/tools/pngfix) for rewriting a PNG file while +optimizing the CMF bytes in its IDAT chunk correctly. + +Libpng-1.6.0 and libpng-1.6.1 wrote uncompressed iTXt chunks with the wrong +length, which resulted in PNG files that cannot be read beyond the bad iTXt +chunk. This error was fixed in libpng-1.6.3, and a tool (called +contrib/tools/png-fix-itxt) has been added to the libpng distribution. + +Starting with libpng-1.6.17, the PNG_SAFE_LIMITS macro was eliminated +and safe limits are used by default (users who need larger limits +can still override them at compile time or run time, as described above). + +The new limits are + default spec limit + png_user_width_max 1,000,000 2,147,483,647 + png_user_height_max 1,000,000 2,147,483,647 + png_user_chunk_cache_max 128 unlimited + png_user_chunk_malloc_max 8,000,000 unlimited + +Starting with libpng-1.6.18, a PNG_RELEASE_BUILD macro was added, which allows +library builders to control compilation for an installed system (a release build). +It can be set for testing debug or beta builds to ensure that they will compile +when the build type is switched to RC or STABLE. In essence this overrides the +PNG_LIBPNG_BUILD_BASE_TYPE definition which is not directly user controllable. + +Starting with libpng-1.6.19, attempting to set an over-length PLTE chunk +is an error. Previously this requirement of the PNG specification was not +enforced, and the palette was always limited to 256 entries. An over-length +PLTE chunk found in an input PNG is silently truncated. + +XIII. Detecting libpng + +The png_get_io_ptr() function has been present since libpng-0.88, has never +changed, and is unaffected by conditional compilation macros. It is the +best choice for use in configure scripts for detecting the presence of any +libpng version since 0.88. In an autoconf "configure.in" you could use + + AC_CHECK_LIB(png, png_get_io_ptr, ... + +XV. Source code repository + +Since about February 2009, version 1.2.34, libpng has been under "git" source +control. The git repository was built from old libpng-x.y.z.tar.gz files +going back to version 0.70. You can access the git repository (read only) +at + + git://git.code.sf.net/p/libpng/code + +or you can browse it with a web browser by selecting the "code" button at + + https://sourceforge.net/projects/libpng + +Patches can be sent to glennrp at users.sourceforge.net or to +png-mng-implement at lists.sourceforge.net or you can upload them to +the libpng bug tracker at + + http://libpng.sourceforge.net + +We also accept patches built from the tar or zip distributions, and +simple verbal discriptions of bug fixes, reported either to the +SourceForge bug tracker, to the png-mng-implement at lists.sf.net +mailing list, or directly to glennrp. + +XV. Coding style + +Our coding style is similar to the "Allman" style +(See http://en.wikipedia.org/wiki/Indent_style#Allman_style), with curly +braces on separate lines: + + if (condition) + { + action; + } + + else if (another condition) + { + another action; + } + +The braces can be omitted from simple one-line actions: + + if (condition) + return (0); + +We use 3-space indentation, except for continued statements which +are usually indented the same as the first line of the statement +plus four more spaces. + +For macro definitions we use 2-space indentation, always leaving the "#" +in the first column. + + #ifndef PNG_NO_FEATURE + # ifndef PNG_FEATURE_SUPPORTED + # define PNG_FEATURE_SUPPORTED + # endif + #endif + +Comments appear with the leading "/*" at the same indentation as +the statement that follows the comment: + + /* Single-line comment */ + statement; + + /* This is a multiple-line + * comment. + */ + statement; + +Very short comments can be placed after the end of the statement +to which they pertain: + + statement; /* comment */ + +We don't use C++ style ("//") comments. We have, however, +used them in the past in some now-abandoned MMX assembler +code. + +Functions and their curly braces are not indented, and +exported functions are marked with PNGAPI: + + /* This is a public function that is visible to + * application programmers. It does thus-and-so. + */ + void PNGAPI + png_exported_function(png_ptr, png_info, foo) + { + body; + } + +The return type and decorations are placed on a separate line +ahead of the function name, as illustrated above. + +The prototypes for all exported functions appear in png.h, +above the comment that says + + /* Maintainer: Put new public prototypes here ... */ + +We mark all non-exported functions with "/* PRIVATE */"": + + void /* PRIVATE */ + png_non_exported_function(png_ptr, png_info, foo) + { + body; + } + +The prototypes for non-exported functions (except for those in +pngtest) appear in pngpriv.h above the comment that says + + /* Maintainer: Put new private prototypes here ^ */ + +To avoid polluting the global namespace, the names of all exported +functions and variables begin with "png_", and all publicly visible C +preprocessor macros begin with "PNG". We request that applications that +use libpng *not* begin any of their own symbols with either of these strings. + +We put a space after the "sizeof" operator and we omit the +optional parentheses around its argument when the argument +is an expression, not a type name, and we always enclose the +sizeof operator, with its argument, in parentheses: + + (sizeof (png_uint_32)) + (sizeof array) + +Prior to libpng-1.6.0 we used a "png_sizeof()" macro, formatted as +though it were a function. + +Control keywords if, for, while, and switch are always followed by a space +to distinguish them from function calls, which have no trailing space. + +We put a space after each comma and after each semicolon +in "for" statements, and we put spaces before and after each +C binary operator and after "for" or "while", and before +"?". We don't put a space between a typecast and the expression +being cast, nor do we put one between a function name and the +left parenthesis that follows it: + + for (i = 2; i > 0; --i) + y[i] = a(x) + (int)b; + +We prefer #ifdef and #ifndef to #if defined() and #if !defined() +when there is only one macro being tested. We always use parentheses +with "defined". + +We express integer constants that are used as bit masks in hex format, +with an even number of lower-case hex digits, and to make them unsigned +(e.g., 0x00U, 0xffU, 0x0100U) and long if they are greater than 0x7fff +(e.g., 0xffffUL). + +We prefer to use underscores rather than camelCase in names, except +for a few type names that we inherit from zlib.h. + +We prefer "if (something != 0)" and "if (something == 0)" +over "if (something)" and if "(!something)", respectively. + +We do not use the TAB character for indentation in the C sources. + +Lines do not exceed 80 characters. + +Other rules can be inferred by inspecting the libpng source. + +XVI. Y2K Compliance in libpng + +Since the PNG Development group is an ad-hoc body, we can't make +an official declaration. + +This is your unofficial assurance that libpng from version 0.71 and +upward through 1.6.23 are Y2K compliant. It is my belief that earlier +versions were also Y2K compliant. + +Libpng only has two year fields. One is a 2-byte unsigned integer +that will hold years up to 65535. The other, which is deprecated, +holds the date in text format, and will hold years up to 9999. + +The integer is + "png_uint_16 year" in png_time_struct. + +The string is + "char time_buffer[29]" in png_struct. This is no longer used +in libpng-1.6.x and will be removed from libpng-1.7.0. + +There are seven time-related functions: + + png_convert_to_rfc_1123_buffer() in png.c + (formerly png_convert_to_rfc_1152() in error, and + also formerly png_convert_to_rfc_1123()) + png_convert_from_struct_tm() in pngwrite.c, called + in pngwrite.c + png_convert_from_time_t() in pngwrite.c + png_get_tIME() in pngget.c + png_handle_tIME() in pngrutil.c, called in pngread.c + png_set_tIME() in pngset.c + png_write_tIME() in pngwutil.c, called in pngwrite.c + +All appear to handle dates properly in a Y2K environment. The +png_convert_from_time_t() function calls gmtime() to convert from system +clock time, which returns (year - 1900), which we properly convert to +the full 4-digit year. There is a possibility that applications using +libpng are not passing 4-digit years into the png_convert_to_rfc_1123() +function, or that they are incorrectly passing only a 2-digit year +instead of "year - 1900" into the png_convert_from_struct_tm() function, +but this is not under our control. The libpng documentation has always +stated that it works with 4-digit years, and the APIs have been +documented as such. + +The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned +integer to hold the year, and can hold years as large as 65535. + +zlib, upon which libpng depends, is also Y2K compliant. It contains +no date-related code. + + + Glenn Randers-Pehrson + libpng maintainer + PNG Development Group diff --git a/source/Irrlicht/libpng/libpng.3 b/source/Irrlicht/libpng/libpng.3 new file mode 100644 index 00000000..9f5f2db2 --- /dev/null +++ b/source/Irrlicht/libpng/libpng.3 @@ -0,0 +1,6169 @@ +.TH LIBPNG 3 "June 9, 2016" +.SH NAME +libpng \- Portable Network Graphics (PNG) Reference Library 1.6.23 +.SH SYNOPSIS +\fB +#include \fP + +\fBpng_uint_32 png_access_version_number \fI(void\fP\fB);\fP + +\fBvoid png_benign_error (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fIerror\fP\fB);\fP + +\fBvoid png_build_grayscale_palette (int \fP\fIbit_depth\fP\fB, png_colorp \fIpalette\fP\fB);\fP + +\fBpng_voidp png_calloc (png_structp \fP\fIpng_ptr\fP\fB, png_alloc_size_t \fIsize\fP\fB);\fP + +\fBvoid png_chunk_benign_error (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fIerror\fP\fB);\fP + +\fBvoid png_chunk_error (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fIerror\fP\fB);\fP + +\fBvoid png_chunk_warning (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fImessage\fP\fB);\fP + +\fBvoid png_convert_from_struct_tm (png_timep \fP\fIptime\fP\fB, struct tm FAR * \fIttime\fP\fB);\fP + +\fBvoid png_convert_from_time_t (png_timep \fP\fIptime\fP\fB, time_t \fIttime\fP\fB);\fP + +\fBpng_charp png_convert_to_rfc1123 (png_structp \fP\fIpng_ptr\fP\fB, png_timep \fIptime\fP\fB);\fP + +\fBpng_infop png_create_info_struct (png_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_structp png_create_read_struct (png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fIwarn_fn\fP\fB);\fP + +\fBpng_structp png_create_read_struct_2 (png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fP\fIwarn_fn\fP\fB, png_voidp \fP\fImem_ptr\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_free_ptr \fIfree_fn\fP\fB);\fP + +\fBpng_structp png_create_write_struct (png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fIwarn_fn\fP\fB);\fP + +\fBpng_structp png_create_write_struct_2 (png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fP\fIwarn_fn\fP\fB, png_voidp \fP\fImem_ptr\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_free_ptr \fIfree_fn\fP\fB);\fP + +\fBvoid png_data_freer (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fIfreer\fP\fB, png_uint_32 \fImask)\fP\fB);\fP + +\fBvoid png_destroy_info_struct (png_structp \fP\fIpng_ptr\fP\fB, png_infopp \fIinfo_ptr_ptr\fP\fB);\fP + +\fBvoid png_destroy_read_struct (png_structpp \fP\fIpng_ptr_ptr\fP\fB, png_infopp \fP\fIinfo_ptr_ptr\fP\fB, png_infopp \fIend_info_ptr_ptr\fP\fB);\fP + +\fBvoid png_destroy_write_struct (png_structpp \fP\fIpng_ptr_ptr\fP\fB, png_infopp \fIinfo_ptr_ptr\fP\fB);\fP + +\fBvoid png_err (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_error (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fIerror\fP\fB);\fP + +\fBvoid png_free (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fIptr\fP\fB);\fP + +\fBvoid png_free_chunk_list (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_free_default (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fIptr\fP\fB);\fP + +\fBvoid png_free_data (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fInum\fP\fB);\fP + +\fBpng_byte png_get_bit_depth (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_bKGD (png_const_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_16p \fI*background\fP\fB);\fP + +\fBpng_byte png_get_channels (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_cHRM (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, double \fP\fI*white_x\fP\fB, double \fP\fI*white_y\fP\fB, double \fP\fI*red_x\fP\fB, double \fP\fI*red_y\fP\fB, double \fP\fI*green_x\fP\fB, double \fP\fI*green_y\fP\fB, double \fP\fI*blue_x\fP\fB, double \fI*blue_y\fP\fB);\fP + +\fBpng_uint_32 png_get_cHRM_fixed (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*white_x\fP\fB, png_uint_32 \fP\fI*white_y\fP\fB, png_uint_32 \fP\fI*red_x\fP\fB, png_uint_32 \fP\fI*red_y\fP\fB, png_uint_32 \fP\fI*green_x\fP\fB, png_uint_32 \fP\fI*green_y\fP\fB, png_uint_32 \fP\fI*blue_x\fP\fB, png_uint_32 \fI*blue_y\fP\fB);\fP + +\fBpng_uint_32 png_get_cHRM_XYZ (png_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, double \fP\fI*red_X\fP\fB, double \fP\fI*red_Y\fP\fB, double \fP\fI*red_Z\fP\fB, double \fP\fI*green_X\fP\fB, double \fP\fI*green_Y\fP\fB, double \fP\fI*green_Z\fP\fB, double \fP\fI*blue_X\fP\fB, double \fP\fI*blue_Y\fP\fB, double \fI*blue_Z\fP\fB);\fP + +\fBpng_uint_32 png_get_cHRM_XYZ_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, png_fixed_point \fP\fI*int_red_X\fP\fB, png_fixed_point \fP\fI*int_red_Y\fP\fB, png_fixed_point \fP\fI*int_red_Z\fP\fB, png_fixed_point \fP\fI*int_green_X\fP\fB, png_fixed_point \fP\fI*int_green_Y\fP\fB, png_fixed_point \fP\fI*int_green_Z\fP\fB, png_fixed_point \fP\fI*int_blue_X\fP\fB, png_fixed_point \fP\fI*int_blue_Y\fP\fB, png_fixed_point \fI*int_blue_Z\fP\fB);\fP + +\fBpng_uint_32 png_get_chunk_cache_max (png_const_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_alloc_size_t png_get_chunk_malloc_max (png_const_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_byte png_get_color_type (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_compression_buffer_size (png_const_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_byte png_get_compression_type (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_byte png_get_copyright (png_const_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_current_row_number \fI(png_const_structp\fP\fB);\fP + +\fBpng_byte png_get_current_pass_number \fI(png_const_structp\fP\fB);\fP + +\fBpng_voidp png_get_error_ptr (png_const_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_byte png_get_filter_type (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_gAMA (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, double \fI*file_gamma\fP\fB);\fP + +\fBpng_uint_32 png_get_gAMA_fixed (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fI*int_file_gamma\fP\fB);\fP + +\fBpng_byte png_get_header_ver (png_const_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_byte png_get_header_version (png_const_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_hIST (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, png_uint_16p \fI*hist\fP\fB);\fP + +\fBpng_uint_32 png_get_iCCP (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, png_charpp \fP\fIname\fP\fB, int \fP\fI*compression_type\fP\fB, png_bytepp \fP\fIprofile\fP\fB, png_uint_32 \fI*proflen\fP\fB);\fP + +\fBpng_uint_32 png_get_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*width\fP\fB, png_uint_32 \fP\fI*height\fP\fB, int \fP\fI*bit_depth\fP\fB, int \fP\fI*color_type\fP\fB, int \fP\fI*interlace_type\fP\fB, int \fP\fI*compression_type\fP\fB, int \fI*filter_type\fP\fB);\fP + +\fBpng_uint_32 png_get_image_height (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_image_width (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_int_32 png_get_int_32 (png_bytep \fIbuf\fP\fB);\fP + +\fBpng_byte png_get_interlace_type (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_io_chunk_type (png_const_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_voidp png_get_io_ptr (png_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_io_state (png_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_byte png_get_libpng_ver (png_const_structp \fIpng_ptr\fP\fB);\fP + +\fBint png_get_palette_max(png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_voidp png_get_mem_ptr (png_const_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_oFFs (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*offset_x\fP\fB, png_uint_32 \fP\fI*offset_y\fP\fB, int \fI*unit_type\fP\fB);\fP + +\fBpng_uint_32 png_get_pCAL (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fI*purpose\fP\fB, png_int_32 \fP\fI*X0\fP\fB, png_int_32 \fP\fI*X1\fP\fB, int \fP\fI*type\fP\fB, int \fP\fI*nparams\fP\fB, png_charp \fP\fI*units\fP\fB, png_charpp \fI*params\fP\fB);\fP + +\fBpng_uint_32 png_get_pHYs (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*res_x\fP\fB, png_uint_32 \fP\fI*res_y\fP\fB, int \fI*unit_type\fP\fB);\fP + +\fBfloat png_get_pixel_aspect_ratio (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_pHYs_dpi (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*res_x\fP\fB, png_uint_32 \fP\fI*res_y\fP\fB, int \fI*unit_type\fP\fB);\fP + +\fBpng_fixed_point png_get_pixel_aspect_ratio_fixed (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_pixels_per_inch (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_pixels_per_meter (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_voidp png_get_progressive_ptr (png_const_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_PLTE (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, png_colorp \fP\fI*palette\fP\fB, int \fI*num_palette\fP\fB);\fP + +\fBpng_byte png_get_rgb_to_gray_status (png_const_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_rowbytes (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_bytepp png_get_rows (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_sBIT (png_const_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_8p \fI*sig_bit\fP\fB);\fP + +\fBvoid png_get_sCAL (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, int* \fP\fIunit\fP\fB, double* \fP\fIwidth\fP\fB, double* \fIheight\fP\fB);\fP + +\fBvoid png_get_sCAL_fixed (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, int* \fP\fIunit\fP\fB, png_fixed_pointp \fP\fIwidth\fP\fB, png_fixed_pointp \fIheight\fP\fB);\fP + +\fBvoid png_get_sCAL_s (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, int* \fP\fIunit\fP\fB, png_charpp \fP\fIwidth\fP\fB, png_charpp \fIheight\fP\fB);\fP + +\fBpng_bytep png_get_signature (png_const_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_sPLT (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, png_spalette_p \fI*splt_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_sRGB (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, int \fI*file_srgb_intent\fP\fB);\fP + +\fBpng_uint_32 png_get_text (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, png_textp \fP\fI*text_ptr\fP\fB, int \fI*num_text\fP\fB);\fP + +\fBpng_uint_32 png_get_tIME (png_const_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_timep \fI*mod_time\fP\fB);\fP + +\fBpng_uint_32 png_get_tRNS (png_const_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytep \fP\fI*trans_alpha\fP\fB, int \fP\fI*num_trans\fP\fB, png_color_16p \fI*trans_color\fP\fB);\fP + +\fB/* This function is really an inline macro. \fI*/ + +\fBpng_uint_16 png_get_uint_16 (png_bytep \fIbuf\fP\fB);\fP + +\fBpng_uint_32 png_get_uint_31 (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIbuf\fP\fB);\fP + +\fB/* This function is really an inline macro. \fI*/ + +\fBpng_uint_32 png_get_uint_32 (png_bytep \fIbuf\fP\fB);\fP + +\fBpng_uint_32 png_get_unknown_chunks (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, png_unknown_chunkpp \fIunknowns\fP\fB);\fP + +\fBpng_voidp png_get_user_chunk_ptr (png_const_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_user_height_max (png_const_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_voidp png_get_user_transform_ptr (png_const_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_user_width_max (png_const_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_valid (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIflag\fP\fB);\fP + +\fBfloat png_get_x_offset_inches (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_fixed_point png_get_x_offset_inches_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_int_32 png_get_x_offset_microns (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_int_32 png_get_x_offset_pixels (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_x_pixels_per_inch (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_x_pixels_per_meter (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBfloat png_get_y_offset_inches (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_fixed_point png_get_y_offset_inches_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_int_32 png_get_y_offset_microns (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_int_32 png_get_y_offset_pixels (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_y_pixels_per_inch (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBpng_uint_32 png_get_y_pixels_per_meter (png_const_structp \fP\fIpng_ptr\fP\fB, png_const_infop \fIinfo_ptr\fP\fB);\fP + +\fBint png_handle_as_unknown (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIchunk_name\fP\fB);\fP + +\fBint png_image_begin_read_from_file (png_imagep \fP\fIimage\fP\fB, const char \fI*file_name\fP\fB);\fP + +\fBint png_image_begin_read_from_stdio (png_imagep \fP\fIimage\fP\fB, FILE* \fIfile\fP\fB);\fP + +\fBint, png_image_begin_read_from_memory (png_imagep \fP\fIimage\fP\fB, png_const_voidp \fP\fImemory\fP\fB, png_size_t \fIsize\fP\fB);\fP + +\fBint png_image_finish_read (png_imagep \fP\fIimage\fP\fB, png_colorp \fP\fIbackground\fP\fB, void \fP\fI*buffer\fP\fB, png_int_32 \fP\fIrow_stride\fP\fB, void \fI*colormap\fP\fB);\fP + +\fBvoid png_image_free (png_imagep \fIimage\fP\fB);\fP + +\fBint png_image_write_to_file (png_imagep \fP\fIimage\fP\fB, const char \fP\fI*file\fP\fB, int \fP\fIconvert_to_8bit\fP\fB, const void \fP\fI*buffer\fP\fB, png_int_32 \fP\fIrow_stride\fP\fB, void \fI*colormap\fP\fB);\fP + +\fBint png_image_write_to_memory (png_imagep \fP\fIimage\fP\fB, void \fP\fI*memory\fP\fB, png_alloc_size_t * PNG_RESTRICT \fP\fImemory_bytes\fP\fB, int \fP\fIconvert_to_8_bit\fP\fB, const void \fP\fI*buffer\fP\fB, png_int_32 \fP\fIrow_stride\fP\fB, const void \fI*colormap)\fP\fB);\fP + +\fBint png_image_write_to_stdio (png_imagep \fP\fIimage\fP\fB, FILE \fP\fI*file\fP\fB, int \fP\fIconvert_to_8_bit\fP\fB, const void \fP\fI*buffer\fP\fB, png_int_32 \fP\fIrow_stride\fP\fB, void \fI*colormap)\fP\fB);\fP + +\fBvoid png_info_init_3 (png_infopp \fP\fIinfo_ptr\fP\fB, png_size_t \fIpng_info_struct_size\fP\fB);\fP + +\fBvoid png_init_io (png_structp \fP\fIpng_ptr\fP\fB, FILE \fI*fp\fP\fB);\fP + +\fBvoid png_longjmp (png_structp \fP\fIpng_ptr\fP\fB, int \fIval\fP\fB);\fP + +\fBpng_voidp png_malloc (png_structp \fP\fIpng_ptr\fP\fB, png_alloc_size_t \fIsize\fP\fB);\fP + +\fBpng_voidp png_malloc_default (png_structp \fP\fIpng_ptr\fP\fB, png_alloc_size_t \fIsize\fP\fB);\fP + +\fBpng_voidp png_malloc_warn (png_structp \fP\fIpng_ptr\fP\fB, png_alloc_size_t \fIsize\fP\fB);\fP + +\fBpng_uint_32 png_permit_mng_features (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fImng_features_permitted\fP\fB);\fP + +\fBvoid png_process_data (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytep \fP\fIbuffer\fP\fB, png_size_t \fIbuffer_size\fP\fB);\fP + +\fBpng_size_t png_process_data_pause \fP\fI(png_structp\fP\fB, int \fIsave\fP\fB);\fP + +\fBpng_uint_32 png_process_data_skip \fI(png_structp\fP\fB);\fP + +\fBvoid png_progressive_combine_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIold_row\fP\fB, png_bytep \fInew_row\fP\fB);\fP + +\fBvoid png_read_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_read_image (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fIimage\fP\fB);\fP + +\fBvoid png_read_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_read_png (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fItransforms\fP\fB, png_voidp \fIparams\fP\fB);\fP + +\fBvoid png_read_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIrow\fP\fB, png_bytep \fIdisplay_row\fP\fB);\fP + +\fBvoid png_read_rows (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fP\fIrow\fP\fB, png_bytepp \fP\fIdisplay_row\fP\fB, png_uint_32 \fInum_rows\fP\fB);\fP + +\fBvoid png_read_update_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBint png_reset_zstream (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_save_int_32 (png_bytep \fP\fIbuf\fP\fB, png_int_32 \fIi\fP\fB);\fP + +\fBvoid png_save_uint_16 (png_bytep \fP\fIbuf\fP\fB, unsigned int \fIi\fP\fB);\fP + +\fBvoid png_save_uint_32 (png_bytep \fP\fIbuf\fP\fB, png_uint_32 \fIi\fP\fB);\fP + +\fBvoid png_set_add_alpha (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIfiller\fP\fB, int \fIflags\fP\fB);\fP + +\fBvoid png_set_alpha_mode (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fImode\fP\fB, double \fIoutput_gamma\fP\fB);\fP + +\fBvoid png_set_alpha_mode_fixed (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fImode\fP\fB, png_fixed_point \fIoutput_gamma\fP\fB);\fP + +\fBvoid png_set_background (png_structp \fP\fIpng_ptr\fP\fB, png_color_16p \fP\fIbackground_color\fP\fB, int \fP\fIbackground_gamma_code\fP\fB, int \fP\fIneed_expand\fP\fB, double \fIbackground_gamma\fP\fB);\fP + +\fBvoid png_set_background_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_color_16p \fP\fIbackground_color\fP\fB, int \fP\fIbackground_gamma_code\fP\fB, int \fP\fIneed_expand\fP\fB, png_uint_32 \fIbackground_gamma\fP\fB);\fP + +\fBvoid png_set_benign_errors (png_structp \fP\fIpng_ptr\fP\fB, int \fIallowed\fP\fB);\fP + +\fBvoid png_set_bgr (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_bKGD (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_16p \fIbackground\fP\fB);\fP + +\fBvoid png_set_check_for_invalid_index(png_structrp \fP\fIpng_ptr\fP\fB, int \fIallowed\fP\fB);\fP + +\fBvoid png_set_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fP\fIwhite_x\fP\fB, double \fP\fIwhite_y\fP\fB, double \fP\fIred_x\fP\fB, double \fP\fIred_y\fP\fB, double \fP\fIgreen_x\fP\fB, double \fP\fIgreen_y\fP\fB, double \fP\fIblue_x\fP\fB, double \fIblue_y\fP\fB);\fP + +\fBvoid png_set_cHRM_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIwhite_x\fP\fB, png_uint_32 \fP\fIwhite_y\fP\fB, png_uint_32 \fP\fIred_x\fP\fB, png_uint_32 \fP\fIred_y\fP\fB, png_uint_32 \fP\fIgreen_x\fP\fB, png_uint_32 \fP\fIgreen_y\fP\fB, png_uint_32 \fP\fIblue_x\fP\fB, png_uint_32 \fIblue_y\fP\fB);\fP + +\fBvoid png_set_cHRM_XYZ (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fP\fIred_X\fP\fB, double \fP\fIred_Y\fP\fB, double \fP\fIred_Z\fP\fB, double \fP\fIgreen_X\fP\fB, double \fP\fIgreen_Y\fP\fB, double \fP\fIgreen_Z\fP\fB, double \fP\fIblue_X\fP\fB, double \fP\fIblue_Y\fP\fB, double \fIblue_Z\fP\fB);\fP + +\fBvoid png_set_cHRM_XYZ_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_fixed_point \fP\fIint_red_X\fP\fB, png_fixed_point \fP\fIint_red_Y\fP\fB, png_fixed_point \fP\fIint_red_Z\fP\fB, png_fixed_point \fP\fIint_green_X\fP\fB, png_fixed_point \fP\fIint_green_Y\fP\fB, png_fixed_point \fP\fIint_green_Z\fP\fB, png_fixed_point \fP\fIint_blue_X\fP\fB, png_fixed_point \fP\fIint_blue_Y\fP\fB, png_fixed_point \fIint_blue_Z\fP\fB);\fP + +\fBvoid png_set_chunk_cache_max (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIuser_chunk_cache_max\fP\fB);\fP + +\fBvoid png_set_compression_level (png_structp \fP\fIpng_ptr\fP\fB, int \fIlevel\fP\fB);\fP + +\fBvoid png_set_compression_mem_level (png_structp \fP\fIpng_ptr\fP\fB, int \fImem_level\fP\fB);\fP + +\fBvoid png_set_compression_method (png_structp \fP\fIpng_ptr\fP\fB, int \fImethod\fP\fB);\fP + +\fBvoid png_set_compression_strategy (png_structp \fP\fIpng_ptr\fP\fB, int \fIstrategy\fP\fB);\fP + +\fBvoid png_set_compression_window_bits (png_structp \fP\fIpng_ptr\fP\fB, int \fIwindow_bits\fP\fB);\fP + +\fBvoid png_set_crc_action (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIcrit_action\fP\fB, int \fIancil_action\fP\fB);\fP + +\fBvoid png_set_error_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fIwarning_fn\fP\fB);\fP + +\fBvoid png_set_expand (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_expand_16 (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_expand_gray_1_2_4_to_8 (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_filler (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIfiller\fP\fB, int \fIflags\fP\fB);\fP + +\fBvoid png_set_filter (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fImethod\fP\fB, int \fIfilters\fP\fB);\fP + +\fBvoid png_set_filter_heuristics (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIheuristic_method\fP\fB, int \fP\fInum_weights\fP\fB, png_doublep \fP\fIfilter_weights\fP\fB, png_doublep \fIfilter_costs\fP\fB);\fP + +\fBvoid png_set_filter_heuristics_fixed (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIheuristic_method\fP\fB, int \fP\fInum_weights\fP\fB, png_fixed_point_p \fP\fIfilter_weights\fP\fB, png_fixed_point_p \fIfilter_costs\fP\fB);\fP + +\fBvoid png_set_flush (png_structp \fP\fIpng_ptr\fP\fB, int \fInrows\fP\fB);\fP + +\fBvoid png_set_gamma (png_structp \fP\fIpng_ptr\fP\fB, double \fP\fIscreen_gamma\fP\fB, double \fIdefault_file_gamma\fP\fB);\fP + +\fBvoid png_set_gamma_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIscreen_gamma\fP\fB, png_uint_32 \fIdefault_file_gamma\fP\fB);\fP + +\fBvoid png_set_gAMA (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fIfile_gamma\fP\fB);\fP + +\fBvoid png_set_gAMA_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIfile_gamma\fP\fB);\fP + +\fBvoid png_set_gray_1_2_4_to_8 (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_gray_to_rgb (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_hIST (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_16p \fIhist\fP\fB);\fP + +\fBvoid png_set_iCCP (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_const_charp \fP\fIname\fP\fB, int \fP\fIcompression_type\fP\fB, png_const_bytep \fP\fIprofile\fP\fB, png_uint_32 \fIproflen\fP\fB);\fP + +\fBint png_set_interlace_handling (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_invalid (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fImask\fP\fB);\fP + +\fBvoid png_set_invert_alpha (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_invert_mono (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIwidth\fP\fB, png_uint_32 \fP\fIheight\fP\fB, int \fP\fIbit_depth\fP\fB, int \fP\fIcolor_type\fP\fB, int \fP\fIinterlace_type\fP\fB, int \fP\fIcompression_type\fP\fB, int \fIfilter_type\fP\fB);\fP + +\fBvoid png_set_keep_unknown_chunks (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIkeep\fP\fB, png_bytep \fP\fIchunk_list\fP\fB, int \fInum_chunks\fP\fB);\fP + +\fBjmp_buf* png_set_longjmp_fn (png_structp \fP\fIpng_ptr\fP\fB, png_longjmp_ptr \fP\fIlongjmp_fn\fP\fB, size_t \fIjmp_buf_size\fP\fB);\fP + +\fBvoid png_set_chunk_malloc_max (png_structp \fP\fIpng_ptr\fP\fB, png_alloc_size_t \fIuser_chunk_cache_max\fP\fB);\fP + +\fBvoid png_set_compression_buffer_size (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIsize\fP\fB);\fP + +\fBvoid png_set_mem_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fImem_ptr\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_free_ptr \fIfree_fn\fP\fB);\fP + +\fBvoid png_set_oFFs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIoffset_x\fP\fB, png_uint_32 \fP\fIoffset_y\fP\fB, int \fIunit_type\fP\fB);\fP + +\fBint png_set_option(png_structrp \fP\fIpng_ptr\fP\fB, int \fP\fIoption\fP\fB, int \fIonoff\fP\fB);\fP + +\fBvoid png_set_packing (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_packswap (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_palette_to_rgb (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_pCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fIpurpose\fP\fB, png_int_32 \fP\fIX0\fP\fB, png_int_32 \fP\fIX1\fP\fB, int \fP\fItype\fP\fB, int \fP\fInparams\fP\fB, png_charp \fP\fIunits\fP\fB, png_charpp \fIparams\fP\fB);\fP + +\fBvoid png_set_pHYs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIres_x\fP\fB, png_uint_32 \fP\fIres_y\fP\fB, int \fIunit_type\fP\fB);\fP + +\fBvoid png_set_progressive_read_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIprogressive_ptr\fP\fB, png_progressive_info_ptr \fP\fIinfo_fn\fP\fB, png_progressive_row_ptr \fP\fIrow_fn\fP\fB, png_progressive_end_ptr \fIend_fn\fP\fB);\fP + +\fBvoid png_set_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, int \fInum_palette\fP\fB);\fP + +\fBvoid png_set_quantize (png_structp \fP\fIpng_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, int \fP\fInum_palette\fP\fB, int \fP\fImaximum_colors\fP\fB, png_uint_16p \fP\fIhistogram\fP\fB, int \fIfull_quantize\fP\fB);\fP + +\fBvoid png_set_read_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIio_ptr\fP\fB, png_rw_ptr \fIread_data_fn\fP\fB);\fP + +\fBvoid png_set_read_status_fn (png_structp \fP\fIpng_ptr\fP\fB, png_read_status_ptr \fIread_row_fn\fP\fB);\fP + +\fBvoid png_set_read_user_chunk_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIuser_chunk_ptr\fP\fB, png_user_chunk_ptr \fIread_user_chunk_fn\fP\fB);\fP + +\fBvoid png_set_read_user_transform_fn (png_structp \fP\fIpng_ptr\fP\fB, png_user_transform_ptr \fIread_user_transform_fn\fP\fB);\fP + +\fBvoid png_set_rgb_to_gray (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIerror_action\fP\fB, double \fP\fIred\fP\fB, double \fIgreen\fP\fB);\fP + +\fBvoid png_set_rgb_to_gray_fixed (png_structp \fP\fIpng_ptr\fP\fB, int error_action png_uint_32 \fP\fIred\fP\fB, png_uint_32 \fIgreen\fP\fB);\fP + +\fBvoid png_set_rows (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytepp \fIrow_pointers\fP\fB);\fP + +\fBvoid png_set_sBIT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_8p \fIsig_bit\fP\fB);\fP + +\fBvoid png_set_sCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fIunit\fP\fB, double \fP\fIwidth\fP\fB, double \fIheight\fP\fB);\fP + +\fBvoid png_set_sCAL_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fIunit\fP\fB, png_fixed_point \fP\fIwidth\fP\fB, png_fixed_point \fIheight\fP\fB);\fP + +\fBvoid png_set_sCAL_s (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fIunit\fP\fB, png_charp \fP\fIwidth\fP\fB, png_charp \fIheight\fP\fB);\fP + +\fBvoid png_set_scale_16 (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_shift (png_structp \fP\fIpng_ptr\fP\fB, png_color_8p \fItrue_bits\fP\fB);\fP + +\fBvoid png_set_sig_bytes (png_structp \fP\fIpng_ptr\fP\fB, int \fInum_bytes\fP\fB);\fP + +\fBvoid png_set_sPLT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_spalette_p \fP\fIsplt_ptr\fP\fB, int \fInum_spalettes\fP\fB);\fP + +\fBvoid png_set_sRGB (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fIsrgb_intent\fP\fB);\fP + +\fBvoid png_set_sRGB_gAMA_and_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fIsrgb_intent\fP\fB);\fP + +\fBvoid png_set_strip_16 (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_strip_alpha (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_strip_error_numbers (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIstrip_mode\fP\fB);\fP + +\fBvoid png_set_swap (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_swap_alpha (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_set_text (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_textp \fP\fItext_ptr\fP\fB, int \fInum_text\fP\fB);\fP + +\fBvoid png_set_text_compression_level (png_structp \fP\fIpng_ptr\fP\fB, int \fIlevel\fP\fB);\fP + +\fBvoid png_set_text_compression_mem_level (png_structp \fP\fIpng_ptr\fP\fB, int \fImem_level\fP\fB);\fP + +\fBvoid png_set_text_compression_strategy (png_structp \fP\fIpng_ptr\fP\fB, int \fIstrategy\fP\fB);\fP + +\fBvoid png_set_text_compression_window_bits (png_structp \fP\fIpng_ptr\fP\fB, int \fIwindow_bits\fP\fB);\fP + +\fBvoid \fP\fIpng_set_text_compression_method\fP\fB, (png_structp \fP\fIpng_ptr\fP\fB, int \fImethod)\fP\fB);\fP + +\fBvoid png_set_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_timep \fImod_time\fP\fB);\fP + +\fBvoid png_set_tRNS (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytep \fP\fItrans_alpha\fP\fB, int \fP\fInum_trans\fP\fB, png_color_16p \fItrans_color\fP\fB);\fP + +\fBvoid png_set_tRNS_to_alpha (png_structp \fIpng_ptr\fP\fB);\fP + +\fBpng_uint_32 png_set_unknown_chunks (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_unknown_chunkp \fP\fIunknowns\fP\fB, int \fP\fInum\fP\fB, int \fIlocation\fP\fB);\fP + +\fBvoid png_set_unknown_chunk_location (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fIchunk\fP\fB, int \fIlocation\fP\fB);\fP + +\fBvoid png_set_user_limits (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIuser_width_max\fP\fB, png_uint_32 \fIuser_height_max\fP\fB);\fP + +\fBvoid png_set_user_transform_info (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIuser_transform_ptr\fP\fB, int \fP\fIuser_transform_depth\fP\fB, int \fIuser_transform_channels\fP\fB);\fP + +\fBvoid png_set_write_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIio_ptr\fP\fB, png_rw_ptr \fP\fIwrite_data_fn\fP\fB, png_flush_ptr \fIoutput_flush_fn\fP\fB);\fP + +\fBvoid png_set_write_status_fn (png_structp \fP\fIpng_ptr\fP\fB, png_write_status_ptr \fIwrite_row_fn\fP\fB);\fP + +\fBvoid png_set_write_user_transform_fn (png_structp \fP\fIpng_ptr\fP\fB, png_user_transform_ptr \fIwrite_user_transform_fn\fP\fB);\fP + +\fBint png_sig_cmp (png_bytep \fP\fIsig\fP\fB, png_size_t \fP\fIstart\fP\fB, png_size_t \fInum_to_check\fP\fB);\fP + +\fBvoid png_start_read_image (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_warning (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fImessage\fP\fB);\fP + +\fBvoid png_write_chunk (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIchunk_name\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP + +\fBvoid png_write_chunk_data (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP + +\fBvoid png_write_chunk_end (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_write_chunk_start (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIchunk_name\fP\fB, png_uint_32 \fIlength\fP\fB);\fP + +\fBvoid png_write_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_write_flush (png_structp \fIpng_ptr\fP\fB);\fP + +\fBvoid png_write_image (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fIimage\fP\fB);\fP + +\fBvoid png_write_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_write_info_before_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP + +\fBvoid png_write_png (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fItransforms\fP\fB, png_voidp \fIparams\fP\fB);\fP + +\fBvoid png_write_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIrow\fP\fB);\fP + +\fBvoid png_write_rows (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fP\fIrow\fP\fB, png_uint_32 \fInum_rows\fP\fB);\fP + +\fBvoid png_write_sig (png_structp \fIpng_ptr\fP\fB);\fP + +.SH DESCRIPTION +The +.I libpng +library supports encoding, decoding, and various manipulations of +the Portable Network Graphics (PNG) format image files. It uses the +.IR zlib(3) +compression library. +Following is a copy of the libpng-manual.txt file that accompanies libpng. +.SH LIBPNG.TXT +libpng-manual.txt - A description on how to use and modify libpng + + libpng version 1.6.23 - June 9, 2016 + Updated and distributed by Glenn Randers-Pehrson + + Copyright (c) 1998-2016 Glenn Randers-Pehrson + + This document is released under the libpng license. + For conditions of distribution and use, see the disclaimer + and license in png.h + + Based on: + + libpng versions 0.97, January 1998, through 1.6.23 - June 9, 2016 + Updated and distributed by Glenn Randers-Pehrson + Copyright (c) 1998-2016 Glenn Randers-Pehrson + + libpng 1.0 beta 6 - version 0.96 - May 28, 1997 + Updated and distributed by Andreas Dilger + Copyright (c) 1996, 1997 Andreas Dilger + + libpng 1.0 beta 2 - version 0.88 - January 26, 1996 + For conditions of distribution and use, see copyright + notice in png.h. Copyright (c) 1995, 1996 Guy Eric + Schalnat, Group 42, Inc. + + Updated/rewritten per request in the libpng FAQ + Copyright (c) 1995, 1996 Frank J. T. Wojcik + December 18, 1995 & January 20, 1996 + + TABLE OF CONTENTS + + I. Introduction + II. Structures + III. Reading + IV. Writing + V. Simplified API + VI. Modifying/Customizing libpng + VII. MNG support + VIII. Changes to Libpng from version 0.88 + IX. Changes to Libpng from version 1.0.x to 1.2.x + X. Changes to Libpng from version 1.0.x/1.2.x to 1.4.x + XI. Changes to Libpng from version 1.4.x to 1.5.x + XII. Changes to Libpng from version 1.5.x to 1.6.x + XIII. Detecting libpng + XIV. Source code repository + XV. Coding style + XVI. Y2K Compliance in libpng + +.SH I. Introduction + +This file describes how to use and modify the PNG reference library +(known as libpng) for your own use. In addition to this +file, example.c is a good starting point for using the library, as +it is heavily commented and should include everything most people +will need. We assume that libpng is already installed; see the +INSTALL file for instructions on how to configure and install libpng. + +For examples of libpng usage, see the files "example.c", "pngtest.c", +and the files in the "contrib" directory, all of which are included in +the libpng distribution. + +Libpng was written as a companion to the PNG specification, as a way +of reducing the amount of time and effort it takes to support the PNG +file format in application programs. + +The PNG specification (second edition), November 2003, is available as +a W3C Recommendation and as an ISO Standard (ISO/IEC 15948:2004 (E)) at +. +It is technically equivalent +to the PNG specification (second edition) but has some additional material. + +The PNG-1.0 specification is available as RFC 2083 + and as a +W3C Recommendation . + +Some additional chunks are described in the special-purpose public chunks +documents at + +Other information +about PNG, and the latest version of libpng, can be found at the PNG home +page, . + +Most users will not have to modify the library significantly; advanced +users may want to modify it more. All attempts were made to make it as +complete as possible, while keeping the code easy to understand. +Currently, this library only supports C. Support for other languages +is being considered. + +Libpng has been designed to handle multiple sessions at one time, +to be easily modifiable, to be portable to the vast majority of +machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy +to use. The ultimate goal of libpng is to promote the acceptance of +the PNG file format in whatever way possible. While there is still +work to be done (see the TODO file), libpng should cover the +majority of the needs of its users. + +Libpng uses zlib for its compression and decompression of PNG files. +Further information about zlib, and the latest version of zlib, can +be found at the zlib home page, . +The zlib compression utility is a general purpose utility that is +useful for more than PNG files, and can be used without libpng. +See the documentation delivered with zlib for more details. +You can usually find the source files for the zlib utility wherever you +find the libpng source files. + +Libpng is thread safe, provided the threads are using different +instances of the structures. Each thread should have its own +png_struct and png_info instances, and thus its own image. +Libpng does not protect itself against two threads using the +same instance of a structure. + +.SH II. Structures + +There are two main structures that are important to libpng, png_struct +and png_info. Both are internal structures that are no longer exposed +in the libpng interface (as of libpng 1.5.0). + +The png_info structure is designed to provide information about the +PNG file. At one time, the fields of png_info were intended to be +directly accessible to the user. However, this tended to cause problems +with applications using dynamically loaded libraries, and as a result +a set of interface functions for png_info (the png_get_*() and png_set_*() +functions) was developed, and direct access to the png_info fields was +deprecated.. + +The png_struct structure is the object used by the library to decode a +single image. As of 1.5.0 this structure is also not exposed. + +Almost all libpng APIs require a pointer to a png_struct as the first argument. +Many (in particular the png_set and png_get APIs) also require a pointer +to png_info as the second argument. Some application visible macros +defined in png.h designed for basic data access (reading and writing +integers in the PNG format) don't take a png_info pointer, but it's almost +always safe to assume that a (png_struct*) has to be passed to call an API +function. + +You can have more than one png_info structure associated with an image, +as illustrated in pngtest.c, one for information valid prior to the +IDAT chunks and another (called "end_info" below) for things after them. + +The png.h header file is an invaluable reference for programming with libpng. +And while I'm on the topic, make sure you include the libpng header file: + +#include + +and also (as of libpng-1.5.0) the zlib header file, if you need it: + +#include + +.SS Types + +The png.h header file defines a number of integral types used by the +APIs. Most of these are fairly obvious; for example types corresponding +to integers of particular sizes and types for passing color values. + +One exception is how non-integral numbers are handled. For application +convenience most APIs that take such numbers have C (double) arguments; +however, internally PNG, and libpng, use 32 bit signed integers and encode +the value by multiplying by 100,000. As of libpng 1.5.0 a convenience +macro PNG_FP_1 is defined in png.h along with a type (png_fixed_point) +which is simply (png_int_32). + +All APIs that take (double) arguments also have a matching API that +takes the corresponding fixed point integer arguments. The fixed point +API has the same name as the floating point one with "_fixed" appended. +The actual range of values permitted in the APIs is frequently less than +the full range of (png_fixed_point) (\-21474 to +21474). When APIs require +a non-negative argument the type is recorded as png_uint_32 above. Consult +the header file and the text below for more information. + +Special care must be take with sCAL chunk handling because the chunk itself +uses non-integral values encoded as strings containing decimal floating point +numbers. See the comments in the header file. + +.SS Configuration + +The main header file function declarations are frequently protected by C +preprocessing directives of the form: + + #ifdef PNG_feature_SUPPORTED + declare-function + #endif + ... + #ifdef PNG_feature_SUPPORTED + use-function + #endif + +The library can be built without support for these APIs, although a +standard build will have all implemented APIs. Application programs +should check the feature macros before using an API for maximum +portability. From libpng 1.5.0 the feature macros set during the build +of libpng are recorded in the header file "pnglibconf.h" and this file +is always included by png.h. + +If you don't need to change the library configuration from the default, skip to +the next section ("Reading"). + +Notice that some of the makefiles in the 'scripts' directory and (in 1.5.0) all +of the build project files in the 'projects' directory simply copy +scripts/pnglibconf.h.prebuilt to pnglibconf.h. This means that these build +systems do not permit easy auto-configuration of the library - they only +support the default configuration. + +The easiest way to make minor changes to the libpng configuration when +auto-configuration is supported is to add definitions to the command line +using (typically) CPPFLAGS. For example: + +CPPFLAGS=\-DPNG_NO_FLOATING_ARITHMETIC + +will change the internal libpng math implementation for gamma correction and +other arithmetic calculations to fixed point, avoiding the need for fast +floating point support. The result can be seen in the generated pnglibconf.h - +make sure it contains the changed feature macro setting. + +If you need to make more extensive configuration changes - more than one or two +feature macro settings - you can either add \-DPNG_USER_CONFIG to the build +command line and put a list of feature macro settings in pngusr.h or you can set +DFA_XTRA (a makefile variable) to a file containing the same information in the +form of 'option' settings. + +A. Changing pnglibconf.h + +A variety of methods exist to build libpng. Not all of these support +reconfiguration of pnglibconf.h. To reconfigure pnglibconf.h it must either be +rebuilt from scripts/pnglibconf.dfa using awk or it must be edited by hand. + +Hand editing is achieved by copying scripts/pnglibconf.h.prebuilt to +pnglibconf.h and changing the lines defining the supported features, paying +very close attention to the 'option' information in scripts/pnglibconf.dfa +that describes those features and their requirements. This is easy to get +wrong. + +B. Configuration using DFA_XTRA + +Rebuilding from pnglibconf.dfa is easy if a functioning 'awk', or a later +variant such as 'nawk' or 'gawk', is available. The configure build will +automatically find an appropriate awk and build pnglibconf.h. +The scripts/pnglibconf.mak file contains a set of make rules for doing the +same thing if configure is not used, and many of the makefiles in the scripts +directory use this approach. + +When rebuilding simply write a new file containing changed options and set +DFA_XTRA to the name of this file. This causes the build to append the new file +to the end of scripts/pnglibconf.dfa. The pngusr.dfa file should contain lines +of the following forms: + +everything = off + +This turns all optional features off. Include it at the start of pngusr.dfa to +make it easier to build a minimal configuration. You will need to turn at least +some features on afterward to enable either reading or writing code, or both. + +option feature on +option feature off + +Enable or disable a single feature. This will automatically enable other +features required by a feature that is turned on or disable other features that +require a feature which is turned off. Conflicting settings will cause an error +message to be emitted by awk. + +setting feature default value + +Changes the default value of setting 'feature' to 'value'. There are a small +number of settings listed at the top of pnglibconf.h, they are documented in the +source code. Most of these values have performance implications for the library +but most of them have no visible effect on the API. Some can also be overridden +from the API. + +This method of building a customized pnglibconf.h is illustrated in +contrib/pngminim/*. See the "$(PNGCONF):" target in the makefile and +pngusr.dfa in these directories. + +C. Configuration using PNG_USER_CONFIG + +If \-DPNG_USER_CONFIG is added to the CPPFLAGS when pnglibconf.h is built, +the file pngusr.h will automatically be included before the options in +scripts/pnglibconf.dfa are processed. Your pngusr.h file should contain only +macro definitions turning features on or off or setting settings. + +Apart from the global setting "everything = off" all the options listed above +can be set using macros in pngusr.h: + +#define PNG_feature_SUPPORTED + +is equivalent to: + +option feature on + +#define PNG_NO_feature + +is equivalent to: + +option feature off + +#define PNG_feature value + +is equivalent to: + +setting feature default value + +Notice that in both cases, pngusr.dfa and pngusr.h, the contents of the +pngusr file you supply override the contents of scripts/pnglibconf.dfa + +If confusing or incomprehensible behavior results it is possible to +examine the intermediate file pnglibconf.dfn to find the full set of +dependency information for each setting and option. Simply locate the +feature in the file and read the C comments that precede it. + +This method is also illustrated in the contrib/pngminim/* makefiles and +pngusr.h. + +.SH III. Reading + +We'll now walk you through the possible functions to call when reading +in a PNG file sequentially, briefly explaining the syntax and purpose +of each one. See example.c and png.h for more detail. While +progressive reading is covered in the next section, you will still +need some of the functions discussed in this section to read a PNG +file. + +.SS Setup + +You will want to do the I/O initialization(*) before you get into libpng, +so if it doesn't work, you don't have much to undo. Of course, you +will also want to insure that you are, in fact, dealing with a PNG +file. Libpng provides a simple check to see if a file is a PNG file. +To use it, pass in the first 1 to 8 bytes of the file to the function +png_sig_cmp(), and it will return 0 (false) if the bytes match the +corresponding bytes of the PNG signature, or nonzero (true) otherwise. +Of course, the more bytes you pass in, the greater the accuracy of the +prediction. + +If you are intending to keep the file pointer open for use in libpng, +you must ensure you don't read more than 8 bytes from the beginning +of the file, and you also have to make a call to png_set_sig_bytes() +with the number of bytes you read from the beginning. Libpng will +then only check the bytes (if any) that your program didn't read. + +(*): If you are not using the standard I/O functions, you will need +to replace them with custom functions. See the discussion under +Customizing libpng. + + FILE *fp = fopen(file_name, "rb"); + if (!fp) + { + return (ERROR); + } + + if (fread(header, 1, number, fp) != number) + { + return (ERROR); + } + + is_png = !png_sig_cmp(header, 0, number); + if (!is_png) + { + return (NOT_PNG); + } + +Next, png_struct and png_info need to be allocated and initialized. In +order to ensure that the size of these structures is correct even with a +dynamically linked libpng, there are functions to initialize and +allocate the structures. We also pass the library version, optional +pointers to error handling functions, and a pointer to a data struct for +use by the error functions, if necessary (the pointer and functions can +be NULL if the default error handlers are to be used). See the section +on Changes to Libpng below regarding the old initialization functions. +The structure allocation functions quietly return NULL if they fail to +create the structure, so your application should check for that. + + png_structp png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + + if (!png_ptr) + return (ERROR); + + png_infop info_ptr = png_create_info_struct(png_ptr); + + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, + (png_infopp)NULL, (png_infopp)NULL); + return (ERROR); + } + +If you want to use your own memory allocation routines, +use a libpng that was built with PNG_USER_MEM_SUPPORTED defined, and use +png_create_read_struct_2() instead of png_create_read_struct(): + + png_structp png_ptr = png_create_read_struct_2 + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn, (png_voidp) + user_mem_ptr, user_malloc_fn, user_free_fn); + +The error handling routines passed to png_create_read_struct() +and the memory alloc/free routines passed to png_create_struct_2() +are only necessary if you are not using the libpng supplied error +handling and memory alloc/free functions. + +When libpng encounters an error, it expects to longjmp back +to your routine. Therefore, you will need to call setjmp and pass +your png_jmpbuf(png_ptr). If you read the file from different +routines, you will need to update the longjmp buffer every time you enter +a new routine that will call a png_*() function. + +See your documentation of setjmp/longjmp for your compiler for more +information on setjmp/longjmp. See the discussion on libpng error +handling in the Customizing Libpng section below for more information +on the libpng error handling. If an error occurs, and libpng longjmp's +back to your setjmp, you will want to call png_destroy_read_struct() to +free any memory. + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + &end_info); + fclose(fp); + return (ERROR); + } + +Pass (png_infopp)NULL instead of &end_info if you didn't create +an end_info structure. + +If you would rather avoid the complexity of setjmp/longjmp issues, +you can compile libpng with PNG_NO_SETJMP, in which case +errors will result in a call to PNG_ABORT() which defaults to abort(). + +You can #define PNG_ABORT() to a function that does something +more useful than abort(), as long as your function does not +return. + +Now you need to set up the input code. The default for libpng is to +use the C function fread(). If you use this, you will need to pass a +valid FILE * in the function png_init_io(). Be sure that the file is +opened in binary mode. If you wish to handle reading data in another +way, you need not call the png_init_io() function, but you must then +implement the libpng I/O methods discussed in the Customizing Libpng +section below. + + png_init_io(png_ptr, fp); + +If you had previously opened the file and read any of the signature from +the beginning in order to see if this was a PNG file, you need to let +libpng know that there are some bytes missing from the start of the file. + + png_set_sig_bytes(png_ptr, number); + +You can change the zlib compression buffer size to be used while +reading compressed data with + + png_set_compression_buffer_size(png_ptr, buffer_size); + +where the default size is 8192 bytes. Note that the buffer size +is changed immediately and the buffer is reallocated immediately, +instead of setting a flag to be acted upon later. + +If you want CRC errors to be handled in a different manner than +the default, use + + png_set_crc_action(png_ptr, crit_action, ancil_action); + +The values for png_set_crc_action() say how libpng is to handle CRC errors in +ancillary and critical chunks, and whether to use the data contained +therein. Note that it is impossible to "discard" data in a critical +chunk. + +Choices for (int) crit_action are + PNG_CRC_DEFAULT 0 error/quit + PNG_CRC_ERROR_QUIT 1 error/quit + PNG_CRC_WARN_USE 3 warn/use data + PNG_CRC_QUIET_USE 4 quiet/use data + PNG_CRC_NO_CHANGE 5 use the current value + +Choices for (int) ancil_action are + PNG_CRC_DEFAULT 0 error/quit + PNG_CRC_ERROR_QUIT 1 error/quit + PNG_CRC_WARN_DISCARD 2 warn/discard data + PNG_CRC_WARN_USE 3 warn/use data + PNG_CRC_QUIET_USE 4 quiet/use data + PNG_CRC_NO_CHANGE 5 use the current value + +.SS Setting up callback code + +You can set up a callback function to handle any unknown chunks in the +input stream. You must supply the function + + read_chunk_callback(png_structp png_ptr, + png_unknown_chunkp chunk); + { + /* The unknown chunk structure contains your + chunk data, along with similar data for any other + unknown chunks: */ + + png_byte name[5]; + png_byte *data; + png_size_t size; + + /* Note that libpng has already taken care of + the CRC handling */ + + /* put your code here. Search for your chunk in the + unknown chunk structure, process it, and return one + of the following: */ + + return (\-n); /* chunk had an error */ + return (0); /* did not recognize */ + return (n); /* success */ + } + +(You can give your function another name that you like instead of +"read_chunk_callback") + +To inform libpng about your function, use + + png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, + read_chunk_callback); + +This names not only the callback function, but also a user pointer that +you can retrieve with + + png_get_user_chunk_ptr(png_ptr); + +If you call the png_set_read_user_chunk_fn() function, then all unknown +chunks which the callback does not handle will be saved when read. You can +cause them to be discarded by returning '1' ("handled") instead of '0'. This +behavior will change in libpng 1.7 and the default handling set by the +png_set_keep_unknown_chunks() function, described below, will be used when the +callback returns 0. If you want the existing behavior you should set the global +default to PNG_HANDLE_CHUNK_IF_SAFE now; this is compatible with all current +versions of libpng and with 1.7. Libpng 1.6 issues a warning if you keep the +default, or PNG_HANDLE_CHUNK_NEVER, and the callback returns 0. + +At this point, you can set up a callback function that will be +called after each row has been read, which you can use to control +a progress meter or the like. It's demonstrated in pngtest.c. +You must supply a function + + void read_row_callback(png_structp png_ptr, + png_uint_32 row, int pass); + { + /* put your code here */ + } + +(You can give it another name that you like instead of "read_row_callback") + +To inform libpng about your function, use + + png_set_read_status_fn(png_ptr, read_row_callback); + +When this function is called the row has already been completely processed and +the 'row' and 'pass' refer to the next row to be handled. For the +non-interlaced case the row that was just handled is simply one less than the +passed in row number, and pass will always be 0. For the interlaced case the +same applies unless the row value is 0, in which case the row just handled was +the last one from one of the preceding passes. Because interlacing may skip a +pass you cannot be sure that the preceding pass is just 'pass\-1', if you really +need to know what the last pass is record (row,pass) from the callback and use +the last recorded value each time. + +As with the user transform you can find the output row using the +PNG_ROW_FROM_PASS_ROW macro. + +.SS Unknown-chunk handling + +Now you get to set the way the library processes unknown chunks in the +input PNG stream. Both known and unknown chunks will be read. Normal +behavior is that known chunks will be parsed into information in +various info_ptr members while unknown chunks will be discarded. This +behavior can be wasteful if your application will never use some known +chunk types. To change this, you can call: + + png_set_keep_unknown_chunks(png_ptr, keep, + chunk_list, num_chunks); + + keep - 0: default unknown chunk handling + 1: ignore; do not keep + 2: keep only if safe-to-copy + 3: keep even if unsafe-to-copy + + You can use these definitions: + PNG_HANDLE_CHUNK_AS_DEFAULT 0 + PNG_HANDLE_CHUNK_NEVER 1 + PNG_HANDLE_CHUNK_IF_SAFE 2 + PNG_HANDLE_CHUNK_ALWAYS 3 + + chunk_list - list of chunks affected (a byte string, + five bytes per chunk, NULL or '\0' if + num_chunks is positive; ignored if + numchunks <= 0). + + num_chunks - number of chunks affected; if 0, all + unknown chunks are affected. If positive, + only the chunks in the list are affected, + and if negative all unknown chunks and + all known chunks except for the IHDR, + PLTE, tRNS, IDAT, and IEND chunks are + affected. + +Unknown chunks declared in this way will be saved as raw data onto a +list of png_unknown_chunk structures. If a chunk that is normally +known to libpng is named in the list, it will be handled as unknown, +according to the "keep" directive. If a chunk is named in successive +instances of png_set_keep_unknown_chunks(), the final instance will +take precedence. The IHDR and IEND chunks should not be named in +chunk_list; if they are, libpng will process them normally anyway. +If you know that your application will never make use of some particular +chunks, use PNG_HANDLE_CHUNK_NEVER (or 1) as demonstrated below. + +Here is an example of the usage of png_set_keep_unknown_chunks(), +where the private "vpAg" chunk will later be processed by a user chunk +callback function: + + png_byte vpAg[5]={118, 112, 65, 103, (png_byte) '\0'}; + + #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + png_byte unused_chunks[]= + { + 104, 73, 83, 84, (png_byte) '\0', /* hIST */ + 105, 84, 88, 116, (png_byte) '\0', /* iTXt */ + 112, 67, 65, 76, (png_byte) '\0', /* pCAL */ + 115, 67, 65, 76, (png_byte) '\0', /* sCAL */ + 115, 80, 76, 84, (png_byte) '\0', /* sPLT */ + 116, 73, 77, 69, (png_byte) '\0', /* tIME */ + }; + #endif + + ... + + #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + /* ignore all unknown chunks + * (use global setting "2" for libpng16 and earlier): + */ + png_set_keep_unknown_chunks(read_ptr, 2, NULL, 0); + + /* except for vpAg: */ + png_set_keep_unknown_chunks(read_ptr, 2, vpAg, 1); + + /* also ignore unused known chunks: */ + png_set_keep_unknown_chunks(read_ptr, 1, unused_chunks, + (int)(sizeof unused_chunks)/5); + #endif + +.SS User limits + +The PNG specification allows the width and height of an image to be as +large as 2^(31\-1 (0x7fffffff), or about 2.147 billion rows and columns. +For safety, libpng imposes a default limit of 1 million rows and columns. +Larger images will be rejected immediately with a png_error() call. If +you wish to change these limits, you can use + + png_set_user_limits(png_ptr, width_max, height_max); + +to set your own limits (libpng may reject some very wide images +anyway because of potential buffer overflow conditions). + +You should put this statement after you create the PNG structure and +before calling png_read_info(), png_read_png(), or png_process_data(). + +When writing a PNG datastream, put this statement before calling +png_write_info() or png_write_png(). + +If you need to retrieve the limits that are being applied, use + + width_max = png_get_user_width_max(png_ptr); + height_max = png_get_user_height_max(png_ptr); + +The PNG specification sets no limit on the number of ancillary chunks +allowed in a PNG datastream. By default, libpng imposes a limit of +a total of 1000 sPLT, tEXt, iTXt, zTXt, and unknown chunks to be stored. +If you have set up both info_ptr and end_info_ptr, the limit applies +separately to each. You can change the limit on the total number of such +chunks that will be stored, with + + png_set_chunk_cache_max(png_ptr, user_chunk_cache_max); + +where 0x7fffffffL means unlimited. You can retrieve this limit with + + chunk_cache_max = png_get_chunk_cache_max(png_ptr); + +Libpng imposes a limit of 8 Megabytes (8,000,000 bytes) on the amount of +memory that a compressed chunk other than IDAT can occupy, when decompressed. +You can change this limit with + + png_set_chunk_malloc_max(png_ptr, user_chunk_malloc_max); + +and you can retrieve the limit with + + chunk_malloc_max = png_get_chunk_malloc_max(png_ptr); + +Any chunks that would cause either of these limits to be exceeded will +be ignored. + +.SS Information about your system + +If you intend to display the PNG or to incorporate it in other image data you +need to tell libpng information about your display or drawing surface so that +libpng can convert the values in the image to match the display. + +From libpng-1.5.4 this information can be set before reading the PNG file +header. In earlier versions png_set_gamma() existed but behaved incorrectly if +called before the PNG file header had been read and png_set_alpha_mode() did not +exist. + +If you need to support versions prior to libpng-1.5.4 test the version number +as illustrated below using "PNG_LIBPNG_VER >= 10504" and follow the procedures +described in the appropriate manual page. + +You give libpng the encoding expected by your system expressed as a 'gamma' +value. You can also specify a default encoding for the PNG file in +case the required information is missing from the file. By default libpng +assumes that the PNG data matches your system, to keep this default call: + + png_set_gamma(png_ptr, screen_gamma, output_gamma); + +or you can use the fixed point equivalent: + + png_set_gamma_fixed(png_ptr, PNG_FP_1*screen_gamma, + PNG_FP_1*output_gamma); + +If you don't know the gamma for your system it is probably 2.2 - a good +approximation to the IEC standard for display systems (sRGB). If images are +too contrasty or washed out you got the value wrong - check your system +documentation! + +Many systems permit the system gamma to be changed via a lookup table in the +display driver, a few systems, including older Macs, change the response by +default. As of 1.5.4 three special values are available to handle common +situations: + + PNG_DEFAULT_sRGB: Indicates that the system conforms to the + IEC 61966-2-1 standard. This matches almost + all systems. + PNG_GAMMA_MAC_18: Indicates that the system is an older + (pre Mac OS 10.6) Apple Macintosh system with + the default settings. + PNG_GAMMA_LINEAR: Just the fixed point value for 1.0 - indicates + that the system expects data with no gamma + encoding. + +You would use the linear (unencoded) value if you need to process the pixel +values further because this avoids the need to decode and re-encode each +component value whenever arithmetic is performed. A lot of graphics software +uses linear values for this reason, often with higher precision component values +to preserve overall accuracy. + + +The output_gamma value expresses how to decode the output values, not how +they are encoded. The values used correspond to the normal numbers used to +describe the overall gamma of a computer display system; for example 2.2 for +an sRGB conformant system. The values are scaled by 100000 in the _fixed +version of the API (so 220000 for sRGB.) + +The inverse of the value is always used to provide a default for the PNG file +encoding if it has no gAMA chunk and if png_set_gamma() has not been called +to override the PNG gamma information. + +When the ALPHA_OPTIMIZED mode is selected the output gamma is used to encode +opaque pixels however pixels with lower alpha values are not encoded, +regardless of the output gamma setting. + +When the standard Porter Duff handling is requested with mode 1 the output +encoding is set to be linear and the output_gamma value is only relevant +as a default for input data that has no gamma information. The linear output +encoding will be overridden if png_set_gamma() is called - the results may be +highly unexpected! + +The following numbers are derived from the sRGB standard and the research +behind it. sRGB is defined to be approximated by a PNG gAMA chunk value of +0.45455 (1/2.2) for PNG. The value implicitly includes any viewing +correction required to take account of any differences in the color +environment of the original scene and the intended display environment; the +value expresses how to *decode* the image for display, not how the original +data was *encoded*. + +sRGB provides a peg for the PNG standard by defining a viewing environment. +sRGB itself, and earlier TV standards, actually use a more complex transform +(a linear portion then a gamma 2.4 power law) than PNG can express. (PNG is +limited to simple power laws.) By saying that an image for direct display on +an sRGB conformant system should be stored with a gAMA chunk value of 45455 +(11.3.3.2 and 11.3.3.5 of the ISO PNG specification) the PNG specification +makes it possible to derive values for other display systems and +environments. + +The Mac value is deduced from the sRGB based on an assumption that the actual +extra viewing correction used in early Mac display systems was implemented as +a power 1.45 lookup table. + +Any system where a programmable lookup table is used or where the behavior of +the final display device characteristics can be changed requires system +specific code to obtain the current characteristic. However this can be +difficult and most PNG gamma correction only requires an approximate value. + +By default, if png_set_alpha_mode() is not called, libpng assumes that all +values are unencoded, linear, values and that the output device also has a +linear characteristic. This is only very rarely correct - it is invariably +better to call png_set_alpha_mode() with PNG_DEFAULT_sRGB than rely on the +default if you don't know what the right answer is! + +The special value PNG_GAMMA_MAC_18 indicates an older Mac system (pre Mac OS +10.6) which used a correction table to implement a somewhat lower gamma on an +otherwise sRGB system. + +Both these values are reserved (not simple gamma values) in order to allow +more precise correction internally in the future. + +NOTE: the values can be passed to either the fixed or floating +point APIs, but the floating point API will also accept floating point +values. + +The second thing you may need to tell libpng about is how your system handles +alpha channel information. Some, but not all, PNG files contain an alpha +channel. To display these files correctly you need to compose the data onto a +suitable background, as described in the PNG specification. + +Libpng only supports composing onto a single color (using png_set_background; +see below). Otherwise you must do the composition yourself and, in this case, +you may need to call png_set_alpha_mode: + + #if PNG_LIBPNG_VER >= 10504 + png_set_alpha_mode(png_ptr, mode, screen_gamma); + #else + png_set_gamma(png_ptr, screen_gamma, 1.0/screen_gamma); + #endif + +The screen_gamma value is the same as the argument to png_set_gamma; however, +how it affects the output depends on the mode. png_set_alpha_mode() sets the +file gamma default to 1/screen_gamma, so normally you don't need to call +png_set_gamma. If you need different defaults call png_set_gamma() before +png_set_alpha_mode() - if you call it after it will override the settings made +by png_set_alpha_mode(). + +The mode is as follows: + + PNG_ALPHA_PNG: The data is encoded according to the PNG +specification. Red, green and blue, or gray, components are +gamma encoded color values and are not premultiplied by the +alpha value. The alpha value is a linear measure of the +contribution of the pixel to the corresponding final output pixel. + +You should normally use this format if you intend to perform +color correction on the color values; most, maybe all, color +correction software has no handling for the alpha channel and, +anyway, the math to handle pre-multiplied component values is +unnecessarily complex. + +Before you do any arithmetic on the component values you need +to remove the gamma encoding and multiply out the alpha +channel. See the PNG specification for more detail. It is +important to note that when an image with an alpha channel is +scaled, linear encoded, pre-multiplied component values must +be used! + +The remaining modes assume you don't need to do any further color correction or +that if you do, your color correction software knows all about alpha (it +probably doesn't!). They 'associate' the alpha with the color information by +storing color channel values that have been scaled by the alpha. The +advantage is that the color channels can be resampled (the image can be +scaled) in this form. The disadvantage is that normal practice is to store +linear, not (gamma) encoded, values and this requires 16-bit channels for +still images rather than the 8-bit channels that are just about sufficient if +gamma encoding is used. In addition all non-transparent pixel values, +including completely opaque ones, must be gamma encoded to produce the final +image. These are the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' modes +described below (the latter being the two common names for associated alpha +color channels). Note that PNG files always contain non-associated color +channels; png_set_alpha_mode() with one of the modes causes the decoder to +convert the pixels to an associated form before returning them to your +application. + +Since it is not necessary to perform arithmetic on opaque color values so +long as they are not to be resampled and are in the final color space it is +possible to optimize the handling of alpha by storing the opaque pixels in +the PNG format (adjusted for the output color space) while storing partially +opaque pixels in the standard, linear, format. The accuracy required for +standard alpha composition is relatively low, because the pixels are +isolated, therefore typically the accuracy loss in storing 8-bit linear +values is acceptable. (This is not true if the alpha channel is used to +simulate transparency over large areas - use 16 bits or the PNG mode in +this case!) This is the 'OPTIMIZED' mode. For this mode a pixel is +treated as opaque only if the alpha value is equal to the maximum value. + + PNG_ALPHA_STANDARD: The data libpng produces is encoded in the +standard way assumed by most correctly written graphics software. +The gamma encoding will be removed by libpng and the +linear component values will be pre-multiplied by the +alpha channel. + +With this format the final image must be re-encoded to +match the display gamma before the image is displayed. +If your system doesn't do that, yet still seems to +perform arithmetic on the pixels without decoding them, +it is broken - check out the modes below. + +With PNG_ALPHA_STANDARD libpng always produces linear +component values, whatever screen_gamma you supply. The +screen_gamma value is, however, used as a default for +the file gamma if the PNG file has no gamma information. + +If you call png_set_gamma() after png_set_alpha_mode() you +will override the linear encoding. Instead the +pre-multiplied pixel values will be gamma encoded but +the alpha channel will still be linear. This may +actually match the requirements of some broken software, +but it is unlikely. + +While linear 8-bit data is often used it has +insufficient precision for any image with a reasonable +dynamic range. To avoid problems, and if your software +supports it, use png_set_expand_16() to force all +components to 16 bits. + + PNG_ALPHA_OPTIMIZED: This mode is the same as PNG_ALPHA_STANDARD +except that completely opaque pixels are gamma encoded according to +the screen_gamma value. Pixels with alpha less than 1.0 +will still have linear components. + +Use this format if you have control over your +compositing software and so don't do other arithmetic +(such as scaling) on the data you get from libpng. Your +compositing software can simply copy opaque pixels to +the output but still has linear values for the +non-opaque pixels. + +In normal compositing, where the alpha channel encodes +partial pixel coverage (as opposed to broad area +translucency), the inaccuracies of the 8-bit +representation of non-opaque pixels are irrelevant. + +You can also try this format if your software is broken; +it might look better. + + PNG_ALPHA_BROKEN: This is PNG_ALPHA_STANDARD; however, all component +values, including the alpha channel are gamma encoded. This is +broken because, in practice, no implementation that uses this choice +correctly undoes the encoding before handling alpha composition. Use this +choice only if other serious errors in the software or hardware you use +mandate it. In most cases of broken software or hardware the bug in the +final display manifests as a subtle halo around composited parts of the +image. You may not even perceive this as a halo; the composited part of +the image may simply appear separate from the background, as though it had +been cut out of paper and pasted on afterward. + +If you don't have to deal with bugs in software or hardware, or if you can fix +them, there are three recommended ways of using png_set_alpha_mode(): + + png_set_alpha_mode(png_ptr, PNG_ALPHA_PNG, + screen_gamma); + +You can do color correction on the result (libpng does not currently +support color correction internally). When you handle the alpha channel +you need to undo the gamma encoding and multiply out the alpha. + + png_set_alpha_mode(png_ptr, PNG_ALPHA_STANDARD, + screen_gamma); + png_set_expand_16(png_ptr); + +If you are using the high level interface, don't call png_set_expand_16(); +instead pass PNG_TRANSFORM_EXPAND_16 to the interface. + +With this mode you can't do color correction, but you can do arithmetic, +including composition and scaling, on the data without further processing. + + png_set_alpha_mode(png_ptr, PNG_ALPHA_OPTIMIZED, + screen_gamma); + +You can avoid the expansion to 16-bit components with this mode, but you +lose the ability to scale the image or perform other linear arithmetic. +All you can do is compose the result onto a matching output. Since this +mode is libpng-specific you also need to write your own composition +software. + +The following are examples of calls to png_set_alpha_mode to achieve the +required overall gamma correction and, where necessary, alpha +premultiplication. + + png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + +This is the default libpng handling of the alpha channel - it is not +pre-multiplied into the color components. In addition the call states +that the output is for a sRGB system and causes all PNG files without gAMA +chunks to be assumed to be encoded using sRGB. + + png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + +In this case the output is assumed to be something like an sRGB conformant +display preceeded by a power-law lookup table of power 1.45. This is how +early Mac systems behaved. + + png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR); + +This is the classic Jim Blinn approach and will work in academic +environments where everything is done by the book. It has the shortcoming +of assuming that input PNG data with no gamma information is linear - this +is unlikely to be correct unless the PNG files where generated locally. +Most of the time the output precision will be so low as to show +significant banding in dark areas of the image. + + png_set_expand_16(pp); + png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_DEFAULT_sRGB); + +This is a somewhat more realistic Jim Blinn inspired approach. PNG files +are assumed to have the sRGB encoding if not marked with a gamma value and +the output is always 16 bits per component. This permits accurate scaling +and processing of the data. If you know that your input PNG files were +generated locally you might need to replace PNG_DEFAULT_sRGB with the +correct value for your system. + + png_set_alpha_mode(pp, PNG_ALPHA_OPTIMIZED, PNG_DEFAULT_sRGB); + +If you just need to composite the PNG image onto an existing background +and if you control the code that does this you can use the optimization +setting. In this case you just copy completely opaque pixels to the +output. For pixels that are not completely transparent (you just skip +those) you do the composition math using png_composite or png_composite_16 +below then encode the resultant 8-bit or 16-bit values to match the output +encoding. + + Other cases + +If neither the PNG nor the standard linear encoding work for you because +of the software or hardware you use then you have a big problem. The PNG +case will probably result in halos around the image. The linear encoding +will probably result in a washed out, too bright, image (it's actually too +contrasty.) Try the ALPHA_OPTIMIZED mode above - this will probably +substantially reduce the halos. Alternatively try: + + png_set_alpha_mode(pp, PNG_ALPHA_BROKEN, PNG_DEFAULT_sRGB); + +This option will also reduce the halos, but there will be slight dark +halos round the opaque parts of the image where the background is light. +In the OPTIMIZED mode the halos will be light halos where the background +is dark. Take your pick - the halos are unavoidable unless you can get +your hardware/software fixed! (The OPTIMIZED approach is slightly +faster.) + +When the default gamma of PNG files doesn't match the output gamma. +If you have PNG files with no gamma information png_set_alpha_mode allows +you to provide a default gamma, but it also sets the ouput gamma to the +matching value. If you know your PNG files have a gamma that doesn't +match the output you can take advantage of the fact that +png_set_alpha_mode always sets the output gamma but only sets the PNG +default if it is not already set: + + png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + +The first call sets both the default and the output gamma values, the +second call overrides the output gamma without changing the default. This +is easier than achieving the same effect with png_set_gamma. You must use +PNG_ALPHA_PNG for the first call - internal checking in png_set_alpha will +fire if more than one call to png_set_alpha_mode and png_set_background is +made in the same read operation, however multiple calls with PNG_ALPHA_PNG +are ignored. + +If you don't need, or can't handle, the alpha channel you can call +png_set_background() to remove it by compositing against a fixed color. Don't +call png_set_strip_alpha() to do this - it will leave spurious pixel values in +transparent parts of this image. + + png_set_background(png_ptr, &background_color, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1); + +The background_color is an RGB or grayscale value according to the data format +libpng will produce for you. Because you don't yet know the format of the PNG +file, if you call png_set_background at this point you must arrange for the +format produced by libpng to always have 8-bit or 16-bit components and then +store the color as an 8-bit or 16-bit color as appropriate. The color contains +separate gray and RGB component values, so you can let libpng produce gray or +RGB output according to the input format, but low bit depth grayscale images +must always be converted to at least 8-bit format. (Even though low bit depth +grayscale images can't have an alpha channel they can have a transparent +color!) + +You set the transforms you need later, either as flags to the high level +interface or libpng API calls for the low level interface. For reference the +settings and API calls required are: + +8-bit values: + PNG_TRANSFORM_SCALE_16 | PNG_EXPAND + png_set_expand(png_ptr); png_set_scale_16(png_ptr); + + If you must get exactly the same inaccurate results + produced by default in versions prior to libpng-1.5.4, + use PNG_TRANSFORM_STRIP_16 and png_set_strip_16(png_ptr) + instead. + +16-bit values: + PNG_TRANSFORM_EXPAND_16 + png_set_expand_16(png_ptr); + +In either case palette image data will be expanded to RGB. If you just want +color data you can add PNG_TRANSFORM_GRAY_TO_RGB or png_set_gray_to_rgb(png_ptr) +to the list. + +Calling png_set_background before the PNG file header is read will not work +prior to libpng-1.5.4. Because the failure may result in unexpected warnings or +errors it is therefore much safer to call png_set_background after the head has +been read. Unfortunately this means that prior to libpng-1.5.4 it cannot be +used with the high level interface. + +.SS The high-level read interface + +At this point there are two ways to proceed; through the high-level +read interface, or through a sequence of low-level read operations. +You can use the high-level interface if (a) you are willing to read +the entire image into memory, and (b) the input transformations +you want to do are limited to the following set: + + PNG_TRANSFORM_IDENTITY No transformation + PNG_TRANSFORM_SCALE_16 Strip 16-bit samples to + 8-bit accurately + PNG_TRANSFORM_STRIP_16 Chop 16-bit samples to + 8-bit less accurately + PNG_TRANSFORM_STRIP_ALPHA Discard the alpha channel + PNG_TRANSFORM_PACKING Expand 1, 2 and 4-bit + samples to bytes + PNG_TRANSFORM_PACKSWAP Change order of packed + pixels to LSB first + PNG_TRANSFORM_EXPAND Perform set_expand() + PNG_TRANSFORM_INVERT_MONO Invert monochrome images + PNG_TRANSFORM_SHIFT Normalize pixels to the + sBIT depth + PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA + to BGRA + PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA + to AG + PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity + to transparency + PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples + PNG_TRANSFORM_GRAY_TO_RGB Expand grayscale samples + to RGB (or GA to RGBA) + PNG_TRANSFORM_EXPAND_16 Expand samples to 16 bits + +(This excludes setting a background color, doing gamma transformation, +quantizing, and setting filler.) If this is the case, simply do this: + + png_read_png(png_ptr, info_ptr, png_transforms, NULL) + +where png_transforms is an integer containing the bitwise OR of some +set of transformation flags. This call is equivalent to png_read_info(), +followed the set of transformations indicated by the transform mask, +then png_read_image(), and finally png_read_end(). + +(The final parameter of this call is not yet used. Someday it might point +to transformation parameters required by some future input transform.) + +You must use png_transforms and not call any png_set_transform() functions +when you use png_read_png(). + +After you have called png_read_png(), you can retrieve the image data +with + + row_pointers = png_get_rows(png_ptr, info_ptr); + +where row_pointers is an array of pointers to the pixel data for each row: + + png_bytep row_pointers[height]; + +If you know your image size and pixel size ahead of time, you can allocate +row_pointers prior to calling png_read_png() with + + if (height > PNG_UINT_32_MAX/(sizeof (png_byte))) + png_error (png_ptr, + "Image is too tall to process in memory"); + + if (width > PNG_UINT_32_MAX/pixel_size) + png_error (png_ptr, + "Image is too wide to process in memory"); + + row_pointers = png_malloc(png_ptr, + height*(sizeof (png_bytep))); + + for (int i=0; i) and +png_get_(png_ptr, info_ptr, ...) functions return non-zero if the +data has been read, or zero if it is missing. The parameters to the +png_get_ are set directly if they are simple data types, or a +pointer into the info_ptr is returned for any complex types. + +The colorspace data from gAMA, cHRM, sRGB, iCCP, and sBIT chunks +is simply returned to give the application information about how the +image was encoded. Libpng itself only does transformations using the file +gamma when combining semitransparent pixels with the background color, and, +since libpng-1.6.0, when converting between 8-bit sRGB and 16-bit linear pixels +within the simplified API. Libpng also uses the file gamma when converting +RGB to gray, beginning with libpng-1.0.5, if the application calls +png_set_rgb_to_gray()). + + png_get_PLTE(png_ptr, info_ptr, &palette, + &num_palette); + + palette - the palette for the file + (array of png_color) + + num_palette - number of entries in the palette + + png_get_gAMA(png_ptr, info_ptr, &file_gamma); + png_get_gAMA_fixed(png_ptr, info_ptr, &int_file_gamma); + + file_gamma - the gamma at which the file is + written (PNG_INFO_gAMA) + + int_file_gamma - 100,000 times the gamma at which the + file is written + + png_get_cHRM(png_ptr, info_ptr, &white_x, &white_y, &red_x, + &red_y, &green_x, &green_y, &blue_x, &blue_y) + png_get_cHRM_XYZ(png_ptr, info_ptr, &red_X, &red_Y, &red_Z, + &green_X, &green_Y, &green_Z, &blue_X, &blue_Y, + &blue_Z) + png_get_cHRM_fixed(png_ptr, info_ptr, &int_white_x, + &int_white_y, &int_red_x, &int_red_y, + &int_green_x, &int_green_y, &int_blue_x, + &int_blue_y) + png_get_cHRM_XYZ_fixed(png_ptr, info_ptr, &int_red_X, &int_red_Y, + &int_red_Z, &int_green_X, &int_green_Y, + &int_green_Z, &int_blue_X, &int_blue_Y, + &int_blue_Z) + + {white,red,green,blue}_{x,y} + A color space encoding specified using the + chromaticities of the end points and the + white point. (PNG_INFO_cHRM) + + {red,green,blue}_{X,Y,Z} + A color space encoding specified using the + encoding end points - the CIE tristimulus + specification of the intended color of the red, + green and blue channels in the PNG RGB data. + The white point is simply the sum of the three + end points. (PNG_INFO_cHRM) + + png_get_sRGB(png_ptr, info_ptr, &srgb_intent); + + srgb_intent - the rendering intent (PNG_INFO_sRGB) + The presence of the sRGB chunk + means that the pixel data is in the + sRGB color space. This chunk also + implies specific values of gAMA and + cHRM. + + png_get_iCCP(png_ptr, info_ptr, &name, + &compression_type, &profile, &proflen); + + name - The profile name. + + compression_type - The compression type; always + PNG_COMPRESSION_TYPE_BASE for PNG 1.0. + You may give NULL to this argument to + ignore it. + + profile - International Color Consortium color + profile data. May contain NULs. + + proflen - length of profile data in bytes. + + png_get_sBIT(png_ptr, info_ptr, &sig_bit); + + sig_bit - the number of significant bits for + (PNG_INFO_sBIT) each of the gray, + red, green, and blue channels, + whichever are appropriate for the + given color type (png_color_16) + + png_get_tRNS(png_ptr, info_ptr, &trans_alpha, + &num_trans, &trans_color); + + trans_alpha - array of alpha (transparency) + entries for palette (PNG_INFO_tRNS) + + num_trans - number of transparent entries + (PNG_INFO_tRNS) + + trans_color - graylevel or color sample values of + the single transparent color for + non-paletted images (PNG_INFO_tRNS) + + png_get_hIST(png_ptr, info_ptr, &hist); + (PNG_INFO_hIST) + + hist - histogram of palette (array of + png_uint_16) + + png_get_tIME(png_ptr, info_ptr, &mod_time); + + mod_time - time image was last modified + (PNG_VALID_tIME) + + png_get_bKGD(png_ptr, info_ptr, &background); + + background - background color (of type + png_color_16p) (PNG_VALID_bKGD) + valid 16-bit red, green and blue + values, regardless of color_type + + num_comments = png_get_text(png_ptr, info_ptr, + &text_ptr, &num_text); + + num_comments - number of comments + + text_ptr - array of png_text holding image + comments + + text_ptr[i].compression - type of compression used + on "text" PNG_TEXT_COMPRESSION_NONE + PNG_TEXT_COMPRESSION_zTXt + PNG_ITXT_COMPRESSION_NONE + PNG_ITXT_COMPRESSION_zTXt + + text_ptr[i].key - keyword for comment. Must contain + 1-79 characters. + + text_ptr[i].text - text comments for current + keyword. Can be empty. + + text_ptr[i].text_length - length of text string, + after decompression, 0 for iTXt + + text_ptr[i].itxt_length - length of itxt string, + after decompression, 0 for tEXt/zTXt + + text_ptr[i].lang - language of comment (empty + string for unknown). + + text_ptr[i].lang_key - keyword in UTF-8 + (empty string for unknown). + + Note that the itxt_length, lang, and lang_key + members of the text_ptr structure only exist when the + library is built with iTXt chunk support. Prior to + libpng-1.4.0 the library was built by default without + iTXt support. Also note that when iTXt is supported, + they contain NULL pointers when the "compression" + field contains PNG_TEXT_COMPRESSION_NONE or + PNG_TEXT_COMPRESSION_zTXt. + + num_text - number of comments (same as + num_comments; you can put NULL here + to avoid the duplication) + + Note while png_set_text() will accept text, language, + and translated keywords that can be NULL pointers, the + structure returned by png_get_text will always contain + regular zero-terminated C strings. They might be + empty strings but they will never be NULL pointers. + + num_spalettes = png_get_sPLT(png_ptr, info_ptr, + &palette_ptr); + + num_spalettes - number of sPLT chunks read. + + palette_ptr - array of palette structures holding + contents of one or more sPLT chunks + read. + + png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, + &unit_type); + + offset_x - positive offset from the left edge + of the screen (can be negative) + + offset_y - positive offset from the top edge + of the screen (can be negative) + + unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER + + png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, + &unit_type); + + res_x - pixels/unit physical resolution in + x direction + + res_y - pixels/unit physical resolution in + x direction + + unit_type - PNG_RESOLUTION_UNKNOWN, + PNG_RESOLUTION_METER + + png_get_sCAL(png_ptr, info_ptr, &unit, &width, + &height) + + unit - physical scale units (an integer) + + width - width of a pixel in physical scale units + + height - height of a pixel in physical scale units + (width and height are doubles) + + png_get_sCAL_s(png_ptr, info_ptr, &unit, &width, + &height) + + unit - physical scale units (an integer) + + width - width of a pixel in physical scale units + (expressed as a string) + + height - height of a pixel in physical scale units + (width and height are strings like "2.54") + + num_unknown_chunks = png_get_unknown_chunks(png_ptr, + info_ptr, &unknowns) + + unknowns - array of png_unknown_chunk + structures holding unknown chunks + + unknowns[i].name - name of unknown chunk + + unknowns[i].data - data of unknown chunk + + unknowns[i].size - size of unknown chunk's data + + unknowns[i].location - position of chunk in file + + The value of "i" corresponds to the order in which the + chunks were read from the PNG file or inserted with the + png_set_unknown_chunks() function. + + The value of "location" is a bitwise "or" of + + PNG_HAVE_IHDR (0x01) + PNG_HAVE_PLTE (0x02) + PNG_AFTER_IDAT (0x08) + +The data from the pHYs chunk can be retrieved in several convenient +forms: + + res_x = png_get_x_pixels_per_meter(png_ptr, + info_ptr) + + res_y = png_get_y_pixels_per_meter(png_ptr, + info_ptr) + + res_x_and_y = png_get_pixels_per_meter(png_ptr, + info_ptr) + + res_x = png_get_x_pixels_per_inch(png_ptr, + info_ptr) + + res_y = png_get_y_pixels_per_inch(png_ptr, + info_ptr) + + res_x_and_y = png_get_pixels_per_inch(png_ptr, + info_ptr) + + aspect_ratio = png_get_pixel_aspect_ratio(png_ptr, + info_ptr) + + Each of these returns 0 [signifying "unknown"] if + the data is not present or if res_x is 0; + res_x_and_y is 0 if res_x != res_y + + Note that because of the way the resolutions are + stored internally, the inch conversions won't + come out to exactly even number. For example, + 72 dpi is stored as 0.28346 pixels/meter, and + when this is retrieved it is 71.9988 dpi, so + be sure to round the returned value appropriately + if you want to display a reasonable-looking result. + +The data from the oFFs chunk can be retrieved in several convenient +forms: + + x_offset = png_get_x_offset_microns(png_ptr, info_ptr); + + y_offset = png_get_y_offset_microns(png_ptr, info_ptr); + + x_offset = png_get_x_offset_inches(png_ptr, info_ptr); + + y_offset = png_get_y_offset_inches(png_ptr, info_ptr); + + Each of these returns 0 [signifying "unknown" if both + x and y are 0] if the data is not present or if the + chunk is present but the unit is the pixel. The + remark about inexact inch conversions applies here + as well, because a value in inches can't always be + converted to microns and back without some loss + of precision. + +For more information, see the +PNG specification for chunk contents. Be careful with trusting +rowbytes, as some of the transformations could increase the space +needed to hold a row (expand, filler, gray_to_rgb, etc.). +See png_read_update_info(), below. + +A quick word about text_ptr and num_text. PNG stores comments in +keyword/text pairs, one pair per chunk, with no limit on the number +of text chunks, and a 2^31 byte limit on their size. While there are +suggested keywords, there is no requirement to restrict the use to these +strings. It is strongly suggested that keywords and text be sensible +to humans (that's the point), so don't use abbreviations. Non-printing +symbols are not allowed. See the PNG specification for more details. +There is also no requirement to have text after the keyword. + +Keywords should be limited to 79 Latin-1 characters without leading or +trailing spaces, but non-consecutive spaces are allowed within the +keyword. It is possible to have the same keyword any number of times. +The text_ptr is an array of png_text structures, each holding a +pointer to a language string, a pointer to a keyword and a pointer to +a text string. The text string, language code, and translated +keyword may be empty or NULL pointers. The keyword/text +pairs are put into the array in the order that they are received. +However, some or all of the text chunks may be after the image, so, to +make sure you have read all the text chunks, don't mess with these +until after you read the stuff after the image. This will be +mentioned again below in the discussion that goes with png_read_end(). + +.SS Input transformations + +After you've read the header information, you can set up the library +to handle any special transformations of the image data. The various +ways to transform the data will be described in the order that they +should occur. This is important, as some of these change the color +type and/or bit depth of the data, and some others only work on +certain color types and bit depths. + +Transformations you request are ignored if they don't have any meaning for a +particular input data format. However some transformations can have an effect +as a result of a previous transformation. If you specify a contradictory set of +transformations, for example both adding and removing the alpha channel, you +cannot predict the final result. + +The color used for the transparency values should be supplied in the same +format/depth as the current image data. It is stored in the same format/depth +as the image data in a tRNS chunk, so this is what libpng expects for this data. + +The color used for the background value depends on the need_expand argument as +described below. + +Data will be decoded into the supplied row buffers packed into bytes +unless the library has been told to transform it into another format. +For example, 4 bit/pixel paletted or grayscale data will be returned +2 pixels/byte with the leftmost pixel in the high-order bits of the byte, +unless png_set_packing() is called. 8-bit RGB data will be stored +in RGB RGB RGB format unless png_set_filler() or png_set_add_alpha() +is called to insert filler bytes, either before or after each RGB triplet. + +16-bit RGB data will be returned RRGGBB RRGGBB, with the most significant +byte of the color value first, unless png_set_scale_16() is called to +transform it to regular RGB RGB triplets, or png_set_filler() or +png_set_add alpha() is called to insert two filler bytes, either before +or after each RRGGBB triplet. Similarly, 8-bit or 16-bit grayscale data can +be modified with png_set_filler(), png_set_add_alpha(), png_set_strip_16(), +or png_set_scale_16(). + +The following code transforms grayscale images of less than 8 to 8 bits, +changes paletted images to RGB, and adds a full alpha channel if there is +transparency information in a tRNS chunk. This is most useful on +grayscale images with bit depths of 2 or 4 or if there is a multiple-image +viewing application that wishes to treat all images in the same way. + + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + + if (png_get_valid(png_ptr, info_ptr, + PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); + + if (color_type == PNG_COLOR_TYPE_GRAY && + bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); + +The first two functions are actually aliases for png_set_expand(), added +in libpng version 1.0.4, with the function names expanded to improve code +readability. In some future version they may actually do different +things. + +As of libpng version 1.2.9, png_set_expand_gray_1_2_4_to_8() was +added. It expands the sample depth without changing tRNS to alpha. + +As of libpng version 1.5.2, png_set_expand_16() was added. It behaves as +png_set_expand(); however, the resultant channels have 16 bits rather than 8. +Use this when the output color or gray channels are made linear to avoid fairly +severe accuracy loss. + + if (bit_depth < 16) + png_set_expand_16(png_ptr); + +PNG can have files with 16 bits per channel. If you only can handle +8 bits per channel, this will strip the pixels down to 8-bit. + + if (bit_depth == 16) +#if PNG_LIBPNG_VER >= 10504 + png_set_scale_16(png_ptr); +#else + png_set_strip_16(png_ptr); +#endif + +(The more accurate "png_set_scale_16()" API became available in libpng version +1.5.4). + +If you need to process the alpha channel on the image separately from the image +data (for example if you convert it to a bitmap mask) it is possible to have +libpng strip the channel leaving just RGB or gray data: + + if (color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(png_ptr); + +If you strip the alpha channel you need to find some other way of dealing with +the information. If, instead, you want to convert the image to an opaque +version with no alpha channel use png_set_background; see below. + +As of libpng version 1.5.2, almost all useful expansions are supported, the +major ommissions are conversion of grayscale to indexed images (which can be +done trivially in the application) and conversion of indexed to grayscale (which +can be done by a trivial manipulation of the palette.) + +In the following table, the 01 means grayscale with depth<8, 31 means +indexed with depth<8, other numerals represent the color type, "T" means +the tRNS chunk is present, A means an alpha channel is present, and O +means tRNS or alpha is present but all pixels in the image are opaque. + + FROM 01 31 0 0T 0O 2 2T 2O 3 3T 3O 4A 4O 6A 6O + TO + 01 - [G] - - - - - - - - - - - - - + 31 [Q] Q [Q] [Q] [Q] Q Q Q Q Q Q [Q] [Q] Q Q + 0 1 G + . . G G G G G G B B GB GB + 0T lt Gt t + . Gt G G Gt G G Bt Bt GBt GBt + 0O lt Gt t . + Gt Gt G Gt Gt G Bt Bt GBt GBt + 2 C P C C C + . . C - - CB CB B B + 2T Ct - Ct C C t + t - - - CBt CBt Bt Bt + 2O Ct - Ct C C t t + - - - CBt CBt Bt Bt + 3 [Q] p [Q] [Q] [Q] Q Q Q + . . [Q] [Q] Q Q + 3T [Qt] p [Qt][Q] [Q] Qt Qt Qt t + t [Qt][Qt] Qt Qt + 3O [Qt] p [Qt][Q] [Q] Qt Qt Qt t t + [Qt][Qt] Qt Qt + 4A lA G A T T GA GT GT GA GT GT + BA G GBA + 4O lA GBA A T T GA GT GT GA GT GT BA + GBA G + 6A CA PA CA C C A T tT PA P P C CBA + BA + 6O CA PBA CA C C A tT T PA P P CBA C BA + + +Within the matrix, + "+" identifies entries where 'from' and 'to' are the same. + "-" means the transformation is not supported. + "." means nothing is necessary (a tRNS chunk can just be ignored). + "t" means the transformation is obtained by png_set_tRNS. + "A" means the transformation is obtained by png_set_add_alpha(). + "X" means the transformation is obtained by png_set_expand(). + "1" means the transformation is obtained by + png_set_expand_gray_1_2_4_to_8() (and by png_set_expand() + if there is no transparency in the original or the final + format). + "C" means the transformation is obtained by png_set_gray_to_rgb(). + "G" means the transformation is obtained by png_set_rgb_to_gray(). + "P" means the transformation is obtained by + png_set_expand_palette_to_rgb(). + "p" means the transformation is obtained by png_set_packing(). + "Q" means the transformation is obtained by png_set_quantize(). + "T" means the transformation is obtained by + png_set_tRNS_to_alpha(). + "B" means the transformation is obtained by + png_set_background(), or png_strip_alpha(). + +When an entry has multiple transforms listed all are required to cause the +right overall transformation. When two transforms are separated by a comma +either will do the job. When transforms are enclosed in [] the transform should +do the job but this is currently unimplemented - a different format will result +if the suggested transformations are used. + +In PNG files, the alpha channel in an image +is the level of opacity. If you need the alpha channel in an image to +be the level of transparency instead of opacity, you can invert the +alpha channel (or the tRNS chunk data) after it's read, so that 0 is +fully opaque and 255 (in 8-bit or paletted images) or 65535 (in 16-bit +images) is fully transparent, with + + png_set_invert_alpha(png_ptr); + +PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as +they can, resulting in, for example, 8 pixels per byte for 1 bit +files. This code expands to 1 pixel per byte without changing the +values of the pixels: + + if (bit_depth < 8) + png_set_packing(png_ptr); + +PNG files have possible bit depths of 1, 2, 4, 8, and 16. All pixels +stored in a PNG image have been "scaled" or "shifted" up to the next +higher possible bit depth (e.g. from 5 bits/sample in the range [0,31] +to 8 bits/sample in the range [0, 255]). However, it is also possible +to convert the PNG pixel data back to the original bit depth of the +image. This call reduces the pixels back down to the original bit depth: + + png_color_8p sig_bit; + + if (png_get_sBIT(png_ptr, info_ptr, &sig_bit)) + png_set_shift(png_ptr, sig_bit); + +PNG files store 3-color pixels in red, green, blue order. This code +changes the storage of the pixels to blue, green, red: + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_bgr(png_ptr); + +PNG files store RGB pixels packed into 3 or 6 bytes. This code expands them +into 4 or 8 bytes for windowing systems that need them in this format: + + if (color_type == PNG_COLOR_TYPE_RGB) + png_set_filler(png_ptr, filler, PNG_FILLER_BEFORE); + +where "filler" is the 8-bit or 16-bit number to fill with, and the location +is either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether +you want the filler before the RGB or after. When filling an 8-bit pixel, +the least significant 8 bits of the number are used, if a 16-bit number is +supplied. This transformation does not affect images that already have full +alpha channels. To add an opaque alpha channel, use filler=0xffff and +PNG_FILLER_AFTER which will generate RGBA pixels. + +Note that png_set_filler() does not change the color type. If you want +to do that, you can add a true alpha channel with + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_GRAY) + png_set_add_alpha(png_ptr, filler, PNG_FILLER_AFTER); + +where "filler" contains the alpha value to assign to each pixel. +The png_set_add_alpha() function was added in libpng-1.2.7. + +If you are reading an image with an alpha channel, and you need the +data as ARGB instead of the normal PNG format RGBA: + + if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_swap_alpha(png_ptr); + +For some uses, you may want a grayscale image to be represented as +RGB. This code will do that conversion: + + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + +Conversely, you can convert an RGB or RGBA image to grayscale or grayscale +with alpha. + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_rgb_to_gray(png_ptr, error_action, + double red_weight, double green_weight); + + error_action = 1: silently do the conversion + + error_action = 2: issue a warning if the original + image has any pixel where + red != green or red != blue + + error_action = 3: issue an error and abort the + conversion if the original + image has any pixel where + red != green or red != blue + + red_weight: weight of red component + + green_weight: weight of green component + If either weight is negative, default + weights are used. + +In the corresponding fixed point API the red_weight and green_weight values are +simply scaled by 100,000: + + png_set_rgb_to_gray(png_ptr, error_action, + png_fixed_point red_weight, + png_fixed_point green_weight); + +If you have set error_action = 1 or 2, you can +later check whether the image really was gray, after processing +the image rows, with the png_get_rgb_to_gray_status(png_ptr) function. +It will return a png_byte that is zero if the image was gray or +1 if there were any non-gray pixels. Background and sBIT data +will be silently converted to grayscale, using the green channel +data for sBIT, regardless of the error_action setting. + +The default values come from the PNG file cHRM chunk if present; otherwise, the +defaults correspond to the ITU-R recommendation 709, and also the sRGB color +space, as recommended in the Charles Poynton's Colour FAQ, +Copyright (c) 2006-11-28 Charles Poynton, in section 9: + + + + Y = 0.2126 * R + 0.7152 * G + 0.0722 * B + +Previous versions of this document, 1998 through 2002, recommended a slightly +different formula: + + Y = 0.212671 * R + 0.715160 * G + 0.072169 * B + +Libpng uses an integer approximation: + + Y = (6968 * R + 23434 * G + 2366 * B)/32768 + +The calculation is done in a linear colorspace, if the image gamma +can be determined. + +The png_set_background() function has been described already; it tells libpng to +composite images with alpha or simple transparency against the supplied +background color. For compatibility with versions of libpng earlier than +libpng-1.5.4 it is recommended that you call the function after reading the file +header, even if you don't want to use the color in a bKGD chunk, if one exists. + +If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid), +you may use this color, or supply another color more suitable for +the current display (e.g., the background color from a web page). You +need to tell libpng how the color is represented, both the format of the +component values in the color (the number of bits) and the gamma encoding of the +color. The function takes two arguments, background_gamma_mode and need_expand +to convey this information; however, only two combinations are likely to be +useful: + + png_color_16 my_background; + png_color_16p image_background; + + if (png_get_bKGD(png_ptr, info_ptr, &image_background)) + png_set_background(png_ptr, image_background, + PNG_BACKGROUND_GAMMA_FILE, 1/*needs to be expanded*/, 1); + else + png_set_background(png_ptr, &my_background, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*do not expand*/, 1); + +The second call was described above - my_background is in the format of the +final, display, output produced by libpng. Because you now know the format of +the PNG it is possible to avoid the need to choose either 8-bit or 16-bit +output and to retain palette images (the palette colors will be modified +appropriately and the tRNS chunk removed.) However, if you are doing this, +take great care not to ask for transformations without checking first that +they apply! + +In the first call the background color has the original bit depth and color type +of the PNG file. So, for palette images the color is supplied as a palette +index and for low bit greyscale images the color is a reduced bit value in +image_background->gray. + +If you didn't call png_set_gamma() before reading the file header, for example +if you need your code to remain compatible with older versions of libpng prior +to libpng-1.5.4, this is the place to call it. + +Do not call it if you called png_set_alpha_mode(); doing so will damage the +settings put in place by png_set_alpha_mode(). (If png_set_alpha_mode() is +supported then you can certainly do png_set_gamma() before reading the PNG +header.) + +This API unconditionally sets the screen and file gamma values, so it will +override the value in the PNG file unless it is called before the PNG file +reading starts. For this reason you must always call it with the PNG file +value when you call it in this position: + + if (png_get_gAMA(png_ptr, info_ptr, &file_gamma)) + png_set_gamma(png_ptr, screen_gamma, file_gamma); + + else + png_set_gamma(png_ptr, screen_gamma, 0.45455); + +If you need to reduce an RGB file to a paletted file, or if a paletted +file has more entries than will fit on your screen, png_set_quantize() +will do that. Note that this is a simple match quantization that merely +finds the closest color available. This should work fairly well with +optimized palettes, but fairly badly with linear color cubes. If you +pass a palette that is larger than maximum_colors, the file will +reduce the number of colors in the palette so it will fit into +maximum_colors. If there is a histogram, libpng will use it to make +more intelligent choices when reducing the palette. If there is no +histogram, it may not do as good a job. + + if (color_type & PNG_COLOR_MASK_COLOR) + { + if (png_get_valid(png_ptr, info_ptr, + PNG_INFO_PLTE)) + { + png_uint_16p histogram = NULL; + + png_get_hIST(png_ptr, info_ptr, + &histogram); + png_set_quantize(png_ptr, palette, num_palette, + max_screen_colors, histogram, 1); + } + + else + { + png_color std_color_cube[MAX_SCREEN_COLORS] = + { ... colors ... }; + + png_set_quantize(png_ptr, std_color_cube, + MAX_SCREEN_COLORS, MAX_SCREEN_COLORS, + NULL,0); + } + } + +PNG files describe monochrome as black being zero and white being one. +The following code will reverse this (make black be one and white be +zero): + + if (bit_depth == 1 && color_type == PNG_COLOR_TYPE_GRAY) + png_set_invert_mono(png_ptr); + +This function can also be used to invert grayscale and gray-alpha images: + + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_invert_mono(png_ptr); + +PNG files store 16-bit pixels in network byte order (big-endian, +ie. most significant bits first). This code changes the storage to the +other way (little-endian, i.e. least significant bits first, the +way PCs store them): + + if (bit_depth == 16) + png_set_swap(png_ptr); + +If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you +need to change the order the pixels are packed into bytes, you can use: + + if (bit_depth < 8) + png_set_packswap(png_ptr); + +Finally, you can write your own transformation function if none of +the existing ones meets your needs. This is done by setting a callback +with + + png_set_read_user_transform_fn(png_ptr, + read_transform_fn); + +You must supply the function + + void read_transform_fn(png_structp png_ptr, png_row_infop + row_info, png_bytep data) + +See pngtest.c for a working example. Your function will be called +after all of the other transformations have been processed. Take care with +interlaced images if you do the interlace yourself - the width of the row is the +width in 'row_info', not the overall image width. + +If supported, libpng provides two information routines that you can use to find +where you are in processing the image: + + png_get_current_pass_number(png_structp png_ptr); + png_get_current_row_number(png_structp png_ptr); + +Don't try using these outside a transform callback - firstly they are only +supported if user transforms are supported, secondly they may well return +unexpected results unless the row is actually being processed at the moment they +are called. + +With interlaced +images the value returned is the row in the input sub-image image. Use +PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to +find the output pixel (x,y) given an interlaced sub-image pixel (row,col,pass). + +The discussion of interlace handling above contains more information on how to +use these values. + +You can also set up a pointer to a user structure for use by your +callback function, and you can inform libpng that your transform +function will change the number of channels or bit depth with the +function + + png_set_user_transform_info(png_ptr, user_ptr, + user_depth, user_channels); + +The user's application, not libpng, is responsible for allocating and +freeing any memory required for the user structure. + +You can retrieve the pointer via the function +png_get_user_transform_ptr(). For example: + + voidp read_user_transform_ptr = + png_get_user_transform_ptr(png_ptr); + +The last thing to handle is interlacing; this is covered in detail below, +but you must call the function here if you want libpng to handle expansion +of the interlaced image. + + number_of_passes = png_set_interlace_handling(png_ptr); + +After setting the transformations, libpng can update your png_info +structure to reflect any transformations you've requested with this +call. + + png_read_update_info(png_ptr, info_ptr); + +This is most useful to update the info structure's rowbytes +field so you can use it to allocate your image memory. This function +will also update your palette with the correct screen_gamma and +background if these have been given with the calls above. You may +only call png_read_update_info() once with a particular info_ptr. + +After you call png_read_update_info(), you can allocate any +memory you need to hold the image. The row data is simply +raw byte data for all forms of images. As the actual allocation +varies among applications, no example will be given. If you +are allocating one large chunk, you will need to build an +array of pointers to each row, as it will be needed for some +of the functions below. + +Remember: Before you call png_read_update_info(), the png_get_*() +functions return the values corresponding to the original PNG image. +After you call png_read_update_info the values refer to the image +that libpng will output. Consequently you must call all the png_set_ +functions before you call png_read_update_info(). This is particularly +important for png_set_interlace_handling() - if you are going to call +png_read_update_info() you must call png_set_interlace_handling() before +it unless you want to receive interlaced output. + +.SS Reading image data + +After you've allocated memory, you can read the image data. +The simplest way to do this is in one function call. If you are +allocating enough memory to hold the whole image, you can just +call png_read_image() and libpng will read in all the image data +and put it in the memory area supplied. You will need to pass in +an array of pointers to each row. + +This function automatically handles interlacing, so you don't +need to call png_set_interlace_handling() (unless you call +png_read_update_info()) or call this function multiple times, or any +of that other stuff necessary with png_read_rows(). + + png_read_image(png_ptr, row_pointers); + +where row_pointers is: + + png_bytep row_pointers[height]; + +You can point to void or char or whatever you use for pixels. + +If you don't want to read in the whole image at once, you can +use png_read_rows() instead. If there is no interlacing (check +interlace_type == PNG_INTERLACE_NONE), this is simple: + + png_read_rows(png_ptr, row_pointers, NULL, + number_of_rows); + +where row_pointers is the same as in the png_read_image() call. + +If you are doing this just one row at a time, you can do this with +a single row_pointer instead of an array of row_pointers: + + png_bytep row_pointer = row; + png_read_row(png_ptr, row_pointer, NULL); + +If the file is interlaced (interlace_type != 0 in the IHDR chunk), things +get somewhat harder. The only current (PNG Specification version 1.2) +interlacing type for PNG is (interlace_type == PNG_INTERLACE_ADAM7); +a somewhat complicated 2D interlace scheme, known as Adam7, that +breaks down an image into seven smaller images of varying size, based +on an 8x8 grid. This number is defined (from libpng 1.5) as +PNG_INTERLACE_ADAM7_PASSES in png.h + +libpng can fill out those images or it can give them to you "as is". +It is almost always better to have libpng handle the interlacing for you. +If you want the images filled out, there are two ways to do that. The one +mentioned in the PNG specification is to expand each pixel to cover +those pixels that have not been read yet (the "rectangle" method). +This results in a blocky image for the first pass, which gradually +smooths out as more pixels are read. The other method is the "sparkle" +method, where pixels are drawn only in their final locations, with the +rest of the image remaining whatever colors they were initialized to +before the start of the read. The first method usually looks better, +but tends to be slower, as there are more pixels to put in the rows. + +If, as is likely, you want libpng to expand the images, call this before +calling png_start_read_image() or png_read_update_info(): + + if (interlace_type == PNG_INTERLACE_ADAM7) + number_of_passes + = png_set_interlace_handling(png_ptr); + +This will return the number of passes needed. Currently, this is seven, +but may change if another interlace type is added. This function can be +called even if the file is not interlaced, where it will return one pass. +You then need to read the whole image 'number_of_passes' times. Each time +will distribute the pixels from the current pass to the correct place in +the output image, so you need to supply the same rows to png_read_rows in +each pass. + +If you are not going to display the image after each pass, but are +going to wait until the entire image is read in, use the sparkle +effect. This effect is faster and the end result of either method +is exactly the same. If you are planning on displaying the image +after each pass, the "rectangle" effect is generally considered the +better looking one. + +If you only want the "sparkle" effect, just call png_read_rows() as +normal, with the third parameter NULL. Make sure you make pass over +the image number_of_passes times, and you don't change the data in the +rows between calls. You can change the locations of the data, just +not the data. Each pass only writes the pixels appropriate for that +pass, and assumes the data from previous passes is still valid. + + png_read_rows(png_ptr, row_pointers, NULL, + number_of_rows); + +If you only want the first effect (the rectangles), do the same as +before except pass the row buffer in the third parameter, and leave +the second parameter NULL. + + png_read_rows(png_ptr, NULL, row_pointers, + number_of_rows); + +If you don't want libpng to handle the interlacing details, just call +png_read_rows() PNG_INTERLACE_ADAM7_PASSES times to read in all the images. +Each of the images is a valid image by itself; however, you will almost +certainly need to distribute the pixels from each sub-image to the +correct place. This is where everything gets very tricky. + +If you want to retrieve the separate images you must pass the correct +number of rows to each successive call of png_read_rows(). The calculation +gets pretty complicated for small images, where some sub-images may +not even exist because either their width or height ends up zero. +libpng provides two macros to help you in 1.5 and later versions: + + png_uint_32 width = PNG_PASS_COLS(image_width, pass_number); + png_uint_32 height = PNG_PASS_ROWS(image_height, pass_number); + +Respectively these tell you the width and height of the sub-image +corresponding to the numbered pass. 'pass' is in in the range 0 to 6 - +this can be confusing because the specification refers to the same passes +as 1 to 7! Be careful, you must check both the width and height before +calling png_read_rows() and not call it for that pass if either is zero. + +You can, of course, read each sub-image row by row. If you want to +produce optimal code to make a pixel-by-pixel transformation of an +interlaced image this is the best approach; read each row of each pass, +transform it, and write it out to a new interlaced image. + +If you want to de-interlace the image yourself libpng provides further +macros to help that tell you where to place the pixels in the output image. +Because the interlacing scheme is rectangular - sub-image pixels are always +arranged on a rectangular grid - all you need to know for each pass is the +starting column and row in the output image of the first pixel plus the +spacing between each pixel. As of libpng 1.5 there are four macros to +retrieve this information: + + png_uint_32 x = PNG_PASS_START_COL(pass); + png_uint_32 y = PNG_PASS_START_ROW(pass); + png_uint_32 xStep = 1U << PNG_PASS_COL_SHIFT(pass); + png_uint_32 yStep = 1U << PNG_PASS_ROW_SHIFT(pass); + +These allow you to write the obvious loop: + + png_uint_32 input_y = 0; + png_uint_32 output_y = PNG_PASS_START_ROW(pass); + + while (output_y < output_image_height) + { + png_uint_32 input_x = 0; + png_uint_32 output_x = PNG_PASS_START_COL(pass); + + while (output_x < output_image_width) + { + image[output_y][output_x] = + subimage[pass][input_y][input_x++]; + + output_x += xStep; + } + + ++input_y; + output_y += yStep; + } + +Notice that the steps between successive output rows and columns are +returned as shifts. This is possible because the pixels in the subimages +are always a power of 2 apart - 1, 2, 4 or 8 pixels - in the original +image. In practice you may need to directly calculate the output coordinate +given an input coordinate. libpng provides two further macros for this +purpose: + + png_uint_32 output_x = PNG_COL_FROM_PASS_COL(input_x, pass); + png_uint_32 output_y = PNG_ROW_FROM_PASS_ROW(input_y, pass); + +Finally a pair of macros are provided to tell you if a particular image +row or column appears in a given pass: + + int col_in_pass = PNG_COL_IN_INTERLACE_PASS(output_x, pass); + int row_in_pass = PNG_ROW_IN_INTERLACE_PASS(output_y, pass); + +Bear in mind that you will probably also need to check the width and height +of the pass in addition to the above to be sure the pass even exists! + +With any luck you are convinced by now that you don't want to do your own +interlace handling. In reality normally the only good reason for doing this +is if you are processing PNG files on a pixel-by-pixel basis and don't want +to load the whole file into memory when it is interlaced. + +libpng includes a test program, pngvalid, that illustrates reading and +writing of interlaced images. If you can't get interlacing to work in your +code and don't want to leave it to libpng (the recommended approach), see +how pngvalid.c does it. + +.SS Finishing a sequential read + +After you are finished reading the image through the +low-level interface, you can finish reading the file. + +If you want to use a different crc action for handling CRC errors in +chunks after the image data, you can call png_set_crc_action() +again at this point. + +If you are interested in comments or time, which may be stored either +before or after the image data, you should pass the separate png_info +struct if you want to keep the comments from before and after the image +separate. + + png_infop end_info = png_create_info_struct(png_ptr); + + if (!end_info) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + + png_read_end(png_ptr, end_info); + +If you are not interested, you should still call png_read_end() +but you can pass NULL, avoiding the need to create an end_info structure. +If you do this, libpng will not process any chunks after IDAT other than +skipping over them and perhaps (depending on whether you have called +png_set_crc_action) checking their CRCs while looking for the IEND chunk. + + png_read_end(png_ptr, (png_infop)NULL); + +If you don't call png_read_end(), then your file pointer will be +left pointing to the first chunk after the last IDAT, which is probably +not what you want if you expect to read something beyond the end of +the PNG datastream. + +When you are done, you can free all memory allocated by libpng like this: + + png_destroy_read_struct(&png_ptr, &info_ptr, + &end_info); + +or, if you didn't create an end_info structure, + + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + +It is also possible to individually free the info_ptr members that +point to libpng-allocated storage with the following function: + + png_free_data(png_ptr, info_ptr, mask, seq) + + mask - identifies data to be freed, a mask + containing the bitwise OR of one or + more of + PNG_FREE_PLTE, PNG_FREE_TRNS, + PNG_FREE_HIST, PNG_FREE_ICCP, + PNG_FREE_PCAL, PNG_FREE_ROWS, + PNG_FREE_SCAL, PNG_FREE_SPLT, + PNG_FREE_TEXT, PNG_FREE_UNKN, + or simply PNG_FREE_ALL + + seq - sequence number of item to be freed + (\-1 for all items) + +This function may be safely called when the relevant storage has +already been freed, or has not yet been allocated, or was allocated +by the user and not by libpng, and will in those cases do nothing. +The "seq" parameter is ignored if only one item of the selected data +type, such as PLTE, is allowed. If "seq" is not \-1, and multiple items +are allowed for the data type identified in the mask, such as text or +sPLT, only the n'th item in the structure is freed, where n is "seq". + +The default behavior is only to free data that was allocated internally +by libpng. This can be changed, so that libpng will not free the data, +or so that it will free data that was allocated by the user with png_malloc() +or png_calloc() and passed in via a png_set_*() function, with + + png_data_freer(png_ptr, info_ptr, freer, mask) + + freer - one of + PNG_DESTROY_WILL_FREE_DATA + PNG_SET_WILL_FREE_DATA + PNG_USER_WILL_FREE_DATA + + mask - which data elements are affected + same choices as in png_free_data() + +This function only affects data that has already been allocated. +You can call this function after reading the PNG data but before calling +any png_set_*() functions, to control whether the user or the png_set_*() +function is responsible for freeing any existing data that might be present, +and again after the png_set_*() functions to control whether the user +or png_destroy_*() is supposed to free the data. When the user assumes +responsibility for libpng-allocated data, the application must use +png_free() to free it, and when the user transfers responsibility to libpng +for data that the user has allocated, the user must have used png_malloc() +or png_calloc() to allocate it. + +If you allocated your row_pointers in a single block, as suggested above in +the description of the high level read interface, you must not transfer +responsibility for freeing it to the png_set_rows or png_read_destroy function, +because they would also try to free the individual row_pointers[i]. + +If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword +separately, do not transfer responsibility for freeing text_ptr to libpng, +because when libpng fills a png_text structure it combines these members with +the key member, and png_free_data() will free only text_ptr.key. Similarly, +if you transfer responsibility for free'ing text_ptr from libpng to your +application, your application must not separately free those members. + +The png_free_data() function will turn off the "valid" flag for anything +it frees. If you need to turn the flag off for a chunk that was freed by +your application instead of by libpng, you can use + + png_set_invalid(png_ptr, info_ptr, mask); + + mask - identifies the chunks to be made invalid, + containing the bitwise OR of one or + more of + PNG_INFO_gAMA, PNG_INFO_sBIT, + PNG_INFO_cHRM, PNG_INFO_PLTE, + PNG_INFO_tRNS, PNG_INFO_bKGD, + PNG_INFO_hIST, PNG_INFO_pHYs, + PNG_INFO_oFFs, PNG_INFO_tIME, + PNG_INFO_pCAL, PNG_INFO_sRGB, + PNG_INFO_iCCP, PNG_INFO_sPLT, + PNG_INFO_sCAL, PNG_INFO_IDAT + +For a more compact example of reading a PNG image, see the file example.c. + +.SS Reading PNG files progressively + +The progressive reader is slightly different from the non-progressive +reader. Instead of calling png_read_info(), png_read_rows(), and +png_read_end(), you make one call to png_process_data(), which calls +callbacks when it has the info, a row, or the end of the image. You +set up these callbacks with png_set_progressive_read_fn(). You don't +have to worry about the input/output functions of libpng, as you are +giving the library the data directly in png_process_data(). I will +assume that you have read the section on reading PNG files above, +so I will only highlight the differences (although I will show +all of the code). + +png_structp png_ptr; +png_infop info_ptr; + + /* An example code fragment of how you would + initialize the progressive reader in your + application. */ + int + initialize_png_reader() + { + png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + + if (!png_ptr) + return (ERROR); + + info_ptr = png_create_info_struct(png_ptr); + + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, + (png_infopp)NULL, (png_infopp)NULL); + return (ERROR); + } + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + + /* This one's new. You can provide functions + to be called when the header info is valid, + when each row is completed, and when the image + is finished. If you aren't using all functions, + you can specify NULL parameters. Even when all + three functions are NULL, you need to call + png_set_progressive_read_fn(). You can use + any struct as the user_ptr (cast to a void pointer + for the function call), and retrieve the pointer + from inside the callbacks using the function + + png_get_progressive_ptr(png_ptr); + + which will return a void pointer, which you have + to cast appropriately. + */ + png_set_progressive_read_fn(png_ptr, (void *)user_ptr, + info_callback, row_callback, end_callback); + + return 0; + } + + /* A code fragment that you call as you receive blocks + of data */ + int + process_data(png_bytep buffer, png_uint_32 length) + { + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + + /* This one's new also. Simply give it a chunk + of data from the file stream (in order, of + course). On machines with segmented memory + models machines, don't give it any more than + 64K. The library seems to run fine with sizes + of 4K. Although you can give it much less if + necessary (I assume you can give it chunks of + 1 byte, I haven't tried less than 256 bytes + yet). When this function returns, you may + want to display any rows that were generated + in the row callback if you don't already do + so there. + */ + png_process_data(png_ptr, info_ptr, buffer, length); + + /* At this point you can call png_process_data_skip if + you want to handle data the library will skip yourself; + it simply returns the number of bytes to skip (and stops + libpng skipping that number of bytes on the next + png_process_data call). + return 0; + } + + /* This function is called (as set by + png_set_progressive_read_fn() above) when enough data + has been supplied so all of the header has been + read. + */ + void + info_callback(png_structp png_ptr, png_infop info) + { + /* Do any setup here, including setting any of + the transformations mentioned in the Reading + PNG files section. For now, you _must_ call + either png_start_read_image() or + png_read_update_info() after all the + transformations are set (even if you don't set + any). You may start getting rows before + png_process_data() returns, so this is your + last chance to prepare for that. + + This is where you turn on interlace handling, + assuming you don't want to do it yourself. + + If you need to you can stop the processing of + your original input data at this point by calling + png_process_data_pause. This returns the number + of unprocessed bytes from the last png_process_data + call - it is up to you to ensure that the next call + sees these bytes again. If you don't want to bother + with this you can get libpng to cache the unread + bytes by setting the 'save' parameter (see png.h) but + then libpng will have to copy the data internally. + */ + } + + /* This function is called when each row of image + data is complete */ + void + row_callback(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass) + { + /* If the image is interlaced, and you turned + on the interlace handler, this function will + be called for every row in every pass. Some + of these rows will not be changed from the + previous pass. When the row is not changed, + the new_row variable will be NULL. The rows + and passes are called in order, so you don't + really need the row_num and pass, but I'm + supplying them because it may make your life + easier. + + If you did not turn on interlace handling then + the callback is called for each row of each + sub-image when the image is interlaced. In this + case 'row_num' is the row in the sub-image, not + the row in the output image as it is in all other + cases. + + For the non-NULL rows of interlaced images when + you have switched on libpng interlace handling, + you must call png_progressive_combine_row() + passing in the row and the old row. You can + call this function for NULL rows (it will just + return) and for non-interlaced images (it just + does the memcpy for you) if it will make the + code easier. Thus, you can just do this for + all cases if you switch on interlace handling; + */ + + png_progressive_combine_row(png_ptr, old_row, + new_row); + + /* where old_row is what was displayed + previously for the row. Note that the first + pass (pass == 0, really) will completely cover + the old row, so the rows do not have to be + initialized. After the first pass (and only + for interlaced images), you will have to pass + the current row, and the function will combine + the old row and the new row. + + You can also call png_process_data_pause in this + callback - see above. + */ + } + + void + end_callback(png_structp png_ptr, png_infop info) + { + /* This function is called after the whole image + has been read, including any chunks after the + image (up to and including the IEND). You + will usually have the same info chunk as you + had in the header, although some data may have + been added to the comments and time fields. + + Most people won't do much here, perhaps setting + a flag that marks the image as finished. + */ + } + + + +.SH IV. Writing + +Much of this is very similar to reading. However, everything of +importance is repeated here, so you won't have to constantly look +back up in the reading section to understand writing. + +.SS Setup + +You will want to do the I/O initialization before you get into libpng, +so if it doesn't work, you don't have anything to undo. If you are not +using the standard I/O functions, you will need to replace them with +custom writing functions. See the discussion under Customizing libpng. + + FILE *fp = fopen(file_name, "wb"); + + if (!fp) + return (ERROR); + +Next, png_struct and png_info need to be allocated and initialized. +As these can be both relatively large, you may not want to store these +on the stack, unless you have stack space to spare. Of course, you +will want to check if they return NULL. If you are also reading, +you won't want to name your read structure and your write structure +both "png_ptr"; you can call them anything you like, such as +"read_ptr" and "write_ptr". Look at pngtest.c, for example. + + png_structp png_ptr = png_create_write_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + + if (!png_ptr) + return (ERROR); + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_write_struct(&png_ptr, + (png_infopp)NULL); + return (ERROR); + } + +If you want to use your own memory allocation routines, +define PNG_USER_MEM_SUPPORTED and use +png_create_write_struct_2() instead of png_create_write_struct(): + + png_structp png_ptr = png_create_write_struct_2 + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn, (png_voidp) + user_mem_ptr, user_malloc_fn, user_free_fn); + +After you have these structures, you will need to set up the +error handling. When libpng encounters an error, it expects to +longjmp() back to your routine. Therefore, you will need to call +setjmp() and pass the png_jmpbuf(png_ptr). If you +write the file from different routines, you will need to update +the png_jmpbuf(png_ptr) every time you enter a new routine that will +call a png_*() function. See your documentation of setjmp/longjmp +for your compiler for more information on setjmp/longjmp. See +the discussion on libpng error handling in the Customizing Libpng +section below for more information on the libpng error handling. + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + return (ERROR); + } + ... + return; + +If you would rather avoid the complexity of setjmp/longjmp issues, +you can compile libpng with PNG_NO_SETJMP, in which case +errors will result in a call to PNG_ABORT() which defaults to abort(). + +You can #define PNG_ABORT() to a function that does something +more useful than abort(), as long as your function does not +return. + +Checking for invalid palette index on write was added at libpng +1.5.10. If a pixel contains an invalid (out-of-range) index libpng issues +a benign error. This is enabled by default because this condition is an +error according to the PNG specification, Clause 11.3.2, but the error can +be ignored in each png_ptr with + + png_set_check_for_invalid_index(png_ptr, 0); + +If the error is ignored, or if png_benign_error() treats it as a warning, +any invalid pixels are written as-is by the encoder, resulting in an +invalid PNG datastream as output. In this case the application is +responsible for ensuring that the pixel indexes are in range when it writes +a PLTE chunk with fewer entries than the bit depth would allow. + +Now you need to set up the output code. The default for libpng is to +use the C function fwrite(). If you use this, you will need to pass a +valid FILE * in the function png_init_io(). Be sure that the file is +opened in binary mode. Again, if you wish to handle writing data in +another way, see the discussion on libpng I/O handling in the Customizing +Libpng section below. + + png_init_io(png_ptr, fp); + +If you are embedding your PNG into a datastream such as MNG, and don't +want libpng to write the 8-byte signature, or if you have already +written the signature in your application, use + + png_set_sig_bytes(png_ptr, 8); + +to inform libpng that it should not write a signature. + +.SS Write callbacks + +At this point, you can set up a callback function that will be +called after each row has been written, which you can use to control +a progress meter or the like. It's demonstrated in pngtest.c. +You must supply a function + + void write_row_callback(png_structp png_ptr, png_uint_32 row, + int pass); + { + /* put your code here */ + } + +(You can give it another name that you like instead of "write_row_callback") + +To inform libpng about your function, use + + png_set_write_status_fn(png_ptr, write_row_callback); + +When this function is called the row has already been completely processed and +it has also been written out. The 'row' and 'pass' refer to the next row to be +handled. For the +non-interlaced case the row that was just handled is simply one less than the +passed in row number, and pass will always be 0. For the interlaced case the +same applies unless the row value is 0, in which case the row just handled was +the last one from one of the preceding passes. Because interlacing may skip a +pass you cannot be sure that the preceding pass is just 'pass\-1', if you really +need to know what the last pass is record (row,pass) from the callback and use +the last recorded value each time. + +As with the user transform you can find the output row using the +PNG_ROW_FROM_PASS_ROW macro. + +You now have the option of modifying how the compression library will +run. The following functions are mainly for testing, but may be useful +in some cases, like if you need to write PNG files extremely fast and +are willing to give up some compression, or if you want to get the +maximum possible compression at the expense of slower writing. If you +have no special needs in this area, let the library do what it wants by +not calling this function at all, as it has been tuned to deliver a good +speed/compression ratio. The second parameter to png_set_filter() is +the filter method, for which the only valid values are 0 (as of the +July 1999 PNG specification, version 1.2) or 64 (if you are writing +a PNG datastream that is to be embedded in a MNG datastream). The third +parameter is a flag that indicates which filter type(s) are to be tested +for each scanline. See the PNG specification for details on the specific +filter types. + + + /* turn on or off filtering, and/or choose + specific filters. You can use either a single + PNG_FILTER_VALUE_NAME or the bitwise OR of one + or more PNG_FILTER_NAME masks. + */ + png_set_filter(png_ptr, 0, + PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | + PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB | + PNG_FILTER_UP | PNG_FILTER_VALUE_UP | + PNG_FILTER_AVG | PNG_FILTER_VALUE_AVG | + PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH| + PNG_ALL_FILTERS | PNG_FAST_FILTERS); + +If an application wants to start and stop using particular filters during +compression, it should start out with all of the filters (to ensure that +the previous row of pixels will be stored in case it's needed later), +and then add and remove them after the start of compression. + +If you are writing a PNG datastream that is to be embedded in a MNG +datastream, the second parameter can be either 0 or 64. + +The png_set_compression_*() functions interface to the zlib compression +library, and should mostly be ignored unless you really know what you are +doing. The only generally useful call is png_set_compression_level() +which changes how much time zlib spends on trying to compress the image +data. See the Compression Library (zlib.h and algorithm.txt, distributed +with zlib) for details on the compression levels. + + #include zlib.h + + /* Set the zlib compression level */ + png_set_compression_level(png_ptr, + Z_BEST_COMPRESSION); + + /* Set other zlib parameters for compressing IDAT */ + png_set_compression_mem_level(png_ptr, 8); + png_set_compression_strategy(png_ptr, + Z_DEFAULT_STRATEGY); + png_set_compression_window_bits(png_ptr, 15); + png_set_compression_method(png_ptr, 8); + png_set_compression_buffer_size(png_ptr, 8192) + + /* Set zlib parameters for text compression + * If you don't call these, the parameters + * fall back on those defined for IDAT chunks + */ + png_set_text_compression_mem_level(png_ptr, 8); + png_set_text_compression_strategy(png_ptr, + Z_DEFAULT_STRATEGY); + png_set_text_compression_window_bits(png_ptr, 15); + png_set_text_compression_method(png_ptr, 8); + +.SS Setting the contents of info for output + +You now need to fill in the png_info structure with all the data you +wish to write before the actual image. Note that the only thing you +are allowed to write after the image is the text chunks and the time +chunk (as of PNG Specification 1.2, anyway). See png_write_end() and +the latest PNG specification for more information on that. If you +wish to write them before the image, fill them in now, and flag that +data as being valid. If you want to wait until after the data, don't +fill them until png_write_end(). For all the fields in png_info and +their data types, see png.h. For explanations of what the fields +contain, see the PNG specification. + +Some of the more important parts of the png_info are: + + png_set_IHDR(png_ptr, info_ptr, width, height, + bit_depth, color_type, interlace_type, + compression_type, filter_method) + + width - holds the width of the image + in pixels (up to 2^31). + + height - holds the height of the image + in pixels (up to 2^31). + + bit_depth - holds the bit depth of one of the + image channels. + (valid values are 1, 2, 4, 8, 16 + and depend also on the + color_type. See also significant + bits (sBIT) below). + + color_type - describes which color/alpha + channels are present. + PNG_COLOR_TYPE_GRAY + (bit depths 1, 2, 4, 8, 16) + PNG_COLOR_TYPE_GRAY_ALPHA + (bit depths 8, 16) + PNG_COLOR_TYPE_PALETTE + (bit depths 1, 2, 4, 8) + PNG_COLOR_TYPE_RGB + (bit_depths 8, 16) + PNG_COLOR_TYPE_RGB_ALPHA + (bit_depths 8, 16) + + PNG_COLOR_MASK_PALETTE + PNG_COLOR_MASK_COLOR + PNG_COLOR_MASK_ALPHA + + interlace_type - PNG_INTERLACE_NONE or + PNG_INTERLACE_ADAM7 + + compression_type - (must be + PNG_COMPRESSION_TYPE_DEFAULT) + + filter_method - (must be PNG_FILTER_TYPE_DEFAULT + or, if you are writing a PNG to + be embedded in a MNG datastream, + can also be + PNG_INTRAPIXEL_DIFFERENCING) + +If you call png_set_IHDR(), the call must appear before any of the +other png_set_*() functions, because they might require access to some of +the IHDR settings. The remaining png_set_*() functions can be called +in any order. + +If you wish, you can reset the compression_type, interlace_type, or +filter_method later by calling png_set_IHDR() again; if you do this, the +width, height, bit_depth, and color_type must be the same in each call. + + png_set_PLTE(png_ptr, info_ptr, palette, + num_palette); + + palette - the palette for the file + (array of png_color) + num_palette - number of entries in the palette + + + png_set_gAMA(png_ptr, info_ptr, file_gamma); + png_set_gAMA_fixed(png_ptr, info_ptr, int_file_gamma); + + file_gamma - the gamma at which the image was + created (PNG_INFO_gAMA) + + int_file_gamma - 100,000 times the gamma at which + the image was created + + png_set_cHRM(png_ptr, info_ptr, white_x, white_y, red_x, red_y, + green_x, green_y, blue_x, blue_y) + png_set_cHRM_XYZ(png_ptr, info_ptr, red_X, red_Y, red_Z, green_X, + green_Y, green_Z, blue_X, blue_Y, blue_Z) + png_set_cHRM_fixed(png_ptr, info_ptr, int_white_x, int_white_y, + int_red_x, int_red_y, int_green_x, int_green_y, + int_blue_x, int_blue_y) + png_set_cHRM_XYZ_fixed(png_ptr, info_ptr, int_red_X, int_red_Y, + int_red_Z, int_green_X, int_green_Y, int_green_Z, + int_blue_X, int_blue_Y, int_blue_Z) + + {white,red,green,blue}_{x,y} + A color space encoding specified using the chromaticities + of the end points and the white point. + + {red,green,blue}_{X,Y,Z} + A color space encoding specified using the encoding end + points - the CIE tristimulus specification of the intended + color of the red, green and blue channels in the PNG RGB + data. The white point is simply the sum of the three end + points. + + png_set_sRGB(png_ptr, info_ptr, srgb_intent); + + srgb_intent - the rendering intent + (PNG_INFO_sRGB) The presence of + the sRGB chunk means that the pixel + data is in the sRGB color space. + This chunk also implies specific + values of gAMA and cHRM. Rendering + intent is the CSS-1 property that + has been defined by the International + Color Consortium + (http://www.color.org). + It can be one of + PNG_sRGB_INTENT_SATURATION, + PNG_sRGB_INTENT_PERCEPTUAL, + PNG_sRGB_INTENT_ABSOLUTE, or + PNG_sRGB_INTENT_RELATIVE. + + + png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, + srgb_intent); + + srgb_intent - the rendering intent + (PNG_INFO_sRGB) The presence of the + sRGB chunk means that the pixel + data is in the sRGB color space. + This function also causes gAMA and + cHRM chunks with the specific values + that are consistent with sRGB to be + written. + + png_set_iCCP(png_ptr, info_ptr, name, compression_type, + profile, proflen); + + name - The profile name. + + compression_type - The compression type; always + PNG_COMPRESSION_TYPE_BASE for PNG 1.0. + You may give NULL to this argument to + ignore it. + + profile - International Color Consortium color + profile data. May contain NULs. + + proflen - length of profile data in bytes. + + png_set_sBIT(png_ptr, info_ptr, sig_bit); + + sig_bit - the number of significant bits for + (PNG_INFO_sBIT) each of the gray, red, + green, and blue channels, whichever are + appropriate for the given color type + (png_color_16) + + png_set_tRNS(png_ptr, info_ptr, trans_alpha, + num_trans, trans_color); + + trans_alpha - array of alpha (transparency) + entries for palette (PNG_INFO_tRNS) + + num_trans - number of transparent entries + (PNG_INFO_tRNS) + + trans_color - graylevel or color sample values + (in order red, green, blue) of the + single transparent color for + non-paletted images (PNG_INFO_tRNS) + + png_set_hIST(png_ptr, info_ptr, hist); + + hist - histogram of palette (array of + png_uint_16) (PNG_INFO_hIST) + + png_set_tIME(png_ptr, info_ptr, mod_time); + + mod_time - time image was last modified + (PNG_VALID_tIME) + + png_set_bKGD(png_ptr, info_ptr, background); + + background - background color (of type + png_color_16p) (PNG_VALID_bKGD) + + png_set_text(png_ptr, info_ptr, text_ptr, num_text); + + text_ptr - array of png_text holding image + comments + + text_ptr[i].compression - type of compression used + on "text" PNG_TEXT_COMPRESSION_NONE + PNG_TEXT_COMPRESSION_zTXt + PNG_ITXT_COMPRESSION_NONE + PNG_ITXT_COMPRESSION_zTXt + text_ptr[i].key - keyword for comment. Must contain + 1-79 characters. + text_ptr[i].text - text comments for current + keyword. Can be NULL or empty. + text_ptr[i].text_length - length of text string, + after decompression, 0 for iTXt + text_ptr[i].itxt_length - length of itxt string, + after decompression, 0 for tEXt/zTXt + text_ptr[i].lang - language of comment (NULL or + empty for unknown). + text_ptr[i].translated_keyword - keyword in UTF-8 (NULL + or empty for unknown). + + Note that the itxt_length, lang, and lang_key + members of the text_ptr structure only exist when the + library is built with iTXt chunk support. Prior to + libpng-1.4.0 the library was built by default without + iTXt support. Also note that when iTXt is supported, + they contain NULL pointers when the "compression" + field contains PNG_TEXT_COMPRESSION_NONE or + PNG_TEXT_COMPRESSION_zTXt. + + num_text - number of comments + + png_set_sPLT(png_ptr, info_ptr, &palette_ptr, + num_spalettes); + + palette_ptr - array of png_sPLT_struct structures + to be added to the list of palettes + in the info structure. + num_spalettes - number of palette structures to be + added. + + png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, + unit_type); + + offset_x - positive offset from the left + edge of the screen + + offset_y - positive offset from the top + edge of the screen + + unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER + + png_set_pHYs(png_ptr, info_ptr, res_x, res_y, + unit_type); + + res_x - pixels/unit physical resolution + in x direction + + res_y - pixels/unit physical resolution + in y direction + + unit_type - PNG_RESOLUTION_UNKNOWN, + PNG_RESOLUTION_METER + + png_set_sCAL(png_ptr, info_ptr, unit, width, height) + + unit - physical scale units (an integer) + + width - width of a pixel in physical scale units + + height - height of a pixel in physical scale units + (width and height are doubles) + + png_set_sCAL_s(png_ptr, info_ptr, unit, width, height) + + unit - physical scale units (an integer) + + width - width of a pixel in physical scale units + expressed as a string + + height - height of a pixel in physical scale units + (width and height are strings like "2.54") + + png_set_unknown_chunks(png_ptr, info_ptr, &unknowns, + num_unknowns) + + unknowns - array of png_unknown_chunk + structures holding unknown chunks + unknowns[i].name - name of unknown chunk + unknowns[i].data - data of unknown chunk + unknowns[i].size - size of unknown chunk's data + unknowns[i].location - position to write chunk in file + 0: do not write chunk + PNG_HAVE_IHDR: before PLTE + PNG_HAVE_PLTE: before IDAT + PNG_AFTER_IDAT: after IDAT + +The "location" member is set automatically according to +what part of the output file has already been written. +You can change its value after calling png_set_unknown_chunks() +as demonstrated in pngtest.c. Within each of the "locations", +the chunks are sequenced according to their position in the +structure (that is, the value of "i", which is the order in which +the chunk was either read from the input file or defined with +png_set_unknown_chunks). + +A quick word about text and num_text. text is an array of png_text +structures. num_text is the number of valid structures in the array. +Each png_text structure holds a language code, a keyword, a text value, +and a compression type. + +The compression types have the same valid numbers as the compression +types of the image data. Currently, the only valid number is zero. +However, you can store text either compressed or uncompressed, unlike +images, which always have to be compressed. So if you don't want the +text compressed, set the compression type to PNG_TEXT_COMPRESSION_NONE. +Because tEXt and zTXt chunks don't have a language field, if you +specify PNG_TEXT_COMPRESSION_NONE or PNG_TEXT_COMPRESSION_zTXt +any language code or translated keyword will not be written out. + +Until text gets around a few hundred bytes, it is not worth compressing it. +After the text has been written out to the file, the compression type +is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR, +so that it isn't written out again at the end (in case you are calling +png_write_end() with the same struct). + +The keywords that are given in the PNG Specification are: + + Title Short (one line) title or + caption for image + + Author Name of image's creator + + Description Description of image (possibly long) + + Copyright Copyright notice + + Creation Time Time of original image creation + (usually RFC 1123 format, see below) + + Software Software used to create the image + + Disclaimer Legal disclaimer + + Warning Warning of nature of content + + Source Device used to create the image + + Comment Miscellaneous comment; conversion + from other image format + +The keyword-text pairs work like this. Keywords should be short +simple descriptions of what the comment is about. Some typical +keywords are found in the PNG specification, as is some recommendations +on keywords. You can repeat keywords in a file. You can even write +some text before the image and some after. For example, you may want +to put a description of the image before the image, but leave the +disclaimer until after, so viewers working over modem connections +don't have to wait for the disclaimer to go over the modem before +they start seeing the image. Finally, keywords should be full +words, not abbreviations. Keywords and text are in the ISO 8859-1 +(Latin-1) character set (a superset of regular ASCII) and can not +contain NUL characters, and should not contain control or other +unprintable characters. To make the comments widely readable, stick +with basic ASCII, and avoid machine specific character set extensions +like the IBM-PC character set. The keyword must be present, but +you can leave off the text string on non-compressed pairs. +Compressed pairs must have a text string, as only the text string +is compressed anyway, so the compression would be meaningless. + +PNG supports modification time via the png_time structure. Two +conversion routines are provided, png_convert_from_time_t() for +time_t and png_convert_from_struct_tm() for struct tm. The +time_t routine uses gmtime(). You don't have to use either of +these, but if you wish to fill in the png_time structure directly, +you should provide the time in universal time (GMT) if possible +instead of your local time. Note that the year number is the full +year (e.g. 1998, rather than 98 - PNG is year 2000 compliant!), and +that months start with 1. + +If you want to store the time of the original image creation, you should +use a plain tEXt chunk with the "Creation Time" keyword. This is +necessary because the "creation time" of a PNG image is somewhat vague, +depending on whether you mean the PNG file, the time the image was +created in a non-PNG format, a still photo from which the image was +scanned, or possibly the subject matter itself. In order to facilitate +machine-readable dates, it is recommended that the "Creation Time" +tEXt chunk use RFC 1123 format dates (e.g. "22 May 1997 18:07:10 GMT"), +although this isn't a requirement. Unlike the tIME chunk, the +"Creation Time" tEXt chunk is not expected to be automatically changed +by the software. To facilitate the use of RFC 1123 dates, a function +png_convert_to_rfc1123_buffer(buffer, png_timep) is provided to +convert from PNG time to an RFC 1123 format string. The caller must provide +a writeable buffer of at least 29 bytes. + +.SS Writing unknown chunks + +You can use the png_set_unknown_chunks function to queue up private chunks +for writing. You give it a chunk name, location, raw data, and a size. You +also must use png_set_keep_unknown_chunks() to ensure that libpng will +handle them. That's all there is to it. The chunks will be written by the +next following png_write_info_before_PLTE, png_write_info, or png_write_end +function, depending upon the specified location. Any chunks previously +read into the info structure's unknown-chunk list will also be written out +in a sequence that satisfies the PNG specification's ordering rules. + +Here is an example of writing two private chunks, prVt and miNE: + + #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + /* Set unknown chunk data */ + png_unknown_chunk unk_chunk[2]; + strcpy((char *) unk_chunk[0].name, "prVt"; + unk_chunk[0].data = (unsigned char *) "PRIVATE DATA"; + unk_chunk[0].size = strlen(unk_chunk[0].data)+1; + unk_chunk[0].location = PNG_HAVE_IHDR; + strcpy((char *) unk_chunk[1].name, "miNE"; + unk_chunk[1].data = (unsigned char *) "MY CHUNK DATA"; + unk_chunk[1].size = strlen(unk_chunk[0].data)+1; + unk_chunk[1].location = PNG_AFTER_IDAT; + png_set_unknown_chunks(write_ptr, write_info_ptr, + unk_chunk, 2); + /* Needed because miNE is not safe-to-copy */ + png_set_keep_unknown_chunks(png, PNG_HANDLE_CHUNK_ALWAYS, + (png_bytep) "miNE", 1); + # if PNG_LIBPNG_VER < 10600 + /* Deal with unknown chunk location bug in 1.5.x and earlier */ + png_set_unknown_chunk_location(png, info, 0, PNG_HAVE_IHDR); + png_set_unknown_chunk_location(png, info, 1, PNG_AFTER_IDAT); + # endif + # if PNG_LIBPNG_VER < 10500 + /* PNG_AFTER_IDAT writes two copies of the chunk prior to libpng-1.5.0, + * one before IDAT and another after IDAT, so don't use it; only use + * PNG_HAVE_IHDR location. This call resets the location previously + * set by assignment and png_set_unknown_chunk_location() for chunk 1. + */ + png_set_unknown_chunk_location(png, info, 1, PNG_HAVE_IHDR); + # endif + #endif + +.SS The high-level write interface + +At this point there are two ways to proceed; through the high-level +write interface, or through a sequence of low-level write operations. +You can use the high-level interface if your image data is present +in the info structure. All defined output +transformations are permitted, enabled by the following masks. + + PNG_TRANSFORM_IDENTITY No transformation + PNG_TRANSFORM_PACKING Pack 1, 2 and 4-bit samples + PNG_TRANSFORM_PACKSWAP Change order of packed + pixels to LSB first + PNG_TRANSFORM_INVERT_MONO Invert monochrome images + PNG_TRANSFORM_SHIFT Normalize pixels to the + sBIT depth + PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA + to BGRA + PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA + to AG + PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity + to transparency + PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples + PNG_TRANSFORM_STRIP_FILLER Strip out filler + bytes (deprecated). + PNG_TRANSFORM_STRIP_FILLER_BEFORE Strip out leading + filler bytes + PNG_TRANSFORM_STRIP_FILLER_AFTER Strip out trailing + filler bytes + +If you have valid image data in the info structure (you can use +png_set_rows() to put image data in the info structure), simply do this: + + png_write_png(png_ptr, info_ptr, png_transforms, NULL) + +where png_transforms is an integer containing the bitwise OR of some set of +transformation flags. This call is equivalent to png_write_info(), +followed the set of transformations indicated by the transform mask, +then png_write_image(), and finally png_write_end(). + +(The final parameter of this call is not yet used. Someday it might point +to transformation parameters required by some future output transform.) + +You must use png_transforms and not call any png_set_transform() functions +when you use png_write_png(). + +.SS The low-level write interface + +If you are going the low-level route instead, you are now ready to +write all the file information up to the actual image data. You do +this with a call to png_write_info(). + + png_write_info(png_ptr, info_ptr); + +Note that there is one transformation you may need to do before +png_write_info(). In PNG files, the alpha channel in an image is the +level of opacity. If your data is supplied as a level of transparency, +you can invert the alpha channel before you write it, so that 0 is +fully transparent and 255 (in 8-bit or paletted images) or 65535 +(in 16-bit images) is fully opaque, with + + png_set_invert_alpha(png_ptr); + +This must appear before png_write_info() instead of later with the +other transformations because in the case of paletted images the tRNS +chunk data has to be inverted before the tRNS chunk is written. If +your image is not a paletted image, the tRNS data (which in such cases +represents a single color to be rendered as transparent) won't need to +be changed, and you can safely do this transformation after your +png_write_info() call. + +If you need to write a private chunk that you want to appear before +the PLTE chunk when PLTE is present, you can write the PNG info in +two steps, and insert code to write your own chunk between them: + + png_write_info_before_PLTE(png_ptr, info_ptr); + png_set_unknown_chunks(png_ptr, info_ptr, ...); + png_write_info(png_ptr, info_ptr); + +After you've written the file information, you can set up the library +to handle any special transformations of the image data. The various +ways to transform the data will be described in the order that they +should occur. This is important, as some of these change the color +type and/or bit depth of the data, and some others only work on +certain color types and bit depths. Even though each transformation +checks to see if it has data that it can do something with, you should +make sure to only enable a transformation if it will be valid for the +data. For example, don't swap red and blue on grayscale data. + +PNG files store RGB pixels packed into 3 or 6 bytes. This code tells +the library to strip input data that has 4 or 8 bytes per pixel down +to 3 or 6 bytes (or strip 2 or 4-byte grayscale+filler data to 1 or 2 +bytes per pixel). + + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); + +where the 0 is unused, and the location is either PNG_FILLER_BEFORE or +PNG_FILLER_AFTER, depending upon whether the filler byte in the pixel +is stored XRGB or RGBX. + +PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as +they can, resulting in, for example, 8 pixels per byte for 1 bit files. +If the data is supplied at 1 pixel per byte, use this code, which will +correctly pack the pixels into a single byte: + + png_set_packing(png_ptr); + +PNG files reduce possible bit depths to 1, 2, 4, 8, and 16. If your +data is of another bit depth, you can write an sBIT chunk into the +file so that decoders can recover the original data if desired. + + /* Set the true bit depth of the image data */ + if (color_type & PNG_COLOR_MASK_COLOR) + { + sig_bit.red = true_bit_depth; + sig_bit.green = true_bit_depth; + sig_bit.blue = true_bit_depth; + } + + else + { + sig_bit.gray = true_bit_depth; + } + + if (color_type & PNG_COLOR_MASK_ALPHA) + { + sig_bit.alpha = true_bit_depth; + } + + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + +If the data is stored in the row buffer in a bit depth other than +one supported by PNG (e.g. 3 bit data in the range 0-7 for a 4-bit PNG), +this will scale the values to appear to be the correct bit depth as +is required by PNG. + + png_set_shift(png_ptr, &sig_bit); + +PNG files store 16-bit pixels in network byte order (big-endian, +ie. most significant bits first). This code would be used if they are +supplied the other way (little-endian, i.e. least significant bits +first, the way PCs store them): + + if (bit_depth > 8) + png_set_swap(png_ptr); + +If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you +need to change the order the pixels are packed into bytes, you can use: + + if (bit_depth < 8) + png_set_packswap(png_ptr); + +PNG files store 3 color pixels in red, green, blue order. This code +would be used if they are supplied as blue, green, red: + + png_set_bgr(png_ptr); + +PNG files describe monochrome as black being zero and white being +one. This code would be used if the pixels are supplied with this reversed +(black being one and white being zero): + + png_set_invert_mono(png_ptr); + +Finally, you can write your own transformation function if none of +the existing ones meets your needs. This is done by setting a callback +with + + png_set_write_user_transform_fn(png_ptr, + write_transform_fn); + +You must supply the function + + void write_transform_fn(png_structp png_ptr, png_row_infop + row_info, png_bytep data) + +See pngtest.c for a working example. Your function will be called +before any of the other transformations are processed. If supported +libpng also supplies an information routine that may be called from +your callback: + + png_get_current_row_number(png_ptr); + png_get_current_pass_number(png_ptr); + +This returns the current row passed to the transform. With interlaced +images the value returned is the row in the input sub-image image. Use +PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to +find the output pixel (x,y) given an interlaced sub-image pixel (row,col,pass). + +The discussion of interlace handling above contains more information on how to +use these values. + +You can also set up a pointer to a user structure for use by your +callback function. + + png_set_user_transform_info(png_ptr, user_ptr, 0, 0); + +The user_channels and user_depth parameters of this function are ignored +when writing; you can set them to zero as shown. + +You can retrieve the pointer via the function png_get_user_transform_ptr(). +For example: + + voidp write_user_transform_ptr = + png_get_user_transform_ptr(png_ptr); + +It is possible to have libpng flush any pending output, either manually, +or automatically after a certain number of lines have been written. To +flush the output stream a single time call: + + png_write_flush(png_ptr); + +and to have libpng flush the output stream periodically after a certain +number of scanlines have been written, call: + + png_set_flush(png_ptr, nrows); + +Note that the distance between rows is from the last time png_write_flush() +was called, or the first row of the image if it has never been called. +So if you write 50 lines, and then png_set_flush 25, it will flush the +output on the next scanline, and every 25 lines thereafter, unless +png_write_flush() is called before 25 more lines have been written. +If nrows is too small (less than about 10 lines for a 640 pixel wide +RGB image) the image compression may decrease noticeably (although this +may be acceptable for real-time applications). Infrequent flushing will +only degrade the compression performance by a few percent over images +that do not use flushing. + +.SS Writing the image data + +That's it for the transformations. Now you can write the image data. +The simplest way to do this is in one function call. If you have the +whole image in memory, you can just call png_write_image() and libpng +will write the image. You will need to pass in an array of pointers to +each row. This function automatically handles interlacing, so you don't +need to call png_set_interlace_handling() or call this function multiple +times, or any of that other stuff necessary with png_write_rows(). + + png_write_image(png_ptr, row_pointers); + +where row_pointers is: + + png_byte *row_pointers[height]; + +You can point to void or char or whatever you use for pixels. + +If you don't want to write the whole image at once, you can +use png_write_rows() instead. If the file is not interlaced, +this is simple: + + png_write_rows(png_ptr, row_pointers, + number_of_rows); + +row_pointers is the same as in the png_write_image() call. + +If you are just writing one row at a time, you can do this with +a single row_pointer instead of an array of row_pointers: + + png_bytep row_pointer = row; + + png_write_row(png_ptr, row_pointer); + +When the file is interlaced, things can get a good deal more complicated. +The only currently (as of the PNG Specification version 1.2, dated July +1999) defined interlacing scheme for PNG files is the "Adam7" interlace +scheme, that breaks down an image into seven smaller images of varying +size. libpng will build these images for you, or you can do them +yourself. If you want to build them yourself, see the PNG specification +for details of which pixels to write when. + +If you don't want libpng to handle the interlacing details, just +use png_set_interlace_handling() and call png_write_rows() the +correct number of times to write all the sub-images +(png_set_interlace_handling() returns the number of sub-images.) + +If you want libpng to build the sub-images, call this before you start +writing any rows: + + number_of_passes = png_set_interlace_handling(png_ptr); + +This will return the number of passes needed. Currently, this is seven, +but may change if another interlace type is added. + +Then write the complete image number_of_passes times. + + png_write_rows(png_ptr, row_pointers, number_of_rows); + +Think carefully before you write an interlaced image. Typically code that +reads such images reads all the image data into memory, uncompressed, before +doing any processing. Only code that can display an image on the fly can +take advantage of the interlacing and even then the image has to be exactly +the correct size for the output device, because scaling an image requires +adjacent pixels and these are not available until all the passes have been +read. + +If you do write an interlaced image you will hardly ever need to handle +the interlacing yourself. Call png_set_interlace_handling() and use the +approach described above. + +The only time it is conceivable that you will really need to write an +interlaced image pass-by-pass is when you have read one pass by pass and +made some pixel-by-pixel transformation to it, as described in the read +code above. In this case use the PNG_PASS_ROWS and PNG_PASS_COLS macros +to determine the size of each sub-image in turn and simply write the rows +you obtained from the read code. + +.SS Finishing a sequential write + +After you are finished writing the image, you should finish writing +the file. If you are interested in writing comments or time, you should +pass an appropriately filled png_info pointer. If you are not interested, +you can pass NULL. + + png_write_end(png_ptr, info_ptr); + +When you are done, you can free all memory used by libpng like this: + + png_destroy_write_struct(&png_ptr, &info_ptr); + +It is also possible to individually free the info_ptr members that +point to libpng-allocated storage with the following function: + + png_free_data(png_ptr, info_ptr, mask, seq) + + mask - identifies data to be freed, a mask + containing the bitwise OR of one or + more of + PNG_FREE_PLTE, PNG_FREE_TRNS, + PNG_FREE_HIST, PNG_FREE_ICCP, + PNG_FREE_PCAL, PNG_FREE_ROWS, + PNG_FREE_SCAL, PNG_FREE_SPLT, + PNG_FREE_TEXT, PNG_FREE_UNKN, + or simply PNG_FREE_ALL + + seq - sequence number of item to be freed + (\-1 for all items) + +This function may be safely called when the relevant storage has +already been freed, or has not yet been allocated, or was allocated +by the user and not by libpng, and will in those cases do nothing. +The "seq" parameter is ignored if only one item of the selected data +type, such as PLTE, is allowed. If "seq" is not \-1, and multiple items +are allowed for the data type identified in the mask, such as text or +sPLT, only the n'th item in the structure is freed, where n is "seq". + +If you allocated data such as a palette that you passed in to libpng +with png_set_*, you must not free it until just before the call to +png_destroy_write_struct(). + +The default behavior is only to free data that was allocated internally +by libpng. This can be changed, so that libpng will not free the data, +or so that it will free data that was allocated by the user with png_malloc() +or png_calloc() and passed in via a png_set_*() function, with + + png_data_freer(png_ptr, info_ptr, freer, mask) + + freer - one of + PNG_DESTROY_WILL_FREE_DATA + PNG_SET_WILL_FREE_DATA + PNG_USER_WILL_FREE_DATA + + mask - which data elements are affected + same choices as in png_free_data() + +For example, to transfer responsibility for some data from a read structure +to a write structure, you could use + + png_data_freer(read_ptr, read_info_ptr, + PNG_USER_WILL_FREE_DATA, + PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) + + png_data_freer(write_ptr, write_info_ptr, + PNG_DESTROY_WILL_FREE_DATA, + PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) + +thereby briefly reassigning responsibility for freeing to the user but +immediately afterwards reassigning it once more to the write_destroy +function. Having done this, it would then be safe to destroy the read +structure and continue to use the PLTE, tRNS, and hIST data in the write +structure. + +This function only affects data that has already been allocated. +You can call this function before calling after the png_set_*() functions +to control whether the user or png_destroy_*() is supposed to free the data. +When the user assumes responsibility for libpng-allocated data, the +application must use +png_free() to free it, and when the user transfers responsibility to libpng +for data that the user has allocated, the user must have used png_malloc() +or png_calloc() to allocate it. + +If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword +separately, do not transfer responsibility for freeing text_ptr to libpng, +because when libpng fills a png_text structure it combines these members with +the key member, and png_free_data() will free only text_ptr.key. Similarly, +if you transfer responsibility for free'ing text_ptr from libpng to your +application, your application must not separately free those members. +For a more compact example of writing a PNG image, see the file example.c. + +.SH V. Simplified API + +The simplified API, which became available in libpng-1.6.0, hides the details +of both libpng and the PNG file format itself. +It allows PNG files to be read into a very limited number of +in-memory bitmap formats or to be written from the same formats. If these +formats do not accommodate your needs then you can, and should, use the more +sophisticated APIs above - these support a wide variety of in-memory formats +and a wide variety of sophisticated transformations to those formats as well +as a wide variety of APIs to manipulate ancilliary information. + +To read a PNG file using the simplified API: + + 1) Declare a 'png_image' structure (see below) on the stack, set the + version field to PNG_IMAGE_VERSION and the 'opaque' pointer to NULL + (this is REQUIRED, your program may crash if you don't do it.) + + 2) Call the appropriate png_image_begin_read... function. + + 3) Set the png_image 'format' member to the required sample format. + + 4) Allocate a buffer for the image and, if required, the color-map. + + 5) Call png_image_finish_read to read the image and, if required, the + color-map into your buffers. + +There are no restrictions on the format of the PNG input itself; all valid +color types, bit depths, and interlace methods are acceptable, and the +input image is transformed as necessary to the requested in-memory format +during the png_image_finish_read() step. The only caveat is that if you +request a color-mapped image from a PNG that is full-color or makes +complex use of an alpha channel the transformation is extremely lossy and the +result may look terrible. + +To write a PNG file using the simplified API: + + 1) Declare a 'png_image' structure on the stack and memset() + it to all zero. + + 2) Initialize the members of the structure that describe the + image, setting the 'format' member to the format of the + image samples. + + 3) Call the appropriate png_image_write... function with a + pointer to the image and, if necessary, the color-map to write + the PNG data. + +png_image is a structure that describes the in-memory format of an image +when it is being read or defines the in-memory format of an image that you +need to write. The "png_image" structure contains the following members: + + png_controlp opaque Initialize to NULL, free with png_image_free + png_uint_32 version Set to PNG_IMAGE_VERSION + png_uint_32 width Image width in pixels (columns) + png_uint_32 height Image height in pixels (rows) + png_uint_32 format Image format as defined below + png_uint_32 flags A bit mask containing informational flags + png_uint_32 colormap_entries; Number of entries in the color-map + png_uint_32 warning_or_error; + char message[64]; + +In the event of an error or warning the "warning_or_error" +field will be set to a non-zero value and the 'message' field will contain +a '\0' terminated string with the libpng error or warning message. If both +warnings and an error were encountered, only the error is recorded. If there +are multiple warnings, only the first one is recorded. + +The upper 30 bits of the "warning_or_error" value are reserved; the low two +bits contain a two bit code such that a value more than 1 indicates a failure +in the API just called: + + 0 - no warning or error + 1 - warning + 2 - error + 3 - error preceded by warning + +The pixels (samples) of the image have one to four channels whose components +have original values in the range 0 to 1.0: + + 1: A single gray or luminance channel (G). + 2: A gray/luminance channel and an alpha channel (GA). + 3: Three red, green, blue color channels (RGB). + 4: Three color channels and an alpha channel (RGBA). + +The channels are encoded in one of two ways: + + a) As a small integer, value 0..255, contained in a single byte. For the +alpha channel the original value is simply value/255. For the color or +luminance channels the value is encoded according to the sRGB specification +and matches the 8-bit format expected by typical display devices. + +The color/gray channels are not scaled (pre-multiplied) by the alpha +channel and are suitable for passing to color management software. + + b) As a value in the range 0..65535, contained in a 2-byte integer, in +the native byte order of the platform on which the application is running. +All channels can be converted to the original value by dividing by 65535; all +channels are linear. Color channels use the RGB encoding (RGB end-points) of +the sRGB specification. This encoding is identified by the +PNG_FORMAT_FLAG_LINEAR flag below. + +When the simplified API needs to convert between sRGB and linear colorspaces, +the actual sRGB transfer curve defined in the sRGB specification (see the +article at http://en.wikipedia.org/wiki/SRGB) is used, not the gamma=1/2.2 +approximation used elsewhere in libpng. + +When an alpha channel is present it is expected to denote pixel coverage +of the color or luminance channels and is returned as an associated alpha +channel: the color/gray channels are scaled (pre-multiplied) by the alpha +value. + +The samples are either contained directly in the image data, between 1 and 8 +bytes per pixel according to the encoding, or are held in a color-map indexed +by bytes in the image data. In the case of a color-map the color-map entries +are individual samples, encoded as above, and the image data has one byte per +pixel to select the relevant sample from the color-map. + +PNG_FORMAT_* + +The #defines to be used in png_image::format. Each #define identifies a +particular layout of channel data and, if present, alpha values. There are +separate defines for each of the two component encodings. + +A format is built up using single bit flag values. All combinations are +valid. Formats can be built up from the flag values or you can use one of +the predefined values below. When testing formats always use the FORMAT_FLAG +macros to test for individual features - future versions of the library may +add new flags. + +When reading or writing color-mapped images the format should be set to the +format of the entries in the color-map then png_image_{read,write}_colormap +called to read or write the color-map and set the format correctly for the +image data. Do not set the PNG_FORMAT_FLAG_COLORMAP bit directly! + +NOTE: libpng can be built with particular features disabled. If you see +compiler errors because the definition of one of the following flags has been +compiled out it is because libpng does not have the required support. It is +possible, however, for the libpng configuration to enable the format on just +read or just write; in that case you may see an error at run time. +You can guard against this by checking for the definition of the +appropriate "_SUPPORTED" macro, one of: + + PNG_SIMPLIFIED_{READ,WRITE}_{BGR,AFIRST}_SUPPORTED + + PNG_FORMAT_FLAG_ALPHA format with an alpha channel + PNG_FORMAT_FLAG_COLOR color format: otherwise grayscale + PNG_FORMAT_FLAG_LINEAR 2-byte channels else 1-byte + PNG_FORMAT_FLAG_COLORMAP image data is color-mapped + PNG_FORMAT_FLAG_BGR BGR colors, else order is RGB + PNG_FORMAT_FLAG_AFIRST alpha channel comes first + +Supported formats are as follows. Future versions of libpng may support more +formats; for compatibility with older versions simply check if the format +macro is defined using #ifdef. These defines describe the in-memory layout +of the components of the pixels of the image. + +First the single byte (sRGB) formats: + + PNG_FORMAT_GRAY + PNG_FORMAT_GA + PNG_FORMAT_AG + PNG_FORMAT_RGB + PNG_FORMAT_BGR + PNG_FORMAT_RGBA + PNG_FORMAT_ARGB + PNG_FORMAT_BGRA + PNG_FORMAT_ABGR + +Then the linear 2-byte formats. When naming these "Y" is used to +indicate a luminance (gray) channel. The component order within the pixel +is always the same - there is no provision for swapping the order of the +components in the linear format. The components are 16-bit integers in +the native byte order for your platform, and there is no provision for +swapping the bytes to a different endian condition. + + PNG_FORMAT_LINEAR_Y + PNG_FORMAT_LINEAR_Y_ALPHA + PNG_FORMAT_LINEAR_RGB + PNG_FORMAT_LINEAR_RGB_ALPHA + +With color-mapped formats the image data is one byte for each pixel. The byte +is an index into the color-map which is formatted as above. To obtain a +color-mapped format it is sufficient just to add the PNG_FOMAT_FLAG_COLORMAP +to one of the above definitions, or you can use one of the definitions below. + + PNG_FORMAT_RGB_COLORMAP + PNG_FORMAT_BGR_COLORMAP + PNG_FORMAT_RGBA_COLORMAP + PNG_FORMAT_ARGB_COLORMAP + PNG_FORMAT_BGRA_COLORMAP + PNG_FORMAT_ABGR_COLORMAP + +PNG_IMAGE macros + +These are convenience macros to derive information from a png_image +structure. The PNG_IMAGE_SAMPLE_ macros return values appropriate to the +actual image sample values - either the entries in the color-map or the +pixels in the image. The PNG_IMAGE_PIXEL_ macros return corresponding values +for the pixels and will always return 1 for color-mapped formats. The +remaining macros return information about the rows in the image and the +complete image. + +NOTE: All the macros that take a png_image::format parameter are compile time +constants if the format parameter is, itself, a constant. Therefore these +macros can be used in array declarations and case labels where required. +Similarly the macros are also pre-processor constants (sizeof is not used) so +they can be used in #if tests. + + PNG_IMAGE_SAMPLE_CHANNELS(fmt) + Returns the total number of channels in a given format: 1..4 + + PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt) + Returns the size in bytes of a single component of a pixel or color-map + entry (as appropriate) in the image: 1 or 2. + + PNG_IMAGE_SAMPLE_SIZE(fmt) + This is the size of the sample data for one sample. If the image is + color-mapped it is the size of one color-map entry (and image pixels are + one byte in size), otherwise it is the size of one image pixel. + + PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(fmt) + The maximum size of the color-map required by the format expressed in a + count of components. This can be used to compile-time allocate a + color-map: + + png_uint_16 colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(linear_fmt)]; + + png_byte colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(sRGB_fmt)]; + + Alternatively use the PNG_IMAGE_COLORMAP_SIZE macro below to use the + information from one of the png_image_begin_read_ APIs and dynamically + allocate the required memory. + + PNG_IMAGE_COLORMAP_SIZE(fmt) + The size of the color-map required by the format; this is the size of the + color-map buffer passed to the png_image_{read,write}_colormap APIs. It is + a fixed number determined by the format so can easily be allocated on the + stack if necessary. + +Corresponding information about the pixels + + PNG_IMAGE_PIXEL_CHANNELS(fmt) + The number of separate channels (components) in a pixel; 1 for a + color-mapped image. + + PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)\ + The size, in bytes, of each component in a pixel; 1 for a color-mapped + image. + + PNG_IMAGE_PIXEL_SIZE(fmt) + The size, in bytes, of a complete pixel; 1 for a color-mapped image. + +Information about the whole row, or whole image + + PNG_IMAGE_ROW_STRIDE(image) + Returns the total number of components in a single row of the image; this + is the minimum 'row stride', the minimum count of components between each + row. For a color-mapped image this is the minimum number of bytes in a + row. + + If you need the stride measured in bytes, row_stride_bytes is + PNG_IMAGE_ROW_STRIDE(image) * PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt) + plus any padding bytes that your application might need, for example + to start the next row on a 4-byte boundary. + + PNG_IMAGE_BUFFER_SIZE(image, row_stride) + Return the size, in bytes, of an image buffer given a png_image and a row + stride - the number of components to leave space for in each row. + + PNG_IMAGE_SIZE(image) + Return the size, in bytes, of the image in memory given just a png_image; + the row stride is the minimum stride required for the image. + + PNG_IMAGE_COLORMAP_SIZE(image) + Return the size, in bytes, of the color-map of this image. If the image + format is not a color-map format this will return a size sufficient for + 256 entries in the given format; check PNG_FORMAT_FLAG_COLORMAP if + you don't want to allocate a color-map in this case. + +PNG_IMAGE_FLAG_* + +Flags containing additional information about the image are held in +the 'flags' field of png_image. + + PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB == 0x01 + This indicates the the RGB values of the in-memory bitmap do not + correspond to the red, green and blue end-points defined by sRGB. + + PNG_IMAGE_FLAG_FAST == 0x02 + On write emphasise speed over compression; the resultant PNG file will be + larger but will be produced significantly faster, particular for large + images. Do not use this option for images which will be distributed, only + used it when producing intermediate files that will be read back in + repeatedly. For a typical 24-bit image the option will double the read + speed at the cost of increasing the image size by 25%, however for many + more compressible images the PNG file can be 10 times larger with only a + slight speed gain. + + PNG_IMAGE_FLAG_16BIT_sRGB == 0x04 + On read if the image is a 16-bit per component image and there is no gAMA + or sRGB chunk assume that the components are sRGB encoded. Notice that + images output by the simplified API always have gamma information; setting + this flag only affects the interpretation of 16-bit images from an + external source. It is recommended that the application expose this flag + to the user; the user can normally easily recognize the difference between + linear and sRGB encoding. This flag has no effect on write - the data + passed to the write APIs must have the correct encoding (as defined + above.) + + If the flag is not set (the default) input 16-bit per component data is + assumed to be linear. + + NOTE: the flag can only be set after the png_image_begin_read_ call, + because that call initializes the 'flags' field. + +READ APIs + + The png_image passed to the read APIs must have been initialized by setting + the png_controlp field 'opaque' to NULL (or, better, memset the whole thing.) + + int png_image_begin_read_from_file( png_imagep image, + const char *file_name) + + The named file is opened for read and the image header + is filled in from the PNG header in the file. + + int png_image_begin_read_from_stdio (png_imagep image, + FILE* file) + + The PNG header is read from the stdio FILE object. + + int png_image_begin_read_from_memory(png_imagep image, + png_const_voidp memory, png_size_t size) + + The PNG header is read from the given memory buffer. + + int png_image_finish_read(png_imagep image, + png_colorp background, void *buffer, + png_int_32 row_stride, void *colormap)); + + Finish reading the image into the supplied buffer and + clean up the png_image structure. + + row_stride is the step, in png_byte or png_uint_16 units + as appropriate, between adjacent rows. A positive stride + indicates that the top-most row is first in the buffer - + the normal top-down arrangement. A negative stride + indicates that the bottom-most row is first in the buffer. + + background need only be supplied if an alpha channel must + be removed from a png_byte format and the removal is to be + done by compositing on a solid color; otherwise it may be + NULL and any composition will be done directly onto the + buffer. The value is an sRGB color to use for the + background, for grayscale output the green channel is used. + + For linear output removing the alpha channel is always done + by compositing on black. + + void png_image_free(png_imagep image) + + Free any data allocated by libpng in image->opaque, + setting the pointer to NULL. May be called at any time + after the structure is initialized. + +When the simplified API needs to convert between sRGB and linear colorspaces, +the actual sRGB transfer curve defined in the sRGB specification (see the +article at http://en.wikipedia.org/wiki/SRGB) is used, not the gamma=1/2.2 +approximation used elsewhere in libpng. + +WRITE APIS + +For write you must initialize a png_image structure to describe the image to +be written: + + version: must be set to PNG_IMAGE_VERSION + opaque: must be initialized to NULL + width: image width in pixels + height: image height in rows + format: the format of the data you wish to write + flags: set to 0 unless one of the defined flags applies; set + PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB for color format images + where the RGB values do not correspond to the colors in sRGB. + colormap_entries: set to the number of entries in the color-map (0 to 256) + + int png_image_write_to_file, (png_imagep image, + const char *file, int convert_to_8bit, const void *buffer, + png_int_32 row_stride, const void *colormap)); + + Write the image to the named file. + + int png_image_write_to_memory (png_imagep image, void *memory, + png_alloc_size_t * PNG_RESTRICT memory_bytes, + int convert_to_8_bit, const void *buffer, ptrdiff_t row_stride, + const void *colormap)); + + Write the image to memory. + + int png_image_write_to_stdio(png_imagep image, FILE *file, + int convert_to_8_bit, const void *buffer, + png_int_32 row_stride, const void *colormap) + + Write the image to the given (FILE*). + +With all write APIs if image is in one of the linear formats with +(png_uint_16) data then setting convert_to_8_bit will cause the output to be +a (png_byte) PNG gamma encoded according to the sRGB specification, otherwise +a 16-bit linear encoded PNG file is written. + +With all APIs row_stride is handled as in the read APIs - it is the spacing +from one row to the next in component sized units (float) and if negative +indicates a bottom-up row layout in the buffer. If you pass zero, libpng will +calculate the row_stride for you from the width and number of channels. + +Note that the write API does not support interlacing, sub-8-bit pixels, +indexed (paletted) images, or most ancillary chunks. + +.SH VI. Modifying/Customizing libpng + +There are two issues here. The first is changing how libpng does +standard things like memory allocation, input/output, and error handling. +The second deals with more complicated things like adding new chunks, +adding new transformations, and generally changing how libpng works. +Both of those are compile-time issues; that is, they are generally +determined at the time the code is written, and there is rarely a need +to provide the user with a means of changing them. + +Memory allocation, input/output, and error handling + +All of the memory allocation, input/output, and error handling in libpng +goes through callbacks that are user-settable. The default routines are +in pngmem.c, pngrio.c, pngwio.c, and pngerror.c, respectively. To change +these functions, call the appropriate png_set_*_fn() function. + +Memory allocation is done through the functions png_malloc(), png_calloc(), +and png_free(). The png_malloc() and png_free() functions currently just +call the standard C functions and png_calloc() calls png_malloc() and then +clears the newly allocated memory to zero; note that png_calloc(png_ptr, size) +is not the same as the calloc(number, size) function provided by stdlib.h. +There is limited support for certain systems with segmented memory +architectures and the types of pointers declared by png.h match this; you +will have to use appropriate pointers in your application. If you prefer +to use a different method of allocating and freeing data, you can use +png_create_read_struct_2() or png_create_write_struct_2() to register your +own functions as described above. These functions also provide a void +pointer that can be retrieved via + + mem_ptr=png_get_mem_ptr(png_ptr); + +Your replacement memory functions must have prototypes as follows: + + png_voidp malloc_fn(png_structp png_ptr, + png_alloc_size_t size); + + void free_fn(png_structp png_ptr, png_voidp ptr); + +Your malloc_fn() must return NULL in case of failure. The png_malloc() +function will normally call png_error() if it receives a NULL from the +system memory allocator or from your replacement malloc_fn(). + +Your free_fn() will never be called with a NULL ptr, since libpng's +png_free() checks for NULL before calling free_fn(). + +Input/Output in libpng is done through png_read() and png_write(), +which currently just call fread() and fwrite(). The FILE * is stored in +png_struct and is initialized via png_init_io(). If you wish to change +the method of I/O, the library supplies callbacks that you can set +through the function png_set_read_fn() and png_set_write_fn() at run +time, instead of calling the png_init_io() function. These functions +also provide a void pointer that can be retrieved via the function +png_get_io_ptr(). For example: + + png_set_read_fn(png_structp read_ptr, + voidp read_io_ptr, png_rw_ptr read_data_fn) + + png_set_write_fn(png_structp write_ptr, + voidp write_io_ptr, png_rw_ptr write_data_fn, + png_flush_ptr output_flush_fn); + + voidp read_io_ptr = png_get_io_ptr(read_ptr); + voidp write_io_ptr = png_get_io_ptr(write_ptr); + +The replacement I/O functions must have prototypes as follows: + + void user_read_data(png_structp png_ptr, + png_bytep data, png_size_t length); + + void user_write_data(png_structp png_ptr, + png_bytep data, png_size_t length); + + void user_flush_data(png_structp png_ptr); + +The user_read_data() function is responsible for detecting and +handling end-of-data errors. + +Supplying NULL for the read, write, or flush functions sets them back +to using the default C stream functions, which expect the io_ptr to +point to a standard *FILE structure. It is probably a mistake +to use NULL for one of write_data_fn and output_flush_fn but not both +of them, unless you have built libpng with PNG_NO_WRITE_FLUSH defined. +It is an error to read from a write stream, and vice versa. + +Error handling in libpng is done through png_error() and png_warning(). +Errors handled through png_error() are fatal, meaning that png_error() +should never return to its caller. Currently, this is handled via +setjmp() and longjmp() (unless you have compiled libpng with +PNG_NO_SETJMP, in which case it is handled via PNG_ABORT()), +but you could change this to do things like exit() if you should wish, +as long as your function does not return. + +On non-fatal errors, png_warning() is called +to print a warning message, and then control returns to the calling code. +By default png_error() and png_warning() print a message on stderr via +fprintf() unless the library is compiled with PNG_NO_CONSOLE_IO defined +(because you don't want the messages) or PNG_NO_STDIO defined (because +fprintf() isn't available). If you wish to change the behavior of the error +functions, you will need to set up your own message callbacks. These +functions are normally supplied at the time that the png_struct is created. +It is also possible to redirect errors and warnings to your own replacement +functions after png_create_*_struct() has been called by calling: + + png_set_error_fn(png_structp png_ptr, + png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warning_fn); + + png_voidp error_ptr = png_get_error_ptr(png_ptr); + +If NULL is supplied for either error_fn or warning_fn, then the libpng +default function will be used, calling fprintf() and/or longjmp() if a +problem is encountered. The replacement error functions should have +parameters as follows: + + void user_error_fn(png_structp png_ptr, + png_const_charp error_msg); + + void user_warning_fn(png_structp png_ptr, + png_const_charp warning_msg); + +The motivation behind using setjmp() and longjmp() is the C++ throw and +catch exception handling methods. This makes the code much easier to write, +as there is no need to check every return code of every function call. +However, there are some uncertainties about the status of local variables +after a longjmp, so the user may want to be careful about doing anything +after setjmp returns non-zero besides returning itself. Consult your +compiler documentation for more details. For an alternative approach, you +may wish to use the "cexcept" facility (see http://cexcept.sourceforge.net), +which is illustrated in pngvalid.c and in contrib/visupng. + +Beginning in libpng-1.4.0, the png_set_benign_errors() API became available. +You can use this to handle certain errors (normally handled as errors) +as warnings. + + png_set_benign_errors (png_ptr, int allowed); + + allowed: 0: treat png_benign_error() as an error. + 1: treat png_benign_error() as a warning. + +As of libpng-1.6.0, the default condition is to treat benign errors as +warnings while reading and as errors while writing. + +.SS Custom chunks + +If you need to read or write custom chunks, you may need to get deeper +into the libpng code. The library now has mechanisms for storing +and writing chunks of unknown type; you can even declare callbacks +for custom chunks. However, this may not be good enough if the +library code itself needs to know about interactions between your +chunk and existing `intrinsic' chunks. + +If you need to write a new intrinsic chunk, first read the PNG +specification. Acquire a first level of understanding of how it works. +Pay particular attention to the sections that describe chunk names, +and look at how other chunks were designed, so you can do things +similarly. Second, check out the sections of libpng that read and +write chunks. Try to find a chunk that is similar to yours and use +it as a template. More details can be found in the comments inside +the code. It is best to handle private or unknown chunks in a generic method, +via callback functions, instead of by modifying libpng functions. This +is illustrated in pngtest.c, which uses a callback function to handle a +private "vpAg" chunk and the new "sTER" chunk, which are both unknown to +libpng. + +If you wish to write your own transformation for the data, look through +the part of the code that does the transformations, and check out some of +the simpler ones to get an idea of how they work. Try to find a similar +transformation to the one you want to add and copy off of it. More details +can be found in the comments inside the code itself. + +.SS Configuring for gui/windowing platforms: + +You will need to write new error and warning functions that use the GUI +interface, as described previously, and set them to be the error and +warning functions at the time that png_create_*_struct() is called, +in order to have them available during the structure initialization. +They can be changed later via png_set_error_fn(). On some compilers, +you may also have to change the memory allocators (png_malloc, etc.). + +.SS Configuring zlib: + +There are special functions to configure the compression. Perhaps the +most useful one changes the compression level, which currently uses +input compression values in the range 0 - 9. The library normally +uses the default compression level (Z_DEFAULT_COMPRESSION = 6). Tests +have shown that for a large majority of images, compression values in +the range 3-6 compress nearly as well as higher levels, and do so much +faster. For online applications it may be desirable to have maximum speed +(Z_BEST_SPEED = 1). With versions of zlib after v0.99, you can also +specify no compression (Z_NO_COMPRESSION = 0), but this would create +files larger than just storing the raw bitmap. You can specify the +compression level by calling: + + #include zlib.h + png_set_compression_level(png_ptr, level); + +Another useful one is to reduce the memory level used by the library. +The memory level defaults to 8, but it can be lowered if you are +short on memory (running DOS, for example, where you only have 640K). +Note that the memory level does have an effect on compression; among +other things, lower levels will result in sections of incompressible +data being emitted in smaller stored blocks, with a correspondingly +larger relative overhead of up to 15% in the worst case. + + #include zlib.h + png_set_compression_mem_level(png_ptr, level); + +The other functions are for configuring zlib. They are not recommended +for normal use and may result in writing an invalid PNG file. See +zlib.h for more information on what these mean. + + #include zlib.h + png_set_compression_strategy(png_ptr, + strategy); + + png_set_compression_window_bits(png_ptr, + window_bits); + + png_set_compression_method(png_ptr, method); + +This controls the size of the IDAT chunks (default 8192): + + png_set_compression_buffer_size(png_ptr, size); + +As of libpng version 1.5.4, additional APIs became +available to set these separately for non-IDAT +compressed chunks such as zTXt, iTXt, and iCCP: + + #include zlib.h + #if PNG_LIBPNG_VER >= 10504 + png_set_text_compression_level(png_ptr, level); + + png_set_text_compression_mem_level(png_ptr, level); + + png_set_text_compression_strategy(png_ptr, + strategy); + + png_set_text_compression_window_bits(png_ptr, + window_bits); + + png_set_text_compression_method(png_ptr, method); + #endif + +.SS Controlling row filtering + +If you want to control whether libpng uses filtering or not, which +filters are used, and how it goes about picking row filters, you +can call one of these functions. The selection and configuration +of row filters can have a significant impact on the size and +encoding speed and a somewhat lesser impact on the decoding speed +of an image. Filtering is enabled by default for RGB and grayscale +images (with and without alpha), but not for paletted images nor +for any images with bit depths less than 8 bits/pixel. + +The 'method' parameter sets the main filtering method, which is +currently only '0' in the PNG 1.2 specification. The 'filters' +parameter sets which filter(s), if any, should be used for each +scanline. Possible values are PNG_ALL_FILTERS, PNG_NO_FILTERS, +or PNG_FAST_FILTERS to turn filtering on and off, or to turn on +just the fast-decoding subset of filters, respectively. + +Individual filter types are PNG_FILTER_NONE, PNG_FILTER_SUB, +PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH, which can be bitwise +ORed together with '|' to specify one or more filters to use. +These filters are described in more detail in the PNG specification. +If you intend to change the filter type during the course of writing +the image, you should start with flags set for all of the filters +you intend to use so that libpng can initialize its internal +structures appropriately for all of the filter types. (Note that this +means the first row must always be adaptively filtered, because libpng +currently does not allocate the filter buffers until png_write_row() +is called for the first time.) + + filters = PNG_NO_FILTERS; + filters = PNG_ALL_FILTERS; + filters = PNG_FAST_FILTERS; + + or + + filters = PNG_FILTER_NONE | PNG_FILTER_SUB | + PNG_FILTER_UP | PNG_FILTER_AVG | + PNG_FILTER_PAETH; + + png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, + filters); + + The second parameter can also be + PNG_INTRAPIXEL_DIFFERENCING if you are + writing a PNG to be embedded in a MNG + datastream. This parameter must be the + same as the value of filter_method used + in png_set_IHDR(). + +.SS Requesting debug printout + +The macro definition PNG_DEBUG can be used to request debugging +printout. Set it to an integer value in the range 0 to 3. Higher +numbers result in increasing amounts of debugging information. The +information is printed to the "stderr" file, unless another file +name is specified in the PNG_DEBUG_FILE macro definition. + +When PNG_DEBUG > 0, the following functions (macros) become available: + + png_debug(level, message) + png_debug1(level, message, p1) + png_debug2(level, message, p1, p2) + +in which "level" is compared to PNG_DEBUG to decide whether to print +the message, "message" is the formatted string to be printed, +and p1 and p2 are parameters that are to be embedded in the string +according to printf-style formatting directives. For example, + + png_debug1(2, "foo=%d", foo); + +is expanded to + + if (PNG_DEBUG > 2) + fprintf(PNG_DEBUG_FILE, "foo=%d\en", foo); + +When PNG_DEBUG is defined but is zero, the macros aren't defined, but you +can still use PNG_DEBUG to control your own debugging: + + #ifdef PNG_DEBUG + fprintf(stderr, ... + #endif + +When PNG_DEBUG = 1, the macros are defined, but only png_debug statements +having level = 0 will be printed. There aren't any such statements in +this version of libpng, but if you insert some they will be printed. + +.SH VII. MNG support + +The MNG specification (available at http://www.libpng.org/pub/mng) allows +certain extensions to PNG for PNG images that are embedded in MNG datastreams. +Libpng can support some of these extensions. To enable them, use the +png_permit_mng_features() function: + + feature_set = png_permit_mng_features(png_ptr, mask) + + mask is a png_uint_32 containing the bitwise OR of the + features you want to enable. These include + PNG_FLAG_MNG_EMPTY_PLTE + PNG_FLAG_MNG_FILTER_64 + PNG_ALL_MNG_FEATURES + + feature_set is a png_uint_32 that is the bitwise AND of + your mask with the set of MNG features that is + supported by the version of libpng that you are using. + +It is an error to use this function when reading or writing a standalone +PNG file with the PNG 8-byte signature. The PNG datastream must be wrapped +in a MNG datastream. As a minimum, it must have the MNG 8-byte signature +and the MHDR and MEND chunks. Libpng does not provide support for these +or any other MNG chunks; your application must provide its own support for +them. You may wish to consider using libmng (available at +http://www.libmng.com) instead. + +.SH VIII. Changes to Libpng from version 0.88 + +It should be noted that versions of libpng later than 0.96 are not +distributed by the original libpng author, Guy Schalnat, nor by +Andreas Dilger, who had taken over from Guy during 1996 and 1997, and +distributed versions 0.89 through 0.96, but rather by another member +of the original PNG Group, Glenn Randers-Pehrson. Guy and Andreas are +still alive and well, but they have moved on to other things. + +The old libpng functions png_read_init(), png_write_init(), +png_info_init(), png_read_destroy(), and png_write_destroy() have been +moved to PNG_INTERNAL in version 0.95 to discourage their use. These +functions will be removed from libpng version 1.4.0. + +The preferred method of creating and initializing the libpng structures is +via the png_create_read_struct(), png_create_write_struct(), and +png_create_info_struct() because they isolate the size of the structures +from the application, allow version error checking, and also allow the +use of custom error handling routines during the initialization, which +the old functions do not. The functions png_read_destroy() and +png_write_destroy() do not actually free the memory that libpng +allocated for these structs, but just reset the data structures, so they +can be used instead of png_destroy_read_struct() and +png_destroy_write_struct() if you feel there is too much system overhead +allocating and freeing the png_struct for each image read. + +Setting the error callbacks via png_set_message_fn() before +png_read_init() as was suggested in libpng-0.88 is no longer supported +because this caused applications that do not use custom error functions +to fail if the png_ptr was not initialized to zero. It is still possible +to set the error callbacks AFTER png_read_init(), or to change them with +png_set_error_fn(), which is essentially the same function, but with a new +name to force compilation errors with applications that try to use the old +method. + +Support for the sCAL, iCCP, iTXt, and sPLT chunks was added at libpng-1.0.6; +however, iTXt support was not enabled by default. + +Starting with version 1.0.7, you can find out which version of the library +you are using at run-time: + + png_uint_32 libpng_vn = png_access_version_number(); + +The number libpng_vn is constructed from the major version, minor +version with leading zero, and release number with leading zero, +(e.g., libpng_vn for version 1.0.7 is 10007). + +Note that this function does not take a png_ptr, so you can call it +before you've created one. + +You can also check which version of png.h you used when compiling your +application: + + png_uint_32 application_vn = PNG_LIBPNG_VER; + +.SH IX. Changes to Libpng from version 1.0.x to 1.2.x + +Support for user memory management was enabled by default. To +accomplish this, the functions png_create_read_struct_2(), +png_create_write_struct_2(), png_set_mem_fn(), png_get_mem_ptr(), +png_malloc_default(), and png_free_default() were added. + +Support for the iTXt chunk has been enabled by default as of +version 1.2.41. + +Support for certain MNG features was enabled. + +Support for numbered error messages was added. However, we never got +around to actually numbering the error messages. The function +png_set_strip_error_numbers() was added (Note: the prototype for this +function was inadvertently removed from png.h in PNG_NO_ASSEMBLER_CODE +builds of libpng-1.2.15. It was restored in libpng-1.2.36). + +The png_malloc_warn() function was added at libpng-1.2.3. This issues +a png_warning and returns NULL instead of aborting when it fails to +acquire the requested memory allocation. + +Support for setting user limits on image width and height was enabled +by default. The functions png_set_user_limits(), png_get_user_width_max(), +and png_get_user_height_max() were added at libpng-1.2.6. + +The png_set_add_alpha() function was added at libpng-1.2.7. + +The function png_set_expand_gray_1_2_4_to_8() was added at libpng-1.2.9. +Unlike png_set_gray_1_2_4_to_8(), the new function does not expand the +tRNS chunk to alpha. The png_set_gray_1_2_4_to_8() function is +deprecated. + +A number of macro definitions in support of runtime selection of +assembler code features (especially Intel MMX code support) were +added at libpng-1.2.0: + + PNG_ASM_FLAG_MMX_SUPPORT_COMPILED + PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU + PNG_ASM_FLAG_MMX_READ_COMBINE_ROW + PNG_ASM_FLAG_MMX_READ_INTERLACE + PNG_ASM_FLAG_MMX_READ_FILTER_SUB + PNG_ASM_FLAG_MMX_READ_FILTER_UP + PNG_ASM_FLAG_MMX_READ_FILTER_AVG + PNG_ASM_FLAG_MMX_READ_FILTER_PAETH + PNG_ASM_FLAGS_INITIALIZED + PNG_MMX_READ_FLAGS + PNG_MMX_FLAGS + PNG_MMX_WRITE_FLAGS + PNG_MMX_FLAGS + +We added the following functions in support of runtime +selection of assembler code features: + + png_get_mmx_flagmask() + png_set_mmx_thresholds() + png_get_asm_flags() + png_get_mmx_bitdepth_threshold() + png_get_mmx_rowbytes_threshold() + png_set_asm_flags() + +We replaced all of these functions with simple stubs in libpng-1.2.20, +when the Intel assembler code was removed due to a licensing issue. + +These macros are deprecated: + + PNG_READ_TRANSFORMS_NOT_SUPPORTED + PNG_PROGRESSIVE_READ_NOT_SUPPORTED + PNG_NO_SEQUENTIAL_READ_SUPPORTED + PNG_WRITE_TRANSFORMS_NOT_SUPPORTED + PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED + PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED + +They have been replaced, respectively, by: + + PNG_NO_READ_TRANSFORMS + PNG_NO_PROGRESSIVE_READ + PNG_NO_SEQUENTIAL_READ + PNG_NO_WRITE_TRANSFORMS + PNG_NO_READ_ANCILLARY_CHUNKS + PNG_NO_WRITE_ANCILLARY_CHUNKS + +PNG_MAX_UINT was replaced with PNG_UINT_31_MAX. It has been +deprecated since libpng-1.0.16 and libpng-1.2.6. + +The function + png_check_sig(sig, num) +was replaced with + !png_sig_cmp(sig, 0, num) +It has been deprecated since libpng-0.90. + +The function + png_set_gray_1_2_4_to_8() +which also expands tRNS to alpha was replaced with + png_set_expand_gray_1_2_4_to_8() +which does not. It has been deprecated since libpng-1.0.18 and 1.2.9. + +.SH X. Changes to Libpng from version 1.0.x/1.2.x to 1.4.x + +Private libpng prototypes and macro definitions were moved from +png.h and pngconf.h into a new pngpriv.h header file. + +Functions png_set_benign_errors(), png_benign_error(), and +png_chunk_benign_error() were added. + +Support for setting the maximum amount of memory that the application +will allocate for reading chunks was added, as a security measure. +The functions png_set_chunk_cache_max() and png_get_chunk_cache_max() +were added to the library. + +We implemented support for I/O states by adding png_ptr member io_state +and functions png_get_io_chunk_name() and png_get_io_state() in pngget.c + +We added PNG_TRANSFORM_GRAY_TO_RGB to the available high-level +input transforms. + +Checking for and reporting of errors in the IHDR chunk is more thorough. + +Support for global arrays was removed, to improve thread safety. + +Some obsolete/deprecated macros and functions have been removed. + +Typecasted NULL definitions such as + #define png_voidp_NULL (png_voidp)NULL +were eliminated. If you used these in your application, just use +NULL instead. + +The png_struct and info_struct members "trans" and "trans_values" were +changed to "trans_alpha" and "trans_color", respectively. + +The obsolete, unused pnggccrd.c and pngvcrd.c files and related makefiles +were removed. + +The PNG_1_0_X and PNG_1_2_X macros were eliminated. + +The PNG_LEGACY_SUPPORTED macro was eliminated. + +Many WIN32_WCE #ifdefs were removed. + +The functions png_read_init(info_ptr), png_write_init(info_ptr), +png_info_init(info_ptr), png_read_destroy(), and png_write_destroy() +have been removed. They have been deprecated since libpng-0.95. + +The png_permit_empty_plte() was removed. It has been deprecated +since libpng-1.0.9. Use png_permit_mng_features() instead. + +We removed the obsolete stub functions png_get_mmx_flagmask(), +png_set_mmx_thresholds(), png_get_asm_flags(), +png_get_mmx_bitdepth_threshold(), png_get_mmx_rowbytes_threshold(), +png_set_asm_flags(), and png_mmx_supported() + +We removed the obsolete png_check_sig(), png_memcpy_check(), and +png_memset_check() functions. Instead use !png_sig_cmp(), memcpy(), +and memset(), respectively. + +The function png_set_gray_1_2_4_to_8() was removed. It has been +deprecated since libpng-1.0.18 and 1.2.9, when it was replaced with +png_set_expand_gray_1_2_4_to_8() because the former function also +expanded any tRNS chunk to an alpha channel. + +Macros for png_get_uint_16, png_get_uint_32, and png_get_int_32 +were added and are used by default instead of the corresponding +functions. Unfortunately, +from libpng-1.4.0 until 1.4.4, the png_get_uint_16 macro (but not the +function) incorrectly returned a value of type png_uint_32. + +We changed the prototype for png_malloc() from + png_malloc(png_structp png_ptr, png_uint_32 size) +to + png_malloc(png_structp png_ptr, png_alloc_size_t size) + +This also applies to the prototype for the user replacement malloc_fn(). + +The png_calloc() function was added and is used in place of +of "png_malloc(); memset();" except in the case in png_read_png() +where the array consists of pointers; in this case a "for" loop is used +after the png_malloc() to set the pointers to NULL, to give robust. +behavior in case the application runs out of memory part-way through +the process. + +We changed the prototypes of png_get_compression_buffer_size() and +png_set_compression_buffer_size() to work with png_size_t instead of +png_uint_32. + +Support for numbered error messages was removed by default, since we +never got around to actually numbering the error messages. The function +png_set_strip_error_numbers() was removed from the library by default. + +The png_zalloc() and png_zfree() functions are no longer exported. +The png_zalloc() function no longer zeroes out the memory that it +allocates. Applications that called png_zalloc(png_ptr, number, size) +can call png_calloc(png_ptr, number*size) instead, and can call +png_free() instead of png_zfree(). + +Support for dithering was disabled by default in libpng-1.4.0, because +it has not been well tested and doesn't actually "dither". +The code was not +removed, however, and could be enabled by building libpng with +PNG_READ_DITHER_SUPPORTED defined. In libpng-1.4.2, this support +was re-enabled, but the function was renamed png_set_quantize() to +reflect more accurately what it actually does. At the same time, +the PNG_DITHER_[RED,GREEN_BLUE]_BITS macros were also renamed to +PNG_QUANTIZE_[RED,GREEN,BLUE]_BITS, and PNG_READ_DITHER_SUPPORTED +was renamed to PNG_READ_QUANTIZE_SUPPORTED. + +We removed the trailing '.' from the warning and error messages. + +.SH XI. Changes to Libpng from version 1.4.x to 1.5.x + +From libpng-1.4.0 until 1.4.4, the png_get_uint_16 macro (but not the +function) incorrectly returned a value of type png_uint_32. +The incorrect macro was removed from libpng-1.4.5. + +Checking for invalid palette index on write was added at libpng +1.5.10. If a pixel contains an invalid (out-of-range) index libpng issues +a benign error. This is enabled by default because this condition is an +error according to the PNG specification, Clause 11.3.2, but the error can +be ignored in each png_ptr with + + png_set_check_for_invalid_index(png_ptr, allowed); + + allowed - one of + 0: disable benign error (accept the + invalid data without warning). + 1: enable benign error (treat the + invalid data as an error or a + warning). + +If the error is ignored, or if png_benign_error() treats it as a warning, +any invalid pixels are decoded as opaque black by the decoder and written +as-is by the encoder. + +Retrieving the maximum palette index found was added at libpng-1.5.15. +This statement must appear after png_read_png() or png_read_image() while +reading, and after png_write_png() or png_write_image() while writing. + + int max_palette = png_get_palette_max(png_ptr, info_ptr); + +This will return the maximum palette index found in the image, or "\-1" if +the palette was not checked, or "0" if no palette was found. Note that this +does not account for any palette index used by ancillary chunks such as the +bKGD chunk; you must check those separately to determine the maximum +palette index actually used. + +There are no substantial API changes between the non-deprecated parts of +the 1.4.5 API and the 1.5.0 API; however, the ability to directly access +members of the main libpng control structures, png_struct and png_info, +deprecated in earlier versions of libpng, has been completely removed from +libpng 1.5, and new private "pngstruct.h", "pnginfo.h", and "pngdebug.h" +header files were created. + +We no longer include zlib.h in png.h. The include statement has been moved +to pngstruct.h, where it is not accessible by applications. Applications that +need access to information in zlib.h will need to add the '#include "zlib.h"' +directive. It does not matter whether this is placed prior to or after +the '"#include png.h"' directive. + +The png_sprintf(), png_strcpy(), and png_strncpy() macros are no longer used +and were removed. + +We moved the png_strlen(), png_memcpy(), png_memset(), and png_memcmp() +macros into a private header file (pngpriv.h) that is not accessible to +applications. + +In png_get_iCCP, the type of "profile" was changed from png_charpp +to png_bytepp, and in png_set_iCCP, from png_charp to png_const_bytep. + +There are changes of form in png.h, including new and changed macros to +declare parts of the API. Some API functions with arguments that are +pointers to data not modified within the function have been corrected to +declare these arguments with PNG_CONST. + +Much of the internal use of C macros to control the library build has also +changed and some of this is visible in the exported header files, in +particular the use of macros to control data and API elements visible +during application compilation may require significant revision to +application code. (It is extremely rare for an application to do this.) + +Any program that compiled against libpng 1.4 and did not use deprecated +features or access internal library structures should compile and work +against libpng 1.5, except for the change in the prototype for +png_get_iCCP() and png_set_iCCP() API functions mentioned above. + +libpng 1.5.0 adds PNG_ PASS macros to help in the reading and writing of +interlaced images. The macros return the number of rows and columns in +each pass and information that can be used to de-interlace and (if +absolutely necessary) interlace an image. + +libpng 1.5.0 adds an API png_longjmp(png_ptr, value). This API calls +the application-provided png_longjmp_ptr on the internal, but application +initialized, longjmp buffer. It is provided as a convenience to avoid +the need to use the png_jmpbuf macro, which had the unnecessary side +effect of resetting the internal png_longjmp_ptr value. + +libpng 1.5.0 includes a complete fixed point API. By default this is +present along with the corresponding floating point API. In general the +fixed point API is faster and smaller than the floating point one because +the PNG file format used fixed point, not floating point. This applies +even if the library uses floating point in internal calculations. A new +macro, PNG_FLOATING_ARITHMETIC_SUPPORTED, reveals whether the library +uses floating point arithmetic (the default) or fixed point arithmetic +internally for performance critical calculations such as gamma correction. +In some cases, the gamma calculations may produce slightly different +results. This has changed the results in png_rgb_to_gray and in alpha +composition (png_set_background for example). This applies even if the +original image was already linear (gamma == 1.0) and, therefore, it is +not necessary to linearize the image. This is because libpng has *not* +been changed to optimize that case correctly, yet. + +Fixed point support for the sCAL chunk comes with an important caveat; +the sCAL specification uses a decimal encoding of floating point values +and the accuracy of PNG fixed point values is insufficient for +representation of these values. Consequently a "string" API +(png_get_sCAL_s and png_set_sCAL_s) is the only reliable way of reading +arbitrary sCAL chunks in the absence of either the floating point API or +internal floating point calculations. Starting with libpng-1.5.0, both +of these functions are present when PNG_sCAL_SUPPORTED is defined. Prior +to libpng-1.5.0, their presence also depended upon PNG_FIXED_POINT_SUPPORTED +being defined and PNG_FLOATING_POINT_SUPPORTED not being defined. + +Applications no longer need to include the optional distribution header +file pngusr.h or define the corresponding macros during application +build in order to see the correct variant of the libpng API. From 1.5.0 +application code can check for the corresponding _SUPPORTED macro: + +#ifdef PNG_INCH_CONVERSIONS_SUPPORTED + /* code that uses the inch conversion APIs. */ +#endif + +This macro will only be defined if the inch conversion functions have been +compiled into libpng. The full set of macros, and whether or not support +has been compiled in, are available in the header file pnglibconf.h. +This header file is specific to the libpng build. Notice that prior to +1.5.0 the _SUPPORTED macros would always have the default definition unless +reset by pngusr.h or by explicit settings on the compiler command line. +These settings may produce compiler warnings or errors in 1.5.0 because +of macro redefinition. + +Applications can now choose whether to use these macros or to call the +corresponding function by defining PNG_USE_READ_MACROS or +PNG_NO_USE_READ_MACROS before including png.h. Notice that this is +only supported from 1.5.0; defining PNG_NO_USE_READ_MACROS prior to 1.5.0 +will lead to a link failure. + +Prior to libpng-1.5.4, the zlib compressor used the same set of parameters +when compressing the IDAT data and textual data such as zTXt and iCCP. +In libpng-1.5.4 we reinitialized the zlib stream for each type of data. +We added five png_set_text_*() functions for setting the parameters to +use with textual data. + +Prior to libpng-1.5.4, the PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +option was off by default, and slightly inaccurate scaling occurred. +This option can no longer be turned off, and the choice of accurate +or inaccurate 16-to-8 scaling is by using the new png_set_scale_16_to_8() +API for accurate scaling or the old png_set_strip_16_to_8() API for simple +chopping. In libpng-1.5.4, the PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +macro became PNG_READ_SCALE_16_TO_8_SUPPORTED, and the PNG_READ_16_TO_8 +macro became PNG_READ_STRIP_16_TO_8_SUPPORTED, to enable the two +png_set_*_16_to_8() functions separately. + +Prior to libpng-1.5.4, the png_set_user_limits() function could only be +used to reduce the width and height limits from the value of +PNG_USER_WIDTH_MAX and PNG_USER_HEIGHT_MAX, although this document said +that it could be used to override them. Now this function will reduce or +increase the limits. + +Starting in libpng-1.5.10, the user limits can be set en masse with the +configuration option PNG_SAFE_LIMITS_SUPPORTED. If this option is enabled, +a set of "safe" limits is applied in pngpriv.h. These can be overridden by +application calls to png_set_user_limits(), png_set_user_chunk_cache_max(), +and/or png_set_user_malloc_max() that increase or decrease the limits. Also, +in libpng-1.5.10 the default width and height limits were increased +from 1,000,000 to 0x7fffffff (i.e., made unlimited). Therefore, the +limits are now + default safe + png_user_width_max 0x7fffffff 1,000,000 + png_user_height_max 0x7fffffff 1,000,000 + png_user_chunk_cache_max 0 (unlimited) 128 + png_user_chunk_malloc_max 0 (unlimited) 8,000,000 + +The png_set_option() function (and the "options" member of the png struct) was +added to libpng-1.5.15, with option PNG_ARM_NEON. + +The library now supports a complete fixed point implementation and can +thus be used on systems that have no floating point support or very +limited or slow support. Previously gamma correction, an essential part +of complete PNG support, required reasonably fast floating point. + +As part of this the choice of internal implementation has been made +independent of the choice of fixed versus floating point APIs and all the +missing fixed point APIs have been implemented. + +The exact mechanism used to control attributes of API functions has +changed, as described in the INSTALL file. + +A new test program, pngvalid, is provided in addition to pngtest. +pngvalid validates the arithmetic accuracy of the gamma correction +calculations and includes a number of validations of the file format. +A subset of the full range of tests is run when "make check" is done +(in the 'configure' build.) pngvalid also allows total allocated memory +usage to be evaluated and performs additional memory overwrite validation. + +Many changes to individual feature macros have been made. The following +are the changes most likely to be noticed by library builders who +configure libpng: + +1) All feature macros now have consistent naming: + +#define PNG_NO_feature turns the feature off +#define PNG_feature_SUPPORTED turns the feature on + +pnglibconf.h contains one line for each feature macro which is either: + +#define PNG_feature_SUPPORTED + +if the feature is supported or: + +/*#undef PNG_feature_SUPPORTED*/ + +if it is not. Library code consistently checks for the 'SUPPORTED' macro. +It does not, and libpng applications should not, check for the 'NO' macro +which will not normally be defined even if the feature is not supported. +The 'NO' macros are only used internally for setting or not setting the +corresponding 'SUPPORTED' macros. + +Compatibility with the old names is provided as follows: + +PNG_INCH_CONVERSIONS turns on PNG_INCH_CONVERSIONS_SUPPORTED + +And the following definitions disable the corresponding feature: + +PNG_SETJMP_NOT_SUPPORTED disables SETJMP +PNG_READ_TRANSFORMS_NOT_SUPPORTED disables READ_TRANSFORMS +PNG_NO_READ_COMPOSITED_NODIV disables READ_COMPOSITE_NODIV +PNG_WRITE_TRANSFORMS_NOT_SUPPORTED disables WRITE_TRANSFORMS +PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED disables READ_ANCILLARY_CHUNKS +PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED disables WRITE_ANCILLARY_CHUNKS + +Library builders should remove use of the above, inconsistent, names. + +2) Warning and error message formatting was previously conditional on +the STDIO feature. The library has been changed to use the +CONSOLE_IO feature instead. This means that if CONSOLE_IO is disabled +the library no longer uses the printf(3) functions, even though the +default read/write implementations use (FILE) style stdio.h functions. + +3) Three feature macros now control the fixed/floating point decisions: + +PNG_FLOATING_POINT_SUPPORTED enables the floating point APIs + +PNG_FIXED_POINT_SUPPORTED enables the fixed point APIs; however, in +practice these are normally required internally anyway (because the PNG +file format is fixed point), therefore in most cases PNG_NO_FIXED_POINT +merely stops the function from being exported. + +PNG_FLOATING_ARITHMETIC_SUPPORTED chooses between the internal floating +point implementation or the fixed point one. Typically the fixed point +implementation is larger and slower than the floating point implementation +on a system that supports floating point; however, it may be faster on a +system which lacks floating point hardware and therefore uses a software +emulation. + +4) Added PNG_{READ,WRITE}_INT_FUNCTIONS_SUPPORTED. This allows the +functions to read and write ints to be disabled independently of +PNG_USE_READ_MACROS, which allows libpng to be built with the functions +even though the default is to use the macros - this allows applications +to choose at app buildtime whether or not to use macros (previously +impossible because the functions weren't in the default build.) + +.SH XII. Changes to Libpng from version 1.5.x to 1.6.x + +A "simplified API" has been added (see documentation in png.h and a simple +example in contrib/examples/pngtopng.c). The new publicly visible API +includes the following: + + macros: + PNG_FORMAT_* + PNG_IMAGE_* + structures: + png_control + png_image + read functions + png_image_begin_read_from_file() + png_image_begin_read_from_stdio() + png_image_begin_read_from_memory() + png_image_finish_read() + png_image_free() + write functions + png_image_write_to_file() + png_image_write_to_memory() + png_image_write_to_stdio() + +Starting with libpng-1.6.0, you can configure libpng to prefix all exported +symbols, using the PNG_PREFIX macro. + +We no longer include string.h in png.h. The include statement has been moved +to pngpriv.h, where it is not accessible by applications. Applications that +need access to information in string.h must add an '#include ' +directive. It does not matter whether this is placed prior to or after +the '#include "png.h"' directive. + +The following API are now DEPRECATED: + png_info_init_3() + png_convert_to_rfc1123() which has been replaced + with png_convert_to_rfc1123_buffer() + png_malloc_default() + png_free_default() + png_reset_zstream() + +The following have been removed: + png_get_io_chunk_name(), which has been replaced + with png_get_io_chunk_type(). The new + function returns a 32-bit integer instead of + a string. + The png_sizeof(), png_strlen(), png_memcpy(), png_memcmp(), and + png_memset() macros are no longer used in the libpng sources and + have been removed. These had already been made invisible to applications + (i.e., defined in the private pngpriv.h header file) since libpng-1.5.0. + +The signatures of many exported functions were changed, such that + png_structp became png_structrp or png_const_structrp + png_infop became png_inforp or png_const_inforp +where "rp" indicates a "restricted pointer". + +Dropped support for 16-bit platforms. The support for FAR/far types has +been eliminated and the definition of png_alloc_size_t is now controlled +by a flag so that 'small size_t' systems can select it if necessary. + +Error detection in some chunks has improved; in particular the iCCP chunk +reader now does pretty complete validation of the basic format. Some bad +profiles that were previously accepted are now accepted with a warning or +rejected, depending upon the png_set_benign_errors() setting, in particular +the very old broken Microsoft/HP 3144-byte sRGB profile. Starting with +libpng-1.6.11, recognizing and checking sRGB profiles can be avoided by +means of + + #if defined(PNG_SKIP_sRGB_CHECK_PROFILE) && \ + defined(PNG_SET_OPTION_SUPPORTED) + png_set_option(png_ptr, PNG_SKIP_sRGB_CHECK_PROFILE, + PNG_OPTION_ON); + #endif + +It's not a good idea to do this if you are using the "simplified API", +which needs to be able to recognize sRGB profiles conveyed via the iCCP +chunk. + +The PNG spec requirement that only grayscale profiles may appear in images +with color type 0 or 4 and that even if the image only contains gray pixels, +only RGB profiles may appear in images with color type 2, 3, or 6, is now +enforced. The sRGB chunk is allowed to appear in images with any color type +and is interpreted by libpng to convey a one-tracer-curve gray profile or a +three-tracer-curve RGB profile as appropriate. + +Libpng 1.5.x erroneously used /MD for Debug DLL builds; if you used the debug +builds in your app and you changed your app to use /MD you will need to +change it back to /MDd for libpng 1.6.x. + +Prior to libpng-1.6.0 a warning would be issued if the iTXt chunk contained +an empty language field or an empty translated keyword. Both of these +are allowed by the PNG specification, so these warnings are no longer issued. + +The library now issues an error if the application attempts to set a +transform after it calls png_read_update_info() or if it attempts to call +both png_read_update_info() and png_start_read_image() or to call either +of them more than once. + +The default condition for benign_errors is now to treat benign errors as +warnings while reading and as errors while writing. + +The library now issues a warning if both background processing and RGB to +gray are used when gamma correction happens. As with previous versions of +the library the results are numerically very incorrect in this case. + +There are some minor arithmetic changes in some transforms such as +png_set_background(), that might be detected by certain regression tests. + +Unknown chunk handling has been improved internally, without any API change. +This adds more correct option control of the unknown handling, corrects +a pre-existing bug where the per-chunk 'keep' setting is ignored, and makes +it possible to skip IDAT chunks in the sequential reader. + +The machine-generated configure files are no longer included in branches +libpng16 and later of the GIT repository. They continue to be included +in the tarball releases, however. + +Libpng-1.6.0 through 1.6.2 used the CMF bytes at the beginning of the IDAT +stream to set the size of the sliding window for reading instead of using the +default 32-kbyte sliding window size. It was discovered that there are +hundreds of PNG files in the wild that have incorrect CMF bytes that caused +zlib to issue the "invalid distance too far back" error and reject the file. +Libpng-1.6.3 and later calculate their own safe CMF from the image dimensions, +provide a way to revert to the libpng-1.5.x behavior (ignoring the CMF bytes +and using a 32-kbyte sliding window), by using + + png_set_option(png_ptr, PNG_MAXIMUM_INFLATE_WINDOW, + PNG_OPTION_ON); + +and provide a tool (contrib/tools/pngfix) for rewriting a PNG file while +optimizing the CMF bytes in its IDAT chunk correctly. + +Libpng-1.6.0 and libpng-1.6.1 wrote uncompressed iTXt chunks with the wrong +length, which resulted in PNG files that cannot be read beyond the bad iTXt +chunk. This error was fixed in libpng-1.6.3, and a tool (called +contrib/tools/png-fix-itxt) has been added to the libpng distribution. + +Starting with libpng-1.6.17, the PNG_SAFE_LIMITS macro was eliminated +and safe limits are used by default (users who need larger limits +can still override them at compile time or run time, as described above). + +The new limits are + default spec limit + png_user_width_max 1,000,000 2,147,483,647 + png_user_height_max 1,000,000 2,147,483,647 + png_user_chunk_cache_max 128 unlimited + png_user_chunk_malloc_max 8,000,000 unlimited + +Starting with libpng-1.6.18, a PNG_RELEASE_BUILD macro was added, which allows +library builders to control compilation for an installed system (a release build). +It can be set for testing debug or beta builds to ensure that they will compile +when the build type is switched to RC or STABLE. In essence this overrides the +PNG_LIBPNG_BUILD_BASE_TYPE definition which is not directly user controllable. + +Starting with libpng-1.6.19, attempting to set an over-length PLTE chunk +is an error. Previously this requirement of the PNG specification was not +enforced, and the palette was always limited to 256 entries. An over-length +PLTE chunk found in an input PNG is silently truncated. + +.SH XIII. Detecting libpng + +The png_get_io_ptr() function has been present since libpng-0.88, has never +changed, and is unaffected by conditional compilation macros. It is the +best choice for use in configure scripts for detecting the presence of any +libpng version since 0.88. In an autoconf "configure.in" you could use + + AC_CHECK_LIB(png, png_get_io_ptr, ... + +.SH XV. Source code repository + +Since about February 2009, version 1.2.34, libpng has been under "git" source +control. The git repository was built from old libpng-x.y.z.tar.gz files +going back to version 0.70. You can access the git repository (read only) +at + + git://git.code.sf.net/p/libpng/code + +or you can browse it with a web browser by selecting the "code" button at + + https://sourceforge.net/projects/libpng + +Patches can be sent to glennrp at users.sourceforge.net or to +png-mng-implement at lists.sourceforge.net or you can upload them to +the libpng bug tracker at + + http://libpng.sourceforge.net + +We also accept patches built from the tar or zip distributions, and +simple verbal discriptions of bug fixes, reported either to the +SourceForge bug tracker, to the png-mng-implement at lists.sf.net +mailing list, or directly to glennrp. + +.SH XV. Coding style + +Our coding style is similar to the "Allman" style +(See http://en.wikipedia.org/wiki/Indent_style#Allman_style), with curly +braces on separate lines: + + if (condition) + { + action; + } + + else if (another condition) + { + another action; + } + +The braces can be omitted from simple one-line actions: + + if (condition) + return (0); + +We use 3-space indentation, except for continued statements which +are usually indented the same as the first line of the statement +plus four more spaces. + +For macro definitions we use 2-space indentation, always leaving the "#" +in the first column. + + #ifndef PNG_NO_FEATURE + # ifndef PNG_FEATURE_SUPPORTED + # define PNG_FEATURE_SUPPORTED + # endif + #endif + +Comments appear with the leading "/*" at the same indentation as +the statement that follows the comment: + + /* Single-line comment */ + statement; + + /* This is a multiple-line + * comment. + */ + statement; + +Very short comments can be placed after the end of the statement +to which they pertain: + + statement; /* comment */ + +We don't use C++ style ("//") comments. We have, however, +used them in the past in some now-abandoned MMX assembler +code. + +Functions and their curly braces are not indented, and +exported functions are marked with PNGAPI: + + /* This is a public function that is visible to + * application programmers. It does thus-and-so. + */ + void PNGAPI + png_exported_function(png_ptr, png_info, foo) + { + body; + } + +The return type and decorations are placed on a separate line +ahead of the function name, as illustrated above. + +The prototypes for all exported functions appear in png.h, +above the comment that says + + /* Maintainer: Put new public prototypes here ... */ + +We mark all non-exported functions with "/* PRIVATE */"": + + void /* PRIVATE */ + png_non_exported_function(png_ptr, png_info, foo) + { + body; + } + +The prototypes for non-exported functions (except for those in +pngtest) appear in pngpriv.h above the comment that says + + /* Maintainer: Put new private prototypes here ^ */ + +To avoid polluting the global namespace, the names of all exported +functions and variables begin with "png_", and all publicly visible C +preprocessor macros begin with "PNG". We request that applications that +use libpng *not* begin any of their own symbols with either of these strings. + +We put a space after the "sizeof" operator and we omit the +optional parentheses around its argument when the argument +is an expression, not a type name, and we always enclose the +sizeof operator, with its argument, in parentheses: + + (sizeof (png_uint_32)) + (sizeof array) + +Prior to libpng-1.6.0 we used a "png_sizeof()" macro, formatted as +though it were a function. + +Control keywords if, for, while, and switch are always followed by a space +to distinguish them from function calls, which have no trailing space. + +We put a space after each comma and after each semicolon +in "for" statements, and we put spaces before and after each +C binary operator and after "for" or "while", and before +"?". We don't put a space between a typecast and the expression +being cast, nor do we put one between a function name and the +left parenthesis that follows it: + + for (i = 2; i > 0; \-\-i) + y[i] = a(x) + (int)b; + +We prefer #ifdef and #ifndef to #if defined() and #if !defined() +when there is only one macro being tested. We always use parentheses +with "defined". + +We express integer constants that are used as bit masks in hex format, +with an even number of lower-case hex digits, and to make them unsigned +(e.g., 0x00U, 0xffU, 0x0100U) and long if they are greater than 0x7fff +(e.g., 0xffffUL). + +We prefer to use underscores rather than camelCase in names, except +for a few type names that we inherit from zlib.h. + +We prefer "if (something != 0)" and "if (something == 0)" +over "if (something)" and if "(!something)", respectively. + +We do not use the TAB character for indentation in the C sources. + +Lines do not exceed 80 characters. + +Other rules can be inferred by inspecting the libpng source. + +.SH XVI. Y2K Compliance in libpng + +Since the PNG Development group is an ad-hoc body, we can't make +an official declaration. + +This is your unofficial assurance that libpng from version 0.71 and +upward through 1.6.23 are Y2K compliant. It is my belief that earlier +versions were also Y2K compliant. + +Libpng only has two year fields. One is a 2-byte unsigned integer +that will hold years up to 65535. The other, which is deprecated, +holds the date in text format, and will hold years up to 9999. + +The integer is + "png_uint_16 year" in png_time_struct. + +The string is + "char time_buffer[29]" in png_struct. This is no longer used +in libpng-1.6.x and will be removed from libpng-1.7.0. + +There are seven time-related functions: + + png_convert_to_rfc_1123_buffer() in png.c + (formerly png_convert_to_rfc_1152() in error, and + also formerly png_convert_to_rfc_1123()) + png_convert_from_struct_tm() in pngwrite.c, called + in pngwrite.c + png_convert_from_time_t() in pngwrite.c + png_get_tIME() in pngget.c + png_handle_tIME() in pngrutil.c, called in pngread.c + png_set_tIME() in pngset.c + png_write_tIME() in pngwutil.c, called in pngwrite.c + +All appear to handle dates properly in a Y2K environment. The +png_convert_from_time_t() function calls gmtime() to convert from system +clock time, which returns (year - 1900), which we properly convert to +the full 4-digit year. There is a possibility that applications using +libpng are not passing 4-digit years into the png_convert_to_rfc_1123() +function, or that they are incorrectly passing only a 2-digit year +instead of "year - 1900" into the png_convert_from_struct_tm() function, +but this is not under our control. The libpng documentation has always +stated that it works with 4-digit years, and the APIs have been +documented as such. + +The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned +integer to hold the year, and can hold years as large as 65535. + +zlib, upon which libpng depends, is also Y2K compliant. It contains +no date-related code. + + + Glenn Randers-Pehrson + libpng maintainer + PNG Development Group + +.SH NOTE + +Note about libpng version numbers: + +Due to various miscommunications, unforeseen code incompatibilities +and occasional factors outside the authors' control, version numbering +on the library has not always been consistent and straightforward. +The following table summarizes matters since version 0.89c, which was +the first widely used release: + + source png.h png.h shared-lib + version string int version + ------- ------ ----- ---------- + 0.89c "1.0 beta 3" 0.89 89 1.0.89 + 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90] + 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95] + 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96] + 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97] + 0.97c 0.97 97 2.0.97 + 0.98 0.98 98 2.0.98 + 0.99 0.99 98 2.0.99 + 0.99a-m 0.99 99 2.0.99 + 1.00 1.00 100 2.1.0 [100 should be 10000] + 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000] + 1.0.1 png.h string is 10001 2.1.0 + 1.0.1a-e identical to the 10002 from here on, the shared library + 1.0.2 source version) 10002 is 2.V where V is the source code + 1.0.2a-b 10003 version, except as noted. + 1.0.3 10003 + 1.0.3a-d 10004 + 1.0.4 10004 + 1.0.4a-f 10005 + 1.0.5 (+ 2 patches) 10005 + 1.0.5a-d 10006 + 1.0.5e-r 10100 (not source compatible) + 1.0.5s-v 10006 (not binary compatible) + 1.0.6 (+ 3 patches) 10006 (still binary incompatible) + 1.0.6d-f 10007 (still binary incompatible) + 1.0.6g 10007 + 1.0.6h 10007 10.6h (testing xy.z so-numbering) + 1.0.6i 10007 10.6i + 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0) + 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible) + 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible) + 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible) + 1.0.7 1 10007 (still compatible) + ... + 1.0.19 10 10019 10.so.0.19[.0] + ... + 1.2.56 13 10256 12.so.0.56[.0] + ... + 1.5.27 15 10527 15.so.15.27[.0] + ... + 1.6.23 16 10623 16.so.16.23[.0] + +Henceforth the source version will match the shared-library minor +and patch numbers; the shared-library major version number will be +used for changes in backward compatibility, as it is intended. The +PNG_PNGLIB_VER macro, which is not used within libpng but is available +for applications, is an unsigned integer of the form xyyzz corresponding +to the source version x.y.z (leading zeros in y and z). Beta versions +were given the previous public release number plus a letter, until +version 1.0.6j; from then on they were given the upcoming public +release number plus "betaNN" or "rcNN". + +.SH "SEE ALSO" +.IR libpngpf(3) ", " png(5) +.LP +.IR libpng : +.IP +http://libpng.sourceforge.net (follow the [DOWNLOAD] link) +http://www.libpng.org/pub/png + +.LP +.IR zlib : +.IP +(generally) at the same location as +.I libpng +or at +.br +ftp://ftp.info-zip.org/pub/infozip/zlib + +.LP +.IR PNG specification: RFC 2083 +.IP +(generally) at the same location as +.I libpng +or at +.br +ftp://ftp.rfc-editor.org:/in-notes/rfc2083.txt +.br +or (as a W3C Recommendation) at +.br +http://www.w3.org/TR/REC-png.html + +.LP +In the case of any inconsistency between the PNG specification +and this library, the specification takes precedence. + +.SH AUTHORS +This man page: Glenn Randers-Pehrson + + +The contributing authors would like to thank all those who helped +with testing, bug fixes, and patience. This wouldn't have been +possible without all of you. + +Thanks to Frank J. T. Wojcik for helping with the documentation. + +Libpng version 1.6.23 - June 9, 2016: +Initially created in 1995 by Guy Eric Schalnat, then of Group 42, Inc. +Currently maintained by Glenn Randers-Pehrson (glennrp at users.sourceforge.net). + +Supported by the PNG development group +.br +png-mng-implement at lists.sf.net +(subscription required; visit +png-mng-implement at lists.sourceforge.net (subscription required; visit +https://lists.sourceforge.net/lists/listinfo/png-mng-implement +to subscribe). + +.SH NOTICES: + +This copy of the libpng notices is provided for your convenience. In case of +any discrepancy between this copy and the notices in the file png.h that is +included in the libpng distribution, the latter shall prevail. + +COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: + +If you modify libpng you may insert additional notices immediately following +this sentence. + +This code is released under the libpng license. + +libpng versions 1.0.7, July 1, 2000 through 1.6.23, June 9, 2016 are +Copyright (c) 2000-2002, 2004, 2006-2016 Glenn Randers-Pehrson, are +derived from libpng-1.0.6, and are distributed according to the same +disclaimer and license as libpng-1.0.6 with the following individuals +added to the list of Contributing Authors: + + Simon-Pierre Cadieux + Eric S. Raymond + Mans Rullgard + Cosmin Truta + Gilles Vollant + James Yu + +and with the following additions to the disclaimer: + + There is no warranty against interference with your enjoyment of the + library or against infringement. There is no warranty that our + efforts or the library will fulfill any of your particular purposes + or needs. This library is provided with all faults, and the entire + risk of satisfactory quality, performance, accuracy, and effort is with + the user. + +Some files in the "contrib" directory and some configure-generated +files that are distributed with libpng have other copyright owners and +are released under other open source licenses. + +libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are +Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from +libpng-0.96, and are distributed according to the same disclaimer and +license as libpng-0.96, with the following individuals added to the list +of Contributing Authors: + + Tom Lane + Glenn Randers-Pehrson + Willem van Schaik + +libpng versions 0.89, June 1996, through 0.96, May 1997, are +Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88, +and are distributed according to the same disclaimer and license as +libpng-0.88, with the following individuals added to the list of +Contributing Authors: + + John Bowler + Kevin Bracey + Sam Bushell + Magnus Holmgren + Greg Roelofs + Tom Tanner + +Some files in the "scripts" directory have other copyright owners +but are released under this license. + +libpng versions 0.5, May 1995, through 0.88, January 1996, are +Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + +For the purposes of this copyright and license, "Contributing Authors" +is defined as the following set of individuals: + + Andreas Dilger + Dave Martindale + Guy Eric Schalnat + Paul Schmidt + Tim Wegner + +The PNG Reference Library is supplied "AS IS". The Contributing Authors +and Group 42, Inc. disclaim all warranties, expressed or implied, +including, without limitation, the warranties of merchantability and of +fitness for any purpose. The Contributing Authors and Group 42, Inc. +assume no liability for direct, indirect, incidental, special, exemplary, +or consequential damages, which may result from the use of the PNG +Reference Library, even if advised of the possibility of such damage. + +Permission is hereby granted to use, copy, modify, and distribute this +source code, or portions hereof, for any purpose, without fee, subject +to the following restrictions: + + 1. The origin of this source code must not be misrepresented. + + 2. Altered versions must be plainly marked as such and must not + be misrepresented as being the original source. + + 3. This Copyright notice may not be removed or altered from any + source or altered source distribution. + +The Contributing Authors and Group 42, Inc. specifically permit, without +fee, and encourage the use of this source code as a component to +supporting the PNG file format in commercial products. If you use this +source code in a product, acknowledgment is not required but would be +appreciated. + +END OF COPYRIGHT NOTICE, DISCLAIMER, and LICENSE. + +TRADEMARK: + +The name "libpng" has not been registered by the Copyright owner +as a trademark in any jurisdiction. However, because libpng has +been distributed and maintained world-wide, continually since 1995, +the Copyright owner claims "common-law trademark protection" in any +jurisdiction where common-law trademark is recognized. + +OSI CERTIFICATION: + +Libpng is OSI Certified Open Source Software. OSI Certified Open Source is +a certification mark of the Open Source Initiative. OSI has not addressed +the additional disclaimers inserted at version 1.0.7. + +EXPORT CONTROL: + +The Copyright owner believes that the Export Control Classification +Number (ECCN) for libpng is EAR99, which means not subject to export +controls or International Traffic in Arms Regulations (ITAR) because +it is open source, publicly available software, that does not contain +any encryption software. See the EAR, paragraphs 734.3(b)(3) and +734.7(b). + +A "png_get_copyright" function is available, for convenient use in "about" +boxes and the like: + + printf("%s", png_get_copyright(NULL)); + +Also, the PNG logo (in PNG format, of course) is supplied in the +files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). + +Glenn Randers-Pehrson +glennrp at users.sourceforge.net +June 9, 2016 + +.\" end of man page + diff --git a/source/Irrlicht/libpng/libpng.pc.in b/source/Irrlicht/libpng/libpng.pc.in new file mode 100644 index 00000000..05ad81ee --- /dev/null +++ b/source/Irrlicht/libpng/libpng.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@ + +Name: libpng +Description: Loads and saves PNG files +Version: @PNGLIB_VERSION@ +Libs: -L${libdir} -lpng@PNGLIB_MAJOR@@PNGLIB_MINOR@ +Libs.private: @LIBS@ +Cflags: -I${includedir} diff --git a/source/Irrlicht/libpng/libpngpf.3 b/source/Irrlicht/libpng/libpngpf.3 new file mode 100644 index 00000000..9b675246 --- /dev/null +++ b/source/Irrlicht/libpng/libpngpf.3 @@ -0,0 +1,18 @@ +.TH LIBPNGPF 3 "June 9, 2016" +.SH NAME +libpng \- Portable Network Graphics (PNG) Reference Library 1.6.23 +(private functions) +.SH SYNOPSIS +\fB#include \fI"pngpriv.h" + +\fBAs of libpng version \fP\fI1.5.1\fP\fB, this section is no longer \fP\fImaintained\fP\fB, now that the private function prototypes are hidden in pngpriv.h and not accessible to applications. Look in pngpriv.h for the prototypes and a short description of each \fIfunction. + +.SH DESCRIPTION +The functions previously listed here are used privately by libpng and are not +available for use by applications. They are not "exported" to applications +using shared libraries. + +.SH SEE ALSO +.BR "png"(5), " libpng"(3), " zlib"(3), " deflate"(5), " " and " zlib"(5) +.SH AUTHOR +Glenn Randers-Pehrson diff --git a/source/Irrlicht/libpng/png.5 b/source/Irrlicht/libpng/png.5 new file mode 100644 index 00000000..7c0b9a46 --- /dev/null +++ b/source/Irrlicht/libpng/png.5 @@ -0,0 +1,74 @@ +.TH PNG 5 "June 9, 2016" +.SH NAME +png \- Portable Network Graphics (PNG) format +.SH DESCRIPTION +PNG (Portable Network Graphics) is an extensible file format for the +lossless, portable, well-compressed storage of raster images. PNG provides +a patent-free replacement for GIF and can also replace many +common uses of TIFF. Indexed-color, grayscale, and truecolor images are +supported, plus an optional alpha channel. Sample depths range from +1 to 16 bits. +.br + +PNG is designed to work well in online viewing applications, such as the +World Wide Web, so it is fully streamable with a progressive display +option. PNG is robust, providing both full file integrity checking and +fast, simple detection of common transmission errors. Also, PNG can store +gamma and chromaticity data for improved color matching on heterogeneous +platforms. + +.SH "SEE ALSO" +.BR "libpng"(3), " libpngpf"(3), " zlib"(3), " deflate"(5), " " and " zlib"(5) +.LP +PNG specification (second edition), November 2003: +.IP +.br + 8) + png_error(png_ptr, "Too many bytes for PNG signature"); + + png_ptr->sig_bytes = (png_byte)nb; +} + +/* Checks whether the supplied bytes match the PNG signature. We allow + * checking less than the full 8-byte signature so that those apps that + * already read the first few bytes of a file to determine the file type + * can simply check the remaining bytes for extra assurance. Returns + * an integer less than, equal to, or greater than zero if sig is found, + * respectively, to be less than, to match, or be greater than the correct + * PNG signature (this is the same behavior as strcmp, memcmp, etc). + */ +int PNGAPI +png_sig_cmp(png_const_bytep sig, png_size_t start, png_size_t num_to_check) +{ + png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + + if (num_to_check > 8) + num_to_check = 8; + + else if (num_to_check < 1) + return (-1); + + if (start > 7) + return (-1); + + if (start + num_to_check > 8) + num_to_check = 8 - start; + + return ((int)(memcmp(&sig[start], &png_signature[start], num_to_check))); +} + +#endif /* READ */ + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +/* Function to allocate memory for zlib */ +PNG_FUNCTION(voidpf /* PRIVATE */, +png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED) +{ + png_alloc_size_t num_bytes = size; + + if (png_ptr == NULL) + return NULL; + + if (items >= (~(png_alloc_size_t)0)/size) + { + png_warning (png_voidcast(png_structrp, png_ptr), + "Potential overflow in png_zalloc()"); + return NULL; + } + + num_bytes *= items; + return png_malloc_warn(png_voidcast(png_structrp, png_ptr), num_bytes); +} + +/* Function to free memory for zlib */ +void /* PRIVATE */ +png_zfree(voidpf png_ptr, voidpf ptr) +{ + png_free(png_voidcast(png_const_structrp,png_ptr), ptr); +} + +/* Reset the CRC variable to 32 bits of 1's. Care must be taken + * in case CRC is > 32 bits to leave the top bits 0. + */ +void /* PRIVATE */ +png_reset_crc(png_structrp png_ptr) +{ + /* The cast is safe because the crc is a 32-bit value. */ + png_ptr->crc = (png_uint_32)crc32(0, Z_NULL, 0); +} + +/* Calculate the CRC over a section of data. We can only pass as + * much data to this routine as the largest single buffer size. We + * also check that this data will actually be used before going to the + * trouble of calculating it. + */ +void /* PRIVATE */ +png_calculate_crc(png_structrp png_ptr, png_const_bytep ptr, png_size_t length) +{ + int need_crc = 1; + + if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0) + { + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == + (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) + need_crc = 0; + } + + else /* critical */ + { + if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0) + need_crc = 0; + } + + /* 'uLong' is defined in zlib.h as unsigned long; this means that on some + * systems it is a 64-bit value. crc32, however, returns 32 bits so the + * following cast is safe. 'uInt' may be no more than 16 bits, so it is + * necessary to perform a loop here. + */ + if (need_crc != 0 && length > 0) + { + uLong crc = png_ptr->crc; /* Should never issue a warning */ + + do + { + uInt safe_length = (uInt)length; +#ifndef __COVERITY__ + if (safe_length == 0) + safe_length = (uInt)-1; /* evil, but safe */ +#endif + + crc = crc32(crc, ptr, safe_length); + + /* The following should never issue compiler warnings; if they do the + * target system has characteristics that will probably violate other + * assumptions within the libpng code. + */ + ptr += safe_length; + length -= safe_length; + } + while (length > 0); + + /* And the following is always safe because the crc is only 32 bits. */ + png_ptr->crc = (png_uint_32)crc; + } +} + +/* Check a user supplied version number, called from both read and write + * functions that create a png_struct. + */ +int +png_user_version_check(png_structrp png_ptr, png_const_charp user_png_ver) +{ + /* Libpng versions 1.0.0 and later are binary compatible if the version + * string matches through the second '.'; we must recompile any + * applications that use any older library version. + */ + + if (user_png_ver != NULL) + { + int i = -1; + int found_dots = 0; + + do + { + i++; + if (user_png_ver[i] != PNG_LIBPNG_VER_STRING[i]) + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + if (user_png_ver[i] == '.') + found_dots++; + } while (found_dots < 2 && user_png_ver[i] != 0 && + PNG_LIBPNG_VER_STRING[i] != 0); + } + + else + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + + if ((png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) != 0) + { +#ifdef PNG_WARNINGS_SUPPORTED + size_t pos = 0; + char m[128]; + + pos = png_safecat(m, (sizeof m), pos, + "Application built with libpng-"); + pos = png_safecat(m, (sizeof m), pos, user_png_ver); + pos = png_safecat(m, (sizeof m), pos, " but running with "); + pos = png_safecat(m, (sizeof m), pos, PNG_LIBPNG_VER_STRING); + PNG_UNUSED(pos) + + png_warning(png_ptr, m); +#endif + +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags = 0; +#endif + + return 0; + } + + /* Success return. */ + return 1; +} + +/* Generic function to create a png_struct for either read or write - this + * contains the common initialization. + */ +PNG_FUNCTION(png_structp /* PRIVATE */, +png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) +{ + png_struct create_struct; +# ifdef PNG_SETJMP_SUPPORTED + jmp_buf create_jmp_buf; +# endif + + /* This temporary stack-allocated structure is used to provide a place to + * build enough context to allow the user provided memory allocator (if any) + * to be called. + */ + memset(&create_struct, 0, (sizeof create_struct)); + + /* Added at libpng-1.2.6 */ +# ifdef PNG_USER_LIMITS_SUPPORTED + create_struct.user_width_max = PNG_USER_WIDTH_MAX; + create_struct.user_height_max = PNG_USER_HEIGHT_MAX; + +# ifdef PNG_USER_CHUNK_CACHE_MAX + /* Added at libpng-1.2.43 and 1.4.0 */ + create_struct.user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX; +# endif + +# ifdef PNG_USER_CHUNK_MALLOC_MAX + /* Added at libpng-1.2.43 and 1.4.1, required only for read but exists + * in png_struct regardless. + */ + create_struct.user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX; +# endif +# endif + + /* The following two API calls simply set fields in png_struct, so it is safe + * to do them now even though error handling is not yet set up. + */ +# ifdef PNG_USER_MEM_SUPPORTED + png_set_mem_fn(&create_struct, mem_ptr, malloc_fn, free_fn); +# else + PNG_UNUSED(mem_ptr) + PNG_UNUSED(malloc_fn) + PNG_UNUSED(free_fn) +# endif + + /* (*error_fn) can return control to the caller after the error_ptr is set, + * this will result in a memory leak unless the error_fn does something + * extremely sophisticated. The design lacks merit but is implicit in the + * API. + */ + png_set_error_fn(&create_struct, error_ptr, error_fn, warn_fn); + +# ifdef PNG_SETJMP_SUPPORTED + if (!setjmp(create_jmp_buf)) +# endif + { +# ifdef PNG_SETJMP_SUPPORTED + /* Temporarily fake out the longjmp information until we have + * successfully completed this function. This only works if we have + * setjmp() support compiled in, but it is safe - this stuff should + * never happen. + */ + create_struct.jmp_buf_ptr = &create_jmp_buf; + create_struct.jmp_buf_size = 0; /*stack allocation*/ + create_struct.longjmp_fn = longjmp; +# endif + /* Call the general version checker (shared with read and write code): + */ + if (png_user_version_check(&create_struct, user_png_ver) != 0) + { + png_structrp png_ptr = png_voidcast(png_structrp, + png_malloc_warn(&create_struct, (sizeof *png_ptr))); + + if (png_ptr != NULL) + { + /* png_ptr->zstream holds a back-pointer to the png_struct, so + * this can only be done now: + */ + create_struct.zstream.zalloc = png_zalloc; + create_struct.zstream.zfree = png_zfree; + create_struct.zstream.opaque = png_ptr; + +# ifdef PNG_SETJMP_SUPPORTED + /* Eliminate the local error handling: */ + create_struct.jmp_buf_ptr = NULL; + create_struct.jmp_buf_size = 0; + create_struct.longjmp_fn = 0; +# endif + + *png_ptr = create_struct; + + /* This is the successful return point */ + return png_ptr; + } + } + } + + /* A longjmp because of a bug in the application storage allocator or a + * simple failure to allocate the png_struct. + */ + return NULL; +} + +/* Allocate the memory for an info_struct for the application. */ +PNG_FUNCTION(png_infop,PNGAPI +png_create_info_struct,(png_const_structrp png_ptr),PNG_ALLOCATED) +{ + png_inforp info_ptr; + + png_debug(1, "in png_create_info_struct"); + + if (png_ptr == NULL) + return NULL; + + /* Use the internal API that does not (or at least should not) error out, so + * that this call always returns ok. The application typically sets up the + * error handling *after* creating the info_struct because this is the way it + * has always been done in 'example.c'. + */ + info_ptr = png_voidcast(png_inforp, png_malloc_base(png_ptr, + (sizeof *info_ptr))); + + if (info_ptr != NULL) + memset(info_ptr, 0, (sizeof *info_ptr)); + + return info_ptr; +} + +/* This function frees the memory associated with a single info struct. + * Normally, one would use either png_destroy_read_struct() or + * png_destroy_write_struct() to free an info struct, but this may be + * useful for some applications. From libpng 1.6.0 this function is also used + * internally to implement the png_info release part of the 'struct' destroy + * APIs. This ensures that all possible approaches free the same data (all of + * it). + */ +void PNGAPI +png_destroy_info_struct(png_const_structrp png_ptr, png_infopp info_ptr_ptr) +{ + png_inforp info_ptr = NULL; + + png_debug(1, "in png_destroy_info_struct"); + + if (png_ptr == NULL) + return; + + if (info_ptr_ptr != NULL) + info_ptr = *info_ptr_ptr; + + if (info_ptr != NULL) + { + /* Do this first in case of an error below; if the app implements its own + * memory management this can lead to png_free calling png_error, which + * will abort this routine and return control to the app error handler. + * An infinite loop may result if it then tries to free the same info + * ptr. + */ + *info_ptr_ptr = NULL; + + png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); + memset(info_ptr, 0, (sizeof *info_ptr)); + png_free(png_ptr, info_ptr); + } +} + +/* Initialize the info structure. This is now an internal function (0.89) + * and applications using it are urged to use png_create_info_struct() + * instead. Use deprecated in 1.6.0, internal use removed (used internally it + * is just a memset). + * + * NOTE: it is almost inconceivable that this API is used because it bypasses + * the user-memory mechanism and the user error handling/warning mechanisms in + * those cases where it does anything other than a memset. + */ +PNG_FUNCTION(void,PNGAPI +png_info_init_3,(png_infopp ptr_ptr, png_size_t png_info_struct_size), + PNG_DEPRECATED) +{ + png_inforp info_ptr = *ptr_ptr; + + png_debug(1, "in png_info_init_3"); + + if (info_ptr == NULL) + return; + + if ((sizeof (png_info)) > png_info_struct_size) + { + *ptr_ptr = NULL; + /* The following line is why this API should not be used: */ + free(info_ptr); + info_ptr = png_voidcast(png_inforp, png_malloc_base(NULL, + (sizeof *info_ptr))); + if (info_ptr == NULL) + return; + *ptr_ptr = info_ptr; + } + + /* Set everything to 0 */ + memset(info_ptr, 0, (sizeof *info_ptr)); +} + +/* The following API is not called internally */ +void PNGAPI +png_data_freer(png_const_structrp png_ptr, png_inforp info_ptr, + int freer, png_uint_32 mask) +{ + png_debug(1, "in png_data_freer"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (freer == PNG_DESTROY_WILL_FREE_DATA) + info_ptr->free_me |= mask; + + else if (freer == PNG_USER_WILL_FREE_DATA) + info_ptr->free_me &= ~mask; + + else + png_error(png_ptr, "Unknown freer parameter in png_data_freer"); +} + +void PNGAPI +png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask, + int num) +{ + png_debug(1, "in png_free_data"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + +#ifdef PNG_TEXT_SUPPORTED + /* Free text item num or (if num == -1) all text items */ + if (info_ptr->text != 0 && + ((mask & PNG_FREE_TEXT) & info_ptr->free_me) != 0) + { + if (num != -1) + { + png_free(png_ptr, info_ptr->text[num].key); + info_ptr->text[num].key = NULL; + } + + else + { + int i; + + for (i = 0; i < info_ptr->num_text; i++) + png_free(png_ptr, info_ptr->text[i].key); + + png_free(png_ptr, info_ptr->text); + info_ptr->text = NULL; + info_ptr->num_text = 0; + } + } +#endif + +#ifdef PNG_tRNS_SUPPORTED + /* Free any tRNS entry */ + if (((mask & PNG_FREE_TRNS) & info_ptr->free_me) != 0) + { + info_ptr->valid &= ~PNG_INFO_tRNS; + png_free(png_ptr, info_ptr->trans_alpha); + info_ptr->trans_alpha = NULL; + info_ptr->num_trans = 0; + } +#endif + +#ifdef PNG_sCAL_SUPPORTED + /* Free any sCAL entry */ + if (((mask & PNG_FREE_SCAL) & info_ptr->free_me) != 0) + { + png_free(png_ptr, info_ptr->scal_s_width); + png_free(png_ptr, info_ptr->scal_s_height); + info_ptr->scal_s_width = NULL; + info_ptr->scal_s_height = NULL; + info_ptr->valid &= ~PNG_INFO_sCAL; + } +#endif + +#ifdef PNG_pCAL_SUPPORTED + /* Free any pCAL entry */ + if (((mask & PNG_FREE_PCAL) & info_ptr->free_me) != 0) + { + png_free(png_ptr, info_ptr->pcal_purpose); + png_free(png_ptr, info_ptr->pcal_units); + info_ptr->pcal_purpose = NULL; + info_ptr->pcal_units = NULL; + + if (info_ptr->pcal_params != NULL) + { + int i; + + for (i = 0; i < info_ptr->pcal_nparams; i++) + png_free(png_ptr, info_ptr->pcal_params[i]); + + png_free(png_ptr, info_ptr->pcal_params); + info_ptr->pcal_params = NULL; + } + info_ptr->valid &= ~PNG_INFO_pCAL; + } +#endif + +#ifdef PNG_iCCP_SUPPORTED + /* Free any profile entry */ + if (((mask & PNG_FREE_ICCP) & info_ptr->free_me) != 0) + { + png_free(png_ptr, info_ptr->iccp_name); + png_free(png_ptr, info_ptr->iccp_profile); + info_ptr->iccp_name = NULL; + info_ptr->iccp_profile = NULL; + info_ptr->valid &= ~PNG_INFO_iCCP; + } +#endif + +#ifdef PNG_sPLT_SUPPORTED + /* Free a given sPLT entry, or (if num == -1) all sPLT entries */ + if (info_ptr->splt_palettes != 0 && + ((mask & PNG_FREE_SPLT) & info_ptr->free_me) != 0) + { + if (num != -1) + { + png_free(png_ptr, info_ptr->splt_palettes[num].name); + png_free(png_ptr, info_ptr->splt_palettes[num].entries); + info_ptr->splt_palettes[num].name = NULL; + info_ptr->splt_palettes[num].entries = NULL; + } + + else + { + int i; + + for (i = 0; i < info_ptr->splt_palettes_num; i++) + { + png_free(png_ptr, info_ptr->splt_palettes[i].name); + png_free(png_ptr, info_ptr->splt_palettes[i].entries); + } + + png_free(png_ptr, info_ptr->splt_palettes); + info_ptr->splt_palettes = NULL; + info_ptr->splt_palettes_num = 0; + info_ptr->valid &= ~PNG_INFO_sPLT; + } + } +#endif + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED + if (info_ptr->unknown_chunks != 0 && + ((mask & PNG_FREE_UNKN) & info_ptr->free_me) != 0) + { + if (num != -1) + { + png_free(png_ptr, info_ptr->unknown_chunks[num].data); + info_ptr->unknown_chunks[num].data = NULL; + } + + else + { + int i; + + for (i = 0; i < info_ptr->unknown_chunks_num; i++) + png_free(png_ptr, info_ptr->unknown_chunks[i].data); + + png_free(png_ptr, info_ptr->unknown_chunks); + info_ptr->unknown_chunks = NULL; + info_ptr->unknown_chunks_num = 0; + } + } +#endif + +#ifdef PNG_hIST_SUPPORTED + /* Free any hIST entry */ + if (((mask & PNG_FREE_HIST) & info_ptr->free_me) != 0) + { + png_free(png_ptr, info_ptr->hist); + info_ptr->hist = NULL; + info_ptr->valid &= ~PNG_INFO_hIST; + } +#endif + + /* Free any PLTE entry that was internally allocated */ + if (((mask & PNG_FREE_PLTE) & info_ptr->free_me) != 0) + { + png_free(png_ptr, info_ptr->palette); + info_ptr->palette = NULL; + info_ptr->valid &= ~PNG_INFO_PLTE; + info_ptr->num_palette = 0; + } + +#ifdef PNG_INFO_IMAGE_SUPPORTED + /* Free any image bits attached to the info structure */ + if (((mask & PNG_FREE_ROWS) & info_ptr->free_me) != 0) + { + if (info_ptr->row_pointers != 0) + { + png_uint_32 row; + for (row = 0; row < info_ptr->height; row++) + png_free(png_ptr, info_ptr->row_pointers[row]); + + png_free(png_ptr, info_ptr->row_pointers); + info_ptr->row_pointers = NULL; + } + info_ptr->valid &= ~PNG_INFO_IDAT; + } +#endif + + if (num != -1) + mask &= ~PNG_FREE_MUL; + + info_ptr->free_me &= ~mask; +} +#endif /* READ || WRITE */ + +/* This function returns a pointer to the io_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy() or png_read_destroy() are called. + */ +png_voidp PNGAPI +png_get_io_ptr(png_const_structrp png_ptr) +{ + if (png_ptr == NULL) + return (NULL); + + return (png_ptr->io_ptr); +} + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +# ifdef PNG_STDIO_SUPPORTED +/* Initialize the default input/output functions for the PNG file. If you + * use your own read or write routines, you can call either png_set_read_fn() + * or png_set_write_fn() instead of png_init_io(). If you have defined + * PNG_NO_STDIO or otherwise disabled PNG_STDIO_SUPPORTED, you must use a + * function of your own because "FILE *" isn't necessarily available. + */ +void PNGAPI +png_init_io(png_structrp png_ptr, png_FILE_p fp) +{ + png_debug(1, "in png_init_io"); + + if (png_ptr == NULL) + return; + + png_ptr->io_ptr = (png_voidp)fp; +} +# endif + +# ifdef PNG_SAVE_INT_32_SUPPORTED +/* PNG signed integers are saved in 32-bit 2's complement format. ANSI C-90 + * defines a cast of a signed integer to an unsigned integer either to preserve + * the value, if it is positive, or to calculate: + * + * (UNSIGNED_MAX+1) + integer + * + * Where UNSIGNED_MAX is the appropriate maximum unsigned value, so when the + * negative integral value is added the result will be an unsigned value + * correspnding to the 2's complement representation. + */ +void PNGAPI +png_save_int_32(png_bytep buf, png_int_32 i) +{ + png_save_uint_32(buf, i); +} +# endif + +# ifdef PNG_TIME_RFC1123_SUPPORTED +/* Convert the supplied time into an RFC 1123 string suitable for use in + * a "Creation Time" or other text-based time string. + */ +int PNGAPI +png_convert_to_rfc1123_buffer(char out[29], png_const_timep ptime) +{ + static PNG_CONST char short_months[12][4] = + {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + + if (out == NULL) + return 0; + + if (ptime->year > 9999 /* RFC1123 limitation */ || + ptime->month == 0 || ptime->month > 12 || + ptime->day == 0 || ptime->day > 31 || + ptime->hour > 23 || ptime->minute > 59 || + ptime->second > 60) + return 0; + + { + size_t pos = 0; + char number_buf[5]; /* enough for a four-digit year */ + +# define APPEND_STRING(string) pos = png_safecat(out, 29, pos, (string)) +# define APPEND_NUMBER(format, value)\ + APPEND_STRING(PNG_FORMAT_NUMBER(number_buf, format, (value))) +# define APPEND(ch) if (pos < 28) out[pos++] = (ch) + + APPEND_NUMBER(PNG_NUMBER_FORMAT_u, (unsigned)ptime->day); + APPEND(' '); + APPEND_STRING(short_months[(ptime->month - 1)]); + APPEND(' '); + APPEND_NUMBER(PNG_NUMBER_FORMAT_u, ptime->year); + APPEND(' '); + APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->hour); + APPEND(':'); + APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->minute); + APPEND(':'); + APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->second); + APPEND_STRING(" +0000"); /* This reliably terminates the buffer */ + PNG_UNUSED (pos) + +# undef APPEND +# undef APPEND_NUMBER +# undef APPEND_STRING + } + + return 1; +} + +# if PNG_LIBPNG_VER < 10700 +/* To do: remove the following from libpng-1.7 */ +/* Original API that uses a private buffer in png_struct. + * Deprecated because it causes png_struct to carry a spurious temporary + * buffer (png_struct::time_buffer), better to have the caller pass this in. + */ +png_const_charp PNGAPI +png_convert_to_rfc1123(png_structrp png_ptr, png_const_timep ptime) +{ + if (png_ptr != NULL) + { + /* The only failure above if png_ptr != NULL is from an invalid ptime */ + if (png_convert_to_rfc1123_buffer(png_ptr->time_buffer, ptime) == 0) + png_warning(png_ptr, "Ignoring invalid time value"); + + else + return png_ptr->time_buffer; + } + + return NULL; +} +# endif /* LIBPNG_VER < 10700 */ +# endif /* TIME_RFC1123 */ + +#endif /* READ || WRITE */ + +png_const_charp PNGAPI +png_get_copyright(png_const_structrp png_ptr) +{ + PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ +#ifdef PNG_STRING_COPYRIGHT + return PNG_STRING_COPYRIGHT +#else +# ifdef __STDC__ + return PNG_STRING_NEWLINE \ + "libpng version 1.6.23 - June 9, 2016" PNG_STRING_NEWLINE \ + "Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson" \ + PNG_STRING_NEWLINE \ + "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \ + "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \ + PNG_STRING_NEWLINE; +# else + return "libpng version 1.6.23 - June 9, 2016\ + Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson\ + Copyright (c) 1996-1997 Andreas Dilger\ + Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc."; +# endif +#endif +} + +/* The following return the library version as a short string in the + * format 1.0.0 through 99.99.99zz. To get the version of *.h files + * used with your application, print out PNG_LIBPNG_VER_STRING, which + * is defined in png.h. + * Note: now there is no difference between png_get_libpng_ver() and + * png_get_header_ver(). Due to the version_nn_nn_nn typedef guard, + * it is guaranteed that png.c uses the correct version of png.h. + */ +png_const_charp PNGAPI +png_get_libpng_ver(png_const_structrp png_ptr) +{ + /* Version of *.c files used when building libpng */ + return png_get_header_ver(png_ptr); +} + +png_const_charp PNGAPI +png_get_header_ver(png_const_structrp png_ptr) +{ + /* Version of *.h files used when building libpng */ + PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ + return PNG_LIBPNG_VER_STRING; +} + +png_const_charp PNGAPI +png_get_header_version(png_const_structrp png_ptr) +{ + /* Returns longer string containing both version and date */ + PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ +#ifdef __STDC__ + return PNG_HEADER_VERSION_STRING +# ifndef PNG_READ_SUPPORTED + " (NO READ SUPPORT)" +# endif + PNG_STRING_NEWLINE; +#else + return PNG_HEADER_VERSION_STRING; +#endif +} + +#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED +/* NOTE: this routine is not used internally! */ +/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth + * large of png_color. This lets grayscale images be treated as + * paletted. Most useful for gamma correction and simplification + * of code. This API is not used internally. + */ +void PNGAPI +png_build_grayscale_palette(int bit_depth, png_colorp palette) +{ + int num_palette; + int color_inc; + int i; + int v; + + png_debug(1, "in png_do_build_grayscale_palette"); + + if (palette == NULL) + return; + + switch (bit_depth) + { + case 1: + num_palette = 2; + color_inc = 0xff; + break; + + case 2: + num_palette = 4; + color_inc = 0x55; + break; + + case 4: + num_palette = 16; + color_inc = 0x11; + break; + + case 8: + num_palette = 256; + color_inc = 1; + break; + + default: + num_palette = 0; + color_inc = 0; + break; + } + + for (i = 0, v = 0; i < num_palette; i++, v += color_inc) + { + palette[i].red = (png_byte)(v & 0xff); + palette[i].green = (png_byte)(v & 0xff); + palette[i].blue = (png_byte)(v & 0xff); + } +} +#endif + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED +int PNGAPI +png_handle_as_unknown(png_const_structrp png_ptr, png_const_bytep chunk_name) +{ + /* Check chunk_name and return "keep" value if it's on the list, else 0 */ + png_const_bytep p, p_end; + + if (png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list == 0) + return PNG_HANDLE_CHUNK_AS_DEFAULT; + + p_end = png_ptr->chunk_list; + p = p_end + png_ptr->num_chunk_list*5; /* beyond end */ + + /* The code is the fifth byte after each four byte string. Historically this + * code was always searched from the end of the list, this is no longer + * necessary because the 'set' routine handles duplicate entries correcty. + */ + do /* num_chunk_list > 0, so at least one */ + { + p -= 5; + + if (memcmp(chunk_name, p, 4) == 0) + return p[4]; + } + while (p > p_end); + + /* This means that known chunks should be processed and unknown chunks should + * be handled according to the value of png_ptr->unknown_default; this can be + * confusing because, as a result, there are two levels of defaulting for + * unknown chunks. + */ + return PNG_HANDLE_CHUNK_AS_DEFAULT; +} + +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\ + defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) +int /* PRIVATE */ +png_chunk_unknown_handling(png_const_structrp png_ptr, png_uint_32 chunk_name) +{ + png_byte chunk_string[5]; + + PNG_CSTRING_FROM_CHUNK(chunk_string, chunk_name); + return png_handle_as_unknown(png_ptr, chunk_string); +} +#endif /* READ_UNKNOWN_CHUNKS || HANDLE_AS_UNKNOWN */ +#endif /* SET_UNKNOWN_CHUNKS */ + +#ifdef PNG_READ_SUPPORTED +/* This function, added to libpng-1.0.6g, is untested. */ +int PNGAPI +png_reset_zstream(png_structrp png_ptr) +{ + if (png_ptr == NULL) + return Z_STREAM_ERROR; + + /* WARNING: this resets the window bits to the maximum! */ + return (inflateReset(&png_ptr->zstream)); +} +#endif /* READ */ + +/* This function was added to libpng-1.0.7 */ +png_uint_32 PNGAPI +png_access_version_number(void) +{ + /* Version of *.c files used when building libpng */ + return((png_uint_32)PNG_LIBPNG_VER); +} + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +/* Ensure that png_ptr->zstream.msg holds some appropriate error message string. + * If it doesn't 'ret' is used to set it to something appropriate, even in cases + * like Z_OK or Z_STREAM_END where the error code is apparently a success code. + */ +void /* PRIVATE */ +png_zstream_error(png_structrp png_ptr, int ret) +{ + /* Translate 'ret' into an appropriate error string, priority is given to the + * one in zstream if set. This always returns a string, even in cases like + * Z_OK or Z_STREAM_END where the error code is a success code. + */ + if (png_ptr->zstream.msg == NULL) switch (ret) + { + default: + case Z_OK: + png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return code"); + break; + + case Z_STREAM_END: + /* Normal exit */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected end of LZ stream"); + break; + + case Z_NEED_DICT: + /* This means the deflate stream did not have a dictionary; this + * indicates a bogus PNG. + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("missing LZ dictionary"); + break; + + case Z_ERRNO: + /* gz APIs only: should not happen */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("zlib IO error"); + break; + + case Z_STREAM_ERROR: + /* internal libpng error */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("bad parameters to zlib"); + break; + + case Z_DATA_ERROR: + png_ptr->zstream.msg = PNGZ_MSG_CAST("damaged LZ stream"); + break; + + case Z_MEM_ERROR: + png_ptr->zstream.msg = PNGZ_MSG_CAST("insufficient memory"); + break; + + case Z_BUF_ERROR: + /* End of input or output; not a problem if the caller is doing + * incremental read or write. + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("truncated"); + break; + + case Z_VERSION_ERROR: + png_ptr->zstream.msg = PNGZ_MSG_CAST("unsupported zlib version"); + break; + + case PNG_UNEXPECTED_ZLIB_RETURN: + /* Compile errors here mean that zlib now uses the value co-opted in + * pngpriv.h for PNG_UNEXPECTED_ZLIB_RETURN; update the switch above + * and change pngpriv.h. Note that this message is "... return", + * whereas the default/Z_OK one is "... return code". + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return"); + break; + } +} + +/* png_convert_size: a PNGAPI but no longer in png.h, so deleted + * at libpng 1.5.5! + */ + +/* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */ +#ifdef PNG_GAMMA_SUPPORTED /* always set if COLORSPACE */ +static int +png_colorspace_check_gamma(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_fixed_point gAMA, int from) + /* This is called to check a new gamma value against an existing one. The + * routine returns false if the new gamma value should not be written. + * + * 'from' says where the new gamma value comes from: + * + * 0: the new gamma value is the libpng estimate for an ICC profile + * 1: the new gamma value comes from a gAMA chunk + * 2: the new gamma value comes from an sRGB chunk + */ +{ + png_fixed_point gtest; + + if ((colorspace->flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 && + (png_muldiv(>est, colorspace->gamma, PNG_FP_1, gAMA) == 0 || + png_gamma_significant(gtest) != 0)) + { + /* Either this is an sRGB image, in which case the calculated gamma + * approximation should match, or this is an image with a profile and the + * value libpng calculates for the gamma of the profile does not match the + * value recorded in the file. The former, sRGB, case is an error, the + * latter is just a warning. + */ + if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0 || from == 2) + { + png_chunk_report(png_ptr, "gamma value does not match sRGB", + PNG_CHUNK_ERROR); + /* Do not overwrite an sRGB value */ + return from == 2; + } + + else /* sRGB tag not involved */ + { + png_chunk_report(png_ptr, "gamma value does not match libpng estimate", + PNG_CHUNK_WARNING); + return from == 1; + } + } + + return 1; +} + +void /* PRIVATE */ +png_colorspace_set_gamma(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_fixed_point gAMA) +{ + /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't + * occur. Since the fixed point representation is asymetrical it is + * possible for 1/gamma to overflow the limit of 21474 and this means the + * gamma value must be at least 5/100000 and hence at most 20000.0. For + * safety the limits here are a little narrower. The values are 0.00016 to + * 6250.0, which are truly ridiculous gamma values (and will produce + * displays that are all black or all white.) + * + * In 1.6.0 this test replaces the ones in pngrutil.c, in the gAMA chunk + * handling code, which only required the value to be >0. + */ + png_const_charp errmsg; + + if (gAMA < 16 || gAMA > 625000000) + errmsg = "gamma value out of range"; + +# ifdef PNG_READ_gAMA_SUPPORTED + /* Allow the application to set the gamma value more than once */ + else if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + (colorspace->flags & PNG_COLORSPACE_FROM_gAMA) != 0) + errmsg = "duplicate"; +# endif + + /* Do nothing if the colorspace is already invalid */ + else if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0) + return; + + else + { + if (png_colorspace_check_gamma(png_ptr, colorspace, gAMA, + 1/*from gAMA*/) != 0) + { + /* Store this gamma value. */ + colorspace->gamma = gAMA; + colorspace->flags |= + (PNG_COLORSPACE_HAVE_GAMMA | PNG_COLORSPACE_FROM_gAMA); + } + + /* At present if the check_gamma test fails the gamma of the colorspace is + * not updated however the colorspace is not invalidated. This + * corresponds to the case where the existing gamma comes from an sRGB + * chunk or profile. An error message has already been output. + */ + return; + } + + /* Error exit - errmsg has been set. */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_chunk_report(png_ptr, errmsg, PNG_CHUNK_WRITE_ERROR); +} + +void /* PRIVATE */ +png_colorspace_sync_info(png_const_structrp png_ptr, png_inforp info_ptr) +{ + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) + { + /* Everything is invalid */ + info_ptr->valid &= ~(PNG_INFO_gAMA|PNG_INFO_cHRM|PNG_INFO_sRGB| + PNG_INFO_iCCP); + +# ifdef PNG_COLORSPACE_SUPPORTED + /* Clean up the iCCP profile now if it won't be used. */ + png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, -1/*not used*/); +# else + PNG_UNUSED(png_ptr) +# endif + } + + else + { +# ifdef PNG_COLORSPACE_SUPPORTED + /* Leave the INFO_iCCP flag set if the pngset.c code has already set + * it; this allows a PNG to contain a profile which matches sRGB and + * yet still have that profile retrievable by the application. + */ + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_MATCHES_sRGB) != 0) + info_ptr->valid |= PNG_INFO_sRGB; + + else + info_ptr->valid &= ~PNG_INFO_sRGB; + + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) + info_ptr->valid |= PNG_INFO_cHRM; + + else + info_ptr->valid &= ~PNG_INFO_cHRM; +# endif + + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0) + info_ptr->valid |= PNG_INFO_gAMA; + + else + info_ptr->valid &= ~PNG_INFO_gAMA; + } +} + +#ifdef PNG_READ_SUPPORTED +void /* PRIVATE */ +png_colorspace_sync(png_const_structrp png_ptr, png_inforp info_ptr) +{ + if (info_ptr == NULL) /* reduce code size; check here not in the caller */ + return; + + info_ptr->colorspace = png_ptr->colorspace; + png_colorspace_sync_info(png_ptr, info_ptr); +} +#endif +#endif /* GAMMA */ + +#ifdef PNG_COLORSPACE_SUPPORTED +/* Added at libpng-1.5.5 to support read and write of true CIEXYZ values for + * cHRM, as opposed to using chromaticities. These internal APIs return + * non-zero on a parameter error. The X, Y and Z values are required to be + * positive and less than 1.0. + */ +static int +png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ) +{ + png_int_32 d, dwhite, whiteX, whiteY; + + d = XYZ->red_X + XYZ->red_Y + XYZ->red_Z; + if (png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, d) == 0) + return 1; + if (png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, d) == 0) + return 1; + dwhite = d; + whiteX = XYZ->red_X; + whiteY = XYZ->red_Y; + + d = XYZ->green_X + XYZ->green_Y + XYZ->green_Z; + if (png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, d) == 0) + return 1; + if (png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, d) == 0) + return 1; + dwhite += d; + whiteX += XYZ->green_X; + whiteY += XYZ->green_Y; + + d = XYZ->blue_X + XYZ->blue_Y + XYZ->blue_Z; + if (png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, d) == 0) + return 1; + if (png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, d) == 0) + return 1; + dwhite += d; + whiteX += XYZ->blue_X; + whiteY += XYZ->blue_Y; + + /* The reference white is simply the sum of the end-point (X,Y,Z) vectors, + * thus: + */ + if (png_muldiv(&xy->whitex, whiteX, PNG_FP_1, dwhite) == 0) + return 1; + if (png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite) == 0) + return 1; + + return 0; +} + +static int +png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy) +{ + png_fixed_point red_inverse, green_inverse, blue_scale; + png_fixed_point left, right, denominator; + + /* Check xy and, implicitly, z. Note that wide gamut color spaces typically + * have end points with 0 tristimulus values (these are impossible end + * points, but they are used to cover the possible colors). We check + * xy->whitey against 5, not 0, to avoid a possible integer overflow. + */ + if (xy->redx < 0 || xy->redx > PNG_FP_1) return 1; + if (xy->redy < 0 || xy->redy > PNG_FP_1-xy->redx) return 1; + if (xy->greenx < 0 || xy->greenx > PNG_FP_1) return 1; + if (xy->greeny < 0 || xy->greeny > PNG_FP_1-xy->greenx) return 1; + if (xy->bluex < 0 || xy->bluex > PNG_FP_1) return 1; + if (xy->bluey < 0 || xy->bluey > PNG_FP_1-xy->bluex) return 1; + if (xy->whitex < 0 || xy->whitex > PNG_FP_1) return 1; + if (xy->whitey < 5 || xy->whitey > PNG_FP_1-xy->whitex) return 1; + + /* The reverse calculation is more difficult because the original tristimulus + * value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8 + * derived values were recorded in the cHRM chunk; + * (red,green,blue,white)x(x,y). This loses one degree of freedom and + * therefore an arbitrary ninth value has to be introduced to undo the + * original transformations. + * + * Think of the original end-points as points in (X,Y,Z) space. The + * chromaticity values (c) have the property: + * + * C + * c = --------- + * X + Y + Z + * + * For each c (x,y,z) from the corresponding original C (X,Y,Z). Thus the + * three chromaticity values (x,y,z) for each end-point obey the + * relationship: + * + * x + y + z = 1 + * + * This describes the plane in (X,Y,Z) space that intersects each axis at the + * value 1.0; call this the chromaticity plane. Thus the chromaticity + * calculation has scaled each end-point so that it is on the x+y+z=1 plane + * and chromaticity is the intersection of the vector from the origin to the + * (X,Y,Z) value with the chromaticity plane. + * + * To fully invert the chromaticity calculation we would need the three + * end-point scale factors, (red-scale, green-scale, blue-scale), but these + * were not recorded. Instead we calculated the reference white (X,Y,Z) and + * recorded the chromaticity of this. The reference white (X,Y,Z) would have + * given all three of the scale factors since: + * + * color-C = color-c * color-scale + * white-C = red-C + green-C + blue-C + * = red-c*red-scale + green-c*green-scale + blue-c*blue-scale + * + * But cHRM records only white-x and white-y, so we have lost the white scale + * factor: + * + * white-C = white-c*white-scale + * + * To handle this the inverse transformation makes an arbitrary assumption + * about white-scale: + * + * Assume: white-Y = 1.0 + * Hence: white-scale = 1/white-y + * Or: red-Y + green-Y + blue-Y = 1.0 + * + * Notice the last statement of the assumption gives an equation in three of + * the nine values we want to calculate. 8 more equations come from the + * above routine as summarised at the top above (the chromaticity + * calculation): + * + * Given: color-x = color-X / (color-X + color-Y + color-Z) + * Hence: (color-x - 1)*color-X + color.x*color-Y + color.x*color-Z = 0 + * + * This is 9 simultaneous equations in the 9 variables "color-C" and can be + * solved by Cramer's rule. Cramer's rule requires calculating 10 9x9 matrix + * determinants, however this is not as bad as it seems because only 28 of + * the total of 90 terms in the various matrices are non-zero. Nevertheless + * Cramer's rule is notoriously numerically unstable because the determinant + * calculation involves the difference of large, but similar, numbers. It is + * difficult to be sure that the calculation is stable for real world values + * and it is certain that it becomes unstable where the end points are close + * together. + * + * So this code uses the perhaps slightly less optimal but more + * understandable and totally obvious approach of calculating color-scale. + * + * This algorithm depends on the precision in white-scale and that is + * (1/white-y), so we can immediately see that as white-y approaches 0 the + * accuracy inherent in the cHRM chunk drops off substantially. + * + * libpng arithmetic: a simple inversion of the above equations + * ------------------------------------------------------------ + * + * white_scale = 1/white-y + * white-X = white-x * white-scale + * white-Y = 1.0 + * white-Z = (1 - white-x - white-y) * white_scale + * + * white-C = red-C + green-C + blue-C + * = red-c*red-scale + green-c*green-scale + blue-c*blue-scale + * + * This gives us three equations in (red-scale,green-scale,blue-scale) where + * all the coefficients are now known: + * + * red-x*red-scale + green-x*green-scale + blue-x*blue-scale + * = white-x/white-y + * red-y*red-scale + green-y*green-scale + blue-y*blue-scale = 1 + * red-z*red-scale + green-z*green-scale + blue-z*blue-scale + * = (1 - white-x - white-y)/white-y + * + * In the last equation color-z is (1 - color-x - color-y) so we can add all + * three equations together to get an alternative third: + * + * red-scale + green-scale + blue-scale = 1/white-y = white-scale + * + * So now we have a Cramer's rule solution where the determinants are just + * 3x3 - far more tractible. Unfortunately 3x3 determinants still involve + * multiplication of three coefficients so we can't guarantee to avoid + * overflow in the libpng fixed point representation. Using Cramer's rule in + * floating point is probably a good choice here, but it's not an option for + * fixed point. Instead proceed to simplify the first two equations by + * eliminating what is likely to be the largest value, blue-scale: + * + * blue-scale = white-scale - red-scale - green-scale + * + * Hence: + * + * (red-x - blue-x)*red-scale + (green-x - blue-x)*green-scale = + * (white-x - blue-x)*white-scale + * + * (red-y - blue-y)*red-scale + (green-y - blue-y)*green-scale = + * 1 - blue-y*white-scale + * + * And now we can trivially solve for (red-scale,green-scale): + * + * green-scale = + * (white-x - blue-x)*white-scale - (red-x - blue-x)*red-scale + * ----------------------------------------------------------- + * green-x - blue-x + * + * red-scale = + * 1 - blue-y*white-scale - (green-y - blue-y) * green-scale + * --------------------------------------------------------- + * red-y - blue-y + * + * Hence: + * + * red-scale = + * ( (green-x - blue-x) * (white-y - blue-y) - + * (green-y - blue-y) * (white-x - blue-x) ) / white-y + * ------------------------------------------------------------------------- + * (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x) + * + * green-scale = + * ( (red-y - blue-y) * (white-x - blue-x) - + * (red-x - blue-x) * (white-y - blue-y) ) / white-y + * ------------------------------------------------------------------------- + * (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x) + * + * Accuracy: + * The input values have 5 decimal digits of accuracy. The values are all in + * the range 0 < value < 1, so simple products are in the same range but may + * need up to 10 decimal digits to preserve the original precision and avoid + * underflow. Because we are using a 32-bit signed representation we cannot + * match this; the best is a little over 9 decimal digits, less than 10. + * + * The approach used here is to preserve the maximum precision within the + * signed representation. Because the red-scale calculation above uses the + * difference between two products of values that must be in the range -1..+1 + * it is sufficient to divide the product by 7; ceil(100,000/32767*2). The + * factor is irrelevant in the calculation because it is applied to both + * numerator and denominator. + * + * Note that the values of the differences of the products of the + * chromaticities in the above equations tend to be small, for example for + * the sRGB chromaticities they are: + * + * red numerator: -0.04751 + * green numerator: -0.08788 + * denominator: -0.2241 (without white-y multiplication) + * + * The resultant Y coefficients from the chromaticities of some widely used + * color space definitions are (to 15 decimal places): + * + * sRGB + * 0.212639005871510 0.715168678767756 0.072192315360734 + * Kodak ProPhoto + * 0.288071128229293 0.711843217810102 0.000085653960605 + * Adobe RGB + * 0.297344975250536 0.627363566255466 0.075291458493998 + * Adobe Wide Gamut RGB + * 0.258728243040113 0.724682314948566 0.016589442011321 + */ + /* By the argument, above overflow should be impossible here. The return + * value of 2 indicates an internal error to the caller. + */ + if (png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 7) == 0) + return 2; + if (png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 7) == 0) + return 2; + denominator = left - right; + + /* Now find the red numerator. */ + if (png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 7) == 0) + return 2; + if (png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 7) == 0) + return 2; + + /* Overflow is possible here and it indicates an extreme set of PNG cHRM + * chunk values. This calculation actually returns the reciprocal of the + * scale value because this allows us to delay the multiplication of white-y + * into the denominator, which tends to produce a small number. + */ + if (png_muldiv(&red_inverse, xy->whitey, denominator, left-right) == 0 || + red_inverse <= xy->whitey /* r+g+b scales = white scale */) + return 1; + + /* Similarly for green_inverse: */ + if (png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 7) == 0) + return 2; + if (png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 7) == 0) + return 2; + if (png_muldiv(&green_inverse, xy->whitey, denominator, left-right) == 0 || + green_inverse <= xy->whitey) + return 1; + + /* And the blue scale, the checks above guarantee this can't overflow but it + * can still produce 0 for extreme cHRM values. + */ + blue_scale = png_reciprocal(xy->whitey) - png_reciprocal(red_inverse) - + png_reciprocal(green_inverse); + if (blue_scale <= 0) + return 1; + + + /* And fill in the png_XYZ: */ + if (png_muldiv(&XYZ->red_X, xy->redx, PNG_FP_1, red_inverse) == 0) + return 1; + if (png_muldiv(&XYZ->red_Y, xy->redy, PNG_FP_1, red_inverse) == 0) + return 1; + if (png_muldiv(&XYZ->red_Z, PNG_FP_1 - xy->redx - xy->redy, PNG_FP_1, + red_inverse) == 0) + return 1; + + if (png_muldiv(&XYZ->green_X, xy->greenx, PNG_FP_1, green_inverse) == 0) + return 1; + if (png_muldiv(&XYZ->green_Y, xy->greeny, PNG_FP_1, green_inverse) == 0) + return 1; + if (png_muldiv(&XYZ->green_Z, PNG_FP_1 - xy->greenx - xy->greeny, PNG_FP_1, + green_inverse) == 0) + return 1; + + if (png_muldiv(&XYZ->blue_X, xy->bluex, blue_scale, PNG_FP_1) == 0) + return 1; + if (png_muldiv(&XYZ->blue_Y, xy->bluey, blue_scale, PNG_FP_1) == 0) + return 1; + if (png_muldiv(&XYZ->blue_Z, PNG_FP_1 - xy->bluex - xy->bluey, blue_scale, + PNG_FP_1) == 0) + return 1; + + return 0; /*success*/ +} + +static int +png_XYZ_normalize(png_XYZ *XYZ) +{ + png_int_32 Y; + + if (XYZ->red_Y < 0 || XYZ->green_Y < 0 || XYZ->blue_Y < 0 || + XYZ->red_X < 0 || XYZ->green_X < 0 || XYZ->blue_X < 0 || + XYZ->red_Z < 0 || XYZ->green_Z < 0 || XYZ->blue_Z < 0) + return 1; + + /* Normalize by scaling so the sum of the end-point Y values is PNG_FP_1. + * IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore + * relying on addition of two positive values producing a negative one is not + * safe. + */ + Y = XYZ->red_Y; + if (0x7fffffff - Y < XYZ->green_X) + return 1; + Y += XYZ->green_Y; + if (0x7fffffff - Y < XYZ->blue_X) + return 1; + Y += XYZ->blue_Y; + + if (Y != PNG_FP_1) + { + if (png_muldiv(&XYZ->red_X, XYZ->red_X, PNG_FP_1, Y) == 0) + return 1; + if (png_muldiv(&XYZ->red_Y, XYZ->red_Y, PNG_FP_1, Y) == 0) + return 1; + if (png_muldiv(&XYZ->red_Z, XYZ->red_Z, PNG_FP_1, Y) == 0) + return 1; + + if (png_muldiv(&XYZ->green_X, XYZ->green_X, PNG_FP_1, Y) == 0) + return 1; + if (png_muldiv(&XYZ->green_Y, XYZ->green_Y, PNG_FP_1, Y) == 0) + return 1; + if (png_muldiv(&XYZ->green_Z, XYZ->green_Z, PNG_FP_1, Y) == 0) + return 1; + + if (png_muldiv(&XYZ->blue_X, XYZ->blue_X, PNG_FP_1, Y) == 0) + return 1; + if (png_muldiv(&XYZ->blue_Y, XYZ->blue_Y, PNG_FP_1, Y) == 0) + return 1; + if (png_muldiv(&XYZ->blue_Z, XYZ->blue_Z, PNG_FP_1, Y) == 0) + return 1; + } + + return 0; +} + +static int +png_colorspace_endpoints_match(const png_xy *xy1, const png_xy *xy2, int delta) +{ + /* Allow an error of +/-0.01 (absolute value) on each chromaticity */ + if (PNG_OUT_OF_RANGE(xy1->whitex, xy2->whitex,delta) || + PNG_OUT_OF_RANGE(xy1->whitey, xy2->whitey,delta) || + PNG_OUT_OF_RANGE(xy1->redx, xy2->redx, delta) || + PNG_OUT_OF_RANGE(xy1->redy, xy2->redy, delta) || + PNG_OUT_OF_RANGE(xy1->greenx, xy2->greenx,delta) || + PNG_OUT_OF_RANGE(xy1->greeny, xy2->greeny,delta) || + PNG_OUT_OF_RANGE(xy1->bluex, xy2->bluex, delta) || + PNG_OUT_OF_RANGE(xy1->bluey, xy2->bluey, delta)) + return 0; + return 1; +} + +/* Added in libpng-1.6.0, a different check for the validity of a set of cHRM + * chunk chromaticities. Earlier checks used to simply look for the overflow + * condition (where the determinant of the matrix to solve for XYZ ends up zero + * because the chromaticity values are not all distinct.) Despite this it is + * theoretically possible to produce chromaticities that are apparently valid + * but that rapidly degrade to invalid, potentially crashing, sets because of + * arithmetic inaccuracies when calculations are performed on them. The new + * check is to round-trip xy -> XYZ -> xy and then check that the result is + * within a small percentage of the original. + */ +static int +png_colorspace_check_xy(png_XYZ *XYZ, const png_xy *xy) +{ + int result; + png_xy xy_test; + + /* As a side-effect this routine also returns the XYZ endpoints. */ + result = png_XYZ_from_xy(XYZ, xy); + if (result != 0) + return result; + + result = png_xy_from_XYZ(&xy_test, XYZ); + if (result != 0) + return result; + + if (png_colorspace_endpoints_match(xy, &xy_test, + 5/*actually, the math is pretty accurate*/) != 0) + return 0; + + /* Too much slip */ + return 1; +} + +/* This is the check going the other way. The XYZ is modified to normalize it + * (another side-effect) and the xy chromaticities are returned. + */ +static int +png_colorspace_check_XYZ(png_xy *xy, png_XYZ *XYZ) +{ + int result; + png_XYZ XYZtemp; + + result = png_XYZ_normalize(XYZ); + if (result != 0) + return result; + + result = png_xy_from_XYZ(xy, XYZ); + if (result != 0) + return result; + + XYZtemp = *XYZ; + return png_colorspace_check_xy(&XYZtemp, xy); +} + +/* Used to check for an endpoint match against sRGB */ +static const png_xy sRGB_xy = /* From ITU-R BT.709-3 */ +{ + /* color x y */ + /* red */ 64000, 33000, + /* green */ 30000, 60000, + /* blue */ 15000, 6000, + /* white */ 31270, 32900 +}; + +static int +png_colorspace_set_xy_and_XYZ(png_const_structrp png_ptr, + png_colorspacerp colorspace, const png_xy *xy, const png_XYZ *XYZ, + int preferred) +{ + if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0) + return 0; + + /* The consistency check is performed on the chromaticities; this factors out + * variations because of the normalization (or not) of the end point Y + * values. + */ + if (preferred < 2 && + (colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) + { + /* The end points must be reasonably close to any we already have. The + * following allows an error of up to +/-.001 + */ + if (png_colorspace_endpoints_match(xy, &colorspace->end_points_xy, + 100) == 0) + { + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_benign_error(png_ptr, "inconsistent chromaticities"); + return 0; /* failed */ + } + + /* Only overwrite with preferred values */ + if (preferred == 0) + return 1; /* ok, but no change */ + } + + colorspace->end_points_xy = *xy; + colorspace->end_points_XYZ = *XYZ; + colorspace->flags |= PNG_COLORSPACE_HAVE_ENDPOINTS; + + /* The end points are normally quoted to two decimal digits, so allow +/-0.01 + * on this test. + */ + if (png_colorspace_endpoints_match(xy, &sRGB_xy, 1000) != 0) + colorspace->flags |= PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB; + + else + colorspace->flags &= PNG_COLORSPACE_CANCEL( + PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB); + + return 2; /* ok and changed */ +} + +int /* PRIVATE */ +png_colorspace_set_chromaticities(png_const_structrp png_ptr, + png_colorspacerp colorspace, const png_xy *xy, int preferred) +{ + /* We must check the end points to ensure they are reasonable - in the past + * color management systems have crashed as a result of getting bogus + * colorant values, while this isn't the fault of libpng it is the + * responsibility of libpng because PNG carries the bomb and libpng is in a + * position to protect against it. + */ + png_XYZ XYZ; + + switch (png_colorspace_check_xy(&XYZ, xy)) + { + case 0: /* success */ + return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, xy, &XYZ, + preferred); + + case 1: + /* We can't invert the chromaticities so we can't produce value XYZ + * values. Likely as not a color management system will fail too. + */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_benign_error(png_ptr, "invalid chromaticities"); + break; + + default: + /* libpng is broken; this should be a warning but if it happens we + * want error reports so for the moment it is an error. + */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_error(png_ptr, "internal error checking chromaticities"); + } + + return 0; /* failed */ +} + +int /* PRIVATE */ +png_colorspace_set_endpoints(png_const_structrp png_ptr, + png_colorspacerp colorspace, const png_XYZ *XYZ_in, int preferred) +{ + png_XYZ XYZ = *XYZ_in; + png_xy xy; + + switch (png_colorspace_check_XYZ(&xy, &XYZ)) + { + case 0: + return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, &xy, &XYZ, + preferred); + + case 1: + /* End points are invalid. */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_benign_error(png_ptr, "invalid end points"); + break; + + default: + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_error(png_ptr, "internal error checking chromaticities"); + } + + return 0; /* failed */ +} + +#if defined(PNG_sRGB_SUPPORTED) || defined(PNG_iCCP_SUPPORTED) +/* Error message generation */ +static char +png_icc_tag_char(png_uint_32 byte) +{ + byte &= 0xff; + if (byte >= 32 && byte <= 126) + return (char)byte; + else + return '?'; +} + +static void +png_icc_tag_name(char *name, png_uint_32 tag) +{ + name[0] = '\''; + name[1] = png_icc_tag_char(tag >> 24); + name[2] = png_icc_tag_char(tag >> 16); + name[3] = png_icc_tag_char(tag >> 8); + name[4] = png_icc_tag_char(tag ); + name[5] = '\''; +} + +static int +is_ICC_signature_char(png_alloc_size_t it) +{ + return it == 32 || (it >= 48 && it <= 57) || (it >= 65 && it <= 90) || + (it >= 97 && it <= 122); +} + +static int +is_ICC_signature(png_alloc_size_t it) +{ + return is_ICC_signature_char(it >> 24) /* checks all the top bits */ && + is_ICC_signature_char((it >> 16) & 0xff) && + is_ICC_signature_char((it >> 8) & 0xff) && + is_ICC_signature_char(it & 0xff); +} + +static int +png_icc_profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_alloc_size_t value, png_const_charp reason) +{ + size_t pos; + char message[196]; /* see below for calculation */ + + if (colorspace != NULL) + colorspace->flags |= PNG_COLORSPACE_INVALID; + + pos = png_safecat(message, (sizeof message), 0, "profile '"); /* 9 chars */ + pos = png_safecat(message, pos+79, pos, name); /* Truncate to 79 chars */ + pos = png_safecat(message, (sizeof message), pos, "': "); /* +2 = 90 */ + if (is_ICC_signature(value) != 0) + { + /* So 'value' is at most 4 bytes and the following cast is safe */ + png_icc_tag_name(message+pos, (png_uint_32)value); + pos += 6; /* total +8; less than the else clause */ + message[pos++] = ':'; + message[pos++] = ' '; + } +# ifdef PNG_WARNINGS_SUPPORTED + else + { + char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114*/ + + pos = png_safecat(message, (sizeof message), pos, + png_format_number(number, number+(sizeof number), + PNG_NUMBER_FORMAT_x, value)); + pos = png_safecat(message, (sizeof message), pos, "h: "); /*+2 = 116*/ + } +# endif + /* The 'reason' is an arbitrary message, allow +79 maximum 195 */ + pos = png_safecat(message, (sizeof message), pos, reason); + PNG_UNUSED(pos) + + /* This is recoverable, but make it unconditionally an app_error on write to + * avoid writing invalid ICC profiles into PNG files (i.e., we handle them + * on read, with a warning, but on write unless the app turns off + * application errors the PNG won't be written.) + */ + png_chunk_report(png_ptr, message, + (colorspace != NULL) ? PNG_CHUNK_ERROR : PNG_CHUNK_WRITE_ERROR); + + return 0; +} +#endif /* sRGB || iCCP */ + +#ifdef PNG_sRGB_SUPPORTED +int /* PRIVATE */ +png_colorspace_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace, + int intent) +{ + /* sRGB sets known gamma, end points and (from the chunk) intent. */ + /* IMPORTANT: these are not necessarily the values found in an ICC profile + * because ICC profiles store values adapted to a D50 environment; it is + * expected that the ICC profile mediaWhitePointTag will be D50; see the + * checks and code elsewhere to understand this better. + * + * These XYZ values, which are accurate to 5dp, produce rgb to gray + * coefficients of (6968,23435,2366), which are reduced (because they add up + * to 32769 not 32768) to (6968,23434,2366). These are the values that + * libpng has traditionally used (and are the best values given the 15bit + * algorithm used by the rgb to gray code.) + */ + static const png_XYZ sRGB_XYZ = /* D65 XYZ (*not* the D50 adapted values!) */ + { + /* color X Y Z */ + /* red */ 41239, 21264, 1933, + /* green */ 35758, 71517, 11919, + /* blue */ 18048, 7219, 95053 + }; + + /* Do nothing if the colorspace is already invalidated. */ + if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0) + return 0; + + /* Check the intent, then check for existing settings. It is valid for the + * PNG file to have cHRM or gAMA chunks along with sRGB, but the values must + * be consistent with the correct values. If, however, this function is + * called below because an iCCP chunk matches sRGB then it is quite + * conceivable that an older app recorded incorrect gAMA and cHRM because of + * an incorrect calculation based on the values in the profile - this does + * *not* invalidate the profile (though it still produces an error, which can + * be ignored.) + */ + if (intent < 0 || intent >= PNG_sRGB_INTENT_LAST) + return png_icc_profile_error(png_ptr, colorspace, "sRGB", + (unsigned)intent, "invalid sRGB rendering intent"); + + if ((colorspace->flags & PNG_COLORSPACE_HAVE_INTENT) != 0 && + colorspace->rendering_intent != intent) + return png_icc_profile_error(png_ptr, colorspace, "sRGB", + (unsigned)intent, "inconsistent rendering intents"); + + if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0) + { + png_benign_error(png_ptr, "duplicate sRGB information ignored"); + return 0; + } + + /* If the standard sRGB cHRM chunk does not match the one from the PNG file + * warn but overwrite the value with the correct one. + */ + if ((colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0 && + !png_colorspace_endpoints_match(&sRGB_xy, &colorspace->end_points_xy, + 100)) + png_chunk_report(png_ptr, "cHRM chunk does not match sRGB", + PNG_CHUNK_ERROR); + + /* This check is just done for the error reporting - the routine always + * returns true when the 'from' argument corresponds to sRGB (2). + */ + (void)png_colorspace_check_gamma(png_ptr, colorspace, PNG_GAMMA_sRGB_INVERSE, + 2/*from sRGB*/); + + /* intent: bugs in GCC force 'int' to be used as the parameter type. */ + colorspace->rendering_intent = (png_uint_16)intent; + colorspace->flags |= PNG_COLORSPACE_HAVE_INTENT; + + /* endpoints */ + colorspace->end_points_xy = sRGB_xy; + colorspace->end_points_XYZ = sRGB_XYZ; + colorspace->flags |= + (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB); + + /* gamma */ + colorspace->gamma = PNG_GAMMA_sRGB_INVERSE; + colorspace->flags |= PNG_COLORSPACE_HAVE_GAMMA; + + /* Finally record that we have an sRGB profile */ + colorspace->flags |= + (PNG_COLORSPACE_MATCHES_sRGB|PNG_COLORSPACE_FROM_sRGB); + + return 1; /* set */ +} +#endif /* sRGB */ + +#ifdef PNG_iCCP_SUPPORTED +/* Encoded value of D50 as an ICC XYZNumber. From the ICC 2010 spec the value + * is XYZ(0.9642,1.0,0.8249), which scales to: + * + * (63189.8112, 65536, 54060.6464) + */ +static const png_byte D50_nCIEXYZ[12] = + { 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d }; + +int /* PRIVATE */ +png_icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length) +{ + if (profile_length < 132) + return png_icc_profile_error(png_ptr, colorspace, name, profile_length, + "too short"); + + return 1; +} + +int /* PRIVATE */ +png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length, + png_const_bytep profile/* first 132 bytes only */, int color_type) +{ + png_uint_32 temp; + + /* Length check; this cannot be ignored in this code because profile_length + * is used later to check the tag table, so even if the profile seems over + * long profile_length from the caller must be correct. The caller can fix + * this up on read or write by just passing in the profile header length. + */ + temp = png_get_uint_32(profile); + if (temp != profile_length) + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "length does not match profile"); + + temp = (png_uint_32) (*(profile+8)); + if (temp > 3 && (profile_length & 3)) + return png_icc_profile_error(png_ptr, colorspace, name, profile_length, + "invalid length"); + + temp = png_get_uint_32(profile+128); /* tag count: 12 bytes/tag */ + if (temp > 357913930 || /* (2^32-4-132)/12: maximum possible tag count */ + profile_length < 132+12*temp) /* truncated tag table */ + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "tag count too large"); + + /* The 'intent' must be valid or we can't store it, ICC limits the intent to + * 16 bits. + */ + temp = png_get_uint_32(profile+64); + if (temp >= 0xffff) /* The ICC limit */ + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid rendering intent"); + + /* This is just a warning because the profile may be valid in future + * versions. + */ + if (temp >= PNG_sRGB_INTENT_LAST) + (void)png_icc_profile_error(png_ptr, NULL, name, temp, + "intent outside defined range"); + + /* At this point the tag table can't be checked because it hasn't necessarily + * been loaded; however, various header fields can be checked. These checks + * are for values permitted by the PNG spec in an ICC profile; the PNG spec + * restricts the profiles that can be passed in an iCCP chunk (they must be + * appropriate to processing PNG data!) + */ + + /* Data checks (could be skipped). These checks must be independent of the + * version number; however, the version number doesn't accomodate changes in + * the header fields (just the known tags and the interpretation of the + * data.) + */ + temp = png_get_uint_32(profile+36); /* signature 'ascp' */ + if (temp != 0x61637370) + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid signature"); + + /* Currently the PCS illuminant/adopted white point (the computational + * white point) are required to be D50, + * however the profile contains a record of the illuminant so perhaps ICC + * expects to be able to change this in the future (despite the rationale in + * the introduction for using a fixed PCS adopted white.) Consequently the + * following is just a warning. + */ + if (memcmp(profile+68, D50_nCIEXYZ, 12) != 0) + (void)png_icc_profile_error(png_ptr, NULL, name, 0/*no tag value*/, + "PCS illuminant is not D50"); + + /* The PNG spec requires this: + * "If the iCCP chunk is present, the image samples conform to the colour + * space represented by the embedded ICC profile as defined by the + * International Color Consortium [ICC]. The colour space of the ICC profile + * shall be an RGB colour space for colour images (PNG colour types 2, 3, and + * 6), or a greyscale colour space for greyscale images (PNG colour types 0 + * and 4)." + * + * This checking code ensures the embedded profile (on either read or write) + * conforms to the specification requirements. Notice that an ICC 'gray' + * color-space profile contains the information to transform the monochrome + * data to XYZ or L*a*b (according to which PCS the profile uses) and this + * should be used in preference to the standard libpng K channel replication + * into R, G and B channels. + * + * Previously it was suggested that an RGB profile on grayscale data could be + * handled. However it it is clear that using an RGB profile in this context + * must be an error - there is no specification of what it means. Thus it is + * almost certainly more correct to ignore the profile. + */ + temp = png_get_uint_32(profile+16); /* data colour space field */ + switch (temp) + { + case 0x52474220: /* 'RGB ' */ + if ((color_type & PNG_COLOR_MASK_COLOR) == 0) + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "RGB color space not permitted on grayscale PNG"); + break; + + case 0x47524159: /* 'GRAY' */ + if ((color_type & PNG_COLOR_MASK_COLOR) != 0) + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "Gray color space not permitted on RGB PNG"); + break; + + default: + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid ICC profile color space"); + } + + /* It is up to the application to check that the profile class matches the + * application requirements; the spec provides no guidance, but it's pretty + * weird if the profile is not scanner ('scnr'), monitor ('mntr'), printer + * ('prtr') or 'spac' (for generic color spaces). Issue a warning in these + * cases. Issue an error for device link or abstract profiles - these don't + * contain the records necessary to transform the color-space to anything + * other than the target device (and not even that for an abstract profile). + * Profiles of these classes may not be embedded in images. + */ + temp = png_get_uint_32(profile+12); /* profile/device class */ + switch (temp) + { + case 0x73636e72: /* 'scnr' */ + case 0x6d6e7472: /* 'mntr' */ + case 0x70727472: /* 'prtr' */ + case 0x73706163: /* 'spac' */ + /* All supported */ + break; + + case 0x61627374: /* 'abst' */ + /* May not be embedded in an image */ + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid embedded Abstract ICC profile"); + + case 0x6c696e6b: /* 'link' */ + /* DeviceLink profiles cannot be interpreted in a non-device specific + * fashion, if an app uses the AToB0Tag in the profile the results are + * undefined unless the result is sent to the intended device, + * therefore a DeviceLink profile should not be found embedded in a + * PNG. + */ + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "unexpected DeviceLink ICC profile class"); + + case 0x6e6d636c: /* 'nmcl' */ + /* A NamedColor profile is also device specific, however it doesn't + * contain an AToB0 tag that is open to misinterpretation. Almost + * certainly it will fail the tests below. + */ + (void)png_icc_profile_error(png_ptr, NULL, name, temp, + "unexpected NamedColor ICC profile class"); + break; + + default: + /* To allow for future enhancements to the profile accept unrecognized + * profile classes with a warning, these then hit the test below on the + * tag content to ensure they are backward compatible with one of the + * understood profiles. + */ + (void)png_icc_profile_error(png_ptr, NULL, name, temp, + "unrecognized ICC profile class"); + break; + } + + /* For any profile other than a device link one the PCS must be encoded + * either in XYZ or Lab. + */ + temp = png_get_uint_32(profile+20); + switch (temp) + { + case 0x58595a20: /* 'XYZ ' */ + case 0x4c616220: /* 'Lab ' */ + break; + + default: + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "unexpected ICC PCS encoding"); + } + + return 1; +} + +int /* PRIVATE */ +png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length, + png_const_bytep profile /* header plus whole tag table */) +{ + png_uint_32 tag_count = png_get_uint_32(profile+128); + png_uint_32 itag; + png_const_bytep tag = profile+132; /* The first tag */ + + /* First scan all the tags in the table and add bits to the icc_info value + * (temporarily in 'tags'). + */ + for (itag=0; itag < tag_count; ++itag, tag += 12) + { + png_uint_32 tag_id = png_get_uint_32(tag+0); + png_uint_32 tag_start = png_get_uint_32(tag+4); /* must be aligned */ + png_uint_32 tag_length = png_get_uint_32(tag+8);/* not padded */ + + /* The ICC specification does not exclude zero length tags, therefore the + * start might actually be anywhere if there is no data, but this would be + * a clear abuse of the intent of the standard so the start is checked for + * being in range. All defined tag types have an 8 byte header - a 4 byte + * type signature then 0. + */ + if ((tag_start & 3) != 0) + { + /* CNHP730S.icc shipped with Microsoft Windows 64 violates this, it is + * only a warning here because libpng does not care about the + * alignment. + */ + (void)png_icc_profile_error(png_ptr, NULL, name, tag_id, + "ICC profile tag start not a multiple of 4"); + } + + /* This is a hard error; potentially it can cause read outside the + * profile. + */ + if (tag_start > profile_length || tag_length > profile_length - tag_start) + return png_icc_profile_error(png_ptr, colorspace, name, tag_id, + "ICC profile tag outside profile"); + } + + return 1; /* success, maybe with warnings */ +} + +#ifdef PNG_sRGB_SUPPORTED +#if PNG_sRGB_PROFILE_CHECKS >= 0 +/* Information about the known ICC sRGB profiles */ +static const struct +{ + png_uint_32 adler, crc, length; + png_uint_32 md5[4]; + png_byte have_md5; + png_byte is_broken; + png_uint_16 intent; + +# define PNG_MD5(a,b,c,d) { a, b, c, d }, (a!=0)||(b!=0)||(c!=0)||(d!=0) +# define PNG_ICC_CHECKSUM(adler, crc, md5, intent, broke, date, length, fname)\ + { adler, crc, length, md5, broke, intent }, + +} png_sRGB_checks[] = +{ + /* This data comes from contrib/tools/checksum-icc run on downloads of + * all four ICC sRGB profiles from www.color.org. + */ + /* adler32, crc32, MD5[4], intent, date, length, file-name */ + PNG_ICC_CHECKSUM(0x0a3fd9f6, 0x3b8772b9, + PNG_MD5(0x29f83dde, 0xaff255ae, 0x7842fae4, 0xca83390d), 0, 0, + "2009/03/27 21:36:31", 3048, "sRGB_IEC61966-2-1_black_scaled.icc") + + /* ICC sRGB v2 perceptual no black-compensation: */ + PNG_ICC_CHECKSUM(0x4909e5e1, 0x427ebb21, + PNG_MD5(0xc95bd637, 0xe95d8a3b, 0x0df38f99, 0xc1320389), 1, 0, + "2009/03/27 21:37:45", 3052, "sRGB_IEC61966-2-1_no_black_scaling.icc") + + PNG_ICC_CHECKSUM(0xfd2144a1, 0x306fd8ae, + PNG_MD5(0xfc663378, 0x37e2886b, 0xfd72e983, 0x8228f1b8), 0, 0, + "2009/08/10 17:28:01", 60988, "sRGB_v4_ICC_preference_displayclass.icc") + + /* ICC sRGB v4 perceptual */ + PNG_ICC_CHECKSUM(0x209c35d2, 0xbbef7812, + PNG_MD5(0x34562abf, 0x994ccd06, 0x6d2c5721, 0xd0d68c5d), 0, 0, + "2007/07/25 00:05:37", 60960, "sRGB_v4_ICC_preference.icc") + + /* The following profiles have no known MD5 checksum. If there is a match + * on the (empty) MD5 the other fields are used to attempt a match and + * a warning is produced. The first two of these profiles have a 'cprt' tag + * which suggests that they were also made by Hewlett Packard. + */ + PNG_ICC_CHECKSUM(0xa054d762, 0x5d5129ce, + PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 0, + "2004/07/21 18:57:42", 3024, "sRGB_IEC61966-2-1_noBPC.icc") + + /* This is a 'mntr' (display) profile with a mediaWhitePointTag that does not + * match the D50 PCS illuminant in the header (it is in fact the D65 values, + * so the white point is recorded as the un-adapted value.) The profiles + * below only differ in one byte - the intent - and are basically the same as + * the previous profile except for the mediaWhitePointTag error and a missing + * chromaticAdaptationTag. + */ + PNG_ICC_CHECKSUM(0xf784f3fb, 0x182ea552, + PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 0, 1/*broken*/, + "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 perceptual") + + PNG_ICC_CHECKSUM(0x0398f3fc, 0xf29e526d, + PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 1/*broken*/, + "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 media-relative") +}; + +static int +png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr, + png_const_bytep profile, uLong adler) +{ + /* The quick check is to verify just the MD5 signature and trust the + * rest of the data. Because the profile has already been verified for + * correctness this is safe. png_colorspace_set_sRGB will check the 'intent' + * field too, so if the profile has been edited with an intent not defined + * by sRGB (but maybe defined by a later ICC specification) the read of + * the profile will fail at that point. + */ + + png_uint_32 length = 0; + png_uint_32 intent = 0x10000; /* invalid */ +#if PNG_sRGB_PROFILE_CHECKS > 1 + uLong crc = 0; /* the value for 0 length data */ +#endif + unsigned int i; + +#ifdef PNG_SET_OPTION_SUPPORTED + /* First see if PNG_SKIP_sRGB_CHECK_PROFILE has been set to "on" */ + if (((png_ptr->options >> PNG_SKIP_sRGB_CHECK_PROFILE) & 3) == + PNG_OPTION_ON) + return 0; +#endif + + for (i=0; i < (sizeof png_sRGB_checks) / (sizeof png_sRGB_checks[0]); ++i) + { + if (png_get_uint_32(profile+84) == png_sRGB_checks[i].md5[0] && + png_get_uint_32(profile+88) == png_sRGB_checks[i].md5[1] && + png_get_uint_32(profile+92) == png_sRGB_checks[i].md5[2] && + png_get_uint_32(profile+96) == png_sRGB_checks[i].md5[3]) + { + /* This may be one of the old HP profiles without an MD5, in that + * case we can only use the length and Adler32 (note that these + * are not used by default if there is an MD5!) + */ +# if PNG_sRGB_PROFILE_CHECKS == 0 + if (png_sRGB_checks[i].have_md5 != 0) + return 1+png_sRGB_checks[i].is_broken; +# endif + + /* Profile is unsigned or more checks have been configured in. */ + if (length == 0) + { + length = png_get_uint_32(profile); + intent = png_get_uint_32(profile+64); + } + + /* Length *and* intent must match */ + if (length == (png_uint_32) png_sRGB_checks[i].length && + intent == (png_uint_32) png_sRGB_checks[i].intent) + { + /* Now calculate the adler32 if not done already. */ + if (adler == 0) + { + adler = adler32(0, NULL, 0); + adler = adler32(adler, profile, length); + } + + if (adler == png_sRGB_checks[i].adler) + { + /* These basic checks suggest that the data has not been + * modified, but if the check level is more than 1 perform + * our own crc32 checksum on the data. + */ +# if PNG_sRGB_PROFILE_CHECKS > 1 + if (crc == 0) + { + crc = crc32(0, NULL, 0); + crc = crc32(crc, profile, length); + } + + /* So this check must pass for the 'return' below to happen. + */ + if (crc == png_sRGB_checks[i].crc) +# endif + { + if (png_sRGB_checks[i].is_broken != 0) + { + /* These profiles are known to have bad data that may cause + * problems if they are used, therefore attempt to + * discourage their use, skip the 'have_md5' warning below, + * which is made irrelevant by this error. + */ + png_chunk_report(png_ptr, "known incorrect sRGB profile", + PNG_CHUNK_ERROR); + } + + /* Warn that this being done; this isn't even an error since + * the profile is perfectly valid, but it would be nice if + * people used the up-to-date ones. + */ + else if (png_sRGB_checks[i].have_md5 == 0) + { + png_chunk_report(png_ptr, + "out-of-date sRGB profile with no signature", + PNG_CHUNK_WARNING); + } + + return 1+png_sRGB_checks[i].is_broken; + } + } + +# if PNG_sRGB_PROFILE_CHECKS > 0 + /* The signature matched, but the profile had been changed in some + * way. This probably indicates a data error or uninformed hacking. + * Fall through to "no match". + */ + png_chunk_report(png_ptr, + "Not recognizing known sRGB profile that has been edited", + PNG_CHUNK_WARNING); + break; +# endif + } + } + } + + return 0; /* no match */ +} +#endif /* PNG_sRGB_PROFILE_CHECKS >= 0 */ + +void /* PRIVATE */ +png_icc_set_sRGB(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_bytep profile, uLong adler) +{ + /* Is this profile one of the known ICC sRGB profiles? If it is, just set + * the sRGB information. + */ +#if PNG_sRGB_PROFILE_CHECKS >= 0 + if (png_compare_ICC_profile_with_sRGB(png_ptr, profile, adler) != 0) +#endif + (void)png_colorspace_set_sRGB(png_ptr, colorspace, + (int)/*already checked*/png_get_uint_32(profile+64)); +} +#endif /* sRGB */ + +int /* PRIVATE */ +png_colorspace_set_ICC(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length, png_const_bytep profile, + int color_type) +{ + if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0) + return 0; + + if (png_icc_check_length(png_ptr, colorspace, name, profile_length) != 0 && + png_icc_check_header(png_ptr, colorspace, name, profile_length, profile, + color_type) != 0 && + png_icc_check_tag_table(png_ptr, colorspace, name, profile_length, + profile) != 0) + { +# ifdef PNG_sRGB_SUPPORTED + /* If no sRGB support, don't try storing sRGB information */ + png_icc_set_sRGB(png_ptr, colorspace, profile, 0); +# endif + return 1; + } + + /* Failure case */ + return 0; +} +#endif /* iCCP */ + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +void /* PRIVATE */ +png_colorspace_set_rgb_coefficients(png_structrp png_ptr) +{ + /* Set the rgb_to_gray coefficients from the colorspace. */ + if (png_ptr->rgb_to_gray_coefficients_set == 0 && + (png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) + { + /* png_set_background has not been called, get the coefficients from the Y + * values of the colorspace colorants. + */ + png_fixed_point r = png_ptr->colorspace.end_points_XYZ.red_Y; + png_fixed_point g = png_ptr->colorspace.end_points_XYZ.green_Y; + png_fixed_point b = png_ptr->colorspace.end_points_XYZ.blue_Y; + png_fixed_point total = r+g+b; + + if (total > 0 && + r >= 0 && png_muldiv(&r, r, 32768, total) && r >= 0 && r <= 32768 && + g >= 0 && png_muldiv(&g, g, 32768, total) && g >= 0 && g <= 32768 && + b >= 0 && png_muldiv(&b, b, 32768, total) && b >= 0 && b <= 32768 && + r+g+b <= 32769) + { + /* We allow 0 coefficients here. r+g+b may be 32769 if two or + * all of the coefficients were rounded up. Handle this by + * reducing the *largest* coefficient by 1; this matches the + * approach used for the default coefficients in pngrtran.c + */ + int add = 0; + + if (r+g+b > 32768) + add = -1; + else if (r+g+b < 32768) + add = 1; + + if (add != 0) + { + if (g >= r && g >= b) + g += add; + else if (r >= g && r >= b) + r += add; + else + b += add; + } + + /* Check for an internal error. */ + if (r+g+b != 32768) + png_error(png_ptr, + "internal error handling cHRM coefficients"); + + else + { + png_ptr->rgb_to_gray_red_coeff = (png_uint_16)r; + png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g; + } + } + + /* This is a png_error at present even though it could be ignored - + * it should never happen, but it is important that if it does, the + * bug is fixed. + */ + else + png_error(png_ptr, "internal error handling cHRM->XYZ"); + } +} +#endif /* READ_RGB_TO_GRAY */ + +#endif /* COLORSPACE */ + +#ifdef __GNUC__ +/* This exists solely to work round a warning from GNU C. */ +static int /* PRIVATE */ +png_gt(size_t a, size_t b) +{ + return a > b; +} +#else +# define png_gt(a,b) ((a) > (b)) +#endif + +void /* PRIVATE */ +png_check_IHDR(png_const_structrp png_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type) +{ + int error = 0; + + /* Check for width and height valid values */ + if (width == 0) + { + png_warning(png_ptr, "Image width is zero in IHDR"); + error = 1; + } + + if (width > PNG_UINT_31_MAX) + { + png_warning(png_ptr, "Invalid image width in IHDR"); + error = 1; + } + + if (png_gt(((width + 7) & (~7)), + ((PNG_SIZE_MAX + - 48 /* big_row_buf hack */ + - 1) /* filter byte */ + / 8) /* 8-byte RGBA pixels */ + - 1)) /* extra max_pixel_depth pad */ + { + /* The size of the row must be within the limits of this architecture. + * Because the read code can perform arbitrary transformations the + * maximum size is checked here. Because the code in png_read_start_row + * adds extra space "for safety's sake" in several places a conservative + * limit is used here. + * + * NOTE: it would be far better to check the size that is actually used, + * but the effect in the real world is minor and the changes are more + * extensive, therefore much more dangerous and much more difficult to + * write in a way that avoids compiler warnings. + */ + png_warning(png_ptr, "Image width is too large for this architecture"); + error = 1; + } + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (width > png_ptr->user_width_max) +#else + if (width > PNG_USER_WIDTH_MAX) +#endif + { + png_warning(png_ptr, "Image width exceeds user limit in IHDR"); + error = 1; + } + + if (height == 0) + { + png_warning(png_ptr, "Image height is zero in IHDR"); + error = 1; + } + + if (height > PNG_UINT_31_MAX) + { + png_warning(png_ptr, "Invalid image height in IHDR"); + error = 1; + } + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (height > png_ptr->user_height_max) +#else + if (height > PNG_USER_HEIGHT_MAX) +#endif + { + png_warning(png_ptr, "Image height exceeds user limit in IHDR"); + error = 1; + } + + /* Check other values */ + if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 && + bit_depth != 8 && bit_depth != 16) + { + png_warning(png_ptr, "Invalid bit depth in IHDR"); + error = 1; + } + + if (color_type < 0 || color_type == 1 || + color_type == 5 || color_type > 6) + { + png_warning(png_ptr, "Invalid color type in IHDR"); + error = 1; + } + + if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) || + ((color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8)) + { + png_warning(png_ptr, "Invalid color type/bit depth combination in IHDR"); + error = 1; + } + + if (interlace_type >= PNG_INTERLACE_LAST) + { + png_warning(png_ptr, "Unknown interlace method in IHDR"); + error = 1; + } + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + { + png_warning(png_ptr, "Unknown compression method in IHDR"); + error = 1; + } + +#ifdef PNG_MNG_FEATURES_SUPPORTED + /* Accept filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not read a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 && + png_ptr->mng_features_permitted != 0) + png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); + + if (filter_type != PNG_FILTER_TYPE_BASE) + { + if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + (filter_type == PNG_INTRAPIXEL_DIFFERENCING) && + ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) && + (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA))) + { + png_warning(png_ptr, "Unknown filter method in IHDR"); + error = 1; + } + + if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0) + { + png_warning(png_ptr, "Invalid filter method in IHDR"); + error = 1; + } + } + +#else + if (filter_type != PNG_FILTER_TYPE_BASE) + { + png_warning(png_ptr, "Unknown filter method in IHDR"); + error = 1; + } +#endif + + if (error == 1) + png_error(png_ptr, "Invalid IHDR data"); +} + +#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) +/* ASCII to fp functions */ +/* Check an ASCII formated floating point value, see the more detailed + * comments in pngpriv.h + */ +/* The following is used internally to preserve the sticky flags */ +#define png_fp_add(state, flags) ((state) |= (flags)) +#define png_fp_set(state, value) ((state) = (value) | ((state) & PNG_FP_STICKY)) + +int /* PRIVATE */ +png_check_fp_number(png_const_charp string, png_size_t size, int *statep, + png_size_tp whereami) +{ + int state = *statep; + png_size_t i = *whereami; + + while (i < size) + { + int type; + /* First find the type of the next character */ + switch (string[i]) + { + case 43: type = PNG_FP_SAW_SIGN; break; + case 45: type = PNG_FP_SAW_SIGN + PNG_FP_NEGATIVE; break; + case 46: type = PNG_FP_SAW_DOT; break; + case 48: type = PNG_FP_SAW_DIGIT; break; + case 49: case 50: case 51: case 52: + case 53: case 54: case 55: case 56: + case 57: type = PNG_FP_SAW_DIGIT + PNG_FP_NONZERO; break; + case 69: + case 101: type = PNG_FP_SAW_E; break; + default: goto PNG_FP_End; + } + + /* Now deal with this type according to the current + * state, the type is arranged to not overlap the + * bits of the PNG_FP_STATE. + */ + switch ((state & PNG_FP_STATE) + (type & PNG_FP_SAW_ANY)) + { + case PNG_FP_INTEGER + PNG_FP_SAW_SIGN: + if ((state & PNG_FP_SAW_ANY) != 0) + goto PNG_FP_End; /* not a part of the number */ + + png_fp_add(state, type); + break; + + case PNG_FP_INTEGER + PNG_FP_SAW_DOT: + /* Ok as trailer, ok as lead of fraction. */ + if ((state & PNG_FP_SAW_DOT) != 0) /* two dots */ + goto PNG_FP_End; + + else if ((state & PNG_FP_SAW_DIGIT) != 0) /* trailing dot? */ + png_fp_add(state, type); + + else + png_fp_set(state, PNG_FP_FRACTION | type); + + break; + + case PNG_FP_INTEGER + PNG_FP_SAW_DIGIT: + if ((state & PNG_FP_SAW_DOT) != 0) /* delayed fraction */ + png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT); + + png_fp_add(state, type | PNG_FP_WAS_VALID); + + break; + + case PNG_FP_INTEGER + PNG_FP_SAW_E: + if ((state & PNG_FP_SAW_DIGIT) == 0) + goto PNG_FP_End; + + png_fp_set(state, PNG_FP_EXPONENT); + + break; + + /* case PNG_FP_FRACTION + PNG_FP_SAW_SIGN: + goto PNG_FP_End; ** no sign in fraction */ + + /* case PNG_FP_FRACTION + PNG_FP_SAW_DOT: + goto PNG_FP_End; ** Because SAW_DOT is always set */ + + case PNG_FP_FRACTION + PNG_FP_SAW_DIGIT: + png_fp_add(state, type | PNG_FP_WAS_VALID); + break; + + case PNG_FP_FRACTION + PNG_FP_SAW_E: + /* This is correct because the trailing '.' on an + * integer is handled above - so we can only get here + * with the sequence ".E" (with no preceding digits). + */ + if ((state & PNG_FP_SAW_DIGIT) == 0) + goto PNG_FP_End; + + png_fp_set(state, PNG_FP_EXPONENT); + + break; + + case PNG_FP_EXPONENT + PNG_FP_SAW_SIGN: + if ((state & PNG_FP_SAW_ANY) != 0) + goto PNG_FP_End; /* not a part of the number */ + + png_fp_add(state, PNG_FP_SAW_SIGN); + + break; + + /* case PNG_FP_EXPONENT + PNG_FP_SAW_DOT: + goto PNG_FP_End; */ + + case PNG_FP_EXPONENT + PNG_FP_SAW_DIGIT: + png_fp_add(state, PNG_FP_SAW_DIGIT | PNG_FP_WAS_VALID); + + break; + + /* case PNG_FP_EXPONEXT + PNG_FP_SAW_E: + goto PNG_FP_End; */ + + default: goto PNG_FP_End; /* I.e. break 2 */ + } + + /* The character seems ok, continue. */ + ++i; + } + +PNG_FP_End: + /* Here at the end, update the state and return the correct + * return code. + */ + *statep = state; + *whereami = i; + + return (state & PNG_FP_SAW_DIGIT) != 0; +} + + +/* The same but for a complete string. */ +int +png_check_fp_string(png_const_charp string, png_size_t size) +{ + int state=0; + png_size_t char_index=0; + + if (png_check_fp_number(string, size, &state, &char_index) != 0 && + (char_index == size || string[char_index] == 0)) + return state /* must be non-zero - see above */; + + return 0; /* i.e. fail */ +} +#endif /* pCAL || sCAL */ + +#ifdef PNG_sCAL_SUPPORTED +# ifdef PNG_FLOATING_POINT_SUPPORTED +/* Utility used below - a simple accurate power of ten from an integral + * exponent. + */ +static double +png_pow10(int power) +{ + int recip = 0; + double d = 1; + + /* Handle negative exponent with a reciprocal at the end because + * 10 is exact whereas .1 is inexact in base 2 + */ + if (power < 0) + { + if (power < DBL_MIN_10_EXP) return 0; + recip = 1, power = -power; + } + + if (power > 0) + { + /* Decompose power bitwise. */ + double mult = 10; + do + { + if (power & 1) d *= mult; + mult *= mult; + power >>= 1; + } + while (power > 0); + + if (recip != 0) d = 1/d; + } + /* else power is 0 and d is 1 */ + + return d; +} + +/* Function to format a floating point value in ASCII with a given + * precision. + */ +void /* PRIVATE */ +png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size, + double fp, unsigned int precision) +{ + /* We use standard functions from math.h, but not printf because + * that would require stdio. The caller must supply a buffer of + * sufficient size or we will png_error. The tests on size and + * the space in ascii[] consumed are indicated below. + */ + if (precision < 1) + precision = DBL_DIG; + + /* Enforce the limit of the implementation precision too. */ + if (precision > DBL_DIG+1) + precision = DBL_DIG+1; + + /* Basic sanity checks */ + if (size >= precision+5) /* See the requirements below. */ + { + if (fp < 0) + { + fp = -fp; + *ascii++ = 45; /* '-' PLUS 1 TOTAL 1 */ + --size; + } + + if (fp >= DBL_MIN && fp <= DBL_MAX) + { + int exp_b10; /* A base 10 exponent */ + double base; /* 10^exp_b10 */ + + /* First extract a base 10 exponent of the number, + * the calculation below rounds down when converting + * from base 2 to base 10 (multiply by log10(2) - + * 0.3010, but 77/256 is 0.3008, so exp_b10 needs to + * be increased. Note that the arithmetic shift + * performs a floor() unlike C arithmetic - using a + * C multiply would break the following for negative + * exponents. + */ + (void)frexp(fp, &exp_b10); /* exponent to base 2 */ + + exp_b10 = (exp_b10 * 77) >> 8; /* <= exponent to base 10 */ + + /* Avoid underflow here. */ + base = png_pow10(exp_b10); /* May underflow */ + + while (base < DBL_MIN || base < fp) + { + /* And this may overflow. */ + double test = png_pow10(exp_b10+1); + + if (test <= DBL_MAX) + ++exp_b10, base = test; + + else + break; + } + + /* Normalize fp and correct exp_b10, after this fp is in the + * range [.1,1) and exp_b10 is both the exponent and the digit + * *before* which the decimal point should be inserted + * (starting with 0 for the first digit). Note that this + * works even if 10^exp_b10 is out of range because of the + * test on DBL_MAX above. + */ + fp /= base; + while (fp >= 1) fp /= 10, ++exp_b10; + + /* Because of the code above fp may, at this point, be + * less than .1, this is ok because the code below can + * handle the leading zeros this generates, so no attempt + * is made to correct that here. + */ + + { + unsigned int czero, clead, cdigits; + char exponent[10]; + + /* Allow up to two leading zeros - this will not lengthen + * the number compared to using E-n. + */ + if (exp_b10 < 0 && exp_b10 > -3) /* PLUS 3 TOTAL 4 */ + { + czero = -exp_b10; /* PLUS 2 digits: TOTAL 3 */ + exp_b10 = 0; /* Dot added below before first output. */ + } + else + czero = 0; /* No zeros to add */ + + /* Generate the digit list, stripping trailing zeros and + * inserting a '.' before a digit if the exponent is 0. + */ + clead = czero; /* Count of leading zeros */ + cdigits = 0; /* Count of digits in list. */ + + do + { + double d; + + fp *= 10; + /* Use modf here, not floor and subtract, so that + * the separation is done in one step. At the end + * of the loop don't break the number into parts so + * that the final digit is rounded. + */ + if (cdigits+czero+1 < precision+clead) + fp = modf(fp, &d); + + else + { + d = floor(fp + .5); + + if (d > 9) + { + /* Rounding up to 10, handle that here. */ + if (czero > 0) + { + --czero, d = 1; + if (cdigits == 0) --clead; + } + else + { + while (cdigits > 0 && d > 9) + { + int ch = *--ascii; + + if (exp_b10 != (-1)) + ++exp_b10; + + else if (ch == 46) + { + ch = *--ascii, ++size; + /* Advance exp_b10 to '1', so that the + * decimal point happens after the + * previous digit. + */ + exp_b10 = 1; + } + + --cdigits; + d = ch - 47; /* I.e. 1+(ch-48) */ + } + + /* Did we reach the beginning? If so adjust the + * exponent but take into account the leading + * decimal point. + */ + if (d > 9) /* cdigits == 0 */ + { + if (exp_b10 == (-1)) + { + /* Leading decimal point (plus zeros?), if + * we lose the decimal point here it must + * be reentered below. + */ + int ch = *--ascii; + + if (ch == 46) + ++size, exp_b10 = 1; + + /* Else lost a leading zero, so 'exp_b10' is + * still ok at (-1) + */ + } + else + ++exp_b10; + + /* In all cases we output a '1' */ + d = 1; + } + } + } + fp = 0; /* Guarantees termination below. */ + } + + if (d == 0) + { + ++czero; + if (cdigits == 0) ++clead; + } + else + { + /* Included embedded zeros in the digit count. */ + cdigits += czero - clead; + clead = 0; + + while (czero > 0) + { + /* exp_b10 == (-1) means we just output the decimal + * place - after the DP don't adjust 'exp_b10' any + * more! + */ + if (exp_b10 != (-1)) + { + if (exp_b10 == 0) *ascii++ = 46, --size; + /* PLUS 1: TOTAL 4 */ + --exp_b10; + } + *ascii++ = 48, --czero; + } + + if (exp_b10 != (-1)) + { + if (exp_b10 == 0) + *ascii++ = 46, --size; /* counted above */ + + --exp_b10; + } + *ascii++ = (char)(48 + (int)d), ++cdigits; + } + } + while (cdigits+czero < precision+clead && fp > DBL_MIN); + + /* The total output count (max) is now 4+precision */ + + /* Check for an exponent, if we don't need one we are + * done and just need to terminate the string. At + * this point exp_b10==(-1) is effectively if flag - it got + * to '-1' because of the decrement after outputting + * the decimal point above (the exponent required is + * *not* -1!) + */ + if (exp_b10 >= (-1) && exp_b10 <= 2) + { + /* The following only happens if we didn't output the + * leading zeros above for negative exponent, so this + * doesn't add to the digit requirement. Note that the + * two zeros here can only be output if the two leading + * zeros were *not* output, so this doesn't increase + * the output count. + */ + while (--exp_b10 >= 0) *ascii++ = 48; + + *ascii = 0; + + /* Total buffer requirement (including the '\0') is + * 5+precision - see check at the start. + */ + return; + } + + /* Here if an exponent is required, adjust size for + * the digits we output but did not count. The total + * digit output here so far is at most 1+precision - no + * decimal point and no leading or trailing zeros have + * been output. + */ + size -= cdigits; + + *ascii++ = 69, --size; /* 'E': PLUS 1 TOTAL 2+precision */ + + /* The following use of an unsigned temporary avoids ambiguities in + * the signed arithmetic on exp_b10 and permits GCC at least to do + * better optimization. + */ + { + unsigned int uexp_b10; + + if (exp_b10 < 0) + { + *ascii++ = 45, --size; /* '-': PLUS 1 TOTAL 3+precision */ + uexp_b10 = -exp_b10; + } + + else + uexp_b10 = exp_b10; + + cdigits = 0; + + while (uexp_b10 > 0) + { + exponent[cdigits++] = (char)(48 + uexp_b10 % 10); + uexp_b10 /= 10; + } + } + + /* Need another size check here for the exponent digits, so + * this need not be considered above. + */ + if (size > cdigits) + { + while (cdigits > 0) *ascii++ = exponent[--cdigits]; + + *ascii = 0; + + return; + } + } + } + else if (!(fp >= DBL_MIN)) + { + *ascii++ = 48; /* '0' */ + *ascii = 0; + return; + } + else + { + *ascii++ = 105; /* 'i' */ + *ascii++ = 110; /* 'n' */ + *ascii++ = 102; /* 'f' */ + *ascii = 0; + return; + } + } + + /* Here on buffer too small. */ + png_error(png_ptr, "ASCII conversion buffer too small"); +} + +# endif /* FLOATING_POINT */ + +# ifdef PNG_FIXED_POINT_SUPPORTED +/* Function to format a fixed point value in ASCII. + */ +void /* PRIVATE */ +png_ascii_from_fixed(png_const_structrp png_ptr, png_charp ascii, + png_size_t size, png_fixed_point fp) +{ + /* Require space for 10 decimal digits, a decimal point, a minus sign and a + * trailing \0, 13 characters: + */ + if (size > 12) + { + png_uint_32 num; + + /* Avoid overflow here on the minimum integer. */ + if (fp < 0) + *ascii++ = 45, num = -fp; + else + num = fp; + + if (num <= 0x80000000) /* else overflowed */ + { + unsigned int ndigits = 0, first = 16 /* flag value */; + char digits[10]; + + while (num) + { + /* Split the low digit off num: */ + unsigned int tmp = num/10; + num -= tmp*10; + digits[ndigits++] = (char)(48 + num); + /* Record the first non-zero digit, note that this is a number + * starting at 1, it's not actually the array index. + */ + if (first == 16 && num > 0) + first = ndigits; + num = tmp; + } + + if (ndigits > 0) + { + while (ndigits > 5) *ascii++ = digits[--ndigits]; + /* The remaining digits are fractional digits, ndigits is '5' or + * smaller at this point. It is certainly not zero. Check for a + * non-zero fractional digit: + */ + if (first <= 5) + { + unsigned int i; + *ascii++ = 46; /* decimal point */ + /* ndigits may be <5 for small numbers, output leading zeros + * then ndigits digits to first: + */ + i = 5; + while (ndigits < i) *ascii++ = 48, --i; + while (ndigits >= first) *ascii++ = digits[--ndigits]; + /* Don't output the trailing zeros! */ + } + } + else + *ascii++ = 48; + + /* And null terminate the string: */ + *ascii = 0; + return; + } + } + + /* Here on buffer too small. */ + png_error(png_ptr, "ASCII conversion buffer too small"); +} +# endif /* FIXED_POINT */ +#endif /* SCAL */ + +#if defined(PNG_FLOATING_POINT_SUPPORTED) && \ + !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ + (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \ + defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \ + (defined(PNG_sCAL_SUPPORTED) && \ + defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)) +png_fixed_point +png_fixed(png_const_structrp png_ptr, double fp, png_const_charp text) +{ + double r = floor(100000 * fp + .5); + + if (r > 2147483647. || r < -2147483648.) + png_fixed_error(png_ptr, text); + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(text) +# endif + + return (png_fixed_point)r; +} +#endif + +#if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_COLORSPACE_SUPPORTED) ||\ + defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED) +/* muldiv functions */ +/* This API takes signed arguments and rounds the result to the nearest + * integer (or, for a fixed point number - the standard argument - to + * the nearest .00001). Overflow and divide by zero are signalled in + * the result, a boolean - true on success, false on overflow. + */ +int +png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times, + png_int_32 divisor) +{ + /* Return a * times / divisor, rounded. */ + if (divisor != 0) + { + if (a == 0 || times == 0) + { + *res = 0; + return 1; + } + else + { +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + double r = a; + r *= times; + r /= divisor; + r = floor(r+.5); + + /* A png_fixed_point is a 32-bit integer. */ + if (r <= 2147483647. && r >= -2147483648.) + { + *res = (png_fixed_point)r; + return 1; + } +#else + int negative = 0; + png_uint_32 A, T, D; + png_uint_32 s16, s32, s00; + + if (a < 0) + negative = 1, A = -a; + else + A = a; + + if (times < 0) + negative = !negative, T = -times; + else + T = times; + + if (divisor < 0) + negative = !negative, D = -divisor; + else + D = divisor; + + /* Following can't overflow because the arguments only + * have 31 bits each, however the result may be 32 bits. + */ + s16 = (A >> 16) * (T & 0xffff) + + (A & 0xffff) * (T >> 16); + /* Can't overflow because the a*times bit is only 30 + * bits at most. + */ + s32 = (A >> 16) * (T >> 16) + (s16 >> 16); + s00 = (A & 0xffff) * (T & 0xffff); + + s16 = (s16 & 0xffff) << 16; + s00 += s16; + + if (s00 < s16) + ++s32; /* carry */ + + if (s32 < D) /* else overflow */ + { + /* s32.s00 is now the 64-bit product, do a standard + * division, we know that s32 < D, so the maximum + * required shift is 31. + */ + int bitshift = 32; + png_fixed_point result = 0; /* NOTE: signed */ + + while (--bitshift >= 0) + { + png_uint_32 d32, d00; + + if (bitshift > 0) + d32 = D >> (32-bitshift), d00 = D << bitshift; + + else + d32 = 0, d00 = D; + + if (s32 > d32) + { + if (s00 < d00) --s32; /* carry */ + s32 -= d32, s00 -= d00, result += 1<= d00) + s32 = 0, s00 -= d00, result += 1<= (D >> 1)) + ++result; + + if (negative != 0) + result = -result; + + /* Check for overflow. */ + if ((negative != 0 && result <= 0) || + (negative == 0 && result >= 0)) + { + *res = result; + return 1; + } + } +#endif + } + } + + return 0; +} +#endif /* READ_GAMMA || INCH_CONVERSIONS */ + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED) +/* The following is for when the caller doesn't much care about the + * result. + */ +png_fixed_point +png_muldiv_warn(png_const_structrp png_ptr, png_fixed_point a, png_int_32 times, + png_int_32 divisor) +{ + png_fixed_point result; + + if (png_muldiv(&result, a, times, divisor) != 0) + return result; + + png_warning(png_ptr, "fixed point overflow ignored"); + return 0; +} +#endif + +#ifdef PNG_GAMMA_SUPPORTED /* more fixed point functions for gamma */ +/* Calculate a reciprocal, return 0 on div-by-zero or overflow. */ +png_fixed_point +png_reciprocal(png_fixed_point a) +{ +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + double r = floor(1E10/a+.5); + + if (r <= 2147483647. && r >= -2147483648.) + return (png_fixed_point)r; +#else + png_fixed_point res; + + if (png_muldiv(&res, 100000, 100000, a) != 0) + return res; +#endif + + return 0; /* error/overflow */ +} + +/* This is the shared test on whether a gamma value is 'significant' - whether + * it is worth doing gamma correction. + */ +int /* PRIVATE */ +png_gamma_significant(png_fixed_point gamma_val) +{ + return gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED || + gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED; +} +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +#ifdef PNG_16BIT_SUPPORTED +/* A local convenience routine. */ +static png_fixed_point +png_product2(png_fixed_point a, png_fixed_point b) +{ + /* The required result is 1/a * 1/b; the following preserves accuracy. */ +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + double r = a * 1E-5; + r *= b; + r = floor(r+.5); + + if (r <= 2147483647. && r >= -2147483648.) + return (png_fixed_point)r; +#else + png_fixed_point res; + + if (png_muldiv(&res, a, b, 100000) != 0) + return res; +#endif + + return 0; /* overflow */ +} +#endif /* 16BIT */ + +/* The inverse of the above. */ +png_fixed_point +png_reciprocal2(png_fixed_point a, png_fixed_point b) +{ + /* The required result is 1/a * 1/b; the following preserves accuracy. */ +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + if (a != 0 && b != 0) + { + double r = 1E15/a; + r /= b; + r = floor(r+.5); + + if (r <= 2147483647. && r >= -2147483648.) + return (png_fixed_point)r; + } +#else + /* This may overflow because the range of png_fixed_point isn't symmetric, + * but this API is only used for the product of file and screen gamma so it + * doesn't matter that the smallest number it can produce is 1/21474, not + * 1/100000 + */ + png_fixed_point res = png_product2(a, b); + + if (res != 0) + return png_reciprocal(res); +#endif + + return 0; /* overflow */ +} +#endif /* READ_GAMMA */ + +#ifdef PNG_READ_GAMMA_SUPPORTED /* gamma table code */ +#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED +/* Fixed point gamma. + * + * The code to calculate the tables used below can be found in the shell script + * contrib/tools/intgamma.sh + * + * To calculate gamma this code implements fast log() and exp() calls using only + * fixed point arithmetic. This code has sufficient precision for either 8-bit + * or 16-bit sample values. + * + * The tables used here were calculated using simple 'bc' programs, but C double + * precision floating point arithmetic would work fine. + * + * 8-bit log table + * This is a table of -log(value/255)/log(2) for 'value' in the range 128 to + * 255, so it's the base 2 logarithm of a normalized 8-bit floating point + * mantissa. The numbers are 32-bit fractions. + */ +static const png_uint_32 +png_8bit_l2[128] = +{ + 4270715492U, 4222494797U, 4174646467U, 4127164793U, 4080044201U, 4033279239U, + 3986864580U, 3940795015U, 3895065449U, 3849670902U, 3804606499U, 3759867474U, + 3715449162U, 3671346997U, 3627556511U, 3584073329U, 3540893168U, 3498011834U, + 3455425220U, 3413129301U, 3371120137U, 3329393864U, 3287946700U, 3246774933U, + 3205874930U, 3165243125U, 3124876025U, 3084770202U, 3044922296U, 3005329011U, + 2965987113U, 2926893432U, 2888044853U, 2849438323U, 2811070844U, 2772939474U, + 2735041326U, 2697373562U, 2659933400U, 2622718104U, 2585724991U, 2548951424U, + 2512394810U, 2476052606U, 2439922311U, 2404001468U, 2368287663U, 2332778523U, + 2297471715U, 2262364947U, 2227455964U, 2192742551U, 2158222529U, 2123893754U, + 2089754119U, 2055801552U, 2022034013U, 1988449497U, 1955046031U, 1921821672U, + 1888774511U, 1855902668U, 1823204291U, 1790677560U, 1758320682U, 1726131893U, + 1694109454U, 1662251657U, 1630556815U, 1599023271U, 1567649391U, 1536433567U, + 1505374214U, 1474469770U, 1443718700U, 1413119487U, 1382670639U, 1352370686U, + 1322218179U, 1292211689U, 1262349810U, 1232631153U, 1203054352U, 1173618059U, + 1144320946U, 1115161701U, 1086139034U, 1057251672U, 1028498358U, 999877854U, + 971388940U, 943030410U, 914801076U, 886699767U, 858725327U, 830876614U, + 803152505U, 775551890U, 748073672U, 720716771U, 693480120U, 666362667U, + 639363374U, 612481215U, 585715177U, 559064263U, 532527486U, 506103872U, + 479792461U, 453592303U, 427502463U, 401522014U, 375650043U, 349885648U, + 324227938U, 298676034U, 273229066U, 247886176U, 222646516U, 197509248U, + 172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U, + 24347096U, 0U + +#if 0 + /* The following are the values for 16-bit tables - these work fine for the + * 8-bit conversions but produce very slightly larger errors in the 16-bit + * log (about 1.2 as opposed to 0.7 absolute error in the final value). To + * use these all the shifts below must be adjusted appropriately. + */ + 65166, 64430, 63700, 62976, 62257, 61543, 60835, 60132, 59434, 58741, 58054, + 57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803, + 50170, 49542, 48918, 48298, 47682, 47070, 46462, 45858, 45257, 44661, 44068, + 43479, 42894, 42312, 41733, 41159, 40587, 40020, 39455, 38894, 38336, 37782, + 37230, 36682, 36137, 35595, 35057, 34521, 33988, 33459, 32932, 32408, 31887, + 31369, 30854, 30341, 29832, 29325, 28820, 28319, 27820, 27324, 26830, 26339, + 25850, 25364, 24880, 24399, 23920, 23444, 22970, 22499, 22029, 21562, 21098, + 20636, 20175, 19718, 19262, 18808, 18357, 17908, 17461, 17016, 16573, 16132, + 15694, 15257, 14822, 14390, 13959, 13530, 13103, 12678, 12255, 11834, 11415, + 10997, 10582, 10168, 9756, 9346, 8937, 8531, 8126, 7723, 7321, 6921, 6523, + 6127, 5732, 5339, 4947, 4557, 4169, 3782, 3397, 3014, 2632, 2251, 1872, 1495, + 1119, 744, 372 +#endif +}; + +static png_int_32 +png_log8bit(unsigned int x) +{ + unsigned int lg2 = 0; + /* Each time 'x' is multiplied by 2, 1 must be subtracted off the final log, + * because the log is actually negate that means adding 1. The final + * returned value thus has the range 0 (for 255 input) to 7.994 (for 1 + * input), return -1 for the overflow (log 0) case, - so the result is + * always at most 19 bits. + */ + if ((x &= 0xff) == 0) + return -1; + + if ((x & 0xf0) == 0) + lg2 = 4, x <<= 4; + + if ((x & 0xc0) == 0) + lg2 += 2, x <<= 2; + + if ((x & 0x80) == 0) + lg2 += 1, x <<= 1; + + /* result is at most 19 bits, so this cast is safe: */ + return (png_int_32)((lg2 << 16) + ((png_8bit_l2[x-128]+32768)>>16)); +} + +/* The above gives exact (to 16 binary places) log2 values for 8-bit images, + * for 16-bit images we use the most significant 8 bits of the 16-bit value to + * get an approximation then multiply the approximation by a correction factor + * determined by the remaining up to 8 bits. This requires an additional step + * in the 16-bit case. + * + * We want log2(value/65535), we have log2(v'/255), where: + * + * value = v' * 256 + v'' + * = v' * f + * + * So f is value/v', which is equal to (256+v''/v') since v' is in the range 128 + * to 255 and v'' is in the range 0 to 255 f will be in the range 256 to less + * than 258. The final factor also needs to correct for the fact that our 8-bit + * value is scaled by 255, whereas the 16-bit values must be scaled by 65535. + * + * This gives a final formula using a calculated value 'x' which is value/v' and + * scaling by 65536 to match the above table: + * + * log2(x/257) * 65536 + * + * Since these numbers are so close to '1' we can use simple linear + * interpolation between the two end values 256/257 (result -368.61) and 258/257 + * (result 367.179). The values used below are scaled by a further 64 to give + * 16-bit precision in the interpolation: + * + * Start (256): -23591 + * Zero (257): 0 + * End (258): 23499 + */ +#ifdef PNG_16BIT_SUPPORTED +static png_int_32 +png_log16bit(png_uint_32 x) +{ + unsigned int lg2 = 0; + + /* As above, but now the input has 16 bits. */ + if ((x &= 0xffff) == 0) + return -1; + + if ((x & 0xff00) == 0) + lg2 = 8, x <<= 8; + + if ((x & 0xf000) == 0) + lg2 += 4, x <<= 4; + + if ((x & 0xc000) == 0) + lg2 += 2, x <<= 2; + + if ((x & 0x8000) == 0) + lg2 += 1, x <<= 1; + + /* Calculate the base logarithm from the top 8 bits as a 28-bit fractional + * value. + */ + lg2 <<= 28; + lg2 += (png_8bit_l2[(x>>8)-128]+8) >> 4; + + /* Now we need to interpolate the factor, this requires a division by the top + * 8 bits. Do this with maximum precision. + */ + x = ((x << 16) + (x >> 9)) / (x >> 8); + + /* Since we divided by the top 8 bits of 'x' there will be a '1' at 1<<24, + * the value at 1<<16 (ignoring this) will be 0 or 1; this gives us exactly + * 16 bits to interpolate to get the low bits of the result. Round the + * answer. Note that the end point values are scaled by 64 to retain overall + * precision and that 'lg2' is current scaled by an extra 12 bits, so adjust + * the overall scaling by 6-12. Round at every step. + */ + x -= 1U << 24; + + if (x <= 65536U) /* <= '257' */ + lg2 += ((23591U * (65536U-x)) + (1U << (16+6-12-1))) >> (16+6-12); + + else + lg2 -= ((23499U * (x-65536U)) + (1U << (16+6-12-1))) >> (16+6-12); + + /* Safe, because the result can't have more than 20 bits: */ + return (png_int_32)((lg2 + 2048) >> 12); +} +#endif /* 16BIT */ + +/* The 'exp()' case must invert the above, taking a 20-bit fixed point + * logarithmic value and returning a 16 or 8-bit number as appropriate. In + * each case only the low 16 bits are relevant - the fraction - since the + * integer bits (the top 4) simply determine a shift. + * + * The worst case is the 16-bit distinction between 65535 and 65534. This + * requires perhaps spurious accuracy in the decoding of the logarithm to + * distinguish log2(65535/65534.5) - 10^-5 or 17 bits. There is little chance + * of getting this accuracy in practice. + * + * To deal with this the following exp() function works out the exponent of the + * frational part of the logarithm by using an accurate 32-bit value from the + * top four fractional bits then multiplying in the remaining bits. + */ +static const png_uint_32 +png_32bit_exp[16] = +{ + /* NOTE: the first entry is deliberately set to the maximum 32-bit value. */ + 4294967295U, 4112874773U, 3938502376U, 3771522796U, 3611622603U, 3458501653U, + 3311872529U, 3171459999U, 3037000500U, 2908241642U, 2784941738U, 2666869345U, + 2553802834U, 2445529972U, 2341847524U, 2242560872U +}; + +/* Adjustment table; provided to explain the numbers in the code below. */ +#if 0 +for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"} + 11 44937.64284865548751208448 + 10 45180.98734845585101160448 + 9 45303.31936980687359311872 + 8 45364.65110595323018870784 + 7 45395.35850361789624614912 + 6 45410.72259715102037508096 + 5 45418.40724413220722311168 + 4 45422.25021786898173001728 + 3 45424.17186732298419044352 + 2 45425.13273269940811464704 + 1 45425.61317555035558641664 + 0 45425.85339951654943850496 +#endif + +static png_uint_32 +png_exp(png_fixed_point x) +{ + if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */ + { + /* Obtain a 4-bit approximation */ + png_uint_32 e = png_32bit_exp[(x >> 12) & 0x0f]; + + /* Incorporate the low 12 bits - these decrease the returned value by + * multiplying by a number less than 1 if the bit is set. The multiplier + * is determined by the above table and the shift. Notice that the values + * converge on 45426 and this is used to allow linear interpolation of the + * low bits. + */ + if (x & 0x800) + e -= (((e >> 16) * 44938U) + 16U) >> 5; + + if (x & 0x400) + e -= (((e >> 16) * 45181U) + 32U) >> 6; + + if (x & 0x200) + e -= (((e >> 16) * 45303U) + 64U) >> 7; + + if (x & 0x100) + e -= (((e >> 16) * 45365U) + 128U) >> 8; + + if (x & 0x080) + e -= (((e >> 16) * 45395U) + 256U) >> 9; + + if (x & 0x040) + e -= (((e >> 16) * 45410U) + 512U) >> 10; + + /* And handle the low 6 bits in a single block. */ + e -= (((e >> 16) * 355U * (x & 0x3fU)) + 256U) >> 9; + + /* Handle the upper bits of x. */ + e >>= x >> 16; + return e; + } + + /* Check for overflow */ + if (x <= 0) + return png_32bit_exp[0]; + + /* Else underflow */ + return 0; +} + +static png_byte +png_exp8bit(png_fixed_point lg2) +{ + /* Get a 32-bit value: */ + png_uint_32 x = png_exp(lg2); + + /* Convert the 32-bit value to 0..255 by multiplying by 256-1. Note that the + * second, rounding, step can't overflow because of the first, subtraction, + * step. + */ + x -= x >> 8; + return (png_byte)(((x + 0x7fffffU) >> 24) & 0xff); +} + +#ifdef PNG_16BIT_SUPPORTED +static png_uint_16 +png_exp16bit(png_fixed_point lg2) +{ + /* Get a 32-bit value: */ + png_uint_32 x = png_exp(lg2); + + /* Convert the 32-bit value to 0..65535 by multiplying by 65536-1: */ + x -= x >> 16; + return (png_uint_16)((x + 32767U) >> 16); +} +#endif /* 16BIT */ +#endif /* FLOATING_ARITHMETIC */ + +png_byte +png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val) +{ + if (value > 0 && value < 255) + { +# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + /* 'value' is unsigned, ANSI-C90 requires the compiler to correctly + * convert this to a floating point value. This includes values that + * would overflow if 'value' were to be converted to 'int'. + * + * Apparently GCC, however, does an intermediate conversion to (int) + * on some (ARM) but not all (x86) platforms, possibly because of + * hardware FP limitations. (E.g. if the hardware conversion always + * assumes the integer register contains a signed value.) This results + * in ANSI-C undefined behavior for large values. + * + * Other implementations on the same machine might actually be ANSI-C90 + * conformant and therefore compile spurious extra code for the large + * values. + * + * We can be reasonably sure that an unsigned to float conversion + * won't be faster than an int to float one. Therefore this code + * assumes responsibility for the undefined behavior, which it knows + * can't happen because of the check above. + * + * Note the argument to this routine is an (unsigned int) because, on + * 16-bit platforms, it is assigned a value which might be out of + * range for an (int); that would result in undefined behavior in the + * caller if the *argument* ('value') were to be declared (int). + */ + double r = floor(255*pow((int)/*SAFE*/value/255.,gamma_val*.00001)+.5); + return (png_byte)r; +# else + png_int_32 lg2 = png_log8bit(value); + png_fixed_point res; + + if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1) != 0) + return png_exp8bit(res); + + /* Overflow. */ + value = 0; +# endif + } + + return (png_byte)(value & 0xff); +} + +#ifdef PNG_16BIT_SUPPORTED +png_uint_16 +png_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val) +{ + if (value > 0 && value < 65535) + { +# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + /* The same (unsigned int)->(double) constraints apply here as above, + * however in this case the (unsigned int) to (int) conversion can + * overflow on an ANSI-C90 compliant system so the cast needs to ensure + * that this is not possible. + */ + double r = floor(65535*pow((png_int_32)value/65535., + gamma_val*.00001)+.5); + return (png_uint_16)r; +# else + png_int_32 lg2 = png_log16bit(value); + png_fixed_point res; + + if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1) != 0) + return png_exp16bit(res); + + /* Overflow. */ + value = 0; +# endif + } + + return (png_uint_16)value; +} +#endif /* 16BIT */ + +/* This does the right thing based on the bit_depth field of the + * png_struct, interpreting values as 8-bit or 16-bit. While the result + * is nominally a 16-bit value if bit depth is 8 then the result is + * 8-bit (as are the arguments.) + */ +png_uint_16 /* PRIVATE */ +png_gamma_correct(png_structrp png_ptr, unsigned int value, + png_fixed_point gamma_val) +{ + if (png_ptr->bit_depth == 8) + return png_gamma_8bit_correct(value, gamma_val); + +#ifdef PNG_16BIT_SUPPORTED + else + return png_gamma_16bit_correct(value, gamma_val); +#else + /* should not reach this */ + return 0; +#endif /* 16BIT */ +} + +#ifdef PNG_16BIT_SUPPORTED +/* Internal function to build a single 16-bit table - the table consists of + * 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount + * to shift the input values right (or 16-number_of_signifiant_bits). + * + * The caller is responsible for ensuring that the table gets cleaned up on + * png_error (i.e. if one of the mallocs below fails) - i.e. the *table argument + * should be somewhere that will be cleaned. + */ +static void +png_build_16bit_table(png_structrp png_ptr, png_uint_16pp *ptable, + PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val) +{ + /* Various values derived from 'shift': */ + PNG_CONST unsigned int num = 1U << (8U - shift); +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + /* CSE the division and work round wacky GCC warnings (see the comments + * in png_gamma_8bit_correct for where these come from.) + */ + PNG_CONST double fmax = 1./(((png_int_32)1 << (16U - shift))-1); +#endif + PNG_CONST unsigned int max = (1U << (16U - shift))-1U; + PNG_CONST unsigned int max_by_2 = 1U << (15U-shift); + unsigned int i; + + png_uint_16pp table = *ptable = + (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p))); + + for (i = 0; i < num; i++) + { + png_uint_16p sub_table = table[i] = + (png_uint_16p)png_malloc(png_ptr, 256 * (sizeof (png_uint_16))); + + /* The 'threshold' test is repeated here because it can arise for one of + * the 16-bit tables even if the others don't hit it. + */ + if (png_gamma_significant(gamma_val) != 0) + { + /* The old code would overflow at the end and this would cause the + * 'pow' function to return a result >1, resulting in an + * arithmetic error. This code follows the spec exactly; ig is + * the recovered input sample, it always has 8-16 bits. + * + * We want input * 65535/max, rounded, the arithmetic fits in 32 + * bits (unsigned) so long as max <= 32767. + */ + unsigned int j; + for (j = 0; j < 256; j++) + { + png_uint_32 ig = (j << (8-shift)) + i; +# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + /* Inline the 'max' scaling operation: */ + /* See png_gamma_8bit_correct for why the cast to (int) is + * required here. + */ + double d = floor(65535.*pow(ig*fmax, gamma_val*.00001)+.5); + sub_table[j] = (png_uint_16)d; +# else + if (shift != 0) + ig = (ig * 65535U + max_by_2)/max; + + sub_table[j] = png_gamma_16bit_correct(ig, gamma_val); +# endif + } + } + else + { + /* We must still build a table, but do it the fast way. */ + unsigned int j; + + for (j = 0; j < 256; j++) + { + png_uint_32 ig = (j << (8-shift)) + i; + + if (shift != 0) + ig = (ig * 65535U + max_by_2)/max; + + sub_table[j] = (png_uint_16)ig; + } + } + } +} + +/* NOTE: this function expects the *inverse* of the overall gamma transformation + * required. + */ +static void +png_build_16to8_table(png_structrp png_ptr, png_uint_16pp *ptable, + PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val) +{ + PNG_CONST unsigned int num = 1U << (8U - shift); + PNG_CONST unsigned int max = (1U << (16U - shift))-1U; + unsigned int i; + png_uint_32 last; + + png_uint_16pp table = *ptable = + (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p))); + + /* 'num' is the number of tables and also the number of low bits of low + * bits of the input 16-bit value used to select a table. Each table is + * itself indexed by the high 8 bits of the value. + */ + for (i = 0; i < num; i++) + table[i] = (png_uint_16p)png_malloc(png_ptr, + 256 * (sizeof (png_uint_16))); + + /* 'gamma_val' is set to the reciprocal of the value calculated above, so + * pow(out,g) is an *input* value. 'last' is the last input value set. + * + * In the loop 'i' is used to find output values. Since the output is + * 8-bit there are only 256 possible values. The tables are set up to + * select the closest possible output value for each input by finding + * the input value at the boundary between each pair of output values + * and filling the table up to that boundary with the lower output + * value. + * + * The boundary values are 0.5,1.5..253.5,254.5. Since these are 9-bit + * values the code below uses a 16-bit value in i; the values start at + * 128.5 (for 0.5) and step by 257, for a total of 254 values (the last + * entries are filled with 255). Start i at 128 and fill all 'last' + * table entries <= 'max' + */ + last = 0; + for (i = 0; i < 255; ++i) /* 8-bit output value */ + { + /* Find the corresponding maximum input value */ + png_uint_16 out = (png_uint_16)(i * 257U); /* 16-bit output value */ + + /* Find the boundary value in 16 bits: */ + png_uint_32 bound = png_gamma_16bit_correct(out+128U, gamma_val); + + /* Adjust (round) to (16-shift) bits: */ + bound = (bound * max + 32768U)/65535U + 1U; + + while (last < bound) + { + table[last & (0xffU >> shift)][last >> (8U - shift)] = out; + last++; + } + } + + /* And fill in the final entries. */ + while (last < (num << 8)) + { + table[last & (0xff >> shift)][last >> (8U - shift)] = 65535U; + last++; + } +} +#endif /* 16BIT */ + +/* Build a single 8-bit table: same as the 16-bit case but much simpler (and + * typically much faster). Note that libpng currently does no sBIT processing + * (apparently contrary to the spec) so a 256-entry table is always generated. + */ +static void +png_build_8bit_table(png_structrp png_ptr, png_bytepp ptable, + PNG_CONST png_fixed_point gamma_val) +{ + unsigned int i; + png_bytep table = *ptable = (png_bytep)png_malloc(png_ptr, 256); + + if (png_gamma_significant(gamma_val) != 0) + for (i=0; i<256; i++) + table[i] = png_gamma_8bit_correct(i, gamma_val); + + else + for (i=0; i<256; ++i) + table[i] = (png_byte)(i & 0xff); +} + +/* Used from png_read_destroy and below to release the memory used by the gamma + * tables. + */ +void /* PRIVATE */ +png_destroy_gamma_table(png_structrp png_ptr) +{ + png_free(png_ptr, png_ptr->gamma_table); + png_ptr->gamma_table = NULL; + +#ifdef PNG_16BIT_SUPPORTED + if (png_ptr->gamma_16_table != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_table[i]); + } + png_free(png_ptr, png_ptr->gamma_16_table); + png_ptr->gamma_16_table = NULL; + } +#endif /* 16BIT */ + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + png_free(png_ptr, png_ptr->gamma_from_1); + png_ptr->gamma_from_1 = NULL; + png_free(png_ptr, png_ptr->gamma_to_1); + png_ptr->gamma_to_1 = NULL; + +#ifdef PNG_16BIT_SUPPORTED + if (png_ptr->gamma_16_from_1 != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_from_1[i]); + } + png_free(png_ptr, png_ptr->gamma_16_from_1); + png_ptr->gamma_16_from_1 = NULL; + } + if (png_ptr->gamma_16_to_1 != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_to_1[i]); + } + png_free(png_ptr, png_ptr->gamma_16_to_1); + png_ptr->gamma_16_to_1 = NULL; + } +#endif /* 16BIT */ +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ +} + +/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit + * tables, we don't make a full table if we are reducing to 8-bit in + * the future. Note also how the gamma_16 tables are segmented so that + * we don't need to allocate > 64K chunks for a full 16-bit table. + */ +void /* PRIVATE */ +png_build_gamma_table(png_structrp png_ptr, int bit_depth) +{ + png_debug(1, "in png_build_gamma_table"); + + /* Remove any existing table; this copes with multiple calls to + * png_read_update_info. The warning is because building the gamma tables + * multiple times is a performance hit - it's harmless but the ability to call + * png_read_update_info() multiple times is new in 1.5.6 so it seems sensible + * to warn if the app introduces such a hit. + */ + if (png_ptr->gamma_table != NULL || png_ptr->gamma_16_table != NULL) + { + png_warning(png_ptr, "gamma table being rebuilt"); + png_destroy_gamma_table(png_ptr); + } + + if (bit_depth <= 8) + { + png_build_8bit_table(png_ptr, &png_ptr->gamma_table, + png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma) : PNG_FP_1); + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0) + { + png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1, + png_reciprocal(png_ptr->colorspace.gamma)); + + png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1, + png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) : + png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */); + } +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ + } +#ifdef PNG_16BIT_SUPPORTED + else + { + png_byte shift, sig_bit; + + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + sig_bit = png_ptr->sig_bit.red; + + if (png_ptr->sig_bit.green > sig_bit) + sig_bit = png_ptr->sig_bit.green; + + if (png_ptr->sig_bit.blue > sig_bit) + sig_bit = png_ptr->sig_bit.blue; + } + else + sig_bit = png_ptr->sig_bit.gray; + + /* 16-bit gamma code uses this equation: + * + * ov = table[(iv & 0xff) >> gamma_shift][iv >> 8] + * + * Where 'iv' is the input color value and 'ov' is the output value - + * pow(iv, gamma). + * + * Thus the gamma table consists of up to 256 256-entry tables. The table + * is selected by the (8-gamma_shift) most significant of the low 8 bits of + * the color value then indexed by the upper 8 bits: + * + * table[low bits][high 8 bits] + * + * So the table 'n' corresponds to all those 'iv' of: + * + * ..<(n+1 << gamma_shift)-1> + * + */ + if (sig_bit > 0 && sig_bit < 16U) + /* shift == insignificant bits */ + shift = (png_byte)((16U - sig_bit) & 0xff); + + else + shift = 0; /* keep all 16 bits */ + + if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) != 0) + { + /* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively + * the significant bits in the *input* when the output will + * eventually be 8 bits. By default it is 11. + */ + if (shift < (16U - PNG_MAX_GAMMA_8)) + shift = (16U - PNG_MAX_GAMMA_8); + } + + if (shift > 8U) + shift = 8U; /* Guarantees at least one table! */ + + png_ptr->gamma_shift = shift; + + /* NOTE: prior to 1.5.4 this test used to include PNG_BACKGROUND (now + * PNG_COMPOSE). This effectively smashed the background calculation for + * 16-bit output because the 8-bit table assumes the result will be reduced + * to 8 bits. + */ + if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) != 0) + png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift, + png_ptr->screen_gamma > 0 ? png_product2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma) : PNG_FP_1); + + else + png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift, + png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma) : PNG_FP_1); + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0) + { + png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift, + png_reciprocal(png_ptr->colorspace.gamma)); + + /* Notice that the '16 from 1' table should be full precision, however + * the lookup on this table still uses gamma_shift, so it can't be. + * TODO: fix this. + */ + png_build_16bit_table(png_ptr, &png_ptr->gamma_16_from_1, shift, + png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) : + png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */); + } +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ + } +#endif /* 16BIT */ +} +#endif /* READ_GAMMA */ + +/* HARDWARE OR SOFTWARE OPTION SUPPORT */ +#ifdef PNG_SET_OPTION_SUPPORTED +int PNGAPI +png_set_option(png_structrp png_ptr, int option, int onoff) +{ + if (png_ptr != NULL && option >= 0 && option < PNG_OPTION_NEXT && + (option & 1) == 0) + { + int mask = 3 << option; + int setting = (2 + (onoff != 0)) << option; + int current = png_ptr->options; + + png_ptr->options = (png_byte)(((current & ~mask) | setting) & 0xff); + + return (current & mask) >> option; + } + + return PNG_OPTION_INVALID; +} +#endif + +/* sRGB support */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +/* sRGB conversion tables; these are machine generated with the code in + * contrib/tools/makesRGB.c. The actual sRGB transfer curve defined in the + * specification (see the article at http://en.wikipedia.org/wiki/SRGB) + * is used, not the gamma=1/2.2 approximation use elsewhere in libpng. + * The sRGB to linear table is exact (to the nearest 16-bit linear fraction). + * The inverse (linear to sRGB) table has accuracies as follows: + * + * For all possible (255*65535+1) input values: + * + * error: -0.515566 - 0.625971, 79441 (0.475369%) of readings inexact + * + * For the input values corresponding to the 65536 16-bit values: + * + * error: -0.513727 - 0.607759, 308 (0.469978%) of readings inexact + * + * In all cases the inexact readings are only off by one. + */ + +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +/* The convert-to-sRGB table is only currently required for read. */ +const png_uint_16 png_sRGB_table[256] = +{ + 0,20,40,60,80,99,119,139, + 159,179,199,219,241,264,288,313, + 340,367,396,427,458,491,526,562, + 599,637,677,718,761,805,851,898, + 947,997,1048,1101,1156,1212,1270,1330, + 1391,1453,1517,1583,1651,1720,1790,1863, + 1937,2013,2090,2170,2250,2333,2418,2504, + 2592,2681,2773,2866,2961,3058,3157,3258, + 3360,3464,3570,3678,3788,3900,4014,4129, + 4247,4366,4488,4611,4736,4864,4993,5124, + 5257,5392,5530,5669,5810,5953,6099,6246, + 6395,6547,6700,6856,7014,7174,7335,7500, + 7666,7834,8004,8177,8352,8528,8708,8889, + 9072,9258,9445,9635,9828,10022,10219,10417, + 10619,10822,11028,11235,11446,11658,11873,12090, + 12309,12530,12754,12980,13209,13440,13673,13909, + 14146,14387,14629,14874,15122,15371,15623,15878, + 16135,16394,16656,16920,17187,17456,17727,18001, + 18277,18556,18837,19121,19407,19696,19987,20281, + 20577,20876,21177,21481,21787,22096,22407,22721, + 23038,23357,23678,24002,24329,24658,24990,25325, + 25662,26001,26344,26688,27036,27386,27739,28094, + 28452,28813,29176,29542,29911,30282,30656,31033, + 31412,31794,32179,32567,32957,33350,33745,34143, + 34544,34948,35355,35764,36176,36591,37008,37429, + 37852,38278,38706,39138,39572,40009,40449,40891, + 41337,41785,42236,42690,43147,43606,44069,44534, + 45002,45473,45947,46423,46903,47385,47871,48359, + 48850,49344,49841,50341,50844,51349,51858,52369, + 52884,53401,53921,54445,54971,55500,56032,56567, + 57105,57646,58190,58737,59287,59840,60396,60955, + 61517,62082,62650,63221,63795,64372,64952,65535 +}; +#endif /* SIMPLIFIED_READ */ + +/* The base/delta tables are required for both read and write (but currently + * only the simplified versions.) + */ +const png_uint_16 png_sRGB_base[512] = +{ + 128,1782,3383,4644,5675,6564,7357,8074, + 8732,9346,9921,10463,10977,11466,11935,12384, + 12816,13233,13634,14024,14402,14769,15125,15473, + 15812,16142,16466,16781,17090,17393,17690,17981, + 18266,18546,18822,19093,19359,19621,19879,20133, + 20383,20630,20873,21113,21349,21583,21813,22041, + 22265,22487,22707,22923,23138,23350,23559,23767, + 23972,24175,24376,24575,24772,24967,25160,25352, + 25542,25730,25916,26101,26284,26465,26645,26823, + 27000,27176,27350,27523,27695,27865,28034,28201, + 28368,28533,28697,28860,29021,29182,29341,29500, + 29657,29813,29969,30123,30276,30429,30580,30730, + 30880,31028,31176,31323,31469,31614,31758,31902, + 32045,32186,32327,32468,32607,32746,32884,33021, + 33158,33294,33429,33564,33697,33831,33963,34095, + 34226,34357,34486,34616,34744,34873,35000,35127, + 35253,35379,35504,35629,35753,35876,35999,36122, + 36244,36365,36486,36606,36726,36845,36964,37083, + 37201,37318,37435,37551,37668,37783,37898,38013, + 38127,38241,38354,38467,38580,38692,38803,38915, + 39026,39136,39246,39356,39465,39574,39682,39790, + 39898,40005,40112,40219,40325,40431,40537,40642, + 40747,40851,40955,41059,41163,41266,41369,41471, + 41573,41675,41777,41878,41979,42079,42179,42279, + 42379,42478,42577,42676,42775,42873,42971,43068, + 43165,43262,43359,43456,43552,43648,43743,43839, + 43934,44028,44123,44217,44311,44405,44499,44592, + 44685,44778,44870,44962,45054,45146,45238,45329, + 45420,45511,45601,45692,45782,45872,45961,46051, + 46140,46229,46318,46406,46494,46583,46670,46758, + 46846,46933,47020,47107,47193,47280,47366,47452, + 47538,47623,47709,47794,47879,47964,48048,48133, + 48217,48301,48385,48468,48552,48635,48718,48801, + 48884,48966,49048,49131,49213,49294,49376,49458, + 49539,49620,49701,49782,49862,49943,50023,50103, + 50183,50263,50342,50422,50501,50580,50659,50738, + 50816,50895,50973,51051,51129,51207,51285,51362, + 51439,51517,51594,51671,51747,51824,51900,51977, + 52053,52129,52205,52280,52356,52432,52507,52582, + 52657,52732,52807,52881,52956,53030,53104,53178, + 53252,53326,53400,53473,53546,53620,53693,53766, + 53839,53911,53984,54056,54129,54201,54273,54345, + 54417,54489,54560,54632,54703,54774,54845,54916, + 54987,55058,55129,55199,55269,55340,55410,55480, + 55550,55620,55689,55759,55828,55898,55967,56036, + 56105,56174,56243,56311,56380,56448,56517,56585, + 56653,56721,56789,56857,56924,56992,57059,57127, + 57194,57261,57328,57395,57462,57529,57595,57662, + 57728,57795,57861,57927,57993,58059,58125,58191, + 58256,58322,58387,58453,58518,58583,58648,58713, + 58778,58843,58908,58972,59037,59101,59165,59230, + 59294,59358,59422,59486,59549,59613,59677,59740, + 59804,59867,59930,59993,60056,60119,60182,60245, + 60308,60370,60433,60495,60558,60620,60682,60744, + 60806,60868,60930,60992,61054,61115,61177,61238, + 61300,61361,61422,61483,61544,61605,61666,61727, + 61788,61848,61909,61969,62030,62090,62150,62211, + 62271,62331,62391,62450,62510,62570,62630,62689, + 62749,62808,62867,62927,62986,63045,63104,63163, + 63222,63281,63340,63398,63457,63515,63574,63632, + 63691,63749,63807,63865,63923,63981,64039,64097, + 64155,64212,64270,64328,64385,64443,64500,64557, + 64614,64672,64729,64786,64843,64900,64956,65013, + 65070,65126,65183,65239,65296,65352,65409,65465 +}; + +const png_byte png_sRGB_delta[512] = +{ + 207,201,158,129,113,100,90,82,77,72,68,64,61,59,56,54, + 52,50,49,47,46,45,43,42,41,40,39,39,38,37,36,36, + 35,34,34,33,33,32,32,31,31,30,30,30,29,29,28,28, + 28,27,27,27,27,26,26,26,25,25,25,25,24,24,24,24, + 23,23,23,23,23,22,22,22,22,22,22,21,21,21,21,21, + 21,20,20,20,20,20,20,20,20,19,19,19,19,19,19,19, + 19,18,18,18,18,18,18,18,18,18,18,17,17,17,17,17, + 17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; +#endif /* SIMPLIFIED READ/WRITE sRGB support */ + +/* SIMPLIFIED READ/WRITE SUPPORT */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +static int +png_image_free_function(png_voidp argument) +{ + png_imagep image = png_voidcast(png_imagep, argument); + png_controlp cp = image->opaque; + png_control c; + + /* Double check that we have a png_ptr - it should be impossible to get here + * without one. + */ + if (cp->png_ptr == NULL) + return 0; + + /* First free any data held in the control structure. */ +# ifdef PNG_STDIO_SUPPORTED + if (cp->owned_file != 0) + { + FILE *fp = png_voidcast(FILE*, cp->png_ptr->io_ptr); + cp->owned_file = 0; + + /* Ignore errors here. */ + if (fp != NULL) + { + cp->png_ptr->io_ptr = NULL; + (void)fclose(fp); + } + } +# endif + + /* Copy the control structure so that the original, allocated, version can be + * safely freed. Notice that a png_error here stops the remainder of the + * cleanup, but this is probably fine because that would indicate bad memory + * problems anyway. + */ + c = *cp; + image->opaque = &c; + png_free(c.png_ptr, cp); + + /* Then the structures, calling the correct API. */ + if (c.for_write != 0) + { +# ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED + png_destroy_write_struct(&c.png_ptr, &c.info_ptr); +# else + png_error(c.png_ptr, "simplified write not supported"); +# endif + } + else + { +# ifdef PNG_SIMPLIFIED_READ_SUPPORTED + png_destroy_read_struct(&c.png_ptr, &c.info_ptr, NULL); +# else + png_error(c.png_ptr, "simplified read not supported"); +# endif + } + + /* Success. */ + return 1; +} + +void PNGAPI +png_image_free(png_imagep image) +{ + /* Safely call the real function, but only if doing so is safe at this point + * (if not inside an error handling context). Otherwise assume + * png_safe_execute will call this API after the return. + */ + if (image != NULL && image->opaque != NULL && + image->opaque->error_buf == NULL) + { + /* Ignore errors here: */ + (void)png_safe_execute(image, png_image_free_function, image); + image->opaque = NULL; + } +} + +int /* PRIVATE */ +png_image_error(png_imagep image, png_const_charp error_message) +{ + /* Utility to log an error. */ + png_safecat(image->message, (sizeof image->message), 0, error_message); + image->warning_or_error |= PNG_IMAGE_ERROR; + png_image_free(image); + return 0; +} + +#endif /* SIMPLIFIED READ/WRITE */ +#endif /* READ || WRITE */ diff --git a/source/Irrlicht/libpng/png.h b/source/Irrlicht/libpng/png.h new file mode 100644 index 00000000..04648c7a --- /dev/null +++ b/source/Irrlicht/libpng/png.h @@ -0,0 +1,3257 @@ + +/* png.h - header file for PNG reference library + * + * libpng version 1.6.23, June 9, 2016 + * + * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license (See LICENSE, below) + * + * Authors and maintainers: + * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat + * libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger + * libpng versions 0.97, January 1998, through 1.6.23, June 9, 2016: + * Glenn Randers-Pehrson. + * See also "Contributing Authors", below. + */ + +/* + * COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: + * + * If you modify libpng you may insert additional notices immediately following + * this sentence. + * + * This code is released under the libpng license. + * + * Some files in the "contrib" directory and some configure-generated + * files that are distributed with libpng have other copyright owners and + * are released under other open source licenses. + * + * libpng versions 1.0.7, July 1, 2000 through 1.6.23, June 9, 2016 are + * Copyright (c) 2000-2002, 2004, 2006-2016 Glenn Randers-Pehrson, are + * derived from libpng-1.0.6, and are distributed according to the same + * disclaimer and license as libpng-1.0.6 with the following individuals + * added to the list of Contributing Authors: + * + * Simon-Pierre Cadieux + * Eric S. Raymond + * Mans Rullgard + * Cosmin Truta + * Gilles Vollant + * James Yu + * + * and with the following additions to the disclaimer: + * + * There is no warranty against interference with your enjoyment of the + * library or against infringement. There is no warranty that our + * efforts or the library will fulfill any of your particular purposes + * or needs. This library is provided with all faults, and the entire + * risk of satisfactory quality, performance, accuracy, and effort is with + * the user. + * + * Some files in the "contrib" directory have other copyright owners and + * are released under other open source licenses. + * + * + * libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are + * Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from + * libpng-0.96, and are distributed according to the same disclaimer and + * license as libpng-0.96, with the following individuals added to the list + * of Contributing Authors: + * + * Tom Lane + * Glenn Randers-Pehrson + * Willem van Schaik + * + * Some files in the "scripts" directory have different copyright owners + * but are also released under this license. + * + * libpng versions 0.89, June 1996, through 0.96, May 1997, are + * Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88, + * and are distributed according to the same disclaimer and license as + * libpng-0.88, with the following individuals added to the list of + * Contributing Authors: + * + * John Bowler + * Kevin Bracey + * Sam Bushell + * Magnus Holmgren + * Greg Roelofs + * Tom Tanner + * + * Some files in the "scripts" directory have other copyright owners + * but are released under this license. + * + * libpng versions 0.5, May 1995, through 0.88, January 1996, are + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * + * For the purposes of this copyright and license, "Contributing Authors" + * is defined as the following set of individuals: + * + * Andreas Dilger + * Dave Martindale + * Guy Eric Schalnat + * Paul Schmidt + * Tim Wegner + * + * The PNG Reference Library is supplied "AS IS". The Contributing Authors + * and Group 42, Inc. disclaim all warranties, expressed or implied, + * including, without limitation, the warranties of merchantability and of + * fitness for any purpose. The Contributing Authors and Group 42, Inc. + * assume no liability for direct, indirect, incidental, special, exemplary, + * or consequential damages, which may result from the use of the PNG + * Reference Library, even if advised of the possibility of such damage. + * + * Permission is hereby granted to use, copy, modify, and distribute this + * source code, or portions hereof, for any purpose, without fee, subject + * to the following restrictions: + * + * 1. The origin of this source code must not be misrepresented. + * + * 2. Altered versions must be plainly marked as such and must not + * be misrepresented as being the original source. + * + * 3. This Copyright notice may not be removed or altered from any + * source or altered source distribution. + * + * The Contributing Authors and Group 42, Inc. specifically permit, without + * fee, and encourage the use of this source code as a component to + * supporting the PNG file format in commercial products. If you use this + * source code in a product, acknowledgment is not required but would be + * appreciated. + * + * END OF COPYRIGHT NOTICE, DISCLAIMER, and LICENSE. + * + * TRADEMARK: + * + * The name "libpng" has not been registered by the Copyright owner + * as a trademark in any jurisdiction. However, because libpng has + * been distributed and maintained world-wide, continually since 1995, + * the Copyright owner claims "common-law trademark protection" in any + * jurisdiction where common-law trademark is recognized. + * + * OSI CERTIFICATION: + * + * Libpng is OSI Certified Open Source Software. OSI Certified Open Source is + * a certification mark of the Open Source Initiative. OSI has not addressed + * the additional disclaimers inserted at version 1.0.7. + * + * EXPORT CONTROL: + * + * The Copyright owner believes that the Export Control Classification + * Number (ECCN) for libpng is EAR99, which means not subject to export + * controls or International Traffic in Arms Regulations (ITAR) because + * it is open source, publicly available software, that does not contain + * any encryption software. See the EAR, paragraphs 734.3(b)(3) and + * 734.7(b). + */ + +/* + * A "png_get_copyright" function is available, for convenient use in "about" + * boxes and the like: + * + * printf("%s", png_get_copyright(NULL)); + * + * Also, the PNG logo (in PNG format, of course) is supplied in the + * files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). + */ + +/* + * The contributing authors would like to thank all those who helped + * with testing, bug fixes, and patience. This wouldn't have been + * possible without all of you. + * + * Thanks to Frank J. T. Wojcik for helping with the documentation. + */ + +/* Note about libpng version numbers: + * + * Due to various miscommunications, unforeseen code incompatibilities + * and occasional factors outside the authors' control, version numbering + * on the library has not always been consistent and straightforward. + * The following table summarizes matters since version 0.89c, which was + * the first widely used release: + * + * source png.h png.h shared-lib + * version string int version + * ------- ------ ----- ---------- + * 0.89c "1.0 beta 3" 0.89 89 1.0.89 + * 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90] + * 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95] + * 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96] + * 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97] + * 0.97c 0.97 97 2.0.97 + * 0.98 0.98 98 2.0.98 + * 0.99 0.99 98 2.0.99 + * 0.99a-m 0.99 99 2.0.99 + * 1.00 1.00 100 2.1.0 [100 should be 10000] + * 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000] + * 1.0.1 png.h string is 10001 2.1.0 + * 1.0.1a-e identical to the 10002 from here on, the shared library + * 1.0.2 source version) 10002 is 2.V where V is the source code + * 1.0.2a-b 10003 version, except as noted. + * 1.0.3 10003 + * 1.0.3a-d 10004 + * 1.0.4 10004 + * 1.0.4a-f 10005 + * 1.0.5 (+ 2 patches) 10005 + * 1.0.5a-d 10006 + * 1.0.5e-r 10100 (not source compatible) + * 1.0.5s-v 10006 (not binary compatible) + * 1.0.6 (+ 3 patches) 10006 (still binary incompatible) + * 1.0.6d-f 10007 (still binary incompatible) + * 1.0.6g 10007 + * 1.0.6h 10007 10.6h (testing xy.z so-numbering) + * 1.0.6i 10007 10.6i + * 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0) + * 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible) + * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible) + * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible) + * 1.0.7 1 10007 (still compatible) + * ... + * 1.0.19 10 10019 10.so.0.19[.0] + * ... + * 1.2.56 13 10256 12.so.0.56[.0] + * ... + * 1.5.27 15 10527 15.so.15.27[.0] + * ... + * 1.6.23 16 10623 16.so.16.23[.0] + * + * Henceforth the source version will match the shared-library major + * and minor numbers; the shared-library major version number will be + * used for changes in backward compatibility, as it is intended. The + * PNG_LIBPNG_VER macro, which is not used within libpng but is available + * for applications, is an unsigned integer of the form xyyzz corresponding + * to the source version x.y.z (leading zeros in y and z). Beta versions + * were given the previous public release number plus a letter, until + * version 1.0.6j; from then on they were given the upcoming public + * release number plus "betaNN" or "rcNN". + * + * Binary incompatibility exists only when applications make direct access + * to the info_ptr or png_ptr members through png.h, and the compiled + * application is loaded with a different version of the library. + * + * DLLNUM will change each time there are forward or backward changes + * in binary compatibility (e.g., when a new feature is added). + * + * See libpng.txt or libpng.3 for more information. The PNG specification + * is available as a W3C Recommendation and as an ISO Specification, + * + * + * If you just need to read a PNG file and don't want to read the documentation + * skip to the end of this file and read the section entitled 'simplified API'. + */ + +/* Version information for png.h - this should match the version in png.c */ +#define PNG_LIBPNG_VER_STRING "1.6.23" +#define PNG_HEADER_VERSION_STRING \ + " libpng version 1.6.23 - June 9, 2016\n" + +#define PNG_LIBPNG_VER_SONUM 16 +#define PNG_LIBPNG_VER_DLLNUM 16 + +/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */ +#define PNG_LIBPNG_VER_MAJOR 1 +#define PNG_LIBPNG_VER_MINOR 6 +#define PNG_LIBPNG_VER_RELEASE 23 + +/* This should match the numeric part of the final component of + * PNG_LIBPNG_VER_STRING, omitting any leading zero: + */ + +#define PNG_LIBPNG_VER_BUILD 0 + +/* Release Status */ +#define PNG_LIBPNG_BUILD_ALPHA 1 +#define PNG_LIBPNG_BUILD_BETA 2 +#define PNG_LIBPNG_BUILD_RC 3 +#define PNG_LIBPNG_BUILD_STABLE 4 +#define PNG_LIBPNG_BUILD_RELEASE_STATUS_MASK 7 + +/* Release-Specific Flags */ +#define PNG_LIBPNG_BUILD_PATCH 8 /* Can be OR'ed with + PNG_LIBPNG_BUILD_STABLE only */ +#define PNG_LIBPNG_BUILD_PRIVATE 16 /* Cannot be OR'ed with + PNG_LIBPNG_BUILD_SPECIAL */ +#define PNG_LIBPNG_BUILD_SPECIAL 32 /* Cannot be OR'ed with + PNG_LIBPNG_BUILD_PRIVATE */ + +#define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_STABLE + +/* Careful here. At one time, Guy wanted to use 082, but that would be octal. + * We must not include leading zeros. + * Versions 0.7 through 1.0.0 were in the range 0 to 100 here (only + * version 1.0.0 was mis-numbered 100 instead of 10000). From + * version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release + */ +#define PNG_LIBPNG_VER 10623 /* 1.6.23 */ + +/* Library configuration: these options cannot be changed after + * the library has been built. + */ +#ifndef PNGLCONF_H + /* If pnglibconf.h is missing, you can + * copy scripts/pnglibconf.h.prebuilt to pnglibconf.h + */ +# include "pnglibconf.h" +#endif + +#ifndef PNG_VERSION_INFO_ONLY + /* Machine specific configuration. */ +# include "pngconf.h" +#endif + +/* + * Added at libpng-1.2.8 + * + * Ref MSDN: Private as priority over Special + * VS_FF_PRIVATEBUILD File *was not* built using standard release + * procedures. If this value is given, the StringFileInfo block must + * contain a PrivateBuild string. + * + * VS_FF_SPECIALBUILD File *was* built by the original company using + * standard release procedures but is a variation of the standard + * file of the same version number. If this value is given, the + * StringFileInfo block must contain a SpecialBuild string. + */ + +#ifdef PNG_USER_PRIVATEBUILD /* From pnglibconf.h */ +# define PNG_LIBPNG_BUILD_TYPE \ + (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_PRIVATE) +#else +# ifdef PNG_LIBPNG_SPECIALBUILD +# define PNG_LIBPNG_BUILD_TYPE \ + (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_SPECIAL) +# else +# define PNG_LIBPNG_BUILD_TYPE (PNG_LIBPNG_BUILD_BASE_TYPE) +# endif +#endif + +#ifndef PNG_VERSION_INFO_ONLY + +/* Inhibit C++ name-mangling for libpng functions but not for system calls. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Version information for C files, stored in png.c. This had better match + * the version above. + */ +#define png_libpng_ver png_get_header_ver(NULL) + +/* This file is arranged in several sections: + * + * 1. [omitted] + * 2. Any configuration options that can be specified by for the application + * code when it is built. (Build time configuration is in pnglibconf.h) + * 3. Type definitions (base types are defined in pngconf.h), structure + * definitions. + * 4. Exported library functions. + * 5. Simplified API. + * 6. Implementation options. + * + * The library source code has additional files (principally pngpriv.h) that + * allow configuration of the library. + */ + +/* Section 1: [omitted] */ + +/* Section 2: run time configuration + * See pnglibconf.h for build time configuration + * + * Run time configuration allows the application to choose between + * implementations of certain arithmetic APIs. The default is set + * at build time and recorded in pnglibconf.h, but it is safe to + * override these (and only these) settings. Note that this won't + * change what the library does, only application code, and the + * settings can (and probably should) be made on a per-file basis + * by setting the #defines before including png.h + * + * Use macros to read integers from PNG data or use the exported + * functions? + * PNG_USE_READ_MACROS: use the macros (see below) Note that + * the macros evaluate their argument multiple times. + * PNG_NO_USE_READ_MACROS: call the relevant library function. + * + * Use the alternative algorithm for compositing alpha samples that + * does not use division? + * PNG_READ_COMPOSITE_NODIV_SUPPORTED: use the 'no division' + * algorithm. + * PNG_NO_READ_COMPOSITE_NODIV: use the 'division' algorithm. + * + * How to handle benign errors if PNG_ALLOW_BENIGN_ERRORS is + * false? + * PNG_ALLOW_BENIGN_ERRORS: map calls to the benign error + * APIs to png_warning. + * Otherwise the calls are mapped to png_error. + */ + +/* Section 3: type definitions, including structures and compile time + * constants. + * See pngconf.h for base types that vary by machine/system + */ + +/* This triggers a compiler error in png.c, if png.c and png.h + * do not agree upon the version number. + */ +typedef char* png_libpng_version_1_6_23; + +/* Basic control structions. Read libpng-manual.txt or libpng.3 for more info. + * + * png_struct is the cache of information used while reading or writing a single + * PNG file. One of these is always required, although the simplified API + * (below) hides the creation and destruction of it. + */ +typedef struct png_struct_def png_struct; +typedef const png_struct * png_const_structp; +typedef png_struct * png_structp; +typedef png_struct * * png_structpp; + +/* png_info contains information read from or to be written to a PNG file. One + * or more of these must exist while reading or creating a PNG file. The + * information is not used by libpng during read but is used to control what + * gets written when a PNG file is created. "png_get_" function calls read + * information during read and "png_set_" functions calls write information + * when creating a PNG. + * been moved into a separate header file that is not accessible to + * applications. Read libpng-manual.txt or libpng.3 for more info. + */ +typedef struct png_info_def png_info; +typedef png_info * png_infop; +typedef const png_info * png_const_infop; +typedef png_info * * png_infopp; + +/* Types with names ending 'p' are pointer types. The corresponding types with + * names ending 'rp' are identical pointer types except that the pointer is + * marked 'restrict', which means that it is the only pointer to the object + * passed to the function. Applications should not use the 'restrict' types; + * it is always valid to pass 'p' to a pointer with a function argument of the + * corresponding 'rp' type. Different compilers have different rules with + * regard to type matching in the presence of 'restrict'. For backward + * compatibility libpng callbacks never have 'restrict' in their parameters and, + * consequentially, writing portable application code is extremely difficult if + * an attempt is made to use 'restrict'. + */ +typedef png_struct * PNG_RESTRICT png_structrp; +typedef const png_struct * PNG_RESTRICT png_const_structrp; +typedef png_info * PNG_RESTRICT png_inforp; +typedef const png_info * PNG_RESTRICT png_const_inforp; + +/* Three color definitions. The order of the red, green, and blue, (and the + * exact size) is not important, although the size of the fields need to + * be png_byte or png_uint_16 (as defined below). + */ +typedef struct png_color_struct +{ + png_byte red; + png_byte green; + png_byte blue; +} png_color; +typedef png_color * png_colorp; +typedef const png_color * png_const_colorp; +typedef png_color * * png_colorpp; + +typedef struct png_color_16_struct +{ + png_byte index; /* used for palette files */ + png_uint_16 red; /* for use in red green blue files */ + png_uint_16 green; + png_uint_16 blue; + png_uint_16 gray; /* for use in grayscale files */ +} png_color_16; +typedef png_color_16 * png_color_16p; +typedef const png_color_16 * png_const_color_16p; +typedef png_color_16 * * png_color_16pp; + +typedef struct png_color_8_struct +{ + png_byte red; /* for use in red green blue files */ + png_byte green; + png_byte blue; + png_byte gray; /* for use in grayscale files */ + png_byte alpha; /* for alpha channel files */ +} png_color_8; +typedef png_color_8 * png_color_8p; +typedef const png_color_8 * png_const_color_8p; +typedef png_color_8 * * png_color_8pp; + +/* + * The following two structures are used for the in-core representation + * of sPLT chunks. + */ +typedef struct png_sPLT_entry_struct +{ + png_uint_16 red; + png_uint_16 green; + png_uint_16 blue; + png_uint_16 alpha; + png_uint_16 frequency; +} png_sPLT_entry; +typedef png_sPLT_entry * png_sPLT_entryp; +typedef const png_sPLT_entry * png_const_sPLT_entryp; +typedef png_sPLT_entry * * png_sPLT_entrypp; + +/* When the depth of the sPLT palette is 8 bits, the color and alpha samples + * occupy the LSB of their respective members, and the MSB of each member + * is zero-filled. The frequency member always occupies the full 16 bits. + */ + +typedef struct png_sPLT_struct +{ + png_charp name; /* palette name */ + png_byte depth; /* depth of palette samples */ + png_sPLT_entryp entries; /* palette entries */ + png_int_32 nentries; /* number of palette entries */ +} png_sPLT_t; +typedef png_sPLT_t * png_sPLT_tp; +typedef const png_sPLT_t * png_const_sPLT_tp; +typedef png_sPLT_t * * png_sPLT_tpp; + +#ifdef PNG_TEXT_SUPPORTED +/* png_text holds the contents of a text/ztxt/itxt chunk in a PNG file, + * and whether that contents is compressed or not. The "key" field + * points to a regular zero-terminated C string. The "text" fields can be a + * regular C string, an empty string, or a NULL pointer. + * However, the structure returned by png_get_text() will always contain + * the "text" field as a regular zero-terminated C string (possibly + * empty), never a NULL pointer, so it can be safely used in printf() and + * other string-handling functions. Note that the "itxt_length", "lang", and + * "lang_key" members of the structure only exist when the library is built + * with iTXt chunk support. Prior to libpng-1.4.0 the library was built by + * default without iTXt support. Also note that when iTXt *is* supported, + * the "lang" and "lang_key" fields contain NULL pointers when the + * "compression" field contains * PNG_TEXT_COMPRESSION_NONE or + * PNG_TEXT_COMPRESSION_zTXt. Note that the "compression value" is not the + * same as what appears in the PNG tEXt/zTXt/iTXt chunk's "compression flag" + * which is always 0 or 1, or its "compression method" which is always 0. + */ +typedef struct png_text_struct +{ + int compression; /* compression value: + -1: tEXt, none + 0: zTXt, deflate + 1: iTXt, none + 2: iTXt, deflate */ + png_charp key; /* keyword, 1-79 character description of "text" */ + png_charp text; /* comment, may be an empty string (ie "") + or a NULL pointer */ + png_size_t text_length; /* length of the text string */ + png_size_t itxt_length; /* length of the itxt string */ + png_charp lang; /* language code, 0-79 characters + or a NULL pointer */ + png_charp lang_key; /* keyword translated UTF-8 string, 0 or more + chars or a NULL pointer */ +} png_text; +typedef png_text * png_textp; +typedef const png_text * png_const_textp; +typedef png_text * * png_textpp; +#endif + +/* Supported compression types for text in PNG files (tEXt, and zTXt). + * The values of the PNG_TEXT_COMPRESSION_ defines should NOT be changed. */ +#define PNG_TEXT_COMPRESSION_NONE_WR -3 +#define PNG_TEXT_COMPRESSION_zTXt_WR -2 +#define PNG_TEXT_COMPRESSION_NONE -1 +#define PNG_TEXT_COMPRESSION_zTXt 0 +#define PNG_ITXT_COMPRESSION_NONE 1 +#define PNG_ITXT_COMPRESSION_zTXt 2 +#define PNG_TEXT_COMPRESSION_LAST 3 /* Not a valid value */ + +/* png_time is a way to hold the time in an machine independent way. + * Two conversions are provided, both from time_t and struct tm. There + * is no portable way to convert to either of these structures, as far + * as I know. If you know of a portable way, send it to me. As a side + * note - PNG has always been Year 2000 compliant! + */ +typedef struct png_time_struct +{ + png_uint_16 year; /* full year, as in, 1995 */ + png_byte month; /* month of year, 1 - 12 */ + png_byte day; /* day of month, 1 - 31 */ + png_byte hour; /* hour of day, 0 - 23 */ + png_byte minute; /* minute of hour, 0 - 59 */ + png_byte second; /* second of minute, 0 - 60 (for leap seconds) */ +} png_time; +typedef png_time * png_timep; +typedef const png_time * png_const_timep; +typedef png_time * * png_timepp; + +#if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) ||\ + defined(PNG_USER_CHUNKS_SUPPORTED) +/* png_unknown_chunk is a structure to hold queued chunks for which there is + * no specific support. The idea is that we can use this to queue + * up private chunks for output even though the library doesn't actually + * know about their semantics. + * + * The data in the structure is set by libpng on read and used on write. + */ +typedef struct png_unknown_chunk_t +{ + png_byte name[5]; /* Textual chunk name with '\0' terminator */ + png_byte *data; /* Data, should not be modified on read! */ + png_size_t size; + + /* On write 'location' must be set using the flag values listed below. + * Notice that on read it is set by libpng however the values stored have + * more bits set than are listed below. Always treat the value as a + * bitmask. On write set only one bit - setting multiple bits may cause the + * chunk to be written in multiple places. + */ + png_byte location; /* mode of operation at read time */ +} +png_unknown_chunk; + +typedef png_unknown_chunk * png_unknown_chunkp; +typedef const png_unknown_chunk * png_const_unknown_chunkp; +typedef png_unknown_chunk * * png_unknown_chunkpp; +#endif + +/* Flag values for the unknown chunk location byte. */ +#define PNG_HAVE_IHDR 0x01 +#define PNG_HAVE_PLTE 0x02 +#define PNG_AFTER_IDAT 0x08 + +/* Maximum positive integer used in PNG is (2^31)-1 */ +#define PNG_UINT_31_MAX ((png_uint_32)0x7fffffffL) +#define PNG_UINT_32_MAX ((png_uint_32)(-1)) +#define PNG_SIZE_MAX ((png_size_t)(-1)) + +/* These are constants for fixed point values encoded in the + * PNG specification manner (x100000) + */ +#define PNG_FP_1 100000 +#define PNG_FP_HALF 50000 +#define PNG_FP_MAX ((png_fixed_point)0x7fffffffL) +#define PNG_FP_MIN (-PNG_FP_MAX) + +/* These describe the color_type field in png_info. */ +/* color type masks */ +#define PNG_COLOR_MASK_PALETTE 1 +#define PNG_COLOR_MASK_COLOR 2 +#define PNG_COLOR_MASK_ALPHA 4 + +/* color types. Note that not all combinations are legal */ +#define PNG_COLOR_TYPE_GRAY 0 +#define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE) +#define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR) +#define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA) +#define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA) +/* aliases */ +#define PNG_COLOR_TYPE_RGBA PNG_COLOR_TYPE_RGB_ALPHA +#define PNG_COLOR_TYPE_GA PNG_COLOR_TYPE_GRAY_ALPHA + +/* This is for compression type. PNG 1.0-1.2 only define the single type. */ +#define PNG_COMPRESSION_TYPE_BASE 0 /* Deflate method 8, 32K window */ +#define PNG_COMPRESSION_TYPE_DEFAULT PNG_COMPRESSION_TYPE_BASE + +/* This is for filter type. PNG 1.0-1.2 only define the single type. */ +#define PNG_FILTER_TYPE_BASE 0 /* Single row per-byte filtering */ +#define PNG_INTRAPIXEL_DIFFERENCING 64 /* Used only in MNG datastreams */ +#define PNG_FILTER_TYPE_DEFAULT PNG_FILTER_TYPE_BASE + +/* These are for the interlacing type. These values should NOT be changed. */ +#define PNG_INTERLACE_NONE 0 /* Non-interlaced image */ +#define PNG_INTERLACE_ADAM7 1 /* Adam7 interlacing */ +#define PNG_INTERLACE_LAST 2 /* Not a valid value */ + +/* These are for the oFFs chunk. These values should NOT be changed. */ +#define PNG_OFFSET_PIXEL 0 /* Offset in pixels */ +#define PNG_OFFSET_MICROMETER 1 /* Offset in micrometers (1/10^6 meter) */ +#define PNG_OFFSET_LAST 2 /* Not a valid value */ + +/* These are for the pCAL chunk. These values should NOT be changed. */ +#define PNG_EQUATION_LINEAR 0 /* Linear transformation */ +#define PNG_EQUATION_BASE_E 1 /* Exponential base e transform */ +#define PNG_EQUATION_ARBITRARY 2 /* Arbitrary base exponential transform */ +#define PNG_EQUATION_HYPERBOLIC 3 /* Hyperbolic sine transformation */ +#define PNG_EQUATION_LAST 4 /* Not a valid value */ + +/* These are for the sCAL chunk. These values should NOT be changed. */ +#define PNG_SCALE_UNKNOWN 0 /* unknown unit (image scale) */ +#define PNG_SCALE_METER 1 /* meters per pixel */ +#define PNG_SCALE_RADIAN 2 /* radians per pixel */ +#define PNG_SCALE_LAST 3 /* Not a valid value */ + +/* These are for the pHYs chunk. These values should NOT be changed. */ +#define PNG_RESOLUTION_UNKNOWN 0 /* pixels/unknown unit (aspect ratio) */ +#define PNG_RESOLUTION_METER 1 /* pixels/meter */ +#define PNG_RESOLUTION_LAST 2 /* Not a valid value */ + +/* These are for the sRGB chunk. These values should NOT be changed. */ +#define PNG_sRGB_INTENT_PERCEPTUAL 0 +#define PNG_sRGB_INTENT_RELATIVE 1 +#define PNG_sRGB_INTENT_SATURATION 2 +#define PNG_sRGB_INTENT_ABSOLUTE 3 +#define PNG_sRGB_INTENT_LAST 4 /* Not a valid value */ + +/* This is for text chunks */ +#define PNG_KEYWORD_MAX_LENGTH 79 + +/* Maximum number of entries in PLTE/sPLT/tRNS arrays */ +#define PNG_MAX_PALETTE_LENGTH 256 + +/* These determine if an ancillary chunk's data has been successfully read + * from the PNG header, or if the application has filled in the corresponding + * data in the info_struct to be written into the output file. The values + * of the PNG_INFO_ defines should NOT be changed. + */ +#define PNG_INFO_gAMA 0x0001U +#define PNG_INFO_sBIT 0x0002U +#define PNG_INFO_cHRM 0x0004U +#define PNG_INFO_PLTE 0x0008U +#define PNG_INFO_tRNS 0x0010U +#define PNG_INFO_bKGD 0x0020U +#define PNG_INFO_hIST 0x0040U +#define PNG_INFO_pHYs 0x0080U +#define PNG_INFO_oFFs 0x0100U +#define PNG_INFO_tIME 0x0200U +#define PNG_INFO_pCAL 0x0400U +#define PNG_INFO_sRGB 0x0800U /* GR-P, 0.96a */ +#define PNG_INFO_iCCP 0x1000U /* ESR, 1.0.6 */ +#define PNG_INFO_sPLT 0x2000U /* ESR, 1.0.6 */ +#define PNG_INFO_sCAL 0x4000U /* ESR, 1.0.6 */ +#define PNG_INFO_IDAT 0x8000U /* ESR, 1.0.6 */ + +/* This is used for the transformation routines, as some of them + * change these values for the row. It also should enable using + * the routines for other purposes. + */ +typedef struct png_row_info_struct +{ + png_uint_32 width; /* width of row */ + png_size_t rowbytes; /* number of bytes in row */ + png_byte color_type; /* color type of row */ + png_byte bit_depth; /* bit depth of row */ + png_byte channels; /* number of channels (1, 2, 3, or 4) */ + png_byte pixel_depth; /* bits per pixel (depth * channels) */ +} png_row_info; + +typedef png_row_info * png_row_infop; +typedef png_row_info * * png_row_infopp; + +/* These are the function types for the I/O functions and for the functions + * that allow the user to override the default I/O functions with his or her + * own. The png_error_ptr type should match that of user-supplied warning + * and error functions, while the png_rw_ptr type should match that of the + * user read/write data functions. Note that the 'write' function must not + * modify the buffer it is passed. The 'read' function, on the other hand, is + * expected to return the read data in the buffer. + */ +typedef PNG_CALLBACK(void, *png_error_ptr, (png_structp, png_const_charp)); +typedef PNG_CALLBACK(void, *png_rw_ptr, (png_structp, png_bytep, png_size_t)); +typedef PNG_CALLBACK(void, *png_flush_ptr, (png_structp)); +typedef PNG_CALLBACK(void, *png_read_status_ptr, (png_structp, png_uint_32, + int)); +typedef PNG_CALLBACK(void, *png_write_status_ptr, (png_structp, png_uint_32, + int)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop)); +typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop)); + +/* The following callback receives png_uint_32 row_number, int pass for the + * png_bytep data of the row. When transforming an interlaced image the + * row number is the row number within the sub-image of the interlace pass, so + * the value will increase to the height of the sub-image (not the full image) + * then reset to 0 for the next pass. + * + * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to + * find the output pixel (x,y) given an interlaced sub-image pixel + * (row,col,pass). (See below for these macros.) + */ +typedef PNG_CALLBACK(void, *png_progressive_row_ptr, (png_structp, png_bytep, + png_uint_32, int)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +typedef PNG_CALLBACK(void, *png_user_transform_ptr, (png_structp, png_row_infop, + png_bytep)); +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +typedef PNG_CALLBACK(int, *png_user_chunk_ptr, (png_structp, + png_unknown_chunkp)); +#endif +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED +/* not used anywhere */ +/* typedef PNG_CALLBACK(void, *png_unknown_chunk_ptr, (png_structp)); */ +#endif + +#ifdef PNG_SETJMP_SUPPORTED +/* This must match the function definition in , and the application + * must include this before png.h to obtain the definition of jmp_buf. The + * function is required to be PNG_NORETURN, but this is not checked. If the + * function does return the application will crash via an abort() or similar + * system level call. + * + * If you get a warning here while building the library you may need to make + * changes to ensure that pnglibconf.h records the calling convention used by + * your compiler. This may be very difficult - try using a different compiler + * to build the library! + */ +PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)), typedef); +#endif + +/* Transform masks for the high-level interface */ +#define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */ +#define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */ +#define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */ +#define PNG_TRANSFORM_PACKING 0x0004 /* read and write */ +#define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */ +#define PNG_TRANSFORM_EXPAND 0x0010 /* read only */ +#define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */ +#define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */ +#define PNG_TRANSFORM_BGR 0x0080 /* read and write */ +#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */ +#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */ +#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */ +#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* write only */ +/* Added to libpng-1.2.34 */ +#define PNG_TRANSFORM_STRIP_FILLER_BEFORE PNG_TRANSFORM_STRIP_FILLER +#define PNG_TRANSFORM_STRIP_FILLER_AFTER 0x1000 /* write only */ +/* Added to libpng-1.4.0 */ +#define PNG_TRANSFORM_GRAY_TO_RGB 0x2000 /* read only */ +/* Added to libpng-1.5.4 */ +#define PNG_TRANSFORM_EXPAND_16 0x4000 /* read only */ +#if INT_MAX >= 0x8000 /* else this might break */ +#define PNG_TRANSFORM_SCALE_16 0x8000 /* read only */ +#endif + +/* Flags for MNG supported features */ +#define PNG_FLAG_MNG_EMPTY_PLTE 0x01 +#define PNG_FLAG_MNG_FILTER_64 0x04 +#define PNG_ALL_MNG_FEATURES 0x05 + +/* NOTE: prior to 1.5 these functions had no 'API' style declaration, + * this allowed the zlib default functions to be used on Windows + * platforms. In 1.5 the zlib default malloc (which just calls malloc and + * ignores the first argument) should be completely compatible with the + * following. + */ +typedef PNG_CALLBACK(png_voidp, *png_malloc_ptr, (png_structp, + png_alloc_size_t)); +typedef PNG_CALLBACK(void, *png_free_ptr, (png_structp, png_voidp)); + +/* Section 4: exported functions + * Here are the function definitions most commonly used. This is not + * the place to find out how to use libpng. See libpng-manual.txt for the + * full explanation, see example.c for the summary. This just provides + * a simple one line description of the use of each function. + * + * The PNG_EXPORT() and PNG_EXPORTA() macros used below are defined in + * pngconf.h and in the *.dfn files in the scripts directory. + * + * PNG_EXPORT(ordinal, type, name, (args)); + * + * ordinal: ordinal that is used while building + * *.def files. The ordinal value is only + * relevant when preprocessing png.h with + * the *.dfn files for building symbol table + * entries, and are removed by pngconf.h. + * type: return type of the function + * name: function name + * args: function arguments, with types + * + * When we wish to append attributes to a function prototype we use + * the PNG_EXPORTA() macro instead. + * + * PNG_EXPORTA(ordinal, type, name, (args), attributes); + * + * ordinal, type, name, and args: same as in PNG_EXPORT(). + * attributes: function attributes + */ + +/* Returns the version number of the library */ +PNG_EXPORT(1, png_uint_32, png_access_version_number, (void)); + +/* Tell lib we have already handled the first magic bytes. + * Handling more than 8 bytes from the beginning of the file is an error. + */ +PNG_EXPORT(2, void, png_set_sig_bytes, (png_structrp png_ptr, int num_bytes)); + +/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a + * PNG file. Returns zero if the supplied bytes match the 8-byte PNG + * signature, and non-zero otherwise. Having num_to_check == 0 or + * start > 7 will always fail (ie return non-zero). + */ +PNG_EXPORT(3, int, png_sig_cmp, (png_const_bytep sig, png_size_t start, + png_size_t num_to_check)); + +/* Simple signature checking function. This is the same as calling + * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n). + */ +#define png_check_sig(sig, n) !png_sig_cmp((sig), 0, (n)) + +/* Allocate and initialize png_ptr struct for reading, and any other memory. */ +PNG_EXPORTA(4, png_structp, png_create_read_struct, + (png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn), + PNG_ALLOCATED); + +/* Allocate and initialize png_ptr struct for writing, and any other memory */ +PNG_EXPORTA(5, png_structp, png_create_write_struct, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn), + PNG_ALLOCATED); + +PNG_EXPORT(6, png_size_t, png_get_compression_buffer_size, + (png_const_structrp png_ptr)); + +PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structrp png_ptr, + png_size_t size)); + +/* Moved from pngconf.h in 1.4.0 and modified to ensure setjmp/longjmp + * match up. + */ +#ifdef PNG_SETJMP_SUPPORTED +/* This function returns the jmp_buf built in to *png_ptr. It must be + * supplied with an appropriate 'longjmp' function to use on that jmp_buf + * unless the default error function is overridden in which case NULL is + * acceptable. The size of the jmp_buf is checked against the actual size + * allocated by the library - the call will return NULL on a mismatch + * indicating an ABI mismatch. + */ +PNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn, (png_structrp png_ptr, + png_longjmp_ptr longjmp_fn, size_t jmp_buf_size)); +# define png_jmpbuf(png_ptr) \ + (*png_set_longjmp_fn((png_ptr), longjmp, (sizeof (jmp_buf)))) +#else +# define png_jmpbuf(png_ptr) \ + (LIBPNG_WAS_COMPILED_WITH__PNG_NO_SETJMP) +#endif +/* This function should be used by libpng applications in place of + * longjmp(png_ptr->jmpbuf, val). If longjmp_fn() has been set, it + * will use it; otherwise it will call PNG_ABORT(). This function was + * added in libpng-1.5.0. + */ +PNG_EXPORTA(9, void, png_longjmp, (png_const_structrp png_ptr, int val), + PNG_NORETURN); + +#ifdef PNG_READ_SUPPORTED +/* Reset the compression stream */ +PNG_EXPORTA(10, int, png_reset_zstream, (png_structrp png_ptr), PNG_DEPRECATED); +#endif + +/* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */ +#ifdef PNG_USER_MEM_SUPPORTED +PNG_EXPORTA(11, png_structp, png_create_read_struct_2, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn, + png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn), + PNG_ALLOCATED); +PNG_EXPORTA(12, png_structp, png_create_write_struct_2, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn, + png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn), + PNG_ALLOCATED); +#endif + +/* Write the PNG file signature. */ +PNG_EXPORT(13, void, png_write_sig, (png_structrp png_ptr)); + +/* Write a PNG chunk - size, type, (optional) data, CRC. */ +PNG_EXPORT(14, void, png_write_chunk, (png_structrp png_ptr, png_const_bytep + chunk_name, png_const_bytep data, png_size_t length)); + +/* Write the start of a PNG chunk - length and chunk name. */ +PNG_EXPORT(15, void, png_write_chunk_start, (png_structrp png_ptr, + png_const_bytep chunk_name, png_uint_32 length)); + +/* Write the data of a PNG chunk started with png_write_chunk_start(). */ +PNG_EXPORT(16, void, png_write_chunk_data, (png_structrp png_ptr, + png_const_bytep data, png_size_t length)); + +/* Finish a chunk started with png_write_chunk_start() (includes CRC). */ +PNG_EXPORT(17, void, png_write_chunk_end, (png_structrp png_ptr)); + +/* Allocate and initialize the info structure */ +PNG_EXPORTA(18, png_infop, png_create_info_struct, (png_const_structrp png_ptr), + PNG_ALLOCATED); + +/* DEPRECATED: this function allowed init structures to be created using the + * default allocation method (typically malloc). Use is deprecated in 1.6.0 and + * the API will be removed in the future. + */ +PNG_EXPORTA(19, void, png_info_init_3, (png_infopp info_ptr, + png_size_t png_info_struct_size), PNG_DEPRECATED); + +/* Writes all the PNG information before the image. */ +PNG_EXPORT(20, void, png_write_info_before_PLTE, + (png_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(21, void, png_write_info, + (png_structrp png_ptr, png_const_inforp info_ptr)); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the information before the actual image data. */ +PNG_EXPORT(22, void, png_read_info, + (png_structrp png_ptr, png_inforp info_ptr)); +#endif + +#ifdef PNG_TIME_RFC1123_SUPPORTED + /* Convert to a US string format: there is no localization support in this + * routine. The original implementation used a 29 character buffer in + * png_struct, this will be removed in future versions. + */ +#if PNG_LIBPNG_VER < 10700 +/* To do: remove this from libpng17 (and from libpng17/png.c and pngstruct.h) */ +PNG_EXPORTA(23, png_const_charp, png_convert_to_rfc1123, (png_structrp png_ptr, + png_const_timep ptime),PNG_DEPRECATED); +#endif +PNG_EXPORT(241, int, png_convert_to_rfc1123_buffer, (char out[29], + png_const_timep ptime)); +#endif + +#ifdef PNG_CONVERT_tIME_SUPPORTED +/* Convert from a struct tm to png_time */ +PNG_EXPORT(24, void, png_convert_from_struct_tm, (png_timep ptime, + const struct tm * ttime)); + +/* Convert from time_t to png_time. Uses gmtime() */ +PNG_EXPORT(25, void, png_convert_from_time_t, (png_timep ptime, time_t ttime)); +#endif /* CONVERT_tIME */ + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */ +PNG_EXPORT(26, void, png_set_expand, (png_structrp png_ptr)); +PNG_EXPORT(27, void, png_set_expand_gray_1_2_4_to_8, (png_structrp png_ptr)); +PNG_EXPORT(28, void, png_set_palette_to_rgb, (png_structrp png_ptr)); +PNG_EXPORT(29, void, png_set_tRNS_to_alpha, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_EXPAND_16_SUPPORTED +/* Expand to 16-bit channels, forces conversion of palette to RGB and expansion + * of a tRNS chunk if present. + */ +PNG_EXPORT(221, void, png_set_expand_16, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Use blue, green, red order for pixels. */ +PNG_EXPORT(30, void, png_set_bgr, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +/* Expand the grayscale to 24-bit RGB if necessary. */ +PNG_EXPORT(31, void, png_set_gray_to_rgb, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +/* Reduce RGB to grayscale. */ +#define PNG_ERROR_ACTION_NONE 1 +#define PNG_ERROR_ACTION_WARN 2 +#define PNG_ERROR_ACTION_ERROR 3 +#define PNG_RGB_TO_GRAY_DEFAULT (-1)/*for red/green coefficients*/ + +PNG_FP_EXPORT(32, void, png_set_rgb_to_gray, (png_structrp png_ptr, + int error_action, double red, double green)) +PNG_FIXED_EXPORT(33, void, png_set_rgb_to_gray_fixed, (png_structrp png_ptr, + int error_action, png_fixed_point red, png_fixed_point green)) + +PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, (png_const_structrp + png_ptr)); +#endif + +#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED +PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth, + png_colorp palette)); +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +/* How the alpha channel is interpreted - this affects how the color channels + * of a PNG file are returned to the calling application when an alpha channel, + * or a tRNS chunk in a palette file, is present. + * + * This has no effect on the way pixels are written into a PNG output + * datastream. The color samples in a PNG datastream are never premultiplied + * with the alpha samples. + * + * The default is to return data according to the PNG specification: the alpha + * channel is a linear measure of the contribution of the pixel to the + * corresponding composited pixel, and the color channels are unassociated + * (not premultiplied). The gamma encoded color channels must be scaled + * according to the contribution and to do this it is necessary to undo + * the encoding, scale the color values, perform the composition and reencode + * the values. This is the 'PNG' mode. + * + * The alternative is to 'associate' the alpha with the color information by + * storing color channel values that have been scaled by the alpha. + * image. These are the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' modes + * (the latter being the two common names for associated alpha color channels). + * + * For the 'OPTIMIZED' mode, a pixel is treated as opaque only if the alpha + * value is equal to the maximum value. + * + * The final choice is to gamma encode the alpha channel as well. This is + * broken because, in practice, no implementation that uses this choice + * correctly undoes the encoding before handling alpha composition. Use this + * choice only if other serious errors in the software or hardware you use + * mandate it; the typical serious error is for dark halos to appear around + * opaque areas of the composited PNG image because of arithmetic overflow. + * + * The API function png_set_alpha_mode specifies which of these choices to use + * with an enumerated 'mode' value and the gamma of the required output: + */ +#define PNG_ALPHA_PNG 0 /* according to the PNG standard */ +#define PNG_ALPHA_STANDARD 1 /* according to Porter/Duff */ +#define PNG_ALPHA_ASSOCIATED 1 /* as above; this is the normal practice */ +#define PNG_ALPHA_PREMULTIPLIED 1 /* as above */ +#define PNG_ALPHA_OPTIMIZED 2 /* 'PNG' for opaque pixels, else 'STANDARD' */ +#define PNG_ALPHA_BROKEN 3 /* the alpha channel is gamma encoded */ + +PNG_FP_EXPORT(227, void, png_set_alpha_mode, (png_structrp png_ptr, int mode, + double output_gamma)) +PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structrp png_ptr, + int mode, png_fixed_point output_gamma)) +#endif + +#if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_READ_ALPHA_MODE_SUPPORTED) +/* The output_gamma value is a screen gamma in libpng terminology: it expresses + * how to decode the output values, not how they are encoded. + */ +#define PNG_DEFAULT_sRGB -1 /* sRGB gamma and color space */ +#define PNG_GAMMA_MAC_18 -2 /* Old Mac '1.8' gamma and color space */ +#define PNG_GAMMA_sRGB 220000 /* Television standards--matches sRGB gamma */ +#define PNG_GAMMA_LINEAR PNG_FP_1 /* Linear */ +#endif + +/* The following are examples of calls to png_set_alpha_mode to achieve the + * required overall gamma correction and, where necessary, alpha + * premultiplication. + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + * This is the default libpng handling of the alpha channel - it is not + * pre-multiplied into the color components. In addition the call states + * that the output is for a sRGB system and causes all PNG files without gAMA + * chunks to be assumed to be encoded using sRGB. + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + * In this case the output is assumed to be something like an sRGB conformant + * display preceeded by a power-law lookup table of power 1.45. This is how + * early Mac systems behaved. + * + * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR); + * This is the classic Jim Blinn approach and will work in academic + * environments where everything is done by the book. It has the shortcoming + * of assuming that input PNG data with no gamma information is linear - this + * is unlikely to be correct unless the PNG files where generated locally. + * Most of the time the output precision will be so low as to show + * significant banding in dark areas of the image. + * + * png_set_expand_16(pp); + * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_DEFAULT_sRGB); + * This is a somewhat more realistic Jim Blinn inspired approach. PNG files + * are assumed to have the sRGB encoding if not marked with a gamma value and + * the output is always 16 bits per component. This permits accurate scaling + * and processing of the data. If you know that your input PNG files were + * generated locally you might need to replace PNG_DEFAULT_sRGB with the + * correct value for your system. + * + * png_set_alpha_mode(pp, PNG_ALPHA_OPTIMIZED, PNG_DEFAULT_sRGB); + * If you just need to composite the PNG image onto an existing background + * and if you control the code that does this you can use the optimization + * setting. In this case you just copy completely opaque pixels to the + * output. For pixels that are not completely transparent (you just skip + * those) you do the composition math using png_composite or png_composite_16 + * below then encode the resultant 8-bit or 16-bit values to match the output + * encoding. + * + * Other cases + * If neither the PNG nor the standard linear encoding work for you because + * of the software or hardware you use then you have a big problem. The PNG + * case will probably result in halos around the image. The linear encoding + * will probably result in a washed out, too bright, image (it's actually too + * contrasty.) Try the ALPHA_OPTIMIZED mode above - this will probably + * substantially reduce the halos. Alternatively try: + * + * png_set_alpha_mode(pp, PNG_ALPHA_BROKEN, PNG_DEFAULT_sRGB); + * This option will also reduce the halos, but there will be slight dark + * halos round the opaque parts of the image where the background is light. + * In the OPTIMIZED mode the halos will be light halos where the background + * is dark. Take your pick - the halos are unavoidable unless you can get + * your hardware/software fixed! (The OPTIMIZED approach is slightly + * faster.) + * + * When the default gamma of PNG files doesn't match the output gamma. + * If you have PNG files with no gamma information png_set_alpha_mode allows + * you to provide a default gamma, but it also sets the ouput gamma to the + * matching value. If you know your PNG files have a gamma that doesn't + * match the output you can take advantage of the fact that + * png_set_alpha_mode always sets the output gamma but only sets the PNG + * default if it is not already set: + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + * The first call sets both the default and the output gamma values, the + * second call overrides the output gamma without changing the default. This + * is easier than achieving the same effect with png_set_gamma. You must use + * PNG_ALPHA_PNG for the first call - internal checking in png_set_alpha will + * fire if more than one call to png_set_alpha_mode and png_set_background is + * made in the same read operation, however multiple calls with PNG_ALPHA_PNG + * are ignored. + */ + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED +PNG_EXPORT(36, void, png_set_strip_alpha, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +PNG_EXPORT(37, void, png_set_swap_alpha, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +PNG_EXPORT(38, void, png_set_invert_alpha, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +/* Add a filler byte to 8-bit or 16-bit Gray or 24-bit or 48-bit RGB images. */ +PNG_EXPORT(39, void, png_set_filler, (png_structrp png_ptr, png_uint_32 filler, + int flags)); +/* The values of the PNG_FILLER_ defines should NOT be changed */ +# define PNG_FILLER_BEFORE 0 +# define PNG_FILLER_AFTER 1 +/* Add an alpha byte to 8-bit or 16-bit Gray or 24-bit or 48-bit RGB images. */ +PNG_EXPORT(40, void, png_set_add_alpha, (png_structrp png_ptr, + png_uint_32 filler, int flags)); +#endif /* READ_FILLER || WRITE_FILLER */ + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Swap bytes in 16-bit depth files. */ +PNG_EXPORT(41, void, png_set_swap, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) +/* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ +PNG_EXPORT(42, void, png_set_packing, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ + defined(PNG_WRITE_PACKSWAP_SUPPORTED) +/* Swap packing order of pixels in bytes. */ +PNG_EXPORT(43, void, png_set_packswap, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) +/* Converts files to legal bit depths. */ +PNG_EXPORT(44, void, png_set_shift, (png_structrp png_ptr, png_const_color_8p + true_bits)); +#endif + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) +/* Have the code handle the interlacing. Returns the number of passes. + * MUST be called before png_read_update_info or png_start_read_image, + * otherwise it will not have the desired effect. Note that it is still + * necessary to call png_read_row or png_read_rows png_get_image_height + * times for each pass. +*/ +PNG_EXPORT(45, int, png_set_interlace_handling, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +/* Invert monochrome files */ +PNG_EXPORT(46, void, png_set_invert_mono, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_BACKGROUND_SUPPORTED +/* Handle alpha and tRNS by replacing with a background color. Prior to + * libpng-1.5.4 this API must not be called before the PNG file header has been + * read. Doing so will result in unexpected behavior and possible warnings or + * errors if the PNG file contains a bKGD chunk. + */ +PNG_FP_EXPORT(47, void, png_set_background, (png_structrp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma)) +PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structrp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, png_fixed_point background_gamma)) +#endif +#ifdef PNG_READ_BACKGROUND_SUPPORTED +# define PNG_BACKGROUND_GAMMA_UNKNOWN 0 +# define PNG_BACKGROUND_GAMMA_SCREEN 1 +# define PNG_BACKGROUND_GAMMA_FILE 2 +# define PNG_BACKGROUND_GAMMA_UNIQUE 3 +#endif + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +/* Scale a 16-bit depth file down to 8-bit, accurately. */ +PNG_EXPORT(229, void, png_set_scale_16, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +#define PNG_READ_16_TO_8_SUPPORTED /* Name prior to 1.5.4 */ +/* Strip the second byte of information from a 16-bit depth file. */ +PNG_EXPORT(48, void, png_set_strip_16, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +/* Turn on quantizing, and reduce the palette to the number of colors + * available. + */ +PNG_EXPORT(49, void, png_set_quantize, (png_structrp png_ptr, + png_colorp palette, int num_palette, int maximum_colors, + png_const_uint_16p histogram, int full_quantize)); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* The threshold on gamma processing is configurable but hard-wired into the + * library. The following is the floating point variant. + */ +#define PNG_GAMMA_THRESHOLD (PNG_GAMMA_THRESHOLD_FIXED*.00001) + +/* Handle gamma correction. Screen_gamma=(display_exponent). + * NOTE: this API simply sets the screen and file gamma values. It will + * therefore override the value for gamma in a PNG file if it is called after + * the file header has been read - use with care - call before reading the PNG + * file for best results! + * + * These routines accept the same gamma values as png_set_alpha_mode (described + * above). The PNG_GAMMA_ defines and PNG_DEFAULT_sRGB can be passed to either + * API (floating point or fixed.) Notice, however, that the 'file_gamma' value + * is the inverse of a 'screen gamma' value. + */ +PNG_FP_EXPORT(50, void, png_set_gamma, (png_structrp png_ptr, + double screen_gamma, double override_file_gamma)) +PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structrp png_ptr, + png_fixed_point screen_gamma, png_fixed_point override_file_gamma)) +#endif + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +/* Set how many lines between output flushes - 0 for no flushing */ +PNG_EXPORT(51, void, png_set_flush, (png_structrp png_ptr, int nrows)); +/* Flush the current PNG output buffer */ +PNG_EXPORT(52, void, png_write_flush, (png_structrp png_ptr)); +#endif + +/* Optional update palette with requested transformations */ +PNG_EXPORT(53, void, png_start_read_image, (png_structrp png_ptr)); + +/* Optional call to update the users info structure */ +PNG_EXPORT(54, void, png_read_update_info, (png_structrp png_ptr, + png_inforp info_ptr)); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read one or more rows of image data. */ +PNG_EXPORT(55, void, png_read_rows, (png_structrp png_ptr, png_bytepp row, + png_bytepp display_row, png_uint_32 num_rows)); +#endif + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read a row of data. */ +PNG_EXPORT(56, void, png_read_row, (png_structrp png_ptr, png_bytep row, + png_bytep display_row)); +#endif + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the whole image into memory at once. */ +PNG_EXPORT(57, void, png_read_image, (png_structrp png_ptr, png_bytepp image)); +#endif + +/* Write a row of image data */ +PNG_EXPORT(58, void, png_write_row, (png_structrp png_ptr, + png_const_bytep row)); + +/* Write a few rows of image data: (*row) is not written; however, the type + * is declared as writeable to maintain compatibility with previous versions + * of libpng and to allow the 'display_row' array from read_rows to be passed + * unchanged to write_rows. + */ +PNG_EXPORT(59, void, png_write_rows, (png_structrp png_ptr, png_bytepp row, + png_uint_32 num_rows)); + +/* Write the image data */ +PNG_EXPORT(60, void, png_write_image, (png_structrp png_ptr, png_bytepp image)); + +/* Write the end of the PNG file. */ +PNG_EXPORT(61, void, png_write_end, (png_structrp png_ptr, + png_inforp info_ptr)); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the end of the PNG file. */ +PNG_EXPORT(62, void, png_read_end, (png_structrp png_ptr, png_inforp info_ptr)); +#endif + +/* Free any memory associated with the png_info_struct */ +PNG_EXPORT(63, void, png_destroy_info_struct, (png_const_structrp png_ptr, + png_infopp info_ptr_ptr)); + +/* Free any memory associated with the png_struct and the png_info_structs */ +PNG_EXPORT(64, void, png_destroy_read_struct, (png_structpp png_ptr_ptr, + png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)); + +/* Free any memory associated with the png_struct and the png_info_structs */ +PNG_EXPORT(65, void, png_destroy_write_struct, (png_structpp png_ptr_ptr, + png_infopp info_ptr_ptr)); + +/* Set the libpng method of handling chunk CRC errors */ +PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action, + int ancil_action)); + +/* Values for png_set_crc_action() say how to handle CRC errors in + * ancillary and critical chunks, and whether to use the data contained + * therein. Note that it is impossible to "discard" data in a critical + * chunk. For versions prior to 0.90, the action was always error/quit, + * whereas in version 0.90 and later, the action for CRC errors in ancillary + * chunks is warn/discard. These values should NOT be changed. + * + * value action:critical action:ancillary + */ +#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */ +#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */ +#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */ +#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */ +#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ +#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ + +#ifdef PNG_WRITE_SUPPORTED +/* These functions give the user control over the scan-line filtering in + * libpng and the compression methods used by zlib. These functions are + * mainly useful for testing, as the defaults should work with most users. + * Those users who are tight on memory or want faster performance at the + * expense of compression can modify them. See the compression library + * header file (zlib.h) for an explination of the compression functions. + */ + +/* Set the filtering method(s) used by libpng. Currently, the only valid + * value for "method" is 0. + */ +PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method, + int filters)); +#endif /* WRITE */ + +/* Flags for png_set_filter() to say which filters to use. The flags + * are chosen so that they don't conflict with real filter types + * below, in case they are supplied instead of the #defined constants. + * These values should NOT be changed. + */ +#define PNG_NO_FILTERS 0x00 +#define PNG_FILTER_NONE 0x08 +#define PNG_FILTER_SUB 0x10 +#define PNG_FILTER_UP 0x20 +#define PNG_FILTER_AVG 0x40 +#define PNG_FILTER_PAETH 0x80 +#define PNG_FAST_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP) +#define PNG_ALL_FILTERS (PNG_FAST_FILTERS | PNG_FILTER_AVG | PNG_FILTER_PAETH) + +/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now. + * These defines should NOT be changed. + */ +#define PNG_FILTER_VALUE_NONE 0 +#define PNG_FILTER_VALUE_SUB 1 +#define PNG_FILTER_VALUE_UP 2 +#define PNG_FILTER_VALUE_AVG 3 +#define PNG_FILTER_VALUE_PAETH 4 +#define PNG_FILTER_VALUE_LAST 5 + +#ifdef PNG_WRITE_SUPPORTED +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */ +PNG_FP_EXPORT(68, void, png_set_filter_heuristics, (png_structrp png_ptr, + int heuristic_method, int num_weights, png_const_doublep filter_weights, + png_const_doublep filter_costs)) +PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed, + (png_structrp png_ptr, int heuristic_method, int num_weights, + png_const_fixed_point_p filter_weights, + png_const_fixed_point_p filter_costs)) +#endif /* WRITE_WEIGHTED_FILTER */ + +/* The following are no longer used and will be removed from libpng-1.7: */ +#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */ +#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */ +#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ +#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ + +/* Set the library compression level. Currently, valid values range from + * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 + * (0 - no compression, 9 - "maximal" compression). Note that tests have + * shown that zlib compression levels 3-6 usually perform as well as level 9 + * for PNG images, and do considerably fewer caclulations. In the future, + * these values may not correspond directly to the zlib compression levels. + */ +#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED +PNG_EXPORT(69, void, png_set_compression_level, (png_structrp png_ptr, + int level)); + +PNG_EXPORT(70, void, png_set_compression_mem_level, (png_structrp png_ptr, + int mem_level)); + +PNG_EXPORT(71, void, png_set_compression_strategy, (png_structrp png_ptr, + int strategy)); + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +PNG_EXPORT(72, void, png_set_compression_window_bits, (png_structrp png_ptr, + int window_bits)); + +PNG_EXPORT(73, void, png_set_compression_method, (png_structrp png_ptr, + int method)); +#endif /* WRITE_CUSTOMIZE_COMPRESSION */ + +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +/* Also set zlib parameters for compressing non-IDAT chunks */ +PNG_EXPORT(222, void, png_set_text_compression_level, (png_structrp png_ptr, + int level)); + +PNG_EXPORT(223, void, png_set_text_compression_mem_level, (png_structrp png_ptr, + int mem_level)); + +PNG_EXPORT(224, void, png_set_text_compression_strategy, (png_structrp png_ptr, + int strategy)); + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +PNG_EXPORT(225, void, png_set_text_compression_window_bits, + (png_structrp png_ptr, int window_bits)); + +PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr, + int method)); +#endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */ +#endif /* WRITE */ + +/* These next functions are called for input/output, memory, and error + * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, + * and call standard C I/O routines such as fread(), fwrite(), and + * fprintf(). These functions can be made to use other I/O routines + * at run time for those applications that need to handle I/O in a + * different manner by calling png_set_???_fn(). See libpng-manual.txt for + * more information. + */ + +#ifdef PNG_STDIO_SUPPORTED +/* Initialize the input/output for the PNG file to the default functions. */ +PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, png_FILE_p fp)); +#endif + +/* Replace the (error and abort), and warning functions with user + * supplied functions. If no messages are to be printed you must still + * write and use replacement functions. The replacement error_fn should + * still do a longjmp to the last setjmp location if you are using this + * method of error handling. If error_fn or warning_fn is NULL, the + * default function will be used. + */ + +PNG_EXPORT(75, void, png_set_error_fn, (png_structrp png_ptr, + png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn)); + +/* Return the user pointer associated with the error functions */ +PNG_EXPORT(76, png_voidp, png_get_error_ptr, (png_const_structrp png_ptr)); + +/* Replace the default data output functions with a user supplied one(s). + * If buffered output is not used, then output_flush_fn can be set to NULL. + * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time + * output_flush_fn will be ignored (and thus can be NULL). + * It is probably a mistake to use NULL for output_flush_fn if + * write_data_fn is not also NULL unless you have built libpng with + * PNG_WRITE_FLUSH_SUPPORTED undefined, because in this case libpng's + * default flush function, which uses the standard *FILE structure, will + * be used. + */ +PNG_EXPORT(77, void, png_set_write_fn, (png_structrp png_ptr, png_voidp io_ptr, + png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)); + +/* Replace the default data input function with a user supplied one. */ +PNG_EXPORT(78, void, png_set_read_fn, (png_structrp png_ptr, png_voidp io_ptr, + png_rw_ptr read_data_fn)); + +/* Return the user pointer associated with the I/O functions */ +PNG_EXPORT(79, png_voidp, png_get_io_ptr, (png_const_structrp png_ptr)); + +PNG_EXPORT(80, void, png_set_read_status_fn, (png_structrp png_ptr, + png_read_status_ptr read_row_fn)); + +PNG_EXPORT(81, void, png_set_write_status_fn, (png_structrp png_ptr, + png_write_status_ptr write_row_fn)); + +#ifdef PNG_USER_MEM_SUPPORTED +/* Replace the default memory allocation functions with user supplied one(s). */ +PNG_EXPORT(82, void, png_set_mem_fn, (png_structrp png_ptr, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +/* Return the user pointer associated with the memory functions */ +PNG_EXPORT(83, png_voidp, png_get_mem_ptr, (png_const_structrp png_ptr)); +#endif + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED +PNG_EXPORT(84, void, png_set_read_user_transform_fn, (png_structrp png_ptr, + png_user_transform_ptr read_user_transform_fn)); +#endif + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED +PNG_EXPORT(85, void, png_set_write_user_transform_fn, (png_structrp png_ptr, + png_user_transform_ptr write_user_transform_fn)); +#endif + +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED +PNG_EXPORT(86, void, png_set_user_transform_info, (png_structrp png_ptr, + png_voidp user_transform_ptr, int user_transform_depth, + int user_transform_channels)); +/* Return the user pointer associated with the user transform functions */ +PNG_EXPORT(87, png_voidp, png_get_user_transform_ptr, + (png_const_structrp png_ptr)); +#endif + +#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED +/* Return information about the row currently being processed. Note that these + * APIs do not fail but will return unexpected results if called outside a user + * transform callback. Also note that when transforming an interlaced image the + * row number is the row number within the sub-image of the interlace pass, so + * the value will increase to the height of the sub-image (not the full image) + * then reset to 0 for the next pass. + * + * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to + * find the output pixel (x,y) given an interlaced sub-image pixel + * (row,col,pass). (See below for these macros.) + */ +PNG_EXPORT(217, png_uint_32, png_get_current_row_number, (png_const_structrp)); +PNG_EXPORT(218, png_byte, png_get_current_pass_number, (png_const_structrp)); +#endif + +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED +/* This callback is called only for *unknown* chunks. If + * PNG_HANDLE_AS_UNKNOWN_SUPPORTED is set then it is possible to set known + * chunks to be treated as unknown, however in this case the callback must do + * any processing required by the chunk (e.g. by calling the appropriate + * png_set_ APIs.) + * + * There is no write support - on write, by default, all the chunks in the + * 'unknown' list are written in the specified position. + * + * The integer return from the callback function is interpreted thus: + * + * negative: An error occurred; png_chunk_error will be called. + * zero: The chunk was not handled, the chunk will be saved. A critical + * chunk will cause an error at this point unless it is to be saved. + * positive: The chunk was handled, libpng will ignore/discard it. + * + * See "INTERACTION WTIH USER CHUNK CALLBACKS" below for important notes about + * how this behavior will change in libpng 1.7 + */ +PNG_EXPORT(88, void, png_set_read_user_chunk_fn, (png_structrp png_ptr, + png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn)); +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +PNG_EXPORT(89, png_voidp, png_get_user_chunk_ptr, (png_const_structrp png_ptr)); +#endif + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +/* Sets the function callbacks for the push reader, and a pointer to a + * user-defined structure available to the callback functions. + */ +PNG_EXPORT(90, void, png_set_progressive_read_fn, (png_structrp png_ptr, + png_voidp progressive_ptr, png_progressive_info_ptr info_fn, + png_progressive_row_ptr row_fn, png_progressive_end_ptr end_fn)); + +/* Returns the user pointer associated with the push read functions */ +PNG_EXPORT(91, png_voidp, png_get_progressive_ptr, + (png_const_structrp png_ptr)); + +/* Function to be called when data becomes available */ +PNG_EXPORT(92, void, png_process_data, (png_structrp png_ptr, + png_inforp info_ptr, png_bytep buffer, png_size_t buffer_size)); + +/* A function which may be called *only* within png_process_data to stop the + * processing of any more data. The function returns the number of bytes + * remaining, excluding any that libpng has cached internally. A subsequent + * call to png_process_data must supply these bytes again. If the argument + * 'save' is set to true the routine will first save all the pending data and + * will always return 0. + */ +PNG_EXPORT(219, png_size_t, png_process_data_pause, (png_structrp, int save)); + +/* A function which may be called *only* outside (after) a call to + * png_process_data. It returns the number of bytes of data to skip in the + * input. Normally it will return 0, but if it returns a non-zero value the + * application must skip than number of bytes of input data and pass the + * following data to the next call to png_process_data. + */ +PNG_EXPORT(220, png_uint_32, png_process_data_skip, (png_structrp)); + +/* Function that combines rows. 'new_row' is a flag that should come from + * the callback and be non-NULL if anything needs to be done; the library + * stores its own version of the new data internally and ignores the passed + * in value. + */ +PNG_EXPORT(93, void, png_progressive_combine_row, (png_const_structrp png_ptr, + png_bytep old_row, png_const_bytep new_row)); +#endif /* PROGRESSIVE_READ */ + +PNG_EXPORTA(94, png_voidp, png_malloc, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); +/* Added at libpng version 1.4.0 */ +PNG_EXPORTA(95, png_voidp, png_calloc, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); + +/* Added at libpng version 1.2.4 */ +PNG_EXPORTA(96, png_voidp, png_malloc_warn, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); + +/* Frees a pointer allocated by png_malloc() */ +PNG_EXPORT(97, void, png_free, (png_const_structrp png_ptr, png_voidp ptr)); + +/* Free data that was allocated internally */ +PNG_EXPORT(98, void, png_free_data, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 free_me, int num)); + +/* Reassign responsibility for freeing existing data, whether allocated + * by libpng or by the application; this works on the png_info structure passed + * in, it does not change the state for other png_info structures. + * + * It is unlikely that this function works correctly as of 1.6.0 and using it + * may result either in memory leaks or double free of allocated data. + */ +PNG_EXPORT(99, void, png_data_freer, (png_const_structrp png_ptr, + png_inforp info_ptr, int freer, png_uint_32 mask)); + +/* Assignments for png_data_freer */ +#define PNG_DESTROY_WILL_FREE_DATA 1 +#define PNG_SET_WILL_FREE_DATA 1 +#define PNG_USER_WILL_FREE_DATA 2 +/* Flags for png_ptr->free_me and info_ptr->free_me */ +#define PNG_FREE_HIST 0x0008U +#define PNG_FREE_ICCP 0x0010U +#define PNG_FREE_SPLT 0x0020U +#define PNG_FREE_ROWS 0x0040U +#define PNG_FREE_PCAL 0x0080U +#define PNG_FREE_SCAL 0x0100U +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_FREE_UNKN 0x0200U +#endif +/* PNG_FREE_LIST 0x0400U removed in 1.6.0 because it is ignored */ +#define PNG_FREE_PLTE 0x1000U +#define PNG_FREE_TRNS 0x2000U +#define PNG_FREE_TEXT 0x4000U +#define PNG_FREE_ALL 0x7fffU +#define PNG_FREE_MUL 0x4220U /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ + +#ifdef PNG_USER_MEM_SUPPORTED +PNG_EXPORTA(100, png_voidp, png_malloc_default, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED PNG_DEPRECATED); +PNG_EXPORTA(101, void, png_free_default, (png_const_structrp png_ptr, + png_voidp ptr), PNG_DEPRECATED); +#endif + +#ifdef PNG_ERROR_TEXT_SUPPORTED +/* Fatal error in PNG image of libpng - can't continue */ +PNG_EXPORTA(102, void, png_error, (png_const_structrp png_ptr, + png_const_charp error_message), PNG_NORETURN); + +/* The same, but the chunk name is prepended to the error string. */ +PNG_EXPORTA(103, void, png_chunk_error, (png_const_structrp png_ptr, + png_const_charp error_message), PNG_NORETURN); + +#else +/* Fatal error in PNG image of libpng - can't continue */ +PNG_EXPORTA(104, void, png_err, (png_const_structrp png_ptr), PNG_NORETURN); +# define png_error(s1,s2) png_err(s1) +# define png_chunk_error(s1,s2) png_err(s1) +#endif + +#ifdef PNG_WARNINGS_SUPPORTED +/* Non-fatal error in libpng. Can continue, but may have a problem. */ +PNG_EXPORT(105, void, png_warning, (png_const_structrp png_ptr, + png_const_charp warning_message)); + +/* Non-fatal error in libpng, chunk name is prepended to message. */ +PNG_EXPORT(106, void, png_chunk_warning, (png_const_structrp png_ptr, + png_const_charp warning_message)); +#else +# define png_warning(s1,s2) ((void)(s1)) +# define png_chunk_warning(s1,s2) ((void)(s1)) +#endif + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +/* Benign error in libpng. Can continue, but may have a problem. + * User can choose whether to handle as a fatal error or as a warning. */ +PNG_EXPORT(107, void, png_benign_error, (png_const_structrp png_ptr, + png_const_charp warning_message)); + +#ifdef PNG_READ_SUPPORTED +/* Same, chunk name is prepended to message (only during read) */ +PNG_EXPORT(108, void, png_chunk_benign_error, (png_const_structrp png_ptr, + png_const_charp warning_message)); +#endif + +PNG_EXPORT(109, void, png_set_benign_errors, + (png_structrp png_ptr, int allowed)); +#else +# ifdef PNG_ALLOW_BENIGN_ERRORS +# define png_benign_error png_warning +# define png_chunk_benign_error png_chunk_warning +# else +# define png_benign_error png_error +# define png_chunk_benign_error png_chunk_error +# endif +#endif + +/* The png_set_ functions are for storing values in the png_info_struct. + * Similarly, the png_get_ calls are used to read values from the + * png_info_struct, either storing the parameters in the passed variables, or + * setting pointers into the png_info_struct where the data is stored. The + * png_get_ functions return a non-zero value if the data was available + * in info_ptr, or return zero and do not change any of the parameters if the + * data was not available. + * + * These functions should be used instead of directly accessing png_info + * to avoid problems with future changes in the size and internal layout of + * png_info_struct. + */ +/* Returns "flag" if chunk data is valid in info_ptr. */ +PNG_EXPORT(110, png_uint_32, png_get_valid, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 flag)); + +/* Returns number of bytes needed to hold a transformed row. */ +PNG_EXPORT(111, png_size_t, png_get_rowbytes, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +#ifdef PNG_INFO_IMAGE_SUPPORTED +/* Returns row_pointers, which is an array of pointers to scanlines that was + * returned from png_read_png(). + */ +PNG_EXPORT(112, png_bytepp, png_get_rows, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Set row_pointers, which is an array of pointers to scanlines for use + * by png_write_png(). + */ +PNG_EXPORT(113, void, png_set_rows, (png_const_structrp png_ptr, + png_inforp info_ptr, png_bytepp row_pointers)); +#endif + +/* Returns number of color channels in image. */ +PNG_EXPORT(114, png_byte, png_get_channels, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +#ifdef PNG_EASY_ACCESS_SUPPORTED +/* Returns image width in pixels. */ +PNG_EXPORT(115, png_uint_32, png_get_image_width, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image height in pixels. */ +PNG_EXPORT(116, png_uint_32, png_get_image_height, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image bit_depth. */ +PNG_EXPORT(117, png_byte, png_get_bit_depth, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image color_type. */ +PNG_EXPORT(118, png_byte, png_get_color_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image filter_type. */ +PNG_EXPORT(119, png_byte, png_get_filter_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image interlace_type. */ +PNG_EXPORT(120, png_byte, png_get_interlace_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image compression_type. */ +PNG_EXPORT(121, png_byte, png_get_compression_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image resolution in pixels per meter, from pHYs chunk data. */ +PNG_EXPORT(122, png_uint_32, png_get_pixels_per_meter, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(123, png_uint_32, png_get_x_pixels_per_meter, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(124, png_uint_32, png_get_y_pixels_per_meter, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +/* Returns pixel aspect ratio, computed from pHYs chunk data. */ +PNG_FP_EXPORT(125, float, png_get_pixel_aspect_ratio, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +PNG_FIXED_EXPORT(210, png_fixed_point, png_get_pixel_aspect_ratio_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) + +/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ +PNG_EXPORT(126, png_int_32, png_get_x_offset_pixels, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(127, png_int_32, png_get_y_offset_pixels, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(128, png_int_32, png_get_x_offset_microns, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(129, png_int_32, png_get_y_offset_microns, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +#endif /* EASY_ACCESS */ + +#ifdef PNG_READ_SUPPORTED +/* Returns pointer to signature string read from PNG header */ +PNG_EXPORT(130, png_const_bytep, png_get_signature, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); +#endif + +#ifdef PNG_bKGD_SUPPORTED +PNG_EXPORT(131, png_uint_32, png_get_bKGD, (png_const_structrp png_ptr, + png_inforp info_ptr, png_color_16p *background)); +#endif + +#ifdef PNG_bKGD_SUPPORTED +PNG_EXPORT(132, void, png_set_bKGD, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_color_16p background)); +#endif + +#ifdef PNG_cHRM_SUPPORTED +PNG_FP_EXPORT(133, png_uint_32, png_get_cHRM, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *white_x, double *white_y, double *red_x, + double *red_y, double *green_x, double *green_y, double *blue_x, + double *blue_y)) +PNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *red_X, double *red_Y, double *red_Z, + double *green_X, double *green_Y, double *green_Z, double *blue_X, + double *blue_Y, double *blue_Z)) +PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_white_x, png_fixed_point *int_white_y, + png_fixed_point *int_red_x, png_fixed_point *int_red_y, + png_fixed_point *int_green_x, png_fixed_point *int_green_y, + png_fixed_point *int_blue_x, png_fixed_point *int_blue_y)) +PNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_red_X, png_fixed_point *int_red_Y, + png_fixed_point *int_red_Z, png_fixed_point *int_green_X, + png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, + png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, + png_fixed_point *int_blue_Z)) +#endif + +#ifdef PNG_cHRM_SUPPORTED +PNG_FP_EXPORT(135, void, png_set_cHRM, (png_const_structrp png_ptr, + png_inforp info_ptr, + double white_x, double white_y, double red_x, double red_y, double green_x, + double green_y, double blue_x, double blue_y)) +PNG_FP_EXPORT(232, void, png_set_cHRM_XYZ, (png_const_structrp png_ptr, + png_inforp info_ptr, double red_X, double red_Y, double red_Z, + double green_X, double green_Y, double green_Z, double blue_X, + double blue_Y, double blue_Z)) +PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_white_x, + png_fixed_point int_white_y, png_fixed_point int_red_x, + png_fixed_point int_red_y, png_fixed_point int_green_x, + png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)) +PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y, + png_fixed_point int_red_Z, png_fixed_point int_green_X, + png_fixed_point int_green_Y, png_fixed_point int_green_Z, + png_fixed_point int_blue_X, png_fixed_point int_blue_Y, + png_fixed_point int_blue_Z)) +#endif + +#ifdef PNG_gAMA_SUPPORTED +PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *file_gamma)) +PNG_FIXED_EXPORT(138, png_uint_32, png_get_gAMA_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_file_gamma)) +#endif + +#ifdef PNG_gAMA_SUPPORTED +PNG_FP_EXPORT(139, void, png_set_gAMA, (png_const_structrp png_ptr, + png_inforp info_ptr, double file_gamma)) +PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_file_gamma)) +#endif + +#ifdef PNG_hIST_SUPPORTED +PNG_EXPORT(141, png_uint_32, png_get_hIST, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_16p *hist)); +#endif + +#ifdef PNG_hIST_SUPPORTED +PNG_EXPORT(142, void, png_set_hIST, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_uint_16p hist)); +#endif + +PNG_EXPORT(143, png_uint_32, png_get_IHDR, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *width, png_uint_32 *height, + int *bit_depth, int *color_type, int *interlace_method, + int *compression_method, int *filter_method)); + +PNG_EXPORT(144, void, png_set_IHDR, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_method, int compression_method, + int filter_method)); + +#ifdef PNG_oFFs_SUPPORTED +PNG_EXPORT(145, png_uint_32, png_get_oFFs, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, + int *unit_type)); +#endif + +#ifdef PNG_oFFs_SUPPORTED +PNG_EXPORT(146, void, png_set_oFFs, (png_const_structrp png_ptr, + png_inforp info_ptr, png_int_32 offset_x, png_int_32 offset_y, + int unit_type)); +#endif + +#ifdef PNG_pCAL_SUPPORTED +PNG_EXPORT(147, png_uint_32, png_get_pCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, png_charp *purpose, png_int_32 *X0, + png_int_32 *X1, int *type, int *nparams, png_charp *units, + png_charpp *params)); +#endif + +#ifdef PNG_pCAL_SUPPORTED +PNG_EXPORT(148, void, png_set_pCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_charp purpose, png_int_32 X0, png_int_32 X1, + int type, int nparams, png_const_charp units, png_charpp params)); +#endif + +#ifdef PNG_pHYs_SUPPORTED +PNG_EXPORT(149, png_uint_32, png_get_pHYs, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, + int *unit_type)); +#endif + +#ifdef PNG_pHYs_SUPPORTED +PNG_EXPORT(150, void, png_set_pHYs, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type)); +#endif + +PNG_EXPORT(151, png_uint_32, png_get_PLTE, (png_const_structrp png_ptr, + png_inforp info_ptr, png_colorp *palette, int *num_palette)); + +PNG_EXPORT(152, void, png_set_PLTE, (png_structrp png_ptr, + png_inforp info_ptr, png_const_colorp palette, int num_palette)); + +#ifdef PNG_sBIT_SUPPORTED +PNG_EXPORT(153, png_uint_32, png_get_sBIT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_color_8p *sig_bit)); +#endif + +#ifdef PNG_sBIT_SUPPORTED +PNG_EXPORT(154, void, png_set_sBIT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_color_8p sig_bit)); +#endif + +#ifdef PNG_sRGB_SUPPORTED +PNG_EXPORT(155, png_uint_32, png_get_sRGB, (png_const_structrp png_ptr, + png_const_inforp info_ptr, int *file_srgb_intent)); +#endif + +#ifdef PNG_sRGB_SUPPORTED +PNG_EXPORT(156, void, png_set_sRGB, (png_const_structrp png_ptr, + png_inforp info_ptr, int srgb_intent)); +PNG_EXPORT(157, void, png_set_sRGB_gAMA_and_cHRM, (png_const_structrp png_ptr, + png_inforp info_ptr, int srgb_intent)); +#endif + +#ifdef PNG_iCCP_SUPPORTED +PNG_EXPORT(158, png_uint_32, png_get_iCCP, (png_const_structrp png_ptr, + png_inforp info_ptr, png_charpp name, int *compression_type, + png_bytepp profile, png_uint_32 *proflen)); +#endif + +#ifdef PNG_iCCP_SUPPORTED +PNG_EXPORT(159, void, png_set_iCCP, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_charp name, int compression_type, + png_const_bytep profile, png_uint_32 proflen)); +#endif + +#ifdef PNG_sPLT_SUPPORTED +PNG_EXPORT(160, int, png_get_sPLT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_sPLT_tpp entries)); +#endif + +#ifdef PNG_sPLT_SUPPORTED +PNG_EXPORT(161, void, png_set_sPLT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_sPLT_tp entries, int nentries)); +#endif + +#ifdef PNG_TEXT_SUPPORTED +/* png_get_text also returns the number of text chunks in *num_text */ +PNG_EXPORT(162, int, png_get_text, (png_const_structrp png_ptr, + png_inforp info_ptr, png_textp *text_ptr, int *num_text)); +#endif + +/* Note while png_set_text() will accept a structure whose text, + * language, and translated keywords are NULL pointers, the structure + * returned by png_get_text will always contain regular + * zero-terminated C strings. They might be empty strings but + * they will never be NULL pointers. + */ + +#ifdef PNG_TEXT_SUPPORTED +PNG_EXPORT(163, void, png_set_text, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_textp text_ptr, int num_text)); +#endif + +#ifdef PNG_tIME_SUPPORTED +PNG_EXPORT(164, png_uint_32, png_get_tIME, (png_const_structrp png_ptr, + png_inforp info_ptr, png_timep *mod_time)); +#endif + +#ifdef PNG_tIME_SUPPORTED +PNG_EXPORT(165, void, png_set_tIME, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_timep mod_time)); +#endif + +#ifdef PNG_tRNS_SUPPORTED +PNG_EXPORT(166, png_uint_32, png_get_tRNS, (png_const_structrp png_ptr, + png_inforp info_ptr, png_bytep *trans_alpha, int *num_trans, + png_color_16p *trans_color)); +#endif + +#ifdef PNG_tRNS_SUPPORTED +PNG_EXPORT(167, void, png_set_tRNS, (png_structrp png_ptr, + png_inforp info_ptr, png_const_bytep trans_alpha, int num_trans, + png_const_color_16p trans_color)); +#endif + +#ifdef PNG_sCAL_SUPPORTED +PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL, (png_const_structrp png_ptr, + png_const_inforp info_ptr, int *unit, double *width, double *height)) +#if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \ + defined(PNG_FLOATING_POINT_SUPPORTED) +/* NOTE: this API is currently implemented using floating point arithmetic, + * consequently it can only be used on systems with floating point support. + * In any case the range of values supported by png_fixed_point is small and it + * is highly recommended that png_get_sCAL_s be used instead. + */ +PNG_FIXED_EXPORT(214, png_uint_32, png_get_sCAL_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, + png_fixed_point *width, png_fixed_point *height)) +#endif +PNG_EXPORT(169, png_uint_32, png_get_sCAL_s, + (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, + png_charpp swidth, png_charpp sheight)); + +PNG_FP_EXPORT(170, void, png_set_sCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, double width, double height)) +PNG_FIXED_EXPORT(213, void, png_set_sCAL_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, png_fixed_point width, + png_fixed_point height)) +PNG_EXPORT(171, void, png_set_sCAL_s, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, + png_const_charp swidth, png_const_charp sheight)); +#endif /* sCAL */ + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED +/* Provide the default handling for all unknown chunks or, optionally, for + * specific unknown chunks. + * + * NOTE: prior to 1.6.0 the handling specified for particular chunks on read was + * ignored and the default was used, the per-chunk setting only had an effect on + * write. If you wish to have chunk-specific handling on read in code that must + * work on earlier versions you must use a user chunk callback to specify the + * desired handling (keep or discard.) + * + * The 'keep' parameter is a PNG_HANDLE_CHUNK_ value as listed below. The + * parameter is interpreted as follows: + * + * READ: + * PNG_HANDLE_CHUNK_AS_DEFAULT: + * Known chunks: do normal libpng processing, do not keep the chunk (but + * see the comments below about PNG_HANDLE_AS_UNKNOWN_SUPPORTED) + * Unknown chunks: for a specific chunk use the global default, when used + * as the default discard the chunk data. + * PNG_HANDLE_CHUNK_NEVER: + * Discard the chunk data. + * PNG_HANDLE_CHUNK_IF_SAFE: + * Keep the chunk data if the chunk is not critical else raise a chunk + * error. + * PNG_HANDLE_CHUNK_ALWAYS: + * Keep the chunk data. + * + * If the chunk data is saved it can be retrieved using png_get_unknown_chunks, + * below. Notice that specifying "AS_DEFAULT" as a global default is equivalent + * to specifying "NEVER", however when "AS_DEFAULT" is used for specific chunks + * it simply resets the behavior to the libpng default. + * + * INTERACTION WTIH USER CHUNK CALLBACKS: + * The per-chunk handling is always used when there is a png_user_chunk_ptr + * callback and the callback returns 0; the chunk is then always stored *unless* + * it is critical and the per-chunk setting is other than ALWAYS. Notice that + * the global default is *not* used in this case. (In effect the per-chunk + * value is incremented to at least IF_SAFE.) + * + * IMPORTANT NOTE: this behavior will change in libpng 1.7 - the global and + * per-chunk defaults will be honored. If you want to preserve the current + * behavior when your callback returns 0 you must set PNG_HANDLE_CHUNK_IF_SAFE + * as the default - if you don't do this libpng 1.6 will issue a warning. + * + * If you want unhandled unknown chunks to be discarded in libpng 1.6 and + * earlier simply return '1' (handled). + * + * PNG_HANDLE_AS_UNKNOWN_SUPPORTED: + * If this is *not* set known chunks will always be handled by libpng and + * will never be stored in the unknown chunk list. Known chunks listed to + * png_set_keep_unknown_chunks will have no effect. If it is set then known + * chunks listed with a keep other than AS_DEFAULT will *never* be processed + * by libpng, in addition critical chunks must either be processed by the + * callback or saved. + * + * The IHDR and IEND chunks must not be listed. Because this turns off the + * default handling for chunks that would otherwise be recognized the + * behavior of libpng transformations may well become incorrect! + * + * WRITE: + * When writing chunks the options only apply to the chunks specified by + * png_set_unknown_chunks (below), libpng will *always* write known chunks + * required by png_set_ calls and will always write the core critical chunks + * (as required for PLTE). + * + * Each chunk in the png_set_unknown_chunks list is looked up in the + * png_set_keep_unknown_chunks list to find the keep setting, this is then + * interpreted as follows: + * + * PNG_HANDLE_CHUNK_AS_DEFAULT: + * Write safe-to-copy chunks and write other chunks if the global + * default is set to _ALWAYS, otherwise don't write this chunk. + * PNG_HANDLE_CHUNK_NEVER: + * Do not write the chunk. + * PNG_HANDLE_CHUNK_IF_SAFE: + * Write the chunk if it is safe-to-copy, otherwise do not write it. + * PNG_HANDLE_CHUNK_ALWAYS: + * Write the chunk. + * + * Note that the default behavior is effectively the opposite of the read case - + * in read unknown chunks are not stored by default, in write they are written + * by default. Also the behavior of PNG_HANDLE_CHUNK_IF_SAFE is very different + * - on write the safe-to-copy bit is checked, on read the critical bit is + * checked and on read if the chunk is critical an error will be raised. + * + * num_chunks: + * =========== + * If num_chunks is positive, then the "keep" parameter specifies the manner + * for handling only those chunks appearing in the chunk_list array, + * otherwise the chunk list array is ignored. + * + * If num_chunks is 0 the "keep" parameter specifies the default behavior for + * unknown chunks, as described above. + * + * If num_chunks is negative, then the "keep" parameter specifies the manner + * for handling all unknown chunks plus all chunks recognized by libpng + * except for the IHDR, PLTE, tRNS, IDAT, and IEND chunks (which continue to + * be processed by libpng. + */ +PNG_EXPORT(172, void, png_set_keep_unknown_chunks, (png_structrp png_ptr, + int keep, png_const_bytep chunk_list, int num_chunks)); + +/* The "keep" PNG_HANDLE_CHUNK_ parameter for the specified chunk is returned; + * the result is therefore true (non-zero) if special handling is required, + * false for the default handling. + */ +PNG_EXPORT(173, int, png_handle_as_unknown, (png_const_structrp png_ptr, + png_const_bytep chunk_name)); +#endif + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +PNG_EXPORT(174, void, png_set_unknown_chunks, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_unknown_chunkp unknowns, + int num_unknowns)); + /* NOTE: prior to 1.6.0 this routine set the 'location' field of the added + * unknowns to the location currently stored in the png_struct. This is + * invariably the wrong value on write. To fix this call the following API + * for each chunk in the list with the correct location. If you know your + * code won't be compiled on earlier versions you can rely on + * png_set_unknown_chunks(write-ptr, png_get_unknown_chunks(read-ptr)) doing + * the correct thing. + */ + +PNG_EXPORT(175, void, png_set_unknown_chunk_location, + (png_const_structrp png_ptr, png_inforp info_ptr, int chunk, int location)); + +PNG_EXPORT(176, int, png_get_unknown_chunks, (png_const_structrp png_ptr, + png_inforp info_ptr, png_unknown_chunkpp entries)); +#endif + +/* Png_free_data() will turn off the "valid" flag for anything it frees. + * If you need to turn it off for a chunk that your application has freed, + * you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); + */ +PNG_EXPORT(177, void, png_set_invalid, (png_const_structrp png_ptr, + png_inforp info_ptr, int mask)); + +#ifdef PNG_INFO_IMAGE_SUPPORTED +/* The "params" pointer is currently not used and is for future expansion. */ +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +PNG_EXPORT(178, void, png_read_png, (png_structrp png_ptr, png_inforp info_ptr, + int transforms, png_voidp params)); +#endif +#ifdef PNG_WRITE_SUPPORTED +PNG_EXPORT(179, void, png_write_png, (png_structrp png_ptr, png_inforp info_ptr, + int transforms, png_voidp params)); +#endif +#endif + +PNG_EXPORT(180, png_const_charp, png_get_copyright, + (png_const_structrp png_ptr)); +PNG_EXPORT(181, png_const_charp, png_get_header_ver, + (png_const_structrp png_ptr)); +PNG_EXPORT(182, png_const_charp, png_get_header_version, + (png_const_structrp png_ptr)); +PNG_EXPORT(183, png_const_charp, png_get_libpng_ver, + (png_const_structrp png_ptr)); + +#ifdef PNG_MNG_FEATURES_SUPPORTED +PNG_EXPORT(184, png_uint_32, png_permit_mng_features, (png_structrp png_ptr, + png_uint_32 mng_features_permitted)); +#endif + +/* For use in png_set_keep_unknown, added to version 1.2.6 */ +#define PNG_HANDLE_CHUNK_AS_DEFAULT 0 +#define PNG_HANDLE_CHUNK_NEVER 1 +#define PNG_HANDLE_CHUNK_IF_SAFE 2 +#define PNG_HANDLE_CHUNK_ALWAYS 3 +#define PNG_HANDLE_CHUNK_LAST 4 + +/* Strip the prepended error numbers ("#nnn ") from error and warning + * messages before passing them to the error or warning handler. + */ +#ifdef PNG_ERROR_NUMBERS_SUPPORTED +PNG_EXPORT(185, void, png_set_strip_error_numbers, (png_structrp png_ptr, + png_uint_32 strip_mode)); +#endif + +/* Added in libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +PNG_EXPORT(186, void, png_set_user_limits, (png_structrp png_ptr, + png_uint_32 user_width_max, png_uint_32 user_height_max)); +PNG_EXPORT(187, png_uint_32, png_get_user_width_max, + (png_const_structrp png_ptr)); +PNG_EXPORT(188, png_uint_32, png_get_user_height_max, + (png_const_structrp png_ptr)); +/* Added in libpng-1.4.0 */ +PNG_EXPORT(189, void, png_set_chunk_cache_max, (png_structrp png_ptr, + png_uint_32 user_chunk_cache_max)); +PNG_EXPORT(190, png_uint_32, png_get_chunk_cache_max, + (png_const_structrp png_ptr)); +/* Added in libpng-1.4.1 */ +PNG_EXPORT(191, void, png_set_chunk_malloc_max, (png_structrp png_ptr, + png_alloc_size_t user_chunk_cache_max)); +PNG_EXPORT(192, png_alloc_size_t, png_get_chunk_malloc_max, + (png_const_structrp png_ptr)); +#endif + +#if defined(PNG_INCH_CONVERSIONS_SUPPORTED) +PNG_EXPORT(193, png_uint_32, png_get_pixels_per_inch, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +PNG_EXPORT(194, png_uint_32, png_get_x_pixels_per_inch, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +PNG_EXPORT(195, png_uint_32, png_get_y_pixels_per_inch, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +PNG_FP_EXPORT(196, float, png_get_x_offset_inches, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ +PNG_FIXED_EXPORT(211, png_fixed_point, png_get_x_offset_inches_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +#endif + +PNG_FP_EXPORT(197, float, png_get_y_offset_inches, (png_const_structrp png_ptr, + png_const_inforp info_ptr)) +#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ +PNG_FIXED_EXPORT(212, png_fixed_point, png_get_y_offset_inches_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +#endif + +# ifdef PNG_pHYs_SUPPORTED +PNG_EXPORT(198, png_uint_32, png_get_pHYs_dpi, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, + int *unit_type)); +# endif /* pHYs */ +#endif /* INCH_CONVERSIONS */ + +/* Added in libpng-1.4.0 */ +#ifdef PNG_IO_STATE_SUPPORTED +PNG_EXPORT(199, png_uint_32, png_get_io_state, (png_const_structrp png_ptr)); + +/* Removed from libpng 1.6; use png_get_io_chunk_type. */ +PNG_REMOVED(200, png_const_bytep, png_get_io_chunk_name, (png_structrp png_ptr), + PNG_DEPRECATED) + +PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type, + (png_const_structrp png_ptr)); + +/* The flags returned by png_get_io_state() are the following: */ +# define PNG_IO_NONE 0x0000 /* no I/O at this moment */ +# define PNG_IO_READING 0x0001 /* currently reading */ +# define PNG_IO_WRITING 0x0002 /* currently writing */ +# define PNG_IO_SIGNATURE 0x0010 /* currently at the file signature */ +# define PNG_IO_CHUNK_HDR 0x0020 /* currently at the chunk header */ +# define PNG_IO_CHUNK_DATA 0x0040 /* currently at the chunk data */ +# define PNG_IO_CHUNK_CRC 0x0080 /* currently at the chunk crc */ +# define PNG_IO_MASK_OP 0x000f /* current operation: reading/writing */ +# define PNG_IO_MASK_LOC 0x00f0 /* current location: sig/hdr/data/crc */ +#endif /* IO_STATE */ + +/* Interlace support. The following macros are always defined so that if + * libpng interlace handling is turned off the macros may be used to handle + * interlaced images within the application. + */ +#define PNG_INTERLACE_ADAM7_PASSES 7 + +/* Two macros to return the first row and first column of the original, + * full, image which appears in a given pass. 'pass' is in the range 0 + * to 6 and the result is in the range 0 to 7. + */ +#define PNG_PASS_START_ROW(pass) (((1&~(pass))<<(3-((pass)>>1)))&7) +#define PNG_PASS_START_COL(pass) (((1& (pass))<<(3-(((pass)+1)>>1)))&7) + +/* A macro to return the offset between pixels in the output row for a pair of + * pixels in the input - effectively the inverse of the 'COL_SHIFT' macro that + * follows. Note that ROW_OFFSET is the offset from one row to the next whereas + * COL_OFFSET is from one column to the next, within a row. + */ +#define PNG_PASS_ROW_OFFSET(pass) ((pass)>2?(8>>(((pass)-1)>>1)):8) +#define PNG_PASS_COL_OFFSET(pass) (1<<((7-(pass))>>1)) + +/* Two macros to help evaluate the number of rows or columns in each + * pass. This is expressed as a shift - effectively log2 of the number or + * rows or columns in each 8x8 tile of the original image. + */ +#define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3) +#define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3) + +/* Hence two macros to determine the number of rows or columns in a given + * pass of an image given its height or width. In fact these macros may + * return non-zero even though the sub-image is empty, because the other + * dimension may be empty for a small image. + */ +#define PNG_PASS_ROWS(height, pass) (((height)+(((1<>PNG_PASS_ROW_SHIFT(pass)) +#define PNG_PASS_COLS(width, pass) (((width)+(((1<>PNG_PASS_COL_SHIFT(pass)) + +/* For the reader row callbacks (both progressive and sequential) it is + * necessary to find the row in the output image given a row in an interlaced + * image, so two more macros: + */ +#define PNG_ROW_FROM_PASS_ROW(y_in, pass) \ + (((y_in)<>(((7-(off))-(pass))<<2)) & 0xF) | \ + ((0x01145AF0>>(((7-(off))-(pass))<<2)) & 0xF0)) + +#define PNG_ROW_IN_INTERLACE_PASS(y, pass) \ + ((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1) +#define PNG_COL_IN_INTERLACE_PASS(x, pass) \ + ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1) + +#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED +/* With these routines we avoid an integer divide, which will be slower on + * most machines. However, it does take more operations than the corresponding + * divide method, so it may be slower on a few RISC systems. There are two + * shifts (by 8 or 16 bits) and an addition, versus a single integer divide. + * + * Note that the rounding factors are NOT supposed to be the same! 128 and + * 32768 are correct for the NODIV code; 127 and 32767 are correct for the + * standard method. + * + * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ] + */ + + /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */ + +# define png_composite(composite, fg, alpha, bg) \ + { png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) \ + * (png_uint_16)(alpha) \ + + (png_uint_16)(bg)*(png_uint_16)(255 \ + - (png_uint_16)(alpha)) + 128); \ + (composite) = (png_byte)(((temp + (temp >> 8)) >> 8) & 0xff); } + +# define png_composite_16(composite, fg, alpha, bg) \ + { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) \ + * (png_uint_32)(alpha) \ + + (png_uint_32)(bg)*(65535 \ + - (png_uint_32)(alpha)) + 32768); \ + (composite) = (png_uint_16)(0xffff & ((temp + (temp >> 16)) >> 16)); } + +#else /* Standard method using integer division */ + +# define png_composite(composite, fg, alpha, bg) \ + (composite) = \ + (png_byte)(0xff & (((png_uint_16)(fg) * (png_uint_16)(alpha) + \ + (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ + 127) / 255)) + +# define png_composite_16(composite, fg, alpha, bg) \ + (composite) = \ + (png_uint_16)(0xffff & (((png_uint_32)(fg) * (png_uint_32)(alpha) + \ + (png_uint_32)(bg)*(png_uint_32)(65535 - (png_uint_32)(alpha)) + \ + 32767) / 65535)) +#endif /* READ_COMPOSITE_NODIV */ + +#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED +PNG_EXPORT(201, png_uint_32, png_get_uint_32, (png_const_bytep buf)); +PNG_EXPORT(202, png_uint_16, png_get_uint_16, (png_const_bytep buf)); +PNG_EXPORT(203, png_int_32, png_get_int_32, (png_const_bytep buf)); +#endif + +PNG_EXPORT(204, png_uint_32, png_get_uint_31, (png_const_structrp png_ptr, + png_const_bytep buf)); +/* No png_get_int_16 -- may be added if there's a real need for it. */ + +/* Place a 32-bit number into a buffer in PNG byte order (big-endian). */ +#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED +PNG_EXPORT(205, void, png_save_uint_32, (png_bytep buf, png_uint_32 i)); +#endif +#ifdef PNG_SAVE_INT_32_SUPPORTED +PNG_EXPORT(206, void, png_save_int_32, (png_bytep buf, png_int_32 i)); +#endif + +/* Place a 16-bit number into a buffer in PNG byte order. + * The parameter is declared unsigned int, not png_uint_16, + * just to avoid potential problems on pre-ANSI C compilers. + */ +#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED +PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i)); +/* No png_save_int_16 -- may be added if there's a real need for it. */ +#endif + +#ifdef PNG_USE_READ_MACROS +/* Inline macros to do direct reads of bytes from the input buffer. + * The png_get_int_32() routine assumes we are using two's complement + * format for negative values, which is almost certainly true. + */ +# define PNG_get_uint_32(buf) \ + (((png_uint_32)(*(buf)) << 24) + \ + ((png_uint_32)(*((buf) + 1)) << 16) + \ + ((png_uint_32)(*((buf) + 2)) << 8) + \ + ((png_uint_32)(*((buf) + 3)))) + + /* From libpng-1.4.0 until 1.4.4, the png_get_uint_16 macro (but not the + * function) incorrectly returned a value of type png_uint_32. + */ +# define PNG_get_uint_16(buf) \ + ((png_uint_16) \ + (((unsigned int)(*(buf)) << 8) + \ + ((unsigned int)(*((buf) + 1))))) + +# define PNG_get_int_32(buf) \ + ((png_int_32)((*(buf) & 0x80) \ + ? -((png_int_32)(((png_get_uint_32(buf)^0xffffffffU)+1U)&0x7fffffffU)) \ + : (png_int_32)png_get_uint_32(buf))) + + /* If PNG_PREFIX is defined the same thing as below happens in pnglibconf.h, + * but defining a macro name prefixed with PNG_PREFIX. + */ +# ifndef PNG_PREFIX +# define png_get_uint_32(buf) PNG_get_uint_32(buf) +# define png_get_uint_16(buf) PNG_get_uint_16(buf) +# define png_get_int_32(buf) PNG_get_int_32(buf) +# endif +#else +# ifdef PNG_PREFIX + /* No macros; revert to the (redefined) function */ +# define PNG_get_uint_32 (png_get_uint_32) +# define PNG_get_uint_16 (png_get_uint_16) +# define PNG_get_int_32 (png_get_int_32) +# endif +#endif + +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED +PNG_EXPORT(242, void, png_set_check_for_invalid_index, + (png_structrp png_ptr, int allowed)); +# ifdef PNG_GET_PALETTE_MAX_SUPPORTED +PNG_EXPORT(243, int, png_get_palette_max, (png_const_structp png_ptr, + png_const_infop info_ptr)); +# endif +#endif /* CHECK_FOR_INVALID_INDEX */ + +/******************************************************************************* + * Section 5: SIMPLIFIED API + ******************************************************************************* + * + * Please read the documentation in libpng-manual.txt (TODO: write said + * documentation) if you don't understand what follows. + * + * The simplified API hides the details of both libpng and the PNG file format + * itself. It allows PNG files to be read into a very limited number of + * in-memory bitmap formats or to be written from the same formats. If these + * formats do not accomodate your needs then you can, and should, use the more + * sophisticated APIs above - these support a wide variety of in-memory formats + * and a wide variety of sophisticated transformations to those formats as well + * as a wide variety of APIs to manipulate ancillary information. + * + * To read a PNG file using the simplified API: + * + * 1) Declare a 'png_image' structure (see below) on the stack, set the + * version field to PNG_IMAGE_VERSION and the 'opaque' pointer to NULL + * (this is REQUIRED, your program may crash if you don't do it.) + * 2) Call the appropriate png_image_begin_read... function. + * 3) Set the png_image 'format' member to the required sample format. + * 4) Allocate a buffer for the image and, if required, the color-map. + * 5) Call png_image_finish_read to read the image and, if required, the + * color-map into your buffers. + * + * There are no restrictions on the format of the PNG input itself; all valid + * color types, bit depths, and interlace methods are acceptable, and the + * input image is transformed as necessary to the requested in-memory format + * during the png_image_finish_read() step. The only caveat is that if you + * request a color-mapped image from a PNG that is full-color or makes + * complex use of an alpha channel the transformation is extremely lossy and the + * result may look terrible. + * + * To write a PNG file using the simplified API: + * + * 1) Declare a 'png_image' structure on the stack and memset() it to all zero. + * 2) Initialize the members of the structure that describe the image, setting + * the 'format' member to the format of the image samples. + * 3) Call the appropriate png_image_write... function with a pointer to the + * image and, if necessary, the color-map to write the PNG data. + * + * png_image is a structure that describes the in-memory format of an image + * when it is being read or defines the in-memory format of an image that you + * need to write: + */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) || \ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) + +#define PNG_IMAGE_VERSION 1 + +typedef struct png_control *png_controlp; +typedef struct +{ + png_controlp opaque; /* Initialize to NULL, free with png_image_free */ + png_uint_32 version; /* Set to PNG_IMAGE_VERSION */ + png_uint_32 width; /* Image width in pixels (columns) */ + png_uint_32 height; /* Image height in pixels (rows) */ + png_uint_32 format; /* Image format as defined below */ + png_uint_32 flags; /* A bit mask containing informational flags */ + png_uint_32 colormap_entries; + /* Number of entries in the color-map */ + + /* In the event of an error or warning the following field will be set to a + * non-zero value and the 'message' field will contain a '\0' terminated + * string with the libpng error or warning message. If both warnings and + * an error were encountered, only the error is recorded. If there + * are multiple warnings, only the first one is recorded. + * + * The upper 30 bits of this value are reserved, the low two bits contain + * a value as follows: + */ +# define PNG_IMAGE_WARNING 1 +# define PNG_IMAGE_ERROR 2 + /* + * The result is a two-bit code such that a value more than 1 indicates + * a failure in the API just called: + * + * 0 - no warning or error + * 1 - warning + * 2 - error + * 3 - error preceded by warning + */ +# define PNG_IMAGE_FAILED(png_cntrl) ((((png_cntrl).warning_or_error)&0x03)>1) + + png_uint_32 warning_or_error; + + char message[64]; +} png_image, *png_imagep; + +/* The samples of the image have one to four channels whose components have + * original values in the range 0 to 1.0: + * + * 1: A single gray or luminance channel (G). + * 2: A gray/luminance channel and an alpha channel (GA). + * 3: Three red, green, blue color channels (RGB). + * 4: Three color channels and an alpha channel (RGBA). + * + * The components are encoded in one of two ways: + * + * a) As a small integer, value 0..255, contained in a single byte. For the + * alpha channel the original value is simply value/255. For the color or + * luminance channels the value is encoded according to the sRGB specification + * and matches the 8-bit format expected by typical display devices. + * + * The color/gray channels are not scaled (pre-multiplied) by the alpha + * channel and are suitable for passing to color management software. + * + * b) As a value in the range 0..65535, contained in a 2-byte integer. All + * channels can be converted to the original value by dividing by 65535; all + * channels are linear. Color channels use the RGB encoding (RGB end-points) of + * the sRGB specification. This encoding is identified by the + * PNG_FORMAT_FLAG_LINEAR flag below. + * + * When the simplified API needs to convert between sRGB and linear colorspaces, + * the actual sRGB transfer curve defined in the sRGB specification (see the + * article at http://en.wikipedia.org/wiki/SRGB) is used, not the gamma=1/2.2 + * approximation used elsewhere in libpng. + * + * When an alpha channel is present it is expected to denote pixel coverage + * of the color or luminance channels and is returned as an associated alpha + * channel: the color/gray channels are scaled (pre-multiplied) by the alpha + * value. + * + * The samples are either contained directly in the image data, between 1 and 8 + * bytes per pixel according to the encoding, or are held in a color-map indexed + * by bytes in the image data. In the case of a color-map the color-map entries + * are individual samples, encoded as above, and the image data has one byte per + * pixel to select the relevant sample from the color-map. + */ + +/* PNG_FORMAT_* + * + * #defines to be used in png_image::format. Each #define identifies a + * particular layout of sample data and, if present, alpha values. There are + * separate defines for each of the two component encodings. + * + * A format is built up using single bit flag values. All combinations are + * valid. Formats can be built up from the flag values or you can use one of + * the predefined values below. When testing formats always use the FORMAT_FLAG + * macros to test for individual features - future versions of the library may + * add new flags. + * + * When reading or writing color-mapped images the format should be set to the + * format of the entries in the color-map then png_image_{read,write}_colormap + * called to read or write the color-map and set the format correctly for the + * image data. Do not set the PNG_FORMAT_FLAG_COLORMAP bit directly! + * + * NOTE: libpng can be built with particular features disabled. If you see + * compiler errors because the definition of one of the following flags has been + * compiled out it is because libpng does not have the required support. It is + * possible, however, for the libpng configuration to enable the format on just + * read or just write; in that case you may see an error at run time. You can + * guard against this by checking for the definition of the appropriate + * "_SUPPORTED" macro, one of: + * + * PNG_SIMPLIFIED_{READ,WRITE}_{BGR,AFIRST}_SUPPORTED + */ +#define PNG_FORMAT_FLAG_ALPHA 0x01U /* format with an alpha channel */ +#define PNG_FORMAT_FLAG_COLOR 0x02U /* color format: otherwise grayscale */ +#define PNG_FORMAT_FLAG_LINEAR 0x04U /* 2-byte channels else 1-byte */ +#define PNG_FORMAT_FLAG_COLORMAP 0x08U /* image data is color-mapped */ + +#ifdef PNG_FORMAT_BGR_SUPPORTED +# define PNG_FORMAT_FLAG_BGR 0x10U /* BGR colors, else order is RGB */ +#endif + +#ifdef PNG_FORMAT_AFIRST_SUPPORTED +# define PNG_FORMAT_FLAG_AFIRST 0x20U /* alpha channel comes first */ +#endif + +/* Commonly used formats have predefined macros. + * + * First the single byte (sRGB) formats: + */ +#define PNG_FORMAT_GRAY 0 +#define PNG_FORMAT_GA PNG_FORMAT_FLAG_ALPHA +#define PNG_FORMAT_AG (PNG_FORMAT_GA|PNG_FORMAT_FLAG_AFIRST) +#define PNG_FORMAT_RGB PNG_FORMAT_FLAG_COLOR +#define PNG_FORMAT_BGR (PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_BGR) +#define PNG_FORMAT_RGBA (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_ARGB (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_AFIRST) +#define PNG_FORMAT_BGRA (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_ABGR (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_AFIRST) + +/* Then the linear 2-byte formats. When naming these "Y" is used to + * indicate a luminance (gray) channel. + */ +#define PNG_FORMAT_LINEAR_Y PNG_FORMAT_FLAG_LINEAR +#define PNG_FORMAT_LINEAR_Y_ALPHA (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_LINEAR_RGB (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR) +#define PNG_FORMAT_LINEAR_RGB_ALPHA \ + (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA) + +/* With color-mapped formats the image data is one byte for each pixel, the byte + * is an index into the color-map which is formatted as above. To obtain a + * color-mapped format it is sufficient just to add the PNG_FOMAT_FLAG_COLORMAP + * to one of the above definitions, or you can use one of the definitions below. + */ +#define PNG_FORMAT_RGB_COLORMAP (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_BGR_COLORMAP (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_RGBA_COLORMAP (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_ARGB_COLORMAP (PNG_FORMAT_ARGB|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_BGRA_COLORMAP (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_ABGR_COLORMAP (PNG_FORMAT_ABGR|PNG_FORMAT_FLAG_COLORMAP) + +/* PNG_IMAGE macros + * + * These are convenience macros to derive information from a png_image + * structure. The PNG_IMAGE_SAMPLE_ macros return values appropriate to the + * actual image sample values - either the entries in the color-map or the + * pixels in the image. The PNG_IMAGE_PIXEL_ macros return corresponding values + * for the pixels and will always return 1 for color-mapped formats. The + * remaining macros return information about the rows in the image and the + * complete image. + * + * NOTE: All the macros that take a png_image::format parameter are compile time + * constants if the format parameter is, itself, a constant. Therefore these + * macros can be used in array declarations and case labels where required. + * Similarly the macros are also pre-processor constants (sizeof is not used) so + * they can be used in #if tests. + * + * First the information about the samples. + */ +#define PNG_IMAGE_SAMPLE_CHANNELS(fmt)\ + (((fmt)&(PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA))+1) + /* Return the total number of channels in a given format: 1..4 */ + +#define PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt)\ + ((((fmt) & PNG_FORMAT_FLAG_LINEAR) >> 2)+1) + /* Return the size in bytes of a single component of a pixel or color-map + * entry (as appropriate) in the image: 1 or 2. + */ + +#define PNG_IMAGE_SAMPLE_SIZE(fmt)\ + (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt)) + /* This is the size of the sample data for one sample. If the image is + * color-mapped it is the size of one color-map entry (and image pixels are + * one byte in size), otherwise it is the size of one image pixel. + */ + +#define PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(fmt)\ + (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * 256) + /* The maximum size of the color-map required by the format expressed in a + * count of components. This can be used to compile-time allocate a + * color-map: + * + * png_uint_16 colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(linear_fmt)]; + * + * png_byte colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(sRGB_fmt)]; + * + * Alternatively use the PNG_IMAGE_COLORMAP_SIZE macro below to use the + * information from one of the png_image_begin_read_ APIs and dynamically + * allocate the required memory. + */ + +/* Corresponding information about the pixels */ +#define PNG_IMAGE_PIXEL_(test,fmt)\ + (((fmt)&PNG_FORMAT_FLAG_COLORMAP)?1:test(fmt)) + +#define PNG_IMAGE_PIXEL_CHANNELS(fmt)\ + PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_CHANNELS,fmt) + /* The number of separate channels (components) in a pixel; 1 for a + * color-mapped image. + */ + +#define PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)\ + PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_COMPONENT_SIZE,fmt) + /* The size, in bytes, of each component in a pixel; 1 for a color-mapped + * image. + */ + +#define PNG_IMAGE_PIXEL_SIZE(fmt) PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_SIZE,fmt) + /* The size, in bytes, of a complete pixel; 1 for a color-mapped image. */ + +/* Information about the whole row, or whole image */ +#define PNG_IMAGE_ROW_STRIDE(image)\ + (PNG_IMAGE_PIXEL_CHANNELS((image).format) * (image).width) + /* Return the total number of components in a single row of the image; this + * is the minimum 'row stride', the minimum count of components between each + * row. For a color-mapped image this is the minimum number of bytes in a + * row. + * + * WARNING: this macro overflows for some images with more than one component + * and very large image widths. libpng will refuse to process an image where + * this macro would overflow. + */ + +#define PNG_IMAGE_BUFFER_SIZE(image, row_stride)\ + (PNG_IMAGE_PIXEL_COMPONENT_SIZE((image).format)*(image).height*(row_stride)) + /* Return the size, in bytes, of an image buffer given a png_image and a row + * stride - the number of components to leave space for in each row. + * + * WARNING: this macro overflows a 32-bit integer for some large PNG images, + * libpng will refuse to process an image where such an overflow would occur. + */ + +#define PNG_IMAGE_SIZE(image)\ + PNG_IMAGE_BUFFER_SIZE(image, PNG_IMAGE_ROW_STRIDE(image)) + /* Return the size, in bytes, of the image in memory given just a png_image; + * the row stride is the minimum stride required for the image. + */ + +#define PNG_IMAGE_COLORMAP_SIZE(image)\ + (PNG_IMAGE_SAMPLE_SIZE((image).format) * (image).colormap_entries) + /* Return the size, in bytes, of the color-map of this image. If the image + * format is not a color-map format this will return a size sufficient for + * 256 entries in the given format; check PNG_FORMAT_FLAG_COLORMAP if + * you don't want to allocate a color-map in this case. + */ + +/* PNG_IMAGE_FLAG_* + * + * Flags containing additional information about the image are held in the + * 'flags' field of png_image. + */ +#define PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB 0x01 + /* This indicates the the RGB values of the in-memory bitmap do not + * correspond to the red, green and blue end-points defined by sRGB. + */ + +#define PNG_IMAGE_FLAG_FAST 0x02 + /* On write emphasise speed over compression; the resultant PNG file will be + * larger but will be produced significantly faster, particular for large + * images. Do not use this option for images which will be distributed, only + * used it when producing intermediate files that will be read back in + * repeatedly. For a typical 24-bit image the option will double the read + * speed at the cost of increasing the image size by 25%, however for many + * more compressible images the PNG file can be 10 times larger with only a + * slight speed gain. + */ + +#define PNG_IMAGE_FLAG_16BIT_sRGB 0x04 + /* On read if the image is a 16-bit per component image and there is no gAMA + * or sRGB chunk assume that the components are sRGB encoded. Notice that + * images output by the simplified API always have gamma information; setting + * this flag only affects the interpretation of 16-bit images from an + * external source. It is recommended that the application expose this flag + * to the user; the user can normally easily recognize the difference between + * linear and sRGB encoding. This flag has no effect on write - the data + * passed to the write APIs must have the correct encoding (as defined + * above.) + * + * If the flag is not set (the default) input 16-bit per component data is + * assumed to be linear. + * + * NOTE: the flag can only be set after the png_image_begin_read_ call, + * because that call initializes the 'flags' field. + */ + +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +/* READ APIs + * --------- + * + * The png_image passed to the read APIs must have been initialized by setting + * the png_controlp field 'opaque' to NULL (or, safer, memset the whole thing.) + */ +#ifdef PNG_STDIO_SUPPORTED +PNG_EXPORT(234, int, png_image_begin_read_from_file, (png_imagep image, + const char *file_name)); + /* The named file is opened for read and the image header is filled in + * from the PNG header in the file. + */ + +PNG_EXPORT(235, int, png_image_begin_read_from_stdio, (png_imagep image, + FILE* file)); + /* The PNG header is read from the stdio FILE object. */ +#endif /* STDIO */ + +PNG_EXPORT(236, int, png_image_begin_read_from_memory, (png_imagep image, + png_const_voidp memory, png_size_t size)); + /* The PNG header is read from the given memory buffer. */ + +PNG_EXPORT(237, int, png_image_finish_read, (png_imagep image, + png_const_colorp background, void *buffer, png_int_32 row_stride, + void *colormap)); + /* Finish reading the image into the supplied buffer and clean up the + * png_image structure. + * + * row_stride is the step, in byte or 2-byte units as appropriate, + * between adjacent rows. A positive stride indicates that the top-most row + * is first in the buffer - the normal top-down arrangement. A negative + * stride indicates that the bottom-most row is first in the buffer. + * + * background need only be supplied if an alpha channel must be removed from + * a png_byte format and the removal is to be done by compositing on a solid + * color; otherwise it may be NULL and any composition will be done directly + * onto the buffer. The value is an sRGB color to use for the background, + * for grayscale output the green channel is used. + * + * background must be supplied when an alpha channel must be removed from a + * single byte color-mapped output format, in other words if: + * + * 1) The original format from png_image_begin_read_from_* had + * PNG_FORMAT_FLAG_ALPHA set. + * 2) The format set by the application does not. + * 3) The format set by the application has PNG_FORMAT_FLAG_COLORMAP set and + * PNG_FORMAT_FLAG_LINEAR *not* set. + * + * For linear output removing the alpha channel is always done by compositing + * on black and background is ignored. + * + * colormap must be supplied when PNG_FORMAT_FLAG_COLORMAP is set. It must + * be at least the size (in bytes) returned by PNG_IMAGE_COLORMAP_SIZE. + * image->colormap_entries will be updated to the actual number of entries + * written to the colormap; this may be less than the original value. + */ + +PNG_EXPORT(238, void, png_image_free, (png_imagep image)); + /* Free any data allocated by libpng in image->opaque, setting the pointer to + * NULL. May be called at any time after the structure is initialized. + */ +#endif /* SIMPLIFIED_READ */ + +#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED +/* WRITE APIS + * ---------- + * For write you must initialize a png_image structure to describe the image to + * be written. To do this use memset to set the whole structure to 0 then + * initialize fields describing your image. + * + * version: must be set to PNG_IMAGE_VERSION + * opaque: must be initialized to NULL + * width: image width in pixels + * height: image height in rows + * format: the format of the data (image and color-map) you wish to write + * flags: set to 0 unless one of the defined flags applies; set + * PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB for color format images where the RGB + * values do not correspond to the colors in sRGB. + * colormap_entries: set to the number of entries in the color-map (0 to 256) + */ +#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED +PNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image, + const char *file, int convert_to_8bit, const void *buffer, + png_int_32 row_stride, const void *colormap)); + /* Write the image to the named file. */ + +PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file, + int convert_to_8_bit, const void *buffer, png_int_32 row_stride, + const void *colormap)); + /* Write the image to the given (FILE*). */ +#endif /* SIMPLIFIED_WRITE_STDIO */ + +/* With all write APIs if image is in one of the linear formats with 16-bit + * data then setting convert_to_8_bit will cause the output to be an 8-bit PNG + * gamma encoded according to the sRGB specification, otherwise a 16-bit linear + * encoded PNG file is written. + * + * With color-mapped data formats the colormap parameter point to a color-map + * with at least image->colormap_entries encoded in the specified format. If + * the format is linear the written PNG color-map will be converted to sRGB + * regardless of the convert_to_8_bit flag. + * + * With all APIs row_stride is handled as in the read APIs - it is the spacing + * from one row to the next in component sized units (1 or 2 bytes) and if + * negative indicates a bottom-up row layout in the buffer. If row_stride is + * zero, libpng will calculate it for you from the image width and number of + * channels. + * + * Note that the write API does not support interlacing, sub-8-bit pixels or + * most ancillary chunks. If you need to write text chunks (e.g. for copyright + * notices) you need to use one of the other APIs. + */ + +PNG_EXPORT(245, int, png_image_write_to_memory, (png_imagep image, void *memory, + png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8_bit, + const void *buffer, png_int_32 row_stride, const void *colormap)); + /* Write the image to the given memory buffer. The function both writes the + * whole PNG data stream to *memory and updates *memory_bytes with the count + * of bytes written. + * + * 'memory' may be NULL. In this case *memory_bytes is not read however on + * success the number of bytes which would have been written will still be + * stored in *memory_bytes. On failure *memory_bytes will contain 0. + * + * If 'memory' is not NULL it must point to memory[*memory_bytes] of + * writeable memory. + * + * If the function returns success memory[*memory_bytes] (if 'memory' is not + * NULL) contains the written PNG data. *memory_bytes will always be less + * than or equal to the original value. + * + * If the function returns false and *memory_bytes was not changed an error + * occured during write. If *memory_bytes was changed, or is not 0 if + * 'memory' was NULL, the write would have succeeded but for the memory + * buffer being too small. *memory_bytes contains the required number of + * bytes and will be bigger that the original value. + */ + +#define png_image_write_get_memory_size(image, size, convert_to_8_bit, buffer,\ + row_stride, colormap)\ + png_image_write_to_memory(&(image), 0, &(size), convert_to_8_bit, buffer,\ + row_stride, colormap) + /* Return the amount of memory in 'size' required to compress this image. + * The png_image structure 'image' must be filled in as in the above + * function and must not be changed before the actual write call, the buffer + * and all other parameters must also be identical to that in the final + * write call. The 'size' variable need not be initialized. + * + * NOTE: the macro returns true/false, if false is returned 'size' will be + * set to zero and the write failed and probably will fail if tried again. + */ + +/* You can pre-allocate the buffer by making sure it is of sufficient size + * regardless of the amount of compression achieved. The buffer size will + * always be bigger than the original image and it will never be filled. The + * following macros are provided to assist in allocating the buffer. + */ +#define PNG_IMAGE_DATA_SIZE(image) (PNG_IMAGE_SIZE(image)+(image).height) + /* The number of uncompressed bytes in the PNG byte encoding of the image; + * uncompressing the PNG IDAT data will give this number of bytes. + * + * NOTE: while PNG_IMAGE_SIZE cannot overflow for an image in memory this + * macro can because of the extra bytes used in the PNG byte encoding. You + * need to avoid this macro if your image size approaches 2^30 in width or + * height. The same goes for the remainder of these macros; they all produce + * bigger numbers than the actual in-memory image size. + */ +#ifndef PNG_ZLIB_MAX_SIZE +# define PNG_ZLIB_MAX_SIZE(b) ((b)+(((b)+7U)>>3)+(((b)+63U)>>6)+11U) + /* An upper bound on the number of compressed bytes given 'b' uncompressed + * bytes. This is based on deflateBounds() in zlib; different + * implementations of zlib compression may conceivably produce more data so + * if your zlib implementation is not zlib itself redefine this macro + * appropriately. + */ +#endif + +#define PNG_IMAGE_COMPRESSED_SIZE_MAX(image)\ + PNG_ZLIB_MAX_SIZE((png_alloc_size_t)PNG_IMAGE_DATA_SIZE(image)) + /* An upper bound on the size of the data in the PNG IDAT chunks. */ + +#define PNG_IMAGE_PNG_SIZE_MAX_(image, image_size)\ + ((8U/*sig*/+25U/*IHDR*/+16U/*gAMA*/+44U/*cHRM*/+12U/*IEND*/+\ + (((image).format&PNG_FORMAT_FLAG_COLORMAP)?/*colormap: PLTE, tRNS*/\ + 12U+3U*(image).colormap_entries/*PLTE data*/+\ + (((image).format&PNG_FORMAT_FLAG_ALPHA)?\ + 12U/*tRNS*/+(image).colormap_entries:0U):0U)+\ + 12U)+(12U*((image_size)/PNG_ZBUF_SIZE))/*IDAT*/+(image_size)) + /* A helper for the following macro; if your compiler cannot handle the + * following macro use this one with the result of + * PNG_IMAGE_COMPRESSED_SIZE_MAX(image) as the second argument (most + * compilers should handle this just fine.) + */ + +#define PNG_IMAGE_PNG_SIZE_MAX(image)\ + PNG_IMAGE_PNG_SIZE_MAX_(image, PNG_IMAGE_COMPRESSED_SIZE_MAX(image)) + /* An upper bound on the total length of the PNG data stream for 'image'. + * The result is of type png_alloc_size_t, on 32-bit systems this may + * overflow even though PNG_IMAGE_DATA_SIZE does not overflow; the write will + * run out of buffer space but return a corrected size which should work. + */ +#endif /* SIMPLIFIED_WRITE */ +/******************************************************************************* + * END OF SIMPLIFIED API + ******************************************************************************/ +#endif /* SIMPLIFIED_{READ|WRITE} */ + +/******************************************************************************* + * Section 6: IMPLEMENTATION OPTIONS + ******************************************************************************* + * + * Support for arbitrary implementation-specific optimizations. The API allows + * particular options to be turned on or off. 'Option' is the number of the + * option and 'onoff' is 0 (off) or non-0 (on). The value returned is given + * by the PNG_OPTION_ defines below. + * + * HARDWARE: normally hardware capabilites, such as the Intel SSE instructions, + * are detected at run time, however sometimes it may be impossible + * to do this in user mode, in which case it is necessary to discover + * the capabilities in an OS specific way. Such capabilities are + * listed here when libpng has support for them and must be turned + * ON by the application if present. + * + * SOFTWARE: sometimes software optimizations actually result in performance + * decrease on some architectures or systems, or with some sets of + * PNG images. 'Software' options allow such optimizations to be + * selected at run time. + */ +#ifdef PNG_SET_OPTION_SUPPORTED +#ifdef PNG_ARM_NEON_API_SUPPORTED +# define PNG_ARM_NEON 0 /* HARDWARE: ARM Neon SIMD instructions supported */ +#endif +#define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */ +#define PNG_SKIP_sRGB_CHECK_PROFILE 4 /* SOFTWARE: Check ICC profile for sRGB */ +#define PNG_OPTION_NEXT 6 /* Next option - numbers must be even */ + +/* Return values: NOTE: there are four values and 'off' is *not* zero */ +#define PNG_OPTION_UNSET 0 /* Unset - defaults to off */ +#define PNG_OPTION_INVALID 1 /* Option number out of range */ +#define PNG_OPTION_OFF 2 +#define PNG_OPTION_ON 3 + +PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option, + int onoff)); +#endif /* SET_OPTION */ + +/******************************************************************************* + * END OF HARDWARE AND SOFTWARE OPTIONS + ******************************************************************************/ + +/* Maintainer: Put new public prototypes here ^, in libpng.3, in project + * defs, and in scripts/symbols.def. + */ + +/* The last ordinal number (this is the *last* one already used; the next + * one to use is one more than this.) + */ +#ifdef PNG_EXPORT_LAST_ORDINAL + PNG_EXPORT_LAST_ORDINAL(245); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PNG_VERSION_INFO_ONLY */ +/* Do not put anything past this line */ +#endif /* PNG_H */ diff --git a/source/Irrlicht/libpng/pngbar.jpg b/source/Irrlicht/libpng/pngbar.jpg new file mode 100644 index 00000000..70ba8d81 Binary files /dev/null and b/source/Irrlicht/libpng/pngbar.jpg differ diff --git a/source/Irrlicht/libpng/pngbar.png b/source/Irrlicht/libpng/pngbar.png new file mode 100644 index 00000000..49798c8e Binary files /dev/null and b/source/Irrlicht/libpng/pngbar.png differ diff --git a/source/Irrlicht/libpng/pngconf.h b/source/Irrlicht/libpng/pngconf.h new file mode 100644 index 00000000..058bcf67 --- /dev/null +++ b/source/Irrlicht/libpng/pngconf.h @@ -0,0 +1,622 @@ + +/* pngconf.h - machine configurable file for libpng + * + * libpng version 1.6.23, June 9, 2016 + * + * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * Any machine specific code is near the front of this file, so if you + * are configuring libpng for a machine, you may want to read the section + * starting here down to where it starts to typedef png_color, png_text, + * and png_info. + */ + +#ifndef PNGCONF_H +#define PNGCONF_H + +#ifndef PNG_BUILDING_SYMBOL_TABLE /* else includes may cause problems */ + +/* From libpng 1.6.0 libpng requires an ANSI X3.159-1989 ("ISOC90") compliant C + * compiler for correct compilation. The following header files are required by + * the standard. If your compiler doesn't provide these header files, or they + * do not match the standard, you will need to provide/improve them. + */ +#include +#include + +/* Library header files. These header files are all defined by ISOC90; libpng + * expects conformant implementations, however, an ISOC90 conformant system need + * not provide these header files if the functionality cannot be implemented. + * In this case it will be necessary to disable the relevant parts of libpng in + * the build of pnglibconf.h. + * + * Prior to 1.6.0 string.h was included here; the API changes in 1.6.0 to not + * include this unnecessary header file. + */ + +#ifdef PNG_STDIO_SUPPORTED + /* Required for the definition of FILE: */ +# include +#endif + +#ifdef PNG_SETJMP_SUPPORTED + /* Required for the definition of jmp_buf and the declaration of longjmp: */ +# include +#endif + +#ifdef PNG_CONVERT_tIME_SUPPORTED + /* Required for struct tm: */ +# include +#endif + +#endif /* PNG_BUILDING_SYMBOL_TABLE */ + +/* Prior to 1.6.0 it was possible to turn off 'const' in declarations using + * PNG_NO_CONST; this is no longer supported except for data declarations which + * apparently still cause problems in 2011 on some compilers. + */ +#define PNG_CONST const /* backward compatibility only */ + +/* This controls optimization of the reading of 16-bit and 32-bit values + * from PNG files. It can be set on a per-app-file basis - it + * just changes whether a macro is used when the function is called. + * The library builder sets the default; if read functions are not + * built into the library the macro implementation is forced on. + */ +#ifndef PNG_READ_INT_FUNCTIONS_SUPPORTED +# define PNG_USE_READ_MACROS +#endif +#if !defined(PNG_NO_USE_READ_MACROS) && !defined(PNG_USE_READ_MACROS) +# if PNG_DEFAULT_READ_MACROS +# define PNG_USE_READ_MACROS +# endif +#endif + +/* COMPILER SPECIFIC OPTIONS. + * + * These options are provided so that a variety of difficult compilers + * can be used. Some are fixed at build time (e.g. PNG_API_RULE + * below) but still have compiler specific implementations, others + * may be changed on a per-file basis when compiling against libpng. + */ + +/* The PNGARG macro was used in versions of libpng prior to 1.6.0 to protect + * against legacy (pre ISOC90) compilers that did not understand function + * prototypes. It is not required for modern C compilers. + */ +#ifndef PNGARG +# define PNGARG(arglist) arglist +#endif + +/* Function calling conventions. + * ============================= + * Normally it is not necessary to specify to the compiler how to call + * a function - it just does it - however on x86 systems derived from + * Microsoft and Borland C compilers ('IBM PC', 'DOS', 'Windows' systems + * and some others) there are multiple ways to call a function and the + * default can be changed on the compiler command line. For this reason + * libpng specifies the calling convention of every exported function and + * every function called via a user supplied function pointer. This is + * done in this file by defining the following macros: + * + * PNGAPI Calling convention for exported functions. + * PNGCBAPI Calling convention for user provided (callback) functions. + * PNGCAPI Calling convention used by the ANSI-C library (required + * for longjmp callbacks and sometimes used internally to + * specify the calling convention for zlib). + * + * These macros should never be overridden. If it is necessary to + * change calling convention in a private build this can be done + * by setting PNG_API_RULE (which defaults to 0) to one of the values + * below to select the correct 'API' variants. + * + * PNG_API_RULE=0 Use PNGCAPI - the 'C' calling convention - throughout. + * This is correct in every known environment. + * PNG_API_RULE=1 Use the operating system convention for PNGAPI and + * the 'C' calling convention (from PNGCAPI) for + * callbacks (PNGCBAPI). This is no longer required + * in any known environment - if it has to be used + * please post an explanation of the problem to the + * libpng mailing list. + * + * These cases only differ if the operating system does not use the C + * calling convention, at present this just means the above cases + * (x86 DOS/Windows sytems) and, even then, this does not apply to + * Cygwin running on those systems. + * + * Note that the value must be defined in pnglibconf.h so that what + * the application uses to call the library matches the conventions + * set when building the library. + */ + +/* Symbol export + * ============= + * When building a shared library it is almost always necessary to tell + * the compiler which symbols to export. The png.h macro 'PNG_EXPORT' + * is used to mark the symbols. On some systems these symbols can be + * extracted at link time and need no special processing by the compiler, + * on other systems the symbols are flagged by the compiler and just + * the declaration requires a special tag applied (unfortunately) in a + * compiler dependent way. Some systems can do either. + * + * A small number of older systems also require a symbol from a DLL to + * be flagged to the program that calls it. This is a problem because + * we do not know in the header file included by application code that + * the symbol will come from a shared library, as opposed to a statically + * linked one. For this reason the application must tell us by setting + * the magic flag PNG_USE_DLL to turn on the special processing before + * it includes png.h. + * + * Four additional macros are used to make this happen: + * + * PNG_IMPEXP The magic (if any) to cause a symbol to be exported from + * the build or imported if PNG_USE_DLL is set - compiler + * and system specific. + * + * PNG_EXPORT_TYPE(type) A macro that pre or appends PNG_IMPEXP to + * 'type', compiler specific. + * + * PNG_DLL_EXPORT Set to the magic to use during a libpng build to + * make a symbol exported from the DLL. Not used in the + * public header files; see pngpriv.h for how it is used + * in the libpng build. + * + * PNG_DLL_IMPORT Set to the magic to force the libpng symbols to come + * from a DLL - used to define PNG_IMPEXP when + * PNG_USE_DLL is set. + */ + +/* System specific discovery. + * ========================== + * This code is used at build time to find PNG_IMPEXP, the API settings + * and PNG_EXPORT_TYPE(), it may also set a macro to indicate the DLL + * import processing is possible. On Windows systems it also sets + * compiler-specific macros to the values required to change the calling + * conventions of the various functions. + */ +#if defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\ + defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) + /* Windows system (DOS doesn't support DLLs). Includes builds under Cygwin or + * MinGW on any architecture currently supported by Windows. Also includes + * Watcom builds but these need special treatment because they are not + * compatible with GCC or Visual C because of different calling conventions. + */ +# if PNG_API_RULE == 2 + /* If this line results in an error, either because __watcall is not + * understood or because of a redefine just below you cannot use *this* + * build of the library with the compiler you are using. *This* build was + * build using Watcom and applications must also be built using Watcom! + */ +# define PNGCAPI __watcall +# endif + +# if defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER >= 800)) +# define PNGCAPI __cdecl +# if PNG_API_RULE == 1 + /* If this line results in an error __stdcall is not understood and + * PNG_API_RULE should not have been set to '1'. + */ +# define PNGAPI __stdcall +# endif +# else + /* An older compiler, or one not detected (erroneously) above, + * if necessary override on the command line to get the correct + * variants for the compiler. + */ +# ifndef PNGCAPI +# define PNGCAPI _cdecl +# endif +# if PNG_API_RULE == 1 && !defined(PNGAPI) +# define PNGAPI _stdcall +# endif +# endif /* compiler/api */ + + /* NOTE: PNGCBAPI always defaults to PNGCAPI. */ + +# if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD) +# error "PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed" +# endif + +# if (defined(_MSC_VER) && _MSC_VER < 800) ||\ + (defined(__BORLANDC__) && __BORLANDC__ < 0x500) + /* older Borland and MSC + * compilers used '__export' and required this to be after + * the type. + */ +# ifndef PNG_EXPORT_TYPE +# define PNG_EXPORT_TYPE(type) type PNG_IMPEXP +# endif +# define PNG_DLL_EXPORT __export +# else /* newer compiler */ +# define PNG_DLL_EXPORT __declspec(dllexport) +# ifndef PNG_DLL_IMPORT +# define PNG_DLL_IMPORT __declspec(dllimport) +# endif +# endif /* compiler */ + +#else /* !Windows */ +# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__) +# define PNGAPI _System +# else /* !Windows/x86 && !OS/2 */ + /* Use the defaults, or define PNG*API on the command line (but + * this will have to be done for every compile!) + */ +# endif /* other system, !OS/2 */ +#endif /* !Windows/x86 */ + +/* Now do all the defaulting . */ +#ifndef PNGCAPI +# define PNGCAPI +#endif +#ifndef PNGCBAPI +# define PNGCBAPI PNGCAPI +#endif +#ifndef PNGAPI +# define PNGAPI PNGCAPI +#endif + +/* PNG_IMPEXP may be set on the compilation system command line or (if not set) + * then in an internal header file when building the library, otherwise (when + * using the library) it is set here. + */ +#ifndef PNG_IMPEXP +# if defined(PNG_USE_DLL) && defined(PNG_DLL_IMPORT) + /* This forces use of a DLL, disallowing static linking */ +# define PNG_IMPEXP PNG_DLL_IMPORT +# endif + +# ifndef PNG_IMPEXP +# define PNG_IMPEXP +# endif +#endif + +/* In 1.5.2 the definition of PNG_FUNCTION has been changed to always treat + * 'attributes' as a storage class - the attributes go at the start of the + * function definition, and attributes are always appended regardless of the + * compiler. This considerably simplifies these macros but may cause problems + * if any compilers both need function attributes and fail to handle them as + * a storage class (this is unlikely.) + */ +#ifndef PNG_FUNCTION +# define PNG_FUNCTION(type, name, args, attributes) attributes type name args +#endif + +#ifndef PNG_EXPORT_TYPE +# define PNG_EXPORT_TYPE(type) PNG_IMPEXP type +#endif + + /* The ordinal value is only relevant when preprocessing png.h for symbol + * table entries, so we discard it here. See the .dfn files in the + * scripts directory. + */ + +#ifndef PNG_EXPORTA +# define PNG_EXPORTA(ordinal, type, name, args, attributes) \ + PNG_FUNCTION(PNG_EXPORT_TYPE(type), (PNGAPI name), PNGARG(args), \ + PNG_LINKAGE_API attributes) +#endif + +/* ANSI-C (C90) does not permit a macro to be invoked with an empty argument, + * so make something non-empty to satisfy the requirement: + */ +#define PNG_EMPTY /*empty list*/ + +#define PNG_EXPORT(ordinal, type, name, args) \ + PNG_EXPORTA(ordinal, type, name, args, PNG_EMPTY) + +/* Use PNG_REMOVED to comment out a removed interface. */ +#ifndef PNG_REMOVED +# define PNG_REMOVED(ordinal, type, name, args, attributes) +#endif + +#ifndef PNG_CALLBACK +# define PNG_CALLBACK(type, name, args) type (PNGCBAPI name) PNGARG(args) +#endif + +/* Support for compiler specific function attributes. These are used + * so that where compiler support is available incorrect use of API + * functions in png.h will generate compiler warnings. + * + * Added at libpng-1.2.41. + */ + +#ifndef PNG_NO_PEDANTIC_WARNINGS +# ifndef PNG_PEDANTIC_WARNINGS_SUPPORTED +# define PNG_PEDANTIC_WARNINGS_SUPPORTED +# endif +#endif + +#ifdef PNG_PEDANTIC_WARNINGS_SUPPORTED + /* Support for compiler specific function attributes. These are used + * so that where compiler support is available, incorrect use of API + * functions in png.h will generate compiler warnings. Added at libpng + * version 1.2.41. Disabling these removes the warnings but may also produce + * less efficient code. + */ +# if defined(__clang__) && defined(__has_attribute) + /* Clang defines both __clang__ and __GNUC__. Check __clang__ first. */ +# if !defined(PNG_USE_RESULT) && __has_attribute(__warn_unused_result__) +# define PNG_USE_RESULT __attribute__((__warn_unused_result__)) +# endif +# if !defined(PNG_NORETURN) && __has_attribute(__noreturn__) +# define PNG_NORETURN __attribute__((__noreturn__)) +# endif +# if !defined(PNG_ALLOCATED) && __has_attribute(__malloc__) +# define PNG_ALLOCATED __attribute__((__malloc__)) +# endif +# if !defined(PNG_DEPRECATED) && __has_attribute(__deprecated__) +# define PNG_DEPRECATED __attribute__((__deprecated__)) +# endif +# if !defined(PNG_PRIVATE) +# ifdef __has_extension +# if __has_extension(attribute_unavailable_with_message) +# define PNG_PRIVATE __attribute__((__unavailable__(\ + "This function is not exported by libpng."))) +# endif +# endif +# endif +# ifndef PNG_RESTRICT +# define PNG_RESTRICT __restrict +# endif + +# elif defined(__GNUC__) +# ifndef PNG_USE_RESULT +# define PNG_USE_RESULT __attribute__((__warn_unused_result__)) +# endif +# ifndef PNG_NORETURN +# define PNG_NORETURN __attribute__((__noreturn__)) +# endif +# if __GNUC__ >= 3 +# ifndef PNG_ALLOCATED +# define PNG_ALLOCATED __attribute__((__malloc__)) +# endif +# ifndef PNG_DEPRECATED +# define PNG_DEPRECATED __attribute__((__deprecated__)) +# endif +# ifndef PNG_PRIVATE +# if 0 /* Doesn't work so we use deprecated instead*/ +# define PNG_PRIVATE \ + __attribute__((warning("This function is not exported by libpng."))) +# else +# define PNG_PRIVATE \ + __attribute__((__deprecated__)) +# endif +# endif +# if ((__GNUC__ > 3) || !defined(__GNUC_MINOR__) || (__GNUC_MINOR__ >= 1)) +# ifndef PNG_RESTRICT +# define PNG_RESTRICT __restrict +# endif +# endif /* __GNUC__.__GNUC_MINOR__ > 3.0 */ +# endif /* __GNUC__ >= 3 */ + +# elif defined(_MSC_VER) && (_MSC_VER >= 1300) +# ifndef PNG_USE_RESULT +# define PNG_USE_RESULT /* not supported */ +# endif +# ifndef PNG_NORETURN +# define PNG_NORETURN __declspec(noreturn) +# endif +# ifndef PNG_ALLOCATED +# if (_MSC_VER >= 1400) +# define PNG_ALLOCATED __declspec(restrict) +# endif +# endif +# ifndef PNG_DEPRECATED +# define PNG_DEPRECATED __declspec(deprecated) +# endif +# ifndef PNG_PRIVATE +# define PNG_PRIVATE __declspec(deprecated) +# endif +# ifndef PNG_RESTRICT +# if (_MSC_VER >= 1400) +# define PNG_RESTRICT __restrict +# endif +# endif + +# elif defined(__WATCOMC__) +# ifndef PNG_RESTRICT +# define PNG_RESTRICT __restrict +# endif +# endif +#endif /* PNG_PEDANTIC_WARNINGS */ + +#ifndef PNG_DEPRECATED +# define PNG_DEPRECATED /* Use of this function is deprecated */ +#endif +#ifndef PNG_USE_RESULT +# define PNG_USE_RESULT /* The result of this function must be checked */ +#endif +#ifndef PNG_NORETURN +# define PNG_NORETURN /* This function does not return */ +#endif +#ifndef PNG_ALLOCATED +# define PNG_ALLOCATED /* The result of the function is new memory */ +#endif +#ifndef PNG_PRIVATE +# define PNG_PRIVATE /* This is a private libpng function */ +#endif +#ifndef PNG_RESTRICT +# define PNG_RESTRICT /* The C99 "restrict" feature */ +#endif + +#ifndef PNG_FP_EXPORT /* A floating point API. */ +# ifdef PNG_FLOATING_POINT_SUPPORTED +# define PNG_FP_EXPORT(ordinal, type, name, args)\ + PNG_EXPORT(ordinal, type, name, args); +# else /* No floating point APIs */ +# define PNG_FP_EXPORT(ordinal, type, name, args) +# endif +#endif +#ifndef PNG_FIXED_EXPORT /* A fixed point API. */ +# ifdef PNG_FIXED_POINT_SUPPORTED +# define PNG_FIXED_EXPORT(ordinal, type, name, args)\ + PNG_EXPORT(ordinal, type, name, args); +# else /* No fixed point APIs */ +# define PNG_FIXED_EXPORT(ordinal, type, name, args) +# endif +#endif + +#ifndef PNG_BUILDING_SYMBOL_TABLE +/* Some typedefs to get us started. These should be safe on most of the common + * platforms. + * + * png_uint_32 and png_int_32 may, currently, be larger than required to hold a + * 32-bit value however this is not normally advisable. + * + * png_uint_16 and png_int_16 should always be two bytes in size - this is + * verified at library build time. + * + * png_byte must always be one byte in size. + * + * The checks below use constants from limits.h, as defined by the ISOC90 + * standard. + */ +#if CHAR_BIT == 8 && UCHAR_MAX == 255 + typedef unsigned char png_byte; +#else +# error "libpng requires 8-bit bytes" +#endif + +#if INT_MIN == -32768 && INT_MAX == 32767 + typedef int png_int_16; +#elif SHRT_MIN == -32768 && SHRT_MAX == 32767 + typedef short png_int_16; +#else +# error "libpng requires a signed 16-bit type" +#endif + +#if UINT_MAX == 65535 + typedef unsigned int png_uint_16; +#elif USHRT_MAX == 65535 + typedef unsigned short png_uint_16; +#else +# error "libpng requires an unsigned 16-bit type" +#endif + +#if INT_MIN < -2147483646 && INT_MAX > 2147483646 + typedef int png_int_32; +#elif LONG_MIN < -2147483646 && LONG_MAX > 2147483646 + typedef long int png_int_32; +#else +# error "libpng requires a signed 32-bit (or more) type" +#endif + +#if UINT_MAX > 4294967294 + typedef unsigned int png_uint_32; +#elif ULONG_MAX > 4294967294 + typedef unsigned long int png_uint_32; +#else +# error "libpng requires an unsigned 32-bit (or more) type" +#endif + +/* Prior to 1.6.0 it was possible to disable the use of size_t, 1.6.0, however, + * requires an ISOC90 compiler and relies on consistent behavior of sizeof. + */ +typedef size_t png_size_t; +typedef ptrdiff_t png_ptrdiff_t; + +/* libpng needs to know the maximum value of 'size_t' and this controls the + * definition of png_alloc_size_t, below. This maximum value of size_t limits + * but does not control the maximum allocations the library makes - there is + * direct application control of this through png_set_user_limits(). + */ +#ifndef PNG_SMALL_SIZE_T + /* Compiler specific tests for systems where size_t is known to be less than + * 32 bits (some of these systems may no longer work because of the lack of + * 'far' support; see above.) + */ +# if (defined(__TURBOC__) && !defined(__FLAT__)) ||\ + (defined(_MSC_VER) && defined(MAXSEG_64K)) +# define PNG_SMALL_SIZE_T +# endif +#endif + +/* png_alloc_size_t is guaranteed to be no smaller than png_size_t, and no + * smaller than png_uint_32. Casts from png_size_t or png_uint_32 to + * png_alloc_size_t are not necessary; in fact, it is recommended not to use + * them at all so that the compiler can complain when something turns out to be + * problematic. + * + * Casts in the other direction (from png_alloc_size_t to png_size_t or + * png_uint_32) should be explicitly applied; however, we do not expect to + * encounter practical situations that require such conversions. + * + * PNG_SMALL_SIZE_T must be defined if the maximum value of size_t is less than + * 4294967295 - i.e. less than the maximum value of png_uint_32. + */ +#ifdef PNG_SMALL_SIZE_T + typedef png_uint_32 png_alloc_size_t; +#else + typedef png_size_t png_alloc_size_t; +#endif + +/* Prior to 1.6.0 libpng offered limited support for Microsoft C compiler + * implementations of Intel CPU specific support of user-mode segmented address + * spaces, where 16-bit pointers address more than 65536 bytes of memory using + * separate 'segment' registers. The implementation requires two different + * types of pointer (only one of which includes the segment value.) + * + * If required this support is available in version 1.2 of libpng and may be + * available in versions through 1.5, although the correctness of the code has + * not been verified recently. + */ + +/* Typedef for floating-point numbers that are converted to fixed-point with a + * multiple of 100,000, e.g., gamma + */ +typedef png_int_32 png_fixed_point; + +/* Add typedefs for pointers */ +typedef void * png_voidp; +typedef const void * png_const_voidp; +typedef png_byte * png_bytep; +typedef const png_byte * png_const_bytep; +typedef png_uint_32 * png_uint_32p; +typedef const png_uint_32 * png_const_uint_32p; +typedef png_int_32 * png_int_32p; +typedef const png_int_32 * png_const_int_32p; +typedef png_uint_16 * png_uint_16p; +typedef const png_uint_16 * png_const_uint_16p; +typedef png_int_16 * png_int_16p; +typedef const png_int_16 * png_const_int_16p; +typedef char * png_charp; +typedef const char * png_const_charp; +typedef png_fixed_point * png_fixed_point_p; +typedef const png_fixed_point * png_const_fixed_point_p; +typedef png_size_t * png_size_tp; +typedef const png_size_t * png_const_size_tp; + +#ifdef PNG_STDIO_SUPPORTED +typedef FILE * png_FILE_p; +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double * png_doublep; +typedef const double * png_const_doublep; +#endif + +/* Pointers to pointers; i.e. arrays */ +typedef png_byte * * png_bytepp; +typedef png_uint_32 * * png_uint_32pp; +typedef png_int_32 * * png_int_32pp; +typedef png_uint_16 * * png_uint_16pp; +typedef png_int_16 * * png_int_16pp; +typedef const char * * png_const_charpp; +typedef char * * png_charpp; +typedef png_fixed_point * * png_fixed_point_pp; +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double * * png_doublepp; +#endif + +/* Pointers to pointers to pointers; i.e., pointer to array */ +typedef char * * * png_charppp; + +#endif /* PNG_BUILDING_SYMBOL_TABLE */ + +#endif /* PNGCONF_H */ diff --git a/source/Irrlicht/libpng/pngdebug.h b/source/Irrlicht/libpng/pngdebug.h new file mode 100644 index 00000000..3d1e78c1 --- /dev/null +++ b/source/Irrlicht/libpng/pngdebug.h @@ -0,0 +1,153 @@ + +/* pngdebug.h - Debugging macros for libpng, also used in pngtest.c + * + * Last changed in libpng 1.6.8 [December 19, 2013] + * Copyright (c) 1998-2002,2004,2006-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +/* Define PNG_DEBUG at compile time for debugging information. Higher + * numbers for PNG_DEBUG mean more debugging information. This has + * only been added since version 0.95 so it is not implemented throughout + * libpng yet, but more support will be added as needed. + * + * png_debug[1-2]?(level, message ,arg{0-2}) + * Expands to a statement (either a simple expression or a compound + * do..while(0) statement) that outputs a message with parameter + * substitution if PNG_DEBUG is defined to 2 or more. If PNG_DEBUG + * is undefined, 0 or 1 every png_debug expands to a simple expression + * (actually ((void)0)). + * + * level: level of detail of message, starting at 0. A level 'n' + * message is preceded by 'n' 3-space indentations (not implemented + * on Microsoft compilers unless PNG_DEBUG_FILE is also + * defined, to allow debug DLL compilation with no standard IO). + * message: a printf(3) style text string. A trailing '\n' is added + * to the message. + * arg: 0 to 2 arguments for printf(3) style substitution in message. + */ +#ifndef PNGDEBUG_H +#define PNGDEBUG_H +/* These settings control the formatting of messages in png.c and pngerror.c */ +/* Moved to pngdebug.h at 1.5.0 */ +# ifndef PNG_LITERAL_SHARP +# define PNG_LITERAL_SHARP 0x23 +# endif +# ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET +# define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b +# endif +# ifndef PNG_LITERAL_RIGHT_SQUARE_BRACKET +# define PNG_LITERAL_RIGHT_SQUARE_BRACKET 0x5d +# endif +# ifndef PNG_STRING_NEWLINE +# define PNG_STRING_NEWLINE "\n" +# endif + +#ifdef PNG_DEBUG +# if (PNG_DEBUG > 0) +# if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER) +# include +# if (PNG_DEBUG > 1) +# ifndef _DEBUG +# define _DEBUG +# endif +# ifndef png_debug +# define png_debug(l,m) _RPT0(_CRT_WARN,m PNG_STRING_NEWLINE) +# endif +# ifndef png_debug1 +# define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m PNG_STRING_NEWLINE,p1) +# endif +# ifndef png_debug2 +# define png_debug2(l,m,p1,p2) \ + _RPT2(_CRT_WARN,m PNG_STRING_NEWLINE,p1,p2) +# endif +# endif +# else /* PNG_DEBUG_FILE || !_MSC_VER */ +# ifndef PNG_STDIO_SUPPORTED +# include /* not included yet */ +# endif +# ifndef PNG_DEBUG_FILE +# define PNG_DEBUG_FILE stderr +# endif /* PNG_DEBUG_FILE */ + +# if (PNG_DEBUG > 1) +# ifdef __STDC__ +# ifndef png_debug +# define png_debug(l,m) \ + do { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \ + (num_tabs==2 ? " " : (num_tabs>2 ? " " : "")))); \ + } while (0) +# endif +# ifndef png_debug1 +# define png_debug1(l,m,p1) \ + do { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \ + (num_tabs==2 ? " " : (num_tabs>2 ? " " : ""))),p1); \ + } while (0) +# endif +# ifndef png_debug2 +# define png_debug2(l,m,p1,p2) \ + do { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \ + (num_tabs==2 ? " " : (num_tabs>2 ? " " : ""))),p1,p2);\ + } while (0) +# endif +# else /* __STDC __ */ +# ifndef png_debug +# define png_debug(l,m) \ + do { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format); \ + } while (0) +# endif +# ifndef png_debug1 +# define png_debug1(l,m,p1) \ + do { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format,p1); \ + } while (0) +# endif +# ifndef png_debug2 +# define png_debug2(l,m,p1,p2) \ + do { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format,p1,p2); \ + } while (0) +# endif +# endif /* __STDC __ */ +# endif /* (PNG_DEBUG > 1) */ + +# endif /* _MSC_VER */ +# endif /* (PNG_DEBUG > 0) */ +#endif /* PNG_DEBUG */ +#ifndef png_debug +# define png_debug(l, m) ((void)0) +#endif +#ifndef png_debug1 +# define png_debug1(l, m, p1) ((void)0) +#endif +#ifndef png_debug2 +# define png_debug2(l, m, p1, p2) ((void)0) +#endif +#endif /* PNGDEBUG_H */ diff --git a/source/Irrlicht/libpng/pngerror.c b/source/Irrlicht/libpng/pngerror.c new file mode 100644 index 00000000..3e5f33f7 --- /dev/null +++ b/source/Irrlicht/libpng/pngerror.c @@ -0,0 +1,963 @@ + +/* pngerror.c - stub functions for i/o and memory allocation + * + * Last changed in libpng 1.6.15 [November 20, 2014] + * Copyright (c) 1998-2002,2004,2006-2014 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all error handling. Users who + * need special error handling are expected to write replacement functions + * and use png_set_error_fn() to use those functions. See the instructions + * at each function. + */ + +#include "pngpriv.h" + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + +static PNG_FUNCTION(void, png_default_error,PNGARG((png_const_structrp png_ptr, + png_const_charp error_message)),PNG_NORETURN); + +#ifdef PNG_WARNINGS_SUPPORTED +static void /* PRIVATE */ +png_default_warning PNGARG((png_const_structrp png_ptr, + png_const_charp warning_message)); +#endif /* WARNINGS */ + +/* This function is called whenever there is a fatal error. This function + * should not be changed. If there is a need to handle errors differently, + * you should supply a replacement error function and use png_set_error_fn() + * to replace the error function at run-time. + */ +#ifdef PNG_ERROR_TEXT_SUPPORTED +PNG_FUNCTION(void,PNGAPI +png_error,(png_const_structrp png_ptr, png_const_charp error_message), + PNG_NORETURN) +{ +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + char msg[16]; + if (png_ptr != NULL) + { + if ((png_ptr->flags & + (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0) + { + if (*error_message == PNG_LITERAL_SHARP) + { + /* Strip "#nnnn " from beginning of error message. */ + int offset; + for (offset = 1; offset<15; offset++) + if (error_message[offset] == ' ') + break; + + if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0) + { + int i; + for (i = 0; i < offset - 1; i++) + msg[i] = error_message[i + 1]; + msg[i - 1] = '\0'; + error_message = msg; + } + + else + error_message += offset; + } + + else + { + if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0) + { + msg[0] = '0'; + msg[1] = '\0'; + error_message = msg; + } + } + } + } +#endif + if (png_ptr != NULL && png_ptr->error_fn != NULL) + (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), + error_message); + + /* If the custom handler doesn't exist, or if it returns, + use the default handler, which will not return. */ + png_default_error(png_ptr, error_message); +} +#else +PNG_FUNCTION(void,PNGAPI +png_err,(png_const_structrp png_ptr),PNG_NORETURN) +{ + /* Prior to 1.5.2 the error_fn received a NULL pointer, expressed + * erroneously as '\0', instead of the empty string "". This was + * apparently an error, introduced in libpng-1.2.20, and png_default_error + * will crash in this case. + */ + if (png_ptr != NULL && png_ptr->error_fn != NULL) + (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), ""); + + /* If the custom handler doesn't exist, or if it returns, + use the default handler, which will not return. */ + png_default_error(png_ptr, ""); +} +#endif /* ERROR_TEXT */ + +/* Utility to safely appends strings to a buffer. This never errors out so + * error checking is not required in the caller. + */ +size_t +png_safecat(png_charp buffer, size_t bufsize, size_t pos, + png_const_charp string) +{ + if (buffer != NULL && pos < bufsize) + { + if (string != NULL) + while (*string != '\0' && pos < bufsize-1) + buffer[pos++] = *string++; + + buffer[pos] = '\0'; + } + + return pos; +} + +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED) +/* Utility to dump an unsigned value into a buffer, given a start pointer and + * and end pointer (which should point just *beyond* the end of the buffer!) + * Returns the pointer to the start of the formatted string. + */ +png_charp +png_format_number(png_const_charp start, png_charp end, int format, + png_alloc_size_t number) +{ + int count = 0; /* number of digits output */ + int mincount = 1; /* minimum number required */ + int output = 0; /* digit output (for the fixed point format) */ + + *--end = '\0'; + + /* This is written so that the loop always runs at least once, even with + * number zero. + */ + while (end > start && (number != 0 || count < mincount)) + { + + static const char digits[] = "0123456789ABCDEF"; + + switch (format) + { + case PNG_NUMBER_FORMAT_fixed: + /* Needs five digits (the fraction) */ + mincount = 5; + if (output != 0 || number % 10 != 0) + { + *--end = digits[number % 10]; + output = 1; + } + number /= 10; + break; + + case PNG_NUMBER_FORMAT_02u: + /* Expects at least 2 digits. */ + mincount = 2; + /* FALL THROUGH */ + + case PNG_NUMBER_FORMAT_u: + *--end = digits[number % 10]; + number /= 10; + break; + + case PNG_NUMBER_FORMAT_02x: + /* This format expects at least two digits */ + mincount = 2; + /* FALL THROUGH */ + + case PNG_NUMBER_FORMAT_x: + *--end = digits[number & 0xf]; + number >>= 4; + break; + + default: /* an error */ + number = 0; + break; + } + + /* Keep track of the number of digits added */ + ++count; + + /* Float a fixed number here: */ + if ((format == PNG_NUMBER_FORMAT_fixed) && (count == 5) && (end > start)) + { + /* End of the fraction, but maybe nothing was output? In that case + * drop the decimal point. If the number is a true zero handle that + * here. + */ + if (output != 0) + *--end = '.'; + else if (number == 0) /* and !output */ + *--end = '0'; + } + } + + return end; +} +#endif + +#ifdef PNG_WARNINGS_SUPPORTED +/* This function is called whenever there is a non-fatal error. This function + * should not be changed. If there is a need to handle warnings differently, + * you should supply a replacement warning function and use + * png_set_error_fn() to replace the warning function at run-time. + */ +void PNGAPI +png_warning(png_const_structrp png_ptr, png_const_charp warning_message) +{ + int offset = 0; + if (png_ptr != NULL) + { +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + if ((png_ptr->flags & + (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0) +#endif + { + if (*warning_message == PNG_LITERAL_SHARP) + { + for (offset = 1; offset < 15; offset++) + if (warning_message[offset] == ' ') + break; + } + } + } + if (png_ptr != NULL && png_ptr->warning_fn != NULL) + (*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr), + warning_message + offset); + else + png_default_warning(png_ptr, warning_message + offset); +} + +/* These functions support 'formatted' warning messages with up to + * PNG_WARNING_PARAMETER_COUNT parameters. In the format string the parameter + * is introduced by @, where 'number' starts at 1. This follows the + * standard established by X/Open for internationalizable error messages. + */ +void +png_warning_parameter(png_warning_parameters p, int number, + png_const_charp string) +{ + if (number > 0 && number <= PNG_WARNING_PARAMETER_COUNT) + (void)png_safecat(p[number-1], (sizeof p[number-1]), 0, string); +} + +void +png_warning_parameter_unsigned(png_warning_parameters p, int number, int format, + png_alloc_size_t value) +{ + char buffer[PNG_NUMBER_BUFFER_SIZE]; + png_warning_parameter(p, number, PNG_FORMAT_NUMBER(buffer, format, value)); +} + +void +png_warning_parameter_signed(png_warning_parameters p, int number, int format, + png_int_32 value) +{ + png_alloc_size_t u; + png_charp str; + char buffer[PNG_NUMBER_BUFFER_SIZE]; + + /* Avoid overflow by doing the negate in a png_alloc_size_t: */ + u = (png_alloc_size_t)value; + if (value < 0) + u = ~u + 1; + + str = PNG_FORMAT_NUMBER(buffer, format, u); + + if (value < 0 && str > buffer) + *--str = '-'; + + png_warning_parameter(p, number, str); +} + +void +png_formatted_warning(png_const_structrp png_ptr, png_warning_parameters p, + png_const_charp message) +{ + /* The internal buffer is just 192 bytes - enough for all our messages, + * overflow doesn't happen because this code checks! If someone figures + * out how to send us a message longer than 192 bytes, all that will + * happen is that the message will be truncated appropriately. + */ + size_t i = 0; /* Index in the msg[] buffer: */ + char msg[192]; + + /* Each iteration through the following loop writes at most one character + * to msg[i++] then returns here to validate that there is still space for + * the trailing '\0'. It may (in the case of a parameter) read more than + * one character from message[]; it must check for '\0' and continue to the + * test if it finds the end of string. + */ + while (i<(sizeof msg)-1 && *message != '\0') + { + /* '@' at end of string is now just printed (previously it was skipped); + * it is an error in the calling code to terminate the string with @. + */ + if (p != NULL && *message == '@' && message[1] != '\0') + { + int parameter_char = *++message; /* Consume the '@' */ + static const char valid_parameters[] = "123456789"; + int parameter = 0; + + /* Search for the parameter digit, the index in the string is the + * parameter to use. + */ + while (valid_parameters[parameter] != parameter_char && + valid_parameters[parameter] != '\0') + ++parameter; + + /* If the parameter digit is out of range it will just get printed. */ + if (parameter < PNG_WARNING_PARAMETER_COUNT) + { + /* Append this parameter */ + png_const_charp parm = p[parameter]; + png_const_charp pend = p[parameter] + (sizeof p[parameter]); + + /* No need to copy the trailing '\0' here, but there is no guarantee + * that parm[] has been initialized, so there is no guarantee of a + * trailing '\0': + */ + while (i<(sizeof msg)-1 && *parm != '\0' && parm < pend) + msg[i++] = *parm++; + + /* Consume the parameter digit too: */ + ++message; + continue; + } + + /* else not a parameter and there is a character after the @ sign; just + * copy that. This is known not to be '\0' because of the test above. + */ + } + + /* At this point *message can't be '\0', even in the bad parameter case + * above where there is a lone '@' at the end of the message string. + */ + msg[i++] = *message++; + } + + /* i is always less than (sizeof msg), so: */ + msg[i] = '\0'; + + /* And this is the formatted message. It may be larger than + * PNG_MAX_ERROR_TEXT, but that is only used for 'chunk' errors and these + * are not (currently) formatted. + */ + png_warning(png_ptr, msg); +} +#endif /* WARNINGS */ + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +void PNGAPI +png_benign_error(png_const_structrp png_ptr, png_const_charp error_message) +{ + if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0) + { +# ifdef PNG_READ_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + png_ptr->chunk_name != 0) + png_chunk_warning(png_ptr, error_message); + else +# endif + png_warning(png_ptr, error_message); + } + + else + { +# ifdef PNG_READ_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + png_ptr->chunk_name != 0) + png_chunk_error(png_ptr, error_message); + else +# endif + png_error(png_ptr, error_message); + } + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(error_message) +# endif +} + +void /* PRIVATE */ +png_app_warning(png_const_structrp png_ptr, png_const_charp error_message) +{ + if ((png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN) != 0) + png_warning(png_ptr, error_message); + else + png_error(png_ptr, error_message); + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(error_message) +# endif +} + +void /* PRIVATE */ +png_app_error(png_const_structrp png_ptr, png_const_charp error_message) +{ + if ((png_ptr->flags & PNG_FLAG_APP_ERRORS_WARN) != 0) + png_warning(png_ptr, error_message); + else + png_error(png_ptr, error_message); + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(error_message) +# endif +} +#endif /* BENIGN_ERRORS */ + +#define PNG_MAX_ERROR_TEXT 196 /* Currently limited by profile_error in png.c */ +#if defined(PNG_WARNINGS_SUPPORTED) || \ + (defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED)) +/* These utilities are used internally to build an error message that relates + * to the current chunk. The chunk name comes from png_ptr->chunk_name, + * which is used to prefix the message. The message is limited in length + * to 63 bytes. The name characters are output as hex digits wrapped in [] + * if the character is invalid. + */ +#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) +static PNG_CONST char png_digit[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' +}; + +static void /* PRIVATE */ +png_format_buffer(png_const_structrp png_ptr, png_charp buffer, png_const_charp + error_message) +{ + png_uint_32 chunk_name = png_ptr->chunk_name; + int iout = 0, ishift = 24; + + while (ishift >= 0) + { + int c = (int)(chunk_name >> ishift) & 0xff; + + ishift -= 8; + if (isnonalpha(c) != 0) + { + buffer[iout++] = PNG_LITERAL_LEFT_SQUARE_BRACKET; + buffer[iout++] = png_digit[(c & 0xf0) >> 4]; + buffer[iout++] = png_digit[c & 0x0f]; + buffer[iout++] = PNG_LITERAL_RIGHT_SQUARE_BRACKET; + } + + else + { + buffer[iout++] = (char)c; + } + } + + if (error_message == NULL) + buffer[iout] = '\0'; + + else + { + int iin = 0; + + buffer[iout++] = ':'; + buffer[iout++] = ' '; + + while (iin < PNG_MAX_ERROR_TEXT-1 && error_message[iin] != '\0') + buffer[iout++] = error_message[iin++]; + + /* iin < PNG_MAX_ERROR_TEXT, so the following is safe: */ + buffer[iout] = '\0'; + } +} +#endif /* WARNINGS || ERROR_TEXT */ + +#if defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED) +PNG_FUNCTION(void,PNGAPI +png_chunk_error,(png_const_structrp png_ptr, png_const_charp error_message), + PNG_NORETURN) +{ + char msg[18+PNG_MAX_ERROR_TEXT]; + if (png_ptr == NULL) + png_error(png_ptr, error_message); + + else + { + png_format_buffer(png_ptr, msg, error_message); + png_error(png_ptr, msg); + } +} +#endif /* READ && ERROR_TEXT */ + +#ifdef PNG_WARNINGS_SUPPORTED +void PNGAPI +png_chunk_warning(png_const_structrp png_ptr, png_const_charp warning_message) +{ + char msg[18+PNG_MAX_ERROR_TEXT]; + if (png_ptr == NULL) + png_warning(png_ptr, warning_message); + + else + { + png_format_buffer(png_ptr, msg, warning_message); + png_warning(png_ptr, msg); + } +} +#endif /* WARNINGS */ + +#ifdef PNG_READ_SUPPORTED +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +void PNGAPI +png_chunk_benign_error(png_const_structrp png_ptr, png_const_charp + error_message) +{ + if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0) + png_chunk_warning(png_ptr, error_message); + + else + png_chunk_error(png_ptr, error_message); + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(error_message) +# endif +} +#endif +#endif /* READ */ + +void /* PRIVATE */ +png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error) +{ +# ifndef PNG_WARNINGS_SUPPORTED + PNG_UNUSED(message) +# endif + + /* This is always supported, but for just read or just write it + * unconditionally does the right thing. + */ +# if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED) + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) +# endif + +# ifdef PNG_READ_SUPPORTED + { + if (error < PNG_CHUNK_ERROR) + png_chunk_warning(png_ptr, message); + + else + png_chunk_benign_error(png_ptr, message); + } +# endif + +# if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED) + else if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) +# endif + +# ifdef PNG_WRITE_SUPPORTED + { + if (error < PNG_CHUNK_WRITE_ERROR) + png_app_warning(png_ptr, message); + + else + png_app_error(png_ptr, message); + } +# endif +} + +#ifdef PNG_ERROR_TEXT_SUPPORTED +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_FUNCTION(void, +png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN) +{ +# define fixed_message "fixed point overflow in " +# define fixed_message_ln ((sizeof fixed_message)-1) + int iin; + char msg[fixed_message_ln+PNG_MAX_ERROR_TEXT]; + memcpy(msg, fixed_message, fixed_message_ln); + iin = 0; + if (name != NULL) + while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0) + { + msg[fixed_message_ln + iin] = name[iin]; + ++iin; + } + msg[fixed_message_ln + iin] = 0; + png_error(png_ptr, msg); +} +#endif +#endif + +#ifdef PNG_SETJMP_SUPPORTED +/* This API only exists if ANSI-C style error handling is used, + * otherwise it is necessary for png_default_error to be overridden. + */ +jmp_buf* PNGAPI +png_set_longjmp_fn(png_structrp png_ptr, png_longjmp_ptr longjmp_fn, + size_t jmp_buf_size) +{ + /* From libpng 1.6.0 the app gets one chance to set a 'jmpbuf_size' value + * and it must not change after that. Libpng doesn't care how big the + * buffer is, just that it doesn't change. + * + * If the buffer size is no *larger* than the size of jmp_buf when libpng is + * compiled a built in jmp_buf is returned; this preserves the pre-1.6.0 + * semantics that this call will not fail. If the size is larger, however, + * the buffer is allocated and this may fail, causing the function to return + * NULL. + */ + if (png_ptr == NULL) + return NULL; + + if (png_ptr->jmp_buf_ptr == NULL) + { + png_ptr->jmp_buf_size = 0; /* not allocated */ + + if (jmp_buf_size <= (sizeof png_ptr->jmp_buf_local)) + png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; + + else + { + png_ptr->jmp_buf_ptr = png_voidcast(jmp_buf *, + png_malloc_warn(png_ptr, jmp_buf_size)); + + if (png_ptr->jmp_buf_ptr == NULL) + return NULL; /* new NULL return on OOM */ + + png_ptr->jmp_buf_size = jmp_buf_size; + } + } + + else /* Already allocated: check the size */ + { + size_t size = png_ptr->jmp_buf_size; + + if (size == 0) + { + size = (sizeof png_ptr->jmp_buf_local); + if (png_ptr->jmp_buf_ptr != &png_ptr->jmp_buf_local) + { + /* This is an internal error in libpng: somehow we have been left + * with a stack allocated jmp_buf when the application regained + * control. It's always possible to fix this up, but for the moment + * this is a png_error because that makes it easy to detect. + */ + png_error(png_ptr, "Libpng jmp_buf still allocated"); + /* png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; */ + } + } + + if (size != jmp_buf_size) + { + png_warning(png_ptr, "Application jmp_buf size changed"); + return NULL; /* caller will probably crash: no choice here */ + } + } + + /* Finally fill in the function, now we have a satisfactory buffer. It is + * valid to change the function on every call. + */ + png_ptr->longjmp_fn = longjmp_fn; + return png_ptr->jmp_buf_ptr; +} + +void /* PRIVATE */ +png_free_jmpbuf(png_structrp png_ptr) +{ + if (png_ptr != NULL) + { + jmp_buf *jb = png_ptr->jmp_buf_ptr; + + /* A size of 0 is used to indicate a local, stack, allocation of the + * pointer; used here and in png.c + */ + if (jb != NULL && png_ptr->jmp_buf_size > 0) + { + + /* This stuff is so that a failure to free the error control structure + * does not leave libpng in a state with no valid error handling: the + * free always succeeds, if there is an error it gets ignored. + */ + if (jb != &png_ptr->jmp_buf_local) + { + /* Make an internal, libpng, jmp_buf to return here */ + jmp_buf free_jmp_buf; + + if (!setjmp(free_jmp_buf)) + { + png_ptr->jmp_buf_ptr = &free_jmp_buf; /* come back here */ + png_ptr->jmp_buf_size = 0; /* stack allocation */ + png_ptr->longjmp_fn = longjmp; + png_free(png_ptr, jb); /* Return to setjmp on error */ + } + } + } + + /* *Always* cancel everything out: */ + png_ptr->jmp_buf_size = 0; + png_ptr->jmp_buf_ptr = NULL; + png_ptr->longjmp_fn = 0; + } +} +#endif + +/* This is the default error handling function. Note that replacements for + * this function MUST NOT RETURN, or the program will likely crash. This + * function is used by default, or if the program supplies NULL for the + * error function pointer in png_set_error_fn(). + */ +static PNG_FUNCTION(void /* PRIVATE */, +png_default_error,(png_const_structrp png_ptr, png_const_charp error_message), + PNG_NORETURN) +{ +#ifdef PNG_CONSOLE_IO_SUPPORTED +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + /* Check on NULL only added in 1.5.4 */ + if (error_message != NULL && *error_message == PNG_LITERAL_SHARP) + { + /* Strip "#nnnn " from beginning of error message. */ + int offset; + char error_number[16]; + for (offset = 0; offset<15; offset++) + { + error_number[offset] = error_message[offset + 1]; + if (error_message[offset] == ' ') + break; + } + + if ((offset > 1) && (offset < 15)) + { + error_number[offset - 1] = '\0'; + fprintf(stderr, "libpng error no. %s: %s", + error_number, error_message + offset + 1); + fprintf(stderr, PNG_STRING_NEWLINE); + } + + else + { + fprintf(stderr, "libpng error: %s, offset=%d", + error_message, offset); + fprintf(stderr, PNG_STRING_NEWLINE); + } + } + else +#endif + { + fprintf(stderr, "libpng error: %s", error_message ? error_message : + "undefined"); + fprintf(stderr, PNG_STRING_NEWLINE); + } +#else + PNG_UNUSED(error_message) /* Make compiler happy */ +#endif + png_longjmp(png_ptr, 1); +} + +PNG_FUNCTION(void,PNGAPI +png_longjmp,(png_const_structrp png_ptr, int val),PNG_NORETURN) +{ +#ifdef PNG_SETJMP_SUPPORTED + if (png_ptr != NULL && png_ptr->longjmp_fn != NULL && + png_ptr->jmp_buf_ptr != NULL) + png_ptr->longjmp_fn(*png_ptr->jmp_buf_ptr, val); +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(val) +#endif + + /* If control reaches this point, png_longjmp() must not return. The only + * choice is to terminate the whole process (or maybe the thread); to do + * this the ANSI-C abort() function is used unless a different method is + * implemented by overriding the default configuration setting for + * PNG_ABORT(). + */ + PNG_ABORT(); +} + +#ifdef PNG_WARNINGS_SUPPORTED +/* This function is called when there is a warning, but the library thinks + * it can continue anyway. Replacement functions don't have to do anything + * here if you don't want them to. In the default configuration, png_ptr is + * not used, but it is passed in case it may be useful. + */ +static void /* PRIVATE */ +png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message) +{ +#ifdef PNG_CONSOLE_IO_SUPPORTED +# ifdef PNG_ERROR_NUMBERS_SUPPORTED + if (*warning_message == PNG_LITERAL_SHARP) + { + int offset; + char warning_number[16]; + for (offset = 0; offset < 15; offset++) + { + warning_number[offset] = warning_message[offset + 1]; + if (warning_message[offset] == ' ') + break; + } + + if ((offset > 1) && (offset < 15)) + { + warning_number[offset + 1] = '\0'; + fprintf(stderr, "libpng warning no. %s: %s", + warning_number, warning_message + offset); + fprintf(stderr, PNG_STRING_NEWLINE); + } + + else + { + fprintf(stderr, "libpng warning: %s", + warning_message); + fprintf(stderr, PNG_STRING_NEWLINE); + } + } + else +# endif + + { + fprintf(stderr, "libpng warning: %s", warning_message); + fprintf(stderr, PNG_STRING_NEWLINE); + } +#else + PNG_UNUSED(warning_message) /* Make compiler happy */ +#endif + PNG_UNUSED(png_ptr) /* Make compiler happy */ +} +#endif /* WARNINGS */ + +/* This function is called when the application wants to use another method + * of handling errors and warnings. Note that the error function MUST NOT + * return to the calling routine or serious problems will occur. The return + * method used in the default routine calls longjmp(png_ptr->jmp_buf_ptr, 1) + */ +void PNGAPI +png_set_error_fn(png_structrp png_ptr, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warning_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->error_ptr = error_ptr; + png_ptr->error_fn = error_fn; +#ifdef PNG_WARNINGS_SUPPORTED + png_ptr->warning_fn = warning_fn; +#else + PNG_UNUSED(warning_fn) +#endif +} + + +/* This function returns a pointer to the error_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy and png_read_destroy are called. + */ +png_voidp PNGAPI +png_get_error_ptr(png_const_structrp png_ptr) +{ + if (png_ptr == NULL) + return NULL; + + return ((png_voidp)png_ptr->error_ptr); +} + + +#ifdef PNG_ERROR_NUMBERS_SUPPORTED +void PNGAPI +png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode) +{ + if (png_ptr != NULL) + { + png_ptr->flags &= + ((~(PNG_FLAG_STRIP_ERROR_NUMBERS | + PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode); + } +} +#endif + +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) + /* Currently the above both depend on SETJMP_SUPPORTED, however it would be + * possible to implement without setjmp support just so long as there is some + * way to handle the error return here: + */ +PNG_FUNCTION(void /* PRIVATE */, (PNGCBAPI +png_safe_error),(png_structp png_nonconst_ptr, png_const_charp error_message), + PNG_NORETURN) +{ + const png_const_structrp png_ptr = png_nonconst_ptr; + png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr); + + /* An error is always logged here, overwriting anything (typically a warning) + * that is already there: + */ + if (image != NULL) + { + png_safecat(image->message, (sizeof image->message), 0, error_message); + image->warning_or_error |= PNG_IMAGE_ERROR; + + /* Retrieve the jmp_buf from within the png_control, making this work for + * C++ compilation too is pretty tricky: C++ wants a pointer to the first + * element of a jmp_buf, but C doesn't tell us the type of that. + */ + if (image->opaque != NULL && image->opaque->error_buf != NULL) + longjmp(png_control_jmp_buf(image->opaque), 1); + + /* Missing longjmp buffer, the following is to help debugging: */ + { + size_t pos = png_safecat(image->message, (sizeof image->message), 0, + "bad longjmp: "); + png_safecat(image->message, (sizeof image->message), pos, + error_message); + } + } + + /* Here on an internal programming error. */ + abort(); +} + +#ifdef PNG_WARNINGS_SUPPORTED +void /* PRIVATE */ PNGCBAPI +png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message) +{ + const png_const_structrp png_ptr = png_nonconst_ptr; + png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr); + + /* A warning is only logged if there is no prior warning or error. */ + if (image->warning_or_error == 0) + { + png_safecat(image->message, (sizeof image->message), 0, warning_message); + image->warning_or_error |= PNG_IMAGE_WARNING; + } +} +#endif + +int /* PRIVATE */ +png_safe_execute(png_imagep image_in, int (*function)(png_voidp), png_voidp arg) +{ + volatile png_imagep image = image_in; + volatile int result; + volatile png_voidp saved_error_buf; + jmp_buf safe_jmpbuf; + + /* Safely execute function(arg) with png_error returning to this function. */ + saved_error_buf = image->opaque->error_buf; + result = setjmp(safe_jmpbuf) == 0; + + if (result != 0) + { + + image->opaque->error_buf = safe_jmpbuf; + result = function(arg); + } + + image->opaque->error_buf = saved_error_buf; + + /* And do the cleanup prior to any failure return. */ + if (result == 0) + png_image_free(image); + + return result; +} +#endif /* SIMPLIFIED READ || SIMPLIFIED_WRITE */ +#endif /* READ || WRITE */ diff --git a/source/Irrlicht/libpng/pngget.c b/source/Irrlicht/libpng/pngget.c new file mode 100644 index 00000000..53a06ff1 --- /dev/null +++ b/source/Irrlicht/libpng/pngget.c @@ -0,0 +1,1219 @@ + +/* pngget.c - retrieval of values from info struct + * + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + */ + +#include "pngpriv.h" + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + +png_uint_32 PNGAPI +png_get_valid(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_uint_32 flag) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->valid & flag); + + return(0); +} + +png_size_t PNGAPI +png_get_rowbytes(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->rowbytes); + + return(0); +} + +#ifdef PNG_INFO_IMAGE_SUPPORTED +png_bytepp PNGAPI +png_get_rows(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->row_pointers); + + return(0); +} +#endif + +#ifdef PNG_EASY_ACCESS_SUPPORTED +/* Easy access to info, added in libpng-0.99 */ +png_uint_32 PNGAPI +png_get_image_width(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->width; + + return (0); +} + +png_uint_32 PNGAPI +png_get_image_height(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->height; + + return (0); +} + +png_byte PNGAPI +png_get_bit_depth(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->bit_depth; + + return (0); +} + +png_byte PNGAPI +png_get_color_type(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->color_type; + + return (0); +} + +png_byte PNGAPI +png_get_filter_type(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->filter_type; + + return (0); +} + +png_byte PNGAPI +png_get_interlace_type(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->interlace_type; + + return (0); +} + +png_byte PNGAPI +png_get_compression_type(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return info_ptr->compression_type; + + return (0); +} + +png_uint_32 PNGAPI +png_get_x_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp + info_ptr) +{ +#ifdef PNG_pHYs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) + { + png_debug1(1, "in %s retrieval function", + "png_get_x_pixels_per_meter"); + + if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER) + return (info_ptr->x_pixels_per_unit); + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return (0); +} + +png_uint_32 PNGAPI +png_get_y_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp + info_ptr) +{ +#ifdef PNG_pHYs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) + { + png_debug1(1, "in %s retrieval function", + "png_get_y_pixels_per_meter"); + + if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER) + return (info_ptr->y_pixels_per_unit); + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return (0); +} + +png_uint_32 PNGAPI +png_get_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ +#ifdef PNG_pHYs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) + { + png_debug1(1, "in %s retrieval function", "png_get_pixels_per_meter"); + + if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER && + info_ptr->x_pixels_per_unit == info_ptr->y_pixels_per_unit) + return (info_ptr->x_pixels_per_unit); + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return (0); +} + +#ifdef PNG_FLOATING_POINT_SUPPORTED +float PNGAPI +png_get_pixel_aspect_ratio(png_const_structrp png_ptr, png_const_inforp + info_ptr) +{ +#ifdef PNG_READ_pHYs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) + { + png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio"); + + if (info_ptr->x_pixels_per_unit != 0) + return ((float)((float)info_ptr->y_pixels_per_unit + /(float)info_ptr->x_pixels_per_unit)); + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return ((float)0.0); +} +#endif + +#ifdef PNG_FIXED_POINT_SUPPORTED +png_fixed_point PNGAPI +png_get_pixel_aspect_ratio_fixed(png_const_structrp png_ptr, + png_const_inforp info_ptr) +{ +#ifdef PNG_READ_pHYs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0 && + info_ptr->x_pixels_per_unit > 0 && info_ptr->y_pixels_per_unit > 0 && + info_ptr->x_pixels_per_unit <= PNG_UINT_31_MAX && + info_ptr->y_pixels_per_unit <= PNG_UINT_31_MAX) + { + png_fixed_point res; + + png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio_fixed"); + + /* The following casts work because a PNG 4 byte integer only has a valid + * range of 0..2^31-1; otherwise the cast might overflow. + */ + if (png_muldiv(&res, (png_int_32)info_ptr->y_pixels_per_unit, PNG_FP_1, + (png_int_32)info_ptr->x_pixels_per_unit) != 0) + return res; + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return 0; +} +#endif + +png_int_32 PNGAPI +png_get_x_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ +#ifdef PNG_oFFs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0) + { + png_debug1(1, "in %s retrieval function", "png_get_x_offset_microns"); + + if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER) + return (info_ptr->x_offset); + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return (0); +} + +png_int_32 PNGAPI +png_get_y_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ +#ifdef PNG_oFFs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0) + { + png_debug1(1, "in %s retrieval function", "png_get_y_offset_microns"); + + if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER) + return (info_ptr->y_offset); + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return (0); +} + +png_int_32 PNGAPI +png_get_x_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ +#ifdef PNG_oFFs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0) + { + png_debug1(1, "in %s retrieval function", "png_get_x_offset_pixels"); + + if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL) + return (info_ptr->x_offset); + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return (0); +} + +png_int_32 PNGAPI +png_get_y_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ +#ifdef PNG_oFFs_SUPPORTED + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0) + { + png_debug1(1, "in %s retrieval function", "png_get_y_offset_pixels"); + + if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL) + return (info_ptr->y_offset); + } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) +#endif + + return (0); +} + +#ifdef PNG_INCH_CONVERSIONS_SUPPORTED +static png_uint_32 +ppi_from_ppm(png_uint_32 ppm) +{ +#if 0 + /* The conversion is *(2.54/100), in binary (32 digits): + * .00000110100000001001110101001001 + */ + png_uint_32 t1001, t1101; + ppm >>= 1; /* .1 */ + t1001 = ppm + (ppm >> 3); /* .1001 */ + t1101 = t1001 + (ppm >> 1); /* .1101 */ + ppm >>= 20; /* .000000000000000000001 */ + t1101 += t1101 >> 15; /* .1101000000000001101 */ + t1001 >>= 11; /* .000000000001001 */ + t1001 += t1001 >> 12; /* .000000000001001000000001001 */ + ppm += t1001; /* .000000000001001000001001001 */ + ppm += t1101; /* .110100000001001110101001001 */ + return (ppm + 16) >> 5;/* .00000110100000001001110101001001 */ +#else + /* The argument is a PNG unsigned integer, so it is not permitted + * to be bigger than 2^31. + */ + png_fixed_point result; + if (ppm <= PNG_UINT_31_MAX && png_muldiv(&result, (png_int_32)ppm, 127, + 5000) != 0) + return result; + + /* Overflow. */ + return 0; +#endif +} + +png_uint_32 PNGAPI +png_get_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + return ppi_from_ppm(png_get_pixels_per_meter(png_ptr, info_ptr)); +} + +png_uint_32 PNGAPI +png_get_x_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + return ppi_from_ppm(png_get_x_pixels_per_meter(png_ptr, info_ptr)); +} + +png_uint_32 PNGAPI +png_get_y_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + return ppi_from_ppm(png_get_y_pixels_per_meter(png_ptr, info_ptr)); +} + +#ifdef PNG_FIXED_POINT_SUPPORTED +static png_fixed_point +png_fixed_inches_from_microns(png_const_structrp png_ptr, png_int_32 microns) +{ + /* Convert from metres * 1,000,000 to inches * 100,000, meters to + * inches is simply *(100/2.54), so we want *(10/2.54) == 500/127. + * Notice that this can overflow - a warning is output and 0 is + * returned. + */ + return png_muldiv_warn(png_ptr, microns, 500, 127); +} + +png_fixed_point PNGAPI +png_get_x_offset_inches_fixed(png_const_structrp png_ptr, + png_const_inforp info_ptr) +{ + return png_fixed_inches_from_microns(png_ptr, + png_get_x_offset_microns(png_ptr, info_ptr)); +} +#endif + +#ifdef PNG_FIXED_POINT_SUPPORTED +png_fixed_point PNGAPI +png_get_y_offset_inches_fixed(png_const_structrp png_ptr, + png_const_inforp info_ptr) +{ + return png_fixed_inches_from_microns(png_ptr, + png_get_y_offset_microns(png_ptr, info_ptr)); +} +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +float PNGAPI +png_get_x_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + /* To avoid the overflow do the conversion directly in floating + * point. + */ + return (float)(png_get_x_offset_microns(png_ptr, info_ptr) * .00003937); +} +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +float PNGAPI +png_get_y_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + /* To avoid the overflow do the conversion directly in floating + * point. + */ + return (float)(png_get_y_offset_microns(png_ptr, info_ptr) * .00003937); +} +#endif + +#ifdef PNG_pHYs_SUPPORTED +png_uint_32 PNGAPI +png_get_pHYs_dpi(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) +{ + png_uint_32 retval = 0; + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) + { + png_debug1(1, "in %s retrieval function", "pHYs"); + + if (res_x != NULL) + { + *res_x = info_ptr->x_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + + if (res_y != NULL) + { + *res_y = info_ptr->y_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + + if (unit_type != NULL) + { + *unit_type = (int)info_ptr->phys_unit_type; + retval |= PNG_INFO_pHYs; + + if (*unit_type == 1) + { + if (res_x != NULL) *res_x = (png_uint_32)(*res_x * .0254 + .50); + if (res_y != NULL) *res_y = (png_uint_32)(*res_y * .0254 + .50); + } + } + } + + return (retval); +} +#endif /* pHYs */ +#endif /* INCH_CONVERSIONS */ + +/* png_get_channels really belongs in here, too, but it's been around longer */ + +#endif /* EASY_ACCESS */ + + +png_byte PNGAPI +png_get_channels(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->channels); + + return (0); +} + +#ifdef PNG_READ_SUPPORTED +png_const_bytep PNGAPI +png_get_signature(png_const_structrp png_ptr, png_const_inforp info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->signature); + + return (NULL); +} +#endif + +#ifdef PNG_bKGD_SUPPORTED +png_uint_32 PNGAPI +png_get_bKGD(png_const_structrp png_ptr, png_inforp info_ptr, + png_color_16p *background) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_bKGD) != 0 && + background != NULL) + { + png_debug1(1, "in %s retrieval function", "bKGD"); + + *background = &(info_ptr->background); + return (PNG_INFO_bKGD); + } + + return (0); +} +#endif + +#ifdef PNG_cHRM_SUPPORTED +/* The XYZ APIs were added in 1.5.5 to take advantage of the code added at the + * same time to correct the rgb grayscale coefficient defaults obtained from the + * cHRM chunk in 1.5.4 + */ +# ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_cHRM(png_const_structrp png_ptr, png_const_inforp info_ptr, + double *white_x, double *white_y, double *red_x, double *red_y, + double *green_x, double *green_y, double *blue_x, double *blue_y) +{ + /* Quiet API change: this code used to only return the end points if a cHRM + * chunk was present, but the end points can also come from iCCP or sRGB + * chunks, so in 1.6.0 the png_get_ APIs return the end points regardless and + * the png_set_ APIs merely check that set end points are mutually + * consistent. + */ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) + { + png_debug1(1, "in %s retrieval function", "cHRM"); + + if (white_x != NULL) + *white_x = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.whitex, "cHRM white X"); + if (white_y != NULL) + *white_y = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.whitey, "cHRM white Y"); + if (red_x != NULL) + *red_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redx, + "cHRM red X"); + if (red_y != NULL) + *red_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redy, + "cHRM red Y"); + if (green_x != NULL) + *green_x = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.greenx, "cHRM green X"); + if (green_y != NULL) + *green_y = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.greeny, "cHRM green Y"); + if (blue_x != NULL) + *blue_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluex, + "cHRM blue X"); + if (blue_y != NULL) + *blue_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluey, + "cHRM blue Y"); + return (PNG_INFO_cHRM); + } + + return (0); +} + +png_uint_32 PNGAPI +png_get_cHRM_XYZ(png_const_structrp png_ptr, png_const_inforp info_ptr, + double *red_X, double *red_Y, double *red_Z, double *green_X, + double *green_Y, double *green_Z, double *blue_X, double *blue_Y, + double *blue_Z) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) + { + png_debug1(1, "in %s retrieval function", "cHRM_XYZ(float)"); + + if (red_X != NULL) + *red_X = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_X, + "cHRM red X"); + if (red_Y != NULL) + *red_Y = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Y, + "cHRM red Y"); + if (red_Z != NULL) + *red_Z = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Z, + "cHRM red Z"); + if (green_X != NULL) + *green_X = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.green_X, "cHRM green X"); + if (green_Y != NULL) + *green_Y = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.green_Y, "cHRM green Y"); + if (green_Z != NULL) + *green_Z = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.green_Z, "cHRM green Z"); + if (blue_X != NULL) + *blue_X = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.blue_X, "cHRM blue X"); + if (blue_Y != NULL) + *blue_Y = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.blue_Y, "cHRM blue Y"); + if (blue_Z != NULL) + *blue_Z = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.blue_Z, "cHRM blue Z"); + return (PNG_INFO_cHRM); + } + + return (0); +} +# endif + +# ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_red_X, png_fixed_point *int_red_Y, + png_fixed_point *int_red_Z, png_fixed_point *int_green_X, + png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, + png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, + png_fixed_point *int_blue_Z) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) + { + png_debug1(1, "in %s retrieval function", "cHRM_XYZ"); + + if (int_red_X != NULL) + *int_red_X = info_ptr->colorspace.end_points_XYZ.red_X; + if (int_red_Y != NULL) + *int_red_Y = info_ptr->colorspace.end_points_XYZ.red_Y; + if (int_red_Z != NULL) + *int_red_Z = info_ptr->colorspace.end_points_XYZ.red_Z; + if (int_green_X != NULL) + *int_green_X = info_ptr->colorspace.end_points_XYZ.green_X; + if (int_green_Y != NULL) + *int_green_Y = info_ptr->colorspace.end_points_XYZ.green_Y; + if (int_green_Z != NULL) + *int_green_Z = info_ptr->colorspace.end_points_XYZ.green_Z; + if (int_blue_X != NULL) + *int_blue_X = info_ptr->colorspace.end_points_XYZ.blue_X; + if (int_blue_Y != NULL) + *int_blue_Y = info_ptr->colorspace.end_points_XYZ.blue_Y; + if (int_blue_Z != NULL) + *int_blue_Z = info_ptr->colorspace.end_points_XYZ.blue_Z; + return (PNG_INFO_cHRM); + } + + return (0); +} + +png_uint_32 PNGAPI +png_get_cHRM_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x, + png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y, + png_fixed_point *blue_x, png_fixed_point *blue_y) +{ + png_debug1(1, "in %s retrieval function", "cHRM"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) + { + if (white_x != NULL) + *white_x = info_ptr->colorspace.end_points_xy.whitex; + if (white_y != NULL) + *white_y = info_ptr->colorspace.end_points_xy.whitey; + if (red_x != NULL) + *red_x = info_ptr->colorspace.end_points_xy.redx; + if (red_y != NULL) + *red_y = info_ptr->colorspace.end_points_xy.redy; + if (green_x != NULL) + *green_x = info_ptr->colorspace.end_points_xy.greenx; + if (green_y != NULL) + *green_y = info_ptr->colorspace.end_points_xy.greeny; + if (blue_x != NULL) + *blue_x = info_ptr->colorspace.end_points_xy.bluex; + if (blue_y != NULL) + *blue_y = info_ptr->colorspace.end_points_xy.bluey; + return (PNG_INFO_cHRM); + } + + return (0); +} +# endif +#endif + +#ifdef PNG_gAMA_SUPPORTED +# ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_gAMA_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *file_gamma) +{ + png_debug1(1, "in %s retrieval function", "gAMA"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 && + file_gamma != NULL) + { + *file_gamma = info_ptr->colorspace.gamma; + return (PNG_INFO_gAMA); + } + + return (0); +} +# endif + +# ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_gAMA(png_const_structrp png_ptr, png_const_inforp info_ptr, + double *file_gamma) +{ + png_debug1(1, "in %s retrieval function", "gAMA(float)"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 && + file_gamma != NULL) + { + *file_gamma = png_float(png_ptr, info_ptr->colorspace.gamma, + "png_get_gAMA"); + return (PNG_INFO_gAMA); + } + + return (0); +} +# endif +#endif + +#ifdef PNG_sRGB_SUPPORTED +png_uint_32 PNGAPI +png_get_sRGB(png_const_structrp png_ptr, png_const_inforp info_ptr, + int *file_srgb_intent) +{ + png_debug1(1, "in %s retrieval function", "sRGB"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sRGB) != 0 && file_srgb_intent != NULL) + { + *file_srgb_intent = info_ptr->colorspace.rendering_intent; + return (PNG_INFO_sRGB); + } + + return (0); +} +#endif + +#ifdef PNG_iCCP_SUPPORTED +png_uint_32 PNGAPI +png_get_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, + png_charpp name, int *compression_type, + png_bytepp profile, png_uint_32 *proflen) +{ + png_debug1(1, "in %s retrieval function", "iCCP"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_iCCP) != 0 && + name != NULL && compression_type != NULL && profile != NULL && + proflen != NULL) + { + *name = info_ptr->iccp_name; + *profile = info_ptr->iccp_profile; + *proflen = png_get_uint_32(info_ptr->iccp_profile); + /* This is somewhat irrelevant since the profile data returned has + * actually been uncompressed. + */ + *compression_type = PNG_COMPRESSION_TYPE_BASE; + return (PNG_INFO_iCCP); + } + + return (0); +} +#endif + +#ifdef PNG_sPLT_SUPPORTED +int PNGAPI +png_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr, + png_sPLT_tpp spalettes) +{ + if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL) + { + *spalettes = info_ptr->splt_palettes; + return info_ptr->splt_palettes_num; + } + + return (0); +} +#endif + +#ifdef PNG_hIST_SUPPORTED +png_uint_32 PNGAPI +png_get_hIST(png_const_structrp png_ptr, png_inforp info_ptr, + png_uint_16p *hist) +{ + png_debug1(1, "in %s retrieval function", "hIST"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_hIST) != 0 && hist != NULL) + { + *hist = info_ptr->hist; + return (PNG_INFO_hIST); + } + + return (0); +} +#endif + +png_uint_32 PNGAPI +png_get_IHDR(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_uint_32 *width, png_uint_32 *height, int *bit_depth, + int *color_type, int *interlace_type, int *compression_type, + int *filter_type) +{ + png_debug1(1, "in %s retrieval function", "IHDR"); + + if (png_ptr == NULL || info_ptr == NULL) + return (0); + + if (width != NULL) + *width = info_ptr->width; + + if (height != NULL) + *height = info_ptr->height; + + if (bit_depth != NULL) + *bit_depth = info_ptr->bit_depth; + + if (color_type != NULL) + *color_type = info_ptr->color_type; + + if (compression_type != NULL) + *compression_type = info_ptr->compression_type; + + if (filter_type != NULL) + *filter_type = info_ptr->filter_type; + + if (interlace_type != NULL) + *interlace_type = info_ptr->interlace_type; + + /* This is redundant if we can be sure that the info_ptr values were all + * assigned in png_set_IHDR(). We do the check anyhow in case an + * application has ignored our advice not to mess with the members + * of info_ptr directly. + */ + png_check_IHDR(png_ptr, info_ptr->width, info_ptr->height, + info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, + info_ptr->compression_type, info_ptr->filter_type); + + return (1); +} + +#ifdef PNG_oFFs_SUPPORTED +png_uint_32 PNGAPI +png_get_oFFs(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type) +{ + png_debug1(1, "in %s retrieval function", "oFFs"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0 && + offset_x != NULL && offset_y != NULL && unit_type != NULL) + { + *offset_x = info_ptr->x_offset; + *offset_y = info_ptr->y_offset; + *unit_type = (int)info_ptr->offset_unit_type; + return (PNG_INFO_oFFs); + } + + return (0); +} +#endif + +#ifdef PNG_pCAL_SUPPORTED +png_uint_32 PNGAPI +png_get_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, + png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams, + png_charp *units, png_charpp *params) +{ + png_debug1(1, "in %s retrieval function", "pCAL"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pCAL) != 0 && + purpose != NULL && X0 != NULL && X1 != NULL && type != NULL && + nparams != NULL && units != NULL && params != NULL) + { + *purpose = info_ptr->pcal_purpose; + *X0 = info_ptr->pcal_X0; + *X1 = info_ptr->pcal_X1; + *type = (int)info_ptr->pcal_type; + *nparams = (int)info_ptr->pcal_nparams; + *units = info_ptr->pcal_units; + *params = info_ptr->pcal_params; + return (PNG_INFO_pCAL); + } + + return (0); +} +#endif + +#ifdef PNG_sCAL_SUPPORTED +# ifdef PNG_FIXED_POINT_SUPPORTED +# if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \ + defined(PNG_FLOATING_POINT_SUPPORTED) +png_uint_32 PNGAPI +png_get_sCAL_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, + int *unit, png_fixed_point *width, png_fixed_point *height) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL) != 0) + { + *unit = info_ptr->scal_unit; + /*TODO: make this work without FP support; the API is currently eliminated + * if neither floating point APIs nor internal floating point arithmetic + * are enabled. + */ + *width = png_fixed(png_ptr, atof(info_ptr->scal_s_width), "sCAL width"); + *height = png_fixed(png_ptr, atof(info_ptr->scal_s_height), + "sCAL height"); + return (PNG_INFO_sCAL); + } + + return(0); +} +# endif /* FLOATING_ARITHMETIC */ +# endif /* FIXED_POINT */ +# ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_sCAL(png_const_structrp png_ptr, png_const_inforp info_ptr, + int *unit, double *width, double *height) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL) != 0) + { + *unit = info_ptr->scal_unit; + *width = atof(info_ptr->scal_s_width); + *height = atof(info_ptr->scal_s_height); + return (PNG_INFO_sCAL); + } + + return(0); +} +# endif /* FLOATING POINT */ +png_uint_32 PNGAPI +png_get_sCAL_s(png_const_structrp png_ptr, png_const_inforp info_ptr, + int *unit, png_charpp width, png_charpp height) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL) != 0) + { + *unit = info_ptr->scal_unit; + *width = info_ptr->scal_s_width; + *height = info_ptr->scal_s_height; + return (PNG_INFO_sCAL); + } + + return(0); +} +#endif /* sCAL */ + +#ifdef PNG_pHYs_SUPPORTED +png_uint_32 PNGAPI +png_get_pHYs(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) +{ + png_uint_32 retval = 0; + + png_debug1(1, "in %s retrieval function", "pHYs"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) + { + if (res_x != NULL) + { + *res_x = info_ptr->x_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + + if (res_y != NULL) + { + *res_y = info_ptr->y_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + + if (unit_type != NULL) + { + *unit_type = (int)info_ptr->phys_unit_type; + retval |= PNG_INFO_pHYs; + } + } + + return (retval); +} +#endif /* pHYs */ + +png_uint_32 PNGAPI +png_get_PLTE(png_const_structrp png_ptr, png_inforp info_ptr, + png_colorp *palette, int *num_palette) +{ + png_debug1(1, "in %s retrieval function", "PLTE"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_PLTE) != 0 && palette != NULL) + { + *palette = info_ptr->palette; + *num_palette = info_ptr->num_palette; + png_debug1(3, "num_palette = %d", *num_palette); + return (PNG_INFO_PLTE); + } + + return (0); +} + +#ifdef PNG_sBIT_SUPPORTED +png_uint_32 PNGAPI +png_get_sBIT(png_const_structrp png_ptr, png_inforp info_ptr, + png_color_8p *sig_bit) +{ + png_debug1(1, "in %s retrieval function", "sBIT"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sBIT) != 0 && sig_bit != NULL) + { + *sig_bit = &(info_ptr->sig_bit); + return (PNG_INFO_sBIT); + } + + return (0); +} +#endif + +#ifdef PNG_TEXT_SUPPORTED +int PNGAPI +png_get_text(png_const_structrp png_ptr, png_inforp info_ptr, + png_textp *text_ptr, int *num_text) +{ + if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0) + { + png_debug1(1, "in 0x%lx retrieval function", + (unsigned long)png_ptr->chunk_name); + + if (text_ptr != NULL) + *text_ptr = info_ptr->text; + + if (num_text != NULL) + *num_text = info_ptr->num_text; + + return info_ptr->num_text; + } + + if (num_text != NULL) + *num_text = 0; + + return(0); +} +#endif + +#ifdef PNG_tIME_SUPPORTED +png_uint_32 PNGAPI +png_get_tIME(png_const_structrp png_ptr, png_inforp info_ptr, + png_timep *mod_time) +{ + png_debug1(1, "in %s retrieval function", "tIME"); + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_tIME) != 0 && mod_time != NULL) + { + *mod_time = &(info_ptr->mod_time); + return (PNG_INFO_tIME); + } + + return (0); +} +#endif + +#ifdef PNG_tRNS_SUPPORTED +png_uint_32 PNGAPI +png_get_tRNS(png_const_structrp png_ptr, png_inforp info_ptr, + png_bytep *trans_alpha, int *num_trans, png_color_16p *trans_color) +{ + png_uint_32 retval = 0; + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_tRNS) != 0) + { + png_debug1(1, "in %s retrieval function", "tRNS"); + + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (trans_alpha != NULL) + { + *trans_alpha = info_ptr->trans_alpha; + retval |= PNG_INFO_tRNS; + } + + if (trans_color != NULL) + *trans_color = &(info_ptr->trans_color); + } + + else /* if (info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) */ + { + if (trans_color != NULL) + { + *trans_color = &(info_ptr->trans_color); + retval |= PNG_INFO_tRNS; + } + + if (trans_alpha != NULL) + *trans_alpha = NULL; + } + + if (num_trans != NULL) + { + *num_trans = info_ptr->num_trans; + retval |= PNG_INFO_tRNS; + } + } + + return (retval); +} +#endif + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +int PNGAPI +png_get_unknown_chunks(png_const_structrp png_ptr, png_inforp info_ptr, + png_unknown_chunkpp unknowns) +{ + if (png_ptr != NULL && info_ptr != NULL && unknowns != NULL) + { + *unknowns = info_ptr->unknown_chunks; + return info_ptr->unknown_chunks_num; + } + + return (0); +} +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +png_byte PNGAPI +png_get_rgb_to_gray_status (png_const_structrp png_ptr) +{ + return (png_byte)(png_ptr ? png_ptr->rgb_to_gray_status : 0); +} +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +png_voidp PNGAPI +png_get_user_chunk_ptr(png_const_structrp png_ptr) +{ + return (png_ptr ? png_ptr->user_chunk_ptr : NULL); +} +#endif + +png_size_t PNGAPI +png_get_compression_buffer_size(png_const_structrp png_ptr) +{ + if (png_ptr == NULL) + return 0; + +#ifdef PNG_WRITE_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) +#endif + { +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED + return png_ptr->IDAT_read_size; +#else + return PNG_IDAT_READ_SIZE; +#endif + } + +#ifdef PNG_WRITE_SUPPORTED + else + return png_ptr->zbuffer_size; +#endif +} + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +/* These functions were added to libpng 1.2.6 and were enabled + * by default in libpng-1.4.0 */ +png_uint_32 PNGAPI +png_get_user_width_max (png_const_structrp png_ptr) +{ + return (png_ptr ? png_ptr->user_width_max : 0); +} + +png_uint_32 PNGAPI +png_get_user_height_max (png_const_structrp png_ptr) +{ + return (png_ptr ? png_ptr->user_height_max : 0); +} + +/* This function was added to libpng 1.4.0 */ +png_uint_32 PNGAPI +png_get_chunk_cache_max (png_const_structrp png_ptr) +{ + return (png_ptr ? png_ptr->user_chunk_cache_max : 0); +} + +/* This function was added to libpng 1.4.1 */ +png_alloc_size_t PNGAPI +png_get_chunk_malloc_max (png_const_structrp png_ptr) +{ + return (png_ptr ? png_ptr->user_chunk_malloc_max : 0); +} +#endif /* SET_USER_LIMITS */ + +/* These functions were added to libpng 1.4.0 */ +#ifdef PNG_IO_STATE_SUPPORTED +png_uint_32 PNGAPI +png_get_io_state (png_const_structrp png_ptr) +{ + return png_ptr->io_state; +} + +png_uint_32 PNGAPI +png_get_io_chunk_type (png_const_structrp png_ptr) +{ + return png_ptr->chunk_name; +} +#endif /* IO_STATE */ + +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED +# ifdef PNG_GET_PALETTE_MAX_SUPPORTED +int PNGAPI +png_get_palette_max(png_const_structp png_ptr, png_const_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return png_ptr->num_palette_max; + + return (-1); +} +# endif +#endif + +#endif /* READ || WRITE */ diff --git a/source/Irrlicht/libpng/pnginfo.h b/source/Irrlicht/libpng/pnginfo.h new file mode 100644 index 00000000..036f58c2 --- /dev/null +++ b/source/Irrlicht/libpng/pnginfo.h @@ -0,0 +1,259 @@ + +/* pnginfo.h - header file for PNG reference library + * + * Last changed in libpng 1.6.1 [March 28, 2013] + * Copyright (c) 1998-2002,2004,2006-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + + /* png_info is a structure that holds the information in a PNG file so + * that the application can find out the characteristics of the image. + * If you are reading the file, this structure will tell you what is + * in the PNG file. If you are writing the file, fill in the information + * you want to put into the PNG file, using png_set_*() functions, then + * call png_write_info(). + * + * The names chosen should be very close to the PNG specification, so + * consult that document for information about the meaning of each field. + * + * With libpng < 0.95, it was only possible to directly set and read the + * the values in the png_info_struct, which meant that the contents and + * order of the values had to remain fixed. With libpng 0.95 and later, + * however, there are now functions that abstract the contents of + * png_info_struct from the application, so this makes it easier to use + * libpng with dynamic libraries, and even makes it possible to use + * libraries that don't have all of the libpng ancillary chunk-handing + * functionality. In libpng-1.5.0 this was moved into a separate private + * file that is not visible to applications. + * + * The following members may have allocated storage attached that should be + * cleaned up before the structure is discarded: palette, trans, text, + * pcal_purpose, pcal_units, pcal_params, hist, iccp_name, iccp_profile, + * splt_palettes, scal_unit, row_pointers, and unknowns. By default, these + * are automatically freed when the info structure is deallocated, if they were + * allocated internally by libpng. This behavior can be changed by means + * of the png_data_freer() function. + * + * More allocation details: all the chunk-reading functions that + * change these members go through the corresponding png_set_* + * functions. A function to clear these members is available: see + * png_free_data(). The png_set_* functions do not depend on being + * able to point info structure members to any of the storage they are + * passed (they make their own copies), EXCEPT that the png_set_text + * functions use the same storage passed to them in the text_ptr or + * itxt_ptr structure argument, and the png_set_rows and png_set_unknowns + * functions do not make their own copies. + */ +#ifndef PNGINFO_H +#define PNGINFO_H + +struct png_info_def +{ + /* The following are necessary for every PNG file */ + png_uint_32 width; /* width of image in pixels (from IHDR) */ + png_uint_32 height; /* height of image in pixels (from IHDR) */ + png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */ + png_size_t rowbytes; /* bytes needed to hold an untransformed row */ + png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */ + png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */ + png_uint_16 num_trans; /* number of transparent palette color (tRNS) */ + png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */ + png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */ + /* The following three should have been named *_method not *_type */ + png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */ + png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */ + png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ + + /* The following are set by png_set_IHDR, called from the application on + * write, but the are never actually used by the write code. + */ + png_byte channels; /* number of data channels per pixel (1, 2, 3, 4) */ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte spare_byte; /* to align the data, and for future use */ + +#ifdef PNG_READ_SUPPORTED + /* This is never set during write */ + png_byte signature[8]; /* magic bytes read by libpng from start of file */ +#endif + + /* The rest of the data is optional. If you are reading, check the + * valid field to see if the information in these are valid. If you + * are writing, set the valid field to those chunks you want written, + * and initialize the appropriate fields below. + */ + +#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) + /* png_colorspace only contains 'flags' if neither GAMMA or COLORSPACE are + * defined. When COLORSPACE is switched on all the colorspace-defining + * chunks should be enabled, when GAMMA is switched on all the gamma-defining + * chunks should be enabled. If this is not done it becomes possible to read + * inconsistent PNG files and assign a probably incorrect interpretation to + * the information. (In other words, by carefully choosing which chunks to + * recognize the system configuration can select an interpretation for PNG + * files containing ambiguous data and this will result in inconsistent + * behavior between different libpng builds!) + */ + png_colorspace colorspace; +#endif + +#ifdef PNG_iCCP_SUPPORTED + /* iCCP chunk data. */ + png_charp iccp_name; /* profile name */ + png_bytep iccp_profile; /* International Color Consortium profile data */ + png_uint_32 iccp_proflen; /* ICC profile data length */ +#endif + +#ifdef PNG_TEXT_SUPPORTED + /* The tEXt, and zTXt chunks contain human-readable textual data in + * uncompressed, compressed, and optionally compressed forms, respectively. + * The data in "text" is an array of pointers to uncompressed, + * null-terminated C strings. Each chunk has a keyword that describes the + * textual data contained in that chunk. Keywords are not required to be + * unique, and the text string may be empty. Any number of text chunks may + * be in an image. + */ + int num_text; /* number of comments read or comments to write */ + int max_text; /* current size of text array */ + png_textp text; /* array of comments read or comments to write */ +#endif /* TEXT */ + +#ifdef PNG_tIME_SUPPORTED + /* The tIME chunk holds the last time the displayed image data was + * modified. See the png_time struct for the contents of this struct. + */ + png_time mod_time; +#endif + +#ifdef PNG_sBIT_SUPPORTED + /* The sBIT chunk specifies the number of significant high-order bits + * in the pixel data. Values are in the range [1, bit_depth], and are + * only specified for the channels in the pixel data. The contents of + * the low-order bits is not specified. Data is valid if + * (valid & PNG_INFO_sBIT) is non-zero. + */ + png_color_8 sig_bit; /* significant bits in color channels */ +#endif + +#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_EXPAND_SUPPORTED) || \ +defined(PNG_READ_BACKGROUND_SUPPORTED) + /* The tRNS chunk supplies transparency data for paletted images and + * other image types that don't need a full alpha channel. There are + * "num_trans" transparency values for a paletted image, stored in the + * same order as the palette colors, starting from index 0. Values + * for the data are in the range [0, 255], ranging from fully transparent + * to fully opaque, respectively. For non-paletted images, there is a + * single color specified that should be treated as fully transparent. + * Data is valid if (valid & PNG_INFO_tRNS) is non-zero. + */ + png_bytep trans_alpha; /* alpha values for paletted image */ + png_color_16 trans_color; /* transparent color for non-palette image */ +#endif + +#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + /* The bKGD chunk gives the suggested image background color if the + * display program does not have its own background color and the image + * is needs to composited onto a background before display. The colors + * in "background" are normally in the same color space/depth as the + * pixel data. Data is valid if (valid & PNG_INFO_bKGD) is non-zero. + */ + png_color_16 background; +#endif + +#ifdef PNG_oFFs_SUPPORTED + /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards + * and downwards from the top-left corner of the display, page, or other + * application-specific co-ordinate space. See the PNG_OFFSET_ defines + * below for the unit types. Valid if (valid & PNG_INFO_oFFs) non-zero. + */ + png_int_32 x_offset; /* x offset on page */ + png_int_32 y_offset; /* y offset on page */ + png_byte offset_unit_type; /* offset units type */ +#endif + +#ifdef PNG_pHYs_SUPPORTED + /* The pHYs chunk gives the physical pixel density of the image for + * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_ + * defines below). Data is valid if (valid & PNG_INFO_pHYs) is non-zero. + */ + png_uint_32 x_pixels_per_unit; /* horizontal pixel density */ + png_uint_32 y_pixels_per_unit; /* vertical pixel density */ + png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */ +#endif + +#ifdef PNG_hIST_SUPPORTED + /* The hIST chunk contains the relative frequency or importance of the + * various palette entries, so that a viewer can intelligently select a + * reduced-color palette, if required. Data is an array of "num_palette" + * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST) + * is non-zero. + */ + png_uint_16p hist; +#endif + +#ifdef PNG_pCAL_SUPPORTED + /* The pCAL chunk describes a transformation between the stored pixel + * values and original physical data values used to create the image. + * The integer range [0, 2^bit_depth - 1] maps to the floating-point + * range given by [pcal_X0, pcal_X1], and are further transformed by a + * (possibly non-linear) transformation function given by "pcal_type" + * and "pcal_params" into "pcal_units". Please see the PNG_EQUATION_ + * defines below, and the PNG-Group's PNG extensions document for a + * complete description of the transformations and how they should be + * implemented, and for a description of the ASCII parameter strings. + * Data values are valid if (valid & PNG_INFO_pCAL) non-zero. + */ + png_charp pcal_purpose; /* pCAL chunk description string */ + png_int_32 pcal_X0; /* minimum value */ + png_int_32 pcal_X1; /* maximum value */ + png_charp pcal_units; /* Latin-1 string giving physical units */ + png_charpp pcal_params; /* ASCII strings containing parameter values */ + png_byte pcal_type; /* equation type (see PNG_EQUATION_ below) */ + png_byte pcal_nparams; /* number of parameters given in pcal_params */ +#endif + +/* New members added in libpng-1.0.6 */ + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED + /* Storage for unknown chunks that the library doesn't recognize. */ + png_unknown_chunkp unknown_chunks; + + /* The type of this field is limited by the type of + * png_struct::user_chunk_cache_max, else overflow can occur. + */ + int unknown_chunks_num; +#endif + +#ifdef PNG_sPLT_SUPPORTED + /* Data on sPLT chunks (there may be more than one). */ + png_sPLT_tp splt_palettes; + int splt_palettes_num; /* Match type returned by png_get API */ +#endif + +#ifdef PNG_sCAL_SUPPORTED + /* The sCAL chunk describes the actual physical dimensions of the + * subject matter of the graphic. The chunk contains a unit specification + * a byte value, and two ASCII strings representing floating-point + * values. The values are width and height corresponsing to one pixel + * in the image. Data values are valid if (valid & PNG_INFO_sCAL) is + * non-zero. + */ + png_byte scal_unit; /* unit of physical scale */ + png_charp scal_s_width; /* string containing height */ + png_charp scal_s_height; /* string containing width */ +#endif + +#ifdef PNG_INFO_IMAGE_SUPPORTED + /* Memory has been allocated if (valid & PNG_ALLOCATED_INFO_ROWS) + non-zero */ + /* Data valid if (valid & PNG_INFO_IDAT) non-zero */ + png_bytepp row_pointers; /* the image bits */ +#endif + +}; +#endif /* PNGINFO_H */ diff --git a/source/Irrlicht/libpng/pnglibconf.h b/source/Irrlicht/libpng/pnglibconf.h new file mode 100644 index 00000000..c5a5f803 --- /dev/null +++ b/source/Irrlicht/libpng/pnglibconf.h @@ -0,0 +1,213 @@ +/* pnglibconf.h - library build configuration */ + +/* libpng version 1.6.23, June 9, 2016 */ + +/* Copyright (c) 1998-2016 Glenn Randers-Pehrson */ + +/* This code is released under the libpng license. */ +/* For conditions of distribution and use, see the disclaimer */ +/* and license in png.h */ + +/* pnglibconf.h */ +/* Machine generated file: DO NOT EDIT */ +/* Derived from: scripts/pnglibconf.dfa */ +#ifndef PNGLCONF_H +#define PNGLCONF_H +/* options */ +#define PNG_16BIT_SUPPORTED +#define PNG_ALIGNED_MEMORY_SUPPORTED +/*#undef PNG_ARM_NEON_API_SUPPORTED*/ +/*#undef PNG_ARM_NEON_CHECK_SUPPORTED*/ +#define PNG_BENIGN_ERRORS_SUPPORTED +#define PNG_BENIGN_READ_ERRORS_SUPPORTED +/*#undef PNG_BENIGN_WRITE_ERRORS_SUPPORTED*/ +#define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED +#define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED +#define PNG_COLORSPACE_SUPPORTED +#define PNG_CONSOLE_IO_SUPPORTED +#define PNG_CONVERT_tIME_SUPPORTED +#define PNG_EASY_ACCESS_SUPPORTED +/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/ +#define PNG_ERROR_TEXT_SUPPORTED +#define PNG_FIXED_POINT_SUPPORTED +#define PNG_FLOATING_ARITHMETIC_SUPPORTED +#define PNG_FLOATING_POINT_SUPPORTED +#define PNG_FORMAT_AFIRST_SUPPORTED +#define PNG_FORMAT_BGR_SUPPORTED +#define PNG_GAMMA_SUPPORTED +#define PNG_GET_PALETTE_MAX_SUPPORTED +#define PNG_HANDLE_AS_UNKNOWN_SUPPORTED +#define PNG_INCH_CONVERSIONS_SUPPORTED +#define PNG_INFO_IMAGE_SUPPORTED +#define PNG_IO_STATE_SUPPORTED +#define PNG_MNG_FEATURES_SUPPORTED +#define PNG_POINTER_INDEXING_SUPPORTED +#define PNG_PROGRESSIVE_READ_SUPPORTED +#define PNG_READ_16BIT_SUPPORTED +#define PNG_READ_ALPHA_MODE_SUPPORTED +#define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED +#define PNG_READ_BACKGROUND_SUPPORTED +#define PNG_READ_BGR_SUPPORTED +#define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED +#define PNG_READ_COMPOSITE_NODIV_SUPPORTED +#define PNG_READ_COMPRESSED_TEXT_SUPPORTED +#define PNG_READ_EXPAND_16_SUPPORTED +#define PNG_READ_EXPAND_SUPPORTED +#define PNG_READ_FILLER_SUPPORTED +#define PNG_READ_GAMMA_SUPPORTED +#define PNG_READ_GET_PALETTE_MAX_SUPPORTED +#define PNG_READ_GRAY_TO_RGB_SUPPORTED +#define PNG_READ_INTERLACING_SUPPORTED +#define PNG_READ_INT_FUNCTIONS_SUPPORTED +#define PNG_READ_INVERT_ALPHA_SUPPORTED +#define PNG_READ_INVERT_SUPPORTED +#define PNG_READ_OPT_PLTE_SUPPORTED +#define PNG_READ_PACKSWAP_SUPPORTED +#define PNG_READ_PACK_SUPPORTED +#define PNG_READ_QUANTIZE_SUPPORTED +#define PNG_READ_RGB_TO_GRAY_SUPPORTED +#define PNG_READ_SCALE_16_TO_8_SUPPORTED +#define PNG_READ_SHIFT_SUPPORTED +#define PNG_READ_STRIP_16_TO_8_SUPPORTED +#define PNG_READ_STRIP_ALPHA_SUPPORTED +#define PNG_READ_SUPPORTED +#define PNG_READ_SWAP_ALPHA_SUPPORTED +#define PNG_READ_SWAP_SUPPORTED +#define PNG_READ_TEXT_SUPPORTED +#define PNG_READ_TRANSFORMS_SUPPORTED +#define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_READ_USER_CHUNKS_SUPPORTED +#define PNG_READ_USER_TRANSFORM_SUPPORTED +#define PNG_READ_bKGD_SUPPORTED +#define PNG_READ_cHRM_SUPPORTED +#define PNG_READ_gAMA_SUPPORTED +#define PNG_READ_hIST_SUPPORTED +#define PNG_READ_iCCP_SUPPORTED +#define PNG_READ_iTXt_SUPPORTED +#define PNG_READ_oFFs_SUPPORTED +#define PNG_READ_pCAL_SUPPORTED +#define PNG_READ_pHYs_SUPPORTED +#define PNG_READ_sBIT_SUPPORTED +#define PNG_READ_sCAL_SUPPORTED +#define PNG_READ_sPLT_SUPPORTED +#define PNG_READ_sRGB_SUPPORTED +#define PNG_READ_tEXt_SUPPORTED +#define PNG_READ_tIME_SUPPORTED +#define PNG_READ_tRNS_SUPPORTED +#define PNG_READ_zTXt_SUPPORTED +#define PNG_SAVE_INT_32_SUPPORTED +#define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_SEQUENTIAL_READ_SUPPORTED +#define PNG_SETJMP_SUPPORTED +#define PNG_SET_OPTION_SUPPORTED +#define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_SET_USER_LIMITS_SUPPORTED +#define PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED +#define PNG_SIMPLIFIED_READ_BGR_SUPPORTED +#define PNG_SIMPLIFIED_READ_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_SUPPORTED +#define PNG_STDIO_SUPPORTED +#define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_TEXT_SUPPORTED +#define PNG_TIME_RFC1123_SUPPORTED +#define PNG_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_USER_CHUNKS_SUPPORTED +#define PNG_USER_LIMITS_SUPPORTED +#define PNG_USER_MEM_SUPPORTED +#define PNG_USER_TRANSFORM_INFO_SUPPORTED +#define PNG_USER_TRANSFORM_PTR_SUPPORTED +#define PNG_WARNINGS_SUPPORTED +#define PNG_WRITE_16BIT_SUPPORTED +#define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED +#define PNG_WRITE_BGR_SUPPORTED +#define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED +#define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED +#define PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED +#define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +#define PNG_WRITE_FILLER_SUPPORTED +#define PNG_WRITE_FILTER_SUPPORTED +#define PNG_WRITE_FLUSH_SUPPORTED +#define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED +#define PNG_WRITE_INTERLACING_SUPPORTED +#define PNG_WRITE_INT_FUNCTIONS_SUPPORTED +#define PNG_WRITE_INVERT_ALPHA_SUPPORTED +#define PNG_WRITE_INVERT_SUPPORTED +#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED +#define PNG_WRITE_PACKSWAP_SUPPORTED +#define PNG_WRITE_PACK_SUPPORTED +#define PNG_WRITE_SHIFT_SUPPORTED +#define PNG_WRITE_SUPPORTED +#define PNG_WRITE_SWAP_ALPHA_SUPPORTED +#define PNG_WRITE_SWAP_SUPPORTED +#define PNG_WRITE_TEXT_SUPPORTED +#define PNG_WRITE_TRANSFORMS_SUPPORTED +#define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_WRITE_USER_TRANSFORM_SUPPORTED +#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED +#define PNG_WRITE_bKGD_SUPPORTED +#define PNG_WRITE_cHRM_SUPPORTED +#define PNG_WRITE_gAMA_SUPPORTED +#define PNG_WRITE_hIST_SUPPORTED +#define PNG_WRITE_iCCP_SUPPORTED +#define PNG_WRITE_iTXt_SUPPORTED +#define PNG_WRITE_oFFs_SUPPORTED +#define PNG_WRITE_pCAL_SUPPORTED +#define PNG_WRITE_pHYs_SUPPORTED +#define PNG_WRITE_sBIT_SUPPORTED +#define PNG_WRITE_sCAL_SUPPORTED +#define PNG_WRITE_sPLT_SUPPORTED +#define PNG_WRITE_sRGB_SUPPORTED +#define PNG_WRITE_tEXt_SUPPORTED +#define PNG_WRITE_tIME_SUPPORTED +#define PNG_WRITE_tRNS_SUPPORTED +#define PNG_WRITE_zTXt_SUPPORTED +#define PNG_bKGD_SUPPORTED +#define PNG_cHRM_SUPPORTED +#define PNG_gAMA_SUPPORTED +#define PNG_hIST_SUPPORTED +#define PNG_iCCP_SUPPORTED +#define PNG_iTXt_SUPPORTED +#define PNG_oFFs_SUPPORTED +#define PNG_pCAL_SUPPORTED +#define PNG_pHYs_SUPPORTED +#define PNG_sBIT_SUPPORTED +#define PNG_sCAL_SUPPORTED +#define PNG_sPLT_SUPPORTED +#define PNG_sRGB_SUPPORTED +#define PNG_tEXt_SUPPORTED +#define PNG_tIME_SUPPORTED +#define PNG_tRNS_SUPPORTED +#define PNG_zTXt_SUPPORTED +/* end of options */ +/* settings */ +#define PNG_API_RULE 0 +#define PNG_DEFAULT_READ_MACROS 1 +#define PNG_GAMMA_THRESHOLD_FIXED 5000 +#define PNG_IDAT_READ_SIZE PNG_ZBUF_SIZE +#define PNG_INFLATE_BUF_SIZE 1024 +#define PNG_LINKAGE_API extern +#define PNG_LINKAGE_CALLBACK extern +#define PNG_LINKAGE_DATA extern +#define PNG_LINKAGE_FUNCTION extern +#define PNG_MAX_GAMMA_8 11 +#define PNG_QUANTIZE_BLUE_BITS 5 +#define PNG_QUANTIZE_GREEN_BITS 5 +#define PNG_QUANTIZE_RED_BITS 5 +#define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1) +#define PNG_TEXT_Z_DEFAULT_STRATEGY 0 +#define PNG_USER_CHUNK_CACHE_MAX 1000 +#define PNG_USER_CHUNK_MALLOC_MAX 8000000 +#define PNG_USER_HEIGHT_MAX 1000000 +#define PNG_USER_WIDTH_MAX 1000000 +#define PNG_ZBUF_SIZE 8192 +#define PNG_ZLIB_VERNUM 0x1280 +#define PNG_Z_DEFAULT_COMPRESSION (-1) +#define PNG_Z_DEFAULT_NOFILTER_STRATEGY 0 +#define PNG_Z_DEFAULT_STRATEGY 1 +#define PNG_sCAL_PRECISION 5 +#define PNG_sRGB_PROFILE_CHECKS 2 +/* end of settings */ +#endif /* PNGLCONF_H */ diff --git a/source/Irrlicht/libpng/pngmem.c b/source/Irrlicht/libpng/pngmem.c new file mode 100644 index 00000000..52028fb2 --- /dev/null +++ b/source/Irrlicht/libpng/pngmem.c @@ -0,0 +1,284 @@ + +/* pngmem.c - stub functions for memory allocation + * + * Last changed in libpng 1.6.15 [November 20, 2014] + * Copyright (c) 1998-2002,2004,2006-2014 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all memory allocation. Users who + * need special memory handling are expected to supply replacement + * functions for png_malloc() and png_free(), and to use + * png_create_read_struct_2() and png_create_write_struct_2() to + * identify the replacement functions. + */ + +#include "pngpriv.h" + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +/* Free a png_struct */ +void /* PRIVATE */ +png_destroy_png_struct(png_structrp png_ptr) +{ + if (png_ptr != NULL) + { + /* png_free might call png_error and may certainly call + * png_get_mem_ptr, so fake a temporary png_struct to support this. + */ + png_struct dummy_struct = *png_ptr; + memset(png_ptr, 0, (sizeof *png_ptr)); + png_free(&dummy_struct, png_ptr); + +# ifdef PNG_SETJMP_SUPPORTED + /* We may have a jmp_buf left to deallocate. */ + png_free_jmpbuf(&dummy_struct); +# endif + } +} + +/* Allocate memory. For reasonable files, size should never exceed + * 64K. However, zlib may allocate more than 64K if you don't tell + * it not to. See zconf.h and png.h for more information. zlib does + * need to allocate exactly 64K, so whatever you call here must + * have the ability to do that. + */ +PNG_FUNCTION(png_voidp,PNGAPI +png_calloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) +{ + png_voidp ret; + + ret = png_malloc(png_ptr, size); + + if (ret != NULL) + memset(ret, 0, size); + + return ret; +} + +/* png_malloc_base, an internal function added at libpng 1.6.0, does the work of + * allocating memory, taking into account limits and PNG_USER_MEM_SUPPORTED. + * Checking and error handling must happen outside this routine; it returns NULL + * if the allocation cannot be done (for any reason.) + */ +PNG_FUNCTION(png_voidp /* PRIVATE */, +png_malloc_base,(png_const_structrp png_ptr, png_alloc_size_t size), + PNG_ALLOCATED) +{ + /* Moved to png_malloc_base from png_malloc_default in 1.6.0; the DOS + * allocators have also been removed in 1.6.0, so any 16-bit system now has + * to implement a user memory handler. This checks to be sure it isn't + * called with big numbers. + */ +#ifndef PNG_USER_MEM_SUPPORTED + PNG_UNUSED(png_ptr) +#endif + + /* Some compilers complain that this is always true. However, it + * can be false when integer overflow happens. + */ + if (size > 0 && size <= PNG_SIZE_MAX +# ifdef PNG_MAX_MALLOC_64K + && size <= 65536U +# endif + ) + { +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr != NULL && png_ptr->malloc_fn != NULL) + return png_ptr->malloc_fn(png_constcast(png_structrp,png_ptr), size); + + else +#endif + return malloc((size_t)size); /* checked for truncation above */ + } + + else + return NULL; +} + +#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\ + defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) +/* This is really here only to work round a spurious warning in GCC 4.6 and 4.7 + * that arises because of the checks in png_realloc_array that are repeated in + * png_malloc_array. + */ +static png_voidp +png_malloc_array_checked(png_const_structrp png_ptr, int nelements, + size_t element_size) +{ + png_alloc_size_t req = nelements; /* known to be > 0 */ + + if (req <= PNG_SIZE_MAX/element_size) + return png_malloc_base(png_ptr, req * element_size); + + /* The failure case when the request is too large */ + return NULL; +} + +PNG_FUNCTION(png_voidp /* PRIVATE */, +png_malloc_array,(png_const_structrp png_ptr, int nelements, + size_t element_size),PNG_ALLOCATED) +{ + if (nelements <= 0 || element_size == 0) + png_error(png_ptr, "internal error: array alloc"); + + return png_malloc_array_checked(png_ptr, nelements, element_size); +} + +PNG_FUNCTION(png_voidp /* PRIVATE */, +png_realloc_array,(png_const_structrp png_ptr, png_const_voidp old_array, + int old_elements, int add_elements, size_t element_size),PNG_ALLOCATED) +{ + /* These are internal errors: */ + if (add_elements <= 0 || element_size == 0 || old_elements < 0 || + (old_array == NULL && old_elements > 0)) + png_error(png_ptr, "internal error: array realloc"); + + /* Check for overflow on the elements count (so the caller does not have to + * check.) + */ + if (add_elements <= INT_MAX - old_elements) + { + png_voidp new_array = png_malloc_array_checked(png_ptr, + old_elements+add_elements, element_size); + + if (new_array != NULL) + { + /* Because png_malloc_array worked the size calculations below cannot + * overflow. + */ + if (old_elements > 0) + memcpy(new_array, old_array, element_size*(unsigned)old_elements); + + memset((char*)new_array + element_size*(unsigned)old_elements, 0, + element_size*(unsigned)add_elements); + + return new_array; + } + } + + return NULL; /* error */ +} +#endif /* TEXT || sPLT || STORE_UNKNOWN_CHUNKS */ + +/* Various functions that have different error handling are derived from this. + * png_malloc always exists, but if PNG_USER_MEM_SUPPORTED is defined a separate + * function png_malloc_default is also provided. + */ +PNG_FUNCTION(png_voidp,PNGAPI +png_malloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) +{ + png_voidp ret; + + if (png_ptr == NULL) + return NULL; + + ret = png_malloc_base(png_ptr, size); + + if (ret == NULL) + png_error(png_ptr, "Out of memory"); /* 'm' means png_malloc */ + + return ret; +} + +#ifdef PNG_USER_MEM_SUPPORTED +PNG_FUNCTION(png_voidp,PNGAPI +png_malloc_default,(png_const_structrp png_ptr, png_alloc_size_t size), + PNG_ALLOCATED PNG_DEPRECATED) +{ + png_voidp ret; + + if (png_ptr == NULL) + return NULL; + + /* Passing 'NULL' here bypasses the application provided memory handler. */ + ret = png_malloc_base(NULL/*use malloc*/, size); + + if (ret == NULL) + png_error(png_ptr, "Out of Memory"); /* 'M' means png_malloc_default */ + + return ret; +} +#endif /* USER_MEM */ + +/* This function was added at libpng version 1.2.3. The png_malloc_warn() + * function will issue a png_warning and return NULL instead of issuing a + * png_error, if it fails to allocate the requested memory. + */ +PNG_FUNCTION(png_voidp,PNGAPI +png_malloc_warn,(png_const_structrp png_ptr, png_alloc_size_t size), + PNG_ALLOCATED) +{ + if (png_ptr != NULL) + { + png_voidp ret = png_malloc_base(png_ptr, size); + + if (ret != NULL) + return ret; + + png_warning(png_ptr, "Out of memory"); + } + + return NULL; +} + +/* Free a pointer allocated by png_malloc(). If ptr is NULL, return + * without taking any action. + */ +void PNGAPI +png_free(png_const_structrp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL || ptr == NULL) + return; + +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr->free_fn != NULL) + png_ptr->free_fn(png_constcast(png_structrp,png_ptr), ptr); + + else + png_free_default(png_ptr, ptr); +} + +PNG_FUNCTION(void,PNGAPI +png_free_default,(png_const_structrp png_ptr, png_voidp ptr),PNG_DEPRECATED) +{ + if (png_ptr == NULL || ptr == NULL) + return; +#endif /* USER_MEM */ + + free(ptr); +} + +#ifdef PNG_USER_MEM_SUPPORTED +/* This function is called when the application wants to use another method + * of allocating and freeing memory. + */ +void PNGAPI +png_set_mem_fn(png_structrp png_ptr, png_voidp mem_ptr, png_malloc_ptr + malloc_fn, png_free_ptr free_fn) +{ + if (png_ptr != NULL) + { + png_ptr->mem_ptr = mem_ptr; + png_ptr->malloc_fn = malloc_fn; + png_ptr->free_fn = free_fn; + } +} + +/* This function returns a pointer to the mem_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy and png_read_destroy are called. + */ +png_voidp PNGAPI +png_get_mem_ptr(png_const_structrp png_ptr) +{ + if (png_ptr == NULL) + return NULL; + + return png_ptr->mem_ptr; +} +#endif /* USER_MEM */ +#endif /* READ || WRITE */ diff --git a/source/Irrlicht/libpng/pngnow.png b/source/Irrlicht/libpng/pngnow.png new file mode 100644 index 00000000..82793ebd Binary files /dev/null and b/source/Irrlicht/libpng/pngnow.png differ diff --git a/source/Irrlicht/libpng/pngpread.c b/source/Irrlicht/libpng/pngpread.c new file mode 100644 index 00000000..23dce14b --- /dev/null +++ b/source/Irrlicht/libpng/pngpread.c @@ -0,0 +1,1090 @@ + +/* pngpread.c - read a png file in push mode + * + * Last changed in libpng 1.6.23 [June 9, 2016] + * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include "pngpriv.h" + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + +/* Push model modes */ +#define PNG_READ_SIG_MODE 0 +#define PNG_READ_CHUNK_MODE 1 +#define PNG_READ_IDAT_MODE 2 +#define PNG_READ_tEXt_MODE 4 +#define PNG_READ_zTXt_MODE 5 +#define PNG_READ_DONE_MODE 6 +#define PNG_READ_iTXt_MODE 7 +#define PNG_ERROR_MODE 8 + +#define PNG_PUSH_SAVE_BUFFER_IF_FULL \ +if (png_ptr->push_length + 4 > png_ptr->buffer_size) \ + { png_push_save_buffer(png_ptr); return; } +#define PNG_PUSH_SAVE_BUFFER_IF_LT(N) \ +if (png_ptr->buffer_size < N) \ + { png_push_save_buffer(png_ptr); return; } + +void PNGAPI +png_process_data(png_structrp png_ptr, png_inforp info_ptr, + png_bytep buffer, png_size_t buffer_size) +{ + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_push_restore_buffer(png_ptr, buffer, buffer_size); + + while (png_ptr->buffer_size) + { + png_process_some_data(png_ptr, info_ptr); + } +} + +png_size_t PNGAPI +png_process_data_pause(png_structrp png_ptr, int save) +{ + if (png_ptr != NULL) + { + /* It's easiest for the caller if we do the save; then the caller doesn't + * have to supply the same data again: + */ + if (save != 0) + png_push_save_buffer(png_ptr); + else + { + /* This includes any pending saved bytes: */ + png_size_t remaining = png_ptr->buffer_size; + png_ptr->buffer_size = 0; + + /* So subtract the saved buffer size, unless all the data + * is actually 'saved', in which case we just return 0 + */ + if (png_ptr->save_buffer_size < remaining) + return remaining - png_ptr->save_buffer_size; + } + } + + return 0; +} + +png_uint_32 PNGAPI +png_process_data_skip(png_structrp png_ptr) +{ + /* TODO: Deprecate and remove this API. + * Somewhere the implementation of this seems to have been lost, + * or abandoned. It was only to support some internal back-door access + * to png_struct) in libpng-1.4.x. + */ + png_app_warning(png_ptr, +"png_process_data_skip is not implemented in any current version of libpng"); + return 0; +} + +/* What we do with the incoming data depends on what we were previously + * doing before we ran out of data... + */ +void /* PRIVATE */ +png_process_some_data(png_structrp png_ptr, png_inforp info_ptr) +{ + if (png_ptr == NULL) + return; + + switch (png_ptr->process_mode) + { + case PNG_READ_SIG_MODE: + { + png_push_read_sig(png_ptr, info_ptr); + break; + } + + case PNG_READ_CHUNK_MODE: + { + png_push_read_chunk(png_ptr, info_ptr); + break; + } + + case PNG_READ_IDAT_MODE: + { + png_push_read_IDAT(png_ptr); + break; + } + + default: + { + png_ptr->buffer_size = 0; + break; + } + } +} + +/* Read any remaining signature bytes from the stream and compare them with + * the correct PNG signature. It is possible that this routine is called + * with bytes already read from the signature, either because they have been + * checked by the calling application, or because of multiple calls to this + * routine. + */ +void /* PRIVATE */ +png_push_read_sig(png_structrp png_ptr, png_inforp info_ptr) +{ + png_size_t num_checked = png_ptr->sig_bytes, /* SAFE, does not exceed 8 */ + num_to_check = 8 - num_checked; + + if (png_ptr->buffer_size < num_to_check) + { + num_to_check = png_ptr->buffer_size; + } + + png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]), + num_to_check); + png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes + num_to_check); + + if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) + { + if (num_checked < 4 && + png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) + png_error(png_ptr, "Not a PNG file"); + + else + png_error(png_ptr, "PNG file corrupted by ASCII conversion"); + } + else + { + if (png_ptr->sig_bytes >= 8) + { + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + } + } +} + +void /* PRIVATE */ +png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) +{ + png_uint_32 chunk_name; +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + int keep; /* unknown handling method */ +#endif + + /* First we make sure we have enough data for the 4-byte chunk name + * and the 4-byte chunk length before proceeding with decoding the + * chunk data. To fully decode each of these chunks, we also make + * sure we have enough data in the buffer for the 4-byte CRC at the + * end of every chunk (except IDAT, which is handled separately). + */ + if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0) + { + png_byte chunk_length[4]; + png_byte chunk_tag[4]; + + PNG_PUSH_SAVE_BUFFER_IF_LT(8) + png_push_fill_buffer(png_ptr, chunk_length, 4); + png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); + png_reset_crc(png_ptr); + png_crc_read(png_ptr, chunk_tag, 4); + png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag); + png_check_chunk_name(png_ptr, png_ptr->chunk_name); + png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; + } + + chunk_name = png_ptr->chunk_name; + + if (chunk_name == png_IDAT) + { + if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) + png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; + + /* If we reach an IDAT chunk, this means we have read all of the + * header chunks, and we can start reading the image (or if this + * is called after the image has been read - we have an error). + */ + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_error(png_ptr, "Missing IHDR before IDAT"); + + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + (png_ptr->mode & PNG_HAVE_PLTE) == 0) + png_error(png_ptr, "Missing PLTE before IDAT"); + + png_ptr->process_mode = PNG_READ_IDAT_MODE; + + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + if ((png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) == 0) + if (png_ptr->push_length == 0) + return; + + png_ptr->mode |= PNG_HAVE_IDAT; + + if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) + png_benign_error(png_ptr, "Too many IDATs found"); + } + + if (chunk_name == png_IHDR) + { + if (png_ptr->push_length != 13) + png_error(png_ptr, "Invalid IHDR length"); + + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length); + } + + else if (chunk_name == png_IEND) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length); + + png_ptr->process_mode = PNG_READ_DONE_MODE; + png_push_have_end(png_ptr, info_ptr); + } + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, keep); + + if (chunk_name == png_PLTE) + png_ptr->mode |= PNG_HAVE_PLTE; + } +#endif + + else if (chunk_name == png_PLTE) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length); + } + + else if (chunk_name == png_IDAT) + { + png_ptr->idat_size = png_ptr->push_length; + png_ptr->process_mode = PNG_READ_IDAT_MODE; + png_push_have_info(png_ptr, info_ptr); + png_ptr->zstream.avail_out = + (uInt) PNG_ROWBYTES(png_ptr->pixel_depth, + png_ptr->iwidth) + 1; + png_ptr->zstream.next_out = png_ptr->row_buf; + return; + } + +#ifdef PNG_READ_gAMA_SUPPORTED + else if (png_ptr->chunk_name == png_gAMA) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sBIT_SUPPORTED + else if (png_ptr->chunk_name == png_sBIT) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_cHRM_SUPPORTED + else if (png_ptr->chunk_name == png_cHRM) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sRGB_SUPPORTED + else if (chunk_name == png_sRGB) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_iCCP_SUPPORTED + else if (png_ptr->chunk_name == png_iCCP) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sPLT_SUPPORTED + else if (chunk_name == png_sPLT) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_tRNS_SUPPORTED + else if (chunk_name == png_tRNS) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_bKGD_SUPPORTED + else if (chunk_name == png_bKGD) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_hIST_SUPPORTED + else if (chunk_name == png_hIST) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_pHYs_SUPPORTED + else if (chunk_name == png_pHYs) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_oFFs_SUPPORTED + else if (chunk_name == png_oFFs) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length); + } +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED + else if (chunk_name == png_pCAL) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sCAL_SUPPORTED + else if (chunk_name == png_sCAL) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_tIME_SUPPORTED + else if (chunk_name == png_tIME) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_tEXt_SUPPORTED + else if (chunk_name == png_tEXt) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_zTXt_SUPPORTED + else if (chunk_name == png_zTXt) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_iTXt_SUPPORTED + else if (chunk_name == png_iTXt) + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); + } +#endif + + else + { + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, + PNG_HANDLE_CHUNK_AS_DEFAULT); + } + + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; +} + +void PNGCBAPI +png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) +{ + png_bytep ptr; + + if (png_ptr == NULL) + return; + + ptr = buffer; + if (png_ptr->save_buffer_size != 0) + { + png_size_t save_size; + + if (length < png_ptr->save_buffer_size) + save_size = length; + + else + save_size = png_ptr->save_buffer_size; + + memcpy(ptr, png_ptr->save_buffer_ptr, save_size); + length -= save_size; + ptr += save_size; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + if (length != 0 && png_ptr->current_buffer_size != 0) + { + png_size_t save_size; + + if (length < png_ptr->current_buffer_size) + save_size = length; + + else + save_size = png_ptr->current_buffer_size; + + memcpy(ptr, png_ptr->current_buffer_ptr, save_size); + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } +} + +void /* PRIVATE */ +png_push_save_buffer(png_structrp png_ptr) +{ + if (png_ptr->save_buffer_size != 0) + { + if (png_ptr->save_buffer_ptr != png_ptr->save_buffer) + { + png_size_t i, istop; + png_bytep sp; + png_bytep dp; + + istop = png_ptr->save_buffer_size; + for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer; + i < istop; i++, sp++, dp++) + { + *dp = *sp; + } + } + } + if (png_ptr->save_buffer_size + png_ptr->current_buffer_size > + png_ptr->save_buffer_max) + { + png_size_t new_max; + png_bytep old_buffer; + + if (png_ptr->save_buffer_size > PNG_SIZE_MAX - + (png_ptr->current_buffer_size + 256)) + { + png_error(png_ptr, "Potential overflow of save_buffer"); + } + + new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256; + old_buffer = png_ptr->save_buffer; + png_ptr->save_buffer = (png_bytep)png_malloc_warn(png_ptr, + (png_size_t)new_max); + + if (png_ptr->save_buffer == NULL) + { + png_free(png_ptr, old_buffer); + png_error(png_ptr, "Insufficient memory for save_buffer"); + } + + if (old_buffer) + memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size); + else if (png_ptr->save_buffer_size) + png_error(png_ptr, "save_buffer error"); + png_free(png_ptr, old_buffer); + png_ptr->save_buffer_max = new_max; + } + if (png_ptr->current_buffer_size) + { + memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size, + png_ptr->current_buffer_ptr, png_ptr->current_buffer_size); + png_ptr->save_buffer_size += png_ptr->current_buffer_size; + png_ptr->current_buffer_size = 0; + } + png_ptr->save_buffer_ptr = png_ptr->save_buffer; + png_ptr->buffer_size = 0; +} + +void /* PRIVATE */ +png_push_restore_buffer(png_structrp png_ptr, png_bytep buffer, + png_size_t buffer_length) +{ + png_ptr->current_buffer = buffer; + png_ptr->current_buffer_size = buffer_length; + png_ptr->buffer_size = buffer_length + png_ptr->save_buffer_size; + png_ptr->current_buffer_ptr = png_ptr->current_buffer; +} + +void /* PRIVATE */ +png_push_read_IDAT(png_structrp png_ptr) +{ + if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0) + { + png_byte chunk_length[4]; + png_byte chunk_tag[4]; + + /* TODO: this code can be commoned up with the same code in push_read */ + PNG_PUSH_SAVE_BUFFER_IF_LT(8) + png_push_fill_buffer(png_ptr, chunk_length, 4); + png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); + png_reset_crc(png_ptr); + png_crc_read(png_ptr, chunk_tag, 4); + png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag); + png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; + + if (png_ptr->chunk_name != png_IDAT) + { + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) + png_error(png_ptr, "Not enough compressed data"); + + return; + } + + png_ptr->idat_size = png_ptr->push_length; + } + + if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0) + { + png_size_t save_size = png_ptr->save_buffer_size; + png_uint_32 idat_size = png_ptr->idat_size; + + /* We want the smaller of 'idat_size' and 'current_buffer_size', but they + * are of different types and we don't know which variable has the fewest + * bits. Carefully select the smaller and cast it to the type of the + * larger - this cannot overflow. Do not cast in the following test - it + * will break on either 16-bit or 64-bit platforms. + */ + if (idat_size < save_size) + save_size = (png_size_t)idat_size; + + else + idat_size = (png_uint_32)save_size; + + png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); + + png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size); + + png_ptr->idat_size -= idat_size; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + + if (png_ptr->idat_size != 0 && png_ptr->current_buffer_size != 0) + { + png_size_t save_size = png_ptr->current_buffer_size; + png_uint_32 idat_size = png_ptr->idat_size; + + /* We want the smaller of 'idat_size' and 'current_buffer_size', but they + * are of different types and we don't know which variable has the fewest + * bits. Carefully select the smaller and cast it to the type of the + * larger - this cannot overflow. + */ + if (idat_size < save_size) + save_size = (png_size_t)idat_size; + + else + idat_size = (png_uint_32)save_size; + + png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); + + png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size); + + png_ptr->idat_size -= idat_size; + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } + + if (png_ptr->idat_size == 0) + { + PNG_PUSH_SAVE_BUFFER_IF_LT(4) + png_crc_finish(png_ptr, 0); + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->zowner = 0; + } +} + +void /* PRIVATE */ +png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer, + png_size_t buffer_length) +{ + /* The caller checks for a non-zero buffer length. */ + if (!(buffer_length > 0) || buffer == NULL) + png_error(png_ptr, "No IDAT data (internal error)"); + + /* This routine must process all the data it has been given + * before returning, calling the row callback as required to + * handle the uncompressed results. + */ + png_ptr->zstream.next_in = buffer; + /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */ + png_ptr->zstream.avail_in = (uInt)buffer_length; + + /* Keep going until the decompressed data is all processed + * or the stream marked as finished. + */ + while (png_ptr->zstream.avail_in > 0 && + (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) + { + int ret; + + /* We have data for zlib, but we must check that zlib + * has someplace to put the results. It doesn't matter + * if we don't expect any results -- it may be the input + * data is just the LZ end code. + */ + if (!(png_ptr->zstream.avail_out > 0)) + { + /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */ + png_ptr->zstream.avail_out = (uInt)(PNG_ROWBYTES(png_ptr->pixel_depth, + png_ptr->iwidth) + 1); + + png_ptr->zstream.next_out = png_ptr->row_buf; + } + + /* Using Z_SYNC_FLUSH here means that an unterminated + * LZ stream (a stream with a missing end code) can still + * be handled, otherwise (Z_NO_FLUSH) a future zlib + * implementation might defer output and therefore + * change the current behavior (see comments in inflate.c + * for why this doesn't happen at present with zlib 1.2.5). + */ + ret = PNG_INFLATE(png_ptr, Z_SYNC_FLUSH); + + /* Check for any failure before proceeding. */ + if (ret != Z_OK && ret != Z_STREAM_END) + { + /* Terminate the decompression. */ + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + png_ptr->zowner = 0; + + /* This may be a truncated stream (missing or + * damaged end code). Treat that as a warning. + */ + if (png_ptr->row_number >= png_ptr->num_rows || + png_ptr->pass > 6) + png_warning(png_ptr, "Truncated compressed data in IDAT"); + + else + png_error(png_ptr, "Decompression error in IDAT"); + + /* Skip the check on unprocessed input */ + return; + } + + /* Did inflate output any data? */ + if (png_ptr->zstream.next_out != png_ptr->row_buf) + { + /* Is this unexpected data after the last row? + * If it is, artificially terminate the LZ output + * here. + */ + if (png_ptr->row_number >= png_ptr->num_rows || + png_ptr->pass > 6) + { + /* Extra data. */ + png_warning(png_ptr, "Extra compressed data in IDAT"); + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + png_ptr->zowner = 0; + + /* Do no more processing; skip the unprocessed + * input check below. + */ + return; + } + + /* Do we have a complete row? */ + if (png_ptr->zstream.avail_out == 0) + png_push_process_row(png_ptr); + } + + /* And check for the end of the stream. */ + if (ret == Z_STREAM_END) + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + } + + /* All the data should have been processed, if anything + * is left at this point we have bytes of IDAT data + * after the zlib end code. + */ + if (png_ptr->zstream.avail_in > 0) + png_warning(png_ptr, "Extra compression data in IDAT"); +} + +void /* PRIVATE */ +png_push_process_row(png_structrp png_ptr) +{ + /* 1.5.6: row_info moved out of png_struct to a local here. */ + png_row_info row_info; + + row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */ + row_info.color_type = png_ptr->color_type; + row_info.bit_depth = png_ptr->bit_depth; + row_info.channels = png_ptr->channels; + row_info.pixel_depth = png_ptr->pixel_depth; + row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); + + if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE) + { + if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST) + png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1, + png_ptr->prev_row + 1, png_ptr->row_buf[0]); + else + png_error(png_ptr, "bad adaptive filter value"); + } + + /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before + * 1.5.6, while the buffer really is this big in current versions of libpng + * it may not be in the future, so this was changed just to copy the + * interlaced row count: + */ + memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1); + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED + if (png_ptr->transformations != 0) + png_do_read_transformations(png_ptr, &row_info); +#endif + + /* The transformed pixel depth should match the depth now in row_info. */ + if (png_ptr->transformed_pixel_depth == 0) + { + png_ptr->transformed_pixel_depth = row_info.pixel_depth; + if (row_info.pixel_depth > png_ptr->maximum_pixel_depth) + png_error(png_ptr, "progressive row overflow"); + } + + else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth) + png_error(png_ptr, "internal progressive row size calculation error"); + + +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Expand interlaced rows to full size */ + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0) + { + if (png_ptr->pass < 6) + png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass, + png_ptr->transformations); + + switch (png_ptr->pass) + { + case 0: + { + int i; + for (i = 0; i < 8 && png_ptr->pass == 0; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); /* Updates png_ptr->pass */ + } + + if (png_ptr->pass == 2) /* Pass 1 might be empty */ + { + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + if (png_ptr->pass == 4 && png_ptr->height <= 4) + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + if (png_ptr->pass == 6 && png_ptr->height <= 4) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + break; + } + + case 1: + { + int i; + for (i = 0; i < 8 && png_ptr->pass == 1; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 2) /* Skip top 4 generated rows */ + { + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + break; + } + + case 2: + { + int i; + + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 4) /* Pass 3 might be empty */ + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + break; + } + + case 3: + { + int i; + + for (i = 0; i < 4 && png_ptr->pass == 3; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 4) /* Skip top two generated rows */ + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + + break; + } + + case 4: + { + int i; + + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 6) /* Pass 5 might be empty */ + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + break; + } + + case 5: + { + int i; + + for (i = 0; i < 2 && png_ptr->pass == 5; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + + if (png_ptr->pass == 6) /* Skip top generated row */ + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + + break; + } + + default: + case 6: + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + + if (png_ptr->pass != 6) + break; + + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + } + else +#endif + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } +} + +void /* PRIVATE */ +png_read_push_finish_row(png_structrp png_ptr) +{ +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + static PNG_CONST png_byte png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + static PNG_CONST png_byte png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + static PNG_CONST png_byte png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + static PNG_CONST png_byte png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; + + /* Height of interlace block. This is not currently used - if you need + * it, uncomment it here and in png.h + static PNG_CONST png_byte png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; + */ +#endif + + png_ptr->row_number++; + if (png_ptr->row_number < png_ptr->num_rows) + return; + +#ifdef PNG_READ_INTERLACING_SUPPORTED + if (png_ptr->interlaced != 0) + { + png_ptr->row_number = 0; + memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + + do + { + png_ptr->pass++; + if ((png_ptr->pass == 1 && png_ptr->width < 5) || + (png_ptr->pass == 3 && png_ptr->width < 3) || + (png_ptr->pass == 5 && png_ptr->width < 2)) + png_ptr->pass++; + + if (png_ptr->pass > 7) + png_ptr->pass--; + + if (png_ptr->pass >= 7) + break; + + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + + if ((png_ptr->transformations & PNG_INTERLACE) != 0) + break; + + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + + } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0); + } +#endif /* READ_INTERLACING */ +} + +void /* PRIVATE */ +png_push_have_info(png_structrp png_ptr, png_inforp info_ptr) +{ + if (png_ptr->info_fn != NULL) + (*(png_ptr->info_fn))(png_ptr, info_ptr); +} + +void /* PRIVATE */ +png_push_have_end(png_structrp png_ptr, png_inforp info_ptr) +{ + if (png_ptr->end_fn != NULL) + (*(png_ptr->end_fn))(png_ptr, info_ptr); +} + +void /* PRIVATE */ +png_push_have_row(png_structrp png_ptr, png_bytep row) +{ + if (png_ptr->row_fn != NULL) + (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number, + (int)png_ptr->pass); +} + +#ifdef PNG_READ_INTERLACING_SUPPORTED +void PNGAPI +png_progressive_combine_row(png_const_structrp png_ptr, png_bytep old_row, + png_const_bytep new_row) +{ + if (png_ptr == NULL) + return; + + /* new_row is a flag here - if it is NULL then the app callback was called + * from an empty row (see the calls to png_struct::row_fn below), otherwise + * it must be png_ptr->row_buf+1 + */ + if (new_row != NULL) + png_combine_row(png_ptr, old_row, 1/*blocky display*/); +} +#endif /* READ_INTERLACING */ + +void PNGAPI +png_set_progressive_read_fn(png_structrp png_ptr, png_voidp progressive_ptr, + png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, + png_progressive_end_ptr end_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->info_fn = info_fn; + png_ptr->row_fn = row_fn; + png_ptr->end_fn = end_fn; + + png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer); +} + +png_voidp PNGAPI +png_get_progressive_ptr(png_const_structrp png_ptr) +{ + if (png_ptr == NULL) + return (NULL); + + return png_ptr->io_ptr; +} +#endif /* PROGRESSIVE_READ */ diff --git a/source/Irrlicht/libpng/pngpriv.h b/source/Irrlicht/libpng/pngpriv.h new file mode 100644 index 00000000..e2ad960d --- /dev/null +++ b/source/Irrlicht/libpng/pngpriv.h @@ -0,0 +1,1932 @@ + +/* pngpriv.h - private declarations for use inside libpng + * + * Last changed in libpng 1.6.22 [May 26, 2016] + * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +/* The symbols declared in this file (including the functions declared + * as extern) are PRIVATE. They are not part of the libpng public + * interface, and are not recommended for use by regular applications. + * Some of them may become public in the future; others may stay private, + * change in an incompatible way, or even disappear. + * Although the libpng users are not forbidden to include this header, + * they should be well aware of the issues that may arise from doing so. + */ + +#ifndef PNGPRIV_H +#define PNGPRIV_H + +/* Feature Test Macros. The following are defined here to ensure that correctly + * implemented libraries reveal the APIs libpng needs to build and hide those + * that are not needed and potentially damaging to the compilation. + * + * Feature Test Macros must be defined before any system header is included (see + * POSIX 1003.1 2.8.2 "POSIX Symbols." + * + * These macros only have an effect if the operating system supports either + * POSIX 1003.1 or C99, or both. On other operating systems (particularly + * Windows/Visual Studio) there is no effect; the OS specific tests below are + * still required (as of 2011-05-02.) + */ +#define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */ + +#ifndef PNG_VERSION_INFO_ONLY +/* Standard library headers not required by png.h: */ +# include +# include +#endif + +#define PNGLIB_BUILD /*libpng is being built, not used*/ + +/* If HAVE_CONFIG_H is defined during the build then the build system must + * provide an appropriate "config.h" file on the include path. The header file + * must provide definitions as required below (search for "HAVE_CONFIG_H"); + * see configure.ac for more details of the requirements. The macro + * "PNG_NO_CONFIG_H" is provided for maintainers to test for dependencies on + * 'configure'; define this macro to prevent the configure build including the + * configure generated config.h. Libpng is expected to compile without *any* + * special build system support on a reasonably ANSI-C compliant system. + */ +#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) +# include + + /* Pick up the definition of 'restrict' from config.h if it was read: */ +# define PNG_RESTRICT restrict +#endif + +/* To support symbol prefixing it is necessary to know *before* including png.h + * whether the fixed point (and maybe other) APIs are exported, because if they + * are not internal definitions may be required. This is handled below just + * before png.h is included, but load the configuration now if it is available. + */ +#ifndef PNGLCONF_H +# include "pnglibconf.h" +#endif + +/* Local renames may change non-exported API functions from png.h */ +#if defined(PNG_PREFIX) && !defined(PNGPREFIX_H) +# include "pngprefix.h" +#endif + +#ifdef PNG_USER_CONFIG +# include "pngusr.h" + /* These should have been defined in pngusr.h */ +# ifndef PNG_USER_PRIVATEBUILD +# define PNG_USER_PRIVATEBUILD "Custom libpng build" +# endif +# ifndef PNG_USER_DLLFNAME_POSTFIX +# define PNG_USER_DLLFNAME_POSTFIX "Cb" +# endif +#endif + +/* Compile time options. + * ===================== + * In a multi-arch build the compiler may compile the code several times for the + * same object module, producing different binaries for different architectures. + * When this happens configure-time setting of the target host options cannot be + * done and this interferes with the handling of the ARM NEON optimizations, and + * possibly other similar optimizations. Put additional tests here; in general + * this is needed when the same option can be changed at both compile time and + * run time depending on the target OS (i.e. iOS vs Android.) + * + * NOTE: symbol prefixing does not pass $(CFLAGS) to the preprocessor, because + * this is not possible with certain compilers (Oracle SUN OS CC), as a result + * it is necessary to ensure that all extern functions that *might* be used + * regardless of $(CFLAGS) get declared in this file. The test on __ARM_NEON__ + * below is one example of this behavior because it is controlled by the + * presence or not of -mfpu=neon on the GCC command line, it is possible to do + * this in $(CC), e.g. "CC=gcc -mfpu=neon", but people who build libpng rarely + * do this. + */ +#ifndef PNG_ARM_NEON_OPT + /* ARM NEON optimizations are being controlled by the compiler settings, + * typically the target FPU. If the FPU has been set to NEON (-mfpu=neon + * with GCC) then the compiler will define __ARM_NEON__ and we can rely + * unconditionally on NEON instructions not crashing, otherwise we must + * disable use of NEON instructions. + * + * NOTE: at present these optimizations depend on 'ALIGNED_MEMORY', so they + * can only be turned on automatically if that is supported too. If + * PNG_ARM_NEON_OPT is set in CPPFLAGS (to >0) then arm/arm_init.c will fail + * to compile with an appropriate #error if ALIGNED_MEMORY has been turned + * off. + * + * Note that gcc-4.9 defines __ARM_NEON instead of the deprecated + * __ARM_NEON__, so we check both variants. + * + * To disable ARM_NEON optimizations entirely, and skip compiling the + * associated assembler code, pass --enable-arm-neon=no to configure + * or put -DPNG_ARM_NEON_OPT=0 in CPPFLAGS. + */ +# if (defined(__ARM_NEON__) || defined(__ARM_NEON)) && \ + defined(PNG_ALIGNED_MEMORY_SUPPORTED) +# define PNG_ARM_NEON_OPT 2 +# else +# define PNG_ARM_NEON_OPT 0 +# endif +#endif + +#if PNG_ARM_NEON_OPT > 0 + /* NEON optimizations are to be at least considered by libpng, so enable the + * callbacks to do this. + */ +# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_neon + + /* By default the 'intrinsics' code in arm/filter_neon_intrinsics.c is used + * if possible - if __ARM_NEON__ is set and the compiler version is not known + * to be broken. This is controlled by PNG_ARM_NEON_IMPLEMENTATION which can + * be: + * + * 1 The intrinsics code (the default with __ARM_NEON__) + * 2 The hand coded assembler (the default without __ARM_NEON__) + * + * It is possible to set PNG_ARM_NEON_IMPLEMENTATION in CPPFLAGS, however + * this is *NOT* supported and may cease to work even after a minor revision + * to libpng. It *is* valid to do this for testing purposes, e.g. speed + * testing or a new compiler, but the results should be communicated to the + * libpng implementation list for incorporation in the next minor release. + */ +# ifndef PNG_ARM_NEON_IMPLEMENTATION +# if defined(__ARM_NEON__) || defined(__ARM_NEON) +# if defined(__clang__) + /* At present it is unknown by the libpng developers which versions + * of clang support the intrinsics, however some or perhaps all + * versions do not work with the assembler so this may be + * irrelevant, so just use the default (do nothing here.) + */ +# elif defined(__GNUC__) + /* GCC 4.5.4 NEON support is known to be broken. 4.6.3 is known to + * work, so if this *is* GCC, or G++, look for a version >4.5 + */ +# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6) +# define PNG_ARM_NEON_IMPLEMENTATION 2 +# endif /* no GNUC support */ +# endif /* __GNUC__ */ +# else /* !defined __ARM_NEON__ */ + /* The 'intrinsics' code simply won't compile without this -mfpu=neon: + */ +# define PNG_ARM_NEON_IMPLEMENTATION 2 +# endif /* __ARM_NEON__ */ +# endif /* !PNG_ARM_NEON_IMPLEMENTATION */ + +# ifndef PNG_ARM_NEON_IMPLEMENTATION + /* Use the intrinsics code by default. */ +# define PNG_ARM_NEON_IMPLEMENTATION 1 +# endif +#endif /* PNG_ARM_NEON_OPT > 0 */ + +/* Is this a build of a DLL where compilation of the object modules requires + * different preprocessor settings to those required for a simple library? If + * so PNG_BUILD_DLL must be set. + * + * If libpng is used inside a DLL but that DLL does not export the libpng APIs + * PNG_BUILD_DLL must not be set. To avoid the code below kicking in build a + * static library of libpng then link the DLL against that. + */ +#ifndef PNG_BUILD_DLL +# ifdef DLL_EXPORT + /* This is set by libtool when files are compiled for a DLL; libtool + * always compiles twice, even on systems where it isn't necessary. Set + * PNG_BUILD_DLL in case it is necessary: + */ +# define PNG_BUILD_DLL +# else +# ifdef _WINDLL + /* This is set by the Microsoft Visual Studio IDE in projects that + * build a DLL. It can't easily be removed from those projects (it + * isn't visible in the Visual Studio UI) so it is a fairly reliable + * indication that PNG_IMPEXP needs to be set to the DLL export + * attributes. + */ +# define PNG_BUILD_DLL +# else +# ifdef __DLL__ + /* This is set by the Borland C system when compiling for a DLL + * (as above.) + */ +# define PNG_BUILD_DLL +# else + /* Add additional compiler cases here. */ +# endif +# endif +# endif +#endif /* Setting PNG_BUILD_DLL if required */ + +/* See pngconf.h for more details: the builder of the library may set this on + * the command line to the right thing for the specific compilation system or it + * may be automagically set above (at present we know of no system where it does + * need to be set on the command line.) + * + * PNG_IMPEXP must be set here when building the library to prevent pngconf.h + * setting it to the "import" setting for a DLL build. + */ +#ifndef PNG_IMPEXP +# ifdef PNG_BUILD_DLL +# define PNG_IMPEXP PNG_DLL_EXPORT +# else + /* Not building a DLL, or the DLL doesn't require specific export + * definitions. + */ +# define PNG_IMPEXP +# endif +#endif + +/* No warnings for private or deprecated functions in the build: */ +#ifndef PNG_DEPRECATED +# define PNG_DEPRECATED +#endif +#ifndef PNG_PRIVATE +# define PNG_PRIVATE +#endif + +/* Symbol preprocessing support. + * + * To enable listing global, but internal, symbols the following macros should + * always be used to declare an extern data or function object in this file. + */ +#ifndef PNG_INTERNAL_DATA +# define PNG_INTERNAL_DATA(type, name, array) PNG_LINKAGE_DATA type name array +#endif + +#ifndef PNG_INTERNAL_FUNCTION +# define PNG_INTERNAL_FUNCTION(type, name, args, attributes)\ + PNG_LINKAGE_FUNCTION PNG_FUNCTION(type, name, args, PNG_EMPTY attributes) +#endif + +#ifndef PNG_INTERNAL_CALLBACK +# define PNG_INTERNAL_CALLBACK(type, name, args, attributes)\ + PNG_LINKAGE_CALLBACK PNG_FUNCTION(type, (PNGCBAPI name), args,\ + PNG_EMPTY attributes) +#endif + +/* If floating or fixed point APIs are disabled they may still be compiled + * internally. To handle this make sure they are declared as the appropriate + * internal extern function (otherwise the symbol prefixing stuff won't work and + * the functions will be used without definitions.) + * + * NOTE: although all the API functions are declared here they are not all + * actually built! Because the declarations are still made it is necessary to + * fake out types that they depend on. + */ +#ifndef PNG_FP_EXPORT +# ifndef PNG_FLOATING_POINT_SUPPORTED +# define PNG_FP_EXPORT(ordinal, type, name, args)\ + PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY); +# ifndef PNG_VERSION_INFO_ONLY + typedef struct png_incomplete png_double; + typedef png_double* png_doublep; + typedef const png_double* png_const_doublep; + typedef png_double** png_doublepp; +# endif +# endif +#endif +#ifndef PNG_FIXED_EXPORT +# ifndef PNG_FIXED_POINT_SUPPORTED +# define PNG_FIXED_EXPORT(ordinal, type, name, args)\ + PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY); +# endif +#endif + +#include "png.h" + +/* pngconf.h does not set PNG_DLL_EXPORT unless it is required, so: */ +#ifndef PNG_DLL_EXPORT +# define PNG_DLL_EXPORT +#endif + +/* This is a global switch to set the compilation for an installed system + * (a release build). It can be set for testing debug builds to ensure that + * they will compile when the build type is switched to RC or STABLE, the + * default is just to use PNG_LIBPNG_BUILD_BASE_TYPE. Set this in CPPFLAGS + * with either: + * + * -DPNG_RELEASE_BUILD Turns on the release compile path + * -DPNG_RELEASE_BUILD=0 Turns it off + * or in your pngusr.h with + * #define PNG_RELEASE_BUILD=1 Turns on the release compile path + * #define PNG_RELEASE_BUILD=0 Turns it off + */ +#ifndef PNG_RELEASE_BUILD +# define PNG_RELEASE_BUILD (PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC) +#endif + +/* SECURITY and SAFETY: + * + * libpng is built with support for internal limits on image dimensions and + * memory usage. These are documented in scripts/pnglibconf.dfa of the + * source and recorded in the machine generated header file pnglibconf.h. + */ + +/* If you are running on a machine where you cannot allocate more + * than 64K of memory at once, uncomment this. While libpng will not + * normally need that much memory in a chunk (unless you load up a very + * large file), zlib needs to know how big of a chunk it can use, and + * libpng thus makes sure to check any memory allocation to verify it + * will fit into memory. + * + * zlib provides 'MAXSEG_64K' which, if defined, indicates the + * same limit and pngconf.h (already included) sets the limit + * if certain operating systems are detected. + */ +#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) +# define PNG_MAX_MALLOC_64K +#endif + +#ifndef PNG_UNUSED +/* Unused formal parameter warnings are silenced using the following macro + * which is expected to have no bad effects on performance (optimizing + * compilers will probably remove it entirely). Note that if you replace + * it with something other than whitespace, you must include the terminating + * semicolon. + */ +# define PNG_UNUSED(param) (void)param; +#endif + +/* Just a little check that someone hasn't tried to define something + * contradictory. + */ +#if (PNG_ZBUF_SIZE > 65536L) && defined(PNG_MAX_MALLOC_64K) +# undef PNG_ZBUF_SIZE +# define PNG_ZBUF_SIZE 65536L +#endif + +/* If warnings or errors are turned off the code is disabled or redirected here. + * From 1.5.4 functions have been added to allow very limited formatting of + * error and warning messages - this code will also be disabled here. + */ +#ifdef PNG_WARNINGS_SUPPORTED +# define PNG_WARNING_PARAMETERS(p) png_warning_parameters p; +#else +# define png_warning_parameter(p,number,string) ((void)0) +# define png_warning_parameter_unsigned(p,number,format,value) ((void)0) +# define png_warning_parameter_signed(p,number,format,value) ((void)0) +# define png_formatted_warning(pp,p,message) ((void)(pp)) +# define PNG_WARNING_PARAMETERS(p) +#endif +#ifndef PNG_ERROR_TEXT_SUPPORTED +# define png_fixed_error(s1,s2) png_err(s1) +#endif + +/* C allows up-casts from (void*) to any pointer and (const void*) to any + * pointer to a const object. C++ regards this as a type error and requires an + * explicit, static, cast and provides the static_cast<> rune to ensure that + * const is not cast away. + */ +#ifdef __cplusplus +# define png_voidcast(type, value) static_cast(value) +# define png_constcast(type, value) const_cast(value) +# define png_aligncast(type, value) \ + static_cast(static_cast(value)) +# define png_aligncastconst(type, value) \ + static_cast(static_cast(value)) +#else +# define png_voidcast(type, value) (value) +# define png_constcast(type, value) ((type)(value)) +# define png_aligncast(type, value) ((void*)(value)) +# define png_aligncastconst(type, value) ((const void*)(value)) +#endif /* __cplusplus */ + +/* Some fixed point APIs are still required even if not exported because + * they get used by the corresponding floating point APIs. This magic + * deals with this: + */ +#ifdef PNG_FIXED_POINT_SUPPORTED +# define PNGFAPI PNGAPI +#else +# define PNGFAPI /* PRIVATE */ +#endif + +#ifndef PNG_VERSION_INFO_ONLY +/* Other defines specific to compilers can go here. Try to keep + * them inside an appropriate ifdef/endif pair for portability. + */ +#if defined(PNG_FLOATING_POINT_SUPPORTED) ||\ + defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) + /* png.c requires the following ANSI-C constants if the conversion of + * floating point to ASCII is implemented therein: + * + * DBL_DIG Maximum number of decimal digits (can be set to any constant) + * DBL_MIN Smallest normalized fp number (can be set to an arbitrary value) + * DBL_MAX Maximum floating point number (can be set to an arbitrary value) + */ +# include + +# if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \ + defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC) + /* We need to check that hasn't already been included earlier + * as it seems it doesn't agree with , yet we should really use + * if possible. + */ +# if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__) +# include +# endif +# else +# include +# endif +# if defined(_AMIGA) && defined(__SASC) && defined(_M68881) + /* Amiga SAS/C: We must include builtin FPU functions when compiling using + * MATH=68881 + */ +# include +# endif +#endif + +/* This provides the non-ANSI (far) memory allocation routines. */ +#if defined(__TURBOC__) && defined(__MSDOS__) +# include +# include +#endif + +#if defined(WIN32) || defined(_Windows) || defined(_WINDOWS) || \ + defined(_WIN32) || defined(__WIN32__) +# include /* defines _WINDOWS_ macro */ +#endif +#endif /* PNG_VERSION_INFO_ONLY */ + +/* Moved here around 1.5.0beta36 from pngconf.h */ +/* Users may want to use these so they are not private. Any library + * functions that are passed far data must be model-independent. + */ + +/* Memory model/platform independent fns */ +#ifndef PNG_ABORT +# ifdef _WINDOWS_ +# define PNG_ABORT() ExitProcess(0) +# else +# define PNG_ABORT() abort() +# endif +#endif + +/* These macros may need to be architecture dependent. */ +#define PNG_ALIGN_NONE 0 /* do not use data alignment */ +#define PNG_ALIGN_ALWAYS 1 /* assume unaligned accesses are OK */ +#ifdef offsetof +# define PNG_ALIGN_OFFSET 2 /* use offsetof to determine alignment */ +#else +# define PNG_ALIGN_OFFSET -1 /* prevent the use of this */ +#endif +#define PNG_ALIGN_SIZE 3 /* use sizeof to determine alignment */ + +#ifndef PNG_ALIGN_TYPE + /* Default to using aligned access optimizations and requiring alignment to a + * multiple of the data type size. Override in a compiler specific fashion + * if necessary by inserting tests here: + */ +# define PNG_ALIGN_TYPE PNG_ALIGN_SIZE +#endif + +#if PNG_ALIGN_TYPE == PNG_ALIGN_SIZE + /* This is used because in some compiler implementations non-aligned + * structure members are supported, so the offsetof approach below fails. + * Set PNG_ALIGN_SIZE=0 for compiler combinations where unaligned access + * is good for performance. Do not do this unless you have tested the result + * and understand it. + */ +# define png_alignof(type) (sizeof (type)) +#else +# if PNG_ALIGN_TYPE == PNG_ALIGN_OFFSET +# define png_alignof(type) offsetof(struct{char c; type t;}, t) +# else +# if PNG_ALIGN_TYPE == PNG_ALIGN_ALWAYS +# define png_alignof(type) (1) +# endif + /* Else leave png_alignof undefined to prevent use thereof */ +# endif +#endif + +/* This implicitly assumes alignment is always to a power of 2. */ +#ifdef png_alignof +# define png_isaligned(ptr, type)\ + ((((const char*)ptr-(const char*)0) & (png_alignof(type)-1)) == 0) +#else +# define png_isaligned(ptr, type) 0 +#endif + +/* End of memory model/platform independent support */ +/* End of 1.5.0beta36 move from pngconf.h */ + +/* CONSTANTS and UTILITY MACROS + * These are used internally by libpng and not exposed in the API + */ + +/* Various modes of operation. Note that after an init, mode is set to + * zero automatically when the structure is created. Three of these + * are defined in png.h because they need to be visible to applications + * that call png_set_unknown_chunk(). + */ +/* #define PNG_HAVE_IHDR 0x01 (defined in png.h) */ +/* #define PNG_HAVE_PLTE 0x02 (defined in png.h) */ +#define PNG_HAVE_IDAT 0x04 +/* #define PNG_AFTER_IDAT 0x08 (defined in png.h) */ +#define PNG_HAVE_IEND 0x10 + /* 0x20 (unused) */ + /* 0x40 (unused) */ + /* 0x80 (unused) */ +#define PNG_HAVE_CHUNK_HEADER 0x100 +#define PNG_WROTE_tIME 0x200 +#define PNG_WROTE_INFO_BEFORE_PLTE 0x400 +#define PNG_BACKGROUND_IS_GRAY 0x800 +#define PNG_HAVE_PNG_SIGNATURE 0x1000 +#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */ + /* 0x4000 (unused) */ +#define PNG_IS_READ_STRUCT 0x8000 /* Else is a write struct */ + +/* Flags for the transformations the PNG library does on the image data */ +#define PNG_BGR 0x0001 +#define PNG_INTERLACE 0x0002 +#define PNG_PACK 0x0004 +#define PNG_SHIFT 0x0008 +#define PNG_SWAP_BYTES 0x0010 +#define PNG_INVERT_MONO 0x0020 +#define PNG_QUANTIZE 0x0040 +#define PNG_COMPOSE 0x0080 /* Was PNG_BACKGROUND */ +#define PNG_BACKGROUND_EXPAND 0x0100 +#define PNG_EXPAND_16 0x0200 /* Added to libpng 1.5.2 */ +#define PNG_16_TO_8 0x0400 /* Becomes 'chop' in 1.5.4 */ +#define PNG_RGBA 0x0800 +#define PNG_EXPAND 0x1000 +#define PNG_GAMMA 0x2000 +#define PNG_GRAY_TO_RGB 0x4000 +#define PNG_FILLER 0x8000 +#define PNG_PACKSWAP 0x10000 +#define PNG_SWAP_ALPHA 0x20000 +#define PNG_STRIP_ALPHA 0x40000 +#define PNG_INVERT_ALPHA 0x80000 +#define PNG_USER_TRANSFORM 0x100000 +#define PNG_RGB_TO_GRAY_ERR 0x200000 +#define PNG_RGB_TO_GRAY_WARN 0x400000 +#define PNG_RGB_TO_GRAY 0x600000 /* two bits, RGB_TO_GRAY_ERR|WARN */ +#define PNG_ENCODE_ALPHA 0x800000 /* Added to libpng-1.5.4 */ +#define PNG_ADD_ALPHA 0x1000000 /* Added to libpng-1.2.7 */ +#define PNG_EXPAND_tRNS 0x2000000 /* Added to libpng-1.2.9 */ +#define PNG_SCALE_16_TO_8 0x4000000 /* Added to libpng-1.5.4 */ + /* 0x8000000 unused */ + /* 0x10000000 unused */ + /* 0x20000000 unused */ + /* 0x40000000 unused */ +/* Flags for png_create_struct */ +#define PNG_STRUCT_PNG 0x0001 +#define PNG_STRUCT_INFO 0x0002 + +/* Flags for the png_ptr->flags rather than declaring a byte for each one */ +#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001 +#define PNG_FLAG_ZSTREAM_INITIALIZED 0x0002 /* Added to libpng-1.6.0 */ + /* 0x0004 unused */ +#define PNG_FLAG_ZSTREAM_ENDED 0x0008 /* Added to libpng-1.6.0 */ + /* 0x0010 unused */ + /* 0x0020 unused */ +#define PNG_FLAG_ROW_INIT 0x0040 +#define PNG_FLAG_FILLER_AFTER 0x0080 +#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100 +#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200 +#define PNG_FLAG_CRC_CRITICAL_USE 0x0400 +#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800 +#define PNG_FLAG_ASSUME_sRGB 0x1000 /* Added to libpng-1.5.4 */ +#define PNG_FLAG_OPTIMIZE_ALPHA 0x2000 /* Added to libpng-1.5.4 */ +#define PNG_FLAG_DETECT_UNINITIALIZED 0x4000 /* Added to libpng-1.5.4 */ +/* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000 */ +/* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000 */ +#define PNG_FLAG_LIBRARY_MISMATCH 0x20000 +#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000 +#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000 +#define PNG_FLAG_BENIGN_ERRORS_WARN 0x100000 /* Added to libpng-1.4.0 */ +#define PNG_FLAG_APP_WARNINGS_WARN 0x200000 /* Added to libpng-1.6.0 */ +#define PNG_FLAG_APP_ERRORS_WARN 0x400000 /* Added to libpng-1.6.0 */ + /* 0x800000 unused */ + /* 0x1000000 unused */ + /* 0x2000000 unused */ + /* 0x4000000 unused */ + /* 0x8000000 unused */ + /* 0x10000000 unused */ + /* 0x20000000 unused */ + /* 0x40000000 unused */ + +#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ + PNG_FLAG_CRC_ANCILLARY_NOWARN) + +#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \ + PNG_FLAG_CRC_CRITICAL_IGNORE) + +#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \ + PNG_FLAG_CRC_CRITICAL_MASK) + +/* Save typing and make code easier to understand */ + +#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \ + abs((int)((c1).green) - (int)((c2).green)) + \ + abs((int)((c1).blue) - (int)((c2).blue))) + +/* Added to libpng-1.6.0: scale a 16-bit value in the range 0..65535 to 0..255 + * by dividing by 257 *with rounding*. This macro is exact for the given range. + * See the discourse in pngrtran.c png_do_scale_16_to_8. The values in the + * macro were established by experiment (modifying the added value). The macro + * has a second variant that takes a value already scaled by 255 and divides by + * 65535 - this has a maximum error of .502. Over the range 0..65535*65535 it + * only gives off-by-one errors and only for 0.5% (1 in 200) of the values. + */ +#define PNG_DIV65535(v24) (((v24) + 32895) >> 16) +#define PNG_DIV257(v16) PNG_DIV65535((png_uint_32)(v16) * 255) + +/* Added to libpng-1.2.6 JB */ +#define PNG_ROWBYTES(pixel_bits, width) \ + ((pixel_bits) >= 8 ? \ + ((png_size_t)(width) * (((png_size_t)(pixel_bits)) >> 3)) : \ + (( ((png_size_t)(width) * ((png_size_t)(pixel_bits))) + 7) >> 3) ) + +/* PNG_OUT_OF_RANGE returns true if value is outside the range + * ideal-delta..ideal+delta. Each argument is evaluated twice. + * "ideal" and "delta" should be constants, normally simple + * integers, "value" a variable. Added to libpng-1.2.6 JB + */ +#define PNG_OUT_OF_RANGE(value, ideal, delta) \ + ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) ) + +/* Conversions between fixed and floating point, only defined if + * required (to make sure the code doesn't accidentally use float + * when it is supposedly disabled.) + */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +/* The floating point conversion can't overflow, though it can and + * does lose accuracy relative to the original fixed point value. + * In practice this doesn't matter because png_fixed_point only + * stores numbers with very low precision. The png_ptr and s + * arguments are unused by default but are there in case error + * checking becomes a requirement. + */ +#define png_float(png_ptr, fixed, s) (.00001 * (fixed)) + +/* The fixed point conversion performs range checking and evaluates + * its argument multiple times, so must be used with care. The + * range checking uses the PNG specification values for a signed + * 32-bit fixed point value except that the values are deliberately + * rounded-to-zero to an integral value - 21474 (21474.83 is roughly + * (2^31-1) * 100000). 's' is a string that describes the value being + * converted. + * + * NOTE: this macro will raise a png_error if the range check fails, + * therefore it is normally only appropriate to use this on values + * that come from API calls or other sources where an out of range + * error indicates a programming error, not a data error! + * + * NOTE: by default this is off - the macro is not used - because the + * function call saves a lot of code. + */ +#ifdef PNG_FIXED_POINT_MACRO_SUPPORTED +#define png_fixed(png_ptr, fp, s) ((fp) <= 21474 && (fp) >= -21474 ?\ + ((png_fixed_point)(100000 * (fp))) : (png_fixed_error(png_ptr, s),0)) +#endif +/* else the corresponding function is defined below, inside the scope of the + * cplusplus test. + */ +#endif + +/* Constants for known chunk types. If you need to add a chunk, define the name + * here. For historical reasons these constants have the form png_; i.e. + * the prefix is lower case. Please use decimal values as the parameters to + * match the ISO PNG specification and to avoid relying on the C locale + * interpretation of character values. + * + * Prior to 1.5.6 these constants were strings, as of 1.5.6 png_uint_32 values + * are computed and a new macro (PNG_STRING_FROM_CHUNK) added to allow a string + * to be generated if required. + * + * PNG_32b correctly produces a value shifted by up to 24 bits, even on + * architectures where (int) is only 16 bits. + */ +#define PNG_32b(b,s) ((png_uint_32)(b) << (s)) +#define PNG_U32(b1,b2,b3,b4) \ + (PNG_32b(b1,24) | PNG_32b(b2,16) | PNG_32b(b3,8) | PNG_32b(b4,0)) + +/* Constants for known chunk types. + * + * MAINTAINERS: If you need to add a chunk, define the name here. + * For historical reasons these constants have the form png_; i.e. + * the prefix is lower case. Please use decimal values as the parameters to + * match the ISO PNG specification and to avoid relying on the C locale + * interpretation of character values. Please keep the list sorted. + * + * Notice that PNG_U32 is used to define a 32-bit value for the 4 byte chunk + * type. In fact the specification does not express chunk types this way, + * however using a 32-bit value means that the chunk type can be read from the + * stream using exactly the same code as used for a 32-bit unsigned value and + * can be examined far more efficiently (using one arithmetic compare). + * + * Prior to 1.5.6 the chunk type constants were expressed as C strings. The + * libpng API still uses strings for 'unknown' chunks and a macro, + * PNG_STRING_FROM_CHUNK, allows a string to be generated if required. Notice + * that for portable code numeric values must still be used; the string "IHDR" + * is not portable and neither is PNG_U32('I', 'H', 'D', 'R'). + * + * In 1.7.0 the definitions will be made public in png.h to avoid having to + * duplicate the same definitions in application code. + */ +#define png_IDAT PNG_U32( 73, 68, 65, 84) +#define png_IEND PNG_U32( 73, 69, 78, 68) +#define png_IHDR PNG_U32( 73, 72, 68, 82) +#define png_PLTE PNG_U32( 80, 76, 84, 69) +#define png_bKGD PNG_U32( 98, 75, 71, 68) +#define png_cHRM PNG_U32( 99, 72, 82, 77) +#define png_fRAc PNG_U32(102, 82, 65, 99) /* registered, not defined */ +#define png_gAMA PNG_U32(103, 65, 77, 65) +#define png_gIFg PNG_U32(103, 73, 70, 103) +#define png_gIFt PNG_U32(103, 73, 70, 116) /* deprecated */ +#define png_gIFx PNG_U32(103, 73, 70, 120) +#define png_hIST PNG_U32(104, 73, 83, 84) +#define png_iCCP PNG_U32(105, 67, 67, 80) +#define png_iTXt PNG_U32(105, 84, 88, 116) +#define png_oFFs PNG_U32(111, 70, 70, 115) +#define png_pCAL PNG_U32(112, 67, 65, 76) +#define png_pHYs PNG_U32(112, 72, 89, 115) +#define png_sBIT PNG_U32(115, 66, 73, 84) +#define png_sCAL PNG_U32(115, 67, 65, 76) +#define png_sPLT PNG_U32(115, 80, 76, 84) +#define png_sRGB PNG_U32(115, 82, 71, 66) +#define png_sTER PNG_U32(115, 84, 69, 82) +#define png_tEXt PNG_U32(116, 69, 88, 116) +#define png_tIME PNG_U32(116, 73, 77, 69) +#define png_tRNS PNG_U32(116, 82, 78, 83) +#define png_zTXt PNG_U32(122, 84, 88, 116) + +/* The following will work on (signed char*) strings, whereas the get_uint_32 + * macro will fail on top-bit-set values because of the sign extension. + */ +#define PNG_CHUNK_FROM_STRING(s)\ + PNG_U32(0xff & (s)[0], 0xff & (s)[1], 0xff & (s)[2], 0xff & (s)[3]) + +/* This uses (char), not (png_byte) to avoid warnings on systems where (char) is + * signed and the argument is a (char[]) This macro will fail miserably on + * systems where (char) is more than 8 bits. + */ +#define PNG_STRING_FROM_CHUNK(s,c)\ + (void)(((char*)(s))[0]=(char)(((c)>>24) & 0xff), \ + ((char*)(s))[1]=(char)(((c)>>16) & 0xff),\ + ((char*)(s))[2]=(char)(((c)>>8) & 0xff), \ + ((char*)(s))[3]=(char)((c & 0xff))) + +/* Do the same but terminate with a null character. */ +#define PNG_CSTRING_FROM_CHUNK(s,c)\ + (void)(PNG_STRING_FROM_CHUNK(s,c), ((char*)(s))[4] = 0) + +/* Test on flag values as defined in the spec (section 5.4): */ +#define PNG_CHUNK_ANCILLARY(c) (1 & ((c) >> 29)) +#define PNG_CHUNK_CRITICAL(c) (!PNG_CHUNK_ANCILLARY(c)) +#define PNG_CHUNK_PRIVATE(c) (1 & ((c) >> 21)) +#define PNG_CHUNK_RESERVED(c) (1 & ((c) >> 13)) +#define PNG_CHUNK_SAFE_TO_COPY(c) (1 & ((c) >> 5)) + +/* Gamma values (new at libpng-1.5.4): */ +#define PNG_GAMMA_MAC_OLD 151724 /* Assume '1.8' is really 2.2/1.45! */ +#define PNG_GAMMA_MAC_INVERSE 65909 +#define PNG_GAMMA_sRGB_INVERSE 45455 + +/* Almost everything below is C specific; the #defines above can be used in + * non-C code (so long as it is C-preprocessed) the rest of this stuff cannot. + */ +#ifndef PNG_VERSION_INFO_ONLY + +#include "pngstruct.h" +#include "pnginfo.h" + +/* Validate the include paths - the include path used to generate pnglibconf.h + * must match that used in the build, or we must be using pnglibconf.h.prebuilt: + */ +#if PNG_ZLIB_VERNUM != 0 && PNG_ZLIB_VERNUM != ZLIB_VERNUM +# error ZLIB_VERNUM != PNG_ZLIB_VERNUM \ + "-I (include path) error: see the notes in pngpriv.h" + /* This means that when pnglibconf.h was built the copy of zlib.h that it + * used is not the same as the one being used here. Because the build of + * libpng makes decisions to use inflateInit2 and inflateReset2 based on the + * zlib version number and because this affects handling of certain broken + * PNG files the -I directives must match. + * + * The most likely explanation is that you passed a -I in CFLAGS. This will + * not work; all the preprocessor directories and in particular all the -I + * directives must be in CPPFLAGS. + */ +#endif + +/* This is used for 16-bit gamma tables -- only the top level pointers are + * const; this could be changed: + */ +typedef const png_uint_16p * png_const_uint_16pp; + +/* Added to libpng-1.5.7: sRGB conversion tables */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_table, [256]); + /* Convert from an sRGB encoded value 0..255 to a 16-bit linear value, + * 0..65535. This table gives the closest 16-bit answers (no errors). + */ +#endif + +PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_base, [512]); +PNG_INTERNAL_DATA(const png_byte, png_sRGB_delta, [512]); + +#define PNG_sRGB_FROM_LINEAR(linear) \ + ((png_byte)(0xff & ((png_sRGB_base[(linear)>>15] \ + + ((((linear) & 0x7fff)*png_sRGB_delta[(linear)>>15])>>12)) >> 8))) + /* Given a value 'linear' in the range 0..255*65535 calculate the 8-bit sRGB + * encoded value with maximum error 0.646365. Note that the input is not a + * 16-bit value; it has been multiplied by 255! */ +#endif /* SIMPLIFIED_READ/WRITE */ + + +/* Inhibit C++ name-mangling for libpng functions but not for system calls. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Internal functions; these are not exported from a DLL however because they + * are used within several of the C source files they have to be C extern. + * + * All of these functions must be declared with PNG_INTERNAL_FUNCTION. + */ + +/* Zlib support */ +#define PNG_UNEXPECTED_ZLIB_RETURN (-7) +PNG_INTERNAL_FUNCTION(void, png_zstream_error,(png_structrp png_ptr, int ret), + PNG_EMPTY); + /* Used by the zlib handling functions to ensure that z_stream::msg is always + * set before they return. + */ + +#ifdef PNG_WRITE_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_free_buffer_list,(png_structrp png_ptr, + png_compression_bufferp *list),PNG_EMPTY); + /* Free the buffer list used by the compressed write code. */ +#endif + +#if defined(PNG_FLOATING_POINT_SUPPORTED) && \ + !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ + (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \ + defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \ + (defined(PNG_sCAL_SUPPORTED) && \ + defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)) +PNG_INTERNAL_FUNCTION(png_fixed_point,png_fixed,(png_const_structrp png_ptr, + double fp, png_const_charp text),PNG_EMPTY); +#endif + +/* Check the user version string for compatibility, returns false if the version + * numbers aren't compatible. + */ +PNG_INTERNAL_FUNCTION(int,png_user_version_check,(png_structrp png_ptr, + png_const_charp user_png_ver),PNG_EMPTY); + +/* Internal base allocator - no messages, NULL on failure to allocate. This + * does, however, call the application provided allocator and that could call + * png_error (although that would be a bug in the application implementation.) + */ +PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_base,(png_const_structrp png_ptr, + png_alloc_size_t size),PNG_ALLOCATED); + +#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\ + defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) +/* Internal array allocator, outputs no error or warning messages on failure, + * just returns NULL. + */ +PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_array,(png_const_structrp png_ptr, + int nelements, size_t element_size),PNG_ALLOCATED); + +/* The same but an existing array is extended by add_elements. This function + * also memsets the new elements to 0 and copies the old elements. The old + * array is not freed or altered. + */ +PNG_INTERNAL_FUNCTION(png_voidp,png_realloc_array,(png_const_structrp png_ptr, + png_const_voidp array, int old_elements, int add_elements, + size_t element_size),PNG_ALLOCATED); +#endif /* text, sPLT or unknown chunks */ + +/* Magic to create a struct when there is no struct to call the user supplied + * memory allocators. Because error handling has not been set up the memory + * handlers can't safely call png_error, but this is an obscure and undocumented + * restriction so libpng has to assume that the 'free' handler, at least, might + * call png_error. + */ +PNG_INTERNAL_FUNCTION(png_structp,png_create_png_struct, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, + png_free_ptr free_fn),PNG_ALLOCATED); + +/* Free memory from internal libpng struct */ +PNG_INTERNAL_FUNCTION(void,png_destroy_png_struct,(png_structrp png_ptr), + PNG_EMPTY); + +/* Free an allocated jmp_buf (always succeeds) */ +PNG_INTERNAL_FUNCTION(void,png_free_jmpbuf,(png_structrp png_ptr),PNG_EMPTY); + +/* Function to allocate memory for zlib. PNGAPI is disallowed. */ +PNG_INTERNAL_FUNCTION(voidpf,png_zalloc,(voidpf png_ptr, uInt items, uInt size), + PNG_ALLOCATED); + +/* Function to free memory for zlib. PNGAPI is disallowed. */ +PNG_INTERNAL_FUNCTION(void,png_zfree,(voidpf png_ptr, voidpf ptr),PNG_EMPTY); + +/* Next four functions are used internally as callbacks. PNGCBAPI is required + * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3, changed to + * PNGCBAPI at 1.5.0 + */ + +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_read_data,(png_structp png_ptr, + png_bytep data, png_size_t length),PNG_EMPTY); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_push_fill_buffer,(png_structp png_ptr, + png_bytep buffer, png_size_t length),PNG_EMPTY); +#endif + +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_write_data,(png_structp png_ptr, + png_bytep data, png_size_t length),PNG_EMPTY); + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +# ifdef PNG_STDIO_SUPPORTED +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_flush,(png_structp png_ptr), + PNG_EMPTY); +# endif +#endif + +/* Reset the CRC variable */ +PNG_INTERNAL_FUNCTION(void,png_reset_crc,(png_structrp png_ptr),PNG_EMPTY); + +/* Write the "data" buffer to whatever output you are using */ +PNG_INTERNAL_FUNCTION(void,png_write_data,(png_structrp png_ptr, + png_const_bytep data, png_size_t length),PNG_EMPTY); + +/* Read and check the PNG file signature */ +PNG_INTERNAL_FUNCTION(void,png_read_sig,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); + +/* Read the chunk header (length + type name) */ +PNG_INTERNAL_FUNCTION(png_uint_32,png_read_chunk_header,(png_structrp png_ptr), + PNG_EMPTY); + +/* Read data from whatever input you are using into the "data" buffer */ +PNG_INTERNAL_FUNCTION(void,png_read_data,(png_structrp png_ptr, png_bytep data, + png_size_t length),PNG_EMPTY); + +/* Read bytes into buf, and update png_ptr->crc */ +PNG_INTERNAL_FUNCTION(void,png_crc_read,(png_structrp png_ptr, png_bytep buf, + png_uint_32 length),PNG_EMPTY); + +/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */ +PNG_INTERNAL_FUNCTION(int,png_crc_finish,(png_structrp png_ptr, + png_uint_32 skip),PNG_EMPTY); + +/* Read the CRC from the file and compare it to the libpng calculated CRC */ +PNG_INTERNAL_FUNCTION(int,png_crc_error,(png_structrp png_ptr),PNG_EMPTY); + +/* Calculate the CRC over a section of data. Note that we are only + * passing a maximum of 64K on systems that have this as a memory limit, + * since this is the maximum buffer size we can specify. + */ +PNG_INTERNAL_FUNCTION(void,png_calculate_crc,(png_structrp png_ptr, + png_const_bytep ptr, png_size_t length),PNG_EMPTY); + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_flush,(png_structrp png_ptr),PNG_EMPTY); +#endif + +/* Write various chunks */ + +/* Write the IHDR chunk, and update the png_struct with the necessary + * information. + */ +PNG_INTERNAL_FUNCTION(void,png_write_IHDR,(png_structrp png_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, + int compression_method, int filter_method, int interlace_method),PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_write_PLTE,(png_structrp png_ptr, + png_const_colorp palette, png_uint_32 num_pal),PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_compress_IDAT,(png_structrp png_ptr, + png_const_bytep row_data, png_alloc_size_t row_data_length, int flush), + PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_write_IEND,(png_structrp png_ptr),PNG_EMPTY); + +#ifdef PNG_WRITE_gAMA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_gAMA_fixed,(png_structrp png_ptr, + png_fixed_point file_gamma),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_sBIT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_sBIT,(png_structrp png_ptr, + png_const_color_8p sbit, int color_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_cHRM_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_cHRM_fixed,(png_structrp png_ptr, + const png_xy *xy), PNG_EMPTY); + /* The xy value must have been previously validated */ +#endif + +#ifdef PNG_WRITE_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_sRGB,(png_structrp png_ptr, + int intent),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_iCCP_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_iCCP,(png_structrp png_ptr, + png_const_charp name, png_const_bytep profile), PNG_EMPTY); + /* The profile must have been previously validated for correctness, the + * length comes from the first four bytes. Only the base, deflate, + * compression is supported. + */ +#endif + +#ifdef PNG_WRITE_sPLT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_sPLT,(png_structrp png_ptr, + png_const_sPLT_tp palette),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_tRNS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_tRNS,(png_structrp png_ptr, + png_const_bytep trans, png_const_color_16p values, int number, + int color_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_bKGD_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_bKGD,(png_structrp png_ptr, + png_const_color_16p values, int color_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_hIST_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_hIST,(png_structrp png_ptr, + png_const_uint_16p hist, int num_hist),PNG_EMPTY); +#endif + +/* Chunks that have keywords */ +#ifdef PNG_WRITE_tEXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_tEXt,(png_structrp png_ptr, + png_const_charp key, png_const_charp text, png_size_t text_len),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_zTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_zTXt,(png_structrp png_ptr, png_const_charp + key, png_const_charp text, int compression),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_iTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_iTXt,(png_structrp png_ptr, + int compression, png_const_charp key, png_const_charp lang, + png_const_charp lang_key, png_const_charp text),PNG_EMPTY); +#endif + +#ifdef PNG_TEXT_SUPPORTED /* Added at version 1.0.14 and 1.2.4 */ +PNG_INTERNAL_FUNCTION(int,png_set_text_2,(png_const_structrp png_ptr, + png_inforp info_ptr, png_const_textp text_ptr, int num_text),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_oFFs_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_oFFs,(png_structrp png_ptr, + png_int_32 x_offset, png_int_32 y_offset, int unit_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_pCAL_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_pCAL,(png_structrp png_ptr, + png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, + png_const_charp units, png_charpp params),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_pHYs_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_pHYs,(png_structrp png_ptr, + png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, + int unit_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_tIME_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_tIME,(png_structrp png_ptr, + png_const_timep mod_time),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_sCAL_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_sCAL_s,(png_structrp png_ptr, + int unit, png_const_charp width, png_const_charp height),PNG_EMPTY); +#endif + +/* Called when finished processing a row of data */ +PNG_INTERNAL_FUNCTION(void,png_write_finish_row,(png_structrp png_ptr), + PNG_EMPTY); + +/* Internal use only. Called before first row of data */ +PNG_INTERNAL_FUNCTION(void,png_write_start_row,(png_structrp png_ptr), + PNG_EMPTY); + +/* Combine a row of data, dealing with alpha, etc. if requested. 'row' is an + * array of png_ptr->width pixels. If the image is not interlaced or this + * is the final pass this just does a memcpy, otherwise the "display" flag + * is used to determine whether to copy pixels that are not in the current pass. + * + * Because 'png_do_read_interlace' (below) replicates pixels this allows this + * function to achieve the documented 'blocky' appearance during interlaced read + * if display is 1 and the 'sparkle' appearance, where existing pixels in 'row' + * are not changed if they are not in the current pass, when display is 0. + * + * 'display' must be 0 or 1, otherwise the memcpy will be done regardless. + * + * The API always reads from the png_struct row buffer and always assumes that + * it is full width (png_do_read_interlace has already been called.) + * + * This function is only ever used to write to row buffers provided by the + * caller of the relevant libpng API and the row must have already been + * transformed by the read transformations. + * + * The PNG_USE_COMPILE_TIME_MASKS option causes generation of pre-computed + * bitmasks for use within the code, otherwise runtime generated masks are used. + * The default is compile time masks. + */ +#ifndef PNG_USE_COMPILE_TIME_MASKS +# define PNG_USE_COMPILE_TIME_MASKS 1 +#endif +PNG_INTERNAL_FUNCTION(void,png_combine_row,(png_const_structrp png_ptr, + png_bytep row, int display),PNG_EMPTY); + +#ifdef PNG_READ_INTERLACING_SUPPORTED +/* Expand an interlaced row: the 'row_info' describes the pass data that has + * been read in and must correspond to the pixels in 'row', the pixels are + * expanded (moved apart) in 'row' to match the final layout, when doing this + * the pixels are *replicated* to the intervening space. This is essential for + * the correct operation of png_combine_row, above. + */ +PNG_INTERNAL_FUNCTION(void,png_do_read_interlace,(png_row_infop row_info, + png_bytep row, int pass, png_uint_32 transformations),PNG_EMPTY); +#endif + +/* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */ + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED +/* Grab pixels out of a row for an interlaced pass */ +PNG_INTERNAL_FUNCTION(void,png_do_write_interlace,(png_row_infop row_info, + png_bytep row, int pass),PNG_EMPTY); +#endif + +/* Unfilter a row: check the filter value before calling this, there is no point + * calling it for PNG_FILTER_VALUE_NONE. + */ +PNG_INTERNAL_FUNCTION(void,png_read_filter_row,(png_structrp pp, png_row_infop + row_info, png_bytep row, png_const_bytep prev_row, int filter),PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_neon,(png_row_infop row_info, + png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); + +/* Choose the best filter to use and filter the row data */ +PNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_read_IDAT_data,(png_structrp png_ptr, + png_bytep output, png_alloc_size_t avail_out),PNG_EMPTY); + /* Read 'avail_out' bytes of data from the IDAT stream. If the output buffer + * is NULL the function checks, instead, for the end of the stream. In this + * case a benign error will be issued if the stream end is not found or if + * extra data has to be consumed. + */ +PNG_INTERNAL_FUNCTION(void,png_read_finish_IDAT,(png_structrp png_ptr), + PNG_EMPTY); + /* This cleans up when the IDAT LZ stream does not end when the last image + * byte is read; there is still some pending input. + */ + +PNG_INTERNAL_FUNCTION(void,png_read_finish_row,(png_structrp png_ptr), + PNG_EMPTY); + /* Finish a row while reading, dealing with interlacing passes, etc. */ +#endif /* SEQUENTIAL_READ */ + +/* Initialize the row buffers, etc. */ +PNG_INTERNAL_FUNCTION(void,png_read_start_row,(png_structrp png_ptr),PNG_EMPTY); + +#if PNG_ZLIB_VERNUM >= 0x1240 +PNG_INTERNAL_FUNCTION(int,png_zlib_inflate,(png_structrp png_ptr, int flush), + PNG_EMPTY); +# define PNG_INFLATE(pp, flush) png_zlib_inflate(pp, flush) +#else /* Zlib < 1.2.4 */ +# define PNG_INFLATE(pp, flush) inflate(&(pp)->zstream, flush) +#endif /* Zlib < 1.2.4 */ + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +/* Optional call to update the users info structure */ +PNG_INTERNAL_FUNCTION(void,png_read_transform_info,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +#endif + +/* Shared transform functions, defined in pngtran.c */ +#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ + defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_strip_channel,(png_row_infop row_info, + png_bytep row, int at_start),PNG_EMPTY); +#endif + +#ifdef PNG_16BIT_SUPPORTED +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_swap,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ + defined(PNG_WRITE_PACKSWAP_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_packswap,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_invert,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_bgr,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +/* The following decodes the appropriate chunks, and does error correction, + * then calls the appropriate callback for the chunk if it is valid. + */ + +/* Decode the IHDR chunk */ +PNG_INTERNAL_FUNCTION(void,png_handle_IHDR,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_handle_PLTE,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_handle_IEND,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); + +#ifdef PNG_READ_bKGD_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_bKGD,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_cHRM_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_cHRM,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_gAMA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_gAMA,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_hIST_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_hIST,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_iCCP_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_iCCP,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif /* READ_iCCP */ + +#ifdef PNG_READ_iTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_iTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_oFFs_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_oFFs,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_pCAL,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_pHYs_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_pHYs,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_sBIT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_sBIT,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_sCAL_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_sCAL,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_sPLT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_sPLT,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif /* READ_sPLT */ + +#ifdef PNG_READ_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_sRGB,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_tEXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_tEXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_tIME_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_tIME,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_tRNS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_tRNS,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_zTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_zTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +PNG_INTERNAL_FUNCTION(void,png_check_chunk_name,(png_structrp png_ptr, + png_uint_32 chunk_name),PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_handle_unknown,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length, int keep),PNG_EMPTY); + /* This is the function that gets called for unknown chunks. The 'keep' + * argument is either non-zero for a known chunk that has been set to be + * handled as unknown or zero for an unknown chunk. By default the function + * just skips the chunk or errors out if it is critical. + */ + +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\ + defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) +PNG_INTERNAL_FUNCTION(int,png_chunk_unknown_handling, + (png_const_structrp png_ptr, png_uint_32 chunk_name),PNG_EMPTY); + /* Exactly as the API png_handle_as_unknown() except that the argument is a + * 32-bit chunk name, not a string. + */ +#endif /* READ_UNKNOWN_CHUNKS || HANDLE_AS_UNKNOWN */ + +/* Handle the transformations for reading and writing */ +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_read_transformations,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); +#endif +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_write_transformations,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); +#endif + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_init_read_transformations,(png_structrp png_ptr), + PNG_EMPTY); +#endif + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_push_read_chunk,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_sig,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_check_crc,(png_structrp png_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_save_buffer,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_restore_buffer,(png_structrp png_ptr, + png_bytep buffer, png_size_t buffer_length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_IDAT,(png_structrp png_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_process_IDAT_data,(png_structrp png_ptr, + png_bytep buffer, png_size_t buffer_length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_process_row,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_handle_unknown,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_info,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_end,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_row,(png_structrp png_ptr, + png_bytep row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_end,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_process_some_data,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_push_finish_row,(png_structrp png_ptr), + PNG_EMPTY); +# ifdef PNG_READ_tEXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_push_handle_tEXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_tEXt,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +# endif +# ifdef PNG_READ_zTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_push_handle_zTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_zTXt,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +# endif +# ifdef PNG_READ_iTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_push_handle_iTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_iTXt,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +# endif + +#endif /* PROGRESSIVE_READ */ + +/* Added at libpng version 1.6.0 */ +#ifdef PNG_GAMMA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_colorspace_set_gamma,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_fixed_point gAMA), PNG_EMPTY); + /* Set the colorspace gamma with a value provided by the application or by + * the gAMA chunk on read. The value will override anything set by an ICC + * profile. + */ + +PNG_INTERNAL_FUNCTION(void,png_colorspace_sync_info,(png_const_structrp png_ptr, + png_inforp info_ptr), PNG_EMPTY); + /* Synchronize the info 'valid' flags with the colorspace */ + +PNG_INTERNAL_FUNCTION(void,png_colorspace_sync,(png_const_structrp png_ptr, + png_inforp info_ptr), PNG_EMPTY); + /* Copy the png_struct colorspace to the info_struct and call the above to + * synchronize the flags. Checks for NULL info_ptr and does nothing. + */ +#endif + +/* Added at libpng version 1.4.0 */ +#ifdef PNG_COLORSPACE_SUPPORTED +/* These internal functions are for maintaining the colorspace structure within + * a png_info or png_struct (or, indeed, both). + */ +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_chromaticities, + (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_xy *xy, + int preferred), PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_endpoints, + (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_XYZ *XYZ, + int preferred), PNG_EMPTY); + +#ifdef PNG_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_sRGB,(png_const_structrp png_ptr, + png_colorspacerp colorspace, int intent), PNG_EMPTY); + /* This does set the colorspace gAMA and cHRM values too, but doesn't set the + * flags to write them, if it returns false there was a problem and an error + * message has already been output (but the colorspace may still need to be + * synced to record the invalid flag). + */ +#endif /* sRGB */ + +#ifdef PNG_iCCP_SUPPORTED +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_ICC,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length, png_const_bytep profile, int color_type), + PNG_EMPTY); + /* The 'name' is used for information only */ + +/* Routines for checking parts of an ICC profile. */ +PNG_INTERNAL_FUNCTION(int,png_icc_check_length,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length), PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_icc_check_header,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length, + png_const_bytep profile /* first 132 bytes only */, int color_type), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_icc_check_tag_table,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length, + png_const_bytep profile /* header plus whole tag table */), PNG_EMPTY); +#ifdef PNG_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_icc_set_sRGB,( + png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_bytep profile, uLong adler), PNG_EMPTY); + /* 'adler' is the Adler32 checksum of the uncompressed profile data. It may + * be zero to indicate that it is not available. It is used, if provided, + * as a fast check on the profile when checking to see if it is sRGB. + */ +#endif +#endif /* iCCP */ + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_colorspace_set_rgb_coefficients, + (png_structrp png_ptr), PNG_EMPTY); + /* Set the rgb_to_gray coefficients from the colorspace Y values */ +#endif /* READ_RGB_TO_GRAY */ +#endif /* COLORSPACE */ + +/* Added at libpng version 1.4.0 */ +PNG_INTERNAL_FUNCTION(void,png_check_IHDR,(png_const_structrp png_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type),PNG_EMPTY); + +/* Added at libpng version 1.5.10 */ +#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \ + defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_check_palette_indexes, + (png_structrp png_ptr, png_row_infop row_info),PNG_EMPTY); +#endif + +#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_fixed_error,(png_const_structrp png_ptr, + png_const_charp name),PNG_NORETURN); +#endif + +/* Puts 'string' into 'buffer' at buffer[pos], taking care never to overwrite + * the end. Always leaves the buffer nul terminated. Never errors out (and + * there is no error code.) + */ +PNG_INTERNAL_FUNCTION(size_t,png_safecat,(png_charp buffer, size_t bufsize, + size_t pos, png_const_charp string),PNG_EMPTY); + +/* Various internal functions to handle formatted warning messages, currently + * only implemented for warnings. + */ +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED) +/* Utility to dump an unsigned value into a buffer, given a start pointer and + * and end pointer (which should point just *beyond* the end of the buffer!) + * Returns the pointer to the start of the formatted string. This utility only + * does unsigned values. + */ +PNG_INTERNAL_FUNCTION(png_charp,png_format_number,(png_const_charp start, + png_charp end, int format, png_alloc_size_t number),PNG_EMPTY); + +/* Convenience macro that takes an array: */ +#define PNG_FORMAT_NUMBER(buffer,format,number) \ + png_format_number(buffer, buffer + (sizeof buffer), format, number) + +/* Suggested size for a number buffer (enough for 64 bits and a sign!) */ +#define PNG_NUMBER_BUFFER_SIZE 24 + +/* These are the integer formats currently supported, the name is formed from + * the standard printf(3) format string. + */ +#define PNG_NUMBER_FORMAT_u 1 /* chose unsigned API! */ +#define PNG_NUMBER_FORMAT_02u 2 +#define PNG_NUMBER_FORMAT_d 1 /* chose signed API! */ +#define PNG_NUMBER_FORMAT_02d 2 +#define PNG_NUMBER_FORMAT_x 3 +#define PNG_NUMBER_FORMAT_02x 4 +#define PNG_NUMBER_FORMAT_fixed 5 /* choose the signed API */ +#endif + +#ifdef PNG_WARNINGS_SUPPORTED +/* New defines and members adding in libpng-1.5.4 */ +# define PNG_WARNING_PARAMETER_SIZE 32 +# define PNG_WARNING_PARAMETER_COUNT 8 /* Maximum 9; see pngerror.c */ + +/* An l-value of this type has to be passed to the APIs below to cache the + * values of the parameters to a formatted warning message. + */ +typedef char png_warning_parameters[PNG_WARNING_PARAMETER_COUNT][ + PNG_WARNING_PARAMETER_SIZE]; + +PNG_INTERNAL_FUNCTION(void,png_warning_parameter,(png_warning_parameters p, + int number, png_const_charp string),PNG_EMPTY); + /* Parameters are limited in size to PNG_WARNING_PARAMETER_SIZE characters, + * including the trailing '\0'. + */ +PNG_INTERNAL_FUNCTION(void,png_warning_parameter_unsigned, + (png_warning_parameters p, int number, int format, png_alloc_size_t value), + PNG_EMPTY); + /* Use png_alloc_size_t because it is an unsigned type as big as any we + * need to output. Use the following for a signed value. + */ +PNG_INTERNAL_FUNCTION(void,png_warning_parameter_signed, + (png_warning_parameters p, int number, int format, png_int_32 value), + PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_formatted_warning,(png_const_structrp png_ptr, + png_warning_parameters p, png_const_charp message),PNG_EMPTY); + /* 'message' follows the X/Open approach of using @1, @2 to insert + * parameters previously supplied using the above functions. Errors in + * specifying the parameters will simply result in garbage substitutions. + */ +#endif + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +/* Application errors (new in 1.6); use these functions (declared below) for + * errors in the parameters or order of API function calls on read. The + * 'warning' should be used for an error that can be handled completely; the + * 'error' for one which can be handled safely but which may lose application + * information or settings. + * + * By default these both result in a png_error call prior to release, while in a + * released version the 'warning' is just a warning. However if the application + * explicitly disables benign errors (explicitly permitting the code to lose + * information) they both turn into warnings. + * + * If benign errors aren't supported they end up as the corresponding base call + * (png_warning or png_error.) + */ +PNG_INTERNAL_FUNCTION(void,png_app_warning,(png_const_structrp png_ptr, + png_const_charp message),PNG_EMPTY); + /* The application provided invalid parameters to an API function or called + * an API function at the wrong time, libpng can completely recover. + */ + +PNG_INTERNAL_FUNCTION(void,png_app_error,(png_const_structrp png_ptr, + png_const_charp message),PNG_EMPTY); + /* As above but libpng will ignore the call, or attempt some other partial + * recovery from the error. + */ +#else +# define png_app_warning(pp,s) png_warning(pp,s) +# define png_app_error(pp,s) png_error(pp,s) +#endif + +PNG_INTERNAL_FUNCTION(void,png_chunk_report,(png_const_structrp png_ptr, + png_const_charp message, int error),PNG_EMPTY); + /* Report a recoverable issue in chunk data. On read this is used to report + * a problem found while reading a particular chunk and the + * png_chunk_benign_error or png_chunk_warning function is used as + * appropriate. On write this is used to report an error that comes from + * data set via an application call to a png_set_ API and png_app_error or + * png_app_warning is used as appropriate. + * + * The 'error' parameter must have one of the following values: + */ +#define PNG_CHUNK_WARNING 0 /* never an error */ +#define PNG_CHUNK_WRITE_ERROR 1 /* an error only on write */ +#define PNG_CHUNK_ERROR 2 /* always an error */ + +/* ASCII to FP interfaces, currently only implemented if sCAL + * support is required. + */ +#if defined(PNG_sCAL_SUPPORTED) +/* MAX_DIGITS is actually the maximum number of characters in an sCAL + * width or height, derived from the precision (number of significant + * digits - a build time settable option) and assumptions about the + * maximum ridiculous exponent. + */ +#define PNG_sCAL_MAX_DIGITS (PNG_sCAL_PRECISION+1/*.*/+1/*E*/+10/*exponent*/) + +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_ascii_from_fp,(png_const_structrp png_ptr, + png_charp ascii, png_size_t size, double fp, unsigned int precision), + PNG_EMPTY); +#endif /* FLOATING_POINT */ + +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_ascii_from_fixed,(png_const_structrp png_ptr, + png_charp ascii, png_size_t size, png_fixed_point fp),PNG_EMPTY); +#endif /* FIXED_POINT */ +#endif /* sCAL */ + +#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) +/* An internal API to validate the format of a floating point number. + * The result is the index of the next character. If the number is + * not valid it will be the index of a character in the supposed number. + * + * The format of a number is defined in the PNG extensions specification + * and this API is strictly conformant to that spec, not anyone elses! + * + * The format as a regular expression is: + * + * [+-]?[0-9]+.?([Ee][+-]?[0-9]+)? + * + * or: + * + * [+-]?.[0-9]+(.[0-9]+)?([Ee][+-]?[0-9]+)? + * + * The complexity is that either integer or fraction must be present and the + * fraction is permitted to have no digits only if the integer is present. + * + * NOTE: The dangling E problem. + * There is a PNG valid floating point number in the following: + * + * PNG floating point numbers are not greedy. + * + * Working this out requires *TWO* character lookahead (because of the + * sign), the parser does not do this - it will fail at the 'r' - this + * doesn't matter for PNG sCAL chunk values, but it requires more care + * if the value were ever to be embedded in something more complex. Use + * ANSI-C strtod if you need the lookahead. + */ +/* State table for the parser. */ +#define PNG_FP_INTEGER 0 /* before or in integer */ +#define PNG_FP_FRACTION 1 /* before or in fraction */ +#define PNG_FP_EXPONENT 2 /* before or in exponent */ +#define PNG_FP_STATE 3 /* mask for the above */ +#define PNG_FP_SAW_SIGN 4 /* Saw +/- in current state */ +#define PNG_FP_SAW_DIGIT 8 /* Saw a digit in current state */ +#define PNG_FP_SAW_DOT 16 /* Saw a dot in current state */ +#define PNG_FP_SAW_E 32 /* Saw an E (or e) in current state */ +#define PNG_FP_SAW_ANY 60 /* Saw any of the above 4 */ + +/* These three values don't affect the parser. They are set but not used. + */ +#define PNG_FP_WAS_VALID 64 /* Preceding substring is a valid fp number */ +#define PNG_FP_NEGATIVE 128 /* A negative number, including "-0" */ +#define PNG_FP_NONZERO 256 /* A non-zero value */ +#define PNG_FP_STICKY 448 /* The above three flags */ + +/* This is available for the caller to store in 'state' if required. Do not + * call the parser after setting it (the parser sometimes clears it.) + */ +#define PNG_FP_INVALID 512 /* Available for callers as a distinct value */ + +/* Result codes for the parser (boolean - true meants ok, false means + * not ok yet.) + */ +#define PNG_FP_MAYBE 0 /* The number may be valid in the future */ +#define PNG_FP_OK 1 /* The number is valid */ + +/* Tests on the sticky non-zero and negative flags. To pass these checks + * the state must also indicate that the whole number is valid - this is + * achieved by testing PNG_FP_SAW_DIGIT (see the implementation for why this + * is equivalent to PNG_FP_OK above.) + */ +#define PNG_FP_NZ_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NEGATIVE | PNG_FP_NONZERO) + /* NZ_MASK: the string is valid and a non-zero negative value */ +#define PNG_FP_Z_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NONZERO) + /* Z MASK: the string is valid and a non-zero value. */ + /* PNG_FP_SAW_DIGIT: the string is valid. */ +#define PNG_FP_IS_ZERO(state) (((state) & PNG_FP_Z_MASK) == PNG_FP_SAW_DIGIT) +#define PNG_FP_IS_POSITIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_Z_MASK) +#define PNG_FP_IS_NEGATIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_NZ_MASK) + +/* The actual parser. This can be called repeatedly. It updates + * the index into the string and the state variable (which must + * be initialized to 0). It returns a result code, as above. There + * is no point calling the parser any more if it fails to advance to + * the end of the string - it is stuck on an invalid character (or + * terminated by '\0'). + * + * Note that the pointer will consume an E or even an E+ and then leave + * a 'maybe' state even though a preceding integer.fraction is valid. + * The PNG_FP_WAS_VALID flag indicates that a preceding substring was + * a valid number. It's possible to recover from this by calling + * the parser again (from the start, with state 0) but with a string + * that omits the last character (i.e. set the size to the index of + * the problem character.) This has not been tested within libpng. + */ +PNG_INTERNAL_FUNCTION(int,png_check_fp_number,(png_const_charp string, + png_size_t size, int *statep, png_size_tp whereami),PNG_EMPTY); + +/* This is the same but it checks a complete string and returns true + * only if it just contains a floating point number. As of 1.5.4 this + * function also returns the state at the end of parsing the number if + * it was valid (otherwise it returns 0.) This can be used for testing + * for negative or zero values using the sticky flag. + */ +PNG_INTERNAL_FUNCTION(int,png_check_fp_string,(png_const_charp string, + png_size_t size),PNG_EMPTY); +#endif /* pCAL || sCAL */ + +#if defined(PNG_GAMMA_SUPPORTED) ||\ + defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED) +/* Added at libpng version 1.5.0 */ +/* This is a utility to provide a*times/div (rounded) and indicate + * if there is an overflow. The result is a boolean - false (0) + * for overflow, true (1) if no overflow, in which case *res + * holds the result. + */ +PNG_INTERNAL_FUNCTION(int,png_muldiv,(png_fixed_point_p res, png_fixed_point a, + png_int_32 multiplied_by, png_int_32 divided_by),PNG_EMPTY); +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED) +/* Same deal, but issue a warning on overflow and return 0. */ +PNG_INTERNAL_FUNCTION(png_fixed_point,png_muldiv_warn, + (png_const_structrp png_ptr, png_fixed_point a, png_int_32 multiplied_by, + png_int_32 divided_by),PNG_EMPTY); +#endif + +#ifdef PNG_GAMMA_SUPPORTED +/* Calculate a reciprocal - used for gamma values. This returns + * 0 if the argument is 0 in order to maintain an undefined value; + * there are no warnings. + */ +PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal,(png_fixed_point a), + PNG_EMPTY); + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* The same but gives a reciprocal of the product of two fixed point + * values. Accuracy is suitable for gamma calculations but this is + * not exact - use png_muldiv for that. Only required at present on read. + */ +PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal2,(png_fixed_point a, + png_fixed_point b),PNG_EMPTY); +#endif + +/* Return true if the gamma value is significantly different from 1.0 */ +PNG_INTERNAL_FUNCTION(int,png_gamma_significant,(png_fixed_point gamma_value), + PNG_EMPTY); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* Internal fixed point gamma correction. These APIs are called as + * required to convert single values - they don't need to be fast, + * they are not used when processing image pixel values. + * + * While the input is an 'unsigned' value it must actually be the + * correct bit value - 0..255 or 0..65535 as required. + */ +PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_correct,(png_structrp png_ptr, + unsigned int value, png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_16bit_correct,(unsigned int value, + png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(png_byte,png_gamma_8bit_correct,(unsigned int value, + png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_destroy_gamma_table,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_build_gamma_table,(png_structrp png_ptr, + int bit_depth),PNG_EMPTY); +#endif + +/* SIMPLIFIED READ/WRITE SUPPORT */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +/* The internal structure that png_image::opaque points to. */ +typedef struct png_control +{ + png_structp png_ptr; + png_infop info_ptr; + png_voidp error_buf; /* Always a jmp_buf at present. */ + + png_const_bytep memory; /* Memory buffer. */ + png_size_t size; /* Size of the memory buffer. */ + + unsigned int for_write :1; /* Otherwise it is a read structure */ + unsigned int owned_file :1; /* We own the file in io_ptr */ +} png_control; + +/* Return the pointer to the jmp_buf from a png_control: necessary because C + * does not reveal the type of the elements of jmp_buf. + */ +#ifdef __cplusplus +# define png_control_jmp_buf(pc) (((jmp_buf*)((pc)->error_buf))[0]) +#else +# define png_control_jmp_buf(pc) ((pc)->error_buf) +#endif + +/* Utility to safely execute a piece of libpng code catching and logging any + * errors that might occur. Returns true on success, false on failure (either + * of the function or as a result of a png_error.) + */ +PNG_INTERNAL_CALLBACK(void,png_safe_error,(png_structp png_ptr, + png_const_charp error_message),PNG_NORETURN); + +#ifdef PNG_WARNINGS_SUPPORTED +PNG_INTERNAL_CALLBACK(void,png_safe_warning,(png_structp png_ptr, + png_const_charp warning_message),PNG_EMPTY); +#else +# define png_safe_warning 0/*dummy argument*/ +#endif + +PNG_INTERNAL_FUNCTION(int,png_safe_execute,(png_imagep image, + int (*function)(png_voidp), png_voidp arg),PNG_EMPTY); + +/* Utility to log an error; this also cleans up the png_image; the function + * always returns 0 (false). + */ +PNG_INTERNAL_FUNCTION(int,png_image_error,(png_imagep image, + png_const_charp error_message),PNG_EMPTY); + +#ifndef PNG_SIMPLIFIED_READ_SUPPORTED +/* png_image_free is used by the write code but not exported */ +PNG_INTERNAL_FUNCTION(void, png_image_free, (png_imagep image), PNG_EMPTY); +#endif /* !SIMPLIFIED_READ */ + +#endif /* SIMPLIFIED READ/WRITE */ + +/* These are initialization functions for hardware specific PNG filter + * optimizations; list these here then select the appropriate one at compile + * time using the macro PNG_FILTER_OPTIMIZATIONS. If the macro is not defined + * the generic code is used. + */ +#ifdef PNG_FILTER_OPTIMIZATIONS +PNG_INTERNAL_FUNCTION(void, PNG_FILTER_OPTIMIZATIONS, (png_structp png_ptr, + unsigned int bpp), PNG_EMPTY); + /* Just declare the optimization that will be used */ +#else + /* List *all* the possible optimizations here - this branch is required if + * the builder of libpng passes the definition of PNG_FILTER_OPTIMIZATIONS in + * CFLAGS in place of CPPFLAGS *and* uses symbol prefixing. + */ +PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_neon, + (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); +#endif + +PNG_INTERNAL_FUNCTION(png_uint_32, png_check_keyword, (png_structrp png_ptr, + png_const_charp key, png_bytep new_key), PNG_EMPTY); + +/* Maintainer: Put new private prototypes here ^ */ + +#include "pngdebug.h" + +#ifdef __cplusplus +} +#endif + +#endif /* PNG_VERSION_INFO_ONLY */ +#endif /* PNGPRIV_H */ diff --git a/source/Irrlicht/libpng/pngread.c b/source/Irrlicht/libpng/pngread.c new file mode 100644 index 00000000..41c9e772 --- /dev/null +++ b/source/Irrlicht/libpng/pngread.c @@ -0,0 +1,4172 @@ + +/* pngread.c - read a PNG file + * + * Last changed in libpng 1.6.23 [June 9, 2016] + * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file contains routines that an application calls directly to + * read a PNG file or stream. + */ + +#include "pngpriv.h" +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) +# include +#endif + +#ifdef PNG_READ_SUPPORTED + +/* Create a PNG structure for reading, and allocate any memory needed. */ +PNG_FUNCTION(png_structp,PNGAPI +png_create_read_struct,(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED) +{ +#ifndef PNG_USER_MEM_SUPPORTED + png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, NULL, NULL, NULL); +#else + return png_create_read_struct_2(user_png_ver, error_ptr, error_fn, + warn_fn, NULL, NULL, NULL); +} + +/* Alternate create PNG structure for reading, and allocate any memory + * needed. + */ +PNG_FUNCTION(png_structp,PNGAPI +png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) +{ + png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); +#endif /* USER_MEM */ + + if (png_ptr != NULL) + { + png_ptr->mode = PNG_IS_READ_STRUCT; + + /* Added in libpng-1.6.0; this can be used to detect a read structure if + * required (it will be zero in a write structure.) + */ +# ifdef PNG_SEQUENTIAL_READ_SUPPORTED + png_ptr->IDAT_read_size = PNG_IDAT_READ_SIZE; +# endif + +# ifdef PNG_BENIGN_READ_ERRORS_SUPPORTED + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; + + /* In stable builds only warn if an application error can be completely + * handled. + */ +# if PNG_RELEASE_BUILD + png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; +# endif +# endif + + /* TODO: delay this, it can be done in png_init_io (if the app doesn't + * do it itself) avoiding setting the default function if it is not + * required. + */ + png_set_read_fn(png_ptr, NULL, NULL); + } + + return png_ptr; +} + + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the information before the actual image data. This has been + * changed in v0.90 to allow reading a file that already has the magic + * bytes read from the stream. You can tell libpng how many bytes have + * been read from the beginning of the stream (up to the maximum of 8) + * via png_set_sig_bytes(), and we will only check the remaining bytes + * here. The application can then have access to the signature bytes we + * read if it is determined that this isn't a valid PNG file. + */ +void PNGAPI +png_read_info(png_structrp png_ptr, png_inforp info_ptr) +{ +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + int keep; +#endif + + png_debug(1, "in png_read_info"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* Read and check the PNG file signature. */ + png_read_sig(png_ptr, info_ptr); + + for (;;) + { + png_uint_32 length = png_read_chunk_header(png_ptr); + png_uint_32 chunk_name = png_ptr->chunk_name; + + /* IDAT logic needs to happen here to simplify getting the two flags + * right. + */ + if (chunk_name == png_IDAT) + { + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "Missing IHDR before IDAT"); + + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + (png_ptr->mode & PNG_HAVE_PLTE) == 0) + png_chunk_error(png_ptr, "Missing PLTE before IDAT"); + + else if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) + png_chunk_benign_error(png_ptr, "Too many IDATs found"); + + png_ptr->mode |= PNG_HAVE_IDAT; + } + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + { + png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; + png_ptr->mode |= PNG_AFTER_IDAT; + } + + /* This should be a binary subdivision search or a hash for + * matching the chunk name rather than a linear search. + */ + if (chunk_name == png_IHDR) + png_handle_IHDR(png_ptr, info_ptr, length); + + else if (chunk_name == png_IEND) + png_handle_IEND(png_ptr, info_ptr, length); + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) + { + png_handle_unknown(png_ptr, info_ptr, length, keep); + + if (chunk_name == png_PLTE) + png_ptr->mode |= PNG_HAVE_PLTE; + + else if (chunk_name == png_IDAT) + { + png_ptr->idat_size = 0; /* It has been consumed */ + break; + } + } +#endif + else if (chunk_name == png_PLTE) + png_handle_PLTE(png_ptr, info_ptr, length); + + else if (chunk_name == png_IDAT) + { + png_ptr->idat_size = length; + break; + } + +#ifdef PNG_READ_bKGD_SUPPORTED + else if (chunk_name == png_bKGD) + png_handle_bKGD(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_cHRM_SUPPORTED + else if (chunk_name == png_cHRM) + png_handle_cHRM(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_gAMA_SUPPORTED + else if (chunk_name == png_gAMA) + png_handle_gAMA(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_hIST_SUPPORTED + else if (chunk_name == png_hIST) + png_handle_hIST(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_oFFs_SUPPORTED + else if (chunk_name == png_oFFs) + png_handle_oFFs(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED + else if (chunk_name == png_pCAL) + png_handle_pCAL(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sCAL_SUPPORTED + else if (chunk_name == png_sCAL) + png_handle_sCAL(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_pHYs_SUPPORTED + else if (chunk_name == png_pHYs) + png_handle_pHYs(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sBIT_SUPPORTED + else if (chunk_name == png_sBIT) + png_handle_sBIT(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sRGB_SUPPORTED + else if (chunk_name == png_sRGB) + png_handle_sRGB(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_iCCP_SUPPORTED + else if (chunk_name == png_iCCP) + png_handle_iCCP(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sPLT_SUPPORTED + else if (chunk_name == png_sPLT) + png_handle_sPLT(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_tEXt_SUPPORTED + else if (chunk_name == png_tEXt) + png_handle_tEXt(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_tIME_SUPPORTED + else if (chunk_name == png_tIME) + png_handle_tIME(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_tRNS_SUPPORTED + else if (chunk_name == png_tRNS) + png_handle_tRNS(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_zTXt_SUPPORTED + else if (chunk_name == png_zTXt) + png_handle_zTXt(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_iTXt_SUPPORTED + else if (chunk_name == png_iTXt) + png_handle_iTXt(png_ptr, info_ptr, length); +#endif + + else + png_handle_unknown(png_ptr, info_ptr, length, + PNG_HANDLE_CHUNK_AS_DEFAULT); + } +} +#endif /* SEQUENTIAL_READ */ + +/* Optional call to update the users info_ptr structure */ +void PNGAPI +png_read_update_info(png_structrp png_ptr, png_inforp info_ptr) +{ + png_debug(1, "in png_read_update_info"); + + if (png_ptr != NULL) + { + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + { + png_read_start_row(png_ptr); + +# ifdef PNG_READ_TRANSFORMS_SUPPORTED + png_read_transform_info(png_ptr, info_ptr); +# else + PNG_UNUSED(info_ptr) +# endif + } + + /* New in 1.6.0 this avoids the bug of doing the initializations twice */ + else + png_app_error(png_ptr, + "png_read_update_info/png_start_read_image: duplicate call"); + } +} + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Initialize palette, background, etc, after transformations + * are set, but before any reading takes place. This allows + * the user to obtain a gamma-corrected palette, for example. + * If the user doesn't call this, we will do it ourselves. + */ +void PNGAPI +png_start_read_image(png_structrp png_ptr) +{ + png_debug(1, "in png_start_read_image"); + + if (png_ptr != NULL) + { + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + png_read_start_row(png_ptr); + + /* New in 1.6.0 this avoids the bug of doing the initializations twice */ + else + png_app_error(png_ptr, + "png_start_read_image/png_read_update_info: duplicate call"); + } +} +#endif /* SEQUENTIAL_READ */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +#ifdef PNG_MNG_FEATURES_SUPPORTED +/* Undoes intrapixel differencing, + * NOTE: this is apparently only supported in the 'sequential' reader. + */ +static void +png_do_read_intrapixel(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_read_intrapixel"); + + if ( + (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + int bytes_per_pixel; + png_uint_32 row_width = row_info->width; + + if (row_info->bit_depth == 8) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 3; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 4; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + *(rp) = (png_byte)((256 + *rp + *(rp + 1)) & 0xff); + *(rp+2) = (png_byte)((256 + *(rp + 2) + *(rp + 1)) & 0xff); + } + } + else if (row_info->bit_depth == 16) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 6; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 8; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); + png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); + png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); + png_uint_32 red = (s0 + s1 + 65536) & 0xffff; + png_uint_32 blue = (s2 + s1 + 65536) & 0xffff; + *(rp ) = (png_byte)((red >> 8) & 0xff); + *(rp + 1) = (png_byte)(red & 0xff); + *(rp + 4) = (png_byte)((blue >> 8) & 0xff); + *(rp + 5) = (png_byte)(blue & 0xff); + } + } + } +} +#endif /* MNG_FEATURES */ + +void PNGAPI +png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row) +{ + png_row_info row_info; + + if (png_ptr == NULL) + return; + + png_debug2(1, "in png_read_row (row %lu, pass %d)", + (unsigned long)png_ptr->row_number, png_ptr->pass); + + /* png_read_start_row sets the information (in particular iwidth) for this + * interlace pass. + */ + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + png_read_start_row(png_ptr); + + /* 1.5.6: row_info moved out of png_struct to a local here. */ + row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */ + row_info.color_type = png_ptr->color_type; + row_info.bit_depth = png_ptr->bit_depth; + row_info.channels = png_ptr->channels; + row_info.pixel_depth = png_ptr->pixel_depth; + row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); + +#ifdef PNG_WARNINGS_SUPPORTED + if (png_ptr->row_number == 0 && png_ptr->pass == 0) + { + /* Check for transforms that have been set but were defined out */ +#if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED) + if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) + png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined"); +#endif + +#if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED) + if ((png_ptr->transformations & PNG_FILLER) != 0) + png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined"); +#endif + +#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ + !defined(PNG_READ_PACKSWAP_SUPPORTED) + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined"); +#endif + +#if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED) + if ((png_ptr->transformations & PNG_PACK) != 0) + png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined"); +#endif + +#if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) + if ((png_ptr->transformations & PNG_SHIFT) != 0) + png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined"); +#endif + +#if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED) + if ((png_ptr->transformations & PNG_BGR) != 0) + png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined"); +#endif + +#if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED) + if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) + png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined"); +#endif + } +#endif /* WARNINGS */ + +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* If interlaced and we do not need a new row, combine row and return. + * Notice that the pixels we have from previous rows have been transformed + * already; we can only combine like with like (transformed or + * untransformed) and, because of the libpng API for interlaced images, this + * means we must transform before de-interlacing. + */ + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0) + { + switch (png_ptr->pass) + { + case 0: + if (png_ptr->row_number & 0x07) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + png_read_finish_row(png_ptr); + return; + } + break; + + case 1: + if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + + png_read_finish_row(png_ptr); + return; + } + break; + + case 2: + if ((png_ptr->row_number & 0x07) != 4) + { + if (dsp_row != NULL && (png_ptr->row_number & 4)) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + + png_read_finish_row(png_ptr); + return; + } + break; + + case 3: + if ((png_ptr->row_number & 3) || png_ptr->width < 3) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + + png_read_finish_row(png_ptr); + return; + } + break; + + case 4: + if ((png_ptr->row_number & 3) != 2) + { + if (dsp_row != NULL && (png_ptr->row_number & 2)) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + + png_read_finish_row(png_ptr); + return; + } + break; + + case 5: + if ((png_ptr->row_number & 1) || png_ptr->width < 2) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + + png_read_finish_row(png_ptr); + return; + } + break; + + default: + case 6: + if ((png_ptr->row_number & 1) == 0) + { + png_read_finish_row(png_ptr); + return; + } + break; + } + } +#endif + + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0) + png_error(png_ptr, "Invalid attempt to read row data"); + + /* Fill the row with IDAT data: */ + png_read_IDAT_data(png_ptr, png_ptr->row_buf, row_info.rowbytes + 1); + + if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE) + { + if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST) + png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1, + png_ptr->prev_row + 1, png_ptr->row_buf[0]); + else + png_error(png_ptr, "bad adaptive filter value"); + } + + /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before + * 1.5.6, while the buffer really is this big in current versions of libpng + * it may not be in the future, so this was changed just to copy the + * interlaced count: + */ + memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1); + +#ifdef PNG_MNG_FEATURES_SUPPORTED + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) + { + /* Intrapixel differencing */ + png_do_read_intrapixel(&row_info, png_ptr->row_buf + 1); + } +#endif + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED + if (png_ptr->transformations) + png_do_read_transformations(png_ptr, &row_info); +#endif + + /* The transformed pixel depth should match the depth now in row_info. */ + if (png_ptr->transformed_pixel_depth == 0) + { + png_ptr->transformed_pixel_depth = row_info.pixel_depth; + if (row_info.pixel_depth > png_ptr->maximum_pixel_depth) + png_error(png_ptr, "sequential row overflow"); + } + + else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth) + png_error(png_ptr, "internal sequential row size calculation error"); + +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Expand interlaced rows to full size */ + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0) + { + if (png_ptr->pass < 6) + png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass, + png_ptr->transformations); + + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, 1/*display*/); + + if (row != NULL) + png_combine_row(png_ptr, row, 0/*row*/); + } + + else +#endif + { + if (row != NULL) + png_combine_row(png_ptr, row, -1/*ignored*/); + + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, -1/*ignored*/); + } + png_read_finish_row(png_ptr); + + if (png_ptr->read_row_fn != NULL) + (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); + +} +#endif /* SEQUENTIAL_READ */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read one or more rows of image data. If the image is interlaced, + * and png_set_interlace_handling() has been called, the rows need to + * contain the contents of the rows from the previous pass. If the + * image has alpha or transparency, and png_handle_alpha()[*] has been + * called, the rows contents must be initialized to the contents of the + * screen. + * + * "row" holds the actual image, and pixels are placed in it + * as they arrive. If the image is displayed after each pass, it will + * appear to "sparkle" in. "display_row" can be used to display a + * "chunky" progressive image, with finer detail added as it becomes + * available. If you do not want this "chunky" display, you may pass + * NULL for display_row. If you do not want the sparkle display, and + * you have not called png_handle_alpha(), you may pass NULL for rows. + * If you have called png_handle_alpha(), and the image has either an + * alpha channel or a transparency chunk, you must provide a buffer for + * rows. In this case, you do not have to provide a display_row buffer + * also, but you may. If the image is not interlaced, or if you have + * not called png_set_interlace_handling(), the display_row buffer will + * be ignored, so pass NULL to it. + * + * [*] png_handle_alpha() does not exist yet, as of this version of libpng + */ + +void PNGAPI +png_read_rows(png_structrp png_ptr, png_bytepp row, + png_bytepp display_row, png_uint_32 num_rows) +{ + png_uint_32 i; + png_bytepp rp; + png_bytepp dp; + + png_debug(1, "in png_read_rows"); + + if (png_ptr == NULL) + return; + + rp = row; + dp = display_row; + if (rp != NULL && dp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep rptr = *rp++; + png_bytep dptr = *dp++; + + png_read_row(png_ptr, rptr, dptr); + } + + else if (rp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep rptr = *rp; + png_read_row(png_ptr, rptr, NULL); + rp++; + } + + else if (dp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep dptr = *dp; + png_read_row(png_ptr, NULL, dptr); + dp++; + } +} +#endif /* SEQUENTIAL_READ */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the entire image. If the image has an alpha channel or a tRNS + * chunk, and you have called png_handle_alpha()[*], you will need to + * initialize the image to the current image that PNG will be overlaying. + * We set the num_rows again here, in case it was incorrectly set in + * png_read_start_row() by a call to png_read_update_info() or + * png_start_read_image() if png_set_interlace_handling() wasn't called + * prior to either of these functions like it should have been. You can + * only call this function once. If you desire to have an image for + * each pass of a interlaced image, use png_read_rows() instead. + * + * [*] png_handle_alpha() does not exist yet, as of this version of libpng + */ +void PNGAPI +png_read_image(png_structrp png_ptr, png_bytepp image) +{ + png_uint_32 i, image_height; + int pass, j; + png_bytepp rp; + + png_debug(1, "in png_read_image"); + + if (png_ptr == NULL) + return; + +#ifdef PNG_READ_INTERLACING_SUPPORTED + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + { + pass = png_set_interlace_handling(png_ptr); + /* And make sure transforms are initialized. */ + png_start_read_image(png_ptr); + } + else + { + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) == 0) + { + /* Caller called png_start_read_image or png_read_update_info without + * first turning on the PNG_INTERLACE transform. We can fix this here, + * but the caller should do it! + */ + png_warning(png_ptr, "Interlace handling should be turned on when " + "using png_read_image"); + /* Make sure this is set correctly */ + png_ptr->num_rows = png_ptr->height; + } + + /* Obtain the pass number, which also turns on the PNG_INTERLACE flag in + * the above error case. + */ + pass = png_set_interlace_handling(png_ptr); + } +#else + if (png_ptr->interlaced) + png_error(png_ptr, + "Cannot read interlaced image -- interlace handler disabled"); + + pass = 1; +#endif + + image_height=png_ptr->height; + + for (j = 0; j < pass; j++) + { + rp = image; + for (i = 0; i < image_height; i++) + { + png_read_row(png_ptr, *rp, NULL); + rp++; + } + } +} +#endif /* SEQUENTIAL_READ */ + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the end of the PNG file. Will not read past the end of the + * file, will verify the end is accurate, and will read any comments + * or time information at the end of the file, if info is not NULL. + */ +void PNGAPI +png_read_end(png_structrp png_ptr, png_inforp info_ptr) +{ +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + int keep; +#endif + + png_debug(1, "in png_read_end"); + + if (png_ptr == NULL) + return; + + /* If png_read_end is called in the middle of reading the rows there may + * still be pending IDAT data and an owned zstream. Deal with this here. + */ +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + if (png_chunk_unknown_handling(png_ptr, png_IDAT) == 0) +#endif + png_read_finish_IDAT(png_ptr); + +#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Report invalid palette index; added at libng-1.5.10 */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + png_ptr->num_palette_max > png_ptr->num_palette) + png_benign_error(png_ptr, "Read palette index exceeding num_palette"); +#endif + + do + { + png_uint_32 length = png_read_chunk_header(png_ptr); + png_uint_32 chunk_name = png_ptr->chunk_name; + + if (chunk_name != png_IDAT) + png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; + + if (chunk_name == png_IEND) + png_handle_IEND(png_ptr, info_ptr, length); + + else if (chunk_name == png_IHDR) + png_handle_IHDR(png_ptr, info_ptr, length); + + else if (info_ptr == NULL) + png_crc_finish(png_ptr, length); + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) + { + if (chunk_name == png_IDAT) + { + if ((length > 0 && !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) + || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0) + png_benign_error(png_ptr, ".Too many IDATs found"); + } + png_handle_unknown(png_ptr, info_ptr, length, keep); + if (chunk_name == png_PLTE) + png_ptr->mode |= PNG_HAVE_PLTE; + } +#endif + + else if (chunk_name == png_IDAT) + { + /* Zero length IDATs are legal after the last IDAT has been + * read, but not after other chunks have been read. 1.6 does not + * always read all the deflate data; specifically it cannot be relied + * upon to read the Adler32 at the end. If it doesn't ignore IDAT + * chunks which are longer than zero as well: + */ + if ((length > 0 && !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) + || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0) + png_benign_error(png_ptr, "..Too many IDATs found"); + + png_crc_finish(png_ptr, length); + } + else if (chunk_name == png_PLTE) + png_handle_PLTE(png_ptr, info_ptr, length); + +#ifdef PNG_READ_bKGD_SUPPORTED + else if (chunk_name == png_bKGD) + png_handle_bKGD(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_cHRM_SUPPORTED + else if (chunk_name == png_cHRM) + png_handle_cHRM(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_gAMA_SUPPORTED + else if (chunk_name == png_gAMA) + png_handle_gAMA(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_hIST_SUPPORTED + else if (chunk_name == png_hIST) + png_handle_hIST(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_oFFs_SUPPORTED + else if (chunk_name == png_oFFs) + png_handle_oFFs(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED + else if (chunk_name == png_pCAL) + png_handle_pCAL(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sCAL_SUPPORTED + else if (chunk_name == png_sCAL) + png_handle_sCAL(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_pHYs_SUPPORTED + else if (chunk_name == png_pHYs) + png_handle_pHYs(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sBIT_SUPPORTED + else if (chunk_name == png_sBIT) + png_handle_sBIT(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sRGB_SUPPORTED + else if (chunk_name == png_sRGB) + png_handle_sRGB(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_iCCP_SUPPORTED + else if (chunk_name == png_iCCP) + png_handle_iCCP(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sPLT_SUPPORTED + else if (chunk_name == png_sPLT) + png_handle_sPLT(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_tEXt_SUPPORTED + else if (chunk_name == png_tEXt) + png_handle_tEXt(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_tIME_SUPPORTED + else if (chunk_name == png_tIME) + png_handle_tIME(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_tRNS_SUPPORTED + else if (chunk_name == png_tRNS) + png_handle_tRNS(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_zTXt_SUPPORTED + else if (chunk_name == png_zTXt) + png_handle_zTXt(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_iTXt_SUPPORTED + else if (chunk_name == png_iTXt) + png_handle_iTXt(png_ptr, info_ptr, length); +#endif + + else + png_handle_unknown(png_ptr, info_ptr, length, + PNG_HANDLE_CHUNK_AS_DEFAULT); + } while ((png_ptr->mode & PNG_HAVE_IEND) == 0); +} +#endif /* SEQUENTIAL_READ */ + +/* Free all memory used in the read struct */ +static void +png_read_destroy(png_structrp png_ptr) +{ + png_debug(1, "in png_read_destroy"); + +#ifdef PNG_READ_GAMMA_SUPPORTED + png_destroy_gamma_table(png_ptr); +#endif + + png_free(png_ptr, png_ptr->big_row_buf); + png_ptr->big_row_buf = NULL; + png_free(png_ptr, png_ptr->big_prev_row); + png_ptr->big_prev_row = NULL; + png_free(png_ptr, png_ptr->read_buffer); + png_ptr->read_buffer = NULL; + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + png_free(png_ptr, png_ptr->palette_lookup); + png_ptr->palette_lookup = NULL; + png_free(png_ptr, png_ptr->quantize_index); + png_ptr->quantize_index = NULL; +#endif + + if ((png_ptr->free_me & PNG_FREE_PLTE) != 0) + { + png_zfree(png_ptr, png_ptr->palette); + png_ptr->palette = NULL; + } + png_ptr->free_me &= ~PNG_FREE_PLTE; + +#if defined(PNG_tRNS_SUPPORTED) || \ + defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if ((png_ptr->free_me & PNG_FREE_TRNS) != 0) + { + png_free(png_ptr, png_ptr->trans_alpha); + png_ptr->trans_alpha = NULL; + } + png_ptr->free_me &= ~PNG_FREE_TRNS; +#endif + + inflateEnd(&png_ptr->zstream); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + png_free(png_ptr, png_ptr->save_buffer); + png_ptr->save_buffer = NULL; +#endif + +#if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) && \ + defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + png_free(png_ptr, png_ptr->unknown_chunk.data); + png_ptr->unknown_chunk.data = NULL; +#endif + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list = NULL; +#endif + + /* NOTE: the 'setjmp' buffer may still be allocated and the memory and error + * callbacks are still set at this point. They are required to complete the + * destruction of the png_struct itself. + */ +} + +/* Free all memory used by the read */ +void PNGAPI +png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, + png_infopp end_info_ptr_ptr) +{ + png_structrp png_ptr = NULL; + + png_debug(1, "in png_destroy_read_struct"); + + if (png_ptr_ptr != NULL) + png_ptr = *png_ptr_ptr; + + if (png_ptr == NULL) + return; + + /* libpng 1.6.0: use the API to destroy info structs to ensure consistent + * behavior. Prior to 1.6.0 libpng did extra 'info' destruction in this API. + * The extra was, apparently, unnecessary yet this hides memory leak bugs. + */ + png_destroy_info_struct(png_ptr, end_info_ptr_ptr); + png_destroy_info_struct(png_ptr, info_ptr_ptr); + + *png_ptr_ptr = NULL; + png_read_destroy(png_ptr); + png_destroy_png_struct(png_ptr); +} + +void PNGAPI +png_set_read_status_fn(png_structrp png_ptr, png_read_status_ptr read_row_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->read_row_fn = read_row_fn; +} + + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +#ifdef PNG_INFO_IMAGE_SUPPORTED +void PNGAPI +png_read_png(png_structrp png_ptr, png_inforp info_ptr, + int transforms, + voidp params) +{ + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* png_read_info() gives us all of the information from the + * PNG file before the first IDAT (image data chunk). + */ + png_read_info(png_ptr, info_ptr); + if (info_ptr->height > PNG_UINT_32_MAX/(sizeof (png_bytep))) + png_error(png_ptr, "Image is too high to process with png_read_png()"); + + /* -------------- image transformations start here ------------------- */ + /* libpng 1.6.10: add code to cause a png_app_error if a selected TRANSFORM + * is not implemented. This will only happen in de-configured (non-default) + * libpng builds. The results can be unexpected - png_read_png may return + * short or mal-formed rows because the transform is skipped. + */ + + /* Tell libpng to strip 16-bit/color files down to 8 bits per color. + */ + if ((transforms & PNG_TRANSFORM_SCALE_16) != 0) + /* Added at libpng-1.5.4. "strip_16" produces the same result that it + * did in earlier versions, while "scale_16" is now more accurate. + */ +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + png_set_scale_16(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SCALE_16 not supported"); +#endif + + /* If both SCALE and STRIP are required pngrtran will effectively cancel the + * latter by doing SCALE first. This is ok and allows apps not to check for + * which is supported to get the right answer. + */ + if ((transforms & PNG_TRANSFORM_STRIP_16) != 0) +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + png_set_strip_16(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_16 not supported"); +#endif + + /* Strip alpha bytes from the input data without combining with + * the background (not recommended). + */ + if ((transforms & PNG_TRANSFORM_STRIP_ALPHA) != 0) +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + png_set_strip_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_ALPHA not supported"); +#endif + + /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single + * byte into separate bytes (useful for paletted and grayscale images). + */ + if ((transforms & PNG_TRANSFORM_PACKING) != 0) +#ifdef PNG_READ_PACK_SUPPORTED + png_set_packing(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported"); +#endif + + /* Change the order of packed pixels to least significant bit first + * (not useful if you are using png_set_packing). + */ + if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0) +#ifdef PNG_READ_PACKSWAP_SUPPORTED + png_set_packswap(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported"); +#endif + + /* Expand paletted colors into true RGB triplets + * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel + * Expand paletted or RGB images with transparency to full alpha + * channels so the data will be available as RGBA quartets. + */ + if ((transforms & PNG_TRANSFORM_EXPAND) != 0) +#ifdef PNG_READ_EXPAND_SUPPORTED + png_set_expand(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_EXPAND not supported"); +#endif + + /* We don't handle background color or gamma transformation or quantizing. + */ + + /* Invert monochrome files to have 0 as white and 1 as black + */ + if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0) +#ifdef PNG_READ_INVERT_SUPPORTED + png_set_invert_mono(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported"); +#endif + + /* If you want to shift the pixel values from the range [0,255] or + * [0,65535] to the original [0,7] or [0,31], or whatever range the + * colors were originally in: + */ + if ((transforms & PNG_TRANSFORM_SHIFT) != 0) +#ifdef PNG_READ_SHIFT_SUPPORTED + if ((info_ptr->valid & PNG_INFO_sBIT) != 0) + png_set_shift(png_ptr, &info_ptr->sig_bit); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported"); +#endif + + /* Flip the RGB pixels to BGR (or RGBA to BGRA) */ + if ((transforms & PNG_TRANSFORM_BGR) != 0) +#ifdef PNG_READ_BGR_SUPPORTED + png_set_bgr(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported"); +#endif + + /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ + if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0) +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED + png_set_swap_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported"); +#endif + + /* Swap bytes of 16-bit files to least significant byte first */ + if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0) +#ifdef PNG_READ_SWAP_SUPPORTED + png_set_swap(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported"); +#endif + +/* Added at libpng-1.2.41 */ + /* Invert the alpha channel from opacity to transparency */ + if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0) +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + png_set_invert_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported"); +#endif + +/* Added at libpng-1.2.41 */ + /* Expand grayscale image to RGB */ + if ((transforms & PNG_TRANSFORM_GRAY_TO_RGB) != 0) +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + png_set_gray_to_rgb(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_GRAY_TO_RGB not supported"); +#endif + +/* Added at libpng-1.5.4 */ + if ((transforms & PNG_TRANSFORM_EXPAND_16) != 0) +#ifdef PNG_READ_EXPAND_16_SUPPORTED + png_set_expand_16(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_EXPAND_16 not supported"); +#endif + + /* We don't handle adding filler bytes */ + + /* We use png_read_image and rely on that for interlace handling, but we also + * call png_read_update_info therefore must turn on interlace handling now: + */ + (void)png_set_interlace_handling(png_ptr); + + /* Optional call to gamma correct and add the background to the palette + * and update info structure. REQUIRED if you are expecting libpng to + * update the palette for you (i.e., you selected such a transform above). + */ + png_read_update_info(png_ptr, info_ptr); + + /* -------------- image transformations end here ------------------- */ + + png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); + if (info_ptr->row_pointers == NULL) + { + png_uint_32 iptr; + + info_ptr->row_pointers = png_voidcast(png_bytepp, png_malloc(png_ptr, + info_ptr->height * (sizeof (png_bytep)))); + + for (iptr=0; iptrheight; iptr++) + info_ptr->row_pointers[iptr] = NULL; + + info_ptr->free_me |= PNG_FREE_ROWS; + + for (iptr = 0; iptr < info_ptr->height; iptr++) + info_ptr->row_pointers[iptr] = png_voidcast(png_bytep, + png_malloc(png_ptr, info_ptr->rowbytes)); + } + + png_read_image(png_ptr, info_ptr->row_pointers); + info_ptr->valid |= PNG_INFO_IDAT; + + /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ + png_read_end(png_ptr, info_ptr); + + PNG_UNUSED(params) +} +#endif /* INFO_IMAGE */ +#endif /* SEQUENTIAL_READ */ + +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +/* SIMPLIFIED READ + * + * This code currently relies on the sequential reader, though it could easily + * be made to work with the progressive one. + */ +/* Arguments to png_image_finish_read: */ + +/* Encoding of PNG data (used by the color-map code) */ +# define P_NOTSET 0 /* File encoding not yet known */ +# define P_sRGB 1 /* 8-bit encoded to sRGB gamma */ +# define P_LINEAR 2 /* 16-bit linear: not encoded, NOT pre-multiplied! */ +# define P_FILE 3 /* 8-bit encoded to file gamma, not sRGB or linear */ +# define P_LINEAR8 4 /* 8-bit linear: only from a file value */ + +/* Color-map processing: after libpng has run on the PNG image further + * processing may be needed to convert the data to color-map indices. + */ +#define PNG_CMAP_NONE 0 +#define PNG_CMAP_GA 1 /* Process GA data to a color-map with alpha */ +#define PNG_CMAP_TRANS 2 /* Process GA data to a background index */ +#define PNG_CMAP_RGB 3 /* Process RGB data */ +#define PNG_CMAP_RGB_ALPHA 4 /* Process RGBA data */ + +/* The following document where the background is for each processing case. */ +#define PNG_CMAP_NONE_BACKGROUND 256 +#define PNG_CMAP_GA_BACKGROUND 231 +#define PNG_CMAP_TRANS_BACKGROUND 254 +#define PNG_CMAP_RGB_BACKGROUND 256 +#define PNG_CMAP_RGB_ALPHA_BACKGROUND 216 + +typedef struct +{ + /* Arguments: */ + png_imagep image; + png_voidp buffer; + png_int_32 row_stride; + png_voidp colormap; + png_const_colorp background; + /* Local variables: */ + png_voidp local_row; + png_voidp first_row; + ptrdiff_t row_bytes; /* step between rows */ + int file_encoding; /* E_ values above */ + png_fixed_point gamma_to_linear; /* For P_FILE, reciprocal of gamma */ + int colormap_processing; /* PNG_CMAP_ values above */ +} png_image_read_control; + +/* Do all the *safe* initialization - 'safe' means that png_error won't be + * called, so setting up the jmp_buf is not required. This means that anything + * called from here must *not* call png_malloc - it has to call png_malloc_warn + * instead so that control is returned safely back to this routine. + */ +static int +png_image_read_init(png_imagep image) +{ + if (image->opaque == NULL) + { + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, image, + png_safe_error, png_safe_warning); + + /* And set the rest of the structure to NULL to ensure that the various + * fields are consistent. + */ + memset(image, 0, (sizeof *image)); + image->version = PNG_IMAGE_VERSION; + + if (png_ptr != NULL) + { + png_infop info_ptr = png_create_info_struct(png_ptr); + + if (info_ptr != NULL) + { + png_controlp control = png_voidcast(png_controlp, + png_malloc_warn(png_ptr, (sizeof *control))); + + if (control != NULL) + { + memset(control, 0, (sizeof *control)); + + control->png_ptr = png_ptr; + control->info_ptr = info_ptr; + control->for_write = 0; + + image->opaque = control; + return 1; + } + + /* Error clean up */ + png_destroy_info_struct(png_ptr, &info_ptr); + } + + png_destroy_read_struct(&png_ptr, NULL, NULL); + } + + return png_image_error(image, "png_image_read: out of memory"); + } + + return png_image_error(image, "png_image_read: opaque pointer not NULL"); +} + +/* Utility to find the base format of a PNG file from a png_struct. */ +static png_uint_32 +png_image_format(png_structrp png_ptr) +{ + png_uint_32 format = 0; + + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + format |= PNG_FORMAT_FLAG_COLOR; + + if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) + format |= PNG_FORMAT_FLAG_ALPHA; + + /* Use png_ptr here, not info_ptr, because by examination png_handle_tRNS + * sets the png_struct fields; that's all we are interested in here. The + * precise interaction with an app call to png_set_tRNS and PNG file reading + * is unclear. + */ + else if (png_ptr->num_trans > 0) + format |= PNG_FORMAT_FLAG_ALPHA; + + if (png_ptr->bit_depth == 16) + format |= PNG_FORMAT_FLAG_LINEAR; + + if ((png_ptr->color_type & PNG_COLOR_MASK_PALETTE) != 0) + format |= PNG_FORMAT_FLAG_COLORMAP; + + return format; +} + +/* Is the given gamma significantly different from sRGB? The test is the same + * one used in pngrtran.c when deciding whether to do gamma correction. The + * arithmetic optimizes the division by using the fact that the inverse of the + * file sRGB gamma is 2.2 + */ +static int +png_gamma_not_sRGB(png_fixed_point g) +{ + if (g < PNG_FP_1) + { + /* An uninitialized gamma is assumed to be sRGB for the simplified API. */ + if (g == 0) + return 0; + + return png_gamma_significant((g * 11 + 2)/5 /* i.e. *2.2, rounded */); + } + + return 1; +} + +/* Do the main body of a 'png_image_begin_read' function; read the PNG file + * header and fill in all the information. This is executed in a safe context, + * unlike the init routine above. + */ +static int +png_image_read_header(png_voidp argument) +{ + png_imagep image = png_voidcast(png_imagep, argument); + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + + png_set_benign_errors(png_ptr, 1/*warn*/); + png_read_info(png_ptr, info_ptr); + + /* Do this the fast way; just read directly out of png_struct. */ + image->width = png_ptr->width; + image->height = png_ptr->height; + + { + png_uint_32 format = png_image_format(png_ptr); + + image->format = format; + +#ifdef PNG_COLORSPACE_SUPPORTED + /* Does the colorspace match sRGB? If there is no color endpoint + * (colorant) information assume yes, otherwise require the + * 'ENDPOINTS_MATCHP_sRGB' colorspace flag to have been set. If the + * colorspace has been determined to be invalid ignore it. + */ + if ((format & PNG_FORMAT_FLAG_COLOR) != 0 && ((png_ptr->colorspace.flags + & (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB| + PNG_COLORSPACE_INVALID)) == PNG_COLORSPACE_HAVE_ENDPOINTS)) + image->flags |= PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB; +#endif + } + + /* We need the maximum number of entries regardless of the format the + * application sets here. + */ + { + png_uint_32 cmap_entries; + + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_GRAY: + cmap_entries = 1U << png_ptr->bit_depth; + break; + + case PNG_COLOR_TYPE_PALETTE: + cmap_entries = png_ptr->num_palette; + break; + + default: + cmap_entries = 256; + break; + } + + if (cmap_entries > 256) + cmap_entries = 256; + + image->colormap_entries = cmap_entries; + } + + return 1; +} + +#ifdef PNG_STDIO_SUPPORTED +int PNGAPI +png_image_begin_read_from_stdio(png_imagep image, FILE* file) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file != NULL) + { + if (png_image_read_init(image) != 0) + { + /* This is slightly evil, but png_init_io doesn't do anything other + * than this and we haven't changed the standard IO functions so + * this saves a 'safe' function. + */ + image->opaque->png_ptr->io_ptr = file; + return png_safe_execute(image, png_image_read_header, image); + } + } + + else + return png_image_error(image, + "png_image_begin_read_from_stdio: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_begin_read_from_stdio: incorrect PNG_IMAGE_VERSION"); + + return 0; +} + +int PNGAPI +png_image_begin_read_from_file(png_imagep image, const char *file_name) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file_name != NULL) + { + FILE *fp = fopen(file_name, "rb"); + + if (fp != NULL) + { + if (png_image_read_init(image) != 0) + { + image->opaque->png_ptr->io_ptr = fp; + image->opaque->owned_file = 1; + return png_safe_execute(image, png_image_read_header, image); + } + + /* Clean up: just the opened file. */ + (void)fclose(fp); + } + + else + return png_image_error(image, strerror(errno)); + } + + else + return png_image_error(image, + "png_image_begin_read_from_file: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_begin_read_from_file: incorrect PNG_IMAGE_VERSION"); + + return 0; +} +#endif /* STDIO */ + +static void PNGCBAPI +png_image_memory_read(png_structp png_ptr, png_bytep out, png_size_t need) +{ + if (png_ptr != NULL) + { + png_imagep image = png_voidcast(png_imagep, png_ptr->io_ptr); + if (image != NULL) + { + png_controlp cp = image->opaque; + if (cp != NULL) + { + png_const_bytep memory = cp->memory; + png_size_t size = cp->size; + + if (memory != NULL && size >= need) + { + memcpy(out, memory, need); + cp->memory = memory + need; + cp->size = size - need; + return; + } + + png_error(png_ptr, "read beyond end of data"); + } + } + + png_error(png_ptr, "invalid memory read"); + } +} + +int PNGAPI png_image_begin_read_from_memory(png_imagep image, + png_const_voidp memory, png_size_t size) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (memory != NULL && size > 0) + { + if (png_image_read_init(image) != 0) + { + /* Now set the IO functions to read from the memory buffer and + * store it into io_ptr. Again do this in-place to avoid calling a + * libpng function that requires error handling. + */ + image->opaque->memory = png_voidcast(png_const_bytep, memory); + image->opaque->size = size; + image->opaque->png_ptr->io_ptr = image; + image->opaque->png_ptr->read_data_fn = png_image_memory_read; + + return png_safe_execute(image, png_image_read_header, image); + } + } + + else + return png_image_error(image, + "png_image_begin_read_from_memory: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_begin_read_from_memory: incorrect PNG_IMAGE_VERSION"); + + return 0; +} + +/* Utility function to skip chunks that are not used by the simplified image + * read functions and an appropriate macro to call it. + */ +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +static void +png_image_skip_unused_chunks(png_structrp png_ptr) +{ + /* Prepare the reader to ignore all recognized chunks whose data will not + * be used, i.e., all chunks recognized by libpng except for those + * involved in basic image reading: + * + * IHDR, PLTE, IDAT, IEND + * + * Or image data handling: + * + * tRNS, bKGD, gAMA, cHRM, sRGB, [iCCP] and sBIT. + * + * This provides a small performance improvement and eliminates any + * potential vulnerability to security problems in the unused chunks. + * + * At present the iCCP chunk data isn't used, so iCCP chunk can be ignored + * too. This allows the simplified API to be compiled without iCCP support, + * however if the support is there the chunk is still checked to detect + * errors (which are unfortunately quite common.) + */ + { + static PNG_CONST png_byte chunks_to_process[] = { + 98, 75, 71, 68, '\0', /* bKGD */ + 99, 72, 82, 77, '\0', /* cHRM */ + 103, 65, 77, 65, '\0', /* gAMA */ +# ifdef PNG_READ_iCCP_SUPPORTED + 105, 67, 67, 80, '\0', /* iCCP */ +# endif + 115, 66, 73, 84, '\0', /* sBIT */ + 115, 82, 71, 66, '\0', /* sRGB */ + }; + + /* Ignore unknown chunks and all other chunks except for the + * IHDR, PLTE, tRNS, IDAT, and IEND chunks. + */ + png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER, + NULL, -1); + + /* But do not ignore image data handling chunks */ + png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_AS_DEFAULT, + chunks_to_process, (int)/*SAFE*/(sizeof chunks_to_process)/5); + } +} + +# define PNG_SKIP_CHUNKS(p) png_image_skip_unused_chunks(p) +#else +# define PNG_SKIP_CHUNKS(p) ((void)0) +#endif /* HANDLE_AS_UNKNOWN */ + +/* The following macro gives the exact rounded answer for all values in the + * range 0..255 (it actually divides by 51.2, but the rounding still generates + * the correct numbers 0..5 + */ +#define PNG_DIV51(v8) (((v8) * 5 + 130) >> 8) + +/* Utility functions to make particular color-maps */ +static void +set_file_encoding(png_image_read_control *display) +{ + png_fixed_point g = display->image->opaque->png_ptr->colorspace.gamma; + if (png_gamma_significant(g) != 0) + { + if (png_gamma_not_sRGB(g) != 0) + { + display->file_encoding = P_FILE; + display->gamma_to_linear = png_reciprocal(g); + } + + else + display->file_encoding = P_sRGB; + } + + else + display->file_encoding = P_LINEAR8; +} + +static unsigned int +decode_gamma(png_image_read_control *display, png_uint_32 value, int encoding) +{ + if (encoding == P_FILE) /* double check */ + encoding = display->file_encoding; + + if (encoding == P_NOTSET) /* must be the file encoding */ + { + set_file_encoding(display); + encoding = display->file_encoding; + } + + switch (encoding) + { + case P_FILE: + value = png_gamma_16bit_correct(value*257, display->gamma_to_linear); + break; + + case P_sRGB: + value = png_sRGB_table[value]; + break; + + case P_LINEAR: + break; + + case P_LINEAR8: + value *= 257; + break; + +#ifdef __GNUC__ + default: + png_error(display->image->opaque->png_ptr, + "unexpected encoding (internal error)"); +#endif + } + + return value; +} + +static png_uint_32 +png_colormap_compose(png_image_read_control *display, + png_uint_32 foreground, int foreground_encoding, png_uint_32 alpha, + png_uint_32 background, int encoding) +{ + /* The file value is composed on the background, the background has the given + * encoding and so does the result, the file is encoded with P_FILE and the + * file and alpha are 8-bit values. The (output) encoding will always be + * P_LINEAR or P_sRGB. + */ + png_uint_32 f = decode_gamma(display, foreground, foreground_encoding); + png_uint_32 b = decode_gamma(display, background, encoding); + + /* The alpha is always an 8-bit value (it comes from the palette), the value + * scaled by 255 is what PNG_sRGB_FROM_LINEAR requires. + */ + f = f * alpha + b * (255-alpha); + + if (encoding == P_LINEAR) + { + /* Scale to 65535; divide by 255, approximately (in fact this is extremely + * accurate, it divides by 255.00000005937181414556, with no overflow.) + */ + f *= 257; /* Now scaled by 65535 */ + f += f >> 16; + f = (f+32768) >> 16; + } + + else /* P_sRGB */ + f = PNG_sRGB_FROM_LINEAR(f); + + return f; +} + +/* NOTE: P_LINEAR values to this routine must be 16-bit, but P_FILE values must + * be 8-bit. + */ +static void +png_create_colormap_entry(png_image_read_control *display, + png_uint_32 ip, png_uint_32 red, png_uint_32 green, png_uint_32 blue, + png_uint_32 alpha, int encoding) +{ + png_imagep image = display->image; + const int output_encoding = (image->format & PNG_FORMAT_FLAG_LINEAR) != 0 ? + P_LINEAR : P_sRGB; + const int convert_to_Y = (image->format & PNG_FORMAT_FLAG_COLOR) == 0 && + (red != green || green != blue); + + if (ip > 255) + png_error(image->opaque->png_ptr, "color-map index out of range"); + + /* Update the cache with whether the file gamma is significantly different + * from sRGB. + */ + if (encoding == P_FILE) + { + if (display->file_encoding == P_NOTSET) + set_file_encoding(display); + + /* Note that the cached value may be P_FILE too, but if it is then the + * gamma_to_linear member has been set. + */ + encoding = display->file_encoding; + } + + if (encoding == P_FILE) + { + png_fixed_point g = display->gamma_to_linear; + + red = png_gamma_16bit_correct(red*257, g); + green = png_gamma_16bit_correct(green*257, g); + blue = png_gamma_16bit_correct(blue*257, g); + + if (convert_to_Y != 0 || output_encoding == P_LINEAR) + { + alpha *= 257; + encoding = P_LINEAR; + } + + else + { + red = PNG_sRGB_FROM_LINEAR(red * 255); + green = PNG_sRGB_FROM_LINEAR(green * 255); + blue = PNG_sRGB_FROM_LINEAR(blue * 255); + encoding = P_sRGB; + } + } + + else if (encoding == P_LINEAR8) + { + /* This encoding occurs quite frequently in test cases because PngSuite + * includes a gAMA 1.0 chunk with most images. + */ + red *= 257; + green *= 257; + blue *= 257; + alpha *= 257; + encoding = P_LINEAR; + } + + else if (encoding == P_sRGB && + (convert_to_Y != 0 || output_encoding == P_LINEAR)) + { + /* The values are 8-bit sRGB values, but must be converted to 16-bit + * linear. + */ + red = png_sRGB_table[red]; + green = png_sRGB_table[green]; + blue = png_sRGB_table[blue]; + alpha *= 257; + encoding = P_LINEAR; + } + + /* This is set if the color isn't gray but the output is. */ + if (encoding == P_LINEAR) + { + if (convert_to_Y != 0) + { + /* NOTE: these values are copied from png_do_rgb_to_gray */ + png_uint_32 y = (png_uint_32)6968 * red + (png_uint_32)23434 * green + + (png_uint_32)2366 * blue; + + if (output_encoding == P_LINEAR) + y = (y + 16384) >> 15; + + else + { + /* y is scaled by 32768, we need it scaled by 255: */ + y = (y + 128) >> 8; + y *= 255; + y = PNG_sRGB_FROM_LINEAR((y + 64) >> 7); + alpha = PNG_DIV257(alpha); + encoding = P_sRGB; + } + + blue = red = green = y; + } + + else if (output_encoding == P_sRGB) + { + red = PNG_sRGB_FROM_LINEAR(red * 255); + green = PNG_sRGB_FROM_LINEAR(green * 255); + blue = PNG_sRGB_FROM_LINEAR(blue * 255); + alpha = PNG_DIV257(alpha); + encoding = P_sRGB; + } + } + + if (encoding != output_encoding) + png_error(image->opaque->png_ptr, "bad encoding (internal error)"); + + /* Store the value. */ + { +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + const int afirst = (image->format & PNG_FORMAT_FLAG_AFIRST) != 0 && + (image->format & PNG_FORMAT_FLAG_ALPHA) != 0; +# else +# define afirst 0 +# endif +# ifdef PNG_FORMAT_BGR_SUPPORTED + const int bgr = (image->format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0; +# else +# define bgr 0 +# endif + + if (output_encoding == P_LINEAR) + { + png_uint_16p entry = png_voidcast(png_uint_16p, display->colormap); + + entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format); + + /* The linear 16-bit values must be pre-multiplied by the alpha channel + * value, if less than 65535 (this is, effectively, composite on black + * if the alpha channel is removed.) + */ + switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format)) + { + case 4: + entry[afirst ? 0 : 3] = (png_uint_16)alpha; + /* FALL THROUGH */ + + case 3: + if (alpha < 65535) + { + if (alpha > 0) + { + blue = (blue * alpha + 32767U)/65535U; + green = (green * alpha + 32767U)/65535U; + red = (red * alpha + 32767U)/65535U; + } + + else + red = green = blue = 0; + } + entry[afirst + (2 ^ bgr)] = (png_uint_16)blue; + entry[afirst + 1] = (png_uint_16)green; + entry[afirst + bgr] = (png_uint_16)red; + break; + + case 2: + entry[1 ^ afirst] = (png_uint_16)alpha; + /* FALL THROUGH */ + + case 1: + if (alpha < 65535) + { + if (alpha > 0) + green = (green * alpha + 32767U)/65535U; + + else + green = 0; + } + entry[afirst] = (png_uint_16)green; + break; + + default: + break; + } + } + + else /* output encoding is P_sRGB */ + { + png_bytep entry = png_voidcast(png_bytep, display->colormap); + + entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format); + + switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format)) + { + case 4: + entry[afirst ? 0 : 3] = (png_byte)alpha; + case 3: + entry[afirst + (2 ^ bgr)] = (png_byte)blue; + entry[afirst + 1] = (png_byte)green; + entry[afirst + bgr] = (png_byte)red; + break; + + case 2: + entry[1 ^ afirst] = (png_byte)alpha; + case 1: + entry[afirst] = (png_byte)green; + break; + + default: + break; + } + } + +# ifdef afirst +# undef afirst +# endif +# ifdef bgr +# undef bgr +# endif + } +} + +static int +make_gray_file_colormap(png_image_read_control *display) +{ + unsigned int i; + + for (i=0; i<256; ++i) + png_create_colormap_entry(display, i, i, i, i, 255, P_FILE); + + return i; +} + +static int +make_gray_colormap(png_image_read_control *display) +{ + unsigned int i; + + for (i=0; i<256; ++i) + png_create_colormap_entry(display, i, i, i, i, 255, P_sRGB); + + return i; +} +#define PNG_GRAY_COLORMAP_ENTRIES 256 + +static int +make_ga_colormap(png_image_read_control *display) +{ + unsigned int i, a; + + /* Alpha is retained, the output will be a color-map with entries + * selected by six levels of alpha. One transparent entry, 6 gray + * levels for all the intermediate alpha values, leaving 230 entries + * for the opaque grays. The color-map entries are the six values + * [0..5]*51, the GA processing uses PNG_DIV51(value) to find the + * relevant entry. + * + * if (alpha > 229) // opaque + * { + * // The 231 entries are selected to make the math below work: + * base = 0; + * entry = (231 * gray + 128) >> 8; + * } + * else if (alpha < 26) // transparent + * { + * base = 231; + * entry = 0; + * } + * else // partially opaque + * { + * base = 226 + 6 * PNG_DIV51(alpha); + * entry = PNG_DIV51(gray); + * } + */ + i = 0; + while (i < 231) + { + unsigned int gray = (i * 256 + 115) / 231; + png_create_colormap_entry(display, i++, gray, gray, gray, 255, P_sRGB); + } + + /* 255 is used here for the component values for consistency with the code + * that undoes premultiplication in pngwrite.c. + */ + png_create_colormap_entry(display, i++, 255, 255, 255, 0, P_sRGB); + + for (a=1; a<5; ++a) + { + unsigned int g; + + for (g=0; g<6; ++g) + png_create_colormap_entry(display, i++, g*51, g*51, g*51, a*51, + P_sRGB); + } + + return i; +} + +#define PNG_GA_COLORMAP_ENTRIES 256 + +static int +make_rgb_colormap(png_image_read_control *display) +{ + unsigned int i, r; + + /* Build a 6x6x6 opaque RGB cube */ + for (i=r=0; r<6; ++r) + { + unsigned int g; + + for (g=0; g<6; ++g) + { + unsigned int b; + + for (b=0; b<6; ++b) + png_create_colormap_entry(display, i++, r*51, g*51, b*51, 255, + P_sRGB); + } + } + + return i; +} + +#define PNG_RGB_COLORMAP_ENTRIES 216 + +/* Return a palette index to the above palette given three 8-bit sRGB values. */ +#define PNG_RGB_INDEX(r,g,b) \ + ((png_byte)(6 * (6 * PNG_DIV51(r) + PNG_DIV51(g)) + PNG_DIV51(b))) + +static int +png_image_read_colormap(png_voidp argument) +{ + png_image_read_control *display = + png_voidcast(png_image_read_control*, argument); + const png_imagep image = display->image; + + const png_structrp png_ptr = image->opaque->png_ptr; + const png_uint_32 output_format = image->format; + const int output_encoding = (output_format & PNG_FORMAT_FLAG_LINEAR) != 0 ? + P_LINEAR : P_sRGB; + + unsigned int cmap_entries; + unsigned int output_processing; /* Output processing option */ + unsigned int data_encoding = P_NOTSET; /* Encoding libpng must produce */ + + /* Background information; the background color and the index of this color + * in the color-map if it exists (else 256). + */ + unsigned int background_index = 256; + png_uint_32 back_r, back_g, back_b; + + /* Flags to accumulate things that need to be done to the input. */ + int expand_tRNS = 0; + + /* Exclude the NYI feature of compositing onto a color-mapped buffer; it is + * very difficult to do, the results look awful, and it is difficult to see + * what possible use it is because the application can't control the + * color-map. + */ + if (((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0 || + png_ptr->num_trans > 0) /* alpha in input */ && + ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) /* no alpha in output */) + { + if (output_encoding == P_LINEAR) /* compose on black */ + back_b = back_g = back_r = 0; + + else if (display->background == NULL /* no way to remove it */) + png_error(png_ptr, + "a background color must be supplied to remove alpha/transparency"); + + /* Get a copy of the background color (this avoids repeating the checks + * below.) The encoding is 8-bit sRGB or 16-bit linear, depending on the + * output format. + */ + else + { + back_g = display->background->green; + if ((output_format & PNG_FORMAT_FLAG_COLOR) != 0) + { + back_r = display->background->red; + back_b = display->background->blue; + } + else + back_b = back_r = back_g; + } + } + + else if (output_encoding == P_LINEAR) + back_b = back_r = back_g = 65535; + + else + back_b = back_r = back_g = 255; + + /* Default the input file gamma if required - this is necessary because + * libpng assumes that if no gamma information is present the data is in the + * output format, but the simplified API deduces the gamma from the input + * format. + */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) == 0) + { + /* Do this directly, not using the png_colorspace functions, to ensure + * that it happens even if the colorspace is invalid (though probably if + * it is the setting will be ignored) Note that the same thing can be + * achieved at the application interface with png_set_gAMA. + */ + if (png_ptr->bit_depth == 16 && + (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) + png_ptr->colorspace.gamma = PNG_GAMMA_LINEAR; + + else + png_ptr->colorspace.gamma = PNG_GAMMA_sRGB_INVERSE; + + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; + } + + /* Decide what to do based on the PNG color type of the input data. The + * utility function png_create_colormap_entry deals with most aspects of the + * output transformations; this code works out how to produce bytes of + * color-map entries from the original format. + */ + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_GRAY: + if (png_ptr->bit_depth <= 8) + { + /* There at most 256 colors in the output, regardless of + * transparency. + */ + unsigned int step, i, val, trans = 256/*ignore*/, back_alpha = 0; + + cmap_entries = 1U << png_ptr->bit_depth; + if (cmap_entries > image->colormap_entries) + png_error(png_ptr, "gray[8] color-map: too few entries"); + + step = 255 / (cmap_entries - 1); + output_processing = PNG_CMAP_NONE; + + /* If there is a tRNS chunk then this either selects a transparent + * value or, if the output has no alpha, the background color. + */ + if (png_ptr->num_trans > 0) + { + trans = png_ptr->trans_color.gray; + + if ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) + back_alpha = output_encoding == P_LINEAR ? 65535 : 255; + } + + /* png_create_colormap_entry just takes an RGBA and writes the + * corresponding color-map entry using the format from 'image', + * including the required conversion to sRGB or linear as + * appropriate. The input values are always either sRGB (if the + * gamma correction flag is 0) or 0..255 scaled file encoded values + * (if the function must gamma correct them). + */ + for (i=val=0; ibit_depth < 8) + png_set_packing(png_ptr); + } + + else /* bit depth is 16 */ + { + /* The 16-bit input values can be converted directly to 8-bit gamma + * encoded values; however, if a tRNS chunk is present 257 color-map + * entries are required. This means that the extra entry requires + * special processing; add an alpha channel, sacrifice gray level + * 254 and convert transparent (alpha==0) entries to that. + * + * Use libpng to chop the data to 8 bits. Convert it to sRGB at the + * same time to minimize quality loss. If a tRNS chunk is present + * this means libpng must handle it too; otherwise it is impossible + * to do the exact match on the 16-bit value. + * + * If the output has no alpha channel *and* the background color is + * gray then it is possible to let libpng handle the substitution by + * ensuring that the corresponding gray level matches the background + * color exactly. + */ + data_encoding = P_sRGB; + + if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "gray[16] color-map: too few entries"); + + cmap_entries = make_gray_colormap(display); + + if (png_ptr->num_trans > 0) + { + unsigned int back_alpha; + + if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + back_alpha = 0; + + else + { + if (back_r == back_g && back_g == back_b) + { + /* Background is gray; no special processing will be + * required. + */ + png_color_16 c; + png_uint_32 gray = back_g; + + if (output_encoding == P_LINEAR) + { + gray = PNG_sRGB_FROM_LINEAR(gray * 255); + + /* And make sure the corresponding palette entry + * matches. + */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 65535, P_LINEAR); + } + + /* The background passed to libpng, however, must be the + * sRGB value. + */ + c.index = 0; /*unused*/ + c.gray = c.red = c.green = c.blue = (png_uint_16)gray; + + /* NOTE: does this work without expanding tRNS to alpha? + * It should be the color->gray case below apparently + * doesn't. + */ + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + + output_processing = PNG_CMAP_NONE; + break; + } +#ifdef __COVERITY__ + /* Coverity claims that output_encoding cannot be 2 (P_LINEAR) + * here. + */ + back_alpha = 255; +#else + back_alpha = output_encoding == P_LINEAR ? 65535 : 255; +#endif + } + + /* output_processing means that the libpng-processed row will be + * 8-bit GA and it has to be processing to single byte color-map + * values. Entry 254 is replaced by either a completely + * transparent entry or by the background color at full + * precision (and the background color is not a simple gray + * level in this case.) + */ + expand_tRNS = 1; + output_processing = PNG_CMAP_TRANS; + background_index = 254; + + /* And set (overwrite) color-map entry 254 to the actual + * background color at full precision. + */ + png_create_colormap_entry(display, 254, back_r, back_g, back_b, + back_alpha, output_encoding); + } + + else + output_processing = PNG_CMAP_NONE; + } + break; + + case PNG_COLOR_TYPE_GRAY_ALPHA: + /* 8-bit or 16-bit PNG with two channels - gray and alpha. A minimum + * of 65536 combinations. If, however, the alpha channel is to be + * removed there are only 256 possibilities if the background is gray. + * (Otherwise there is a subset of the 65536 possibilities defined by + * the triangle between black, white and the background color.) + * + * Reduce 16-bit files to 8-bit and sRGB encode the result. No need to + * worry about tRNS matching - tRNS is ignored if there is an alpha + * channel. + */ + data_encoding = P_sRGB; + + if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "gray+alpha color-map: too few entries"); + + cmap_entries = make_ga_colormap(display); + + background_index = PNG_CMAP_GA_BACKGROUND; + output_processing = PNG_CMAP_GA; + } + + else /* alpha is removed */ + { + /* Alpha must be removed as the PNG data is processed when the + * background is a color because the G and A channels are + * independent and the vector addition (non-parallel vectors) is a + * 2-D problem. + * + * This can be reduced to the same algorithm as above by making a + * colormap containing gray levels (for the opaque grays), a + * background entry (for a transparent pixel) and a set of four six + * level color values, one set for each intermediate alpha value. + * See the comments in make_ga_colormap for how this works in the + * per-pixel processing. + * + * If the background is gray, however, we only need a 256 entry gray + * level color map. It is sufficient to make the entry generated + * for the background color be exactly the color specified. + */ + if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0 || + (back_r == back_g && back_g == back_b)) + { + /* Background is gray; no special processing will be required. */ + png_color_16 c; + png_uint_32 gray = back_g; + + if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "gray-alpha color-map: too few entries"); + + cmap_entries = make_gray_colormap(display); + + if (output_encoding == P_LINEAR) + { + gray = PNG_sRGB_FROM_LINEAR(gray * 255); + + /* And make sure the corresponding palette entry matches. */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 65535, P_LINEAR); + } + + /* The background passed to libpng, however, must be the sRGB + * value. + */ + c.index = 0; /*unused*/ + c.gray = c.red = c.green = c.blue = (png_uint_16)gray; + + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + + output_processing = PNG_CMAP_NONE; + } + + else + { + png_uint_32 i, a; + + /* This is the same as png_make_ga_colormap, above, except that + * the entries are all opaque. + */ + if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "ga-alpha color-map: too few entries"); + + i = 0; + while (i < 231) + { + png_uint_32 gray = (i * 256 + 115) / 231; + png_create_colormap_entry(display, i++, gray, gray, gray, + 255, P_sRGB); + } + + /* NOTE: this preserves the full precision of the application + * background color. + */ + background_index = i; + png_create_colormap_entry(display, i++, back_r, back_g, back_b, +#ifdef __COVERITY__ + /* Coverity claims that output_encoding cannot be 2 (P_LINEAR) + * here. + */ 255U, +#else + output_encoding == P_LINEAR ? 65535U : 255U, +#endif + output_encoding); + + /* For non-opaque input composite on the sRGB background - this + * requires inverting the encoding for each component. The input + * is still converted to the sRGB encoding because this is a + * reasonable approximate to the logarithmic curve of human + * visual sensitivity, at least over the narrow range which PNG + * represents. Consequently 'G' is always sRGB encoded, while + * 'A' is linear. We need the linear background colors. + */ + if (output_encoding == P_sRGB) /* else already linear */ + { + /* This may produce a value not exactly matching the + * background, but that's ok because these numbers are only + * used when alpha != 0 + */ + back_r = png_sRGB_table[back_r]; + back_g = png_sRGB_table[back_g]; + back_b = png_sRGB_table[back_b]; + } + + for (a=1; a<5; ++a) + { + unsigned int g; + + /* PNG_sRGB_FROM_LINEAR expects a 16-bit linear value scaled + * by an 8-bit alpha value (0..255). + */ + png_uint_32 alpha = 51 * a; + png_uint_32 back_rx = (255-alpha) * back_r; + png_uint_32 back_gx = (255-alpha) * back_g; + png_uint_32 back_bx = (255-alpha) * back_b; + + for (g=0; g<6; ++g) + { + png_uint_32 gray = png_sRGB_table[g*51] * alpha; + + png_create_colormap_entry(display, i++, + PNG_sRGB_FROM_LINEAR(gray + back_rx), + PNG_sRGB_FROM_LINEAR(gray + back_gx), + PNG_sRGB_FROM_LINEAR(gray + back_bx), 255, P_sRGB); + } + } + + cmap_entries = i; + output_processing = PNG_CMAP_GA; + } + } + break; + + case PNG_COLOR_TYPE_RGB: + case PNG_COLOR_TYPE_RGB_ALPHA: + /* Exclude the case where the output is gray; we can always handle this + * with the cases above. + */ + if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0) + { + /* The color-map will be grayscale, so we may as well convert the + * input RGB values to a simple grayscale and use the grayscale + * code above. + * + * NOTE: calling this apparently damages the recognition of the + * transparent color in background color handling; call + * png_set_tRNS_to_alpha before png_set_background_fixed. + */ + png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, -1, + -1); + data_encoding = P_sRGB; + + /* The output will now be one or two 8-bit gray or gray+alpha + * channels. The more complex case arises when the input has alpha. + */ + if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) && + (output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + /* Both input and output have an alpha channel, so no background + * processing is required; just map the GA bytes to the right + * color-map entry. + */ + expand_tRNS = 1; + + if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "rgb[ga] color-map: too few entries"); + + cmap_entries = make_ga_colormap(display); + background_index = PNG_CMAP_GA_BACKGROUND; + output_processing = PNG_CMAP_GA; + } + + else + { + /* Either the input or the output has no alpha channel, so there + * will be no non-opaque pixels in the color-map; it will just be + * grayscale. + */ + if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "rgb[gray] color-map: too few entries"); + + /* Ideally this code would use libpng to do the gamma correction, + * but if an input alpha channel is to be removed we will hit the + * libpng bug in gamma+compose+rgb-to-gray (the double gamma + * correction bug). Fix this by dropping the gamma correction in + * this case and doing it in the palette; this will result in + * duplicate palette entries, but that's better than the + * alternative of double gamma correction. + */ + if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) && + png_gamma_not_sRGB(png_ptr->colorspace.gamma) != 0) + { + cmap_entries = make_gray_file_colormap(display); + data_encoding = P_FILE; + } + + else + cmap_entries = make_gray_colormap(display); + + /* But if the input has alpha or transparency it must be removed + */ + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) + { + png_color_16 c; + png_uint_32 gray = back_g; + + /* We need to ensure that the application background exists in + * the colormap and that completely transparent pixels map to + * it. Achieve this simply by ensuring that the entry + * selected for the background really is the background color. + */ + if (data_encoding == P_FILE) /* from the fixup above */ + { + /* The app supplied a gray which is in output_encoding, we + * need to convert it to a value of the input (P_FILE) + * encoding then set this palette entry to the required + * output encoding. + */ + if (output_encoding == P_sRGB) + gray = png_sRGB_table[gray]; /* now P_LINEAR */ + + gray = PNG_DIV257(png_gamma_16bit_correct(gray, + png_ptr->colorspace.gamma)); /* now P_FILE */ + + /* And make sure the corresponding palette entry contains + * exactly the required sRGB value. + */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 0/*unused*/, output_encoding); + } + + else if (output_encoding == P_LINEAR) + { + gray = PNG_sRGB_FROM_LINEAR(gray * 255); + + /* And make sure the corresponding palette entry matches. + */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 0/*unused*/, P_LINEAR); + } + + /* The background passed to libpng, however, must be the + * output (normally sRGB) value. + */ + c.index = 0; /*unused*/ + c.gray = c.red = c.green = c.blue = (png_uint_16)gray; + + /* NOTE: the following is apparently a bug in libpng. Without + * it the transparent color recognition in + * png_set_background_fixed seems to go wrong. + */ + expand_tRNS = 1; + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + } + + output_processing = PNG_CMAP_NONE; + } + } + + else /* output is color */ + { + /* We could use png_quantize here so long as there is no transparent + * color or alpha; png_quantize ignores alpha. Easier overall just + * to do it once and using PNG_DIV51 on the 6x6x6 reduced RGB cube. + * Consequently we always want libpng to produce sRGB data. + */ + data_encoding = P_sRGB; + + /* Is there any transparency or alpha? */ + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) + { + /* Is there alpha in the output too? If so all four channels are + * processed into a special RGB cube with alpha support. + */ + if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + png_uint_32 r; + + if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries) + png_error(png_ptr, "rgb+alpha color-map: too few entries"); + + cmap_entries = make_rgb_colormap(display); + + /* Add a transparent entry. */ + png_create_colormap_entry(display, cmap_entries, 255, 255, + 255, 0, P_sRGB); + + /* This is stored as the background index for the processing + * algorithm. + */ + background_index = cmap_entries++; + + /* Add 27 r,g,b entries each with alpha 0.5. */ + for (r=0; r<256; r = (r << 1) | 0x7f) + { + png_uint_32 g; + + for (g=0; g<256; g = (g << 1) | 0x7f) + { + png_uint_32 b; + + /* This generates components with the values 0, 127 and + * 255 + */ + for (b=0; b<256; b = (b << 1) | 0x7f) + png_create_colormap_entry(display, cmap_entries++, + r, g, b, 128, P_sRGB); + } + } + + expand_tRNS = 1; + output_processing = PNG_CMAP_RGB_ALPHA; + } + + else + { + /* Alpha/transparency must be removed. The background must + * exist in the color map (achieved by setting adding it after + * the 666 color-map). If the standard processing code will + * pick up this entry automatically that's all that is + * required; libpng can be called to do the background + * processing. + */ + unsigned int sample_size = + PNG_IMAGE_SAMPLE_SIZE(output_format); + png_uint_32 r, g, b; /* sRGB background */ + + if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries) + png_error(png_ptr, "rgb-alpha color-map: too few entries"); + + cmap_entries = make_rgb_colormap(display); + + png_create_colormap_entry(display, cmap_entries, back_r, + back_g, back_b, 0/*unused*/, output_encoding); + + if (output_encoding == P_LINEAR) + { + r = PNG_sRGB_FROM_LINEAR(back_r * 255); + g = PNG_sRGB_FROM_LINEAR(back_g * 255); + b = PNG_sRGB_FROM_LINEAR(back_b * 255); + } + + else + { + r = back_r; + g = back_g; + b = back_g; + } + + /* Compare the newly-created color-map entry with the one the + * PNG_CMAP_RGB algorithm will use. If the two entries don't + * match, add the new one and set this as the background + * index. + */ + if (memcmp((png_const_bytep)display->colormap + + sample_size * cmap_entries, + (png_const_bytep)display->colormap + + sample_size * PNG_RGB_INDEX(r,g,b), + sample_size) != 0) + { + /* The background color must be added. */ + background_index = cmap_entries++; + + /* Add 27 r,g,b entries each with created by composing with + * the background at alpha 0.5. + */ + for (r=0; r<256; r = (r << 1) | 0x7f) + { + for (g=0; g<256; g = (g << 1) | 0x7f) + { + /* This generates components with the values 0, 127 + * and 255 + */ + for (b=0; b<256; b = (b << 1) | 0x7f) + png_create_colormap_entry(display, cmap_entries++, + png_colormap_compose(display, r, P_sRGB, 128, + back_r, output_encoding), + png_colormap_compose(display, g, P_sRGB, 128, + back_g, output_encoding), + png_colormap_compose(display, b, P_sRGB, 128, + back_b, output_encoding), + 0/*unused*/, output_encoding); + } + } + + expand_tRNS = 1; + output_processing = PNG_CMAP_RGB_ALPHA; + } + + else /* background color is in the standard color-map */ + { + png_color_16 c; + + c.index = 0; /*unused*/ + c.red = (png_uint_16)back_r; + c.gray = c.green = (png_uint_16)back_g; + c.blue = (png_uint_16)back_b; + + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + + output_processing = PNG_CMAP_RGB; + } + } + } + + else /* no alpha or transparency in the input */ + { + /* Alpha in the output is irrelevant, simply map the opaque input + * pixels to the 6x6x6 color-map. + */ + if (PNG_RGB_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "rgb color-map: too few entries"); + + cmap_entries = make_rgb_colormap(display); + output_processing = PNG_CMAP_RGB; + } + } + break; + + case PNG_COLOR_TYPE_PALETTE: + /* It's already got a color-map. It may be necessary to eliminate the + * tRNS entries though. + */ + { + unsigned int num_trans = png_ptr->num_trans; + png_const_bytep trans = num_trans > 0 ? png_ptr->trans_alpha : NULL; + png_const_colorp colormap = png_ptr->palette; + const int do_background = trans != NULL && + (output_format & PNG_FORMAT_FLAG_ALPHA) == 0; + unsigned int i; + + /* Just in case: */ + if (trans == NULL) + num_trans = 0; + + output_processing = PNG_CMAP_NONE; + data_encoding = P_FILE; /* Don't change from color-map indices */ + cmap_entries = png_ptr->num_palette; + if (cmap_entries > 256) + cmap_entries = 256; + + if (cmap_entries > image->colormap_entries) + png_error(png_ptr, "palette color-map: too few entries"); + + for (i=0; i < cmap_entries; ++i) + { + if (do_background != 0 && i < num_trans && trans[i] < 255) + { + if (trans[i] == 0) + png_create_colormap_entry(display, i, back_r, back_g, + back_b, 0, output_encoding); + + else + { + /* Must compose the PNG file color in the color-map entry + * on the sRGB color in 'back'. + */ + png_create_colormap_entry(display, i, + png_colormap_compose(display, colormap[i].red, P_FILE, + trans[i], back_r, output_encoding), + png_colormap_compose(display, colormap[i].green, P_FILE, + trans[i], back_g, output_encoding), + png_colormap_compose(display, colormap[i].blue, P_FILE, + trans[i], back_b, output_encoding), + output_encoding == P_LINEAR ? trans[i] * 257U : + trans[i], + output_encoding); + } + } + + else + png_create_colormap_entry(display, i, colormap[i].red, + colormap[i].green, colormap[i].blue, + i < num_trans ? trans[i] : 255U, P_FILE/*8-bit*/); + } + + /* The PNG data may have indices packed in fewer than 8 bits, it + * must be expanded if so. + */ + if (png_ptr->bit_depth < 8) + png_set_packing(png_ptr); + } + break; + + default: + png_error(png_ptr, "invalid PNG color type"); + /*NOT REACHED*/ + } + + /* Now deal with the output processing */ + if (expand_tRNS != 0 && png_ptr->num_trans > 0 && + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) == 0) + png_set_tRNS_to_alpha(png_ptr); + + switch (data_encoding) + { + case P_sRGB: + /* Change to 8-bit sRGB */ + png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, PNG_GAMMA_sRGB); + /* FALL THROUGH */ + + case P_FILE: + if (png_ptr->bit_depth > 8) + png_set_scale_16(png_ptr); + break; + +#ifdef __GNUC__ + default: + png_error(png_ptr, "bad data option (internal error)"); +#endif + } + + if (cmap_entries > 256 || cmap_entries > image->colormap_entries) + png_error(png_ptr, "color map overflow (BAD internal error)"); + + image->colormap_entries = cmap_entries; + + /* Double check using the recorded background index */ + switch (output_processing) + { + case PNG_CMAP_NONE: + if (background_index != PNG_CMAP_NONE_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_GA: + if (background_index != PNG_CMAP_GA_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_TRANS: + if (background_index >= cmap_entries || + background_index != PNG_CMAP_TRANS_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_RGB: + if (background_index != PNG_CMAP_RGB_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_RGB_ALPHA: + if (background_index != PNG_CMAP_RGB_ALPHA_BACKGROUND) + goto bad_background; + break; + + default: + png_error(png_ptr, "bad processing option (internal error)"); + + bad_background: + png_error(png_ptr, "bad background index (internal error)"); + } + + display->colormap_processing = output_processing; + + return 1/*ok*/; +} + +/* The final part of the color-map read called from png_image_finish_read. */ +static int +png_image_read_and_map(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + int passes; + + /* Called when the libpng data must be transformed into the color-mapped + * form. There is a local row buffer in display->local and this routine must + * do the interlace handling. + */ + switch (png_ptr->interlaced) + { + case PNG_INTERLACE_NONE: + passes = 1; + break; + + case PNG_INTERLACE_ADAM7: + passes = PNG_INTERLACE_ADAM7_PASSES; + break; + + default: + png_error(png_ptr, "unknown interlace type"); + } + + { + png_uint_32 height = image->height; + png_uint_32 width = image->width; + int proc = display->colormap_processing; + png_bytep first_row = png_voidcast(png_bytep, display->first_row); + ptrdiff_t step_row = display->row_bytes; + int pass; + + for (pass = 0; pass < passes; ++pass) + { + unsigned int startx, stepx, stepy; + png_uint_32 y; + + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass); + stepx = PNG_PASS_COL_OFFSET(pass); + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = stepy = 1; + } + + for (; ylocal_row); + png_bytep outrow = first_row + y * step_row; + png_const_bytep end_row = outrow + width; + + /* Read read the libpng data into the temporary buffer. */ + png_read_row(png_ptr, inrow, NULL); + + /* Now process the row according to the processing option, note + * that the caller verifies that the format of the libpng output + * data is as required. + */ + outrow += startx; + switch (proc) + { + case PNG_CMAP_GA: + for (; outrow < end_row; outrow += stepx) + { + /* The data is always in the PNG order */ + unsigned int gray = *inrow++; + unsigned int alpha = *inrow++; + unsigned int entry; + + /* NOTE: this code is copied as a comment in + * make_ga_colormap above. Please update the + * comment if you change this code! + */ + if (alpha > 229) /* opaque */ + { + entry = (231 * gray + 128) >> 8; + } + else if (alpha < 26) /* transparent */ + { + entry = 231; + } + else /* partially opaque */ + { + entry = 226 + 6 * PNG_DIV51(alpha) + PNG_DIV51(gray); + } + + *outrow = (png_byte)entry; + } + break; + + case PNG_CMAP_TRANS: + for (; outrow < end_row; outrow += stepx) + { + png_byte gray = *inrow++; + png_byte alpha = *inrow++; + + if (alpha == 0) + *outrow = PNG_CMAP_TRANS_BACKGROUND; + + else if (gray != PNG_CMAP_TRANS_BACKGROUND) + *outrow = gray; + + else + *outrow = (png_byte)(PNG_CMAP_TRANS_BACKGROUND+1); + } + break; + + case PNG_CMAP_RGB: + for (; outrow < end_row; outrow += stepx) + { + *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], inrow[2]); + inrow += 3; + } + break; + + case PNG_CMAP_RGB_ALPHA: + for (; outrow < end_row; outrow += stepx) + { + unsigned int alpha = inrow[3]; + + /* Because the alpha entries only hold alpha==0.5 values + * split the processing at alpha==0.25 (64) and 0.75 + * (196). + */ + + if (alpha >= 196) + *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], + inrow[2]); + + else if (alpha < 64) + *outrow = PNG_CMAP_RGB_ALPHA_BACKGROUND; + + else + { + /* Likewise there are three entries for each of r, g + * and b. We could select the entry by popcount on + * the top two bits on those architectures that + * support it, this is what the code below does, + * crudely. + */ + unsigned int back_i = PNG_CMAP_RGB_ALPHA_BACKGROUND+1; + + /* Here are how the values map: + * + * 0x00 .. 0x3f -> 0 + * 0x40 .. 0xbf -> 1 + * 0xc0 .. 0xff -> 2 + * + * So, as above with the explicit alpha checks, the + * breakpoints are at 64 and 196. + */ + if (inrow[0] & 0x80) back_i += 9; /* red */ + if (inrow[0] & 0x40) back_i += 9; + if (inrow[0] & 0x80) back_i += 3; /* green */ + if (inrow[0] & 0x40) back_i += 3; + if (inrow[0] & 0x80) back_i += 1; /* blue */ + if (inrow[0] & 0x40) back_i += 1; + + *outrow = (png_byte)back_i; + } + + inrow += 4; + } + break; + + default: + break; + } + } + } + } + + return 1; +} + +static int +png_image_read_colormapped(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_controlp control = image->opaque; + png_structrp png_ptr = control->png_ptr; + png_inforp info_ptr = control->info_ptr; + + int passes = 0; /* As a flag */ + + PNG_SKIP_CHUNKS(png_ptr); + + /* Update the 'info' structure and make sure the result is as required; first + * make sure to turn on the interlace handling if it will be required + * (because it can't be turned on *after* the call to png_read_update_info!) + */ + if (display->colormap_processing == PNG_CMAP_NONE) + passes = png_set_interlace_handling(png_ptr); + + png_read_update_info(png_ptr, info_ptr); + + /* The expected output can be deduced from the colormap_processing option. */ + switch (display->colormap_processing) + { + case PNG_CMAP_NONE: + /* Output must be one channel and one byte per pixel, the output + * encoding can be anything. + */ + if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE || + info_ptr->color_type == PNG_COLOR_TYPE_GRAY) && + info_ptr->bit_depth == 8) + break; + + goto bad_output; + + case PNG_CMAP_TRANS: + case PNG_CMAP_GA: + /* Output must be two channels and the 'G' one must be sRGB, the latter + * can be checked with an exact number because it should have been set + * to this number above! + */ + if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + info_ptr->bit_depth == 8 && + png_ptr->screen_gamma == PNG_GAMMA_sRGB && + image->colormap_entries == 256) + break; + + goto bad_output; + + case PNG_CMAP_RGB: + /* Output must be 8-bit sRGB encoded RGB */ + if (info_ptr->color_type == PNG_COLOR_TYPE_RGB && + info_ptr->bit_depth == 8 && + png_ptr->screen_gamma == PNG_GAMMA_sRGB && + image->colormap_entries == 216) + break; + + goto bad_output; + + case PNG_CMAP_RGB_ALPHA: + /* Output must be 8-bit sRGB encoded RGBA */ + if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA && + info_ptr->bit_depth == 8 && + png_ptr->screen_gamma == PNG_GAMMA_sRGB && + image->colormap_entries == 244 /* 216 + 1 + 27 */) + break; + + /* goto bad_output; */ + /* FALL THROUGH */ + + default: + bad_output: + png_error(png_ptr, "bad color-map processing (internal error)"); + } + + /* Now read the rows. Do this here if it is possible to read directly into + * the output buffer, otherwise allocate a local row buffer of the maximum + * size libpng requires and call the relevant processing routine safely. + */ + { + png_voidp first_row = display->buffer; + ptrdiff_t row_bytes = display->row_stride; + + /* The following expression is designed to work correctly whether it gives + * a signed or an unsigned result. + */ + if (row_bytes < 0) + { + char *ptr = png_voidcast(char*, first_row); + ptr += (image->height-1) * (-row_bytes); + first_row = png_voidcast(png_voidp, ptr); + } + + display->first_row = first_row; + display->row_bytes = row_bytes; + } + + if (passes == 0) + { + int result; + png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); + + display->local_row = row; + result = png_safe_execute(image, png_image_read_and_map, display); + display->local_row = NULL; + png_free(png_ptr, row); + + return result; + } + + else + { + png_alloc_size_t row_bytes = display->row_bytes; + + while (--passes >= 0) + { + png_uint_32 y = image->height; + png_bytep row = png_voidcast(png_bytep, display->first_row); + + while (y-- > 0) + { + png_read_row(png_ptr, row, NULL); + row += row_bytes; + } + } + + return 1; + } +} + +/* Just the row reading part of png_image_read. */ +static int +png_image_read_composite(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + int passes; + + switch (png_ptr->interlaced) + { + case PNG_INTERLACE_NONE: + passes = 1; + break; + + case PNG_INTERLACE_ADAM7: + passes = PNG_INTERLACE_ADAM7_PASSES; + break; + + default: + png_error(png_ptr, "unknown interlace type"); + } + + { + png_uint_32 height = image->height; + png_uint_32 width = image->width; + ptrdiff_t step_row = display->row_bytes; + unsigned int channels = + (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; + int pass; + + for (pass = 0; pass < passes; ++pass) + { + unsigned int startx, stepx, stepy; + png_uint_32 y; + + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass) * channels; + stepx = PNG_PASS_COL_OFFSET(pass) * channels; + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = channels; + stepy = 1; + } + + for (; ylocal_row); + png_bytep outrow; + png_const_bytep end_row; + + /* Read the row, which is packed: */ + png_read_row(png_ptr, inrow, NULL); + + outrow = png_voidcast(png_bytep, display->first_row); + outrow += y * step_row; + end_row = outrow + width * channels; + + /* Now do the composition on each pixel in this row. */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_byte alpha = inrow[channels]; + + if (alpha > 0) /* else no change to the output */ + { + unsigned int c; + + for (c=0; cimage; + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + png_uint_32 height = image->height; + png_uint_32 width = image->width; + int pass, passes; + + /* Double check the convoluted logic below. We expect to get here with + * libpng doing rgb to gray and gamma correction but background processing + * left to the png_image_read_background function. The rows libpng produce + * might be 8 or 16-bit but should always have two channels; gray plus alpha. + */ + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == 0) + png_error(png_ptr, "lost rgb to gray"); + + if ((png_ptr->transformations & PNG_COMPOSE) != 0) + png_error(png_ptr, "unexpected compose"); + + if (png_get_channels(png_ptr, info_ptr) != 2) + png_error(png_ptr, "lost/gained channels"); + + /* Expect the 8-bit case to always remove the alpha channel */ + if ((image->format & PNG_FORMAT_FLAG_LINEAR) == 0 && + (image->format & PNG_FORMAT_FLAG_ALPHA) != 0) + png_error(png_ptr, "unexpected 8-bit transformation"); + + switch (png_ptr->interlaced) + { + case PNG_INTERLACE_NONE: + passes = 1; + break; + + case PNG_INTERLACE_ADAM7: + passes = PNG_INTERLACE_ADAM7_PASSES; + break; + + default: + png_error(png_ptr, "unknown interlace type"); + } + + /* Use direct access to info_ptr here because otherwise the simplified API + * would require PNG_EASY_ACCESS_SUPPORTED (just for this.) Note this is + * checking the value after libpng expansions, not the original value in the + * PNG. + */ + switch (info_ptr->bit_depth) + { + case 8: + /* 8-bit sRGB gray values with an alpha channel; the alpha channel is + * to be removed by composing on a background: either the row if + * display->background is NULL or display->background->green if not. + * Unlike the code above ALPHA_OPTIMIZED has *not* been done. + */ + { + png_bytep first_row = png_voidcast(png_bytep, display->first_row); + ptrdiff_t step_row = display->row_bytes; + + for (pass = 0; pass < passes; ++pass) + { + png_bytep row = png_voidcast(png_bytep, + display->first_row); + unsigned int startx, stepx, stepy; + png_uint_32 y; + + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass); + stepx = PNG_PASS_COL_OFFSET(pass); + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = stepy = 1; + } + + if (display->background == NULL) + { + for (; ylocal_row); + png_bytep outrow = first_row + y * step_row; + png_const_bytep end_row = outrow + width; + + /* Read the row, which is packed: */ + png_read_row(png_ptr, inrow, NULL); + + /* Now do the composition on each pixel in this row. */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_byte alpha = inrow[1]; + + if (alpha > 0) /* else no change to the output */ + { + png_uint_32 component = inrow[0]; + + if (alpha < 255) /* else just use component */ + { + /* Since PNG_OPTIMIZED_ALPHA was not set it is + * necessary to invert the sRGB transfer + * function and multiply the alpha out. + */ + component = png_sRGB_table[component] * alpha; + component += png_sRGB_table[outrow[0]] * + (255-alpha); + component = PNG_sRGB_FROM_LINEAR(component); + } + + outrow[0] = (png_byte)component; + } + + inrow += 2; /* gray and alpha channel */ + } + } + } + + else /* constant background value */ + { + png_byte background8 = display->background->green; + png_uint_16 background = png_sRGB_table[background8]; + + for (; ylocal_row); + png_bytep outrow = first_row + y * step_row; + png_const_bytep end_row = outrow + width; + + /* Read the row, which is packed: */ + png_read_row(png_ptr, inrow, NULL); + + /* Now do the composition on each pixel in this row. */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_byte alpha = inrow[1]; + + if (alpha > 0) /* else use background */ + { + png_uint_32 component = inrow[0]; + + if (alpha < 255) /* else just use component */ + { + component = png_sRGB_table[component] * alpha; + component += background * (255-alpha); + component = PNG_sRGB_FROM_LINEAR(component); + } + + outrow[0] = (png_byte)component; + } + + else + outrow[0] = background8; + + inrow += 2; /* gray and alpha channel */ + } + + row += display->row_bytes; + } + } + } + } + break; + + case 16: + /* 16-bit linear with pre-multiplied alpha; the pre-multiplication must + * still be done and, maybe, the alpha channel removed. This code also + * handles the alpha-first option. + */ + { + png_uint_16p first_row = png_voidcast(png_uint_16p, + display->first_row); + /* The division by two is safe because the caller passed in a + * stride which was multiplied by 2 (below) to get row_bytes. + */ + ptrdiff_t step_row = display->row_bytes / 2; + int preserve_alpha = (image->format & PNG_FORMAT_FLAG_ALPHA) != 0; + unsigned int outchannels = 1+preserve_alpha; + int swap_alpha = 0; + +# ifdef PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED + if (preserve_alpha != 0 && + (image->format & PNG_FORMAT_FLAG_AFIRST) != 0) + swap_alpha = 1; +# endif + + for (pass = 0; pass < passes; ++pass) + { + unsigned int startx, stepx, stepy; + png_uint_32 y; + + /* The 'x' start and step are adjusted to output components here. + */ + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass) * outchannels; + stepx = PNG_PASS_COL_OFFSET(pass) * outchannels; + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = outchannels; + stepy = 1; + } + + for (; ylocal_row), NULL); + inrow = png_voidcast(png_const_uint_16p, display->local_row); + + /* Now do the pre-multiplication on each pixel in this row. + */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_uint_32 component = inrow[0]; + png_uint_16 alpha = inrow[1]; + + if (alpha > 0) /* else 0 */ + { + if (alpha < 65535) /* else just use component */ + { + component *= alpha; + component += 32767; + component /= 65535; + } + } + + else + component = 0; + + outrow[swap_alpha] = (png_uint_16)component; + if (preserve_alpha != 0) + outrow[1 ^ swap_alpha] = alpha; + + inrow += 2; /* components and alpha channel */ + } + } + } + } + break; + +#ifdef __GNUC__ + default: + png_error(png_ptr, "unexpected bit depth"); +#endif + } + + return 1; +} + +/* The guts of png_image_finish_read as a png_safe_execute callback. */ +static int +png_image_read_direct(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + + png_uint_32 format = image->format; + int linear = (format & PNG_FORMAT_FLAG_LINEAR) != 0; + int do_local_compose = 0; + int do_local_background = 0; /* to avoid double gamma correction bug */ + int passes = 0; + + /* Add transforms to ensure the correct output format is produced then check + * that the required implementation support is there. Always expand; always + * need 8 bits minimum, no palette and expanded tRNS. + */ + png_set_expand(png_ptr); + + /* Now check the format to see if it was modified. */ + { + png_uint_32 base_format = png_image_format(png_ptr) & + ~PNG_FORMAT_FLAG_COLORMAP /* removed by png_set_expand */; + png_uint_32 change = format ^ base_format; + png_fixed_point output_gamma; + int mode; /* alpha mode */ + + /* Do this first so that we have a record if rgb to gray is happening. */ + if ((change & PNG_FORMAT_FLAG_COLOR) != 0) + { + /* gray<->color transformation required. */ + if ((format & PNG_FORMAT_FLAG_COLOR) != 0) + png_set_gray_to_rgb(png_ptr); + + else + { + /* libpng can't do both rgb to gray and + * background/pre-multiplication if there is also significant gamma + * correction, because both operations require linear colors and + * the code only supports one transform doing the gamma correction. + * Handle this by doing the pre-multiplication or background + * operation in this code, if necessary. + * + * TODO: fix this by rewriting pngrtran.c (!) + * + * For the moment (given that fixing this in pngrtran.c is an + * enormous change) 'do_local_background' is used to indicate that + * the problem exists. + */ + if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0) + do_local_background = 1/*maybe*/; + + png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, + PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT); + } + + change &= ~PNG_FORMAT_FLAG_COLOR; + } + + /* Set the gamma appropriately, linear for 16-bit input, sRGB otherwise. + */ + { + png_fixed_point input_gamma_default; + + if ((base_format & PNG_FORMAT_FLAG_LINEAR) != 0 && + (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) + input_gamma_default = PNG_GAMMA_LINEAR; + else + input_gamma_default = PNG_DEFAULT_sRGB; + + /* Call png_set_alpha_mode to set the default for the input gamma; the + * output gamma is set by a second call below. + */ + png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, input_gamma_default); + } + + if (linear != 0) + { + /* If there *is* an alpha channel in the input it must be multiplied + * out; use PNG_ALPHA_STANDARD, otherwise just use PNG_ALPHA_PNG. + */ + if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0) + mode = PNG_ALPHA_STANDARD; /* associated alpha */ + + else + mode = PNG_ALPHA_PNG; + + output_gamma = PNG_GAMMA_LINEAR; + } + + else + { + mode = PNG_ALPHA_PNG; + output_gamma = PNG_DEFAULT_sRGB; + } + + /* If 'do_local_background' is set check for the presence of gamma + * correction; this is part of the work-round for the libpng bug + * described above. + * + * TODO: fix libpng and remove this. + */ + if (do_local_background != 0) + { + png_fixed_point gtest; + + /* This is 'png_gamma_threshold' from pngrtran.c; the test used for + * gamma correction, the screen gamma hasn't been set on png_struct + * yet; it's set below. png_struct::gamma, however, is set to the + * final value. + */ + if (png_muldiv(>est, output_gamma, png_ptr->colorspace.gamma, + PNG_FP_1) != 0 && png_gamma_significant(gtest) == 0) + do_local_background = 0; + + else if (mode == PNG_ALPHA_STANDARD) + { + do_local_background = 2/*required*/; + mode = PNG_ALPHA_PNG; /* prevent libpng doing it */ + } + + /* else leave as 1 for the checks below */ + } + + /* If the bit-depth changes then handle that here. */ + if ((change & PNG_FORMAT_FLAG_LINEAR) != 0) + { + if (linear != 0 /*16-bit output*/) + png_set_expand_16(png_ptr); + + else /* 8-bit output */ + png_set_scale_16(png_ptr); + + change &= ~PNG_FORMAT_FLAG_LINEAR; + } + + /* Now the background/alpha channel changes. */ + if ((change & PNG_FORMAT_FLAG_ALPHA) != 0) + { + /* Removing an alpha channel requires composition for the 8-bit + * formats; for the 16-bit it is already done, above, by the + * pre-multiplication and the channel just needs to be stripped. + */ + if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + /* If RGB->gray is happening the alpha channel must be left and the + * operation completed locally. + * + * TODO: fix libpng and remove this. + */ + if (do_local_background != 0) + do_local_background = 2/*required*/; + + /* 16-bit output: just remove the channel */ + else if (linear != 0) /* compose on black (well, pre-multiply) */ + png_set_strip_alpha(png_ptr); + + /* 8-bit output: do an appropriate compose */ + else if (display->background != NULL) + { + png_color_16 c; + + c.index = 0; /*unused*/ + c.red = display->background->red; + c.green = display->background->green; + c.blue = display->background->blue; + c.gray = display->background->green; + + /* This is always an 8-bit sRGB value, using the 'green' channel + * for gray is much better than calculating the luminance here; + * we can get off-by-one errors in that calculation relative to + * the app expectations and that will show up in transparent + * pixels. + */ + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + } + + else /* compose on row: implemented below. */ + { + do_local_compose = 1; + /* This leaves the alpha channel in the output, so it has to be + * removed by the code below. Set the encoding to the 'OPTIMIZE' + * one so the code only has to hack on the pixels that require + * composition. + */ + mode = PNG_ALPHA_OPTIMIZED; + } + } + + else /* output needs an alpha channel */ + { + /* This is tricky because it happens before the swap operation has + * been accomplished; however, the swap does *not* swap the added + * alpha channel (weird API), so it must be added in the correct + * place. + */ + png_uint_32 filler; /* opaque filler */ + int where; + + if (linear != 0) + filler = 65535; + + else + filler = 255; + +#ifdef PNG_FORMAT_AFIRST_SUPPORTED + if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + where = PNG_FILLER_BEFORE; + change &= ~PNG_FORMAT_FLAG_AFIRST; + } + + else +#endif + where = PNG_FILLER_AFTER; + + png_set_add_alpha(png_ptr, filler, where); + } + + /* This stops the (irrelevant) call to swap_alpha below. */ + change &= ~PNG_FORMAT_FLAG_ALPHA; + } + + /* Now set the alpha mode correctly; this is always done, even if there is + * no alpha channel in either the input or the output because it correctly + * sets the output gamma. + */ + png_set_alpha_mode_fixed(png_ptr, mode, output_gamma); + +# ifdef PNG_FORMAT_BGR_SUPPORTED + if ((change & PNG_FORMAT_FLAG_BGR) != 0) + { + /* Check only the output format; PNG is never BGR; don't do this if + * the output is gray, but fix up the 'format' value in that case. + */ + if ((format & PNG_FORMAT_FLAG_COLOR) != 0) + png_set_bgr(png_ptr); + + else + format &= ~PNG_FORMAT_FLAG_BGR; + + change &= ~PNG_FORMAT_FLAG_BGR; + } +# endif + +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + if ((change & PNG_FORMAT_FLAG_AFIRST) != 0) + { + /* Only relevant if there is an alpha channel - it's particularly + * important to handle this correctly because do_local_compose may + * be set above and then libpng will keep the alpha channel for this + * code to remove. + */ + if ((format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + /* Disable this if doing a local background, + * TODO: remove this when local background is no longer required. + */ + if (do_local_background != 2) + png_set_swap_alpha(png_ptr); + } + + else + format &= ~PNG_FORMAT_FLAG_AFIRST; + + change &= ~PNG_FORMAT_FLAG_AFIRST; + } +# endif + + /* If the *output* is 16-bit then we need to check for a byte-swap on this + * architecture. + */ + if (linear != 0) + { + PNG_CONST png_uint_16 le = 0x0001; + + if ((*(png_const_bytep) & le) != 0) + png_set_swap(png_ptr); + } + + /* If change is not now 0 some transformation is missing - error out. */ + if (change != 0) + png_error(png_ptr, "png_read_image: unsupported transformation"); + } + + PNG_SKIP_CHUNKS(png_ptr); + + /* Update the 'info' structure and make sure the result is as required; first + * make sure to turn on the interlace handling if it will be required + * (because it can't be turned on *after* the call to png_read_update_info!) + * + * TODO: remove the do_local_background fixup below. + */ + if (do_local_compose == 0 && do_local_background != 2) + passes = png_set_interlace_handling(png_ptr); + + png_read_update_info(png_ptr, info_ptr); + + { + png_uint_32 info_format = 0; + + if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + info_format |= PNG_FORMAT_FLAG_COLOR; + + if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) + { + /* do_local_compose removes this channel below. */ + if (do_local_compose == 0) + { + /* do_local_background does the same if required. */ + if (do_local_background != 2 || + (format & PNG_FORMAT_FLAG_ALPHA) != 0) + info_format |= PNG_FORMAT_FLAG_ALPHA; + } + } + + else if (do_local_compose != 0) /* internal error */ + png_error(png_ptr, "png_image_read: alpha channel lost"); + + if (info_ptr->bit_depth == 16) + info_format |= PNG_FORMAT_FLAG_LINEAR; + +#ifdef PNG_FORMAT_BGR_SUPPORTED + if ((png_ptr->transformations & PNG_BGR) != 0) + info_format |= PNG_FORMAT_FLAG_BGR; +#endif + +#ifdef PNG_FORMAT_AFIRST_SUPPORTED + if (do_local_background == 2) + { + if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) + info_format |= PNG_FORMAT_FLAG_AFIRST; + } + + if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0 || + ((png_ptr->transformations & PNG_ADD_ALPHA) != 0 && + (png_ptr->flags & PNG_FLAG_FILLER_AFTER) == 0)) + { + if (do_local_background == 2) + png_error(png_ptr, "unexpected alpha swap transformation"); + + info_format |= PNG_FORMAT_FLAG_AFIRST; + } +# endif + + /* This is actually an internal error. */ + if (info_format != format) + png_error(png_ptr, "png_read_image: invalid transformations"); + } + + /* Now read the rows. If do_local_compose is set then it is necessary to use + * a local row buffer. The output will be GA, RGBA or BGRA and must be + * converted to G, RGB or BGR as appropriate. The 'local_row' member of the + * display acts as a flag. + */ + { + png_voidp first_row = display->buffer; + ptrdiff_t row_bytes = display->row_stride; + + if (linear != 0) + row_bytes *= 2; + + /* The following expression is designed to work correctly whether it gives + * a signed or an unsigned result. + */ + if (row_bytes < 0) + { + char *ptr = png_voidcast(char*, first_row); + ptr += (image->height-1) * (-row_bytes); + first_row = png_voidcast(png_voidp, ptr); + } + + display->first_row = first_row; + display->row_bytes = row_bytes; + } + + if (do_local_compose != 0) + { + int result; + png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); + + display->local_row = row; + result = png_safe_execute(image, png_image_read_composite, display); + display->local_row = NULL; + png_free(png_ptr, row); + + return result; + } + + else if (do_local_background == 2) + { + int result; + png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); + + display->local_row = row; + result = png_safe_execute(image, png_image_read_background, display); + display->local_row = NULL; + png_free(png_ptr, row); + + return result; + } + + else + { + png_alloc_size_t row_bytes = display->row_bytes; + + while (--passes >= 0) + { + png_uint_32 y = image->height; + png_bytep row = png_voidcast(png_bytep, display->first_row); + + while (y-- > 0) + { + png_read_row(png_ptr, row, NULL); + row += row_bytes; + } + } + + return 1; + } +} + +int PNGAPI +png_image_finish_read(png_imagep image, png_const_colorp background, + void *buffer, png_int_32 row_stride, void *colormap) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + /* Check for row_stride overflow. This check is not performed on the + * original PNG format because it may not occur in the output PNG format + * and libpng deals with the issues of reading the original. + */ + const unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format); + + if (image->width <= 0x7FFFFFFFU/channels) /* no overflow */ + { + png_uint_32 check; + const png_uint_32 png_row_stride = image->width * channels; + + if (row_stride == 0) + row_stride = (png_int_32)/*SAFE*/png_row_stride; + + if (row_stride < 0) + check = -row_stride; + + else + check = row_stride; + + if (image->opaque != NULL && buffer != NULL && check >= png_row_stride) + { + /* Now check for overflow of the image buffer calculation; this + * limits the whole image size to 32 bits for API compatibility with + * the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro. + */ + if (image->height <= 0xFFFFFFFF/png_row_stride) + { + if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 || + (image->colormap_entries > 0 && colormap != NULL)) + { + int result; + png_image_read_control display; + + memset(&display, 0, (sizeof display)); + display.image = image; + display.buffer = buffer; + display.row_stride = row_stride; + display.colormap = colormap; + display.background = background; + display.local_row = NULL; + + /* Choose the correct 'end' routine; for the color-map case + * all the setup has already been done. + */ + if ((image->format & PNG_FORMAT_FLAG_COLORMAP) != 0) + result = png_safe_execute(image, + png_image_read_colormap, &display) && + png_safe_execute(image, + png_image_read_colormapped, &display); + + else + result = + png_safe_execute(image, + png_image_read_direct, &display); + + png_image_free(image); + return result; + } + + else + return png_image_error(image, + "png_image_finish_read[color-map]: no color-map"); + } + + else + return png_image_error(image, + "png_image_finish_read: image too large"); + } + + else + return png_image_error(image, + "png_image_finish_read: invalid argument"); + } + + else + return png_image_error(image, + "png_image_finish_read: row_stride too large"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_finish_read: damaged PNG_IMAGE_VERSION"); + + return 0; +} + +#endif /* SIMPLIFIED_READ */ +#endif /* READ */ diff --git a/source/Irrlicht/libpng/pngrio.c b/source/Irrlicht/libpng/pngrio.c new file mode 100644 index 00000000..99cb5715 --- /dev/null +++ b/source/Irrlicht/libpng/pngrio.c @@ -0,0 +1,120 @@ + +/* pngrio.c - functions for data input + * + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all input. Users who need + * special handling are expected to write a function that has the same + * arguments as this and performs a similar function, but that possibly + * has a different input method. Note that you shouldn't change this + * function, but rather write a replacement function and then make + * libpng use it at run time with png_set_read_fn(...). + */ + +#include "pngpriv.h" + +#ifdef PNG_READ_SUPPORTED + +/* Read the data from whatever input you are using. The default routine + * reads from a file pointer. Note that this routine sometimes gets called + * with very small lengths, so you should implement some kind of simple + * buffering if you are using unbuffered reads. This should never be asked + * to read more than 64K on a 16-bit machine. + */ +void /* PRIVATE */ +png_read_data(png_structrp png_ptr, png_bytep data, png_size_t length) +{ + png_debug1(4, "reading %d bytes", (int)length); + + if (png_ptr->read_data_fn != NULL) + (*(png_ptr->read_data_fn))(png_ptr, data, length); + + else + png_error(png_ptr, "Call to NULL read function"); +} + +#ifdef PNG_STDIO_SUPPORTED +/* This is the function that does the actual reading of data. If you are + * not reading from a standard C stream, you should create a replacement + * read_data function and use it at run time with png_set_read_fn(), rather + * than changing the library. + */ +void PNGCBAPI +png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check; + + if (png_ptr == NULL) + return; + + /* fread() returns 0 on error, so it is OK to store this in a png_size_t + * instead of an int, which is what fread() actually returns. + */ + check = fread(data, 1, length, png_voidcast(png_FILE_p, png_ptr->io_ptr)); + + if (check != length) + png_error(png_ptr, "Read Error"); +} +#endif + +/* This function allows the application to supply a new input function + * for libpng if standard C streams aren't being used. + * + * This function takes as its arguments: + * + * png_ptr - pointer to a png input data structure + * + * io_ptr - pointer to user supplied structure containing info about + * the input functions. May be NULL. + * + * read_data_fn - pointer to a new input function that takes as its + * arguments a pointer to a png_struct, a pointer to + * a location where input data can be stored, and a 32-bit + * unsigned int that is the number of bytes to be read. + * To exit and output any fatal error messages the new write + * function should call png_error(png_ptr, "Error msg"). + * May be NULL, in which case libpng's default function will + * be used. + */ +void PNGAPI +png_set_read_fn(png_structrp png_ptr, png_voidp io_ptr, + png_rw_ptr read_data_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->io_ptr = io_ptr; + +#ifdef PNG_STDIO_SUPPORTED + if (read_data_fn != NULL) + png_ptr->read_data_fn = read_data_fn; + + else + png_ptr->read_data_fn = png_default_read_data; +#else + png_ptr->read_data_fn = read_data_fn; +#endif + +#ifdef PNG_WRITE_SUPPORTED + /* It is an error to write to a read device */ + if (png_ptr->write_data_fn != NULL) + { + png_ptr->write_data_fn = NULL; + png_warning(png_ptr, + "Can't set both read_data_fn and write_data_fn in the" + " same structure"); + } +#endif + +#ifdef PNG_WRITE_FLUSH_SUPPORTED + png_ptr->output_flush_fn = NULL; +#endif +} +#endif /* READ */ diff --git a/source/Irrlicht/libpng/pngrtran.c b/source/Irrlicht/libpng/pngrtran.c new file mode 100644 index 00000000..0fc53ec6 --- /dev/null +++ b/source/Irrlicht/libpng/pngrtran.c @@ -0,0 +1,5000 @@ + +/* pngrtran.c - transforms the data in a row for PNG readers + * + * Last changed in libpng 1.6.22 [May 26, 2016] + * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file contains functions optionally called by an application + * in order to tell libpng how to handle data when reading a PNG. + * Transformations that are used in both reading and writing are + * in pngtrans.c. + */ + +#include "pngpriv.h" + +#ifdef PNG_READ_SUPPORTED + +/* Set the action on getting a CRC error for an ancillary or critical chunk. */ +void PNGAPI +png_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action) +{ + png_debug(1, "in png_set_crc_action"); + + if (png_ptr == NULL) + return; + + /* Tell libpng how we react to CRC errors in critical chunks */ + switch (crit_action) + { + case PNG_CRC_NO_CHANGE: /* Leave setting as is */ + break; + + case PNG_CRC_WARN_USE: /* Warn/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE; + break; + + case PNG_CRC_QUIET_USE: /* Quiet/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE | + PNG_FLAG_CRC_CRITICAL_IGNORE; + break; + + case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */ + png_warning(png_ptr, + "Can't discard critical data on CRC error"); + case PNG_CRC_ERROR_QUIT: /* Error/quit */ + + case PNG_CRC_DEFAULT: + default: + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + break; + } + + /* Tell libpng how we react to CRC errors in ancillary chunks */ + switch (ancil_action) + { + case PNG_CRC_NO_CHANGE: /* Leave setting as is */ + break; + + case PNG_CRC_WARN_USE: /* Warn/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE; + break; + + case PNG_CRC_QUIET_USE: /* Quiet/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE | + PNG_FLAG_CRC_ANCILLARY_NOWARN; + break; + + case PNG_CRC_ERROR_QUIT: /* Error/quit */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN; + break; + + case PNG_CRC_WARN_DISCARD: /* Warn/discard data */ + + case PNG_CRC_DEFAULT: + default: + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + break; + } +} + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +/* Is it OK to set a transformation now? Only if png_start_read_image or + * png_read_update_info have not been called. It is not necessary for the IHDR + * to have been read in all cases; the need_IHDR parameter allows for this + * check too. + */ +static int +png_rtran_ok(png_structrp png_ptr, int need_IHDR) +{ + if (png_ptr != NULL) + { + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) != 0) + png_app_error(png_ptr, + "invalid after png_start_read_image or png_read_update_info"); + + else if (need_IHDR && (png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_app_error(png_ptr, "invalid before the PNG header has been read"); + + else + { + /* Turn on failure to initialize correctly for all transforms. */ + png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED; + + return 1; /* Ok */ + } + } + + return 0; /* no png_error possible! */ +} +#endif + +#ifdef PNG_READ_BACKGROUND_SUPPORTED +/* Handle alpha and tRNS via a background color */ +void PNGFAPI +png_set_background_fixed(png_structrp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, png_fixed_point background_gamma) +{ + png_debug(1, "in png_set_background_fixed"); + + if (png_rtran_ok(png_ptr, 0) == 0 || background_color == NULL) + return; + + if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN) + { + png_warning(png_ptr, "Application must supply a known background gamma"); + return; + } + + png_ptr->transformations |= PNG_COMPOSE | PNG_STRIP_ALPHA; + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + + png_ptr->background = *background_color; + png_ptr->background_gamma = background_gamma; + png_ptr->background_gamma_type = (png_byte)(background_gamma_code); + if (need_expand != 0) + png_ptr->transformations |= PNG_BACKGROUND_EXPAND; + else + png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND; +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_background(png_structrp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma) +{ + png_set_background_fixed(png_ptr, background_color, background_gamma_code, + need_expand, png_fixed(png_ptr, background_gamma, "png_set_background")); +} +# endif /* FLOATING_POINT */ +#endif /* READ_BACKGROUND */ + +/* Scale 16-bit depth files to 8-bit depth. If both of these are set then the + * one that pngrtran does first (scale) happens. This is necessary to allow the + * TRANSFORM and API behavior to be somewhat consistent, and it's simpler. + */ +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +void PNGAPI +png_set_scale_16(png_structrp png_ptr) +{ + png_debug(1, "in png_set_scale_16"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= PNG_SCALE_16_TO_8; +} +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +/* Chop 16-bit depth files to 8-bit depth */ +void PNGAPI +png_set_strip_16(png_structrp png_ptr) +{ + png_debug(1, "in png_set_strip_16"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= PNG_16_TO_8; +} +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED +void PNGAPI +png_set_strip_alpha(png_structrp png_ptr) +{ + png_debug(1, "in png_set_strip_alpha"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= PNG_STRIP_ALPHA; +} +#endif + +#if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED) +static png_fixed_point +translate_gamma_flags(png_structrp png_ptr, png_fixed_point output_gamma, + int is_screen) +{ + /* Check for flag values. The main reason for having the old Mac value as a + * flag is that it is pretty near impossible to work out what the correct + * value is from Apple documentation - a working Mac system is needed to + * discover the value! + */ + if (output_gamma == PNG_DEFAULT_sRGB || + output_gamma == PNG_FP_1 / PNG_DEFAULT_sRGB) + { + /* If there is no sRGB support this just sets the gamma to the standard + * sRGB value. (This is a side effect of using this function!) + */ +# ifdef PNG_READ_sRGB_SUPPORTED + png_ptr->flags |= PNG_FLAG_ASSUME_sRGB; +# else + PNG_UNUSED(png_ptr) +# endif + if (is_screen != 0) + output_gamma = PNG_GAMMA_sRGB; + else + output_gamma = PNG_GAMMA_sRGB_INVERSE; + } + + else if (output_gamma == PNG_GAMMA_MAC_18 || + output_gamma == PNG_FP_1 / PNG_GAMMA_MAC_18) + { + if (is_screen != 0) + output_gamma = PNG_GAMMA_MAC_OLD; + else + output_gamma = PNG_GAMMA_MAC_INVERSE; + } + + return output_gamma; +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +static png_fixed_point +convert_gamma_value(png_structrp png_ptr, double output_gamma) +{ + /* The following silently ignores cases where fixed point (times 100,000) + * gamma values are passed to the floating point API. This is safe and it + * means the fixed point constants work just fine with the floating point + * API. The alternative would just lead to undetected errors and spurious + * bug reports. Negative values fail inside the _fixed API unless they + * correspond to the flag values. + */ + if (output_gamma > 0 && output_gamma < 128) + output_gamma *= PNG_FP_1; + + /* This preserves -1 and -2 exactly: */ + output_gamma = floor(output_gamma + .5); + + if (output_gamma > PNG_FP_MAX || output_gamma < PNG_FP_MIN) + png_fixed_error(png_ptr, "gamma value"); + + return (png_fixed_point)output_gamma; +} +# endif +#endif /* READ_ALPHA_MODE || READ_GAMMA */ + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +void PNGFAPI +png_set_alpha_mode_fixed(png_structrp png_ptr, int mode, + png_fixed_point output_gamma) +{ + int compose = 0; + png_fixed_point file_gamma; + + png_debug(1, "in png_set_alpha_mode"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/); + + /* Validate the value to ensure it is in a reasonable range. The value + * is expected to be 1 or greater, but this range test allows for some + * viewing correction values. The intent is to weed out users of this API + * who use the inverse of the gamma value accidentally! Since some of these + * values are reasonable this may have to be changed: + * + * 1.6.x: changed from 0.07..3 to 0.01..100 (to accomodate the optimal 16-bit + * gamma of 36, and its reciprocal.) + */ + if (output_gamma < 1000 || output_gamma > 10000000) + png_error(png_ptr, "output gamma out of expected range"); + + /* The default file gamma is the inverse of the output gamma; the output + * gamma may be changed below so get the file value first: + */ + file_gamma = png_reciprocal(output_gamma); + + /* There are really 8 possibilities here, composed of any combination + * of: + * + * premultiply the color channels + * do not encode non-opaque pixels + * encode the alpha as well as the color channels + * + * The differences disappear if the input/output ('screen') gamma is 1.0, + * because then the encoding is a no-op and there is only the choice of + * premultiplying the color channels or not. + * + * png_set_alpha_mode and png_set_background interact because both use + * png_compose to do the work. Calling both is only useful when + * png_set_alpha_mode is used to set the default mode - PNG_ALPHA_PNG - along + * with a default gamma value. Otherwise PNG_COMPOSE must not be set. + */ + switch (mode) + { + case PNG_ALPHA_PNG: /* default: png standard */ + /* No compose, but it may be set by png_set_background! */ + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + break; + + case PNG_ALPHA_ASSOCIATED: /* color channels premultiplied */ + compose = 1; + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + /* The output is linear: */ + output_gamma = PNG_FP_1; + break; + + case PNG_ALPHA_OPTIMIZED: /* associated, non-opaque pixels linear */ + compose = 1; + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags |= PNG_FLAG_OPTIMIZE_ALPHA; + /* output_gamma records the encoding of opaque pixels! */ + break; + + case PNG_ALPHA_BROKEN: /* associated, non-linear, alpha encoded */ + compose = 1; + png_ptr->transformations |= PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + break; + + default: + png_error(png_ptr, "invalid alpha mode"); + } + + /* Only set the default gamma if the file gamma has not been set (this has + * the side effect that the gamma in a second call to png_set_alpha_mode will + * be ignored.) + */ + if (png_ptr->colorspace.gamma == 0) + { + png_ptr->colorspace.gamma = file_gamma; + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; + } + + /* But always set the output gamma: */ + png_ptr->screen_gamma = output_gamma; + + /* Finally, if pre-multiplying, set the background fields to achieve the + * desired result. + */ + if (compose != 0) + { + /* And obtain alpha pre-multiplication by composing on black: */ + memset(&png_ptr->background, 0, (sizeof png_ptr->background)); + png_ptr->background_gamma = png_ptr->colorspace.gamma; /* just in case */ + png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_FILE; + png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND; + + if ((png_ptr->transformations & PNG_COMPOSE) != 0) + png_error(png_ptr, + "conflicting calls to set alpha mode and background"); + + png_ptr->transformations |= PNG_COMPOSE; + } +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma) +{ + png_set_alpha_mode_fixed(png_ptr, mode, convert_gamma_value(png_ptr, + output_gamma)); +} +# endif +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +/* Dither file to 8-bit. Supply a palette, the current number + * of elements in the palette, the maximum number of elements + * allowed, and a histogram if possible. If the current number + * of colors is greater than the maximum number, the palette will be + * modified to fit in the maximum number. "full_quantize" indicates + * whether we need a quantizing cube set up for RGB images, or if we + * simply are reducing the number of colors in a paletted image. + */ + +typedef struct png_dsort_struct +{ + struct png_dsort_struct * next; + png_byte left; + png_byte right; +} png_dsort; +typedef png_dsort * png_dsortp; +typedef png_dsort * * png_dsortpp; + +void PNGAPI +png_set_quantize(png_structrp png_ptr, png_colorp palette, + int num_palette, int maximum_colors, png_const_uint_16p histogram, + int full_quantize) +{ + png_debug(1, "in png_set_quantize"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= PNG_QUANTIZE; + + if (full_quantize == 0) + { + int i; + + png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * (sizeof (png_byte)))); + for (i = 0; i < num_palette; i++) + png_ptr->quantize_index[i] = (png_byte)i; + } + + if (num_palette > maximum_colors) + { + if (histogram != NULL) + { + /* This is easy enough, just throw out the least used colors. + * Perhaps not the best solution, but good enough. + */ + + int i; + + /* Initialize an array to sort colors */ + png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * (sizeof (png_byte)))); + + /* Initialize the quantize_sort array */ + for (i = 0; i < num_palette; i++) + png_ptr->quantize_sort[i] = (png_byte)i; + + /* Find the least used palette entries by starting a + * bubble sort, and running it until we have sorted + * out enough colors. Note that we don't care about + * sorting all the colors, just finding which are + * least used. + */ + + for (i = num_palette - 1; i >= maximum_colors; i--) + { + int done; /* To stop early if the list is pre-sorted */ + int j; + + done = 1; + for (j = 0; j < i; j++) + { + if (histogram[png_ptr->quantize_sort[j]] + < histogram[png_ptr->quantize_sort[j + 1]]) + { + png_byte t; + + t = png_ptr->quantize_sort[j]; + png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1]; + png_ptr->quantize_sort[j + 1] = t; + done = 0; + } + } + + if (done != 0) + break; + } + + /* Swap the palette around, and set up a table, if necessary */ + if (full_quantize != 0) + { + int j = num_palette; + + /* Put all the useful colors within the max, but don't + * move the others. + */ + for (i = 0; i < maximum_colors; i++) + { + if ((int)png_ptr->quantize_sort[i] >= maximum_colors) + { + do + j--; + while ((int)png_ptr->quantize_sort[j] >= maximum_colors); + + palette[i] = palette[j]; + } + } + } + else + { + int j = num_palette; + + /* Move all the used colors inside the max limit, and + * develop a translation table. + */ + for (i = 0; i < maximum_colors; i++) + { + /* Only move the colors we need to */ + if ((int)png_ptr->quantize_sort[i] >= maximum_colors) + { + png_color tmp_color; + + do + j--; + while ((int)png_ptr->quantize_sort[j] >= maximum_colors); + + tmp_color = palette[j]; + palette[j] = palette[i]; + palette[i] = tmp_color; + /* Indicate where the color went */ + png_ptr->quantize_index[j] = (png_byte)i; + png_ptr->quantize_index[i] = (png_byte)j; + } + } + + /* Find closest color for those colors we are not using */ + for (i = 0; i < num_palette; i++) + { + if ((int)png_ptr->quantize_index[i] >= maximum_colors) + { + int min_d, k, min_k, d_index; + + /* Find the closest color to one we threw out */ + d_index = png_ptr->quantize_index[i]; + min_d = PNG_COLOR_DIST(palette[d_index], palette[0]); + for (k = 1, min_k = 0; k < maximum_colors; k++) + { + int d; + + d = PNG_COLOR_DIST(palette[d_index], palette[k]); + + if (d < min_d) + { + min_d = d; + min_k = k; + } + } + /* Point to closest color */ + png_ptr->quantize_index[i] = (png_byte)min_k; + } + } + } + png_free(png_ptr, png_ptr->quantize_sort); + png_ptr->quantize_sort = NULL; + } + else + { + /* This is much harder to do simply (and quickly). Perhaps + * we need to go through a median cut routine, but those + * don't always behave themselves with only a few colors + * as input. So we will just find the closest two colors, + * and throw out one of them (chosen somewhat randomly). + * [We don't understand this at all, so if someone wants to + * work on improving it, be our guest - AED, GRP] + */ + int i; + int max_d; + int num_new_palette; + png_dsortp t; + png_dsortpp hash; + + t = NULL; + + /* Initialize palette index arrays */ + png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * (sizeof (png_byte)))); + png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * (sizeof (png_byte)))); + + /* Initialize the sort array */ + for (i = 0; i < num_palette; i++) + { + png_ptr->index_to_palette[i] = (png_byte)i; + png_ptr->palette_to_index[i] = (png_byte)i; + } + + hash = (png_dsortpp)png_calloc(png_ptr, (png_uint_32)(769 * + (sizeof (png_dsortp)))); + + num_new_palette = num_palette; + + /* Initial wild guess at how far apart the farthest pixel + * pair we will be eliminating will be. Larger + * numbers mean more areas will be allocated, Smaller + * numbers run the risk of not saving enough data, and + * having to do this all over again. + * + * I have not done extensive checking on this number. + */ + max_d = 96; + + while (num_new_palette > maximum_colors) + { + for (i = 0; i < num_new_palette - 1; i++) + { + int j; + + for (j = i + 1; j < num_new_palette; j++) + { + int d; + + d = PNG_COLOR_DIST(palette[i], palette[j]); + + if (d <= max_d) + { + + t = (png_dsortp)png_malloc_warn(png_ptr, + (png_uint_32)(sizeof (png_dsort))); + + if (t == NULL) + break; + + t->next = hash[d]; + t->left = (png_byte)i; + t->right = (png_byte)j; + hash[d] = t; + } + } + if (t == NULL) + break; + } + + if (t != NULL) + for (i = 0; i <= max_d; i++) + { + if (hash[i] != NULL) + { + png_dsortp p; + + for (p = hash[i]; p; p = p->next) + { + if ((int)png_ptr->index_to_palette[p->left] + < num_new_palette && + (int)png_ptr->index_to_palette[p->right] + < num_new_palette) + { + int j, next_j; + + if (num_new_palette & 0x01) + { + j = p->left; + next_j = p->right; + } + else + { + j = p->right; + next_j = p->left; + } + + num_new_palette--; + palette[png_ptr->index_to_palette[j]] + = palette[num_new_palette]; + if (full_quantize == 0) + { + int k; + + for (k = 0; k < num_palette; k++) + { + if (png_ptr->quantize_index[k] == + png_ptr->index_to_palette[j]) + png_ptr->quantize_index[k] = + png_ptr->index_to_palette[next_j]; + + if ((int)png_ptr->quantize_index[k] == + num_new_palette) + png_ptr->quantize_index[k] = + png_ptr->index_to_palette[j]; + } + } + + png_ptr->index_to_palette[png_ptr->palette_to_index + [num_new_palette]] = png_ptr->index_to_palette[j]; + + png_ptr->palette_to_index[png_ptr->index_to_palette[j]] + = png_ptr->palette_to_index[num_new_palette]; + + png_ptr->index_to_palette[j] = + (png_byte)num_new_palette; + + png_ptr->palette_to_index[num_new_palette] = + (png_byte)j; + } + if (num_new_palette <= maximum_colors) + break; + } + if (num_new_palette <= maximum_colors) + break; + } + } + + for (i = 0; i < 769; i++) + { + if (hash[i] != NULL) + { + png_dsortp p = hash[i]; + while (p) + { + t = p->next; + png_free(png_ptr, p); + p = t; + } + } + hash[i] = 0; + } + max_d += 96; + } + png_free(png_ptr, hash); + png_free(png_ptr, png_ptr->palette_to_index); + png_free(png_ptr, png_ptr->index_to_palette); + png_ptr->palette_to_index = NULL; + png_ptr->index_to_palette = NULL; + } + num_palette = maximum_colors; + } + if (png_ptr->palette == NULL) + { + png_ptr->palette = palette; + } + png_ptr->num_palette = (png_uint_16)num_palette; + + if (full_quantize != 0) + { + int i; + png_bytep distance; + int total_bits = PNG_QUANTIZE_RED_BITS + PNG_QUANTIZE_GREEN_BITS + + PNG_QUANTIZE_BLUE_BITS; + int num_red = (1 << PNG_QUANTIZE_RED_BITS); + int num_green = (1 << PNG_QUANTIZE_GREEN_BITS); + int num_blue = (1 << PNG_QUANTIZE_BLUE_BITS); + png_size_t num_entries = ((png_size_t)1 << total_bits); + + png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr, + (png_uint_32)(num_entries * (sizeof (png_byte)))); + + distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries * + (sizeof (png_byte)))); + + memset(distance, 0xff, num_entries * (sizeof (png_byte))); + + for (i = 0; i < num_palette; i++) + { + int ir, ig, ib; + int r = (palette[i].red >> (8 - PNG_QUANTIZE_RED_BITS)); + int g = (palette[i].green >> (8 - PNG_QUANTIZE_GREEN_BITS)); + int b = (palette[i].blue >> (8 - PNG_QUANTIZE_BLUE_BITS)); + + for (ir = 0; ir < num_red; ir++) + { + /* int dr = abs(ir - r); */ + int dr = ((ir > r) ? ir - r : r - ir); + int index_r = (ir << (PNG_QUANTIZE_BLUE_BITS + + PNG_QUANTIZE_GREEN_BITS)); + + for (ig = 0; ig < num_green; ig++) + { + /* int dg = abs(ig - g); */ + int dg = ((ig > g) ? ig - g : g - ig); + int dt = dr + dg; + int dm = ((dr > dg) ? dr : dg); + int index_g = index_r | (ig << PNG_QUANTIZE_BLUE_BITS); + + for (ib = 0; ib < num_blue; ib++) + { + int d_index = index_g | ib; + /* int db = abs(ib - b); */ + int db = ((ib > b) ? ib - b : b - ib); + int dmax = ((dm > db) ? dm : db); + int d = dmax + dt + db; + + if (d < (int)distance[d_index]) + { + distance[d_index] = (png_byte)d; + png_ptr->palette_lookup[d_index] = (png_byte)i; + } + } + } + } + } + + png_free(png_ptr, distance); + } +} +#endif /* READ_QUANTIZE */ + +#ifdef PNG_READ_GAMMA_SUPPORTED +void PNGFAPI +png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma, + png_fixed_point file_gamma) +{ + png_debug(1, "in png_set_gamma_fixed"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + /* New in libpng-1.5.4 - reserve particular negative values as flags. */ + scrn_gamma = translate_gamma_flags(png_ptr, scrn_gamma, 1/*screen*/); + file_gamma = translate_gamma_flags(png_ptr, file_gamma, 0/*file*/); + + /* Checking the gamma values for being >0 was added in 1.5.4 along with the + * premultiplied alpha support; this actually hides an undocumented feature + * of the previous implementation which allowed gamma processing to be + * disabled in background handling. There is no evidence (so far) that this + * was being used; however, png_set_background itself accepted and must still + * accept '0' for the gamma value it takes, because it isn't always used. + * + * Since this is an API change (albeit a very minor one that removes an + * undocumented API feature) the following checks were only enabled in + * libpng-1.6.0. + */ + if (file_gamma <= 0) + png_error(png_ptr, "invalid file gamma in png_set_gamma"); + + if (scrn_gamma <= 0) + png_error(png_ptr, "invalid screen gamma in png_set_gamma"); + + /* Set the gamma values unconditionally - this overrides the value in the PNG + * file if a gAMA chunk was present. png_set_alpha_mode provides a + * different, easier, way to default the file gamma. + */ + png_ptr->colorspace.gamma = file_gamma; + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; + png_ptr->screen_gamma = scrn_gamma; +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_gamma(png_structrp png_ptr, double scrn_gamma, double file_gamma) +{ + png_set_gamma_fixed(png_ptr, convert_gamma_value(png_ptr, scrn_gamma), + convert_gamma_value(png_ptr, file_gamma)); +} +# endif /* FLOATING_POINT */ +#endif /* READ_GAMMA */ + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* Expand paletted images to RGB, expand grayscale images of + * less than 8-bit depth to 8-bit depth, and expand tRNS chunks + * to alpha channels. + */ +void PNGAPI +png_set_expand(png_structrp png_ptr) +{ + png_debug(1, "in png_set_expand"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); +} + +/* GRR 19990627: the following three functions currently are identical + * to png_set_expand(). However, it is entirely reasonable that someone + * might wish to expand an indexed image to RGB but *not* expand a single, + * fully transparent palette entry to a full alpha channel--perhaps instead + * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace + * the transparent color with a particular RGB value, or drop tRNS entirely. + * IOW, a future version of the library may make the transformations flag + * a bit more fine-grained, with separate bits for each of these three + * functions. + * + * More to the point, these functions make it obvious what libpng will be + * doing, whereas "expand" can (and does) mean any number of things. + * + * GRP 20060307: In libpng-1.2.9, png_set_gray_1_2_4_to_8() was modified + * to expand only the sample depth but not to expand the tRNS to alpha + * and its name was changed to png_set_expand_gray_1_2_4_to_8(). + */ + +/* Expand paletted images to RGB. */ +void PNGAPI +png_set_palette_to_rgb(png_structrp png_ptr) +{ + png_debug(1, "in png_set_palette_to_rgb"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); +} + +/* Expand grayscale images of less than 8-bit depth to 8 bits. */ +void PNGAPI +png_set_expand_gray_1_2_4_to_8(png_structrp png_ptr) +{ + png_debug(1, "in png_set_expand_gray_1_2_4_to_8"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= PNG_EXPAND; +} + +/* Expand tRNS chunks to alpha channels. */ +void PNGAPI +png_set_tRNS_to_alpha(png_structrp png_ptr) +{ + png_debug(1, "in png_set_tRNS_to_alpha"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); +} +#endif /* READ_EXPAND */ + +#ifdef PNG_READ_EXPAND_16_SUPPORTED +/* Expand to 16-bit channels, expand the tRNS chunk too (because otherwise + * it may not work correctly.) + */ +void PNGAPI +png_set_expand_16(png_structrp png_ptr) +{ + png_debug(1, "in png_set_expand_16"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + png_ptr->transformations |= (PNG_EXPAND_16 | PNG_EXPAND | PNG_EXPAND_tRNS); +} +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +void PNGAPI +png_set_gray_to_rgb(png_structrp png_ptr) +{ + png_debug(1, "in png_set_gray_to_rgb"); + + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + /* Because rgb must be 8 bits or more: */ + png_set_expand_gray_1_2_4_to_8(png_ptr); + png_ptr->transformations |= PNG_GRAY_TO_RGB; +} +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +void PNGFAPI +png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action, + png_fixed_point red, png_fixed_point green) +{ + png_debug(1, "in png_set_rgb_to_gray"); + + /* Need the IHDR here because of the check on color_type below. */ + /* TODO: fix this */ + if (png_rtran_ok(png_ptr, 1) == 0) + return; + + switch (error_action) + { + case PNG_ERROR_ACTION_NONE: + png_ptr->transformations |= PNG_RGB_TO_GRAY; + break; + + case PNG_ERROR_ACTION_WARN: + png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN; + break; + + case PNG_ERROR_ACTION_ERROR: + png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR; + break; + + default: + png_error(png_ptr, "invalid error action to rgb_to_gray"); + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) +#ifdef PNG_READ_EXPAND_SUPPORTED + png_ptr->transformations |= PNG_EXPAND; +#else + { + /* Make this an error in 1.6 because otherwise the application may assume + * that it just worked and get a memory overwrite. + */ + png_error(png_ptr, + "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED"); + + /* png_ptr->transformations &= ~PNG_RGB_TO_GRAY; */ + } +#endif + { + if (red >= 0 && green >= 0 && red + green <= PNG_FP_1) + { + png_uint_16 red_int, green_int; + + /* NOTE: this calculation does not round, but this behavior is retained + * for consistency; the inaccuracy is very small. The code here always + * overwrites the coefficients, regardless of whether they have been + * defaulted or set already. + */ + red_int = (png_uint_16)(((png_uint_32)red*32768)/100000); + green_int = (png_uint_16)(((png_uint_32)green*32768)/100000); + + png_ptr->rgb_to_gray_red_coeff = red_int; + png_ptr->rgb_to_gray_green_coeff = green_int; + png_ptr->rgb_to_gray_coefficients_set = 1; + } + + else + { + if (red >= 0 && green >= 0) + png_app_warning(png_ptr, + "ignoring out of range rgb_to_gray coefficients"); + + /* Use the defaults, from the cHRM chunk if set, else the historical + * values which are close to the sRGB/HDTV/ITU-Rec 709 values. See + * png_do_rgb_to_gray for more discussion of the values. In this case + * the coefficients are not marked as 'set' and are not overwritten if + * something has already provided a default. + */ + if (png_ptr->rgb_to_gray_red_coeff == 0 && + png_ptr->rgb_to_gray_green_coeff == 0) + { + png_ptr->rgb_to_gray_red_coeff = 6968; + png_ptr->rgb_to_gray_green_coeff = 23434; + /* png_ptr->rgb_to_gray_blue_coeff = 2366; */ + } + } + } +} + +#ifdef PNG_FLOATING_POINT_SUPPORTED +/* Convert a RGB image to a grayscale of the same width. This allows us, + * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image. + */ + +void PNGAPI +png_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red, + double green) +{ + png_set_rgb_to_gray_fixed(png_ptr, error_action, + png_fixed(png_ptr, red, "rgb to gray red coefficient"), + png_fixed(png_ptr, green, "rgb to gray green coefficient")); +} +#endif /* FLOATING POINT */ + +#endif /* RGB_TO_GRAY */ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +void PNGAPI +png_set_read_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr + read_user_transform_fn) +{ + png_debug(1, "in png_set_read_user_transform_fn"); + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + png_ptr->transformations |= PNG_USER_TRANSFORM; + png_ptr->read_user_transform_fn = read_user_transform_fn; +#endif +} +#endif + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +#ifdef PNG_READ_GAMMA_SUPPORTED +/* In the case of gamma transformations only do transformations on images where + * the [file] gamma and screen_gamma are not close reciprocals, otherwise it + * slows things down slightly, and also needlessly introduces small errors. + */ +static int /* PRIVATE */ +png_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma) +{ + /* PNG_GAMMA_THRESHOLD is the threshold for performing gamma + * correction as a difference of the overall transform from 1.0 + * + * We want to compare the threshold with s*f - 1, if we get + * overflow here it is because of wacky gamma values so we + * turn on processing anyway. + */ + png_fixed_point gtest; + return !png_muldiv(>est, screen_gamma, file_gamma, PNG_FP_1) || + png_gamma_significant(gtest); +} +#endif + +/* Initialize everything needed for the read. This includes modifying + * the palette. + */ + +/* For the moment 'png_init_palette_transformations' and + * 'png_init_rgb_transformations' only do some flag canceling optimizations. + * The intent is that these two routines should have palette or rgb operations + * extracted from 'png_init_read_transformations'. + */ +static void /* PRIVATE */ +png_init_palette_transformations(png_structrp png_ptr) +{ + /* Called to handle the (input) palette case. In png_do_read_transformations + * the first step is to expand the palette if requested, so this code must + * take care to only make changes that are invariant with respect to the + * palette expansion, or only do them if there is no expansion. + * + * STRIP_ALPHA has already been handled in the caller (by setting num_trans + * to 0.) + */ + int input_has_alpha = 0; + int input_has_transparency = 0; + + if (png_ptr->num_trans > 0) + { + int i; + + /* Ignore if all the entries are opaque (unlikely!) */ + for (i=0; inum_trans; ++i) + { + if (png_ptr->trans_alpha[i] == 255) + continue; + else if (png_ptr->trans_alpha[i] == 0) + input_has_transparency = 1; + else + { + input_has_transparency = 1; + input_has_alpha = 1; + break; + } + } + } + + /* If no alpha we can optimize. */ + if (input_has_alpha == 0) + { + /* Any alpha means background and associative alpha processing is + * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA + * and ENCODE_ALPHA are irrelevant. + */ + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + + if (input_has_transparency == 0) + png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND); + } + +#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) + /* png_set_background handling - deals with the complexity of whether the + * background color is in the file format or the screen format in the case + * where an 'expand' will happen. + */ + + /* The following code cannot be entered in the alpha pre-multiplication case + * because PNG_BACKGROUND_EXPAND is cancelled below. + */ + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 && + (png_ptr->transformations & PNG_EXPAND) != 0) + { + { + png_ptr->background.red = + png_ptr->palette[png_ptr->background.index].red; + png_ptr->background.green = + png_ptr->palette[png_ptr->background.index].green; + png_ptr->background.blue = + png_ptr->palette[png_ptr->background.index].blue; + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) + { + if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0) + { + /* Invert the alpha channel (in tRNS) unless the pixels are + * going to be expanded, in which case leave it for later + */ + int i, istop = png_ptr->num_trans; + + for (i=0; itrans_alpha[i] = (png_byte)(255 - + png_ptr->trans_alpha[i]); + } + } +#endif /* READ_INVERT_ALPHA */ + } + } /* background expand and (therefore) no alpha association. */ +#endif /* READ_EXPAND && READ_BACKGROUND */ +} + +static void /* PRIVATE */ +png_init_rgb_transformations(png_structrp png_ptr) +{ + /* Added to libpng-1.5.4: check the color type to determine whether there + * is any alpha or transparency in the image and simply cancel the + * background and alpha mode stuff if there isn't. + */ + int input_has_alpha = (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0; + int input_has_transparency = png_ptr->num_trans > 0; + + /* If no alpha we can optimize. */ + if (input_has_alpha == 0) + { + /* Any alpha means background and associative alpha processing is + * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA + * and ENCODE_ALPHA are irrelevant. + */ +# ifdef PNG_READ_ALPHA_MODE_SUPPORTED + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; +# endif + + if (input_has_transparency == 0) + png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND); + } + +#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) + /* png_set_background handling - deals with the complexity of whether the + * background color is in the file format or the screen format in the case + * where an 'expand' will happen. + */ + + /* The following code cannot be entered in the alpha pre-multiplication case + * because PNG_BACKGROUND_EXPAND is cancelled below. + */ + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 && + (png_ptr->transformations & PNG_EXPAND) != 0 && + (png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) + /* i.e., GRAY or GRAY_ALPHA */ + { + { + /* Expand background and tRNS chunks */ + int gray = png_ptr->background.gray; + int trans_gray = png_ptr->trans_color.gray; + + switch (png_ptr->bit_depth) + { + case 1: + gray *= 0xff; + trans_gray *= 0xff; + break; + + case 2: + gray *= 0x55; + trans_gray *= 0x55; + break; + + case 4: + gray *= 0x11; + trans_gray *= 0x11; + break; + + default: + + case 8: + /* FALL THROUGH (Already 8 bits) */ + + case 16: + /* Already a full 16 bits */ + break; + } + + png_ptr->background.red = png_ptr->background.green = + png_ptr->background.blue = (png_uint_16)gray; + + if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0) + { + png_ptr->trans_color.red = png_ptr->trans_color.green = + png_ptr->trans_color.blue = (png_uint_16)trans_gray; + } + } + } /* background expand and (therefore) no alpha association. */ +#endif /* READ_EXPAND && READ_BACKGROUND */ +} + +void /* PRIVATE */ +png_init_read_transformations(png_structrp png_ptr) +{ + png_debug(1, "in png_init_read_transformations"); + + /* This internal function is called from png_read_start_row in pngrutil.c + * and it is called before the 'rowbytes' calculation is done, so the code + * in here can change or update the transformations flags. + * + * First do updates that do not depend on the details of the PNG image data + * being processed. + */ + +#ifdef PNG_READ_GAMMA_SUPPORTED + /* Prior to 1.5.4 these tests were performed from png_set_gamma, 1.5.4 adds + * png_set_alpha_mode and this is another source for a default file gamma so + * the test needs to be performed later - here. In addition prior to 1.5.4 + * the tests were repeated for the PALETTE color type here - this is no + * longer necessary (and doesn't seem to have been necessary before.) + */ + { + /* The following temporary indicates if overall gamma correction is + * required. + */ + int gamma_correction = 0; + + if (png_ptr->colorspace.gamma != 0) /* has been set */ + { + if (png_ptr->screen_gamma != 0) /* screen set too */ + gamma_correction = png_gamma_threshold(png_ptr->colorspace.gamma, + png_ptr->screen_gamma); + + else + /* Assume the output matches the input; a long time default behavior + * of libpng, although the standard has nothing to say about this. + */ + png_ptr->screen_gamma = png_reciprocal(png_ptr->colorspace.gamma); + } + + else if (png_ptr->screen_gamma != 0) + /* The converse - assume the file matches the screen, note that this + * perhaps undesireable default can (from 1.5.4) be changed by calling + * png_set_alpha_mode (even if the alpha handling mode isn't required + * or isn't changed from the default.) + */ + png_ptr->colorspace.gamma = png_reciprocal(png_ptr->screen_gamma); + + else /* neither are set */ + /* Just in case the following prevents any processing - file and screen + * are both assumed to be linear and there is no way to introduce a + * third gamma value other than png_set_background with 'UNIQUE', and, + * prior to 1.5.4 + */ + png_ptr->screen_gamma = png_ptr->colorspace.gamma = PNG_FP_1; + + /* We have a gamma value now. */ + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; + + /* Now turn the gamma transformation on or off as appropriate. Notice + * that PNG_GAMMA just refers to the file->screen correction. Alpha + * composition may independently cause gamma correction because it needs + * linear data (e.g. if the file has a gAMA chunk but the screen gamma + * hasn't been specified.) In any case this flag may get turned off in + * the code immediately below if the transform can be handled outside the + * row loop. + */ + if (gamma_correction != 0) + png_ptr->transformations |= PNG_GAMMA; + + else + png_ptr->transformations &= ~PNG_GAMMA; + } +#endif + + /* Certain transformations have the effect of preventing other + * transformations that happen afterward in png_do_read_transformations; + * resolve the interdependencies here. From the code of + * png_do_read_transformations the order is: + * + * 1) PNG_EXPAND (including PNG_EXPAND_tRNS) + * 2) PNG_STRIP_ALPHA (if no compose) + * 3) PNG_RGB_TO_GRAY + * 4) PNG_GRAY_TO_RGB iff !PNG_BACKGROUND_IS_GRAY + * 5) PNG_COMPOSE + * 6) PNG_GAMMA + * 7) PNG_STRIP_ALPHA (if compose) + * 8) PNG_ENCODE_ALPHA + * 9) PNG_SCALE_16_TO_8 + * 10) PNG_16_TO_8 + * 11) PNG_QUANTIZE (converts to palette) + * 12) PNG_EXPAND_16 + * 13) PNG_GRAY_TO_RGB iff PNG_BACKGROUND_IS_GRAY + * 14) PNG_INVERT_MONO + * 15) PNG_INVERT_ALPHA + * 16) PNG_SHIFT + * 17) PNG_PACK + * 18) PNG_BGR + * 19) PNG_PACKSWAP + * 20) PNG_FILLER (includes PNG_ADD_ALPHA) + * 21) PNG_SWAP_ALPHA + * 22) PNG_SWAP_BYTES + * 23) PNG_USER_TRANSFORM [must be last] + */ +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && + (png_ptr->transformations & PNG_COMPOSE) == 0) + { + /* Stripping the alpha channel happens immediately after the 'expand' + * transformations, before all other transformation, so it cancels out + * the alpha handling. It has the side effect negating the effect of + * PNG_EXPAND_tRNS too: + */ + png_ptr->transformations &= ~(PNG_BACKGROUND_EXPAND | PNG_ENCODE_ALPHA | + PNG_EXPAND_tRNS); + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + + /* Kill the tRNS chunk itself too. Prior to 1.5.4 this did not happen + * so transparency information would remain just so long as it wasn't + * expanded. This produces unexpected API changes if the set of things + * that do PNG_EXPAND_tRNS changes (perfectly possible given the + * documentation - which says ask for what you want, accept what you + * get.) This makes the behavior consistent from 1.5.4: + */ + png_ptr->num_trans = 0; + } +#endif /* STRIP_ALPHA supported, no COMPOSE */ + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + /* If the screen gamma is about 1.0 then the OPTIMIZE_ALPHA and ENCODE_ALPHA + * settings will have no effect. + */ + if (png_gamma_significant(png_ptr->screen_gamma) == 0) + { + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + } +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* Make sure the coefficients for the rgb to gray conversion are set + * appropriately. + */ + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) + png_colorspace_set_rgb_coefficients(png_ptr); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) + /* Detect gray background and attempt to enable optimization for + * gray --> RGB case. + * + * Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or + * RGB_ALPHA (in which case need_expand is superfluous anyway), the + * background color might actually be gray yet not be flagged as such. + * This is not a problem for the current code, which uses + * PNG_BACKGROUND_IS_GRAY only to decide when to do the + * png_do_gray_to_rgb() transformation. + * + * TODO: this code needs to be revised to avoid the complexity and + * interdependencies. The color type of the background should be recorded in + * png_set_background, along with the bit depth, then the code has a record + * of exactly what color space the background is currently in. + */ + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0) + { + /* PNG_BACKGROUND_EXPAND: the background is in the file color space, so if + * the file was grayscale the background value is gray. + */ + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) + png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; + } + + else if ((png_ptr->transformations & PNG_COMPOSE) != 0) + { + /* PNG_COMPOSE: png_set_background was called with need_expand false, + * so the color is in the color space of the output or png_set_alpha_mode + * was called and the color is black. Ignore RGB_TO_GRAY because that + * happens before GRAY_TO_RGB. + */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) + { + if (png_ptr->background.red == png_ptr->background.green && + png_ptr->background.red == png_ptr->background.blue) + { + png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; + png_ptr->background.gray = png_ptr->background.red; + } + } + } +#endif /* READ_EXPAND && READ_BACKGROUND */ +#endif /* READ_GRAY_TO_RGB */ + + /* For indexed PNG data (PNG_COLOR_TYPE_PALETTE) many of the transformations + * can be performed directly on the palette, and some (such as rgb to gray) + * can be optimized inside the palette. This is particularly true of the + * composite (background and alpha) stuff, which can be pretty much all done + * in the palette even if the result is expanded to RGB or gray afterward. + * + * NOTE: this is Not Yet Implemented, the code behaves as in 1.5.1 and + * earlier and the palette stuff is actually handled on the first row. This + * leads to the reported bug that the palette returned by png_get_PLTE is not + * updated. + */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + png_init_palette_transformations(png_ptr); + + else + png_init_rgb_transformations(png_ptr); + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + defined(PNG_READ_EXPAND_16_SUPPORTED) + if ((png_ptr->transformations & PNG_EXPAND_16) != 0 && + (png_ptr->transformations & PNG_COMPOSE) != 0 && + (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 && + png_ptr->bit_depth != 16) + { + /* TODO: fix this. Because the expand_16 operation is after the compose + * handling the background color must be 8, not 16, bits deep, but the + * application will supply a 16-bit value so reduce it here. + * + * The PNG_BACKGROUND_EXPAND code above does not expand to 16 bits at + * present, so that case is ok (until do_expand_16 is moved.) + * + * NOTE: this discards the low 16 bits of the user supplied background + * color, but until expand_16 works properly there is no choice! + */ +# define CHOP(x) (x)=((png_uint_16)PNG_DIV257(x)) + CHOP(png_ptr->background.red); + CHOP(png_ptr->background.green); + CHOP(png_ptr->background.blue); + CHOP(png_ptr->background.gray); +# undef CHOP + } +#endif /* READ_BACKGROUND && READ_EXPAND_16 */ + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + (defined(PNG_READ_SCALE_16_TO_8_SUPPORTED) || \ + defined(PNG_READ_STRIP_16_TO_8_SUPPORTED)) + if ((png_ptr->transformations & (PNG_16_TO_8|PNG_SCALE_16_TO_8)) != 0 && + (png_ptr->transformations & PNG_COMPOSE) != 0 && + (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 && + png_ptr->bit_depth == 16) + { + /* On the other hand, if a 16-bit file is to be reduced to 8-bits per + * component this will also happen after PNG_COMPOSE and so the background + * color must be pre-expanded here. + * + * TODO: fix this too. + */ + png_ptr->background.red = (png_uint_16)(png_ptr->background.red * 257); + png_ptr->background.green = + (png_uint_16)(png_ptr->background.green * 257); + png_ptr->background.blue = (png_uint_16)(png_ptr->background.blue * 257); + png_ptr->background.gray = (png_uint_16)(png_ptr->background.gray * 257); + } +#endif + + /* NOTE: below 'PNG_READ_ALPHA_MODE_SUPPORTED' is presumed to also enable the + * background support (see the comments in scripts/pnglibconf.dfa), this + * allows pre-multiplication of the alpha channel to be implemented as + * compositing on black. This is probably sub-optimal and has been done in + * 1.5.4 betas simply to enable external critique and testing (i.e. to + * implement the new API quickly, without lots of internal changes.) + */ + +#ifdef PNG_READ_GAMMA_SUPPORTED +# ifdef PNG_READ_BACKGROUND_SUPPORTED + /* Includes ALPHA_MODE */ + png_ptr->background_1 = png_ptr->background; +# endif + + /* This needs to change - in the palette image case a whole set of tables are + * built when it would be quicker to just calculate the correct value for + * each palette entry directly. Also, the test is too tricky - why check + * PNG_RGB_TO_GRAY if PNG_GAMMA is not set? The answer seems to be that + * PNG_GAMMA is cancelled even if the gamma is known? The test excludes the + * PNG_COMPOSE case, so apparently if there is no *overall* gamma correction + * the gamma tables will not be built even if composition is required on a + * gamma encoded value. + * + * In 1.5.4 this is addressed below by an additional check on the individual + * file gamma - if it is not 1.0 both RGB_TO_GRAY and COMPOSE need the + * tables. + */ + if ((png_ptr->transformations & PNG_GAMMA) != 0 || + ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0 && + (png_gamma_significant(png_ptr->colorspace.gamma) != 0 || + png_gamma_significant(png_ptr->screen_gamma) != 0)) || + ((png_ptr->transformations & PNG_COMPOSE) != 0 && + (png_gamma_significant(png_ptr->colorspace.gamma) != 0 || + png_gamma_significant(png_ptr->screen_gamma) != 0 +# ifdef PNG_READ_BACKGROUND_SUPPORTED + || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE && + png_gamma_significant(png_ptr->background_gamma) != 0) +# endif + )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 && + png_gamma_significant(png_ptr->screen_gamma) != 0)) + { + png_build_gamma_table(png_ptr, png_ptr->bit_depth); + +#ifdef PNG_READ_BACKGROUND_SUPPORTED + if ((png_ptr->transformations & PNG_COMPOSE) != 0) + { + /* Issue a warning about this combination: because RGB_TO_GRAY is + * optimized to do the gamma transform if present yet do_background has + * to do the same thing if both options are set a + * double-gamma-correction happens. This is true in all versions of + * libpng to date. + */ + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) + png_warning(png_ptr, + "libpng does not support gamma+background+rgb_to_gray"); + + if ((png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) != 0) + { + /* We don't get to here unless there is a tRNS chunk with non-opaque + * entries - see the checking code at the start of this function. + */ + png_color back, back_1; + png_colorp palette = png_ptr->palette; + int num_palette = png_ptr->num_palette; + int i; + if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE) + { + + back.red = png_ptr->gamma_table[png_ptr->background.red]; + back.green = png_ptr->gamma_table[png_ptr->background.green]; + back.blue = png_ptr->gamma_table[png_ptr->background.blue]; + + back_1.red = png_ptr->gamma_to_1[png_ptr->background.red]; + back_1.green = png_ptr->gamma_to_1[png_ptr->background.green]; + back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue]; + } + else + { + png_fixed_point g, gs; + + switch (png_ptr->background_gamma_type) + { + case PNG_BACKGROUND_GAMMA_SCREEN: + g = (png_ptr->screen_gamma); + gs = PNG_FP_1; + break; + + case PNG_BACKGROUND_GAMMA_FILE: + g = png_reciprocal(png_ptr->colorspace.gamma); + gs = png_reciprocal2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma); + break; + + case PNG_BACKGROUND_GAMMA_UNIQUE: + g = png_reciprocal(png_ptr->background_gamma); + gs = png_reciprocal2(png_ptr->background_gamma, + png_ptr->screen_gamma); + break; + default: + g = PNG_FP_1; /* back_1 */ + gs = PNG_FP_1; /* back */ + break; + } + + if (png_gamma_significant(gs) != 0) + { + back.red = png_gamma_8bit_correct(png_ptr->background.red, + gs); + back.green = png_gamma_8bit_correct(png_ptr->background.green, + gs); + back.blue = png_gamma_8bit_correct(png_ptr->background.blue, + gs); + } + + else + { + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; + } + + if (png_gamma_significant(g) != 0) + { + back_1.red = png_gamma_8bit_correct(png_ptr->background.red, + g); + back_1.green = png_gamma_8bit_correct( + png_ptr->background.green, g); + back_1.blue = png_gamma_8bit_correct(png_ptr->background.blue, + g); + } + + else + { + back_1.red = (png_byte)png_ptr->background.red; + back_1.green = (png_byte)png_ptr->background.green; + back_1.blue = (png_byte)png_ptr->background.blue; + } + } + + for (i = 0; i < num_palette; i++) + { + if (i < (int)png_ptr->num_trans && + png_ptr->trans_alpha[i] != 0xff) + { + if (png_ptr->trans_alpha[i] == 0) + { + palette[i] = back; + } + else /* if (png_ptr->trans_alpha[i] != 0xff) */ + { + png_byte v, w; + + v = png_ptr->gamma_to_1[palette[i].red]; + png_composite(w, v, png_ptr->trans_alpha[i], back_1.red); + palette[i].red = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[palette[i].green]; + png_composite(w, v, png_ptr->trans_alpha[i], back_1.green); + palette[i].green = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[palette[i].blue]; + png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue); + palette[i].blue = png_ptr->gamma_from_1[w]; + } + } + else + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } + + /* Prevent the transformations being done again. + * + * NOTE: this is highly dubious; it removes the transformations in + * place. This seems inconsistent with the general treatment of the + * transformations elsewhere. + */ + png_ptr->transformations &= ~(PNG_COMPOSE | PNG_GAMMA); + } /* color_type == PNG_COLOR_TYPE_PALETTE */ + + /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */ + else /* color_type != PNG_COLOR_TYPE_PALETTE */ + { + int gs_sig, g_sig; + png_fixed_point g = PNG_FP_1; /* Correction to linear */ + png_fixed_point gs = PNG_FP_1; /* Correction to screen */ + + switch (png_ptr->background_gamma_type) + { + case PNG_BACKGROUND_GAMMA_SCREEN: + g = png_ptr->screen_gamma; + /* gs = PNG_FP_1; */ + break; + + case PNG_BACKGROUND_GAMMA_FILE: + g = png_reciprocal(png_ptr->colorspace.gamma); + gs = png_reciprocal2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma); + break; + + case PNG_BACKGROUND_GAMMA_UNIQUE: + g = png_reciprocal(png_ptr->background_gamma); + gs = png_reciprocal2(png_ptr->background_gamma, + png_ptr->screen_gamma); + break; + + default: + png_error(png_ptr, "invalid background gamma type"); + } + + g_sig = png_gamma_significant(g); + gs_sig = png_gamma_significant(gs); + + if (g_sig != 0) + png_ptr->background_1.gray = png_gamma_correct(png_ptr, + png_ptr->background.gray, g); + + if (gs_sig != 0) + png_ptr->background.gray = png_gamma_correct(png_ptr, + png_ptr->background.gray, gs); + + if ((png_ptr->background.red != png_ptr->background.green) || + (png_ptr->background.red != png_ptr->background.blue) || + (png_ptr->background.red != png_ptr->background.gray)) + { + /* RGB or RGBA with color background */ + if (g_sig != 0) + { + png_ptr->background_1.red = png_gamma_correct(png_ptr, + png_ptr->background.red, g); + + png_ptr->background_1.green = png_gamma_correct(png_ptr, + png_ptr->background.green, g); + + png_ptr->background_1.blue = png_gamma_correct(png_ptr, + png_ptr->background.blue, g); + } + + if (gs_sig != 0) + { + png_ptr->background.red = png_gamma_correct(png_ptr, + png_ptr->background.red, gs); + + png_ptr->background.green = png_gamma_correct(png_ptr, + png_ptr->background.green, gs); + + png_ptr->background.blue = png_gamma_correct(png_ptr, + png_ptr->background.blue, gs); + } + } + + else + { + /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */ + png_ptr->background_1.red = png_ptr->background_1.green + = png_ptr->background_1.blue = png_ptr->background_1.gray; + + png_ptr->background.red = png_ptr->background.green + = png_ptr->background.blue = png_ptr->background.gray; + } + + /* The background is now in screen gamma: */ + png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_SCREEN; + } /* color_type != PNG_COLOR_TYPE_PALETTE */ + }/* png_ptr->transformations & PNG_BACKGROUND */ + + else + /* Transformation does not include PNG_BACKGROUND */ +#endif /* READ_BACKGROUND */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* RGB_TO_GRAY needs to have non-gamma-corrected values! */ + && ((png_ptr->transformations & PNG_EXPAND) == 0 || + (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0) +#endif + ) + { + png_colorp palette = png_ptr->palette; + int num_palette = png_ptr->num_palette; + int i; + + /* NOTE: there are other transformations that should probably be in + * here too. + */ + for (i = 0; i < num_palette; i++) + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + + /* Done the gamma correction. */ + png_ptr->transformations &= ~PNG_GAMMA; + } /* color_type == PALETTE && !PNG_BACKGROUND transformation */ + } +#ifdef PNG_READ_BACKGROUND_SUPPORTED + else +#endif +#endif /* READ_GAMMA */ + +#ifdef PNG_READ_BACKGROUND_SUPPORTED + /* No GAMMA transformation (see the hanging else 4 lines above) */ + if ((png_ptr->transformations & PNG_COMPOSE) != 0 && + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) + { + int i; + int istop = (int)png_ptr->num_trans; + png_color back; + png_colorp palette = png_ptr->palette; + + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; + + for (i = 0; i < istop; i++) + { + if (png_ptr->trans_alpha[i] == 0) + { + palette[i] = back; + } + + else if (png_ptr->trans_alpha[i] != 0xff) + { + /* The png_composite() macro is defined in png.h */ + png_composite(palette[i].red, palette[i].red, + png_ptr->trans_alpha[i], back.red); + + png_composite(palette[i].green, palette[i].green, + png_ptr->trans_alpha[i], back.green); + + png_composite(palette[i].blue, palette[i].blue, + png_ptr->trans_alpha[i], back.blue); + } + } + + png_ptr->transformations &= ~PNG_COMPOSE; + } +#endif /* READ_BACKGROUND */ + +#ifdef PNG_READ_SHIFT_SUPPORTED + if ((png_ptr->transformations & PNG_SHIFT) != 0 && + (png_ptr->transformations & PNG_EXPAND) == 0 && + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) + { + int i; + int istop = png_ptr->num_palette; + int shift = 8 - png_ptr->sig_bit.red; + + png_ptr->transformations &= ~PNG_SHIFT; + + /* significant bits can be in the range 1 to 7 for a meaninful result, if + * the number of significant bits is 0 then no shift is done (this is an + * error condition which is silently ignored.) + */ + if (shift > 0 && shift < 8) + for (i=0; ipalette[i].red; + + component >>= shift; + png_ptr->palette[i].red = (png_byte)component; + } + + shift = 8 - png_ptr->sig_bit.green; + if (shift > 0 && shift < 8) + for (i=0; ipalette[i].green; + + component >>= shift; + png_ptr->palette[i].green = (png_byte)component; + } + + shift = 8 - png_ptr->sig_bit.blue; + if (shift > 0 && shift < 8) + for (i=0; ipalette[i].blue; + + component >>= shift; + png_ptr->palette[i].blue = (png_byte)component; + } + } +#endif /* READ_SHIFT */ +} + +/* Modify the info structure to reflect the transformations. The + * info should be updated so a PNG file could be written with it, + * assuming the transformations result in valid PNG data. + */ +void /* PRIVATE */ +png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr) +{ + png_debug(1, "in png_read_transform_info"); + +#ifdef PNG_READ_EXPAND_SUPPORTED + if ((png_ptr->transformations & PNG_EXPAND) != 0) + { + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + /* This check must match what actually happens in + * png_do_expand_palette; if it ever checks the tRNS chunk to see if + * it is all opaque we must do the same (at present it does not.) + */ + if (png_ptr->num_trans > 0) + info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA; + + else + info_ptr->color_type = PNG_COLOR_TYPE_RGB; + + info_ptr->bit_depth = 8; + info_ptr->num_trans = 0; + + if (png_ptr->palette == NULL) + png_error (png_ptr, "Palette is NULL in indexed image"); + } + else + { + if (png_ptr->num_trans != 0) + { + if ((png_ptr->transformations & PNG_EXPAND_tRNS) != 0) + info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; + } + if (info_ptr->bit_depth < 8) + info_ptr->bit_depth = 8; + + info_ptr->num_trans = 0; + } + } +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + /* The following is almost certainly wrong unless the background value is in + * the screen space! + */ + if ((png_ptr->transformations & PNG_COMPOSE) != 0) + info_ptr->background = png_ptr->background; +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED + /* The following used to be conditional on PNG_GAMMA (prior to 1.5.4), + * however it seems that the code in png_init_read_transformations, which has + * been called before this from png_read_update_info->png_read_start_row + * sometimes does the gamma transform and cancels the flag. + * + * TODO: this looks wrong; the info_ptr should end up with a gamma equal to + * the screen_gamma value. The following probably results in weirdness if + * the info_ptr is used by the app after the rows have been read. + */ + info_ptr->colorspace.gamma = png_ptr->colorspace.gamma; +#endif + + if (info_ptr->bit_depth == 16) + { +# ifdef PNG_READ_16BIT_SUPPORTED +# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0) + info_ptr->bit_depth = 8; +# endif + +# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + if ((png_ptr->transformations & PNG_16_TO_8) != 0) + info_ptr->bit_depth = 8; +# endif + +# else + /* No 16-bit support: force chopping 16-bit input down to 8, in this case + * the app program can chose if both APIs are available by setting the + * correct scaling to use. + */ +# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + /* For compatibility with previous versions use the strip method by + * default. This code works because if PNG_SCALE_16_TO_8 is already + * set the code below will do that in preference to the chop. + */ + png_ptr->transformations |= PNG_16_TO_8; + info_ptr->bit_depth = 8; +# else + +# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + png_ptr->transformations |= PNG_SCALE_16_TO_8; + info_ptr->bit_depth = 8; +# else + + CONFIGURATION ERROR: you must enable at least one 16 to 8 method +# endif +# endif +#endif /* !READ_16BIT */ + } + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) + info_ptr->color_type = (png_byte)(info_ptr->color_type | + PNG_COLOR_MASK_COLOR); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) + info_ptr->color_type = (png_byte)(info_ptr->color_type & + ~PNG_COLOR_MASK_COLOR); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + if ((png_ptr->transformations & PNG_QUANTIZE) != 0) + { + if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || + (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) && + png_ptr->palette_lookup != 0 && info_ptr->bit_depth == 8) + { + info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; + } + } +#endif + +#ifdef PNG_READ_EXPAND_16_SUPPORTED + if ((png_ptr->transformations & PNG_EXPAND_16) != 0 && + info_ptr->bit_depth == 8 && + info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + { + info_ptr->bit_depth = 16; + } +#endif + +#ifdef PNG_READ_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) != 0 && + (info_ptr->bit_depth < 8)) + info_ptr->bit_depth = 8; +#endif + + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + info_ptr->channels = 1; + + else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + info_ptr->channels = 3; + + else + info_ptr->channels = 1; + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0) + { + info_ptr->color_type = (png_byte)(info_ptr->color_type & + ~PNG_COLOR_MASK_ALPHA); + info_ptr->num_trans = 0; + } +#endif + + if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) + info_ptr->channels++; + +#ifdef PNG_READ_FILLER_SUPPORTED + /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */ + if ((png_ptr->transformations & PNG_FILLER) != 0 && + (info_ptr->color_type == PNG_COLOR_TYPE_RGB || + info_ptr->color_type == PNG_COLOR_TYPE_GRAY)) + { + info_ptr->channels++; + /* If adding a true alpha channel not just filler */ + if ((png_ptr->transformations & PNG_ADD_ALPHA) != 0) + info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; + } +#endif + +#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \ +defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) + { + if (png_ptr->user_transform_depth != 0) + info_ptr->bit_depth = png_ptr->user_transform_depth; + + if (png_ptr->user_transform_channels != 0) + info_ptr->channels = png_ptr->user_transform_channels; + } +#endif + + info_ptr->pixel_depth = (png_byte)(info_ptr->channels * + info_ptr->bit_depth); + + info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width); + + /* Adding in 1.5.4: cache the above value in png_struct so that we can later + * check in png_rowbytes that the user buffer won't get overwritten. Note + * that the field is not always set - if png_read_update_info isn't called + * the application has to either not do any transforms or get the calculation + * right itself. + */ + png_ptr->info_rowbytes = info_ptr->rowbytes; + +#ifndef PNG_READ_EXPAND_SUPPORTED + if (png_ptr != NULL) + return; +#endif +} + +#ifdef PNG_READ_PACK_SUPPORTED +/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel, + * without changing the actual values. Thus, if you had a row with + * a bit depth of 1, you would end up with bytes that only contained + * the numbers 0 or 1. If you would rather they contain 0 and 255, use + * png_do_shift() after this. + */ +static void +png_do_unpack(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_unpack"); + + if (row_info->bit_depth < 8) + { + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + switch (row_info->bit_depth) + { + case 1: + { + png_bytep sp = row + (png_size_t)((row_width - 1) >> 3); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x01); + + if (shift == 7) + { + shift = 0; + sp--; + } + + else + shift++; + + dp--; + } + break; + } + + case 2: + { + + png_bytep sp = row + (png_size_t)((row_width - 1) >> 2); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x03); + + if (shift == 6) + { + shift = 0; + sp--; + } + + else + shift += 2; + + dp--; + } + break; + } + + case 4: + { + png_bytep sp = row + (png_size_t)((row_width - 1) >> 1); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x0f); + + if (shift == 4) + { + shift = 0; + sp--; + } + + else + shift = 4; + + dp--; + } + break; + } + + default: + break; + } + row_info->bit_depth = 8; + row_info->pixel_depth = (png_byte)(8 * row_info->channels); + row_info->rowbytes = row_width * row_info->channels; + } +} +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED +/* Reverse the effects of png_do_shift. This routine merely shifts the + * pixels back to their significant bits values. Thus, if you have + * a row of bit depth 8, but only 5 are significant, this will shift + * the values back to 0 through 31. + */ +static void +png_do_unshift(png_row_infop row_info, png_bytep row, + png_const_color_8p sig_bits) +{ + int color_type; + + png_debug(1, "in png_do_unshift"); + + /* The palette case has already been handled in the _init routine. */ + color_type = row_info->color_type; + + if (color_type != PNG_COLOR_TYPE_PALETTE) + { + int shift[4]; + int channels = 0; + int bit_depth = row_info->bit_depth; + + if ((color_type & PNG_COLOR_MASK_COLOR) != 0) + { + shift[channels++] = bit_depth - sig_bits->red; + shift[channels++] = bit_depth - sig_bits->green; + shift[channels++] = bit_depth - sig_bits->blue; + } + + else + { + shift[channels++] = bit_depth - sig_bits->gray; + } + + if ((color_type & PNG_COLOR_MASK_ALPHA) != 0) + { + shift[channels++] = bit_depth - sig_bits->alpha; + } + + { + int c, have_shift; + + for (c = have_shift = 0; c < channels; ++c) + { + /* A shift of more than the bit depth is an error condition but it + * gets ignored here. + */ + if (shift[c] <= 0 || shift[c] >= bit_depth) + shift[c] = 0; + + else + have_shift = 1; + } + + if (have_shift == 0) + return; + } + + switch (bit_depth) + { + default: + /* Must be 1bpp gray: should not be here! */ + /* NOTREACHED */ + break; + + case 2: + /* Must be 2bpp gray */ + /* assert(channels == 1 && shift[0] == 1) */ + { + png_bytep bp = row; + png_bytep bp_end = bp + row_info->rowbytes; + + while (bp < bp_end) + { + int b = (*bp >> 1) & 0x55; + *bp++ = (png_byte)b; + } + break; + } + + case 4: + /* Must be 4bpp gray */ + /* assert(channels == 1) */ + { + png_bytep bp = row; + png_bytep bp_end = bp + row_info->rowbytes; + int gray_shift = shift[0]; + int mask = 0xf >> gray_shift; + + mask |= mask << 4; + + while (bp < bp_end) + { + int b = (*bp >> gray_shift) & mask; + *bp++ = (png_byte)b; + } + break; + } + + case 8: + /* Single byte components, G, GA, RGB, RGBA */ + { + png_bytep bp = row; + png_bytep bp_end = bp + row_info->rowbytes; + int channel = 0; + + while (bp < bp_end) + { + int b = *bp >> shift[channel]; + if (++channel >= channels) + channel = 0; + *bp++ = (png_byte)b; + } + break; + } + +#ifdef PNG_READ_16BIT_SUPPORTED + case 16: + /* Double byte components, G, GA, RGB, RGBA */ + { + png_bytep bp = row; + png_bytep bp_end = bp + row_info->rowbytes; + int channel = 0; + + while (bp < bp_end) + { + int value = (bp[0] << 8) + bp[1]; + + value >>= shift[channel]; + if (++channel >= channels) + channel = 0; + *bp++ = (png_byte)(value >> 8); + *bp++ = (png_byte)value; + } + break; + } +#endif + } + } +} +#endif + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +/* Scale rows of bit depth 16 down to 8 accurately */ +static void +png_do_scale_16_to_8(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_scale_16_to_8"); + + if (row_info->bit_depth == 16) + { + png_bytep sp = row; /* source */ + png_bytep dp = row; /* destination */ + png_bytep ep = sp + row_info->rowbytes; /* end+1 */ + + while (sp < ep) + { + /* The input is an array of 16-bit components, these must be scaled to + * 8 bits each. For a 16-bit value V the required value (from the PNG + * specification) is: + * + * (V * 255) / 65535 + * + * This reduces to round(V / 257), or floor((V + 128.5)/257) + * + * Represent V as the two byte value vhi.vlo. Make a guess that the + * result is the top byte of V, vhi, then the correction to this value + * is: + * + * error = floor(((V-vhi.vhi) + 128.5) / 257) + * = floor(((vlo-vhi) + 128.5) / 257) + * + * This can be approximated using integer arithmetic (and a signed + * shift): + * + * error = (vlo-vhi+128) >> 8; + * + * The approximate differs from the exact answer only when (vlo-vhi) is + * 128; it then gives a correction of +1 when the exact correction is + * 0. This gives 128 errors. The exact answer (correct for all 16-bit + * input values) is: + * + * error = (vlo-vhi+128)*65535 >> 24; + * + * An alternative arithmetic calculation which also gives no errors is: + * + * (V * 255 + 32895) >> 16 + */ + + png_int_32 tmp = *sp++; /* must be signed! */ + tmp += (((int)*sp++ - tmp + 128) * 65535) >> 24; + *dp++ = (png_byte)tmp; + } + + row_info->bit_depth = 8; + row_info->pixel_depth = (png_byte)(8 * row_info->channels); + row_info->rowbytes = row_info->width * row_info->channels; + } +} +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +static void +/* Simply discard the low byte. This was the default behavior prior + * to libpng-1.5.4. + */ +png_do_chop(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_chop"); + + if (row_info->bit_depth == 16) + { + png_bytep sp = row; /* source */ + png_bytep dp = row; /* destination */ + png_bytep ep = sp + row_info->rowbytes; /* end+1 */ + + while (sp < ep) + { + *dp++ = *sp; + sp += 2; /* skip low byte */ + } + + row_info->bit_depth = 8; + row_info->pixel_depth = (png_byte)(8 * row_info->channels); + row_info->rowbytes = row_info->width * row_info->channels; + } +} +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED +static void +png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_read_swap_alpha"); + + { + png_uint_32 row_width = row_info->width; + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This converts from RGBA to ARGB */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save; + } + } + +#ifdef PNG_READ_16BIT_SUPPORTED + /* This converts from RRGGBBAA to AARRGGBB */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save[2]; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save[0] = *(--sp); + save[1] = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save[0]; + *(--dp) = save[1]; + } + } +#endif + } + + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This converts from GA to AG */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save; + } + } + +#ifdef PNG_READ_16BIT_SUPPORTED + /* This converts from GGAA to AAGG */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save[2]; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save[0] = *(--sp); + save[1] = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save[0]; + *(--dp) = save[1]; + } + } +#endif + } + } +} +#endif + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED +static void +png_do_read_invert_alpha(png_row_infop row_info, png_bytep row) +{ + png_uint_32 row_width; + png_debug(1, "in png_do_read_invert_alpha"); + + row_width = row_info->width; + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This inverts the alpha channel in RGBA */ + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + +/* This does nothing: + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + We can replace it with: +*/ + sp-=3; + dp=sp; + } + } + +#ifdef PNG_READ_16BIT_SUPPORTED + /* This inverts the alpha channel in RRGGBBAA */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = (png_byte)(255 - *(--sp)); + +/* This does nothing: + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + We can replace it with: +*/ + sp-=6; + dp=sp; + } + } +#endif + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This inverts the alpha channel in GA */ + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = *(--sp); + } + } + +#ifdef PNG_READ_16BIT_SUPPORTED + else + { + /* This inverts the alpha channel in GGAA */ + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = (png_byte)(255 - *(--sp)); +/* + *(--dp) = *(--sp); + *(--dp) = *(--sp); +*/ + sp-=2; + dp=sp; + } + } +#endif + } +} +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED +/* Add filler channel if we have RGB color */ +static void +png_do_read_filler(png_row_infop row_info, png_bytep row, + png_uint_32 filler, png_uint_32 flags) +{ + png_uint_32 i; + png_uint_32 row_width = row_info->width; + +#ifdef PNG_READ_16BIT_SUPPORTED + png_byte hi_filler = (png_byte)(filler>>8); +#endif + png_byte lo_filler = (png_byte)filler; + + png_debug(1, "in png_do_read_filler"); + + if ( + row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + if (row_info->bit_depth == 8) + { + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) + { + /* This changes the data from G to GX */ + png_bytep sp = row + (png_size_t)row_width; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 1; i < row_width; i++) + { + *(--dp) = lo_filler; + *(--dp) = *(--sp); + } + *(--dp) = lo_filler; + row_info->channels = 2; + row_info->pixel_depth = 16; + row_info->rowbytes = row_width * 2; + } + + else + { + /* This changes the data from G to XG */ + png_bytep sp = row + (png_size_t)row_width; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = lo_filler; + } + row_info->channels = 2; + row_info->pixel_depth = 16; + row_info->rowbytes = row_width * 2; + } + } + +#ifdef PNG_READ_16BIT_SUPPORTED + else if (row_info->bit_depth == 16) + { + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) + { + /* This changes the data from GG to GGXX */ + png_bytep sp = row + (png_size_t)row_width * 2; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 1; i < row_width; i++) + { + *(--dp) = lo_filler; + *(--dp) = hi_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = lo_filler; + *(--dp) = hi_filler; + row_info->channels = 2; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + + else + { + /* This changes the data from GG to XXGG */ + png_bytep sp = row + (png_size_t)row_width * 2; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = lo_filler; + *(--dp) = hi_filler; + } + row_info->channels = 2; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + } +#endif + } /* COLOR_TYPE == GRAY */ + else if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + if (row_info->bit_depth == 8) + { + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) + { + /* This changes the data from RGB to RGBX */ + png_bytep sp = row + (png_size_t)row_width * 3; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 1; i < row_width; i++) + { + *(--dp) = lo_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = lo_filler; + row_info->channels = 4; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + + else + { + /* This changes the data from RGB to XRGB */ + png_bytep sp = row + (png_size_t)row_width * 3; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = lo_filler; + } + row_info->channels = 4; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + } + +#ifdef PNG_READ_16BIT_SUPPORTED + else if (row_info->bit_depth == 16) + { + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) + { + /* This changes the data from RRGGBB to RRGGBBXX */ + png_bytep sp = row + (png_size_t)row_width * 6; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 1; i < row_width; i++) + { + *(--dp) = lo_filler; + *(--dp) = hi_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = lo_filler; + *(--dp) = hi_filler; + row_info->channels = 4; + row_info->pixel_depth = 64; + row_info->rowbytes = row_width * 8; + } + + else + { + /* This changes the data from RRGGBB to XXRRGGBB */ + png_bytep sp = row + (png_size_t)row_width * 6; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = lo_filler; + *(--dp) = hi_filler; + } + + row_info->channels = 4; + row_info->pixel_depth = 64; + row_info->rowbytes = row_width * 8; + } + } +#endif + } /* COLOR_TYPE == RGB */ +} +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +/* Expand grayscale files to RGB, with or without alpha */ +static void +png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) +{ + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + png_debug(1, "in png_do_gray_to_rgb"); + + if (row_info->bit_depth >= 8 && + (row_info->color_type & PNG_COLOR_MASK_COLOR) == 0) + { + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + if (row_info->bit_depth == 8) + { + /* This changes G to RGB */ + png_bytep sp = row + (png_size_t)row_width - 1; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(dp--) = *sp; + *(dp--) = *sp; + *(dp--) = *(sp--); + } + } + + else + { + /* This changes GG to RRGGBB */ + png_bytep sp = row + (png_size_t)row_width * 2 - 1; + png_bytep dp = sp + (png_size_t)row_width * 4; + for (i = 0; i < row_width; i++) + { + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *(sp--); + *(dp--) = *(sp--); + } + } + } + + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This changes GA to RGBA */ + png_bytep sp = row + (png_size_t)row_width * 2 - 1; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(dp--) = *(sp--); + *(dp--) = *sp; + *(dp--) = *sp; + *(dp--) = *(sp--); + } + } + + else + { + /* This changes GGAA to RRGGBBAA */ + png_bytep sp = row + (png_size_t)row_width * 4 - 1; + png_bytep dp = sp + (png_size_t)row_width * 4; + for (i = 0; i < row_width; i++) + { + *(dp--) = *(sp--); + *(dp--) = *(sp--); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *(sp--); + *(dp--) = *(sp--); + } + } + } + row_info->channels = (png_byte)(row_info->channels + 2); + row_info->color_type |= PNG_COLOR_MASK_COLOR; + row_info->pixel_depth = (png_byte)(row_info->channels * + row_info->bit_depth); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } +} +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +/* Reduce RGB files to grayscale, with or without alpha + * using the equation given in Poynton's ColorFAQ of 1998-01-04 at + * (THIS LINK IS DEAD June 2008 but + * versions dated 1998 through November 2002 have been archived at + * http://web.archive.org/web/20000816232553/http://www.inforamp.net/ + * ~poynton/notes/colour_and_gamma/ColorFAQ.txt ) + * Charles Poynton poynton at poynton.com + * + * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B + * + * which can be expressed with integers as + * + * Y = (6969 * R + 23434 * G + 2365 * B)/32768 + * + * Poynton's current link (as of January 2003 through July 2011): + * + * has changed the numbers slightly: + * + * Y = 0.2126*R + 0.7152*G + 0.0722*B + * + * which can be expressed with integers as + * + * Y = (6966 * R + 23436 * G + 2366 * B)/32768 + * + * Historically, however, libpng uses numbers derived from the ITU-R Rec 709 + * end point chromaticities and the D65 white point. Depending on the + * precision used for the D65 white point this produces a variety of different + * numbers, however if the four decimal place value used in ITU-R Rec 709 is + * used (0.3127,0.3290) the Y calculation would be: + * + * Y = (6968 * R + 23435 * G + 2366 * B)/32768 + * + * While this is correct the rounding results in an overflow for white, because + * the sum of the rounded coefficients is 32769, not 32768. Consequently + * libpng uses, instead, the closest non-overflowing approximation: + * + * Y = (6968 * R + 23434 * G + 2366 * B)/32768 + * + * Starting with libpng-1.5.5, if the image being converted has a cHRM chunk + * (including an sRGB chunk) then the chromaticities are used to calculate the + * coefficients. See the chunk handling in pngrutil.c for more information. + * + * In all cases the calculation is to be done in a linear colorspace. If no + * gamma information is available to correct the encoding of the original RGB + * values this results in an implicit assumption that the original PNG RGB + * values were linear. + * + * Other integer coefficents can be used via png_set_rgb_to_gray(). Because + * the API takes just red and green coefficients the blue coefficient is + * calculated to make the sum 32768. This will result in different rounding + * to that used above. + */ +static int +png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row) + +{ + int rgb_error = 0; + + png_debug(1, "in png_do_rgb_to_gray"); + + if ((row_info->color_type & PNG_COLOR_MASK_PALETTE) == 0 && + (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + PNG_CONST png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff; + PNG_CONST png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff; + PNG_CONST png_uint_32 bc = 32768 - rc - gc; + PNG_CONST png_uint_32 row_width = row_info->width; + PNG_CONST int have_alpha = + (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0; + + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + /* Notice that gamma to/from 1 are not necessarily inverses (if + * there is an overall gamma correction). Prior to 1.5.5 this code + * checked the linearized values for equality; this doesn't match + * the documentation, the original values must be checked. + */ + if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + png_byte red = *(sp++); + png_byte green = *(sp++); + png_byte blue = *(sp++); + + if (red != green || red != blue) + { + red = png_ptr->gamma_to_1[red]; + green = png_ptr->gamma_to_1[green]; + blue = png_ptr->gamma_to_1[blue]; + + rgb_error |= 1; + *(dp++) = png_ptr->gamma_from_1[ + (rc*red + gc*green + bc*blue + 16384)>>15]; + } + + else + { + /* If there is no overall correction the table will not be + * set. + */ + if (png_ptr->gamma_table != NULL) + red = png_ptr->gamma_table[red]; + + *(dp++) = red; + } + + if (have_alpha != 0) + *(dp++) = *(sp++); + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + png_byte red = *(sp++); + png_byte green = *(sp++); + png_byte blue = *(sp++); + + if (red != green || red != blue) + { + rgb_error |= 1; + /* NOTE: this is the historical approach which simply + * truncates the results. + */ + *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); + } + + else + *(dp++) = red; + + if (have_alpha != 0) + *(dp++) = *(sp++); + } + } + } + + else /* RGB bit_depth == 16 */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (png_ptr->gamma_16_to_1 != NULL && png_ptr->gamma_16_from_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, w; + png_byte hi,lo; + + hi=*(sp)++; lo=*(sp)++; red = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; blue = (png_uint_16)((hi << 8) | (lo)); + + if (red == green && red == blue) + { + if (png_ptr->gamma_16_table != NULL) + w = png_ptr->gamma_16_table[(red & 0xff) + >> png_ptr->gamma_shift][red >> 8]; + + else + w = red; + } + + else + { + png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red & 0xff) + >> png_ptr->gamma_shift][red>>8]; + png_uint_16 green_1 = + png_ptr->gamma_16_to_1[(green & 0xff) >> + png_ptr->gamma_shift][green>>8]; + png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue & 0xff) + >> png_ptr->gamma_shift][blue>>8]; + png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1 + + bc*blue_1 + 16384)>>15); + w = png_ptr->gamma_16_from_1[(gray16 & 0xff) >> + png_ptr->gamma_shift][gray16 >> 8]; + rgb_error |= 1; + } + + *(dp++) = (png_byte)((w>>8) & 0xff); + *(dp++) = (png_byte)(w & 0xff); + + if (have_alpha != 0) + { + *(dp++) = *(sp++); + *(dp++) = *(sp++); + } + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, gray16; + png_byte hi,lo; + + hi=*(sp)++; lo=*(sp)++; red = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; blue = (png_uint_16)((hi << 8) | (lo)); + + if (red != green || red != blue) + rgb_error |= 1; + + /* From 1.5.5 in the 16-bit case do the accurate conversion even + * in the 'fast' case - this is because this is where the code + * ends up when handling linear 16-bit data. + */ + gray16 = (png_uint_16)((rc*red + gc*green + bc*blue + 16384) >> + 15); + *(dp++) = (png_byte)((gray16 >> 8) & 0xff); + *(dp++) = (png_byte)(gray16 & 0xff); + + if (have_alpha != 0) + { + *(dp++) = *(sp++); + *(dp++) = *(sp++); + } + } + } + } + + row_info->channels = (png_byte)(row_info->channels - 2); + row_info->color_type = (png_byte)(row_info->color_type & + ~PNG_COLOR_MASK_COLOR); + row_info->pixel_depth = (png_byte)(row_info->channels * + row_info->bit_depth); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + return rgb_error; +} +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) +/* Replace any alpha or transparency with the supplied background color. + * "background" is already in the screen gamma, while "background_1" is + * at a gamma of 1.0. Paletted files have already been taken care of. + */ +static void +png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr) +{ +#ifdef PNG_READ_GAMMA_SUPPORTED + png_const_bytep gamma_table = png_ptr->gamma_table; + png_const_bytep gamma_from_1 = png_ptr->gamma_from_1; + png_const_bytep gamma_to_1 = png_ptr->gamma_to_1; + png_const_uint_16pp gamma_16 = png_ptr->gamma_16_table; + png_const_uint_16pp gamma_16_from_1 = png_ptr->gamma_16_from_1; + png_const_uint_16pp gamma_16_to_1 = png_ptr->gamma_16_to_1; + int gamma_shift = png_ptr->gamma_shift; + int optimize = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0; +#endif + + png_bytep sp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + int shift; + + png_debug(1, "in png_do_compose"); + + { + switch (row_info->color_type) + { + case PNG_COLOR_TYPE_GRAY: + { + switch (row_info->bit_depth) + { + case 1: + { + sp = row; + shift = 7; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x01) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0x7f7f >> (7 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); + } + + if (shift == 0) + { + shift = 7; + sp++; + } + + else + shift--; + } + break; + } + + case 2: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + shift = 6; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x03) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); + } + + else + { + unsigned int p = (*sp >> shift) & 0x03; + unsigned int g = (gamma_table [p | (p << 2) | + (p << 4) | (p << 6)] >> 6) & 0x03; + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= g << shift; + *sp = (png_byte)(tmp & 0xff); + } + + if (shift == 0) + { + shift = 6; + sp++; + } + + else + shift -= 2; + } + } + + else +#endif + { + sp = row; + shift = 6; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x03) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); + } + + if (shift == 0) + { + shift = 6; + sp++; + } + + else + shift -= 2; + } + } + break; + } + + case 4: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + shift = 4; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x0f) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0x0f0f >> (4 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); + } + + else + { + unsigned int p = (*sp >> shift) & 0x0f; + unsigned int g = (gamma_table[p | (p << 4)] >> 4) & + 0x0f; + unsigned int tmp = *sp & (0x0f0f >> (4 - shift)); + tmp |= g << shift; + *sp = (png_byte)(tmp & 0xff); + } + + if (shift == 0) + { + shift = 4; + sp++; + } + + else + shift -= 4; + } + } + + else +#endif + { + sp = row; + shift = 4; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x0f) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0x0f0f >> (4 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); + } + + if (shift == 0) + { + shift = 4; + sp++; + } + + else + shift -= 4; + } + } + break; + } + + case 8: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + if (*sp == png_ptr->trans_color.gray) + *sp = (png_byte)png_ptr->background.gray; + + else + *sp = gamma_table[*sp]; + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + if (*sp == png_ptr->trans_color.gray) + *sp = (png_byte)png_ptr->background.gray; + } + } + break; + } + + case 16: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 v; + + v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + + if (v == png_ptr->trans_color.gray) + { + /* Background is already in screen gamma */ + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray + & 0xff); + } + + else + { + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 v; + + v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + + if (v == png_ptr->trans_color.gray) + { + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray + & 0xff); + } + } + } + break; + } + + default: + break; + } + break; + } + + case PNG_COLOR_TYPE_RGB: + { + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 3) + { + if (*sp == png_ptr->trans_color.red && + *(sp + 1) == png_ptr->trans_color.green && + *(sp + 2) == png_ptr->trans_color.blue) + { + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; + } + + else + { + *sp = gamma_table[*sp]; + *(sp + 1) = gamma_table[*(sp + 1)]; + *(sp + 2) = gamma_table[*(sp + 2)]; + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 3) + { + if (*sp == png_ptr->trans_color.red && + *(sp + 1) == png_ptr->trans_color.green && + *(sp + 2) == png_ptr->trans_color.blue) + { + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; + } + } + } + } + else /* if (row_info->bit_depth == 16) */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 6) + { + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + + png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + + png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + + *(sp + 5)); + + if (r == png_ptr->trans_color.red && + g == png_ptr->trans_color.green && + b == png_ptr->trans_color.blue) + { + /* Background is already in screen gamma */ + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); + } + + else + { + png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + + v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 3) = (png_byte)(v & 0xff); + + v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 5) = (png_byte)(v & 0xff); + } + } + } + + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 6) + { + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + + png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + + png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + + *(sp + 5)); + + if (r == png_ptr->trans_color.red && + g == png_ptr->trans_color.green && + b == png_ptr->trans_color.blue) + { + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); + } + } + } + } + break; + } + + case PNG_COLOR_TYPE_GRAY_ALPHA: + { + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_to_1 != NULL && gamma_from_1 != NULL && + gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 a = *(sp + 1); + + if (a == 0xff) + *sp = gamma_table[*sp]; + + else if (a == 0) + { + /* Background is already in screen gamma */ + *sp = (png_byte)png_ptr->background.gray; + } + + else + { + png_byte v, w; + + v = gamma_to_1[*sp]; + png_composite(w, v, a, png_ptr->background_1.gray); + if (optimize == 0) + w = gamma_from_1[w]; + *sp = w; + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_byte a = *(sp + 1); + + if (a == 0) + *sp = (png_byte)png_ptr->background.gray; + + else if (a < 0xff) + png_composite(*sp, *sp, a, png_ptr->background.gray); + } + } + } + else /* if (png_ptr->bit_depth == 16) */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL && gamma_16_from_1 != NULL && + gamma_16_to_1 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 4) + { + png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + + if (a == (png_uint_16)0xffff) + { + png_uint_16 v; + + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + } + + else if (a == 0) + { + /* Background is already in screen gamma */ + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); + } + + else + { + png_uint_16 g, v, w; + + g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; + png_composite_16(v, g, a, png_ptr->background_1.gray); + if (optimize != 0) + w = v; + else + w = gamma_16_from_1[(v & 0xff) >> + gamma_shift][v >> 8]; + *sp = (png_byte)((w >> 8) & 0xff); + *(sp + 1) = (png_byte)(w & 0xff); + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 4) + { + png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + + if (a == 0) + { + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); + } + + else if (a < 0xffff) + { + png_uint_16 g, v; + + g = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_composite_16(v, g, a, png_ptr->background.gray); + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + } + } + } + } + break; + } + + case PNG_COLOR_TYPE_RGB_ALPHA: + { + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_to_1 != NULL && gamma_from_1 != NULL && + gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 4) + { + png_byte a = *(sp + 3); + + if (a == 0xff) + { + *sp = gamma_table[*sp]; + *(sp + 1) = gamma_table[*(sp + 1)]; + *(sp + 2) = gamma_table[*(sp + 2)]; + } + + else if (a == 0) + { + /* Background is already in screen gamma */ + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; + } + + else + { + png_byte v, w; + + v = gamma_to_1[*sp]; + png_composite(w, v, a, png_ptr->background_1.red); + if (optimize == 0) w = gamma_from_1[w]; + *sp = w; + + v = gamma_to_1[*(sp + 1)]; + png_composite(w, v, a, png_ptr->background_1.green); + if (optimize == 0) w = gamma_from_1[w]; + *(sp + 1) = w; + + v = gamma_to_1[*(sp + 2)]; + png_composite(w, v, a, png_ptr->background_1.blue); + if (optimize == 0) w = gamma_from_1[w]; + *(sp + 2) = w; + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 4) + { + png_byte a = *(sp + 3); + + if (a == 0) + { + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; + } + + else if (a < 0xff) + { + png_composite(*sp, *sp, a, png_ptr->background.red); + + png_composite(*(sp + 1), *(sp + 1), a, + png_ptr->background.green); + + png_composite(*(sp + 2), *(sp + 2), a, + png_ptr->background.blue); + } + } + } + } + else /* if (row_info->bit_depth == 16) */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL && gamma_16_from_1 != NULL && + gamma_16_to_1 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 8) + { + png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) + << 8) + (png_uint_16)(*(sp + 7))); + + if (a == (png_uint_16)0xffff) + { + png_uint_16 v; + + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + + v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 3) = (png_byte)(v & 0xff); + + v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 5) = (png_byte)(v & 0xff); + } + + else if (a == 0) + { + /* Background is already in screen gamma */ + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); + } + + else + { + png_uint_16 v, w; + + v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; + png_composite_16(w, v, a, png_ptr->background_1.red); + if (optimize == 0) + w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> + 8]; + *sp = (png_byte)((w >> 8) & 0xff); + *(sp + 1) = (png_byte)(w & 0xff); + + v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)]; + png_composite_16(w, v, a, png_ptr->background_1.green); + if (optimize == 0) + w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> + 8]; + + *(sp + 2) = (png_byte)((w >> 8) & 0xff); + *(sp + 3) = (png_byte)(w & 0xff); + + v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)]; + png_composite_16(w, v, a, png_ptr->background_1.blue); + if (optimize == 0) + w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> + 8]; + + *(sp + 4) = (png_byte)((w >> 8) & 0xff); + *(sp + 5) = (png_byte)(w & 0xff); + } + } + } + + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 8) + { + png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) + << 8) + (png_uint_16)(*(sp + 7))); + + if (a == 0) + { + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); + } + + else if (a < 0xffff) + { + png_uint_16 v; + + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + + *(sp + 5)); + + png_composite_16(v, r, a, png_ptr->background.red); + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + + png_composite_16(v, g, a, png_ptr->background.green); + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 3) = (png_byte)(v & 0xff); + + png_composite_16(v, b, a, png_ptr->background.blue); + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 5) = (png_byte)(v & 0xff); + } + } + } + } + break; + } + + default: + break; + } + } +} +#endif /* READ_BACKGROUND || READ_ALPHA_MODE */ + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* Gamma correct the image, avoiding the alpha channel. Make sure + * you do this after you deal with the transparency issue on grayscale + * or RGB images. If your bit depth is 8, use gamma_table, if it + * is 16, use gamma_16_table and gamma_shift. Build these with + * build_gamma_table(). + */ +static void +png_do_gamma(png_row_infop row_info, png_bytep row, png_structrp png_ptr) +{ + png_const_bytep gamma_table = png_ptr->gamma_table; + png_const_uint_16pp gamma_16_table = png_ptr->gamma_16_table; + int gamma_shift = png_ptr->gamma_shift; + + png_bytep sp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_gamma"); + + if (((row_info->bit_depth <= 8 && gamma_table != NULL) || + (row_info->bit_depth == 16 && gamma_16_table != NULL))) + { + switch (row_info->color_type) + { + case PNG_COLOR_TYPE_RGB: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + } + } + + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v; + + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + } + } + break; + } + + case PNG_COLOR_TYPE_RGB_ALPHA: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + + *sp = gamma_table[*sp]; + sp++; + + *sp = gamma_table[*sp]; + sp++; + + sp++; + } + } + + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 4; + } + } + break; + } + + case PNG_COLOR_TYPE_GRAY_ALPHA: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp += 2; + } + } + + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 4; + } + } + break; + } + + case PNG_COLOR_TYPE_GRAY: + { + if (row_info->bit_depth == 2) + { + sp = row; + for (i = 0; i < row_width; i += 4) + { + int a = *sp & 0xc0; + int b = *sp & 0x30; + int c = *sp & 0x0c; + int d = *sp & 0x03; + + *sp = (png_byte)( + ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)| + ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)| + ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)| + ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) )); + sp++; + } + } + + if (row_info->bit_depth == 4) + { + sp = row; + for (i = 0; i < row_width; i += 2) + { + int msb = *sp & 0xf0; + int lsb = *sp & 0x0f; + + *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0) + | (((int)gamma_table[(lsb << 4) | lsb]) >> 4)); + sp++; + } + } + + else if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + } + } + + else if (row_info->bit_depth == 16) + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + } + } + break; + } + + default: + break; + } + } +} +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +/* Encode the alpha channel to the output gamma (the input channel is always + * linear.) Called only with color types that have an alpha channel. Needs the + * from_1 tables. + */ +static void +png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structrp png_ptr) +{ + png_uint_32 row_width = row_info->width; + + png_debug(1, "in png_do_encode_alpha"); + + if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) + { + if (row_info->bit_depth == 8) + { + PNG_CONST png_bytep table = png_ptr->gamma_from_1; + + if (table != NULL) + { + PNG_CONST int step = + (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 4 : 2; + + /* The alpha channel is the last component: */ + row += step - 1; + + for (; row_width > 0; --row_width, row += step) + *row = table[*row]; + + return; + } + } + + else if (row_info->bit_depth == 16) + { + PNG_CONST png_uint_16pp table = png_ptr->gamma_16_from_1; + PNG_CONST int gamma_shift = png_ptr->gamma_shift; + + if (table != NULL) + { + PNG_CONST int step = + (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 8 : 4; + + /* The alpha channel is the last component: */ + row += step - 2; + + for (; row_width > 0; --row_width, row += step) + { + png_uint_16 v; + + v = table[*(row + 1) >> gamma_shift][*row]; + *row = (png_byte)((v >> 8) & 0xff); + *(row + 1) = (png_byte)(v & 0xff); + } + + return; + } + } + } + + /* Only get to here if called with a weird row_info; no harm has been done, + * so just issue a warning. + */ + png_warning(png_ptr, "png_do_encode_alpha: unexpected call"); +} +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* Expands a palette row to an RGB or RGBA row depending + * upon whether you supply trans and num_trans. + */ +static void +png_do_expand_palette(png_row_infop row_info, png_bytep row, + png_const_colorp palette, png_const_bytep trans_alpha, int num_trans) +{ + int shift, value; + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_expand_palette"); + + if (row_info->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (row_info->bit_depth < 8) + { + switch (row_info->bit_depth) + { + case 1: + { + sp = row + (png_size_t)((row_width - 1) >> 3); + dp = row + (png_size_t)row_width - 1; + shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + if ((*sp >> shift) & 0x01) + *dp = 1; + + else + *dp = 0; + + if (shift == 7) + { + shift = 0; + sp--; + } + + else + shift++; + + dp--; + } + break; + } + + case 2: + { + sp = row + (png_size_t)((row_width - 1) >> 2); + dp = row + (png_size_t)row_width - 1; + shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x03; + *dp = (png_byte)value; + if (shift == 6) + { + shift = 0; + sp--; + } + + else + shift += 2; + + dp--; + } + break; + } + + case 4: + { + sp = row + (png_size_t)((row_width - 1) >> 1); + dp = row + (png_size_t)row_width - 1; + shift = (int)((row_width & 0x01) << 2); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x0f; + *dp = (png_byte)value; + if (shift == 4) + { + shift = 0; + sp--; + } + + else + shift += 4; + + dp--; + } + break; + } + + default: + break; + } + row_info->bit_depth = 8; + row_info->pixel_depth = 8; + row_info->rowbytes = row_width; + } + + if (row_info->bit_depth == 8) + { + { + if (num_trans > 0) + { + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width << 2) - 1; + + for (i = 0; i < row_width; i++) + { + if ((int)(*sp) >= num_trans) + *dp-- = 0xff; + + else + *dp-- = trans_alpha[*sp]; + + *dp-- = palette[*sp].blue; + *dp-- = palette[*sp].green; + *dp-- = palette[*sp].red; + sp--; + } + row_info->bit_depth = 8; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + row_info->color_type = 6; + row_info->channels = 4; + } + + else + { + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width * 3) - 1; + + for (i = 0; i < row_width; i++) + { + *dp-- = palette[*sp].blue; + *dp-- = palette[*sp].green; + *dp-- = palette[*sp].red; + sp--; + } + + row_info->bit_depth = 8; + row_info->pixel_depth = 24; + row_info->rowbytes = row_width * 3; + row_info->color_type = 2; + row_info->channels = 3; + } + } + } + } +} + +/* If the bit depth < 8, it is expanded to 8. Also, if the already + * expanded transparency value is supplied, an alpha channel is built. + */ +static void +png_do_expand(png_row_infop row_info, png_bytep row, + png_const_color_16p trans_color) +{ + int shift, value; + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_expand"); + + { + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + unsigned int gray = trans_color != NULL ? trans_color->gray : 0; + + if (row_info->bit_depth < 8) + { + switch (row_info->bit_depth) + { + case 1: + { + gray = (gray & 0x01) * 0xff; + sp = row + (png_size_t)((row_width - 1) >> 3); + dp = row + (png_size_t)row_width - 1; + shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + if ((*sp >> shift) & 0x01) + *dp = 0xff; + + else + *dp = 0; + + if (shift == 7) + { + shift = 0; + sp--; + } + + else + shift++; + + dp--; + } + break; + } + + case 2: + { + gray = (gray & 0x03) * 0x55; + sp = row + (png_size_t)((row_width - 1) >> 2); + dp = row + (png_size_t)row_width - 1; + shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x03; + *dp = (png_byte)(value | (value << 2) | (value << 4) | + (value << 6)); + if (shift == 6) + { + shift = 0; + sp--; + } + + else + shift += 2; + + dp--; + } + break; + } + + case 4: + { + gray = (gray & 0x0f) * 0x11; + sp = row + (png_size_t)((row_width - 1) >> 1); + dp = row + (png_size_t)row_width - 1; + shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x0f; + *dp = (png_byte)(value | (value << 4)); + if (shift == 4) + { + shift = 0; + sp--; + } + + else + shift = 4; + + dp--; + } + break; + } + + default: + break; + } + + row_info->bit_depth = 8; + row_info->pixel_depth = 8; + row_info->rowbytes = row_width; + } + + if (trans_color != NULL) + { + if (row_info->bit_depth == 8) + { + gray = gray & 0xff; + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width << 1) - 1; + + for (i = 0; i < row_width; i++) + { + if ((*sp & 0xffU) == gray) + *dp-- = 0; + + else + *dp-- = 0xff; + + *dp-- = *sp--; + } + } + + else if (row_info->bit_depth == 16) + { + unsigned int gray_high = (gray >> 8) & 0xff; + unsigned int gray_low = gray & 0xff; + sp = row + row_info->rowbytes - 1; + dp = row + (row_info->rowbytes << 1) - 1; + for (i = 0; i < row_width; i++) + { + if ((*(sp - 1) & 0xffU) == gray_high && + (*(sp) & 0xffU) == gray_low) + { + *dp-- = 0; + *dp-- = 0; + } + + else + { + *dp-- = 0xff; + *dp-- = 0xff; + } + + *dp-- = *sp--; + *dp-- = *sp--; + } + } + + row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA; + row_info->channels = 2; + row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_width); + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB && + trans_color != NULL) + { + if (row_info->bit_depth == 8) + { + png_byte red = (png_byte)(trans_color->red & 0xff); + png_byte green = (png_byte)(trans_color->green & 0xff); + png_byte blue = (png_byte)(trans_color->blue & 0xff); + sp = row + (png_size_t)row_info->rowbytes - 1; + dp = row + (png_size_t)(row_width << 2) - 1; + for (i = 0; i < row_width; i++) + { + if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue) + *dp-- = 0; + + else + *dp-- = 0xff; + + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + } + } + else if (row_info->bit_depth == 16) + { + png_byte red_high = (png_byte)((trans_color->red >> 8) & 0xff); + png_byte green_high = (png_byte)((trans_color->green >> 8) & 0xff); + png_byte blue_high = (png_byte)((trans_color->blue >> 8) & 0xff); + png_byte red_low = (png_byte)(trans_color->red & 0xff); + png_byte green_low = (png_byte)(trans_color->green & 0xff); + png_byte blue_low = (png_byte)(trans_color->blue & 0xff); + sp = row + row_info->rowbytes - 1; + dp = row + (png_size_t)(row_width << 3) - 1; + for (i = 0; i < row_width; i++) + { + if (*(sp - 5) == red_high && + *(sp - 4) == red_low && + *(sp - 3) == green_high && + *(sp - 2) == green_low && + *(sp - 1) == blue_high && + *(sp ) == blue_low) + { + *dp-- = 0; + *dp-- = 0; + } + + else + { + *dp-- = 0xff; + *dp-- = 0xff; + } + + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + } + } + row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA; + row_info->channels = 4; + row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + } +} +#endif + +#ifdef PNG_READ_EXPAND_16_SUPPORTED +/* If the bit depth is 8 and the color type is not a palette type expand the + * whole row to 16 bits. Has no effect otherwise. + */ +static void +png_do_expand_16(png_row_infop row_info, png_bytep row) +{ + if (row_info->bit_depth == 8 && + row_info->color_type != PNG_COLOR_TYPE_PALETTE) + { + /* The row have a sequence of bytes containing [0..255] and we need + * to turn it into another row containing [0..65535], to do this we + * calculate: + * + * (input / 255) * 65535 + * + * Which happens to be exactly input * 257 and this can be achieved + * simply by byte replication in place (copying backwards). + */ + png_byte *sp = row + row_info->rowbytes; /* source, last byte + 1 */ + png_byte *dp = sp + row_info->rowbytes; /* destination, end + 1 */ + while (dp > sp) + dp[-2] = dp[-1] = *--sp, dp -= 2; + + row_info->rowbytes *= 2; + row_info->bit_depth = 16; + row_info->pixel_depth = (png_byte)(row_info->channels * 16); + } +} +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +static void +png_do_quantize(png_row_infop row_info, png_bytep row, + png_const_bytep palette_lookup, png_const_bytep quantize_lookup) +{ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_quantize"); + + if (row_info->bit_depth == 8) + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB && palette_lookup) + { + int r, g, b, p; + sp = row; + dp = row; + for (i = 0; i < row_width; i++) + { + r = *sp++; + g = *sp++; + b = *sp++; + + /* This looks real messy, but the compiler will reduce + * it down to a reasonable formula. For example, with + * 5 bits per color, we get: + * p = (((r >> 3) & 0x1f) << 10) | + * (((g >> 3) & 0x1f) << 5) | + * ((b >> 3) & 0x1f); + */ + p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) & + ((1 << PNG_QUANTIZE_RED_BITS) - 1)) << + (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) | + (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) & + ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) << + (PNG_QUANTIZE_BLUE_BITS)) | + ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) & + ((1 << PNG_QUANTIZE_BLUE_BITS) - 1)); + + *dp++ = palette_lookup[p]; + } + + row_info->color_type = PNG_COLOR_TYPE_PALETTE; + row_info->channels = 1; + row_info->pixel_depth = row_info->bit_depth; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA && + palette_lookup != NULL) + { + int r, g, b, p; + sp = row; + dp = row; + for (i = 0; i < row_width; i++) + { + r = *sp++; + g = *sp++; + b = *sp++; + sp++; + + p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) & + ((1 << PNG_QUANTIZE_RED_BITS) - 1)) << + (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) | + (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) & + ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) << + (PNG_QUANTIZE_BLUE_BITS)) | + ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) & + ((1 << PNG_QUANTIZE_BLUE_BITS) - 1)); + + *dp++ = palette_lookup[p]; + } + + row_info->color_type = PNG_COLOR_TYPE_PALETTE; + row_info->channels = 1; + row_info->pixel_depth = row_info->bit_depth; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); + } + + else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && + quantize_lookup) + { + sp = row; + + for (i = 0; i < row_width; i++, sp++) + { + *sp = quantize_lookup[*sp]; + } + } + } +} +#endif /* READ_QUANTIZE */ + +/* Transform the row. The order of transformations is significant, + * and is very touchy. If you add a transformation, take care to + * decide how it fits in with the other transformations here. + */ +void /* PRIVATE */ +png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info) +{ + png_debug(1, "in png_do_read_transformations"); + + if (png_ptr->row_buf == NULL) + { + /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this + * error is incredibly rare and incredibly easy to debug without this + * information. + */ + png_error(png_ptr, "NULL row buffer"); + } + + /* The following is debugging; prior to 1.5.4 the code was never compiled in; + * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro + * PNG_WARN_UNINITIALIZED_ROW removed. In 1.6 the new flag is set only for + * all transformations, however in practice the ROW_INIT always gets done on + * demand, if necessary. + */ + if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 && + (png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + { + /* Application has failed to call either png_read_start_image() or + * png_read_update_info() after setting transforms that expand pixels. + * This check added to libpng-1.2.19 (but not enabled until 1.5.4). + */ + png_error(png_ptr, "Uninitialized row"); + } + +#ifdef PNG_READ_EXPAND_SUPPORTED + if ((png_ptr->transformations & PNG_EXPAND) != 0) + { + if (row_info->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_do_expand_palette(row_info, png_ptr->row_buf + 1, + png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans); + } + + else + { + if (png_ptr->num_trans != 0 && + (png_ptr->transformations & PNG_EXPAND_tRNS) != 0) + png_do_expand(row_info, png_ptr->row_buf + 1, + &(png_ptr->trans_color)); + + else + png_do_expand(row_info, png_ptr->row_buf + 1, + NULL); + } + } +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && + (png_ptr->transformations & PNG_COMPOSE) == 0 && + (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + 0 /* at_start == false, because SWAP_ALPHA happens later */); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) + { + int rgb_error = + png_do_rgb_to_gray(png_ptr, row_info, + png_ptr->row_buf + 1); + + if (rgb_error != 0) + { + png_ptr->rgb_to_gray_status=1; + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == + PNG_RGB_TO_GRAY_WARN) + png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == + PNG_RGB_TO_GRAY_ERR) + png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + } + } +#endif + +/* From Andreas Dilger e-mail to png-implement, 26 March 1998: + * + * In most cases, the "simple transparency" should be done prior to doing + * gray-to-RGB, or you will have to test 3x as many bytes to check if a + * pixel is transparent. You would also need to make sure that the + * transparency information is upgraded to RGB. + * + * To summarize, the current flow is: + * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite + * with background "in place" if transparent, + * convert to RGB if necessary + * - Gray + alpha -> composite with gray background and remove alpha bytes, + * convert to RGB if necessary + * + * To support RGB backgrounds for gray images we need: + * - Gray + simple transparency -> convert to RGB + simple transparency, + * compare 3 or 6 bytes and composite with + * background "in place" if transparent + * (3x compare/pixel compared to doing + * composite with gray bkgrnd) + * - Gray + alpha -> convert to RGB + alpha, composite with background and + * remove alpha bytes (3x float + * operations/pixel compared with composite + * on gray background) + * + * Greg's change will do this. The reason it wasn't done before is for + * performance, as this increases the per-pixel operations. If we would check + * in advance if the background was gray or RGB, and position the gray-to-RGB + * transform appropriately, then it would save a lot of work/time. + */ + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* If gray -> RGB, do so now only if background is non-gray; else do later + * for performance reasons + */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 && + (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) == 0) + png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + if ((png_ptr->transformations & PNG_COMPOSE) != 0) + png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED + if ((png_ptr->transformations & PNG_GAMMA) != 0 && +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* Because RGB_TO_GRAY does the gamma transform. */ + (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0 && +#endif +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + /* Because PNG_COMPOSE does the gamma transform if there is something to + * do (if there is an alpha channel or transparency.) + */ + !((png_ptr->transformations & PNG_COMPOSE) != 0 && + ((png_ptr->num_trans != 0) || + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)) && +#endif + /* Because png_init_read_transformations transforms the palette, unless + * RGB_TO_GRAY will do the transform. + */ + (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)) + png_do_gamma(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && + (png_ptr->transformations & PNG_COMPOSE) != 0 && + (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + 0 /* at_start == false, because SWAP_ALPHA happens later */); +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + if ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 && + (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) + png_do_encode_alpha(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0) + png_do_scale_16_to_8(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + /* There is no harm in doing both of these because only one has any effect, + * by putting the 'scale' option first if the app asks for scale (either by + * calling the API or in a TRANSFORM flag) this is what happens. + */ + if ((png_ptr->transformations & PNG_16_TO_8) != 0) + png_do_chop(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + if ((png_ptr->transformations & PNG_QUANTIZE) != 0) + { + png_do_quantize(row_info, png_ptr->row_buf + 1, + png_ptr->palette_lookup, png_ptr->quantize_index); + + if (row_info->rowbytes == 0) + png_error(png_ptr, "png_do_quantize returned rowbytes=0"); + } +#endif /* READ_QUANTIZE */ + +#ifdef PNG_READ_EXPAND_16_SUPPORTED + /* Do the expansion now, after all the arithmetic has been done. Notice + * that previous transformations can handle the PNG_EXPAND_16 flag if this + * is efficient (particularly true in the case of gamma correction, where + * better accuracy results faster!) + */ + if ((png_ptr->transformations & PNG_EXPAND_16) != 0) + png_do_expand_16(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* NOTE: moved here in 1.5.4 (from much later in this list.) */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 && + (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) != 0) + png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_INVERT_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) + png_do_invert(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) + png_do_read_invert_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED + if ((png_ptr->transformations & PNG_SHIFT) != 0) + png_do_unshift(row_info, png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif + +#ifdef PNG_READ_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) != 0) + png_do_unpack(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Added at libpng-1.5.10 */ + if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && + png_ptr->num_palette_max >= 0) + png_do_check_palette_indexes(png_ptr, row_info); +#endif + +#ifdef PNG_READ_BGR_SUPPORTED + if ((png_ptr->transformations & PNG_BGR) != 0) + png_do_bgr(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + png_do_packswap(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED + if ((png_ptr->transformations & PNG_FILLER) != 0) + png_do_read_filler(row_info, png_ptr->row_buf + 1, + (png_uint_32)png_ptr->filler, png_ptr->flags); +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0) + png_do_read_swap_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_16BIT_SUPPORTED +#ifdef PNG_READ_SWAP_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) + png_do_swap(row_info, png_ptr->row_buf + 1); +#endif +#endif + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) + { + if (png_ptr->read_user_transform_fn != NULL) + (*(png_ptr->read_user_transform_fn)) /* User read transform function */ + (png_ptr, /* png_ptr */ + row_info, /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_size_t rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED + if (png_ptr->user_transform_depth != 0) + row_info->bit_depth = png_ptr->user_transform_depth; + + if (png_ptr->user_transform_channels != 0) + row_info->channels = png_ptr->user_transform_channels; +#endif + row_info->pixel_depth = (png_byte)(row_info->bit_depth * + row_info->channels); + + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_info->width); + } +#endif +} + +#endif /* READ_TRANSFORMS */ +#endif /* READ */ diff --git a/source/Irrlicht/libpng/pngrutil.c b/source/Irrlicht/libpng/pngrutil.c new file mode 100644 index 00000000..357b1728 --- /dev/null +++ b/source/Irrlicht/libpng/pngrutil.c @@ -0,0 +1,4529 @@ + +/* pngrutil.c - utilities to read a PNG file + * + * Last changed in libpng 1.6.20 [December 3, 2014] + * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file contains routines that are only called from within + * libpng itself during the course of reading an image. + */ + +#include "pngpriv.h" + +#ifdef PNG_READ_SUPPORTED + +png_uint_32 PNGAPI +png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf) +{ + png_uint_32 uval = png_get_uint_32(buf); + + if (uval > PNG_UINT_31_MAX) + png_error(png_ptr, "PNG unsigned integer out of range"); + + return (uval); +} + +#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_READ_cHRM_SUPPORTED) +/* The following is a variation on the above for use with the fixed + * point values used for gAMA and cHRM. Instead of png_error it + * issues a warning and returns (-1) - an invalid value because both + * gAMA and cHRM use *unsigned* integers for fixed point values. + */ +#define PNG_FIXED_ERROR (-1) + +static png_fixed_point /* PRIVATE */ +png_get_fixed_point(png_structrp png_ptr, png_const_bytep buf) +{ + png_uint_32 uval = png_get_uint_32(buf); + + if (uval <= PNG_UINT_31_MAX) + return (png_fixed_point)uval; /* known to be in range */ + + /* The caller can turn off the warning by passing NULL. */ + if (png_ptr != NULL) + png_warning(png_ptr, "PNG fixed point integer out of range"); + + return PNG_FIXED_ERROR; +} +#endif + +#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED +/* NOTE: the read macros will obscure these definitions, so that if + * PNG_USE_READ_MACROS is set the library will not use them internally, + * but the APIs will still be available externally. + * + * The parentheses around "PNGAPI function_name" in the following three + * functions are necessary because they allow the macros to co-exist with + * these (unused but exported) functions. + */ + +/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */ +png_uint_32 (PNGAPI +png_get_uint_32)(png_const_bytep buf) +{ + png_uint_32 uval = + ((png_uint_32)(*(buf )) << 24) + + ((png_uint_32)(*(buf + 1)) << 16) + + ((png_uint_32)(*(buf + 2)) << 8) + + ((png_uint_32)(*(buf + 3)) ) ; + + return uval; +} + +/* Grab a signed 32-bit integer from a buffer in big-endian format. The + * data is stored in the PNG file in two's complement format and there + * is no guarantee that a 'png_int_32' is exactly 32 bits, therefore + * the following code does a two's complement to native conversion. + */ +png_int_32 (PNGAPI +png_get_int_32)(png_const_bytep buf) +{ + png_uint_32 uval = png_get_uint_32(buf); + if ((uval & 0x80000000) == 0) /* non-negative */ + return uval; + + uval = (uval ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */ + if ((uval & 0x80000000) == 0) /* no overflow */ + return -(png_int_32)uval; + /* The following has to be safe; this function only gets called on PNG data + * and if we get here that data is invalid. 0 is the most safe value and + * if not then an attacker would surely just generate a PNG with 0 instead. + */ + return 0; +} + +/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */ +png_uint_16 (PNGAPI +png_get_uint_16)(png_const_bytep buf) +{ + /* ANSI-C requires an int value to accomodate at least 16 bits so this + * works and allows the compiler not to worry about possible narrowing + * on 32-bit systems. (Pre-ANSI systems did not make integers smaller + * than 16 bits either.) + */ + unsigned int val = + ((unsigned int)(*buf) << 8) + + ((unsigned int)(*(buf + 1))); + + return (png_uint_16)val; +} + +#endif /* READ_INT_FUNCTIONS */ + +/* Read and check the PNG file signature */ +void /* PRIVATE */ +png_read_sig(png_structrp png_ptr, png_inforp info_ptr) +{ + png_size_t num_checked, num_to_check; + + /* Exit if the user application does not expect a signature. */ + if (png_ptr->sig_bytes >= 8) + return; + + num_checked = png_ptr->sig_bytes; + num_to_check = 8 - num_checked; + +#ifdef PNG_IO_STATE_SUPPORTED + png_ptr->io_state = PNG_IO_READING | PNG_IO_SIGNATURE; +#endif + + /* The signature must be serialized in a single I/O call. */ + png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check); + png_ptr->sig_bytes = 8; + + if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check) != 0) + { + if (num_checked < 4 && + png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) + png_error(png_ptr, "Not a PNG file"); + else + png_error(png_ptr, "PNG file corrupted by ASCII conversion"); + } + if (num_checked < 3) + png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; +} + +/* Read the chunk header (length + type name). + * Put the type name into png_ptr->chunk_name, and return the length. + */ +png_uint_32 /* PRIVATE */ +png_read_chunk_header(png_structrp png_ptr) +{ + png_byte buf[8]; + png_uint_32 length; + +#ifdef PNG_IO_STATE_SUPPORTED + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR; +#endif + + /* Read the length and the chunk name. + * This must be performed in a single I/O call. + */ + png_read_data(png_ptr, buf, 8); + length = png_get_uint_31(png_ptr, buf); + + /* Put the chunk name into png_ptr->chunk_name. */ + png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(buf+4); + + png_debug2(0, "Reading %lx chunk, length = %lu", + (unsigned long)png_ptr->chunk_name, (unsigned long)length); + + /* Reset the crc and run it over the chunk name. */ + png_reset_crc(png_ptr); + png_calculate_crc(png_ptr, buf + 4, 4); + + /* Check to see if chunk name is valid. */ + png_check_chunk_name(png_ptr, png_ptr->chunk_name); + +#ifdef PNG_IO_STATE_SUPPORTED + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA; +#endif + + return length; +} + +/* Read data, and (optionally) run it through the CRC. */ +void /* PRIVATE */ +png_crc_read(png_structrp png_ptr, png_bytep buf, png_uint_32 length) +{ + if (png_ptr == NULL) + return; + + png_read_data(png_ptr, buf, length); + png_calculate_crc(png_ptr, buf, length); +} + +/* Optionally skip data and then check the CRC. Depending on whether we + * are reading an ancillary or critical chunk, and how the program has set + * things up, we may calculate the CRC on the data and print a message. + * Returns '1' if there was a CRC error, '0' otherwise. + */ +int /* PRIVATE */ +png_crc_finish(png_structrp png_ptr, png_uint_32 skip) +{ + /* The size of the local buffer for inflate is a good guess as to a + * reasonable size to use for buffering reads from the application. + */ + while (skip > 0) + { + png_uint_32 len; + png_byte tmpbuf[PNG_INFLATE_BUF_SIZE]; + + len = (sizeof tmpbuf); + if (len > skip) + len = skip; + skip -= len; + + png_crc_read(png_ptr, tmpbuf, len); + } + + if (png_crc_error(png_ptr) != 0) + { + if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0 ? + (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0 : + (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE) != 0) + { + png_chunk_warning(png_ptr, "CRC error"); + } + + else + png_chunk_error(png_ptr, "CRC error"); + + return (1); + } + + return (0); +} + +/* Compare the CRC stored in the PNG file with that calculated by libpng from + * the data it has read thus far. + */ +int /* PRIVATE */ +png_crc_error(png_structrp png_ptr) +{ + png_byte crc_bytes[4]; + png_uint_32 crc; + int need_crc = 1; + + if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0) + { + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == + (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) + need_crc = 0; + } + + else /* critical */ + { + if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0) + need_crc = 0; + } + +#ifdef PNG_IO_STATE_SUPPORTED + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC; +#endif + + /* The chunk CRC must be serialized in a single I/O call. */ + png_read_data(png_ptr, crc_bytes, 4); + + if (need_crc != 0) + { + crc = png_get_uint_32(crc_bytes); + return ((int)(crc != png_ptr->crc)); + } + + else + return (0); +} + +#if defined(PNG_READ_iCCP_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) ||\ + defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_READ_sCAL_SUPPORTED) ||\ + defined(PNG_READ_sPLT_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) ||\ + defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_SEQUENTIAL_READ_SUPPORTED) +/* Manage the read buffer; this simply reallocates the buffer if it is not small + * enough (or if it is not allocated). The routine returns a pointer to the + * buffer; if an error occurs and 'warn' is set the routine returns NULL, else + * it will call png_error (via png_malloc) on failure. (warn == 2 means + * 'silent'). + */ +static png_bytep +png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn) +{ + png_bytep buffer = png_ptr->read_buffer; + + if (buffer != NULL && new_size > png_ptr->read_buffer_size) + { + png_ptr->read_buffer = NULL; + png_ptr->read_buffer = NULL; + png_ptr->read_buffer_size = 0; + png_free(png_ptr, buffer); + buffer = NULL; + } + + if (buffer == NULL) + { + buffer = png_voidcast(png_bytep, png_malloc_base(png_ptr, new_size)); + + if (buffer != NULL) + { + png_ptr->read_buffer = buffer; + png_ptr->read_buffer_size = new_size; + } + + else if (warn < 2) /* else silent */ + { + if (warn != 0) + png_chunk_warning(png_ptr, "insufficient memory to read chunk"); + + else + png_chunk_error(png_ptr, "insufficient memory to read chunk"); + } + } + + return buffer; +} +#endif /* READ_iCCP|iTXt|pCAL|sCAL|sPLT|tEXt|zTXt|SEQUENTIAL_READ */ + +/* png_inflate_claim: claim the zstream for some nefarious purpose that involves + * decompression. Returns Z_OK on success, else a zlib error code. It checks + * the owner but, in final release builds, just issues a warning if some other + * chunk apparently owns the stream. Prior to release it does a png_error. + */ +static int +png_inflate_claim(png_structrp png_ptr, png_uint_32 owner) +{ + if (png_ptr->zowner != 0) + { + char msg[64]; + + PNG_STRING_FROM_CHUNK(msg, png_ptr->zowner); + /* So the message that results is " using zstream"; this is an + * internal error, but is very useful for debugging. i18n requirements + * are minimal. + */ + (void)png_safecat(msg, (sizeof msg), 4, " using zstream"); +#if PNG_RELEASE_BUILD + png_chunk_warning(png_ptr, msg); + png_ptr->zowner = 0; +#else + png_chunk_error(png_ptr, msg); +#endif + } + + /* Implementation note: unlike 'png_deflate_claim' this internal function + * does not take the size of the data as an argument. Some efficiency could + * be gained by using this when it is known *if* the zlib stream itself does + * not record the number; however, this is an illusion: the original writer + * of the PNG may have selected a lower window size, and we really must + * follow that because, for systems with with limited capabilities, we + * would otherwise reject the application's attempts to use a smaller window + * size (zlib doesn't have an interface to say "this or lower"!). + * + * inflateReset2 was added to zlib 1.2.4; before this the window could not be + * reset, therefore it is necessary to always allocate the maximum window + * size with earlier zlibs just in case later compressed chunks need it. + */ + { + int ret; /* zlib return code */ +#if PNG_ZLIB_VERNUM >= 0x1240 + +# if defined(PNG_SET_OPTION_SUPPORTED) && defined(PNG_MAXIMUM_INFLATE_WINDOW) + int window_bits; + + if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) == + PNG_OPTION_ON) + { + window_bits = 15; + png_ptr->zstream_start = 0; /* fixed window size */ + } + + else + { + window_bits = 0; + png_ptr->zstream_start = 1; + } +# else +# define window_bits 0 +# endif +#endif + + /* Set this for safety, just in case the previous owner left pointers to + * memory allocations. + */ + png_ptr->zstream.next_in = NULL; + png_ptr->zstream.avail_in = 0; + png_ptr->zstream.next_out = NULL; + png_ptr->zstream.avail_out = 0; + + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) + { +#if PNG_ZLIB_VERNUM < 0x1240 + ret = inflateReset(&png_ptr->zstream); +#else + ret = inflateReset2(&png_ptr->zstream, window_bits); +#endif + } + + else + { +#if PNG_ZLIB_VERNUM < 0x1240 + ret = inflateInit(&png_ptr->zstream); +#else + ret = inflateInit2(&png_ptr->zstream, window_bits); +#endif + + if (ret == Z_OK) + png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; + } + + if (ret == Z_OK) + png_ptr->zowner = owner; + + else + png_zstream_error(png_ptr, ret); + + return ret; + } + +#ifdef window_bits +# undef window_bits +#endif +} + +#if PNG_ZLIB_VERNUM >= 0x1240 +/* Handle the start of the inflate stream if we called inflateInit2(strm,0); + * in this case some zlib versions skip validation of the CINFO field and, in + * certain circumstances, libpng may end up displaying an invalid image, in + * contrast to implementations that call zlib in the normal way (e.g. libpng + * 1.5). + */ +int /* PRIVATE */ +png_zlib_inflate(png_structrp png_ptr, int flush) +{ + if (png_ptr->zstream_start && png_ptr->zstream.avail_in > 0) + { + if ((*png_ptr->zstream.next_in >> 4) > 7) + { + png_ptr->zstream.msg = "invalid window size (libpng)"; + return Z_DATA_ERROR; + } + + png_ptr->zstream_start = 0; + } + + return inflate(&png_ptr->zstream, flush); +} +#endif /* Zlib >= 1.2.4 */ + +#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED +/* png_inflate now returns zlib error codes including Z_OK and Z_STREAM_END to + * allow the caller to do multiple calls if required. If the 'finish' flag is + * set Z_FINISH will be passed to the final inflate() call and Z_STREAM_END must + * be returned or there has been a problem, otherwise Z_SYNC_FLUSH is used and + * Z_OK or Z_STREAM_END will be returned on success. + * + * The input and output sizes are updated to the actual amounts of data consumed + * or written, not the amount available (as in a z_stream). The data pointers + * are not changed, so the next input is (data+input_size) and the next + * available output is (output+output_size). + */ +static int +png_inflate(png_structrp png_ptr, png_uint_32 owner, int finish, + /* INPUT: */ png_const_bytep input, png_uint_32p input_size_ptr, + /* OUTPUT: */ png_bytep output, png_alloc_size_t *output_size_ptr) +{ + if (png_ptr->zowner == owner) /* Else not claimed */ + { + int ret; + png_alloc_size_t avail_out = *output_size_ptr; + png_uint_32 avail_in = *input_size_ptr; + + /* zlib can't necessarily handle more than 65535 bytes at once (i.e. it + * can't even necessarily handle 65536 bytes) because the type uInt is + * "16 bits or more". Consequently it is necessary to chunk the input to + * zlib. This code uses ZLIB_IO_MAX, from pngpriv.h, as the maximum (the + * maximum value that can be stored in a uInt.) It is possible to set + * ZLIB_IO_MAX to a lower value in pngpriv.h and this may sometimes have + * a performance advantage, because it reduces the amount of data accessed + * at each step and that may give the OS more time to page it in. + */ + png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input); + /* avail_in and avail_out are set below from 'size' */ + png_ptr->zstream.avail_in = 0; + png_ptr->zstream.avail_out = 0; + + /* Read directly into the output if it is available (this is set to + * a local buffer below if output is NULL). + */ + if (output != NULL) + png_ptr->zstream.next_out = output; + + do + { + uInt avail; + Byte local_buffer[PNG_INFLATE_BUF_SIZE]; + + /* zlib INPUT BUFFER */ + /* The setting of 'avail_in' used to be outside the loop; by setting it + * inside it is possible to chunk the input to zlib and simply rely on + * zlib to advance the 'next_in' pointer. This allows arbitrary + * amounts of data to be passed through zlib at the unavoidable cost of + * requiring a window save (memcpy of up to 32768 output bytes) + * every ZLIB_IO_MAX input bytes. + */ + avail_in += png_ptr->zstream.avail_in; /* not consumed last time */ + + avail = ZLIB_IO_MAX; + + if (avail_in < avail) + avail = (uInt)avail_in; /* safe: < than ZLIB_IO_MAX */ + + avail_in -= avail; + png_ptr->zstream.avail_in = avail; + + /* zlib OUTPUT BUFFER */ + avail_out += png_ptr->zstream.avail_out; /* not written last time */ + + avail = ZLIB_IO_MAX; /* maximum zlib can process */ + + if (output == NULL) + { + /* Reset the output buffer each time round if output is NULL and + * make available the full buffer, up to 'remaining_space' + */ + png_ptr->zstream.next_out = local_buffer; + if ((sizeof local_buffer) < avail) + avail = (sizeof local_buffer); + } + + if (avail_out < avail) + avail = (uInt)avail_out; /* safe: < ZLIB_IO_MAX */ + + png_ptr->zstream.avail_out = avail; + avail_out -= avail; + + /* zlib inflate call */ + /* In fact 'avail_out' may be 0 at this point, that happens at the end + * of the read when the final LZ end code was not passed at the end of + * the previous chunk of input data. Tell zlib if we have reached the + * end of the output buffer. + */ + ret = PNG_INFLATE(png_ptr, avail_out > 0 ? Z_NO_FLUSH : + (finish ? Z_FINISH : Z_SYNC_FLUSH)); + } while (ret == Z_OK); + + /* For safety kill the local buffer pointer now */ + if (output == NULL) + png_ptr->zstream.next_out = NULL; + + /* Claw back the 'size' and 'remaining_space' byte counts. */ + avail_in += png_ptr->zstream.avail_in; + avail_out += png_ptr->zstream.avail_out; + + /* Update the input and output sizes; the updated values are the amount + * consumed or written, effectively the inverse of what zlib uses. + */ + if (avail_out > 0) + *output_size_ptr -= avail_out; + + if (avail_in > 0) + *input_size_ptr -= avail_in; + + /* Ensure png_ptr->zstream.msg is set (even in the success case!) */ + png_zstream_error(png_ptr, ret); + return ret; + } + + else + { + /* This is a bad internal error. The recovery assigns to the zstream msg + * pointer, which is not owned by the caller, but this is safe; it's only + * used on errors! + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed"); + return Z_STREAM_ERROR; + } +} + +/* + * Decompress trailing data in a chunk. The assumption is that read_buffer + * points at an allocated area holding the contents of a chunk with a + * trailing compressed part. What we get back is an allocated area + * holding the original prefix part and an uncompressed version of the + * trailing part (the malloc area passed in is freed). + */ +static int +png_decompress_chunk(png_structrp png_ptr, + png_uint_32 chunklength, png_uint_32 prefix_size, + png_alloc_size_t *newlength /* must be initialized to the maximum! */, + int terminate /*add a '\0' to the end of the uncompressed data*/) +{ + /* TODO: implement different limits for different types of chunk. + * + * The caller supplies *newlength set to the maximum length of the + * uncompressed data, but this routine allocates space for the prefix and + * maybe a '\0' terminator too. We have to assume that 'prefix_size' is + * limited only by the maximum chunk size. + */ + png_alloc_size_t limit = PNG_SIZE_MAX; + +# ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_malloc_max > 0 && + png_ptr->user_chunk_malloc_max < limit) + limit = png_ptr->user_chunk_malloc_max; +# elif PNG_USER_CHUNK_MALLOC_MAX > 0 + if (PNG_USER_CHUNK_MALLOC_MAX < limit) + limit = PNG_USER_CHUNK_MALLOC_MAX; +# endif + + if (limit >= prefix_size + (terminate != 0)) + { + int ret; + + limit -= prefix_size + (terminate != 0); + + if (limit < *newlength) + *newlength = limit; + + /* Now try to claim the stream. */ + ret = png_inflate_claim(png_ptr, png_ptr->chunk_name); + + if (ret == Z_OK) + { + png_uint_32 lzsize = chunklength - prefix_size; + + ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/, + /* input: */ png_ptr->read_buffer + prefix_size, &lzsize, + /* output: */ NULL, newlength); + + if (ret == Z_STREAM_END) + { + /* Use 'inflateReset' here, not 'inflateReset2' because this + * preserves the previously decided window size (otherwise it would + * be necessary to store the previous window size.) In practice + * this doesn't matter anyway, because png_inflate will call inflate + * with Z_FINISH in almost all cases, so the window will not be + * maintained. + */ + if (inflateReset(&png_ptr->zstream) == Z_OK) + { + /* Because of the limit checks above we know that the new, + * expanded, size will fit in a size_t (let alone an + * png_alloc_size_t). Use png_malloc_base here to avoid an + * extra OOM message. + */ + png_alloc_size_t new_size = *newlength; + png_alloc_size_t buffer_size = prefix_size + new_size + + (terminate != 0); + png_bytep text = png_voidcast(png_bytep, png_malloc_base(png_ptr, + buffer_size)); + + if (text != NULL) + { + ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/, + png_ptr->read_buffer + prefix_size, &lzsize, + text + prefix_size, newlength); + + if (ret == Z_STREAM_END) + { + if (new_size == *newlength) + { + if (terminate != 0) + text[prefix_size + *newlength] = 0; + + if (prefix_size > 0) + memcpy(text, png_ptr->read_buffer, prefix_size); + + { + png_bytep old_ptr = png_ptr->read_buffer; + + png_ptr->read_buffer = text; + png_ptr->read_buffer_size = buffer_size; + text = old_ptr; /* freed below */ + } + } + + else + { + /* The size changed on the second read, there can be no + * guarantee that anything is correct at this point. + * The 'msg' pointer has been set to "unexpected end of + * LZ stream", which is fine, but return an error code + * that the caller won't accept. + */ + ret = PNG_UNEXPECTED_ZLIB_RETURN; + } + } + + else if (ret == Z_OK) + ret = PNG_UNEXPECTED_ZLIB_RETURN; /* for safety */ + + /* Free the text pointer (this is the old read_buffer on + * success) + */ + png_free(png_ptr, text); + + /* This really is very benign, but it's still an error because + * the extra space may otherwise be used as a Trojan Horse. + */ + if (ret == Z_STREAM_END && + chunklength - prefix_size != lzsize) + png_chunk_benign_error(png_ptr, "extra compressed data"); + } + + else + { + /* Out of memory allocating the buffer */ + ret = Z_MEM_ERROR; + png_zstream_error(png_ptr, Z_MEM_ERROR); + } + } + + else + { + /* inflateReset failed, store the error message */ + png_zstream_error(png_ptr, ret); + + if (ret == Z_STREAM_END) + ret = PNG_UNEXPECTED_ZLIB_RETURN; + } + } + + else if (ret == Z_OK) + ret = PNG_UNEXPECTED_ZLIB_RETURN; + + /* Release the claimed stream */ + png_ptr->zowner = 0; + } + + else /* the claim failed */ if (ret == Z_STREAM_END) /* impossible! */ + ret = PNG_UNEXPECTED_ZLIB_RETURN; + + return ret; + } + + else + { + /* Application/configuration limits exceeded */ + png_zstream_error(png_ptr, Z_MEM_ERROR); + return Z_MEM_ERROR; + } +} +#endif /* READ_COMPRESSED_TEXT */ + +#ifdef PNG_READ_iCCP_SUPPORTED +/* Perform a partial read and decompress, producing 'avail_out' bytes and + * reading from the current chunk as required. + */ +static int +png_inflate_read(png_structrp png_ptr, png_bytep read_buffer, uInt read_size, + png_uint_32p chunk_bytes, png_bytep next_out, png_alloc_size_t *out_size, + int finish) +{ + if (png_ptr->zowner == png_ptr->chunk_name) + { + int ret; + + /* next_in and avail_in must have been initialized by the caller. */ + png_ptr->zstream.next_out = next_out; + png_ptr->zstream.avail_out = 0; /* set in the loop */ + + do + { + if (png_ptr->zstream.avail_in == 0) + { + if (read_size > *chunk_bytes) + read_size = (uInt)*chunk_bytes; + *chunk_bytes -= read_size; + + if (read_size > 0) + png_crc_read(png_ptr, read_buffer, read_size); + + png_ptr->zstream.next_in = read_buffer; + png_ptr->zstream.avail_in = read_size; + } + + if (png_ptr->zstream.avail_out == 0) + { + uInt avail = ZLIB_IO_MAX; + if (avail > *out_size) + avail = (uInt)*out_size; + *out_size -= avail; + + png_ptr->zstream.avail_out = avail; + } + + /* Use Z_SYNC_FLUSH when there is no more chunk data to ensure that all + * the available output is produced; this allows reading of truncated + * streams. + */ + ret = PNG_INFLATE(png_ptr, + *chunk_bytes > 0 ? Z_NO_FLUSH : (finish ? Z_FINISH : Z_SYNC_FLUSH)); + } + while (ret == Z_OK && (*out_size > 0 || png_ptr->zstream.avail_out > 0)); + + *out_size += png_ptr->zstream.avail_out; + png_ptr->zstream.avail_out = 0; /* Should not be required, but is safe */ + + /* Ensure the error message pointer is always set: */ + png_zstream_error(png_ptr, ret); + return ret; + } + + else + { + png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed"); + return Z_STREAM_ERROR; + } +} +#endif + +/* Read and check the IDHR chunk */ + +void /* PRIVATE */ +png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte buf[13]; + png_uint_32 width, height; + int bit_depth, color_type, compression_type, filter_type; + int interlace_type; + + png_debug(1, "in png_handle_IHDR"); + + if ((png_ptr->mode & PNG_HAVE_IHDR) != 0) + png_chunk_error(png_ptr, "out of place"); + + /* Check the length */ + if (length != 13) + png_chunk_error(png_ptr, "invalid"); + + png_ptr->mode |= PNG_HAVE_IHDR; + + png_crc_read(png_ptr, buf, 13); + png_crc_finish(png_ptr, 0); + + width = png_get_uint_31(png_ptr, buf); + height = png_get_uint_31(png_ptr, buf + 4); + bit_depth = buf[8]; + color_type = buf[9]; + compression_type = buf[10]; + filter_type = buf[11]; + interlace_type = buf[12]; + + /* Set internal variables */ + png_ptr->width = width; + png_ptr->height = height; + png_ptr->bit_depth = (png_byte)bit_depth; + png_ptr->interlaced = (png_byte)interlace_type; + png_ptr->color_type = (png_byte)color_type; +#ifdef PNG_MNG_FEATURES_SUPPORTED + png_ptr->filter_type = (png_byte)filter_type; +#endif + png_ptr->compression_type = (png_byte)compression_type; + + /* Find number of channels */ + switch (png_ptr->color_type) + { + default: /* invalid, png_set_IHDR calls png_error */ + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_PALETTE: + png_ptr->channels = 1; + break; + + case PNG_COLOR_TYPE_RGB: + png_ptr->channels = 3; + break; + + case PNG_COLOR_TYPE_GRAY_ALPHA: + png_ptr->channels = 2; + break; + + case PNG_COLOR_TYPE_RGB_ALPHA: + png_ptr->channels = 4; + break; + } + + /* Set up other useful info */ + png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * png_ptr->channels); + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width); + png_debug1(3, "bit_depth = %d", png_ptr->bit_depth); + png_debug1(3, "channels = %d", png_ptr->channels); + png_debug1(3, "rowbytes = %lu", (unsigned long)png_ptr->rowbytes); + png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, + color_type, interlace_type, compression_type, filter_type); +} + +/* Read and check the palette */ +void /* PRIVATE */ +png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_color palette[PNG_MAX_PALETTE_LENGTH]; + int max_palette_length, num, i; +#ifdef PNG_POINTER_INDEXING_SUPPORTED + png_colorp pal_ptr; +#endif + + png_debug(1, "in png_handle_PLTE"); + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + /* Moved to before the 'after IDAT' check below because otherwise duplicate + * PLTE chunks are potentially ignored (the spec says there shall not be more + * than one PLTE, the error is not treated as benign, so this check trumps + * the requirement that PLTE appears before IDAT.) + */ + else if ((png_ptr->mode & PNG_HAVE_PLTE) != 0) + png_chunk_error(png_ptr, "duplicate"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + { + /* This is benign because the non-benign error happened before, when an + * IDAT was encountered in a color-mapped image with no PLTE. + */ + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + png_ptr->mode |= PNG_HAVE_PLTE; + + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "ignored in grayscale PNG"); + return; + } + +#ifndef PNG_READ_OPT_PLTE_SUPPORTED + if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + { + png_crc_finish(png_ptr, length); + return; + } +#endif + + if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3) + { + png_crc_finish(png_ptr, length); + + if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + png_chunk_benign_error(png_ptr, "invalid"); + + else + png_chunk_error(png_ptr, "invalid"); + + return; + } + + /* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */ + num = (int)length / 3; + + /* If the palette has 256 or fewer entries but is too large for the bit + * depth, we don't issue an error, to preserve the behavior of previous + * libpng versions. We silently truncate the unused extra palette entries + * here. + */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + max_palette_length = (1 << png_ptr->bit_depth); + else + max_palette_length = PNG_MAX_PALETTE_LENGTH; + + if (num > max_palette_length) + num = max_palette_length; + +#ifdef PNG_POINTER_INDEXING_SUPPORTED + for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++) + { + png_byte buf[3]; + + png_crc_read(png_ptr, buf, 3); + pal_ptr->red = buf[0]; + pal_ptr->green = buf[1]; + pal_ptr->blue = buf[2]; + } +#else + for (i = 0; i < num; i++) + { + png_byte buf[3]; + + png_crc_read(png_ptr, buf, 3); + /* Don't depend upon png_color being any order */ + palette[i].red = buf[0]; + palette[i].green = buf[1]; + palette[i].blue = buf[2]; + } +#endif + + /* If we actually need the PLTE chunk (ie for a paletted image), we do + * whatever the normal CRC configuration tells us. However, if we + * have an RGB image, the PLTE can be considered ancillary, so + * we will act as though it is. + */ +#ifndef PNG_READ_OPT_PLTE_SUPPORTED + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) +#endif + { + png_crc_finish(png_ptr, (int) length - num * 3); + } + +#ifndef PNG_READ_OPT_PLTE_SUPPORTED + else if (png_crc_error(png_ptr) != 0) /* Only if we have a CRC error */ + { + /* If we don't want to use the data from an ancillary chunk, + * we have two options: an error abort, or a warning and we + * ignore the data in this chunk (which should be OK, since + * it's considered ancillary for a RGB or RGBA image). + * + * IMPLEMENTATION NOTE: this is only here because png_crc_finish uses the + * chunk type to determine whether to check the ancillary or the critical + * flags. + */ + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE) == 0) + { + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) != 0) + return; + + else + png_chunk_error(png_ptr, "CRC error"); + } + + /* Otherwise, we (optionally) emit a warning and use the chunk. */ + else if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0) + png_chunk_warning(png_ptr, "CRC error"); + } +#endif + + /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to its + * own copy of the palette. This has the side effect that when png_start_row + * is called (this happens after any call to png_read_update_info) the + * info_ptr palette gets changed. This is extremely unexpected and + * confusing. + * + * Fix this by not sharing the palette in this way. + */ + png_set_PLTE(png_ptr, info_ptr, palette, num); + + /* The three chunks, bKGD, hIST and tRNS *must* appear after PLTE and before + * IDAT. Prior to 1.6.0 this was not checked; instead the code merely + * checked the apparent validity of a tRNS chunk inserted before PLTE on a + * palette PNG. 1.6.0 attempts to rigorously follow the standard and + * therefore does a benign error if the erroneous condition is detected *and* + * cancels the tRNS if the benign error returns. The alternative is to + * amend the standard since it would be rather hypocritical of the standards + * maintainers to ignore it. + */ +#ifdef PNG_READ_tRNS_SUPPORTED + if (png_ptr->num_trans > 0 || + (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0)) + { + /* Cancel this because otherwise it would be used if the transforms + * require it. Don't cancel the 'valid' flag because this would prevent + * detection of duplicate chunks. + */ + png_ptr->num_trans = 0; + + if (info_ptr != NULL) + info_ptr->num_trans = 0; + + png_chunk_benign_error(png_ptr, "tRNS must be after"); + } +#endif + +#ifdef PNG_READ_hIST_SUPPORTED + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0) + png_chunk_benign_error(png_ptr, "hIST must be after"); +#endif + +#ifdef PNG_READ_bKGD_SUPPORTED + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0) + png_chunk_benign_error(png_ptr, "bKGD must be after"); +#endif +} + +void /* PRIVATE */ +png_handle_IEND(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_debug(1, "in png_handle_IEND"); + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0 || + (png_ptr->mode & PNG_HAVE_IDAT) == 0) + png_chunk_error(png_ptr, "out of place"); + + png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND); + + png_crc_finish(png_ptr, length); + + if (length != 0) + png_chunk_benign_error(png_ptr, "invalid"); + + PNG_UNUSED(info_ptr) +} + +#ifdef PNG_READ_gAMA_SUPPORTED +void /* PRIVATE */ +png_handle_gAMA(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_fixed_point igamma; + png_byte buf[4]; + + png_debug(1, "in png_handle_gAMA"); + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + if (length != 4) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, buf, 4); + + if (png_crc_finish(png_ptr, 0) != 0) + return; + + igamma = png_get_fixed_point(NULL, buf); + + png_colorspace_set_gamma(png_ptr, &png_ptr->colorspace, igamma); + png_colorspace_sync(png_ptr, info_ptr); +} +#endif + +#ifdef PNG_READ_sBIT_SUPPORTED +void /* PRIVATE */ +png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + unsigned int truelen, i; + png_byte sample_depth; + png_byte buf[4]; + + png_debug(1, "in png_handle_sBIT"); + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + truelen = 3; + sample_depth = 8; + } + + else + { + truelen = png_ptr->channels; + sample_depth = png_ptr->bit_depth; + } + + if (length != truelen || length > 4) + { + png_chunk_benign_error(png_ptr, "invalid"); + png_crc_finish(png_ptr, length); + return; + } + + buf[0] = buf[1] = buf[2] = buf[3] = sample_depth; + png_crc_read(png_ptr, buf, truelen); + + if (png_crc_finish(png_ptr, 0) != 0) + return; + + for (i=0; i sample_depth) + { + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + } + + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + png_ptr->sig_bit.red = buf[0]; + png_ptr->sig_bit.green = buf[1]; + png_ptr->sig_bit.blue = buf[2]; + png_ptr->sig_bit.alpha = buf[3]; + } + + else + { + png_ptr->sig_bit.gray = buf[0]; + png_ptr->sig_bit.red = buf[0]; + png_ptr->sig_bit.green = buf[0]; + png_ptr->sig_bit.blue = buf[0]; + png_ptr->sig_bit.alpha = buf[1]; + } + + png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit)); +} +#endif + +#ifdef PNG_READ_cHRM_SUPPORTED +void /* PRIVATE */ +png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte buf[32]; + png_xy xy; + + png_debug(1, "in png_handle_cHRM"); + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + if (length != 32) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, buf, 32); + + if (png_crc_finish(png_ptr, 0) != 0) + return; + + xy.whitex = png_get_fixed_point(NULL, buf); + xy.whitey = png_get_fixed_point(NULL, buf + 4); + xy.redx = png_get_fixed_point(NULL, buf + 8); + xy.redy = png_get_fixed_point(NULL, buf + 12); + xy.greenx = png_get_fixed_point(NULL, buf + 16); + xy.greeny = png_get_fixed_point(NULL, buf + 20); + xy.bluex = png_get_fixed_point(NULL, buf + 24); + xy.bluey = png_get_fixed_point(NULL, buf + 28); + + if (xy.whitex == PNG_FIXED_ERROR || + xy.whitey == PNG_FIXED_ERROR || + xy.redx == PNG_FIXED_ERROR || + xy.redy == PNG_FIXED_ERROR || + xy.greenx == PNG_FIXED_ERROR || + xy.greeny == PNG_FIXED_ERROR || + xy.bluex == PNG_FIXED_ERROR || + xy.bluey == PNG_FIXED_ERROR) + { + png_chunk_benign_error(png_ptr, "invalid values"); + return; + } + + /* If a colorspace error has already been output skip this chunk */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) + return; + + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0) + { + png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; + png_colorspace_sync(png_ptr, info_ptr); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + png_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; + (void)png_colorspace_set_chromaticities(png_ptr, &png_ptr->colorspace, &xy, + 1/*prefer cHRM values*/); + png_colorspace_sync(png_ptr, info_ptr); +} +#endif + +#ifdef PNG_READ_sRGB_SUPPORTED +void /* PRIVATE */ +png_handle_sRGB(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte intent; + + png_debug(1, "in png_handle_sRGB"); + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + if (length != 1) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, &intent, 1); + + if (png_crc_finish(png_ptr, 0) != 0) + return; + + /* If a colorspace error has already been output skip this chunk */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) + return; + + /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect + * this. + */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) != 0) + { + png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; + png_colorspace_sync(png_ptr, info_ptr); + png_chunk_benign_error(png_ptr, "too many profiles"); + return; + } + + (void)png_colorspace_set_sRGB(png_ptr, &png_ptr->colorspace, intent); + png_colorspace_sync(png_ptr, info_ptr); +} +#endif /* READ_sRGB */ + +#ifdef PNG_READ_iCCP_SUPPORTED +void /* PRIVATE */ +png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +/* Note: this does not properly handle profiles that are > 64K under DOS */ +{ + png_const_charp errmsg = NULL; /* error message output, or no error */ + int finished = 0; /* crc checked */ + + png_debug(1, "in png_handle_iCCP"); + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + /* Consistent with all the above colorspace handling an obviously *invalid* + * chunk is just ignored, so does not invalidate the color space. An + * alternative is to set the 'invalid' flags at the start of this routine + * and only clear them in they were not set before and all the tests pass. + * The minimum 'deflate' stream is assumed to be just the 2 byte header and + * 4 byte checksum. The keyword must be at least one character and there is + * a terminator (0) byte and the compression method. + */ + if (length < 9) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "too short"); + return; + } + + /* If a colorspace error has already been output skip this chunk */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) + { + png_crc_finish(png_ptr, length); + return; + } + + /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect + * this. + */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) == 0) + { + uInt read_length, keyword_length; + char keyword[81]; + + /* Find the keyword; the keyword plus separator and compression method + * bytes can be at most 81 characters long. + */ + read_length = 81; /* maximum */ + if (read_length > length) + read_length = (uInt)length; + + png_crc_read(png_ptr, (png_bytep)keyword, read_length); + length -= read_length; + + keyword_length = 0; + while (keyword_length < 80 && keyword_length < read_length && + keyword[keyword_length] != 0) + ++keyword_length; + + /* TODO: make the keyword checking common */ + if (keyword_length >= 1 && keyword_length <= 79) + { + /* We only understand '0' compression - deflate - so if we get a + * different value we can't safely decode the chunk. + */ + if (keyword_length+1 < read_length && + keyword[keyword_length+1] == PNG_COMPRESSION_TYPE_BASE) + { + read_length -= keyword_length+2; + + if (png_inflate_claim(png_ptr, png_iCCP) == Z_OK) + { + Byte profile_header[132]; + Byte local_buffer[PNG_INFLATE_BUF_SIZE]; + png_alloc_size_t size = (sizeof profile_header); + + png_ptr->zstream.next_in = (Bytef*)keyword + (keyword_length+2); + png_ptr->zstream.avail_in = read_length; + (void)png_inflate_read(png_ptr, local_buffer, + (sizeof local_buffer), &length, profile_header, &size, + 0/*finish: don't, because the output is too small*/); + + if (size == 0) + { + /* We have the ICC profile header; do the basic header checks. + */ + const png_uint_32 profile_length = + png_get_uint_32(profile_header); + + if (png_icc_check_length(png_ptr, &png_ptr->colorspace, + keyword, profile_length) != 0) + { + /* The length is apparently ok, so we can check the 132 + * byte header. + */ + if (png_icc_check_header(png_ptr, &png_ptr->colorspace, + keyword, profile_length, profile_header, + png_ptr->color_type) != 0) + { + /* Now read the tag table; a variable size buffer is + * needed at this point, allocate one for the whole + * profile. The header check has already validated + * that none of these stuff will overflow. + */ + const png_uint_32 tag_count = png_get_uint_32( + profile_header+128); + png_bytep profile = png_read_buffer(png_ptr, + profile_length, 2/*silent*/); + + if (profile != NULL) + { + memcpy(profile, profile_header, + (sizeof profile_header)); + + size = 12 * tag_count; + + (void)png_inflate_read(png_ptr, local_buffer, + (sizeof local_buffer), &length, + profile + (sizeof profile_header), &size, 0); + + /* Still expect a buffer error because we expect + * there to be some tag data! + */ + if (size == 0) + { + if (png_icc_check_tag_table(png_ptr, + &png_ptr->colorspace, keyword, profile_length, + profile) != 0) + { + /* The profile has been validated for basic + * security issues, so read the whole thing in. + */ + size = profile_length - (sizeof profile_header) + - 12 * tag_count; + + (void)png_inflate_read(png_ptr, local_buffer, + (sizeof local_buffer), &length, + profile + (sizeof profile_header) + + 12 * tag_count, &size, 1/*finish*/); + + if (length > 0 && !(png_ptr->flags & + PNG_FLAG_BENIGN_ERRORS_WARN)) + errmsg = "extra compressed data"; + + /* But otherwise allow extra data: */ + else if (size == 0) + { + if (length > 0) + { + /* This can be handled completely, so + * keep going. + */ + png_chunk_warning(png_ptr, + "extra compressed data"); + } + + png_crc_finish(png_ptr, length); + finished = 1; + +# ifdef PNG_sRGB_SUPPORTED + /* Check for a match against sRGB */ + png_icc_set_sRGB(png_ptr, + &png_ptr->colorspace, profile, + png_ptr->zstream.adler); +# endif + + /* Steal the profile for info_ptr. */ + if (info_ptr != NULL) + { + png_free_data(png_ptr, info_ptr, + PNG_FREE_ICCP, 0); + + info_ptr->iccp_name = png_voidcast(char*, + png_malloc_base(png_ptr, + keyword_length+1)); + if (info_ptr->iccp_name != NULL) + { + memcpy(info_ptr->iccp_name, keyword, + keyword_length+1); + info_ptr->iccp_proflen = + profile_length; + info_ptr->iccp_profile = profile; + png_ptr->read_buffer = NULL; /*steal*/ + info_ptr->free_me |= PNG_FREE_ICCP; + info_ptr->valid |= PNG_INFO_iCCP; + } + + else + { + png_ptr->colorspace.flags |= + PNG_COLORSPACE_INVALID; + errmsg = "out of memory"; + } + } + + /* else the profile remains in the read + * buffer which gets reused for subsequent + * chunks. + */ + + if (info_ptr != NULL) + png_colorspace_sync(png_ptr, info_ptr); + + if (errmsg == NULL) + { + png_ptr->zowner = 0; + return; + } + } + + else if (size > 0) + errmsg = "truncated"; + +#ifndef __COVERITY__ + else + errmsg = png_ptr->zstream.msg; +#endif + } + + /* else png_icc_check_tag_table output an error */ + } + + else /* profile truncated */ + errmsg = png_ptr->zstream.msg; + } + + else + errmsg = "out of memory"; + } + + /* else png_icc_check_header output an error */ + } + + /* else png_icc_check_length output an error */ + } + + else /* profile truncated */ + errmsg = png_ptr->zstream.msg; + + /* Release the stream */ + png_ptr->zowner = 0; + } + + else /* png_inflate_claim failed */ + errmsg = png_ptr->zstream.msg; + } + + else + errmsg = "bad compression method"; /* or missing */ + } + + else + errmsg = "bad keyword"; + } + + else + errmsg = "too many profiles"; + + /* Failure: the reason is in 'errmsg' */ + if (finished == 0) + png_crc_finish(png_ptr, length); + + png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; + png_colorspace_sync(png_ptr, info_ptr); + if (errmsg != NULL) /* else already output */ + png_chunk_benign_error(png_ptr, errmsg); +} +#endif /* READ_iCCP */ + +#ifdef PNG_READ_sPLT_SUPPORTED +void /* PRIVATE */ +png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +/* Note: this does not properly handle chunks that are > 64K under DOS */ +{ + png_bytep entry_start, buffer; + png_sPLT_t new_palette; + png_sPLT_entryp pp; + png_uint_32 data_length; + int entry_size, i; + png_uint_32 skip = 0; + png_uint_32 dl; + png_size_t max_dl; + + png_debug(1, "in png_handle_sPLT"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for sPLT"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + +#ifdef PNG_MAX_MALLOC_64K + if (length > 65535U) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "too large to fit in memory"); + return; + } +#endif + + buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); + if (buffer == NULL) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); + return; + } + + + /* WARNING: this may break if size_t is less than 32 bits; it is assumed + * that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a + * potential breakage point if the types in pngconf.h aren't exactly right. + */ + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, skip) != 0) + return; + + buffer[length] = 0; + + for (entry_start = buffer; *entry_start; entry_start++) + /* Empty loop to find end of name */ ; + + ++entry_start; + + /* A sample depth should follow the separator, and we should be on it */ + if (length < 2U || entry_start > buffer + (length - 2U)) + { + png_warning(png_ptr, "malformed sPLT chunk"); + return; + } + + new_palette.depth = *entry_start++; + entry_size = (new_palette.depth == 8 ? 6 : 10); + /* This must fit in a png_uint_32 because it is derived from the original + * chunk data length. + */ + data_length = length - (png_uint_32)(entry_start - buffer); + + /* Integrity-check the data length */ + if ((data_length % entry_size) != 0) + { + png_warning(png_ptr, "sPLT chunk has bad length"); + return; + } + + dl = (png_int_32)(data_length / entry_size); + max_dl = PNG_SIZE_MAX / (sizeof (png_sPLT_entry)); + + if (dl > max_dl) + { + png_warning(png_ptr, "sPLT chunk too long"); + return; + } + + new_palette.nentries = (png_int_32)(data_length / entry_size); + + new_palette.entries = (png_sPLT_entryp)png_malloc_warn( + png_ptr, new_palette.nentries * (sizeof (png_sPLT_entry))); + + if (new_palette.entries == NULL) + { + png_warning(png_ptr, "sPLT chunk requires too much memory"); + return; + } + +#ifdef PNG_POINTER_INDEXING_SUPPORTED + for (i = 0; i < new_palette.nentries; i++) + { + pp = new_palette.entries + i; + + if (new_palette.depth == 8) + { + pp->red = *entry_start++; + pp->green = *entry_start++; + pp->blue = *entry_start++; + pp->alpha = *entry_start++; + } + + else + { + pp->red = png_get_uint_16(entry_start); entry_start += 2; + pp->green = png_get_uint_16(entry_start); entry_start += 2; + pp->blue = png_get_uint_16(entry_start); entry_start += 2; + pp->alpha = png_get_uint_16(entry_start); entry_start += 2; + } + + pp->frequency = png_get_uint_16(entry_start); entry_start += 2; + } +#else + pp = new_palette.entries; + + for (i = 0; i < new_palette.nentries; i++) + { + + if (new_palette.depth == 8) + { + pp[i].red = *entry_start++; + pp[i].green = *entry_start++; + pp[i].blue = *entry_start++; + pp[i].alpha = *entry_start++; + } + + else + { + pp[i].red = png_get_uint_16(entry_start); entry_start += 2; + pp[i].green = png_get_uint_16(entry_start); entry_start += 2; + pp[i].blue = png_get_uint_16(entry_start); entry_start += 2; + pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2; + } + + pp[i].frequency = png_get_uint_16(entry_start); entry_start += 2; + } +#endif + + /* Discard all chunk data except the name and stash that */ + new_palette.name = (png_charp)buffer; + + png_set_sPLT(png_ptr, info_ptr, &new_palette, 1); + + png_free(png_ptr, new_palette.entries); +} +#endif /* READ_sPLT */ + +#ifdef PNG_READ_tRNS_SUPPORTED +void /* PRIVATE */ +png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte readbuf[PNG_MAX_PALETTE_LENGTH]; + + png_debug(1, "in png_handle_tRNS"); + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + png_byte buf[2]; + + if (length != 2) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, buf, 2); + png_ptr->num_trans = 1; + png_ptr->trans_color.gray = png_get_uint_16(buf); + } + + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + png_byte buf[6]; + + if (length != 6) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, buf, length); + png_ptr->num_trans = 1; + png_ptr->trans_color.red = png_get_uint_16(buf); + png_ptr->trans_color.green = png_get_uint_16(buf + 2); + png_ptr->trans_color.blue = png_get_uint_16(buf + 4); + } + + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if ((png_ptr->mode & PNG_HAVE_PLTE) == 0) + { + /* TODO: is this actually an error in the ISO spec? */ + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + if (length > (unsigned int) png_ptr->num_palette || + length > (unsigned int) PNG_MAX_PALETTE_LENGTH || + length == 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, readbuf, length); + png_ptr->num_trans = (png_uint_16)length; + } + + else + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid with alpha channel"); + return; + } + + if (png_crc_finish(png_ptr, 0) != 0) + { + png_ptr->num_trans = 0; + return; + } + + /* TODO: this is a horrible side effect in the palette case because the + * png_struct ends up with a pointer to the tRNS buffer owned by the + * png_info. Fix this. + */ + png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans, + &(png_ptr->trans_color)); +} +#endif + +#ifdef PNG_READ_bKGD_SUPPORTED +void /* PRIVATE */ +png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + unsigned int truelen; + png_byte buf[6]; + png_color_16 background; + + png_debug(1, "in png_handle_bKGD"); + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0 || + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + (png_ptr->mode & PNG_HAVE_PLTE) == 0)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + truelen = 1; + + else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + truelen = 6; + + else + truelen = 2; + + if (length != truelen) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, buf, truelen); + + if (png_crc_finish(png_ptr, 0) != 0) + return; + + /* We convert the index value into RGB components so that we can allow + * arbitrary RGB values for background when we have transparency, and + * so it is easy to determine the RGB values of the background color + * from the info_ptr struct. + */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + background.index = buf[0]; + + if (info_ptr != NULL && info_ptr->num_palette != 0) + { + if (buf[0] >= info_ptr->num_palette) + { + png_chunk_benign_error(png_ptr, "invalid index"); + return; + } + + background.red = (png_uint_16)png_ptr->palette[buf[0]].red; + background.green = (png_uint_16)png_ptr->palette[buf[0]].green; + background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue; + } + + else + background.red = background.green = background.blue = 0; + + background.gray = 0; + } + + else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) /* GRAY */ + { + background.index = 0; + background.red = + background.green = + background.blue = + background.gray = png_get_uint_16(buf); + } + + else + { + background.index = 0; + background.red = png_get_uint_16(buf); + background.green = png_get_uint_16(buf + 2); + background.blue = png_get_uint_16(buf + 4); + background.gray = 0; + } + + png_set_bKGD(png_ptr, info_ptr, &background); +} +#endif + +#ifdef PNG_READ_hIST_SUPPORTED +void /* PRIVATE */ +png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + unsigned int num, i; + png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH]; + + png_debug(1, "in png_handle_hIST"); + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0 || + (png_ptr->mode & PNG_HAVE_PLTE) == 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + num = length / 2 ; + + if (num != (unsigned int) png_ptr->num_palette || + num > (unsigned int) PNG_MAX_PALETTE_LENGTH) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + for (i = 0; i < num; i++) + { + png_byte buf[2]; + + png_crc_read(png_ptr, buf, 2); + readbuf[i] = png_get_uint_16(buf); + } + + if (png_crc_finish(png_ptr, 0) != 0) + return; + + png_set_hIST(png_ptr, info_ptr, readbuf); +} +#endif + +#ifdef PNG_READ_pHYs_SUPPORTED +void /* PRIVATE */ +png_handle_pHYs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte buf[9]; + png_uint_32 res_x, res_y; + int unit_type; + + png_debug(1, "in png_handle_pHYs"); + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + if (length != 9) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, buf, 9); + + if (png_crc_finish(png_ptr, 0) != 0) + return; + + res_x = png_get_uint_32(buf); + res_y = png_get_uint_32(buf + 4); + unit_type = buf[8]; + png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type); +} +#endif + +#ifdef PNG_READ_oFFs_SUPPORTED +void /* PRIVATE */ +png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte buf[9]; + png_int_32 offset_x, offset_y; + int unit_type; + + png_debug(1, "in png_handle_oFFs"); + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + if (length != 9) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, buf, 9); + + if (png_crc_finish(png_ptr, 0) != 0) + return; + + offset_x = png_get_int_32(buf); + offset_y = png_get_int_32(buf + 4); + unit_type = buf[8]; + png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type); +} +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED +/* Read the pCAL chunk (described in the PNG Extensions document) */ +void /* PRIVATE */ +png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_int_32 X0, X1; + png_byte type, nparams; + png_bytep buffer, buf, units, endptr; + png_charpp params; + int i; + + png_debug(1, "in png_handle_pCAL"); + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)", + length + 1); + + buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); + + if (buffer == NULL) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); + return; + } + + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, 0) != 0) + return; + + buffer[length] = 0; /* Null terminate the last string */ + + png_debug(3, "Finding end of pCAL purpose string"); + for (buf = buffer; *buf; buf++) + /* Empty loop */ ; + + endptr = buffer + length; + + /* We need to have at least 12 bytes after the purpose string + * in order to get the parameter information. + */ + if (endptr - buf <= 12) + { + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_debug(3, "Reading pCAL X0, X1, type, nparams, and units"); + X0 = png_get_int_32((png_bytep)buf+1); + X1 = png_get_int_32((png_bytep)buf+5); + type = buf[9]; + nparams = buf[10]; + units = buf + 11; + + png_debug(3, "Checking pCAL equation type and number of parameters"); + /* Check that we have the right number of parameters for known + * equation types. + */ + if ((type == PNG_EQUATION_LINEAR && nparams != 2) || + (type == PNG_EQUATION_BASE_E && nparams != 3) || + (type == PNG_EQUATION_ARBITRARY && nparams != 3) || + (type == PNG_EQUATION_HYPERBOLIC && nparams != 4)) + { + png_chunk_benign_error(png_ptr, "invalid parameter count"); + return; + } + + else if (type >= PNG_EQUATION_LAST) + { + png_chunk_benign_error(png_ptr, "unrecognized equation type"); + } + + for (buf = units; *buf; buf++) + /* Empty loop to move past the units string. */ ; + + png_debug(3, "Allocating pCAL parameters array"); + + params = png_voidcast(png_charpp, png_malloc_warn(png_ptr, + nparams * (sizeof (png_charp)))); + + if (params == NULL) + { + png_chunk_benign_error(png_ptr, "out of memory"); + return; + } + + /* Get pointers to the start of each parameter string. */ + for (i = 0; i < nparams; i++) + { + buf++; /* Skip the null string terminator from previous parameter. */ + + png_debug1(3, "Reading pCAL parameter %d", i); + + for (params[i] = (png_charp)buf; buf <= endptr && *buf != 0; buf++) + /* Empty loop to move past each parameter string */ ; + + /* Make sure we haven't run out of data yet */ + if (buf > endptr) + { + png_free(png_ptr, params); + png_chunk_benign_error(png_ptr, "invalid data"); + return; + } + } + + png_set_pCAL(png_ptr, info_ptr, (png_charp)buffer, X0, X1, type, nparams, + (png_charp)units, params); + + png_free(png_ptr, params); +} +#endif + +#ifdef PNG_READ_sCAL_SUPPORTED +/* Read the sCAL chunk */ +void /* PRIVATE */ +png_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_bytep buffer; + png_size_t i; + int state; + + png_debug(1, "in png_handle_sCAL"); + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + /* Need unit type, width, \0, height: minimum 4 bytes */ + else if (length < 4) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)", + length + 1); + + buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); + + if (buffer == NULL) + { + png_chunk_benign_error(png_ptr, "out of memory"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buffer, length); + buffer[length] = 0; /* Null terminate the last string */ + + if (png_crc_finish(png_ptr, 0) != 0) + return; + + /* Validate the unit. */ + if (buffer[0] != 1 && buffer[0] != 2) + { + png_chunk_benign_error(png_ptr, "invalid unit"); + return; + } + + /* Validate the ASCII numbers, need two ASCII numbers separated by + * a '\0' and they need to fit exactly in the chunk data. + */ + i = 1; + state = 0; + + if (png_check_fp_number((png_const_charp)buffer, length, &state, &i) == 0 || + i >= length || buffer[i++] != 0) + png_chunk_benign_error(png_ptr, "bad width format"); + + else if (PNG_FP_IS_POSITIVE(state) == 0) + png_chunk_benign_error(png_ptr, "non-positive width"); + + else + { + png_size_t heighti = i; + + state = 0; + if (png_check_fp_number((png_const_charp)buffer, length, + &state, &i) == 0 || i != length) + png_chunk_benign_error(png_ptr, "bad height format"); + + else if (PNG_FP_IS_POSITIVE(state) == 0) + png_chunk_benign_error(png_ptr, "non-positive height"); + + else + /* This is the (only) success case. */ + png_set_sCAL_s(png_ptr, info_ptr, buffer[0], + (png_charp)buffer+1, (png_charp)buffer+heighti); + } +} +#endif + +#ifdef PNG_READ_tIME_SUPPORTED +void /* PRIVATE */ +png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_byte buf[7]; + png_time mod_time; + + png_debug(1, "in png_handle_tIME"); + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) != 0) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + png_ptr->mode |= PNG_AFTER_IDAT; + + if (length != 7) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, buf, 7); + + if (png_crc_finish(png_ptr, 0) != 0) + return; + + mod_time.second = buf[6]; + mod_time.minute = buf[5]; + mod_time.hour = buf[4]; + mod_time.day = buf[3]; + mod_time.month = buf[2]; + mod_time.year = png_get_uint_16(buf); + + png_set_tIME(png_ptr, info_ptr, &mod_time); +} +#endif + +#ifdef PNG_READ_tEXt_SUPPORTED +/* Note: this does not properly handle chunks that are > 64K under DOS */ +void /* PRIVATE */ +png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_text text_info; + png_bytep buffer; + png_charp key; + png_charp text; + png_uint_32 skip = 0; + + png_debug(1, "in png_handle_tEXt"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + + if (--png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "no space in chunk cache"); + return; + } + } +#endif + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + png_ptr->mode |= PNG_AFTER_IDAT; + +#ifdef PNG_MAX_MALLOC_64K + if (length > 65535U) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "too large to fit in memory"); + return; + } +#endif + + buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/); + + if (buffer == NULL) + { + png_chunk_benign_error(png_ptr, "out of memory"); + return; + } + + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, skip) != 0) + return; + + key = (png_charp)buffer; + key[length] = 0; + + for (text = key; *text; text++) + /* Empty loop to find end of key */ ; + + if (text != key + length) + text++; + + text_info.compression = PNG_TEXT_COMPRESSION_NONE; + text_info.key = key; + text_info.lang = NULL; + text_info.lang_key = NULL; + text_info.itxt_length = 0; + text_info.text = text; + text_info.text_length = strlen(text); + + if (png_set_text_2(png_ptr, info_ptr, &text_info, 1) != 0) + png_warning(png_ptr, "Insufficient memory to process text chunk"); +} +#endif + +#ifdef PNG_READ_zTXt_SUPPORTED +/* Note: this does not correctly handle chunks that are > 64K under DOS */ +void /* PRIVATE */ +png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_const_charp errmsg = NULL; + png_bytep buffer; + png_uint_32 keyword_length; + + png_debug(1, "in png_handle_zTXt"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + + if (--png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "no space in chunk cache"); + return; + } + } +#endif + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + png_ptr->mode |= PNG_AFTER_IDAT; + + buffer = png_read_buffer(png_ptr, length, 2/*silent*/); + + if (buffer == NULL) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); + return; + } + + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, 0) != 0) + return; + + /* TODO: also check that the keyword contents match the spec! */ + for (keyword_length = 0; + keyword_length < length && buffer[keyword_length] != 0; + ++keyword_length) + /* Empty loop to find end of name */ ; + + if (keyword_length > 79 || keyword_length < 1) + errmsg = "bad keyword"; + + /* zTXt must have some LZ data after the keyword, although it may expand to + * zero bytes; we need a '\0' at the end of the keyword, the compression type + * then the LZ data: + */ + else if (keyword_length + 3 > length) + errmsg = "truncated"; + + else if (buffer[keyword_length+1] != PNG_COMPRESSION_TYPE_BASE) + errmsg = "unknown compression type"; + + else + { + png_alloc_size_t uncompressed_length = PNG_SIZE_MAX; + + /* TODO: at present png_decompress_chunk imposes a single application + * level memory limit, this should be split to different values for iCCP + * and text chunks. + */ + if (png_decompress_chunk(png_ptr, length, keyword_length+2, + &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) + { + png_text text; + + /* It worked; png_ptr->read_buffer now looks like a tEXt chunk except + * for the extra compression type byte and the fact that it isn't + * necessarily '\0' terminated. + */ + buffer = png_ptr->read_buffer; + buffer[uncompressed_length+(keyword_length+2)] = 0; + + text.compression = PNG_TEXT_COMPRESSION_zTXt; + text.key = (png_charp)buffer; + text.text = (png_charp)(buffer + keyword_length+2); + text.text_length = uncompressed_length; + text.itxt_length = 0; + text.lang = NULL; + text.lang_key = NULL; + + if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0) + errmsg = "insufficient memory"; + } + + else + errmsg = png_ptr->zstream.msg; + } + + if (errmsg != NULL) + png_chunk_benign_error(png_ptr, errmsg); +} +#endif + +#ifdef PNG_READ_iTXt_SUPPORTED +/* Note: this does not correctly handle chunks that are > 64K under DOS */ +void /* PRIVATE */ +png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +{ + png_const_charp errmsg = NULL; + png_bytep buffer; + png_uint_32 prefix_length; + + png_debug(1, "in png_handle_iTXt"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + + if (--png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "no space in chunk cache"); + return; + } + } +#endif + + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + png_ptr->mode |= PNG_AFTER_IDAT; + + buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/); + + if (buffer == NULL) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); + return; + } + + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, 0) != 0) + return; + + /* First the keyword. */ + for (prefix_length=0; + prefix_length < length && buffer[prefix_length] != 0; + ++prefix_length) + /* Empty loop */ ; + + /* Perform a basic check on the keyword length here. */ + if (prefix_length > 79 || prefix_length < 1) + errmsg = "bad keyword"; + + /* Expect keyword, compression flag, compression type, language, translated + * keyword (both may be empty but are 0 terminated) then the text, which may + * be empty. + */ + else if (prefix_length + 5 > length) + errmsg = "truncated"; + + else if (buffer[prefix_length+1] == 0 || + (buffer[prefix_length+1] == 1 && + buffer[prefix_length+2] == PNG_COMPRESSION_TYPE_BASE)) + { + int compressed = buffer[prefix_length+1] != 0; + png_uint_32 language_offset, translated_keyword_offset; + png_alloc_size_t uncompressed_length = 0; + + /* Now the language tag */ + prefix_length += 3; + language_offset = prefix_length; + + for (; prefix_length < length && buffer[prefix_length] != 0; + ++prefix_length) + /* Empty loop */ ; + + /* WARNING: the length may be invalid here, this is checked below. */ + translated_keyword_offset = ++prefix_length; + + for (; prefix_length < length && buffer[prefix_length] != 0; + ++prefix_length) + /* Empty loop */ ; + + /* prefix_length should now be at the trailing '\0' of the translated + * keyword, but it may already be over the end. None of this arithmetic + * can overflow because chunks are at most 2^31 bytes long, but on 16-bit + * systems the available allocation may overflow. + */ + ++prefix_length; + + if (compressed == 0 && prefix_length <= length) + uncompressed_length = length - prefix_length; + + else if (compressed != 0 && prefix_length < length) + { + uncompressed_length = PNG_SIZE_MAX; + + /* TODO: at present png_decompress_chunk imposes a single application + * level memory limit, this should be split to different values for + * iCCP and text chunks. + */ + if (png_decompress_chunk(png_ptr, length, prefix_length, + &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) + buffer = png_ptr->read_buffer; + + else + errmsg = png_ptr->zstream.msg; + } + + else + errmsg = "truncated"; + + if (errmsg == NULL) + { + png_text text; + + buffer[uncompressed_length+prefix_length] = 0; + + if (compressed == 0) + text.compression = PNG_ITXT_COMPRESSION_NONE; + + else + text.compression = PNG_ITXT_COMPRESSION_zTXt; + + text.key = (png_charp)buffer; + text.lang = (png_charp)buffer + language_offset; + text.lang_key = (png_charp)buffer + translated_keyword_offset; + text.text = (png_charp)buffer + prefix_length; + text.text_length = 0; + text.itxt_length = uncompressed_length; + + if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0) + errmsg = "insufficient memory"; + } + } + + else + errmsg = "bad compression info"; + + if (errmsg != NULL) + png_chunk_benign_error(png_ptr, errmsg); +} +#endif + +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +/* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */ +static int +png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length) +{ + png_alloc_size_t limit = PNG_SIZE_MAX; + + if (png_ptr->unknown_chunk.data != NULL) + { + png_free(png_ptr, png_ptr->unknown_chunk.data); + png_ptr->unknown_chunk.data = NULL; + } + +# ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_malloc_max > 0 && + png_ptr->user_chunk_malloc_max < limit) + limit = png_ptr->user_chunk_malloc_max; + +# elif PNG_USER_CHUNK_MALLOC_MAX > 0 + if (PNG_USER_CHUNK_MALLOC_MAX < limit) + limit = PNG_USER_CHUNK_MALLOC_MAX; +# endif + + if (length <= limit) + { + PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name); + /* The following is safe because of the PNG_SIZE_MAX init above */ + png_ptr->unknown_chunk.size = (png_size_t)length/*SAFE*/; + /* 'mode' is a flag array, only the bottom four bits matter here */ + png_ptr->unknown_chunk.location = (png_byte)png_ptr->mode/*SAFE*/; + + if (length == 0) + png_ptr->unknown_chunk.data = NULL; + + else + { + /* Do a 'warn' here - it is handled below. */ + png_ptr->unknown_chunk.data = png_voidcast(png_bytep, + png_malloc_warn(png_ptr, length)); + } + } + + if (png_ptr->unknown_chunk.data == NULL && length > 0) + { + /* This is benign because we clean up correctly */ + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "unknown chunk exceeds memory limits"); + return 0; + } + + else + { + if (length > 0) + png_crc_read(png_ptr, png_ptr->unknown_chunk.data, length); + png_crc_finish(png_ptr, 0); + return 1; + } +} +#endif /* READ_UNKNOWN_CHUNKS */ + +/* Handle an unknown, or known but disabled, chunk */ +void /* PRIVATE */ +png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr, + png_uint_32 length, int keep) +{ + int handled = 0; /* the chunk was handled */ + + png_debug(1, "in png_handle_unknown"); + +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + /* NOTE: this code is based on the code in libpng-1.4.12 except for fixing + * the bug which meant that setting a non-default behavior for a specific + * chunk would be ignored (the default was always used unless a user + * callback was installed). + * + * 'keep' is the value from the png_chunk_unknown_handling, the setting for + * this specific chunk_name, if PNG_HANDLE_AS_UNKNOWN_SUPPORTED, if not it + * will always be PNG_HANDLE_CHUNK_AS_DEFAULT and it needs to be set here. + * This is just an optimization to avoid multiple calls to the lookup + * function. + */ +# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + keep = png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name); +# endif +# endif + + /* One of the following methods will read the chunk or skip it (at least one + * of these is always defined because this is the only way to switch on + * PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + */ +# ifdef PNG_READ_USER_CHUNKS_SUPPORTED + /* The user callback takes precedence over the chunk keep value, but the + * keep value is still required to validate a save of a critical chunk. + */ + if (png_ptr->read_user_chunk_fn != NULL) + { + if (png_cache_unknown_chunk(png_ptr, length) != 0) + { + /* Callback to user unknown chunk handler */ + int ret = (*(png_ptr->read_user_chunk_fn))(png_ptr, + &png_ptr->unknown_chunk); + + /* ret is: + * negative: An error occurred; png_chunk_error will be called. + * zero: The chunk was not handled, the chunk will be discarded + * unless png_set_keep_unknown_chunks has been used to set + * a 'keep' behavior for this particular chunk, in which + * case that will be used. A critical chunk will cause an + * error at this point unless it is to be saved. + * positive: The chunk was handled, libpng will ignore/discard it. + */ + if (ret < 0) + png_chunk_error(png_ptr, "error in user chunk"); + + else if (ret == 0) + { + /* If the keep value is 'default' or 'never' override it, but + * still error out on critical chunks unless the keep value is + * 'always' While this is weird it is the behavior in 1.4.12. + * A possible improvement would be to obey the value set for the + * chunk, but this would be an API change that would probably + * damage some applications. + * + * The png_app_warning below catches the case that matters, where + * the application has not set specific save or ignore for this + * chunk or global save or ignore. + */ + if (keep < PNG_HANDLE_CHUNK_IF_SAFE) + { +# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + if (png_ptr->unknown_default < PNG_HANDLE_CHUNK_IF_SAFE) + { + png_chunk_warning(png_ptr, "Saving unknown chunk:"); + png_app_warning(png_ptr, + "forcing save of an unhandled chunk;" + " please call png_set_keep_unknown_chunks"); + /* with keep = PNG_HANDLE_CHUNK_IF_SAFE */ + } +# endif + keep = PNG_HANDLE_CHUNK_IF_SAFE; + } + } + + else /* chunk was handled */ + { + handled = 1; + /* Critical chunks can be safely discarded at this point. */ + keep = PNG_HANDLE_CHUNK_NEVER; + } + } + + else + keep = PNG_HANDLE_CHUNK_NEVER; /* insufficient memory */ + } + + else + /* Use the SAVE_UNKNOWN_CHUNKS code or skip the chunk */ +# endif /* READ_USER_CHUNKS */ + +# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED + { + /* keep is currently just the per-chunk setting, if there was no + * setting change it to the global default now (not that this may + * still be AS_DEFAULT) then obtain the cache of the chunk if required, + * if not simply skip the chunk. + */ + if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT) + keep = png_ptr->unknown_default; + + if (keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_IF_SAFE && + PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))) + { + if (png_cache_unknown_chunk(png_ptr, length) == 0) + keep = PNG_HANDLE_CHUNK_NEVER; + } + + else + png_crc_finish(png_ptr, length); + } +# else +# ifndef PNG_READ_USER_CHUNKS_SUPPORTED +# error no method to support READ_UNKNOWN_CHUNKS +# endif + + { + /* If here there is no read callback pointer set and no support is + * compiled in to just save the unknown chunks, so simply skip this + * chunk. If 'keep' is something other than AS_DEFAULT or NEVER then + * the app has erroneously asked for unknown chunk saving when there + * is no support. + */ + if (keep > PNG_HANDLE_CHUNK_NEVER) + png_app_error(png_ptr, "no unknown chunk support available"); + + png_crc_finish(png_ptr, length); + } +# endif + +# ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED + /* Now store the chunk in the chunk list if appropriate, and if the limits + * permit it. + */ + if (keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_IF_SAFE && + PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))) + { +# ifdef PNG_USER_LIMITS_SUPPORTED + switch (png_ptr->user_chunk_cache_max) + { + case 2: + png_ptr->user_chunk_cache_max = 1; + png_chunk_benign_error(png_ptr, "no space in chunk cache"); + /* FALL THROUGH */ + case 1: + /* NOTE: prior to 1.6.0 this case resulted in an unknown critical + * chunk being skipped, now there will be a hard error below. + */ + break; + + default: /* not at limit */ + --(png_ptr->user_chunk_cache_max); + /* FALL THROUGH */ + case 0: /* no limit */ +# endif /* USER_LIMITS */ + /* Here when the limit isn't reached or when limits are compiled + * out; store the chunk. + */ + png_set_unknown_chunks(png_ptr, info_ptr, + &png_ptr->unknown_chunk, 1); + handled = 1; +# ifdef PNG_USER_LIMITS_SUPPORTED + break; + } +# endif + } +# else /* no store support: the chunk must be handled by the user callback */ + PNG_UNUSED(info_ptr) +# endif + + /* Regardless of the error handling below the cached data (if any) can be + * freed now. Notice that the data is not freed if there is a png_error, but + * it will be freed by destroy_read_struct. + */ + if (png_ptr->unknown_chunk.data != NULL) + png_free(png_ptr, png_ptr->unknown_chunk.data); + png_ptr->unknown_chunk.data = NULL; + +#else /* !PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ + /* There is no support to read an unknown chunk, so just skip it. */ + png_crc_finish(png_ptr, length); + PNG_UNUSED(info_ptr) + PNG_UNUSED(keep) +#endif /* !READ_UNKNOWN_CHUNKS */ + + /* Check for unhandled critical chunks */ + if (handled == 0 && PNG_CHUNK_CRITICAL(png_ptr->chunk_name)) + png_chunk_error(png_ptr, "unhandled critical chunk"); +} + +/* This function is called to verify that a chunk name is valid. + * This function can't have the "critical chunk check" incorporated + * into it, since in the future we will need to be able to call user + * functions to handle unknown critical chunks after we check that + * the chunk name itself is valid. + */ + +/* Bit hacking: the test for an invalid byte in the 4 byte chunk name is: + * + * ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) + */ + +void /* PRIVATE */ +png_check_chunk_name(png_structrp png_ptr, png_uint_32 chunk_name) +{ + int i; + + png_debug(1, "in png_check_chunk_name"); + + for (i=1; i<=4; ++i) + { + int c = chunk_name & 0xff; + + if (c < 65 || c > 122 || (c > 90 && c < 97)) + png_chunk_error(png_ptr, "invalid chunk type"); + + chunk_name >>= 8; + } +} + +/* Combines the row recently read in with the existing pixels in the row. This + * routine takes care of alpha and transparency if requested. This routine also + * handles the two methods of progressive display of interlaced images, + * depending on the 'display' value; if 'display' is true then the whole row + * (dp) is filled from the start by replicating the available pixels. If + * 'display' is false only those pixels present in the pass are filled in. + */ +void /* PRIVATE */ +png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) +{ + unsigned int pixel_depth = png_ptr->transformed_pixel_depth; + png_const_bytep sp = png_ptr->row_buf + 1; + png_alloc_size_t row_width = png_ptr->width; + unsigned int pass = png_ptr->pass; + png_bytep end_ptr = 0; + png_byte end_byte = 0; + unsigned int end_mask; + + png_debug(1, "in png_combine_row"); + + /* Added in 1.5.6: it should not be possible to enter this routine until at + * least one row has been read from the PNG data and transformed. + */ + if (pixel_depth == 0) + png_error(png_ptr, "internal row logic error"); + + /* Added in 1.5.4: the pixel depth should match the information returned by + * any call to png_read_update_info at this point. Do not continue if we got + * this wrong. + */ + if (png_ptr->info_rowbytes != 0 && png_ptr->info_rowbytes != + PNG_ROWBYTES(pixel_depth, row_width)) + png_error(png_ptr, "internal row size calculation error"); + + /* Don't expect this to ever happen: */ + if (row_width == 0) + png_error(png_ptr, "internal row width error"); + + /* Preserve the last byte in cases where only part of it will be overwritten, + * the multiply below may overflow, we don't care because ANSI-C guarantees + * we get the low bits. + */ + end_mask = (pixel_depth * row_width) & 7; + if (end_mask != 0) + { + /* end_ptr == NULL is a flag to say do nothing */ + end_ptr = dp + PNG_ROWBYTES(pixel_depth, row_width) - 1; + end_byte = *end_ptr; +# ifdef PNG_READ_PACKSWAP_SUPPORTED + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + /* little-endian byte */ + end_mask = 0xff << end_mask; + + else /* big-endian byte */ +# endif + end_mask = 0xff >> end_mask; + /* end_mask is now the bits to *keep* from the destination row */ + } + + /* For non-interlaced images this reduces to a memcpy(). A memcpy() + * will also happen if interlacing isn't supported or if the application + * does not call png_set_interlace_handling(). In the latter cases the + * caller just gets a sequence of the unexpanded rows from each interlace + * pass. + */ +#ifdef PNG_READ_INTERLACING_SUPPORTED + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0 && + pass < 6 && (display == 0 || + /* The following copies everything for 'display' on passes 0, 2 and 4. */ + (display == 1 && (pass & 1) != 0))) + { + /* Narrow images may have no bits in a pass; the caller should handle + * this, but this test is cheap: + */ + if (row_width <= PNG_PASS_START_COL(pass)) + return; + + if (pixel_depth < 8) + { + /* For pixel depths up to 4 bpp the 8-pixel mask can be expanded to fit + * into 32 bits, then a single loop over the bytes using the four byte + * values in the 32-bit mask can be used. For the 'display' option the + * expanded mask may also not require any masking within a byte. To + * make this work the PACKSWAP option must be taken into account - it + * simply requires the pixels to be reversed in each byte. + * + * The 'regular' case requires a mask for each of the first 6 passes, + * the 'display' case does a copy for the even passes in the range + * 0..6. This has already been handled in the test above. + * + * The masks are arranged as four bytes with the first byte to use in + * the lowest bits (little-endian) regardless of the order (PACKSWAP or + * not) of the pixels in each byte. + * + * NOTE: the whole of this logic depends on the caller of this function + * only calling it on rows appropriate to the pass. This function only + * understands the 'x' logic; the 'y' logic is handled by the caller. + * + * The following defines allow generation of compile time constant bit + * masks for each pixel depth and each possibility of swapped or not + * swapped bytes. Pass 'p' is in the range 0..6; 'x', a pixel index, + * is in the range 0..7; and the result is 1 if the pixel is to be + * copied in the pass, 0 if not. 'S' is for the sparkle method, 'B' + * for the block method. + * + * With some compilers a compile time expression of the general form: + * + * (shift >= 32) ? (a >> (shift-32)) : (b >> shift) + * + * Produces warnings with values of 'shift' in the range 33 to 63 + * because the right hand side of the ?: expression is evaluated by + * the compiler even though it isn't used. Microsoft Visual C (various + * versions) and the Intel C compiler are known to do this. To avoid + * this the following macros are used in 1.5.6. This is a temporary + * solution to avoid destabilizing the code during the release process. + */ +# if PNG_USE_COMPILE_TIME_MASKS +# define PNG_LSR(x,s) ((x)>>((s) & 0x1f)) +# define PNG_LSL(x,s) ((x)<<((s) & 0x1f)) +# else +# define PNG_LSR(x,s) ((x)>>(s)) +# define PNG_LSL(x,s) ((x)<<(s)) +# endif +# define S_COPY(p,x) (((p)<4 ? PNG_LSR(0x80088822,(3-(p))*8+(7-(x))) :\ + PNG_LSR(0xaa55ff00,(7-(p))*8+(7-(x)))) & 1) +# define B_COPY(p,x) (((p)<4 ? PNG_LSR(0xff0fff33,(3-(p))*8+(7-(x))) :\ + PNG_LSR(0xff55ff00,(7-(p))*8+(7-(x)))) & 1) + + /* Return a mask for pass 'p' pixel 'x' at depth 'd'. The mask is + * little endian - the first pixel is at bit 0 - however the extra + * parameter 's' can be set to cause the mask position to be swapped + * within each byte, to match the PNG format. This is done by XOR of + * the shift with 7, 6 or 4 for bit depths 1, 2 and 4. + */ +# define PIXEL_MASK(p,x,d,s) \ + (PNG_LSL(((PNG_LSL(1U,(d)))-1),(((x)*(d))^((s)?8-(d):0)))) + + /* Hence generate the appropriate 'block' or 'sparkle' pixel copy mask. + */ +# define S_MASKx(p,x,d,s) (S_COPY(p,x)?PIXEL_MASK(p,x,d,s):0) +# define B_MASKx(p,x,d,s) (B_COPY(p,x)?PIXEL_MASK(p,x,d,s):0) + + /* Combine 8 of these to get the full mask. For the 1-bpp and 2-bpp + * cases the result needs replicating, for the 4-bpp case the above + * generates a full 32 bits. + */ +# define MASK_EXPAND(m,d) ((m)*((d)==1?0x01010101:((d)==2?0x00010001:1))) + +# define S_MASK(p,d,s) MASK_EXPAND(S_MASKx(p,0,d,s) + S_MASKx(p,1,d,s) +\ + S_MASKx(p,2,d,s) + S_MASKx(p,3,d,s) + S_MASKx(p,4,d,s) +\ + S_MASKx(p,5,d,s) + S_MASKx(p,6,d,s) + S_MASKx(p,7,d,s), d) + +# define B_MASK(p,d,s) MASK_EXPAND(B_MASKx(p,0,d,s) + B_MASKx(p,1,d,s) +\ + B_MASKx(p,2,d,s) + B_MASKx(p,3,d,s) + B_MASKx(p,4,d,s) +\ + B_MASKx(p,5,d,s) + B_MASKx(p,6,d,s) + B_MASKx(p,7,d,s), d) + +#if PNG_USE_COMPILE_TIME_MASKS + /* Utility macros to construct all the masks for a depth/swap + * combination. The 's' parameter says whether the format is PNG + * (big endian bytes) or not. Only the three odd-numbered passes are + * required for the display/block algorithm. + */ +# define S_MASKS(d,s) { S_MASK(0,d,s), S_MASK(1,d,s), S_MASK(2,d,s),\ + S_MASK(3,d,s), S_MASK(4,d,s), S_MASK(5,d,s) } + +# define B_MASKS(d,s) { B_MASK(1,d,s), B_MASK(3,d,s), B_MASK(5,d,s) } + +# define DEPTH_INDEX(d) ((d)==1?0:((d)==2?1:2)) + + /* Hence the pre-compiled masks indexed by PACKSWAP (or not), depth and + * then pass: + */ + static PNG_CONST png_uint_32 row_mask[2/*PACKSWAP*/][3/*depth*/][6] = + { + /* Little-endian byte masks for PACKSWAP */ + { S_MASKS(1,0), S_MASKS(2,0), S_MASKS(4,0) }, + /* Normal (big-endian byte) masks - PNG format */ + { S_MASKS(1,1), S_MASKS(2,1), S_MASKS(4,1) } + }; + + /* display_mask has only three entries for the odd passes, so index by + * pass>>1. + */ + static PNG_CONST png_uint_32 display_mask[2][3][3] = + { + /* Little-endian byte masks for PACKSWAP */ + { B_MASKS(1,0), B_MASKS(2,0), B_MASKS(4,0) }, + /* Normal (big-endian byte) masks - PNG format */ + { B_MASKS(1,1), B_MASKS(2,1), B_MASKS(4,1) } + }; + +# define MASK(pass,depth,display,png)\ + ((display)?display_mask[png][DEPTH_INDEX(depth)][pass>>1]:\ + row_mask[png][DEPTH_INDEX(depth)][pass]) + +#else /* !PNG_USE_COMPILE_TIME_MASKS */ + /* This is the runtime alternative: it seems unlikely that this will + * ever be either smaller or faster than the compile time approach. + */ +# define MASK(pass,depth,display,png)\ + ((display)?B_MASK(pass,depth,png):S_MASK(pass,depth,png)) +#endif /* !USE_COMPILE_TIME_MASKS */ + + /* Use the appropriate mask to copy the required bits. In some cases + * the byte mask will be 0 or 0xff; optimize these cases. row_width is + * the number of pixels, but the code copies bytes, so it is necessary + * to special case the end. + */ + png_uint_32 pixels_per_byte = 8 / pixel_depth; + png_uint_32 mask; + +# ifdef PNG_READ_PACKSWAP_SUPPORTED + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + mask = MASK(pass, pixel_depth, display, 0); + + else +# endif + mask = MASK(pass, pixel_depth, display, 1); + + for (;;) + { + png_uint_32 m; + + /* It doesn't matter in the following if png_uint_32 has more than + * 32 bits because the high bits always match those in m<<24; it is, + * however, essential to use OR here, not +, because of this. + */ + m = mask; + mask = (m >> 8) | (m << 24); /* rotate right to good compilers */ + m &= 0xff; + + if (m != 0) /* something to copy */ + { + if (m != 0xff) + *dp = (png_byte)((*dp & ~m) | (*sp & m)); + else + *dp = *sp; + } + + /* NOTE: this may overwrite the last byte with garbage if the image + * is not an exact number of bytes wide; libpng has always done + * this. + */ + if (row_width <= pixels_per_byte) + break; /* May need to restore part of the last byte */ + + row_width -= pixels_per_byte; + ++dp; + ++sp; + } + } + + else /* pixel_depth >= 8 */ + { + unsigned int bytes_to_copy, bytes_to_jump; + + /* Validate the depth - it must be a multiple of 8 */ + if (pixel_depth & 7) + png_error(png_ptr, "invalid user transform pixel depth"); + + pixel_depth >>= 3; /* now in bytes */ + row_width *= pixel_depth; + + /* Regardless of pass number the Adam 7 interlace always results in a + * fixed number of pixels to copy then to skip. There may be a + * different number of pixels to skip at the start though. + */ + { + unsigned int offset = PNG_PASS_START_COL(pass) * pixel_depth; + + row_width -= offset; + dp += offset; + sp += offset; + } + + /* Work out the bytes to copy. */ + if (display != 0) + { + /* When doing the 'block' algorithm the pixel in the pass gets + * replicated to adjacent pixels. This is why the even (0,2,4,6) + * passes are skipped above - the entire expanded row is copied. + */ + bytes_to_copy = (1<<((6-pass)>>1)) * pixel_depth; + + /* But don't allow this number to exceed the actual row width. */ + if (bytes_to_copy > row_width) + bytes_to_copy = (unsigned int)/*SAFE*/row_width; + } + + else /* normal row; Adam7 only ever gives us one pixel to copy. */ + bytes_to_copy = pixel_depth; + + /* In Adam7 there is a constant offset between where the pixels go. */ + bytes_to_jump = PNG_PASS_COL_OFFSET(pass) * pixel_depth; + + /* And simply copy these bytes. Some optimization is possible here, + * depending on the value of 'bytes_to_copy'. Special case the low + * byte counts, which we know to be frequent. + * + * Notice that these cases all 'return' rather than 'break' - this + * avoids an unnecessary test on whether to restore the last byte + * below. + */ + switch (bytes_to_copy) + { + case 1: + for (;;) + { + *dp = *sp; + + if (row_width <= bytes_to_jump) + return; + + dp += bytes_to_jump; + sp += bytes_to_jump; + row_width -= bytes_to_jump; + } + + case 2: + /* There is a possibility of a partial copy at the end here; this + * slows the code down somewhat. + */ + do + { + dp[0] = sp[0], dp[1] = sp[1]; + + if (row_width <= bytes_to_jump) + return; + + sp += bytes_to_jump; + dp += bytes_to_jump; + row_width -= bytes_to_jump; + } + while (row_width > 1); + + /* And there can only be one byte left at this point: */ + *dp = *sp; + return; + + case 3: + /* This can only be the RGB case, so each copy is exactly one + * pixel and it is not necessary to check for a partial copy. + */ + for (;;) + { + dp[0] = sp[0], dp[1] = sp[1], dp[2] = sp[2]; + + if (row_width <= bytes_to_jump) + return; + + sp += bytes_to_jump; + dp += bytes_to_jump; + row_width -= bytes_to_jump; + } + + default: +#if PNG_ALIGN_TYPE != PNG_ALIGN_NONE + /* Check for double byte alignment and, if possible, use a + * 16-bit copy. Don't attempt this for narrow images - ones that + * are less than an interlace panel wide. Don't attempt it for + * wide bytes_to_copy either - use the memcpy there. + */ + if (bytes_to_copy < 16 /*else use memcpy*/ && + png_isaligned(dp, png_uint_16) && + png_isaligned(sp, png_uint_16) && + bytes_to_copy % (sizeof (png_uint_16)) == 0 && + bytes_to_jump % (sizeof (png_uint_16)) == 0) + { + /* Everything is aligned for png_uint_16 copies, but try for + * png_uint_32 first. + */ + if (png_isaligned(dp, png_uint_32) != 0 && + png_isaligned(sp, png_uint_32) != 0 && + bytes_to_copy % (sizeof (png_uint_32)) == 0 && + bytes_to_jump % (sizeof (png_uint_32)) == 0) + { + png_uint_32p dp32 = png_aligncast(png_uint_32p,dp); + png_const_uint_32p sp32 = png_aligncastconst( + png_const_uint_32p, sp); + size_t skip = (bytes_to_jump-bytes_to_copy) / + (sizeof (png_uint_32)); + + do + { + size_t c = bytes_to_copy; + do + { + *dp32++ = *sp32++; + c -= (sizeof (png_uint_32)); + } + while (c > 0); + + if (row_width <= bytes_to_jump) + return; + + dp32 += skip; + sp32 += skip; + row_width -= bytes_to_jump; + } + while (bytes_to_copy <= row_width); + + /* Get to here when the row_width truncates the final copy. + * There will be 1-3 bytes left to copy, so don't try the + * 16-bit loop below. + */ + dp = (png_bytep)dp32; + sp = (png_const_bytep)sp32; + do + *dp++ = *sp++; + while (--row_width > 0); + return; + } + + /* Else do it in 16-bit quantities, but only if the size is + * not too large. + */ + else + { + png_uint_16p dp16 = png_aligncast(png_uint_16p, dp); + png_const_uint_16p sp16 = png_aligncastconst( + png_const_uint_16p, sp); + size_t skip = (bytes_to_jump-bytes_to_copy) / + (sizeof (png_uint_16)); + + do + { + size_t c = bytes_to_copy; + do + { + *dp16++ = *sp16++; + c -= (sizeof (png_uint_16)); + } + while (c > 0); + + if (row_width <= bytes_to_jump) + return; + + dp16 += skip; + sp16 += skip; + row_width -= bytes_to_jump; + } + while (bytes_to_copy <= row_width); + + /* End of row - 1 byte left, bytes_to_copy > row_width: */ + dp = (png_bytep)dp16; + sp = (png_const_bytep)sp16; + do + *dp++ = *sp++; + while (--row_width > 0); + return; + } + } +#endif /* ALIGN_TYPE code */ + + /* The true default - use a memcpy: */ + for (;;) + { + memcpy(dp, sp, bytes_to_copy); + + if (row_width <= bytes_to_jump) + return; + + sp += bytes_to_jump; + dp += bytes_to_jump; + row_width -= bytes_to_jump; + if (bytes_to_copy > row_width) + bytes_to_copy = (unsigned int)/*SAFE*/row_width; + } + } + + /* NOT REACHED*/ + } /* pixel_depth >= 8 */ + + /* Here if pixel_depth < 8 to check 'end_ptr' below. */ + } + else +#endif /* READ_INTERLACING */ + + /* If here then the switch above wasn't used so just memcpy the whole row + * from the temporary row buffer (notice that this overwrites the end of the + * destination row if it is a partial byte.) + */ + memcpy(dp, sp, PNG_ROWBYTES(pixel_depth, row_width)); + + /* Restore the overwritten bits from the last byte if necessary. */ + if (end_ptr != NULL) + *end_ptr = (png_byte)((end_byte & end_mask) | (*end_ptr & ~end_mask)); +} + +#ifdef PNG_READ_INTERLACING_SUPPORTED +void /* PRIVATE */ +png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, + png_uint_32 transformations /* Because these may affect the byte layout */) +{ + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + /* Offset to next interlace block */ + static PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + png_debug(1, "in png_do_read_interlace"); + if (row != NULL && row_info != NULL) + { + png_uint_32 final_width; + + final_width = row_info->width * png_pass_inc[pass]; + + switch (row_info->pixel_depth) + { + case 1: + { + png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3); + png_bytep dp = row + (png_size_t)((final_width - 1) >> 3); + int sshift, dshift; + int s_start, s_end, s_inc; + int jstop = png_pass_inc[pass]; + png_byte v; + png_uint_32 i; + int j; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if ((transformations & PNG_PACKSWAP) != 0) + { + sshift = (int)((row_info->width + 7) & 0x07); + dshift = (int)((final_width + 7) & 0x07); + s_start = 7; + s_end = 0; + s_inc = -1; + } + + else +#endif + { + sshift = 7 - (int)((row_info->width + 7) & 0x07); + dshift = 7 - (int)((final_width + 7) & 0x07); + s_start = 0; + s_end = 7; + s_inc = 1; + } + + for (i = 0; i < row_info->width; i++) + { + v = (png_byte)((*sp >> sshift) & 0x01); + for (j = 0; j < jstop; j++) + { + unsigned int tmp = *dp & (0x7f7f >> (7 - dshift)); + tmp |= v << dshift; + *dp = (png_byte)(tmp & 0xff); + + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + + else + dshift += s_inc; + } + + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + + else + sshift += s_inc; + } + break; + } + + case 2: + { + png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2); + png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2); + int sshift, dshift; + int s_start, s_end, s_inc; + int jstop = png_pass_inc[pass]; + png_uint_32 i; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if ((transformations & PNG_PACKSWAP) != 0) + { + sshift = (int)(((row_info->width + 3) & 0x03) << 1); + dshift = (int)(((final_width + 3) & 0x03) << 1); + s_start = 6; + s_end = 0; + s_inc = -2; + } + + else +#endif + { + sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1); + dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1); + s_start = 0; + s_end = 6; + s_inc = 2; + } + + for (i = 0; i < row_info->width; i++) + { + png_byte v; + int j; + + v = (png_byte)((*sp >> sshift) & 0x03); + for (j = 0; j < jstop; j++) + { + unsigned int tmp = *dp & (0x3f3f >> (6 - dshift)); + tmp |= v << dshift; + *dp = (png_byte)(tmp & 0xff); + + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + + else + dshift += s_inc; + } + + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + + else + sshift += s_inc; + } + break; + } + + case 4: + { + png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1); + png_bytep dp = row + (png_size_t)((final_width - 1) >> 1); + int sshift, dshift; + int s_start, s_end, s_inc; + png_uint_32 i; + int jstop = png_pass_inc[pass]; + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if ((transformations & PNG_PACKSWAP) != 0) + { + sshift = (int)(((row_info->width + 1) & 0x01) << 2); + dshift = (int)(((final_width + 1) & 0x01) << 2); + s_start = 4; + s_end = 0; + s_inc = -4; + } + + else +#endif + { + sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2); + dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2); + s_start = 0; + s_end = 4; + s_inc = 4; + } + + for (i = 0; i < row_info->width; i++) + { + png_byte v = (png_byte)((*sp >> sshift) & 0x0f); + int j; + + for (j = 0; j < jstop; j++) + { + unsigned int tmp = *dp & (0xf0f >> (4 - dshift)); + tmp |= v << dshift; + *dp = (png_byte)(tmp & 0xff); + + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + + else + dshift += s_inc; + } + + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + + else + sshift += s_inc; + } + break; + } + + default: + { + png_size_t pixel_bytes = (row_info->pixel_depth >> 3); + + png_bytep sp = row + (png_size_t)(row_info->width - 1) + * pixel_bytes; + + png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes; + + int jstop = png_pass_inc[pass]; + png_uint_32 i; + + for (i = 0; i < row_info->width; i++) + { + png_byte v[8]; /* SAFE; pixel_depth does not exceed 64 */ + int j; + + memcpy(v, sp, pixel_bytes); + + for (j = 0; j < jstop; j++) + { + memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + + sp -= pixel_bytes; + } + break; + } + } + + row_info->width = final_width; + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width); + } +#ifndef PNG_READ_PACKSWAP_SUPPORTED + PNG_UNUSED(transformations) /* Silence compiler warning */ +#endif +} +#endif /* READ_INTERLACING */ + +static void +png_read_filter_row_sub(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_size_t i; + png_size_t istop = row_info->rowbytes; + unsigned int bpp = (row_info->pixel_depth + 7) >> 3; + png_bytep rp = row + bpp; + + PNG_UNUSED(prev_row) + + for (i = bpp; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff); + rp++; + } +} + +static void +png_read_filter_row_up(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_size_t i; + png_size_t istop = row_info->rowbytes; + png_bytep rp = row; + png_const_bytep pp = prev_row; + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } +} + +static void +png_read_filter_row_avg(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_size_t i; + png_bytep rp = row; + png_const_bytep pp = prev_row; + unsigned int bpp = (row_info->pixel_depth + 7) >> 3; + png_size_t istop = row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++) / 2 )) & 0xff); + + rp++; + } + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + + (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff); + + rp++; + } +} + +static void +png_read_filter_row_paeth_1byte_pixel(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_bytep rp_end = row + row_info->rowbytes; + int a, c; + + /* First pixel/byte */ + c = *prev_row++; + a = *row + c; + *row++ = (png_byte)a; + + /* Remainder */ + while (row < rp_end) + { + int b, pa, pb, pc, p; + + a &= 0xff; /* From previous iteration or start */ + b = *prev_row++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + /* Find the best predictor, the least of pa, pb, pc favoring the earlier + * ones in the case of a tie. + */ + if (pb < pa) pa = pb, a = b; + if (pc < pa) a = c; + + /* Calculate the current pixel in a, and move the previous row pixel to c + * for the next time round the loop + */ + c = b; + a += *row; + *row++ = (png_byte)a; + } +} + +static void +png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + int bpp = (row_info->pixel_depth + 7) >> 3; + png_bytep rp_end = row + bpp; + + /* Process the first pixel in the row completely (this is the same as 'up' + * because there is only one candidate predictor for the first row). + */ + while (row < rp_end) + { + int a = *row + *prev_row++; + *row++ = (png_byte)a; + } + + /* Remainder */ + rp_end += row_info->rowbytes - bpp; + + while (row < rp_end) + { + int a, b, c, pa, pb, pc, p; + + c = *(prev_row - bpp); + a = *(row - bpp); + b = *prev_row++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + if (pb < pa) pa = pb, a = b; + if (pc < pa) a = c; + + a += *row; + *row++ = (png_byte)a; + } +} + +static void +png_init_filter_functions(png_structrp pp) + /* This function is called once for every PNG image (except for PNG images + * that only use PNG_FILTER_VALUE_NONE for all rows) to set the + * implementations required to reverse the filtering of PNG rows. Reversing + * the filter is the first transformation performed on the row data. It is + * performed in place, therefore an implementation can be selected based on + * the image pixel format. If the implementation depends on image width then + * take care to ensure that it works correctly if the image is interlaced - + * interlacing causes the actual row width to vary. + */ +{ + unsigned int bpp = (pp->pixel_depth + 7) >> 3; + + pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub; + pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up; + pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg; + if (bpp == 1) + pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = + png_read_filter_row_paeth_1byte_pixel; + else + pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = + png_read_filter_row_paeth_multibyte_pixel; + +#ifdef PNG_FILTER_OPTIMIZATIONS + /* To use this define PNG_FILTER_OPTIMIZATIONS as the name of a function to + * call to install hardware optimizations for the above functions; simply + * replace whatever elements of the pp->read_filter[] array with a hardware + * specific (or, for that matter, generic) optimization. + * + * To see an example of this examine what configure.ac does when + * --enable-arm-neon is specified on the command line. + */ + // PNG_FILTER_OPTIMIZATIONS(pp, bpp); // TO-TO: Fix NEON support +#endif +} + +void /* PRIVATE */ +png_read_filter_row(png_structrp pp, png_row_infop row_info, png_bytep row, + png_const_bytep prev_row, int filter) +{ + /* OPTIMIZATION: DO NOT MODIFY THIS FUNCTION, instead #define + * PNG_FILTER_OPTIMIZATIONS to a function that overrides the generic + * implementations. See png_init_filter_functions above. + */ + if (filter > PNG_FILTER_VALUE_NONE && filter < PNG_FILTER_VALUE_LAST) + { + if (pp->read_filter[0] == NULL) + png_init_filter_functions(pp); + + pp->read_filter[filter-1](row_info, row, prev_row); + } +} + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +void /* PRIVATE */ +png_read_IDAT_data(png_structrp png_ptr, png_bytep output, + png_alloc_size_t avail_out) +{ + /* Loop reading IDATs and decompressing the result into output[avail_out] */ + png_ptr->zstream.next_out = output; + png_ptr->zstream.avail_out = 0; /* safety: set below */ + + if (output == NULL) + avail_out = 0; + + do + { + int ret; + png_byte tmpbuf[PNG_INFLATE_BUF_SIZE]; + + if (png_ptr->zstream.avail_in == 0) + { + uInt avail_in; + png_bytep buffer; + + while (png_ptr->idat_size == 0) + { + png_crc_finish(png_ptr, 0); + + png_ptr->idat_size = png_read_chunk_header(png_ptr); + /* This is an error even in the 'check' case because the code just + * consumed a non-IDAT header. + */ + if (png_ptr->chunk_name != png_IDAT) + png_error(png_ptr, "Not enough image data"); + } + + avail_in = png_ptr->IDAT_read_size; + + if (avail_in > png_ptr->idat_size) + avail_in = (uInt)png_ptr->idat_size; + + /* A PNG with a gradually increasing IDAT size will defeat this attempt + * to minimize memory usage by causing lots of re-allocs, but + * realistically doing IDAT_read_size re-allocs is not likely to be a + * big problem. + */ + buffer = png_read_buffer(png_ptr, avail_in, 0/*error*/); + + png_crc_read(png_ptr, buffer, avail_in); + png_ptr->idat_size -= avail_in; + + png_ptr->zstream.next_in = buffer; + png_ptr->zstream.avail_in = avail_in; + } + + /* And set up the output side. */ + if (output != NULL) /* standard read */ + { + uInt out = ZLIB_IO_MAX; + + if (out > avail_out) + out = (uInt)avail_out; + + avail_out -= out; + png_ptr->zstream.avail_out = out; + } + + else /* after last row, checking for end */ + { + png_ptr->zstream.next_out = tmpbuf; + png_ptr->zstream.avail_out = (sizeof tmpbuf); + } + + /* Use NO_FLUSH; this gives zlib the maximum opportunity to optimize the + * process. If the LZ stream is truncated the sequential reader will + * terminally damage the stream, above, by reading the chunk header of the + * following chunk (it then exits with png_error). + * + * TODO: deal more elegantly with truncated IDAT lists. + */ + ret = PNG_INFLATE(png_ptr, Z_NO_FLUSH); + + /* Take the unconsumed output back. */ + if (output != NULL) + avail_out += png_ptr->zstream.avail_out; + + else /* avail_out counts the extra bytes */ + avail_out += (sizeof tmpbuf) - png_ptr->zstream.avail_out; + + png_ptr->zstream.avail_out = 0; + + if (ret == Z_STREAM_END) + { + /* Do this for safety; we won't read any more into this row. */ + png_ptr->zstream.next_out = NULL; + + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + + if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0) + png_chunk_benign_error(png_ptr, "Extra compressed data"); + break; + } + + if (ret != Z_OK) + { + png_zstream_error(png_ptr, ret); + + if (output != NULL) + png_chunk_error(png_ptr, png_ptr->zstream.msg); + + else /* checking */ + { + png_chunk_benign_error(png_ptr, png_ptr->zstream.msg); + return; + } + } + } while (avail_out > 0); + + if (avail_out > 0) + { + /* The stream ended before the image; this is the same as too few IDATs so + * should be handled the same way. + */ + if (output != NULL) + png_error(png_ptr, "Not enough image data"); + + else /* the deflate stream contained extra data */ + png_chunk_benign_error(png_ptr, "Too much image data"); + } +} + +void /* PRIVATE */ +png_read_finish_IDAT(png_structrp png_ptr) +{ + /* We don't need any more data and the stream should have ended, however the + * LZ end code may actually not have been processed. In this case we must + * read it otherwise stray unread IDAT data or, more likely, an IDAT chunk + * may still remain to be consumed. + */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) + { + /* The NULL causes png_read_IDAT_data to swallow any remaining bytes in + * the compressed stream, but the stream may be damaged too, so even after + * this call we may need to terminate the zstream ownership. + */ + png_read_IDAT_data(png_ptr, NULL, 0); + png_ptr->zstream.next_out = NULL; /* safety */ + + /* Now clear everything out for safety; the following may not have been + * done. + */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) + { + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + } + } + + /* If the zstream has not been released do it now *and* terminate the reading + * of the final IDAT chunk. + */ + if (png_ptr->zowner == png_IDAT) + { + /* Always do this; the pointers otherwise point into the read buffer. */ + png_ptr->zstream.next_in = NULL; + png_ptr->zstream.avail_in = 0; + + /* Now we no longer own the zstream. */ + png_ptr->zowner = 0; + + /* The slightly weird semantics of the sequential IDAT reading is that we + * are always in or at the end of an IDAT chunk, so we always need to do a + * crc_finish here. If idat_size is non-zero we also need to read the + * spurious bytes at the end of the chunk now. + */ + (void)png_crc_finish(png_ptr, png_ptr->idat_size); + } +} + +void /* PRIVATE */ +png_read_finish_row(png_structrp png_ptr) +{ + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; + + png_debug(1, "in png_read_finish_row"); + png_ptr->row_number++; + if (png_ptr->row_number < png_ptr->num_rows) + return; + + if (png_ptr->interlaced != 0) + { + png_ptr->row_number = 0; + + /* TO DO: don't do this if prev_row isn't needed (requires + * read-ahead of the next row's filter byte. + */ + memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + + do + { + png_ptr->pass++; + + if (png_ptr->pass >= 7) + break; + + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + + if ((png_ptr->transformations & PNG_INTERLACE) == 0) + { + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + } + + else /* if (png_ptr->transformations & PNG_INTERLACE) */ + break; /* libpng deinterlacing sees every row */ + + } while (png_ptr->num_rows == 0 || png_ptr->iwidth == 0); + + if (png_ptr->pass < 7) + return; + } + + /* Here after at the end of the last row of the last pass. */ + png_read_finish_IDAT(png_ptr); +} +#endif /* SEQUENTIAL_READ */ + +void /* PRIVATE */ +png_read_start_row(png_structrp png_ptr) +{ + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; + + int max_pixel_depth; + png_size_t row_bytes; + + png_debug(1, "in png_read_start_row"); + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED + png_init_read_transformations(png_ptr); +#endif + if (png_ptr->interlaced != 0) + { + if ((png_ptr->transformations & PNG_INTERLACE) == 0) + png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - + png_pass_ystart[0]) / png_pass_yinc[0]; + + else + png_ptr->num_rows = png_ptr->height; + + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + } + + else + { + png_ptr->num_rows = png_ptr->height; + png_ptr->iwidth = png_ptr->width; + } + + max_pixel_depth = png_ptr->pixel_depth; + + /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpler set of + * calculations to calculate the final pixel depth, then + * png_do_read_transforms actually does the transforms. This means that the + * code which effectively calculates this value is actually repeated in three + * separate places. They must all match. Innocent changes to the order of + * transformations can and will break libpng in a way that causes memory + * overwrites. + * + * TODO: fix this. + */ +#ifdef PNG_READ_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) != 0 && png_ptr->bit_depth < 8) + max_pixel_depth = 8; +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED + if ((png_ptr->transformations & PNG_EXPAND) != 0) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (png_ptr->num_trans != 0) + max_pixel_depth = 32; + + else + max_pixel_depth = 24; + } + + else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + if (max_pixel_depth < 8) + max_pixel_depth = 8; + + if (png_ptr->num_trans != 0) + max_pixel_depth *= 2; + } + + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + if (png_ptr->num_trans != 0) + { + max_pixel_depth *= 4; + max_pixel_depth /= 3; + } + } + } +#endif + +#ifdef PNG_READ_EXPAND_16_SUPPORTED + if ((png_ptr->transformations & PNG_EXPAND_16) != 0) + { +# ifdef PNG_READ_EXPAND_SUPPORTED + /* In fact it is an error if it isn't supported, but checking is + * the safe way. + */ + if ((png_ptr->transformations & PNG_EXPAND) != 0) + { + if (png_ptr->bit_depth < 16) + max_pixel_depth *= 2; + } + else +# endif + png_ptr->transformations &= ~PNG_EXPAND_16; + } +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED + if ((png_ptr->transformations & (PNG_FILLER)) != 0) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + if (max_pixel_depth <= 8) + max_pixel_depth = 16; + + else + max_pixel_depth = 32; + } + + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB || + png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (max_pixel_depth <= 32) + max_pixel_depth = 32; + + else + max_pixel_depth = 64; + } + } +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) + { + if ( +#ifdef PNG_READ_EXPAND_SUPPORTED + (png_ptr->num_trans != 0 && + (png_ptr->transformations & PNG_EXPAND) != 0) || +#endif +#ifdef PNG_READ_FILLER_SUPPORTED + (png_ptr->transformations & (PNG_FILLER)) != 0 || +#endif + png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (max_pixel_depth <= 16) + max_pixel_depth = 32; + + else + max_pixel_depth = 64; + } + + else + { + if (max_pixel_depth <= 8) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + max_pixel_depth = 32; + + else + max_pixel_depth = 24; + } + + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + max_pixel_depth = 64; + + else + max_pixel_depth = 48; + } + } +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \ +defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) + { + int user_pixel_depth = png_ptr->user_transform_depth * + png_ptr->user_transform_channels; + + if (user_pixel_depth > max_pixel_depth) + max_pixel_depth = user_pixel_depth; + } +#endif + + /* This value is stored in png_struct and double checked in the row read + * code. + */ + png_ptr->maximum_pixel_depth = (png_byte)max_pixel_depth; + png_ptr->transformed_pixel_depth = 0; /* calculated on demand */ + + /* Align the width on the next larger 8 pixels. Mainly used + * for interlacing + */ + row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7)); + /* Calculate the maximum bytes needed, adding a byte and a pixel + * for safety's sake + */ + row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) + + 1 + ((max_pixel_depth + 7) >> 3); + +#ifdef PNG_MAX_MALLOC_64K + if (row_bytes > (png_uint_32)65536L) + png_error(png_ptr, "This image requires a row greater than 64KB"); +#endif + + if (row_bytes + 48 > png_ptr->old_big_row_buf_size) + { + png_free(png_ptr, png_ptr->big_row_buf); + png_free(png_ptr, png_ptr->big_prev_row); + + if (png_ptr->interlaced != 0) + png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr, + row_bytes + 48); + + else + png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes + 48); + + png_ptr->big_prev_row = (png_bytep)png_malloc(png_ptr, row_bytes + 48); + +#ifdef PNG_ALIGNED_MEMORY_SUPPORTED + /* Use 16-byte aligned memory for row_buf with at least 16 bytes + * of padding before and after row_buf; treat prev_row similarly. + * NOTE: the alignment is to the start of the pixels, one beyond the start + * of the buffer, because of the filter byte. Prior to libpng 1.5.6 this + * was incorrect; the filter byte was aligned, which had the exact + * opposite effect of that intended. + */ + { + png_bytep temp = png_ptr->big_row_buf + 32; + int extra = (int)((temp - (png_bytep)0) & 0x0f); + png_ptr->row_buf = temp - extra - 1/*filter byte*/; + + temp = png_ptr->big_prev_row + 32; + extra = (int)((temp - (png_bytep)0) & 0x0f); + png_ptr->prev_row = temp - extra - 1/*filter byte*/; + } + +#else + /* Use 31 bytes of padding before and 17 bytes after row_buf. */ + png_ptr->row_buf = png_ptr->big_row_buf + 31; + png_ptr->prev_row = png_ptr->big_prev_row + 31; +#endif + png_ptr->old_big_row_buf_size = row_bytes + 48; + } + +#ifdef PNG_MAX_MALLOC_64K + if (png_ptr->rowbytes > 65535) + png_error(png_ptr, "This image requires a row greater than 64KB"); + +#endif + if (png_ptr->rowbytes > (PNG_SIZE_MAX - 1)) + png_error(png_ptr, "Row has too many bytes to allocate in memory"); + + memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + + png_debug1(3, "width = %u,", png_ptr->width); + png_debug1(3, "height = %u,", png_ptr->height); + png_debug1(3, "iwidth = %u,", png_ptr->iwidth); + png_debug1(3, "num_rows = %u,", png_ptr->num_rows); + png_debug1(3, "rowbytes = %lu,", (unsigned long)png_ptr->rowbytes); + png_debug1(3, "irowbytes = %lu", + (unsigned long)PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1); + + /* The sequential reader needs a buffer for IDAT, but the progressive reader + * does not, so free the read buffer now regardless; the sequential reader + * reallocates it on demand. + */ + if (png_ptr->read_buffer != 0) + { + png_bytep buffer = png_ptr->read_buffer; + + png_ptr->read_buffer_size = 0; + png_ptr->read_buffer = NULL; + png_free(png_ptr, buffer); + } + + /* Finally claim the zstream for the inflate of the IDAT data, use the bits + * value from the stream (note that this will result in a fatal error if the + * IDAT stream has a bogus deflate header window_bits value, but this should + * not be happening any longer!) + */ + if (png_inflate_claim(png_ptr, png_IDAT) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + + png_ptr->flags |= PNG_FLAG_ROW_INIT; +} +#endif /* READ */ diff --git a/source/Irrlicht/libpng/pngset.c b/source/Irrlicht/libpng/pngset.c new file mode 100644 index 00000000..b050e95a --- /dev/null +++ b/source/Irrlicht/libpng/pngset.c @@ -0,0 +1,1733 @@ + +/* pngset.c - storage of image information into info struct + * + * Last changed in libpng 1.6.23 [June 9, 2016] + * Copyright (c) 1998-2016 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * The functions here are used during reads to store data from the file + * into the info struct, and during writes to store application data + * into the info struct for writing into the file. This abstracts the + * info struct and allows us to change the structure in the future. + */ + +#include "pngpriv.h" + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + +#ifdef PNG_bKGD_SUPPORTED +void PNGAPI +png_set_bKGD(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_color_16p background) +{ + png_debug1(1, "in %s storage function", "bKGD"); + + if (png_ptr == NULL || info_ptr == NULL || background == NULL) + return; + + info_ptr->background = *background; + info_ptr->valid |= PNG_INFO_bKGD; +} +#endif + +#ifdef PNG_cHRM_SUPPORTED +void PNGFAPI +png_set_cHRM_fixed(png_const_structrp png_ptr, png_inforp info_ptr, + png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x, + png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, + png_fixed_point blue_x, png_fixed_point blue_y) +{ + png_xy xy; + + png_debug1(1, "in %s storage function", "cHRM fixed"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + xy.redx = red_x; + xy.redy = red_y; + xy.greenx = green_x; + xy.greeny = green_y; + xy.bluex = blue_x; + xy.bluey = blue_y; + xy.whitex = white_x; + xy.whitey = white_y; + + if (png_colorspace_set_chromaticities(png_ptr, &info_ptr->colorspace, &xy, + 2/* override with app values*/) != 0) + info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; + + png_colorspace_sync_info(png_ptr, info_ptr); +} + +void PNGFAPI +png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr, + png_fixed_point int_red_X, png_fixed_point int_red_Y, + png_fixed_point int_red_Z, png_fixed_point int_green_X, + png_fixed_point int_green_Y, png_fixed_point int_green_Z, + png_fixed_point int_blue_X, png_fixed_point int_blue_Y, + png_fixed_point int_blue_Z) +{ + png_XYZ XYZ; + + png_debug1(1, "in %s storage function", "cHRM XYZ fixed"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + XYZ.red_X = int_red_X; + XYZ.red_Y = int_red_Y; + XYZ.red_Z = int_red_Z; + XYZ.green_X = int_green_X; + XYZ.green_Y = int_green_Y; + XYZ.green_Z = int_green_Z; + XYZ.blue_X = int_blue_X; + XYZ.blue_Y = int_blue_Y; + XYZ.blue_Z = int_blue_Z; + + if (png_colorspace_set_endpoints(png_ptr, &info_ptr->colorspace, + &XYZ, 2) != 0) + info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; + + png_colorspace_sync_info(png_ptr, info_ptr); +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, + double white_x, double white_y, double red_x, double red_y, + double green_x, double green_y, double blue_x, double blue_y) +{ + png_set_cHRM_fixed(png_ptr, info_ptr, + png_fixed(png_ptr, white_x, "cHRM White X"), + png_fixed(png_ptr, white_y, "cHRM White Y"), + png_fixed(png_ptr, red_x, "cHRM Red X"), + png_fixed(png_ptr, red_y, "cHRM Red Y"), + png_fixed(png_ptr, green_x, "cHRM Green X"), + png_fixed(png_ptr, green_y, "cHRM Green Y"), + png_fixed(png_ptr, blue_x, "cHRM Blue X"), + png_fixed(png_ptr, blue_y, "cHRM Blue Y")); +} + +void PNGAPI +png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X, + double red_Y, double red_Z, double green_X, double green_Y, double green_Z, + double blue_X, double blue_Y, double blue_Z) +{ + png_set_cHRM_XYZ_fixed(png_ptr, info_ptr, + png_fixed(png_ptr, red_X, "cHRM Red X"), + png_fixed(png_ptr, red_Y, "cHRM Red Y"), + png_fixed(png_ptr, red_Z, "cHRM Red Z"), + png_fixed(png_ptr, green_X, "cHRM Green X"), + png_fixed(png_ptr, green_Y, "cHRM Green Y"), + png_fixed(png_ptr, green_Z, "cHRM Green Z"), + png_fixed(png_ptr, blue_X, "cHRM Blue X"), + png_fixed(png_ptr, blue_Y, "cHRM Blue Y"), + png_fixed(png_ptr, blue_Z, "cHRM Blue Z")); +} +# endif /* FLOATING_POINT */ + +#endif /* cHRM */ + +#ifdef PNG_gAMA_SUPPORTED +void PNGFAPI +png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr, + png_fixed_point file_gamma) +{ + png_debug1(1, "in %s storage function", "gAMA"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma); + png_colorspace_sync_info(png_ptr, info_ptr); +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_gAMA(png_const_structrp png_ptr, png_inforp info_ptr, double file_gamma) +{ + png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma, + "png_set_gAMA")); +} +# endif +#endif + +#ifdef PNG_hIST_SUPPORTED +void PNGAPI +png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_uint_16p hist) +{ + int i; + + png_debug1(1, "in %s storage function", "hIST"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (info_ptr->num_palette == 0 || info_ptr->num_palette + > PNG_MAX_PALETTE_LENGTH) + { + png_warning(png_ptr, + "Invalid palette size, hIST allocation skipped"); + + return; + } + + png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0); + + /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in + * version 1.2.1 + */ + info_ptr->hist = png_voidcast(png_uint_16p, png_malloc_warn(png_ptr, + PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16)))); + + if (info_ptr->hist == NULL) + { + png_warning(png_ptr, "Insufficient memory for hIST chunk data"); + + return; + } + + info_ptr->free_me |= PNG_FREE_HIST; + + for (i = 0; i < info_ptr->num_palette; i++) + info_ptr->hist[i] = hist[i]; + + info_ptr->valid |= PNG_INFO_hIST; +} +#endif + +void PNGAPI +png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type) +{ + png_debug1(1, "in %s storage function", "IHDR"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->width = width; + info_ptr->height = height; + info_ptr->bit_depth = (png_byte)bit_depth; + info_ptr->color_type = (png_byte)color_type; + info_ptr->compression_type = (png_byte)compression_type; + info_ptr->filter_type = (png_byte)filter_type; + info_ptr->interlace_type = (png_byte)interlace_type; + + png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height, + info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, + info_ptr->compression_type, info_ptr->filter_type); + + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + info_ptr->channels = 1; + + else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + info_ptr->channels = 3; + + else + info_ptr->channels = 1; + + if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) + info_ptr->channels++; + + info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); + + info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); +} + +#ifdef PNG_oFFs_SUPPORTED +void PNGAPI +png_set_oFFs(png_const_structrp png_ptr, png_inforp info_ptr, + png_int_32 offset_x, png_int_32 offset_y, int unit_type) +{ + png_debug1(1, "in %s storage function", "oFFs"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->x_offset = offset_x; + info_ptr->y_offset = offset_y; + info_ptr->offset_unit_type = (png_byte)unit_type; + info_ptr->valid |= PNG_INFO_oFFs; +} +#endif + +#ifdef PNG_pCAL_SUPPORTED +void PNGAPI +png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type, + int nparams, png_const_charp units, png_charpp params) +{ + png_size_t length; + int i; + + png_debug1(1, "in %s storage function", "pCAL"); + + if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL + || (nparams > 0 && params == NULL)) + return; + + length = strlen(purpose) + 1; + png_debug1(3, "allocating purpose for info (%lu bytes)", + (unsigned long)length); + + /* TODO: validate format of calibration name and unit name */ + + /* Check that the type matches the specification. */ + if (type < 0 || type > 3) + png_error(png_ptr, "Invalid pCAL equation type"); + + if (nparams < 0 || nparams > 255) + png_error(png_ptr, "Invalid pCAL parameter count"); + + /* Validate params[nparams] */ + for (i=0; ipcal_purpose = png_voidcast(png_charp, + png_malloc_warn(png_ptr, length)); + + if (info_ptr->pcal_purpose == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL purpose"); + + return; + } + + memcpy(info_ptr->pcal_purpose, purpose, length); + + png_debug(3, "storing X0, X1, type, and nparams in info"); + info_ptr->pcal_X0 = X0; + info_ptr->pcal_X1 = X1; + info_ptr->pcal_type = (png_byte)type; + info_ptr->pcal_nparams = (png_byte)nparams; + + length = strlen(units) + 1; + png_debug1(3, "allocating units for info (%lu bytes)", + (unsigned long)length); + + info_ptr->pcal_units = png_voidcast(png_charp, + png_malloc_warn(png_ptr, length)); + + if (info_ptr->pcal_units == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL units"); + + return; + } + + memcpy(info_ptr->pcal_units, units, length); + + info_ptr->pcal_params = png_voidcast(png_charpp, png_malloc_warn(png_ptr, + (png_size_t)((nparams + 1) * (sizeof (png_charp))))); + + if (info_ptr->pcal_params == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL params"); + + return; + } + + memset(info_ptr->pcal_params, 0, (nparams + 1) * (sizeof (png_charp))); + + for (i = 0; i < nparams; i++) + { + length = strlen(params[i]) + 1; + png_debug2(3, "allocating parameter %d for info (%lu bytes)", i, + (unsigned long)length); + + info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length); + + if (info_ptr->pcal_params[i] == NULL) + { + png_warning(png_ptr, "Insufficient memory for pCAL parameter"); + + return; + } + + memcpy(info_ptr->pcal_params[i], params[i], length); + } + + info_ptr->valid |= PNG_INFO_pCAL; + info_ptr->free_me |= PNG_FREE_PCAL; +} +#endif + +#ifdef PNG_sCAL_SUPPORTED +void PNGAPI +png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr, + int unit, png_const_charp swidth, png_const_charp sheight) +{ + png_size_t lengthw = 0, lengthh = 0; + + png_debug1(1, "in %s storage function", "sCAL"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* Double check the unit (should never get here with an invalid + * unit unless this is an API call.) + */ + if (unit != 1 && unit != 2) + png_error(png_ptr, "Invalid sCAL unit"); + + if (swidth == NULL || (lengthw = strlen(swidth)) == 0 || + swidth[0] == 45 /* '-' */ || !png_check_fp_string(swidth, lengthw)) + png_error(png_ptr, "Invalid sCAL width"); + + if (sheight == NULL || (lengthh = strlen(sheight)) == 0 || + sheight[0] == 45 /* '-' */ || !png_check_fp_string(sheight, lengthh)) + png_error(png_ptr, "Invalid sCAL height"); + + info_ptr->scal_unit = (png_byte)unit; + + ++lengthw; + + png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthw); + + info_ptr->scal_s_width = png_voidcast(png_charp, + png_malloc_warn(png_ptr, lengthw)); + + if (info_ptr->scal_s_width == NULL) + { + png_warning(png_ptr, "Memory allocation failed while processing sCAL"); + + return; + } + + memcpy(info_ptr->scal_s_width, swidth, lengthw); + + ++lengthh; + + png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthh); + + info_ptr->scal_s_height = png_voidcast(png_charp, + png_malloc_warn(png_ptr, lengthh)); + + if (info_ptr->scal_s_height == NULL) + { + png_free (png_ptr, info_ptr->scal_s_width); + info_ptr->scal_s_width = NULL; + + png_warning(png_ptr, "Memory allocation failed while processing sCAL"); + + return; + } + + memcpy(info_ptr->scal_s_height, sheight, lengthh); + + info_ptr->valid |= PNG_INFO_sCAL; + info_ptr->free_me |= PNG_FREE_SCAL; +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_sCAL(png_const_structrp png_ptr, png_inforp info_ptr, int unit, + double width, double height) +{ + png_debug1(1, "in %s storage function", "sCAL"); + + /* Check the arguments. */ + if (width <= 0) + png_warning(png_ptr, "Invalid sCAL width ignored"); + + else if (height <= 0) + png_warning(png_ptr, "Invalid sCAL height ignored"); + + else + { + /* Convert 'width' and 'height' to ASCII. */ + char swidth[PNG_sCAL_MAX_DIGITS+1]; + char sheight[PNG_sCAL_MAX_DIGITS+1]; + + png_ascii_from_fp(png_ptr, swidth, (sizeof swidth), width, + PNG_sCAL_PRECISION); + png_ascii_from_fp(png_ptr, sheight, (sizeof sheight), height, + PNG_sCAL_PRECISION); + + png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); + } +} +# endif + +# ifdef PNG_FIXED_POINT_SUPPORTED +void PNGAPI +png_set_sCAL_fixed(png_const_structrp png_ptr, png_inforp info_ptr, int unit, + png_fixed_point width, png_fixed_point height) +{ + png_debug1(1, "in %s storage function", "sCAL"); + + /* Check the arguments. */ + if (width <= 0) + png_warning(png_ptr, "Invalid sCAL width ignored"); + + else if (height <= 0) + png_warning(png_ptr, "Invalid sCAL height ignored"); + + else + { + /* Convert 'width' and 'height' to ASCII. */ + char swidth[PNG_sCAL_MAX_DIGITS+1]; + char sheight[PNG_sCAL_MAX_DIGITS+1]; + + png_ascii_from_fixed(png_ptr, swidth, (sizeof swidth), width); + png_ascii_from_fixed(png_ptr, sheight, (sizeof sheight), height); + + png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); + } +} +# endif +#endif + +#ifdef PNG_pHYs_SUPPORTED +void PNGAPI +png_set_pHYs(png_const_structrp png_ptr, png_inforp info_ptr, + png_uint_32 res_x, png_uint_32 res_y, int unit_type) +{ + png_debug1(1, "in %s storage function", "pHYs"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->x_pixels_per_unit = res_x; + info_ptr->y_pixels_per_unit = res_y; + info_ptr->phys_unit_type = (png_byte)unit_type; + info_ptr->valid |= PNG_INFO_pHYs; +} +#endif + +void PNGAPI +png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr, + png_const_colorp palette, int num_palette) +{ + + png_uint_32 max_palette_length; + + png_debug1(1, "in %s storage function", "PLTE"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + max_palette_length = (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ? + (1 << info_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH; + + if (num_palette < 0 || num_palette > (int) max_palette_length) + { + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + png_error(png_ptr, "Invalid palette length"); + + else + { + png_warning(png_ptr, "Invalid palette length"); + + return; + } + } + + if ((num_palette > 0 && palette == NULL) || + (num_palette == 0 +# ifdef PNG_MNG_FEATURES_SUPPORTED + && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 +# endif + )) + { + png_error(png_ptr, "Invalid palette"); + } + + /* It may not actually be necessary to set png_ptr->palette here; + * we do it for backward compatibility with the way the png_handle_tRNS + * function used to do the allocation. + * + * 1.6.0: the above statement appears to be incorrect; something has to set + * the palette inside png_struct on read. + */ + png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); + + /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead + * of num_palette entries, in case of an invalid PNG file or incorrect + * call to png_set_PLTE() with too-large sample values. + */ + png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr, + PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)))); + + if (num_palette > 0) + memcpy(png_ptr->palette, palette, num_palette * (sizeof (png_color))); + info_ptr->palette = png_ptr->palette; + info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette; + + info_ptr->free_me |= PNG_FREE_PLTE; + + info_ptr->valid |= PNG_INFO_PLTE; +} + +#ifdef PNG_sBIT_SUPPORTED +void PNGAPI +png_set_sBIT(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_color_8p sig_bit) +{ + png_debug1(1, "in %s storage function", "sBIT"); + + if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL) + return; + + info_ptr->sig_bit = *sig_bit; + info_ptr->valid |= PNG_INFO_sBIT; +} +#endif + +#ifdef PNG_sRGB_SUPPORTED +void PNGAPI +png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent) +{ + png_debug1(1, "in %s storage function", "sRGB"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + (void)png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent); + png_colorspace_sync_info(png_ptr, info_ptr); +} + +void PNGAPI +png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, + int srgb_intent) +{ + png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, + srgb_intent) != 0) + { + /* This causes the gAMA and cHRM to be written too */ + info_ptr->colorspace.flags |= + PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM; + } + + png_colorspace_sync_info(png_ptr, info_ptr); +} +#endif /* sRGB */ + + +#ifdef PNG_iCCP_SUPPORTED +void PNGAPI +png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_charp name, int compression_type, + png_const_bytep profile, png_uint_32 proflen) +{ + png_charp new_iccp_name; + png_bytep new_iccp_profile; + png_size_t length; + + png_debug1(1, "in %s storage function", "iCCP"); + + if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL) + return; + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + png_app_error(png_ptr, "Invalid iCCP compression method"); + + /* Set the colorspace first because this validates the profile; do not + * override previously set app cHRM or gAMA here (because likely as not the + * application knows better than libpng what the correct values are.) Pass + * the info_ptr color_type field to png_colorspace_set_ICC because in the + * write case it has not yet been stored in png_ptr. + */ + { + int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name, + proflen, profile, info_ptr->color_type); + + png_colorspace_sync_info(png_ptr, info_ptr); + + /* Don't do any of the copying if the profile was bad, or inconsistent. */ + if (result == 0) + return; + + /* But do write the gAMA and cHRM chunks from the profile. */ + info_ptr->colorspace.flags |= + PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM; + } + + length = strlen(name)+1; + new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length)); + + if (new_iccp_name == NULL) + { + png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk"); + + return; + } + + memcpy(new_iccp_name, name, length); + new_iccp_profile = png_voidcast(png_bytep, + png_malloc_warn(png_ptr, proflen)); + + if (new_iccp_profile == NULL) + { + png_free(png_ptr, new_iccp_name); + png_benign_error(png_ptr, + "Insufficient memory to process iCCP profile"); + + return; + } + + memcpy(new_iccp_profile, profile, proflen); + + png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0); + + info_ptr->iccp_proflen = proflen; + info_ptr->iccp_name = new_iccp_name; + info_ptr->iccp_profile = new_iccp_profile; + info_ptr->free_me |= PNG_FREE_ICCP; + info_ptr->valid |= PNG_INFO_iCCP; +} +#endif + +#ifdef PNG_TEXT_SUPPORTED +void PNGAPI +png_set_text(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_textp text_ptr, int num_text) +{ + int ret; + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text); + + if (ret != 0) + png_error(png_ptr, "Insufficient memory to store text"); +} + +int /* PRIVATE */ +png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_textp text_ptr, int num_text) +{ + int i; + + png_debug1(1, "in %lx storage function", png_ptr == NULL ? 0xabadca11U : + (unsigned long)png_ptr->chunk_name); + + if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL) + return(0); + + /* Make sure we have enough space in the "text" array in info_struct + * to hold all of the incoming text_ptr objects. This compare can't overflow + * because max_text >= num_text (anyway, subtract of two positive integers + * can't overflow in any case.) + */ + if (num_text > info_ptr->max_text - info_ptr->num_text) + { + int old_num_text = info_ptr->num_text; + int max_text; + png_textp new_text = NULL; + + /* Calculate an appropriate max_text, checking for overflow. */ + max_text = old_num_text; + if (num_text <= INT_MAX - max_text) + { + max_text += num_text; + + /* Round up to a multiple of 8 */ + if (max_text < INT_MAX-8) + max_text = (max_text + 8) & ~0x7; + + else + max_text = INT_MAX; + + /* Now allocate a new array and copy the old members in; this does all + * the overflow checks. + */ + new_text = png_voidcast(png_textp,png_realloc_array(png_ptr, + info_ptr->text, old_num_text, max_text-old_num_text, + sizeof *new_text)); + } + + if (new_text == NULL) + { + png_chunk_report(png_ptr, "too many text chunks", + PNG_CHUNK_WRITE_ERROR); + + return 1; + } + + png_free(png_ptr, info_ptr->text); + + info_ptr->text = new_text; + info_ptr->free_me |= PNG_FREE_TEXT; + info_ptr->max_text = max_text; + /* num_text is adjusted below as the entries are copied in */ + + png_debug1(3, "allocated %d entries for info_ptr->text", max_text); + } + + for (i = 0; i < num_text; i++) + { + size_t text_length, key_len; + size_t lang_len, lang_key_len; + png_textp textp = &(info_ptr->text[info_ptr->num_text]); + + if (text_ptr[i].key == NULL) + continue; + + if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE || + text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST) + { + png_chunk_report(png_ptr, "text compression mode is out of range", + PNG_CHUNK_WRITE_ERROR); + continue; + } + + key_len = strlen(text_ptr[i].key); + + if (text_ptr[i].compression <= 0) + { + lang_len = 0; + lang_key_len = 0; + } + + else +# ifdef PNG_iTXt_SUPPORTED + { + /* Set iTXt data */ + + if (text_ptr[i].lang != NULL) + lang_len = strlen(text_ptr[i].lang); + + else + lang_len = 0; + + if (text_ptr[i].lang_key != NULL) + lang_key_len = strlen(text_ptr[i].lang_key); + + else + lang_key_len = 0; + } +# else /* iTXt */ + { + png_chunk_report(png_ptr, "iTXt chunk not supported", + PNG_CHUNK_WRITE_ERROR); + continue; + } +# endif + + if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0') + { + text_length = 0; +# ifdef PNG_iTXt_SUPPORTED + if (text_ptr[i].compression > 0) + textp->compression = PNG_ITXT_COMPRESSION_NONE; + + else +# endif + textp->compression = PNG_TEXT_COMPRESSION_NONE; + } + + else + { + text_length = strlen(text_ptr[i].text); + textp->compression = text_ptr[i].compression; + } + + textp->key = png_voidcast(png_charp,png_malloc_base(png_ptr, + key_len + text_length + lang_len + lang_key_len + 4)); + + if (textp->key == NULL) + { + png_chunk_report(png_ptr, "text chunk: out of memory", + PNG_CHUNK_WRITE_ERROR); + + return 1; + } + + png_debug2(2, "Allocated %lu bytes at %p in png_set_text", + (unsigned long)(png_uint_32) + (key_len + lang_len + lang_key_len + text_length + 4), + textp->key); + + memcpy(textp->key, text_ptr[i].key, key_len); + *(textp->key + key_len) = '\0'; + + if (text_ptr[i].compression > 0) + { + textp->lang = textp->key + key_len + 1; + memcpy(textp->lang, text_ptr[i].lang, lang_len); + *(textp->lang + lang_len) = '\0'; + textp->lang_key = textp->lang + lang_len + 1; + memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len); + *(textp->lang_key + lang_key_len) = '\0'; + textp->text = textp->lang_key + lang_key_len + 1; + } + + else + { + textp->lang=NULL; + textp->lang_key=NULL; + textp->text = textp->key + key_len + 1; + } + + if (text_length != 0) + memcpy(textp->text, text_ptr[i].text, text_length); + + *(textp->text + text_length) = '\0'; + +# ifdef PNG_iTXt_SUPPORTED + if (textp->compression > 0) + { + textp->text_length = 0; + textp->itxt_length = text_length; + } + + else +# endif + { + textp->text_length = text_length; + textp->itxt_length = 0; + } + + info_ptr->num_text++; + png_debug1(3, "transferred text chunk %d", info_ptr->num_text); + } + + return(0); +} +#endif + +#ifdef PNG_tIME_SUPPORTED +void PNGAPI +png_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_timep mod_time) +{ + png_debug1(1, "in %s storage function", "tIME"); + + if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL || + (png_ptr->mode & PNG_WROTE_tIME) != 0) + return; + + if (mod_time->month == 0 || mod_time->month > 12 || + mod_time->day == 0 || mod_time->day > 31 || + mod_time->hour > 23 || mod_time->minute > 59 || + mod_time->second > 60) + { + png_warning(png_ptr, "Ignoring invalid time value"); + + return; + } + + info_ptr->mod_time = *mod_time; + info_ptr->valid |= PNG_INFO_tIME; +} +#endif + +#ifdef PNG_tRNS_SUPPORTED +void PNGAPI +png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr, + png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color) +{ + png_debug1(1, "in %s storage function", "tRNS"); + + if (png_ptr == NULL || info_ptr == NULL) + + return; + + if (trans_alpha != NULL) + { + /* It may not actually be necessary to set png_ptr->trans_alpha here; + * we do it for backward compatibility with the way the png_handle_tRNS + * function used to do the allocation. + * + * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively + * relies on png_set_tRNS storing the information in png_struct + * (otherwise it won't be there for the code in pngrtran.c). + */ + + png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); + + if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH) + { + /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */ + info_ptr->trans_alpha = png_voidcast(png_bytep, + png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH)); + memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans); + } + png_ptr->trans_alpha = info_ptr->trans_alpha; + } + + if (trans_color != NULL) + { +#ifdef PNG_WARNINGS_SUPPORTED + if (info_ptr->bit_depth < 16) + { + int sample_max = (1 << info_ptr->bit_depth) - 1; + + if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY && + trans_color->gray > sample_max) || + (info_ptr->color_type == PNG_COLOR_TYPE_RGB && + (trans_color->red > sample_max || + trans_color->green > sample_max || + trans_color->blue > sample_max))) + png_warning(png_ptr, + "tRNS chunk has out-of-range samples for bit_depth"); + } +#endif + + info_ptr->trans_color = *trans_color; + + if (num_trans == 0) + num_trans = 1; + } + + info_ptr->num_trans = (png_uint_16)num_trans; + + if (num_trans != 0) + { + info_ptr->valid |= PNG_INFO_tRNS; + info_ptr->free_me |= PNG_FREE_TRNS; + } +} +#endif + +#ifdef PNG_sPLT_SUPPORTED +void PNGAPI +png_set_sPLT(png_const_structrp png_ptr, + png_inforp info_ptr, png_const_sPLT_tp entries, int nentries) +/* + * entries - array of png_sPLT_t structures + * to be added to the list of palettes + * in the info structure. + * + * nentries - number of palette structures to be + * added. + */ +{ + png_sPLT_tp np; + + if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL) + return; + + /* Use the internal realloc function, which checks for all the possible + * overflows. Notice that the parameters are (int) and (size_t) + */ + np = png_voidcast(png_sPLT_tp,png_realloc_array(png_ptr, + info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries, + sizeof *np)); + + if (np == NULL) + { + /* Out of memory or too many chunks */ + png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR); + + return; + } + + png_free(png_ptr, info_ptr->splt_palettes); + info_ptr->splt_palettes = np; + info_ptr->free_me |= PNG_FREE_SPLT; + + np += info_ptr->splt_palettes_num; + + do + { + png_size_t length; + + /* Skip invalid input entries */ + if (entries->name == NULL || entries->entries == NULL) + { + /* png_handle_sPLT doesn't do this, so this is an app error */ + png_app_error(png_ptr, "png_set_sPLT: invalid sPLT"); + /* Just skip the invalid entry */ + continue; + } + + np->depth = entries->depth; + + /* In the event of out-of-memory just return - there's no point keeping + * on trying to add sPLT chunks. + */ + length = strlen(entries->name) + 1; + np->name = png_voidcast(png_charp, png_malloc_base(png_ptr, length)); + + if (np->name == NULL) + break; + + memcpy(np->name, entries->name, length); + + /* IMPORTANT: we have memory now that won't get freed if something else + * goes wrong; this code must free it. png_malloc_array produces no + * warnings; use a png_chunk_report (below) if there is an error. + */ + np->entries = png_voidcast(png_sPLT_entryp, png_malloc_array(png_ptr, + entries->nentries, sizeof (png_sPLT_entry))); + + if (np->entries == NULL) + { + png_free(png_ptr, np->name); + np->name = NULL; + break; + } + + np->nentries = entries->nentries; + /* This multiply can't overflow because png_malloc_array has already + * checked it when doing the allocation. + */ + memcpy(np->entries, entries->entries, + entries->nentries * sizeof (png_sPLT_entry)); + + /* Note that 'continue' skips the advance of the out pointer and out + * count, so an invalid entry is not added. + */ + info_ptr->valid |= PNG_INFO_sPLT; + ++(info_ptr->splt_palettes_num); + ++np; + } + while (++entries, --nentries); + + if (nentries > 0) + png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR); +} +#endif /* sPLT */ + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +static png_byte +check_location(png_const_structrp png_ptr, int location) +{ + location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT); + + /* New in 1.6.0; copy the location and check it. This is an API + * change; previously the app had to use the + * png_set_unknown_chunk_location API below for each chunk. + */ + if (location == 0 && (png_ptr->mode & PNG_IS_READ_STRUCT) == 0) + { + /* Write struct, so unknown chunks come from the app */ + png_app_warning(png_ptr, + "png_set_unknown_chunks now expects a valid location"); + /* Use the old behavior */ + location = (png_byte)(png_ptr->mode & + (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)); + } + + /* This need not be an internal error - if the app calls + * png_set_unknown_chunks on a read pointer it must get the location right. + */ + if (location == 0) + png_error(png_ptr, "invalid location in png_set_unknown_chunks"); + + /* Now reduce the location to the top-most set bit by removing each least + * significant bit in turn. + */ + while (location != (location & -location)) + location &= ~(location & -location); + + /* The cast is safe because 'location' is a bit mask and only the low four + * bits are significant. + */ + return (png_byte)location; +} + +void PNGAPI +png_set_unknown_chunks(png_const_structrp png_ptr, + png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns) +{ + png_unknown_chunkp np; + + if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 || + unknowns == NULL) + return; + + /* Check for the failure cases where support has been disabled at compile + * time. This code is hardly ever compiled - it's here because + * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this + * code) but may be meaningless if the read or write handling of unknown + * chunks is not compiled in. + */ +# if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \ + defined(PNG_READ_SUPPORTED) + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) + { + png_app_error(png_ptr, "no unknown chunk support on read"); + + return; + } +# endif +# if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \ + defined(PNG_WRITE_SUPPORTED) + if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) + { + png_app_error(png_ptr, "no unknown chunk support on write"); + + return; + } +# endif + + /* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that + * unknown critical chunks could be lost with just a warning resulting in + * undefined behavior. Now png_chunk_report is used to provide behavior + * appropriate to read or write. + */ + np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr, + info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns, + sizeof *np)); + + if (np == NULL) + { + png_chunk_report(png_ptr, "too many unknown chunks", + PNG_CHUNK_WRITE_ERROR); + + return; + } + + png_free(png_ptr, info_ptr->unknown_chunks); + info_ptr->unknown_chunks = np; /* safe because it is initialized */ + info_ptr->free_me |= PNG_FREE_UNKN; + + np += info_ptr->unknown_chunks_num; + + /* Increment unknown_chunks_num each time round the loop to protect the + * just-allocated chunk data. + */ + for (; num_unknowns > 0; --num_unknowns, ++unknowns) + { + memcpy(np->name, unknowns->name, (sizeof np->name)); + np->name[(sizeof np->name)-1] = '\0'; + np->location = check_location(png_ptr, unknowns->location); + + if (unknowns->size == 0) + { + np->data = NULL; + np->size = 0; + } + + else + { + np->data = png_voidcast(png_bytep, + png_malloc_base(png_ptr, unknowns->size)); + + if (np->data == NULL) + { + png_chunk_report(png_ptr, "unknown chunk: out of memory", + PNG_CHUNK_WRITE_ERROR); + /* But just skip storing the unknown chunk */ + continue; + } + + memcpy(np->data, unknowns->data, unknowns->size); + np->size = unknowns->size; + } + + /* These increments are skipped on out-of-memory for the data - the + * unknown chunk entry gets overwritten if the png_chunk_report returns. + * This is correct in the read case (the chunk is just dropped.) + */ + ++np; + ++(info_ptr->unknown_chunks_num); + } +} + +void PNGAPI +png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr, + int chunk, int location) +{ + /* This API is pretty pointless in 1.6.0 because the location can be set + * before the call to png_set_unknown_chunks. + * + * TODO: add a png_app_warning in 1.7 + */ + if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 && + chunk < info_ptr->unknown_chunks_num) + { + if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0) + { + png_app_error(png_ptr, "invalid unknown chunk location"); + /* Fake out the pre 1.6.0 behavior: */ + if ((location & PNG_HAVE_IDAT) != 0) /* undocumented! */ + location = PNG_AFTER_IDAT; + + else + location = PNG_HAVE_IHDR; /* also undocumented */ + } + + info_ptr->unknown_chunks[chunk].location = + check_location(png_ptr, location); + } +} +#endif /* STORE_UNKNOWN_CHUNKS */ + +#ifdef PNG_MNG_FEATURES_SUPPORTED +png_uint_32 PNGAPI +png_permit_mng_features (png_structrp png_ptr, png_uint_32 mng_features) +{ + png_debug(1, "in png_permit_mng_features"); + + if (png_ptr == NULL) + return 0; + + png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES; + + return png_ptr->mng_features_permitted; +} +#endif + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +static unsigned int +add_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep) +{ + unsigned int i; + + /* Utility function: update the 'keep' state of a chunk if it is already in + * the list, otherwise add it to the list. + */ + for (i=0; i= PNG_HANDLE_CHUNK_LAST) + { + png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep"); + + return; + } + + if (num_chunks_in <= 0) + { + png_ptr->unknown_default = keep; + + /* '0' means just set the flags, so stop here */ + if (num_chunks_in == 0) + return; + } + + if (num_chunks_in < 0) + { + /* Ignore all unknown chunks and all chunks recognized by + * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND + */ + static PNG_CONST png_byte chunks_to_ignore[] = { + 98, 75, 71, 68, '\0', /* bKGD */ + 99, 72, 82, 77, '\0', /* cHRM */ + 103, 65, 77, 65, '\0', /* gAMA */ + 104, 73, 83, 84, '\0', /* hIST */ + 105, 67, 67, 80, '\0', /* iCCP */ + 105, 84, 88, 116, '\0', /* iTXt */ + 111, 70, 70, 115, '\0', /* oFFs */ + 112, 67, 65, 76, '\0', /* pCAL */ + 112, 72, 89, 115, '\0', /* pHYs */ + 115, 66, 73, 84, '\0', /* sBIT */ + 115, 67, 65, 76, '\0', /* sCAL */ + 115, 80, 76, 84, '\0', /* sPLT */ + 115, 84, 69, 82, '\0', /* sTER */ + 115, 82, 71, 66, '\0', /* sRGB */ + 116, 69, 88, 116, '\0', /* tEXt */ + 116, 73, 77, 69, '\0', /* tIME */ + 122, 84, 88, 116, '\0' /* zTXt */ + }; + + chunk_list = chunks_to_ignore; + num_chunks = (unsigned int)/*SAFE*/(sizeof chunks_to_ignore)/5U; + } + + else /* num_chunks_in > 0 */ + { + if (chunk_list == NULL) + { + /* Prior to 1.6.0 this was silently ignored, now it is an app_error + * which can be switched off. + */ + png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list"); + + return; + } + + num_chunks = num_chunks_in; + } + + old_num_chunks = png_ptr->num_chunk_list; + if (png_ptr->chunk_list == NULL) + old_num_chunks = 0; + + /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow. + */ + if (num_chunks + old_num_chunks > UINT_MAX/5) + { + png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks"); + + return; + } + + /* If these chunks are being reset to the default then no more memory is + * required because add_one_chunk above doesn't extend the list if the 'keep' + * parameter is the default. + */ + if (keep != 0) + { + new_list = png_voidcast(png_bytep, png_malloc(png_ptr, + 5 * (num_chunks + old_num_chunks))); + + if (old_num_chunks > 0) + memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks); + } + + else if (old_num_chunks > 0) + new_list = png_ptr->chunk_list; + + else + new_list = NULL; + + /* Add the new chunks together with each one's handling code. If the chunk + * already exists the code is updated, otherwise the chunk is added to the + * end. (In libpng 1.6.0 order no longer matters because this code enforces + * the earlier convention that the last setting is the one that is used.) + */ + if (new_list != NULL) + { + png_const_bytep inlist; + png_bytep outlist; + unsigned int i; + + for (i=0; ichunk_list != new_list) + png_free(png_ptr, new_list); + + new_list = NULL; + } + } + + else + num_chunks = 0; + + png_ptr->num_chunk_list = num_chunks; + + if (png_ptr->chunk_list != new_list) + { + if (png_ptr->chunk_list != NULL) + png_free(png_ptr, png_ptr->chunk_list); + + png_ptr->chunk_list = new_list; + } +} +#endif + +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED +void PNGAPI +png_set_read_user_chunk_fn(png_structrp png_ptr, png_voidp user_chunk_ptr, + png_user_chunk_ptr read_user_chunk_fn) +{ + png_debug(1, "in png_set_read_user_chunk_fn"); + + if (png_ptr == NULL) + return; + + png_ptr->read_user_chunk_fn = read_user_chunk_fn; + png_ptr->user_chunk_ptr = user_chunk_ptr; +} +#endif + +#ifdef PNG_INFO_IMAGE_SUPPORTED +void PNGAPI +png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr, + png_bytepp row_pointers) +{ + png_debug1(1, "in %s storage function", "rows"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (info_ptr->row_pointers != NULL && + (info_ptr->row_pointers != row_pointers)) + png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); + + info_ptr->row_pointers = row_pointers; + + if (row_pointers != NULL) + info_ptr->valid |= PNG_INFO_IDAT; +} +#endif + +void PNGAPI +png_set_compression_buffer_size(png_structrp png_ptr, png_size_t size) +{ + if (png_ptr == NULL) + return; + + if (size == 0 || size > PNG_UINT_31_MAX) + png_error(png_ptr, "invalid compression buffer size"); + +# ifdef PNG_SEQUENTIAL_READ_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) + { + png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */ + return; + } +# endif + +# ifdef PNG_WRITE_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) + { + if (png_ptr->zowner != 0) + { + png_warning(png_ptr, + "Compression buffer size cannot be changed because it is in use"); + + return; + } + +#ifndef __COVERITY__ + /* Some compilers complain that this is always false. However, it + * can be true when integer overflow happens. + */ + if (size > ZLIB_IO_MAX) + { + png_warning(png_ptr, + "Compression buffer size limited to system maximum"); + size = ZLIB_IO_MAX; /* must fit */ + } +#endif + + if (size < 6) + { + /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH + * if this is permitted. + */ + png_warning(png_ptr, + "Compression buffer size cannot be reduced below 6"); + + return; + } + + if (png_ptr->zbuffer_size != size) + { + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); + png_ptr->zbuffer_size = (uInt)size; + } + } +# endif +} + +void PNGAPI +png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask) +{ + if (png_ptr != NULL && info_ptr != NULL) + info_ptr->valid &= ~mask; +} + + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +/* This function was added to libpng 1.2.6 */ +void PNGAPI +png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max, + png_uint_32 user_height_max) +{ + /* Images with dimensions larger than these limits will be + * rejected by png_set_IHDR(). To accept any PNG datastream + * regardless of dimensions, set both limits to 0x7fffffff. + */ + if (png_ptr == NULL) + return; + + png_ptr->user_width_max = user_width_max; + png_ptr->user_height_max = user_height_max; +} + +/* This function was added to libpng 1.4.0 */ +void PNGAPI +png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max) +{ + if (png_ptr != NULL) + png_ptr->user_chunk_cache_max = user_chunk_cache_max; +} + +/* This function was added to libpng 1.4.1 */ +void PNGAPI +png_set_chunk_malloc_max (png_structrp png_ptr, + png_alloc_size_t user_chunk_malloc_max) +{ + if (png_ptr != NULL) + png_ptr->user_chunk_malloc_max = user_chunk_malloc_max; +} +#endif /* ?SET_USER_LIMITS */ + + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +void PNGAPI +png_set_benign_errors(png_structrp png_ptr, int allowed) +{ + png_debug(1, "in png_set_benign_errors"); + + /* If allowed is 1, png_benign_error() is treated as a warning. + * + * If allowed is 0, png_benign_error() is treated as an error (which + * is the default behavior if png_set_benign_errors() is not called). + */ + + if (allowed != 0) + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN | + PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN; + + else + png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN | + PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN); +} +#endif /* BENIGN_ERRORS */ + +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Whether to report invalid palette index; added at libng-1.5.10. + * It is possible for an indexed (color-type==3) PNG file to contain + * pixels with invalid (out-of-range) indexes if the PLTE chunk has + * fewer entries than the image's bit-depth would allow. We recover + * from this gracefully by filling any incomplete palette with zeros + * (opaque black). By default, when this occurs libpng will issue + * a benign error. This API can be used to override that behavior. + */ +void PNGAPI +png_set_check_for_invalid_index(png_structrp png_ptr, int allowed) +{ + png_debug(1, "in png_set_check_for_invalid_index"); + + if (allowed > 0) + png_ptr->num_palette_max = 0; + + else + png_ptr->num_palette_max = -1; +} +#endif + +#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) || \ + defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) +/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, + * and if invalid, correct the keyword rather than discarding the entire + * chunk. The PNG 1.0 specification requires keywords 1-79 characters in + * length, forbids leading or trailing whitespace, multiple internal spaces, + * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. + * + * The 'new_key' buffer must be 80 characters in size (for the keyword plus a + * trailing '\0'). If this routine returns 0 then there was no keyword, or a + * valid one could not be generated, and the caller must png_error. + */ +png_uint_32 /* PRIVATE */ +png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key) +{ + png_const_charp orig_key = key; + png_uint_32 key_len = 0; + int bad_character = 0; + int space = 1; + + png_debug(1, "in png_check_keyword"); + + if (key == NULL) + { + *new_key = 0; + return 0; + } + + while (*key && key_len < 79) + { + png_byte ch = (png_byte)*key++; + + if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/)) + *new_key++ = ch, ++key_len, space = 0; + + else if (space == 0) + { + /* A space or an invalid character when one wasn't seen immediately + * before; output just a space. + */ + *new_key++ = 32, ++key_len, space = 1; + + /* If the character was not a space then it is invalid. */ + if (ch != 32) + bad_character = ch; + } + + else if (bad_character == 0) + bad_character = ch; /* just skip it, record the first error */ + } + + if (key_len > 0 && space != 0) /* trailing space */ + { + --key_len, --new_key; + if (bad_character == 0) + bad_character = 32; + } + + /* Terminate the keyword */ + *new_key = 0; + + if (key_len == 0) + return 0; + +#ifdef PNG_WARNINGS_SUPPORTED + /* Try to only output one warning per keyword: */ + if (*key != 0) /* keyword too long */ + png_warning(png_ptr, "keyword truncated"); + + else if (bad_character != 0) + { + PNG_WARNING_PARAMETERS(p) + + png_warning_parameter(p, 1, orig_key); + png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character); + + png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'"); + } +#endif /* WARNINGS */ + + return key_len; +} +#endif /* TEXT || pCAL || iCCP || sPLT */ +#endif /* READ || WRITE */ diff --git a/source/Irrlicht/libpng/pngstruct.h b/source/Irrlicht/libpng/pngstruct.h new file mode 100644 index 00000000..c8e2068a --- /dev/null +++ b/source/Irrlicht/libpng/pngstruct.h @@ -0,0 +1,483 @@ + +/* pngstruct.h - header file for PNG reference library + * + * Last changed in libpng 1.6.18 [July 23, 2015] + * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +/* The structure that holds the information to read and write PNG files. + * The only people who need to care about what is inside of this are the + * people who will be modifying the library for their own special needs. + * It should NOT be accessed directly by an application. + */ + +#ifndef PNGSTRUCT_H +#define PNGSTRUCT_H +/* zlib.h defines the structure z_stream, an instance of which is included + * in this structure and is required for decompressing the LZ compressed + * data in PNG files. + */ +#ifndef ZLIB_CONST + /* We must ensure that zlib uses 'const' in declarations. */ +# define ZLIB_CONST +#endif +#include "zlib.h" +#ifdef const + /* zlib.h sometimes #defines const to nothing, undo this. */ +# undef const +#endif + +/* zlib.h has mediocre z_const use before 1.2.6, this stuff is for compatibility + * with older builds. + */ +#if ZLIB_VERNUM < 0x1260 +# define PNGZ_MSG_CAST(s) png_constcast(char*,s) +# define PNGZ_INPUT_CAST(b) png_constcast(png_bytep,b) +#else +# define PNGZ_MSG_CAST(s) (s) +# define PNGZ_INPUT_CAST(b) (b) +#endif + +/* zlib.h declares a magic type 'uInt' that limits the amount of data that zlib + * can handle at once. This type need be no larger than 16 bits (so maximum of + * 65535), this define allows us to discover how big it is, but limited by the + * maximuum for png_size_t. The value can be overriden in a library build + * (pngusr.h, or set it in CPPFLAGS) and it works to set it to a considerably + * lower value (e.g. 255 works). A lower value may help memory usage (slightly) + * and may even improve performance on some systems (and degrade it on others.) + */ +#ifndef ZLIB_IO_MAX +# define ZLIB_IO_MAX ((uInt)-1) +#endif + +#ifdef PNG_WRITE_SUPPORTED +/* The type of a compression buffer list used by the write code. */ +typedef struct png_compression_buffer +{ + struct png_compression_buffer *next; + png_byte output[1]; /* actually zbuf_size */ +} png_compression_buffer, *png_compression_bufferp; + +#define PNG_COMPRESSION_BUFFER_SIZE(pp)\ + (offsetof(png_compression_buffer, output) + (pp)->zbuffer_size) +#endif + +/* Colorspace support; structures used in png_struct, png_info and in internal + * functions to hold and communicate information about the color space. + * + * PNG_COLORSPACE_SUPPORTED is only required if the application will perform + * colorspace corrections, otherwise all the colorspace information can be + * skipped and the size of libpng can be reduced (significantly) by compiling + * out the colorspace support. + */ +#ifdef PNG_COLORSPACE_SUPPORTED +/* The chromaticities of the red, green and blue colorants and the chromaticity + * of the corresponding white point (i.e. of rgb(1.0,1.0,1.0)). + */ +typedef struct png_xy +{ + png_fixed_point redx, redy; + png_fixed_point greenx, greeny; + png_fixed_point bluex, bluey; + png_fixed_point whitex, whitey; +} png_xy; + +/* The same data as above but encoded as CIE XYZ values. When this data comes + * from chromaticities the sum of the Y values is assumed to be 1.0 + */ +typedef struct png_XYZ +{ + png_fixed_point red_X, red_Y, red_Z; + png_fixed_point green_X, green_Y, green_Z; + png_fixed_point blue_X, blue_Y, blue_Z; +} png_XYZ; +#endif /* COLORSPACE */ + +#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) +/* A colorspace is all the above plus, potentially, profile information; + * however at present libpng does not use the profile internally so it is only + * stored in the png_info struct (if iCCP is supported.) The rendering intent + * is retained here and is checked. + * + * The file gamma encoding information is also stored here and gamma correction + * is done by libpng, whereas color correction must currently be done by the + * application. + */ +typedef struct png_colorspace +{ +#ifdef PNG_GAMMA_SUPPORTED + png_fixed_point gamma; /* File gamma */ +#endif + +#ifdef PNG_COLORSPACE_SUPPORTED + png_xy end_points_xy; /* End points as chromaticities */ + png_XYZ end_points_XYZ; /* End points as CIE XYZ colorant values */ + png_uint_16 rendering_intent; /* Rendering intent of a profile */ +#endif + + /* Flags are always defined to simplify the code. */ + png_uint_16 flags; /* As defined below */ +} png_colorspace, * PNG_RESTRICT png_colorspacerp; + +typedef const png_colorspace * PNG_RESTRICT png_const_colorspacerp; + +/* General flags for the 'flags' field */ +#define PNG_COLORSPACE_HAVE_GAMMA 0x0001 +#define PNG_COLORSPACE_HAVE_ENDPOINTS 0x0002 +#define PNG_COLORSPACE_HAVE_INTENT 0x0004 +#define PNG_COLORSPACE_FROM_gAMA 0x0008 +#define PNG_COLORSPACE_FROM_cHRM 0x0010 +#define PNG_COLORSPACE_FROM_sRGB 0x0020 +#define PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB 0x0040 +#define PNG_COLORSPACE_MATCHES_sRGB 0x0080 /* exact match on profile */ +#define PNG_COLORSPACE_INVALID 0x8000 +#define PNG_COLORSPACE_CANCEL(flags) (0xffff ^ (flags)) +#endif /* COLORSPACE || GAMMA */ + +struct png_struct_def +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf jmp_buf_local; /* New name in 1.6.0 for jmp_buf in png_struct */ + png_longjmp_ptr longjmp_fn;/* setjmp non-local goto function. */ + jmp_buf *jmp_buf_ptr; /* passed to longjmp_fn */ + size_t jmp_buf_size; /* size of the above, if allocated */ +#endif + png_error_ptr error_fn; /* function for printing errors and aborting */ +#ifdef PNG_WARNINGS_SUPPORTED + png_error_ptr warning_fn; /* function for printing warnings */ +#endif + png_voidp error_ptr; /* user supplied struct for error functions */ + png_rw_ptr write_data_fn; /* function for writing output data */ + png_rw_ptr read_data_fn; /* function for reading input data */ + png_voidp io_ptr; /* ptr to application struct for I/O functions */ + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + png_user_transform_ptr read_user_transform_fn; /* user read transform */ +#endif + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + png_user_transform_ptr write_user_transform_fn; /* user write transform */ +#endif + +/* These were added in libpng-1.0.2 */ +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + png_voidp user_transform_ptr; /* user supplied struct for user transform */ + png_byte user_transform_depth; /* bit depth of user transformed pixels */ + png_byte user_transform_channels; /* channels in user transformed pixels */ +#endif +#endif + + png_uint_32 mode; /* tells us where we are in the PNG file */ + png_uint_32 flags; /* flags indicating various things to libpng */ + png_uint_32 transformations; /* which transformations to perform */ + + png_uint_32 zowner; /* ID (chunk type) of zstream owner, 0 if none */ + z_stream zstream; /* decompression structure */ + +#ifdef PNG_WRITE_SUPPORTED + png_compression_bufferp zbuffer_list; /* Created on demand during write */ + uInt zbuffer_size; /* size of the actual buffer */ + + int zlib_level; /* holds zlib compression level */ + int zlib_method; /* holds zlib compression method */ + int zlib_window_bits; /* holds zlib compression window bits */ + int zlib_mem_level; /* holds zlib compression memory level */ + int zlib_strategy; /* holds zlib compression strategy */ +#endif +/* Added at libpng 1.5.4 */ +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED + int zlib_text_level; /* holds zlib compression level */ + int zlib_text_method; /* holds zlib compression method */ + int zlib_text_window_bits; /* holds zlib compression window bits */ + int zlib_text_mem_level; /* holds zlib compression memory level */ + int zlib_text_strategy; /* holds zlib compression strategy */ +#endif +/* End of material added at libpng 1.5.4 */ +/* Added at libpng 1.6.0 */ +#ifdef PNG_WRITE_SUPPORTED + int zlib_set_level; /* Actual values set into the zstream on write */ + int zlib_set_method; + int zlib_set_window_bits; + int zlib_set_mem_level; + int zlib_set_strategy; +#endif + + png_uint_32 width; /* width of image in pixels */ + png_uint_32 height; /* height of image in pixels */ + png_uint_32 num_rows; /* number of rows in current pass */ + png_uint_32 usr_width; /* width of row at start of write */ + png_size_t rowbytes; /* size of row in bytes */ + png_uint_32 iwidth; /* width of current interlaced row in pixels */ + png_uint_32 row_number; /* current row in interlace pass */ + png_uint_32 chunk_name; /* PNG_CHUNK() id of current chunk */ + png_bytep prev_row; /* buffer to save previous (unfiltered) row. + * While reading this is a pointer into + * big_prev_row; while writing it is separately + * allocated if needed. + */ + png_bytep row_buf; /* buffer to save current (unfiltered) row. + * While reading, this is a pointer into + * big_row_buf; while writing it is separately + * allocated. + */ +#ifdef PNG_WRITE_FILTER_SUPPORTED + png_bytep try_row; /* buffer to save trial row when filtering */ + png_bytep tst_row; /* buffer to save best trial row when filtering */ +#endif + png_size_t info_rowbytes; /* Added in 1.5.4: cache of updated row bytes */ + + png_uint_32 idat_size; /* current IDAT size for read */ + png_uint_32 crc; /* current chunk CRC value */ + png_colorp palette; /* palette from the input file */ + png_uint_16 num_palette; /* number of color entries in palette */ + +/* Added at libpng-1.5.10 */ +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED + int num_palette_max; /* maximum palette index found in IDAT */ +#endif + + png_uint_16 num_trans; /* number of transparency values */ + png_byte compression; /* file compression type (always 0) */ + png_byte filter; /* file filter type (always 0) */ + png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ + png_byte pass; /* current interlace pass (0 - 6) */ + png_byte do_filter; /* row filter flags (see PNG_FILTER_ below ) */ + png_byte color_type; /* color type of file */ + png_byte bit_depth; /* bit depth of file */ + png_byte usr_bit_depth; /* bit depth of users row: write only */ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte channels; /* number of channels in file */ +#ifdef PNG_WRITE_SUPPORTED + png_byte usr_channels; /* channels at start of write: write only */ +#endif + png_byte sig_bytes; /* magic bytes read/written from start of file */ + png_byte maximum_pixel_depth; + /* pixel depth used for the row buffers */ + png_byte transformed_pixel_depth; + /* pixel depth after read/write transforms */ +#if PNG_ZLIB_VERNUM >= 0x1240 + png_byte zstream_start; /* at start of an input zlib stream */ +#endif /* Zlib >= 1.2.4 */ +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) + png_uint_16 filler; /* filler bytes for pixel expansion */ +#endif + +#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + png_byte background_gamma_type; + png_fixed_point background_gamma; + png_color_16 background; /* background color in screen gamma space */ +#ifdef PNG_READ_GAMMA_SUPPORTED + png_color_16 background_1; /* background normalized to gamma 1.0 */ +#endif +#endif /* bKGD */ + +#ifdef PNG_WRITE_FLUSH_SUPPORTED + png_flush_ptr output_flush_fn; /* Function for flushing output */ + png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */ + png_uint_32 flush_rows; /* number of rows written since last flush */ +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED + int gamma_shift; /* number of "insignificant" bits in 16-bit gamma */ + png_fixed_point screen_gamma; /* screen gamma value (display_exponent) */ + + png_bytep gamma_table; /* gamma table for 8-bit depth files */ + png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */ +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + png_bytep gamma_from_1; /* converts from 1.0 to screen */ + png_bytep gamma_to_1; /* converts from file to 1.0 */ + png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */ + png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */ +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED) + png_color_8 sig_bit; /* significant bits in each available channel */ +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) + png_color_8 shift; /* shift for significant bit tranformation */ +#endif + +#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \ + || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_bytep trans_alpha; /* alpha values for paletted files */ + png_color_16 trans_color; /* transparent color for non-paletted files */ +#endif + + png_read_status_ptr read_row_fn; /* called after each row is decoded */ + png_write_status_ptr write_row_fn; /* called after each row is encoded */ +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + png_progressive_info_ptr info_fn; /* called after header data fully read */ + png_progressive_row_ptr row_fn; /* called after a prog. row is decoded */ + png_progressive_end_ptr end_fn; /* called after image is complete */ + png_bytep save_buffer_ptr; /* current location in save_buffer */ + png_bytep save_buffer; /* buffer for previously read data */ + png_bytep current_buffer_ptr; /* current location in current_buffer */ + png_bytep current_buffer; /* buffer for recently used data */ + png_uint_32 push_length; /* size of current input chunk */ + png_uint_32 skip_length; /* bytes to skip in input data */ + png_size_t save_buffer_size; /* amount of data now in save_buffer */ + png_size_t save_buffer_max; /* total size of save_buffer */ + png_size_t buffer_size; /* total amount of available input data */ + png_size_t current_buffer_size; /* amount of data now in current_buffer */ + int process_mode; /* what push library is currently doing */ + int cur_palette; /* current push library palette index */ + +#endif /* PROGRESSIVE_READ */ + +#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) +/* For the Borland special 64K segment handler */ + png_bytepp offset_table_ptr; + png_bytep offset_table; + png_uint_16 offset_table_number; + png_uint_16 offset_table_count; + png_uint_16 offset_table_count_free; +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + png_bytep palette_lookup; /* lookup table for quantizing */ + png_bytep quantize_index; /* index translation for palette files */ +#endif + +/* Options */ +#ifdef PNG_SET_OPTION_SUPPORTED + png_byte options; /* On/off state (up to 4 options) */ +#endif + +#if PNG_LIBPNG_VER < 10700 +/* To do: remove this from libpng-1.7 */ +#ifdef PNG_TIME_RFC1123_SUPPORTED + char time_buffer[29]; /* String to hold RFC 1123 time text */ +#endif +#endif + +/* New members added in libpng-1.0.6 */ + + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ + +#ifdef PNG_USER_CHUNKS_SUPPORTED + png_voidp user_chunk_ptr; +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */ +#endif +#endif + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + int unknown_default; /* As PNG_HANDLE_* */ + unsigned int num_chunk_list; /* Number of entries in the list */ + png_bytep chunk_list; /* List of png_byte[5]; the textual chunk name + * followed by a PNG_HANDLE_* byte */ +#endif + +/* New members added in libpng-1.0.3 */ +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + png_byte rgb_to_gray_status; + /* Added in libpng 1.5.5 to record setting of coefficients: */ + png_byte rgb_to_gray_coefficients_set; + /* These were changed from png_byte in libpng-1.0.6 */ + png_uint_16 rgb_to_gray_red_coeff; + png_uint_16 rgb_to_gray_green_coeff; + /* deleted in 1.5.5: rgb_to_gray_blue_coeff; */ +#endif + +/* New member added in libpng-1.0.4 (renamed in 1.0.9) */ +#if defined(PNG_MNG_FEATURES_SUPPORTED) +/* Changed from png_byte to png_uint_32 at version 1.2.0 */ + png_uint_32 mng_features_permitted; +#endif + +/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */ +#ifdef PNG_MNG_FEATURES_SUPPORTED + png_byte filter_type; +#endif + +/* New members added in libpng-1.2.0 */ + +/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */ +#ifdef PNG_USER_MEM_SUPPORTED + png_voidp mem_ptr; /* user supplied struct for mem functions */ + png_malloc_ptr malloc_fn; /* function for allocating memory */ + png_free_ptr free_fn; /* function for freeing memory */ +#endif + +/* New member added in libpng-1.0.13 and 1.2.0 */ + png_bytep big_row_buf; /* buffer to save current (unfiltered) row */ + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +/* The following three members were added at version 1.0.14 and 1.2.4 */ + png_bytep quantize_sort; /* working sort array */ + png_bytep index_to_palette; /* where the original index currently is + in the palette */ + png_bytep palette_to_index; /* which original index points to this + palette color */ +#endif + +/* New members added in libpng-1.0.16 and 1.2.6 */ + png_byte compression_type; + +#ifdef PNG_USER_LIMITS_SUPPORTED + png_uint_32 user_width_max; + png_uint_32 user_height_max; + + /* Added in libpng-1.4.0: Total number of sPLT, text, and unknown + * chunks that can be stored (0 means unlimited). + */ + png_uint_32 user_chunk_cache_max; + + /* Total memory that a zTXt, sPLT, iTXt, iCCP, or unknown chunk + * can occupy when decompressed. 0 means unlimited. + */ + png_alloc_size_t user_chunk_malloc_max; +#endif + +/* New member added in libpng-1.0.25 and 1.2.17 */ +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + /* Temporary storage for unknown chunk that the library doesn't recognize, + * used while reading the chunk. + */ + png_unknown_chunk unknown_chunk; +#endif + +/* New member added in libpng-1.2.26 */ + png_size_t old_big_row_buf_size; + +#ifdef PNG_READ_SUPPORTED +/* New member added in libpng-1.2.30 */ + png_bytep read_buffer; /* buffer for reading chunk data */ + png_alloc_size_t read_buffer_size; /* current size of the buffer */ +#endif +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED + uInt IDAT_read_size; /* limit on read buffer size for IDAT */ +#endif + +#ifdef PNG_IO_STATE_SUPPORTED +/* New member added in libpng-1.4.0 */ + png_uint_32 io_state; +#endif + +/* New member added in libpng-1.5.6 */ + png_bytep big_prev_row; + +/* New member added in libpng-1.5.7 */ + void (*read_filter[PNG_FILTER_VALUE_LAST-1])(png_row_infop row_info, + png_bytep row, png_const_bytep prev_row); + +#ifdef PNG_READ_SUPPORTED +#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) + png_colorspace colorspace; +#endif +#endif +}; +#endif /* PNGSTRUCT_H */ diff --git a/source/Irrlicht/libpng/pngtest.c b/source/Irrlicht/libpng/pngtest.c new file mode 100644 index 00000000..792bd039 --- /dev/null +++ b/source/Irrlicht/libpng/pngtest.c @@ -0,0 +1,2082 @@ + +/* pngtest.c - a simple test program to test libpng + * + * Last changed in libpng 1.5.25 [December 3, 2015] + * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This program reads in a PNG image, writes it out again, and then + * compares the two files. If the files are identical, this shows that + * the basic chunk handling, filtering, and (de)compression code is working + * properly. It does not currently test all of the transforms, although + * it probably should. + * + * The program will report "FAIL" in certain legitimate cases: + * 1) when the compression level or filter selection method is changed. + * 2) when the maximum IDAT size (PNG_ZBUF_SIZE in pngconf.h) is not 8192. + * 3) unknown unsafe-to-copy ancillary chunks or unknown critical chunks + * exist in the input file. + * 4) others not listed here... + * In these cases, it is best to check with another tool such as "pngcheck" + * to see what the differences between the two files are. + * + * If a filename is given on the command-line, then this file is used + * for the input, rather than the default "pngtest.png". This allows + * testing a wide variety of files easily. You can also test a number + * of files at once by typing "pngtest -m file1.png file2.png ..." + */ + +#define _POSIX_SOURCE 1 + +#include +#include +#include + +/* Defined so I can write to a file on gui/windowing platforms */ +/* #define STDERR stderr */ +#define STDERR stdout /* For DOS */ + +#include "png.h" + +/* 1.6.1 added support for the configure test harness, which uses 77 to indicate + * a skipped test, in earlier versions we need to succeed on a skipped test, so: + */ +#if PNG_LIBPNG_VER >= 10601 && defined(HAVE_CONFIG_H) +# define SKIP 77 +#else +# define SKIP 0 +#endif + +/* Known chunks that exist in pngtest.png must be supported or pngtest will fail + * simply as a result of re-ordering them. This may be fixed in 1.7 + * + * pngtest allocates a single row buffer for each row and overwrites it, + * therefore if the write side doesn't support the writing of interlaced images + * nothing can be done for an interlaced image (and the code below will fail + * horribly trying to write extra data after writing garbage). + */ +#if defined PNG_READ_SUPPORTED && /* else nothing can be done */\ + defined PNG_READ_bKGD_SUPPORTED &&\ + defined PNG_READ_cHRM_SUPPORTED &&\ + defined PNG_READ_gAMA_SUPPORTED &&\ + defined PNG_READ_oFFs_SUPPORTED &&\ + defined PNG_READ_pCAL_SUPPORTED &&\ + defined PNG_READ_pHYs_SUPPORTED &&\ + defined PNG_READ_sBIT_SUPPORTED &&\ + defined PNG_READ_sCAL_SUPPORTED &&\ + defined PNG_READ_sRGB_SUPPORTED &&\ + defined PNG_READ_sPLT_SUPPORTED &&\ + defined PNG_READ_tEXt_SUPPORTED &&\ + defined PNG_READ_tIME_SUPPORTED &&\ + defined PNG_READ_zTXt_SUPPORTED &&\ + (defined PNG_WRITE_INTERLACING_SUPPORTED || PNG_LIBPNG_VER >= 10700) + +#ifdef PNG_ZLIB_HEADER +# include PNG_ZLIB_HEADER /* defined by pnglibconf.h from 1.7 */ +#else +# include "zlib.h" +#endif + +/* Copied from pngpriv.h but only used in error messages below. */ +#ifndef PNG_ZBUF_SIZE +# define PNG_ZBUF_SIZE 8192 +#endif +#define FCLOSE(file) fclose(file) + +#ifndef PNG_STDIO_SUPPORTED +typedef FILE * png_FILE_p; +#endif + +/* Makes pngtest verbose so we can find problems. */ +#ifndef PNG_DEBUG +# define PNG_DEBUG 0 +#endif + +#if PNG_DEBUG > 1 +# define pngtest_debug(m) ((void)fprintf(stderr, m "\n")) +# define pngtest_debug1(m,p1) ((void)fprintf(stderr, m "\n", p1)) +# define pngtest_debug2(m,p1,p2) ((void)fprintf(stderr, m "\n", p1, p2)) +#else +# define pngtest_debug(m) ((void)0) +# define pngtest_debug1(m,p1) ((void)0) +# define pngtest_debug2(m,p1,p2) ((void)0) +#endif + +#if !PNG_DEBUG +# define SINGLE_ROWBUF_ALLOC /* Makes buffer overruns easier to nail */ +#endif + +#ifndef PNG_UNUSED +# define PNG_UNUSED(param) (void)param; +#endif + +/* Turn on CPU timing +#define PNGTEST_TIMING +*/ + +#ifndef PNG_FLOATING_POINT_SUPPORTED +#undef PNGTEST_TIMING +#endif + +#ifdef PNGTEST_TIMING +static float t_start, t_stop, t_decode, t_encode, t_misc; +#include +#endif + +#ifdef PNG_TIME_RFC1123_SUPPORTED +#define PNG_tIME_STRING_LENGTH 29 +static int tIME_chunk_present = 0; +static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present"; + +#if PNG_LIBPNG_VER < 10619 +#define png_convert_to_rfc1123_buffer(ts, t) tIME_to_str(read_ptr, ts, t) + +static int +tIME_to_str(png_structp png_ptr, png_charp ts, png_const_timep t) +{ + png_const_charp str = png_convert_to_rfc1123(png_ptr, t); + + if (str == NULL) + return 0; + + strcpy(ts, str); + return 1; +} +#endif /* older libpng */ +#endif + +static int verbose = 0; +static int strict = 0; +static int relaxed = 0; +static int unsupported_chunks = 0; /* chunk unsupported by libpng in input */ +static int error_count = 0; /* count calls to png_error */ +static int warning_count = 0; /* count calls to png_warning */ + +/* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */ +#ifndef png_jmpbuf +# define png_jmpbuf(png_ptr) png_ptr->jmpbuf +#endif + +/* Defines for unknown chunk handling if required. */ +#ifndef PNG_HANDLE_CHUNK_ALWAYS +# define PNG_HANDLE_CHUNK_ALWAYS 3 +#endif +#ifndef PNG_HANDLE_CHUNK_IF_SAFE +# define PNG_HANDLE_CHUNK_IF_SAFE 2 +#endif + +/* Utility to save typing/errors, the argument must be a name */ +#define MEMZERO(var) ((void)memset(&var, 0, sizeof var)) + +/* Example of using row callbacks to make a simple progress meter */ +static int status_pass = 1; +static int status_dots_requested = 0; +static int status_dots = 1; + +static void PNGCBAPI +read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) +{ + if (png_ptr == NULL || row_number > PNG_UINT_31_MAX) + return; + + if (status_pass != pass) + { + fprintf(stdout, "\n Pass %d: ", pass); + status_pass = pass; + status_dots = 31; + } + + status_dots--; + + if (status_dots == 0) + { + fprintf(stdout, "\n "); + status_dots=30; + } + + fprintf(stdout, "r"); +} + +#ifdef PNG_WRITE_SUPPORTED +static void PNGCBAPI +write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) +{ + if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7) + return; + + fprintf(stdout, "w"); +} +#endif + + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED +/* Example of using a user transform callback (doesn't do anything at present). + */ +static void PNGCBAPI +read_user_callback(png_structp png_ptr, png_row_infop row_info, png_bytep data) +{ + PNG_UNUSED(png_ptr) + PNG_UNUSED(row_info) + PNG_UNUSED(data) +} +#endif + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED +/* Example of using user transform callback (we don't transform anything, + * but merely count the zero samples) + */ + +static png_uint_32 zero_samples; + +static void PNGCBAPI +count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data) +{ + png_bytep dp = data; + if (png_ptr == NULL) + return; + + /* Contents of row_info: + * png_uint_32 width width of row + * png_uint_32 rowbytes number of bytes in row + * png_byte color_type color type of pixels + * png_byte bit_depth bit depth of samples + * png_byte channels number of channels (1-4) + * png_byte pixel_depth bits per pixel (depth*channels) + */ + + /* Counts the number of zero samples (or zero pixels if color_type is 3 */ + + if (row_info->color_type == 0 || row_info->color_type == 3) + { + int pos = 0; + png_uint_32 n, nstop; + + for (n = 0, nstop=row_info->width; nbit_depth == 1) + { + if (((*dp << pos++ ) & 0x80) == 0) + zero_samples++; + + if (pos == 8) + { + pos = 0; + dp++; + } + } + + if (row_info->bit_depth == 2) + { + if (((*dp << (pos+=2)) & 0xc0) == 0) + zero_samples++; + + if (pos == 8) + { + pos = 0; + dp++; + } + } + + if (row_info->bit_depth == 4) + { + if (((*dp << (pos+=4)) & 0xf0) == 0) + zero_samples++; + + if (pos == 8) + { + pos = 0; + dp++; + } + } + + if (row_info->bit_depth == 8) + if (*dp++ == 0) + zero_samples++; + + if (row_info->bit_depth == 16) + { + if ((*dp | *(dp+1)) == 0) + zero_samples++; + dp+=2; + } + } + } + else /* Other color types */ + { + png_uint_32 n, nstop; + int channel; + int color_channels = row_info->channels; + if (row_info->color_type > 3) + color_channels--; + + for (n = 0, nstop=row_info->width; nbit_depth == 8) + if (*dp++ == 0) + zero_samples++; + + if (row_info->bit_depth == 16) + { + if ((*dp | *(dp+1)) == 0) + zero_samples++; + + dp+=2; + } + } + if (row_info->color_type > 3) + { + dp++; + if (row_info->bit_depth == 16) + dp++; + } + } + } +} +#endif /* WRITE_USER_TRANSFORM */ + +#ifndef PNG_STDIO_SUPPORTED +/* START of code to validate stdio-free compilation */ +/* These copies of the default read/write functions come from pngrio.c and + * pngwio.c. They allow "don't include stdio" testing of the library. + * This is the function that does the actual reading of data. If you are + * not reading from a standard C stream, you should create a replacement + * read_data function and use it at run time with png_set_read_fn(), rather + * than changing the library. + */ + +#ifdef PNG_IO_STATE_SUPPORTED +void +pngtest_check_io_state(png_structp png_ptr, png_size_t data_length, + png_uint_32 io_op); +void +pngtest_check_io_state(png_structp png_ptr, png_size_t data_length, + png_uint_32 io_op) +{ + png_uint_32 io_state = png_get_io_state(png_ptr); + int err = 0; + + /* Check if the current operation (reading / writing) is as expected. */ + if ((io_state & PNG_IO_MASK_OP) != io_op) + png_error(png_ptr, "Incorrect operation in I/O state"); + + /* Check if the buffer size specific to the current location + * (file signature / header / data / crc) is as expected. + */ + switch (io_state & PNG_IO_MASK_LOC) + { + case PNG_IO_SIGNATURE: + if (data_length > 8) + err = 1; + break; + case PNG_IO_CHUNK_HDR: + if (data_length != 8) + err = 1; + break; + case PNG_IO_CHUNK_DATA: + break; /* no restrictions here */ + case PNG_IO_CHUNK_CRC: + if (data_length != 4) + err = 1; + break; + default: + err = 1; /* uninitialized */ + } + if (err != 0) + png_error(png_ptr, "Bad I/O state or buffer size"); +} +#endif + +static void PNGCBAPI +pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check = 0; + png_voidp io_ptr; + + /* fread() returns 0 on error, so it is OK to store this in a png_size_t + * instead of an int, which is what fread() actually returns. + */ + io_ptr = png_get_io_ptr(png_ptr); + if (io_ptr != NULL) + { + check = fread(data, 1, length, (png_FILE_p)io_ptr); + } + + if (check != length) + { + png_error(png_ptr, "Read Error"); + } + +#ifdef PNG_IO_STATE_SUPPORTED + pngtest_check_io_state(png_ptr, length, PNG_IO_READING); +#endif +} + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +static void PNGCBAPI +pngtest_flush(png_structp png_ptr) +{ + /* Do nothing; fflush() is said to be just a waste of energy. */ + PNG_UNUSED(png_ptr) /* Stifle compiler warning */ +} +#endif + +/* This is the function that does the actual writing of data. If you are + * not writing to a standard C stream, you should create a replacement + * write_data function and use it at run time with png_set_write_fn(), rather + * than changing the library. + */ +static void PNGCBAPI +pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check; + + check = fwrite(data, 1, length, (png_FILE_p)png_get_io_ptr(png_ptr)); + + if (check != length) + { + png_error(png_ptr, "Write Error"); + } + +#ifdef PNG_IO_STATE_SUPPORTED + pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING); +#endif +} +#endif /* !STDIO */ + +/* This function is called when there is a warning, but the library thinks + * it can continue anyway. Replacement functions don't have to do anything + * here if you don't want to. In the default configuration, png_ptr is + * not used, but it is passed in case it may be useful. + */ +typedef struct +{ + PNG_CONST char *file_name; +} pngtest_error_parameters; + +static void PNGCBAPI +pngtest_warning(png_structp png_ptr, png_const_charp message) +{ + PNG_CONST char *name = "UNKNOWN (ERROR!)"; + pngtest_error_parameters *test = + (pngtest_error_parameters*)png_get_error_ptr(png_ptr); + + ++warning_count; + + if (test != NULL && test->file_name != NULL) + name = test->file_name; + + fprintf(STDERR, "%s: libpng warning: %s\n", name, message); +} + +/* This is the default error handling function. Note that replacements for + * this function MUST NOT RETURN, or the program will likely crash. This + * function is used by default, or if the program supplies NULL for the + * error function pointer in png_set_error_fn(). + */ +static void PNGCBAPI +pngtest_error(png_structp png_ptr, png_const_charp message) +{ + ++error_count; + + pngtest_warning(png_ptr, message); + /* We can return because png_error calls the default handler, which is + * actually OK in this case. + */ +} + +/* END of code to validate stdio-free compilation */ + +/* START of code to validate memory allocation and deallocation */ +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + +/* Allocate memory. For reasonable files, size should never exceed + * 64K. However, zlib may allocate more than 64K if you don't tell + * it not to. See zconf.h and png.h for more information. zlib does + * need to allocate exactly 64K, so whatever you call here must + * have the ability to do that. + * + * This piece of code can be compiled to validate max 64K allocations + * by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. + */ +typedef struct memory_information +{ + png_alloc_size_t size; + png_voidp pointer; + struct memory_information *next; +} memory_information; +typedef memory_information *memory_infop; + +static memory_infop pinformation = NULL; +static int current_allocation = 0; +static int maximum_allocation = 0; +static int total_allocation = 0; +static int num_allocations = 0; + +png_voidp PNGCBAPI png_debug_malloc PNGARG((png_structp png_ptr, + png_alloc_size_t size)); +void PNGCBAPI png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr)); + +png_voidp +PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size) +{ + + /* png_malloc has already tested for NULL; png_create_struct calls + * png_debug_malloc directly, with png_ptr == NULL which is OK + */ + + if (size == 0) + return (NULL); + + /* This calls the library allocator twice, once to get the requested + buffer and once to get a new free list entry. */ + { + /* Disable malloc_fn and free_fn */ + memory_infop pinfo; + png_set_mem_fn(png_ptr, NULL, NULL, NULL); + pinfo = (memory_infop)png_malloc(png_ptr, + (sizeof *pinfo)); + pinfo->size = size; + current_allocation += size; + total_allocation += size; + num_allocations ++; + + if (current_allocation > maximum_allocation) + maximum_allocation = current_allocation; + + pinfo->pointer = png_malloc(png_ptr, size); + /* Restore malloc_fn and free_fn */ + + png_set_mem_fn(png_ptr, + NULL, png_debug_malloc, png_debug_free); + + if (size != 0 && pinfo->pointer == NULL) + { + current_allocation -= size; + total_allocation -= size; + png_error(png_ptr, + "out of memory in pngtest->png_debug_malloc"); + } + + pinfo->next = pinformation; + pinformation = pinfo; + /* Make sure the caller isn't assuming zeroed memory. */ + memset(pinfo->pointer, 0xdd, pinfo->size); + + if (verbose != 0) + printf("png_malloc %lu bytes at %p\n", (unsigned long)size, + pinfo->pointer); + + return (png_voidp)(pinfo->pointer); + } +} + +/* Free a pointer. It is removed from the list at the same time. */ +void PNGCBAPI +png_debug_free(png_structp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL) + fprintf(STDERR, "NULL pointer to png_debug_free.\n"); + + if (ptr == 0) + { +#if 0 /* This happens all the time. */ + fprintf(STDERR, "WARNING: freeing NULL pointer\n"); +#endif + return; + } + + /* Unlink the element from the list. */ + if (pinformation != NULL) + { + memory_infop *ppinfo = &pinformation; + + for (;;) + { + memory_infop pinfo = *ppinfo; + + if (pinfo->pointer == ptr) + { + *ppinfo = pinfo->next; + current_allocation -= pinfo->size; + if (current_allocation < 0) + fprintf(STDERR, "Duplicate free of memory\n"); + /* We must free the list element too, but first kill + the memory that is to be freed. */ + memset(ptr, 0x55, pinfo->size); + free(pinfo); + pinfo = NULL; + break; + } + + if (pinfo->next == NULL) + { + fprintf(STDERR, "Pointer %p not found\n", ptr); + break; + } + + ppinfo = &pinfo->next; + } + } + + /* Finally free the data. */ + if (verbose != 0) + printf("Freeing %p\n", ptr); + + if (ptr != NULL) + free(ptr); + ptr = NULL; +} +#endif /* USER_MEM && DEBUG */ +/* END of code to test memory allocation/deallocation */ + + +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED +/* Demonstration of user chunk support of the sTER and vpAg chunks */ + +/* (sTER is a public chunk not yet known by libpng. vpAg is a private +chunk used in ImageMagick to store "virtual page" size). */ + +static struct user_chunk_data +{ + png_const_infop info_ptr; + png_uint_32 vpAg_width, vpAg_height; + png_byte vpAg_units; + png_byte sTER_mode; + int location[2]; +} +user_chunk_data; + +/* Used for location and order; zero means nothing. */ +#define have_sTER 0x01 +#define have_vpAg 0x02 +#define before_PLTE 0x10 +#define before_IDAT 0x20 +#define after_IDAT 0x40 + +static void +init_callback_info(png_const_infop info_ptr) +{ + MEMZERO(user_chunk_data); + user_chunk_data.info_ptr = info_ptr; +} + +static int +set_location(png_structp png_ptr, struct user_chunk_data *data, int what) +{ + int location; + + if ((data->location[0] & what) != 0 || (data->location[1] & what) != 0) + return 0; /* already have one of these */ + + /* Find where we are (the code below zeroes info_ptr to indicate that the + * chunks before the first IDAT have been read.) + */ + if (data->info_ptr == NULL) /* after IDAT */ + location = what | after_IDAT; + + else if (png_get_valid(png_ptr, data->info_ptr, PNG_INFO_PLTE) != 0) + location = what | before_IDAT; + + else + location = what | before_PLTE; + + if (data->location[0] == 0) + data->location[0] = location; + + else + data->location[1] = location; + + return 1; /* handled */ +} + +static int PNGCBAPI +read_user_chunk_callback(png_struct *png_ptr, png_unknown_chunkp chunk) +{ + struct user_chunk_data *my_user_chunk_data = + (struct user_chunk_data*)png_get_user_chunk_ptr(png_ptr); + + if (my_user_chunk_data == NULL) + png_error(png_ptr, "lost user chunk pointer"); + + /* Return one of the following: + * return (-n); chunk had an error + * return (0); did not recognize + * return (n); success + * + * The unknown chunk structure contains the chunk data: + * png_byte name[5]; + * png_byte *data; + * png_size_t size; + * + * Note that libpng has already taken care of the CRC handling. + */ + + if (chunk->name[0] == 115 && chunk->name[1] == 84 && /* s T */ + chunk->name[2] == 69 && chunk->name[3] == 82) /* E R */ + { + /* Found sTER chunk */ + if (chunk->size != 1) + return (-1); /* Error return */ + + if (chunk->data[0] != 0 && chunk->data[0] != 1) + return (-1); /* Invalid mode */ + + if (set_location(png_ptr, my_user_chunk_data, have_sTER) != 0) + { + my_user_chunk_data->sTER_mode=chunk->data[0]; + return (1); + } + + else + return (0); /* duplicate sTER - give it to libpng */ + } + + if (chunk->name[0] != 118 || chunk->name[1] != 112 || /* v p */ + chunk->name[2] != 65 || chunk->name[3] != 103) /* A g */ + return (0); /* Did not recognize */ + + /* Found ImageMagick vpAg chunk */ + + if (chunk->size != 9) + return (-1); /* Error return */ + + if (set_location(png_ptr, my_user_chunk_data, have_vpAg) == 0) + return (0); /* duplicate vpAg */ + + my_user_chunk_data->vpAg_width = png_get_uint_31(png_ptr, chunk->data); + my_user_chunk_data->vpAg_height = png_get_uint_31(png_ptr, chunk->data + 4); + my_user_chunk_data->vpAg_units = chunk->data[8]; + + return (1); +} + +#ifdef PNG_WRITE_SUPPORTED +static void +write_sTER_chunk(png_structp write_ptr) +{ + png_byte sTER[5] = {115, 84, 69, 82, '\0'}; + + if (verbose != 0) + fprintf(STDERR, "\n stereo mode = %d\n", user_chunk_data.sTER_mode); + + png_write_chunk(write_ptr, sTER, &user_chunk_data.sTER_mode, 1); +} + +static void +write_vpAg_chunk(png_structp write_ptr) +{ + png_byte vpAg[5] = {118, 112, 65, 103, '\0'}; + + png_byte vpag_chunk_data[9]; + + if (verbose != 0) + fprintf(STDERR, " vpAg = %lu x %lu, units = %d\n", + (unsigned long)user_chunk_data.vpAg_width, + (unsigned long)user_chunk_data.vpAg_height, + user_chunk_data.vpAg_units); + + png_save_uint_32(vpag_chunk_data, user_chunk_data.vpAg_width); + png_save_uint_32(vpag_chunk_data + 4, user_chunk_data.vpAg_height); + vpag_chunk_data[8] = user_chunk_data.vpAg_units; + png_write_chunk(write_ptr, vpAg, vpag_chunk_data, 9); +} + +static void +write_chunks(png_structp write_ptr, int location) +{ + int i; + + /* Notice that this preserves the original chunk order, however chunks + * intercepted by the callback will be written *after* chunks passed to + * libpng. This will actually reverse a pair of sTER chunks or a pair of + * vpAg chunks, resulting in an error later. This is not worth worrying + * about - the chunks should not be duplicated! + */ + for (i=0; i<2; ++i) + { + if (user_chunk_data.location[i] == (location | have_sTER)) + write_sTER_chunk(write_ptr); + + else if (user_chunk_data.location[i] == (location | have_vpAg)) + write_vpAg_chunk(write_ptr); + } +} +#endif /* WRITE */ +#else /* !READ_USER_CHUNKS */ +# define write_chunks(pp,loc) ((void)0) +#endif +/* END of code to demonstrate user chunk support */ + +/* START of code to check that libpng has the required text support; this only + * checks for the write support because if read support is missing the chunk + * will simply not be reported back to pngtest. + */ +#ifdef PNG_TEXT_SUPPORTED +static void +pngtest_check_text_support(png_structp png_ptr, png_textp text_ptr, + int num_text) +{ + while (num_text > 0) + { + switch (text_ptr[--num_text].compression) + { + case PNG_TEXT_COMPRESSION_NONE: + break; + + case PNG_TEXT_COMPRESSION_zTXt: +# ifndef PNG_WRITE_zTXt_SUPPORTED + ++unsupported_chunks; + /* In libpng 1.7 this now does an app-error, so stop it: */ + text_ptr[num_text].compression = PNG_TEXT_COMPRESSION_NONE; +# endif + break; + + case PNG_ITXT_COMPRESSION_NONE: + case PNG_ITXT_COMPRESSION_zTXt: +# ifndef PNG_WRITE_iTXt_SUPPORTED + ++unsupported_chunks; + text_ptr[num_text].compression = PNG_TEXT_COMPRESSION_NONE; +# endif + break; + + default: + /* This is an error */ + png_error(png_ptr, "invalid text chunk compression field"); + break; + } + } +} +#endif +/* END of code to check that libpng has the required text support */ + +/* Test one file */ +static int +test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) +{ + static png_FILE_p fpin; + static png_FILE_p fpout; /* "static" prevents setjmp corruption */ + pngtest_error_parameters error_parameters; + png_structp read_ptr; + png_infop read_info_ptr, end_info_ptr; +#ifdef PNG_WRITE_SUPPORTED + png_structp write_ptr; + png_infop write_info_ptr; + png_infop write_end_info_ptr; +#ifdef PNG_WRITE_FILTER_SUPPORTED + int interlace_preserved = 1; +#endif /* WRITE_FILTER */ +#else /* !WRITE */ + png_structp write_ptr = NULL; + png_infop write_info_ptr = NULL; + png_infop write_end_info_ptr = NULL; +#endif /* !WRITE */ + png_bytep row_buf; + png_uint_32 y; + png_uint_32 width, height; + volatile int num_passes; + int pass; + int bit_depth, color_type; + + row_buf = NULL; + error_parameters.file_name = inname; + + if ((fpin = fopen(inname, "rb")) == NULL) + { + fprintf(STDERR, "Could not find input file %s\n", inname); + return (1); + } + + if ((fpout = fopen(outname, "wb")) == NULL) + { + fprintf(STDERR, "Could not open output file %s\n", outname); + FCLOSE(fpin); + return (1); + } + + pngtest_debug("Allocating read and write structures"); +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + read_ptr = + png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, + NULL, NULL, NULL, png_debug_malloc, png_debug_free); +#else + read_ptr = + png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); +#endif + png_set_error_fn(read_ptr, &error_parameters, pngtest_error, + pngtest_warning); + +#ifdef PNG_WRITE_SUPPORTED +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + write_ptr = + png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, + NULL, NULL, NULL, png_debug_malloc, png_debug_free); +#else + write_ptr = + png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); +#endif + png_set_error_fn(write_ptr, &error_parameters, pngtest_error, + pngtest_warning); +#endif + pngtest_debug("Allocating read_info, write_info and end_info structures"); + read_info_ptr = png_create_info_struct(read_ptr); + end_info_ptr = png_create_info_struct(read_ptr); +#ifdef PNG_WRITE_SUPPORTED + write_info_ptr = png_create_info_struct(write_ptr); + write_end_info_ptr = png_create_info_struct(write_ptr); +#endif + +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + init_callback_info(read_info_ptr); + png_set_read_user_chunk_fn(read_ptr, &user_chunk_data, + read_user_chunk_callback); +#endif + +#ifdef PNG_SETJMP_SUPPORTED + pngtest_debug("Setting jmpbuf for read struct"); + if (setjmp(png_jmpbuf(read_ptr))) + { + fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname); + png_free(read_ptr, row_buf); + row_buf = NULL; + png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); +#ifdef PNG_WRITE_SUPPORTED + png_destroy_info_struct(write_ptr, &write_end_info_ptr); + png_destroy_write_struct(&write_ptr, &write_info_ptr); +#endif + FCLOSE(fpin); + FCLOSE(fpout); + return (1); + } + +#ifdef PNG_WRITE_SUPPORTED + pngtest_debug("Setting jmpbuf for write struct"); + + if (setjmp(png_jmpbuf(write_ptr))) + { + fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname); + png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); + png_destroy_info_struct(write_ptr, &write_end_info_ptr); +#ifdef PNG_WRITE_SUPPORTED + png_destroy_write_struct(&write_ptr, &write_info_ptr); +#endif + FCLOSE(fpin); + FCLOSE(fpout); + return (1); + } +#endif +#endif + + if (strict != 0) + { + /* Treat png_benign_error() as errors on read */ + png_set_benign_errors(read_ptr, 0); + +#ifdef PNG_WRITE_SUPPORTED + /* Treat them as errors on write */ + png_set_benign_errors(write_ptr, 0); +#endif + + /* if strict is not set, then app warnings and errors are treated as + * warnings in release builds, but not in unstable builds; this can be + * changed with '--relaxed'. + */ + } + + else if (relaxed != 0) + { + /* Allow application (pngtest) errors and warnings to pass */ + png_set_benign_errors(read_ptr, 1); + +#ifdef PNG_WRITE_SUPPORTED + png_set_benign_errors(write_ptr, 1); +#endif + } + + pngtest_debug("Initializing input and output streams"); +#ifdef PNG_STDIO_SUPPORTED + png_init_io(read_ptr, fpin); +# ifdef PNG_WRITE_SUPPORTED + png_init_io(write_ptr, fpout); +# endif +#else + png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data); +# ifdef PNG_WRITE_SUPPORTED + png_set_write_fn(write_ptr, (png_voidp)fpout, pngtest_write_data, +# ifdef PNG_WRITE_FLUSH_SUPPORTED + pngtest_flush); +# else + NULL); +# endif +# endif +#endif + + if (status_dots_requested == 1) + { +#ifdef PNG_WRITE_SUPPORTED + png_set_write_status_fn(write_ptr, write_row_callback); +#endif + png_set_read_status_fn(read_ptr, read_row_callback); + } + + else + { +#ifdef PNG_WRITE_SUPPORTED + png_set_write_status_fn(write_ptr, NULL); +#endif + png_set_read_status_fn(read_ptr, NULL); + } + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + png_set_read_user_transform_fn(read_ptr, read_user_callback); +#endif +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + zero_samples = 0; + png_set_write_user_transform_fn(write_ptr, count_zero_samples); +#endif + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + /* Preserve all the unknown chunks, if possible. If this is disabled then, + * even if the png_{get,set}_unknown_chunks stuff is enabled, we can't use + * libpng to *save* the unknown chunks on read (because we can't switch the + * save option on!) + * + * Notice that if SET_UNKNOWN_CHUNKS is *not* supported read will discard all + * unknown chunks and write will write them all. + */ +#ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED + png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS, + NULL, 0); +#endif +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS, + NULL, 0); +#endif +#endif + + pngtest_debug("Reading info struct"); + png_read_info(read_ptr, read_info_ptr); + +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + /* This is a bit of a hack; there is no obvious way in the callback function + * to determine that the chunks before the first IDAT have been read, so + * remove the info_ptr (which is only used to determine position relative to + * PLTE) here to indicate that we are after the IDAT. + */ + user_chunk_data.info_ptr = NULL; +#endif + + pngtest_debug("Transferring info struct"); + { + int interlace_type, compression_type, filter_type; + + if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth, + &color_type, &interlace_type, &compression_type, &filter_type) != 0) + { + png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth, + color_type, interlace_type, compression_type, filter_type); + /* num_passes may not be available below if interlace support is not + * provided by libpng for both read and write. + */ + switch (interlace_type) + { + case PNG_INTERLACE_NONE: + num_passes = 1; + break; + + case PNG_INTERLACE_ADAM7: + num_passes = 7; + break; + + default: + png_error(read_ptr, "invalid interlace type"); + /*NOT REACHED*/ + } + } + + else + png_error(read_ptr, "png_get_IHDR failed"); + } +#ifdef PNG_FIXED_POINT_SUPPORTED +#ifdef PNG_cHRM_SUPPORTED + { + png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x, + blue_y; + + if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, + &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y) != 0) + { + png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x, + red_y, green_x, green_y, blue_x, blue_y); + } + } +#endif +#ifdef PNG_gAMA_SUPPORTED + { + png_fixed_point gamma; + + if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma) != 0) + png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma); + } +#endif +#else /* Use floating point versions */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +#ifdef PNG_cHRM_SUPPORTED + { + double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, + blue_y; + + if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x, + &red_y, &green_x, &green_y, &blue_x, &blue_y) != 0) + { + png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x, + red_y, green_x, green_y, blue_x, blue_y); + } + } +#endif +#ifdef PNG_gAMA_SUPPORTED + { + double gamma; + + if (png_get_gAMA(read_ptr, read_info_ptr, &gamma) != 0) + png_set_gAMA(write_ptr, write_info_ptr, gamma); + } +#endif +#endif /* Floating point */ +#endif /* Fixed point */ +#ifdef PNG_iCCP_SUPPORTED + { + png_charp name; + png_bytep profile; + png_uint_32 proflen; + int compression_type; + + if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type, + &profile, &proflen) != 0) + { + png_set_iCCP(write_ptr, write_info_ptr, name, compression_type, + profile, proflen); + } + } +#endif +#ifdef PNG_sRGB_SUPPORTED + { + int intent; + + if (png_get_sRGB(read_ptr, read_info_ptr, &intent) != 0) + png_set_sRGB(write_ptr, write_info_ptr, intent); + } +#endif + { + png_colorp palette; + int num_palette; + + if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette) != 0) + png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette); + } +#ifdef PNG_bKGD_SUPPORTED + { + png_color_16p background; + + if (png_get_bKGD(read_ptr, read_info_ptr, &background) != 0) + { + png_set_bKGD(write_ptr, write_info_ptr, background); + } + } +#endif +#ifdef PNG_hIST_SUPPORTED + { + png_uint_16p hist; + + if (png_get_hIST(read_ptr, read_info_ptr, &hist) != 0) + png_set_hIST(write_ptr, write_info_ptr, hist); + } +#endif +#ifdef PNG_oFFs_SUPPORTED + { + png_int_32 offset_x, offset_y; + int unit_type; + + if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y, + &unit_type) != 0) + { + png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type); + } + } +#endif +#ifdef PNG_pCAL_SUPPORTED + { + png_charp purpose, units; + png_charpp params; + png_int_32 X0, X1; + int type, nparams; + + if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type, + &nparams, &units, ¶ms) != 0) + { + png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type, + nparams, units, params); + } + } +#endif +#ifdef PNG_pHYs_SUPPORTED + { + png_uint_32 res_x, res_y; + int unit_type; + + if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, + &unit_type) != 0) + png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type); + } +#endif +#ifdef PNG_sBIT_SUPPORTED + { + png_color_8p sig_bit; + + if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit) != 0) + png_set_sBIT(write_ptr, write_info_ptr, sig_bit); + } +#endif +#ifdef PNG_sCAL_SUPPORTED +#if defined(PNG_FLOATING_POINT_SUPPORTED) && \ + defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) + { + int unit; + double scal_width, scal_height; + + if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width, + &scal_height) != 0) + { + png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height); + } + } +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + { + int unit; + png_charp scal_width, scal_height; + + if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width, + &scal_height) != 0) + { + png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, + scal_height); + } + } +#endif +#endif +#endif + +#ifdef PNG_sPLT_SUPPORTED + { + png_sPLT_tp entries; + + int num_entries = (int) png_get_sPLT(read_ptr, read_info_ptr, &entries); + if (num_entries) + { + png_set_sPLT(write_ptr, write_info_ptr, entries, num_entries); + } + } +#endif + +#ifdef PNG_TEXT_SUPPORTED + { + png_textp text_ptr; + int num_text; + + if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0) + { + pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text); + + pngtest_check_text_support(read_ptr, text_ptr, num_text); + + if (verbose != 0) + { + int i; + + printf("\n"); + for (i=0; igray > sample_max) || + (color_type == PNG_COLOR_TYPE_RGB && + ((int)trans_color->red > sample_max || + (int)trans_color->green > sample_max || + (int)trans_color->blue > sample_max)))) + png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans, + trans_color); + } + } +#endif +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + { + png_unknown_chunkp unknowns; + int num_unknowns = png_get_unknown_chunks(read_ptr, read_info_ptr, + &unknowns); + + if (num_unknowns != 0) + { + png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns, + num_unknowns); +#if PNG_LIBPNG_VER < 10600 + /* Copy the locations from the read_info_ptr. The automatically + * generated locations in write_end_info_ptr are wrong prior to 1.6.0 + * because they are reset from the write pointer (removed in 1.6.0). + */ + { + int i; + for (i = 0; i < num_unknowns; i++) + png_set_unknown_chunk_location(write_ptr, write_info_ptr, i, + unknowns[i].location); + } +#endif + } + } +#endif + +#ifdef PNG_WRITE_SUPPORTED + pngtest_debug("Writing info struct"); + + /* Write the info in two steps so that if we write the 'unknown' chunks here + * they go to the correct place. + */ + png_write_info_before_PLTE(write_ptr, write_info_ptr); + + write_chunks(write_ptr, before_PLTE); /* before PLTE */ + + png_write_info(write_ptr, write_info_ptr); + + write_chunks(write_ptr, before_IDAT); /* after PLTE */ +#endif + +#ifdef SINGLE_ROWBUF_ALLOC + pngtest_debug("Allocating row buffer..."); + row_buf = (png_bytep)png_malloc(read_ptr, + png_get_rowbytes(read_ptr, read_info_ptr)); + + pngtest_debug1("\t0x%08lx", (unsigned long)row_buf); +#endif /* SINGLE_ROWBUF_ALLOC */ + pngtest_debug("Writing row data"); + +#if defined(PNG_READ_INTERLACING_SUPPORTED) &&\ + defined(PNG_WRITE_INTERLACING_SUPPORTED) + /* Both must be defined for libpng to be able to handle the interlace, + * otherwise it gets handled below by simply reading and writing the passes + * directly. + */ + if (png_set_interlace_handling(read_ptr) != num_passes) + png_error(write_ptr, + "png_set_interlace_handling(read): wrong pass count "); + if (png_set_interlace_handling(write_ptr) != num_passes) + png_error(write_ptr, + "png_set_interlace_handling(write): wrong pass count "); +#else /* png_set_interlace_handling not called on either read or write */ +# define calc_pass_height +#endif /* not using libpng interlace handling */ + +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_misc += (t_stop - t_start); + t_start = t_stop; +#endif + for (pass = 0; pass < num_passes; pass++) + { +# ifdef calc_pass_height + png_uint_32 pass_height; + + if (num_passes == 7) /* interlaced */ + { + if (PNG_PASS_COLS(width, pass) > 0) + pass_height = PNG_PASS_ROWS(height, pass); + + else + pass_height = 0; + } + + else /* not interlaced */ + pass_height = height; +# else +# define pass_height height +# endif + + pngtest_debug1("Writing row data for pass %d", pass); + for (y = 0; y < pass_height; y++) + { +#ifndef SINGLE_ROWBUF_ALLOC + pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y); + + row_buf = (png_bytep)png_malloc(read_ptr, + png_get_rowbytes(read_ptr, read_info_ptr)); + + pngtest_debug2("\t0x%08lx (%lu bytes)", (unsigned long)row_buf, + (unsigned long)png_get_rowbytes(read_ptr, read_info_ptr)); + +#endif /* !SINGLE_ROWBUF_ALLOC */ + png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1); + +#ifdef PNG_WRITE_SUPPORTED +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_decode += (t_stop - t_start); + t_start = t_stop; +#endif + png_write_rows(write_ptr, (png_bytepp)&row_buf, 1); +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_encode += (t_stop - t_start); + t_start = t_stop; +#endif +#endif /* WRITE */ + +#ifndef SINGLE_ROWBUF_ALLOC + pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y); + png_free(read_ptr, row_buf); + row_buf = NULL; +#endif /* !SINGLE_ROWBUF_ALLOC */ + } + } + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +# ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1); +# endif +# ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1); +# endif +#endif + + pngtest_debug("Reading and writing end_info data"); + + png_read_end(read_ptr, end_info_ptr); +#ifdef PNG_TEXT_SUPPORTED + { + png_textp text_ptr; + int num_text; + + if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0) + { + pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text); + + pngtest_check_text_support(read_ptr, text_ptr, num_text); + + if (verbose != 0) + { + int i; + + printf("\n"); + for (i=0; i 0) + { + /* We don't really expect to get here because of the setjmp handling + * above, but this is safe. + */ + fprintf(STDERR, "\n %s: %d libpng errors found (%d warnings)", + inname, error_count, warning_count); + + if (strict != 0) + return (1); + } + +# ifdef PNG_WRITE_SUPPORTED + /* If there is no write support nothing was written! */ + else if (unsupported_chunks > 0) + { + fprintf(STDERR, "\n %s: unsupported chunks (%d)%s", + inname, unsupported_chunks, strict ? ": IGNORED --strict!" : ""); + } +# endif + + else if (warning_count > 0) + { + fprintf(STDERR, "\n %s: %d libpng warnings found", + inname, warning_count); + + if (strict != 0) + return (1); + } + + pngtest_debug("Opening files for comparison"); + if ((fpin = fopen(inname, "rb")) == NULL) + { + fprintf(STDERR, "Could not find file %s\n", inname); + return (1); + } + + if ((fpout = fopen(outname, "rb")) == NULL) + { + fprintf(STDERR, "Could not find file %s\n", outname); + FCLOSE(fpin); + return (1); + } + +#if defined (PNG_WRITE_SUPPORTED) /* else nothing was written */ &&\ + defined (PNG_WRITE_FILTER_SUPPORTED) + if (interlace_preserved != 0) /* else the files will be changed */ + { + for (;;) + { + static int wrote_question = 0; + png_size_t num_in, num_out; + char inbuf[256], outbuf[256]; + + num_in = fread(inbuf, 1, sizeof inbuf, fpin); + num_out = fread(outbuf, 1, sizeof outbuf, fpout); + + if (num_in != num_out) + { + fprintf(STDERR, "\nFiles %s and %s are of a different size\n", + inname, outname); + + if (wrote_question == 0 && unsupported_chunks == 0) + { + fprintf(STDERR, + " Was %s written with the same maximum IDAT chunk size (%d bytes),", + inname, PNG_ZBUF_SIZE); + fprintf(STDERR, + "\n filtering heuristic (libpng default), compression"); + fprintf(STDERR, + " level (zlib default),\n and zlib version (%s)?\n\n", + ZLIB_VERSION); + wrote_question = 1; + } + + FCLOSE(fpin); + FCLOSE(fpout); + + if (strict != 0 && unsupported_chunks == 0) + return (1); + + else + return (0); + } + + if (num_in == 0) + break; + + if (memcmp(inbuf, outbuf, num_in)) + { + fprintf(STDERR, "\nFiles %s and %s are different\n", inname, + outname); + + if (wrote_question == 0 && unsupported_chunks == 0) + { + fprintf(STDERR, + " Was %s written with the same maximum IDAT chunk size (%d bytes),", + inname, PNG_ZBUF_SIZE); + fprintf(STDERR, + "\n filtering heuristic (libpng default), compression"); + fprintf(STDERR, + " level (zlib default),\n and zlib version (%s)?\n\n", + ZLIB_VERSION); + wrote_question = 1; + } + + FCLOSE(fpin); + FCLOSE(fpout); + + /* NOTE: the unsupported_chunks escape is permitted here because + * unsupported text chunk compression will result in the compression + * mode being changed (to NONE) yet, in the test case, the result + * can be exactly the same size! + */ + if (strict != 0 && unsupported_chunks == 0) + return (1); + + else + return (0); + } + } + } +#endif /* WRITE && WRITE_FILTER */ + + FCLOSE(fpin); + FCLOSE(fpout); + + return (0); +} + +/* Input and output filenames */ +#ifdef RISCOS +static PNG_CONST char *inname = "pngtest/png"; +static PNG_CONST char *outname = "pngout/png"; +#else +static PNG_CONST char *inname = "pngtest.png"; +static PNG_CONST char *outname = "pngout.png"; +#endif + +int +main(int argc, char *argv[]) +{ + int multiple = 0; + int ierror = 0; + + png_structp dummy_ptr; + + fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING); + fprintf(STDERR, " with zlib version %s\n", ZLIB_VERSION); + fprintf(STDERR, "%s", png_get_copyright(NULL)); + /* Show the version of libpng used in building the library */ + fprintf(STDERR, " library (%lu):%s", + (unsigned long)png_access_version_number(), + png_get_header_version(NULL)); + + /* Show the version of libpng used in building the application */ + fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER, + PNG_HEADER_VERSION_STRING); + + /* Do some consistency checking on the memory allocation settings, I'm + * not sure this matters, but it is nice to know, the first of these + * tests should be impossible because of the way the macros are set + * in pngconf.h + */ +#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) + fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n"); +#endif + /* I think the following can happen. */ +#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K) + fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n"); +#endif + + if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING)) + { + fprintf(STDERR, + "Warning: versions are different between png.h and png.c\n"); + fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING); + fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver); + ++ierror; + } + + if (argc > 1) + { + if (strcmp(argv[1], "-m") == 0) + { + multiple = 1; + status_dots_requested = 0; + } + + else if (strcmp(argv[1], "-mv") == 0 || + strcmp(argv[1], "-vm") == 0 ) + { + multiple = 1; + verbose = 1; + status_dots_requested = 1; + } + + else if (strcmp(argv[1], "-v") == 0) + { + verbose = 1; + status_dots_requested = 1; + inname = argv[2]; + } + + else if (strcmp(argv[1], "--strict") == 0) + { + status_dots_requested = 0; + verbose = 1; + inname = argv[2]; + strict++; + relaxed = 0; + } + + else if (strcmp(argv[1], "--relaxed") == 0) + { + status_dots_requested = 0; + verbose = 1; + inname = argv[2]; + strict = 0; + relaxed++; + } + + else + { + inname = argv[1]; + status_dots_requested = 0; + } + } + + if (multiple == 0 && argc == 3 + verbose) + outname = argv[2 + verbose]; + + if ((multiple == 0 && argc > 3 + verbose) || + (multiple != 0 && argc < 2)) + { + fprintf(STDERR, + "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n", + argv[0], argv[0]); + fprintf(STDERR, + " reads/writes one PNG file (without -m) or multiple files (-m)\n"); + fprintf(STDERR, + " with -m %s is used as a temporary file\n", outname); + exit(1); + } + + if (multiple != 0) + { + int i; +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + int allocation_now = current_allocation; +#endif + for (i=2; i 0 + fprintf(STDERR, "\n"); +#endif + kerror = test_one_file(argv[i], outname); + if (kerror == 0) + { +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + fprintf(STDERR, "\n PASS (%lu zero samples)\n", + (unsigned long)zero_samples); +#else + fprintf(STDERR, " PASS\n"); +#endif +#ifdef PNG_TIME_RFC1123_SUPPORTED + if (tIME_chunk_present != 0) + fprintf(STDERR, " tIME = %s\n", tIME_string); + + tIME_chunk_present = 0; +#endif /* TIME_RFC1123 */ + } + + else + { + fprintf(STDERR, " FAIL\n"); + ierror += kerror; + } +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + if (allocation_now != current_allocation) + fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n", + current_allocation - allocation_now); + + if (current_allocation != 0) + { + memory_infop pinfo = pinformation; + + fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n", + current_allocation); + + while (pinfo != NULL) + { + fprintf(STDERR, " %lu bytes at %p\n", + (unsigned long)pinfo->size, + pinfo->pointer); + pinfo = pinfo->next; + } + } +#endif + } +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + fprintf(STDERR, " Current memory allocation: %10d bytes\n", + current_allocation); + fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", + maximum_allocation); + fprintf(STDERR, " Total memory allocation: %10d bytes\n", + total_allocation); + fprintf(STDERR, " Number of allocations: %10d\n", + num_allocations); +#endif + } + + else + { + int i; + for (i = 0; i<3; ++i) + { + int kerror; +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + int allocation_now = current_allocation; +#endif + if (i == 1) + status_dots_requested = 1; + + else if (verbose == 0) + status_dots_requested = 0; + + if (i == 0 || verbose == 1 || ierror != 0) + { + fprintf(STDERR, "\n Testing %s:", inname); +#if PNG_DEBUG > 0 + fprintf(STDERR, "\n"); +#endif + } + + kerror = test_one_file(inname, outname); + + if (kerror == 0) + { + if (verbose == 1 || i == 2) + { +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + fprintf(STDERR, "\n PASS (%lu zero samples)\n", + (unsigned long)zero_samples); +#else + fprintf(STDERR, " PASS\n"); +#endif +#ifdef PNG_TIME_RFC1123_SUPPORTED + if (tIME_chunk_present != 0) + fprintf(STDERR, " tIME = %s\n", tIME_string); +#endif /* TIME_RFC1123 */ + } + } + + else + { + if (verbose == 0 && i != 2) + { + fprintf(STDERR, "\n Testing %s:", inname); +#if PNG_DEBUG > 0 + fprintf(STDERR, "\n"); +#endif + } + + fprintf(STDERR, " FAIL\n"); + ierror += kerror; + } +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + if (allocation_now != current_allocation) + fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n", + current_allocation - allocation_now); + + if (current_allocation != 0) + { + memory_infop pinfo = pinformation; + + fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n", + current_allocation); + + while (pinfo != NULL) + { + fprintf(STDERR, " %lu bytes at %p\n", + (unsigned long)pinfo->size, pinfo->pointer); + pinfo = pinfo->next; + } + } +#endif + } +#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG + fprintf(STDERR, " Current memory allocation: %10d bytes\n", + current_allocation); + fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", + maximum_allocation); + fprintf(STDERR, " Total memory allocation: %10d bytes\n", + total_allocation); + fprintf(STDERR, " Number of allocations: %10d\n", + num_allocations); +#endif + } + +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_misc += (t_stop - t_start); + t_start = t_stop; + fprintf(STDERR, " CPU time used = %.3f seconds", + (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC); + fprintf(STDERR, " (decoding %.3f,\n", + t_decode/(float)CLOCKS_PER_SEC); + fprintf(STDERR, " encoding %.3f ,", + t_encode/(float)CLOCKS_PER_SEC); + fprintf(STDERR, " other %.3f seconds)\n\n", + t_misc/(float)CLOCKS_PER_SEC); +#endif + + if (ierror == 0) + fprintf(STDERR, " libpng passes test\n"); + + else + fprintf(STDERR, " libpng FAILS test\n"); + + dummy_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + fprintf(STDERR, " Default limits:\n"); + fprintf(STDERR, " width_max = %lu\n", + (unsigned long) png_get_user_width_max(dummy_ptr)); + fprintf(STDERR, " height_max = %lu\n", + (unsigned long) png_get_user_height_max(dummy_ptr)); + if (png_get_chunk_cache_max(dummy_ptr) == 0) + fprintf(STDERR, " cache_max = unlimited\n"); + else + fprintf(STDERR, " cache_max = %lu\n", + (unsigned long) png_get_chunk_cache_max(dummy_ptr)); + if (png_get_chunk_malloc_max(dummy_ptr) == 0) + fprintf(STDERR, " malloc_max = unlimited\n"); + else + fprintf(STDERR, " malloc_max = %lu\n", + (unsigned long) png_get_chunk_malloc_max(dummy_ptr)); + png_destroy_read_struct(&dummy_ptr, NULL, NULL); + + return (int)(ierror != 0); +} +#else +int +main(void) +{ + fprintf(STDERR, + " test ignored because libpng was not built with read support\n"); + /* And skip this test */ + return SKIP; +} +#endif + +/* Generate a compiler error if there is an old png.h in the search path. */ +typedef png_libpng_version_1_6_23 Your_png_h_is_not_version_1_6_23; diff --git a/source/Irrlicht/libpng/pngtest.png b/source/Irrlicht/libpng/pngtest.png new file mode 100644 index 00000000..81f5f843 Binary files /dev/null and b/source/Irrlicht/libpng/pngtest.png differ diff --git a/source/Irrlicht/libpng/pngtrans.c b/source/Irrlicht/libpng/pngtrans.c new file mode 100644 index 00000000..33ca1e2b --- /dev/null +++ b/source/Irrlicht/libpng/pngtrans.c @@ -0,0 +1,849 @@ + +/* pngtrans.c - transforms the data in a row (used by both readers and writers) + * + * Last changed in libpng 1.6.18 [July 23, 2015] + * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include "pngpriv.h" + +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Turn on BGR-to-RGB mapping */ +void PNGAPI +png_set_bgr(png_structrp png_ptr) +{ + png_debug(1, "in png_set_bgr"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_BGR; +} +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Turn on 16-bit byte swapping */ +void PNGAPI +png_set_swap(png_structrp png_ptr) +{ + png_debug(1, "in png_set_swap"); + + if (png_ptr == NULL) + return; + + if (png_ptr->bit_depth == 16) + png_ptr->transformations |= PNG_SWAP_BYTES; +} +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) +/* Turn on pixel packing */ +void PNGAPI +png_set_packing(png_structrp png_ptr) +{ + png_debug(1, "in png_set_packing"); + + if (png_ptr == NULL) + return; + + if (png_ptr->bit_depth < 8) + { + png_ptr->transformations |= PNG_PACK; +# ifdef PNG_WRITE_SUPPORTED + png_ptr->usr_bit_depth = 8; +# endif + } +} +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) +/* Turn on packed pixel swapping */ +void PNGAPI +png_set_packswap(png_structrp png_ptr) +{ + png_debug(1, "in png_set_packswap"); + + if (png_ptr == NULL) + return; + + if (png_ptr->bit_depth < 8) + png_ptr->transformations |= PNG_PACKSWAP; +} +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) +void PNGAPI +png_set_shift(png_structrp png_ptr, png_const_color_8p true_bits) +{ + png_debug(1, "in png_set_shift"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_SHIFT; + png_ptr->shift = *true_bits; +} +#endif + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) +int PNGAPI +png_set_interlace_handling(png_structrp png_ptr) +{ + png_debug(1, "in png_set_interlace handling"); + + if (png_ptr != 0 && png_ptr->interlaced != 0) + { + png_ptr->transformations |= PNG_INTERLACE; + return (7); + } + + return (1); +} +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +/* Add a filler byte on read, or remove a filler or alpha byte on write. + * The filler type has changed in v0.95 to allow future 2-byte fillers + * for 48-bit input data, as well as to avoid problems with some compilers + * that don't like bytes as parameters. + */ +void PNGAPI +png_set_filler(png_structrp png_ptr, png_uint_32 filler, int filler_loc) +{ + png_debug(1, "in png_set_filler"); + + if (png_ptr == NULL) + return; + + /* In libpng 1.6 it is possible to determine whether this is a read or write + * operation and therefore to do more checking here for a valid call. + */ + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) + { +# ifdef PNG_READ_FILLER_SUPPORTED + /* On read png_set_filler is always valid, regardless of the base PNG + * format, because other transformations can give a format where the + * filler code can execute (basically an 8 or 16-bit component RGB or G + * format.) + * + * NOTE: usr_channels is not used by the read code! (This has led to + * confusion in the past.) The filler is only used in the read code. + */ + png_ptr->filler = (png_uint_16)filler; +# else + png_app_error(png_ptr, "png_set_filler not supported on read"); + PNG_UNUSED(filler) /* not used in the write case */ + return; +# endif + } + + else /* write */ + { +# ifdef PNG_WRITE_FILLER_SUPPORTED + /* On write the usr_channels parameter must be set correctly at the + * start to record the number of channels in the app-supplied data. + */ + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_RGB: + png_ptr->usr_channels = 4; + break; + + case PNG_COLOR_TYPE_GRAY: + if (png_ptr->bit_depth >= 8) + { + png_ptr->usr_channels = 2; + break; + } + + else + { + /* There simply isn't any code in libpng to strip out bits + * from bytes when the components are less than a byte in + * size! + */ + png_app_error(png_ptr, + "png_set_filler is invalid for low bit depth gray output"); + return; + } + + default: + png_app_error(png_ptr, + "png_set_filler: inappropriate color type"); + return; + } +# else + png_app_error(png_ptr, "png_set_filler not supported on write"); + return; +# endif + } + + /* Here on success - libpng supports the operation, set the transformation + * and the flag to say where the filler channel is. + */ + png_ptr->transformations |= PNG_FILLER; + + if (filler_loc == PNG_FILLER_AFTER) + png_ptr->flags |= PNG_FLAG_FILLER_AFTER; + + else + png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER; +} + +/* Added to libpng-1.2.7 */ +void PNGAPI +png_set_add_alpha(png_structrp png_ptr, png_uint_32 filler, int filler_loc) +{ + png_debug(1, "in png_set_add_alpha"); + + if (png_ptr == NULL) + return; + + png_set_filler(png_ptr, filler, filler_loc); + /* The above may fail to do anything. */ + if ((png_ptr->transformations & PNG_FILLER) != 0) + png_ptr->transformations |= PNG_ADD_ALPHA; +} + +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +void PNGAPI +png_set_swap_alpha(png_structrp png_ptr) +{ + png_debug(1, "in png_set_swap_alpha"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_SWAP_ALPHA; +} +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +void PNGAPI +png_set_invert_alpha(png_structrp png_ptr) +{ + png_debug(1, "in png_set_invert_alpha"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_INVERT_ALPHA; +} +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +void PNGAPI +png_set_invert_mono(png_structrp png_ptr) +{ + png_debug(1, "in png_set_invert_mono"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_INVERT_MONO; +} + +/* Invert monochrome grayscale data */ +void /* PRIVATE */ +png_do_invert(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_invert"); + + /* This test removed from libpng version 1.0.13 and 1.2.0: + * if (row_info->bit_depth == 1 && + */ + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + png_bytep rp = row; + png_size_t i; + png_size_t istop = row_info->rowbytes; + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(~(*rp)); + rp++; + } + } + + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + row_info->bit_depth == 8) + { + png_bytep rp = row; + png_size_t i; + png_size_t istop = row_info->rowbytes; + + for (i = 0; i < istop; i += 2) + { + *rp = (png_byte)(~(*rp)); + rp += 2; + } + } + +#ifdef PNG_16BIT_SUPPORTED + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + row_info->bit_depth == 16) + { + png_bytep rp = row; + png_size_t i; + png_size_t istop = row_info->rowbytes; + + for (i = 0; i < istop; i += 4) + { + *rp = (png_byte)(~(*rp)); + *(rp + 1) = (png_byte)(~(*(rp + 1))); + rp += 4; + } + } +#endif +} +#endif + +#ifdef PNG_16BIT_SUPPORTED +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Swaps byte order on 16-bit depth images */ +void /* PRIVATE */ +png_do_swap(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_swap"); + + if (row_info->bit_depth == 16) + { + png_bytep rp = row; + png_uint_32 i; + png_uint_32 istop= row_info->width * row_info->channels; + + for (i = 0; i < istop; i++, rp += 2) + { +#ifdef PNG_BUILTIN_BSWAP16_SUPPORTED + /* Feature added to libpng-1.6.11 for testing purposes, not + * enabled by default. + */ + *(png_uint_16*)rp = __builtin_bswap16(*(png_uint_16*)rp); +#else + png_byte t = *rp; + *rp = *(rp + 1); + *(rp + 1) = t; +#endif + } + } +} +#endif +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) +static PNG_CONST png_byte onebppswaptable[256] = { + 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, + 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, + 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, + 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, + 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, + 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, + 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, + 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, + 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, + 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, + 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, + 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, + 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, + 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, + 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, + 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, + 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, + 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, + 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, + 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, + 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, + 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, + 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, + 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, + 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, + 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, + 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, + 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, + 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, + 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, + 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, + 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF +}; + +static PNG_CONST png_byte twobppswaptable[256] = { + 0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0, + 0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0, + 0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4, + 0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4, + 0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8, + 0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8, + 0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC, + 0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC, + 0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1, + 0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1, + 0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5, + 0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5, + 0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9, + 0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9, + 0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD, + 0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD, + 0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2, + 0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2, + 0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6, + 0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6, + 0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA, + 0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA, + 0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE, + 0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE, + 0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3, + 0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3, + 0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7, + 0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7, + 0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB, + 0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB, + 0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF, + 0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF +}; + +static PNG_CONST png_byte fourbppswaptable[256] = { + 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, + 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, + 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, + 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1, + 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, + 0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2, + 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73, + 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3, + 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74, + 0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4, + 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75, + 0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5, + 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76, + 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6, + 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, + 0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7, + 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, + 0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8, + 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79, + 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9, + 0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A, + 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA, + 0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, + 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB, + 0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C, + 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC, + 0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D, + 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD, + 0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E, + 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE, + 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F, + 0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF +}; + +/* Swaps pixel packing order within bytes */ +void /* PRIVATE */ +png_do_packswap(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_packswap"); + + if (row_info->bit_depth < 8) + { + png_bytep rp; + png_const_bytep end, table; + + end = row + row_info->rowbytes; + + if (row_info->bit_depth == 1) + table = onebppswaptable; + + else if (row_info->bit_depth == 2) + table = twobppswaptable; + + else if (row_info->bit_depth == 4) + table = fourbppswaptable; + + else + return; + + for (rp = row; rp < end; rp++) + *rp = table[*rp]; + } +} +#endif /* PACKSWAP || WRITE_PACKSWAP */ + +#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ + defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +/* Remove a channel - this used to be 'png_do_strip_filler' but it used a + * somewhat weird combination of flags to determine what to do. All the calls + * to png_do_strip_filler are changed in 1.5.2 to call this instead with the + * correct arguments. + * + * The routine isn't general - the channel must be the channel at the start or + * end (not in the middle) of each pixel. + */ +void /* PRIVATE */ +png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start) +{ + png_bytep sp = row; /* source pointer */ + png_bytep dp = row; /* destination pointer */ + png_bytep ep = row + row_info->rowbytes; /* One beyond end of row */ + + /* At the start sp will point to the first byte to copy and dp to where + * it is copied to. ep always points just beyond the end of the row, so + * the loop simply copies (channels-1) channels until sp reaches ep. + * + * at_start: 0 -- convert AG, XG, ARGB, XRGB, AAGG, XXGG, etc. + * nonzero -- convert GA, GX, RGBA, RGBX, GGAA, RRGGBBXX, etc. + */ + + /* GA, GX, XG cases */ + if (row_info->channels == 2) + { + if (row_info->bit_depth == 8) + { + if (at_start != 0) /* Skip initial filler */ + ++sp; + else /* Skip initial channel and, for sp, the filler */ + sp += 2, ++dp; + + /* For a 1 pixel wide image there is nothing to do */ + while (sp < ep) + *dp++ = *sp, sp += 2; + + row_info->pixel_depth = 8; + } + + else if (row_info->bit_depth == 16) + { + if (at_start != 0) /* Skip initial filler */ + sp += 2; + else /* Skip initial channel and, for sp, the filler */ + sp += 4, dp += 2; + + while (sp < ep) + *dp++ = *sp++, *dp++ = *sp, sp += 3; + + row_info->pixel_depth = 16; + } + + else + return; /* bad bit depth */ + + row_info->channels = 1; + + /* Finally fix the color type if it records an alpha channel */ + if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + row_info->color_type = PNG_COLOR_TYPE_GRAY; + } + + /* RGBA, RGBX, XRGB cases */ + else if (row_info->channels == 4) + { + if (row_info->bit_depth == 8) + { + if (at_start != 0) /* Skip initial filler */ + ++sp; + else /* Skip initial channels and, for sp, the filler */ + sp += 4, dp += 3; + + /* Note that the loop adds 3 to dp and 4 to sp each time. */ + while (sp < ep) + *dp++ = *sp++, *dp++ = *sp++, *dp++ = *sp, sp += 2; + + row_info->pixel_depth = 24; + } + + else if (row_info->bit_depth == 16) + { + if (at_start != 0) /* Skip initial filler */ + sp += 2; + else /* Skip initial channels and, for sp, the filler */ + sp += 8, dp += 6; + + while (sp < ep) + { + /* Copy 6 bytes, skip 2 */ + *dp++ = *sp++, *dp++ = *sp++; + *dp++ = *sp++, *dp++ = *sp++; + *dp++ = *sp++, *dp++ = *sp, sp += 3; + } + + row_info->pixel_depth = 48; + } + + else + return; /* bad bit depth */ + + row_info->channels = 3; + + /* Finally fix the color type if it records an alpha channel */ + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + row_info->color_type = PNG_COLOR_TYPE_RGB; + } + + else + return; /* The filler channel has gone already */ + + /* Fix the rowbytes value. */ + row_info->rowbytes = dp-row; +} +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Swaps red and blue bytes within a pixel */ +void /* PRIVATE */ +png_do_bgr(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_bgr"); + + if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 3) + { + png_byte save = *rp; + *rp = *(rp + 2); + *(rp + 2) = save; + } + } + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 4) + { + png_byte save = *rp; + *rp = *(rp + 2); + *(rp + 2) = save; + } + } + } + +#ifdef PNG_16BIT_SUPPORTED + else if (row_info->bit_depth == 16) + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 6) + { + png_byte save = *rp; + *rp = *(rp + 4); + *(rp + 4) = save; + save = *(rp + 1); + *(rp + 1) = *(rp + 5); + *(rp + 5) = save; + } + } + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 8) + { + png_byte save = *rp; + *rp = *(rp + 4); + *(rp + 4) = save; + save = *(rp + 1); + *(rp + 1) = *(rp + 5); + *(rp + 5) = save; + } + } + } +#endif + } +} +#endif /* READ_BGR || WRITE_BGR */ + +#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \ + defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED) +/* Added at libpng-1.5.10 */ +void /* PRIVATE */ +png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info) +{ + if (png_ptr->num_palette < (1 << row_info->bit_depth) && + png_ptr->num_palette > 0) /* num_palette can be 0 in MNG files */ + { + /* Calculations moved outside switch in an attempt to stop different + * compiler warnings. 'padding' is in *bits* within the last byte, it is + * an 'int' because pixel_depth becomes an 'int' in the expression below, + * and this calculation is used because it avoids warnings that other + * forms produced on either GCC or MSVC. + */ + int padding = (-row_info->pixel_depth * row_info->width) & 7; + png_bytep rp = png_ptr->row_buf + row_info->rowbytes; + + switch (row_info->bit_depth) + { + case 1: + { + /* in this case, all bytes must be 0 so we don't need + * to unpack the pixels except for the rightmost one. + */ + for (; rp > png_ptr->row_buf; rp--) + { + if ((*rp >> padding) != 0) + png_ptr->num_palette_max = 1; + padding = 0; + } + + break; + } + + case 2: + { + for (; rp > png_ptr->row_buf; rp--) + { + int i = ((*rp >> padding) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 2) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 4) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 6) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + padding = 0; + } + + break; + } + + case 4: + { + for (; rp > png_ptr->row_buf; rp--) + { + int i = ((*rp >> padding) & 0x0f); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 4) & 0x0f); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + padding = 0; + } + + break; + } + + case 8: + { + for (; rp > png_ptr->row_buf; rp--) + { + if (*rp > png_ptr->num_palette_max) + png_ptr->num_palette_max = (int) *rp; + } + + break; + } + + default: + break; + } + } +} +#endif /* CHECK_FOR_INVALID_INDEX */ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED +void PNGAPI +png_set_user_transform_info(png_structrp png_ptr, png_voidp + user_transform_ptr, int user_transform_depth, int user_transform_channels) +{ + png_debug(1, "in png_set_user_transform_info"); + + if (png_ptr == NULL) + return; + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + (png_ptr->flags & PNG_FLAG_ROW_INIT) != 0) + { + png_app_error(png_ptr, + "info change after png_start_read_image or png_read_update_info"); + return; + } +#endif + + png_ptr->user_transform_ptr = user_transform_ptr; + png_ptr->user_transform_depth = (png_byte)user_transform_depth; + png_ptr->user_transform_channels = (png_byte)user_transform_channels; +} +#endif + +/* This function returns a pointer to the user_transform_ptr associated with + * the user transform functions. The application should free any memory + * associated with this pointer before png_write_destroy and png_read_destroy + * are called. + */ +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED +png_voidp PNGAPI +png_get_user_transform_ptr(png_const_structrp png_ptr) +{ + if (png_ptr == NULL) + return (NULL); + + return png_ptr->user_transform_ptr; +} +#endif + +#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED +png_uint_32 PNGAPI +png_get_current_row_number(png_const_structrp png_ptr) +{ + /* See the comments in png.h - this is the sub-image row when reading an + * interlaced image. + */ + if (png_ptr != NULL) + return png_ptr->row_number; + + return PNG_UINT_32_MAX; /* help the app not to fail silently */ +} + +png_byte PNGAPI +png_get_current_pass_number(png_const_structrp png_ptr) +{ + if (png_ptr != NULL) + return png_ptr->pass; + return 8; /* invalid */ +} +#endif /* USER_TRANSFORM_INFO */ +#endif /* READ_USER_TRANSFORM || WRITE_USER_TRANSFORM */ +#endif /* READ || WRITE */ diff --git a/source/Irrlicht/libpng/pngwio.c b/source/Irrlicht/libpng/pngwio.c new file mode 100644 index 00000000..b973f637 --- /dev/null +++ b/source/Irrlicht/libpng/pngwio.c @@ -0,0 +1,168 @@ + +/* pngwio.c - functions for data output + * + * Last changed in libpng 1.6.15 [November 20, 2014] + * Copyright (c) 1998-2002,2004,2006-2014 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + * This file provides a location for all output. Users who need + * special handling are expected to write functions that have the same + * arguments as these and perform similar functions, but that possibly + * use different output methods. Note that you shouldn't change these + * functions, but rather write replacement functions and then change + * them at run time with png_set_write_fn(...). + */ + +#include "pngpriv.h" + +#ifdef PNG_WRITE_SUPPORTED + +/* Write the data to whatever output you are using. The default routine + * writes to a file pointer. Note that this routine sometimes gets called + * with very small lengths, so you should implement some kind of simple + * buffering if you are using unbuffered writes. This should never be asked + * to write more than 64K on a 16-bit machine. + */ + +void /* PRIVATE */ +png_write_data(png_structrp png_ptr, png_const_bytep data, png_size_t length) +{ + /* NOTE: write_data_fn must not change the buffer! */ + if (png_ptr->write_data_fn != NULL ) + (*(png_ptr->write_data_fn))(png_ptr, png_constcast(png_bytep,data), + length); + + else + png_error(png_ptr, "Call to NULL write function"); +} + +#ifdef PNG_STDIO_SUPPORTED +/* This is the function that does the actual writing of data. If you are + * not writing to a standard C stream, you should create a replacement + * write_data function and use it at run time with png_set_write_fn(), rather + * than changing the library. + */ +void PNGCBAPI +png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check; + + if (png_ptr == NULL) + return; + + check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr)); + + if (check != length) + png_error(png_ptr, "Write Error"); +} +#endif + +/* This function is called to output any data pending writing (normally + * to disk). After png_flush is called, there should be no data pending + * writing in any buffers. + */ +#ifdef PNG_WRITE_FLUSH_SUPPORTED +void /* PRIVATE */ +png_flush(png_structrp png_ptr) +{ + if (png_ptr->output_flush_fn != NULL) + (*(png_ptr->output_flush_fn))(png_ptr); +} + +# ifdef PNG_STDIO_SUPPORTED +void PNGCBAPI +png_default_flush(png_structp png_ptr) +{ + png_FILE_p io_ptr; + + if (png_ptr == NULL) + return; + + io_ptr = png_voidcast(png_FILE_p, (png_ptr->io_ptr)); + fflush(io_ptr); +} +# endif +#endif + +/* This function allows the application to supply new output functions for + * libpng if standard C streams aren't being used. + * + * This function takes as its arguments: + * png_ptr - pointer to a png output data structure + * io_ptr - pointer to user supplied structure containing info about + * the output functions. May be NULL. + * write_data_fn - pointer to a new output function that takes as its + * arguments a pointer to a png_struct, a pointer to + * data to be written, and a 32-bit unsigned int that is + * the number of bytes to be written. The new write + * function should call png_error(png_ptr, "Error msg") + * to exit and output any fatal error messages. May be + * NULL, in which case libpng's default function will + * be used. + * flush_data_fn - pointer to a new flush function that takes as its + * arguments a pointer to a png_struct. After a call to + * the flush function, there should be no data in any buffers + * or pending transmission. If the output method doesn't do + * any buffering of output, a function prototype must still be + * supplied although it doesn't have to do anything. If + * PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile + * time, output_flush_fn will be ignored, although it must be + * supplied for compatibility. May be NULL, in which case + * libpng's default function will be used, if + * PNG_WRITE_FLUSH_SUPPORTED is defined. This is not + * a good idea if io_ptr does not point to a standard + * *FILE structure. + */ +void PNGAPI +png_set_write_fn(png_structrp png_ptr, png_voidp io_ptr, + png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->io_ptr = io_ptr; + +#ifdef PNG_STDIO_SUPPORTED + if (write_data_fn != NULL) + png_ptr->write_data_fn = write_data_fn; + + else + png_ptr->write_data_fn = png_default_write_data; +#else + png_ptr->write_data_fn = write_data_fn; +#endif + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +# ifdef PNG_STDIO_SUPPORTED + + if (output_flush_fn != NULL) + png_ptr->output_flush_fn = output_flush_fn; + + else + png_ptr->output_flush_fn = png_default_flush; + +# else + png_ptr->output_flush_fn = output_flush_fn; +# endif +#else + PNG_UNUSED(output_flush_fn) +#endif /* WRITE_FLUSH */ + +#ifdef PNG_READ_SUPPORTED + /* It is an error to read while writing a png file */ + if (png_ptr->read_data_fn != NULL) + { + png_ptr->read_data_fn = NULL; + + png_warning(png_ptr, + "Can't set both read_data_fn and write_data_fn in the" + " same structure"); + } +#endif +} +#endif /* WRITE */ diff --git a/source/Irrlicht/libpng/pngwrite.c b/source/Irrlicht/libpng/pngwrite.c new file mode 100644 index 00000000..12f05aef --- /dev/null +++ b/source/Irrlicht/libpng/pngwrite.c @@ -0,0 +1,2383 @@ + +/* pngwrite.c - general routines to write a PNG file + * + * Last changed in libpng 1.6.19 [November 12, 2015] + * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include "pngpriv.h" +#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED +# include +#endif /* SIMPLIFIED_WRITE_STDIO */ + +#ifdef PNG_WRITE_SUPPORTED + +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +/* Write out all the unknown chunks for the current given location */ +static void +write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr, + unsigned int where) +{ + if (info_ptr->unknown_chunks_num != 0) + { + png_const_unknown_chunkp up; + + png_debug(5, "writing extra chunks"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + ++up) + if ((up->location & where) != 0) + { + /* If per-chunk unknown chunk handling is enabled use it, otherwise + * just write the chunks the application has set. + */ +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + int keep = png_handle_as_unknown(png_ptr, up->name); + + /* NOTE: this code is radically different from the read side in the + * matter of handling an ancillary unknown chunk. In the read side + * the default behavior is to discard it, in the code below the default + * behavior is to write it. Critical chunks are, however, only + * written if explicitly listed or if the default is set to write all + * unknown chunks. + * + * The default handling is also slightly weird - it is not possible to + * stop the writing of all unsafe-to-copy chunks! + * + * TODO: REVIEW: this would seem to be a bug. + */ + if (keep != PNG_HANDLE_CHUNK_NEVER && + ((up->name[3] & 0x20) /* safe-to-copy overrides everything */ || + keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_AS_DEFAULT && + png_ptr->unknown_default == PNG_HANDLE_CHUNK_ALWAYS))) +#endif + { + /* TODO: review, what is wrong with a zero length unknown chunk? */ + if (up->size == 0) + png_warning(png_ptr, "Writing zero-length unknown chunk"); + + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +} +#endif /* WRITE_UNKNOWN_CHUNKS */ + +/* Writes all the PNG information. This is the suggested way to use the + * library. If you have a new chunk to add, make a function to write it, + * and put it in the correct location here. If you want the chunk written + * after the image data, put it in png_write_end(). I strongly encourage + * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing + * the chunk, as that will keep the code from breaking if you want to just + * write a plain PNG file. If you have long comments, I suggest writing + * them in png_write_end(), and compressing them. + */ +void PNGAPI +png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr) +{ + png_debug(1, "in png_write_info_before_PLTE"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0) + { + /* Write PNG signature */ + png_write_sig(png_ptr); + +#ifdef PNG_MNG_FEATURES_SUPPORTED + if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 && \ + png_ptr->mng_features_permitted != 0) + { + png_warning(png_ptr, + "MNG features are not allowed in a PNG datastream"); + png_ptr->mng_features_permitted = 0; + } +#endif + + /* Write IHDR information. */ + png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, + info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, + info_ptr->filter_type, +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + info_ptr->interlace_type +#else + 0 +#endif + ); + + /* The rest of these check to see if the valid field has the appropriate + * flag set, and if it does, writes the chunk. + * + * 1.6.0: COLORSPACE support controls the writing of these chunks too, and + * the chunks will be written if the WRITE routine is there and + * information * is available in the COLORSPACE. (See + * png_colorspace_sync_info in png.c for where the valid flags get set.) + * + * Under certain circumstances the colorspace can be invalidated without + * syncing the info_struct 'valid' flags; this happens if libpng detects + * an error and calls png_error while the color space is being set, yet + * the application continues writing the PNG. So check the 'invalid' + * flag here too. + */ +#ifdef PNG_GAMMA_SUPPORTED +# ifdef PNG_WRITE_gAMA_SUPPORTED + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && + (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) != 0 && + (info_ptr->valid & PNG_INFO_gAMA) != 0) + png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma); +# endif +#endif + +#ifdef PNG_COLORSPACE_SUPPORTED + /* Write only one of sRGB or an ICC profile. If a profile was supplied + * and it matches one of the known sRGB ones issue a warning. + */ +# ifdef PNG_WRITE_iCCP_SUPPORTED + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && + (info_ptr->valid & PNG_INFO_iCCP) != 0) + { +# ifdef PNG_WRITE_sRGB_SUPPORTED + if ((info_ptr->valid & PNG_INFO_sRGB) != 0) + png_app_warning(png_ptr, + "profile matches sRGB but writing iCCP instead"); +# endif + + png_write_iCCP(png_ptr, info_ptr->iccp_name, + info_ptr->iccp_profile); + } +# ifdef PNG_WRITE_sRGB_SUPPORTED + else +# endif +# endif + +# ifdef PNG_WRITE_sRGB_SUPPORTED + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && + (info_ptr->valid & PNG_INFO_sRGB) != 0) + png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent); +# endif /* WRITE_sRGB */ +#endif /* COLORSPACE */ + +#ifdef PNG_WRITE_sBIT_SUPPORTED + if ((info_ptr->valid & PNG_INFO_sBIT) != 0) + png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); +#endif + +#ifdef PNG_COLORSPACE_SUPPORTED +# ifdef PNG_WRITE_cHRM_SUPPORTED + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && + (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0 && + (info_ptr->valid & PNG_INFO_cHRM) != 0) + png_write_cHRM_fixed(png_ptr, &info_ptr->colorspace.end_points_xy); +# endif +#endif + +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR); +#endif + + png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; + } +} + +void PNGAPI +png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) +{ +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) + int i; +#endif + + png_debug(1, "in png_write_info"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_write_info_before_PLTE(png_ptr, info_ptr); + + if ((info_ptr->valid & PNG_INFO_PLTE) != 0) + png_write_PLTE(png_ptr, info_ptr->palette, + (png_uint_32)info_ptr->num_palette); + + else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + png_error(png_ptr, "Valid palette required for paletted images"); + +#ifdef PNG_WRITE_tRNS_SUPPORTED + if ((info_ptr->valid & PNG_INFO_tRNS) !=0) + { +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + /* Invert the alpha channel (in tRNS) */ + if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0 && + info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + int j, jend; + + jend = info_ptr->num_trans; + if (jend > PNG_MAX_PALETTE_LENGTH) + jend = PNG_MAX_PALETTE_LENGTH; + + for (j = 0; jtrans_alpha[j] = + (png_byte)(255 - info_ptr->trans_alpha[j]); + } +#endif + png_write_tRNS(png_ptr, info_ptr->trans_alpha, &(info_ptr->trans_color), + info_ptr->num_trans, info_ptr->color_type); + } +#endif +#ifdef PNG_WRITE_bKGD_SUPPORTED + if ((info_ptr->valid & PNG_INFO_bKGD) != 0) + png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); +#endif + +#ifdef PNG_WRITE_hIST_SUPPORTED + if ((info_ptr->valid & PNG_INFO_hIST) != 0) + png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); +#endif + +#ifdef PNG_WRITE_oFFs_SUPPORTED + if ((info_ptr->valid & PNG_INFO_oFFs) != 0) + png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, + info_ptr->offset_unit_type); +#endif + +#ifdef PNG_WRITE_pCAL_SUPPORTED + if ((info_ptr->valid & PNG_INFO_pCAL) != 0) + png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0, + info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams, + info_ptr->pcal_units, info_ptr->pcal_params); +#endif + +#ifdef PNG_WRITE_sCAL_SUPPORTED + if ((info_ptr->valid & PNG_INFO_sCAL) != 0) + png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, + info_ptr->scal_s_width, info_ptr->scal_s_height); +#endif /* sCAL */ + +#ifdef PNG_WRITE_pHYs_SUPPORTED + if ((info_ptr->valid & PNG_INFO_pHYs) != 0) + png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, + info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); +#endif /* pHYs */ + +#ifdef PNG_WRITE_tIME_SUPPORTED + if ((info_ptr->valid & PNG_INFO_tIME) != 0) + { + png_write_tIME(png_ptr, &(info_ptr->mod_time)); + png_ptr->mode |= PNG_WROTE_tIME; + } +#endif /* tIME */ + +#ifdef PNG_WRITE_sPLT_SUPPORTED + if ((info_ptr->valid & PNG_INFO_sPLT) != 0) + for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) + png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); +#endif /* sPLT */ + +#ifdef PNG_WRITE_TEXT_SUPPORTED + /* Check to see if we need to write text chunks */ + for (i = 0; i < info_ptr->num_text; i++) + { + png_debug2(2, "Writing header text chunk %d, type %d", i, + info_ptr->text[i].compression); + /* An internationalized chunk? */ + if (info_ptr->text[i].compression > 0) + { +#ifdef PNG_WRITE_iTXt_SUPPORTED + /* Write international chunk */ + png_write_iTXt(png_ptr, + info_ptr->text[i].compression, + info_ptr->text[i].key, + info_ptr->text[i].lang, + info_ptr->text[i].lang_key, + info_ptr->text[i].text); + /* Mark this chunk as written */ + if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + else + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; +#else + png_warning(png_ptr, "Unable to write international text"); +#endif + } + + /* If we want a compressed text chunk */ + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt) + { +#ifdef PNG_WRITE_zTXt_SUPPORTED + /* Write compressed chunk */ + png_write_zTXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, info_ptr->text[i].compression); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; +#else + png_warning(png_ptr, "Unable to write compressed text"); +#endif + } + + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + { +#ifdef PNG_WRITE_tEXt_SUPPORTED + /* Write uncompressed chunk */ + png_write_tEXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, + 0); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; +#else + /* Can't get here */ + png_warning(png_ptr, "Unable to write uncompressed text"); +#endif + } + } +#endif /* tEXt */ + +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_PLTE); +#endif +} + +/* Writes the end of the PNG file. If you don't want to write comments or + * time information, you can pass NULL for info. If you already wrote these + * in png_write_info(), do not write them again here. If you have long + * comments, I suggest writing them here, and compressing them. + */ +void PNGAPI +png_write_end(png_structrp png_ptr, png_inforp info_ptr) +{ + png_debug(1, "in png_write_end"); + + if (png_ptr == NULL) + return; + + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0) + png_error(png_ptr, "No IDATs written into file"); + +#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED + if (png_ptr->num_palette_max > png_ptr->num_palette) + png_benign_error(png_ptr, "Wrote palette index exceeding num_palette"); +#endif + + /* See if user wants us to write information chunks */ + if (info_ptr != NULL) + { +#ifdef PNG_WRITE_TEXT_SUPPORTED + int i; /* local index variable */ +#endif +#ifdef PNG_WRITE_tIME_SUPPORTED + /* Check to see if user has supplied a time chunk */ + if ((info_ptr->valid & PNG_INFO_tIME) != 0 && + (png_ptr->mode & PNG_WROTE_tIME) == 0) + png_write_tIME(png_ptr, &(info_ptr->mod_time)); + +#endif +#ifdef PNG_WRITE_TEXT_SUPPORTED + /* Loop through comment chunks */ + for (i = 0; i < info_ptr->num_text; i++) + { + png_debug2(2, "Writing trailer text chunk %d, type %d", i, + info_ptr->text[i].compression); + /* An internationalized chunk? */ + if (info_ptr->text[i].compression > 0) + { +#ifdef PNG_WRITE_iTXt_SUPPORTED + /* Write international chunk */ + png_write_iTXt(png_ptr, + info_ptr->text[i].compression, + info_ptr->text[i].key, + info_ptr->text[i].lang, + info_ptr->text[i].lang_key, + info_ptr->text[i].text); + /* Mark this chunk as written */ + if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + else + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; +#else + png_warning(png_ptr, "Unable to write international text"); +#endif + } + + else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) + { +#ifdef PNG_WRITE_zTXt_SUPPORTED + /* Write compressed chunk */ + png_write_zTXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, info_ptr->text[i].compression); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; +#else + png_warning(png_ptr, "Unable to write compressed text"); +#endif + } + + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + { +#ifdef PNG_WRITE_tEXt_SUPPORTED + /* Write uncompressed chunk */ + png_write_tEXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, 0); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; +#else + png_warning(png_ptr, "Unable to write uncompressed text"); +#endif + } + } +#endif +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT); +#endif + } + + png_ptr->mode |= PNG_AFTER_IDAT; + + /* Write end of PNG file */ + png_write_IEND(png_ptr); + + /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03, + * and restored again in libpng-1.2.30, may cause some applications that + * do not set png_ptr->output_flush_fn to crash. If your application + * experiences a problem, please try building libpng with + * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to + * png-mng-implement at lists.sf.net . + */ +#ifdef PNG_WRITE_FLUSH_SUPPORTED +# ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED + png_flush(png_ptr); +# endif +#endif +} + +#ifdef PNG_CONVERT_tIME_SUPPORTED +void PNGAPI +png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm * ttime) +{ + png_debug(1, "in png_convert_from_struct_tm"); + + ptime->year = (png_uint_16)(1900 + ttime->tm_year); + ptime->month = (png_byte)(ttime->tm_mon + 1); + ptime->day = (png_byte)ttime->tm_mday; + ptime->hour = (png_byte)ttime->tm_hour; + ptime->minute = (png_byte)ttime->tm_min; + ptime->second = (png_byte)ttime->tm_sec; +} + +void PNGAPI +png_convert_from_time_t(png_timep ptime, time_t ttime) +{ + struct tm *tbuf; + + png_debug(1, "in png_convert_from_time_t"); + + tbuf = gmtime(&ttime); + png_convert_from_struct_tm(ptime, tbuf); +} +#endif + +/* Initialize png_ptr structure, and allocate any memory needed */ +PNG_FUNCTION(png_structp,PNGAPI +png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED) +{ +#ifndef PNG_USER_MEM_SUPPORTED + png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, NULL, NULL, NULL); +#else + return png_create_write_struct_2(user_png_ver, error_ptr, error_fn, + warn_fn, NULL, NULL, NULL); +} + +/* Alternate initialize png_ptr structure, and allocate any memory needed */ +PNG_FUNCTION(png_structp,PNGAPI +png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) +{ + png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); +#endif /* USER_MEM */ + if (png_ptr != NULL) + { + /* Set the zlib control values to defaults; they can be overridden by the + * application after the struct has been created. + */ + png_ptr->zbuffer_size = PNG_ZBUF_SIZE; + + /* The 'zlib_strategy' setting is irrelevant because png_default_claim in + * pngwutil.c defaults it according to whether or not filters will be + * used, and ignores this setting. + */ + png_ptr->zlib_strategy = PNG_Z_DEFAULT_STRATEGY; + png_ptr->zlib_level = PNG_Z_DEFAULT_COMPRESSION; + png_ptr->zlib_mem_level = 8; + png_ptr->zlib_window_bits = 15; + png_ptr->zlib_method = 8; + +#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED + png_ptr->zlib_text_strategy = PNG_TEXT_Z_DEFAULT_STRATEGY; + png_ptr->zlib_text_level = PNG_TEXT_Z_DEFAULT_COMPRESSION; + png_ptr->zlib_text_mem_level = 8; + png_ptr->zlib_text_window_bits = 15; + png_ptr->zlib_text_method = 8; +#endif /* WRITE_COMPRESSED_TEXT */ + + /* This is a highly dubious configuration option; by default it is off, + * but it may be appropriate for private builds that are testing + * extensions not conformant to the current specification, or of + * applications that must not fail to write at all costs! + */ +#ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED + /* In stable builds only warn if an application error can be completely + * handled. + */ + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; +#endif + + /* App warnings are warnings in release (or release candidate) builds but + * are errors during development. + */ +#if PNG_RELEASE_BUILD + png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; +#endif + + /* TODO: delay this, it can be done in png_init_io() (if the app doesn't + * do it itself) avoiding setting the default function if it is not + * required. + */ + png_set_write_fn(png_ptr, NULL, NULL, NULL); + } + + return png_ptr; +} + + +/* Write a few rows of image data. If the image is interlaced, + * either you will have to write the 7 sub images, or, if you + * have called png_set_interlace_handling(), you will have to + * "write" the image seven times. + */ +void PNGAPI +png_write_rows(png_structrp png_ptr, png_bytepp row, + png_uint_32 num_rows) +{ + png_uint_32 i; /* row counter */ + png_bytepp rp; /* row pointer */ + + png_debug(1, "in png_write_rows"); + + if (png_ptr == NULL) + return; + + /* Loop through the rows */ + for (i = 0, rp = row; i < num_rows; i++, rp++) + { + png_write_row(png_ptr, *rp); + } +} + +/* Write the image. You only need to call this function once, even + * if you are writing an interlaced image. + */ +void PNGAPI +png_write_image(png_structrp png_ptr, png_bytepp image) +{ + png_uint_32 i; /* row index */ + int pass, num_pass; /* pass variables */ + png_bytepp rp; /* points to current row */ + + if (png_ptr == NULL) + return; + + png_debug(1, "in png_write_image"); + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Initialize interlace handling. If image is not interlaced, + * this will set pass to 1 + */ + num_pass = png_set_interlace_handling(png_ptr); +#else + num_pass = 1; +#endif + /* Loop through passes */ + for (pass = 0; pass < num_pass; pass++) + { + /* Loop through image */ + for (i = 0, rp = image; i < png_ptr->height; i++, rp++) + { + png_write_row(png_ptr, *rp); + } + } +} + +#ifdef PNG_MNG_FEATURES_SUPPORTED +/* Performs intrapixel differencing */ +static void +png_do_write_intrapixel(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_intrapixel"); + + if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + int bytes_per_pixel; + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 3; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 4; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + *(rp) = (png_byte)(*rp - *(rp + 1)); + *(rp + 2) = (png_byte)(*(rp + 2) - *(rp + 1)); + } + } + +#ifdef PNG_WRITE_16BIT_SUPPORTED + else if (row_info->bit_depth == 16) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 6; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 8; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); + png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); + png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); + png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL); + png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); + *(rp ) = (png_byte)(red >> 8); + *(rp + 1) = (png_byte)red; + *(rp + 4) = (png_byte)(blue >> 8); + *(rp + 5) = (png_byte)blue; + } + } +#endif /* WRITE_16BIT */ + } +} +#endif /* MNG_FEATURES */ + +/* Called by user to write a row of image data */ +void PNGAPI +png_write_row(png_structrp png_ptr, png_const_bytep row) +{ + /* 1.5.6: moved from png_struct to be a local structure: */ + png_row_info row_info; + + if (png_ptr == NULL) + return; + + png_debug2(1, "in png_write_row (row %u, pass %d)", + png_ptr->row_number, png_ptr->pass); + + /* Initialize transformations and other stuff if first time */ + if (png_ptr->row_number == 0 && png_ptr->pass == 0) + { + /* Make sure we wrote the header info */ + if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0) + png_error(png_ptr, + "png_write_info was never called before png_write_row"); + + /* Check for transforms that have been set but were defined out */ +#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED) + if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) + png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined"); +#endif + +#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED) + if ((png_ptr->transformations & PNG_FILLER) != 0) + png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined"); +#endif +#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ + defined(PNG_READ_PACKSWAP_SUPPORTED) + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + png_warning(png_ptr, + "PNG_WRITE_PACKSWAP_SUPPORTED is not defined"); +#endif + +#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED) + if ((png_ptr->transformations & PNG_PACK) != 0) + png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined"); +#endif + +#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED) + if ((png_ptr->transformations & PNG_SHIFT) != 0) + png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined"); +#endif + +#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED) + if ((png_ptr->transformations & PNG_BGR) != 0) + png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined"); +#endif + +#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED) + if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) + png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined"); +#endif + + png_write_start_row(png_ptr); + } + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* If interlaced and not interested in row, return */ + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0) + { + switch (png_ptr->pass) + { + case 0: + if ((png_ptr->row_number & 0x07) != 0) + { + png_write_finish_row(png_ptr); + return; + } + break; + + case 1: + if ((png_ptr->row_number & 0x07) != 0 || png_ptr->width < 5) + { + png_write_finish_row(png_ptr); + return; + } + break; + + case 2: + if ((png_ptr->row_number & 0x07) != 4) + { + png_write_finish_row(png_ptr); + return; + } + break; + + case 3: + if ((png_ptr->row_number & 0x03) != 0 || png_ptr->width < 3) + { + png_write_finish_row(png_ptr); + return; + } + break; + + case 4: + if ((png_ptr->row_number & 0x03) != 2) + { + png_write_finish_row(png_ptr); + return; + } + break; + + case 5: + if ((png_ptr->row_number & 0x01) != 0 || png_ptr->width < 2) + { + png_write_finish_row(png_ptr); + return; + } + break; + + case 6: + if ((png_ptr->row_number & 0x01) == 0) + { + png_write_finish_row(png_ptr); + return; + } + break; + + default: /* error: ignore it */ + break; + } + } +#endif + + /* Set up row info for transformations */ + row_info.color_type = png_ptr->color_type; + row_info.width = png_ptr->usr_width; + row_info.channels = png_ptr->usr_channels; + row_info.bit_depth = png_ptr->usr_bit_depth; + row_info.pixel_depth = (png_byte)(row_info.bit_depth * row_info.channels); + row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); + + png_debug1(3, "row_info->color_type = %d", row_info.color_type); + png_debug1(3, "row_info->width = %u", row_info.width); + png_debug1(3, "row_info->channels = %d", row_info.channels); + png_debug1(3, "row_info->bit_depth = %d", row_info.bit_depth); + png_debug1(3, "row_info->pixel_depth = %d", row_info.pixel_depth); + png_debug1(3, "row_info->rowbytes = %lu", (unsigned long)row_info.rowbytes); + + /* Copy user's row into buffer, leaving room for filter byte. */ + memcpy(png_ptr->row_buf + 1, row, row_info.rowbytes); + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Handle interlacing */ + if (png_ptr->interlaced && png_ptr->pass < 6 && + (png_ptr->transformations & PNG_INTERLACE) != 0) + { + png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass); + /* This should always get caught above, but still ... */ + if (row_info.width == 0) + { + png_write_finish_row(png_ptr); + return; + } + } +#endif + +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED + /* Handle other transformations */ + if (png_ptr->transformations != 0) + png_do_write_transformations(png_ptr, &row_info); +#endif + + /* At this point the row_info pixel depth must match the 'transformed' depth, + * which is also the output depth. + */ + if (row_info.pixel_depth != png_ptr->pixel_depth || + row_info.pixel_depth != png_ptr->transformed_pixel_depth) + png_error(png_ptr, "internal write transform logic error"); + +#ifdef PNG_MNG_FEATURES_SUPPORTED + /* Write filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not write a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) + { + /* Intrapixel differencing */ + png_do_write_intrapixel(&row_info, png_ptr->row_buf + 1); + } +#endif + +/* Added at libpng-1.5.10 */ +#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Check for out-of-range palette index */ + if (row_info.color_type == PNG_COLOR_TYPE_PALETTE && + png_ptr->num_palette_max >= 0) + png_do_check_palette_indexes(png_ptr, &row_info); +#endif + + /* Find a filter if necessary, filter the row and write it out. */ + png_write_find_filter(png_ptr, &row_info); + + if (png_ptr->write_row_fn != NULL) + (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); +} + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +/* Set the automatic flush interval or 0 to turn flushing off */ +void PNGAPI +png_set_flush(png_structrp png_ptr, int nrows) +{ + png_debug(1, "in png_set_flush"); + + if (png_ptr == NULL) + return; + + png_ptr->flush_dist = (nrows < 0 ? 0 : nrows); +} + +/* Flush the current output buffers now */ +void PNGAPI +png_write_flush(png_structrp png_ptr) +{ + png_debug(1, "in png_write_flush"); + + if (png_ptr == NULL) + return; + + /* We have already written out all of the data */ + if (png_ptr->row_number >= png_ptr->num_rows) + return; + + png_compress_IDAT(png_ptr, NULL, 0, Z_SYNC_FLUSH); + png_ptr->flush_rows = 0; + png_flush(png_ptr); +} +#endif /* WRITE_FLUSH */ + +/* Free any memory used in png_ptr struct without freeing the struct itself. */ +static void +png_write_destroy(png_structrp png_ptr) +{ + png_debug(1, "in png_write_destroy"); + + /* Free any memory zlib uses */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) + deflateEnd(&png_ptr->zstream); + + /* Free our memory. png_free checks NULL for us. */ + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); + png_free(png_ptr, png_ptr->row_buf); + png_ptr->row_buf = NULL; +#ifdef PNG_WRITE_FILTER_SUPPORTED + png_free(png_ptr, png_ptr->prev_row); + png_free(png_ptr, png_ptr->try_row); + png_free(png_ptr, png_ptr->tst_row); + png_ptr->prev_row = NULL; + png_ptr->try_row = NULL; + png_ptr->tst_row = NULL; +#endif + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list = NULL; +#endif + + /* The error handling and memory handling information is left intact at this + * point: the jmp_buf may still have to be freed. See png_destroy_png_struct + * for how this happens. + */ +} + +/* Free all memory used by the write. + * In libpng 1.6.0 this API changed quietly to no longer accept a NULL value for + * *png_ptr_ptr. Prior to 1.6.0 it would accept such a value and it would free + * the passed in info_structs but it would quietly fail to free any of the data + * inside them. In 1.6.0 it quietly does nothing (it has to be quiet because it + * has no png_ptr.) + */ +void PNGAPI +png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) +{ + png_debug(1, "in png_destroy_write_struct"); + + if (png_ptr_ptr != NULL) + { + png_structrp png_ptr = *png_ptr_ptr; + + if (png_ptr != NULL) /* added in libpng 1.6.0 */ + { + png_destroy_info_struct(png_ptr, info_ptr_ptr); + + *png_ptr_ptr = NULL; + png_write_destroy(png_ptr); + png_destroy_png_struct(png_ptr); + } + } +} + +/* Allow the application to select one or more row filters to use. */ +void PNGAPI +png_set_filter(png_structrp png_ptr, int method, int filters) +{ + png_debug(1, "in png_set_filter"); + + if (png_ptr == NULL) + return; + +#ifdef PNG_MNG_FEATURES_SUPPORTED + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + (method == PNG_INTRAPIXEL_DIFFERENCING)) + method = PNG_FILTER_TYPE_BASE; + +#endif + if (method == PNG_FILTER_TYPE_BASE) + { + switch (filters & (PNG_ALL_FILTERS | 0x07)) + { +#ifdef PNG_WRITE_FILTER_SUPPORTED + case 5: + case 6: + case 7: png_app_error(png_ptr, "Unknown row filter for method 0"); + /* FALL THROUGH */ +#endif /* WRITE_FILTER */ + case PNG_FILTER_VALUE_NONE: + png_ptr->do_filter = PNG_FILTER_NONE; break; + +#ifdef PNG_WRITE_FILTER_SUPPORTED + case PNG_FILTER_VALUE_SUB: + png_ptr->do_filter = PNG_FILTER_SUB; break; + + case PNG_FILTER_VALUE_UP: + png_ptr->do_filter = PNG_FILTER_UP; break; + + case PNG_FILTER_VALUE_AVG: + png_ptr->do_filter = PNG_FILTER_AVG; break; + + case PNG_FILTER_VALUE_PAETH: + png_ptr->do_filter = PNG_FILTER_PAETH; break; + + default: + png_ptr->do_filter = (png_byte)filters; break; +#else + default: + png_app_error(png_ptr, "Unknown row filter for method 0"); +#endif /* WRITE_FILTER */ + } + +#ifdef PNG_WRITE_FILTER_SUPPORTED + /* If we have allocated the row_buf, this means we have already started + * with the image and we should have allocated all of the filter buffers + * that have been selected. If prev_row isn't already allocated, then + * it is too late to start using the filters that need it, since we + * will be missing the data in the previous row. If an application + * wants to start and stop using particular filters during compression, + * it should start out with all of the filters, and then remove them + * or add them back after the start of compression. + * + * NOTE: this is a nasty constraint on the code, because it means that the + * prev_row buffer must be maintained even if there are currently no + * 'prev_row' requiring filters active. + */ + if (png_ptr->row_buf != NULL) + { + int num_filters; + png_alloc_size_t buf_size; + + /* Repeat the checks in png_write_start_row; 1 pixel high or wide + * images cannot benefit from certain filters. If this isn't done here + * the check below will fire on 1 pixel high images. + */ + if (png_ptr->height == 1) + filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH); + + if (png_ptr->width == 1) + filters &= ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH); + + if ((filters & (PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH)) != 0 + && png_ptr->prev_row == NULL) + { + /* This is the error case, however it is benign - the previous row + * is not available so the filter can't be used. Just warn here. + */ + png_app_warning(png_ptr, + "png_set_filter: UP/AVG/PAETH cannot be added after start"); + filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH); + } + + num_filters = 0; + + if (filters & PNG_FILTER_SUB) + num_filters++; + + if (filters & PNG_FILTER_UP) + num_filters++; + + if (filters & PNG_FILTER_AVG) + num_filters++; + + if (filters & PNG_FILTER_PAETH) + num_filters++; + + /* Allocate needed row buffers if they have not already been + * allocated. + */ + buf_size = PNG_ROWBYTES(png_ptr->usr_channels * png_ptr->usr_bit_depth, + png_ptr->width) + 1; + + if (png_ptr->try_row == NULL) + png_ptr->try_row = png_voidcast(png_bytep, + png_malloc(png_ptr, buf_size)); + + if (num_filters > 1) + { + if (png_ptr->tst_row == NULL) + png_ptr->tst_row = png_voidcast(png_bytep, + png_malloc(png_ptr, buf_size)); + } + } + png_ptr->do_filter = (png_byte)filters; +#endif + } + else + png_error(png_ptr, "Unknown custom filter method"); +} + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */ +/* Provide floating and fixed point APIs */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_filter_heuristics(png_structrp png_ptr, int heuristic_method, + int num_weights, png_const_doublep filter_weights, + png_const_doublep filter_costs) +{ + PNG_UNUSED(png_ptr) + PNG_UNUSED(heuristic_method) + PNG_UNUSED(num_weights) + PNG_UNUSED(filter_weights) + PNG_UNUSED(filter_costs) +} +#endif /* FLOATING_POINT */ + +#ifdef PNG_FIXED_POINT_SUPPORTED +void PNGAPI +png_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method, + int num_weights, png_const_fixed_point_p filter_weights, + png_const_fixed_point_p filter_costs) +{ + PNG_UNUSED(png_ptr) + PNG_UNUSED(heuristic_method) + PNG_UNUSED(num_weights) + PNG_UNUSED(filter_weights) + PNG_UNUSED(filter_costs) +} +#endif /* FIXED_POINT */ +#endif /* WRITE_WEIGHTED_FILTER */ + +#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED +void PNGAPI +png_set_compression_level(png_structrp png_ptr, int level) +{ + png_debug(1, "in png_set_compression_level"); + + if (png_ptr == NULL) + return; + + png_ptr->zlib_level = level; +} + +void PNGAPI +png_set_compression_mem_level(png_structrp png_ptr, int mem_level) +{ + png_debug(1, "in png_set_compression_mem_level"); + + if (png_ptr == NULL) + return; + + png_ptr->zlib_mem_level = mem_level; +} + +void PNGAPI +png_set_compression_strategy(png_structrp png_ptr, int strategy) +{ + png_debug(1, "in png_set_compression_strategy"); + + if (png_ptr == NULL) + return; + + /* The flag setting here prevents the libpng dynamic selection of strategy. + */ + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; + png_ptr->zlib_strategy = strategy; +} + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +void PNGAPI +png_set_compression_window_bits(png_structrp png_ptr, int window_bits) +{ + if (png_ptr == NULL) + return; + + /* Prior to 1.6.0 this would warn but then set the window_bits value. This + * meant that negative window bits values could be selected that would cause + * libpng to write a non-standard PNG file with raw deflate or gzip + * compressed IDAT or ancillary chunks. Such files can be read and there is + * no warning on read, so this seems like a very bad idea. + */ + if (window_bits > 15) + { + png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); + window_bits = 15; + } + + else if (window_bits < 8) + { + png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); + window_bits = 8; + } + + png_ptr->zlib_window_bits = window_bits; +} + +void PNGAPI +png_set_compression_method(png_structrp png_ptr, int method) +{ + png_debug(1, "in png_set_compression_method"); + + if (png_ptr == NULL) + return; + + /* This would produce an invalid PNG file if it worked, but it doesn't and + * deflate will fault it, so it is harmless to just warn here. + */ + if (method != 8) + png_warning(png_ptr, "Only compression method 8 is supported by PNG"); + + png_ptr->zlib_method = method; +} +#endif /* WRITE_CUSTOMIZE_COMPRESSION */ + +/* The following were added to libpng-1.5.4 */ +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +void PNGAPI +png_set_text_compression_level(png_structrp png_ptr, int level) +{ + png_debug(1, "in png_set_text_compression_level"); + + if (png_ptr == NULL) + return; + + png_ptr->zlib_text_level = level; +} + +void PNGAPI +png_set_text_compression_mem_level(png_structrp png_ptr, int mem_level) +{ + png_debug(1, "in png_set_text_compression_mem_level"); + + if (png_ptr == NULL) + return; + + png_ptr->zlib_text_mem_level = mem_level; +} + +void PNGAPI +png_set_text_compression_strategy(png_structrp png_ptr, int strategy) +{ + png_debug(1, "in png_set_text_compression_strategy"); + + if (png_ptr == NULL) + return; + + png_ptr->zlib_text_strategy = strategy; +} + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +void PNGAPI +png_set_text_compression_window_bits(png_structrp png_ptr, int window_bits) +{ + if (png_ptr == NULL) + return; + + if (window_bits > 15) + { + png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); + window_bits = 15; + } + + else if (window_bits < 8) + { + png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); + window_bits = 8; + } + + png_ptr->zlib_text_window_bits = window_bits; +} + +void PNGAPI +png_set_text_compression_method(png_structrp png_ptr, int method) +{ + png_debug(1, "in png_set_text_compression_method"); + + if (png_ptr == NULL) + return; + + if (method != 8) + png_warning(png_ptr, "Only compression method 8 is supported by PNG"); + + png_ptr->zlib_text_method = method; +} +#endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */ +/* end of API added to libpng-1.5.4 */ + +void PNGAPI +png_set_write_status_fn(png_structrp png_ptr, png_write_status_ptr write_row_fn) +{ + if (png_ptr == NULL) + return; + + png_ptr->write_row_fn = write_row_fn; +} + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED +void PNGAPI +png_set_write_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr + write_user_transform_fn) +{ + png_debug(1, "in png_set_write_user_transform_fn"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_USER_TRANSFORM; + png_ptr->write_user_transform_fn = write_user_transform_fn; +} +#endif + + +#ifdef PNG_INFO_IMAGE_SUPPORTED +void PNGAPI +png_write_png(png_structrp png_ptr, png_inforp info_ptr, + int transforms, voidp params) +{ + if (png_ptr == NULL || info_ptr == NULL) + return; + + if ((info_ptr->valid & PNG_INFO_IDAT) == 0) + { + png_app_error(png_ptr, "no rows for png_write_image to write"); + return; + } + + /* Write the file header information. */ + png_write_info(png_ptr, info_ptr); + + /* ------ these transformations don't touch the info structure ------- */ + + /* Invert monochrome pixels */ + if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0) +#ifdef PNG_WRITE_INVERT_SUPPORTED + png_set_invert_mono(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported"); +#endif + + /* Shift the pixels up to a legal bit depth and fill in + * as appropriate to correctly scale the image. + */ + if ((transforms & PNG_TRANSFORM_SHIFT) != 0) +#ifdef PNG_WRITE_SHIFT_SUPPORTED + if ((info_ptr->valid & PNG_INFO_sBIT) != 0) + png_set_shift(png_ptr, &info_ptr->sig_bit); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported"); +#endif + + /* Pack pixels into bytes */ + if ((transforms & PNG_TRANSFORM_PACKING) != 0) +#ifdef PNG_WRITE_PACK_SUPPORTED + png_set_packing(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported"); +#endif + + /* Swap location of alpha bytes from ARGB to RGBA */ + if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0) +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED + png_set_swap_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported"); +#endif + + /* Remove a filler (X) from XRGB/RGBX/AG/GA into to convert it into + * RGB, note that the code expects the input color type to be G or RGB; no + * alpha channel. + */ + if ((transforms & (PNG_TRANSFORM_STRIP_FILLER_AFTER| + PNG_TRANSFORM_STRIP_FILLER_BEFORE)) != 0) + { +#ifdef PNG_WRITE_FILLER_SUPPORTED + if ((transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) != 0) + { + if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0) + png_app_error(png_ptr, + "PNG_TRANSFORM_STRIP_FILLER: BEFORE+AFTER not supported"); + + /* Continue if ignored - this is the pre-1.6.10 behavior */ + png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); + } + + else if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0) + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_FILLER not supported"); +#endif + } + + /* Flip BGR pixels to RGB */ + if ((transforms & PNG_TRANSFORM_BGR) != 0) +#ifdef PNG_WRITE_BGR_SUPPORTED + png_set_bgr(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported"); +#endif + + /* Swap bytes of 16-bit files to most significant byte first */ + if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0) +#ifdef PNG_WRITE_SWAP_SUPPORTED + png_set_swap(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported"); +#endif + + /* Swap bits of 1-bit, 2-bit, 4-bit packed pixel formats */ + if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0) +#ifdef PNG_WRITE_PACKSWAP_SUPPORTED + png_set_packswap(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported"); +#endif + + /* Invert the alpha channel from opacity to transparency */ + if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0) +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + png_set_invert_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported"); +#endif + + /* ----------------------- end of transformations ------------------- */ + + /* Write the bits */ + png_write_image(png_ptr, info_ptr->row_pointers); + + /* It is REQUIRED to call this to finish writing the rest of the file */ + png_write_end(png_ptr, info_ptr); + + PNG_UNUSED(params) +} +#endif + + +#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED +/* Initialize the write structure - general purpose utility. */ +static int +png_image_write_init(png_imagep image) +{ + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image, + png_safe_error, png_safe_warning); + + if (png_ptr != NULL) + { + png_infop info_ptr = png_create_info_struct(png_ptr); + + if (info_ptr != NULL) + { + png_controlp control = png_voidcast(png_controlp, + png_malloc_warn(png_ptr, (sizeof *control))); + + if (control != NULL) + { + memset(control, 0, (sizeof *control)); + + control->png_ptr = png_ptr; + control->info_ptr = info_ptr; + control->for_write = 1; + + image->opaque = control; + return 1; + } + + /* Error clean up */ + png_destroy_info_struct(png_ptr, &info_ptr); + } + + png_destroy_write_struct(&png_ptr, NULL); + } + + return png_image_error(image, "png_image_write_: out of memory"); +} + +/* Arguments to png_image_write_main: */ +typedef struct +{ + /* Arguments: */ + png_imagep image; + png_const_voidp buffer; + png_int_32 row_stride; + png_const_voidp colormap; + int convert_to_8bit; + /* Local variables: */ + png_const_voidp first_row; + ptrdiff_t row_bytes; + png_voidp local_row; + /* Byte count for memory writing */ + png_bytep memory; + png_alloc_size_t memory_bytes; /* not used for STDIO */ + png_alloc_size_t output_bytes; /* running total */ +} png_image_write_control; + +/* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to + * do any necessary byte swapping. The component order is defined by the + * png_image format value. + */ +static int +png_write_image_16bit(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + + png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, + display->first_row); + png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row); + png_uint_16p row_end; + const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; + int aindex = 0; + png_uint_32 y = image->height; + + if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0) + { +# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED + if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + aindex = -1; + ++input_row; /* To point to the first component */ + ++output_row; + } + else + aindex = channels; +# else + aindex = channels; +# endif + } + + else + png_error(png_ptr, "png_write_image: internal call error"); + + /* Work out the output row end and count over this, note that the increment + * above to 'row' means that row_end can actually be beyond the end of the + * row; this is correct. + */ + row_end = output_row + image->width * (channels+1); + + while (y-- > 0) + { + png_const_uint_16p in_ptr = input_row; + png_uint_16p out_ptr = output_row; + + while (out_ptr < row_end) + { + const png_uint_16 alpha = in_ptr[aindex]; + png_uint_32 reciprocal = 0; + int c; + + out_ptr[aindex] = alpha; + + /* Calculate a reciprocal. The correct calculation is simply + * component/alpha*65535 << 15. (I.e. 15 bits of precision); this + * allows correct rounding by adding .5 before the shift. 'reciprocal' + * is only initialized when required. + */ + if (alpha > 0 && alpha < 65535) + reciprocal = ((0xffff<<15)+(alpha>>1))/alpha; + + c = channels; + do /* always at least one channel */ + { + png_uint_16 component = *in_ptr++; + + /* The following gives 65535 for an alpha of 0, which is fine, + * otherwise if 0/0 is represented as some other value there is more + * likely to be a discontinuity which will probably damage + * compression when moving from a fully transparent area to a + * nearly transparent one. (The assumption here is that opaque + * areas tend not to be 0 intensity.) + */ + if (component >= alpha) + component = 65535; + + /* component 0 && alpha < 65535) + { + png_uint_32 calc = component * reciprocal; + calc += 16384; /* round to nearest */ + component = (png_uint_16)(calc >> 15); + } + + *out_ptr++ = component; + } + while (--c > 0); + + /* Skip to next component (skip the intervening alpha channel) */ + ++in_ptr; + ++out_ptr; + } + + png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row)); + input_row += display->row_bytes/(sizeof (png_uint_16)); + } + + return 1; +} + +/* Given 16-bit input (1 to 4 channels) write 8-bit output. If an alpha channel + * is present it must be removed from the components, the components are then + * written in sRGB encoding. No components are added or removed. + * + * Calculate an alpha reciprocal to reverse pre-multiplication. As above the + * calculation can be done to 15 bits of accuracy; however, the output needs to + * be scaled in the range 0..255*65535, so include that scaling here. + */ +# define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+(alpha>>1))/alpha) + +static png_byte +png_unpremultiply(png_uint_32 component, png_uint_32 alpha, + png_uint_32 reciprocal/*from the above macro*/) +{ + /* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0 + * is represented as some other value there is more likely to be a + * discontinuity which will probably damage compression when moving from a + * fully transparent area to a nearly transparent one. (The assumption here + * is that opaque areas tend not to be 0 intensity.) + * + * There is a rounding problem here; if alpha is less than 128 it will end up + * as 0 when scaled to 8 bits. To avoid introducing spurious colors into the + * output change for this too. + */ + if (component >= alpha || alpha < 128) + return 255; + + /* component 0) + { + /* The test is that alpha/257 (rounded) is less than 255, the first value + * that becomes 255 is 65407. + * NOTE: this must agree with the PNG_DIV257 macro (which must, therefore, + * be exact!) [Could also test reciprocal != 0] + */ + if (alpha < 65407) + { + component *= reciprocal; + component += 64; /* round to nearest */ + component >>= 7; + } + + else + component *= 255; + + /* Convert the component to sRGB. */ + return (png_byte)PNG_sRGB_FROM_LINEAR(component); + } + + else + return 0; +} + +static int +png_write_image_8bit(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + + png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, + display->first_row); + png_bytep output_row = png_voidcast(png_bytep, display->local_row); + png_uint_32 y = image->height; + const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; + + if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + png_bytep row_end; + int aindex; + +# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED + if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + aindex = -1; + ++input_row; /* To point to the first component */ + ++output_row; + } + + else +# endif + aindex = channels; + + /* Use row_end in place of a loop counter: */ + row_end = output_row + image->width * (channels+1); + + while (y-- > 0) + { + png_const_uint_16p in_ptr = input_row; + png_bytep out_ptr = output_row; + + while (out_ptr < row_end) + { + png_uint_16 alpha = in_ptr[aindex]; + png_byte alphabyte = (png_byte)PNG_DIV257(alpha); + png_uint_32 reciprocal = 0; + int c; + + /* Scale and write the alpha channel. */ + out_ptr[aindex] = alphabyte; + + if (alphabyte > 0 && alphabyte < 255) + reciprocal = UNP_RECIPROCAL(alpha); + + c = channels; + do /* always at least one channel */ + *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal); + while (--c > 0); + + /* Skip to next component (skip the intervening alpha channel) */ + ++in_ptr; + ++out_ptr; + } /* while out_ptr < row_end */ + + png_write_row(png_ptr, png_voidcast(png_const_bytep, + display->local_row)); + input_row += display->row_bytes/(sizeof (png_uint_16)); + } /* while y */ + } + + else + { + /* No alpha channel, so the row_end really is the end of the row and it + * is sufficient to loop over the components one by one. + */ + png_bytep row_end = output_row + image->width * channels; + + while (y-- > 0) + { + png_const_uint_16p in_ptr = input_row; + png_bytep out_ptr = output_row; + + while (out_ptr < row_end) + { + png_uint_32 component = *in_ptr++; + + component *= 255; + *out_ptr++ = (png_byte)PNG_sRGB_FROM_LINEAR(component); + } + + png_write_row(png_ptr, output_row); + input_row += display->row_bytes/(sizeof (png_uint_16)); + } + } + + return 1; +} + +static void +png_image_set_PLTE(png_image_write_control *display) +{ + const png_imagep image = display->image; + const void *cmap = display->colormap; + const int entries = image->colormap_entries > 256 ? 256 : + (int)image->colormap_entries; + + /* NOTE: the caller must check for cmap != NULL and entries != 0 */ + const png_uint_32 format = image->format; + const int channels = PNG_IMAGE_SAMPLE_CHANNELS(format); + +# if defined(PNG_FORMAT_BGR_SUPPORTED) &&\ + defined(PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED) + const int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 && + (format & PNG_FORMAT_FLAG_ALPHA) != 0; +# else +# define afirst 0 +# endif + +# ifdef PNG_FORMAT_BGR_SUPPORTED + const int bgr = (format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0; +# else +# define bgr 0 +# endif + + int i, num_trans; + png_color palette[256]; + png_byte tRNS[256]; + + memset(tRNS, 255, (sizeof tRNS)); + memset(palette, 0, (sizeof palette)); + + for (i=num_trans=0; i= 3) /* RGB */ + { + palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 * + entry[(2 ^ bgr)]); + palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 * + entry[1]); + palette[i].red = (png_byte)PNG_sRGB_FROM_LINEAR(255 * + entry[bgr]); + } + + else /* Gray */ + palette[i].blue = palette[i].red = palette[i].green = + (png_byte)PNG_sRGB_FROM_LINEAR(255 * *entry); + } + + else /* alpha */ + { + png_uint_16 alpha = entry[afirst ? 0 : channels-1]; + png_byte alphabyte = (png_byte)PNG_DIV257(alpha); + png_uint_32 reciprocal = 0; + + /* Calculate a reciprocal, as in the png_write_image_8bit code above + * this is designed to produce a value scaled to 255*65535 when + * divided by 128 (i.e. asr 7). + */ + if (alphabyte > 0 && alphabyte < 255) + reciprocal = (((0xffff*0xff)<<7)+(alpha>>1))/alpha; + + tRNS[i] = alphabyte; + if (alphabyte < 255) + num_trans = i+1; + + if (channels >= 3) /* RGB */ + { + palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)], + alpha, reciprocal); + palette[i].green = png_unpremultiply(entry[afirst + 1], alpha, + reciprocal); + palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha, + reciprocal); + } + + else /* gray */ + palette[i].blue = palette[i].red = palette[i].green = + png_unpremultiply(entry[afirst], alpha, reciprocal); + } + } + + else /* Color-map has sRGB values */ + { + png_const_bytep entry = png_voidcast(png_const_bytep, cmap); + + entry += i * channels; + + switch (channels) + { + case 4: + tRNS[i] = entry[afirst ? 0 : 3]; + if (tRNS[i] < 255) + num_trans = i+1; + /* FALL THROUGH */ + case 3: + palette[i].blue = entry[afirst + (2 ^ bgr)]; + palette[i].green = entry[afirst + 1]; + palette[i].red = entry[afirst + bgr]; + break; + + case 2: + tRNS[i] = entry[1 ^ afirst]; + if (tRNS[i] < 255) + num_trans = i+1; + /* FALL THROUGH */ + case 1: + palette[i].blue = palette[i].red = palette[i].green = + entry[afirst]; + break; + + default: + break; + } + } + } + +# ifdef afirst +# undef afirst +# endif +# ifdef bgr +# undef bgr +# endif + + png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette, + entries); + + if (num_trans > 0) + png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS, + num_trans, NULL); + + image->colormap_entries = entries; +} + +static int +png_image_write_main(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + png_uint_32 format = image->format; + + /* The following four ints are actually booleans */ + int colormap = (format & PNG_FORMAT_FLAG_COLORMAP); + int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR); /* input */ + int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA); + int write_16bit = linear && !colormap && (display->convert_to_8bit == 0); + +# ifdef PNG_BENIGN_ERRORS_SUPPORTED + /* Make sure we error out on any bad situation */ + png_set_benign_errors(png_ptr, 0/*error*/); +# endif + + /* Default the 'row_stride' parameter if required, also check the row stride + * and total image size to ensure that they are within the system limits. + */ + { + const unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format); + + if (image->width <= 0x7FFFFFFFU/channels) /* no overflow */ + { + png_uint_32 check; + const png_uint_32 png_row_stride = image->width * channels; + + if (display->row_stride == 0) + display->row_stride = (png_int_32)/*SAFE*/png_row_stride; + + if (display->row_stride < 0) + check = -display->row_stride; + + else + check = display->row_stride; + + if (check >= png_row_stride) + { + /* Now check for overflow of the image buffer calculation; this + * limits the whole image size to 32 bits for API compatibility with + * the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro. + */ + if (image->height > 0xFFFFFFFF/png_row_stride) + png_error(image->opaque->png_ptr, "memory image too large"); + } + + else + png_error(image->opaque->png_ptr, "supplied row stride too small"); + } + + else + png_error(image->opaque->png_ptr, "image row stride too large"); + } + + /* Set the required transforms then write the rows in the correct order. */ + if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0) + { + if (display->colormap != NULL && image->colormap_entries > 0) + { + png_uint_32 entries = image->colormap_entries; + + png_set_IHDR(png_ptr, info_ptr, image->width, image->height, + entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)), + PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_image_set_PLTE(display); + } + + else + png_error(image->opaque->png_ptr, + "no color-map for color-mapped image"); + } + + else + png_set_IHDR(png_ptr, info_ptr, image->width, image->height, + write_16bit ? 16 : 8, + ((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) + + ((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0), + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + /* Counter-intuitively the data transformations must be called *after* + * png_write_info, not before as in the read code, but the 'set' functions + * must still be called before. Just set the color space information, never + * write an interlaced image. + */ + + if (write_16bit != 0) + { + /* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */ + png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR); + + if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0) + png_set_cHRM_fixed(png_ptr, info_ptr, + /* color x y */ + /* white */ 31270, 32900, + /* red */ 64000, 33000, + /* green */ 30000, 60000, + /* blue */ 15000, 6000 + ); + } + + else if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0) + png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL); + + /* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit + * space must still be gamma encoded. + */ + else + png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE); + + /* Write the file header. */ + png_write_info(png_ptr, info_ptr); + + /* Now set up the data transformations (*after* the header is written), + * remove the handled transformations from the 'format' flags for checking. + * + * First check for a little endian system if writing 16-bit files. + */ + if (write_16bit != 0) + { + PNG_CONST png_uint_16 le = 0x0001; + + if ((*(png_const_bytep) & le) != 0) + png_set_swap(png_ptr); + } + +# ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED + if ((format & PNG_FORMAT_FLAG_BGR) != 0) + { + if (colormap == 0 && (format & PNG_FORMAT_FLAG_COLOR) != 0) + png_set_bgr(png_ptr); + format &= ~PNG_FORMAT_FLAG_BGR; + } +# endif + +# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED + if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + if (colormap == 0 && (format & PNG_FORMAT_FLAG_ALPHA) != 0) + png_set_swap_alpha(png_ptr); + format &= ~PNG_FORMAT_FLAG_AFIRST; + } +# endif + + /* If there are 16 or fewer color-map entries we wrote a lower bit depth + * above, but the application data is still byte packed. + */ + if (colormap != 0 && image->colormap_entries <= 16) + png_set_packing(png_ptr); + + /* That should have handled all (both) the transforms. */ + if ((format & ~(png_uint_32)(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR | + PNG_FORMAT_FLAG_ALPHA | PNG_FORMAT_FLAG_COLORMAP)) != 0) + png_error(png_ptr, "png_write_image: unsupported transformation"); + + { + png_const_bytep row = png_voidcast(png_const_bytep, display->buffer); + ptrdiff_t row_bytes = display->row_stride; + + if (linear != 0) + row_bytes *= (sizeof (png_uint_16)); + + if (row_bytes < 0) + row += (image->height-1) * (-row_bytes); + + display->first_row = row; + display->row_bytes = row_bytes; + } + + /* Apply 'fast' options if the flag is set. */ + if ((image->flags & PNG_IMAGE_FLAG_FAST) != 0) + { + png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_NO_FILTERS); + /* NOTE: determined by experiment using pngstest, this reflects some + * balance between the time to write the image once and the time to read + * it about 50 times. The speed-up in pngstest was about 10-20% of the + * total (user) time on a heavily loaded system. + */ +# ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED + png_set_compression_level(png_ptr, 3); +# endif + } + + /* Check for the cases that currently require a pre-transform on the row + * before it is written. This only applies when the input is 16-bit and + * either there is an alpha channel or it is converted to 8-bit. + */ + if ((linear != 0 && alpha != 0 ) || + (colormap == 0 && display->convert_to_8bit != 0)) + { + png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr, + png_get_rowbytes(png_ptr, info_ptr))); + int result; + + display->local_row = row; + if (write_16bit != 0) + result = png_safe_execute(image, png_write_image_16bit, display); + else + result = png_safe_execute(image, png_write_image_8bit, display); + display->local_row = NULL; + + png_free(png_ptr, row); + + /* Skip the 'write_end' on error: */ + if (result == 0) + return 0; + } + + /* Otherwise this is the case where the input is in a format currently + * supported by the rest of the libpng write code; call it directly. + */ + else + { + png_const_bytep row = png_voidcast(png_const_bytep, display->first_row); + ptrdiff_t row_bytes = display->row_bytes; + png_uint_32 y = image->height; + + while (y-- > 0) + { + png_write_row(png_ptr, row); + row += row_bytes; + } + } + + png_write_end(png_ptr, info_ptr); + return 1; +} + + +static void (PNGCBAPI +image_memory_write)(png_structp png_ptr, png_bytep/*const*/ data, + png_size_t size) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + png_ptr->io_ptr/*backdoor: png_get_io_ptr(png_ptr)*/); + const png_alloc_size_t ob = display->output_bytes; + + /* Check for overflow; this should never happen: */ + if (size <= ((png_alloc_size_t)-1) - ob) + { + /* I don't think libpng ever does this, but just in case: */ + if (size > 0) + { + if (display->memory_bytes >= ob+size) /* writing */ + memcpy(display->memory+ob, data, size); + + /* Always update the size: */ + display->output_bytes = ob+size; + } + } + + else + png_error(png_ptr, "png_image_write_to_memory: PNG too big"); +} + +static void (PNGCBAPI +image_memory_flush)(png_structp png_ptr) +{ + PNG_UNUSED(png_ptr) +} + +static int +png_image_write_memory(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + + /* The rest of the memory-specific init and write_main in an error protected + * environment. This case needs to use callbacks for the write operations + * since libpng has no built in support for writing to memory. + */ + png_set_write_fn(display->image->opaque->png_ptr, display/*io_ptr*/, + image_memory_write, image_memory_flush); + + return png_image_write_main(display); +} + +int PNGAPI +png_image_write_to_memory(png_imagep image, void *memory, + png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8bit, + const void *buffer, png_int_32 row_stride, const void *colormap) +{ + /* Write the image to the given buffer, or count the bytes if it is NULL */ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (memory_bytes != NULL && buffer != NULL) + { + /* This is to give the caller an easier error detection in the NULL + * case and guard against uninitialized variable problems: + */ + if (memory == NULL) + *memory_bytes = 0; + + if (png_image_write_init(image) != 0) + { + png_image_write_control display; + int result; + + memset(&display, 0, (sizeof display)); + display.image = image; + display.buffer = buffer; + display.row_stride = row_stride; + display.colormap = colormap; + display.convert_to_8bit = convert_to_8bit; + display.memory = png_voidcast(png_bytep, memory); + display.memory_bytes = *memory_bytes; + display.output_bytes = 0; + + result = png_safe_execute(image, png_image_write_memory, &display); + png_image_free(image); + + /* write_memory returns true even if we ran out of buffer. */ + if (result) + { + /* On out-of-buffer this function returns '0' but still updates + * memory_bytes: + */ + if (memory != NULL && display.output_bytes > *memory_bytes) + result = 0; + + *memory_bytes = display.output_bytes; + } + + return result; + } + + else + return 0; + } + + else + return png_image_error(image, + "png_image_write_to_memory: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_write_to_memory: incorrect PNG_IMAGE_VERSION"); + + else + return 0; +} + +#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED +int PNGAPI +png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit, + const void *buffer, png_int_32 row_stride, const void *colormap) +{ + /* Write the image to the given (FILE*). */ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file != NULL && buffer != NULL) + { + if (png_image_write_init(image) != 0) + { + png_image_write_control display; + int result; + + /* This is slightly evil, but png_init_io doesn't do anything other + * than this and we haven't changed the standard IO functions so + * this saves a 'safe' function. + */ + image->opaque->png_ptr->io_ptr = file; + + memset(&display, 0, (sizeof display)); + display.image = image; + display.buffer = buffer; + display.row_stride = row_stride; + display.colormap = colormap; + display.convert_to_8bit = convert_to_8bit; + + result = png_safe_execute(image, png_image_write_main, &display); + png_image_free(image); + return result; + } + + else + return 0; + } + + else + return png_image_error(image, + "png_image_write_to_stdio: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION"); + + else + return 0; +} + +int PNGAPI +png_image_write_to_file(png_imagep image, const char *file_name, + int convert_to_8bit, const void *buffer, png_int_32 row_stride, + const void *colormap) +{ + /* Write the image to the named file. */ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file_name != NULL && buffer != NULL) + { + FILE *fp = fopen(file_name, "wb"); + + if (fp != NULL) + { + if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer, + row_stride, colormap) != 0) + { + int error; /* from fflush/fclose */ + + /* Make sure the file is flushed correctly. */ + if (fflush(fp) == 0 && ferror(fp) == 0) + { + if (fclose(fp) == 0) + return 1; + + error = errno; /* from fclose */ + } + + else + { + error = errno; /* from fflush or ferror */ + (void)fclose(fp); + } + + (void)remove(file_name); + /* The image has already been cleaned up; this is just used to + * set the error (because the original write succeeded). + */ + return png_image_error(image, strerror(error)); + } + + else + { + /* Clean up: just the opened file. */ + (void)fclose(fp); + (void)remove(file_name); + return 0; + } + } + + else + return png_image_error(image, strerror(errno)); + } + + else + return png_image_error(image, + "png_image_write_to_file: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_write_to_file: incorrect PNG_IMAGE_VERSION"); + + else + return 0; +} +#endif /* SIMPLIFIED_WRITE_STDIO */ +#endif /* SIMPLIFIED_WRITE */ +#endif /* WRITE */ diff --git a/source/Irrlicht/libpng/pngwtran.c b/source/Irrlicht/libpng/pngwtran.c new file mode 100644 index 00000000..834f678a --- /dev/null +++ b/source/Irrlicht/libpng/pngwtran.c @@ -0,0 +1,576 @@ + +/* pngwtran.c - transforms the data in a row for PNG writers + * + * Last changed in libpng 1.6.18 [July 23, 2015] + * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include "pngpriv.h" + +#ifdef PNG_WRITE_SUPPORTED +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED + +#ifdef PNG_WRITE_PACK_SUPPORTED +/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The + * row_info bit depth should be 8 (one pixel per byte). The channels + * should be 1 (this only happens on grayscale and paletted images). + */ +static void +png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) +{ + png_debug(1, "in png_do_pack"); + + if (row_info->bit_depth == 8 && + row_info->channels == 1) + { + switch ((int)bit_depth) + { + case 1: + { + png_bytep sp, dp; + int mask, v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + mask = 0x80; + v = 0; + + for (i = 0; i < row_width; i++) + { + if (*sp != 0) + v |= mask; + + sp++; + + if (mask > 1) + mask >>= 1; + + else + { + mask = 0x80; + *dp = (png_byte)v; + dp++; + v = 0; + } + } + + if (mask != 0x80) + *dp = (png_byte)v; + + break; + } + + case 2: + { + png_bytep sp, dp; + unsigned int shift; + int v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + shift = 6; + v = 0; + + for (i = 0; i < row_width; i++) + { + png_byte value; + + value = (png_byte)(*sp & 0x03); + v |= (value << shift); + + if (shift == 0) + { + shift = 6; + *dp = (png_byte)v; + dp++; + v = 0; + } + + else + shift -= 2; + + sp++; + } + + if (shift != 6) + *dp = (png_byte)v; + + break; + } + + case 4: + { + png_bytep sp, dp; + unsigned int shift; + int v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + shift = 4; + v = 0; + + for (i = 0; i < row_width; i++) + { + png_byte value; + + value = (png_byte)(*sp & 0x0f); + v |= (value << shift); + + if (shift == 0) + { + shift = 4; + *dp = (png_byte)v; + dp++; + v = 0; + } + + else + shift -= 4; + + sp++; + } + + if (shift != 4) + *dp = (png_byte)v; + + break; + } + + default: + break; + } + + row_info->bit_depth = (png_byte)bit_depth; + row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_info->width); + } +} +#endif + +#ifdef PNG_WRITE_SHIFT_SUPPORTED +/* Shift pixel values to take advantage of whole range. Pass the + * true number of bits in bit_depth. The row should be packed + * according to row_info->bit_depth. Thus, if you had a row of + * bit depth 4, but the pixels only had values from 0 to 7, you + * would pass 3 as bit_depth, and this routine would translate the + * data to 0 to 15. + */ +static void +png_do_shift(png_row_infop row_info, png_bytep row, + png_const_color_8p bit_depth) +{ + png_debug(1, "in png_do_shift"); + + if (row_info->color_type != PNG_COLOR_TYPE_PALETTE) + { + int shift_start[4], shift_dec[4]; + int channels = 0; + + if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + shift_start[channels] = row_info->bit_depth - bit_depth->red; + shift_dec[channels] = bit_depth->red; + channels++; + + shift_start[channels] = row_info->bit_depth - bit_depth->green; + shift_dec[channels] = bit_depth->green; + channels++; + + shift_start[channels] = row_info->bit_depth - bit_depth->blue; + shift_dec[channels] = bit_depth->blue; + channels++; + } + + else + { + shift_start[channels] = row_info->bit_depth - bit_depth->gray; + shift_dec[channels] = bit_depth->gray; + channels++; + } + + if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) + { + shift_start[channels] = row_info->bit_depth - bit_depth->alpha; + shift_dec[channels] = bit_depth->alpha; + channels++; + } + + /* With low row depths, could only be grayscale, so one channel */ + if (row_info->bit_depth < 8) + { + png_bytep bp = row; + png_size_t i; + unsigned int mask; + png_size_t row_bytes = row_info->rowbytes; + + if (bit_depth->gray == 1 && row_info->bit_depth == 2) + mask = 0x55; + + else if (row_info->bit_depth == 4 && bit_depth->gray == 3) + mask = 0x11; + + else + mask = 0xff; + + for (i = 0; i < row_bytes; i++, bp++) + { + int j; + unsigned int v, out; + + v = *bp; + out = 0; + + for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0]) + { + if (j > 0) + out |= v << j; + + else + out |= (v >> (-j)) & mask; + } + + *bp = (png_byte)(out & 0xff); + } + } + + else if (row_info->bit_depth == 8) + { + png_bytep bp = row; + png_uint_32 i; + png_uint_32 istop = channels * row_info->width; + + for (i = 0; i < istop; i++, bp++) + { + + const unsigned int c = i%channels; + int j; + unsigned int v, out; + + v = *bp; + out = 0; + + for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) + { + if (j > 0) + out |= v << j; + + else + out |= v >> (-j); + } + + *bp = (png_byte)(out & 0xff); + } + } + + else + { + png_bytep bp; + png_uint_32 i; + png_uint_32 istop = channels * row_info->width; + + for (bp = row, i = 0; i < istop; i++) + { + const unsigned int c = i%channels; + int j; + unsigned int value, v; + + v = png_get_uint_16(bp); + value = 0; + + for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) + { + if (j > 0) + value |= v << j; + + else + value |= v >> (-j); + } + *bp++ = (png_byte)((value >> 8) & 0xff); + *bp++ = (png_byte)(value & 0xff); + } + } + } +} +#endif + +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED +static void +png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_swap_alpha"); + + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This converts from ARGB to RGBA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save; + } + } + +#ifdef PNG_WRITE_16BIT_SUPPORTED + else + { + /* This converts from AARRGGBB to RRGGBBAA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save[2]; + save[0] = *(sp++); + save[1] = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save[0]; + *(dp++) = save[1]; + } + } +#endif /* WRITE_16BIT */ + } + + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This converts from AG to GA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save; + } + } + +#ifdef PNG_WRITE_16BIT_SUPPORTED + else + { + /* This converts from AAGG to GGAA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save[2]; + save[0] = *(sp++); + save[1] = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save[0]; + *(dp++) = save[1]; + } + } +#endif /* WRITE_16BIT */ + } + } +} +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED +static void +png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_invert_alpha"); + + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This inverts the alpha channel in RGBA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + /* Does nothing + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + */ + sp+=3; dp = sp; + *dp = (png_byte)(255 - *(sp++)); + } + } + +#ifdef PNG_WRITE_16BIT_SUPPORTED + else + { + /* This inverts the alpha channel in RRGGBBAA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + /* Does nothing + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + */ + sp+=6; dp = sp; + *(dp++) = (png_byte)(255 - *(sp++)); + *dp = (png_byte)(255 - *(sp++)); + } + } +#endif /* WRITE_16BIT */ + } + + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (row_info->bit_depth == 8) + { + /* This inverts the alpha channel in GA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + *(dp++) = *(sp++); + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + +#ifdef PNG_WRITE_16BIT_SUPPORTED + else + { + /* This inverts the alpha channel in GGAA */ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + /* Does nothing + *(dp++) = *(sp++); + *(dp++) = *(sp++); + */ + sp+=2; dp = sp; + *(dp++) = (png_byte)(255 - *(sp++)); + *dp = (png_byte)(255 - *(sp++)); + } + } +#endif /* WRITE_16BIT */ + } + } +} +#endif + +/* Transform the data according to the user's wishes. The order of + * transformations is significant. + */ +void /* PRIVATE */ +png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info) +{ + png_debug(1, "in png_do_write_transformations"); + + if (png_ptr == NULL) + return; + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) + if (png_ptr->write_user_transform_fn != NULL) + (*(png_ptr->write_user_transform_fn)) /* User write transform + function */ + (png_ptr, /* png_ptr */ + row_info, /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_size_t rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#endif + +#ifdef PNG_WRITE_FILLER_SUPPORTED + if ((png_ptr->transformations & PNG_FILLER) != 0) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + !(png_ptr->flags & PNG_FLAG_FILLER_AFTER)); +#endif + +#ifdef PNG_WRITE_PACKSWAP_SUPPORTED + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + png_do_packswap(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) != 0) + png_do_pack(row_info, png_ptr->row_buf + 1, + (png_uint_32)png_ptr->bit_depth); +#endif + +#ifdef PNG_WRITE_SWAP_SUPPORTED +# ifdef PNG_16BIT_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) + png_do_swap(row_info, png_ptr->row_buf + 1); +# endif +#endif + +#ifdef PNG_WRITE_SHIFT_SUPPORTED + if ((png_ptr->transformations & PNG_SHIFT) != 0) + png_do_shift(row_info, png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif + +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0) + png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) + png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_BGR_SUPPORTED + if ((png_ptr->transformations & PNG_BGR) != 0) + png_do_bgr(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_INVERT_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) + png_do_invert(row_info, png_ptr->row_buf + 1); +#endif +} +#endif /* WRITE_TRANSFORMS */ +#endif /* WRITE */ diff --git a/source/Irrlicht/libpng/pngwutil.c b/source/Irrlicht/libpng/pngwutil.c new file mode 100644 index 00000000..a1ac2752 --- /dev/null +++ b/source/Irrlicht/libpng/pngwutil.c @@ -0,0 +1,2625 @@ + +/* pngwutil.c - utilities to write a PNG file + * + * Last changed in libpng 1.6.22 [May 26, 2016] + * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include "pngpriv.h" + +#ifdef PNG_WRITE_SUPPORTED + +#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED +/* Place a 32-bit number into a buffer in PNG byte order. We work + * with unsigned numbers for convenience, although one supported + * ancillary chunk uses signed (two's complement) numbers. + */ +void PNGAPI +png_save_uint_32(png_bytep buf, png_uint_32 i) +{ + buf[0] = (png_byte)((i >> 24) & 0xffU); + buf[1] = (png_byte)((i >> 16) & 0xffU); + buf[2] = (png_byte)((i >> 8) & 0xffU); + buf[3] = (png_byte)( i & 0xffU); +} + +/* Place a 16-bit number into a buffer in PNG byte order. + * The parameter is declared unsigned int, not png_uint_16, + * just to avoid potential problems on pre-ANSI C compilers. + */ +void PNGAPI +png_save_uint_16(png_bytep buf, unsigned int i) +{ + buf[0] = (png_byte)((i >> 8) & 0xffU); + buf[1] = (png_byte)( i & 0xffU); +} +#endif + +/* Simple function to write the signature. If we have already written + * the magic bytes of the signature, or more likely, the PNG stream is + * being embedded into another stream and doesn't need its own signature, + * we should call png_set_sig_bytes() to tell libpng how many of the + * bytes have already been written. + */ +void PNGAPI +png_write_sig(png_structrp png_ptr) +{ + png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the signature is being written */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_SIGNATURE; +#endif + + /* Write the rest of the 8 byte signature */ + png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes], + (png_size_t)(8 - png_ptr->sig_bytes)); + + if (png_ptr->sig_bytes < 3) + png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; +} + +/* Write the start of a PNG chunk. The type is the chunk type. + * The total_length is the sum of the lengths of all the data you will be + * passing in png_write_chunk_data(). + */ +static void +png_write_chunk_header(png_structrp png_ptr, png_uint_32 chunk_name, + png_uint_32 length) +{ + png_byte buf[8]; + +#if defined(PNG_DEBUG) && (PNG_DEBUG > 0) + PNG_CSTRING_FROM_CHUNK(buf, chunk_name); + png_debug2(0, "Writing %s chunk, length = %lu", buf, (unsigned long)length); +#endif + + if (png_ptr == NULL) + return; + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the chunk header is being written. + * PNG_IO_CHUNK_HDR requires a single I/O call. + */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_HDR; +#endif + + /* Write the length and the chunk name */ + png_save_uint_32(buf, length); + png_save_uint_32(buf + 4, chunk_name); + png_write_data(png_ptr, buf, 8); + + /* Put the chunk name into png_ptr->chunk_name */ + png_ptr->chunk_name = chunk_name; + + /* Reset the crc and run it over the chunk name */ + png_reset_crc(png_ptr); + + png_calculate_crc(png_ptr, buf + 4, 4); + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that chunk data will (possibly) be written. + * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls. + */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_DATA; +#endif +} + +void PNGAPI +png_write_chunk_start(png_structrp png_ptr, png_const_bytep chunk_string, + png_uint_32 length) +{ + png_write_chunk_header(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), length); +} + +/* Write the data of a PNG chunk started with png_write_chunk_header(). + * Note that multiple calls to this function are allowed, and that the + * sum of the lengths from these calls *must* add up to the total_length + * given to png_write_chunk_header(). + */ +void PNGAPI +png_write_chunk_data(png_structrp png_ptr, png_const_bytep data, + png_size_t length) +{ + /* Write the data, and run the CRC over it */ + if (png_ptr == NULL) + return; + + if (data != NULL && length > 0) + { + png_write_data(png_ptr, data, length); + + /* Update the CRC after writing the data, + * in case the user I/O routine alters it. + */ + png_calculate_crc(png_ptr, data, length); + } +} + +/* Finish a chunk started with png_write_chunk_header(). */ +void PNGAPI +png_write_chunk_end(png_structrp png_ptr) +{ + png_byte buf[4]; + + if (png_ptr == NULL) return; + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the chunk CRC is being written. + * PNG_IO_CHUNK_CRC requires a single I/O function call. + */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_CRC; +#endif + + /* Write the crc in a single operation */ + png_save_uint_32(buf, png_ptr->crc); + + png_write_data(png_ptr, buf, (png_size_t)4); +} + +/* Write a PNG chunk all at once. The type is an array of ASCII characters + * representing the chunk name. The array must be at least 4 bytes in + * length, and does not need to be null terminated. To be safe, pass the + * pre-defined chunk names here, and if you need a new one, define it + * where the others are defined. The length is the length of the data. + * All the data must be present. If that is not possible, use the + * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end() + * functions instead. + */ +static void +png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name, + png_const_bytep data, png_size_t length) +{ + if (png_ptr == NULL) + return; + + /* On 64-bit architectures 'length' may not fit in a png_uint_32. */ + if (length > PNG_UINT_31_MAX) + png_error(png_ptr, "length exceeds PNG maximum"); + + png_write_chunk_header(png_ptr, chunk_name, (png_uint_32)length); + png_write_chunk_data(png_ptr, data, length); + png_write_chunk_end(png_ptr); +} + +/* This is the API that calls the internal function above. */ +void PNGAPI +png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string, + png_const_bytep data, png_size_t length) +{ + png_write_complete_chunk(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), data, + length); +} + +/* This is used below to find the size of an image to pass to png_deflate_claim, + * so it only needs to be accurate if the size is less than 16384 bytes (the + * point at which a lower LZ window size can be used.) + */ +static png_alloc_size_t +png_image_size(png_structrp png_ptr) +{ + /* Only return sizes up to the maximum of a png_uint_32; do this by limiting + * the width and height used to 15 bits. + */ + png_uint_32 h = png_ptr->height; + + if (png_ptr->rowbytes < 32768 && h < 32768) + { + if (png_ptr->interlaced != 0) + { + /* Interlacing makes the image larger because of the replication of + * both the filter byte and the padding to a byte boundary. + */ + png_uint_32 w = png_ptr->width; + unsigned int pd = png_ptr->pixel_depth; + png_alloc_size_t cb_base; + int pass; + + for (cb_base=0, pass=0; pass<=6; ++pass) + { + png_uint_32 pw = PNG_PASS_COLS(w, pass); + + if (pw > 0) + cb_base += (PNG_ROWBYTES(pd, pw)+1) * PNG_PASS_ROWS(h, pass); + } + + return cb_base; + } + + else + return (png_ptr->rowbytes+1) * h; + } + + else + return 0xffffffffU; +} + +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + /* This is the code to hack the first two bytes of the deflate stream (the + * deflate header) to correct the windowBits value to match the actual data + * size. Note that the second argument is the *uncompressed* size but the + * first argument is the *compressed* data (and it must be deflate + * compressed.) + */ +static void +optimize_cmf(png_bytep data, png_alloc_size_t data_size) +{ + /* Optimize the CMF field in the zlib stream. The resultant zlib stream is + * still compliant to the stream specification. + */ + if (data_size <= 16384) /* else windowBits must be 15 */ + { + unsigned int z_cmf = data[0]; /* zlib compression method and flags */ + + if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) + { + unsigned int z_cinfo; + unsigned int half_z_window_size; + + z_cinfo = z_cmf >> 4; + half_z_window_size = 1U << (z_cinfo + 7); + + if (data_size <= half_z_window_size) /* else no change */ + { + unsigned int tmp; + + do + { + half_z_window_size >>= 1; + --z_cinfo; + } + while (z_cinfo > 0 && data_size <= half_z_window_size); + + z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); + + data[0] = (png_byte)z_cmf; + tmp = data[1] & 0xe0; + tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f; + data[1] = (png_byte)tmp; + } + } + } +} +#endif /* WRITE_OPTIMIZE_CMF */ + +/* Initialize the compressor for the appropriate type of compression. */ +static int +png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, + png_alloc_size_t data_size) +{ + if (png_ptr->zowner != 0) + { +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED) + char msg[64]; + + PNG_STRING_FROM_CHUNK(msg, owner); + msg[4] = ':'; + msg[5] = ' '; + PNG_STRING_FROM_CHUNK(msg+6, png_ptr->zowner); + /* So the message that results is " using zstream"; this is an + * internal error, but is very useful for debugging. i18n requirements + * are minimal. + */ + (void)png_safecat(msg, (sizeof msg), 10, " using zstream"); +#endif +#if PNG_RELEASE_BUILD + png_warning(png_ptr, msg); + + /* Attempt sane error recovery */ + if (png_ptr->zowner == png_IDAT) /* don't steal from IDAT */ + { + png_ptr->zstream.msg = PNGZ_MSG_CAST("in use by IDAT"); + return Z_STREAM_ERROR; + } + + png_ptr->zowner = 0; +#else + png_error(png_ptr, msg); +#endif + } + + { + int level = png_ptr->zlib_level; + int method = png_ptr->zlib_method; + int windowBits = png_ptr->zlib_window_bits; + int memLevel = png_ptr->zlib_mem_level; + int strategy; /* set below */ + int ret; /* zlib return code */ + + if (owner == png_IDAT) + { + if ((png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY) != 0) + strategy = png_ptr->zlib_strategy; + + else if (png_ptr->do_filter != PNG_FILTER_NONE) + strategy = PNG_Z_DEFAULT_STRATEGY; + + else + strategy = PNG_Z_DEFAULT_NOFILTER_STRATEGY; + } + + else + { +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED + level = png_ptr->zlib_text_level; + method = png_ptr->zlib_text_method; + windowBits = png_ptr->zlib_text_window_bits; + memLevel = png_ptr->zlib_text_mem_level; + strategy = png_ptr->zlib_text_strategy; +#else + /* If customization is not supported the values all come from the + * IDAT values except for the strategy, which is fixed to the + * default. (This is the pre-1.6.0 behavior too, although it was + * implemented in a very different way.) + */ + strategy = Z_DEFAULT_STRATEGY; +#endif + } + + /* Adjust 'windowBits' down if larger than 'data_size'; to stop this + * happening just pass 32768 as the data_size parameter. Notice that zlib + * requires an extra 262 bytes in the window in addition to the data to be + * able to see the whole of the data, so if data_size+262 takes us to the + * next windowBits size we need to fix up the value later. (Because even + * though deflate needs the extra window, inflate does not!) + */ + if (data_size <= 16384) + { + /* IMPLEMENTATION NOTE: this 'half_window_size' stuff is only here to + * work round a Microsoft Visual C misbehavior which, contrary to C-90, + * widens the result of the following shift to 64-bits if (and, + * apparently, only if) it is used in a test. + */ + unsigned int half_window_size = 1U << (windowBits-1); + + while (data_size + 262 <= half_window_size) + { + half_window_size >>= 1; + --windowBits; + } + } + + /* Check against the previous initialized values, if any. */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0 && + (png_ptr->zlib_set_level != level || + png_ptr->zlib_set_method != method || + png_ptr->zlib_set_window_bits != windowBits || + png_ptr->zlib_set_mem_level != memLevel || + png_ptr->zlib_set_strategy != strategy)) + { + if (deflateEnd(&png_ptr->zstream) != Z_OK) + png_warning(png_ptr, "deflateEnd failed (ignored)"); + + png_ptr->flags &= ~PNG_FLAG_ZSTREAM_INITIALIZED; + } + + /* For safety clear out the input and output pointers (currently zlib + * doesn't use them on Init, but it might in the future). + */ + png_ptr->zstream.next_in = NULL; + png_ptr->zstream.avail_in = 0; + png_ptr->zstream.next_out = NULL; + png_ptr->zstream.avail_out = 0; + + /* Now initialize if required, setting the new parameters, otherwise just + * to a simple reset to the previous parameters. + */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) + ret = deflateReset(&png_ptr->zstream); + + else + { + ret = deflateInit2(&png_ptr->zstream, level, method, windowBits, + memLevel, strategy); + + if (ret == Z_OK) + png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; + } + + /* The return code is from either deflateReset or deflateInit2; they have + * pretty much the same set of error codes. + */ + if (ret == Z_OK) + png_ptr->zowner = owner; + + else + png_zstream_error(png_ptr, ret); + + return ret; + } +} + +/* Clean up (or trim) a linked list of compression buffers. */ +void /* PRIVATE */ +png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp) +{ + png_compression_bufferp list = *listp; + + if (list != NULL) + { + *listp = NULL; + + do + { + png_compression_bufferp next = list->next; + + png_free(png_ptr, list); + list = next; + } + while (list != NULL); + } +} + +#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED +/* This pair of functions encapsulates the operation of (a) compressing a + * text string, and (b) issuing it later as a series of chunk data writes. + * The compression_state structure is shared context for these functions + * set up by the caller to allow access to the relevant local variables. + * + * compression_buffer (new in 1.6.0) is just a linked list of zbuffer_size + * temporary buffers. From 1.6.0 it is retained in png_struct so that it will + * be correctly freed in the event of a write error (previous implementations + * just leaked memory.) + */ +typedef struct +{ + png_const_bytep input; /* The uncompressed input data */ + png_alloc_size_t input_len; /* Its length */ + png_uint_32 output_len; /* Final compressed length */ + png_byte output[1024]; /* First block of output */ +} compression_state; + +static void +png_text_compress_init(compression_state *comp, png_const_bytep input, + png_alloc_size_t input_len) +{ + comp->input = input; + comp->input_len = input_len; + comp->output_len = 0; +} + +/* Compress the data in the compression state input */ +static int +png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name, + compression_state *comp, png_uint_32 prefix_len) +{ + int ret; + + /* To find the length of the output it is necessary to first compress the + * input. The result is buffered rather than using the two-pass algorithm + * that is used on the inflate side; deflate is assumed to be slower and a + * PNG writer is assumed to have more memory available than a PNG reader. + * + * IMPLEMENTATION NOTE: the zlib API deflateBound() can be used to find an + * upper limit on the output size, but it is always bigger than the input + * size so it is likely to be more efficient to use this linked-list + * approach. + */ + ret = png_deflate_claim(png_ptr, chunk_name, comp->input_len); + + if (ret != Z_OK) + return ret; + + /* Set up the compression buffers, we need a loop here to avoid overflowing a + * uInt. Use ZLIB_IO_MAX to limit the input. The output is always limited + * by the output buffer size, so there is no need to check that. Since this + * is ANSI-C we know that an 'int', hence a uInt, is always at least 16 bits + * in size. + */ + { + png_compression_bufferp *end = &png_ptr->zbuffer_list; + png_alloc_size_t input_len = comp->input_len; /* may be zero! */ + png_uint_32 output_len; + + /* zlib updates these for us: */ + png_ptr->zstream.next_in = PNGZ_INPUT_CAST(comp->input); + png_ptr->zstream.avail_in = 0; /* Set below */ + png_ptr->zstream.next_out = comp->output; + png_ptr->zstream.avail_out = (sizeof comp->output); + + output_len = png_ptr->zstream.avail_out; + + do + { + uInt avail_in = ZLIB_IO_MAX; + + if (avail_in > input_len) + avail_in = (uInt)input_len; + + input_len -= avail_in; + + png_ptr->zstream.avail_in = avail_in; + + if (png_ptr->zstream.avail_out == 0) + { + png_compression_buffer *next; + + /* Chunk data is limited to 2^31 bytes in length, so the prefix + * length must be counted here. + */ + if (output_len + prefix_len > PNG_UINT_31_MAX) + { + ret = Z_MEM_ERROR; + break; + } + + /* Need a new (malloc'ed) buffer, but there may be one present + * already. + */ + next = *end; + if (next == NULL) + { + next = png_voidcast(png_compression_bufferp, png_malloc_base + (png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); + + if (next == NULL) + { + ret = Z_MEM_ERROR; + break; + } + + /* Link in this buffer (so that it will be freed later) */ + next->next = NULL; + *end = next; + } + + png_ptr->zstream.next_out = next->output; + png_ptr->zstream.avail_out = png_ptr->zbuffer_size; + output_len += png_ptr->zstream.avail_out; + + /* Move 'end' to the next buffer pointer. */ + end = &next->next; + } + + /* Compress the data */ + ret = deflate(&png_ptr->zstream, + input_len > 0 ? Z_NO_FLUSH : Z_FINISH); + + /* Claw back input data that was not consumed (because avail_in is + * reset above every time round the loop). + */ + input_len += png_ptr->zstream.avail_in; + png_ptr->zstream.avail_in = 0; /* safety */ + } + while (ret == Z_OK); + + /* There may be some space left in the last output buffer. This needs to + * be subtracted from output_len. + */ + output_len -= png_ptr->zstream.avail_out; + png_ptr->zstream.avail_out = 0; /* safety */ + comp->output_len = output_len; + + /* Now double check the output length, put in a custom message if it is + * too long. Otherwise ensure the z_stream::msg pointer is set to + * something. + */ + if (output_len + prefix_len >= PNG_UINT_31_MAX) + { + png_ptr->zstream.msg = PNGZ_MSG_CAST("compressed data too long"); + ret = Z_MEM_ERROR; + } + + else + png_zstream_error(png_ptr, ret); + + /* Reset zlib for another zTXt/iTXt or image data */ + png_ptr->zowner = 0; + + /* The only success case is Z_STREAM_END, input_len must be 0; if not this + * is an internal error. + */ + if (ret == Z_STREAM_END && input_len == 0) + { +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + /* Fix up the deflate header, if required */ + optimize_cmf(comp->output, comp->input_len); +#endif + /* But Z_OK is returned, not Z_STREAM_END; this allows the claim + * function above to return Z_STREAM_END on an error (though it never + * does in the current versions of zlib.) + */ + return Z_OK; + } + + else + return ret; + } +} + +/* Ship the compressed text out via chunk writes */ +static void +png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp) +{ + png_uint_32 output_len = comp->output_len; + png_const_bytep output = comp->output; + png_uint_32 avail = (sizeof comp->output); + png_compression_buffer *next = png_ptr->zbuffer_list; + + for (;;) + { + if (avail > output_len) + avail = output_len; + + png_write_chunk_data(png_ptr, output, avail); + + output_len -= avail; + + if (output_len == 0 || next == NULL) + break; + + avail = png_ptr->zbuffer_size; + output = next->output; + next = next->next; + } + + /* This is an internal error; 'next' must have been NULL! */ + if (output_len > 0) + png_error(png_ptr, "error writing ancillary chunked compressed data"); +} +#endif /* WRITE_COMPRESSED_TEXT */ + +/* Write the IHDR chunk, and update the png_struct with the necessary + * information. Note that the rest of this code depends upon this + * information being correct. + */ +void /* PRIVATE */ +png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, + int bit_depth, int color_type, int compression_type, int filter_type, + int interlace_type) +{ + png_byte buf[13]; /* Buffer to store the IHDR info */ + + png_debug(1, "in png_write_IHDR"); + + /* Check that we have valid input data from the application info */ + switch (color_type) + { + case PNG_COLOR_TYPE_GRAY: + switch (bit_depth) + { + case 1: + case 2: + case 4: + case 8: +#ifdef PNG_WRITE_16BIT_SUPPORTED + case 16: +#endif + png_ptr->channels = 1; break; + + default: + png_error(png_ptr, + "Invalid bit depth for grayscale image"); + } + break; + + case PNG_COLOR_TYPE_RGB: +#ifdef PNG_WRITE_16BIT_SUPPORTED + if (bit_depth != 8 && bit_depth != 16) +#else + if (bit_depth != 8) +#endif + png_error(png_ptr, "Invalid bit depth for RGB image"); + + png_ptr->channels = 3; + break; + + case PNG_COLOR_TYPE_PALETTE: + switch (bit_depth) + { + case 1: + case 2: + case 4: + case 8: + png_ptr->channels = 1; + break; + + default: + png_error(png_ptr, "Invalid bit depth for paletted image"); + } + break; + + case PNG_COLOR_TYPE_GRAY_ALPHA: + if (bit_depth != 8 && bit_depth != 16) + png_error(png_ptr, "Invalid bit depth for grayscale+alpha image"); + + png_ptr->channels = 2; + break; + + case PNG_COLOR_TYPE_RGB_ALPHA: +#ifdef PNG_WRITE_16BIT_SUPPORTED + if (bit_depth != 8 && bit_depth != 16) +#else + if (bit_depth != 8) +#endif + png_error(png_ptr, "Invalid bit depth for RGBA image"); + + png_ptr->channels = 4; + break; + + default: + png_error(png_ptr, "Invalid image color type specified"); + } + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + { + png_warning(png_ptr, "Invalid compression type specified"); + compression_type = PNG_COMPRESSION_TYPE_BASE; + } + + /* Write filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not write a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if ( +#ifdef PNG_MNG_FEATURES_SUPPORTED + !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) && + (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) && + (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) && +#endif + filter_type != PNG_FILTER_TYPE_BASE) + { + png_warning(png_ptr, "Invalid filter type specified"); + filter_type = PNG_FILTER_TYPE_BASE; + } + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + if (interlace_type != PNG_INTERLACE_NONE && + interlace_type != PNG_INTERLACE_ADAM7) + { + png_warning(png_ptr, "Invalid interlace type specified"); + interlace_type = PNG_INTERLACE_ADAM7; + } +#else + interlace_type=PNG_INTERLACE_NONE; +#endif + + /* Save the relevant information */ + png_ptr->bit_depth = (png_byte)bit_depth; + png_ptr->color_type = (png_byte)color_type; + png_ptr->interlaced = (png_byte)interlace_type; +#ifdef PNG_MNG_FEATURES_SUPPORTED + png_ptr->filter_type = (png_byte)filter_type; +#endif + png_ptr->compression_type = (png_byte)compression_type; + png_ptr->width = width; + png_ptr->height = height; + + png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels); + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width); + /* Set the usr info, so any transformations can modify it */ + png_ptr->usr_width = png_ptr->width; + png_ptr->usr_bit_depth = png_ptr->bit_depth; + png_ptr->usr_channels = png_ptr->channels; + + /* Pack the header information into the buffer */ + png_save_uint_32(buf, width); + png_save_uint_32(buf + 4, height); + buf[8] = (png_byte)bit_depth; + buf[9] = (png_byte)color_type; + buf[10] = (png_byte)compression_type; + buf[11] = (png_byte)filter_type; + buf[12] = (png_byte)interlace_type; + + /* Write the chunk */ + png_write_complete_chunk(png_ptr, png_IHDR, buf, (png_size_t)13); + + if ((png_ptr->do_filter) == PNG_NO_FILTERS) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || + png_ptr->bit_depth < 8) + png_ptr->do_filter = PNG_FILTER_NONE; + + else + png_ptr->do_filter = PNG_ALL_FILTERS; + } + + png_ptr->mode = PNG_HAVE_IHDR; /* not READY_FOR_ZTXT */ +} + +/* Write the palette. We are careful not to trust png_color to be in the + * correct order for PNG, so people can redefine it to any convenient + * structure. + */ +void /* PRIVATE */ +png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, + png_uint_32 num_pal) +{ + png_uint_32 max_palette_length, i; + png_const_colorp pal_ptr; + png_byte buf[3]; + + png_debug(1, "in png_write_PLTE"); + + max_palette_length = (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ? + (1 << png_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH; + + if (( +#ifdef PNG_MNG_FEATURES_SUPPORTED + (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 && +#endif + num_pal == 0) || num_pal > max_palette_length) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_error(png_ptr, "Invalid number of colors in palette"); + } + + else + { + png_warning(png_ptr, "Invalid number of colors in palette"); + return; + } + } + + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) + { + png_warning(png_ptr, + "Ignoring request to write a PLTE chunk in grayscale PNG"); + + return; + } + + png_ptr->num_palette = (png_uint_16)num_pal; + png_debug1(3, "num_palette = %d", png_ptr->num_palette); + + png_write_chunk_header(png_ptr, png_PLTE, (png_uint_32)(num_pal * 3)); +#ifdef PNG_POINTER_INDEXING_SUPPORTED + + for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++) + { + buf[0] = pal_ptr->red; + buf[1] = pal_ptr->green; + buf[2] = pal_ptr->blue; + png_write_chunk_data(png_ptr, buf, (png_size_t)3); + } + +#else + /* This is a little slower but some buggy compilers need to do this + * instead + */ + pal_ptr=palette; + + for (i = 0; i < num_pal; i++) + { + buf[0] = pal_ptr[i].red; + buf[1] = pal_ptr[i].green; + buf[2] = pal_ptr[i].blue; + png_write_chunk_data(png_ptr, buf, (png_size_t)3); + } + +#endif + png_write_chunk_end(png_ptr); + png_ptr->mode |= PNG_HAVE_PLTE; +} + +/* This is similar to png_text_compress, above, except that it does not require + * all of the data at once and, instead of buffering the compressed result, + * writes it as IDAT chunks. Unlike png_text_compress it *can* png_error out + * because it calls the write interface. As a result it does its own error + * reporting and does not return an error code. In the event of error it will + * just call png_error. The input data length may exceed 32-bits. The 'flush' + * parameter is exactly the same as that to deflate, with the following + * meanings: + * + * Z_NO_FLUSH: normal incremental output of compressed data + * Z_SYNC_FLUSH: do a SYNC_FLUSH, used by png_write_flush + * Z_FINISH: this is the end of the input, do a Z_FINISH and clean up + * + * The routine manages the acquire and release of the png_ptr->zstream by + * checking and (at the end) clearing png_ptr->zowner; it does some sanity + * checks on the 'mode' flags while doing this. + */ +void /* PRIVATE */ +png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, + png_alloc_size_t input_len, int flush) +{ + if (png_ptr->zowner != png_IDAT) + { + /* First time. Ensure we have a temporary buffer for compression and + * trim the buffer list if it has more than one entry to free memory. + * If 'WRITE_COMPRESSED_TEXT' is not set the list will never have been + * created at this point, but the check here is quick and safe. + */ + if (png_ptr->zbuffer_list == NULL) + { + png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp, + png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); + png_ptr->zbuffer_list->next = NULL; + } + + else + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list->next); + + /* It is a terminal error if we can't claim the zstream. */ + if (png_deflate_claim(png_ptr, png_IDAT, png_image_size(png_ptr)) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + + /* The output state is maintained in png_ptr->zstream, so it must be + * initialized here after the claim. + */ + png_ptr->zstream.next_out = png_ptr->zbuffer_list->output; + png_ptr->zstream.avail_out = png_ptr->zbuffer_size; + } + + /* Now loop reading and writing until all the input is consumed or an error + * terminates the operation. The _out values are maintained across calls to + * this function, but the input must be reset each time. + */ + png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input); + png_ptr->zstream.avail_in = 0; /* set below */ + for (;;) + { + int ret; + + /* INPUT: from the row data */ + uInt avail = ZLIB_IO_MAX; + + if (avail > input_len) + avail = (uInt)input_len; /* safe because of the check */ + + png_ptr->zstream.avail_in = avail; + input_len -= avail; + + ret = deflate(&png_ptr->zstream, input_len > 0 ? Z_NO_FLUSH : flush); + + /* Include as-yet unconsumed input */ + input_len += png_ptr->zstream.avail_in; + png_ptr->zstream.avail_in = 0; + + /* OUTPUT: write complete IDAT chunks when avail_out drops to zero. Note + * that these two zstream fields are preserved across the calls, therefore + * there is no need to set these up on entry to the loop. + */ + if (png_ptr->zstream.avail_out == 0) + { + png_bytep data = png_ptr->zbuffer_list->output; + uInt size = png_ptr->zbuffer_size; + + /* Write an IDAT containing the data then reset the buffer. The + * first IDAT may need deflate header optimization. + */ +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + optimize_cmf(data, png_image_size(png_ptr)); +#endif + + png_write_complete_chunk(png_ptr, png_IDAT, data, size); + png_ptr->mode |= PNG_HAVE_IDAT; + + png_ptr->zstream.next_out = data; + png_ptr->zstream.avail_out = size; + + /* For SYNC_FLUSH or FINISH it is essential to keep calling zlib with + * the same flush parameter until it has finished output, for NO_FLUSH + * it doesn't matter. + */ + if (ret == Z_OK && flush != Z_NO_FLUSH) + continue; + } + + /* The order of these checks doesn't matter much; it just affects which + * possible error might be detected if multiple things go wrong at once. + */ + if (ret == Z_OK) /* most likely return code! */ + { + /* If all the input has been consumed then just return. If Z_FINISH + * was used as the flush parameter something has gone wrong if we get + * here. + */ + if (input_len == 0) + { + if (flush == Z_FINISH) + png_error(png_ptr, "Z_OK on Z_FINISH with output space"); + + return; + } + } + + else if (ret == Z_STREAM_END && flush == Z_FINISH) + { + /* This is the end of the IDAT data; any pending output must be + * flushed. For small PNG files we may still be at the beginning. + */ + png_bytep data = png_ptr->zbuffer_list->output; + uInt size = png_ptr->zbuffer_size - png_ptr->zstream.avail_out; + +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + optimize_cmf(data, png_image_size(png_ptr)); +#endif + + png_write_complete_chunk(png_ptr, png_IDAT, data, size); + png_ptr->zstream.avail_out = 0; + png_ptr->zstream.next_out = NULL; + png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT; + + png_ptr->zowner = 0; /* Release the stream */ + return; + } + + else + { + /* This is an error condition. */ + png_zstream_error(png_ptr, ret); + png_error(png_ptr, png_ptr->zstream.msg); + } + } +} + +/* Write an IEND chunk */ +void /* PRIVATE */ +png_write_IEND(png_structrp png_ptr) +{ + png_debug(1, "in png_write_IEND"); + + png_write_complete_chunk(png_ptr, png_IEND, NULL, (png_size_t)0); + png_ptr->mode |= PNG_HAVE_IEND; +} + +#ifdef PNG_WRITE_gAMA_SUPPORTED +/* Write a gAMA chunk */ +void /* PRIVATE */ +png_write_gAMA_fixed(png_structrp png_ptr, png_fixed_point file_gamma) +{ + png_byte buf[4]; + + png_debug(1, "in png_write_gAMA"); + + /* file_gamma is saved in 1/100,000ths */ + png_save_uint_32(buf, (png_uint_32)file_gamma); + png_write_complete_chunk(png_ptr, png_gAMA, buf, (png_size_t)4); +} +#endif + +#ifdef PNG_WRITE_sRGB_SUPPORTED +/* Write a sRGB chunk */ +void /* PRIVATE */ +png_write_sRGB(png_structrp png_ptr, int srgb_intent) +{ + png_byte buf[1]; + + png_debug(1, "in png_write_sRGB"); + + if (srgb_intent >= PNG_sRGB_INTENT_LAST) + png_warning(png_ptr, + "Invalid sRGB rendering intent specified"); + + buf[0]=(png_byte)srgb_intent; + png_write_complete_chunk(png_ptr, png_sRGB, buf, (png_size_t)1); +} +#endif + +#ifdef PNG_WRITE_iCCP_SUPPORTED +/* Write an iCCP chunk */ +void /* PRIVATE */ +png_write_iCCP(png_structrp png_ptr, png_const_charp name, + png_const_bytep profile) +{ + png_uint_32 name_len; + png_uint_32 profile_len; + png_byte new_name[81]; /* 1 byte for the compression byte */ + compression_state comp; + png_uint_32 temp; + + png_debug(1, "in png_write_iCCP"); + + /* These are all internal problems: the profile should have been checked + * before when it was stored. + */ + if (profile == NULL) + png_error(png_ptr, "No profile for iCCP chunk"); /* internal error */ + + profile_len = png_get_uint_32(profile); + + if (profile_len < 132) + png_error(png_ptr, "ICC profile too short"); + + temp = (png_uint_32) (*(profile+8)); + if (temp > 3 && (profile_len & 0x03)) + png_error(png_ptr, "ICC profile length invalid (not a multiple of 4)"); + + { + png_uint_32 embedded_profile_len = png_get_uint_32(profile); + + if (profile_len != embedded_profile_len) + png_error(png_ptr, "Profile length does not match profile"); + } + + name_len = png_check_keyword(png_ptr, name, new_name); + + if (name_len == 0) + png_error(png_ptr, "iCCP: invalid keyword"); + + new_name[++name_len] = PNG_COMPRESSION_TYPE_BASE; + + /* Make sure we include the NULL after the name and the compression type */ + ++name_len; + + png_text_compress_init(&comp, profile, profile_len); + + /* Allow for keyword terminator and compression byte */ + if (png_text_compress(png_ptr, png_iCCP, &comp, name_len) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + + png_write_chunk_header(png_ptr, png_iCCP, name_len + comp.output_len); + + png_write_chunk_data(png_ptr, new_name, name_len); + + png_write_compressed_data_out(png_ptr, &comp); + + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_sPLT_SUPPORTED +/* Write a sPLT chunk */ +void /* PRIVATE */ +png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette) +{ + png_uint_32 name_len; + png_byte new_name[80]; + png_byte entrybuf[10]; + png_size_t entry_size = (spalette->depth == 8 ? 6 : 10); + png_size_t palette_size = entry_size * spalette->nentries; + png_sPLT_entryp ep; +#ifndef PNG_POINTER_INDEXING_SUPPORTED + int i; +#endif + + png_debug(1, "in png_write_sPLT"); + + name_len = png_check_keyword(png_ptr, spalette->name, new_name); + + if (name_len == 0) + png_error(png_ptr, "sPLT: invalid keyword"); + + /* Make sure we include the NULL after the name */ + png_write_chunk_header(png_ptr, png_sPLT, + (png_uint_32)(name_len + 2 + palette_size)); + + png_write_chunk_data(png_ptr, (png_bytep)new_name, + (png_size_t)(name_len + 1)); + + png_write_chunk_data(png_ptr, &spalette->depth, (png_size_t)1); + + /* Loop through each palette entry, writing appropriately */ +#ifdef PNG_POINTER_INDEXING_SUPPORTED + for (ep = spalette->entries; epentries + spalette->nentries; ep++) + { + if (spalette->depth == 8) + { + entrybuf[0] = (png_byte)ep->red; + entrybuf[1] = (png_byte)ep->green; + entrybuf[2] = (png_byte)ep->blue; + entrybuf[3] = (png_byte)ep->alpha; + png_save_uint_16(entrybuf + 4, ep->frequency); + } + + else + { + png_save_uint_16(entrybuf + 0, ep->red); + png_save_uint_16(entrybuf + 2, ep->green); + png_save_uint_16(entrybuf + 4, ep->blue); + png_save_uint_16(entrybuf + 6, ep->alpha); + png_save_uint_16(entrybuf + 8, ep->frequency); + } + + png_write_chunk_data(png_ptr, entrybuf, entry_size); + } +#else + ep=spalette->entries; + for (i = 0; i>spalette->nentries; i++) + { + if (spalette->depth == 8) + { + entrybuf[0] = (png_byte)ep[i].red; + entrybuf[1] = (png_byte)ep[i].green; + entrybuf[2] = (png_byte)ep[i].blue; + entrybuf[3] = (png_byte)ep[i].alpha; + png_save_uint_16(entrybuf + 4, ep[i].frequency); + } + + else + { + png_save_uint_16(entrybuf + 0, ep[i].red); + png_save_uint_16(entrybuf + 2, ep[i].green); + png_save_uint_16(entrybuf + 4, ep[i].blue); + png_save_uint_16(entrybuf + 6, ep[i].alpha); + png_save_uint_16(entrybuf + 8, ep[i].frequency); + } + + png_write_chunk_data(png_ptr, entrybuf, entry_size); + } +#endif + + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_sBIT_SUPPORTED +/* Write the sBIT chunk */ +void /* PRIVATE */ +png_write_sBIT(png_structrp png_ptr, png_const_color_8p sbit, int color_type) +{ + png_byte buf[4]; + png_size_t size; + + png_debug(1, "in png_write_sBIT"); + + /* Make sure we don't depend upon the order of PNG_COLOR_8 */ + if ((color_type & PNG_COLOR_MASK_COLOR) != 0) + { + png_byte maxbits; + + maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 : + png_ptr->usr_bit_depth); + + if (sbit->red == 0 || sbit->red > maxbits || + sbit->green == 0 || sbit->green > maxbits || + sbit->blue == 0 || sbit->blue > maxbits) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + + buf[0] = sbit->red; + buf[1] = sbit->green; + buf[2] = sbit->blue; + size = 3; + } + + else + { + if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + + buf[0] = sbit->gray; + size = 1; + } + + if ((color_type & PNG_COLOR_MASK_ALPHA) != 0) + { + if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + + buf[size++] = sbit->alpha; + } + + png_write_complete_chunk(png_ptr, png_sBIT, buf, size); +} +#endif + +#ifdef PNG_WRITE_cHRM_SUPPORTED +/* Write the cHRM chunk */ +void /* PRIVATE */ +png_write_cHRM_fixed(png_structrp png_ptr, const png_xy *xy) +{ + png_byte buf[32]; + + png_debug(1, "in png_write_cHRM"); + + /* Each value is saved in 1/100,000ths */ + png_save_int_32(buf, xy->whitex); + png_save_int_32(buf + 4, xy->whitey); + + png_save_int_32(buf + 8, xy->redx); + png_save_int_32(buf + 12, xy->redy); + + png_save_int_32(buf + 16, xy->greenx); + png_save_int_32(buf + 20, xy->greeny); + + png_save_int_32(buf + 24, xy->bluex); + png_save_int_32(buf + 28, xy->bluey); + + png_write_complete_chunk(png_ptr, png_cHRM, buf, 32); +} +#endif + +#ifdef PNG_WRITE_tRNS_SUPPORTED +/* Write the tRNS chunk */ +void /* PRIVATE */ +png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha, + png_const_color_16p tran, int num_trans, int color_type) +{ + png_byte buf[6]; + + png_debug(1, "in png_write_tRNS"); + + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette) + { + png_app_warning(png_ptr, + "Invalid number of transparent colors specified"); + return; + } + + /* Write the chunk out as it is */ + png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha, + (png_size_t)num_trans); + } + + else if (color_type == PNG_COLOR_TYPE_GRAY) + { + /* One 16-bit value */ + if (tran->gray >= (1 << png_ptr->bit_depth)) + { + png_app_warning(png_ptr, + "Ignoring attempt to write tRNS chunk out-of-range for bit_depth"); + + return; + } + + png_save_uint_16(buf, tran->gray); + png_write_complete_chunk(png_ptr, png_tRNS, buf, (png_size_t)2); + } + + else if (color_type == PNG_COLOR_TYPE_RGB) + { + /* Three 16-bit values */ + png_save_uint_16(buf, tran->red); + png_save_uint_16(buf + 2, tran->green); + png_save_uint_16(buf + 4, tran->blue); +#ifdef PNG_WRITE_16BIT_SUPPORTED + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0) +#else + if ((buf[0] | buf[2] | buf[4]) != 0) +#endif + { + png_app_warning(png_ptr, + "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8"); + return; + } + + png_write_complete_chunk(png_ptr, png_tRNS, buf, (png_size_t)6); + } + + else + { + png_app_warning(png_ptr, "Can't write tRNS with an alpha channel"); + } +} +#endif + +#ifdef PNG_WRITE_bKGD_SUPPORTED +/* Write the background chunk */ +void /* PRIVATE */ +png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type) +{ + png_byte buf[6]; + + png_debug(1, "in png_write_bKGD"); + + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + if ( +#ifdef PNG_MNG_FEATURES_SUPPORTED + (png_ptr->num_palette != 0 || + (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0) && +#endif + back->index >= png_ptr->num_palette) + { + png_warning(png_ptr, "Invalid background palette index"); + return; + } + + buf[0] = back->index; + png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)1); + } + + else if ((color_type & PNG_COLOR_MASK_COLOR) != 0) + { + png_save_uint_16(buf, back->red); + png_save_uint_16(buf + 2, back->green); + png_save_uint_16(buf + 4, back->blue); +#ifdef PNG_WRITE_16BIT_SUPPORTED + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0) +#else + if ((buf[0] | buf[2] | buf[4]) != 0) +#endif + { + png_warning(png_ptr, + "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8"); + + return; + } + + png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)6); + } + + else + { + if (back->gray >= (1 << png_ptr->bit_depth)) + { + png_warning(png_ptr, + "Ignoring attempt to write bKGD chunk out-of-range for bit_depth"); + + return; + } + + png_save_uint_16(buf, back->gray); + png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)2); + } +} +#endif + +#ifdef PNG_WRITE_hIST_SUPPORTED +/* Write the histogram */ +void /* PRIVATE */ +png_write_hIST(png_structrp png_ptr, png_const_uint_16p hist, int num_hist) +{ + int i; + png_byte buf[3]; + + png_debug(1, "in png_write_hIST"); + + if (num_hist > (int)png_ptr->num_palette) + { + png_debug2(3, "num_hist = %d, num_palette = %d", num_hist, + png_ptr->num_palette); + + png_warning(png_ptr, "Invalid number of histogram entries specified"); + return; + } + + png_write_chunk_header(png_ptr, png_hIST, (png_uint_32)(num_hist * 2)); + + for (i = 0; i < num_hist; i++) + { + png_save_uint_16(buf, hist[i]); + png_write_chunk_data(png_ptr, buf, (png_size_t)2); + } + + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_tEXt_SUPPORTED +/* Write a tEXt chunk */ +void /* PRIVATE */ +png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, + png_size_t text_len) +{ + png_uint_32 key_len; + png_byte new_key[80]; + + png_debug(1, "in png_write_tEXt"); + + key_len = png_check_keyword(png_ptr, key, new_key); + + if (key_len == 0) + png_error(png_ptr, "tEXt: invalid keyword"); + + if (text == NULL || *text == '\0') + text_len = 0; + + else + text_len = strlen(text); + + if (text_len > PNG_UINT_31_MAX - (key_len+1)) + png_error(png_ptr, "tEXt: text too long"); + + /* Make sure we include the 0 after the key */ + png_write_chunk_header(png_ptr, png_tEXt, + (png_uint_32)/*checked above*/(key_len + text_len + 1)); + /* + * We leave it to the application to meet PNG-1.0 requirements on the + * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of + * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. + * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. + */ + png_write_chunk_data(png_ptr, new_key, key_len + 1); + + if (text_len != 0) + png_write_chunk_data(png_ptr, (png_const_bytep)text, text_len); + + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_zTXt_SUPPORTED +/* Write a compressed text chunk */ +void /* PRIVATE */ +png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, + int compression) +{ + png_uint_32 key_len; + png_byte new_key[81]; + compression_state comp; + + png_debug(1, "in png_write_zTXt"); + + if (compression == PNG_TEXT_COMPRESSION_NONE) + { + png_write_tEXt(png_ptr, key, text, 0); + return; + } + + if (compression != PNG_TEXT_COMPRESSION_zTXt) + png_error(png_ptr, "zTXt: invalid compression type"); + + key_len = png_check_keyword(png_ptr, key, new_key); + + if (key_len == 0) + png_error(png_ptr, "zTXt: invalid keyword"); + + /* Add the compression method and 1 for the keyword separator. */ + new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE; + ++key_len; + + /* Compute the compressed data; do it now for the length */ + png_text_compress_init(&comp, (png_const_bytep)text, + text == NULL ? 0 : strlen(text)); + + if (png_text_compress(png_ptr, png_zTXt, &comp, key_len) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + + /* Write start of chunk */ + png_write_chunk_header(png_ptr, png_zTXt, key_len + comp.output_len); + + /* Write key */ + png_write_chunk_data(png_ptr, new_key, key_len); + + /* Write the compressed data */ + png_write_compressed_data_out(png_ptr, &comp); + + /* Close the chunk */ + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_iTXt_SUPPORTED +/* Write an iTXt chunk */ +void /* PRIVATE */ +png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key, + png_const_charp lang, png_const_charp lang_key, png_const_charp text) +{ + png_uint_32 key_len, prefix_len; + png_size_t lang_len, lang_key_len; + png_byte new_key[82]; + compression_state comp; + + png_debug(1, "in png_write_iTXt"); + + key_len = png_check_keyword(png_ptr, key, new_key); + + if (key_len == 0) + png_error(png_ptr, "iTXt: invalid keyword"); + + /* Set the compression flag */ + switch (compression) + { + case PNG_ITXT_COMPRESSION_NONE: + case PNG_TEXT_COMPRESSION_NONE: + compression = new_key[++key_len] = 0; /* no compression */ + break; + + case PNG_TEXT_COMPRESSION_zTXt: + case PNG_ITXT_COMPRESSION_zTXt: + compression = new_key[++key_len] = 1; /* compressed */ + break; + + default: + png_error(png_ptr, "iTXt: invalid compression"); + } + + new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE; + ++key_len; /* for the keywod separator */ + + /* We leave it to the application to meet PNG-1.0 requirements on the + * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of + * any non-Latin-1 characters except for NEWLINE. ISO PNG, however, + * specifies that the text is UTF-8 and this really doesn't require any + * checking. + * + * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. + * + * TODO: validate the language tag correctly (see the spec.) + */ + if (lang == NULL) lang = ""; /* empty language is valid */ + lang_len = strlen(lang)+1; + if (lang_key == NULL) lang_key = ""; /* may be empty */ + lang_key_len = strlen(lang_key)+1; + if (text == NULL) text = ""; /* may be empty */ + + prefix_len = key_len; + if (lang_len > PNG_UINT_31_MAX-prefix_len) + prefix_len = PNG_UINT_31_MAX; + else + prefix_len = (png_uint_32)(prefix_len + lang_len); + + if (lang_key_len > PNG_UINT_31_MAX-prefix_len) + prefix_len = PNG_UINT_31_MAX; + else + prefix_len = (png_uint_32)(prefix_len + lang_key_len); + + png_text_compress_init(&comp, (png_const_bytep)text, strlen(text)); + + if (compression != 0) + { + if (png_text_compress(png_ptr, png_iTXt, &comp, prefix_len) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + } + + else + { + if (comp.input_len > PNG_UINT_31_MAX-prefix_len) + png_error(png_ptr, "iTXt: uncompressed text too long"); + + /* So the string will fit in a chunk: */ + comp.output_len = (png_uint_32)/*SAFE*/comp.input_len; + } + + png_write_chunk_header(png_ptr, png_iTXt, comp.output_len + prefix_len); + + png_write_chunk_data(png_ptr, new_key, key_len); + + png_write_chunk_data(png_ptr, (png_const_bytep)lang, lang_len); + + png_write_chunk_data(png_ptr, (png_const_bytep)lang_key, lang_key_len); + + if (compression != 0) + png_write_compressed_data_out(png_ptr, &comp); + + else + png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.output_len); + + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_oFFs_SUPPORTED +/* Write the oFFs chunk */ +void /* PRIVATE */ +png_write_oFFs(png_structrp png_ptr, png_int_32 x_offset, png_int_32 y_offset, + int unit_type) +{ + png_byte buf[9]; + + png_debug(1, "in png_write_oFFs"); + + if (unit_type >= PNG_OFFSET_LAST) + png_warning(png_ptr, "Unrecognized unit type for oFFs chunk"); + + png_save_int_32(buf, x_offset); + png_save_int_32(buf + 4, y_offset); + buf[8] = (png_byte)unit_type; + + png_write_complete_chunk(png_ptr, png_oFFs, buf, (png_size_t)9); +} +#endif +#ifdef PNG_WRITE_pCAL_SUPPORTED +/* Write the pCAL chunk (described in the PNG extensions document) */ +void /* PRIVATE */ +png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0, + png_int_32 X1, int type, int nparams, png_const_charp units, + png_charpp params) +{ + png_uint_32 purpose_len; + png_size_t units_len, total_len; + png_size_tp params_len; + png_byte buf[10]; + png_byte new_purpose[80]; + int i; + + png_debug1(1, "in png_write_pCAL (%d parameters)", nparams); + + if (type >= PNG_EQUATION_LAST) + png_error(png_ptr, "Unrecognized equation type for pCAL chunk"); + + purpose_len = png_check_keyword(png_ptr, purpose, new_purpose); + + if (purpose_len == 0) + png_error(png_ptr, "pCAL: invalid keyword"); + + ++purpose_len; /* terminator */ + + png_debug1(3, "pCAL purpose length = %d", (int)purpose_len); + units_len = strlen(units) + (nparams == 0 ? 0 : 1); + png_debug1(3, "pCAL units length = %d", (int)units_len); + total_len = purpose_len + units_len + 10; + + params_len = (png_size_tp)png_malloc(png_ptr, + (png_alloc_size_t)(nparams * (sizeof (png_size_t)))); + + /* Find the length of each parameter, making sure we don't count the + * null terminator for the last parameter. + */ + for (i = 0; i < nparams; i++) + { + params_len[i] = strlen(params[i]) + (i == nparams - 1 ? 0 : 1); + png_debug2(3, "pCAL parameter %d length = %lu", i, + (unsigned long)params_len[i]); + total_len += params_len[i]; + } + + png_debug1(3, "pCAL total length = %d", (int)total_len); + png_write_chunk_header(png_ptr, png_pCAL, (png_uint_32)total_len); + png_write_chunk_data(png_ptr, new_purpose, purpose_len); + png_save_int_32(buf, X0); + png_save_int_32(buf + 4, X1); + buf[8] = (png_byte)type; + buf[9] = (png_byte)nparams; + png_write_chunk_data(png_ptr, buf, (png_size_t)10); + png_write_chunk_data(png_ptr, (png_const_bytep)units, (png_size_t)units_len); + + for (i = 0; i < nparams; i++) + { + png_write_chunk_data(png_ptr, (png_const_bytep)params[i], params_len[i]); + } + + png_free(png_ptr, params_len); + png_write_chunk_end(png_ptr); +} +#endif + +#ifdef PNG_WRITE_sCAL_SUPPORTED +/* Write the sCAL chunk */ +void /* PRIVATE */ +png_write_sCAL_s(png_structrp png_ptr, int unit, png_const_charp width, + png_const_charp height) +{ + png_byte buf[64]; + png_size_t wlen, hlen, total_len; + + png_debug(1, "in png_write_sCAL_s"); + + wlen = strlen(width); + hlen = strlen(height); + total_len = wlen + hlen + 2; + + if (total_len > 64) + { + png_warning(png_ptr, "Can't write sCAL (buffer too small)"); + return; + } + + buf[0] = (png_byte)unit; + memcpy(buf + 1, width, wlen + 1); /* Append the '\0' here */ + memcpy(buf + wlen + 2, height, hlen); /* Do NOT append the '\0' here */ + + png_debug1(3, "sCAL total length = %u", (unsigned int)total_len); + png_write_complete_chunk(png_ptr, png_sCAL, buf, total_len); +} +#endif + +#ifdef PNG_WRITE_pHYs_SUPPORTED +/* Write the pHYs chunk */ +void /* PRIVATE */ +png_write_pHYs(png_structrp png_ptr, png_uint_32 x_pixels_per_unit, + png_uint_32 y_pixels_per_unit, + int unit_type) +{ + png_byte buf[9]; + + png_debug(1, "in png_write_pHYs"); + + if (unit_type >= PNG_RESOLUTION_LAST) + png_warning(png_ptr, "Unrecognized unit type for pHYs chunk"); + + png_save_uint_32(buf, x_pixels_per_unit); + png_save_uint_32(buf + 4, y_pixels_per_unit); + buf[8] = (png_byte)unit_type; + + png_write_complete_chunk(png_ptr, png_pHYs, buf, (png_size_t)9); +} +#endif + +#ifdef PNG_WRITE_tIME_SUPPORTED +/* Write the tIME chunk. Use either png_convert_from_struct_tm() + * or png_convert_from_time_t(), or fill in the structure yourself. + */ +void /* PRIVATE */ +png_write_tIME(png_structrp png_ptr, png_const_timep mod_time) +{ + png_byte buf[7]; + + png_debug(1, "in png_write_tIME"); + + if (mod_time->month > 12 || mod_time->month < 1 || + mod_time->day > 31 || mod_time->day < 1 || + mod_time->hour > 23 || mod_time->second > 60) + { + png_warning(png_ptr, "Invalid time specified for tIME chunk"); + return; + } + + png_save_uint_16(buf, mod_time->year); + buf[2] = mod_time->month; + buf[3] = mod_time->day; + buf[4] = mod_time->hour; + buf[5] = mod_time->minute; + buf[6] = mod_time->second; + + png_write_complete_chunk(png_ptr, png_tIME, buf, (png_size_t)7); +} +#endif + +/* Initializes the row writing capability of libpng */ +void /* PRIVATE */ +png_write_start_row(png_structrp png_ptr) +{ +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + png_alloc_size_t buf_size; + int usr_pixel_depth; + +#ifdef PNG_WRITE_FILTER_SUPPORTED + png_byte filters; +#endif + + png_debug(1, "in png_write_start_row"); + + usr_pixel_depth = png_ptr->usr_channels * png_ptr->usr_bit_depth; + buf_size = PNG_ROWBYTES(usr_pixel_depth, png_ptr->width) + 1; + + /* 1.5.6: added to allow checking in the row write code. */ + png_ptr->transformed_pixel_depth = png_ptr->pixel_depth; + png_ptr->maximum_pixel_depth = (png_byte)usr_pixel_depth; + + /* Set up row buffer */ + png_ptr->row_buf = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size)); + + png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE; + +#ifdef PNG_WRITE_FILTER_SUPPORTED + filters = png_ptr->do_filter; + + if (png_ptr->height == 1) + filters &= 0xff & ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH); + + if (png_ptr->width == 1) + filters &= 0xff & ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH); + + if (filters == 0) + filters = PNG_FILTER_NONE; + + png_ptr->do_filter = filters; + + if (((filters & (PNG_FILTER_SUB | PNG_FILTER_UP | PNG_FILTER_AVG | + PNG_FILTER_PAETH)) != 0) && png_ptr->try_row == NULL) + { + int num_filters = 0; + + png_ptr->try_row = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size)); + + if (filters & PNG_FILTER_SUB) + num_filters++; + + if (filters & PNG_FILTER_UP) + num_filters++; + + if (filters & PNG_FILTER_AVG) + num_filters++; + + if (filters & PNG_FILTER_PAETH) + num_filters++; + + if (num_filters > 1) + png_ptr->tst_row = png_voidcast(png_bytep, png_malloc(png_ptr, + buf_size)); + } + + /* We only need to keep the previous row if we are using one of the following + * filters. + */ + if ((filters & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) != 0) + png_ptr->prev_row = png_voidcast(png_bytep, + png_calloc(png_ptr, buf_size)); +#endif /* WRITE_FILTER */ + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* If interlaced, we need to set up width and height of pass */ + if (png_ptr->interlaced != 0) + { + if ((png_ptr->transformations & PNG_INTERLACE) == 0) + { + png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - + png_pass_ystart[0]) / png_pass_yinc[0]; + + png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 - + png_pass_start[0]) / png_pass_inc[0]; + } + + else + { + png_ptr->num_rows = png_ptr->height; + png_ptr->usr_width = png_ptr->width; + } + } + + else +#endif + { + png_ptr->num_rows = png_ptr->height; + png_ptr->usr_width = png_ptr->width; + } +} + +/* Internal use only. Called when finished processing a row of data. */ +void /* PRIVATE */ +png_write_finish_row(png_structrp png_ptr) +{ +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + png_debug(1, "in png_write_finish_row"); + + /* Next row */ + png_ptr->row_number++; + + /* See if we are done */ + if (png_ptr->row_number < png_ptr->num_rows) + return; + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* If interlaced, go to next pass */ + if (png_ptr->interlaced != 0) + { + png_ptr->row_number = 0; + if ((png_ptr->transformations & PNG_INTERLACE) != 0) + { + png_ptr->pass++; + } + + else + { + /* Loop until we find a non-zero width or height pass */ + do + { + png_ptr->pass++; + + if (png_ptr->pass >= 7) + break; + + png_ptr->usr_width = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + + if ((png_ptr->transformations & PNG_INTERLACE) != 0) + break; + + } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0); + + } + + /* Reset the row above the image for the next pass */ + if (png_ptr->pass < 7) + { + if (png_ptr->prev_row != NULL) + memset(png_ptr->prev_row, 0, + (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels* + png_ptr->usr_bit_depth, png_ptr->width)) + 1); + + return; + } + } +#endif + + /* If we get here, we've just written the last row, so we need + to flush the compressor */ + png_compress_IDAT(png_ptr, NULL, 0, Z_FINISH); +} + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED +/* Pick out the correct pixels for the interlace pass. + * The basic idea here is to go through the row with a source + * pointer and a destination pointer (sp and dp), and copy the + * correct pixels for the pass. As the row gets compacted, + * sp will always be >= dp, so we should never overwrite anything. + * See the default: case for the easiest code to understand. + */ +void /* PRIVATE */ +png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) +{ + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + png_debug(1, "in png_do_write_interlace"); + + /* We don't have to do anything on the last pass (6) */ + if (pass < 6) + { + /* Each pixel depth is handled separately */ + switch (row_info->pixel_depth) + { + case 1: + { + png_bytep sp; + png_bytep dp; + unsigned int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + d = 0; + shift = 7; + + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (png_size_t)(i >> 3); + value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01; + d |= (value << shift); + + if (shift == 0) + { + shift = 7; + *dp++ = (png_byte)d; + d = 0; + } + + else + shift--; + + } + if (shift != 7) + *dp = (png_byte)d; + + break; + } + + case 2: + { + png_bytep sp; + png_bytep dp; + unsigned int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + shift = 6; + d = 0; + + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (png_size_t)(i >> 2); + value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03; + d |= (value << shift); + + if (shift == 0) + { + shift = 6; + *dp++ = (png_byte)d; + d = 0; + } + + else + shift -= 2; + } + if (shift != 6) + *dp = (png_byte)d; + + break; + } + + case 4: + { + png_bytep sp; + png_bytep dp; + unsigned int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + shift = 4; + d = 0; + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (png_size_t)(i >> 1); + value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f; + d |= (value << shift); + + if (shift == 0) + { + shift = 4; + *dp++ = (png_byte)d; + d = 0; + } + + else + shift -= 4; + } + if (shift != 4) + *dp = (png_byte)d; + + break; + } + + default: + { + png_bytep sp; + png_bytep dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + png_size_t pixel_bytes; + + /* Start at the beginning */ + dp = row; + + /* Find out how many bytes each pixel takes up */ + pixel_bytes = (row_info->pixel_depth >> 3); + + /* Loop through the row, only looking at the pixels that matter */ + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + /* Find out where the original pixel is */ + sp = row + (png_size_t)i * pixel_bytes; + + /* Move the pixel */ + if (dp != sp) + memcpy(dp, sp, pixel_bytes); + + /* Next pixel */ + dp += pixel_bytes; + } + break; + } + } + /* Set new row width */ + row_info->width = (row_info->width + + png_pass_inc[pass] - 1 - + png_pass_start[pass]) / + png_pass_inc[pass]; + + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_info->width); + } +} +#endif + + +/* This filters the row, chooses which filter to use, if it has not already + * been specified by the application, and then writes the row out with the + * chosen filter. + */ +static void /* PRIVATE */ +png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, + png_size_t row_bytes); + +#ifdef PNG_WRITE_FILTER_SUPPORTED +static png_size_t /* PRIVATE */ +png_setup_sub_row(png_structrp png_ptr, const png_uint_32 bpp, + const png_size_t row_bytes, const png_size_t lmins) +{ + png_bytep rp, dp, lp; + png_size_t i; + png_size_t sum = 0; + int v; + + png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB; + + for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp; + i++, rp++, dp++) + { + v = *dp = *rp; + sum += (v < 128) ? v : 256 - v; + } + + for (lp = png_ptr->row_buf + 1; i < row_bytes; + i++, rp++, lp++, dp++) + { + v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + + return (sum); +} + +static png_size_t /* PRIVATE */ +png_setup_up_row(png_structrp png_ptr, const png_size_t row_bytes, + const png_size_t lmins) +{ + png_bytep rp, dp, pp; + png_size_t i; + png_size_t sum = 0; + int v; + + png_ptr->try_row[0] = PNG_FILTER_VALUE_UP; + + for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, + pp = png_ptr->prev_row + 1; i < row_bytes; + i++, rp++, pp++, dp++) + { + v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + + return (sum); +} + +static png_size_t /* PRIVATE */ +png_setup_avg_row(png_structrp png_ptr, const png_uint_32 bpp, + const png_size_t row_bytes, const png_size_t lmins) +{ + png_bytep rp, dp, pp, lp; + png_uint_32 i; + png_size_t sum = 0; + int v; + + png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG; + + for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, + pp = png_ptr->prev_row + 1; i < bpp; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); + + sum += (v < 128) ? v : 256 - v; + } + + for (lp = png_ptr->row_buf + 1; i < row_bytes; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) + & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + + return (sum); +} + +static png_size_t /* PRIVATE */ +png_setup_paeth_row(png_structrp png_ptr, const png_uint_32 bpp, + const png_size_t row_bytes, const png_size_t lmins) +{ + png_bytep rp, dp, pp, cp, lp; + png_size_t i; + png_size_t sum = 0; + int v; + + png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH; + + for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, + pp = png_ptr->prev_row + 1; i < bpp; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + + sum += (v < 128) ? v : 256 - v; + } + + for (lp = png_ptr->row_buf + 1, cp = png_ptr->prev_row + 1; i < row_bytes; + i++) + { + int a, b, c, pa, pb, pc, p; + + b = *pp++; + c = *cp++; + a = *lp++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; + + v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + + return (sum); +} +#endif /* WRITE_FILTER */ + +void /* PRIVATE */ +png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) +{ +#ifndef PNG_WRITE_FILTER_SUPPORTED + png_write_filtered_row(png_ptr, png_ptr->row_buf, row_info->rowbytes+1); +#else + png_byte filter_to_do = png_ptr->do_filter; + png_bytep row_buf; + png_bytep best_row; + png_uint_32 bpp; + png_size_t mins; + png_size_t row_bytes = row_info->rowbytes; + + png_debug(1, "in png_write_find_filter"); + + /* Find out how many bytes offset each pixel is */ + bpp = (row_info->pixel_depth + 7) >> 3; + + row_buf = png_ptr->row_buf; + mins = PNG_SIZE_MAX - 256/* so we can detect potential overflow of the + running sum */; + + /* The prediction method we use is to find which method provides the + * smallest value when summing the absolute values of the distances + * from zero, using anything >= 128 as negative numbers. This is known + * as the "minimum sum of absolute differences" heuristic. Other + * heuristics are the "weighted minimum sum of absolute differences" + * (experimental and can in theory improve compression), and the "zlib + * predictive" method (not implemented yet), which does test compressions + * of lines using different filter methods, and then chooses the + * (series of) filter(s) that give minimum compressed data size (VERY + * computationally expensive). + * + * GRR 980525: consider also + * + * (1) minimum sum of absolute differences from running average (i.e., + * keep running sum of non-absolute differences & count of bytes) + * [track dispersion, too? restart average if dispersion too large?] + * + * (1b) minimum sum of absolute differences from sliding average, probably + * with window size <= deflate window (usually 32K) + * + * (2) minimum sum of squared differences from zero or running average + * (i.e., ~ root-mean-square approach) + */ + + + /* We don't need to test the 'no filter' case if this is the only filter + * that has been chosen, as it doesn't actually do anything to the data. + */ + best_row = png_ptr->row_buf; + + + if ((filter_to_do & PNG_FILTER_NONE) != 0 && filter_to_do != PNG_FILTER_NONE) + { + png_bytep rp; + png_size_t sum = 0; + png_size_t i; + int v; + + if (PNG_SIZE_MAX/128 <= row_bytes) + { + for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++) + { + /* Check for overflow */ + if (sum > PNG_SIZE_MAX/128 - 256) + break; + + v = *rp; + sum += (v < 128) ? v : 256 - v; + } + } + else /* Overflow is not possible */ + { + for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++) + { + v = *rp; + sum += (v < 128) ? v : 256 - v; + } + } + + mins = sum; + } + + /* Sub filter */ + if (filter_to_do == PNG_FILTER_SUB) + /* It's the only filter so no testing is needed */ + { + (void) png_setup_sub_row(png_ptr, bpp, row_bytes, mins); + best_row = png_ptr->try_row; + } + + else if ((filter_to_do & PNG_FILTER_SUB) != 0) + { + png_size_t sum; + png_size_t lmins = mins; + + sum = png_setup_sub_row(png_ptr, bpp, row_bytes, lmins); + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->try_row; + if (png_ptr->tst_row != NULL) + { + png_ptr->try_row = png_ptr->tst_row; + png_ptr->tst_row = best_row; + } + } + } + + /* Up filter */ + if (filter_to_do == PNG_FILTER_UP) + { + (void) png_setup_up_row(png_ptr, row_bytes, mins); + best_row = png_ptr->try_row; + } + + else if ((filter_to_do & PNG_FILTER_UP) != 0) + { + png_size_t sum; + png_size_t lmins = mins; + + sum = png_setup_up_row(png_ptr, row_bytes, lmins); + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->try_row; + if (png_ptr->tst_row != NULL) + { + png_ptr->try_row = png_ptr->tst_row; + png_ptr->tst_row = best_row; + } + } + } + + /* Avg filter */ + if (filter_to_do == PNG_FILTER_AVG) + { + (void) png_setup_avg_row(png_ptr, bpp, row_bytes, mins); + best_row = png_ptr->try_row; + } + + else if ((filter_to_do & PNG_FILTER_AVG) != 0) + { + png_size_t sum; + png_size_t lmins = mins; + + sum= png_setup_avg_row(png_ptr, bpp, row_bytes, lmins); + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->try_row; + if (png_ptr->tst_row != NULL) + { + png_ptr->try_row = png_ptr->tst_row; + png_ptr->tst_row = best_row; + } + } + } + + /* Paeth filter */ + if ((filter_to_do == PNG_FILTER_PAETH) != 0) + { + (void) png_setup_paeth_row(png_ptr, bpp, row_bytes, mins); + best_row = png_ptr->try_row; + } + + else if ((filter_to_do & PNG_FILTER_PAETH) != 0) + { + png_size_t sum; + png_size_t lmins = mins; + + sum = png_setup_paeth_row(png_ptr, bpp, row_bytes, lmins); + + if (sum < mins) + { + best_row = png_ptr->try_row; + if (png_ptr->tst_row != NULL) + { + png_ptr->try_row = png_ptr->tst_row; + png_ptr->tst_row = best_row; + } + } + } + + /* Do the actual writing of the filtered row data from the chosen filter. */ + png_write_filtered_row(png_ptr, best_row, row_info->rowbytes+1); + +#endif /* WRITE_FILTER */ +} + + +/* Do the actual writing of a previously filtered row. */ +static void +png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, + png_size_t full_row_length/*includes filter byte*/) +{ + png_debug(1, "in png_write_filtered_row"); + + png_debug1(2, "filter = %d", filtered_row[0]); + + png_compress_IDAT(png_ptr, filtered_row, full_row_length, Z_NO_FLUSH); + +#ifdef PNG_WRITE_FILTER_SUPPORTED + /* Swap the current and previous rows */ + if (png_ptr->prev_row != NULL) + { + png_bytep tptr; + + tptr = png_ptr->prev_row; + png_ptr->prev_row = png_ptr->row_buf; + png_ptr->row_buf = tptr; + } +#endif /* WRITE_FILTER */ + + /* Finish row - updates counters and flushes zlib if last row */ + png_write_finish_row(png_ptr); + +#ifdef PNG_WRITE_FLUSH_SUPPORTED + png_ptr->flush_rows++; + + if (png_ptr->flush_dist > 0 && + png_ptr->flush_rows >= png_ptr->flush_dist) + { + png_write_flush(png_ptr); + } +#endif /* WRITE_FLUSH */ +} +#endif /* WRITE */ diff --git a/source/Irrlicht/lzma/LzmaDec.c b/source/Irrlicht/lzma/LzmaDec.c new file mode 100644 index 00000000..4fdc11d4 --- /dev/null +++ b/source/Irrlicht/lzma/LzmaDec.c @@ -0,0 +1,999 @@ +/* LzmaDec.c -- LZMA Decoder +2009-09-20 : Igor Pavlov : Public domain */ + +#include "LzmaDec.h" + +#include + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +#define RC_INIT_SIZE 5 + +#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); +#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); +#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ + { UPDATE_0(p); i = (i + i); A0; } else \ + { UPDATE_1(p); i = (i + i) + 1; A1; } +#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) + +#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } +#define TREE_DECODE(probs, limit, i) \ + { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } + +/* #define _LZMA_SIZE_OPT */ + +#ifdef _LZMA_SIZE_OPT +#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) +#else +#define TREE_6_DECODE(probs, i) \ + { i = 1; \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + i -= 0x40; } +#endif + +#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0_CHECK range = bound; +#define UPDATE_1_CHECK range -= bound; code -= bound; +#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ + { UPDATE_0_CHECK; i = (i + i); A0; } else \ + { UPDATE_1_CHECK; i = (i + i) + 1; A1; } +#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) +#define TREE_DECODE_CHECK(probs, limit, i) \ + { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } + + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenChoice 0 +#define LenChoice2 (LenChoice + 1) +#define LenLow (LenChoice2 + 1) +#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) +#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + + +#define kNumStates 12 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 +#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) + +#define IsMatch 0 +#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define IsRep0Long (IsRepG2 + kNumStates) +#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) +#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) +#define LenCoder (Align + kAlignTableSize) +#define RepLenCoder (LenCoder + kNumLenProbs) +#define Literal (RepLenCoder + kNumLenProbs) + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) + +#if Literal != LZMA_BASE_SIZE +StopCompilingDueBUG +#endif + +#define LZMA_DIC_MIN (1 << 12) + +/* First LZMA-symbol is always decoded. +And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization +Out: + Result: + SZ_OK - OK + SZ_ERROR_DATA - Error + p->remainLen: + < kMatchSpecLenStart : normal remain + = kMatchSpecLenStart : finished + = kMatchSpecLenStart + 1 : Flush marker + = kMatchSpecLenStart + 2 : State Init Marker +*/ + +static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + CLzmaProb *probs = p->probs; + + unsigned state = p->state; + UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; + unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; + unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; + unsigned lc = p->prop.lc; + + Byte *dic = p->dic; + SizeT dicBufSize = p->dicBufSize; + SizeT dicPos = p->dicPos; + + UInt32 processedPos = p->processedPos; + UInt32 checkDicSize = p->checkDicSize; + unsigned len = 0; + + const Byte *buf = p->buf; + UInt32 range = p->range; + UInt32 code = p->code; + + do + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = processedPos & pbMask; + + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + unsigned symbol; + UPDATE_0(prob); + prob = probs + Literal; + if (checkDicSize != 0 || processedPos != 0) + prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + + (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); + + if (state < kNumLitStates) + { + state -= (state < 4) ? state : 3; + symbol = 1; + do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + unsigned offs = 0x100; + state -= (state < 10) ? 3 : 6; + symbol = 1; + do + { + unsigned bit; + CLzmaProb *probLit; + matchByte <<= 1; + bit = (matchByte & offs); + probLit = prob + offs + bit + symbol; + GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) + } + while (symbol < 0x100); + } + dic[dicPos++] = (Byte)symbol; + processedPos++; + continue; + } + else + { + UPDATE_1(prob); + prob = probs + IsRep + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + state += kNumStates; + prob = probs + LenCoder; + } + else + { + UPDATE_1(prob); + if (checkDicSize == 0 && processedPos == 0) + return SZ_ERROR_DATA; + prob = probs + IsRepG0 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + UPDATE_0(prob); + dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dicPos++; + processedPos++; + state = state < kNumLitStates ? 9 : 11; + continue; + } + UPDATE_1(prob); + } + else + { + UInt32 distance; + UPDATE_1(prob); + prob = probs + IsRepG1 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep1; + } + else + { + UPDATE_1(prob); + prob = probs + IsRepG2 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep2; + } + else + { + UPDATE_1(prob); + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < kNumLitStates ? 8 : 11; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + limit = (1 << kLenNumLowBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenChoice2; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + limit = (1 << kLenNumMidBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + limit = (1 << kLenNumHighBits); + } + } + TREE_DECODE(probLen, limit, len); + len += offset; + } + + if (state >= kNumStates) + { + UInt32 distance; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); + TREE_6_DECODE(prob, distance); + if (distance >= kStartPosModelIndex) + { + unsigned posSlot = (unsigned)distance; + int numDirectBits = (int)(((distance >> 1) - 1)); + distance = (2 | (distance & 1)); + if (posSlot < kEndPosModelIndex) + { + distance <<= numDirectBits; + prob = probs + SpecPos + distance - posSlot - 1; + { + UInt32 mask = 1; + unsigned i = 1; + do + { + GET_BIT2(prob + i, i, ; , distance |= mask); + mask <<= 1; + } + while (--numDirectBits != 0); + } + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE + range >>= 1; + + { + UInt32 t; + code -= range; + t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ + distance = (distance << 1) + (t + 1); + code += range & t; + } + /* + distance <<= 1; + if (code >= range) + { + code -= range; + distance |= 1; + } + */ + } + while (--numDirectBits != 0); + prob = probs + Align; + distance <<= kNumAlignBits; + { + unsigned i = 1; + GET_BIT2(prob + i, i, ; , distance |= 1); + GET_BIT2(prob + i, i, ; , distance |= 2); + GET_BIT2(prob + i, i, ; , distance |= 4); + GET_BIT2(prob + i, i, ; , distance |= 8); + } + if (distance == (UInt32)0xFFFFFFFF) + { + len += kMatchSpecLenStart; + state -= kNumStates; + break; + } + } + } + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + rep0 = distance + 1; + if (checkDicSize == 0) + { + if (distance >= processedPos) + return SZ_ERROR_DATA; + } + else if (distance >= checkDicSize) + return SZ_ERROR_DATA; + state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; + } + + len += kMatchMinLen; + + if (limit == dicPos) + return SZ_ERROR_DATA; + { + SizeT rem = limit - dicPos; + unsigned curLen = ((rem < len) ? (unsigned)rem : len); + SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); + + processedPos += curLen; + + len -= curLen; + if (pos + curLen <= dicBufSize) + { + Byte *dest = dic + dicPos; + ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; + const Byte *lim = dest + curLen; + dicPos += curLen; + do + *(dest) = (Byte)*(dest + src); + while (++dest != lim); + } + else + { + do + { + dic[dicPos++] = dic[pos]; + if (++pos == dicBufSize) + pos = 0; + } + while (--curLen != 0); + } + } + } + } + while (dicPos < limit && buf < bufLimit); + NORMALIZE; + p->buf = buf; + p->range = range; + p->code = code; + p->remainLen = len; + p->dicPos = dicPos; + p->processedPos = processedPos; + p->reps[0] = rep0; + p->reps[1] = rep1; + p->reps[2] = rep2; + p->reps[3] = rep3; + p->state = state; + + return SZ_OK; +} + +static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) +{ + if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) + { + Byte *dic = p->dic; + SizeT dicPos = p->dicPos; + SizeT dicBufSize = p->dicBufSize; + unsigned len = p->remainLen; + UInt32 rep0 = p->reps[0]; + if (limit - dicPos < len) + len = (unsigned)(limit - dicPos); + + if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) + p->checkDicSize = p->prop.dicSize; + + p->processedPos += len; + p->remainLen -= len; + while (len-- != 0) + { + dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dicPos++; + } + p->dicPos = dicPos; + } +} + +static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + do + { + SizeT limit2 = limit; + if (p->checkDicSize == 0) + { + UInt32 rem = p->prop.dicSize - p->processedPos; + if (limit - p->dicPos > rem) + limit2 = p->dicPos + rem; + } + RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); + if (p->processedPos >= p->prop.dicSize) + p->checkDicSize = p->prop.dicSize; + LzmaDec_WriteRem(p, limit); + } + while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); + + if (p->remainLen > kMatchSpecLenStart) + { + p->remainLen = kMatchSpecLenStart; + } + return 0; +} + +typedef enum +{ + DUMMY_ERROR, /* unexpected end of input stream */ + DUMMY_LIT, + DUMMY_MATCH, + DUMMY_REP +} ELzmaDummy; + +static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) +{ + UInt32 range = p->range; + UInt32 code = p->code; + const Byte *bufLimit = buf + inSize; + CLzmaProb *probs = p->probs; + unsigned state = p->state; + ELzmaDummy res; + + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); + + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK + + /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ + + prob = probs + Literal; + if (p->checkDicSize != 0 || p->processedPos != 0) + prob += (LZMA_LIT_SIZE * + ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + + (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); + + if (state < kNumLitStates) + { + unsigned symbol = 1; + do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[p->dicPos - p->reps[0] + + ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; + unsigned offs = 0x100; + unsigned symbol = 1; + do + { + unsigned bit; + CLzmaProb *probLit; + matchByte <<= 1; + bit = (matchByte & offs); + probLit = prob + offs + bit + symbol; + GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) + } + while (symbol < 0x100); + } + res = DUMMY_LIT; + } + else + { + unsigned len; + UPDATE_1_CHECK; + + prob = probs + IsRep + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + state = 0; + prob = probs + LenCoder; + res = DUMMY_MATCH; + } + else + { + UPDATE_1_CHECK; + res = DUMMY_REP; + prob = probs + IsRepG0 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + NORMALIZE_CHECK; + return DUMMY_REP; + } + else + { + UPDATE_1_CHECK; + } + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG1 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG2 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + } + } + } + state = kNumStates; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + limit = 1 << kLenNumLowBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenChoice2; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + limit = 1 << kLenNumMidBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + limit = 1 << kLenNumHighBits; + } + } + TREE_DECODE_CHECK(probLen, limit, len); + len += offset; + } + + if (state < 4) + { + unsigned posSlot; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits); + TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); + if (posSlot >= kStartPosModelIndex) + { + int numDirectBits = ((posSlot >> 1) - 1); + + /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ + + if (posSlot < kEndPosModelIndex) + { + prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE_CHECK + range >>= 1; + code -= range & (((code - range) >> 31) - 1); + /* if (code >= range) code -= range; */ + } + while (--numDirectBits != 0); + prob = probs + Align; + numDirectBits = kNumAlignBits; + } + { + unsigned i = 1; + do + { + GET_BIT_CHECK(prob + i, i); + } + while (--numDirectBits != 0); + } + } + } + } + } + NORMALIZE_CHECK; + return res; +} + + +static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) +{ + p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); + p->range = 0xFFFFFFFF; + p->needFlush = 0; +} + +void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) +{ + p->needFlush = 1; + p->remainLen = 0; + p->tempBufSize = 0; + + if (initDic) + { + p->processedPos = 0; + p->checkDicSize = 0; + p->needInitState = 1; + } + if (initState) + p->needInitState = 1; +} + +void LzmaDec_Init(CLzmaDec *p) +{ + p->dicPos = 0; + LzmaDec_InitDicAndState(p, True, True); +} + +static void LzmaDec_InitStateReal(CLzmaDec *p) +{ + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); + UInt32 i; + CLzmaProb *probs = p->probs; + for (i = 0; i < numProbs; i++) + probs[i] = kBitModelTotal >> 1; + p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; + p->state = 0; + p->needInitState = 0; +} + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, + ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT inSize = *srcLen; + (*srcLen) = 0; + LzmaDec_WriteRem(p, dicLimit); + + *status = LZMA_STATUS_NOT_SPECIFIED; + + while (p->remainLen != kMatchSpecLenStart) + { + int checkEndMarkNow; + + if (p->needFlush != 0) + { + for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) + p->tempBuf[p->tempBufSize++] = *src++; + if (p->tempBufSize < RC_INIT_SIZE) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (p->tempBuf[0] != 0) + return SZ_ERROR_DATA; + + LzmaDec_InitRc(p, p->tempBuf); + p->tempBufSize = 0; + } + + checkEndMarkNow = 0; + if (p->dicPos >= dicLimit) + { + if (p->remainLen == 0 && p->code == 0) + { + *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; + return SZ_OK; + } + if (finishMode == LZMA_FINISH_ANY) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_OK; + } + if (p->remainLen != 0) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + checkEndMarkNow = 1; + } + + if (p->needInitState) + LzmaDec_InitStateReal(p); + + if (p->tempBufSize == 0) + { + SizeT processed; + const Byte *bufLimit; + if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, src, inSize); + if (dummyRes == DUMMY_ERROR) + { + memcpy(p->tempBuf, src, inSize); + p->tempBufSize = (unsigned)inSize; + (*srcLen) += inSize; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + bufLimit = src; + } + else + bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; + p->buf = src; + if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) + return SZ_ERROR_DATA; + processed = (SizeT)(p->buf - src); + (*srcLen) += processed; + src += processed; + inSize -= processed; + } + else + { + unsigned rem = p->tempBufSize, lookAhead = 0; + while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) + p->tempBuf[rem++] = src[lookAhead++]; + p->tempBufSize = rem; + if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); + if (dummyRes == DUMMY_ERROR) + { + (*srcLen) += lookAhead; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + } + p->buf = p->tempBuf; + if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) + return SZ_ERROR_DATA; + lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); + (*srcLen) += lookAhead; + src += lookAhead; + inSize -= lookAhead; + p->tempBufSize = 0; + } + } + if (p->code == 0) + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; +} + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT outSize = *destLen; + SizeT inSize = *srcLen; + *srcLen = *destLen = 0; + for (;;) + { + SizeT inSizeCur = inSize, outSizeCur, dicPos; + ELzmaFinishMode curFinishMode; + SRes res; + if (p->dicPos == p->dicBufSize) + p->dicPos = 0; + dicPos = p->dicPos; + if (outSize > p->dicBufSize - dicPos) + { + outSizeCur = p->dicBufSize; + curFinishMode = LZMA_FINISH_ANY; + } + else + { + outSizeCur = dicPos + outSize; + curFinishMode = finishMode; + } + + res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); + src += inSizeCur; + inSize -= inSizeCur; + *srcLen += inSizeCur; + outSizeCur = p->dicPos - dicPos; + memcpy(dest, p->dic + dicPos, outSizeCur); + dest += outSizeCur; + outSize -= outSizeCur; + *destLen += outSizeCur; + if (res != 0) + return res; + if (outSizeCur == 0 || outSize == 0) + return SZ_OK; + } +} + +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->probs); + p->probs = 0; +} + +static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->dic); + p->dic = 0; +} + +void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) +{ + LzmaDec_FreeProbs(p, alloc); + LzmaDec_FreeDict(p, alloc); +} + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) +{ + UInt32 dicSize; + Byte d; + + if (size < LZMA_PROPS_SIZE) + return SZ_ERROR_UNSUPPORTED; + else + dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); + + if (dicSize < LZMA_DIC_MIN) + dicSize = LZMA_DIC_MIN; + p->dicSize = dicSize; + + d = data[0]; + if (d >= (9 * 5 * 5)) + return SZ_ERROR_UNSUPPORTED; + + p->lc = d % 9; + d /= 9; + p->pb = d / 5; + p->lp = d % 5; + + return SZ_OK; +} + +static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) +{ + UInt32 numProbs = LzmaProps_GetNumProbs(propNew); + if (p->probs == 0 || numProbs != p->numProbs) + { + LzmaDec_FreeProbs(p, alloc); + p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); + p->numProbs = numProbs; + if (p->probs == 0) + return SZ_ERROR_MEM; + } + return SZ_OK; +} + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +{ + CLzmaProps propNew; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +{ + CLzmaProps propNew; + SizeT dicBufSize; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + dicBufSize = propNew.dicSize; + if (p->dic == 0 || dicBufSize != p->dicBufSize) + { + LzmaDec_FreeDict(p, alloc); + p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); + if (p->dic == 0) + { + LzmaDec_FreeProbs(p, alloc); + return SZ_ERROR_MEM; + } + } + p->dicBufSize = dicBufSize; + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc) +{ + CLzmaDec p; + SRes res; + SizeT inSize = *srcLen; + SizeT outSize = *destLen; + *srcLen = *destLen = 0; + if (inSize < RC_INIT_SIZE) + return SZ_ERROR_INPUT_EOF; + + LzmaDec_Construct(&p); + res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc); + if (res != 0) + return res; + p.dic = dest; + p.dicBufSize = outSize; + + LzmaDec_Init(&p); + + *srcLen = inSize; + res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); + + if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + + (*destLen) = p.dicPos; + LzmaDec_FreeProbs(&p, alloc); + return res; +} diff --git a/source/Irrlicht/lzma/LzmaDec.h b/source/Irrlicht/lzma/LzmaDec.h new file mode 100644 index 00000000..6741a644 --- /dev/null +++ b/source/Irrlicht/lzma/LzmaDec.h @@ -0,0 +1,231 @@ +/* LzmaDec.h -- LZMA Decoder +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __LZMA_DEC_H +#define __LZMA_DEC_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* #define _LZMA_PROB32 */ +/* _LZMA_PROB32 can increase the speed on some CPUs, + but memory usage for CLzmaDec::probs will be doubled in that case */ + +#ifdef _LZMA_PROB32 +#define CLzmaProb UInt32 +#else +#define CLzmaProb UInt16 +#endif + + +/* ---------- LZMA Properties ---------- */ + +#define LZMA_PROPS_SIZE 5 + +typedef struct _CLzmaProps +{ + unsigned lc, lp, pb; + UInt32 dicSize; +} CLzmaProps; + +/* LzmaProps_Decode - decodes properties +Returns: + SZ_OK + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); + + +/* ---------- LZMA Decoder state ---------- */ + +/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. + Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ + +#define LZMA_REQUIRED_INPUT_MAX 20 + +typedef struct +{ + CLzmaProps prop; + CLzmaProb *probs; + Byte *dic; + const Byte *buf; + UInt32 range, code; + SizeT dicPos; + SizeT dicBufSize; + UInt32 processedPos; + UInt32 checkDicSize; + unsigned state; + UInt32 reps[4]; + unsigned remainLen; + int needFlush; + int needInitState; + UInt32 numProbs; + unsigned tempBufSize; + Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; +} CLzmaDec; + +#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } + +void LzmaDec_Init(CLzmaDec *p); + +/* There are two types of LZMA streams: + 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. + 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ + +typedef enum +{ + LZMA_FINISH_ANY, /* finish at any point */ + LZMA_FINISH_END /* block must be finished at the end */ +} ELzmaFinishMode; + +/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! + + You must use LZMA_FINISH_END, when you know that current output buffer + covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. + + If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, + and output value of destLen will be less than output buffer size limit. + You can check status result also. + + You can use multiple checks to test data integrity after full decompression: + 1) Check Result and "status" variable. + 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. + 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. + You must use correct finish mode in that case. */ + +typedef enum +{ + LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ + LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ + LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ + LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ +} ELzmaStatus; + +/* ELzmaStatus is used only as output value for function call */ + + +/* ---------- Interfaces ---------- */ + +/* There are 3 levels of interfaces: + 1) Dictionary Interface + 2) Buffer Interface + 3) One Call Interface + You can select any of these interfaces, but don't mix functions from different + groups for same object. */ + + +/* There are two variants to allocate state for Dictionary Interface: + 1) LzmaDec_Allocate / LzmaDec_Free + 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs + You can use variant 2, if you set dictionary buffer manually. + For Buffer Interface you must always use variant 1. + +LzmaDec_Allocate* can return: + SZ_OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); + +SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); +void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); + +/* ---------- Dictionary Interface ---------- */ + +/* You can use it, if you want to eliminate the overhead for data copying from + dictionary to some other external buffer. + You must work with CLzmaDec variables directly in this interface. + + STEPS: + LzmaDec_Constr() + LzmaDec_Allocate() + for (each new stream) + { + LzmaDec_Init() + while (it needs more decompression) + { + LzmaDec_DecodeToDic() + use data from CLzmaDec::dic and update CLzmaDec::dicPos + } + } + LzmaDec_Free() +*/ + +/* LzmaDec_DecodeToDic + + The decoding to internal dictionary buffer (CLzmaDec::dic). + You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! + +finishMode: + It has meaning only if the decoding reaches output limit (dicLimit). + LZMA_FINISH_ANY - Decode just dicLimit bytes. + LZMA_FINISH_END - Stream must be finished after dicLimit. + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_NEEDS_MORE_INPUT + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error +*/ + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- Buffer Interface ---------- */ + +/* It's zlib-like interface. + See LzmaDec_DecodeToDic description for information about STEPS and return results, + but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need + to work with CLzmaDec variables manually. + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). +*/ + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- One Call Interface ---------- */ + +/* LzmaDecode + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). +*/ + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/Irrlicht/lzma/Types.h b/source/Irrlicht/lzma/Types.h new file mode 100644 index 00000000..f193ce2f --- /dev/null +++ b/source/Irrlicht/lzma/Types.h @@ -0,0 +1,254 @@ +/* Types.h -- Basic types +2010-10-09 : Igor Pavlov : Public domain */ + +#ifndef __7Z_TYPES_H +#define __7Z_TYPES_H + +#include + +#ifdef _WIN32 +#include +#endif + +#ifndef EXTERN_C_BEGIN +#ifdef __cplusplus +#define EXTERN_C_BEGIN extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_BEGIN +#define EXTERN_C_END +#endif +#endif + +EXTERN_C_BEGIN + +#define SZ_OK 0 + +#define SZ_ERROR_DATA 1 +#define SZ_ERROR_MEM 2 +#define SZ_ERROR_CRC 3 +#define SZ_ERROR_UNSUPPORTED 4 +#define SZ_ERROR_PARAM 5 +#define SZ_ERROR_INPUT_EOF 6 +#define SZ_ERROR_OUTPUT_EOF 7 +#define SZ_ERROR_READ 8 +#define SZ_ERROR_WRITE 9 +#define SZ_ERROR_PROGRESS 10 +#define SZ_ERROR_FAIL 11 +#define SZ_ERROR_THREAD 12 + +#define SZ_ERROR_ARCHIVE 16 +#define SZ_ERROR_NO_ARCHIVE 17 + +typedef int SRes; + +#ifdef _WIN32 +typedef DWORD WRes; +#else +typedef int WRes; +#endif + +#ifndef RINOK +#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } +#endif + +typedef unsigned char Byte; +typedef short Int16; +typedef unsigned short UInt16; + +#ifdef _LZMA_UINT32_IS_ULONG +typedef long Int32; +typedef unsigned long UInt32; +#else +typedef int Int32; +typedef unsigned int UInt32; +#endif + +#ifdef _SZ_NO_INT_64 + +/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. + NOTES: Some code will work incorrectly in that case! */ + +typedef long Int64; +typedef unsigned long UInt64; + +#else + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#define UINT64_CONST(n) n +#else +typedef long long int Int64; +typedef unsigned long long int UInt64; +#define UINT64_CONST(n) n ## ULL +#endif + +#endif + +#ifdef _LZMA_NO_SYSTEM_SIZE_T +typedef UInt32 SizeT; +#else +typedef size_t SizeT; +#endif + +typedef int Bool; +#define True 1 +#define False 0 + + +#ifdef _WIN32 +#define MY_STD_CALL __stdcall +#else +#define MY_STD_CALL +#endif + +#ifdef _MSC_VER + +#if _MSC_VER >= 1300 +#define MY_NO_INLINE __declspec(noinline) +#else +#define MY_NO_INLINE +#endif + +#define MY_CDECL __cdecl +#define MY_FAST_CALL __fastcall + +#else + +#define MY_CDECL +#define MY_FAST_CALL + +#endif + + +/* The following interfaces use first parameter as pointer to structure */ + +typedef struct +{ + Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */ +} IByteIn; + +typedef struct +{ + void (*Write)(void *p, Byte b); +} IByteOut; + +typedef struct +{ + SRes (*Read)(void *p, void *buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) < input(*size)) is allowed */ +} ISeqInStream; + +/* it can return SZ_ERROR_INPUT_EOF */ +SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); +SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); +SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); + +typedef struct +{ + size_t (*Write)(void *p, const void *buf, size_t size); + /* Returns: result - the number of actually written bytes. + (result < size) means error */ +} ISeqOutStream; + +typedef enum +{ + SZ_SEEK_SET = 0, + SZ_SEEK_CUR = 1, + SZ_SEEK_END = 2 +} ESzSeek; + +typedef struct +{ + SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ISeekInStream; + +typedef struct +{ + SRes (*Look)(void *p, const void **buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) > input(*size)) is not allowed + (output(*size) < input(*size)) is allowed */ + SRes (*Skip)(void *p, size_t offset); + /* offset must be <= output(*size) of Look */ + + SRes (*Read)(void *p, void *buf, size_t *size); + /* reads directly (without buffer). It's same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ILookInStream; + +SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); +SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); + +/* reads via ILookInStream::Read */ +SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); +SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); + +#define LookToRead_BUF_SIZE (1 << 14) + +typedef struct +{ + ILookInStream s; + ISeekInStream *realStream; + size_t pos; + size_t size; + Byte buf[LookToRead_BUF_SIZE]; +} CLookToRead; + +void LookToRead_CreateVTable(CLookToRead *p, int lookahead); +void LookToRead_Init(CLookToRead *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToLook; + +void SecToLook_CreateVTable(CSecToLook *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToRead; + +void SecToRead_CreateVTable(CSecToRead *p); + +typedef struct +{ + SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); + /* Returns: result. (result != SZ_OK) means break. + Value (UInt64)(Int64)-1 for size means unknown value. */ +} ICompressProgress; + +typedef struct +{ + void *(*Alloc)(void *p, size_t size); + void (*Free)(void *p, void *address); /* address can be 0 */ +} ISzAlloc; + +#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) +#define IAlloc_Free(p, a) (p)->Free((p), a) + +#ifdef _WIN32 + +#define CHAR_PATH_SEPARATOR '\\' +#define WCHAR_PATH_SEPARATOR L'\\' +#define STRING_PATH_SEPARATOR "\\" +#define WSTRING_PATH_SEPARATOR L"\\" + +#else + +#define CHAR_PATH_SEPARATOR '/' +#define WCHAR_PATH_SEPARATOR L'/' +#define STRING_PATH_SEPARATOR "/" +#define WSTRING_PATH_SEPARATOR L"/" + +#endif + +EXTERN_C_END + +#endif diff --git a/source/Irrlicht/os.cpp b/source/Irrlicht/os.cpp new file mode 100644 index 00000000..2af9443a --- /dev/null +++ b/source/Irrlicht/os.cpp @@ -0,0 +1,475 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "os.h" +#include "irrString.h" +#include "IrrCompileConfig.h" +#include "irrMath.h" + +#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_) + #include + #define bswap_16(X) SDL_Swap16(X) + #define bswap_32(X) SDL_Swap32(X) + #define bswap_64(X) SDL_Swap64(X) +#elif defined(_IRR_WINDOWS_API_) && defined(_MSC_VER) && (_MSC_VER > 1298) + #include + #define bswap_16(X) _byteswap_ushort(X) + #define bswap_32(X) _byteswap_ulong(X) + #define bswap_64(X) _byteswap_uint64(X) +#if (_MSC_VER >= 1400) + #define localtime _localtime_s +#endif +#elif defined(_IRR_OSX_PLATFORM_) || defined(_IRR_IOS_PLATFORM_) + #include + #define bswap_16(X) OSReadSwapInt16(&X,0) + #define bswap_32(X) OSReadSwapInt32(&X,0) + #define bswap_64(X) OSReadSwapInt64(&X,0) +#elif defined(__FreeBSD__) || defined(__OpenBSD__) + #include + #define bswap_16(X) bswap16(X) + #define bswap_32(X) bswap32(X) + #define bswap_64(X) bswap64(X) +#elif !defined(_IRR_SOLARIS_PLATFORM_) && !defined(__PPC__) && !defined(_IRR_WINDOWS_API_) + #include +#else + #define bswap_16(X) ((((X)&0xFF) << 8) | (((X)&0xFF00) >> 8)) + #define bswap_32(X) ((((X)&0x000000FF) << 24) | (((X)&0xFF000000) >> 24) | (((X)&0x0000FF00) << 8) | (((X) &0x00FF0000) >> 8)) + #define bswap_64(X) ((((X)&0x00000000000000FF) << 56) | (((X)&0xFF00000000000000) >> 56) | (((X)&0x000000000000FF00) << 40) | (((X)&0x00FF000000000000) >> 40) | (((X)&0x0000000000FF0000) << 24) | (((X)&0x0000FF0000000000) >> 24) | (((X)&0x00000000FF000000) << 8) | (((X) &0x000000FF00000000) >> 8)) +#endif + +namespace irr +{ +namespace os +{ + u16 Byteswap::byteswap(u16 num) {return bswap_16(num);} + s16 Byteswap::byteswap(s16 num) {return bswap_16(num);} + u32 Byteswap::byteswap(u32 num) {return bswap_32(num);} + s32 Byteswap::byteswap(s32 num) {return bswap_32(num);} + u64 Byteswap::byteswap(u64 num) {return bswap_64(num);} + s64 Byteswap::byteswap(s64 num) {return bswap_64(num);} + f32 Byteswap::byteswap(f32 num) {u32 tmp=IR(num); tmp=bswap_32(tmp); return (FR(tmp));} + // prevent accidental byte swapping of chars + u8 Byteswap::byteswap(u8 num) {return num;} + c8 Byteswap::byteswap(c8 num) {return num;} +} +} + +#if defined(_IRR_WINDOWS_API_) +// ---------------------------------------------------------------- +// Windows specific functions +// ---------------------------------------------------------------- + +#ifdef _IRR_XBOX_PLATFORM_ +#include +#else +#define WIN32_LEAN_AND_MEAN +#include +#include +#endif + +namespace irr +{ +namespace os +{ + //! prints a debuginfo string + void Printer::print(const c8* message, ELOG_LEVEL ll) + { +#if defined (_WIN32_WCE ) + core::stringw tmp(message); + tmp += L"\n"; + OutputDebugStringW(tmp.c_str()); +#else + core::stringc tmp(message); + tmp += "\n"; + OutputDebugStringA(tmp.c_str()); + printf("%s", tmp.c_str()); +#endif + } + + static LARGE_INTEGER HighPerformanceFreq; + static BOOL HighPerformanceTimerSupport = FALSE; + static BOOL MultiCore = FALSE; + + void Timer::initTimer(bool usePerformanceTimer) + { +#if !defined(_WIN32_WCE) && !defined (_IRR_XBOX_PLATFORM_) + // workaround for hires timer on multiple core systems, bios bugs result in bad hires timers. + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + MultiCore = (sysinfo.dwNumberOfProcessors > 1); +#endif + if (usePerformanceTimer) + HighPerformanceTimerSupport = QueryPerformanceFrequency(&HighPerformanceFreq); + else + HighPerformanceTimerSupport = FALSE; + initVirtualTimer(); + } + + u32 Timer::getRealTime() + { + if (HighPerformanceTimerSupport) + { +#if !defined(_WIN32_WCE) && !defined (_IRR_XBOX_PLATFORM_) + // Avoid potential timing inaccuracies across multiple cores by + // temporarily setting the affinity of this process to one core. + DWORD_PTR affinityMask=0; + if(MultiCore) + affinityMask = SetThreadAffinityMask(GetCurrentThread(), 1); +#endif + LARGE_INTEGER nTime; + BOOL queriedOK = QueryPerformanceCounter(&nTime); + +#if !defined(_WIN32_WCE) && !defined (_IRR_XBOX_PLATFORM_) + // Restore the true affinity. + if(MultiCore) + (void)SetThreadAffinityMask(GetCurrentThread(), affinityMask); +#endif + if(queriedOK) + return u32((nTime.QuadPart) * 1000 / HighPerformanceFreq.QuadPart); + + } + + return GetTickCount(); + } + +} // end namespace os + + +#elif defined( _IRR_ANDROID_PLATFORM_ ) + +// ---------------------------------------------------------------- +// Android version +// ---------------------------------------------------------------- + +#include + +namespace irr +{ +namespace os +{ + + //! prints a debuginfo string + void Printer::print(const c8* message, ELOG_LEVEL ll) + { + android_LogPriority LogLevel = ANDROID_LOG_UNKNOWN; + + switch (ll) + { + case ELL_DEBUG: + LogLevel = ANDROID_LOG_DEBUG; + break; + case ELL_INFORMATION: + LogLevel = ANDROID_LOG_INFO; + break; + case ELL_WARNING: + LogLevel = ANDROID_LOG_WARN; + break; + case ELL_ERROR: + LogLevel = ANDROID_LOG_ERROR; + break; + default: // ELL_NONE + LogLevel = ANDROID_LOG_VERBOSE; + break; + } + + // Android logcat restricts log-output and cuts the rest of the message away. But we want it all. + // On my device max-len is 1023 (+ 0 byte). Some websites claim a limit of 4096 so maybe different numbers on different devices. + const size_t maxLogLen = 1023; + size_t msgLen = strlen(message); + size_t start = 0; + while ( msgLen-start > maxLogLen ) + { + __android_log_print(LogLevel, "Irrlicht", "%.*s\n", maxLogLen, &message[start]); + start += maxLogLen; + } + __android_log_print(LogLevel, "Irrlicht", "%s\n", &message[start]); + } + + void Timer::initTimer(bool usePerformanceTimer) + { + initVirtualTimer(); + } + + u32 Timer::getRealTime() + { + timeval tv; + gettimeofday(&tv, 0); + return (u32)(tv.tv_sec * 1000) + (tv.tv_usec / 1000); + } +} // end namespace os + +#elif defined(_IRR_EMSCRIPTEN_PLATFORM_) + +// ---------------------------------------------------------------- +// emscripten version +// ---------------------------------------------------------------- + +#include +#include +#include + +namespace irr +{ +namespace os +{ + + //! prints a debuginfo string + void Printer::print(const c8* message, ELOG_LEVEL ll) + { + int log_level; + switch (ll) + { + case ELL_DEBUG: + log_level=0; + break; + case ELL_INFORMATION: + log_level=0; + break; + case ELL_WARNING: + log_level=EM_LOG_WARN; + break; + case ELL_ERROR: + log_level=EM_LOG_ERROR; + break; + default: // ELL_NONE + log_level=0; + break; + } + emscripten_log(log_level, "%s", message); // Note: not adding \n as emscripten_log seems to do that already. + } + + void Timer::initTimer(bool usePerformanceTimer) + { + initVirtualTimer(); + } + + u32 Timer::getRealTime() + { + double time = emscripten_get_now(); + return (u32)(time); + } +} // end namespace os + +#else + +// ---------------------------------------------------------------- +// linux/ansi version +// ---------------------------------------------------------------- + +#include +#include +#include + +namespace irr +{ +namespace os +{ + + //! prints a debuginfo string + void Printer::print(const c8* message, ELOG_LEVEL ll) + { + printf("%s\n", message); + } + + void Timer::initTimer(bool usePerformanceTimer) + { + initVirtualTimer(); + } + + u32 Timer::getRealTime() + { + timeval tv; + gettimeofday(&tv, 0); + return (u32)(tv.tv_sec * 1000) + (tv.tv_usec / 1000); + } +} // end namespace os + +#endif // end linux / emscripten / android / windows + +namespace os +{ + // The platform independent implementation of the printer + ILogger* Printer::Logger = 0; + + void Printer::log(const c8* message, ELOG_LEVEL ll) + { + if (Logger) + Logger->log(message, ll); + } + + void Printer::log(const wchar_t* message, ELOG_LEVEL ll) + { + if (Logger) + Logger->log(message, ll); + } + + void Printer::log(const c8* message, const c8* hint, ELOG_LEVEL ll) + { + if (Logger) + Logger->log(message, hint, ll); + } + + void Printer::log(const c8* message, const io::path& hint, ELOG_LEVEL ll) + { + if (Logger) + Logger->log(message, hint.c_str(), ll); + } + + // our Randomizer is not really os specific, so we + // code one for all, which should work on every platform the same, + // which is desirable. + + s32 Randomizer::seed = 0x0f0f0f0f; + + //! generates a pseudo random number + s32 Randomizer::rand() + { + // (a*seed)%m with Schrage's method + seed = a * (seed%q) - r* (seed/q); + if (seed<1) + seed += m; + + return seed-1; // -1 because we want it to start at 0 + } + + //! generates a pseudo random number + f32 Randomizer::frand() + { + return rand()*(1.f/rMax); + } + + s32 Randomizer::randMax() + { + return rMax; + } + + //! resets the randomizer + void Randomizer::reset(s32 value) + { + if (value<0) + seed = value+m; + else if ( value == 0 || value == m) + seed = 1; + else + seed = value; + } + + + // ------------------------------------------------------ + // virtual timer implementation + + f32 Timer::VirtualTimerSpeed = 1.0f; + s32 Timer::VirtualTimerStopCounter = 0; + u32 Timer::LastVirtualTime = 0; + u32 Timer::StartRealTime = 0; + u32 Timer::StaticTime = 0; + + //! Get real time and date in calendar form + ITimer::RealTimeDate Timer::getRealTimeAndDate() + { + time_t rawtime; + time(&rawtime); + + struct tm * timeinfo; + timeinfo = localtime(&rawtime); + + // init with all 0 to indicate error + ITimer::RealTimeDate date; + memset(&date, 0, sizeof(date)); + // at least Windows returns NULL on some illegal dates + if (timeinfo) + { + // set useful values if succeeded + date.Hour=(u32)timeinfo->tm_hour; + date.Minute=(u32)timeinfo->tm_min; + date.Second=(u32)timeinfo->tm_sec; + date.Day=(u32)timeinfo->tm_mday; + date.Month=(u32)timeinfo->tm_mon+1; + date.Year=(u32)timeinfo->tm_year+1900; + date.Weekday=(ITimer::EWeekday)timeinfo->tm_wday; + date.Yearday=(u32)timeinfo->tm_yday+1; + date.IsDST=timeinfo->tm_isdst != 0; + } + return date; + } + + //! returns current virtual time + u32 Timer::getTime() + { + if (isStopped()) + return LastVirtualTime; + + return LastVirtualTime + (u32)((StaticTime - StartRealTime) * VirtualTimerSpeed); + } + + //! ticks, advances the virtual timer + void Timer::tick() + { + StaticTime = getRealTime(); + } + + //! sets the current virtual time + void Timer::setTime(u32 time) + { + StaticTime = getRealTime(); + LastVirtualTime = time; + StartRealTime = StaticTime; + } + + //! stops the virtual timer + void Timer::stopTimer() + { + if (!isStopped()) + { + // stop the virtual timer + LastVirtualTime = getTime(); + } + + --VirtualTimerStopCounter; + } + + //! starts the virtual timer + void Timer::startTimer() + { + ++VirtualTimerStopCounter; + + if (!isStopped()) + { + // restart virtual timer + setTime(LastVirtualTime); + } + } + + //! sets the speed of the virtual timer + void Timer::setSpeed(f32 speed) + { + setTime(getTime()); + + VirtualTimerSpeed = speed; + if (VirtualTimerSpeed < 0.0f) + VirtualTimerSpeed = 0.0f; + } + + //! gets the speed of the virtual timer + f32 Timer::getSpeed() + { + return VirtualTimerSpeed; + } + + //! returns if the timer currently is stopped + bool Timer::isStopped() + { + return VirtualTimerStopCounter < 0; + } + + void Timer::initVirtualTimer() + { + StaticTime = getRealTime(); + StartRealTime = StaticTime; + } + +} // end namespace os +} // end namespace irr + + diff --git a/source/Irrlicht/os.h b/source/Irrlicht/os.h new file mode 100644 index 00000000..379abb83 --- /dev/null +++ b/source/Irrlicht/os.h @@ -0,0 +1,134 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_OS_H_INCLUDED__ +#define __IRR_OS_H_INCLUDED__ + +#include "IrrCompileConfig.h" // for endian check +#include "irrTypes.h" +#include "irrString.h" +#include "path.h" +#include "ILogger.h" +#include "ITimer.h" + +namespace irr +{ + +namespace os +{ + class Byteswap + { + public: + static u16 byteswap(u16 num); + static s16 byteswap(s16 num); + static u32 byteswap(u32 num); + static s32 byteswap(s32 num); + static u64 byteswap(u64 num); + static s64 byteswap(s64 num); + static f32 byteswap(f32 num); + // prevent accidental swapping of chars + static u8 byteswap(u8 num); + static c8 byteswap(c8 num); + }; + + class Printer + { + public: + // prints out a string to the console out stdout or debug log or whatever + static void print(const c8* message, ELOG_LEVEL ll = ELL_INFORMATION); + static void log(const c8* message, ELOG_LEVEL ll = ELL_INFORMATION); + static void log(const wchar_t* message, ELOG_LEVEL ll = ELL_INFORMATION); + static void log(const c8* message, const c8* hint, ELOG_LEVEL ll = ELL_INFORMATION); + static void log(const c8* message, const io::path& hint, ELOG_LEVEL ll = ELL_INFORMATION); + static ILogger* Logger; + }; + + + // congruential pseudo-random generator + // numbers identical to std::minstd_rand0 + // period is somewhere around m-1 + class Randomizer + { + public: + + //! resets the randomizer + static void reset(s32 value=0x0f0f0f0f); + + //! generates a pseudo random number in the range 0..randMax() + static s32 rand(); + + //! generates a pseudo random number in the range 0..1 + static f32 frand(); + + //! get maximum number generated by rand() + static s32 randMax(); + + private: + + static s32 seed; + + static const s32 m = 2147483647; // a Mersenne prime (2^31-1) + static const s32 a = 16807; // another spectral success story + static const s32 q = m/a; + static const s32 r = m%a; // again less than q + static const s32 rMax = m-2; + }; + + + + + class Timer + { + public: + + //! returns the current time in milliseconds + static u32 getTime(); + + //! get current time and date in calendar form + static ITimer::RealTimeDate getRealTimeAndDate(); + + //! initializes the real timer + static void initTimer(bool usePerformanceTimer=true); + + //! sets the current virtual (game) time + static void setTime(u32 time); + + //! stops the virtual (game) timer + static void stopTimer(); + + //! starts the game timer + static void startTimer(); + + //! sets the speed of the virtual timer + static void setSpeed(f32 speed); + + //! gets the speed of the virtual timer + static f32 getSpeed(); + + //! returns if the timer currently is stopped + static bool isStopped(); + + //! makes the virtual timer update the time value based on the real time + static void tick(); + + //! returns the current real time in milliseconds + static u32 getRealTime(); + + private: + + static void initVirtualTimer(); + + static f32 VirtualTimerSpeed; + static s32 VirtualTimerStopCounter; + static u32 StartRealTime; + static u32 LastVirtualTime; + static u32 StaticTime; + }; + +} // end namespace os +} // end namespace irr + + +#endif + diff --git a/source/Irrlicht/resource.h b/source/Irrlicht/resource.h new file mode 100644 index 00000000..c734d2a5 --- /dev/null +++ b/source/Irrlicht/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Irrlicht.rc + +// Nchste Standardwerte fr neue Objekte +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/source/Irrlicht/source.txt b/source/Irrlicht/source.txt new file mode 100644 index 00000000..f90ea063 --- /dev/null +++ b/source/Irrlicht/source.txt @@ -0,0 +1,40 @@ +Source code of the Irrlicht Engine + +The complete source of the Irrlicht Engine can be found when decompressing +the .zip file included in this directory. +Please note that YOU DO NOT NEED THIS SOURCE to develop 3d applications with +the Irrlicht Engine. Instead, please use the .dll in the \bin directory, the +.lib in the \lib directory and the header files in the \include directory. + +You will find a good tutorial how to set up your development environment and to +use the engine in the \examples directory. (Try 1.helloworld) + +The source of the engine is only included because of the following reasons: + + - To let developers be able to debug the engine. + - To let developers be able to make changes to the engine. + - To let developers be able to compile their own versions of the engine. + + + +HOW TO COMPILE THE ENGINE WITH LINUX + +If you wish to compile the engine in linux yourself, unzip the source source.zip +file in the \source directory. Run a 'make' in the now existing new subfolder 'Irrlicht'. +After this, you should be able to make all example applications in \examples. +Then just start an X Server and run them, from the directory where they are. + +If you get a compiling/linking problem like + + undefined reference to `glXGetProcAddress' + +Then there are several solutions: +A) This disables the use of OpenGL extensions: + Open the file IrrCompileConfig.h, comment out _IRR_OPENGL_USE_EXTPOINTER_, + and recompile Irrlicht using + make clean + make +B) Replace all occurrences of 'glXGetProcAddress' with 'glXGetProcAddressARB' and run a + make + This will solve the issue but keep the OpenGL extension enabled. + diff --git a/source/Irrlicht/utf8.cpp b/source/Irrlicht/utf8.cpp new file mode 100644 index 00000000..5ba06d9a --- /dev/null +++ b/source/Irrlicht/utf8.cpp @@ -0,0 +1,380 @@ +// Copyright (C) 2014 Lauri Kasanen +// This file is part of the "Irrlicht Engine". The UTF-8 functions are from physfs, +// under the zlib license, reproduced below. + +#include "irrTypes.h" +#include "irrString.h" + +namespace irr +{ +namespace core +{ + +/* + Copyright (c) 2001-2011 Ryan C. Gordon and others. + + This software is provided 'as-is', without any express or implied warranty. + In no event will the authors be held liable for any damages arising from + the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software in a + product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. + + Ryan C. Gordon +*/ + +/* + * From rfc3629, the UTF-8 spec: + * http://www.ietf.org/rfc/rfc3629.txt + * + * Char. number range | UTF-8 octet sequence + * (hexadecimal) | (binary) + * --------------------+--------------------------------------------- + * 0000 0000-0000 007F | 0xxxxxxx + * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx + * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx + * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + + +/* + * This may not be the best value, but it's one that isn't represented + * in Unicode (0x10FFFF is the largest codepoint value). We return this + * value from utf8codepoint() if there's bogus bits in the + * stream. utf8codepoint() will turn this value into something + * reasonable (like a question mark), for text that wants to try to recover, + * whereas utf8valid() will use the value to determine if a string has bad + * bits. + */ +#define UNICODE_BOGUS_CHAR_VALUE 0xFFFFFFFF + +/* + * This is the codepoint we currently return when there was bogus bits in a + * UTF-8 string. May not fly in Asian locales? + */ +#define UNICODE_BOGUS_CHAR_CODEPOINT '?' + +static u32 utf8codepoint(const char **_str) +{ + const char *str = *_str; + u32 retval = 0; + u32 octet = (u32) ((u8) *str); + u32 octet2, octet3, octet4; + + if (octet == 0) /* null terminator, end of string. */ + return 0; + + else if (octet < 128) /* one octet char: 0 to 127 */ + { + (*_str)++; /* skip to next possible start of codepoint. */ + return(octet); + } /* else if */ + + else if ((octet > 127) && (octet < 192)) /* bad (starts with 10xxxxxx). */ + { + /* + * Apparently each of these is supposed to be flagged as a bogus + * char, instead of just resyncing to the next valid codepoint. + */ + (*_str)++; /* skip to next possible start of codepoint. */ + return UNICODE_BOGUS_CHAR_VALUE; + } /* else if */ + + else if (octet < 224) /* two octets */ + { + octet -= (128+64); + octet2 = (u32) ((u8) *(++str)); + if ((octet2 & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + *_str += 2; /* skip to next possible start of codepoint. */ + retval = ((octet << 6) | (octet2 - 128)); + if ((retval >= 0x80) && (retval <= 0x7FF)) + return retval; + } /* else if */ + + else if (octet < 240) /* three octets */ + { + octet -= (128+64+32); + octet2 = (u32) ((u8) *(++str)); + if ((octet2 & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet3 = (u32) ((u8) *(++str)); + if ((octet3 & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + *_str += 3; /* skip to next possible start of codepoint. */ + retval = ( ((octet << 12)) | ((octet2-128) << 6) | ((octet3-128)) ); + + /* There are seven "UTF-16 surrogates" that are illegal in UTF-8. */ + switch (retval) + { + case 0xD800: + case 0xDB7F: + case 0xDB80: + case 0xDBFF: + case 0xDC00: + case 0xDF80: + case 0xDFFF: + return UNICODE_BOGUS_CHAR_VALUE; + } /* switch */ + + /* 0xFFFE and 0xFFFF are illegal, too, so we check them at the edge. */ + if ((retval >= 0x800) && (retval <= 0xFFFD)) + return retval; + } /* else if */ + + else if (octet < 248) /* four octets */ + { + octet -= (128+64+32+16); + octet2 = (u32) ((u8) *(++str)); + if ((octet2 & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet3 = (u32) ((u8) *(++str)); + if ((octet3 & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet4 = (u32) ((u8) *(++str)); + if ((octet4 & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + *_str += 4; /* skip to next possible start of codepoint. */ + retval = ( ((octet << 18)) | ((octet2 - 128) << 12) | + ((octet3 - 128) << 6) | ((octet4 - 128)) ); + if ((retval >= 0x10000) && (retval <= 0x10FFFF)) + return retval; + } /* else if */ + + /* + * Five and six octet sequences became illegal in rfc3629. + * We throw the codepoint away, but parse them to make sure we move + * ahead the right number of bytes and don't overflow the buffer. + */ + + else if (octet < 252) /* five octets */ + { + octet = (u32) ((u8) *(++str)); + if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (u32) ((u8) *(++str)); + if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (u32) ((u8) *(++str)); + if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (u32) ((u8) *(++str)); + if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + *_str += 5; /* skip to next possible start of codepoint. */ + return UNICODE_BOGUS_CHAR_VALUE; + } /* else if */ + + else /* six octets */ + { + octet = (u32) ((u8) *(++str)); + if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (u32) ((u8) *(++str)); + if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (u32) ((u8) *(++str)); + if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (u32) ((u8) *(++str)); + if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (u32) ((u8) *(++str)); + if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + *_str += 6; /* skip to next possible start of codepoint. */ + return UNICODE_BOGUS_CHAR_VALUE; + } /* else if */ + + return UNICODE_BOGUS_CHAR_VALUE; +} /* utf8codepoint */ + + +static void PHYSFS_utf8ToUcs4(const char *src, u32 *dst, u64 len) +{ + len -= sizeof (u32); /* save room for null char. */ + while (len >= sizeof (u32)) + { + u32 cp = utf8codepoint(&src); + if (cp == 0) + break; + else if (cp == UNICODE_BOGUS_CHAR_VALUE) + cp = UNICODE_BOGUS_CHAR_CODEPOINT; + *(dst++) = cp; + len -= sizeof (u32); + } /* while */ + + *dst = 0; +} /* PHYSFS_utf8ToUcs4 */ + + +static void PHYSFS_utf8ToUcs2(const char *src, u16 *dst, u64 len) +{ + len -= sizeof (u16); /* save room for null char. */ + while (len >= sizeof (u16)) + { + u32 cp = utf8codepoint(&src); + if (cp == 0) + break; + else if (cp == UNICODE_BOGUS_CHAR_VALUE) + cp = UNICODE_BOGUS_CHAR_CODEPOINT; + + /* !!! BLUESKY: UTF-16 surrogates? */ + if (cp > 0xFFFF) + cp = UNICODE_BOGUS_CHAR_CODEPOINT; + + *(dst++) = cp; + len -= sizeof (u16); + } /* while */ + + *dst = 0; +} /* PHYSFS_utf8ToUcs2 */ + +static void utf8fromcodepoint(u32 cp, char **_dst, u64 *_len) +{ + char *dst = *_dst; + u64 len = *_len; + + if (len == 0) + return; + + if (cp > 0x10FFFF) + cp = UNICODE_BOGUS_CHAR_CODEPOINT; + else if ((cp == 0xFFFE) || (cp == 0xFFFF)) /* illegal values. */ + cp = UNICODE_BOGUS_CHAR_CODEPOINT; + else + { + /* There are seven "UTF-16 surrogates" that are illegal in UTF-8. */ + switch (cp) + { + case 0xD800: + case 0xDB7F: + case 0xDB80: + case 0xDBFF: + case 0xDC00: + case 0xDF80: + case 0xDFFF: + cp = UNICODE_BOGUS_CHAR_CODEPOINT; + } /* switch */ + } /* else */ + + /* Do the encoding... */ + if (cp < 0x80) + { + *(dst++) = (char) cp; + len--; + } /* if */ + + else if (cp < 0x800) + { + if (len < 2) + len = 0; + else + { + *(dst++) = (char) ((cp >> 6) | 128 | 64); + *(dst++) = (char) (cp & 0x3F) | 128; + len -= 2; + } /* else */ + } /* else if */ + + else if (cp < 0x10000) + { + if (len < 3) + len = 0; + else + { + *(dst++) = (char) ((cp >> 12) | 128 | 64 | 32); + *(dst++) = (char) ((cp >> 6) & 0x3F) | 128; + *(dst++) = (char) (cp & 0x3F) | 128; + len -= 3; + } /* else */ + } /* else if */ + + else + { + if (len < 4) + len = 0; + else + { + *(dst++) = (char) ((cp >> 18) | 128 | 64 | 32 | 16); + *(dst++) = (char) ((cp >> 12) & 0x3F) | 128; + *(dst++) = (char) ((cp >> 6) & 0x3F) | 128; + *(dst++) = (char) (cp & 0x3F) | 128; + len -= 4; + } /* else if */ + } /* else */ + + *_dst = dst; + *_len = len; +} /* utf8fromcodepoint */ + +#define UTF8FROMTYPE(typ, src, dst, len) \ + if (len == 0) return; \ + len--; \ + while (len) \ + { \ + const u32 cp = (u32) ((typ) (*(src++))); \ + if (cp == 0) break; \ + utf8fromcodepoint(cp, &dst, &len); \ + } \ + *dst = '\0'; \ + +static void PHYSFS_utf8FromUcs4(const u32 *src, char *dst, u64 len) +{ + UTF8FROMTYPE(u32, src, dst, len); +} /* PHYSFS_utf8FromUcs4 */ + +static void PHYSFS_utf8FromUcs2(const u16 *src, char *dst, u64 len) +{ + UTF8FROMTYPE(u64, src, dst, len); +} /* PHYSFS_utf8FromUcs4 */ + +#undef UTF8FROMTYPE + +void utf8ToWchar(const char *in, wchar_t *out, const u64 len) +{ +#ifdef _WIN32 + PHYSFS_utf8ToUcs2(in, (u16 *) out, len); +#else + PHYSFS_utf8ToUcs4(in, (u32 *) out, len); +#endif +} + +void wcharToUtf8(const wchar_t *in, char *out, const u64 len) +{ +#ifdef _WIN32 + PHYSFS_utf8FromUcs2((const u16 *) in, out, len); +#else + PHYSFS_utf8FromUcs4((const u32 *) in, out, len); +#endif +} + +} // end namespace core +} // end namespace irr + diff --git a/source/Irrlicht/wglext.h b/source/Irrlicht/wglext.h new file mode 100644 index 00000000..a283f6a7 --- /dev/null +++ b/source/Irrlicht/wglext.h @@ -0,0 +1,855 @@ +#ifndef __wgl_wglext_h_ +#define __wgl_wglext_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2013-2018 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ +/* +** This header is generated from the Khronos OpenGL / OpenGL ES XML +** API Registry. The current version of the Registry, generator scripts +** used to make the header, and the header can be found at +** https://github.com/KhronosGroup/OpenGL-Registry +*/ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#define WIN32_LEAN_AND_MEAN 1 +#include +#endif + +#define WGL_WGLEXT_VERSION 20190515 + +/* Generated C header for: + * API: wgl + * Versions considered: .* + * Versions emitted: _nomatch_^ + * Default extensions included: wgl + * Additional extensions included: _nomatch_^ + * Extensions removed: _nomatch_^ + */ + +#ifndef WGL_ARB_buffer_region +#define WGL_ARB_buffer_region 1 +#define WGL_FRONT_COLOR_BUFFER_BIT_ARB 0x00000001 +#define WGL_BACK_COLOR_BUFFER_BIT_ARB 0x00000002 +#define WGL_DEPTH_BUFFER_BIT_ARB 0x00000004 +#define WGL_STENCIL_BUFFER_BIT_ARB 0x00000008 +typedef HANDLE (WINAPI * PFNWGLCREATEBUFFERREGIONARBPROC) (HDC hDC, int iLayerPlane, UINT uType); +typedef VOID (WINAPI * PFNWGLDELETEBUFFERREGIONARBPROC) (HANDLE hRegion); +typedef BOOL (WINAPI * PFNWGLSAVEBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height); +typedef BOOL (WINAPI * PFNWGLRESTOREBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); +#ifdef WGL_WGLEXT_PROTOTYPES +HANDLE WINAPI wglCreateBufferRegionARB (HDC hDC, int iLayerPlane, UINT uType); +VOID WINAPI wglDeleteBufferRegionARB (HANDLE hRegion); +BOOL WINAPI wglSaveBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height); +BOOL WINAPI wglRestoreBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); +#endif +#endif /* WGL_ARB_buffer_region */ + +#ifndef WGL_ARB_context_flush_control +#define WGL_ARB_context_flush_control 1 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#endif /* WGL_ARB_context_flush_control */ + +#ifndef WGL_ARB_create_context +#define WGL_ARB_create_context 1 +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define ERROR_INVALID_VERSION_ARB 0x2095 +typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList); +#ifdef WGL_WGLEXT_PROTOTYPES +HGLRC WINAPI wglCreateContextAttribsARB (HDC hDC, HGLRC hShareContext, const int *attribList); +#endif +#endif /* WGL_ARB_create_context */ + +#ifndef WGL_ARB_create_context_no_error +#define WGL_ARB_create_context_no_error 1 +#define WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31B3 +#endif /* WGL_ARB_create_context_no_error */ + +#ifndef WGL_ARB_create_context_profile +#define WGL_ARB_create_context_profile 1 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define ERROR_INVALID_PROFILE_ARB 0x2096 +#endif /* WGL_ARB_create_context_profile */ + +#ifndef WGL_ARB_create_context_robustness +#define WGL_ARB_create_context_robustness 1 +#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 +#endif /* WGL_ARB_create_context_robustness */ + +#ifndef WGL_ARB_extensions_string +#define WGL_ARB_extensions_string 1 +typedef const char *(WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); +#ifdef WGL_WGLEXT_PROTOTYPES +const char *WINAPI wglGetExtensionsStringARB (HDC hdc); +#endif +#endif /* WGL_ARB_extensions_string */ + +#ifndef WGL_ARB_framebuffer_sRGB +#define WGL_ARB_framebuffer_sRGB 1 +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 +#endif /* WGL_ARB_framebuffer_sRGB */ + +#ifndef WGL_ARB_make_current_read +#define WGL_ARB_make_current_read 1 +#define ERROR_INVALID_PIXEL_TYPE_ARB 0x2043 +#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054 +typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTARBPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); +typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCARBPROC) (void); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglMakeContextCurrentARB (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); +HDC WINAPI wglGetCurrentReadDCARB (void); +#endif +#endif /* WGL_ARB_make_current_read */ + +#ifndef WGL_ARB_multisample +#define WGL_ARB_multisample 1 +#define WGL_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 +#endif /* WGL_ARB_multisample */ + +#ifndef WGL_ARB_pbuffer +#define WGL_ARB_pbuffer 1 +DECLARE_HANDLE(HPBUFFERARB); +#define WGL_DRAW_TO_PBUFFER_ARB 0x202D +#define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E +#define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F +#define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030 +#define WGL_PBUFFER_LARGEST_ARB 0x2033 +#define WGL_PBUFFER_WIDTH_ARB 0x2034 +#define WGL_PBUFFER_HEIGHT_ARB 0x2035 +#define WGL_PBUFFER_LOST_ARB 0x2036 +typedef HPBUFFERARB (WINAPI * PFNWGLCREATEPBUFFERARBPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); +typedef HDC (WINAPI * PFNWGLGETPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer); +typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer, HDC hDC); +typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFERARBPROC) (HPBUFFERARB hPbuffer); +typedef BOOL (WINAPI * PFNWGLQUERYPBUFFERARBPROC) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); +#ifdef WGL_WGLEXT_PROTOTYPES +HPBUFFERARB WINAPI wglCreatePbufferARB (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); +HDC WINAPI wglGetPbufferDCARB (HPBUFFERARB hPbuffer); +int WINAPI wglReleasePbufferDCARB (HPBUFFERARB hPbuffer, HDC hDC); +BOOL WINAPI wglDestroyPbufferARB (HPBUFFERARB hPbuffer); +BOOL WINAPI wglQueryPbufferARB (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); +#endif +#endif /* WGL_ARB_pbuffer */ + +#ifndef WGL_ARB_pixel_format +#define WGL_ARB_pixel_format 1 +#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_DRAW_TO_BITMAP_ARB 0x2002 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_NEED_PALETTE_ARB 0x2004 +#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 +#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 +#define WGL_SWAP_METHOD_ARB 0x2007 +#define WGL_NUMBER_OVERLAYS_ARB 0x2008 +#define WGL_NUMBER_UNDERLAYS_ARB 0x2009 +#define WGL_TRANSPARENT_ARB 0x200A +#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 +#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 +#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 +#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A +#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B +#define WGL_SHARE_DEPTH_ARB 0x200C +#define WGL_SHARE_STENCIL_ARB 0x200D +#define WGL_SHARE_ACCUM_ARB 0x200E +#define WGL_SUPPORT_GDI_ARB 0x200F +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_STEREO_ARB 0x2012 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_RED_SHIFT_ARB 0x2016 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_GREEN_SHIFT_ARB 0x2018 +#define WGL_BLUE_BITS_ARB 0x2019 +#define WGL_BLUE_SHIFT_ARB 0x201A +#define WGL_ALPHA_BITS_ARB 0x201B +#define WGL_ALPHA_SHIFT_ARB 0x201C +#define WGL_ACCUM_BITS_ARB 0x201D +#define WGL_ACCUM_RED_BITS_ARB 0x201E +#define WGL_ACCUM_GREEN_BITS_ARB 0x201F +#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 +#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_AUX_BUFFERS_ARB 0x2024 +#define WGL_NO_ACCELERATION_ARB 0x2025 +#define WGL_GENERIC_ACCELERATION_ARB 0x2026 +#define WGL_FULL_ACCELERATION_ARB 0x2027 +#define WGL_SWAP_EXCHANGE_ARB 0x2028 +#define WGL_SWAP_COPY_ARB 0x2029 +#define WGL_SWAP_UNDEFINED_ARB 0x202A +#define WGL_TYPE_RGBA_ARB 0x202B +#define WGL_TYPE_COLORINDEX_ARB 0x202C +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); +typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetPixelFormatAttribivARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); +BOOL WINAPI wglGetPixelFormatAttribfvARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); +BOOL WINAPI wglChoosePixelFormatARB (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +#endif +#endif /* WGL_ARB_pixel_format */ + +#ifndef WGL_ARB_pixel_format_float +#define WGL_ARB_pixel_format_float 1 +#define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 +#endif /* WGL_ARB_pixel_format_float */ + +#ifndef WGL_ARB_render_texture +#define WGL_ARB_render_texture 1 +#define WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070 +#define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071 +#define WGL_TEXTURE_FORMAT_ARB 0x2072 +#define WGL_TEXTURE_TARGET_ARB 0x2073 +#define WGL_MIPMAP_TEXTURE_ARB 0x2074 +#define WGL_TEXTURE_RGB_ARB 0x2075 +#define WGL_TEXTURE_RGBA_ARB 0x2076 +#define WGL_NO_TEXTURE_ARB 0x2077 +#define WGL_TEXTURE_CUBE_MAP_ARB 0x2078 +#define WGL_TEXTURE_1D_ARB 0x2079 +#define WGL_TEXTURE_2D_ARB 0x207A +#define WGL_MIPMAP_LEVEL_ARB 0x207B +#define WGL_CUBE_MAP_FACE_ARB 0x207C +#define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D +#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E +#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F +#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080 +#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081 +#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082 +#define WGL_FRONT_LEFT_ARB 0x2083 +#define WGL_FRONT_RIGHT_ARB 0x2084 +#define WGL_BACK_LEFT_ARB 0x2085 +#define WGL_BACK_RIGHT_ARB 0x2086 +#define WGL_AUX0_ARB 0x2087 +#define WGL_AUX1_ARB 0x2088 +#define WGL_AUX2_ARB 0x2089 +#define WGL_AUX3_ARB 0x208A +#define WGL_AUX4_ARB 0x208B +#define WGL_AUX5_ARB 0x208C +#define WGL_AUX6_ARB 0x208D +#define WGL_AUX7_ARB 0x208E +#define WGL_AUX8_ARB 0x208F +#define WGL_AUX9_ARB 0x2090 +typedef BOOL (WINAPI * PFNWGLBINDTEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); +typedef BOOL (WINAPI * PFNWGLRELEASETEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); +typedef BOOL (WINAPI * PFNWGLSETPBUFFERATTRIBARBPROC) (HPBUFFERARB hPbuffer, const int *piAttribList); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglBindTexImageARB (HPBUFFERARB hPbuffer, int iBuffer); +BOOL WINAPI wglReleaseTexImageARB (HPBUFFERARB hPbuffer, int iBuffer); +BOOL WINAPI wglSetPbufferAttribARB (HPBUFFERARB hPbuffer, const int *piAttribList); +#endif +#endif /* WGL_ARB_render_texture */ + +#ifndef WGL_ARB_robustness_application_isolation +#define WGL_ARB_robustness_application_isolation 1 +#define WGL_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008 +#endif /* WGL_ARB_robustness_application_isolation */ + +#ifndef WGL_ARB_robustness_share_group_isolation +#define WGL_ARB_robustness_share_group_isolation 1 +#endif /* WGL_ARB_robustness_share_group_isolation */ + +#ifndef WGL_3DFX_multisample +#define WGL_3DFX_multisample 1 +#define WGL_SAMPLE_BUFFERS_3DFX 0x2060 +#define WGL_SAMPLES_3DFX 0x2061 +#endif /* WGL_3DFX_multisample */ + +#ifndef WGL_3DL_stereo_control +#define WGL_3DL_stereo_control 1 +#define WGL_STEREO_EMITTER_ENABLE_3DL 0x2055 +#define WGL_STEREO_EMITTER_DISABLE_3DL 0x2056 +#define WGL_STEREO_POLARITY_NORMAL_3DL 0x2057 +#define WGL_STEREO_POLARITY_INVERT_3DL 0x2058 +typedef BOOL (WINAPI * PFNWGLSETSTEREOEMITTERSTATE3DLPROC) (HDC hDC, UINT uState); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglSetStereoEmitterState3DL (HDC hDC, UINT uState); +#endif +#endif /* WGL_3DL_stereo_control */ + +#ifndef WGL_AMD_gpu_association +#define WGL_AMD_gpu_association 1 +#define WGL_GPU_VENDOR_AMD 0x1F00 +#define WGL_GPU_RENDERER_STRING_AMD 0x1F01 +#define WGL_GPU_OPENGL_VERSION_STRING_AMD 0x1F02 +#define WGL_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2 +#define WGL_GPU_RAM_AMD 0x21A3 +#define WGL_GPU_CLOCK_AMD 0x21A4 +#define WGL_GPU_NUM_PIPES_AMD 0x21A5 +#define WGL_GPU_NUM_SIMD_AMD 0x21A6 +#define WGL_GPU_NUM_RB_AMD 0x21A7 +#define WGL_GPU_NUM_SPI_AMD 0x21A8 +typedef UINT (WINAPI * PFNWGLGETGPUIDSAMDPROC) (UINT maxCount, UINT *ids); +typedef INT (WINAPI * PFNWGLGETGPUINFOAMDPROC) (UINT id, INT property, GLenum dataType, UINT size, void *data); +typedef UINT (WINAPI * PFNWGLGETCONTEXTGPUIDAMDPROC) (HGLRC hglrc); +typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC) (UINT id); +typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC) (UINT id, HGLRC hShareContext, const int *attribList); +typedef BOOL (WINAPI * PFNWGLDELETEASSOCIATEDCONTEXTAMDPROC) (HGLRC hglrc); +typedef BOOL (WINAPI * PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC) (HGLRC hglrc); +typedef HGLRC (WINAPI * PFNWGLGETCURRENTASSOCIATEDCONTEXTAMDPROC) (void); +typedef VOID (WINAPI * PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC) (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +#ifdef WGL_WGLEXT_PROTOTYPES +UINT WINAPI wglGetGPUIDsAMD (UINT maxCount, UINT *ids); +INT WINAPI wglGetGPUInfoAMD (UINT id, INT property, GLenum dataType, UINT size, void *data); +UINT WINAPI wglGetContextGPUIDAMD (HGLRC hglrc); +HGLRC WINAPI wglCreateAssociatedContextAMD (UINT id); +HGLRC WINAPI wglCreateAssociatedContextAttribsAMD (UINT id, HGLRC hShareContext, const int *attribList); +BOOL WINAPI wglDeleteAssociatedContextAMD (HGLRC hglrc); +BOOL WINAPI wglMakeAssociatedContextCurrentAMD (HGLRC hglrc); +HGLRC WINAPI wglGetCurrentAssociatedContextAMD (void); +VOID WINAPI wglBlitContextFramebufferAMD (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +#endif +#endif /* WGL_AMD_gpu_association */ + +#ifndef WGL_ATI_pixel_format_float +#define WGL_ATI_pixel_format_float 1 +#define WGL_TYPE_RGBA_FLOAT_ATI 0x21A0 +#endif /* WGL_ATI_pixel_format_float */ + +#ifndef WGL_ATI_render_texture_rectangle +#define WGL_ATI_render_texture_rectangle 1 +#define WGL_TEXTURE_RECTANGLE_ATI 0x21A5 +#endif /* WGL_ATI_render_texture_rectangle */ + +#ifndef WGL_EXT_colorspace +#define WGL_EXT_colorspace 1 +#define WGL_COLORSPACE_EXT 0x309D +#define WGL_COLORSPACE_SRGB_EXT 0x3089 +#define WGL_COLORSPACE_LINEAR_EXT 0x308A +#endif /* WGL_EXT_colorspace */ + +#ifndef WGL_EXT_create_context_es2_profile +#define WGL_EXT_create_context_es2_profile 1 +#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 +#endif /* WGL_EXT_create_context_es2_profile */ + +#ifndef WGL_EXT_create_context_es_profile +#define WGL_EXT_create_context_es_profile 1 +#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 +#endif /* WGL_EXT_create_context_es_profile */ + +#ifndef WGL_EXT_depth_float +#define WGL_EXT_depth_float 1 +#define WGL_DEPTH_FLOAT_EXT 0x2040 +#endif /* WGL_EXT_depth_float */ + +#ifndef WGL_EXT_display_color_table +#define WGL_EXT_display_color_table 1 +typedef GLboolean (WINAPI * PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC) (GLushort id); +typedef GLboolean (WINAPI * PFNWGLLOADDISPLAYCOLORTABLEEXTPROC) (const GLushort *table, GLuint length); +typedef GLboolean (WINAPI * PFNWGLBINDDISPLAYCOLORTABLEEXTPROC) (GLushort id); +typedef VOID (WINAPI * PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC) (GLushort id); +#ifdef WGL_WGLEXT_PROTOTYPES +GLboolean WINAPI wglCreateDisplayColorTableEXT (GLushort id); +GLboolean WINAPI wglLoadDisplayColorTableEXT (const GLushort *table, GLuint length); +GLboolean WINAPI wglBindDisplayColorTableEXT (GLushort id); +VOID WINAPI wglDestroyDisplayColorTableEXT (GLushort id); +#endif +#endif /* WGL_EXT_display_color_table */ + +#ifndef WGL_EXT_extensions_string +#define WGL_EXT_extensions_string 1 +typedef const char *(WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC) (void); +#ifdef WGL_WGLEXT_PROTOTYPES +const char *WINAPI wglGetExtensionsStringEXT (void); +#endif +#endif /* WGL_EXT_extensions_string */ + +#ifndef WGL_EXT_framebuffer_sRGB +#define WGL_EXT_framebuffer_sRGB 1 +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9 +#endif /* WGL_EXT_framebuffer_sRGB */ + +#ifndef WGL_EXT_make_current_read +#define WGL_EXT_make_current_read 1 +#define ERROR_INVALID_PIXEL_TYPE_EXT 0x2043 +typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTEXTPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); +typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCEXTPROC) (void); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglMakeContextCurrentEXT (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); +HDC WINAPI wglGetCurrentReadDCEXT (void); +#endif +#endif /* WGL_EXT_make_current_read */ + +#ifndef WGL_EXT_multisample +#define WGL_EXT_multisample 1 +#define WGL_SAMPLE_BUFFERS_EXT 0x2041 +#define WGL_SAMPLES_EXT 0x2042 +#endif /* WGL_EXT_multisample */ + +#ifndef WGL_EXT_pbuffer +#define WGL_EXT_pbuffer 1 +DECLARE_HANDLE(HPBUFFEREXT); +#define WGL_DRAW_TO_PBUFFER_EXT 0x202D +#define WGL_MAX_PBUFFER_PIXELS_EXT 0x202E +#define WGL_MAX_PBUFFER_WIDTH_EXT 0x202F +#define WGL_MAX_PBUFFER_HEIGHT_EXT 0x2030 +#define WGL_OPTIMAL_PBUFFER_WIDTH_EXT 0x2031 +#define WGL_OPTIMAL_PBUFFER_HEIGHT_EXT 0x2032 +#define WGL_PBUFFER_LARGEST_EXT 0x2033 +#define WGL_PBUFFER_WIDTH_EXT 0x2034 +#define WGL_PBUFFER_HEIGHT_EXT 0x2035 +typedef HPBUFFEREXT (WINAPI * PFNWGLCREATEPBUFFEREXTPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); +typedef HDC (WINAPI * PFNWGLGETPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer); +typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer, HDC hDC); +typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer); +typedef BOOL (WINAPI * PFNWGLQUERYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); +#ifdef WGL_WGLEXT_PROTOTYPES +HPBUFFEREXT WINAPI wglCreatePbufferEXT (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); +HDC WINAPI wglGetPbufferDCEXT (HPBUFFEREXT hPbuffer); +int WINAPI wglReleasePbufferDCEXT (HPBUFFEREXT hPbuffer, HDC hDC); +BOOL WINAPI wglDestroyPbufferEXT (HPBUFFEREXT hPbuffer); +BOOL WINAPI wglQueryPbufferEXT (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); +#endif +#endif /* WGL_EXT_pbuffer */ + +#ifndef WGL_EXT_pixel_format +#define WGL_EXT_pixel_format 1 +#define WGL_NUMBER_PIXEL_FORMATS_EXT 0x2000 +#define WGL_DRAW_TO_WINDOW_EXT 0x2001 +#define WGL_DRAW_TO_BITMAP_EXT 0x2002 +#define WGL_ACCELERATION_EXT 0x2003 +#define WGL_NEED_PALETTE_EXT 0x2004 +#define WGL_NEED_SYSTEM_PALETTE_EXT 0x2005 +#define WGL_SWAP_LAYER_BUFFERS_EXT 0x2006 +#define WGL_SWAP_METHOD_EXT 0x2007 +#define WGL_NUMBER_OVERLAYS_EXT 0x2008 +#define WGL_NUMBER_UNDERLAYS_EXT 0x2009 +#define WGL_TRANSPARENT_EXT 0x200A +#define WGL_TRANSPARENT_VALUE_EXT 0x200B +#define WGL_SHARE_DEPTH_EXT 0x200C +#define WGL_SHARE_STENCIL_EXT 0x200D +#define WGL_SHARE_ACCUM_EXT 0x200E +#define WGL_SUPPORT_GDI_EXT 0x200F +#define WGL_SUPPORT_OPENGL_EXT 0x2010 +#define WGL_DOUBLE_BUFFER_EXT 0x2011 +#define WGL_STEREO_EXT 0x2012 +#define WGL_PIXEL_TYPE_EXT 0x2013 +#define WGL_COLOR_BITS_EXT 0x2014 +#define WGL_RED_BITS_EXT 0x2015 +#define WGL_RED_SHIFT_EXT 0x2016 +#define WGL_GREEN_BITS_EXT 0x2017 +#define WGL_GREEN_SHIFT_EXT 0x2018 +#define WGL_BLUE_BITS_EXT 0x2019 +#define WGL_BLUE_SHIFT_EXT 0x201A +#define WGL_ALPHA_BITS_EXT 0x201B +#define WGL_ALPHA_SHIFT_EXT 0x201C +#define WGL_ACCUM_BITS_EXT 0x201D +#define WGL_ACCUM_RED_BITS_EXT 0x201E +#define WGL_ACCUM_GREEN_BITS_EXT 0x201F +#define WGL_ACCUM_BLUE_BITS_EXT 0x2020 +#define WGL_ACCUM_ALPHA_BITS_EXT 0x2021 +#define WGL_DEPTH_BITS_EXT 0x2022 +#define WGL_STENCIL_BITS_EXT 0x2023 +#define WGL_AUX_BUFFERS_EXT 0x2024 +#define WGL_NO_ACCELERATION_EXT 0x2025 +#define WGL_GENERIC_ACCELERATION_EXT 0x2026 +#define WGL_FULL_ACCELERATION_EXT 0x2027 +#define WGL_SWAP_EXCHANGE_EXT 0x2028 +#define WGL_SWAP_COPY_EXT 0x2029 +#define WGL_SWAP_UNDEFINED_EXT 0x202A +#define WGL_TYPE_RGBA_EXT 0x202B +#define WGL_TYPE_COLORINDEX_EXT 0x202C +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); +typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATEXTPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetPixelFormatAttribivEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); +BOOL WINAPI wglGetPixelFormatAttribfvEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); +BOOL WINAPI wglChoosePixelFormatEXT (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +#endif +#endif /* WGL_EXT_pixel_format */ + +#ifndef WGL_EXT_pixel_format_packed_float +#define WGL_EXT_pixel_format_packed_float 1 +#define WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT 0x20A8 +#endif /* WGL_EXT_pixel_format_packed_float */ + +#ifndef WGL_EXT_swap_control +#define WGL_EXT_swap_control 1 +typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval); +typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglSwapIntervalEXT (int interval); +int WINAPI wglGetSwapIntervalEXT (void); +#endif +#endif /* WGL_EXT_swap_control */ + +#ifndef WGL_EXT_swap_control_tear +#define WGL_EXT_swap_control_tear 1 +#endif /* WGL_EXT_swap_control_tear */ + +#ifndef WGL_I3D_digital_video_control +#define WGL_I3D_digital_video_control 1 +#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D 0x2050 +#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D 0x2051 +#define WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D 0x2052 +#define WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D 0x2053 +typedef BOOL (WINAPI * PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); +typedef BOOL (WINAPI * PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetDigitalVideoParametersI3D (HDC hDC, int iAttribute, int *piValue); +BOOL WINAPI wglSetDigitalVideoParametersI3D (HDC hDC, int iAttribute, const int *piValue); +#endif +#endif /* WGL_I3D_digital_video_control */ + +#ifndef WGL_I3D_gamma +#define WGL_I3D_gamma 1 +#define WGL_GAMMA_TABLE_SIZE_I3D 0x204E +#define WGL_GAMMA_EXCLUDE_DESKTOP_I3D 0x204F +typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); +typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); +typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); +typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetGammaTableParametersI3D (HDC hDC, int iAttribute, int *piValue); +BOOL WINAPI wglSetGammaTableParametersI3D (HDC hDC, int iAttribute, const int *piValue); +BOOL WINAPI wglGetGammaTableI3D (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); +BOOL WINAPI wglSetGammaTableI3D (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); +#endif +#endif /* WGL_I3D_gamma */ + +#ifndef WGL_I3D_genlock +#define WGL_I3D_genlock 1 +#define WGL_GENLOCK_SOURCE_MULTIVIEW_I3D 0x2044 +#define WGL_GENLOCK_SOURCE_EXTERNAL_SYNC_I3D 0x2045 +#define WGL_GENLOCK_SOURCE_EXTERNAL_FIELD_I3D 0x2046 +#define WGL_GENLOCK_SOURCE_EXTERNAL_TTL_I3D 0x2047 +#define WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D 0x2048 +#define WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D 0x2049 +#define WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D 0x204A +#define WGL_GENLOCK_SOURCE_EDGE_RISING_I3D 0x204B +#define WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D 0x204C +typedef BOOL (WINAPI * PFNWGLENABLEGENLOCKI3DPROC) (HDC hDC); +typedef BOOL (WINAPI * PFNWGLDISABLEGENLOCKI3DPROC) (HDC hDC); +typedef BOOL (WINAPI * PFNWGLISENABLEDGENLOCKI3DPROC) (HDC hDC, BOOL *pFlag); +typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEI3DPROC) (HDC hDC, UINT uSource); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEI3DPROC) (HDC hDC, UINT *uSource); +typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT uEdge); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT *uEdge); +typedef BOOL (WINAPI * PFNWGLGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT uRate); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT *uRate); +typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT uDelay); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT *uDelay); +typedef BOOL (WINAPI * PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC) (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglEnableGenlockI3D (HDC hDC); +BOOL WINAPI wglDisableGenlockI3D (HDC hDC); +BOOL WINAPI wglIsEnabledGenlockI3D (HDC hDC, BOOL *pFlag); +BOOL WINAPI wglGenlockSourceI3D (HDC hDC, UINT uSource); +BOOL WINAPI wglGetGenlockSourceI3D (HDC hDC, UINT *uSource); +BOOL WINAPI wglGenlockSourceEdgeI3D (HDC hDC, UINT uEdge); +BOOL WINAPI wglGetGenlockSourceEdgeI3D (HDC hDC, UINT *uEdge); +BOOL WINAPI wglGenlockSampleRateI3D (HDC hDC, UINT uRate); +BOOL WINAPI wglGetGenlockSampleRateI3D (HDC hDC, UINT *uRate); +BOOL WINAPI wglGenlockSourceDelayI3D (HDC hDC, UINT uDelay); +BOOL WINAPI wglGetGenlockSourceDelayI3D (HDC hDC, UINT *uDelay); +BOOL WINAPI wglQueryGenlockMaxSourceDelayI3D (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); +#endif +#endif /* WGL_I3D_genlock */ + +#ifndef WGL_I3D_image_buffer +#define WGL_I3D_image_buffer 1 +#define WGL_IMAGE_BUFFER_MIN_ACCESS_I3D 0x00000001 +#define WGL_IMAGE_BUFFER_LOCK_I3D 0x00000002 +typedef LPVOID (WINAPI * PFNWGLCREATEIMAGEBUFFERI3DPROC) (HDC hDC, DWORD dwSize, UINT uFlags); +typedef BOOL (WINAPI * PFNWGLDESTROYIMAGEBUFFERI3DPROC) (HDC hDC, LPVOID pAddress); +typedef BOOL (WINAPI * PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); +typedef BOOL (WINAPI * PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const LPVOID *pAddress, UINT count); +#ifdef WGL_WGLEXT_PROTOTYPES +LPVOID WINAPI wglCreateImageBufferI3D (HDC hDC, DWORD dwSize, UINT uFlags); +BOOL WINAPI wglDestroyImageBufferI3D (HDC hDC, LPVOID pAddress); +BOOL WINAPI wglAssociateImageBufferEventsI3D (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); +BOOL WINAPI wglReleaseImageBufferEventsI3D (HDC hDC, const LPVOID *pAddress, UINT count); +#endif +#endif /* WGL_I3D_image_buffer */ + +#ifndef WGL_I3D_swap_frame_lock +#define WGL_I3D_swap_frame_lock 1 +typedef BOOL (WINAPI * PFNWGLENABLEFRAMELOCKI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLDISABLEFRAMELOCKI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLISENABLEDFRAMELOCKI3DPROC) (BOOL *pFlag); +typedef BOOL (WINAPI * PFNWGLQUERYFRAMELOCKMASTERI3DPROC) (BOOL *pFlag); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglEnableFrameLockI3D (void); +BOOL WINAPI wglDisableFrameLockI3D (void); +BOOL WINAPI wglIsEnabledFrameLockI3D (BOOL *pFlag); +BOOL WINAPI wglQueryFrameLockMasterI3D (BOOL *pFlag); +#endif +#endif /* WGL_I3D_swap_frame_lock */ + +#ifndef WGL_I3D_swap_frame_usage +#define WGL_I3D_swap_frame_usage 1 +typedef BOOL (WINAPI * PFNWGLGETFRAMEUSAGEI3DPROC) (float *pUsage); +typedef BOOL (WINAPI * PFNWGLBEGINFRAMETRACKINGI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLENDFRAMETRACKINGI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLQUERYFRAMETRACKINGI3DPROC) (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetFrameUsageI3D (float *pUsage); +BOOL WINAPI wglBeginFrameTrackingI3D (void); +BOOL WINAPI wglEndFrameTrackingI3D (void); +BOOL WINAPI wglQueryFrameTrackingI3D (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); +#endif +#endif /* WGL_I3D_swap_frame_usage */ + +#ifndef WGL_NV_DX_interop +#define WGL_NV_DX_interop 1 +#define WGL_ACCESS_READ_ONLY_NV 0x00000000 +#define WGL_ACCESS_READ_WRITE_NV 0x00000001 +#define WGL_ACCESS_WRITE_DISCARD_NV 0x00000002 +typedef BOOL (WINAPI * PFNWGLDXSETRESOURCESHAREHANDLENVPROC) (void *dxObject, HANDLE shareHandle); +typedef HANDLE (WINAPI * PFNWGLDXOPENDEVICENVPROC) (void *dxDevice); +typedef BOOL (WINAPI * PFNWGLDXCLOSEDEVICENVPROC) (HANDLE hDevice); +typedef HANDLE (WINAPI * PFNWGLDXREGISTEROBJECTNVPROC) (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access); +typedef BOOL (WINAPI * PFNWGLDXUNREGISTEROBJECTNVPROC) (HANDLE hDevice, HANDLE hObject); +typedef BOOL (WINAPI * PFNWGLDXOBJECTACCESSNVPROC) (HANDLE hObject, GLenum access); +typedef BOOL (WINAPI * PFNWGLDXLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects); +typedef BOOL (WINAPI * PFNWGLDXUNLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglDXSetResourceShareHandleNV (void *dxObject, HANDLE shareHandle); +HANDLE WINAPI wglDXOpenDeviceNV (void *dxDevice); +BOOL WINAPI wglDXCloseDeviceNV (HANDLE hDevice); +HANDLE WINAPI wglDXRegisterObjectNV (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access); +BOOL WINAPI wglDXUnregisterObjectNV (HANDLE hDevice, HANDLE hObject); +BOOL WINAPI wglDXObjectAccessNV (HANDLE hObject, GLenum access); +BOOL WINAPI wglDXLockObjectsNV (HANDLE hDevice, GLint count, HANDLE *hObjects); +BOOL WINAPI wglDXUnlockObjectsNV (HANDLE hDevice, GLint count, HANDLE *hObjects); +#endif +#endif /* WGL_NV_DX_interop */ + +#ifndef WGL_NV_DX_interop2 +#define WGL_NV_DX_interop2 1 +#endif /* WGL_NV_DX_interop2 */ + +#ifndef WGL_NV_copy_image +#define WGL_NV_copy_image 1 +typedef BOOL (WINAPI * PFNWGLCOPYIMAGESUBDATANVPROC) (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglCopyImageSubDataNV (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); +#endif +#endif /* WGL_NV_copy_image */ + +#ifndef WGL_NV_delay_before_swap +#define WGL_NV_delay_before_swap 1 +typedef BOOL (WINAPI * PFNWGLDELAYBEFORESWAPNVPROC) (HDC hDC, GLfloat seconds); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglDelayBeforeSwapNV (HDC hDC, GLfloat seconds); +#endif +#endif /* WGL_NV_delay_before_swap */ + +#ifndef WGL_NV_float_buffer +#define WGL_NV_float_buffer 1 +#define WGL_FLOAT_COMPONENTS_NV 0x20B0 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV 0x20B1 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV 0x20B2 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV 0x20B3 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV 0x20B4 +#define WGL_TEXTURE_FLOAT_R_NV 0x20B5 +#define WGL_TEXTURE_FLOAT_RG_NV 0x20B6 +#define WGL_TEXTURE_FLOAT_RGB_NV 0x20B7 +#define WGL_TEXTURE_FLOAT_RGBA_NV 0x20B8 +#endif /* WGL_NV_float_buffer */ + +#ifndef WGL_NV_gpu_affinity +#define WGL_NV_gpu_affinity 1 +DECLARE_HANDLE(HGPUNV); +struct _GPU_DEVICE { + DWORD cb; + CHAR DeviceName[32]; + CHAR DeviceString[128]; + DWORD Flags; + RECT rcVirtualScreen; +}; +typedef struct _GPU_DEVICE *PGPU_DEVICE; +#define ERROR_INCOMPATIBLE_AFFINITY_MASKS_NV 0x20D0 +#define ERROR_MISSING_AFFINITY_MASK_NV 0x20D1 +typedef BOOL (WINAPI * PFNWGLENUMGPUSNVPROC) (UINT iGpuIndex, HGPUNV *phGpu); +typedef BOOL (WINAPI * PFNWGLENUMGPUDEVICESNVPROC) (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice); +typedef HDC (WINAPI * PFNWGLCREATEAFFINITYDCNVPROC) (const HGPUNV *phGpuList); +typedef BOOL (WINAPI * PFNWGLENUMGPUSFROMAFFINITYDCNVPROC) (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu); +typedef BOOL (WINAPI * PFNWGLDELETEDCNVPROC) (HDC hdc); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglEnumGpusNV (UINT iGpuIndex, HGPUNV *phGpu); +BOOL WINAPI wglEnumGpuDevicesNV (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice); +HDC WINAPI wglCreateAffinityDCNV (const HGPUNV *phGpuList); +BOOL WINAPI wglEnumGpusFromAffinityDCNV (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu); +BOOL WINAPI wglDeleteDCNV (HDC hdc); +#endif +#endif /* WGL_NV_gpu_affinity */ + +#ifndef WGL_NV_multisample_coverage +#define WGL_NV_multisample_coverage 1 +#define WGL_COVERAGE_SAMPLES_NV 0x2042 +#define WGL_COLOR_SAMPLES_NV 0x20B9 +#endif /* WGL_NV_multisample_coverage */ + +#ifndef WGL_NV_present_video +#define WGL_NV_present_video 1 +DECLARE_HANDLE(HVIDEOOUTPUTDEVICENV); +#define WGL_NUM_VIDEO_SLOTS_NV 0x20F0 +typedef int (WINAPI * PFNWGLENUMERATEVIDEODEVICESNVPROC) (HDC hDc, HVIDEOOUTPUTDEVICENV *phDeviceList); +typedef BOOL (WINAPI * PFNWGLBINDVIDEODEVICENVPROC) (HDC hDc, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList); +typedef BOOL (WINAPI * PFNWGLQUERYCURRENTCONTEXTNVPROC) (int iAttribute, int *piValue); +#ifdef WGL_WGLEXT_PROTOTYPES +int WINAPI wglEnumerateVideoDevicesNV (HDC hDc, HVIDEOOUTPUTDEVICENV *phDeviceList); +BOOL WINAPI wglBindVideoDeviceNV (HDC hDc, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList); +BOOL WINAPI wglQueryCurrentContextNV (int iAttribute, int *piValue); +#endif +#endif /* WGL_NV_present_video */ + +#ifndef WGL_NV_render_depth_texture +#define WGL_NV_render_depth_texture 1 +#define WGL_BIND_TO_TEXTURE_DEPTH_NV 0x20A3 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4 +#define WGL_DEPTH_TEXTURE_FORMAT_NV 0x20A5 +#define WGL_TEXTURE_DEPTH_COMPONENT_NV 0x20A6 +#define WGL_DEPTH_COMPONENT_NV 0x20A7 +#endif /* WGL_NV_render_depth_texture */ + +#ifndef WGL_NV_render_texture_rectangle +#define WGL_NV_render_texture_rectangle 1 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV 0x20A0 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV 0x20A1 +#define WGL_TEXTURE_RECTANGLE_NV 0x20A2 +#endif /* WGL_NV_render_texture_rectangle */ + +#ifndef WGL_NV_swap_group +#define WGL_NV_swap_group 1 +typedef BOOL (WINAPI * PFNWGLJOINSWAPGROUPNVPROC) (HDC hDC, GLuint group); +typedef BOOL (WINAPI * PFNWGLBINDSWAPBARRIERNVPROC) (GLuint group, GLuint barrier); +typedef BOOL (WINAPI * PFNWGLQUERYSWAPGROUPNVPROC) (HDC hDC, GLuint *group, GLuint *barrier); +typedef BOOL (WINAPI * PFNWGLQUERYMAXSWAPGROUPSNVPROC) (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers); +typedef BOOL (WINAPI * PFNWGLQUERYFRAMECOUNTNVPROC) (HDC hDC, GLuint *count); +typedef BOOL (WINAPI * PFNWGLRESETFRAMECOUNTNVPROC) (HDC hDC); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglJoinSwapGroupNV (HDC hDC, GLuint group); +BOOL WINAPI wglBindSwapBarrierNV (GLuint group, GLuint barrier); +BOOL WINAPI wglQuerySwapGroupNV (HDC hDC, GLuint *group, GLuint *barrier); +BOOL WINAPI wglQueryMaxSwapGroupsNV (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers); +BOOL WINAPI wglQueryFrameCountNV (HDC hDC, GLuint *count); +BOOL WINAPI wglResetFrameCountNV (HDC hDC); +#endif +#endif /* WGL_NV_swap_group */ + +#ifndef WGL_NV_vertex_array_range +#define WGL_NV_vertex_array_range 1 +typedef void *(WINAPI * PFNWGLALLOCATEMEMORYNVPROC) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); +typedef void (WINAPI * PFNWGLFREEMEMORYNVPROC) (void *pointer); +#ifdef WGL_WGLEXT_PROTOTYPES +void *WINAPI wglAllocateMemoryNV (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); +void WINAPI wglFreeMemoryNV (void *pointer); +#endif +#endif /* WGL_NV_vertex_array_range */ + +#ifndef WGL_NV_video_capture +#define WGL_NV_video_capture 1 +DECLARE_HANDLE(HVIDEOINPUTDEVICENV); +#define WGL_UNIQUE_ID_NV 0x20CE +#define WGL_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF +typedef BOOL (WINAPI * PFNWGLBINDVIDEOCAPTUREDEVICENVPROC) (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice); +typedef UINT (WINAPI * PFNWGLENUMERATEVIDEOCAPTUREDEVICESNVPROC) (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList); +typedef BOOL (WINAPI * PFNWGLLOCKVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice); +typedef BOOL (WINAPI * PFNWGLQUERYVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue); +typedef BOOL (WINAPI * PFNWGLRELEASEVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglBindVideoCaptureDeviceNV (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice); +UINT WINAPI wglEnumerateVideoCaptureDevicesNV (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList); +BOOL WINAPI wglLockVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice); +BOOL WINAPI wglQueryVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue); +BOOL WINAPI wglReleaseVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice); +#endif +#endif /* WGL_NV_video_capture */ + +#ifndef WGL_NV_video_output +#define WGL_NV_video_output 1 +DECLARE_HANDLE(HPVIDEODEV); +#define WGL_BIND_TO_VIDEO_RGB_NV 0x20C0 +#define WGL_BIND_TO_VIDEO_RGBA_NV 0x20C1 +#define WGL_BIND_TO_VIDEO_RGB_AND_DEPTH_NV 0x20C2 +#define WGL_VIDEO_OUT_COLOR_NV 0x20C3 +#define WGL_VIDEO_OUT_ALPHA_NV 0x20C4 +#define WGL_VIDEO_OUT_DEPTH_NV 0x20C5 +#define WGL_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6 +#define WGL_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7 +#define WGL_VIDEO_OUT_FRAME 0x20C8 +#define WGL_VIDEO_OUT_FIELD_1 0x20C9 +#define WGL_VIDEO_OUT_FIELD_2 0x20CA +#define WGL_VIDEO_OUT_STACKED_FIELDS_1_2 0x20CB +#define WGL_VIDEO_OUT_STACKED_FIELDS_2_1 0x20CC +typedef BOOL (WINAPI * PFNWGLGETVIDEODEVICENVPROC) (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice); +typedef BOOL (WINAPI * PFNWGLRELEASEVIDEODEVICENVPROC) (HPVIDEODEV hVideoDevice); +typedef BOOL (WINAPI * PFNWGLBINDVIDEOIMAGENVPROC) (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer); +typedef BOOL (WINAPI * PFNWGLRELEASEVIDEOIMAGENVPROC) (HPBUFFERARB hPbuffer, int iVideoBuffer); +typedef BOOL (WINAPI * PFNWGLSENDPBUFFERTOVIDEONVPROC) (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock); +typedef BOOL (WINAPI * PFNWGLGETVIDEOINFONVPROC) (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetVideoDeviceNV (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice); +BOOL WINAPI wglReleaseVideoDeviceNV (HPVIDEODEV hVideoDevice); +BOOL WINAPI wglBindVideoImageNV (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer); +BOOL WINAPI wglReleaseVideoImageNV (HPBUFFERARB hPbuffer, int iVideoBuffer); +BOOL WINAPI wglSendPbufferToVideoNV (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock); +BOOL WINAPI wglGetVideoInfoNV (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); +#endif +#endif /* WGL_NV_video_output */ + +#ifndef WGL_OML_sync_control +#define WGL_OML_sync_control 1 +typedef BOOL (WINAPI * PFNWGLGETSYNCVALUESOMLPROC) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); +typedef BOOL (WINAPI * PFNWGLGETMSCRATEOMLPROC) (HDC hdc, INT32 *numerator, INT32 *denominator); +typedef INT64 (WINAPI * PFNWGLSWAPBUFFERSMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); +typedef INT64 (WINAPI * PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) (HDC hdc, INT fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); +typedef BOOL (WINAPI * PFNWGLWAITFORMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); +typedef BOOL (WINAPI * PFNWGLWAITFORSBCOMLPROC) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetSyncValuesOML (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); +BOOL WINAPI wglGetMscRateOML (HDC hdc, INT32 *numerator, INT32 *denominator); +INT64 WINAPI wglSwapBuffersMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); +INT64 WINAPI wglSwapLayerBuffersMscOML (HDC hdc, INT fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); +BOOL WINAPI wglWaitForMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); +BOOL WINAPI wglWaitForSbcOML (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); +#endif +#endif /* WGL_OML_sync_control */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/Irrlicht/zlib/CMakeLists.txt b/source/Irrlicht/zlib/CMakeLists.txt new file mode 100644 index 00000000..0c0247cc --- /dev/null +++ b/source/Irrlicht/zlib/CMakeLists.txt @@ -0,0 +1,249 @@ +cmake_minimum_required(VERSION 2.4.4) +set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON) + +project(zlib C) + +set(VERSION "1.2.8") + +option(ASM686 "Enable building i686 assembly implementation") +option(AMD64 "Enable building amd64 assembly implementation") + +set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables") +set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries") +set(INSTALL_INC_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "Installation directory for headers") +set(INSTALL_MAN_DIR "${CMAKE_INSTALL_PREFIX}/share/man" CACHE PATH "Installation directory for manual pages") +set(INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/share/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files") + +include(CheckTypeSize) +include(CheckFunctionExists) +include(CheckIncludeFile) +include(CheckCSourceCompiles) +enable_testing() + +check_include_file(sys/types.h HAVE_SYS_TYPES_H) +check_include_file(stdint.h HAVE_STDINT_H) +check_include_file(stddef.h HAVE_STDDEF_H) + +# +# Check to see if we have large file support +# +set(CMAKE_REQUIRED_DEFINITIONS -D_LARGEFILE64_SOURCE=1) +# We add these other definitions here because CheckTypeSize.cmake +# in CMake 2.4.x does not automatically do so and we want +# compatibility with CMake 2.4.x. +if(HAVE_SYS_TYPES_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_SYS_TYPES_H) +endif() +if(HAVE_STDINT_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDINT_H) +endif() +if(HAVE_STDDEF_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDDEF_H) +endif() +check_type_size(off64_t OFF64_T) +if(HAVE_OFF64_T) + add_definitions(-D_LARGEFILE64_SOURCE=1) +endif() +set(CMAKE_REQUIRED_DEFINITIONS) # clear variable + +# +# Check for fseeko +# +check_function_exists(fseeko HAVE_FSEEKO) +if(NOT HAVE_FSEEKO) + add_definitions(-DNO_FSEEKO) +endif() + +# +# Check for unistd.h +# +check_include_file(unistd.h Z_HAVE_UNISTD_H) + +if(MSVC) + set(CMAKE_DEBUG_POSTFIX "d") + add_definitions(-D_CRT_SECURE_NO_DEPRECATE) + add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE) + include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +endif() + +if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) + # If we're doing an out of source build and the user has a zconf.h + # in their source tree... + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h) + message(STATUS "Renaming") + message(STATUS " ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h") + message(STATUS "to 'zconf.h.included' because this file is included with zlib") + message(STATUS "but CMake generates it automatically in the build directory.") + file(RENAME ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.included) + endif() +endif() + +set(ZLIB_PC ${CMAKE_CURRENT_BINARY_DIR}/zlib.pc) +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/zlib.pc.cmakein + ${ZLIB_PC} @ONLY) +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.cmakein + ${CMAKE_CURRENT_BINARY_DIR}/zconf.h @ONLY) +include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}) + + +#============================================================================ +# zlib +#============================================================================ + +set(ZLIB_PUBLIC_HDRS + ${CMAKE_CURRENT_BINARY_DIR}/zconf.h + zlib.h +) +set(ZLIB_PRIVATE_HDRS + crc32.h + deflate.h + gzguts.h + inffast.h + inffixed.h + inflate.h + inftrees.h + trees.h + zutil.h +) +set(ZLIB_SRCS + adler32.c + compress.c + crc32.c + deflate.c + gzclose.c + gzlib.c + gzread.c + gzwrite.c + inflate.c + infback.c + inftrees.c + inffast.c + trees.c + uncompr.c + zutil.c +) + +if(NOT MINGW) + set(ZLIB_DLL_SRCS + win32/zlib1.rc # If present will override custom build rule below. + ) +endif() + +if(CMAKE_COMPILER_IS_GNUCC) + if(ASM686) + set(ZLIB_ASMS contrib/asm686/match.S) + elseif (AMD64) + set(ZLIB_ASMS contrib/amd64/amd64-match.S) + endif () + + if(ZLIB_ASMS) + add_definitions(-DASMV) + set_source_files_properties(${ZLIB_ASMS} PROPERTIES LANGUAGE C COMPILE_FLAGS -DNO_UNDERLINE) + endif() +endif() + +if(MSVC) + if(ASM686) + ENABLE_LANGUAGE(ASM_MASM) + set(ZLIB_ASMS + contrib/masmx86/inffas32.asm + contrib/masmx86/match686.asm + ) + elseif (AMD64) + ENABLE_LANGUAGE(ASM_MASM) + set(ZLIB_ASMS + contrib/masmx64/gvmat64.asm + contrib/masmx64/inffasx64.asm + ) + endif() + + if(ZLIB_ASMS) + add_definitions(-DASMV -DASMINF) + endif() +endif() + +# parse the full version number from zlib.h and include in ZLIB_FULL_VERSION +file(READ ${CMAKE_CURRENT_SOURCE_DIR}/zlib.h _zlib_h_contents) +string(REGEX REPLACE ".*#define[ \t]+ZLIB_VERSION[ \t]+\"([-0-9A-Za-z.]+)\".*" + "\\1" ZLIB_FULL_VERSION ${_zlib_h_contents}) + +if(MINGW) + # This gets us DLL resource information when compiling on MinGW. + if(NOT CMAKE_RC_COMPILER) + set(CMAKE_RC_COMPILER windres.exe) + endif() + + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj + COMMAND ${CMAKE_RC_COMPILER} + -D GCC_WINDRES + -I ${CMAKE_CURRENT_SOURCE_DIR} + -I ${CMAKE_CURRENT_BINARY_DIR} + -o ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj + -i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zlib1.rc) + set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj) +endif(MINGW) + +add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) +add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) +set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL) +set_target_properties(zlib PROPERTIES SOVERSION 1) + +if(NOT CYGWIN) + # This property causes shared libraries on Linux to have the full version + # encoded into their final filename. We disable this on Cygwin because + # it causes cygz-${ZLIB_FULL_VERSION}.dll to be created when cygz.dll + # seems to be the default. + # + # This has no effect with MSVC, on that platform the version info for + # the DLL comes from the resource file win32/zlib1.rc + set_target_properties(zlib PROPERTIES VERSION ${ZLIB_FULL_VERSION}) +endif() + +if(UNIX) + # On unix-like platforms the library is almost always called libz + set_target_properties(zlib zlibstatic PROPERTIES OUTPUT_NAME z) + if(NOT APPLE) + set_target_properties(zlib PROPERTIES LINK_FLAGS "-Wl,--version-script,\"${CMAKE_CURRENT_SOURCE_DIR}/zlib.map\"") + endif() +elseif(BUILD_SHARED_LIBS AND WIN32) + # Creates zlib1.dll when building shared library version + set_target_properties(zlib PROPERTIES SUFFIX "1.dll") +endif() + +if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL ) + install(TARGETS zlib zlibstatic + RUNTIME DESTINATION "${INSTALL_BIN_DIR}" + ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" + LIBRARY DESTINATION "${INSTALL_LIB_DIR}" ) +endif() +if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL ) + install(FILES ${ZLIB_PUBLIC_HDRS} DESTINATION "${INSTALL_INC_DIR}") +endif() +if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) + install(FILES zlib.3 DESTINATION "${INSTALL_MAN_DIR}/man3") +endif() +if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) + install(FILES ${ZLIB_PC} DESTINATION "${INSTALL_PKGCONFIG_DIR}") +endif() + +#============================================================================ +# Example binaries +#============================================================================ + +add_executable(example test/example.c) +target_link_libraries(example zlib) +add_test(example example) + +add_executable(minigzip test/minigzip.c) +target_link_libraries(minigzip zlib) + +if(HAVE_OFF64_T) + add_executable(example64 test/example.c) + target_link_libraries(example64 zlib) + set_target_properties(example64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") + add_test(example64 example64) + + add_executable(minigzip64 test/minigzip.c) + target_link_libraries(minigzip64 zlib) + set_target_properties(minigzip64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") +endif() diff --git a/source/Irrlicht/zlib/ChangeLog b/source/Irrlicht/zlib/ChangeLog new file mode 100644 index 00000000..f22aabae --- /dev/null +++ b/source/Irrlicht/zlib/ChangeLog @@ -0,0 +1,1472 @@ + + ChangeLog file for zlib + +Changes in 1.2.8 (28 Apr 2013) +- Update contrib/minizip/iowin32.c for Windows RT [Vollant] +- Do not force Z_CONST for C++ +- Clean up contrib/vstudio [Ro] +- Correct spelling error in zlib.h +- Fix mixed line endings in contrib/vstudio + +Changes in 1.2.7.3 (13 Apr 2013) +- Fix version numbers and DLL names in contrib/vstudio/*/zlib.rc + +Changes in 1.2.7.2 (13 Apr 2013) +- Change check for a four-byte type back to hexadecimal +- Fix typo in win32/Makefile.msc +- Add casts in gzwrite.c for pointer differences + +Changes in 1.2.7.1 (24 Mar 2013) +- Replace use of unsafe string functions with snprintf if available +- Avoid including stddef.h on Windows for Z_SOLO compile [Niessink] +- Fix gzgetc undefine when Z_PREFIX set [Turk] +- Eliminate use of mktemp in Makefile (not always available) +- Fix bug in 'F' mode for gzopen() +- Add inflateGetDictionary() function +- Correct comment in deflate.h +- Use _snprintf for snprintf in Microsoft C +- On Darwin, only use /usr/bin/libtool if libtool is not Apple +- Delete "--version" file if created by "ar --version" [Richard G.] +- Fix configure check for veracity of compiler error return codes +- Fix CMake compilation of static lib for MSVC2010 x64 +- Remove unused variable in infback9.c +- Fix argument checks in gzlog_compress() and gzlog_write() +- Clean up the usage of z_const and respect const usage within zlib +- Clean up examples/gzlog.[ch] comparisons of different types +- Avoid shift equal to bits in type (caused endless loop) +- Fix unintialized value bug in gzputc() introduced by const patches +- Fix memory allocation error in examples/zran.c [Nor] +- Fix bug where gzopen(), gzclose() would write an empty file +- Fix bug in gzclose() when gzwrite() runs out of memory +- Check for input buffer malloc failure in examples/gzappend.c +- Add note to contrib/blast to use binary mode in stdio +- Fix comparisons of differently signed integers in contrib/blast +- Check for invalid code length codes in contrib/puff +- Fix serious but very rare decompression bug in inftrees.c +- Update inflateBack() comments, since inflate() can be faster +- Use underscored I/O function names for WINAPI_FAMILY +- Add _tr_flush_bits to the external symbols prefixed by --zprefix +- Add contrib/vstudio/vc10 pre-build step for static only +- Quote --version-script argument in CMakeLists.txt +- Don't specify --version-script on Apple platforms in CMakeLists.txt +- Fix casting error in contrib/testzlib/testzlib.c +- Fix types in contrib/minizip to match result of get_crc_table() +- Simplify contrib/vstudio/vc10 with 'd' suffix +- Add TOP support to win32/Makefile.msc +- Suport i686 and amd64 assembler builds in CMakeLists.txt +- Fix typos in the use of _LARGEFILE64_SOURCE in zconf.h +- Add vc11 and vc12 build files to contrib/vstudio +- Add gzvprintf() as an undocumented function in zlib +- Fix configure for Sun shell +- Remove runtime check in configure for four-byte integer type +- Add casts and consts to ease user conversion to C++ +- Add man pages for minizip and miniunzip +- In Makefile uninstall, don't rm if preceding cd fails +- Do not return Z_BUF_ERROR if deflateParam() has nothing to write + +Changes in 1.2.7 (2 May 2012) +- Replace use of memmove() with a simple copy for portability +- Test for existence of strerror +- Restore gzgetc_ for backward compatibility with 1.2.6 +- Fix build with non-GNU make on Solaris +- Require gcc 4.0 or later on Mac OS X to use the hidden attribute +- Include unistd.h for Watcom C +- Use __WATCOMC__ instead of __WATCOM__ +- Do not use the visibility attribute if NO_VIZ defined +- Improve the detection of no hidden visibility attribute +- Avoid using __int64 for gcc or solo compilation +- Cast to char * in gzprintf to avoid warnings [Zinser] +- Fix make_vms.com for VAX [Zinser] +- Don't use library or built-in byte swaps +- Simplify test and use of gcc hidden attribute +- Fix bug in gzclose_w() when gzwrite() fails to allocate memory +- Add "x" (O_EXCL) and "e" (O_CLOEXEC) modes support to gzopen() +- Fix bug in test/minigzip.c for configure --solo +- Fix contrib/vstudio project link errors [Mohanathas] +- Add ability to choose the builder in make_vms.com [Schweda] +- Add DESTDIR support to mingw32 win32/Makefile.gcc +- Fix comments in win32/Makefile.gcc for proper usage +- Allow overriding the default install locations for cmake +- Generate and install the pkg-config file with cmake +- Build both a static and a shared version of zlib with cmake +- Include version symbols for cmake builds +- If using cmake with MSVC, add the source directory to the includes +- Remove unneeded EXTRA_CFLAGS from win32/Makefile.gcc [Truta] +- Move obsolete emx makefile to old [Truta] +- Allow the use of -Wundef when compiling or using zlib +- Avoid the use of the -u option with mktemp +- Improve inflate() documentation on the use of Z_FINISH +- Recognize clang as gcc +- Add gzopen_w() in Windows for wide character path names +- Rename zconf.h in CMakeLists.txt to move it out of the way +- Add source directory in CMakeLists.txt for building examples +- Look in build directory for zlib.pc in CMakeLists.txt +- Remove gzflags from zlibvc.def in vc9 and vc10 +- Fix contrib/minizip compilation in the MinGW environment +- Update ./configure for Solaris, support --64 [Mooney] +- Remove -R. from Solaris shared build (possible security issue) +- Avoid race condition for parallel make (-j) running example +- Fix type mismatch between get_crc_table() and crc_table +- Fix parsing of version with "-" in CMakeLists.txt [Snider, Ziegler] +- Fix the path to zlib.map in CMakeLists.txt +- Force the native libtool in Mac OS X to avoid GNU libtool [Beebe] +- Add instructions to win32/Makefile.gcc for shared install [Torri] + +Changes in 1.2.6.1 (12 Feb 2012) +- Avoid the use of the Objective-C reserved name "id" +- Include io.h in gzguts.h for Microsoft compilers +- Fix problem with ./configure --prefix and gzgetc macro +- Include gz_header definition when compiling zlib solo +- Put gzflags() functionality back in zutil.c +- Avoid library header include in crc32.c for Z_SOLO +- Use name in GCC_CLASSIC as C compiler for coverage testing, if set +- Minor cleanup in contrib/minizip/zip.c [Vollant] +- Update make_vms.com [Zinser] +- Remove unnecessary gzgetc_ function +- Use optimized byte swap operations for Microsoft and GNU [Snyder] +- Fix minor typo in zlib.h comments [Rzesniowiecki] + +Changes in 1.2.6 (29 Jan 2012) +- Update the Pascal interface in contrib/pascal +- Fix function numbers for gzgetc_ in zlibvc.def files +- Fix configure.ac for contrib/minizip [Schiffer] +- Fix large-entry detection in minizip on 64-bit systems [Schiffer] +- Have ./configure use the compiler return code for error indication +- Fix CMakeLists.txt for cross compilation [McClure] +- Fix contrib/minizip/zip.c for 64-bit architectures [Dalsnes] +- Fix compilation of contrib/minizip on FreeBSD [Marquez] +- Correct suggested usages in win32/Makefile.msc [Shachar, Horvath] +- Include io.h for Turbo C / Borland C on all platforms [Truta] +- Make version explicit in contrib/minizip/configure.ac [Bosmans] +- Avoid warning for no encryption in contrib/minizip/zip.c [Vollant] +- Minor cleanup up contrib/minizip/unzip.c [Vollant] +- Fix bug when compiling minizip with C++ [Vollant] +- Protect for long name and extra fields in contrib/minizip [Vollant] +- Avoid some warnings in contrib/minizip [Vollant] +- Add -I../.. -L../.. to CFLAGS for minizip and miniunzip +- Add missing libs to minizip linker command +- Add support for VPATH builds in contrib/minizip +- Add an --enable-demos option to contrib/minizip/configure +- Add the generation of configure.log by ./configure +- Exit when required parameters not provided to win32/Makefile.gcc +- Have gzputc return the character written instead of the argument +- Use the -m option on ldconfig for BSD systems [Tobias] +- Correct in zlib.map when deflateResetKeep was added + +Changes in 1.2.5.3 (15 Jan 2012) +- Restore gzgetc function for binary compatibility +- Do not use _lseeki64 under Borland C++ [Truta] +- Update win32/Makefile.msc to build test/*.c [Truta] +- Remove old/visualc6 given CMakefile and other alternatives +- Update AS400 build files and documentation [Monnerat] +- Update win32/Makefile.gcc to build test/*.c [Truta] +- Permit stronger flushes after Z_BLOCK flushes +- Avoid extraneous empty blocks when doing empty flushes +- Permit Z_NULL arguments to deflatePending +- Allow deflatePrime() to insert bits in the middle of a stream +- Remove second empty static block for Z_PARTIAL_FLUSH +- Write out all of the available bits when using Z_BLOCK +- Insert the first two strings in the hash table after a flush + +Changes in 1.2.5.2 (17 Dec 2011) +- fix ld error: unable to find version dependency 'ZLIB_1.2.5' +- use relative symlinks for shared libs +- Avoid searching past window for Z_RLE strategy +- Assure that high-water mark initialization is always applied in deflate +- Add assertions to fill_window() in deflate.c to match comments +- Update python link in README +- Correct spelling error in gzread.c +- Fix bug in gzgets() for a concatenated empty gzip stream +- Correct error in comment for gz_make() +- Change gzread() and related to ignore junk after gzip streams +- Allow gzread() and related to continue after gzclearerr() +- Allow gzrewind() and gzseek() after a premature end-of-file +- Simplify gzseek() now that raw after gzip is ignored +- Change gzgetc() to a macro for speed (~40% speedup in testing) +- Fix gzclose() to return the actual error last encountered +- Always add large file support for windows +- Include zconf.h for windows large file support +- Include zconf.h.cmakein for windows large file support +- Update zconf.h.cmakein on make distclean +- Merge vestigial vsnprintf determination from zutil.h to gzguts.h +- Clarify how gzopen() appends in zlib.h comments +- Correct documentation of gzdirect() since junk at end now ignored +- Add a transparent write mode to gzopen() when 'T' is in the mode +- Update python link in zlib man page +- Get inffixed.h and MAKEFIXED result to match +- Add a ./config --solo option to make zlib subset with no libary use +- Add undocumented inflateResetKeep() function for CAB file decoding +- Add --cover option to ./configure for gcc coverage testing +- Add #define ZLIB_CONST option to use const in the z_stream interface +- Add comment to gzdopen() in zlib.h to use dup() when using fileno() +- Note behavior of uncompress() to provide as much data as it can +- Add files in contrib/minizip to aid in building libminizip +- Split off AR options in Makefile.in and configure +- Change ON macro to Z_ARG to avoid application conflicts +- Facilitate compilation with Borland C++ for pragmas and vsnprintf +- Include io.h for Turbo C / Borland C++ +- Move example.c and minigzip.c to test/ +- Simplify incomplete code table filling in inflate_table() +- Remove code from inflate.c and infback.c that is impossible to execute +- Test the inflate code with full coverage +- Allow deflateSetDictionary, inflateSetDictionary at any time (in raw) +- Add deflateResetKeep and fix inflateResetKeep to retain dictionary +- Fix gzwrite.c to accommodate reduced memory zlib compilation +- Have inflate() with Z_FINISH avoid the allocation of a window +- Do not set strm->adler when doing raw inflate +- Fix gzeof() to behave just like feof() when read is not past end of file +- Fix bug in gzread.c when end-of-file is reached +- Avoid use of Z_BUF_ERROR in gz* functions except for premature EOF +- Document gzread() capability to read concurrently written files +- Remove hard-coding of resource compiler in CMakeLists.txt [Blammo] + +Changes in 1.2.5.1 (10 Sep 2011) +- Update FAQ entry on shared builds (#13) +- Avoid symbolic argument to chmod in Makefile.in +- Fix bug and add consts in contrib/puff [Oberhumer] +- Update contrib/puff/zeros.raw test file to have all block types +- Add full coverage test for puff in contrib/puff/Makefile +- Fix static-only-build install in Makefile.in +- Fix bug in unzGetCurrentFileInfo() in contrib/minizip [Kuno] +- Add libz.a dependency to shared in Makefile.in for parallel builds +- Spell out "number" (instead of "nb") in zlib.h for total_in, total_out +- Replace $(...) with `...` in configure for non-bash sh [Bowler] +- Add darwin* to Darwin* and solaris* to SunOS\ 5* in configure [Groffen] +- Add solaris* to Linux* in configure to allow gcc use [Groffen] +- Add *bsd* to Linux* case in configure [Bar-Lev] +- Add inffast.obj to dependencies in win32/Makefile.msc +- Correct spelling error in deflate.h [Kohler] +- Change libzdll.a again to libz.dll.a (!) in win32/Makefile.gcc +- Add test to configure for GNU C looking for gcc in output of $cc -v +- Add zlib.pc generation to win32/Makefile.gcc [Weigelt] +- Fix bug in zlib.h for _FILE_OFFSET_BITS set and _LARGEFILE64_SOURCE not +- Add comment in zlib.h that adler32_combine with len2 < 0 makes no sense +- Make NO_DIVIDE option in adler32.c much faster (thanks to John Reiser) +- Make stronger test in zconf.h to include unistd.h for LFS +- Apply Darwin patches for 64-bit file offsets to contrib/minizip [Slack] +- Fix zlib.h LFS support when Z_PREFIX used +- Add updated as400 support (removed from old) [Monnerat] +- Avoid deflate sensitivity to volatile input data +- Avoid division in adler32_combine for NO_DIVIDE +- Clarify the use of Z_FINISH with deflateBound() amount of space +- Set binary for output file in puff.c +- Use u4 type for crc_table to avoid conversion warnings +- Apply casts in zlib.h to avoid conversion warnings +- Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller] +- Improve inflateSync() documentation to note indeterminancy +- Add deflatePending() function to return the amount of pending output +- Correct the spelling of "specification" in FAQ [Randers-Pehrson] +- Add a check in configure for stdarg.h, use for gzprintf() +- Check that pointers fit in ints when gzprint() compiled old style +- Add dummy name before $(SHAREDLIBV) in Makefile [Bar-Lev, Bowler] +- Delete line in configure that adds -L. libz.a to LDFLAGS [Weigelt] +- Add debug records in assmebler code [Londer] +- Update RFC references to use http://tools.ietf.org/html/... [Li] +- Add --archs option, use of libtool to configure for Mac OS X [Borstel] + +Changes in 1.2.5 (19 Apr 2010) +- Disable visibility attribute in win32/Makefile.gcc [Bar-Lev] +- Default to libdir as sharedlibdir in configure [Nieder] +- Update copyright dates on modified source files +- Update trees.c to be able to generate modified trees.h +- Exit configure for MinGW, suggesting win32/Makefile.gcc +- Check for NULL path in gz_open [Homurlu] + +Changes in 1.2.4.5 (18 Apr 2010) +- Set sharedlibdir in configure [Torok] +- Set LDFLAGS in Makefile.in [Bar-Lev] +- Avoid mkdir objs race condition in Makefile.in [Bowler] +- Add ZLIB_INTERNAL in front of internal inter-module functions and arrays +- Define ZLIB_INTERNAL to hide internal functions and arrays for GNU C +- Don't use hidden attribute when it is a warning generator (e.g. Solaris) + +Changes in 1.2.4.4 (18 Apr 2010) +- Fix CROSS_PREFIX executable testing, CHOST extract, mingw* [Torok] +- Undefine _LARGEFILE64_SOURCE in zconf.h if it is zero, but not if empty +- Try to use bash or ksh regardless of functionality of /bin/sh +- Fix configure incompatibility with NetBSD sh +- Remove attempt to run under bash or ksh since have better NetBSD fix +- Fix win32/Makefile.gcc for MinGW [Bar-Lev] +- Add diagnostic messages when using CROSS_PREFIX in configure +- Added --sharedlibdir option to configure [Weigelt] +- Use hidden visibility attribute when available [Frysinger] + +Changes in 1.2.4.3 (10 Apr 2010) +- Only use CROSS_PREFIX in configure for ar and ranlib if they exist +- Use CROSS_PREFIX for nm [Bar-Lev] +- Assume _LARGEFILE64_SOURCE defined is equivalent to true +- Avoid use of undefined symbols in #if with && and || +- Make *64 prototypes in gzguts.h consistent with functions +- Add -shared load option for MinGW in configure [Bowler] +- Move z_off64_t to public interface, use instead of off64_t +- Remove ! from shell test in configure (not portable to Solaris) +- Change +0 macro tests to -0 for possibly increased portability + +Changes in 1.2.4.2 (9 Apr 2010) +- Add consistent carriage returns to readme.txt's in masmx86 and masmx64 +- Really provide prototypes for *64 functions when building without LFS +- Only define unlink() in minigzip.c if unistd.h not included +- Update README to point to contrib/vstudio project files +- Move projects/vc6 to old/ and remove projects/ +- Include stdlib.h in minigzip.c for setmode() definition under WinCE +- Clean up assembler builds in win32/Makefile.msc [Rowe] +- Include sys/types.h for Microsoft for off_t definition +- Fix memory leak on error in gz_open() +- Symbolize nm as $NM in configure [Weigelt] +- Use TEST_LDSHARED instead of LDSHARED to link test programs [Weigelt] +- Add +0 to _FILE_OFFSET_BITS and _LFS64_LARGEFILE in case not defined +- Fix bug in gzeof() to take into account unused input data +- Avoid initialization of structures with variables in puff.c +- Updated win32/README-WIN32.txt [Rowe] + +Changes in 1.2.4.1 (28 Mar 2010) +- Remove the use of [a-z] constructs for sed in configure [gentoo 310225] +- Remove $(SHAREDLIB) from LIBS in Makefile.in [Creech] +- Restore "for debugging" comment on sprintf() in gzlib.c +- Remove fdopen for MVS from gzguts.h +- Put new README-WIN32.txt in win32 [Rowe] +- Add check for shell to configure and invoke another shell if needed +- Fix big fat stinking bug in gzseek() on uncompressed files +- Remove vestigial F_OPEN64 define in zutil.h +- Set and check the value of _LARGEFILE_SOURCE and _LARGEFILE64_SOURCE +- Avoid errors on non-LFS systems when applications define LFS macros +- Set EXE to ".exe" in configure for MINGW [Kahle] +- Match crc32() in crc32.c exactly to the prototype in zlib.h [Sherrill] +- Add prefix for cross-compilation in win32/makefile.gcc [Bar-Lev] +- Add DLL install in win32/makefile.gcc [Bar-Lev] +- Allow Linux* or linux* from uname in configure [Bar-Lev] +- Allow ldconfig to be redefined in configure and Makefile.in [Bar-Lev] +- Add cross-compilation prefixes to configure [Bar-Lev] +- Match type exactly in gz_load() invocation in gzread.c +- Match type exactly of zcalloc() in zutil.c to zlib.h alloc_func +- Provide prototypes for *64 functions when building zlib without LFS +- Don't use -lc when linking shared library on MinGW +- Remove errno.h check in configure and vestigial errno code in zutil.h + +Changes in 1.2.4 (14 Mar 2010) +- Fix VER3 extraction in configure for no fourth subversion +- Update zlib.3, add docs to Makefile.in to make .pdf out of it +- Add zlib.3.pdf to distribution +- Don't set error code in gzerror() if passed pointer is NULL +- Apply destination directory fixes to CMakeLists.txt [Lowman] +- Move #cmakedefine's to a new zconf.in.cmakein +- Restore zconf.h for builds that don't use configure or cmake +- Add distclean to dummy Makefile for convenience +- Update and improve INDEX, README, and FAQ +- Update CMakeLists.txt for the return of zconf.h [Lowman] +- Update contrib/vstudio/vc9 and vc10 [Vollant] +- Change libz.dll.a back to libzdll.a in win32/Makefile.gcc +- Apply license and readme changes to contrib/asm686 [Raiter] +- Check file name lengths and add -c option in minigzip.c [Li] +- Update contrib/amd64 and contrib/masmx86/ [Vollant] +- Avoid use of "eof" parameter in trees.c to not shadow library variable +- Update make_vms.com for removal of zlibdefs.h [Zinser] +- Update assembler code and vstudio projects in contrib [Vollant] +- Remove outdated assembler code contrib/masm686 and contrib/asm586 +- Remove old vc7 and vc8 from contrib/vstudio +- Update win32/Makefile.msc, add ZLIB_VER_SUBREVISION [Rowe] +- Fix memory leaks in gzclose_r() and gzclose_w(), file leak in gz_open() +- Add contrib/gcc_gvmat64 for longest_match and inflate_fast [Vollant] +- Remove *64 functions from win32/zlib.def (they're not 64-bit yet) +- Fix bug in void-returning vsprintf() case in gzwrite.c +- Fix name change from inflate.h in contrib/inflate86/inffas86.c +- Check if temporary file exists before removing in make_vms.com [Zinser] +- Fix make install and uninstall for --static option +- Fix usage of _MSC_VER in gzguts.h and zutil.h [Truta] +- Update readme.txt in contrib/masmx64 and masmx86 to assemble + +Changes in 1.2.3.9 (21 Feb 2010) +- Expunge gzio.c +- Move as400 build information to old +- Fix updates in contrib/minizip and contrib/vstudio +- Add const to vsnprintf test in configure to avoid warnings [Weigelt] +- Delete zconf.h (made by configure) [Weigelt] +- Change zconf.in.h to zconf.h.in per convention [Weigelt] +- Check for NULL buf in gzgets() +- Return empty string for gzgets() with len == 1 (like fgets()) +- Fix description of gzgets() in zlib.h for end-of-file, NULL return +- Update minizip to 1.1 [Vollant] +- Avoid MSVC loss of data warnings in gzread.c, gzwrite.c +- Note in zlib.h that gzerror() should be used to distinguish from EOF +- Remove use of snprintf() from gzlib.c +- Fix bug in gzseek() +- Update contrib/vstudio, adding vc9 and vc10 [Kuno, Vollant] +- Fix zconf.h generation in CMakeLists.txt [Lowman] +- Improve comments in zconf.h where modified by configure + +Changes in 1.2.3.8 (13 Feb 2010) +- Clean up text files (tabs, trailing whitespace, etc.) [Oberhumer] +- Use z_off64_t in gz_zero() and gz_skip() to match state->skip +- Avoid comparison problem when sizeof(int) == sizeof(z_off64_t) +- Revert to Makefile.in from 1.2.3.6 (live with the clutter) +- Fix missing error return in gzflush(), add zlib.h note +- Add *64 functions to zlib.map [Levin] +- Fix signed/unsigned comparison in gz_comp() +- Use SFLAGS when testing shared linking in configure +- Add --64 option to ./configure to use -m64 with gcc +- Fix ./configure --help to correctly name options +- Have make fail if a test fails [Levin] +- Avoid buffer overrun in contrib/masmx64/gvmat64.asm [Simpson] +- Remove assembler object files from contrib + +Changes in 1.2.3.7 (24 Jan 2010) +- Always gzopen() with O_LARGEFILE if available +- Fix gzdirect() to work immediately after gzopen() or gzdopen() +- Make gzdirect() more precise when the state changes while reading +- Improve zlib.h documentation in many places +- Catch memory allocation failure in gz_open() +- Complete close operation if seek forward in gzclose_w() fails +- Return Z_ERRNO from gzclose_r() if close() fails +- Return Z_STREAM_ERROR instead of EOF for gzclose() being passed NULL +- Return zero for gzwrite() errors to match zlib.h description +- Return -1 on gzputs() error to match zlib.h description +- Add zconf.in.h to allow recovery from configure modification [Weigelt] +- Fix static library permissions in Makefile.in [Weigelt] +- Avoid warnings in configure tests that hide functionality [Weigelt] +- Add *BSD and DragonFly to Linux case in configure [gentoo 123571] +- Change libzdll.a to libz.dll.a in win32/Makefile.gcc [gentoo 288212] +- Avoid access of uninitialized data for first inflateReset2 call [Gomes] +- Keep object files in subdirectories to reduce the clutter somewhat +- Remove default Makefile and zlibdefs.h, add dummy Makefile +- Add new external functions to Z_PREFIX, remove duplicates, z_z_ -> z_ +- Remove zlibdefs.h completely -- modify zconf.h instead + +Changes in 1.2.3.6 (17 Jan 2010) +- Avoid void * arithmetic in gzread.c and gzwrite.c +- Make compilers happier with const char * for gz_error message +- Avoid unused parameter warning in inflate.c +- Avoid signed-unsigned comparison warning in inflate.c +- Indent #pragma's for traditional C +- Fix usage of strwinerror() in glib.c, change to gz_strwinerror() +- Correct email address in configure for system options +- Update make_vms.com and add make_vms.com to contrib/minizip [Zinser] +- Update zlib.map [Brown] +- Fix Makefile.in for Solaris 10 make of example64 and minizip64 [Torok] +- Apply various fixes to CMakeLists.txt [Lowman] +- Add checks on len in gzread() and gzwrite() +- Add error message for no more room for gzungetc() +- Remove zlib version check in gzwrite() +- Defer compression of gzprintf() result until need to +- Use snprintf() in gzdopen() if available +- Remove USE_MMAP configuration determination (only used by minigzip) +- Remove examples/pigz.c (available separately) +- Update examples/gun.c to 1.6 + +Changes in 1.2.3.5 (8 Jan 2010) +- Add space after #if in zutil.h for some compilers +- Fix relatively harmless bug in deflate_fast() [Exarevsky] +- Fix same problem in deflate_slow() +- Add $(SHAREDLIBV) to LIBS in Makefile.in [Brown] +- Add deflate_rle() for faster Z_RLE strategy run-length encoding +- Add deflate_huff() for faster Z_HUFFMAN_ONLY encoding +- Change name of "write" variable in inffast.c to avoid library collisions +- Fix premature EOF from gzread() in gzio.c [Brown] +- Use zlib header window size if windowBits is 0 in inflateInit2() +- Remove compressBound() call in deflate.c to avoid linking compress.o +- Replace use of errno in gz* with functions, support WinCE [Alves] +- Provide alternative to perror() in minigzip.c for WinCE [Alves] +- Don't use _vsnprintf on later versions of MSVC [Lowman] +- Add CMake build script and input file [Lowman] +- Update contrib/minizip to 1.1 [Svensson, Vollant] +- Moved nintendods directory from contrib to . +- Replace gzio.c with a new set of routines with the same functionality +- Add gzbuffer(), gzoffset(), gzclose_r(), gzclose_w() as part of above +- Update contrib/minizip to 1.1b +- Change gzeof() to return 0 on error instead of -1 to agree with zlib.h + +Changes in 1.2.3.4 (21 Dec 2009) +- Use old school .SUFFIXES in Makefile.in for FreeBSD compatibility +- Update comments in configure and Makefile.in for default --shared +- Fix test -z's in configure [Marquess] +- Build examplesh and minigzipsh when not testing +- Change NULL's to Z_NULL's in deflate.c and in comments in zlib.h +- Import LDFLAGS from the environment in configure +- Fix configure to populate SFLAGS with discovered CFLAGS options +- Adapt make_vms.com to the new Makefile.in [Zinser] +- Add zlib2ansi script for C++ compilation [Marquess] +- Add _FILE_OFFSET_BITS=64 test to make test (when applicable) +- Add AMD64 assembler code for longest match to contrib [Teterin] +- Include options from $SFLAGS when doing $LDSHARED +- Simplify 64-bit file support by introducing z_off64_t type +- Make shared object files in objs directory to work around old Sun cc +- Use only three-part version number for Darwin shared compiles +- Add rc option to ar in Makefile.in for when ./configure not run +- Add -WI,-rpath,. to LDFLAGS for OSF 1 V4* +- Set LD_LIBRARYN32_PATH for SGI IRIX shared compile +- Protect against _FILE_OFFSET_BITS being defined when compiling zlib +- Rename Makefile.in targets allstatic to static and allshared to shared +- Fix static and shared Makefile.in targets to be independent +- Correct error return bug in gz_open() by setting state [Brown] +- Put spaces before ;;'s in configure for better sh compatibility +- Add pigz.c (parallel implementation of gzip) to examples/ +- Correct constant in crc32.c to UL [Leventhal] +- Reject negative lengths in crc32_combine() +- Add inflateReset2() function to work like inflateEnd()/inflateInit2() +- Include sys/types.h for _LARGEFILE64_SOURCE [Brown] +- Correct typo in doc/algorithm.txt [Janik] +- Fix bug in adler32_combine() [Zhu] +- Catch missing-end-of-block-code error in all inflates and in puff + Assures that random input to inflate eventually results in an error +- Added enough.c (calculation of ENOUGH for inftrees.h) to examples/ +- Update ENOUGH and its usage to reflect discovered bounds +- Fix gzerror() error report on empty input file [Brown] +- Add ush casts in trees.c to avoid pedantic runtime errors +- Fix typo in zlib.h uncompress() description [Reiss] +- Correct inflate() comments with regard to automatic header detection +- Remove deprecation comment on Z_PARTIAL_FLUSH (it stays) +- Put new version of gzlog (2.0) in examples with interruption recovery +- Add puff compile option to permit invalid distance-too-far streams +- Add puff TEST command options, ability to read piped input +- Prototype the *64 functions in zlib.h when _FILE_OFFSET_BITS == 64, but + _LARGEFILE64_SOURCE not defined +- Fix Z_FULL_FLUSH to truly erase the past by resetting s->strstart +- Fix deflateSetDictionary() to use all 32K for output consistency +- Remove extraneous #define MIN_LOOKAHEAD in deflate.c (in deflate.h) +- Clear bytes after deflate lookahead to avoid use of uninitialized data +- Change a limit in inftrees.c to be more transparent to Coverity Prevent +- Update win32/zlib.def with exported symbols from zlib.h +- Correct spelling errors in zlib.h [Willem, Sobrado] +- Allow Z_BLOCK for deflate() to force a new block +- Allow negative bits in inflatePrime() to delete existing bit buffer +- Add Z_TREES flush option to inflate() to return at end of trees +- Add inflateMark() to return current state information for random access +- Add Makefile for NintendoDS to contrib [Costa] +- Add -w in configure compile tests to avoid spurious warnings [Beucler] +- Fix typos in zlib.h comments for deflateSetDictionary() +- Fix EOF detection in transparent gzread() [Maier] + +Changes in 1.2.3.3 (2 October 2006) +- Make --shared the default for configure, add a --static option +- Add compile option to permit invalid distance-too-far streams +- Add inflateUndermine() function which is required to enable above +- Remove use of "this" variable name for C++ compatibility [Marquess] +- Add testing of shared library in make test, if shared library built +- Use ftello() and fseeko() if available instead of ftell() and fseek() +- Provide two versions of all functions that use the z_off_t type for + binary compatibility -- a normal version and a 64-bit offset version, + per the Large File Support Extension when _LARGEFILE64_SOURCE is + defined; use the 64-bit versions by default when _FILE_OFFSET_BITS + is defined to be 64 +- Add a --uname= option to configure to perhaps help with cross-compiling + +Changes in 1.2.3.2 (3 September 2006) +- Turn off silly Borland warnings [Hay] +- Use off64_t and define _LARGEFILE64_SOURCE when present +- Fix missing dependency on inffixed.h in Makefile.in +- Rig configure --shared to build both shared and static [Teredesai, Truta] +- Remove zconf.in.h and instead create a new zlibdefs.h file +- Fix contrib/minizip/unzip.c non-encrypted after encrypted [Vollant] +- Add treebuild.xml (see http://treebuild.metux.de/) [Weigelt] + +Changes in 1.2.3.1 (16 August 2006) +- Add watcom directory with OpenWatcom make files [Daniel] +- Remove #undef of FAR in zconf.in.h for MVS [Fedtke] +- Update make_vms.com [Zinser] +- Use -fPIC for shared build in configure [Teredesai, Nicholson] +- Use only major version number for libz.so on IRIX and OSF1 [Reinholdtsen] +- Use fdopen() (not _fdopen()) for Interix in zutil.h [Bck] +- Add some FAQ entries about the contrib directory +- Update the MVS question in the FAQ +- Avoid extraneous reads after EOF in gzio.c [Brown] +- Correct spelling of "successfully" in gzio.c [Randers-Pehrson] +- Add comments to zlib.h about gzerror() usage [Brown] +- Set extra flags in gzip header in gzopen() like deflate() does +- Make configure options more compatible with double-dash conventions + [Weigelt] +- Clean up compilation under Solaris SunStudio cc [Rowe, Reinholdtsen] +- Fix uninstall target in Makefile.in [Truta] +- Add pkgconfig support [Weigelt] +- Use $(DESTDIR) macro in Makefile.in [Reinholdtsen, Weigelt] +- Replace set_data_type() with a more accurate detect_data_type() in + trees.c, according to the txtvsbin.txt document [Truta] +- Swap the order of #include and #include "zlib.h" in + gzio.c, example.c and minigzip.c [Truta] +- Shut up annoying VS2005 warnings about standard C deprecation [Rowe, + Truta] (where?) +- Fix target "clean" from win32/Makefile.bor [Truta] +- Create .pdb and .manifest files in win32/makefile.msc [Ziegler, Rowe] +- Update zlib www home address in win32/DLL_FAQ.txt [Truta] +- Update contrib/masmx86/inffas32.asm for VS2005 [Vollant, Van Wassenhove] +- Enable browse info in the "Debug" and "ASM Debug" configurations in + the Visual C++ 6 project, and set (non-ASM) "Debug" as default [Truta] +- Add pkgconfig support [Weigelt] +- Add ZLIB_VER_MAJOR, ZLIB_VER_MINOR and ZLIB_VER_REVISION in zlib.h, + for use in win32/zlib1.rc [Polushin, Rowe, Truta] +- Add a document that explains the new text detection scheme to + doc/txtvsbin.txt [Truta] +- Add rfc1950.txt, rfc1951.txt and rfc1952.txt to doc/ [Truta] +- Move algorithm.txt into doc/ [Truta] +- Synchronize FAQ with website +- Fix compressBound(), was low for some pathological cases [Fearnley] +- Take into account wrapper variations in deflateBound() +- Set examples/zpipe.c input and output to binary mode for Windows +- Update examples/zlib_how.html with new zpipe.c (also web site) +- Fix some warnings in examples/gzlog.c and examples/zran.c (it seems + that gcc became pickier in 4.0) +- Add zlib.map for Linux: "All symbols from zlib-1.1.4 remain + un-versioned, the patch adds versioning only for symbols introduced in + zlib-1.2.0 or later. It also declares as local those symbols which are + not designed to be exported." [Levin] +- Update Z_PREFIX list in zconf.in.h, add --zprefix option to configure +- Do not initialize global static by default in trees.c, add a response + NO_INIT_GLOBAL_POINTERS to initialize them if needed [Marquess] +- Don't use strerror() in gzio.c under WinCE [Yakimov] +- Don't use errno.h in zutil.h under WinCE [Yakimov] +- Move arguments for AR to its usage to allow replacing ar [Marot] +- Add HAVE_VISIBILITY_PRAGMA in zconf.in.h for Mozilla [Randers-Pehrson] +- Improve inflateInit() and inflateInit2() documentation +- Fix structure size comment in inflate.h +- Change configure help option from --h* to --help [Santos] + +Changes in 1.2.3 (18 July 2005) +- Apply security vulnerability fixes to contrib/infback9 as well +- Clean up some text files (carriage returns, trailing space) +- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant] + +Changes in 1.2.2.4 (11 July 2005) +- Add inflatePrime() function for starting inflation at bit boundary +- Avoid some Visual C warnings in deflate.c +- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit + compile +- Fix some spelling errors in comments [Betts] +- Correct inflateInit2() error return documentation in zlib.h +- Add zran.c example of compressed data random access to examples + directory, shows use of inflatePrime() +- Fix cast for assignments to strm->state in inflate.c and infback.c +- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer] +- Move declarations of gf2 functions to right place in crc32.c [Oberhumer] +- Add cast in trees.c t avoid a warning [Oberhumer] +- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer] +- Update make_vms.com [Zinser] +- Initialize state->write in inflateReset() since copied in inflate_fast() +- Be more strict on incomplete code sets in inflate_table() and increase + ENOUGH and MAXD -- this repairs a possible security vulnerability for + invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for + discovering the vulnerability and providing test cases. +- Add ia64 support to configure for HP-UX [Smith] +- Add error return to gzread() for format or i/o error [Levin] +- Use malloc.h for OS/2 [Necasek] + +Changes in 1.2.2.3 (27 May 2005) +- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile +- Typecast fread() return values in gzio.c [Vollant] +- Remove trailing space in minigzip.c outmode (VC++ can't deal with it) +- Fix crc check bug in gzread() after gzungetc() [Heiner] +- Add the deflateTune() function to adjust internal compression parameters +- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack) +- Remove an incorrect assertion in examples/zpipe.c +- Add C++ wrapper in infback9.h [Donais] +- Fix bug in inflateCopy() when decoding fixed codes +- Note in zlib.h how much deflateSetDictionary() actually uses +- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used) +- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer] +- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer] +- Add gzdirect() function to indicate transparent reads +- Update contrib/minizip [Vollant] +- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer] +- Add casts in crc32.c to avoid warnings [Oberhumer] +- Add contrib/masmx64 [Vollant] +- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant] + +Changes in 1.2.2.2 (30 December 2004) +- Replace structure assignments in deflate.c and inflate.c with zmemcpy to + avoid implicit memcpy calls (portability for no-library compilation) +- Increase sprintf() buffer size in gzdopen() to allow for large numbers +- Add INFLATE_STRICT to check distances against zlib header +- Improve WinCE errno handling and comments [Chang] +- Remove comment about no gzip header processing in FAQ +- Add Z_FIXED strategy option to deflateInit2() to force fixed trees +- Add updated make_vms.com [Coghlan], update README +- Create a new "examples" directory, move gzappend.c there, add zpipe.c, + fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html. +- Add FAQ entry and comments in deflate.c on uninitialized memory access +- Add Solaris 9 make options in configure [Gilbert] +- Allow strerror() usage in gzio.c for STDC +- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer] +- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant] +- Use z_off_t for adler32_combine() and crc32_combine() lengths +- Make adler32() much faster for small len +- Use OS_CODE in deflate() default gzip header + +Changes in 1.2.2.1 (31 October 2004) +- Allow inflateSetDictionary() call for raw inflate +- Fix inflate header crc check bug for file names and comments +- Add deflateSetHeader() and gz_header structure for custom gzip headers +- Add inflateGetheader() to retrieve gzip headers +- Add crc32_combine() and adler32_combine() functions +- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list +- Use zstreamp consistently in zlib.h (inflate_back functions) +- Remove GUNZIP condition from definition of inflate_mode in inflate.h + and in contrib/inflate86/inffast.S [Truta, Anderson] +- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson] +- Update projects/README.projects and projects/visualc6 [Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta] +- Deprecate Z_ASCII; use Z_TEXT instead [Truta] +- Use a new algorithm for setting strm->data_type in trees.c [Truta] +- Do not define an exit() prototype in zutil.c unless DEBUG defined +- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta] +- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate() +- Fix Darwin build version identification [Peterson] + +Changes in 1.2.2 (3 October 2004) +- Update zlib.h comments on gzip in-memory processing +- Set adler to 1 in inflateReset() to support Java test suite [Walles] +- Add contrib/dotzlib [Ravn] +- Update win32/DLL_FAQ.txt [Truta] +- Update contrib/minizip [Vollant] +- Move contrib/visual-basic.txt to old/ [Truta] +- Fix assembler builds in projects/visualc6/ [Truta] + +Changes in 1.2.1.2 (9 September 2004) +- Update INDEX file +- Fix trees.c to update strm->data_type (no one ever noticed!) +- Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown] +- Add "volatile" to crc table flag declaration (for DYNAMIC_CRC_TABLE) +- Add limited multitasking protection to DYNAMIC_CRC_TABLE +- Add NO_vsnprintf for VMS in zutil.h [Mozilla] +- Don't declare strerror() under VMS [Mozilla] +- Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize +- Update contrib/ada [Anisimkov] +- Update contrib/minizip [Vollant] +- Fix configure to not hardcode directories for Darwin [Peterson] +- Fix gzio.c to not return error on empty files [Brown] +- Fix indentation; update version in contrib/delphi/ZLib.pas and + contrib/pascal/zlibpas.pas [Truta] +- Update mkasm.bat in contrib/masmx86 [Truta] +- Update contrib/untgz [Truta] +- Add projects/README.projects [Truta] +- Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta] +- Remove an unnecessary assignment to curr in inftrees.c [Truta] +- Add OS/2 to exe builds in configure [Poltorak] +- Remove err dummy parameter in zlib.h [Kientzle] + +Changes in 1.2.1.1 (9 January 2004) +- Update email address in README +- Several FAQ updates +- Fix a big fat bug in inftrees.c that prevented decoding valid + dynamic blocks with only literals and no distance codes -- + Thanks to "Hot Emu" for the bug report and sample file +- Add a note to puff.c on no distance codes case. + +Changes in 1.2.1 (17 November 2003) +- Remove a tab in contrib/gzappend/gzappend.c +- Update some interfaces in contrib for new zlib functions +- Update zlib version number in some contrib entries +- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta] +- Support shared libraries on Hurd and KFreeBSD [Brown] +- Fix error in NO_DIVIDE option of adler32.c + +Changes in 1.2.0.8 (4 November 2003) +- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas +- Add experimental NO_DIVIDE #define in adler32.c + - Possibly faster on some processors (let me know if it is) +- Correct Z_BLOCK to not return on first inflate call if no wrap +- Fix strm->data_type on inflate() return to correctly indicate EOB +- Add deflatePrime() function for appending in the middle of a byte +- Add contrib/gzappend for an example of appending to a stream +- Update win32/DLL_FAQ.txt [Truta] +- Delete Turbo C comment in README [Truta] +- Improve some indentation in zconf.h [Truta] +- Fix infinite loop on bad input in configure script [Church] +- Fix gzeof() for concatenated gzip files [Johnson] +- Add example to contrib/visual-basic.txt [Michael B.] +- Add -p to mkdir's in Makefile.in [vda] +- Fix configure to properly detect presence or lack of printf functions +- Add AS400 support [Monnerat] +- Add a little Cygwin support [Wilson] + +Changes in 1.2.0.7 (21 September 2003) +- Correct some debug formats in contrib/infback9 +- Cast a type in a debug statement in trees.c +- Change search and replace delimiter in configure from % to # [Beebe] +- Update contrib/untgz to 0.2 with various fixes [Truta] +- Add build support for Amiga [Nikl] +- Remove some directories in old that have been updated to 1.2 +- Add dylib building for Mac OS X in configure and Makefile.in +- Remove old distribution stuff from Makefile +- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X +- Update links in README + +Changes in 1.2.0.6 (13 September 2003) +- Minor FAQ updates +- Update contrib/minizip to 1.00 [Vollant] +- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta] +- Update POSTINC comment for 68060 [Nikl] +- Add contrib/infback9 with deflate64 decoding (unsupported) +- For MVS define NO_vsnprintf and undefine FAR [van Burik] +- Add pragma for fdopen on MVS [van Burik] + +Changes in 1.2.0.5 (8 September 2003) +- Add OF to inflateBackEnd() declaration in zlib.h +- Remember start when using gzdopen in the middle of a file +- Use internal off_t counters in gz* functions to properly handle seeks +- Perform more rigorous check for distance-too-far in inffast.c +- Add Z_BLOCK flush option to return from inflate at block boundary +- Set strm->data_type on return from inflate + - Indicate bits unused, if at block boundary, and if in last block +- Replace size_t with ptrdiff_t in crc32.c, and check for correct size +- Add condition so old NO_DEFLATE define still works for compatibility +- FAQ update regarding the Windows DLL [Truta] +- INDEX update: add qnx entry, remove aix entry [Truta] +- Install zlib.3 into mandir [Wilson] +- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta] +- Adapt the zlib interface to the new DLL convention guidelines [Truta] +- Introduce ZLIB_WINAPI macro to allow the export of functions using + the WINAPI calling convention, for Visual Basic [Vollant, Truta] +- Update msdos and win32 scripts and makefiles [Truta] +- Export symbols by name, not by ordinal, in win32/zlib.def [Truta] +- Add contrib/ada [Anisimkov] +- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta] +- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant] +- Add contrib/masm686 [Truta] +- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm + [Truta, Vollant] +- Update contrib/delphi; rename to contrib/pascal; add example [Truta] +- Remove contrib/delphi2; add a new contrib/delphi [Truta] +- Avoid inclusion of the nonstandard in contrib/iostream, + and fix some method prototypes [Truta] +- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip + [Truta] +- Avoid the use of backslash (\) in contrib/minizip [Vollant] +- Fix file time handling in contrib/untgz; update makefiles [Truta] +- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines + [Vollant] +- Remove contrib/vstudio/vc15_16 [Vollant] +- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta] +- Update README.contrib [Truta] +- Invert the assignment order of match_head and s->prev[...] in + INSERT_STRING [Truta] +- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings + [Truta] +- Compare function pointers with 0, not with NULL or Z_NULL [Truta] +- Fix prototype of syncsearch in inflate.c [Truta] +- Introduce ASMINF macro to be enabled when using an ASM implementation + of inflate_fast [Truta] +- Change NO_DEFLATE to NO_GZCOMPRESS [Truta] +- Modify test_gzio in example.c to take a single file name as a + parameter [Truta] +- Exit the example.c program if gzopen fails [Truta] +- Add type casts around strlen in example.c [Truta] +- Remove casting to sizeof in minigzip.c; give a proper type + to the variable compared with SUFFIX_LEN [Truta] +- Update definitions of STDC and STDC99 in zconf.h [Truta] +- Synchronize zconf.h with the new Windows DLL interface [Truta] +- Use SYS16BIT instead of __32BIT__ to distinguish between + 16- and 32-bit platforms [Truta] +- Use far memory allocators in small 16-bit memory models for + Turbo C [Truta] +- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in + zlibCompileFlags [Truta] +- Cygwin has vsnprintf [Wilson] +- In Windows16, OS_CODE is 0, as in MSDOS [Truta] +- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson] + +Changes in 1.2.0.4 (10 August 2003) +- Minor FAQ updates +- Be more strict when checking inflateInit2's windowBits parameter +- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well +- Add gzip wrapper option to deflateInit2 using windowBits +- Add updated QNX rule in configure and qnx directory [Bonnefoy] +- Make inflate distance-too-far checks more rigorous +- Clean up FAR usage in inflate +- Add casting to sizeof() in gzio.c and minigzip.c + +Changes in 1.2.0.3 (19 July 2003) +- Fix silly error in gzungetc() implementation [Vollant] +- Update contrib/minizip and contrib/vstudio [Vollant] +- Fix printf format in example.c +- Correct cdecl support in zconf.in.h [Anisimkov] +- Minor FAQ updates + +Changes in 1.2.0.2 (13 July 2003) +- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons +- Attempt to avoid warnings in crc32.c for pointer-int conversion +- Add AIX to configure, remove aix directory [Bakker] +- Add some casts to minigzip.c +- Improve checking after insecure sprintf() or vsprintf() calls +- Remove #elif's from crc32.c +- Change leave label to inf_leave in inflate.c and infback.c to avoid + library conflicts +- Remove inflate gzip decoding by default--only enable gzip decoding by + special request for stricter backward compatibility +- Add zlibCompileFlags() function to return compilation information +- More typecasting in deflate.c to avoid warnings +- Remove leading underscore from _Capital #defines [Truta] +- Fix configure to link shared library when testing +- Add some Windows CE target adjustments [Mai] +- Remove #define ZLIB_DLL in zconf.h [Vollant] +- Add zlib.3 [Rodgers] +- Update RFC URL in deflate.c and algorithm.txt [Mai] +- Add zlib_dll_FAQ.txt to contrib [Truta] +- Add UL to some constants [Truta] +- Update minizip and vstudio [Vollant] +- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h +- Expand use of NO_DUMMY_DECL to avoid all dummy structures +- Added iostream3 to contrib [Schwardt] +- Replace rewind() with fseek() for WinCE [Truta] +- Improve setting of zlib format compression level flags + - Report 0 for huffman and rle strategies and for level == 0 or 1 + - Report 2 only for level == 6 +- Only deal with 64K limit when necessary at compile time [Truta] +- Allow TOO_FAR check to be turned off at compile time [Truta] +- Add gzclearerr() function [Souza] +- Add gzungetc() function + +Changes in 1.2.0.1 (17 March 2003) +- Add Z_RLE strategy for run-length encoding [Truta] + - When Z_RLE requested, restrict matches to distance one + - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE +- Correct FASTEST compilation to allow level == 0 +- Clean up what gets compiled for FASTEST +- Incorporate changes to zconf.in.h [Vollant] + - Refine detection of Turbo C need for dummy returns + - Refine ZLIB_DLL compilation + - Include additional header file on VMS for off_t typedef +- Try to use _vsnprintf where it supplants vsprintf [Vollant] +- Add some casts in inffast.c +- Enchance comments in zlib.h on what happens if gzprintf() tries to + write more than 4095 bytes before compression +- Remove unused state from inflateBackEnd() +- Remove exit(0) from minigzip.c, example.c +- Get rid of all those darn tabs +- Add "check" target to Makefile.in that does the same thing as "test" +- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in +- Update contrib/inflate86 [Anderson] +- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant] +- Add msdos and win32 directories with makefiles [Truta] +- More additions and improvements to the FAQ + +Changes in 1.2.0 (9 March 2003) +- New and improved inflate code + - About 20% faster + - Does not allocate 32K window unless and until needed + - Automatically detects and decompresses gzip streams + - Raw inflate no longer needs an extra dummy byte at end + - Added inflateBack functions using a callback interface--even faster + than inflate, useful for file utilities (gzip, zip) + - Added inflateCopy() function to record state for random access on + externally generated deflate streams (e.g. in gzip files) + - More readable code (I hope) +- New and improved crc32() + - About 50% faster, thanks to suggestions from Rodney Brown +- Add deflateBound() and compressBound() functions +- Fix memory leak in deflateInit2() +- Permit setting dictionary for raw deflate (for parallel deflate) +- Fix const declaration for gzwrite() +- Check for some malloc() failures in gzio.c +- Fix bug in gzopen() on single-byte file 0x1f +- Fix bug in gzread() on concatenated file with 0x1f at end of buffer + and next buffer doesn't start with 0x8b +- Fix uncompress() to return Z_DATA_ERROR on truncated input +- Free memory at end of example.c +- Remove MAX #define in trees.c (conflicted with some libraries) +- Fix static const's in deflate.c, gzio.c, and zutil.[ch] +- Declare malloc() and free() in gzio.c if STDC not defined +- Use malloc() instead of calloc() in zutil.c if int big enough +- Define STDC for AIX +- Add aix/ with approach for compiling shared library on AIX +- Add HP-UX support for shared libraries in configure +- Add OpenUNIX support for shared libraries in configure +- Use $cc instead of gcc to build shared library +- Make prefix directory if needed when installing +- Correct Macintosh avoidance of typedef Byte in zconf.h +- Correct Turbo C memory allocation when under Linux +- Use libz.a instead of -lz in Makefile (assure use of compiled library) +- Update configure to check for snprintf or vsnprintf functions and their + return value, warn during make if using an insecure function +- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that + is lost when library is used--resolution is to build new zconf.h +- Documentation improvements (in zlib.h): + - Document raw deflate and inflate + - Update RFCs URL + - Point out that zlib and gzip formats are different + - Note that Z_BUF_ERROR is not fatal + - Document string limit for gzprintf() and possible buffer overflow + - Note requirement on avail_out when flushing + - Note permitted values of flush parameter of inflate() +- Add some FAQs (and even answers) to the FAQ +- Add contrib/inflate86/ for x86 faster inflate +- Add contrib/blast/ for PKWare Data Compression Library decompression +- Add contrib/puff/ simple inflate for deflate format description + +Changes in 1.1.4 (11 March 2002) +- ZFREE was repeated on same allocation on some error conditions. + This creates a security problem described in + http://www.zlib.org/advisory-2002-03-11.txt +- Returned incorrect error (Z_MEM_ERROR) on some invalid data +- Avoid accesses before window for invalid distances with inflate window + less than 32K. +- force windowBits > 8 to avoid a bug in the encoder for a window size + of 256 bytes. (A complete fix will be available in 1.1.5). + +Changes in 1.1.3 (9 July 1998) +- fix "an inflate input buffer bug that shows up on rare but persistent + occasions" (Mark) +- fix gzread and gztell for concatenated .gz files (Didier Le Botlan) +- fix gzseek(..., SEEK_SET) in write mode +- fix crc check after a gzeek (Frank Faubert) +- fix miniunzip when the last entry in a zip file is itself a zip file + (J Lillge) +- add contrib/asm586 and contrib/asm686 (Brian Raiter) + See http://www.muppetlabs.com/~breadbox/software/assembly.html +- add support for Delphi 3 in contrib/delphi (Bob Dellaca) +- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti) +- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren) +- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks) +- added a FAQ file + +- Support gzdopen on Mac with Metrowerks (Jason Linhart) +- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart) +- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young) +- avoid some warnings with Borland C (Tom Tanner) +- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant) +- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant) +- allow several arguments to configure (Tim Mooney, Frodo Looijaard) +- use libdir and includedir in Makefile.in (Tim Mooney) +- support shared libraries on OSF1 V4 (Tim Mooney) +- remove so_locations in "make clean" (Tim Mooney) +- fix maketree.c compilation error (Glenn, Mark) +- Python interface to zlib now in Python 1.5 (Jeremy Hylton) +- new Makefile.riscos (Rich Walker) +- initialize static descriptors in trees.c for embedded targets (Nick Smith) +- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith) +- add the OS/2 files in Makefile.in too (Andrew Zabolotny) +- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane) +- fix maketree.c to allow clean compilation of inffixed.h (Mark) +- fix parameter check in deflateCopy (Gunther Nikl) +- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler) +- Many portability patches by Christian Spieler: + . zutil.c, zutil.h: added "const" for zmem* + . Make_vms.com: fixed some typos + . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists + . msdos/Makefile.msc: remove "default rtl link library" info from obj files + . msdos/Makefile.*: use model-dependent name for the built zlib library + . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc: + new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT) +- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane) +- replace __far with _far for better portability (Christian Spieler, Tom Lane) +- fix test for errno.h in configure (Tim Newsham) + +Changes in 1.1.2 (19 March 98) +- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant) + See http://www.winimage.com/zLibDll/unzip.html +- preinitialize the inflate tables for fixed codes, to make the code + completely thread safe (Mark) +- some simplifications and slight speed-up to the inflate code (Mark) +- fix gzeof on non-compressed files (Allan Schrum) +- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs) +- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn) +- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny) +- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori) +- do not wrap extern "C" around system includes (Tom Lane) +- mention zlib binding for TCL in README (Andreas Kupries) +- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert) +- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson) +- allow "configure --prefix $HOME" (Tim Mooney) +- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson) +- move Makefile.sas to amiga/Makefile.sas + +Changes in 1.1.1 (27 Feb 98) +- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson) +- remove block truncation heuristic which had very marginal effect for zlib + (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the + compression ratio on some files. This also allows inlining _tr_tally for + matches in deflate_slow. +- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier) + +Changes in 1.1.0 (24 Feb 98) +- do not return STREAM_END prematurely in inflate (John Bowler) +- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler) +- compile with -DFASTEST to get compression code optimized for speed only +- in minigzip, try mmap'ing the input file first (Miguel Albrecht) +- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain + on Sun but significant on HP) + +- add a pointer to experimental unzip library in README (Gilles Vollant) +- initialize variable gcc in configure (Chris Herborth) + +Changes in 1.0.9 (17 Feb 1998) +- added gzputs and gzgets functions +- do not clear eof flag in gzseek (Mark Diekhans) +- fix gzseek for files in transparent mode (Mark Diekhans) +- do not assume that vsprintf returns the number of bytes written (Jens Krinke) +- replace EXPORT with ZEXPORT to avoid conflict with other programs +- added compress2 in zconf.h, zlib.def, zlib.dnt +- new asm code from Gilles Vollant in contrib/asm386 +- simplify the inflate code (Mark): + . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new() + . ZALLOC the length list in inflate_trees_fixed() instead of using stack + . ZALLOC the value area for huft_build() instead of using stack + . Simplify Z_FINISH check in inflate() + +- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 +- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) +- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with + the declaration of FAR (Gilles VOllant) +- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) +- read_buf buf parameter of type Bytef* instead of charf* +- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) +- do not redeclare unlink in minigzip.c for WIN32 (John Bowler) +- fix check for presence of directories in "make install" (Ian Willis) + +Changes in 1.0.8 (27 Jan 1998) +- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant) +- fix gzgetc and gzputc for big endian systems (Markus Oberhumer) +- added compress2() to allow setting the compression level +- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong) +- use constant arrays for the static trees in trees.c instead of computing + them at run time (thanks to Ken Raeburn for this suggestion). To create + trees.h, compile with GEN_TREES_H and run "make test". +- check return code of example in "make test" and display result +- pass minigzip command line options to file_compress +- simplifying code of inflateSync to avoid gcc 2.8 bug + +- support CC="gcc -Wall" in configure -s (QingLong) +- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn) +- fix test for shared library support to avoid compiler warnings +- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant) +- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit) +- do not use fdopen for Metrowerks on Mac (Brad Pettit)) +- add checks for gzputc and gzputc in example.c +- avoid warnings in gzio.c and deflate.c (Andreas Kleinert) +- use const for the CRC table (Ken Raeburn) +- fixed "make uninstall" for shared libraries +- use Tracev instead of Trace in infblock.c +- in example.c use correct compressed length for test_sync +- suppress +vnocompatwarnings in configure for HPUX (not always supported) + +Changes in 1.0.7 (20 Jan 1998) +- fix gzseek which was broken in write mode +- return error for gzseek to negative absolute position +- fix configure for Linux (Chun-Chung Chen) +- increase stack space for MSC (Tim Wegner) +- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant) +- define EXPORTVA for gzprintf (Gilles Vollant) +- added man page zlib.3 (Rick Rodgers) +- for contrib/untgz, fix makedir() and improve Makefile + +- check gzseek in write mode in example.c +- allocate extra buffer for seeks only if gzseek is actually called +- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant) +- add inflateSyncPoint in zconf.h +- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def + +Changes in 1.0.6 (19 Jan 1998) +- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and + gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) +- Fix a deflate bug occurring only with compression level 0 (thanks to + Andy Buckler for finding this one). +- In minigzip, pass transparently also the first byte for .Z files. +- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() +- check Z_FINISH in inflate (thanks to Marc Schluper) +- Implement deflateCopy (thanks to Adam Costello) +- make static libraries by default in configure, add --shared option. +- move MSDOS or Windows specific files to directory msdos +- suppress the notion of partial flush to simplify the interface + (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4) +- suppress history buffer provided by application to simplify the interface + (this feature was not implemented anyway in 1.0.4) +- next_in and avail_in must be initialized before calling inflateInit or + inflateInit2 +- add EXPORT in all exported functions (for Windows DLL) +- added Makefile.nt (thanks to Stephen Williams) +- added the unsupported "contrib" directory: + contrib/asm386/ by Gilles Vollant + 386 asm code replacing longest_match(). + contrib/iostream/ by Kevin Ruland + A C++ I/O streams interface to the zlib gz* functions + contrib/iostream2/ by Tyge Lvset + Another C++ I/O streams interface + contrib/untgz/ by "Pedro A. Aranda Guti\irrez" + A very simple tar.gz file extractor using zlib + contrib/visual-basic.txt by Carlos Rios + How to use compress(), uncompress() and the gz* functions from VB. +- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression + level) in minigzip (thanks to Tom Lane) + +- use const for rommable constants in deflate +- added test for gzseek and gztell in example.c +- add undocumented function inflateSyncPoint() (hack for Paul Mackerras) +- add undocumented function zError to convert error code to string + (for Tim Smithers) +- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code. +- Use default memcpy for Symantec MSDOS compiler. +- Add EXPORT keyword for check_func (needed for Windows DLL) +- add current directory to LD_LIBRARY_PATH for "make test" +- create also a link for libz.so.1 +- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura) +- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX) +- added -soname for Linux in configure (Chun-Chung Chen, +- assign numbers to the exported functions in zlib.def (for Windows DLL) +- add advice in zlib.h for best usage of deflateSetDictionary +- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn) +- allow compilation with ANSI keywords only enabled for TurboC in large model +- avoid "versionString"[0] (Borland bug) +- add NEED_DUMMY_RETURN for Borland +- use variable z_verbose for tracing in debug mode (L. Peter Deutsch). +- allow compilation with CC +- defined STDC for OS/2 (David Charlap) +- limit external names to 8 chars for MVS (Thomas Lund) +- in minigzip.c, use static buffers only for 16-bit systems +- fix suffix check for "minigzip -d foo.gz" +- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee) +- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau) +- added makelcc.bat for lcc-win32 (Tom St Denis) +- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe) +- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion. +- check for unistd.h in configure (for off_t) +- remove useless check parameter in inflate_blocks_free +- avoid useless assignment of s->check to itself in inflate_blocks_new +- do not flush twice in gzclose (thanks to Ken Raeburn) +- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h +- use NO_ERRNO_H instead of enumeration of operating systems with errno.h +- work around buggy fclose on pipes for HP/UX +- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson) +- fix configure if CC is already equal to gcc + +Changes in 1.0.5 (3 Jan 98) +- Fix inflate to terminate gracefully when fed corrupted or invalid data +- Use const for rommable constants in inflate +- Eliminate memory leaks on error conditions in inflate +- Removed some vestigial code in inflate +- Update web address in README + +Changes in 1.0.4 (24 Jul 96) +- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF + bit, so the decompressor could decompress all the correct data but went + on to attempt decompressing extra garbage data. This affected minigzip too. +- zlibVersion and gzerror return const char* (needed for DLL) +- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) +- use z_error only for DEBUG (avoid problem with DLLs) + +Changes in 1.0.3 (2 Jul 96) +- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS + small and medium models; this makes the library incompatible with previous + versions for these models. (No effect in large model or on other systems.) +- return OK instead of BUF_ERROR if previous deflate call returned with + avail_out as zero but there is nothing to do +- added memcmp for non STDC compilers +- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly) +- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO) +- better check for 16-bit mode MSC (avoids problem with Symantec) + +Changes in 1.0.2 (23 May 96) +- added Windows DLL support +- added a function zlibVersion (for the DLL support) +- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model) +- Bytef is define's instead of typedef'd only for Borland C +- avoid reading uninitialized memory in example.c +- mention in README that the zlib format is now RFC1950 +- updated Makefile.dj2 +- added algorithm.doc + +Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] +- fix array overlay in deflate.c which sometimes caused bad compressed data +- fix inflate bug with empty stored block +- fix MSDOS medium model which was broken in 0.99 +- fix deflateParams() which could generated bad compressed data. +- Bytef is define'd instead of typedef'ed (work around Borland bug) +- added an INDEX file +- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32), + Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas) +- speed up adler32 for modern machines without auto-increment +- added -ansi for IRIX in configure +- static_init_done in trees.c is an int +- define unlink as delete for VMS +- fix configure for QNX +- add configure branch for SCO and HPUX +- avoid many warnings (unused variables, dead assignments, etc...) +- no fdopen for BeOS +- fix the Watcom fix for 32 bit mode (define FAR as empty) +- removed redefinition of Byte for MKWERKS +- work around an MWKERKS bug (incorrect merge of all .h files) + +Changes in 0.99 (27 Jan 96) +- allow preset dictionary shared between compressor and decompressor +- allow compression level 0 (no compression) +- add deflateParams in zlib.h: allow dynamic change of compression level + and compression strategy. +- test large buffers and deflateParams in example.c +- add optional "configure" to build zlib as a shared library +- suppress Makefile.qnx, use configure instead +- fixed deflate for 64-bit systems (detected on Cray) +- fixed inflate_blocks for 64-bit systems (detected on Alpha) +- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2) +- always return Z_BUF_ERROR when deflate() has nothing to do +- deflateInit and inflateInit are now macros to allow version checking +- prefix all global functions and types with z_ with -DZ_PREFIX +- make falloc completely reentrant (inftrees.c) +- fixed very unlikely race condition in ct_static_init +- free in reverse order of allocation to help memory manager +- use zlib-1.0/* instead of zlib/* inside the tar.gz +- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith + -Wconversion -Wstrict-prototypes -Wmissing-prototypes" +- allow gzread on concatenated .gz files +- deflateEnd now returns Z_DATA_ERROR if it was premature +- deflate is finally (?) fully deterministic (no matches beyond end of input) +- Document Z_SYNC_FLUSH +- add uninstall in Makefile +- Check for __cpluplus in zlib.h +- Better test in ct_align for partial flush +- avoid harmless warnings for Borland C++ +- initialize hash_head in deflate.c +- avoid warning on fdopen (gzio.c) for HP cc -Aa +- include stdlib.h for STDC compilers +- include errno.h for Cray +- ignore error if ranlib doesn't exist +- call ranlib twice for NeXTSTEP +- use exec_prefix instead of prefix for libz.a +- renamed ct_* as _tr_* to avoid conflict with applications +- clear z->msg in inflateInit2 before any error return +- initialize opaque in example.c, gzio.c, deflate.c and inflate.c +- fixed typo in zconf.h (_GNUC__ => __GNUC__) +- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) +- fix typo in Make_vms.com (f$trnlnm -> f$getsyi) +- in fcalloc, normalize pointer if size > 65520 bytes +- don't use special fcalloc for 32 bit Borland C++ +- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc... +- use Z_BINARY instead of BINARY +- document that gzclose after gzdopen will close the file +- allow "a" as mode in gzopen. +- fix error checking in gzread +- allow skipping .gz extra-field on pipes +- added reference to Perl interface in README +- put the crc table in FAR data (I dislike more and more the medium model :) +- added get_crc_table +- added a dimension to all arrays (Borland C can't count). +- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast +- guard against multiple inclusion of *.h (for precompiled header on Mac) +- Watcom C pretends to be Microsoft C small model even in 32 bit mode. +- don't use unsized arrays to avoid silly warnings by Visual C++: + warning C4746: 'inflate_mask' : unsized array treated as '__far' + (what's wrong with far data in far model?). +- define enum out of inflate_blocks_state to allow compilation with C++ + +Changes in 0.95 (16 Aug 95) +- fix MSDOS small and medium model (now easier to adapt to any compiler) +- inlined send_bits +- fix the final (:-) bug for deflate with flush (output was correct but + not completely flushed in rare occasions). +- default window size is same for compression and decompression + (it's now sufficient to set MAX_WBITS in zconf.h). +- voidp -> voidpf and voidnp -> voidp (for consistency with other + typedefs and because voidnp was not near in large model). + +Changes in 0.94 (13 Aug 95) +- support MSDOS medium model +- fix deflate with flush (could sometimes generate bad output) +- fix deflateReset (zlib header was incorrectly suppressed) +- added support for VMS +- allow a compression level in gzopen() +- gzflush now calls fflush +- For deflate with flush, flush even if no more input is provided. +- rename libgz.a as libz.a +- avoid complex expression in infcodes.c triggering Turbo C bug +- work around a problem with gcc on Alpha (in INSERT_STRING) +- don't use inline functions (problem with some gcc versions) +- allow renaming of Byte, uInt, etc... with #define. +- avoid warning about (unused) pointer before start of array in deflate.c +- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c +- avoid reserved word 'new' in trees.c + +Changes in 0.93 (25 June 95) +- temporarily disable inline functions +- make deflate deterministic +- give enough lookahead for PARTIAL_FLUSH +- Set binary mode for stdin/stdout in minigzip.c for OS/2 +- don't even use signed char in inflate (not portable enough) +- fix inflate memory leak for segmented architectures + +Changes in 0.92 (3 May 95) +- don't assume that char is signed (problem on SGI) +- Clear bit buffer when starting a stored block +- no memcpy on Pyramid +- suppressed inftest.c +- optimized fill_window, put longest_match inline for gcc +- optimized inflate on stored blocks. +- untabify all sources to simplify patches + +Changes in 0.91 (2 May 95) +- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h +- Document the memory requirements in zconf.h +- added "make install" +- fix sync search logic in inflateSync +- deflate(Z_FULL_FLUSH) now works even if output buffer too short +- after inflateSync, don't scare people with just "lo world" +- added support for DJGPP + +Changes in 0.9 (1 May 95) +- don't assume that zalloc clears the allocated memory (the TurboC bug + was Mark's bug after all :) +- let again gzread copy uncompressed data unchanged (was working in 0.71) +- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented +- added a test of inflateSync in example.c +- moved MAX_WBITS to zconf.h because users might want to change that. +- document explicitly that zalloc(64K) on MSDOS must return a normalized + pointer (zero offset) +- added Makefiles for Microsoft C, Turbo C, Borland C++ +- faster crc32() + +Changes in 0.8 (29 April 95) +- added fast inflate (inffast.c) +- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this + is incompatible with previous versions of zlib which returned Z_OK. +- work around a TurboC compiler bug (bad code for b << 0, see infutil.h) + (actually that was not a compiler bug, see 0.81 above) +- gzread no longer reads one extra byte in certain cases +- In gzio destroy(), don't reference a freed structure +- avoid many warnings for MSDOS +- avoid the ERROR symbol which is used by MS Windows + +Changes in 0.71 (14 April 95) +- Fixed more MSDOS compilation problems :( There is still a bug with + TurboC large model. + +Changes in 0.7 (14 April 95) +- Added full inflate support. +- Simplified the crc32() interface. The pre- and post-conditioning + (one's complement) is now done inside crc32(). WARNING: this is + incompatible with previous versions; see zlib.h for the new usage. + +Changes in 0.61 (12 April 95) +- workaround for a bug in TurboC. example and minigzip now work on MSDOS. + +Changes in 0.6 (11 April 95) +- added minigzip.c +- added gzdopen to reopen a file descriptor as gzFile +- added transparent reading of non-gziped files in gzread. +- fixed bug in gzread (don't read crc as data) +- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose). +- don't allocate big arrays in the stack (for MSDOS) +- fix some MSDOS compilation problems + +Changes in 0.5: +- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but + not yet Z_FULL_FLUSH. +- support decompression but only in a single step (forced Z_FINISH) +- added opaque object for zalloc and zfree. +- added deflateReset and inflateReset +- added a variable zlib_version for consistency checking. +- renamed the 'filter' parameter of deflateInit2 as 'strategy'. + Added Z_FILTERED and Z_HUFFMAN_ONLY constants. + +Changes in 0.4: +- avoid "zip" everywhere, use zlib instead of ziplib. +- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush + if compression method == 8. +- added adler32 and crc32 +- renamed deflateOptions as deflateInit2, call one or the other but not both +- added the method parameter for deflateInit2. +- added inflateInit2 +- simplied considerably deflateInit and inflateInit by not supporting + user-provided history buffer. This is supported only in deflateInit2 + and inflateInit2. + +Changes in 0.3: +- prefix all macro names with Z_ +- use Z_FINISH instead of deflateEnd to finish compression. +- added Z_HUFFMAN_ONLY +- added gzerror() diff --git a/source/Irrlicht/zlib/FAQ b/source/Irrlicht/zlib/FAQ new file mode 100644 index 00000000..99b7cf92 --- /dev/null +++ b/source/Irrlicht/zlib/FAQ @@ -0,0 +1,368 @@ + + Frequently Asked Questions about zlib + + +If your question is not there, please check the zlib home page +http://zlib.net/ which may have more recent information. +The lastest zlib FAQ is at http://zlib.net/zlib_faq.html + + + 1. Is zlib Y2K-compliant? + + Yes. zlib doesn't handle dates. + + 2. Where can I get a Windows DLL version? + + The zlib sources can be compiled without change to produce a DLL. See the + file win32/DLL_FAQ.txt in the zlib distribution. Pointers to the + precompiled DLL are found in the zlib web site at http://zlib.net/ . + + 3. Where can I get a Visual Basic interface to zlib? + + See + * http://marknelson.us/1997/01/01/zlib-engine/ + * win32/DLL_FAQ.txt in the zlib distribution + + 4. compress() returns Z_BUF_ERROR. + + Make sure that before the call of compress(), the length of the compressed + buffer is equal to the available size of the compressed buffer and not + zero. For Visual Basic, check that this parameter is passed by reference + ("as any"), not by value ("as long"). + + 5. deflate() or inflate() returns Z_BUF_ERROR. + + Before making the call, make sure that avail_in and avail_out are not zero. + When setting the parameter flush equal to Z_FINISH, also make sure that + avail_out is big enough to allow processing all pending input. Note that a + Z_BUF_ERROR is not fatal--another call to deflate() or inflate() can be + made with more input or output space. A Z_BUF_ERROR may in fact be + unavoidable depending on how the functions are used, since it is not + possible to tell whether or not there is more output pending when + strm.avail_out returns with zero. See http://zlib.net/zlib_how.html for a + heavily annotated example. + + 6. Where's the zlib documentation (man pages, etc.)? + + It's in zlib.h . Examples of zlib usage are in the files test/example.c + and test/minigzip.c, with more in examples/ . + + 7. Why don't you use GNU autoconf or libtool or ...? + + Because we would like to keep zlib as a very small and simple package. + zlib is rather portable and doesn't need much configuration. + + 8. I found a bug in zlib. + + Most of the time, such problems are due to an incorrect usage of zlib. + Please try to reproduce the problem with a small program and send the + corresponding source to us at zlib@gzip.org . Do not send multi-megabyte + data files without prior agreement. + + 9. Why do I get "undefined reference to gzputc"? + + If "make test" produces something like + + example.o(.text+0x154): undefined reference to `gzputc' + + check that you don't have old files libz.* in /usr/lib, /usr/local/lib or + /usr/X11R6/lib. Remove any old versions, then do "make install". + +10. I need a Delphi interface to zlib. + + See the contrib/delphi directory in the zlib distribution. + +11. Can zlib handle .zip archives? + + Not by itself, no. See the directory contrib/minizip in the zlib + distribution. + +12. Can zlib handle .Z files? + + No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt + the code of uncompress on your own. + +13. How can I make a Unix shared library? + + By default a shared (and a static) library is built for Unix. So: + + make distclean + ./configure + make + +14. How do I install a shared zlib library on Unix? + + After the above, then: + + make install + + However, many flavors of Unix come with a shared zlib already installed. + Before going to the trouble of compiling a shared version of zlib and + trying to install it, you may want to check if it's already there! If you + can #include , it's there. The -lz option will probably link to + it. You can check the version at the top of zlib.h or with the + ZLIB_VERSION symbol defined in zlib.h . + +15. I have a question about OttoPDF. + + We are not the authors of OttoPDF. The real author is on the OttoPDF web + site: Joel Hainley, jhainley@myndkryme.com. + +16. Can zlib decode Flate data in an Adobe PDF file? + + Yes. See http://www.pdflib.com/ . To modify PDF forms, see + http://sourceforge.net/projects/acroformtool/ . + +17. Why am I getting this "register_frame_info not found" error on Solaris? + + After installing zlib 1.1.4 on Solaris 2.6, running applications using zlib + generates an error such as: + + ld.so.1: rpm: fatal: relocation error: file /usr/local/lib/libz.so: + symbol __register_frame_info: referenced symbol not found + + The symbol __register_frame_info is not part of zlib, it is generated by + the C compiler (cc or gcc). You must recompile applications using zlib + which have this problem. This problem is specific to Solaris. See + http://www.sunfreeware.com for Solaris versions of zlib and applications + using zlib. + +18. Why does gzip give an error on a file I make with compress/deflate? + + The compress and deflate functions produce data in the zlib format, which + is different and incompatible with the gzip format. The gz* functions in + zlib on the other hand use the gzip format. Both the zlib and gzip formats + use the same compressed data format internally, but have different headers + and trailers around the compressed data. + +19. Ok, so why are there two different formats? + + The gzip format was designed to retain the directory information about a + single file, such as the name and last modification date. The zlib format + on the other hand was designed for in-memory and communication channel + applications, and has a much more compact header and trailer and uses a + faster integrity check than gzip. + +20. Well that's nice, but how do I make a gzip file in memory? + + You can request that deflate write the gzip format instead of the zlib + format using deflateInit2(). You can also request that inflate decode the + gzip format using inflateInit2(). Read zlib.h for more details. + +21. Is zlib thread-safe? + + Yes. However any library routines that zlib uses and any application- + provided memory allocation routines must also be thread-safe. zlib's gz* + functions use stdio library routines, and most of zlib's functions use the + library memory allocation routines by default. zlib's *Init* functions + allow for the application to provide custom memory allocation routines. + + Of course, you should only operate on any given zlib or gzip stream from a + single thread at a time. + +22. Can I use zlib in my commercial application? + + Yes. Please read the license in zlib.h. + +23. Is zlib under the GNU license? + + No. Please read the license in zlib.h. + +24. The license says that altered source versions must be "plainly marked". So + what exactly do I need to do to meet that requirement? + + You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In + particular, the final version number needs to be changed to "f", and an + identification string should be appended to ZLIB_VERSION. Version numbers + x.x.x.f are reserved for modifications to zlib by others than the zlib + maintainers. For example, if the version of the base zlib you are altering + is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and + ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also + update the version strings in deflate.c and inftrees.c. + + For altered source distributions, you should also note the origin and + nature of the changes in zlib.h, as well as in ChangeLog and README, along + with the dates of the alterations. The origin should include at least your + name (or your company's name), and an email address to contact for help or + issues with the library. + + Note that distributing a compiled zlib library along with zlib.h and + zconf.h is also a source distribution, and so you should change + ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes + in zlib.h as you would for a full source distribution. + +25. Will zlib work on a big-endian or little-endian architecture, and can I + exchange compressed data between them? + + Yes and yes. + +26. Will zlib work on a 64-bit machine? + + Yes. It has been tested on 64-bit machines, and has no dependence on any + data types being limited to 32-bits in length. If you have any + difficulties, please provide a complete problem report to zlib@gzip.org + +27. Will zlib decompress data from the PKWare Data Compression Library? + + No. The PKWare DCL uses a completely different compressed data format than + does PKZIP and zlib. However, you can look in zlib's contrib/blast + directory for a possible solution to your problem. + +28. Can I access data randomly in a compressed stream? + + No, not without some preparation. If when compressing you periodically use + Z_FULL_FLUSH, carefully write all the pending data at those points, and + keep an index of those locations, then you can start decompression at those + points. You have to be careful to not use Z_FULL_FLUSH too often, since it + can significantly degrade compression. Alternatively, you can scan a + deflate stream once to generate an index, and then use that index for + random access. See examples/zran.c . + +29. Does zlib work on MVS, OS/390, CICS, etc.? + + It has in the past, but we have not heard of any recent evidence. There + were working ports of zlib 1.1.4 to MVS, but those links no longer work. + If you know of recent, successful applications of zlib on these operating + systems, please let us know. Thanks. + +30. Is there some simpler, easier to read version of inflate I can look at to + understand the deflate format? + + First off, you should read RFC 1951. Second, yes. Look in zlib's + contrib/puff directory. + +31. Does zlib infringe on any patents? + + As far as we know, no. In fact, that was originally the whole point behind + zlib. Look here for some more information: + + http://www.gzip.org/#faq11 + +32. Can zlib work with greater than 4 GB of data? + + Yes. inflate() and deflate() will process any amount of data correctly. + Each call of inflate() or deflate() is limited to input and output chunks + of the maximum value that can be stored in the compiler's "unsigned int" + type, but there is no limit to the number of chunks. Note however that the + strm.total_in and strm_total_out counters may be limited to 4 GB. These + counters are provided as a convenience and are not used internally by + inflate() or deflate(). The application can easily set up its own counters + updated after each call of inflate() or deflate() to count beyond 4 GB. + compress() and uncompress() may be limited to 4 GB, since they operate in a + single call. gzseek() and gztell() may be limited to 4 GB depending on how + zlib is compiled. See the zlibCompileFlags() function in zlib.h. + + The word "may" appears several times above since there is a 4 GB limit only + if the compiler's "long" type is 32 bits. If the compiler's "long" type is + 64 bits, then the limit is 16 exabytes. + +33. Does zlib have any security vulnerabilities? + + The only one that we are aware of is potentially in gzprintf(). If zlib is + compiled to use sprintf() or vsprintf(), then there is no protection + against a buffer overflow of an 8K string space (or other value as set by + gzbuffer()), other than the caller of gzprintf() assuring that the output + will not exceed 8K. On the other hand, if zlib is compiled to use + snprintf() or vsnprintf(), which should normally be the case, then there is + no vulnerability. The ./configure script will display warnings if an + insecure variation of sprintf() will be used by gzprintf(). Also the + zlibCompileFlags() function will return information on what variant of + sprintf() is used by gzprintf(). + + If you don't have snprintf() or vsnprintf() and would like one, you can + find a portable implementation here: + + http://www.ijs.si/software/snprintf/ + + Note that you should be using the most recent version of zlib. Versions + 1.1.3 and before were subject to a double-free vulnerability, and versions + 1.2.1 and 1.2.2 were subject to an access exception when decompressing + invalid compressed data. + +34. Is there a Java version of zlib? + + Probably what you want is to use zlib in Java. zlib is already included + as part of the Java SDK in the java.util.zip package. If you really want + a version of zlib written in the Java language, look on the zlib home + page for links: http://zlib.net/ . + +35. I get this or that compiler or source-code scanner warning when I crank it + up to maximally-pedantic. Can't you guys write proper code? + + Many years ago, we gave up attempting to avoid warnings on every compiler + in the universe. It just got to be a waste of time, and some compilers + were downright silly as well as contradicted each other. So now, we simply + make sure that the code always works. + +36. Valgrind (or some similar memory access checker) says that deflate is + performing a conditional jump that depends on an uninitialized value. + Isn't that a bug? + + No. That is intentional for performance reasons, and the output of deflate + is not affected. This only started showing up recently since zlib 1.2.x + uses malloc() by default for allocations, whereas earlier versions used + calloc(), which zeros out the allocated memory. Even though the code was + correct, versions 1.2.4 and later was changed to not stimulate these + checkers. + +37. Will zlib read the (insert any ancient or arcane format here) compressed + data format? + + Probably not. Look in the comp.compression FAQ for pointers to various + formats and associated software. + +38. How can I encrypt/decrypt zip files with zlib? + + zlib doesn't support encryption. The original PKZIP encryption is very + weak and can be broken with freely available programs. To get strong + encryption, use GnuPG, http://www.gnupg.org/ , which already includes zlib + compression. For PKZIP compatible "encryption", look at + http://www.info-zip.org/ + +39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings? + + "gzip" is the gzip format, and "deflate" is the zlib format. They should + probably have called the second one "zlib" instead to avoid confusion with + the raw deflate compressed data format. While the HTTP 1.1 RFC 2616 + correctly points to the zlib specification in RFC 1950 for the "deflate" + transfer encoding, there have been reports of servers and browsers that + incorrectly produce or expect raw deflate data per the deflate + specification in RFC 1951, most notably Microsoft. So even though the + "deflate" transfer encoding using the zlib format would be the more + efficient approach (and in fact exactly what the zlib format was designed + for), using the "gzip" transfer encoding is probably more reliable due to + an unfortunate choice of name on the part of the HTTP 1.1 authors. + + Bottom line: use the gzip format for HTTP 1.1 encoding. + +40. Does zlib support the new "Deflate64" format introduced by PKWare? + + No. PKWare has apparently decided to keep that format proprietary, since + they have not documented it as they have previous compression formats. In + any case, the compression improvements are so modest compared to other more + modern approaches, that it's not worth the effort to implement. + +41. I'm having a problem with the zip functions in zlib, can you help? + + There are no zip functions in zlib. You are probably using minizip by + Giles Vollant, which is found in the contrib directory of zlib. It is not + part of zlib. In fact none of the stuff in contrib is part of zlib. The + files in there are not supported by the zlib authors. You need to contact + the authors of the respective contribution for help. + +42. The match.asm code in contrib is under the GNU General Public License. + Since it's part of zlib, doesn't that mean that all of zlib falls under the + GNU GPL? + + No. The files in contrib are not part of zlib. They were contributed by + other authors and are provided as a convenience to the user within the zlib + distribution. Each item in contrib has its own license. + +43. Is zlib subject to export controls? What is its ECCN? + + zlib is not subject to export controls, and so is classified as EAR99. + +44. Can you please sign these lengthy legal documents and fax them back to us + so that we can use your software in our product? + + No. Go away. Shoo. diff --git a/source/Irrlicht/zlib/INDEX b/source/Irrlicht/zlib/INDEX new file mode 100644 index 00000000..2ba06412 --- /dev/null +++ b/source/Irrlicht/zlib/INDEX @@ -0,0 +1,68 @@ +CMakeLists.txt cmake build file +ChangeLog history of changes +FAQ Frequently Asked Questions about zlib +INDEX this file +Makefile dummy Makefile that tells you to ./configure +Makefile.in template for Unix Makefile +README guess what +configure configure script for Unix +make_vms.com makefile for VMS +test/example.c zlib usages examples for build testing +test/minigzip.c minimal gzip-like functionality for build testing +test/infcover.c inf*.c code coverage for build coverage testing +treebuild.xml XML description of source file dependencies +zconf.h.cmakein zconf.h template for cmake +zconf.h.in zconf.h template for configure +zlib.3 Man page for zlib +zlib.3.pdf Man page in PDF format +zlib.map Linux symbol information +zlib.pc.in Template for pkg-config descriptor +zlib.pc.cmakein zlib.pc template for cmake +zlib2ansi perl script to convert source files for C++ compilation + +amiga/ makefiles for Amiga SAS C +as400/ makefiles for AS/400 +doc/ documentation for formats and algorithms +msdos/ makefiles for MSDOS +nintendods/ makefile for Nintendo DS +old/ makefiles for various architectures and zlib documentation + files that have not yet been updated for zlib 1.2.x +qnx/ makefiles for QNX +watcom/ makefiles for OpenWatcom +win32/ makefiles for Windows + + zlib public header files (required for library use): +zconf.h +zlib.h + + private source files used to build the zlib library: +adler32.c +compress.c +crc32.c +crc32.h +deflate.c +deflate.h +gzclose.c +gzguts.h +gzlib.c +gzread.c +gzwrite.c +infback.c +inffast.c +inffast.h +inffixed.h +inflate.c +inflate.h +inftrees.c +inftrees.h +trees.c +trees.h +uncompr.c +zutil.c +zutil.h + + source files for sample programs +See examples/README.examples + + unsupported contributions by third parties +See contrib/README.contrib diff --git a/source/Irrlicht/zlib/Makefile b/source/Irrlicht/zlib/Makefile new file mode 100644 index 00000000..6bba86c7 --- /dev/null +++ b/source/Irrlicht/zlib/Makefile @@ -0,0 +1,5 @@ +all: + -@echo "Please use ./configure first. Thank you." + +distclean: + make -f Makefile.in distclean diff --git a/source/Irrlicht/zlib/Makefile.in b/source/Irrlicht/zlib/Makefile.in new file mode 100644 index 00000000..c61aa300 --- /dev/null +++ b/source/Irrlicht/zlib/Makefile.in @@ -0,0 +1,288 @@ +# Makefile for zlib +# Copyright (C) 1995-2013 Jean-loup Gailly, Mark Adler +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile and test, type: +# ./configure; make test +# Normally configure builds both a static and a shared library. +# If you want to build just a static library, use: ./configure --static + +# To use the asm code, type: +# cp contrib/asm?86/match.S ./match.S +# make LOC=-DASMV OBJA=match.o + +# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type: +# make install +# To install in $HOME instead of /usr/local, use: +# make install prefix=$HOME + +CC=cc + +CFLAGS=-O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-g -DDEBUG +#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ +# -Wstrict-prototypes -Wmissing-prototypes + +SFLAGS=-O +LDFLAGS= +TEST_LDFLAGS=-L. libz.a +LDSHARED=$(CC) +CPP=$(CC) -E + +STATICLIB=libz.a +SHAREDLIB=libz.so +SHAREDLIBV=libz.so.1.2.8 +SHAREDLIBM=libz.so.1 +LIBS=$(STATICLIB) $(SHAREDLIBV) + +AR=ar +ARFLAGS=rc +RANLIB=ranlib +LDCONFIG=ldconfig +LDSHAREDLIBC=-lc +TAR=tar +SHELL=/bin/sh +EXE= + +prefix = /usr/local +exec_prefix = ${prefix} +libdir = ${exec_prefix}/lib +sharedlibdir = ${libdir} +includedir = ${prefix}/include +mandir = ${prefix}/share/man +man3dir = ${mandir}/man3 +pkgconfigdir = ${libdir}/pkgconfig + +OBJZ = adler32.o crc32.o deflate.o infback.o inffast.o inflate.o inftrees.o trees.o zutil.o +OBJG = compress.o uncompr.o gzclose.o gzlib.o gzread.o gzwrite.o +OBJC = $(OBJZ) $(OBJG) + +PIC_OBJZ = adler32.lo crc32.lo deflate.lo infback.lo inffast.lo inflate.lo inftrees.lo trees.lo zutil.lo +PIC_OBJG = compress.lo uncompr.lo gzclose.lo gzlib.lo gzread.lo gzwrite.lo +PIC_OBJC = $(PIC_OBJZ) $(PIC_OBJG) + +# to use the asm code: make OBJA=match.o, PIC_OBJA=match.lo +OBJA = +PIC_OBJA = + +OBJS = $(OBJC) $(OBJA) + +PIC_OBJS = $(PIC_OBJC) $(PIC_OBJA) + +all: static shared + +static: example$(EXE) minigzip$(EXE) + +shared: examplesh$(EXE) minigzipsh$(EXE) + +all64: example64$(EXE) minigzip64$(EXE) + +check: test + +test: all teststatic testshared + +teststatic: static + @TMPST=tmpst_$$; \ + if echo hello world | ./minigzip | ./minigzip -d && ./example $$TMPST ; then \ + echo ' *** zlib test OK ***'; \ + else \ + echo ' *** zlib test FAILED ***'; false; \ + fi; \ + rm -f $$TMPST + +testshared: shared + @LD_LIBRARY_PATH=`pwd`:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \ + LD_LIBRARYN32_PATH=`pwd`:$(LD_LIBRARYN32_PATH) ; export LD_LIBRARYN32_PATH; \ + DYLD_LIBRARY_PATH=`pwd`:$(DYLD_LIBRARY_PATH) ; export DYLD_LIBRARY_PATH; \ + SHLIB_PATH=`pwd`:$(SHLIB_PATH) ; export SHLIB_PATH; \ + TMPSH=tmpsh_$$; \ + if echo hello world | ./minigzipsh | ./minigzipsh -d && ./examplesh $$TMPSH; then \ + echo ' *** zlib shared test OK ***'; \ + else \ + echo ' *** zlib shared test FAILED ***'; false; \ + fi; \ + rm -f $$TMPSH + +test64: all64 + @TMP64=tmp64_$$; \ + if echo hello world | ./minigzip64 | ./minigzip64 -d && ./example64 $$TMP64; then \ + echo ' *** zlib 64-bit test OK ***'; \ + else \ + echo ' *** zlib 64-bit test FAILED ***'; false; \ + fi; \ + rm -f $$TMP64 + +infcover.o: test/infcover.c zlib.h zconf.h + $(CC) $(CFLAGS) -I. -c -o $@ test/infcover.c + +infcover: infcover.o libz.a + $(CC) $(CFLAGS) -o $@ infcover.o libz.a + +cover: infcover + rm -f *.gcda + ./infcover + gcov inf*.c + +libz.a: $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + -@ ($(RANLIB) $@ || true) >/dev/null 2>&1 + +match.o: match.S + $(CPP) match.S > _match.s + $(CC) -c _match.s + mv _match.o match.o + rm -f _match.s + +match.lo: match.S + $(CPP) match.S > _match.s + $(CC) -c -fPIC _match.s + mv _match.o match.lo + rm -f _match.s + +example.o: test/example.c zlib.h zconf.h + $(CC) $(CFLAGS) -I. -c -o $@ test/example.c + +minigzip.o: test/minigzip.c zlib.h zconf.h + $(CC) $(CFLAGS) -I. -c -o $@ test/minigzip.c + +example64.o: test/example.c zlib.h zconf.h + $(CC) $(CFLAGS) -I. -D_FILE_OFFSET_BITS=64 -c -o $@ test/example.c + +minigzip64.o: test/minigzip.c zlib.h zconf.h + $(CC) $(CFLAGS) -I. -D_FILE_OFFSET_BITS=64 -c -o $@ test/minigzip.c + +.SUFFIXES: .lo + +.c.lo: + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) -DPIC -c -o objs/$*.o $< + -@mv objs/$*.o $@ + +placebo $(SHAREDLIBV): $(PIC_OBJS) libz.a + $(LDSHARED) $(SFLAGS) -o $@ $(PIC_OBJS) $(LDSHAREDLIBC) $(LDFLAGS) + rm -f $(SHAREDLIB) $(SHAREDLIBM) + ln -s $@ $(SHAREDLIB) + ln -s $@ $(SHAREDLIBM) + -@rmdir objs + +example$(EXE): example.o $(STATICLIB) + $(CC) $(CFLAGS) -o $@ example.o $(TEST_LDFLAGS) + +minigzip$(EXE): minigzip.o $(STATICLIB) + $(CC) $(CFLAGS) -o $@ minigzip.o $(TEST_LDFLAGS) + +examplesh$(EXE): example.o $(SHAREDLIBV) + $(CC) $(CFLAGS) -o $@ example.o -L. $(SHAREDLIBV) + +minigzipsh$(EXE): minigzip.o $(SHAREDLIBV) + $(CC) $(CFLAGS) -o $@ minigzip.o -L. $(SHAREDLIBV) + +example64$(EXE): example64.o $(STATICLIB) + $(CC) $(CFLAGS) -o $@ example64.o $(TEST_LDFLAGS) + +minigzip64$(EXE): minigzip64.o $(STATICLIB) + $(CC) $(CFLAGS) -o $@ minigzip64.o $(TEST_LDFLAGS) + +install-libs: $(LIBS) + -@if [ ! -d $(DESTDIR)$(exec_prefix) ]; then mkdir -p $(DESTDIR)$(exec_prefix); fi + -@if [ ! -d $(DESTDIR)$(libdir) ]; then mkdir -p $(DESTDIR)$(libdir); fi + -@if [ ! -d $(DESTDIR)$(sharedlibdir) ]; then mkdir -p $(DESTDIR)$(sharedlibdir); fi + -@if [ ! -d $(DESTDIR)$(man3dir) ]; then mkdir -p $(DESTDIR)$(man3dir); fi + -@if [ ! -d $(DESTDIR)$(pkgconfigdir) ]; then mkdir -p $(DESTDIR)$(pkgconfigdir); fi + cp $(STATICLIB) $(DESTDIR)$(libdir) + chmod 644 $(DESTDIR)$(libdir)/$(STATICLIB) + -@($(RANLIB) $(DESTDIR)$(libdir)/libz.a || true) >/dev/null 2>&1 + -@if test -n "$(SHAREDLIBV)"; then \ + cp $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir); \ + echo "cp $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)"; \ + chmod 755 $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBV); \ + echo "chmod 755 $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBV)"; \ + rm -f $(DESTDIR)$(sharedlibdir)/$(SHAREDLIB) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBM); \ + ln -s $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIB); \ + ln -s $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBM); \ + ($(LDCONFIG) || true) >/dev/null 2>&1; \ + fi + cp zlib.3 $(DESTDIR)$(man3dir) + chmod 644 $(DESTDIR)$(man3dir)/zlib.3 + cp zlib.pc $(DESTDIR)$(pkgconfigdir) + chmod 644 $(DESTDIR)$(pkgconfigdir)/zlib.pc +# The ranlib in install is needed on NeXTSTEP which checks file times +# ldconfig is for Linux + +install: install-libs + -@if [ ! -d $(DESTDIR)$(includedir) ]; then mkdir -p $(DESTDIR)$(includedir); fi + cp zlib.h zconf.h $(DESTDIR)$(includedir) + chmod 644 $(DESTDIR)$(includedir)/zlib.h $(DESTDIR)$(includedir)/zconf.h + +uninstall: + cd $(DESTDIR)$(includedir) && rm -f zlib.h zconf.h + cd $(DESTDIR)$(libdir) && rm -f libz.a; \ + if test -n "$(SHAREDLIBV)" -a -f $(SHAREDLIBV); then \ + rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \ + fi + cd $(DESTDIR)$(man3dir) && rm -f zlib.3 + cd $(DESTDIR)$(pkgconfigdir) && rm -f zlib.pc + +docs: zlib.3.pdf + +zlib.3.pdf: zlib.3 + groff -mandoc -f H -T ps zlib.3 | ps2pdf - zlib.3.pdf + +zconf.h.cmakein: zconf.h.in + -@ TEMPFILE=zconfh_$$; \ + echo "/#define ZCONF_H/ a\\\\\n#cmakedefine Z_PREFIX\\\\\n#cmakedefine Z_HAVE_UNISTD_H\n" >> $$TEMPFILE &&\ + sed -f $$TEMPFILE zconf.h.in > zconf.h.cmakein &&\ + touch -r zconf.h.in zconf.h.cmakein &&\ + rm $$TEMPFILE + +zconf: zconf.h.in + cp -p zconf.h.in zconf.h + +mostlyclean: clean +clean: + rm -f *.o *.lo *~ \ + example$(EXE) minigzip$(EXE) examplesh$(EXE) minigzipsh$(EXE) \ + example64$(EXE) minigzip64$(EXE) \ + infcover \ + libz.* foo.gz so_locations \ + _match.s maketree contrib/infback9/*.o + rm -rf objs + rm -f *.gcda *.gcno *.gcov + rm -f contrib/infback9/*.gcda contrib/infback9/*.gcno contrib/infback9/*.gcov + +maintainer-clean: distclean +distclean: clean zconf zconf.h.cmakein docs + rm -f Makefile zlib.pc configure.log + -@rm -f .DS_Store + -@printf 'all:\n\t-@echo "Please use ./configure first. Thank you."\n' > Makefile + -@printf '\ndistclean:\n\tmake -f Makefile.in distclean\n' >> Makefile + -@touch -r Makefile.in Makefile + +tags: + etags *.[ch] + +depend: + makedepend -- $(CFLAGS) -- *.[ch] + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +adler32.o zutil.o: zutil.h zlib.h zconf.h +gzclose.o gzlib.o gzread.o gzwrite.o: zlib.h zconf.h gzguts.h +compress.o example.o minigzip.o uncompr.o: zlib.h zconf.h +crc32.o: zutil.h zlib.h zconf.h crc32.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +infback.o inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h inffixed.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h + +adler32.lo zutil.lo: zutil.h zlib.h zconf.h +gzclose.lo gzlib.lo gzread.lo gzwrite.lo: zlib.h zconf.h gzguts.h +compress.lo example.lo minigzip.lo uncompr.lo: zlib.h zconf.h +crc32.lo: zutil.h zlib.h zconf.h crc32.h +deflate.lo: deflate.h zutil.h zlib.h zconf.h +infback.lo inflate.lo: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h inffixed.h +inffast.lo: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.lo: zutil.h zlib.h zconf.h inftrees.h +trees.lo: deflate.h zutil.h zlib.h zconf.h trees.h diff --git a/source/Irrlicht/zlib/README b/source/Irrlicht/zlib/README new file mode 100644 index 00000000..5ca9d127 --- /dev/null +++ b/source/Irrlicht/zlib/README @@ -0,0 +1,115 @@ +ZLIB DATA COMPRESSION LIBRARY + +zlib 1.2.8 is a general purpose data compression library. All the code is +thread safe. The data format used by the zlib library is described by RFCs +(Request for Comments) 1950 to 1952 in the files +http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and +rfc1952 (gzip format). + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example +of the library is given in the file test/example.c which also tests that +the library is working correctly. Another example is given in the file +test/minigzip.c. The compression library itself is composed of all source +files in the root directory. + +To compile all files and run the test program, follow the instructions given at +the top of Makefile.in. In short "./configure; make test", and if that goes +well, "make install" should work for most flavors of Unix. For Windows, use +one of the special makefiles in win32/ or contrib/vstudio/ . For VMS, use +make_vms.com. + +Questions about zlib should be sent to , or to Gilles Vollant + for the Windows DLL version. The zlib home page is +http://zlib.net/ . Before reporting a problem, please check this site to +verify that you have the latest version of zlib; otherwise get the latest +version and check whether the problem still exists or not. + +PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. + +Mark Nelson wrote an article about zlib for the Jan. 1997 +issue of Dr. Dobb's Journal; a copy of the article is available at +http://marknelson.us/1997/01/01/zlib-engine/ . + +The changes made in version 1.2.8 are documented in the file ChangeLog. + +Unsupported third party contributions are provided in directory contrib/ . + +zlib is available in Java using the java.util.zip package, documented at +http://java.sun.com/developer/technicalArticles/Programming/compression/ . + +A Perl interface to zlib written by Paul Marquess is available +at CPAN (Comprehensive Perl Archive Network) sites, including +http://search.cpan.org/~pmqs/IO-Compress-Zlib/ . + +A Python interface to zlib written by A.M. Kuchling is +available in Python 1.5 and later versions, see +http://docs.python.org/library/zlib.html . + +zlib is built into tcl: http://wiki.tcl.tk/4610 . + +An experimental package to read and write files in .zip format, written on top +of zlib by Gilles Vollant , is available in the +contrib/minizip directory of zlib. + + +Notes for some targets: + +- For Windows DLL versions, please see win32/DLL_FAQ.txt + +- For 64-bit Irix, deflate.c must be compiled without any optimization. With + -O, one libpng test fails. The test works in 32 bit mode (with the -n32 + compiler flag). The compiler bug has been reported to SGI. + +- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works + when compiled with cc. + +- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is + necessary to get gzprintf working correctly. This is done by configure. + +- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with + other compilers. Use "make test" to check your compiler. + +- gzdopen is not supported on RISCOS or BEOS. + +- For PalmOs, see http://palmzlib.sourceforge.net/ + + +Acknowledgments: + + The deflate format used by zlib was defined by Phil Katz. The deflate and + zlib specifications were written by L. Peter Deutsch. Thanks to all the + people who reported problems and suggested various improvements in zlib; they + are too numerous to cite here. + +Copyright notice: + + (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* receiving +lengthy legal documents to sign. The sources are provided for free but without +warranty of any kind. The library has been entirely written by Jean-loup +Gailly and Mark Adler; it does not include third-party code. + +If you redistribute modified sources, we would appreciate that you include in +the file ChangeLog history information documenting your changes. Please read +the FAQ for more information on the distribution of modified source versions. diff --git a/source/Irrlicht/zlib/adler32.c b/source/Irrlicht/zlib/adler32.c new file mode 100644 index 00000000..003d3734 --- /dev/null +++ b/source/Irrlicht/zlib/adler32.c @@ -0,0 +1,179 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2011 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#define local static + +local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); + +#define BASE 65521 /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware -- + try it both ways to see which is faster */ +#ifdef NO_DIVIDE +/* note that this assumes BASE is 65521, where 65536 % 65521 == 15 + (thank you to John Reiser for pointing this out) */ +# define CHOP(a) \ + do { \ + unsigned long tmp = a >> 16; \ + a &= 0xffffUL; \ + a += (tmp << 4) - tmp; \ + } while (0) +# define MOD28(a) \ + do { \ + CHOP(a); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD(a) \ + do { \ + CHOP(a); \ + MOD28(a); \ + } while (0) +# define MOD63(a) \ + do { /* this assumes a is not negative */ \ + z_off64_t tmp = a >> 32; \ + a &= 0xffffffffL; \ + a += (tmp << 8) - (tmp << 5) + tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD28(a) a %= BASE +# define MOD63(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD28(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +local uLong adler32_combine_(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* for negative len, return invalid adler32 as a clue for debugging */ + if (len2 < 0) + return 0xffffffffUL; + + /* the derivation of this formula is left as an exercise for the reader */ + MOD63(len2); /* assumes len2 >= 0 */ + rem = (unsigned)len2; + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 >= BASE) sum1 -= BASE; + if (sum1 >= BASE) sum1 -= BASE; + if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 >= BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + return adler32_combine_(adler1, adler2, len2); +} + +uLong ZEXPORT adler32_combine64(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ + return adler32_combine_(adler1, adler2, len2); +} diff --git a/source/Irrlicht/zlib/compress.c b/source/Irrlicht/zlib/compress.c new file mode 100644 index 00000000..832a5488 --- /dev/null +++ b/source/Irrlicht/zlib/compress.c @@ -0,0 +1,80 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (z_const Bytef *)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13; +} diff --git a/source/Irrlicht/zlib/configure b/source/Irrlicht/zlib/configure new file mode 100644 index 00000000..b77a8a8c --- /dev/null +++ b/source/Irrlicht/zlib/configure @@ -0,0 +1,831 @@ +#!/bin/sh +# configure script for zlib. +# +# Normally configure builds both a static and a shared library. +# If you want to build just a static library, use: ./configure --static +# +# To impose specific compiler or flags or install directory, use for example: +# prefix=$HOME CC=cc CFLAGS="-O4" ./configure +# or for csh/tcsh users: +# (setenv prefix $HOME; setenv CC cc; setenv CFLAGS "-O4"; ./configure) + +# Incorrect settings of CC or CFLAGS may prevent creating a shared library. +# If you have problems, try without defining CC and CFLAGS before reporting +# an error. + +# start off configure.log +echo -------------------- >> configure.log +echo $0 $* >> configure.log +date >> configure.log + +# set command prefix for cross-compilation +if [ -n "${CHOST}" ]; then + uname="`echo "${CHOST}" | sed -e 's/^[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)-.*$/\1/'`" + CROSS_PREFIX="${CHOST}-" +fi + +# destination name for static library +STATICLIB=libz.a + +# extract zlib version numbers from zlib.h +VER=`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h` +VER3=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\\.[0-9]*\).*/\1/p' < zlib.h` +VER2=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\)\\..*/\1/p' < zlib.h` +VER1=`sed -n -e '/VERSION "/s/.*"\([0-9]*\)\\..*/\1/p' < zlib.h` + +# establish commands for library building +if "${CROSS_PREFIX}ar" --version >/dev/null 2>/dev/null || test $? -lt 126; then + AR=${AR-"${CROSS_PREFIX}ar"} + test -n "${CROSS_PREFIX}" && echo Using ${AR} | tee -a configure.log +else + AR=${AR-"ar"} + test -n "${CROSS_PREFIX}" && echo Using ${AR} | tee -a configure.log +fi +ARFLAGS=${ARFLAGS-"rc"} +if "${CROSS_PREFIX}ranlib" --version >/dev/null 2>/dev/null || test $? -lt 126; then + RANLIB=${RANLIB-"${CROSS_PREFIX}ranlib"} + test -n "${CROSS_PREFIX}" && echo Using ${RANLIB} | tee -a configure.log +else + RANLIB=${RANLIB-"ranlib"} +fi +if "${CROSS_PREFIX}nm" --version >/dev/null 2>/dev/null || test $? -lt 126; then + NM=${NM-"${CROSS_PREFIX}nm"} + test -n "${CROSS_PREFIX}" && echo Using ${NM} | tee -a configure.log +else + NM=${NM-"nm"} +fi + +# set defaults before processing command line options +LDCONFIG=${LDCONFIG-"ldconfig"} +LDSHAREDLIBC="${LDSHAREDLIBC--lc}" +ARCHS= +prefix=${prefix-/usr/local} +exec_prefix=${exec_prefix-'${prefix}'} +libdir=${libdir-'${exec_prefix}/lib'} +sharedlibdir=${sharedlibdir-'${libdir}'} +includedir=${includedir-'${prefix}/include'} +mandir=${mandir-'${prefix}/share/man'} +shared_ext='.so' +shared=1 +solo=0 +cover=0 +zprefix=0 +zconst=0 +build64=0 +gcc=0 +old_cc="$CC" +old_cflags="$CFLAGS" +OBJC='$(OBJZ) $(OBJG)' +PIC_OBJC='$(PIC_OBJZ) $(PIC_OBJG)' + +# leave this script, optionally in a bad way +leave() +{ + if test "$*" != "0"; then + echo "** $0 aborting." | tee -a configure.log + fi + rm -f $test.[co] $test $test$shared_ext $test.gcno ./--version + echo -------------------- >> configure.log + echo >> configure.log + echo >> configure.log + exit $1 +} + +# process command line options +while test $# -ge 1 +do +case "$1" in + -h* | --help) + echo 'usage:' | tee -a configure.log + echo ' configure [--const] [--zprefix] [--prefix=PREFIX] [--eprefix=EXPREFIX]' | tee -a configure.log + echo ' [--static] [--64] [--libdir=LIBDIR] [--sharedlibdir=LIBDIR]' | tee -a configure.log + echo ' [--includedir=INCLUDEDIR] [--archs="-arch i386 -arch x86_64"]' | tee -a configure.log + exit 0 ;; + -p*=* | --prefix=*) prefix=`echo $1 | sed 's/.*=//'`; shift ;; + -e*=* | --eprefix=*) exec_prefix=`echo $1 | sed 's/.*=//'`; shift ;; + -l*=* | --libdir=*) libdir=`echo $1 | sed 's/.*=//'`; shift ;; + --sharedlibdir=*) sharedlibdir=`echo $1 | sed 's/.*=//'`; shift ;; + -i*=* | --includedir=*) includedir=`echo $1 | sed 's/.*=//'`;shift ;; + -u*=* | --uname=*) uname=`echo $1 | sed 's/.*=//'`;shift ;; + -p* | --prefix) prefix="$2"; shift; shift ;; + -e* | --eprefix) exec_prefix="$2"; shift; shift ;; + -l* | --libdir) libdir="$2"; shift; shift ;; + -i* | --includedir) includedir="$2"; shift; shift ;; + -s* | --shared | --enable-shared) shared=1; shift ;; + -t | --static) shared=0; shift ;; + --solo) solo=1; shift ;; + --cover) cover=1; shift ;; + -z* | --zprefix) zprefix=1; shift ;; + -6* | --64) build64=1; shift ;; + -a*=* | --archs=*) ARCHS=`echo $1 | sed 's/.*=//'`; shift ;; + --sysconfdir=*) echo "ignored option: --sysconfdir" | tee -a configure.log; shift ;; + --localstatedir=*) echo "ignored option: --localstatedir" | tee -a configure.log; shift ;; + -c* | --const) zconst=1; shift ;; + *) + echo "unknown option: $1" | tee -a configure.log + echo "$0 --help for help" | tee -a configure.log + leave 1;; + esac +done + +# temporary file name +test=ztest$$ + +# put arguments in log, also put test file in log if used in arguments +show() +{ + case "$*" in + *$test.c*) + echo === $test.c === >> configure.log + cat $test.c >> configure.log + echo === >> configure.log;; + esac + echo $* >> configure.log +} + +# check for gcc vs. cc and set compile and link flags based on the system identified by uname +cat > $test.c <&1` in + *gcc*) gcc=1 ;; +esac + +show $cc -c $test.c +if test "$gcc" -eq 1 && ($cc -c $test.c) >> configure.log 2>&1; then + echo ... using gcc >> configure.log + CC="$cc" + CFLAGS="${CFLAGS--O3} ${ARCHS}" + SFLAGS="${CFLAGS--O3} -fPIC" + LDFLAGS="${LDFLAGS} ${ARCHS}" + if test $build64 -eq 1; then + CFLAGS="${CFLAGS} -m64" + SFLAGS="${SFLAGS} -m64" + fi + if test "${ZLIBGCCWARN}" = "YES"; then + if test "$zconst" -eq 1; then + CFLAGS="${CFLAGS} -Wall -Wextra -Wcast-qual -pedantic -DZLIB_CONST" + else + CFLAGS="${CFLAGS} -Wall -Wextra -pedantic" + fi + fi + if test -z "$uname"; then + uname=`(uname -s || echo unknown) 2>/dev/null` + fi + case "$uname" in + Linux* | linux* | GNU | GNU/* | solaris*) + LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,zlib.map"} ;; + *BSD | *bsd* | DragonFly) + LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,zlib.map"} + LDCONFIG="ldconfig -m" ;; + CYGWIN* | Cygwin* | cygwin* | OS/2*) + EXE='.exe' ;; + MINGW* | mingw*) +# temporary bypass + rm -f $test.[co] $test $test$shared_ext + echo "Please use win32/Makefile.gcc instead." | tee -a configure.log + leave 1 + LDSHARED=${LDSHARED-"$cc -shared"} + LDSHAREDLIBC="" + EXE='.exe' ;; + QNX*) # This is for QNX6. I suppose that the QNX rule below is for QNX2,QNX4 + # (alain.bonnefoy@icbt.com) + LDSHARED=${LDSHARED-"$cc -shared -Wl,-hlibz.so.1"} ;; + HP-UX*) + LDSHARED=${LDSHARED-"$cc -shared $SFLAGS"} + case `(uname -m || echo unknown) 2>/dev/null` in + ia64) + shared_ext='.so' + SHAREDLIB='libz.so' ;; + *) + shared_ext='.sl' + SHAREDLIB='libz.sl' ;; + esac ;; + Darwin* | darwin*) + shared_ext='.dylib' + SHAREDLIB=libz$shared_ext + SHAREDLIBV=libz.$VER$shared_ext + SHAREDLIBM=libz.$VER1$shared_ext + LDSHARED=${LDSHARED-"$cc -dynamiclib -install_name $libdir/$SHAREDLIBM -compatibility_version $VER1 -current_version $VER3"} + if libtool -V 2>&1 | grep Apple > /dev/null; then + AR="libtool" + else + AR="/usr/bin/libtool" + fi + ARFLAGS="-o" ;; + *) LDSHARED=${LDSHARED-"$cc -shared"} ;; + esac +else + # find system name and corresponding cc options + CC=${CC-cc} + gcc=0 + echo ... using $CC >> configure.log + if test -z "$uname"; then + uname=`(uname -sr || echo unknown) 2>/dev/null` + fi + case "$uname" in + HP-UX*) SFLAGS=${CFLAGS-"-O +z"} + CFLAGS=${CFLAGS-"-O"} +# LDSHARED=${LDSHARED-"ld -b +vnocompatwarnings"} + LDSHARED=${LDSHARED-"ld -b"} + case `(uname -m || echo unknown) 2>/dev/null` in + ia64) + shared_ext='.so' + SHAREDLIB='libz.so' ;; + *) + shared_ext='.sl' + SHAREDLIB='libz.sl' ;; + esac ;; + IRIX*) SFLAGS=${CFLAGS-"-ansi -O2 -rpath ."} + CFLAGS=${CFLAGS-"-ansi -O2"} + LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so.1"} ;; + OSF1\ V4*) SFLAGS=${CFLAGS-"-O -std1"} + CFLAGS=${CFLAGS-"-O -std1"} + LDFLAGS="${LDFLAGS} -Wl,-rpath,." + LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so -Wl,-msym -Wl,-rpath,$(libdir) -Wl,-set_version,${VER}:1.0"} ;; + OSF1*) SFLAGS=${CFLAGS-"-O -std1"} + CFLAGS=${CFLAGS-"-O -std1"} + LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so.1"} ;; + QNX*) SFLAGS=${CFLAGS-"-4 -O"} + CFLAGS=${CFLAGS-"-4 -O"} + LDSHARED=${LDSHARED-"cc"} + RANLIB=${RANLIB-"true"} + AR="cc" + ARFLAGS="-A" ;; + SCO_SV\ 3.2*) SFLAGS=${CFLAGS-"-O3 -dy -KPIC "} + CFLAGS=${CFLAGS-"-O3"} + LDSHARED=${LDSHARED-"cc -dy -KPIC -G"} ;; + SunOS\ 5* | solaris*) + LDSHARED=${LDSHARED-"cc -G -h libz$shared_ext.$VER1"} + SFLAGS=${CFLAGS-"-fast -KPIC"} + CFLAGS=${CFLAGS-"-fast"} + if test $build64 -eq 1; then + # old versions of SunPRO/Workshop/Studio don't support -m64, + # but newer ones do. Check for it. + flag64=`$CC -flags | egrep -- '^-m64'` + if test x"$flag64" != x"" ; then + CFLAGS="${CFLAGS} -m64" + SFLAGS="${SFLAGS} -m64" + else + case `(uname -m || echo unknown) 2>/dev/null` in + i86*) + SFLAGS="$SFLAGS -xarch=amd64" + CFLAGS="$CFLAGS -xarch=amd64" ;; + *) + SFLAGS="$SFLAGS -xarch=v9" + CFLAGS="$CFLAGS -xarch=v9" ;; + esac + fi + fi + ;; + SunOS\ 4*) SFLAGS=${CFLAGS-"-O2 -PIC"} + CFLAGS=${CFLAGS-"-O2"} + LDSHARED=${LDSHARED-"ld"} ;; + SunStudio\ 9*) SFLAGS=${CFLAGS-"-fast -xcode=pic32 -xtarget=ultra3 -xarch=v9b"} + CFLAGS=${CFLAGS-"-fast -xtarget=ultra3 -xarch=v9b"} + LDSHARED=${LDSHARED-"cc -xarch=v9b"} ;; + UNIX_System_V\ 4.2.0) + SFLAGS=${CFLAGS-"-KPIC -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"} ;; + UNIX_SV\ 4.2MP) + SFLAGS=${CFLAGS-"-Kconform_pic -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"} ;; + OpenUNIX\ 5) + SFLAGS=${CFLAGS-"-KPIC -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"} ;; + AIX*) # Courtesy of dbakker@arrayasolutions.com + SFLAGS=${CFLAGS-"-O -qmaxmem=8192"} + CFLAGS=${CFLAGS-"-O -qmaxmem=8192"} + LDSHARED=${LDSHARED-"xlc -G"} ;; + # send working options for other systems to zlib@gzip.org + *) SFLAGS=${CFLAGS-"-O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -shared"} ;; + esac +fi + +# destination names for shared library if not defined above +SHAREDLIB=${SHAREDLIB-"libz$shared_ext"} +SHAREDLIBV=${SHAREDLIBV-"libz$shared_ext.$VER"} +SHAREDLIBM=${SHAREDLIBM-"libz$shared_ext.$VER1"} + +echo >> configure.log + +# define functions for testing compiler and library characteristics and logging the results + +cat > $test.c </dev/null; then + try() + { + show $* + test "`( $* ) 2>&1 | tee -a configure.log`" = "" + } + echo - using any output from compiler to indicate an error >> configure.log +else +try() +{ + show $* + ( $* ) >> configure.log 2>&1 + ret=$? + if test $ret -ne 0; then + echo "(exit code "$ret")" >> configure.log + fi + return $ret +} +fi + +tryboth() +{ + show $* + got=`( $* ) 2>&1` + ret=$? + printf %s "$got" >> configure.log + if test $ret -ne 0; then + return $ret + fi + test "$got" = "" +} + +cat > $test.c << EOF +int foo() { return 0; } +EOF +echo "Checking for obsessive-compulsive compiler options..." >> configure.log +if try $CC -c $CFLAGS $test.c; then + : +else + echo "Compiler error reporting is too harsh for $0 (perhaps remove -Werror)." | tee -a configure.log + leave 1 +fi + +echo >> configure.log + +# see if shared library build supported +cat > $test.c <> configure.log + show "$NM $test.o | grep _hello" + if test "`$NM $test.o | grep _hello | tee -a configure.log`" = ""; then + CPP="$CPP -DNO_UNDERLINE" + echo Checking for underline in external names... No. | tee -a configure.log + else + echo Checking for underline in external names... Yes. | tee -a configure.log + fi ;; +esac + +echo >> configure.log + +# check for large file support, and if none, check for fseeko() +cat > $test.c < +off64_t dummy = 0; +EOF +if try $CC -c $CFLAGS -D_LARGEFILE64_SOURCE=1 $test.c; then + CFLAGS="${CFLAGS} -D_LARGEFILE64_SOURCE=1" + SFLAGS="${SFLAGS} -D_LARGEFILE64_SOURCE=1" + ALL="${ALL} all64" + TEST="${TEST} test64" + echo "Checking for off64_t... Yes." | tee -a configure.log + echo "Checking for fseeko... Yes." | tee -a configure.log +else + echo "Checking for off64_t... No." | tee -a configure.log + echo >> configure.log + cat > $test.c < +int main(void) { + fseeko(NULL, 0, 0); + return 0; +} +EOF + if try $CC $CFLAGS -o $test $test.c; then + echo "Checking for fseeko... Yes." | tee -a configure.log + else + CFLAGS="${CFLAGS} -DNO_FSEEKO" + SFLAGS="${SFLAGS} -DNO_FSEEKO" + echo "Checking for fseeko... No." | tee -a configure.log + fi +fi + +echo >> configure.log + +# check for strerror() for use by gz* functions +cat > $test.c < +#include +int main() { return strlen(strerror(errno)); } +EOF +if try $CC $CFLAGS -o $test $test.c; then + echo "Checking for strerror... Yes." | tee -a configure.log +else + CFLAGS="${CFLAGS} -DNO_STRERROR" + SFLAGS="${SFLAGS} -DNO_STRERROR" + echo "Checking for strerror... No." | tee -a configure.log +fi + +# copy clean zconf.h for subsequent edits +cp -p zconf.h.in zconf.h + +echo >> configure.log + +# check for unistd.h and save result in zconf.h +cat > $test.c < +int main() { return 0; } +EOF +if try $CC -c $CFLAGS $test.c; then + sed < zconf.h "/^#ifdef HAVE_UNISTD_H.* may be/s/def HAVE_UNISTD_H\(.*\) may be/ 1\1 was/" > zconf.temp.h + mv zconf.temp.h zconf.h + echo "Checking for unistd.h... Yes." | tee -a configure.log +else + echo "Checking for unistd.h... No." | tee -a configure.log +fi + +echo >> configure.log + +# check for stdarg.h and save result in zconf.h +cat > $test.c < +int main() { return 0; } +EOF +if try $CC -c $CFLAGS $test.c; then + sed < zconf.h "/^#ifdef HAVE_STDARG_H.* may be/s/def HAVE_STDARG_H\(.*\) may be/ 1\1 was/" > zconf.temp.h + mv zconf.temp.h zconf.h + echo "Checking for stdarg.h... Yes." | tee -a configure.log +else + echo "Checking for stdarg.h... No." | tee -a configure.log +fi + +# if the z_ prefix was requested, save that in zconf.h +if test $zprefix -eq 1; then + sed < zconf.h "/#ifdef Z_PREFIX.* may be/s/def Z_PREFIX\(.*\) may be/ 1\1 was/" > zconf.temp.h + mv zconf.temp.h zconf.h + echo >> configure.log + echo "Using z_ prefix on all symbols." | tee -a configure.log +fi + +# if --solo compilation was requested, save that in zconf.h and remove gz stuff from object lists +if test $solo -eq 1; then + sed '/#define ZCONF_H/a\ +#define Z_SOLO + +' < zconf.h > zconf.temp.h + mv zconf.temp.h zconf.h +OBJC='$(OBJZ)' +PIC_OBJC='$(PIC_OBJZ)' +fi + +# if code coverage testing was requested, use older gcc if defined, e.g. "gcc-4.2" on Mac OS X +if test $cover -eq 1; then + CFLAGS="${CFLAGS} -fprofile-arcs -ftest-coverage" + if test -n "$GCC_CLASSIC"; then + CC=$GCC_CLASSIC + fi +fi + +echo >> configure.log + +# conduct a series of tests to resolve eight possible cases of using "vs" or "s" printf functions +# (using stdarg or not), with or without "n" (proving size of buffer), and with or without a +# return value. The most secure result is vsnprintf() with a return value. snprintf() with a +# return value is secure as well, but then gzprintf() will be limited to 20 arguments. +cat > $test.c < +#include +#include "zconf.h" +int main() +{ +#ifndef STDC + choke me +#endif + return 0; +} +EOF +if try $CC -c $CFLAGS $test.c; then + echo "Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf()." | tee -a configure.log + + echo >> configure.log + cat > $test.c < +#include +int mytest(const char *fmt, ...) +{ + char buf[20]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return 0; +} +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + if try $CC $CFLAGS -o $test $test.c; then + echo "Checking for vsnprintf() in stdio.h... Yes." | tee -a configure.log + + echo >> configure.log + cat >$test.c < +#include +int mytest(const char *fmt, ...) +{ + int n; + char buf[20]; + va_list ap; + va_start(ap, fmt); + n = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return n; +} +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + + if try $CC -c $CFLAGS $test.c; then + echo "Checking for return value of vsnprintf()... Yes." | tee -a configure.log + else + CFLAGS="$CFLAGS -DHAS_vsnprintf_void" + SFLAGS="$SFLAGS -DHAS_vsnprintf_void" + echo "Checking for return value of vsnprintf()... No." | tee -a configure.log + echo " WARNING: apparently vsnprintf() does not return a value. zlib" | tee -a configure.log + echo " can build but will be open to possible string-format security" | tee -a configure.log + echo " vulnerabilities." | tee -a configure.log + fi + else + CFLAGS="$CFLAGS -DNO_vsnprintf" + SFLAGS="$SFLAGS -DNO_vsnprintf" + echo "Checking for vsnprintf() in stdio.h... No." | tee -a configure.log + echo " WARNING: vsnprintf() not found, falling back to vsprintf(). zlib" | tee -a configure.log + echo " can build but will be open to possible buffer-overflow security" | tee -a configure.log + echo " vulnerabilities." | tee -a configure.log + + echo >> configure.log + cat >$test.c < +#include +int mytest(const char *fmt, ...) +{ + int n; + char buf[20]; + va_list ap; + va_start(ap, fmt); + n = vsprintf(buf, fmt, ap); + va_end(ap); + return n; +} +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + + if try $CC -c $CFLAGS $test.c; then + echo "Checking for return value of vsprintf()... Yes." | tee -a configure.log + else + CFLAGS="$CFLAGS -DHAS_vsprintf_void" + SFLAGS="$SFLAGS -DHAS_vsprintf_void" + echo "Checking for return value of vsprintf()... No." | tee -a configure.log + echo " WARNING: apparently vsprintf() does not return a value. zlib" | tee -a configure.log + echo " can build but will be open to possible string-format security" | tee -a configure.log + echo " vulnerabilities." | tee -a configure.log + fi + fi +else + echo "Checking whether to use vs[n]printf() or s[n]printf()... using s[n]printf()." | tee -a configure.log + + echo >> configure.log + cat >$test.c < +int mytest() +{ + char buf[20]; + snprintf(buf, sizeof(buf), "%s", "foo"); + return 0; +} +int main() +{ + return (mytest()); +} +EOF + + if try $CC $CFLAGS -o $test $test.c; then + echo "Checking for snprintf() in stdio.h... Yes." | tee -a configure.log + + echo >> configure.log + cat >$test.c < +int mytest() +{ + char buf[20]; + return snprintf(buf, sizeof(buf), "%s", "foo"); +} +int main() +{ + return (mytest()); +} +EOF + + if try $CC -c $CFLAGS $test.c; then + echo "Checking for return value of snprintf()... Yes." | tee -a configure.log + else + CFLAGS="$CFLAGS -DHAS_snprintf_void" + SFLAGS="$SFLAGS -DHAS_snprintf_void" + echo "Checking for return value of snprintf()... No." | tee -a configure.log + echo " WARNING: apparently snprintf() does not return a value. zlib" | tee -a configure.log + echo " can build but will be open to possible string-format security" | tee -a configure.log + echo " vulnerabilities." | tee -a configure.log + fi + else + CFLAGS="$CFLAGS -DNO_snprintf" + SFLAGS="$SFLAGS -DNO_snprintf" + echo "Checking for snprintf() in stdio.h... No." | tee -a configure.log + echo " WARNING: snprintf() not found, falling back to sprintf(). zlib" | tee -a configure.log + echo " can build but will be open to possible buffer-overflow security" | tee -a configure.log + echo " vulnerabilities." | tee -a configure.log + + echo >> configure.log + cat >$test.c < +int mytest() +{ + char buf[20]; + return sprintf(buf, "%s", "foo"); +} +int main() +{ + return (mytest()); +} +EOF + + if try $CC -c $CFLAGS $test.c; then + echo "Checking for return value of sprintf()... Yes." | tee -a configure.log + else + CFLAGS="$CFLAGS -DHAS_sprintf_void" + SFLAGS="$SFLAGS -DHAS_sprintf_void" + echo "Checking for return value of sprintf()... No." | tee -a configure.log + echo " WARNING: apparently sprintf() does not return a value. zlib" | tee -a configure.log + echo " can build but will be open to possible string-format security" | tee -a configure.log + echo " vulnerabilities." | tee -a configure.log + fi + fi +fi + +# see if we can hide zlib internal symbols that are linked between separate source files +if test "$gcc" -eq 1; then + echo >> configure.log + cat > $test.c <> configure.log +echo ALL = $ALL >> configure.log +echo AR = $AR >> configure.log +echo ARFLAGS = $ARFLAGS >> configure.log +echo CC = $CC >> configure.log +echo CFLAGS = $CFLAGS >> configure.log +echo CPP = $CPP >> configure.log +echo EXE = $EXE >> configure.log +echo LDCONFIG = $LDCONFIG >> configure.log +echo LDFLAGS = $LDFLAGS >> configure.log +echo LDSHARED = $LDSHARED >> configure.log +echo LDSHAREDLIBC = $LDSHAREDLIBC >> configure.log +echo OBJC = $OBJC >> configure.log +echo PIC_OBJC = $PIC_OBJC >> configure.log +echo RANLIB = $RANLIB >> configure.log +echo SFLAGS = $SFLAGS >> configure.log +echo SHAREDLIB = $SHAREDLIB >> configure.log +echo SHAREDLIBM = $SHAREDLIBM >> configure.log +echo SHAREDLIBV = $SHAREDLIBV >> configure.log +echo STATICLIB = $STATICLIB >> configure.log +echo TEST = $TEST >> configure.log +echo VER = $VER >> configure.log +echo Z_U4 = $Z_U4 >> configure.log +echo exec_prefix = $exec_prefix >> configure.log +echo includedir = $includedir >> configure.log +echo libdir = $libdir >> configure.log +echo mandir = $mandir >> configure.log +echo prefix = $prefix >> configure.log +echo sharedlibdir = $sharedlibdir >> configure.log +echo uname = $uname >> configure.log + +# udpate Makefile with the configure results +sed < Makefile.in " +/^CC *=/s#=.*#=$CC# +/^CFLAGS *=/s#=.*#=$CFLAGS# +/^SFLAGS *=/s#=.*#=$SFLAGS# +/^LDFLAGS *=/s#=.*#=$LDFLAGS# +/^LDSHARED *=/s#=.*#=$LDSHARED# +/^CPP *=/s#=.*#=$CPP# +/^STATICLIB *=/s#=.*#=$STATICLIB# +/^SHAREDLIB *=/s#=.*#=$SHAREDLIB# +/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV# +/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM# +/^AR *=/s#=.*#=$AR# +/^ARFLAGS *=/s#=.*#=$ARFLAGS# +/^RANLIB *=/s#=.*#=$RANLIB# +/^LDCONFIG *=/s#=.*#=$LDCONFIG# +/^LDSHAREDLIBC *=/s#=.*#=$LDSHAREDLIBC# +/^EXE *=/s#=.*#=$EXE# +/^prefix *=/s#=.*#=$prefix# +/^exec_prefix *=/s#=.*#=$exec_prefix# +/^libdir *=/s#=.*#=$libdir# +/^sharedlibdir *=/s#=.*#=$sharedlibdir# +/^includedir *=/s#=.*#=$includedir# +/^mandir *=/s#=.*#=$mandir# +/^OBJC *=/s#=.*#= $OBJC# +/^PIC_OBJC *=/s#=.*#= $PIC_OBJC# +/^all: */s#:.*#: $ALL# +/^test: */s#:.*#: $TEST# +" > Makefile + +# create zlib.pc with the configure results +sed < zlib.pc.in " +/^CC *=/s#=.*#=$CC# +/^CFLAGS *=/s#=.*#=$CFLAGS# +/^CPP *=/s#=.*#=$CPP# +/^LDSHARED *=/s#=.*#=$LDSHARED# +/^STATICLIB *=/s#=.*#=$STATICLIB# +/^SHAREDLIB *=/s#=.*#=$SHAREDLIB# +/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV# +/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM# +/^AR *=/s#=.*#=$AR# +/^ARFLAGS *=/s#=.*#=$ARFLAGS# +/^RANLIB *=/s#=.*#=$RANLIB# +/^EXE *=/s#=.*#=$EXE# +/^prefix *=/s#=.*#=$prefix# +/^exec_prefix *=/s#=.*#=$exec_prefix# +/^libdir *=/s#=.*#=$libdir# +/^sharedlibdir *=/s#=.*#=$sharedlibdir# +/^includedir *=/s#=.*#=$includedir# +/^mandir *=/s#=.*#=$mandir# +/^LDFLAGS *=/s#=.*#=$LDFLAGS# +" | sed -e " +s/\@VERSION\@/$VER/g; +" > zlib.pc + +# done +leave 0 diff --git a/source/Irrlicht/zlib/crc32.c b/source/Irrlicht/zlib/crc32.c new file mode 100644 index 00000000..95a30f1c --- /dev/null +++ b/source/Irrlicht/zlib/crc32.c @@ -0,0 +1,425 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + + DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h. + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Definitions for doing the crc four data bytes at a time. */ +#if !defined(NOBYFOUR) && defined(Z_U4) +# define BYFOUR +#endif +#ifdef BYFOUR + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); +local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2)); + + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local z_crc_t FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const z_crc_t FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + z_crc_t c; + int n, k; + z_crc_t poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0; + for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++) + poly |= (z_crc_t)1 << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (z_crc_t)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = ZSWAP32(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = ZSWAP32(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const z_crc_t FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const z_crc_t FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", + (unsigned long)(table[n]), + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const z_crc_t FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const z_crc_t FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + uInt len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + z_crc_t endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register z_crc_t c; + register const z_crc_t FAR *buf4; + + c = (z_crc_t)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const z_crc_t FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register z_crc_t c; + register const z_crc_t FAR *buf4; + + c = ZSWAP32((z_crc_t)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const z_crc_t FAR *)(const void FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(ZSWAP32(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +local uLong crc32_combine_(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off64_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case (also disallow negative lengths) */ + if (len2 <= 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + return crc32_combine_(crc1, crc2, len2); +} + +uLong ZEXPORT crc32_combine64(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off64_t len2; +{ + return crc32_combine_(crc1, crc2, len2); +} diff --git a/source/Irrlicht/zlib/crc32.h b/source/Irrlicht/zlib/crc32.h new file mode 100644 index 00000000..b7e25cf9 --- /dev/null +++ b/source/Irrlicht/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const z_crc_t FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/source/Irrlicht/zlib/deflate.c b/source/Irrlicht/zlib/deflate.c new file mode 100644 index 00000000..89b47f12 --- /dev/null +++ b/source/Irrlicht/zlib/deflate.c @@ -0,0 +1,1967 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://tools.ietf.org/html/rfc1951 + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.8 Copyright 1995-2013 Jean-loup Gailly and Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local block_state deflate_rle OF((deflate_state *s, int flush)); +local block_state deflate_huff OF((deflate_state *s, int flush)); +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ +#define RANK(f) (((f) << 1) - ((f) > 4 ? 9 : 0)) + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->high_water = 0; /* nothing written to s->window yet */ + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt str, n; + int wrap; + unsigned avail; + z_const unsigned char *next; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL) + return Z_STREAM_ERROR; + s = strm->state; + wrap = s->wrap; + if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) + return Z_STREAM_ERROR; + + /* when using zlib wrappers, compute Adler-32 for provided dictionary */ + if (wrap == 1) + strm->adler = adler32(strm->adler, dictionary, dictLength); + s->wrap = 0; /* avoid computing Adler-32 in read_buf */ + + /* if dictionary would fill window, just replace the history */ + if (dictLength >= s->w_size) { + if (wrap == 0) { /* already empty otherwise */ + CLEAR_HASH(s); + s->strstart = 0; + s->block_start = 0L; + s->insert = 0; + } + dictionary += dictLength - s->w_size; /* use the tail */ + dictLength = s->w_size; + } + + /* insert dictionary into window and hash */ + avail = strm->avail_in; + next = strm->next_in; + strm->avail_in = dictLength; + strm->next_in = (z_const Bytef *)dictionary; + fill_window(s); + while (s->lookahead >= MIN_MATCH) { + str = s->strstart; + n = s->lookahead - (MIN_MATCH-1); + do { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + } while (--n); + s->strstart = str; + s->lookahead = MIN_MATCH-1; + fill_window(s); + } + s->strstart += s->lookahead; + s->block_start = (long)s->strstart; + s->insert = s->lookahead; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + strm->next_in = next; + strm->avail_in = avail; + s->wrap = wrap; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateResetKeep (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + int ret; + + ret = deflateResetKeep(strm); + if (ret == Z_OK) + lm_init(strm->state); + return ret; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePending (strm, pending, bits) + unsigned *pending; + int *bits; + z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (pending != Z_NULL) + *pending = strm->state->pending; + if (bits != Z_NULL) + *bits = strm->state->bi_valid; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + deflate_state *s; + int put; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3)) + return Z_BUF_ERROR; + do { + put = Buf_size - s->bi_valid; + if (put > bits) + put = bits; + s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); + s->bi_valid += put; + _tr_flush_bits(s); + value >>= put; + bits -= put; + } while (bits); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if ((strategy != s->strategy || func != configuration_table[level].func) && + strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_BLOCK); + if (err == Z_BUF_ERROR && s->pending == 0) + err = Z_OK; + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds for + * every combination of windowBits and memLevel. But even the conservative + * upper bound of about 14% expansion does not seem onerous for output buffer + * allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong complen, wraplen; + Bytef *str; + + /* conservative upper bound for compressed data */ + complen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; + + /* if can't get parameters, return conservative bound plus zlib wrapper */ + if (strm == Z_NULL || strm->state == Z_NULL) + return complen + 6; + + /* compute wrapper length */ + s = strm->state; + switch (s->wrap) { + case 0: /* raw deflate */ + wraplen = 0; + break; + case 1: /* zlib wrapper */ + wraplen = 6 + (s->strstart ? 4 : 0); + break; + case 2: /* gzip wrapper */ + wraplen = 18; + if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ + if (s->gzhead->extra != Z_NULL) + wraplen += 2 + s->gzhead->extra_len; + str = s->gzhead->name; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + str = s->gzhead->comment; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + if (s->gzhead->hcrc) + wraplen += 2; + } + break; + default: /* for compiler happiness */ + wraplen = 6; + } + + /* if not default parameters, return conservative bound */ + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return complen + wraplen; + + /* default settings: return tight bound for that case */ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13 - 6 + wraplen; +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len; + deflate_state *s = strm->state; + + _tr_flush_bits(s); + len = s->pending; + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, s->pending_out, len); + strm->next_out += len; + s->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + s->pending -= len; + if (s->pending == 0) { + s->pending_out = s->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_BLOCK || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == Z_NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != Z_NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != Z_NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != Z_NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != Z_NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : + (s->strategy == Z_RLE ? deflate_rle(s, flush) : + (*(configuration_table[s->level].func))(s, flush)); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + if (s->lookahead == 0) { + s->strstart = 0; + s->block_start = 0L; + s->insert = 0; + } + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + zmemcpy(buf, strm->next_in, len); + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, buf, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, buf, len); + } +#endif + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->insert = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ + +#else /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for FASTEST only + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#endif /* FASTEST */ + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) break; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead + s->insert >= MIN_MATCH) { + uInt str = s->strstart - s->insert; + s->ins_h = s->window[str]; + UPDATE_HASH(s, s->ins_h, s->window[str + 1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + while (s->insert) { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + s->insert--; + if (s->lookahead + s->insert < MIN_MATCH) + break; + } + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ + if (s->high_water < s->window_size) { + ulg curr = s->strstart + (ulg)(s->lookahead); + ulg init; + + if (s->high_water < curr) { + /* Previous high water mark below current data -- zero WIN_INIT + * bytes or up to end of window, whichever is less. + */ + init = s->window_size - curr; + if (init > WIN_INIT) + init = WIN_INIT; + zmemzero(s->window + curr, (unsigned)init); + s->high_water = curr + init; + } + else if (s->high_water < (ulg)curr + WIN_INIT) { + /* High water mark at or above current data, but below current data + * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up + * to end of window, whichever is less. + */ + init = (ulg)curr + WIN_INIT - s->high_water; + if (init > s->window_size - s->high_water) + init = s->window_size - s->high_water; + zmemzero(s->window + s->high_water, (unsigned)init); + s->high_water += init; + } + } + + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "not enough room for search"); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, last) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (last)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, last) { \ + FLUSH_BLOCK_ONLY(s, last); \ + if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if ((long)s->strstart > s->block_start) + FLUSH_BLOCK(s, 0); + return block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return block_done; +} +#endif /* FASTEST */ + +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt prev; /* byte at distance one to match */ + Bytef *scan, *strend; /* scan goes up to strend for length of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest run, plus one for the unrolled loop. + */ + if (s->lookahead <= MAX_MATCH) { + fill_window(s); + if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + s->match_length = 0; + if (s->lookahead >= MIN_MATCH && s->strstart > 0) { + scan = s->window + s->strstart - 1; + prev = *scan; + if (prev == *++scan && prev == *++scan && prev == *++scan) { + strend = s->window + s->strstart + MAX_MATCH; + do { + } while (prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + scan < strend); + s->match_length = MAX_MATCH - (int)(strend - scan); + if (s->match_length > s->lookahead) + s->match_length = s->lookahead; + } + Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, s->match_length); + + _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + s->strstart += s->match_length; + s->match_length = 0; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return block_done; +} + +/* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ +local block_state deflate_huff(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s->lookahead == 0) { + fill_window(s); + if (s->lookahead == 0) { + if (flush == Z_NO_FLUSH) + return need_more; + break; /* flush the current block */ + } + } + + /* Output a literal byte */ + s->match_length = 0; + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return block_done; +} diff --git a/source/Irrlicht/zlib/deflate.h b/source/Irrlicht/zlib/deflate.h new file mode 100644 index 00000000..bb64c573 --- /dev/null +++ b/source/Irrlicht/zlib/deflate.h @@ -0,0 +1,346 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2012 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define Buf_size 16 +/* size of bit buffer in bi_buf */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* can only be DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to suppress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + uInt insert; /* bytes at end of window left to insert */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + + ulg high_water; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + +#define WIN_INIT MAX_MATCH +/* Number of bytes after end of data in window to initialize in order to avoid + memory checker errors from longest match routines */ + + /* in trees.c */ +void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); +int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); +void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); +void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); +void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch ZLIB_INTERNAL _length_code[]; + extern uch ZLIB_INTERNAL _dist_code[]; +#else + extern const uch ZLIB_INTERNAL _length_code[]; + extern const uch ZLIB_INTERNAL _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/source/Irrlicht/zlib/gzclose.c b/source/Irrlicht/zlib/gzclose.c new file mode 100644 index 00000000..caeb99a3 --- /dev/null +++ b/source/Irrlicht/zlib/gzclose.c @@ -0,0 +1,25 @@ +/* gzclose.c -- zlib gzclose() function + * Copyright (C) 2004, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* gzclose() is in a separate file so that it is linked in only if it is used. + That way the other gzclose functions can be used instead to avoid linking in + unneeded compression or decompression routines. */ +int ZEXPORT gzclose(file) + gzFile file; +{ +#ifndef NO_GZCOMPRESS + gz_statep state; + + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file); +#else + return gzclose_r(file); +#endif +} diff --git a/source/Irrlicht/zlib/gzguts.h b/source/Irrlicht/zlib/gzguts.h new file mode 100644 index 00000000..d87659d0 --- /dev/null +++ b/source/Irrlicht/zlib/gzguts.h @@ -0,0 +1,209 @@ +/* gzguts.h -- zlib internal header definitions for gz* operations + * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef _LARGEFILE64_SOURCE +# ifndef _LARGEFILE_SOURCE +# define _LARGEFILE_SOURCE 1 +# endif +# ifdef _FILE_OFFSET_BITS +# undef _FILE_OFFSET_BITS +# endif +#endif + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include +#include "zlib.h" +#ifdef STDC +# include +# include +# include +#endif +#include + +#ifdef _WIN32 +# include +#endif + +#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) +# include +#endif + +#ifdef WINAPI_FAMILY +# define open _open +# define read _read +# define write _write +# define close _close +#endif + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS +/* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 +/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) +# define vsnprintf _vsnprintf +# endif +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +# ifdef VMS +# define NO_vsnprintf +# endif +# ifdef __OS400__ +# define NO_vsnprintf +# endif +# ifdef __MVS__ +# define NO_vsnprintf +# endif +#endif + +/* unlike snprintf (which is required in C99, yet still not supported by + Microsoft more than a decade later!), _snprintf does not guarantee null + termination of the result -- however this is only used in gzlib.c where + the result is assured to fit in the space provided */ +#ifdef _MSC_VER +# define snprintf _snprintf +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +/* gz* functions always use library allocation functions */ +#ifndef STDC + extern voidp malloc OF((uInt size)); + extern void free OF((voidpf ptr)); +#endif + +/* get errno and strerror definition */ +#if defined UNDER_CE +# include +# define zstrerror() gz_strwinerror((DWORD)GetLastError()) +#else +# ifndef NO_STRERROR +# include +# define zstrerror() strerror(errno) +# else +# define zstrerror() "stdio error (consult errno)" +# endif +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); +#endif + +/* default memLevel */ +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif + +/* default i/o buffer size -- double this for output when reading (this and + twice this must be able to fit in an unsigned type) */ +#define GZBUFSIZE 8192 + +/* gzip modes, also provide a little integrity check on the passed structure */ +#define GZ_NONE 0 +#define GZ_READ 7247 +#define GZ_WRITE 31153 +#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ + +/* values for gz_state how */ +#define LOOK 0 /* look for a gzip header */ +#define COPY 1 /* copy input directly */ +#define GZIP 2 /* decompress a gzip stream */ + +/* internal gzip file state data structure */ +typedef struct { + /* exposed contents for gzgetc() macro */ + struct gzFile_s x; /* "x" for exposed */ + /* x.have: number of bytes available at x.next */ + /* x.next: next output data to deliver or write */ + /* x.pos: current position in uncompressed data */ + /* used for both reading and writing */ + int mode; /* see gzip modes above */ + int fd; /* file descriptor */ + char *path; /* path or fd for error messages */ + unsigned size; /* buffer size, zero if not allocated yet */ + unsigned want; /* requested buffer size, default is GZBUFSIZE */ + unsigned char *in; /* input buffer */ + unsigned char *out; /* output buffer (double-sized when reading) */ + int direct; /* 0 if processing gzip, 1 if transparent */ + /* just for reading */ + int how; /* 0: get header, 1: copy, 2: decompress */ + z_off64_t start; /* where the gzip data started, for rewinding */ + int eof; /* true if end of input file reached */ + int past; /* true if read requested past end */ + /* just for writing */ + int level; /* compression level */ + int strategy; /* compression strategy */ + /* seek request */ + z_off64_t skip; /* amount to skip (already rewound if backwards) */ + int seek; /* true if seek request pending */ + /* error information */ + int err; /* error code */ + char *msg; /* error message */ + /* zlib inflate or deflate stream */ + z_stream strm; /* stream structure in-place (not a pointer) */ +} gz_state; +typedef gz_state FAR *gz_statep; + +/* shared functions */ +void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); +#if defined UNDER_CE +char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); +#endif + +/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t + value -- needed when comparing unsigned to z_off64_t, which is signed + (possible z_off64_t types off_t, off64_t, and long are all signed) */ +#ifdef INT_MAX +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) +#else +unsigned ZLIB_INTERNAL gz_intmax OF((void)); +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) +#endif diff --git a/source/Irrlicht/zlib/gzlib.c b/source/Irrlicht/zlib/gzlib.c new file mode 100644 index 00000000..fae202ef --- /dev/null +++ b/source/Irrlicht/zlib/gzlib.c @@ -0,0 +1,634 @@ +/* gzlib.c -- zlib functions common to reading and writing gzip files + * Copyright (C) 2004, 2010, 2011, 2012, 2013 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +#if defined(_WIN32) && !defined(__BORLANDC__) +# define LSEEK _lseeki64 +#else +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define LSEEK lseek64 +#else +# define LSEEK lseek +#endif +#endif + +/* Local functions */ +local void gz_reset OF((gz_statep)); +local gzFile gz_open OF((const void *, int, const char *)); + +#if defined UNDER_CE + +/* Map the Windows error number in ERROR to a locale-dependent error message + string and return a pointer to it. Typically, the values for ERROR come + from GetLastError. + + The string pointed to shall not be modified by the application, but may be + overwritten by a subsequent call to gz_strwinerror + + The gz_strwinerror function does not change the current setting of + GetLastError. */ +char ZLIB_INTERNAL *gz_strwinerror (error) + DWORD error; +{ + static char buf[1024]; + + wchar_t *msgbuf; + DWORD lasterr = GetLastError(); + DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + error, + 0, /* Default language */ + (LPVOID)&msgbuf, + 0, + NULL); + if (chars != 0) { + /* If there is an \r\n appended, zap it. */ + if (chars >= 2 + && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { + chars -= 2; + msgbuf[chars] = 0; + } + + if (chars > sizeof (buf) - 1) { + chars = sizeof (buf) - 1; + msgbuf[chars] = 0; + } + + wcstombs(buf, msgbuf, chars + 1); + LocalFree(msgbuf); + } + else { + sprintf(buf, "unknown win32 error (%ld)", error); + } + + SetLastError(lasterr); + return buf; +} + +#endif /* UNDER_CE */ + +/* Reset gzip file state */ +local void gz_reset(state) + gz_statep state; +{ + state->x.have = 0; /* no output data available */ + if (state->mode == GZ_READ) { /* for reading ... */ + state->eof = 0; /* not at end of file */ + state->past = 0; /* have not read past end yet */ + state->how = LOOK; /* look for gzip header */ + } + state->seek = 0; /* no seek request pending */ + gz_error(state, Z_OK, NULL); /* clear error */ + state->x.pos = 0; /* no uncompressed data yet */ + state->strm.avail_in = 0; /* no input data yet */ +} + +/* Open a gzip file either by name or file descriptor. */ +local gzFile gz_open(path, fd, mode) + const void *path; + int fd; + const char *mode; +{ + gz_statep state; + size_t len; + int oflag; +#ifdef O_CLOEXEC + int cloexec = 0; +#endif +#ifdef O_EXCL + int exclusive = 0; +#endif + + /* check input */ + if (path == NULL) + return NULL; + + /* allocate gzFile structure to return */ + state = (gz_statep)malloc(sizeof(gz_state)); + if (state == NULL) + return NULL; + state->size = 0; /* no buffers allocated yet */ + state->want = GZBUFSIZE; /* requested buffer size */ + state->msg = NULL; /* no error message yet */ + + /* interpret mode */ + state->mode = GZ_NONE; + state->level = Z_DEFAULT_COMPRESSION; + state->strategy = Z_DEFAULT_STRATEGY; + state->direct = 0; + while (*mode) { + if (*mode >= '0' && *mode <= '9') + state->level = *mode - '0'; + else + switch (*mode) { + case 'r': + state->mode = GZ_READ; + break; +#ifndef NO_GZCOMPRESS + case 'w': + state->mode = GZ_WRITE; + break; + case 'a': + state->mode = GZ_APPEND; + break; +#endif + case '+': /* can't read and write at the same time */ + free(state); + return NULL; + case 'b': /* ignore -- will request binary anyway */ + break; +#ifdef O_CLOEXEC + case 'e': + cloexec = 1; + break; +#endif +#ifdef O_EXCL + case 'x': + exclusive = 1; + break; +#endif + case 'f': + state->strategy = Z_FILTERED; + break; + case 'h': + state->strategy = Z_HUFFMAN_ONLY; + break; + case 'R': + state->strategy = Z_RLE; + break; + case 'F': + state->strategy = Z_FIXED; + break; + case 'T': + state->direct = 1; + break; + default: /* could consider as an error, but just ignore */ + ; + } + mode++; + } + + /* must provide an "r", "w", or "a" */ + if (state->mode == GZ_NONE) { + free(state); + return NULL; + } + + /* can't force transparent read */ + if (state->mode == GZ_READ) { + if (state->direct) { + free(state); + return NULL; + } + state->direct = 1; /* for empty file */ + } + + /* save the path name for error messages */ +#ifdef _WIN32 + if (fd == -2) { + len = wcstombs(NULL, path, 0); + if (len == (size_t)-1) + len = 0; + } + else +#endif + len = strlen((const char *)path); + state->path = (char *)malloc(len + 1); + if (state->path == NULL) { + free(state); + return NULL; + } +#ifdef _WIN32 + if (fd == -2) + if (len) + wcstombs(state->path, path, len + 1); + else + *(state->path) = 0; + else +#endif +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(state->path, len + 1, "%s", (const char *)path); +#else + strcpy(state->path, path); +#endif + + /* compute the flags for open() */ + oflag = +#ifdef O_LARGEFILE + O_LARGEFILE | +#endif +#ifdef O_BINARY + O_BINARY | +#endif +#ifdef O_CLOEXEC + (cloexec ? O_CLOEXEC : 0) | +#endif + (state->mode == GZ_READ ? + O_RDONLY : + (O_WRONLY | O_CREAT | +#ifdef O_EXCL + (exclusive ? O_EXCL : 0) | +#endif + (state->mode == GZ_WRITE ? + O_TRUNC : + O_APPEND))); + + /* open the file with the appropriate flags (or just use fd) */ + state->fd = fd > -1 ? fd : ( +#ifdef _WIN32 + fd == -2 ? _wopen(path, oflag, 0666) : +#endif + open((const char *)path, oflag, 0666)); + if (state->fd == -1) { + free(state->path); + free(state); + return NULL; + } + if (state->mode == GZ_APPEND) + state->mode = GZ_WRITE; /* simplify later checks */ + + /* save the current position for rewinding (only if reading) */ + if (state->mode == GZ_READ) { + state->start = LSEEK(state->fd, 0, SEEK_CUR); + if (state->start == -1) state->start = 0; + } + + /* initialize stream */ + gz_reset(state); + + /* return stream */ + return (gzFile)state; +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzopen(path, mode) + const char *path; + const char *mode; +{ + return gz_open(path, -1, mode); +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzopen64(path, mode) + const char *path; + const char *mode; +{ + return gz_open(path, -1, mode); +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzdopen(fd, mode) + int fd; + const char *mode; +{ + char *path; /* identifier for error messages */ + gzFile gz; + + if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) + return NULL; +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(path, 7 + 3 * sizeof(int), "", fd); /* for debugging */ +#else + sprintf(path, "", fd); /* for debugging */ +#endif + gz = gz_open(path, fd, mode); + free(path); + return gz; +} + +/* -- see zlib.h -- */ +#ifdef _WIN32 +gzFile ZEXPORT gzopen_w(path, mode) + const wchar_t *path; + const char *mode; +{ + return gz_open(path, -2, mode); +} +#endif + +/* -- see zlib.h -- */ +int ZEXPORT gzbuffer(file, size) + gzFile file; + unsigned size; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* make sure we haven't already allocated memory */ + if (state->size != 0) + return -1; + + /* check and set requested size */ + if (size < 2) + size = 2; /* need two bytes to check magic header */ + state->want = size; + return 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzrewind(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* back up and start over */ + if (LSEEK(state->fd, state->start, SEEK_SET) == -1) + return -1; + gz_reset(state); + return 0; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gzseek64(file, offset, whence) + gzFile file; + z_off64_t offset; + int whence; +{ + unsigned n; + z_off64_t ret; + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* check that there's no error */ + if (state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + + /* can only seek from start or relative to current position */ + if (whence != SEEK_SET && whence != SEEK_CUR) + return -1; + + /* normalize offset to a SEEK_CUR specification */ + if (whence == SEEK_SET) + offset -= state->x.pos; + else if (state->seek) + offset += state->skip; + state->seek = 0; + + /* if within raw area while reading, just go there */ + if (state->mode == GZ_READ && state->how == COPY && + state->x.pos + offset >= 0) { + ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR); + if (ret == -1) + return -1; + state->x.have = 0; + state->eof = 0; + state->past = 0; + state->seek = 0; + gz_error(state, Z_OK, NULL); + state->strm.avail_in = 0; + state->x.pos += offset; + return state->x.pos; + } + + /* calculate skip amount, rewinding if needed for back seek when reading */ + if (offset < 0) { + if (state->mode != GZ_READ) /* writing -- can't go backwards */ + return -1; + offset += state->x.pos; + if (offset < 0) /* before start of file! */ + return -1; + if (gzrewind(file) == -1) /* rewind, then skip to offset */ + return -1; + } + + /* if reading, skip what's in output buffer (one less gzgetc() check) */ + if (state->mode == GZ_READ) { + n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? + (unsigned)offset : state->x.have; + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + offset -= n; + } + + /* request skip (if not zero) */ + if (offset) { + state->seek = 1; + state->skip = offset; + } + return state->x.pos + offset; +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gzseek(file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + z_off64_t ret; + + ret = gzseek64(file, (z_off64_t)offset, whence); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gztell64(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* return position */ + return state->x.pos + (state->seek ? state->skip : 0); +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gztell(file) + gzFile file; +{ + z_off64_t ret; + + ret = gztell64(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gzoffset64(file) + gzFile file; +{ + z_off64_t offset; + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* compute and return effective offset in file */ + offset = LSEEK(state->fd, 0, SEEK_CUR); + if (offset == -1) + return -1; + if (state->mode == GZ_READ) /* reading */ + offset -= state->strm.avail_in; /* don't count buffered input */ + return offset; +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gzoffset(file) + gzFile file; +{ + z_off64_t ret; + + ret = gzoffset64(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzeof(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return 0; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return 0; + + /* return end-of-file state */ + return state->mode == GZ_READ ? state->past : 0; +} + +/* -- see zlib.h -- */ +const char * ZEXPORT gzerror(file, errnum) + gzFile file; + int *errnum; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return NULL; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return NULL; + + /* return error information */ + if (errnum != NULL) + *errnum = state->err; + return state->err == Z_MEM_ERROR ? "out of memory" : + (state->msg == NULL ? "" : state->msg); +} + +/* -- see zlib.h -- */ +void ZEXPORT gzclearerr(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return; + + /* clear error and end-of-file */ + if (state->mode == GZ_READ) { + state->eof = 0; + state->past = 0; + } + gz_error(state, Z_OK, NULL); +} + +/* Create an error message in allocated memory and set state->err and + state->msg accordingly. Free any previous error message already there. Do + not try to free or allocate space if the error is Z_MEM_ERROR (out of + memory). Simply save the error message as a static string. If there is an + allocation failure constructing the error message, then convert the error to + out of memory. */ +void ZLIB_INTERNAL gz_error(state, err, msg) + gz_statep state; + int err; + const char *msg; +{ + /* free previously allocated message and clear */ + if (state->msg != NULL) { + if (state->err != Z_MEM_ERROR) + free(state->msg); + state->msg = NULL; + } + + /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */ + if (err != Z_OK && err != Z_BUF_ERROR) + state->x.have = 0; + + /* set error code, and if no message, then done */ + state->err = err; + if (msg == NULL) + return; + + /* for an out of memory error, return literal string when requested */ + if (err == Z_MEM_ERROR) + return; + + /* construct error message with path */ + if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) == + NULL) { + state->err = Z_MEM_ERROR; + return; + } +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, + "%s%s%s", state->path, ": ", msg); +#else + strcpy(state->msg, state->path); + strcat(state->msg, ": "); + strcat(state->msg, msg); +#endif + return; +} + +#ifndef INT_MAX +/* portably return maximum value for an int (when limits.h presumed not + available) -- we need to do this to cover cases where 2's complement not + used, since C standard permits 1's complement and sign-bit representations, + otherwise we could just use ((unsigned)-1) >> 1 */ +unsigned ZLIB_INTERNAL gz_intmax() +{ + unsigned p, q; + + p = 1; + do { + q = p; + p <<= 1; + p++; + } while (p > q); + return q >> 1; +} +#endif diff --git a/source/Irrlicht/zlib/gzread.c b/source/Irrlicht/zlib/gzread.c new file mode 100644 index 00000000..bf4538eb --- /dev/null +++ b/source/Irrlicht/zlib/gzread.c @@ -0,0 +1,594 @@ +/* gzread.c -- zlib functions for reading gzip files + * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* Local functions */ +local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); +local int gz_avail OF((gz_statep)); +local int gz_look OF((gz_statep)); +local int gz_decomp OF((gz_statep)); +local int gz_fetch OF((gz_statep)); +local int gz_skip OF((gz_statep, z_off64_t)); + +/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from + state->fd, and update state->eof, state->err, and state->msg as appropriate. + This function needs to loop on read(), since read() is not guaranteed to + read the number of bytes requested, depending on the type of descriptor. */ +local int gz_load(state, buf, len, have) + gz_statep state; + unsigned char *buf; + unsigned len; + unsigned *have; +{ + int ret; + + *have = 0; + do { + ret = read(state->fd, buf + *have, len - *have); + if (ret <= 0) + break; + *have += ret; + } while (*have < len); + if (ret < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + if (ret == 0) + state->eof = 1; + return 0; +} + +/* Load up input buffer and set eof flag if last data loaded -- return -1 on + error, 0 otherwise. Note that the eof flag is set when the end of the input + file is reached, even though there may be unused data in the buffer. Once + that data has been used, no more attempts will be made to read the file. + If strm->avail_in != 0, then the current data is moved to the beginning of + the input buffer, and then the remainder of the buffer is loaded with the + available data from the input file. */ +local int gz_avail(state) + gz_statep state; +{ + unsigned got; + z_streamp strm = &(state->strm); + + if (state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + if (state->eof == 0) { + if (strm->avail_in) { /* copy what's there to the start */ + unsigned char *p = state->in; + unsigned const char *q = strm->next_in; + unsigned n = strm->avail_in; + do { + *p++ = *q++; + } while (--n); + } + if (gz_load(state, state->in + strm->avail_in, + state->size - strm->avail_in, &got) == -1) + return -1; + strm->avail_in += got; + strm->next_in = state->in; + } + return 0; +} + +/* Look for gzip header, set up for inflate or copy. state->x.have must be 0. + If this is the first time in, allocate required memory. state->how will be + left unchanged if there is no more input data available, will be set to COPY + if there is no gzip header and direct copying will be performed, or it will + be set to GZIP for decompression. If direct copying, then leftover input + data from the input buffer will be copied to the output buffer. In that + case, all further file reads will be directly to either the output buffer or + a user buffer. If decompressing, the inflate state will be initialized. + gz_look() will return 0 on success or -1 on failure. */ +local int gz_look(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); + + /* allocate read buffers and inflate memory */ + if (state->size == 0) { + /* allocate buffers */ + state->in = (unsigned char *)malloc(state->want); + state->out = (unsigned char *)malloc(state->want << 1); + if (state->in == NULL || state->out == NULL) { + if (state->out != NULL) + free(state->out); + if (state->in != NULL) + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + state->size = state->want; + + /* allocate inflate memory */ + state->strm.zalloc = Z_NULL; + state->strm.zfree = Z_NULL; + state->strm.opaque = Z_NULL; + state->strm.avail_in = 0; + state->strm.next_in = Z_NULL; + if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */ + free(state->out); + free(state->in); + state->size = 0; + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + } + + /* get at least the magic bytes in the input buffer */ + if (strm->avail_in < 2) { + if (gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) + return 0; + } + + /* look for gzip magic bytes -- if there, do gzip decoding (note: there is + a logical dilemma here when considering the case of a partially written + gzip file, to wit, if a single 31 byte is written, then we cannot tell + whether this is a single-byte file, or just a partially written gzip + file -- for here we assume that if a gzip file is being written, then + the header will be written in a single operation, so that reading a + single byte is sufficient indication that it is not a gzip file) */ + if (strm->avail_in > 1 && + strm->next_in[0] == 31 && strm->next_in[1] == 139) { + inflateReset(strm); + state->how = GZIP; + state->direct = 0; + return 0; + } + + /* no gzip header -- if we were decoding gzip before, then this is trailing + garbage. Ignore the trailing garbage and finish. */ + if (state->direct == 0) { + strm->avail_in = 0; + state->eof = 1; + state->x.have = 0; + return 0; + } + + /* doing raw i/o, copy any leftover input to output -- this assumes that + the output buffer is larger than the input buffer, which also assures + space for gzungetc() */ + state->x.next = state->out; + if (strm->avail_in) { + memcpy(state->x.next, strm->next_in, strm->avail_in); + state->x.have = strm->avail_in; + strm->avail_in = 0; + } + state->how = COPY; + state->direct = 1; + return 0; +} + +/* Decompress from input to the provided next_out and avail_out in the state. + On return, state->x.have and state->x.next point to the just decompressed + data. If the gzip stream completes, state->how is reset to LOOK to look for + the next gzip stream or raw data, once state->x.have is depleted. Returns 0 + on success, -1 on failure. */ +local int gz_decomp(state) + gz_statep state; +{ + int ret = Z_OK; + unsigned had; + z_streamp strm = &(state->strm); + + /* fill output buffer up to end of deflate stream */ + had = strm->avail_out; + do { + /* get more input for inflate() */ + if (strm->avail_in == 0 && gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) { + gz_error(state, Z_BUF_ERROR, "unexpected end of file"); + break; + } + + /* decompress and handle errors */ + ret = inflate(strm, Z_NO_FLUSH); + if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { + gz_error(state, Z_STREAM_ERROR, + "internal error: inflate stream corrupt"); + return -1; + } + if (ret == Z_MEM_ERROR) { + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ + gz_error(state, Z_DATA_ERROR, + strm->msg == NULL ? "compressed data error" : strm->msg); + return -1; + } + } while (strm->avail_out && ret != Z_STREAM_END); + + /* update available output */ + state->x.have = had - strm->avail_out; + state->x.next = strm->next_out - state->x.have; + + /* if the gzip stream completed successfully, look for another */ + if (ret == Z_STREAM_END) + state->how = LOOK; + + /* good decompression */ + return 0; +} + +/* Fetch data and put it in the output buffer. Assumes state->x.have is 0. + Data is either copied from the input file or decompressed from the input + file depending on state->how. If state->how is LOOK, then a gzip header is + looked for to determine whether to copy or decompress. Returns -1 on error, + otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the + end of the input file has been reached and all data has been processed. */ +local int gz_fetch(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); + + do { + switch(state->how) { + case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ + if (gz_look(state) == -1) + return -1; + if (state->how == LOOK) + return 0; + break; + case COPY: /* -> COPY */ + if (gz_load(state, state->out, state->size << 1, &(state->x.have)) + == -1) + return -1; + state->x.next = state->out; + return 0; + case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */ + strm->avail_out = state->size << 1; + strm->next_out = state->out; + if (gz_decomp(state) == -1) + return -1; + } + } while (state->x.have == 0 && (!state->eof || strm->avail_in)); + return 0; +} + +/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ +local int gz_skip(state, len) + gz_statep state; + z_off64_t len; +{ + unsigned n; + + /* skip over len bytes or reach end-of-file, whichever comes first */ + while (len) + /* skip over whatever is in output buffer */ + if (state->x.have) { + n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? + (unsigned)len : state->x.have; + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + len -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && state->strm.avail_in == 0) + break; + + /* need more data to skip -- load up output buffer */ + else { + /* get more output, looking for header if required */ + if (gz_fetch(state) == -1) + return -1; + } + return 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzread(file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + unsigned got, n; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids the flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); + return -1; + } + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return -1; + } + + /* get len bytes to buf, or less than len if at the end */ + got = 0; + do { + /* first just try copying data from the output buffer */ + if (state->x.have) { + n = state->x.have > len ? len : state->x.have; + memcpy(buf, state->x.next, n); + state->x.next += n; + state->x.have -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && strm->avail_in == 0) { + state->past = 1; /* tried to read past end */ + break; + } + + /* need output data -- for small len or new stream load up our output + buffer */ + else if (state->how == LOOK || len < (state->size << 1)) { + /* get more output, looking for header if required */ + if (gz_fetch(state) == -1) + return -1; + continue; /* no progress yet -- go back to copy above */ + /* the copy above assures that we will leave with space in the + output buffer, allowing at least one gzungetc() to succeed */ + } + + /* large len -- read directly into user buffer */ + else if (state->how == COPY) { /* read directly */ + if (gz_load(state, (unsigned char *)buf, len, &n) == -1) + return -1; + } + + /* large len -- decompress directly into user buffer */ + else { /* state->how == GZIP */ + strm->avail_out = len; + strm->next_out = (unsigned char *)buf; + if (gz_decomp(state) == -1) + return -1; + n = state->x.have; + state->x.have = 0; + } + + /* update progress */ + len -= n; + buf = (char *)buf + n; + got += n; + state->x.pos += n; + } while (len); + + /* return number of bytes read into user buffer (will fit in int) */ + return (int)got; +} + +/* -- see zlib.h -- */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +#else +# undef gzgetc +#endif +int ZEXPORT gzgetc(file) + gzFile file; +{ + int ret; + unsigned char buf[1]; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* try output buffer (no need to check for skip request) */ + if (state->x.have) { + state->x.have--; + state->x.pos++; + return *(state->x.next)++; + } + + /* nothing there -- try gzread() */ + ret = gzread(file, buf, 1); + return ret < 1 ? -1 : buf[0]; +} + +int ZEXPORT gzgetc_(file) +gzFile file; +{ + return gzgetc(file); +} + +/* -- see zlib.h -- */ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return -1; + } + + /* can't push EOF */ + if (c < 0) + return -1; + + /* if output buffer empty, put byte at end (allows more pushing) */ + if (state->x.have == 0) { + state->x.have = 1; + state->x.next = state->out + (state->size << 1) - 1; + state->x.next[0] = c; + state->x.pos--; + state->past = 0; + return c; + } + + /* if no room, give up (must have already done a gzungetc()) */ + if (state->x.have == (state->size << 1)) { + gz_error(state, Z_DATA_ERROR, "out of room to push characters"); + return -1; + } + + /* slide output data if needed and insert byte before existing data */ + if (state->x.next == state->out) { + unsigned char *src = state->out + state->x.have; + unsigned char *dest = state->out + (state->size << 1); + while (src > state->out) + *--dest = *--src; + state->x.next = dest; + } + state->x.have++; + state->x.next--; + state->x.next[0] = c; + state->x.pos--; + state->past = 0; + return c; +} + +/* -- see zlib.h -- */ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + unsigned left, n; + char *str; + unsigned char *eol; + gz_statep state; + + /* check parameters and get internal structure */ + if (file == NULL || buf == NULL || len < 1) + return NULL; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return NULL; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return NULL; + } + + /* copy output bytes up to new line or len - 1, whichever comes first -- + append a terminating zero to the string (we don't check for a zero in + the contents, let the user worry about that) */ + str = buf; + left = (unsigned)len - 1; + if (left) do { + /* assure that something is in the output buffer */ + if (state->x.have == 0 && gz_fetch(state) == -1) + return NULL; /* error */ + if (state->x.have == 0) { /* end of file */ + state->past = 1; /* read past end */ + break; /* return what we have */ + } + + /* look for end-of-line in current output buffer */ + n = state->x.have > left ? left : state->x.have; + eol = (unsigned char *)memchr(state->x.next, '\n', n); + if (eol != NULL) + n = (unsigned)(eol - state->x.next) + 1; + + /* copy through end-of-line, or remainder if not found */ + memcpy(buf, state->x.next, n); + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + left -= n; + buf += n; + } while (left && eol == NULL); + + /* return terminated string, or if nothing, end of file */ + if (buf == str) + return NULL; + buf[0] = 0; + return str; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzdirect(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* if the state is not known, but we can find out, then do so (this is + mainly for right after a gzopen() or gzdopen()) */ + if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) + (void)gz_look(state); + + /* return 1 if transparent, 0 if processing a gzip stream */ + return state->direct; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzclose_r(file) + gzFile file; +{ + int ret, err; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're reading */ + if (state->mode != GZ_READ) + return Z_STREAM_ERROR; + + /* free memory and close file */ + if (state->size) { + inflateEnd(&(state->strm)); + free(state->out); + free(state->in); + } + err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; + gz_error(state, Z_OK, NULL); + free(state->path); + ret = close(state->fd); + free(state); + return ret ? Z_ERRNO : err; +} diff --git a/source/Irrlicht/zlib/gzwrite.c b/source/Irrlicht/zlib/gzwrite.c new file mode 100644 index 00000000..aa767fbf --- /dev/null +++ b/source/Irrlicht/zlib/gzwrite.c @@ -0,0 +1,577 @@ +/* gzwrite.c -- zlib functions for writing gzip files + * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* Local functions */ +local int gz_init OF((gz_statep)); +local int gz_comp OF((gz_statep, int)); +local int gz_zero OF((gz_statep, z_off64_t)); + +/* Initialize state for writing a gzip file. Mark initialization by setting + state->size to non-zero. Return -1 on failure or 0 on success. */ +local int gz_init(state) + gz_statep state; +{ + int ret; + z_streamp strm = &(state->strm); + + /* allocate input buffer */ + state->in = (unsigned char *)malloc(state->want); + if (state->in == NULL) { + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* only need output buffer and deflate state if compressing */ + if (!state->direct) { + /* allocate output buffer */ + state->out = (unsigned char *)malloc(state->want); + if (state->out == NULL) { + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* allocate deflate memory, set up for gzip compression */ + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; + strm->opaque = Z_NULL; + ret = deflateInit2(strm, state->level, Z_DEFLATED, + MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); + if (ret != Z_OK) { + free(state->out); + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + } + + /* mark state as initialized */ + state->size = state->want; + + /* initialize write buffer if compressing */ + if (!state->direct) { + strm->avail_out = state->size; + strm->next_out = state->out; + state->x.next = strm->next_out; + } + return 0; +} + +/* Compress whatever is at avail_in and next_in and write to the output file. + Return -1 if there is an error writing to the output file, otherwise 0. + flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, + then the deflate() state is reset to start a new gzip stream. If gz->direct + is true, then simply write to the output file without compressing, and + ignore flush. */ +local int gz_comp(state, flush) + gz_statep state; + int flush; +{ + int ret, got; + unsigned have; + z_streamp strm = &(state->strm); + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return -1; + + /* write directly if requested */ + if (state->direct) { + got = write(state->fd, strm->next_in, strm->avail_in); + if (got < 0 || (unsigned)got != strm->avail_in) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + strm->avail_in = 0; + return 0; + } + + /* run deflate() on provided input until it produces no more output */ + ret = Z_OK; + do { + /* write out current buffer contents if full, or if flushing, but if + doing Z_FINISH then don't write until we get to Z_STREAM_END */ + if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && + (flush != Z_FINISH || ret == Z_STREAM_END))) { + have = (unsigned)(strm->next_out - state->x.next); + if (have && ((got = write(state->fd, state->x.next, have)) < 0 || + (unsigned)got != have)) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + if (strm->avail_out == 0) { + strm->avail_out = state->size; + strm->next_out = state->out; + } + state->x.next = strm->next_out; + } + + /* compress */ + have = strm->avail_out; + ret = deflate(strm, flush); + if (ret == Z_STREAM_ERROR) { + gz_error(state, Z_STREAM_ERROR, + "internal error: deflate stream corrupt"); + return -1; + } + have -= strm->avail_out; + } while (have); + + /* if that completed a deflate stream, allow another to start */ + if (flush == Z_FINISH) + deflateReset(strm); + + /* all done, no errors */ + return 0; +} + +/* Compress len zeros to output. Return -1 on error, 0 on success. */ +local int gz_zero(state, len) + gz_statep state; + z_off64_t len; +{ + int first; + unsigned n; + z_streamp strm = &(state->strm); + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + + /* compress len zeros (len guaranteed > 0) */ + first = 1; + while (len) { + n = GT_OFF(state->size) || (z_off64_t)state->size > len ? + (unsigned)len : state->size; + if (first) { + memset(state->in, 0, n); + first = 0; + } + strm->avail_in = n; + strm->next_in = state->in; + state->x.pos += n; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + len -= n; + } + return 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzwrite(file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + unsigned put = len; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids the flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); + return 0; + } + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* for small len, copy to input buffer, otherwise compress directly */ + if (len < state->size) { + /* copy to input buffer, compress when full */ + do { + unsigned have, copy; + + if (strm->avail_in == 0) + strm->next_in = state->in; + have = (unsigned)((strm->next_in + strm->avail_in) - state->in); + copy = state->size - have; + if (copy > len) + copy = len; + memcpy(state->in + have, buf, copy); + strm->avail_in += copy; + state->x.pos += copy; + buf = (const char *)buf + copy; + len -= copy; + if (len && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + } while (len); + } + else { + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* directly compress user buffer to file */ + strm->avail_in = len; + strm->next_in = (z_const Bytef *)buf; + state->x.pos += len; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + } + + /* input was all buffered or compressed (put will fit in int) */ + return (int)put; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned have; + unsigned char buf[1]; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return -1; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* try writing to input buffer for speed (state->size == 0 if buffer not + initialized) */ + if (state->size) { + if (strm->avail_in == 0) + strm->next_in = state->in; + have = (unsigned)((strm->next_in + strm->avail_in) - state->in); + if (have < state->size) { + state->in[have] = c; + strm->avail_in++; + state->x.pos++; + return c & 0xff; + } + } + + /* no room in buffer or not initialized, use gz_write() */ + buf[0] = c; + if (gzwrite(file, buf, 1) != 1) + return -1; + return c & 0xff; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzputs(file, str) + gzFile file; + const char *str; +{ + int ret; + unsigned len; + + /* write string */ + len = (unsigned)strlen(str); + ret = gzwrite(file, str, len); + return ret == 0 && len != 0 ? -1 : ret; +} + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +#include + +/* -- see zlib.h -- */ +int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) +{ + int size, len; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* do the printf() into the input buffer, put length in len */ + size = (int)(state->size); + state->in[size - 1] = 0; +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf((char *)(state->in), format, va); + for (len = 0; len < size; len++) + if (state->in[len] == 0) break; +# else + len = vsprintf((char *)(state->in), format, va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf((char *)(state->in), size, format, va); + len = strlen((char *)(state->in)); +# else + len = vsnprintf((char *)(state->in), size, format, va); +# endif +#endif + + /* check that printf() results fit in buffer */ + if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) + return 0; + + /* update buffer and position, defer compression until needed */ + strm->avail_in = (unsigned)len; + strm->next_in = state->in; + state->x.pos += len; + return len; +} + +int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) +{ + va_list va; + int ret; + + va_start(va, format); + ret = gzvprintf(file, format, va); + va_end(va); + return ret; +} + +#else /* !STDC && !Z_HAVE_STDARG_H */ + +/* -- see zlib.h -- */ +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + int size, len; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that can really pass pointer in ints */ + if (sizeof(int) != sizeof(void *)) + return 0; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* do the printf() into the input buffer, put length in len */ + size = (int)(state->size); + state->in[size - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < size; len++) + if (state->in[len] == 0) break; +# else + len = sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen((char *)(state->in)); +# else + len = snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, + a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, + a19, a20); +# endif +#endif + + /* check that printf() results fit in buffer */ + if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) + return 0; + + /* update buffer and position, defer compression until needed */ + strm->avail_in = (unsigned)len; + strm->next_in = state->in; + state->x.pos += len; + return len; +} + +#endif + +/* -- see zlib.h -- */ +int ZEXPORT gzflush(file, flush) + gzFile file; + int flush; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* check flush parameter */ + if (flush < 0 || flush > Z_FINISH) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* compress remaining data with requested flush */ + gz_comp(state, flush); + return state->err; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzsetparams(file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* if no change is requested, then do nothing */ + if (level == state->level && strategy == state->strategy) + return Z_OK; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* change compression parameters for subsequent input */ + if (state->size) { + /* flush previous input with previous parameters before changing */ + if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1) + return state->err; + deflateParams(strm, level, strategy); + } + state->level = level; + state->strategy = strategy; + return Z_OK; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzclose_w(file) + gzFile file; +{ + int ret = Z_OK; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're writing */ + if (state->mode != GZ_WRITE) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + ret = state->err; + } + + /* flush, free memory, and close file */ + if (gz_comp(state, Z_FINISH) == -1) + ret = state->err; + if (state->size) { + if (!state->direct) { + (void)deflateEnd(&(state->strm)); + free(state->out); + } + free(state->in); + } + gz_error(state, Z_OK, NULL); + free(state->path); + if (close(state->fd) == -1) + ret = Z_ERRNO; + free(state); + return ret; +} diff --git a/source/Irrlicht/zlib/infback.c b/source/Irrlicht/zlib/infback.c new file mode 100644 index 00000000..aa42a004 --- /dev/null +++ b/source/Irrlicht/zlib/infback.c @@ -0,0 +1,640 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2011 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->wnext = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + state->length = (unsigned)here.val; + + /* process literal */ + if (here.op == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/source/Irrlicht/zlib/inffast.c b/source/Irrlicht/zlib/inffast.c new file mode 100644 index 00000000..38446d8a --- /dev/null +++ b/source/Irrlicht/zlib/inffast.c @@ -0,0 +1,340 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2008, 2010, 2013 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - M68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void ZLIB_INTERNAL inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *in; /* local strm->next_in */ + z_const unsigned char FAR *last; /* have enough input while in < last */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code here; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + wnext = state->wnext; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + here = lcode[hold & lmask]; + dolen: + op = (unsigned)(here.bits); + hold >>= op; + bits -= op; + op = (unsigned)(here.op); + if (op == 0) { /* literal */ + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + PUP(out) = (unsigned char)(here.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(here.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + here = dcode[hold & dmask]; + dodist: + op = (unsigned)(here.bits); + hold >>= op; + bits -= op; + op = (unsigned)(here.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(here.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state->sane) { + strm->msg = + (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (len <= op - whave) { + do { + PUP(out) = 0; + } while (--len); + continue; + } + len -= op - whave; + do { + PUP(out) = 0; + } while (--op > whave); + if (op == 0) { + from = out - dist; + do { + PUP(out) = PUP(from); + } while (--len); + continue; + } +#endif + } + from = window - OFF; + if (wnext == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (wnext < op) { /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (wnext < len) { /* some from start of window */ + op = wnext; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += wnext - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + here = dcode[here.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + here = lcode[here.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and wnext == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/source/Irrlicht/zlib/inffast.h b/source/Irrlicht/zlib/inffast.h new file mode 100644 index 00000000..e1e6db4a --- /dev/null +++ b/source/Irrlicht/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/source/Irrlicht/zlib/inffixed.h b/source/Irrlicht/zlib/inffixed.h new file mode 100644 index 00000000..0b29a5ad --- /dev/null +++ b/source/Irrlicht/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. + It is part of the implementation of this library and is + subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/source/Irrlicht/zlib/inflate.c b/source/Irrlicht/zlib/inflate.c new file mode 100644 index 00000000..e43d9992 --- /dev/null +++ b/source/Irrlicht/zlib/inflate.c @@ -0,0 +1,1512 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2012 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common wnext == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, + unsigned copy)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateResetKeep(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + if (state->wrap) /* to support ill-conceived Java test suite */ + strm->adler = state->wrap & 1; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + state->sane = 1; + state->back = -1; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + state->wsize = 0; + state->whave = 0; + state->wnext = 0; + return inflateResetKeep(strm); +} + +int ZEXPORT inflateReset2(strm, windowBits) +z_streamp strm; +int windowBits; +{ + int wrap; + struct inflate_state FAR *state; + + /* get the state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + wrap = 0; + windowBits = -windowBits; + } + else { + wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) + windowBits &= 15; +#endif + } + + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) + return Z_STREAM_ERROR; + if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { + ZFREE(strm, state->window); + state->window = Z_NULL; + } + + /* update state and reset the rest of it */ + state->wrap = wrap; + state->wbits = (unsigned)windowBits; + return inflateReset(strm); +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + int ret; + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->window = Z_NULL; + ret = inflateReset2(strm, windowBits); + if (ret != Z_OK) { + ZFREE(strm, state); + strm->state = Z_NULL; + } + return ret; +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits < 0) { + state->hold = 0; + state->bits = 0; + return Z_OK; + } + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, + state.lencode[low].bits, state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, end, copy) +z_streamp strm; +const Bytef *end; +unsigned copy; +{ + struct inflate_state FAR *state; + unsigned dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->wnext = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + if (copy >= state->wsize) { + zmemcpy(state->window, end - state->wsize, state->wsize); + state->wnext = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->wnext; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->wnext, end - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, end - copy, copy); + state->wnext = copy; + state->whave = state->wsize; + } + else { + state->wnext += dist; + if (state->wnext == state->wsize) state->wnext = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (state->wbits == 0) + state->wbits = len; + else if (len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = ZSWAP32(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN_; /* decode codes */ + if (flush == Z_TREES) { + DROPBITS(2); + goto inf_leave; + } + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY_; + if (flush == Z_TREES) goto inf_leave; + case COPY_: + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (const code FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN_; + if (flush == Z_TREES) goto inf_leave; + case LEN_: + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + if (state->mode == TYPE) + state->back = -1; + break; + } + state->back = 0; + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + state->length = (unsigned)here.val; + if ((int)(here.op) == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + state->mode = LIT; + break; + } + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->back = -1; + state->mode = TYPE; + break; + } + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(here.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->was = state->length; + state->mode = DIST; + case DIST: + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + state->extra = (unsigned)(here.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->whave) { + if (state->sane) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + Trace((stderr, "inflate.c too far\n")); + copy -= state->whave; + if (copy > state->length) copy = state->length; + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = 0; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; +#endif + } + if (copy > state->wnext) { + copy -= state->wnext; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->wnext - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + ZSWAP32(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (out != strm->avail_out && state->mode < BAD && + (state->mode < CHECK || flush != Z_FINISH))) + if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0) + + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength) +z_streamp strm; +Bytef *dictionary; +uInt *dictLength; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* copy dictionary */ + if (state->whave && dictionary != Z_NULL) { + zmemcpy(dictionary, state->window + state->wnext, + state->whave - state->wnext); + zmemcpy(dictionary + state->whave - state->wnext, + state->window, state->wnext); + } + if (dictLength != Z_NULL) + *dictLength = state->whave; + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long dictid; + int ret; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary identifier */ + if (state->mode == DICT) { + dictid = adler32(0L, Z_NULL, 0); + dictid = adler32(dictid, dictionary, dictLength); + if (dictid != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window using updatewindow(), which will amend the + existing dictionary if appropriate */ + ret = updatewindow(strm, dictionary + dictLength, dictLength); + if (ret) { + state->mode = MEM; + return Z_MEM_ERROR; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +const unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); + zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} + +int ZEXPORT inflateUndermine(strm, subvert) +z_streamp strm; +int subvert; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + state->sane = !subvert; +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + return Z_OK; +#else + state->sane = 1; + return Z_DATA_ERROR; +#endif +} + +long ZEXPORT inflateMark(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16; + state = (struct inflate_state FAR *)strm->state; + return ((long)(state->back) << 16) + + (state->mode == COPY ? state->length : + (state->mode == MATCH ? state->was - state->length : 0)); +} diff --git a/source/Irrlicht/zlib/inflate.h b/source/Irrlicht/zlib/inflate.h new file mode 100644 index 00000000..a8ef4287 --- /dev/null +++ b/source/Irrlicht/zlib/inflate.h @@ -0,0 +1,122 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2009 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY_, /* i/o: same as COPY below, but only first time in */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN_, /* i: same as LEN below, but only first time in */ + LEN, /* i: waiting for length/lit/eob code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to BAD or MEM on error -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) or (raw) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> + HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + (raw) -> TYPEDO + Read deflate blocks: + TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK + STORED -> COPY_ -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN_ + LEN_ -> LEN + Read deflate codes in fixed or dynamic block: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 10K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ + int sane; /* if false, allow invalid distance too far */ + int back; /* bits back of last unprocessed length/lit */ + unsigned was; /* initial length of match */ +}; diff --git a/source/Irrlicht/zlib/inftrees.c b/source/Irrlicht/zlib/inftrees.c new file mode 100644 index 00000000..9bd12184 --- /dev/null +++ b/source/Irrlicht/zlib/inftrees.c @@ -0,0 +1,306 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2013 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.8 Copyright 1995-2013 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code here; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)1; + here.val = (unsigned short)0; + *(*table)++ = here; /* make a table to force an error */ + *(*table)++ = here; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + here.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + here.op = (unsigned char)0; + here.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + here.op = (unsigned char)(extra[work[sym]]); + here.val = base[work[sym]]; + } + else { + here.op = (unsigned char)(32 + 64); /* end of block */ + here.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = here; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if (huff != 0) { + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)(len - drop); + here.val = (unsigned short)0; + next[huff] = here; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/source/Irrlicht/zlib/inftrees.h b/source/Irrlicht/zlib/inftrees.h new file mode 100644 index 00000000..a685d8c6 --- /dev/null +++ b/source/Irrlicht/zlib/inftrees.h @@ -0,0 +1,62 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of the dynamic table. The maximum number of code structures is + 1444, which is the sum of 852 for literal/length codes and 592 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distribtution. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns returns 852, and "enough 30 6 15" for distance codes returns 592. + The initial root table size (9 or 6) is found in the fifth argument of the + inflate_table() calls in inflate.c and infback.c. If the root table size is + changed, then these maximum sizes would be need to be recalculated and + updated. */ +#define ENOUGH_LENS 852 +#define ENOUGH_DISTS 592 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/source/Irrlicht/zlib/treebuild.xml b/source/Irrlicht/zlib/treebuild.xml new file mode 100644 index 00000000..38d29d75 --- /dev/null +++ b/source/Irrlicht/zlib/treebuild.xml @@ -0,0 +1,116 @@ + + + + zip compression library + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/Irrlicht/zlib/trees.c b/source/Irrlicht/zlib/trees.c new file mode 100644 index 00000000..d5b32d1c --- /dev/null +++ b/source/Irrlicht/zlib/trees.c @@ -0,0 +1,1226 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2012 Jean-loup Gailly + * detect_data_type() function provided freely by Cosmin Truta, 2006 + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, const ct_data *ltree, + const ct_data *dtree)); +local int detect_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (ush)value << s->bi_valid; + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= (ush)value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (ush)val << s->bi_valid;\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (ush)(value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ +#ifdef NO_INIT_GLOBAL_POINTERS + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; +#endif + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, + "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void ZLIB_INTERNAL _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int last; /* one if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) + */ +void ZLIB_INTERNAL _tr_flush_bits(s) + deflate_state *s; +{ + bi_flush(s); +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + */ +void ZLIB_INTERNAL _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int last; /* one if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (s->strm->data_type == Z_UNKNOWN) + s->strm->data_type = detect_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, last); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+last, 3); + compress_block(s, (const ct_data *)static_ltree, + (const ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+last, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (const ct_data *)s->dyn_ltree, + (const ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (last) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*last)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int ZLIB_INTERNAL _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + const ct_data *ltree; /* literal tree */ + const ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); +} + +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "black list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local int detect_data_type(s) + deflate_state *s; +{ + /* black_mask is the bit mask of black-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + unsigned long black_mask = 0xf3ffc07fUL; + int n; + + /* Check for non-textual ("black-listed") bytes. */ + for (n = 0; n <= 31; n++, black_mask >>= 1) + if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0)) + return Z_BINARY; + + /* Check for textual ("white-listed") bytes. */ + if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 + || s->dyn_ltree[13].Freq != 0) + return Z_TEXT; + for (n = 32; n < LITERALS; n++) + if (s->dyn_ltree[n].Freq != 0) + return Z_TEXT; + + /* There are no "black-listed" or "white-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/source/Irrlicht/zlib/trees.h b/source/Irrlicht/zlib/trees.h new file mode 100644 index 00000000..ce8f6204 --- /dev/null +++ b/source/Irrlicht/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/source/Irrlicht/zlib/uncompr.c b/source/Irrlicht/zlib/uncompr.c new file mode 100644 index 00000000..6cfc6dd6 --- /dev/null +++ b/source/Irrlicht/zlib/uncompr.c @@ -0,0 +1,59 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003, 2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (z_const Bytef *)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/source/Irrlicht/zlib/zconf.h b/source/Irrlicht/zlib/zconf.h new file mode 100644 index 00000000..add1675f --- /dev/null +++ b/source/Irrlicht/zlib/zconf.h @@ -0,0 +1,511 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2013 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzvprintf z_gzvprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetHeader z_inflateGetHeader +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateSetDictionary z_inflateSetDictionary +# define inflateGetDictionary z_inflateGetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateResetKeep z_inflateResetKeep +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) +# define Z_HAVE_UNISTD_H +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/source/Irrlicht/zlib/zconf.h.cmakein b/source/Irrlicht/zlib/zconf.h.cmakein new file mode 100644 index 00000000..043019cd --- /dev/null +++ b/source/Irrlicht/zlib/zconf.h.cmakein @@ -0,0 +1,513 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2013 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H +#cmakedefine Z_PREFIX +#cmakedefine Z_HAVE_UNISTD_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzvprintf z_gzvprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetHeader z_inflateGetHeader +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateSetDictionary z_inflateSetDictionary +# define inflateGetDictionary z_inflateGetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateResetKeep z_inflateResetKeep +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) +# define Z_HAVE_UNISTD_H +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/source/Irrlicht/zlib/zconf.h.in b/source/Irrlicht/zlib/zconf.h.in new file mode 100644 index 00000000..9987a775 --- /dev/null +++ b/source/Irrlicht/zlib/zconf.h.in @@ -0,0 +1,511 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2013 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzvprintf z_gzvprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetHeader z_inflateGetHeader +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateSetDictionary z_inflateSetDictionary +# define inflateGetDictionary z_inflateGetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateResetKeep z_inflateResetKeep +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) +# define Z_HAVE_UNISTD_H +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/source/Irrlicht/zlib/zlib.3 b/source/Irrlicht/zlib/zlib.3 new file mode 100644 index 00000000..0160e62b --- /dev/null +++ b/source/Irrlicht/zlib/zlib.3 @@ -0,0 +1,151 @@ +.TH ZLIB 3 "28 Apr 2013" +.SH NAME +zlib \- compression/decompression library +.SH SYNOPSIS +[see +.I zlib.h +for full description] +.SH DESCRIPTION +The +.I zlib +library is a general purpose data compression library. +The code is thread safe, assuming that the standard library functions +used are thread safe, such as memory allocation routines. +It provides in-memory compression and decompression functions, +including integrity checks of the uncompressed data. +This version of the library supports only one compression method (deflation) +but other algorithms may be added later +with the same stream interface. +.LP +Compression can be done in a single step if the buffers are large enough +or can be done by repeated calls of the compression function. +In the latter case, +the application must provide more input and/or consume the output +(providing more output space) before each call. +.LP +The library also supports reading and writing files in +.IR gzip (1) +(.gz) format +with an interface similar to that of stdio. +.LP +The library does not install any signal handler. +The decoder checks the consistency of the compressed data, +so the library should never crash even in the case of corrupted input. +.LP +All functions of the compression library are documented in the file +.IR zlib.h . +The distribution source includes examples of use of the library +in the files +.I test/example.c +and +.IR test/minigzip.c, +as well as other examples in the +.IR examples/ +directory. +.LP +Changes to this version are documented in the file +.I ChangeLog +that accompanies the source. +.LP +.I zlib +is available in Java using the java.util.zip package: +.IP +http://java.sun.com/developer/technicalArticles/Programming/compression/ +.LP +A Perl interface to +.IR zlib , +written by Paul Marquess (pmqs@cpan.org), +is available at CPAN (Comprehensive Perl Archive Network) sites, +including: +.IP +http://search.cpan.org/~pmqs/IO-Compress-Zlib/ +.LP +A Python interface to +.IR zlib , +written by A.M. Kuchling (amk@magnet.com), +is available in Python 1.5 and later versions: +.IP +http://docs.python.org/library/zlib.html +.LP +.I zlib +is built into +.IR tcl: +.IP +http://wiki.tcl.tk/4610 +.LP +An experimental package to read and write files in .zip format, +written on top of +.I zlib +by Gilles Vollant (info@winimage.com), +is available at: +.IP +http://www.winimage.com/zLibDll/minizip.html +and also in the +.I contrib/minizip +directory of the main +.I zlib +source distribution. +.SH "SEE ALSO" +The +.I zlib +web site can be found at: +.IP +http://zlib.net/ +.LP +The data format used by the zlib library is described by RFC +(Request for Comments) 1950 to 1952 in the files: +.IP +http://tools.ietf.org/html/rfc1950 (for the zlib header and trailer format) +.br +http://tools.ietf.org/html/rfc1951 (for the deflate compressed data format) +.br +http://tools.ietf.org/html/rfc1952 (for the gzip header and trailer format) +.LP +Mark Nelson wrote an article about +.I zlib +for the Jan. 1997 issue of Dr. Dobb's Journal; +a copy of the article is available at: +.IP +http://marknelson.us/1997/01/01/zlib-engine/ +.SH "REPORTING PROBLEMS" +Before reporting a problem, +please check the +.I zlib +web site to verify that you have the latest version of +.IR zlib ; +otherwise, +obtain the latest version and see if the problem still exists. +Please read the +.I zlib +FAQ at: +.IP +http://zlib.net/zlib_faq.html +.LP +before asking for help. +Send questions and/or comments to zlib@gzip.org, +or (for the Windows DLL version) to Gilles Vollant (info@winimage.com). +.SH AUTHORS +Version 1.2.8 +Copyright (C) 1995-2013 Jean-loup Gailly (jloup@gzip.org) +and Mark Adler (madler@alumni.caltech.edu). +.LP +This software is provided "as-is," +without any express or implied warranty. +In no event will the authors be held liable for any damages +arising from the use of this software. +See the distribution directory with respect to requirements +governing redistribution. +The deflate format used by +.I zlib +was defined by Phil Katz. +The deflate and +.I zlib +specifications were written by L. Peter Deutsch. +Thanks to all the people who reported problems and suggested various +improvements in +.IR zlib ; +who are too numerous to cite here. +.LP +UNIX manual page by R. P. C. Rodgers, +U.S. National Library of Medicine (rodgers@nlm.nih.gov). +.\" end of man page diff --git a/source/Irrlicht/zlib/zlib.3.pdf b/source/Irrlicht/zlib/zlib.3.pdf new file mode 100644 index 00000000..485306cd Binary files /dev/null and b/source/Irrlicht/zlib/zlib.3.pdf differ diff --git a/source/Irrlicht/zlib/zlib.h b/source/Irrlicht/zlib/zlib.h new file mode 100644 index 00000000..1d98298f --- /dev/null +++ b/source/Irrlicht/zlib/zlib.h @@ -0,0 +1,1768 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.8, April 28th, 2013 + + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.8" +#define ZLIB_VERNUM 0x1280 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 8 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + z_const Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total number of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total number of bytes output so far */ + + z_const char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use in the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). Some + output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed code + block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the stream + are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least the + value returned by deflateBound (see below). Then deflate is guaranteed to + return Z_STREAM_END. If not enough output space is provided, deflate will + not return Z_STREAM_END, and it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect the + compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the + exact value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit() does not process any header information -- that is deferred + until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing will + resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the Adler-32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained, so applications that need that information should + instead use raw inflate, see inflateInit2() below, or inflateBack() and + perform their own processing of the gzip header and trailer. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + producted so far. The CRC-32 is checked against the gzip trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by the + caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The + compressor and decompressor must use exactly the same dictionary (see + inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. The + stream will keep the same compression level and any other attributes that + may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression level is changed, the input available so far is + compressed with the old level (and may be flushed); the new level will take + effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to be + compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if + strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. +*/ + +ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, + unsigned *pending, + int *bits)); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must insure that the dictionary + that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similary, if dictLength is Z_NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible full flush point has been found, + Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point + has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. + In the success case, the application may save the current current value of + total_in which indicates where valid compressed data was found. In the + error case, the application may repeatedly call inflateSync, providing more + input each time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, + int windowBits)); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above or -1 << 16 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the parameters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, + z_const unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the normal + behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + +#ifndef Z_SOLO + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed buffer. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. +*/ + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); + + Opens a gzip (.gz) file for reading or writing. The mode parameter is as + in fopen ("rb" or "wb") but can also include a compression level ("wb9") or + a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only + compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' + for fixed code compression as in "wb9F". (See the description of + deflateInit2 for more information about the strategy parameter.) 'T' will + request transparent writing or appending with no compression and not using + the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen associates a gzFile with the file descriptor fd. File descriptors + are obtained from calls like open, dup, creat, pipe or fileno (if the file + has been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +/* + Set the internal buffer size used by this library's functions. The + default buffer size is 8192 bytes. This function must be called after + gzopen() or gzdopen(), and before any other calls that read or write the + file. The buffer memory allocation is always deferred to the first read or + write. Two buffers are allocated, either both of the specified size when + writing, or one of the specified size and the other twice that size when + reading. A larger buffer size of, for example, 64K or 128K bytes will + noticeably increase the speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. If + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. +*/ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes written or 0 in case of + error. +*/ + +ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the arguments to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or 0 in case of error. The number of + uncompressed bytes written is limited to 8191, or one less than the buffer + size given to gzbuffer(). The caller should assure that this limit is not + exceeded. If it is exceeded, then gzprintf() will return an error (0) with + nothing written. In this case, there may also be a buffer overflow with + unpredictable consequences, which is possible only if zlib was compiled with + the insecure functions sprintf() or vsprintf() because the secure snprintf() + or vsnprintf() functions were not available. This can be determined using + zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or a + newline character is read and transferred to buf, or an end-of-file + condition is encountered. If any characters are read or if len == 1, the + string is terminated with a null character. If no characters are read due + to an end-of-file or len < 1, then the buffer is left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte or -1 + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read as the first character + on the next read. At least one character of push-back is allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter flush + is as in the deflate() function. The return value is the zlib error number + (see function gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatented gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); + + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); + + Returns the starting position for the next gzread or gzwrite on the given + compressed file. This position represents a number of bytes in the + uncompressed data stream, and is zero when starting, even if appending or + reading a gzip stream from the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); + + Returns the current offset in the file being read or written. This offset + includes the count of bytes that precede the gzip stream, for example when + appending or when using gzdopen() for reading. When reading, the offset + does not include as yet unused buffered input. This information can be used + for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns true (1) if the end-of-file indicator has been set while reading, + false (0) otherwise. Note that the end-of-file indicator is set only if the + read tried to go past the end of the input, but came up short. Therefore, + just like feof(), gzeof() may return false even if there is no more data to + read, in the event that the last read request was for the exact number of + bytes remaining in the input file. This will happen if the input file size + is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file and + deallocates the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the given + compressed file. errnum is set to zlib error number. If an error occurred + in the file system and not in the compression library, errnum is set to + Z_ERRNO and the application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + +#endif /* !Z_SOLO */ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is Z_NULL, this function returns the + required initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is Z_NULL, this function returns the required + initial value for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) + +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +# define z_gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) +#else +# define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) +#endif + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#ifdef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); +#endif + +#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# else +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# endif +# ifndef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); +#endif + +#else /* Z_SOLO */ + + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + +#endif /* !Z_SOLO */ + +/* hack for buggy compilers */ +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; +#endif + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); +ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); +ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); +ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); +#if defined(_WIN32) && !defined(Z_SOLO) +ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, + const char *mode)); +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, + const char *format, + va_list va)); +# endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/source/Irrlicht/zlib/zlib.map b/source/Irrlicht/zlib/zlib.map new file mode 100644 index 00000000..55c6647e --- /dev/null +++ b/source/Irrlicht/zlib/zlib.map @@ -0,0 +1,83 @@ +ZLIB_1.2.0 { + global: + compressBound; + deflateBound; + inflateBack; + inflateBackEnd; + inflateBackInit_; + inflateCopy; + local: + deflate_copyright; + inflate_copyright; + inflate_fast; + inflate_table; + zcalloc; + zcfree; + z_errmsg; + gz_error; + gz_intmax; + _*; +}; + +ZLIB_1.2.0.2 { + gzclearerr; + gzungetc; + zlibCompileFlags; +} ZLIB_1.2.0; + +ZLIB_1.2.0.8 { + deflatePrime; +} ZLIB_1.2.0.2; + +ZLIB_1.2.2 { + adler32_combine; + crc32_combine; + deflateSetHeader; + inflateGetHeader; +} ZLIB_1.2.0.8; + +ZLIB_1.2.2.3 { + deflateTune; + gzdirect; +} ZLIB_1.2.2; + +ZLIB_1.2.2.4 { + inflatePrime; +} ZLIB_1.2.2.3; + +ZLIB_1.2.3.3 { + adler32_combine64; + crc32_combine64; + gzopen64; + gzseek64; + gztell64; + inflateUndermine; +} ZLIB_1.2.2.4; + +ZLIB_1.2.3.4 { + inflateReset2; + inflateMark; +} ZLIB_1.2.3.3; + +ZLIB_1.2.3.5 { + gzbuffer; + gzoffset; + gzoffset64; + gzclose_r; + gzclose_w; +} ZLIB_1.2.3.4; + +ZLIB_1.2.5.1 { + deflatePending; +} ZLIB_1.2.3.5; + +ZLIB_1.2.5.2 { + deflateResetKeep; + gzgetc_; + inflateResetKeep; +} ZLIB_1.2.5.1; + +ZLIB_1.2.7.1 { + inflateGetDictionary; + gzvprintf; +} ZLIB_1.2.5.2; diff --git a/source/Irrlicht/zlib/zlib.pc.cmakein b/source/Irrlicht/zlib/zlib.pc.cmakein new file mode 100644 index 00000000..a5e64293 --- /dev/null +++ b/source/Irrlicht/zlib/zlib.pc.cmakein @@ -0,0 +1,13 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=@INSTALL_LIB_DIR@ +sharedlibdir=@INSTALL_LIB_DIR@ +includedir=@INSTALL_INC_DIR@ + +Name: zlib +Description: zlib compression library +Version: @VERSION@ + +Requires: +Libs: -L${libdir} -L${sharedlibdir} -lz +Cflags: -I${includedir} diff --git a/source/Irrlicht/zlib/zlib.pc.in b/source/Irrlicht/zlib/zlib.pc.in new file mode 100644 index 00000000..7e5acf9c --- /dev/null +++ b/source/Irrlicht/zlib/zlib.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +sharedlibdir=@sharedlibdir@ +includedir=@includedir@ + +Name: zlib +Description: zlib compression library +Version: @VERSION@ + +Requires: +Libs: -L${libdir} -L${sharedlibdir} -lz +Cflags: -I${includedir} diff --git a/source/Irrlicht/zlib/zlib2ansi b/source/Irrlicht/zlib/zlib2ansi new file mode 100644 index 00000000..15e3e165 --- /dev/null +++ b/source/Irrlicht/zlib/zlib2ansi @@ -0,0 +1,152 @@ +#!/usr/bin/perl + +# Transform K&R C function definitions into ANSI equivalent. +# +# Author: Paul Marquess +# Version: 1.0 +# Date: 3 October 2006 + +# TODO +# +# Asumes no function pointer parameters. unless they are typedefed. +# Assumes no literal strings that look like function definitions +# Assumes functions start at the beginning of a line + +use strict; +use warnings; + +local $/; +$_ = <>; + +my $sp = qr{ \s* (?: /\* .*? \*/ )? \s* }x; # assume no nested comments + +my $d1 = qr{ $sp (?: [\w\*\s]+ $sp)* $sp \w+ $sp [\[\]\s]* $sp }x ; +my $decl = qr{ $sp (?: \w+ $sp )+ $d1 }xo ; +my $dList = qr{ $sp $decl (?: $sp , $d1 )* $sp ; $sp }xo ; + + +while (s/^ + ( # Start $1 + ( # Start $2 + .*? # Minimal eat content + ( ^ \w [\w\s\*]+ ) # $3 -- function name + \s* # optional whitespace + ) # $2 - Matched up to before parameter list + + \( \s* # Literal "(" + optional whitespace + ( [^\)]+ ) # $4 - one or more anythings except ")" + \s* \) # optional whitespace surrounding a Literal ")" + + ( (?: $dList )+ ) # $5 + + $sp ^ { # literal "{" at start of line + ) # Remember to $1 + //xsom + ) +{ + my $all = $1 ; + my $prefix = $2; + my $param_list = $4 ; + my $params = $5; + + StripComments($params); + StripComments($param_list); + $param_list =~ s/^\s+//; + $param_list =~ s/\s+$//; + + my $i = 0 ; + my %pList = map { $_ => $i++ } + split /\s*,\s*/, $param_list; + my $pMatch = '(\b' . join('|', keys %pList) . '\b)\W*$' ; + + my @params = split /\s*;\s*/, $params; + my @outParams = (); + foreach my $p (@params) + { + if ($p =~ /,/) + { + my @bits = split /\s*,\s*/, $p; + my $first = shift @bits; + $first =~ s/^\s*//; + push @outParams, $first; + $first =~ /^(\w+\s*)/; + my $type = $1 ; + push @outParams, map { $type . $_ } @bits; + } + else + { + $p =~ s/^\s+//; + push @outParams, $p; + } + } + + + my %tmp = map { /$pMatch/; $_ => $pList{$1} } + @outParams ; + + @outParams = map { " $_" } + sort { $tmp{$a} <=> $tmp{$b} } + @outParams ; + + print $prefix ; + print "(\n" . join(",\n", @outParams) . ")\n"; + print "{" ; + +} + +# Output any trailing code. +print ; +exit 0; + + +sub StripComments +{ + + no warnings; + + # Strip C & C++ coments + # From the perlfaq + $_[0] =~ + + s{ + /\* ## Start of /* ... */ comment + [^*]*\*+ ## Non-* followed by 1-or-more *'s + ( + [^/*][^*]*\*+ + )* ## 0-or-more things which don't start with / + ## but do end with '*' + / ## End of /* ... */ comment + + | ## OR C++ Comment + // ## Start of C++ comment // + [^\n]* ## followed by 0-or-more non end of line characters + + | ## OR various things which aren't comments: + + ( + " ## Start of " ... " string + ( + \\. ## Escaped char + | ## OR + [^"\\] ## Non "\ + )* + " ## End of " ... " string + + | ## OR + + ' ## Start of ' ... ' string + ( + \\. ## Escaped char + | ## OR + [^'\\] ## Non '\ + )* + ' ## End of ' ... ' string + + | ## OR + + . ## Anything other char + [^/"'\\]* ## Chars which doesn't start a comment, string or escape + ) + }{$2}gxs; + +} diff --git a/source/Irrlicht/zlib/zutil.c b/source/Irrlicht/zlib/zutil.c new file mode 100644 index 00000000..0bf0426f --- /dev/null +++ b/source/Irrlicht/zlib/zutil.c @@ -0,0 +1,324 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2005, 2010, 2011, 2012 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" +#ifndef Z_SOLO +# include "gzguts.h" +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +z_const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch ((int)(sizeof(uInt))) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch ((int)(sizeof(uLong))) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch ((int)(sizeof(voidpf))) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch ((int)(sizeof(z_off_t))) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int ZLIB_INTERNAL z_verbose = verbose; + +void ZLIB_INTERNAL z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void ZLIB_INTERNAL zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int ZLIB_INTERNAL zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void ZLIB_INTERNAL zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + +#ifndef Z_SOLO + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void ZLIB_INTERNAL zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ + +#endif /* !Z_SOLO */ diff --git a/source/Irrlicht/zlib/zutil.h b/source/Irrlicht/zlib/zutil.h new file mode 100644 index 00000000..f4e4d059 --- /dev/null +++ b/source/Irrlicht/zlib/zutil.h @@ -0,0 +1,253 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2013 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include "zlib.h" + +#if defined(STDC) && !defined(Z_SOLO) +# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) +# include +# endif +# include +# include +#endif + +#ifdef Z_SOLO + typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# ifndef Z_SOLO +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# if defined(M_I86) && !defined(Z_SOLO) +# include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# ifndef Z_SOLO +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + +#if defined(__BORLANDC__) && !defined(MSDOS) + #pragma warn -8004 + #pragma warn -8008 + #pragma warn -8066 +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_WIN32) && \ + (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(pyr) || defined(Z_SOLO) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int ZLIB_INTERNAL z_verbose; + extern void ZLIB_INTERNAL z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +#ifndef Z_SOLO + voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, + unsigned size)); + void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); +#endif + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +/* Reverse the bytes in a 32-bit value */ +#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +#endif /* ZUTIL_H */ diff --git a/source/source.txt b/source/source.txt new file mode 100644 index 00000000..55812446 --- /dev/null +++ b/source/source.txt @@ -0,0 +1,53 @@ +Source code of the Irrlicht Engine + +The complete source of the Irrlicht Engine can be found in this directory. +Please note that YOU DO NOT NEED THIS SOURCE to develop 3d applications with +the Irrlicht Engine. Instead, please use the .dll in the \bin directory, the +.lib in the \lib directory and the header files in the \include directory. + +You will find a good tutorial how to set up your development environment and to +use the engine in the \examples directory. (Try 01.helloworld) + +The source of the engine is included because for the following reasons: + + - To let developers be able to debug the engine. + - To let developers be able to make changes to the engine. + - To let developers be able to compile their own versions of the engine. + + + +HOW TO COMPILE THE ENGINE WITH LINUX + +If you wish to compile the engine for Linux yourself, run a 'make' in the +folder 'source/Irrlicht'. After this, you should be able to make all example +applications in examples. Then just run them from the directory where they are +built. +For the necessary compiler and linker flags please check the provided Makefiles +in the examples directories. + +Only the Software Drivers and the Null Driver will work on all Linux machines, +while OpenGL support requires either GLX support of the X11 server (try glxinfo) +or a software OpenGL solution such as Mesa. + +If you get a compiling/linking problem like + + undefined reference to `glXGetProcAddress' + +This is a problem introduced by the NVidia drivers. There are several solutions: +A) Update your drivers. All versions with GLX 1.4 support (i.e. beginning with + 12/2005) will work. +B) Define the symbol _IRR_GETPROCADDRESS_WORKAROUND_ during compilation of + COpenGLDriver.cpp, either by adding it to the compiler command line or by + uncommenting the line defining this symbol inside the OpenGL driver source. + This will force the use of glXGetProcAddressARB which has better chances to + work on older systems. + +If you get compiling or runtime problems regarding XF86VidMode, Xxf86vm.so, or +the XFree86 VidMode extension you have also several solutions: +A) Install the extension for your X server or the developer package in case of + compiler/linker problems. +B) Disable the VidMode usage by disabling the define _IRR_LINUX_X11_VIDMODE_ in + include/IrrCompileConfig.h + In this case you might give the RandR extension a try (by enabling the + next define in that file) which also provides fullscreen support under Linux. + If both extensions fail you won't have fullscreen support for Irrlicht. diff --git a/tests/2dmaterial.cpp b/tests/2dmaterial.cpp new file mode 100644 index 00000000..96eec8e6 --- /dev/null +++ b/tests/2dmaterial.cpp @@ -0,0 +1,912 @@ +#include "testUtils.h" +#include +using namespace irr; + +namespace +{ +// don't use this code! It lacks many checks and is for testing +// purposes only!!! +// based on code and media from SuperTuxKart +class ScalableFont : public gui::IGUIFontBitmap +{ + float m_scale; + struct TextureInfo + { + irr::core::stringc m_file_name; + bool m_has_alpha; + float m_scale; + + TextureInfo() + { + m_has_alpha = false; + m_scale = 1.0f; + } + }; + + std::map m_texture_files; + + void lazyLoadTexture(int texID) + { + const bool mipmap = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); + Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true); + // load texture + SpriteBank->setTexture(texID, Driver->getTexture( m_texture_files[texID].m_file_name )); + // set previous mip-map+filter state + Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, mipmap); + + // couldn't load texture, abort. + if (!SpriteBank->getTexture(texID)) + { + return; + } + else + { + // colorkey texture rather than alpha channel? + if (! m_texture_files[texID].m_has_alpha) + { + Driver->makeColorKeyTexture(SpriteBank->getTexture(texID), core::position2di(0,0)); + } + } + } + void doReadXmlFile(io::IXMLReader* xml) + { + while (xml->read()) + { + if (io::EXN_ELEMENT == xml->getNodeType()) + { + if (core::stringw(L"include") == xml->getNodeName()) + { + core::stringc filename = xml->getAttributeValue(L"file"); + io::IXMLReader* included = Environment->getFileSystem()->createXMLReader(filename.c_str()); + if (included != NULL) + { + doReadXmlFile(included); + included->drop(); + } + } + else if (core::stringw(L"Texture") == xml->getNodeName()) + { + // add a texture + core::stringc filename = xml->getAttributeValue(L"filename"); + core::stringc fn = filename; + u32 i = (u32)xml->getAttributeValueAsInt(L"index"); + + float scale=1.0f; + if (xml->getAttributeValue(L"scale")) + scale = xml->getAttributeValueAsFloat(L"scale"); + //std::cout << "scale = " << scale << std::endl; + + core::stringw alpha = xml->getAttributeValue(L"hasAlpha"); + + //std::cout << "---- Adding font texture " << fn.c_str() << "; alpha=" << alpha.c_str() << std::endl; + + + // make sure the sprite bank has enough textures in it + while (i+1 > SpriteBank->getTextureCount()) + { + SpriteBank->addTexture(NULL); + } + + TextureInfo info; + info.m_file_name = fn; + info.m_has_alpha = (alpha == core::stringw("true")); + info.m_scale = scale; + + m_texture_files[i] = info; + } + else if (core::stringw(L"c") == xml->getNodeName()) + { + // adding a character to this font + SFontArea a; + gui::SGUISpriteFrame f; + gui::SGUISprite s; + core::rect rectangle; + + a.underhang = xml->getAttributeValueAsInt(L"u"); + a.overhang = xml->getAttributeValueAsInt(L"o"); + a.spriteno = SpriteBank->getSprites().size(); + s32 texno = xml->getAttributeValueAsInt(L"i"); + + // parse rectangle + core::stringc rectstr = xml->getAttributeValue(L"r"); + 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'; + c++; + } + rectangle.UpperLeftCorner.X = val; + while (*c == L' ' || *c == L',') c++; + + val = 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'; + c++; + } + rectangle.LowerRightCorner.X = val; + while (*c == L' ' || *c == L',') c++; + + val = 0; + while (*c >= '0' && *c <= '9') + { + val *= 10; + val += *c - '0'; + c++; + } + rectangle.LowerRightCorner.Y = val; + + CharacterMap[ch] = Areas.size(); + + // make frame + f.rectNumber = SpriteBank->getPositions().size(); + f.textureNumber = texno; + + // add frame to sprite + s.Frames.push_back(f); + s.frameTime = 0; + + // add rectangle to sprite bank + SpriteBank->getPositions().push_back(rectangle); + a.width = rectangle.getWidth(); + + // add sprite to sprite bank + SpriteBank->getSprites().push_back(s); + + // add character to font + Areas.push_back(a); + } + } + } + } + +public: + + bool m_black_border; + + ScalableFont* m_fallback_font; + float m_fallback_font_scale; + int m_fallback_kerning_width; + + //! constructor + ScalableFont(gui::IGUIEnvironment *env, const io::path& filename) + : Driver(0), SpriteBank(0), Environment(env), WrongCharacter(0), + MaxHeight(0), GlobalKerningWidth(0), GlobalKerningHeight(0) + { + #ifdef _DEBUG + setDebugName("ScalableFont"); + #endif + + m_fallback_font = NULL; + m_fallback_kerning_width = 0; + m_fallback_font_scale = 1.0f; + m_scale = 0.37f; + m_black_border = false; + + if (Environment) + { + // don't grab environment, to avoid circular references + Driver = Environment->getVideoDriver(); + + SpriteBank = Environment->addEmptySpriteBank(filename); + if (SpriteBank) + SpriteBank->grab(); + } + + if (Driver) + Driver->grab(); + + setInvisibleCharacters ( L" " ); + + io::IXMLReader* reader = env->getFileSystem()->createXMLReader(filename.c_str()); + if (reader) + { + load( reader ); + reader->drop(); + } + assert_log(Areas.size() > 0); + } + + //! destructor + virtual ~ScalableFont() + { + if (Driver) + Driver->drop(); + if (SpriteBank) + SpriteBank->drop(); + } + + //! loads a font from an XML file + bool load(io::IXMLReader* xml) + { + if (!SpriteBank) + return false; + + doReadXmlFile(xml); + + // set bad character + WrongCharacter = getAreaIDFromCharacter(L' ', NULL); + + setMaxHeight(); + + for(wchar_t c='0'; c<='9'; c++) + { + SFontArea a = getAreaFromCharacter(c, NULL); + if (a.overhang > m_max_digit_area.overhang ) m_max_digit_area.overhang = a.overhang; + if (a.underhang > m_max_digit_area.underhang) m_max_digit_area.underhang = a.underhang; + if (a.width > m_max_digit_area.width) m_max_digit_area.width = a.width; + } + m_max_digit_area.overhang = 0; + m_max_digit_area.underhang=0; + return true; + } + //! draws an text and clips it to the specified rectangle if wanted + virtual void draw(const core::stringw& text, const core::rect& position, + video::SColor color, bool hcenter=false, + bool vcenter=false, const core::rect* clip=0) + { + if (!Driver) return; + + core::position2d offset = position.UpperLeftCorner; + core::dimension2d text_dimension; + + // When we use the "tab" hack, disable right-alignment, it messes up everything +// bool has_tab = (text.findFirst(L'\t') != -1); + // ---- collect character locations + const unsigned int text_size = text.size(); + core::array indices(text_size); + core::array offsets(text_size); + core::array fallback; + fallback.set_used(text_size); + + for (u32 i = 0; i> 1; + continue; + } // if lineBreak + + bool use_fallback_font = false; + const SFontArea &area = getAreaFromCharacter(c, &use_fallback_font); + fallback[i] = use_fallback_font; + offset.X += area.underhang; + offsets.push_back(offset); + // Invisible character. add something to the array anyway so that + // indices from the various arrays remain in sync + indices.push_back((Invisible.findFirst(c) < 0) ? (int)area.spriteno + : -1); + offset.X += getCharWidth(area, fallback[i]); + } // for i& sprites = SpriteBank->getSprites(); + core::array< core::rect >& positions = SpriteBank->getPositions(); + core::array< gui::SGUISprite >* fallback_sprites; + core::array< core::rect >* fallback_positions; + if (m_fallback_font!=NULL) + { + fallback_sprites = &m_fallback_font->SpriteBank->getSprites(); + fallback_positions = &m_fallback_font->SpriteBank->getPositions(); + } + else + { + fallback_sprites = NULL; + fallback_positions = NULL; + } + + video::IVideoDriver* driver = Environment->getVideoDriver(); + const int spriteAmount = sprites.size(); + for (int n=0; n= spriteAmount)) + continue; + if (indices[n] == -1) + continue; + + //assert_log(sprites[spriteID].Frames.size() > 0); + + const int texID = (fallback[n] ? + (*fallback_sprites)[spriteID].Frames[0].textureNumber : + sprites[spriteID].Frames[0].textureNumber); + + core::rect source = (fallback[n] ? + (*fallback_positions)[(*fallback_sprites)[spriteID].Frames[0].rectNumber] : + positions[sprites[spriteID].Frames[0].rectNumber]); + + const TextureInfo& info = (fallback[n] ? + (*(m_fallback_font->m_texture_files.find(texID))).second : + (*(m_texture_files.find(texID))).second); + float char_scale = info.m_scale; + + core::dimension2d size = source.getSize(); + + float scale = (fallback[n] ? m_scale*m_fallback_font_scale : m_scale); + size.Width = (int)(size.Width * scale * char_scale); + size.Height = (int)(size.Height * scale * char_scale); + + // align vertically if character is smaller + int y_shift = (size.Height < MaxHeight*m_scale ? (int)((MaxHeight*m_scale - size.Height)/2.0f) : 0); + + core::rect dest(offsets[n] + core::position2di(0, y_shift), size); + + video::SColor colors[] = {color, color, color, color}; + + video::ITexture* texture = (fallback[n] ? + m_fallback_font->SpriteBank->getTexture(texID) : + SpriteBank->getTexture(texID) ); + + if (texture == NULL) + { + // perform lazy loading + + if (fallback[n]) + { + m_fallback_font->lazyLoadTexture(texID); + texture = m_fallback_font->SpriteBank->getTexture(texID); + } + else + { + lazyLoadTexture(texID); + texture = SpriteBank->getTexture(texID); + } + + if (texture == NULL) + { + continue; // no such character + } + } + + if (m_black_border) + { + // draw black border + video::SColor black(color.getAlpha(),0,0,0); + video::SColor black_colors[] = {black, black, black, black}; + + for (int x_delta=-2; x_delta<=2; x_delta++) + { + for (int y_delta=-2; y_delta<=2; y_delta++) + { + if (x_delta == 0 || y_delta == 0) continue; + driver->draw2DImage(texture, + dest + core::position2d(x_delta, y_delta), + source, + clip, + black_colors, true); + } + } + } + + if (fallback[n]) + { + // draw text over + static video::SColor orange(color.getAlpha(), 255, 100, 0); + static video::SColor yellow(color.getAlpha(), 255, 220, 15); + video::SColor title_colors[] = {yellow, orange, orange, yellow}; + driver->draw2DImage(texture, + dest, + source, + clip, + title_colors, true); + } + else + { + driver->draw2DImage(texture, + dest, + source, + clip, + colors, true); + + } + } + } + + //! returns the dimension of a text + virtual core::dimension2d getDimension(const wchar_t* text) const + { + assert_log(Areas.size() > 0); + + core::dimension2d dim(0, 0); + core::dimension2d thisLine(0, (int)(MaxHeight*m_scale)); + + for (const wchar_t* p = text; *p; ++p) + { + if (*p == L'\r' || // Windows breaks + *p == L'\n') // Unix breaks + { + if (*p==L'\r' && p[1] == L'\n') // Windows breaks + ++p; + dim.Height += thisLine.Height; + if (dim.Width < thisLine.Width) + dim.Width = thisLine.Width; + thisLine.Width = 0; + continue; + } + + bool fallback = false; + const SFontArea &area = getAreaFromCharacter(*p, &fallback); + + thisLine.Width += area.underhang; + + thisLine.Width += getCharWidth(area, fallback); + } + + dim.Height += thisLine.Height; + if (dim.Width < thisLine.Width) dim.Width = thisLine.Width; + + // std::cout << "ScalableFont::getDimension returns : " << dim.Width << ", " << dim.Height << " --> "; + + dim.Width = (int)(dim.Width + 0.9f); // round up + dim.Height = (int)(dim.Height + 0.9f); + + //std::cout << dim.Width << ", " << dim.Height << std::endl; + + return dim; + } + //! 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 + { + s32 x = 0; + s32 idx = 0; + + while (text[idx]) + { + const SFontArea& a = Areas[getAreaIDFromCharacter(text[idx], NULL)]; + + x += a.width + a.overhang + a.underhang + GlobalKerningWidth; + + if (x >= pixel_x) + return idx; + + ++idx; + } + + return -1; + } + //! Returns the type of this font + virtual gui::EGUI_FONT_TYPE getType() const { return gui::EGFT_BITMAP; } + + //! set an Pixel Offset on Drawing ( scale position on width ) + virtual void setKerningWidth (s32 kerning) + { + GlobalKerningWidth = kerning; + } + virtual void setKerningHeight (s32 kerning) + { + GlobalKerningHeight = kerning; + } + //! set an Pixel Offset on Drawing ( scale position on width ) + virtual s32 getKerningWidth(const wchar_t* thisLetter=0, const wchar_t* previousLetter=0) const + { + s32 ret = GlobalKerningWidth; + + if (thisLetter) + { + ret += Areas[getAreaIDFromCharacter(*thisLetter, NULL)].overhang; + + if (previousLetter) + { + ret += Areas[getAreaIDFromCharacter(*previousLetter, NULL)].underhang; + } + } + + return ret; + } + virtual s32 getKerningHeight() const + { + return GlobalKerningHeight; + } + + //! gets the sprite bank + virtual gui::IGUISpriteBank* getSpriteBank() const + { + return SpriteBank; + } + + //! returns the sprite number from a given character + virtual u32 getSpriteNoFromChar(const wchar_t *c) const + { + return Areas[getAreaIDFromCharacter(*c, NULL)].spriteno; + } + + virtual void setInvisibleCharacters( const wchar_t *s ) + { + Invisible = s; + } + +private: + + struct SFontArea + { + SFontArea() : underhang(0), overhang(0), width(0), spriteno(0) {} + s32 underhang; + s32 overhang; + s32 width; + u32 spriteno; + }; + + int getCharWidth(const SFontArea& area, const bool fallback) const + { + core::array< gui::SGUISprite >& sprites = SpriteBank->getSprites(); + core::array< gui::SGUISprite >* fallback_sprites = (m_fallback_font != NULL ? + &m_fallback_font->SpriteBank->getSprites() : + NULL); + + const int texID = (fallback ? + (*fallback_sprites)[area.spriteno].Frames[0].textureNumber : + sprites[area.spriteno].Frames[0].textureNumber); + + const TextureInfo& info = (fallback ? + (*(m_fallback_font->m_texture_files.find(texID))).second : + (*(m_texture_files.find(texID))).second); + const float char_scale = info.m_scale; + + //std::cout << "area.spriteno=" << area.spriteno << ", char_scale=" << char_scale << std::endl; + + if (fallback) + return (int)(((area.width + area.overhang)*m_fallback_font_scale + m_fallback_kerning_width) * m_scale * char_scale); + else + return (int)((area.width + area.overhang + GlobalKerningWidth) * m_scale * char_scale); + } + s32 getAreaIDFromCharacter(const wchar_t c, bool* fallback_font) const + { + std::map::const_iterator n = CharacterMap.find(c); + if (n != CharacterMap.end()) + { + if (fallback_font != NULL) + *fallback_font = false; + return (*n).second; + } + else if (m_fallback_font != NULL && fallback_font != NULL) + { + *fallback_font = true; + return m_fallback_font->getAreaIDFromCharacter(c, NULL); + } + else + { + // std::cout << "The font does not have this character : <" << (int)c << ">" << std::endl; + if (fallback_font != NULL) + *fallback_font = false; + return WrongCharacter; + } + } + const SFontArea &getAreaFromCharacter(const wchar_t c, bool* fallback_font) const + { + const int area_id = getAreaIDFromCharacter(c, fallback_font); + const bool use_fallback_font = (fallback_font && *fallback_font); + + // Note: fallback_font can be NULL + return ( use_fallback_font ? m_fallback_font->Areas[area_id] : Areas[area_id]); + } // getAreaFromCharacter + void setMaxHeight() + { + // FIXME: should consider per-texture scaling + MaxHeight = 0; + s32 t; + + core::array< core::rect >& p = SpriteBank->getPositions(); + + for (u32 i=0; iMaxHeight) + MaxHeight = t; + } + } + core::array Areas; + /** The maximum values of all digits, used in monospace_digits. */ + mutable SFontArea m_max_digit_area; + std::map CharacterMap; + video::IVideoDriver* Driver; + gui::IGUISpriteBank* SpriteBank; + gui::IGUIEnvironment* Environment; + u32 WrongCharacter; + s32 MaxHeight; + s32 GlobalKerningWidth, GlobalKerningHeight; + + core::stringw Invisible; +}; +} + +// The actual bug that was behind this issue was the combination of +// 2d rendering and mipmaps. The issue was reproduced using the special +// draw2dimage version, hence the name. +static bool draw2DImage4c(video::E_DRIVER_TYPE type) +{ + IrrlichtDevice *device = createDevice(type, core::dimension2d(240, 120)); + + if (!device) + return true; // could not create selected driver. + + video::IVideoDriver* driver = device->getVideoDriver(); + + if (!driver->queryFeature(video::EVDF_BILINEAR_FILTER)) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS,true); + driver->setTextureCreationFlag(video::ETCF_OPTIMIZED_FOR_QUALITY,true); + + video::ITexture* images = driver->getTexture("../media/2ddemo.png"); + driver->makeColorKeyTexture(images, core::position2d(0,0)); + + core::rect imp1(349,15,385,78); + core::rect imp2(387,15,423,78); + + // font cannot handle loading from sub-dirs + io::path cwd = device->getFileSystem()->getWorkingDirectory(); + device->getFileSystem()->changeWorkingDirectoryTo("media"); + + ScalableFont* font = new ScalableFont(device->getGUIEnvironment(), "title_font.xml"); + font->m_fallback_font_scale = 4.0f; + font->m_fallback_kerning_width = 15; + font->setKerningWidth(-18); + font->m_black_border = true; + + /* + Prepare a nicely filtering 2d render mode for special cases. + */ + driver->getMaterial2D().UseMipMaps = true; + driver->getMaterial2D().TextureLayer[0].BilinearFilter = true; + + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,120,102,136)); + + driver->enableMaterial2D(); + + // draw fire & dragons background world + driver->draw2DImage(images, core::position2di(), + core::rect(0,0,342,224), 0, + video::SColor(255,255,255,255), true); + + // draw flying imp + driver->draw2DImage(images, core::position2d(114,75), + imp1, 0, video::SColor(255,255,255,255), true); + + // draw second flying imp + driver->draw2DImage(images, core::position2d(220,55), + imp2, 0, video::SColor(255,255,255,255), true); + + driver->draw2DImage(images, core::rect(10,10,108,48), + core::rect(354,87,442,118)); + + video::SColor colors[] = {0xff00ffff, 0xff00ffff, 0xffffff00, 0xffffff00}; + driver->draw2DImage(images, core::recti(10,50,108,88), + core::recti(354,87,442,118), 0, colors, true); + + font->draw( L"WXYZsSdDrRjJbB", core::rect(30,20,300,300), + video::SColor(255,255,255,255) ); + + driver->enableMaterial2D(false); + + driver->draw2DImage(images, core::recti(10,90,108,128), + core::recti(354,87,442,118), 0, colors, true); + + font->draw( L"WXYZsSdDrRjJbB", core::rect(30,60,300,400), + video::SColor(255,255,255,255) ); + + driver->endScene(); + } + font->drop(); + device->getFileSystem()->changeWorkingDirectoryTo(cwd); + + // don't go under 99% as the difference is not very large + bool result = takeScreenshotAndCompareAgainstReference(driver, "-draw2DImage4cFilter.png"); + + device->closeDevice(); + device->run(); + device->drop(); + return result; +} + +// This test renders a 3d scene and a gui on top of it. The GUI is +// filtered via 2dmaterial (blurred). +// TODO: Works only for OpenGL right now +static bool addBlend2d(video::E_DRIVER_TYPE type) +{ + SIrrlichtCreationParameters params; + params.AntiAlias = 0; + params.Bits = 32; + params.WindowSize = core::dimension2d(160, 120); + params.DriverType = type; + + IrrlichtDevice *device = createDeviceEx(params); + + if (!device) + return true; // in case the driver type does not exist + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + + if (!driver->queryFeature(video::EVDF_BILINEAR_FILTER)) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + logTestString("Testing driver %ls\n", driver->getName()); + + scene::IAnimatedMesh* mesh = smgr->getMesh("../media/sydney.md2"); + if (!mesh) + { + device->closeDevice(); + device->run(); + device->drop(); + return false; + } + + stabilizeScreenBackground(driver); + + scene::IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh ); + + if (node) + { + node->setMaterialFlag(video::EMF_LIGHTING, false); + node->setMD2Animation(scene::EMAT_STAND); + node->setMaterialTexture( 0, driver->getTexture("../media/sydney.bmp") ); + } + + smgr->addCameraSceneNode(0, core::vector3df(0,30,-40), core::vector3df(0,5,0)); + + gui::IGUIEnvironment* env = device->getGUIEnvironment(); + { + // create the toolbox window + gui::IGUIWindow* wnd = env->addWindow(core::rect(0,0,800,480), + false, L"Toolset", 0, 100); + + // create tab control and tabs + gui::IGUITabControl* tab = env->addTabControl( + core::rect(2,20,800-602,480-7), wnd, true, true); + + gui::IGUITab* t1 = tab->addTab(L"Config"); + + // add some edit boxes and a button to tab one + env->addImage(driver->getTexture("../media/tools.png"), core::vector2d(10,20), true, t1); + env->addStaticText(L"X:", core::rect(22,48,40,66), false, false, t1); + env->addEditBox(L"1.0", core::rect(40,46,130,66), true, t1, 201); + + // quick scale buttons + env->addButton(core::rect(65,20,95,40), t1, 102, L"* 10"); + env->addButton(core::rect(100,20,130,40), t1, 103, L"* 0.1"); + } + + video::SMaterial& material2D = driver->getMaterial2D(); + for (unsigned int n=0; nbeginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,100,101,140)); + smgr->drawAll(); + driver->enableMaterial2D(); + env->drawAll(); + driver->enableMaterial2D(false); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-addBlend2D.png", 98.2f); + + device->closeDevice(); + device->run(); + device->drop(); + return result; +} + +// This test renders 4 times the same image. Two via IGUIImage, two via draw2DImage +// 3 of the 4 images are filtered via 2dmaterial and bilinear filter, only the one +// at the bottom left is not. +static bool moreFilterTests(video::E_DRIVER_TYPE type) +{ + IrrlichtDevice* device = irr::createDevice(type, core::dimension2du(160,120)); + if (!device) + return true; + + video::IVideoDriver* driver = device->getVideoDriver(); + gui::IGUIEnvironment* gui = device->getGUIEnvironment(); + + if (!driver->queryFeature(video::EVDF_BILINEAR_FILTER)) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); + video::ITexture* tex = driver->getTexture("../media/irrlichtlogo.jpg"); + gui::IGUIImage* image = gui->addImage(core::recti(0,0,64,64)); + image->setScaleImage(true); + image->setImage(tex); + image->setUseAlphaChannel(true); + driver->getMaterial2D().TextureLayer[0].BilinearFilter=true; + driver->getMaterial2D().TextureLayer[0].TrilinearFilter=true; + + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, irr::video::SColor(255,255,255,255)); + + // all three logos should be with filtering + driver->enableMaterial2D(); + + driver->getMaterial2D().setTexture(0, 0); + driver->draw2DImage(tex, irr::core::rect(64, 64, 128, 128), irr::core::rect(0, 0, 88, 31)); + + driver->getMaterial2D().setTexture(0, tex); + driver->draw2DImage(tex, irr::core::rect(64, 0, 128, 64), irr::core::rect(0, 0, 88, 31)); + + gui->drawAll(); + + // the next gui image should be without filter + driver->enableMaterial2D(false); + image->setRelativePosition(core::recti(0,64,64,128)); + gui->drawAll(); + + driver->endScene(); + } + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-2dmatFilter.png"); + + device->closeDevice(); + device->run(); + device->drop(); + return result; +} + +bool twodmaterial() +{ + bool result = true; + TestWithAllDrivers(addBlend2d); + TestWithAllDrivers(moreFilterTests); +#ifdef _IRR_COMPILE_WITH_XML_ + TestWithAllDrivers(draw2DImage4c); +#endif + return result; +} diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 00000000..83b4b26b --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,53 @@ +# Irrlicht Engine Regression Tests Makefile +Target = tests +Sources = $(wildcard *.cpp) + +CPPFLAGS = -I../include -I/usr/X11R6/include -pipe +CXXFLAGS += -Wall -ansi -pedantic -fno-exceptions +ifndef NDEBUG +CXXFLAGS += -O0 -g -D_DEBUG +else +CXXFLAGS += -fexpensive-optimizations -O3 +endif + +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif + +all: all_linux + +# target specific settings +all_linux: SYSTEM=Linux +all_linux: LDFLAGS = -L/usr/X11R6/lib$(LIBSELECT) -L../lib/$(SYSTEM) -lIrrlicht -lGL -lXxf86vm -lXext -lX11 -lXcursor + +all_win32 clean_win32: SYSTEM=Win32-gcc +all_win32: LDFLAGS = -L../lib/$(SYSTEM) -lIrrlicht -lopengl32 -lm + +all_win32 clean_win32: SUF=.exe +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = ../bin/$(SYSTEM)/$(Target)$(SUF) + +OBJ = $(Sources:.cpp=.o) + +all_linux all_win32: $(OBJ) + $(warning Building...) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $(DESTPATH) $(LDFLAGS) + @$(RM) tests # otherwise it's easy to forget to copy it and run the old binary + +clean: clean_linux clean_win32 + $(warning Cleaning...) + @$(RM) $(OBJ) + +clean_linux clean_win32: + @$(RM) $(DESTPATH) + +.PHONY: all all_win32 clean clean_linux clean_win32 + +# Create dependency files for automatic recompilation +%.d:%.cpp + $(CXX) $(CPPFLAGS) -MM -MF $@ $< + +ifneq ($(MAKECMDGOALS),clean) +-include $(OBJ:.o=.d) +endif + diff --git a/tests/anti-aliasing.cpp b/tests/anti-aliasing.cpp new file mode 100644 index 00000000..62446c5f --- /dev/null +++ b/tests/anti-aliasing.cpp @@ -0,0 +1,74 @@ +#include "testUtils.h" + +using namespace irr; + +static bool testLineRendering(video::E_DRIVER_TYPE type) +{ + SIrrlichtCreationParameters params; + params.AntiAlias = 2; + params.Bits = 16; + params.WindowSize = core::dimension2d(160, 120); + params.DriverType = type; + + IrrlichtDevice *device = createDeviceEx(params); + + if (!device) + return true; // in case the driver type does not exist + + video::IVideoDriver* driver = device->getVideoDriver(); + // if no AntiAliasing supported, skip this test + if (driver->getDriverAttributes().getAttributeAsInt("AntiAlias")<2) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + logTestString("Testing driver %ls\n", driver->getName()); + + scene::ISceneManager* smgr = device->getSceneManager(); + + scene::IAnimatedMesh* mesh = smgr->getMesh("./media/sydney.md2"); + if (!mesh) + { + device->closeDevice(); + device->run(); + device->drop(); + return false; + } + + stabilizeScreenBackground(driver); + + scene::IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh ); + + if (node) + { + node->setMaterialFlag(video::EMF_LIGHTING, false); + node->setMD2Animation(scene::EMAT_STAND); + node->setMaterialTexture( 0, driver->getTexture("./media/sydney.bmp") ); + } + + smgr->addCameraSceneNode(0, core::vector3df(0,30,-40), core::vector3df(0,5,0)); + + device->getTimer()->setTime(0); // scene has animations and current scene seems to be saved at that time + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,100,101,140)); + smgr->drawAll(); + driver->draw3DBox(node->getBoundingBox(), video::SColor(0,255,0,0)); + driver->draw2DLine(core::position2di(10,10), core::position2di(100,100), video::SColor(255,0,0,0)); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-lineAntiAliasing.png", 99.4f ); + + device->closeDevice(); + device->run(); + device->drop(); + return result; +} + +bool antiAliasing() +{ + bool result = true; + TestWithAllHWDrivers(testLineRendering); + return result; +} diff --git a/tests/archiveReader.cpp b/tests/archiveReader.cpp new file mode 100644 index 00000000..5674f6c9 --- /dev/null +++ b/tests/archiveReader.cpp @@ -0,0 +1,469 @@ +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace io; + +namespace +{ + +bool testArchive(IFileSystem* fs, const io::path& archiveName) +{ + // make sure there is no archive mounted + if ( fs->getFileArchiveCount() ) + { + logTestString("Already mounted archives found\n"); + return false; + } + + if ( !fs->addFileArchive(archiveName, /*bool ignoreCase=*/true, /*bool ignorePaths=*/false) ) + { + logTestString("Mounting archive failed\n"); + return false; + } + + // make sure there is an archive mounted + if ( !fs->getFileArchiveCount() ) + { + logTestString("Mounted archive not in list\n"); + return false; + } + + // mount again + if ( !fs->addFileArchive(archiveName, /*bool ignoreCase=*/true, /*bool ignorePaths=*/false) ) + { + logTestString("Mounting a second time failed\n"); + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + + // make sure there is exactly one archive mounted + if ( fs->getFileArchiveCount() != 1 ) + { + logTestString("Duplicate mount not recognized\n"); + while (fs->getFileArchiveCount()) + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + if (fs->getFileArchive(0)->getType()==io::EFAT_FOLDER) + { + // mount again with different path end symbol (either with slash or without) + core::stringc newArchiveName=archiveName; + if (archiveName.lastChar()=='/') + newArchiveName.erase(newArchiveName.size()-1); + else + newArchiveName.append('/'); + if ( !fs->addFileArchive(newArchiveName, /*bool ignoreCase=*/true, /*bool ignorePaths=*/false) ) + { + logTestString("Mounting a second time with different name failed\n"); + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + + // make sure there is exactly one archive mounted + if ( fs->getFileArchiveCount() != 1 ) + { + logTestString("Duplicate mount with different filename not recognized\n"); + while (fs->getFileArchiveCount()) + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + } + +#if 0 + // log what we got + io::IFileArchive* archive = fs->getFileArchive(fs->getFileArchiveCount()-1); + const io::IFileList* fileList = archive->getFileList(); + for ( u32 f=0; f < fileList->getFileCount(); ++f) + { + logTestString("File name: %s\n", fileList->getFileName(f).c_str()); + logTestString("Full path: %s\n", fileList->getFullFileName(f).c_str()); + logTestString("ID: %d\n", fileList->getID(f)); + } +#endif + + io::path filename("mypath/mypath/myfile.txt"); + if (!fs->existFile(filename)) + { + logTestString("existFile with deep path failed\n"); + while (fs->getFileArchiveCount()) + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + + const char* names[] = {"test/test.txt", "mypath/myfile.txt", "mypath/mypath/myfile.txt"}; + const char* basenames[] = {"test.txt", "myfile.txt", "myfile.txt"}; + const char* content[] = {"Hello world!", "1est\n", "2est"}; + + for (u32 i=0; i<3; ++i) + { + if (!fs->existFile(names[i])) + { + logTestString("existFile failed\n"); + while (fs->getFileArchiveCount()) + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + + IReadFile* readFile = fs->createAndOpenFile(names[i]); + if (!readFile) + { + logTestString("createAndOpenFile failed\n"); + while (fs->getFileArchiveCount()) + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + + if (fs->getFileBasename(readFile->getFileName()) != basenames[i]) + { + logTestString("Wrong filename, file list seems to be corrupt\n"); + while (fs->getFileArchiveCount()) + fs->removeFileArchive(fs->getFileArchiveCount()-1); + readFile->drop(); + return false; + } + char tmp[13] = {'\0'}; + readFile->read(tmp, 12); + if (strcmp(tmp, content[i])) + { + logTestString("Read bad data from archive: %s\n", tmp); + while (fs->getFileArchiveCount()) + fs->removeFileArchive(fs->getFileArchiveCount()-1); + readFile->drop(); + return false; + } + readFile->drop(); + } + + if (!fs->removeFileArchive(fs->getFileArchiveCount()-1)) + { + logTestString("Couldn't remove archive.\n"); + return false; + } + + // make sure there is no archive mounted + if ( fs->getFileArchiveCount() ) + return false; + + return true; +} + +bool testEncryptedZip(IFileSystem* fs) +{ + // make sure there is no archive mounted + if ( fs->getFileArchiveCount() ) + { + logTestString("Already mounted archives found\n"); + return false; + } + + const char* archiveName = "media/enc.zip"; + if ( !fs->addFileArchive(archiveName, /*bool ignoreCase=*/true, /*bool ignorePaths=*/false) ) + { + logTestString("Mounting archive failed\n"); + return false; + } + + // make sure there is an archive mounted + if ( !fs->getFileArchiveCount() ) + { + logTestString("Mounted archive not in list\n"); + return false; + } + + // mount again + if ( !fs->addFileArchive(archiveName, /*bool ignoreCase=*/true, /*bool ignorePaths=*/false) ) + { + logTestString("Mounting a second time failed\n"); + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + + // make sure there is exactly one archive mounted + if ( fs->getFileArchiveCount() != 1 ) + { + logTestString("Duplicate mount not recognized\n"); + while (fs->getFileArchiveCount()) + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + + // log what we got + io::IFileArchive* archive = fs->getFileArchive(fs->getFileArchiveCount()-1); + io::path filename("doc"); + const io::IFileList* fileList = archive->getFileList(); + for ( u32 f=0; f < fileList->getFileCount(); ++f) + { + logTestString("%s name: %s\n", fileList->isDirectory(f)?"Directory":"File", fileList->getFileName(f).c_str()); + logTestString("Full path: %s\n", fileList->getFullFileName(f).c_str()); + } + if (fileList->findFile(filename) != -1) + { + logTestString("findFile wrongly succeeded on directory\n"); + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + if (fileList->findFile(filename, true)==-1) + { + logTestString("findFile failed on directory\n"); + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + + filename="doc/readme.txt"; + if (fileList->findFile(filename)==-1) + { + logTestString("findFile failed\n"); + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + if (fileList->findFile(filename, true) != -1) + { + logTestString("findFile wrongly succeeded on non-directory\n"); + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + + if (!fs->existFile(filename)) + { + logTestString("existFile failed\n"); + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + + filename="doc"; + if (fs->existFile(filename)) + { + logTestString("existFile succeeded wrongly on directory\n"); + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + + filename="doc/readme.txt"; + IReadFile* readFile = fs->createAndOpenFile(filename); + if ( readFile ) + { + logTestString("createAndOpenFile succeeded, even though no password was set.\n"); + readFile->drop(); + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + + archive->Password="33445"; + readFile = fs->createAndOpenFile(filename); +#ifdef _IRR_COMPILE_WITH_ZIP_ENCRYPTION_ + if ( !readFile ) + { + logTestString("createAndOpenFile failed\n"); + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + + char tmp[13] = {'\0'}; + readFile->read(tmp, 12); + readFile->drop(); + if (strncmp(tmp, "Linux Users:", 12)) + { + logTestString("Read bad data from archive: %s\n", tmp); + return false; + } +#endif + + if (!fs->removeFileArchive(fs->getFileArchiveCount()-1)) + { + logTestString("Couldn't remove archive.\n"); + return false; + } + + // make sure there is no archive mounted + if ( fs->getFileArchiveCount() ) + return false; + + return true; +} + +bool testSpecialZip(IFileSystem* fs, const char* archiveName, const char* filename, const void* content) +{ + // make sure there is no archive mounted + if ( fs->getFileArchiveCount() ) + { + logTestString("Already mounted archives found\n"); + return false; + } + + if ( !fs->addFileArchive(archiveName, /*bool ignoreCase=*/true, /*bool ignorePaths=*/false) ) + { + logTestString("Mounting archive failed\n"); + return false; + } + + // make sure there is an archive mounted + if ( !fs->getFileArchiveCount() ) + { + logTestString("Mounted archive not in list\n"); + return false; + } + + // log what we got + io::IFileArchive* archive = fs->getFileArchive(fs->getFileArchiveCount()-1); + const io::IFileList* fileList = archive->getFileList(); + for ( u32 f=0; f < fileList->getFileCount(); ++f) + { + logTestString("%s name: %s\n", fileList->isDirectory(f)?"Directory":"File", fileList->getFileName(f).c_str()); + logTestString("Full path: %s\n", fileList->getFullFileName(f).c_str()); + } + + if (!fs->existFile(filename)) + { + logTestString("existFile failed\n"); + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + + IReadFile* readFile = fs->createAndOpenFile(filename); + if ( !readFile ) + { + logTestString("createAndOpenFile failed\n"); + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + + char tmp[6] = {'\0'}; + readFile->read(tmp, 5); + if (memcmp(tmp, content, 5)) + { + logTestString("Read bad data from archive: %s\n", tmp); + readFile->drop(); + fs->removeFileArchive(fs->getFileArchiveCount()-1); + return false; + } + + readFile->drop(); + + if (!fs->removeFileArchive(fs->getFileArchiveCount()-1)) + { + logTestString("Couldn't remove archive.\n"); + return false; + } + + // make sure there is no archive mounted + if ( fs->getFileArchiveCount() ) + return false; + + return true; +} + +static bool testMountFile(IFileSystem* fs) +{ + bool result = true; +#if 1 + fs->changeWorkingDirectoryTo("empty"); + // log what we got + const io::IFileList* fileList = fs->createFileList(); + for ( u32 f=0; f < fileList->getFileCount(); ++f) + { + logTestString("File name: %s\n", fileList->getFileName(f).c_str()); + logTestString("Full path: %s\n", fileList->getFullFileName(f).c_str()); + logTestString("ID: %d\n", fileList->getID(f)); + } + fileList->drop(); + fs->changeWorkingDirectoryTo(".."); +#endif + if (!fs->addFileArchive("empty"), false) + result = false; + const IFileList* list = fs->getFileArchive(0)->getFileList(); +#if 1 + // log what we got + io::IFileArchive* archive = fs->getFileArchive(fs->getFileArchiveCount()-1); + fileList = archive->getFileList(); + for ( u32 f=0; f < fileList->getFileCount(); ++f) + { + logTestString("File name: %s\n", fileList->getFileName(f).c_str()); + logTestString("Full path: %s\n", fileList->getFullFileName(f).c_str()); + logTestString("ID: %d\n", fileList->getID(f)); + } +#endif + + if (list->getFileName(0) != "burnings video 0.39b.png") + result = false; + return result; +} + +bool testAddRemove(IFileSystem* fs, const io::path& archiveName) +{ + // make sure there is no archive mounted + if ( fs->getFileArchiveCount() ) + { + logTestString("Already mounted archives found\n"); + return false; + } + + if ( !fs->addFileArchive(archiveName, /*bool ignoreCase=*/true, /*bool ignorePaths=*/false) ) + { + logTestString("Mounting archive failed\n"); + return false; + } + + // make sure there is an archive mounted + if ( !fs->getFileArchiveCount() ) + { + logTestString("Mounted archive not in list\n"); + return false; + } + + if (!fs->removeFileArchive(archiveName)) + { + logTestString("Couldn't remove archive.\n"); + return false; + } + + // make sure there is no archive mounted + if ( fs->getFileArchiveCount() ) + return false; + + return true; +} +} + + +bool archiveReader() +{ + IrrlichtDevice * device = irr::createDevice(video::EDT_NULL, dimension2d(1, 1)); + assert_log(device); + if(!device) + return false; + + io::IFileSystem * fs = device->getFileSystem (); + if ( !fs ) + return false; + + bool ret = true; + logTestString("Testing mount file.\n"); + ret &= testArchive(fs, "media/file_with_path"); + logTestString("Testing mount file.\n"); + ret &= testArchive(fs, "media/file_with_path/"); + logTestString("Testing zip files.\n"); + ret &= testArchive(fs, "media/file_with_path.zip"); + logTestString("Testing pak files.\n"); + ret &= testArchive(fs, "media/sample_pakfile.pak"); + logTestString("Testing npk files.\n"); + ret &= testArchive(fs, "media/file_with_path.npk"); + logTestString("Testing encrypted zip files.\n"); + ret &= testEncryptedZip(fs); + logTestString("Testing special zip files.\n"); + ret &= testSpecialZip(fs, "media/Monty.zip", "monty/license.txt", "Monty"); + logTestString("Testing special zip files lzma.\n"); + const u8 buf[] = {0xff, 0xfe, 0x3c, 0x00, 0x3f}; + ret &= testSpecialZip(fs, "media/lzmadata.zip", "tahoma10_.xml", buf); +// logTestString("Testing complex mount file.\n"); +// ret &= testMountFile(fs); + logTestString("Testing add/remove with filenames.\n"); + ret &= testAddRemove(fs, "media/file_with_path.zip"); + + device->closeDevice(); + device->run(); + device->drop(); + + return ret; +} + diff --git a/tests/b3dAnimation.cpp b/tests/b3dAnimation.cpp new file mode 100644 index 00000000..c0dbf3b5 --- /dev/null +++ b/tests/b3dAnimation.cpp @@ -0,0 +1,87 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; + +// Tests B3D animations. +bool b3dAnimation(void) +{ + // Use EDT_BURNINGSVIDEO since it is not dependent on (e.g.) OpenGL driver versions. + IrrlichtDevice *device = createDevice(video::EDT_BURNINGSVIDEO, core::dimension2d(160, 120), 32); + assert_log(device); + if (!device) + return false; + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager * smgr = device->getSceneManager(); + + scene::ISkinnedMesh* mesh = (scene::ISkinnedMesh*)smgr->getMesh("../media/ninja.b3d"); + assert_log(mesh); + + bool result = false; + if (!mesh) + return false; + + scene::IAnimatedMeshSceneNode* node1 = smgr->addAnimatedMeshSceneNode(mesh); + assert_log(node1); + + /** Verify that two skinned animated mesh scene nodes can use different frames of the skinned mesh */ + if(node1) + { + node1->setPosition(core::vector3df(-3, -3, 10)); + node1->setMaterialFlag(video::EMF_LIGHTING, false); + node1->setAnimationSpeed(0.f); + node1->setCurrentFrame(10.f); + node1->setDebugDataVisible(irr::scene::EDS_BBOX_BUFFERS); + } + + scene::IAnimatedMeshSceneNode* node2 = smgr->addAnimatedMeshSceneNode(mesh); + assert_log(node2); + if(node2) + { + node2->setPosition(core::vector3df(3, -3, 10)); + node2->setMaterialFlag(video::EMF_LIGHTING, false); + node2->setAnimationSpeed(0.f); + node2->setCurrentFrame(62.f); + node2->setDebugDataVisible(scene::EDS_BBOX_BUFFERS); + } + + (void)smgr->addCameraSceneNode(); + + // Just jump to the last frame since that's all we're interested in. + device->run(); + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255, 60, 60, 60)); + smgr->drawAll(); + driver->endScene(); + + result = takeScreenshotAndCompareAgainstReference(driver, "-b3dAnimation.png"); + if (node2) + node2->remove(); + + /** Now test if bones are correctly positioned. */ + node1->setDebugDataVisible(scene::EDS_SKELETON); + node1->setPosition(core::vector3df(1,-5,8)); + node1->setRotation(core::vector3df(0,180,0)); + node1->updateAbsolutePosition(); + for (u32 i=0; igetJointCount(); ++i) + { + smgr->addCubeSceneNode(1.f,0,-1,node1->getJointNode(i)->getAbsolutePosition()); +// smgr->addCubeSceneNode(1.f,node1->getJointNode(i)); + } + + // Simple render call + device->run(); + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255, 60, 60, 60)); + smgr->drawAll(); + driver->endScene(); + + result &= takeScreenshotAndCompareAgainstReference(driver, "-b3dJointPosition.png"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} diff --git a/tests/billboards.cpp b/tests/billboards.cpp new file mode 100644 index 00000000..2b1499b1 --- /dev/null +++ b/tests/billboards.cpp @@ -0,0 +1,156 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; + +namespace +{ +// Test billboard sizing +bool billboardSize(void) +{ + // Use EDT_BURNINGSVIDEO since it is not dependent on (e.g.) OpenGL driver versions. + IrrlichtDevice *device = createDevice(video::EDT_BURNINGSVIDEO, core::dimension2d(160, 120), 32); + assert_log(device); + if (!device) + return false; + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager * smgr = device->getSceneManager(); + + smgr->addCameraSceneNode(); + scene::IBillboardSceneNode* bill = smgr->addBillboardSceneNode(); + bill->setPosition(core::vector3df(0,0,50)); + bill = smgr->addBillboardSceneNode(); + bill->setPosition(core::vector3df(-30,0,50)); + bill->getMaterial(0).Lighting=false; + bill = smgr->addBillboardSceneNode(); + bill->setPosition(core::vector3df(30,0,50)); + bill->getMaterial(0).Lighting=false; + bill->getMaterial(0).Wireframe=true; + bill = smgr->addBillboardSceneNode(); + bill->setPosition(core::vector3df(30,0,50)); + bill->setSize(2,2,2); + + bill = smgr->addBillboardSceneNode(); + bill->setSize(10,20,2); + bill->setPosition(core::vector3df(0,30,50)); + bill = smgr->addBillboardSceneNode(); + bill->setSize(10,2,20); + bill->setPosition(core::vector3df(-30,30,50)); + bill->getMaterial(0).Lighting=false; + bill = smgr->addBillboardSceneNode(); + bill->setSize(10,2,20); + bill->setPosition(core::vector3df(30,30,50)); + bill->getMaterial(0).Lighting=false; + bill->getMaterial(0).Wireframe=true; + bill = smgr->addBillboardSceneNode(); + bill->setPosition(core::vector3df(30,30,50)); + bill->setSize(2,2,2); + + video::ITexture* tex = driver->getTexture("../media/fireball.bmp"); + bill = smgr->addBillboardSceneNode(); + bill->getMaterial(0).Lighting=false; + bill->getMaterial(0).TextureLayer[0].AnisotropicFilter=true; + bill->getMaterial(0).setTexture(0, tex); + bill->setSize(10,20,2); + bill->setPosition(core::vector3df(0,-30,50)); + bill = smgr->addBillboardSceneNode(); + bill->setSize(10,2,20); + bill->setPosition(core::vector3df(-30,-30,50)); + bill->getMaterial(0).TextureLayer[0].AnisotropicFilter=true; + bill->getMaterial(0).setTexture(0, tex); + bill->getMaterial(0).Lighting=false; + bill = smgr->addBillboardSceneNode(); + bill->setSize(10,2,20); + bill->setPosition(core::vector3df(30,-30,50)); + bill->getMaterial(0).TextureLayer[0].AnisotropicFilter=true; + bill->getMaterial(0).setTexture(0, tex); + bill->getMaterial(0).Lighting=false; + bill->getMaterial(0).Wireframe=true; + bill = smgr->addBillboardSceneNode(); + bill->setPosition(core::vector3df(30,-30,50)); + bill->setSize(2,2,2); + + bill = smgr->addBillboardSceneNode(); + bill->getMaterial(0).Lighting=false; + bill->getMaterial(0).setTexture(0, tex); + bill->setSize(10,20,14); + bill->setPosition(core::vector3df(0,-15,50)); + bill = smgr->addBillboardSceneNode(); + bill->setSize(10,14,20); + bill->setPosition(core::vector3df(-30,-15,50)); + bill->getMaterial(0).setTexture(0, tex); + bill->getMaterial(0).Lighting=false; + bill = smgr->addBillboardSceneNode(); + bill->setSize(10,14,20); + bill->setPosition(core::vector3df(30,-15,50)); + bill->getMaterial(0).setTexture(0, tex); + bill->getMaterial(0).Lighting=false; + bill->getMaterial(0).Wireframe=true; + bill = smgr->addBillboardSceneNode(); + bill->setPosition(core::vector3df(30,-15,50)); + bill->setSize(2,2,2); + + bool result = false; + + device->run(); + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255, 60, 60, 60)); + smgr->drawAll(); + driver->endScene(); + + result = takeScreenshotAndCompareAgainstReference(driver, "-billboard.png"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +// Test billboard orientation +// Should generate a properly readable (i.e. not mirrored or flipped) +// font file display. +bool billboardOrientation(void) +{ + // Use EDT_BURNINGSVIDEO since it is not dependent on (e.g.) OpenGL driver versions. + IrrlichtDevice *device = createDevice(video::EDT_BURNINGSVIDEO, core::dimension2d(160, 120), 32); + assert_log(device); + if (!device) + return false; + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager * smgr = device->getSceneManager(); + + smgr->addCameraSceneNode(); + scene::IBillboardSceneNode* bill = smgr->addBillboardSceneNode(0, core::dimension2df(40,40)); + bill->setPosition(core::vector3df(0,-15,10)); + bill->getMaterial(0).Lighting=false; + bill->getMaterial(0).setTexture(0, driver->getTexture("../media/fontcourier.bmp")); + + bool result = false; + + device->run(); + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255, 60, 60, 60)); + smgr->drawAll(); + driver->endScene(); + + result = takeScreenshotAndCompareAgainstReference(driver, "-billboardOrientation.png"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +} // end anonymous namespace + +// Test billboards +bool billboards(void) +{ + bool result = billboardSize(); + result &= billboardOrientation(); + return result; +} diff --git a/tests/burningsVideo.cpp b/tests/burningsVideo.cpp new file mode 100644 index 00000000..665a4865 --- /dev/null +++ b/tests/burningsVideo.cpp @@ -0,0 +1,40 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.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(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0, 80, 80, 80))) + { + smgr->drawAll(); + driver->endScene(); + result = takeScreenshotAndCompareAgainstReference(driver, "-ambient-lighting.png", 100); + } + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} diff --git a/tests/collisionResponseAnimator.cpp b/tests/collisionResponseAnimator.cpp new file mode 100644 index 00000000..e852a1b0 --- /dev/null +++ b/tests/collisionResponseAnimator.cpp @@ -0,0 +1,198 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +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_log(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_log(false); + } + + if(animator.getTargetNode() != ExpectedTarget) + { + logTestString("*** Error: wrong node\n"); + expectedCollisionCallbackPositions = false; + assert_log(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 + jumping it back again. */ +bool collisionResponseAnimator(void) +{ + IrrlichtDevice * device = irr::createDevice(video::EDT_NULL); + assert_log(device); + if(!device) + return false; + + ISceneManager * smgr = device->getSceneManager(); + + // Create 2 nodes to the left of a "wall" + ISceneNode * testNode1 = smgr->addEmptySceneNode(); + ISceneNode * testNode2 = smgr->addEmptySceneNode(); + testNode1->setPosition(vector3df(-50, 0,0)); + testNode2->setPosition(vector3df(-50, 0,0)); + + // Create a "wall" node, and collision response animators for each test node. + IMeshSceneNode * wallNode = smgr->addCubeSceneNode(10.f); + + ITriangleSelector * wallSelector = smgr->createTriangleSelectorFromBoundingBox(wallNode); + ISceneNodeAnimatorCollisionResponse * collisionAnimator1 = + smgr->createCollisionResponseAnimator(wallSelector, + testNode1, + vector3df(10,10,10), + vector3df(0, 0, 0)); + testNode1->addAnimator(collisionAnimator1); + + CMyCollisionCallback collisionCallback; + collisionAnimator1->setCollisionCallback(&collisionCallback); + + collisionAnimator1->drop(); + collisionAnimator1 = 0; + + ISceneNodeAnimatorCollisionResponse * collisionAnimator2 = + smgr->createCollisionResponseAnimator(wallSelector, + testNode2, + 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. + + // Get the system in a good state + device->run(); + smgr->drawAll(); + + // 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 + // the animator was removed and later re-added); + testNode2->setPosition(vector3df(50, 0,0)); + collisionAnimator2->setTargetNode(testNode2); + collisionAnimator2->drop(); // We're done using this now. + + device->run(); + smgr->drawAll(); + + bool result = true; + + if(testNode1->getAbsolutePosition().X > -15.f) + { + logTestString("collisionResponseAnimator test node 1 wasn't stopped from moving.\n"); + assert_log(false); + result = false; + } + + if(testNode2->getAbsolutePosition().X < 50.f) + { + logTestString("collisionResponseAnimator test node 2 was stopped from moving.\n"); + assert_log(false); + result = false; + } + + // 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 != -50.f) + { + logTestString("collisionResponseAnimator test node 2 was stopped from moving.\n"); + assert_log(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_log(false); + result = false; + } + + device->closeDevice(); + device->run(); + device->drop(); + + result &= expectedCollisionCallbackPositions; + return result; +} + diff --git a/tests/color.cpp b/tests/color.cpp new file mode 100644 index 00000000..c31e4273 --- /dev/null +++ b/tests/color.cpp @@ -0,0 +1,21 @@ +#include "testUtils.h" + +using namespace irr; +using namespace video; + +bool rounding() +{ + SColorf colf(0.003922f, 0.007843f, 0.011765f); // test-values by virion which once failed + SColor col = colf.toSColor(); + return col.getRed() == 1 && col.getGreen() == 2 && col.getBlue() == 3; +} + +//! Test SColor and SColorf +bool color(void) +{ + bool ok = true; + + ok &= rounding(); + + return ok; +} diff --git a/tests/coreutil.cpp b/tests/coreutil.cpp new file mode 100644 index 00000000..672cce0a --- /dev/null +++ b/tests/coreutil.cpp @@ -0,0 +1,59 @@ +#include "testUtils.h" + +using namespace irr; +using namespace core; + +bool testMergeFilename() +{ + // path mergeFilename(const path& path, const path& filename, const path& extension = ""); + if ( mergeFilename(_IRR_TEXT(""), _IRR_TEXT(""), _IRR_TEXT("") ) != io::path(_IRR_TEXT("")) ) + return false; + if ( mergeFilename(_IRR_TEXT("folder"), _IRR_TEXT(""), _IRR_TEXT("") ) != io::path(_IRR_TEXT("folder/")) ) + return false; + if ( mergeFilename(_IRR_TEXT("folder/"), _IRR_TEXT(""), _IRR_TEXT("") ) != io::path(_IRR_TEXT("folder/")) ) + return false; + if ( mergeFilename(_IRR_TEXT("folder"), _IRR_TEXT("file"), _IRR_TEXT("") ) != io::path(_IRR_TEXT("folder/file")) ) + return false; + if ( mergeFilename(_IRR_TEXT("folder/"), _IRR_TEXT("file"), _IRR_TEXT("") ) != io::path(_IRR_TEXT("folder/file")) ) + return false; + if ( mergeFilename(_IRR_TEXT("folder\\"), _IRR_TEXT("file"), _IRR_TEXT("") ) != io::path(_IRR_TEXT("folder\\file")) ) + return false; + if ( mergeFilename(_IRR_TEXT(""), _IRR_TEXT("file"), _IRR_TEXT("") ) != io::path(_IRR_TEXT("file")) ) + return false; + if ( mergeFilename(_IRR_TEXT("."), _IRR_TEXT("file"), _IRR_TEXT("") ) != io::path(_IRR_TEXT("./file")) ) + return false; + if ( mergeFilename(_IRR_TEXT("folder"), _IRR_TEXT(""), _IRR_TEXT(".bmp") ) != io::path(_IRR_TEXT("folder/.bmp")) ) + return false; + if ( mergeFilename(_IRR_TEXT("folder/"), _IRR_TEXT(""), _IRR_TEXT(".bmp") ) != io::path(_IRR_TEXT("folder/.bmp")) ) + return false; + if ( mergeFilename(_IRR_TEXT("folder"), _IRR_TEXT(""), _IRR_TEXT("bmp") ) != io::path(_IRR_TEXT("folder/.bmp")) ) + return false; + if ( mergeFilename(_IRR_TEXT("."), _IRR_TEXT(""), _IRR_TEXT("bmp") ) != io::path(_IRR_TEXT("./.bmp")) ) + return false; + if ( mergeFilename(_IRR_TEXT("folder"), _IRR_TEXT("file"), _IRR_TEXT("bmp") ) != io::path(_IRR_TEXT("folder/file.bmp")) ) + return false; + if ( mergeFilename(_IRR_TEXT("folder/"), _IRR_TEXT("file"), _IRR_TEXT("bmp") ) != io::path(_IRR_TEXT("folder/file.bmp")) ) + return false; + if ( mergeFilename(_IRR_TEXT("folder/"), _IRR_TEXT("file"), _IRR_TEXT(".bmp") ) != io::path(_IRR_TEXT("folder/file.bmp")) ) + return false; + if ( mergeFilename(_IRR_TEXT("folder"), _IRR_TEXT("file.bmp"), _IRR_TEXT("") ) != io::path(_IRR_TEXT("folder/file.bmp")) ) + return false; + if ( mergeFilename(_IRR_TEXT(""), _IRR_TEXT("file"), _IRR_TEXT("bmp") ) != io::path(_IRR_TEXT("file.bmp")) ) + return false; + if ( mergeFilename(_IRR_TEXT(""), _IRR_TEXT("file"), _IRR_TEXT(".bmp") ) != io::path(_IRR_TEXT("file.bmp")) ) + return false; + if ( mergeFilename(_IRR_TEXT("c:"), _IRR_TEXT("file"), _IRR_TEXT(".bmp") ) != io::path(_IRR_TEXT("c:/file.bmp")) ) // TODO: is this actually correct on windows? + return false; + + return true; +} + +// Test the functionality of the Irrlicht timer +bool testCoreutil(void) +{ + bool ok = true; + + ok &= testMergeFilename(); + + return ok; +} diff --git a/tests/createImage.cpp b/tests/createImage.cpp new file mode 100644 index 00000000..91a20e56 --- /dev/null +++ b/tests/createImage.cpp @@ -0,0 +1,94 @@ +#include "testUtils.h" + +using namespace irr; + +namespace +{ +bool testImageCreation() +{ + // create device + + IrrlichtDevice *device = createDevice(video::EDT_SOFTWARE, core::dimension2d(160,120)); + + if (device == 0) + return true; // could not create selected driver. + + bool result = true; + video::IVideoDriver* driver = device->getVideoDriver(); + video::ITexture* tex=driver->getTexture("../media/water.jpg"); + video::ITexture* tex1=0; + video::ITexture* tex2=0; + if (!tex) + result=false; + else + { + video::IImage* img1=driver->createImage(tex, core::vector2di(0,0), core::dimension2du(32,32)); + if (!img1) + result=false; + else + { + tex1=driver->addTexture("new1", img1); + img1->drop(); + img1=0; + } + video::IImage* img2=driver->createImage(tex, core::vector2di(0,0), tex->getSize()); + if (!img2) + result=false; + else + { + tex2=driver->addTexture("new2", img2); + img2->drop(); + img2 = 0; + } + } + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,255,0,255));//Backbuffer background is pink + + driver->draw2DImage(tex, core::position2d(0,0), core::recti(0,0,32,32)); + driver->draw2DImage(tex1, core::position2d(32,0)); + driver->draw2DImage(tex2, core::position2d(64,0), core::recti(0,0,32,32)); + + driver->endScene(); + + result = takeScreenshotAndCompareAgainstReference(driver, "-createImage.png"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +bool testImageFormats() +{ + IrrlichtDevice *device = createDevice(video::EDT_BURNINGSVIDEO, core::dimension2d(256,128)); + + if (device == 0) + return true; // could not create selected driver. + + video::IVideoDriver* driver = device->getVideoDriver(); + video::ITexture* tex=driver->getTexture("../media/water.jpg"); + video::ITexture* tex1=driver->getTexture("media/grey.tga"); + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,0,0,0)); + + driver->draw2DImage(tex, core::position2d(0,0), core::recti(0,0,64,64)); + driver->draw2DImage(tex1, core::position2d(0,64), core::recti(0,0,64,64)); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-testImageFormats.png", 99.5f); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} +} + +bool createImage() +{ + bool result = testImageCreation(); + result &= testImageFormats(); + return result; +} + diff --git a/tests/cursorSetVisible.cpp b/tests/cursorSetVisible.cpp new file mode 100644 index 00000000..bf08cdf5 --- /dev/null +++ b/tests/cursorSetVisible.cpp @@ -0,0 +1,70 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +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->closeDevice(); + device->run(); + device->drop(); + + if(!result) + { + logTestString("ERROR: cursorSetVisible received %d events.\n", moveTrapper.MouseMovesReceived); + assert_log(false); + } + + return result; +} + diff --git a/tests/disambiguateTextures.cpp b/tests/disambiguateTextures.cpp new file mode 100644 index 00000000..e53275f1 --- /dev/null +++ b/tests/disambiguateTextures.cpp @@ -0,0 +1,84 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +/** This tests verifies that textures opened from different places in the filesystem + can be distinguished, even if they have the same filename. */ +bool disambiguateTextures(void) +{ + IrrlichtDevice *device = + createDevice( video::EDT_NULL, dimension2d(640, 480)); + + if (!device) + { + logTestString("Unable to create EDT_NULL device\n"); + return false; + } + + // Expects an empty tmp/tmp directory under this app's wd and + // a media directory under this apps' directory with tools.png in it. + stringc wd = device->getFileSystem()->getWorkingDirectory(); + + if(-1 == wd.find("/tests") && -1 == wd.find("\\tests")) + { + logTestString("The tests must be run from the /tests directory, regardless of where\n"\ + "the test executable was built.\n"); + device->drop(); + return false; + } + + IVideoDriver * driver = device->getVideoDriver(); + + ITexture * tex1 = driver->getTexture("../media/tools.png"); + assert_log(tex1); + if(!tex1) + logTestString("Unable to open ../media/tools.png\n"); + + ITexture * tex2 = driver->getTexture("../media/tools.png"); + assert_log(tex2); + if(!tex2) + logTestString("Unable to open ../media/tools.png\n"); + + IReadFile * readFile = device->getFileSystem()->createAndOpenFile("../media/tools.png"); + assert_log(readFile); + if(!readFile) + logTestString("Unable to open ../media/tools.png\n"); + + ITexture * tex3 = driver->getTexture(readFile); + assert_log(tex3); + if(!readFile) + logTestString("Unable to create texture from ../media/tools.png\n"); + + readFile->drop(); + + // All 3 of the above textures should be identical. + assert_log(tex1 == tex2); + assert_log(tex1 == tex3); + + stringc newWd = wd + "/empty/empty"; + bool changed = device->getFileSystem()->changeWorkingDirectoryTo(newWd.c_str()); + assert_log(changed); + ITexture * tex4 = driver->getTexture("../../media/tools.png"); + assert_log(tex4); + if(!tex4) + logTestString("Unable to open ../../media/tools.png\n"); + assert_log(tex1 != tex4); + + // The working directory must be restored for the other tests to work. + changed &= device->getFileSystem()->changeWorkingDirectoryTo(wd.c_str()); + + device->closeDevice(); + device->run(); + device->drop(); + + return (changed && tex1 == tex2 && tex1 == tex3 && tex1 != tex4) ? true : false; +} + diff --git a/tests/draw2DImage.cpp b/tests/draw2DImage.cpp new file mode 100644 index 00000000..1d80c041 --- /dev/null +++ b/tests/draw2DImage.cpp @@ -0,0 +1,196 @@ +#include "testUtils.h" + +using namespace irr; + +namespace +{ + +bool testWithRenderTarget(video::E_DRIVER_TYPE driverType) +{ + // create device + + IrrlichtDevice *device = createDevice(driverType, core::dimension2d(160,120)); + + if (device == 0) + return true; // could not create selected driver. + + video::IVideoDriver* driver = device->getVideoDriver(); + + if (!driver->queryFeature(video::EVDF_RENDER_TO_TARGET)) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + video::ITexture* renderTargetTex = driver->addRenderTargetTexture(core::dimension2d(64, 64), "BASEMAP"); + video::ITexture* renderTargetDepth = driver->addRenderTargetTexture(core::dimension2d(64, 64), "rtd", video::ECF_D16); + + video::IRenderTarget* renderTarget = driver->addRenderTarget(); + renderTarget->setTexture(renderTargetTex, renderTargetDepth); + + video::ITexture* tex=driver->getTexture("../media/water.jpg"); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,255,0,255));//Backbuffer background is pink + + //draw the 256x256 water image on the rendertarget: + + + driver->setRenderTargetEx(renderTarget,video::ECBF_COLOR|video::ECBF_DEPTH,video::SColor(255,0,0,255));//Rendertarget background is blue + driver->draw2DImage(tex, core::position2d(0,0), core::recti(0,0,32,32)); + driver->setRenderTargetEx(0, 0); + + //draw the rendertarget on screen: + //this should normally draw a 64x64 image containing a 32x32 image in the top left corner + driver->draw2DImage(renderTargetTex, core::position2d(0,0)); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-draw2DImageRTT.png"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +// Test various special destination rectangles +bool testRectangles(video::E_DRIVER_TYPE driverType) +{ + // create device + IrrlichtDevice *device = createDevice(driverType, core::dimension2d(160,120)); + + if (device == 0) + return true; // could not create selected driver. + + video::IVideoDriver* driver = device->getVideoDriver(); + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + video::ITexture *tex=driver->getTexture("../media/fireball.bmp"); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,255,0,255));//Backbuffer background is pink + + // draw normal, will be overdrwan in error case + driver->draw2DImage(tex, core::recti(68,32,132,96), core::recti(0,0,64,64)); + //draw the image larger + driver->draw2DImage(tex, core::recti(0,0,64,64), core::recti(0,0,32,32)); + //draw the image flipped horizontally + driver->draw2DImage(tex, core::recti(132,0,68,64), core::recti(0,0,64,64)); + //draw the image smaller + driver->draw2DImage(tex, core::recti(0,64,32,96), core::recti(0,0,64,64)); + //draw the image much smaller + driver->draw2DImage(tex, core::recti(36,64,44,72), core::recti(0,0,64,64)); + //draw the image flipped horizontally + driver->draw2DImage(tex, core::recti(68,64,132,0), core::recti(0,0,64,64)); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-draw2DImageRect.png"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +// draws a complex (interlaced, paletted, alpha) png image +bool testWithPNG(video::E_DRIVER_TYPE driverType) +{ + // create device + + IrrlichtDevice *device = createDevice(driverType, core::dimension2d(160,120)); + + if (device == 0) + return true; // could not create selected driver. + + video::IVideoDriver* driver = device->getVideoDriver(); + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + video::ITexture *tex=driver->getTexture("media/RedbrushAlpha-0.25.png"); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,40,40,255));//Backbuffer background is blue + driver->draw2DImage(tex, core::recti(0,0,160,120), core::recti(0,0,256,256), 0, 0, true); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-draw2DImagePNG.png", 98.f); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +// draws an image and checks if the written example equals the original image +bool testExactPlacement(video::E_DRIVER_TYPE driverType) +{ + // create device + + IrrlichtDevice *device = createDevice(driverType, core::dimension2d(160,120), 32); + + if (device == 0) + return true; // could not create selected driver. + + video::IVideoDriver* driver = device->getVideoDriver(); + + if (driver->getColorFormat() != video::ECF_A8R8G8B8 || !driver->queryFeature(video::EVDF_RENDER_TO_TARGET)) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + video::ITexture* renderTargetTex = driver->addRenderTargetTexture(core::dimension2d(32, 32), "rt1"); + video::ITexture* renderTargetDepth = driver->addRenderTargetTexture(core::dimension2d(32, 32), "rtd", video::ECF_D16); + + video::IRenderTarget* renderTarget = driver->addRenderTarget(); + renderTarget->setTexture(renderTargetTex, renderTargetDepth); + + video::ITexture* tex=driver->getTexture("../media/fireball.bmp"); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,40,40,255));//Backbuffer background is blue + driver->setRenderTargetEx(renderTarget, 0, video::ECBF_COLOR | video::ECBF_DEPTH); + driver->draw2DImage(tex, core::recti(0,0,32,32), core::recti(0,0,64,64)); + driver->setRenderTargetEx(0, 0, 0); + driver->endScene(); + + video::IImage* img = driver->createImage(renderTargetTex, core::vector2di(), renderTargetTex->getSize()); + driver->writeImageToFile(img, "results/fireball.png"); + img->drop(); + bool result = fuzzyCompareImages(driver, "media/fireball.png", "results/fireball.png")>98.25f; + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +} + +bool draw2DImage() +{ + bool result = true; + TestWithAllDrivers(testWithRenderTarget); + TestWithAllHWDrivers(testWithPNG); + // TODO D3D driver moves image 1 pixel top-left in case of down scaling + TestWithAllDrivers(testExactPlacement); + TestWithAllDrivers(testRectangles); + return result; +} diff --git a/tests/drawPixel.cpp b/tests/drawPixel.cpp new file mode 100644 index 00000000..38a6baf6 --- /dev/null +++ b/tests/drawPixel.cpp @@ -0,0 +1,191 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +//! Tests IVideoDriver::drawPixel(). +/** Expect to see two diagonal lines overlaying a wall texture cube. + One line should run from green at the top left to red at the bottom right. + The other should run from cyan 100% transparent at the bottom left to + cyan 100% opaque at the top right. */ +static bool lineRender(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(); + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + // 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(video::ECBF_COLOR | video::ECBF_DEPTH, 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 = takeScreenshotAndCompareAgainstReference(driver, "-drawPixel.png", 98.81f); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +// this test draws alternating white and black borders with +// increasing thickness. Intended use of this test is to ensure +// the corect pixel alignment within the render window. +static bool pixelAccuracy(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(); + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + device->getSceneManager()->addCameraSceneNode(); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, SColor(255,100,101,140)); + u32 start=0; + for (u32 count=1; count<10; ++count) + { + for (u32 j=0; jdrawPixel(start+x, start, (count%2==1)?0xffffffff:0xff000000); + } + ++start; + } + } + start=0; + for (u32 count=1; count<10; ++count) + { + for (u32 j=0; jdrawPixel(start, start+x, (count%2==1)?0xffffffff:0xff000000); + } + ++start; + } + } + for (u32 x=0; x<100; ++x) + { + driver->drawPixel(x, x, 0xffff0000); + } + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-pixelAccuracy.png"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +// this test draws lines of different lengths and compares +// them with pixel placement +// grey pixels denote start and end of the white drawn lines +// black pixels only make those grey points better visible +// yellow and magenta lines should start and end next toa black pixel, +// yellow one right to the last black pixel down, magenta below the last +// black pixel to the right +// white lines are always double drawn, lines back and forth. +static bool drawLine(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(); + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + device->getSceneManager()->addCameraSceneNode(); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, SColor(255,100,101,140)); + // horizontal lines + for (u32 i=0; i<20; ++i) + { + driver->draw2DLine(core::vector2di(10,10+3*i), core::vector2di(10+2*i,10+3*i)); + // mark start point + driver->drawPixel(9,10+3*i+1, video::SColor(0xff000000)); + driver->drawPixel(10,10+3*i+1, video::SColor(0xff888888)); + driver->drawPixel(11,10+3*i+1, video::SColor(0xff000000)); + // mark end point + driver->drawPixel(9+2*i,10+3*i+1, video::SColor(0xff000000)); + driver->drawPixel(10+2*i,10+3*i+1, video::SColor(0xff888888)); + driver->drawPixel(11+2*i,10+3*i+1, video::SColor(0xff000000)); + driver->draw2DLine(core::vector2di(10+2*i,10+3*i+2), core::vector2di(10,10+3*i+2)); + } + // vertical lines + for (u32 i=0; i<20; ++i) + { + driver->draw2DLine(core::vector2di(11+3*i,10), core::vector2di(11+3*i,10+2*i)); + // mark start point + driver->drawPixel(11+3*i+1,9, video::SColor(0xff000000)); + driver->drawPixel(11+3*i+1,10, video::SColor(0xff888888)); + driver->drawPixel(11+3*i+1,11, video::SColor(0xff000000)); + // mark end point + driver->drawPixel(11+3*i+1,9+2*i, video::SColor(0xff000000)); + driver->drawPixel(11+3*i+1,10+2*i, video::SColor(0xff888888)); + driver->drawPixel(11+3*i+1,11+2*i, video::SColor(0xff000000)); + driver->draw2DLine(core::vector2di(11+3*i+2,10+2*i), core::vector2di(11+3*i+2, 10)); + } + // diagonal lines + driver->draw2DLine(core::vector2di(14,14),core::vector2di(50,68), video::SColor(0xffffff00)); + driver->draw2DLine(core::vector2di(15,14),core::vector2di(69,50), video::SColor(0xffff00ff)); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-drawLine.png"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +bool drawPixel(void) +{ + bool result = true; + + TestWithAllDrivers(lineRender); + TestWithAllDrivers(pixelAccuracy); + TestWithAllDrivers(drawLine); + + return result; +} diff --git a/tests/drawRectOutline.cpp b/tests/drawRectOutline.cpp new file mode 100644 index 00000000..6995e155 --- /dev/null +++ b/tests/drawRectOutline.cpp @@ -0,0 +1,54 @@ +#include "testUtils.h" + +using namespace irr; + +namespace +{ + +bool testWithDriver(video::E_DRIVER_TYPE driverType) +{ + IrrlichtDevice *device = + createDevice(driverType, core::dimension2du(160, 120)); + if (!device) + return true; + + video::IVideoDriver* driver = device->getVideoDriver(); + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, 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->getMaterial2D().Thickness=12.f; + driver->enableMaterial2D(); + r += core::position2di( 10 , 10 ); + driver->draw2DRectangleOutline( r , video::SColor(128, 255, 128, 128) ); + + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-drawRectOutline.png", 98.5f ); + + device->closeDevice(); + device->run(); + device->drop(); + + return result ; +} +} + +bool drawRectOutline(void) +{ + // TODO: Only OpenGL supports thick lines + bool result = true; + TestWithAllDrivers(testWithDriver); + return result; +} diff --git a/tests/drawVertexPrimitive.cpp b/tests/drawVertexPrimitive.cpp new file mode 100644 index 00000000..825e6134 --- /dev/null +++ b/tests/drawVertexPrimitive.cpp @@ -0,0 +1,104 @@ +#include "testUtils.h" + +using namespace irr; + +namespace +{ + +// this test renders random point clouds using different primitives on top +// tests the primitives type support in general and can hint to differences +// between the drivers +bool testWithDriver(video::E_DRIVER_TYPE driverType) +{ + IrrlichtDevice *device = + createDevice(driverType, core::dimension2du(160, 120)); + if (!device) + return true; + + scene::ISceneManager* smgr = device->getSceneManager(); + video::IVideoDriver* driver = device->getVideoDriver(); + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + smgr->addCameraSceneNode(0, core::vector3df(128,128,-100), core::vector3df(128,128,128)); + + scene::SMeshBuffer Buffer; + + Buffer.Material.Wireframe = false; + Buffer.Material.Lighting = false; + Buffer.Material.FogEnable = false; + Buffer.Material.BackfaceCulling = false; + Buffer.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + + device->getRandomizer()->reset(); + const u32 points=256; + Buffer.Vertices.reallocate(points); + for (u32 i=0; igetRandomizer()->rand()%points); + f32 y = (f32)(1+device->getRandomizer()->rand()%points); + f32 z = (f32)(1+device->getRandomizer()->rand()%points); + video::SColor color(255, device->getRandomizer()->rand()%255, device->getRandomizer()->rand()%255, device->getRandomizer()->rand()%255); + Buffer.Vertices.push_back( video::S3DVertex(x,y,z,0,1,0,color,0,0) ); + } + Buffer.recalculateBoundingBox(); + for (u32 i=0; ibeginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,100,101,140)); + smgr->drawAll(); + u32 primCount = 0; + switch (Type) + { + case scene::EPT_POINTS: primCount = Buffer.Indices.size(); break; + case scene::EPT_LINE_STRIP: primCount = Buffer.Indices.size()-1; break; + case scene::EPT_LINE_LOOP: primCount = Buffer.Indices.size()-1; break; + case scene::EPT_LINES: primCount = Buffer.Indices.size()/2; break; + case scene::EPT_TRIANGLE_STRIP: primCount = Buffer.Indices.size()-2; break; + case scene::EPT_TRIANGLE_FAN: primCount = Buffer.Indices.size()-2; break; + case scene::EPT_TRIANGLES: primCount = Buffer.Indices.size()/3; break; + case scene::EPT_QUAD_STRIP: primCount = (Buffer.Indices.size()-2)/4; break; + case scene::EPT_QUADS: primCount = Buffer.Indices.size()/4; break; + case scene::EPT_POLYGON: primCount = Buffer.Indices.size()-1; break; + case scene::EPT_POINT_SPRITES: primCount = Buffer.Indices.size(); break; + default: break; + } + + // TODO: mode is buggy, but required for skybox. So driver supports it, but would core dump here. + if (driverType==video::EDT_BURNINGSVIDEO && Type==scene::EPT_TRIANGLE_FAN) + continue; + driver->setMaterial(Buffer.Material); + driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); + driver->drawVertexPrimitiveList(Buffer.getVertices(), + Buffer.getVertexCount(), Buffer.getIndices(), primCount, + video::EVT_STANDARD, (scene::E_PRIMITIVE_TYPE)Type, + video::EIT_16BIT); + driver->endScene(); + core::stringc name = "-drawVPL_"; + // we use character enumeration as we have more than 9 types + name.append(Type-scene::EPT_POINTS+'a'); + name.append(".png"); + result &= takeScreenshotAndCompareAgainstReference(driver, name.c_str(), 99.5f); + } + + device->closeDevice(); + device->run(); + device->drop(); + + return result ; +} +} + +bool drawVertexPrimitive(void) +{ + bool result = true; + TestWithAllDrivers(testWithDriver); + return result; +} diff --git a/tests/empty/empty/Direct3D 9.0.png b/tests/empty/empty/Direct3D 9.0.png new file mode 100644 index 00000000..66f160a8 Binary files /dev/null and b/tests/empty/empty/Direct3D 9.0.png differ diff --git a/tests/empty/empty/Irrlicht Software Device 1.0.png b/tests/empty/empty/Irrlicht Software Device 1.0.png new file mode 100644 index 00000000..b5389f1d Binary files /dev/null and b/tests/empty/empty/Irrlicht Software Device 1.0.png differ diff --git a/tests/empty/empty/OpenGL 2.1.2.png b/tests/empty/empty/OpenGL 2.1.2.png new file mode 100644 index 00000000..a88e0476 Binary files /dev/null and b/tests/empty/empty/OpenGL 2.1.2.png differ diff --git a/tests/empty/empty/burnings video 0.39b.png b/tests/empty/empty/burnings video 0.39b.png new file mode 100644 index 00000000..de345676 Binary files /dev/null and b/tests/empty/empty/burnings video 0.39b.png differ diff --git a/tests/enumerateImageManipulators.cpp b/tests/enumerateImageManipulators.cpp new file mode 100644 index 00000000..556ba4cd --- /dev/null +++ b/tests/enumerateImageManipulators.cpp @@ -0,0 +1,133 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace scene; +using namespace video; + +bool enumerateImageManipulators(void) +{ + IrrlichtDevice *device = createDevice(video::EDT_NULL); + if (!device) + return false; + + IVideoDriver* driver = device->getVideoDriver(); + + const char* filenames[] = + { + "foo.bmp", + "foo.jpg", + "foo.pcx", + "foo.png", + "foo.ppm", + "foo.psd", + "foo.tga", + // the following have no writers + "foo.wal", + "foo.pgm", + "foo.pbm", + "foo.rgb", + "foo.rgba", + "foo.sgi", + "foo.int", + "foo.inta", + "foo.bw" + }; + // how many formats have loaders? + const u32 writersUntil = 7; + + const u32 numberOfFilenames = sizeof(filenames) / sizeof(filenames[0]); + bool loaderForFilename[numberOfFilenames] = { false }; // and the rest get 0 == false + bool writerForFilename[numberOfFilenames] = { false }; // and the rest get 0 == false + + bool result = true; + + u32 i; + const u32 loaders = driver->getImageLoaderCount(); + for (i = 0; i < loaders; ++i) + { + IImageLoader * loader = driver->getImageLoader(i); + + if(!loader) + { + logTestString("Failed to get image loader %d\n", i); + assert_log(false); + result = false; + } + + for(u32 filename = 0; filename < numberOfFilenames; ++filename) + { + if(loader->isALoadableFileExtension(filenames[filename])) + { + loaderForFilename[filename] = true; + } + } + } + + IImageLoader * loader = driver->getImageLoader(i); + assert_log(loader == 0); + if(loader) + { + logTestString("Got a loader when none was expected (%d)\n", i); + result = false; + } + + for(u32 filename = 0; filename < numberOfFilenames; ++filename) + { + if(!loaderForFilename[filename]) + { + logTestString("File type '%s' doesn't have a loader\n", filenames[filename]); + assert_log(false); + result = false; + } + } + + const u32 writers = driver->getImageWriterCount(); + for (i = 0; i < writers; ++i) + { + IImageWriter * writer = driver->getImageWriter(i); + + if(!writer) + { + logTestString("Failed to get image writer %d\n", i); + assert_log(false); + result = false; + } + + for(u32 filename = 0; filename < numberOfFilenames; ++filename) + { + if(writer->isAWriteableFileExtension(filenames[filename])) + { + writerForFilename[filename] = true; + break; + } + } + } + + IImageWriter * writer = driver->getImageWriter(i); + assert_log(writer == 0); + if(writer) + { + logTestString("Got a writer when none was expected (%d)\n", i); + result = false; + } + + for(u32 filename = 0; filename < numberOfFilenames; ++filename) + { + // There's no writer for the .WAL file type. + if(!writerForFilename[filename] && (filenamecloseDevice(); + device->run(); + device->drop(); + + return result; +} diff --git a/tests/exports.cpp b/tests/exports.cpp new file mode 100644 index 00000000..7bbc2eee --- /dev/null +++ b/tests/exports.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +//! Tests that symbols exported from Irrlicht can be used by the user app. +bool exports(void) +{ + logTestString("Checking whether IdentityMatrix is exported.\n"); + irr::core::matrix4 identity = irr::core::IdentityMatrix; + (void)identity; // Satisfy the compiler that it's used. + + irr::video::SMaterial id = irr::video::IdentityMaterial; + (void)id; // Satisfy the compiler that it's used. + // If it built, we're done. + return true; +} diff --git a/tests/fast_atof.cpp b/tests/fast_atof.cpp new file mode 100644 index 00000000..46ecb573 --- /dev/null +++ b/tests/fast_atof.cpp @@ -0,0 +1,290 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; + +//! This was an older Irrlicht implementation, tested against for reference. +static inline u32 old_strtol10(const char* in, const char** out=0) +{ + u32 value = 0; + + while ( ( *in >= '0') && ( *in <= '9' )) + { + value = ( value * 10 ) + ( *in - '0' ); + ++in; + } + if (out) + *out = in; + return value; +} + +//! This was an older Irrlicht implementation, tested against for reference. +static inline const char* old_fast_atof_move( const char* c, float& out) +{ + bool inv = false; + const char *t; + float f; + + if (*c=='-') + { + ++c; + inv = true; + } + + //f = (float)strtol(c, &t, 10); + f = (float) old_strtol10 ( c, &c ); + + if (*c == '.') + { + ++c; + + //float pl = (float)strtol(c, &t, 10); + float pl = (float) old_strtol10 ( c, &t ); + pl *= fast_atof_table[t-c]; + + f += pl; + + c = t; + + if (*c == 'e') + { + ++c; + //float exp = (float)strtol(c, &t, 10); + bool einv = (*c=='-'); + if (einv) + ++c; + + float exp = (float)old_strtol10(c, &c); + if (einv) + exp *= -1.0f; + + f *= (float)pow(10.0f, exp); + } + } + + if (inv) + f *= -1.0f; + + out = f; + return c; +} + +//! This was an older Irrlicht implementation, tested against for reference. +static inline float old_fast_atof(const char* c) +{ + float ret; + old_fast_atof_move(c, ret); + return ret; +} + + +static bool testCalculation_atof(const char * valueString) +{ + const f32 newFastValue = fast_atof(valueString); + const f32 oldFastValue = old_fast_atof(valueString); + const f32 atofValue = (f32)atof(valueString); + + logTestString("\n String '%s'\n New fast %.40f\n Old fast %.40f\n atof %.40f\n", + valueString, newFastValue, oldFastValue, atofValue); + + const f32 diffNew = fabs(newFastValue - atofValue) ; + const f32 diffOld = fabs(oldFastValue - atofValue) ; + bool accurate = diffNew <= diffOld || equalsByUlp(diffNew, diffOld, 1); + + if(!accurate) + logTestString("*** ERROR - less accurate than old method ***\n\n"); + + return accurate; +} + +static bool testCalculation_strtol(const char * valueString) +{ + const s32 newFastValue = strtol10(valueString); + const s32 oldFastValue = old_strtol10(valueString); + const s32 strtolValue = (s32)clamp(strtol(valueString, 0, 10), (long int)INT_MIN, (long int)INT_MAX); + + logTestString("\n String '%s'\n New fast %d\n Old fast %d\n strtol %d\n", + valueString, newFastValue, oldFastValue, strtolValue); + + bool accurate = (newFastValue == strtolValue) || (oldFastValue != strtolValue); + + if (!accurate) + logTestString("*** ERROR - wrong calculation in new method ***\n\n"); + + return accurate; +} + +//! Test both the accuracy and speed of Irrlicht's fast_atof() implementation. +bool test_fast_atof(void) +{ + bool accurate = true; + + accurate &= testCalculation_atof("340282346638528859811704183484516925440.000000"); + accurate &= testCalculation_atof("3.402823466e+38F"); + accurate &= testCalculation_atof("3402823466e+29F"); + accurate &= testCalculation_atof("-340282346638528859811704183484516925440.000000"); + accurate &= testCalculation_atof("-3.402823466e+38F"); + accurate &= testCalculation_atof("-3402823466e+29F"); + accurate &= testCalculation_atof("34028234663852885981170418348451692544.000000"); + accurate &= testCalculation_atof("3.402823466e+37F"); + accurate &= testCalculation_atof("3402823466e+28F"); + accurate &= testCalculation_atof("-34028234663852885981170418348451692544.000000"); + accurate &= testCalculation_atof("-3.402823466e+37F"); + accurate &= testCalculation_atof("-3402823466e+28F"); + accurate &= testCalculation_atof(".00234567"); + accurate &= testCalculation_atof("-.00234567"); + accurate &= testCalculation_atof("0.00234567"); + accurate &= testCalculation_atof("-0.00234567"); + accurate &= testCalculation_atof("1.175494351e-38F"); + accurate &= testCalculation_atof("1175494351e-47F"); + accurate &= testCalculation_atof("1.175494351e-37F"); + accurate &= testCalculation_atof("1.175494351e-36F"); + accurate &= testCalculation_atof("-1.175494351e-36F"); + accurate &= testCalculation_atof("123456.789"); + accurate &= testCalculation_atof("-123456.789"); + accurate &= testCalculation_atof("0000123456.789"); + accurate &= testCalculation_atof("-0000123456.789"); + accurate &= testCalculation_atof("-0.0690462109446526"); + accurate &= testCalculation_atof("0.11999999731779099"); // more numbers past dot than in lookup table + accurate &= testCalculation_atof("0.119999997317790999"); + + if (!accurate) + { + logTestString("Calculation is not accurate, so the speed is irrelevant\n"); + return false; + } + +#ifndef _DEBUG // it's only faster in release + IrrlichtDevice* device = createDevice(video::EDT_NULL); + if (!device) + return false; + ITimer* timer = device->getTimer(); + + const int ITERATIONS = 100000; + int i; + + f32 value; + u32 then = timer->getRealTime(); + for(i = 0; i < ITERATIONS; ++i) + value = (f32)atof("-340282346638528859811704183484516925440.000000"); + + const u32 atofTime = timer->getRealTime() - then; + + then += atofTime; + for(i = 0; i < ITERATIONS; ++i) + value = fast_atof("-340282346638528859811704183484516925440.000000"); + const u32 fastAtofTime = timer->getRealTime() - then; + + then += fastAtofTime; + for(i = 0; i < ITERATIONS; ++i) + value = old_fast_atof("-340282346638528859811704183484516925440.000000"); + const u32 oldFastAtofTime = timer->getRealTime() - then; + + logTestString("Speed test\n atof time = %d\n fast_atof Time = %d\nold fast_atof time = %d\n", + atofTime, fastAtofTime, oldFastAtofTime); + + device->closeDevice(); + device->run(); + device->drop(); + + if(fastAtofTime > (1.2f*atofTime)) + { + logTestString("The fast method is slower than atof()\n"); + return false; + } +#endif // #ifndef _DEBUG + + return true; +} + +//! Test both the accuracy and speed of Irrlicht's strtol10() implementation. +bool test_strtol(void) +{ + bool accurate = true; + + accurate &= testCalculation_strtol("340282346638528859811704183484516925440"); + accurate &= testCalculation_strtol("3402823466"); + accurate &= testCalculation_strtol("3402823466e+29F"); + accurate &= testCalculation_strtol("-340282346638528859811704183484516925440"); + accurate &= testCalculation_strtol("-3402823466"); + accurate &= testCalculation_strtol("-3402823466e+29F"); + accurate &= testCalculation_strtol("402823466385288598117"); + accurate &= testCalculation_strtol("402823466"); + accurate &= testCalculation_strtol("402823466e+28F"); + accurate &= testCalculation_strtol("402823466385288598117"); + accurate &= testCalculation_strtol("-402823466"); + accurate &= testCalculation_strtol("-402823466e+28F"); + accurate &= testCalculation_strtol(".00234567"); + accurate &= testCalculation_strtol("-234567"); + accurate &= testCalculation_strtol("234567"); + accurate &= testCalculation_strtol("-234567"); + accurate &= testCalculation_strtol("1175494351"); + accurate &= testCalculation_strtol("11754943512"); + accurate &= testCalculation_strtol("11754943513"); + accurate &= testCalculation_strtol("11754943514"); + accurate &= testCalculation_strtol("-1175494351"); + accurate &= testCalculation_strtol("123456789"); + accurate &= testCalculation_strtol("-123456789"); + accurate &= testCalculation_strtol("123456.789"); + accurate &= testCalculation_strtol("-123456.789"); + accurate &= testCalculation_strtol("-109446526"); + + if(!accurate) + { + logTestString("Calculation is not accurate, so the speed is irrelevant\n"); + return false; + } + +#ifndef _DEBUG // it's only faster in release + IrrlichtDevice* device = createDevice(video::EDT_NULL); + if (!device) + return false; + ITimer* timer = device->getTimer(); + + const int ITERATIONS = 1000000; + int i; + + s32 value; + u32 then = timer->getRealTime(); + for(i = 0; i < ITERATIONS; ++i) + value = strtol("-3402823466", 0, 10); + + const u32 strtolTime = timer->getRealTime() - then; + + then += strtolTime; + for(i = 0; i < ITERATIONS; ++i) + value = strtol10("-3402823466"); + const u32 strtol10Time = timer->getRealTime() - then; + + then += strtol10Time; + for(i = 0; i < ITERATIONS; ++i) + value = old_strtol10("-3402823466"); + const u32 oldstrtol10Time = timer->getRealTime() - then; + + logTestString("Speed test\n strtol time = %d\n strtol10 time = %d\nold strtol10 time = %d\n", + strtolTime, strtol10Time, oldstrtol10Time); + + device->closeDevice(); + device->run(); + device->drop(); + + if (strtol10Time > (1.2f*strtolTime)) + { + logTestString("The fast method is slower than strtol()\n"); + return false; + } +#endif // #ifndef _DEBUG + + return true; +} + +bool fast_atof(void) +{ + bool ok = true; + ok &= test_fast_atof() ; + ok &= test_strtol(); + return ok; +} diff --git a/tests/filesystem.cpp b/tests/filesystem.cpp new file mode 100644 index 00000000..fed70d1c --- /dev/null +++ b/tests/filesystem.cpp @@ -0,0 +1,183 @@ +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace io; + +static bool testgetAbsoluteFilename(io::IFileSystem* fs) +{ + bool result=true; + io::path apath = fs->getAbsolutePath("media"); + io::path cwd = fs->getWorkingDirectory(); + if (apath!=(cwd+"/media")) + { + logTestString("getAbsolutePath failed on existing dir %s\n", apath.c_str()); + result = false; + } + + apath = fs->getAbsolutePath("../media/"); + core::deletePathFromPath(cwd, 1); + if (apath!=(cwd+"media/")) + { + logTestString("getAbsolutePath failed on dir with postfix / %s\n", apath.c_str()); + result = false; + } + + apath = fs->getAbsolutePath ("../nothere.txt"); // file does not exist + if (apath!=(cwd+"nothere.txt")) + { + logTestString("getAbsolutePath failed on non-existing file %s\n", apath.c_str()); + result = false; + } + + return result; +} + +static bool testFlattenFilename(io::IFileSystem* fs) +{ + bool result=true; + io::path tmpString="../tmp"; + io::path refString="../tmp/"; + fs->flattenFilename(tmpString); + if (tmpString != refString) + { + logTestString("flattening destroys path.\n%s!=%s\n", tmpString.c_str(),refString.c_str()); + result = false; + } + + tmpString="tmp/tmp/../"; + refString="tmp/"; + fs->flattenFilename(tmpString); + if (tmpString != refString) + { + logTestString("flattening destroys path.\n%s!=%s\n", tmpString.c_str(),refString.c_str()); + result = false; + } + + tmpString="tmp/tmp/.."; + fs->flattenFilename(tmpString); + if (tmpString != refString) + { + logTestString("flattening destroys path.\n%s!=%s\n", tmpString.c_str(),refString.c_str()); + result = false; + } + + tmpString="tmp/next/../third"; + refString="tmp/third/"; + fs->flattenFilename(tmpString); + if (tmpString != refString) + { + logTestString("flattening destroys path.\n%s!=%s\n", tmpString.c_str(),refString.c_str()); + result = false; + } + + tmpString="this/tmp/next/../../my/fourth"; + refString="this/my/fourth/"; + fs->flattenFilename(tmpString); + if (tmpString != refString) + { + logTestString("flattening destroys path.\n%s!=%s\n", tmpString.c_str(),refString.c_str()); + result = false; + } + + tmpString="this/is/../../../a/fifth/test/"; + refString="../a/fifth/test/"; + fs->flattenFilename(tmpString); + if (tmpString != refString) + { + logTestString("flattening destroys path.\n%s!=%s\n", tmpString.c_str(),refString.c_str()); + result = false; + } + + tmpString="this/../is/../../a/sixth/test/"; + refString="../a/sixth/test/"; + fs->flattenFilename(tmpString); + if (tmpString != refString) + { + logTestString("flattening destroys path.\n%s!=%s\n", tmpString.c_str(),refString.c_str()); + result = false; + } + + return result; +} + +static bool testgetRelativeFilename(io::IFileSystem* fs) +{ + bool result=true; + io::path apath = fs->getAbsolutePath("media"); + io::path cwd = fs->getWorkingDirectory(); + if (fs->getRelativeFilename(apath, cwd) != "media") + { + logTestString("getRelativePath failed on %s\n", apath.c_str()); + result = false; + } + + apath = fs->getAbsolutePath("../media/"); + if (fs->getRelativeFilename(apath, cwd) != "../media/") + { + logTestString("getRelativePath failed on %s\n", apath.c_str()); + result = false; + } + + return result; +} + +bool filesystem(void) +{ + IrrlichtDevice * device = irr::createDevice(video::EDT_NULL, dimension2d(1, 1)); + assert_log(device); + if(!device) + return false; + + io::IFileSystem * fs = device->getFileSystem (); + if ( !fs ) + return false; + + bool result = true; + + io::path workingDir = device->getFileSystem()->getWorkingDirectory(); + + io::path empty; + if ( fs->existFile(empty) ) + { + logTestString("Empty filename should not exist.\n"); + result = false; + } + + io::path newWd = workingDir + "/media"; + bool changed = device->getFileSystem()->changeWorkingDirectoryTo(newWd); + assert_log(changed); + + if ( fs->existFile(empty) ) + { + logTestString("Empty filename should not exist even in another workingdirectory.\n"); + result = false; + } + + // The working directory must be restored for the other tests to work. + changed = device->getFileSystem()->changeWorkingDirectoryTo(workingDir.c_str()); + assert_log(changed); + + // adding a folder archive which just should not really change anything + device->getFileSystem()->addFileArchive( "./" ); + + if ( fs->existFile(empty) ) + { + logTestString("Empty filename should not exist in folder file archive.\n"); + result = false; + } + + // remove it again to not affect other tests + device->getFileSystem()->removeFileArchive( device->getFileSystem()->getFileArchiveCount() ); + + result &= testFlattenFilename(fs); + result &= testgetAbsoluteFilename(fs); + result &= testgetRelativeFilename(fs); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + diff --git a/tests/flyCircleAnimator.cpp b/tests/flyCircleAnimator.cpp new file mode 100644 index 00000000..272dd895 --- /dev/null +++ b/tests/flyCircleAnimator.cpp @@ -0,0 +1,60 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.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(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0, 80, 80, 80))) + { + smgr->drawAll(); + driver->endScene(); + result = takeScreenshotAndCompareAgainstReference(driver, "-flyCircleAnimator.png", 100); + } + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + diff --git a/tests/guiDisabledMenu.cpp b/tests/guiDisabledMenu.cpp new file mode 100644 index 00000000..9ca2466f --- /dev/null +++ b/tests/guiDisabledMenu.cpp @@ -0,0 +1,58 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace gui; + +// Tests that disabled GUI menu items don't cause their submenu to appear when hovered over. +/** + http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?p=178436#178436 + */ + +bool guiDisabledMenu(void) +{ + IrrlichtDevice *device = createDevice( video::EDT_BURNINGSVIDEO, + dimension2d(160, 40), 32); + assert_log(device); + if (!device) + return false; + + video::IVideoDriver* driver = device->getVideoDriver(); + gui::IGUIEnvironment* env = device->getGUIEnvironment(); + + gui::IGUIContextMenu* menu = env->addMenu(); + menu->addItem(L"Menu", -1, true, true); + gui::IGUIContextMenu* subMenu = menu->getSubMenu(0); + subMenu->addItem(L"Submenu 1", -1, false, true); + gui::IGUIContextMenu* subSubMenu = subMenu->getSubMenu(0); + subSubMenu->addItem(L"Final item"); + + SEvent event; + event.EventType = EET_MOUSE_INPUT_EVENT; + event.MouseInput.Event = EMIE_LMOUSE_PRESSED_DOWN; + event.MouseInput.X = menu->getAbsolutePosition().UpperLeftCorner.X + 1; + event.MouseInput.Y = menu->getAbsolutePosition().UpperLeftCorner.Y + 1; + (void)menu->OnEvent(event); + + // Hovering over the disabled submenu shouldn't cause the "Final item" to appear. + event.MouseInput.Event = EMIE_MOUSE_MOVED; + event.MouseInput.X = subMenu->getAbsolutePosition().UpperLeftCorner.X + 40; + event.MouseInput.Y = subMenu->getAbsolutePosition().UpperLeftCorner.Y + 10; + (void)menu->OnEvent(event); + + device->run(); + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(150,50,50,50)); + env->drawAll(); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-guiDisabledMenu.png", 98.77f); + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + diff --git a/tests/ioScene.cpp b/tests/ioScene.cpp new file mode 100644 index 00000000..f36f33b1 --- /dev/null +++ b/tests/ioScene.cpp @@ -0,0 +1,132 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +// Tests save scene. +static bool saveScene(void) +{ + IrrlichtDevice *device = createDevice( EDT_NULL, dimension2d(160, 120), 32); + assert_log(device); + if (!device) + return false; + + ISceneManager * smgr = device->getSceneManager(); + + ISkinnedMesh* mesh = (ISkinnedMesh*)smgr->getMesh("../media/ninja.b3d"); + if (!mesh) + return false; + + IAnimatedMeshSceneNode* node1 = smgr->addAnimatedMeshSceneNode(mesh); + if (node1) + { + node1->setPosition(vector3df(-3, -3, 10)); + node1->setMaterialFlag(EMF_LIGHTING, false); + node1->setAnimationSpeed(0.f); + node1->setCurrentFrame(10.f); + node1->setDebugDataVisible(irr::scene::EDS_BBOX_BUFFERS); + } + + ISkinnedMesh* mesh2 = (ISkinnedMesh*)smgr->getMesh(device->getFileSystem()->getAbsolutePath("../media/dwarf.x")); + if (!mesh2) + return false; + + IAnimatedMeshSceneNode* node2 = smgr->addAnimatedMeshSceneNode(mesh2); + if (node2) + { + node2->setPosition(vector3df(33, -93, 120)); + node2->setMaterialFlag(EMF_LIGHTING, false); + node2->setAnimationSpeed(10.f); + node2->setCurrentFrame(2.f); + } + + IAnimatedMeshSceneNode* node3 = smgr->addAnimatedMeshSceneNode(mesh2, node2); + if (node3) + { + node3->setPosition(vector3df(-88, -300, 150)); + node3->setMaterialFlag(EMF_LIGHTING, false); + node3->setAnimationSpeed(0.f); + node3->setCurrentFrame(12.f); + } + + smgr->addCameraSceneNode(); + + logTestString("Test scene.irr"); + smgr->saveScene("results/scene.irr"); + bool result = xmlCompareFiles(device->getFileSystem(), "results/scene.irr", "media/scene.irr"); + + logTestString("Test scene2.irr"); + smgr->saveScene("results/scene2.irr", 0, node3); + result &= xmlCompareFiles(device->getFileSystem(), "results/scene2.irr", "media/scene2.irr"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +static bool loadScene(void) +{ + IrrlichtDevice *device = createDevice(video::EDT_BURNINGSVIDEO, + core::dimension2du(160,120), 32); + if (!device) + return false; + + IVideoDriver* driver = device->getVideoDriver(); + ISceneManager* smgr = device->getSceneManager(); + // load scene from example, with correct relative path + device->getFileSystem()->changeWorkingDirectoryTo("results"); + smgr->loadScene("../../media/example.irr"); + smgr->addCameraSceneNode(0, core::vector3df(0,0,-50)); + device->getFileSystem()->changeWorkingDirectoryTo(".."); + + bool result = false; + device->run(); + device->getTimer()->setTime(666); // scene has animations and current scene seems to be saved at that time ... really - best result with just that number :-) + if (driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0, 80, 80, 80))) + { + smgr->drawAll(); + driver->endScene(); + // we need to be very sloppy, because the animators will produce a different + // start depending on the actual loading time. 97% seems to be safe, as removing + // an object produces values around 95% + result = takeScreenshotAndCompareAgainstReference(driver, "-loadScene.png", 97.4f); + if (!result) + logTestString("Rendering the loaded scene failed.\n"); + } + + ISceneNode* node = smgr->getSceneNodeFromId(128); + if (!node) + result=false; + else if (result) // only check if scene was correctly loaded + { + result &= (node->getChildren().size()==0); + if (!result) + logTestString("Node has an illegal child node.\n"); + device->getSceneManager()->loadScene("results/scene2.irr", 0, node); + result &= (node->getChildren().size()!=0); + if (!result) + logTestString("Loading second scene as child failed.\n"); + } + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +bool ioScene(void) +{ + bool result = saveScene(); + result &= loadScene(); + return result; +} diff --git a/tests/irrArray.cpp b/tests/irrArray.cpp new file mode 100644 index 00000000..12d46b32 --- /dev/null +++ b/tests/irrArray.cpp @@ -0,0 +1,184 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" +#include + +using namespace irr; +using namespace core; + +core::map countReferences; + +struct SDummy +{ + SDummy(int a) : x(a) + { + countReferences.insert(x,1); + } + + SDummy() : x(0) + { + countReferences.insert(x,1); + } + + SDummy(const SDummy& other) + { + x = other.x; + countReferences[x] = countReferences[x] + 1; + } + + ~SDummy() + { + countReferences[x] = countReferences[x] - 1; + } + + int x; +}; + +static bool testErase() +{ + { + core::array aaa; + aaa.push_back(SDummy(0)); + aaa.push_back(SDummy(1)); + aaa.push_back(SDummy(2)); + aaa.push_back(SDummy(3)); + aaa.push_back(SDummy(4)); + aaa.push_back(SDummy(5)); + + aaa.erase(0,2); + } + + for ( core::map::Iterator it = countReferences.getIterator(); !it.atEnd(); it++ ) + { + if ( it->getValue() != 0 ) + { + logTestString("testErase: wrong count for %d, it's: %d\n", it->getKey(), it->getValue()); + return false; + } + } + return true; +} + + +struct VarArray +{ + core::array < int, core::irrAllocatorFast > MyArray; +}; + +static bool testSelfAssignment() +{ + core::array myArray; + myArray.push_back(1); + myArray = myArray; + return myArray.size() == 1; +} + +// this will (did once) crash when wrong due to deallocating memory twice, so no return value +static void crashTestFastAlloc() +{ + core::array < VarArray, core::irrAllocatorFast > ArrayArray; + ArrayArray.setAllocStrategy(core::ALLOC_STRATEGY_SAFE); // force more re-allocations + VarArray var; + var.MyArray.setAllocStrategy(core::ALLOC_STRATEGY_SAFE); // force more re-allocations + var.MyArray.push_back( 0 ); + + for ( int i=0; i< 100; ++i ) + { + ArrayArray.push_back(var); + ArrayArray.push_back(var); + } +} + +static bool testSwap() +{ + bool result = true; + + core::array array1, array2, copy1, copy2; + for ( int i=0; i<99; ++i ) + { + array1.push_back(i); + if ( i < 10 ) // we want also different container sizes + array2.push_back(99-i); + } + copy1 = array1; + copy2 = array2; + array1.swap(array2); + + result &= (array1 == copy2); + result &= (array2 == copy1); + + assert_log( result ); + + return result; +} + +// add numbers to the array going down from size to 1 +static void addInvNumbers(irr::core::array& arr, irr::u32 size) +{ + for ( irr::u32 i=0; i& arr) +{ + for ( irr::u32 i=1; i< arr.size(); ++ i) + { + if ( arr[i-1] > arr[i] ) + return false; + } + + return true; +} + +static bool testSort() +{ + irr::core::array arr; + for ( irr::u32 i=0; i<1000; ++i ) + { + arr.clear(); + addInvNumbers(arr, i); + arr.sort(); + if ( !validateSortedAscending(arr) ) + { + return false; + } + } + + for ( irr::u32 i=0; i<1000; ++i ) + { + arr.clear(); + addInvNumbers(arr, i); + addInvNumbers(arr, i); + arr.sort(); + if ( !validateSortedAscending(arr) ) + { + return false; + } + } + + return true; +} + +// Test the functionality of core::array +bool testIrrArray(void) +{ + bool allExpected = true; + + logTestString("crashTestFastAlloc\n"); + crashTestFastAlloc(); + allExpected &= testSelfAssignment(); + allExpected &= testSwap(); + allExpected &= testErase(); + allExpected &= testSort(); + + if(allExpected) + logTestString("\nAll tests passed\n"); + else + logTestString("\nFAIL!\n"); + + return allExpected; +} diff --git a/tests/irrCoreEquals.cpp b/tests/irrCoreEquals.cpp new file mode 100644 index 00000000..45c176ac --- /dev/null +++ b/tests/irrCoreEquals.cpp @@ -0,0 +1,132 @@ +// Copyright (C) 2008-2012 Colin MacDonald and Christian Stehno +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +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, 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, 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/irrList.cpp b/tests/irrList.cpp new file mode 100644 index 00000000..de1ec913 --- /dev/null +++ b/tests/irrList.cpp @@ -0,0 +1,76 @@ +#include "testUtils.h" +#include + +using namespace irr; +using namespace core; + +// list has no operator== currently so we have to check manually +// TODO: Add an operator== to core::list and the kick this function out +template +static bool compareLists(const core::list & a, const core::list & b) +{ + if ( a.size() != b.size() ) + return false; + // can't test allocator because we have no access to it here + typename core::list::ConstIterator iterA = a.begin(); + typename core::list::ConstIterator iterB = b.begin(); + for ( ; iterA != a.end(); ++iterA, ++iterB ) + { + if ( (*iterA) != (*iterB) ) + return false; + } + return true; +} + +// Make sure that we can get a const iterator from a non-const list +template +static void constIteratorCompileTest(core::list & a) +{ + typename core::list::ConstIterator iterA = a.begin(); + while (iterA != a.end() ) + { + ++iterA; + } +} + +static bool testSwap() +{ + bool result = true; + + core::list list1, list2, copy1, copy2; + for ( int i=0; i<99; ++i ) + { + list1.push_back(i); + if ( i < 10 ) // we want also different container sizes i < 50 ) + list2.push_back(99-i); + } + copy1 = list1; + copy2 = list2; + list1.swap(list2); + + + result &= compareLists(list1, copy2); + result &= compareLists(list2, copy1); + + assert_log( result ); + + return result; +} + +// Test the functionality of core::list +bool testIrrList(void) +{ + bool success = true; + + core::list compileThisList; + constIteratorCompileTest(compileThisList); + + success &= testSwap(); + + if(success) + logTestString("\nAll tests passed\n"); + else + logTestString("\nFAIL!\n"); + + return success; +} diff --git a/tests/irrMap.cpp b/tests/irrMap.cpp new file mode 100644 index 00000000..7ce85dfb --- /dev/null +++ b/tests/irrMap.cpp @@ -0,0 +1,64 @@ +#include "testUtils.h" +#include + +using namespace irr; +using namespace core; + +// map has no operator== currently so we have to check manually +// TODO: Add an operator== to core::map and the kick this function out +template +static bool compareMaps(core::map & a, core::map & b) +{ + if ( a.size() != b.size() ) + return false; + // can't test allocator because we have no access to it here + typename core::map::Iterator iterA = a.getIterator(); + typename core::map::Iterator iterB = b.getIterator(); + for ( ; !iterA.atEnd(); iterA++, iterB++ ) // TODO: only iter++, no ++iter in irr::map + { + if ( iterA->getValue() != iterB->getValue() ) + return false; + } + return true; +} + + +static bool testSwap() +{ + bool result = true; + + core::map map1, map2, copy1, copy2; + for ( int i=0; i<99; ++i ) + { + map1[i] = i; + copy1[i] = i; // TODO: whatever the reason - irr::map does not want operator= so we have to assign to identical values + if ( i < 10 ) // we want also different container sizes + { + map2[i] = 99-i; + copy2[i] = 99-i; // TODO: whatever the reason - irr::map does not want operator= so we have to assign to identical values + } + } + map1.swap(map2); + + result &= compareMaps(map1, copy2); + result &= compareMaps(map2, copy1); + + assert_log( result ); + + return result; +} + +// Test the functionality of core::list +bool testIrrMap(void) +{ + bool success = true; + + success &= testSwap(); + + if(success) + logTestString("\nAll tests passed\n"); + else + logTestString("\nFAIL!\n"); + + return success; +} diff --git a/tests/irrString.cpp b/tests/irrString.cpp new file mode 100644 index 00000000..a5298ff6 --- /dev/null +++ b/tests/irrString.cpp @@ -0,0 +1,415 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" +#include + +using namespace irr; +using namespace core; + +static bool testSelfAssignment() +{ + core::stringw myString(L"foo"); + myString = myString; + return myString == core::stringw(L"foo"); +} + +static bool testSplit() +{ + logTestString("Test stringw::split()\n"); + core::stringw teststring(L"[b]this [/b] is a [color=0xff000000]test[/color]."); + core::list parts1; + teststring.split >(parts1, L"["); + core::array parts2; + teststring.split >(parts2, L"[", 1, false, true); + return (parts1.size()==4) && (parts2.size()==9); +} + +static bool testFastAlloc() +{ + core::string > FastString(L"abc"); + core::string > FastStringLong(L"longer"); + + FastString = L"test"; + + // cause a reallocation + FastString = FastStringLong; + + // this test should either not compile or crash when the allocaters are messed up + return true; +} + +static bool testReplace() +{ + // test string getting longer + core::stringw str = L"no"; + str.replace(L"no", L"yes"); + if ( str != L"yes" ) + return false; + str = L"nonono"; + str.replace(L"no", L"yes"); + if ( str != L"yesyesyes" ) + return false; + str = L"nomaybenomaybeno"; + str.replace(L"no", L"yes"); + if ( str != L"yesmaybeyesmaybeyes" ) + return false; + + // test string staying same length + str = L"one"; + str.replace(L"one", L"two"); + if ( str != L"two" ) + return false; + str = L"oneone"; + str.replace(L"one", L"two"); + if ( str != L"twotwo" ) + return false; + + // test string getting shorter + str = L"yes"; + str.replace(L"yes", L"no"); + if ( str != L"no" ) + return false; + + str = L"yesyes"; + str.replace(L"yes", L"no"); + if ( str != L"nono" ) + return false; + + // remove string-parts completely + str = L"killme"; + str.replace(L"killme", L""); + if ( str != L"" ) + return false; + + str = L"killmenow"; + str.replace(L"killme", L""); + if ( str != L"now" ) + return false; + + str = L"nowkillme"; + str.replace(L"killme", L""); + if ( str != L"now" ) + return false; + + // remove nothing + str = L"keepme"; + str.replace(L"", L"whatever"); + if ( str != L"keepme" ) + return false; + + str = L"keepme"; + str.replace(L"", L""); + if ( str != L"keepme" ) + return false; + + return true; +} + + +bool testAppendStringc() +{ + core::stringc str; + // Test with character + if (str != "") + return false; + str += 'W'; + if (str != "W") + return false; + str += 'i'; + if (str != "Wi") + return false; + str=""; + if (str != "") + return false; + + // Test with C-style string + str += "Another Test"; + if (str != "Another Test") + return false; + str=""; + str += 'A'; + str += "nother Test"; + if (str != "Another Test") + return false; + str=""; + + // Test with int + str += 10; + if (str != "10") + return false; + str += 0; + if (str != "100") + return false; + str=""; + str += "-32"; + if (str != "-32") + return false; + str=""; + + // Test with unsigned int + str += 21u; + if (str != "21") + return false; + str += 0u; + if (str != "210") + return false; + str=""; + + // Test with long int + str += 456l; + if (str != "456") + return false; + str += 0l; + if (str != "4560") + return false; + str=""; + str += -456l; + if (str != "-456") + return false; + str=""; + + // Test with unsigned long + str += 994ul; + if (str != "994") + return false; + str += 0ul; + if (str != "9940") + return false; + str=""; + return true; +} + +bool testInsert() +{ + core::stringc str; + + str.insert(0, "something", 4); + if (str != "some") + return false; + + str.insert(4, "thing", 5); + if (str != "something") + return false; + + str.insert(0, "is ", 3); + if (str != "is something") + return false; + + str.insert(3, "there ", 6); + if (str != "is there something") + return false; + + return true; +} + +bool testLowerUpper() +{ + irr::core::array stringsOrig, targetLower, targetUpper; + stringsOrig.push_back("abc"); + targetLower.push_back("abc"); + targetUpper.push_back("ABC"); + stringsOrig.push_back("ABC"); + targetLower.push_back("abc"); + targetUpper.push_back("ABC"); + stringsOrig.push_back("Abc"); + targetLower.push_back("abc"); + targetUpper.push_back("ABC"); + stringsOrig.push_back("aBBc"); + targetLower.push_back("abbc"); + targetUpper.push_back("ABBC"); + stringsOrig.push_back("abC"); + targetLower.push_back("abc"); + targetUpper.push_back("ABC"); + stringsOrig.push_back(""); + targetLower.push_back(""); + targetUpper.push_back(""); + /* TODO: those are not supported so far + stringsOrig.push_back("ßäöü"); + targetLower.push_back("ßäöü"); + targetUpper.push_back("ßÄÖÜ"); + stringsOrig.push_back("ßÄÖÜ"); + targetLower.push_back("ßäöü"); + targetUpper.push_back("ßÄÖÜ"); + */ + + for ( irr::u32 i=0; i= 0 ) + return false; + + irr::core::stringc empty(""); + p = empty.findLastCharNotInList("x",1); + if ( p >= 0 ) + return false; + + irr::core::stringc lastX("max"); + p = lastX.findLastCharNotInList("x",1); + if ( p != 1 ) + return false; + p = lastX.findLastCharNotInList("y",1); + if ( p != 2 ) + return false; + + p = empty.findLast('x'); + if ( p >= 0 ) + return false; + + p = dot.findLast('.'); + if ( p != 0 ) + return false; + + p = empty.findLastChar("ab", 2); + if ( p >= 0 ) + return false; + + p = dot.findLastChar("-.", 2); + if ( p != 0 ) + return false; + + return true; +} + +bool testErase() +{ + if ( stringc(1.f).eraseTrailingFloatZeros() != stringc("1") ) + return false; + + if ( stringc("0.100000").eraseTrailingFloatZeros() != stringc("0.1") ) + return false; + + if ( stringc("10.000000").eraseTrailingFloatZeros() != stringc("10") ) + return false; + + if ( stringc("foo 3.140000").eraseTrailingFloatZeros() != stringc("foo 3.14") ) + return false; + + if ( stringc("no_num.000").eraseTrailingFloatZeros() != stringc("no_num.000") ) + return false; + + if ( stringc("1.").eraseTrailingFloatZeros() != stringc("1.") ) + return false; + + return true; +} + +// Test the functionality of irrString +/** Validation is done with assert_log() against expected results. */ +bool testIrrString(void) +{ + bool allExpected = true; + + logTestString("Test stringc\n"); + { + // Check empty string + core::stringc empty; + assert_log(empty.size()==0); + assert_log(empty[0]==0); + assert_log(empty.c_str()!=0); + assert_log(*(empty.c_str())==0); + // Assign content + empty = "Test"; + assert_log(empty.size()==4); + assert_log(empty[0]=='T'); + assert_log(empty[3]=='t'); + assert_log(*(empty.c_str())=='T'); + //Assign empty string, should be same as in the beginning + empty = ""; + assert_log(empty.size()==0); + assert_log(empty[0]==0); + assert_log(*(empty.c_str())==0); + } + logTestString("Test stringw\n"); + { + core::stringw empty; + assert_log(empty.size()==0); + assert_log(empty[0]==0); + assert_log(empty.c_str()!=0); + assert_log(*(empty.c_str())==0); + empty = L"Test"; + assert_log(empty.size()==4); + assert_log(empty[0]==L'T'); + assert_log(empty[3]=='t'); + assert_log(*(empty.c_str())==L'T'); + empty = L""; + assert_log(empty.size()==0); + assert_log(empty[0]==0); + assert_log(*(empty.c_str())==0); + assert_log(allExpected &= testSplit()); + } + allExpected &= testAppendStringc(); + + allExpected &= testInsert(); + + logTestString("Test io::path\n"); + { + // Only test that this type exists, it's one from above + io::path myPath; + myPath = "Some text"; // Only to avoid wrong optimizations + } + + logTestString("Test self assignment\n"); + allExpected &= testSelfAssignment(); + + logTestString("test fast alloc\n"); + allExpected &= testFastAlloc(); + + logTestString("test replace\n"); + allExpected &= testReplace(); + + logTestString("test make_lower and make_uppers\n"); + allExpected &= testLowerUpper(); + + logTestString("test find functions\n"); + allExpected &= testFindFunctions(); + + logTestString("test erase functions\n"); + allExpected &= testErase(); + + if(allExpected) + logTestString("\nAll tests passed\n"); + else + logTestString("\nFAIL!\n"); + + return allExpected; +} diff --git a/tests/lightMaps.cpp b/tests/lightMaps.cpp new file mode 100644 index 00000000..2e9273f2 --- /dev/null +++ b/tests/lightMaps.cpp @@ -0,0 +1,73 @@ +// Copyright (C) 2008-2012 Christian Stehno, Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +//! Tests lightmaps under all drivers that support them +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(); + + logTestString("Testing driver %ls\n", driver->getName()); + if (driver->getDriverAttributes().getAttributeAsInt("MaxTextures")<2) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + stabilizeScreenBackground(driver); + + bool result = true; + bool added = device->getFileSystem()->addFileArchive("../media/map-20kdm2.pk3"); + assert_log(added); + + if(added) + { + ISceneNode * node = smgr->addOctreeSceneNode(smgr->getMesh("20kdm2.bsp")->getMesh(0), 0, -1, 1024); + assert_log(node); + + if (node) + { + node->setMaterialFlag(EMF_LIGHTING, false); + node->setPosition(core::vector3df(-1300,-820,-1249)); + node->setScale(core::vector3df(1, 5, 1)); + + (void)smgr->addCameraSceneNode(0, core::vector3df(0,0,0), core::vector3df(40,100,30)); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,255,255,0)); + smgr->drawAll(); + driver->endScene(); + + result = takeScreenshotAndCompareAgainstReference(driver, "-lightmaps.png", 96); + } + } + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + + +bool lightMaps(void) +{ + bool result = true; + TestWithAllDrivers(runTestWithDriver); + return result; +} + diff --git a/tests/lights.cpp b/tests/lights.cpp new file mode 100644 index 00000000..cdc2af5a --- /dev/null +++ b/tests/lights.cpp @@ -0,0 +1,70 @@ +// Copyright (C) 2008-2012 Christian Stehno, Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; + +static bool testLightTypes(video::E_DRIVER_TYPE driverType) +{ + IrrlichtDevice *device = createDevice (driverType, core::dimension2d(256,128)); + if (!device) + return true; // No error if device does not exist + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + if (!driver->getDriverAttributes().getAttributeAsInt("MaxLights")) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + +// smgr->setAmbientLight(video::SColorf(0.3f,0.3f,0.3f)); + scene::ICameraSceneNode* cam = smgr->addCameraSceneNode(); + cam->setPosition(core::vector3df(0,200,0)); + cam->setTarget(core::vector3df()); + smgr->addAnimatedMeshSceneNode(device->getSceneManager()->addHillPlaneMesh("plane", core::dimension2df(4,4), core::dimension2du(128,128))); + scene::ILightSceneNode* light1 = smgr->addLightSceneNode(0, core::vector3df(-100,30,-100)); + light1->setLightType(video::ELT_POINT); + light1->setRadius(100.f); + light1->getLightData().DiffuseColor.set(0,1,1); +// smgr->addCubeSceneNode(10, light1)->setMaterialFlag(video::EMF_LIGHTING, false); + scene::ILightSceneNode* light2 = smgr->addLightSceneNode(0, core::vector3df(100,30,100)); + light2->setRotation(core::vector3df(90,0,0)); + light2->setLightType(video::ELT_SPOT); + light2->setRadius(100.f); + light2->getLightData().DiffuseColor.set(1,0,0); + light2->getLightData().InnerCone=10.f; + light2->getLightData().OuterCone=30.f; +// smgr->addCubeSceneNode(10, light2)->setMaterialFlag(video::EMF_LIGHTING, false); + scene::ILightSceneNode* light3 = smgr->addLightSceneNode(); + light3->setRotation(core::vector3df(15,0,0)); + light3->setLightType(video::ELT_DIRECTIONAL); + light1->getLightData().DiffuseColor.set(0,1,0); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0)); + smgr->drawAll(); + driver->endScene(); + + const bool result = takeScreenshotAndCompareAgainstReference(driver, "-lightType.png", 99.91f); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +bool lights(void) +{ + bool result = true; + // no lights in sw renderer + TestWithAllDrivers(testLightTypes); + return result; +} diff --git a/tests/line2d.cpp b/tests/line2d.cpp new file mode 100644 index 00000000..eda2d543 --- /dev/null +++ b/tests/line2d.cpp @@ -0,0 +1,79 @@ +// Copyright (C) 2017 Dario Oliveri +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +#include + +using namespace irr; +using namespace irr::core; + +#define EXPECT( condition, value, name) if( condition != value) \ + { std::cout<< name << ": test failed"<< std::endl; return false;} + +//! Tests the basic functionality of the software device. +bool line2DTest(void) +{ + { + line2d< f32> a(0, 0, 0, 1); + line2d< f32> b(2, 0, 2, 1); + line2d< f32> c(2, 0, 2, 1 + 0.00001f); + + EXPECT( a.nearlyParallel( b), true, "parallel Lines are parallel"); + EXPECT( a.nearlyParallel( c, (f32)32), true, "nearly parallel lines are parallel"); + } + + { + line2d< f32> a( 0, 0, 0, 1); + line2d< f32> b( 0, 2, 2, 1); + EXPECT( a.nearlyParallel( b, 1), false, "orthogonal lines are NOT parallel"); + } + + { + line2d< f32> a( 0, 0, 100, 100); + line2d< f32> b( 100, 0, 0, 100); + + EXPECT( a.nearlyParallel( b, 1), false, "orthogonal lines are NOT parallel 2"); + + vector2df t = a.fastLinesIntersection( b); + vector2df u = vector2df( 50.0f, 50.0f); + + EXPECT( t.equals( u, roundingError() ), true, "fast intersection in known point"); + + EXPECT( a .intersectAsSegments(b), true, "intersect as Segments"); + + EXPECT( a.incidentSegments(b), true, "incidentSegments"); + + vector2df out; + EXPECT( a.lineIntersectSegment( b, out), true, "lineIntersectSegment"); + EXPECT( t.equals( out), true, "line intersect segment in known point"); + + EXPECT( a.isPointBetweenStartAndEnd( out), true, "point isBetween StartEnd of first line"); + EXPECT( b.isPointBetweenStartAndEnd( out), true, "point isBetween StartEnd of second line"); + + EXPECT( a.isPointOnLine( out), true, "is point on first line"); + EXPECT( b.isPointOnLine( out), true, "is point on second line"); + + EXPECT( out.isBetweenPoints( a.start, a.end), true, "test point is on segment with first line"); + EXPECT( out.isBetweenPoints( b.start, b.end), true, "test point is on segment with first line"); + } + + { + vector2df a( 0, 0); + vector2df b( 10, 0); + vector2df c( 0, 10); + vector2df d( 0, 40); + + EXPECT( a.areClockwise( c, b), true, "test if points are clockwise"); + EXPECT( a.areClockwise( b, c), false, "test if points are NOT clockwise"); + EXPECT( a.areCounterClockwise( b, c), true, "test if points are counter clockwise"); + EXPECT( a.areCounterClockwise( c, b), false, "test if points are NOT counter clockwise"); + + EXPECT( a.checkOrientation( c, b), 1, "test if orientation is clockwise"); + EXPECT( a.checkOrientation( b, c), 2, "test if orientation is anticlockwise"); + EXPECT( a.checkOrientation( c, d), 0, "test if orientation is colinear"); + EXPECT( a.checkOrientation( d, c), 0, "test if orientation is colinear 2"); + } + + return true; +} diff --git a/tests/loadTextures.cpp b/tests/loadTextures.cpp new file mode 100644 index 00000000..4080607a --- /dev/null +++ b/tests/loadTextures.cpp @@ -0,0 +1,97 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +/** This tests verifies that textures opened from different places in the + filesystem don't create duplicated textures. */ +bool loadFromFileFolder(void) +{ + IrrlichtDevice *device = + createDevice( video::EDT_NULL, dimension2du(160, 120)); + + if (!device) + { + logTestString("Unable to create EDT_NULL device\n"); + return false; + } + + IVideoDriver * driver = device->getVideoDriver(); + + u32 numTexs = driver->getTextureCount(); + + ITexture * tex1 = driver->getTexture("../media/tools.png"); + assert_log(tex1); + if(!tex1) + logTestString("Unable to open ../media/tools.png\n"); + if (driver->getTextureCount()!=numTexs+1) + { + logTestString("No additional texture in the texture cache %s:%d\n", __FILE__, __LINE__); + return false; + } + + IReadFile * readFile = device->getFileSystem()->createAndOpenFile("../media/tools.png"); + assert_log(readFile); + if(!readFile) + logTestString("Unable to open ../media/tools.png\n"); + if (driver->getTextureCount()!=numTexs+1) + { + logTestString("Additional texture in the texture cache %s:%d\n", __FILE__, __LINE__); + return false; + } + + ITexture * tex2 = driver->getTexture(readFile); + assert_log(tex2); + if(!readFile) + logTestString("Unable to create texture from ../media/tools.png\n"); + if (driver->getTextureCount()!=numTexs+1) + { + logTestString("Additional texture in the texture cache %s:%d\n", __FILE__, __LINE__); + return false; + } + + readFile->drop(); + + // adding a folder archive + device->getFileSystem()->addFileArchive( "../media/" ); + + ITexture * tex3 = driver->getTexture("tools.png"); + assert_log(tex3); + if(!tex3) + logTestString("Unable to open tools.png\n"); + if (driver->getTextureCount()!=numTexs+1) + { + logTestString("Additional texture in the texture cache %s:%d\n", __FILE__, __LINE__); + return false; + } + + ITexture * tex4 = driver->getTexture("tools.png"); + assert_log(tex4); + if(!tex4) + logTestString("Unable to open tools.png\n"); + if (driver->getTextureCount()!=numTexs+1) + { + logTestString("Additional texture in the texture cache %s:%d\n", __FILE__, __LINE__); + return false; + } + + device->closeDevice(); + device->run(); + device->drop(); + return ((tex1 == tex2) && (tex1 == tex3) && (tex1 == tex4)); +} + +bool loadTextures() +{ + bool result = true; + result &= loadFromFileFolder(); + return result; +} + diff --git a/tests/main.cpp b/tests/main.cpp new file mode 100644 index 00000000..6becc7c3 --- /dev/null +++ b/tests/main.cpp @@ -0,0 +1,260 @@ +// Copyright (C) 2008-2012 Colin MacDonald and Christian Stehno +// No rights reserved: this software is in the public domain. + +// 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 + +#include "testUtils.h" +#include +#include +#include + +struct STestDefinition +{ + //! The test entry point function + bool(*testSignature)(void); + + //! A descriptive name for the test + const char * testName; +}; + +//! This is the main entry point for the Irrlicht test suite. +/** \return The number of test that failed, i.e. 0 is success. */ +int main(int argumentCount, char * arguments[]) +{ + if(argumentCount > 3) + { + logTestString("\nUsage: %s [testNumber] [testCount]\n"); + return 9999; + } + + #define TEST(x)\ + {\ + extern bool x(void);\ + STestDefinition newTest;\ + newTest.testSignature = x;\ + newTest.testName = #x;\ + tests.push_back(newTest);\ + } + + // Use an STL vector so that we don't rely on Irrlicht. + std::vector tests; + +#if 0 + // To interactively debug a test, move it (temporarily) in here and enable the define to only run this test + // Otherwise debugging is slightly tricky as each test runs in it's own process. + TEST(ioScene); +#else + + TEST(disambiguateTextures); // Normally you should run this first, since it validates the working directory. + // Now the simple tests without device + TEST(testIrrArray); + TEST(testIrrMap); + TEST(testIrrList); + TEST(exports); + TEST(irrCoreEquals); + TEST(testIrrString); + TEST(testLine2d); + TEST(matrixOps); + TEST(testDimension2d); + TEST(testVector2d); + TEST(testVector3d); + TEST(testQuaternion); + TEST(testS3DVertex); + TEST(testaabbox3d); + TEST(color); + TEST(testTriangle3d); + TEST(vectorPositionDimension2d); + // file system checks (with null driver) + TEST(filesystem); + TEST(archiveReader); + TEST(testXML); + TEST(serializeAttributes); + // null driver + TEST(fast_atof); + TEST(loadTextures); + TEST(collisionResponseAnimator); + TEST(enumerateImageManipulators); + TEST(removeCustomAnimator); + TEST(sceneCollisionManager); + TEST(sceneNodeAnimator); + TEST(meshLoaders); + TEST(testTimer); + TEST(testCoreutil); + // software drivers only + TEST(softwareDevice); + TEST(b3dAnimation); + TEST(burningsVideo); + TEST(billboards); + TEST(createImage); + TEST(cursorSetVisible); + TEST(flyCircleAnimator); + TEST(guiDisabledMenu); + TEST(makeColorKeyTexture); + TEST(md2Animation); + TEST(meshTransform); + TEST(skinnedMesh); + TEST(testGeometryCreator); + TEST(writeImageToFile); + TEST(ioScene); + // all driver checks + TEST(videoDriver); + TEST(screenshot); + TEST(drawPixel); + TEST(drawRectOutline); + TEST(drawVertexPrimitive); + TEST(material); + TEST(renderTargetTexture); + TEST(textureFeatures); + TEST(textureRenderStates); + TEST(transparentMaterials); + TEST(userclipplane); + TEST(antiAliasing); + TEST(draw2DImage); + TEST(lights); + TEST(twodmaterial); + TEST(viewPort); + TEST(mrt); + TEST(projectionMatrix); + // large scenes/long rendering + TEST(orthoCam); + TEST(stencilShadow); + // q3 maps are slow + TEST(planeMatrix); + TEST(terrainSceneNode); + TEST(lightMaps); + TEST(triangleSelector); + TEST(line2DTest); +#endif + + unsigned int numberOfTests = tests.size(); + unsigned int testToRun = 0; + unsigned int fails = 0; + + bool firstRun=true; + const bool spawn=false; + // args: [testNumber] [testCount] + if(argumentCount > 1) + { + if (!strcmp(arguments[1],"--list")) + { + for (unsigned int i=0; i=0); + testToRun=abs(tmp); + if (!firstRun) + testToRun -= 1; + + if(argumentCount > 2) + { + numberOfTests = testToRun + abs(atoi(arguments[2])); + if (numberOfTests>=tests.size()) + numberOfTests=tests.size(); + } + } + + if(testToRun >= numberOfTests) + { + logTestString("\nError: invalid test %d (maximum %d)\n", + testToRun, numberOfTests-testToRun); + return 9999; + } + + const unsigned int testCount = numberOfTests-testToRun; + const bool logFileOpened = openTestLog(firstRun); + assert(logFileOpened); + + if (firstRun) + { + if (numberOfTests) + { + for (unsigned int i=testToRun; i(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(video::ECBF_COLOR | video::ECBF_DEPTH, 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_irr(screenshotName, 256, "-makeColorKeyTexture-%s.png", + zeroTexels? "old" : "new"); + + bool result = takeScreenshotAndCompareAgainstReference(driver, screenshotName); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +bool makeColorKeyTexture(void) +{ + bool result = true; + + result &= doTestWith(EDT_BURNINGSVIDEO, false); + result &= doTestWith(EDT_SOFTWARE, false); + result &= doTestWith(EDT_BURNINGSVIDEO, true); + result &= doTestWith(EDT_SOFTWARE, true); + + return result; +} diff --git a/tests/material.cpp b/tests/material.cpp new file mode 100644 index 00000000..2a6dc1ae --- /dev/null +++ b/tests/material.cpp @@ -0,0 +1,79 @@ +#include "testUtils.h" + +using namespace irr; + +static bool polygonOffset(video::E_DRIVER_TYPE type) +{ + IrrlichtDevice* device = createDevice(type, core::dimension2d(160, 120)); + + if (device == 0) + return true; + + video::IVideoDriver* driver = device->getVideoDriver(); + if (!driver->queryFeature(video::EVDF_POLYGON_OFFSET)) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + stabilizeScreenBackground(driver); + + scene::ISceneManager* smgr = device->getSceneManager(); + + // create first plane + scene::ISceneNode* plane = smgr->addMeshSceneNode(smgr->addHillPlaneMesh( + "plane", core::dimension2df(10,10), core::dimension2du(2,2)), 0, -1, + core::vector3df(0,0,20), core::vector3df(270,0,0)); + + if (plane) + { + plane->setMaterialTexture(0, driver->getTexture("../media/t351sml.jpg")); + plane->setMaterialFlag(video::EMF_LIGHTING, false); + plane->setMaterialFlag(video::EMF_BACK_FACE_CULLING, true); + } + + // create second plane exactly on top of the first one + scene::ISceneNode* plane2 = smgr->addMeshSceneNode(smgr->addHillPlaneMesh( + "plane2", core::dimension2df(5,5), core::dimension2du(2,2)), 0, -1, + core::vector3df(0,0,20), core::vector3df(270,0,0)); + plane2->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false); + + smgr->addCameraSceneNode(); + + // test back plane to back + plane->getMaterial(0).PolygonOffsetSlopeScale = 1.f; + plane->getMaterial(0).PolygonOffsetDepthBias = 1.f; + if ( type == video::EDT_DIRECT3D9 ) + plane->getMaterial(0).PolygonOffsetDepthBias *= 2.f*4.8e-7f; + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,113,113,133)); + smgr->drawAll(); + driver->endScene(); + bool result = takeScreenshotAndCompareAgainstReference(driver, "-polygonBack.png"); + + //reset back plane + plane->getMaterial(0).PolygonOffsetDepthBias=0; + // test front plane to front + plane2->getMaterial(0).PolygonOffsetSlopeScale=-1.f; + plane2->getMaterial(0).PolygonOffsetDepthBias=-1.f; + if ( type == video::EDT_DIRECT3D9 ) + plane2->getMaterial(0).PolygonOffsetDepthBias *= 2.f*4.8e-7f; + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,113,113,133)); + smgr->drawAll(); + driver->endScene(); + result &= takeScreenshotAndCompareAgainstReference(driver, "-polygonFront.png"); + + device->closeDevice(); + device->run(); + device->drop(); + return result; +} + +bool material() +{ + bool result = true; + TestWithAllDrivers(polygonOffset); + return result; +} diff --git a/tests/matrixOps.cpp b/tests/matrixOps.cpp new file mode 100644 index 00000000..63a0877c --- /dev/null +++ b/tests/matrixOps.cpp @@ -0,0 +1,465 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +namespace +{ + +// Basic tests for identity matrix +bool identity(void) +{ + bool result = true; + matrix4 m; + // Check default init + result &= (m==core::IdentityMatrix); + result &= (core::IdentityMatrix==m); + assert_log(result); + // Since the last test can be made with isDefinitelyIdentityMatrix we set it to false here + m.setDefinitelyIdentityMatrix(false); + result &= (m==core::IdentityMatrix); + result &= (core::IdentityMatrix==m); + assert_log(result); + // also equals should see this + result &= m.equals(core::IdentityMatrix); + result &= core::IdentityMatrix.equals(m); + assert_log(result); + // Check inequality + m[12]=5.f; + result &= (m!=core::IdentityMatrix); + result &= (core::IdentityMatrix!=m); + result &= !m.equals(core::IdentityMatrix); + result &= !core::IdentityMatrix.equals(m); + assert_log(result); + + // Test multiplication + result &= (m==(core::IdentityMatrix*m)); + result &= m.equals(core::IdentityMatrix*m); + result &= (m==(m*core::IdentityMatrix)); + result &= m.equals(m*core::IdentityMatrix); + assert_log(result); + + return result; +} + +// Test rotations +bool transformations(void) +{ + bool result = true; + matrix4 m, s; + m.setRotationDegrees(core::vector3df(30,40,50)); + s.setScale(core::vector3df(2,3,4)); + m *= s; + m.setTranslation(core::vector3df(5,6,7)); + result &= (core::vector3df(5,6,7).equals(m.getTranslation())); + assert_log(result); + result &= (core::vector3df(2,3,4).equals(m.getScale())); + assert_log(result); + core::vector3df newRotation = m.getRotationDegrees(); + result &= (core::vector3df(30,40,50).equals(newRotation, 0.000004f)); + assert_log(result); + m.setRotationDegrees(vector3df(90.0001f, 270.85f, 180.0f)); + s.setRotationDegrees(vector3df(0,0, 0.860866f)); + m *= s; + newRotation = m.getRotationDegrees(); + result &= (core::vector3df(0,270,270).equals(newRotation, 0.0001f)); + assert_log(result); + m.setRotationDegrees(vector3df(270.0f, 89.8264f, 0.000100879f)); + s.setRotationDegrees(vector3df(0,0, 0.189398f)); + m *= s; + newRotation = m.getRotationDegrees(); + result &= (core::vector3df(0,90,90).equals(newRotation, 0.0001f)); + assert_log(result); + m.setRotationDegrees(vector3df(270.0f, 89.0602f, 359.999f)); + s.setRotationDegrees(vector3df(0,0, 0.949104f)); + m *= s; + newRotation = m.getRotationDegrees(); + result &= (core::vector3df(0,90,89.999f).equals(newRotation)); + assert_log(result); + + return result; +} + +// Test rotations +bool rotations(void) +{ + bool result = true; + matrix4 rot1,rot2,rot3,rot4,rot5; + core::vector3df vec1(1,2,3),vec12(1,2,3); + core::vector3df vec2(-5,0,0),vec22(-5,0,0); + core::vector3df vec3(20,0,-20), vec32(20,0,-20); + // Make sure the matrix multiplication and rotation application give same results + rot1.setRotationDegrees(core::vector3df(90,0,0)); + rot2.setRotationDegrees(core::vector3df(0,90,0)); + rot3.setRotationDegrees(core::vector3df(0,0,90)); + rot4.setRotationDegrees(core::vector3df(90,90,90)); + rot5 = rot3*rot2*rot1; + result &= (rot4.equals(rot5, ROUNDING_ERROR_f32)); + assert_log(result); + rot4.transformVect(vec1);rot5.transformVect(vec12); + rot4.transformVect(vec2);rot5.transformVect(vec22); + rot4.transformVect(vec3);rot5.transformVect(vec32); + result &= (vec1.equals(vec12)); + result &= (vec2.equals(vec22)); + result &= (vec3.equals(vec32)); + assert_log(result); + + vec1.set(1,2,3);vec12.set(1,2,3); + vec2.set(-5,0,0);vec22.set(-5,0,0); + vec3.set(20,0,-20);vec32.set(20,0,-20); + rot1.setRotationDegrees(core::vector3df(45,0,0)); + rot2.setRotationDegrees(core::vector3df(0,45,0)); + rot3.setRotationDegrees(core::vector3df(0,0,45)); + rot4.setRotationDegrees(core::vector3df(45,45,45)); + rot5 = rot3*rot2*rot1; + result &= (rot4.equals(rot5, ROUNDING_ERROR_f32)); + assert_log(result); + rot4.transformVect(vec1);rot5.transformVect(vec12); + rot4.transformVect(vec2);rot5.transformVect(vec22); + rot4.transformVect(vec3);rot5.transformVect(vec32); + result &= (vec1.equals(vec12)); + result &= (vec2.equals(vec22)); + result &= (vec3.equals(vec32, 2*ROUNDING_ERROR_f32)); + assert_log(result); + + vec1.set(1,2,3);vec12.set(1,2,3); + vec2.set(-5,0,0);vec22.set(-5,0,0); + vec3.set(20,0,-20);vec32.set(20,0,-20); + rot1.setRotationDegrees(core::vector3df(-60,0,0)); + rot2.setRotationDegrees(core::vector3df(0,-60,0)); + rot3.setRotationDegrees(core::vector3df(0,0,-60)); + rot4.setRotationDegrees(core::vector3df(-60,-60,-60)); + rot5 = rot3*rot2*rot1; + result &= (rot4.equals(rot5, ROUNDING_ERROR_f32)); + assert_log(result); + rot4.transformVect(vec1);rot5.transformVect(vec12); + rot4.transformVect(vec2);rot5.transformVect(vec22); + rot4.transformVect(vec3);rot5.transformVect(vec32); + result &= (vec1.equals(vec12)); + result &= (vec2.equals(vec22)); + // this one needs higher tolerance due to rounding issues + result &= (vec3.equals(vec32, 0.000002f)); + assert_log(result); + + vec1.set(1,2,3);vec12.set(1,2,3); + vec2.set(-5,0,0);vec22.set(-5,0,0); + vec3.set(20,0,-20);vec32.set(20,0,-20); + rot1.setRotationDegrees(core::vector3df(113,0,0)); + rot2.setRotationDegrees(core::vector3df(0,-27,0)); + rot3.setRotationDegrees(core::vector3df(0,0,193)); + rot4.setRotationDegrees(core::vector3df(113,-27,193)); + rot5 = rot3*rot2*rot1; + result &= (rot4.equals(rot5, ROUNDING_ERROR_f32)); + assert_log(result); + rot4.transformVect(vec1);rot5.transformVect(vec12); + rot4.transformVect(vec2);rot5.transformVect(vec22); + rot4.transformVect(vec3);rot5.transformVect(vec32); + // these ones need higher tolerance due to rounding issues + result &= (vec1.equals(vec12, 0.000002f)); + assert_log(result); + result &= (vec2.equals(vec22)); + assert_log(result); + result &= (vec3.equals(vec32, 0.000002f)); + assert_log(result); + + rot1.setRotationDegrees(core::vector3df(0,0,34)); + rot2.setRotationDegrees(core::vector3df(0,43,0)); + vec1=(rot2*rot1).getRotationDegrees(); + result &= (vec1.equals(core::vector3df(27.5400505f, 34.4302292f, 42.6845398f), 0.000002f)); + assert_log(result); + + // corner cases + rot1.setRotationDegrees(irr::core::vector3df(180.0f, 0.f, 0.f)); + vec1=rot1.getRotationDegrees(); + result &= (vec1.equals(core::vector3df(180.0f, 0.f, 0.f), 0.000002f)); + assert_log(result); + rot1.setRotationDegrees(irr::core::vector3df(0.f, 180.0f, 0.f)); + vec1=rot1.getRotationDegrees(); + result &= (vec1.equals(core::vector3df(180.0f, 360, 180.0f), 0.000002f)); + assert_log(result); + rot1.setRotationDegrees(irr::core::vector3df(0.f, 0.f, 180.0f)); + vec1=rot1.getRotationDegrees(); + result &= (vec1.equals(core::vector3df(0.f, 0.f, 180.0f), 0.000002f)); + assert_log(result); + + rot1.makeIdentity(); + rot1.setRotationDegrees(core::vector3df(270.f,0,0)); + rot2.makeIdentity(); + rot2.setRotationDegrees(core::vector3df(-90.f,0,0)); + vec1=(rot1*rot2).getRotationDegrees(); + result &= (vec1.equals(core::vector3df(180.f, 0.f, 0.0f))); + assert_log(result); + + return result; +} + +// Test isOrthogonal +bool isOrthogonal(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; +} + +bool checkMatrixRotation(irr::core::matrix4& m, const vector3df& vector, const vector3df& expectedResult) +{ + vector3df v(vector); + m.rotateVect(v); + if ( expectedResult.equals(v) ) + return true; + logTestString("checkMatrixRotation failed for vector %f %f %f. Expected %f %f %f, got %f %f %f \n" + , vector.X, vector.Y, vector.Z, expectedResult.X, expectedResult.Y, expectedResult.Z, v.X, v.Y, v.Z); + logTestString("matrix: "); + for ( int i=0; i<16; ++i ) + logTestString("%.2f ", m[i]); + logTestString("\n"); + + return false; +} + +bool setRotationAxis() +{ + matrix4 m; + vector3df v; + + // y up, x right, z depth (as usual) + + // y rotated around x-axis + if ( !checkMatrixRotation( m.setRotationAxisRadians(90.f*DEGTORAD, vector3df(1,0,0)), vector3df(0,1,0), vector3df(0, 0, 1)) ) + { + logTestString("%s:%d", __FILE__, __LINE__); + return false; + } + if ( !checkMatrixRotation( m.setRotationAxisRadians(180.f*DEGTORAD, vector3df(1,0,0)), vector3df(0,1,0), vector3df(0, -1, 0)) ) + { + logTestString("%s:%d", __FILE__, __LINE__); + return false; + } + + // y rotated around negative x-axis + m.makeIdentity(); + if ( !checkMatrixRotation( m.setRotationAxisRadians(90.f*DEGTORAD, vector3df(-1,0,0)), vector3df(0,1,0), vector3df(0, 0, -1)) ) + { + logTestString("%s:%d", __FILE__, __LINE__); + return false; + } + + // x rotated around x-axis + if ( !checkMatrixRotation( m.setRotationAxisRadians(90.f*DEGTORAD, vector3df(1,0,0)), vector3df(1,0,0), vector3df(1, 0, 0)) ) + { + logTestString("%s:%d", __FILE__, __LINE__); + return false; + } + + // x rotated around y-axis + if ( !checkMatrixRotation( m.setRotationAxisRadians(90.f*DEGTORAD, vector3df(0,1,0)), vector3df(1,0,0), vector3df(0, 0, -1)) ) + { + logTestString("%s:%d", __FILE__, __LINE__); + return false; + } + if ( !checkMatrixRotation( m.setRotationAxisRadians(180.f*DEGTORAD, vector3df(0,1,0)), vector3df(1,0,0), vector3df(-1, 0, 0)) ) + { + logTestString("%s:%d", __FILE__, __LINE__); + return false; + } + + // x rotated around negative y-axis + if ( !checkMatrixRotation( m.setRotationAxisRadians(90.f*DEGTORAD, vector3df(0,-1,0)), vector3df(1,0,0), vector3df(0, 0, 1)) ) + { + logTestString("%s:%d", __FILE__, __LINE__); + return false; + } + + // y rotated around y-axis + if ( !checkMatrixRotation( m.setRotationAxisRadians(90.f*DEGTORAD, vector3df(0,1,0)), vector3df(0,1,0), vector3df(0, 1, 0)) ) + { + logTestString("%s:%d", __FILE__, __LINE__); + return false; + } + + // x rotated around z-axis + if ( !checkMatrixRotation( m.setRotationAxisRadians(90.f*DEGTORAD, vector3df(0,0,1)), vector3df(1,0,0), vector3df(0, 1, 0)) ) + { + logTestString("%s:%d", __FILE__, __LINE__); + return false; + } + if ( !checkMatrixRotation( m.setRotationAxisRadians(180.f*DEGTORAD, vector3df(0,0,1)), vector3df(1,0,0), vector3df(-1, 0, 0)) ) + { + logTestString("%s:%d", __FILE__, __LINE__); + return false; + } + + // x rotated around negative z-axis + if ( !checkMatrixRotation( m.setRotationAxisRadians(90.f*DEGTORAD, vector3df(0,0,-1)), vector3df(1,0,0), vector3df(0, -1, 0)) ) + { + logTestString("%s:%d", __FILE__, __LINE__); + return false; + } + + // y rotated around z-axis + if ( !checkMatrixRotation( m.setRotationAxisRadians(90.f*DEGTORAD, vector3df(0,0,1)), vector3df(0,1,0), vector3df(-1, 0, 0)) ) + { + logTestString("%s:%d", __FILE__, __LINE__); + return false; + } + if ( !checkMatrixRotation( m.setRotationAxisRadians(180.f*DEGTORAD, vector3df(0,0,1)), vector3df(0,1,0), vector3df(0, -1, 0)) ) + { + logTestString("%s:%d", __FILE__, __LINE__); + return false; + } + + // z rotated around z-axis + if ( !checkMatrixRotation( m.setRotationAxisRadians(90.f*DEGTORAD, vector3df(0,0,1)), vector3df(0,0,1), vector3df(0, 0, 1)) ) + { + logTestString("%s:%d", __FILE__, __LINE__); + return false; + } + + + return true; +} + +// just calling each function once to find compile problems +void calltest() +{ + matrix4 mat; + matrix4 mat2(mat); + f32& f1 = mat(0,0); + const f32& f2 = mat(0,0); + f32& f3 = mat[0]; + const f32& f4 = mat[0]; + mat = mat; + mat = 1.f; + const f32 * pf1 = mat.pointer(); + f32 * pf2 = mat.pointer(); + bool b = mat == mat2; + b = mat != mat2; + mat = mat + mat2; + mat += mat2; + mat = mat - mat2; + mat -= mat2; + mat.setbyproduct(mat, mat2); + mat.setbyproduct_nocheck(mat, mat2); + mat = mat * mat2; + mat *= mat2; + mat = mat * 10.f; + mat *= 10.f; + mat.makeIdentity(); + b = mat.isIdentity(); + b = mat.isOrthogonal(); + b = mat.isIdentity_integer_base (); + mat.setTranslation(vector3df(1.f, 1.f, 1.f) ); + vector3df v1 = mat.getTranslation(); + mat.setInverseTranslation(vector3df(1.f, 1.f, 1.f) ); + mat.setRotationRadians(vector3df(1.f, 1.f, 1.f) ); + mat.setRotationDegrees(vector3df(1.f, 1.f, 1.f) ); + vector3df v2 = mat.getRotationDegrees(); + mat.setInverseRotationRadians(vector3df(1.f, 1.f, 1.f) ); + mat.setInverseRotationDegrees(vector3df(1.f, 1.f, 1.f) ); + mat.setRotationAxisRadians(1.f, vector3df(1.f, 1.f, 1.f) ); + mat.setScale(vector3df(1.f, 1.f, 1.f) ); + mat.setScale(1.f); + vector3df v3 = mat.getScale(); + mat.inverseTranslateVect(v1); + mat.inverseRotateVect(v1); + mat.rotateVect(v1); + mat.rotateVect(v1, v2); + f32 fv3[3]; + mat.rotateVect(fv3, v1); + mat.transformVect(v1); + mat.transformVect(v1, v1); + f32 fv4[4]; + mat.transformVect(fv4, v1); + mat.transformVec3(fv3, fv3); + mat.translateVect(v1); + plane3df p1; + mat.transformPlane(p1); + mat.transformPlane(p1, p1); + aabbox3df bb1; + mat.transformBox(bb1); + mat.transformBoxEx(bb1); + mat.multiplyWith1x4Matrix(fv4); + mat.makeInverse(); + b = mat.getInversePrimitive(mat2); + b = mat.getInverse(mat2); + mat.buildProjectionMatrixPerspectiveFovRH(1.f, 1.f, 1.f, 1000.f); + mat.buildProjectionMatrixPerspectiveFovLH(1.f, 1.f, 1.f, 1000.f); + mat.buildProjectionMatrixPerspectiveFovInfinityLH(1.f, 1.f, 1.f); + mat.buildProjectionMatrixPerspectiveRH(100.f, 100.f, 1.f, 1000.f); + mat.buildProjectionMatrixPerspectiveLH(10000.f, 10000.f, 1.f, 1000.f); + mat.buildProjectionMatrixOrthoLH(10000.f, 10000.f, 1.f, 1000.f); + mat.buildProjectionMatrixOrthoRH(10000.f, 10000.f, 1.f, 1000.f); + mat.buildCameraLookAtMatrixLH(vector3df(1.f, 1.f, 1.f), vector3df(0.f, 0.f, 0.f), vector3df(0.f, 1.f, 0.f) ); + mat.buildCameraLookAtMatrixRH(vector3df(1.f, 1.f, 1.f), vector3df(0.f, 0.f, 0.f), vector3df(0.f, 1.f, 0.f) ); + mat.buildShadowMatrix(vector3df(1.f, 1.f, 1.f), p1); + core::rect a1(0,0,100,100); + mat.buildNDCToDCMatrix(a1, 1.f); + mat.interpolate(mat2, 1.f); + mat = mat.getTransposed(); + mat.getTransposed(mat2); + mat.buildRotateFromTo(vector3df(1.f, 1.f, 1.f), vector3df(1.f, 1.f, 1.f)); + mat.setRotationCenter(vector3df(1.f, 1.f, 1.f), vector3df(1.f, 1.f, 1.f)); + mat.buildAxisAlignedBillboard(vector3df(1.f, 1.f, 1.f), vector3df(1.f, 1.f, 1.f), vector3df(1.f, 1.f, 1.f), vector3df(1.f, 1.f, 1.f), vector3df(1.f, 1.f, 1.f)); + mat.buildTextureTransform( 1.f,vector2df(1.f, 1.f), vector2df(1.f, 1.f), vector2df(1.f, 1.f)); + mat.setTextureRotationCenter( 1.f ); + mat.setTextureTranslate( 1.f, 1.f ); + mat.setTextureTranslateTransposed(1.f, 1.f); + mat.setTextureScale( 1.f, 1.f ); + mat.setTextureScaleCenter( 1.f, 1.f ); + f32 fv16[16]; + mat.setM(fv16); + mat.setDefinitelyIdentityMatrix(false); + b = mat.getDefinitelyIdentityMatrix(); + b = mat.equals(mat2); + f1 = f1+f2+f3+f4+*pf1+*pf2; // getting rid of unused variable warnings. +} + +} + +bool matrixOps(void) +{ + bool result = true; + calltest(); + result &= identity(); + result &= rotations(); + result &= isOrthogonal(); + result &= transformations(); + result &= setRotationAxis(); + return result; +} + diff --git a/tests/md2Animation.cpp b/tests/md2Animation.cpp new file mode 100644 index 00000000..29013743 --- /dev/null +++ b/tests/md2Animation.cpp @@ -0,0 +1,128 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; + +namespace +{ +// Tests MD2 animations. +/** At the moment, this just verifies that the last frame of the animation produces the expected bitmap. */ +bool testLastFrame() +{ + // Use EDT_BURNINGSVIDEO since it is not dependent on (e.g.) OpenGL driver versions. + IrrlichtDevice *device = createDevice(video::EDT_BURNINGSVIDEO, dimension2d(160, 120), 32); + if (!device) + return false; + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager * smgr = device->getSceneManager(); + + scene::IAnimatedMesh* mesh = smgr->getMesh("./media/sydney.md2"); + + bool result = (mesh != 0); + if (mesh) + { + scene::IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh); + + if (node) + { + node->setPosition(vector3df(20, 0, 30)); + node->setMaterialFlag(video::EMF_LIGHTING, false); + node->setMaterialTexture(0, driver->getTexture("./media/sydney.bmp")); + node->setLoopMode(false); + + (void)smgr->addCameraSceneNode(); + + // Just jump to the last frame since that's all we're interested in. + node->setMD2Animation(scene::EMAT_DEATH_FALLBACK); + node->setCurrentFrame((f32)(node->getEndFrame())); + node->setAnimationSpeed(0); + device->run(); + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255, 255, 255, 0)); + smgr->drawAll(); + driver->endScene(); + if (mesh->getBoundingBox() != mesh->getMesh(node->getEndFrame())->getBoundingBox()) + { + logTestString("bbox of md2 mesh not updated.\n"); + result = false; + } + //TODO: Does not yet work, not sure if this is correct or not +#if 0 + if (node->getBoundingBox() != mesh->getMesh(node->getFrameNr())->getBoundingBox()) + { + logTestString("bbox of md2 scene node not updated.\n"); + result = false; + } +#endif + if (node->getTransformedBoundingBox() == core::aabbox3df()) + { + logTestString("md2 node returns empty bbox.\n"); + result = false; + } + } + } + + result &= takeScreenshotAndCompareAgainstReference(driver, "-md2Animation.png"); + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +// Tests MD2 normals. +bool testNormals() +{ + // Use EDT_BURNINGSVIDEO since it is not dependent on (e.g.) OpenGL driver versions. + IrrlichtDevice *device = createDevice(video::EDT_BURNINGSVIDEO, dimension2d(160, 120), 32); + if (!device) + return false; + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager * smgr = device->getSceneManager(); + + scene::IAnimatedMesh* mesh = smgr->getMesh("./media/sydney.md2"); + + bool result = (mesh != 0); + if (mesh) + { + scene::IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh); + if (node) + { + node->setPosition(vector3df(20, 0, 30)); + node->setMaterialFlag(video::EMF_LIGHTING, false); + node->setDebugDataVisible(scene::EDS_NORMALS); + node->setMaterialTexture(0, driver->getTexture("./media/sydney.bmp")); + node->setLoopMode(false); + + (void)smgr->addCameraSceneNode(); + + node->setMD2Animation(scene::EMAT_STAND); + node->setAnimationSpeed(0); + device->run(); + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255, 255, 255, 0)); + smgr->drawAll(); + driver->endScene(); + } + } + + result &= takeScreenshotAndCompareAgainstReference(driver, "-md2Normals.png"); + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +} + +// test md2 features +bool md2Animation(void) +{ + bool result = testLastFrame(); + result &= testNormals(); + return result; +} diff --git a/tests/media/Burning's Video-2dmatFilter.png b/tests/media/Burning's Video-2dmatFilter.png new file mode 100644 index 00000000..af1a9e0b Binary files /dev/null and b/tests/media/Burning's Video-2dmatFilter.png differ diff --git a/tests/media/Burning's Video-addBlend2D.png b/tests/media/Burning's Video-addBlend2D.png new file mode 100644 index 00000000..2122aa35 Binary files /dev/null and b/tests/media/Burning's Video-addBlend2D.png differ diff --git a/tests/media/Burning's Video-ambient-lighting.png b/tests/media/Burning's Video-ambient-lighting.png new file mode 100644 index 00000000..a49b3071 Binary files /dev/null and b/tests/media/Burning's Video-ambient-lighting.png differ diff --git a/tests/media/Burning's Video-b3dAnimation.png b/tests/media/Burning's Video-b3dAnimation.png new file mode 100644 index 00000000..52feb695 Binary files /dev/null and b/tests/media/Burning's Video-b3dAnimation.png differ diff --git a/tests/media/Burning's Video-b3dJointPosition.png b/tests/media/Burning's Video-b3dJointPosition.png new file mode 100644 index 00000000..fc33f23c Binary files /dev/null and b/tests/media/Burning's Video-b3dJointPosition.png differ diff --git a/tests/media/Burning's Video-billboard.png b/tests/media/Burning's Video-billboard.png new file mode 100644 index 00000000..9892076a Binary files /dev/null and b/tests/media/Burning's Video-billboard.png differ diff --git a/tests/media/Burning's Video-billboardOrientation.png b/tests/media/Burning's Video-billboardOrientation.png new file mode 100644 index 00000000..fb99360f Binary files /dev/null and b/tests/media/Burning's Video-billboardOrientation.png differ diff --git a/tests/media/Burning's Video-draw2DImage4cFilter.png b/tests/media/Burning's Video-draw2DImage4cFilter.png new file mode 100644 index 00000000..a245525b Binary files /dev/null and b/tests/media/Burning's Video-draw2DImage4cFilter.png differ diff --git a/tests/media/Burning's Video-draw2DImageRTT.png b/tests/media/Burning's Video-draw2DImageRTT.png new file mode 100644 index 00000000..dde350ff Binary files /dev/null and b/tests/media/Burning's Video-draw2DImageRTT.png differ diff --git a/tests/media/Burning's Video-draw2DImageRect.png b/tests/media/Burning's Video-draw2DImageRect.png new file mode 100644 index 00000000..652e784a Binary files /dev/null and b/tests/media/Burning's Video-draw2DImageRect.png differ diff --git a/tests/media/Burning's Video-drawLine.png b/tests/media/Burning's Video-drawLine.png new file mode 100644 index 00000000..b3b2ea41 Binary files /dev/null and b/tests/media/Burning's Video-drawLine.png differ diff --git a/tests/media/Burning's Video-drawPixel.png b/tests/media/Burning's Video-drawPixel.png new file mode 100644 index 00000000..b7539cf8 Binary files /dev/null and b/tests/media/Burning's Video-drawPixel.png differ diff --git a/tests/media/Burning's Video-drawRectOutline.png b/tests/media/Burning's Video-drawRectOutline.png new file mode 100644 index 00000000..ab97c508 Binary files /dev/null and b/tests/media/Burning's Video-drawRectOutline.png differ diff --git a/tests/media/Burning's Video-drawVPL_a.png b/tests/media/Burning's Video-drawVPL_a.png new file mode 100644 index 00000000..a5666b7c Binary files /dev/null and b/tests/media/Burning's Video-drawVPL_a.png differ diff --git a/tests/media/Burning's Video-drawVPL_b.png b/tests/media/Burning's Video-drawVPL_b.png new file mode 100644 index 00000000..a5666b7c Binary files /dev/null and b/tests/media/Burning's Video-drawVPL_b.png differ diff --git a/tests/media/Burning's Video-drawVPL_c.png b/tests/media/Burning's Video-drawVPL_c.png new file mode 100644 index 00000000..a5666b7c Binary files /dev/null and b/tests/media/Burning's Video-drawVPL_c.png differ diff --git a/tests/media/Burning's Video-drawVPL_d.png b/tests/media/Burning's Video-drawVPL_d.png new file mode 100644 index 00000000..a5666b7c Binary files /dev/null and b/tests/media/Burning's Video-drawVPL_d.png differ diff --git a/tests/media/Burning's Video-drawVPL_e.png b/tests/media/Burning's Video-drawVPL_e.png new file mode 100644 index 00000000..a3f51623 Binary files /dev/null and b/tests/media/Burning's Video-drawVPL_e.png differ diff --git a/tests/media/Burning's Video-drawVPL_f.png b/tests/media/Burning's Video-drawVPL_f.png new file mode 100644 index 00000000..a5666b7c Binary files /dev/null and b/tests/media/Burning's Video-drawVPL_f.png differ diff --git a/tests/media/Burning's Video-drawVPL_g.png b/tests/media/Burning's Video-drawVPL_g.png new file mode 100644 index 00000000..113dc35c Binary files /dev/null and b/tests/media/Burning's Video-drawVPL_g.png differ diff --git a/tests/media/Burning's Video-drawVPL_h.png b/tests/media/Burning's Video-drawVPL_h.png new file mode 100644 index 00000000..d1b1f8dc Binary files /dev/null and b/tests/media/Burning's Video-drawVPL_h.png differ diff --git a/tests/media/Burning's Video-drawVPL_i.png b/tests/media/Burning's Video-drawVPL_i.png new file mode 100644 index 00000000..be45d0f1 Binary files /dev/null and b/tests/media/Burning's Video-drawVPL_i.png differ diff --git a/tests/media/Burning's Video-drawVPL_j.png b/tests/media/Burning's Video-drawVPL_j.png new file mode 100644 index 00000000..a5666b7c Binary files /dev/null and b/tests/media/Burning's Video-drawVPL_j.png differ diff --git a/tests/media/Burning's Video-drawVPL_k.png b/tests/media/Burning's Video-drawVPL_k.png new file mode 100644 index 00000000..a5666b7c Binary files /dev/null and b/tests/media/Burning's Video-drawVPL_k.png differ diff --git a/tests/media/Burning's Video-flyCircleAnimator.png b/tests/media/Burning's Video-flyCircleAnimator.png new file mode 100644 index 00000000..fbc2ecad Binary files /dev/null and b/tests/media/Burning's Video-flyCircleAnimator.png differ diff --git a/tests/media/Burning's Video-guiDisabledMenu.png b/tests/media/Burning's Video-guiDisabledMenu.png new file mode 100644 index 00000000..b25bb937 Binary files /dev/null and b/tests/media/Burning's Video-guiDisabledMenu.png differ diff --git a/tests/media/Burning's Video-lightType.png b/tests/media/Burning's Video-lightType.png new file mode 100644 index 00000000..a472e92d Binary files /dev/null and b/tests/media/Burning's Video-lightType.png differ diff --git a/tests/media/Burning's Video-lightmaps.png b/tests/media/Burning's Video-lightmaps.png new file mode 100644 index 00000000..f53a7e36 Binary files /dev/null and b/tests/media/Burning's Video-lightmaps.png differ diff --git a/tests/media/Burning's Video-loadScene.png b/tests/media/Burning's Video-loadScene.png new file mode 100644 index 00000000..b68c9144 Binary files /dev/null and b/tests/media/Burning's Video-loadScene.png differ diff --git a/tests/media/Burning's Video-makeColorKeyTexture-new.png b/tests/media/Burning's Video-makeColorKeyTexture-new.png new file mode 100644 index 00000000..a49dfbfa Binary files /dev/null and b/tests/media/Burning's Video-makeColorKeyTexture-new.png differ diff --git a/tests/media/Burning's Video-makeColorKeyTexture-old.png b/tests/media/Burning's Video-makeColorKeyTexture-old.png new file mode 100644 index 00000000..d584cd41 Binary files /dev/null and b/tests/media/Burning's Video-makeColorKeyTexture-old.png differ diff --git a/tests/media/Burning's Video-md2Animation.png b/tests/media/Burning's Video-md2Animation.png new file mode 100644 index 00000000..b9c5be6c Binary files /dev/null and b/tests/media/Burning's Video-md2Animation.png differ diff --git a/tests/media/Burning's Video-md2Normals.png b/tests/media/Burning's Video-md2Normals.png new file mode 100644 index 00000000..709b97e9 Binary files /dev/null and b/tests/media/Burning's Video-md2Normals.png differ diff --git a/tests/media/Burning's Video-meshTransform.png b/tests/media/Burning's Video-meshTransform.png new file mode 100644 index 00000000..e8abb00a Binary files /dev/null and b/tests/media/Burning's Video-meshTransform.png differ diff --git a/tests/media/Burning's Video-multiTexture.png b/tests/media/Burning's Video-multiTexture.png new file mode 100644 index 00000000..a5666b7c Binary files /dev/null and b/tests/media/Burning's Video-multiTexture.png differ diff --git a/tests/media/Burning's Video-orthoCam.png b/tests/media/Burning's Video-orthoCam.png new file mode 100644 index 00000000..5e35ddde Binary files /dev/null and b/tests/media/Burning's Video-orthoCam.png differ diff --git a/tests/media/Burning's Video-pixelAccuracy.png b/tests/media/Burning's Video-pixelAccuracy.png new file mode 100644 index 00000000..24190ef8 Binary files /dev/null and b/tests/media/Burning's Video-pixelAccuracy.png differ diff --git a/tests/media/Burning's Video-planeMatrix-scaledClip.png b/tests/media/Burning's Video-planeMatrix-scaledClip.png new file mode 100644 index 00000000..14f6dc35 Binary files /dev/null and b/tests/media/Burning's Video-planeMatrix-scaledClip.png differ diff --git a/tests/media/Burning's Video-projMat.png b/tests/media/Burning's Video-projMat.png new file mode 100644 index 00000000..c1ff258a Binary files /dev/null and b/tests/media/Burning's Video-projMat.png differ diff --git a/tests/media/Burning's Video-renderMipmap.png b/tests/media/Burning's Video-renderMipmap.png new file mode 100644 index 00000000..06fc37f0 Binary files /dev/null and b/tests/media/Burning's Video-renderMipmap.png differ diff --git a/tests/media/Burning's Video-rttAndAntiAlias.png b/tests/media/Burning's Video-rttAndAntiAlias.png new file mode 100644 index 00000000..37d65bd3 Binary files /dev/null and b/tests/media/Burning's Video-rttAndAntiAlias.png differ diff --git a/tests/media/Burning's Video-rttAndText.png b/tests/media/Burning's Video-rttAndText.png new file mode 100644 index 00000000..cf7eaf18 Binary files /dev/null and b/tests/media/Burning's Video-rttAndText.png differ diff --git a/tests/media/Burning's Video-rttWith2DImage.png b/tests/media/Burning's Video-rttWith2DImage.png new file mode 100644 index 00000000..6fedf81d Binary files /dev/null and b/tests/media/Burning's Video-rttWith2DImage.png differ diff --git a/tests/media/Burning's Video-stencilSelfShadow.png b/tests/media/Burning's Video-stencilSelfShadow.png new file mode 100644 index 00000000..dcdb6087 Binary files /dev/null and b/tests/media/Burning's Video-stencilSelfShadow.png differ diff --git a/tests/media/Burning's Video-stencilShadow.png b/tests/media/Burning's Video-stencilShadow.png new file mode 100644 index 00000000..60f31cdc Binary files /dev/null and b/tests/media/Burning's Video-stencilShadow.png differ diff --git a/tests/media/Burning's Video-terrainGap.png b/tests/media/Burning's Video-terrainGap.png new file mode 100644 index 00000000..835a946c Binary files /dev/null and b/tests/media/Burning's Video-terrainGap.png differ diff --git a/tests/media/Burning's Video-terrainSceneNode-1.png b/tests/media/Burning's Video-terrainSceneNode-1.png new file mode 100644 index 00000000..ba53a288 Binary files /dev/null and b/tests/media/Burning's Video-terrainSceneNode-1.png differ diff --git a/tests/media/Burning's Video-terrainSceneNode-2.png b/tests/media/Burning's Video-terrainSceneNode-2.png new file mode 100644 index 00000000..4c92f024 Binary files /dev/null and b/tests/media/Burning's Video-terrainSceneNode-2.png differ diff --git a/tests/media/Burning's Video-testGeometryCreator.png b/tests/media/Burning's Video-testGeometryCreator.png new file mode 100644 index 00000000..5ea41667 Binary files /dev/null and b/tests/media/Burning's Video-testGeometryCreator.png differ diff --git a/tests/media/Burning's Video-testImageFormats.png b/tests/media/Burning's Video-testImageFormats.png new file mode 100644 index 00000000..7efc85a1 Binary files /dev/null and b/tests/media/Burning's Video-testImageFormats.png differ diff --git a/tests/media/Burning's Video-testTerrainMesh.png b/tests/media/Burning's Video-testTerrainMesh.png new file mode 100644 index 00000000..53d0aa56 Binary files /dev/null and b/tests/media/Burning's Video-testTerrainMesh.png differ diff --git a/tests/media/Burning's Video-textureRenderStates.png b/tests/media/Burning's Video-textureRenderStates.png new file mode 100644 index 00000000..98282fa1 Binary files /dev/null and b/tests/media/Burning's Video-textureRenderStates.png differ diff --git a/tests/media/Burning's Video-transparentAddColor.png b/tests/media/Burning's Video-transparentAddColor.png new file mode 100644 index 00000000..87261e59 Binary files /dev/null and b/tests/media/Burning's Video-transparentAddColor.png differ diff --git a/tests/media/Burning's Video-transparentAlphaChannel.png b/tests/media/Burning's Video-transparentAlphaChannel.png new file mode 100644 index 00000000..0986ed44 Binary files /dev/null and b/tests/media/Burning's Video-transparentAlphaChannel.png differ diff --git a/tests/media/Burning's Video-transparentAlphaChannelRef.png b/tests/media/Burning's Video-transparentAlphaChannelRef.png new file mode 100644 index 00000000..09ff338b Binary files /dev/null and b/tests/media/Burning's Video-transparentAlphaChannelRef.png differ diff --git a/tests/media/Burning's Video-transparentReflection2Layer.png b/tests/media/Burning's Video-transparentReflection2Layer.png new file mode 100644 index 00000000..7acfba64 Binary files /dev/null and b/tests/media/Burning's Video-transparentReflection2Layer.png differ diff --git a/tests/media/Burning's Video-transparentVertexAlpha.png b/tests/media/Burning's Video-transparentVertexAlpha.png new file mode 100644 index 00000000..b8f268c6 Binary files /dev/null and b/tests/media/Burning's Video-transparentVertexAlpha.png differ diff --git a/tests/media/Burning's Video-transparentVertexAlphaChannelMore.png b/tests/media/Burning's Video-transparentVertexAlphaChannelMore.png new file mode 100644 index 00000000..4dfaff0c Binary files /dev/null and b/tests/media/Burning's Video-transparentVertexAlphaChannelMore.png differ diff --git a/tests/media/Burning's Video-viewPortText.png b/tests/media/Burning's Video-viewPortText.png new file mode 100644 index 00000000..7c9f7813 Binary files /dev/null and b/tests/media/Burning's Video-viewPortText.png differ diff --git a/tests/media/Direct3D 9.0-2dmatFilter.png b/tests/media/Direct3D 9.0-2dmatFilter.png new file mode 100644 index 00000000..c4e366cf Binary files /dev/null and b/tests/media/Direct3D 9.0-2dmatFilter.png differ diff --git a/tests/media/Direct3D 9.0-addBlend2D.png b/tests/media/Direct3D 9.0-addBlend2D.png new file mode 100644 index 00000000..2c9bba58 Binary files /dev/null and b/tests/media/Direct3D 9.0-addBlend2D.png differ diff --git a/tests/media/Direct3D 9.0-draw2DImage4cFilter.png b/tests/media/Direct3D 9.0-draw2DImage4cFilter.png new file mode 100644 index 00000000..2b64f445 Binary files /dev/null and b/tests/media/Direct3D 9.0-draw2DImage4cFilter.png differ diff --git a/tests/media/Direct3D 9.0-draw2DImagePNG.png b/tests/media/Direct3D 9.0-draw2DImagePNG.png new file mode 100644 index 00000000..49a4e2ee Binary files /dev/null and b/tests/media/Direct3D 9.0-draw2DImagePNG.png differ diff --git a/tests/media/Direct3D 9.0-draw2DImageRTT.png b/tests/media/Direct3D 9.0-draw2DImageRTT.png new file mode 100644 index 00000000..dde350ff Binary files /dev/null and b/tests/media/Direct3D 9.0-draw2DImageRTT.png differ diff --git a/tests/media/Direct3D 9.0-draw2DImageRect.png b/tests/media/Direct3D 9.0-draw2DImageRect.png new file mode 100644 index 00000000..c89b00b8 Binary files /dev/null and b/tests/media/Direct3D 9.0-draw2DImageRect.png differ diff --git a/tests/media/Direct3D 9.0-drawLine.png b/tests/media/Direct3D 9.0-drawLine.png new file mode 100644 index 00000000..b3b2ea41 Binary files /dev/null and b/tests/media/Direct3D 9.0-drawLine.png differ diff --git a/tests/media/Direct3D 9.0-drawPixel.png b/tests/media/Direct3D 9.0-drawPixel.png new file mode 100644 index 00000000..55668eff Binary files /dev/null and b/tests/media/Direct3D 9.0-drawPixel.png differ diff --git a/tests/media/Direct3D 9.0-drawRectOutline.png b/tests/media/Direct3D 9.0-drawRectOutline.png new file mode 100644 index 00000000..b53eeacf Binary files /dev/null and b/tests/media/Direct3D 9.0-drawRectOutline.png differ diff --git a/tests/media/Direct3D 9.0-drawVPL_a.png b/tests/media/Direct3D 9.0-drawVPL_a.png new file mode 100644 index 00000000..c6e8a6c6 Binary files /dev/null and b/tests/media/Direct3D 9.0-drawVPL_a.png differ diff --git a/tests/media/Direct3D 9.0-drawVPL_b.png b/tests/media/Direct3D 9.0-drawVPL_b.png new file mode 100644 index 00000000..7ee9b7b3 Binary files /dev/null and b/tests/media/Direct3D 9.0-drawVPL_b.png differ diff --git a/tests/media/Direct3D 9.0-drawVPL_c.png b/tests/media/Direct3D 9.0-drawVPL_c.png new file mode 100644 index 00000000..6920275d Binary files /dev/null and b/tests/media/Direct3D 9.0-drawVPL_c.png differ diff --git a/tests/media/Direct3D 9.0-drawVPL_d.png b/tests/media/Direct3D 9.0-drawVPL_d.png new file mode 100644 index 00000000..9e36fa0c Binary files /dev/null and b/tests/media/Direct3D 9.0-drawVPL_d.png differ diff --git a/tests/media/Direct3D 9.0-drawVPL_e.png b/tests/media/Direct3D 9.0-drawVPL_e.png new file mode 100644 index 00000000..d88c7fad Binary files /dev/null and b/tests/media/Direct3D 9.0-drawVPL_e.png differ diff --git a/tests/media/Direct3D 9.0-drawVPL_f.png b/tests/media/Direct3D 9.0-drawVPL_f.png new file mode 100644 index 00000000..7172eeae Binary files /dev/null and b/tests/media/Direct3D 9.0-drawVPL_f.png differ diff --git a/tests/media/Direct3D 9.0-drawVPL_g.png b/tests/media/Direct3D 9.0-drawVPL_g.png new file mode 100644 index 00000000..107000de Binary files /dev/null and b/tests/media/Direct3D 9.0-drawVPL_g.png differ diff --git a/tests/media/Direct3D 9.0-drawVPL_h.png b/tests/media/Direct3D 9.0-drawVPL_h.png new file mode 100644 index 00000000..a5666b7c Binary files /dev/null and b/tests/media/Direct3D 9.0-drawVPL_h.png differ diff --git a/tests/media/Direct3D 9.0-drawVPL_i.png b/tests/media/Direct3D 9.0-drawVPL_i.png new file mode 100644 index 00000000..a5666b7c Binary files /dev/null and b/tests/media/Direct3D 9.0-drawVPL_i.png differ diff --git a/tests/media/Direct3D 9.0-drawVPL_j.png b/tests/media/Direct3D 9.0-drawVPL_j.png new file mode 100644 index 00000000..a5666b7c Binary files /dev/null and b/tests/media/Direct3D 9.0-drawVPL_j.png differ diff --git a/tests/media/Direct3D 9.0-drawVPL_k.png b/tests/media/Direct3D 9.0-drawVPL_k.png new file mode 100644 index 00000000..c6e8a6c6 Binary files /dev/null and b/tests/media/Direct3D 9.0-drawVPL_k.png differ diff --git a/tests/media/Direct3D 9.0-lightType.png b/tests/media/Direct3D 9.0-lightType.png new file mode 100644 index 00000000..a349a5b5 Binary files /dev/null and b/tests/media/Direct3D 9.0-lightType.png differ diff --git a/tests/media/Direct3D 9.0-lightmaps.png b/tests/media/Direct3D 9.0-lightmaps.png new file mode 100644 index 00000000..f53a7e36 Binary files /dev/null and b/tests/media/Direct3D 9.0-lightmaps.png differ diff --git a/tests/media/Direct3D 9.0-lineAntiAliasing.png b/tests/media/Direct3D 9.0-lineAntiAliasing.png new file mode 100644 index 00000000..7d93bcea Binary files /dev/null and b/tests/media/Direct3D 9.0-lineAntiAliasing.png differ diff --git a/tests/media/Direct3D 9.0-mrt.png b/tests/media/Direct3D 9.0-mrt.png new file mode 100644 index 00000000..c3b6598c Binary files /dev/null and b/tests/media/Direct3D 9.0-mrt.png differ diff --git a/tests/media/Direct3D 9.0-mrt2.png b/tests/media/Direct3D 9.0-mrt2.png new file mode 100644 index 00000000..88f4e209 Binary files /dev/null and b/tests/media/Direct3D 9.0-mrt2.png differ diff --git a/tests/media/Direct3D 9.0-multiTexture.png b/tests/media/Direct3D 9.0-multiTexture.png new file mode 100644 index 00000000..4b891f95 Binary files /dev/null and b/tests/media/Direct3D 9.0-multiTexture.png differ diff --git a/tests/media/Direct3D 9.0-orthoCam.png b/tests/media/Direct3D 9.0-orthoCam.png new file mode 100644 index 00000000..54d4118f Binary files /dev/null and b/tests/media/Direct3D 9.0-orthoCam.png differ diff --git a/tests/media/Direct3D 9.0-orthoStencil.png b/tests/media/Direct3D 9.0-orthoStencil.png new file mode 100644 index 00000000..4e7afb8a Binary files /dev/null and b/tests/media/Direct3D 9.0-orthoStencil.png differ diff --git a/tests/media/Direct3D 9.0-pixelAccuracy.png b/tests/media/Direct3D 9.0-pixelAccuracy.png new file mode 100644 index 00000000..24190ef8 Binary files /dev/null and b/tests/media/Direct3D 9.0-pixelAccuracy.png differ diff --git a/tests/media/Direct3D 9.0-polygonBack.png b/tests/media/Direct3D 9.0-polygonBack.png new file mode 100644 index 00000000..76fb2e2d Binary files /dev/null and b/tests/media/Direct3D 9.0-polygonBack.png differ diff --git a/tests/media/Direct3D 9.0-polygonFront.png b/tests/media/Direct3D 9.0-polygonFront.png new file mode 100644 index 00000000..76fb2e2d Binary files /dev/null and b/tests/media/Direct3D 9.0-polygonFront.png differ diff --git a/tests/media/Direct3D 9.0-projMat.png b/tests/media/Direct3D 9.0-projMat.png new file mode 100644 index 00000000..06022a79 Binary files /dev/null and b/tests/media/Direct3D 9.0-projMat.png differ diff --git a/tests/media/Direct3D 9.0-renderMipmap.png b/tests/media/Direct3D 9.0-renderMipmap.png new file mode 100644 index 00000000..86e4fda6 Binary files /dev/null and b/tests/media/Direct3D 9.0-renderMipmap.png differ diff --git a/tests/media/Direct3D 9.0-rttAndAntiAlias.png b/tests/media/Direct3D 9.0-rttAndAntiAlias.png new file mode 100644 index 00000000..bb482c22 Binary files /dev/null and b/tests/media/Direct3D 9.0-rttAndAntiAlias.png differ diff --git a/tests/media/Direct3D 9.0-rttAndText.png b/tests/media/Direct3D 9.0-rttAndText.png new file mode 100644 index 00000000..f162da7b Binary files /dev/null and b/tests/media/Direct3D 9.0-rttAndText.png differ diff --git a/tests/media/Direct3D 9.0-rttWith2DImage.png b/tests/media/Direct3D 9.0-rttWith2DImage.png new file mode 100644 index 00000000..bc179e80 Binary files /dev/null and b/tests/media/Direct3D 9.0-rttWith2DImage.png differ diff --git a/tests/media/Direct3D 9.0-stencilSelfShadow.png b/tests/media/Direct3D 9.0-stencilSelfShadow.png new file mode 100644 index 00000000..4c271de7 Binary files /dev/null and b/tests/media/Direct3D 9.0-stencilSelfShadow.png differ diff --git a/tests/media/Direct3D 9.0-stencilShadow.png b/tests/media/Direct3D 9.0-stencilShadow.png new file mode 100644 index 00000000..724d5d3b Binary files /dev/null and b/tests/media/Direct3D 9.0-stencilShadow.png differ diff --git a/tests/media/Direct3D 9.0-textureMatrix.png b/tests/media/Direct3D 9.0-textureMatrix.png new file mode 100644 index 00000000..d561bbd9 Binary files /dev/null and b/tests/media/Direct3D 9.0-textureMatrix.png differ diff --git a/tests/media/Direct3D 9.0-textureMatrix2.png b/tests/media/Direct3D 9.0-textureMatrix2.png new file mode 100644 index 00000000..30aabf05 Binary files /dev/null and b/tests/media/Direct3D 9.0-textureMatrix2.png differ diff --git a/tests/media/Direct3D 9.0-textureMatrixInMixedScenes.png b/tests/media/Direct3D 9.0-textureMatrixInMixedScenes.png new file mode 100644 index 00000000..187d3b8e Binary files /dev/null and b/tests/media/Direct3D 9.0-textureMatrixInMixedScenes.png differ diff --git a/tests/media/Direct3D 9.0-textureRenderStates.png b/tests/media/Direct3D 9.0-textureRenderStates.png new file mode 100644 index 00000000..98282fa1 Binary files /dev/null and b/tests/media/Direct3D 9.0-textureRenderStates.png differ diff --git a/tests/media/Direct3D 9.0-transparentAddColor.png b/tests/media/Direct3D 9.0-transparentAddColor.png new file mode 100644 index 00000000..cb741c49 Binary files /dev/null and b/tests/media/Direct3D 9.0-transparentAddColor.png differ diff --git a/tests/media/Direct3D 9.0-transparentAlphaChannel.png b/tests/media/Direct3D 9.0-transparentAlphaChannel.png new file mode 100644 index 00000000..be28cc56 Binary files /dev/null and b/tests/media/Direct3D 9.0-transparentAlphaChannel.png differ diff --git a/tests/media/Direct3D 9.0-transparentAlphaChannelRef.png b/tests/media/Direct3D 9.0-transparentAlphaChannelRef.png new file mode 100644 index 00000000..4f40301f Binary files /dev/null and b/tests/media/Direct3D 9.0-transparentAlphaChannelRef.png differ diff --git a/tests/media/Direct3D 9.0-transparentReflection2Layer.png b/tests/media/Direct3D 9.0-transparentReflection2Layer.png new file mode 100644 index 00000000..12baed71 Binary files /dev/null and b/tests/media/Direct3D 9.0-transparentReflection2Layer.png differ diff --git a/tests/media/Direct3D 9.0-transparentVertexAlpha.png b/tests/media/Direct3D 9.0-transparentVertexAlpha.png new file mode 100644 index 00000000..88e03583 Binary files /dev/null and b/tests/media/Direct3D 9.0-transparentVertexAlpha.png differ diff --git a/tests/media/Direct3D 9.0-transparentVertexAlphaChannelMore.png b/tests/media/Direct3D 9.0-transparentVertexAlphaChannelMore.png new file mode 100644 index 00000000..ceb2a810 Binary files /dev/null and b/tests/media/Direct3D 9.0-transparentVertexAlphaChannelMore.png differ diff --git a/tests/media/Direct3D 9.0-ucpsphere.png b/tests/media/Direct3D 9.0-ucpsphere.png new file mode 100644 index 00000000..103987a9 Binary files /dev/null and b/tests/media/Direct3D 9.0-ucpsphere.png differ diff --git a/tests/media/Direct3D 9.0-viewPortText.png b/tests/media/Direct3D 9.0-viewPortText.png new file mode 100644 index 00000000..c1cd9247 Binary files /dev/null and b/tests/media/Direct3D 9.0-viewPortText.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-createImage.png b/tests/media/Irrlicht Software Driver 1.0-createImage.png new file mode 100644 index 00000000..0ccc2bc4 Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-createImage.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-draw2DImageRTT.png b/tests/media/Irrlicht Software Driver 1.0-draw2DImageRTT.png new file mode 100644 index 00000000..58a6e761 Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-draw2DImageRTT.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-draw2DImageRect.png b/tests/media/Irrlicht Software Driver 1.0-draw2DImageRect.png new file mode 100644 index 00000000..7b9fab1f Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-draw2DImageRect.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-drawLine.png b/tests/media/Irrlicht Software Driver 1.0-drawLine.png new file mode 100644 index 00000000..8bcb70f3 Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-drawLine.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-drawPixel.png b/tests/media/Irrlicht Software Driver 1.0-drawPixel.png new file mode 100644 index 00000000..9002faf8 Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-drawPixel.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-drawRectOutline.png b/tests/media/Irrlicht Software Driver 1.0-drawRectOutline.png new file mode 100644 index 00000000..452d1642 Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-drawRectOutline.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-drawVPL_a.png b/tests/media/Irrlicht Software Driver 1.0-drawVPL_a.png new file mode 100644 index 00000000..a41c6c5d Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-drawVPL_a.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-drawVPL_b.png b/tests/media/Irrlicht Software Driver 1.0-drawVPL_b.png new file mode 100644 index 00000000..cb2655fc Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-drawVPL_b.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-drawVPL_c.png b/tests/media/Irrlicht Software Driver 1.0-drawVPL_c.png new file mode 100644 index 00000000..2e831ace Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-drawVPL_c.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-drawVPL_d.png b/tests/media/Irrlicht Software Driver 1.0-drawVPL_d.png new file mode 100644 index 00000000..38157810 Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-drawVPL_d.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-drawVPL_e.png b/tests/media/Irrlicht Software Driver 1.0-drawVPL_e.png new file mode 100644 index 00000000..a41c6c5d Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-drawVPL_e.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-drawVPL_f.png b/tests/media/Irrlicht Software Driver 1.0-drawVPL_f.png new file mode 100644 index 00000000..5e019a6f Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-drawVPL_f.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-drawVPL_g.png b/tests/media/Irrlicht Software Driver 1.0-drawVPL_g.png new file mode 100644 index 00000000..9e488d7f Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-drawVPL_g.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-drawVPL_h.png b/tests/media/Irrlicht Software Driver 1.0-drawVPL_h.png new file mode 100644 index 00000000..a41c6c5d Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-drawVPL_h.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-drawVPL_i.png b/tests/media/Irrlicht Software Driver 1.0-drawVPL_i.png new file mode 100644 index 00000000..a41c6c5d Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-drawVPL_i.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-drawVPL_j.png b/tests/media/Irrlicht Software Driver 1.0-drawVPL_j.png new file mode 100644 index 00000000..a41c6c5d Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-drawVPL_j.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-drawVPL_k.png b/tests/media/Irrlicht Software Driver 1.0-drawVPL_k.png new file mode 100644 index 00000000..a41c6c5d Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-drawVPL_k.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-makeColorKeyTexture-new.png b/tests/media/Irrlicht Software Driver 1.0-makeColorKeyTexture-new.png new file mode 100644 index 00000000..20cc84e0 Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-makeColorKeyTexture-new.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-makeColorKeyTexture-old.png b/tests/media/Irrlicht Software Driver 1.0-makeColorKeyTexture-old.png new file mode 100644 index 00000000..87dc6624 Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-makeColorKeyTexture-old.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-multiTexture.png b/tests/media/Irrlicht Software Driver 1.0-multiTexture.png new file mode 100644 index 00000000..8b4f3527 Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-multiTexture.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-pixelAccuracy.png b/tests/media/Irrlicht Software Driver 1.0-pixelAccuracy.png new file mode 100644 index 00000000..70a441df Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-pixelAccuracy.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-projMat.png b/tests/media/Irrlicht Software Driver 1.0-projMat.png new file mode 100644 index 00000000..4cb549d8 Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-projMat.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-rttAndText.png b/tests/media/Irrlicht Software Driver 1.0-rttAndText.png new file mode 100644 index 00000000..6c165904 Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-rttAndText.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-rttWith2DImage.png b/tests/media/Irrlicht Software Driver 1.0-rttWith2DImage.png new file mode 100644 index 00000000..98cdd8e5 Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-rttWith2DImage.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-softwareDevice-rotatedClip.png b/tests/media/Irrlicht Software Driver 1.0-softwareDevice-rotatedClip.png new file mode 100644 index 00000000..9f753599 Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-softwareDevice-rotatedClip.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-textureRenderStates.png b/tests/media/Irrlicht Software Driver 1.0-textureRenderStates.png new file mode 100644 index 00000000..81853f21 Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-textureRenderStates.png differ diff --git a/tests/media/Irrlicht Software Driver 1.0-viewPortText.png b/tests/media/Irrlicht Software Driver 1.0-viewPortText.png new file mode 100644 index 00000000..0c2234eb Binary files /dev/null and b/tests/media/Irrlicht Software Driver 1.0-viewPortText.png differ diff --git a/tests/media/Monty.zip b/tests/media/Monty.zip new file mode 100644 index 00000000..956c33c9 Binary files /dev/null and b/tests/media/Monty.zip differ diff --git a/tests/media/OpenGL-2dmatFilter.png b/tests/media/OpenGL-2dmatFilter.png new file mode 100644 index 00000000..75b59df6 Binary files /dev/null and b/tests/media/OpenGL-2dmatFilter.png differ diff --git a/tests/media/OpenGL-addBlend2D.png b/tests/media/OpenGL-addBlend2D.png new file mode 100644 index 00000000..09fd9bad Binary files /dev/null and b/tests/media/OpenGL-addBlend2D.png differ diff --git a/tests/media/OpenGL-draw2DImage4cFilter.png b/tests/media/OpenGL-draw2DImage4cFilter.png new file mode 100644 index 00000000..57ef58a8 Binary files /dev/null and b/tests/media/OpenGL-draw2DImage4cFilter.png differ diff --git a/tests/media/OpenGL-draw2DImagePNG.png b/tests/media/OpenGL-draw2DImagePNG.png new file mode 100644 index 00000000..4bec6930 Binary files /dev/null and b/tests/media/OpenGL-draw2DImagePNG.png differ diff --git a/tests/media/OpenGL-draw2DImageRTT.png b/tests/media/OpenGL-draw2DImageRTT.png new file mode 100644 index 00000000..dde350ff Binary files /dev/null and b/tests/media/OpenGL-draw2DImageRTT.png differ diff --git a/tests/media/OpenGL-draw2DImageRect.png b/tests/media/OpenGL-draw2DImageRect.png new file mode 100644 index 00000000..c89b00b8 Binary files /dev/null and b/tests/media/OpenGL-draw2DImageRect.png differ diff --git a/tests/media/OpenGL-drawLine.png b/tests/media/OpenGL-drawLine.png new file mode 100644 index 00000000..b3b2ea41 Binary files /dev/null and b/tests/media/OpenGL-drawLine.png differ diff --git a/tests/media/OpenGL-drawPixel.png b/tests/media/OpenGL-drawPixel.png new file mode 100644 index 00000000..2f9f5811 Binary files /dev/null and b/tests/media/OpenGL-drawPixel.png differ diff --git a/tests/media/OpenGL-drawRectOutline.png b/tests/media/OpenGL-drawRectOutline.png new file mode 100644 index 00000000..6032237a Binary files /dev/null and b/tests/media/OpenGL-drawRectOutline.png differ diff --git a/tests/media/OpenGL-drawVPL_a.png b/tests/media/OpenGL-drawVPL_a.png new file mode 100644 index 00000000..f2bb71f0 Binary files /dev/null and b/tests/media/OpenGL-drawVPL_a.png differ diff --git a/tests/media/OpenGL-drawVPL_b.png b/tests/media/OpenGL-drawVPL_b.png new file mode 100644 index 00000000..3f7eca4c Binary files /dev/null and b/tests/media/OpenGL-drawVPL_b.png differ diff --git a/tests/media/OpenGL-drawVPL_c.png b/tests/media/OpenGL-drawVPL_c.png new file mode 100644 index 00000000..5d52e953 Binary files /dev/null and b/tests/media/OpenGL-drawVPL_c.png differ diff --git a/tests/media/OpenGL-drawVPL_d.png b/tests/media/OpenGL-drawVPL_d.png new file mode 100644 index 00000000..144ba9be Binary files /dev/null and b/tests/media/OpenGL-drawVPL_d.png differ diff --git a/tests/media/OpenGL-drawVPL_e.png b/tests/media/OpenGL-drawVPL_e.png new file mode 100644 index 00000000..a6ab41ff Binary files /dev/null and b/tests/media/OpenGL-drawVPL_e.png differ diff --git a/tests/media/OpenGL-drawVPL_f.png b/tests/media/OpenGL-drawVPL_f.png new file mode 100644 index 00000000..373748de Binary files /dev/null and b/tests/media/OpenGL-drawVPL_f.png differ diff --git a/tests/media/OpenGL-drawVPL_g.png b/tests/media/OpenGL-drawVPL_g.png new file mode 100644 index 00000000..473384c6 Binary files /dev/null and b/tests/media/OpenGL-drawVPL_g.png differ diff --git a/tests/media/OpenGL-drawVPL_h.png b/tests/media/OpenGL-drawVPL_h.png new file mode 100644 index 00000000..2e82269f Binary files /dev/null and b/tests/media/OpenGL-drawVPL_h.png differ diff --git a/tests/media/OpenGL-drawVPL_i.png b/tests/media/OpenGL-drawVPL_i.png new file mode 100644 index 00000000..3fc59ec0 Binary files /dev/null and b/tests/media/OpenGL-drawVPL_i.png differ diff --git a/tests/media/OpenGL-drawVPL_j.png b/tests/media/OpenGL-drawVPL_j.png new file mode 100644 index 00000000..f6becb6c Binary files /dev/null and b/tests/media/OpenGL-drawVPL_j.png differ diff --git a/tests/media/OpenGL-drawVPL_k.png b/tests/media/OpenGL-drawVPL_k.png new file mode 100644 index 00000000..f2bb71f0 Binary files /dev/null and b/tests/media/OpenGL-drawVPL_k.png differ diff --git a/tests/media/OpenGL-lightType.png b/tests/media/OpenGL-lightType.png new file mode 100644 index 00000000..46af20bb Binary files /dev/null and b/tests/media/OpenGL-lightType.png differ diff --git a/tests/media/OpenGL-lightmaps.png b/tests/media/OpenGL-lightmaps.png new file mode 100644 index 00000000..f53a7e36 Binary files /dev/null and b/tests/media/OpenGL-lightmaps.png differ diff --git a/tests/media/OpenGL-lineAntiAliasing.png b/tests/media/OpenGL-lineAntiAliasing.png new file mode 100644 index 00000000..75456881 Binary files /dev/null and b/tests/media/OpenGL-lineAntiAliasing.png differ diff --git a/tests/media/OpenGL-mrt.png b/tests/media/OpenGL-mrt.png new file mode 100644 index 00000000..c3b6598c Binary files /dev/null and b/tests/media/OpenGL-mrt.png differ diff --git a/tests/media/OpenGL-mrt2.png b/tests/media/OpenGL-mrt2.png new file mode 100644 index 00000000..88f4e209 Binary files /dev/null and b/tests/media/OpenGL-mrt2.png differ diff --git a/tests/media/OpenGL-multiTexture.png b/tests/media/OpenGL-multiTexture.png new file mode 100644 index 00000000..5eb8ae92 Binary files /dev/null and b/tests/media/OpenGL-multiTexture.png differ diff --git a/tests/media/OpenGL-octree_select1.png b/tests/media/OpenGL-octree_select1.png new file mode 100644 index 00000000..8129b455 Binary files /dev/null and b/tests/media/OpenGL-octree_select1.png differ diff --git a/tests/media/OpenGL-octree_select2.png b/tests/media/OpenGL-octree_select2.png new file mode 100644 index 00000000..2fb50ef5 Binary files /dev/null and b/tests/media/OpenGL-octree_select2.png differ diff --git a/tests/media/OpenGL-orthoCam.png b/tests/media/OpenGL-orthoCam.png new file mode 100644 index 00000000..fa7b8b04 Binary files /dev/null and b/tests/media/OpenGL-orthoCam.png differ diff --git a/tests/media/OpenGL-orthoStencil.png b/tests/media/OpenGL-orthoStencil.png new file mode 100644 index 00000000..913905cb Binary files /dev/null and b/tests/media/OpenGL-orthoStencil.png differ diff --git a/tests/media/OpenGL-pixelAccuracy.png b/tests/media/OpenGL-pixelAccuracy.png new file mode 100644 index 00000000..24190ef8 Binary files /dev/null and b/tests/media/OpenGL-pixelAccuracy.png differ diff --git a/tests/media/OpenGL-polygonBack.png b/tests/media/OpenGL-polygonBack.png new file mode 100644 index 00000000..b6d57707 Binary files /dev/null and b/tests/media/OpenGL-polygonBack.png differ diff --git a/tests/media/OpenGL-polygonFront.png b/tests/media/OpenGL-polygonFront.png new file mode 100644 index 00000000..2d3da542 Binary files /dev/null and b/tests/media/OpenGL-polygonFront.png differ diff --git a/tests/media/OpenGL-projMat.png b/tests/media/OpenGL-projMat.png new file mode 100644 index 00000000..b3970372 Binary files /dev/null and b/tests/media/OpenGL-projMat.png differ diff --git a/tests/media/OpenGL-renderMipmap.png b/tests/media/OpenGL-renderMipmap.png new file mode 100644 index 00000000..699bbf47 Binary files /dev/null and b/tests/media/OpenGL-renderMipmap.png differ diff --git a/tests/media/OpenGL-rttAndAntiAlias.png b/tests/media/OpenGL-rttAndAntiAlias.png new file mode 100644 index 00000000..947362fc Binary files /dev/null and b/tests/media/OpenGL-rttAndAntiAlias.png differ diff --git a/tests/media/OpenGL-rttAndText.png b/tests/media/OpenGL-rttAndText.png new file mode 100644 index 00000000..ca6b8198 Binary files /dev/null and b/tests/media/OpenGL-rttAndText.png differ diff --git a/tests/media/OpenGL-rttWith2DImage.png b/tests/media/OpenGL-rttWith2DImage.png new file mode 100644 index 00000000..bc179e80 Binary files /dev/null and b/tests/media/OpenGL-rttWith2DImage.png differ diff --git a/tests/media/OpenGL-stencilSelfShadow.png b/tests/media/OpenGL-stencilSelfShadow.png new file mode 100644 index 00000000..d5a9abf3 Binary files /dev/null and b/tests/media/OpenGL-stencilSelfShadow.png differ diff --git a/tests/media/OpenGL-stencilShadow.png b/tests/media/OpenGL-stencilShadow.png new file mode 100644 index 00000000..8f1534ad Binary files /dev/null and b/tests/media/OpenGL-stencilShadow.png differ diff --git a/tests/media/OpenGL-textureMatrix.png b/tests/media/OpenGL-textureMatrix.png new file mode 100644 index 00000000..4cd34dc7 Binary files /dev/null and b/tests/media/OpenGL-textureMatrix.png differ diff --git a/tests/media/OpenGL-textureMatrix2.png b/tests/media/OpenGL-textureMatrix2.png new file mode 100644 index 00000000..5faaad75 Binary files /dev/null and b/tests/media/OpenGL-textureMatrix2.png differ diff --git a/tests/media/OpenGL-textureMatrixInMixedScenes.png b/tests/media/OpenGL-textureMatrixInMixedScenes.png new file mode 100644 index 00000000..9e52511e Binary files /dev/null and b/tests/media/OpenGL-textureMatrixInMixedScenes.png differ diff --git a/tests/media/OpenGL-texturePointer.png b/tests/media/OpenGL-texturePointer.png new file mode 100644 index 00000000..4fbbbf71 Binary files /dev/null and b/tests/media/OpenGL-texturePointer.png differ diff --git a/tests/media/OpenGL-textureRenderStates.png b/tests/media/OpenGL-textureRenderStates.png new file mode 100644 index 00000000..98282fa1 Binary files /dev/null and b/tests/media/OpenGL-textureRenderStates.png differ diff --git a/tests/media/OpenGL-transparentAddColor.png b/tests/media/OpenGL-transparentAddColor.png new file mode 100644 index 00000000..f590388f Binary files /dev/null and b/tests/media/OpenGL-transparentAddColor.png differ diff --git a/tests/media/OpenGL-transparentAlphaChannel.png b/tests/media/OpenGL-transparentAlphaChannel.png new file mode 100644 index 00000000..a99ad2c1 Binary files /dev/null and b/tests/media/OpenGL-transparentAlphaChannel.png differ diff --git a/tests/media/OpenGL-transparentAlphaChannelRef.png b/tests/media/OpenGL-transparentAlphaChannelRef.png new file mode 100644 index 00000000..3091a66c Binary files /dev/null and b/tests/media/OpenGL-transparentAlphaChannelRef.png differ diff --git a/tests/media/OpenGL-transparentReflection2Layer.png b/tests/media/OpenGL-transparentReflection2Layer.png new file mode 100644 index 00000000..ed1b45d3 Binary files /dev/null and b/tests/media/OpenGL-transparentReflection2Layer.png differ diff --git a/tests/media/OpenGL-transparentVertexAlpha.png b/tests/media/OpenGL-transparentVertexAlpha.png new file mode 100644 index 00000000..71d71df2 Binary files /dev/null and b/tests/media/OpenGL-transparentVertexAlpha.png differ diff --git a/tests/media/OpenGL-transparentVertexAlphaChannelMore.png b/tests/media/OpenGL-transparentVertexAlphaChannelMore.png new file mode 100644 index 00000000..a2dae695 Binary files /dev/null and b/tests/media/OpenGL-transparentVertexAlphaChannelMore.png differ diff --git a/tests/media/OpenGL-tri_select1.png b/tests/media/OpenGL-tri_select1.png new file mode 100644 index 00000000..7f0f772f Binary files /dev/null and b/tests/media/OpenGL-tri_select1.png differ diff --git a/tests/media/OpenGL-tri_select2.png b/tests/media/OpenGL-tri_select2.png new file mode 100644 index 00000000..6abed251 Binary files /dev/null and b/tests/media/OpenGL-tri_select2.png differ diff --git a/tests/media/OpenGL-tri_select3.png b/tests/media/OpenGL-tri_select3.png new file mode 100644 index 00000000..27c5d0b3 Binary files /dev/null and b/tests/media/OpenGL-tri_select3.png differ diff --git a/tests/media/OpenGL-ucpsphere.png b/tests/media/OpenGL-ucpsphere.png new file mode 100644 index 00000000..89cbd00f Binary files /dev/null and b/tests/media/OpenGL-ucpsphere.png differ diff --git a/tests/media/OpenGL-viewPortText.png b/tests/media/OpenGL-viewPortText.png new file mode 100644 index 00000000..adacf93c Binary files /dev/null and b/tests/media/OpenGL-viewPortText.png differ diff --git a/tests/media/RedbrushAlpha-0.25.png b/tests/media/RedbrushAlpha-0.25.png new file mode 100644 index 00000000..e17d5be9 Binary files /dev/null and b/tests/media/RedbrushAlpha-0.25.png differ diff --git a/tests/media/attributes.xml b/tests/media/attributes.xml new file mode 100644 index 00000000..b2c73f25 --- /dev/null +++ b/tests/media/attributes.xml @@ -0,0 +1,4 @@ + + + + diff --git a/tests/media/cdata.xml b/tests/media/cdata.xml new file mode 100644 index 00000000..dfcfa0c7 --- /dev/null +++ b/tests/media/cdata.xml @@ -0,0 +1,14 @@ + + + + + ]]> + ]]> + + + + diff --git a/tests/media/enc.zip b/tests/media/enc.zip new file mode 100755 index 00000000..db5bcc71 Binary files /dev/null and b/tests/media/enc.zip differ diff --git a/tests/media/file_with_path.npk b/tests/media/file_with_path.npk new file mode 100644 index 00000000..cda73db7 Binary files /dev/null and b/tests/media/file_with_path.npk differ diff --git a/tests/media/file_with_path.zip b/tests/media/file_with_path.zip new file mode 100644 index 00000000..8d301e62 Binary files /dev/null and b/tests/media/file_with_path.zip differ diff --git a/tests/media/file_with_path/mypath/myfile.txt b/tests/media/file_with_path/mypath/myfile.txt new file mode 100644 index 00000000..19fe4276 --- /dev/null +++ b/tests/media/file_with_path/mypath/myfile.txt @@ -0,0 +1 @@ +1est diff --git a/tests/media/file_with_path/mypath/mypath/myfile.txt b/tests/media/file_with_path/mypath/mypath/myfile.txt new file mode 100644 index 00000000..75845e16 --- /dev/null +++ b/tests/media/file_with_path/mypath/mypath/myfile.txt @@ -0,0 +1 @@ +2est \ No newline at end of file diff --git a/tests/media/file_with_path/test/test.txt b/tests/media/file_with_path/test/test.txt new file mode 100644 index 00000000..cd087558 --- /dev/null +++ b/tests/media/file_with_path/test/test.txt @@ -0,0 +1 @@ +Hello world! diff --git a/tests/media/fireball.png b/tests/media/fireball.png new file mode 100644 index 00000000..7f41b3f6 Binary files /dev/null and b/tests/media/fireball.png differ diff --git a/tests/media/grey.tga b/tests/media/grey.tga new file mode 100644 index 00000000..5186a61a Binary files /dev/null and b/tests/media/grey.tga differ diff --git a/tests/media/licenses.txt b/tests/media/licenses.txt new file mode 100644 index 00000000..b8c06bcf --- /dev/null +++ b/tests/media/licenses.txt @@ -0,0 +1,7 @@ +All assets of this test suite, except where noted below, are tkane from the main Irrlicht repository and are copyright/licensed as stated there. The source code is copyright by the authors, except where stated differently inside the files. + +title_font.xml and its png files are taken from SuperTuxKart. They are in the public domain. + +The image RedbrushAlpha-0.25.png is Copyright 1999 Pieter S. van der Meulen. This image, including the alpha channel, may be used, edited and reproduced freely. + Taken from http://www.libpng.org/pub/png/png-RedbrushAlpha.html + diff --git a/tests/media/lzmadata.zip b/tests/media/lzmadata.zip new file mode 100644 index 00000000..3c257b1e Binary files /dev/null and b/tests/media/lzmadata.zip differ diff --git a/tests/media/sample_pakfile.pak b/tests/media/sample_pakfile.pak new file mode 100644 index 00000000..aa90ccad Binary files /dev/null and b/tests/media/sample_pakfile.pak differ diff --git a/tests/media/scene.irr b/tests/media/scene.irr new file mode 100644 index 00000000..244913b2 Binary files /dev/null and b/tests/media/scene.irr differ diff --git a/tests/media/scene2.irr b/tests/media/scene2.irr new file mode 100644 index 00000000..49ff185e Binary files /dev/null and b/tests/media/scene2.irr differ diff --git a/tests/media/sydney.bmp b/tests/media/sydney.bmp new file mode 100644 index 00000000..2f14a5a0 Binary files /dev/null and b/tests/media/sydney.bmp differ diff --git a/tests/media/sydney.md2 b/tests/media/sydney.md2 new file mode 100644 index 00000000..7d3521dd Binary files /dev/null and b/tests/media/sydney.md2 differ diff --git a/tests/media/ter1.png b/tests/media/ter1.png new file mode 100644 index 00000000..0675b275 Binary files /dev/null and b/tests/media/ter1.png differ diff --git a/tests/media/test.xml b/tests/media/test.xml new file mode 100644 index 00000000..d311c1aa --- /dev/null +++ b/tests/media/test.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/tests/media/title_font.png b/tests/media/title_font.png new file mode 100644 index 00000000..f075aa2f Binary files /dev/null and b/tests/media/title_font.png differ diff --git a/tests/media/title_font.xml b/tests/media/title_font.xml new file mode 100644 index 00000000..32a6b0da Binary files /dev/null and b/tests/media/title_font.xml differ diff --git a/tests/media/title_font_2.png b/tests/media/title_font_2.png new file mode 100644 index 00000000..2f4b0fb0 Binary files /dev/null and b/tests/media/title_font_2.png differ diff --git a/tests/media/tools.png b/tests/media/tools.png new file mode 100644 index 00000000..b7e86c93 Binary files /dev/null and b/tests/media/tools.png differ diff --git a/tests/meshLoaders.cpp b/tests/meshLoaders.cpp new file mode 100644 index 00000000..2a828c3d --- /dev/null +++ b/tests/meshLoaders.cpp @@ -0,0 +1,37 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; + +// Tests mesh loading features and the mesh cache. +/** This won't test render results. Currently, not all mesh loaders are tested. */ +bool meshLoaders(void) +{ + IrrlichtDevice *device = createDevice(video::EDT_NULL, core::dimension2d(160, 120), 32); + assert_log(device); + if (!device) + return false; + + scene::ISceneManager * smgr = device->getSceneManager(); + scene::IAnimatedMesh* mesh = smgr->getMesh("../media/ninja.b3d"); + assert_log(mesh); + + bool result = (mesh != 0); + + if (mesh) + { + if (mesh != smgr->getMesh("../media/ninja.b3d")) + { + logTestString("Loading from same file results in different meshes!"); + result=false; + } + } + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} diff --git a/tests/meshTransform.cpp b/tests/meshTransform.cpp new file mode 100644 index 00000000..e57bcb0b --- /dev/null +++ b/tests/meshTransform.cpp @@ -0,0 +1,88 @@ +// Copyright (C) 2009-2012 Christian Stehno +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +// Tests mesh transformations via mesh manipulator. +bool meshTransform(void) +{ + // Use EDT_BURNINGSVIDEO since it is not dependent on (e.g.) OpenGL driver versions. + IrrlichtDevice *device = createDevice(EDT_BURNINGSVIDEO, dimension2d(160, 120), 32); + assert_log(device); + if (!device) + return false; + + IVideoDriver* driver = device->getVideoDriver(); + ISceneManager * smgr = device->getSceneManager(); + + IMeshSceneNode* node1 = smgr->addCubeSceneNode(50); + IAnimatedMesh* amesh = smgr->getMesh("../media/sydney.md2"); + IAnimatedMesh* smesh = smgr->getMesh("../media/ninja.b3d"); + assert_log(node1 && amesh && smesh); + + bool result = false; + if (!node1 || !amesh || !smesh) + return false; + +// node1->setPosition(core::vector3df(-60,0,150)); + node1->setDebugDataVisible(scene::EDS_BBOX_ALL); + + IMeshSceneNode* node2 = smgr->addMeshSceneNode(amesh->getMesh(10)); + assert_log(node2); + + if (!node2) + return false; + +// node2->setPosition(core::vector3df(30,10,150)); + node2->setDebugDataVisible(scene::EDS_BBOX_ALL); + node2->setMaterialFlag(EMF_LIGHTING, false); + + IMeshSceneNode* node3 = smgr->addMeshSceneNode(smesh->getMesh(10)); + assert_log(node3); + + if (!node3) + return false; + +// node3->setPosition(core::vector3df(10,0,0)); + node3->setDebugDataVisible(scene::EDS_BBOX_ALL); + node3->setMaterialFlag(EMF_LIGHTING, false); + + smgr->addCameraSceneNode()->setPosition(core::vector3df(0,0,-20)); + + // Just jump to the last frame since that's all we're interested in. + device->run(); + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, SColor(255, 60, 60, 60)); + smgr->drawAll(); + driver->endScene(); + + core::matrix4 mat; + mat.setTranslation(core::vector3df(-60,0,150)); + driver->getMeshManipulator()->transform(node1->getMesh(), mat); + + mat.setTranslation(core::vector3df(30,10,150)); + driver->getMeshManipulator()->transform(node2->getMesh(), mat); + + mat.setTranslation(core::vector3df(10,0,0)); + driver->getMeshManipulator()->transform(node3->getMesh(), mat); + + // Just jump to the last frame since that's all we're interested in. + device->run(); + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, SColor(255, 60, 60, 60)); + smgr->drawAll(); + driver->endScene(); + + result = takeScreenshotAndCompareAgainstReference(driver, "-meshTransform.png"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} diff --git a/tests/mrt.cpp b/tests/mrt.cpp new file mode 100644 index 00000000..84c8c4d3 --- /dev/null +++ b/tests/mrt.cpp @@ -0,0 +1,138 @@ +// Copyright (C) 2008-2012 Christian Stehno, Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; + +//! Tests rendering MRTs +static bool testWithDriver(video::E_DRIVER_TYPE driverType) +{ + IrrlichtDevice *device = createDevice (driverType, core::dimension2d < u32 > (220, 80)); + if (!device) + return true; // No error if device does not exist + + video::IVideoDriver* driver = device->getVideoDriver(); + // We need at least GLSL 1.10 or HLSL 1.1 +// if (driver->getDriverAttributes().getAttributeAsInt("ShaderLanguageVersion")<=100) +// return true; + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + // write white to first render-texture, green to second, blue to third + const char* const psHLSL = + "struct PS_INPUT\n"\ + "{\n"\ + " float4 Position : POSITION0;\n"\ + "};\n"\ + "struct PS_OUTPUT\n"\ + "{\n "\ + " float4 Color : COLOR0;\n"\ + " float4 Normal : COLOR1;\n"\ + " float4 Depth : COLOR2;\n"\ + "};\n"\ + "PS_OUTPUT pixelMain( PS_INPUT Input )\n"\ + "{\n"\ + " PS_OUTPUT Output;\n"\ + " Output.Color = float4(1.0,1.0,1.0,1.0);\n"\ + " Output.Normal = float4(0.0,1.0,0.0,1.0);\n"\ + " Output.Depth = float4(0.0,0.0,1.0,1.0);\n"\ + " return Output;\n"\ + "}"; + + const char* const psGLSL = + "void main(void)\n"\ + "{\n"\ + " gl_FragData[0] = vec4(1.0,1.0,1.0,1.0);\n"\ + " gl_FragData[1] = vec4(0.0,1.0,0.0,1.0);\n"\ + " gl_FragData[2] = vec4(0.0,0.0,1.0,1.0);\n"\ + "}"; + + // variable + video::IRenderTarget* renderTarget = 0; + core::array renderTargetTex; + video::ITexture* renderTargetDepth = 0; + + const core::dimension2du texsize(64,64); + bool result=true; + s32 newMaterialType = -1; + + if (device->getVideoDriver()->getDriverAttributes().getAttributeAsInt("MaxMultipleRenderTargets") > 2) + { + renderTargetTex.set_used(3); + renderTargetTex[0] = driver->addRenderTargetTexture(texsize, "rta", video::ECF_A8R8G8B8); + renderTargetTex[1] = driver->addRenderTargetTexture(texsize, "rtb", video::ECF_A8R8G8B8); + renderTargetTex[2] = driver->addRenderTargetTexture(texsize, "rtc", video::ECF_A8R8G8B8); + + renderTargetDepth = driver->addRenderTargetTexture(texsize, "rtd", video::ECF_D16); + + renderTarget = driver->addRenderTarget(); + renderTarget->setTexture(renderTargetTex, renderTargetDepth); + + video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices(); + + if (gpu) + { + newMaterialType = gpu->addHighLevelShaderMaterial( + 0, "vertexMain", video::EVST_VS_1_1, + driverType==video::EDT_DIRECT3D9?psHLSL:psGLSL, "pixelMain", video::EPST_PS_1_1); + } + } + + // shader creation succeeded + if (newMaterialType!=-1) + { + scene::ISceneNode* node = device->getSceneManager()->addCubeSceneNode(); + node->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType); + device->getSceneManager()->addCameraSceneNode(0, core::vector3df(0,0,-10)); + + driver->beginScene(video::ECBF_COLOR, video::SColor(255, 0, 0, 0)); + // render + driver->setRenderTargetEx(renderTarget, video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,0,0,0)); + device->getSceneManager()->drawAll(); + driver->setRenderTargetEx(0, 0, video::SColor(255, 0, 0, 0)); + + // draw debug rt + driver->draw2DImage(renderTargetTex[0], core::position2d(0,0)); + driver->draw2DImage(renderTargetTex[1], core::position2d(64,0)); + driver->draw2DImage(renderTargetTex[2], core::position2d(128,0)); + + driver->endScene(); + + result = takeScreenshotAndCompareAgainstReference(driver, "-mrt.png"); + + driver->beginScene(video::ECBF_COLOR, video::SColor(255, 0, 0, 0)); + // render + device->getSceneManager()->getActiveCamera()->setPosition(core::vector3df(0,0,-15)); + driver->setRenderTargetEx(renderTarget, video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,0,0,0)); + device->getSceneManager()->drawAll(); + driver->setRenderTargetEx(0, 0, video::SColor(255,0,0,0)); + + // draw debug rt + driver->draw2DImage(renderTargetTex[0], core::position2d(0,0)); + driver->draw2DImage(renderTargetTex[1], core::position2d(64,0)); + driver->draw2DImage(renderTargetTex[2], core::position2d(128,0)); + + driver->endScene(); + + result &= takeScreenshotAndCompareAgainstReference(driver, "-mrt2.png"); + } + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + + +bool mrt(void) +{ + bool result = true; + + TestWithAllHWDrivers(testWithDriver); + + return result; +} diff --git a/tests/orthoCam.cpp b/tests/orthoCam.cpp new file mode 100644 index 00000000..deb08bcd --- /dev/null +++ b/tests/orthoCam.cpp @@ -0,0 +1,105 @@ +// Copyright (C) 2008-2012 Christian Stehno, Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; + +static bool testOrthoCam(video::E_DRIVER_TYPE driverType) +{ + IrrlichtDevice *device = createDevice (driverType, core::dimension2d(160,120)); + if (!device) + return true; // No error if device does not exist + + stabilizeScreenBackground(device->getVideoDriver()); + + scene::ICameraSceneNode* cam = device->getSceneManager()->addCameraSceneNode(); + cam->setPosition(core::vector3df(500,200,-500)); + cam->setTarget(core::vector3df()); + cam->setProjectionMatrix(core::matrix4().buildProjectionMatrixOrthoLH(240,180,0.9f,2000.f,driverType != video::EDT_OPENGL), true); + + device->getSceneManager()->addAnimatedMeshSceneNode(device->getSceneManager()->addHillPlaneMesh("plane", core::dimension2df(32,32), core::dimension2du(16,16)));//->setMaterialFlag(video::EMF_WIREFRAME, true); + device->getSceneManager()->addCubeSceneNode(20.f)->setPosition(core::vector3df(50,20,50)); + device->getSceneManager()->addCubeSceneNode(20.f)->setPosition(core::vector3df(50,20,-50)); + device->getSceneManager()->addCubeSceneNode(20.f)->setPosition(core::vector3df(50,50,0)); + + device->getSceneManager()->addCubeSceneNode(20.f)->setPosition(core::vector3df(-50,10,0)); + device->getSceneManager()->addCubeSceneNode(20.f)->setPosition(core::vector3df(100,10,-100)); + device->getSceneManager()->addCubeSceneNode(20.f)->setPosition(core::vector3df(150,10,0)); + + scene::IAnimatedMeshSceneNode* node = device->getSceneManager()->addAnimatedMeshSceneNode(device->getSceneManager()->getMesh("../media/ninja.b3d"), 0, -1, core::vector3df(-50,2,-50), core::vector3df(),core::vector3df(5,5,5)); + node->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true); + node->setAnimationSpeed(0.f); + + scene::ILightSceneNode* light = device->getSceneManager()->addLightSceneNode(0, core::vector3df(0,100,0)); + light->setLightType(video::ELT_POINT); + light->setRadius(500.f); + light->getLightData().DiffuseColor.set(0,1,1); + + device->getVideoDriver()->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0,0,0,0)); + device->getSceneManager()->drawAll(); + device->getVideoDriver()->endScene(); + + const bool result = takeScreenshotAndCompareAgainstReference(device->getVideoDriver(), "-orthoCam.png", 99.91f); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +static bool testOrthoStencil(video::E_DRIVER_TYPE driverType) +{ + IrrlichtDevice *device = createDevice (driverType, core::dimension2d(160,120), 16, false, true); + if (!device) + return true; // No error if device does not exist + + stabilizeScreenBackground(device->getVideoDriver()); + + scene::ICameraSceneNode* cam = device->getSceneManager()->addCameraSceneNode(); + cam->setPosition(core::vector3df(300,250,-300)); + cam->setTarget(core::vector3df(0,20,0)); + cam->setProjectionMatrix(core::matrix4().buildProjectionMatrixOrthoLH(120,90,0.9f,5000.f,driverType != video::EDT_OPENGL), true); + + device->getSceneManager()->addAnimatedMeshSceneNode(device->getSceneManager()->addHillPlaneMesh("plane", core::dimension2df(32,32), core::dimension2du(16,16)));//->setMaterialFlag(video::EMF_WIREFRAME, true); + + scene::IAnimatedMeshSceneNode* node = device->getSceneManager()->addAnimatedMeshSceneNode(device->getSceneManager()->getMesh("../media/ninja.b3d"), 0, -1, core::vector3df(0,2,0), core::vector3df(),core::vector3df(5,5,5)); + node->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true); + node->addShadowVolumeSceneNode(); + node->setAnimationSpeed(0.f); + + scene::ILightSceneNode* light = device->getSceneManager()->addLightSceneNode(0, core::vector3df(100,150,100)); + light->setLightType(video::ELT_POINT); + light->setRadius(500.f); + light->getLightData().DiffuseColor.set(0,1,1); + + device->getVideoDriver()->beginScene(video::ECBF_ALL, video::SColor(0,0,0,0)); + device->getSceneManager()->drawAll(); + device->getVideoDriver()->endScene(); + + const bool result = takeScreenshotAndCompareAgainstReference(device->getVideoDriver(), "-orthoStencil.png", 99.91f); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +bool orthoCam(void) +{ + bool passed = true; + + passed &= testOrthoCam(video::EDT_OPENGL); + // no lights in sw renderer +// passed &= testOrthoCam(video::EDT_SOFTWARE); + passed &= testOrthoCam(video::EDT_BURNINGSVIDEO); + passed &= testOrthoCam(video::EDT_DIRECT3D9); + + // TODO: not sure if burnings could work? Currently it doesn't. + passed &= testOrthoStencil(video::EDT_OPENGL); + passed &= testOrthoStencil(video::EDT_DIRECT3D9); + + return passed; +} diff --git a/tests/planeMatrix.cpp b/tests/planeMatrix.cpp new file mode 100644 index 00000000..30d46264 --- /dev/null +++ b/tests/planeMatrix.cpp @@ -0,0 +1,244 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +// There's all sorts of minor and inevitable FP accuracy errors here, so use a sloppy comparison. +static bool sloppyComparePlanes(const plane3df plane1, const plane3df plane2) +{ + return(equals(plane1.D, plane2.D, 0.001f) && + equals(plane1.Normal.X, plane2.Normal.X, 0.001f) && + equals(plane1.Normal.Y, plane2.Normal.Y, 0.001f) && + equals(plane1.Normal.Z, plane2.Normal.Z, 0.001f)); +} + +static bool transformPlane(const vector3df & point, const vector3df & normal, + const matrix4 & matrix, const plane3df & expected) +{ + plane3df plane(point, vector3df(normal).normalize()); + + logTestString("\n Pre N:(%.3ff,%.3ff,%.3ff), D:%.3ff\n", + plane.Normal.X, plane.Normal.Y, plane.Normal.Z, plane.D); + + matrix.transformPlane(plane); + + logTestString(" Post N:(%.3ff,%.3ff,%.3ff), D:%.3ff\n", + plane.Normal.X, plane.Normal.Y, plane.Normal.Z, plane.D); + + logTestString("Expected N:(%.3ff,%.3ff,%.3ff), D:%.3ff\n", + expected.Normal.X, expected.Normal.Y, expected.Normal.Z, expected.D); + + if(!plane.Normal.equals(vector3df(plane.Normal).normalize())) + { + logTestString("Plane normal no longer normalized after transformation\n"); + assert_log(false); + return false; + } + + if(!sloppyComparePlanes(plane, expected)) + { + logTestString("Unexpected result\n"); + assert_log(false); + return false; + } + + return true; +} + + +static bool drawScaledOctree(void) +{ + bool result = false; + IrrlichtDevice *device = createDevice(video::EDT_BURNINGSVIDEO, dimension2d(160, 120), 32); + if (!device) + return false; + + video::IVideoDriver* driver = device->getVideoDriver(); + ISceneManager * smgr = device->getSceneManager(); + + bool added = device->getFileSystem()->addFileArchive("../media/map-20kdm2.pk3"); + assert_log(added); + + if(added) + { + ISceneNode * node = smgr->addOctreeSceneNode(smgr->getMesh("20kdm2.bsp")->getMesh(0), 0, -1, 1024); + assert_log(node); + + if (node) + { + node->setMaterialFlag(EMF_LIGHTING, false); + node->setPosition(core::vector3df(-1300,-820,-1249)); + node->setScale(core::vector3df(1, 5, 1)); + + (void)smgr->addCameraSceneNode(0, core::vector3df(0,0,0), core::vector3df(40,100,30)); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,255,255,0)); + smgr->drawAll(); + driver->endScene(); + + result = takeScreenshotAndCompareAgainstReference(driver, "-planeMatrix-scaledClip.png"); + } + } + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + + +// Test the ability to transform a plane with a matrix. +bool planeMatrix(void) +{ + matrix4 rotationMatrix; + rotationMatrix.setRotationDegrees(vector3df(90, 0, 0)); + + matrix4 translationMatrix; + translationMatrix.setTranslation(vector3df(0, 3, 0)); + + matrix4 scaleMatrix; + scaleMatrix.setScale(vector3df(1, 2, 3)); + + bool success = true; + + matrix4 matrix = rotationMatrix; + logTestString("\nRotation matrix\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f\n", + matrix[0], matrix[1], matrix[2], matrix[3], + matrix[4], matrix[5], matrix[6], matrix[7], + matrix[8], matrix[9], matrix[10], matrix[11], + matrix[12], matrix[13], matrix[14], matrix[15]); + success &= transformPlane(vector3df(0, 0, 0), vector3df(-1, -1, 0), matrix, plane3df(vector3df(-.707f, 0.f, -.707f), 0.f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(1, 1, 0), matrix, plane3df(vector3df(.707f, 0.f, .707f), 0.f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(-1, 1, 0), matrix, plane3df(vector3df(-.707f, 0.f, .707f), 0.f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(1, -1, 0), matrix, plane3df(vector3df(.707f, 0.f, -.707f), 0.f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(-1, -1, 0), matrix, plane3df(vector3df(-.707f, 0.f, -.707f), .707f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(1, 1, 0), matrix, plane3df(vector3df(.707f, 0.f, .707f), -.707f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(-1, 1, 0), matrix, plane3df(vector3df(-.707f, 0.f, .707f), -.707f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(1, -1, 0), matrix, plane3df(vector3df(.707f, 0.f, -.707f), .707f)); + + + matrix = translationMatrix; + logTestString("\nTranslation matrix\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f\n", + matrix[0], matrix[1], matrix[2], matrix[3], + matrix[4], matrix[5], matrix[6], matrix[7], + matrix[8], matrix[9], matrix[10], matrix[11], + matrix[12], matrix[13], matrix[14], matrix[15]); + success &= transformPlane(vector3df(0, 0, 0), vector3df(-1, -1, 0), matrix, plane3df(vector3df(-0.707f,-0.707f,0.000f), 2.121f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(1, 1, 0), matrix, plane3df(vector3df(0.707f,0.707f,0.000f), -2.121f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(-1, 1, 0), matrix, plane3df(vector3df(-0.707f,0.707f,0.000f), -2.121f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(1, -1, 0), matrix, plane3df(vector3df(0.707f,-0.707f,0.000f), 2.121f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(-1, -1, 0), matrix, plane3df(vector3df(-0.707f,-0.707f,0.000f), 2.828f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(1, 1, 0), matrix, plane3df(vector3df(0.707f,0.707f,0.000f), -2.828f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(-1, 1, 0), matrix, plane3df(vector3df(-0.707f,0.707f,0.000f), -2.828f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(1, -1, 0), matrix, plane3df(vector3df(0.707f,-0.707f,0.000f), 2.828f)); + + + matrix = scaleMatrix; + logTestString("\nScale matrix\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f\n", + matrix[0], matrix[1], matrix[2], matrix[3], + matrix[4], matrix[5], matrix[6], matrix[7], + matrix[8], matrix[9], matrix[10], matrix[11], + matrix[12], matrix[13], matrix[14], matrix[15]); + success &= transformPlane(vector3df(0, 0, 0), vector3df(-1, -1, 0), matrix, plane3df(vector3df(-0.707f,-0.354f,0.000f).normalize(), -0.000f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(1, 1, 0), matrix, plane3df(vector3df(0.707f,0.354f,0.000f).normalize(), -0.000f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(-1, 1, 0), matrix, plane3df(vector3df(-0.707f,0.354f,0.000f).normalize(), -0.000f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(1, -1, 0), matrix, plane3df(vector3df(0.707f,-0.354f,0.000f).normalize(), -0.000f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(-1, -1, 0), matrix, plane3df(vector3df(-0.707f,-0.354f,0.000f).normalize(), 0.894f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(1, 1, 0), matrix, plane3df(vector3df(0.707f,0.354f,0.000f).normalize(), -0.894f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(-1, 1, 0), matrix, plane3df(vector3df(-0.707f,0.354f,0.000f).normalize(), -0.894f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(1, -1, 0), matrix, plane3df(vector3df(0.707f,-0.354f,0.000f).normalize(), 0.894f)); + + matrix = rotationMatrix * translationMatrix; + logTestString("\nRotation * translation matrix\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f\n", + matrix[0], matrix[1], matrix[2], matrix[3], + matrix[4], matrix[5], matrix[6], matrix[7], + matrix[8], matrix[9], matrix[10], matrix[11], + matrix[12], matrix[13], matrix[14], matrix[15]); + success &= transformPlane(vector3df(0, 0, 0), vector3df(-1, -1, 0), matrix, plane3df(vector3df(-0.707f,0.000f,-0.707f).normalize(), 2.121f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(1, 1, 0), matrix, plane3df(vector3df(0.707f,-0.000f,0.707f).normalize(), -2.121f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(-1, 1, 0), matrix, plane3df(vector3df(-0.707f,-0.000f,0.707f).normalize(), -2.121f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(1, -1, 0), matrix, plane3df(vector3df(0.707f,0.000f,-0.707f).normalize(), 2.121f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(-1, -1, 0), matrix, plane3df(vector3df(-0.707f,0.000f,-0.707f).normalize(), 2.828f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(1, 1, 0), matrix, plane3df(vector3df(0.707f,-0.000f,0.707f).normalize(), -2.828f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(-1, 1, 0), matrix, plane3df(vector3df(-0.707f,-0.000f,0.707f).normalize(), -2.828f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(1, -1, 0), matrix, plane3df(vector3df(0.707f,0.000f,-0.707f).normalize(), 2.828f)); + + matrix = rotationMatrix * scaleMatrix; + logTestString("\nRotation * scale matrix\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f\n", + matrix[0], matrix[1], matrix[2], matrix[3], + matrix[4], matrix[5], matrix[6], matrix[7], + matrix[8], matrix[9], matrix[10], matrix[11], + matrix[12], matrix[13], matrix[14], matrix[15]); + success &= transformPlane(vector3df(0, 0, 0), vector3df(-1, -1, 0), matrix, plane3df(vector3df(-0.707f,0.000f,-0.354f).normalize(), -0.000f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(1, 1, 0), matrix, plane3df(vector3df(0.707f,-0.000f,0.354f).normalize(), -0.000f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(-1, 1, 0), matrix, plane3df(vector3df(-0.707f,-0.000f,0.354f).normalize(), -0.000f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(1, -1, 0), matrix, plane3df(vector3df(0.707f,0.000f,-0.354f).normalize(), -0.000f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(-1, -1, 0), matrix, plane3df(vector3df(-0.707f,0.000f,-0.354f).normalize(), 0.894f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(1, 1, 0), matrix, plane3df(vector3df(0.707f,-0.000f,0.354f).normalize(), -0.894f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(-1, 1, 0), matrix, plane3df(vector3df(-0.707f,-0.000f,0.354f).normalize(), -0.894f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(1, -1, 0), matrix, plane3df(vector3df(0.707f,0.000f,-0.354f).normalize(), 0.894f)); + + matrix = translationMatrix * scaleMatrix; + logTestString("\nTranslation * scale matrix\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f\n", + matrix[0], matrix[1], matrix[2], matrix[3], + matrix[4], matrix[5], matrix[6], matrix[7], + matrix[8], matrix[9], matrix[10], matrix[11], + matrix[12], matrix[13], matrix[14], matrix[15]); + success &= transformPlane(vector3df(0, 0, 0), vector3df(-1, -1, 0), matrix, plane3df(vector3df(-0.707f,-0.354f,0.000f).normalize(), 1.3416f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(1, 1, 0), matrix, plane3df(vector3df(0.707f,0.354f,0.000f).normalize(), -1.3416f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(-1, 1, 0), matrix, plane3df(vector3df(-0.707f,0.354f,0.000f).normalize(), -1.3416f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(1, -1, 0), matrix, plane3df(vector3df(0.707f,-0.354f,0.000f).normalize(), 1.3416f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(-1, -1, 0), matrix, plane3df(vector3df(-0.707f,-0.354f,0.000f).normalize(), 2.236f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(1, 1, 0), matrix, plane3df(vector3df(0.707f,0.354f,0.000f).normalize(), -2.236f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(-1, 1, 0), matrix, plane3df(vector3df(-0.707f,0.354f,0.000f).normalize(), -2.236f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(1, -1, 0), matrix, plane3df(vector3df(0.707f,-0.354f,0.000f).normalize(), 2.236f)); + + matrix = rotationMatrix * translationMatrix * scaleMatrix; + logTestString("\nRotation * translation * scale matrix\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f" + "\n%02.02f %02.02f %02.02f %02.02f\n", + matrix[0], matrix[1], matrix[2], matrix[3], + matrix[4], matrix[5], matrix[6], matrix[7], + matrix[8], matrix[9], matrix[10], matrix[11], + matrix[12], matrix[13], matrix[14], matrix[15]); + success &= transformPlane(vector3df(0, 0, 0), vector3df(-1, -1, 0), matrix, plane3df(vector3df(-0.707f,0.000f,-0.354f).normalize(), 1.3416f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(1, 1, 0), matrix, plane3df(vector3df(0.707f,-0.000f,0.354f).normalize(), -1.3416f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(-1, 1, 0), matrix, plane3df(vector3df(-0.707f,-0.000f,0.354f).normalize(), -1.3416f)); + success &= transformPlane(vector3df(0, 0, 0), vector3df(1, -1, 0), matrix, plane3df(vector3df(0.707f,0.000f,-0.354f).normalize(), 1.3416f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(-1, -1, 0), matrix, plane3df(vector3df(-0.707f,0.000f,-0.354f).normalize(), 2.236f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(1, 1, 0), matrix, plane3df(vector3df(0.707f,-0.000f,0.354f).normalize(), -2.236f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(-1, 1, 0), matrix, plane3df(vector3df(-0.707f,-0.000f,0.354f).normalize(), -2.236f)); + success &= transformPlane(vector3df(0, 1, 0), vector3df(1, -1, 0), matrix, plane3df(vector3df(0.707f,0.000f,-0.354f).normalize(), 2.236f)); + + success &= drawScaledOctree(); + + return success; +} + diff --git a/tests/projectionMatrix.cpp b/tests/projectionMatrix.cpp new file mode 100644 index 00000000..439d8e82 --- /dev/null +++ b/tests/projectionMatrix.cpp @@ -0,0 +1,86 @@ +// Copyright (C) 2008-2012 Christian Stehno, Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +//! Tests projection matrices +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(); + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + bool result = true; + + driver->beginScene(video::ECBF_COLOR, SColor(255,0,0,0)); + + SMaterial mat; + mat.MaterialType = EMT_SOLID; + mat.Lighting = false; + mat.ZBuffer = false; + mat.ZWriteEnable = video::EZW_OFF; + mat.Thickness = 1; + + driver->setMaterial(mat); + + core::dimension2d dims(driver->getCurrentRenderTargetSize()); + //apply custom projection, no offset + core::matrix4 pmtx = matrix4().buildProjectionMatrixOrthoLH(dims.Width, dims.Height, 0, 100); + driver->setTransform(ETS_PROJECTION, pmtx); + driver->setTransform(ETS_VIEW, matrix4()); + driver->setTransform(ETS_WORLD, matrix4()); + + //the red cross appears at center + for (u32 i=0; i<10; ++i) + { + driver->draw3DLine(vector3df(0.f+i,-50.f,1.f), vector3df(0.f+i,50.f,1.f), SColor(255,255,0,0)); + driver->draw3DLine(vector3df(-50.f,0.f+i,1.f), vector3df(50.f,0.f+i,1.f), SColor(255,255,0,0)); + } + + //apply custom projection, offset to right-top + pmtx.setTranslation(vector3df(0.7f, 0.7f, 0.f)); + driver->setTransform(ETS_PROJECTION, pmtx); + driver->setTransform(ETS_VIEW, matrix4()); + driver->setTransform(ETS_WORLD, matrix4()); + + //The green cross must be in right-top corner. But for OpenGL driver it is in left-top corner + for (u32 i=0; i<10; ++i) + { + driver->draw3DLine(vector3df(0.f+i,-50,1), vector3df(0.f+i,50,1), SColor(255,0,255,0)); + driver->draw3DLine(vector3df(-50,0.f+i,1), vector3df(50,0.f+i,1), SColor(255,0,255,0)); + } + + driver->endScene(); + + result = takeScreenshotAndCompareAgainstReference(driver, "-projMat.png", 98.71f); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + + +bool projectionMatrix(void) +{ + bool result = true; + + // TODO: Seems that software driver does not handle this projection matrix + TestWithAllDrivers(runTestWithDriver); + + return result; +} diff --git a/tests/removeCustomAnimator.cpp b/tests/removeCustomAnimator.cpp new file mode 100644 index 00000000..9a69e00b --- /dev/null +++ b/tests/removeCustomAnimator.cpp @@ -0,0 +1,52 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace scene; + +class CustomAnimator : public ISceneNodeAnimator +{ + void animateNode(ISceneNode* node, u32 timeMs) + { + // Check that I can remove myself from my node durings its animateNode() loop. + node->removeAnimator(this); + } + + ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0) { return 0 ; } +}; + + +/** Test that a custom animator can remove itself cleanly from an ISceneNode during its + * own animateNode() loop. + * http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=32271 */ +bool removeCustomAnimator(void) +{ + IrrlichtDevice * device = irr::createDevice(video::EDT_NULL, dimension2du(160, 120)); + assert_log(device); + if(!device) + return false; + + ISceneManager * smgr = device->getSceneManager(); + + ISceneNode * node = smgr->addEmptySceneNode(); + CustomAnimator * instantlyElapsing1 = new CustomAnimator(); + CustomAnimator * instantlyElapsing2 = new CustomAnimator(); + node->addAnimator(instantlyElapsing1); + node->addAnimator(instantlyElapsing2); + + // This should result in both custom animators being removed and + // deleted cleanly, without a crash. + node->OnAnimate(0); + + device->closeDevice(); + device->run(); + device->drop(); + + // If we didn't crash, then the test passed. + return true; +} + + diff --git a/tests/renderTargetTexture.cpp b/tests/renderTargetTexture.cpp new file mode 100644 index 00000000..24d15d0d --- /dev/null +++ b/tests/renderTargetTexture.cpp @@ -0,0 +1,604 @@ +// Copyright (C) 2008-2012 Christian Stehno, Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; + +//! Tests rendering RTTs with draw2DImage +/** This test is very special in its setup, problematic situation was found by stefbuet. */ +static bool testWith2DImage(video::E_DRIVER_TYPE driverType) +{ + IrrlichtDevice *device = createDevice(driverType, core::dimension2d (256, 128)); + if (!device) + return true; // No error if device does not exist + + video::IVideoDriver *driver = device->getVideoDriver (); + scene::ISceneManager *smgr = device->getSceneManager (); + + if (!driver->queryFeature(video::EVDF_RENDER_TO_TARGET)) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + video::ITexture *image = driver->getTexture ("../media/irrlichtlogo2.png"); + video::ITexture *RTT_texture = driver->addRenderTargetTexture (core::dimension2d < u32 > (256, 128)); + + smgr->addCameraSceneNode (0, core::vector3df (100, 100, 100), + core::vector3df (0, 0, 0)); + + /*to reproduce the bug : + -draw the image : it's normal + -apply an RTT texture to a model + -remove the model + -draw the image again : it's flipped + */ + + video::SColor colors[4]={0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}; + //draw the image : + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor (255, 200, 200, 200)); + driver->draw2DImage (image, + core::rect < s32 > + (64 - image->getSize ().Width / 2, + 64 - image->getSize ().Height / 2, + 64 + image->getSize ().Width / 2, + 64 + image->getSize ().Height / 2), + core::rect < s32 > (0, 0, image->getSize ().Width, + image->getSize ().Height), 0, colors, + true); + driver->endScene (); + + //then create a model and apply to it the RTT Texture + //rendering the model is important, if not rendered 1 time, bug won't appear. + //after the render, we remove the node : important, if not done, bug won't appear too. + scene::IMesh *modelMesh = smgr->getMesh ("../media/earth.x"); + scene::ISceneNode *modelNode = smgr->addMeshSceneNode(modelMesh); + modelNode->setMaterialTexture (0, RTT_texture); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor (255, 200, 200, 200)); + smgr->drawAll(); + driver->endScene(); + + modelNode->remove(); + + //then we render the image normaly + //it's now fliped... + for (u32 i=0; i<10; ++i) + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor (255, 200, 200, 200)); + + //draw img + driver->draw2DImage (image, + core::rect < s32 > + (64 - image->getSize ().Width / 2, + 64 - image->getSize ().Height / 2, + 64 + image->getSize ().Width / 2, + 64 + image->getSize ().Height / 2), + core::rect < s32 > (0, 0, image->getSize ().Width, + image->getSize ().Height), 0, + colors, true); + + //call this is important : + //if not called, the bug won't appear + smgr->drawAll(); + + driver->endScene(); + } + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-rttWith2DImage.png", 99.9f); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + + +bool rttAndZBuffer(video::E_DRIVER_TYPE driverType) +{ + SIrrlichtCreationParameters cp; + cp.WindowSize.set(160,120); + cp.Bits = 32; + cp.AntiAlias = 4; + cp.DriverType = driverType; + + IrrlichtDevice* nullDevice = createDevice(video::EDT_NULL); + cp.WindowSize = nullDevice->getVideoModeList()->getDesktopResolution(); + nullDevice->closeDevice(); + nullDevice->run(); + nullDevice->drop(); + + cp.WindowSize -= core::dimension2d(100, 100); + + IrrlichtDevice* device = createDeviceEx(cp); + if (!device) + return true; + + video::IVideoDriver* vd = device->getVideoDriver(); + scene::ISceneManager* sm = device->getSceneManager(); + + if (!vd->queryFeature(video::EVDF_RENDER_TO_TARGET)) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + stabilizeScreenBackground(vd); + + logTestString("Testing driver %ls\n", vd->getName()); + + video::ITexture* renderTargetTex = vd->addRenderTargetTexture(cp.WindowSize, "rt", video::ECF_A32B32G32R32F); + video::ITexture* renderTargetDepth = vd->addRenderTargetTexture(cp.WindowSize, "rtd", video::ECF_D16); + + video::IRenderTarget* renderTarget = vd->addRenderTarget(); + renderTarget->setTexture(renderTargetTex, renderTargetDepth); + + video::S3DVertex vertices[4]; + vertices[0].Pos.Z = vertices[1].Pos.Z = vertices[2].Pos.Z = vertices[3].Pos.Z = 1.0f; + vertices[0].Pos.Y = vertices[1].Pos.Y = 1.0f; + vertices[2].Pos.Y = vertices[3].Pos.Y = -1.0f; + vertices[0].Pos.X = vertices[3].Pos.X = -1.0f; + vertices[1].Pos.X = vertices[2].Pos.X = 1.0f; + vertices[0].TCoords.Y = vertices[1].TCoords.Y = 0.0f; + vertices[2].TCoords.Y = vertices[3].TCoords.Y = 1.0f; + vertices[0].TCoords.X = vertices[3].TCoords.X = 1.0f; + vertices[1].TCoords.X = vertices[2].TCoords.X = 0.0f; + + u16 indices[6] = {0, 1, 3, 1, 2, 3}; + + video::SMaterial rtMat; + rtMat.BackfaceCulling = false; + rtMat.Lighting = false; + rtMat.TextureLayer[0].TextureWrapU = + rtMat.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE; + + sm->addLightSceneNode(NULL, core::vector3df(0, 50, 0), + video::SColorf(1, 1, 1), 100); + + sm->addCameraSceneNode(NULL, core::vector3df(0, 10, 0)); + + const scene::IGeometryCreator* geom = sm->getGeometryCreator(); + scene::IMeshManipulator* manip = sm->getMeshManipulator(); + scene::IMesh* mesh; + scene::ISceneNode* node; + + mesh = geom->createCubeMesh(core::vector3df(10, 10, 10)); + manip->setVertexColors(mesh, video::SColor(255, 0, 0, 255)); + node = sm->addMeshSceneNode(mesh, NULL, -1, core::vector3df(0, 0, 30)); + node->getMaterial(0).EmissiveColor = video::SColor(255, 0, 0, 30); + mesh->drop(); + + mesh = geom->createSphereMesh(5.0f, 32, 32); + node = sm->addMeshSceneNode(mesh, NULL, -1, core::vector3df(0, 0, 50)); + node->getMaterial(0).EmissiveColor = video::SColor(255, 30, 30, 30); + mesh->drop(); + + mesh = geom->createConeMesh(5.0f, 10.0f, 32, video::SColor(255, 255, 0, 0), video::SColor(255, 255, 0, 0)); + node = sm->addMeshSceneNode(mesh, NULL, -1, core::vector3df(0, 0, 70)); + node->getMaterial(0).EmissiveColor = video::SColor(255, 30, 0, 0); + mesh->drop(); + + { + vd->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255, 0, 0, 0)); + vd->setRenderTargetEx(renderTarget, video::ECBF_COLOR | video::ECBF_DEPTH); + sm->drawAll(); + vd->setRenderTargetEx(0, 0, 0); + vd->setTransform(video::ETS_WORLD, core::IdentityMatrix); + vd->setTransform(video::ETS_VIEW, core::IdentityMatrix); + vd->setTransform(video::ETS_PROJECTION, core::IdentityMatrix); + rtMat.setTexture(0, renderTargetTex); + vd->setMaterial(rtMat); + vd->drawIndexedTriangleList(vertices, 4, indices, 2); + vd->endScene(); + } + bool result = takeScreenshotAndCompareAgainstReference(vd, "-rttAndZBuffer.png"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + + +// result should be two times the same blind text on the left side, and +// the fireball image (with a very small text inside) in the middle of the screen +// drivers that don't support image scaling will show a pink background instead +bool rttAndText(video::E_DRIVER_TYPE driverType) +{ + IrrlichtDevice* device = createDevice(driverType, core::dimension2d(160, 120)); + if (!device) + return true; + + video::IVideoDriver* driver = device->getVideoDriver(); + gui::IGUIEnvironment* guienv = device->getGUIEnvironment(); + + if (!driver->queryFeature(video::EVDF_RENDER_TO_TARGET)) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + logTestString("Testing driver %ls\n", driver->getName()); + + //RTT + video::ITexture* renderTargetTex = driver->addRenderTargetTexture(core::dimension2d(256, 256), "rt"); + video::ITexture* renderTargetDepth = driver->addRenderTargetTexture(core::dimension2d(256, 256), "rtd", video::ECF_D16); + + video::IRenderTarget* renderTarget = driver->addRenderTarget(); + renderTarget->setTexture(renderTargetTex, renderTargetDepth); + + stabilizeScreenBackground(driver); + + driver->beginScene(0, video::SColor(255,255, 255, 255)); + driver->setRenderTargetEx(renderTarget, video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,255,0,255)); + driver->draw2DImage(driver->getTexture("../media/fireball.bmp"), core::recti(0, 0, renderTargetTex->getSize().Width, renderTargetTex->getSize().Height), core::recti(0, 0, 64, 64)); + guienv->getBuiltInFont()->draw(L"OMGGG =!", core::rect(120, 100, 256, 256), video::SColor(255, 0, 0, 255)); + driver->setRenderTargetEx(0, 0, 0); + driver->endScene(); + + scene::ISceneManager* smgr = device->getSceneManager(); + + scene::ISceneNode* cube = smgr->addCubeSceneNode(20); + cube->setMaterialFlag(video::EMF_LIGHTING, false); + cube->setMaterialTexture(0, renderTargetTex); // set material of cube to render target + + smgr->addCameraSceneNode(0, core::vector3df(0, 0, -30)); + + // create a long text to produce much difference in failing result pictures + gui::IGUIStaticText* text = guienv->addStaticText(L"asdddddddoamgmoasmgom\nfoaomsodommogdd\nddddddddd", core::rect(10, 20, 100, 160)); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,255, 255, 255)); + cube->setVisible(false); + smgr->drawAll(); + guienv->drawAll(); + + cube->setVisible(true); + smgr->drawAll(); + video::SMaterial mat(cube->getMaterial(0)); + driver->setMaterial(mat); + text->setRelativePosition(core::position2di(10,30)); + guienv->drawAll(); + + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-rttAndText.png"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +static void Render(IrrlichtDevice* device, video::IRenderTarget* rt, core::vector3df& pos1, + core::vector3df& pos2, scene::IAnimatedMesh* sphereMesh, core::vector3df& pos3, core::vector3df& pos4) +{ + video::IVideoDriver* driver = device->getVideoDriver(); + driver->setRenderTargetEx(rt, video::ECBF_COLOR | video::ECBF_DEPTH); + device->getSceneManager()->drawAll(); + + video::SMaterial mat; + mat.ColorMaterial=video::ECM_NONE; + mat.AmbientColor.set(255, 80, 80, 80); + mat.DiffuseColor.set(255, 120, 30, 210); + mat.SpecularColor.set(255,80,80,80); + mat.Shininess = 8.f; + + core::matrix4 m; + m.setTranslation(pos1); + driver->setTransform(video::ETS_WORLD, m); + driver->setMaterial(mat); + driver->drawMeshBuffer(sphereMesh->getMeshBuffer(0)); + + m.setTranslation(pos2); + mat.Shininess=0.f; + driver->setTransform(video::ETS_WORLD, m); + driver->setMaterial(mat); + driver->drawMeshBuffer(sphereMesh->getMeshBuffer(0)); + + m.setTranslation(pos3); + mat.Shininess=8.f; + driver->setTransform(video::ETS_WORLD, m); + driver->setMaterial(mat); + driver->drawMeshBuffer(sphereMesh->getMeshBuffer(0)); + + m.setTranslation(pos4); + mat.Shininess=0.f; + driver->setTransform(video::ETS_WORLD, m); + driver->setMaterial(mat); + driver->drawMeshBuffer(sphereMesh->getMeshBuffer(0)); +} + +bool rttAndAntiAliasing(video::E_DRIVER_TYPE driverType) +{ + SIrrlichtCreationParameters cp; + cp.DriverType = driverType; + cp.WindowSize = core::dimension2di(160, 120); + cp.AntiAlias = 2; + cp.Vsync = true; + + IrrlichtDevice* device = createDeviceEx(cp); + if (!device) + return true; + + video::IVideoDriver* driver = device->getVideoDriver(); + if ((driver->getDriverAttributes().getAttributeAsInt("AntiAlias")<2) || + (!driver->queryFeature(video::EVDF_RENDER_TO_TARGET))) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + // sphere mesh + scene::IAnimatedMesh* sphereMesh = device->getSceneManager()->addSphereMesh("atom", 1, 32, 32); + + // cam + scene::ICameraSceneNode* cam = device->getSceneManager()->addCameraSceneNode(NULL, core::vector3df(0, 1, -5), core::vector3df(0, 0, 0)); + cam->setNearValue(0.01f); + cam->setFarValue(100.f); + cam->updateAbsolutePosition(); + device->getSceneManager()->setActiveCamera(cam); + device->getSceneManager()->addLightSceneNode(0, core::vector3df(10,10,10)); + device->getSceneManager()->setAmbientLight(video::SColorf(0.3f,0.3f,0.3f)); + + float radius = 3.f; + core::vector3df pos1(-radius,0,0); + core::vector3df pos2(radius,0,0); + core::vector3df pos3(0,0,radius); + core::vector3df pos4(0,0,-radius); + core::matrix4 m; + + gui::IGUIStaticText* st = device->getGUIEnvironment()->addStaticText(L"", core::recti(0,0,200,20), false, false); + st->setOverrideColor(video::SColor(255,255,255,0)); + + core::dimension2du dim_txt = core::dimension2du(160/2, 120/2); + + video::ITexture* renderTargetTex1 = driver->addRenderTargetTexture(dim_txt, "rt1", device->getColorFormat()); + video::ITexture* renderTargetTex2 = driver->addRenderTargetTexture(dim_txt, "rt2", device->getColorFormat()); + video::ITexture* renderTargetTex3 = driver->addRenderTargetTexture(dim_txt, "rt3", video::ECF_A8R8G8B8); + video::ITexture* renderTargetTex4 = driver->addRenderTargetTexture(dim_txt, "rt4", device->getColorFormat()); + video::ITexture* renderTargetDepth = driver->addRenderTargetTexture(dim_txt, "rtd", video::ECF_D16); + + video::IRenderTarget* renderTarget1 = driver->addRenderTarget(); + renderTarget1->setTexture(renderTargetTex1, renderTargetDepth); + + video::IRenderTarget* renderTarget2 = driver->addRenderTarget(); + renderTarget2->setTexture(renderTargetTex2, renderTargetDepth); + + video::IRenderTarget* renderTarget3 = driver->addRenderTarget(); + renderTarget3->setTexture(renderTargetTex3, renderTargetDepth); + + video::IRenderTarget* renderTarget4 = driver->addRenderTarget(); + renderTarget4->setTexture(renderTargetTex4, renderTargetDepth); + + device->getSceneManager()->setActiveCamera(cam); + device->getVideoDriver()->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,0,0,0)); +#if 1 + st->setText(L"Texture Rendering"); + Render(device, renderTarget1, pos1, pos2, sphereMesh, pos3, pos4); + + Render(device, renderTarget2, pos1, pos2, sphereMesh, pos3, pos4); + Render(device, renderTarget3, pos1, pos2, sphereMesh, pos3, pos4); + Render(device, renderTarget4, pos1, pos2, sphereMesh, pos3, pos4); + + device->getVideoDriver()->setRenderTargetEx(0, video::ECBF_COLOR | video::ECBF_DEPTH); + device->getVideoDriver()->draw2DImage(renderTargetTex1, core::position2di(0, 0)); + device->getVideoDriver()->draw2DImage(renderTargetTex2, core::position2di(80, 0)); + device->getVideoDriver()->draw2DImage(renderTargetTex3, core::position2di(0, 60)); + device->getVideoDriver()->draw2DImage(renderTargetTex4, core::position2di(80, 60)); +#else + ITexture* rt0 = NULL; + Render(device, rt0, pos1, pos2, sphereMesh, pos3, pos4); +#endif + st->draw(); + device->getVideoDriver()->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-rttAndAntiAlias.png", 98.25f); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +bool rttFormats(video::E_DRIVER_TYPE driverType) +{ + SIrrlichtCreationParameters cp; + cp.DriverType = driverType; + cp.WindowSize = core::dimension2di(160, 120); + + IrrlichtDevice* device = createDeviceEx(cp); + if (!device) + return true; + + video::IVideoDriver* driver = device->getVideoDriver(); + + logTestString("Testing driver %ls\n", driver->getName()); + + video::ITexture* tex = 0; + + { + tex = device->getVideoDriver()->addRenderTargetTexture(core::dimension2du(256,256), "rt", video::ECF_A1R5G5B5); + if (tex) + { + if (tex->getColorFormat() != video::ECF_A1R5G5B5) + logTestString("Format changed: ECF_A1R5G5B5 to %x\n", tex->getColorFormat()); + else + logTestString("Format supported: ECF_A1R5G5B5\n"); + driver->removeTexture(tex); + tex=0; + } + else + logTestString("Format unsupported: ECF_A1R5G5B5\n"); + } + { + tex = device->getVideoDriver()->addRenderTargetTexture(core::dimension2du(256,256), "rt", video::ECF_R5G6B5); + if (tex) + { + if (tex->getColorFormat() != video::ECF_R5G6B5) + logTestString("Format changed: ECF_R5G6B5 to %x\n", tex->getColorFormat()); + else + logTestString("Format supported: ECF_R5G6B5\n"); + driver->removeTexture(tex); + tex=0; + } + else + logTestString("Format unsupported: ECF_R5G6B5\n"); + } + { + tex = device->getVideoDriver()->addRenderTargetTexture(core::dimension2du(256,256), "rt", video::ECF_R8G8B8); + if (tex) + { + if (tex->getColorFormat() != video::ECF_R8G8B8) + logTestString("Format changed: ECF_R8G8B8 to %x\n", tex->getColorFormat()); + else + logTestString("Format supported: ECF_R8G8B8\n"); + driver->removeTexture(tex); + tex=0; + } + else + logTestString("Format unsupported: ECF_R8G8B8\n"); + } + { + tex = device->getVideoDriver()->addRenderTargetTexture(core::dimension2du(256,256), "rt", video::ECF_A8R8G8B8); + if (tex) + { + if (tex->getColorFormat() != video::ECF_A8R8G8B8) + logTestString("Format changed: ECF_A8R8G8B8 to %x\n", tex->getColorFormat()); + else + logTestString("Format supported: ECF_A8R8G8B8\n"); + driver->removeTexture(tex); + tex=0; + } + else + logTestString("Format unsupported: ECF_A8R8G8B8\n"); + } + { + tex = device->getVideoDriver()->addRenderTargetTexture(core::dimension2du(256,256), "rt", video::ECF_R16F); + if (tex) + { + if (tex->getColorFormat() != video::ECF_R16F) + logTestString("Format changed: ECF_R16F to %x\n", tex->getColorFormat()); + else + logTestString("Format supported: ECF_R16F\n"); + driver->removeTexture(tex); + tex=0; + } + else + logTestString("Format unsupported: ECF_R16F\n"); + } + { + tex = device->getVideoDriver()->addRenderTargetTexture(core::dimension2du(256,256), "rt", video::ECF_G16R16F); + if (tex) + { + if (tex->getColorFormat() != video::ECF_G16R16F) + logTestString("Format changed: ECF_G16R16F to %x\n", tex->getColorFormat()); + else + logTestString("Format supported: ECF_G16R16F\n"); + driver->removeTexture(tex); + tex=0; + } + else + logTestString("Format unsupported: ECF_G16R16F\n"); + } + { + tex = device->getVideoDriver()->addRenderTargetTexture(core::dimension2du(256,256), "rt", video::ECF_A16B16G16R16F); + if (tex) + { + if (tex->getColorFormat() != video::ECF_A16B16G16R16F) + logTestString("Format changed: ECF_A16B16G16R16F to %x\n", tex->getColorFormat()); + else + logTestString("Format supported: ECF_A16B16G16R16F\n"); + driver->removeTexture(tex); + tex=0; + } + else + logTestString("Format unsupported: ECF_A16B16G16R16F\n"); + } + { + tex = device->getVideoDriver()->addRenderTargetTexture(core::dimension2du(256,256), "rt", video::ECF_R32F); + if (tex) + { + if (tex->getColorFormat() != video::ECF_R32F) + logTestString("Format changed: ECF_R32F to %x\n", tex->getColorFormat()); + else + logTestString("Format supported: ECF_R32F\n"); + driver->removeTexture(tex); + tex=0; + } + else + logTestString("Format unsupported: ECF_R32F\n"); + } + { + tex = device->getVideoDriver()->addRenderTargetTexture(core::dimension2du(256,256), "rt", video::ECF_G32R32F); + if (tex) + { + if (tex->getColorFormat() != video::ECF_G32R32F) + logTestString("Format changed: ECF_G32R32F to %x\n", tex->getColorFormat()); + else + logTestString("Format supported: ECF_G32R32F\n"); + driver->removeTexture(tex); + tex=0; + } + else + logTestString("Format unsupported: ECF_G32R32F\n"); + } + { + tex = device->getVideoDriver()->addRenderTargetTexture(core::dimension2du(256,256), "rt", video::ECF_A32B32G32R32F); + if (tex) + { + if (tex->getColorFormat() != video::ECF_A32B32G32R32F) + logTestString("Format changed: ECF_A32B32G32R32F to %x\n", tex->getColorFormat()); + else + logTestString("Format supported: ECF_A32B32G32R32F\n"); + driver->removeTexture(tex); + tex=0; + } + else + logTestString("Format unsupported: ECF_A32B32G32R32F\n"); + } + + device->closeDevice(); + device->run(); + device->drop(); + + return true; +} + +bool renderTargetTexture(void) +{ + bool result = true; + + TestWithAllDrivers(testWith2DImage); + +#if 0 + TestWithAllDrivers(rttAndZBuffer); +#endif + + TestWithAllDrivers(rttAndAntiAliasing); + TestWithAllDrivers(rttAndText); + + logTestString("Test RTT format support\n"); + TestWithAllHWDrivers(rttFormats); + + return result; +} diff --git a/tests/sceneCollisionManager.cpp b/tests/sceneCollisionManager.cpp new file mode 100644 index 00000000..93bccf00 --- /dev/null +++ b/tests/sceneCollisionManager.cpp @@ -0,0 +1,471 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; + +static bool testGetCollisionResultPosition(IrrlichtDevice * device, + ISceneManager * smgr, + ISceneCollisionManager * collMgr) +{ + IMeshSceneNode * cubeNode = smgr->addCubeSceneNode(10.f); + ITriangleSelector * cubeSelector = smgr->createTriangleSelectorFromBoundingBox(cubeNode); + + triangle3df triOut; + vector3df hitPosition; + bool falling; + ISceneNode* hitNode; + + vector3df resultPosition = + collMgr->getCollisionResultPosition(cubeSelector, + 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"); + result = false; + } + + if(!equals(resultPosition.Y, 25.f, 0.01f)) + { + logTestString("Unexpected collision response position\n"); + result = false; + } + + if(!equals(hitPosition.Y, 5.f, 0.01f)) + { + logTestString("Unexpected collision position\n"); + result = false; + } + + resultPosition = + collMgr->getCollisionResultPosition(cubeSelector, + vector3df(-20, 0, 0), + vector3df(10, 20, 10), + vector3df(100, 0, 0), + triOut, + hitPosition, + falling, + hitNode); + + if(hitNode != cubeNode) + { + logTestString("Unexpected collision node\n"); + result = false; + } + + if(!equals(resultPosition.X, -15.f, 0.01f)) + { + logTestString("Unexpected collision response position\n"); + result = false; + } + + if(!equals(hitPosition.X, -5.f, 0.01f)) + { + logTestString("Unexpected collision position\n"); + result = false; + } + + assert_log(result); + + cubeSelector->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; + 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; + } + + smgr->clear(); + + 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. + + 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; + } + + + // Now verify bitmasking + + // Test the 01010101010101010101010101010101 bitmask (0x55555555) + cubeNode1->setVisible(true); + cubeNode1->setID(0xAAAAAAAA); + hitNode = collMgr->getSceneNodeFromScreenCoordinatesBB(position2d(80, 60), 0x55555555); + if(hitNode != cubeNode2) + { + logTestString("Unexpected node hit. Expected cubeNode2.\n"); + result = false; + } + assert_log(result); + + smgr->clear(); + + 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 middle (scaled) target.\n"); + + assert_log(result); + + smgr->clear(); + + return result; +} + + +// box intersection according to Kay et al., code from gamedev.net +static bool IntersectBox(const core::vector3df& origin, const core::vector3df& dir, const core::aabbox3df& box) +{ + core::vector3df minDist = (box.MinEdge - origin)/dir; + core::vector3df maxDist = (box.MaxEdge - origin)/dir; + + core::vector3df realMin(core::min_(minDist.X, maxDist.X),core::min_(minDist.Y, maxDist.Y),core::min_(minDist.Z, maxDist.Z)); + core::vector3df realMax(core::max_(minDist.X, maxDist.X),core::max_(minDist.Y, maxDist.Y),core::max_(minDist.Z, maxDist.Z)); + + f32 minmax = core::min_(realMax.X, realMax.Y, realMax.Z); + // nearest distance to intersection + f32 maxmin = core::max_(realMin.X, realMin.Y, realMin.Z); + + return (maxmin >=0 && minmax >= maxmin); +} + +static bool checkBBoxIntersection(IrrlichtDevice * device, + ISceneManager * smgr) +{ + video::IVideoDriver* driver = device->getVideoDriver(); + + // add camera + scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(); + camera->setPosition(core::vector3df(30, 30, 30)); + camera->setTarget(core::vector3df(8.f, 8.f, 8.f)); + camera->setID(0); + + // add a cube to pick + scene::ISceneNode* cube = smgr->addCubeSceneNode(30, 0, -1, core::vector3df(0,0,0),core::vector3df(30,40,50)); + + bool result=true; + for (u32 round=0; round<2; ++round) + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(100, 50, 50, 100)); + smgr->drawAll(); + driver->endScene(); + + core::matrix4 invMat = cube->getAbsoluteTransformation(); + invMat.makeInverse(); + + s32 hits=0; + u32 start = device->getTimer()->getRealTime(); + for (u32 i=10; i<150; ++i) + { + for (u32 j=10; j<110; ++j) + { + const core::position2di pos(i, j); + + // get the line used for picking + core::line3df ray = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(pos, camera); + + invMat.transformVect(ray.start); + invMat.transformVect(ray.end); + + hits += (cube->getBoundingBox().intersectsWithLine(ray)?1:0); + } + } + u32 duration = device->getTimer()->getRealTime()-start; + logTestString("bbox intersection checks %d hits (of 14000).\n", hits); + hits = -hits; + + start = device->getTimer()->getRealTime(); + for (u32 i=10; i<150; ++i) + { + for (u32 j=10; j<110; ++j) + { + const core::position2di pos(i, j); + + // get the line used for picking + core::line3df ray = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(pos, camera); + + invMat.transformVect(ray.start); + invMat.transformVect(ray.end); + + hits += (IntersectBox(ray.start, (ray.end-ray.start).normalize(), cube->getBoundingBox())?1:0); + } + } + u32 duration2 = device->getTimer()->getRealTime()-start; + logTestString("bbox intersection resulted in %d misses at a speed of %d (old) compared to %d (new).\n", abs(hits), duration, duration2); + if (duration>(duration2*1.2f)) + logTestString("Consider replacement of bbox intersection test.\n"); + + result &= (hits==0); + assert_log(result); + // second round without any hits, so check opposite direction + camera->setTarget(core::vector3df(80.f, 80.f, 80.f)); + } + + ISceneNode* node = smgr->addSphereSceneNode(5.f, 16, 0, -1, core::vector3df(0, 0, 1), core::vector3df(), core::vector3df(0.3f, 0.3f, 0.3f)); + cube->remove(); + cube = smgr->addCubeSceneNode(10.f, 0, -1, core::vector3df(0, 6.5f, 1), core::vector3df(), core::vector3df(10, 0.1f, 1.f)); + camera->setPosition(core::vector3df(0, 0, 10)); + camera->setTarget(core::vector3df()); + + u32 count=0; + for (u32 i=0; i<30; ++i) + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(100, 50, 50, 100)); + smgr->drawAll(); + driver->endScene(); + + count += node->getTransformedBoundingBox().intersectsWithBox(cube->getTransformedBoundingBox())?1:0; + node->setPosition(node->getPosition()+core::vector3df(.5f,.5f,0)); + if (i==8 && count != 0) + result=false; + if (i==17 && count != 9) + result=false; + } + if (count != 9) + result=false; + + smgr->clear(); + + return result; +} + + +static bool compareGetSceneNodeFromRayBBWithBBIntersectsWithLine(IrrlichtDevice * device, + ISceneManager * smgr, + ISceneCollisionManager * collMgr) +{ + video::IVideoDriver* driver = device->getVideoDriver(); + + // add camera + scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(); + camera->setPosition(core::vector3df(30, 30, 30)); + camera->setTarget(core::vector3df(-8.f, 8.f, -8.f)); + camera->setID(0); + + // add a dynamic light (this causes weirdness) + smgr->addLightSceneNode(0, core::vector3df(4, 4, 4), video::SColorf(.2f, .3f, .2f)); + + // add a cube to pick + scene::ISceneNode* cube = smgr->addCubeSceneNode(15); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(100, 50, 50, 100)); + smgr->drawAll(); + driver->endScene(); + + core::matrix4 invMat = cube->getAbsoluteTransformation(); + invMat.makeInverse(); + + bool result = true; + for (u32 i=76; i<82; ++i) + { + for (u32 j=56; j<64; ++j) + { + const core::position2di pos(i, j); + + // get the line used for picking + core::line3df ray = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(pos, camera); + + // find a selected node + scene::ISceneNode* pick = smgr->getSceneCollisionManager()->getSceneNodeFromRayBB(ray, 1); + + invMat.transformVect(ray.start); + invMat.transformVect(ray.end); + + const int a_hit = (pick == cube); + const int b_hit = cube->getBoundingBox().intersectsWithLine(ray); + result = (a_hit==b_hit); + } + } + + assert_log(result); + + smgr->clear(); + + return result; +} + + +/** Test functionality of the sceneCollisionManager */ +bool sceneCollisionManager(void) +{ + IrrlichtDevice * device = irr::createDevice(video::EDT_NULL, dimension2d(160, 120)); + assert_log(device); + if(!device) + return false; + + ISceneManager * smgr = device->getSceneManager(); + ISceneCollisionManager * collMgr = smgr->getSceneCollisionManager(); + + bool result = testGetCollisionResultPosition(device, smgr, collMgr); + + smgr->clear(); + + result &= testGetSceneNodeFromScreenCoordinatesBB(device, smgr, collMgr); + + result &= getScaledPickedNodeBB(device, smgr, collMgr); + + result &= getCollisionPoint_ignoreTriangleVertices(device, smgr, collMgr); + + result &= checkBBoxIntersection(device, smgr); + + result &= compareGetSceneNodeFromRayBBWithBBIntersectsWithLine(device, smgr, collMgr); + + device->closeDevice(); + device->run(); + device->drop(); + return result; +} diff --git a/tests/sceneNodeAnimator.cpp b/tests/sceneNodeAnimator.cpp new file mode 100644 index 00000000..1016f4e4 --- /dev/null +++ b/tests/sceneNodeAnimator.cpp @@ -0,0 +1,117 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +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_log(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->closeDevice(); + device->run(); + device->drop(); + + if(!result) + { + logTestString("One or more animators has a bad hasFinished() state\n."); + assert_log(false); + } + + return result; +} + + diff --git a/tests/screenshot.cpp b/tests/screenshot.cpp new file mode 100644 index 00000000..51f31489 --- /dev/null +++ b/tests/screenshot.cpp @@ -0,0 +1,83 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; + + + +// Tests screenshots features +bool testShots(video::E_DRIVER_TYPE type) +{ + IrrlichtDevice *device = createDevice(type, core::dimension2d(160, 120), 32); + if (!device) + return true; + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager * smgr = device->getSceneManager(); + + logTestString("Testing driver %ls\n", driver->getName()); + + scene::IAnimatedMesh* mesh = smgr->getMesh("../media/sydney.md2"); + scene::IAnimatedMeshSceneNode* node; + + if (!mesh) + return false; + node = smgr->addAnimatedMeshSceneNode(mesh); + if (!node) + return false; + + stabilizeScreenBackground(driver); + + node->setPosition(core::vector3df(20, 0, 30)); + node->setMaterialFlag(video::EMF_LIGHTING, false); + node->setMaterialTexture(0, driver->getTexture("../media/sydney.bmp")); + node->setLoopMode(false); + + smgr->addCameraSceneNode(); + + node->setMD2Animation(scene::EMAT_DEATH_FALLBACK); + node->setCurrentFrame((f32)(node->getEndFrame())); + node->setAnimationSpeed(0); + + device->run(); + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255, 255, 255, 0)); + smgr->drawAll(); + driver->endScene(); + + for (s32 i=0; icreateScreenShot((video::ECOLOR_FORMAT)i); + logTestString("Color Format %d %ssupported\n", i, (img && img->getColorFormat() == i)?"":"un"); + +#if 0 // Enable for a quick check while testing. + // If someone adds comparison images please use another scene without animation + // and maybe a texture using the full color spectrum. + if ( img ) + { + irr::core::stringc screenshotFilename = "results/"; + screenshotFilename += shortDriverName(driver); + screenshotFilename += "screenshot"; + screenshotFilename += core::stringc(i); + screenshotFilename += ".png"; + driver->writeImageToFile(img, screenshotFilename.c_str()); + } +#endif + + if (img) + img->drop(); + } + device->closeDevice(); + device->run(); + device->drop(); + + return true; +} + +bool screenshot() +{ + bool result = true; + TestWithAllHWDrivers(testShots); + return result; +} diff --git a/tests/serializeAttributes.cpp b/tests/serializeAttributes.cpp new file mode 100644 index 00000000..220666ac --- /dev/null +++ b/tests/serializeAttributes.cpp @@ -0,0 +1,378 @@ +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace io; + +#define COMPARE(a, b) if ( (a) != (b) ) { logTestString("Not identical %s in %s:%d\n", #a, __FILE__, __LINE__ ); return false; } + +const u32 BINARY_BLOCK_SIZE = 10; + +enum EMockEnum +{ + EME_NONE, + EME_ONE, + EME_COUNT +}; + +const c8* const MockEnumNames[EME_COUNT+1] = +{ + "none", + "one", + 0, +}; + +class SerializableMock : public virtual io::IAttributeExchangingObject +{ +public: + SerializableMock(bool comparePointers=true) : ComparePointers(comparePointers) + { + } + + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const + { + out->addInt("ValInt", ValInt); + out->addFloat("ValFloat", ValFloat); + out->addString("ValString", ValString.c_str()); + out->addString("ValStringW", ValStringW.c_str()); + out->addBinary("ValBinary", (void*)ValBinary, BINARY_BLOCK_SIZE); + out->addArray("ValStringWArray", ValStringWArray); + out->addBool("ValBool", ValBool); + out->addEnum("ValEnum", ValEnum, MockEnumNames); + out->addColor("ValColor", ValColor); + out->addColorf("ValColorf", ValColorf); + out->addVector3d("ValVector3df", ValVector3df); + out->addVector2d("ValVector2df", ValVector2df); + out->addDimension2d("ValDimension2du", ValDimension2du); + out->addPosition2d("ValPosition2di", ValPosition2di); + out->addRect("ValRect", ValRect); + out->addMatrix("ValMatrix", ValMatrix); + out->addQuaternion("ValQuaternion", ValQuaternion); + out->addBox3d("ValAabbox3df", ValAabbox3df); + out->addPlane3d("ValPlane3df", ValPlane3df); + out->addTriangle3d("ValTriangle3df", ValTriangle3df); + out->addLine2d("ValLine2df", ValLine2df); + out->addLine3d("ValLine3df", ValLine3df); + out->addTexture("ValTexture", ValTexture ); + out->addUserPointer("ValPointer", ValPointer); + } + + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) + { + ValInt = in->getAttributeAsInt("ValInt"); + ValFloat = in->getAttributeAsFloat("ValFloat"); + ValString = in->getAttributeAsString("ValString"); + ValStringW = in->getAttributeAsStringW("ValStringW"); + in->getAttributeAsBinaryData("ValBinary", ValBinary, BINARY_BLOCK_SIZE); + ValStringWArray = in->getAttributeAsArray("ValStringWArray"); + ValBool = in->getAttributeAsBool("ValBool"); + ValEnum = (EMockEnum)in->getAttributeAsEnumeration("ValEnum", MockEnumNames); + ValColor = in->getAttributeAsColor("ValColor"); + ValColorf = in->getAttributeAsColorf("ValColorf"); + ValVector3df = in->getAttributeAsVector3d("ValVector3df"); + ValVector2df = in->getAttributeAsVector2d("ValVector2df"); + ValDimension2du = in->getAttributeAsDimension2d("ValDimension2du"); + ValPosition2di = in->getAttributeAsPosition2d("ValPosition2di"); + ValRect = in->getAttributeAsRect("ValRect"); + ValMatrix = in->getAttributeAsMatrix("ValMatrix"); + ValQuaternion = in->getAttributeAsQuaternion("ValQuaternion"); + ValAabbox3df = in->getAttributeAsBox3d("ValAabbox3df"); + ValPlane3df = in->getAttributeAsPlane3d("ValPlane3df"); + ValTriangle3df = in->getAttributeAsTriangle3d("ValTriangle3df"); + ValLine2df = in->getAttributeAsLine2d("ValLine2df"); + ValLine3df = in->getAttributeAsLine3d("ValLine3df"); + ValTexture = in->getAttributeAsTexture("ValTexture"); + ValPointer = in->getAttributeAsUserPointer("ValPointer"); + } + + bool operator==(const SerializableMock& other) + { + COMPARE(ValInt, other.ValInt); + COMPARE(ValFloat, other.ValFloat); + COMPARE(ValString, other.ValString); + COMPARE(ValStringW, other.ValStringW); + if ( memcmp( ValBinary, other.ValBinary, BINARY_BLOCK_SIZE) != 0 ) + { + logTestString("Not identical %s in %s:%d", "ValBinary", __FILE__, __LINE__ ); + return false; + } + COMPARE(ValStringWArray, other.ValStringWArray); + COMPARE(ValBool, other.ValBool); + COMPARE(ValEnum, other.ValEnum); + COMPARE(ValColor, other.ValColor); + if ( ValColorf.r != other.ValColorf.r || ValColorf.g != other.ValColorf.g || ValColorf.b != other.ValColorf.b || ValColorf.a != other.ValColorf.a ) + { + logTestString("Not identical %s in %s:%d", "ValColorf", __FILE__, __LINE__ ); + return false; + } + COMPARE(ValVector3df, other.ValVector3df); + COMPARE(ValVector2df, other.ValVector2df); + COMPARE(ValDimension2du, other.ValDimension2du); + COMPARE(ValPosition2di, other.ValPosition2di); + COMPARE(ValRect, other.ValRect); + COMPARE(ValMatrix, other.ValMatrix); + COMPARE(ValQuaternion, other.ValQuaternion); + COMPARE(ValAabbox3df, other.ValAabbox3df); + COMPARE(ValPlane3df, other.ValPlane3df); + COMPARE(ValTriangle3df, other.ValTriangle3df); + COMPARE(ValLine2df, other.ValLine2df); + COMPARE(ValLine3df, other.ValLine3df); +// ValTexture; // TODO + if ( ComparePointers ) + COMPARE(ValPointer, other.ValPointer); + return true; + } + + void reset() + { + ValInt = 0; + ValFloat = 0.f; + ValString = ""; + ValStringW = L""; + memset(ValBinary, 0, BINARY_BLOCK_SIZE); + ValStringWArray.clear(); + ValBool = false; + ValEnum = EME_NONE; + ValColor.set(0,0,0,0); + ValColorf.set(0.f, 0.f, 0.f, 0.f); + ValVector3df.set(0.f, 0.f, 0.f); + ValVector2df.set(0.f, 0.f); + ValDimension2du.set(0, 0); + ValPosition2di.set(0,0); + ValRect = core::rect(0,0,0,0); + ValMatrix.makeIdentity(); + ValQuaternion.set(0,0,0,0); + ValAabbox3df.reset(0,0,0); + ValPlane3df.setPlane(vector3df(0.f,0.f,0.f), 0.f); + ValTriangle3df.set( vector3df(0.f,0.f,0.f), vector3df(0.f,0.f,0.f), vector3df(0.f,0.f,0.f) ); + ValLine2df.setLine(0.f, 0.f, 0.f, 0.f); + ValLine3df.setLine(0.f, 0.f, 0.f, 0.f, 0.f, 0.f); + ValTexture = NULL; + ValPointer = 0; + } + + void set() + { + ValInt = 152722522; + ValFloat = 1.f; + ValString = "one"; + ValStringW = L"ONE"; + memset(ValBinary, 0xff, BINARY_BLOCK_SIZE); + ValStringWArray.push_back( stringw("ONE") ); + ValStringWArray.push_back( stringw("TWO") ); + ValStringWArray.push_back( stringw("THREE") ); + ValBool = true; + ValEnum = EME_ONE; + ValColor.set(1,2,3,4); + ValColorf.set(1.f, 2.f, 3.f, 4.f); + ValVector3df.set(1.f, 2.f, 3.f); + ValVector2df.set(1.f, 2.f); + ValDimension2du.set(1, 2); + ValPosition2di.set(1,2); + ValRect = core::rect(1,2,3,4); + ValMatrix = 99.9f; + ValQuaternion.set(1,2,3,4); + ValAabbox3df.reset(1,2,3); + ValPlane3df.setPlane(vector3df(1.f,2.f,3.f), 4.f); + ValTriangle3df.set( vector3df(1.f,2.f,3.f), vector3df(4.f,5.f,6.f), vector3df(7.f,8.f,9.f) ); + ValLine2df.setLine(1.f, 2.f, 3.f, 4.f); + ValLine3df.setLine(1.f, 2.f, 3.f, 4.f, 5.f, 6.f); + ValTexture = NULL; // TODO + ValPointer = (void*)0xffffff; + } + + s32 ValInt; + f32 ValFloat; + core::stringc ValString; + core::stringw ValStringW; + char ValBinary[BINARY_BLOCK_SIZE]; + core::array ValStringWArray; + bool ValBool; + EMockEnum ValEnum; + video::SColor ValColor; + video::SColorf ValColorf; + core::vector3df ValVector3df; + core::vector2df ValVector2df; + core::dimension2du ValDimension2du; + core::position2di ValPosition2di; + core::rect ValRect; + core::matrix4 ValMatrix; + core::quaternion ValQuaternion; + core::aabbox3df ValAabbox3df; + core::plane3df ValPlane3df; + core::triangle3df ValTriangle3df; + core::line2df ValLine2df; + core::line3df ValLine3df; + video::ITexture* ValTexture; + void* ValPointer; + + bool ComparePointers; +}; + +// Serialization in memory +bool MemorySerialization(io::IFileSystem * fs ) +{ + SerializableMock origMock, copyMock; + origMock.set(); + copyMock.reset(); + + io::IAttributes* attr = fs->createEmptyAttributes(); + origMock.serializeAttributes(attr, 0); + copyMock.deserializeAttributes(attr, 0); + attr->drop(); + + return origMock == copyMock; +} + +// Serialization to/from an xml-file +bool XmlSerialization(io::IFileSystem * fs, video::IVideoDriver * driver ) +{ + const io::path XML_FILENAME("results/attributeSerialization.xml"); + SerializableMock origMock(false), copyMock; + origMock.set(); + copyMock.reset(); + + // write to xml + io::IWriteFile* fileWrite = fs->createAndWriteFile(XML_FILENAME); + if (!fileWrite) + { + logTestString("Could not create xml in %s:%d\n", __FILE__, __LINE__ ); + return false; + } + io::IXMLWriter* writer = fs->createXMLWriter(fileWrite); + if (!writer) + { + logTestString("Could not create xml-writer in %s:%d\n", __FILE__, __LINE__ ); + return false; + } + writer->writeXMLHeader(); + writer->writeLineBreak(); + io::IAttributes* attrToXml = fs->createEmptyAttributes(); + origMock.serializeAttributes(attrToXml, 0); + attrToXml->write(writer); + attrToXml->drop(); + writer->writeLineBreak(); + writer->drop(); + fileWrite->drop(); + + // read from xml + io::IReadFile* fileRead = fs->createAndOpenFile(XML_FILENAME); + if (!fileRead) + { + logTestString("Could not open xml-file in %s:%d\n", __FILE__, __LINE__ ); + return false; + } + io::IXMLReader* reader = fs->createXMLReader(fileRead); + if (!reader) + { + logTestString("createXMLReader failed in %s:%d\n", __FILE__, __LINE__ ); + return false; + } + while(reader->read()) + { + switch (reader->getNodeType()) + { + case EXN_ELEMENT: + { + // read attributes + io::IAttributes* attr = fs->createEmptyAttributes(driver); + if ( attr->read(reader, true) ) + { + copyMock.deserializeAttributes(attr, 0); + } + else + { + logTestString("attr->read failed in %s:%d\n", __FILE__, __LINE__ ); + } + attr->drop(); + } + break; + default: + break; + } + } + reader->drop(); + fileRead->drop(); + + return origMock == copyMock; +} + +// All attributes can also be read/written in string format +bool stringSerialization(io::IFileSystem * fs) +{ + SerializableMock mock; + mock.set(); + + io::IAttributes* attr = fs->createEmptyAttributes(); + mock.serializeAttributes(attr, 0); + + for ( s32 i=0; i< (s32)attr->getAttributeCount(); ++i ) + { + core::stringw value(attr->getAttributeAsString(i)); + attr->setAttribute(i, value.c_str() ); + core::stringw value2(attr->getAttributeAsString(i)); + + if ( value != value2 ) + { + logTestString("old-string: %s new-string: %s for %d.%s in %s:%d\n" + , core::stringc(value).c_str(), core::stringc(value2).c_str(), i, attr->getAttributeName(i), __FILE__, __LINE__ ); + return false; + } + else + { + // TODO: We can't catch yet if getAttributeAsString and setAttribute both change nothing + // Except if string returned is empty - which would be fine in some cases (0 pointers or if string was empty originally) + // But right now at least stringw arrays don't do stringSerialization which is a bug + //if ( value.empty() ) + //return false; + } + + } + + attr->drop(); + + return true; +} + +bool serializeAttributes() +{ + bool result = true; + + IrrlichtDevice * device = irr::createDevice(video::EDT_NULL, dimension2d(1, 1)); + assert(device); + if(!device) + { + logTestString("device creation failed in %s:%d\n", __FILE__, __LINE__ ); + return false; + } + + io::IFileSystem * fs = device->getFileSystem (); + if ( !fs ) + { + return false; + } + + result &= MemorySerialization(fs); + if ( !result ) + { + logTestString("MemorySerialization failed in %s:%d\n", __FILE__, __LINE__ ); + } + + result &= XmlSerialization(fs, device->getVideoDriver()); + if ( !result ) + { + logTestString("XmlSerialization failed in %s:%d\n", __FILE__, __LINE__ ); + } + + result &= stringSerialization(fs); + if ( !result ) + { + logTestString("stringSerialization failed in %s:%d\n", __FILE__, __LINE__ ); + } + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} diff --git a/tests/skinnedMesh.cpp b/tests/skinnedMesh.cpp new file mode 100644 index 00000000..68bb6186 --- /dev/null +++ b/tests/skinnedMesh.cpp @@ -0,0 +1,75 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; + +// Tests skinned meshes. +bool skinnedMesh(void) +{ + // Use EDT_BURNINGSVIDEO since it is not dependent on (e.g.) OpenGL driver versions. + IrrlichtDevice *device = createDevice(video::EDT_BURNINGSVIDEO, core::dimension2d(160, 120), 32); + if (!device) + return false; + + scene::ISceneManager * smgr = device->getSceneManager(); + + logTestString("Testing setMesh()\n"); + + scene::ISkinnedMesh* mesh = (scene::ISkinnedMesh*)smgr->getMesh("../media/ninja.b3d"); + if (!mesh) + { + logTestString("Could not load ninja.\n"); + return false; + } + + scene::IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh); + if (!node) + { + logTestString("Could not add ninja node.\n"); + return false; + } + + // test if certain joint is found + bool result = (node->getJointNode("Joint1") != 0); + if (!result) + logTestString("Could not find joint in ninja.\n"); + + mesh = (scene::ISkinnedMesh*)smgr->getMesh("../media/dwarf.x"); + if (!mesh) + { + logTestString("Could not load dwarf.\n"); + return false; + } + node->setMesh(mesh); + + // make sure old joint is non-existant anymore + logTestString("Ignore error message in log, this is intended.\n"); + result &= (node->getJointNode("Joint1")==0); + if (!result) + logTestString("Found non-existing joint in dwarf.\n"); + + // and check that a new joint can be found + // we use a late one, in order to see also inconsistencies in the joint cache + result &= (node->getJointNode("hit") != 0); + if (!result) + logTestString("Could not find joint in dwarf.\n"); + + node = smgr->addAnimatedMeshSceneNode(mesh); + if (!node) + { + logTestString("Could not add dwarf node.\n"); + return false; + } + // check that a joint can really be found + result &= (node->getJointNode("hit") != 0); + if (!result) + logTestString("Could not find joint in dwarf.\n"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} diff --git a/tests/softwareDevice.cpp b/tests/softwareDevice.cpp new file mode 100644 index 00000000..e9bace12 --- /dev/null +++ b/tests/softwareDevice.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace scene; + +//! Tests the basic functionality of the software device. +bool softwareDevice(void) +{ + IrrlichtDevice *device = createDevice(video::EDT_SOFTWARE, dimension2d(160, 120), 32); + if (!device) + return false; + + video::IVideoDriver* driver = device->getVideoDriver(); + ISceneManager * smgr = device->getSceneManager(); + + // Test a particular rotation that highlighted a clipping issue from matrix::transformPlane() + video::S3DVertex vertices[3]; + vertices[0] = video::S3DVertex(10,0,-10, 1,0,0, + video::SColor(255,255,0,255), 1, 1); + vertices[1] = video::S3DVertex(0,20,0, 0,1,1, + video::SColor(255,255,255,0), 1, 0); + vertices[2] = video::S3DVertex(-10,0,-10, 0,0,1, + video::SColor(255,0,255,0), 0, 0); + + video::SMaterial material; + material.Lighting = false; + material.Wireframe = false; + const u16 indices[] = { 1,0,2, }; + + matrix4 transform(matrix4::EM4CONST_IDENTITY); + vector3df rotations(290, 0, 290); // <-- This rotation used to clip the triangle incorrectly + transform.setRotationDegrees(rotations); + + (void)smgr->addCameraSceneNode(0, core::vector3df(0,0,-40), core::vector3df(0,0,0)); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,255,255,0)); + smgr->drawAll(); + + driver->setMaterial(material); + + driver->setTransform(video::ETS_WORLD, transform); + driver->drawIndexedTriangleList(&vertices[0], 3, &indices[0], 1); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-softwareDevice-rotatedClip.png"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} diff --git a/tests/stencilshadow.cpp b/tests/stencilshadow.cpp new file mode 100644 index 00000000..4e7f3e3f --- /dev/null +++ b/tests/stencilshadow.cpp @@ -0,0 +1,108 @@ +// Copyright (C) 2008-2012 Christian Stehno, Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; + +// +static bool stencilShadow(video::E_DRIVER_TYPE driverType) +{ + IrrlichtDevice *device = createDevice (driverType, core::dimension2d(160,120), 16, false, true); + if (!device) + return true; // No error if device does not exist + + stabilizeScreenBackground(device->getVideoDriver()); + + scene::ICameraSceneNode* cam = device->getSceneManager()->addCameraSceneNodeFPS(); + cam->setPosition(core::vector3df(-15,60,40)); + cam->setTarget(core::vector3df(+25,-5,-25)); + + device->getSceneManager()->setAmbientLight(video::SColorf(.5f,.5f,.5f)); + device->getSceneManager()->setShadowColor( video::SColor(255, 50, 0, 50)); + device->getSceneManager()->addCubeSceneNode(100, 0, -1, core::vector3df(0,50,0), core::vector3df(), core::vector3df(-1,-1,-1)); + + scene::IAnimatedMeshSceneNode* node = device->getSceneManager()->addAnimatedMeshSceneNode(device->getSceneManager()->getMesh("../media/ninja.b3d"), 0, -1, core::vector3df(), core::vector3df(0.f, 230.f, 0.f),core::vector3df(5,5,5)); + node->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true); + node->addShadowVolumeSceneNode(0, -1, true, 200.f); + node->setAnimationSpeed(0.f); + + scene::IMeshSceneNode* cube2 = device->getSceneManager()->addCubeSceneNode(10, 0, -1, core::vector3df(40,0,0), core::vector3df(), core::vector3df(1,1,2.5f)); + cube2->getMaterial(0).DiffuseColor = video::SColor(220, 0, 100, 100); + cube2->addShadowVolumeSceneNode(0, -1, false, 200.f); + + scene::ILightSceneNode* light = device->getSceneManager()->addLightSceneNode(0, core::vector3df(-40,10,20)); + light->setLightType(video::ELT_POINT); + light->setRadius(500.f); + light->getLightData().DiffuseColor.set(1,1,1); + + device->getVideoDriver()->beginScene(video::ECBF_ALL, video::SColor(0,0,0,0)); + device->getSceneManager()->drawAll(); + device->getVideoDriver()->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(device->getVideoDriver(), "-stencilShadow.png", 99.91f); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +// test self-shadowing +static bool selfShadowing(video::E_DRIVER_TYPE driverType) +{ + IrrlichtDevice *device = createDevice (driverType, core::dimension2d(160,120), 16, false, true); + if (!device) + return true; // No error if device does not exist + + stabilizeScreenBackground(device->getVideoDriver()); + + device->getSceneManager()->setAmbientLight(video::SColorf(.5f,.5f,.5f)); + device->getSceneManager()->setShadowColor( video::SColor(220, 50, 0, 0)); + + scene::IAnimatedMeshSceneNode* node = device->getSceneManager()->addAnimatedMeshSceneNode(device->getSceneManager()->getMesh("../media/dwarf.x")); + node->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true); + node->addShadowVolumeSceneNode(); + node->setAnimationSpeed(0.f); + + scene::ICameraSceneNode* cam = device->getSceneManager()->addCameraSceneNodeFPS(); + cam->setPosition(core::vector3df(0,55,-30)); + cam->setTarget(core::vector3df(60,45,150)); + + scene::ILightSceneNode* light = device->getSceneManager()->addLightSceneNode(0, core::vector3df(100,100,-20)); + light->setLightType(video::ELT_POINT); + light->setRadius(500.f); + light->getLightData().DiffuseColor.set(0,1,1); + + device->getVideoDriver()->beginScene(video::ECBF_ALL, video::SColor(0,0,0,0)); + device->getSceneManager()->drawAll(); + device->getVideoDriver()->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(device->getVideoDriver(), "-stencilSelfShadow.png", 99.41f); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +bool stencilShadow(void) +{ + bool passed = true; + + passed &= stencilShadow(video::EDT_OPENGL); + passed &= stencilShadow(video::EDT_DIRECT3D9); + // no shadows in software renderer +// passed &= stencilShadow(video::EDT_SOFTWARE); + passed &= stencilShadow(video::EDT_BURNINGSVIDEO); // Note: cube has wrong color, if that gets ever changed just update the test-image. + + passed &= selfShadowing(video::EDT_OPENGL); + passed &= selfShadowing(video::EDT_DIRECT3D9); + // no shadows in software renderer +// passed &= selfShadowing(video::EDT_SOFTWARE); + passed &= selfShadowing(video::EDT_BURNINGSVIDEO); + + return passed; +} diff --git a/tests/terrainSceneNode.cpp b/tests/terrainSceneNode.cpp new file mode 100644 index 00000000..7c336618 --- /dev/null +++ b/tests/terrainSceneNode.cpp @@ -0,0 +1,128 @@ + +#include "testUtils.h" + +using namespace irr; +using namespace core; + +namespace +{ + +// test camera changes with terrain scene node recalculation +bool terrainRecalc(void) +{ + IrrlichtDevice *device = + createDevice(video::EDT_BURNINGSVIDEO, dimension2du(160, 120), 32); + + if (!device) + return true; + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + + scene::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); + + scene::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(video::ECBF_COLOR | video::ECBF_DEPTH, 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", 97.98f); + if(!result) + { + logTestString("Small camera up rotation caused bad recalc.\n"); + } + + // This is big enough to cause a recalc + camera->setUpVector(vector3df(1.f, 0.f, .1f).normalize()); + device->run(); + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,100,101,140)); + smgr->drawAll(); + driver->endScene(); + + result &= takeScreenshotAndCompareAgainstReference(driver, "-terrainSceneNode-2.png", 98.38f); + if(!result) + { + logTestString("Large camera up rotation caused bad recalc.\n"); + } + + device->closeDevice(); + device->run(); + device->drop(); + return result; +} + +bool terrainGaps() +{ + IrrlichtDevice* device = createDevice(video::EDT_BURNINGSVIDEO, dimension2d(160, 120)); + if (!device) + return true; + + video::IVideoDriver * irrVideo = device->getVideoDriver(); + scene::ISceneManager* irrScene = device->getSceneManager(); + + // Add camera + scene::ICameraSceneNode* camera = irrScene->addCameraSceneNode(); + camera->setPosition(vector3df(20000, 500, 12800)); + camera->setTarget(vector3df(16800, 0, 12800)); + camera->setFarValue(42000.0f); + + // Add terrain scene node + for (u32 i = 0; i < 2; i++) + { + const char* name="media/ter1.png"; + scene::ITerrainSceneNode* terrain = irrScene->addTerrainSceneNode( + name, 0, -1, + vector3df((f32)(256*50), 0.f, (f32)(i*256*50)),// position 12800(==imgsize*scale) + vector3df(0.f, 0.f, 0.f), // rotation + vector3df(50.f, 15.0f, 50.f) // scale 50 15 50 + ); + + terrain->setMaterialFlag(video::EMF_LIGHTING, false); + terrain->setMaterialFlag(video::EMF_WIREFRAME, !terrain->getMaterial(0).Wireframe); + } + + irrVideo->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0,150,150,150)); + irrScene->drawAll(); + irrVideo->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(irrVideo, "-terrainGap.png"); + + device->closeDevice(); + device->run(); + device->drop(); + return result; +} + +} + +bool terrainSceneNode() +{ + bool result = terrainRecalc(); + result &= terrainGaps(); + return result; +} + diff --git a/tests/testDimension2d.cpp b/tests/testDimension2d.cpp new file mode 100644 index 00000000..801c2cfe --- /dev/null +++ b/tests/testDimension2d.cpp @@ -0,0 +1,36 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +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_log(false); + return false; + } + + (void)(dimension -= addDimension); + if(dimension != dimension2df(100.f, 100.f)) + { + logTestString("dimension2df -= produced unexpected result.\n"); + assert_log(false); + return false; + } + + return true; +} + diff --git a/tests/testGeometryCreator.cpp b/tests/testGeometryCreator.cpp new file mode 100644 index 00000000..cbf48ddb --- /dev/null +++ b/tests/testGeometryCreator.cpp @@ -0,0 +1,127 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; + +/** Tests that the geometry creator does what it says it does. */ +bool testGeometryCreator(void) +{ + IrrlichtDevice *device = createDevice(video::EDT_BURNINGSVIDEO, + core::dimension2du(160,120), 32); + if (!device) + return false; + + IVideoDriver* driver = device->getVideoDriver(); + ISceneManager* smgr = device->getSceneManager(); + (void)smgr->addCameraSceneNode(0, vector3df(0, 0, -50)); + + const IGeometryCreator * geom = smgr->getGeometryCreator(); + + ITexture * wall = driver->getTexture("../media/wall.bmp"); + + SMaterial material; + material.Lighting = false; + material.TextureLayer[0].Texture = wall; + + irr::scene::IMesh * meshHill = geom->createHillPlaneMesh(dimension2df(10, 5), dimension2du(5, 5), + &material, 10, dimension2df(2, 2), dimension2df(3, 3) ); + IMeshSceneNode * node = smgr->addMeshSceneNode(meshHill, 0, -1, + vector3df(0, 10, 0), vector3df(-60, 0, 0)); + meshHill->drop(); + + irr::scene::IMesh * meshArrow = geom->createArrowMesh(4, 8, 10, 6, 3, 6, + SColor(255, 255, 0, 0), SColor(255, 0, 255, 0)); + node = smgr->addMeshSceneNode(meshArrow, 0, -1, vector3df(-10, -20, 0)); + node->setMaterialFlag(video::EMF_LIGHTING, false); + meshArrow->drop(); + + irr::scene::IMesh * meshCone = geom->createConeMesh(5.f, 10.f, 16); + node = smgr->addMeshSceneNode(meshCone, 0, -1, vector3df(-35, -20, 0)); + node->setMaterialFlag(video::EMF_LIGHTING, false); + node->setMaterialTexture(0, wall); + meshCone->drop(); + + irr::scene::IMesh * meshCube = geom->createCubeMesh(); + node = smgr->addMeshSceneNode(meshCube, 0, -1, vector3df(-20, -20, 0)); + node->setMaterialFlag(video::EMF_LIGHTING, false); + node->setMaterialTexture(0, wall); + meshCube->drop(); + + irr::scene::IMesh * meshCylinder = geom->createCylinderMesh(3, 10, 16); + node = smgr->addMeshSceneNode(meshCylinder, 0, -1, vector3df(0, -20, 10), core::vector3df(45,0,0)); + node->setMaterialFlag(video::EMF_LIGHTING, false); + node->setMaterialTexture(0, wall); + meshCylinder->drop(); + + irr::scene::IMesh * meshSphere = geom->createSphereMesh(); + node = smgr->addMeshSceneNode(meshSphere, 0, -1, vector3df(10, -15, 0)); + node->setMaterialFlag(video::EMF_LIGHTING, false); + node->setMaterialTexture(0, wall); + meshSphere->drop(); + + irr::scene::IMesh * meshVolumeLight = geom->createVolumeLightMesh(); + node = smgr->addMeshSceneNode(meshVolumeLight, 0, -1, vector3df(20, -20, -10)); + node->setMaterialFlag(video::EMF_LIGHTING, false); + node->setMaterialTexture(0, wall); + node->setScale(core::vector3df(4.f,4.f,4.f)); + meshVolumeLight->drop(); + + bool result = false; + device->run(); + if (driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0, 80, 80, 80))) + { + smgr->drawAll(); + driver->endScene(); + result = takeScreenshotAndCompareAgainstReference(driver, "-testGeometryCreator.png", 99.994f); + } + + smgr->clear(); + + driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true); + + // add camera + scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(0,100.0f,2.0f); + camera->setPosition(core::vector3df(2000.0f,5000.f,0.0f)); + camera->setTarget(core::vector3df(0.0f,0.0f,0.0f)); + camera->setFarValue(20000.0f); + device->getCursorControl()->setVisible(false); // disable mouse cursor + + video::IImage* colorMapImage = driver->createImageFromFile("../media/terrain-texture.jpg"); + video::IImage* heightMapImage = driver->createImageFromFile("../media/terrain-heightmap.bmp"); + + scene::IAnimatedMesh* terrain = smgr->addTerrainMesh("TerrainMeshName", + colorMapImage, heightMapImage, + core::dimension2d(40, 40), // size of a pixel + 8*40); // maximum height + colorMapImage->drop(); + colorMapImage = 0; + heightMapImage->drop(); + heightMapImage = 0; + + scene::IAnimatedMeshSceneNode* anode = smgr->addAnimatedMeshSceneNode(terrain); + if (anode) + { + anode->setMaterialFlag(video::EMF_LIGHTING, false); + anode->setPosition(core::vector3df(-5000,0,-5000)); + } + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0)); + smgr->drawAll(); + driver->endScene(); + + // This screenshot shows some mipmap problems, but this seems to be + // no fault of the mesh + result &= takeScreenshotAndCompareAgainstReference(driver, "-testTerrainMesh.png", 99.989f); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + diff --git a/tests/testLine2d.cpp b/tests/testLine2d.cpp new file mode 100644 index 00000000..f8fe1f39 --- /dev/null +++ b/tests/testLine2d.cpp @@ -0,0 +1,301 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; + +static bool testLines(line2df const & line1, + line2df const & line2, + bool expectedHit, + const vector2df & expectedIntersection) +{ + bool gotExpectedResult = true; + + logTestString("\nLine 1 = %.1f %.1f to %.1f %.1f \n", + line1.start.X, line1.start.Y, + line1.end.X, line1.end.Y); + logTestString("Line 2 = %.1f %.1f to %.1f %.1f\n", + line2.start.X, line2.start.Y, + line2.end.X, line2.end.Y); + + vector2df intersection; + logTestString("line1 with line2 = "); + if(line1.intersectWith(line2, intersection)) + { + logTestString("hit at %.1f %.1f - ", + intersection.X, intersection.Y); + + if(!line1.isPointOnLine(intersection) || !line2.isPointOnLine(intersection)) + { + logTestString("ERROR! point is not on both lines - "); + gotExpectedResult = false; + } + + if(expectedHit) + { + if(intersection == expectedIntersection) + { + logTestString("expected\n"); + } + else + { + logTestString("unexpected intersection (expected %.1f %.1f)\n", + expectedIntersection.X, expectedIntersection.Y); + gotExpectedResult = false; + } + } + else + { + logTestString("UNEXPECTED\n"); + gotExpectedResult = false; + } + } + else + { + logTestString("miss - "); + if(!expectedHit) + { + logTestString("expected\n"); + } + else + { + logTestString("UNEXPECTED\n"); + gotExpectedResult = false; + } + } + + logTestString("line2 with line1 = "); + if(line2.intersectWith(line1, intersection)) + { + logTestString("hit at %.1f %.1f - ", + intersection.X, intersection.Y); + if(!line1.isPointOnLine(intersection) || !line2.isPointOnLine(intersection)) + { + logTestString("ERROR! point is not on both lines - "); + gotExpectedResult = false; + } + + if(expectedHit) + { + if(intersection == expectedIntersection) + { + logTestString("expected\n"); + } + else + { + logTestString("unexpected intersection (expected %.1f %.1f)\n", + expectedIntersection.X, expectedIntersection.Y); + gotExpectedResult = false; + } + } + else + { + logTestString("UNEXPECTED\n"); + gotExpectedResult = false; + } + } + else + { + logTestString("miss - "); + if(!expectedHit) + { + logTestString("expected\n"); + } + else + { + logTestString("UNEXPECTED\n"); + gotExpectedResult = false; + } + } + + return gotExpectedResult; +} + +// Test the functionality of line2d>T>::intersectWith(). +/** Validation is done with assert_log() against expected results. */ +bool line2dIntersectWith(void) +{ + bool allExpected = true; + + // Crossing lines, horizontal and vertical + allExpected &= testLines(line2df(vector2df(1,1),vector2df(1,3)), + line2df(vector2df(0,2),vector2df(2,2)), + true, vector2df(1,2)); + assert_log(allExpected); + + // Crossing lines, both diagonal + allExpected &= testLines(line2df(vector2df(0,0),vector2df(2,2)), + line2df(vector2df(0,2),vector2df(2,0)), + true, vector2df(1,1)); + assert_log(allExpected); + + // Non-crossing lines, horizontal and vertical + allExpected &= testLines(line2df(vector2df(1,1),vector2df(1,3)), + line2df(vector2df(0,4),vector2df(2,4)), + false, vector2df()); + assert_log(allExpected); + + // Non-crossing lines, both diagonal + allExpected &= testLines(line2df(vector2df(0,0),vector2df(2,2)), + line2df(vector2df(3,4),vector2df(4,3)), + false, vector2df()); + assert_log(allExpected); + + // Meeting at a common point + allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,0)), + line2df(vector2df(1,0),vector2df(2,0)), + true, vector2df(1,0)); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,0)), + line2df(vector2df(1,0),vector2df(0,1)), + true, vector2df(1,0)); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,0)), + line2df(vector2df(1,0),vector2df(0,-1)), + true, vector2df(1,0)); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(0,0),vector2df(0,1)), + line2df(vector2df(0,1),vector2df(1,1)), + true, vector2df(0,1)); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(0,0),vector2df(0,1)), + line2df(vector2df(0,1),vector2df(1,-1)), + true, vector2df(0,1)); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(0,0),vector2df(0,1)), + line2df(vector2df(0,1),vector2df(0,2)), + true, vector2df(0,1)); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,0)), + line2df(vector2df(1,0),vector2df(2,0)), + true, vector2df(1,0)); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,1)), + line2df(vector2df(1,1),vector2df(0,2)), + true, vector2df(1,1)); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,1)), + line2df(vector2df(1,1),vector2df(2,0)), + true, vector2df(1,1)); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,1)), + line2df(vector2df(1,1),vector2df(2,2)), + true, vector2df(1,1)); + assert_log(allExpected); + + + // Parallel lines, no intersection + allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,0)), + line2df(vector2df(0,1),vector2df(1,1)), + false, vector2df()); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(0,0),vector2df(0,1)), + line2df(vector2df(1,0),vector2df(1,1)), + false, vector2df()); + assert_log(allExpected); + + // Non parallel lines, no intersection + allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,0)), + line2df(vector2df(0,1),vector2df(0,2)), + false, vector2df()); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(0,0),vector2df(0,1)), + line2df(vector2df(1,0),vector2df(2,0)), + false, vector2df()); + assert_log(allExpected); + + // Coincident (and thus parallel) lines + allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,0)), + line2df(vector2df(0,0),vector2df(1,0)), + true, vector2df(0,0)); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(2,0),vector2df(0,2)), + line2df(vector2df(2,0),vector2df(0,2)), + true, vector2df(2,0)); + assert_log(allExpected); + + // Two segments of the same unlimited line, but no intersection + allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,1)), + line2df(vector2df(2,2),vector2df(3,3)), + false, vector2df()); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,0)), + line2df(vector2df(2,0),vector2df(3,0)), + false, vector2df()); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(0,0),vector2df(0,1)), + line2df(vector2df(0,2),vector2df(0,3)), + false, vector2df()); + assert_log(allExpected); + + // Overlapping parallel lines + allExpected &= testLines(line2df(vector2df(1,0),vector2df(2,0)), + line2df(vector2df(0,0),vector2df(3,0)), + true, vector2df(1.5f, 0)); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(0,1),vector2df(0,2)), + line2df(vector2df(0,0),vector2df(0,3)), + true, vector2df(0, 1.5f)); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(1,0),vector2df(2,0)), + line2df(vector2df(0,0),vector2df(3,0)), + true, vector2df(1.5f, 0)); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(0,1),vector2df(0,2)), + line2df(vector2df(0,0),vector2df(0,3)), + true, vector2df(0, 1.5f)); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(1,1),vector2df(2,2)), + line2df(vector2df(0,0),vector2df(3,3)), + true, vector2df(1.5f, 1.5f)); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(1,2),vector2df(2,1)), + line2df(vector2df(0,3),vector2df(3,0)), + true, vector2df(1.5f, 1.5f)); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(0,0),vector2df(10,8)), + line2df(vector2df(2.5f,2.0f),vector2df(5.0f,4.0f)), + true, vector2df(3.75f, 3.0f)); + assert_log(allExpected); + allExpected &= testLines(line2df(vector2df(0,0),vector2df(2000,1000)), + line2df(vector2df(2,1),vector2df(2.2f,1.4f)), + true, vector2df(2.0f, 1.0f)); + assert_log(allExpected); + + if(!allExpected) + logTestString("\nline2dIntersectWith failed\n"); + + return allExpected; +} + +bool getClosestPoint(void) +{ + // testcase that fails when integers are handled like floats + irr::core::line2di line(-283, -372, 374, 289); + irr::core::vector2di p1 = line.getClosestPoint( irr::core::vector2di(290,372) ); + irr::core::vector2di p2 = line.getClosestPoint( irr::core::vector2di(135,372) ); + if( p1 == p2 ) + { + logTestString("getClosestPoint failed\n"); + return false; + } + + return true; +} + +bool testLine2d(void) +{ + bool allExpected = true; + + allExpected &= line2dIntersectWith(); + allExpected &= getClosestPoint(); + + if(allExpected) + logTestString("\nAll tests passed\n"); + else + logTestString("\nFAIL!\n"); + + return allExpected; +} diff --git a/tests/testQuaternion.cpp b/tests/testQuaternion.cpp new file mode 100644 index 00000000..b54f0c88 --- /dev/null +++ b/tests/testQuaternion.cpp @@ -0,0 +1,329 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; + +namespace +{ +inline bool compareQ(const core::vector3df& v, const core::vector3df& turn=core::vector3df(0,0,1)) +{ + core::quaternion q(v*core::DEGTORAD); + core::vector3df v2; + + const core::vector3df v3=v.rotationToDirection(turn); + if (!v3.equals(q*turn, 0.002f)) + { + logTestString("Inequality before quat.toEuler(): %f,%f,%f\n", v.X,v.Y,v.Z); + return false; + } + + q.toEuler(v2); + v2*=core::RADTODEG; + v2=v2.rotationToDirection(turn); + + // this yields pretty far values sometimes, so don't be too picky + if (!v3.equals(v2, 0.0035f)) + { + logTestString("Inequality: %f,%f,%f != %f,%f,%f\n", v.X,v.Y,v.Z, v2.X,v2.Y,v2.Z); + return false; + } + return true; +} + +const core::vector3df vals[] = { + core::vector3df(0.f, 0.f, 0.f), + core::vector3df(0.f, 0.f, 24.04f), + core::vector3df(0.f, 0.f, 71.f), + core::vector3df(0.f, 0.f, 71.19f), + core::vector3df(0.f, 0.f, 80.f), + core::vector3df(0.f, 0.f, 103.99f), + core::vector3df(0.f, 0.f, 261.73f), + core::vector3df(0.f, 0.f, 276.f), + core::vector3df(0.f, 0.f, 286.29f), + core::vector3df(0.f, 0.f, 295.f), + core::vector3df(0.f, 0.f, 318.3f), + core::vector3df(360.f, 75.55f, 155.89f), + core::vector3df(0.f, 90.f, 159.51f), + core::vector3df(0.f, 90.f, 249.48f), + core::vector3df(0.f, 90.f, 269.91f), + core::vector3df(0.f, 90.f, 270.f), + core::vector3df(0.f, 284.45f, 155.89f), + core::vector3df(0.01f, 0.42f, 90.38f), + core::vector3df(0.04f, 359.99f, 9.5f), + core::vector3df(0.34f, 89.58f, 360.f), + core::vector3df(0.58f, 4.36f, 334.36f), + core::vector3df(3.23f, 359.65f, 10.17f), + core::vector3df(3.23f, 359.65f, 10.21f), + core::vector3df(4.85f, 359.3f, 94.33f), + core::vector3df(8.90f, 6.63f, 9.27f), + core::vector3df(11.64f, 311.52f, 345.35f), + core::vector3df(12.1f, 4.72f, 11.24f), + core::vector3df(14.63f, 48.72f, 31.79f), + core::vector3df(76.68f, 1.11f, 18.65f), + core::vector3df(90.f, 0.f, 0.f), + core::vector3df(90.01f, 270.49f, 360.f), + core::vector3df(90.95f, 0.f, 0.f), + core::vector3df(173.58f, 348.13f, 132.25f), + core::vector3df(115.52f, 89.04f, 205.51f), + core::vector3df(179.3f, 359.18f, 0.58f), + core::vector3df(180.09f, 270.06f, 0.f), + core::vector3df(180.41f, 359.94f, 179.69f), + core::vector3df(180.92f, 10.79f, 144.53f), + core::vector3df(181.95f, 270.03f, 0.f), + core::vector3df(269.05f, 0.f, 0.f), + core::vector3df(269.99f, 270.49f, 360.f), + core::vector3df(283.32f, 358.89f, 18.65f), + core::vector3df(347.9f, 355.28f, 11.24f), + core::vector3df(351.1f, 353.37f, 9.27f), + core::vector3df(355.82f, 345.96f, 273.26f), + core::vector3df(358.24f, 358.07f, 342.82f), + core::vector3df(359.78f, 357.69f, 7.52f), + core::vector3df(359.96f, 0.01f, 9.5f), + core::vector3df(-57.197479f,-90.f,0.f), + core::vector3df(-57.187481f,-90.f,0.f) +}; + +bool testQuatEulerMatrix() +{ + // Test fromAngleAxis + core::vector3df v4; + core::quaternion q1; + f32 angle = 60.f; + q1.fromAngleAxis(angle*core::DEGTORAD, core::vector3df(1, 0, 0)); + q1.toEuler(v4); + bool result = v4.equals(core::vector3df(angle*core::DEGTORAD,0,0)); + + // Test maxtrix constructor + core::vector3df v5; + core::matrix4 mx4; + mx4.setRotationDegrees(core::vector3df(angle,0,0)); + core::quaternion q2(mx4); + q2.toEuler(v5); + result &= q1.equals(q2); + result &= v4.equals(v5); + + // Test matrix conversion via getMatrix + core::matrix4 mat; + mat.setRotationDegrees(core::vector3df(angle,0,0)); + core::vector3df v6 = mat.getRotationDegrees()*core::DEGTORAD; + // make sure comparison matrix is correct + result &= v4.equals(v6); + + core::matrix4 mat2 = q1.getMatrix(); + result &= mat.equals(mat2, 0.0005f); + + // test for proper handedness + angle=90; + q1.fromAngleAxis(angle*core::DEGTORAD, core::vector3df(0,0,1)); + // check we have the correct quat + result &= q1.equals(core::quaternion(0,0,sqrtf(2)/2,sqrtf(2)/2)); + q1.toEuler(v4); + // and the correct rotation vector + result &= v4.equals(core::vector3df(0,0,90*core::DEGTORAD)); + mat.setRotationRadians(v4); + mat2=q1.getMatrix(); + // check matrix + result &= mat.equals(mat2, 0.0005f); + // and to be absolutely sure, check rotation results + v5.set(1,0,0); + mat.transformVect(v5); + v6.set(1,0,0); + mat2.transformVect(v6); + result &= v5.equals(v6); + + return result; +} + +bool testEulerConversion() +{ + bool result = true; + for (u32 i=0; i testmap; + video::S3DVertex v; + v.Pos = core::vector3df(1.000000f, -1.000000f, 1.000000f); + v.Normal = core::vector3df(0.577350f, -0.577350f, 0.577350f); + v.Color = SColor(255,204,204,204); + v.TCoords = core::vector2d(0.f, 0.f); + testmap.insert(v, 0); + + v.Pos = core::vector3df(-1.000000f, -1.000000f, 1.000000f); + v.Normal = core::vector3df(-0.577350f, -0.577350f, 0.577350f); + v.Color = SColor(255,204,204,204); + v.TCoords = core::vector2d(0.f, 0.f); + testmap.insert(v, 1); + + v.Pos = core::vector3df(1.000000f, 1.000000f, 1.000000f); + v.Normal = core::vector3df(0.577350f, 0.577350f, 0.577350f); + v.Color = SColor(255,204,204,204); + v.TCoords = core::vector2d(0.f, 0.f); + testmap.insert(v, 2); + + v.Pos = core::vector3df(1.000000f, -1.000000f, 1.000000f); + v.Normal = core::vector3df(0.577350f, -0.577350f, 0.577350f); + v.Color = SColor(255,204,204,204); + v.TCoords = core::vector2d(0.f, 0.f); + + core::map::Node* n = testmap.find(v); // look for the vertex just inserted + return n ? true : false; +} + +bool testS3DVertex(void) +{ + bool result = true; + result &= testSorting(); + return result; +} diff --git a/tests/testUtils.cpp b/tests/testUtils.cpp new file mode 100644 index 00000000..fe5a043a --- /dev/null +++ b/tests/testUtils.cpp @@ -0,0 +1,523 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" +#include +#include +#include +#include + +#if defined(_MSC_VER) || defined(_IRR_WINDOWS_API_) +#define _CRT_SECURE_NO_WARNINGS 1 +#include // For OutputDebugString() +#endif // _MSC_VER || _IRR_WINDOWS_API_ + +#ifdef _MSC_VER +#pragma warning( disable: 4996) +#endif + +using namespace irr; + +bool binaryCompareFiles(const char * fileName1, const char * fileName2) +{ + assert(fileName1); + assert(fileName2); + if (!fileName1 || !fileName2) + return false; + + FILE * file1 = fopen(fileName1, "rb"); + if (!file1) + { + logTestString("binaryCompareFiles: File '%s' cannot be opened\n", fileName1); + assert(file1); + return false; + } + + FILE * file2 = fopen(fileName2, "rb"); + if (!file2) + { + logTestString("binaryCompareFiles: File '%s' cannot be opened\n", fileName2); + (void)fclose(file1); + assert(file2); + return false; + } + + + (void)fseek(file1, 0, SEEK_END); + (void)fseek(file2, 0, SEEK_END); + const size_t file1Size = ftell(file1); + const size_t file2Size = ftell(file2); + if (file1Size != file2Size) + { + logTestString("binaryCompareFiles: Files are different sizes: %d vs %d\n", + file1Size, file2Size); + (void)fclose(file1); + (void)fclose(file2); + return false; + } + + (void)fseek(file1, 0, SEEK_SET); + (void)fseek(file2, 0, SEEK_SET); + + char file1Buffer[8196]; + char file2Buffer[8196]; + + while (!feof(file1)) + { + if (feof(file2) + ||(fread(file1Buffer, sizeof(file1Buffer), 1, file1) != + fread(file2Buffer, sizeof(file2Buffer), 1, file2))) + { + logTestString("binaryCompareFiles: Error during file reading\n"); + break; + } + + if (memcmp(file1Buffer, file2Buffer, sizeof(file1Buffer))) + { + logTestString("binaryCompareFiles: files are different\n"); + break; + } + } + + bool filesAreIdentical = feof(file1) && feof(file2); + (void)fclose(file1); + (void)fclose(file2); + + return filesAreIdentical; +} + +bool xmlCompareFiles(irr::io::IFileSystem * fs, const char * fileName1, const char * fileName2) +{ + if (!fileName1 || !fileName2) + return false; + + io::IXMLReaderUTF8* reader1 = fs->createXMLReaderUTF8(fileName1); + if (!reader1) + { + logTestString("xmlCompareFiles: Could not create a XML reader for '%s'\n", fileName1); + return false; + } + io::IXMLReaderUTF8* reader2 = fs->createXMLReaderUTF8(fileName2); + if (!reader2) + { + logTestString("xmlCompareFiles: Could not create a XML reader for '%s'\n", fileName2); + reader1->drop(); + return false; + } + + bool different = false; + bool read1 = reader1->read(); + bool read2 = reader2->read(); + if ( !read1 && !read2 ) + { + logTestString("xmlCompareFiles: Both files have no nodes: '%s' %s - is this ok?\n", fileName1, fileName2); + reader1->drop(); + reader2->drop(); + return true; + } + + while (read1 && read2) + { + io::EXML_NODE type1 = reader1->getNodeType(); + io::EXML_NODE type2 = reader2->getNodeType(); + if ( type1 != type2 ) + { + const c8* name1 = reader1->getNodeName(); + const c8* name2 = reader2->getNodeName(); + logTestString("xmlCompareFiles: file '%s' has different nodes than %s in nodes \"%s\" and \"%s\"\n" + , fileName1, fileName2, name1 ? name1 : "NULL", name2 ? name2 : "NULL"); + different = true; + break; + } + + if ( reader1->isEmptyElement() != reader2->isEmptyElement() ) + { + logTestString("xmlCompareFiles: file '%s' has different empty elements than %s\n", fileName1, fileName2); + different = true; + break; + } + + switch ( type1 ) + { + case io::EXN_NONE: + case io::EXN_ELEMENT_END: + break; + + case io::EXN_ELEMENT: + { + core::stringc name1(reader1->getNodeName()); + core::stringc name2(reader2->getNodeName()); + if ( name1 != name2 ) + { + logTestString("xmlCompareFiles: %s has node %s where %s has node %s\n" + , fileName1, name1.c_str(), fileName2, name2.c_str() ); + different = true; + break; + } + + unsigned int numAttributes1 = reader1->getAttributeCount(); + unsigned int numAttributes2 = reader2->getAttributeCount(); + if ( numAttributes1 != numAttributes2 ) + { + logTestString("xmlCompareFiles: %s node %s has %d attributes where %s node %s has %d attributes\n" + , fileName1, name1.c_str(), numAttributes1 + , fileName2, name2.c_str(), numAttributes2); + different = true; + break; + } + + for ( unsigned int i=0; i < numAttributes1; ++i ) + { + core::stringc attribName1(reader1->getAttributeName(int(i))); + core::stringc attribName2(reader2->getAttributeName(int(i))); + + if ( attribName1 != attribName2 ) + { + logTestString("xmlCompareFiles: %s node %s has attribute-name \"%s\" where %s node %s has name \"%s\"\n" + , fileName1, name1.c_str(), attribName1.c_str() + , fileName2, name2.c_str(), attribName2.c_str()); + different = true; + break; + } + + core::stringc attribVal1(reader1->getAttributeValue(int(i))); + core::stringc attribVal2(reader2->getAttributeValue(int(i))); + if ( attribName1 != attribName2 ) + { + logTestString("xmlCompareFiles: %s node %s has attribute-value \"%s\" where %s node %s has value \"%s\"\n" + , fileName1, name1.c_str(), attribVal1.c_str() + , fileName2, name2.c_str(), attribVal2.c_str()); + different = true; + break; + } + } + + break; + } + + case io::EXN_TEXT: + case io::EXN_UNKNOWN: + case io::EXN_COMMENT: + case io::EXN_CDATA: + { + core::stringc nodeData1( reader1->getNodeData() ); + core::stringc nodeData2( reader1->getNodeData() ); + + // removeChars('\r') needed because irrXML doesn't do that (as it probably should) + nodeData1.removeChars(core::stringc('\r')); + nodeData2.removeChars(core::stringc('\r')); + + if ( nodeData1 != nodeData2 ) + { + logTestString("xmlCompareFiles: %s has data \"%s\" where %s has data \"%s\"\n" + , fileName1, nodeData1.c_str() + , fileName2, nodeData2.c_str()); + different = true; + } + break; + } + } + + if ( different ) + break; + + read1 = reader1->read(); + read2 = reader2->read(); + } + + if ( !different && !read1 && !read2 ) + { + reader1->drop(); + reader2->drop(); + return true; + } + + if ( !different && read1 ) + { + logTestString("xmlCompareFiles: file '%s' has more nodes than %s\n", fileName1, fileName2); + } + if ( !different && read2 ) + { + logTestString("xmlCompareFiles: file '%s' has more nodes than %s\n", fileName2, fileName1); + } + + reader1->drop(); + reader2->drop(); + + return false; +} + + +//! Compare two images, returning the degree to which they match. +/** \param image1 The first image to compare. + \param image2 The second image to compare. + \return The match, from 0.f to 100.f */ +static float fuzzyCompareImages(irr::video::IImage * image1, + irr::video::IImage * image2) +{ + assert(image1); + assert(image2); + if (!image1 || !image2) + return 0.f; + + if (image1->getDimension() != image2->getDimension()) + { + logTestString("fuzzyCompareImages: images are different sizes\n"); + return 0.f; + } + + video::ECOLOR_FORMAT format1 = image1->getColorFormat(); + if (video::ECF_A8R8G8B8 != format1 && video::ECF_R8G8B8 != format1) + { + logTestString("fuzzyCompareImages: image 1 must be ECF_AR8G8B8 or ECF_R8G8B8\n"); + return 0.f; + } + + video::ECOLOR_FORMAT format2 = image2->getColorFormat(); + if (video::ECF_A8R8G8B8 != format2 && video::ECF_R8G8B8 != format2) + { + logTestString("fuzzyCompareImages: image 2 must be ECF_AR8G8B8 or ECF_R8G8B8\n"); + return 0.f; + } + + u8 * image1Data = (u8*)image1->getData(); + u8 * image2Data = (u8*)image2->getData(); + + const u32 pixels = (image1->getPitch() * image1->getDimension().Height) / 4; + u32 mismatchedColours = 0; + for (u32 pixel = 0; pixel < pixels; ++pixel) + { + if (video::ECF_A8R8G8B8 == format1) + image1Data++; + + const u8 r1 = *(image1Data++); + const u8 g1 = *(image1Data++); + const u8 b1 = *(image1Data++); + + if (video::ECF_A8R8G8B8 == format2) + image2Data++; + + const u8 r2 = *(image2Data++); + const u8 g2 = *(image2Data++); + const u8 b2 = *(image2Data++); + + mismatchedColours += abs(r1 - r2) + abs(g1 - g2) + abs(b1 - b2); + } + + const u32 totalColours = pixels * 255*3; + return 100.f * (totalColours - mismatchedColours) / totalColours; +} + + +//! Compare two images, returning the degree to which they match. +/** \param image1 The first image to compare. + \param image2 The second image to compare. + \return The match, from 0.f to 100.f */ +float fuzzyCompareImages(irr::video::IVideoDriver * driver, + const char * fileName1, const char * fileName2) +{ + assert(fileName1); + assert(fileName2); + irr::video::IImage * img1 = driver->createImageFromFile(fileName1); + if (!img1) + return 0; + irr::video::IImage * img2 = driver->createImageFromFile(fileName2); + const float result = fuzzyCompareImages(img1, img2); + logTestString("Image match: %f%%\n", result); + img1->drop(); + if (img2) + img2->drop(); + return result; +} + +void stabilizeScreenBackground(irr::video::IVideoDriver * driver, + irr::video::SColor color) +{ + for(int i = 0; i < 10000; ++i) + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, color); + driver->endScene(); + + irr::video::IImage * screenshot = driver->createScreenShot(); + if (!screenshot) + return; + + const video::ECOLOR_FORMAT format = screenshot->getColorFormat(); + if (format != video::ECF_R8G8B8) + { + irr::video::IImage * fixedScreenshot = driver->createImage(video::ECF_R8G8B8, screenshot->getDimension()); + screenshot->copyTo(fixedScreenshot); + screenshot->drop(); + + if (!fixedScreenshot) + return; + + screenshot = fixedScreenshot; + } + + u8 * image1Data = (u8*)screenshot->getData(); + + const u32 pixels = (screenshot->getPitch() * screenshot->getDimension().Height) / 4; + bool status = true; + for(u32 pixel = 0; pixel < pixels; ++pixel) + { + const u8 r = *(image1Data++); + const u8 g = *(image1Data++); + const u8 b = *(image1Data++); + + if (r != color.getRed() || g != color.getGreen() || b != color.getBlue()) + { + status = false; + break; + } + } + + if (status) + { + screenshot->drop(); + return; + } + screenshot->drop(); + } + + logTestString("stabilizeScreenBackground failed\n"); +} + +irr::core::stringc shortDriverName(irr::video::IVideoDriver * driver) +{ + irr::core::stringc driverName = driver->getName(); + + // For OpenGL and Burning, chop the version number out. Other drivers have more stable version numbers. + // TA: Sorry Rogerborg. burnings video also has the version number inside;-) + // maybe you sould take the getDriverType Info for this + if (driverName.find("OpenGL") > -1) + driverName = "OpenGL"; + else if (driverName.find("Burning's Video") > -1) + driverName = "Burning's Video"; + + return driverName; +} + +bool takeScreenshotAndCompareAgainstReference(irr::video::IVideoDriver * driver, + const char * fileName, + irr::f32 requiredMatch) +{ + irr::video::IImage * screenshot = driver->createScreenShot(); + if (!screenshot) + { + logTestString("Failed to take screenshot\n"); + assert(false); + return false; + } + + const video::ECOLOR_FORMAT format = screenshot->getColorFormat(); + if (format != video::ECF_R8G8B8) + { + irr::video::IImage * fixedScreenshot = driver->createImage(video::ECF_R8G8B8, screenshot->getDimension()); + screenshot->copyTo(fixedScreenshot); + screenshot->drop(); + + if (!fixedScreenshot) + { + logTestString("Failed to convert screenshot to ECF_A8R8G8B8\n"); + assert(false); + return false; + } + + screenshot = fixedScreenshot; + } + + irr::core::stringc driverName = shortDriverName(driver); + + irr::core::stringc referenceFilename = "media/"; + referenceFilename += driverName; + referenceFilename += fileName; + irr::video::IImage * reference = driver->createImageFromFile(referenceFilename.c_str()); + if (!reference) + { + logTestString("\n*** Failed to load reference image '%s'\n*** Creating from screenshot - please check this image.\n\n", + referenceFilename.c_str()); + (void)driver->writeImageToFile(screenshot, referenceFilename.c_str()); + screenshot->drop(); + return false; + } + + const float match = fuzzyCompareImages(screenshot, reference); + logTestString("Image match: %f%%\n", match); + + if (match < requiredMatch) + { + irr::core::stringc mismatchFilename = "results/"; + mismatchFilename += driverName; + mismatchFilename += fileName; + logTestString("Writing mismatched image to '%s'\n", mismatchFilename.c_str()); + (void)driver->writeImageToFile(screenshot, mismatchFilename.c_str()); + } + + + screenshot->drop(); + reference->drop(); + + return (match >= requiredMatch); +} + +static FILE * logFile = 0; + +bool openTestLog(bool startNewLog, const char * filename) +{ + closeTestLog(); + + if (startNewLog) + logFile = fopen(filename, "w"); + else + logFile = fopen(filename, "a"); + + assert(logFile); + if (!logFile) + logTestString("\nWARNING: unable to open the test log file %s\n", filename); + + return (logFile != 0); +} + +void closeTestLog(void) +{ + if (logFile) + { + (void)fclose(logFile); + logFile = 0; + } +} + + +void logTestString(const char * format, ...) +{ + char logString[1024]; + + va_list arguments; + va_start(arguments, format); + vsprintf(logString, format, arguments); + va_end(arguments); + +#if defined(_IRR_WINDOWS_API_) +#if defined (_WIN32_WCE ) + core::stringw tmp(logString); + tmp += L"\n"; + OutputDebugStringW(tmp.c_str()); +#else + OutputDebugStringA(logString); + OutputDebugStringA("\n"); +#endif +#endif + + (void)printf(logString); + if (logFile) + { + (void)fprintf(logFile, logString); + (void)fflush(logFile); + } + +#if defined(TESTING_ON_WINDOWS) + OutputDebugStringA(logString); +#endif // #if defined(TESTING_ON_WINDOWS) +} + diff --git a/tests/testUtils.h b/tests/testUtils.h new file mode 100644 index 00000000..f1d7b6ea --- /dev/null +++ b/tests/testUtils.h @@ -0,0 +1,110 @@ + +#ifndef _TEST_UTILS_H_ +#define _TEST_UTILS_H_ 1 + +#include "irrlicht.h" +#include + +// Small hack. Some newer X11 systems can't handle switching drivers too fast (causing BadWindow errors in X_ChangeWindowAttributes). +// Could be they don't like when Windows with different Visuals are created very quickly (it always happened after creating a new Window with different Visual to previous one). +// timeMs value set by try&error +#ifdef _IRR_POSIX_API_ + #include + #define SLOW_SWITCH \ + do { \ + struct timespec ts; \ + const int timeMs = 250; \ + ts.tv_sec = (time_t) (timeMs / 1000); \ + ts.tv_nsec = (long) (timeMs % 1000) * 1000000; \ + nanosleep(&ts, NULL);\ + } while (false) +#else + #define SLOW_SWITCH +#endif + +#define TestWithAllDrivers(X) \ + logTestString("Running test " #X "\n"); \ + for (u32 i=1; i +static bool compareVectors(const core::vector2d & compare, + const core::vector2d & with) +{ + if (!compare.equals(with)) + { + logTestString("\nERROR: vector2d %.16f, %.16f != vector2d %.16f, %.16f\n", + (f64)compare.X, (f64)compare.Y, (f64)with.X, (f64)with.Y); + assert_log(compare == with); + return false; + } + + return true; +} + +template +static bool doTests() +{ + #define COMPARE_VECTORS(compare, with)\ + if(!compareVectors(compare, with)) return false; + + vector2d vec(5, 5); + vector2d otherVec(10, 20); + if(!equals(vec.getDistanceFrom(otherVec), (T)15.8113883)) + { + logTestString("vector2d::getDistanceFrom() failed\n"); + assert_log(0); + return false; + } + + otherVec = vector2d(1,2); + otherVec[0] = vec[0]; + otherVec[1] = vec[1]; + if(!vec.equals(otherVec)) + { + logTestString("vector2d::operator[] failed\n"); + assert_log(0); + return false; + } + + vec.rotateBy(45); // Test implicit (0, 0) center + COMPARE_VECTORS(vec, vector2d(0, (T)7.0710678118654755)); + + vec.normalize(); + COMPARE_VECTORS(vec, vector2d(0, (T)1.0000000461060017)); + + vec.set(10, 10); + vector2d center(5, 5); + vec.rotateBy(-5, center); + // -5 means rotate clockwise slightly, so expect the X to increase + // slightly and the Y to decrease slightly. + COMPARE_VECTORS(vec, vector2d((T)10.416752204197017, (T)9.5451947767204359)); + + vec.set(5, 5); + vec.normalize(); + COMPARE_VECTORS(vec, vector2d((T)0.7071068137884140, (T)0.7071068137884140)); + + vec.set(5, 5); + otherVec.set(10, 20); + + logTestString("vector2d interpolation\n"); + vector2d interpolated; + (void)interpolated.interpolate(vec, otherVec, 0.f); + COMPARE_VECTORS(interpolated, otherVec); // 0.f means all the second vector + + (void)interpolated.interpolate(vec, otherVec, 0.25f); + COMPARE_VECTORS(interpolated, vector2d((T)8.75, (T)16.25)); + + (void)interpolated.interpolate(vec, otherVec, 0.75f); + COMPARE_VECTORS(interpolated, vector2d((T)6.25, (T)8.75)); + + (void)interpolated.interpolate(vec, otherVec, 1.f); + COMPARE_VECTORS(interpolated, vec); // 1.f means all the first vector + + + interpolated = vec.getInterpolated(otherVec, 0.f); + COMPARE_VECTORS(interpolated, otherVec); // 0.f means all the second vector + + interpolated = vec.getInterpolated(otherVec, 0.25f); + COMPARE_VECTORS(interpolated, vector2d((T)8.75, (T)16.25)); + + interpolated = vec.getInterpolated(otherVec, 0.75f); + COMPARE_VECTORS(interpolated, vector2d((T)6.25, (T)8.75)); + + interpolated = vec.getInterpolated(otherVec, 1.f); + COMPARE_VECTORS(interpolated, vec); // 1.f means all the first vector + + + logTestString("vector2d quadratic interpolation\n"); + vector2d thirdVec(20, 10); + interpolated = vec.getInterpolated_quadratic(otherVec, thirdVec, 0.f); + COMPARE_VECTORS(interpolated, vec); // 0.f means all the 1st vector + + interpolated = vec.getInterpolated_quadratic(otherVec, thirdVec, 0.25f); + COMPARE_VECTORS(interpolated, vector2d((T)7.8125, (T)10.9375)); + + interpolated = vec.getInterpolated_quadratic(otherVec, thirdVec, 0.5f); + COMPARE_VECTORS(interpolated, vector2d((T)11.25, (T)13.75)); + + interpolated = vec.getInterpolated_quadratic(otherVec, thirdVec, 0.75f); + COMPARE_VECTORS(interpolated, vector2d((T)15.3125, (T)13.4375)); + + interpolated = vec.getInterpolated_quadratic(otherVec, thirdVec, 1.f); + COMPARE_VECTORS(interpolated, thirdVec); // 1.f means all the 3rd vector + + // check if getAngle returns values matching those of the double precision version + logTestString("vector2d getAngle\n"); + for (s32 i=0; i<200; ++i) + { + core::vector2d tmp((T)-1, (T)(-100+i)); + core::vector2d ref(-1, -100+i); + if (!equals(tmp.getAngle(),ref.getAngle(), 0.0003)) + { + logTestString("\nERROR: angle %.16f != angle %.16f\n", + tmp.getAngle(), ref.getAngle()); + return false; + } + f32 val = atan2f((float)tmp.Y, (float)tmp.X)*core::RADTODEG; + if (val<=0) + val=-val; + else + val=360-val; + if (!equals((f32)tmp.getAngle(),val, 0.5f)) + { + logTestString("\nERROR: angle %.16f != atan2 %.16f\n vector %.16f, %.16f\n", + tmp.getAngle(), val, tmp.X, tmp.Y); + return false; + } + tmp = core::vector2d((T)1, (T)(-100+i)); + ref = core::vector2d(1, -100+i); + if (!equals(tmp.getAngle(),ref.getAngle(), 0.0003)) + { + logTestString("\nERROR: angle %.16f != angle %.16f\n", + tmp.getAngle(), ref.getAngle()); + return false; + } + val = atan2f((f32)tmp.Y, (f32)tmp.X)*core::RADTODEG; + if (val<=0) + val=-val; + else + val=360-val; + if (!equals((f32)tmp.getAngle(),val, 0.5f)) + { + logTestString("\nERROR: angle %.16f != atan2 %.16f\n vector %.16f, %.16f\n", + tmp.getAngle(), val, tmp.X, tmp.Y); + return false; + } + } + core::vector2d tmp(0, -100); + core::vector2d ref(0, -100); + if (!equals(tmp.getAngle(),ref.getAngle())) + { + logTestString("\nERROR: angle %.16f != angle %.16f\n", + tmp.getAngle(), ref.getAngle()); + return false; + } + tmp = core::vector2d(0, 100); + ref = core::vector2d(0, 100); + if (!equals(tmp.getAngle(),ref.getAngle())) + { + logTestString("\nERROR: angle %.16f != angle %.16f\n", + tmp.getAngle(), ref.getAngle()); + return false; + } + tmp = core::vector2d(static_cast(-1.53080559e-16), static_cast(2.49999523)); + ref = core::vector2d(-1.53080559e-16, 2.49999523); + if (!equals(tmp.getAngle(),ref.getAngle())) + { + logTestString("\nERROR: angle %.16f != angle %.16f\n", + tmp.getAngle(), ref.getAngle()); + return false; + } + + core::vector2d zeroZero(0, 0); + core::vector2d oneOne(1, 1); + // Check if comparing (0.0, 0.0) with (1.0, 1.0) returns false. + if(zeroZero == oneOne) + { + logTestString("\nERROR: vector2d %.16f, %.16f == vector2d %.16f, %.16f\n", + (f64)zeroZero.X, (f64)zeroZero.Y, (f64)oneOne.X, (f64)oneOne.Y); + return false; + } + + return true; +} + +/** Test the functionality of vector2d, particularly methods that + involve calculations done using different precision than . + Note that all reference vector2ds are creating using double precision + values cast to (T), as we need to test . */ +bool testVector2d(void) +{ + bool f32Success = doTests(); + if(f32Success) + logTestString("vector2df tests passed\n\n"); + else + logTestString("\n*** vector2df tests failed ***\n\n"); + + bool f64Success = doTests(); + if(f64Success) + logTestString("vector2d tests passed\n\n"); + else + logTestString("\n*** vector2d tests failed ***\n\n"); + + bool s32Success = doTests(); + if(s32Success) + logTestString("vector2di tests passed\n\n"); + else + logTestString("\n*** vector2di tests failed ***\n\n"); + + return f32Success && f64Success && s32Success; +} + diff --git a/tests/testVector3d.cpp b/tests/testVector3d.cpp new file mode 100644 index 00000000..a94d0303 --- /dev/null +++ b/tests/testVector3d.cpp @@ -0,0 +1,312 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; + +#define EQUAL_VECTORS(compare, with)\ + if(!equalVectors(cmp_equal >(compare), with)) {assert(false); return false;} + +#define LESS_VECTORS(compare, with)\ + if(!equalVectors(cmp_less >(compare), with)) return false; + +#define LESS_EQUAL_VECTORS(compare, with)\ + if(!equalVectors(cmp_less_equal >(compare), with)) return false; + +#define MORE_VECTORS(compare, with)\ + if(!equalVectors(cmp_more >(compare), with)) return false; + +#define MORE_EQUAL_VECTORS(compare, with)\ + if(!equalVectors(cmp_more_equal >(compare), with)) return false; + +// check if the vector contains a NAN (a==b is guaranteed to return false in this case) +template +static bool is_nan(const core::vector3d &vec ) +{ + return ( !(vec.X == vec.X) + || !(vec.Y == vec.Y) + || !(vec.Z == vec.Z) ); +} + +template +struct cmp_less +{ + cmp_less(const T& a) : val(a) {} + bool operator()(const T& other) const + { + return val +struct cmp_less_equal +{ + cmp_less_equal(const T& a) : val(a) {} + bool operator()(const T& other) const + { + return val<=other; + } + const char* getName() const {return "<=";} + const T val; +}; + +template +struct cmp_more +{ + cmp_more(const T& a) : val(a) {} + bool operator()(const T& other) const + { + return val>other; + } + const char* getName() const {return ">";} + const T val; +}; + +template +struct cmp_more_equal +{ + cmp_more_equal(const T& a) : val(a) {} + bool operator()(const T& other) const + { + return val>=other; + } + const char* getName() const {return ">=";} + const T val; +}; + +template +struct cmp_equal +{ + cmp_equal(const T& a) : val(a) {} + bool operator()(const T& other) const + { + return val.equals(other); + } + const char* getName() const {return "==";} + const T val; +}; + +template +static bool equalVectors(const S& compare, + const core::vector3d & with) +{ + if (!compare(with)) + { + logTestString("\nERROR: vector3d %.16f, %.16f, %.16f %s vector3d %.16f, %.16f, %.16f\n", + (f64)compare.val.X, (f64)compare.val.Y, (f64)compare.val.Z, compare.getName(), + (f64)with.X, (f64)with.Y, (f64)with.Z); + assert_log(compare(with)); + return false; + } + + return true; +} + +template +static bool checkInterpolation() +{ + core::vector3d vec(5, 5, 0); + core::vector3d otherVec(10, 20, 40); + + vector3d interpolated; + (void)interpolated.interpolate(vec, otherVec, 0.f); + EQUAL_VECTORS(interpolated, otherVec); // 0.f means all the second vector + + (void)interpolated.interpolate(vec, otherVec, 0.25f); + EQUAL_VECTORS(interpolated, vector3d((T)8.75, (T)16.25, 30)); + + (void)interpolated.interpolate(vec, otherVec, 0.75f); + EQUAL_VECTORS(interpolated, vector3d((T)6.25, (T)8.75, 10)); + + (void)interpolated.interpolate(vec, otherVec, 1.f); + EQUAL_VECTORS(interpolated, vec); // 1.f means all the first vector + + + interpolated = vec.getInterpolated(otherVec, 0.f); + EQUAL_VECTORS(interpolated, otherVec); // 0.f means all the second vector + + interpolated = vec.getInterpolated(otherVec, 0.25f); + EQUAL_VECTORS(interpolated, vector3d((T)8.75, (T)16.25, 30)); + + interpolated = vec.getInterpolated(otherVec, 0.75f); + EQUAL_VECTORS(interpolated, vector3d((T)6.25, (T)8.75, 10)); + + interpolated = vec.getInterpolated(otherVec, 1.f); + EQUAL_VECTORS(interpolated, vec); // 1.f means all the first vector + + + vector3d thirdVec(20, 10, -30); + interpolated = vec.getInterpolated_quadratic(otherVec, thirdVec, 0.f); + EQUAL_VECTORS(interpolated, vec); // 0.f means all the 1st vector + + interpolated = vec.getInterpolated_quadratic(otherVec, thirdVec, 0.25f); + EQUAL_VECTORS(interpolated, vector3d((T)7.8125, (T)10.9375, (T)13.125)); + + interpolated = vec.getInterpolated_quadratic(otherVec, thirdVec, 0.5f); + EQUAL_VECTORS(interpolated, vector3d((T)11.25, (T)13.75, (T)12.5)); + + interpolated = vec.getInterpolated_quadratic(otherVec, thirdVec, 0.75f); + EQUAL_VECTORS(interpolated, vector3d((T)15.3125, (T)13.4375, (T)-1.875)); + + interpolated = vec.getInterpolated_quadratic(otherVec, thirdVec, 1.f); + EQUAL_VECTORS(interpolated, thirdVec); // 1.f means all the 3rd vector + return true; +} + +template +static bool checkAngleCalculations() +{ + core::vector3d vec(5, 5, 0); + EQUAL_VECTORS(vec.getHorizontalAngle(), vector3d(315, (T)90.0, 0)); + EQUAL_VECTORS(vec.getSphericalCoordinateAngles(), vector3d((T)45.0, 0, 0)); + return true; +} + +template +static bool checkRotations() +{ + core::vector3d vec(5, 5, 0); + vector3d center(0, 0, 0); + + vec.rotateXYBy(45, center); + EQUAL_VECTORS(vec, vector3d(0, (T)7.0710678118654755, 0)); + + vec.normalize(); + // TODO: This breaks under Linux/gcc due to FP differences, but is no bug + if (((T)0.5f)>0.f) + EQUAL_VECTORS(vec, vector3d(0, (T)1.0, 0)); + + 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 + // slightly and the Y to decrease slightly. + EQUAL_VECTORS(vec, vector3d((T)10.416752204197017, (T)9.5451947767204359, 10)); + + vec.set(10, 10, 10); + center.set(5, 10, 5); + vec.rotateXZBy(-5, center); + EQUAL_VECTORS(vec, vector3d((T)10.416752204197017, 10, (T)9.5451947767204359)); + + vec.set(10, 10, 10); + center.set(10, 5, 5); + vec.rotateYZBy(-5, center); + EQUAL_VECTORS(vec, vector3d(10, (T)10.416752204197017, (T)9.5451947767204359)); + + vec.set(5, 5, 0); + vec.normalize(); + EQUAL_VECTORS(vec, vector3d((T)0.70710681378841400, (T)0.70710681378841400, 0)); + return true; +} + +template +static bool doTests() +{ + vector3d vec(-5, 5, 0); + vector3d otherVec((T)-5.1, 5, 0); + + if(!vec.equals(otherVec, (T)0.1)) + { + logTestString("vector3d::equals failed\n"); + assert_log(0); + return false; + } + + otherVec = vector3d(1,2,3); + otherVec[0] = vec[0]; + otherVec[1] = vec[1]; + otherVec[2] = vec[2]; + if(!vec.equals(otherVec)) + { + logTestString("vector3d::operator[] failed\n"); + assert_log(0); + return false; + } + + vec.set(5, 5, 0); + otherVec.set(10, 20, 0); + if(!equals(vec.getDistanceFrom(otherVec), (T)15.8113883)) + { + logTestString("vector3d::getDistanceFrom() failed\n"); + assert_log(0); + return false; + } + + if (!checkRotations()) + return false; + + if (!checkInterpolation()) + return false; + + if (!checkAngleCalculations()) + return false; + + vec.set(0,0,0); + vec.setLength(99); + if ( is_nan(vec) ) + return false; + + core::vector3d zeroZero(0, 0, 0); + core::vector3d oneOne(1, 1, 1); + // Check if comparing (0.0, 0.0, 0.0) with (1.0, 1.0, 1.0) returns false. + if(zeroZero == oneOne) + { + logTestString("\nERROR: vector3d %.16f, %.16f, %.16f == vector3d %.16f, %.16f, %.16f\n", + (f64)zeroZero.X, (f64)zeroZero.Y, (f64)zeroZero.Z, + (f64)oneOne.X, (f64)oneOne.Y, (f64)oneOne.Z); + return false; + } + + vec.set(5, 5, 0); + + otherVec.set(10, 20, 40); + LESS_VECTORS(vec, otherVec); + LESS_EQUAL_VECTORS(vec, otherVec); + MORE_VECTORS(otherVec, vec); + MORE_EQUAL_VECTORS(otherVec, vec); + + vec.set(-1,-1,1); + otherVec.set(1,-1,1); + LESS_VECTORS(vec, otherVec); + LESS_EQUAL_VECTORS(vec, otherVec); + MORE_VECTORS(otherVec, vec); + MORE_EQUAL_VECTORS(otherVec, vec); + + LESS_EQUAL_VECTORS(vec, vec); + MORE_EQUAL_VECTORS(vec, vec); + + return true; +} + + +/** Test the functionality of vector3d, particularly methods that + involve calculations done using different precision than . + Note that all reference vector3ds are creating using double precision + values cast to (T), as we need to test . */ +bool testVector3d(void) +{ + const bool f32Success = doTests(); + if (f32Success) + logTestString("vector3df tests passed\n\n"); + else + logTestString("\n*** vector3df tests failed ***\n\n"); + + const bool f64Success = doTests(); + if (f64Success) + logTestString("vector3d tests passed\n\n"); + else + logTestString("\n*** vector3d tests failed ***\n\n"); + + const bool s32Success = doTests(); + if (s32Success) + logTestString("vector3di tests passed\n\n"); + else + logTestString("\n*** vector3di tests failed ***\n\n"); + + return f32Success && f64Success && s32Success; +} + diff --git a/tests/testXML.cpp b/tests/testXML.cpp new file mode 100644 index 00000000..29a210d4 --- /dev/null +++ b/tests/testXML.cpp @@ -0,0 +1,169 @@ +// Copyright (C) 2009-2012 Christian Stehno +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; + +bool simple_xml( irr::io::IFileSystem * fs ) +{ + io::IXMLReaderUTF8* reader = fs->createXMLReaderUTF8("media/test.xml"); + if (!reader) + { + logTestString("Could not create XML reader.\n"); + return false; + } + + const core::stringc expected[] = { + "a", "b", "c" + }; + + bool retVal = true; + u32 i=0; + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if (expected[i++] != reader->getNodeName()) + { + logTestString("Did not find expected string in XML element name.\n"); + retVal = false; + break; + } + } + } + + reader->drop(); + return retVal; +} + +// CDATA should return everything between "![CDATA[" and "]]>" as it's in the file +bool cdata( irr::io::IFileSystem * fs ) +{ + io::IXMLReaderUTF8* reader = fs->createXMLReaderUTF8("media/cdata.xml"); + if (!reader) + { + logTestString("Could not create XML reader.\n"); + return false; + } + + const core::stringc textNode("text"); + core::array< core::stringc > compareStrings; + compareStrings.push_back("simple"); + compareStrings.push_back(""); + compareStrings.push_back("] ]> "); + compareStrings.push_back("]\n]> "); + compareStrings.push_back("\nNewlines\n\tand tabs\n\t\tgogogo"); + compareStrings.push_back("&&#@#$%*()@#$%*()#$%*("); + compareStrings.push_back("& & && &&& &a &ü &ä &ö &&#"); + + bool result = true; + size_t count = 0; + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_ELEMENT) + { + if ( core::stringc(reader->getNodeName()) == textNode ) + { + while(reader->read()) + { + if (reader->getNodeType() == io::EXN_CDATA) + { + core::stringc data = reader->getNodeData(); + core::stringc name = reader->getNodeName(); + if ( count == compareStrings.size() ) + { + logTestString("too many cdata elements for reading in %s:%d\n", __FILE__, __LINE__); + } + else if ( count < compareStrings.size() ) + { + core::stringc cmpString(compareStrings[count]); + + // some (unused) variables to ease debugging + // const c8* dataRaw = data.c_str(); + // const c8* cmpRaw = cmpString.c_str(); + if ( cmpString != data ) + { + result = false; + logTestString("cdata read failed for string %d in %s:%d\n", count, __FILE__, __LINE__); + } + } + ++count; + } + if ( reader->getNodeType() == io::EXN_ELEMENT_END ) + { + break; + } + } + } + } + } + + reader->drop(); + return result; +} + +bool attributeValues(irr::io::IFileSystem * fs) +{ + io::IXMLReaderUTF8* reader = fs->createXMLReaderUTF8("media/attributes.xml"); + if (!reader) + { + logTestString("Could not create XML reader.\n"); + return false; + } + + bool result = true; + bool hasNode = false; + while (reader->read()) + { + if (io::EXN_ELEMENT == reader->getNodeType() ) + { + if ( core::stringc(reader->getNodeName()) == core::stringc("element_position") ) + { + hasNode = true; + int id1 = reader->getAttributeValueAsInt("id1"); + if ( id1 != 152722522 ) + { + logTestString("id1 is %d in %s:%d\n", id1, __FILE__, __LINE__); + result = false; + } + int id2 = reader->getAttributeValueAsInt("id2"); + result &= id2 == 3; + int x = reader->getAttributeValueAsInt("x"); + result &= x == 301; + int y = reader->getAttributeValueAsInt("y"); + result &= y == 118; + } + } + } + + if ( !hasNode ) + { + logTestString("missing node in xml in %s:%d\n", __FILE__, __LINE__); + return false; + } + + reader->drop(); + return result; +} + +/** Tests for XML handling */ +bool testXML(void) +{ + IrrlichtDevice *device = createDevice(video::EDT_NULL, dimension2du(400, 200)); + + bool result = true; + + logTestString("Test simple XML reader features.\n"); + result &= simple_xml(device->getFileSystem()); + logTestString("Test XML reader CDATA support.\n"); + result &= cdata(device->getFileSystem()); + logTestString("Test XML reader attribute support.\n"); + result &= attributeValues(device->getFileSystem()); + + device->closeDevice(); + device->run(); + device->drop(); + return result; +} diff --git a/tests/testaabbox.cpp b/tests/testaabbox.cpp new file mode 100644 index 00000000..01c0815d --- /dev/null +++ b/tests/testaabbox.cpp @@ -0,0 +1,405 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; + +// These tests are also only called for f32 and f64, due to conversion problems +// in the respective methods. +template +static bool checkCollisions() +{ + aabbox3d one(0,0,0,4,4,4); + aabbox3d two(2,2,2,4,4,4); + + if (two.getInterpolated(one, 1) != two) + { + logTestString("aabbox3d interpolation wrong on 1\n"); + return false; + } + if (two.getInterpolated(one, 0) != one) + { + logTestString("aabbox3d interpolation wrong on 0\n"); + return false; + } + aabbox3d three(two.getInterpolated(one, 0.5f)); + if (two == one) + { + logTestString("aabbox3d interpolation wrong on 0.5 (right)\n"); + return false; + } + if (two == three) + { + logTestString("aabbox3d interpolation wrong on 0.5 (left)\n"); + return false; + } + three.reset(aabbox3d(2,2,2,5,5,5)); + if (!two.isFullInside(one)) + { + logTestString("small aabbox3d is not fully inside\n"); + return false; + } + if (three.isFullInside(one)) + { + logTestString("large aabbox3d is fully inside\n"); + return false; + } + + if (!two.intersectsWithBox(one)) + { + logTestString("small aabbox3d does not intersect\n"); + return false; + } + if (!three.intersectsWithBox(one)) + { + logTestString("large aabbox3d does not intersect\n"); + return false; + } + + core::line3d line(-2,-2,-2,2,2,2); + if (!one.intersectsWithLine(line)) + { + logTestString("aabbox3d does not intersect with line(1)\n"); + return false; + } + line.end.set(2,2,10); + if (!one.intersectsWithLine(line)) + { + logTestString("aabbox3d does not intersect with line(2)\n"); + return false; + } + line.end.set(0,2,10); + if (one.intersectsWithLine(line)) + { + logTestString("aabbox3d does intersect with line(3)\n"); + return false; + } + return true; +} + +template +static bool checkPoints() +{ + aabbox3d one(-1,-2,-3,2,2,2); + + if (!one.isPointInside(core::vector3d(-1,-2,-3))) + { + logTestString("isPointInside failed with min vertex\n"); + return false; + } + if (!one.isPointInside(core::vector3d(-1,2,-3))) + { + logTestString("isPointInside failed with other min vertex\n"); + return false; + } + if (!one.isPointInside(core::vector3d(2,-2,2))) + { + logTestString("isPointInside failed with other max vertex\n"); + return false; + } + if (!one.isPointInside(core::vector3d(2,2,2))) + { + logTestString("isPointInside failed with max vertex\n"); + return false; + } + if (!one.isPointInside(core::vector3d(0,0,0))) + { + logTestString("isPointInside failed with origin\n"); + return false; + } + if (!one.isPointInside(core::vector3d((T)1.2,-1,1))) + { + logTestString("isPointInside failed with random point inside\n"); + return false; + } + if (one.isPointInside(core::vector3d(-2,-2,-3))) + { + logTestString("isPointInside failed near min vertex\n"); + return false; + } + if (one.isPointInside(core::vector3d(2,3,2))) + { + logTestString("isPointInside failed near max vertex\n"); + return false; + } + if (one.isPointInside(core::vector3d(3,0,0))) + { + logTestString("isPointInside failed near origin\n"); + return false; + } + if (one.isPointInside(core::vector3d((T)10.2,-1,1))) + { + logTestString("isPointInside failed with random point outside\n"); + return false; + } + if (one.isPointTotalInside(core::vector3d(-1,-2,-3))) + { + logTestString("isPointTotalInside failed with min vertex\n"); + return false; + } + if (one.isPointTotalInside(core::vector3d(-1,2,-3))) + { + logTestString("isPointTotalInside failed with other min vertex\n"); + return false; + } + if (one.isPointTotalInside(core::vector3d(2,-2,2))) + { + logTestString("isPointTotalInside failed with other max vertex\n"); + return false; + } + if (one.isPointTotalInside(core::vector3d(2,2,2))) + { + logTestString("isPointTotalInside failed with max vertex\n"); + return false; + } + if (!one.isPointTotalInside(core::vector3d(0,0,0))) + { + logTestString("isPointTotalInside failed with origin\n"); + return false; + } + if (!one.isPointTotalInside(core::vector3d((T)1.2,-1,1))) + { + logTestString("isPointTotalInside failed with random point inside\n"); + return false; + } + if (one.isPointTotalInside(core::vector3d((T)10.2,-1,1))) + { + logTestString("isPointTotalInside failed with random point outside\n"); + return false; + } + + core::plane3d plane(core::vector3d(0,0,-1), -10); + if (one.classifyPlaneRelation(plane) != core::ISREL3D_BACK) + { + logTestString("box not behind\n"); + return false; + } + plane.D=0; + if (one.classifyPlaneRelation(plane) != core::ISREL3D_CLIPPED) + { + logTestString("box not clipped\n"); + return false; + } + plane.D=10; + if (one.classifyPlaneRelation(plane) != core::ISREL3D_FRONT) + { + logTestString("box not in front\n"); + return false; + } + return true; +} + +template +static bool doTests() +{ + aabbox3d empty; + aabbox3d one(-1,-1,-1,1,1,1); + if (empty != one) + { + logTestString("default aabbox3d wrong, or comparison failed\n"); + return false; + } + if (empty.getCenter() != core::vector3d(0,0,0)) + { + logTestString("default aabbox3d has wrong Center\n"); + return false; + } + if (empty.getExtent() != core::vector3d(2,2,2)) + { + logTestString("default aabbox3d has wrong Extent\n"); + return false; + } + if (!core::equals(empty.getRadius(), (T)sqrt(3.0))) + { + logTestString("default aabbox3d has wrong radius\n"); + return false; + } + if (empty.isEmpty()) + { + logTestString("default aabbox3d is empty\n"); + return false; + } + if (empty.getVolume() != 8) + { + logTestString("default aabbox3d has wrong volume\n"); + return false; + } + if (empty.getArea() != 24) + { + logTestString("default aabbox3d has wrong area\n"); + return false; + } + aabbox3d two(core::vector3d(-1,-1,-1),core::vector3d(2,2,2)); + if (empty == two) + { + logTestString("empty aabbox3d too large, or comparison failed\n"); + return false; + } + if (two.getCenter() != core::vector3d((T)0.5,(T)0.5,(T)0.5)) + { + logTestString("extended aabbox3d has wrong Center\n"); + return false; + } + if (two.getExtent() != core::vector3d(3,3,3)) + { + logTestString("extended aabbox3d has wrong Extent\n"); + return false; + } + if (!core::equals(two.getRadius(), (T)sqrt(27./4.))) + { + logTestString("extended aabbox3d has wrong radius\n"); + return false; + } + if (two.isEmpty()) + { + logTestString("extended aabbox3d is empty\n"); + return false; + } + if (two.getVolume() != 27) + { + logTestString("extended aabbox3d has wrong volume\n"); + return false; + } + if (two.getArea() != 54) + { + logTestString("extended aabbox3d has wrong area\n"); + return false; + } + one.reset(1,1,1); + if (one==empty) + { + logTestString("reset failed, or comparison failed\n"); + return false; + } + if (one.getCenter() != core::vector3d(1,1,1)) + { + logTestString("singular aabbox3d has wrong Center\n"); + return false; + } + if (one.getExtent() != core::vector3d(0,0,0)) + { + logTestString("singular aabbox3d has Extent\n"); + return false; + } + if (one.getRadius() != 0) + { + logTestString("singular aabbox3d has radius\n"); + return false; + } + if (!one.isEmpty()) + { + logTestString("empty aabbox3d is not empty\n"); + return false; + } + if (one.getVolume() != 0) + { + logTestString("empty aabbox3d has wrong volume\n"); + return false; + } + if (one.getArea() != 0) + { + logTestString("empty aabbox3d has wrong area\n"); + return false; + } + one.addInternalPoint(core::vector3d(-1,-1,-1)); + if (one!=empty) + { + logTestString("addInternalPoint failed, creating default bbox\n"); + return false; + } + one.reset(1,1,1); + one.reset(empty); + if (one!=empty) + { + logTestString("reset with bbox failed, creating default bbox\n"); + return false; + } + one.addInternalPoint(core::vector3d(2,2,2)); + if (one != two) + { + logTestString("addInternalPoint for aabbox3d failed.\n"); + return false; + } + one.addInternalBox(empty); + if (one != two) + { + logTestString("addInternalBox with smaller box failed.\n"); + return false; + } + one.addInternalBox(two); + if (one != two) + { + logTestString("addInternalBox with same box failed.\n"); + return false; + } + one.addInternalPoint(-1,-2,-3); + two.addInternalPoint(-1,-2,-3); + empty.addInternalBox(one); + if (empty != two) + { + logTestString("addInternalBox with larger box failed\n"); + return false; + } + if (one.getCenter() != core::vector3d((T)0.5,0,(T)-0.5)) + { + logTestString("large aabbox3d has wrong Center\n"); + return false; + } + if (one.getExtent() != core::vector3d(3,4,5)) + { + logTestString("large aabbox3d has wrong Extent\n"); + return false; + } + if (!core::equals(one.getRadius(), (T)sqrt(50./4.))) + { + logTestString("large aabbox3d has wrong radius\n"); + return false; + } + if (one.isEmpty()) + { + logTestString("large aabbox3d is empty\n"); + return false; + } + if (one.getVolume() != 60) + { + logTestString("large aabbox3d has wrong volume\n"); + return false; + } + if (one.getArea() != 94) + { + logTestString("large aabbox3d has wrong area\n"); + return false; + } + if (!checkPoints()) + return false; + return true; +} + + +/** Test the functionality of aabbox3d. */ +bool testaabbox3d(void) +{ + bool f32Success = doTests(); + f32Success &= checkCollisions(); + if(f32Success) + logTestString("aabbox3d tests passed\n\n"); + else + logTestString("\n*** aabbox3d tests failed ***\n\n"); + + bool f64Success = doTests(); + f64Success &= checkCollisions(); + if(f64Success) + logTestString("aabbox3d tests passed\n\n"); + else + logTestString("\n*** aabbox3d tests failed ***\n\n"); + + bool s32Success = doTests(); + if(s32Success) + logTestString("aabbox3d tests passed\n\n"); + else + logTestString("\n*** aabbox3d tests failed ***\n\n"); + + return f32Success && f64Success && s32Success; +} diff --git a/tests/tests-last-passed-at.txt b/tests/tests-last-passed-at.txt new file mode 100644 index 00000000..1034815d --- /dev/null +++ b/tests/tests-last-passed-at.txt @@ -0,0 +1,4 @@ +Tests finished. 72 tests of 72 passed. +Compiled as DEBUG +Test suite pass at GMT Fri Jan 3 17:05:41 2020 + diff --git a/tests/tests-readme.txt b/tests/tests-readme.txt new file mode 100644 index 00000000..c40b8171 --- /dev/null +++ b/tests/tests-readme.txt @@ -0,0 +1,227 @@ + +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 and spot +regressions. + +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. + +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). + + +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 + + +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 interesting 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, often around 99% match (of total colour values across all +pixels). 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. + +Running specific tests +====================== +The app takes two parameters. First is the test to start with (starting at 0 +anddefaulting to 0), the second is the number of tests to run (beginning with +the one given as first parameter). If the second parameter is not given, all +existing tests are run (again starting with the first parameter). So, starting +the test suite without a parameter will really run all tests. Another special +parameter is '--list', which outputs a list of all existing tests and their +respective number. + +For debugging purposes it can make sense to run a test without spawning a +separate process for each test case. This can be switched off by a boolean flag +in main.cpp ('spawn=false'). + +Currently implemented tests +=========================== +000. disambiguateTextures +001. testIrrArray +002. testIrrMap +003. testIrrList +004. exports +005. irrCoreEquals +006. testIrrString +007. testLine2d +008. matrixOps +009. testDimension2d +010. testVector2d +011. testVector3d +012. testQuaternion +013. testS3DVertex +014. testaabbox3d +015. color +016. testTriangle3d +017. vectorPositionDimension2d +018. filesystem +019. archiveReader +020. testXML +021. serializeAttributes +022. fast_atof +023. loadTextures +024. collisionResponseAnimator +025. enumerateImageManipulators +026. removeCustomAnimator +027. sceneCollisionManager +028. sceneNodeAnimator +029. meshLoaders +030. testTimer +031. softwareDevice +032. b3dAnimation +033. burningsVideo +034. billboards +035. createImage +036. cursorSetVisible +037. flyCircleAnimator +038. guiDisabledMenu +039. makeColorKeyTexture +040. md2Animation +041. meshTransform +042. skinnedMesh +043. testGeometryCreator +044. writeImageToFile +045. ioScene +046. videoDriver +047. screenshot +048. drawPixel +049. drawRectOutline +050. drawVertexPrimitive +051. material +052. renderTargetTexture +053. textureFeatures +054. textureRenderStates +055. transparentMaterials +056. userclipplane +057. antiAliasing +058. draw2DImage +059. lights +060. twodmaterial +061. viewPort +062. mrt +063. projectionMatrix +064. planeMatrix +065. terrainSceneNode +066. lightMaps +067. triangleSelector + diff --git a/tests/tests.cbp b/tests/tests.cbp new file mode 100644 index 00000000..f5d2dd10 --- /dev/null +++ b/tests/tests.cbp @@ -0,0 +1,159 @@ + + + + + + diff --git a/tests/tests.workspace b/tests/tests.workspace new file mode 100644 index 00000000..069224f8 --- /dev/null +++ b/tests/tests.workspace @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tests/tests_vc10.sln b/tests/tests_vc10.sln new file mode 100644 index 00000000..d94b7c13 --- /dev/null +++ b/tests/tests_vc10.sln @@ -0,0 +1,76 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tests", "tests_vc10.vcxproj", "{2A1DE18B-F678-4A94-A996-E848E20B2983}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Irrlicht", "..\source\Irrlicht\Irrlicht10.0.vcxproj", "{E08E042A-6C45-411B-92BE-3CC31331019F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release - Fast FPU|Win32 = Release - Fast FPU|Win32 + Release - Fast FPU|x64 = Release - Fast FPU|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + Static lib - Debug|Win32 = Static lib - Debug|Win32 + Static lib - Debug|x64 = Static lib - Debug|x64 + Static lib - Release - Fast FPU|Win32 = Static lib - Release - Fast FPU|Win32 + Static lib - Release - Fast FPU|x64 = Static lib - Release - Fast FPU|x64 + Static lib - Release|Win32 = Static lib - Release|Win32 + Static lib - Release|x64 = Static lib - Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Debug|Win32.ActiveCfg = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Debug|Win32.Build.0 = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Debug|x64.ActiveCfg = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Debug|x64.Build.0 = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release - Fast FPU|x64.Build.0 = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release|Win32.ActiveCfg = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release|Win32.Build.0 = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release|x64.ActiveCfg = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release|x64.Build.0 = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Debug|x64.Build.0 = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release|Win32.Build.0 = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release|x64.ActiveCfg = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release|x64.Build.0 = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.ActiveCfg = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.Build.0 = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.ActiveCfg = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.Build.0 = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.ActiveCfg = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.Build.0 = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.ActiveCfg = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.Build.0 = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.ActiveCfg = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.Build.0 = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.ActiveCfg = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.Build.0 = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.ActiveCfg = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.Build.0 = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.ActiveCfg = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.Build.0 = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.Build.0 = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.ActiveCfg = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.Build.0 = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.ActiveCfg = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.Build.0 = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.ActiveCfg = Static lib - Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.Build.0 = Static lib - Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/tests_vc10.vcxproj b/tests/tests_vc10.vcxproj new file mode 100644 index 00000000..8e225799 --- /dev/null +++ b/tests/tests_vc10.vcxproj @@ -0,0 +1,239 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + tests + {2A1DE18B-F678-4A94-A996-E848E20B2983} + tests + + + + Application + MultiByte + true + Windows7.1SDK + + + Application + MultiByte + true + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\bin\Win32-VisualStudio\ + ..\bin\Win64-VisualStudio\ + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + ..\bin\Win32-VisualStudio\ + ..\bin\Win64-VisualStudio\ + + + + Disabled + ..\include;%(AdditionalIncludeDirectories) + true + EnableFastChecks + MultiThreadedDebugDLL + Level3 + + + ..\lib\Win32-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + true + + + + + + + Disabled + ..\include;%(AdditionalIncludeDirectories) + EnableFastChecks + MultiThreadedDebugDLL + Level3 + + + ..\lib\Win64-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + true + + + + + + + MaxSpeed + true + ..\include;%(AdditionalIncludeDirectories) + MultiThreadedDLL + true + Level3 + + + ..\lib\Win32-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + false + true + true + + + + + + + MaxSpeed + true + ..\include;%(AdditionalIncludeDirectories) + MultiThreadedDLL + true + Level3 + + + ..\lib\Win64-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + false + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {e08e042a-6c45-411b-92be-3cc31331019f} + false + + + + + + diff --git a/tests/tests_vc11.sln b/tests/tests_vc11.sln new file mode 100644 index 00000000..85e0fa4e --- /dev/null +++ b/tests/tests_vc11.sln @@ -0,0 +1,76 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tests", "tests_vc11.vcxproj", "{2A1DE18B-F678-4A94-A996-E848E20B2983}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Irrlicht", "..\source\Irrlicht\Irrlicht11.0.vcxproj", "{E08E042A-6C45-411B-92BE-3CC31331019F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release - Fast FPU|Win32 = Release - Fast FPU|Win32 + Release - Fast FPU|x64 = Release - Fast FPU|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + Static lib - Debug|Win32 = Static lib - Debug|Win32 + Static lib - Debug|x64 = Static lib - Debug|x64 + Static lib - Release - Fast FPU|Win32 = Static lib - Release - Fast FPU|Win32 + Static lib - Release - Fast FPU|x64 = Static lib - Release - Fast FPU|x64 + Static lib - Release|Win32 = Static lib - Release|Win32 + Static lib - Release|x64 = Static lib - Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Debug|Win32.ActiveCfg = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Debug|Win32.Build.0 = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Debug|x64.ActiveCfg = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Debug|x64.Build.0 = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release - Fast FPU|x64.Build.0 = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release|Win32.ActiveCfg = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release|Win32.Build.0 = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release|x64.ActiveCfg = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release|x64.Build.0 = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Debug|x64.Build.0 = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release|Win32.Build.0 = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release|x64.ActiveCfg = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release|x64.Build.0 = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.ActiveCfg = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.Build.0 = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.ActiveCfg = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.Build.0 = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.ActiveCfg = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.Build.0 = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.ActiveCfg = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.Build.0 = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.ActiveCfg = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.Build.0 = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.ActiveCfg = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.Build.0 = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.ActiveCfg = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.Build.0 = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.ActiveCfg = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.Build.0 = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.Build.0 = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.ActiveCfg = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.Build.0 = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.ActiveCfg = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.Build.0 = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.ActiveCfg = Static lib - Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.Build.0 = Static lib - Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/tests_vc11.vcxproj b/tests/tests_vc11.vcxproj new file mode 100644 index 00000000..ec454632 --- /dev/null +++ b/tests/tests_vc11.vcxproj @@ -0,0 +1,239 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + tests + {2A1DE18B-F678-4A94-A996-E848E20B2983} + tests + + + + Application + MultiByte + true + Windows7.1SDK + + + Application + MultiByte + true + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\bin\Win32-VisualStudio\ + ..\bin\Win64-VisualStudio\ + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + ..\bin\Win32-VisualStudio\ + ..\bin\Win64-VisualStudio\ + + + + Disabled + ..\include;%(AdditionalIncludeDirectories) + true + EnableFastChecks + MultiThreadedDebugDLL + Level3 + + + ..\lib\Win32-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + true + + + + + + + Disabled + ..\include;%(AdditionalIncludeDirectories) + EnableFastChecks + MultiThreadedDebugDLL + Level3 + + + ..\lib\Win64-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + true + + + + + + + MaxSpeed + true + ..\include;%(AdditionalIncludeDirectories) + MultiThreadedDLL + true + Level3 + + + ..\lib\Win32-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + false + true + true + + + + + + + MaxSpeed + true + ..\include;%(AdditionalIncludeDirectories) + MultiThreadedDLL + true + Level3 + + + ..\lib\Win64-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + false + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {e08e042a-6c45-411b-92be-3cc31331019f} + false + + + + + + \ No newline at end of file diff --git a/tests/tests_vc12.sln b/tests/tests_vc12.sln new file mode 100644 index 00000000..098c24ea --- /dev/null +++ b/tests/tests_vc12.sln @@ -0,0 +1,88 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2013 for Windows Desktop +VisualStudioVersion = 12.0.30501.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Irrlicht", "..\source\Irrlicht\Irrlicht12.0.vcxproj", "{E08E042A-6C45-411B-92BE-3CC31331019F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tests", "tests_vc12.vcxproj", "{2A1DE18B-F678-4A94-A996-E848E20B2983}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release - Fast FPU|Win32 = Release - Fast FPU|Win32 + Release - Fast FPU|x64 = Release - Fast FPU|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + SDL-Debug|Win32 = SDL-Debug|Win32 + SDL-Debug|x64 = SDL-Debug|x64 + Static lib - Debug|Win32 = Static lib - Debug|Win32 + Static lib - Debug|x64 = Static lib - Debug|x64 + Static lib - Release - Fast FPU|Win32 = Static lib - Release - Fast FPU|Win32 + Static lib - Release - Fast FPU|x64 = Static lib - Release - Fast FPU|x64 + Static lib - Release|Win32 = Static lib - Release|Win32 + Static lib - Release|x64 = Static lib - Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.ActiveCfg = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.Build.0 = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.ActiveCfg = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.Build.0 = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.ActiveCfg = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.Build.0 = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.ActiveCfg = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.Build.0 = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.ActiveCfg = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.Build.0 = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.ActiveCfg = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.Build.0 = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|Win32.ActiveCfg = SDL-Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|Win32.Build.0 = SDL-Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|x64.ActiveCfg = SDL-Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|x64.Build.0 = SDL-Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.ActiveCfg = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.Build.0 = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.ActiveCfg = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.Build.0 = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.Build.0 = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.ActiveCfg = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.Build.0 = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.ActiveCfg = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.Build.0 = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.ActiveCfg = Static lib - Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.Build.0 = Static lib - Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Debug|Win32.ActiveCfg = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Debug|Win32.Build.0 = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Debug|x64.ActiveCfg = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Debug|x64.Build.0 = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release - Fast FPU|x64.Build.0 = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release|Win32.ActiveCfg = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release|Win32.Build.0 = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release|x64.ActiveCfg = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release|x64.Build.0 = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.SDL-Debug|x64.Build.0 = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Debug|x64.Build.0 = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release|Win32.Build.0 = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release|x64.ActiveCfg = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/tests_vc12.vcxproj b/tests/tests_vc12.vcxproj new file mode 100644 index 00000000..91a313c7 --- /dev/null +++ b/tests/tests_vc12.vcxproj @@ -0,0 +1,239 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + tests + {2A1DE18B-F678-4A94-A996-E848E20B2983} + tests + + + + Application + MultiByte + true + Windows7.1SDK + + + Application + MultiByte + true + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\bin\Win32-VisualStudio\ + ..\bin\Win64-VisualStudio\ + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + ..\bin\Win32-VisualStudio\ + ..\bin\Win64-VisualStudio\ + + + + Disabled + ..\include;%(AdditionalIncludeDirectories) + true + EnableFastChecks + MultiThreadedDebugDLL + Level3 + + + ..\lib\Win32-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + true + + + + + + + Disabled + ..\include;%(AdditionalIncludeDirectories) + EnableFastChecks + MultiThreadedDebugDLL + Level3 + + + ..\lib\Win64-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + true + + + + + + + MaxSpeed + true + ..\include;%(AdditionalIncludeDirectories) + MultiThreadedDLL + true + Level3 + + + ..\lib\Win32-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + false + true + true + + + + + + + MaxSpeed + true + ..\include;%(AdditionalIncludeDirectories) + MultiThreadedDLL + true + Level3 + + + ..\lib\Win64-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + false + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {e08e042a-6c45-411b-92be-3cc31331019f} + false + + + + + + \ No newline at end of file diff --git a/tests/tests_vc14.sln b/tests/tests_vc14.sln new file mode 100644 index 00000000..ce31f9c4 --- /dev/null +++ b/tests/tests_vc14.sln @@ -0,0 +1,88 @@ + +Microsoft Visual Studio Solution File, Format Version 14.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Irrlicht", "..\source\Irrlicht\Irrlicht14.0.vcxproj", "{E08E042A-6C45-411B-92BE-3CC31331019F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tests", "tests_vc14.vcxproj", "{2A1DE18B-F678-4A94-A996-E848E20B2983}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release - Fast FPU|Win32 = Release - Fast FPU|Win32 + Release - Fast FPU|x64 = Release - Fast FPU|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + SDL-Debug|Win32 = SDL-Debug|Win32 + SDL-Debug|x64 = SDL-Debug|x64 + Static lib - Debug|Win32 = Static lib - Debug|Win32 + Static lib - Debug|x64 = Static lib - Debug|x64 + Static lib - Release - Fast FPU|Win32 = Static lib - Release - Fast FPU|Win32 + Static lib - Release - Fast FPU|x64 = Static lib - Release - Fast FPU|x64 + Static lib - Release|Win32 = Static lib - Release|Win32 + Static lib - Release|x64 = Static lib - Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.ActiveCfg = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|Win32.Build.0 = Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.ActiveCfg = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Debug|x64.Build.0 = Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.ActiveCfg = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|Win32.Build.0 = Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.ActiveCfg = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release - Fast FPU|x64.Build.0 = Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.ActiveCfg = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|Win32.Build.0 = Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.ActiveCfg = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Release|x64.Build.0 = Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|Win32.ActiveCfg = SDL-Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|Win32.Build.0 = SDL-Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|x64.ActiveCfg = SDL-Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.SDL-Debug|x64.Build.0 = SDL-Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.ActiveCfg = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|Win32.Build.0 = Static lib - Debug|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.ActiveCfg = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Debug|x64.Build.0 = Static lib - Debug|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|Win32.Build.0 = Static lib - Release - Fast FPU|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.ActiveCfg = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release - Fast FPU|x64.Build.0 = Static lib - Release - Fast FPU|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.ActiveCfg = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.Build.0 = Static lib - Release|Win32 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.ActiveCfg = Static lib - Release|x64 + {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.Build.0 = Static lib - Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Debug|Win32.ActiveCfg = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Debug|Win32.Build.0 = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Debug|x64.ActiveCfg = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Debug|x64.Build.0 = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release - Fast FPU|x64.Build.0 = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release|Win32.ActiveCfg = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release|Win32.Build.0 = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release|x64.ActiveCfg = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Release|x64.Build.0 = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.SDL-Debug|x64.Build.0 = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Debug|x64.Build.0 = Debug|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release|Win32.Build.0 = Release|Win32 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release|x64.ActiveCfg = Release|x64 + {2A1DE18B-F678-4A94-A996-E848E20B2983}.Static lib - Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tests/tests_vc14.vcxproj b/tests/tests_vc14.vcxproj new file mode 100644 index 00000000..07229875 --- /dev/null +++ b/tests/tests_vc14.vcxproj @@ -0,0 +1,239 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + tests + {2A1DE18B-F678-4A94-A996-E848E20B2983} + tests + + + + Application + MultiByte + true + v140 + + + Application + MultiByte + true + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\bin\Win32-VisualStudio\ + ..\bin\Win64-VisualStudio\ + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + ..\bin\Win32-VisualStudio\ + ..\bin\Win64-VisualStudio\ + + + + Disabled + ..\include;%(AdditionalIncludeDirectories) + true + EnableFastChecks + MultiThreadedDebugDLL + Level3 + + + ..\lib\Win32-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + true + + + + + + + Disabled + ..\include;%(AdditionalIncludeDirectories) + EnableFastChecks + MultiThreadedDebugDLL + Level3 + + + ..\lib\Win64-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + true + + + + + + + MaxSpeed + true + ..\include;%(AdditionalIncludeDirectories) + MultiThreadedDLL + true + Level3 + + + ..\lib\Win32-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + false + true + true + + + + + + + MaxSpeed + true + ..\include;%(AdditionalIncludeDirectories) + MultiThreadedDLL + true + Level3 + + + ..\lib\Win64-visualstudio\Irrlicht.lib;%(AdditionalDependencies) + false + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {e08e042a-6c45-411b-92be-3cc31331019f} + false + + + + + + \ No newline at end of file diff --git a/tests/textureFeatures.cpp b/tests/textureFeatures.cpp new file mode 100644 index 00000000..9ce787df --- /dev/null +++ b/tests/textureFeatures.cpp @@ -0,0 +1,454 @@ +// Copyright (C) 2008-2012 Christian Stehno, Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; + +namespace +{ +//! check miplevels by visual test +bool renderMipLevels(video::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 + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager * smgr = device->getSceneManager(); + if (!driver->queryFeature(video::EVDF_MIP_MAP)) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + // Can't pass manual data with hardware mip maps (at least on d3d, not sure about older GL) + driver->setTextureCreationFlag(video::ETCF_AUTO_GENERATE_MIP_MAPS, false); + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + scene::ISceneNode* n = smgr->addCubeSceneNode(); + scene::ISceneNode* n2 = smgr->addCubeSceneNode(10, 0, -1, vector3df(20,0,30), vector3df(0,45,0)); + + // we use a main texture with blue on top and red below + // and mipmap with pink on top and cyan below + if (n && n2) + { + // create the texture and miplevels with distinct colors + u32 texData[16*16]; + for (u32 i=0; i<16*16; ++i) + texData[i]=(i<8*16?0xff0000ff:0xffff0000); + video::IImage* image = driver->createImageFromData(video::ECF_A8R8G8B8, dimension2du(16,16), texData, false); + u32 mipdata[8*16]; + u32 index=0; + for (u32 j=8; j>0; j/=2) + { + for (u32 i=0; isetMipMapsData(mipdata, false, true); + video::ITexture* tex = driver->addTexture("miptest", image); + if (!tex) + // is probably an error in the mipdata handling + return false; + else + { + n->setMaterialFlag(video::EMF_LIGHTING, false); + n->setMaterialTexture(0, tex); + n2->setMaterialFlag(video::EMF_LIGHTING, false); + n2->setMaterialTexture(0, tex); + } + image->drop(); + } + + (void)smgr->addCameraSceneNode(0, vector3df(10,0,-30)); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,100,101,140)); + smgr->drawAll(); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-renderMipmap.png", 99.5); + + if (!result) + logTestString("mipmap render failed.\n", driver->getName()); + else + logTestString("Passed\n"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +//! Tests locking miplevels +bool lockAllMipLevels(video::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 + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager * smgr = device->getSceneManager(); + + if (!driver->queryFeature(video::EVDF_MIP_MAP)) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + // Can't lock surfaces for hardware mip-maps + driver->setTextureCreationFlag(video::ETCF_AUTO_GENERATE_MIP_MAPS, false); + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + scene::ISceneNode* n = smgr->addCubeSceneNode(); + + if (n) + { + // create the texture and miplevels with distinct colors + u32 texData[16*16]; + for (u32 i=0; i<16*16; ++i) + texData[i]=0xff0000ff-i; + video::IImage* image = driver->createImageFromData(video::ECF_A8R8G8B8, core::dimension2du(16,16), texData, false); + u32 mipdata[8*16]; + u32 index=0; + for (u32 j=8; j>0; j/=2) + { + u32 val=(j==8?0x00ff00ff:(j==4?0x0000ffff:(j==2?0xc2c200ff:0x001212ff))); + for (u32 i=0; iaddTexture("miptest", image, mipdata); + if (!tex) + // is probably an error in the mipdata handling + return false; + else + n->setMaterialTexture(0, tex); + image->drop(); + } + + smgr->addCameraSceneNode(); + + driver->beginScene(true, true, video::SColor(255,100,101,140)); + smgr->drawAll(); + driver->endScene(); + + video::ITexture* tex = driver->findTexture("miptest"); + video::SColor* bits = (video::SColor*)tex->lock(video::ETLM_READ_ONLY, 0); + bool result = bits && (bits[0].color==0xff0000ff); + tex->unlock(); + bits = (video::SColor*)tex->lock(video::ETLM_READ_ONLY, 1); + result &= bits && (bits[0].color==0x00ff00ff); + tex->unlock(); + bits = (video::SColor*)tex->lock(video::ETLM_READ_ONLY, 2); + result &= bits && (bits[0].color==0x0000ffff); + tex->unlock(); + bits = (video::SColor*)tex->lock(video::ETLM_READ_ONLY, 3); + result &= bits && (bits[0].color==0xc2c200ff); + tex->unlock(); + bits = (video::SColor*)tex->lock(video::ETLM_READ_ONLY, 4); + result &= bits && (bits[0].color==0x001212ff); + tex->unlock(); + + if (!result) + logTestString("mipmap lock after init with driver %ls failed.\n", driver->getName()); + + // test with updating a lower level, and reading upper and lower + bits = (video::SColor*)tex->lock(video::ETLM_READ_WRITE, 3); + if ( bits ) + { + bits[0]=0xff00ff00; + bits[1]=0xff00ff00; + } + tex->unlock(); + bits = (video::SColor*)tex->lock(video::ETLM_READ_WRITE, 4); + result &= bits && (bits[0].color==0x001212ff); + tex->unlock(); + bits = (video::SColor*)tex->lock(video::ETLM_READ_ONLY, 3); + result &= bits && ((bits[0].color==0xff00ff00)&&(bits[2].color==0xc2c200fe)); + tex->unlock(); + + if (!result) + logTestString("mipmap lock after mipmap write with driver %ls failed.\n", driver->getName()); + + // now test locking level 0 + bits = (video::SColor*)tex->lock(video::ETLM_READ_WRITE, 0); + if ( bits ) + { + bits[0]=0xff00ff00; + bits[1]=0xff00ff00; + } + tex->unlock(); + bits = (video::SColor*)tex->lock(video::ETLM_READ_WRITE, 4); + result &= bits && (bits[0].color==0x001212ff); + tex->unlock(); + bits = (video::SColor*)tex->lock(video::ETLM_READ_ONLY, 0); + result &= bits && ((bits[0].color==0xff00ff00)&&(bits[2].color==0xff0000fd)); + tex->unlock(); + + if (!result) + logTestString("mipmap lock at level 0 after mipmap write with driver %ls failed.\n", driver->getName()); + else + logTestString("Passed\n"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + + +//! Tests locking miplevels after texture was created with auto mipmap update +bool lockWithAutoMipmap(video::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 + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager * smgr = device->getSceneManager(); + + if (!driver->queryFeature(video::EVDF_MIP_MAP)) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + // Can't lock surfaces for hardware mip-maps (sadly... so also can't test if it works like this) + driver->setTextureCreationFlag(video::ETCF_AUTO_GENERATE_MIP_MAPS, false); + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + scene::ISceneNode* n = smgr->addCubeSceneNode(); + + if (n) + { + // create the texture + u32 texData[16*16]; + for (u32 i=0; i<16*16; ++i) + texData[i]=0xff0000ff-i; + video::IImage* image = driver->createImageFromData(video::ECF_A8R8G8B8, core::dimension2du(16,16), texData, false); + + video::ITexture* tex = driver->addTexture("miptest", image); + if (!tex) + return false; + else + n->setMaterialTexture(0, tex); + image->drop(); + } + (void)smgr->addCameraSceneNode(); + + driver->beginScene(true, true, video::SColor(255,100,101,140)); + smgr->drawAll(); + driver->endScene(); + + video::ITexture* tex = driver->findTexture("miptest"); + video::SColor* bits = (video::SColor*)tex->lock(video::ETLM_READ_ONLY, 0); + bool result = bits && (bits[0].color==0xff0000ff); + tex->unlock(); + if (!result) + logTestString("mipmap lock after init with driver %ls failed.\n", driver->getName()); + + // test with updating a lower level, and reading upper and lower + bits = (video::SColor*)tex->lock(video::ETLM_READ_WRITE, 3); + if ( bits ) + { + bits[0]=0xff00ff00; + bits[1]=0xff00ff00; + } + tex->unlock(); + // lock another texture just to invalidate caches in the driver + bits = (video::SColor*)tex->lock(video::ETLM_READ_WRITE, 4); + tex->unlock(); + bits = (video::SColor*)tex->lock(video::ETLM_READ_ONLY, 3); + result &= bits && ((bits[0].color==0xff00ff00)&&(bits[2].color!=0xff00ff00)); + tex->unlock(); + + if (!result) + logTestString("mipmap lock after mipmap write with driver %ls failed.\n", driver->getName()); + + // now test locking level 0 + bits = (video::SColor*)tex->lock(video::ETLM_READ_WRITE, 0); + if ( bits ) + { + bits[0]=0x00ff00ff; + bits[1]=0x00ff00ff; + } + tex->unlock(); + bits = (video::SColor*)tex->lock(video::ETLM_READ_ONLY, 3); + result &= bits && ((bits[0].color==0xff00ff00)&&(bits[2].color!=0xff00ff00)); + tex->unlock(); + + if (!result) + logTestString("mipmap lock at level 0 after mipmap write with driver %ls failed.\n", driver->getName()); + else + logTestString("Passed\n"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +//! Tests locking +bool lockCubemapTexture(video::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 + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager * smgr = device->getSceneManager(); + + if (!driver->queryFeature(video::EVDF_MIP_MAP)) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + bool testCubemap = driver->queryFeature(video::EVDF_TEXTURE_CUBEMAP); + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + scene::ISceneNode* n = smgr->addCubeSceneNode(); + scene::ISceneNode* n2 = smgr->addCubeSceneNode(10, 0, -1, vector3df(20, 0, 30), vector3df(0, 45, 0)); + + if (n && n2) + { + u32 texData[16*16]; + + for (u32 i=0; i<16*16; ++i) + texData[i]=0xff0000ff-i; + + // texture 2d + + video::IImage* image = driver->createImageFromData(video::ECF_A8R8G8B8, dimension2du(16,16), texData, false); + + video::ITexture* tex = driver->addTexture("tex2d", image); + + if (!tex) + return false; + else + n->setMaterialTexture(0, tex); + + // cubemap + + if (testCubemap) + { + video::ITexture* texCube = driver->addTextureCubemap("texcube", image, image, image, image, image, image); + + if (!texCube) + testCubemap = false; + else + n2->setMaterialTexture(0, texCube); + } + + image->drop(); + } + + smgr->addCameraSceneNode(0, vector3df(10, 0, -30)); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,100,101,140)); + smgr->drawAll(); + driver->endScene(); + + video::ITexture* tex = driver->findTexture("tex2d"); + + video::SColor* bits = (video::SColor*)tex->lock(video::ETLM_READ_WRITE); + bits[0]=0xff00ff00; + bits[1]=0xff00ff00; + tex->unlock(); + + bits = (video::SColor*)tex->lock(video::ETLM_READ_ONLY, 0); + bool result = ((bits[0].color==0xff00ff00)&&(bits[2].color==0xff0000fd)); + tex->unlock(); + + if (!result) + logTestString("texture 2d lock with driver %ls failed.\n", driver->getName()); + else + logTestString("Passed\n"); + + if (testCubemap) + { + tex = driver->findTexture("texcube"); + + for (u32 i = 0; i < 6; ++i) + { + bits = (video::SColor*)tex->lock(video::ETLM_READ_WRITE, 0, i); + if ( !bits) + { + result = false; + break; + } + bits[0] = 0xff00ff00; + bits[1] = 0xff00ff00; + tex->unlock(); + } + + for (u32 i = 0; i < 6; ++i) + { + bits = (video::SColor*)tex->lock(video::ETLM_READ_ONLY, 0, i); + if ( !bits) + { + result = false; + break; + } + result &= ((bits[0].color == 0xff00ff00) && (bits[2].color == 0xff0000fd)); + tex->unlock(); + } + + if (!result) + logTestString("texture cubemap lock with driver %ls failed.\n", driver->getName()); + else + logTestString("Passed\n"); + } + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +} + +bool textureFeatures(void) +{ + bool result = true; + + TestWithAllDrivers(renderMipLevels); + TestWithAllDrivers(lockAllMipLevels); + TestWithAllDrivers(lockWithAutoMipmap); + TestWithAllDrivers(lockCubemapTexture); + + return result; +} diff --git a/tests/textureRenderStates.cpp b/tests/textureRenderStates.cpp new file mode 100644 index 00000000..b0d965b2 --- /dev/null +++ b/tests/textureRenderStates.cpp @@ -0,0 +1,362 @@ +// Copyright (C) 2008-2012 Christian Stehno, Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; + +static bool manyTextures(video::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 + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager * smgr = device->getSceneManager(); + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + (void)smgr->addCameraSceneNode(); + + scene::SMeshBufferLightMap* mesh = new scene::SMeshBufferLightMap; + + mesh->Vertices.reallocate(4); + mesh->Indices.reallocate(6); + + mesh->Vertices.push_back(video::S3DVertex2TCoords(-50,50,80,irr::video::SColor(255,100,100,100),0,1,0,1)); + mesh->Vertices.push_back(video::S3DVertex2TCoords(50,50,80,irr::video::SColor(255,100,100,100),1,1,1,1)); + mesh->Vertices.push_back(video::S3DVertex2TCoords(50,-50,80,irr::video::SColor(255,100,100,100),1,0,1,0)); + mesh->Vertices.push_back(video::S3DVertex2TCoords(-50,-50,80,irr::video::SColor(255,100,100,100),0,0,0,0)); + + mesh->Indices.push_back(0); + mesh->Indices.push_back(1); + mesh->Indices.push_back(2); + mesh->Indices.push_back(2); + mesh->Indices.push_back(3); + mesh->Indices.push_back(0); + + video::SMaterial& mat = mesh->getMaterial(); + mat.Lighting = false; + mat.setTexture(0,driver->getTexture("../media/fire.bmp")); + mat.setTexture(1,driver->getTexture("../media/fire.bmp")); + mat.setTexture(2,driver->getTexture("../media/fire.bmp")); + mat.setTexture(3,driver->getTexture("../media/fire.bmp")); + + mesh->setDirty(); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,100,101,140)); + // set camera + smgr->drawAll(); + // draw meshbuffer + driver->setMaterial(mat); + driver->drawMeshBuffer(mesh); + driver->endScene(); + mesh->drop(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-multiTexture.png", 99.31f); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +//! 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 renderAndLoad(video::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 + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager * smgr = device->getSceneManager(); + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + video::ITexture* tex1 = driver->getTexture("../media/wall.bmp"); + + (void)smgr->addCameraSceneNode(); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,100,101,140)); + driver->draw2DImage(tex1, position2di(0,0)); + driver->endScene(); + + driver->getTexture("../media/tools.png"); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,100,101,140)); + driver->draw2DImage(tex1, position2di(0,0)); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-textureRenderStates.png", 99.85f); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + + +// This test would cause a crash if it does not work +// in 1.5.1 and 1.6 an illegal access in the OpenGL driver caused this +static bool renderAndRemove(video::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 + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager * smgr = device->getSceneManager(); + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255, 0, 255, 0)); + smgr->drawAll(); + driver->endScene(); + + smgr->addCameraSceneNode(); + video::ITexture* texture = driver->getTexture ("media/tools.png"); + scene::ISceneNode * img = smgr->addCubeSceneNode(); + img->setMaterialTexture(0, texture); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor (255, 0, 255, 0)); + smgr->drawAll(); + driver->endScene(); + + smgr->clear(); // Remove anything that used the texture + driver->removeTexture(texture); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,100,101,140)); + smgr->drawAll(); + driver->endScene(); + + smgr->addCameraSceneNode(); + texture = driver->getTexture("media/tools.png"); + img = smgr->addCubeSceneNode(); + img->setMaterialTexture(0, texture); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, irr::video::SColor (255, 0, 255, 0)); + smgr->drawAll(); + driver->endScene(); + + device->closeDevice(); + device->run(); + device->drop(); + + return true; +} + + +static bool testTextureMatrixInMixedScenes(video::E_DRIVER_TYPE driverType) +{ + irr::IrrlichtDevice* device = createDevice(driverType, dimension2du(160,120)); + if (!device) + return true; + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* sceneManager = device->getSceneManager(); + gui::IGUIEnvironment* gui = device->getGUIEnvironment(); + + if (!driver->queryFeature(video::EVDF_TEXTURE_MATRIX)) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + scene::ICameraSceneNode* camera = sceneManager->addCameraSceneNode(); + camera->setPosition(vector3df(0,10,0)); + + gui::IGUIStaticText* stext = gui->addStaticText(L" ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 ", + rect(5,100,150,125),false,false,0,false); + stext->setBackgroundColor(video::SColor(255,128,0,0)); + stext->setOverrideColor(video::SColor(255,255,255,255)); + + gui->addEditBox(L"Test edit box", rect(5,50,150,75)); + + gui->addCheckBox(true, rect(5, 20, 150, 45),0,-1,L"Test CheckBox"); + + video::SMaterial mat; + mat.MaterialType = video::EMT_SOLID; + mat.setFlag(video::EMF_LIGHTING, false); + // problem doesn't occur if the scale defaults: (1.f,1.f). + mat.getTextureMatrix(0).setTextureScale(2.0,2.0); + + scene::IAnimatedMesh* pmesh = sceneManager->addHillPlaneMesh("testMesh",dimension2d(50,50),dimension2d(6,6),&mat); + sceneManager->addAnimatedMeshSceneNode(pmesh); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,100,101,140)); + sceneManager->drawAll(); + gui->drawAll(); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-textureMatrixInMixedScenes.png", 99.33f); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +// animated texture matrix test. +static bool textureMatrix(video::E_DRIVER_TYPE driverType) +{ + irr::IrrlichtDevice* device = createDevice(driverType, dimension2du(160,120)); + if (!device) + return true; + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* sceneManager = device->getSceneManager(); + + if (!driver->queryFeature(video::EVDF_TEXTURE_MATRIX)) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + scene::ICameraSceneNode* camera = sceneManager->addCameraSceneNode(); + camera->setPosition(vector3df(0,0,-10)); + + // set up plane mesh to face the camera + scene::IMesh* mesh = sceneManager->getGeometryCreator()->createPlaneMesh(dimension2df(150,150), core::dimension2du(1,1),0,core::dimension2df(1,1)); + scene::IMeshSceneNode* node = sceneManager->addMeshSceneNode(mesh, 0, -1, vector3df(0, 0, 150), vector3df(-90, 0, 0)); + if (mesh) + mesh->drop(); + + // set the hillplane material texture & save a reference + // to the texture matrix. + video::SMaterial& material = node->getMaterial(0); + video::ITexture* tex = driver->getTexture("../media/water.jpg"); + + material.setTexture(0,tex); + material.setFlag(video::EMF_LIGHTING,false); + matrix4& textureMatrix = material.TextureLayer[0].getTextureMatrix(); + + const vector2df rcenter, scale(1.f, 1.f); + vector2df trans; + + trans.X += 0.0005f; + textureMatrix.buildTextureTransform(0.f, rcenter, trans, scale); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,100,101,140)); + sceneManager->drawAll(); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-textureMatrix.png"); + + trans.X += 0.45f; + textureMatrix.buildTextureTransform(0.f, rcenter, trans, scale); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,100,101,140)); + sceneManager->drawAll(); + driver->endScene(); + + result &= takeScreenshotAndCompareAgainstReference(driver, "-textureMatrix2.png"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +bool danglingTexturePointer() +{ +// A demo of the OpenGL "white texture" bug in Irrlicht +// Author: Matt Giuca +// (Vaguely based on the Irrlicht 2D graphics tutorial) + +// I have found that in some situations, when using the OpenGL driver, some +// textures appear white. +// This is caused by deleting a texture while it is active (the last texture +// read or written to), and then loading a new texture at the same memory +// location. The new texture will not be loaded properly. + +// This demo triggers the bug (though there is some probability that it won't +// be triggered; just run it again until it shows a white square instead of +// the Irrlicht logo). + + // This is only a problem in the OpenGL driver + irr::IrrlichtDevice* device = irr::createDevice(irr::video::EDT_OPENGL, + irr::core::dimension2d(160, 120)); + if (!device) + return true; + + irr::video::IVideoDriver* driver = device->getVideoDriver(); + + stabilizeScreenBackground(driver); + + // Load a texture from a file + // This binds and uploads to OpenGL texture #2. + irr::video::ITexture* logo2 = driver->getTexture("../media/irrlichtlogo2.png"); + // Remove the texture from the driver (delete it from hardware) + // This leaves CurrentTexture pointing at logo2 + driver->removeTexture(logo2); + // Load another texture from a file + // There is a good probability that logo3 will be allocated the same + // memory address as logo2. If that happens, + // COpenGLDriver::setActiveTexture will not bother to call glBindTextures + // (thinking that logo3 is the same texture as logo2). + // Therefore, the logo3 texture will be uploaded to texture #0, not #2. + irr::video::ITexture* logo3 = driver->getTexture("../media/irrlichtlogo3.png"); + + device->run(); + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, irr::video::SColor(255,100,101,140)); + + // This is required to trigger the white appearance (this unbinds the + // texture, forcing draw2DImage to rebind the logo3 texture (#2)). + driver->setMaterial(irr::video::SMaterial()); + + // Since logo3 was uploaded to #0, not #2, this will bind texture #2, + // which has never been written to. OpenGL considers an empty texture + // to be white. + driver->draw2DImage(logo3, irr::core::position2d(20, 20)); + + driver->endScene(); + } + + const bool result = takeScreenshotAndCompareAgainstReference(driver, "-texturePointer.png"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +bool textureRenderStates(void) +{ + bool result = true; + TestWithAllDrivers(renderAndLoad); + TestWithAllDrivers(renderAndRemove); + TestWithAllDrivers(testTextureMatrixInMixedScenes); + TestWithAllDrivers(manyTextures); + TestWithAllDrivers(textureMatrix); + result &= danglingTexturePointer(); + + return result; +} diff --git a/tests/timer.cpp b/tests/timer.cpp new file mode 100644 index 00000000..935c2ef5 --- /dev/null +++ b/tests/timer.cpp @@ -0,0 +1,66 @@ +#include "testUtils.h" + +using namespace irr; +using namespace core; + +// Test the functionality of the Irrlicht timer +bool testTimer(void) +{ + bool success = true; + + IrrlichtDevice* device = createDevice(video::EDT_NULL); + if (!device) + return false; + + logTestString("Testing virtual timer.\n"); + + ITimer* timer = device->getTimer(); + + // must be running at start + success &= !timer->isStopped(); + + // starting more often should not stop the timer + timer->start(); + success &= !timer->isStopped(); + + // one stop should not stop the timer because it's started twice now + timer->stop(); + success &= !timer->isStopped(); + + // another stop should really stop it + timer->stop(); + success &= timer->isStopped(); + + // third stop - timer should still be stopped + timer->stop(); + success &= timer->isStopped(); + + // should not start yet + timer->start(); + success &= timer->isStopped(); + + // start again + timer->start(); + success &= !timer->isStopped(); + + logTestString("Testing virtual timer done. %s\n", success?"Success":"Failure"); + + logTestString("Testing real timer.\n"); + const u32 startVirtual = timer->getTime(); + const u32 startReal = timer->getRealTime(); + device->sleep(2); + if (startReal != timer->getRealTime()) + logTestString("Warning: Real timer did not progress. Maybe the time slices are too coarse to see.\n"); + if (startVirtual != timer->getTime()) + logTestString("Warning: Virtual timer did not progress. Maybe the time slices are too coarse to see.\n"); + + irr::ITimer::RealTimeDate date = timer->getRealTimeAndDate(); + logTestString("Real time and date. %d.%d.%d at %d:%d:%d\n", date.Day, date.Month, date.Year, date.Hour, date.Minute, date.Second); + logTestString("This is day %d of the year and weekday %d. The current time zone has daylight saving %s\n", date.Yearday, date.Weekday, date.IsDST?"enabled":"disabled"); + + device->closeDevice(); + device->run(); + device->drop(); + + return success; +} diff --git a/tests/transparentMaterials.cpp b/tests/transparentMaterials.cpp new file mode 100644 index 00000000..e411b674 --- /dev/null +++ b/tests/transparentMaterials.cpp @@ -0,0 +1,371 @@ +// Copyright (C) 2008-2012 Christian Stehno, Colin MacDonald +// No rights reserved: this software is in the public domain. + +#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 testTransparentAlphaChannelRef(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(); + + if (driver->getColorFormat() != video::ECF_A8R8G8B8) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + 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); + 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); + frontCube->setMaterialFlag(video::EMF_LIGHTING, false); + + (void)smgr->addCameraSceneNode(0, vector3df(0, 0, -15)); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,113,113,133)); + smgr->drawAll(); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-transparentAlphaChannelRef.png", 99.18f); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + + +//! Check that EMT_TRANSPARENT_ALPHA_CHANNEL works as expected +bool testTransparentAlphaChannel(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(); + + if (driver->getColorFormat() != video::ECF_A8R8G8B8) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + 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); + 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); + frontCube->setMaterialFlag(video::EMF_LIGHTING, false); + + (void)smgr->addCameraSceneNode(0, vector3df(0, 0, -15)); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,113,113,133)); + smgr->drawAll(); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-transparentAlphaChannel.png"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + + +//! Check that EMT_TRANSPARENT_VERTEX_ALPHA works as expected +bool testTransparentVertexAlpha(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(); + + if (driver->getColorFormat() != video::ECF_A8R8G8B8) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + 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")); + // vertex color has alpha 255, hence solid + backCube->setMaterialType(video::EMT_TRANSPARENT_VERTEX_ALPHA); + backCube->setMaterialFlag(video::EMF_LIGHTING, false); + + IMeshSceneNode * frontCube = smgr->addCubeSceneNode(10,0,-1,core::vector3df(-10,0,0)); + frontCube->setMaterialTexture(0, driver->getTexture("../media/help.png")); + frontCube->setMaterialType(video::EMT_TRANSPARENT_VERTEX_ALPHA); + frontCube->setMaterialFlag(video::EMF_LIGHTING, false); + driver->getMeshManipulator()->setVertexColorAlpha(frontCube->getMesh(), 128); + frontCube = smgr->addCubeSceneNode(10,0,-1,core::vector3df(10,0,0)); + frontCube->setMaterialTexture(0, driver->getTexture("../media/help.png")); + frontCube->setMaterialType(video::EMT_TRANSPARENT_VERTEX_ALPHA); + frontCube->setMaterialFlag(video::EMF_LIGHTING, false); + driver->getMeshManipulator()->setVertexColorAlpha(frontCube->getMesh(), 45); + + (void)smgr->addCameraSceneNode(0, vector3df(0, 0, -15)); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,113,113,133)); + smgr->drawAll(); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-transparentVertexAlpha.png", 98.76f); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + + +//! Check that EMT_TRANSPARENT_REFLECTION_2_LAYER works as expected +bool testTransparentReflection2Layer(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(); + + if (driver->getColorFormat() != video::ECF_A8R8G8B8) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + 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->setMaterialTexture(1, driver->getTexture("../media/water.jpg")); + // vertex color has alpha 255, hence solid + backCube->setMaterialType(video::EMT_TRANSPARENT_REFLECTION_2_LAYER); + backCube->setMaterialFlag(video::EMF_LIGHTING, false); + + IMeshSceneNode * frontCube = smgr->addCubeSceneNode(10,0,-1,core::vector3df(-10,0,0)); + frontCube->setMaterialTexture(0, driver->getTexture("../media/help.png")); + frontCube->setMaterialTexture(1, driver->getTexture("../media/water.jpg")); + frontCube->setMaterialType(video::EMT_TRANSPARENT_REFLECTION_2_LAYER); + frontCube->setMaterialFlag(video::EMF_LIGHTING, false); + driver->getMeshManipulator()->setVertexColorAlpha(frontCube->getMesh(), 128); + frontCube = smgr->addCubeSceneNode(10,0,-1,core::vector3df(10,0,0)); + frontCube->setMaterialTexture(0, driver->getTexture("../media/help.png")); + frontCube->setMaterialTexture(1, driver->getTexture("../media/water.jpg")); + frontCube->setMaterialType(video::EMT_TRANSPARENT_REFLECTION_2_LAYER); + frontCube->setMaterialFlag(video::EMF_LIGHTING, false); + driver->getMeshManipulator()->setVertexColorAlpha(frontCube->getMesh(), 45); + + (void)smgr->addCameraSceneNode(0, vector3df(0, 0, -15)); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,113,113,133)); + smgr->drawAll(); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-transparentReflection2Layer.png"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + + +//! Check that EMT_TRANSPARENT_ADD_COLOR works as expected +bool testTransparentAddColor(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(); + + if (driver->getColorFormat() != video::ECF_A8R8G8B8) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + 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); + backCube->setMaterialFlag(video::EMF_LIGHTING, false); + + IMeshSceneNode * frontCube = smgr->addCubeSceneNode(); + frontCube->setMaterialTexture(0, driver->getTexture("../media/help.png")); + frontCube->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); + frontCube->setMaterialFlag(video::EMF_LIGHTING, false); + + (void)smgr->addCameraSceneNode(0, vector3df(0, 0, -15)); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,113,113,133)); + smgr->drawAll(); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-transparentAddColor.png"); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + + +bool testTransparentVertexAlphaMore(E_DRIVER_TYPE driverType) +{ + IrrlichtDevice *device = createDevice(driverType, dimension2d(160, 120)); + if (!device) + return true; + + IVideoDriver* driver = device->getVideoDriver(); + ISceneManager* smgr = device->getSceneManager(); + + if (driver->getColorFormat() != video::ECF_A8R8G8B8) + { + device->closeDevice(); + device->run(); + device->drop(); + return true; + } + + stabilizeScreenBackground(driver); + + logTestString("Testing driver %ls\n", driver->getName()); + + IAnimatedMesh* mesh = smgr->getMesh("../media/sydney.md2"); + IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh ); + IMeshSceneNode* cube = smgr->addCubeSceneNode(10.0f,0,-1,vector3df(-5,3,-15)); + + if (node) + { + node->setMaterialFlag(EMF_LIGHTING, false); + node->setFrameLoop(0, 310); + node->setMaterialTexture( 0, driver->getTexture("../media/sydney.bmp") ); + } + if (cube) + { + cube->getMaterial(0).MaterialType = EMT_TRANSPARENT_VERTEX_ALPHA; + cube->setMaterialTexture(0, driver->getTexture("../media/wall.bmp")); + cube->setMaterialFlag(EMF_LIGHTING, false); + smgr->getMeshManipulator()->setVertexColorAlpha(cube->getMesh(),128); + } + // second cube without texture + cube = smgr->addCubeSceneNode(10.0f,0,-1,vector3df(5,3,-15)); + if (cube) + { + cube->getMaterial(0).MaterialType = EMT_TRANSPARENT_VERTEX_ALPHA; + cube->setMaterialFlag(EMF_LIGHTING, false); + smgr->getMeshManipulator()->setVertexColorAlpha(cube->getMesh(),128); + } + + smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0)); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, SColor(0,200,200,200)); + smgr->drawAll(); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-transparentVertexAlphaChannelMore.png", 99.18f); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + + +bool transparentMaterials(void) +{ + bool result = true; + TestWithAllDrivers(testTransparentAlphaChannel); + // FIXME Rogerborg 8-January-2010. 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. + TestWithAllDrivers(testTransparentAlphaChannelRef); + // This type seems to be broken as well for Burning's video. + TestWithAllDrivers(testTransparentVertexAlpha); + TestWithAllDrivers(testTransparentAddColor); + // TODO: this simply does not work in OpenGL due to the sphere map + // at least it creates different results, and also varies across drivers + TestWithAllDrivers(testTransparentReflection2Layer); + // This type seems to be broken as well for Burning's video. + TestWithAllDrivers(testTransparentVertexAlphaMore); + + return result; +} diff --git a/tests/triangle3d.cpp b/tests/triangle3d.cpp new file mode 100644 index 00000000..7da3148a --- /dev/null +++ b/tests/triangle3d.cpp @@ -0,0 +1,281 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" +#include + +using namespace irr; +using namespace core; + +template +static bool testGetIntersectionWithLine(core::triangle3d& triangle, const core::line3d& ray) +{ + bool allExpected=true; + const vector3d linevect = ray.getVector().normalize(); + vector3d intersection; + // When we just raise Y parallel to the ray then either all should fail or all succeed (the latter in our case). + for (u32 i=0; i<100; ++i) + { + if (!triangle.getIntersectionOfPlaneWithLine(ray.start, linevect, intersection)) + { + allExpected=false; + logTestString("triangle3d plane test %d failed\n", i); + } + //logTestString("intersection: %f %f %f\n", intersection.X, intersection.Y, intersection.Z); + if (!triangle.isPointInsideFast(intersection)) + { + allExpected=false; + logTestString("triangle3d fast point test %d failed\n", i); + } + if (!triangle.isPointInside(intersection)) + { + allExpected=false; + logTestString("triangle3d point test %d failed\n", i); + } + + if (!triangle.getIntersectionWithLine(ray.start, linevect, intersection)) + { + allExpected=false; + logTestString("triangle3d tri test %d failed\n", i); + } + + triangle.pointB.Y += 1; + } + return allExpected; +} + +// modifying the same triangle in diverse ways get some more test-cases automatically +template +static bool stageModifications(int stage, triangle3d& triangle) +{ + switch ( stage ) + { + case 0: + return true; + case 1: + swap(triangle.pointB, triangle.pointC); + return true; + case 2: + swap(triangle.pointA, triangle.pointC); + return true; + case 3: + triangle.pointA.Z += 1000; + triangle.pointB.Z += 1000; + triangle.pointC.Z += 1000; + return true; + case 4: + swap(triangle.pointA.Y, triangle.pointA.Z); + swap(triangle.pointB.Y, triangle.pointB.Z); + swap(triangle.pointC.Y, triangle.pointC.Z); + return true; + } + return false; +} + +template +static void stageModifications(int stage, vector3d& point) +{ + switch ( stage ) + { + case 3: + point.Z += 1000; + break; + case 4: + swap(point.Y, point.Z); + break; + } +} + +template +static bool isPointInside(triangle3d triangleOrig, bool testIsInside, bool testIsInsideFast) +{ + bool allExpected=true; + + array< vector3d > pointsInside; + pointsInside.push_back( vector3d(0,0,0) ); + pointsInside.push_back( (triangleOrig.pointA + triangleOrig.pointB + triangleOrig.pointC) / 3 ); + pointsInside.push_back( (triangleOrig.pointA + triangleOrig.pointB)/2 + vector3d(0,1,0) ); + pointsInside.push_back( (triangleOrig.pointA + triangleOrig.pointC)/2 + vector3d(1,0,0) ); + pointsInside.push_back( (triangleOrig.pointB + triangleOrig.pointC)/2 - vector3d(1,0,0) ); + + for (u32 stage=0; ; ++stage) + { + triangle3d triangle = triangleOrig; + if ( !stageModifications(stage, triangle) ) + break; + + for ( u32 i=0; i < pointsInside.size(); ++i ) + { + vector3d point = pointsInside[i]; + stageModifications(stage, point); + + if ( testIsInside ) + { + allExpected &= triangle.isPointInside( point ); + if ( !allExpected ) + { + logTestString("triangle3d::isPointInside pointsInside test failed in stage %d point %d\n", stage, i); + return false; + } + } + + if ( testIsInsideFast ) + { + allExpected &= triangle.isPointInsideFast( point ); + if ( !allExpected ) + { + logTestString("triangle3d::isPointInsideFast pointsInside test failed in stage %d point %d\n", stage, i); + return false; + } + } + } + } + + array< vector3d > pointsOutside; + pointsOutside.push_back( triangleOrig.pointA - vector3d(1,0,0) ); + pointsOutside.push_back( triangleOrig.pointA - vector3d(0,1,0) ); + pointsOutside.push_back( triangleOrig.pointB + vector3d(1,0,0) ); + pointsOutside.push_back( triangleOrig.pointB - vector3d(0,1,0) ); + pointsOutside.push_back( triangleOrig.pointC - vector3d(1,0,0) ); + pointsOutside.push_back( triangleOrig.pointC + vector3d(1,0,0) ); + pointsOutside.push_back( triangleOrig.pointC + vector3d(0,1,0) ); + pointsOutside.push_back( (triangleOrig.pointA + triangleOrig.pointB)/2 - vector3d(0,1,0) ); + pointsOutside.push_back( (triangleOrig.pointA + triangleOrig.pointC)/2 - vector3d(1,0,0) ); + pointsOutside.push_back( (triangleOrig.pointB + triangleOrig.pointC)/2 + vector3d(1,0,0) ); + + for (u32 stage=0; ; ++stage) + { + triangle3d triangle = triangleOrig; + if ( !stageModifications(stage, triangle) ) + break; + + for ( u32 i=0; i < pointsOutside.size(); ++i ) + { + vector3d point = pointsOutside[i]; + stageModifications(stage, point); + + if ( testIsInside ) + { + allExpected &= !triangle.isPointInside( point ); + if ( !allExpected ) + { + logTestString("triangle3d::isPointInside pointsOutside test failed in stage %d point %d\n", stage, i); + return false; + } + } + + if ( testIsInsideFast ) + { + allExpected &= !triangle.isPointInsideFast( point ); + if ( !allExpected ) + { + logTestString("triangle3d::isPointInsideFast pointsOutside test failed in stage %d point %d\n", stage, i); + return false; + } + } + } + } + + array< vector3d > pointsBorder; + pointsBorder.push_back( triangleOrig.pointA ); + pointsBorder.push_back( triangleOrig.pointB ); + pointsBorder.push_back( triangleOrig.pointC ); + pointsBorder.push_back( (triangleOrig.pointA + triangleOrig.pointB)/2 ); + pointsBorder.push_back( (triangleOrig.pointA + triangleOrig.pointC)/2 ); + pointsBorder.push_back( (triangleOrig.pointB + triangleOrig.pointC)/2 ); + + for (u32 stage=0; ; ++stage) + { + triangle3d triangle = triangleOrig; + if ( !stageModifications(stage, triangle) ) + break; + + for ( u32 i=0; i < pointsBorder.size(); ++i ) + { + vector3d point = pointsBorder[i]; + stageModifications(stage, point); + + if ( testIsInside ) + { + allExpected &= triangle.isPointInside( point ); + if ( !allExpected ) + { + logTestString("triangle3d::isPointInside pointsBorder test failed in stage %d point %d\n", stage, i); + return false; + } + } + + if ( testIsInsideFast ) + { + allExpected &= triangle.isPointInsideFast( point ); + if ( !allExpected ) + { + logTestString("triangle3d::isPointInsideFast pointsBorder test failed in stage %d point %d\n", stage, i); + return false; + } + } + } + } + + return allExpected; +} + +// Test the functionality of triangle3d +bool testTriangle3d(void) +{ + bool allExpected = true; + + logTestString("Test getIntersectionWithLine with f32\n"); + { + triangle3df triangle( + vector3df(11300.f, 129.411758f, 200.f), + vector3df(11200.f, 94.117645f, 300.f), + vector3df(11300.f, 129.411758f, 300.f)); + line3df ray; + ray.start = vector3df(11250.f, 329.f, 250.f); + ray.end = vector3df(11250.f, -1000.f, 250.f); + allExpected &= testGetIntersectionWithLine(triangle, ray); + } + logTestString("Test getIntersectionWithLine with f64\n"); + { + triangle3d triangle( + vector3d(11300., 129.411758, 200.), + vector3d(11200., 94.117645, 300.), + vector3d(11300., 129.411758, 300.)); + line3d ray; + ray.start = vector3d(11250., 329., 250.); + ray.end = vector3d(11250., -1000., 250.); + allExpected &= testGetIntersectionWithLine(triangle, ray); + } + + bool testEigen = triangle3di(vector3di(250, 0, 0), vector3di(0, 0, 500), vector3di(500, 0, 500)).isPointInside(vector3di(300,0,300)); + if ( !testEigen ) // test from Eigen from here: http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=44372&p=254331#p254331 + logTestString("Test isPointInside fails with integers\n"); + allExpected &= testEigen; + + logTestString("Test isPointInside with f32\n"); + { + triangle3d t(vector3d(-1000,-1000,0), vector3d(1000,-1000,0), vector3d(0,1000,0)); + allExpected &= isPointInside(t, true, true); + } + + logTestString("Test isPointInside with f64\n"); + { + triangle3d t(vector3d(-1000,-1000,0), vector3d(1000,-1000,0), vector3d(0,1000,0)); + allExpected &= isPointInside(t, true, true); + } + + logTestString("Test isPointInside with s32\n"); + { + triangle3d t(vector3d(-1000,-1000,0), vector3d(1000,-1000,0), vector3d(0,1000,0)); + allExpected &= isPointInside(t, false, true); + } + + if(allExpected) + logTestString("\nAll tests passed\n"); + else + logTestString("\nFAIL!\n"); + + return allExpected; +} + diff --git a/tests/triangleSelector.cpp b/tests/triangleSelector.cpp new file mode 100644 index 00000000..36dfcf25 --- /dev/null +++ b/tests/triangleSelector.cpp @@ -0,0 +1,300 @@ +// Copyright (C) 2008-2012 Christian Stehno, Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; + +namespace{ + +class MyEventReceiver : public IEventReceiver +{ +public: + // This is the one method that we have to implement + virtual bool OnEvent(const SEvent& event) + { + // Remember whether each key is down or up + if (event.EventType == EET_KEY_INPUT_EVENT) + KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown; + + return false; + } + + // This is used to check whether a key is being held down + virtual bool IsKeyDown(EKEY_CODE keyCode) const + { + return KeyIsDown[keyCode]; + } + + MyEventReceiver() + { + for (u32 i=0; i (160, 120)); + if (!device) + return true; // No error if device does not exist + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + + stabilizeScreenBackground(driver); + + scene::IMetaTriangleSelector * meta = smgr->createMetaTriangleSelector(); + + device->getFileSystem()->addFileArchive("../media/map-20kdm2.pk3"); + scene::IAnimatedMesh* q3levelmesh = smgr->getMesh("20kdm2.bsp"); + if (q3levelmesh) + { + scene::ISceneNode* q3node = smgr->addOctreeSceneNode(q3levelmesh->getMesh(0)); + + q3node->setPosition(core::vector3df(-1350,-130,-1400)); + + scene::ITriangleSelector * selector = + smgr->createOctreeTriangleSelector(q3levelmesh->getMesh(0), q3node, 128); + meta->addTriangleSelector(selector); + selector->drop(); + } + + scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(); + camera->setPosition(core::vector3df(-100,50,-150)); + camera->updateAbsolutePosition(); + camera->setTarget(camera->getAbsolutePosition() + core::vector3df(0, 0, 20)); + + device->getCursorControl()->setVisible(false); + + enum + { + MAX_TRIANGLES = 4096, // Large to test getting all the triangles + BOX_SIZE1 = 300, + BOX_SIZE2 = 50 + }; + + core::triangle3df triangles[MAX_TRIANGLES]; + core::vector3df boxPosition(camera->getAbsolutePosition()); + + video::SMaterial unlit; + unlit.Lighting = false; + unlit.Thickness = 3.f; + unlit.PolygonOffsetSlopeScale= -1.f; + unlit.PolygonOffsetDepthBias = -1.f; + + bool result = true; + { + camera->setPosition(core::vector3df(-620,-20,550)); + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0)); + smgr->drawAll(); + + core::aabbox3df box(boxPosition.X - BOX_SIZE1, boxPosition.Y - BOX_SIZE1, boxPosition.Z - BOX_SIZE1, + boxPosition.X + BOX_SIZE1, boxPosition.Y + BOX_SIZE1, boxPosition.Z + BOX_SIZE1); + + driver->setTransform(video::ETS_WORLD, core::matrix4()); + driver->setMaterial(unlit); + driver->draw3DBox(box, video::SColor(255, 0, 255, 0)); + + if(meta) + { + s32 found; + meta->getTriangles(triangles, MAX_TRIANGLES, found, box); + + while(--found >= 0) + driver->draw3DTriangle(triangles[found], video::SColor(255, 255, 0, 0)); + } + + driver->endScene(); + result &= takeScreenshotAndCompareAgainstReference(driver, "-octree_select1.png"); + } + { + camera->setPosition(core::vector3df(120,40,50)); + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0)); + smgr->drawAll(); + + core::aabbox3df box(boxPosition.X - BOX_SIZE2, boxPosition.Y - BOX_SIZE2, boxPosition.Z - BOX_SIZE2, + boxPosition.X + BOX_SIZE2, boxPosition.Y + BOX_SIZE2, boxPosition.Z + BOX_SIZE2); + + driver->setTransform(video::ETS_WORLD, core::matrix4()); + driver->setMaterial(unlit); + driver->draw3DBox(box, video::SColor(255, 0, 255, 0)); + + if(meta) + { + s32 found; + meta->getTriangles(triangles, MAX_TRIANGLES, found, box); + + while(--found >= 0) + driver->draw3DTriangle(triangles[found], video::SColor(255, 255, 0, 0)); + } + + driver->endScene(); + result &= takeScreenshotAndCompareAgainstReference(driver, "-octree_select2.png"); + } + + meta->drop(); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +//! Tests using triangle selector +bool triangle() +{ + IrrlichtDevice *device = createDevice (video::EDT_OPENGL, core::dimension2d < u32 > (160, 120)); + if (!device) + return true; // No error if device does not exist + + MyEventReceiver receiver; + device->setEventReceiver(&receiver); + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + + stabilizeScreenBackground(driver); + + scene::IMetaTriangleSelector * meta = smgr->createMetaTriangleSelector(); + + scene::IAnimatedMesh * mesh = smgr->getMesh("../media/sydney.md2"); + scene::IAnimatedMeshSceneNode * sydney = smgr->addAnimatedMeshSceneNode( mesh ); + if (sydney) + { + sydney->setPosition(core::vector3df(15, -10, 15)); + sydney->setMaterialFlag(video::EMF_LIGHTING, false); + sydney->setMD2Animation ( scene::EMAT_STAND ); + sydney->setAnimationSpeed(0.f); + sydney->setMaterialTexture( 0, driver->getTexture("../media/sydney.bmp") ); + + scene::ITriangleSelector * selector = + smgr->createTriangleSelector(sydney->getMesh()->getMesh(0), sydney); + meta->addTriangleSelector(selector); + selector->drop(); + } + + scene::ICameraSceneNode* camera = + smgr->addCameraSceneNodeFPS(); + camera->setPosition(core::vector3df(70,0,-30)); + camera->updateAbsolutePosition(); + camera->setTarget(camera->getAbsolutePosition() + core::vector3df(-20, 0, 20)); + + device->getCursorControl()->setVisible(false); + + enum + { + MAX_TRIANGLES = 5000, // Large to test getting all the triangles + BOX_SIZE = 30 + }; + + core::triangle3df triangles[MAX_TRIANGLES]; + core::vector3df boxPosition(0,0,0); + + video::SMaterial unlit; + unlit.Lighting = false; + unlit.Thickness = 3.f; + unlit.PolygonOffsetSlopeScale= -1.f; + unlit.PolygonOffsetDepthBias = -1.f; + + bool result = true; + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0xff00ffff)); + smgr->drawAll(); + + core::aabbox3df box(boxPosition.X - BOX_SIZE, boxPosition.Y - BOX_SIZE, boxPosition.Z - BOX_SIZE, + boxPosition.X + BOX_SIZE, boxPosition.Y + BOX_SIZE, boxPosition.Z + BOX_SIZE); + + driver->setTransform(video::ETS_WORLD, core::matrix4()); + driver->setMaterial(unlit); + driver->draw3DBox(box, video::SColor(255, 0, 255, 0)); + + if(meta) + { + s32 found; + meta->getTriangles(triangles, MAX_TRIANGLES, found, box); + + while(--found >= 0) + driver->draw3DTriangle(triangles[found], video::SColor(255, 255, 0, 0)); + } + + driver->endScene(); + result &= takeScreenshotAndCompareAgainstReference(driver, "-tri_select1.png"); + } + { + boxPosition.Z -= 10.f; + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0xff00ffff)); + smgr->drawAll(); + + core::aabbox3df box(boxPosition.X - BOX_SIZE, boxPosition.Y - BOX_SIZE, boxPosition.Z - BOX_SIZE, + boxPosition.X + BOX_SIZE, boxPosition.Y + BOX_SIZE, boxPosition.Z + BOX_SIZE); + + driver->setTransform(video::ETS_WORLD, core::matrix4()); + driver->setMaterial(unlit); + driver->draw3DBox(box, video::SColor(255, 0, 255, 0)); + + if(meta) + { + s32 found; + meta->getTriangles(triangles, MAX_TRIANGLES, found, box); + + while(--found >= 0) + driver->draw3DTriangle(triangles[found], video::SColor(255, 255, 0, 0)); + } + + driver->endScene(); + result &= takeScreenshotAndCompareAgainstReference(driver, "-tri_select2.png"); + } + { + boxPosition.Z -= 20.f; + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0xff00ffff)); + smgr->drawAll(); + + core::aabbox3df box(boxPosition.X - BOX_SIZE, boxPosition.Y - BOX_SIZE, boxPosition.Z - BOX_SIZE, + boxPosition.X + BOX_SIZE, boxPosition.Y + BOX_SIZE, boxPosition.Z + BOX_SIZE); + + driver->setTransform(video::ETS_WORLD, core::matrix4()); + driver->setMaterial(unlit); + driver->draw3DBox(box, video::SColor(255, 0, 255, 0)); + + if(meta) + { + s32 found; + meta->getTriangles(triangles, MAX_TRIANGLES, found, box); + + while(--found >= 0) + driver->draw3DTriangle(triangles[found], video::SColor(255, 255, 0, 0)); + } + + driver->endScene(); + result &= takeScreenshotAndCompareAgainstReference(driver, "-tri_select3.png"); + } + + meta->drop(); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} +} + +// Tests need not be accurate, as we just need to include at least +// the triangles that match the criteria. But we try to be as close +// as possible of course, to reduce the collision checks done afterwards +bool triangleSelector(void) +{ + bool result = true; + + result &= octree(); + result &= triangle(); + + return result; +} diff --git a/tests/userClipPlane.cpp b/tests/userClipPlane.cpp new file mode 100644 index 00000000..ab87cfeb --- /dev/null +++ b/tests/userClipPlane.cpp @@ -0,0 +1,69 @@ +#include "testUtils.h" + +using namespace irr; + +static bool withSphere(video::E_DRIVER_TYPE type) +{ + IrrlichtDevice* device = createDevice(type, core::dimension2d(160, 120)); + + if (device == 0) + return true; + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + + stabilizeScreenBackground(driver); + + driver->setClipPlane(0, core::plane3df(core::vector3df(0,18,0), core::vector3df(0,-1,0)), true); + smgr->addLightSceneNode(0, core::vector3df(30,30,50)); + // create first sphere + scene::ISceneNode* sphere = smgr->addMeshSceneNode(smgr->addSphereMesh("sphere", 10, 64, 64)); + + if (sphere) + { + sphere->setPosition(core::vector3df(0,10,0)); + sphere->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false); + } + + sphere = smgr->addMeshSceneNode(smgr->addHillPlaneMesh("mesh", core::dimension2df(10,10), core::dimension2du(10,10))); + sphere->setPosition(core::vector3df(0,10,0)); + + smgr->addCameraSceneNode(0, core::vector3df(-25,30,20), core::vector3df()); + + driver->setClipPlane(1, core::plane3df(core::vector3df(0,2,0), core::vector3df(0,1,0)), true); + driver->setClipPlane(2, core::plane3df(core::vector3df(8,0,0), core::vector3df(-1,0,0))); + + device->run(); +// while(device->run()) + { + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,113,113,133)); + driver->setClipPlane(3, core::plane3df(core::vector3df(-8,0,0), core::vector3df(1,0,0)), true); + driver->setClipPlane(4, core::plane3df(core::vector3df(0,0,8), core::vector3df(0,0,-1))); + driver->setClipPlane(5, core::plane3df(core::vector3df(0,0,-8), core::vector3df(0,0,1))); + driver->enableClipPlane(2, true); + driver->enableClipPlane(4, true); + driver->enableClipPlane(5, true); + smgr->drawAll(); + driver->enableClipPlane(1, false); + driver->enableClipPlane(2, false); + driver->enableClipPlane(4, false); + driver->enableClipPlane(5, false); + driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); + driver->setMaterial(video::IdentityMaterial); + driver->draw3DLine(core::vector3df(), core::vector3df(0,0,50)); + driver->endScene(); + } + bool result = takeScreenshotAndCompareAgainstReference(driver, "-ucpsphere.png"); + + device->closeDevice(); + device->run(); + device->drop(); + return result; +} + +bool userclipplane() +{ + bool result = true; + TestWithAllHWDrivers(withSphere); + return result; +} diff --git a/tests/vectorPositionDimension2d.cpp b/tests/vectorPositionDimension2d.cpp new file mode 100644 index 00000000..5a02fb5d --- /dev/null +++ b/tests/vectorPositionDimension2d.cpp @@ -0,0 +1,93 @@ +// Copyright (C) 2008-2012 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" + +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)); + assert_log(result); + + dimension = (T)2 * position; + result &= (dimension == VECTOR(2 * (T)99.9, 2 * (T)99.9)); + assert_log(result); + + dimension /= (T)2; + result &= (dimension == POSITION((T)99.9, (T)99.9)); + assert_log(result); + + dimension += vector; + result &= (dimension == VECTOR(2 * (T)99.9, 2 * (T)99.9)); + assert_log(result); + + dimension -= position; + result &= (dimension == POSITION((T)99.9, (T)99.9)); + assert_log(result); + + position = dimension; + result &= (position == VECTOR((T)99.9, (T)99.9)); + assert_log(result); + + vector += position; + result &= (vector == POSITION(2 * (T)99.9, 2 * (T)99.9)); + assert_log(result); + + vector -= position; + result &= (vector == dimension); + assert_log(result); + + position *= (T)3.5; + result &= (position == VECTOR((T)3.5 * (T)99.9, (T)3.5 * (T)99.9)); + assert_log(result); + + vector += dimension; + result &= (vector == VECTOR(2 * (T)99.9, 2 * (T)99.9)); + assert_log(result); + + return result; +} + +bool vectorPositionDimension2d(void) +{ + bool result = true; + + logTestString("vector,position,dimension test with s32\n\n"); + result &= doTest(); + if (result) + logTestString("tests passed\n\n"); + else + logTestString("\ntests failed\n\n"); + logTestString("vector,position,dimension test with f32\n\n"); + result &= doTest(); + if (result) + logTestString("tests passed\n\n"); + else + logTestString("\ntests failed\n\n"); + logTestString("vector,position,dimension test with f64\n\n"); + result &= doTest, vector2d, position2d, f64>(); + if (result) + logTestString("tests passed\n\n"); + else + logTestString("\ntests failed\n\n"); + + return result; +} + diff --git a/tests/videoDriver.cpp b/tests/videoDriver.cpp new file mode 100644 index 00000000..3635ebe8 --- /dev/null +++ b/tests/videoDriver.cpp @@ -0,0 +1,44 @@ +// Copyright (C) 2008-2012 Colin MacDonald, Christian Stehno +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; + +/** Test various things in video drivers. */ +bool testVideoDriver(video::E_DRIVER_TYPE driverType) +{ + IrrlichtDevice *device = + createDevice(driverType, dimension2d(160, 120)); + + if (!device) + return true; + + video::IVideoDriver* driver = device->getVideoDriver(); + logTestString("Testing driver %ls\n", driver->getName()); + logTestString("MaxTextures: %d\n", driver->getDriverAttributes().getAttributeAsInt("MaxTextures")); + logTestString("MaxSupportedTextures: %d\n", driver->getDriverAttributes().getAttributeAsInt("MaxSupportedTextures")); + logTestString("MaxLights: %d\n", driver->getDriverAttributes().getAttributeAsInt("MaxLights")); + logTestString("MaxAnisotropy: %d\n", driver->getDriverAttributes().getAttributeAsInt("MaxAnisotropy")); + logTestString("MaxUserClipPlanes: %d\n", driver->getDriverAttributes().getAttributeAsInt("MaxUserClipPlanes")); + logTestString("MaxAuxBuffers: %d\n", driver->getDriverAttributes().getAttributeAsInt("MaxAuxBuffers")); + logTestString("MaxMultipleRenderTargets: %d\n", driver->getDriverAttributes().getAttributeAsInt("MaxMultipleRenderTargets")); + logTestString("MaxIndices: %d\n", driver->getDriverAttributes().getAttributeAsInt("MaxIndices")); + logTestString("MaxTextureSize: %d\n", driver->getDriverAttributes().getAttributeAsInt("MaxTextureSize")); + logTestString("MaxGeometryVerticesOut: %d\n", driver->getDriverAttributes().getAttributeAsInt("MaxGeometryVerticesOut")); + logTestString("Version: %d\n", driver->getDriverAttributes().getAttributeAsInt("Version")); + logTestString("ShaderLanguageVersion: %d\n\n", driver->getDriverAttributes().getAttributeAsInt("ShaderLanguageVersion")); + + device->closeDevice(); + device->run(); + device->drop(); + return true; +} + +bool videoDriver() +{ + bool result = true; + TestWithAllDrivers(testVideoDriver); + return result; +} diff --git a/tests/viewPort.cpp b/tests/viewPort.cpp new file mode 100644 index 00000000..9afd9e27 --- /dev/null +++ b/tests/viewPort.cpp @@ -0,0 +1,79 @@ +// Copyright (C) 2008-2012 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +//! Tests view ports and text rendering. +/** The result should be as follows: We have three times the same image, a billboard with a cube and the text in front. +They are replicated three times, one centered in the screen without viewport, one in the upper left (qurter screen) and +one on the right (half screen). The latter is stretched due to the changed aspect ratio. +The two viewport scenes get the texture drawn over the center as well, using draw2dimage. This should mark the proper +image position with the top left corner of the texture. +Finally, each scene has a checkbox drawn at the left side, vertically centered. This will show whether GUI elements adhere +to viewports as well. */ +static bool viewPortText(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(); + IGUIEnvironment* env = smgr->getGUIEnvironment(); + + stabilizeScreenBackground(driver); + + env->addCheckBox(true, core::recti(10,60,28,82)); + + logTestString("Testing driver %ls\n", driver->getName()); + + IBillboardSceneNode * bnode = smgr->addBillboardSceneNode(0,dimension2d(32,32),core::vector3df(0,0,10)); + bnode->setMaterialFlag(video::EMF_LIGHTING, false); + bnode->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); + bnode->setMaterialTexture(0, driver->getTexture("../media/fire.bmp")); + + smgr->addTextSceneNode(device->getGUIEnvironment()->getBuiltInFont(), L"TEST", video::SColor(255,255,255,255), 0); + smgr->addCubeSceneNode(); + smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0)); + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, SColor(255,100,101,140)); + smgr->drawAll(); + env->drawAll(); + driver->setViewPort(rect(0,0,160/2,120/2)); + smgr->drawAll(); + env->drawAll(); + driver->draw2DImage(driver->getTexture("../media/fire.bmp"), core::vector2di(160/2,120/2)); + driver->setViewPort(rect(160/2,0,160,120)); + smgr->drawAll(); + env->drawAll(); + driver->draw2DImage(driver->getTexture("../media/fire.bmp"), core::vector2di(160/2,120/2)); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-viewPortText.png", 98.71f); + + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + + +bool viewPort(void) +{ + bool result = true; + + // TODO: software driver and burnings don't use view port for + // 2d rendering, so result is pretty wrong. + TestWithAllDrivers(viewPortText); + + return result; +} + diff --git a/tests/writeImageToFile.cpp b/tests/writeImageToFile.cpp new file mode 100644 index 00000000..4614befe --- /dev/null +++ b/tests/writeImageToFile.cpp @@ -0,0 +1,137 @@ +// Copyright (C) 2009-2012 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 "testUtils.h" + +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(video::ECBF_COLOR | video::ECBF_DEPTH, 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; + video::ECOLOR_FORMAT format; + + irr::video::IImage * screenshot = driver->createScreenShot(video::ECF_R8G8B8); + if (!screenshot) + { + logTestString("Failed to take screenshot\n"); + assert_log(false); + goto cleanup; + } + + format = screenshot->getColorFormat(); + if (format != video::ECF_R8G8B8) + { + irr::video::IImage * fixedScreenshot = driver->createImage(video::ECF_R8G8B8, screenshot->getDimension()); + screenshot->copyTo(fixedScreenshot); + screenshot->drop(); + screenshot = 0; + + if (!fixedScreenshot) + { + logTestString("Failed to convert screenshot to ECF_A8R8G8B8\n"); + assert_log(false); + goto cleanup; + } + + screenshot = fixedScreenshot; + } + + buffer = new c8[BUFFER_SIZE]; + writtenFilename = "results/Burning's Video-writeImageToFile.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_log(false); + goto cleanup; + } + + writtenFile = device->getFileSystem()->createAndWriteFile(memoryFile->getFileName()); + if (!writtenFile) + { + logTestString("Can't open %s for writing.\n", writtenFilename); + assert_log(false); + goto cleanup; + } + + if ((size_t)memoryFile->getPos() != writtenFile->write(buffer, (size_t)memoryFile->getPos())) + { + logTestString("Error while writing to %s.\n", writtenFilename); + assert_log(false); + goto cleanup; + } + + writtenFile->drop(); + writtenFile = 0; + + referenceFilename = "media/Burning's Video-drawPixel.png"; + + if ( fuzzyCompareImages(driver,writtenFilename, referenceFilename) < 99.9) + { + logTestString("File written from memory is not the same as the reference file. %s:%d\n" , __FILE__, __LINE__); +// assert_log(false); + goto cleanup; + } + + result = true; + +cleanup: + if ( screenshot ) + screenshot->drop(); + + if(writtenFile) + writtenFile->drop(); + + if(memoryFile) + memoryFile->drop(); + + delete [] buffer; + + device->drop(); + + return result; +} + diff --git a/tools/Exporters/Blender/B3DExport.py b/tools/Exporters/Blender/B3DExport.py new file mode 100644 index 00000000..025b64eb --- /dev/null +++ b/tools/Exporters/Blender/B3DExport.py @@ -0,0 +1,1611 @@ +#!BPY + +""" +Name: 'B3D Exporter (.b3d)...' +Blender: 259 +Group: 'Export' +Tooltip: 'Export to Blitz3D file format (.b3d)' +""" +__author__ = ["iego 'GaNDaLDF' Parisi, MTLZ (is06), Joerg Henrichs, Marianne Gagnon"] +__url__ = ["www.gandaldf.com"] +__version__ = "3.0" +__bpydoc__ = """\ +""" + +# BLITZ3D EXPORTER 3.0 +# Copyright (C) 2009 by Diego "GaNDaLDF" Parisi - www.gandaldf.com +# Lightmap issue fixed by Capricorn 76 Pty. Ltd. - www.capricorn76.com +# Blender 2.63 compatiblity based on work by MTLZ, www.is06.com +# With changes by Marianne Gagnon, Joerg Henrichs and Vincent Lejeune, supertuxkart.sf.net (Copyright (C) 2011-2012) +# +# LICENSE: +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +bl_info = { + "name": "B3D (BLITZ3D) Model Exporter", + "description": "Exports a blender scene or object to the B3D (BLITZ3D) format", + "author": "Diego 'GaNDaLDF' Parisi, MTLZ (is06), Joerg Henrichs, Marianne Gagnon, Vincent Lejeune", + "version": (3,1), + "blender": (2, 5, 9), + "api": 31236, + "location": "File > Export", + "warning": '', # used for warning icon and text in addons panel + "wiki_url": "http://supertuxkart.sourceforge.net/Get_involved", + "tracker_url": "https://sourceforge.net/apps/trac/supertuxkart/", + "category": "Import-Export"} + + +import bpy +import sys,os,os.path,struct,math,string +import mathutils +import math + +if not hasattr(sys,"argv"): sys.argv = ["???"] + + +#Global Stacks +b3d_parameters = {} +texture_flags = [] +texs_stack = {} +brus_stack = [] +vertex_groups = [] +bone_stack = {} +keys_stack = [] + +texture_count = 0 + +# bone_stack indices constants +BONE_PARENT_MATRIX = 0 +BONE_PARENT = 1 +BONE_ITSELF = 2 + +# texture stack indices constants +TEXTURE_ID = 0 +TEXTURE_FLAGS = 1 + +per_face_vertices = {} + +the_scene = None + +#Transformation Matrix +TRANS_MATRIX = mathutils.Matrix([[1,0,0,0],[0,0,1,0],[0,1,0,0],[0,0,0,1]]) +BONE_TRANS_MATRIX = mathutils.Matrix([[-1,0,0,0],[0,0,-1,0],[0,-1,0,0],[0,0,0,1]]) + +DEBUG = False +PROGRESS = True +PROGRESS_VERBOSE = False + +tesselated_objects = {} + +#Support Functions +def write_int(value): + return struct.pack(" 48: + value = encoded[0:48] + binary_format = "<%ds"%(len(encoded)+1) + return struct.pack(binary_format, encoded) + +def write_chunk(name,value): + dummy = bytearray() + return dummy + name + write_int(len(value)) + value + +trimmed_paths = {} + +def getArmatureAnimationEnd(armature): + end_frame = 1 + if armature.animation_data.action: + ipo = armature.animation_data.action.fcurves + for curve in ipo: + if "pose" in curve.data_path: + end_frame = max(end_frame, curve.keyframe_points[-1].co[0]) + + for nla_track in armature.animation_data.nla_tracks: + if len(nla_track.strips) > 0: + end_frame = max(end_frame, nla_track.strips[-1].frame_end) + + return end_frame + +# ==== Write B3D File ==== +# (main exporter function) +def write_b3d_file(filename, objects=[]): + global texture_flags, texs_stack, trimmed_paths, tesselated_objects + global brus_stack, vertex_groups, bone_stack, keys_stack + + #Global Stacks + texture_flags = [] + texs_stack = {} + brus_stack = [] + vertex_groups = [] + bone_stack = [] + keys_stack = [] + trimmed_paths = {} + file_buf = bytearray() + temp_buf = bytearray() + tesselated_objects = {} + + import time + start = time.time() + + temp_buf += write_int(1) #Version + temp_buf += write_texs(objects) #TEXS + temp_buf += write_brus(objects) #BRUS + temp_buf += write_node(objects) #NODE + + if len(temp_buf) > 0: + file_buf += write_chunk(b"BB3D",temp_buf) + temp_buf = "" + + file = open(filename,'wb') + file.write(file_buf) + file.close() + + # free memory + trimmed_paths = {} + + end = time.time() + + print("Exported in", (end - start)) + + +def tesselate_if_needed(objdata): + if objdata not in tesselated_objects: + objdata.calc_tessface() + tesselated_objects[objdata] = True + return objdata + +def getUVTextures(obj_data): + # BMesh in blender 2.63 broke this + if bpy.app.version[1] >= 63: + return tesselate_if_needed(obj_data).tessface_uv_textures + else: + return obj_data.uv_textures + +def getFaces(obj_data): + # BMesh in blender 2.63 broke this + if bpy.app.version[1] >= 63: + return tesselate_if_needed(obj_data).tessfaces + else: + return obj_data.faces + +def getVertexColors(obj_data): + # BMesh in blender 2.63 broke this + if bpy.app.version[1] >= 63: + return tesselate_if_needed(obj_data).tessface_vertex_colors + else: + return obj_data.vertex_colors + +# ==== Write TEXS Chunk ==== +def write_texs(objects=[]): + global b3d_parameters + global trimmed_paths + global texture_count + texs_buf = bytearray() + temp_buf = bytearray() + layer_max = 0 + obj_count = 0 + set_wrote = 0 + + if objects: + exp_obj = objects + else: + if b3d_parameters.get("export-selected"): + exp_obj = [ob for ob in bpy.data.objects if ob.select] + else: + exp_obj = bpy.data.objects + + if PROGRESS: print(len(exp_obj),"TEXS") + + if PROGRESS_VERBOSE: progress = 0 + + for obj in exp_obj: + + if PROGRESS_VERBOSE: + progress = progress + 1 + if (progress % 10 == 0): print("TEXS",progress,"/",len(exp_obj)) + + if obj.type == "MESH": + set_count = 0 + set_wrote = 0 + #data = obj.getData(mesh = True) + data = obj.data + + # FIXME? + #orig_uvlayer = data.activeUVLayer + + layer_set = [[],[],[],[],[],[],[],[]] + + # 8 UV layers are supported + texture_flags.append([None,None,None,None,None,None,None,None]) + + #if len(data.getUVLayerNames()) <= 8: + uv_textures = getUVTextures(data) + if len(uv_textures) <= 8: + if len(uv_textures) > layer_max: + layer_max = len(uv_textures) + else: + layer_max = 8 + + for face in getFaces(data): + for iuvlayer,uvlayer in enumerate(uv_textures): + if iuvlayer < 8: + + # FIXME? + #data.activeUVLayer = uvlayer + + #layer_set[iuvlayer].append(face.uv) + new_data = None + try: + new_data = uvlayer.data[face.index].uv + except: + pass + + layer_set[iuvlayer].append( new_data ) + + for i in range(len(uv_textures)): + if set_wrote: + set_count += 1 + set_wrote = 0 + + for iuvlayer in range(i,len(uv_textures)): + if layer_set[i] == layer_set[iuvlayer]: + if texture_flags[obj_count][iuvlayer] is None: + if set_count == 0: + tex_flag = 1 + elif set_count == 1: + tex_flag = 65536 + elif set_count > 1: + tex_flag = 1 + if b3d_parameters.get("mipmap"): + enable_mipmaps=8 + else: + enable_mipmaps=0 + texture_flags[obj_count][iuvlayer] = tex_flag | enable_mipmaps + set_wrote = 1 + + for face in getFaces(data): + for iuvlayer,uvlayer in enumerate(uv_textures): + if iuvlayer < 8: + + if not (iuvlayer < len(uv_textures)): + continue + + # FIXME? + #data.activeUVLayer = uvlayer + + #if DEBUG: print("") + + img = getUVTextures(data)[iuvlayer].data[face.index].image + + if img: + + if img.filepath in trimmed_paths: + img_name = trimmed_paths[img.filepath] + else: + img_name = bpy.path.basename(img.filepath) + trimmed_paths[img.filepath] = img_name + + if not img_name in texs_stack: + texs_stack[img_name] = [len(texs_stack), texture_flags[obj_count][iuvlayer]] + temp_buf += write_string(img_name) #Texture File Name + temp_buf += write_int(texture_flags[obj_count][iuvlayer]) #Flags + temp_buf += write_int(2) #Blend + temp_buf += write_float(0) #X_Pos + temp_buf += write_float(0) #Y_Pos + temp_buf += write_float(1) #X_Scale + temp_buf += write_float(1) #Y_Scale + temp_buf += write_float(0) #Rotation + #else: + # if DEBUG: print(" ") + + #if DEBUG: print("") + + obj_count += 1 + + #FIXME? + #if orig_uvlayer: + # data.activeUVLayer = orig_uvlayer + + texture_count = layer_max + + if len(temp_buf) > 0: + texs_buf += write_chunk(b"TEXS",temp_buf) + temp_buf = "" + + return texs_buf + +# ==== Write BRUS Chunk ==== +def write_brus(objects=[]): + global b3d_parameters + global trimmed_paths + global texture_count + brus_buf = bytearray() + temp_buf = bytearray() + mat_count = 0 + obj_count = 0 + + if DEBUG: print("") + + if objects: + exp_obj = objects + else: + if b3d_parameters.get("export-selected"): + exp_obj = [ob for ob in bpy.data.objects if ob.select] + else: + exp_obj = bpy.data.objects + + if PROGRESS: print(len(exp_obj),"BRUS") + if PROGRESS_VERBOSE: progress = 0 + + for obj in exp_obj: + + if PROGRESS_VERBOSE: + progress += 1 + if (progress % 10 == 0): print("BRUS",progress,"/",len(exp_obj)) + + if obj.type == "MESH": + data = obj.data + + uv_textures = getUVTextures(data) + + if len(uv_textures) <= 0: + continue + + if DEBUG: print("") + + img_found = 0 + + for face in getFaces(data): + + face_stack = [] + + for iuvlayer,uvlayer in enumerate(uv_textures): + if iuvlayer < 8: + + img_id = -1 + + if face.index >= len(uv_textures[iuvlayer].data): + continue + + img = uv_textures[iuvlayer].data[face.index].image + + if not img: + continue + + img_found = 1 + + if img.filepath in trimmed_paths: + img_name = trimmed_paths[img.filepath] + else: + img_name = os.path.basename(img.filepath) + trimmed_paths[img.filepath] = img_name + + if DEBUG: print(" ") + + if img_name in texs_stack: + img_id = texs_stack[img_name][TEXTURE_ID] + + face_stack.insert(iuvlayer,img_id) + if DEBUG: print(" ") + + for i in range(len(face_stack),texture_count): + face_stack.append(-1) + + + if DEBUG: print(" ") + + if not img_found: + if data.materials: + if data.materials[face.material_index]: + mat_data = data.materials[face.material_index] + mat_colr = mat_data.diffuse_color[0] + mat_colg = mat_data.diffuse_color[1] + mat_colb = mat_data.diffuse_color[2] + mat_alpha = mat_data.alpha + mat_name = mat_data.name + + if not mat_name in brus_stack: + brus_stack.append(mat_name) + temp_buf += write_string(mat_name) #Brush Name + temp_buf += write_float(mat_colr) #Red + temp_buf += write_float(mat_colg) #Green + temp_buf += write_float(mat_colb) #Blue + temp_buf += write_float(mat_alpha) #Alpha + temp_buf += write_float(0) #Shininess + temp_buf += write_int(1) #Blend + if b3d_parameters.get("vertex-colors") and len(getVertexColors(data)): + temp_buf += write_int(2) #Fx + else: + temp_buf += write_int(0) #Fx + + for i in face_stack: + temp_buf += write_int(i) #Texture ID + else: + if b3d_parameters.get("vertex-colors") and len(getVertexColors(data)) > 0: + if not face_stack in brus_stack: + brus_stack.append(face_stack) + mat_count += 1 + temp_buf += write_string("Brush.%.3i"%mat_count) #Brush Name + temp_buf += write_float(1) #Red + temp_buf += write_float(1) #Green + temp_buf += write_float(1) #Blue + temp_buf += write_float(1) #Alpha + temp_buf += write_float(0) #Shininess + temp_buf += write_int(1) #Blend + temp_buf += write_int(2) #Fx + + for i in face_stack: + temp_buf += write_int(i) #Texture ID + else: # img_found + + if not face_stack in brus_stack: + brus_stack.append(face_stack) + mat_count += 1 + temp_buf += write_string("Brush.%.3i"%mat_count) #Brush Name + temp_buf += write_float(1) #Red + temp_buf += write_float(1) #Green + temp_buf += write_float(1) #Blue + temp_buf += write_float(1) #Alpha + temp_buf += write_float(0) #Shininess + temp_buf += write_int(1) #Blend + + if DEBUG: print(" ") + + if b3d_parameters.get("vertex-colors") and len(getVertexColors(data)) > 0: + temp_buf += write_int(2) #Fx + else: + temp_buf += write_int(0) #Fx + + for i in face_stack: + temp_buf += write_int(i) #Texture ID + if DEBUG: print(" ") + + if DEBUG: print(" ") + + if DEBUG: print("") + + if DEBUG: print("") + obj_count += 1 + + #FIXME? + #if orig_uvlayer: + # data.activeUVLayer = orig_uvlayer + + if len(temp_buf) > 0: + brus_buf += write_chunk(b"BRUS",write_int(texture_count) + temp_buf) #N Texs + temp_buf = "" + + return brus_buf + +# ==== Write NODE Chunk ==== +def write_node(objects=[]): + global bone_stack + global keys_stack + global b3d_parameters + global the_scene + + root_buf = [] + node_buf = [] + main_buf = bytearray() + temp_buf = [] + obj_count = 0 + amb_light = 0 + + num_mesh = 0 + num_ligs = 0 + num_cams = 0 + num_lorc = 0 + #exp_scn = Blender.Scene.GetCurrent() + #exp_scn = the_scene + #exp_con = exp_scn.getRenderingContext() + + #first_frame = Blender.Draw.Create(exp_con.startFrame()) + #last_frame = Blender.Draw.Create(exp_con.endFrame()) + #num_frames = last_frame.val - first_frame.val + first_frame = the_scene.frame_start + + if DEBUG: print("") + + if objects: + exp_obj = objects + else: + if b3d_parameters.get("export-selected"): + exp_obj = [ob for ob in bpy.data.objects if ob.select] + else: + exp_obj = bpy.data.objects + + for obj in exp_obj: + if obj.type == "MESH": + num_mesh += 1 + if obj.type == "CAMERA": + num_cams += 1 + if obj.type == "LAMP": + num_ligs += 1 + + if b3d_parameters.get("cameras"): + num_lorc += num_cams + + if b3d_parameters.get("lights"): + num_lorc += 1 + num_lorc += num_ligs + + if num_mesh + num_lorc > 1: + exp_root = 1 + else: + exp_root = 0 + + if exp_root: + root_buf.append(write_string("ROOT")) #Node Name + + root_buf.append(write_float_triplet(0, 0, 0)) #Position X,Y,Z + root_buf.append(write_float_triplet(1, 1, 1)) #Scale X, Y, Z + root_buf.append(write_float_quad(1, 0, 0, 0)) #Rotation W, X, Y, Z + + if PROGRESS: progress = 0 + + for obj in exp_obj: + + if PROGRESS: + progress += 1 + print("NODE:",progress,"/",len(exp_obj),obj.name) + + if obj.type == "MESH": + + if DEBUG: print(" ") + + bone_stack = {} + keys_stack = [] + + anim_data = None + + # check if this object has an armature modifier + for curr_mod in obj.modifiers: + if curr_mod.type == 'ARMATURE': + arm = curr_mod.object + if arm is not None: + anim_data = arm.animation_data + + # check if this object has an armature parent (second way to do armature animations in blender) + if anim_data is None: + if obj.parent: + if obj.parent.type == "ARMATURE": + arm = obj.parent + if arm.animation_data: + anim_data = arm.animation_data + + if anim_data: + matrix = mathutils.Matrix() + + temp_buf.append(write_string(obj.name)) #Node Name + + position = matrix.to_translation() + temp_buf.append(write_float_triplet(position[0], position[1], position[2])) #Position X, Y, Z + + scale = matrix.to_scale() + temp_buf.append(write_float_triplet(scale[0], scale[2], scale[1])) #Scale X, Y, Z + + if DEBUG: print(" ") + + quat = matrix.to_quaternion() + quat.normalize() + + temp_buf.append(write_float_quad(quat.w, quat.x, quat.z, quat.y)) + else: + if b3d_parameters.get("local-space"): + matrix = TRANS_MATRIX.copy() + scale_matrix = mathutils.Matrix() + else: + matrix = obj.matrix_world*TRANS_MATRIX + scale_matrix = obj.matrix_world.copy() + + + if bpy.app.version[1] >= 62: + # blender 2.62 broke the API : Column-major access was changed to row-major access + tmp = mathutils.Vector([matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1]]) + matrix[0][1] = matrix[0][2] + matrix[1][1] = matrix[1][2] + matrix[2][1] = matrix[2][2] + matrix[3][1] = matrix[3][2] + + matrix[0][2] = tmp[0] + matrix[1][2] = tmp[1] + matrix[2][2] = tmp[2] + matrix[3][2] = tmp[3] + else: + tmp = mathutils.Vector(matrix[1]) + matrix[1] = matrix[2] + matrix[2] = tmp + + temp_buf.append(write_string(obj.name)) #Node Name + + #print("Matrix : ", matrix) + position = matrix.to_translation() + + temp_buf.append(write_float_triplet(position[0], position[2], position[1])) + + scale = scale_matrix.to_scale() + temp_buf.append(write_float_triplet(scale[0], scale[2], scale[1])) + + quat = matrix.to_quaternion() + quat.normalize() + + temp_buf.append(write_float_quad(quat.w, quat.x, quat.z, quat.y)) + + if DEBUG: + print(" ",position[0],position[2],position[1],"") + print(" ",scale[0],scale[1],scale[2],"") + print(" ", quat.w, quat.x, quat.y, quat.z, "") + + if anim_data: + the_scene.frame_set(1,subframe=0.0) + + arm_matrix = arm.matrix_world + + if b3d_parameters.get("local-space"): + arm_matrix = mathutils.Matrix() + + def read_armature(arm_matrix,bone,parent = None): + if (parent and not bone.parent.name == parent.name): + return + + matrix = mathutils.Matrix(bone.matrix) + + if parent: + + #print("==== "+bone.name+" ====") + a = (bone.matrix_local) + + #print("A : [%.2f %.2f %.2f %.2f]" % (a[0][0], a[0][1], a[0][2], a[0][3])) + #print(" [%.2f %.2f %.2f %.2f]" % (a[1][0], a[1][1], a[1][2], a[1][3])) + #print(" [%.2f %.2f %.2f %.2f]" % (a[2][0], a[2][1], a[2][2], a[2][3])) + #print(" [%.2f %.2f %.2f %.2f]" % (a[3][0], a[3][1], a[3][2], a[3][3])) + + b = (parent.matrix_local.inverted().to_4x4()) + + #print("B : [%.2f %.2f %.2f %.2f]" % (b[0][0], b[0][1], b[0][2], b[0][3])) + #print(" [%.2f %.2f %.2f %.2f]" % (b[1][0], b[1][1], b[1][2], b[1][3])) + #print(" [%.2f %.2f %.2f %.2f]" % (b[2][0], b[2][1], b[2][2], b[2][3])) + #print(" [%.2f %.2f %.2f %.2f]" % (b[3][0], b[3][1], b[3][2], b[3][3])) + + par_matrix = b * a + + transform = mathutils.Matrix([[1,0,0,0],[0,0,-1,0],[0,-1,0,0],[0,0,0,1]]) + par_matrix = transform*par_matrix*transform + + # FIXME: that's ugly, find a clean way to change the matrix..... + if bpy.app.version[1] >= 62: + # blender 2.62 broke the API : Column-major access was changed to row-major access + # TODO: test me + par_matrix[1][3] = -par_matrix[1][3] + par_matrix[2][3] = -par_matrix[2][3] + else: + par_matrix[3][1] = -par_matrix[3][1] + par_matrix[3][2] = -par_matrix[3][2] + + #c = par_matrix + #print("With parent") + #print("C : [%.3f %.3f %.3f %.3f]" % (c[0][0], c[0][1], c[0][2], c[0][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[1][0], c[1][1], c[1][2], c[1][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[2][0], c[2][1], c[2][2], c[2][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[3][0], c[3][1], c[3][2], c[3][3])) + + else: + + #print("==== "+bone.name+" ====") + #print("Without parent") + + m = arm_matrix*bone.matrix_local + + #c = arm.matrix_world + #print("A : [%.3f %.3f %.3f %.3f]" % (c[0][0], c[0][1], c[0][2], c[0][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[1][0], c[1][1], c[1][2], c[1][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[2][0], c[2][1], c[2][2], c[2][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[3][0], c[3][1], c[3][2], c[3][3])) + + #c = bone.matrix_local + #print("B : [%.3f %.3f %.3f %.3f]" % (c[0][0], c[0][1], c[0][2], c[0][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[1][0], c[1][1], c[1][2], c[1][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[2][0], c[2][1], c[2][2], c[2][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[3][0], c[3][1], c[3][2], c[3][3])) + + par_matrix = m*mathutils.Matrix([[-1,0,0,0],[0,0,1,0],[0,1,0,0],[0,0,0,1]]) + + #c = par_matrix + #print("C : [%.3f %.3f %.3f %.3f]" % (c[0][0], c[0][1], c[0][2], c[0][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[1][0], c[1][1], c[1][2], c[1][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[2][0], c[2][1], c[2][2], c[2][3])) + #print(" [%.3f %.3f %.3f %.3f]" % (c[3][0], c[3][1], c[3][2], c[3][3])) + + + bone_stack[bone.name] = [par_matrix,parent,bone] + + if bone.children: + for child in bone.children: read_armature(arm_matrix,child,bone) + + for bone in arm.data.bones.values(): + if not bone.parent: + read_armature(arm_matrix,bone) + + frame_count = first_frame + + last_frame = int(getArmatureAnimationEnd(arm)) + num_frames = last_frame - first_frame + + while frame_count <= last_frame: + + the_scene.frame_set(int(frame_count), subframe=0.0) + + if DEBUG: print(" ") + arm_pose = arm.pose + arm_matrix = arm.matrix_world + + transform = mathutils.Matrix([[-1,0,0,0],[0,0,1,0],[0,1,0,0],[0,0,0,1]]) + arm_matrix = transform*arm_matrix + #arm_quat = arm_matrix.to_quaternion() + #arm_quat.normalize() + + for bone_name in arm.data.bones.keys(): + #bone_matrix = mathutils.Matrix(arm_pose.bones[bone_name].poseMatrix) + bone_matrix = mathutils.Matrix(arm_pose.bones[bone_name].matrix) + + #print("(outer loop) bone_matrix for",bone_name,"=", bone_matrix) + + #print(bone_name,":",bone_matrix) + + #bone_matrix = bpy.data.scenes[0].objects[0].pose.bones['Bone'].matrix + + for ibone in bone_stack: + + bone = bone_stack[ibone] + + if bone[BONE_ITSELF].name == bone_name: + + if DEBUG: print(" ") + + # == 2.4 exporter == + #if bone_stack[ibone][1]: + # par_matrix = Blender.Mathutils.Matrix(arm_pose.bones[bone_stack[ibone][1].name].poseMatrix) + # bone_matrix *= par_matrix.invert() + #else: + # if b3d_parameters.get("local-space"): + # bone_matrix *= TRANS_MATRIX + # else: + # bone_matrix *= arm_matrix + #bone_loc = bone_matrix.translationPart() + #bone_rot = bone_matrix.rotationPart().toQuat() + #bone_rot.normalize() + #bone_sca = bone_matrix.scalePart() + #keys_stack.append([frame_count - first_frame.val+1,bone_name,bone_loc,bone_sca,bone_rot]) + + # if has parent + if bone[BONE_PARENT]: + par_matrix = mathutils.Matrix(arm_pose.bones[bone[BONE_PARENT].name].matrix) + bone_matrix = par_matrix.inverted()*bone_matrix + else: + if b3d_parameters.get("local-space"): + bone_matrix = bone_matrix*mathutils.Matrix([[-1,0,0,0],[0,0,1,0],[0,1,0,0],[0,0,0,1]]) + else: + + #if frame_count == 1: + # print("====",bone_name,"====") + # print("arm_matrix = ", arm_matrix) + # print("bone_matrix = ", bone_matrix) + + bone_matrix = arm_matrix*bone_matrix + + #if frame_count == 1: + # print("arm_matrix*bone_matrix", bone_matrix) + + + #print("bone_matrix =", bone_matrix) + + bone_sca = bone_matrix.to_scale() + bone_loc = bone_matrix.to_translation() + + # FIXME: silly tweaks to resemble the Blender 2.4 exporter output + if b3d_parameters.get("local-space"): + + bone_rot = bone_matrix.to_quaternion() + bone_rot.normalize() + + + if not bone[BONE_PARENT]: + tmp = bone_rot.z + bone_rot.z = bone_rot.y + bone_rot.y = tmp + + bone_rot.x = -bone_rot.x + else: + tmp = bone_loc.z + bone_loc.z = bone_loc.y + bone_loc.y = tmp + + else: + bone_rot = bone_matrix.to_quaternion() + bone_rot.normalize() + + # Sometimes to_quaternion exhibits precision issue with parent bone + # Use quaternion product instead of getting quaternion from the product. + #if not bone[BONE_PARENT]: + # bone_rot = arm_pose.bones[bone_name].matrix.to_quaternion() * arm_quat + # bone_rot.x = -bone_rot.x + # tmp = bone_rot.z + # bone_rot.z = bone_rot.y + # bone_rot.y = tmp + + keys_stack.append([frame_count - first_frame+1, bone_name, bone_loc, bone_sca, bone_rot]) + if DEBUG: print(" ", bone_loc, "") + if DEBUG: print(" ", bone_rot, "") + if DEBUG: print(" ", bone_sca, "") + if DEBUG: print(" ") + + frame_count += 1 + + if DEBUG: print(" ") + + #Blender.Set("curframe",0) + #Blender.Window.Redraw() + + temp_buf.append(write_node_mesh(obj,obj_count,anim_data,exp_root)) #NODE MESH + + if anim_data: + temp_buf.append(write_node_anim(num_frames)) #NODE ANIM + + for ibone in bone_stack: + if not bone_stack[ibone][BONE_PARENT]: + temp_buf.append(write_node_node(ibone)) #NODE NODE + + obj_count += 1 + + if len(temp_buf) > 0: + node_buf.append(write_chunk(b"NODE",b"".join(temp_buf))) + temp_buf = [] + + if DEBUG: print(" ") + + if b3d_parameters.get("cameras"): + if obj.type == "CAMERA": + data = obj.data + matrix = obj.getMatrix("worldspace") + matrix *= TRANS_MATRIX + + if data.type == "ORTHO": + cam_type = 2 + cam_zoom = round(data.scale,4) + else: + cam_type = 1 + cam_zoom = round(data.lens,4) + + cam_near = round(data.clipStart,4) + cam_far = round(data.clipEnd,4) + + node_name = ("CAMS"+"\n%s"%obj.name+"\n%s"%cam_type+\ + "\n%s"%cam_zoom+"\n%s"%cam_near+"\n%s"%cam_far) + temp_buf.append(write_string(node_name)) #Node Name + + position = matrix.translation_part() + temp_buf.append(write_float_triplet(-position[0], position[1], position[2])) + + scale = matrix.scale_part() + temp_buf.append(write_float_triplet(scale[0], scale[1], scale[2])) + + matrix *= mathutils.Matrix.Rotation(180,4,'Y') + quat = matrix.to_quat() + quat.normalize() + + temp_buf.append(write_float_quad(quat.w, quat.x, quat.y, -quat.z)) + + if len(temp_buf) > 0: + node_buf.append(write_chunk(b"NODE",b"".join(temp_buf))) + temp_buf = [] + + if b3d_parameters.get("lights"): + if amb_light == 0: + data = Blender.World.GetCurrent() + + amb_light = 1 + amb_color = (int(data.amb[2]*255) |(int(data.amb[1]*255) << 8) | (int(data.amb[0]*255) << 16)) + + node_name = (b"AMBI"+"\n%s"%amb_color) + temp_buf.append(write_string(node_name)) #Node Name + + temp_buf.append(write_float_triplet(0, 0, 0)) #Position X, Y, Z + temp_buf.append(write_float_triplet(1, 1, 1)) #Scale X, Y, Z + temp_buf.append(write_float_quad(1, 0, 0, 0)) #Rotation W, X, Y, Z + + if len(temp_buf) > 0: + node_buf.append(write_chunk(b"NODE",b"".join(temp_buf))) + temp_buf = [] + + if obj.type == "LAMP": + data = obj.getData() + matrix = obj.getMatrix("worldspace") + matrix *= TRANS_MATRIX + + if data.type == 0: + lig_type = 2 + elif data.type == 2: + lig_type = 3 + else: + lig_type = 1 + + lig_angle = round(data.spotSize,4) + lig_color = (int(data.b*255) |(int(data.g*255) << 8) | (int(data.r*255) << 16)) + lig_range = round(data.dist,4) + + node_name = ("LIGS"+"\n%s"%obj.name+"\n%s"%lig_type+\ + "\n%s"%lig_angle+"\n%s"%lig_color+"\n%s"%lig_range) + temp_buf.append(write_string(node_name)) #Node Name + + position = matrix.translation_part() + temp_buf.append(write_float_triplet(-position[0], position[1], position[2])) + if DEBUG: print(" ",-position[0],position[1],position[2],"") + + scale = matrix.scale_part() + temp_buf.append(write_float_triplet(scale[0], scale[1], scale[2])) + + if DEBUG: print(" ",scale[0],scale[1],scale[2],"") + + matrix *= mathutils.Matrix.Rotation(180,4,'Y') + quat = matrix.toQuat() + quat.normalize() + + temp_buf.append(write_float_quad(quat.w, quat.x, quat.y, -quat.z)) + if DEBUG: print(" ", quat.w, quat.x, quat.y, quat.z, "") + + if len(temp_buf) > 0: + node_buf.append(write_chunk(b"NODE","b".join(temp_buf))) + temp_buf = [] + + if len(node_buf) > 0: + if exp_root: + main_buf += write_chunk(b"NODE",b"".join(root_buf) + b"".join(node_buf)) + else: + main_buf += b"".join(node_buf) + + node_buf = [] + root_buf = [] + + if DEBUG: print("") + + return main_buf + +# ==== Write NODE MESH Chunk ==== +def write_node_mesh(obj,obj_count,arm_action,exp_root): + global vertex_groups + vertex_groups = [] + mesh_buf = bytearray() + temp_buf = bytearray() + + if arm_action: + data = obj.data + elif b3d_parameters.get("apply-modifiers"): + data = obj.to_mesh(the_scene, True, 'PREVIEW') # Apply modifiers + else: + data = obj.data + + temp_buf += write_int(-1) #Brush ID + temp_buf += write_node_mesh_vrts(obj, data, obj_count, arm_action, exp_root) #NODE MESH VRTS + temp_buf += write_node_mesh_tris(obj, data, obj_count, arm_action, exp_root) #NODE MESH TRIS + + if len(temp_buf) > 0: + mesh_buf += write_chunk(b"MESH",temp_buf) + temp_buf = "" + + return mesh_buf + +def build_vertex_groups(data): + for f in getFaces(data): + for v in f.vertices: + vertex_groups.append({}) + + +# ==== Write NODE MESH VRTS Chunk ==== +def write_node_mesh_vrts(obj, data, obj_count, arm_action, exp_root): + vrts_buf = bytearray() + temp_buf = [] + obj_flags = 0 + + #global time_in_a + #global time_in_b + #global time_in_b1 + #global time_in_b2 + #global time_in_b3 + #global time_in_b4 + + #data = obj.getData(mesh = True) + global the_scene + + # FIXME: port to 2.5 API? + #orig_uvlayer = data.activeUVLayer + + if b3d_parameters.get("vertex-normals"): + obj_flags += 1 + + #if b3d_parameters.get("vertex-colors") and data.getColorLayerNames(): + if b3d_parameters.get("vertex-colors") and len(getVertexColors(data)) > 0: + obj_flags += 2 + + temp_buf.append(write_int(obj_flags)) #Flags + #temp_buf += write_int(len(data.getUVLayerNames())) #UV Set + temp_buf.append(write_int(len(getUVTextures(data)))) #UV Set + temp_buf.append(write_int(2)) #UV Set Size + + # ---- Prepare the mesh "stack" + build_vertex_groups(data) + + # ---- Fill the mesh "stack" + if DEBUG: print("") + if DEBUG: print(" \n") + + ivert = -1 + + + #if PROGRESS_VERBOSE: + # progress = 0 + # print(" vertex_groups, face:",0,"/",len(getFaces(data))) + + the_scene.frame_set(1,subframe=0.0) + + if b3d_parameters.get("local-space"): + mesh_matrix = mathutils.Matrix() + else: + mesh_matrix = obj.matrix_world.copy() + + #import time + + uvdata = getUVTextures(data) + uv_layers_count = len(uvdata) + uv_textures = {} + weldable_vertices = {} + vertex_id_mapping = {} + for face in getFaces(data): + for vertex_index,vert in enumerate(face.vertices): + #for id,vert in enumerate(data.vertices): + + if vert not in uv_textures: + uv_textures[vert] = {} + if face not in uv_textures[vert]: + uv_textures[vert][face] = {} + + for iuvlayer in range(uv_layers_count): + if vertex_index == 0: + uv_textures[vert][face][iuvlayer] = uvdata[iuvlayer].data[face.index].uv1 + elif vertex_index == 1: + uv_textures[vert][face][iuvlayer] = uvdata[iuvlayer].data[face.index].uv2 + elif vertex_index == 2: + uv_textures[vert][face][iuvlayer] = uvdata[iuvlayer].data[face.index].uv3 + elif vertex_index == 3: + uv_textures[vert][face][iuvlayer] = uvdata[iuvlayer].data[face.index].uv4 + + for idVertex, vertexFaces in uv_textures.items(): + is_weldable = True + + for iuvlayer in range(uv_layers_count): + u = None + v = None + for idFace, face in vertexFaces.items(): + if iuvlayer not in face: + continue + faceuvlayer = face[iuvlayer] + if u is None: + u = round(faceuvlayer[0]*1000) + v = round(faceuvlayer[1]*1000) + else: + if round(faceuvlayer[0] * 1000) != u or round(faceuvlayer[1]*1000) != v: + is_weldable = False + break + if not is_weldable: + break + + weldable_vertices[idVertex] = is_weldable + + + #print('uv_textures', uv_textures) + #print('weldable_vertices', weldable_vertices) + + for face in getFaces(data): + + if DEBUG: print(" ") + + #if PROGRESS_VERBOSE: + # progress += 1 + # if (progress % 50 == 0): print(" vertex_groups, face:",progress,"/",len(data.faces)) + + per_face_vertices[face.index] = [] + + for vertex_id,vert in enumerate(face.vertices): + + if vert in weldable_vertices and weldable_vertices[vert] and vert in vertex_id_mapping: + per_face_vertices[face.index].append(vertex_id_mapping[vert]) + continue + + ivert += 1 + vertex_id_mapping[vert] = ivert + per_face_vertices[face.index].append(ivert) + + #a = time.time() + + if arm_action: + v = mesh_matrix * data.vertices[vert].co + vert_matrix = mathutils.Matrix.Translation(v) + else: + vert_matrix = mathutils.Matrix.Translation(data.vertices[vert].co) + + vert_matrix *= TRANS_MATRIX + vcoord = vert_matrix.to_translation() + + temp_buf.append(write_float_triplet(vcoord.x, vcoord.z, vcoord.y)) + + #b = time.time() + #time_in_a += b - a + + if b3d_parameters.get("vertex-normals"): + norm_matrix = mathutils.Matrix.Translation(data.vertices[vert].normal) + + if arm_action: + norm_matrix *= mesh_matrix + + norm_matrix *= TRANS_MATRIX + normal_vector = norm_matrix.to_translation() + + temp_buf.append(write_float_triplet(normal_vector.x, #NX + normal_vector.z, #NY + normal_vector.y)) #NZ + + #c = time.time() + #time_in_b += c - b + + if b3d_parameters.get("vertex-colors") and len(getVertexColors(data)) > 0: + vertex_colors = getVertexColors(data) + if vertex_id == 0: + vcolor = vertex_colors[0].data[face.index].color1 + elif vertex_id == 1: + vcolor = vertex_colors[0].data[face.index].color2 + elif vertex_id == 2: + vcolor = vertex_colors[0].data[face.index].color3 + elif vertex_id == 3: + vcolor = vertex_colors[0].data[face.index].color4 + + valpha = 1.0 + if (len(vertex_colors) > 1): + if vertex_id == 0: + valpha = vertex_colors[1].data[face.index].color1.r + elif vertex_id == 1: + valpha = vertex_colors[1].data[face.index].color2.r + elif vertex_id == 2: + valpha = vertex_colors[1].data[face.index].color3.r + elif vertex_id == 3: + valpha = vertex_colors[1].data[face.index].color4.r + + temp_buf.append(write_float_quad(vcolor.r, #R + vcolor.g, #G + vcolor.b, #B + valpha)) #A (FIXME?) + + #d = time.time() + #time_in_b1 += d - c + + for vg in obj.vertex_groups: + w = 0.0 + try: + w = vg.weight(vert) + except: + pass + vertex_groups[ivert][vg.name] = w + + #e = time.time() + #time_in_b2 += e - d + + for iuvlayer in range(uv_layers_count): + uv = [10, 10] + if vert in uv_textures: + vertex_uv = uv_textures[vert] + + if face in vertex_uv: + vertex_face_uv = vertex_uv[face] + + if iuvlayer in vertex_face_uv: + uv = vertex_face_uv[iuvlayer] + + temp_buf.append(write_float_couple(uv[0], 1-uv[1]) ) # U, V + + + + if DEBUG: print("") + + #c = time.time() + #time_in_b += c - b + #print("time_in_a = ",time_in_a) + #print("time_in_b = ",time_in_b) + #print("time_in_b1 = ", time_in_b1) + #print("time_in_b2 = ", time_in_b2) + #print("time_in_b3 = ", time_in_b3) + #print("time_in_b4 = ", time_in_b4) + + if len(temp_buf) > 0: + vrts_buf += write_chunk(b"VRTS",b"".join(temp_buf)) + temp_buf = [] + + return vrts_buf + +# ==== Write NODE MESH TRIS Chunk ==== +def write_node_mesh_tris(obj, data, obj_count,arm_action,exp_root): + + global texture_count + + #FIXME? + #orig_uvlayer = data.activeUVLayer + + # An dictoriary that maps all brush-ids to a list of faces + # using this brush. This helps to sort the triangles by + # brush, creating less mesh buffer in irrlicht. + dBrushId2Face = {} + + if DEBUG: print("") + + for face in getFaces(data): + img_found = 0 + face_stack = [] + + uv_textures = getUVTextures(data) + uv_layer_count = len(uv_textures) + for iuvlayer,uvlayer in enumerate(uv_textures): + if iuvlayer < 8: + + if iuvlayer >= uv_layer_count: + continue + + img_id = -1 + + img = uv_textures[iuvlayer].data[face.index].image + if img: + + if img.filepath in trimmed_paths: + img_name = trimmed_paths[img.filepath] + else: + img_name = os.path.basename(img.filepath) + trimmed_paths[img.filepath] = img_name + + img_found = 1 + if img_name in texs_stack: + img_id = texs_stack[img_name][TEXTURE_ID] + + face_stack.insert(iuvlayer,img_id) + + for i in range(len(face_stack),texture_count): + face_stack.append(-1) + + if img_found == 0: + brus_id = -1 + if data.materials and data.materials[face.material_index]: + mat_name = data.materials[face.material_index].name + for i in range(len(brus_stack)): + if brus_stack[i] == mat_name: + brus_id = i + break + else: + for i in range(len(brus_stack)): + if brus_stack[i] == face_stack: + brus_id = i + break + else: + brus_id = -1 + for i in range(len(brus_stack)): + if brus_stack[i] == face_stack: + brus_id = i + break + if brus_id == -1: + print("Cannot find in brus stack : ", face_stack) + + if brus_id in dBrushId2Face: + dBrushId2Face[brus_id].append(face) + else: + dBrushId2Face[brus_id] = [face] + + if DEBUG: print(" ") + + tris_buf = bytearray() + + if DEBUG: print("") + if DEBUG: print(" ") + + if PROGRESS_VERBOSE: progress = 0 + + for brus_id in dBrushId2Face.keys(): + + if PROGRESS_VERBOSE: + progress += 1 + print("BRUS:",progress,"/",len(dBrushId2Face.keys())) + + temp_buf = [write_int(brus_id)] #Brush ID + + if DEBUG: print(" ") + + if PROGRESS_VERBOSE: progress2 = 0 + + for face in dBrushId2Face[brus_id]: + + if PROGRESS_VERBOSE: + progress2 += 1 + if (progress2 % 50 == 0): print(" TRIS:",progress2,"/",len(dBrushId2Face[brus_id])) + + vertices = per_face_vertices[face.index] + + temp_buf.append(write_int(vertices[2])) #A + temp_buf.append(write_int(vertices[1])) #B + temp_buf.append(write_int(vertices[0])) #C + + if DEBUG: print(" ") + + if len(face.vertices) == 4: + temp_buf.append(write_int(vertices[3])) #A + temp_buf.append(write_int(vertices[2])) #B + temp_buf.append(write_int(vertices[0])) #C + if DEBUG: print(" ") + + if DEBUG: print(" ") + tris_buf += write_chunk(b"TRIS", b"".join(temp_buf)) + + return tris_buf + +# ==== Write NODE ANIM Chunk ==== +def write_node_anim(num_frames): + anim_buf = bytearray() + temp_buf = bytearray() + + temp_buf += write_int(0) #Flags + temp_buf += write_int(num_frames) #Frames + temp_buf += write_float(60) #FPS + + if len(temp_buf) > 0: + anim_buf += write_chunk(b"ANIM",temp_buf) + temp_buf = "" + + return anim_buf + +# ==== Write NODE NODE Chunk ==== +def write_node_node(ibone): + node_buf = bytearray() + temp_buf = [] + + bone = bone_stack[ibone] + + matrix = bone[BONE_PARENT_MATRIX] + temp_buf.append(write_string(bone[BONE_ITSELF].name)) #Node Name + + + + # FIXME: we should use the same matrix format everywhere to not require this + + position = matrix.to_translation() + if bone[BONE_PARENT]: + temp_buf.append(write_float_triplet(-position[0], position[2], position[1])) + else: + temp_buf.append(write_float_triplet(position[0], position[2], position[1])) + + + scale = matrix.to_scale() + temp_buf.append(write_float_triplet(scale[0], scale[2], scale[1])) + + quat = matrix.to_quaternion() + quat.normalize() + + temp_buf.append(write_float_quad(quat.w, quat.x, quat.z, quat.y)) + + temp_buf.append(write_node_bone(ibone)) + temp_buf.append(write_node_keys(ibone)) + + for iibone in bone_stack: + if bone_stack[iibone][BONE_PARENT] == bone_stack[ibone][BONE_ITSELF]: + temp_buf.append(write_node_node(iibone)) + + if len(temp_buf) > 0: + node_buf += write_chunk(b"NODE", b"".join(temp_buf)) + temp_buf = [] + + return node_buf + +# ==== Write NODE BONE Chunk ==== +def write_node_bone(ibone): + bone_buf = bytearray() + temp_buf = [] + + my_name = bone_stack[ibone][BONE_ITSELF].name + + for ivert in range(len(vertex_groups)): + if my_name in vertex_groups[ivert]: + vert_influ = vertex_groups[ivert][my_name] + #if DEBUG: print(" ") + temp_buf.append(write_int(ivert)) # Face Vertex ID + temp_buf.append(write_float(vert_influ)) #Weight + + bone_buf += write_chunk(b"BONE", b"".join(temp_buf)) + temp_buf = [] + + return bone_buf + +# ==== Write NODE KEYS Chunk ==== +def write_node_keys(ibone): + keys_buf = bytearray() + temp_buf = [] + + temp_buf.append(write_int(7)) #Flags + + my_name = bone_stack[ibone][BONE_ITSELF].name + + for ikeys in range(len(keys_stack)): + if keys_stack[ikeys][1] == my_name: + temp_buf.append(write_int(keys_stack[ikeys][0])) #Frame + + position = keys_stack[ikeys][2] + # FIXME: we should use the same matrix format everywhere and not require this + if b3d_parameters.get("local-space"): + if bone_stack[ibone][BONE_PARENT]: + temp_buf.append(write_float_triplet(-position[0], position[2], position[1])) + else: + temp_buf.append(write_float_triplet(position[0], position[2], position[1])) + else: + temp_buf.append(write_float_triplet(-position[0], position[1], position[2])) + + scale = keys_stack[ikeys][3] + temp_buf.append(write_float_triplet(scale[0], scale[1], scale[2])) + + quat = keys_stack[ikeys][4] + quat.normalize() + + temp_buf.append(write_float_quad(quat.w, -quat.x, quat.y, quat.z)) + #break + + keys_buf += write_chunk(b"KEYS",b"".join(temp_buf)) + temp_buf = [] + + return keys_buf + + +# ==== CONFIRM OPERATOR ==== +class B3D_Confirm_Operator(bpy.types.Operator): + bl_idname = ("screen.b3d_confirm") + bl_label = ("File Exists, Overwrite?") + + def invoke(self, context, event): + wm = context.window_manager + return wm.invoke_props_dialog(self) + + def execute(self, context): + write_b3d_file(B3D_Confirm_Operator.filepath) + return {'FINISHED'} + + +#class ObjectListItem(bpy.types.PropertyGroup): +# id = bpy.props.IntProperty(name="ID") +# +#bpy.utils.register_class(ObjectListItem) + +# ==== EXPORT OPERATOR ==== + +class B3D_Export_Operator(bpy.types.Operator): + bl_idname = ("screen.b3d_export") + bl_label = ("B3D Export") + filepath = bpy.props.StringProperty(subtype="FILE_PATH") + + selected = bpy.props.BoolProperty(name="Export Selected Only", default=False) + vnormals = bpy.props.BoolProperty(name="Export Vertex Normals", default=True) + vcolors = bpy.props.BoolProperty(name="Export Vertex Colors", default=True) + cameras = bpy.props.BoolProperty(name="Export Cameras", default=False) + lights = bpy.props.BoolProperty(name="Export Lights", default=False) + mipmap = bpy.props.BoolProperty(name="Mipmap", default=False) + localsp = bpy.props.BoolProperty(name="Use Local Space Coords", default=False) + applymodifiers = bpy.props.BoolProperty(name="Apply modifiers", default=True) + + overwrite_without_asking = bpy.props.BoolProperty(name="Overwrite without asking", default=False) + + #skip_dialog = False + + #objects = bpy.props.CollectionProperty(type=ObjectListItem, options={'HIDDEN'}) + + def invoke(self, context, event): + blend_filepath = context.blend_data.filepath + if not blend_filepath: + blend_filepath = "Untitled.b3d" + else: + blend_filepath = os.path.splitext(blend_filepath)[0] + ".b3d" + self.filepath = blend_filepath + + context.window_manager.fileselect_add(self) + return {'RUNNING_MODAL'} + + def execute(self, context): + + global b3d_parameters + global the_scene + b3d_parameters["export-selected"] = self.selected + b3d_parameters["vertex-normals" ] = self.vnormals + b3d_parameters["vertex-colors" ] = self.vcolors + b3d_parameters["cameras" ] = self.cameras + b3d_parameters["lights" ] = self.lights + b3d_parameters["mipmap" ] = self.mipmap + b3d_parameters["local-space" ] = self.localsp + b3d_parameters["apply-modifiers"] = self.applymodifiers + + the_scene = context.scene + + if self.filepath == "": + return {'FINISHED'} + + if not self.filepath.endswith(".b3d"): + self.filepath += ".b3d" + + print("EXPORT", self.filepath," vcolor = ", self.vcolors) + + obj_list = [] + try: + # FIXME: silly and ugly hack, the list of objects to export is passed through + # a custom scene property + obj_list = context.scene.obj_list + except: + pass + + if len(obj_list) > 0: + + #objlist = [] + #for a in self.objects: + # objlist.append(bpy.data.objects[a.id]) + # + #write_b3d_file(self.filepath, obj_list) + + write_b3d_file(self.filepath, obj_list) + else: + if os.path.exists(self.filepath) and not self.overwrite_without_asking: + #self.report({'ERROR'}, "File Exists") + B3D_Confirm_Operator.filepath = self.filepath + bpy.ops.screen.b3d_confirm('INVOKE_DEFAULT') + return {'FINISHED'} + else: + write_b3d_file(self.filepath) + return {'FINISHED'} + + +# Add to a menu +def menu_func_export(self, context): + global the_scene + the_scene = context.scene + self.layout.operator(B3D_Export_Operator.bl_idname, text="B3D (.b3d)") + +def register(): + bpy.types.INFO_MT_file_export.append(menu_func_export) + bpy.utils.register_module(__name__) + +def unregister(): + bpy.types.INFO_MT_file_export.remove(menu_func_export) + +if __name__ == "__main__": + register() + diff --git a/tools/FileToHeader/FileToHeader.cbp b/tools/FileToHeader/FileToHeader.cbp new file mode 100644 index 00000000..e6c1a2d7 --- /dev/null +++ b/tools/FileToHeader/FileToHeader.cbp @@ -0,0 +1,48 @@ + + + + + + diff --git a/tools/FileToHeader/Makefile b/tools/FileToHeader/Makefile new file mode 100644 index 00000000..e9cd8184 --- /dev/null +++ b/tools/FileToHeader/Makefile @@ -0,0 +1,35 @@ +# Makefile for FileToHeader +Target = FileToHeader +Sources = main.cpp + +# general compiler settings +CPPFLAGS = -I../../include +CXXFLAGS = -O3 -ffast-math -Wall +#CXXFLAGS = -g -Wall + +#default target is Linux +all: all_linux + +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif + +# target specific settings +all_linux clean_linux: SYSTEM=Linux +all_win32: LDFLAGS = -L../../lib/Win32-gcc +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/tools/FileToHeader/main.cpp b/tools/FileToHeader/main.cpp new file mode 100644 index 00000000..b3cc7a75 --- /dev/null +++ b/tools/FileToHeader/main.cpp @@ -0,0 +1,175 @@ +// Copyright (C) 2012 Gaz Davidson +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +/*** + This tool creates a .h file from a given input file by encoding it into a C string, + allowing you to build your resources directly into your binaries, just like Irrlicht's + built-in font. + + To distribute your app as a single executable file of minimal size: + + 1. Put all your resources into a single directory and add it to Irrlicht's filesystem + as a folder through IFileSystem::addArchive. Develop and test your app as usual. + 2. Open IrrCompileConfig.h and comment out all the options that your app does not use. + This will reduce the size of the Irrlicht library considerably. + * You should remove the D3D video drivers, because they rely on external DLLs. + * You should keep either the TAR or ZIP archive loader, used in step 6. + * If you remove the JPEG loader, you don't have to say you use JPEG code in your + documentation. + 3. Recompile Irrlicht as a static library, editing the IRR_STATIC_LIB line in + IrrCompileConfig.h. + The next time you compile your application it will take a while longer, but + Irrlicht will be built into your binary. + 4. TAR or ZIP your resource directory using your favourite archiving tool (ie 7zip). + * If you chose ZIP but compiled without zlib, don't compress this archive or it + won't open. + 5. Run this tool to convert your resource file into a .h file, like so: + FileToHeader res.zip > EmbeddedResources.h + 6. Add the .h file to your project, create the embedded read file then mount as a + ZIP or TAR archive instead of the folder, like so: + io::IReadFile *f = io::createEmbeddedFile(device->getFileSystem(), "res.zip"); + device->getFileSystem()->addFileArchive(f); + archive->drop(); + 7. Recompile your app. + * If you use Microsoft's compiler, make sure your CRT (common run-time) is + the static library version, otherwise you'll have a dependency on the CRT DLLs. + Your binary should now be completely portable; you can distribute just the exe file. + 8. Optional: Use UPX (upx.sf.net) to compress your binary. +*/ + +#include +#include +#include + +using namespace std; + +int main(int argc, char* argv[]) +{ + if (argc < 2) + { + // print usage + cerr << "You must to specify at least one input file" << endl; + cerr << "usage: " << argv[0] << " [file2...]" << endl; + cerr << "outputs a header file to stdout, so for example use"; + return 1; + } + + int i = 1; + + // write file header + cout << "// File made by FileToHeader, part of the Irrlicht Engine" << endl + << endl + << "#ifndef _EMBEDDED_FILES_H_INCLUDED_" << endl + << "#define _EMBEDDED_FILES_H_INCLUDED_" << endl + << endl + << "#include \"irrTypes.h\"" << endl + << "#include \"IReadFile.h\"" << endl + << "#include \"IFileSystem.h\"" << endl + << endl + << "namespace irr" << endl + << "{" << endl + << "namespace io" << endl + << "{" << endl + << endl + << " const c8* EmbeddedFileData[] = " << endl + << " {" << endl; + + // store sizes and file names + stringstream sizes; + stringstream names; + sizes << "const u32 EmbeddedFileSizes[] = {"; + names << "const c8* EmbeddedFileNames[] = {"; + int fileCount = 0; + + // char to hex digit table, probably doesn't help for speed due to fstream. better than using sprintf though + char hextable[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + + while (i < argc) + { + // open and seek to end of file + ifstream input; + input.open(argv[i], ios::in | ios::binary | ios::ate); + + if (input.is_open()) + { + int size = input.tellg(); + input.seekg(0, ios::beg); + // read the file into RAM + char *entireFile = new char[size]; + input.read(entireFile, size); + + if (fileCount) + { + sizes << ", "; + names << ", "; + cout << "," << endl; + } + + // save file size and name + sizes << size; + names << '"' << argv[i] << '"'; + + // write the file data + cout << " \""; + for (int count=0; count < size; ++count) + { + if (count && (count % 16) == 0) + cout << "\"" << endl << " \""; + + cout << "\\x" << hextable[(entireFile[count] >> 4) & 0xF] << hextable[entireFile[count] & 0x0F]; + } + cout << "\""; + + delete [] entireFile; + // + input.close(); + + fileCount++; + } + else + { + cerr << "Failed to open file: " << argv[i] << endl; + } + + ++i; + } + + // close binary file list and write file metadata + cout << endl + << " , 0};" << endl + << endl + << " const u32 EmbeddedFileCount = " << fileCount << ";" << endl + << " " << sizes.str() << "};" << endl + << " " << names.str() << "};" << endl + << endl; + + // write functions to create embedded IReadFiles + cout << " IReadFile* createEmbeddedFile(IFileSystem *fs, u32 index)" << endl + << " {" << endl + << " if (EmbeddedFileCount < index)" << endl + << " return 0;" << endl + << endl + << " return fs->createMemoryReadFile((void*)EmbeddedFileData[index], " << endl + << " EmbeddedFileSizes[index], EmbeddedFileNames[index]);" << endl + << " }" << endl + << endl + << " IReadFile* createEmbeddedFile(IFileSystem *fs, path filename)" << endl + << " {" << endl + << " for (u32 i=0; i < EmbeddedFileCount; ++i)" << endl + << " if (filename == EmbeddedFileNames[i])" << endl + << " return createEmbeddedFile(fs, i);" << endl + << endl + << " return 0;" << endl + << " }" << endl + << endl; + + // write footer + cout << "} // namespace io" << endl + << "} // namespace irr" << endl + << endl + << "#endif // _EMBEDDED_FILES_H_INCLUDED_" << endl; + + return 0; +} + diff --git a/tools/GUIEditor/CGUIAttribute.h b/tools/GUIEditor/CGUIAttribute.h new file mode 100644 index 00000000..05854980 --- /dev/null +++ b/tools/GUIEditor/CGUIAttribute.h @@ -0,0 +1,169 @@ +/* + This base class is used by the Attribute editor for making your own attribute types. + + The attribute editor will try and create an attribute called "AttribType_attribute", + and if it fails, it will create a "string_attribute". + +*/ + +#ifndef __C_GUI_ATTRIBUTE_H_INCLUDED__ +#define __C_GUI_ATTRIBUTE_H_INCLUDED__ + +#include "IGUIElement.h" +#include "IGUIEnvironment.h" +#include "IGUIFont.h" +#include "IGUIStaticText.h" +#include "IAttributes.h" +#include "CGUIEditWorkspace.h" + +namespace irr +{ + +namespace gui +{ + + const u32 ATTRIBEDIT_ATTRIB_CHANGED=MAKE_IRR_ID('A','T','T','R'); + + class CGUIAttribute : public IGUIElement + { + public: + //! constructor + CGUIAttribute(IGUIEnvironment* environment, IGUIElement *parent, s32 myParentID) : + IGUIElement(EGUIET_ELEMENT, environment, parent, -1, core::rect(0, 0, 100, 100) ), + AttribName(0), Attribs(0), Index(0), MyParentID(myParentID) + { + + #ifdef _DEBUG + setDebugName("CGUIAttribute"); + #endif + + AttribName = environment->addStaticText(0, + core::rect(0, 0, + 100, Environment->getSkin()->getFont()->getDimension(L"A").Height), + false, false, this, -1, false); + AttribName->grab(); + AttribName->setSubElement(true); + AttribName->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + } + + virtual ~CGUIAttribute() + { + if (Attribs) + Attribs->drop(); + if (AttribName) + AttribName->drop(); + } + + virtual bool OnEvent(const SEvent &e) + { + if (IsEnabled) + { + switch (e.EventType) + { + case EET_GUI_EVENT: + switch (e.GUIEvent.EventType) + { + case EGET_ELEMENT_FOCUSED: + if (Parent && isMyChild(e.GUIEvent.Caller)) + Parent->bringToFront(this); + break; + case EGET_ELEMENT_HOVERED: + case EGET_ELEMENT_LEFT: + return IGUIElement::OnEvent(e); + case EGET_ELEMENT_FOCUS_LOST: + updateAttrib(); + return IGUIElement::OnEvent(e); + default: + return updateAttrib(); + } + break; + case EET_KEY_INPUT_EVENT: + return true; + default: + break; + } + } + + return IGUIElement::OnEvent(e); + } + + //! sets the attribute to use + virtual void setAttrib(io::IAttributes *attribs, u32 attribIndex) + { + if (Attribs) + Attribs->drop(); + Attribs = attribs; + if (Attribs) + Attribs->grab(); + Index = attribIndex; + + core::stringw name(attribs->getAttributeName(attribIndex)); + name += L" ("; + name += attribs->getAttributeTypeString(attribIndex); + name += L")"; + AttribName->setText(name.c_str()); + + core::rect r = Parent->getAbsolutePosition(); + core::rect r2(0, 5, + r.getWidth(), Environment->getSkin()->getFont()->getDimension(L"A").Height + 10 ); + + AttribName->setRelativePosition(r2); + + // get minimum height + s32 y=0; + core::list::Iterator it = Children.begin(); + for (; it != Children.end(); ++it) + { + if (y < (*it)->getRelativePosition().LowerRightCorner.Y) + y = (*it)->getRelativePosition().LowerRightCorner.Y; + } + setMinSize( core::dimension2du(0, y+5)); + + updateAttrib(false); + } + + //! sets the parent ID, for identifying where events came from + void setParentID(s32 parentID) + { + MyParentID = parentID; + } + + //! save the attribute and possibly post the event to its parent + virtual bool updateAttrib(bool sendEvent=true) + { + if (Attribs && IsEnabled && sendEvent) + { + // build event and pass to parent + SEvent event; + event.EventType = (EEVENT_TYPE)ATTRIBEDIT_ATTRIB_CHANGED; + event.UserEvent.UserData1 = MyParentID; + event.UserEvent.UserData2 = Index; + return Parent->OnEvent(event); + } + + return true; + } + + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) + { + IGUIElement::serializeAttributes(out, options); + } + + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) + { + IGUIElement::deserializeAttributes(in, options); + if (AttribName) + AttribName->setText(Text.c_str()); + } + + protected: + IGUIStaticText* AttribName; + io::IAttributes* Attribs; + u32 Index; + s32 MyParentID; + }; + +} // namespace gui +} // namespace irr + +#endif diff --git a/tools/GUIEditor/CGUIAttributeEditor.cpp b/tools/GUIEditor/CGUIAttributeEditor.cpp new file mode 100644 index 00000000..45913b66 --- /dev/null +++ b/tools/GUIEditor/CGUIAttributeEditor.cpp @@ -0,0 +1,120 @@ + +#include "CGUIAttributeEditor.h" +#include "IGUIEnvironment.h" +#include "IFileSystem.h" +#include "IVideoDriver.h" +#include "IAttributes.h" +#include "IGUIFont.h" +#include "IGUIScrollBar.h" +#include "CGUIEditWorkspace.h" +#include "CGUIAttribute.h" +#include "CGUIStringAttribute.h" + +namespace irr +{ +namespace gui +{ + +using namespace core; +using namespace io; + +CGUIAttributeEditor::CGUIAttributeEditor(IGUIEnvironment* environment, s32 id, IGUIElement *parent) : + CGUIPanel(environment, parent, id, rect(0, 0, 100, 100)), + Attribs(0), Panel(0) +{ + #ifdef _DEBUG + setDebugName("CGUIAttributeEditor"); + #endif + + // create attributes + Attribs = environment->getFileSystem()->createEmptyAttributes(Environment->getVideoDriver()); + + calculateClientArea(); + resizeInnerPane(); + + // refresh attrib list + refreshAttribs(); + + IGUIScrollBar* sb = getVScrollBar(); + core::rect r = sb->getRelativePosition(); + r.LowerRightCorner.Y -= 16; + sb->setRelativePosition(r); +} + +CGUIAttributeEditor::~CGUIAttributeEditor() +{ + for (u32 i=0; iremove(); + AttribList[i]->drop(); + } + AttribList.clear(); + + Attribs->drop(); +} + + +IAttributes* CGUIAttributeEditor::getAttribs() +{ + return Attribs; +} + +void CGUIAttributeEditor::refreshAttribs() +{ + // clear the attribute list + u32 i; + for (i=0; iremove(); + AttribList[i]->drop(); + } + AttribList.clear(); + + position2di top(10, 5); + rect r(top.X, top.Y, + getClientArea().getWidth() - 10, + 5 + Environment->getSkin()->getFont()->getDimension(L"A").Height); + + // add attribute elements + u32 c = Attribs->getAttributeCount(); + for (i=0; igetAttributeTypeString(i); + str += "_attribute"; + CGUIAttribute* n = (CGUIAttribute*)Environment->addGUIElement(str.c_str(), 0); + + // if this doesn't exist, use a string editor + if (!n) + n = (CGUIAttribute*)Environment->addGUIElement("string_attribute", 0); + + if (n) + { + AttribList.push_back(n); + n->setParentID(getID()); + n->grab(); + } + + // We can't set "this" as parent above as we need functionality + // of the overloaded addChild which isn't called in the constructor. + // (that's a general Irrlicht messup with too fat constructors) + addChild(n); + + AttribList[i]->setSubElement(true); + AttribList[i]->setRelativePosition(r); + AttribList[i]->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + AttribList[i]->setAttrib(Attribs, i); + r += position2di(0, AttribList[i]->getRelativePosition().getHeight() + 5); + } +} + +void CGUIAttributeEditor::updateAttribs() +{ + for (u32 i=0; iupdateAttrib(false); +} + +} // namespace gui +} // namespace irr + diff --git a/tools/GUIEditor/CGUIAttributeEditor.h b/tools/GUIEditor/CGUIAttributeEditor.h new file mode 100644 index 00000000..0bcdab50 --- /dev/null +++ b/tools/GUIEditor/CGUIAttributeEditor.h @@ -0,0 +1,54 @@ +#ifndef __C_GUI_ATTRIBUTE_EDITOR_H_INCLUDED__ +#define __C_GUI_ATTRIBUTE_EDITOR_H_INCLUDED__ + +#include "IGUIElement.h" +#include "CGUIPanel.h" +#include "irrArray.h" +#include "IAttributes.h" +#include "EGUIEditTypes.h" + +namespace irr +{ +namespace gui +{ + + class CGUIAttribute; + + + class CGUIAttributeEditor : public CGUIPanel + { + public: + + //! constructor + CGUIAttributeEditor(IGUIEnvironment* environment, s32 id, IGUIElement *parent=0); + + //! destructor + ~CGUIAttributeEditor(); + + // gets the current attributes list + virtual io::IAttributes* getAttribs(); + + // update the attribute list after making a change + void refreshAttribs(); + + // save the attributes + void updateAttribs(); + + //! Returns the type name of the gui element. + virtual const c8* getTypeName() const + { + return GUIEditElementTypeNames[EGUIEDIT_ATTRIBUTEEDITOR]; + } + + private: + + core::array AttribList; // attributes editing controls + io::IAttributes* Attribs; // current attributes + CGUIPanel* Panel; + }; + +} // end namespace gui +} // end namespace irr + +#endif // __C_GUI_ATTRIBUTE_EDITOR_H_INCLUDED__ + diff --git a/tools/GUIEditor/CGUIBoolAttribute.h b/tools/GUIEditor/CGUIBoolAttribute.h new file mode 100644 index 00000000..b0521db9 --- /dev/null +++ b/tools/GUIEditor/CGUIBoolAttribute.h @@ -0,0 +1,68 @@ +#ifndef __C_GUI_BOOL_ATTRIBUTE_H_INCLUDED__ +#define __C_GUI_BOOL_ATTRIBUTE_H_INCLUDED__ + +#include "CGUIAttribute.h" +#include "IGUICheckBox.h" +#include "EGUIEditTypes.h" + +namespace irr +{ +namespace gui +{ + + class CGUIBoolAttribute : public CGUIAttribute + { + public: + // + CGUIBoolAttribute(IGUIEnvironment* environment, IGUIElement *parent, s32 myParentID) : + CGUIAttribute(environment, parent, myParentID), AttribCheckBox(0) + { + + core::rect r = getAbsolutePosition(); + core::rect r2(0, Environment->getSkin()->getFont()->getDimension(L"A").Height + 10, + r.getWidth() - 5, + Environment->getSkin()->getFont()->getDimension(L"A").Height*2 + 15 ); + + AttribCheckBox = environment->addCheckBox(false, r2, this); + AttribCheckBox->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + AttribCheckBox->setSubElement(true); + AttribCheckBox->grab(); + } + + virtual ~CGUIBoolAttribute() + { + if (AttribCheckBox) + AttribCheckBox->drop(); + } + + virtual void setAttrib(io::IAttributes *attribs, u32 attribIndex) + { + AttribCheckBox->setChecked(attribs->getAttributeAsBool(attribIndex)); + CGUIAttribute::setAttrib(attribs, attribIndex); + } + + // save the attribute and possibly post the event to its parent + virtual bool updateAttrib(bool sendEvent=true) + { + if (!Attribs) + return true; + + Attribs->setAttribute(Index, AttribCheckBox->isChecked()); + + return CGUIAttribute::updateAttrib(sendEvent); + } + + //! Returns the type name of the gui element. + virtual const c8* getTypeName() const + { + return GUIEditElementTypeNames[EGUIEDIT_BOOLATTRIBUTE]; + } + + private: + IGUICheckBox* AttribCheckBox; + }; + +} // namespace gui +} // namespace irr + +#endif diff --git a/tools/GUIEditor/CGUIColorAttribute.h b/tools/GUIEditor/CGUIColorAttribute.h new file mode 100644 index 00000000..e0c5212d --- /dev/null +++ b/tools/GUIEditor/CGUIColorAttribute.h @@ -0,0 +1,179 @@ +#ifndef __C_GUI_COLOR_ATTRIBUTE_H_INCLUDED__ +#define __C_GUI_COLOR_ATTRIBUTE_H_INCLUDED__ + +#include "CGUIAttribute.h" +#include "IGUIStaticText.h" +#include "IGUIScrollBar.h" +#include "IGUITabControl.h" +#include "EGUIEditTypes.h" + +namespace irr +{ +namespace gui +{ + class CGUIColorAttribute : public CGUIAttribute + { + public: + // + CGUIColorAttribute(IGUIEnvironment* environment, IGUIElement *parent, s32 myParentID) : + CGUIAttribute(environment, parent, myParentID), + AttribSliderA(0), AttribSliderR(0), AttribSliderG(0), AttribSliderB(0), + AttribEditBox(0), AttribColor(0) + { + s32 fh = Environment->getSkin()->getFont()->getDimension(L"A").Height; + + core::rect r0(getAbsolutePosition()), + r2(0, fh + 5, r0.getWidth() - 5, fh*2 + 10 ), + r3(r2), + r4(r2.getWidth() - 20, 3, r2.getWidth() - 3, r2.getHeight()-3); + + AttribColor = Environment->addTab(r4, this, 0); + AttribColor->grab(); + AttribColor->setDrawBackground(true); + AttribColor->setSubElement(true); + AttribColor->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + + s32 h=2; + r2 += core::position2di(0, h*4 + Environment->getSkin()->getSize(EGDS_WINDOW_BUTTON_WIDTH)*2); + r3.LowerRightCorner.Y = r3.UpperLeftCorner.Y + Environment->getSkin()->getSize(EGDS_WINDOW_BUTTON_WIDTH)/2; + + AttribSliderA = environment->addScrollBar(true, r3, this, -1); + AttribSliderA->setMax(255); + AttribSliderA->grab(); + AttribSliderA->setSubElement(true); + AttribSliderA->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + r3 += core::position2di(0, r3.getHeight()+h); + AttribSliderR = environment->addScrollBar(true, r3, this, -1); + AttribSliderR->setMax(255); + AttribSliderR->grab(); + AttribSliderR->setSubElement(true); + AttribSliderR->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + r3 += core::position2di(0, r3.getHeight()+h); + AttribSliderG = environment->addScrollBar(true, r3, this, -1); + AttribSliderG->setMax(255); + AttribSliderG->grab(); + AttribSliderG->setSubElement(true); + AttribSliderG->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + r3 += core::position2di(0, r3.getHeight()+h); + AttribSliderB = environment->addScrollBar(true, r3, this, -1); + AttribSliderB->setMax(255); + AttribSliderB->grab(); + AttribSliderB->setSubElement(true); + AttribSliderB->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + + // add editbox + AttribEditBox = environment->addEditBox( + L"", + r2, + true, this, -1); + AttribEditBox->grab(); + AttribEditBox->setSubElement(true); + AttribEditBox->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + } + + virtual ~CGUIColorAttribute() + { + if (AttribSliderA) + AttribSliderA->drop(); + if (AttribSliderR) + AttribSliderR->drop(); + if (AttribSliderG) + AttribSliderG->drop(); + if (AttribSliderB) + AttribSliderB->drop(); + if (AttribEditBox) + AttribEditBox->drop(); + if (AttribColor) + AttribColor->drop(); + } + + virtual void setAttrib(io::IAttributes *attribs, u32 attribIndex) + { + video::SColor col = attribs->getAttributeAsColor(attribIndex); + + AttribSliderA->setPos(col.getAlpha()); + AttribSliderR->setPos(col.getRed()); + AttribSliderG->setPos(col.getGreen()); + AttribSliderB->setPos(col.getBlue()); + AttribEditBox->setText( attribs->getAttributeAsStringW(attribIndex).c_str() ); + AttribColor->setBackgroundColor(col); + + CGUIAttribute::setAttrib(attribs, attribIndex); + } + + virtual bool OnEvent(const SEvent &e) + { + switch (e.EventType) + { + + case EET_GUI_EVENT: + switch (e.GUIEvent.EventType) + { + case EGET_EDITBOX_ENTER: + case EGET_ELEMENT_FOCUS_LOST: + if (e.GUIEvent.Caller == AttribEditBox) + { + // update scrollbars from textbox + Attribs->setAttribute(Index, AttribEditBox->getText()); + video::SColor col = Attribs->getAttributeAsColor(Index); + AttribSliderA->setPos(col.getAlpha()); + AttribSliderR->setPos(col.getRed()); + AttribSliderG->setPos(col.getGreen()); + AttribSliderB->setPos(col.getBlue()); + // update colour + AttribColor->setBackgroundColor(col); + } + break; + case EGET_SCROLL_BAR_CHANGED: + { + // update editbox from scrollbars + video::SColor col( AttribSliderA->getPos(), AttribSliderR->getPos(), + AttribSliderG->getPos(), AttribSliderB->getPos()); + + Attribs->setAttribute(Index, col); + AttribEditBox->setText( Attribs->getAttributeAsStringW(Index).c_str()); + // update colour + AttribColor->setBackgroundColor(col); + } + return updateAttrib(); + default: + break; + } + break; + default: + break; + } + return CGUIAttribute::OnEvent(e); + } + + // save the attribute and possibly post the event to its parent + virtual bool updateAttrib(bool sendEvent=true) + { + if (!Attribs) + return true; + + Attribs->setAttribute(Index, AttribEditBox->getText()); + AttribEditBox->setText(Attribs->getAttributeAsStringW(Index).c_str()); + return CGUIAttribute::updateAttrib(sendEvent); + } + + //! Returns the type name of the gui element. + virtual const c8* getTypeName() const + { + return GUIEditElementTypeNames[EGUIEDIT_COLORATTRIBUTE]; + } + + private: + IGUIScrollBar* AttribSliderA; + IGUIScrollBar* AttribSliderR; + IGUIScrollBar* AttribSliderG; + IGUIScrollBar* AttribSliderB; + IGUIEditBox* AttribEditBox; + IGUITab* AttribColor; + }; + +} // namespace gui +} // namespace irr + +#endif + diff --git a/tools/GUIEditor/CGUIDummyEditorStub.h b/tools/GUIEditor/CGUIDummyEditorStub.h new file mode 100644 index 00000000..635501ad --- /dev/null +++ b/tools/GUIEditor/CGUIDummyEditorStub.h @@ -0,0 +1,59 @@ +/* + This is a custom editor for stubbing problematic elements out, + for example elements which include modal screens +*/ + +#ifndef __C_GUI_DUMMY_EDITOR_STUB_H_INCLUDED__ +#define __C_GUI_DUMMY_EDITOR_STUB_H_INCLUDED__ + +#include "IGUIElement.h" +#include "IGUIEnvironment.h" +#include "IGUIStaticText.h" + +namespace irr +{ + +namespace gui +{ + class CGUIDummyEditorStub : public IGUIElement + { + public: + //! constructor + CGUIDummyEditorStub(IGUIEnvironment* environment, IGUIElement *parent, const char *text) : + IGUIElement(EGUIET_ELEMENT, environment, parent, -1, core::rect(0, 0, 100, 100) ), + TextBox(0), TypeName(text) + { + + #ifdef _DEBUG + setDebugName("CGUIDummyEditorStub"); + #endif + + core::dimension2du d = Environment->getSkin()->getFont()->getDimension(L"A"); + s32 h = d.Height / 2; + s32 w = d.Width / 2; + + TextBox = environment->addStaticText(core::stringw(text).c_str(), + core::rect(50-w, 50-h, 50+w, 50+h), + false, false, this, -1, false); + TextBox->grab(); + TextBox->setSubElement(true); + TextBox->setAlignment(EGUIA_CENTER, EGUIA_CENTER, EGUIA_CENTER, EGUIA_CENTER); + } + + virtual ~CGUIDummyEditorStub() + { + if (TextBox) + TextBox->drop(); + } + virtual const c8* getTypeName() const { return TypeName.c_str(); } + + protected: + IGUIStaticText* TextBox; + core::stringc TypeName; + + }; + +} // namespace gui +} // namespace irr + +#endif diff --git a/tools/GUIEditor/CGUIEditFactory.cpp b/tools/GUIEditor/CGUIEditFactory.cpp new file mode 100644 index 00000000..cbf930b5 --- /dev/null +++ b/tools/GUIEditor/CGUIEditFactory.cpp @@ -0,0 +1,120 @@ +#include "CGUIEditFactory.h" +#include "IGUIEnvironment.h" +#include "irrString.h" + +#include "EGUIEditTypes.h" + +#include "CGUIEditWorkspace.h" +#include "CGUIEditWindow.h" +#include "CGUIPanel.h" +#include "CGUITextureCacheBrowser.h" +#include "CGUIAttributeEditor.h" +#include "CGUIStringAttribute.h" +#include "CGUIBoolAttribute.h" +#include "CGUIEnumAttribute.h" +#include "CGUIColorAttribute.h" +#include "CGUITextureAttribute.h" +#include "CGUIDummyEditorStub.h" + +namespace irr +{ +namespace gui +{ + +CGUIEditFactory::CGUIEditFactory(IGUIEnvironment* env) +: Environment(env) +{ + #ifdef _DEBUG + setDebugName("CGUIEditFactory"); + #endif + + // don't grab the gui environment here to prevent cyclic references +} + + +CGUIEditFactory::~CGUIEditFactory() +{ +} + + +//! adds an element to the environment based on its type name +IGUIElement* CGUIEditFactory::addGUIElement(const c8* typeName, IGUIElement* parent) +{ + /* + here we create elements, add them to the manager, and then drop them + */ + + core::stringc elementType(typeName); + IGUIElement* ret=0; + if (!parent) + parent = Environment->getRootGUIElement(); + + // editor workspace + if (elementType == core::stringc(GUIEditElementTypeNames[EGUIEDIT_GUIEDIT])) + ret = new CGUIEditWorkspace(Environment, -1, 0); + // editor window + else if (elementType == core::stringc(GUIEditElementTypeNames[EGUIEDIT_GUIEDITWINDOW])) + ret = new CGUIEditWindow(Environment, core::rect(0,0,100,100), 0); + // Klasker's GUI Panel + else if (elementType == core::stringc(GUIEditElementTypeNames[EGUIEDIT_GUIPANEL])) + ret = new CGUIPanel(Environment, 0); + // texture cache browser + else if (elementType == core::stringc(GUIEditElementTypeNames[EGUIEDIT_TEXTUREBROWSER])) + ret = new CGUITextureCacheBrowser(Environment, -1, 0); + // block of attribute editors + else if (elementType == core::stringc(GUIEditElementTypeNames[EGUIEDIT_ATTRIBUTEEDITOR])) + ret = new CGUIAttributeEditor(Environment, -1, 0); + //! single attribute editors + else if (elementType == core::stringc(GUIEditElementTypeNames[EGUIEDIT_STRINGATTRIBUTE])) + ret = new CGUIStringAttribute(Environment, 0, -1); + else if (elementType == core::stringc(GUIEditElementTypeNames[EGUIEDIT_BOOLATTRIBUTE])) + ret = new CGUIBoolAttribute(Environment, 0, -1); + else if (elementType == core::stringc(GUIEditElementTypeNames[EGUIEDIT_ENUMATTRIBUTE])) + ret = new CGUIEnumAttribute(Environment, 0, -1); + else if (elementType == core::stringc(GUIEditElementTypeNames[EGUIEDIT_COLORATTRIBUTE])) + ret = new CGUIColorAttribute(Environment, 0, -1); + else if (elementType == core::stringc(GUIEditElementTypeNames[EGUIEDIT_COLORFATTRIBUTE])) + ret = new CGUIColorAttribute(Environment, 0, -1); + else if (elementType == core::stringc(GUIEditElementTypeNames[EGUIEDIT_TEXTUREATTRIBUTE])) + ret = new CGUITextureAttribute(Environment, 0, -1); + // stubs and custom editors + else if (elementType == core::stringc(GUIEditElementTypeNames[EGUIEDIT_CONTEXTMENUEDITOR]) || + elementType == core::stringc(GUIEditElementTypeNames[EGUIEDIT_MENUEDITOR]) || + elementType == core::stringc(GUIEditElementTypeNames[EGUIEDIT_FILEDIALOGEDITOR]) || + elementType == core::stringc(GUIEditElementTypeNames[EGUIEDIT_COLORDIALOGEDITOR]) || + elementType == core::stringc(GUIEditElementTypeNames[EGUIEDIT_MODALSCREENEDITOR]) ) + ret = new CGUIDummyEditorStub(Environment, 0, typeName); + + // add the element to its parent + if (ret) + parent->addChild(ret); + + // the environment now has the reference, so we can drop the element + if (ret) + ret->drop(); + + return ret; +} + + +//! returns amount of element types this factory is able to create +s32 CGUIEditFactory::getCreatableGUIElementTypeCount() const +{ + return EGUIEDIT_COUNT; +} + + +//! returns type name of a creatable element type +const c8* CGUIEditFactory::getCreateableGUIElementTypeName(s32 idx) const +{ + if (idx>=0 && idx rectangle, IGUIElement *parent) + : IGUIWindow(environment, parent, -1, rectangle), + Dragging(false), IsDraggable(true), Resizing(false), SelectedElement(0), + AttribEditor(0), OptionEditor(0), EnvEditor(0) +{ + #ifdef _DEBUG + setDebugName("CGUIEditWindow"); + #endif + + // we can't tab out of this window + setTabGroup(true); + // we can ctrl+tab to it + setTabStop(true); + // the tab order number is auto-assigned + setTabOrder(-1); + + // set window text + setText(L"GUI Editor"); + + // return if we have no skin. + IGUISkin *skin = environment->getSkin(); + if (!skin) + return; + + core::rect dlgRect(50,50,250,500); + setRelativePosition(dlgRect); + setMinSize(core::dimension2du(200,200)); + + s32 th = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH); + IGUITabControl *TabControl = environment->addTabControl(core::rect(1,th+5,dlgRect.getWidth()-1,dlgRect.getHeight()-1), this, false, true); + TabControl->setSubElement(true); + TabControl->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + + //TabControl->addTab(L"Tools"); + //L"Texture Cache Browser" + //L"Font Browser" + //L"Font Generator" + //L"Sprite Editor" + //Environment->addGUIElement("textureCacheBrowser", this); + + IGUITab* EditorTab = TabControl->addTab(L"Editor"); + OptionEditor = (CGUIAttributeEditor*) environment->addGUIElement("attributeEditor", EditorTab); + OptionEditor->grab(); + OptionEditor->setID(EGUIEDCE_OPTION_EDITOR); + OptionEditor->setRelativePositionProportional(core::rect(0.0f, 0.0f, 1.0f, 1.0f)); + OptionEditor->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + + if (Parent && Parent->getParent() == Environment->getRootGUIElement()) + { + IGUITab* EnvTab = TabControl->addTab(L"Env"); + EnvEditor = (CGUIAttributeEditor*) environment->addGUIElement("attributeEditor", EnvTab); + EnvEditor->grab(); + EnvEditor->setID(EGUIEDCE_ENV_EDITOR); + EnvEditor->setRelativePositionProportional(core::rect(0.0f, 0.0f, 1.0f, 1.0f)); + EnvEditor->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + } + IGUITab* ElementTab = TabControl->addTab(L"Element"); + + AttribEditor = (CGUIAttributeEditor*) environment->addGUIElement("attributeEditor", ElementTab); + AttribEditor->grab(); + AttribEditor->setID(EGUIEDCE_ATTRIB_EDITOR); + AttribEditor->setRelativePositionProportional(core::rect(0.0f, 0.0f, 1.0f, 1.0f)); + AttribEditor->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + + IGUITab* TreeTab = TabControl->addTab(L"Tree"); + TreeView = environment->addTreeView(core::rect(0,0,0,0), TreeTab); + TreeView->setRelativePositionProportional(core::rect(0.0f, 0.0f, 1.0f, 1.0f)); + TreeView->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + IGUITreeViewNode* treenode = TreeView->getRoot(); + //treenode->addChildFront(L"Elements"); + + ResizeButton = environment->addButton(core::rect(dlgRect.getWidth()-(th+1),dlgRect.getHeight()-(th+1),dlgRect.getWidth()-1,dlgRect.getHeight()-1), this); + ResizeButton->setDrawBorder(false); + ResizeButton->setEnabled(false); + ResizeButton->setSpriteBank(skin->getSpriteBank()); + ResizeButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_RESIZE), skin->getColor(EGDC_WINDOW_SYMBOL)); + ResizeButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_RESIZE), skin->getColor(EGDC_WINDOW_SYMBOL)); + ResizeButton->grab(); + ResizeButton->setSubElement(true); + ResizeButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT); + + updateTree(); +} + + +//! destructor +CGUIEditWindow::~CGUIEditWindow() +{ + // drop everything + if (AttribEditor) + AttribEditor->drop(); + if (EnvEditor) + EnvEditor->drop(); + if (OptionEditor) + OptionEditor->drop(); + if (ResizeButton) + ResizeButton->drop(); +} + +IGUITreeView* CGUIEditWindow::getTreeView() const +{ + return TreeView; +} +CGUIAttributeEditor* CGUIEditWindow::getEnvironmentEditor() const +{ + return EnvEditor; +} + +CGUIAttributeEditor* CGUIEditWindow::getAttributeEditor() const +{ + return AttribEditor; +} + +CGUIAttributeEditor* CGUIEditWindow::getOptionEditor() const +{ + return OptionEditor; +} + +IGUITreeViewNode* CGUIEditWindow::getTreeNode(IGUIElement* element, IGUITreeViewNode* searchnode) +{ + IGUITreeViewNode* child = searchnode->getFirstChild(); + while (child) + { + if (((IGUIElement*) child->getData()) == element) + return child; + + if (child->hasChildren()) + { + IGUITreeViewNode* foundnode = getTreeNode(element, child); + if (foundnode) + return foundnode; + } + child = child->getNextSibling(); + } + return 0; +} + +void CGUIEditWindow::addChildrenToTree(IGUIElement* parentElement, IGUITreeViewNode* treenode) +{ + core::stringw name = core::stringw(parentElement->getTypeName()); + if (parentElement->getID() != -1) + name += core::stringw(L" [") + core::stringw(parentElement->getID()) + core::stringw(L"]"); + + IGUITreeViewNode* newnode = treenode->addChildBack(name.c_str()); + newnode->setData((void*)parentElement); + core::list children = parentElement->getChildren(); + + for (core::list::Iterator i = children.begin(); i != children.end(); i++ ) + { + if(core::stringc((*i)->getTypeName()) != "GUIEditor" && !(*i)->isSubElement()) + addChildrenToTree(*i, newnode); + } +} + +void CGUIEditWindow::updateTree() +{ + TreeView->getRoot()->clearChildren(); + IGUIElement* root = Environment->getRootGUIElement(); + addChildrenToTree(root, TreeView->getRoot()); + TreeView->getRoot()->getFirstChild()->setExpanded(true); +} + +void CGUIEditWindow::setSelectedElement(IGUIElement *sel) +{ + // save changes + AttribEditor->updateAttribs(); + IGUITreeViewNode* elementTreeNode = getTreeNode(sel, TreeView->getRoot()); + + if (elementTreeNode) + { + elementTreeNode->setSelected(true); + while (elementTreeNode) + { + elementTreeNode->setExpanded(true); + elementTreeNode = elementTreeNode->getParent(); + } + } + + io::IAttributes* Attribs = AttribEditor->getAttribs(); + + if (SelectedElement && sel != SelectedElement) + { + // deserialize attributes + SelectedElement->deserializeAttributes(Attribs); + } + // clear the attributes list + Attribs->clear(); + SelectedElement = sel; + + // get the new attributes + if (SelectedElement) + SelectedElement->serializeAttributes(Attribs); + + AttribEditor->refreshAttribs(); +} + +//! draws the element and its children. +//! same code as for a window +void CGUIEditWindow::draw() +{ + if (!IsVisible) + return; + + IGUISkin* skin = Environment->getSkin(); + + core::rect rect = AbsoluteRect; + + // draw body fast + rect = skin->draw3DWindowBackground(this, true, skin->getColor(EGDC_ACTIVE_BORDER), + AbsoluteRect, &AbsoluteClippingRect); + + if (Text.size()) + { + rect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X); + rect.UpperLeftCorner.Y += skin->getSize(EGDS_TEXT_DISTANCE_Y); + rect.LowerRightCorner.X -= skin->getSize(EGDS_WINDOW_BUTTON_WIDTH) + 5; + + IGUIFont* font = skin->getFont(); + if (font) + font->draw(Text.c_str(), rect, skin->getColor(EGDC_ACTIVE_CAPTION), false, true, &AbsoluteClippingRect); + } + + IGUIElement::draw(); +} + + +//! called if an event happened. +bool CGUIEditWindow::OnEvent(const SEvent &event) +{ + switch(event.EventType) + { + case EET_GUI_EVENT: + switch(event.GUIEvent.EventType) + { + case EGET_ELEMENT_FOCUS_LOST: + if (event.GUIEvent.Caller == this || + event.GUIEvent.Caller == ResizeButton) + { + Dragging = false; + Resizing = false; + } + break; + default: + break; + } + + break; + case EET_MOUSE_INPUT_EVENT: + switch(event.MouseInput.Event) + { + case EMIE_LMOUSE_PRESSED_DOWN: + { + DragStart.X = event.MouseInput.X; + DragStart.Y = event.MouseInput.Y; + + IGUIElement* clickedElement = getElementFromPoint(DragStart); + + if (clickedElement == this) + { + Dragging = IsDraggable; + //Environment->setFocus(this); + if (Parent) + Parent->bringToFront(this); + return true; + } + else if (clickedElement == ResizeButton) + { + Resizing = true; + //Environment->setFocus(this); + if (Parent) + Parent->bringToFront(this); + return true; + } + break; + } + case EMIE_LMOUSE_LEFT_UP: + if (Dragging || Resizing) + { + Dragging = false; + Resizing = false; + return true; + } + break; + case EMIE_MOUSE_MOVED: + if (Dragging || Resizing) + { + // gui window should not be dragged outside of its parent + if (Parent) + if (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; + core::position2di diff(event.MouseInput.X - DragStart.X, event.MouseInput.Y - DragStart.Y); + if (Dragging) + { + move(diff); + DragStart.X = event.MouseInput.X; + DragStart.Y = event.MouseInput.Y; + } + else if (Resizing) + { + core::position2di dp = RelativeRect.LowerRightCorner + diff; + setRelativePosition(core::rect(RelativeRect.UpperLeftCorner, dp)); + DragStart += dp - RelativeRect.LowerRightCorner + diff; + } + + return true; + } + break; + default: + break; + } + default: + break; + } + + return Parent ? Parent->OnEvent(event) : false; +} + +bool CGUIEditWindow::isDraggable() const +{ + return IsDraggable; +} + +void CGUIEditWindow::setDraggable(bool draggable) +{ + IsDraggable = draggable; + + if (Dragging && !IsDraggable) + Dragging = false; +} + + +// we're supposed to supply these if we're creating an IGUIWindow +// but we don't need them so we'll just return null + +//! Returns the rectangle of the drawable area (without border, without titlebar and without scrollbars) +core::rect CGUIEditWindow::getClientRect() const {return core::recti();} +IGUIButton* CGUIEditWindow::getCloseButton() const {return 0;} +IGUIButton* CGUIEditWindow::getMinimizeButton() const {return 0;} +IGUIButton* CGUIEditWindow::getMaximizeButton() const {return 0;} diff --git a/tools/GUIEditor/CGUIEditWindow.h b/tools/GUIEditor/CGUIEditWindow.h new file mode 100644 index 00000000..4b1d72f5 --- /dev/null +++ b/tools/GUIEditor/CGUIEditWindow.h @@ -0,0 +1,88 @@ +#ifndef __C_GUI_EDITOR_H_INCLUDED__ +#define __C_GUI_EDITOR_H_INCLUDED__ + + +#include "IGUIWindow.h" +#include "CGUIAttributeEditor.h" +//#include "IGUIStaticText.h" +#include "IGUIButton.h" +#include "IGUITreeView.h" +#include "irrArray.h" +#include "IAttributes.h" +#include "EGUIEditTypes.h" + +namespace irr +{ +namespace gui +{ + class CGUIEditWindow : public IGUIWindow + { + public: + + //! constructor + CGUIEditWindow(IGUIEnvironment* environment, core::rect rectangle, IGUIElement *parent); + + //! destructor + ~CGUIEditWindow(); + + //! this part draws the window + virtual void draw(); + //! handles events + virtual bool OnEvent(const SEvent &event); + + //! change selection + virtual void setSelectedElement(IGUIElement *sel); + + //! get draggable + virtual bool isDraggable() const; + + //! get draggable + virtual void setDraggable(bool draggable); + + // not used + virtual core::rect getClientRect() const; + virtual IGUIButton* getCloseButton() const; + virtual IGUIButton* getMinimizeButton() const; + virtual IGUIButton* getMaximizeButton() const; + virtual void setDrawBackground(bool draw) { } + virtual bool getDrawBackground() const { return true; } + virtual void setDrawTitlebar(bool draw) { } + virtual bool getDrawTitlebar() const { return true; } + + IGUITreeView* getTreeView() const; + CGUIAttributeEditor* getAttributeEditor() const; + CGUIAttributeEditor* getOptionEditor() const; + CGUIAttributeEditor* getEnvironmentEditor() const; + + //! Returns the type name of the gui element. + virtual const c8* getTypeName() const + { + return GUIEditElementTypeNames[EGUIEDIT_GUIEDITWINDOW]; + } + + void updateTree(); + private: + + void addChildrenToTree(IGUIElement* parentElement, IGUITreeViewNode* treenode); + IGUITreeViewNode* getTreeNode(IGUIElement* element, IGUITreeViewNode* searchnode); + // for dragging the window + bool Dragging; + bool IsDraggable; + bool Resizing; + core::position2d DragStart; + + IGUIElement* SelectedElement; // current selected element + + CGUIAttributeEditor* AttribEditor; // edits the current attribute + CGUIAttributeEditor* OptionEditor; // edits the options for the window + CGUIAttributeEditor* EnvEditor; // edits attributes for the environment + IGUITreeView* TreeView; // tree view of all elements in scene + IGUIButton* ResizeButton; + + }; + +} // end namespace gui +} // end namespace irr + +#endif // __C_GUI_EDITOR_H_INCLUDED__ + diff --git a/tools/GUIEditor/CGUIEditWorkspace.cpp b/tools/GUIEditor/CGUIEditWorkspace.cpp new file mode 100644 index 00000000..3934c027 --- /dev/null +++ b/tools/GUIEditor/CGUIEditWorkspace.cpp @@ -0,0 +1,940 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Gaz Davidson +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +// Thanks to Midnight for all his testing, bug fixes and patches :) + +#include "CGUIEditWorkspace.h" +#include "IGUIEnvironment.h" +#include "IVideoDriver.h" +#include "IOSOperator.h" +#include "IReadFile.h" +#include "IFileSystem.h" +#include "IXMLWriter.h" +#include "IGUISkin.h" +#include "IGUIElementFactory.h" +#include "CGUIEditWindow.h" +#include "IGUIContextMenu.h" +#include "IGUIFileOpenDialog.h" +#include "IGUITreeView.h" +#include "CGUIAttribute.h" +#include "CMemoryReadWriteFile.h" + +namespace irr +{ +namespace gui +{ + +//! constructor +CGUIEditWorkspace::CGUIEditWorkspace(IGUIEnvironment* environment, s32 id, IGUIElement *parent) +: IGUIElement(EGUIET_ELEMENT, environment, parent ? parent : environment->getRootGUIElement(), id, environment->getRootGUIElement()->getAbsolutePosition()), + CurrentMode(EGUIEDM_SELECT), MouseOverMode(EGUIEDM_SELECT), + GridSize(10,10), MenuCommandStart(0x3D17), DrawGrid(false), UseGrid(true), + MouseOverElement(0), SelectedElement(0), EditorWindow(0) +{ + #ifdef _DEBUG + setDebugName("CGUIEditWorkspace"); + #endif + + // this element is never saved. + setSubElement(true); + + // it resizes to fit a resizing window + setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + + // Types which we currently can't handle in editor + // Most of them also just don't make sense in here (like Dialogs) + // TODO: We should have a way to create context-menus + UnusableElementTypeFilter.push_back(EGUIET_CONTEXT_MENU); + UnusableElementTypeFilter.push_back(EGUIET_FILE_OPEN_DIALOG); + UnusableElementTypeFilter.push_back(EGUIET_COLOR_SELECT_DIALOG); + UnusableElementTypeFilter.push_back(EGUIET_MESSAGE_BOX); + UnusableElementTypeFilter.push_back(EGUIET_MODAL_SCREEN); + UnusableElementTypeFilter.push_back(EGUIET_ELEMENT); // wouldn't do anything, so don't show in menu + UnusableElementTypeFilter.push_back(EGUIET_ROOT); // wouldn't do anything, so don't show in menu + + EditorWindow = (CGUIEditWindow*) Environment->addGUIElement("GUIEditWindow", this); + if (EditorWindow) + { + EditorWindow->grab(); + EditorWindow->setSubElement(true); + + Environment->setFocus(EditorWindow); + serializeAttributes(EditorWindow->getOptionEditor()->getAttribs()); + EditorWindow->getOptionEditor()->refreshAttribs(); + + if (EditorWindow->getEnvironmentEditor()) + { + Environment->serializeAttributes(EditorWindow->getEnvironmentEditor()->getAttribs()); + EditorWindow->getEnvironmentEditor()->refreshAttribs(); + } + } +} + + +//! destructor +CGUIEditWorkspace::~CGUIEditWorkspace() +{ + if (EditorWindow) + EditorWindow->drop(); +} + + +void CGUIEditWorkspace::setMenuCommandIDStart(s32 id) +{ + MenuCommandStart = id; +} + +CGUIEditWorkspace::EGUIEDIT_MODE CGUIEditWorkspace::getModeFromPos(core::position2di p) +{ + if (SelectedElement) + { + core::rect r = SelectedElement->getAbsolutePosition(); + + if (TLRect.isPointInside(p)) + return EGUIEDM_RESIZE_TL; + + else if (TRRect.isPointInside(p)) + return EGUIEDM_RESIZE_TR; + + else if (BLRect.isPointInside(p) ) + return EGUIEDM_RESIZE_BL; + + else if (BRRect.isPointInside(p)) + return EGUIEDM_RESIZE_BR; + + else if (TopRect.isPointInside(p)) + return EGUIEDM_RESIZE_T; + + else if (BRect.isPointInside(p)) + return EGUIEDM_RESIZE_B; + + else if (LRect.isPointInside(p)) + return EGUIEDM_RESIZE_L; + + else if (RRect.isPointInside(p)) + return EGUIEDM_RESIZE_R; + + else if (getEditableElementFromPoint(SelectedElement, p) == SelectedElement) + return EGUIEDM_MOVE; + + else + return EGUIEDM_SELECT; + } + + return EGUIEDM_SELECT; + +} + +IGUIElement* CGUIEditWorkspace::getEditableElementFromPoint(IGUIElement *start, const core::position2di &point, s32 index ) +{ + IGUIElement* target = 0; + + // we have to search from back to front. + + core::list::ConstIterator it = start->getChildren().getLast(); + s32 count=0; + while(it != start->getChildren().end()) + { + target = getEditableElementFromPoint((*it),point); + if (target) + { + if (!target->isSubElement() && !isMyChild(target) && target != this) + { + if (index == count) + return target; + else + count++; + } + else + target = 0; + } + --it; + } + + if (start->getAbsolutePosition().isPointInside(point)) + target = start; + + return target; +} + +void CGUIEditWorkspace::setSelectedElement(IGUIElement *sel) +{ + IGUIElement* focus = Environment->getFocus(); + // we only give focus back to children + if (!isMyChild(focus)) + focus = 0; + + if (SelectedElement != Parent) + { + if (SelectedElement != sel && EditorWindow) + { + EditorWindow->setSelectedElement(sel); + SelectedElement = sel; + } + } + else + SelectedElement = 0; + + if (focus) + Environment->setFocus(focus); + else + Environment->setFocus(this); +} + +IGUIElement* CGUIEditWorkspace::getSelectedElement() +{ + return SelectedElement; +} +void CGUIEditWorkspace::selectNextSibling() +{ + IGUIElement* p=0; + + if (SelectedElement && SelectedElement->getParent()) + p = SelectedElement->getParent(); + else + p = Parent; + + core::list::ConstIterator it = p->getChildren().begin(); + // find selected element + if (SelectedElement) + while (*it != SelectedElement) + ++it; + if (it !=p->getChildren().end()) + ++it; + // find next non sub-element + while (it != p->getChildren().end() && (*it)->isSubElement()) + ++it; + + if (it != p->getChildren().end()) + setSelectedElement(*it); +} +void CGUIEditWorkspace::selectPreviousSibling() +{ + IGUIElement* p=0; + + if (SelectedElement && SelectedElement->getParent()) + p = SelectedElement->getParent(); + else + p = Parent; + + core::list::ConstIterator it = p->getChildren().getLast(); + // find selected element + if (SelectedElement) + while (*it != SelectedElement) + --it; + if (it != p->getChildren().end()) + --it; + // find next non sub-element + while (it != p->getChildren().end() && (*it)->isSubElement()) + --it; + + if (it != p->getChildren().end()) + setSelectedElement(*it); +} + +//! called if an event happened. +bool CGUIEditWorkspace::OnEvent(const SEvent &e) +{ + IGUIFileOpenDialog* dialog=0; + switch(e.EventType) + { + case ATTRIBEDIT_ATTRIB_CHANGED: + { + switch (e.UserEvent.UserData1) + { + case EGUIEDCE_ATTRIB_EDITOR: + { + // update selected items attributes + if (SelectedElement) + { + SelectedElement->deserializeAttributes(EditorWindow->getAttributeEditor()->getAttribs()); + EditorWindow->updateTree(); + } + return true; + } + case EGUIEDCE_OPTION_EDITOR: + { + // update editor options + deserializeAttributes(EditorWindow->getOptionEditor()->getAttribs()); + return true; + } + case EGUIEDCE_ENV_EDITOR: + { + // update environment + Environment->deserializeAttributes(EditorWindow->getEnvironmentEditor()->getAttribs()); + return true; + } + } + } + break; + + case EET_KEY_INPUT_EVENT: + if (!e.KeyInput.PressedDown) + { + switch (e.KeyInput.Key) + { + case KEY_DELETE: + if (SelectedElement) + { + IGUIElement* el = SelectedElement; + setSelectedElement(0); + MouseOverElement = 0; + el->remove(); + EditorWindow->updateTree(); + } + break; + case KEY_KEY_X: + if (e.KeyInput.Control && SelectedElement) + { + // cut + CopySelectedElementXML(); + // delete element + IGUIElement *el = SelectedElement; + setSelectedElement(0); + MouseOverElement = 0; + el->remove(); + } + break; + case KEY_KEY_C: + // copy + if (e.KeyInput.Control && SelectedElement) + { + CopySelectedElementXML(); + } + break; + case KEY_KEY_V: + // paste + if (e.KeyInput.Control) + { + PasteXMLToSelectedElement(); + } + break; + default: + break; + } + + return true; + } + break; + + case EET_MOUSE_INPUT_EVENT: + + switch(e.MouseInput.Event) + { + case EMIE_MOUSE_WHEEL: + { + f32 wheel = e.MouseInput.Wheel; + + if (wheel > 0) + selectPreviousSibling(); + else + selectNextSibling(); + } + break; + case EMIE_LMOUSE_PRESSED_DOWN: + { + core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y); + + IGUIElement* newSelection = getElementFromPoint(p); + + if (newSelection != this && isMyChild(newSelection) ) // redirect event + { + Environment->setFocus(newSelection); + return true; + } + + // hide the gui editor + if (EditorWindow) + EditorWindow->setVisible(false); + + if (CurrentMode == EGUIEDM_SELECT) + { + if (SelectedElement) + { + // start moving or dragging + CurrentMode = getModeFromPos(p); + + if (CurrentMode == EGUIEDM_MOVE) + StartMovePos = SelectedElement->getAbsolutePosition().UpperLeftCorner; + + DragStart = p; + SelectedArea = SelectedElement->getAbsolutePosition(); + } + + if (CurrentMode < EGUIEDM_MOVE) + { + // selecting an element... + MouseOverElement = getEditableElementFromPoint(Parent, p); + + if (MouseOverElement == Parent) + MouseOverElement = 0; + + setSelectedElement(MouseOverElement); + } + } + + break; + } + case EMIE_RMOUSE_PRESSED_DOWN: + if (CurrentMode == EGUIEDM_SELECT_NEW_PARENT || CurrentMode >= EGUIEDM_MOVE) + { + // cancel dragging + CurrentMode = EGUIEDM_SELECT; + } + else + { + DragStart = core::position2di(e.MouseInput.X,e.MouseInput.Y); + // root menu + IGUIContextMenu* mnu = Environment->addContextMenu( + core::rect(e.MouseInput.X, e.MouseInput.Y, e.MouseInput.Y+100, e.MouseInput.Y+100),this); + mnu->addItem(L"File",-1,true,true); + mnu->addItem(L"Edit",-1,true,true); + mnu->addItem(L"View",-1,true,true); + mnu->addItem(SelectedElement ? L"Add child" : L"Add" ,-1,true,true); + + // file menu + IGUIContextMenu* sub = mnu->getSubMenu(0); + IGUIContextMenu* sub2 =0; + + sub->addItem(L"New", MenuCommandStart + EGUIEDMC_FILE_NEW ); + sub->addItem(L"Load...",MenuCommandStart + EGUIEDMC_FILE_LOAD); + sub->addItem(L"Save...",MenuCommandStart + EGUIEDMC_FILE_SAVE); + + // edit menu + sub = mnu->getSubMenu(1); + sub->addItem(L"Cut (ctrl+x)", MenuCommandStart + EGUIEDMC_CUT_ELEMENT, (SelectedElement != 0)); + sub->addItem(L"Copy (ctrl+c)", MenuCommandStart + EGUIEDMC_COPY_ELEMENT, (SelectedElement != 0)); + sub->addItem(L"Paste (ctrl+v)", MenuCommandStart + EGUIEDMC_PASTE_ELEMENT, + (core::stringc(Environment->getOSOperator()->getTextFromClipboard()) != "")); + sub->addItem(L"Delete (del)", MenuCommandStart + EGUIEDMC_DELETE_ELEMENT, (SelectedElement != 0)); + sub->addSeparator(); + sub->addItem(L"Set parent", MenuCommandStart + EGUIEDMC_SET_PARENT, (SelectedElement != 0)); + sub->addItem(L"Bring to front", MenuCommandStart + EGUIEDMC_BRING_TO_FRONT, (SelectedElement != 0)); + sub->addSeparator(); + sub->addItem(L"Save to XML...", MenuCommandStart + EGUIEDMC_SAVE_ELEMENT, (SelectedElement != 0)); + + sub = mnu->getSubMenu(2); + // view menu + if (EditorWindow) + sub->addItem(EditorWindow->isVisible() ? L"Hide window" : L"Show window", MenuCommandStart + EGUIEDMC_TOGGLE_EDITOR); + + sub = mnu->getSubMenu(3); + + s32 i,j,c=0; + sub->addItem(L"Default factory",-1,true, true); + + // add elements from each factory + for (i=0; u32(i) < Environment->getRegisteredGUIElementFactoryCount(); ++i) + { + sub2 = sub->getSubMenu(i); + + IGUIElementFactory *f = Environment->getGUIElementFactory(i); + + for (j=0; j< f->getCreatableGUIElementTypeCount(); ++j) + { + EGUI_ELEMENT_TYPE type = f->getCreateableGUIElementType(j); + if ( UnusableElementTypeFilter.linear_search(type) < 0 ) + sub2->addItem(core::stringw(f->getCreateableGUIElementTypeName(j)).c_str(), MenuCommandStart + EGUIEDMC_COUNT + c); + c++; + } + + if (u32(i+1) < Environment->getRegisteredGUIElementFactoryCount()) + { + core::stringw strFact; + strFact = L"Factory "; + strFact += i+1; + sub->addItem(strFact.c_str(),-1, true, true); + } + } + sub->addSeparator(); + sub->addItem(L"From XML...", MenuCommandStart + EGUIEDMC_INSERT_XML); + + // set focus to menu + Environment->setFocus(mnu); + + } + break; + case EMIE_LMOUSE_LEFT_UP: + + // make window visible again + if (EditorWindow) + EditorWindow->setVisible(true); + if (CurrentMode == EGUIEDM_SELECT_NEW_PARENT) + { + if (SelectedElement) + { + MouseOverElement = getEditableElementFromPoint(Parent, + core::position2di(e.MouseInput.X,e.MouseInput.Y)); + if (MouseOverElement) + { + MouseOverElement->addChild(SelectedElement); + setSelectedElement(0); + setSelectedElement(SelectedElement); + } + } + CurrentMode = EGUIEDM_SELECT; + } + else if (CurrentMode >= EGUIEDM_MOVE) + { + IGUIElement *sel = SelectedElement; + // unselect + setSelectedElement(0); + + // move + core::position2d p(0,0); + if (sel->getParent()) + p = sel->getParent()->getAbsolutePosition().UpperLeftCorner; + + sel->setRelativePosition(SelectedArea - p); + + // select + setSelectedElement(sel); + + // reset selection mode... + CurrentMode = EGUIEDM_SELECT; + } + break; + case EMIE_MOUSE_MOVED: + // always on top + Parent->bringToFront(this); + + // if selecting + if (CurrentMode == EGUIEDM_SELECT || CurrentMode == EGUIEDM_SELECT_NEW_PARENT) + { + + core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y); + + // highlight the element that the mouse is over + MouseOverElement = getEditableElementFromPoint(Parent, p); + if (MouseOverElement == Parent) + { + MouseOverElement = 0; + } + + if (CurrentMode == EGUIEDM_SELECT) + { + MouseOverMode = getModeFromPos(p); + if (MouseOverMode > EGUIEDM_MOVE) + { + MouseOverElement = SelectedElement; + } + } + } + else if (CurrentMode == EGUIEDM_MOVE) + { + // get difference + core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y); + p -= DragStart; + + // apply to top corner + p = StartMovePos + p; + if (UseGrid) + { + p.X = (p.X/GridSize.Width)*GridSize.Width; + p.Y = (p.Y/GridSize.Height)*GridSize.Height; + } + + SelectedArea += p - SelectedArea.UpperLeftCorner; + } + else if (CurrentMode > EGUIEDM_MOVE) + { + // get difference from start position + core::position2di p = core::position2di(e.MouseInput.X,e.MouseInput.Y); + if (UseGrid) + { + p.X = (p.X/GridSize.Width)*GridSize.Width; + p.Y = (p.Y/GridSize.Height)*GridSize.Height; + } + + switch(CurrentMode) + { + case EGUIEDM_RESIZE_T: + SelectedArea.UpperLeftCorner.Y = p.Y; + break; + case EGUIEDM_RESIZE_B: + SelectedArea.LowerRightCorner.Y = p.Y; + break; + case EGUIEDM_RESIZE_L: + SelectedArea.UpperLeftCorner.X = p.X; + break; + case EGUIEDM_RESIZE_R: + SelectedArea.LowerRightCorner.X = p.X; + break; + case EGUIEDM_RESIZE_TL: + SelectedArea.UpperLeftCorner = p; + break; + case EGUIEDM_RESIZE_TR: + SelectedArea.UpperLeftCorner.Y = p.Y; + SelectedArea.LowerRightCorner.X = p.X; + break; + case EGUIEDM_RESIZE_BL: + SelectedArea.UpperLeftCorner.X = p.X; + SelectedArea.LowerRightCorner.Y = p.Y; + break; + case EGUIEDM_RESIZE_BR: + SelectedArea.LowerRightCorner = p; + break; + default: + break; + } + } + + break; + default: + break; + } + break; + + case EET_GUI_EVENT: + switch(e.GUIEvent.EventType) + { + case EGET_TREEVIEW_NODE_SELECT: + { + IGUITreeViewNode* eventnode = ((IGUITreeView*)e.GUIEvent.Caller)->getLastEventNode(); + if(!eventnode->isRoot()) + setSelectedElement((IGUIElement*)(eventnode->getData())); + break; + } + // load a gui file + case EGET_FILE_SELECTED: + dialog = (IGUIFileOpenDialog*)e.GUIEvent.Caller; + Environment->loadGUI(core::stringc(dialog->getFileName()).c_str()); + break; + + case EGET_MENU_ITEM_SELECTED: + { + IGUIContextMenu *menu = (IGUIContextMenu*)e.GUIEvent.Caller; + s32 cmdID = menu->getItemCommandId(menu->getSelectedItem()) - MenuCommandStart; + + IGUIElement* el; + + switch(cmdID) + { + + //! file commands + case EGUIEDMC_FILE_NEW: + // clear all elements belonging to our parent + setSelectedElement(0); + MouseOverElement = 0; + el = Parent; + grab(); + // remove all children + while(Children.end() != el->getChildren().begin()) + el->removeChild(*(el->getChildren().begin())); + // attach to parent again + el->addChild(this); + drop(); + + break; + case EGUIEDMC_FILE_LOAD: + Environment->addFileOpenDialog(L"Please select a GUI file to open", false, this); + break; + case EGUIEDMC_FILE_SAVE: + Environment->saveGUI("guiTest.xml"); + break; + + //! edit menu + case EGUIEDMC_CUT_ELEMENT: + { + CopySelectedElementXML(); + // delete element + el = SelectedElement; + setSelectedElement(0); + MouseOverElement = 0; + el->remove(); + break; + } + case EGUIEDMC_COPY_ELEMENT: + CopySelectedElementXML(); + break; + case EGUIEDMC_PASTE_ELEMENT: + PasteXMLToSelectedElement(); + break; + case EGUIEDMC_DELETE_ELEMENT: + el = SelectedElement; + setSelectedElement(0); + MouseOverElement = 0; + el->remove(); + break; + case EGUIEDMC_SET_PARENT: + CurrentMode = EGUIEDM_SELECT_NEW_PARENT; + break; + case EGUIEDMC_BRING_TO_FRONT: + if (SelectedElement->getParent()) + SelectedElement->getParent()->bringToFront(SelectedElement); + break; + + case EGUIEDMC_SAVE_ELEMENT: + //TODO: add 'save' dialog. + Environment->saveGUI("guiTest.xml", SelectedElement ? SelectedElement : Environment->getRootGUIElement() ); + break; + + //! toggle edit window + case EGUIEDMC_TOGGLE_EDITOR: + break; + + case EGUIEDMC_INSERT_XML: + Environment->loadGUI("guiTest.xml", SelectedElement ? SelectedElement : Environment->getRootGUIElement() ); + break; + + default: + // create element from factory? + if (cmdID >= EGUIEDMC_COUNT) + { + + s32 num = cmdID - EGUIEDMC_COUNT; // get index + // loop through all factories + s32 i, c=Environment->getRegisteredGUIElementFactoryCount(); + for (i=0; i Environment->getGUIElementFactory(i)->getCreatableGUIElementTypeCount(); ++i) + { + num -= Environment->getGUIElementFactory(i)->getCreatableGUIElementTypeCount(); + } + if (num < Environment->getGUIElementFactory(i)->getCreatableGUIElementTypeCount() ) + { + core::stringc name = Environment->getGUIElementFactory(i)->getCreateableGUIElementTypeName(num); + IGUIElement *parentElement = SelectedElement ? SelectedElement : Environment->getRootGUIElement(); + // add it + IGUIElement *newElement = Environment->getGUIElementFactory(i)->addGUIElement(name.c_str(),parentElement); + if (newElement) + { + core::position2di p = DragStart - parentElement->getAbsolutePosition().UpperLeftCorner; + newElement->setRelativePosition(core::rect(p,p+core::position2di(100,100))); + //Environment->removeFocus(newElement); + } + } + } + break; + } + EditorWindow->updateTree(); + } + return true; + default: + break; + } + break; + + default: + break; + } + + // even if we didn't absorb the event, + // we never pass events back to the GUI we're editing! + return false; +} + + +//! draws the element and its children +void CGUIEditWorkspace::draw() +{ + video::IVideoDriver *driver = Environment->getVideoDriver(); + + if (DrawGrid) + { + // draw the grid + + core::rect r = getAbsolutePosition(); + + s32 cy = r.UpperLeftCorner.Y; + while (cy < r.LowerRightCorner.Y) + { + s32 cx = r.UpperLeftCorner.X; + while (cx < r.LowerRightCorner.X) + { + driver->draw2DRectangle(video::SColor(40,0,0,90),core::rect(cx+1,cy+1,GridSize.Width+cx,GridSize.Height+cy)); + cx += GridSize.Width; + } + cy += GridSize.Height; + } + } + if (MouseOverElement && + MouseOverElement != SelectedElement && + MouseOverElement != Parent) + { + core::rect r = MouseOverElement->getAbsolutePosition(); + driver->draw2DRectangle(video::SColor(100,0,0,255), r); + } + if (SelectedElement && CurrentMode == EGUIEDM_SELECT) + { + driver->draw2DRectangle(video::SColor(100,0,255,0),SelectedElement->getAbsolutePosition()); + } + if (CurrentMode >= EGUIEDM_MOVE) + { + driver->draw2DRectangle(video::SColor(100,255,0,0),SelectedArea); + } + + if ( (SelectedElement && CurrentMode >= EGUIEDM_MOVE) || + (SelectedElement && MouseOverElement == SelectedElement && MouseOverMode >= EGUIEDM_MOVE) ) + { + // draw handles for moving + EGUIEDIT_MODE m = CurrentMode; + core::rect r = SelectedArea; + if (m < EGUIEDM_MOVE) + { + m = MouseOverMode; + r = SelectedElement->getAbsolutePosition(); + } + + core::position2di d = core::position2di(4,4); + + TLRect = core::rect(r.UpperLeftCorner, r.UpperLeftCorner + d ); + TRRect = core::rect(r.LowerRightCorner.X-4, r.UpperLeftCorner.Y, r.LowerRightCorner.X, r.UpperLeftCorner.Y+4); + TopRect = core::rect(r.getCenter().X-2, r.UpperLeftCorner.Y,r.getCenter().X+2, r.UpperLeftCorner.Y+4 ); + BLRect = core::rect(r.UpperLeftCorner.X, r.LowerRightCorner.Y-4, r.UpperLeftCorner.X+4, r.LowerRightCorner.Y); + LRect = core::rect(r.UpperLeftCorner.X,r.getCenter().Y-2, r.UpperLeftCorner.X+4, r.getCenter().Y+2 ); + RRect = core::rect(r.LowerRightCorner.X-4,r.getCenter().Y-2, r.LowerRightCorner.X, r.getCenter().Y+2 ); + BRRect = core::rect(r.LowerRightCorner-d, r.LowerRightCorner); + BRect = core::rect(r.getCenter().X-2, r.LowerRightCorner.Y-4,r.getCenter().X+2, r.LowerRightCorner.Y ); + + // top left + if (m == EGUIEDM_RESIZE_T || m == EGUIEDM_RESIZE_L || m == EGUIEDM_RESIZE_TL || m == EGUIEDM_MOVE ) + driver->draw2DRectangle(video::SColor(100,255,255,255), TLRect); + + if (m == EGUIEDM_RESIZE_T || m == EGUIEDM_RESIZE_R || m == EGUIEDM_RESIZE_TR || m == EGUIEDM_MOVE ) + driver->draw2DRectangle(video::SColor(100,255,255,255), TRRect); + + if (m == EGUIEDM_RESIZE_T || m == EGUIEDM_MOVE ) + driver->draw2DRectangle(video::SColor(100,255,255,255), TopRect); + + if (m == EGUIEDM_RESIZE_L || m == EGUIEDM_RESIZE_BL || m == EGUIEDM_RESIZE_B || m == EGUIEDM_MOVE ) + driver->draw2DRectangle(video::SColor(100,255,255,255), BLRect); + + if (m == EGUIEDM_RESIZE_L || m == EGUIEDM_MOVE ) + driver->draw2DRectangle(video::SColor(100,255,255,255), LRect); + + if (m == EGUIEDM_RESIZE_R || m == EGUIEDM_MOVE ) + driver->draw2DRectangle(video::SColor(100,255,255,255), RRect); + + if (m == EGUIEDM_RESIZE_R || m == EGUIEDM_RESIZE_BR || m == EGUIEDM_RESIZE_B || m == EGUIEDM_MOVE ) + driver->draw2DRectangle(video::SColor(100,255,255,255), BRRect ); + + if (m == EGUIEDM_RESIZE_B || m == EGUIEDM_MOVE ) + driver->draw2DRectangle(video::SColor(100,255,255,255), BRect); + + + } + + IGUIElement::draw(); +} + + +void CGUIEditWorkspace::setDrawGrid(bool drawGrid) +{ + DrawGrid = drawGrid; +} + +void CGUIEditWorkspace::setGridSize(const core::dimension2di& gridSize) +{ + GridSize = gridSize; + if (GridSize.Width < 2) + GridSize.Width = 2; + if (GridSize.Height < 2) + GridSize.Height = 2; +} + +void CGUIEditWorkspace::setUseGrid(bool useGrid) +{ + UseGrid = useGrid; +} + + +//! Removes a child. +void CGUIEditWorkspace::removeChild(IGUIElement* child) +{ + IGUIElement::removeChild(child); + + if (Children.empty()) + remove(); +} + + +void CGUIEditWorkspace::updateAbsolutePosition() +{ + core::rect parentRect(0,0,0,0); + + if (Parent) + { + parentRect = Parent->getAbsolutePosition(); + RelativeRect.UpperLeftCorner.X = 0; + RelativeRect.UpperLeftCorner.Y = 0; + RelativeRect.LowerRightCorner.X = parentRect.getWidth(); + RelativeRect.LowerRightCorner.Y = parentRect.getHeight(); + } + + IGUIElement::updateAbsolutePosition(); +} + +void CGUIEditWorkspace::CopySelectedElementXML() +{ + core::stringc XMLText; + core::stringw wXMLText; + // create memory write file + io::CMemoryReadWriteFile* memWrite = new io::CMemoryReadWriteFile("#Clipboard#"); + // save gui to mem file + io::IXMLWriter* xml = Environment->getFileSystem()->createXMLWriter(memWrite); + Environment->writeGUIElement(xml, SelectedElement); + + // copy to clipboard- wide chars not supported yet :( + wXMLText = (wchar_t*)&memWrite->getData()[0]; + u32 i = memWrite->getData().size()/sizeof(wchar_t); + if (wXMLText.size() > i) + wXMLText[i] = L'\0'; + XMLText = wXMLText.c_str(); + memWrite->drop(); + xml->drop(); + Environment->getOSOperator()->copyToClipboard(XMLText.c_str()); +} + +void CGUIEditWorkspace::PasteXMLToSelectedElement() +{ + // get clipboard data + const char * p = Environment->getOSOperator()->getTextFromClipboard(); + irr::core::stringw wXMLText; + core::multibyteToWString(wXMLText, p); + + io::CMemoryReadWriteFile* memWrite = new io::CMemoryReadWriteFile("#Clipboard#"); + + io::IXMLWriter* xmlw = Environment->getFileSystem()->createXMLWriter(memWrite); + xmlw->writeXMLHeader(); // it needs one of those + xmlw->drop(); + + // write clipboard data + memWrite->write((void*)&wXMLText[0], wXMLText.size() * sizeof(wchar_t)); + + // rewind file + memWrite->seek(0, false); + + // read xml + Environment->loadGUI(memWrite, SelectedElement); + + // reset focus + Environment->setFocus(this); + + // drop the read file + memWrite->drop(); +} + +void CGUIEditWorkspace::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) +{ + out->addBool("DrawGrid", DrawGrid); + out->addBool("UseGrid", UseGrid); + out->addPosition2d("GridSize", core::position2di(GridSize.Width, GridSize.Height)); + out->addInt("MenuCommandStart", MenuCommandStart); +} + +void CGUIEditWorkspace::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + setDrawGrid(in->getAttributeAsBool("DrawGrid")); + setUseGrid(in->getAttributeAsBool("UseGrid")); + + core::position2di tmpp = in->getAttributeAsPosition2d("GridSize"); + core::dimension2di tmpd(tmpp.X, tmpp.Y); + setGridSize(tmpd); + setMenuCommandIDStart(in->getAttributeAsInt("MenuCommandStart")); +} + + +} // end namespace gui +} // end namespace irr + + diff --git a/tools/GUIEditor/CGUIEditWorkspace.h b/tools/GUIEditor/CGUIEditWorkspace.h new file mode 100644 index 00000000..2c39f271 --- /dev/null +++ b/tools/GUIEditor/CGUIEditWorkspace.h @@ -0,0 +1,171 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Gaz Davidson +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUIEDIT_WORKSPACE_H_INCLUDED__ +#define __C_GUIEDIT_WORKSPACE_H_INCLUDED__ + +#include "IGUIElement.h" +#include "CGUIEditWindow.h" +#include "EGUIEditTypes.h" + +namespace irr +{ +namespace gui +{ + + //! Adding the GUI Editor Workspace to an element allows you + /** to create, edit, load and save any elements supported + by any loaded factories. + When you add it without a parent (to the root element) + it will also allow you to edit, load and save settings in + the current skin. + */ + + // custom events + enum EGUIEDIT_CUSTOM_EVENTS + { + EGUIEDCE_ATTRIB_EDITOR = MAKE_IRR_ID('g','A','t','t'), + EGUIEDCE_OPTION_EDITOR = MAKE_IRR_ID('g','O','p','t'), + EGUIEDCE_ENV_EDITOR = MAKE_IRR_ID('g','E','n','v') + }; + + class CGUIEditWorkspace : public IGUIElement + { + public: + + //! constructor + CGUIEditWorkspace(IGUIEnvironment* environment, s32 id=-1, IGUIElement *parent=0); + + //! destructor + ~CGUIEditWorkspace(); + + //! called if an event happened. + virtual bool OnEvent(const SEvent &event); + + //! Removes a child. + virtual void removeChild(IGUIElement* child); + + //! draws the element and its children + virtual void draw(); + + //! Updates the absolute position. + virtual void updateAbsolutePosition(); + + //! Sets the menu command id's + /** The GUI editor defaults to command ID's from 0xED17 to 0xED17+EGUIEDMC_COUNT + In the rare case that these are already in use and you wish to use menus + while the editor is present you can set a new offset here. + */ + virtual void setMenuCommandIDStart(s32 id); + + //! grid drawing... + virtual void setDrawGrid(bool drawGrid); + virtual void setGridSize(const core::dimension2di& gridSize); + virtual void setUseGrid(bool useGrid); + + //! returns the first editable element under the mouse + virtual IGUIElement* getEditableElementFromPoint(IGUIElement *start, const core::position2di &point, s32 index=0 ); + + //! selecting elements + virtual void setSelectedElement(IGUIElement *sel); + virtual void selectNextSibling(); + virtual void selectPreviousSibling(); + + //! returns the selected element + virtual IGUIElement* getSelectedElement(); + + //! copies the xml of the selected element and all children to the clipboard + virtual void CopySelectedElementXML(); + + //! copies the xml of the selected element and all children to the clipboard + virtual void PasteXMLToSelectedElement(); + + virtual const c8* getTypeName() const + { + return GUIEditElementTypeNames[EGUIEDIT_GUIEDIT]; + } + + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0); + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0); + + private: + + enum EGUIEDIT_MODE + { + // when we are currently selecting an element + EGUIEDM_SELECT=0, + // selecting a new parent for the selected element + EGUIEDM_SELECT_NEW_PARENT, + + // moving the selected element + EGUIEDM_MOVE, + // resizing the selected element + EGUIEDM_RESIZE_TL, + EGUIEDM_RESIZE_T, + EGUIEDM_RESIZE_TR, + EGUIEDM_RESIZE_R, + EGUIEDM_RESIZE_BR, + EGUIEDM_RESIZE_B, + EGUIEDM_RESIZE_BL, + EGUIEDM_RESIZE_L + }; + + enum EGUIEDIT_MENUCOMMANDS + { + //! file commands + EGUIEDMC_FILE_NEW, + EGUIEDMC_FILE_LOAD, + EGUIEDMC_FILE_SAVE, + //! edit menu + EGUIEDMC_CUT_ELEMENT, + EGUIEDMC_COPY_ELEMENT, + EGUIEDMC_PASTE_ELEMENT, + EGUIEDMC_DELETE_ELEMENT, + EGUIEDMC_SET_PARENT, + EGUIEDMC_BRING_TO_FRONT, + EGUIEDMC_SAVE_ELEMENT, + //! grid + EGUIEDMC_TOGGLE_EDITOR, + + EGUIEDMC_INSERT_XML, + + //! number of menu options + EGUIEDMC_COUNT + }; + + EGUIEDIT_MODE getModeFromPos(core::position2di p); + + EGUIEDIT_MODE CurrentMode; + EGUIEDIT_MODE MouseOverMode; + core::position2di DragStart; + core::position2di StartMovePos; + core::rect SelectedArea; + + core::dimension2di GridSize; + s32 MenuCommandStart; + bool DrawGrid, UseGrid; + + IGUIElement *MouseOverElement, + *SelectedElement; + CGUIEditWindow *EditorWindow; + + core::rect TLRect; + core::rect TRRect; + core::rect TopRect; + core::rect BLRect; + core::rect LRect; + core::rect RRect; + core::rect BRRect; + core::rect BRect; + + //! Some gui-elements can't be created in this editor + core::array UnusableElementTypeFilter; + }; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/tools/GUIEditor/CGUIEnumAttribute.h b/tools/GUIEditor/CGUIEnumAttribute.h new file mode 100644 index 00000000..9e3958d4 --- /dev/null +++ b/tools/GUIEditor/CGUIEnumAttribute.h @@ -0,0 +1,114 @@ +#ifndef __C_GUI_ENUM_ATTRIBUTE_H_INCLUDED__ +#define __C_GUI_ENUM_ATTRIBUTE_H_INCLUDED__ + +#include "CGUIAttribute.h" +#include "IGUIComboBox.h" +#include "IGUIEditBox.h" +#include "EGUIEditTypes.h" + +namespace irr +{ +namespace gui +{ + + class CGUIEnumAttribute : public CGUIAttribute + { + public: + // + CGUIEnumAttribute(IGUIEnvironment* environment, IGUIElement *parent, s32 myParentID) : + CGUIAttribute(environment, parent, myParentID), + AttribComboBox(0), AttribEditBox(0) + { + + } + + virtual ~CGUIEnumAttribute() + { + if (AttribComboBox) + AttribComboBox->drop(); + if (AttribEditBox) + AttribEditBox->drop(); + } + + // save the attribute and possibly post the event to its parent + virtual void setAttrib(io::IAttributes *attribs, u32 attribIndex) + { + + if (AttribComboBox) + { + AttribComboBox->remove(); + AttribComboBox->drop(); + AttribComboBox = 0; + } + + if (AttribEditBox) + { + AttribEditBox->remove(); + AttribEditBox->drop(); + AttribEditBox = 0; + } + + core::array outLiterals; + attribs->getAttributeEnumerationLiteralsOfEnumeration(attribIndex, outLiterals); + + core::rect r = getAbsolutePosition(); + core::rect r2(0, Environment->getSkin()->getFont()->getDimension(L"A").Height + 10, + r.getWidth() - 5, + Environment->getSkin()->getFont()->getDimension(L"A").Height*2 + 20 ); + + if (outLiterals.size() > 0) + { + AttribComboBox = Environment->addComboBox(r2, this, -1); + for (u32 i=0; iaddItem( core::stringw(outLiterals[i].c_str()).c_str()); + + AttribComboBox->setSelected( attribs->getAttributeAsInt(attribIndex) ); + + AttribComboBox->grab(); + AttribComboBox->setSubElement(true); + AttribComboBox->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + } + else + { + + AttribEditBox = Environment->addEditBox( + attribs->getAttributeAsStringW(attribIndex).c_str(), + r2, true, this, -1); + AttribEditBox->grab(); + AttribEditBox->setSubElement(true); + AttribEditBox->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + } + + CGUIAttribute::setAttrib(attribs, attribIndex); + } + + //! save the attribute and possibly post the event to its parent + virtual bool updateAttrib(bool sendEvent=true) + { + if (!Attribs) + return true; + + if (AttribComboBox) + Attribs->setAttribute(Index, AttribComboBox->getText()); + else if (AttribEditBox) + Attribs->setAttribute(Index, AttribEditBox->getText()); + + return CGUIAttribute::updateAttrib(sendEvent); + } + + //! Returns the type name of the gui element. + virtual const c8* getTypeName() const + { + return GUIEditElementTypeNames[EGUIEDIT_ENUMATTRIBUTE]; + } + + private: + IGUIComboBox* AttribComboBox; + IGUIEditBox* AttribEditBox; + }; + +} // namespace gui +} // namespace irr + +#endif + diff --git a/tools/GUIEditor/CGUIPanel.cpp b/tools/GUIEditor/CGUIPanel.cpp new file mode 100644 index 00000000..4135b7a8 --- /dev/null +++ b/tools/GUIEditor/CGUIPanel.cpp @@ -0,0 +1,340 @@ +// Copyright 2006-2012 Asger Feldthaus +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +/* + Originally Klasker's but I've messed around with it lots - Gaz +*/ + +#include "CGUIPanel.h" +#include "IGUIEnvironment.h" +#include "IGUIScrollBar.h" +#include "IGUITabControl.h" +#include "IVideoDriver.h" + +const int SCROLL_BAR_SIZE = 16; // Scroll bars are 16 pixels wide +const int BORDER_WIDTH = 2; + +namespace irr +{ +namespace gui +{ + +CGUIPanel::CGUIPanel(IGUIEnvironment* environment, IGUIElement* parent, s32 id, const core::rect& rectangle, + bool border, E_SCROLL_BAR_MODE vMode, E_SCROLL_BAR_MODE hMode) + : IGUIElement(EGUIET_ELEMENT, environment, parent, id, rectangle), + VScrollBar(0), HScrollBar(0), ClipPane(0), InnerPane(0), + VScrollBarMode(vMode), HScrollBarMode(hMode), NeedsUpdate(true), Border(border) +{ + #ifdef _DEBUG + setDebugName("CGUIPanel"); + #endif + + s32 width = rectangle.getWidth(); + s32 height = rectangle.getHeight(); + + core::rect rct = core::rect(width - SCROLL_BAR_SIZE,0, width, height); + + VScrollBar = environment->addScrollBar(false, rct, 0, id); + VScrollBar->setSubElement(true); + VScrollBar->setTabStop(false); + VScrollBar->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + VScrollBar->grab(); + IGUIElement::addChild(VScrollBar); + + rct = core::rect(0, height - SCROLL_BAR_SIZE, width - SCROLL_BAR_SIZE,height ); + + HScrollBar = environment->addScrollBar(true, rct, 0, id); + HScrollBar->setSubElement(true); + HScrollBar->setTabStop(false); + HScrollBar->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT); + HScrollBar->grab(); + IGUIElement::addChild(HScrollBar); + + rct = core::rect(0,0, width - SCROLL_BAR_SIZE, height - SCROLL_BAR_SIZE); + + ClipPane = environment->addTab( rct, 0, -1); + ClipPane->setSubElement(true); + ClipPane->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + ClipPane->grab(); + IGUIElement::addChild(ClipPane); + + InnerPane = environment->addTab(rct, ClipPane, -1); + InnerPane->setSubElement(true); + InnerPane->grab(); + + calculateClientArea(); + resizeInnerPane(); +} + +CGUIPanel::~CGUIPanel() +{ + // because the inner pane has the list of children, we need to remove the outer ones manually + IGUIElement::removeChild(VScrollBar); + IGUIElement::removeChild(HScrollBar); + IGUIElement::removeChild(ClipPane); + + // now we can drop the others + VScrollBar->drop(); + HScrollBar->drop(); + ClipPane->drop(); + InnerPane->drop(); +} + + +void CGUIPanel::draw() +{ + if (NeedsUpdate) + { + calculateClientArea(); + resizeInnerPane(); + NeedsUpdate = false; + } + + IGUISkin* skin = Environment->getSkin(); + if (Border && skin) + { + skin->draw3DSunkenPane( this, skin->getColor( EGDC_APP_WORKSPACE), false, true, AbsoluteRect, &AbsoluteClippingRect ); + } + + IGUIElement::draw(); +} + +void CGUIPanel::addChild(IGUIElement *child) +{ + // add the child to the inner pane + InnerPane->addChild(child); + + NeedsUpdate = true; +} + +void CGUIPanel::removeChild(IGUIElement *child) +{ + InnerPane->removeChild(child); + + NeedsUpdate = true; +} + +//! returns children of the inner pane +const core::list& CGUIPanel::getChildren() +{ + return InnerPane->getChildren(); +} + +bool CGUIPanel::hasBorder() const +{ + return Border; +} + +void CGUIPanel::setBorder( bool enabled ) +{ + Border = enabled; +} + +IGUIScrollBar* CGUIPanel::getVScrollBar() const +{ + return VScrollBar; +} + +IGUIScrollBar* CGUIPanel::getHScrollBar() const +{ + return HScrollBar; +} + +E_SCROLL_BAR_MODE CGUIPanel::getVScrollBarMode() const +{ + return VScrollBarMode; +} + +void CGUIPanel::setVScrollBarMode( E_SCROLL_BAR_MODE mode ) +{ + VScrollBarMode = mode; + NeedsUpdate = true; +} + +E_SCROLL_BAR_MODE CGUIPanel::getHScrollBarMode() const +{ + return HScrollBarMode; +} + +void CGUIPanel::setHScrollBarMode(E_SCROLL_BAR_MODE mode) +{ + HScrollBarMode = mode; + NeedsUpdate = true; +} + +bool CGUIPanel::OnEvent(const SEvent &event) +{ + // Redirect mouse wheel to scrollbar + if (event.EventType == EET_MOUSE_INPUT_EVENT && event.MouseInput.Event == EMIE_MOUSE_WHEEL) + { + if (VScrollBar->isVisible()) + { + Environment->setFocus(VScrollBar); + VScrollBar->OnEvent(event); + return true; + } + else if (VScrollBar->isVisible()) + { + Environment->setFocus(HScrollBar); + HScrollBar->OnEvent(event); + return true; + } + } + else + { + if (event.EventType == EET_GUI_EVENT && event.GUIEvent.EventType == EGET_SCROLL_BAR_CHANGED && + (event.GUIEvent.Caller == HScrollBar || event.GUIEvent.Caller == VScrollBar) ) + { + moveInnerPane(); + + return true; + } + } + + return IGUIElement::OnEvent(event); +} + +void CGUIPanel::moveInnerPane() +{ + core::dimension2d dim = InnerPane->getAbsolutePosition().getSize(); + core::position2d newpos(HScrollBar->isVisible() ? -HScrollBar->getPos() : 0 , VScrollBar->isVisible() ? -VScrollBar->getPos() : 0); + core::rect r(newpos, newpos + dim); + InnerPane->setRelativePosition(r); +} + + +void CGUIPanel::updateAbsolutePosition() +{ + IGUIElement::updateAbsolutePosition(); + calculateClientArea(); + resizeInnerPane(); +} + + +void CGUIPanel::resizeInnerPane() +{ + if (!HScrollBar || !VScrollBar || !InnerPane || !ClipPane) + return; + + // get outer pane size + core::rect outerRect = ClipPane->getRelativePosition(); + + // resize flexible children depending on outer pane + InnerPane->setRelativePosition(outerRect); + + // get desired size (total size of all children) + core::rect totalRect(0, 0, 0, 0); + + core::list::ConstIterator it; + + for (it = InnerPane->getChildren().begin(); + it != InnerPane->getChildren().end(); ++it) + { + core::rect rct = (*it)->getRelativePosition(); + totalRect.addInternalPoint(rct.UpperLeftCorner); + totalRect.addInternalPoint(rct.LowerRightCorner); + } + + // move children if pane needs to grow + core::position2di adjustedMovement(0,0); + + if (totalRect.UpperLeftCorner.X < 0) + adjustedMovement.X = -totalRect.UpperLeftCorner.X; + if (totalRect.UpperLeftCorner.Y < 0) + adjustedMovement.Y = -totalRect.UpperLeftCorner.Y; + + if (adjustedMovement.X > 0 || adjustedMovement.Y > 0) + { + totalRect += adjustedMovement; + + for (it = InnerPane->getChildren().begin(); + it != InnerPane->getChildren().end(); ++it ) + { + (*it)->move(adjustedMovement); + } + } + + // make sure the inner pane is at least as big as the outer + if (totalRect.getWidth() < outerRect.getWidth()) + { + totalRect.UpperLeftCorner.X = 0; + totalRect.LowerRightCorner.X = outerRect.getWidth(); + } + if (totalRect.getHeight() < outerRect.getHeight()) + { + totalRect.UpperLeftCorner.Y = 0; + totalRect.LowerRightCorner.Y = outerRect.getHeight(); + } + + InnerPane->setRelativePosition(totalRect); + + // scrollbars + if ( HScrollBarMode != ESBM_ALWAYS_INVISIBLE && + (totalRect.getWidth() > outerRect.getWidth() || HScrollBarMode == ESBM_ALWAYS_VISIBLE) ) + { + HScrollBar->setVisible(true); + HScrollBar->setMax(totalRect.getWidth() - outerRect.getWidth()); + bringToFront(HScrollBar); + } + else + HScrollBar->setVisible(false); + + if ( VScrollBarMode != ESBM_ALWAYS_INVISIBLE && + (totalRect.getHeight() > outerRect.getHeight() || VScrollBarMode == ESBM_ALWAYS_VISIBLE) ) + { + VScrollBar->setVisible(true); + VScrollBar->setMax(totalRect.getHeight() - outerRect.getHeight()); + bringToFront(VScrollBar); + } + else + VScrollBar->setVisible(false); + + // move to adjust for scrollbar pos + moveInnerPane(); +} + +void CGUIPanel::calculateClientArea() +{ + core::rect ClientArea(0,0, AbsoluteRect.getWidth(),AbsoluteRect.getHeight()); + + if (VScrollBar->isVisible()) + ClientArea.LowerRightCorner.X -= VScrollBar->getRelativePosition().getWidth(); + + if (HScrollBar->isVisible()) + ClientArea.LowerRightCorner.Y -= HScrollBar->getRelativePosition().getHeight(); + + if (Border) + { + ClientArea.UpperLeftCorner += core::position2d( BORDER_WIDTH, BORDER_WIDTH ); + ClientArea.LowerRightCorner -= core::position2d( BORDER_WIDTH, BORDER_WIDTH ); + } + + ClipPane->setRelativePosition(ClientArea); +} + +core::rect CGUIPanel::getClientArea() const +{ + return ClipPane->getRelativePosition(); +} + +void CGUIPanel::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) +{ + IGUIElement::serializeAttributes(out, options); + + out->addBool("border", Border); + out->addEnum("horizontalScrollBar", HScrollBarMode, GUIScrollBarModeNames ); + out->addEnum("verticalScrollBar", VScrollBarMode, GUIScrollBarModeNames ); +} + +void CGUIPanel::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + IGUIElement::deserializeAttributes(in, options); + + setBorder(in->getAttributeAsBool("border")); + setHScrollBarMode((E_SCROLL_BAR_MODE)in->getAttributeAsEnumeration("horizontalScrollBar", GUIScrollBarModeNames)); + setVScrollBarMode((E_SCROLL_BAR_MODE)in->getAttributeAsEnumeration("verticalScrollBar", GUIScrollBarModeNames)); +} + +} // namespace gui +} // namespace irr diff --git a/tools/GUIEditor/CGUIPanel.h b/tools/GUIEditor/CGUIPanel.h new file mode 100644 index 00000000..cb6f79a5 --- /dev/null +++ b/tools/GUIEditor/CGUIPanel.h @@ -0,0 +1,128 @@ +// Copyright 2006-2012 Asger Feldthaus +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef _C_GUI_PANEL_H_ +#define _C_GUI_PANEL_H_ + +#include "IGUIElement.h" +#include "EGUIEditTypes.h" + +namespace irr +{ +namespace gui +{ + +class IGUIScrollBar; +class IGUITab; + +enum E_SCROLL_BAR_MODE +{ + //! The scrollbar will only show up when needed. + ESBM_AUTOMATIC = 0, + + //! The scrollbar will never be visible. + ESBM_ALWAYS_INVISIBLE, + + //! The scrollbar will always the visible. + ESBM_ALWAYS_VISIBLE, + + //! just a count of how many are in this enum + ESBM_COUNT +}; + +const c8* const GUIScrollBarModeNames[] = +{ + "automatic", + "alwaysInvisible", + "alwaysVisible", + 0 +}; + +class CGUIPanel : public IGUIElement +{ +public: + CGUIPanel( IGUIEnvironment* environment, IGUIElement* parent, s32 id=-1, + const core::rect& rectangle = core::rect(0,0,100,100), + bool border=false, + E_SCROLL_BAR_MODE vMode=ESBM_AUTOMATIC, + E_SCROLL_BAR_MODE hMode=ESBM_ALWAYS_INVISIBLE ); + + virtual ~CGUIPanel(); + + //! draws the panel and its children + virtual void draw(); + + //! returns true if it has a border, false if not + bool hasBorder() const; + + //! sets whether the element draws a border + void setBorder(bool enabled); + + //! returns a pointer to the vertical scrollbar + IGUIScrollBar* getVScrollBar() const; + + //! returns a pointer to the horizontal scrollbar + IGUIScrollBar* getHScrollBar() const; + + //! returns the vertical scrollbar visibility rule + E_SCROLL_BAR_MODE getVScrollBarMode() const; + + //! sets the vertical scrollbar visibility rule + void setVScrollBarMode(E_SCROLL_BAR_MODE mode); + + //! returns the horizontal scrollbar visibility rule + E_SCROLL_BAR_MODE getHScrollBarMode() const; + + //! sets the horizontal scrollbar visibility rule + void setHScrollBarMode(E_SCROLL_BAR_MODE mode); + + //! returns the visible area inside the panel, excluding scrollbar and border + core::rect getClientArea() const; + + virtual bool OnEvent(const SEvent &event); + + //! adds a child to the panel + virtual void addChild(IGUIElement* child); + + //! removes a child from the panel + virtual void removeChild(IGUIElement* child); + + //! updates the absolute position + virtual void updateAbsolutePosition(); + + //! returns children of the inner pane + virtual const core::list& getChildren(); + + //! Returns the type name of the gui element. + virtual const c8* getTypeName() const + { + return GUIEditElementTypeNames[EGUIEDIT_GUIPANEL]; + } + + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0); + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0); + +protected: + void moveInnerPane(); + void resizeInnerPane(); + void calculateClientArea(); + +private: + + IGUIScrollBar* VScrollBar; + IGUIScrollBar* HScrollBar; + IGUITab* ClipPane; + IGUITab* InnerPane; + + E_SCROLL_BAR_MODE VScrollBarMode; + E_SCROLL_BAR_MODE HScrollBarMode; + + bool NeedsUpdate; + bool Border; +}; + +} // namespace gui +} // namespace irr + +#endif diff --git a/tools/GUIEditor/CGUIStringAttribute.h b/tools/GUIEditor/CGUIStringAttribute.h new file mode 100644 index 00000000..af9ac03e --- /dev/null +++ b/tools/GUIEditor/CGUIStringAttribute.h @@ -0,0 +1,70 @@ +#ifndef __C_GUI_STRING_ATTRIBUTE_H_INCLUDED__ +#define __C_GUI_STRING_ATTRIBUTE_H_INCLUDED__ + +#include "CGUIAttribute.h" +#include "IGUIEditBox.h" +#include "EGUIEditTypes.h" + +namespace irr +{ +namespace gui +{ + + class CGUIStringAttribute : public CGUIAttribute + { + public: + // + CGUIStringAttribute(IGUIEnvironment* environment, IGUIElement *parent, s32 myParentID) : + CGUIAttribute(environment, parent, myParentID), + AttribEditBox(0) + { + core::rect r = getAbsolutePosition(); + core::rect r2(0, Environment->getSkin()->getFont()->getDimension(L"A").Height + 10, + r.getWidth() - 5, + Environment->getSkin()->getFont()->getDimension(L"A").Height*2 + 15 ); + + AttribEditBox = environment->addEditBox(0, r2, true, this, -1); + AttribEditBox->grab(); + AttribEditBox->setSubElement(true); + AttribEditBox->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + + } + + virtual ~CGUIStringAttribute() + { + if (AttribEditBox) + AttribEditBox->drop(); + } + + virtual void setAttrib(io::IAttributes *attribs, u32 attribIndex) + { + AttribEditBox->setText(attribs->getAttributeAsStringW(attribIndex).c_str()); + CGUIAttribute::setAttrib(attribs, attribIndex); + } + + //! save the attribute and possibly post the event to its parent + virtual bool updateAttrib(bool sendEvent=true) + { + if (!Attribs) + return true; + + Attribs->setAttribute(Index, AttribEditBox->getText()); + AttribEditBox->setText(Attribs->getAttributeAsStringW(Index).c_str()); + + return CGUIAttribute::updateAttrib(sendEvent); + } + + //! Returns the type name of the gui element. + virtual const c8* getTypeName() const + { + return GUIEditElementTypeNames[EGUIEDIT_STRINGATTRIBUTE]; + } + + private: + IGUIEditBox* AttribEditBox; + }; + +} // namespace gui +} // namespace irr + +#endif diff --git a/tools/GUIEditor/CGUITextureAttribute.h b/tools/GUIEditor/CGUITextureAttribute.h new file mode 100644 index 00000000..6a4fef20 --- /dev/null +++ b/tools/GUIEditor/CGUITextureAttribute.h @@ -0,0 +1,140 @@ +#ifndef __C_GUI_TEXTURE_ATTRIBUTE_H_INCLUDED__ +#define __C_GUI_TEXTURE_ATTRIBUTE_H_INCLUDED__ + +#include "CGUIAttribute.h" +#include "IGUIEditBox.h" +#include "IGUIImage.h" +#include "IGUIButton.h" +#include "EGUIEditTypes.h" + +namespace irr +{ +namespace gui +{ + + class CGUITextureAttribute : public CGUIAttribute + { + public: + // + CGUITextureAttribute(IGUIEnvironment* environment, IGUIElement *parent, s32 myParentID) : + CGUIAttribute(environment, parent, myParentID), + AttribEditBox(0), AttribImage(0), AttribButton(0) + { + IGUISkin* skin = Environment->getSkin(); + + core::rect r = getAbsolutePosition(); + s32 topy = skin->getFont()->getDimension(L"A").Height + 10; + s32 h = skin->getFont()->getDimension(L"A").Height + 5; + + AttribImage = environment->addImage(0, core::position2di(0, topy), false, this); + AttribImage->setRelativePosition( core::rect(0,topy, r.getWidth() - 5, 100+topy)); + AttribImage->grab(); + AttribImage->setSubElement(true); + AttribImage->setScaleImage(true); + AttribImage->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + + topy += 105; + + core::rect r2(0, topy, r.getWidth() - 15 - skin->getSize(EGDS_CHECK_BOX_WIDTH), topy + h); + core::rect br(r.getWidth() - 10 - skin->getSize(EGDS_CHECK_BOX_WIDTH), topy, r.getWidth(), topy + h); + + AttribEditBox = environment->addEditBox(0, r2, true, this, -1); + AttribEditBox->grab(); + AttribEditBox->setSubElement(true); + AttribEditBox->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + + AttribButton = environment->addButton(br, this, -1, L"..."); + AttribButton->grab(); + AttribButton->setSubElement(true); + AttribButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + //AttribButton->setSpriteBank(skin->getSpriteBank()); + //AttribButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_FILE), skin->getColor(EGDC_WINDOW_SYMBOL)); + //AttribButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_FILE), skin->getColor(EGDC_WINDOW_SYMBOL), true); + } + + virtual ~CGUITextureAttribute() + { + if (AttribEditBox) + AttribEditBox->drop(); + if (AttribImage) + AttribImage->drop(); + if (AttribButton) + AttribButton->drop(); + } + + virtual bool OnEvent(const SEvent &e) + { + + if (IsEnabled) + { + switch (e.EventType) + { + case EET_GUI_EVENT: + switch (e.GUIEvent.EventType) + { + case EGET_BUTTON_CLICKED: + // button click: open file dialog + if (e.GUIEvent.Caller == AttribButton) + { + //Environment->addGUIElement("textureBrowser", Environment->getRootGUIElement()); + return true; + } + break; + case EGET_FILE_SELECTED: + // file selected: change editbox value and set event + + return true; + case EGET_FILE_CHOOSE_DIALOG_CANCELLED: + + return true; + default: + break; + } + break; + case EET_KEY_INPUT_EVENT: + return true; + default: + break; + } + } + return CGUIAttribute::OnEvent(e); + } + + virtual void setAttrib(io::IAttributes *attribs, u32 attribIndex) + { + AttribEditBox->setText(attribs->getAttributeAsStringW(attribIndex).c_str()); + AttribImage->setImage(attribs->getAttributeAsTexture(Index)); + + CGUIAttribute::setAttrib(attribs, attribIndex); + } + + //! save the attribute and possibly post the event to its parent + virtual bool updateAttrib(bool sendEvent=true) + { + if (!Attribs) + return true; + + Attribs->setAttribute(Index, AttribEditBox->getText()); + core::stringw tmp = Attribs->getAttributeAsStringW(Index); + AttribEditBox->setText(Attribs->getAttributeAsStringW(Index).c_str()); + AttribImage->setImage(Attribs->getAttributeAsTexture(Index)); + + return CGUIAttribute::updateAttrib(sendEvent); + } + + //! Returns the type name of the gui element. + virtual const c8* getTypeName() const + { + return GUIEditElementTypeNames[EGUIEDIT_TEXTUREATTRIBUTE]; + } + + private: + IGUIEditBox* AttribEditBox; + IGUIImage* AttribImage; + IGUIButton* AttribButton; + }; + +} // namespace gui +} // namespace irr + +#endif diff --git a/tools/GUIEditor/CGUITextureCacheBrowser.cpp b/tools/GUIEditor/CGUITextureCacheBrowser.cpp new file mode 100644 index 00000000..bac5233f --- /dev/null +++ b/tools/GUIEditor/CGUITextureCacheBrowser.cpp @@ -0,0 +1,336 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Gaz Davidson +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CGUITextureCacheBrowser.h" +#include "IGUIEnvironment.h" +#include "IGUIButton.h" +#include "IGUISkin.h" +#include "IGUIFont.h" +#include "IVideoDriver.h" + +namespace irr +{ +namespace gui +{ + +CGUITextureCacheBrowser::CGUITextureCacheBrowser(IGUIEnvironment* environment, s32 id, IGUIElement *parent) +: IGUIWindow(environment, parent, id, core::rect(0,0,300,200)), + CloseButton(0), Panel(0), SelectedTexture(-1), Dragging(false), IsDraggable(true) +{ + #ifdef _DEBUG + setDebugName("CGUITextureCacheBrowser"); + #endif + + IGUISkin* skin = 0; + IGUISpriteBank* sprites = 0; + video::SColor color(255,255,255,255); + + if (environment) + skin = environment->getSkin(); + + s32 buttonw = 15; + if (skin) + { + buttonw = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH); + sprites = skin->getSpriteBank(); + color = skin->getColor(EGDC_WINDOW_SYMBOL); + } + 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" ); + CloseButton->setSubElement(true); + CloseButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); + if (sprites) + { + CloseButton->setSpriteBank(sprites); + CloseButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_CLOSE), color); + CloseButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_CLOSE), color); + } + + CloseButton->grab(); + + // window title + Text = L"Texture Browser"; + + // panel element + Panel = new CGUIPanel(environment, this); + Panel->setRelativePosition( core::rect(1, buttonw + 5, 151, RelativeRect.getHeight() - 1)); + Panel->setAlignment(EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); + Panel->setBorder(true); + Panel->setSubElement(true); + + // some buttons + + + // add images from texture cache + updateImageList(); + +} + +CGUITextureCacheBrowser::~CGUITextureCacheBrowser() +{ + if (CloseButton) + CloseButton->drop(); + if (Panel) + Panel->drop(); + + // drop images + u32 i; + for (i=0; idrop(); + Images[i]->remove(); + } + Images.clear(); +} +void CGUITextureCacheBrowser::updateImageList() +{ + if (!Panel) + return; + + video::IVideoDriver* Driver = Environment->getVideoDriver(); + + // clear images + u32 i; + for (i=0; idrop(); + Images[i]->remove(); + } + Images.clear(); + + u32 count = (u32)Driver->getTextureCount(); + + s32 h = Panel->getClientArea().getWidth()-10; + s32 hw = h/2; + core::rect pos(Panel->getClientArea().getCenter().X - Panel->getAbsolutePosition().UpperLeftCorner.X - hw, 5, + Panel->getClientArea().getCenter().X - Panel->getAbsolutePosition().UpperLeftCorner.X + hw, h+5); + + core::position2di moveDist(0, h+5); + + for (u32 i=0; igetTextureByIndex(i); + details = L"File name: "; + details += tex->getName(); + details += L"\nFormat: "; + video::ECOLOR_FORMAT cf = tex->getColorFormat(); + + bool alpha = false; + + switch (cf) + { + case video::ECF_A1R5G5B5: + details += L"A1R5G5B5 (16-bit with 1-bit alpha channel)\n"; + alpha = true; + break; + case video::ECF_R5G6B5: + details += L"R5G6B5 (16-bit, no alpha channel)\n"; + break; + case video::ECF_R8G8B8: + details += L"R8G8B8 (16-bit, no alpha channel)\n"; + break; + case video::ECF_A8R8G8B8: + details += L"R8G8B8 (32-bit with 8-bit alpha channel)\n"; + alpha = true; + break; + default: + details += L"Unknown\n"; + } + + core::dimension2du osize = tex->getOriginalSize(); + core::dimension2du size = tex->getOriginalSize(); + + details += "Size: "; + details += size.Width; + details += "x"; + details += size.Height; + + if (osize != size) + { + details += "\nOriginal Size: "; + details += osize.Width; + details += "x"; + details += osize.Height; + } + + details += L"\nMip-maps: "; + + if (tex->hasMipMaps()) + details += L"Yes\n"; + else + details += L"No\n"; + + IGUIImage* img = Environment->addImage(tex, core::position2di(1,1), alpha, Panel, i); + img->grab(); + Images.push_back(img); + img->setRelativePosition(pos); + img->setToolTipText(details.c_str()); + img->setScaleImage(true); + img->setColor( SelectedTexture == (s32)i ? video::SColor(255,255,255,255) : video::SColor(128,128,128,128) ); + + pos = pos + moveDist; + } +} + +void CGUITextureCacheBrowser::updateAbsolutePosition() +{ + IGUIWindow::updateAbsolutePosition(); + updateImageList(); +} + +//! called if an event happened. +bool CGUITextureCacheBrowser::OnEvent(const SEvent &event) +{ + switch(event.EventType) + { + case EET_GUI_EVENT: + if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST) + { + if (event.GUIEvent.Caller == (IGUIElement*)this) + Dragging = false; + return true; + } + else + if (event.GUIEvent.EventType == EGET_BUTTON_CLICKED) + { + if (event.GUIEvent.Caller == CloseButton) + { + remove(); + return true; + } + } + break; + case EET_MOUSE_INPUT_EVENT: + switch(event.MouseInput.Event) + { + case EMIE_LMOUSE_PRESSED_DOWN: + DragStart.X = event.MouseInput.X; + DragStart.Y = event.MouseInput.Y; + + if (getElementFromPoint(DragStart) == this) + { + if (!Environment->hasFocus(this)) + { + Dragging = IsDraggable; + //Environment->setFocus(this); + if (Parent) + Parent->bringToFront(this); + } + return true; + } + else + { + if (Panel->getAbsolutePosition().isPointInside(DragStart)) + { + // select an image + IGUIElement* el = Panel->getElementFromPoint(DragStart); + if (el && el != Panel) + { + if (el->getType() == EGUIET_IMAGE) + { + setSelected(el->getID()); + } + } + else + { + setSelected(); + } + } + } + break; + case EMIE_LMOUSE_LEFT_UP: + Dragging = false; + //Environment->removeFocus(this); + return true; + case EMIE_MOUSE_MOVED: + if (Dragging) + { + // gui window should not be dragged outside its parent + if (Parent) + if (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; + + + move(core::position2d(event.MouseInput.X - DragStart.X, event.MouseInput.Y - DragStart.Y)); + DragStart.X = event.MouseInput.X; + DragStart.Y = event.MouseInput.Y; + return true; + } + break; + default: + break; + } + default: + break; + } + + return Parent ? Parent->OnEvent(event) : false; +} + +void CGUITextureCacheBrowser::setSelected(s32 index) +{ + SelectedTexture = index; + updateImageList(); + printf("Texture %d selected\n", index); +} + +void CGUITextureCacheBrowser::draw() +{ + if (!IsVisible) + return; + + IGUISkin* skin = Environment->getSkin(); + + core::rect rect = AbsoluteRect; + core::rect *cl = &AbsoluteClippingRect; + + // draw body fast + rect = skin->draw3DWindowBackground(this, true, skin->getColor(EGDC_ACTIVE_BORDER), + AbsoluteRect, &AbsoluteClippingRect); + + // draw window text + if (Text.size()) + { + rect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X); + rect.UpperLeftCorner.Y += skin->getSize(EGDS_TEXT_DISTANCE_Y); + rect.LowerRightCorner.X -= skin->getSize(EGDS_WINDOW_BUTTON_WIDTH) + 5; + + IGUIFont* font = skin->getFont(); + if (font) + font->draw(Text.c_str(), rect, skin->getColor(EGDC_ACTIVE_CAPTION), false, true, cl); + } + + IGUIElement::draw(); +} + + +bool CGUITextureCacheBrowser::isDraggable() const +{ + return IsDraggable; +} + +void CGUITextureCacheBrowser::setDraggable(bool draggable) +{ + IsDraggable = draggable; + + if (Dragging && !IsDraggable) + Dragging = false; +} + + +//! Returns the rectangle of the drawable area (without border, without titlebar and without scrollbars) +core::rect CGUITextureCacheBrowser::getClientRect() const +{ + return core::recti(); +} + +} // namespace gui +} // namespace irr diff --git a/tools/GUIEditor/CGUITextureCacheBrowser.h b/tools/GUIEditor/CGUITextureCacheBrowser.h new file mode 100644 index 00000000..108d4d64 --- /dev/null +++ b/tools/GUIEditor/CGUITextureCacheBrowser.h @@ -0,0 +1,88 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt / Gaz Davidson +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_GUI_TEXTURE_CACHE_BROWSER_H_INCLUDED__ +#define __C_GUI_TEXTURE_CACHE_BROWSER_H_INCLUDED__ + +#include "IGUIWindow.h" +#include "CGUIPanel.h" +#include "IGUIImage.h" +#include "EGUIEditTypes.h" + +namespace irr +{ +namespace gui +{ + + //! Texture cache browser + + const u32 TEXTURE_BROWSER_TEXTURE_SELECTED = 0x5E1EC7ED; // custom event number for texture selected + + class CGUITextureCacheBrowser : public IGUIWindow + { + public: + + //! constructor + CGUITextureCacheBrowser(IGUIEnvironment* environment, s32 id=-1, IGUIElement *parent=0); + + //! destructor + ~CGUITextureCacheBrowser(); + + //! event handler + virtual bool OnEvent(const SEvent &event); + + //! draws the element + virtual void draw(); + + //! update absolute position + virtual void updateAbsolutePosition(); + + //! this shoudln't be serialized, but this is included as it's an example + virtual const c8* getTypeName() const { return "textureCacheBrowser"; } + + //! Returns pointer to the close button + virtual IGUIButton* getCloseButton() const { return CloseButton; } + + //! Returns pointer to the minimize button + virtual IGUIButton* getMinimizeButton() const { return 0;} + + //! Returns pointer to the maximize button + virtual IGUIButton* getMaximizeButton() const { return 0;} + + //! get draggable + virtual bool isDraggable() const; + + //! get draggable + virtual void setDraggable(bool draggable); + + //! not used + virtual core::rect getClientRect() const; + virtual void setDrawBackground(bool draw) { } + virtual bool getDrawBackground() const { return true; } + virtual void setDrawTitlebar(bool draw) { } + virtual bool getDrawTitlebar() const { return true; } + + + void setSelected(s32 index=-1); + + private: + + void updateImageList(); + + core::array Images; + core::position2d DragStart; + + IGUIButton* CloseButton; + CGUIPanel* Panel; + s32 SelectedTexture; + bool Dragging; + bool IsDraggable; + }; + + +} // end namespace gui +} // end namespace irr + +#endif + diff --git a/tools/GUIEditor/CMemoryReadWriteFile.cpp b/tools/GUIEditor/CMemoryReadWriteFile.cpp new file mode 100644 index 00000000..7a803e0d --- /dev/null +++ b/tools/GUIEditor/CMemoryReadWriteFile.cpp @@ -0,0 +1,99 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CMemoryReadWriteFile.h" + +using namespace irr; +using namespace io; + +CMemoryReadWriteFile::CMemoryReadWriteFile(const c8* filename) +: Data(), FileName(filename), Pos(0) +{ +} + + +size_t CMemoryReadWriteFile::write(const void* buffer, size_t sizeToWrite) +{ + // no point in writing 0 bytes + if (sizeToWrite < 1) + return 0; + + // expand size + if (Pos + sizeToWrite > Data.size()) + Data.set_used(Pos+sizeToWrite); + + // copy data + memcpy( (void*) &Data[Pos], buffer, sizeToWrite); + + Pos += sizeToWrite; + + return sizeToWrite; + +} + +bool CMemoryReadWriteFile::seek(long finalPos, bool relativeMovement) +{ + if (relativeMovement) + { + if (finalPos + Pos < 0) + return 0; + else + Pos += finalPos; + } + else + { + Pos = finalPos; + } + + if (Pos > (s32)Data.size()) + Data.set_used(Pos+1); + + return true; + +} + +const io::path& CMemoryReadWriteFile::getFileName() const +{ + return FileName; +} + +long CMemoryReadWriteFile::getPos() const +{ + return Pos; +} + +core::array& CMemoryReadWriteFile::getData() +{ + return Data; +} + + +long CMemoryReadWriteFile::getSize() const +{ + return Data.size(); +} + + +size_t CMemoryReadWriteFile::read(void* buffer, size_t sizeToRead) +{ + // cant read past the end + if ((size_t)Pos + sizeToRead >= Data.size()) + sizeToRead = Data.size() - (size_t)Pos; + + // cant read 0 bytes + if (!sizeToRead) + return 0; + + // copy data + memcpy( buffer, (void*) &Data[Pos], sizeToRead); + + Pos += (long)sizeToRead; + + return sizeToRead; +} + +bool CMemoryReadWriteFile::flush() +{ + return true; // no buffering, nothing to do +} diff --git a/tools/GUIEditor/CMemoryReadWriteFile.h b/tools/GUIEditor/CMemoryReadWriteFile.h new file mode 100644 index 00000000..4b110bf9 --- /dev/null +++ b/tools/GUIEditor/CMemoryReadWriteFile.h @@ -0,0 +1,76 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_MEMORY_READ_WRITE_FILE_H_INCLUDED__ +#define __C_MEMORY_READ_WRITE_FILE_H_INCLUDED__ + +#include "IWriteFile.h" +#include "IReadFile.h" +#include "irrArray.h" +#include "irrString.h" +#include "memory.h" + +namespace irr +{ +namespace io +{ + + //! Provides write access to an array as if it is a file. + class CMemoryReadWriteFile : public virtual IWriteFile, public virtual IReadFile + { + public: + + CMemoryReadWriteFile(const c8* filename=0); + + //! Reads an amount of bytes from the file. + //! \param buffer: Pointer to buffer of bytes to write. + //! \param sizeToWrite: Amount of bytes to written to the file. + //! \return Returns how much bytes were written. + virtual size_t write(const void* buffer, size_t sizeToWrite); + + //! Changes position in file, returns true if successful. + //! \param finalPos: Destination position in the file. + //! \param relativeMovement: If set to true, the position in the file is + //! changed relative to current position. Otherwise the position is changed + //! from begin of file. + //! \return Returns true if successful, otherwise false. + virtual bool seek(long finalPos, bool relativeMovement = false); + + //! Returns size of file. + //! \return Returns the size of the file in bytes. + virtual long getSize() const; + + //! Reads an amount of bytes from the file. + //! \param buffer: Pointer to buffer where to read bytes will be written to. + //! \param sizeToRead: Amount of bytes to read from the file. + //! \return Returns how much bytes were read. + virtual size_t read(void* buffer, size_t sizeToRead); + + //! Returns the current position in the file. + //! \return Returns the current position in the file in bytes. + virtual long getPos() const; + + //! Returns name of file. + //! \return Returns the file name as zero terminated character string. + virtual const io::path& getFileName() const; + + //! Flush the content of the buffer in the file + virtual bool flush() _IRR_OVERRIDE_; + + //! Returns file data as an array + core::array& getData(); + + private: + + core::array Data; + io::path FileName; + long Pos; + }; + + + +} // end namespace io +} // end namespace irr + +#endif // __C_MEMORY_READ_WRITE_FILE_H_INCLUDED__ diff --git a/tools/GUIEditor/EGUIEditTypes.h b/tools/GUIEditor/EGUIEditTypes.h new file mode 100644 index 00000000..88d119e2 --- /dev/null +++ b/tools/GUIEditor/EGUIEditTypes.h @@ -0,0 +1,61 @@ +#ifndef __C_GUIEDIT_TYPES_H_INCLUDED__ +#define __C_GUIEDIT_TYPES_H_INCLUDED__ + +#include "irrTypes.h" + +namespace irr { +namespace gui { + +enum EGUIEDIT_ELEMENT_TYPES +{ + // GUI Editor + EGUIEDIT_GUIEDIT=0, + EGUIEDIT_GUIEDITWINDOW, + // Generic + EGUIEDIT_GUIPANEL, + EGUIEDIT_TEXTUREBROWSER, + // Attribute editors + EGUIEDIT_ATTRIBUTEEDITOR, + EGUIEDIT_STRINGATTRIBUTE, + EGUIEDIT_BOOLATTRIBUTE, + EGUIEDIT_ENUMATTRIBUTE, + EGUIEDIT_COLORATTRIBUTE, + EGUIEDIT_COLORFATTRIBUTE, + EGUIEDIT_TEXTUREATTRIBUTE, + // Dummy editor stubs + EGUIEDIT_CONTEXTMENUEDITOR, + EGUIEDIT_MENUEDITOR, + EGUIEDIT_FILEDIALOGEDITOR, + EGUIEDIT_COLORDIALOGEDITOR, + EGUIEDIT_MODALSCREENEDITOR, + // Count + EGUIEDIT_COUNT +}; + +const c8* const GUIEditElementTypeNames[] = +{ + "GUIEditor", + "GUIEditWindow", + "panel", + "textureCacheBrowser", + "attributeEditor", + "string_attribute", + "bool_attribute", + "enum_attribute", + "color_attribute", + "colorf_attribute", + "texture_attribute", + // dummy editors + "contextMenu_editor", + "menu_editor", + "fileOpenDialog_editor", + "colorSelectDialog_editor", + "modalScreen_editor", + 0 +}; + +} // gui +} // irr + +#endif + diff --git a/tools/GUIEditor/GUI Editor_vc10.vcxproj b/tools/GUIEditor/GUI Editor_vc10.vcxproj new file mode 100644 index 00000000..82c0fbb3 --- /dev/null +++ b/tools/GUIEditor/GUI Editor_vc10.vcxproj @@ -0,0 +1,217 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {853A396E-C031-4C26-A716-5B4E176BE11D} + GUI Editor + Win32Proj + GUIEditor + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + Neither + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib %(AdditionalOptions) + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Neither + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib %(AdditionalOptions) + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Full + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ../../bin/Win32-visualstudio/GUIEditor.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + true + true + + + + + + + Full + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ../../bin/Win32-visualstudio/GUIEditor.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {e08e042a-6c45-411b-92be-3cc31331019f} + false + + + + + + \ No newline at end of file diff --git a/tools/GUIEditor/GUI Editor_vc10.vcxproj.filters b/tools/GUIEditor/GUI Editor_vc10.vcxproj.filters new file mode 100644 index 00000000..1d06fa46 --- /dev/null +++ b/tools/GUIEditor/GUI Editor_vc10.vcxproj.filters @@ -0,0 +1,88 @@ + + + + + {f6ad9df9-ebaa-4c0f-997b-c8101c1fc669} + + + {7fd14cb1-d2e7-4fd0-85c1-68fc9d1249f7} + + + {ab2c3f3a-1d99-4619-b5df-47fdd9449f3f} + + + {740a4255-37cc-4ac4-94e9-f2f0970491a8} + + + {a28a0b21-3336-432f-9759-ff2dc064874a} + + + + + gui + + + gui + + + gui + + + gui + + + gui\GUIAttributes + + + gui\Useful GUI Elements + + + io + + + + + + gui + + + gui + + + gui + + + gui + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\Useful GUI Elements + + + gui\Element Editors + + + io + + + \ No newline at end of file diff --git a/tools/GUIEditor/GUI Editor_vc11.vcxproj b/tools/GUIEditor/GUI Editor_vc11.vcxproj new file mode 100644 index 00000000..f90a1ac6 --- /dev/null +++ b/tools/GUIEditor/GUI Editor_vc11.vcxproj @@ -0,0 +1,217 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {853A396E-C031-4C26-A716-5B4E176BE11D} + GUI Editor + Win32Proj + GUIEditor + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + Neither + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib %(AdditionalOptions) + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Neither + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib %(AdditionalOptions) + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Full + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ../../bin/Win32-visualstudio/GUIEditor.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + true + true + + + + + + + Full + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ../../bin/Win32-visualstudio/GUIEditor.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {e08e042a-6c45-411b-92be-3cc31331019f} + false + + + + + + \ No newline at end of file diff --git a/tools/GUIEditor/GUI Editor_vc11.vcxproj.filters b/tools/GUIEditor/GUI Editor_vc11.vcxproj.filters new file mode 100644 index 00000000..1d06fa46 --- /dev/null +++ b/tools/GUIEditor/GUI Editor_vc11.vcxproj.filters @@ -0,0 +1,88 @@ + + + + + {f6ad9df9-ebaa-4c0f-997b-c8101c1fc669} + + + {7fd14cb1-d2e7-4fd0-85c1-68fc9d1249f7} + + + {ab2c3f3a-1d99-4619-b5df-47fdd9449f3f} + + + {740a4255-37cc-4ac4-94e9-f2f0970491a8} + + + {a28a0b21-3336-432f-9759-ff2dc064874a} + + + + + gui + + + gui + + + gui + + + gui + + + gui\GUIAttributes + + + gui\Useful GUI Elements + + + io + + + + + + gui + + + gui + + + gui + + + gui + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\Useful GUI Elements + + + gui\Element Editors + + + io + + + \ No newline at end of file diff --git a/tools/GUIEditor/GUI Editor_vc12.vcxproj b/tools/GUIEditor/GUI Editor_vc12.vcxproj new file mode 100644 index 00000000..0b391be2 --- /dev/null +++ b/tools/GUIEditor/GUI Editor_vc12.vcxproj @@ -0,0 +1,217 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {853A396E-C031-4C26-A716-5B4E176BE11D} + GUI Editor + Win32Proj + GUIEditor + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + Neither + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib %(AdditionalOptions) + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Neither + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib %(AdditionalOptions) + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Full + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ../../bin/Win32-visualstudio/GUIEditor.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + true + true + + + + + + + Full + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ../../bin/Win32-visualstudio/GUIEditor.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {e08e042a-6c45-411b-92be-3cc31331019f} + false + + + + + + \ No newline at end of file diff --git a/tools/GUIEditor/GUI Editor_vc12.vcxproj.filters b/tools/GUIEditor/GUI Editor_vc12.vcxproj.filters new file mode 100644 index 00000000..1d06fa46 --- /dev/null +++ b/tools/GUIEditor/GUI Editor_vc12.vcxproj.filters @@ -0,0 +1,88 @@ + + + + + {f6ad9df9-ebaa-4c0f-997b-c8101c1fc669} + + + {7fd14cb1-d2e7-4fd0-85c1-68fc9d1249f7} + + + {ab2c3f3a-1d99-4619-b5df-47fdd9449f3f} + + + {740a4255-37cc-4ac4-94e9-f2f0970491a8} + + + {a28a0b21-3336-432f-9759-ff2dc064874a} + + + + + gui + + + gui + + + gui + + + gui + + + gui\GUIAttributes + + + gui\Useful GUI Elements + + + io + + + + + + gui + + + gui + + + gui + + + gui + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\Useful GUI Elements + + + gui\Element Editors + + + io + + + \ No newline at end of file diff --git a/tools/GUIEditor/GUI Editor_vc14.vcxproj b/tools/GUIEditor/GUI Editor_vc14.vcxproj new file mode 100644 index 00000000..e84a01b4 --- /dev/null +++ b/tools/GUIEditor/GUI Editor_vc14.vcxproj @@ -0,0 +1,217 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {853A396E-C031-4C26-A716-5B4E176BE11D} + GUI Editor + Win32Proj + GUIEditor + + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + Neither + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib %(AdditionalOptions) + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Neither + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib %(AdditionalOptions) + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Full + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ../../bin/Win32-visualstudio/GUIEditor.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + true + true + + + + + + + Full + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ../../bin/Win32-visualstudio/GUIEditor.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {e08e042a-6c45-411b-92be-3cc31331019f} + false + + + + + + \ No newline at end of file diff --git a/tools/GUIEditor/GUI Editor_vc14.vcxproj.filters b/tools/GUIEditor/GUI Editor_vc14.vcxproj.filters new file mode 100644 index 00000000..1d06fa46 --- /dev/null +++ b/tools/GUIEditor/GUI Editor_vc14.vcxproj.filters @@ -0,0 +1,88 @@ + + + + + {f6ad9df9-ebaa-4c0f-997b-c8101c1fc669} + + + {7fd14cb1-d2e7-4fd0-85c1-68fc9d1249f7} + + + {ab2c3f3a-1d99-4619-b5df-47fdd9449f3f} + + + {740a4255-37cc-4ac4-94e9-f2f0970491a8} + + + {a28a0b21-3336-432f-9759-ff2dc064874a} + + + + + gui + + + gui + + + gui + + + gui + + + gui\GUIAttributes + + + gui\Useful GUI Elements + + + io + + + + + + gui + + + gui + + + gui + + + gui + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\GUIAttributes + + + gui\Useful GUI Elements + + + gui\Element Editors + + + io + + + \ No newline at end of file diff --git a/tools/GUIEditor/GUIEditor_gcc.cbp b/tools/GUIEditor/GUIEditor_gcc.cbp new file mode 100644 index 00000000..b32df768 --- /dev/null +++ b/tools/GUIEditor/GUIEditor_gcc.cbp @@ -0,0 +1,78 @@ + + + + + + diff --git a/tools/GUIEditor/Makefile b/tools/GUIEditor/Makefile new file mode 100644 index 00000000..02f8189f --- /dev/null +++ b/tools/GUIEditor/Makefile @@ -0,0 +1,43 @@ +# Irrlicht Engine GUIEditor Makefile +Target = GUIEditor +Sources = CGUIAttributeEditor.cpp CGUIEditFactory.cpp CGUIEditWindow.cpp CGUIEditWorkspace.cpp CGUIPanel.cpp CGUITextureCacheBrowser.cpp CMemoryReadWriteFile.cpp main.cpp + +CPPFLAGS = -I../../include -I/usr/X11R6/include +CXXFLAGS = -Wall -O3 -ffast-math + +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif + +all: all_linux + +# target specific settings +all_linux: SYSTEM=Linux +all_linux: LDFLAGS = -L/usr/X11R6/lib$(LIBSELECT) -L../../lib/$(SYSTEM) -lIrrlicht -lGL -lXxf86vm -lXext -lX11 + +all_win32 clean_win32: SYSTEM=Win32-gcc +all_win32: LDFLAGS = -L../../lib/$(SYSTEM) -lIrrlicht -lopengl32 -lm + +# if you enable sound add the proper library for linking +#LDFLAGS += -lIrrKlang +#LDFLAGS += -laudiere +#LDFLAGS += -lSDL_mixer -lSDL + +all_win32 clean_win32: SUF=.exe +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = ../../bin/$(SYSTEM)/$(Target)$(SUF) + +OBJ = $(Sources:.cpp=.o) + +all_linux all_win32: $(OBJ) + $(warning Building...) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $(DESTPATH) $(LDFLAGS) + +clean: clean_linux clean_win32 + $(warning Cleaning...) + @$(RM) $(OBJ) + +clean_linux clean_win32: + @$(RM) $(DESTPATH) + +.PHONY: all all_win32 clean clean_linux clean_win32 diff --git a/tools/GUIEditor/main.cpp b/tools/GUIEditor/main.cpp new file mode 100644 index 00000000..d591c147 --- /dev/null +++ b/tools/GUIEditor/main.cpp @@ -0,0 +1,84 @@ +#include +#include "driverChoice.h" + +// include the gui creator element factory +#include "CGUIEditFactory.h" + +using namespace irr; +using namespace gui; + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +int main() +{ + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(false); + if (driverType==video::EDT_COUNT) + return 1; + + IrrlichtDevice *device = createDevice(driverType, core::dimension2du(800, 600)); + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + gui::IGUIEnvironment *env = device->getGUIEnvironment(); + + device->setResizable(true); + + /* + first we create the factory which can make new GUI elements + and register it with the gui environment. + */ + + IGUIElementFactory* factory = new CGUIEditFactory(env); + env->registerGUIElementFactory(factory); + // remember to drop since we created with a create call + factory->drop(); + + IGUISkin *skin = env->createSkin(EGST_WINDOWS_METALLIC); + env->setSkin(skin); + + IGUIFont *font = env->getFont("../../media/lucida.xml"); + if (font) + skin->setFont(font); + skin->drop(); + + // change transparency of skin + for (s32 i=0; igetSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i); + col.setAlpha(250); + env->getSkin()->setColor((gui::EGUI_DEFAULT_COLOR)i, col); + } + + /* + now we add the GUI Editor Workspace + */ + + env->addGUIElement("GUIEditor"); + + while(device->run()) + { + if (!device->isWindowMinimized()) + { + const core::dimension2d& screenSize = driver->getScreenSize(); + wchar_t caption[512]; + swprintf_irr(caption, 512, L"screen (%4u/%4u)", screenSize.Width, screenSize.Height); + device->setWindowCaption(caption); + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0,200,200,200)); + smgr->drawAll(); + env->drawAll(); + driver->endScene(); + } + + // be nice to CPU + device->sleep(10); + if (!device->isWindowActive()) + device->sleep(90); + } + + device->closeDevice(); + device->drop(); + + return 0; +} diff --git a/tools/IrrFontTool/newFontTool/CFontTool.cpp b/tools/IrrFontTool/newFontTool/CFontTool.cpp new file mode 100644 index 00000000..7c957ed9 --- /dev/null +++ b/tools/IrrFontTool/newFontTool/CFontTool.cpp @@ -0,0 +1,801 @@ +#include "CFontTool.h" +#include "IXMLWriter.h" + +using namespace irr; + +const int fontsizes[] = {4,6,8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,56,68,72,0}; + +inline u32 getTextureSizeFromSurfaceSize(u32 size) +{ + u32 ts = 0x01; + while(ts < size) + ts <<= 1; + + return ts; +} + +// windows specific +#ifdef _IRR_WINDOWS_ + + const DWORD charsets[] = { ANSI_CHARSET, DEFAULT_CHARSET, OEM_CHARSET, BALTIC_CHARSET, GB2312_CHARSET, CHINESEBIG5_CHARSET, + EASTEUROPE_CHARSET, GREEK_CHARSET, HANGUL_CHARSET, MAC_CHARSET, RUSSIAN_CHARSET, + SHIFTJIS_CHARSET, SYMBOL_CHARSET, TURKISH_CHARSET, VIETNAMESE_CHARSET, JOHAB_CHARSET, + ARABIC_CHARSET, HEBREW_CHARSET, THAI_CHARSET, 0}; + + const wchar_t *setnames[] = {L"ANSI", L"All Available", L"OEM", L"Baltic", L"Chinese Simplified", L"Chinese Traditional", + L"Eastern European", L"Greek", L"Hangul", L"Macintosh", L"Russian", + L"Japanese", L"Symbol", L"Turkish", L"Vietnamese", L"Johab", + L"Arabic", L"Hebrew", L"Thai", 0}; + + // callback for adding font names + int CALLBACK EnumFontFamExProc( ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *lpntme, + DWORD FontType, LPARAM lParam) + { + CFontTool* t = (CFontTool*) lParam; + t->FontNames.push_back( core::stringw(lpelfe->elfFullName)); + return 1; + } + + // + // Constructor + // + + CFontTool::CFontTool(IrrlichtDevice* device) : FontSizes(fontsizes), + Device(device), UseAlphaChannel(false), + // win specific + dc(0) + { + // init display context + dc = CreateDC(L"DISPLAY", L"DISPLAY", 0 ,0 ); + + // populate list of available character set names + for (int i=0; setnames[i] != 0; ++i) + CharSets.push_back( core::stringw(setnames[i])); + + selectCharSet(0); + } + + void CFontTool::selectCharSet(u32 currentCharSet) + { + if ( currentCharSet >= CharSets.size() ) + return; + + LOGFONTW lf; + lf.lfFaceName[0] = L'\0'; + lf.lfCharSet = (BYTE) charsets[currentCharSet]; + // HRESULT hr; // no error checking(!) + + // clear font list + FontNames.clear(); + + // create list of available fonts + EnumFontFamiliesExW( dc, (LPLOGFONTW) &lf, (FONTENUMPROCW) EnumFontFamExProc, (LPARAM) this, 0); + } + + bool CFontTool::makeBitmapFont(u32 fontIndex, u32 charsetIndex, s32 fontSize, u32 textureWidth, u32 textureHeight, bool bold, bool italic, bool aa, bool alpha) + { + if (fontIndex >= FontNames.size() || charsetIndex >= CharSets.size() ) + return false; + + UseAlphaChannel = alpha; + u32 currentImage = 0; + + // create the font + HFONT font = CreateFontW( + -MulDiv(fontSize, GetDeviceCaps(dc, LOGPIXELSY), 72), 0, + 0,0, + bold ? FW_BOLD : 0, + italic, 0,0, charsets[charsetIndex], 0,0, + aa ? ANTIALIASED_QUALITY : 0, + 0, FontNames[fontIndex].c_str() ); + + if (!font) + return false; + + SelectObject(dc, font); + SetTextAlign (dc,TA_LEFT | TA_TOP | TA_NOUPDATECP); + + // get rid of the current textures/images + for (u32 i=0; idrop(); + currentTextures.clear(); + + for (u32 i=0; idrop(); + currentImages.clear(); + + // clear current image mappings + CharMap.clear(); + // clear array + Areas.clear(); + + // get information about this font's unicode ranges. + s32 size = GetFontUnicodeRanges( dc, 0); + c8 *buf = new c8[size]; + LPGLYPHSET glyphs = (LPGLYPHSET)buf; + + GetFontUnicodeRanges( dc, glyphs); + + // s32 TotalCharCount = glyphs->cGlyphsSupported; + + s32 currentx=0, currenty=0, maxy=0; + + for (u32 range=0; range < glyphs->cRanges; range++) + { + WCRANGE* current = &glyphs->ranges[range]; + + //maxy=0; + + // loop through each glyph and write its size and position + for (s32 ch=current->wcLow; ch< current->wcLow + current->cGlyphs; ch++) + { + wchar_t currentchar = ch; + + if ( IsDBCSLeadByte((BYTE) ch)) + continue; // surrogate pairs unsupported + + // get the dimensions + SIZE size; + ABC abc; + GetTextExtentPoint32W(dc, ¤tchar, 1, &size); + SFontArea fa; + fa.underhang = 0; + fa.overhang = 0; + + if (GetCharABCWidthsW(dc, currentchar, currentchar, &abc)) // for unicode fonts, get overhang, underhang, width + { + size.cx = abc.abcB; // full font width (ignoring padding/underhang ) + fa.underhang = abc.abcA; // underhang/padding left - can also be negative (in which case it's overhang left) + fa.overhang = abc.abcC; // overhang/padding right - can also be negative (in which case it's underhand right) + + if (abc.abcB-abc.abcA+abc.abcC<1) + continue; // nothing of width 0 + } + if (size.cy < 1) + continue; + + //GetGlyphOutline(dc, currentchar, GGO_METRICS, &gm, 0, 0, 0); + + //size.cx++; size.cy++; + + // wrap around? + if (currentx + size.cx > (s32) textureWidth) + { + currenty += maxy; + currentx = 0; + if ((u32)(currenty + maxy) > textureHeight) + { + currentImage++; // increase Image count + currenty=0; + } + maxy = 0; + } + // add this char dimension to the current map + + fa.rectangle = core::rect(currentx, currenty, currentx + size.cx, currenty + size.cy); + fa.sourceimage = currentImage; + + CharMap.insert(currentchar, Areas.size()); + Areas.push_back( fa ); + + currentx += size.cx +1; + + if (size.cy+1 > maxy) + maxy = size.cy+1; + } + } + currenty += maxy; + + u32 lastTextureHeight = getTextureSizeFromSurfaceSize(currenty); + + // delete the glyph set + delete [] buf; + + currentImages.set_used(currentImage+1); + currentTextures.set_used(currentImage+1); + + for (currentImage=0; currentImage < currentImages.size(); ++currentImage) + { + core::stringc logmsg = "Creating image "; + logmsg += (s32) (currentImage+1); + logmsg += " of "; + logmsg += (s32) currentImages.size(); + Device->getLogger()->log(logmsg.c_str()); + // no need for a huge final texture + u32 texHeight = textureHeight; + if (currentImage == currentImages.size()-1 ) + texHeight = lastTextureHeight; + + // make a new bitmap + HBITMAP bmp = CreateCompatibleBitmap(dc, textureWidth, texHeight); + HDC bmpdc = CreateCompatibleDC(dc); + + LOGBRUSH lbrush; + lbrush.lbColor = RGB(0,0,0); + lbrush.lbHatch = 0; + lbrush.lbStyle = BS_SOLID; + + HBRUSH brush = CreateBrushIndirect(&lbrush); + HPEN pen = CreatePen(PS_NULL, 0, 0); + + HGDIOBJ oldbmp = SelectObject(bmpdc, bmp); + HGDIOBJ oldbmppen = SelectObject(bmpdc, pen); + HGDIOBJ oldbmpbrush = SelectObject(bmpdc, brush); + HGDIOBJ oldbmpfont = SelectObject(bmpdc, font); + + SetTextColor(bmpdc, RGB(255,255,255)); + + Rectangle(bmpdc, 0,0,textureWidth,texHeight); + SetBkMode(bmpdc, TRANSPARENT); + + // draw the letters... + + // iterate through the tree + core::map::Iterator it = CharMap.getIterator(); + while (!it.atEnd()) + { + s32 currentArea = (*it).getValue(); + wchar_t wch = (*it).getKey(); + // sloppy but I couldn't be bothered rewriting it + if (Areas[currentArea].sourceimage == currentImage) + { + // draw letter + s32 sx = Areas[currentArea].rectangle.UpperLeftCorner.X - Areas[currentArea].underhang; + TextOutW(bmpdc, sx, Areas[currentArea].rectangle.UpperLeftCorner.Y, &wch, 1); + + // if ascii font... + //SetPixel(bmpdc, Areas[currentArea].rectangle.UpperLeftCorner.X, Areas[currentArea].rectangle.UpperLeftCorner.Y, RGB(255,255,0));// left upper corner mark + } + it++; + } + + // copy the font bitmap into a new irrlicht image + BITMAP b; + PBITMAPINFO pbmi; + WORD cClrBits; + u32 cformat; + + // Retrieve the bitmap color format, width, and height. + GetObject(bmp, sizeof(BITMAP), (LPSTR)&b); + + // Convert the color format to a count of bits. + cClrBits = (WORD)(b.bmPlanes * b.bmBitsPixel); + + if (cClrBits <= 8) // we're not supporting these + cformat = -1; + else if (cClrBits <= 16) + cformat = video::ECF_A1R5G5B5; + else if (cClrBits <= 24) + cformat = video::ECF_R8G8B8; + else + cformat = video::ECF_A8R8G8B8; + + pbmi = (PBITMAPINFO) LocalAlloc(LPTR, + sizeof(BITMAPINFOHEADER)); + + // Initialize the fields in the BITMAPINFO structure. + + pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + pbmi->bmiHeader.biWidth = b.bmWidth; + pbmi->bmiHeader.biHeight = b.bmHeight; + pbmi->bmiHeader.biPlanes = b.bmPlanes; + pbmi->bmiHeader.biBitCount = b.bmBitsPixel; + + // If the bitmap is not compressed, set the BI_RGB flag. + pbmi->bmiHeader.biCompression = BI_RGB; + + // Compute the number of bytes in the array of color + // indices and store the result in biSizeImage. + // For Windows NT, the width must be DWORD aligned unless + // the bitmap is RLE compressed. This example shows this. + // For Windows 95/98/Me, the width must be WORD aligned unless the + // bitmap is RLE compressed. + pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8 + * pbmi->bmiHeader.biHeight; + // Set biClrImportant to 0, indicating that all of the + // device colors are important. + pbmi->bmiHeader.biClrImportant = 0; + + LPBYTE lpBits; // memory pointer + + PBITMAPINFOHEADER pbih = (PBITMAPINFOHEADER) pbmi; + lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage); + + GetDIBits(dc, bmp, 0, (WORD) pbih->biHeight, lpBits, pbmi, DIB_RGB_COLORS); + + // DEBUG- copy to clipboard + //OpenClipboard(hWnd); + //EmptyClipboard(); + //SetClipboardData(CF_BITMAP, bmp); + //CloseClipboard(); + + // flip bitmap + s32 rowsize = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8; + c8 *row = new c8[rowsize]; + for (s32 i=0; i < (pbih->biHeight/2); ++i) + { + // grab a row + memcpy(row, lpBits + (rowsize * i), rowsize); + // swap row + memcpy(lpBits + (rowsize * i), lpBits + ((pbih->biHeight-1 -i) * rowsize ) , rowsize); + memcpy(lpBits + ((pbih->biHeight-1 -i) * rowsize ), row , rowsize); + } + + bool ret = false; + + if (cformat == video::ECF_A8R8G8B8) + { + // in this case the font should have an alpha channel, but since windows doesn't draw one + // we have to set one manually by going through all the pixels.. *sigh* + + u8* m; + for (m = lpBits; m < lpBits + pbih->biSizeImage; m+=4) + { + if (UseAlphaChannel) + { + if (m[0] > 0) // pixel has colour + { + m[3]=m[0]; // set alpha + m[0]=m[1]=m[2] = 255; // everything else is full + } + } + else + m[3]=255; // all pixels are full alpha + } + + } + else if (cformat == video::ECF_A1R5G5B5) + { + u8* m; + for (m = lpBits; m < lpBits + pbih->biSizeImage; m+=2) + { + WORD *p = (WORD*)m; + if (m[0] > 0 || !UseAlphaChannel) // alpha should be set + *p |= 0x8000; // set alpha bit + } + } + else + { + cformat = -1; + } + + // make a texture from the image + if (cformat != -1) + { + // turn mip-mapping off + bool b = Device->getVideoDriver()->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); + currentImages[currentImage] = Device->getVideoDriver()->createImageFromData((video::ECOLOR_FORMAT)cformat, core::dimension2d(textureWidth,texHeight), (void*)lpBits); + Device->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS,b); + } + else + { + Device->getLogger()->log("Couldn't create font, your pixel format is unsupported."); + } + + // free memory and windows resources + // sloppy I know, but I only intended to create one image at first. + delete [] row; + LocalFree(pbmi); + GlobalFree(lpBits); + DeleteDC(bmpdc); + DeleteObject(brush); + DeleteObject(pen); + DeleteObject(bmp); + + if (currentImages[currentImage]) + { + // add texture + currentTextures[currentImage] = Device->getVideoDriver()->addTexture("GUIFontImage",currentImages[currentImage]); + currentTextures[currentImage]->grab(); + } + else + { + Device->getLogger()->log("Something went wrong, aborting."); + // drop all images + DeleteObject(font); + return false; + } + } // looping through each texture + DeleteObject(font); + return true; + } + +#else + + CFontTool::CFontTool(IrrlichtDevice *device) : FontSizes(fontsizes), Device(device), UseAlphaChannel(false) + { + if (!XftInitFtLibrary()) + { + core::stringc logmsg = "XFT not found\n"; + Device->getLogger()->log(logmsg.c_str()); + exit(EXIT_FAILURE); + } + + /* Get a list of the font foundries, storing them in a set to sort */ + std::set foundries; + Display* display = (Display*)Device->getVideoDriver()->getExposedVideoData().OpenGLLinux.X11Display; + XftFontSet* fonts = XftListFonts(display, DefaultScreen(display), 0, XFT_FOUNDRY, 0); + for (int i = 0; i < fonts->nfont; i++) + { + char *foundry; + XftPatternGetString(fonts->fonts[i], XFT_FOUNDRY, 0, &foundry); + core::stringw tmp(foundry); + foundries.insert(tmp); + } + XftFontSetDestroy(fonts); + + /* Copy the sorted list into the array */ + CharSets.clear(); + for (std::set::iterator i = foundries.begin(); i != foundries.end(); i++) + CharSets.push_back((*i).c_str()); + selectCharSet(0); + } + + /* Note: There must be some trick for using strings as pattern parameters to XftListFonts because + no matter how I specify a string, I end up with an intermittent segfault. Since XftFontList is + just calling FcFontList, that's what I'll do too since that works OK */ + void CFontTool::selectCharSet(u32 currentCharSet) + { + /* Get a list of the font families, storing them in a set to sort */ + char foundry[256]; + sprintf(&foundry[0],"%ls",CharSets[currentCharSet].c_str()); + std::set families; + XftPattern *pattern = FcPatternCreate(); + XftPatternAddString(pattern, FC_FOUNDRY, &foundry[0]); + XftObjectSet *objectset = FcObjectSetCreate(); + XftObjectSetAdd(objectset, XFT_FOUNDRY); + XftObjectSetAdd(objectset, XFT_FAMILY); + FcFontSet *fonts = FcFontList(NULL, pattern, objectset); + + for (int i = 0; i < fonts->nfont; i++) + { + char* ptr; + XftPatternGetString(fonts->fonts[i], XFT_FAMILY, 0, &ptr); + core::stringw family(ptr); + families.insert(family); + } + XftPatternDestroy(pattern); + FcObjectSetDestroy(objectset); + + /* Copy the sorted list into the array */ + FontNames.clear(); + for (std::set::iterator i = families.begin(); i != families.end(); i++) + FontNames.push_back((*i).c_str()); + } + + bool CFontTool::makeBitmapFont(u32 fontIndex, u32 charsetIndex, s32 fontSize, u32 textureWidth, u32 textureHeight, bool bold, bool italic, bool aa, bool alpha) + { + if (fontIndex >= FontNames.size() || charsetIndex >= CharSets.size() ) + return false; + + Display *display = (Display*) Device->getVideoDriver()->getExposedVideoData().OpenGLLinux.X11Display; + u32 screen = DefaultScreen(display); + Window win = RootWindow(display, screen); + Visual *visual = DefaultVisual(display, screen); + UseAlphaChannel = alpha; + u32 currentImage = 0; + + XftResult result; + XftPattern *request = XftPatternCreate(); + char foundry[256], family[256]; + sprintf(&foundry[0],"%ls",CharSets[charsetIndex].c_str()); + sprintf(&family[0],"%ls",FontNames[fontIndex].c_str()); + XftPatternAddString(request, XFT_FOUNDRY, &foundry[0]); + XftPatternAddString(request, XFT_FAMILY, &family[0]); + XftPatternAddInteger(request, XFT_PIXEL_SIZE, fontSize); + XftPatternAddInteger(request, XFT_WEIGHT, bold ? XFT_WEIGHT_BLACK : XFT_WEIGHT_LIGHT); + XftPatternAddInteger(request, XFT_SLANT, italic ? XFT_SLANT_ITALIC : XFT_SLANT_ROMAN); + XftPatternAddBool(request, XFT_ANTIALIAS, aa); + + /* Find the closest font that matches the user choices and open it and check if the returned + font has anti aliasing enabled by default, even if it wasn't requested */ + FcBool aaEnabled; + XftPattern *found = XftFontMatch(display, DefaultScreen(display), request, &result); + XftPatternGetBool(found, XFT_ANTIALIAS, 0, &aaEnabled); + aa = aaEnabled; + XftFont *font = XftFontOpenPattern(display, found); + + // get rid of the current textures/images + for (u32 i=0; idrop(); + currentTextures.clear(); + for (u32 i=0; idrop(); + currentImages.clear(); + CharMap.clear(); + Areas.clear(); + + /* Calculate the max height of the font. Annoyingly, it seems that the height property of the font + is the maximum height of any single character, but a string of characters, aligned along their + baselines, can exceed this figure. Because I don't know any better way of doing it, I'm going to + have to use the brute force method. + + Note: There will be a certain number of charters in a font, however they may not be grouped + consecutively, and could in fact be spread out with many gaps */ + u32 maxY = 0; + u32 charsFound = 0; + for (FT_UInt charCode = 0; charsFound < FcCharSetCount(font->charset); charCode++) + { + if (!XftCharExists(display, font, charCode)) + continue; + + charsFound++; + + XGlyphInfo extents; + XftTextExtents32(display, font, &charCode, 1, &extents); + if ((extents.xOff <= 0) && (extents.height <= 0)) + continue; + + /* Calculate the width and height, adding 1 extra pixel if anti aliasing is enabled */ + u32 chWidth = extents.xOff + (aa ? 1 : 0); + u32 chHeight = (font->ascent - extents.y + extents.height) + (aa ? 1 : 0); + if (chHeight > maxY) + maxY = chHeight; + + /* Store the character details here */ + SFontArea fontArea; + fontArea.rectangle = core::rect(0, 0, chWidth, chHeight); + CharMap.insert(charCode, Areas.size()); + Areas.push_back(fontArea); + } + core::stringc logmsg = "Found "; + logmsg += (s32) (CharMap.size() + 1); + logmsg += " characters"; + Device->getLogger()->log(logmsg.c_str()); + + /* Get the size of the chars and allocate them a position on a texture. If the next character that + is added would be outside the width or height of the texture, then a new texture is added */ + u32 currentX = 0, currentY = 0, rowY = 0; + for (core::map::Iterator it = CharMap.getIterator(); !it.atEnd(); it++) + { + s32 currentArea = (*it).getValue(); + SFontArea *fontArea = &Areas[currentArea]; + u32 chWidth = fontArea->rectangle.LowerRightCorner.X; + u32 chHeight = fontArea->rectangle.LowerRightCorner.Y; + + /* If the width of this char will exceed the textureWidth then start a new row */ + if ((currentX + chWidth) > textureWidth) + { + currentY += rowY; + currentX = 0; + + /* If the new row added to the texture exceeds the textureHeight then start a new texture */ + if ((currentY + rowY) > textureHeight) + { + currentImage++; + currentY = 0; + } + rowY = 0; + } + + /* Update the area with the current x and y and texture */ + fontArea->rectangle = core::rect(currentX, currentY, currentX + chWidth, currentY + chHeight); + fontArea->sourceimage = currentImage; + currentX += chWidth + 1; + if (chHeight + 1 > rowY) + rowY = chHeight + 1; + } + + /* The last row of chars and the last texture weren't accounted for in the loop, so add them here */ + currentY += rowY; + u32 lastTextureHeight = getTextureSizeFromSurfaceSize(currentY); + currentImages.set_used(currentImage + 1); + currentTextures.set_used(currentImage + 1); + + /* Initialise colours */ + XftColor colFore, colBack; + XRenderColor xFore = {0xffff, 0xffff, 0xffff, 0xffff}; + XRenderColor xBack = {0x0000, 0x0000, 0x0000, 0xffff}; + XftColorAllocValue(display, DefaultVisual(display, screen), DefaultColormap(display, screen), &xFore, &colFore); + XftColorAllocValue(display, DefaultVisual(display, screen), DefaultColormap(display, screen), &xBack, &colBack); + + /* Create a pixmap that is large enough to hold any character in the font */ + Pixmap pixmap = XCreatePixmap(display, win, textureWidth, maxY, DefaultDepth(display, screen)); + XftDraw *draw = XftDrawCreate(display, pixmap, visual, DefaultColormap(display, screen)); + + /* Render the chars */ + for (currentImage = 0; currentImage < currentImages.size(); ++currentImage) + { + core::stringc logmsg = "Creating image "; + logmsg += (s32) (currentImage+1); + logmsg += " of "; + logmsg += (s32) currentImages.size(); + Device->getLogger()->log(logmsg.c_str()); + + /* The last texture that is saved is vertically shrunk to fit the characters drawn on it */ + u32 texHeight = textureHeight; + if (currentImage == currentImages.size() - 1) + texHeight = lastTextureHeight; + + /* The texture that holds this "page" of characters */ + 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++) + { + FcChar32 wch = (*it).getKey(); + s32 currentArea = (*it).getValue(); + if (Areas[currentArea].sourceimage == currentImage) + { + SFontArea *fontArea = &Areas[currentArea]; + u32 chWidth = fontArea->rectangle.LowerRightCorner.X - fontArea->rectangle.UpperLeftCorner.X; + u32 chHeight = fontArea->rectangle.LowerRightCorner.Y - fontArea->rectangle.UpperLeftCorner.Y; + + /* Draw the glyph onto the pixmap */ + XGlyphInfo extents; + XftDrawRect(draw, &colBack, 0, 0, chWidth, chHeight); + XftTextExtents32(display, font, &wch, 1, &extents); + XftDrawString32(draw, &colFore, font, extents.x, extents.y, &wch, 1); + + /* Convert the pixmap into an image, then copy it onto the Irrlicht texture, pixel by pixel. + There's bound to be a faster way, but this is adequate */ + u32 xDest = fontArea->rectangle.UpperLeftCorner.X; + u32 yDest = fontArea->rectangle.UpperLeftCorner.Y + font->ascent - extents.y; + XImage *image = XGetImage(display, pixmap, 0, 0, chWidth, chHeight, 0xffffff, XYPixmap); + if (image) + { + for (u32 ySrc = 0; ySrc < chHeight; ySrc++) + for (u32 xSrc = 0; xSrc < chWidth; xSrc++) + { + /* Get the pixel colour and break it down into rgb components */ + u32 col = XGetPixel(image, xSrc, ySrc); + u32 a = 255; + u32 r = col & visual->red_mask; + u32 g = col & visual->green_mask; + u32 b = col & visual->blue_mask; + while (r > 0xff) r >>= 8; + while (g > 0xff) g >>= 8; + while (b > 0xff) b >>= 8; + + /* To make the background transparent, set the colour to 100% white and the alpha to + the average of the three rgb colour components to maintain the anti-aliasing */ + if (alpha) + { + a = (r + g + b) / 3; + r = 255; + g = 255; + b = 255; + } + currentImages[currentImage]->setPixel(xDest + xSrc,yDest + ySrc,video::SColor(a,r,g,b)); + } + image->f.destroy_image(image); + } + } + } + + /* Add the texture to the list */ + currentTextures[currentImage] = Device->getVideoDriver()->addTexture("GUIFontImage",currentImages[currentImage]); + currentTextures[currentImage]->grab(); + } + + XftColorFree (display, visual, DefaultColormap(display, screen), &colFore); + XftColorFree (display, visual, DefaultColormap(display, screen), &colBack); + XftFontClose(display,font); + XftPatternDestroy(request); + XftDrawDestroy(draw); + XFreePixmap(display, pixmap); + return true; + } +#endif + + CFontTool::~CFontTool() + { +#ifdef _IRR_WINDOWS_ + // destroy display context + if (dc) + DeleteDC(dc); +#endif + + // drop textures+images + for (u32 i=0; idrop(); + currentTextures.clear(); + + for (u32 i=0; idrop(); + currentImages.clear(); + } + +bool CFontTool::saveBitmapFont(const c8 *filename, const c8* format) +{ + if (currentImages.size() == 0) + { + Device->getLogger()->log("No image data to write, aborting."); + return false; + } + + core::stringc fn = filename; + core::stringc imagename = filename; + fn += ".xml"; + + io::IXMLWriter *writer = Device->getFileSystem()->createXMLWriter(fn.c_str()); + + // header and line breaks + writer->writeXMLHeader(); + writer->writeLineBreak(); + + // write information + writer->writeElement(L"font", false, L"type", L"bitmap"); + writer->writeLineBreak(); + writer->writeLineBreak(); + + // write images and link to them + for (u32 i=0; igetVideoDriver()->writeImageToFile(currentImages[i],imagename.c_str()); + + writer->writeElement(L"Texture", true, + L"index", core::stringw(i).c_str(), + L"filename", core::stringw(imagename.c_str()).c_str(), + L"hasAlpha", UseAlphaChannel ? L"true" : L"false"); + writer->writeLineBreak(); + } + + writer->writeLineBreak(); + + // write each character + core::map::Iterator it = CharMap.getIterator(); + while (!it.atEnd()) + { + SFontArea &fa = Areas[(*it).getValue()]; + + wchar_t c[2]; + c[0] = (*it).getKey(); + c[1] = L'\0'; + core::stringw area, under, over, image; + area = core::stringw(fa.rectangle.UpperLeftCorner.X); + area += L", "; + area += fa.rectangle.UpperLeftCorner.Y; + area += L", "; + area += fa.rectangle.LowerRightCorner.X; + area += L", "; + area += fa.rectangle.LowerRightCorner.Y; + + core::array names; + core::array values; + names.clear(); + values.clear(); + // char + names.push_back(core::stringw(L"c")); + values.push_back(core::stringw(c)); + // image number + if (fa.sourceimage != 0) + { + image = core::stringw(fa.sourceimage); + names.push_back(core::stringw(L"i")); + values.push_back(image); + } + // rectangle + names.push_back(core::stringw(L"r")); + values.push_back(area); + + if (fa.underhang != 0) + { + under = core::stringw(fa.underhang); + names.push_back(core::stringw(L"u")); + values.push_back(under); + } + if (fa.overhang != 0) + { + over = core::stringw(fa.overhang); + names.push_back(core::stringw(L"o")); + values.push_back(over); + } + writer->writeElement(L"c", true, names, values); + + writer->writeLineBreak(); + it++; + } + + writer->writeClosingTag(L"font"); + + writer->drop(); + + Device->getLogger()->log("Bitmap font saved."); + + return true; +} diff --git a/tools/IrrFontTool/newFontTool/CFontTool.h b/tools/IrrFontTool/newFontTool/CFontTool.h new file mode 100644 index 00000000..5a35938b --- /dev/null +++ b/tools/IrrFontTool/newFontTool/CFontTool.h @@ -0,0 +1,78 @@ +#ifndef __IRR_FONT_TOOL_INCLUDED__ +#define __IRR_FONT_TOOL_INCLUDED__ + + +#include "irrlicht.h" + +#if defined(_IRR_WINDOWS_) + #ifdef _MBCS + #undef _MBCS + #endif + + #define UNICODE + #define _WIN32_WINNT 0x0500 + #include "windows.h" +#else + #ifdef _IRR_COMPILE_WITH_X11_ + #include + #endif + #include + #include +#endif + + +namespace irr { + class CFontTool : public irr::IReferenceCounted + { + public: + CFontTool(irr::IrrlichtDevice* device); + ~CFontTool(); + + virtual bool makeBitmapFont(u32 fontIndex, u32 charsetIndex, + s32 fontSize, u32 texturewidth, u32 textureHeight, + bool bold, bool italic, bool aa, bool alpha); + + virtual bool saveBitmapFont(const c8* filename, const c8* format); + + virtual void selectCharSet(u32 currentCharSet); + + struct SFontArea + { + SFontArea() : rectangle(), underhang(0), overhang(0), sourceimage(0) {} + core::rect rectangle; + s32 underhang; + s32 overhang; + u32 sourceimage; + }; + + /* struct SFontMap + { + SFontMap() : areas(), start(0), count(0) {} + core::array< SFontArea > areas; + s32 start; + s32 count; + };*/ + + + + core::array FontNames; + core::array CharSets; + //core::array Mappings; + core::array Areas; + core::map CharMap; + + core::array currentTextures; + core::array currentImages; + const int *FontSizes; + IrrlichtDevice *Device; + + bool UseAlphaChannel; + + // windows + #ifdef _IRR_WINDOWS_ + HDC dc; + #endif + + }; +} +#endif // __IRR_FONT_TOOL_INCLUDED__ diff --git a/tools/IrrFontTool/newFontTool/CVectorFontTool.h b/tools/IrrFontTool/newFontTool/CVectorFontTool.h new file mode 100644 index 00000000..aac5dbcc --- /dev/null +++ b/tools/IrrFontTool/newFontTool/CVectorFontTool.h @@ -0,0 +1,1199 @@ +/* + Vector font tool - Gaz Davidson December 2006-2012 + + 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... + + And I failed! This is a collection of the ugliest, bloated, most inneficient algorithms + i've ever written, but its kinda working so I'm not changing it. +*/ + +#ifndef __VECTOR_FONT_TOOL_INCLUDED__ +#define __VECTOR_FONT_TOOL_INCLUDED__ + +#include "irrlicht.h" +#include "CFontTool.h" +#include + +using namespace irr; +using namespace video; + +struct STriangleList +{ + core::array positions; + core::array indexes; + + // for adding one triangle list to another, + // these triangles share positions, but dont share triangles + STriangleList& operator+=(STriangleList &other) + { + core::matrix4 m; + core::array map; + map.set_used(other.positions.size()); + + for (u32 i=0; i positions; + + bool isMember(s32 x, s32 y) + { + for (u32 i=0; i h1((f32)(positions[i-1].X - positions[i].X),(f32)(positions[i-1].Y - positions[i].Y)), + h2((f32)(positions[i].X - positions[i+1].X),(f32)(positions[i].Y - positions[i+1].Y)); + h1.normalize(); + h2.normalize(); + + if (h1==h2) // erase the current point + positions.erase(i--); + } + + // level 1- if point1 points at point3, we can skip point2 + // level 2+ allow a deviation of level-1 + + } + + }; + + // contains an array of lines for triangulation + struct SLineList + { + core::array lines; + SLineList() : lines() { } + void addEdge(const SEdge &edge) + { + // adds lines to the buffer + for (u32 i=1; i 0 && + lb.getPointOrientation(l2.start) > 0 && + lc.getPointOrientation(l2.start) > 0) + return true; + //if (la.getPointOrientation(l2.start) < 0 && + // lb.getPointOrientation(l2.start) < 0 && + // lc.getPointOrientation(l2.start) < 0) + // return true; + + core::vector2df out; + //if (la.intersectWith(l2,out)) + // if (out != la.start && out != la.end && + // out != l2.start && out != l2.end) + // return true; + if (lb.intersectWith(l2,out)) + if (!out.equals(lb.start) && !out.equals(lb.end) && + !out.equals(l2.start) && !out.equals(l2.end)) + return true; + if (lc.intersectWith(l2,out)) + if (!out.equals(lc.start) && !out.equals(lc.end) && + !out.equals(l2.start) && !out.equals(l2.end)) + return true; + + // my shit intersection code only works with lines in certain directions :( + if (l2.intersectWith(lb,out)) + if (!out.equals(lb.start) && !out.equals(lb.end) && + !out.equals(l2.start) && !out.equals(l2.end)) + return true; + if (l2.intersectWith(lc,out)) + if (!out.equals(lc.start) && !out.equals(lc.end) && + !out.equals(l2.start) && !out.equals(l2.end)) + return true; + + + if (lb.isPointOnLine(l2.start) && l2.start != lb.start && l2.start != lb.end) + return true; + if (lc.isPointOnLine(l2.start) && l2.start != lc.start && l2.start != lc.end) + return true; + + } + return false; + } + }; + + // an area of adjacent pixels + struct SPixelGroup + { + SPixelGroup(IrrlichtDevice *device) : triangles(), pixelWidth(0), pixelHeight(0), + Device(device) {} + + core::array pixels; + core::array edges; + STriangleList triangles; + core::array ll; + core::array isMemberCache; + s32 pixelWidth; + s32 pixelHeight; + IrrlichtDevice *Device; + + void triangulate() + { + + // find edges in this group + makeEdges(); + + // triangulate the group + makeTriangles(); + + } + + void drawTriangle( core::line2df line, core::vector2df point) + { + //const u32 endt = Device->getTimer()->getTime() + t; + f32 scale = 5; + + + //while(Device->getTimer()->getTime() < endt ) + //{ + Device->run(); + Device->getVideoDriver()->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0,0,0,0)); + for (u32 v=0;vgetVideoDriver()->draw2DLine(st,en, SColor(255,255,255,255)); + } + // draw this triangle + const core::position2di st((s32)(line.start.X*scale)+50, (s32)(line.start.Y*scale)+50); + const core::position2di en((s32)(line.end.X*scale)+50, (s32)(line.end.Y*scale)+50); + const core::position2di p((s32)(point.X*scale)+50, (s32)(point.Y*scale)+50); + Device->getVideoDriver()->draw2DLine(st,en, SColor(255,255,0,0)); + Device->getVideoDriver()->draw2DLine(en,p, SColor(255,0,255,0)); + Device->getVideoDriver()->draw2DLine(p,st, SColor(255,0,0,255)); + + Device->getVideoDriver()->endScene(); + //} + } + + void makeTriangles() + { + // make lines from edges, because they're easier to deal with + ll.clear(); + for (u32 i=0; i < edges.size(); ++i) + { + SLineList l; + l.addEdge(edges[i]); + ll.push_back(l); + } + // add an extra one for inside edges + SLineList innerlines; + ll.push_back(innerlines); + + // loop through each edge and make triangles + for (u32 i=0; ibestScore) + { + bestScore = score; + bestEdge = k; + bestPoint = j; + } + } + // hopefully we found one + if (bestEdge >= 0 && bestPoint >= 0 && bestScore >= 0.0f) + { + //assert(bestEdge >= 0 && bestPoint >= 0); + //assert(bestScore >= 0.0f); + + core::vector2df point(ll[bestEdge].lines[bestPoint].start.X, ll[bestEdge].lines[bestPoint].start.Y); + + // add it to the triangles list + triangles.add(currentLine.start, currentLine.end, point); + + // add inner lines to the line buffer, but only if they arent in others + + core::line2df la(point,currentLine.start); + core::line2df lb(currentLine.end,point); + + bool found = false; + for (u32 lineno=0;lineno= 3); + + // all edges should be closed + assert(edges[i].positions[0] == edges[i].positions[edges[i].positions.size()-1] ); + } + } + + // adds a line to the edges arrays + void addToEdges(s32 x1, s32 y1, s32 x2, s32 y2) + { + bool found=false; + // loop through each edge + for (u32 i=0; ipixelWidth || y>pixelHeight || x<0 || y<0) + return false; + else + return isMemberCache[pixelWidth*y + x]; + } + + void refreshIsMemberCache() + { + isMemberCache.clear(); + pixelWidth=0; pixelHeight=0; + for (u32 i=0; ipixelWidth) pixelWidth=pixels[i].X; + if (pixels[i].Y>pixelHeight) pixelHeight=pixels[i].Y; + } + pixelWidth+=2; pixelHeight+=2; + isMemberCache.set_used(pixelWidth*pixelHeight+1); + for (u32 i=0; igetTimer()->getTime(); + const u32 endt = stt + t; + + while(device->getTimer()->getTime() < endt ) + { + const f32 phase = f32((device->getTimer()->getTime()-stt) % 500) / 500.0f; + + device->run(); + device->getVideoDriver()->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0,0,0,0)); + for (u32 g=0;ggetVideoDriver()->draw2DLine(st,en); + device->getVideoDriver()->draw2DLine(st,ep,video::SColor(255,255,0,0) ); + } + device->getVideoDriver()->endScene(); + } + } + + void drawTriangles(IrrlichtDevice *device, u32 t, s32 scale) + { + const u32 stt = device->getTimer()->getTime(); + const u32 endt = stt + t; + + while(device->getTimer()->getTime() < endt ) + { + const f32 phase = f32((device->getTimer()->getTime()-stt) % 500) / 500.0f; + + device->run(); + device->getVideoDriver()->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0,0,0,0)); + for (u32 g=0;ggetVideoDriver()->draw2DLine(st,en, SColor(255,255,0,0)); + st = core::position2di((s32)(t.positions[t.indexes[v+1]].X*scale)+50,(s32)(t.positions[t.indexes[v+1]].Y*scale)+50); + en = core::position2di((s32)(t.positions[t.indexes[v+2]].X*scale)+50,(s32)(t.positions[t.indexes[v+2]].Y*scale)+50); + device->getVideoDriver()->draw2DLine(st,en, SColor(255,0,255,0)); + st = core::position2di((s32)(t.positions[t.indexes[v+2]].X*scale)+50,(s32)(t.positions[t.indexes[v+2]].Y*scale)+50); + en = core::position2di((s32)(t.positions[t.indexes[v+0]].X*scale)+50,(s32)(t.positions[t.indexes[v+0]].Y*scale)+50); + device->getVideoDriver()->draw2DLine(st,en, SColor(255,0,0,255)); + } + device->getVideoDriver()->endScene(); + } + } + + void drawTriLines(IrrlichtDevice *device, u32 t, s32 scale) + { + const u32 endt = device->getTimer()->getTime() + t; + + while(device->getTimer()->getTime() < endt ) + { + device->run(); + device->getVideoDriver()->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0,0,0,0)); + for (u32 g=0;ggetVideoDriver()->draw2DLine(st,en, SColor(255,255,0,0)); + } + + device->getVideoDriver()->endScene(); + } + } + void drawTri3D(IrrlichtDevice *device, u32 t) + { + for (u32 g=0;g verts; + verts.clear(); + for(u32 v=0; v< t.positions.size(); ++v) + { + verts.push_back(S3DVertex( + -t.positions[v].X, -t.positions[v].Y, -100, + 0,0,1,SColor(255,255,255,255),0,0)); + } + + device->getVideoDriver()->drawIndexedTriangleList(verts.pointer(),verts.size(),t.indexes.pointer(), t.indexes.size()/3 ); + } + } + + + // process all pixels + void findGroups() + { + for (int y=0; y0) // look one behind + { + grp = getRef(x-1,y); + if (grp) found=true; + } + if (y>0) // look above + { + if (x>0) // top left + { + g = getRef(x-1,y-1); + + if (g) + { + if (found) + { + mergeGroups(grp, g); + } + else + { + grp = g; + found = true; + } + } + } + + if (x groups; + core::array groupRefs; + core::array refbuffer; + bool *mem; + IrrlichtDevice *Device; +}; + +// creates a simple vector font from a bitmap from the font tool +class CVectorFontTool +{ +public: + CVectorFontTool(CFontTool *fonttool) : + triangulator(0), FontTool(fonttool), + letterHeight(0), letterWidth(0), triangles() + { + core::map::Iterator it = FontTool->CharMap.getIterator(); + + while(!it.atEnd()) + { + CFontTool::SFontArea &fa = FontTool->Areas[(*it).getValue()]; + + if (fa.rectangle.getWidth() > letterWidth) + letterWidth = fa.rectangle.getWidth(); + if (fa.rectangle.getHeight() > letterHeight) + letterHeight = fa.rectangle.getHeight(); + + it++; + } + + // number of verts is one more than number of pixels because it's a grid of squares + letterWidth++; + letterHeight++; + + // create image memory + imagedata.set_used(letterWidth*letterHeight); + + // create vertex list, set position etc + verts.set_used(letterWidth*letterHeight); + for (s32 y=0; yCharMap.getIterator(); + while(!it.atEnd()) + { + addChar((*it).getKey()); + it++; + } + } + + ~CVectorFontTool() + { + if (triangulator) + delete triangulator; + } + + void addChar(wchar_t thischar) + { + const s32 area = FontTool->CharMap[thischar]; + const CFontTool::SFontArea &fa = FontTool->Areas[area]; + + const s32 img = fa.sourceimage; + const core::rect& r = fa.rectangle; + + // init image memory + IImage *image = FontTool->currentImages[img]; + for (u32 i=0; i < imagedata.size(); ++i) + imagedata[i] = false; + for (s32 y=r.UpperLeftCorner.Y; y < r.LowerRightCorner.Y; ++y) + { + for (s32 x=r.UpperLeftCorner.X; x < r.LowerRightCorner.X ; ++x) + if (image->getPixel(x,y).getBlue() > 0) + { + imagedata[letterWidth*(y-r.UpperLeftCorner.Y) +(x-r.UpperLeftCorner.X)] = true; + } + } + + // get shape areas + triangulator = new CGroupFinder(imagedata.pointer(), letterWidth, letterHeight, FontTool->Device ); + + wprintf(L"Created character '%c' in texture %d\n", thischar, img ); + + //floodfill->drawEdges(FontTool->Device, 500, 3); + //floodfill->drawTriangles(FontTool->Device, 500,30); + //floodfill->drawTriLines(FontTool->Device, 200,3); + + /* + if (area==32 && map == 0) + { + scene::ISceneManager *smgr = FontTool->Device->getSceneManager(); + smgr->addCameraSceneNodeFPS(); + while(FontTool->Device->run()) + { + //floodfill->drawEdges(FontTool->Device, 100, 30); + FontTool->Device->getVideoDriver()->beginScene(true, true, video::SColor(0,200,200,200)); + smgr->drawAll(); + floodfill->drawTri3D(FontTool->Device, 100); + FontTool->Device->getVideoDriver()->endScene(); + } + }*/ + + u32 lastind = triangles.indexes.size(); + + // loop through each shape and add it to the current character... + for (u32 i=0; i < triangulator->groups.size(); ++i) + triangles += triangulator->groups[i].triangles; + + // add character details + charstarts.push_back(lastind); + charlengths.push_back(triangles.indexes.size() - lastind); + chars.push_back(thischar); + } + + bool saveVectorFont(const c8 *filename, const c8 *formatname) + { + IrrlichtDevice *Device = FontTool->Device; + + if (triangles.indexes.size() == 0) + { + Device->getLogger()->log("No vector data to write, aborting."); + return false; + } + + core::stringc fn = filename; + + if (core::stringc(formatname) == core::stringc("xml")) + { + fn += ".xml"; + io::IXMLWriter *writer = FontTool->Device->getFileSystem()->createXMLWriter(fn.c_str()); + + // header and line breaks + writer->writeXMLHeader(); + writer->writeLineBreak(); + + // write info header + writer->writeElement(L"font", false, L"type", L"vector"); + writer->writeLineBreak(); + writer->writeLineBreak(); + + // write each letter + + for (u32 n=0; nCharMap[chars[n]]; + CFontTool::SFontArea &fa = FontTool->Areas[i]; + wchar_t c[2]; + c[0] = chars[n]; + c[1] = L'\0'; + core::stringw area, under, over; + area = core::stringw(fa.rectangle.LowerRightCorner.X- + fa.rectangle.UpperLeftCorner.X); + area += L", "; + area += fa.rectangle.LowerRightCorner.Y- + fa.rectangle.UpperLeftCorner.Y; + + + core::array names; + core::array values; + names.clear(); + values.clear(); + // char + names.push_back(core::stringw(L"c")); + values.push_back(core::stringw(c)); + + // width+height + names.push_back(core::stringw(L"wh")); + values.push_back(area); + + // start + names.push_back(core::stringw(L"st")); + values.push_back(core::stringw(charstarts[n])); + // length + names.push_back(core::stringw(L"len")); + values.push_back(core::stringw(charlengths[n])); + + if (fa.underhang != 0) + { + under = core::stringw(fa.underhang); + names.push_back(core::stringw(L"u")); + values.push_back(under); + } + if (fa.overhang != 0) + { + over = core::stringw(fa.overhang); + names.push_back(core::stringw(L"o")); + values.push_back(over); + } + writer->writeElement(L"c", true, names, values); + + writer->writeLineBreak(); + } + + // write vertex data + core::stringw data, count; + data = L""; + count = core::stringw(triangles.positions.size()); + for (u32 i=0; iwriteElement(L"Vertices", true, L"count", count.c_str(), L"data", data.c_str()); + writer->writeLineBreak(); + + // write index list + data = L""; + count = core::stringw(triangles.indexes.size()); + for (u32 i=0; iwriteElement(L"Indices", true, L"count", count.c_str(), L"data", data.c_str()); + writer->writeLineBreak(); + + writer->writeClosingTag(L"font"); + + writer->drop(); + + Device->getLogger()->log("Font saved."); + return true; + + } + else if (core::stringc(formatname) == core::stringc("bin")) + { + FontTool->Device->getLogger()->log("binary fonts not supported yet, sorry"); + return false; + } + else + { + FontTool->Device->getLogger()->log("unsupported file format, unable to save vector font"); + return false; + } + } + + S3DVertex& getVert(s32 x, s32 y) { return verts[letterWidth*y +x]; } + + core::array verts; + core::array inds; + core::array imagedata; + + core::array charstarts; // start position of each char + core::array charlengths; // index count + core::array chars; // letters + + CGroupFinder* triangulator; + CFontTool* FontTool; + + s32 letterHeight; + s32 letterWidth; + + STriangleList triangles; +}; + +#endif // __VECTOR_FONT_TOOL_INCLUDED__ + diff --git a/tools/IrrFontTool/newFontTool/Makefile b/tools/IrrFontTool/newFontTool/Makefile new file mode 100644 index 00000000..cce91457 --- /dev/null +++ b/tools/IrrFontTool/newFontTool/Makefile @@ -0,0 +1,38 @@ +# 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 = FontTool +Sources = CFontTool.cpp main.cpp + +# general compiler settings +CPPFLAGS = -I../../../include -I/usr/X11R6/include -I/usr/include/freetype2/ +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 -lXft -lfontconfig +all_linux clean_linux: SYSTEM=Linux +all_win32: LDFLAGS = -L../../../lib/Win32-gcc -lIrrlicht -lgdi32 -lopengl32 -lglu32 -lm +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/tools/IrrFontTool/newFontTool/irrFontTool_vc10.vcxproj b/tools/IrrFontTool/newFontTool/irrFontTool_vc10.vcxproj new file mode 100644 index 00000000..d031deca --- /dev/null +++ b/tools/IrrFontTool/newFontTool/irrFontTool_vc10.vcxproj @@ -0,0 +1,207 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + FontTool + {4D53E40F-37E3-42B1-8848-F4C6F8313A17} + Win32Proj + + + + Application + MultiByte + true + Windows7.1SDK + + + Application + MultiByte + true + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\..\bin\Win32-VisualStudio\ + ..\..\..\bin\Win64-VisualStudio\ + true + true + ..\..\..\bin\Win32-VisualStudio\ + ..\..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ../../../include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib gdi32.lib %(AdditionalOptions) + ../../../bin/Win32-visualstudio/FontTool.exe + ../../../lib/Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + ../../../include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib gdi32.lib %(AdditionalOptions) + ../../../bin/Win64-visualstudio/FontTool.exe + ../../../lib/Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + MaxSpeed + false + ../../../include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib gdi32.lib %(AdditionalOptions) + ../../../bin/Win32-visualstudio/FontTool.exe + ../../../lib/Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + MaxSpeed + false + ../../../include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib gdi32.lib %(AdditionalOptions) + ../../../bin/Win64-visualstudio/FontTool.exe + ../../../lib/Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + + + + + + + {e08e042a-6c45-411b-92be-3cc31331019f} + false + + + + + + \ No newline at end of file diff --git a/tools/IrrFontTool/newFontTool/irrFontTool_vc11.vcxproj b/tools/IrrFontTool/newFontTool/irrFontTool_vc11.vcxproj new file mode 100644 index 00000000..dc2702b1 --- /dev/null +++ b/tools/IrrFontTool/newFontTool/irrFontTool_vc11.vcxproj @@ -0,0 +1,207 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + FontTool + {4D53E40F-37E3-42B1-8848-F4C6F8313A17} + Win32Proj + + + + Application + MultiByte + true + Windows7.1SDK + + + Application + MultiByte + true + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\..\bin\Win32-VisualStudio\ + ..\..\..\bin\Win64-VisualStudio\ + true + true + ..\..\..\bin\Win32-VisualStudio\ + ..\..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ../../../include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib gdi32.lib %(AdditionalOptions) + ../../../bin/Win32-visualstudio/FontTool.exe + ../../../lib/Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + ../../../include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib gdi32.lib %(AdditionalOptions) + ../../../bin/Win64-visualstudio/FontTool.exe + ../../../lib/Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + MaxSpeed + false + ../../../include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib gdi32.lib %(AdditionalOptions) + ../../../bin/Win32-visualstudio/FontTool.exe + ../../../lib/Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + MaxSpeed + false + ../../../include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib gdi32.lib %(AdditionalOptions) + ../../../bin/Win64-visualstudio/FontTool.exe + ../../../lib/Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + + + + + + + {e08e042a-6c45-411b-92be-3cc31331019f} + false + + + + + + \ No newline at end of file diff --git a/tools/IrrFontTool/newFontTool/irrFontTool_vc12.vcxproj b/tools/IrrFontTool/newFontTool/irrFontTool_vc12.vcxproj new file mode 100644 index 00000000..ca538409 --- /dev/null +++ b/tools/IrrFontTool/newFontTool/irrFontTool_vc12.vcxproj @@ -0,0 +1,207 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + FontTool + {4D53E40F-37E3-42B1-8848-F4C6F8313A17} + Win32Proj + + + + Application + MultiByte + true + Windows7.1SDK + + + Application + MultiByte + true + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\..\bin\Win32-VisualStudio\ + ..\..\..\bin\Win64-VisualStudio\ + true + true + ..\..\..\bin\Win32-VisualStudio\ + ..\..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ../../../include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib gdi32.lib %(AdditionalOptions) + ../../../bin/Win32-visualstudio/FontTool.exe + ../../../lib/Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + ../../../include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib gdi32.lib %(AdditionalOptions) + ../../../bin/Win64-visualstudio/FontTool.exe + ../../../lib/Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + MaxSpeed + false + ../../../include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib gdi32.lib %(AdditionalOptions) + ../../../bin/Win32-visualstudio/FontTool.exe + ../../../lib/Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + MaxSpeed + false + ../../../include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib gdi32.lib %(AdditionalOptions) + ../../../bin/Win64-visualstudio/FontTool.exe + ../../../lib/Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + + + + + + + {e08e042a-6c45-411b-92be-3cc31331019f} + false + + + + + + \ No newline at end of file diff --git a/tools/IrrFontTool/newFontTool/irrFontTool_vc14.vcxproj b/tools/IrrFontTool/newFontTool/irrFontTool_vc14.vcxproj new file mode 100644 index 00000000..a63ae48b --- /dev/null +++ b/tools/IrrFontTool/newFontTool/irrFontTool_vc14.vcxproj @@ -0,0 +1,207 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + FontTool + {4D53E40F-37E3-42B1-8848-F4C6F8313A17} + Win32Proj + + + + Application + MultiByte + true + v140 + + + Application + MultiByte + true + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\..\bin\Win32-VisualStudio\ + ..\..\..\bin\Win64-VisualStudio\ + true + true + ..\..\..\bin\Win32-VisualStudio\ + ..\..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ../../../include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib gdi32.lib %(AdditionalOptions) + ../../../bin/Win32-visualstudio/FontTool.exe + ../../../lib/Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + ../../../include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib gdi32.lib %(AdditionalOptions) + ../../../bin/Win64-visualstudio/FontTool.exe + ../../../lib/Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + MaxSpeed + false + ../../../include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib gdi32.lib %(AdditionalOptions) + ../../../bin/Win32-visualstudio/FontTool.exe + ../../../lib/Win32-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + MaxSpeed + false + ../../../include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib gdi32.lib %(AdditionalOptions) + ../../../bin/Win64-visualstudio/FontTool.exe + ../../../lib/Win64-visualstudio;%(AdditionalLibraryDirectories) + false + Console + true + true + + + + + + + + + + + + + + + + + {e08e042a-6c45-411b-92be-3cc31331019f} + false + + + + + + \ No newline at end of file diff --git a/tools/IrrFontTool/newFontTool/main.cpp b/tools/IrrFontTool/newFontTool/main.cpp new file mode 100644 index 00000000..2b36547e --- /dev/null +++ b/tools/IrrFontTool/newFontTool/main.cpp @@ -0,0 +1,493 @@ +/* + Tool for creating Irrlicht bitmap+vector fonts, + started by Gaz Davidson in December 2006 + + Due to my laziness and Microsoft's unintuitive API, surrogate pairs and + nonspacing diacritical marks are not supported! + + Linux bitmap font support added by Neil Burlock Oct 2008 + Note: Xft/Freetype2 is used to render the fonts under X11. Anti-aliasing + is controlled by the system and cannot be overriden by an application, + so fonts that are rendered will be aliased or anti-aliased depending + on the system that they are created on. + +*/ + + +#include +#include + +#include "CFontTool.h" +#include "CVectorFontTool.h" +#include "ITexture.h" + +using namespace irr; +using namespace gui; + +#pragma comment(lib, "Irrlicht.lib") + +const s32 texturesizes[] = {128, 256, 512, 1024, 2048, 4096, 0}; + +const wchar_t *fileformats[] = { L"bmp", L"ppm", 0 }; // bitmap font formats +const wchar_t *alphafileformats[] = { L"png", L"tga", 0 }; // bitmap font formats which support alpha channels +const wchar_t *vectorfileformats[] = { L"xml", L"bin", 0 }; // file formats for vector fonts + +const wchar_t *warntext = L"Legal Notice\n" + L"------------\n\n" + L"When making bitmap and vector fonts, you should consider the potential legal " + L"issues with redistributing the fonts with your software; this tool basically " + L"copies font data and some authors might not like this!\n" + L"If you purchased fonts or they came with an application or your OS, you'll have" + L"to check the license to see what restrictions are placed on making derivative works.\n\n" + L"PD and the OFL\n" + L"--------------\n\n" + L"You'll find lots of fonts on the web listed as Public Domain, you can do what you like " + L"with these.\n" + L"Many fonts are released under the Open Font License, which is a 'viral' open source " + L"license like the GPL. It's worth reading the license here: http://scripts.sil.org/OFL\n" + L"The most important restrictions are- you must include the original font's license, you " + L"can't stop your users from using or distributing the font, the font must have a " + L"different name the original.\n\n" + L"Some free fonts can be found here- www.openfontlibrary.org\n" + L"http://savannah.nongnu.org/projects/freefont/"; + +const wchar_t *helptext = L"This tool creates bitmap fonts for the Irrlicht Engine\n\n" + + L"First select a character encoding from the list, then choose the font, " + L"size, and whether you'd like bold, italic, antialiasing and an alpha channel. " + L"In Windows, antialiasing will be ignored for small fonts\n\n" + + L"Then select a texture width and height. If the output exceeds this then more than " + L"one image will be created. You can use the scrollbar at the top of the screen to " + L"preview them. Most modern graphics cards will support up to 2048x2048, " + L"keep in mind that more images means worse performance when drawing text!\n\n" + + L"If you want a vector font rather than a bitmap font, check the vector box. " + L"Vector fonts are stored in system memory while bitmap fonts are in video ram\n\n" + + L"Click create to preview your font, this may take lots of time and memory " + L"when making a font with a lot of characters, please be patient!\n\n" + + L"Now you're ready to give your font a name, select a format and click save.\n\n" + L"To load your font in Irrlicht, simply use env->getFont(\"Myfont.xml\");\n\n" + + L"That's all, have fun :-)"; + +#ifdef _IRR_WINDOWS_ + const wchar_t *completeText = L"Font created"; +#else + const 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 +{ + MYGUI_CHARSET = 100, + MYGUI_FONTNAME, + MYGUI_SIZE, + MYGUI_TEXWIDTH, + MYGUI_TEXHEIGHT, + MYGUI_BOLD, + MYGUI_ITALIC, + MYGUI_ANTIALIAS, + MYGUI_ALPHA, + MYGUI_VECTOR, + MYGUI_FILENAME, + MYGUI_FORMAT, + MYGUI_CREATE, + MYGUI_SAVE, + MYGUI_IMAGE, + MYGUI_CURRENTIMAGE, + MYGUI_HELPBUTTON +}; + + +// event reciever +class MyEventReceiver : public IEventReceiver +{ +public: + + MyEventReceiver(IrrlichtDevice* device, CFontTool*& fonttool, CVectorFontTool* &vectool) : + Device(device), FontTool(fonttool), VecTool(vectool) + { + device->setEventReceiver(this); + } + + virtual bool OnEvent(const SEvent &event) + { + if (event.EventType == EET_GUI_EVENT) + { + s32 id = event.GUIEvent.Caller->getID(); + IGUIEnvironment* env = Device->getGUIEnvironment(); + + switch(event.GUIEvent.EventType) + { + case EGET_SCROLL_BAR_CHANGED: + if (id == MYGUI_CURRENTIMAGE) + { + IGUIImage* img = (IGUIImage*)env->getRootGUIElement()->getElementFromId(MYGUI_IMAGE,true); + s32 i = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos(); + img->setImage(FontTool->currentTextures[i]); + + return true; + } + break; + case EGET_COMBO_BOX_CHANGED: + if (id == MYGUI_CHARSET) + { + IGUIComboBox* cbo = (IGUIComboBox*)event.GUIEvent.Caller; + FontTool->selectCharSet(cbo->getSelected()); + // rebuild font list + cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_FONTNAME,true); + cbo->clear(); + for (u32 i=0; i < FontTool->FontNames.size(); ++i) + cbo->addItem(FontTool->FontNames[i].c_str()); + return true; + } + break; + case EGET_CHECKBOX_CHANGED: + if (id == MYGUI_VECTOR) + { + IGUICheckBox* chk = (IGUICheckBox*)event.GUIEvent.Caller; + + IGUIComboBox *cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_FORMAT,true); + cbo->clear(); + + if (chk->isChecked() && VecTool) + { + // vector formats + for (s32 i=0; fileformats[i] != 0; ++i) + cbo->addItem( core::stringw(vectorfileformats[i]).c_str()); + + } + else + { + + // bitmap formats + if (!FontTool->UseAlphaChannel) + { + // add non-alpha formats + for (s32 i=0; fileformats[i] != 0; ++i) + cbo->addItem( core::stringw(fileformats[i]).c_str()); + } + // add formats which support alpha + for (s32 i=0; alphafileformats[i] != 0; ++i) + cbo->addItem( core::stringw(alphafileformats[i]).c_str()); + } + + } + break; + + case EGET_BUTTON_CLICKED: + + if (id == MYGUI_CREATE) + { + // create the font with the params + IGUIComboBox* cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_CHARSET, true); + int charset = cbo->getSelected(); + + cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_FONTNAME,true); + int fontname = cbo->getSelected(); + + cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_SIZE,true); + int fontsize = cbo->getSelected(); + + cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_TEXWIDTH,true); + int texwidth = cbo->getSelected(); + + cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_TEXHEIGHT,true); + int texheight = cbo->getSelected(); + + IGUICheckBox* chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(MYGUI_BOLD,true); + bool bold = chk->isChecked(); + chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(MYGUI_ITALIC,true); + bool italic = chk->isChecked(); + + chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(MYGUI_ALPHA,true); + bool alpha = chk->isChecked(); + + chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(MYGUI_ANTIALIAS,true); + bool aa = chk->isChecked(); + + // vector fonts disabled + //chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(MYGUI_VECTOR,true); + bool vec = false;//chk->isChecked(); + + FontTool->makeBitmapFont(fontname, charset, FontTool->FontSizes[fontsize], texturesizes[texwidth], texturesizes[texheight], bold, italic, aa, alpha); + + IGUIScrollBar* scrl = (IGUIScrollBar*)env->getRootGUIElement()->getElementFromId(MYGUI_CURRENTIMAGE,true); + scrl->setMax(FontTool->currentTextures.size() == 0 ? 0 : FontTool->currentTextures.size()-1); + + if (FontTool->currentTextures.size() > 0) + { + IGUIImage* img = (IGUIImage*)env->getRootGUIElement()->getElementFromId(MYGUI_IMAGE,true); + img->setImage(FontTool->currentTextures[0]); + scrl->setPos(0); + } + + // make sure users pick a file format that supports alpha channel + cbo = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_FORMAT,true); + cbo->clear(); + + if (vec) + { + // add vector formats + for (s32 i=0; fileformats[i] != 0; ++i) + cbo->addItem( core::stringw(vectorfileformats[i]).c_str()); + } + else + { + if (!alpha) + { + // add non-alpha formats + for (s32 i=0; fileformats[i] != 0; ++i) + cbo->addItem( core::stringw(fileformats[i]).c_str()); + } + // add formats which support alpha + for (s32 i=0; alphafileformats[i] != 0; ++i) + cbo->addItem( core::stringw(alphafileformats[i]).c_str()); + } + if (VecTool) + { + delete VecTool; + VecTool = 0; + } + if (vec) + { + VecTool = new CVectorFontTool(FontTool); + } + + /* Message box letting the user know the process is complete */ + env->addMessageBox(L"Create", completeText); + + return true; + } + + if (id == MYGUI_SAVE) + { + IGUIEditBox *edt = (IGUIEditBox*)env->getRootGUIElement()->getElementFromId(MYGUI_FILENAME,true); + core::stringc name = edt->getText(); + + IGUIComboBox *fmt = (IGUIComboBox*)env->getRootGUIElement()->getElementFromId(MYGUI_FORMAT,true); + core::stringc format = fmt->getItem(fmt->getSelected()); + + // vector fonts disabled + IGUICheckBox *chk = (IGUICheckBox*)env->getRootGUIElement()->getElementFromId(MYGUI_VECTOR,true); + bool vec = false; // chk->isChecked(); + + if (vec && VecTool) + VecTool->saveVectorFont(name.c_str(), format.c_str()); + else + FontTool->saveBitmapFont(name.c_str(), format.c_str()); + + return true; + } + + if (id == MYGUI_HELPBUTTON) + { + env->addMessageBox(L"Irrlicht Unicode Font Tool", helptext); + return true; + } + + break; + } + } + + return false; + } + + IrrlichtDevice* Device; + CFontTool* FontTool; + CVectorFontTool* VecTool; + +}; + +void createGUI(IrrlichtDevice* device, CFontTool* fc) +{ + gui::IGUIEnvironment *env = device->getGUIEnvironment(); + + // change transparency of skin + for (s32 i=0; igetSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i); + col.setAlpha(255); + env->getSkin()->setColor((gui::EGUI_DEFAULT_COLOR)i, col); + } + + IGUIWindow *win = env->addWindow( core::rect(10,10,200,500), false, L"Font Creator"); + win->getCloseButton()->setVisible(false); + + s32 xs=10,xp=xs, yp=30, h=20; + + env->addStaticText(L"Charset", core::rect(xp,yp,50,yp+h),false,false, win); + + xp+=60; + + // charset combo + gui::IGUIComboBox* cbo = env->addComboBox( core::rect(xp,yp,180,yp+h),win, MYGUI_CHARSET); + for (u32 i=0; i < fc->CharSets.size(); ++i) + cbo->addItem(fc->CharSets[i].c_str()); + + yp += (s32)(h*1.5f); + xp = xs; + + env->addStaticText(L"Font", core::rect(xp,yp,50,yp+h),false,false, win); + + xp+=60; + + // font name combo + cbo = env->addComboBox( core::rect(xp,yp,180,yp+h),win, MYGUI_FONTNAME); + for (u32 i=0; i < fc->FontNames.size(); ++i) + cbo->addItem(fc->FontNames[i].c_str()); + + yp += (s32)(h*1.5f); + xp = xs; + + env->addStaticText(L"Size", core::rect(xp,yp,50,yp+h),false,false, win); + + xp += 60; + + // font size combo + cbo = env->addComboBox( core::rect(xp,yp,xp+50,yp+h),win, MYGUI_SIZE); + for (s32 i=0; fc->FontSizes[i] != 0; ++i) + cbo->addItem( ((core::stringw(fc->FontSizes[i])) + L"px").c_str()); + + xp = xs; + yp += (s32)(h*1.5f); + + // bold checkbox + env->addCheckBox(false, core::rect(xp,yp,xp+50,yp+h),win, MYGUI_BOLD, L"Bold"); + + xp += 45; + + // italic checkbox + env->addCheckBox(false, core::rect(xp,yp,xp+50,yp+h),win, MYGUI_ITALIC, L"Italic"); + + xp += 45; + + // AA checkbox + env->addCheckBox(false, core::rect(xp,yp,xp+50,yp+h),win, MYGUI_ANTIALIAS, L"AA"); + + xp +=40; + + // Alpha checkbox + env->addCheckBox(false, core::rect(xp,yp,xp+50,yp+h),win, MYGUI_ALPHA, L"Alpha"); + + xp = xs; + yp += (s32)(h*1.5f); + + /* + // vector fonts can't be loaded yet + env->addCheckBox(false, core::rect(xp,yp,xp+200,yp+h),win, MYGUI_VECTOR, L"Vector Font"); + */ + + yp += (s32)(h*1.5f); + + env->addStaticText(L"Max Width:", core::rect(xp,yp,50,yp+h),false,false, win); + + xp += 60; + + // texture widths + cbo = env->addComboBox( core::rect(xp,yp,xp+70,yp+h),win, MYGUI_TEXWIDTH); + for (s32 i=0; texturesizes[i] != 0; ++i) + cbo->addItem( ((core::stringw(texturesizes[i])) + L" wide").c_str()); + + xp=xs; + yp += (s32)(h*1.5f); + + env->addStaticText(L"Max Height:", core::rect(xp,yp,60,yp+h),false,false, win); + + xp += 60; + + // texture height + cbo = env->addComboBox( core::rect(xp,yp,xp+70,yp+h),win, MYGUI_TEXHEIGHT); + for (s32 i=0; texturesizes[i] != 0; ++i) + cbo->addItem( ((core::stringw(texturesizes[i])) + L" tall").c_str()); + + // file name + xp = xs; + yp += (s32)(h*1.5f); + env->addStaticText(L"Filename", core::rect(xp,yp,60,yp+h),false,false, win); + xp += 60; + env->addEditBox(L"myfont",core::rect(xp,yp,xp+70,yp+h), true, win, MYGUI_FILENAME); + + // file format + xp = xs; + yp += (s32)(h*1.5f); + env->addStaticText(L"File Format", core::rect(xp,yp,60,yp+h),false,false, win); + xp += 60; + + cbo = env->addComboBox( core::rect(xp,yp,xp+70,yp+h),win, MYGUI_FORMAT); + for (s32 i=0; fileformats[i] != 0; ++i) + cbo->addItem( core::stringw(fileformats[i]).c_str()); + for (s32 i=0; alphafileformats[i] != 0; ++i) + cbo->addItem( core::stringw(alphafileformats[i]).c_str()); + + xp = xs; + yp += h*2; + + // create button + env->addButton( core::rect(xp,yp,xp+50,yp+h),win, MYGUI_CREATE, L"Create"); + + xp += 60; + + // save button + env->addButton( core::rect(xp,yp,xp+50,yp+h),win, MYGUI_SAVE, L"Save"); + + xp += 60; + + // help button + env->addButton( core::rect(xp,yp,xp+50,yp+h),win, MYGUI_HELPBUTTON, L"Help"); + + // font image + gui::IGUIImage *img = env->addImage(0, core::position2d(0,0), true,0, MYGUI_IMAGE); + img->setRelativePosition(core::rect(0,20,800,600)); + + // font scrollbar + IGUIScrollBar *scrl= env->addScrollBar(true,core::rect(0,0,800,20),0, MYGUI_CURRENTIMAGE); + scrl->setMax(0); + scrl->setSmallStep(1); + + yp += h*3; + + env->getRootGUIElement()->bringToFront(win); + win->setRelativePosition( core::rect(10,10,200,yp)); +} + +int main() +{ + 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(); + + // create font tool + CFontTool *fc = new CFontTool(device); + CVectorFontTool *vc = 0; + + IEventReceiver *events = new MyEventReceiver(device,fc,vc); + + createGUI(device, fc); + + while(device->run()) + { + if (device->isWindowActive()) + { + + driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0,200,200,200)); + smgr->drawAll(); + env->drawAll(); + driver->endScene(); + } + } + + // drop the font tool and resources + fc->drop(); + + device->drop(); + + return 0; +} + diff --git a/tools/IrrFontTool/oldFontTool/IrrFontTool.exe b/tools/IrrFontTool/oldFontTool/IrrFontTool.exe new file mode 100644 index 00000000..faef5932 Binary files /dev/null and b/tools/IrrFontTool/oldFontTool/IrrFontTool.exe differ diff --git a/tools/IrrFontTool/oldFontTool/source.zip b/tools/IrrFontTool/oldFontTool/source.zip new file mode 100644 index 00000000..9228ebb7 Binary files /dev/null and b/tools/IrrFontTool/oldFontTool/source.zip differ diff --git a/tools/IrrFontTool/readme.txt b/tools/IrrFontTool/readme.txt new file mode 100644 index 00000000..5d9cb634 --- /dev/null +++ b/tools/IrrFontTool/readme.txt @@ -0,0 +1,16 @@ +There are two tools available for creating fonts for irrlicht, both are supported. + +oldFontTool: + only works in Windows, creates a simple image file containing all data for displaying fonts. + Those file contain no alpha informations and are limited in their character set. + use the IrrFontTool.exe file in this directory. + +newFontTool: + a more sophisticated font tool supporting alpha channels, anti aliasing, + different character sets, vector fonts and other operating systems than + just windows. It will create multiple image files and an .xml file + containing meta information for the generated font. + You can find it as FontTool.exe in the /bin directory. + +A third tool to create fonts for Irrlicht is web-based on maintained by armen: +http://armen138.me/FontMapper/ \ No newline at end of file diff --git a/tools/MeshConverter/Makefile b/tools/MeshConverter/Makefile new file mode 100644 index 00000000..53282233 --- /dev/null +++ b/tools/MeshConverter/Makefile @@ -0,0 +1,38 @@ +# 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 = MeshConverter +Sources = main.cpp + +# general compiler settings +CPPFLAGS = -I../../include -I/usr/X11R6/include +CXXFLAGS = -O3 -ffast-math -Wall +#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 -lglu32 -lm +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/tools/MeshConverter/MeshConverter.cbp b/tools/MeshConverter/MeshConverter.cbp new file mode 100644 index 00000000..7851f18c --- /dev/null +++ b/tools/MeshConverter/MeshConverter.cbp @@ -0,0 +1,55 @@ + + + + + + diff --git a/tools/MeshConverter/MeshConverter_vc10.vcxproj b/tools/MeshConverter/MeshConverter_vc10.vcxproj new file mode 100644 index 00000000..e36439b3 --- /dev/null +++ b/tools/MeshConverter/MeshConverter_vc10.vcxproj @@ -0,0 +1,195 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + MeshConverter + {E72B637E-4AA6-46F3-885F-AC67B4B470ED} + GUI Editor + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + Neither + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib %(AdditionalOptions) + ../../bin/Win32-visualstudio/MeshConverter.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + Disabled + Neither + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib %(AdditionalOptions) + ../../bin/Win64-visualstudio/MeshConverter.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)TestProject.pdb + Console + + + + + + + Full + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + + + ../../bin/Win32-visualstudio/MeshConverter.exe + true + Console + true + true + + + + + + + Full + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + + + ../../bin/Win64-visualstudio/MeshConverter.exe + true + Console + true + true + + + + + + + + + + {e08e042a-6c45-411b-92be-3cc31331019f} + false + + + + + + \ No newline at end of file diff --git a/tools/MeshConverter/MeshConverter_vc11.vcxproj b/tools/MeshConverter/MeshConverter_vc11.vcxproj new file mode 100644 index 00000000..12aa4665 --- /dev/null +++ b/tools/MeshConverter/MeshConverter_vc11.vcxproj @@ -0,0 +1,196 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + MeshConverter + {E72B637E-4AA6-46F3-885F-AC67B4B470ED} + GUI Editor + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + Neither + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib %(AdditionalOptions) + ../../bin/Win32-visualstudio/MeshConverter.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)TestProject.pdb + Console + + + + + + + Disabled + Neither + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib %(AdditionalOptions) + ../../bin/Win64-visualstudio/MeshConverter.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)TestProject.pdb + Console + + + + + + + Full + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + + + ../../bin/Win32-visualstudio/MeshConverter.exe + true + Console + true + true + + + + + + + Full + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + + + ../../bin/Win64-visualstudio/MeshConverter.exe + true + Console + true + true + + + + + + + + + + {e08e042a-6c45-411b-92be-3cc31331019f} + false + + + + + + \ No newline at end of file diff --git a/tools/MeshConverter/MeshConverter_vc12.vcxproj b/tools/MeshConverter/MeshConverter_vc12.vcxproj new file mode 100644 index 00000000..69030bf4 --- /dev/null +++ b/tools/MeshConverter/MeshConverter_vc12.vcxproj @@ -0,0 +1,196 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + MeshConverter + {E72B637E-4AA6-46F3-885F-AC67B4B470ED} + GUI Editor + Win32Proj + + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + Application + MultiByte + Windows7.1SDK + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + Neither + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib %(AdditionalOptions) + ../../bin/Win32-visualstudio/MeshConverter.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)TestProject.pdb + Console + + + + + + + Disabled + Neither + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib %(AdditionalOptions) + ../../bin/Win64-visualstudio/MeshConverter.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)TestProject.pdb + Console + + + + + + + Full + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + + + ../../bin/Win32-visualstudio/MeshConverter.exe + true + Console + true + true + + + + + + + Full + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + + + ../../bin/Win64-visualstudio/MeshConverter.exe + true + Console + true + true + + + + + + + + + + {e08e042a-6c45-411b-92be-3cc31331019f} + false + + + + + + \ No newline at end of file diff --git a/tools/MeshConverter/MeshConverter_vc14.vcxproj b/tools/MeshConverter/MeshConverter_vc14.vcxproj new file mode 100644 index 00000000..31c87bd7 --- /dev/null +++ b/tools/MeshConverter/MeshConverter_vc14.vcxproj @@ -0,0 +1,196 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + MeshConverter + {E72B637E-4AA6-46F3-885F-AC67B4B470ED} + GUI Editor + Win32Proj + + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + Application + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + true + true + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + Neither + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib %(AdditionalOptions) + ../../bin/Win32-visualstudio/MeshConverter.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)TestProject.pdb + Console + + + + + + + Disabled + Neither + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glu32.lib opengl32.lib %(AdditionalOptions) + ../../bin/Win64-visualstudio/MeshConverter.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + $(OutDir)TestProject.pdb + Console + + + + + + + Full + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + + + ../../bin/Win32-visualstudio/MeshConverter.exe + true + Console + true + true + + + + + + + Full + false + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + + + ../../bin/Win64-visualstudio/MeshConverter.exe + true + Console + true + true + + + + + + + + + + {e08e042a-6c45-411b-92be-3cc31331019f} + false + + + + + + \ No newline at end of file diff --git a/tools/MeshConverter/main.cpp b/tools/MeshConverter/main.cpp new file mode 100644 index 00000000..b1031f06 --- /dev/null +++ b/tools/MeshConverter/main.cpp @@ -0,0 +1,108 @@ +#include +#include + +using namespace irr; + +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +void usage(const char* name) +{ + std::cerr << "Usage: " << name << " [options] " << std::endl; + std::cerr << " where options are" << std::endl; + std::cerr << " --createTangents: convert to tangents mesh is possible." << std::endl; + std::cerr << " --format=[irrmesh|collada|stl|obj|ply]: Choose target format" << std::endl; +} + +int main(int argc, char* argv[]) +{ + if ((argc < 3) || + ((argc==3) && (argv[1][0]=='-'))) + { + usage(argv[0]); + return 1; + } + + IrrlichtDevice *device = createDevice( video::EDT_NULL, + dimension2d(800, 600), 32, false, false, false, 0); + + device->setWindowCaption(L"Mesh Converter"); + + scene::EMESH_WRITER_TYPE type = EMWT_IRR_MESH; + u32 i=1; + bool createTangents=false; + while (argv[i][0]=='-') + { + core::stringc format = argv[i]; + if (format.size() > 3) + { + if (format.equalsn("--format=",9)) + { + format = format.subString(9,format.size()); + if (format=="collada") + type = EMWT_COLLADA; + else if (format=="stl") + type = EMWT_STL; + else if (format=="obj") + type = EMWT_OBJ; + else if (format=="ply") + type = EMWT_PLY; + else + type = EMWT_IRR_MESH; + } + else + if (format =="--createTangents") + createTangents=true; + } + else + if (format=="--") + { + ++i; + break; + } + ++i; + } + + const s32 srcmesh = i; + const s32 destmesh = i+1; + + --argc; + if ((argcgetSceneManager()->getMesh(argv[srcmesh])->getMesh(0); + if (!mesh) + { + std::cerr << "Could not load " << argv[srcmesh] << std::endl; + return 1; + } + if (createTangents) + { + IMesh* tmp = device->getSceneManager()->getMeshManipulator()->createMeshWithTangents(mesh); + mesh->drop(); + mesh=tmp; + } + IMeshWriter* mw = device->getSceneManager()->createMeshWriter(type); + IWriteFile* file = device->getFileSystem()->createAndWriteFile(argv[destmesh]); + mw->writeMesh(file, mesh); + + file->drop(); + mw->drop(); + device->drop(); + + return 0; +} + diff --git a/tools/irrEdit/irrEdit.jpg b/tools/irrEdit/irrEdit.jpg new file mode 100644 index 00000000..deafb3f6 Binary files /dev/null and b/tools/irrEdit/irrEdit.jpg differ diff --git a/tools/irrEdit/irrEdit.txt b/tools/irrEdit/irrEdit.txt new file mode 100644 index 00000000..5e6fe60e --- /dev/null +++ b/tools/irrEdit/irrEdit.txt @@ -0,0 +1,7 @@ +irrEdit is a free scene graph editor for Irrlicht Engine .irr files and is capable as being used as world editor, +particle system designer, meshviewer and more. It is a visual front end for the Irrlicht Engine, and thus has a lot +of impressive features like importing meshes of every format Irrlicht supports, simple but powerful material +system and lots of special effects. + +For package size reasons, irrEdit is not included in this SDK, but you can download it from +http://www.ambiera.com/irredit \ No newline at end of file